From 320870afb468718ceda377164a3a25b00e9066bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Wed, 7 Jan 2026 10:29:28 -0300 Subject: [PATCH 1/3] feat: Add account-modules Solidity package --- .github/workflows/account-modules-ci.yml | 49 + .gitmodules | 15 + solidity/account-modules/.gitignore | 11 + solidity/account-modules/README.md | 69 + .../docs/auto-collect/architecture.md | 252 + .../docs/auto-top-up/architecture.md | 272 + solidity/account-modules/foundry.toml | 28 + .../lib/BokkyPooBahsDateTimeLibrary | 1 + solidity/account-modules/lib/forge-std | 1 + solidity/account-modules/lib/modulekit | 1 + .../lib/openzeppelin-contracts | 1 + .../lib/safe-singleton-deployer-sol | 1 + .../script/CalculateStorageSlot.s.sol | 27 + solidity/account-modules/script/Deploy.s.sol | 85 + solidity/account-modules/script/README.md | 42 + solidity/account-modules/script/verify.sh | 41 + .../src/AutoCollectExecutor.sol | 558 + .../account-modules/src/AutoTopUpExecutor.sol | 551 + .../src/IAutoCollectExecutor.sol | 214 + .../src/IAutoTopUpExecutor.sol | 198 + .../AutoCollectExecutor.integration.t.sol | 675 + .../test/AutoCollectExecutor.t.sol | 1192 ++ .../test/AutoTopUpExecutor.integration.t.sol | 441 + .../test/AutoTopUpExecutor.t.sol | 941 ++ .../test/mocks/MaliciousCollectToken.sol | 32 + .../test/mocks/MaliciousToken.sol | 30 + .../account-modules/test/mocks/MockERC20.sol | 16 + .../account-modules/test/mocks/MockSafe.sol | 63 + .../test/mocks/MockTokenBadReturn.sol | 60 + .../test/mocks/MockTokenReturnsFalse.sol | 55 + .../account-modules/test/mocks/MockUSDT.sol | 54 + .../.github/workflows/test.yml | 40 + .../packages/account-modules/.gitignore | 11 + typescript/packages/account-modules/README.md | 69 + .../docs/auto-collect/architecture.md | 252 + .../docs/auto-top-up/architecture.md | 272 + .../packages/account-modules/foundry.lock | 68 + .../packages/account-modules/foundry.toml | 28 + .../.gitattributes | 1 + .../BokkyPooBahsDateTimeLibrary/.gitignore | 8 + .../lib/BokkyPooBahsDateTimeLibrary/LICENSE | 21 + .../lib/BokkyPooBahsDateTimeLibrary/README.md | 915 + .../BokkyPooBahsDateTimeContract.sol | 177 + .../contracts/BokkyPooBahsDateTimeLibrary.sol | 301 + .../contracts/TestDateTime.sol | 142 + ...ooBahsDateTimeContract_flattened_v1.00.sol | 491 + .../deployment/deployment-v1.00-prerelease.md | 32 + ...enJulianDatesAndGregorianCalendarDates.pdf | Bin 0 -> 90427 bytes .../docs/timestampFromDateTime.png | Bin 0 -> 188342 bytes .../docs/timestampToDateTime.png | Bin 0 -> 168968 bytes .../flattened/TestDateTime_flattened.sol | 439 + .../images/clocks.png | Bin 0 -> 1843439 bytes .../scripts/solidityFlattener.pl | 138 + .../test/00_runGeth.sh | 8 + .../test/01_test1.sh | 605 + .../test/02_attachGeth.sh | 9 + .../test/BokkyPooBahsDateTimeLibrary.js | 11 + .../test/BokkyPooBahsDateTimeLibrary.sol | 300 + .../test/README.md | 56 + .../test/TestDateTime.js | 16 + .../test/TestDateTime.sol | 141 + .../test/deploymentData.js | 11 + .../test/functions.js | 571 + .../test/genesis.json | 112 + .../BokkyPooBahsDateTimeLibrary/test/settings | 21 + .../test/test1output.txt | 3070 ++++ .../test/test1results.txt | 2422 +++ ...--a00af22d07c87d96eeeb0ed583f8f6ac7812827e | 1 + ...--a11aae29840fbb5c86e6fd4cf809eba183aef433 | 1 + ...--a22ab8a9d641ce77e06d98b7d7065d324d3d6976 | 1 + ...--a33a6c312d9ad0e0f2e95541beed0cc081621fd0 | 1 + ...--a44a08d3f6933c69212114bb66e2df1813651844 | 1 + ...--a55a151eb00fded1634d27d1127b4be4627079ea | 1 + ...--a66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 | 1 + ...--a77a2b9d4b1c010a22a7c565dc418cef683dbcec | 1 + ...--a88a05d2b88283ce84c8325760b72a64591279a2 | 1 + ...--a99a0ae3354c06b1459fd441a32a3f71005d7da0 | 1 + ...--aaaa9de1e6c564446ebca0fd102d8bd92093c756 | 1 + ...--abba43e7594e3b76afb157989e93c6621497fd4b | 1 + ...--acca534c9f62ab495bd986e002ddf0f054caae4f | 1 + ...--adda9b762a00ff12711113bfdc36958b73d7f915 | 1 + ...--aeea63b5479b50f79583ec49dacdcf86ddeff392 | 1 + ...--affa4d3a80add8ce4018540e056dacb649589394 | 1 + ...--b00bfde102270687324f9205b693859df64f8923 | 1 + ...--b11be1d4ef8e94d01cb2695092a79d139a8dad98 | 1 + ...--b22be2d9eef0d7e260cf96a64feea0b95ed3e74f | 1 + ...--b33b7ecf5e47be3981c74d989d3af8b665b4b649 | 1 + ...--b44b43d59b738b088b690ae276c1e979aba8268d | 1 + ...--b55b57d113b45481e31aaf03d6f4e5ad4ef325f8 | 1 + ...--b66bcb4e473de80e2c8a47ced10c22c705a5e602 | 1 + ...--b77bbbaa7c1649547ae61de4b80b91568c28351a | 1 + ...--b88b728490b417e29b0784db30535db343830dba | 1 + ...--b99b3d1f72edb05a0321db58eddcf83fd73c4ade | 1 + ...--baab56da883edbe5314b8005be410022c510ccae | 1 + ...--bbbb9809de0456ce0e0cd660e6e4ceabef3f521c | 1 + ...--bccb68dd0ac87ef290aef49870d155f076c87868 | 1 + ...--bddb726ee06906e104db210e6d0506f2b062e477 | 1 + ...--beeb24ff18203658d0a1d4682ee3f36ad663ec87 | 1 + ...--bffbd8f029ef0bd81cf754b53e8b3a5684f8b3ff | 1 + .../lib/forge-std/.gitattributes | 1 + .../lib/forge-std/.github/CODEOWNERS | 1 + .../lib/forge-std/.github/workflows/ci.yml | 82 + .../lib/forge-std/.github/workflows/sync.yml | 31 + .../account-modules/lib/forge-std/.gitignore | 4 + .../lib/forge-std/CONTRIBUTING.md | 193 + .../lib/forge-std/LICENSE-APACHE | 203 + .../account-modules/lib/forge-std/LICENSE-MIT | 25 + .../account-modules/lib/forge-std/README.md | 266 + .../lib/forge-std/foundry.toml | 23 + .../lib/forge-std/package.json | 16 + .../lib/forge-std/scripts/vm.py | 646 + .../lib/forge-std/src/Base.sol | 42 + .../lib/forge-std/src/Script.sol | 28 + .../lib/forge-std/src/StdAssertions.sol | 764 + .../lib/forge-std/src/StdChains.sol | 286 + .../lib/forge-std/src/StdCheats.sol | 829 + .../lib/forge-std/src/StdConstants.sol | 30 + .../lib/forge-std/src/StdError.sol | 15 + .../lib/forge-std/src/StdInvariant.sol | 122 + .../lib/forge-std/src/StdJson.sol | 283 + .../lib/forge-std/src/StdMath.sol | 43 + .../lib/forge-std/src/StdStorage.sol | 473 + .../lib/forge-std/src/StdStyle.sol | 333 + .../lib/forge-std/src/StdToml.sol | 283 + .../lib/forge-std/src/StdUtils.sol | 208 + .../lib/forge-std/src/Test.sol | 34 + .../account-modules/lib/forge-std/src/Vm.sol | 2468 +++ .../lib/forge-std/src/console.sol | 1560 ++ .../lib/forge-std/src/console2.sol | 4 + .../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/IERC6909.sol | 72 + .../lib/forge-std/src/interfaces/IERC721.sol | 164 + .../lib/forge-std/src/interfaces/IERC7540.sol | 150 + .../lib/forge-std/src/interfaces/IERC7575.sol | 241 + .../forge-std/src/interfaces/IMulticall3.sol | 73 + .../lib/forge-std/src/safeconsole.sol | 13937 ++++++++++++++++ .../lib/forge-std/test/CommonBase.t.sol | 44 + .../lib/forge-std/test/StdAssertions.t.sol | 141 + .../lib/forge-std/test/StdChains.t.sol | 227 + .../lib/forge-std/test/StdCheats.t.sol | 639 + .../lib/forge-std/test/StdConstants.t.sol | 38 + .../lib/forge-std/test/StdError.t.sol | 120 + .../lib/forge-std/test/StdJson.t.sol | 49 + .../lib/forge-std/test/StdMath.t.sol | 202 + .../lib/forge-std/test/StdStorage.t.sol | 488 + .../lib/forge-std/test/StdStyle.t.sol | 110 + .../lib/forge-std/test/StdToml.t.sol | 49 + .../lib/forge-std/test/StdUtils.t.sol | 342 + .../lib/forge-std/test/Vm.t.sol | 18 + .../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/forge-std/test/fixtures/test.json | 8 + .../lib/forge-std/test/fixtures/test.toml | 6 + .../lib/modulekit/.changeset/README.md | 8 + .../lib/modulekit/.changeset/config.json | 11 + .../lib/modulekit/.env-example | 2 + .../lib/modulekit/.github/workflows/ci.yaml | 55 + .../.github/workflows/dependency.yml | 88 + .../account-modules/lib/modulekit/.gitignore | 19 + .../account-modules/lib/modulekit/.npmrc | 1 + .../lib/modulekit/.solhint.json | 19 + .../lib/modulekit/.solhintignore | 5 + .../lib/modulekit/CHANGELOG.md | 186 + .../account-modules/lib/modulekit/README.md | 137 + .../lib/modulekit/docs/Accounts.md | 45 + .../lib/modulekit/foundry.toml | 27 + .../lib/modulekit/gas_calculations/.gitkeep | 0 .../lib/modulekit/octanerc.json | 3 + .../lib/modulekit/package.json | 66 + .../lib/modulekit/pnpm-lock.yaml | 4803 ++++++ .../lib/modulekit/remappings.txt | 12 + .../lib/modulekit/src/Accounts.sol | 28 + .../lib/modulekit/src/Helpers.sol | 40 + .../lib/modulekit/src/Integrations.sol | 18 + .../lib/modulekit/src/Interfaces.sol | 30 + .../lib/modulekit/src/Mocks.sol | 31 + .../lib/modulekit/src/ModuleKit.sol | 22 + .../lib/modulekit/src/Modules.sol | 55 + .../common/interfaces/IERC4337Account.sol | 75 + .../common/interfaces/IERC7579Account.sol | 131 + .../common/interfaces/IERC7579Module.sol | 162 + .../src/accounts/common/lib/ModeLib.sol | 160 + .../src/accounts/erc7579/ERC7579Factory.sol | 151 + .../erc7579/helpers/ExecutionHelper.sol | 139 + .../erc7579/interfaces/IERC7579Bootstrap.sol | 38 + .../src/accounts/erc7579/interfaces/IMSA.sol | 28 + .../src/accounts/erc7579/lib/ExecutionLib.sol | 86 + .../factory/interface/IAccountFactory.sol | 36 + .../factory/template/FactoryTemplate.sol | 39 + .../src/accounts/kernel/KernelFactory.sol | 181 + .../accounts/kernel/interfaces/IAccount.sol | 58 + .../kernel/interfaces/IAccountExecute.sol | 26 + .../kernel/interfaces/IERC7579Account.sol | 133 + .../kernel/interfaces/IERC7579Module.sol | 133 + .../accounts/kernel/interfaces/IKernel.sol | 151 + .../kernel/interfaces/IKernelFactory.sol | 7 + .../kernel/interfaces/IValidationManager.sol | 32 + .../src/accounts/kernel/lib/ExecLib.sol | 325 + .../accounts/kernel/lib/ValidationTypeLib.sol | 244 + .../src/accounts/kernel/mock/MockFallback.sol | 78 + .../src/accounts/kernel/types/Constants.sol | 83 + .../src/accounts/kernel/types/Structs.sol | 8 + .../src/accounts/kernel/types/Types.sol | 115 + .../src/accounts/nexus/NexusFactory.sol | 177 + .../src/accounts/nexus/interfaces/INexus.sol | 44 + .../nexus/interfaces/INexusAccountFactory.sol | 30 + .../nexus/interfaces/INexusBootstrap.sol | 104 + .../src/accounts/safe/SafeFactory.sol | 190 + .../src/accounts/safe/interfaces/IERC7484.sol | 48 + .../safe/interfaces/IERC7579Account.sol | 137 + .../accounts/safe/interfaces/ISafe7579.sol | 268 + .../safe/interfaces/ISafe7579Launchpad.sol | 130 + .../src/accounts/safe/interfaces/ISafeOp.sol | 82 + .../safe/interfaces/ISafeProxyFactory.sol | 33 + .../src/accounts/safe/types/DataTypes.sol | 29 + .../precompiles/BytecodeDeployer.sol | 32 + .../precompiles/ERC7579Precompiles.sol | 67 + .../precompiles/KernelPrecompiles.sol | 65 + .../precompiles/NexusPrecompiles.sol | 88 + .../precompiles/Safe7579Precompiles.sol | 63 + .../precompiles/SmartSessionsPrecompiles.sol | 23 + .../src/deployment/predeploy/EntryPoint.sol | 47 + .../src/deployment/predeploy/MockFactory.sol | 22 + .../src/deployment/predeploy/Registry.sol | 20 + .../deployment/registry/RegistryDeployer.sol | 216 + .../registry/interfaces/IERC7484.sol | 52 + .../registry/interfaces/IExternalResolver.sol | 68 + .../interfaces/IExternalSchemaValidator.sol | 23 + .../registry/interfaces/IRegistry.sol | 419 + .../deployment/registry/types/DataTypes.sol | 128 + .../lib/modulekit/src/external/ERC4337.sol | 41 + .../lib/modulekit/src/integrations/ERC20.sol | 129 + .../modulekit/src/integrations/ERC4626.sol | 76 + .../lib/modulekit/src/integrations/ERC721.sol | 43 + .../src/integrations/ERC7579Exec.sol | 108 + .../integrations/interfaces/IBotRegistry.sol | 7 + .../integrations/interfaces/IDFSRegistry.sol | 23 + .../src/integrations/interfaces/IDSProxy.sol | 24 + .../src/integrations/interfaces/IERC20.sol | 34 + .../src/integrations/interfaces/IERC4626.sol | 30 + .../src/integrations/interfaces/IERC721.sol | 21 + .../interfaces/IERC721Enumerable.sol | 11 + .../interfaces/IFLParamGetter.sol | 11 + .../src/integrations/interfaces/IGasToken.sol | 15 + .../integrations/interfaces/ILendingPool.sol | 187 + .../interfaces/IMCDPriceVerifier.sol | 16 + .../integrations/interfaces/IProxyERC20.sol | 8 + .../interfaces/IProxyRegistry.sol | 8 + .../integrations/interfaces/ISmartSession.sol | 364 + .../interfaces/ISubscriptions.sol | 10 + .../src/integrations/interfaces/ITrigger.sol | 9 + .../src/integrations/interfaces/IWETH.sol | 21 + .../integrations/interfaces/LSTs/ICBETH.sol | 7 + .../integrations/interfaces/LSTs/IRETH.sol | 8 + .../integrations/interfaces/LSTs/IWstETH.sol | 8 + .../integrations/interfaces/aave/IAToken.sol | 9 + .../interfaces/aave/ILendToAaveMigrator.sol | 7 + .../interfaces/aave/ILendingPool.sol | 179 + .../aave/ILendingPoolAddressesProvider.sol | 55 + .../integrations/interfaces/aave/IStkAave.sol | 11 + .../aaveV2/IAaveIncentivesController.sol | 108 + .../aaveV2/IAaveProtocolDataProviderV2.sol | 77 + .../ILendingPoolAddressesProviderV2.sol | 48 + .../interfaces/aaveV2/ILendingPoolV2.sol | 517 + .../aaveV2/IPriceOracleGetterAave.sol | 14 + .../interfaces/aaveV2/IStakedToken.sol | 6 + .../interfaces/aaveV3/DataTypes.sol | 271 + .../aaveV3/IAaveProtocolDataProvider.sol | 39 + .../interfaces/aaveV3/IAaveV3Oracle.sol | 66 + .../interfaces/aaveV3/IL2PoolV3.sol | 140 + .../aaveV3/IPoolAddressesProvider.sol | 229 + .../interfaces/aaveV3/IPoolV3.sol | 867 + .../interfaces/aaveV3/IPriceOracleGetter.sol | 28 + .../aaveV3/IPriceOracleSentinel.sol | 54 + .../interfaces/aaveV3/IRewardsController.sol | 189 + .../interfaces/aaveV3/IRewardsDistributor.sol | 201 + .../balancer/IFlashLoanRecipient.sol | 24 + .../interfaces/balancer/IFlashLoans.sol | 12 + .../interfaces/balancer/IMerkleRedeem.sol | 14 + .../interfaces/balancer/IPool.sol | 6 + .../interfaces/balancer/IVault.sol | 44 + .../interfaces/bprotocol/IBAMM.sol | 7 + .../interfaces/chainlink/IAggregatorV3.sol | 43 + .../interfaces/chainlink/IFeedRegistry.sol | 183 + .../interfaces/chainlink/IPhaseAggregator.sol | 15 + .../interfaces/compound/ICToken.sol | 71 + .../interfaces/compound/ICompoundOracle.sol | 7 + .../interfaces/compound/IComptroller.sol | 54 + .../interfaces/compoundV3/IComet.sol | 142 + .../interfaces/compoundV3/ICometExt.sol | 16 + .../interfaces/compoundV3/ICometRewards.sol | 36 + .../interfaces/convex/IBaseRewardPool.sol | 16 + .../interfaces/convex/IBooster.sol | 17 + .../interfaces/convex/IConvexToken.sol | 10 + .../interfaces/convex/IRewardPool.sol | 7 + .../interfaces/curve/IAddressProvider.sol | 9 + .../interfaces/curve/ICurve3PoolZap.sol | 9 + .../interfaces/curve/ICurveFactory.sol | 24 + .../interfaces/curve/IDepositZap.sol | 8 + .../interfaces/curve/IFeeDistributor.sol | 7 + .../interfaces/curve/ILiquidityGauge.sol | 20 + .../integrations/interfaces/curve/IMinter.sol | 8 + .../interfaces/curve/IRegistry.sol | 19 + .../integrations/interfaces/curve/ISwaps.sol | 174 + .../interfaces/curve/IVotingEscrow.sol | 10 + .../curve/stethPool/ICurveStethPool.sol | 8 + .../interfaces/curveusd/ICurveUsd.sol | 157 + .../interfaces/dydx/ISoloMargin.sol | 463 + .../integrations/interfaces/euler/IDToken.sol | 6 + .../interfaces/euler/IEulerMarkets.sol | 6 + .../interfaces/exchange/IExchangeV3.sol | 41 + .../interfaces/exchange/IExchangeWrapper.sol | 45 + .../exchange/IKyberNetworkProxy.sol | 92 + .../interfaces/exchange/IOasis.sol | 45 + .../exchange/IOffchainWrapper.sol.bak | 16 + .../interfaces/exchange/IPair.sol | 18 + .../interfaces/exchange/IQuoter.sol | 70 + .../interfaces/exchange/ISwapRouter.sol | 105 + .../interfaces/exchange/IUniswapRouter.sol | 117 + .../flashloan/IERC3156FlashBorrower.sol | 23 + .../flashloan/IERC3156FlashLender.sol | 37 + .../interfaces/flashloan/IFlashLoanBase.sol | 14 + .../interfaces/guni/IGUniPool.sol | 7 + .../interfaces/guni/IGUniRouter02.sol | 41 + .../interfaces/insta/IInstaAccountV2.sol | 7 + .../interfaces/insta/IInstaIndex.sol | 12 + .../insta/IInstaMakerDAOMerkleDistributor.sol | 24 + .../interfaces/kyber/IAggregationExecutor.sol | 17 + .../interfaces/kyber/IExecutorHelper.sol | 382 + .../kyber/IMetaAggregationRouterV2.sol | 44 + .../integrations/interfaces/lido/IWStEth.sol | 11 + .../interfaces/liquity/IBondNFT.sol | 29 + .../interfaces/liquity/IBondNFTArtwork.sol | 15 + .../liquity/IBorrowerOperations.sol | 75 + .../liquity/IChickenBondManager.sol | 82 + .../interfaces/liquity/ICollSurplusPool.sol | 30 + .../interfaces/liquity/IHintHelpers.sol | 38 + .../interfaces/liquity/ILQTYStaking.sol | 46 + .../interfaces/liquity/IPriceFeed.sol | 8 + .../interfaces/liquity/ISortedTroves.sol | 64 + .../interfaces/liquity/IStabilityPool.sol | 168 + .../interfaces/liquity/ITroveManager.sol | 148 + .../src/integrations/interfaces/mcd/ICat.sol | 13 + .../interfaces/mcd/ICdpRegistry.sol | 14 + .../integrations/interfaces/mcd/ICropJoin.sol | 9 + .../integrations/interfaces/mcd/ICropper.sol | 13 + .../integrations/interfaces/mcd/IDSPause.sol | 7 + .../integrations/interfaces/mcd/IDaiJoin.sol | 12 + .../integrations/interfaces/mcd/IDssSpell.sol | 9 + .../src/integrations/interfaces/mcd/IGem.sol | 17 + .../integrations/interfaces/mcd/IGetCdps.sol | 22 + .../src/integrations/interfaces/mcd/IJoin.sol | 14 + .../src/integrations/interfaces/mcd/IJug.sol | 14 + .../integrations/interfaces/mcd/IManager.sol | 23 + .../src/integrations/interfaces/mcd/IOsm.sol | 8 + .../interfaces/mcd/IPipInterface.sol | 8 + .../src/integrations/interfaces/mcd/IPot.sol | 12 + .../integrations/interfaces/mcd/ISpotter.sol | 16 + .../src/integrations/interfaces/mcd/IVat.sol | 30 + .../interfaces/morpho/IMorpho.sol | 135 + .../interfaces/morpho/IMorphoAaveV2Lens.sol | 257 + .../interfaces/morpho/IMorphoAaveV3.sol | 236 + .../interfaces/morpho/IRewardsDistributor.sol | 8 + .../interfaces/morpho/MorphoTypes.sol | 126 + .../interfaces/morpho/MorphoTypesAaveV3.sol | 991 ++ .../mstable/IBoostedVaultWithLockup.sol | 75 + .../interfaces/mstable/ISavingsContractV2.sol | 35 + .../interfaces/mstable/ImAsset.sol | 151 + .../interfaces/qidao/IQiDaoRegistry.sol | 2 + .../interfaces/qidao/IStablecoin.sol | 48 + .../interfaces/rari/IFundController.sol | 7 + .../interfaces/rari/IFundManager.sol | 11 + .../interfaces/rari/IFundProxy.sol | 15 + .../interfaces/rari/IFuseAsset.sol | 7 + .../reflexer/IBasicTokenAdapters.sol | 12 + .../interfaces/reflexer/ICoinJoin.sol | 10 + .../interfaces/reflexer/IFSMWrapper.sol | 6 + .../interfaces/reflexer/IGetSafes.sol | 22 + .../interfaces/reflexer/IMedianOracle.sol | 7 + .../interfaces/reflexer/IOracleRelayer.sol | 16 + .../interfaces/reflexer/ISAFEEngine.sol | 53 + .../interfaces/reflexer/ISAFEManager.sol | 25 + .../interfaces/reflexer/ISAFESaviour.sol | 11 + .../interfaces/reflexer/ITaxCollector.sol | 14 + .../integrations/interfaces/spark/IsDAI.sol | 11 + .../interfaces/strategy/ISubStorage.sol | 13 + .../interfaces/uniswap/IUniswapV2Factory.sol | 11 + .../interfaces/uniswap/IUniswapV2Pair.sol | 11 + .../interfaces/uniswap/v3/IQuoter.sol | 71 + .../interfaces/uniswap/v3/ISwapRouter.sol | 85 + .../uniswap/v3/IUniswapV3Factory.sol | 15 + .../uniswap/v3/IUniswapV3FlashCallback.sol | 6 + .../IUniswapV3NonfungiblePositionManager.sol | 115 + .../interfaces/uniswap/v3/IUniswapV3Pool.sol | 39 + .../uniswap/v3/IUniswapV3SwapCallback.sol | 25 + .../integrations/interfaces/yearn/IYVault.sol | 18 + .../interfaces/yearn/IYearnRegistry.sol | 9 + .../integrations/registry/ExampleFactory.sol | 147 + .../src/integrations/registry/FactoryBase.sol | 22 + .../src/integrations/uniswap/MockUniswap.sol | 52 + .../uniswap/helpers/MainnetAddresses.sol | 7 + .../src/integrations/uniswap/v3/Uniswap.sol | 197 + .../lib/modulekit/src/mocks/MockERC20.sol | 257 + .../lib/modulekit/src/mocks/MockERC721.sol | 258 + .../src/module-bases/ERC1271Policy.sol | 19 + .../module-bases/ERC7484RegistryAdapter.sol | 20 + .../src/module-bases/ERC7579ActionPolicy.sol | 18 + .../src/module-bases/ERC7579ExecutorBase.sol | 109 + .../src/module-bases/ERC7579FallbackBase.sol | 27 + .../src/module-bases/ERC7579HookBase.sol | 68 + .../src/module-bases/ERC7579HookDestruct.sol | 275 + .../ERC7579HookDestructSingleHook.sol | 275 + .../ERC7579HybridValidatorBase.sol | 17 + .../src/module-bases/ERC7579ModuleBase.sol | 23 + .../src/module-bases/ERC7579PolicyBase.sol | 15 + .../ERC7579StatelessValidatorBase.sol | 17 + .../src/module-bases/ERC7579UserOpPolicy.sol | 16 + .../src/module-bases/ERC7579ValidatorBase.sol | 65 + .../module-bases/ERC7579ValidatorMaster.sol | 68 + .../src/module-bases/SchedulingBase.sol | 145 + .../src/module-bases/interfaces/Flashloan.sol | 75 + .../src/module-bases/interfaces/IERC1271.sol | 25 + .../src/module-bases/interfaces/IERC712.sol | 6 + .../src/module-bases/interfaces/IERC7484.sol | 49 + .../src/module-bases/interfaces/IPolicy.sol | 111 + .../interfaces/IStatelessValidator.sol | 13 + .../src/module-bases/mocks/MockExecutor.sol | 38 + .../src/module-bases/mocks/MockFallback.sol | 28 + .../src/module-bases/mocks/MockHook.sol | 36 + .../mocks/MockHookMultiPlexer.sol | 116 + .../mocks/MockHybridValidator.sol | 65 + .../src/module-bases/mocks/MockPolicy.sol | 72 + .../src/module-bases/mocks/MockRegistry.sol | 44 + .../mocks/MockStatelessValidator.sol | 31 + .../src/module-bases/mocks/MockTarget.sol | 21 + .../src/module-bases/mocks/MockValidator.sol | 53 + .../module-bases/utils/ERC7579Constants.sol | 12 + .../utils/ERC7579ValidatorLib.sol | 190 + .../module-bases/utils/TrustedForwarder.sol | 56 + .../lib/modulekit/src/test/Auxiliary.sol | 60 + .../modulekit/src/test/ModuleKitHelpers.sol | 1322 ++ .../src/test/RhinestoneModuleKit.sol | 471 + .../src/test/helpers/ERC7579Helpers.sol | 164 + .../modulekit/src/test/helpers/HelperBase.sol | 661 + .../src/test/helpers/KernelHelpers.sol | 584 + .../src/test/helpers/NexusHelpers.sol | 292 + .../src/test/helpers/SafeHelpers.sol | 535 + .../src/test/helpers/SmartSessionHelpers.sol | 393 + .../interfaces/IAccountModulesPaginated.sol | 20 + .../lib/modulekit/src/test/utils/ECDSA.sol | 10 + .../src/test/utils/ERC4337Helpers.sol | 272 + .../lib/modulekit/src/test/utils/Log.sol | 19 + .../lib/modulekit/src/test/utils/Storage.sol | 413 + .../lib/modulekit/src/test/utils/Vm.sol | 206 + .../src/test/utils/gas/GasCalculations.sol | 140 + .../src/test/utils/gas/GasParser.sol | 113 + .../src/test/utils/gas/UserOpGasLog.sol | 68 + .../lib/modulekit/test/BaseTest.t.sol | 28 + .../lib/modulekit/test/Diff.t.sol | 910 + .../modulekit/test/GasCalculationsTest.sol | 26 + .../lib/modulekit/test/RegistryDeployer.t.sol | 203 + .../test/integrations/ExampleFactory.t.sol | 75 + .../test/integrations/SmartSession.t.sol | 405 + .../test/integrations/SwapTest.t.sol | 103 + .../modulekit/test/mocks/MockK1Validator.sol | 70 + .../MockK1ValidatorUncompliantUninstall.sol | 69 + .../test/mocks/MockValidatorFalse.sol | 66 + .../.changeset/config.json | 12 + .../lib/openzeppelin-contracts/.codecov.yml | 16 + .../lib/openzeppelin-contracts/.editorconfig | 21 + .../.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 | 51 + .../.github/actions/setup/action.yml | 22 + .../.github/actions/storage-layout/action.yml | 57 + .../.github/workflows/actionlint.yml | 18 + .../.github/workflows/changeset.yml | 28 + .../.github/workflows/checks.yml | 132 + .../.github/workflows/docs.yml | 19 + .../.github/workflows/formal-verification.yml | 86 + .../.github/workflows/release-cycle.yml | 214 + .../.github/workflows/upgradeable.yml | 34 + .../lib/openzeppelin-contracts/.gitignore | 67 + .../lib/openzeppelin-contracts/.gitmodules | 10 + .../openzeppelin-contracts/.husky/pre-commit | 2 + .../lib/openzeppelin-contracts/.mocharc.js | 4 + .../lib/openzeppelin-contracts/.prettierrc | 15 + .../lib/openzeppelin-contracts/.solcover.js | 21 + .../lib/openzeppelin-contracts/CHANGELOG.md | 1278 ++ .../openzeppelin-contracts/CODE_OF_CONDUCT.md | 73 + .../openzeppelin-contracts/CONTRIBUTING.md | 36 + .../lib/openzeppelin-contracts/FUNDING.json | 10 + .../lib/openzeppelin-contracts/GUIDELINES.md | 155 + .../lib/openzeppelin-contracts/LICENSE | 22 + .../lib/openzeppelin-contracts/README.md | 108 + .../lib/openzeppelin-contracts/RELEASING.md | 45 + .../lib/openzeppelin-contracts/SECURITY.md | 43 + .../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 .../audits/2023-05-v4.9.pdf | Bin 0 -> 485395 bytes .../audits/2023-10-v5.0.pdf | Bin 0 -> 910284 bytes .../audits/2024-10-v5.1.pdf | Bin 0 -> 395831 bytes .../audits/2024-12-v5.2.pdf | Bin 0 -> 242253 bytes .../audits/2025-04-v5.3.pdf | Bin 0 -> 154227 bytes .../openzeppelin-contracts/audits/README.md | 20 + .../openzeppelin-contracts/certora/.gitignore | 1 + .../openzeppelin-contracts/certora/Makefile | 54 + .../openzeppelin-contracts/certora/README.md | 60 + .../access_manager_AccessManager.sol.patch | 97 + .../AccessControlDefaultAdminRulesHarness.sol | 46 + .../harnesses/AccessControlHarness.sol | 6 + .../harnesses/AccessManagedHarness.sol | 36 + .../harnesses/AccessManagerHarness.sol | 116 + .../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/NoncesHarness.sol | 14 + .../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 | 168 + .../openzeppelin-contracts/certora/specs.json | 110 + .../certora/specs/AccessControl.spec | 119 + .../specs/AccessControlDefaultAdminRules.spec | 464 + .../certora/specs/AccessManaged.spec | 34 + .../certora/specs/AccessManager.spec | 826 + .../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/Nonces.spec | 92 + .../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 | 12 + .../certora/specs/methods/IAccessControl.spec | 8 + .../IAccessControlDefaultAdminRules.spec | 36 + .../certora/specs/methods/IAccessManaged.spec | 5 + .../certora/specs/methods/IAccessManager.spec | 33 + .../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 | 207 + .../contracts/access/IAccessControl.sol | 98 + .../contracts/access/Ownable.sol | 100 + .../contracts/access/Ownable2Step.sol | 67 + .../contracts/access/README.adoc | 45 + .../AccessControlDefaultAdminRules.sol | 372 + .../extensions/AccessControlEnumerable.sol | 81 + .../IAccessControlDefaultAdminRules.sol | 192 + .../extensions/IAccessControlEnumerable.sol | 31 + .../access/manager/AccessManaged.sol | 112 + .../access/manager/AccessManager.sol | 740 + .../access/manager/AuthorityUtils.sol | 36 + .../access/manager/IAccessManaged.sol | 32 + .../access/manager/IAccessManager.sol | 399 + .../contracts/access/manager/IAuthority.sol | 14 + .../contracts/account/Account.sol | 145 + .../contracts/account/README.adoc | 30 + .../extensions/draft-AccountERC7579.sol | 405 + .../extensions/draft-AccountERC7579Hooked.sol | 107 + .../account/extensions/draft-ERC7821.sol | 70 + .../contracts/account/utils/EIP7702Utils.sol | 21 + .../account/utils/draft-ERC4337Utils.sol | 159 + .../account/utils/draft-ERC7579Utils.sol | 280 + .../contracts/finance/README.adoc | 14 + .../contracts/finance/VestingWallet.sol | 159 + .../contracts/finance/VestingWalletCliff.sol | 54 + .../contracts/governance/Governor.sol | 818 + .../contracts/governance/IGovernor.sol | 454 + .../contracts/governance/README.adoc | 197 + .../governance/TimelockController.sol | 471 + .../extensions/GovernorCountingFractional.sol | 190 + .../GovernorCountingOverridable.sol | 222 + .../extensions/GovernorCountingSimple.sol | 96 + .../extensions/GovernorNoncesKeyed.sol | 91 + .../extensions/GovernorPreventLateQuorum.sol | 92 + .../extensions/GovernorProposalGuardian.sol | 58 + .../GovernorSequentialProposalId.sol | 75 + .../extensions/GovernorSettings.sol | 106 + .../governance/extensions/GovernorStorage.sol | 125 + .../extensions/GovernorSuperQuorum.sol | 58 + .../extensions/GovernorTimelockAccess.sol | 346 + .../extensions/GovernorTimelockCompound.sol | 165 + .../extensions/GovernorTimelockControl.sol | 167 + .../governance/extensions/GovernorVotes.sol | 63 + .../GovernorVotesQuorumFraction.sol | 113 + .../GovernorVotesSuperQuorumFraction.sol | 134 + .../contracts/governance/utils/IVotes.sol | 59 + .../contracts/governance/utils/Votes.sol | 252 + .../governance/utils/VotesExtended.sol | 84 + .../contracts/interfaces/IERC1155.sol | 6 + .../interfaces/IERC1155MetadataURI.sol | 6 + .../contracts/interfaces/IERC1155Receiver.sol | 6 + .../contracts/interfaces/IERC1271.sol | 17 + .../contracts/interfaces/IERC1363.sol | 86 + .../contracts/interfaces/IERC1363Receiver.sol | 32 + .../contracts/interfaces/IERC1363Spender.sol | 26 + .../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 | 26 + .../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/IERC7913.sol | 18 + .../contracts/interfaces/README.adoc | 102 + .../contracts/interfaces/draft-IERC1822.sol | 20 + .../contracts/interfaces/draft-IERC4337.sol | 253 + .../contracts/interfaces/draft-IERC6093.sol | 161 + .../contracts/interfaces/draft-IERC6909.sol | 125 + .../contracts/interfaces/draft-IERC7579.sol | 226 + .../contracts/interfaces/draft-IERC7674.sol | 17 + .../contracts/interfaces/draft-IERC7802.sol | 31 + .../contracts/interfaces/draft-IERC7821.sol | 44 + .../contracts/metatx/ERC2771Context.sol | 90 + .../contracts/metatx/ERC2771Forwarder.sol | 372 + .../contracts/metatx/README.adoc | 17 + .../contracts/mocks/AccessManagedTarget.sol | 34 + .../contracts/mocks/AccessManagerMock.sol | 20 + .../contracts/mocks/ArraysMock.sol | 171 + .../contracts/mocks/AuthorityMock.sol | 69 + .../contracts/mocks/Base64Dirty.sol | 19 + .../contracts/mocks/BatchCaller.sol | 20 + .../contracts/mocks/CallReceiverMock.sol | 78 + .../contracts/mocks/ConstructorMock.sol | 34 + .../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 | 28 + .../mocks/ERC3156FlashBorrowerMock.sol | 53 + .../contracts/mocks/EtherReceiverMock.sol | 17 + .../contracts/mocks/InitializableMock.sol | 130 + .../mocks/MerkleProofCustomHashMock.sol | 62 + .../contracts/mocks/MerkleTreeMock.sol | 52 + .../contracts/mocks/MulticallHelper.sol | 23 + .../MultipleInheritanceInitializableMocks.sol | 131 + .../contracts/mocks/PausableMock.sol | 31 + .../contracts/mocks/ReentrancyAttack.sol | 12 + .../contracts/mocks/ReentrancyMock.sol | 50 + .../mocks/ReentrancyTransientMock.sol | 50 + .../mocks/RegressionImplementation.sol | 61 + .../SingleInheritanceInitializableMocks.sol | 49 + .../contracts/mocks/Stateless.sol | 53 + .../contracts/mocks/StorageSlotMock.sol | 87 + .../contracts/mocks/TimelockReentrant.sol | 26 + .../contracts/mocks/TransientSlotMock.sol | 61 + .../contracts/mocks/UpgradeableBeaconMock.sol | 27 + .../contracts/mocks/VotesExtendedMock.sol | 42 + .../contracts/mocks/VotesMock.sol | 42 + .../contracts/mocks/account/AccountMock.sol | 169 + .../mocks/account/modules/ERC7579Mock.sol | 115 + .../mocks/account/utils/ERC7579UtilsMock.sol | 23 + .../contracts/mocks/compound/CompTimelock.sol | 174 + .../mocks/docs/ERC20WithAutoMinerReward.sol | 22 + .../contracts/mocks/docs/ERC4626Fees.sol | 109 + .../contracts/mocks/docs/MyNFT.sol | 9 + .../AccessControlERC20MintBase.sol | 25 + .../AccessControlERC20MintMissing.sol | 24 + .../AccessControlERC20MintOnlyRole.sol | 23 + .../access-control/AccessControlModified.sol | 14 + .../AccessManagedERC20MintBase.sol | 16 + .../docs/access-control/MyContractOwnable.sol | 17 + .../mocks/docs/account/MyAccountERC7702.sol | 20 + .../mocks/docs/account/MyFactoryAccount.sol | 37 + .../mocks/docs/governance/MyGovernor.sol | 80 + .../mocks/docs/governance/MyToken.sol | 21 + .../docs/governance/MyTokenTimestampBased.sol | 32 + .../mocks/docs/governance/MyTokenWrapped.sol | 28 + .../mocks/docs/token/ERC1155/GameItems.sol | 21 + .../token/ERC1155/MyERC115HolderContract.sol | 7 + .../mocks/docs/token/ERC20/GLDToken.sol | 11 + .../docs/token/ERC6909/ERC6909GameItems.sol | 26 + .../mocks/docs/token/ERC721/GameItem.sol | 19 + .../mocks/docs/utilities/Base64NFT.sol | 27 + .../mocks/docs/utilities/Multicall.sol | 15 + .../GovernorCountingOverridableMock.sol | 18 + .../governance/GovernorFractionalMock.sol | 14 + .../mocks/governance/GovernorMock.sol | 14 + .../governance/GovernorNoncesKeyedMock.sol | 45 + .../GovernorPreventLateQuorumMock.sol | 40 + .../GovernorProposalGuardianMock.sol | 27 + .../GovernorSequentialProposalIdMock.sol | 39 + .../mocks/governance/GovernorStorageMock.sol | 79 + .../governance/GovernorSuperQuorumMock.sol | 95 + .../governance/GovernorTimelockAccessMock.sol | 70 + .../GovernorTimelockCompoundMock.sol | 69 + .../GovernorTimelockControlMock.sol | 69 + .../mocks/governance/GovernorVoteMock.sol | 20 + .../GovernorVotesSuperQuorumFractionMock.sol | 37 + .../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/ERC1363ForceApproveMock.sol | 13 + .../mocks/token/ERC1363NoReturnMock.sol | 33 + .../mocks/token/ERC1363ReceiverMock.sol | 52 + .../mocks/token/ERC1363ReturnFalseMock.sol | 34 + .../mocks/token/ERC1363SpenderMock.sol | 47 + .../mocks/token/ERC20ApprovalMock.sol | 10 + .../mocks/token/ERC20BridgeableMock.sol | 26 + .../mocks/token/ERC20DecimalsMock.sol | 17 + .../mocks/token/ERC20ExcessDecimalsMock.sol | 9 + .../mocks/token/ERC20FlashMintMock.sol | 26 + .../mocks/token/ERC20ForceApproveMock.sol | 13 + .../mocks/token/ERC20GetterHelper.sol | 38 + .../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 + .../ERC20VotesAdditionalCheckpointsMock.sol | 31 + .../mocks/token/ERC20VotesLegacyMock.sol | 253 + .../mocks/token/ERC20VotesTimestampMock.sol | 29 + .../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 + .../mocks/utils/cryptography/ERC7739Mock.sol | 13 + .../contracts/package.json | 32 + .../contracts/proxy/Clones.sol | 294 + .../contracts/proxy/ERC1967/ERC1967Proxy.sol | 40 + .../contracts/proxy/ERC1967/ERC1967Utils.sol | 177 + .../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 | 118 + .../contracts/proxy/utils/Initializable.sol | 238 + .../contracts/proxy/utils/UUPSUpgradeable.sol | 146 + .../contracts/token/ERC1155/ERC1155.sol | 389 + .../contracts/token/ERC1155/IERC1155.sol | 123 + .../token/ERC1155/IERC1155Receiver.sol | 59 + .../contracts/token/ERC1155/README.adoc | 43 + .../ERC1155/extensions/ERC1155Burnable.sol | 28 + .../ERC1155/extensions/ERC1155Pausable.sol | 38 + .../ERC1155/extensions/ERC1155Supply.sol | 88 + .../ERC1155/extensions/ERC1155URIStorage.sol | 61 + .../extensions/IERC1155MetadataURI.sol | 20 + .../token/ERC1155/utils/ERC1155Holder.sol | 40 + .../token/ERC1155/utils/ERC1155Utils.sol | 88 + .../contracts/token/ERC20/ERC20.sol | 305 + .../contracts/token/ERC20/IERC20.sol | 79 + .../contracts/token/ERC20/README.adoc | 78 + .../token/ERC20/extensions/ERC1363.sol | 135 + .../token/ERC20/extensions/ERC20Burnable.sol | 39 + .../token/ERC20/extensions/ERC20Capped.sol | 54 + .../token/ERC20/extensions/ERC20FlashMint.sol | 134 + .../token/ERC20/extensions/ERC20Pausable.sol | 33 + .../token/ERC20/extensions/ERC20Permit.sol | 77 + .../token/ERC20/extensions/ERC20Votes.sol | 83 + .../token/ERC20/extensions/ERC20Wrapper.sol | 89 + .../token/ERC20/extensions/ERC4626.sol | 282 + .../token/ERC20/extensions/IERC20Metadata.sol | 26 + .../token/ERC20/extensions/IERC20Permit.sol | 90 + .../extensions/draft-ERC20Bridgeable.sol | 51 + .../draft-ERC20TemporaryApproval.sol | 119 + .../token/ERC20/utils/ERC1363Utils.sol | 95 + .../contracts/token/ERC20/utils/SafeERC20.sol | 212 + .../contracts/token/ERC6909/README.adoc | 27 + .../contracts/token/ERC6909/draft-ERC6909.sol | 224 + .../extensions/draft-ERC6909ContentURI.sol | 53 + .../extensions/draft-ERC6909Metadata.sol | 77 + .../extensions/draft-ERC6909TokenSupply.sol | 35 + .../contracts/token/ERC721/ERC721.sol | 430 + .../contracts/token/ERC721/IERC721.sol | 135 + .../token/ERC721/IERC721Receiver.sol | 28 + .../contracts/token/ERC721/README.adoc | 69 + .../ERC721/extensions/ERC721Burnable.sol | 26 + .../ERC721/extensions/ERC721Consecutive.sol | 176 + .../ERC721/extensions/ERC721Enumerable.sol | 164 + .../ERC721/extensions/ERC721Pausable.sol | 37 + .../token/ERC721/extensions/ERC721Royalty.sol | 26 + .../ERC721/extensions/ERC721URIStorage.sol | 58 + .../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 + .../token/ERC721/utils/ERC721Utils.sol | 50 + .../contracts/token/common/ERC2981.sol | 139 + .../contracts/token/common/README.adoc | 10 + .../contracts/utils/Address.sol | 149 + .../contracts/utils/Arrays.sol | 552 + .../contracts/utils/Base64.sol | 119 + .../contracts/utils/Blockhash.sol | 53 + .../contracts/utils/Bytes.sol | 113 + .../contracts/utils/CAIP10.sol | 54 + .../contracts/utils/CAIP2.sol | 51 + .../contracts/utils/Calldata.sol | 25 + .../contracts/utils/Comparators.sol | 19 + .../contracts/utils/Context.sol | 28 + .../contracts/utils/Create2.sol | 92 + .../contracts/utils/Errors.sol | 34 + .../contracts/utils/Multicall.sol | 37 + .../contracts/utils/Nonces.sol | 46 + .../contracts/utils/NoncesKeyed.sol | 74 + .../contracts/utils/Packing.sol | 1656 ++ .../contracts/utils/Panic.sol | 57 + .../contracts/utils/Pausable.sol | 112 + .../contracts/utils/README.adoc | 139 + .../contracts/utils/ReentrancyGuard.sol | 87 + .../utils/ReentrancyGuardTransient.sol | 61 + .../contracts/utils/ShortStrings.sol | 122 + .../contracts/utils/SlotDerivation.sol | 155 + .../contracts/utils/StorageSlot.sol | 143 + .../contracts/utils/Strings.sol | 490 + .../contracts/utils/TransientSlot.sol | 183 + .../contracts/utils/cryptography/ECDSA.sol | 180 + .../contracts/utils/cryptography/EIP712.sol | 160 + .../contracts/utils/cryptography/Hashes.sol | 31 + .../utils/cryptography/MerkleProof.sol | 514 + .../utils/cryptography/MessageHashUtils.sol | 99 + .../contracts/utils/cryptography/P256.sol | 408 + .../contracts/utils/cryptography/README.adoc | 67 + .../contracts/utils/cryptography/RSA.sol | 154 + .../utils/cryptography/SignatureChecker.sol | 135 + .../utils/cryptography/draft-ERC7739Utils.sol | 207 + .../cryptography/signers/AbstractSigner.sol | 23 + .../signers/MultiSignerERC7913.sol | 252 + .../signers/MultiSignerERC7913Weighted.sol | 208 + .../cryptography/signers/SignerECDSA.sol | 56 + .../cryptography/signers/SignerERC7702.sol | 25 + .../cryptography/signers/SignerERC7913.sol | 63 + .../utils/cryptography/signers/SignerP256.sol | 64 + .../utils/cryptography/signers/SignerRSA.sol | 65 + .../cryptography/signers/draft-ERC7739.sol | 99 + .../verifiers/ERC7913P256Verifier.sol | 29 + .../verifiers/ERC7913RSAVerifier.sol | 23 + .../contracts/utils/introspection/ERC165.sol | 25 + .../utils/introspection/ERC165Checker.sol | 124 + .../contracts/utils/introspection/IERC165.sol | 25 + .../contracts/utils/math/Math.sol | 749 + .../contracts/utils/math/SafeCast.sol | 1162 ++ .../contracts/utils/math/SignedMath.sol | 68 + .../contracts/utils/structs/BitMaps.sol | 60 + .../contracts/utils/structs/Checkpoints.sol | 630 + .../utils/structs/CircularBuffer.sol | 140 + .../utils/structs/DoubleEndedQueue.sol | 156 + .../contracts/utils/structs/EnumerableMap.sol | 1319 ++ .../contracts/utils/structs/EnumerableSet.sol | 792 + .../contracts/utils/structs/Heap.sol | 256 + .../contracts/utils/structs/MerkleTree.sol | 267 + .../contracts/utils/types/Time.sol | 133 + .../vendor/compound/ICompoundTimelock.sol | 86 + .../contracts/vendor/compound/LICENSE | 11 + .../lib/openzeppelin-contracts/docs/README.md | 16 + .../openzeppelin-contracts/docs/antora.yml | 7 + .../lib/openzeppelin-contracts/docs/config.js | 21 + .../ROOT/images/access-control-multiple.svg | 97 + .../ROOT/images/access-manager-functions.svg | 47 + .../modules/ROOT/images/access-manager.svg | 99 + .../modules/ROOT/images/erc4626-attack-3a.png | Bin 0 -> 60433 bytes .../modules/ROOT/images/erc4626-attack-3b.png | Bin 0 -> 66184 bytes .../modules/ROOT/images/erc4626-attack-6.png | Bin 0 -> 56290 bytes .../modules/ROOT/images/erc4626-attack.png | Bin 0 -> 58886 bytes .../modules/ROOT/images/erc4626-deposit.png | Bin 0 -> 115497 bytes .../docs/modules/ROOT/images/erc4626-mint.png | Bin 0 -> 112787 bytes .../ROOT/images/erc4626-rate-linear.png | Bin 0 -> 50813 bytes .../ROOT/images/erc4626-rate-loglog.png | Bin 0 -> 72818 bytes .../ROOT/images/erc4626-rate-loglogext.png | Bin 0 -> 109923 bytes .../docs/modules/ROOT/images/tally-exec.png | Bin 0 -> 231859 bytes .../docs/modules/ROOT/images/tally-vote.png | Bin 0 -> 40507 bytes .../docs/modules/ROOT/nav.adoc | 29 + .../modules/ROOT/pages/access-control.adoc | 288 + .../ROOT/pages/account-abstraction.adoc | 100 + .../docs/modules/ROOT/pages/accounts.adoc | 354 + .../ROOT/pages/backwards-compatibility.adoc | 50 + .../modules/ROOT/pages/eoa-delegation.adoc | 143 + .../docs/modules/ROOT/pages/erc1155.adoc | 118 + .../docs/modules/ROOT/pages/erc20-supply.adoc | 71 + .../docs/modules/ROOT/pages/erc20.adoc | 67 + .../docs/modules/ROOT/pages/erc4626.adoc | 214 + .../docs/modules/ROOT/pages/erc6909.adoc | 47 + .../docs/modules/ROOT/pages/erc721.adoc | 58 + .../ROOT/pages/extending-contracts.adoc | 51 + .../docs/modules/ROOT/pages/faq.adoc | 13 + .../docs/modules/ROOT/pages/governance.adoc | 239 + .../docs/modules/ROOT/pages/index.adoc | 70 + .../docs/modules/ROOT/pages/multisig.adoc | 306 + .../docs/modules/ROOT/pages/tokens.adoc | 31 + .../docs/modules/ROOT/pages/upgradeable.adoc | 77 + .../docs/modules/ROOT/pages/utilities.adoc | 559 + .../docs/modules/ROOT/pages/wizard.adoc | 15 + .../docs/templates/contract.hbs | 141 + .../docs/templates/helpers.js | 46 + .../docs/templates/page.hbs | 4 + .../docs/templates/properties.js | 88 + .../openzeppelin-contracts/eslint.config.mjs | 26 + .../lib/openzeppelin-contracts/foundry.toml | 15 + .../fv-requirements.txt | 4 + .../openzeppelin-contracts/hardhat.config.js | 124 + .../hardhat/async-test-sanity.js | 10 + .../hardhat/common-contracts.js | 69 + .../hardhat/env-artifacts.js | 29 + .../hardhat/ignore-unreachable-warnings.js | 45 + .../hardhat/remappings.js | 18 + .../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 | 356 + .../lib/erc4626-tests/LICENSE | 661 + .../lib/erc4626-tests/README.md | 116 + .../lib/forge-std/.gitattributes | 1 + .../lib/forge-std/.github/workflows/ci.yml | 128 + .../lib/forge-std/.github/workflows/sync.yml | 31 + .../lib/forge-std/.gitignore | 4 + .../lib/forge-std/CONTRIBUTING.md | 193 + .../lib/forge-std/LICENSE-APACHE | 203 + .../lib/forge-std/LICENSE-MIT | 25 + .../lib/forge-std/README.md | 266 + .../lib/forge-std/foundry.toml | 23 + .../lib/forge-std/package.json | 16 + .../lib/forge-std/scripts/vm.py | 646 + .../lib/forge-std/src/Base.sol | 35 + .../lib/forge-std/src/Script.sol | 27 + .../lib/forge-std/src/StdAssertions.sol | 669 + .../lib/forge-std/src/StdChains.sol | 287 + .../lib/forge-std/src/StdCheats.sol | 829 + .../lib/forge-std/src/StdError.sol | 15 + .../lib/forge-std/src/StdInvariant.sol | 122 + .../lib/forge-std/src/StdJson.sol | 283 + .../lib/forge-std/src/StdMath.sol | 43 + .../lib/forge-std/src/StdStorage.sol | 473 + .../lib/forge-std/src/StdStyle.sol | 333 + .../lib/forge-std/src/StdToml.sol | 283 + .../lib/forge-std/src/StdUtils.sol | 209 + .../lib/forge-std/src/Test.sol | 33 + .../lib/forge-std/src/Vm.sol | 2263 +++ .../lib/forge-std/src/console.sol | 1560 ++ .../lib/forge-std/src/console2.sol | 4 + .../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/src/safeconsole.sol | 13937 ++++++++++++++++ .../lib/forge-std/test/StdAssertions.t.sol | 141 + .../lib/forge-std/test/StdChains.t.sol | 227 + .../lib/forge-std/test/StdCheats.t.sol | 618 + .../lib/forge-std/test/StdError.t.sol | 120 + .../lib/forge-std/test/StdJson.t.sol | 49 + .../lib/forge-std/test/StdMath.t.sol | 202 + .../lib/forge-std/test/StdStorage.t.sol | 488 + .../lib/forge-std/test/StdStyle.t.sol | 110 + .../lib/forge-std/test/StdToml.t.sol | 49 + .../lib/forge-std/test/StdUtils.t.sol | 342 + .../lib/forge-std/test/Vm.t.sol | 18 + .../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/forge-std/test/fixtures/test.json | 8 + .../lib/forge-std/test/fixtures/test.toml | 6 + .../lib/halmos-cheatcodes/LICENSE | 661 + .../lib/halmos-cheatcodes/README.md | 97 + .../lib/halmos-cheatcodes/src/SVM.sol | 49 + .../lib/halmos-cheatcodes/src/SymTest.sol | 11 + .../lib/openzeppelin-contracts/logo.svg | 15 + .../lib/openzeppelin-contracts/netlify.toml | 3 + .../openzeppelin-contracts/package-lock.json | 10552 ++++++++++++ .../lib/openzeppelin-contracts/package.json | 104 + .../lib/openzeppelin-contracts/remappings.txt | 1 + .../lib/openzeppelin-contracts/renovate.json | 4 + .../scripts/checks/compare-layout.js | 20 + .../scripts/checks/compareGasReports.js | 247 + .../scripts/checks/coverage.sh | 24 + .../scripts/checks/extract-layout.js | 38 + .../scripts/checks/generation.sh | 6 + .../scripts/checks/inheritance-ordering.js | 55 + .../scripts/checks/pragma-consistency.js | 49 + .../scripts/fetch-common-contracts.js | 50 + .../openzeppelin-contracts/scripts/gen-nav.js | 81 + .../scripts/generate/format-lines.js | 16 + .../scripts/generate/helpers/sanitize.js | 5 + .../scripts/generate/run.js | 61 + .../scripts/generate/templates/Arrays.js | 386 + .../scripts/generate/templates/Arrays.opts.js | 9 + .../scripts/generate/templates/Checkpoints.js | 242 + .../generate/templates/Checkpoints.opts.js | 17 + .../generate/templates/Checkpoints.t.js | 137 + .../generate/templates/Enumerable.opts.js | 53 + .../generate/templates/EnumerableMap.js | 463 + .../generate/templates/EnumerableSet.js | 469 + .../scripts/generate/templates/MerkleProof.js | 187 + .../generate/templates/MerkleProof.opts.js | 11 + .../scripts/generate/templates/Packing.js | 92 + .../generate/templates/Packing.opts.js | 3 + .../scripts/generate/templates/Packing.t.js | 48 + .../scripts/generate/templates/SafeCast.js | 136 + .../scripts/generate/templates/Slot.opts.js | 15 + .../generate/templates/SlotDerivation.js | 119 + .../generate/templates/SlotDerivation.t.js | 127 + .../scripts/generate/templates/StorageSlot.js | 77 + .../generate/templates/StorageSlotMock.js | 57 + .../generate/templates/TransientSlot.js | 80 + .../generate/templates/TransientSlotMock.js | 35 + .../scripts/generate/templates/conversion.js | 30 + .../scripts/git-user-config.sh | 6 + .../openzeppelin-contracts/scripts/helpers.js | 7 + .../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/set-max-old-space-size.sh | 10 + .../scripts/solhint-custom/index.js | 84 + .../scripts/solhint-custom/package.json | 8 + .../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 | 50 + .../scripts/upgradeable/upgradeable.patch | 398 + .../slither.config.json | 4 + .../openzeppelin-contracts/solhint.config.js | 29 + .../openzeppelin-contracts/test/TESTING.md | 3 + .../test/access/AccessControl.behavior.js | 874 + .../test/access/AccessControl.test.js | 19 + .../test/access/Ownable.test.js | 79 + .../test/access/Ownable2Step.test.js | 102 + .../AccessControlDefaultAdminRules.test.js | 32 + .../AccessControlEnumerable.test.js | 24 + .../test/access/manager/AccessManaged.test.js | 146 + .../access/manager/AccessManager.behavior.js | 257 + .../access/manager/AccessManager.predicate.js | 456 + .../test/access/manager/AccessManager.test.js | 2489 +++ .../access/manager/AuthorityUtils.test.js | 112 + .../test/account/Account.behavior.js | 144 + .../test/account/Account.test.js | 48 + .../test/account/AccountECDSA.test.js | 52 + .../test/account/AccountERC7702.t.sol | 97 + .../test/account/AccountERC7702.test.js | 52 + .../test/account/AccountERC7913.test.js | 116 + .../test/account/AccountMultiSigner.test.js | 326 + .../AccountMultiSignerWeighted.test.js | 312 + .../test/account/AccountP256.test.js | 58 + .../test/account/AccountRSA.test.js | 58 + .../AccountERC7702WithModulesMock.test.js | 99 + .../extensions/AccountERC7579.behavior.js | 563 + .../account/extensions/AccountERC7579.test.js | 60 + .../extensions/AccountERC7579Hooked.test.js | 60 + .../account/extensions/ERC7821.behavior.js | 145 + .../test/account/utils/EIP7702Utils.test.js | 53 + .../account/utils/draft-ERC4337Utils.test.js | 289 + .../account/utils/draft-ERC7579Utils.t.sol | 418 + .../account/utils/draft-ERC7579Utils.test.js | 399 + .../test/bin/EntryPoint070.abi | 1 + .../test/bin/EntryPoint070.bytecode | Bin 0 -> 16035 bytes .../test/bin/EntryPoint080.abi | 1 + .../test/bin/EntryPoint080.bytecode | Bin 0 -> 21738 bytes .../test/bin/SenderCreator070.abi | 1 + .../test/bin/SenderCreator070.bytecode | Bin 0 -> 451 bytes .../test/bin/SenderCreator080.abi | 1 + .../test/bin/SenderCreator080.bytecode | Bin 0 -> 1217 bytes .../test/finance/VestingWallet.behavior.js | 87 + .../test/finance/VestingWallet.test.js | 65 + .../test/finance/VestingWalletCliff.test.js | 70 + .../test/governance/Governor.t.sol | 59 + .../test/governance/Governor.test.js | 980 ++ .../governance/TimelockController.test.js | 1279 ++ .../GovernorCountingFractional.test.js | 248 + .../GovernorCountingOverridable.test.js | 346 + .../extensions/GovernorERC721.test.js | 131 + .../extensions/GovernorNoncesKeyed.test.js | 244 + .../GovernorPreventLateQuorum.test.js | 185 + .../GovernorProposalGuardian.test.js | 132 + .../GovernorSequentialProposalId.test.js | 202 + .../extensions/GovernorStorage.test.js | 155 + .../extensions/GovernorSuperQuorum.test.js | 168 + ...GovernorSuperQuorumGreaterThanQuorum.t.sol | 79 + .../extensions/GovernorTimelockAccess.test.js | 864 + .../GovernorTimelockCompound.test.js | 448 + .../GovernorTimelockControl.test.js | 504 + .../GovernorVotesQuorumFraction.test.js | 165 + .../GovernorVotesSuperQuorumFraction.test.js | 160 + .../extensions/GovernorWithParams.test.js | 245 + .../test/governance/utils/ERC6372.behavior.js | 28 + .../test/governance/utils/Votes.behavior.js | 325 + .../test/governance/utils/Votes.test.js | 102 + .../governance/utils/VotesExtended.test.js | 152 + .../test/helpers/access-manager.js | 85 + .../test/helpers/account.js | 14 + .../test/helpers/chains.js | 109 + .../test/helpers/constants.js | 5 + .../test/helpers/deploy.js | 14 + .../test/helpers/eip712-types.js | 61 + .../test/helpers/eip712.js | 45 + .../test/helpers/enums.js | 14 + .../test/helpers/erc4337.js | 217 + .../test/helpers/erc7579.js | 58 + .../test/helpers/erc7739.js | 118 + .../test/helpers/governance.js | 217 + .../test/helpers/iterate.js | 41 + .../test/helpers/math.js | 33 + .../test/helpers/methods.js | 14 + .../test/helpers/precompiles.js | 12 + .../test/helpers/random.js | 24 + .../test/helpers/signers.js | 184 + .../test/helpers/storage.js | 48 + .../test/helpers/strings.js | 5 + .../test/helpers/time.js | 33 + .../test/helpers/txpool.js | 29 + .../test/metatx/ERC2771Context.test.js | 133 + .../test/metatx/ERC2771Forwarder.t.sol | 279 + .../test/metatx/ERC2771Forwarder.test.js | 384 + .../test/proxy/Clones.behaviour.js | 160 + .../test/proxy/Clones.t.sol | 91 + .../test/proxy/Clones.test.js | 177 + .../test/proxy/ERC1967/ERC1967Proxy.test.js | 23 + .../test/proxy/ERC1967/ERC1967Utils.test.js | 162 + .../test/proxy/Proxy.behaviour.js | 185 + .../test/proxy/beacon/BeaconProxy.test.js | 141 + .../proxy/beacon/UpgradeableBeacon.test.js | 55 + .../test/proxy/transparent/ProxyAdmin.test.js | 82 + .../TransparentUpgradeableProxy.behaviour.js | 357 + .../TransparentUpgradeableProxy.test.js | 28 + .../test/proxy/utils/Initializable.test.js | 216 + .../test/proxy/utils/UUPSUpgradeable.test.js | 120 + .../test/sanity.test.js | 27 + .../test/token/ERC1155/ERC1155.behavior.js | 763 + .../test/token/ERC1155/ERC1155.test.js | 213 + .../extensions/ERC1155Burnable.test.js | 66 + .../extensions/ERC1155Pausable.test.js | 105 + .../ERC1155/extensions/ERC1155Supply.test.js | 119 + .../extensions/ERC1155URIStorage.test.js | 70 + .../token/ERC1155/utils/ERC1155Holder.test.js | 56 + .../token/ERC1155/utils/ERC1155Utils.test.js | 299 + .../test/token/ERC20/ERC20.behavior.js | 269 + .../test/token/ERC20/ERC20.test.js | 199 + .../token/ERC20/extensions/ERC1363.test.js | 370 + .../ERC20/extensions/ERC20Burnable.test.js | 105 + .../ERC20/extensions/ERC20Capped.test.js | 55 + .../ERC20/extensions/ERC20FlashMint.test.js | 164 + .../ERC20/extensions/ERC20Pausable.test.js | 129 + .../ERC20/extensions/ERC20Permit.test.js | 109 + .../token/ERC20/extensions/ERC20Votes.test.js | 546 + .../ERC20/extensions/ERC20Wrapper.test.js | 203 + .../test/token/ERC20/extensions/ERC4626.t.sol | 41 + .../token/ERC20/extensions/ERC4626.test.js | 888 + .../extensions/draft-ERC20Bridgeable.test.js | 89 + .../draft-ERC20TemporaryApproval.test.js | 142 + .../test/token/ERC20/utils/SafeERC20.test.js | 463 + .../test/token/ERC6909/ERC6909.behavior.js | 216 + .../test/token/ERC6909/ERC6909.test.js | 104 + .../extensions/ERC6909ContentURI.test.js | 49 + .../extensions/ERC6909Metadata.test.js | 58 + .../extensions/ERC6909TokenSupply.test.js | 53 + .../test/token/ERC721/ERC721.behavior.js | 946 ++ .../test/token/ERC721/ERC721.test.js | 23 + .../token/ERC721/ERC721Enumerable.test.js | 28 + .../ERC721/extensions/ERC721Burnable.test.js | 77 + .../ERC721/extensions/ERC721Consecutive.t.sol | 181 + .../extensions/ERC721Consecutive.test.js | 228 + .../ERC721/extensions/ERC721Pausable.test.js | 81 + .../ERC721/extensions/ERC721Royalty.test.js | 57 + .../extensions/ERC721URIStorage.test.js | 121 + .../ERC721/extensions/ERC721Votes.test.js | 194 + .../ERC721/extensions/ERC721Wrapper.test.js | 201 + .../token/ERC721/utils/ERC721Holder.test.js | 20 + .../token/ERC721/utils/ERC721Utils.test.js | 94 + .../test/token/common/ERC2981.behavior.js | 152 + .../test/utils/Address.test.js | 281 + .../test/utils/Arrays.t.sol | 31 + .../test/utils/Arrays.test.js | 227 + .../test/utils/Base64.t.sol | 34 + .../test/utils/Base64.test.js | 59 + .../test/utils/Blockhash.t.sol | 100 + .../test/utils/Blockhash.test.js | 76 + .../test/utils/Bytes.t.sol | 117 + .../test/utils/Bytes.test.js | 104 + .../test/utils/CAIP.test.js | 53 + .../test/utils/Calldata.test.js | 22 + .../test/utils/Context.behavior.js | 48 + .../test/utils/Context.test.js | 18 + .../test/utils/Create2.t.sol | 17 + .../test/utils/Create2.test.js | 190 + .../test/utils/Multicall.test.js | 72 + .../test/utils/Nonces.behavior.js | 189 + .../test/utils/Nonces.test.js | 16 + .../test/utils/NoncesKeyed.test.js | 17 + .../test/utils/Packing.t.sol | 993 ++ .../test/utils/Packing.test.js | 70 + .../test/utils/Panic.test.js | 37 + .../test/utils/Pausable.test.js | 90 + .../test/utils/ReentrancyGuard.test.js | 50 + .../test/utils/ShortStrings.t.sol | 109 + .../test/utils/ShortStrings.test.js | 64 + .../test/utils/SlotDerivation.t.sol | 248 + .../test/utils/SlotDerivation.test.js | 58 + .../test/utils/StorageSlot.test.js | 73 + .../test/utils/Strings.t.sol | 50 + .../test/utils/Strings.test.js | 349 + .../test/utils/TransientSlot.test.js | 59 + .../test/utils/cryptography/ECDSA.test.js | 211 + .../test/utils/cryptography/EIP712.test.js | 105 + .../utils/cryptography/ERC1271.behavior.js | 111 + .../test/utils/cryptography/ERC7739.test.js | 42 + .../utils/cryptography/ERC7739Utils.test.js | 203 + .../utils/cryptography/MerkleProof.test.js | 213 + .../utils/cryptography/MessageHashUtils.t.sol | 33 + .../cryptography/MessageHashUtils.test.js | 97 + .../test/utils/cryptography/P256.t.sol | 65 + .../test/utils/cryptography/P256.test.js | 182 + .../test/utils/cryptography/RSA.helper.js | 17 + .../test/utils/cryptography/RSA.test.js | 102 + .../utils/cryptography/SigVer15_186-3.rsp | 3850 +++++ .../cryptography/SignatureChecker.test.js | 416 + .../ecdsa_secp256r1_sha256_p1363_test.json | 3719 +++++ .../test/utils/introspection/ERC165.test.js | 18 + .../utils/introspection/ERC165Checker.test.js | 245 + .../SupportsInterface.behavior.js | 166 + .../test/utils/math/Math.t.sol | 349 + .../test/utils/math/Math.test.js | 713 + .../test/utils/math/SafeCast.test.js | 159 + .../test/utils/math/SignedMath.t.sol | 80 + .../test/utils/math/SignedMath.test.js | 53 + .../test/utils/structs/BitMap.test.js | 149 + .../test/utils/structs/Checkpoints.t.sol | 332 + .../test/utils/structs/Checkpoints.test.js | 146 + .../test/utils/structs/CircularBuffer.test.js | 83 + .../utils/structs/DoubleEndedQueue.test.js | 102 + .../utils/structs/EnumerableMap.behavior.js | 214 + .../test/utils/structs/EnumerableMap.test.js | 83 + .../utils/structs/EnumerableSet.behavior.js | 175 + .../test/utils/structs/EnumerableSet.test.js | 66 + .../test/utils/structs/Heap.t.sol | 74 + .../test/utils/structs/Heap.test.js | 113 + .../test/utils/structs/MerkleTree.test.js | 180 + .../test/utils/types/Time.test.js | 135 + .../safe-singleton-deployer-sol/.gas-snapshot | 3 + .../.github/workflows/test.yml | 86 + .../safe-singleton-deployer-sol/.gitignore | 14 + .../safe-singleton-deployer-sol/.gitmodules | 3 + .../lib/safe-singleton-deployer-sol/README.md | 9 + .../safe-singleton-deployer-sol/foundry.toml | 6 + .../lib/forge-std/.gitattributes | 1 + .../lib/forge-std/.github/workflows/ci.yml | 134 + .../lib/forge-std/.github/workflows/sync.yml | 29 + .../lib/forge-std/.gitignore | 4 + .../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/package.json | 16 + .../lib/forge-std/scripts/vm.py | 635 + .../lib/forge-std/src/Base.sol | 35 + .../lib/forge-std/src/Script.sol | 27 + .../lib/forge-std/src/StdAssertions.sol | 669 + .../lib/forge-std/src/StdChains.sol | 250 + .../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 | 179 + .../lib/forge-std/src/StdMath.sol | 43 + .../lib/forge-std/src/StdStorage.sol | 473 + .../lib/forge-std/src/StdStyle.sol | 333 + .../lib/forge-std/src/StdToml.sol | 179 + .../lib/forge-std/src/StdUtils.sol | 226 + .../lib/forge-std/src/Test.sol | 33 + .../lib/forge-std/src/Vm.sol | 1638 ++ .../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 + .../forge-std/src/interfaces/IMulticall3.sol | 73 + .../lib/forge-std/src/mocks/MockERC20.sol | 234 + .../lib/forge-std/src/mocks/MockERC721.sol | 235 + .../lib/forge-std/src/safeconsole.sol | 13248 +++++++++++++++ .../lib/forge-std/test/StdAssertions.t.sol | 145 + .../lib/forge-std/test/StdChains.t.sol | 221 + .../lib/forge-std/test/StdCheats.t.sol | 618 + .../lib/forge-std/test/StdError.t.sol | 120 + .../lib/forge-std/test/StdJson.t.sol | 49 + .../lib/forge-std/test/StdMath.t.sol | 212 + .../lib/forge-std/test/StdStorage.t.sol | 463 + .../lib/forge-std/test/StdStyle.t.sol | 110 + .../lib/forge-std/test/StdToml.t.sol | 49 + .../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 + .../lib/forge-std/test/fixtures/test.json | 8 + .../lib/forge-std/test/fixtures/test.toml | 6 + .../lib/forge-std/test/mocks/MockERC20.t.sol | 441 + .../lib/forge-std/test/mocks/MockERC721.t.sol | 721 + .../scripts/ExampleDeploy.s.sol | 20 + .../src/SafeSingletonDeployer.sol | 92 + .../safe-singleton-deployer-sol/test/Mock.sol | 14 + .../test/MockReverting.sol | 10 + .../test/SafeSingletonDeployer.t.sol | 54 + .../script/CalculateStorageSlot.s.sol | 27 + .../account-modules/script/Deploy.s.sol | 85 + .../packages/account-modules/script/README.md | 42 + .../packages/account-modules/script/verify.sh | 41 + .../src/AutoCollectExecutor.sol | 558 + .../account-modules/src/AutoTopUpExecutor.sol | 551 + .../src/IAutoCollectExecutor.sol | 214 + .../src/IAutoTopUpExecutor.sol | 198 + .../AutoCollectExecutor.integration.t.sol | 675 + .../test/AutoCollectExecutor.t.sol | 1192 ++ .../test/AutoTopUpExecutor.integration.t.sol | 441 + .../test/AutoTopUpExecutor.t.sol | 941 ++ .../test/mocks/MaliciousCollectToken.sol | 32 + .../test/mocks/MaliciousToken.sol | 30 + .../account-modules/test/mocks/MockERC20.sol | 16 + .../account-modules/test/mocks/MockSafe.sol | 63 + .../test/mocks/MockTokenBadReturn.sol | 60 + .../test/mocks/MockTokenReturnsFalse.sol | 55 + .../account-modules/test/mocks/MockUSDT.sol | 54 + 1393 files changed, 245917 insertions(+) create mode 100644 .github/workflows/account-modules-ci.yml create mode 100644 .gitmodules create mode 100644 solidity/account-modules/.gitignore create mode 100644 solidity/account-modules/README.md create mode 100644 solidity/account-modules/docs/auto-collect/architecture.md create mode 100644 solidity/account-modules/docs/auto-top-up/architecture.md create mode 100644 solidity/account-modules/foundry.toml create mode 160000 solidity/account-modules/lib/BokkyPooBahsDateTimeLibrary create mode 160000 solidity/account-modules/lib/forge-std create mode 160000 solidity/account-modules/lib/modulekit create mode 160000 solidity/account-modules/lib/openzeppelin-contracts create mode 160000 solidity/account-modules/lib/safe-singleton-deployer-sol create mode 100644 solidity/account-modules/script/CalculateStorageSlot.s.sol create mode 100644 solidity/account-modules/script/Deploy.s.sol create mode 100644 solidity/account-modules/script/README.md create mode 100755 solidity/account-modules/script/verify.sh create mode 100644 solidity/account-modules/src/AutoCollectExecutor.sol create mode 100644 solidity/account-modules/src/AutoTopUpExecutor.sol create mode 100644 solidity/account-modules/src/IAutoCollectExecutor.sol create mode 100644 solidity/account-modules/src/IAutoTopUpExecutor.sol create mode 100644 solidity/account-modules/test/AutoCollectExecutor.integration.t.sol create mode 100644 solidity/account-modules/test/AutoCollectExecutor.t.sol create mode 100644 solidity/account-modules/test/AutoTopUpExecutor.integration.t.sol create mode 100644 solidity/account-modules/test/AutoTopUpExecutor.t.sol create mode 100644 solidity/account-modules/test/mocks/MaliciousCollectToken.sol create mode 100644 solidity/account-modules/test/mocks/MaliciousToken.sol create mode 100644 solidity/account-modules/test/mocks/MockERC20.sol create mode 100644 solidity/account-modules/test/mocks/MockSafe.sol create mode 100644 solidity/account-modules/test/mocks/MockTokenBadReturn.sol create mode 100644 solidity/account-modules/test/mocks/MockTokenReturnsFalse.sol create mode 100644 solidity/account-modules/test/mocks/MockUSDT.sol create mode 100644 typescript/packages/account-modules/.github/workflows/test.yml create mode 100644 typescript/packages/account-modules/.gitignore create mode 100644 typescript/packages/account-modules/README.md create mode 100644 typescript/packages/account-modules/docs/auto-collect/architecture.md create mode 100644 typescript/packages/account-modules/docs/auto-top-up/architecture.md create mode 100644 typescript/packages/account-modules/foundry.lock create mode 100644 typescript/packages/account-modules/foundry.toml create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitattributes create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitignore create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/LICENSE create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/README.md create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeContract.sol create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/TestDateTime.sol create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/BokkyPooBahsDateTimeContract_flattened_v1.00.sol create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/deployment-v1.00-prerelease.md create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/docs/ConvertingBetweenJulianDatesAndGregorianCalendarDates.pdf create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/docs/timestampFromDateTime.png create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/docs/timestampToDateTime.png create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/flattened/TestDateTime_flattened.sol create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/images/clocks.png create mode 100755 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/scripts/solidityFlattener.pl create mode 100755 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/00_runGeth.sh create mode 100755 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/01_test1.sh create mode 100755 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/02_attachGeth.sh create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.js create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.sol create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/README.md create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.js create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.sol create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/deploymentData.js create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/functions.js create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/genesis.json create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/settings create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1output.txt create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1results.txt create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-30.360937280Z--a00af22d07c87d96eeeb0ed583f8f6ac7812827e create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-58.104082316Z--a11aae29840fbb5c86e6fd4cf809eba183aef433 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-21.169063367Z--a22ab8a9d641ce77e06d98b7d7065d324d3d6976 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-41.707647638Z--a33a6c312d9ad0e0f2e95541beed0cc081621fd0 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-39-04.584040707Z--a44a08d3f6933c69212114bb66e2df1813651844 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-01.013666678Z--a55a151eb00fded1634d27d1127b4be4627079ea create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-37.426191216Z--a66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-58.899396047Z--a77a2b9d4b1c010a22a7c565dc418cef683dbcec create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-09.150580614Z--a88a05d2b88283ce84c8325760b72a64591279a2 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-34.770098207Z--a99a0ae3354c06b1459fd441a32a3f71005d7da0 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-17.400859858Z--aaaa9de1e6c564446ebca0fd102d8bd92093c756 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-35.122799190Z--abba43e7594e3b76afb157989e93c6621497fd4b create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-51.178332229Z--acca534c9f62ab495bd986e002ddf0f054caae4f create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-14.034178720Z--adda9b762a00ff12711113bfdc36958b73d7f915 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-33.471449656Z--aeea63b5479b50f79583ec49dacdcf86ddeff392 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-51.697690594Z--affa4d3a80add8ce4018540e056dacb649589394 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-46-38.500831000Z--b00bfde102270687324f9205b693859df64f8923 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-13.633282000Z--b11be1d4ef8e94d01cb2695092a79d139a8dad98 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-34.792913000Z--b22be2d9eef0d7e260cf96a64feea0b95ed3e74f create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-50-14.030093000Z--b33b7ecf5e47be3981c74d989d3af8b665b4b649 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-51-02.743266000Z--b44b43d59b738b088b690ae276c1e979aba8268d create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-16.250696000Z--b55b57d113b45481e31aaf03d6f4e5ad4ef325f8 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-56.678333000Z--b66bcb4e473de80e2c8a47ced10c22c705a5e602 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-55-56.546405000Z--b77bbbaa7c1649547ae61de4b80b91568c28351a create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-58-22.605806000Z--b88b728490b417e29b0784db30535db343830dba create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-59-11.614985000Z--b99b3d1f72edb05a0321db58eddcf83fd73c4ade create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-06.765694000Z--baab56da883edbe5314b8005be410022c510ccae create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-29.951106000Z--bbbb9809de0456ce0e0cd660e6e4ceabef3f521c create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-29.293263000Z--bccb68dd0ac87ef290aef49870d155f076c87868 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-54.216243000Z--bddb726ee06906e104db210e6d0506f2b062e477 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-08-54.756436000Z--beeb24ff18203658d0a1d4682ee3f36ad663ec87 create mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-09-53.679255000Z--bffbd8f029ef0bd81cf754b53e8b3a5684f8b3ff create mode 100644 typescript/packages/account-modules/lib/forge-std/.gitattributes create mode 100644 typescript/packages/account-modules/lib/forge-std/.github/CODEOWNERS create mode 100644 typescript/packages/account-modules/lib/forge-std/.github/workflows/ci.yml create mode 100644 typescript/packages/account-modules/lib/forge-std/.github/workflows/sync.yml create mode 100644 typescript/packages/account-modules/lib/forge-std/.gitignore create mode 100644 typescript/packages/account-modules/lib/forge-std/CONTRIBUTING.md create mode 100644 typescript/packages/account-modules/lib/forge-std/LICENSE-APACHE create mode 100644 typescript/packages/account-modules/lib/forge-std/LICENSE-MIT create mode 100644 typescript/packages/account-modules/lib/forge-std/README.md create mode 100644 typescript/packages/account-modules/lib/forge-std/foundry.toml create mode 100644 typescript/packages/account-modules/lib/forge-std/package.json create mode 100755 typescript/packages/account-modules/lib/forge-std/scripts/vm.py create mode 100644 typescript/packages/account-modules/lib/forge-std/src/Base.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/Script.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdAssertions.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdChains.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdCheats.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdConstants.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdError.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdInvariant.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdJson.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdMath.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdStorage.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdStyle.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdToml.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdUtils.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/Test.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/Vm.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/console.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/console2.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC1155.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC165.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC20.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC4626.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC6909.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC721.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7540.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7575.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IMulticall3.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/src/safeconsole.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/CommonBase.t.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdAssertions.t.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdChains.t.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdCheats.t.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdConstants.t.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdError.t.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdJson.t.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdMath.t.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdStorage.t.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdStyle.t.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdToml.t.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdUtils.t.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/Vm.t.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationScript.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationScriptBase.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationTest.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationTestBase.sol create mode 100644 typescript/packages/account-modules/lib/forge-std/test/fixtures/broadcast.log.json create mode 100644 typescript/packages/account-modules/lib/forge-std/test/fixtures/test.json create mode 100644 typescript/packages/account-modules/lib/forge-std/test/fixtures/test.toml create mode 100644 typescript/packages/account-modules/lib/modulekit/.changeset/README.md create mode 100644 typescript/packages/account-modules/lib/modulekit/.changeset/config.json create mode 100644 typescript/packages/account-modules/lib/modulekit/.env-example create mode 100644 typescript/packages/account-modules/lib/modulekit/.github/workflows/ci.yaml create mode 100644 typescript/packages/account-modules/lib/modulekit/.github/workflows/dependency.yml create mode 100644 typescript/packages/account-modules/lib/modulekit/.gitignore create mode 100644 typescript/packages/account-modules/lib/modulekit/.npmrc create mode 100644 typescript/packages/account-modules/lib/modulekit/.solhint.json create mode 100644 typescript/packages/account-modules/lib/modulekit/.solhintignore create mode 100644 typescript/packages/account-modules/lib/modulekit/CHANGELOG.md create mode 100644 typescript/packages/account-modules/lib/modulekit/README.md create mode 100644 typescript/packages/account-modules/lib/modulekit/docs/Accounts.md create mode 100644 typescript/packages/account-modules/lib/modulekit/foundry.toml create mode 100644 typescript/packages/account-modules/lib/modulekit/gas_calculations/.gitkeep create mode 100644 typescript/packages/account-modules/lib/modulekit/octanerc.json create mode 100644 typescript/packages/account-modules/lib/modulekit/package.json create mode 100644 typescript/packages/account-modules/lib/modulekit/pnpm-lock.yaml create mode 100644 typescript/packages/account-modules/lib/modulekit/remappings.txt create mode 100644 typescript/packages/account-modules/lib/modulekit/src/Accounts.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/Helpers.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/Integrations.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/Interfaces.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/Mocks.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/ModuleKit.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/Modules.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC4337Account.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Account.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Module.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/common/lib/ModeLib.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/ERC7579Factory.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/helpers/ExecutionHelper.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IERC7579Bootstrap.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IMSA.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/lib/ExecutionLib.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/factory/interface/IAccountFactory.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/factory/template/FactoryTemplate.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/KernelFactory.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccount.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccountExecute.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Account.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Module.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernel.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernelFactory.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IValidationManager.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ExecLib.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ValidationTypeLib.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/mock/MockFallback.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Constants.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Structs.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Types.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/NexusFactory.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexus.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusAccountFactory.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusBootstrap.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/SafeFactory.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7484.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7579Account.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579Launchpad.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeOp.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeProxyFactory.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/types/DataTypes.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/BytecodeDeployer.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/ERC7579Precompiles.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/KernelPrecompiles.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/NexusPrecompiles.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/Safe7579Precompiles.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/SmartSessionsPrecompiles.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/EntryPoint.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/MockFactory.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/Registry.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/registry/RegistryDeployer.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IERC7484.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalResolver.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalSchemaValidator.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IRegistry.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/registry/types/DataTypes.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/external/ERC4337.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/ERC20.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/ERC4626.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/ERC721.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/ERC7579Exec.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IBotRegistry.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDFSRegistry.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDSProxy.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC20.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC4626.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721Enumerable.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IFLParamGetter.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IGasToken.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ILendingPool.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IMCDPriceVerifier.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyERC20.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyRegistry.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISmartSession.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISubscriptions.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ITrigger.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IWETH.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/ICBETH.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IRETH.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IWstETH.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IAToken.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendToAaveMigrator.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPool.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPoolAddressesProvider.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IStkAave.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveIncentivesController.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveProtocolDataProviderV2.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolAddressesProviderV2.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolV2.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IPriceOracleGetterAave.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IStakedToken.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/DataTypes.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveProtocolDataProvider.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveV3Oracle.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IL2PoolV3.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolAddressesProvider.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolV3.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleGetter.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleSentinel.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsController.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsDistributor.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoanRecipient.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoans.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IMerkleRedeem.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IPool.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IVault.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/bprotocol/IBAMM.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IAggregatorV3.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IFeedRegistry.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IPhaseAggregator.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICToken.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICompoundOracle.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/IComptroller.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/IComet.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometExt.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometRewards.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBaseRewardPool.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBooster.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IConvexToken.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IRewardPool.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IAddressProvider.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurve3PoolZap.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurveFactory.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IDepositZap.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IFeeDistributor.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ILiquidityGauge.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IMinter.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IRegistry.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ISwaps.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IVotingEscrow.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/stethPool/ICurveStethPool.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curveusd/ICurveUsd.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/dydx/ISoloMargin.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IDToken.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IEulerMarkets.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeV3.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeWrapper.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IKyberNetworkProxy.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOasis.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOffchainWrapper.sol.bak create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IPair.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IQuoter.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/ISwapRouter.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IUniswapRouter.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashBorrower.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashLender.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IFlashLoanBase.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniPool.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniRouter02.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaAccountV2.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaIndex.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaMakerDAOMerkleDistributor.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IAggregationExecutor.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IExecutorHelper.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IMetaAggregationRouterV2.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/lido/IWStEth.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFT.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFTArtwork.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBorrowerOperations.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IChickenBondManager.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ICollSurplusPool.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IHintHelpers.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ILQTYStaking.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IPriceFeed.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ISortedTroves.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IStabilityPool.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ITroveManager.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICat.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICdpRegistry.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropJoin.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropper.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDSPause.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDaiJoin.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDssSpell.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGem.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGetCdps.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJoin.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJug.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IManager.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IOsm.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPipInterface.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPot.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ISpotter.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IVat.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorpho.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV2Lens.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV3.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IRewardsDistributor.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypes.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypesAaveV3.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/IBoostedVaultWithLockup.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ISavingsContractV2.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ImAsset.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IQiDaoRegistry.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IStablecoin.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundController.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundManager.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundProxy.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFuseAsset.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IBasicTokenAdapters.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ICoinJoin.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IFSMWrapper.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IGetSafes.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IMedianOracle.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IOracleRelayer.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEEngine.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEManager.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFESaviour.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ITaxCollector.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/spark/IsDAI.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/strategy/ISubStorage.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Factory.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Pair.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IQuoter.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/ISwapRouter.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Factory.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3FlashCallback.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3NonfungiblePositionManager.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Pool.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3SwapCallback.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYVault.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYearnRegistry.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/registry/ExampleFactory.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/registry/FactoryBase.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/MockUniswap.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/helpers/MainnetAddresses.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/v3/Uniswap.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC20.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC721.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC1271Policy.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7484RegistryAdapter.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ActionPolicy.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ExecutorBase.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579FallbackBase.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookBase.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestruct.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestructSingleHook.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HybridValidatorBase.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ModuleBase.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579PolicyBase.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579StatelessValidatorBase.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579UserOpPolicy.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorBase.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorMaster.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/SchedulingBase.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/Flashloan.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC1271.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC712.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC7484.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IPolicy.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IStatelessValidator.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockExecutor.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockFallback.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHook.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHookMultiPlexer.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHybridValidator.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockPolicy.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockRegistry.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockStatelessValidator.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockTarget.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockValidator.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579Constants.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579ValidatorLib.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/TrustedForwarder.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/Auxiliary.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/ModuleKitHelpers.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/RhinestoneModuleKit.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/helpers/ERC7579Helpers.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/helpers/HelperBase.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/helpers/KernelHelpers.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/helpers/NexusHelpers.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/helpers/SafeHelpers.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/helpers/SmartSessionHelpers.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/helpers/interfaces/IAccountModulesPaginated.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/ECDSA.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/ERC4337Helpers.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/Log.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/Storage.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/Vm.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasCalculations.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasParser.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/UserOpGasLog.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/test/BaseTest.t.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/test/Diff.t.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/test/GasCalculationsTest.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/test/RegistryDeployer.t.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/test/integrations/ExampleFactory.t.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/test/integrations/SmartSession.t.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/test/integrations/SwapTest.t.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1Validator.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1ValidatorUncompliantUninstall.sol create mode 100644 typescript/packages/account-modules/lib/modulekit/test/mocks/MockValidatorFalse.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.changeset/config.json create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.codecov.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.editorconfig create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/setup/action.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/storage-layout/action.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/actionlint.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/changeset.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/checks.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/docs.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/formal-verification.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/release-cycle.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/upgradeable.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.gitignore create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.gitmodules create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/.husky/pre-commit create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.mocharc.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.prettierrc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.solcover.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/CHANGELOG.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/CODE_OF_CONDUCT.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/CONTRIBUTING.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/FUNDING.json create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/GUIDELINES.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/LICENSE create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/README.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/RELEASING.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/SECURITY.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2017-03.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2018-10.pdf create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2022-10-Checkpoints.pdf create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2022-10-ERC4626.pdf create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2023-05-v4.9.pdf create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2023-10-v5.0.pdf create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2024-10-v5.1.pdf create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2024-12-v5.2.pdf create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2025-04-v5.3.pdf create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/README.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/.gitignore create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/Makefile create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/README.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/diff/access_manager_AccessManager.sol.patch create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessControlHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagedHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagerHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/DoubleEndedQueueHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20FlashMintHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20PermitHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20WrapperHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC3156FlashBorrowerHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC721Harness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC721ReceiverHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/EnumerableMapHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/EnumerableSetHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/InitializableHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/NoncesHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/Ownable2StepHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/OwnableHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/PausableHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/TimelockControllerHarness.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2021-10.pdf create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2022-03.pdf create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2022-05.pdf create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/run.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs.json create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessControl.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessControlDefaultAdminRules.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManaged.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManager.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/DoubleEndedQueue.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20FlashMint.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20Wrapper.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC721.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/EnumerableMap.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/EnumerableSet.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Initializable.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Nonces.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Ownable.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Ownable2Step.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Pausable.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/TimelockController.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/helpers/helpers.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessControl.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessControlDefaultAdminRules.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManaged.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManager.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC20.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC2612.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashBorrower.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashLender.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC5313.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC721.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC721Receiver.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IOwnable.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IOwnable2Step.spec create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/AccessControl.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/README.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlEnumerable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlDefaultAdminRules.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlEnumerable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManaged.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManager.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAuthority.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/Account.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/README.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579Hooked.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-ERC7821.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/EIP7702Utils.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC4337Utils.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC7579Utils.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/README.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWalletCliff.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/Governor.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/README.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingFractional.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingOverridable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorNoncesKeyed.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorProposalGuardian.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSequentialProposalId.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorStorage.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSuperQuorum.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockAccess.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/VotesExtended.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC7913.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/README.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC4337.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6909.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7579.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7674.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7802.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7821.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Forwarder.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/README.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagedTarget.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagerMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AuthorityMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Base64Dirty.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/BatchCaller.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ConstructorMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165InterfacesSupported.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleProofCustomHashMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleTreeMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MulticallHelper.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyTransientMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Stateless.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TimelockReentrant.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TransientSlotMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/UpgradeableBeaconMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesExtendedMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/AccountMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/modules/ERC7579Mock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/utils/ERC7579UtilsMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC20WithAutoMinerReward.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC4626Fees.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/MyNFT.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintBase.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintMissing.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintOnlyRole.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlModified.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessManagedERC20MintBase.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/MyContractOwnable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyAccountERC7702.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyFactoryAccount.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyGovernor.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyToken.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenTimestampBased.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenWrapped.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/GameItems.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/MyERC115HolderContract.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC20/GLDToken.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC6909/ERC6909GameItems.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC721/GameItem.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Base64NFT.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Multicall.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCountingOverridableMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorFractionalMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorNoncesKeyedMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorProposalGuardianMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSequentialProposalIdMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorStorageMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSuperQuorumMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockAccessMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVotesSuperQuorumFractionMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ForceApproveMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363NoReturnMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReceiverMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReturnFalseMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363SpenderMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ApprovalMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20BridgeableMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ExcessDecimalsMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ForceApproveMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20GetterHelper.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Reentrant.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesAdditionalCheckpointsMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesTimestampMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626LimitsMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626Mock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4646FeesMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/utils/cryptography/ERC7739Mock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/package.json create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Clones.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/README.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Utils.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC1363.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20Bridgeable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20TemporaryApproval.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/ERC1363Utils.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/README.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/draft-ERC6909.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909ContentURI.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909Metadata.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909TokenSupply.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Utils.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/README.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Address.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Arrays.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Base64.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Blockhash.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Bytes.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP10.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP2.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Calldata.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Comparators.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Context.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Create2.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Errors.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Multicall.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Nonces.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/NoncesKeyed.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Packing.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Panic.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Pausable.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/README.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuardTransient.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/SlotDerivation.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Strings.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/TransientSlot.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/Hashes.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/P256.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/README.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/RSA.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/draft-ERC7739Utils.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/AbstractSigner.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerECDSA.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7702.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7913.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerP256.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerRSA.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/draft-ERC7739.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913P256Verifier.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913RSAVerifier.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/Math.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/CircularBuffer.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Heap.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/MerkleTree.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/types/Time.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/README.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/antora.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/config.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-control-multiple.svg create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager-functions.svg create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager.svg create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack-3a.png create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack-3b.png create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack-6.png create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack.png create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-deposit.png create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-mint.png create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-rate-linear.png create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-rate-loglog.png create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-rate-loglogext.png create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/tally-exec.png create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/tally-vote.png create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/nav.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/access-control.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/account-abstraction.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/accounts.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/backwards-compatibility.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/eoa-delegation.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc1155.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20-supply.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc4626.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc6909.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc721.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/extending-contracts.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/faq.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/governance.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/index.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/multisig.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/tokens.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/upgradeable.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/utilities.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/wizard.adoc create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/contract.hbs create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/helpers.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/page.hbs create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/properties.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/eslint.config.mjs create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/foundry.toml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/fv-requirements.txt create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat.config.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/async-test-sanity.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/common-contracts.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/env-artifacts.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/remappings.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/task-test-get-files.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/README.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitattributes create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/sync.yml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitignore create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/CONTRIBUTING.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/README.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/foundry.toml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/package.json create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/scripts/vm.py create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Base.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Script.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdInvariant.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStyle.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdToml.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Test.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IMulticall3.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/safeconsole.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdJson.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStyle.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdToml.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/Vm.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/broadcast.log.json create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.json create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.toml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/LICENSE create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/README.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SVM.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SymTest.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/logo.svg create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/netlify.toml create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/package-lock.json create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/package.json create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/remappings.txt create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/renovate.json create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compare-layout.js create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/coverage.sh create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/extract-layout.js create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/generation.sh create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/pragma-consistency.js create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/fetch-common-contracts.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/gen-nav.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/format-lines.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/helpers/sanitize.js create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/run.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.opts.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.opts.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.t.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Enumerable.opts.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.opts.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.opts.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.t.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Slot.opts.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.t.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlotMock.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlot.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlotMock.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/conversion.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/git-user-config.sh create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/helpers.js create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/prepack.sh create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/prepare-docs.sh create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/format-changelog.js create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/synchronize-versions.js create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/update-comment.js create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/version.sh create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/github-release.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/integrity-check.sh create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/pack.sh create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/publish.sh create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/rerun.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/start.sh create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/state.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/set-max-old-space-size.sh create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/index.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/package.json create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/update-docs-branch.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/README.md create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/patch-apply.sh create mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/patch-save.sh create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile-onto.sh create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile.sh create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/upgradeable.patch create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/slither.config.json create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/solhint.config.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/TESTING.md create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlDefaultAdminRules.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlEnumerable.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManaged.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.predicate.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AuthorityUtils.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountECDSA.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7913.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSigner.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSignerWeighted.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountP256.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountRSA.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/examples/AccountERC7702WithModulesMock.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579Hooked.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/ERC7821.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/EIP7702Utils.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC4337Utils.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint070.abi create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint070.bytecode create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint080.abi create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint080.bytecode create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator070.abi create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator070.bytecode create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator080.abi create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator080.bytecode create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWalletCliff.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/TimelockController.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingFractional.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingOverridable.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorNoncesKeyed.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorProposalGuardian.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSequentialProposalId.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorStorage.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorum.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorumGreaterThanQuorum.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockAccess.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesSuperQuorumFraction.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/ERC6372.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/VotesExtended.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/access-manager.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/account.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/chains.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/constants.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/deploy.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712-types.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/enums.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc4337.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7579.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7739.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/governance.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/iterate.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/math.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/methods.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/precompiles.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/random.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/signers.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/storage.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/strings.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/time.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/txpool.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Utils.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/sanity.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Utils.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC1363.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Permit.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20Bridgeable.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20TemporaryApproval.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909ContentURI.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909Metadata.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909TokenSupply.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Utils.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Address.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/CAIP.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Calldata.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Multicall.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/NoncesKeyed.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Panic.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Pausable.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ReentrancyGuard.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/TransientSlot.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC1271.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739Utils.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.helper.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SigVer15_186-3.rsp create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ecdsa_secp256r1_sha256_p1363_test.json create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/CircularBuffer.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.t.sol create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/MerkleTree.test.js create mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/types/Time.test.js create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gas-snapshot create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.github/workflows/test.yml create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitignore create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitmodules create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/README.md create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/foundry.toml create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitattributes create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.github/workflows/ci.yml create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.github/workflows/sync.yml create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitignore create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/LICENSE-APACHE create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/LICENSE-MIT create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/README.md create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/foundry.toml create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/package.json create mode 100755 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/scripts/vm.py create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Base.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Script.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdAssertions.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdChains.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdCheats.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdError.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdInvariant.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdJson.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdMath.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStorage.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStyle.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdToml.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdUtils.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Test.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Vm.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/console.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/console2.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC1155.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC165.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC20.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC4626.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC721.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IMulticall3.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC20.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC721.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/safeconsole.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdAssertions.t.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdChains.t.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdCheats.t.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdError.t.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdJson.t.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdMath.t.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStorage.t.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStyle.t.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdToml.t.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdUtils.t.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/Vm.t.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationScript.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationScriptBase.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationTest.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationTestBase.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/broadcast.log.json create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.json create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.toml create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC20.t.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC721.t.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/scripts/ExampleDeploy.s.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/src/SafeSingletonDeployer.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/Mock.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/MockReverting.sol create mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/SafeSingletonDeployer.t.sol create mode 100644 typescript/packages/account-modules/script/CalculateStorageSlot.s.sol create mode 100644 typescript/packages/account-modules/script/Deploy.s.sol create mode 100644 typescript/packages/account-modules/script/README.md create mode 100755 typescript/packages/account-modules/script/verify.sh create mode 100644 typescript/packages/account-modules/src/AutoCollectExecutor.sol create mode 100644 typescript/packages/account-modules/src/AutoTopUpExecutor.sol create mode 100644 typescript/packages/account-modules/src/IAutoCollectExecutor.sol create mode 100644 typescript/packages/account-modules/src/IAutoTopUpExecutor.sol create mode 100644 typescript/packages/account-modules/test/AutoCollectExecutor.integration.t.sol create mode 100644 typescript/packages/account-modules/test/AutoCollectExecutor.t.sol create mode 100644 typescript/packages/account-modules/test/AutoTopUpExecutor.integration.t.sol create mode 100644 typescript/packages/account-modules/test/AutoTopUpExecutor.t.sol create mode 100644 typescript/packages/account-modules/test/mocks/MaliciousCollectToken.sol create mode 100644 typescript/packages/account-modules/test/mocks/MaliciousToken.sol create mode 100644 typescript/packages/account-modules/test/mocks/MockERC20.sol create mode 100644 typescript/packages/account-modules/test/mocks/MockSafe.sol create mode 100644 typescript/packages/account-modules/test/mocks/MockTokenBadReturn.sol create mode 100644 typescript/packages/account-modules/test/mocks/MockTokenReturnsFalse.sol create mode 100644 typescript/packages/account-modules/test/mocks/MockUSDT.sol diff --git a/.github/workflows/account-modules-ci.yml b/.github/workflows/account-modules-ci.yml new file mode 100644 index 0000000..ad4b175 --- /dev/null +++ b/.github/workflows/account-modules-ci.yml @@ -0,0 +1,49 @@ +name: Account Modules CI + +on: + pull_request: + paths: + - 'solidity/account-modules/**' + - '.github/workflows/account-modules-ci.yml' + workflow_dispatch: + +env: + FOUNDRY_PROFILE: ci + +jobs: + check: + name: Account Modules Foundry project + runs-on: ubuntu-latest + defaults: + run: + working-directory: solidity/account-modules + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: Show Forge version + run: | + forge --version + + - name: Install Node dependencies + run: | + cd lib/modulekit && npm install + + - name: Run Forge fmt + run: | + forge fmt --check + id: fmt + + - name: Run Forge build + run: | + forge build --sizes src/ + id: build + + - name: Run Forge tests + run: | + ACCOUNT_TYPE=SAFE forge test -vvv + id: test diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..53c9cf2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,15 @@ +[submodule "solidity/account-modules/lib/forge-std"] + path = solidity/account-modules/lib/forge-std + url = https://github.com/foundry-rs/forge-std +[submodule "solidity/account-modules/lib/modulekit"] + path = solidity/account-modules/lib/modulekit + url = https://github.com/pcarranzav/modulekit +[submodule "solidity/account-modules/lib/openzeppelin-contracts"] + path = solidity/account-modules/lib/openzeppelin-contracts + url = https://github.com/OpenZeppelin/openzeppelin-contracts +[submodule "solidity/account-modules/lib/BokkyPooBahsDateTimeLibrary"] + path = solidity/account-modules/lib/BokkyPooBahsDateTimeLibrary + url = https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary +[submodule "solidity/account-modules/lib/safe-singleton-deployer-sol"] + path = solidity/account-modules/lib/safe-singleton-deployer-sol + url = https://github.com/wilsoncusack/safe-singleton-deployer-sol diff --git a/solidity/account-modules/.gitignore b/solidity/account-modules/.gitignore new file mode 100644 index 0000000..3269660 --- /dev/null +++ b/solidity/account-modules/.gitignore @@ -0,0 +1,11 @@ +# Compiler files +cache/ +out/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Dotenv file +.env diff --git a/solidity/account-modules/README.md b/solidity/account-modules/README.md new file mode 100644 index 0000000..1e67976 --- /dev/null +++ b/solidity/account-modules/README.md @@ -0,0 +1,69 @@ +# Account Modules + +ERC-7579 compliant executor modules for smart account automation in the x402 payments system. + +## Modules + +### AutoTopUpModule +- Automatically tops up agent accounts when balance falls below threshold +- Configurable per-agent limits (daily, monthly) +- Permissionless triggering with proper checks +- Used by: Main accounts to fund agent accounts + +### AutoCollectModule +- Automatically collects payments from service accounts +- Configurable collection thresholds (amount and time) +- Batch collection optimization +- Used by: Service accounts to collect to main accounts + +## Architecture + +All modules implement the ERC-7579 executor module interface: +- `onInstall(bytes calldata data)` - Module installation +- `onUninstall(bytes calldata data)` - Module removal +- `isModuleType(uint256 typeID)` - Returns true for executor type (0x01) +- `isInitialized(address account)` - Check if module is initialized for account + +## Deployment + +The modules are deployed as immutable singletons using Safe's Singleton Factory, ensuring the same addresses across all chains: + +- **AutoTopUpExecutor**: `0x16f13052FbFFfcE34E5752b7F4CFF881a030F40B` +- **AutoCollectExecutor**: `0x29864bd91370886c38dE9Fe95F5589E7EbE15130` + +These addresses are deterministic and will remain consistent on all supported chains (Base, Base Sepolia, etc.). + +## Development + +### Prerequisites + +- [Foundry](https://book.getfoundry.sh/getting-started/installation) +- [pnpm](https://pnpm.io/installation) (for ModuleKit dependencies) + +### Setup + +```bash +# Install Forge dependencies +forge install + +# Install ModuleKit node dependencies (required for compilation) +cd lib/modulekit && npm install && cd ../.. + +# Build contracts +forge build + +# Run tests +forge test + +# Deploy +forge script script/Deploy.s.sol --rpc-url $RPC_URL --broadcast +``` + +**Important**: ModuleKit requires its node modules to be installed for proper compilation. This step (`pnpm install` in the modulekit directory) must be performed after cloning the repository and before building. + +## Security + +- Non-custodial design - modules only execute based on user-defined rules +- Access control via ERC-7579 standards +- Immutable singleton contracts - no upgradeability, no owner +- Comprehensive event logging \ No newline at end of file diff --git a/solidity/account-modules/docs/auto-collect/architecture.md b/solidity/account-modules/docs/auto-collect/architecture.md new file mode 100644 index 0000000..5da5185 --- /dev/null +++ b/solidity/account-modules/docs/auto-collect/architecture.md @@ -0,0 +1,252 @@ +# AutoCollectExecutor Architecture + +## Overview + +AutoCollectExecutor is an ERC-7579 executor module that automatically collects funds from service accounts to a main seller account. It mirrors the AutoTopUpExecutor pattern but reverses the transfer direction - collecting funds FROM the account where the module is installed TO a configured target account. + +## Key Design Principles + +1. **Installation Location**: Module is installed ON each service account (not on main account) +2. **Transfer Direction**: FROM service account (where module is installed) TO main account +3. **Permissionless Execution**: Anyone can trigger collections (gas incentives for automation) +4. **Calendar-Based Limits**: Collections limited to once per calendar day (UTC) +5. **Per-Asset Configuration**: Each token has its own collection configuration + +## Architecture Components + +### Storage Structure + +```solidity +// Configuration per asset +struct CollectConfig { + address target; // Main account to collect funds to + address asset; // ERC-20 token address + uint256 threshold; // Minimum balance to trigger collection (0 = no threshold) + uint256 minimumRemaining; // Minimum amount to leave in account (0 = collect all) + bool enabled; // Whether collection is enabled +} + +// State tracking per configuration +struct CollectState { + uint256 lastCollectDate; // Last collection date (YYYYMMDD format) +} + +// Storage mappings +mapping(uint256 => CollectConfig) configs; // configId => config +mapping(uint256 => CollectState) states; // configId => state +mapping(address => EnumerableSet.Bytes32Set) accountConfigs; // service account => configIds (using EnumerableSet) + +// Config ID generation (deterministic) +configId = keccak256(abi.encode("CollectConfig", serviceAccount, asset)) +``` + +### Core Functions + +#### Module Lifecycle +- `onInstall(bytes calldata data)` - Install with optional initial configurations +- `onUninstall(bytes calldata)` - Clean up all configurations and state +- `isModuleType(uint256 typeID)` - Returns MODULE_TYPE_EXECUTOR constant +- `isInitialized(address account)` - Check if module is initialized for account + +#### Configuration Management +- `configureCollection(address asset, CollectConfig config)` - Create/update config for msg.sender +- `enableCollection(bytes32 configId)` - Enable collection for a config +- `disableCollection(bytes32 configId)` - Disable collection for a config + +#### Collection Execution +- `triggerCollection(address account, address asset)` - Trigger collection for specific asset on account +- `triggerAllCollections(address account)` - Trigger all enabled collections for specific account +- `canExecuteCollection(address account, address asset)` - Check if collection can execute + +#### View Functions +- `getCollectionConfig(address account, address asset)` - Get specific config +- `getCollectionConfigs(address account)` - Get all configs for an account +- `getCollectionState(address account, address asset)` - Get collection state + +## Execution Flow + +### Collection Trigger Flow +``` +1. External caller → triggerCollection(account, asset) +2. Module validates: + - Configuration exists and is enabled for account + - Calendar day has changed since last collection + - Balance meets threshold (if threshold > 0) + - Balance >= minimumRemaining (can leave the required amount) + - collectAmount = balance - minimumRemaining > 0 +3. Module executes: + - Get current balance of asset in account + - Calculate collect amount: balance - minimumRemaining + - Transfer collect amount to configured target + - Leave minimumRemaining in account + - If transfer fails, emit CollectionSkipped event and continue + - Update lastCollectDate only on successful transfer +4. Emit CollectionExecuted or CollectionSkipped event +``` + +### Calendar Day Tracking +- Uses BokkyPooBah's DateTime Library (same as AutoTopUpExecutor) +- Dates encoded as YYYYMMDD (e.g., 20240829) +- All timestamps are UTC-based +- Prevents multiple collections per calendar day + +## Security Considerations + +1. **Access Control** + - Only service account (msg.sender) can configure its own collections + - Anyone can trigger collections (permissionless) + - Module can only transfer FROM the account it's installed on + +2. **Reentrancy Protection** + - CEI (Checks-Effects-Interactions) pattern + - State updates before external calls + - ReentrancyGuard on execution functions + +3. **Token Safety** + - Execute transfers via Safe's _execute() (like AutoTopUpExecutor) + - Handle non-standard token returns by checking returndata length + - Decode and validate return value if present + - Zero-value transfer protection + +## Events + +```solidity +event CollectionConfigured( + address indexed account, + address indexed asset, + address indexed target, + uint256 threshold +); + +event CollectionExecuted( + address indexed account, + address indexed asset, + address indexed target, + uint256 amount +); + +event CollectionSkipped( + address indexed account, + address indexed asset, + bytes32 indexed configId, + uint256 balance, + uint256 threshold, + uint256 minimumRemaining, + uint256 collectAmount +); + +event CollectionEnabled(address indexed account, address indexed asset); +event CollectionDisabled(address indexed account, address indexed asset); +``` + +## Edge Cases & Validation + +1. **Collection Validation** + - If balance < threshold: Skip collection, emit CollectionSkipped event + - If balance = 0: Skip collection, emit CollectionSkipped event + - If balance < minimumRemaining: Skip collection, emit CollectionSkipped event + - If balance - minimumRemaining = 0: Skip collection, emit CollectionSkipped event + - Threshold = 0 means trigger collection on any balance + - minimumRemaining = 0 means collect full balance (default behavior) + +2. **Valid Configurations** + - minimumRemaining > threshold: Valid (effective threshold is minimumRemaining) + - minimumRemaining = threshold: Valid (collect when balance exactly at or above threshold) + - minimumRemaining = 0, threshold = 0: Valid (collect any non-zero balance) + - minimumRemaining > 0, threshold = 0: Valid (collect when balance > minimumRemaining) + +3. **Invalid Configuration** + - Target cannot be zero address + - Asset must be valid ERC-20 contract + - Threshold and minimumRemaining can both be 0 + +3. **Date Boundaries** + - Month transitions handled correctly + - Year transitions handled correctly + - Leap years considered + +4. **Token Edge Cases** + - Non-standard return values (USDT) + - Tokens with transfer fees + - Balance changes between check and transfer (handled gracefully by skipping collection) + +## Gas Optimization + +1. **Storage Patterns** + - Separate config and state structs for efficient updates + - Pack struct fields for optimal storage slots + - Use mappings instead of arrays where possible + +2. **Execution Optimization** + - Calculate date once per execution + - Batch operations where possible + - Skip zero-balance collections early + +## Differences from AutoTopUpExecutor + +| Aspect | AutoTopUpExecutor | AutoCollectExecutor | +|--------|-------------------|---------------------| +| Installation | On main account | On service accounts | +| Transfer Direction | Main → Agent accounts | Service account → Main | +| Config Storage | Per (agent, asset) | Per (asset) on each account | +| Limits | Daily/Monthly amounts | Once per calendar day | +| Threshold | Top-up when below | Collect when above | +| Target | Multiple agents | Single main account | + +## Integration with Safe Accounts + +Service accounts will have AutoCollectExecutor installed as an ERC-7579 module: +```solidity +Safe Service Account +├── Owner: User's Privy Wallet +├── Modules: +│ └── AutoCollectExecutor +│ ├── Collection configs per asset +│ ├── Target: Main account (also owned by Privy wallet) +│ └── Thresholds and state +└── Holdings: USDC, other tokens (to be collected) +``` + +## Testing Strategy + +1. **Unit Tests** + - All configuration functions + - Collection execution logic + - Calendar day calculations + - Edge cases and error conditions + +2. **Integration Tests (ModuleKit)** + - Module installation/uninstallation + - Cross-account interactions + - Real Safe account testing + - Gas usage validation + +3. **Fuzz Testing** + - Date arithmetic edge cases + - Random threshold values + - Multiple asset scenarios + +## Implementation Notes + +### Upgradeability +- Use UUPS proxy pattern (same as AutoTopUpExecutor) +- OwnableUpgradeable for upgrade admin control +- ERC-7201 namespaced storage for upgrade safety + +### Dependencies +- BokkyPooBah's DateTime Library (already in lib/) +- OpenZeppelin contracts upgradeable (including EnumerableSet) +- ModuleKit for ERC-7579 compliance +- ERC7579ExecutorBase for _execute() functionality + +## Implementation Checklist + +- [ ] Core contract implementation (UUPS upgradeable) +- [ ] Interface extraction (IAutoCollectExecutor) +- [ ] Token transfer via _execute() with returndata validation +- [ ] Calendar-based date tracking with DateTime library +- [ ] Event and error definitions +- [ ] Unit tests following AutoTopUpExecutor.t.sol patterns +- [ ] Integration tests with ModuleKit +- [ ] Gas optimization and forge fmt +- [ ] Security review \ No newline at end of file diff --git a/solidity/account-modules/docs/auto-top-up/architecture.md b/solidity/account-modules/docs/auto-top-up/architecture.md new file mode 100644 index 0000000..6fc7821 --- /dev/null +++ b/solidity/account-modules/docs/auto-top-up/architecture.md @@ -0,0 +1,272 @@ +# AutoTopUpExecutor Module Architecture + +## Overview + +The AutoTopUpExecutor is an ERC-7579 executor module that enables automatic balance management for Safe smart accounts. It allows anyone to trigger pre-configured ERC-20 token transfers from a main Safe account to designated agent accounts when their balances fall below specified thresholds. + +## Core Design Principles + +### 1. Non-Custodial Architecture +- Module operates as part of the Safe's execution context +- Never holds funds directly +- User maintains full control over configuration and can disable at any time +- Executions happen through Safe's module system + +### 2. Permissionless Triggering +- Anyone can call the trigger function to execute configured top-ups +- Security enforced through on-chain configuration and limits +- Primary automation through our keeper infrastructure (with option for users to self-host) + +### 3. Multi-Agent Support +- Single module instance manages multiple agent configurations +- Each agent has independent thresholds, amounts, and limits +- Efficient batch operations for checking and executing multiple top-ups + +## Technical Architecture + +### Module Type +- **Type**: Executor Module (0x01) +- **Standard**: ERC-7579 compliant +- **Base**: Rhinestone ModuleKit's `ERC7579ExecutorBase` +- **Upgradeable**: Yes, using UUPS pattern with OpenZeppelin + +### Storage Pattern +- **ERC-7201**: Namespaced storage for upgrade safety +- **Storage Layout**: + ```solidity + // User-configurable parameters + struct TopUpConfig { + uint256 dailyLimit; // Target balance to maintain (max top-up per day) + uint256 monthlyLimit; // Maximum total top-ups per month + bool enabled; // Configuration active status + } + + // Immutable identity and internal state (not user-editable) + struct TopUpState { + address agent; // Target agent account (immutable, part of config ID) + address asset; // ERC-20 token address (immutable, part of config ID) + uint256 lastTopUpTime; // Last top-up timestamp (enforces once-per-day) + uint256 monthlySpent; // Amount topped up this month + uint256 lastResetMonth; // Last monthly reset timestamp + } + + struct AutoTopUpStorage { + // Config ID => user configuration + mapping(bytes32 => TopUpConfig) configs; + + // Config ID => internal state + mapping(bytes32 => TopUpState) states; + + // Account => set of config IDs + mapping(address => EnumerableSet.Bytes32Set) accountConfigs; + } + ``` + +- **Config ID Generation**: `keccak256(abi.encode("TopUpConfig", account, agent, asset))` returns bytes32 for unique configs +- **Namespaced IDs**: "TopUpConfig" prefix prevents collision with other system hashes +- **Per-Account Execution**: Each account's configs are triggered separately to avoid gas limits +- **Gas Optimization**: EnumerableSet allows O(1) add/remove and efficient iteration within an account + +### Key Functions + +#### Module Interface (ERC-7579 via ModuleKit) +```solidity +// Inherited from ERC7579ExecutorBase +function onInstall(bytes calldata data) external +function onUninstall(bytes calldata data) external +function isModuleType(uint256 typeID) external view returns (bool) +function isInitialized(address smartAccount) external view returns (bool) + +// Internal execution helpers from base (used within our functions) +// _execute(address account, address to, uint256 value, bytes memory data) - single tx +// _execute(address account, Execution[] memory execs) - batch tx +// (Plus msg.sender variants and delegatecall versions we won't use) +``` + +#### Configuration Management +```solidity +function configureTopUp( + address agent, + address asset, + TopUpConfig calldata config +) external returns (bytes32 configId) + +function configureTopUpById( + bytes32 configId, + TopUpConfig calldata config +) external + +function disableTopUp(bytes32 configId) external +function enableTopUp(bytes32 configId) external +``` + +#### Execution +```solidity +function triggerTopUps(address account) external returns (bytes32[] memory executed) +function triggerTopUp(bytes32 configId) external returns (bool executed) +``` + +#### View Functions +```solidity +function generateConfigId(address account, address agent, address asset) external pure returns (bytes32) +function getTopUpConfigs(address account) external view returns (TopUpConfig[] memory, TopUpState[] memory) +function canExecuteTopUp(bytes32 configId) external view returns (bool, string memory reason) +function getTopUpById(bytes32 configId) external view returns (TopUpConfig memory config, TopUpState memory state) +function getTopUp(address account, address agent, address asset) external view returns (TopUpConfig memory config, TopUpState memory state) +``` + +## Execution Flow + +### 1. Installation +1. Safe owner calls module management to install AutoTopUpExecutor +2. Module's `onInstall` is called with initial configurations (optional) +3. Module registers the Safe account as initialized + +### 2. Configuration +1. Safe owner sends transaction to module to configure top-ups +2. Config ID generated: `keccak256(abi.encode("TopUpConfig", account, agent, asset))` +3. `configureTopUp()` creates new or updates existing config for agent/asset pair +4. `configureTopUpById()` updates existing config by its ID +5. Agent and asset are immutable once set (part of the config ID) +6. Only dailyLimit, monthlyLimit, and enabled status can be updated +7. Multiple configurations can exist for different agents and different tokens +8. Frontend/keeper can precompute config IDs using `generateConfigId()` + +### 3. Triggering +1. Keeper calls `triggerTopUps(account)` for each account (separate transactions) +2. Module iterates through all enabled configurations for that specific account +3. For each configuration: + - Check if already topped up today (via `lastTopUpTime`) + - Calculate top-up amount: `min(dailyLimit - agentBalance, monthlyLimit - monthlySpent)` + - Skip if amount ≤ 0 (agent already funded or monthly limit reached) + - Execute transfer via internal `_execute()` helper (triggers Safe's module execution) + - Update `lastTopUpTime` and `monthlySpent` + +### 4. Limit Management +- **Daily**: Enforced by once-per-day check using `lastTopUpTime` +- **Monthly**: Reset on the 1st of each month (tracked via `lastResetMonth`) +- **Top-up calculation**: Always maintains balance up to `dailyLimit`, respecting `monthlyLimit` +- **No partial days**: If a top-up happens, it's for the full daily amount (up to monthly remaining) + +## Security Considerations + +### Access Control +- Only Safe account can configure its own top-ups +- Configuration updates require Safe transaction +- No admin keys or external control + +### Limit Enforcement +- Once-per-day enforcement prevents abuse +- Monthly budget caps provide spending control +- Simple calculation: top up to daily limit, not exceeding monthly budget + +### Reentrancy Protection +- OpenZeppelin's ReentrancyGuard on all state-changing functions +- Checks-effects-interactions pattern +- State updates before external calls + +### Validation +- Balance checks before transfers +- Sufficient Safe balance validation +- Asset address validation (ensure valid ERC-20 contract) +- Agent address validation (prevent self-transfers) + +## Gas Optimization + +### Batch Operations +- Per-account batch execution (all configs for one account in one tx) +- Bounded gas usage per transaction +- Keeper maintains off-chain list of accounts to service + +### Storage Efficiency +- EnumerableSet for per-account config tracking +- O(1) config lookups via mapping +- Config IDs prevent duplicate account/agent/asset combinations +- No global account list needed (keeper tracks off-chain) + +## Integration Points + +### ERC-7579 Module System +- Registered as executor module (type 0x01) +- Uses ModuleKit's `_execute()` helpers for execution +- Works across all ERC-7579 compliant accounts (Safe, Kernel, Biconomy) + +### Token Contracts +- ERC20 interface for balance checks +- OpenZeppelin's SafeERC20 for safe token transfers +- Transfers executed via Safe module system (using _execute) +- No direct token approvals needed + +### Monitoring & Events +```solidity +event TopUpConfigured(address indexed account, address indexed agent, address asset, bytes32 indexed configId, TopUpConfig config) +event TopUpExecuted(address indexed account, address indexed agent, address asset, bytes32 indexed configId, uint256 amount) +event TopUpFailed(address indexed account, address indexed agent, address asset, bytes32 indexed configId, string reason) +event TopUpEnabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId) +event TopUpDisabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId) +``` + +- **TopUpConfigured**: Emitted on both initial configuration and updates +- **TopUpEnabled/Disabled**: Emitted whenever enabled status changes (via any function) + +## Future Enhancements + +### Post-MVP Improvements +1. **Native Token Support**: ETH/MATIC/etc. alongside ERC-20s +2. **Off-chain Signatures**: Gasless configuration updates via EIP-712 signed messages + +## Testing Strategy + +### Unit Tests +- Configuration CRUD operations +- Daily limit enforcement (once per day) +- Monthly limit tracking and resets +- Balance calculation logic (top up to daily limit) + +### Integration Tests +- Safe module installation/uninstallation using ModuleKit test utilities +- Token transfer execution through Safe +- Multi-account scenarios using ModuleKit's `makeAccountInstance` +- Cross-implementation tests (Safe, Kernel, Biconomy) - lower priority + +### Security Tests +- Reentrancy attempts +- Limit bypass attempts (trying to trigger multiple times per day) +- Unauthorized configuration changes +- Edge cases around month transitions + +## Implementation Stack + +### Dependencies +- **ModuleKit** (v0.5.9+): Rhinestone's development kit for ERC-7579 modules + - Provides `ERC7579ExecutorBase` for executor functionality + - Built-in test utilities for multi-account testing (Safe, Kernel, Biconomy) + - Helper functions for module deployment + - Integration with Module Registry + - Main import: `import "modulekit/Modules.sol"` + - **Important**: Requires `npm install` in lib/modulekit directory for ERC4337 dependencies +- **OpenZeppelin Contracts Upgradeable**: For UUPS proxy pattern and utilities +- **OpenZeppelin Contracts**: For ERC20 interface and security utilities + +### Inheritance Chain +``` +AutoTopUpExecutor + ├── ERC7579ExecutorBase (from ModuleKit) + │ └── IERC7579Module + ├── UUPSUpgradeable (from OpenZeppelin) + ├── OwnableUpgradeable (from OpenZeppelin) + └── ReentrancyGuardUpgradeable (from OpenZeppelin) +``` + +## Deployment Considerations + +### Deployment Steps +1. Deploy implementation contract +2. Deploy proxy with initializer +3. Register in Rhinestone module registry +4. Integrate with Safe deployment flow +5. Utilize ModuleKit's deployment helpers + +### Monitoring +- Subgraph for indexing all contract events +- Track and alert on failed top-ups (especially during initial rollout) \ No newline at end of file diff --git a/solidity/account-modules/foundry.toml b/solidity/account-modules/foundry.toml new file mode 100644 index 0000000..41e39e9 --- /dev/null +++ b/solidity/account-modules/foundry.toml @@ -0,0 +1,28 @@ +[profile.default] +src = "src" +out = "out" +libs = ["lib"] +remappings = [ + "modulekit/=lib/modulekit/", + "@openzeppelin/=lib/openzeppelin-contracts/", + "forge-std/=lib/forge-std/src/", + "BokkyPooBahsDateTimeLibrary/=lib/BokkyPooBahsDateTimeLibrary/", + "safe-singleton-deployer/=lib/safe-singleton-deployer-sol/src/", + # ModuleKit dependencies + "erc4337-validation/=lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/", + "@ERC4337/=lib/modulekit/node_modules/@ERC4337/", + "account-abstraction/=lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/", + "account-abstraction-v0.6/=lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/", + "@rhinestone/=lib/modulekit/node_modules/@rhinestone/", + "ds-test/=lib/modulekit/node_modules/ds-test/src/", + "solady/=lib/modulekit/node_modules/solady/src/", + "solarray/=lib/modulekit/node_modules/solarray/src/", + "@prb/math/=lib/modulekit/node_modules/@prb/math/src/", + "ExcessivelySafeCall/=lib/modulekit/node_modules/excessively-safe-call/src/" +] +solc = "0.8.30" +optimizer = true +optimizer_runs = 200 + +[lint] +exclude_lints = ["asm-keccak256"] diff --git a/solidity/account-modules/lib/BokkyPooBahsDateTimeLibrary b/solidity/account-modules/lib/BokkyPooBahsDateTimeLibrary new file mode 160000 index 0000000..1dc26f9 --- /dev/null +++ b/solidity/account-modules/lib/BokkyPooBahsDateTimeLibrary @@ -0,0 +1 @@ +Subproject commit 1dc26f977c57a6ba3ed6d7c53cafdb191e7e59ae diff --git a/solidity/account-modules/lib/forge-std b/solidity/account-modules/lib/forge-std new file mode 160000 index 0000000..8bbcf6e --- /dev/null +++ b/solidity/account-modules/lib/forge-std @@ -0,0 +1 @@ +Subproject commit 8bbcf6e3f8f62f419e5429a0bd89331c85c37824 diff --git a/solidity/account-modules/lib/modulekit b/solidity/account-modules/lib/modulekit new file mode 160000 index 0000000..676bb65 --- /dev/null +++ b/solidity/account-modules/lib/modulekit @@ -0,0 +1 @@ +Subproject commit 676bb65032c17b13ecd15ee89f435f0afeffca9b diff --git a/solidity/account-modules/lib/openzeppelin-contracts b/solidity/account-modules/lib/openzeppelin-contracts new file mode 160000 index 0000000..c64a1ed --- /dev/null +++ b/solidity/account-modules/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit c64a1edb67b6e3f4a15cca8909c9482ad33a02b0 diff --git a/solidity/account-modules/lib/safe-singleton-deployer-sol b/solidity/account-modules/lib/safe-singleton-deployer-sol new file mode 160000 index 0000000..cf2b89c --- /dev/null +++ b/solidity/account-modules/lib/safe-singleton-deployer-sol @@ -0,0 +1 @@ +Subproject commit cf2b89c33fed536c4dd6fef2fb84f39053068868 diff --git a/solidity/account-modules/script/CalculateStorageSlot.s.sol b/solidity/account-modules/script/CalculateStorageSlot.s.sol new file mode 100644 index 0000000..7fbacdd --- /dev/null +++ b/solidity/account-modules/script/CalculateStorageSlot.s.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Script, console} from "forge-std/Script.sol"; +import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; + +contract CalculateStorageSlot is Script { + using SlotDerivation for string; + + function run() public { + // AutoTopUpExecutor storage slot + string memory topUpNamespace = "autotopup.storage.AutoTopUpExecutor"; + bytes32 topUpSlot = topUpNamespace.erc7201Slot(); + console.log("AutoTopUpExecutor Namespace:", topUpNamespace); + console.log("AutoTopUpExecutor Storage slot:"); + console.logBytes32(topUpSlot); + + console.log(""); + + // AutoCollectExecutor storage slot + string memory collectNamespace = "autocollect.storage.AutoCollectExecutor"; + bytes32 collectSlot = collectNamespace.erc7201Slot(); + console.log("AutoCollectExecutor Namespace:", collectNamespace); + console.log("AutoCollectExecutor Storage slot:"); + console.logBytes32(collectSlot); + } +} diff --git a/solidity/account-modules/script/Deploy.s.sol b/solidity/account-modules/script/Deploy.s.sol new file mode 100644 index 0000000..931afa5 --- /dev/null +++ b/solidity/account-modules/script/Deploy.s.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Script, console} from "forge-std/Script.sol"; +import {SafeSingletonDeployer} from "safe-singleton-deployer/SafeSingletonDeployer.sol"; +import {AutoTopUpExecutor} from "../src/AutoTopUpExecutor.sol"; +import {AutoCollectExecutor} from "../src/AutoCollectExecutor.sol"; + +contract Deploy is Script { + // Use meaningful salts for deterministic addresses across chains + bytes32 constant AUTO_TOPUP_SALT = keccak256("AutoTopUpExecutor.v1"); + bytes32 constant AUTO_COLLECT_SALT = keccak256("AutoCollectExecutor.v1"); + + function run() external returns (address autoTopUp, address autoCollect) { + // Get deployer from environment + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + console.log("=== Deploying Account Modules ==="); + console.log("Deployer:", vm.addr(deployerPrivateKey)); + console.log(""); + + vm.startBroadcast(deployerPrivateKey); + + // Deploy AutoTopUpExecutor using Safe Singleton Factory + console.log("Deploying AutoTopUpExecutor..."); + autoTopUp = _deploySingleton( + type(AutoTopUpExecutor).creationCode, + "", // No constructor args + AUTO_TOPUP_SALT, + "AutoTopUpExecutor" + ); + + // Deploy AutoCollectExecutor using Safe Singleton Factory + console.log("Deploying AutoCollectExecutor..."); + autoCollect = _deploySingleton( + type(AutoCollectExecutor).creationCode, + "", // No constructor args + AUTO_COLLECT_SALT, + "AutoCollectExecutor" + ); + + vm.stopBroadcast(); + + // Log deployment summary + console.log(""); + console.log("=== Deployment Summary ==="); + console.log("AutoTopUpExecutor:", autoTopUp); + console.log("AutoCollectExecutor:", autoCollect); + console.log(""); + console.log("These addresses will be consistent across all chains!"); + console.log("========================="); + } + + function _deploySingleton( + bytes memory creationCode, + bytes memory constructorArgs, + bytes32 salt, + string memory contractName + ) internal returns (address deployed) { + // Use SafeSingletonDeployer.deploy (not broadcastDeploy) since we're already broadcasting + deployed = SafeSingletonDeployer.deploy(creationCode, constructorArgs, salt); + + console.log(string.concat(contractName, " deployed at:"), deployed); + + // Verify deployment + require(deployed.code.length > 0, string.concat(contractName, " deployment failed")); + } + + // Helper function to predict addresses without deploying + function predict() external view { + console.log("=== Predicted Addresses ==="); + + // Predict AutoTopUpExecutor address + address predictedAutoTopUp = + SafeSingletonDeployer.computeAddress(type(AutoTopUpExecutor).creationCode, AUTO_TOPUP_SALT); + console.log("AutoTopUpExecutor:", predictedAutoTopUp); + + // Predict AutoCollectExecutor address + address predictedAutoCollect = + SafeSingletonDeployer.computeAddress(type(AutoCollectExecutor).creationCode, AUTO_COLLECT_SALT); + console.log("AutoCollectExecutor:", predictedAutoCollect); + + console.log("==========================="); + } +} diff --git a/solidity/account-modules/script/README.md b/solidity/account-modules/script/README.md new file mode 100644 index 0000000..d02fbf6 --- /dev/null +++ b/solidity/account-modules/script/README.md @@ -0,0 +1,42 @@ +# Account Modules Deployment Scripts + +## Deploy.s.sol + +Deploys the AutoTopUpExecutor and AutoCollectExecutor modules using Safe's Singleton Factory for deterministic addresses across all chains. + +### Usage + +#### Predict Addresses (without deploying) +```bash +forge script script/Deploy.s.sol:Deploy --sig "predict()" +``` + +#### Deploy to a Network +```bash +# Set required environment variables +export PRIVATE_KEY= + +# Deploy to Base Sepolia +forge script script/Deploy.s.sol:Deploy \ + --rpc-url \ + --broadcast \ + --verify + +# Deploy to Base Mainnet +forge script script/Deploy.s.sol:Deploy \ + --rpc-url \ + --broadcast \ + --verify +``` + +### Deployed Addresses + +The modules will be deployed to the same addresses on all chains: +- **AutoTopUpExecutor**: `0x92Be8FA04bF1d9Ee311F4B2754Ca22252ccA18D4` +- **AutoCollectExecutor**: `0x6647fA97ff1f04614A0A960dcF499545c4DcC431` + +### Notes + +- The contracts are deployed as immutable singletons (no upgradeability, no owner) +- Addresses are deterministic using Safe Singleton Factory +- The factory is deployed on 250+ chains at: `0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7` \ No newline at end of file diff --git a/solidity/account-modules/script/verify.sh b/solidity/account-modules/script/verify.sh new file mode 100755 index 0000000..d33727c --- /dev/null +++ b/solidity/account-modules/script/verify.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# Script to verify deployed contracts on Basescan/Etherscan +# Usage: ./verify.sh [network] +# Example: ./verify.sh base-sepolia + +NETWORK=${1:-base-sepolia} + +# Contract addresses (same on all chains) +AUTO_TOPUP_ADDRESS="0x92Be8FA04bF1d9Ee311F4B2754Ca22252ccA18D4" +AUTO_COLLECT_ADDRESS="0x6647fA97ff1f04614A0A960dcF499545c4DcC431" + +echo "Verifying contracts on $NETWORK..." +echo "" + +# Verify AutoTopUpExecutor +echo "Verifying AutoTopUpExecutor at $AUTO_TOPUP_ADDRESS..." +forge verify-contract \ + --chain $NETWORK \ + --num-of-optimizations 200 \ + --compiler-version v0.8.30 \ + $AUTO_TOPUP_ADDRESS \ + src/AutoTopUpExecutor.sol:AutoTopUpExecutor + +echo "" + +# Verify AutoCollectExecutor +echo "Verifying AutoCollectExecutor at $AUTO_COLLECT_ADDRESS..." +forge verify-contract \ + --chain $NETWORK \ + --num-of-optimizations 200 \ + --compiler-version v0.8.30 \ + $AUTO_COLLECT_ADDRESS \ + src/AutoCollectExecutor.sol:AutoCollectExecutor + +echo "" +echo "Verification complete!" +echo "" +echo "View verified contracts:" +echo "- AutoTopUpExecutor: https://sepolia.basescan.org/address/$AUTO_TOPUP_ADDRESS#code" +echo "- AutoCollectExecutor: https://sepolia.basescan.org/address/$AUTO_COLLECT_ADDRESS#code" diff --git a/solidity/account-modules/src/AutoCollectExecutor.sol b/solidity/account-modules/src/AutoCollectExecutor.sol new file mode 100644 index 0000000..cef3065 --- /dev/null +++ b/solidity/account-modules/src/AutoCollectExecutor.sol @@ -0,0 +1,558 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {IAutoCollectExecutor} from "./IAutoCollectExecutor.sol"; +import {ERC7579ExecutorBase} from "modulekit/src/module-bases/ERC7579ExecutorBase.sol"; +import {IModule} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; +import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; + +/** + * @title AutoCollectExecutor + * @notice ERC-7579 executor module for automatic ERC-20 token collection from service accounts + * @dev Enables permissionless triggering of pre-configured collections from service accounts to main accounts + */ +contract AutoCollectExecutor is IAutoCollectExecutor, ERC7579ExecutorBase, ReentrancyGuard { + using EnumerableSet for EnumerableSet.Bytes32Set; + + // ============ Storage ============ + + /// @dev ERC-7201 namespace for storage + /// @custom:storage-location erc7201:autocollect.storage.AutoCollectExecutor + // keccak256(abi.encode(uint256(keccak256("autocollect.storage.AutoCollectExecutor")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant STORAGE_NAMESPACE = 0x6ede4012bbf78b7156310dfe77e035f310125e160497f34e20b746b314ff2200; + + /// @custom:storage-namespace AutoCollectStorage + struct AutoCollectStorage { + // Config ID => user configuration + mapping(bytes32 => CollectConfig) configs; + // Config ID => internal state + mapping(bytes32 => CollectState) states; + // Account => set of config IDs + mapping(address => EnumerableSet.Bytes32Set) accountConfigs; + // Account => initialized status + mapping(address => bool) initializedAccounts; + } + + // ============ Constructor ============ + + constructor() {} + + // ============ Storage Access ============ + + function _getStorage() private pure returns (AutoCollectStorage storage $) { + assembly { + $.slot := STORAGE_NAMESPACE + } + } + + // ============ Module Management (ERC-7579) ============ + + /** + * @notice Called when module is installed for an account + * @param data Encoded initial configurations (optional) + * @dev Format: abi.encode(address[], CollectConfig[]) + * @dev Parallel arrays: assets and configs at same indices + */ + function onInstall(bytes calldata data) external override(IAutoCollectExecutor, IModule) { + AutoCollectStorage storage $ = _getStorage(); + address account = msg.sender; + + // Prevent double initialization + require(!$.initializedAccounts[account], "Already initialized"); + + // Mark account as initialized + $.initializedAccounts[account] = true; + + uint256 configCount = 0; + + // Optional: decode and set initial configurations + if (data.length > 0) { + // Decode as parallel arrays: assets and configs + (address[] memory assets, CollectConfig[] memory configs) = abi.decode(data, (address[], CollectConfig[])); + + // Validate array lengths match + require(assets.length == configs.length, InvalidConfigurationArrays()); + + configCount = assets.length; + + // Process each configuration using the public function + // This handles all validation, state initialization, and event emission + for (uint256 i = 0; i < assets.length; i++) { + configureCollection(assets[i], configs[i]); + } + } + + emit ModuleInstalled(account, configCount); + } + + /** + * @notice Called when module is uninstalled for an account + * @dev Additional data parameter is unused + */ + function onUninstall(bytes calldata) external override(IAutoCollectExecutor, IModule) { + AutoCollectStorage storage $ = _getStorage(); + + // Clean up all configs for this account + address account = msg.sender; + bytes32[] memory configIds = $.accountConfigs[account].values(); + + // Iterate in reverse to efficiently remove from set while deleting configs + for (uint256 i = configIds.length; i > 0; i--) { + bytes32 configId = configIds[i - 1]; + delete $.configs[configId]; + delete $.states[configId]; + $.accountConfigs[account].remove(configId); + } + + // Mark account as uninitialized + delete $.initializedAccounts[account]; + + emit ModuleUninstalled(account, configIds.length); + } + + /** + * @notice Returns whether this module is of a certain type + * @param _typeId The type ID to check + * @return True if this module is an executor (type 0x01) + */ + function isModuleType(uint256 _typeId) external pure override(IAutoCollectExecutor, IModule) returns (bool) { + return _typeId == TYPE_EXECUTOR; + } + + // ============ Configuration Management ============ + + /** + * @notice Configure a new collection or update an existing one + * @param asset The ERC-20 token address + * @param config The collection configuration + * @return configId The generated config ID + */ + function configureCollection(address asset, CollectConfig memory config) public returns (bytes32 configId) { + require(asset != address(0), InvalidAsset()); + require(config.target != address(0), InvalidTarget()); + + AutoCollectStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + configId = generateConfigId(msg.sender, asset); + + // Check if this is a new config + if ($.states[configId].asset == address(0)) { + // Initialize state for new config + $.states[configId] = CollectState({asset: asset, lastCollectDate: 0}); + + // Add to account's config set + $.accountConfigs[msg.sender].add(configId); + } + + // Update the configuration + _configureCollection(configId, config); + } + + /** + * @notice Update an existing collection configuration by ID + * @param configId The config ID to update + * @param config The new configuration + */ + function configureCollectionById(bytes32 configId, CollectConfig memory config) external { + AutoCollectStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + // Verify config exists and caller owns it + require($.states[configId].asset != address(0), ConfigNotFound()); + require($.accountConfigs[msg.sender].contains(configId), Unauthorized(configId, msg.sender)); + + // Update the configuration + _configureCollection(configId, config); + } + + /** + * @dev Internal function to configure a collection + * @dev IMPORTANT: This function does NOT validate that the config exists or belongs to the caller. + * @dev Caller must perform these checks before calling this function. + * @param configId The config ID to configure + * @param config The configuration to apply + */ + function _configureCollection(bytes32 configId, CollectConfig memory config) internal { + require(config.target != address(0), InvalidTarget()); + + AutoCollectStorage storage $ = _getStorage(); + CollectState memory state = $.states[configId]; + + bool wasEnabled = $.configs[configId].enabled; + $.configs[configId] = config; + + emit CollectionConfigured(msg.sender, state.asset, config.target, configId, config); + + // Emit enable/disable events if status changed + if (config.enabled && !wasEnabled) { + emit CollectionEnabled(msg.sender, state.asset, configId); + } else if (!config.enabled && wasEnabled) { + emit CollectionDisabled(msg.sender, state.asset, configId); + } + } + + /** + * @notice Enable a collection configuration by asset address + * @param asset The asset address + */ + function enableCollection(address asset) external { + bytes32 configId = generateConfigId(msg.sender, asset); + enableCollection(configId); + } + + /** + * @notice Enable a collection configuration by config ID + * @param configId The config ID to enable + */ + function enableCollection(bytes32 configId) public { + AutoCollectStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + CollectState memory state = $.states[configId]; + require(state.asset != address(0), ConfigNotFound()); + + // Verify caller owns this config + address account = msg.sender; + require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); + + if (!$.configs[configId].enabled) { + $.configs[configId].enabled = true; + emit CollectionEnabled(account, state.asset, configId); + } + } + + /** + * @notice Disable a collection configuration by asset address + * @param asset The asset address + */ + function disableCollection(address asset) external { + bytes32 configId = generateConfigId(msg.sender, asset); + disableCollection(configId); + } + + /** + * @notice Disable a collection configuration by config ID + * @param configId The config ID to disable + */ + function disableCollection(bytes32 configId) public { + AutoCollectStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + CollectState memory state = $.states[configId]; + require(state.asset != address(0), ConfigNotFound()); + + // Verify caller owns this config + address account = msg.sender; + require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); + + if ($.configs[configId].enabled) { + $.configs[configId].enabled = false; + emit CollectionDisabled(account, state.asset, configId); + } + } + + // ============ Execution ============ + + /** + * @notice Trigger all collections for a specific account + * @param account The service account to trigger collections for + * @dev Emits CollectionExecuted for each successful collection + */ + function triggerAllCollections(address account) external nonReentrant { + AutoCollectStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[account], ModuleNotInitialized(account)); + + bytes32[] memory configIds = $.accountConfigs[account].values(); + + // Calculate date once for all configs + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + + for (uint256 i = 0; i < configIds.length; i++) { + _tryExecuteCollection(configIds[i], account, year, month, day); + } + } + + /** + * @notice Trigger a specific collection by asset + * @param account The service account to collect from + * @param asset The asset to collect + * @dev Emits CollectionExecuted if successful, CollectionSkipped if conditions not met + */ + function triggerCollection(address account, address asset) external nonReentrant { + AutoCollectStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[account], ModuleNotInitialized(account)); + + bytes32 configId = generateConfigId(account, asset); + + // Verify config exists and belongs to the account + require($.states[configId].asset != address(0), ConfigNotFound()); + require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); + + // Calculate current date + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + + _tryExecuteCollection(configId, account, year, month, day); + } + + /** + * @notice Execute a collection transfer (external for try-catch) + * @param account The service account to transfer from + * @param asset The token address + * @param target The target address to transfer to + * @param amount The amount to transfer + * @dev Must be external/public for try-catch. Only callable by this contract. + */ + function _executeCollectionTransfer(address account, address asset, address target, uint256 amount) external { + require(msg.sender == address(this), "Only self"); + + bytes memory result = + _execute(account, asset, 0, abi.encodeWithSelector(IERC20.transfer.selector, target, amount)); + + // Check return value (handle non-standard tokens like USDT that don't return bool) + if (result.length > 0) { + require(result.length == 32, InvalidTransferReturn(result)); + require(abi.decode(result, (bool)), TransferReturnedFalse(result)); + } + } + + /** + * @dev Internal function to attempt a collection execution + * @param configId The config ID to execute + * @param account The service account that owns the configuration + * @param year Current year + * @param month Current month (1-12) + * @param day Current day (1-31) + * @dev Emits CollectionExecuted on success, CollectionSkipped for conditions not met + * @dev Uses graceful failure handling - does not revert on collection failures + */ + function _tryExecuteCollection(bytes32 configId, address account, uint256 year, uint256 month, uint256 day) + private + { + AutoCollectStorage storage $ = _getStorage(); + + CollectConfig memory config = $.configs[configId]; + CollectState storage state = $.states[configId]; + + // Validate and calculate collection + (bool canExecute, uint256 currentBalance, uint256 collectAmount, uint256 currentDate,) = + _validateAndCalculateCollection(config, state, account, year, month, day); + + if (!canExecute) { + // Always emit skip event for complete visibility + emit CollectionSkipped( + account, state.asset, configId, currentBalance, config.threshold, config.minimumRemaining, collectAmount + ); + return; + } + + // Try to execute transfer - wrapped in try-catch to prevent batch operation failure + // If this fails, other collections in the batch can still succeed + try this._executeCollectionTransfer(account, state.asset, config.target, collectAmount) { + // Update state AFTER successful transfer + state.lastCollectDate = currentDate; + emit CollectionExecuted(account, state.asset, config.target, configId, collectAmount); + } catch Error(string memory reason) { + emit CollectionFailed(account, state.asset, configId, reason); + } catch (bytes memory) { + emit CollectionFailed(account, state.asset, configId, "Transfer failed"); + } + } + + /** + * @dev Validates if a collection can be executed and calculates the amount + * @param config The collection configuration + * @param state The collection state (storage pointer for reading) + * @param account The service account + * @param year Current year + * @param month Current month (1-12) + * @param day Current day (1-31) + * @return canExecute Whether the collection can be executed + * @return currentBalance The current balance of the asset in the account + * @return collectAmount The amount that would be collected (balance - minimumRemaining) + * @return currentDate The encoded current date (YYYYMMDD) + * @return reason Error message if cannot execute + */ + function _validateAndCalculateCollection( + CollectConfig memory config, + CollectState memory state, + address account, + uint256 year, + uint256 month, + uint256 day + ) + private + view + returns ( + bool canExecute, + uint256 currentBalance, + uint256 collectAmount, + uint256 currentDate, + string memory reason + ) + { + // Check if enabled + if (!config.enabled) { + return (false, 0, 0, 0, "Collection not enabled"); + } + + // Check once per day limit using calendar days + currentDate = year * 10000 + month * 100 + day; + if (currentDate <= state.lastCollectDate) { + return (false, 0, 0, currentDate, "Already collected today"); + } + + // Get current balance + currentBalance = IERC20(state.asset).balanceOf(account); + + // Calculate collect amount (balance minus what we want to keep) + collectAmount = currentBalance >= config.minimumRemaining ? currentBalance - config.minimumRemaining : 0; + + // Check for zero balance (skip collection) + if (currentBalance == 0) { + return (false, currentBalance, collectAmount, currentDate, "Balance is zero"); + } + + // Check threshold requirement + if (currentBalance < config.threshold) { + return (false, currentBalance, collectAmount, currentDate, "Balance below threshold"); + } + + // Skip if nothing to collect + if (collectAmount == 0) { + return (false, currentBalance, collectAmount, currentDate, "Collect amount would be zero"); + } + + return (true, currentBalance, collectAmount, currentDate, ""); + } + + // ============ View Functions ============ + + /// @inheritdoc IAutoCollectExecutor + function isInitialized(address smartAccount) external view override(IAutoCollectExecutor, IModule) returns (bool) { + AutoCollectStorage storage $ = _getStorage(); + return $.initializedAccounts[smartAccount]; + } + + /** + * @notice Generate a config ID for given parameters + * @param account The service account + * @param asset The token address + * @return The generated config ID + */ + function generateConfigId(address account, address asset) public pure returns (bytes32) { + return keccak256(abi.encode("CollectConfig", account, asset)); + } + + /** + * @notice Get all collection configurations for an account + * @param account The account to query + * @return configs Array of configurations + * @return states Array of states + */ + function getCollectionConfigs(address account) + external + view + returns (CollectConfig[] memory configs, CollectState[] memory states) + { + AutoCollectStorage storage $ = _getStorage(); + + bytes32[] memory configIds = $.accountConfigs[account].values(); + configs = new CollectConfig[](configIds.length); + states = new CollectState[](configIds.length); + + for (uint256 i = 0; i < configIds.length; i++) { + configs[i] = $.configs[configIds[i]]; + states[i] = $.states[configIds[i]]; + } + } + + /** + * @notice Check if a collection can be executed + * @param account The account that owns the config + * @param asset The asset to check + * @return canExecute Whether the collection can be executed + * @return reason Reason if cannot execute + */ + function canExecuteCollection(address account, address asset) + external + view + returns (bool canExecute, string memory reason) + { + AutoCollectStorage storage $ = _getStorage(); + + bytes32 configId = generateConfigId(account, asset); + CollectConfig memory config = $.configs[configId]; + CollectState memory state = $.states[configId]; + + if (state.asset == address(0)) { + return (false, "Config not found"); + } + + if (!$.accountConfigs[account].contains(configId)) { + return (false, "Account doesn't own config"); + } + + if (!config.enabled) { + return (false, "Collection disabled"); + } + + // Get current date + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + + // Use shared validation logic + (bool canExec,,,, string memory errorReason) = + _validateAndCalculateCollection(config, state, account, year, month, day); + + return (canExec, errorReason); + } + + /** + * @notice Get collection config by asset + * @param account The service account + * @param asset The token address + * @return config The configuration + * @return state The state + */ + function getCollectionConfig(address account, address asset) + external + view + returns (CollectConfig memory config, CollectState memory state) + { + bytes32 configId = generateConfigId(account, asset); + AutoCollectStorage storage $ = _getStorage(); + config = $.configs[configId]; + state = $.states[configId]; + } + + /** + * @notice Get collection config by config ID + * @param configId The config ID + * @return config The configuration + * @return state The state + */ + function getCollectionConfigById(bytes32 configId) + external + view + returns (CollectConfig memory config, CollectState memory state) + { + AutoCollectStorage storage $ = _getStorage(); + config = $.configs[configId]; + state = $.states[configId]; + } +} diff --git a/solidity/account-modules/src/AutoTopUpExecutor.sol b/solidity/account-modules/src/AutoTopUpExecutor.sol new file mode 100644 index 0000000..effb355 --- /dev/null +++ b/solidity/account-modules/src/AutoTopUpExecutor.sol @@ -0,0 +1,551 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {IAutoTopUpExecutor} from "./IAutoTopUpExecutor.sol"; +import {ERC7579ExecutorBase} from "modulekit/src/module-bases/ERC7579ExecutorBase.sol"; +import {IModule} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; +import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; + +/** + * @title AutoTopUpExecutor + * @notice ERC-7579 executor module for automatic ERC-20 token balance management + * @dev Enables permissionless triggering of pre-configured top-ups from Safe accounts to agent accounts + */ +contract AutoTopUpExecutor is IAutoTopUpExecutor, ERC7579ExecutorBase, ReentrancyGuard { + using EnumerableSet for EnumerableSet.Bytes32Set; + using SafeERC20 for IERC20; + + // ============ Storage ============ + + /// @dev ERC-7201 namespace for storage + /// @custom:storage-location erc7201:autotopup.storage.AutoTopUpExecutor + // keccak256(abi.encode(uint256(keccak256("autotopup.storage.AutoTopUpExecutor")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant STORAGE_NAMESPACE = 0xf1fdef444005737c1eaec423fc423d55d53d0a09b4618f0f50ba7fb8df2b0400; + + /// @custom:storage-namespace AutoTopUpStorage + struct AutoTopUpStorage { + // Config ID => user configuration + mapping(bytes32 => TopUpConfig) configs; + // Config ID => internal state + mapping(bytes32 => TopUpState) states; + // Account => set of config IDs + mapping(address => EnumerableSet.Bytes32Set) accountConfigs; + // Account => initialized status + mapping(address => bool) initializedAccounts; + } + + // ============ Constructor ============ + + constructor() {} + + // ============ Storage Access ============ + + function _getStorage() private pure returns (AutoTopUpStorage storage $) { + assembly { + $.slot := STORAGE_NAMESPACE + } + } + + // ============ Module Management (ERC-7579) ============ + + /** + * @notice Called when module is installed for an account + * @param data Encoded initial configurations (optional) + * @dev Format: abi.encode(address[], address[], TopUpConfig[]) + * @dev Parallel arrays: agents, assets, and configs at same indices + */ + function onInstall(bytes calldata data) external override(IAutoTopUpExecutor, IModule) { + AutoTopUpStorage storage $ = _getStorage(); + address account = msg.sender; + + // Prevent double initialization + require(!$.initializedAccounts[account], "Already initialized"); + + // Mark account as initialized + $.initializedAccounts[account] = true; + + uint256 configCount = 0; + + // Optional: decode and set initial configurations + if (data.length > 0) { + // Decode as parallel arrays: agents, assets, and configs + (address[] memory agents, address[] memory assets, TopUpConfig[] memory configs) = + abi.decode(data, (address[], address[], TopUpConfig[])); + + // Validate array lengths match + require(agents.length == assets.length && agents.length == configs.length, InvalidConfigurationArrays()); + + configCount = agents.length; + + // Process each configuration using the public function + // This handles all validation, state initialization, and event emission + for (uint256 i = 0; i < agents.length; i++) { + configureTopUp(agents[i], assets[i], configs[i]); + } + } + + emit ModuleInstalled(account, configCount); + } + + /** + * @notice Called when module is uninstalled for an account + * @dev Additional data parameter is unused + */ + function onUninstall(bytes calldata) external override(IAutoTopUpExecutor, IModule) { + AutoTopUpStorage storage $ = _getStorage(); + + // Clean up all configs for this account + address account = msg.sender; + bytes32[] memory configIds = $.accountConfigs[account].values(); + + // Iterate in reverse to efficiently remove from set while deleting configs + for (uint256 i = configIds.length; i > 0; i--) { + bytes32 configId = configIds[i - 1]; + delete $.configs[configId]; + delete $.states[configId]; + $.accountConfigs[account].remove(configId); + } + + // Mark account as uninitialized + delete $.initializedAccounts[account]; + + emit ModuleUninstalled(account, configIds.length); + } + + /** + * @notice Returns whether this module is of a certain type + * @param _typeId The type ID to check + * @return True if this module is an executor (type 0x01) + */ + function isModuleType(uint256 _typeId) external pure override(IAutoTopUpExecutor, IModule) returns (bool) { + return _typeId == TYPE_EXECUTOR; + } + + // ============ Configuration Management ============ + + /** + * @notice Configure a new top-up or update an existing one + * @param agent The agent account to top up + * @param asset The ERC-20 token address + * @param config The top-up configuration + * @return configId The generated config ID + */ + function configureTopUp(address agent, address asset, TopUpConfig memory config) public returns (bytes32 configId) { + require(agent != address(0) && agent != msg.sender, InvalidAgent()); + require(asset != address(0), InvalidAsset()); + + AutoTopUpStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + configId = generateConfigId(msg.sender, agent, asset); + + // Check if this is a new config + if ($.states[configId].agent == address(0)) { + // Initialize state for new config + $.states[configId] = + TopUpState({agent: agent, asset: asset, lastTopUpDay: 0, monthlySpent: 0, lastResetMonth: 0}); + + // Add to account's config set + $.accountConfigs[msg.sender].add(configId); + } + + // Update the configuration + _configureTopUp(configId, config); + } + + /** + * @notice Update an existing top-up configuration by ID + * @param configId The config ID to update + * @param config The new configuration + */ + function configureTopUpById(bytes32 configId, TopUpConfig memory config) external { + AutoTopUpStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + // Verify config exists and caller owns it + require($.states[configId].agent != address(0), ConfigNotFound()); + require($.accountConfigs[msg.sender].contains(configId), Unauthorized(configId, msg.sender)); + + // Update the configuration + _configureTopUp(configId, config); + } + + /** + * @dev Internal function to configure a top-up + * @dev IMPORTANT: This function does NOT validate that the config exists or belongs to the caller. + * @dev Caller must perform these checks before calling this function. + * @param configId The config ID to configure + * @param config The configuration to apply + */ + function _configureTopUp(bytes32 configId, TopUpConfig memory config) internal { + // Note: dailyLimit can be greater than monthlyLimit for use cases where users want + // monthly budget constraints but no daily restrictions + require(config.dailyLimit > 0 && config.monthlyLimit > 0, InvalidConfiguration()); + + AutoTopUpStorage storage $ = _getStorage(); + TopUpState memory state = $.states[configId]; + + bool wasEnabled = $.configs[configId].enabled; + $.configs[configId] = config; + + emit TopUpConfigured(msg.sender, state.agent, state.asset, configId, config); + + // Emit enable/disable events if status changed + if (config.enabled && !wasEnabled) { + emit TopUpEnabled(msg.sender, state.agent, state.asset, configId); + } else if (!config.enabled && wasEnabled) { + emit TopUpDisabled(msg.sender, state.agent, state.asset, configId); + } + } + + /** + * @notice Enable a top-up configuration + * @param configId The config ID to enable + */ + function enableTopUp(bytes32 configId) external { + AutoTopUpStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + TopUpState memory state = $.states[configId]; + require(state.agent != address(0), ConfigNotFound()); + + // Verify caller owns this config + address account = msg.sender; + require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); + + if (!$.configs[configId].enabled) { + $.configs[configId].enabled = true; + emit TopUpEnabled(account, state.agent, state.asset, configId); + } + } + + /** + * @notice Disable a top-up configuration + * @param configId The config ID to disable + */ + function disableTopUp(bytes32 configId) external { + AutoTopUpStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + TopUpState memory state = $.states[configId]; + require(state.agent != address(0), ConfigNotFound()); + + // Verify caller owns this config + address account = msg.sender; + require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); + + if ($.configs[configId].enabled) { + $.configs[configId].enabled = false; + emit TopUpDisabled(account, state.agent, state.asset, configId); + } + } + + // ============ Execution ============ + + /** + * @notice Trigger all top-ups for a specific account + * @param account The account to trigger top-ups for + * @dev Emits TopUpExecuted for each successful top-up + */ + function triggerTopUps(address account) external nonReentrant { + AutoTopUpStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[account], ModuleNotInitialized(account)); + + bytes32[] memory configIds = $.accountConfigs[account].values(); + + // Calculate date once for all configs + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + + for (uint256 i = 0; i < configIds.length; i++) { + _tryExecuteTopUp(configIds[i], account, year, month, day); + } + } + + /** + * @notice Trigger a specific top-up by config ID + * @param account The account that owns the config + * @param configId The config ID to trigger + * @dev Emits TopUpExecuted if successful, reverts on transfer failure + */ + function triggerTopUp(address account, bytes32 configId) external nonReentrant { + AutoTopUpStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[account], ModuleNotInitialized(account)); + + // Verify config exists and belongs to the account + require($.states[configId].agent != address(0), ConfigNotFound()); + require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); + + // Calculate current date + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + + _tryExecuteTopUp(configId, account, year, month, day); + } + + /** + * @notice Execute a top-up transfer (external for try-catch) + * @param account The main account to transfer from + * @param asset The token address + * @param agent The agent account to transfer to + * @param amount The amount to transfer + * @dev Must be external/public for try-catch. Only callable by this contract. + */ + function _executeTopUpTransfer(address account, address asset, address agent, uint256 amount) external { + require(msg.sender == address(this), "Only self"); + + bytes memory result = + _execute(account, asset, 0, abi.encodeWithSelector(IERC20.transfer.selector, agent, amount)); + + // Check return value (handle non-standard tokens like USDT that don't return bool) + if (result.length > 0) { + require(result.length == 32, InvalidTransferReturn(result)); + require(abi.decode(result, (bool)), TransferReturnedFalse(result)); + } + } + + /** + * @dev Internal function to attempt a top-up execution + * @param configId The config ID to execute + * @param account The Safe account that owns the configuration + * @param year Current year + * @param month Current month (1-12) + * @param day Current day (1-31) + * @dev Emits TopUpExecuted on success, TopUpFailed for insufficient balance + * @dev Reverts on transfer failure (indicates configuration error) + */ + /** + * @dev Validates if a top-up can be executed and calculates the amount + * @param config The top-up configuration + * @param state The top-up state (storage pointer for reading) + * @param account The Safe account + * @param year Current year + * @param month Current month (1-12) + * @param day Current day (1-31) + * @return canExecute Whether the top-up can be executed + * @return topUpAmount The amount to top up (0 if cannot execute) + * @return currentDay The encoded current day (YYYYMMDD) + * @return currentMonth The encoded current month (year * 12 + month) + * @return reason Error message if cannot execute + */ + function _validateAndCalculateTopUp( + TopUpConfig memory config, + TopUpState memory state, + address account, + uint256 year, + uint256 month, + uint256 day + ) + private + view + returns (bool canExecute, uint256 topUpAmount, uint256 currentDay, uint256 currentMonth, string memory reason) + { + // Check if enabled + if (!config.enabled) { + return (false, 0, 0, 0, "Top-up not enabled"); + } + + // Check once per day limit using calendar days + currentDay = year * 10000 + month * 100 + day; + if (currentDay <= state.lastTopUpDay) { + return (false, 0, currentDay, 0, "Already topped up today"); + } + + // Check monthly limit using calendar months + currentMonth = year * 12 + month; + uint256 monthlySpent = state.monthlySpent; + if (currentMonth > state.lastResetMonth) { + monthlySpent = 0; // Will be reset in actual execution + } + + // Check if agent needs top-up + uint256 agentBalance = IERC20(state.asset).balanceOf(state.agent); + if (agentBalance >= config.dailyLimit) { + return (false, 0, currentDay, currentMonth, "Agent balance sufficient"); + } + + // Calculate top-up amount + topUpAmount = config.dailyLimit - agentBalance; + + // Apply monthly limit + if (monthlySpent + topUpAmount > config.monthlyLimit) { + topUpAmount = config.monthlyLimit - monthlySpent; + if (topUpAmount == 0) { + return (false, 0, currentDay, currentMonth, "Monthly limit reached"); + } + } + + // Check account has sufficient balance + if (IERC20(state.asset).balanceOf(account) < topUpAmount) { + return (false, 0, currentDay, currentMonth, "Insufficient account balance"); + } + + return (true, topUpAmount, currentDay, currentMonth, ""); + } + + function _tryExecuteTopUp(bytes32 configId, address account, uint256 year, uint256 month, uint256 day) private { + AutoTopUpStorage storage $ = _getStorage(); + + TopUpConfig memory config = $.configs[configId]; + TopUpState storage state = $.states[configId]; + + // Validate and calculate top-up + (bool canExecute, uint256 topUpAmount, uint256 currentDay, uint256 currentMonth, string memory reason) = + _validateAndCalculateTopUp(config, state, account, year, month, day); + + if (!canExecute) { + // Only emit failure for insufficient balance (not for normal conditions like already topped up) + if (keccak256(bytes(reason)) == keccak256(bytes("Insufficient account balance"))) { + emit TopUpFailed(account, state.agent, state.asset, configId, reason); + } + return; + } + + // Try to execute transfer - wrapped in try-catch to prevent batch operation failure + // If this fails, other top-ups in the batch can still succeed + try this._executeTopUpTransfer(account, state.asset, state.agent, topUpAmount) { + // Update state AFTER successful transfer + + // Reset monthly counter if needed + if (currentMonth > state.lastResetMonth) { + state.monthlySpent = 0; + state.lastResetMonth = currentMonth; + } + + state.lastTopUpDay = currentDay; + state.monthlySpent += topUpAmount; + + emit TopUpExecuted(account, state.agent, state.asset, configId, topUpAmount); + } catch Error(string memory errorReason) { + emit TopUpFailed(account, state.agent, state.asset, configId, errorReason); + } catch (bytes memory) { + emit TopUpFailed(account, state.agent, state.asset, configId, "Transfer failed"); + } + } + + // ============ View Functions ============ + + /// @inheritdoc IAutoTopUpExecutor + function isInitialized(address smartAccount) external view override(IAutoTopUpExecutor, IModule) returns (bool) { + AutoTopUpStorage storage $ = _getStorage(); + return $.initializedAccounts[smartAccount]; + } + + /** + * @notice Generate a config ID for given parameters + * @param account The Safe account + * @param agent The agent account + * @param asset The token address + * @return The generated config ID + */ + function generateConfigId(address account, address agent, address asset) public pure returns (bytes32) { + return keccak256(abi.encode("TopUpConfig", account, agent, asset)); + } + + /** + * @notice Get all top-up configurations for an account + * @param account The account to query + * @return configs Array of configurations + * @return states Array of states + */ + function getTopUpConfigs(address account) + external + view + returns (TopUpConfig[] memory configs, TopUpState[] memory states) + { + AutoTopUpStorage storage $ = _getStorage(); + + bytes32[] memory configIds = $.accountConfigs[account].values(); + configs = new TopUpConfig[](configIds.length); + states = new TopUpState[](configIds.length); + + for (uint256 i = 0; i < configIds.length; i++) { + configs[i] = $.configs[configIds[i]]; + states[i] = $.states[configIds[i]]; + } + } + + /** + * @notice Check if a top-up can be executed + * @param account The account that owns the config + * @param configId The config ID to check + * @return canExecute Whether the top-up can be executed + * @return reason Reason if cannot execute + */ + function canExecuteTopUp(address account, bytes32 configId) + external + view + returns (bool canExecute, string memory reason) + { + AutoTopUpStorage storage $ = _getStorage(); + + TopUpConfig memory config = $.configs[configId]; + TopUpState memory state = $.states[configId]; + + if (state.agent == address(0)) { + return (false, "Config not found"); + } + + if (!$.accountConfigs[account].contains(configId)) { + return (false, "Account doesn't own config"); + } + + if (!config.enabled) { + return (false, "Top-up disabled"); + } + + // Get current date + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + + // Use shared validation logic + (bool canExec,,,, string memory errorReason) = + _validateAndCalculateTopUp(config, state, account, year, month, day); + + return (canExec, errorReason); + } + + /** + * @notice Get top-up by config ID + * @param configId The config ID + * @return config The configuration + * @return state The state + */ + function getTopUpById(bytes32 configId) external view returns (TopUpConfig memory config, TopUpState memory state) { + AutoTopUpStorage storage $ = _getStorage(); + config = $.configs[configId]; + state = $.states[configId]; + } + + /** + * @notice Get top-up by account, agent, and asset + * @param account The Safe account + * @param agent The agent account + * @param asset The token address + * @return config The configuration + * @return state The state + */ + function getTopUp(address account, address agent, address asset) + external + view + returns (TopUpConfig memory config, TopUpState memory state) + { + bytes32 configId = generateConfigId(account, agent, asset); + AutoTopUpStorage storage $ = _getStorage(); + config = $.configs[configId]; + state = $.states[configId]; + } +} diff --git a/solidity/account-modules/src/IAutoCollectExecutor.sol b/solidity/account-modules/src/IAutoCollectExecutor.sol new file mode 100644 index 0000000..caeb7b9 --- /dev/null +++ b/solidity/account-modules/src/IAutoCollectExecutor.sol @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +/** + * @title IAutoCollectExecutor + * @notice Interface for the ERC-7579 executor module that manages automatic ERC-20 token collection + * @dev Enables permissionless triggering of pre-configured collections from service accounts to main accounts + */ +interface IAutoCollectExecutor { + // ============ Structs ============ + + /// @notice User-configurable parameters + struct CollectConfig { + address target; // Main account to collect funds to + uint256 threshold; // Minimum balance to trigger collection (0 = no threshold) + uint256 minimumRemaining; // Minimum amount to leave in account after collection (0 = collect all) + bool enabled; // Configuration active status + } + + /// @notice Immutable identity and internal state (not user-editable) + struct CollectState { + address asset; // ERC-20 token address (immutable, part of config ID) + uint256 lastCollectDate; // Last collection date (YYYYMMDD format) + } + + // ============ Events ============ + + event ModuleInstalled(address indexed account, uint256 initialConfigs); + + event ModuleUninstalled(address indexed account, uint256 removedConfigs); + + event CollectionConfigured( + address indexed account, address indexed asset, address target, bytes32 indexed configId, CollectConfig config + ); + + event CollectionExecuted( + address indexed account, address indexed asset, address target, bytes32 indexed configId, uint256 amount + ); + + event CollectionSkipped( + address indexed account, + address indexed asset, + bytes32 indexed configId, + uint256 balance, + uint256 threshold, + uint256 minimumRemaining, + uint256 collectAmount + ); + + event CollectionFailed(address indexed account, address indexed asset, bytes32 indexed configId, string reason); + + event CollectionEnabled(address indexed account, address indexed asset, bytes32 indexed configId); + + event CollectionDisabled(address indexed account, address indexed asset, bytes32 indexed configId); + + // ============ Errors ============ + + error ModuleNotInitialized(address account); + error InvalidConfiguration(); + error ConfigNotFound(); + error Unauthorized(bytes32 configId, address caller); + error InvalidAsset(); + error InvalidTarget(); + error AlreadyCollectedToday(); + error BalanceBelowThreshold(); + error InvalidConfigurationArrays(); + error TransferFailed(); + error InvalidTransferReturn(bytes result); + error TransferReturnedFalse(bytes result); + + // ============ Module Management (ERC-7579) ============ + + /** + * @notice Called when module is installed for an account + * @param data Encoded initial configurations (optional) + * @dev Format: abi.encode(address[], CollectConfig[]) + * @dev Parallel arrays: assets and configs at same indices + */ + function onInstall(bytes calldata data) external; + + /** + * @notice Called when module is uninstalled for an account + * @dev Additional data parameter is unused + */ + function onUninstall(bytes calldata) external; + + /** + * @notice Returns whether this module is of a certain type + * @param _typeId The type ID to check + * @return True if this module is an executor (type 0x01) + */ + function isModuleType(uint256 _typeId) external pure returns (bool); + + /** + * @notice Check if module is initialized for an account + * @param smartAccount The account to check + * @return Whether the module is initialized + */ + function isInitialized(address smartAccount) external view returns (bool); + + // ============ Configuration Management ============ + + /** + * @notice Configure a new collection or update an existing one + * @param asset The ERC-20 token address + * @param config The collection configuration + * @return configId The generated config ID + */ + function configureCollection(address asset, CollectConfig memory config) external returns (bytes32 configId); + + /** + * @notice Update an existing collection configuration by ID + * @param configId The config ID to update + * @param config The new configuration + */ + function configureCollectionById(bytes32 configId, CollectConfig memory config) external; + + /** + * @notice Enable a collection configuration by asset address + * @param asset The asset address + */ + function enableCollection(address asset) external; + + /** + * @notice Enable a collection configuration by config ID + * @param configId The config ID to enable + */ + function enableCollection(bytes32 configId) external; + + /** + * @notice Disable a collection configuration by asset address + * @param asset The asset address + */ + function disableCollection(address asset) external; + + /** + * @notice Disable a collection configuration by config ID + * @param configId The config ID to disable + */ + function disableCollection(bytes32 configId) external; + + // ============ Execution ============ + + /** + * @notice Trigger all collections for a specific account + * @param account The service account to trigger collections for + * @dev Emits CollectionExecuted for each successful collection + */ + function triggerAllCollections(address account) external; + + /** + * @notice Trigger a specific collection by asset + * @param account The service account to collect from + * @param asset The asset to collect + * @dev Emits CollectionExecuted if successful, CollectionSkipped if conditions not met + */ + function triggerCollection(address account, address asset) external; + + // ============ View Functions ============ + + /** + * @notice Generate a config ID for given parameters + * @param account The service account + * @param asset The token address + * @return The generated config ID + */ + function generateConfigId(address account, address asset) external pure returns (bytes32); + + /** + * @notice Get all collection configurations for an account + * @param account The account to query + * @return configs Array of configurations + * @return states Array of states + */ + function getCollectionConfigs(address account) + external + view + returns (CollectConfig[] memory configs, CollectState[] memory states); + + /** + * @notice Check if a collection can be executed + * @param account The account that owns the config + * @param asset The asset to check + * @return canExecute Whether the collection can be executed + * @return reason Reason if cannot execute + */ + function canExecuteCollection(address account, address asset) + external + view + returns (bool canExecute, string memory reason); + + /** + * @notice Get collection config by asset + * @param account The service account + * @param asset The token address + * @return config The configuration + * @return state The state + */ + function getCollectionConfig(address account, address asset) + external + view + returns (CollectConfig memory config, CollectState memory state); + + /** + * @notice Get collection config by config ID + * @param configId The config ID + * @return config The configuration + * @return state The state + */ + function getCollectionConfigById(bytes32 configId) + external + view + returns (CollectConfig memory config, CollectState memory state); +} diff --git a/solidity/account-modules/src/IAutoTopUpExecutor.sol b/solidity/account-modules/src/IAutoTopUpExecutor.sol new file mode 100644 index 0000000..1f27799 --- /dev/null +++ b/solidity/account-modules/src/IAutoTopUpExecutor.sol @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +/** + * @title IAutoTopUpExecutor + * @notice Interface for the ERC-7579 executor module that manages automatic ERC-20 token balance top-ups + * @dev Enables permissionless triggering of pre-configured top-ups from Safe accounts to agent accounts + */ +interface IAutoTopUpExecutor { + // ============ Structs ============ + + /// @notice User-configurable parameters + struct TopUpConfig { + uint256 dailyLimit; // Target balance to maintain (max top-up per day) + uint256 monthlyLimit; // Maximum total top-ups per month + bool enabled; // Configuration active status + } + + /// @notice Immutable identity and internal state (not user-editable) + struct TopUpState { + address agent; // Target agent account (immutable, part of config ID) + address asset; // ERC-20 token address (immutable, part of config ID) + uint256 lastTopUpDay; // Last top-up day (year * 10000 + month * 100 + day) + uint256 monthlySpent; // Amount topped up this month + uint256 lastResetMonth; // Last reset month (year * 12 + month) + } + + // ============ Events ============ + + event ModuleInstalled(address indexed account, uint256 initialConfigs); + + event ModuleUninstalled(address indexed account, uint256 removedConfigs); + + event TopUpConfigured( + address indexed account, address indexed agent, address asset, bytes32 indexed configId, TopUpConfig config + ); + + event TopUpExecuted( + address indexed account, address indexed agent, address asset, bytes32 indexed configId, uint256 amount + ); + + event TopUpFailed( + address indexed account, address indexed agent, address asset, bytes32 indexed configId, string reason + ); + + event TopUpEnabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId); + + event TopUpDisabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId); + + // ============ Errors ============ + + error ModuleNotInitialized(address account); + error InvalidConfiguration(); + error ConfigNotFound(); + error Unauthorized(bytes32 configId, address caller); + error InvalidAgent(); + error InvalidAsset(); + error AlreadyToppedUpToday(); + error MonthlyLimitExceeded(); + error InsufficientBalance(); + error TopUpNotEnabled(); + error TransferFailed(); + error InvalidTransferReturn(bytes result); + error TransferReturnedFalse(bytes result); + error InvalidConfigurationArrays(); + + // ============ Module Management (ERC-7579) ============ + + /** + * @notice Called when module is installed for an account + * @param data Encoded initial configurations (optional) + * @dev Format: abi.encode(address[], address[], TopUpConfig[]) + * @dev Parallel arrays: agents, assets, and configs at same indices + */ + function onInstall(bytes calldata data) external; + + /** + * @notice Called when module is uninstalled for an account + * @dev Additional data parameter is unused + */ + function onUninstall(bytes calldata) external; + + /** + * @notice Returns whether this module is of a certain type + * @param _typeId The type ID to check + * @return True if this module is an executor (type 0x01) + */ + function isModuleType(uint256 _typeId) external pure returns (bool); + + /** + * @notice Check if module is initialized for an account + * @param smartAccount The account to check + * @return Whether the module is initialized + */ + function isInitialized(address smartAccount) external view returns (bool); + + // ============ Configuration Management ============ + + /** + * @notice Configure a new top-up or update an existing one + * @param agent The agent account to top up + * @param asset The ERC-20 token address + * @param config The top-up configuration + * @return configId The generated config ID + */ + function configureTopUp(address agent, address asset, TopUpConfig memory config) external returns (bytes32 configId); + + /** + * @notice Update an existing top-up configuration by ID + * @param configId The config ID to update + * @param config The new configuration + */ + function configureTopUpById(bytes32 configId, TopUpConfig memory config) external; + + /** + * @notice Enable a top-up configuration + * @param configId The config ID to enable + */ + function enableTopUp(bytes32 configId) external; + + /** + * @notice Disable a top-up configuration + * @param configId The config ID to disable + */ + function disableTopUp(bytes32 configId) external; + + // ============ Execution ============ + + /** + * @notice Trigger all top-ups for a specific account + * @param account The account to trigger top-ups for + * @dev Emits TopUpExecuted for each successful top-up + */ + function triggerTopUps(address account) external; + + /** + * @notice Trigger a specific top-up by config ID + * @param account The account that owns the config + * @param configId The config ID to trigger + * @dev Emits TopUpExecuted if successful, reverts on transfer failure + */ + function triggerTopUp(address account, bytes32 configId) external; + + // ============ View Functions ============ + + /** + * @notice Generate a config ID for given parameters + * @param account The Safe account + * @param agent The agent account + * @param asset The token address + * @return The generated config ID + */ + function generateConfigId(address account, address agent, address asset) external pure returns (bytes32); + + /** + * @notice Get all top-up configurations for an account + * @param account The account to query + * @return configs Array of configurations + * @return states Array of states + */ + function getTopUpConfigs(address account) + external + view + returns (TopUpConfig[] memory configs, TopUpState[] memory states); + + /** + * @notice Check if a top-up can be executed + * @param account The account that owns the config + * @param configId The config ID to check + * @return canExecute Whether the top-up can be executed + * @return reason Reason if cannot execute + */ + function canExecuteTopUp(address account, bytes32 configId) + external + view + returns (bool canExecute, string memory reason); + + /** + * @notice Get top-up by config ID + * @param configId The config ID + * @return config The configuration + * @return state The state + */ + function getTopUpById(bytes32 configId) external view returns (TopUpConfig memory config, TopUpState memory state); + + /** + * @notice Get top-up by account, agent, and asset + * @param account The Safe account + * @param agent The agent account + * @param asset The token address + * @return config The configuration + * @return state The state + */ + function getTopUp(address account, address agent, address asset) + external + view + returns (TopUpConfig memory config, TopUpState memory state); +} diff --git a/solidity/account-modules/test/AutoCollectExecutor.integration.t.sol b/solidity/account-modules/test/AutoCollectExecutor.integration.t.sol new file mode 100644 index 0000000..d03be8b --- /dev/null +++ b/solidity/account-modules/test/AutoCollectExecutor.integration.t.sol @@ -0,0 +1,675 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Test, Vm, console2} from "forge-std/Test.sol"; +import { + RhinestoneModuleKit, + AccountType, + AccountInstance, + UserOpData +} from "modulekit/src/test/RhinestoneModuleKit.sol"; +import {ModuleKitHelpers} from "modulekit/src/test/ModuleKitHelpers.sol"; +import {AutoCollectExecutor} from "../src/AutoCollectExecutor.sol"; +import {IAutoCollectExecutor} from "../src/IAutoCollectExecutor.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { + IModule, + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK, + MODULE_TYPE_HOOK +} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; +import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; + +// Import mocks +import {MockERC20} from "./mocks/MockERC20.sol"; +import {MockUSDT} from "./mocks/MockUSDT.sol"; +import {MaliciousCollectToken} from "./mocks/MaliciousCollectToken.sol"; + +// Integration tests using RhinestoneModuleKit for proper Safe interaction +contract AutoCollectExecutorIntegrationTest is Test, RhinestoneModuleKit { + using SafeERC20 for IERC20; + using ModuleKitHelpers for AccountInstance; + + // Main contracts + AutoCollectExecutor public executor; + MockERC20 public token; + MockUSDT public usdt; + + // Test accounts + AccountInstance public serviceAccount; + address public mainAccount; + address public stranger; + + // Test constants + uint256 constant THRESHOLD = 10 ether; + uint256 constant INITIAL_SERVICE_BALANCE = 100 ether; + uint256 constant INITIAL_MAIN_BALANCE = 1000 ether; + + // Events from the module + event ModuleInstalled(address indexed account, uint256 initialConfigs); + event ModuleUninstalled(address indexed account, uint256 removedConfigs); + event CollectionConfigured( + address indexed account, + address indexed asset, + address target, + bytes32 indexed configId, + IAutoCollectExecutor.CollectConfig config + ); + event CollectionExecuted( + address indexed account, address indexed asset, address target, bytes32 indexed configId, uint256 amount + ); + event CollectionSkipped( + address indexed account, + address indexed asset, + bytes32 indexed configId, + uint256 balance, + uint256 threshold, + uint256 minimumRemaining, + uint256 collectAmount + ); + event CollectionFailed(address indexed account, address indexed asset, bytes32 indexed configId, string reason); + + function setUp() public { + // Initialize ModuleKit with Safe account type + super.init(); + + // Create test addresses + mainAccount = makeAddr("mainAccount"); + stranger = makeAddr("stranger"); + + // Deploy tokens + token = new MockERC20("Test Token", "TEST"); + usdt = new MockUSDT(); + + // Deploy AutoCollectExecutor module as singleton + executor = new AutoCollectExecutor(); + + // Create a Safe service account instance + serviceAccount = makeAccountInstance("service-account"); + + // Fund service account with tokens + token.mint(serviceAccount.account, INITIAL_SERVICE_BALANCE); + usdt.mint(serviceAccount.account, INITIAL_SERVICE_BALANCE); + + // Give main account some initial balance + token.mint(mainAccount, INITIAL_MAIN_BALANCE); + usdt.mint(mainAccount, INITIAL_MAIN_BALANCE); + } + + // ============ Module Installation with Safe ============ + + function test_Integration_InstallModule() public { + // Install the module on the service account using ModuleKit + // Note: Event emissions during UserOp execution cannot be tested with expectEmit + // due to ModuleKit's internal use of recordLogs(). Events are tested in unit tests. + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Verify module is properly installed and initialized + assertTrue(executor.isInitialized(serviceAccount.account)); + assertTrue(serviceAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); + } + + function test_Integration_InstallWithInitialConfigs() public { + // Prepare installation data with initial configurations + address[] memory assets = new address[](2); + IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](2); + + assets[0] = address(token); + assets[1] = address(usdt); + configs[0] = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + configs[1] = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD * 2, minimumRemaining: 0, enabled: true + }); + + bytes memory installData = abi.encode(assets, configs); + + // Install with initial configs using ModuleKit + // Events during UserOp execution are tested in unit tests + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), installData); + + // Verify configs were created + (IAutoCollectExecutor.CollectConfig[] memory retrievedConfigs,) = + executor.getCollectionConfigs(serviceAccount.account); + assertEq(retrievedConfigs.length, 2); + assertTrue(serviceAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); + } + + // ============ Execution Tests with Safe ============ + + function test_Integration_TriggerCollection_Success() public { + // Install module using ModuleKit + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + // Check balances before + uint256 serviceBalanceBefore = token.balanceOf(serviceAccount.account); + uint256 mainBalanceBefore = token.balanceOf(mainAccount); + assertEq(serviceBalanceBefore, INITIAL_SERVICE_BALANCE); + + // Expect the CollectionExecuted event + vm.expectEmit(true, true, true, true); + emit CollectionExecuted(serviceAccount.account, address(token), mainAccount, configId, serviceBalanceBefore); + + // Anyone can trigger the collection (permissionless) + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Check balances after + assertEq(token.balanceOf(serviceAccount.account), 0); // All collected + assertEq(token.balanceOf(mainAccount), mainBalanceBefore + serviceBalanceBefore); + } + + function test_Integration_TriggerCollection_NonStandardToken() public { + // Test with USDT-style token that has non-standard transfer + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(usdt), config); + + // Check initial state + uint256 serviceBalanceBefore = usdt.balanceOf(serviceAccount.account); + uint256 mainBalanceBefore = usdt.balanceOf(mainAccount); + + // Trigger collection with non-standard token + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(usdt)); + + // Verify transfer succeeded despite non-standard return + assertEq(usdt.balanceOf(serviceAccount.account), 0); + assertEq(usdt.balanceOf(mainAccount), mainBalanceBefore + serviceBalanceBefore); + } + + function test_Integration_TriggerAllCollections_BatchExecution() public { + // Setup multiple configs for the same account + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Configure collections for different tokens + vm.startPrank(serviceAccount.account); + IAutoCollectExecutor.CollectConfig memory tokenConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + IAutoCollectExecutor.CollectConfig memory usdtConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + executor.configureCollection(address(token), tokenConfig); + executor.configureCollection(address(usdt), usdtConfig); + vm.stopPrank(); + + // Record balances before + uint256 serviceTokenBefore = token.balanceOf(serviceAccount.account); + uint256 serviceUsdtBefore = usdt.balanceOf(serviceAccount.account); + uint256 mainTokenBefore = token.balanceOf(mainAccount); + uint256 mainUsdtBefore = usdt.balanceOf(mainAccount); + + // Trigger all collections for the service account + vm.prank(stranger); + executor.triggerAllCollections(serviceAccount.account); + + // Should have executed 2 collections (verify by checking balances) + assertEq(token.balanceOf(serviceAccount.account), 0); + assertEq(usdt.balanceOf(serviceAccount.account), 0); + assertEq(token.balanceOf(mainAccount), mainTokenBefore + serviceTokenBefore); + assertEq(usdt.balanceOf(mainAccount), mainUsdtBefore + serviceUsdtBefore); + } + + // ============ Daily Limit Tests ============ + + function test_Integration_DailyLimitReset() public { + // Setup config + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + // First collection (service has 100 ether, above threshold) + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + assertEq(token.balanceOf(serviceAccount.account), 0); + + // Add some tokens back + token.mint(serviceAccount.account, 50 ether); + + // Try to collect again same day - should fail (already collected today) + (bool canExecute, string memory reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); + assertFalse(canExecute); + assertEq(reason, "Already collected today"); + + // Move to next day + vm.warp(block.timestamp + 1 days); + + // Now can execute again (new day, service has 50 ether above threshold) + (canExecute, reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + + // Execute the collection + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + assertEq(token.balanceOf(serviceAccount.account), 0); + } + + function test_Integration_ThresholdEnforcement() public { + // Setup config with high threshold + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + uint256 highThreshold = INITIAL_SERVICE_BALANCE + 50 ether; + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: highThreshold, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + uint256 currentBalance = token.balanceOf(serviceAccount.account); + + // Should not collect - balance below threshold + vm.expectEmit(true, true, true, true); + emit CollectionSkipped( + serviceAccount.account, + address(token), + configId, + currentBalance, + highThreshold, + 0, // minimumRemaining + currentBalance // would collect (balance - 0) + ); + + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Balance should not change + assertEq(token.balanceOf(serviceAccount.account), INITIAL_SERVICE_BALANCE); + + // Add more tokens to exceed threshold + token.mint(serviceAccount.account, 60 ether); + + // Now should be able to collect + (bool canExecute, string memory reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + } + + // ============ Module Uninstall Tests ============ + + function test_Integration_UninstallModule_CleansState() + public + withModuleStorageClearValidation(serviceAccount, address(executor)) + { + // Install and configure using ModuleKit + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + vm.startPrank(serviceAccount.account); + IAutoCollectExecutor.CollectConfig memory tokenConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + IAutoCollectExecutor.CollectConfig memory usdtConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD * 2, minimumRemaining: 0, enabled: true + }); + executor.configureCollection(address(token), tokenConfig); + executor.configureCollection(address(usdt), usdtConfig); + vm.stopPrank(); + + // Verify configs exist + (IAutoCollectExecutor.CollectConfig[] memory configs,) = executor.getCollectionConfigs(serviceAccount.account); + assertEq(configs.length, 2); + + // Uninstall module using ModuleKit + // Events during UserOp execution are tested in unit tests + serviceAccount.uninstallModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Verify state is cleaned + assertFalse(executor.isInitialized(serviceAccount.account)); + assertFalse(serviceAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); + (configs,) = executor.getCollectionConfigs(serviceAccount.account); + assertEq(configs.length, 0); + } + + // ============ Reentrancy Protection Tests ============ + + function test_Integration_ReentrancyProtection() public { + // Deploy malicious token + MaliciousCollectToken malToken = new MaliciousCollectToken(); + + // Setup module with malicious token using ModuleKit + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + executor.configureCollection(address(malToken), config); + + // Set reentrancy target - malicious token will try to call back + malToken.setTarget(executor, serviceAccount.account, address(malToken)); + + // Fund service account with malicious tokens + malToken.mint(serviceAccount.account, INITIAL_SERVICE_BALANCE); + + // Try to trigger - reentrancy guard should prevent issues + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(malToken)); + + // Should have completed successfully despite reentrancy attempt + // Full balance should be collected + assertEq(malToken.balanceOf(serviceAccount.account), 0); + assertEq(malToken.balanceOf(mainAccount), INITIAL_SERVICE_BALANCE); + } + + // ============ Access Control Tests ============ + + function test_Integration_ModuleNotInitialized() public { + // Don't install module - test that uninitialized accounts can't configure + // Stranger cannot configure without module being installed for their account + vm.prank(stranger); + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); + executor.configureCollection(address(token), config); + } + + function test_Integration_CrossAccountConfigurationBlocked() public { + // Install module for serviceAccount only + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Service account can configure for itself + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + // Stranger cannot modify service account's configs (module not initialized for stranger) + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); + executor.disableCollection(configId); + } + + // ============ Edge Case Tests ============ + + function test_Integration_ZeroBalanceSkipped() public { + // Setup module using ModuleKit + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, + threshold: 0, // Zero threshold + minimumRemaining: 0, + enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + // Drain service account balance + vm.prank(serviceAccount.account); + token.transfer(mainAccount, INITIAL_SERVICE_BALANCE); + + uint256 currentBalance = token.balanceOf(serviceAccount.account); + assertEq(currentBalance, 0); + + // Try to trigger - should skip due to zero balance + vm.expectEmit(true, true, true, true); + emit CollectionSkipped( + serviceAccount.account, + address(token), + configId, + 0, // balance + 0, // threshold + 0, // minimumRemaining + 0 // would collect + ); + + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Balance should remain zero + assertEq(token.balanceOf(serviceAccount.account), 0); + } + + function test_Integration_DisabledConfigSkipped() public { + // Setup module using ModuleKit + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + // Disable the configuration + vm.prank(serviceAccount.account); + executor.disableCollection(configId); + + uint256 serviceBalanceBefore = token.balanceOf(serviceAccount.account); + uint256 mainBalanceBefore = token.balanceOf(mainAccount); + + // Try to trigger - should not execute (disabled) + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Balances should not change + assertEq(token.balanceOf(serviceAccount.account), serviceBalanceBefore); + assertEq(token.balanceOf(mainAccount), mainBalanceBefore); + } + + function test_Integration_PartialCollectionAfterThresholdChange() public { + // Setup with low threshold initially + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + // First collection should work (100 ether > 10 ether threshold) + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + assertEq(token.balanceOf(serviceAccount.account), 0); + + // Add some tokens back + token.mint(serviceAccount.account, 5 ether); + + // Update threshold to be higher than current balance + vm.prank(serviceAccount.account); + IAutoCollectExecutor.CollectConfig memory newConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: 20 ether, minimumRemaining: 0, enabled: true + }); + executor.configureCollectionById(configId, newConfig); + + // Move to next day + vm.warp(block.timestamp + 1 days); + + // Should not collect due to threshold (5 ether < 20 ether) + (bool canExecute, string memory reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); + assertFalse(canExecute); + assertEq(reason, "Balance below threshold"); + } + + // ============ Multi-Day Collection Tests ============ + + function test_Integration_CollectionAcrossDays() public { + // Setup config with zero threshold (collect any amount) + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + vm.prank(serviceAccount.account); + IAutoCollectExecutor.CollectConfig memory config = + IAutoCollectExecutor.CollectConfig({target: mainAccount, threshold: 0, minimumRemaining: 0, enabled: true}); + executor.configureCollection(address(token), config); + + // Day 1: Collect all balance + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + assertEq(token.balanceOf(serviceAccount.account), 0); + + // Add some tokens back same day + token.mint(serviceAccount.account, 30 ether); + + // Should not collect again same day + (bool canExecute, string memory reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); + assertFalse(canExecute); + assertEq(reason, "Already collected today"); + + // Move to next day + vm.warp(block.timestamp + 1 days); + + // Day 2: Should be able to collect again + uint256 mainBalanceBeforeDay2 = token.balanceOf(mainAccount); + + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Should have collected the 30 ether + assertEq(token.balanceOf(serviceAccount.account), 0); + assertEq(token.balanceOf(mainAccount), mainBalanceBeforeDay2 + 30 ether); + } + + // ============ Module Type Tests ============ + + function test_Integration_ModuleType() public { + // Verify module type - should only be true for EXECUTOR type + assertTrue(executor.isModuleType(MODULE_TYPE_EXECUTOR)); + assertFalse(executor.isModuleType(MODULE_TYPE_VALIDATOR)); + assertFalse(executor.isModuleType(MODULE_TYPE_FALLBACK)); + assertFalse(executor.isModuleType(MODULE_TYPE_HOOK)); + } + + // ============ Complex Scenarios ============ + + function test_Integration_MultipleServiceAccounts() public { + // Create second service account + AccountInstance memory serviceAccount2 = makeAccountInstance("service-account-2"); + + // Fund second service account + token.mint(serviceAccount2.account, INITIAL_SERVICE_BALANCE); + + // Install module on both accounts + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + serviceAccount2.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Configure collections on both accounts to same main account + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + executor.configureCollection(address(token), config); + + vm.prank(serviceAccount2.account); + executor.configureCollection(address(token), config); + + uint256 mainBalanceBefore = token.balanceOf(mainAccount); + + // Trigger collections from both accounts + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + vm.prank(stranger); + executor.triggerCollection(serviceAccount2.account, address(token)); + + // Both service accounts should be drained, main should receive both balances + assertEq(token.balanceOf(serviceAccount.account), 0); + assertEq(token.balanceOf(serviceAccount2.account), 0); + assertEq(token.balanceOf(mainAccount), mainBalanceBefore + (INITIAL_SERVICE_BALANCE * 2)); + } + + function test_Integration_ConfigurationUpdatesAfterExecution() public { + // Setup and execute first collection + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Add tokens back + token.mint(serviceAccount.account, 40 ether); + + // Update configuration to new target + address newMainAccount = makeAddr("newMainAccount"); + vm.prank(serviceAccount.account); + IAutoCollectExecutor.CollectConfig memory newConfig = IAutoCollectExecutor.CollectConfig({ + target: newMainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + executor.configureCollectionById(configId, newConfig); + + // Move to next day and collect again + vm.warp(block.timestamp + 1 days); + + uint256 newMainBalanceBefore = token.balanceOf(newMainAccount); + + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Should collect to new target + assertEq(token.balanceOf(serviceAccount.account), 0); + assertEq(token.balanceOf(newMainAccount), newMainBalanceBefore + 40 ether); + } + + // ============ Integration Tests for MinimumRemaining ============ + + function test_Integration_PartialCollectionWithMinimumRemaining() public { + // Setup: Service account with 100 tokens, collect with 30 minimumRemaining + // Expected: Collect 70, leave 30 + uint256 minimumRemaining = 30 ether; + uint256 threshold = 50 ether; + + // Install module + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Configure collection with minimumRemaining + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + // Verify initial balances + assertEq(token.balanceOf(serviceAccount.account), INITIAL_SERVICE_BALANCE); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE); + + // Trigger collection + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Verify partial collection - should leave minimumRemaining + uint256 expectedCollected = INITIAL_SERVICE_BALANCE - minimumRemaining; + assertEq(token.balanceOf(serviceAccount.account), minimumRemaining); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollected); + + // Verify config state persists + (IAutoCollectExecutor.CollectConfig memory config,) = executor.getCollectionConfigById(configId); + assertEq(config.minimumRemaining, minimumRemaining); + } +} diff --git a/solidity/account-modules/test/AutoCollectExecutor.t.sol b/solidity/account-modules/test/AutoCollectExecutor.t.sol new file mode 100644 index 0000000..6080146 --- /dev/null +++ b/solidity/account-modules/test/AutoCollectExecutor.t.sol @@ -0,0 +1,1192 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Test, console2} from "forge-std/Test.sol"; +import {AutoCollectExecutor} from "../src/AutoCollectExecutor.sol"; +import {IAutoCollectExecutor} from "../src/IAutoCollectExecutor.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; +import { + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK, + MODULE_TYPE_HOOK +} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; + +// Import mocks +import {MockERC20} from "./mocks/MockERC20.sol"; +import {MockUSDT} from "./mocks/MockUSDT.sol"; +import {MockSafe} from "./mocks/MockSafe.sol"; +import {MockTokenReturnsFalse} from "./mocks/MockTokenReturnsFalse.sol"; + +// Test contract with proper inheritance for module testing +contract AutoCollectExecutorTest is Test { + // Main contracts + AutoCollectExecutor public executor; + MockERC20 public token; + MockUSDT public usdt; + MockSafe public serviceAccount; + + // Test addresses + address public owner; + address public mainAccount; + address public stranger; + + // Test constants + uint256 constant THRESHOLD = 10 ether; + uint256 constant INITIAL_SERVICE_BALANCE = 100 ether; + uint256 constant INITIAL_MAIN_BALANCE = 1000 ether; + + // Events to test + event ModuleInstalled(address indexed account, uint256 initialConfigs); + event ModuleUninstalled(address indexed account, uint256 removedConfigs); + event CollectionConfigured( + address indexed account, + address indexed asset, + address target, + bytes32 indexed configId, + IAutoCollectExecutor.CollectConfig config + ); + event CollectionExecuted( + address indexed account, address indexed asset, address target, bytes32 indexed configId, uint256 amount + ); + event CollectionSkipped( + address indexed account, + address indexed asset, + bytes32 indexed configId, + uint256 balance, + uint256 threshold, + uint256 minimumRemaining, + uint256 collectAmount + ); + event CollectionFailed(address indexed account, address indexed asset, bytes32 indexed configId, string reason); + event CollectionEnabled(address indexed account, address indexed asset, bytes32 indexed configId); + event CollectionDisabled(address indexed account, address indexed asset, bytes32 indexed configId); + + function setUp() public { + // Set up test accounts + owner = makeAddr("owner"); + mainAccount = makeAddr("mainAccount"); + stranger = makeAddr("stranger"); + + // Deploy test tokens + token = new MockERC20("Test Token", "TEST"); + usdt = new MockUSDT(); + + // Deploy mock service account (Safe) + serviceAccount = new MockSafe(owner); + + // Deploy AutoCollectExecutor as singleton + executor = new AutoCollectExecutor(); + + // Enable executor as module on service account + vm.prank(owner); + serviceAccount.enableModule(address(executor)); + + // Fund service account with tokens + token.mint(address(serviceAccount), INITIAL_SERVICE_BALANCE); + usdt.mint(address(serviceAccount), INITIAL_SERVICE_BALANCE); + + // Give main account some initial balance + token.mint(mainAccount, INITIAL_MAIN_BALANCE); + usdt.mint(mainAccount, INITIAL_MAIN_BALANCE); + } + + // ============ Module Installation Tests ============ + + function test_OnInstall_EmptyData() public { + // Install module without initial configs + vm.expectEmit(true, false, false, true); + emit ModuleInstalled(address(serviceAccount), 0); + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + assertTrue(executor.isInitialized(address(serviceAccount))); + } + + function test_OnInstall_WithSingleConfig() public { + // Prepare installation data + address[] memory assets = new address[](1); + IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](1); + + assets[0] = address(token); + configs[0] = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + bytes memory installData = abi.encode(assets, configs); + + // Calculate expected config ID + bytes32 configId = executor.generateConfigId(address(serviceAccount), address(token)); + + // Expect events + vm.expectEmit(true, true, true, true); + emit CollectionConfigured(address(serviceAccount), address(token), mainAccount, configId, configs[0]); + + vm.expectEmit(true, true, true, true); + emit CollectionEnabled(address(serviceAccount), address(token), configId); + + vm.expectEmit(true, false, false, true); + emit ModuleInstalled(address(serviceAccount), 1); + + vm.prank(address(serviceAccount)); + executor.onInstall(installData); + + assertTrue(executor.isInitialized(address(serviceAccount))); + + // Verify config was created + (IAutoCollectExecutor.CollectConfig memory config,) = executor.getCollectionConfigById(configId); + assertEq(config.target, mainAccount); + assertEq(config.threshold, THRESHOLD); + assertEq(config.minimumRemaining, 0); + assertTrue(config.enabled); + } + + function test_OnInstall_RevertInvalidAsset() public { + // Try to install with zero address asset + address[] memory assets = new address[](1); + IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](1); + + assets[0] = address(0); // Invalid + configs[0] = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + bytes memory installData = abi.encode(assets, configs); + + vm.prank(address(serviceAccount)); + vm.expectRevert(IAutoCollectExecutor.InvalidAsset.selector); + executor.onInstall(installData); + } + + function test_OnInstall_RevertInvalidTarget() public { + // Try to install with zero address target + address[] memory assets = new address[](1); + IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](1); + + assets[0] = address(token); + configs[0] = IAutoCollectExecutor.CollectConfig({ + target: address(0), threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); // Invalid target + + bytes memory installData = abi.encode(assets, configs); + + vm.prank(address(serviceAccount)); + vm.expectRevert(IAutoCollectExecutor.InvalidTarget.selector); + executor.onInstall(installData); + } + + // ============ Module Uninstallation Tests ============ + + function test_OnUninstall_CleansUpAllState() public { + // First install with configs + address[] memory assets = new address[](2); + IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](2); + + assets[0] = address(token); + assets[1] = address(usdt); + configs[0] = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + configs[1] = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + executor.onInstall(abi.encode(assets, configs)); + + // Verify installation + assertTrue(executor.isInitialized(address(serviceAccount))); + (IAutoCollectExecutor.CollectConfig[] memory retrievedConfigs,) = + executor.getCollectionConfigs(address(serviceAccount)); + assertEq(retrievedConfigs.length, 2); + + // Now uninstall + vm.expectEmit(true, false, false, true); + emit ModuleUninstalled(address(serviceAccount), 2); + + vm.prank(address(serviceAccount)); + executor.onUninstall(""); + + // Verify all state is cleaned + assertFalse(executor.isInitialized(address(serviceAccount))); + (retrievedConfigs,) = executor.getCollectionConfigs(address(serviceAccount)); + assertEq(retrievedConfigs.length, 0); + } + + // ============ Configuration Management Tests ============ + + function test_ConfigureCollection_NewConfig() public { + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + bytes32 expectedConfigId = executor.generateConfigId(address(serviceAccount), address(token)); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + assertEq(configId, expectedConfigId); + + // Verify config was created + (IAutoCollectExecutor.CollectConfig memory retrievedConfig, IAutoCollectExecutor.CollectState memory state) = + executor.getCollectionConfigById(configId); + assertEq(retrievedConfig.target, mainAccount); + assertEq(retrievedConfig.threshold, THRESHOLD); + assertTrue(retrievedConfig.enabled); + assertEq(state.asset, address(token)); + assertEq(state.lastCollectDate, 0); + } + + function test_ConfigureCollection_RevertInvalidAsset() public { + // Setup: Install module + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + // Try to configure with zero address asset + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.InvalidAsset.selector)); + executor.configureCollection(address(0), config); + } + + function test_ConfigureCollection_RevertInvalidTarget() public { + // Setup: Install module + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + // Try to configure with zero address target + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: address(0), threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.InvalidTarget.selector)); + executor.configureCollection(address(token), config); + } + + function test_ConfigureCollection_ZeroThreshold() public { + // Setup: Install module + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + // Test with zero threshold (should be valid - collect any balance) + IAutoCollectExecutor.CollectConfig memory config = + IAutoCollectExecutor.CollectConfig({target: mainAccount, threshold: 0, minimumRemaining: 0, enabled: true}); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Verify config was created successfully + (IAutoCollectExecutor.CollectConfig memory retrievedConfig,) = executor.getCollectionConfigById(configId); + assertEq(retrievedConfig.target, mainAccount); + assertEq(retrievedConfig.threshold, 0); + assertTrue(retrievedConfig.enabled); + } + + function test_ConfigureCollection_RevertNotInitialized() public { + // Don't install module - try to configure + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + vm.expectRevert( + abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, address(serviceAccount)) + ); + executor.configureCollection(address(token), config); + } + + // ============ Enable/Disable Tests ============ + + function test_EnableDisableCollection() public { + // Setup config (enabled by default) + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Disable it + vm.expectEmit(true, true, true, true); + emit CollectionDisabled(address(serviceAccount), address(token), configId); + + vm.prank(address(serviceAccount)); + executor.disableCollection(configId); + + // Verify it's disabled + (IAutoCollectExecutor.CollectConfig memory retrievedConfig,) = executor.getCollectionConfigById(configId); + assertFalse(retrievedConfig.enabled); + + // Enable it again + vm.expectEmit(true, true, true, true); + emit CollectionEnabled(address(serviceAccount), address(token), configId); + + vm.prank(address(serviceAccount)); + executor.enableCollection(configId); + + // Verify it's enabled + (retrievedConfig,) = executor.getCollectionConfigById(configId); + assertTrue(retrievedConfig.enabled); + } + + function test_EnableDisable_RevertUnauthorized() public { + // Setup config as service account + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Try to disable as stranger (should fail - module not initialized) + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); + executor.disableCollection(configId); + + // Try to enable as stranger (should fail - module not initialized) + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); + executor.enableCollection(configId); + } + + // ============ Configuration By ID Tests ============ + + function test_ConfigureCollectionById_Success() public { + // Setup: Install module and create initial config + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Update config by ID + address newTarget = makeAddr("newTarget"); + uint256 newThreshold = THRESHOLD * 2; + IAutoCollectExecutor.CollectConfig memory newConfig = IAutoCollectExecutor.CollectConfig({ + target: newTarget, threshold: newThreshold, minimumRemaining: 0, enabled: true + }); + + vm.expectEmit(true, true, true, true); + emit CollectionConfigured(address(serviceAccount), address(token), newTarget, configId, newConfig); + + vm.prank(address(serviceAccount)); + executor.configureCollectionById(configId, newConfig); + + // Verify config was updated + (IAutoCollectExecutor.CollectConfig memory retrievedConfig,) = executor.getCollectionConfigById(configId); + assertEq(retrievedConfig.target, newTarget); + assertEq(retrievedConfig.threshold, newThreshold); + assertTrue(retrievedConfig.enabled); + } + + function test_ConfigureCollectionById_RevertConfigNotFound() public { + // Install module but use non-existent configId + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + bytes32 nonExistentConfigId = keccak256("nonexistent"); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ConfigNotFound.selector)); + executor.configureCollectionById(nonExistentConfigId, config); + } + + function test_ConfigureCollectionById_RevertUnauthorized() public { + // Setup: Service account creates a config + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Stranger tries to update service account's config + IAutoCollectExecutor.CollectConfig memory newConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD * 2, minimumRemaining: 0, enabled: true + }); + + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); + executor.configureCollectionById(configId, newConfig); + } + + // ============ Execution Tests ============ + + function test_TriggerCollection_Success() public { + // Setup: Install module and configure collection + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Service account has balance above threshold + uint256 serviceBalanceBefore = token.balanceOf(address(serviceAccount)); + uint256 mainBalanceBefore = token.balanceOf(mainAccount); + assertEq(serviceBalanceBefore, INITIAL_SERVICE_BALANCE); + + // Expect the CollectionExecuted event + vm.expectEmit(true, true, true, true); + emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, serviceBalanceBefore); + + // Trigger the collection + executor.triggerCollection(address(serviceAccount), address(token)); + + // Verify the collection was executed (full balance transferred) + assertEq(token.balanceOf(address(serviceAccount)), 0); + assertEq(token.balanceOf(mainAccount), mainBalanceBefore + serviceBalanceBefore); + } + + function test_TriggerCollection_SkippedBelowThreshold() public { + // Setup with high threshold + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + uint256 highThreshold = INITIAL_SERVICE_BALANCE + 1 ether; + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: highThreshold, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + uint256 currentBalance = token.balanceOf(address(serviceAccount)); + + // Expect CollectionSkipped event + vm.expectEmit(true, true, true, true); + emit CollectionSkipped( + address(serviceAccount), + address(token), + configId, + currentBalance, + highThreshold, + 0, // minimumRemaining + currentBalance // would collect + ); + + // Trigger collection - should be skipped + executor.triggerCollection(address(serviceAccount), address(token)); + + // Balance should not change + assertEq(token.balanceOf(address(serviceAccount)), INITIAL_SERVICE_BALANCE); + } + + function test_TriggerAllCollections_MultipleAssets() public { + // Setup multiple configs for the same account + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + // Configure collections for both tokens + IAutoCollectExecutor.CollectConfig memory tokenConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + IAutoCollectExecutor.CollectConfig memory usdtConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.startPrank(address(serviceAccount)); + executor.configureCollection(address(token), tokenConfig); + executor.configureCollection(address(usdt), usdtConfig); + vm.stopPrank(); + + // Record balances before + uint256 serviceTokenBefore = token.balanceOf(address(serviceAccount)); + uint256 serviceUsdtBefore = usdt.balanceOf(address(serviceAccount)); + uint256 mainTokenBefore = token.balanceOf(mainAccount); + uint256 mainUsdtBefore = usdt.balanceOf(mainAccount); + + // Trigger all collections + vm.prank(stranger); + executor.triggerAllCollections(address(serviceAccount)); + + // Should have executed 2 collections + assertEq(token.balanceOf(address(serviceAccount)), 0); + assertEq(usdt.balanceOf(address(serviceAccount)), 0); + assertEq(token.balanceOf(mainAccount), mainTokenBefore + serviceTokenBefore); + assertEq(usdt.balanceOf(mainAccount), mainUsdtBefore + serviceUsdtBefore); + } + + // ============ Daily Limit Tests ============ + + function test_DailyLimitReset() public { + // Setup config + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // First collection should work + (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + + // Actually execute the collection + executor.triggerCollection(address(serviceAccount), address(token)); + + // Add some tokens back to service account + token.mint(address(serviceAccount), 50 ether); + + // Should not be able to collect again same day + (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertFalse(canExecute); + assertEq(reason, "Already collected today"); + + // Move to next day + vm.warp(block.timestamp + 1 days); + + // Now should be able to collect again + (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + } + + // ============ View Function Tests ============ + + function test_CanExecuteCollection_Conditions() public { + // Setup + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + executor.configureCollection(address(token), config); + + // Should be able to execute (service balance is above threshold) + (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + + // Test with disabled config + bytes32 configId = executor.generateConfigId(address(serviceAccount), address(token)); + vm.prank(address(serviceAccount)); + executor.disableCollection(configId); + + (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertFalse(canExecute); + assertEq(reason, "Collection disabled"); + } + + function test_GetCollectionConfig_Success() public { + // Setup: Install module and create config + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Test getCollectionConfig function + ( + IAutoCollectExecutor.CollectConfig memory retrievedConfig, + IAutoCollectExecutor.CollectState memory retrievedState + ) = executor.getCollectionConfig(address(serviceAccount), address(token)); + + assertEq(retrievedConfig.target, mainAccount); + assertEq(retrievedConfig.threshold, THRESHOLD); + assertTrue(retrievedConfig.enabled); + assertEq(retrievedState.asset, address(token)); + assertEq(retrievedState.lastCollectDate, 0); + } + + function test_GetCollectionConfig_NonExistentConfig() public { + // Test getCollectionConfig with non-existent config + (IAutoCollectExecutor.CollectConfig memory config, IAutoCollectExecutor.CollectState memory state) = + executor.getCollectionConfig(address(serviceAccount), address(token)); + + // Should return zero values for non-existent config + assertEq(config.target, address(0)); + assertEq(config.threshold, 0); + assertEq(config.minimumRemaining, 0); + assertFalse(config.enabled); + assertEq(state.asset, address(0)); + assertEq(state.lastCollectDate, 0); + } + + function test_CanExecuteCollection_ConfigNotFound() public { + bytes32 configId = executor.generateConfigId(address(serviceAccount), address(token)); + + (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + + assertFalse(canExecute); + assertEq(reason, "Config not found"); + } + + function test_GetCollectionConfigs() public { + // Install module and create multiple configs + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory tokenConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + IAutoCollectExecutor.CollectConfig memory usdtConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD * 2, minimumRemaining: 0, enabled: true + }); + + vm.startPrank(address(serviceAccount)); + executor.configureCollection(address(token), tokenConfig); + executor.configureCollection(address(usdt), usdtConfig); + vm.stopPrank(); + + // Get all configs + (IAutoCollectExecutor.CollectConfig[] memory configs, IAutoCollectExecutor.CollectState[] memory states) = + executor.getCollectionConfigs(address(serviceAccount)); + + assertEq(configs.length, 2); + assertEq(states.length, 2); + + // Verify configs (order might vary due to EnumerableSet) + bool foundToken = false; + bool foundUsdt = false; + + for (uint256 i = 0; i < configs.length; i++) { + if (states[i].asset == address(token)) { + foundToken = true; + assertEq(configs[i].target, mainAccount); + assertEq(configs[i].threshold, THRESHOLD); + assertTrue(configs[i].enabled); + } else if (states[i].asset == address(usdt)) { + foundUsdt = true; + assertEq(configs[i].target, mainAccount); + assertEq(configs[i].threshold, THRESHOLD * 2); + assertTrue(configs[i].enabled); + } + } + + assertTrue(foundToken); + assertTrue(foundUsdt); + } + + // ============ Date Boundary Tests ============ + + function test_YearTransition() public { + // Setup config + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + executor.configureCollection(address(token), config); + + // Set time to Dec 31, 2023 + vm.warp(1704067199); // Dec 31, 2023 23:59:59 UTC + + // Execute collection on last day of year + executor.triggerCollection(address(serviceAccount), address(token)); + + // Add tokens back + token.mint(address(serviceAccount), 50 ether); + + // Should not execute again same day + (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertFalse(canExecute); + assertEq(reason, "Already collected today"); + + // Move to Jan 1, 2024 (next year) + vm.warp(1704067200); // Jan 1, 2024 00:00:00 UTC + + // Should be able to execute (new day and new year) + (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + } + + function test_LeapYearFebruary() public { + // Setup config + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + executor.configureCollection(address(token), config); + + // Set time to Feb 28, 2024 (leap year) + vm.warp(1709078400); // Feb 28, 2024 00:00:00 UTC + + // Execute collection on Feb 28 + executor.triggerCollection(address(serviceAccount), address(token)); + + // Add tokens back + token.mint(address(serviceAccount), 50 ether); + + // Move to Feb 29 (leap day) + vm.warp(1709164800); // Feb 29, 2024 00:00:00 UTC + + // Should be able to execute on leap day + (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + + executor.triggerCollection(address(serviceAccount), address(token)); + + // Add tokens back again + token.mint(address(serviceAccount), 50 ether); + + // Move to March 1 + vm.warp(1709251200); // March 1, 2024 00:00:00 UTC + + // Should be able to execute on March 1 + (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + } + + // ============ Fuzz Tests ============ + + function testFuzz_DailyExecutionLimit(uint32 startTimestamp, uint32 timeDelta) public { + // Test that daily execution limit is enforced across various start times and deltas + // Bound start timestamp to reasonable range (year 2020-2030) + uint256 startTime = bound(uint256(startTimestamp), 1577836800, 1893456000); // 2020-2030 + vm.warp(startTime); + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + executor.configureCollection(address(token), config); + + // Execute first collection + executor.triggerCollection(address(serviceAccount), address(token)); + + // Add tokens back + token.mint(address(serviceAccount), 50 ether); + + // Calculate seconds remaining in current calendar day + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + uint256 endOfDay = BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day) + 86400 - 1; + uint256 secondsLeftInDay = endOfDay - block.timestamp; + + // Bound time delta to stay within current calendar day + uint256 deltaSeconds = bound(uint256(timeDelta), 0, secondsLeftInDay); + vm.warp(block.timestamp + deltaSeconds); + + // Should not be able to execute again same calendar day + (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertFalse(canExecute); + assertEq(reason, "Already collected today"); + + // Move to next calendar day + vm.warp(block.timestamp + (secondsLeftInDay - deltaSeconds) + 1); + + // Now should be able to execute + (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + } + + function testFuzz_ConfigurationThresholds(uint256 threshold) public { + // Bound to reasonable values + threshold = bound(threshold, 0, type(uint128).max); + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + // Should succeed with any threshold + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Verify config was stored correctly + (IAutoCollectExecutor.CollectConfig memory retrieved,) = executor.getCollectionConfigById(configId); + assertEq(retrieved.target, mainAccount); + assertEq(retrieved.threshold, threshold); + assertTrue(retrieved.enabled); + } + + // ============ Module Type Tests ============ + + function test_IsModuleType() public { + assertTrue(executor.isModuleType(MODULE_TYPE_EXECUTOR)); + assertFalse(executor.isModuleType(MODULE_TYPE_VALIDATOR)); + assertFalse(executor.isModuleType(MODULE_TYPE_FALLBACK)); + assertFalse(executor.isModuleType(MODULE_TYPE_HOOK)); + } + + // ============ Error Cases Tests ============ + + function test_TriggerCollection_RevertModuleNotInitialized() public { + // Don't install module - try to trigger + vm.expectRevert( + abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, address(serviceAccount)) + ); + executor.triggerCollection(address(serviceAccount), address(token)); + } + + function test_TriggerCollection_RevertConfigNotFound() public { + // Install module but don't create config + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ConfigNotFound.selector)); + executor.triggerCollection(address(serviceAccount), address(token)); + } + + // ============ MinimumRemaining Tests ============ + + function test_CollectWithMinimumRemaining() public { + // Setup: 100 USDC balance, threshold 50, minimumRemaining 20 + // Expected: Collect 80, leave 20 + uint256 minimumRemaining = 20 ether; + uint256 threshold = 50 ether; + + // Install and configure + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + // Verify initial balance + assertEq(token.balanceOf(address(serviceAccount)), INITIAL_SERVICE_BALANCE); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE); + + // Trigger collection + uint256 expectedCollectAmount = INITIAL_SERVICE_BALANCE - minimumRemaining; + + vm.expectEmit(true, true, true, true); + emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, expectedCollectAmount); + + executor.triggerCollection(address(serviceAccount), address(token)); + + // Verify balances + assertEq(token.balanceOf(address(serviceAccount)), minimumRemaining); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollectAmount); + } + + function test_CollectWithZeroThresholdAndMinimumRemaining() public { + // Setup: 100 USDC balance, threshold 0, minimumRemaining 30 + // Expected: Collect 70, leave 30 + uint256 minimumRemaining = 30 ether; + uint256 threshold = 0; + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + // Trigger collection + uint256 expectedCollectAmount = INITIAL_SERVICE_BALANCE - minimumRemaining; + + vm.expectEmit(true, true, true, true); + emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, expectedCollectAmount); + + executor.triggerCollection(address(serviceAccount), address(token)); + + // Verify balances + assertEq(token.balanceOf(address(serviceAccount)), minimumRemaining); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollectAmount); + } + + function test_SkipCollectionWhenMinimumRemainingEqualsBalance() public { + // Setup: 50 USDC balance, threshold 20, minimumRemaining 50 + // Expected: Skip (collect amount = 0) + uint256 balance = 50 ether; + uint256 minimumRemaining = 50 ether; + uint256 threshold = 20 ether; + + // Set service account balance to exactly minimumRemaining + token.burn(address(serviceAccount), INITIAL_SERVICE_BALANCE - balance); + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + // Expect CollectionSkipped event + vm.expectEmit(true, true, true, true); + emit CollectionSkipped( + address(serviceAccount), + address(token), + configId, + balance, // current balance + threshold, + minimumRemaining, + 0 // would collect amount + ); + + executor.triggerCollection(address(serviceAccount), address(token)); + + // Verify balances unchanged + assertEq(token.balanceOf(address(serviceAccount)), balance); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE); + } + + function test_SkipCollectionWhenMinimumRemainingExceedsBalance() public { + // Setup: 40 USDC balance, threshold 20, minimumRemaining 50 + // Expected: Skip (can't leave 50 when we only have 40) + uint256 balance = 40 ether; + uint256 minimumRemaining = 50 ether; + uint256 threshold = 20 ether; + + // Set service account balance + token.burn(address(serviceAccount), INITIAL_SERVICE_BALANCE - balance); + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + // Expect CollectionSkipped event + vm.expectEmit(true, true, true, true); + emit CollectionSkipped( + address(serviceAccount), + address(token), + configId, + balance, // current balance + threshold, + minimumRemaining, + 0 // would collect amount (balance < minimumRemaining, so 0) + ); + + executor.triggerCollection(address(serviceAccount), address(token)); + + // Verify balances unchanged + assertEq(token.balanceOf(address(serviceAccount)), balance); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE); + } + + function test_MinimumRemainingGreaterThanThreshold() public { + // Setup: 100 USDC balance, threshold 10, minimumRemaining 80 + // Expected: Collect 20, leave 80 (triggers at 10 but keeps 80) + uint256 minimumRemaining = 80 ether; + uint256 threshold = 10 ether; + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + // Trigger collection + uint256 expectedCollectAmount = INITIAL_SERVICE_BALANCE - minimumRemaining; + + vm.expectEmit(true, true, true, true); + emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, expectedCollectAmount); + + executor.triggerCollection(address(serviceAccount), address(token)); + + // Verify balances + assertEq(token.balanceOf(address(serviceAccount)), minimumRemaining); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollectAmount); + } + + function test_MinimumRemainingEqualsThreshold() public { + // Setup: 100 USDC balance, threshold 50, minimumRemaining 50 + // Expected: Collect 50, leave 50 + uint256 minimumRemaining = 50 ether; + uint256 threshold = 50 ether; + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + // Trigger collection + uint256 expectedCollectAmount = INITIAL_SERVICE_BALANCE - minimumRemaining; + + vm.expectEmit(true, true, true, true); + emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, expectedCollectAmount); + + executor.triggerCollection(address(serviceAccount), address(token)); + + // Verify balances + assertEq(token.balanceOf(address(serviceAccount)), minimumRemaining); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollectAmount); + } + + function test_CollectionSkippedEventIncludesMinimumRemaining() public { + // Verify new event parameters are emitted correctly when skipping + uint256 threshold = 200 ether; // Higher than balance + uint256 minimumRemaining = 10 ether; + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + uint256 currentBalance = INITIAL_SERVICE_BALANCE; + uint256 wouldCollect = currentBalance - minimumRemaining; + + // Expect CollectionSkipped with all parameters + vm.expectEmit(true, true, true, true); + emit CollectionSkipped( + address(serviceAccount), address(token), configId, currentBalance, threshold, minimumRemaining, wouldCollect + ); + + executor.triggerCollection(address(serviceAccount), address(token)); + } + + // ============ Batch Failure Tests ============ + + function test_TriggerAllCollections_PartialFailure() public { + // Test that if one collection fails, others still succeed + // This demonstrates resilience of batch operations with try-catch + + // Import the bad token mock + MockTokenReturnsFalse badToken = new MockTokenReturnsFalse(); + badToken.mint(address(serviceAccount), INITIAL_SERVICE_BALANCE); + + // Install module + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + // Configure 3 collections: good token, bad token, good USDT + vm.prank(address(serviceAccount)); + bytes32 goodConfigId1 = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }) + ); + + vm.prank(address(serviceAccount)); + bytes32 badConfigId = executor.configureCollection( + address(badToken), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }) + ); + + vm.prank(address(serviceAccount)); + bytes32 goodConfigId2 = executor.configureCollection( + address(usdt), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }) + ); + + // Trigger all collections - should not revert despite badToken failure + executor.triggerAllCollections(address(serviceAccount)); + + // Verify: good tokens collected, bad token remained + assertEq(token.balanceOf(address(serviceAccount)), 0); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + INITIAL_SERVICE_BALANCE); + + assertEq(badToken.balanceOf(address(serviceAccount)), INITIAL_SERVICE_BALANCE); // Failed - balance unchanged + assertEq(badToken.balanceOf(mainAccount), 0); + + assertEq(usdt.balanceOf(address(serviceAccount)), 0); + assertEq(usdt.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + INITIAL_SERVICE_BALANCE); + } + + function test_CollectionFailed_EmitsCorrectReason() public { + // Test that CollectionFailed event contains meaningful error message + MockTokenReturnsFalse badToken = new MockTokenReturnsFalse(); + badToken.mint(address(serviceAccount), INITIAL_SERVICE_BALANCE); + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(badToken), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }) + ); + + // Should emit CollectionFailed with generic reason (custom errors fall to catch(bytes)) + vm.expectEmit(true, true, true, true); + emit CollectionFailed(address(serviceAccount), address(badToken), configId, "Transfer failed"); + + executor.triggerCollection(address(serviceAccount), address(badToken)); + + // Verify state was NOT updated (no collection happened) + (, IAutoCollectExecutor.CollectState memory state) = executor.getCollectionConfigById(configId); + assertEq(state.lastCollectDate, 0); // Should remain 0 since transfer failed + } +} diff --git a/solidity/account-modules/test/AutoTopUpExecutor.integration.t.sol b/solidity/account-modules/test/AutoTopUpExecutor.integration.t.sol new file mode 100644 index 0000000..77e78a5 --- /dev/null +++ b/solidity/account-modules/test/AutoTopUpExecutor.integration.t.sol @@ -0,0 +1,441 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Test, Vm, console2} from "forge-std/Test.sol"; +import { + RhinestoneModuleKit, + AccountType, + AccountInstance, + UserOpData +} from "modulekit/src/test/RhinestoneModuleKit.sol"; +import {ModuleKitHelpers} from "modulekit/src/test/ModuleKitHelpers.sol"; +import {AutoTopUpExecutor} from "../src/AutoTopUpExecutor.sol"; +import {IAutoTopUpExecutor} from "../src/IAutoTopUpExecutor.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { + IModule, + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK, + MODULE_TYPE_HOOK +} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; +import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; + +// Import mocks +import {MockERC20} from "./mocks/MockERC20.sol"; +import {MockUSDT} from "./mocks/MockUSDT.sol"; +import {MaliciousToken} from "./mocks/MaliciousToken.sol"; + +// Integration tests using RhinestoneModuleKit for proper Safe interaction +contract AutoTopUpExecutorIntegrationTest is Test, RhinestoneModuleKit { + using SafeERC20 for IERC20; + using ModuleKitHelpers for AccountInstance; + + // Main contracts + AutoTopUpExecutor public executor; + MockERC20 public token; + MockUSDT public usdt; + + // Test accounts + AccountInstance public safeAccount; + address public agent1; + address public agent2; + address public stranger; + + // Test constants + uint256 constant DAILY_LIMIT = 100 ether; + uint256 constant MONTHLY_LIMIT = 1000 ether; + uint256 constant INITIAL_SAFE_BALANCE = 10000 ether; + uint256 constant INITIAL_AGENT_BALANCE = 50 ether; + + // Events from the module + event ModuleInstalled(address indexed account, uint256 initialConfigs); + event ModuleUninstalled(address indexed account, uint256 removedConfigs); + event TopUpConfigured( + address indexed account, + address indexed agent, + address asset, + bytes32 indexed configId, + IAutoTopUpExecutor.TopUpConfig config + ); + event TopUpExecuted( + address indexed account, address indexed agent, address asset, bytes32 indexed configId, uint256 amount + ); + event TopUpFailed( + address indexed account, address indexed agent, address asset, bytes32 indexed configId, string reason + ); + + function setUp() public { + // Initialize ModuleKit with Safe account type + super.init(); + + // Create test addresses + agent1 = makeAddr("agent1"); + agent2 = makeAddr("agent2"); + stranger = makeAddr("stranger"); + + // Deploy tokens + token = new MockERC20("Test Token", "TEST"); + usdt = new MockUSDT(); + + // Deploy AutoTopUpExecutor module as singleton + executor = new AutoTopUpExecutor(); + + // Create a Safe account instance + safeAccount = makeAccountInstance("safe-account"); + + // Fund Safe account with tokens + token.mint(safeAccount.account, INITIAL_SAFE_BALANCE); + usdt.mint(safeAccount.account, INITIAL_SAFE_BALANCE); + + // Give agents some initial balance (below daily limit) + token.mint(agent1, INITIAL_AGENT_BALANCE); + token.mint(agent2, INITIAL_AGENT_BALANCE); + usdt.mint(agent1, INITIAL_AGENT_BALANCE); + usdt.mint(agent2, INITIAL_AGENT_BALANCE); + } + + // ============ Module Installation with Safe ============ + + function test_Integration_InstallModule() public { + // Install the module on the Safe account using ModuleKit + // Note: Event emissions during UserOp execution cannot be tested with expectEmit + // due to ModuleKit's internal use of recordLogs(). Events are tested in unit tests. + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Verify module is properly installed and initialized + assertTrue(executor.isInitialized(safeAccount.account)); + assertTrue(safeAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); + } + + function test_Integration_InstallWithInitialConfigs() public { + // Prepare installation data with initial configurations + address[] memory agents = new address[](2); + address[] memory assets = new address[](2); + IAutoTopUpExecutor.TopUpConfig[] memory configs = new IAutoTopUpExecutor.TopUpConfig[](2); + + agents[0] = agent1; + agents[1] = agent2; + assets[0] = address(token); + assets[1] = address(token); + + configs[0] = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + configs[1] = IAutoTopUpExecutor.TopUpConfig({ + dailyLimit: DAILY_LIMIT / 2, monthlyLimit: MONTHLY_LIMIT / 2, enabled: false + }); + + bytes memory installData = abi.encode(agents, assets, configs); + + // Install with initial configs using ModuleKit + // Events during UserOp execution are tested in unit tests + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), installData); + + // Verify configs were created + (IAutoTopUpExecutor.TopUpConfig[] memory retrievedConfigs,) = executor.getTopUpConfigs(safeAccount.account); + assertEq(retrievedConfigs.length, 2); + assertTrue(safeAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); + } + + // ============ Execution Tests with Safe ============ + + function test_Integration_TriggerTopUp_Success() public { + // Install module using ModuleKit + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(safeAccount.account); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Check agent balance before + uint256 agentBalanceBefore = token.balanceOf(agent1); + assertEq(agentBalanceBefore, INITIAL_AGENT_BALANCE); + + // Calculate expected top-up amount + uint256 expectedTopUp = DAILY_LIMIT - agentBalanceBefore; + + // Expect the TopUpExecuted event + vm.expectEmit(true, true, true, true); + emit TopUpExecuted(safeAccount.account, agent1, address(token), configId, expectedTopUp); + + // Anyone can trigger the top-up (permissionless) + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + + // Check agent balance after + uint256 agentBalanceAfter = token.balanceOf(agent1); + assertEq(agentBalanceAfter, DAILY_LIMIT); + + // Check Safe balance decreased + assertEq(token.balanceOf(safeAccount.account), INITIAL_SAFE_BALANCE - expectedTopUp); + } + + function test_Integration_TriggerTopUp_NonStandardToken() public { + // Test with USDT-style token that has non-standard transfer + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(safeAccount.account); + bytes32 configId = executor.configureTopUp(agent1, address(usdt), config); + + // Check initial state + uint256 agentBalanceBefore = usdt.balanceOf(agent1); + uint256 expectedTopUp = DAILY_LIMIT - agentBalanceBefore; + + // Trigger top-up with non-standard token + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + + // Verify transfer succeeded despite non-standard return + assertEq(usdt.balanceOf(agent1), DAILY_LIMIT); + assertEq(usdt.balanceOf(safeAccount.account), INITIAL_SAFE_BALANCE - expectedTopUp); + } + + function test_Integration_TriggerTopUps_BatchExecution() public { + // Setup multiple configs for the same account + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + // Configure multiple agents with different tokens + vm.startPrank(safeAccount.account); + executor.configureTopUp(agent1, address(token), config); + executor.configureTopUp(agent2, address(token), config); + executor.configureTopUp(agent1, address(usdt), config); + vm.stopPrank(); + + // Record balances before + uint256 agent1TokenBefore = token.balanceOf(agent1); + uint256 agent2TokenBefore = token.balanceOf(agent2); + uint256 agent1UsdtBefore = usdt.balanceOf(agent1); + + // Trigger all top-ups for the Safe account + vm.prank(stranger); + executor.triggerTopUps(safeAccount.account); + + // Should have executed 3 top-ups (verify by checking balances) + + // Verify all balances were topped up + assertEq(token.balanceOf(agent1), DAILY_LIMIT); + assertEq(token.balanceOf(agent2), DAILY_LIMIT); + assertEq(usdt.balanceOf(agent1), DAILY_LIMIT); + } + + // ============ Daily/Monthly Limit Tests ============ + + function test_Integration_DailyLimitReset() public { + // Setup config with low daily limit + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: 60 ether, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(safeAccount.account); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // First top-up (agent1 has 50 ether, needs 10 ether to reach 60) + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + assertEq(token.balanceOf(agent1), 60 ether); + + // Spend some tokens + vm.prank(agent1); + token.transfer(agent2, 20 ether); + assertEq(token.balanceOf(agent1), 40 ether); + + // Try to top-up again same day - should fail (already topped up today) + (bool canExecute, string memory reason) = executor.canExecuteTopUp(safeAccount.account, configId); + assertFalse(canExecute); + assertEq(reason, "Already topped up today"); + + // Move to next day + vm.warp(block.timestamp + 1 days); + + // Now can execute again (new day, agent balance is 40, needs 20 to reach 60) + (canExecute, reason) = executor.canExecuteTopUp(safeAccount.account, configId); + assertTrue(canExecute); + assertEq(reason, ""); + + // Execute the top-up + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + assertEq(token.balanceOf(agent1), 60 ether); + } + + function test_Integration_MonthlyLimitEnforcement() public { + // Setup config with low monthly limit + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = IAutoTopUpExecutor.TopUpConfig({ + dailyLimit: 100 ether, + monthlyLimit: 120 ether, // Just above one top-up (50 ether needed initially) + enabled: true + }); + + vm.prank(safeAccount.account); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // First top-up should work (agent has 50 ether, needs 50 ether to reach 100) + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + assertEq(token.balanceOf(agent1), 100 ether); + + // Spend most tokens + vm.prank(agent1); + token.transfer(agent2, 90 ether); + assertEq(token.balanceOf(agent1), 10 ether); + + // Move to next day to allow another top-up + vm.warp(block.timestamp + 1 days); + + // Second top-up should be partial (would need 90 ether, but only 70 left in monthly limit) + // Monthly spent: 50 ether, limit: 120 ether, remaining: 70 ether + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + + // Balance should be: 10 (current) + 70 (remaining monthly limit) = 80 ether + assertEq(token.balanceOf(agent1), 80 ether); + + // Move to next day and try again - should fail (monthly limit reached) + vm.warp(block.timestamp + 1 days); + vm.prank(agent1); + token.transfer(agent2, 10 ether); // Spend some to be below daily limit + + (bool canExecute, string memory reason) = executor.canExecuteTopUp(safeAccount.account, configId); + assertFalse(canExecute); + assertEq(reason, "Monthly limit reached"); + } + + // ============ Module Uninstall Tests ============ + + function test_Integration_UninstallModule_CleansState() + public + withModuleStorageClearValidation(safeAccount, address(executor)) + { + // Install and configure using ModuleKit + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.startPrank(safeAccount.account); + executor.configureTopUp(agent1, address(token), config); + executor.configureTopUp(agent2, address(usdt), config); + vm.stopPrank(); + + // Verify configs exist + (IAutoTopUpExecutor.TopUpConfig[] memory configs,) = executor.getTopUpConfigs(safeAccount.account); + assertEq(configs.length, 2); + + // Uninstall module using ModuleKit + // Events during UserOp execution are tested in unit tests + safeAccount.uninstallModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Verify state is cleaned + assertFalse(executor.isInitialized(safeAccount.account)); + assertFalse(safeAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); + (configs,) = executor.getTopUpConfigs(safeAccount.account); + assertEq(configs.length, 0); + } + + // ============ Reentrancy Protection Tests ============ + + function test_Integration_ReentrancyProtection() public { + // Deploy malicious token + MaliciousToken malToken = new MaliciousToken(); + + // Setup module with malicious token using ModuleKit + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(safeAccount.account); + bytes32 configId = executor.configureTopUp(agent1, address(malToken), config); + + // Set reentrancy target + malToken.setTarget(executor, configId); + + // Fund Safe with malicious tokens + malToken.mint(safeAccount.account, INITIAL_SAFE_BALANCE); + + // Try to trigger - reentrancy guard should prevent issues + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + + // Should have completed successfully despite reentrancy attempt + assertEq(malToken.balanceOf(agent1), DAILY_LIMIT); + } + + // ============ Access Control Tests ============ + + function test_Integration_ModuleNotInitialized() public { + // Don't install module - test that uninitialised accounts can't configure + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + // Stranger cannot configure without module being installed for their account + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); + executor.configureTopUp(agent1, address(token), config); + } + + function test_Integration_CrossAccountConfigurationBlocked() public { + // Install module for safeAccount only + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + // Safe account can configure for itself + vm.prank(safeAccount.account); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Stranger cannot modify safe account's configs (module not initialized for stranger) + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); + executor.disableTopUp(configId); + } + + // ============ Edge Case Tests ============ + + function test_Integration_InsufficientSafeBalance() public { + // Setup module using ModuleKit + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(safeAccount.account); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Drain Safe balance + vm.prank(safeAccount.account); + token.transfer(agent2, INITIAL_SAFE_BALANCE); + + // Try to trigger - should fail due to insufficient balance + vm.expectEmit(true, true, true, true); + emit TopUpFailed(safeAccount.account, agent1, address(token), configId, "Insufficient account balance"); + + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + + // Agent balance should not change + assertEq(token.balanceOf(agent1), INITIAL_AGENT_BALANCE); + } + + function test_Integration_ModuleType() public { + // Verify module type - should only be true for EXECUTOR type + assertTrue(executor.isModuleType(MODULE_TYPE_EXECUTOR)); + assertFalse(executor.isModuleType(MODULE_TYPE_VALIDATOR)); + assertFalse(executor.isModuleType(MODULE_TYPE_FALLBACK)); + assertFalse(executor.isModuleType(MODULE_TYPE_HOOK)); + } +} diff --git a/solidity/account-modules/test/AutoTopUpExecutor.t.sol b/solidity/account-modules/test/AutoTopUpExecutor.t.sol new file mode 100644 index 0000000..4a865b9 --- /dev/null +++ b/solidity/account-modules/test/AutoTopUpExecutor.t.sol @@ -0,0 +1,941 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Test, console2} from "forge-std/Test.sol"; +import {AutoTopUpExecutor} from "../src/AutoTopUpExecutor.sol"; +import {IAutoTopUpExecutor} from "../src/IAutoTopUpExecutor.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; + +// Import mocks +import {MockERC20} from "./mocks/MockERC20.sol"; +import {MockUSDT} from "./mocks/MockUSDT.sol"; +import {MockSafe} from "./mocks/MockSafe.sol"; +import {MockTokenBadReturn} from "./mocks/MockTokenBadReturn.sol"; +import {MockTokenReturnsFalse} from "./mocks/MockTokenReturnsFalse.sol"; + +// Test contract with proper inheritance for module testing +contract AutoTopUpExecutorTest is Test { + // Main contracts + AutoTopUpExecutor public executor; + MockERC20 public token; + MockUSDT public usdt; + MockSafe public safe; + + // Test addresses + address public owner; + address public agent1; + address public agent2; + address public stranger; + + // Test constants + uint256 constant DAILY_LIMIT = 100 ether; + uint256 constant MONTHLY_LIMIT = 1000 ether; + uint256 constant INITIAL_SAFE_BALANCE = 10000 ether; + uint256 constant INITIAL_AGENT_BALANCE = 50 ether; // Below daily limit + + // Events to test + event ModuleInstalled(address indexed account, uint256 initialConfigs); + event ModuleUninstalled(address indexed account, uint256 removedConfigs); + event TopUpConfigured( + address indexed account, + address indexed agent, + address asset, + bytes32 indexed configId, + IAutoTopUpExecutor.TopUpConfig config + ); + event TopUpExecuted( + address indexed account, address indexed agent, address asset, bytes32 indexed configId, uint256 amount + ); + event TopUpFailed( + address indexed account, address indexed agent, address asset, bytes32 indexed configId, string reason + ); + event TopUpEnabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId); + event TopUpDisabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId); + + function setUp() public { + // Set up test accounts + owner = makeAddr("owner"); + stranger = makeAddr("stranger"); + agent1 = makeAddr("agent1"); + agent2 = makeAddr("agent2"); + + // Deploy test tokens + token = new MockERC20("Test Token", "TEST"); + usdt = new MockUSDT(); + + // Deploy mock Safe + safe = new MockSafe(owner); + + // Deploy AutoTopUpExecutor as singleton + executor = new AutoTopUpExecutor(); + + // Enable executor as module on Safe + vm.prank(owner); + safe.enableModule(address(executor)); + + // Fund Safe with tokens + token.mint(address(safe), INITIAL_SAFE_BALANCE); + usdt.mint(address(safe), INITIAL_SAFE_BALANCE); + + // Give agents some initial balance (below daily limit) + token.mint(agent1, INITIAL_AGENT_BALANCE); + token.mint(agent2, INITIAL_AGENT_BALANCE); + usdt.mint(agent1, INITIAL_AGENT_BALANCE); + usdt.mint(agent2, INITIAL_AGENT_BALANCE); + } + + // ============ Module Installation Tests ============ + + function test_OnInstall_EmptyData() public { + // Install module without initial configs + vm.expectEmit(true, false, false, true); + emit ModuleInstalled(address(safe), 0); + + vm.prank(address(safe)); + executor.onInstall(""); + + assertTrue(executor.isInitialized(address(safe))); + } + + function test_OnInstall_WithSingleConfig() public { + // Prepare installation data + address[] memory agents = new address[](1); + address[] memory assets = new address[](1); + IAutoTopUpExecutor.TopUpConfig[] memory configs = new IAutoTopUpExecutor.TopUpConfig[](1); + + agents[0] = agent1; + assets[0] = address(token); + configs[0] = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + bytes memory installData = abi.encode(agents, assets, configs); + + // Calculate expected config ID + bytes32 configId = executor.generateConfigId(address(safe), agent1, address(token)); + + // Expect events + vm.expectEmit(true, true, true, true); + emit TopUpConfigured(address(safe), agent1, address(token), configId, configs[0]); + + vm.expectEmit(true, true, true, true); + emit TopUpEnabled(address(safe), agent1, address(token), configId); + + vm.expectEmit(true, false, false, true); + emit ModuleInstalled(address(safe), 1); + + vm.prank(address(safe)); + executor.onInstall(installData); + + assertTrue(executor.isInitialized(address(safe))); + + // Verify config was created + (IAutoTopUpExecutor.TopUpConfig memory config,) = executor.getTopUpById(configId); + assertEq(config.dailyLimit, DAILY_LIMIT); + assertEq(config.monthlyLimit, MONTHLY_LIMIT); + assertTrue(config.enabled); + } + + function test_OnInstall_RevertInvalidAgent() public { + // Try to install with zero address agent + address[] memory agents = new address[](1); + address[] memory assets = new address[](1); + IAutoTopUpExecutor.TopUpConfig[] memory configs = new IAutoTopUpExecutor.TopUpConfig[](1); + + agents[0] = address(0); // Invalid + assets[0] = address(token); + configs[0] = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + bytes memory installData = abi.encode(agents, assets, configs); + + vm.prank(address(safe)); + vm.expectRevert(IAutoTopUpExecutor.InvalidAgent.selector); + executor.onInstall(installData); + } + + // ============ Module Uninstallation Tests ============ + + function test_OnUninstall_CleansUpAllState() public { + // First install with configs + address[] memory agents = new address[](2); + address[] memory assets = new address[](2); + IAutoTopUpExecutor.TopUpConfig[] memory configs = new IAutoTopUpExecutor.TopUpConfig[](2); + + agents[0] = agent1; + agents[1] = agent2; + assets[0] = address(token); + assets[1] = address(token); + + for (uint256 i = 0; i < 2; i++) { + configs[i] = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + } + + vm.prank(address(safe)); + executor.onInstall(abi.encode(agents, assets, configs)); + + // Verify installation + assertTrue(executor.isInitialized(address(safe))); + (IAutoTopUpExecutor.TopUpConfig[] memory retrievedConfigs,) = executor.getTopUpConfigs(address(safe)); + assertEq(retrievedConfigs.length, 2); + + // Now uninstall + vm.expectEmit(true, false, false, true); + emit ModuleUninstalled(address(safe), 2); + + vm.prank(address(safe)); + executor.onUninstall(""); + + // Verify all state is cleaned + assertFalse(executor.isInitialized(address(safe))); + (retrievedConfigs,) = executor.getTopUpConfigs(address(safe)); + assertEq(retrievedConfigs.length, 0); + } + + // ============ Configuration Management Tests ============ + + function test_ConfigureTopUp_NewConfig() public { + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + bytes32 expectedConfigId = executor.generateConfigId(address(safe), agent1, address(token)); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + assertEq(configId, expectedConfigId); + + // Verify config was created + (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig, IAutoTopUpExecutor.TopUpState memory state) = + executor.getTopUpById(configId); + assertEq(retrievedConfig.dailyLimit, DAILY_LIMIT); + assertEq(retrievedConfig.monthlyLimit, MONTHLY_LIMIT); + assertTrue(retrievedConfig.enabled); + assertEq(state.agent, agent1); + assertEq(state.asset, address(token)); + } + + function test_ConfigureTopUp_RevertInvalidAgent_ZeroAddress() public { + // Setup: Install module + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + // Try to configure with zero address agent + vm.prank(address(safe)); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.InvalidAgent.selector)); + executor.configureTopUp(address(0), address(token), config); + } + + function test_ConfigureTopUp_RevertInvalidAgent_SameAsAccount() public { + // Setup: Install module + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + // Try to configure with agent same as account (msg.sender) + vm.prank(address(safe)); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.InvalidAgent.selector)); + executor.configureTopUp(address(safe), address(token), config); + } + + function test_ConfigureTopUp_RevertInvalidAsset() public { + // Setup: Install module + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + // Try to configure with zero address asset + vm.prank(address(safe)); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.InvalidAsset.selector)); + executor.configureTopUp(agent1, address(0), config); + } + + function test_ConfigureTopUp_MaxValues() public { + // Setup: Install module + vm.prank(address(safe)); + executor.onInstall(""); + + // Test with maximum uint256 values + IAutoTopUpExecutor.TopUpConfig memory config = IAutoTopUpExecutor.TopUpConfig({ + dailyLimit: type(uint256).max, monthlyLimit: type(uint256).max, enabled: true + }); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Verify config was created successfully + (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig,) = executor.getTopUpById(configId); + assertEq(retrievedConfig.dailyLimit, type(uint256).max); + assertEq(retrievedConfig.monthlyLimit, type(uint256).max); + assertTrue(retrievedConfig.enabled); + } + + function test_ConfigureTopUp_RevertInvalidConfiguration() public { + vm.prank(address(safe)); + executor.onInstall(""); + + // Zero daily limit + IAutoTopUpExecutor.TopUpConfig memory config1 = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: 0, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + vm.expectRevert(IAutoTopUpExecutor.InvalidConfiguration.selector); + executor.configureTopUp(agent1, address(token), config1); + + // Zero monthly limit + IAutoTopUpExecutor.TopUpConfig memory config2 = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: 0, enabled: true}); + + vm.prank(address(safe)); + vm.expectRevert(IAutoTopUpExecutor.InvalidConfiguration.selector); + executor.configureTopUp(agent1, address(token), config2); + } + + // ============ Enable/Disable Tests ============ + + function test_EnableDisableTopUp() public { + // Setup disabled config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: false}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Enable it + vm.expectEmit(true, true, true, true); + emit TopUpEnabled(address(safe), agent1, address(token), configId); + + vm.prank(address(safe)); + executor.enableTopUp(configId); + + // Verify it's enabled + (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig,) = executor.getTopUpById(configId); + assertTrue(retrievedConfig.enabled); + + // Disable it + vm.expectEmit(true, true, true, true); + emit TopUpDisabled(address(safe), agent1, address(token), configId); + + vm.prank(address(safe)); + executor.disableTopUp(configId); + + // Verify it's disabled + (retrievedConfig,) = executor.getTopUpById(configId); + assertFalse(retrievedConfig.enabled); + } + + function test_EnableDisable_RevertUnauthorized() public { + // Setup config as safe account + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: false}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Try to enable as stranger (should fail - module not initialized) + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); + executor.enableTopUp(configId); + + // Try to disable as stranger (should fail - module not initialized) + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); + executor.disableTopUp(configId); + + // Now test with an initialized but unauthorized account + address otherAccount = makeAddr("otherAccount"); + vm.prank(otherAccount); + executor.onInstall(""); + + // Try to enable config owned by safe account (should fail - unauthorized) + vm.prank(otherAccount); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.Unauthorized.selector, configId, otherAccount)); + executor.enableTopUp(configId); + } + + // ============ View Function Tests ============ + + function test_ConfigureTopUpById_Success() public { + // Setup: Install module and create initial config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory initialConfig = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: false}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), initialConfig); + + // Update config by ID + IAutoTopUpExecutor.TopUpConfig memory newConfig = IAutoTopUpExecutor.TopUpConfig({ + dailyLimit: DAILY_LIMIT * 2, monthlyLimit: MONTHLY_LIMIT * 3, enabled: true + }); + + vm.expectEmit(true, true, true, true); + emit TopUpConfigured(address(safe), agent1, address(token), configId, newConfig); + vm.expectEmit(true, true, true, true); + emit TopUpEnabled(address(safe), agent1, address(token), configId); + + vm.prank(address(safe)); + executor.configureTopUpById(configId, newConfig); + + // Verify config was updated + (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig,) = executor.getTopUpById(configId); + assertEq(retrievedConfig.dailyLimit, DAILY_LIMIT * 2); + assertEq(retrievedConfig.monthlyLimit, MONTHLY_LIMIT * 3); + assertTrue(retrievedConfig.enabled); + } + + function test_ConfigureTopUpById_RevertModuleNotInitialized() public { + // Don't install module for safe + bytes32 configId = keccak256("dummy"); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, address(safe))); + executor.configureTopUpById(configId, config); + } + + function test_ConfigureTopUpById_RevertConfigNotFound() public { + // Install module but use non-existent configId + vm.prank(address(safe)); + executor.onInstall(""); + + bytes32 nonExistentConfigId = keccak256("nonexistent"); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ConfigNotFound.selector)); + executor.configureTopUpById(nonExistentConfigId, config); + } + + function test_ConfigureTopUpById_RevertUnauthorized() public { + // Setup: Safe creates a config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Stranger tries to update safe's config + IAutoTopUpExecutor.TopUpConfig memory newConfig = IAutoTopUpExecutor.TopUpConfig({ + dailyLimit: DAILY_LIMIT * 2, monthlyLimit: MONTHLY_LIMIT * 2, enabled: false + }); + + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); + executor.configureTopUpById(configId, newConfig); + } + + function test_ConfigureTopUpById_RevertInvalidConfiguration() public { + // Setup: Install module and create initial config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory initialConfig = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), initialConfig); + + // Try to update with invalid config (zero daily limit) + IAutoTopUpExecutor.TopUpConfig memory invalidConfig = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: 0, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.InvalidConfiguration.selector)); + executor.configureTopUpById(configId, invalidConfig); + } + + function test_TriggerTopUp_EmitsEvent() public { + // Setup: Install module and configure top-up + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Agent has low balance, needs top-up + uint256 agentBalanceBefore = token.balanceOf(agent1); + uint256 expectedTopUp = DAILY_LIMIT - agentBalanceBefore; + + // Expect the TopUpExecuted event + vm.expectEmit(true, true, true, true); + emit TopUpExecuted(address(safe), agent1, address(token), configId, expectedTopUp); + + // Trigger the top-up + executor.triggerTopUp(address(safe), configId); + + // Verify the top-up was executed + assertEq(token.balanceOf(agent1), DAILY_LIMIT); + } + + function test_CanExecuteTopUp_Conditions() public { + // Setup + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Should be able to execute (agent balance is below daily limit) + (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + + // Fund agent to be above daily limit + token.mint(agent1, DAILY_LIMIT); + + // Should not be able to execute now + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertFalse(canExecute); + assertEq(reason, "Agent balance sufficient"); + + // Test with disabled config + vm.prank(address(safe)); + executor.disableTopUp(configId); + + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertFalse(canExecute); + assertEq(reason, "Top-up disabled"); + } + + function test_TransferValidation_InvalidReturn() public { + // Setup: Install module and configure top-up + vm.prank(address(safe)); + executor.onInstall(""); + + // Create a token that returns malformed data + MockTokenBadReturn badToken = new MockTokenBadReturn(); + badToken.mint(address(safe), INITIAL_SAFE_BALANCE); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(badToken), config); + + // Should emit TopUpFailed when transfer returns malformed data (now caught by try-catch) + vm.prank(stranger); + vm.expectEmit(true, true, true, true); + emit TopUpFailed(address(safe), agent1, address(badToken), configId, "Transfer failed"); + executor.triggerTopUp(address(safe), configId); + + // Verify state was NOT updated (no top-up happened) + (, IAutoTopUpExecutor.TopUpState memory state) = executor.getTopUpById(configId); + assertEq(state.lastTopUpDay, 0); // Should remain 0 since transfer failed + assertEq(state.monthlySpent, 0); // Should remain 0 since transfer failed + } + + function test_TransferValidation_ReturnsFalse() public { + // Setup: Install module and configure top-up + vm.prank(address(safe)); + executor.onInstall(""); + + // Create a token that returns false on transfer + MockTokenReturnsFalse falseToken = new MockTokenReturnsFalse(); + falseToken.mint(address(safe), INITIAL_SAFE_BALANCE); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(falseToken), config); + + // Should emit TopUpFailed when transfer returns false (now caught by try-catch) + vm.prank(stranger); + vm.expectEmit(true, true, true, true); + emit TopUpFailed(address(safe), agent1, address(falseToken), configId, "Transfer failed"); + executor.triggerTopUp(address(safe), configId); + + // Verify state was NOT updated (no top-up happened) + (, IAutoTopUpExecutor.TopUpState memory state) = executor.getTopUpById(configId); + assertEq(state.lastTopUpDay, 0); // Should remain 0 since transfer failed + assertEq(state.monthlySpent, 0); // Should remain 0 since transfer failed + } + + function test_GetTopUp_Success() public { + // Setup: Install module and create config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Test getTopUp function + (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig, IAutoTopUpExecutor.TopUpState memory retrievedState) = + executor.getTopUp(address(safe), agent1, address(token)); + + assertEq(retrievedConfig.dailyLimit, DAILY_LIMIT); + assertEq(retrievedConfig.monthlyLimit, MONTHLY_LIMIT); + assertTrue(retrievedConfig.enabled); + assertEq(retrievedState.agent, agent1); + assertEq(retrievedState.asset, address(token)); + } + + function test_GetTopUp_NonExistentConfig() public { + // Test getTopUp with non-existent config + (IAutoTopUpExecutor.TopUpConfig memory config, IAutoTopUpExecutor.TopUpState memory state) = + executor.getTopUp(address(safe), agent1, address(token)); + + // Should return zero values for non-existent config + assertEq(config.dailyLimit, 0); + assertEq(config.monthlyLimit, 0); + assertFalse(config.enabled); + assertEq(state.agent, address(0)); + assertEq(state.asset, address(0)); + } + + function test_CanExecuteTopUp_ConfigNotFound() public { + bytes32 nonExistentConfigId = keccak256("nonexistent"); + + (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), nonExistentConfigId); + + assertFalse(canExecute); + assertEq(reason, "Config not found"); + } + + function test_CanExecuteTopUp_AccountDoesntOwnConfig() public { + // Setup: Safe creates a config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Try to check canExecute with different account (stranger) + (bool canExecute, string memory reason) = executor.canExecuteTopUp(stranger, configId); + + assertFalse(canExecute); + assertEq(reason, "Account doesn't own config"); + } + + function test_GetTopUpConfigs() public { + // Install module and create multiple configs + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config1 = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + IAutoTopUpExecutor.TopUpConfig memory config2 = IAutoTopUpExecutor.TopUpConfig({ + dailyLimit: DAILY_LIMIT / 2, monthlyLimit: MONTHLY_LIMIT / 2, enabled: false + }); + + vm.startPrank(address(safe)); + executor.configureTopUp(agent1, address(token), config1); + executor.configureTopUp(agent2, address(usdt), config2); + vm.stopPrank(); + + // Get all configs + (IAutoTopUpExecutor.TopUpConfig[] memory configs, IAutoTopUpExecutor.TopUpState[] memory states) = + executor.getTopUpConfigs(address(safe)); + + assertEq(configs.length, 2); + assertEq(states.length, 2); + + // Verify first config + assertEq(configs[0].dailyLimit, DAILY_LIMIT); + assertEq(configs[0].monthlyLimit, MONTHLY_LIMIT); + assertTrue(configs[0].enabled); + + // Verify second config + assertEq(configs[1].dailyLimit, DAILY_LIMIT / 2); + assertEq(configs[1].monthlyLimit, MONTHLY_LIMIT / 2); + assertFalse(configs[1].enabled); + } + + // ============ Date Boundary Tests ============ + + function test_DailyLimitReset() public { + // Setup config with daily limit + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // First execution should work + (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + + // Actually execute the top-up + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + + // Should not be able to execute again same day (daily limit enforced) + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertFalse(canExecute); + assertEq(reason, "Already topped up today"); + + // Move to next day + vm.warp(block.timestamp + 1 days); + + // Now check - should not execute because agent balance is sufficient + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertFalse(canExecute); + assertEq(reason, "Agent balance sufficient"); + + // Reduce agent balance to need another top-up + vm.prank(agent1); + token.transfer(agent2, 60 ether); + + // Now should be able to execute + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + } + + function test_MonthlyLimitReset() public { + // Setup config with low monthly limit (just enough for 2 top-ups) + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = IAutoTopUpExecutor.TopUpConfig({ + dailyLimit: DAILY_LIMIT, + monthlyLimit: 110 ether, // Allows ~2 top-ups of 50 ether each + enabled: true + }); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // First top-up should work + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + assertEq(token.balanceOf(agent1), DAILY_LIMIT); + + // Spend tokens and move to next day + vm.prank(agent1); + token.transfer(agent2, 90 ether); + vm.warp(block.timestamp + 1 days); + + // Second top-up should work (still within monthly limit) + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + + // After second top-up, agent should have less than daily limit due to monthly limit + // Monthly limit is 110 ether, already spent 50 ether, so can only top up 60 ether more + // Agent had 10 ether, topped up by 60 ether to reach 70 ether + assertEq(token.balanceOf(agent1), 70 ether); + + // Spend tokens and move to next day (transfer less than balance) + vm.prank(agent1); + token.transfer(agent2, 60 ether); + vm.warp(block.timestamp + 1 days); + + // Third top-up should fail (monthly limit reached) + (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); + assertFalse(canExecute); + assertEq(reason, "Monthly limit reached"); + + // Move to next month (30 days forward to ensure month change) + vm.warp(block.timestamp + 30 days); + + // Should be able to execute again (new month) + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + + // Execute to verify it actually works + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + assertEq(token.balanceOf(agent1), DAILY_LIMIT); + } + + function test_YearTransition() public { + // Setup config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Set time to Dec 31, 2023 + vm.warp(1704067199); // Dec 31, 2023 23:59:59 UTC + + // Execute top-up on last day of year + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + + // Reduce balance to need another top-up + vm.prank(agent1); + token.transfer(agent2, 60 ether); + + // Should not execute again same day + (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); + assertFalse(canExecute); + assertEq(reason, "Already topped up today"); + + // Move to Jan 1, 2024 (next year) + vm.warp(1704067200); // Jan 1, 2024 00:00:00 UTC + + // Should be able to execute (new day and new year) + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + + // Verify execution works + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + assertEq(token.balanceOf(agent1), DAILY_LIMIT); + } + + function test_LeapYearFebruary() public { + // Setup config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Set time to Feb 28, 2024 (leap year) + vm.warp(1709078400); // Feb 28, 2024 00:00:00 UTC + + // Execute top-up on Feb 28 + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + + // Reduce balance + vm.prank(agent1); + token.transfer(agent2, 60 ether); + + // Move to Feb 29 (leap day) + vm.warp(1709164800); // Feb 29, 2024 00:00:00 UTC + + // Should be able to execute on leap day + (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + + // Reduce balance again + vm.prank(agent1); + token.transfer(agent2, 60 ether); + + // Move to March 1 + vm.warp(1709251200); // March 1, 2024 00:00:00 UTC + + // Should be able to execute on March 1 + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + } + + // ============ Fuzz Tests ============ + + function testFuzz_DailyExecutionLimit(uint32 startTimestamp, uint32 timeDelta) public { + // Test that daily execution limit is enforced across various start times and deltas + // Bound start timestamp to reasonable range (year 2020-2030) + uint256 startTime = bound(uint256(startTimestamp), 1577836800, 1893456000); // 2020-2030 + vm.warp(startTime); + + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Execute first top-up + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + + // Reduce balance to need another top-up + vm.prank(agent1); + token.transfer(agent2, 60 ether); + + // Calculate seconds remaining in current calendar day + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + uint256 endOfDay = BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day) + 86400 - 1; + uint256 secondsLeftInDay = endOfDay - block.timestamp; + + // Bound time delta to stay within current calendar day + uint256 deltaSeconds = bound(uint256(timeDelta), 0, secondsLeftInDay); + vm.warp(block.timestamp + deltaSeconds); + + // Should not be able to execute again same calendar day + (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); + assertFalse(canExecute); + assertEq(reason, "Already topped up today"); + + // Move to next calendar day + vm.warp(block.timestamp + (secondsLeftInDay - deltaSeconds) + 1); + + // Now should be able to execute + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + } + + function testFuzz_ConfigurationLimits(uint256 dailyLimit, uint256 monthlyLimit) public { + // Bound to reasonable values + dailyLimit = bound(dailyLimit, 1, type(uint128).max); + monthlyLimit = bound(monthlyLimit, 1, type(uint128).max); + + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: dailyLimit, monthlyLimit: monthlyLimit, enabled: true}); + + // Should succeed with valid limits + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Verify config was stored correctly + (IAutoTopUpExecutor.TopUpConfig memory retrieved,) = executor.getTopUpById(configId); + assertEq(retrieved.dailyLimit, dailyLimit); + assertEq(retrieved.monthlyLimit, monthlyLimit); + } +} diff --git a/solidity/account-modules/test/mocks/MaliciousCollectToken.sol b/solidity/account-modules/test/mocks/MaliciousCollectToken.sol new file mode 100644 index 0000000..fffb1df --- /dev/null +++ b/solidity/account-modules/test/mocks/MaliciousCollectToken.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {AutoCollectExecutor} from "../../src/AutoCollectExecutor.sol"; + +// Malicious token that tries to re-enter during transfer for collection tests +contract MaliciousCollectToken is ERC20 { + AutoCollectExecutor public target; + address public targetAccount; + address public targetAsset; + + constructor() ERC20("MaliciousCollect", "MALCOL") {} + + function setTarget(AutoCollectExecutor _target, address _account, address _asset) external { + target = _target; + targetAccount = _account; + targetAsset = _asset; + } + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } + + function transfer(address to, uint256 amount) public override returns (bool) { + // Try to re-enter during transfer + if (address(target) != address(0)) { + try target.triggerCollection(targetAccount, targetAsset) {} catch {} + } + return super.transfer(to, amount); + } +} diff --git a/solidity/account-modules/test/mocks/MaliciousToken.sol b/solidity/account-modules/test/mocks/MaliciousToken.sol new file mode 100644 index 0000000..e88e6b3 --- /dev/null +++ b/solidity/account-modules/test/mocks/MaliciousToken.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {AutoTopUpExecutor} from "../../src/AutoTopUpExecutor.sol"; + +// Malicious token that tries to re-enter during transfer +contract MaliciousToken is ERC20 { + AutoTopUpExecutor public target; + bytes32 public targetConfigId; + + constructor() ERC20("Malicious", "MAL") {} + + function setTarget(AutoTopUpExecutor _target, bytes32 _configId) external { + target = _target; + targetConfigId = _configId; + } + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } + + function transfer(address to, uint256 amount) public override returns (bool) { + // Try to re-enter during transfer + if (address(target) != address(0)) { + try target.triggerTopUp(address(this), targetConfigId) {} catch {} + } + return super.transfer(to, amount); + } +} diff --git a/solidity/account-modules/test/mocks/MockERC20.sol b/solidity/account-modules/test/mocks/MockERC20.sol new file mode 100644 index 0000000..96c6a65 --- /dev/null +++ b/solidity/account-modules/test/mocks/MockERC20.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract MockERC20 is ERC20 { + constructor(string memory name, string memory symbol) ERC20(name, symbol) {} + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } + + function burn(address from, uint256 amount) external { + _burn(from, amount); + } +} diff --git a/solidity/account-modules/test/mocks/MockSafe.sol b/solidity/account-modules/test/mocks/MockSafe.sol new file mode 100644 index 0000000..18d90ab --- /dev/null +++ b/solidity/account-modules/test/mocks/MockSafe.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {ModeCode} from "modulekit/src/accounts/common/lib/ModeLib.sol"; +import {ExecutionLib} from "modulekit/src/accounts/erc7579/lib/ExecutionLib.sol"; + +// Mock Safe contract for testing ERC-7579 module execution +contract MockSafe { + mapping(address => bool) public isModuleEnabled; + + // Storage for execution results + bool public lastExecutionSuccess; + bytes public lastExecutionResult; + + // Mock owner for testing + address public owner; + + constructor(address _owner) { + owner = _owner; + } + + function enableModule(address module) external { + require(msg.sender == owner, "Only owner"); + isModuleEnabled[module] = true; + } + + // ERC-7579 compatible execution function + // This is called by the module's _execute function via ERC7579ExecutorBase + function executeFromExecutor( + ModeCode, // mode - we ignore this in the mock + bytes calldata executionCalldata + ) + external + payable + returns (bytes[] memory returnData) + { + require(isModuleEnabled[msg.sender], "Module not enabled"); + + // Decode the execution calldata + // For single execution mode, it's encoded as (target, value, callData) + (address target, uint256 value, bytes memory data) = ExecutionLib.decodeSingle(executionCalldata); + + // Execute the call + bool success; + bytes memory result; + (success, result) = target.call{value: value}(data); + lastExecutionSuccess = success; + lastExecutionResult = result; + + if (!success) { + // Bubble up the revert reason + assembly { + revert(add(result, 32), mload(result)) + } + } + + // Return as array (ERC-7579 expects array of results) + returnData = new bytes[](1); + returnData[0] = result; + + return returnData; + } +} diff --git a/solidity/account-modules/test/mocks/MockTokenBadReturn.sol b/solidity/account-modules/test/mocks/MockTokenBadReturn.sol new file mode 100644 index 0000000..28a2b79 --- /dev/null +++ b/solidity/account-modules/test/mocks/MockTokenBadReturn.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +// Mock ERC20 token that returns malformed data (not 32 bytes) on transfer +contract MockTokenBadReturn { + mapping(address => uint256) private _balances; + mapping(address => mapping(address => uint256)) private _allowances; + uint256 private _totalSupply; + + string public name = "Bad Return Token"; + string public symbol = "BAD"; + uint8 public decimals = 18; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function allowance(address owner, address spender) public view returns (uint256) { + return _allowances[owner][spender]; + } + + function approve(address spender, uint256 amount) external returns (bool) { + _allowances[msg.sender][spender] = amount; + return true; + } + + function transfer(address to, uint256 amount) external returns (bool) { + require(_balances[msg.sender] >= amount, "Insufficient balance"); + _balances[msg.sender] -= amount; + _balances[to] += amount; + + // Return malformed data (64 bytes instead of 32) + assembly { + let ptr := mload(0x40) + mstore(ptr, 0x0000000000000000000000000000000000000000000000000000000000000001) + mstore(add(ptr, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000001) + return(ptr, 0x40) + } + } + + function transferFrom(address from, address to, uint256 amount) external returns (bool) { + require(_balances[from] >= amount, "Insufficient balance"); + require(_allowances[from][msg.sender] >= amount, "Insufficient allowance"); + + _balances[from] -= amount; + _balances[to] += amount; + _allowances[from][msg.sender] -= amount; + + return true; + } + + function mint(address to, uint256 amount) external { + _balances[to] += amount; + _totalSupply += amount; + } +} diff --git a/solidity/account-modules/test/mocks/MockTokenReturnsFalse.sol b/solidity/account-modules/test/mocks/MockTokenReturnsFalse.sol new file mode 100644 index 0000000..1310406 --- /dev/null +++ b/solidity/account-modules/test/mocks/MockTokenReturnsFalse.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +// Mock ERC20 token that returns false on transfer +contract MockTokenReturnsFalse { + mapping(address => uint256) private _balances; + mapping(address => mapping(address => uint256)) private _allowances; + uint256 private _totalSupply; + + string public name = "False Return Token"; + string public symbol = "FALSE"; + uint8 public decimals = 18; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function allowance(address owner, address spender) public view returns (uint256) { + return _allowances[owner][spender]; + } + + function approve(address spender, uint256 amount) external returns (bool) { + _allowances[msg.sender][spender] = amount; + return true; + } + + function transfer(address to, uint256 amount) external returns (bool) { + require(_balances[msg.sender] >= amount, "Insufficient balance"); + _balances[msg.sender] -= amount; + _balances[to] += amount; + + // Always return false even on successful transfer + return false; + } + + function transferFrom(address from, address to, uint256 amount) external returns (bool) { + require(_balances[from] >= amount, "Insufficient balance"); + require(_allowances[from][msg.sender] >= amount, "Insufficient allowance"); + + _balances[from] -= amount; + _balances[to] += amount; + _allowances[from][msg.sender] -= amount; + + return true; + } + + function mint(address to, uint256 amount) external { + _balances[to] += amount; + _totalSupply += amount; + } +} diff --git a/solidity/account-modules/test/mocks/MockUSDT.sol b/solidity/account-modules/test/mocks/MockUSDT.sol new file mode 100644 index 0000000..39ccb57 --- /dev/null +++ b/solidity/account-modules/test/mocks/MockUSDT.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +// Mock ERC20 token that returns nothing on transfer (like USDT) +contract MockUSDT { + mapping(address => uint256) private _balances; + mapping(address => mapping(address => uint256)) private _allowances; + uint256 private _totalSupply; + + string public name = "Mock USDT"; + string public symbol = "mUSDT"; + uint8 public decimals = 6; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function allowance(address owner, address spender) public view returns (uint256) { + return _allowances[owner][spender]; + } + + // USDT-style transfer that returns nothing + function transfer(address to, uint256 amount) external { + require(_balances[msg.sender] >= amount, "Insufficient balance"); + _balances[msg.sender] -= amount; + _balances[to] += amount; + // No return value - mimics USDT behavior + } + + function approve(address spender, uint256 amount) external returns (bool) { + _allowances[msg.sender][spender] = amount; + return true; + } + + function transferFrom(address from, address to, uint256 amount) external returns (bool) { + require(_balances[from] >= amount, "Insufficient balance"); + require(_allowances[from][msg.sender] >= amount, "Insufficient allowance"); + + _balances[from] -= amount; + _balances[to] += amount; + _allowances[from][msg.sender] -= amount; + + return true; + } + + function mint(address to, uint256 amount) external { + _balances[to] += amount; + _totalSupply += amount; + } +} diff --git a/typescript/packages/account-modules/.github/workflows/test.yml b/typescript/packages/account-modules/.github/workflows/test.yml new file mode 100644 index 0000000..4481ec6 --- /dev/null +++ b/typescript/packages/account-modules/.github/workflows/test.yml @@ -0,0 +1,40 @@ +name: CI + +on: + push: + pull_request: + workflow_dispatch: + +env: + FOUNDRY_PROFILE: ci + +jobs: + check: + name: Foundry project + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: Show Forge version + run: | + forge --version + + - name: Run Forge fmt + run: | + forge fmt --check + id: fmt + + - name: Run Forge build + run: | + forge build --sizes + id: build + + - name: Run Forge tests + run: | + forge test -vvv + id: test diff --git a/typescript/packages/account-modules/.gitignore b/typescript/packages/account-modules/.gitignore new file mode 100644 index 0000000..3269660 --- /dev/null +++ b/typescript/packages/account-modules/.gitignore @@ -0,0 +1,11 @@ +# Compiler files +cache/ +out/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Dotenv file +.env diff --git a/typescript/packages/account-modules/README.md b/typescript/packages/account-modules/README.md new file mode 100644 index 0000000..1e67976 --- /dev/null +++ b/typescript/packages/account-modules/README.md @@ -0,0 +1,69 @@ +# Account Modules + +ERC-7579 compliant executor modules for smart account automation in the x402 payments system. + +## Modules + +### AutoTopUpModule +- Automatically tops up agent accounts when balance falls below threshold +- Configurable per-agent limits (daily, monthly) +- Permissionless triggering with proper checks +- Used by: Main accounts to fund agent accounts + +### AutoCollectModule +- Automatically collects payments from service accounts +- Configurable collection thresholds (amount and time) +- Batch collection optimization +- Used by: Service accounts to collect to main accounts + +## Architecture + +All modules implement the ERC-7579 executor module interface: +- `onInstall(bytes calldata data)` - Module installation +- `onUninstall(bytes calldata data)` - Module removal +- `isModuleType(uint256 typeID)` - Returns true for executor type (0x01) +- `isInitialized(address account)` - Check if module is initialized for account + +## Deployment + +The modules are deployed as immutable singletons using Safe's Singleton Factory, ensuring the same addresses across all chains: + +- **AutoTopUpExecutor**: `0x16f13052FbFFfcE34E5752b7F4CFF881a030F40B` +- **AutoCollectExecutor**: `0x29864bd91370886c38dE9Fe95F5589E7EbE15130` + +These addresses are deterministic and will remain consistent on all supported chains (Base, Base Sepolia, etc.). + +## Development + +### Prerequisites + +- [Foundry](https://book.getfoundry.sh/getting-started/installation) +- [pnpm](https://pnpm.io/installation) (for ModuleKit dependencies) + +### Setup + +```bash +# Install Forge dependencies +forge install + +# Install ModuleKit node dependencies (required for compilation) +cd lib/modulekit && npm install && cd ../.. + +# Build contracts +forge build + +# Run tests +forge test + +# Deploy +forge script script/Deploy.s.sol --rpc-url $RPC_URL --broadcast +``` + +**Important**: ModuleKit requires its node modules to be installed for proper compilation. This step (`pnpm install` in the modulekit directory) must be performed after cloning the repository and before building. + +## Security + +- Non-custodial design - modules only execute based on user-defined rules +- Access control via ERC-7579 standards +- Immutable singleton contracts - no upgradeability, no owner +- Comprehensive event logging \ No newline at end of file diff --git a/typescript/packages/account-modules/docs/auto-collect/architecture.md b/typescript/packages/account-modules/docs/auto-collect/architecture.md new file mode 100644 index 0000000..5da5185 --- /dev/null +++ b/typescript/packages/account-modules/docs/auto-collect/architecture.md @@ -0,0 +1,252 @@ +# AutoCollectExecutor Architecture + +## Overview + +AutoCollectExecutor is an ERC-7579 executor module that automatically collects funds from service accounts to a main seller account. It mirrors the AutoTopUpExecutor pattern but reverses the transfer direction - collecting funds FROM the account where the module is installed TO a configured target account. + +## Key Design Principles + +1. **Installation Location**: Module is installed ON each service account (not on main account) +2. **Transfer Direction**: FROM service account (where module is installed) TO main account +3. **Permissionless Execution**: Anyone can trigger collections (gas incentives for automation) +4. **Calendar-Based Limits**: Collections limited to once per calendar day (UTC) +5. **Per-Asset Configuration**: Each token has its own collection configuration + +## Architecture Components + +### Storage Structure + +```solidity +// Configuration per asset +struct CollectConfig { + address target; // Main account to collect funds to + address asset; // ERC-20 token address + uint256 threshold; // Minimum balance to trigger collection (0 = no threshold) + uint256 minimumRemaining; // Minimum amount to leave in account (0 = collect all) + bool enabled; // Whether collection is enabled +} + +// State tracking per configuration +struct CollectState { + uint256 lastCollectDate; // Last collection date (YYYYMMDD format) +} + +// Storage mappings +mapping(uint256 => CollectConfig) configs; // configId => config +mapping(uint256 => CollectState) states; // configId => state +mapping(address => EnumerableSet.Bytes32Set) accountConfigs; // service account => configIds (using EnumerableSet) + +// Config ID generation (deterministic) +configId = keccak256(abi.encode("CollectConfig", serviceAccount, asset)) +``` + +### Core Functions + +#### Module Lifecycle +- `onInstall(bytes calldata data)` - Install with optional initial configurations +- `onUninstall(bytes calldata)` - Clean up all configurations and state +- `isModuleType(uint256 typeID)` - Returns MODULE_TYPE_EXECUTOR constant +- `isInitialized(address account)` - Check if module is initialized for account + +#### Configuration Management +- `configureCollection(address asset, CollectConfig config)` - Create/update config for msg.sender +- `enableCollection(bytes32 configId)` - Enable collection for a config +- `disableCollection(bytes32 configId)` - Disable collection for a config + +#### Collection Execution +- `triggerCollection(address account, address asset)` - Trigger collection for specific asset on account +- `triggerAllCollections(address account)` - Trigger all enabled collections for specific account +- `canExecuteCollection(address account, address asset)` - Check if collection can execute + +#### View Functions +- `getCollectionConfig(address account, address asset)` - Get specific config +- `getCollectionConfigs(address account)` - Get all configs for an account +- `getCollectionState(address account, address asset)` - Get collection state + +## Execution Flow + +### Collection Trigger Flow +``` +1. External caller → triggerCollection(account, asset) +2. Module validates: + - Configuration exists and is enabled for account + - Calendar day has changed since last collection + - Balance meets threshold (if threshold > 0) + - Balance >= minimumRemaining (can leave the required amount) + - collectAmount = balance - minimumRemaining > 0 +3. Module executes: + - Get current balance of asset in account + - Calculate collect amount: balance - minimumRemaining + - Transfer collect amount to configured target + - Leave minimumRemaining in account + - If transfer fails, emit CollectionSkipped event and continue + - Update lastCollectDate only on successful transfer +4. Emit CollectionExecuted or CollectionSkipped event +``` + +### Calendar Day Tracking +- Uses BokkyPooBah's DateTime Library (same as AutoTopUpExecutor) +- Dates encoded as YYYYMMDD (e.g., 20240829) +- All timestamps are UTC-based +- Prevents multiple collections per calendar day + +## Security Considerations + +1. **Access Control** + - Only service account (msg.sender) can configure its own collections + - Anyone can trigger collections (permissionless) + - Module can only transfer FROM the account it's installed on + +2. **Reentrancy Protection** + - CEI (Checks-Effects-Interactions) pattern + - State updates before external calls + - ReentrancyGuard on execution functions + +3. **Token Safety** + - Execute transfers via Safe's _execute() (like AutoTopUpExecutor) + - Handle non-standard token returns by checking returndata length + - Decode and validate return value if present + - Zero-value transfer protection + +## Events + +```solidity +event CollectionConfigured( + address indexed account, + address indexed asset, + address indexed target, + uint256 threshold +); + +event CollectionExecuted( + address indexed account, + address indexed asset, + address indexed target, + uint256 amount +); + +event CollectionSkipped( + address indexed account, + address indexed asset, + bytes32 indexed configId, + uint256 balance, + uint256 threshold, + uint256 minimumRemaining, + uint256 collectAmount +); + +event CollectionEnabled(address indexed account, address indexed asset); +event CollectionDisabled(address indexed account, address indexed asset); +``` + +## Edge Cases & Validation + +1. **Collection Validation** + - If balance < threshold: Skip collection, emit CollectionSkipped event + - If balance = 0: Skip collection, emit CollectionSkipped event + - If balance < minimumRemaining: Skip collection, emit CollectionSkipped event + - If balance - minimumRemaining = 0: Skip collection, emit CollectionSkipped event + - Threshold = 0 means trigger collection on any balance + - minimumRemaining = 0 means collect full balance (default behavior) + +2. **Valid Configurations** + - minimumRemaining > threshold: Valid (effective threshold is minimumRemaining) + - minimumRemaining = threshold: Valid (collect when balance exactly at or above threshold) + - minimumRemaining = 0, threshold = 0: Valid (collect any non-zero balance) + - minimumRemaining > 0, threshold = 0: Valid (collect when balance > minimumRemaining) + +3. **Invalid Configuration** + - Target cannot be zero address + - Asset must be valid ERC-20 contract + - Threshold and minimumRemaining can both be 0 + +3. **Date Boundaries** + - Month transitions handled correctly + - Year transitions handled correctly + - Leap years considered + +4. **Token Edge Cases** + - Non-standard return values (USDT) + - Tokens with transfer fees + - Balance changes between check and transfer (handled gracefully by skipping collection) + +## Gas Optimization + +1. **Storage Patterns** + - Separate config and state structs for efficient updates + - Pack struct fields for optimal storage slots + - Use mappings instead of arrays where possible + +2. **Execution Optimization** + - Calculate date once per execution + - Batch operations where possible + - Skip zero-balance collections early + +## Differences from AutoTopUpExecutor + +| Aspect | AutoTopUpExecutor | AutoCollectExecutor | +|--------|-------------------|---------------------| +| Installation | On main account | On service accounts | +| Transfer Direction | Main → Agent accounts | Service account → Main | +| Config Storage | Per (agent, asset) | Per (asset) on each account | +| Limits | Daily/Monthly amounts | Once per calendar day | +| Threshold | Top-up when below | Collect when above | +| Target | Multiple agents | Single main account | + +## Integration with Safe Accounts + +Service accounts will have AutoCollectExecutor installed as an ERC-7579 module: +```solidity +Safe Service Account +├── Owner: User's Privy Wallet +├── Modules: +│ └── AutoCollectExecutor +│ ├── Collection configs per asset +│ ├── Target: Main account (also owned by Privy wallet) +│ └── Thresholds and state +└── Holdings: USDC, other tokens (to be collected) +``` + +## Testing Strategy + +1. **Unit Tests** + - All configuration functions + - Collection execution logic + - Calendar day calculations + - Edge cases and error conditions + +2. **Integration Tests (ModuleKit)** + - Module installation/uninstallation + - Cross-account interactions + - Real Safe account testing + - Gas usage validation + +3. **Fuzz Testing** + - Date arithmetic edge cases + - Random threshold values + - Multiple asset scenarios + +## Implementation Notes + +### Upgradeability +- Use UUPS proxy pattern (same as AutoTopUpExecutor) +- OwnableUpgradeable for upgrade admin control +- ERC-7201 namespaced storage for upgrade safety + +### Dependencies +- BokkyPooBah's DateTime Library (already in lib/) +- OpenZeppelin contracts upgradeable (including EnumerableSet) +- ModuleKit for ERC-7579 compliance +- ERC7579ExecutorBase for _execute() functionality + +## Implementation Checklist + +- [ ] Core contract implementation (UUPS upgradeable) +- [ ] Interface extraction (IAutoCollectExecutor) +- [ ] Token transfer via _execute() with returndata validation +- [ ] Calendar-based date tracking with DateTime library +- [ ] Event and error definitions +- [ ] Unit tests following AutoTopUpExecutor.t.sol patterns +- [ ] Integration tests with ModuleKit +- [ ] Gas optimization and forge fmt +- [ ] Security review \ No newline at end of file diff --git a/typescript/packages/account-modules/docs/auto-top-up/architecture.md b/typescript/packages/account-modules/docs/auto-top-up/architecture.md new file mode 100644 index 0000000..6fc7821 --- /dev/null +++ b/typescript/packages/account-modules/docs/auto-top-up/architecture.md @@ -0,0 +1,272 @@ +# AutoTopUpExecutor Module Architecture + +## Overview + +The AutoTopUpExecutor is an ERC-7579 executor module that enables automatic balance management for Safe smart accounts. It allows anyone to trigger pre-configured ERC-20 token transfers from a main Safe account to designated agent accounts when their balances fall below specified thresholds. + +## Core Design Principles + +### 1. Non-Custodial Architecture +- Module operates as part of the Safe's execution context +- Never holds funds directly +- User maintains full control over configuration and can disable at any time +- Executions happen through Safe's module system + +### 2. Permissionless Triggering +- Anyone can call the trigger function to execute configured top-ups +- Security enforced through on-chain configuration and limits +- Primary automation through our keeper infrastructure (with option for users to self-host) + +### 3. Multi-Agent Support +- Single module instance manages multiple agent configurations +- Each agent has independent thresholds, amounts, and limits +- Efficient batch operations for checking and executing multiple top-ups + +## Technical Architecture + +### Module Type +- **Type**: Executor Module (0x01) +- **Standard**: ERC-7579 compliant +- **Base**: Rhinestone ModuleKit's `ERC7579ExecutorBase` +- **Upgradeable**: Yes, using UUPS pattern with OpenZeppelin + +### Storage Pattern +- **ERC-7201**: Namespaced storage for upgrade safety +- **Storage Layout**: + ```solidity + // User-configurable parameters + struct TopUpConfig { + uint256 dailyLimit; // Target balance to maintain (max top-up per day) + uint256 monthlyLimit; // Maximum total top-ups per month + bool enabled; // Configuration active status + } + + // Immutable identity and internal state (not user-editable) + struct TopUpState { + address agent; // Target agent account (immutable, part of config ID) + address asset; // ERC-20 token address (immutable, part of config ID) + uint256 lastTopUpTime; // Last top-up timestamp (enforces once-per-day) + uint256 monthlySpent; // Amount topped up this month + uint256 lastResetMonth; // Last monthly reset timestamp + } + + struct AutoTopUpStorage { + // Config ID => user configuration + mapping(bytes32 => TopUpConfig) configs; + + // Config ID => internal state + mapping(bytes32 => TopUpState) states; + + // Account => set of config IDs + mapping(address => EnumerableSet.Bytes32Set) accountConfigs; + } + ``` + +- **Config ID Generation**: `keccak256(abi.encode("TopUpConfig", account, agent, asset))` returns bytes32 for unique configs +- **Namespaced IDs**: "TopUpConfig" prefix prevents collision with other system hashes +- **Per-Account Execution**: Each account's configs are triggered separately to avoid gas limits +- **Gas Optimization**: EnumerableSet allows O(1) add/remove and efficient iteration within an account + +### Key Functions + +#### Module Interface (ERC-7579 via ModuleKit) +```solidity +// Inherited from ERC7579ExecutorBase +function onInstall(bytes calldata data) external +function onUninstall(bytes calldata data) external +function isModuleType(uint256 typeID) external view returns (bool) +function isInitialized(address smartAccount) external view returns (bool) + +// Internal execution helpers from base (used within our functions) +// _execute(address account, address to, uint256 value, bytes memory data) - single tx +// _execute(address account, Execution[] memory execs) - batch tx +// (Plus msg.sender variants and delegatecall versions we won't use) +``` + +#### Configuration Management +```solidity +function configureTopUp( + address agent, + address asset, + TopUpConfig calldata config +) external returns (bytes32 configId) + +function configureTopUpById( + bytes32 configId, + TopUpConfig calldata config +) external + +function disableTopUp(bytes32 configId) external +function enableTopUp(bytes32 configId) external +``` + +#### Execution +```solidity +function triggerTopUps(address account) external returns (bytes32[] memory executed) +function triggerTopUp(bytes32 configId) external returns (bool executed) +``` + +#### View Functions +```solidity +function generateConfigId(address account, address agent, address asset) external pure returns (bytes32) +function getTopUpConfigs(address account) external view returns (TopUpConfig[] memory, TopUpState[] memory) +function canExecuteTopUp(bytes32 configId) external view returns (bool, string memory reason) +function getTopUpById(bytes32 configId) external view returns (TopUpConfig memory config, TopUpState memory state) +function getTopUp(address account, address agent, address asset) external view returns (TopUpConfig memory config, TopUpState memory state) +``` + +## Execution Flow + +### 1. Installation +1. Safe owner calls module management to install AutoTopUpExecutor +2. Module's `onInstall` is called with initial configurations (optional) +3. Module registers the Safe account as initialized + +### 2. Configuration +1. Safe owner sends transaction to module to configure top-ups +2. Config ID generated: `keccak256(abi.encode("TopUpConfig", account, agent, asset))` +3. `configureTopUp()` creates new or updates existing config for agent/asset pair +4. `configureTopUpById()` updates existing config by its ID +5. Agent and asset are immutable once set (part of the config ID) +6. Only dailyLimit, monthlyLimit, and enabled status can be updated +7. Multiple configurations can exist for different agents and different tokens +8. Frontend/keeper can precompute config IDs using `generateConfigId()` + +### 3. Triggering +1. Keeper calls `triggerTopUps(account)` for each account (separate transactions) +2. Module iterates through all enabled configurations for that specific account +3. For each configuration: + - Check if already topped up today (via `lastTopUpTime`) + - Calculate top-up amount: `min(dailyLimit - agentBalance, monthlyLimit - monthlySpent)` + - Skip if amount ≤ 0 (agent already funded or monthly limit reached) + - Execute transfer via internal `_execute()` helper (triggers Safe's module execution) + - Update `lastTopUpTime` and `monthlySpent` + +### 4. Limit Management +- **Daily**: Enforced by once-per-day check using `lastTopUpTime` +- **Monthly**: Reset on the 1st of each month (tracked via `lastResetMonth`) +- **Top-up calculation**: Always maintains balance up to `dailyLimit`, respecting `monthlyLimit` +- **No partial days**: If a top-up happens, it's for the full daily amount (up to monthly remaining) + +## Security Considerations + +### Access Control +- Only Safe account can configure its own top-ups +- Configuration updates require Safe transaction +- No admin keys or external control + +### Limit Enforcement +- Once-per-day enforcement prevents abuse +- Monthly budget caps provide spending control +- Simple calculation: top up to daily limit, not exceeding monthly budget + +### Reentrancy Protection +- OpenZeppelin's ReentrancyGuard on all state-changing functions +- Checks-effects-interactions pattern +- State updates before external calls + +### Validation +- Balance checks before transfers +- Sufficient Safe balance validation +- Asset address validation (ensure valid ERC-20 contract) +- Agent address validation (prevent self-transfers) + +## Gas Optimization + +### Batch Operations +- Per-account batch execution (all configs for one account in one tx) +- Bounded gas usage per transaction +- Keeper maintains off-chain list of accounts to service + +### Storage Efficiency +- EnumerableSet for per-account config tracking +- O(1) config lookups via mapping +- Config IDs prevent duplicate account/agent/asset combinations +- No global account list needed (keeper tracks off-chain) + +## Integration Points + +### ERC-7579 Module System +- Registered as executor module (type 0x01) +- Uses ModuleKit's `_execute()` helpers for execution +- Works across all ERC-7579 compliant accounts (Safe, Kernel, Biconomy) + +### Token Contracts +- ERC20 interface for balance checks +- OpenZeppelin's SafeERC20 for safe token transfers +- Transfers executed via Safe module system (using _execute) +- No direct token approvals needed + +### Monitoring & Events +```solidity +event TopUpConfigured(address indexed account, address indexed agent, address asset, bytes32 indexed configId, TopUpConfig config) +event TopUpExecuted(address indexed account, address indexed agent, address asset, bytes32 indexed configId, uint256 amount) +event TopUpFailed(address indexed account, address indexed agent, address asset, bytes32 indexed configId, string reason) +event TopUpEnabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId) +event TopUpDisabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId) +``` + +- **TopUpConfigured**: Emitted on both initial configuration and updates +- **TopUpEnabled/Disabled**: Emitted whenever enabled status changes (via any function) + +## Future Enhancements + +### Post-MVP Improvements +1. **Native Token Support**: ETH/MATIC/etc. alongside ERC-20s +2. **Off-chain Signatures**: Gasless configuration updates via EIP-712 signed messages + +## Testing Strategy + +### Unit Tests +- Configuration CRUD operations +- Daily limit enforcement (once per day) +- Monthly limit tracking and resets +- Balance calculation logic (top up to daily limit) + +### Integration Tests +- Safe module installation/uninstallation using ModuleKit test utilities +- Token transfer execution through Safe +- Multi-account scenarios using ModuleKit's `makeAccountInstance` +- Cross-implementation tests (Safe, Kernel, Biconomy) - lower priority + +### Security Tests +- Reentrancy attempts +- Limit bypass attempts (trying to trigger multiple times per day) +- Unauthorized configuration changes +- Edge cases around month transitions + +## Implementation Stack + +### Dependencies +- **ModuleKit** (v0.5.9+): Rhinestone's development kit for ERC-7579 modules + - Provides `ERC7579ExecutorBase` for executor functionality + - Built-in test utilities for multi-account testing (Safe, Kernel, Biconomy) + - Helper functions for module deployment + - Integration with Module Registry + - Main import: `import "modulekit/Modules.sol"` + - **Important**: Requires `npm install` in lib/modulekit directory for ERC4337 dependencies +- **OpenZeppelin Contracts Upgradeable**: For UUPS proxy pattern and utilities +- **OpenZeppelin Contracts**: For ERC20 interface and security utilities + +### Inheritance Chain +``` +AutoTopUpExecutor + ├── ERC7579ExecutorBase (from ModuleKit) + │ └── IERC7579Module + ├── UUPSUpgradeable (from OpenZeppelin) + ├── OwnableUpgradeable (from OpenZeppelin) + └── ReentrancyGuardUpgradeable (from OpenZeppelin) +``` + +## Deployment Considerations + +### Deployment Steps +1. Deploy implementation contract +2. Deploy proxy with initializer +3. Register in Rhinestone module registry +4. Integrate with Safe deployment flow +5. Utilize ModuleKit's deployment helpers + +### Monitoring +- Subgraph for indexing all contract events +- Track and alert on failed top-ups (especially during initial rollout) \ No newline at end of file diff --git a/typescript/packages/account-modules/foundry.lock b/typescript/packages/account-modules/foundry.lock new file mode 100644 index 0000000..1d1d4a5 --- /dev/null +++ b/typescript/packages/account-modules/foundry.lock @@ -0,0 +1,68 @@ +{ + "../../external/x402-private": { + "rev": "0fd862e2dc734ca0303210c919e246990b5c1cc7" + }, + "../escrow/lib/forge-std": { + "rev": "addeae62cd620c53f2fdc91bfc82396f5df79d1d" + }, + "../escrow/lib/openzeppelin-contracts": { + "rev": "4a67c6f3ab2be41487889a020c99e11dedbd6eb4" + }, + "../escrow/lib/openzeppelin-contracts-upgradeable": { + "rev": "62164b46517484f5b734d2c0e7e647de058685bf" + }, + "external/x402-private": { + "branch": { + "name": "main", + "rev": "3211e365dc998d8853d1a5cf16d6673feef57340" + } + }, + "lib/BokkyPooBahsDateTimeLibrary": { + "rev": "1dc26f977c57a6ba3ed6d7c53cafdb191e7e59ae" + }, + "lib/forge-std": { + "tag": { + "name": "v1.10.0", + "rev": "8bbcf6e3f8f62f419e5429a0bd89331c85c37824" + } + }, + "lib/modulekit": { + "tag": { + "name": "v0.5.9", + "rev": "b696ccbe1b16a55d8b1a1de192309500af0fae5e" + } + }, + "lib/openzeppelin-contracts": { + "tag": { + "name": "v5.4.0", + "rev": "c64a1edb67b6e3f4a15cca8909c9482ad33a02b0" + } + }, + "lib/openzeppelin-contracts-upgradeable": { + "tag": { + "name": "v5.4.0", + "rev": "e725abddf1e01cf05ace496e950fc8e243cc7cab" + } + }, + "packages/account-modules/lib/BokkyPooBahsDateTimeLibrary": { + "rev": "1dc26f977c57a6ba3ed6d7c53cafdb191e7e59ae" + }, + "packages/account-modules/lib/forge-std": { + "rev": "8bbcf6e3f8f62f419e5429a0bd89331c85c37824" + }, + "packages/account-modules/lib/modulekit": { + "rev": "676bb65032c17b13ecd15ee89f435f0afeffca9b" + }, + "packages/account-modules/lib/openzeppelin-contracts": { + "rev": "c64a1edb67b6e3f4a15cca8909c9482ad33a02b0" + }, + "packages/escrow/lib/forge-std": { + "rev": "addeae62cd620c53f2fdc91bfc82396f5df79d1d" + }, + "packages/escrow/lib/openzeppelin-contracts": { + "rev": "4a67c6f3ab2be41487889a020c99e11dedbd6eb4" + }, + "packages/escrow/lib/openzeppelin-contracts-upgradeable": { + "rev": "62164b46517484f5b734d2c0e7e647de058685bf" + } +} \ No newline at end of file diff --git a/typescript/packages/account-modules/foundry.toml b/typescript/packages/account-modules/foundry.toml new file mode 100644 index 0000000..41e39e9 --- /dev/null +++ b/typescript/packages/account-modules/foundry.toml @@ -0,0 +1,28 @@ +[profile.default] +src = "src" +out = "out" +libs = ["lib"] +remappings = [ + "modulekit/=lib/modulekit/", + "@openzeppelin/=lib/openzeppelin-contracts/", + "forge-std/=lib/forge-std/src/", + "BokkyPooBahsDateTimeLibrary/=lib/BokkyPooBahsDateTimeLibrary/", + "safe-singleton-deployer/=lib/safe-singleton-deployer-sol/src/", + # ModuleKit dependencies + "erc4337-validation/=lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/", + "@ERC4337/=lib/modulekit/node_modules/@ERC4337/", + "account-abstraction/=lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/", + "account-abstraction-v0.6/=lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/", + "@rhinestone/=lib/modulekit/node_modules/@rhinestone/", + "ds-test/=lib/modulekit/node_modules/ds-test/src/", + "solady/=lib/modulekit/node_modules/solady/src/", + "solarray/=lib/modulekit/node_modules/solarray/src/", + "@prb/math/=lib/modulekit/node_modules/@prb/math/src/", + "ExcessivelySafeCall/=lib/modulekit/node_modules/excessively-safe-call/src/" +] +solc = "0.8.30" +optimizer = true +optimizer_runs = 200 + +[lint] +exclude_lints = ["asm-keccak256"] diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitattributes b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitattributes new file mode 100644 index 0000000..52031de --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitattributes @@ -0,0 +1 @@ +*.sol linguist-language=Solidity diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitignore b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitignore new file mode 100644 index 0000000..a26200d --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +.project +.settings +test/testchain/geth +test/testchain/geth.ipc +test/testchain/history +test/contracts +private diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/LICENSE b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/LICENSE new file mode 100644 index 0000000..0040033 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 The Officious BokkyPooBah / Bok Consulting Pty Ltd + +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/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/README.md b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/README.md new file mode 100644 index 0000000..a078dc6 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/README.md @@ -0,0 +1,915 @@ + + +
+ +
+ +# BokkyPooBah's DateTime Library + +A gas-efficient Solidity date and time library. + +Instead of using loops and lookup tables, this date conversions library uses formulae to convert year/month/day hour:minute:second to a Unix timestamp and back. + +See [BokkyPooBah’s Gas-Efficient Solidity DateTime Library](https://medium.com/@BokkyPooBah/bokkypoobahs-gas-efficient-solidity-datetime-library-92bf96d9b2da) for more explanations. + +Thank you to [Alex Kampa](https://github.com/alex-kampa), [James Zaki](https://github.com/jzaki) and [Adrian Guerrera](https://github.com/apguerrera) for helping to validate this library. Thanks also to [Oleksii Matiiasevych](https://github.com/lastperson) for asking about leap seconds. + +
+ +
+ +## Table Of Contents + +* [History](#history) +* [Bug Bounty Scope And Donations](#bug-bounty-scope-and-donations) +* [Deployment](#deployment) +* [Questions And Answers](#questions-and-answers) +* [Conventions](#conventions) +* [Functions](#functions) + * [_daysFromDate](#_daysfromdate) + * [_daysToDate](#_daystodate) + * [timestampFromDate](#timestampfromdate) + * [timestampFromDateTime](#timestampfromdatetime) + * [timestampToDate](#timestamptodate) + * [timestampToDateTime](#timestamptodatetime) + * [isValidDate](#isvaliddate) + * [isValidDateTime](#isvaliddatetime) + * [isLeapYear](#isleapyear) + * [_isLeapYear](#_isleapyear) + * [isWeekDay](#isweekday) + * [isWeekEnd](#isweekend) + * [getDaysInMonth](#getdaysinmonth) + * [_getDaysInMonth](#_getdaysinmonth) + * [getDayOfWeek](#getdayofweek) + * [getYear](#getyear) + * [getMonth](#getmonth) + * [getDay](#getday) + * [getHour](#gethour) + * [getMinute](#getminute) + * [getSecond](#getsecond) + * [addYears](#addyears) + * [addMonths](#addmonths) + * [addDays](#adddays) + * [addHours](#addhours) + * [addMinutes](#addminutes) + * [addSeconds](#addseconds) + * [subYears](#subyears) + * [subMonths](#submonths) + * [subDays](#subdays) + * [subHours](#subhours) + * [subMinutes](#subminutes) + * [subSeconds](#subseconds) + * [diffYears](#diffyears) + * [diffMonths](#diffmonths) + * [diffDays](#diffdays) + * [diffHours](#diffhours) + * [diffMinutes](#diffminutes) + * [diffSeconds](#diffseconds) +* [Gas Cost](#gas-cost) +* [Algorithm](#algorithm) +* [Testing](#testing) +* [References](#references) + +
+ +
+ +## History + +Version | Date | Notes +:------------------ |:------------ |:--------------------------------------- +v1.00-pre-release | May 25 2018 | "Rarefaction" pre-release. I'm currently trying to get this library audited, so don't use in production mode yet. +v1.00-pre-release-a | Jun 2 2018 | "Rarefaction" pre-release a. Added the [contracts/BokkyPooBahsDateTimeContract.sol](contracts/BokkyPooBahsDateTimeContract.sol) wrapper for convenience.
[Alex Kampa](https://github.com/alex-kampa) conducted a range of [tests](https://github.com/alex-kampa/test_BokkyPooBahsDateTimeLibrary) on the library. +v1.00-pre-release-b | Jun 4 2018 | "Rarefaction" pre-release b. Replaced public function with internal for easier EtherScan verification - [a83e13b](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary/commit/a83e13bef31e8ef399007dd237e42bd5cdf479e6).
Deployed [contracts/BokkyPooBahsDateTimeContract.sol](contracts/BokkyPooBahsDateTimeContract.sol) with the inlined [contracts/BokkyPooBahsDateTimeLibrary.sol](contracts/BokkyPooBahsDateTimeLibrary.sol) to the [Ropsten network](deployment/deployment-v1.00-prerelease.md) at address [0x07239bb079094481bfaac91ca842426860021aaa](https://ropsten.etherscan.io/address/0x07239bb079094481bfaac91ca842426860021aaa#code) +v1.00-pre-release-c | June 8 2018 | "Rarefaction" pre-release c. Added `require(year >= 1970)` to `_daysFromDate(...)` in [4002b27](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary/commit/4002b278d1779fcd4f3f4527a60a5887ee6c20ba) as highlighted in [James Zaki](https://github.com/jzaki)'s audit +v1.00-pre-release-d | Sep 1 2018 | "Rarefaction" pre-release d. Added [isValidDate(...)](#isvaliddate) and [isValidDateTime(...)](#isvaliddatetime) in [380061b](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary/commit/380061b9d20c83450ee303f709fe58e973c5f4a9) as highlighted in [Adrian Guerrera](https://github.com/apguerrera)'s audit +v1.00 | Sep 2 2018 | "Rarefaction" release +v1.01 | Feb 14 2019 | "Notoryctes" release. Upgraded contracts to Solidity 0.5.x.
Updated to MIT Licence +v1.01 | Feb 17 2019 | Bug bounty added + +
+ +
+ +## Bug Bounty Scope And Donations + +Details of the bug bounty program for this project can be found at [BokkyPooBah's Hall Of Fame And Bug Bounties](https://github.com/bokkypoobah/BokkyPooBahsHallOfFameAndBugBounties). Please consider [donating](https://github.com/bokkypoobah/BokkyPooBahsHallOfFameAndBugBounties#donations) to support the bug bounty, and the development and maintenance of decentralised applications. + +The scope of the bug bounty for this project follows: + +* [contracts/BokkyPooBahsDateTimeLibrary.sol](contracts/BokkyPooBahsDateTimeLibrary.sol) + +
+ +
+ +## Deployment + +[v1.00 of the source code](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary/tree/1ea8ef42b3d8db17b910b46e4f8c124b59d77c03/contracts) for [BokkyPooBahsDateTimeContract.sol](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary/blob/1ea8ef42b3d8db17b910b46e4f8c124b59d77c03/contracts/BokkyPooBahsDateTimeContract.sol) and [TestDateTime.sol](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary/blob/1ea8ef42b3d8db17b910b46e4f8c124b59d77c03/contracts/TestDateTime.sol) has been deployed to: + +* The Ropsten network: + * BokkyPooBahsDateTimeContract.sol at [0x947cc35992e6723de50bf704828a01fd2d5d6641](https://ropsten.etherscan.io/address/0x947cc35992e6723de50bf704828a01fd2d5d6641#code) + * TestDateTime.sol at [0xa068fe3e029a972ecdda2686318806d2b19875d1](https://ropsten.etherscan.io/address/0xa068fe3e029a972ecdda2686318806d2b19875d1#code) + +* Mainnet: + * BokkyPooBahsDateTimeContract.sol at [0x23d23d8f243e57d0b924bff3a3191078af325101](https://etherscan.io/address/0x23d23d8f243e57d0b924bff3a3191078af325101#code) + * TestDateTime.sol at [0x78f96b2d5f717fa9ad416957b79d825cc4cce69d](https://etherscan.io/address/0x78f96b2d5f717fa9ad416957b79d825cc4cce69d#code) + +For each of the deployed contracts above, you can click on the *Read Contract* tab to test out the date/time/timestamp functions. + +
+ +
+ +## Questions And Answers + +### Questions by `_dredge` + +User [/u/_dredge](https://www.reddit.com/user/_dredge) asked the [following questions](https://www.reddit.com/r/ethereum/comments/8m3p4j/bokkypoobahs_datetime_library_a_solidity/dzkss7n/): + +> Some Muslim countries have a Friday/Saturday weekend. Workday(1-7) may be more useful. +> +> I presume leap seconds and such details are taken care of in the Unix timecode. +> +> Some additional ideas for functions below. +> +> Quarter calculations +> +> weekNumber(1-53) +> +> Complete years / months / weeks / days +> +> Nearest years / months / weeks / days + +Regarding regions and systems where Friday/Saturday are weekends, please use the function `getDayOfWeek(timestamp)` that returns 1 (= Monday, ..., 7 (= Sunday) to determine whether you should treat a day as a weekday or weekend. + +See the next question regarding the leap seconds. + +Regarding the additional ideas, thanks! + +
+ +### What about the leap second? + +Asked by [Oleksii Matiiasevych](https://github.com/lastperson) and */u/_dredge* above. + +For example, a [leap second](https://en.wikipedia.org/wiki/Unix_time#Leap_seconds) was inserted on Jan 01 1999. + +From the first answer to [Unix time and leap seconds](https://stackoverflow.com/a/16539483): + +> The number of seconds per day are fixed with Unix timestamps. +> +> > The Unix time number is zero at the Unix epoch, and increases by exactly 86400 per day since the epoch. +> +> So it cannot represent leap seconds. The OS will slow down the clock to accommodate for this. The leap seconds is simply not existent as far a Unix timestamps are concerned. + +And from the second answer to [Unix time and leap seconds](https://stackoverflow.com/a/16539734): + +> Unix time is easy to work with, but some timestamps are not real times, and some timestamps are not unique times. +> +> That is, there are some duplicate timestamps representing two different seconds in time, because in unix time the sixtieth second might have to repeat itself (as there can't be a sixty-first second). Theoretically, they could also be gaps in the future because the sixtieth second doesn't have to exist, although no skipping leap seconds have been issued so far. +> +> Rationale for unix time: it's defined so that it's easy to work with. Adding support for leap seconds to the standard libraries is very tricky. +> ... + +This library aims to replicate the [Unix time](https://en.wikipedia.org/wiki/Unix_time) functionality and assumes that leap seconds are handled by the underlying operating system. + +
+ +### What is the maximum year 2345? + +Asked by [Adrian Guerrera](https://github.com/apguerrera). + +**2345** is just an arbitrary number chosen for the year limit to test to. The algorithms should still work beyond this date. + +
+ +### Why are there no input validations to some of the functions? + +Asked by [Adrian Guerrera](https://github.com/apguerrera). Specifically, the functions [_daysFromDate](#_daysfromdate), [timestampFromDate](#timestampfromdate) and [timestampFromDateTime](#timestampfromdatetime). + +The date and time inputs should be validated before the values are passed to these functions. The validation functions [isValidDate(...)](#isvaliddate) and [isValidDateTime(...)](#isvaliddatetime) have now been added for this purpose. + +
+ +### Why are all variables 256-bit integers? + +This library provides a cheap conversion between the timestamp and year/month/day hour:minute:second formats. There is no requirement for this library to store a packed structure to represent a DateTime as this data can be stored as a `uint256` and converted on the fly to year/month/day hour:minute:second. + +
+ +### Why do you call this a gas-efficient library? + +The formulae for converting between a timestamp and year/month/day hour:minute:second format uses a mathematically simple algorithm without any loops. The gas cost is relatively constant (as there are no loops) and the mathematical computations are relative cheap (compared to using loops and looking up data from storage). + +
+ +### Can this library be written more efficiently? + +Most likely. The aim of this first version is for the conversions to be computed correctly. + +
+ +### How gas-efficient is this library? + +From [Gas Cost](#gas-cost), `timestampToDateTime(…)` has an execution gas cost of 3,101 gas, and `timestampFromDateTime(…)` has an execution gas cost of 2,566 gas. + +
+ +
+ +## Conventions + +All dates, times and Unix timestamps are [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time). + +Unit | Range | Notes +:------------- |:-------------------------:|:--------------------------------------------------------------- +timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC +year | 1970 ... 2345 | +month | 1 ... 12 | +day | 1 ... 31 | +hour | 0 ... 23 | +minute | 0 ... 59 | +second | 0 ... 59 | +dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday +year/month/day | 1970/01/01 ... 2345/12/31 | + +`_days`, `_months` and `_years` variable names are `_`-prefixed as the non-prefixed versions are reserved words in Solidity. + +All functions operate on the `uint` timestamp data type, except for functions prefixed with `_`. + +
+ +
+ +## Functions + +### _daysFromDate + +Calculate the number of days `_days` from 1970/01/01 to `year`/`month`/`day`. + +```javascript +function _daysFromDate(uint year, uint month, uint day) public pure returns (uint _days) +``` + +**NOTE** This function does not validate the `year`/`month`/`day` input. Use [`isValidDate(...)`](#isvaliddate) to validate the input if necessary. + +
+ +### _daysToDate + +Calculate `year`/`month`/`day` from the number of days `_days` since 1970/01/01 . + +```javascript +function _daysToDate(uint _days) public pure returns (uint year, uint month, uint day) +``` + +
+ +### timestampFromDate + +Calculate the `timestamp` to `year`/`month`/`day`. + +```javascript +function timestampFromDate(uint year, uint month, uint day) public pure returns (uint timestamp) +``` + +**NOTE** This function does not validate the `year`/`month`/`day` input. Use [`isValidDate(...)`](#isvaliddate) to validate the input if necessary. + +
+ +### timestampFromDateTime + +Calculate the `timestamp` to `year`/`month`/`day` `hour`:`minute`:`second` UTC. + +```javascript +function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (uint timestamp) +``` + +**NOTE** This function does not validate the `year`/`month`/`day` `hour`:`minute`:`second` input. Use [`isValidDateTime(...)`](#isvaliddatetime) to validate the input if necessary. + +
+ +### timestampToDate + +Calculate `year`/`month`/`day` from `timestamp`. + +```javascript +function timestampToDate(uint timestamp) public pure returns (uint year, uint month, uint day) +``` + +
+ +### timestampToDateTime + +Calculate `year`/`month`/`day` `hour`:`minute`:`second` from `timestamp`. + +```javascript +function timestampToDateTime(uint timestamp) public pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) +``` + +
+ +### isValidDate + +Is the date specified by `year`/`month`/`day` a valid date? + +```javascript_ +function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) +``` + +
+ +
+ +### isValidDateTime + +Is the date/time specified by `year`/`month`/`day` `hour`:`minute`:`second` a valid date/time? + +```javascript_ +function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) +``` + +
+ +### isLeapYear + +Is the year specified by `timestamp` a leap year? + +```javascript_ +function isLeapYear(uint timestamp) public pure returns (bool leapYear) +``` + +
+ +### _isLeapYear + +Is the specified `year` (e.g. 2018) a leap year? + +```javascript_ +function _isLeapYear(uint year) public pure returns (bool leapYear) +``` + +
+ +### isWeekDay + +Is the day specified by `timestamp` a weekday (Monday, ..., Friday)? + +```javascript +function isWeekDay(uint timestamp) public pure returns (bool weekDay) +``` + +
+ +### isWeekEnd + +Is the day specified by `timestamp` a weekend (Saturday, Sunday)? + +```javascript +function isWeekEnd(uint timestamp) public pure returns (bool weekEnd) +``` + +
+ +### getDaysInMonth + +Return the day in the month `daysInMonth` for the month specified by `timestamp`. + +```javascript +function getDaysInMonth(uint timestamp) public pure returns (uint daysInMonth) +``` + +
+ +### _getDaysInMonth + +Return the day in the month `daysInMonth` (1, ..., 31) for the month specified by the `year`/`month`. + +```javascript +function _getDaysInMonth(uint year, uint month) public pure returns (uint daysInMonth) +``` + +
+ +### getDayOfWeek + +Return the day of the week `dayOfWeek` (1 = Monday, ..., 7 = Sunday) for the date specified by `timestamp`. + +```javascript +function getDayOfWeek(uint timestamp) public pure returns (uint dayOfWeek) +``` + +
+ +### getYear + +Get the `year` of the date specified by `timestamp`. + +```javascript +function getYear(uint timestamp) public pure returns (uint year) +``` + +
+ +### getMonth + +Get the `month` of the date specified by `timestamp`. + +```javascript +function getMonth(uint timestamp) public pure returns (uint month) +``` + +
+ +### getDay + +Get the day of the month `day` (1, ..., 31) of the date specified `timestamp`. + +```javascript +function getDay(uint timestamp) public pure returns (uint day) +``` + +
+ +### getHour + +Get the `hour` of the date and time specified by `timestamp`. + +```javascript +function getHour(uint timestamp) public pure returns (uint hour) +``` + +
+ +### getMinute + +Get the `minute` of the date and time specified by `timestamp`. + +```javascript +function getMinute(uint timestamp) public pure returns (uint minute) +``` + +
+ +### getSecond + +Get the `second` of the date and time specified by `timestamp`. + +```javascript +function getSecond(uint timestamp) public pure returns (uint second) +``` + +
+ +### addYears + +Add `_years` years to the date and time specified by `timestamp`. + +Note that the resulting day of the month will be adjusted if it exceeds the valid number of days in the month. For example, if the original date is 2020/02/29 and an additional year is added to this date, the resulting date will be an invalid date of 2021/02/29. The resulting date is then adjusted to 2021/02/28. + +```javascript +function addYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) +``` + +
+ +### addMonths + +Add `_months` months to the date and time specified by `timestamp`. + +Note that the resulting day of the month will be adjusted if it exceeds the valid number of days in the month. For example, if the original date is 2019/01/31 and an additional month is added to this date, the resulting date will be an invalid date of 2019/02/31. The resulting date is then adjusted to 2019/02/28. + +```javascript +function addMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) +``` + +
+ +### addDays + +Add `_days` days to the date and time specified by `timestamp`. + +```javascript +function addDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) +``` + +
+ +### addHours + +Add `_hours` hours to the date and time specified by `timestamp`. + +```javascript +function addHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) +``` + +
+ +### addMinutes + +Add `_minutes` minutes to the date and time specified by `timestamp`. + +```javascript +function addMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) +``` + +
+ +### addSeconds + +Add `_seconds` seconds to the date and time specified by `timestamp`. + +```javascript +function addSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) +``` + +
+ +### subYears + +Subtract `_years` years from the date and time specified by `timestamp`. + +Note that the resulting day of the month will be adjusted if it exceeds the valid number of days in the month. For example, if the original date is 2020/02/29 and a year is subtracted from this date, the resulting date will be an invalid date of 2019/02/29. The resulting date is then adjusted to 2019/02/28. + +```javascript +function subYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) +``` + +
+ +### subMonths + +Subtract `_months` months from the date and time specified by `timestamp`. + +Note that the resulting day of the month will be adjusted if it exceeds the valid number of days in the month. For example, if the original date is 2019/03/31 and a month is subtracted from this date, the resulting date will be an invalid date of 2019/02/31. The resulting date is then adjusted to 2019/02/28. + +```javascript +function subMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) +``` + +
+ +### subDays + +Subtract `_days` days from the date and time specified by `timestamp`. + +```javascript +function subDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) +``` + +
+ +### subHours + +Subtract `_hours` hours from the date and time specified by `timestamp`. + +```javascript +function subHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) +``` + +
+ +### subMinutes + +Subtract `_minutes` minutes from the date and time specified by `timestamp`. + +```javascript +function subMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) +``` + +
+ +### subSeconds + +Subtract `_seconds` seconds from the date and time specified by `timestamp`. + +```javascript +function subSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) +``` + +
+ +### diffYears + +Calculate the number of years between the dates specified by `fromTimeStamp` and `toTimestamp`. + +Note that this calculation is computed as `getYear(toTimestamp) - getYear(fromTimestamp)`, rather that subtracting the years (since 1970/01/01) represented by both `{to|from}Timestamp`. + +```javascript +function diffYears(uint fromTimestamp, uint toTimestamp) public pure returns (uint _years) +``` + +
+ +### diffMonths + +Calculate the number of months between the dates specified by `fromTimeStamp` and `toTimestamp`. + +Note that this calculation is computed as `getYear(toTimestamp) * 12 + getMonth(toTimestamp) - getYear(fromTimestamp) * 12 - getMonth(fromTimestamp)`, rather that subtracting the months (since 1970/01/01) represented by both `{to|from}Timestamp`. + +```javascript +function diffMonths(uint fromTimestamp, uint toTimestamp) public pure returns (uint _months) +``` + +
+ +### diffDays + +Calculate the number of days between the dates specified by `fromTimeStamp` and `toTimestamp`. + +Note that this calculation is computed as `(toTimestamp - fromTimestamp) / SECONDS_PER_DAY`, rather that subtracting the days (since 1970/01/01) represented by both `{to|from}Timestamp`. + +```javascript +function diffDays(uint fromTimestamp, uint toTimestamp) public pure returns (uint _days) +``` + +
+ +### diffHours + +Calculate the number of hours between the dates specified by `fromTimeStamp` and `toTimestamp`. + +Note that this calculation is computed as `(toTimestamp - fromTimestamp) / SECONDS_PER_HOUR`, rather that subtracting the hours (since 1970/01/01) represented by both `{to|from}Timestamp`. + +```javascript +function diffHours(uint fromTimestamp, uint toTimestamp) public pure returns (uint _hours) +``` + +
+ +### diffMinutes + +Calculate the number of minutes between the dates specified by `fromTimeStamp` and `toTimestamp`. + +Note that this calculation is computed as `(toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE`, rather that subtracting the minutes (since 1970/01/01) represented by both `{to|from}Timestamp`. + +```javascript +function diffMinutes(uint fromTimestamp, uint toTimestamp) public pure returns (uint _minutes) +``` + +
+ +### diffSeconds + +Calculate the number of seconds between the dates specified by `fromTimeStamp` and `toTimestamp`. + +Note that this calculation is computed as `toTimestamp - fromTimestamp`. + +```javascript +function diffSeconds(uint fromTimestamp, uint toTimestamp) public pure returns (uint _seconds) +``` + +
+ +
+ +## Gas Cost + +### `timestampToDateTime(...)` Gas Cost + +From executing the following function, the transaction gas cost is 24,693 + +```javascript +> testDateTime.timestampToDateTime(1527120000) +[2018, 5, 24, 0, 0, 0] +> testDateTime.timestampToDateTime.estimateGas(1527120000) +24693 +``` + +From Remix, the execution gas cost is 3,101 . + +From my latest testing with Remix using Solidity 0.4.24: + + + +
+ +### `timestampFromDateTime(...)` Gas Cost + +From executing the following function, the transaction gas cost is 25,054 + +```javascript +> testDateTime.timestampFromDateTime(2018, 05, 24, 1, 2, 3) +1527123723 +> testDateTime.timestampFromDateTime.estimateGas(2018, 05, 24, 1, 2, 3) +25054 +``` + +From Remix, the execution gas cost is 2,566 . + +From my latest testing with Remix using Solidity 0.4.24: + + + +
+ +### Remix Gas Estimates + +Remix gas estimates using Solidity 0.4.24: + +```json +{ + "Creation": { + "codeDepositCost": "908400", + "executionCost": "942", + "totalCost": "909342" + }, + "External": { + "DOW_FRI()": "1130", + "DOW_MON()": "1262", + "DOW_SAT()": "1064", + "DOW_SUN()": "360", + "DOW_THU()": "1108", + "DOW_TUE()": "250", + "DOW_WED()": "778", + "OFFSET19700101()": "932", + "SECONDS_PER_DAY()": "690", + "SECONDS_PER_HOUR()": "580", + "SECONDS_PER_MINUTE()": "1196", + "_daysFromDate(uint256,uint256,uint256)": "638", + "_daysToDate(uint256)": "1280", + "_getDaysInMonth(uint256,uint256)": "885", + "_isLeapYear(uint256)": "1115", + "_now()": "997", + "_nowDateTime()": "1562", + "addDays(uint256,uint256)": "772", + "addHours(uint256,uint256)": "662", + "addMinutes(uint256,uint256)": "838", + "addMonths(uint256,uint256)": "1851", + "addSeconds(uint256,uint256)": "896", + "addYears(uint256,uint256)": "1846", + "diffDays(uint256,uint256)": "1207", + "diffHours(uint256,uint256)": "503", + "diffMinutes(uint256,uint256)": "316", + "diffMonths(uint256,uint256)": "infinite", + "diffSeconds(uint256,uint256)": "712", + "diffYears(uint256,uint256)": "infinite", + "getDay(uint256)": "1114", + "getDayOfWeek(uint256)": "415", + "getDaysInMonth(uint256)": "1120", + "getHour(uint256)": "491", + "getMinute(uint256)": "1373", + "getMonth(uint256)": "1378", + "getSecond(uint256)": "810", + "getYear(uint256)": "1337", + "isLeapYear(uint256)": "1633", + "isValidDate(uint256,uint256,uint256)": "942", + "isValidDateTime(uint256,uint256,uint256,uint256,uint256,uint256)": "1269", + "isWeekDay(uint256)": "1284", + "isWeekEnd(uint256)": "624", + "subDays(uint256,uint256)": "1146", + "subHours(uint256,uint256)": "288", + "subMinutes(uint256,uint256)": "992", + "subMonths(uint256,uint256)": "2363", + "subSeconds(uint256,uint256)": "1336", + "subYears(uint256,uint256)": "1871", + "timestampFromDate(uint256,uint256,uint256)": "718", + "timestampFromDateTime(uint256,uint256,uint256,uint256,uint256,uint256)": "1077", + "timestampToDate(uint256)": "infinite", + "timestampToDateTime(uint256)": "1945" + } +} +``` +
+ +
+ +## Algorithm + +The formulae to convert year/month/day hour:minute:second to a Unix timestamp and back use the algorithms from [Converting Between Julian Dates and Gregorian Calendar Dates](http://aa.usno.navy.mil/faq/docs/JD_Formula.php). These algorithms were originally designed by [Fliegel and van Flandern (1968)](http://www.worldcat.org/title/machine-algorithm-for-processing-calendar-dates/oclc/754110896). + +Note that these algorithms depend on negative numbers, so Solidity unsigned integers `uint` are converted to signed integers `int` to compute the date conversions and the results are converted back to `uint` for general use. + +
+ +### Converting YYYYMMDD to Unix Timestamp + +The Fortran algorithm follows: + +``` + INTEGER FUNCTION JD (YEAR,MONTH,DAY) +C +C---COMPUTES THE JULIAN DATE (JD) GIVEN A GREGORIAN CALENDAR +C DATE (YEAR,MONTH,DAY). +C + INTEGER YEAR,MONTH,DAY,I,J,K +C + I= YEAR + J= MONTH + K= DAY +C + JD= K-32075+1461*(I+4800+(J-14)/12)/4+367*(J-2-(J-14)/12*12) + 2 /12-3*((I+4900+(J-14)/12)/100)/4 +C + RETURN + END +``` + +Translating this formula, and subtracting an offset (2,440,588) so 1970/01/01 is day 0: + +``` +days = day + - 32075 + + 1461 * (year + 4800 + (month - 14) / 12) / 4 + + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 + - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 + - offset +``` + +
+ +### Converting Unix Timestamp To YYYYMMDD + +The Fortran algorithm follows: + +``` + SUBROUTINE GDATE (JD, YEAR,MONTH,DAY) +C +C---COMPUTES THE GREGORIAN CALENDAR DATE (YEAR,MONTH,DAY) +C GIVEN THE JULIAN DATE (JD). +C + INTEGER JD,YEAR,MONTH,DAY,I,J,K +C + L= JD+68569 + N= 4*L/146097 + L= L-(146097*N+3)/4 + I= 4000*(L+1)/1461001 + L= L-1461*I/4+31 + J= 80*L/2447 + K= L-2447*J/80 + L= J/11 + J= J+2-12*L + I= 100*(N-49)+I+L +C + YEAR= I + MONTH= J + DAY= K +C + RETURN + END + ``` + +Translating this formula and adding an offset (2,440,588) so 1970/01/01 is day 0: + +``` +int L = days + 68569 + offset +int N = 4 * L / 146097 +L = L - (146097 * N + 3) / 4 +year = 4000 * (L + 1) / 1461001 +L = L - 1461 * year / 4 + 31 +month = 80 * L / 2447 +dd = L - 2447 * month / 80 +L = month / 11 +month = month + 2 - 12 * L +year = 100 * (N - 49) + year + L +``` + +
+ +
+ +## Testing + +Details of the testing environment can be found in [test](test). + +The DateTime library calculations have been tested for the date range 1970/01/01 to 2345/12/01 for periodically sampled dates. + +The following functions were tested using the script [test/01_test1.sh](test/01_test1.sh) with the summary results saved +in [test/test1results.txt](test/test1results.txt) and the detailed output saved in [test/test1output.txt](test/test1output.txt): + +* [x] Deploy [contracts/BokkyPooBahsDateTimeLibrary.sol](contracts/BokkyPooBahsDateTimeLibrary.sol) library +* [x] Deploy [contracts/TestDateTime.sol](contracts/TestDateTime.sol) contract +* [x] Test `isValidDate(...)` +* [x] Test `isValidDateTime(...)` +* [x] Test `isLeapYear(...)` +* [x] Test `_isLeapYear(...)` +* [x] Test `isWeekDay(...)` +* [x] Test `isWeekEnd(...)` +* [x] Test `getDaysInMonth(...)` +* [x] Test `_getDaysInMonth(...)` +* [x] Test `getDayOfWeek(...)` +* [x] Test `get{Year|Month|Day|Hour|Minute|Second}(...)` +* [x] Test `add{Years|Months|Days|Hours|Minutes|Seconds}(...)` +* [x] Test `sub{Years|Months|Days|Hours|Minutes|Seconds}(...)` +* [x] Test `diff{Years|Months|Days|Hours|Minutes|Seconds}(...)` +* [x] For a range of Unix timestamps from 1970/01/01 to 2345/12/21 + * [x] Generate the year/month/day hour/minute/second from the Unix timestamp using `timestampToDateTime(...)` + * [x] Generate the Unix timestamp from the calculated year/month/day hour/minute/second using `timestampFromDateTime(...)` + * [x] Compare the year/month/day hour/minute/second to the JavaScript *Date* calculation + +
+ +
+ +## References + +A copy of the webpage with the algorithm [Converting Between Julian Dates and Gregorian Calendar Dates](http://aa.usno.navy.mil/faq/docs/JD_Formula.php) has been saved to [docs/ConvertingBetweenJulianDatesAndGregorianCalendarDates.pdf](docs/ConvertingBetweenJulianDatesAndGregorianCalendarDates.pdf) as some people have had difficulty accessing this page. + +
+ +
+ +Enjoy! + +(c) BokkyPooBah / Bok Consulting Pty Ltd - Feb 17 2019. The MIT Licence. diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeContract.sol b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeContract.sol new file mode 100644 index 0000000..2a58cb1 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeContract.sol @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0 <0.9.0; + +// ---------------------------------------------------------------------------- +// BokkyPooBah's DateTime Library v1.00 - Contract Instance +// +// A gas-efficient Solidity date and time library +// +// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary +// +// Tested date range 1970/01/01 to 2345/12/31 +// +// Conventions: +// Unit | Range | Notes +// :-------- |:-------------:|:----- +// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC +// year | 1970 ... 2345 | +// month | 1 ... 12 | +// day | 1 ... 31 | +// hour | 0 ... 23 | +// minute | 0 ... 59 | +// second | 0 ... 59 | +// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday +// +// +// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018. +// +// GNU Lesser General Public License 3.0 +// https://www.gnu.org/licenses/lgpl-3.0.en.html +// ---------------------------------------------------------------------------- + +import "BokkyPooBahsDateTimeLibrary.sol"; + +contract BokkyPooBahsDateTimeContract { + uint public constant SECONDS_PER_DAY = 24 * 60 * 60; + uint public constant SECONDS_PER_HOUR = 60 * 60; + uint public constant SECONDS_PER_MINUTE = 60; + int public constant OFFSET19700101 = 2440588; + + uint public constant DOW_MON = 1; + uint public constant DOW_TUE = 2; + uint public constant DOW_WED = 3; + uint public constant DOW_THU = 4; + uint public constant DOW_FRI = 5; + uint public constant DOW_SAT = 6; + uint public constant DOW_SUN = 7; + + function _now() public view returns (uint timestamp) { + timestamp = now; + } + function _nowDateTime() public view returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { + (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(now); + } + function _daysFromDate(uint year, uint month, uint day) public pure returns (uint _days) { + return BokkyPooBahsDateTimeLibrary._daysFromDate(year, month, day); + } + function _daysToDate(uint _days) public pure returns (uint year, uint month, uint day) { + return BokkyPooBahsDateTimeLibrary._daysToDate(_days); + } + function timestampFromDate(uint year, uint month, uint day) public pure returns (uint timestamp) { + return BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day); + } + function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (uint timestamp) { + return BokkyPooBahsDateTimeLibrary.timestampFromDateTime(year, month, day, hour, minute, second); + } + function timestampToDate(uint timestamp) public pure returns (uint year, uint month, uint day) { + (year, month, day) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); + } + function timestampToDateTime(uint timestamp) public pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { + (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(timestamp); + } + + function isValidDate(uint year, uint month, uint day) public pure returns (bool valid) { + valid = BokkyPooBahsDateTimeLibrary.isValidDate(year, month, day); + } + function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (bool valid) { + valid = BokkyPooBahsDateTimeLibrary.isValidDateTime(year, month, day, hour, minute, second); + } + function isLeapYear(uint timestamp) public pure returns (bool leapYear) { + leapYear = BokkyPooBahsDateTimeLibrary.isLeapYear(timestamp); + } + function _isLeapYear(uint year) public pure returns (bool leapYear) { + leapYear = BokkyPooBahsDateTimeLibrary._isLeapYear(year); + } + function isWeekDay(uint timestamp) public pure returns (bool weekDay) { + weekDay = BokkyPooBahsDateTimeLibrary.isWeekDay(timestamp); + } + function isWeekEnd(uint timestamp) public pure returns (bool weekEnd) { + weekEnd = BokkyPooBahsDateTimeLibrary.isWeekEnd(timestamp); + } + + function getDaysInMonth(uint timestamp) public pure returns (uint daysInMonth) { + daysInMonth = BokkyPooBahsDateTimeLibrary.getDaysInMonth(timestamp); + } + function _getDaysInMonth(uint year, uint month) public pure returns (uint daysInMonth) { + daysInMonth = BokkyPooBahsDateTimeLibrary._getDaysInMonth(year, month); + } + function getDayOfWeek(uint timestamp) public pure returns (uint dayOfWeek) { + dayOfWeek = BokkyPooBahsDateTimeLibrary.getDayOfWeek(timestamp); + } + + function getYear(uint timestamp) public pure returns (uint year) { + year = BokkyPooBahsDateTimeLibrary.getYear(timestamp); + } + function getMonth(uint timestamp) public pure returns (uint month) { + month = BokkyPooBahsDateTimeLibrary.getMonth(timestamp); + } + function getDay(uint timestamp) public pure returns (uint day) { + day = BokkyPooBahsDateTimeLibrary.getDay(timestamp); + } + function getHour(uint timestamp) public pure returns (uint hour) { + hour = BokkyPooBahsDateTimeLibrary.getHour(timestamp); + } + function getMinute(uint timestamp) public pure returns (uint minute) { + minute = BokkyPooBahsDateTimeLibrary.getMinute(timestamp); + } + function getSecond(uint timestamp) public pure returns (uint second) { + second = BokkyPooBahsDateTimeLibrary.getSecond(timestamp); + } + + function addYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addYears(timestamp, _years); + } + function addMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addMonths(timestamp, _months); + } + function addDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addDays(timestamp, _days); + } + function addHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addHours(timestamp, _hours); + } + function addMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addMinutes(timestamp, _minutes); + } + function addSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addSeconds(timestamp, _seconds); + } + + function subYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subYears(timestamp, _years); + } + function subMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subMonths(timestamp, _months); + } + function subDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subDays(timestamp, _days); + } + function subHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subHours(timestamp, _hours); + } + function subMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subMinutes(timestamp, _minutes); + } + function subSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subSeconds(timestamp, _seconds); + } + + function diffYears(uint fromTimestamp, uint toTimestamp) public pure returns (uint _years) { + _years = BokkyPooBahsDateTimeLibrary.diffYears(fromTimestamp, toTimestamp); + } + function diffMonths(uint fromTimestamp, uint toTimestamp) public pure returns (uint _months) { + _months = BokkyPooBahsDateTimeLibrary.diffMonths(fromTimestamp, toTimestamp); + } + function diffDays(uint fromTimestamp, uint toTimestamp) public pure returns (uint _days) { + _days = BokkyPooBahsDateTimeLibrary.diffDays(fromTimestamp, toTimestamp); + } + function diffHours(uint fromTimestamp, uint toTimestamp) public pure returns (uint _hours) { + _hours = BokkyPooBahsDateTimeLibrary.diffHours(fromTimestamp, toTimestamp); + } + function diffMinutes(uint fromTimestamp, uint toTimestamp) public pure returns (uint _minutes) { + _minutes = BokkyPooBahsDateTimeLibrary.diffMinutes(fromTimestamp, toTimestamp); + } + function diffSeconds(uint fromTimestamp, uint toTimestamp) public pure returns (uint _seconds) { + _seconds = BokkyPooBahsDateTimeLibrary.diffSeconds(fromTimestamp, toTimestamp); + } +} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol new file mode 100644 index 0000000..79a6e10 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0 <0.9.0; + +// ---------------------------------------------------------------------------- +// BokkyPooBah's DateTime Library v1.01 +// +// A gas-efficient Solidity date and time library +// +// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary +// +// Tested date range 1970/01/01 to 2345/12/31 +// +// Conventions: +// Unit | Range | Notes +// :-------- |:-------------:|:----- +// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC +// year | 1970 ... 2345 | +// month | 1 ... 12 | +// day | 1 ... 31 | +// hour | 0 ... 23 | +// minute | 0 ... 59 | +// second | 0 ... 59 | +// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday +// +// +// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. +// ---------------------------------------------------------------------------- + +library BokkyPooBahsDateTimeLibrary { + + uint constant SECONDS_PER_DAY = 24 * 60 * 60; + uint constant SECONDS_PER_HOUR = 60 * 60; + uint constant SECONDS_PER_MINUTE = 60; + int constant OFFSET19700101 = 2440588; + + uint constant DOW_MON = 1; + uint constant DOW_TUE = 2; + uint constant DOW_WED = 3; + uint constant DOW_THU = 4; + uint constant DOW_FRI = 5; + uint constant DOW_SAT = 6; + uint constant DOW_SUN = 7; + + // ------------------------------------------------------------------------ + // Calculate the number of days from 1970/01/01 to year/month/day using + // the date conversion algorithm from + // https://aa.usno.navy.mil/faq/JD_formula.html + // and subtracting the offset 2440588 so that 1970/01/01 is day 0 + // + // days = day + // - 32075 + // + 1461 * (year + 4800 + (month - 14) / 12) / 4 + // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 + // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 + // - offset + // ------------------------------------------------------------------------ + function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) { + require(year >= 1970); + int _year = int(year); + int _month = int(month); + int _day = int(day); + + int __days = _day + - 32075 + + 1461 * (_year + 4800 + (_month - 14) / 12) / 4 + + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12 + - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4 + - OFFSET19700101; + + _days = uint(__days); + } + + // ------------------------------------------------------------------------ + // Calculate year/month/day from the number of days since 1970/01/01 using + // the date conversion algorithm from + // http://aa.usno.navy.mil/faq/docs/JD_Formula.php + // and adding the offset 2440588 so that 1970/01/01 is day 0 + // + // int L = days + 68569 + offset + // int N = 4 * L / 146097 + // L = L - (146097 * N + 3) / 4 + // year = 4000 * (L + 1) / 1461001 + // L = L - 1461 * year / 4 + 31 + // month = 80 * L / 2447 + // dd = L - 2447 * month / 80 + // L = month / 11 + // month = month + 2 - 12 * L + // year = 100 * (N - 49) + year + L + // ------------------------------------------------------------------------ + function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) { + int __days = int(_days); + + int L = __days + 68569 + OFFSET19700101; + int N = 4 * L / 146097; + L = L - (146097 * N + 3) / 4; + int _year = 4000 * (L + 1) / 1461001; + L = L - 1461 * _year / 4 + 31; + int _month = 80 * L / 2447; + int _day = L - 2447 * _month / 80; + L = _month / 11; + _month = _month + 2 - 12 * L; + _year = 100 * (N - 49) + _year + L; + + year = uint(_year); + month = uint(_month); + day = uint(_day); + } + + function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) { + timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; + } + function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) { + timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second; + } + function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) { + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function timestampToDateTime(uint timestamp) internal pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + uint secs = timestamp % SECONDS_PER_DAY; + hour = secs / SECONDS_PER_HOUR; + secs = secs % SECONDS_PER_HOUR; + minute = secs / SECONDS_PER_MINUTE; + second = secs % SECONDS_PER_MINUTE; + } + + function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) { + if (year >= 1970 && month > 0 && month <= 12) { + uint daysInMonth = _getDaysInMonth(year, month); + if (day > 0 && day <= daysInMonth) { + valid = true; + } + } + } + function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) { + if (isValidDate(year, month, day)) { + if (hour < 24 && minute < 60 && second < 60) { + valid = true; + } + } + } + function isLeapYear(uint timestamp) internal pure returns (bool leapYear) { + (uint year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); + leapYear = _isLeapYear(year); + } + function _isLeapYear(uint year) internal pure returns (bool leapYear) { + leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); + } + function isWeekDay(uint timestamp) internal pure returns (bool weekDay) { + weekDay = getDayOfWeek(timestamp) <= DOW_FRI; + } + function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) { + weekEnd = getDayOfWeek(timestamp) >= DOW_SAT; + } + function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) { + (uint year, uint month,) = _daysToDate(timestamp / SECONDS_PER_DAY); + daysInMonth = _getDaysInMonth(year, month); + } + function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) { + if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { + daysInMonth = 31; + } else if (month != 2) { + daysInMonth = 30; + } else { + daysInMonth = _isLeapYear(year) ? 29 : 28; + } + } + // 1 = Monday, 7 = Sunday + function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) { + uint _days = timestamp / SECONDS_PER_DAY; + dayOfWeek = (_days + 3) % 7 + 1; + } + + function getYear(uint timestamp) internal pure returns (uint year) { + (year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function getMonth(uint timestamp) internal pure returns (uint month) { + (,month,) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function getDay(uint timestamp) internal pure returns (uint day) { + (,,day) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function getHour(uint timestamp) internal pure returns (uint hour) { + uint secs = timestamp % SECONDS_PER_DAY; + hour = secs / SECONDS_PER_HOUR; + } + function getMinute(uint timestamp) internal pure returns (uint minute) { + uint secs = timestamp % SECONDS_PER_HOUR; + minute = secs / SECONDS_PER_MINUTE; + } + function getSecond(uint timestamp) internal pure returns (uint second) { + second = timestamp % SECONDS_PER_MINUTE; + } + + function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { + (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); + year += _years; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp >= timestamp); + } + function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { + (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); + month += _months; + year += (month - 1) / 12; + month = (month - 1) % 12 + 1; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp >= timestamp); + } + function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _days * SECONDS_PER_DAY; + require(newTimestamp >= timestamp); + } + function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _hours * SECONDS_PER_HOUR; + require(newTimestamp >= timestamp); + } + function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE; + require(newTimestamp >= timestamp); + } + function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _seconds; + require(newTimestamp >= timestamp); + } + + function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { + (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); + year -= _years; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp <= timestamp); + } + function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { + (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); + uint yearMonth = year * 12 + (month - 1) - _months; + year = yearMonth / 12; + month = yearMonth % 12 + 1; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp <= timestamp); + } + function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _days * SECONDS_PER_DAY; + require(newTimestamp <= timestamp); + } + function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _hours * SECONDS_PER_HOUR; + require(newTimestamp <= timestamp); + } + function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE; + require(newTimestamp <= timestamp); + } + function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _seconds; + require(newTimestamp <= timestamp); + } + + function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) { + require(fromTimestamp <= toTimestamp); + (uint fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); + (uint toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); + _years = toYear - fromYear; + } + function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) { + require(fromTimestamp <= toTimestamp); + (uint fromYear, uint fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); + (uint toYear, uint toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); + _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth; + } + function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) { + require(fromTimestamp <= toTimestamp); + _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY; + } + function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) { + require(fromTimestamp <= toTimestamp); + _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR; + } + function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) { + require(fromTimestamp <= toTimestamp); + _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE; + } + function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) { + require(fromTimestamp <= toTimestamp); + _seconds = toTimestamp - fromTimestamp; + } +} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/TestDateTime.sol b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/TestDateTime.sol new file mode 100644 index 0000000..4213d67 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/TestDateTime.sol @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0 <0.9.0; + +import "BokkyPooBahsDateTimeLibrary.sol"; + +// ---------------------------------------------------------------------------- +// Testing BokkyPooBah's DateTime Library +// +// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary +// +// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. +// ---------------------------------------------------------------------------- + +contract TestDateTime { + using BokkyPooBahsDateTimeLibrary for uint; + + uint public nextYear; + + function test() public { + uint today = now; + nextYear = today.addYears(1); + } + + function timestampFromDate(uint year, uint month, uint day) public pure returns (uint timestamp) { + return BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day); + } + function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (uint timestamp) { + return BokkyPooBahsDateTimeLibrary.timestampFromDateTime(year, month, day, hour, minute, second); + } + function timestampToDate(uint timestamp) public pure returns (uint year, uint month, uint day) { + (year, month, day) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); + } + function timestampToDateTime(uint timestamp) public pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { + (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(timestamp); + } + + function isLeapYear(uint timestamp) public pure returns (bool leapYear) { + leapYear = BokkyPooBahsDateTimeLibrary.isLeapYear(timestamp); + } + function _isLeapYear(uint year) public pure returns (bool leapYear) { + leapYear = BokkyPooBahsDateTimeLibrary._isLeapYear(year); + } + function isWeekDay(uint timestamp) public pure returns (bool weekDay) { + weekDay = BokkyPooBahsDateTimeLibrary.isWeekDay(timestamp); + } + function isWeekEnd(uint timestamp) public pure returns (bool weekEnd) { + weekEnd = BokkyPooBahsDateTimeLibrary.isWeekEnd(timestamp); + } + + function getDaysInMonth(uint timestamp) public pure returns (uint daysInMonth) { + daysInMonth = BokkyPooBahsDateTimeLibrary.getDaysInMonth(timestamp); + } + function _getDaysInMonth(uint year, uint month) public pure returns (uint daysInMonth) { + daysInMonth = BokkyPooBahsDateTimeLibrary._getDaysInMonth(year, month); + } + function getDayOfWeek(uint timestamp) public pure returns (uint dayOfWeek) { + dayOfWeek = BokkyPooBahsDateTimeLibrary.getDayOfWeek(timestamp); + } + + function isValidDate(uint year, uint month, uint day) public pure returns (bool valid) { + valid = BokkyPooBahsDateTimeLibrary.isValidDate(year, month, day); + } + function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (bool valid) { + valid = BokkyPooBahsDateTimeLibrary.isValidDateTime(year, month, day, hour, minute, second); + } + + function getYear(uint timestamp) public pure returns (uint year) { + year = BokkyPooBahsDateTimeLibrary.getYear(timestamp); + } + function getMonth(uint timestamp) public pure returns (uint month) { + month = BokkyPooBahsDateTimeLibrary.getMonth(timestamp); + } + function getDay(uint timestamp) public pure returns (uint day) { + day = BokkyPooBahsDateTimeLibrary.getDay(timestamp); + } + function getHour(uint timestamp) public pure returns (uint hour) { + hour = BokkyPooBahsDateTimeLibrary.getHour(timestamp); + } + function getMinute(uint timestamp) public pure returns (uint minute) { + minute = BokkyPooBahsDateTimeLibrary.getMinute(timestamp); + } + function getSecond(uint timestamp) public pure returns (uint second) { + second = BokkyPooBahsDateTimeLibrary.getSecond(timestamp); + } + + function addYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addYears(timestamp, _years); + } + function addMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addMonths(timestamp, _months); + } + function addDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addDays(timestamp, _days); + } + function addHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addHours(timestamp, _hours); + } + function addMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addMinutes(timestamp, _minutes); + } + function addSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addSeconds(timestamp, _seconds); + } + + function subYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subYears(timestamp, _years); + } + function subMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subMonths(timestamp, _months); + } + function subDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subDays(timestamp, _days); + } + function subHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subHours(timestamp, _hours); + } + function subMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subMinutes(timestamp, _minutes); + } + function subSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subSeconds(timestamp, _seconds); + } + + function diffYears(uint fromTimestamp, uint toTimestamp) public pure returns (uint _years) { + _years = BokkyPooBahsDateTimeLibrary.diffYears(fromTimestamp, toTimestamp); + } + function diffMonths(uint fromTimestamp, uint toTimestamp) public pure returns (uint _months) { + _months = BokkyPooBahsDateTimeLibrary.diffMonths(fromTimestamp, toTimestamp); + } + function diffDays(uint fromTimestamp, uint toTimestamp) public pure returns (uint _days) { + _days = BokkyPooBahsDateTimeLibrary.diffDays(fromTimestamp, toTimestamp); + } + function diffHours(uint fromTimestamp, uint toTimestamp) public pure returns (uint _hours) { + _hours = BokkyPooBahsDateTimeLibrary.diffHours(fromTimestamp, toTimestamp); + } + function diffMinutes(uint fromTimestamp, uint toTimestamp) public pure returns (uint _minutes) { + _minutes = BokkyPooBahsDateTimeLibrary.diffMinutes(fromTimestamp, toTimestamp); + } + function diffSeconds(uint fromTimestamp, uint toTimestamp) public pure returns (uint _seconds) { + _seconds = BokkyPooBahsDateTimeLibrary.diffSeconds(fromTimestamp, toTimestamp); + } +} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/BokkyPooBahsDateTimeContract_flattened_v1.00.sol b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/BokkyPooBahsDateTimeContract_flattened_v1.00.sol new file mode 100644 index 0000000..389ba39 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/BokkyPooBahsDateTimeContract_flattened_v1.00.sol @@ -0,0 +1,491 @@ +pragma solidity ^0.4.23; + +// ---------------------------------------------------------------------------- +// BokkyPooBah's DateTime Library v1.00 +// +// A gas-efficient Solidity date and time library +// +// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary +// +// Tested date range 1970/01/01 to 2345/12/31 +// +// Conventions: +// Unit | Range | Notes +// :-------- |:-------------:|:----- +// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC +// year | 1970 ... 2345 | +// month | 1 ... 12 | +// day | 1 ... 31 | +// hour | 0 ... 23 | +// minute | 0 ... 59 | +// second | 0 ... 59 | +// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday +// +// +// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018. +// +// GNU Lesser General Public License 3.0 +// https://www.gnu.org/licenses/lgpl-3.0.en.html +// ---------------------------------------------------------------------------- + +library BokkyPooBahsDateTimeLibrary { + + uint constant SECONDS_PER_DAY = 24 * 60 * 60; + uint constant SECONDS_PER_HOUR = 60 * 60; + uint constant SECONDS_PER_MINUTE = 60; + int constant OFFSET19700101 = 2440588; + + uint constant DOW_MON = 1; + uint constant DOW_TUE = 2; + uint constant DOW_WED = 3; + uint constant DOW_THU = 4; + uint constant DOW_FRI = 5; + uint constant DOW_SAT = 6; + uint constant DOW_SUN = 7; + + // ------------------------------------------------------------------------ + // Calculate the number of days from 1970/01/01 to year/month/day using + // the date conversion algorithm from + // http://aa.usno.navy.mil/faq/docs/JD_Formula.php + // and subtracting the offset 2440588 so that 1970/01/01 is day 0 + // + // days = day + // - 32075 + // + 1461 * (year + 4800 + (month - 14) / 12) / 4 + // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 + // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 + // - offset + // ------------------------------------------------------------------------ + function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) { + int _year = int(year); + int _month = int(month); + int _day = int(day); + + int __days = _day + - 32075 + + 1461 * (_year + 4800 + (_month - 14) / 12) / 4 + + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12 + - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4 + - OFFSET19700101; + + _days = uint(__days); + } + + // ------------------------------------------------------------------------ + // Calculate year/month/day from the number of days since 1970/01/01 using + // the date conversion algorithm from + // http://aa.usno.navy.mil/faq/docs/JD_Formula.php + // and adding the offset 2440588 so that 1970/01/01 is day 0 + // + // int L = days + 68569 + offset + // int N = 4 * L / 146097 + // L = L - (146097 * N + 3) / 4 + // year = 4000 * (L + 1) / 1461001 + // L = L - 1461 * year / 4 + 31 + // month = 80 * L / 2447 + // dd = L - 2447 * month / 80 + // L = month / 11 + // month = month + 2 - 12 * L + // year = 100 * (N - 49) + year + L + // ------------------------------------------------------------------------ + function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) { + int __days = int(_days); + + int L = __days + 68569 + OFFSET19700101; + int N = 4 * L / 146097; + L = L - (146097 * N + 3) / 4; + int _year = 4000 * (L + 1) / 1461001; + L = L - 1461 * _year / 4 + 31; + int _month = 80 * L / 2447; + int _day = L - 2447 * _month / 80; + L = _month / 11; + _month = _month + 2 - 12 * L; + _year = 100 * (N - 49) + _year + L; + + year = uint(_year); + month = uint(_month); + day = uint(_day); + } + + function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) { + timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; + } + function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) { + timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second; + } + function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) { + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function timestampToDateTime(uint timestamp) internal pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + uint secs = timestamp % SECONDS_PER_DAY; + hour = secs / SECONDS_PER_HOUR; + secs = secs % SECONDS_PER_HOUR; + minute = secs / SECONDS_PER_MINUTE; + second = secs % SECONDS_PER_MINUTE; + } + + function isLeapYear(uint timestamp) internal pure returns (bool leapYear) { + uint year; + uint month; + uint day; + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + leapYear = _isLeapYear(year); + } + function _isLeapYear(uint year) internal pure returns (bool leapYear) { + leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); + } + function isWeekDay(uint timestamp) internal pure returns (bool weekDay) { + weekDay = getDayOfWeek(timestamp) <= DOW_FRI; + } + function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) { + weekEnd = getDayOfWeek(timestamp) >= DOW_SAT; + } + function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) { + uint year; + uint month; + uint day; + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + daysInMonth = _getDaysInMonth(year, month); + } + function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) { + if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { + daysInMonth = 31; + } else if (month != 2) { + daysInMonth = 30; + } else { + daysInMonth = _isLeapYear(year) ? 29 : 28; + } + } + // 1 = Monday, 7 = Sunday + function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) { + uint _days = timestamp / SECONDS_PER_DAY; + dayOfWeek = (_days + 3) % 7 + 1; + } + + function getYear(uint timestamp) internal pure returns (uint year) { + uint month; + uint day; + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function getMonth(uint timestamp) internal pure returns (uint month) { + uint year; + uint day; + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function getDay(uint timestamp) internal pure returns (uint day) { + uint year; + uint month; + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function getHour(uint timestamp) internal pure returns (uint hour) { + uint secs = timestamp % SECONDS_PER_DAY; + hour = secs / SECONDS_PER_HOUR; + } + function getMinute(uint timestamp) internal pure returns (uint minute) { + uint secs = timestamp % SECONDS_PER_HOUR; + minute = secs / SECONDS_PER_MINUTE; + } + function getSecond(uint timestamp) internal pure returns (uint second) { + second = timestamp % SECONDS_PER_MINUTE; + } + + function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { + uint year; + uint month; + uint day; + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + year += _years; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp >= timestamp); + } + function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { + uint year; + uint month; + uint day; + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + month += _months; + year += (month - 1) / 12; + month = (month - 1) % 12 + 1; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp >= timestamp); + } + function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _days * SECONDS_PER_DAY; + require(newTimestamp >= timestamp); + } + function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _hours * SECONDS_PER_HOUR; + require(newTimestamp >= timestamp); + } + function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE; + require(newTimestamp >= timestamp); + } + function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _seconds; + require(newTimestamp >= timestamp); + } + + function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { + uint year; + uint month; + uint day; + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + year -= _years; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp <= timestamp); + } + function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { + uint year; + uint month; + uint day; + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + uint yearMonth = year * 12 + (month - 1) - _months; + year = yearMonth / 12; + month = yearMonth % 12 + 1; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp <= timestamp); + } + function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _days * SECONDS_PER_DAY; + require(newTimestamp <= timestamp); + } + function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _hours * SECONDS_PER_HOUR; + require(newTimestamp <= timestamp); + } + function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE; + require(newTimestamp <= timestamp); + } + function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _seconds; + require(newTimestamp <= timestamp); + } + + function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) { + require(fromTimestamp <= toTimestamp); + uint fromYear; + uint fromMonth; + uint fromDay; + uint toYear; + uint toMonth; + uint toDay; + (fromYear, fromMonth, fromDay) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); + (toYear, toMonth, toDay) = _daysToDate(toTimestamp / SECONDS_PER_DAY); + _years = toYear - fromYear; + } + function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) { + require(fromTimestamp <= toTimestamp); + uint fromYear; + uint fromMonth; + uint fromDay; + uint toYear; + uint toMonth; + uint toDay; + (fromYear, fromMonth, fromDay) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); + (toYear, toMonth, toDay) = _daysToDate(toTimestamp / SECONDS_PER_DAY); + _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth; + } + function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) { + require(fromTimestamp <= toTimestamp); + _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY; + } + function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) { + require(fromTimestamp <= toTimestamp); + _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR; + } + function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) { + require(fromTimestamp <= toTimestamp); + _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE; + } + function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) { + require(fromTimestamp <= toTimestamp); + _seconds = toTimestamp - fromTimestamp; + } +} + + +// ---------------------------------------------------------------------------- +// BokkyPooBah's DateTime Library v1.00 - Contract Instance +// +// A gas-efficient Solidity date and time library +// +// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary +// +// Tested date range 1970/01/01 to 2345/12/31 +// +// Conventions: +// Unit | Range | Notes +// :-------- |:-------------:|:----- +// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC +// year | 1970 ... 2345 | +// month | 1 ... 12 | +// day | 1 ... 31 | +// hour | 0 ... 23 | +// minute | 0 ... 59 | +// second | 0 ... 59 | +// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday +// +// +// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018. +// +// GNU Lesser General Public License 3.0 +// https://www.gnu.org/licenses/lgpl-3.0.en.html +// ---------------------------------------------------------------------------- + +contract BokkyPooBahsDateTimeContract { + uint public constant SECONDS_PER_DAY = 24 * 60 * 60; + uint public constant SECONDS_PER_HOUR = 60 * 60; + uint public constant SECONDS_PER_MINUTE = 60; + int public constant OFFSET19700101 = 2440588; + + uint public constant DOW_MON = 1; + uint public constant DOW_TUE = 2; + uint public constant DOW_WED = 3; + uint public constant DOW_THU = 4; + uint public constant DOW_FRI = 5; + uint public constant DOW_SAT = 6; + uint public constant DOW_SUN = 7; + + function _now() public view returns (uint timestamp) { + timestamp = now; + } + function _nowDateTime() public view returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { + (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(now); + } + function _daysFromDate(uint year, uint month, uint day) public pure returns (uint _days) { + return BokkyPooBahsDateTimeLibrary._daysFromDate(year, month, day); + } + function _daysToDate(uint _days) public pure returns (uint year, uint month, uint day) { + return BokkyPooBahsDateTimeLibrary._daysToDate(_days); + } + function timestampFromDate(uint year, uint month, uint day) public pure returns (uint timestamp) { + return BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day); + } + function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (uint timestamp) { + return BokkyPooBahsDateTimeLibrary.timestampFromDateTime(year, month, day, hour, minute, second); + } + function timestampToDate(uint timestamp) public pure returns (uint year, uint month, uint day) { + (year, month, day) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); + } + function timestampToDateTime(uint timestamp) public pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { + (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(timestamp); + } + + function isLeapYear(uint timestamp) public pure returns (bool leapYear) { + leapYear = BokkyPooBahsDateTimeLibrary.isLeapYear(timestamp); + } + function _isLeapYear(uint year) public pure returns (bool leapYear) { + leapYear = BokkyPooBahsDateTimeLibrary._isLeapYear(year); + } + function isWeekDay(uint timestamp) public pure returns (bool weekDay) { + weekDay = BokkyPooBahsDateTimeLibrary.isWeekDay(timestamp); + } + function isWeekEnd(uint timestamp) public pure returns (bool weekEnd) { + weekEnd = BokkyPooBahsDateTimeLibrary.isWeekEnd(timestamp); + } + + function getDaysInMonth(uint timestamp) public pure returns (uint daysInMonth) { + daysInMonth = BokkyPooBahsDateTimeLibrary.getDaysInMonth(timestamp); + } + function _getDaysInMonth(uint year, uint month) public pure returns (uint daysInMonth) { + daysInMonth = BokkyPooBahsDateTimeLibrary._getDaysInMonth(year, month); + } + function getDayOfWeek(uint timestamp) public pure returns (uint dayOfWeek) { + dayOfWeek = BokkyPooBahsDateTimeLibrary.getDayOfWeek(timestamp); + } + + function getYear(uint timestamp) public pure returns (uint year) { + year = BokkyPooBahsDateTimeLibrary.getYear(timestamp); + } + function getMonth(uint timestamp) public pure returns (uint month) { + month = BokkyPooBahsDateTimeLibrary.getMonth(timestamp); + } + function getDay(uint timestamp) public pure returns (uint day) { + day = BokkyPooBahsDateTimeLibrary.getDay(timestamp); + } + function getHour(uint timestamp) public pure returns (uint hour) { + hour = BokkyPooBahsDateTimeLibrary.getHour(timestamp); + } + function getMinute(uint timestamp) public pure returns (uint minute) { + minute = BokkyPooBahsDateTimeLibrary.getMinute(timestamp); + } + function getSecond(uint timestamp) public pure returns (uint second) { + second = BokkyPooBahsDateTimeLibrary.getSecond(timestamp); + } + + function addYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addYears(timestamp, _years); + } + function addMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addMonths(timestamp, _months); + } + function addDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addDays(timestamp, _days); + } + function addHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addHours(timestamp, _hours); + } + function addMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addMinutes(timestamp, _minutes); + } + function addSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addSeconds(timestamp, _seconds); + } + + function subYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subYears(timestamp, _years); + } + function subMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subMonths(timestamp, _months); + } + function subDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subDays(timestamp, _days); + } + function subHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subHours(timestamp, _hours); + } + function subMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subMinutes(timestamp, _minutes); + } + function subSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subSeconds(timestamp, _seconds); + } + + function diffYears(uint fromTimestamp, uint toTimestamp) public pure returns (uint _years) { + _years = BokkyPooBahsDateTimeLibrary.diffYears(fromTimestamp, toTimestamp); + } + function diffMonths(uint fromTimestamp, uint toTimestamp) public pure returns (uint _months) { + _months = BokkyPooBahsDateTimeLibrary.diffMonths(fromTimestamp, toTimestamp); + } + function diffDays(uint fromTimestamp, uint toTimestamp) public pure returns (uint _days) { + _days = BokkyPooBahsDateTimeLibrary.diffDays(fromTimestamp, toTimestamp); + } + function diffHours(uint fromTimestamp, uint toTimestamp) public pure returns (uint _hours) { + _hours = BokkyPooBahsDateTimeLibrary.diffHours(fromTimestamp, toTimestamp); + } + function diffMinutes(uint fromTimestamp, uint toTimestamp) public pure returns (uint _minutes) { + _minutes = BokkyPooBahsDateTimeLibrary.diffMinutes(fromTimestamp, toTimestamp); + } + function diffSeconds(uint fromTimestamp, uint toTimestamp) public pure returns (uint _seconds) { + _seconds = BokkyPooBahsDateTimeLibrary.diffSeconds(fromTimestamp, toTimestamp); + } +} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/deployment-v1.00-prerelease.md b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/deployment-v1.00-prerelease.md new file mode 100644 index 0000000..e93cb8a --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/deployment-v1.00-prerelease.md @@ -0,0 +1,32 @@ +# Deployment + +Compiled with Remix with Solidity 0.4.24+commit.e67f0147.Emscripten.clang and optimisation switched on + +
+ +
+ +## Deploy From Remix To Ropsten Via Geth + +```javascript +var bokkypoobahsdatetimecontractContract = web3.eth.contract([{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_hours","type":"uint256"}],"name":"subHours","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"fromTimestamp","type":"uint256"},{"name":"toTimestamp","type":"uint256"}],"name":"diffMinutes","outputs":[{"name":"_minutes","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getDaysInMonth","outputs":[{"name":"daysInMonth","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOW_TUE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"},{"name":"day","type":"uint256"}],"name":"_daysFromDate","outputs":[{"name":"_days","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"},{"name":"day","type":"uint256"}],"name":"timestampFromDate","outputs":[{"name":"timestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getDayOfWeek","outputs":[{"name":"dayOfWeek","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOW_SUN","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"fromTimestamp","type":"uint256"},{"name":"toTimestamp","type":"uint256"}],"name":"diffHours","outputs":[{"name":"_hours","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getHour","outputs":[{"name":"hour","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"}],"name":"_getDaysInMonth","outputs":[{"name":"daysInMonth","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_months","type":"uint256"}],"name":"addMonths","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"isWeekEnd","outputs":[{"name":"weekEnd","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_years","type":"uint256"}],"name":"addYears","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_years","type":"uint256"}],"name":"subYears","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_hours","type":"uint256"}],"name":"addHours","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"SECONDS_PER_HOUR","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"},{"name":"day","type":"uint256"},{"name":"hour","type":"uint256"},{"name":"minute","type":"uint256"},{"name":"second","type":"uint256"}],"name":"timestampFromDateTime","outputs":[{"name":"timestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"fromTimestamp","type":"uint256"},{"name":"toTimestamp","type":"uint256"}],"name":"diffSeconds","outputs":[{"name":"_seconds","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getDay","outputs":[{"name":"day","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_days","type":"uint256"}],"name":"addDays","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"SECONDS_PER_DAY","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"fromTimestamp","type":"uint256"},{"name":"toTimestamp","type":"uint256"}],"name":"diffMonths","outputs":[{"name":"_months","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_minutes","type":"uint256"}],"name":"addMinutes","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getSecond","outputs":[{"name":"second","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOW_WED","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_seconds","type":"uint256"}],"name":"addSeconds","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"_days","type":"uint256"}],"name":"_daysToDate","outputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"},{"name":"day","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"_nowDateTime","outputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"},{"name":"day","type":"uint256"},{"name":"hour","type":"uint256"},{"name":"minute","type":"uint256"},{"name":"second","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getYear","outputs":[{"name":"year","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_minutes","type":"uint256"}],"name":"subMinutes","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getMonth","outputs":[{"name":"month","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"OFFSET19700101","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_months","type":"uint256"}],"name":"subMonths","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"year","type":"uint256"}],"name":"_isLeapYear","outputs":[{"name":"leapYear","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"_now","outputs":[{"name":"timestamp","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"isLeapYear","outputs":[{"name":"leapYear","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_days","type":"uint256"}],"name":"subDays","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOW_SAT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"fromTimestamp","type":"uint256"},{"name":"toTimestamp","type":"uint256"}],"name":"diffDays","outputs":[{"name":"_days","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOW_THU","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOW_FRI","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"isWeekDay","outputs":[{"name":"weekDay","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"timestampToDate","outputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"},{"name":"day","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"SECONDS_PER_MINUTE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"timestampToDateTime","outputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"},{"name":"day","type":"uint256"},{"name":"hour","type":"uint256"},{"name":"minute","type":"uint256"},{"name":"second","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_seconds","type":"uint256"}],"name":"subSeconds","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOW_MON","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getMinute","outputs":[{"name":"minute","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"fromTimestamp","type":"uint256"},{"name":"toTimestamp","type":"uint256"}],"name":"diffYears","outputs":[{"name":"_years","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"}]); +var bokkypoobahsdatetimecontract = bokkypoobahsdatetimecontractContract.new( + { + from: web3.eth.accounts[1], + data: '0x608060405234801561001057600080fd5b50611091806100206000396000f30060806040526004361061025a5763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041662501553811461025f57806302e98e0d1461028c57806310848ddf146102a7578063126702a0146102bf5780631e0582e9146102d45780631f4f77b2146102f257806322f8a2b81461031057806329441674146103285780632af123b81461033d5780633e239e1a146103585780633f9e0eb7146103705780634355644d1461038b5780634371c465146103a6578063442b8c79146103d2578063444fda82146103ed5780634b321502146104085780634df86126146104235780635e05bd6d1461043857806362fb96971461045f57806365c728401461047a5780637217523c1461049257806374f0314f146104ad5780637be34109146104c257806389a3a00d146104dd5780638aa001fc146104f85780638bbf51b7146105105780638d4a2d391461052557806390059aed146105405780639220d4261461057657806392d66313146105be5780639e524caa146105d6578063a324ad24146105f1578063a3f144ae14610609578063ad203bd41461061e578063b05eb08d14610639578063b3bb8cd414610651578063b8d16dbc14610666578063c7b6fd6a1461067e578063c7edf88c14610699578063c9d34622146106ae578063cfbb9f37146106c9578063d2b50743146106de578063d6582d0d146106f3578063de5101af1461070b578063e955643014610723578063ea1c169014610738578063f615ed5414610750578063f9fd52501461076b578063fa93f88314610780578063ff2258cb14610798575b600080fd5b34801561026b57600080fd5b5061027a6004356024356107b3565b60408051918252519081900360200190f35b34801561029857600080fd5b5061027a6004356024356107c6565b3480156102b357600080fd5b5061027a6004356107d2565b3480156102cb57600080fd5b5061027a6107e3565b3480156102e057600080fd5b5061027a6004356024356044356107e8565b3480156102fe57600080fd5b5061027a6004356024356044356107fd565b34801561031c57600080fd5b5061027a60043561080a565b34801561033457600080fd5b5061027a610815565b34801561034957600080fd5b5061027a60043560243561081a565b34801561036457600080fd5b5061027a600435610826565b34801561037c57600080fd5b5061027a600435602435610831565b34801561039757600080fd5b5061027a60043560243561083d565b3480156103b257600080fd5b506103be600435610849565b604080519115158252519081900360200190f35b3480156103de57600080fd5b5061027a600435602435610854565b3480156103f957600080fd5b5061027a600435602435610860565b34801561041457600080fd5b5061027a60043560243561086c565b34801561042f57600080fd5b5061027a610878565b34801561044457600080fd5b5061027a60043560243560443560643560843560a43561087e565b34801561046b57600080fd5b5061027a600435602435610899565b34801561048657600080fd5b5061027a6004356108a5565b34801561049e57600080fd5b5061027a6004356024356108b0565b3480156104b957600080fd5b5061027a6108bc565b3480156104ce57600080fd5b5061027a6004356024356108c3565b3480156104e957600080fd5b5061027a6004356024356108cf565b34801561050457600080fd5b5061027a6004356108db565b34801561051c57600080fd5b5061027a6108e6565b34801561053157600080fd5b5061027a6004356024356108eb565b34801561054c57600080fd5b506105586004356108f7565b60408051938452602084019290925282820152519081900360600190f35b34801561058257600080fd5b5061058b610912565b604080519687526020870195909552858501939093526060850191909152608084015260a0830152519081900360c00190f35b3480156105ca57600080fd5b5061027a600435610937565b3480156105e257600080fd5b5061027a600435602435610942565b3480156105fd57600080fd5b5061027a60043561094e565b34801561061557600080fd5b5061027a610959565b34801561062a57600080fd5b5061027a600435602435610960565b34801561064557600080fd5b506103be60043561096c565b34801561065d57600080fd5b5061027a610977565b34801561067257600080fd5b506103be60043561097b565b34801561068a57600080fd5b5061027a600435602435610986565b3480156106a557600080fd5b5061027a610992565b3480156106ba57600080fd5b5061027a600435602435610997565b3480156106d557600080fd5b5061027a6109a3565b3480156106ea57600080fd5b5061027a6109a8565b3480156106ff57600080fd5b506103be6004356109ad565b34801561071757600080fd5b506105586004356109b8565b34801561072f57600080fd5b5061027a6109d3565b34801561074457600080fd5b5061058b6004356109d8565b34801561075c57600080fd5b5061027a6004356024356109fe565b34801561077757600080fd5b5061027a610a0a565b34801561078c57600080fd5b5061027a600435610a0f565b3480156107a457600080fd5b5061027a600435602435610a1a565b60006107bf8383610a26565b9392505050565b60006107bf8383610a3a565b60006107dd82610a57565b92915050565b600281565b60006107f5848484610a85565b949350505050565b60006107f5848484610ad9565b60006107dd82610af3565b600781565b60006107bf8383610b06565b60006107dd82610b20565b60006107bf8383610b2e565b60006107bf8383610bb4565b60006107dd82610c2a565b60006107bf8383610c3f565b60006107bf8383610c65565b60006107bf8383610cc0565b610e1081565b600061088e878787878787610cd4565b979650505050505050565b60006107bf8383610cfe565b60006107dd82610d12565b60006107bf8383610d2d565b6201518081565b60006107bf8383610d42565b60006107bf8383610d96565b60006107dd82610da9565b600381565b60006107bf8383610db0565b600080600061090584610dc0565b9250925092509193909250565b60008060008060008061092442610e55565b949b939a50919850965094509092509050565b60006107dd82610e96565b60006107bf8383610eb2565b60006107dd82610ec5565b62253d8c81565b60006107bf8383610ee0565b60006107dd82610f61565b4290565b60006107dd82610f86565b60006107bf8383610fa8565b600681565b60006107bf8383610fbd565b600481565b600581565b60006107dd82610fd8565b60008060006109c684610fed565b9196909550909350915050565b603c81565b6000806000806000806109ea87610e55565b949c939b5091995097509550909350915050565b60006107bf8383610ffe565b600181565b60006107dd8261100e565b60006107bf838361101d565b610e1081028203828111156107dd57600080fd5b600081831115610a4957600080fd5b603c8383035b049392505050565b6000808080610a6b62015180865b04610dc0565b91945092509050610a7c8383610b2e565b95945050505050565b6225bad61960046064600c600d1986018190059687016113248101929092056003028390056112c09092016105b502929092059093016001199582029094039490940161016f029390930591909101030190565b600062015180610aea858585610a85565b02949350505050565b6007620151809091046003010660010190565b600081831115610b1557600080fd5b610e10838303610a4f565b610e10620151809091060490565b60008160011480610b3f5750816003145b80610b4a5750816005145b80610b555750816007145b80610b605750816008145b80610b6b575081600a145b80610b76575081600c145b15610b835750601f6107dd565b60028214610b935750601e6107dd565b610b9c83610f61565b610ba757601c610baa565b601d5b60ff169392505050565b600080808080610bc76201518088610a65565b600c91890160001901828104939093019650910660010193509150610bec8484610b2e565b905080821115610bfa578091505b62015180870662015180610c0f868686610a85565b0201945086851015610c2057600080fd5b5050505092915050565b60006006610c3783610af3565b101592915050565b600080808080610c526201518088610a65565b918801955093509150610bec8484610b2e565b600080808080610c786201518088610a65565b91889003955093509150610c8c8484610b2e565b905080821115610c9a578091505b62015180870662015180610caf868686610a85565b0201945086851115610c2057600080fd5b610e1081028201828110156107dd57600080fd5b600081603c8402610e10860262015180610cef8b8b8b610a85565b02010101979650505050505050565b600081831115610d0d57600080fd5b500390565b60008080610d236201518085610a65565b9695505050505050565b6201518081028201828110156107dd57600080fd5b600080808080808087891115610d5757600080fd5b610d64620151808a610a65565b91975095509350610d786201518089610a65565b50600c97880297909102019590950393909303979650505050505050565b603c81028201828110156107dd57600080fd5b603c900690565b818101828110156107dd57600080fd5b60008080836226496581018280808062023ab1600486020593506004600362023ab1860201059094039362164b09610fa0600187010205925060046105b58402058503601f01945061098f85605002811515610e1857fe5b059150605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b6000808080808080610e6a6201518089610a65565b919a9099919850610e10620151809092068281049850603c929006828104975091909106945092505050565b60008080610ea76201518085610a65565b509095945050505050565b603c81028203828111156107dd57600080fd5b60008080610ed66201518085610a65565b5095945050505050565b60008080808080610ef46201518089610a65565b91965094509250600c808602850188900360001901925082049450600c82066001019350610f228585610b2e565b905080831115610f30578092505b62015180880662015180610f45878787610a85565b0201955087861115610f5657600080fd5b505050505092915050565b600060048206158015610f7657506064820615155b806107dd57505061019090061590565b6000808080610f986201518086610a65565b91945092509050610a7c83610f61565b6201518081028203828111156107dd57600080fd5b600081831115610fcc57600080fd5b62015180838303610a4f565b60006005610fe583610af3565b111592915050565b600080806109c66201518085610a65565b808203828111156107dd57600080fd5b6000610e108206603c81610a4f565b60008080808080808789111561103257600080fd5b61103f620151808a610a65565b919750955093506110536201518089610a65565b505095909503989750505050505050505600a165627a7a72305820d4f1389ffe027f893a43a30bb50d36944b44ec9d5e69c6327987a6ef9e41a1d60029', + gas: '4700000' + }, function (e, contract){ + console.log(e, contract); + if (typeof contract.address !== 'undefined') { + console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash); + } + }) +``` + +``` +INFO [06-04|17:10:54] Submitted contract creation fullhash=0xf1cfcf58e4f9428da80d8c79e299668fb93959177ca400ed8ae18ed46c9fbae2 contract=0x07239Bb079094481bfAAc91cA842426860021Aaa +``` + +Deployment transaction https://ropsten.etherscan.io/tx/0xf1cfcf58e4f9428da80d8c79e299668fb93959177ca400ed8ae18ed46c9fbae2 with 1,181,383 gas used. + +Deployed contract to https://ropsten.etherscan.io/address/0x07239bb079094481bfaac91ca842426860021aaa#code \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/docs/ConvertingBetweenJulianDatesAndGregorianCalendarDates.pdf b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/docs/ConvertingBetweenJulianDatesAndGregorianCalendarDates.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f079e3155f19e17c33b0dccb8ac3b9de6e881978 GIT binary patch literal 90427 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
d>-QFfMdh%2YivSU}PL({% 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∨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 Td%FyQojC$yF)>LhNn!mT>MxLN literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/docs/timestampFromDateTime.png b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/docs/timestampFromDateTime.png new file mode 100644 index 0000000000000000000000000000000000000000..d991890e5b0d98bb40c93c644b87d13d9e5e9ec9 GIT binary patch literal 188342 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

uDAXVjwEX$UW6zfZ;LYe% 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

^M*lERY{v&i64-?5!m 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 Je8ANEe*l9K+dlvR literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/flattened/TestDateTime_flattened.sol b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/flattened/TestDateTime_flattened.sol new file mode 100644 index 0000000..4efeb9d --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/flattened/TestDateTime_flattened.sol @@ -0,0 +1,439 @@ +pragma solidity ^0.6.0; + + +// ---------------------------------------------------------------------------- +// BokkyPooBah's DateTime Library v1.01 +// +// A gas-efficient Solidity date and time library +// +// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary +// +// Tested date range 1970/01/01 to 2345/12/31 +// +// Conventions: +// Unit | Range | Notes +// :-------- |:-------------:|:----- +// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC +// year | 1970 ... 2345 | +// month | 1 ... 12 | +// day | 1 ... 31 | +// hour | 0 ... 23 | +// minute | 0 ... 59 | +// second | 0 ... 59 | +// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday +// +// +// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. +// ---------------------------------------------------------------------------- + +library BokkyPooBahsDateTimeLibrary { + + uint constant SECONDS_PER_DAY = 24 * 60 * 60; + uint constant SECONDS_PER_HOUR = 60 * 60; + uint constant SECONDS_PER_MINUTE = 60; + int constant OFFSET19700101 = 2440588; + + uint constant DOW_MON = 1; + uint constant DOW_TUE = 2; + uint constant DOW_WED = 3; + uint constant DOW_THU = 4; + uint constant DOW_FRI = 5; + uint constant DOW_SAT = 6; + uint constant DOW_SUN = 7; + + // ------------------------------------------------------------------------ + // Calculate the number of days from 1970/01/01 to year/month/day using + // the date conversion algorithm from + // http://aa.usno.navy.mil/faq/docs/JD_Formula.php + // and subtracting the offset 2440588 so that 1970/01/01 is day 0 + // + // days = day + // - 32075 + // + 1461 * (year + 4800 + (month - 14) / 12) / 4 + // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 + // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 + // - offset + // ------------------------------------------------------------------------ + function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) { + require(year >= 1970); + int _year = int(year); + int _month = int(month); + int _day = int(day); + + int __days = _day + - 32075 + + 1461 * (_year + 4800 + (_month - 14) / 12) / 4 + + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12 + - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4 + - OFFSET19700101; + + _days = uint(__days); + } + + // ------------------------------------------------------------------------ + // Calculate year/month/day from the number of days since 1970/01/01 using + // the date conversion algorithm from + // http://aa.usno.navy.mil/faq/docs/JD_Formula.php + // and adding the offset 2440588 so that 1970/01/01 is day 0 + // + // int L = days + 68569 + offset + // int N = 4 * L / 146097 + // L = L - (146097 * N + 3) / 4 + // year = 4000 * (L + 1) / 1461001 + // L = L - 1461 * year / 4 + 31 + // month = 80 * L / 2447 + // dd = L - 2447 * month / 80 + // L = month / 11 + // month = month + 2 - 12 * L + // year = 100 * (N - 49) + year + L + // ------------------------------------------------------------------------ + function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) { + int __days = int(_days); + + int L = __days + 68569 + OFFSET19700101; + int N = 4 * L / 146097; + L = L - (146097 * N + 3) / 4; + int _year = 4000 * (L + 1) / 1461001; + L = L - 1461 * _year / 4 + 31; + int _month = 80 * L / 2447; + int _day = L - 2447 * _month / 80; + L = _month / 11; + _month = _month + 2 - 12 * L; + _year = 100 * (N - 49) + _year + L; + + year = uint(_year); + month = uint(_month); + day = uint(_day); + } + + function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) { + timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; + } + function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) { + timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second; + } + function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) { + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function timestampToDateTime(uint timestamp) internal pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + uint secs = timestamp % SECONDS_PER_DAY; + hour = secs / SECONDS_PER_HOUR; + secs = secs % SECONDS_PER_HOUR; + minute = secs / SECONDS_PER_MINUTE; + second = secs % SECONDS_PER_MINUTE; + } + + function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) { + if (year >= 1970 && month > 0 && month <= 12) { + uint daysInMonth = _getDaysInMonth(year, month); + if (day > 0 && day <= daysInMonth) { + valid = true; + } + } + } + function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) { + if (isValidDate(year, month, day)) { + if (hour < 24 && minute < 60 && second < 60) { + valid = true; + } + } + } + function isLeapYear(uint timestamp) internal pure returns (bool leapYear) { + (uint year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); + leapYear = _isLeapYear(year); + } + function _isLeapYear(uint year) internal pure returns (bool leapYear) { + leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); + } + function isWeekDay(uint timestamp) internal pure returns (bool weekDay) { + weekDay = getDayOfWeek(timestamp) <= DOW_FRI; + } + function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) { + weekEnd = getDayOfWeek(timestamp) >= DOW_SAT; + } + function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) { + (uint year, uint month,) = _daysToDate(timestamp / SECONDS_PER_DAY); + daysInMonth = _getDaysInMonth(year, month); + } + function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) { + if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { + daysInMonth = 31; + } else if (month != 2) { + daysInMonth = 30; + } else { + daysInMonth = _isLeapYear(year) ? 29 : 28; + } + } + // 1 = Monday, 7 = Sunday + function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) { + uint _days = timestamp / SECONDS_PER_DAY; + dayOfWeek = (_days + 3) % 7 + 1; + } + + function getYear(uint timestamp) internal pure returns (uint year) { + (year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function getMonth(uint timestamp) internal pure returns (uint month) { + (,month,) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function getDay(uint timestamp) internal pure returns (uint day) { + (,,day) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function getHour(uint timestamp) internal pure returns (uint hour) { + uint secs = timestamp % SECONDS_PER_DAY; + hour = secs / SECONDS_PER_HOUR; + } + function getMinute(uint timestamp) internal pure returns (uint minute) { + uint secs = timestamp % SECONDS_PER_HOUR; + minute = secs / SECONDS_PER_MINUTE; + } + function getSecond(uint timestamp) internal pure returns (uint second) { + second = timestamp % SECONDS_PER_MINUTE; + } + + function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { + (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); + year += _years; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp >= timestamp); + } + function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { + (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); + month += _months; + year += (month - 1) / 12; + month = (month - 1) % 12 + 1; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp >= timestamp); + } + function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _days * SECONDS_PER_DAY; + require(newTimestamp >= timestamp); + } + function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _hours * SECONDS_PER_HOUR; + require(newTimestamp >= timestamp); + } + function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE; + require(newTimestamp >= timestamp); + } + function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _seconds; + require(newTimestamp >= timestamp); + } + + function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { + (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); + year -= _years; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp <= timestamp); + } + function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { + (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); + uint yearMonth = year * 12 + (month - 1) - _months; + year = yearMonth / 12; + month = yearMonth % 12 + 1; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp <= timestamp); + } + function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _days * SECONDS_PER_DAY; + require(newTimestamp <= timestamp); + } + function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _hours * SECONDS_PER_HOUR; + require(newTimestamp <= timestamp); + } + function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE; + require(newTimestamp <= timestamp); + } + function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _seconds; + require(newTimestamp <= timestamp); + } + + function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) { + require(fromTimestamp <= toTimestamp); + (uint fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); + (uint toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); + _years = toYear - fromYear; + } + function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) { + require(fromTimestamp <= toTimestamp); + (uint fromYear, uint fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); + (uint toYear, uint toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); + _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth; + } + function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) { + require(fromTimestamp <= toTimestamp); + _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY; + } + function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) { + require(fromTimestamp <= toTimestamp); + _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR; + } + function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) { + require(fromTimestamp <= toTimestamp); + _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE; + } + function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) { + require(fromTimestamp <= toTimestamp); + _seconds = toTimestamp - fromTimestamp; + } +} + +// ---------------------------------------------------------------------------- +// Testing BokkyPooBah's DateTime Library +// +// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary +// +// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. +// ---------------------------------------------------------------------------- + +contract TestDateTime { + using BokkyPooBahsDateTimeLibrary for uint; + + uint public nextYear; + + function test() public { + uint today = now; + nextYear = today.addYears(1); + } + + function timestampFromDate(uint year, uint month, uint day) public pure returns (uint timestamp) { + return BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day); + } + function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (uint timestamp) { + return BokkyPooBahsDateTimeLibrary.timestampFromDateTime(year, month, day, hour, minute, second); + } + function timestampToDate(uint timestamp) public pure returns (uint year, uint month, uint day) { + (year, month, day) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); + } + function timestampToDateTime(uint timestamp) public pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { + (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(timestamp); + } + + function isLeapYear(uint timestamp) public pure returns (bool leapYear) { + leapYear = BokkyPooBahsDateTimeLibrary.isLeapYear(timestamp); + } + function _isLeapYear(uint year) public pure returns (bool leapYear) { + leapYear = BokkyPooBahsDateTimeLibrary._isLeapYear(year); + } + function isWeekDay(uint timestamp) public pure returns (bool weekDay) { + weekDay = BokkyPooBahsDateTimeLibrary.isWeekDay(timestamp); + } + function isWeekEnd(uint timestamp) public pure returns (bool weekEnd) { + weekEnd = BokkyPooBahsDateTimeLibrary.isWeekEnd(timestamp); + } + + function getDaysInMonth(uint timestamp) public pure returns (uint daysInMonth) { + daysInMonth = BokkyPooBahsDateTimeLibrary.getDaysInMonth(timestamp); + } + function _getDaysInMonth(uint year, uint month) public pure returns (uint daysInMonth) { + daysInMonth = BokkyPooBahsDateTimeLibrary._getDaysInMonth(year, month); + } + function getDayOfWeek(uint timestamp) public pure returns (uint dayOfWeek) { + dayOfWeek = BokkyPooBahsDateTimeLibrary.getDayOfWeek(timestamp); + } + + function isValidDate(uint year, uint month, uint day) public pure returns (bool valid) { + valid = BokkyPooBahsDateTimeLibrary.isValidDate(year, month, day); + } + function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (bool valid) { + valid = BokkyPooBahsDateTimeLibrary.isValidDateTime(year, month, day, hour, minute, second); + } + + function getYear(uint timestamp) public pure returns (uint year) { + year = BokkyPooBahsDateTimeLibrary.getYear(timestamp); + } + function getMonth(uint timestamp) public pure returns (uint month) { + month = BokkyPooBahsDateTimeLibrary.getMonth(timestamp); + } + function getDay(uint timestamp) public pure returns (uint day) { + day = BokkyPooBahsDateTimeLibrary.getDay(timestamp); + } + function getHour(uint timestamp) public pure returns (uint hour) { + hour = BokkyPooBahsDateTimeLibrary.getHour(timestamp); + } + function getMinute(uint timestamp) public pure returns (uint minute) { + minute = BokkyPooBahsDateTimeLibrary.getMinute(timestamp); + } + function getSecond(uint timestamp) public pure returns (uint second) { + second = BokkyPooBahsDateTimeLibrary.getSecond(timestamp); + } + + function addYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addYears(timestamp, _years); + } + function addMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addMonths(timestamp, _months); + } + function addDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addDays(timestamp, _days); + } + function addHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addHours(timestamp, _hours); + } + function addMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addMinutes(timestamp, _minutes); + } + function addSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addSeconds(timestamp, _seconds); + } + + function subYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subYears(timestamp, _years); + } + function subMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subMonths(timestamp, _months); + } + function subDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subDays(timestamp, _days); + } + function subHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subHours(timestamp, _hours); + } + function subMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subMinutes(timestamp, _minutes); + } + function subSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subSeconds(timestamp, _seconds); + } + + function diffYears(uint fromTimestamp, uint toTimestamp) public pure returns (uint _years) { + _years = BokkyPooBahsDateTimeLibrary.diffYears(fromTimestamp, toTimestamp); + } + function diffMonths(uint fromTimestamp, uint toTimestamp) public pure returns (uint _months) { + _months = BokkyPooBahsDateTimeLibrary.diffMonths(fromTimestamp, toTimestamp); + } + function diffDays(uint fromTimestamp, uint toTimestamp) public pure returns (uint _days) { + _days = BokkyPooBahsDateTimeLibrary.diffDays(fromTimestamp, toTimestamp); + } + function diffHours(uint fromTimestamp, uint toTimestamp) public pure returns (uint _hours) { + _hours = BokkyPooBahsDateTimeLibrary.diffHours(fromTimestamp, toTimestamp); + } + function diffMinutes(uint fromTimestamp, uint toTimestamp) public pure returns (uint _minutes) { + _minutes = BokkyPooBahsDateTimeLibrary.diffMinutes(fromTimestamp, toTimestamp); + } + function diffSeconds(uint fromTimestamp, uint toTimestamp) public pure returns (uint _seconds) { + _seconds = BokkyPooBahsDateTimeLibrary.diffSeconds(fromTimestamp, toTimestamp); + } +} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/images/clocks.png b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/images/clocks.png new file mode 100644 index 0000000000000000000000000000000000000000..419fd1b9763112e7055c70ba6063553b89fbc7a7 GIT binary patch literal 1843439 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≶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 z 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

    LdX~CcOB^bYOTT+ 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

    PY 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

    MP&7{`%G3ox9F@nJ5Gf$AFzx2r1%JgIdD*eBL$> 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 z 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�kAC#czy9mZlbc`r+SgjG*1LdHALttX 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


    16osIiQ9?ygIMlKEQ(8-Nkz{FvZyz)h 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ÊbL| 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

    U72m^{xYmIp@iB!EFGlB>)a&a_aRxJg= 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

    EzO#bP?0B%_g(^uu3%fiN14k|<2H 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 \$contractsdir, + "remapdir:s" => \$remapdir, + "mainsol:s" => \$mainsol, + "outputsol:s" => \$outputsol, + "verbose" => \$verbose, + "help" => \$help) +or die $helptext; + +die $helptext + if defined $help; + +die $helptext + unless defined $mainsol; + +$contractsdir = $DEFAULTCONTRACTSDIR + unless defined $contractsdir; + +if (!defined $outputsol) { + $outputsol = $mainsol; + $outputsol =~ s/\.sol/_flattened\.sol/g; +} + +if (defined $verbose) { + printf "contractsdir: %s\n", $contractsdir; + printf "remapdir : %s\n", defined $remapdir ? $remapdir : "(no remapping)"; + printf "mainsol : %s\n", $mainsol; + printf "outputsol : %s\n", $outputsol +} + +open OUTPUT, ">$outputsol" + or die "Cannot open $outputsol for writing. Stopped"; + +processSol(catfile($contractsdir, $mainsol), 0); + +close OUTPUT + or die "Cannot close $outputsol. Stopped"; + +exit; + + +# ------------------------------------------------------------------------------ +# Process Solidity file +# ------------------------------------------------------------------------------ +sub processSol { + my ($sol, $level) = @_; + if (defined $remapdir) { + my ($splitfrom, $splitto) = split /=/, $remapdir; + # printf "%sSplit %s: %s => %s\n", " " x $level, $remapdir, $splitfrom, $splitto + # if defined $verbose; + if ($sol =~ /$splitfrom/) { + printf "%sRemapping %s\n", " " x $level, $sol + if defined $verbose; + $sol =~ s!$splitfrom!$splitto!; + printf "%s to %s\n", " " x $level, $sol + if defined $verbose; + } + } + my $dir = dirname($sol); + my $file = basename($sol); + $seen{$file} = 1; + printf "%sProcessing %s\n", " " x $level, $sol + if defined $verbose; + + open INPUT, "<$sol" + or die "Cannot open $sol for reading. Stopped"; + my @lines = ; + close INPUT + or die "Cannot close $sol. Stopped"; + + for my $line (@lines) { + chomp $line; + if ($line =~ /^import/) { + my $importfile = $line; + $importfile =~ s/import [\"\']//; + $importfile =~ s/[\"\'];.*$//; + $file = basename($importfile); + if ($seen{$file}) { + printf "%s Already Imported %s\n", " " x $level, catfile($dir, $importfile) + if defined $verbose; + } else { + printf "%s Importing %s\n", " " x $level, catfile($dir, $importfile) + if defined $verbose; + processSol(catfile($dir, $importfile), $level + 1) + } + } else { + if ($level == 0 || !($line =~ /^pragma/)) { + printf OUTPUT "%s\n", $line; + } + } + } +} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/00_runGeth.sh b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/00_runGeth.sh new file mode 100755 index 0000000..bba6e36 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/00_runGeth.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +rm -f ./testchain/geth/chaindata/* + +# geth --datadir ./testchain init genesis.json + +# geth --datadir ./testchain --unlock 0 --password ./testpassword --rpc --rpccorsdomain '*' --rpcport 8646 --rpcapi "eth,net,web3,debug" --port 32323 --mine --minerthreads 1 --maxpeers 0 --targetgaslimit 994712388 console +geth --allow-insecure-unlock --dev --dev.period 1 --datadir ./testchain --rpc --rpccorsdomain '*' --rpcport 8646 --rpcapi "eth,net,web3,debug" --port 32323 --maxpeers 0 --targetgaslimit 994712388 console diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/01_test1.sh b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/01_test1.sh new file mode 100755 index 0000000..e443682 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/01_test1.sh @@ -0,0 +1,605 @@ +#!/bin/bash +# ---------------------------------------------------------------------------------------------- +# Testing the smart contract +# +# Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2017. The MIT Licence. +# ---------------------------------------------------------------------------------------------- + +MODE=${1:-full} + +source settings +echo "---------- Settings ----------" | tee $TEST1OUTPUT +cat ./settings | tee -a $TEST1OUTPUT +echo "" | tee -a $TEST1OUTPUT + +CURRENTTIME=`date +%s` +CURRENTTIMES=`perl -le "print scalar localtime $CURRENTTIME"` +START_DATE=`echo "$CURRENTTIME+45" | bc` +START_DATE_S=`perl -le "print scalar localtime $START_DATE"` +END_DATE=`echo "$CURRENTTIME+60*2" | bc` +END_DATE_S=`perl -le "print scalar localtime $END_DATE"` + +printf "MODE = '$MODE'\n" | tee $TEST1OUTPUT +printf "GETHATTACHPOINT = '$GETHATTACHPOINT'\n" | tee -a $TEST1OUTPUT +printf "PASSWORD = '$PASSWORD'\n" | tee -a $TEST1OUTPUT +printf "SOURCEDIR = '$SOURCEDIR'\n" | tee -a $TEST1OUTPUT +printf "DATETIMELIBSOL = '$DATETIMELIBSOL'\n" | tee -a $TEST1OUTPUT +printf "DATETIMELIBJS = '$DATETIMELIBJS'\n" | tee -a $TEST1OUTPUT +printf "TESTDATETIMESOL = '$TESTDATETIMESOL'\n" | tee -a $TEST1OUTPUT +printf "TESTDATETIMEJS = '$TESTDATETIMEJS'\n" | tee -a $TEST1OUTPUT +printf "DEPLOYMENTDATA = '$DEPLOYMENTDATA'\n" | tee -a $TEST1OUTPUT +printf "TEST1OUTPUT = '$TEST1OUTPUT'\n" | tee -a $TEST1OUTPUT +printf "TEST1RESULTS = '$TEST1RESULTS'\n" | tee -a $TEST1OUTPUT +printf "CURRENTTIME = '$CURRENTTIME' '$CURRENTTIMES'\n" | tee -a $TEST1OUTPUT +printf "START_DATE = '$START_DATE' '$START_DATE_S'\n" | tee -a $TEST1OUTPUT +printf "END_DATE = '$END_DATE' '$END_DATE_S'\n" | tee -a $TEST1OUTPUT + +# Make copy of SOL file and modify start and end times --- +`cp $SOURCEDIR/$DATETIMELIBSOL .` +`cp $SOURCEDIR/$TESTDATETIMESOL .` + +# --- Modify parameters --- +# `perl -pi -e "s/START_DATE \= 1525132800.*$/START_DATE \= $START_DATE; \/\/ $START_DATE_S/" $CROWDSALESOL` +# `perl -pi -e "s/endDate \= 1527811200;.*$/endDate \= $END_DATE; \/\/ $END_DATE_S/" $CROWDSALESOL` + +DIFFS1=`diff $SOURCEDIR/$DATETIMELIBSOL $DATETIMELIBSOL` +echo "--- Differences $SOURCEDIR/$DATETIMELIBSOL $DATETIMELIBSOL ---" | tee -a $TEST1OUTPUT +echo "$DIFFS1" | tee -a $TEST1OUTPUT + +DIFFS1=`diff $SOURCEDIR/$TESTDATETIMESOL $TESTDATETIMESOL` +echo "--- Differences $SOURCEDIR/$TESTDATETIMESOL $TESTDATETIMESOL ---" | tee -a $TEST1OUTPUT +echo "$DIFFS1" | tee -a $TEST1OUTPUT + +solc_0.6.0 --version | tee -a $TEST1OUTPUT + +echo "var dateTimeLibOutput=`solc_0.6.0 --optimize --pretty-json --combined-json abi,bin,interface $DATETIMELIBSOL`;" > $DATETIMELIBJS +echo "var testDateTimeOutput=`solc_0.6.0 --optimize --pretty-json --combined-json abi,bin,interface $TESTDATETIMESOL`;" > $TESTDATETIMEJS +../scripts/solidityFlattener.pl --contractsdir=../contracts --mainsol=$TESTDATETIMESOL --outputsol=$TESTDATETIMEFLATTENED --verbose | tee -a $TEST1OUTPUT + +if [ "$MODE" = "compile" ]; then + echo "Compiling only" + exit 1; +fi + +geth --verbosity 3 attach $GETHATTACHPOINT << EOF | tee -a $TEST1OUTPUT +loadScript("$DATETIMELIBJS"); +loadScript("$TESTDATETIMEJS"); +loadScript("functions.js"); + +var dateTimeLibAbi = JSON.parse(dateTimeLibOutput.contracts["$DATETIMELIBSOL:BokkyPooBahsDateTimeLibrary"].abi); +var dateTimeLibBin = "0x" + dateTimeLibOutput.contracts["$DATETIMELIBSOL:BokkyPooBahsDateTimeLibrary"].bin; +var testDateTimeAbi = JSON.parse(testDateTimeOutput.contracts["$TESTDATETIMESOL:TestDateTime"].abi); +var testDateTimeBin = "0x" + testDateTimeOutput.contracts["$TESTDATETIMESOL:TestDateTime"].bin; + +console.log("DATA: dateTimeLibAbi=" + JSON.stringify(dateTimeLibAbi)); +console.log("DATA: dateTimeLibBin=" + JSON.stringify(dateTimeLibBin)); +console.log("DATA: testDateTimeAbi=" + JSON.stringify(testDateTimeAbi)); +console.log("DATA: testDateTimeBin=" + JSON.stringify(testDateTimeBin)); + +unlockAccounts("$PASSWORD"); +printBalances(); +console.log("RESULT: "); + + +// ----------------------------------------------------------------------------- +var deployDateTimeLibMessage = "Deploy DateTime Library"; +// ----------------------------------------------------------------------------- +console.log("RESULT: ----- " + deployDateTimeLibMessage + " -----"); +var dateTimeLibContract = web3.eth.contract(dateTimeLibAbi); +// console.log(JSON.stringify(dateTimeLibContract)); +var dateTimeLibTx = null; +var dateTimeLibAddress = null; +var currentBlock = eth.blockNumber; +var dateTimeLib = dateTimeLibContract.new({from: contractOwnerAccount, data: dateTimeLibBin, gas: 6000000, gasPrice: defaultGasPrice}, + function(e, contract) { + if (!e) { + if (!contract.address) { + dateTimeLibTx = contract.transactionHash; + } else { + dateTimeLibAddress = contract.address; + addAccount(dateTimeLibAddress, "DateTime Library"); + console.log("DATA: var dateTimeLibAddress=\"" + dateTimeLibAddress + "\";"); + console.log("DATA: var dateTimeLibAbi=" + JSON.stringify(dateTimeLibAbi) + ";"); + console.log("DATA: var dateTimeLib=eth.contract(dateTimeLibAbi).at(dateTimeLibAddress);"); + } + } + } +); +while (txpool.status.pending > 0) { +} +printBalances(); +failIfTxStatusError(dateTimeLibTx, deployDateTimeLibMessage); +printTxData("dateTimeLibTx", dateTimeLibTx); +console.log("RESULT: "); + + +// ----------------------------------------------------------------------------- +var testDateTimeMessage = "Deploy TestDateTime Contract"; +// ----------------------------------------------------------------------------- +console.log("RESULT: ---------- " + testDateTimeMessage + " ----------"); +// console.log("RESULT: testDateTimeBin='" + testDateTimeBin + "'"); +var newTestDateTimeBin = testDateTimeBin.replace(/__BokkyPooBahsDateTimeLibrary\.sol\:Bokk__/g, dateTimeLibAddress.substring(2, 42)); +// console.log("RESULT: newTestDateTimeBin='" + newTestDateTimeBin + "'"); +var testDateTimeContract = web3.eth.contract(testDateTimeAbi); +var testDateTimeTx = null; +var testDateTimeAddress = null; +var testDateTime = testDateTimeContract.new({from: contractOwnerAccount, data: newTestDateTimeBin, gas: 6000000, gasPrice: defaultGasPrice}, + function(e, contract) { + if (!e) { + if (!contract.address) { + testDateTimeTx = contract.transactionHash; + } else { + testDateTimeAddress = contract.address; + addAccount(testDateTimeAddress, "TestDateTime"); + console.log("DATA: var testDateTimeAddress=\"" + testDateTimeAddress + "\";"); + console.log("DATA: var testDateTimeAbi=" + JSON.stringify(testDateTimeAbi) + ";"); + console.log("DATA: var testDateTime=eth.contract(testDateTimeAbi).at(testDateTimeAddress);"); + console.log("DATA: console.log(\"testDateTime=\" + JSON.stringify(testDateTime));"); + } + } + } +); +while (txpool.status.pending > 0) { +} +printBalances(); +failIfTxStatusError(testDateTimeTx, testDateTimeMessage); +printTxData("testDateTimeAddress=" + testDateTimeAddress, testDateTimeTx); +console.log("RESULT: "); + +var failureDetected = false; +var timestamp; +var newTimestamp; +var expectedTimestamp; +var fromTimestamp; +var toTimestamp; + +if ("$MODE" == "full") { + console.log("RESULT: ---------- Test isLeapYear ----------"); + timestamp = testDateTime.timestampFromDateTime.call(2000, 5, 24, 1, 2, 3); + if (!assert(testDateTime.isLeapYear.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a leap year")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2100, 5, 24, 1, 2, 3); + if (!assert(!testDateTime.isLeapYear.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a not leap year")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2104, 5, 24, 1, 2, 3); + if (!assert(testDateTime.isLeapYear.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a leap year")) { + failureDetected = true; + } + console.log("RESULT: "); +} + +if ("$MODE" == "full") { + console.log("RESULT: ---------- Test isValidDate and isValidDateTime.call ----------"); + if (!assert(testDateTime.isValidDate.call(1969, 1, 1) == false, "testDateTime.isValidDate.call(1969, 1, 1) is false")) { + failureDetected = true; + } + if (!assert(testDateTime.isValidDate.call(1970, 1, 1) == true, "testDateTime.isValidDate.call(1970, 1, 1) is true")) { + failureDetected = true; + } + if (!assert(testDateTime.isValidDate.call(2000, 2, 29) == true, "testDateTime.isValidDate.call(2000, 2, 29) is true")) { + failureDetected = true; + } + if (!assert(testDateTime.isValidDate.call(2001, 2, 29) == false, "testDateTime.isValidDate.call(2001, 2, 29) is false")) { + failureDetected = true; + } + if (!assert(testDateTime.isValidDate.call(2001, 0, 1) == false, "testDateTime.isValidDate.call(2001, 0, 1) is false")) { + failureDetected = true; + } + if (!assert(testDateTime.isValidDate.call(2001, 1, 0) == false, "testDateTime.isValidDate.call(2001, 1, 0) is false")) { + failureDetected = true; + } + if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 0, 0, 0) == true, "testDateTime.isValidDateTime.call(2000, 2, 29, 0, 0, 0) is true")) { + failureDetected = true; + } + if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 1) == true, "testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 1) is true")) { + failureDetected = true; + } + if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 23, 1, 1) == true, "testDateTime.isValidDateTime.call(2000, 2, 29, 23, 1, 1) is true")) { + failureDetected = true; + } + if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 24, 1, 1) == false, "testDateTime.isValidDateTime.call(2000, 2, 29, 24, 1, 1) is false")) { + failureDetected = true; + } + if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 1, 59, 1) == true, "testDateTime.isValidDateTime.call(2000, 2, 29, 1, 59, 1) is true")) { + failureDetected = true; + } + if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 1, 60, 1) == false, "testDateTime.isValidDateTime.call(2000, 2, 29, 1, 60, 1) is false")) { + failureDetected = true; + } + if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 59) == true, "testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 59) is true")) { + failureDetected = true; + } + if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 60) == false, "testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 60) is false")) { + failureDetected = true; + } + console.log("RESULT: "); +} + +if ("$MODE" == "full") { + console.log("RESULT: ---------- Test _isLeapYear ----------"); + if (!assert(testDateTime._isLeapYear.call(2000), "2000 is a leap year")) { + failureDetected = true; + } + if (!assert(!testDateTime._isLeapYear.call(2100), "2100 is a not leap year")) { + failureDetected = true; + } + if (!assert(testDateTime._isLeapYear.call(2104), "2104 is a leap year")) { + failureDetected = true; + } + console.log("RESULT: "); +} + +if ("$MODE" == "full") { + console.log("RESULT: ---------- Test isWeekDay ----------"); + timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 24, 1, 2, 3); + if (!assert(testDateTime.isWeekDay.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a week day")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 25, 1, 2, 3); + if (!assert(testDateTime.isWeekDay.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a week day")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 26, 1, 2, 3); + if (!assert(!testDateTime.isWeekDay.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a not week day")) { + failureDetected = true; + } + console.log("RESULT: "); +} + +if ("$MODE" == "full") { + console.log("RESULT: ---------- Test isWeekEnd ----------"); + timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 24, 1, 2, 3); + if (!assert(!testDateTime.isWeekEnd.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a not a week end")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 25, 1, 2, 3); + if (!assert(!testDateTime.isWeekEnd.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a not a week end")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 26, 1, 2, 3); + if (!assert(testDateTime.isWeekEnd.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a week end")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 27, 1, 2, 3); + if (!assert(testDateTime.isWeekEnd.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a week end")) { + failureDetected = true; + } + console.log("RESULT: "); +} + + +if ("$MODE" == "full") { + console.log("RESULT: ---------- Test getDaysInMonth ----------"); + timestamp = testDateTime.timestampFromDateTime.call(2000, 1, 24, 1, 2, 3); + if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 31, testDateTime.timestampToDateTime.call(timestamp) + " has 31 days")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2000, 2, 24, 1, 2, 3); + if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 29, testDateTime.timestampToDateTime.call(timestamp) + " has 29 days")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2001, 2, 24, 1, 2, 3); + if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 28, testDateTime.timestampToDateTime.call(timestamp) + " has 28 days")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2000, 3, 24, 1, 2, 3); + if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 31, testDateTime.timestampToDateTime.call(timestamp) + " has 31 days")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2000, 4, 24, 1, 2, 3); + if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 30, testDateTime.timestampToDateTime.call(timestamp) + " has 30 days")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2000, 5, 24, 1, 2, 3); + if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 31, testDateTime.timestampToDateTime.call(timestamp) + " has 31 days")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2000, 6, 24, 1, 2, 3); + if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 30, testDateTime.timestampToDateTime.call(timestamp) + " has 30 days")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2000, 7, 24, 1, 2, 3); + if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 31, testDateTime.timestampToDateTime.call(timestamp) + " has 31 days")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2000, 8, 24, 1, 2, 3); + if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 31, testDateTime.timestampToDateTime.call(timestamp) + " has 31 days")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2000, 9, 24, 1, 2, 3); + if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 30, testDateTime.timestampToDateTime.call(timestamp) + " has 30 days")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2000, 10, 24, 1, 2, 3); + if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 31, testDateTime.timestampToDateTime.call(timestamp) + " has 31 days")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2000, 11, 24, 1, 2, 3); + if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 30, testDateTime.timestampToDateTime.call(timestamp) + " has 30 days")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2000, 12, 24, 1, 2, 3); + if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 31, testDateTime.timestampToDateTime.call(timestamp) + " has 31 days")) { + failureDetected = true; + } + console.log("RESULT: "); +} + + +if ("$MODE" == "full") { + console.log("RESULT: ---------- Test _getDaysInMonth ----------"); + if (!assert(testDateTime._getDaysInMonth.call(2000, 1) == 31, "2000/01 has 31 days")) { + failureDetected = true; + } + if (!assert(testDateTime._getDaysInMonth.call(2000, 2) == 29, "2000/02 has 29 days")) { + failureDetected = true; + } + if (!assert(testDateTime._getDaysInMonth.call(2001, 2) == 28, "2001/02 has 28 days")) { + failureDetected = true; + } + if (!assert(testDateTime._getDaysInMonth.call(2000, 3) == 31, "2000/03 has 31 days")) { + failureDetected = true; + } + if (!assert(testDateTime._getDaysInMonth.call(2000, 4) == 30, "2000/04 has 30 days")) { + failureDetected = true; + } + if (!assert(testDateTime._getDaysInMonth.call(2000, 5) == 31, "2000/05 has 31 days")) { + failureDetected = true; + } + if (!assert(testDateTime._getDaysInMonth.call(2000, 6) == 30, "2000/06 has 30 days")) { + failureDetected = true; + } + if (!assert(testDateTime._getDaysInMonth.call(2000, 7) == 31, "2000/07 has 31 days")) { + failureDetected = true; + } + if (!assert(testDateTime._getDaysInMonth.call(2000, 8) == 31, "2000/08 has 31 days")) { + failureDetected = true; + } + if (!assert(testDateTime._getDaysInMonth.call(2000, 9) == 30, "2000/09 has 30 days")) { + failureDetected = true; + } + if (!assert(testDateTime._getDaysInMonth.call(2000, 10) == 31, "2000/10 has 31 days")) { + failureDetected = true; + } + if (!assert(testDateTime._getDaysInMonth.call(2000, 11) == 30, "2000/11 has 30 days")) { + failureDetected = true; + } + if (!assert(testDateTime._getDaysInMonth.call(2000, 12) == 31, "2000/12 has 31 days")) { + failureDetected = true; + } + console.log("RESULT: "); +} + + +if ("$MODE" == "full") { + console.log("RESULT: ---------- Test getDayOfWeek ----------"); + timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 21, 1, 2, 3); + if (!assert(testDateTime.getDayOfWeek.call(timestamp) == 1, testDateTime.timestampToDateTime.call(timestamp) + " is 1 Monday")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 24, 1, 2, 3); + if (!assert(testDateTime.getDayOfWeek.call(timestamp) == 4, testDateTime.timestampToDateTime.call(timestamp) + " is 4 Thursday")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 26, 1, 2, 3); + if (!assert(testDateTime.getDayOfWeek.call(timestamp) == 6, testDateTime.timestampToDateTime.call(timestamp) + " is 6 Saturday")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 27, 1, 2, 3); + if (!assert(testDateTime.getDayOfWeek.call(timestamp) == 7, testDateTime.timestampToDateTime.call(timestamp) + " is 7 Sunday")) { + failureDetected = true; + } + console.log("RESULT: "); +} + + +if ("$MODE" == "full") { + console.log("RESULT: ---------- Test get* ----------"); + timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 21, 1, 2, 3); + if (!assert(testDateTime.getYear.call(timestamp) == 2018, testDateTime.timestampToDateTime.call(timestamp) + " year is 2018")) { + failureDetected = true; + } + if (!assert(testDateTime.getMonth.call(timestamp) == 5, testDateTime.timestampToDateTime.call(timestamp) + " month is 5 May")) { + failureDetected = true; + } + if (!assert(testDateTime.getDay.call(timestamp) == 21, testDateTime.timestampToDateTime.call(timestamp) + " day is 21")) { + failureDetected = true; + } + if (!assert(testDateTime.getHour.call(timestamp) == 1, testDateTime.timestampToDateTime.call(timestamp) + " hour is 1")) { + failureDetected = true; + } + if (!assert(testDateTime.getMinute.call(timestamp) == 2, testDateTime.timestampToDateTime.call(timestamp) + " minute is 2")) { + failureDetected = true; + } + if (!assert(testDateTime.getSecond.call(timestamp) == 3, testDateTime.timestampToDateTime.call(timestamp) + " second is 3")) { + failureDetected = true; + } + console.log("RESULT: "); +} + +if ("$MODE" == "full") { + console.log("RESULT: ---------- Test add{Years|Months|Days|Hours|Minutes|Seconds} ----------"); + timestamp = testDateTime.timestampFromDateTime.call(2000, 2, 29, 1, 2, 3); + newTimestamp = testDateTime.addYears.call(timestamp, 3); + expectedTimestamp = testDateTime.timestampFromDateTime.call(2003, 2, 28, 1, 2, 3); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 3 years is 2003/02/28 01:02:03")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2018, 12, 31, 2, 3, 4); + newTimestamp = testDateTime.addYears.call(timestamp, 30); + expectedTimestamp = testDateTime.timestampFromDateTime.call(2048, 12, 31, 2, 3, 4); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 30 years is 2048/12/31 02:03:04")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2000, 1, 31, 1, 2, 3); + newTimestamp = testDateTime.addMonths.call(timestamp, 37); + expectedTimestamp = testDateTime.timestampFromDateTime.call(2003, 2, 28, 1, 2, 3); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 37 months is 2003/02/28 01:02:03")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2018, 12, 1, 2, 3, 4); + newTimestamp = testDateTime.addMonths.call(timestamp, 362); + expectedTimestamp = testDateTime.timestampFromDateTime.call(2049, 2, 1, 2, 3, 4); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 362 months is 2049/02/01 02:03:04")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2017, 1, 31, 1, 2, 3); + newTimestamp = testDateTime.addDays.call(timestamp, 37532); + expectedTimestamp = testDateTime.timestampFromDateTime.call(2119, 11, 5, 1, 2, 3); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 37,532 days is 2119/11/05 01:02:03")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2017, 1, 31, 1, 2, 3); + newTimestamp = testDateTime.addHours.call(timestamp, 900768); + expectedTimestamp = testDateTime.timestampFromDateTime.call(2119, 11, 5, 1, 2, 3); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 900,768 hours is 2119/11/05 01:02:03")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2017, 1, 31, 1, 2, 3); + newTimestamp = testDateTime.addMinutes.call(timestamp, 781920); + expectedTimestamp = testDateTime.timestampFromDateTime.call(2018, 7, 28, 1, 2, 3); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 781,920 minutes is 2018/07/28 01:02:03")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2017, 1, 31, 1, 2, 3); + newTimestamp = testDateTime.addSeconds.call(timestamp, "461548800"); + expectedTimestamp = testDateTime.timestampFromDateTime.call(2031, 9, 17, 1, 2, 3); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 461,548,800 seconds is 2031/09/17 01:02:03")) { + failureDetected = true; + } + console.log("RESULT: "); +} + +if ("$MODE" == "full") { + console.log("RESULT: ---------- Test sub{Years|Months|Days|Hours|Minutes|Seconds} ----------"); + timestamp = testDateTime.timestampFromDateTime.call(2000, 2, 29, 1, 2, 3); + newTimestamp = testDateTime.subYears.call(timestamp, 3); + expectedTimestamp = testDateTime.timestampFromDateTime.call(1997, 2, 28, 1, 2, 3); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " - 3 years is 1997/02/28 01:02:03")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2000, 2, 29, 1, 2, 3); + newTimestamp = testDateTime.subMonths.call(timestamp, 37); + expectedTimestamp = testDateTime.timestampFromDateTime.call(1997, 1, 29, 1, 2, 3); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " - 37 months is 1997/01/29 01:02:03")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2013, 1, 1, 1, 2, 3); + newTimestamp = testDateTime.subDays.call(timestamp, 3756); + expectedTimestamp = testDateTime.timestampFromDateTime.call(2002, 9, 20, 1, 2, 3); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " - 3,756 days is 2002/09/20 01:02:03")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2013, 1, 1, 1, 2, 3); + newTimestamp = testDateTime.subHours.call(timestamp, 3756 * 24); + expectedTimestamp = testDateTime.timestampFromDateTime.call(2002, 9, 20, 1, 2, 3); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " - 3,756 * 24 hours is 2002/09/20 01:02:03")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2015, 7, 15, 1, 2, 3); + newTimestamp = testDateTime.subHours.call(timestamp, "223776"); + expectedTimestamp = testDateTime.timestampFromDateTime.call(1990, 1, 3, 1, 2, 3); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " - 223,776 hours is 1990/01/03 01:02:03")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2018, 3, 1, 2, 3, 4); + newTimestamp = testDateTime.subMinutes.call(timestamp, "21600000"); + expectedTimestamp = testDateTime.timestampFromDateTime.call(1977, 2, 4, 2, 3, 4); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " - 21,600,000 minutes is 1977/02/04 02:03:04")) { + failureDetected = true; + } + timestamp = testDateTime.timestampFromDateTime.call(2020, 3, 19, 3, 4, 5); + newTimestamp = testDateTime.subSeconds.call(timestamp, "788227200"); + expectedTimestamp = testDateTime.timestampFromDateTime.call(1995, 3, 28, 3, 4, 5); + if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " - 788,227,200 seconds is 1995/03/28 03:04:05")) { + failureDetected = true; + } + console.log("RESULT: "); +} + +if ("$MODE" == "full") { + console.log("RESULT: ---------- Test diff{Years|Months|Days|Hours|Minutes|Seconds} ----------"); + fromTimestamp = testDateTime.timestampFromDateTime.call(2017, 10, 21, 1, 2, 3); + console.log("RESULT: fromTimestamp=" + fromTimestamp + " " + testDateTime.timestampToDateTime.call(fromTimestamp)); + toTimestamp = testDateTime.timestampFromDateTime.call(2019, 7, 18, 4, 5, 6); + console.log("RESULT: toTimestamp=" + toTimestamp + " " + testDateTime.timestampToDateTime.call(toTimestamp)); + + if (!assert(testDateTime.diffYears.call(fromTimestamp, toTimestamp) == 2, testDateTime.timestampToDateTime.call(fromTimestamp) + " to " + testDateTime.timestampToDateTime.call(toTimestamp) + " has 2 years diff")) { + failureDetected = true; + } + if (!assert(testDateTime.diffMonths.call(fromTimestamp, toTimestamp) == 21, testDateTime.timestampToDateTime.call(fromTimestamp) + " to " + testDateTime.timestampToDateTime.call(toTimestamp) + " has 21 months diff")) { + failureDetected = true; + } + if (!assert(testDateTime.diffDays.call(fromTimestamp, toTimestamp) == 635, testDateTime.timestampToDateTime.call(fromTimestamp) + " to " + testDateTime.timestampToDateTime.call(toTimestamp) + " has 635 days diff")) { + failureDetected = true; + } + if (!assert(testDateTime.diffHours.call(fromTimestamp, toTimestamp) == 15243, testDateTime.timestampToDateTime.call(fromTimestamp) + " to " + testDateTime.timestampToDateTime.call(toTimestamp) + " has 15,243 hours diff")) { + failureDetected = true; + } + if (!assert(testDateTime.diffMinutes.call(fromTimestamp, toTimestamp) == 914583, testDateTime.timestampToDateTime.call(fromTimestamp) + " to " + testDateTime.timestampToDateTime.call(toTimestamp) + " has 914,583 minutes diff")) { + failureDetected = true; + } + if (!assert(testDateTime.diffSeconds.call(fromTimestamp, toTimestamp) == 54874983, testDateTime.timestampToDateTime.call(fromTimestamp) + " to " + testDateTime.timestampToDateTime.call(toTimestamp) + " has 54,874,983 seconds diff")) { + failureDetected = true; + } + console.log("RESULT: "); +} + +if ("$MODE" == "full") { + console.log("RESULT: ---------- Test timestampToDateTime.call(...) and timestampFromDateTime.call(...) against JavaScript Date ----------"); + var now = new Date()/1000; + + var fromDate = 0; + // Year 2345 + var toDate = new Date()/1000 + 328 * 365 * 24 * 60 * 60; + // 9 weeks + // var step = 9 * 7 * 24 * 60 * 60; + // 1 year + var step = 365 * 24 * 60 * 60; + + var j = 0; + for (var i = fromDate; i <= toDate; i = parseInt(i) + step) { + j = parseInt(j * 999991) + 48611; + if (j > 365 * 24 * 60 * 60) { + j = j - 365 * 24 * 60 * 60; + } + i = parseInt(i) + j % 999991; + var fromTimestamp = testDateTime.timestampToDateTime.call(i); + var toTimestamp = testDateTime.timestampFromDateTime.call(fromTimestamp[0], fromTimestamp[1], fromTimestamp[2], fromTimestamp[3], fromTimestamp[4], fromTimestamp[5]); + var jsDate = new Date(i * 1000); + console.log("RESULT: timestampToDateTime.call(" + i + ")=" + JSON.stringify(fromTimestamp)); + console.log("RESULT: timestampFromDateTime.call(" + JSON.stringify(fromTimestamp) + ")=" + toTimestamp); + console.log("RESULT: jsDate(" + i + ")=" + jsDate.getUTCFullYear() + "/" + (parseInt(jsDate.getUTCMonth()) + 1) + "/" + jsDate.getUTCDate() + " " + + jsDate.getUTCHours() + ":" + jsDate.getUTCMinutes() + ":" + jsDate.getUTCSeconds()); + + if (jsDate.getUTCFullYear() == fromTimestamp[0] && parseInt(jsDate.getUTCMonth() + 1) == fromTimestamp[1] && jsDate.getUTCDate() == fromTimestamp[2] && + jsDate.getUTCHours() == fromTimestamp[3] && jsDate.getUTCMinutes() == fromTimestamp[4] && jsDate.getUTCSeconds() == fromTimestamp[5]) { + console.log("RESULT: PASS jsDate matches"); + } else { + console.log("RESULT: FAIL jsDate does not match"); + failureDetected = true; + } + if (i == toTimestamp) { + console.log("RESULT: PASS timestampToDateTime.call(" + i + ") => timestampFromDateTime.call(...) matches"); + } else { + console.log("RESULT: FAIL timestampToDateTime.call(" + i + ") => timestampFromDateTime.call(...) does not match"); + failureDetected = true; + } + console.log("RESULT: "); + } +} + +if (!failureDetected) { + console.log("RESULT: ---------- PASS - no failures detected ----------"); +} else { + console.log("RESULT: ---------- FAIL - some failures detected ----------"); +} + + +EOF +grep "DATA: " $TEST1OUTPUT | sed "s/DATA: //" > $DEPLOYMENTDATA +cat $DEPLOYMENTDATA +grep "RESULT: " $TEST1OUTPUT | sed "s/RESULT: //" > $TEST1RESULTS +cat $TEST1RESULTS diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/02_attachGeth.sh b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/02_attachGeth.sh new file mode 100755 index 0000000..52f2307 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/02_attachGeth.sh @@ -0,0 +1,9 @@ +#!/bin/sh + + +echo "Execute the following command to load the latest deployed contracts"; +echo "" +echo "loadScript(\"deploymentData.js\");" +echo "" + +geth attach ipc:./testchain/geth.ipc diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.js b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.js new file mode 100644 index 0000000..0cba4f1 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.js @@ -0,0 +1,11 @@ +var dateTimeLibOutput={ + "contracts": + { + "BokkyPooBahsDateTimeLibrary.sol:BokkyPooBahsDateTimeLibrary": + { + "abi": "[]", + "bin": "60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122075d49f0ac9a443fac8bb202f0adb9e02ed12cbbf6d4d258fcb57548a1e88719064736f6c63430006000033" + } + }, + "version": "0.6.0+commit.26b70077.Darwin.appleclang" +}; diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.sol b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.sol new file mode 100644 index 0000000..fb16487 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.sol @@ -0,0 +1,300 @@ +pragma solidity ^0.6.0; + +// ---------------------------------------------------------------------------- +// BokkyPooBah's DateTime Library v1.01 +// +// A gas-efficient Solidity date and time library +// +// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary +// +// Tested date range 1970/01/01 to 2345/12/31 +// +// Conventions: +// Unit | Range | Notes +// :-------- |:-------------:|:----- +// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC +// year | 1970 ... 2345 | +// month | 1 ... 12 | +// day | 1 ... 31 | +// hour | 0 ... 23 | +// minute | 0 ... 59 | +// second | 0 ... 59 | +// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday +// +// +// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. +// ---------------------------------------------------------------------------- + +library BokkyPooBahsDateTimeLibrary { + + uint constant SECONDS_PER_DAY = 24 * 60 * 60; + uint constant SECONDS_PER_HOUR = 60 * 60; + uint constant SECONDS_PER_MINUTE = 60; + int constant OFFSET19700101 = 2440588; + + uint constant DOW_MON = 1; + uint constant DOW_TUE = 2; + uint constant DOW_WED = 3; + uint constant DOW_THU = 4; + uint constant DOW_FRI = 5; + uint constant DOW_SAT = 6; + uint constant DOW_SUN = 7; + + // ------------------------------------------------------------------------ + // Calculate the number of days from 1970/01/01 to year/month/day using + // the date conversion algorithm from + // http://aa.usno.navy.mil/faq/docs/JD_Formula.php + // and subtracting the offset 2440588 so that 1970/01/01 is day 0 + // + // days = day + // - 32075 + // + 1461 * (year + 4800 + (month - 14) / 12) / 4 + // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 + // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 + // - offset + // ------------------------------------------------------------------------ + function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) { + require(year >= 1970); + int _year = int(year); + int _month = int(month); + int _day = int(day); + + int __days = _day + - 32075 + + 1461 * (_year + 4800 + (_month - 14) / 12) / 4 + + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12 + - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4 + - OFFSET19700101; + + _days = uint(__days); + } + + // ------------------------------------------------------------------------ + // Calculate year/month/day from the number of days since 1970/01/01 using + // the date conversion algorithm from + // http://aa.usno.navy.mil/faq/docs/JD_Formula.php + // and adding the offset 2440588 so that 1970/01/01 is day 0 + // + // int L = days + 68569 + offset + // int N = 4 * L / 146097 + // L = L - (146097 * N + 3) / 4 + // year = 4000 * (L + 1) / 1461001 + // L = L - 1461 * year / 4 + 31 + // month = 80 * L / 2447 + // dd = L - 2447 * month / 80 + // L = month / 11 + // month = month + 2 - 12 * L + // year = 100 * (N - 49) + year + L + // ------------------------------------------------------------------------ + function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) { + int __days = int(_days); + + int L = __days + 68569 + OFFSET19700101; + int N = 4 * L / 146097; + L = L - (146097 * N + 3) / 4; + int _year = 4000 * (L + 1) / 1461001; + L = L - 1461 * _year / 4 + 31; + int _month = 80 * L / 2447; + int _day = L - 2447 * _month / 80; + L = _month / 11; + _month = _month + 2 - 12 * L; + _year = 100 * (N - 49) + _year + L; + + year = uint(_year); + month = uint(_month); + day = uint(_day); + } + + function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) { + timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; + } + function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) { + timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second; + } + function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) { + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function timestampToDateTime(uint timestamp) internal pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { + (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); + uint secs = timestamp % SECONDS_PER_DAY; + hour = secs / SECONDS_PER_HOUR; + secs = secs % SECONDS_PER_HOUR; + minute = secs / SECONDS_PER_MINUTE; + second = secs % SECONDS_PER_MINUTE; + } + + function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) { + if (year >= 1970 && month > 0 && month <= 12) { + uint daysInMonth = _getDaysInMonth(year, month); + if (day > 0 && day <= daysInMonth) { + valid = true; + } + } + } + function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) { + if (isValidDate(year, month, day)) { + if (hour < 24 && minute < 60 && second < 60) { + valid = true; + } + } + } + function isLeapYear(uint timestamp) internal pure returns (bool leapYear) { + (uint year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); + leapYear = _isLeapYear(year); + } + function _isLeapYear(uint year) internal pure returns (bool leapYear) { + leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); + } + function isWeekDay(uint timestamp) internal pure returns (bool weekDay) { + weekDay = getDayOfWeek(timestamp) <= DOW_FRI; + } + function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) { + weekEnd = getDayOfWeek(timestamp) >= DOW_SAT; + } + function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) { + (uint year, uint month,) = _daysToDate(timestamp / SECONDS_PER_DAY); + daysInMonth = _getDaysInMonth(year, month); + } + function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) { + if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { + daysInMonth = 31; + } else if (month != 2) { + daysInMonth = 30; + } else { + daysInMonth = _isLeapYear(year) ? 29 : 28; + } + } + // 1 = Monday, 7 = Sunday + function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) { + uint _days = timestamp / SECONDS_PER_DAY; + dayOfWeek = (_days + 3) % 7 + 1; + } + + function getYear(uint timestamp) internal pure returns (uint year) { + (year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function getMonth(uint timestamp) internal pure returns (uint month) { + (,month,) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function getDay(uint timestamp) internal pure returns (uint day) { + (,,day) = _daysToDate(timestamp / SECONDS_PER_DAY); + } + function getHour(uint timestamp) internal pure returns (uint hour) { + uint secs = timestamp % SECONDS_PER_DAY; + hour = secs / SECONDS_PER_HOUR; + } + function getMinute(uint timestamp) internal pure returns (uint minute) { + uint secs = timestamp % SECONDS_PER_HOUR; + minute = secs / SECONDS_PER_MINUTE; + } + function getSecond(uint timestamp) internal pure returns (uint second) { + second = timestamp % SECONDS_PER_MINUTE; + } + + function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { + (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); + year += _years; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp >= timestamp); + } + function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { + (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); + month += _months; + year += (month - 1) / 12; + month = (month - 1) % 12 + 1; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp >= timestamp); + } + function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _days * SECONDS_PER_DAY; + require(newTimestamp >= timestamp); + } + function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _hours * SECONDS_PER_HOUR; + require(newTimestamp >= timestamp); + } + function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE; + require(newTimestamp >= timestamp); + } + function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp + _seconds; + require(newTimestamp >= timestamp); + } + + function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { + (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); + year -= _years; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp <= timestamp); + } + function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { + (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); + uint yearMonth = year * 12 + (month - 1) - _months; + year = yearMonth / 12; + month = yearMonth % 12 + 1; + uint daysInMonth = _getDaysInMonth(year, month); + if (day > daysInMonth) { + day = daysInMonth; + } + newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; + require(newTimestamp <= timestamp); + } + function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _days * SECONDS_PER_DAY; + require(newTimestamp <= timestamp); + } + function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _hours * SECONDS_PER_HOUR; + require(newTimestamp <= timestamp); + } + function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE; + require(newTimestamp <= timestamp); + } + function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { + newTimestamp = timestamp - _seconds; + require(newTimestamp <= timestamp); + } + + function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) { + require(fromTimestamp <= toTimestamp); + (uint fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); + (uint toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); + _years = toYear - fromYear; + } + function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) { + require(fromTimestamp <= toTimestamp); + (uint fromYear, uint fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); + (uint toYear, uint toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); + _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth; + } + function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) { + require(fromTimestamp <= toTimestamp); + _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY; + } + function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) { + require(fromTimestamp <= toTimestamp); + _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR; + } + function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) { + require(fromTimestamp <= toTimestamp); + _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE; + } + function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) { + require(fromTimestamp <= toTimestamp); + _seconds = toTimestamp - fromTimestamp; + } +} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/README.md b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/README.md new file mode 100644 index 0000000..e9f9bc8 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/README.md @@ -0,0 +1,56 @@ +# Contract - Testing + +
    + +
    + +# Table of contents + +* [Requirements](#requirements) +* [Executing The Tests](#executing-the-tests) +* [Notes](#notes) + +
    + +
    + +# Requirements + +* The tests works on OS/X. Should work in Linux. May work in Windows with Cygwin +* Geth/v1.9.9-stable-01744997/darwin-amd64/go1.13.5 running with the Byzantium fork switched on +* Solc 0.6.0+commit.26b70077.Darwin.appleclang + +
    + +
    + +# Executing The Tests + +* Run `geth` in dev mode + + ./00_runGeth.sh + +* Run the test in [01_test1.sh](01_test1.sh) + + ./01_test1.sh + +* See [test1results.txt](test1results.txt) for the results and [test1output.txt](test1output.txt) for the full output. + +
    + +
    + +# Notes + +* The tests were conducted using bash shell scripts running Geth/v1.9.9-stable-01744997/darwin-amd64/go1.13.5 JavaScript commands +* The smart contracts were compiled using Solidity 0.6.0+commit.26b70077.Darwin.appleclang +* The test script can be found in [01_test1.sh](01_test1.sh) +* The test results can be found in [test1results.txt](test1results.txt) with details in [test1output.txt](test1output.txt) +* The test can be run on OS/X, should run on Linux and may run on Windows with Cygwin +* The [genesis.json](genesis.json) allocates ethers to the test accounts, and specifies a high block gas limit to accommodate many transactions in the same block +* The [00_runGeth.sh](00_runGeth.sh) scripts starts `geth` with the parameter `--targetgaslimit 994712388` to keep the high block gas limit +* The reasons for using the test environment as listed above, instead of truffles/testrpc are: + * The test are conducted using the actual blockchain client software as is running on Mainnet and not just a mock environment like testrpc + * It is easy to change parameters like dates, addresses or blocknumbers using the Unix search/replace tools + * There have been issues in the part with version incompatibility between testrpc and solidity, i.e., version mismatches + * The intermediate and key results are all saved to later viewing diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.js b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.js new file mode 100644 index 0000000..5d7ac27 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.js @@ -0,0 +1,16 @@ +var testDateTimeOutput={ + "contracts": + { + "BokkyPooBahsDateTimeLibrary.sol:BokkyPooBahsDateTimeLibrary": + { + "abi": "[]", + "bin": "60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122075d49f0ac9a443fac8bb202f0adb9e02ed12cbbf6d4d258fcb57548a1e88719064736f6c63430006000033" + }, + "TestDateTime.sol:TestDateTime": + { + "abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"}],\"name\":\"_getDaysInMonth\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"daysInMonth\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"}],\"name\":\"_isLeapYear\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"leapYear\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_days\",\"type\":\"uint256\"}],\"name\":\"addDays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_hours\",\"type\":\"uint256\"}],\"name\":\"addHours\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minutes\",\"type\":\"uint256\"}],\"name\":\"addMinutes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_months\",\"type\":\"uint256\"}],\"name\":\"addMonths\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_seconds\",\"type\":\"uint256\"}],\"name\":\"addSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_years\",\"type\":\"uint256\"}],\"name\":\"addYears\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fromTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTimestamp\",\"type\":\"uint256\"}],\"name\":\"diffDays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"_days\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fromTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTimestamp\",\"type\":\"uint256\"}],\"name\":\"diffHours\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"_hours\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fromTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTimestamp\",\"type\":\"uint256\"}],\"name\":\"diffMinutes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"_minutes\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fromTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTimestamp\",\"type\":\"uint256\"}],\"name\":\"diffMonths\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"_months\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fromTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTimestamp\",\"type\":\"uint256\"}],\"name\":\"diffSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"_seconds\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fromTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTimestamp\",\"type\":\"uint256\"}],\"name\":\"diffYears\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"_years\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getDay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"day\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getDayOfWeek\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"dayOfWeek\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getDaysInMonth\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"daysInMonth\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getHour\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"hour\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getMinute\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"minute\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getMonth\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getSecond\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"second\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getYear\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"isLeapYear\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"leapYear\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"day\",\"type\":\"uint256\"}],\"name\":\"isValidDate\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"valid\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"day\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hour\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minute\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"second\",\"type\":\"uint256\"}],\"name\":\"isValidDateTime\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"valid\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"isWeekDay\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"weekDay\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"isWeekEnd\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"weekEnd\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextYear\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_days\",\"type\":\"uint256\"}],\"name\":\"subDays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_hours\",\"type\":\"uint256\"}],\"name\":\"subHours\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minutes\",\"type\":\"uint256\"}],\"name\":\"subMinutes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_months\",\"type\":\"uint256\"}],\"name\":\"subMonths\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_seconds\",\"type\":\"uint256\"}],\"name\":\"subSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_years\",\"type\":\"uint256\"}],\"name\":\"subYears\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"test\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"day\",\"type\":\"uint256\"}],\"name\":\"timestampFromDate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"day\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hour\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minute\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"second\",\"type\":\"uint256\"}],\"name\":\"timestampFromDateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"timestampToDate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"day\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"timestampToDateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"day\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hour\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minute\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"second\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + "bin": "608060405234801561001057600080fd5b506110ed806100206000396000f3fe608060405234801561001057600080fd5b506004361061023c5760003560e01c80637217523c1161013b578063b8d16dbc116100b8578063ea1c16901161007c578063ea1c169014610704578063f615ed5414610754578063f8a8fd6d14610777578063fa93f88314610781578063ff2258cb1461079e5761023c565b8063b8d16dbc14610649578063c7b6fd6a14610666578063c9d3462214610689578063d6582d0d146106ac578063de5101af146106c95761023c565b806392d66313116100ff57806392d66313146105ac5780639e524caa146105c9578063a324ad24146105ec578063ad203bd414610609578063b05eb08d1461062c5761023c565b80637217523c146105035780637be341091461052657806389a3a00d146105495780638aa001fc1461056c5780638d4a2d39146105895761023c565b80633e239e1a116101c9578063444fda821161018d578063444fda82146104425780634b321502146104655780635e05bd6d1461048857806362fb9697146104c357806365c72840146104e65761023c565b80633e239e1a1461039f5780633f9e0eb7146103bc5780634355644d146103df5780634371c46514610402578063442b8c791461041f5761023c565b806314b2d6dc1161021057806314b2d6dc146102be5780631f4f77b2146102fb57806322f8a2b8146103245780632af123b8146103415780633293d007146103645761023c565b80625015531461024157806302e98e0d1461027657806310848ddf14610299578063146bea7b146102b6575b600080fd5b6102646004803603604081101561025757600080fd5b50803590602001356107c1565b60408051918252519081900360200190f35b6102646004803603604081101561028c57600080fd5b50803590602001356107d4565b610264600480360360208110156102af57600080fd5b50356107e0565b6102646107f1565b6102e7600480360360608110156102d457600080fd5b50803590602081013590604001356107f7565b604080519115158252519081900360200190f35b6102646004803603606081101561031157600080fd5b508035906020810135906040013561080c565b6102646004803603602081101561033a57600080fd5b5035610819565b6102646004803603604081101561035757600080fd5b5080359060200135610824565b6102e7600480360360c081101561037a57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135610830565b610264600480360360208110156103b557600080fd5b503561084b565b610264600480360360408110156103d257600080fd5b5080359060200135610856565b610264600480360360408110156103f557600080fd5b5080359060200135610862565b6102e76004803603602081101561041857600080fd5b503561086e565b6102646004803603604081101561043557600080fd5b5080359060200135610879565b6102646004803603604081101561045857600080fd5b5080359060200135610885565b6102646004803603604081101561047b57600080fd5b5080359060200135610891565b610264600480360360c081101561049e57600080fd5b5080359060208101359060408101359060608101359060808101359060a0013561089d565b610264600480360360408110156104d957600080fd5b50803590602001356108b7565b610264600480360360208110156104fc57600080fd5b50356108c3565b6102646004803603604081101561051957600080fd5b50803590602001356108ce565b6102646004803603604081101561053c57600080fd5b50803590602001356108da565b6102646004803603604081101561055f57600080fd5b50803590602001356108e6565b6102646004803603602081101561058257600080fd5b50356108f2565b6102646004803603604081101561059f57600080fd5b50803590602001356108fd565b610264600480360360208110156105c257600080fd5b5035610909565b610264600480360360408110156105df57600080fd5b5080359060200135610914565b6102646004803603602081101561060257600080fd5b5035610920565b6102646004803603604081101561061f57600080fd5b508035906020013561092b565b6102e76004803603602081101561064257600080fd5b5035610937565b6102e76004803603602081101561065f57600080fd5b5035610942565b6102646004803603604081101561067c57600080fd5b508035906020013561094d565b6102646004803603604081101561069f57600080fd5b5080359060200135610959565b6102e7600480360360208110156106c257600080fd5b5035610965565b6106e6600480360360208110156106df57600080fd5b5035610970565b60408051938452602084019290925282820152519081900360600190f35b6107216004803603602081101561071a57600080fd5b503561098b565b604080519687526020870195909552858501939093526060850191909152608084015260a0830152519081900360c00190f35b6102646004803603604081101561076a57600080fd5b50803590602001356109b1565b61077f6109bd565b005b6102646004803603602081101561079757600080fd5b50356109d5565b610264600480360360408110156107b457600080fd5b50803590602001356109e0565b60006107cd83836109ec565b9392505050565b60006107cd8383610a00565b60006107eb82610a1d565b92915050565b60005481565b6000610804848484610a3f565b949350505050565b6000610804848484610a95565b60006107eb82610aaf565b60006107cd8383610ac2565b6000610840878787878787610adc565b979650505050505050565b60006107eb82610b1c565b60006107cd8383610b2a565b60006107cd8383610bb0565b60006107eb82610c2a565b60006107cd8383610c3f565b60006107cd8383610c66565b60006107cd8383610cc2565b6000610840878787878787610cd6565b9695505050505050565b60006107cd8383610d00565b60006107eb82610d14565b60006107cd8383610d23565b60006107cd8383610d38565b60006107cd8383610d8a565b60006107eb82610d9d565b60006107cd8383610da4565b60006107eb82610db4565b60006107cd8383610dcc565b60006107eb82610ddf565b60006107cd8383610dee565b60006107eb82610e6e565b60006107eb82610e93565b60006107cd8383610eb0565b60006107cd8383610ec5565b60006107eb82610ee0565b600080600061097e84610ef5565b9196909550909350915050565b60008060008060008061099d87610f06565b949c939b5091995097509550909350915050565b60006107cd8383610f45565b426109cf81600163ffffffff610c3f16565b60005550565b60006107eb82610f55565b60006107cd8383610f64565b610e1081028203828111156107eb57600080fd5b600081831115610a0f57600080fd5b603c8383035b049392505050565b60008080610a3062015180855b04610fa5565b50915091506108048282610b2a565b60006107b28410158015610a535750600083115b8015610a605750600c8311155b156107cd576000610a718585610b2a565b9050600083118015610a835750808311155b15610a8d57600191505b509392505050565b600062015180610aa685858561103b565b02949350505050565b6007620151809091046003010660010190565b600081831115610ad157600080fd5b610e10838303610a15565b6000610ae9878787610a3f565b156108ad57601884108015610afe5750603c83105b8015610b0a5750603c82105b156108ad575060019695505050505050565b610e10620151809091060490565b60008160011480610b3b5750816003145b80610b465750816005145b80610b515750816007145b80610b5c5750816008145b80610b67575081600a145b80610b72575081600c145b15610b7f5750601f6107eb565b81600214610b8f5750601e6107eb565b610b9883610e6e565b610ba357601c610ba6565b601d5b60ff169392505050565b6000808080610bc26201518087610a2a565b600c918801600019810183810494909401965094509250900660010191506000610bec8484610b2a565b905080821115610bfa578091505b62015180870662015180610c0f86868661103b565b0201945086851015610c2057600080fd5b5050505092915050565b60006006610c3783610aaf565b101592915050565b6000808080610c516201518087610a2a565b9187019450925090506000610bec8484610b2a565b6000808080610c786201518087610a2a565b918790039450925090506000610c8e8484610b2a565b905080821115610c9c578091505b62015180870662015180610cb186868661103b565b0201945086851115610c2057600080fd5b610e1081028201828110156107eb57600080fd5b600081603c8402610e10860262015180610cf18b8b8b61103b565b02010101979650505050505050565b600081831115610d0f57600080fd5b500390565b60006108046201518083610a2a565b6201518081028201828110156107eb57600080fd5b600081831115610d4757600080fd5b600080610d576201518086610a2a565b5091509150600080610d6e620151808781610a2a57fe5b50600c9586029590910201939093039190910395945050505050565b603c81028201828110156107eb57600080fd5b603c900690565b818101828110156107eb57600080fd5b6000610dc36201518083610a2a565b50909392505050565b603c81028203828111156107eb57600080fd5b6000610a8d6201518083610a2a565b6000808080610e006201518087610a2a565b91945092509050600c8084028301869003600019019081049350600c810660010192506000610e2f8585610b2a565b905080831115610e3d578092505b62015180880662015180610e5287878761103b565b0201955087861115610e6357600080fd5b505050505092915050565b600060048206158015610e8357506064820615155b806107eb57505061019090061590565b600080610ea36201518084610a2a565b505090506107cd81610e6e565b6201518081028203828111156107eb57600080fd5b600081831115610ed457600080fd5b62015180838303610a15565b60006005610eed83610aaf565b111592915050565b6000808061097e6201518085610a2a565b60008080808080610f1a6201518088610a2a565b91999098919750610e10620151809092068281049750603c9290068281049650919091069350915050565b808203828111156107eb57600080fd5b6000610e108206603c81610a15565b600081831115610f7357600080fd5b6000610f826201518085610a2a565b505090506000610f97620151808581610a2a57fe5b505091909103949350505050565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f8460500281610ffc57fe5b0590506000605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b60006107b284101561104c57600080fd5b838383600062253d8c600460036064611324600c600d19890105890101050205600c80600d19870105600c02600287030361016f028161108857fe5b0560046105b5600c600d1989010589016112c0010205617d4b860301010303905080945050505050939250505056fea2646970667358221220144bfa7ff851a685f881e93c3b88c3dce21cc7d3c01423e087bdfba5b17d290964736f6c63430006000033" + } + }, + "version": "0.6.0+commit.26b70077.Darwin.appleclang" +}; diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.sol b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.sol new file mode 100644 index 0000000..1c3d368 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.sol @@ -0,0 +1,141 @@ +pragma solidity ^0.6.0; + +import "BokkyPooBahsDateTimeLibrary.sol"; + +// ---------------------------------------------------------------------------- +// Testing BokkyPooBah's DateTime Library +// +// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary +// +// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. +// ---------------------------------------------------------------------------- + +contract TestDateTime { + using BokkyPooBahsDateTimeLibrary for uint; + + uint public nextYear; + + function test() public { + uint today = now; + nextYear = today.addYears(1); + } + + function timestampFromDate(uint year, uint month, uint day) public pure returns (uint timestamp) { + return BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day); + } + function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (uint timestamp) { + return BokkyPooBahsDateTimeLibrary.timestampFromDateTime(year, month, day, hour, minute, second); + } + function timestampToDate(uint timestamp) public pure returns (uint year, uint month, uint day) { + (year, month, day) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); + } + function timestampToDateTime(uint timestamp) public pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { + (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(timestamp); + } + + function isLeapYear(uint timestamp) public pure returns (bool leapYear) { + leapYear = BokkyPooBahsDateTimeLibrary.isLeapYear(timestamp); + } + function _isLeapYear(uint year) public pure returns (bool leapYear) { + leapYear = BokkyPooBahsDateTimeLibrary._isLeapYear(year); + } + function isWeekDay(uint timestamp) public pure returns (bool weekDay) { + weekDay = BokkyPooBahsDateTimeLibrary.isWeekDay(timestamp); + } + function isWeekEnd(uint timestamp) public pure returns (bool weekEnd) { + weekEnd = BokkyPooBahsDateTimeLibrary.isWeekEnd(timestamp); + } + + function getDaysInMonth(uint timestamp) public pure returns (uint daysInMonth) { + daysInMonth = BokkyPooBahsDateTimeLibrary.getDaysInMonth(timestamp); + } + function _getDaysInMonth(uint year, uint month) public pure returns (uint daysInMonth) { + daysInMonth = BokkyPooBahsDateTimeLibrary._getDaysInMonth(year, month); + } + function getDayOfWeek(uint timestamp) public pure returns (uint dayOfWeek) { + dayOfWeek = BokkyPooBahsDateTimeLibrary.getDayOfWeek(timestamp); + } + + function isValidDate(uint year, uint month, uint day) public pure returns (bool valid) { + valid = BokkyPooBahsDateTimeLibrary.isValidDate(year, month, day); + } + function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (bool valid) { + valid = BokkyPooBahsDateTimeLibrary.isValidDateTime(year, month, day, hour, minute, second); + } + + function getYear(uint timestamp) public pure returns (uint year) { + year = BokkyPooBahsDateTimeLibrary.getYear(timestamp); + } + function getMonth(uint timestamp) public pure returns (uint month) { + month = BokkyPooBahsDateTimeLibrary.getMonth(timestamp); + } + function getDay(uint timestamp) public pure returns (uint day) { + day = BokkyPooBahsDateTimeLibrary.getDay(timestamp); + } + function getHour(uint timestamp) public pure returns (uint hour) { + hour = BokkyPooBahsDateTimeLibrary.getHour(timestamp); + } + function getMinute(uint timestamp) public pure returns (uint minute) { + minute = BokkyPooBahsDateTimeLibrary.getMinute(timestamp); + } + function getSecond(uint timestamp) public pure returns (uint second) { + second = BokkyPooBahsDateTimeLibrary.getSecond(timestamp); + } + + function addYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addYears(timestamp, _years); + } + function addMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addMonths(timestamp, _months); + } + function addDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addDays(timestamp, _days); + } + function addHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addHours(timestamp, _hours); + } + function addMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addMinutes(timestamp, _minutes); + } + function addSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.addSeconds(timestamp, _seconds); + } + + function subYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subYears(timestamp, _years); + } + function subMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subMonths(timestamp, _months); + } + function subDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subDays(timestamp, _days); + } + function subHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subHours(timestamp, _hours); + } + function subMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subMinutes(timestamp, _minutes); + } + function subSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { + newTimestamp = BokkyPooBahsDateTimeLibrary.subSeconds(timestamp, _seconds); + } + + function diffYears(uint fromTimestamp, uint toTimestamp) public pure returns (uint _years) { + _years = BokkyPooBahsDateTimeLibrary.diffYears(fromTimestamp, toTimestamp); + } + function diffMonths(uint fromTimestamp, uint toTimestamp) public pure returns (uint _months) { + _months = BokkyPooBahsDateTimeLibrary.diffMonths(fromTimestamp, toTimestamp); + } + function diffDays(uint fromTimestamp, uint toTimestamp) public pure returns (uint _days) { + _days = BokkyPooBahsDateTimeLibrary.diffDays(fromTimestamp, toTimestamp); + } + function diffHours(uint fromTimestamp, uint toTimestamp) public pure returns (uint _hours) { + _hours = BokkyPooBahsDateTimeLibrary.diffHours(fromTimestamp, toTimestamp); + } + function diffMinutes(uint fromTimestamp, uint toTimestamp) public pure returns (uint _minutes) { + _minutes = BokkyPooBahsDateTimeLibrary.diffMinutes(fromTimestamp, toTimestamp); + } + function diffSeconds(uint fromTimestamp, uint toTimestamp) public pure returns (uint _seconds) { + _seconds = BokkyPooBahsDateTimeLibrary.diffSeconds(fromTimestamp, toTimestamp); + } +} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/deploymentData.js b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/deploymentData.js new file mode 100644 index 0000000..48ea50b --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/deploymentData.js @@ -0,0 +1,11 @@ +dateTimeLibAbi=[] +dateTimeLibBin="0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122075d49f0ac9a443fac8bb202f0adb9e02ed12cbbf6d4d258fcb57548a1e88719064736f6c63430006000033" +testDateTimeAbi=[{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"_getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"name":"_isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"addDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"addHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"addMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"addMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"addSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"addYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffDays","outputs":[{"internalType":"uint256","name":"_days","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffHours","outputs":[{"internalType":"uint256","name":"_hours","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMinutes","outputs":[{"internalType":"uint256","name":"_minutes","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMonths","outputs":[{"internalType":"uint256","name":"_months","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffSeconds","outputs":[{"internalType":"uint256","name":"_seconds","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffYears","outputs":[{"internalType":"uint256","name":"_years","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDay","outputs":[{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDayOfWeek","outputs":[{"internalType":"uint256","name":"dayOfWeek","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getHour","outputs":[{"internalType":"uint256","name":"hour","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMinute","outputs":[{"internalType":"uint256","name":"minute","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMonth","outputs":[{"internalType":"uint256","name":"month","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getSecond","outputs":[{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getYear","outputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"isValidDate","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"isValidDateTime","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekDay","outputs":[{"internalType":"bool","name":"weekDay","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekEnd","outputs":[{"internalType":"bool","name":"weekEnd","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nextYear","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"subDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"subHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"subMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"subMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"subSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"subYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"test","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"timestampFromDate","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"timestampFromDateTime","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDate","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDateTime","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"}] +testDateTimeBin="0x608060405234801561001057600080fd5b506110ed806100206000396000f3fe608060405234801561001057600080fd5b506004361061023c5760003560e01c80637217523c1161013b578063b8d16dbc116100b8578063ea1c16901161007c578063ea1c169014610704578063f615ed5414610754578063f8a8fd6d14610777578063fa93f88314610781578063ff2258cb1461079e5761023c565b8063b8d16dbc14610649578063c7b6fd6a14610666578063c9d3462214610689578063d6582d0d146106ac578063de5101af146106c95761023c565b806392d66313116100ff57806392d66313146105ac5780639e524caa146105c9578063a324ad24146105ec578063ad203bd414610609578063b05eb08d1461062c5761023c565b80637217523c146105035780637be341091461052657806389a3a00d146105495780638aa001fc1461056c5780638d4a2d39146105895761023c565b80633e239e1a116101c9578063444fda821161018d578063444fda82146104425780634b321502146104655780635e05bd6d1461048857806362fb9697146104c357806365c72840146104e65761023c565b80633e239e1a1461039f5780633f9e0eb7146103bc5780634355644d146103df5780634371c46514610402578063442b8c791461041f5761023c565b806314b2d6dc1161021057806314b2d6dc146102be5780631f4f77b2146102fb57806322f8a2b8146103245780632af123b8146103415780633293d007146103645761023c565b80625015531461024157806302e98e0d1461027657806310848ddf14610299578063146bea7b146102b6575b600080fd5b6102646004803603604081101561025757600080fd5b50803590602001356107c1565b60408051918252519081900360200190f35b6102646004803603604081101561028c57600080fd5b50803590602001356107d4565b610264600480360360208110156102af57600080fd5b50356107e0565b6102646107f1565b6102e7600480360360608110156102d457600080fd5b50803590602081013590604001356107f7565b604080519115158252519081900360200190f35b6102646004803603606081101561031157600080fd5b508035906020810135906040013561080c565b6102646004803603602081101561033a57600080fd5b5035610819565b6102646004803603604081101561035757600080fd5b5080359060200135610824565b6102e7600480360360c081101561037a57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135610830565b610264600480360360208110156103b557600080fd5b503561084b565b610264600480360360408110156103d257600080fd5b5080359060200135610856565b610264600480360360408110156103f557600080fd5b5080359060200135610862565b6102e76004803603602081101561041857600080fd5b503561086e565b6102646004803603604081101561043557600080fd5b5080359060200135610879565b6102646004803603604081101561045857600080fd5b5080359060200135610885565b6102646004803603604081101561047b57600080fd5b5080359060200135610891565b610264600480360360c081101561049e57600080fd5b5080359060208101359060408101359060608101359060808101359060a0013561089d565b610264600480360360408110156104d957600080fd5b50803590602001356108b7565b610264600480360360208110156104fc57600080fd5b50356108c3565b6102646004803603604081101561051957600080fd5b50803590602001356108ce565b6102646004803603604081101561053c57600080fd5b50803590602001356108da565b6102646004803603604081101561055f57600080fd5b50803590602001356108e6565b6102646004803603602081101561058257600080fd5b50356108f2565b6102646004803603604081101561059f57600080fd5b50803590602001356108fd565b610264600480360360208110156105c257600080fd5b5035610909565b610264600480360360408110156105df57600080fd5b5080359060200135610914565b6102646004803603602081101561060257600080fd5b5035610920565b6102646004803603604081101561061f57600080fd5b508035906020013561092b565b6102e76004803603602081101561064257600080fd5b5035610937565b6102e76004803603602081101561065f57600080fd5b5035610942565b6102646004803603604081101561067c57600080fd5b508035906020013561094d565b6102646004803603604081101561069f57600080fd5b5080359060200135610959565b6102e7600480360360208110156106c257600080fd5b5035610965565b6106e6600480360360208110156106df57600080fd5b5035610970565b60408051938452602084019290925282820152519081900360600190f35b6107216004803603602081101561071a57600080fd5b503561098b565b604080519687526020870195909552858501939093526060850191909152608084015260a0830152519081900360c00190f35b6102646004803603604081101561076a57600080fd5b50803590602001356109b1565b61077f6109bd565b005b6102646004803603602081101561079757600080fd5b50356109d5565b610264600480360360408110156107b457600080fd5b50803590602001356109e0565b60006107cd83836109ec565b9392505050565b60006107cd8383610a00565b60006107eb82610a1d565b92915050565b60005481565b6000610804848484610a3f565b949350505050565b6000610804848484610a95565b60006107eb82610aaf565b60006107cd8383610ac2565b6000610840878787878787610adc565b979650505050505050565b60006107eb82610b1c565b60006107cd8383610b2a565b60006107cd8383610bb0565b60006107eb82610c2a565b60006107cd8383610c3f565b60006107cd8383610c66565b60006107cd8383610cc2565b6000610840878787878787610cd6565b9695505050505050565b60006107cd8383610d00565b60006107eb82610d14565b60006107cd8383610d23565b60006107cd8383610d38565b60006107cd8383610d8a565b60006107eb82610d9d565b60006107cd8383610da4565b60006107eb82610db4565b60006107cd8383610dcc565b60006107eb82610ddf565b60006107cd8383610dee565b60006107eb82610e6e565b60006107eb82610e93565b60006107cd8383610eb0565b60006107cd8383610ec5565b60006107eb82610ee0565b600080600061097e84610ef5565b9196909550909350915050565b60008060008060008061099d87610f06565b949c939b5091995097509550909350915050565b60006107cd8383610f45565b426109cf81600163ffffffff610c3f16565b60005550565b60006107eb82610f55565b60006107cd8383610f64565b610e1081028203828111156107eb57600080fd5b600081831115610a0f57600080fd5b603c8383035b049392505050565b60008080610a3062015180855b04610fa5565b50915091506108048282610b2a565b60006107b28410158015610a535750600083115b8015610a605750600c8311155b156107cd576000610a718585610b2a565b9050600083118015610a835750808311155b15610a8d57600191505b509392505050565b600062015180610aa685858561103b565b02949350505050565b6007620151809091046003010660010190565b600081831115610ad157600080fd5b610e10838303610a15565b6000610ae9878787610a3f565b156108ad57601884108015610afe5750603c83105b8015610b0a5750603c82105b156108ad575060019695505050505050565b610e10620151809091060490565b60008160011480610b3b5750816003145b80610b465750816005145b80610b515750816007145b80610b5c5750816008145b80610b67575081600a145b80610b72575081600c145b15610b7f5750601f6107eb565b81600214610b8f5750601e6107eb565b610b9883610e6e565b610ba357601c610ba6565b601d5b60ff169392505050565b6000808080610bc26201518087610a2a565b600c918801600019810183810494909401965094509250900660010191506000610bec8484610b2a565b905080821115610bfa578091505b62015180870662015180610c0f86868661103b565b0201945086851015610c2057600080fd5b5050505092915050565b60006006610c3783610aaf565b101592915050565b6000808080610c516201518087610a2a565b9187019450925090506000610bec8484610b2a565b6000808080610c786201518087610a2a565b918790039450925090506000610c8e8484610b2a565b905080821115610c9c578091505b62015180870662015180610cb186868661103b565b0201945086851115610c2057600080fd5b610e1081028201828110156107eb57600080fd5b600081603c8402610e10860262015180610cf18b8b8b61103b565b02010101979650505050505050565b600081831115610d0f57600080fd5b500390565b60006108046201518083610a2a565b6201518081028201828110156107eb57600080fd5b600081831115610d4757600080fd5b600080610d576201518086610a2a565b5091509150600080610d6e620151808781610a2a57fe5b50600c9586029590910201939093039190910395945050505050565b603c81028201828110156107eb57600080fd5b603c900690565b818101828110156107eb57600080fd5b6000610dc36201518083610a2a565b50909392505050565b603c81028203828111156107eb57600080fd5b6000610a8d6201518083610a2a565b6000808080610e006201518087610a2a565b91945092509050600c8084028301869003600019019081049350600c810660010192506000610e2f8585610b2a565b905080831115610e3d578092505b62015180880662015180610e5287878761103b565b0201955087861115610e6357600080fd5b505050505092915050565b600060048206158015610e8357506064820615155b806107eb57505061019090061590565b600080610ea36201518084610a2a565b505090506107cd81610e6e565b6201518081028203828111156107eb57600080fd5b600081831115610ed457600080fd5b62015180838303610a15565b60006005610eed83610aaf565b111592915050565b6000808061097e6201518085610a2a565b60008080808080610f1a6201518088610a2a565b91999098919750610e10620151809092068281049750603c9290068281049650919091069350915050565b808203828111156107eb57600080fd5b6000610e108206603c81610a15565b600081831115610f7357600080fd5b6000610f826201518085610a2a565b505090506000610f97620151808581610a2a57fe5b505091909103949350505050565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f8460500281610ffc57fe5b0590506000605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b60006107b284101561104c57600080fd5b838383600062253d8c600460036064611324600c600d19890105890101050205600c80600d19870105600c02600287030361016f028161108857fe5b0560046105b5600c600d1989010589016112c0010205617d4b860301010303905080945050505050939250505056fea2646970667358221220144bfa7ff851a685f881e93c3b88c3dce21cc7d3c01423e087bdfba5b17d290964736f6c63430006000033" +var dateTimeLibAddress="0x90d8927407c79c4a28ee879b821c76fc9bcc2688"; +var dateTimeLibAbi=[]; +var dateTimeLib=eth.contract(dateTimeLibAbi).at(dateTimeLibAddress); +var testDateTimeAddress="0x0e946b999033257976aa5cbe0e3530618ca1582d"; +var testDateTimeAbi=[{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"_getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"name":"_isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"addDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"addHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"addMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"addMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"addSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"addYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffDays","outputs":[{"internalType":"uint256","name":"_days","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffHours","outputs":[{"internalType":"uint256","name":"_hours","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMinutes","outputs":[{"internalType":"uint256","name":"_minutes","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMonths","outputs":[{"internalType":"uint256","name":"_months","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffSeconds","outputs":[{"internalType":"uint256","name":"_seconds","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffYears","outputs":[{"internalType":"uint256","name":"_years","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDay","outputs":[{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDayOfWeek","outputs":[{"internalType":"uint256","name":"dayOfWeek","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getHour","outputs":[{"internalType":"uint256","name":"hour","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMinute","outputs":[{"internalType":"uint256","name":"minute","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMonth","outputs":[{"internalType":"uint256","name":"month","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getSecond","outputs":[{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getYear","outputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"isValidDate","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"isValidDateTime","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekDay","outputs":[{"internalType":"bool","name":"weekDay","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekEnd","outputs":[{"internalType":"bool","name":"weekEnd","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nextYear","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"subDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"subHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"subMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"subMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"subSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"subYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"test","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"timestampFromDate","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"timestampFromDateTime","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDate","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDateTime","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"}]; +var testDateTime=eth.contract(testDateTimeAbi).at(testDateTimeAddress); +console.log("testDateTime=" + JSON.stringify(testDateTime)); diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/functions.js b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/functions.js new file mode 100644 index 0000000..f8410d7 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/functions.js @@ -0,0 +1,571 @@ +// ETH/USD 19 May 2018 00:14 AEDT from CMC and ethgasstation.info +var ethPriceUSD = 675.71; +var defaultGasPrice = web3.toWei(16, "gwei"); + +// ----------------------------------------------------------------------------- +// Accounts +// ----------------------------------------------------------------------------- +var accounts = []; +var accountNames = {}; + +addAccount(eth.accounts[0], "Account #0 - Miner"); +addAccount(eth.accounts[1], "Account #1 - Contract Owner"); +addAccount(eth.accounts[2], "Account #2 - Alice"); +addAccount(eth.accounts[3], "Account #3 - Bob"); +addAccount(eth.accounts[4], "Account #4 - Carol"); +addAccount(eth.accounts[5], "Account #5 - Dave"); +addAccount(eth.accounts[6], "Account #6"); +addAccount(eth.accounts[7], "Account #7"); +addAccount(eth.accounts[8], "Account #8"); +addAccount(eth.accounts[9], "Account #9"); +addAccount(eth.accounts[10], "Account #10"); +addAccount(eth.accounts[11], "Account #11"); + +var minerAccount = eth.accounts[0]; +var contractOwnerAccount = eth.accounts[1]; +var aliceAccount = eth.accounts[2]; +var bobAccount = eth.accounts[3]; +var carolAccount = eth.accounts[4]; +var daveAccount = eth.accounts[5]; +var account6 = eth.accounts[6]; +var account7 = eth.accounts[7]; +var account8 = eth.accounts[8]; +var account9 = eth.accounts[9]; +var account10 = eth.accounts[10]; +var account11 = eth.accounts[11]; + +var baseBlock = eth.blockNumber; + +function unlockAccounts(password) { + for (var i = 0; i < eth.accounts.length && i < accounts.length; i++) { + personal.unlockAccount(eth.accounts[i], password, 100000); + if (i > 0 && eth.getBalance(eth.accounts[i]) == 0) { + personal.sendTransaction({from: eth.accounts[0], to: eth.accounts[i], value: web3.toWei(1000000, "ether")}); + } + } + while (txpool.status.pending > 0) { + } + baseBlock = eth.blockNumber; +} + +function addAccount(account, accountName) { + accounts.push(account); + accountNames[account] = accountName; +} + + +// ----------------------------------------------------------------------------- +// Token Contract +// ----------------------------------------------------------------------------- +var tokenContractAddress = null; +var tokenContractAbi = null; + +function addTokenContractAddressAndAbi(address, tokenAbi) { + tokenContractAddress = address; + tokenContractAbi = tokenAbi; +} + + +// ----------------------------------------------------------------------------- +// Account ETH and token balances +// ----------------------------------------------------------------------------- +function printBalances() { + var token = tokenContractAddress == null || tokenContractAbi == null ? null : web3.eth.contract(tokenContractAbi).at(tokenContractAddress); + var decimals = token == null ? 18 : token.decimals(); + var i = 0; + var totalTokenBalance = new BigNumber(0); + console.log("RESULT: # Account EtherBalanceChange Token Name"); + console.log("RESULT: -- ------------------------------------------ --------------------------- ------------------------------ ---------------------------"); + accounts.forEach(function(e) { + var etherBalanceBaseBlock = eth.getBalance(e, baseBlock); + var etherBalance = web3.fromWei(eth.getBalance(e).minus(etherBalanceBaseBlock), "ether"); + var tokenBalance = token == null ? new BigNumber(0) : token.balanceOf.call(e).shift(-decimals); + totalTokenBalance = totalTokenBalance.add(tokenBalance); + console.log("RESULT: " + pad2(i) + " " + e + " " + pad(etherBalance) + " " + padToken(tokenBalance, decimals) + " " + accountNames[e]); + i++; + }); + console.log("RESULT: -- ------------------------------------------ --------------------------- ------------------------------ ---------------------------"); + console.log("RESULT: " + padToken(totalTokenBalance, decimals) + " Total Token Balances"); + console.log("RESULT: -- ------------------------------------------ --------------------------- ------------------------------ ---------------------------"); + console.log("RESULT: "); +} + +function pad2(s) { + var o = s.toFixed(0); + while (o.length < 2) { + o = " " + o; + } + return o; +} + +function pad(s) { + var o = s.toFixed(18); + while (o.length < 27) { + o = " " + o; + } + return o; +} + +function padToken(s, decimals) { + var o = s.toFixed(decimals); + var l = parseInt(decimals)+12; + while (o.length < l) { + o = " " + o; + } + return o; +} + + +// ----------------------------------------------------------------------------- +// Transaction status +// ----------------------------------------------------------------------------- +function printTxData(name, txId) { + var tx = eth.getTransaction(txId); + var txReceipt = eth.getTransactionReceipt(txId); + var gasPrice = tx.gasPrice; + var gasCostETH = tx.gasPrice.mul(txReceipt.gasUsed).div(1e18); + var gasCostUSD = gasCostETH.mul(ethPriceUSD); + var block = eth.getBlock(txReceipt.blockNumber); + console.log("RESULT: " + name + " status=" + txReceipt.status + (txReceipt.status == 0 ? " Failure" : " Success") + " gas=" + tx.gas + + " gasUsed=" + txReceipt.gasUsed + " costETH=" + gasCostETH + " costUSD=" + gasCostUSD + + " @ ETH/USD=" + ethPriceUSD + " gasPrice=" + web3.fromWei(gasPrice, "gwei") + " gwei block=" + + txReceipt.blockNumber + " txIx=" + tx.transactionIndex + " txId=" + txId + + " @ " + block.timestamp + " " + new Date(block.timestamp * 1000).toUTCString()); +} + +function assert(condition, message) { + if (condition) { + console.log("RESULT: PASS " + message); + } else { + console.log("RESULT: FAIL " + message); + } + return condition; +} + +function assertIntEquals(result, expected, message) { + if (parseInt(result) == parseInt(expected)) { + console.log("RESULT: PASS " + message); + return true; + } else { + console.log("RESULT: FAIL " + message); + return false; + } +} + +function assertEtherBalance(account, expectedBalance) { + var etherBalance = web3.fromWei(eth.getBalance(account), "ether"); + if (etherBalance == expectedBalance) { + console.log("RESULT: OK " + account + " has expected balance " + expectedBalance); + } else { + console.log("RESULT: FAILURE " + account + " has balance " + etherBalance + " <> expected " + expectedBalance); + } +} + +function failIfTxStatusError(tx, msg) { + var status = eth.getTransactionReceipt(tx).status; + if (status == 0) { + console.log("RESULT: FAIL " + msg); + return 0; + } else { + console.log("RESULT: PASS " + msg); + return 1; + } +} + +function passIfTxStatusError(tx, msg) { + var status = eth.getTransactionReceipt(tx).status; + if (status == 1) { + console.log("RESULT: FAIL " + msg); + return 0; + } else { + console.log("RESULT: PASS " + msg); + return 1; + } +} + +function gasEqualsGasUsed(tx) { + var gas = eth.getTransaction(tx).gas; + var gasUsed = eth.getTransactionReceipt(tx).gasUsed; + return (gas == gasUsed); +} + +function failIfGasEqualsGasUsed(tx, msg) { + var gas = eth.getTransaction(tx).gas; + var gasUsed = eth.getTransactionReceipt(tx).gasUsed; + if (gas == gasUsed) { + console.log("RESULT: FAIL " + msg); + return 0; + } else { + console.log("RESULT: PASS " + msg); + return 1; + } +} + +function passIfGasEqualsGasUsed(tx, msg) { + var gas = eth.getTransaction(tx).gas; + var gasUsed = eth.getTransactionReceipt(tx).gasUsed; + if (gas == gasUsed) { + console.log("RESULT: PASS " + msg); + return 1; + } else { + console.log("RESULT: FAIL " + msg); + return 0; + } +} + +function failIfGasEqualsGasUsedOrContractAddressNull(contractAddress, tx, msg) { + if (contractAddress == null) { + console.log("RESULT: FAIL " + msg); + return 0; + } else { + var gas = eth.getTransaction(tx).gas; + var gasUsed = eth.getTransactionReceipt(tx).gasUsed; + if (gas == gasUsed) { + console.log("RESULT: FAIL " + msg); + return 0; + } else { + console.log("RESULT: PASS " + msg); + return 1; + } + } +} + + +//----------------------------------------------------------------------------- +// Wait one block +//----------------------------------------------------------------------------- +function waitOneBlock(oldCurrentBlock) { + while (eth.blockNumber <= oldCurrentBlock) { + } + console.log("RESULT: Waited one block"); + console.log("RESULT: "); + return eth.blockNumber; +} + + +//----------------------------------------------------------------------------- +// Pause for {x} seconds +//----------------------------------------------------------------------------- +function pause(message, addSeconds) { + var time = new Date((parseInt(new Date().getTime()/1000) + addSeconds) * 1000); + console.log("RESULT: Pausing '" + message + "' for " + addSeconds + "s=" + time + " now=" + new Date()); + while ((new Date()).getTime() <= time.getTime()) { + } + console.log("RESULT: Paused '" + message + "' for " + addSeconds + "s=" + time + " now=" + new Date()); + console.log("RESULT: "); +} + + +//----------------------------------------------------------------------------- +//Wait until some unixTime + additional seconds +//----------------------------------------------------------------------------- +function waitUntil(message, unixTime, addSeconds) { + var t = parseInt(unixTime) + parseInt(addSeconds) + parseInt(1); + var time = new Date(t * 1000); + console.log("RESULT: Waiting until '" + message + "' at " + unixTime + "+" + addSeconds + "s=" + time + " now=" + new Date()); + while ((new Date()).getTime() <= time.getTime()) { + } + console.log("RESULT: Waited until '" + message + "' at at " + unixTime + "+" + addSeconds + "s=" + time + " now=" + new Date()); + console.log("RESULT: "); +} + + +//----------------------------------------------------------------------------- +//Wait until some block +//----------------------------------------------------------------------------- +function waitUntilBlock(message, block, addBlocks) { + var b = parseInt(block) + parseInt(addBlocks); + console.log("RESULT: Waiting until '" + message + "' #" + block + "+" + addBlocks + "=#" + b + " currentBlock=" + eth.blockNumber); + while (eth.blockNumber <= b) { + } + console.log("RESULT: Waited until '" + message + "' #" + block + "+" + addBlocks + "=#" + b + " currentBlock=" + eth.blockNumber); + console.log("RESULT: "); +} + + +//----------------------------------------------------------------------------- +// Token Contract +//----------------------------------------------------------------------------- +var tokenFromBlock = 0; +function printTokenContractDetails() { + console.log("RESULT: tokenContractAddress=" + tokenContractAddress); + if (tokenContractAddress != null && tokenContractAbi != null) { + var contract = eth.contract(tokenContractAbi).at(tokenContractAddress); + var decimals = contract.decimals(); + console.log("RESULT: token.owner=" + contract.owner()); + console.log("RESULT: token.newOwner=" + contract.newOwner()); + console.log("RESULT: token.symbol=" + contract.symbol()); + console.log("RESULT: token.name=" + contract.name()); + console.log("RESULT: token.decimals=" + decimals); + console.log("RESULT: token.totalSupply=" + contract.totalSupply().shift(-decimals)); + // console.log("RESULT: token.transferable=" + contract.transferable()); + // console.log("RESULT: token.mintable=" + contract.mintable()); + // console.log("RESULT: token.minter=" + contract.minter()); + + var latestBlock = eth.blockNumber; + var i; + + var approvalEvents = contract.Approval({}, { fromBlock: tokenFromBlock, toBlock: latestBlock }); + i = 0; + approvalEvents.watch(function (error, result) { + console.log("RESULT: Approval " + i++ + " #" + result.blockNumber + " owner=" + result.args.owner + + " spender=" + result.args.spender + " tokens=" + result.args.tokens.shift(-decimals)); + }); + approvalEvents.stopWatching(); + + var transferEvents = contract.Transfer({}, { fromBlock: tokenFromBlock, toBlock: latestBlock }); + i = 0; + transferEvents.watch(function (error, result) { + console.log("RESULT: Transfer " + i++ + " #" + result.blockNumber + ": from=" + result.args.from + " to=" + result.args.to + + " tokens=" + result.args.tokens.shift(-decimals)); + }); + transferEvents.stopWatching(); + + tokenFromBlock = latestBlock + 1; + } +} + + +// ----------------------------------------------------------------------------- +// Club Contract +// ----------------------------------------------------------------------------- +var clubContractAddress = null; +var clubContractAbi = null; + +function addClubContractAddressAndAbi(address, clubAbi) { + clubContractAddress = address; + clubContractAbi = clubAbi; +} + +function displaySplit(data) { + var eth1 = data[0]; + var eth2 = data[1]; + var eth3 = data[2]; + var refund = data[3]; + var total = eth1.add(eth2).add(eth3).add(refund); + return "[eth1=" + eth1.shift(-18) + "; eth2=" + eth2.shift(-18) + "; eth3=" + eth3.shift(-18) + "; refund=" + refund.shift(-18) + "; total=" + total.shift(-18) + "]"; +} + +var clubFromBlock = 0; +function printClubContractDetails() { + console.log("RESULT: clubContractAddress=" + clubContractAddress); + if (clubContractAddress != null && clubContractAbi != null) { + var contract = eth.contract(clubContractAbi).at(clubContractAddress); + console.log("RESULT: club.token=" + contract.token()); + console.log("RESULT: club.initialised=" + contract.initialised()); + console.log("RESULT: club.numberOfMembers=" + contract.numberOfMembers()); + console.log("RESULT: club.getMembers=" + JSON.stringify(contract.getMembers())); + var i; + for (i = 0; i < contract.numberOfMembers(); i++) { + var member = contract.getMemberByIndex(i); + var data = contract.getMemberData(member); + console.log("RESULT: club.member[" + i + "]=" + member + " [" + data[0] + ", " + data[1] + ", '" + data[2] + "']"); + } + console.log("RESULT: club.numberOfProposals=" + contract.numberOfProposals()); + for (i = 0; i < contract.numberOfProposals(); i++) { + console.log("RESULT: club.getProposal[" + i + "]=" + JSON.stringify(contract.getProposal(i))); + } + console.log("RESULT: club.quorum=" + contract.quorum() + "%"); + console.log("RESULT: club.quorumDecayPerWeek=" + contract.quorumDecayPerWeek() + "%"); + console.log("RESULT: club.requiredMajority=" + contract.requiredMajority() + "%"); + + var now = new Date()/1000; + var line = ""; + for (i = 0; i < 10; i++) { + var date = parseInt(now) + 60 * 60 * 24 * 7 * i; + line = line + i + "w=" + contract.getQuorum(now, date) + "% "; + } + console.log("RESULT: club.getQuorum(now, * weeks)=" + line); + + var latestBlock = eth.blockNumber; + + var newProposalEvents = contract.NewProposal({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); + i = 0; + newProposalEvents.watch(function (error, result) { + console.log("RESULT: NewProposal " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); + var proposal = contract.getProposal(result.args.proposalId); + console.log("RESULT: - proposal=" + JSON.stringify(proposal)); + }); + newProposalEvents.stopWatching(); + + var votedEvents = contract.Voted({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); + i = 0; + votedEvents.watch(function (error, result) { + console.log("RESULT: Voted " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); + }); + votedEvents.stopWatching(); + + var voteResultEvents = contract.VoteResult({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); + i = 0; + voteResultEvents.watch(function (error, result) { + console.log("RESULT: VoteResult " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); + }); + voteResultEvents.stopWatching(); + + var memberAddedEvents = contract.MemberAdded({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); + i = 0; + memberAddedEvents.watch(function (error, result) { + console.log("RESULT: MemberAdded " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); + }); + memberAddedEvents.stopWatching(); + + var memberRemovedEvents = contract.MemberRemoved({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); + i = 0; + memberRemovedEvents.watch(function (error, result) { + console.log("RESULT: MemberRemoved " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); + }); + memberRemovedEvents.stopWatching(); + + var memberNameUpdatedEvents = contract.MemberNameUpdated({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); + i = 0; + memberNameUpdatedEvents.watch(function (error, result) { + console.log("RESULT: MemberNameUpdated " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); + }); + memberNameUpdatedEvents.stopWatching(); + + var tokenUpdatedEvents = contract.TokenUpdated({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); + i = 0; + tokenUpdatedEvents.watch(function (error, result) { + console.log("RESULT: TokenUpdated " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); + }); + tokenUpdatedEvents.stopWatching(); + + var tokensForNewMembersUpdatedEvents = contract.TokensForNewMembersUpdated({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); + i = 0; + tokensForNewMembersUpdatedEvents.watch(function (error, result) { + console.log("RESULT: TokensForNewMembersUpdated " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); + }); + tokensForNewMembersUpdatedEvents.stopWatching(); + + var etherDepositedEvents = contract.EtherDeposited({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); + i = 0; + etherDepositedEvents.watch(function (error, result) { + console.log("RESULT: EtherDeposited " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); + }); + etherDepositedEvents.stopWatching(); + + var etherTransferredEvents = contract.EtherTransferred({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); + i = 0; + etherTransferredEvents.watch(function (error, result) { + console.log("RESULT: EtherTransferred " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); + }); + etherTransferredEvents.stopWatching(); + + clubFromBlock = latestBlock + 1; + } +} + + +// ----------------------------------------------------------------------------- +// ClubFactory Contract +// ----------------------------------------------------------------------------- +var clubFactoryContractAddress = null; +var clubFactoryContractAbi = null; + +function addClubFactoryContractAddressAndAbi(address, clubFactoryAbi) { + clubFactoryContractAddress = address; + clubFactoryContractAbi = clubFactoryAbi; +} + +var clubFactoryFromBlock = 0; + +function getClubAndTokenListing() { + var clubs = []; + var tokens = []; + console.log("RESULT: clubFactoryContractAddress=" + clubFactoryContractAddress); + if (clubFactoryContractAddress != null && clubFactoryContractAbi != null) { + var contract = eth.contract(clubFactoryContractAbi).at(clubFactoryContractAddress); + + var latestBlock = eth.blockNumber; + var i; + + var clubListingEvents = contract.ClubEthListing({}, { fromBlock: clubFactoryFromBlock, toBlock: latestBlock }); + i = 0; + clubListingEvents.watch(function (error, result) { + console.log("RESULT: get ClubEthListing " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); + clubs.push(result.args.clubAddress); + tokens.push(result.args.tokenAddress); + }); + clubListingEvents.stopWatching(); + } + return [clubs, tokens]; +} + +function printClubFactoryContractDetails() { + console.log("RESULT: clubFactoryContractAddress=" + clubFactoryContractAddress); + if (clubFactoryContractAddress != null && clubFactoryContractAbi != null) { + var contract = eth.contract(clubFactoryContractAbi).at(clubFactoryContractAddress); + console.log("RESULT: clubFactory.owner=" + contract.owner()); + console.log("RESULT: clubFactory.newOwner=" + contract.newOwner()); + + var latestBlock = eth.blockNumber; + var i; + + var ownershipTransferredEvents = contract.OwnershipTransferred({}, { fromBlock: clubFactoryFromBlock, toBlock: latestBlock }); + i = 0; + ownershipTransferredEvents.watch(function (error, result) { + console.log("RESULT: OwnershipTransferred " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); + }); + ownershipTransferredEvents.stopWatching(); + + var clubEthListingEvents = contract.ClubEthListing({}, { fromBlock: clubFactoryFromBlock, toBlock: latestBlock }); + i = 0; + clubEthListingEvents.watch(function (error, result) { + console.log("RESULT: ClubEthListing " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); + }); + clubEthListingEvents.stopWatching(); + + clubFactoryFromBlock = latestBlock + 1; + } +} + + +// ----------------------------------------------------------------------------- +// Generate Summary JSON +// ----------------------------------------------------------------------------- +function generateSummaryJSON() { + console.log("JSONSUMMARY: {"); + if (crowdsaleContractAddress != null && crowdsaleContractAbi != null) { + var contract = eth.contract(crowdsaleContractAbi).at(crowdsaleContractAddress); + var blockNumber = eth.blockNumber; + var timestamp = eth.getBlock(blockNumber).timestamp; + console.log("JSONSUMMARY: \"blockNumber\": " + blockNumber + ","); + console.log("JSONSUMMARY: \"blockTimestamp\": " + timestamp + ","); + console.log("JSONSUMMARY: \"blockTimestampString\": \"" + new Date(timestamp * 1000).toUTCString() + "\","); + console.log("JSONSUMMARY: \"crowdsaleContractAddress\": \"" + crowdsaleContractAddress + "\","); + console.log("JSONSUMMARY: \"crowdsaleContractOwnerAddress\": \"" + contract.owner() + "\","); + console.log("JSONSUMMARY: \"tokenContractAddress\": \"" + contract.bttsToken() + "\","); + console.log("JSONSUMMARY: \"tokenContractDecimals\": " + contract.TOKEN_DECIMALS() + ","); + console.log("JSONSUMMARY: \"crowdsaleWalletAddress\": \"" + contract.wallet() + "\","); + console.log("JSONSUMMARY: \"crowdsaleTeamWalletAddress\": \"" + contract.teamWallet() + "\","); + console.log("JSONSUMMARY: \"crowdsaleTeamPercent\": " + contract.TEAM_PERCENT_GZE() + ","); + console.log("JSONSUMMARY: \"bonusListContractAddress\": \"" + contract.bonusList() + "\","); + console.log("JSONSUMMARY: \"tier1Bonus\": " + contract.TIER1_BONUS() + ","); + console.log("JSONSUMMARY: \"tier2Bonus\": " + contract.TIER2_BONUS() + ","); + console.log("JSONSUMMARY: \"tier3Bonus\": " + contract.TIER3_BONUS() + ","); + var startDate = contract.START_DATE(); + // BK TODO - Remove for production + startDate = 1512921600; + var endDate = contract.endDate(); + // BK TODO - Remove for production + endDate = 1513872000; + console.log("JSONSUMMARY: \"crowdsaleStart\": " + startDate + ","); + console.log("JSONSUMMARY: \"crowdsaleStartString\": \"" + new Date(startDate * 1000).toUTCString() + "\","); + console.log("JSONSUMMARY: \"crowdsaleEnd\": " + endDate + ","); + console.log("JSONSUMMARY: \"crowdsaleEndString\": \"" + new Date(endDate * 1000).toUTCString() + "\","); + console.log("JSONSUMMARY: \"usdPerEther\": " + contract.usdPerKEther().shift(-3) + ","); + console.log("JSONSUMMARY: \"usdPerGze\": " + contract.USD_CENT_PER_GZE().shift(-2) + ","); + console.log("JSONSUMMARY: \"gzePerEth\": " + contract.gzePerEth().shift(-18) + ","); + console.log("JSONSUMMARY: \"capInUsd\": " + contract.CAP_USD() + ","); + console.log("JSONSUMMARY: \"capInEth\": " + contract.capEth().shift(-18) + ","); + console.log("JSONSUMMARY: \"minimumContributionEth\": " + contract.MIN_CONTRIBUTION_ETH().shift(-18) + ","); + console.log("JSONSUMMARY: \"contributedEth\": " + contract.contributedEth().shift(-18) + ","); + console.log("JSONSUMMARY: \"contributedUsd\": " + contract.contributedUsd() + ","); + console.log("JSONSUMMARY: \"generatedGze\": " + contract.generatedGze().shift(-18) + ","); + console.log("JSONSUMMARY: \"lockedAccountThresholdUsd\": " + contract.lockedAccountThresholdUsd() + ","); + console.log("JSONSUMMARY: \"lockedAccountThresholdEth\": " + contract.lockedAccountThresholdEth().shift(-18) + ","); + console.log("JSONSUMMARY: \"precommitmentAdjusted\": " + contract.precommitmentAdjusted() + ","); + console.log("JSONSUMMARY: \"finalised\": " + contract.finalised()); + } + console.log("JSONSUMMARY: }"); +} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/genesis.json b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/genesis.json new file mode 100644 index 0000000..ca85b4a --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/genesis.json @@ -0,0 +1,112 @@ +{ + "config": { + "homesteadBlock": 1, + "byzantiumBlock": 2 + }, + "nonce": "0", + "difficulty": "0x400", + "mixhash": "0x00000000000000000000000000000000000000647572616c65787365646c6578", + "coinbase": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x3B4A1B44", + "alloc": { + "0xa00Af22D07c87d96EeeB0Ed583f8F6AC7812827E": { + "balance": "10000000000000000000000000" + }, + "0xa11AAE29840fBb5c86E6fd4cF809EBA183AEf433": { + "balance": "10000000000000000000000000" + }, + "0xa22AB8A9D641CE77e06D98b7D7065d324D3d6976": { + "balance": "10000000000000000000000000" + }, + "0xa33a6c312D9aD0E0F2E95541BeED0Cc081621fd0": { + "balance": "10000000000000000000000000" + }, + "0xa44a08d3F6933c69212114bb66E2Df1813651844": { + "balance": "10000000000000000000000000" + }, + "0xa55A151Eb00fded1634D27D1127b4bE4627079EA": { + "balance": "10000000000000000000000000" + }, + "0xa66a85ede0CBE03694AA9d9dE0BB19c99ff55bD9": { + "balance": "10000000000000000000000000" + }, + "0xa77A2b9D4B1c010A22A7c565Dc418cef683DbceC": { + "balance": "10000000000000000000000000" + }, + "0xA88A05d2b88283ce84C8325760B72a64591279a2": { + "balance": "10000000000000000000000000" + }, + "0xa99A0Ae3354c06B1459fd441a32a3F71005D7Da0": { + "balance": "10000000000000000000000000" + }, + "0xAAAA9De1E6C564446EBCA0fd102D8Bd92093c756": { + "balance": "10000000000000000000000000" + }, + "0xaBBa43E7594E3B76afB157989e93c6621497FD4b": { + "balance": "10000000000000000000000000" + }, + "0xacCa534c9f62Ab495bd986e002DdF0f054caAE4f": { + "balance": "10000000000000000000000000" + }, + "0xAddA9B762A00FF12711113bfDc36958B73d7F915": { + "balance": "10000000000000000000000000" + }, + "0xaeEa63B5479B50F79583ec49DACdcf86DDEff392": { + "balance": "10000000000000000000000000" + }, + "0xaFfa4D3A80Add8CE4018540e056DACb649589394": { + "balance": "10000000000000000000000000" + }, + "0xB00bfdE102270687324F9205b693859df64F8923": { + "balance": "10000000000000000000000000" + }, + "0xB11Be1D4EF8E94d01cB2695092A79d139A8DAD98": { + "balance": "10000000000000000000000000" + }, + "0xB22BE2D9eEF0d7E260CF96A64FEEa0B95ED3E74f": { + "balance": "10000000000000000000000000" + }, + "0xB33B7ecf5E47BE3981c74d989d3Af8b665b4B649": { + "balance": "10000000000000000000000000" + }, + "0xB44B43d59b738B088b690aE276C1E979aBa8268D": { + "balance": "10000000000000000000000000" + }, + "0xb55B57D113b45481E31AaF03D6F4e5Ad4ef325F8": { + "balance": "10000000000000000000000000" + }, + "0xb66BCB4e473De80E2C8A47CED10c22c705A5e602": { + "balance": "10000000000000000000000000" + }, + "0xB77BbBaa7c1649547Ae61de4B80B91568c28351A": { + "balance": "10000000000000000000000000" + }, + "0xB88B728490B417E29b0784Db30535dB343830dba": { + "balance": "10000000000000000000000000" + }, + "0xB99B3d1f72eDb05a0321dB58eddcF83FD73C4aDe": { + "balance": "10000000000000000000000000" + }, + "0xBaAb56DA883EDBe5314b8005BE410022c510cCae": { + "balance": "10000000000000000000000000" + }, + "0xbbbB9809DE0456Ce0E0Cd660E6E4CeabEf3F521c": { + "balance": "10000000000000000000000000" + }, + "0xBccB68DD0Ac87EF290aeF49870d155F076C87868": { + "balance": "10000000000000000000000000" + }, + "0xbDDB726ee06906e104DB210E6d0506F2B062e477": { + "balance": "10000000000000000000000000" + }, + "0xbeEB24ff18203658D0a1d4682ee3f36ad663eC87": { + "balance": "10000000000000000000000000" + }, + "0xbFfBd8F029EF0BD81cF754b53E8b3a5684F8b3fF": { + "balance": "10000000000000000000000000" + } + } +} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/settings b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/settings new file mode 100644 index 0000000..2ce4bf8 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/settings @@ -0,0 +1,21 @@ +GETHATTACHPOINT=ipc:./testchain/geth.ipc +PASSWORD= + +SOURCEDIR=../contracts + +DATETIMELIBSOL=BokkyPooBahsDateTimeLibrary.sol +DATETIMELIBJS=BokkyPooBahsDateTimeLibrary.js +TESTDATETIMESOL=TestDateTime.sol +TESTDATETIMEJS=TestDateTime.js +TESTDATETIMEFLATTENED=../flattened/TestDateTime_flattened.sol + +DEPLOYMENTDATA=deploymentData.js + +TEST1OUTPUT=test1output.txt +TEST1RESULTS=test1results.txt +TEST2OUTPUT=test2output.txt +TEST2RESULTS=test2results.txt +TEST3OUTPUT=test3output.txt +TEST3RESULTS=test3results.txt +TEST4OUTPUT=test4output.txt +TEST4RESULTS=test4results.txt diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1output.txt b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1output.txt new file mode 100644 index 0000000..979b4e0 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1output.txt @@ -0,0 +1,3070 @@ +MODE = 'full' +GETHATTACHPOINT = 'ipc:./testchain/geth.ipc' +PASSWORD = '' +SOURCEDIR = '../contracts' +DATETIMELIBSOL = 'BokkyPooBahsDateTimeLibrary.sol' +DATETIMELIBJS = 'BokkyPooBahsDateTimeLibrary.js' +TESTDATETIMESOL = 'TestDateTime.sol' +TESTDATETIMEJS = 'TestDateTime.js' +DEPLOYMENTDATA = 'deploymentData.js' +TEST1OUTPUT = 'test1output.txt' +TEST1RESULTS = 'test1results.txt' +CURRENTTIME = '1579355174' 'Sun Jan 19 00:46:14 2020' +START_DATE = '1579355219' 'Sun Jan 19 00:46:59 2020' +END_DATE = '1579355294' 'Sun Jan 19 00:48:14 2020' +--- Differences ../contracts/BokkyPooBahsDateTimeLibrary.sol BokkyPooBahsDateTimeLibrary.sol --- + +--- Differences ../contracts/TestDateTime.sol TestDateTime.sol --- + +solc, the solidity compiler commandline interface +Version: 0.6.0+commit.26b70077.Darwin.appleclang +contractsdir: ../contracts +remapdir : (no remapping) +mainsol : TestDateTime.sol +outputsol : ../flattened/TestDateTime_flattened.sol +Processing ../contracts/TestDateTime.sol + Importing ../contracts/BokkyPooBahsDateTimeLibrary.sol + Processing ../contracts/BokkyPooBahsDateTimeLibrary.sol +Welcome to the Geth JavaScript console! + +instance: Geth/v1.9.9-stable-01744997/darwin-amd64/go1.13.5 +coinbase: 0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e +at block: 5 (Sun, 19 Jan 2020 00:46:15 AEDT) + datadir: /Users/bok/Projects/BokkyPooBahsDateTimeLibrary/test/testchain + modules: admin:1.0 clique:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0 + +> +true +> +true +> +true +> +> +undefined +> +undefined +> +undefined +> +undefined +> +> +DATA: dateTimeLibAbi=[] +undefined +> +DATA: dateTimeLibBin="0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122075d49f0ac9a443fac8bb202f0adb9e02ed12cbbf6d4d258fcb57548a1e88719064736f6c63430006000033" +undefined +> +DATA: testDateTimeAbi=[{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"_getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"name":"_isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"addDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"addHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"addMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"addMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"addSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"addYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffDays","outputs":[{"internalType":"uint256","name":"_days","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffHours","outputs":[{"internalType":"uint256","name":"_hours","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMinutes","outputs":[{"internalType":"uint256","name":"_minutes","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMonths","outputs":[{"internalType":"uint256","name":"_months","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffSeconds","outputs":[{"internalType":"uint256","name":"_seconds","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffYears","outputs":[{"internalType":"uint256","name":"_years","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDay","outputs":[{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDayOfWeek","outputs":[{"internalType":"uint256","name":"dayOfWeek","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getHour","outputs":[{"internalType":"uint256","name":"hour","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMinute","outputs":[{"internalType":"uint256","name":"minute","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMonth","outputs":[{"internalType":"uint256","name":"month","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getSecond","outputs":[{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getYear","outputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"isValidDate","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"isValidDateTime","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekDay","outputs":[{"internalType":"bool","name":"weekDay","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekEnd","outputs":[{"internalType":"bool","name":"weekEnd","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nextYear","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"subDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"subHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"subMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"subMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"subSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"subYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"test","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"timestampFromDate","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"timestampFromDateTime","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDate","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDateTime","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"}] +undefined +> +DATA: testDateTimeBin="0x608060405234801561001057600080fd5b506110ed806100206000396000f3fe608060405234801561001057600080fd5b506004361061023c5760003560e01c80637217523c1161013b578063b8d16dbc116100b8578063ea1c16901161007c578063ea1c169014610704578063f615ed5414610754578063f8a8fd6d14610777578063fa93f88314610781578063ff2258cb1461079e5761023c565b8063b8d16dbc14610649578063c7b6fd6a14610666578063c9d3462214610689578063d6582d0d146106ac578063de5101af146106c95761023c565b806392d66313116100ff57806392d66313146105ac5780639e524caa146105c9578063a324ad24146105ec578063ad203bd414610609578063b05eb08d1461062c5761023c565b80637217523c146105035780637be341091461052657806389a3a00d146105495780638aa001fc1461056c5780638d4a2d39146105895761023c565b80633e239e1a116101c9578063444fda821161018d578063444fda82146104425780634b321502146104655780635e05bd6d1461048857806362fb9697146104c357806365c72840146104e65761023c565b80633e239e1a1461039f5780633f9e0eb7146103bc5780634355644d146103df5780634371c46514610402578063442b8c791461041f5761023c565b806314b2d6dc1161021057806314b2d6dc146102be5780631f4f77b2146102fb57806322f8a2b8146103245780632af123b8146103415780633293d007146103645761023c565b80625015531461024157806302e98e0d1461027657806310848ddf14610299578063146bea7b146102b6575b600080fd5b6102646004803603604081101561025757600080fd5b50803590602001356107c1565b60408051918252519081900360200190f35b6102646004803603604081101561028c57600080fd5b50803590602001356107d4565b610264600480360360208110156102af57600080fd5b50356107e0565b6102646107f1565b6102e7600480360360608110156102d457600080fd5b50803590602081013590604001356107f7565b604080519115158252519081900360200190f35b6102646004803603606081101561031157600080fd5b508035906020810135906040013561080c565b6102646004803603602081101561033a57600080fd5b5035610819565b6102646004803603604081101561035757600080fd5b5080359060200135610824565b6102e7600480360360c081101561037a57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135610830565b610264600480360360208110156103b557600080fd5b503561084b565b610264600480360360408110156103d257600080fd5b5080359060200135610856565b610264600480360360408110156103f557600080fd5b5080359060200135610862565b6102e76004803603602081101561041857600080fd5b503561086e565b6102646004803603604081101561043557600080fd5b5080359060200135610879565b6102646004803603604081101561045857600080fd5b5080359060200135610885565b6102646004803603604081101561047b57600080fd5b5080359060200135610891565b610264600480360360c081101561049e57600080fd5b5080359060208101359060408101359060608101359060808101359060a0013561089d565b610264600480360360408110156104d957600080fd5b50803590602001356108b7565b610264600480360360208110156104fc57600080fd5b50356108c3565b6102646004803603604081101561051957600080fd5b50803590602001356108ce565b6102646004803603604081101561053c57600080fd5b50803590602001356108da565b6102646004803603604081101561055f57600080fd5b50803590602001356108e6565b6102646004803603602081101561058257600080fd5b50356108f2565b6102646004803603604081101561059f57600080fd5b50803590602001356108fd565b610264600480360360208110156105c257600080fd5b5035610909565b610264600480360360408110156105df57600080fd5b5080359060200135610914565b6102646004803603602081101561060257600080fd5b5035610920565b6102646004803603604081101561061f57600080fd5b508035906020013561092b565b6102e76004803603602081101561064257600080fd5b5035610937565b6102e76004803603602081101561065f57600080fd5b5035610942565b6102646004803603604081101561067c57600080fd5b508035906020013561094d565b6102646004803603604081101561069f57600080fd5b5080359060200135610959565b6102e7600480360360208110156106c257600080fd5b5035610965565b6106e6600480360360208110156106df57600080fd5b5035610970565b60408051938452602084019290925282820152519081900360600190f35b6107216004803603602081101561071a57600080fd5b503561098b565b604080519687526020870195909552858501939093526060850191909152608084015260a0830152519081900360c00190f35b6102646004803603604081101561076a57600080fd5b50803590602001356109b1565b61077f6109bd565b005b6102646004803603602081101561079757600080fd5b50356109d5565b610264600480360360408110156107b457600080fd5b50803590602001356109e0565b60006107cd83836109ec565b9392505050565b60006107cd8383610a00565b60006107eb82610a1d565b92915050565b60005481565b6000610804848484610a3f565b949350505050565b6000610804848484610a95565b60006107eb82610aaf565b60006107cd8383610ac2565b6000610840878787878787610adc565b979650505050505050565b60006107eb82610b1c565b60006107cd8383610b2a565b60006107cd8383610bb0565b60006107eb82610c2a565b60006107cd8383610c3f565b60006107cd8383610c66565b60006107cd8383610cc2565b6000610840878787878787610cd6565b9695505050505050565b60006107cd8383610d00565b60006107eb82610d14565b60006107cd8383610d23565b60006107cd8383610d38565b60006107cd8383610d8a565b60006107eb82610d9d565b60006107cd8383610da4565b60006107eb82610db4565b60006107cd8383610dcc565b60006107eb82610ddf565b60006107cd8383610dee565b60006107eb82610e6e565b60006107eb82610e93565b60006107cd8383610eb0565b60006107cd8383610ec5565b60006107eb82610ee0565b600080600061097e84610ef5565b9196909550909350915050565b60008060008060008061099d87610f06565b949c939b5091995097509550909350915050565b60006107cd8383610f45565b426109cf81600163ffffffff610c3f16565b60005550565b60006107eb82610f55565b60006107cd8383610f64565b610e1081028203828111156107eb57600080fd5b600081831115610a0f57600080fd5b603c8383035b049392505050565b60008080610a3062015180855b04610fa5565b50915091506108048282610b2a565b60006107b28410158015610a535750600083115b8015610a605750600c8311155b156107cd576000610a718585610b2a565b9050600083118015610a835750808311155b15610a8d57600191505b509392505050565b600062015180610aa685858561103b565b02949350505050565b6007620151809091046003010660010190565b600081831115610ad157600080fd5b610e10838303610a15565b6000610ae9878787610a3f565b156108ad57601884108015610afe5750603c83105b8015610b0a5750603c82105b156108ad575060019695505050505050565b610e10620151809091060490565b60008160011480610b3b5750816003145b80610b465750816005145b80610b515750816007145b80610b5c5750816008145b80610b67575081600a145b80610b72575081600c145b15610b7f5750601f6107eb565b81600214610b8f5750601e6107eb565b610b9883610e6e565b610ba357601c610ba6565b601d5b60ff169392505050565b6000808080610bc26201518087610a2a565b600c918801600019810183810494909401965094509250900660010191506000610bec8484610b2a565b905080821115610bfa578091505b62015180870662015180610c0f86868661103b565b0201945086851015610c2057600080fd5b5050505092915050565b60006006610c3783610aaf565b101592915050565b6000808080610c516201518087610a2a565b9187019450925090506000610bec8484610b2a565b6000808080610c786201518087610a2a565b918790039450925090506000610c8e8484610b2a565b905080821115610c9c578091505b62015180870662015180610cb186868661103b565b0201945086851115610c2057600080fd5b610e1081028201828110156107eb57600080fd5b600081603c8402610e10860262015180610cf18b8b8b61103b565b02010101979650505050505050565b600081831115610d0f57600080fd5b500390565b60006108046201518083610a2a565b6201518081028201828110156107eb57600080fd5b600081831115610d4757600080fd5b600080610d576201518086610a2a565b5091509150600080610d6e620151808781610a2a57fe5b50600c9586029590910201939093039190910395945050505050565b603c81028201828110156107eb57600080fd5b603c900690565b818101828110156107eb57600080fd5b6000610dc36201518083610a2a565b50909392505050565b603c81028203828111156107eb57600080fd5b6000610a8d6201518083610a2a565b6000808080610e006201518087610a2a565b91945092509050600c8084028301869003600019019081049350600c810660010192506000610e2f8585610b2a565b905080831115610e3d578092505b62015180880662015180610e5287878761103b565b0201955087861115610e6357600080fd5b505050505092915050565b600060048206158015610e8357506064820615155b806107eb57505061019090061590565b600080610ea36201518084610a2a565b505090506107cd81610e6e565b6201518081028203828111156107eb57600080fd5b600081831115610ed457600080fd5b62015180838303610a15565b60006005610eed83610aaf565b111592915050565b6000808061097e6201518085610a2a565b60008080808080610f1a6201518088610a2a565b91999098919750610e10620151809092068281049750603c9290068281049650919091069350915050565b808203828111156107eb57600080fd5b6000610e108206603c81610a15565b600081831115610f7357600080fd5b6000610f826201518085610a2a565b505090506000610f97620151808581610a2a57fe5b505091909103949350505050565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f8460500281610ffc57fe5b0590506000605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b60006107b284101561104c57600080fd5b838383600062253d8c600460036064611324600c600d19890105890101050205600c80600d19870105600c02600287030361016f028161108857fe5b0560046105b5600c600d1989010589016112c0010205617d4b860301010303905080945050505050939250505056fea2646970667358221220144bfa7ff851a685f881e93c3b88c3dce21cc7d3c01423e087bdfba5b17d290964736f6c63430006000033" +undefined +> +> +undefined +> +RESULT: # Account EtherBalanceChange Token Name +RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- +RESULT: 0 0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e 0.000000000000000000 0.000000000000000000 Account #0 - Miner +RESULT: 1 0xa11aae29840fbb5c86e6fd4cf809eba183aef433 0.000000000000000000 0.000000000000000000 Account #1 - Contract Owner +RESULT: 2 0xa22ab8a9d641ce77e06d98b7d7065d324d3d6976 0.000000000000000000 0.000000000000000000 Account #2 - Alice +RESULT: 3 0xa33a6c312d9ad0e0f2e95541beed0cc081621fd0 0.000000000000000000 0.000000000000000000 Account #3 - Bob +RESULT: 4 0xa44a08d3f6933c69212114bb66e2df1813651844 0.000000000000000000 0.000000000000000000 Account #4 - Carol +RESULT: 5 0xa55a151eb00fded1634d27d1127b4be4627079ea 0.000000000000000000 0.000000000000000000 Account #5 - Dave +RESULT: 6 0xa66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 0.000000000000000000 0.000000000000000000 Account #6 +RESULT: 7 0xa77a2b9d4b1c010a22a7c565dc418cef683dbcec 0.000000000000000000 0.000000000000000000 Account #7 +RESULT: 8 0xa88a05d2b88283ce84c8325760b72a64591279a2 0.000000000000000000 0.000000000000000000 Account #8 +RESULT: 9 0xa99a0ae3354c06b1459fd441a32a3f71005d7da0 0.000000000000000000 0.000000000000000000 Account #9 +RESULT: 10 0xaaaa9de1e6c564446ebca0fd102d8bd92093c756 0.000000000000000000 0.000000000000000000 Account #10 +RESULT: 11 0xabba43e7594e3b76afb157989e93c6621497fd4b 0.000000000000000000 0.000000000000000000 Account #11 +RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- +RESULT: 0.000000000000000000 Total Token Balances +RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- +RESULT: +undefined +> +RESULT: +undefined +> +> +> +undefined +> +undefined +> +undefined +> +RESULT: ----- Deploy DateTime Library ----- +undefined +> +undefined +> +undefined +> +undefined +> +undefined +> +undefined +> +... +...... +......... +............ +............ +............ +............ +............ +............ +............ +............ +......... +...... +... +undefined +> +... +undefined +> +DATA: var dateTimeLibAddress="0x90d8927407c79c4a28ee879b821c76fc9bcc2688"; +DATA: var dateTimeLibAbi=[]; +DATA: var dateTimeLib=eth.contract(dateTimeLibAbi).at(dateTimeLibAddress); +RESULT: # Account EtherBalanceChange Token Name +RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- +RESULT: 0 0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e 0.001150736000000000 0.000000000000000000 Account #0 - Miner +RESULT: 1 0xa11aae29840fbb5c86e6fd4cf809eba183aef433 -0.001150736000000000 0.000000000000000000 Account #1 - Contract Owner +RESULT: 2 0xa22ab8a9d641ce77e06d98b7d7065d324d3d6976 0.000000000000000000 0.000000000000000000 Account #2 - Alice +RESULT: 3 0xa33a6c312d9ad0e0f2e95541beed0cc081621fd0 0.000000000000000000 0.000000000000000000 Account #3 - Bob +RESULT: 4 0xa44a08d3f6933c69212114bb66e2df1813651844 0.000000000000000000 0.000000000000000000 Account #4 - Carol +RESULT: 5 0xa55a151eb00fded1634d27d1127b4be4627079ea 0.000000000000000000 0.000000000000000000 Account #5 - Dave +RESULT: 6 0xa66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 0.000000000000000000 0.000000000000000000 Account #6 +RESULT: 7 0xa77a2b9d4b1c010a22a7c565dc418cef683dbcec 0.000000000000000000 0.000000000000000000 Account #7 +RESULT: 8 0xa88a05d2b88283ce84c8325760b72a64591279a2 0.000000000000000000 0.000000000000000000 Account #8 +RESULT: 9 0xa99a0ae3354c06b1459fd441a32a3f71005d7da0 0.000000000000000000 0.000000000000000000 Account #9 +RESULT: 10 0xaaaa9de1e6c564446ebca0fd102d8bd92093c756 0.000000000000000000 0.000000000000000000 Account #10 +RESULT: 11 0xabba43e7594e3b76afb157989e93c6621497fd4b 0.000000000000000000 0.000000000000000000 Account #11 +RESULT: 12 0x90d8927407c79c4a28ee879b821c76fc9bcc2688 0.000000000000000000 0.000000000000000000 DateTime Library +RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- +RESULT: 0.000000000000000000 Total Token Balances +RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- +RESULT: +undefined +> +RESULT: PASS Deploy DateTime Library +1 +> +RESULT: dateTimeLibTx status=0x1 Success gas=6000000 gasUsed=71921 costETH=0.001150736 costUSD=0.77756382256 @ ETH/USD=675.71 gasPrice=16 gwei block=19 txIx=0 txId=0x3d6e997266a4df7a6d24ad8461a47646aa30ac31435f55bc7f8d22226d67cd14 @ 1579355189 Sat, 18 Jan 2020 13:46:29 UTC +undefined +> +RESULT: +undefined +> +> +> +undefined +> +undefined +> +undefined +> +RESULT: ---------- Deploy TestDateTime Contract ---------- +undefined +> +undefined +> +undefined +> +undefined +> +undefined +> +undefined +> +undefined +> +... +...... +......... +............ +............ +............ +............ +............ +............ +............ +............ +............ +......... +...... +... +undefined +> +... +undefined +> +DATA: var testDateTimeAddress="0x0e946b999033257976aa5cbe0e3530618ca1582d"; +DATA: var testDateTimeAbi=[{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"_getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"name":"_isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"addDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"addHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"addMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"addMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"addSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"addYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffDays","outputs":[{"internalType":"uint256","name":"_days","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffHours","outputs":[{"internalType":"uint256","name":"_hours","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMinutes","outputs":[{"internalType":"uint256","name":"_minutes","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMonths","outputs":[{"internalType":"uint256","name":"_months","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffSeconds","outputs":[{"internalType":"uint256","name":"_seconds","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffYears","outputs":[{"internalType":"uint256","name":"_years","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDay","outputs":[{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDayOfWeek","outputs":[{"internalType":"uint256","name":"dayOfWeek","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getHour","outputs":[{"internalType":"uint256","name":"hour","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMinute","outputs":[{"internalType":"uint256","name":"minute","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMonth","outputs":[{"internalType":"uint256","name":"month","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getSecond","outputs":[{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getYear","outputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"isValidDate","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"isValidDateTime","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekDay","outputs":[{"internalType":"bool","name":"weekDay","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekEnd","outputs":[{"internalType":"bool","name":"weekEnd","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nextYear","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"subDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"subHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"subMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"subMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"subSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"subYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"test","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"timestampFromDate","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"timestampFromDateTime","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDate","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDateTime","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"}]; +DATA: var testDateTime=eth.contract(testDateTimeAbi).at(testDateTimeAddress); +DATA: console.log("testDateTime=" + JSON.stringify(testDateTime)); +RESULT: # Account EtherBalanceChange Token Name +RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- +RESULT: 0 0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e 0.016965312000000000 0.000000000000000000 Account #0 - Miner +RESULT: 1 0xa11aae29840fbb5c86e6fd4cf809eba183aef433 -0.016965312000000000 0.000000000000000000 Account #1 - Contract Owner +RESULT: 2 0xa22ab8a9d641ce77e06d98b7d7065d324d3d6976 0.000000000000000000 0.000000000000000000 Account #2 - Alice +RESULT: 3 0xa33a6c312d9ad0e0f2e95541beed0cc081621fd0 0.000000000000000000 0.000000000000000000 Account #3 - Bob +RESULT: 4 0xa44a08d3f6933c69212114bb66e2df1813651844 0.000000000000000000 0.000000000000000000 Account #4 - Carol +RESULT: 5 0xa55a151eb00fded1634d27d1127b4be4627079ea 0.000000000000000000 0.000000000000000000 Account #5 - Dave +RESULT: 6 0xa66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 0.000000000000000000 0.000000000000000000 Account #6 +RESULT: 7 0xa77a2b9d4b1c010a22a7c565dc418cef683dbcec 0.000000000000000000 0.000000000000000000 Account #7 +RESULT: 8 0xa88a05d2b88283ce84c8325760b72a64591279a2 0.000000000000000000 0.000000000000000000 Account #8 +RESULT: 9 0xa99a0ae3354c06b1459fd441a32a3f71005d7da0 0.000000000000000000 0.000000000000000000 Account #9 +RESULT: 10 0xaaaa9de1e6c564446ebca0fd102d8bd92093c756 0.000000000000000000 0.000000000000000000 Account #10 +RESULT: 11 0xabba43e7594e3b76afb157989e93c6621497fd4b 0.000000000000000000 0.000000000000000000 Account #11 +RESULT: 12 0x90d8927407c79c4a28ee879b821c76fc9bcc2688 0.000000000000000000 0.000000000000000000 DateTime Library +RESULT: 13 0x0e946b999033257976aa5cbe0e3530618ca1582d 0.000000000000000000 0.000000000000000000 TestDateTime +RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- +RESULT: 0.000000000000000000 Total Token Balances +RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- +RESULT: +undefined +> +RESULT: PASS Deploy TestDateTime Contract +1 +> +RESULT: testDateTimeAddress=0x0e946b999033257976aa5cbe0e3530618ca1582d status=0x1 Success gas=6000000 gasUsed=988411 costETH=0.015814576 costUSD=10.68606714896 @ ETH/USD=675.71 gasPrice=16 gwei block=21 txIx=0 txId=0xdb67f4d0ee1587cd570fc563c69f73dcaffc9f2f4047a1d1792218bb920fbd58 @ 1579355191 Sat, 18 Jan 2020 13:46:31 UTC +undefined +> +RESULT: +undefined +> +> +undefined +> +undefined +> +undefined +> +undefined +> +undefined +> +undefined +> +> +... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +RESULT: ---------- Test isLeapYear ---------- +RESULT: PASS 2000,5,24,1,2,3 is a leap year +RESULT: PASS 2100,5,24,1,2,3 is a not leap year +RESULT: PASS 2104,5,24,1,2,3 is a leap year +RESULT: +undefined +> +> +... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +... +RESULT: ---------- Test isValidDate and isValidDateTime.call ---------- +RESULT: PASS testDateTime.isValidDate.call(1969, 1, 1) is false +RESULT: PASS testDateTime.isValidDate.call(1970, 1, 1) is true +RESULT: PASS testDateTime.isValidDate.call(2000, 2, 29) is true +RESULT: PASS testDateTime.isValidDate.call(2001, 2, 29) is false +RESULT: PASS testDateTime.isValidDate.call(2001, 0, 1) is false +RESULT: PASS testDateTime.isValidDate.call(2001, 1, 0) is false +RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 0, 0, 0) is true +RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 1) is true +RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 23, 1, 1) is true +RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 24, 1, 1) is false +RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 59, 1) is true +RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 60, 1) is false +RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 59) is true +RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 60) is false +RESULT: +undefined +> +> +... +... +...... +...... +... +...... +...... +... +...... +...... +... +... +RESULT: ---------- Test _isLeapYear ---------- +RESULT: PASS 2000 is a leap year +RESULT: PASS 2100 is a not leap year +RESULT: PASS 2104 is a leap year +RESULT: +undefined +> +> +... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +RESULT: ---------- Test isWeekDay ---------- +RESULT: PASS 2018,5,24,1,2,3 is a week day +RESULT: PASS 2018,5,25,1,2,3 is a week day +RESULT: PASS 2018,5,26,1,2,3 is a not week day +RESULT: +undefined +> +> +... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +RESULT: ---------- Test isWeekEnd ---------- +RESULT: PASS 2018,5,24,1,2,3 is a not a week end +RESULT: PASS 2018,5,25,1,2,3 is a not a week end +RESULT: PASS 2018,5,26,1,2,3 is a week end +RESULT: PASS 2018,5,27,1,2,3 is a week end +RESULT: +undefined +> +> +> +... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +RESULT: ---------- Test getDaysInMonth ---------- +RESULT: PASS 2000,1,24,1,2,3 has 31 days +RESULT: PASS 2000,2,24,1,2,3 has 29 days +RESULT: PASS 2001,2,24,1,2,3 has 28 days +RESULT: PASS 2000,3,24,1,2,3 has 31 days +RESULT: PASS 2000,4,24,1,2,3 has 30 days +RESULT: PASS 2000,5,24,1,2,3 has 31 days +RESULT: PASS 2000,6,24,1,2,3 has 30 days +RESULT: PASS 2000,7,24,1,2,3 has 31 days +RESULT: PASS 2000,8,24,1,2,3 has 31 days +RESULT: PASS 2000,9,24,1,2,3 has 30 days +RESULT: PASS 2000,10,24,1,2,3 has 31 days +RESULT: PASS 2000,11,24,1,2,3 has 30 days +RESULT: PASS 2000,12,24,1,2,3 has 31 days +RESULT: +undefined +> +> +> +... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +... +RESULT: ---------- Test _getDaysInMonth ---------- +RESULT: PASS 2000/01 has 31 days +RESULT: PASS 2000/02 has 29 days +RESULT: PASS 2001/02 has 28 days +RESULT: PASS 2000/03 has 31 days +RESULT: PASS 2000/04 has 30 days +RESULT: PASS 2000/05 has 31 days +RESULT: PASS 2000/06 has 30 days +RESULT: PASS 2000/07 has 31 days +RESULT: PASS 2000/08 has 31 days +RESULT: PASS 2000/09 has 30 days +RESULT: PASS 2000/10 has 31 days +RESULT: PASS 2000/11 has 30 days +RESULT: PASS 2000/12 has 31 days +RESULT: +undefined +> +> +> +... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +...... +...... +... +... +RESULT: ---------- Test getDayOfWeek ---------- +RESULT: PASS 2018,5,21,1,2,3 is 1 Monday +RESULT: PASS 2018,5,24,1,2,3 is 4 Thursday +RESULT: PASS 2018,5,26,1,2,3 is 6 Saturday +RESULT: PASS 2018,5,27,1,2,3 is 7 Sunday +RESULT: +undefined +> +> +> +... +... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +... +RESULT: ---------- Test get* ---------- +RESULT: PASS 2018,5,21,1,2,3 year is 2018 +RESULT: PASS 2018,5,21,1,2,3 month is 5 May +RESULT: PASS 2018,5,21,1,2,3 day is 21 +RESULT: PASS 2018,5,21,1,2,3 hour is 1 +RESULT: PASS 2018,5,21,1,2,3 minute is 2 +RESULT: PASS 2018,5,21,1,2,3 second is 3 +RESULT: +undefined +> +> +... +... +... +... +... +...... +...... +... +... +... +... +...... +...... +... +... +... +... +...... +...... +... +... +... +... +...... +...... +... +... +... +... +...... +...... +... +... +... +... +...... +...... +... +... +... +... +...... +...... +... +... +... +... +...... +...... +... +... +RESULT: ---------- Test add{Years|Months|Days|Hours|Minutes|Seconds} ---------- +RESULT: PASS 2000,2,29,1,2,3 + 3 years is 2003/02/28 01:02:03 +RESULT: PASS 2018,12,31,2,3,4 + 30 years is 2048/12/31 02:03:04 +RESULT: PASS 2000,1,31,1,2,3 + 37 months is 2003/02/28 01:02:03 +RESULT: PASS 2018,12,1,2,3,4 + 362 months is 2049/02/01 02:03:04 +RESULT: PASS 2017,1,31,1,2,3 + 37,532 days is 2119/11/05 01:02:03 +RESULT: PASS 2017,1,31,1,2,3 + 900,768 hours is 2119/11/05 01:02:03 +RESULT: PASS 2017,1,31,1,2,3 + 781,920 minutes is 2018/07/28 01:02:03 +RESULT: PASS 2017,1,31,1,2,3 + 461,548,800 seconds is 2031/09/17 01:02:03 +RESULT: +undefined +> +> +... +... +... +... +... +...... +...... +... +... +... +... +...... +...... +... +... +... +... +...... +...... +... +... +... +... +...... +...... +... +... +... +... +...... +...... +... +... +... +... +...... +...... +... +... +... +... +...... +...... +... +... +RESULT: ---------- Test sub{Years|Months|Days|Hours|Minutes|Seconds} ---------- +RESULT: PASS 2000,2,29,1,2,3 - 3 years is 1997/02/28 01:02:03 +RESULT: PASS 2000,2,29,1,2,3 - 37 months is 1997/01/29 01:02:03 +RESULT: PASS 2013,1,1,1,2,3 - 3,756 days is 2002/09/20 01:02:03 +RESULT: PASS 2013,1,1,1,2,3 - 3,756 * 24 hours is 2002/09/20 01:02:03 +RESULT: PASS 2015,7,15,1,2,3 - 223,776 hours is 1990/01/03 01:02:03 +RESULT: PASS 2018,3,1,2,3,4 - 21,600,000 minutes is 1977/02/04 02:03:04 +RESULT: PASS 2020,3,19,3,4,5 - 788,227,200 seconds is 1995/03/28 03:04:05 +RESULT: +undefined +> +> +... +... +... +... +... +... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +...... +...... +... +... +RESULT: ---------- Test diff{Years|Months|Days|Hours|Minutes|Seconds} ---------- +RESULT: fromTimestamp=1508547723 2017,10,21,1,2,3 +RESULT: toTimestamp=1563422706 2019,7,18,4,5,6 +RESULT: PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 2 years diff +RESULT: PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 21 months diff +RESULT: PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 635 days diff +RESULT: PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 15,243 hours diff +RESULT: PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 914,583 minutes diff +RESULT: PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 54,874,983 seconds diff +RESULT: +undefined +> +> +... +... +... +... +... +... +... +... +... +... +... +... +... +...... +...... +......... +......... +...... +...... +...... +...... +...... +...... +...... +......... +...... +...... +......... +......... +......... +......... +......... +......... +...... +......... +......... +......... +......... +......... +...... +...... +... +RESULT: ---------- Test timestampToDateTime.call(...) and timestampFromDateTime.call(...) against JavaScript Date ---------- +RESULT: timestampToDateTime.call(48611)=["1970","1","1","13","30","11"] +RESULT: timestampFromDateTime.call(["1970","1","1","13","30","11"])=48611 +RESULT: jsDate(48611)=1970/1/1 13:30:11 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(48611) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(32096934)=["1971","1","7","11","48","54"] +RESULT: timestampFromDateTime.call(["1971","1","7","11","48","54"])=32096934 +RESULT: jsDate(32096934)=1971/1/7 11:48:54 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(32096934) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(64145254)=["1972","1","13","10","7","34"] +RESULT: timestampFromDateTime.call(["1972","1","13","10","7","34"])=64145254 +RESULT: jsDate(64145254)=1972/1/13 10:7:34 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(64145254) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(95729869)=["1973","1","12","23","37","49"] +RESULT: timestampFromDateTime.call(["1973","1","12","23","37","49"])=95729869 +RESULT: jsDate(95729869)=1973/1/12 23:37:49 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(95729869) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(127778192)=["1974","1","18","21","56","32"] +RESULT: timestampFromDateTime.call(["1974","1","18","21","56","32"])=127778192 +RESULT: jsDate(127778192)=1974/1/18 21:56:32 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(127778192) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(159826516)=["1975","1","24","20","15","16"] +RESULT: timestampFromDateTime.call(["1975","1","24","20","15","16"])=159826516 +RESULT: jsDate(159826516)=1975/1/24 20:15:16 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(159826516) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(191411131)=["1976","1","25","9","45","31"] +RESULT: timestampFromDateTime.call(["1976","1","25","9","45","31"])=191411131 +RESULT: jsDate(191411131)=1976/1/25 9:45:31 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(191411131) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(223459454)=["1977","1","30","8","4","14"] +RESULT: timestampFromDateTime.call(["1977","1","30","8","4","14"])=223459454 +RESULT: jsDate(223459454)=1977/1/30 8:4:14 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(223459454) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(255507778)=["1978","2","5","6","22","58"] +RESULT: timestampFromDateTime.call(["1978","2","5","6","22","58"])=255507778 +RESULT: jsDate(255507778)=1978/2/5 6:22:58 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(255507778) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(287092393)=["1979","2","5","19","53","13"] +RESULT: timestampFromDateTime.call(["1979","2","5","19","53","13"])=287092393 +RESULT: jsDate(287092393)=1979/2/5 19:53:13 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(287092393) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(319140716)=["1980","2","11","18","11","56"] +RESULT: timestampFromDateTime.call(["1980","2","11","18","11","56"])=319140716 +RESULT: jsDate(319140716)=1980/2/11 18:11:56 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(319140716) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(351189040)=["1981","2","16","16","30","40"] +RESULT: timestampFromDateTime.call(["1981","2","16","16","30","40"])=351189040 +RESULT: jsDate(351189040)=1981/2/16 16:30:40 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(351189040) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(382773655)=["1982","2","17","6","0","55"] +RESULT: timestampFromDateTime.call(["1982","2","17","6","0","55"])=382773655 +RESULT: jsDate(382773655)=1982/2/17 6:0:55 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(382773655) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(414821978)=["1983","2","23","4","19","38"] +RESULT: timestampFromDateTime.call(["1983","2","23","4","19","38"])=414821978 +RESULT: jsDate(414821978)=1983/2/23 4:19:38 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(414821978) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(446870302)=["1984","2","29","2","38","22"] +RESULT: timestampFromDateTime.call(["1984","2","29","2","38","22"])=446870302 +RESULT: jsDate(446870302)=1984/2/29 2:38:22 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(446870302) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(478454917)=["1985","2","28","16","8","37"] +RESULT: timestampFromDateTime.call(["1985","2","28","16","8","37"])=478454917 +RESULT: jsDate(478454917)=1985/2/28 16:8:37 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(478454917) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(510503240)=["1986","3","6","14","27","20"] +RESULT: timestampFromDateTime.call(["1986","3","6","14","27","20"])=510503240 +RESULT: jsDate(510503240)=1986/3/6 14:27:20 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(510503240) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(542551564)=["1987","3","12","12","46","4"] +RESULT: timestampFromDateTime.call(["1987","3","12","12","46","4"])=542551564 +RESULT: jsDate(542551564)=1987/3/12 12:46:4 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(542551564) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(574136179)=["1988","3","12","2","16","19"] +RESULT: timestampFromDateTime.call(["1988","3","12","2","16","19"])=574136179 +RESULT: jsDate(574136179)=1988/3/12 2:16:19 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(574136179) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(606184502)=["1989","3","18","0","35","2"] +RESULT: timestampFromDateTime.call(["1989","3","18","0","35","2"])=606184502 +RESULT: jsDate(606184502)=1989/3/18 0:35:2 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(606184502) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(638232826)=["1990","3","23","22","53","46"] +RESULT: timestampFromDateTime.call(["1990","3","23","22","53","46"])=638232826 +RESULT: jsDate(638232826)=1990/3/23 22:53:46 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(638232826) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(669817441)=["1991","3","24","12","24","1"] +RESULT: timestampFromDateTime.call(["1991","3","24","12","24","1"])=669817441 +RESULT: jsDate(669817441)=1991/3/24 12:24:1 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(669817441) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(701865764)=["1992","3","29","10","42","44"] +RESULT: timestampFromDateTime.call(["1992","3","29","10","42","44"])=701865764 +RESULT: jsDate(701865764)=1992/3/29 10:42:44 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(701865764) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(733914088)=["1993","4","4","9","1","28"] +RESULT: timestampFromDateTime.call(["1993","4","4","9","1","28"])=733914088 +RESULT: jsDate(733914088)=1993/4/4 9:1:28 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(733914088) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(765498703)=["1994","4","4","22","31","43"] +RESULT: timestampFromDateTime.call(["1994","4","4","22","31","43"])=765498703 +RESULT: jsDate(765498703)=1994/4/4 22:31:43 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(765498703) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(797547026)=["1995","4","10","20","50","26"] +RESULT: timestampFromDateTime.call(["1995","4","10","20","50","26"])=797547026 +RESULT: jsDate(797547026)=1995/4/10 20:50:26 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(797547026) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(829595350)=["1996","4","15","19","9","10"] +RESULT: timestampFromDateTime.call(["1996","4","15","19","9","10"])=829595350 +RESULT: jsDate(829595350)=1996/4/15 19:9:10 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(829595350) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(861179965)=["1997","4","16","8","39","25"] +RESULT: timestampFromDateTime.call(["1997","4","16","8","39","25"])=861179965 +RESULT: jsDate(861179965)=1997/4/16 8:39:25 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(861179965) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(893228288)=["1998","4","22","6","58","8"] +RESULT: timestampFromDateTime.call(["1998","4","22","6","58","8"])=893228288 +RESULT: jsDate(893228288)=1998/4/22 6:58:8 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(893228288) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(925276612)=["1999","4","28","5","16","52"] +RESULT: timestampFromDateTime.call(["1999","4","28","5","16","52"])=925276612 +RESULT: jsDate(925276612)=1999/4/28 5:16:52 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(925276612) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(956861227)=["2000","4","27","18","47","7"] +RESULT: timestampFromDateTime.call(["2000","4","27","18","47","7"])=956861227 +RESULT: jsDate(956861227)=2000/4/27 18:47:7 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(956861227) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(988909550)=["2001","5","3","17","5","50"] +RESULT: timestampFromDateTime.call(["2001","5","3","17","5","50"])=988909550 +RESULT: jsDate(988909550)=2001/5/3 17:5:50 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(988909550) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1020957874)=["2002","5","9","15","24","34"] +RESULT: timestampFromDateTime.call(["2002","5","9","15","24","34"])=1020957874 +RESULT: jsDate(1020957874)=2002/5/9 15:24:34 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1020957874) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1052542489)=["2003","5","10","4","54","49"] +RESULT: timestampFromDateTime.call(["2003","5","10","4","54","49"])=1052542489 +RESULT: jsDate(1052542489)=2003/5/10 4:54:49 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1052542489) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1084590812)=["2004","5","15","3","13","32"] +RESULT: timestampFromDateTime.call(["2004","5","15","3","13","32"])=1084590812 +RESULT: jsDate(1084590812)=2004/5/15 3:13:32 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1084590812) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1116639136)=["2005","5","21","1","32","16"] +RESULT: timestampFromDateTime.call(["2005","5","21","1","32","16"])=1116639136 +RESULT: jsDate(1116639136)=2005/5/21 1:32:16 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1116639136) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1148223751)=["2006","5","21","15","2","31"] +RESULT: timestampFromDateTime.call(["2006","5","21","15","2","31"])=1148223751 +RESULT: jsDate(1148223751)=2006/5/21 15:2:31 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1148223751) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1180272074)=["2007","5","27","13","21","14"] +RESULT: timestampFromDateTime.call(["2007","5","27","13","21","14"])=1180272074 +RESULT: jsDate(1180272074)=2007/5/27 13:21:14 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1180272074) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1212320398)=["2008","6","1","11","39","58"] +RESULT: timestampFromDateTime.call(["2008","6","1","11","39","58"])=1212320398 +RESULT: jsDate(1212320398)=2008/6/1 11:39:58 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1212320398) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1243905013)=["2009","6","2","1","10","13"] +RESULT: timestampFromDateTime.call(["2009","6","2","1","10","13"])=1243905013 +RESULT: jsDate(1243905013)=2009/6/2 1:10:13 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1243905013) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1275953336)=["2010","6","7","23","28","56"] +RESULT: timestampFromDateTime.call(["2010","6","7","23","28","56"])=1275953336 +RESULT: jsDate(1275953336)=2010/6/7 23:28:56 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1275953336) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1308001660)=["2011","6","13","21","47","40"] +RESULT: timestampFromDateTime.call(["2011","6","13","21","47","40"])=1308001660 +RESULT: jsDate(1308001660)=2011/6/13 21:47:40 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1308001660) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1339586275)=["2012","6","13","11","17","55"] +RESULT: timestampFromDateTime.call(["2012","6","13","11","17","55"])=1339586275 +RESULT: jsDate(1339586275)=2012/6/13 11:17:55 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1339586275) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1371634598)=["2013","6","19","9","36","38"] +RESULT: timestampFromDateTime.call(["2013","6","19","9","36","38"])=1371634598 +RESULT: jsDate(1371634598)=2013/6/19 9:36:38 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1371634598) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1403682922)=["2014","6","25","7","55","22"] +RESULT: timestampFromDateTime.call(["2014","6","25","7","55","22"])=1403682922 +RESULT: jsDate(1403682922)=2014/6/25 7:55:22 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1403682922) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1435267537)=["2015","6","25","21","25","37"] +RESULT: timestampFromDateTime.call(["2015","6","25","21","25","37"])=1435267537 +RESULT: jsDate(1435267537)=2015/6/25 21:25:37 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1435267537) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1467315860)=["2016","6","30","19","44","20"] +RESULT: timestampFromDateTime.call(["2016","6","30","19","44","20"])=1467315860 +RESULT: jsDate(1467315860)=2016/6/30 19:44:20 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1467315860) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1499364184)=["2017","7","6","18","3","4"] +RESULT: timestampFromDateTime.call(["2017","7","6","18","3","4"])=1499364184 +RESULT: jsDate(1499364184)=2017/7/6 18:3:4 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1499364184) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1530948799)=["2018","7","7","7","33","19"] +RESULT: timestampFromDateTime.call(["2018","7","7","7","33","19"])=1530948799 +RESULT: jsDate(1530948799)=2018/7/7 7:33:19 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1530948799) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1562997122)=["2019","7","13","5","52","2"] +RESULT: timestampFromDateTime.call(["2019","7","13","5","52","2"])=1562997122 +RESULT: jsDate(1562997122)=2019/7/13 5:52:2 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1562997122) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1595045446)=["2020","7","18","4","10","46"] +RESULT: timestampFromDateTime.call(["2020","7","18","4","10","46"])=1595045446 +RESULT: jsDate(1595045446)=2020/7/18 4:10:46 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1595045446) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1626630061)=["2021","7","18","17","41","1"] +RESULT: timestampFromDateTime.call(["2021","7","18","17","41","1"])=1626630061 +RESULT: jsDate(1626630061)=2021/7/18 17:41:1 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1626630061) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1658678384)=["2022","7","24","15","59","44"] +RESULT: timestampFromDateTime.call(["2022","7","24","15","59","44"])=1658678384 +RESULT: jsDate(1658678384)=2022/7/24 15:59:44 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1658678384) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1690726708)=["2023","7","30","14","18","28"] +RESULT: timestampFromDateTime.call(["2023","7","30","14","18","28"])=1690726708 +RESULT: jsDate(1690726708)=2023/7/30 14:18:28 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1690726708) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1722311323)=["2024","7","30","3","48","43"] +RESULT: timestampFromDateTime.call(["2024","7","30","3","48","43"])=1722311323 +RESULT: jsDate(1722311323)=2024/7/30 3:48:43 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1722311323) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1754359646)=["2025","8","5","2","7","26"] +RESULT: timestampFromDateTime.call(["2025","8","5","2","7","26"])=1754359646 +RESULT: jsDate(1754359646)=2025/8/5 2:7:26 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1754359646) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1786407970)=["2026","8","11","0","26","10"] +RESULT: timestampFromDateTime.call(["2026","8","11","0","26","10"])=1786407970 +RESULT: jsDate(1786407970)=2026/8/11 0:26:10 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1786407970) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1817992585)=["2027","8","11","13","56","25"] +RESULT: timestampFromDateTime.call(["2027","8","11","13","56","25"])=1817992585 +RESULT: jsDate(1817992585)=2027/8/11 13:56:25 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1817992585) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1850040908)=["2028","8","16","12","15","8"] +RESULT: timestampFromDateTime.call(["2028","8","16","12","15","8"])=1850040908 +RESULT: jsDate(1850040908)=2028/8/16 12:15:8 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1850040908) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1882089232)=["2029","8","22","10","33","52"] +RESULT: timestampFromDateTime.call(["2029","8","22","10","33","52"])=1882089232 +RESULT: jsDate(1882089232)=2029/8/22 10:33:52 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1882089232) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1913673847)=["2030","8","23","0","4","7"] +RESULT: timestampFromDateTime.call(["2030","8","23","0","4","7"])=1913673847 +RESULT: jsDate(1913673847)=2030/8/23 0:4:7 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1913673847) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1945722170)=["2031","8","28","22","22","50"] +RESULT: timestampFromDateTime.call(["2031","8","28","22","22","50"])=1945722170 +RESULT: jsDate(1945722170)=2031/8/28 22:22:50 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1945722170) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(1977770494)=["2032","9","2","20","41","34"] +RESULT: timestampFromDateTime.call(["2032","9","2","20","41","34"])=1977770494 +RESULT: jsDate(1977770494)=2032/9/2 20:41:34 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(1977770494) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2009355109)=["2033","9","3","10","11","49"] +RESULT: timestampFromDateTime.call(["2033","9","3","10","11","49"])=2009355109 +RESULT: jsDate(2009355109)=2033/9/3 10:11:49 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2009355109) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2041403432)=["2034","9","9","8","30","32"] +RESULT: timestampFromDateTime.call(["2034","9","9","8","30","32"])=2041403432 +RESULT: jsDate(2041403432)=2034/9/9 8:30:32 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2041403432) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2073451756)=["2035","9","15","6","49","16"] +RESULT: timestampFromDateTime.call(["2035","9","15","6","49","16"])=2073451756 +RESULT: jsDate(2073451756)=2035/9/15 6:49:16 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2073451756) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2105036371)=["2036","9","14","20","19","31"] +RESULT: timestampFromDateTime.call(["2036","9","14","20","19","31"])=2105036371 +RESULT: jsDate(2105036371)=2036/9/14 20:19:31 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2105036371) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2137084694)=["2037","9","20","18","38","14"] +RESULT: timestampFromDateTime.call(["2037","9","20","18","38","14"])=2137084694 +RESULT: jsDate(2137084694)=2037/9/20 18:38:14 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2137084694) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2169133018)=["2038","9","26","16","56","58"] +RESULT: timestampFromDateTime.call(["2038","9","26","16","56","58"])=2169133018 +RESULT: jsDate(2169133018)=2038/9/26 16:56:58 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2169133018) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2200717633)=["2039","9","27","6","27","13"] +RESULT: timestampFromDateTime.call(["2039","9","27","6","27","13"])=2200717633 +RESULT: jsDate(2200717633)=2039/9/27 6:27:13 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2200717633) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2232765956)=["2040","10","2","4","45","56"] +RESULT: timestampFromDateTime.call(["2040","10","2","4","45","56"])=2232765956 +RESULT: jsDate(2232765956)=2040/10/2 4:45:56 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2232765956) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2264814280)=["2041","10","8","3","4","40"] +RESULT: timestampFromDateTime.call(["2041","10","8","3","4","40"])=2264814280 +RESULT: jsDate(2264814280)=2041/10/8 3:4:40 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2264814280) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2296398895)=["2042","10","8","16","34","55"] +RESULT: timestampFromDateTime.call(["2042","10","8","16","34","55"])=2296398895 +RESULT: jsDate(2296398895)=2042/10/8 16:34:55 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2296398895) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2328447218)=["2043","10","14","14","53","38"] +RESULT: timestampFromDateTime.call(["2043","10","14","14","53","38"])=2328447218 +RESULT: jsDate(2328447218)=2043/10/14 14:53:38 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2328447218) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2360495542)=["2044","10","19","13","12","22"] +RESULT: timestampFromDateTime.call(["2044","10","19","13","12","22"])=2360495542 +RESULT: jsDate(2360495542)=2044/10/19 13:12:22 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2360495542) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2392080157)=["2045","10","20","2","42","37"] +RESULT: timestampFromDateTime.call(["2045","10","20","2","42","37"])=2392080157 +RESULT: jsDate(2392080157)=2045/10/20 2:42:37 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2392080157) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2424128480)=["2046","10","26","1","1","20"] +RESULT: timestampFromDateTime.call(["2046","10","26","1","1","20"])=2424128480 +RESULT: jsDate(2424128480)=2046/10/26 1:1:20 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2424128480) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2456176804)=["2047","10","31","23","20","4"] +RESULT: timestampFromDateTime.call(["2047","10","31","23","20","4"])=2456176804 +RESULT: jsDate(2456176804)=2047/10/31 23:20:4 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2456176804) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2487761419)=["2048","10","31","12","50","19"] +RESULT: timestampFromDateTime.call(["2048","10","31","12","50","19"])=2487761419 +RESULT: jsDate(2487761419)=2048/10/31 12:50:19 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2487761419) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2519809742)=["2049","11","6","11","9","2"] +RESULT: timestampFromDateTime.call(["2049","11","6","11","9","2"])=2519809742 +RESULT: jsDate(2519809742)=2049/11/6 11:9:2 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2519809742) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2551858066)=["2050","11","12","9","27","46"] +RESULT: timestampFromDateTime.call(["2050","11","12","9","27","46"])=2551858066 +RESULT: jsDate(2551858066)=2050/11/12 9:27:46 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2551858066) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2583442681)=["2051","11","12","22","58","1"] +RESULT: timestampFromDateTime.call(["2051","11","12","22","58","1"])=2583442681 +RESULT: jsDate(2583442681)=2051/11/12 22:58:1 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2583442681) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2615491004)=["2052","11","17","21","16","44"] +RESULT: timestampFromDateTime.call(["2052","11","17","21","16","44"])=2615491004 +RESULT: jsDate(2615491004)=2052/11/17 21:16:44 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2615491004) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2647539328)=["2053","11","23","19","35","28"] +RESULT: timestampFromDateTime.call(["2053","11","23","19","35","28"])=2647539328 +RESULT: jsDate(2647539328)=2053/11/23 19:35:28 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2647539328) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2679123943)=["2054","11","24","9","5","43"] +RESULT: timestampFromDateTime.call(["2054","11","24","9","5","43"])=2679123943 +RESULT: jsDate(2679123943)=2054/11/24 9:5:43 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2679123943) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2711172266)=["2055","11","30","7","24","26"] +RESULT: timestampFromDateTime.call(["2055","11","30","7","24","26"])=2711172266 +RESULT: jsDate(2711172266)=2055/11/30 7:24:26 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2711172266) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2743220590)=["2056","12","5","5","43","10"] +RESULT: timestampFromDateTime.call(["2056","12","5","5","43","10"])=2743220590 +RESULT: jsDate(2743220590)=2056/12/5 5:43:10 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2743220590) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2774805205)=["2057","12","5","19","13","25"] +RESULT: timestampFromDateTime.call(["2057","12","5","19","13","25"])=2774805205 +RESULT: jsDate(2774805205)=2057/12/5 19:13:25 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2774805205) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2806853528)=["2058","12","11","17","32","8"] +RESULT: timestampFromDateTime.call(["2058","12","11","17","32","8"])=2806853528 +RESULT: jsDate(2806853528)=2058/12/11 17:32:8 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2806853528) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2838901852)=["2059","12","17","15","50","52"] +RESULT: timestampFromDateTime.call(["2059","12","17","15","50","52"])=2838901852 +RESULT: jsDate(2838901852)=2059/12/17 15:50:52 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2838901852) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2870486467)=["2060","12","17","5","21","7"] +RESULT: timestampFromDateTime.call(["2060","12","17","5","21","7"])=2870486467 +RESULT: jsDate(2870486467)=2060/12/17 5:21:7 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2870486467) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2902534790)=["2061","12","23","3","39","50"] +RESULT: timestampFromDateTime.call(["2061","12","23","3","39","50"])=2902534790 +RESULT: jsDate(2902534790)=2061/12/23 3:39:50 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2902534790) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2934583114)=["2062","12","29","1","58","34"] +RESULT: timestampFromDateTime.call(["2062","12","29","1","58","34"])=2934583114 +RESULT: jsDate(2934583114)=2062/12/29 1:58:34 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2934583114) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2966167729)=["2063","12","29","15","28","49"] +RESULT: timestampFromDateTime.call(["2063","12","29","15","28","49"])=2966167729 +RESULT: jsDate(2966167729)=2063/12/29 15:28:49 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2966167729) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(2998216052)=["2065","1","3","13","47","32"] +RESULT: timestampFromDateTime.call(["2065","1","3","13","47","32"])=2998216052 +RESULT: jsDate(2998216052)=2065/1/3 13:47:32 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(2998216052) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3030264376)=["2066","1","9","12","6","16"] +RESULT: timestampFromDateTime.call(["2066","1","9","12","6","16"])=3030264376 +RESULT: jsDate(3030264376)=2066/1/9 12:6:16 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3030264376) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3061848991)=["2067","1","10","1","36","31"] +RESULT: timestampFromDateTime.call(["2067","1","10","1","36","31"])=3061848991 +RESULT: jsDate(3061848991)=2067/1/10 1:36:31 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3061848991) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3093897314)=["2068","1","15","23","55","14"] +RESULT: timestampFromDateTime.call(["2068","1","15","23","55","14"])=3093897314 +RESULT: jsDate(3093897314)=2068/1/15 23:55:14 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3093897314) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3125945638)=["2069","1","20","22","13","58"] +RESULT: timestampFromDateTime.call(["2069","1","20","22","13","58"])=3125945638 +RESULT: jsDate(3125945638)=2069/1/20 22:13:58 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3125945638) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3157530253)=["2070","1","21","11","44","13"] +RESULT: timestampFromDateTime.call(["2070","1","21","11","44","13"])=3157530253 +RESULT: jsDate(3157530253)=2070/1/21 11:44:13 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3157530253) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3189578576)=["2071","1","27","10","2","56"] +RESULT: timestampFromDateTime.call(["2071","1","27","10","2","56"])=3189578576 +RESULT: jsDate(3189578576)=2071/1/27 10:2:56 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3189578576) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3221626900)=["2072","2","2","8","21","40"] +RESULT: timestampFromDateTime.call(["2072","2","2","8","21","40"])=3221626900 +RESULT: jsDate(3221626900)=2072/2/2 8:21:40 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3221626900) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3253211515)=["2073","2","1","21","51","55"] +RESULT: timestampFromDateTime.call(["2073","2","1","21","51","55"])=3253211515 +RESULT: jsDate(3253211515)=2073/2/1 21:51:55 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3253211515) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3285259838)=["2074","2","7","20","10","38"] +RESULT: timestampFromDateTime.call(["2074","2","7","20","10","38"])=3285259838 +RESULT: jsDate(3285259838)=2074/2/7 20:10:38 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3285259838) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3317308162)=["2075","2","13","18","29","22"] +RESULT: timestampFromDateTime.call(["2075","2","13","18","29","22"])=3317308162 +RESULT: jsDate(3317308162)=2075/2/13 18:29:22 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3317308162) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3348892777)=["2076","2","14","7","59","37"] +RESULT: timestampFromDateTime.call(["2076","2","14","7","59","37"])=3348892777 +RESULT: jsDate(3348892777)=2076/2/14 7:59:37 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3348892777) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3380941100)=["2077","2","19","6","18","20"] +RESULT: timestampFromDateTime.call(["2077","2","19","6","18","20"])=3380941100 +RESULT: jsDate(3380941100)=2077/2/19 6:18:20 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3380941100) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3412989424)=["2078","2","25","4","37","4"] +RESULT: timestampFromDateTime.call(["2078","2","25","4","37","4"])=3412989424 +RESULT: jsDate(3412989424)=2078/2/25 4:37:4 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3412989424) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3444574039)=["2079","2","25","18","7","19"] +RESULT: timestampFromDateTime.call(["2079","2","25","18","7","19"])=3444574039 +RESULT: jsDate(3444574039)=2079/2/25 18:7:19 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3444574039) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3476622362)=["2080","3","2","16","26","2"] +RESULT: timestampFromDateTime.call(["2080","3","2","16","26","2"])=3476622362 +RESULT: jsDate(3476622362)=2080/3/2 16:26:2 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3476622362) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3508670686)=["2081","3","8","14","44","46"] +RESULT: timestampFromDateTime.call(["2081","3","8","14","44","46"])=3508670686 +RESULT: jsDate(3508670686)=2081/3/8 14:44:46 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3508670686) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3540255301)=["2082","3","9","4","15","1"] +RESULT: timestampFromDateTime.call(["2082","3","9","4","15","1"])=3540255301 +RESULT: jsDate(3540255301)=2082/3/9 4:15:1 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3540255301) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3572303624)=["2083","3","15","2","33","44"] +RESULT: timestampFromDateTime.call(["2083","3","15","2","33","44"])=3572303624 +RESULT: jsDate(3572303624)=2083/3/15 2:33:44 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3572303624) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3604351948)=["2084","3","20","0","52","28"] +RESULT: timestampFromDateTime.call(["2084","3","20","0","52","28"])=3604351948 +RESULT: jsDate(3604351948)=2084/3/20 0:52:28 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3604351948) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3635936563)=["2085","3","20","14","22","43"] +RESULT: timestampFromDateTime.call(["2085","3","20","14","22","43"])=3635936563 +RESULT: jsDate(3635936563)=2085/3/20 14:22:43 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3635936563) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3667984886)=["2086","3","26","12","41","26"] +RESULT: timestampFromDateTime.call(["2086","3","26","12","41","26"])=3667984886 +RESULT: jsDate(3667984886)=2086/3/26 12:41:26 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3667984886) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3700033210)=["2087","4","1","11","0","10"] +RESULT: timestampFromDateTime.call(["2087","4","1","11","0","10"])=3700033210 +RESULT: jsDate(3700033210)=2087/4/1 11:0:10 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3700033210) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3731617825)=["2088","4","1","0","30","25"] +RESULT: timestampFromDateTime.call(["2088","4","1","0","30","25"])=3731617825 +RESULT: jsDate(3731617825)=2088/4/1 0:30:25 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3731617825) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3763666148)=["2089","4","6","22","49","8"] +RESULT: timestampFromDateTime.call(["2089","4","6","22","49","8"])=3763666148 +RESULT: jsDate(3763666148)=2089/4/6 22:49:8 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3763666148) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3795714472)=["2090","4","12","21","7","52"] +RESULT: timestampFromDateTime.call(["2090","4","12","21","7","52"])=3795714472 +RESULT: jsDate(3795714472)=2090/4/12 21:7:52 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3795714472) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3827299087)=["2091","4","13","10","38","7"] +RESULT: timestampFromDateTime.call(["2091","4","13","10","38","7"])=3827299087 +RESULT: jsDate(3827299087)=2091/4/13 10:38:7 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3827299087) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3859347410)=["2092","4","18","8","56","50"] +RESULT: timestampFromDateTime.call(["2092","4","18","8","56","50"])=3859347410 +RESULT: jsDate(3859347410)=2092/4/18 8:56:50 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3859347410) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3891395734)=["2093","4","24","7","15","34"] +RESULT: timestampFromDateTime.call(["2093","4","24","7","15","34"])=3891395734 +RESULT: jsDate(3891395734)=2093/4/24 7:15:34 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3891395734) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3922980349)=["2094","4","24","20","45","49"] +RESULT: timestampFromDateTime.call(["2094","4","24","20","45","49"])=3922980349 +RESULT: jsDate(3922980349)=2094/4/24 20:45:49 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3922980349) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3955028672)=["2095","4","30","19","4","32"] +RESULT: timestampFromDateTime.call(["2095","4","30","19","4","32"])=3955028672 +RESULT: jsDate(3955028672)=2095/4/30 19:4:32 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3955028672) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(3987076996)=["2096","5","5","17","23","16"] +RESULT: timestampFromDateTime.call(["2096","5","5","17","23","16"])=3987076996 +RESULT: jsDate(3987076996)=2096/5/5 17:23:16 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(3987076996) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4018661611)=["2097","5","6","6","53","31"] +RESULT: timestampFromDateTime.call(["2097","5","6","6","53","31"])=4018661611 +RESULT: jsDate(4018661611)=2097/5/6 6:53:31 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4018661611) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4050709934)=["2098","5","12","5","12","14"] +RESULT: timestampFromDateTime.call(["2098","5","12","5","12","14"])=4050709934 +RESULT: jsDate(4050709934)=2098/5/12 5:12:14 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4050709934) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4082758258)=["2099","5","18","3","30","58"] +RESULT: timestampFromDateTime.call(["2099","5","18","3","30","58"])=4082758258 +RESULT: jsDate(4082758258)=2099/5/18 3:30:58 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4082758258) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4114342873)=["2100","5","18","17","1","13"] +RESULT: timestampFromDateTime.call(["2100","5","18","17","1","13"])=4114342873 +RESULT: jsDate(4114342873)=2100/5/18 17:1:13 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4114342873) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4146391196)=["2101","5","24","15","19","56"] +RESULT: timestampFromDateTime.call(["2101","5","24","15","19","56"])=4146391196 +RESULT: jsDate(4146391196)=2101/5/24 15:19:56 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4146391196) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4178439520)=["2102","5","30","13","38","40"] +RESULT: timestampFromDateTime.call(["2102","5","30","13","38","40"])=4178439520 +RESULT: jsDate(4178439520)=2102/5/30 13:38:40 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4178439520) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4210024135)=["2103","5","31","3","8","55"] +RESULT: timestampFromDateTime.call(["2103","5","31","3","8","55"])=4210024135 +RESULT: jsDate(4210024135)=2103/5/31 3:8:55 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4210024135) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4242072458)=["2104","6","5","1","27","38"] +RESULT: timestampFromDateTime.call(["2104","6","5","1","27","38"])=4242072458 +RESULT: jsDate(4242072458)=2104/6/5 1:27:38 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4242072458) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4274120782)=["2105","6","10","23","46","22"] +RESULT: timestampFromDateTime.call(["2105","6","10","23","46","22"])=4274120782 +RESULT: jsDate(4274120782)=2105/6/10 23:46:22 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4274120782) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4305705397)=["2106","6","11","13","16","37"] +RESULT: timestampFromDateTime.call(["2106","6","11","13","16","37"])=4305705397 +RESULT: jsDate(4305705397)=2106/6/11 13:16:37 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4305705397) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4337753720)=["2107","6","17","11","35","20"] +RESULT: timestampFromDateTime.call(["2107","6","17","11","35","20"])=4337753720 +RESULT: jsDate(4337753720)=2107/6/17 11:35:20 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4337753720) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4369802044)=["2108","6","22","9","54","4"] +RESULT: timestampFromDateTime.call(["2108","6","22","9","54","4"])=4369802044 +RESULT: jsDate(4369802044)=2108/6/22 9:54:4 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4369802044) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4401386659)=["2109","6","22","23","24","19"] +RESULT: timestampFromDateTime.call(["2109","6","22","23","24","19"])=4401386659 +RESULT: jsDate(4401386659)=2109/6/22 23:24:19 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4401386659) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4433434982)=["2110","6","28","21","43","2"] +RESULT: timestampFromDateTime.call(["2110","6","28","21","43","2"])=4433434982 +RESULT: jsDate(4433434982)=2110/6/28 21:43:2 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4433434982) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4465483306)=["2111","7","4","20","1","46"] +RESULT: timestampFromDateTime.call(["2111","7","4","20","1","46"])=4465483306 +RESULT: jsDate(4465483306)=2111/7/4 20:1:46 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4465483306) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4497067921)=["2112","7","4","9","32","1"] +RESULT: timestampFromDateTime.call(["2112","7","4","9","32","1"])=4497067921 +RESULT: jsDate(4497067921)=2112/7/4 9:32:1 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4497067921) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4529116244)=["2113","7","10","7","50","44"] +RESULT: timestampFromDateTime.call(["2113","7","10","7","50","44"])=4529116244 +RESULT: jsDate(4529116244)=2113/7/10 7:50:44 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4529116244) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4561164568)=["2114","7","16","6","9","28"] +RESULT: timestampFromDateTime.call(["2114","7","16","6","9","28"])=4561164568 +RESULT: jsDate(4561164568)=2114/7/16 6:9:28 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4561164568) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4592749183)=["2115","7","16","19","39","43"] +RESULT: timestampFromDateTime.call(["2115","7","16","19","39","43"])=4592749183 +RESULT: jsDate(4592749183)=2115/7/16 19:39:43 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4592749183) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4624797506)=["2116","7","21","17","58","26"] +RESULT: timestampFromDateTime.call(["2116","7","21","17","58","26"])=4624797506 +RESULT: jsDate(4624797506)=2116/7/21 17:58:26 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4624797506) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4656845830)=["2117","7","27","16","17","10"] +RESULT: timestampFromDateTime.call(["2117","7","27","16","17","10"])=4656845830 +RESULT: jsDate(4656845830)=2117/7/27 16:17:10 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4656845830) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4688430445)=["2118","7","28","5","47","25"] +RESULT: timestampFromDateTime.call(["2118","7","28","5","47","25"])=4688430445 +RESULT: jsDate(4688430445)=2118/7/28 5:47:25 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4688430445) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4720478768)=["2119","8","3","4","6","8"] +RESULT: timestampFromDateTime.call(["2119","8","3","4","6","8"])=4720478768 +RESULT: jsDate(4720478768)=2119/8/3 4:6:8 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4720478768) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4752527092)=["2120","8","8","2","24","52"] +RESULT: timestampFromDateTime.call(["2120","8","8","2","24","52"])=4752527092 +RESULT: jsDate(4752527092)=2120/8/8 2:24:52 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4752527092) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4784111707)=["2121","8","8","15","55","7"] +RESULT: timestampFromDateTime.call(["2121","8","8","15","55","7"])=4784111707 +RESULT: jsDate(4784111707)=2121/8/8 15:55:7 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4784111707) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4816160030)=["2122","8","14","14","13","50"] +RESULT: timestampFromDateTime.call(["2122","8","14","14","13","50"])=4816160030 +RESULT: jsDate(4816160030)=2122/8/14 14:13:50 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4816160030) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4848208354)=["2123","8","20","12","32","34"] +RESULT: timestampFromDateTime.call(["2123","8","20","12","32","34"])=4848208354 +RESULT: jsDate(4848208354)=2123/8/20 12:32:34 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4848208354) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4879792969)=["2124","8","20","2","2","49"] +RESULT: timestampFromDateTime.call(["2124","8","20","2","2","49"])=4879792969 +RESULT: jsDate(4879792969)=2124/8/20 2:2:49 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4879792969) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4911841292)=["2125","8","26","0","21","32"] +RESULT: timestampFromDateTime.call(["2125","8","26","0","21","32"])=4911841292 +RESULT: jsDate(4911841292)=2125/8/26 0:21:32 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4911841292) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4943889616)=["2126","8","31","22","40","16"] +RESULT: timestampFromDateTime.call(["2126","8","31","22","40","16"])=4943889616 +RESULT: jsDate(4943889616)=2126/8/31 22:40:16 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4943889616) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(4975474231)=["2127","9","1","12","10","31"] +RESULT: timestampFromDateTime.call(["2127","9","1","12","10","31"])=4975474231 +RESULT: jsDate(4975474231)=2127/9/1 12:10:31 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(4975474231) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5007522554)=["2128","9","6","10","29","14"] +RESULT: timestampFromDateTime.call(["2128","9","6","10","29","14"])=5007522554 +RESULT: jsDate(5007522554)=2128/9/6 10:29:14 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5007522554) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5039570878)=["2129","9","12","8","47","58"] +RESULT: timestampFromDateTime.call(["2129","9","12","8","47","58"])=5039570878 +RESULT: jsDate(5039570878)=2129/9/12 8:47:58 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5039570878) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5071155493)=["2130","9","12","22","18","13"] +RESULT: timestampFromDateTime.call(["2130","9","12","22","18","13"])=5071155493 +RESULT: jsDate(5071155493)=2130/9/12 22:18:13 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5071155493) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5103203816)=["2131","9","18","20","36","56"] +RESULT: timestampFromDateTime.call(["2131","9","18","20","36","56"])=5103203816 +RESULT: jsDate(5103203816)=2131/9/18 20:36:56 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5103203816) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5135252140)=["2132","9","23","18","55","40"] +RESULT: timestampFromDateTime.call(["2132","9","23","18","55","40"])=5135252140 +RESULT: jsDate(5135252140)=2132/9/23 18:55:40 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5135252140) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5166836755)=["2133","9","24","8","25","55"] +RESULT: timestampFromDateTime.call(["2133","9","24","8","25","55"])=5166836755 +RESULT: jsDate(5166836755)=2133/9/24 8:25:55 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5166836755) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5198885078)=["2134","9","30","6","44","38"] +RESULT: timestampFromDateTime.call(["2134","9","30","6","44","38"])=5198885078 +RESULT: jsDate(5198885078)=2134/9/30 6:44:38 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5198885078) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5230933402)=["2135","10","6","5","3","22"] +RESULT: timestampFromDateTime.call(["2135","10","6","5","3","22"])=5230933402 +RESULT: jsDate(5230933402)=2135/10/6 5:3:22 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5230933402) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5262518017)=["2136","10","5","18","33","37"] +RESULT: timestampFromDateTime.call(["2136","10","5","18","33","37"])=5262518017 +RESULT: jsDate(5262518017)=2136/10/5 18:33:37 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5262518017) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5294566340)=["2137","10","11","16","52","20"] +RESULT: timestampFromDateTime.call(["2137","10","11","16","52","20"])=5294566340 +RESULT: jsDate(5294566340)=2137/10/11 16:52:20 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5294566340) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5326614664)=["2138","10","17","15","11","4"] +RESULT: timestampFromDateTime.call(["2138","10","17","15","11","4"])=5326614664 +RESULT: jsDate(5326614664)=2138/10/17 15:11:4 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5326614664) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5358199279)=["2139","10","18","4","41","19"] +RESULT: timestampFromDateTime.call(["2139","10","18","4","41","19"])=5358199279 +RESULT: jsDate(5358199279)=2139/10/18 4:41:19 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5358199279) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5390247602)=["2140","10","23","3","0","2"] +RESULT: timestampFromDateTime.call(["2140","10","23","3","0","2"])=5390247602 +RESULT: jsDate(5390247602)=2140/10/23 3:0:2 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5390247602) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5422295926)=["2141","10","29","1","18","46"] +RESULT: timestampFromDateTime.call(["2141","10","29","1","18","46"])=5422295926 +RESULT: jsDate(5422295926)=2141/10/29 1:18:46 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5422295926) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5453880541)=["2142","10","29","14","49","1"] +RESULT: timestampFromDateTime.call(["2142","10","29","14","49","1"])=5453880541 +RESULT: jsDate(5453880541)=2142/10/29 14:49:1 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5453880541) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5485928864)=["2143","11","4","13","7","44"] +RESULT: timestampFromDateTime.call(["2143","11","4","13","7","44"])=5485928864 +RESULT: jsDate(5485928864)=2143/11/4 13:7:44 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5485928864) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5517977188)=["2144","11","9","11","26","28"] +RESULT: timestampFromDateTime.call(["2144","11","9","11","26","28"])=5517977188 +RESULT: jsDate(5517977188)=2144/11/9 11:26:28 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5517977188) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5549561803)=["2145","11","10","0","56","43"] +RESULT: timestampFromDateTime.call(["2145","11","10","0","56","43"])=5549561803 +RESULT: jsDate(5549561803)=2145/11/10 0:56:43 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5549561803) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5581610126)=["2146","11","15","23","15","26"] +RESULT: timestampFromDateTime.call(["2146","11","15","23","15","26"])=5581610126 +RESULT: jsDate(5581610126)=2146/11/15 23:15:26 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5581610126) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5613658450)=["2147","11","21","21","34","10"] +RESULT: timestampFromDateTime.call(["2147","11","21","21","34","10"])=5613658450 +RESULT: jsDate(5613658450)=2147/11/21 21:34:10 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5613658450) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5645243065)=["2148","11","21","11","4","25"] +RESULT: timestampFromDateTime.call(["2148","11","21","11","4","25"])=5645243065 +RESULT: jsDate(5645243065)=2148/11/21 11:4:25 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5645243065) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5677291388)=["2149","11","27","9","23","8"] +RESULT: timestampFromDateTime.call(["2149","11","27","9","23","8"])=5677291388 +RESULT: jsDate(5677291388)=2149/11/27 9:23:8 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5677291388) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5709339712)=["2150","12","3","7","41","52"] +RESULT: timestampFromDateTime.call(["2150","12","3","7","41","52"])=5709339712 +RESULT: jsDate(5709339712)=2150/12/3 7:41:52 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5709339712) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5740924327)=["2151","12","3","21","12","7"] +RESULT: timestampFromDateTime.call(["2151","12","3","21","12","7"])=5740924327 +RESULT: jsDate(5740924327)=2151/12/3 21:12:7 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5740924327) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5772972650)=["2152","12","8","19","30","50"] +RESULT: timestampFromDateTime.call(["2152","12","8","19","30","50"])=5772972650 +RESULT: jsDate(5772972650)=2152/12/8 19:30:50 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5772972650) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5805020974)=["2153","12","14","17","49","34"] +RESULT: timestampFromDateTime.call(["2153","12","14","17","49","34"])=5805020974 +RESULT: jsDate(5805020974)=2153/12/14 17:49:34 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5805020974) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5836605589)=["2154","12","15","7","19","49"] +RESULT: timestampFromDateTime.call(["2154","12","15","7","19","49"])=5836605589 +RESULT: jsDate(5836605589)=2154/12/15 7:19:49 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5836605589) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5868653912)=["2155","12","21","5","38","32"] +RESULT: timestampFromDateTime.call(["2155","12","21","5","38","32"])=5868653912 +RESULT: jsDate(5868653912)=2155/12/21 5:38:32 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5868653912) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5900702236)=["2156","12","26","3","57","16"] +RESULT: timestampFromDateTime.call(["2156","12","26","3","57","16"])=5900702236 +RESULT: jsDate(5900702236)=2156/12/26 3:57:16 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5900702236) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5932286851)=["2157","12","26","17","27","31"] +RESULT: timestampFromDateTime.call(["2157","12","26","17","27","31"])=5932286851 +RESULT: jsDate(5932286851)=2157/12/26 17:27:31 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5932286851) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5964335174)=["2159","1","1","15","46","14"] +RESULT: timestampFromDateTime.call(["2159","1","1","15","46","14"])=5964335174 +RESULT: jsDate(5964335174)=2159/1/1 15:46:14 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5964335174) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(5996383498)=["2160","1","7","14","4","58"] +RESULT: timestampFromDateTime.call(["2160","1","7","14","4","58"])=5996383498 +RESULT: jsDate(5996383498)=2160/1/7 14:4:58 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(5996383498) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6027968113)=["2161","1","7","3","35","13"] +RESULT: timestampFromDateTime.call(["2161","1","7","3","35","13"])=6027968113 +RESULT: jsDate(6027968113)=2161/1/7 3:35:13 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6027968113) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6060016436)=["2162","1","13","1","53","56"] +RESULT: timestampFromDateTime.call(["2162","1","13","1","53","56"])=6060016436 +RESULT: jsDate(6060016436)=2162/1/13 1:53:56 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6060016436) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6092064760)=["2163","1","19","0","12","40"] +RESULT: timestampFromDateTime.call(["2163","1","19","0","12","40"])=6092064760 +RESULT: jsDate(6092064760)=2163/1/19 0:12:40 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6092064760) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6123649375)=["2164","1","19","13","42","55"] +RESULT: timestampFromDateTime.call(["2164","1","19","13","42","55"])=6123649375 +RESULT: jsDate(6123649375)=2164/1/19 13:42:55 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6123649375) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6155697698)=["2165","1","24","12","1","38"] +RESULT: timestampFromDateTime.call(["2165","1","24","12","1","38"])=6155697698 +RESULT: jsDate(6155697698)=2165/1/24 12:1:38 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6155697698) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6187746022)=["2166","1","30","10","20","22"] +RESULT: timestampFromDateTime.call(["2166","1","30","10","20","22"])=6187746022 +RESULT: jsDate(6187746022)=2166/1/30 10:20:22 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6187746022) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6219330637)=["2167","1","30","23","50","37"] +RESULT: timestampFromDateTime.call(["2167","1","30","23","50","37"])=6219330637 +RESULT: jsDate(6219330637)=2167/1/30 23:50:37 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6219330637) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6251378960)=["2168","2","5","22","9","20"] +RESULT: timestampFromDateTime.call(["2168","2","5","22","9","20"])=6251378960 +RESULT: jsDate(6251378960)=2168/2/5 22:9:20 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6251378960) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6283427284)=["2169","2","10","20","28","4"] +RESULT: timestampFromDateTime.call(["2169","2","10","20","28","4"])=6283427284 +RESULT: jsDate(6283427284)=2169/2/10 20:28:4 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6283427284) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6315011899)=["2170","2","11","9","58","19"] +RESULT: timestampFromDateTime.call(["2170","2","11","9","58","19"])=6315011899 +RESULT: jsDate(6315011899)=2170/2/11 9:58:19 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6315011899) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6347060222)=["2171","2","17","8","17","2"] +RESULT: timestampFromDateTime.call(["2171","2","17","8","17","2"])=6347060222 +RESULT: jsDate(6347060222)=2171/2/17 8:17:2 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6347060222) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6379108546)=["2172","2","23","6","35","46"] +RESULT: timestampFromDateTime.call(["2172","2","23","6","35","46"])=6379108546 +RESULT: jsDate(6379108546)=2172/2/23 6:35:46 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6379108546) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6410693161)=["2173","2","22","20","6","1"] +RESULT: timestampFromDateTime.call(["2173","2","22","20","6","1"])=6410693161 +RESULT: jsDate(6410693161)=2173/2/22 20:6:1 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6410693161) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6442741484)=["2174","2","28","18","24","44"] +RESULT: timestampFromDateTime.call(["2174","2","28","18","24","44"])=6442741484 +RESULT: jsDate(6442741484)=2174/2/28 18:24:44 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6442741484) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6474789808)=["2175","3","6","16","43","28"] +RESULT: timestampFromDateTime.call(["2175","3","6","16","43","28"])=6474789808 +RESULT: jsDate(6474789808)=2175/3/6 16:43:28 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6474789808) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6506374423)=["2176","3","6","6","13","43"] +RESULT: timestampFromDateTime.call(["2176","3","6","6","13","43"])=6506374423 +RESULT: jsDate(6506374423)=2176/3/6 6:13:43 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6506374423) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6538422746)=["2177","3","12","4","32","26"] +RESULT: timestampFromDateTime.call(["2177","3","12","4","32","26"])=6538422746 +RESULT: jsDate(6538422746)=2177/3/12 4:32:26 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6538422746) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6570471070)=["2178","3","18","2","51","10"] +RESULT: timestampFromDateTime.call(["2178","3","18","2","51","10"])=6570471070 +RESULT: jsDate(6570471070)=2178/3/18 2:51:10 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6570471070) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6602055685)=["2179","3","18","16","21","25"] +RESULT: timestampFromDateTime.call(["2179","3","18","16","21","25"])=6602055685 +RESULT: jsDate(6602055685)=2179/3/18 16:21:25 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6602055685) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6634104008)=["2180","3","23","14","40","8"] +RESULT: timestampFromDateTime.call(["2180","3","23","14","40","8"])=6634104008 +RESULT: jsDate(6634104008)=2180/3/23 14:40:8 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6634104008) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6666152332)=["2181","3","29","12","58","52"] +RESULT: timestampFromDateTime.call(["2181","3","29","12","58","52"])=6666152332 +RESULT: jsDate(6666152332)=2181/3/29 12:58:52 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6666152332) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6697736947)=["2182","3","30","2","29","7"] +RESULT: timestampFromDateTime.call(["2182","3","30","2","29","7"])=6697736947 +RESULT: jsDate(6697736947)=2182/3/30 2:29:7 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6697736947) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6729785270)=["2183","4","5","0","47","50"] +RESULT: timestampFromDateTime.call(["2183","4","5","0","47","50"])=6729785270 +RESULT: jsDate(6729785270)=2183/4/5 0:47:50 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6729785270) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6761833594)=["2184","4","9","23","6","34"] +RESULT: timestampFromDateTime.call(["2184","4","9","23","6","34"])=6761833594 +RESULT: jsDate(6761833594)=2184/4/9 23:6:34 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6761833594) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6793418209)=["2185","4","10","12","36","49"] +RESULT: timestampFromDateTime.call(["2185","4","10","12","36","49"])=6793418209 +RESULT: jsDate(6793418209)=2185/4/10 12:36:49 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6793418209) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6825466532)=["2186","4","16","10","55","32"] +RESULT: timestampFromDateTime.call(["2186","4","16","10","55","32"])=6825466532 +RESULT: jsDate(6825466532)=2186/4/16 10:55:32 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6825466532) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6857514856)=["2187","4","22","9","14","16"] +RESULT: timestampFromDateTime.call(["2187","4","22","9","14","16"])=6857514856 +RESULT: jsDate(6857514856)=2187/4/22 9:14:16 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6857514856) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6889099471)=["2188","4","21","22","44","31"] +RESULT: timestampFromDateTime.call(["2188","4","21","22","44","31"])=6889099471 +RESULT: jsDate(6889099471)=2188/4/21 22:44:31 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6889099471) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6921147794)=["2189","4","27","21","3","14"] +RESULT: timestampFromDateTime.call(["2189","4","27","21","3","14"])=6921147794 +RESULT: jsDate(6921147794)=2189/4/27 21:3:14 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6921147794) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6953196118)=["2190","5","3","19","21","58"] +RESULT: timestampFromDateTime.call(["2190","5","3","19","21","58"])=6953196118 +RESULT: jsDate(6953196118)=2190/5/3 19:21:58 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6953196118) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(6984780733)=["2191","5","4","8","52","13"] +RESULT: timestampFromDateTime.call(["2191","5","4","8","52","13"])=6984780733 +RESULT: jsDate(6984780733)=2191/5/4 8:52:13 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(6984780733) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7016829056)=["2192","5","9","7","10","56"] +RESULT: timestampFromDateTime.call(["2192","5","9","7","10","56"])=7016829056 +RESULT: jsDate(7016829056)=2192/5/9 7:10:56 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7016829056) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7048877380)=["2193","5","15","5","29","40"] +RESULT: timestampFromDateTime.call(["2193","5","15","5","29","40"])=7048877380 +RESULT: jsDate(7048877380)=2193/5/15 5:29:40 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7048877380) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7080461995)=["2194","5","15","18","59","55"] +RESULT: timestampFromDateTime.call(["2194","5","15","18","59","55"])=7080461995 +RESULT: jsDate(7080461995)=2194/5/15 18:59:55 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7080461995) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7112510318)=["2195","5","21","17","18","38"] +RESULT: timestampFromDateTime.call(["2195","5","21","17","18","38"])=7112510318 +RESULT: jsDate(7112510318)=2195/5/21 17:18:38 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7112510318) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7144558642)=["2196","5","26","15","37","22"] +RESULT: timestampFromDateTime.call(["2196","5","26","15","37","22"])=7144558642 +RESULT: jsDate(7144558642)=2196/5/26 15:37:22 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7144558642) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7176143257)=["2197","5","27","5","7","37"] +RESULT: timestampFromDateTime.call(["2197","5","27","5","7","37"])=7176143257 +RESULT: jsDate(7176143257)=2197/5/27 5:7:37 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7176143257) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7208191580)=["2198","6","2","3","26","20"] +RESULT: timestampFromDateTime.call(["2198","6","2","3","26","20"])=7208191580 +RESULT: jsDate(7208191580)=2198/6/2 3:26:20 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7208191580) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7240239904)=["2199","6","8","1","45","4"] +RESULT: timestampFromDateTime.call(["2199","6","8","1","45","4"])=7240239904 +RESULT: jsDate(7240239904)=2199/6/8 1:45:4 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7240239904) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7271824519)=["2200","6","8","15","15","19"] +RESULT: timestampFromDateTime.call(["2200","6","8","15","15","19"])=7271824519 +RESULT: jsDate(7271824519)=2200/6/8 15:15:19 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7271824519) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7303872842)=["2201","6","14","13","34","2"] +RESULT: timestampFromDateTime.call(["2201","6","14","13","34","2"])=7303872842 +RESULT: jsDate(7303872842)=2201/6/14 13:34:2 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7303872842) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7335921166)=["2202","6","20","11","52","46"] +RESULT: timestampFromDateTime.call(["2202","6","20","11","52","46"])=7335921166 +RESULT: jsDate(7335921166)=2202/6/20 11:52:46 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7335921166) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7367505781)=["2203","6","21","1","23","1"] +RESULT: timestampFromDateTime.call(["2203","6","21","1","23","1"])=7367505781 +RESULT: jsDate(7367505781)=2203/6/21 1:23:1 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7367505781) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7399554104)=["2204","6","25","23","41","44"] +RESULT: timestampFromDateTime.call(["2204","6","25","23","41","44"])=7399554104 +RESULT: jsDate(7399554104)=2204/6/25 23:41:44 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7399554104) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7431602428)=["2205","7","1","22","0","28"] +RESULT: timestampFromDateTime.call(["2205","7","1","22","0","28"])=7431602428 +RESULT: jsDate(7431602428)=2205/7/1 22:0:28 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7431602428) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7463187043)=["2206","7","2","11","30","43"] +RESULT: timestampFromDateTime.call(["2206","7","2","11","30","43"])=7463187043 +RESULT: jsDate(7463187043)=2206/7/2 11:30:43 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7463187043) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7495235366)=["2207","7","8","9","49","26"] +RESULT: timestampFromDateTime.call(["2207","7","8","9","49","26"])=7495235366 +RESULT: jsDate(7495235366)=2207/7/8 9:49:26 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7495235366) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7527283690)=["2208","7","13","8","8","10"] +RESULT: timestampFromDateTime.call(["2208","7","13","8","8","10"])=7527283690 +RESULT: jsDate(7527283690)=2208/7/13 8:8:10 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7527283690) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7558868305)=["2209","7","13","21","38","25"] +RESULT: timestampFromDateTime.call(["2209","7","13","21","38","25"])=7558868305 +RESULT: jsDate(7558868305)=2209/7/13 21:38:25 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7558868305) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7590916628)=["2210","7","19","19","57","8"] +RESULT: timestampFromDateTime.call(["2210","7","19","19","57","8"])=7590916628 +RESULT: jsDate(7590916628)=2210/7/19 19:57:8 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7590916628) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7622964952)=["2211","7","25","18","15","52"] +RESULT: timestampFromDateTime.call(["2211","7","25","18","15","52"])=7622964952 +RESULT: jsDate(7622964952)=2211/7/25 18:15:52 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7622964952) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7654549567)=["2212","7","25","7","46","7"] +RESULT: timestampFromDateTime.call(["2212","7","25","7","46","7"])=7654549567 +RESULT: jsDate(7654549567)=2212/7/25 7:46:7 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7654549567) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7686597890)=["2213","7","31","6","4","50"] +RESULT: timestampFromDateTime.call(["2213","7","31","6","4","50"])=7686597890 +RESULT: jsDate(7686597890)=2213/7/31 6:4:50 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7686597890) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7718646214)=["2214","8","6","4","23","34"] +RESULT: timestampFromDateTime.call(["2214","8","6","4","23","34"])=7718646214 +RESULT: jsDate(7718646214)=2214/8/6 4:23:34 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7718646214) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7750230829)=["2215","8","6","17","53","49"] +RESULT: timestampFromDateTime.call(["2215","8","6","17","53","49"])=7750230829 +RESULT: jsDate(7750230829)=2215/8/6 17:53:49 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7750230829) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7782279152)=["2216","8","11","16","12","32"] +RESULT: timestampFromDateTime.call(["2216","8","11","16","12","32"])=7782279152 +RESULT: jsDate(7782279152)=2216/8/11 16:12:32 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7782279152) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7814327476)=["2217","8","17","14","31","16"] +RESULT: timestampFromDateTime.call(["2217","8","17","14","31","16"])=7814327476 +RESULT: jsDate(7814327476)=2217/8/17 14:31:16 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7814327476) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7845912091)=["2218","8","18","4","1","31"] +RESULT: timestampFromDateTime.call(["2218","8","18","4","1","31"])=7845912091 +RESULT: jsDate(7845912091)=2218/8/18 4:1:31 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7845912091) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7877960414)=["2219","8","24","2","20","14"] +RESULT: timestampFromDateTime.call(["2219","8","24","2","20","14"])=7877960414 +RESULT: jsDate(7877960414)=2219/8/24 2:20:14 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7877960414) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7910008738)=["2220","8","29","0","38","58"] +RESULT: timestampFromDateTime.call(["2220","8","29","0","38","58"])=7910008738 +RESULT: jsDate(7910008738)=2220/8/29 0:38:58 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7910008738) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7941593353)=["2221","8","29","14","9","13"] +RESULT: timestampFromDateTime.call(["2221","8","29","14","9","13"])=7941593353 +RESULT: jsDate(7941593353)=2221/8/29 14:9:13 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7941593353) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(7973641676)=["2222","9","4","12","27","56"] +RESULT: timestampFromDateTime.call(["2222","9","4","12","27","56"])=7973641676 +RESULT: jsDate(7973641676)=2222/9/4 12:27:56 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(7973641676) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8005690000)=["2223","9","10","10","46","40"] +RESULT: timestampFromDateTime.call(["2223","9","10","10","46","40"])=8005690000 +RESULT: jsDate(8005690000)=2223/9/10 10:46:40 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8005690000) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8037274615)=["2224","9","10","0","16","55"] +RESULT: timestampFromDateTime.call(["2224","9","10","0","16","55"])=8037274615 +RESULT: jsDate(8037274615)=2224/9/10 0:16:55 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8037274615) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8069322938)=["2225","9","15","22","35","38"] +RESULT: timestampFromDateTime.call(["2225","9","15","22","35","38"])=8069322938 +RESULT: jsDate(8069322938)=2225/9/15 22:35:38 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8069322938) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8101371262)=["2226","9","21","20","54","22"] +RESULT: timestampFromDateTime.call(["2226","9","21","20","54","22"])=8101371262 +RESULT: jsDate(8101371262)=2226/9/21 20:54:22 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8101371262) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8132955877)=["2227","9","22","10","24","37"] +RESULT: timestampFromDateTime.call(["2227","9","22","10","24","37"])=8132955877 +RESULT: jsDate(8132955877)=2227/9/22 10:24:37 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8132955877) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8165004200)=["2228","9","27","8","43","20"] +RESULT: timestampFromDateTime.call(["2228","9","27","8","43","20"])=8165004200 +RESULT: jsDate(8165004200)=2228/9/27 8:43:20 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8165004200) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8197052524)=["2229","10","3","7","2","4"] +RESULT: timestampFromDateTime.call(["2229","10","3","7","2","4"])=8197052524 +RESULT: jsDate(8197052524)=2229/10/3 7:2:4 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8197052524) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8228637139)=["2230","10","3","20","32","19"] +RESULT: timestampFromDateTime.call(["2230","10","3","20","32","19"])=8228637139 +RESULT: jsDate(8228637139)=2230/10/3 20:32:19 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8228637139) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8260685462)=["2231","10","9","18","51","2"] +RESULT: timestampFromDateTime.call(["2231","10","9","18","51","2"])=8260685462 +RESULT: jsDate(8260685462)=2231/10/9 18:51:2 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8260685462) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8292733786)=["2232","10","14","17","9","46"] +RESULT: timestampFromDateTime.call(["2232","10","14","17","9","46"])=8292733786 +RESULT: jsDate(8292733786)=2232/10/14 17:9:46 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8292733786) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8324318401)=["2233","10","15","6","40","1"] +RESULT: timestampFromDateTime.call(["2233","10","15","6","40","1"])=8324318401 +RESULT: jsDate(8324318401)=2233/10/15 6:40:1 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8324318401) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8356366724)=["2234","10","21","4","58","44"] +RESULT: timestampFromDateTime.call(["2234","10","21","4","58","44"])=8356366724 +RESULT: jsDate(8356366724)=2234/10/21 4:58:44 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8356366724) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8388415048)=["2235","10","27","3","17","28"] +RESULT: timestampFromDateTime.call(["2235","10","27","3","17","28"])=8388415048 +RESULT: jsDate(8388415048)=2235/10/27 3:17:28 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8388415048) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8419999663)=["2236","10","26","16","47","43"] +RESULT: timestampFromDateTime.call(["2236","10","26","16","47","43"])=8419999663 +RESULT: jsDate(8419999663)=2236/10/26 16:47:43 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8419999663) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8452047986)=["2237","11","1","15","6","26"] +RESULT: timestampFromDateTime.call(["2237","11","1","15","6","26"])=8452047986 +RESULT: jsDate(8452047986)=2237/11/1 15:6:26 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8452047986) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8484096310)=["2238","11","7","13","25","10"] +RESULT: timestampFromDateTime.call(["2238","11","7","13","25","10"])=8484096310 +RESULT: jsDate(8484096310)=2238/11/7 13:25:10 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8484096310) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8515680925)=["2239","11","8","2","55","25"] +RESULT: timestampFromDateTime.call(["2239","11","8","2","55","25"])=8515680925 +RESULT: jsDate(8515680925)=2239/11/8 2:55:25 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8515680925) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8547729248)=["2240","11","13","1","14","8"] +RESULT: timestampFromDateTime.call(["2240","11","13","1","14","8"])=8547729248 +RESULT: jsDate(8547729248)=2240/11/13 1:14:8 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8547729248) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8579777572)=["2241","11","18","23","32","52"] +RESULT: timestampFromDateTime.call(["2241","11","18","23","32","52"])=8579777572 +RESULT: jsDate(8579777572)=2241/11/18 23:32:52 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8579777572) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8611362187)=["2242","11","19","13","3","7"] +RESULT: timestampFromDateTime.call(["2242","11","19","13","3","7"])=8611362187 +RESULT: jsDate(8611362187)=2242/11/19 13:3:7 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8611362187) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8643410510)=["2243","11","25","11","21","50"] +RESULT: timestampFromDateTime.call(["2243","11","25","11","21","50"])=8643410510 +RESULT: jsDate(8643410510)=2243/11/25 11:21:50 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8643410510) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8675458834)=["2244","11","30","9","40","34"] +RESULT: timestampFromDateTime.call(["2244","11","30","9","40","34"])=8675458834 +RESULT: jsDate(8675458834)=2244/11/30 9:40:34 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8675458834) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8707043449)=["2245","11","30","23","10","49"] +RESULT: timestampFromDateTime.call(["2245","11","30","23","10","49"])=8707043449 +RESULT: jsDate(8707043449)=2245/11/30 23:10:49 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8707043449) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8739091772)=["2246","12","6","21","29","32"] +RESULT: timestampFromDateTime.call(["2246","12","6","21","29","32"])=8739091772 +RESULT: jsDate(8739091772)=2246/12/6 21:29:32 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8739091772) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8771140096)=["2247","12","12","19","48","16"] +RESULT: timestampFromDateTime.call(["2247","12","12","19","48","16"])=8771140096 +RESULT: jsDate(8771140096)=2247/12/12 19:48:16 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8771140096) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8802724711)=["2248","12","12","9","18","31"] +RESULT: timestampFromDateTime.call(["2248","12","12","9","18","31"])=8802724711 +RESULT: jsDate(8802724711)=2248/12/12 9:18:31 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8802724711) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8834773034)=["2249","12","18","7","37","14"] +RESULT: timestampFromDateTime.call(["2249","12","18","7","37","14"])=8834773034 +RESULT: jsDate(8834773034)=2249/12/18 7:37:14 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8834773034) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8866821358)=["2250","12","24","5","55","58"] +RESULT: timestampFromDateTime.call(["2250","12","24","5","55","58"])=8866821358 +RESULT: jsDate(8866821358)=2250/12/24 5:55:58 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8866821358) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8898405973)=["2251","12","24","19","26","13"] +RESULT: timestampFromDateTime.call(["2251","12","24","19","26","13"])=8898405973 +RESULT: jsDate(8898405973)=2251/12/24 19:26:13 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8898405973) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8930454296)=["2252","12","29","17","44","56"] +RESULT: timestampFromDateTime.call(["2252","12","29","17","44","56"])=8930454296 +RESULT: jsDate(8930454296)=2252/12/29 17:44:56 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8930454296) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8962502620)=["2254","1","4","16","3","40"] +RESULT: timestampFromDateTime.call(["2254","1","4","16","3","40"])=8962502620 +RESULT: jsDate(8962502620)=2254/1/4 16:3:40 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8962502620) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(8994087235)=["2255","1","5","5","33","55"] +RESULT: timestampFromDateTime.call(["2255","1","5","5","33","55"])=8994087235 +RESULT: jsDate(8994087235)=2255/1/5 5:33:55 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(8994087235) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9026135558)=["2256","1","11","3","52","38"] +RESULT: timestampFromDateTime.call(["2256","1","11","3","52","38"])=9026135558 +RESULT: jsDate(9026135558)=2256/1/11 3:52:38 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9026135558) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9058183882)=["2257","1","16","2","11","22"] +RESULT: timestampFromDateTime.call(["2257","1","16","2","11","22"])=9058183882 +RESULT: jsDate(9058183882)=2257/1/16 2:11:22 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9058183882) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9089768497)=["2258","1","16","15","41","37"] +RESULT: timestampFromDateTime.call(["2258","1","16","15","41","37"])=9089768497 +RESULT: jsDate(9089768497)=2258/1/16 15:41:37 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9089768497) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9121816820)=["2259","1","22","14","0","20"] +RESULT: timestampFromDateTime.call(["2259","1","22","14","0","20"])=9121816820 +RESULT: jsDate(9121816820)=2259/1/22 14:0:20 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9121816820) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9153865144)=["2260","1","28","12","19","4"] +RESULT: timestampFromDateTime.call(["2260","1","28","12","19","4"])=9153865144 +RESULT: jsDate(9153865144)=2260/1/28 12:19:4 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9153865144) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9185449759)=["2261","1","28","1","49","19"] +RESULT: timestampFromDateTime.call(["2261","1","28","1","49","19"])=9185449759 +RESULT: jsDate(9185449759)=2261/1/28 1:49:19 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9185449759) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9217498082)=["2262","2","3","0","8","2"] +RESULT: timestampFromDateTime.call(["2262","2","3","0","8","2"])=9217498082 +RESULT: jsDate(9217498082)=2262/2/3 0:8:2 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9217498082) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9249546406)=["2263","2","8","22","26","46"] +RESULT: timestampFromDateTime.call(["2263","2","8","22","26","46"])=9249546406 +RESULT: jsDate(9249546406)=2263/2/8 22:26:46 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9249546406) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9281131021)=["2264","2","9","11","57","1"] +RESULT: timestampFromDateTime.call(["2264","2","9","11","57","1"])=9281131021 +RESULT: jsDate(9281131021)=2264/2/9 11:57:1 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9281131021) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9313179344)=["2265","2","14","10","15","44"] +RESULT: timestampFromDateTime.call(["2265","2","14","10","15","44"])=9313179344 +RESULT: jsDate(9313179344)=2265/2/14 10:15:44 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9313179344) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9345227668)=["2266","2","20","8","34","28"] +RESULT: timestampFromDateTime.call(["2266","2","20","8","34","28"])=9345227668 +RESULT: jsDate(9345227668)=2266/2/20 8:34:28 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9345227668) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9376812283)=["2267","2","20","22","4","43"] +RESULT: timestampFromDateTime.call(["2267","2","20","22","4","43"])=9376812283 +RESULT: jsDate(9376812283)=2267/2/20 22:4:43 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9376812283) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9408860606)=["2268","2","26","20","23","26"] +RESULT: timestampFromDateTime.call(["2268","2","26","20","23","26"])=9408860606 +RESULT: jsDate(9408860606)=2268/2/26 20:23:26 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9408860606) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9440908930)=["2269","3","3","18","42","10"] +RESULT: timestampFromDateTime.call(["2269","3","3","18","42","10"])=9440908930 +RESULT: jsDate(9440908930)=2269/3/3 18:42:10 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9440908930) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9472493545)=["2270","3","4","8","12","25"] +RESULT: timestampFromDateTime.call(["2270","3","4","8","12","25"])=9472493545 +RESULT: jsDate(9472493545)=2270/3/4 8:12:25 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9472493545) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9504541868)=["2271","3","10","6","31","8"] +RESULT: timestampFromDateTime.call(["2271","3","10","6","31","8"])=9504541868 +RESULT: jsDate(9504541868)=2271/3/10 6:31:8 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9504541868) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9536590192)=["2272","3","15","4","49","52"] +RESULT: timestampFromDateTime.call(["2272","3","15","4","49","52"])=9536590192 +RESULT: jsDate(9536590192)=2272/3/15 4:49:52 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9536590192) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9568174807)=["2273","3","15","18","20","7"] +RESULT: timestampFromDateTime.call(["2273","3","15","18","20","7"])=9568174807 +RESULT: jsDate(9568174807)=2273/3/15 18:20:7 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9568174807) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9600223130)=["2274","3","21","16","38","50"] +RESULT: timestampFromDateTime.call(["2274","3","21","16","38","50"])=9600223130 +RESULT: jsDate(9600223130)=2274/3/21 16:38:50 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9600223130) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9632271454)=["2275","3","27","14","57","34"] +RESULT: timestampFromDateTime.call(["2275","3","27","14","57","34"])=9632271454 +RESULT: jsDate(9632271454)=2275/3/27 14:57:34 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9632271454) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9663856069)=["2276","3","27","4","27","49"] +RESULT: timestampFromDateTime.call(["2276","3","27","4","27","49"])=9663856069 +RESULT: jsDate(9663856069)=2276/3/27 4:27:49 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9663856069) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9695904392)=["2277","4","2","2","46","32"] +RESULT: timestampFromDateTime.call(["2277","4","2","2","46","32"])=9695904392 +RESULT: jsDate(9695904392)=2277/4/2 2:46:32 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9695904392) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9727952716)=["2278","4","8","1","5","16"] +RESULT: timestampFromDateTime.call(["2278","4","8","1","5","16"])=9727952716 +RESULT: jsDate(9727952716)=2278/4/8 1:5:16 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9727952716) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9759537331)=["2279","4","8","14","35","31"] +RESULT: timestampFromDateTime.call(["2279","4","8","14","35","31"])=9759537331 +RESULT: jsDate(9759537331)=2279/4/8 14:35:31 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9759537331) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9791585654)=["2280","4","13","12","54","14"] +RESULT: timestampFromDateTime.call(["2280","4","13","12","54","14"])=9791585654 +RESULT: jsDate(9791585654)=2280/4/13 12:54:14 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9791585654) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9823633978)=["2281","4","19","11","12","58"] +RESULT: timestampFromDateTime.call(["2281","4","19","11","12","58"])=9823633978 +RESULT: jsDate(9823633978)=2281/4/19 11:12:58 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9823633978) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9855218593)=["2282","4","20","0","43","13"] +RESULT: timestampFromDateTime.call(["2282","4","20","0","43","13"])=9855218593 +RESULT: jsDate(9855218593)=2282/4/20 0:43:13 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9855218593) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9887266916)=["2283","4","25","23","1","56"] +RESULT: timestampFromDateTime.call(["2283","4","25","23","1","56"])=9887266916 +RESULT: jsDate(9887266916)=2283/4/25 23:1:56 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9887266916) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9919315240)=["2284","4","30","21","20","40"] +RESULT: timestampFromDateTime.call(["2284","4","30","21","20","40"])=9919315240 +RESULT: jsDate(9919315240)=2284/4/30 21:20:40 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9919315240) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9950899855)=["2285","5","1","10","50","55"] +RESULT: timestampFromDateTime.call(["2285","5","1","10","50","55"])=9950899855 +RESULT: jsDate(9950899855)=2285/5/1 10:50:55 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9950899855) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(9982948178)=["2286","5","7","9","9","38"] +RESULT: timestampFromDateTime.call(["2286","5","7","9","9","38"])=9982948178 +RESULT: jsDate(9982948178)=2286/5/7 9:9:38 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(9982948178) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10014996502)=["2287","5","13","7","28","22"] +RESULT: timestampFromDateTime.call(["2287","5","13","7","28","22"])=10014996502 +RESULT: jsDate(10014996502)=2287/5/13 7:28:22 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10014996502) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10046581117)=["2288","5","12","20","58","37"] +RESULT: timestampFromDateTime.call(["2288","5","12","20","58","37"])=10046581117 +RESULT: jsDate(10046581117)=2288/5/12 20:58:37 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10046581117) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10078629440)=["2289","5","18","19","17","20"] +RESULT: timestampFromDateTime.call(["2289","5","18","19","17","20"])=10078629440 +RESULT: jsDate(10078629440)=2289/5/18 19:17:20 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10078629440) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10110677764)=["2290","5","24","17","36","4"] +RESULT: timestampFromDateTime.call(["2290","5","24","17","36","4"])=10110677764 +RESULT: jsDate(10110677764)=2290/5/24 17:36:4 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10110677764) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10142262379)=["2291","5","25","7","6","19"] +RESULT: timestampFromDateTime.call(["2291","5","25","7","6","19"])=10142262379 +RESULT: jsDate(10142262379)=2291/5/25 7:6:19 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10142262379) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10174310702)=["2292","5","30","5","25","2"] +RESULT: timestampFromDateTime.call(["2292","5","30","5","25","2"])=10174310702 +RESULT: jsDate(10174310702)=2292/5/30 5:25:2 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10174310702) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10206359026)=["2293","6","5","3","43","46"] +RESULT: timestampFromDateTime.call(["2293","6","5","3","43","46"])=10206359026 +RESULT: jsDate(10206359026)=2293/6/5 3:43:46 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10206359026) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10237943641)=["2294","6","5","17","14","1"] +RESULT: timestampFromDateTime.call(["2294","6","5","17","14","1"])=10237943641 +RESULT: jsDate(10237943641)=2294/6/5 17:14:1 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10237943641) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10269991964)=["2295","6","11","15","32","44"] +RESULT: timestampFromDateTime.call(["2295","6","11","15","32","44"])=10269991964 +RESULT: jsDate(10269991964)=2295/6/11 15:32:44 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10269991964) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10302040288)=["2296","6","16","13","51","28"] +RESULT: timestampFromDateTime.call(["2296","6","16","13","51","28"])=10302040288 +RESULT: jsDate(10302040288)=2296/6/16 13:51:28 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10302040288) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10333624903)=["2297","6","17","3","21","43"] +RESULT: timestampFromDateTime.call(["2297","6","17","3","21","43"])=10333624903 +RESULT: jsDate(10333624903)=2297/6/17 3:21:43 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10333624903) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10365673226)=["2298","6","23","1","40","26"] +RESULT: timestampFromDateTime.call(["2298","6","23","1","40","26"])=10365673226 +RESULT: jsDate(10365673226)=2298/6/23 1:40:26 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10365673226) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10397721550)=["2299","6","28","23","59","10"] +RESULT: timestampFromDateTime.call(["2299","6","28","23","59","10"])=10397721550 +RESULT: jsDate(10397721550)=2299/6/28 23:59:10 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10397721550) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10429306165)=["2300","6","29","13","29","25"] +RESULT: timestampFromDateTime.call(["2300","6","29","13","29","25"])=10429306165 +RESULT: jsDate(10429306165)=2300/6/29 13:29:25 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10429306165) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10461354488)=["2301","7","5","11","48","8"] +RESULT: timestampFromDateTime.call(["2301","7","5","11","48","8"])=10461354488 +RESULT: jsDate(10461354488)=2301/7/5 11:48:8 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10461354488) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10493402812)=["2302","7","11","10","6","52"] +RESULT: timestampFromDateTime.call(["2302","7","11","10","6","52"])=10493402812 +RESULT: jsDate(10493402812)=2302/7/11 10:6:52 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10493402812) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10524987427)=["2303","7","11","23","37","7"] +RESULT: timestampFromDateTime.call(["2303","7","11","23","37","7"])=10524987427 +RESULT: jsDate(10524987427)=2303/7/11 23:37:7 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10524987427) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10557035750)=["2304","7","16","21","55","50"] +RESULT: timestampFromDateTime.call(["2304","7","16","21","55","50"])=10557035750 +RESULT: jsDate(10557035750)=2304/7/16 21:55:50 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10557035750) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10589084074)=["2305","7","22","20","14","34"] +RESULT: timestampFromDateTime.call(["2305","7","22","20","14","34"])=10589084074 +RESULT: jsDate(10589084074)=2305/7/22 20:14:34 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10589084074) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10620668689)=["2306","7","23","9","44","49"] +RESULT: timestampFromDateTime.call(["2306","7","23","9","44","49"])=10620668689 +RESULT: jsDate(10620668689)=2306/7/23 9:44:49 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10620668689) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10652717012)=["2307","7","29","8","3","32"] +RESULT: timestampFromDateTime.call(["2307","7","29","8","3","32"])=10652717012 +RESULT: jsDate(10652717012)=2307/7/29 8:3:32 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10652717012) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10684765336)=["2308","8","3","6","22","16"] +RESULT: timestampFromDateTime.call(["2308","8","3","6","22","16"])=10684765336 +RESULT: jsDate(10684765336)=2308/8/3 6:22:16 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10684765336) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10716349951)=["2309","8","3","19","52","31"] +RESULT: timestampFromDateTime.call(["2309","8","3","19","52","31"])=10716349951 +RESULT: jsDate(10716349951)=2309/8/3 19:52:31 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10716349951) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10748398274)=["2310","8","9","18","11","14"] +RESULT: timestampFromDateTime.call(["2310","8","9","18","11","14"])=10748398274 +RESULT: jsDate(10748398274)=2310/8/9 18:11:14 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10748398274) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10780446598)=["2311","8","15","16","29","58"] +RESULT: timestampFromDateTime.call(["2311","8","15","16","29","58"])=10780446598 +RESULT: jsDate(10780446598)=2311/8/15 16:29:58 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10780446598) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10812031213)=["2312","8","15","6","0","13"] +RESULT: timestampFromDateTime.call(["2312","8","15","6","0","13"])=10812031213 +RESULT: jsDate(10812031213)=2312/8/15 6:0:13 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10812031213) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10844079536)=["2313","8","21","4","18","56"] +RESULT: timestampFromDateTime.call(["2313","8","21","4","18","56"])=10844079536 +RESULT: jsDate(10844079536)=2313/8/21 4:18:56 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10844079536) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10876127860)=["2314","8","27","2","37","40"] +RESULT: timestampFromDateTime.call(["2314","8","27","2","37","40"])=10876127860 +RESULT: jsDate(10876127860)=2314/8/27 2:37:40 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10876127860) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10907712475)=["2315","8","27","16","7","55"] +RESULT: timestampFromDateTime.call(["2315","8","27","16","7","55"])=10907712475 +RESULT: jsDate(10907712475)=2315/8/27 16:7:55 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10907712475) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10939760798)=["2316","9","1","14","26","38"] +RESULT: timestampFromDateTime.call(["2316","9","1","14","26","38"])=10939760798 +RESULT: jsDate(10939760798)=2316/9/1 14:26:38 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10939760798) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(10971809122)=["2317","9","7","12","45","22"] +RESULT: timestampFromDateTime.call(["2317","9","7","12","45","22"])=10971809122 +RESULT: jsDate(10971809122)=2317/9/7 12:45:22 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(10971809122) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11003393737)=["2318","9","8","2","15","37"] +RESULT: timestampFromDateTime.call(["2318","9","8","2","15","37"])=11003393737 +RESULT: jsDate(11003393737)=2318/9/8 2:15:37 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11003393737) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11035442060)=["2319","9","14","0","34","20"] +RESULT: timestampFromDateTime.call(["2319","9","14","0","34","20"])=11035442060 +RESULT: jsDate(11035442060)=2319/9/14 0:34:20 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11035442060) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11067490384)=["2320","9","18","22","53","4"] +RESULT: timestampFromDateTime.call(["2320","9","18","22","53","4"])=11067490384 +RESULT: jsDate(11067490384)=2320/9/18 22:53:4 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11067490384) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11099074999)=["2321","9","19","12","23","19"] +RESULT: timestampFromDateTime.call(["2321","9","19","12","23","19"])=11099074999 +RESULT: jsDate(11099074999)=2321/9/19 12:23:19 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11099074999) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11131123322)=["2322","9","25","10","42","2"] +RESULT: timestampFromDateTime.call(["2322","9","25","10","42","2"])=11131123322 +RESULT: jsDate(11131123322)=2322/9/25 10:42:2 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11131123322) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11163171646)=["2323","10","1","9","0","46"] +RESULT: timestampFromDateTime.call(["2323","10","1","9","0","46"])=11163171646 +RESULT: jsDate(11163171646)=2323/10/1 9:0:46 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11163171646) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11194756261)=["2324","9","30","22","31","1"] +RESULT: timestampFromDateTime.call(["2324","9","30","22","31","1"])=11194756261 +RESULT: jsDate(11194756261)=2324/9/30 22:31:1 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11194756261) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11226804584)=["2325","10","6","20","49","44"] +RESULT: timestampFromDateTime.call(["2325","10","6","20","49","44"])=11226804584 +RESULT: jsDate(11226804584)=2325/10/6 20:49:44 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11226804584) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11258852908)=["2326","10","12","19","8","28"] +RESULT: timestampFromDateTime.call(["2326","10","12","19","8","28"])=11258852908 +RESULT: jsDate(11258852908)=2326/10/12 19:8:28 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11258852908) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11290437523)=["2327","10","13","8","38","43"] +RESULT: timestampFromDateTime.call(["2327","10","13","8","38","43"])=11290437523 +RESULT: jsDate(11290437523)=2327/10/13 8:38:43 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11290437523) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11322485846)=["2328","10","18","6","57","26"] +RESULT: timestampFromDateTime.call(["2328","10","18","6","57","26"])=11322485846 +RESULT: jsDate(11322485846)=2328/10/18 6:57:26 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11322485846) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11354534170)=["2329","10","24","5","16","10"] +RESULT: timestampFromDateTime.call(["2329","10","24","5","16","10"])=11354534170 +RESULT: jsDate(11354534170)=2329/10/24 5:16:10 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11354534170) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11386118785)=["2330","10","24","18","46","25"] +RESULT: timestampFromDateTime.call(["2330","10","24","18","46","25"])=11386118785 +RESULT: jsDate(11386118785)=2330/10/24 18:46:25 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11386118785) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11418167108)=["2331","10","30","17","5","8"] +RESULT: timestampFromDateTime.call(["2331","10","30","17","5","8"])=11418167108 +RESULT: jsDate(11418167108)=2331/10/30 17:5:8 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11418167108) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11450215432)=["2332","11","4","15","23","52"] +RESULT: timestampFromDateTime.call(["2332","11","4","15","23","52"])=11450215432 +RESULT: jsDate(11450215432)=2332/11/4 15:23:52 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11450215432) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11481800047)=["2333","11","5","4","54","7"] +RESULT: timestampFromDateTime.call(["2333","11","5","4","54","7"])=11481800047 +RESULT: jsDate(11481800047)=2333/11/5 4:54:7 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11481800047) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11513848370)=["2334","11","11","3","12","50"] +RESULT: timestampFromDateTime.call(["2334","11","11","3","12","50"])=11513848370 +RESULT: jsDate(11513848370)=2334/11/11 3:12:50 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11513848370) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11545896694)=["2335","11","17","1","31","34"] +RESULT: timestampFromDateTime.call(["2335","11","17","1","31","34"])=11545896694 +RESULT: jsDate(11545896694)=2335/11/17 1:31:34 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11545896694) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11577481309)=["2336","11","16","15","1","49"] +RESULT: timestampFromDateTime.call(["2336","11","16","15","1","49"])=11577481309 +RESULT: jsDate(11577481309)=2336/11/16 15:1:49 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11577481309) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11609529632)=["2337","11","22","13","20","32"] +RESULT: timestampFromDateTime.call(["2337","11","22","13","20","32"])=11609529632 +RESULT: jsDate(11609529632)=2337/11/22 13:20:32 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11609529632) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11641577956)=["2338","11","28","11","39","16"] +RESULT: timestampFromDateTime.call(["2338","11","28","11","39","16"])=11641577956 +RESULT: jsDate(11641577956)=2338/11/28 11:39:16 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11641577956) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11673162571)=["2339","11","29","1","9","31"] +RESULT: timestampFromDateTime.call(["2339","11","29","1","9","31"])=11673162571 +RESULT: jsDate(11673162571)=2339/11/29 1:9:31 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11673162571) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11705210894)=["2340","12","3","23","28","14"] +RESULT: timestampFromDateTime.call(["2340","12","3","23","28","14"])=11705210894 +RESULT: jsDate(11705210894)=2340/12/3 23:28:14 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11705210894) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11737259218)=["2341","12","9","21","46","58"] +RESULT: timestampFromDateTime.call(["2341","12","9","21","46","58"])=11737259218 +RESULT: jsDate(11737259218)=2341/12/9 21:46:58 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11737259218) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11768843833)=["2342","12","10","11","17","13"] +RESULT: timestampFromDateTime.call(["2342","12","10","11","17","13"])=11768843833 +RESULT: jsDate(11768843833)=2342/12/10 11:17:13 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11768843833) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11800892156)=["2343","12","16","9","35","56"] +RESULT: timestampFromDateTime.call(["2343","12","16","9","35","56"])=11800892156 +RESULT: jsDate(11800892156)=2343/12/16 9:35:56 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11800892156) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11832940480)=["2344","12","21","7","54","40"] +RESULT: timestampFromDateTime.call(["2344","12","21","7","54","40"])=11832940480 +RESULT: jsDate(11832940480)=2344/12/21 7:54:40 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11832940480) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11864525095)=["2345","12","21","21","24","55"] +RESULT: timestampFromDateTime.call(["2345","12","21","21","24","55"])=11864525095 +RESULT: jsDate(11864525095)=2345/12/21 21:24:55 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11864525095) => timestampFromDateTime.call(...) matches +RESULT: +RESULT: timestampToDateTime.call(11896573418)=["2346","12","27","19","43","38"] +RESULT: timestampFromDateTime.call(["2346","12","27","19","43","38"])=11896573418 +RESULT: jsDate(11896573418)=2346/12/27 19:43:38 +RESULT: PASS jsDate matches +RESULT: PASS timestampToDateTime.call(11896573418) => timestampFromDateTime.call(...) matches +RESULT: +undefined +> +> +... +... +... +... +RESULT: ---------- PASS - no failures detected ---------- +undefined +> +> +> diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1results.txt b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1results.txt new file mode 100644 index 0000000..dff152a --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1results.txt @@ -0,0 +1,2422 @@ + # Account EtherBalanceChange Token Name +-- ------------------------------------------ --------------------------- ------------------------------ --------------------------- + 0 0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e 0.000000000000000000 0.000000000000000000 Account #0 - Miner + 1 0xa11aae29840fbb5c86e6fd4cf809eba183aef433 0.000000000000000000 0.000000000000000000 Account #1 - Contract Owner + 2 0xa22ab8a9d641ce77e06d98b7d7065d324d3d6976 0.000000000000000000 0.000000000000000000 Account #2 - Alice + 3 0xa33a6c312d9ad0e0f2e95541beed0cc081621fd0 0.000000000000000000 0.000000000000000000 Account #3 - Bob + 4 0xa44a08d3f6933c69212114bb66e2df1813651844 0.000000000000000000 0.000000000000000000 Account #4 - Carol + 5 0xa55a151eb00fded1634d27d1127b4be4627079ea 0.000000000000000000 0.000000000000000000 Account #5 - Dave + 6 0xa66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 0.000000000000000000 0.000000000000000000 Account #6 + 7 0xa77a2b9d4b1c010a22a7c565dc418cef683dbcec 0.000000000000000000 0.000000000000000000 Account #7 + 8 0xa88a05d2b88283ce84c8325760b72a64591279a2 0.000000000000000000 0.000000000000000000 Account #8 + 9 0xa99a0ae3354c06b1459fd441a32a3f71005d7da0 0.000000000000000000 0.000000000000000000 Account #9 +10 0xaaaa9de1e6c564446ebca0fd102d8bd92093c756 0.000000000000000000 0.000000000000000000 Account #10 +11 0xabba43e7594e3b76afb157989e93c6621497fd4b 0.000000000000000000 0.000000000000000000 Account #11 +-- ------------------------------------------ --------------------------- ------------------------------ --------------------------- + 0.000000000000000000 Total Token Balances +-- ------------------------------------------ --------------------------- ------------------------------ --------------------------- + + +----- Deploy DateTime Library ----- + # Account EtherBalanceChange Token Name +-- ------------------------------------------ --------------------------- ------------------------------ --------------------------- + 0 0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e 0.001150736000000000 0.000000000000000000 Account #0 - Miner + 1 0xa11aae29840fbb5c86e6fd4cf809eba183aef433 -0.001150736000000000 0.000000000000000000 Account #1 - Contract Owner + 2 0xa22ab8a9d641ce77e06d98b7d7065d324d3d6976 0.000000000000000000 0.000000000000000000 Account #2 - Alice + 3 0xa33a6c312d9ad0e0f2e95541beed0cc081621fd0 0.000000000000000000 0.000000000000000000 Account #3 - Bob + 4 0xa44a08d3f6933c69212114bb66e2df1813651844 0.000000000000000000 0.000000000000000000 Account #4 - Carol + 5 0xa55a151eb00fded1634d27d1127b4be4627079ea 0.000000000000000000 0.000000000000000000 Account #5 - Dave + 6 0xa66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 0.000000000000000000 0.000000000000000000 Account #6 + 7 0xa77a2b9d4b1c010a22a7c565dc418cef683dbcec 0.000000000000000000 0.000000000000000000 Account #7 + 8 0xa88a05d2b88283ce84c8325760b72a64591279a2 0.000000000000000000 0.000000000000000000 Account #8 + 9 0xa99a0ae3354c06b1459fd441a32a3f71005d7da0 0.000000000000000000 0.000000000000000000 Account #9 +10 0xaaaa9de1e6c564446ebca0fd102d8bd92093c756 0.000000000000000000 0.000000000000000000 Account #10 +11 0xabba43e7594e3b76afb157989e93c6621497fd4b 0.000000000000000000 0.000000000000000000 Account #11 +12 0x90d8927407c79c4a28ee879b821c76fc9bcc2688 0.000000000000000000 0.000000000000000000 DateTime Library +-- ------------------------------------------ --------------------------- ------------------------------ --------------------------- + 0.000000000000000000 Total Token Balances +-- ------------------------------------------ --------------------------- ------------------------------ --------------------------- + +PASS Deploy DateTime Library +dateTimeLibTx status=0x1 Success gas=6000000 gasUsed=71921 costETH=0.001150736 costUSD=0.77756382256 @ ETH/USD=675.71 gasPrice=16 gwei block=19 txIx=0 txId=0x3d6e997266a4df7a6d24ad8461a47646aa30ac31435f55bc7f8d22226d67cd14 @ 1579355189 Sat, 18 Jan 2020 13:46:29 UTC + +---------- Deploy TestDateTime Contract ---------- + # Account EtherBalanceChange Token Name +-- ------------------------------------------ --------------------------- ------------------------------ --------------------------- + 0 0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e 0.016965312000000000 0.000000000000000000 Account #0 - Miner + 1 0xa11aae29840fbb5c86e6fd4cf809eba183aef433 -0.016965312000000000 0.000000000000000000 Account #1 - Contract Owner + 2 0xa22ab8a9d641ce77e06d98b7d7065d324d3d6976 0.000000000000000000 0.000000000000000000 Account #2 - Alice + 3 0xa33a6c312d9ad0e0f2e95541beed0cc081621fd0 0.000000000000000000 0.000000000000000000 Account #3 - Bob + 4 0xa44a08d3f6933c69212114bb66e2df1813651844 0.000000000000000000 0.000000000000000000 Account #4 - Carol + 5 0xa55a151eb00fded1634d27d1127b4be4627079ea 0.000000000000000000 0.000000000000000000 Account #5 - Dave + 6 0xa66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 0.000000000000000000 0.000000000000000000 Account #6 + 7 0xa77a2b9d4b1c010a22a7c565dc418cef683dbcec 0.000000000000000000 0.000000000000000000 Account #7 + 8 0xa88a05d2b88283ce84c8325760b72a64591279a2 0.000000000000000000 0.000000000000000000 Account #8 + 9 0xa99a0ae3354c06b1459fd441a32a3f71005d7da0 0.000000000000000000 0.000000000000000000 Account #9 +10 0xaaaa9de1e6c564446ebca0fd102d8bd92093c756 0.000000000000000000 0.000000000000000000 Account #10 +11 0xabba43e7594e3b76afb157989e93c6621497fd4b 0.000000000000000000 0.000000000000000000 Account #11 +12 0x90d8927407c79c4a28ee879b821c76fc9bcc2688 0.000000000000000000 0.000000000000000000 DateTime Library +13 0x0e946b999033257976aa5cbe0e3530618ca1582d 0.000000000000000000 0.000000000000000000 TestDateTime +-- ------------------------------------------ --------------------------- ------------------------------ --------------------------- + 0.000000000000000000 Total Token Balances +-- ------------------------------------------ --------------------------- ------------------------------ --------------------------- + +PASS Deploy TestDateTime Contract +testDateTimeAddress=0x0e946b999033257976aa5cbe0e3530618ca1582d status=0x1 Success gas=6000000 gasUsed=988411 costETH=0.015814576 costUSD=10.68606714896 @ ETH/USD=675.71 gasPrice=16 gwei block=21 txIx=0 txId=0xdb67f4d0ee1587cd570fc563c69f73dcaffc9f2f4047a1d1792218bb920fbd58 @ 1579355191 Sat, 18 Jan 2020 13:46:31 UTC + +---------- Test isLeapYear ---------- +PASS 2000,5,24,1,2,3 is a leap year +PASS 2100,5,24,1,2,3 is a not leap year +PASS 2104,5,24,1,2,3 is a leap year + +---------- Test isValidDate and isValidDateTime.call ---------- +PASS testDateTime.isValidDate.call(1969, 1, 1) is false +PASS testDateTime.isValidDate.call(1970, 1, 1) is true +PASS testDateTime.isValidDate.call(2000, 2, 29) is true +PASS testDateTime.isValidDate.call(2001, 2, 29) is false +PASS testDateTime.isValidDate.call(2001, 0, 1) is false +PASS testDateTime.isValidDate.call(2001, 1, 0) is false +PASS testDateTime.isValidDateTime.call(2000, 2, 29, 0, 0, 0) is true +PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 1) is true +PASS testDateTime.isValidDateTime.call(2000, 2, 29, 23, 1, 1) is true +PASS testDateTime.isValidDateTime.call(2000, 2, 29, 24, 1, 1) is false +PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 59, 1) is true +PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 60, 1) is false +PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 59) is true +PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 60) is false + +---------- Test _isLeapYear ---------- +PASS 2000 is a leap year +PASS 2100 is a not leap year +PASS 2104 is a leap year + +---------- Test isWeekDay ---------- +PASS 2018,5,24,1,2,3 is a week day +PASS 2018,5,25,1,2,3 is a week day +PASS 2018,5,26,1,2,3 is a not week day + +---------- Test isWeekEnd ---------- +PASS 2018,5,24,1,2,3 is a not a week end +PASS 2018,5,25,1,2,3 is a not a week end +PASS 2018,5,26,1,2,3 is a week end +PASS 2018,5,27,1,2,3 is a week end + +---------- Test getDaysInMonth ---------- +PASS 2000,1,24,1,2,3 has 31 days +PASS 2000,2,24,1,2,3 has 29 days +PASS 2001,2,24,1,2,3 has 28 days +PASS 2000,3,24,1,2,3 has 31 days +PASS 2000,4,24,1,2,3 has 30 days +PASS 2000,5,24,1,2,3 has 31 days +PASS 2000,6,24,1,2,3 has 30 days +PASS 2000,7,24,1,2,3 has 31 days +PASS 2000,8,24,1,2,3 has 31 days +PASS 2000,9,24,1,2,3 has 30 days +PASS 2000,10,24,1,2,3 has 31 days +PASS 2000,11,24,1,2,3 has 30 days +PASS 2000,12,24,1,2,3 has 31 days + +---------- Test _getDaysInMonth ---------- +PASS 2000/01 has 31 days +PASS 2000/02 has 29 days +PASS 2001/02 has 28 days +PASS 2000/03 has 31 days +PASS 2000/04 has 30 days +PASS 2000/05 has 31 days +PASS 2000/06 has 30 days +PASS 2000/07 has 31 days +PASS 2000/08 has 31 days +PASS 2000/09 has 30 days +PASS 2000/10 has 31 days +PASS 2000/11 has 30 days +PASS 2000/12 has 31 days + +---------- Test getDayOfWeek ---------- +PASS 2018,5,21,1,2,3 is 1 Monday +PASS 2018,5,24,1,2,3 is 4 Thursday +PASS 2018,5,26,1,2,3 is 6 Saturday +PASS 2018,5,27,1,2,3 is 7 Sunday + +---------- Test get* ---------- +PASS 2018,5,21,1,2,3 year is 2018 +PASS 2018,5,21,1,2,3 month is 5 May +PASS 2018,5,21,1,2,3 day is 21 +PASS 2018,5,21,1,2,3 hour is 1 +PASS 2018,5,21,1,2,3 minute is 2 +PASS 2018,5,21,1,2,3 second is 3 + +---------- Test add{Years|Months|Days|Hours|Minutes|Seconds} ---------- +PASS 2000,2,29,1,2,3 + 3 years is 2003/02/28 01:02:03 +PASS 2018,12,31,2,3,4 + 30 years is 2048/12/31 02:03:04 +PASS 2000,1,31,1,2,3 + 37 months is 2003/02/28 01:02:03 +PASS 2018,12,1,2,3,4 + 362 months is 2049/02/01 02:03:04 +PASS 2017,1,31,1,2,3 + 37,532 days is 2119/11/05 01:02:03 +PASS 2017,1,31,1,2,3 + 900,768 hours is 2119/11/05 01:02:03 +PASS 2017,1,31,1,2,3 + 781,920 minutes is 2018/07/28 01:02:03 +PASS 2017,1,31,1,2,3 + 461,548,800 seconds is 2031/09/17 01:02:03 + +---------- Test sub{Years|Months|Days|Hours|Minutes|Seconds} ---------- +PASS 2000,2,29,1,2,3 - 3 years is 1997/02/28 01:02:03 +PASS 2000,2,29,1,2,3 - 37 months is 1997/01/29 01:02:03 +PASS 2013,1,1,1,2,3 - 3,756 days is 2002/09/20 01:02:03 +PASS 2013,1,1,1,2,3 - 3,756 * 24 hours is 2002/09/20 01:02:03 +PASS 2015,7,15,1,2,3 - 223,776 hours is 1990/01/03 01:02:03 +PASS 2018,3,1,2,3,4 - 21,600,000 minutes is 1977/02/04 02:03:04 +PASS 2020,3,19,3,4,5 - 788,227,200 seconds is 1995/03/28 03:04:05 + +---------- Test diff{Years|Months|Days|Hours|Minutes|Seconds} ---------- +fromTimestamp=1508547723 2017,10,21,1,2,3 +toTimestamp=1563422706 2019,7,18,4,5,6 +PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 2 years diff +PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 21 months diff +PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 635 days diff +PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 15,243 hours diff +PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 914,583 minutes diff +PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 54,874,983 seconds diff + +---------- Test timestampToDateTime.call(...) and timestampFromDateTime.call(...) against JavaScript Date ---------- +timestampToDateTime.call(48611)=["1970","1","1","13","30","11"] +timestampFromDateTime.call(["1970","1","1","13","30","11"])=48611 +jsDate(48611)=1970/1/1 13:30:11 +PASS jsDate matches +PASS timestampToDateTime.call(48611) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(32096934)=["1971","1","7","11","48","54"] +timestampFromDateTime.call(["1971","1","7","11","48","54"])=32096934 +jsDate(32096934)=1971/1/7 11:48:54 +PASS jsDate matches +PASS timestampToDateTime.call(32096934) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(64145254)=["1972","1","13","10","7","34"] +timestampFromDateTime.call(["1972","1","13","10","7","34"])=64145254 +jsDate(64145254)=1972/1/13 10:7:34 +PASS jsDate matches +PASS timestampToDateTime.call(64145254) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(95729869)=["1973","1","12","23","37","49"] +timestampFromDateTime.call(["1973","1","12","23","37","49"])=95729869 +jsDate(95729869)=1973/1/12 23:37:49 +PASS jsDate matches +PASS timestampToDateTime.call(95729869) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(127778192)=["1974","1","18","21","56","32"] +timestampFromDateTime.call(["1974","1","18","21","56","32"])=127778192 +jsDate(127778192)=1974/1/18 21:56:32 +PASS jsDate matches +PASS timestampToDateTime.call(127778192) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(159826516)=["1975","1","24","20","15","16"] +timestampFromDateTime.call(["1975","1","24","20","15","16"])=159826516 +jsDate(159826516)=1975/1/24 20:15:16 +PASS jsDate matches +PASS timestampToDateTime.call(159826516) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(191411131)=["1976","1","25","9","45","31"] +timestampFromDateTime.call(["1976","1","25","9","45","31"])=191411131 +jsDate(191411131)=1976/1/25 9:45:31 +PASS jsDate matches +PASS timestampToDateTime.call(191411131) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(223459454)=["1977","1","30","8","4","14"] +timestampFromDateTime.call(["1977","1","30","8","4","14"])=223459454 +jsDate(223459454)=1977/1/30 8:4:14 +PASS jsDate matches +PASS timestampToDateTime.call(223459454) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(255507778)=["1978","2","5","6","22","58"] +timestampFromDateTime.call(["1978","2","5","6","22","58"])=255507778 +jsDate(255507778)=1978/2/5 6:22:58 +PASS jsDate matches +PASS timestampToDateTime.call(255507778) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(287092393)=["1979","2","5","19","53","13"] +timestampFromDateTime.call(["1979","2","5","19","53","13"])=287092393 +jsDate(287092393)=1979/2/5 19:53:13 +PASS jsDate matches +PASS timestampToDateTime.call(287092393) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(319140716)=["1980","2","11","18","11","56"] +timestampFromDateTime.call(["1980","2","11","18","11","56"])=319140716 +jsDate(319140716)=1980/2/11 18:11:56 +PASS jsDate matches +PASS timestampToDateTime.call(319140716) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(351189040)=["1981","2","16","16","30","40"] +timestampFromDateTime.call(["1981","2","16","16","30","40"])=351189040 +jsDate(351189040)=1981/2/16 16:30:40 +PASS jsDate matches +PASS timestampToDateTime.call(351189040) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(382773655)=["1982","2","17","6","0","55"] +timestampFromDateTime.call(["1982","2","17","6","0","55"])=382773655 +jsDate(382773655)=1982/2/17 6:0:55 +PASS jsDate matches +PASS timestampToDateTime.call(382773655) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(414821978)=["1983","2","23","4","19","38"] +timestampFromDateTime.call(["1983","2","23","4","19","38"])=414821978 +jsDate(414821978)=1983/2/23 4:19:38 +PASS jsDate matches +PASS timestampToDateTime.call(414821978) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(446870302)=["1984","2","29","2","38","22"] +timestampFromDateTime.call(["1984","2","29","2","38","22"])=446870302 +jsDate(446870302)=1984/2/29 2:38:22 +PASS jsDate matches +PASS timestampToDateTime.call(446870302) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(478454917)=["1985","2","28","16","8","37"] +timestampFromDateTime.call(["1985","2","28","16","8","37"])=478454917 +jsDate(478454917)=1985/2/28 16:8:37 +PASS jsDate matches +PASS timestampToDateTime.call(478454917) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(510503240)=["1986","3","6","14","27","20"] +timestampFromDateTime.call(["1986","3","6","14","27","20"])=510503240 +jsDate(510503240)=1986/3/6 14:27:20 +PASS jsDate matches +PASS timestampToDateTime.call(510503240) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(542551564)=["1987","3","12","12","46","4"] +timestampFromDateTime.call(["1987","3","12","12","46","4"])=542551564 +jsDate(542551564)=1987/3/12 12:46:4 +PASS jsDate matches +PASS timestampToDateTime.call(542551564) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(574136179)=["1988","3","12","2","16","19"] +timestampFromDateTime.call(["1988","3","12","2","16","19"])=574136179 +jsDate(574136179)=1988/3/12 2:16:19 +PASS jsDate matches +PASS timestampToDateTime.call(574136179) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(606184502)=["1989","3","18","0","35","2"] +timestampFromDateTime.call(["1989","3","18","0","35","2"])=606184502 +jsDate(606184502)=1989/3/18 0:35:2 +PASS jsDate matches +PASS timestampToDateTime.call(606184502) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(638232826)=["1990","3","23","22","53","46"] +timestampFromDateTime.call(["1990","3","23","22","53","46"])=638232826 +jsDate(638232826)=1990/3/23 22:53:46 +PASS jsDate matches +PASS timestampToDateTime.call(638232826) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(669817441)=["1991","3","24","12","24","1"] +timestampFromDateTime.call(["1991","3","24","12","24","1"])=669817441 +jsDate(669817441)=1991/3/24 12:24:1 +PASS jsDate matches +PASS timestampToDateTime.call(669817441) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(701865764)=["1992","3","29","10","42","44"] +timestampFromDateTime.call(["1992","3","29","10","42","44"])=701865764 +jsDate(701865764)=1992/3/29 10:42:44 +PASS jsDate matches +PASS timestampToDateTime.call(701865764) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(733914088)=["1993","4","4","9","1","28"] +timestampFromDateTime.call(["1993","4","4","9","1","28"])=733914088 +jsDate(733914088)=1993/4/4 9:1:28 +PASS jsDate matches +PASS timestampToDateTime.call(733914088) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(765498703)=["1994","4","4","22","31","43"] +timestampFromDateTime.call(["1994","4","4","22","31","43"])=765498703 +jsDate(765498703)=1994/4/4 22:31:43 +PASS jsDate matches +PASS timestampToDateTime.call(765498703) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(797547026)=["1995","4","10","20","50","26"] +timestampFromDateTime.call(["1995","4","10","20","50","26"])=797547026 +jsDate(797547026)=1995/4/10 20:50:26 +PASS jsDate matches +PASS timestampToDateTime.call(797547026) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(829595350)=["1996","4","15","19","9","10"] +timestampFromDateTime.call(["1996","4","15","19","9","10"])=829595350 +jsDate(829595350)=1996/4/15 19:9:10 +PASS jsDate matches +PASS timestampToDateTime.call(829595350) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(861179965)=["1997","4","16","8","39","25"] +timestampFromDateTime.call(["1997","4","16","8","39","25"])=861179965 +jsDate(861179965)=1997/4/16 8:39:25 +PASS jsDate matches +PASS timestampToDateTime.call(861179965) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(893228288)=["1998","4","22","6","58","8"] +timestampFromDateTime.call(["1998","4","22","6","58","8"])=893228288 +jsDate(893228288)=1998/4/22 6:58:8 +PASS jsDate matches +PASS timestampToDateTime.call(893228288) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(925276612)=["1999","4","28","5","16","52"] +timestampFromDateTime.call(["1999","4","28","5","16","52"])=925276612 +jsDate(925276612)=1999/4/28 5:16:52 +PASS jsDate matches +PASS timestampToDateTime.call(925276612) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(956861227)=["2000","4","27","18","47","7"] +timestampFromDateTime.call(["2000","4","27","18","47","7"])=956861227 +jsDate(956861227)=2000/4/27 18:47:7 +PASS jsDate matches +PASS timestampToDateTime.call(956861227) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(988909550)=["2001","5","3","17","5","50"] +timestampFromDateTime.call(["2001","5","3","17","5","50"])=988909550 +jsDate(988909550)=2001/5/3 17:5:50 +PASS jsDate matches +PASS timestampToDateTime.call(988909550) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1020957874)=["2002","5","9","15","24","34"] +timestampFromDateTime.call(["2002","5","9","15","24","34"])=1020957874 +jsDate(1020957874)=2002/5/9 15:24:34 +PASS jsDate matches +PASS timestampToDateTime.call(1020957874) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1052542489)=["2003","5","10","4","54","49"] +timestampFromDateTime.call(["2003","5","10","4","54","49"])=1052542489 +jsDate(1052542489)=2003/5/10 4:54:49 +PASS jsDate matches +PASS timestampToDateTime.call(1052542489) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1084590812)=["2004","5","15","3","13","32"] +timestampFromDateTime.call(["2004","5","15","3","13","32"])=1084590812 +jsDate(1084590812)=2004/5/15 3:13:32 +PASS jsDate matches +PASS timestampToDateTime.call(1084590812) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1116639136)=["2005","5","21","1","32","16"] +timestampFromDateTime.call(["2005","5","21","1","32","16"])=1116639136 +jsDate(1116639136)=2005/5/21 1:32:16 +PASS jsDate matches +PASS timestampToDateTime.call(1116639136) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1148223751)=["2006","5","21","15","2","31"] +timestampFromDateTime.call(["2006","5","21","15","2","31"])=1148223751 +jsDate(1148223751)=2006/5/21 15:2:31 +PASS jsDate matches +PASS timestampToDateTime.call(1148223751) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1180272074)=["2007","5","27","13","21","14"] +timestampFromDateTime.call(["2007","5","27","13","21","14"])=1180272074 +jsDate(1180272074)=2007/5/27 13:21:14 +PASS jsDate matches +PASS timestampToDateTime.call(1180272074) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1212320398)=["2008","6","1","11","39","58"] +timestampFromDateTime.call(["2008","6","1","11","39","58"])=1212320398 +jsDate(1212320398)=2008/6/1 11:39:58 +PASS jsDate matches +PASS timestampToDateTime.call(1212320398) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1243905013)=["2009","6","2","1","10","13"] +timestampFromDateTime.call(["2009","6","2","1","10","13"])=1243905013 +jsDate(1243905013)=2009/6/2 1:10:13 +PASS jsDate matches +PASS timestampToDateTime.call(1243905013) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1275953336)=["2010","6","7","23","28","56"] +timestampFromDateTime.call(["2010","6","7","23","28","56"])=1275953336 +jsDate(1275953336)=2010/6/7 23:28:56 +PASS jsDate matches +PASS timestampToDateTime.call(1275953336) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1308001660)=["2011","6","13","21","47","40"] +timestampFromDateTime.call(["2011","6","13","21","47","40"])=1308001660 +jsDate(1308001660)=2011/6/13 21:47:40 +PASS jsDate matches +PASS timestampToDateTime.call(1308001660) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1339586275)=["2012","6","13","11","17","55"] +timestampFromDateTime.call(["2012","6","13","11","17","55"])=1339586275 +jsDate(1339586275)=2012/6/13 11:17:55 +PASS jsDate matches +PASS timestampToDateTime.call(1339586275) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1371634598)=["2013","6","19","9","36","38"] +timestampFromDateTime.call(["2013","6","19","9","36","38"])=1371634598 +jsDate(1371634598)=2013/6/19 9:36:38 +PASS jsDate matches +PASS timestampToDateTime.call(1371634598) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1403682922)=["2014","6","25","7","55","22"] +timestampFromDateTime.call(["2014","6","25","7","55","22"])=1403682922 +jsDate(1403682922)=2014/6/25 7:55:22 +PASS jsDate matches +PASS timestampToDateTime.call(1403682922) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1435267537)=["2015","6","25","21","25","37"] +timestampFromDateTime.call(["2015","6","25","21","25","37"])=1435267537 +jsDate(1435267537)=2015/6/25 21:25:37 +PASS jsDate matches +PASS timestampToDateTime.call(1435267537) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1467315860)=["2016","6","30","19","44","20"] +timestampFromDateTime.call(["2016","6","30","19","44","20"])=1467315860 +jsDate(1467315860)=2016/6/30 19:44:20 +PASS jsDate matches +PASS timestampToDateTime.call(1467315860) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1499364184)=["2017","7","6","18","3","4"] +timestampFromDateTime.call(["2017","7","6","18","3","4"])=1499364184 +jsDate(1499364184)=2017/7/6 18:3:4 +PASS jsDate matches +PASS timestampToDateTime.call(1499364184) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1530948799)=["2018","7","7","7","33","19"] +timestampFromDateTime.call(["2018","7","7","7","33","19"])=1530948799 +jsDate(1530948799)=2018/7/7 7:33:19 +PASS jsDate matches +PASS timestampToDateTime.call(1530948799) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1562997122)=["2019","7","13","5","52","2"] +timestampFromDateTime.call(["2019","7","13","5","52","2"])=1562997122 +jsDate(1562997122)=2019/7/13 5:52:2 +PASS jsDate matches +PASS timestampToDateTime.call(1562997122) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1595045446)=["2020","7","18","4","10","46"] +timestampFromDateTime.call(["2020","7","18","4","10","46"])=1595045446 +jsDate(1595045446)=2020/7/18 4:10:46 +PASS jsDate matches +PASS timestampToDateTime.call(1595045446) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1626630061)=["2021","7","18","17","41","1"] +timestampFromDateTime.call(["2021","7","18","17","41","1"])=1626630061 +jsDate(1626630061)=2021/7/18 17:41:1 +PASS jsDate matches +PASS timestampToDateTime.call(1626630061) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1658678384)=["2022","7","24","15","59","44"] +timestampFromDateTime.call(["2022","7","24","15","59","44"])=1658678384 +jsDate(1658678384)=2022/7/24 15:59:44 +PASS jsDate matches +PASS timestampToDateTime.call(1658678384) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1690726708)=["2023","7","30","14","18","28"] +timestampFromDateTime.call(["2023","7","30","14","18","28"])=1690726708 +jsDate(1690726708)=2023/7/30 14:18:28 +PASS jsDate matches +PASS timestampToDateTime.call(1690726708) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1722311323)=["2024","7","30","3","48","43"] +timestampFromDateTime.call(["2024","7","30","3","48","43"])=1722311323 +jsDate(1722311323)=2024/7/30 3:48:43 +PASS jsDate matches +PASS timestampToDateTime.call(1722311323) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1754359646)=["2025","8","5","2","7","26"] +timestampFromDateTime.call(["2025","8","5","2","7","26"])=1754359646 +jsDate(1754359646)=2025/8/5 2:7:26 +PASS jsDate matches +PASS timestampToDateTime.call(1754359646) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1786407970)=["2026","8","11","0","26","10"] +timestampFromDateTime.call(["2026","8","11","0","26","10"])=1786407970 +jsDate(1786407970)=2026/8/11 0:26:10 +PASS jsDate matches +PASS timestampToDateTime.call(1786407970) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1817992585)=["2027","8","11","13","56","25"] +timestampFromDateTime.call(["2027","8","11","13","56","25"])=1817992585 +jsDate(1817992585)=2027/8/11 13:56:25 +PASS jsDate matches +PASS timestampToDateTime.call(1817992585) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1850040908)=["2028","8","16","12","15","8"] +timestampFromDateTime.call(["2028","8","16","12","15","8"])=1850040908 +jsDate(1850040908)=2028/8/16 12:15:8 +PASS jsDate matches +PASS timestampToDateTime.call(1850040908) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1882089232)=["2029","8","22","10","33","52"] +timestampFromDateTime.call(["2029","8","22","10","33","52"])=1882089232 +jsDate(1882089232)=2029/8/22 10:33:52 +PASS jsDate matches +PASS timestampToDateTime.call(1882089232) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1913673847)=["2030","8","23","0","4","7"] +timestampFromDateTime.call(["2030","8","23","0","4","7"])=1913673847 +jsDate(1913673847)=2030/8/23 0:4:7 +PASS jsDate matches +PASS timestampToDateTime.call(1913673847) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1945722170)=["2031","8","28","22","22","50"] +timestampFromDateTime.call(["2031","8","28","22","22","50"])=1945722170 +jsDate(1945722170)=2031/8/28 22:22:50 +PASS jsDate matches +PASS timestampToDateTime.call(1945722170) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(1977770494)=["2032","9","2","20","41","34"] +timestampFromDateTime.call(["2032","9","2","20","41","34"])=1977770494 +jsDate(1977770494)=2032/9/2 20:41:34 +PASS jsDate matches +PASS timestampToDateTime.call(1977770494) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2009355109)=["2033","9","3","10","11","49"] +timestampFromDateTime.call(["2033","9","3","10","11","49"])=2009355109 +jsDate(2009355109)=2033/9/3 10:11:49 +PASS jsDate matches +PASS timestampToDateTime.call(2009355109) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2041403432)=["2034","9","9","8","30","32"] +timestampFromDateTime.call(["2034","9","9","8","30","32"])=2041403432 +jsDate(2041403432)=2034/9/9 8:30:32 +PASS jsDate matches +PASS timestampToDateTime.call(2041403432) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2073451756)=["2035","9","15","6","49","16"] +timestampFromDateTime.call(["2035","9","15","6","49","16"])=2073451756 +jsDate(2073451756)=2035/9/15 6:49:16 +PASS jsDate matches +PASS timestampToDateTime.call(2073451756) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2105036371)=["2036","9","14","20","19","31"] +timestampFromDateTime.call(["2036","9","14","20","19","31"])=2105036371 +jsDate(2105036371)=2036/9/14 20:19:31 +PASS jsDate matches +PASS timestampToDateTime.call(2105036371) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2137084694)=["2037","9","20","18","38","14"] +timestampFromDateTime.call(["2037","9","20","18","38","14"])=2137084694 +jsDate(2137084694)=2037/9/20 18:38:14 +PASS jsDate matches +PASS timestampToDateTime.call(2137084694) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2169133018)=["2038","9","26","16","56","58"] +timestampFromDateTime.call(["2038","9","26","16","56","58"])=2169133018 +jsDate(2169133018)=2038/9/26 16:56:58 +PASS jsDate matches +PASS timestampToDateTime.call(2169133018) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2200717633)=["2039","9","27","6","27","13"] +timestampFromDateTime.call(["2039","9","27","6","27","13"])=2200717633 +jsDate(2200717633)=2039/9/27 6:27:13 +PASS jsDate matches +PASS timestampToDateTime.call(2200717633) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2232765956)=["2040","10","2","4","45","56"] +timestampFromDateTime.call(["2040","10","2","4","45","56"])=2232765956 +jsDate(2232765956)=2040/10/2 4:45:56 +PASS jsDate matches +PASS timestampToDateTime.call(2232765956) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2264814280)=["2041","10","8","3","4","40"] +timestampFromDateTime.call(["2041","10","8","3","4","40"])=2264814280 +jsDate(2264814280)=2041/10/8 3:4:40 +PASS jsDate matches +PASS timestampToDateTime.call(2264814280) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2296398895)=["2042","10","8","16","34","55"] +timestampFromDateTime.call(["2042","10","8","16","34","55"])=2296398895 +jsDate(2296398895)=2042/10/8 16:34:55 +PASS jsDate matches +PASS timestampToDateTime.call(2296398895) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2328447218)=["2043","10","14","14","53","38"] +timestampFromDateTime.call(["2043","10","14","14","53","38"])=2328447218 +jsDate(2328447218)=2043/10/14 14:53:38 +PASS jsDate matches +PASS timestampToDateTime.call(2328447218) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2360495542)=["2044","10","19","13","12","22"] +timestampFromDateTime.call(["2044","10","19","13","12","22"])=2360495542 +jsDate(2360495542)=2044/10/19 13:12:22 +PASS jsDate matches +PASS timestampToDateTime.call(2360495542) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2392080157)=["2045","10","20","2","42","37"] +timestampFromDateTime.call(["2045","10","20","2","42","37"])=2392080157 +jsDate(2392080157)=2045/10/20 2:42:37 +PASS jsDate matches +PASS timestampToDateTime.call(2392080157) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2424128480)=["2046","10","26","1","1","20"] +timestampFromDateTime.call(["2046","10","26","1","1","20"])=2424128480 +jsDate(2424128480)=2046/10/26 1:1:20 +PASS jsDate matches +PASS timestampToDateTime.call(2424128480) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2456176804)=["2047","10","31","23","20","4"] +timestampFromDateTime.call(["2047","10","31","23","20","4"])=2456176804 +jsDate(2456176804)=2047/10/31 23:20:4 +PASS jsDate matches +PASS timestampToDateTime.call(2456176804) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2487761419)=["2048","10","31","12","50","19"] +timestampFromDateTime.call(["2048","10","31","12","50","19"])=2487761419 +jsDate(2487761419)=2048/10/31 12:50:19 +PASS jsDate matches +PASS timestampToDateTime.call(2487761419) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2519809742)=["2049","11","6","11","9","2"] +timestampFromDateTime.call(["2049","11","6","11","9","2"])=2519809742 +jsDate(2519809742)=2049/11/6 11:9:2 +PASS jsDate matches +PASS timestampToDateTime.call(2519809742) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2551858066)=["2050","11","12","9","27","46"] +timestampFromDateTime.call(["2050","11","12","9","27","46"])=2551858066 +jsDate(2551858066)=2050/11/12 9:27:46 +PASS jsDate matches +PASS timestampToDateTime.call(2551858066) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2583442681)=["2051","11","12","22","58","1"] +timestampFromDateTime.call(["2051","11","12","22","58","1"])=2583442681 +jsDate(2583442681)=2051/11/12 22:58:1 +PASS jsDate matches +PASS timestampToDateTime.call(2583442681) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2615491004)=["2052","11","17","21","16","44"] +timestampFromDateTime.call(["2052","11","17","21","16","44"])=2615491004 +jsDate(2615491004)=2052/11/17 21:16:44 +PASS jsDate matches +PASS timestampToDateTime.call(2615491004) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2647539328)=["2053","11","23","19","35","28"] +timestampFromDateTime.call(["2053","11","23","19","35","28"])=2647539328 +jsDate(2647539328)=2053/11/23 19:35:28 +PASS jsDate matches +PASS timestampToDateTime.call(2647539328) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2679123943)=["2054","11","24","9","5","43"] +timestampFromDateTime.call(["2054","11","24","9","5","43"])=2679123943 +jsDate(2679123943)=2054/11/24 9:5:43 +PASS jsDate matches +PASS timestampToDateTime.call(2679123943) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2711172266)=["2055","11","30","7","24","26"] +timestampFromDateTime.call(["2055","11","30","7","24","26"])=2711172266 +jsDate(2711172266)=2055/11/30 7:24:26 +PASS jsDate matches +PASS timestampToDateTime.call(2711172266) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2743220590)=["2056","12","5","5","43","10"] +timestampFromDateTime.call(["2056","12","5","5","43","10"])=2743220590 +jsDate(2743220590)=2056/12/5 5:43:10 +PASS jsDate matches +PASS timestampToDateTime.call(2743220590) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2774805205)=["2057","12","5","19","13","25"] +timestampFromDateTime.call(["2057","12","5","19","13","25"])=2774805205 +jsDate(2774805205)=2057/12/5 19:13:25 +PASS jsDate matches +PASS timestampToDateTime.call(2774805205) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2806853528)=["2058","12","11","17","32","8"] +timestampFromDateTime.call(["2058","12","11","17","32","8"])=2806853528 +jsDate(2806853528)=2058/12/11 17:32:8 +PASS jsDate matches +PASS timestampToDateTime.call(2806853528) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2838901852)=["2059","12","17","15","50","52"] +timestampFromDateTime.call(["2059","12","17","15","50","52"])=2838901852 +jsDate(2838901852)=2059/12/17 15:50:52 +PASS jsDate matches +PASS timestampToDateTime.call(2838901852) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2870486467)=["2060","12","17","5","21","7"] +timestampFromDateTime.call(["2060","12","17","5","21","7"])=2870486467 +jsDate(2870486467)=2060/12/17 5:21:7 +PASS jsDate matches +PASS timestampToDateTime.call(2870486467) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2902534790)=["2061","12","23","3","39","50"] +timestampFromDateTime.call(["2061","12","23","3","39","50"])=2902534790 +jsDate(2902534790)=2061/12/23 3:39:50 +PASS jsDate matches +PASS timestampToDateTime.call(2902534790) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2934583114)=["2062","12","29","1","58","34"] +timestampFromDateTime.call(["2062","12","29","1","58","34"])=2934583114 +jsDate(2934583114)=2062/12/29 1:58:34 +PASS jsDate matches +PASS timestampToDateTime.call(2934583114) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2966167729)=["2063","12","29","15","28","49"] +timestampFromDateTime.call(["2063","12","29","15","28","49"])=2966167729 +jsDate(2966167729)=2063/12/29 15:28:49 +PASS jsDate matches +PASS timestampToDateTime.call(2966167729) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(2998216052)=["2065","1","3","13","47","32"] +timestampFromDateTime.call(["2065","1","3","13","47","32"])=2998216052 +jsDate(2998216052)=2065/1/3 13:47:32 +PASS jsDate matches +PASS timestampToDateTime.call(2998216052) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3030264376)=["2066","1","9","12","6","16"] +timestampFromDateTime.call(["2066","1","9","12","6","16"])=3030264376 +jsDate(3030264376)=2066/1/9 12:6:16 +PASS jsDate matches +PASS timestampToDateTime.call(3030264376) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3061848991)=["2067","1","10","1","36","31"] +timestampFromDateTime.call(["2067","1","10","1","36","31"])=3061848991 +jsDate(3061848991)=2067/1/10 1:36:31 +PASS jsDate matches +PASS timestampToDateTime.call(3061848991) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3093897314)=["2068","1","15","23","55","14"] +timestampFromDateTime.call(["2068","1","15","23","55","14"])=3093897314 +jsDate(3093897314)=2068/1/15 23:55:14 +PASS jsDate matches +PASS timestampToDateTime.call(3093897314) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3125945638)=["2069","1","20","22","13","58"] +timestampFromDateTime.call(["2069","1","20","22","13","58"])=3125945638 +jsDate(3125945638)=2069/1/20 22:13:58 +PASS jsDate matches +PASS timestampToDateTime.call(3125945638) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3157530253)=["2070","1","21","11","44","13"] +timestampFromDateTime.call(["2070","1","21","11","44","13"])=3157530253 +jsDate(3157530253)=2070/1/21 11:44:13 +PASS jsDate matches +PASS timestampToDateTime.call(3157530253) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3189578576)=["2071","1","27","10","2","56"] +timestampFromDateTime.call(["2071","1","27","10","2","56"])=3189578576 +jsDate(3189578576)=2071/1/27 10:2:56 +PASS jsDate matches +PASS timestampToDateTime.call(3189578576) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3221626900)=["2072","2","2","8","21","40"] +timestampFromDateTime.call(["2072","2","2","8","21","40"])=3221626900 +jsDate(3221626900)=2072/2/2 8:21:40 +PASS jsDate matches +PASS timestampToDateTime.call(3221626900) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3253211515)=["2073","2","1","21","51","55"] +timestampFromDateTime.call(["2073","2","1","21","51","55"])=3253211515 +jsDate(3253211515)=2073/2/1 21:51:55 +PASS jsDate matches +PASS timestampToDateTime.call(3253211515) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3285259838)=["2074","2","7","20","10","38"] +timestampFromDateTime.call(["2074","2","7","20","10","38"])=3285259838 +jsDate(3285259838)=2074/2/7 20:10:38 +PASS jsDate matches +PASS timestampToDateTime.call(3285259838) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3317308162)=["2075","2","13","18","29","22"] +timestampFromDateTime.call(["2075","2","13","18","29","22"])=3317308162 +jsDate(3317308162)=2075/2/13 18:29:22 +PASS jsDate matches +PASS timestampToDateTime.call(3317308162) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3348892777)=["2076","2","14","7","59","37"] +timestampFromDateTime.call(["2076","2","14","7","59","37"])=3348892777 +jsDate(3348892777)=2076/2/14 7:59:37 +PASS jsDate matches +PASS timestampToDateTime.call(3348892777) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3380941100)=["2077","2","19","6","18","20"] +timestampFromDateTime.call(["2077","2","19","6","18","20"])=3380941100 +jsDate(3380941100)=2077/2/19 6:18:20 +PASS jsDate matches +PASS timestampToDateTime.call(3380941100) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3412989424)=["2078","2","25","4","37","4"] +timestampFromDateTime.call(["2078","2","25","4","37","4"])=3412989424 +jsDate(3412989424)=2078/2/25 4:37:4 +PASS jsDate matches +PASS timestampToDateTime.call(3412989424) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3444574039)=["2079","2","25","18","7","19"] +timestampFromDateTime.call(["2079","2","25","18","7","19"])=3444574039 +jsDate(3444574039)=2079/2/25 18:7:19 +PASS jsDate matches +PASS timestampToDateTime.call(3444574039) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3476622362)=["2080","3","2","16","26","2"] +timestampFromDateTime.call(["2080","3","2","16","26","2"])=3476622362 +jsDate(3476622362)=2080/3/2 16:26:2 +PASS jsDate matches +PASS timestampToDateTime.call(3476622362) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3508670686)=["2081","3","8","14","44","46"] +timestampFromDateTime.call(["2081","3","8","14","44","46"])=3508670686 +jsDate(3508670686)=2081/3/8 14:44:46 +PASS jsDate matches +PASS timestampToDateTime.call(3508670686) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3540255301)=["2082","3","9","4","15","1"] +timestampFromDateTime.call(["2082","3","9","4","15","1"])=3540255301 +jsDate(3540255301)=2082/3/9 4:15:1 +PASS jsDate matches +PASS timestampToDateTime.call(3540255301) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3572303624)=["2083","3","15","2","33","44"] +timestampFromDateTime.call(["2083","3","15","2","33","44"])=3572303624 +jsDate(3572303624)=2083/3/15 2:33:44 +PASS jsDate matches +PASS timestampToDateTime.call(3572303624) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3604351948)=["2084","3","20","0","52","28"] +timestampFromDateTime.call(["2084","3","20","0","52","28"])=3604351948 +jsDate(3604351948)=2084/3/20 0:52:28 +PASS jsDate matches +PASS timestampToDateTime.call(3604351948) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3635936563)=["2085","3","20","14","22","43"] +timestampFromDateTime.call(["2085","3","20","14","22","43"])=3635936563 +jsDate(3635936563)=2085/3/20 14:22:43 +PASS jsDate matches +PASS timestampToDateTime.call(3635936563) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3667984886)=["2086","3","26","12","41","26"] +timestampFromDateTime.call(["2086","3","26","12","41","26"])=3667984886 +jsDate(3667984886)=2086/3/26 12:41:26 +PASS jsDate matches +PASS timestampToDateTime.call(3667984886) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3700033210)=["2087","4","1","11","0","10"] +timestampFromDateTime.call(["2087","4","1","11","0","10"])=3700033210 +jsDate(3700033210)=2087/4/1 11:0:10 +PASS jsDate matches +PASS timestampToDateTime.call(3700033210) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3731617825)=["2088","4","1","0","30","25"] +timestampFromDateTime.call(["2088","4","1","0","30","25"])=3731617825 +jsDate(3731617825)=2088/4/1 0:30:25 +PASS jsDate matches +PASS timestampToDateTime.call(3731617825) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3763666148)=["2089","4","6","22","49","8"] +timestampFromDateTime.call(["2089","4","6","22","49","8"])=3763666148 +jsDate(3763666148)=2089/4/6 22:49:8 +PASS jsDate matches +PASS timestampToDateTime.call(3763666148) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3795714472)=["2090","4","12","21","7","52"] +timestampFromDateTime.call(["2090","4","12","21","7","52"])=3795714472 +jsDate(3795714472)=2090/4/12 21:7:52 +PASS jsDate matches +PASS timestampToDateTime.call(3795714472) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3827299087)=["2091","4","13","10","38","7"] +timestampFromDateTime.call(["2091","4","13","10","38","7"])=3827299087 +jsDate(3827299087)=2091/4/13 10:38:7 +PASS jsDate matches +PASS timestampToDateTime.call(3827299087) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3859347410)=["2092","4","18","8","56","50"] +timestampFromDateTime.call(["2092","4","18","8","56","50"])=3859347410 +jsDate(3859347410)=2092/4/18 8:56:50 +PASS jsDate matches +PASS timestampToDateTime.call(3859347410) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3891395734)=["2093","4","24","7","15","34"] +timestampFromDateTime.call(["2093","4","24","7","15","34"])=3891395734 +jsDate(3891395734)=2093/4/24 7:15:34 +PASS jsDate matches +PASS timestampToDateTime.call(3891395734) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3922980349)=["2094","4","24","20","45","49"] +timestampFromDateTime.call(["2094","4","24","20","45","49"])=3922980349 +jsDate(3922980349)=2094/4/24 20:45:49 +PASS jsDate matches +PASS timestampToDateTime.call(3922980349) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3955028672)=["2095","4","30","19","4","32"] +timestampFromDateTime.call(["2095","4","30","19","4","32"])=3955028672 +jsDate(3955028672)=2095/4/30 19:4:32 +PASS jsDate matches +PASS timestampToDateTime.call(3955028672) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(3987076996)=["2096","5","5","17","23","16"] +timestampFromDateTime.call(["2096","5","5","17","23","16"])=3987076996 +jsDate(3987076996)=2096/5/5 17:23:16 +PASS jsDate matches +PASS timestampToDateTime.call(3987076996) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4018661611)=["2097","5","6","6","53","31"] +timestampFromDateTime.call(["2097","5","6","6","53","31"])=4018661611 +jsDate(4018661611)=2097/5/6 6:53:31 +PASS jsDate matches +PASS timestampToDateTime.call(4018661611) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4050709934)=["2098","5","12","5","12","14"] +timestampFromDateTime.call(["2098","5","12","5","12","14"])=4050709934 +jsDate(4050709934)=2098/5/12 5:12:14 +PASS jsDate matches +PASS timestampToDateTime.call(4050709934) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4082758258)=["2099","5","18","3","30","58"] +timestampFromDateTime.call(["2099","5","18","3","30","58"])=4082758258 +jsDate(4082758258)=2099/5/18 3:30:58 +PASS jsDate matches +PASS timestampToDateTime.call(4082758258) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4114342873)=["2100","5","18","17","1","13"] +timestampFromDateTime.call(["2100","5","18","17","1","13"])=4114342873 +jsDate(4114342873)=2100/5/18 17:1:13 +PASS jsDate matches +PASS timestampToDateTime.call(4114342873) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4146391196)=["2101","5","24","15","19","56"] +timestampFromDateTime.call(["2101","5","24","15","19","56"])=4146391196 +jsDate(4146391196)=2101/5/24 15:19:56 +PASS jsDate matches +PASS timestampToDateTime.call(4146391196) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4178439520)=["2102","5","30","13","38","40"] +timestampFromDateTime.call(["2102","5","30","13","38","40"])=4178439520 +jsDate(4178439520)=2102/5/30 13:38:40 +PASS jsDate matches +PASS timestampToDateTime.call(4178439520) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4210024135)=["2103","5","31","3","8","55"] +timestampFromDateTime.call(["2103","5","31","3","8","55"])=4210024135 +jsDate(4210024135)=2103/5/31 3:8:55 +PASS jsDate matches +PASS timestampToDateTime.call(4210024135) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4242072458)=["2104","6","5","1","27","38"] +timestampFromDateTime.call(["2104","6","5","1","27","38"])=4242072458 +jsDate(4242072458)=2104/6/5 1:27:38 +PASS jsDate matches +PASS timestampToDateTime.call(4242072458) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4274120782)=["2105","6","10","23","46","22"] +timestampFromDateTime.call(["2105","6","10","23","46","22"])=4274120782 +jsDate(4274120782)=2105/6/10 23:46:22 +PASS jsDate matches +PASS timestampToDateTime.call(4274120782) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4305705397)=["2106","6","11","13","16","37"] +timestampFromDateTime.call(["2106","6","11","13","16","37"])=4305705397 +jsDate(4305705397)=2106/6/11 13:16:37 +PASS jsDate matches +PASS timestampToDateTime.call(4305705397) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4337753720)=["2107","6","17","11","35","20"] +timestampFromDateTime.call(["2107","6","17","11","35","20"])=4337753720 +jsDate(4337753720)=2107/6/17 11:35:20 +PASS jsDate matches +PASS timestampToDateTime.call(4337753720) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4369802044)=["2108","6","22","9","54","4"] +timestampFromDateTime.call(["2108","6","22","9","54","4"])=4369802044 +jsDate(4369802044)=2108/6/22 9:54:4 +PASS jsDate matches +PASS timestampToDateTime.call(4369802044) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4401386659)=["2109","6","22","23","24","19"] +timestampFromDateTime.call(["2109","6","22","23","24","19"])=4401386659 +jsDate(4401386659)=2109/6/22 23:24:19 +PASS jsDate matches +PASS timestampToDateTime.call(4401386659) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4433434982)=["2110","6","28","21","43","2"] +timestampFromDateTime.call(["2110","6","28","21","43","2"])=4433434982 +jsDate(4433434982)=2110/6/28 21:43:2 +PASS jsDate matches +PASS timestampToDateTime.call(4433434982) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4465483306)=["2111","7","4","20","1","46"] +timestampFromDateTime.call(["2111","7","4","20","1","46"])=4465483306 +jsDate(4465483306)=2111/7/4 20:1:46 +PASS jsDate matches +PASS timestampToDateTime.call(4465483306) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4497067921)=["2112","7","4","9","32","1"] +timestampFromDateTime.call(["2112","7","4","9","32","1"])=4497067921 +jsDate(4497067921)=2112/7/4 9:32:1 +PASS jsDate matches +PASS timestampToDateTime.call(4497067921) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4529116244)=["2113","7","10","7","50","44"] +timestampFromDateTime.call(["2113","7","10","7","50","44"])=4529116244 +jsDate(4529116244)=2113/7/10 7:50:44 +PASS jsDate matches +PASS timestampToDateTime.call(4529116244) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4561164568)=["2114","7","16","6","9","28"] +timestampFromDateTime.call(["2114","7","16","6","9","28"])=4561164568 +jsDate(4561164568)=2114/7/16 6:9:28 +PASS jsDate matches +PASS timestampToDateTime.call(4561164568) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4592749183)=["2115","7","16","19","39","43"] +timestampFromDateTime.call(["2115","7","16","19","39","43"])=4592749183 +jsDate(4592749183)=2115/7/16 19:39:43 +PASS jsDate matches +PASS timestampToDateTime.call(4592749183) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4624797506)=["2116","7","21","17","58","26"] +timestampFromDateTime.call(["2116","7","21","17","58","26"])=4624797506 +jsDate(4624797506)=2116/7/21 17:58:26 +PASS jsDate matches +PASS timestampToDateTime.call(4624797506) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4656845830)=["2117","7","27","16","17","10"] +timestampFromDateTime.call(["2117","7","27","16","17","10"])=4656845830 +jsDate(4656845830)=2117/7/27 16:17:10 +PASS jsDate matches +PASS timestampToDateTime.call(4656845830) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4688430445)=["2118","7","28","5","47","25"] +timestampFromDateTime.call(["2118","7","28","5","47","25"])=4688430445 +jsDate(4688430445)=2118/7/28 5:47:25 +PASS jsDate matches +PASS timestampToDateTime.call(4688430445) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4720478768)=["2119","8","3","4","6","8"] +timestampFromDateTime.call(["2119","8","3","4","6","8"])=4720478768 +jsDate(4720478768)=2119/8/3 4:6:8 +PASS jsDate matches +PASS timestampToDateTime.call(4720478768) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4752527092)=["2120","8","8","2","24","52"] +timestampFromDateTime.call(["2120","8","8","2","24","52"])=4752527092 +jsDate(4752527092)=2120/8/8 2:24:52 +PASS jsDate matches +PASS timestampToDateTime.call(4752527092) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4784111707)=["2121","8","8","15","55","7"] +timestampFromDateTime.call(["2121","8","8","15","55","7"])=4784111707 +jsDate(4784111707)=2121/8/8 15:55:7 +PASS jsDate matches +PASS timestampToDateTime.call(4784111707) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4816160030)=["2122","8","14","14","13","50"] +timestampFromDateTime.call(["2122","8","14","14","13","50"])=4816160030 +jsDate(4816160030)=2122/8/14 14:13:50 +PASS jsDate matches +PASS timestampToDateTime.call(4816160030) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4848208354)=["2123","8","20","12","32","34"] +timestampFromDateTime.call(["2123","8","20","12","32","34"])=4848208354 +jsDate(4848208354)=2123/8/20 12:32:34 +PASS jsDate matches +PASS timestampToDateTime.call(4848208354) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4879792969)=["2124","8","20","2","2","49"] +timestampFromDateTime.call(["2124","8","20","2","2","49"])=4879792969 +jsDate(4879792969)=2124/8/20 2:2:49 +PASS jsDate matches +PASS timestampToDateTime.call(4879792969) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4911841292)=["2125","8","26","0","21","32"] +timestampFromDateTime.call(["2125","8","26","0","21","32"])=4911841292 +jsDate(4911841292)=2125/8/26 0:21:32 +PASS jsDate matches +PASS timestampToDateTime.call(4911841292) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4943889616)=["2126","8","31","22","40","16"] +timestampFromDateTime.call(["2126","8","31","22","40","16"])=4943889616 +jsDate(4943889616)=2126/8/31 22:40:16 +PASS jsDate matches +PASS timestampToDateTime.call(4943889616) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(4975474231)=["2127","9","1","12","10","31"] +timestampFromDateTime.call(["2127","9","1","12","10","31"])=4975474231 +jsDate(4975474231)=2127/9/1 12:10:31 +PASS jsDate matches +PASS timestampToDateTime.call(4975474231) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5007522554)=["2128","9","6","10","29","14"] +timestampFromDateTime.call(["2128","9","6","10","29","14"])=5007522554 +jsDate(5007522554)=2128/9/6 10:29:14 +PASS jsDate matches +PASS timestampToDateTime.call(5007522554) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5039570878)=["2129","9","12","8","47","58"] +timestampFromDateTime.call(["2129","9","12","8","47","58"])=5039570878 +jsDate(5039570878)=2129/9/12 8:47:58 +PASS jsDate matches +PASS timestampToDateTime.call(5039570878) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5071155493)=["2130","9","12","22","18","13"] +timestampFromDateTime.call(["2130","9","12","22","18","13"])=5071155493 +jsDate(5071155493)=2130/9/12 22:18:13 +PASS jsDate matches +PASS timestampToDateTime.call(5071155493) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5103203816)=["2131","9","18","20","36","56"] +timestampFromDateTime.call(["2131","9","18","20","36","56"])=5103203816 +jsDate(5103203816)=2131/9/18 20:36:56 +PASS jsDate matches +PASS timestampToDateTime.call(5103203816) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5135252140)=["2132","9","23","18","55","40"] +timestampFromDateTime.call(["2132","9","23","18","55","40"])=5135252140 +jsDate(5135252140)=2132/9/23 18:55:40 +PASS jsDate matches +PASS timestampToDateTime.call(5135252140) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5166836755)=["2133","9","24","8","25","55"] +timestampFromDateTime.call(["2133","9","24","8","25","55"])=5166836755 +jsDate(5166836755)=2133/9/24 8:25:55 +PASS jsDate matches +PASS timestampToDateTime.call(5166836755) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5198885078)=["2134","9","30","6","44","38"] +timestampFromDateTime.call(["2134","9","30","6","44","38"])=5198885078 +jsDate(5198885078)=2134/9/30 6:44:38 +PASS jsDate matches +PASS timestampToDateTime.call(5198885078) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5230933402)=["2135","10","6","5","3","22"] +timestampFromDateTime.call(["2135","10","6","5","3","22"])=5230933402 +jsDate(5230933402)=2135/10/6 5:3:22 +PASS jsDate matches +PASS timestampToDateTime.call(5230933402) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5262518017)=["2136","10","5","18","33","37"] +timestampFromDateTime.call(["2136","10","5","18","33","37"])=5262518017 +jsDate(5262518017)=2136/10/5 18:33:37 +PASS jsDate matches +PASS timestampToDateTime.call(5262518017) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5294566340)=["2137","10","11","16","52","20"] +timestampFromDateTime.call(["2137","10","11","16","52","20"])=5294566340 +jsDate(5294566340)=2137/10/11 16:52:20 +PASS jsDate matches +PASS timestampToDateTime.call(5294566340) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5326614664)=["2138","10","17","15","11","4"] +timestampFromDateTime.call(["2138","10","17","15","11","4"])=5326614664 +jsDate(5326614664)=2138/10/17 15:11:4 +PASS jsDate matches +PASS timestampToDateTime.call(5326614664) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5358199279)=["2139","10","18","4","41","19"] +timestampFromDateTime.call(["2139","10","18","4","41","19"])=5358199279 +jsDate(5358199279)=2139/10/18 4:41:19 +PASS jsDate matches +PASS timestampToDateTime.call(5358199279) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5390247602)=["2140","10","23","3","0","2"] +timestampFromDateTime.call(["2140","10","23","3","0","2"])=5390247602 +jsDate(5390247602)=2140/10/23 3:0:2 +PASS jsDate matches +PASS timestampToDateTime.call(5390247602) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5422295926)=["2141","10","29","1","18","46"] +timestampFromDateTime.call(["2141","10","29","1","18","46"])=5422295926 +jsDate(5422295926)=2141/10/29 1:18:46 +PASS jsDate matches +PASS timestampToDateTime.call(5422295926) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5453880541)=["2142","10","29","14","49","1"] +timestampFromDateTime.call(["2142","10","29","14","49","1"])=5453880541 +jsDate(5453880541)=2142/10/29 14:49:1 +PASS jsDate matches +PASS timestampToDateTime.call(5453880541) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5485928864)=["2143","11","4","13","7","44"] +timestampFromDateTime.call(["2143","11","4","13","7","44"])=5485928864 +jsDate(5485928864)=2143/11/4 13:7:44 +PASS jsDate matches +PASS timestampToDateTime.call(5485928864) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5517977188)=["2144","11","9","11","26","28"] +timestampFromDateTime.call(["2144","11","9","11","26","28"])=5517977188 +jsDate(5517977188)=2144/11/9 11:26:28 +PASS jsDate matches +PASS timestampToDateTime.call(5517977188) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5549561803)=["2145","11","10","0","56","43"] +timestampFromDateTime.call(["2145","11","10","0","56","43"])=5549561803 +jsDate(5549561803)=2145/11/10 0:56:43 +PASS jsDate matches +PASS timestampToDateTime.call(5549561803) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5581610126)=["2146","11","15","23","15","26"] +timestampFromDateTime.call(["2146","11","15","23","15","26"])=5581610126 +jsDate(5581610126)=2146/11/15 23:15:26 +PASS jsDate matches +PASS timestampToDateTime.call(5581610126) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5613658450)=["2147","11","21","21","34","10"] +timestampFromDateTime.call(["2147","11","21","21","34","10"])=5613658450 +jsDate(5613658450)=2147/11/21 21:34:10 +PASS jsDate matches +PASS timestampToDateTime.call(5613658450) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5645243065)=["2148","11","21","11","4","25"] +timestampFromDateTime.call(["2148","11","21","11","4","25"])=5645243065 +jsDate(5645243065)=2148/11/21 11:4:25 +PASS jsDate matches +PASS timestampToDateTime.call(5645243065) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5677291388)=["2149","11","27","9","23","8"] +timestampFromDateTime.call(["2149","11","27","9","23","8"])=5677291388 +jsDate(5677291388)=2149/11/27 9:23:8 +PASS jsDate matches +PASS timestampToDateTime.call(5677291388) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5709339712)=["2150","12","3","7","41","52"] +timestampFromDateTime.call(["2150","12","3","7","41","52"])=5709339712 +jsDate(5709339712)=2150/12/3 7:41:52 +PASS jsDate matches +PASS timestampToDateTime.call(5709339712) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5740924327)=["2151","12","3","21","12","7"] +timestampFromDateTime.call(["2151","12","3","21","12","7"])=5740924327 +jsDate(5740924327)=2151/12/3 21:12:7 +PASS jsDate matches +PASS timestampToDateTime.call(5740924327) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5772972650)=["2152","12","8","19","30","50"] +timestampFromDateTime.call(["2152","12","8","19","30","50"])=5772972650 +jsDate(5772972650)=2152/12/8 19:30:50 +PASS jsDate matches +PASS timestampToDateTime.call(5772972650) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5805020974)=["2153","12","14","17","49","34"] +timestampFromDateTime.call(["2153","12","14","17","49","34"])=5805020974 +jsDate(5805020974)=2153/12/14 17:49:34 +PASS jsDate matches +PASS timestampToDateTime.call(5805020974) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5836605589)=["2154","12","15","7","19","49"] +timestampFromDateTime.call(["2154","12","15","7","19","49"])=5836605589 +jsDate(5836605589)=2154/12/15 7:19:49 +PASS jsDate matches +PASS timestampToDateTime.call(5836605589) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5868653912)=["2155","12","21","5","38","32"] +timestampFromDateTime.call(["2155","12","21","5","38","32"])=5868653912 +jsDate(5868653912)=2155/12/21 5:38:32 +PASS jsDate matches +PASS timestampToDateTime.call(5868653912) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5900702236)=["2156","12","26","3","57","16"] +timestampFromDateTime.call(["2156","12","26","3","57","16"])=5900702236 +jsDate(5900702236)=2156/12/26 3:57:16 +PASS jsDate matches +PASS timestampToDateTime.call(5900702236) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5932286851)=["2157","12","26","17","27","31"] +timestampFromDateTime.call(["2157","12","26","17","27","31"])=5932286851 +jsDate(5932286851)=2157/12/26 17:27:31 +PASS jsDate matches +PASS timestampToDateTime.call(5932286851) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5964335174)=["2159","1","1","15","46","14"] +timestampFromDateTime.call(["2159","1","1","15","46","14"])=5964335174 +jsDate(5964335174)=2159/1/1 15:46:14 +PASS jsDate matches +PASS timestampToDateTime.call(5964335174) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(5996383498)=["2160","1","7","14","4","58"] +timestampFromDateTime.call(["2160","1","7","14","4","58"])=5996383498 +jsDate(5996383498)=2160/1/7 14:4:58 +PASS jsDate matches +PASS timestampToDateTime.call(5996383498) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6027968113)=["2161","1","7","3","35","13"] +timestampFromDateTime.call(["2161","1","7","3","35","13"])=6027968113 +jsDate(6027968113)=2161/1/7 3:35:13 +PASS jsDate matches +PASS timestampToDateTime.call(6027968113) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6060016436)=["2162","1","13","1","53","56"] +timestampFromDateTime.call(["2162","1","13","1","53","56"])=6060016436 +jsDate(6060016436)=2162/1/13 1:53:56 +PASS jsDate matches +PASS timestampToDateTime.call(6060016436) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6092064760)=["2163","1","19","0","12","40"] +timestampFromDateTime.call(["2163","1","19","0","12","40"])=6092064760 +jsDate(6092064760)=2163/1/19 0:12:40 +PASS jsDate matches +PASS timestampToDateTime.call(6092064760) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6123649375)=["2164","1","19","13","42","55"] +timestampFromDateTime.call(["2164","1","19","13","42","55"])=6123649375 +jsDate(6123649375)=2164/1/19 13:42:55 +PASS jsDate matches +PASS timestampToDateTime.call(6123649375) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6155697698)=["2165","1","24","12","1","38"] +timestampFromDateTime.call(["2165","1","24","12","1","38"])=6155697698 +jsDate(6155697698)=2165/1/24 12:1:38 +PASS jsDate matches +PASS timestampToDateTime.call(6155697698) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6187746022)=["2166","1","30","10","20","22"] +timestampFromDateTime.call(["2166","1","30","10","20","22"])=6187746022 +jsDate(6187746022)=2166/1/30 10:20:22 +PASS jsDate matches +PASS timestampToDateTime.call(6187746022) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6219330637)=["2167","1","30","23","50","37"] +timestampFromDateTime.call(["2167","1","30","23","50","37"])=6219330637 +jsDate(6219330637)=2167/1/30 23:50:37 +PASS jsDate matches +PASS timestampToDateTime.call(6219330637) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6251378960)=["2168","2","5","22","9","20"] +timestampFromDateTime.call(["2168","2","5","22","9","20"])=6251378960 +jsDate(6251378960)=2168/2/5 22:9:20 +PASS jsDate matches +PASS timestampToDateTime.call(6251378960) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6283427284)=["2169","2","10","20","28","4"] +timestampFromDateTime.call(["2169","2","10","20","28","4"])=6283427284 +jsDate(6283427284)=2169/2/10 20:28:4 +PASS jsDate matches +PASS timestampToDateTime.call(6283427284) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6315011899)=["2170","2","11","9","58","19"] +timestampFromDateTime.call(["2170","2","11","9","58","19"])=6315011899 +jsDate(6315011899)=2170/2/11 9:58:19 +PASS jsDate matches +PASS timestampToDateTime.call(6315011899) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6347060222)=["2171","2","17","8","17","2"] +timestampFromDateTime.call(["2171","2","17","8","17","2"])=6347060222 +jsDate(6347060222)=2171/2/17 8:17:2 +PASS jsDate matches +PASS timestampToDateTime.call(6347060222) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6379108546)=["2172","2","23","6","35","46"] +timestampFromDateTime.call(["2172","2","23","6","35","46"])=6379108546 +jsDate(6379108546)=2172/2/23 6:35:46 +PASS jsDate matches +PASS timestampToDateTime.call(6379108546) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6410693161)=["2173","2","22","20","6","1"] +timestampFromDateTime.call(["2173","2","22","20","6","1"])=6410693161 +jsDate(6410693161)=2173/2/22 20:6:1 +PASS jsDate matches +PASS timestampToDateTime.call(6410693161) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6442741484)=["2174","2","28","18","24","44"] +timestampFromDateTime.call(["2174","2","28","18","24","44"])=6442741484 +jsDate(6442741484)=2174/2/28 18:24:44 +PASS jsDate matches +PASS timestampToDateTime.call(6442741484) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6474789808)=["2175","3","6","16","43","28"] +timestampFromDateTime.call(["2175","3","6","16","43","28"])=6474789808 +jsDate(6474789808)=2175/3/6 16:43:28 +PASS jsDate matches +PASS timestampToDateTime.call(6474789808) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6506374423)=["2176","3","6","6","13","43"] +timestampFromDateTime.call(["2176","3","6","6","13","43"])=6506374423 +jsDate(6506374423)=2176/3/6 6:13:43 +PASS jsDate matches +PASS timestampToDateTime.call(6506374423) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6538422746)=["2177","3","12","4","32","26"] +timestampFromDateTime.call(["2177","3","12","4","32","26"])=6538422746 +jsDate(6538422746)=2177/3/12 4:32:26 +PASS jsDate matches +PASS timestampToDateTime.call(6538422746) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6570471070)=["2178","3","18","2","51","10"] +timestampFromDateTime.call(["2178","3","18","2","51","10"])=6570471070 +jsDate(6570471070)=2178/3/18 2:51:10 +PASS jsDate matches +PASS timestampToDateTime.call(6570471070) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6602055685)=["2179","3","18","16","21","25"] +timestampFromDateTime.call(["2179","3","18","16","21","25"])=6602055685 +jsDate(6602055685)=2179/3/18 16:21:25 +PASS jsDate matches +PASS timestampToDateTime.call(6602055685) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6634104008)=["2180","3","23","14","40","8"] +timestampFromDateTime.call(["2180","3","23","14","40","8"])=6634104008 +jsDate(6634104008)=2180/3/23 14:40:8 +PASS jsDate matches +PASS timestampToDateTime.call(6634104008) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6666152332)=["2181","3","29","12","58","52"] +timestampFromDateTime.call(["2181","3","29","12","58","52"])=6666152332 +jsDate(6666152332)=2181/3/29 12:58:52 +PASS jsDate matches +PASS timestampToDateTime.call(6666152332) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6697736947)=["2182","3","30","2","29","7"] +timestampFromDateTime.call(["2182","3","30","2","29","7"])=6697736947 +jsDate(6697736947)=2182/3/30 2:29:7 +PASS jsDate matches +PASS timestampToDateTime.call(6697736947) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6729785270)=["2183","4","5","0","47","50"] +timestampFromDateTime.call(["2183","4","5","0","47","50"])=6729785270 +jsDate(6729785270)=2183/4/5 0:47:50 +PASS jsDate matches +PASS timestampToDateTime.call(6729785270) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6761833594)=["2184","4","9","23","6","34"] +timestampFromDateTime.call(["2184","4","9","23","6","34"])=6761833594 +jsDate(6761833594)=2184/4/9 23:6:34 +PASS jsDate matches +PASS timestampToDateTime.call(6761833594) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6793418209)=["2185","4","10","12","36","49"] +timestampFromDateTime.call(["2185","4","10","12","36","49"])=6793418209 +jsDate(6793418209)=2185/4/10 12:36:49 +PASS jsDate matches +PASS timestampToDateTime.call(6793418209) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6825466532)=["2186","4","16","10","55","32"] +timestampFromDateTime.call(["2186","4","16","10","55","32"])=6825466532 +jsDate(6825466532)=2186/4/16 10:55:32 +PASS jsDate matches +PASS timestampToDateTime.call(6825466532) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6857514856)=["2187","4","22","9","14","16"] +timestampFromDateTime.call(["2187","4","22","9","14","16"])=6857514856 +jsDate(6857514856)=2187/4/22 9:14:16 +PASS jsDate matches +PASS timestampToDateTime.call(6857514856) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6889099471)=["2188","4","21","22","44","31"] +timestampFromDateTime.call(["2188","4","21","22","44","31"])=6889099471 +jsDate(6889099471)=2188/4/21 22:44:31 +PASS jsDate matches +PASS timestampToDateTime.call(6889099471) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6921147794)=["2189","4","27","21","3","14"] +timestampFromDateTime.call(["2189","4","27","21","3","14"])=6921147794 +jsDate(6921147794)=2189/4/27 21:3:14 +PASS jsDate matches +PASS timestampToDateTime.call(6921147794) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6953196118)=["2190","5","3","19","21","58"] +timestampFromDateTime.call(["2190","5","3","19","21","58"])=6953196118 +jsDate(6953196118)=2190/5/3 19:21:58 +PASS jsDate matches +PASS timestampToDateTime.call(6953196118) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(6984780733)=["2191","5","4","8","52","13"] +timestampFromDateTime.call(["2191","5","4","8","52","13"])=6984780733 +jsDate(6984780733)=2191/5/4 8:52:13 +PASS jsDate matches +PASS timestampToDateTime.call(6984780733) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7016829056)=["2192","5","9","7","10","56"] +timestampFromDateTime.call(["2192","5","9","7","10","56"])=7016829056 +jsDate(7016829056)=2192/5/9 7:10:56 +PASS jsDate matches +PASS timestampToDateTime.call(7016829056) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7048877380)=["2193","5","15","5","29","40"] +timestampFromDateTime.call(["2193","5","15","5","29","40"])=7048877380 +jsDate(7048877380)=2193/5/15 5:29:40 +PASS jsDate matches +PASS timestampToDateTime.call(7048877380) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7080461995)=["2194","5","15","18","59","55"] +timestampFromDateTime.call(["2194","5","15","18","59","55"])=7080461995 +jsDate(7080461995)=2194/5/15 18:59:55 +PASS jsDate matches +PASS timestampToDateTime.call(7080461995) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7112510318)=["2195","5","21","17","18","38"] +timestampFromDateTime.call(["2195","5","21","17","18","38"])=7112510318 +jsDate(7112510318)=2195/5/21 17:18:38 +PASS jsDate matches +PASS timestampToDateTime.call(7112510318) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7144558642)=["2196","5","26","15","37","22"] +timestampFromDateTime.call(["2196","5","26","15","37","22"])=7144558642 +jsDate(7144558642)=2196/5/26 15:37:22 +PASS jsDate matches +PASS timestampToDateTime.call(7144558642) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7176143257)=["2197","5","27","5","7","37"] +timestampFromDateTime.call(["2197","5","27","5","7","37"])=7176143257 +jsDate(7176143257)=2197/5/27 5:7:37 +PASS jsDate matches +PASS timestampToDateTime.call(7176143257) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7208191580)=["2198","6","2","3","26","20"] +timestampFromDateTime.call(["2198","6","2","3","26","20"])=7208191580 +jsDate(7208191580)=2198/6/2 3:26:20 +PASS jsDate matches +PASS timestampToDateTime.call(7208191580) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7240239904)=["2199","6","8","1","45","4"] +timestampFromDateTime.call(["2199","6","8","1","45","4"])=7240239904 +jsDate(7240239904)=2199/6/8 1:45:4 +PASS jsDate matches +PASS timestampToDateTime.call(7240239904) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7271824519)=["2200","6","8","15","15","19"] +timestampFromDateTime.call(["2200","6","8","15","15","19"])=7271824519 +jsDate(7271824519)=2200/6/8 15:15:19 +PASS jsDate matches +PASS timestampToDateTime.call(7271824519) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7303872842)=["2201","6","14","13","34","2"] +timestampFromDateTime.call(["2201","6","14","13","34","2"])=7303872842 +jsDate(7303872842)=2201/6/14 13:34:2 +PASS jsDate matches +PASS timestampToDateTime.call(7303872842) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7335921166)=["2202","6","20","11","52","46"] +timestampFromDateTime.call(["2202","6","20","11","52","46"])=7335921166 +jsDate(7335921166)=2202/6/20 11:52:46 +PASS jsDate matches +PASS timestampToDateTime.call(7335921166) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7367505781)=["2203","6","21","1","23","1"] +timestampFromDateTime.call(["2203","6","21","1","23","1"])=7367505781 +jsDate(7367505781)=2203/6/21 1:23:1 +PASS jsDate matches +PASS timestampToDateTime.call(7367505781) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7399554104)=["2204","6","25","23","41","44"] +timestampFromDateTime.call(["2204","6","25","23","41","44"])=7399554104 +jsDate(7399554104)=2204/6/25 23:41:44 +PASS jsDate matches +PASS timestampToDateTime.call(7399554104) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7431602428)=["2205","7","1","22","0","28"] +timestampFromDateTime.call(["2205","7","1","22","0","28"])=7431602428 +jsDate(7431602428)=2205/7/1 22:0:28 +PASS jsDate matches +PASS timestampToDateTime.call(7431602428) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7463187043)=["2206","7","2","11","30","43"] +timestampFromDateTime.call(["2206","7","2","11","30","43"])=7463187043 +jsDate(7463187043)=2206/7/2 11:30:43 +PASS jsDate matches +PASS timestampToDateTime.call(7463187043) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7495235366)=["2207","7","8","9","49","26"] +timestampFromDateTime.call(["2207","7","8","9","49","26"])=7495235366 +jsDate(7495235366)=2207/7/8 9:49:26 +PASS jsDate matches +PASS timestampToDateTime.call(7495235366) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7527283690)=["2208","7","13","8","8","10"] +timestampFromDateTime.call(["2208","7","13","8","8","10"])=7527283690 +jsDate(7527283690)=2208/7/13 8:8:10 +PASS jsDate matches +PASS timestampToDateTime.call(7527283690) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7558868305)=["2209","7","13","21","38","25"] +timestampFromDateTime.call(["2209","7","13","21","38","25"])=7558868305 +jsDate(7558868305)=2209/7/13 21:38:25 +PASS jsDate matches +PASS timestampToDateTime.call(7558868305) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7590916628)=["2210","7","19","19","57","8"] +timestampFromDateTime.call(["2210","7","19","19","57","8"])=7590916628 +jsDate(7590916628)=2210/7/19 19:57:8 +PASS jsDate matches +PASS timestampToDateTime.call(7590916628) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7622964952)=["2211","7","25","18","15","52"] +timestampFromDateTime.call(["2211","7","25","18","15","52"])=7622964952 +jsDate(7622964952)=2211/7/25 18:15:52 +PASS jsDate matches +PASS timestampToDateTime.call(7622964952) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7654549567)=["2212","7","25","7","46","7"] +timestampFromDateTime.call(["2212","7","25","7","46","7"])=7654549567 +jsDate(7654549567)=2212/7/25 7:46:7 +PASS jsDate matches +PASS timestampToDateTime.call(7654549567) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7686597890)=["2213","7","31","6","4","50"] +timestampFromDateTime.call(["2213","7","31","6","4","50"])=7686597890 +jsDate(7686597890)=2213/7/31 6:4:50 +PASS jsDate matches +PASS timestampToDateTime.call(7686597890) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7718646214)=["2214","8","6","4","23","34"] +timestampFromDateTime.call(["2214","8","6","4","23","34"])=7718646214 +jsDate(7718646214)=2214/8/6 4:23:34 +PASS jsDate matches +PASS timestampToDateTime.call(7718646214) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7750230829)=["2215","8","6","17","53","49"] +timestampFromDateTime.call(["2215","8","6","17","53","49"])=7750230829 +jsDate(7750230829)=2215/8/6 17:53:49 +PASS jsDate matches +PASS timestampToDateTime.call(7750230829) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7782279152)=["2216","8","11","16","12","32"] +timestampFromDateTime.call(["2216","8","11","16","12","32"])=7782279152 +jsDate(7782279152)=2216/8/11 16:12:32 +PASS jsDate matches +PASS timestampToDateTime.call(7782279152) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7814327476)=["2217","8","17","14","31","16"] +timestampFromDateTime.call(["2217","8","17","14","31","16"])=7814327476 +jsDate(7814327476)=2217/8/17 14:31:16 +PASS jsDate matches +PASS timestampToDateTime.call(7814327476) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7845912091)=["2218","8","18","4","1","31"] +timestampFromDateTime.call(["2218","8","18","4","1","31"])=7845912091 +jsDate(7845912091)=2218/8/18 4:1:31 +PASS jsDate matches +PASS timestampToDateTime.call(7845912091) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7877960414)=["2219","8","24","2","20","14"] +timestampFromDateTime.call(["2219","8","24","2","20","14"])=7877960414 +jsDate(7877960414)=2219/8/24 2:20:14 +PASS jsDate matches +PASS timestampToDateTime.call(7877960414) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7910008738)=["2220","8","29","0","38","58"] +timestampFromDateTime.call(["2220","8","29","0","38","58"])=7910008738 +jsDate(7910008738)=2220/8/29 0:38:58 +PASS jsDate matches +PASS timestampToDateTime.call(7910008738) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7941593353)=["2221","8","29","14","9","13"] +timestampFromDateTime.call(["2221","8","29","14","9","13"])=7941593353 +jsDate(7941593353)=2221/8/29 14:9:13 +PASS jsDate matches +PASS timestampToDateTime.call(7941593353) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(7973641676)=["2222","9","4","12","27","56"] +timestampFromDateTime.call(["2222","9","4","12","27","56"])=7973641676 +jsDate(7973641676)=2222/9/4 12:27:56 +PASS jsDate matches +PASS timestampToDateTime.call(7973641676) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8005690000)=["2223","9","10","10","46","40"] +timestampFromDateTime.call(["2223","9","10","10","46","40"])=8005690000 +jsDate(8005690000)=2223/9/10 10:46:40 +PASS jsDate matches +PASS timestampToDateTime.call(8005690000) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8037274615)=["2224","9","10","0","16","55"] +timestampFromDateTime.call(["2224","9","10","0","16","55"])=8037274615 +jsDate(8037274615)=2224/9/10 0:16:55 +PASS jsDate matches +PASS timestampToDateTime.call(8037274615) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8069322938)=["2225","9","15","22","35","38"] +timestampFromDateTime.call(["2225","9","15","22","35","38"])=8069322938 +jsDate(8069322938)=2225/9/15 22:35:38 +PASS jsDate matches +PASS timestampToDateTime.call(8069322938) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8101371262)=["2226","9","21","20","54","22"] +timestampFromDateTime.call(["2226","9","21","20","54","22"])=8101371262 +jsDate(8101371262)=2226/9/21 20:54:22 +PASS jsDate matches +PASS timestampToDateTime.call(8101371262) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8132955877)=["2227","9","22","10","24","37"] +timestampFromDateTime.call(["2227","9","22","10","24","37"])=8132955877 +jsDate(8132955877)=2227/9/22 10:24:37 +PASS jsDate matches +PASS timestampToDateTime.call(8132955877) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8165004200)=["2228","9","27","8","43","20"] +timestampFromDateTime.call(["2228","9","27","8","43","20"])=8165004200 +jsDate(8165004200)=2228/9/27 8:43:20 +PASS jsDate matches +PASS timestampToDateTime.call(8165004200) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8197052524)=["2229","10","3","7","2","4"] +timestampFromDateTime.call(["2229","10","3","7","2","4"])=8197052524 +jsDate(8197052524)=2229/10/3 7:2:4 +PASS jsDate matches +PASS timestampToDateTime.call(8197052524) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8228637139)=["2230","10","3","20","32","19"] +timestampFromDateTime.call(["2230","10","3","20","32","19"])=8228637139 +jsDate(8228637139)=2230/10/3 20:32:19 +PASS jsDate matches +PASS timestampToDateTime.call(8228637139) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8260685462)=["2231","10","9","18","51","2"] +timestampFromDateTime.call(["2231","10","9","18","51","2"])=8260685462 +jsDate(8260685462)=2231/10/9 18:51:2 +PASS jsDate matches +PASS timestampToDateTime.call(8260685462) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8292733786)=["2232","10","14","17","9","46"] +timestampFromDateTime.call(["2232","10","14","17","9","46"])=8292733786 +jsDate(8292733786)=2232/10/14 17:9:46 +PASS jsDate matches +PASS timestampToDateTime.call(8292733786) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8324318401)=["2233","10","15","6","40","1"] +timestampFromDateTime.call(["2233","10","15","6","40","1"])=8324318401 +jsDate(8324318401)=2233/10/15 6:40:1 +PASS jsDate matches +PASS timestampToDateTime.call(8324318401) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8356366724)=["2234","10","21","4","58","44"] +timestampFromDateTime.call(["2234","10","21","4","58","44"])=8356366724 +jsDate(8356366724)=2234/10/21 4:58:44 +PASS jsDate matches +PASS timestampToDateTime.call(8356366724) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8388415048)=["2235","10","27","3","17","28"] +timestampFromDateTime.call(["2235","10","27","3","17","28"])=8388415048 +jsDate(8388415048)=2235/10/27 3:17:28 +PASS jsDate matches +PASS timestampToDateTime.call(8388415048) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8419999663)=["2236","10","26","16","47","43"] +timestampFromDateTime.call(["2236","10","26","16","47","43"])=8419999663 +jsDate(8419999663)=2236/10/26 16:47:43 +PASS jsDate matches +PASS timestampToDateTime.call(8419999663) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8452047986)=["2237","11","1","15","6","26"] +timestampFromDateTime.call(["2237","11","1","15","6","26"])=8452047986 +jsDate(8452047986)=2237/11/1 15:6:26 +PASS jsDate matches +PASS timestampToDateTime.call(8452047986) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8484096310)=["2238","11","7","13","25","10"] +timestampFromDateTime.call(["2238","11","7","13","25","10"])=8484096310 +jsDate(8484096310)=2238/11/7 13:25:10 +PASS jsDate matches +PASS timestampToDateTime.call(8484096310) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8515680925)=["2239","11","8","2","55","25"] +timestampFromDateTime.call(["2239","11","8","2","55","25"])=8515680925 +jsDate(8515680925)=2239/11/8 2:55:25 +PASS jsDate matches +PASS timestampToDateTime.call(8515680925) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8547729248)=["2240","11","13","1","14","8"] +timestampFromDateTime.call(["2240","11","13","1","14","8"])=8547729248 +jsDate(8547729248)=2240/11/13 1:14:8 +PASS jsDate matches +PASS timestampToDateTime.call(8547729248) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8579777572)=["2241","11","18","23","32","52"] +timestampFromDateTime.call(["2241","11","18","23","32","52"])=8579777572 +jsDate(8579777572)=2241/11/18 23:32:52 +PASS jsDate matches +PASS timestampToDateTime.call(8579777572) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8611362187)=["2242","11","19","13","3","7"] +timestampFromDateTime.call(["2242","11","19","13","3","7"])=8611362187 +jsDate(8611362187)=2242/11/19 13:3:7 +PASS jsDate matches +PASS timestampToDateTime.call(8611362187) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8643410510)=["2243","11","25","11","21","50"] +timestampFromDateTime.call(["2243","11","25","11","21","50"])=8643410510 +jsDate(8643410510)=2243/11/25 11:21:50 +PASS jsDate matches +PASS timestampToDateTime.call(8643410510) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8675458834)=["2244","11","30","9","40","34"] +timestampFromDateTime.call(["2244","11","30","9","40","34"])=8675458834 +jsDate(8675458834)=2244/11/30 9:40:34 +PASS jsDate matches +PASS timestampToDateTime.call(8675458834) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8707043449)=["2245","11","30","23","10","49"] +timestampFromDateTime.call(["2245","11","30","23","10","49"])=8707043449 +jsDate(8707043449)=2245/11/30 23:10:49 +PASS jsDate matches +PASS timestampToDateTime.call(8707043449) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8739091772)=["2246","12","6","21","29","32"] +timestampFromDateTime.call(["2246","12","6","21","29","32"])=8739091772 +jsDate(8739091772)=2246/12/6 21:29:32 +PASS jsDate matches +PASS timestampToDateTime.call(8739091772) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8771140096)=["2247","12","12","19","48","16"] +timestampFromDateTime.call(["2247","12","12","19","48","16"])=8771140096 +jsDate(8771140096)=2247/12/12 19:48:16 +PASS jsDate matches +PASS timestampToDateTime.call(8771140096) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8802724711)=["2248","12","12","9","18","31"] +timestampFromDateTime.call(["2248","12","12","9","18","31"])=8802724711 +jsDate(8802724711)=2248/12/12 9:18:31 +PASS jsDate matches +PASS timestampToDateTime.call(8802724711) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8834773034)=["2249","12","18","7","37","14"] +timestampFromDateTime.call(["2249","12","18","7","37","14"])=8834773034 +jsDate(8834773034)=2249/12/18 7:37:14 +PASS jsDate matches +PASS timestampToDateTime.call(8834773034) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8866821358)=["2250","12","24","5","55","58"] +timestampFromDateTime.call(["2250","12","24","5","55","58"])=8866821358 +jsDate(8866821358)=2250/12/24 5:55:58 +PASS jsDate matches +PASS timestampToDateTime.call(8866821358) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8898405973)=["2251","12","24","19","26","13"] +timestampFromDateTime.call(["2251","12","24","19","26","13"])=8898405973 +jsDate(8898405973)=2251/12/24 19:26:13 +PASS jsDate matches +PASS timestampToDateTime.call(8898405973) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8930454296)=["2252","12","29","17","44","56"] +timestampFromDateTime.call(["2252","12","29","17","44","56"])=8930454296 +jsDate(8930454296)=2252/12/29 17:44:56 +PASS jsDate matches +PASS timestampToDateTime.call(8930454296) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8962502620)=["2254","1","4","16","3","40"] +timestampFromDateTime.call(["2254","1","4","16","3","40"])=8962502620 +jsDate(8962502620)=2254/1/4 16:3:40 +PASS jsDate matches +PASS timestampToDateTime.call(8962502620) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(8994087235)=["2255","1","5","5","33","55"] +timestampFromDateTime.call(["2255","1","5","5","33","55"])=8994087235 +jsDate(8994087235)=2255/1/5 5:33:55 +PASS jsDate matches +PASS timestampToDateTime.call(8994087235) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9026135558)=["2256","1","11","3","52","38"] +timestampFromDateTime.call(["2256","1","11","3","52","38"])=9026135558 +jsDate(9026135558)=2256/1/11 3:52:38 +PASS jsDate matches +PASS timestampToDateTime.call(9026135558) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9058183882)=["2257","1","16","2","11","22"] +timestampFromDateTime.call(["2257","1","16","2","11","22"])=9058183882 +jsDate(9058183882)=2257/1/16 2:11:22 +PASS jsDate matches +PASS timestampToDateTime.call(9058183882) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9089768497)=["2258","1","16","15","41","37"] +timestampFromDateTime.call(["2258","1","16","15","41","37"])=9089768497 +jsDate(9089768497)=2258/1/16 15:41:37 +PASS jsDate matches +PASS timestampToDateTime.call(9089768497) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9121816820)=["2259","1","22","14","0","20"] +timestampFromDateTime.call(["2259","1","22","14","0","20"])=9121816820 +jsDate(9121816820)=2259/1/22 14:0:20 +PASS jsDate matches +PASS timestampToDateTime.call(9121816820) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9153865144)=["2260","1","28","12","19","4"] +timestampFromDateTime.call(["2260","1","28","12","19","4"])=9153865144 +jsDate(9153865144)=2260/1/28 12:19:4 +PASS jsDate matches +PASS timestampToDateTime.call(9153865144) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9185449759)=["2261","1","28","1","49","19"] +timestampFromDateTime.call(["2261","1","28","1","49","19"])=9185449759 +jsDate(9185449759)=2261/1/28 1:49:19 +PASS jsDate matches +PASS timestampToDateTime.call(9185449759) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9217498082)=["2262","2","3","0","8","2"] +timestampFromDateTime.call(["2262","2","3","0","8","2"])=9217498082 +jsDate(9217498082)=2262/2/3 0:8:2 +PASS jsDate matches +PASS timestampToDateTime.call(9217498082) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9249546406)=["2263","2","8","22","26","46"] +timestampFromDateTime.call(["2263","2","8","22","26","46"])=9249546406 +jsDate(9249546406)=2263/2/8 22:26:46 +PASS jsDate matches +PASS timestampToDateTime.call(9249546406) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9281131021)=["2264","2","9","11","57","1"] +timestampFromDateTime.call(["2264","2","9","11","57","1"])=9281131021 +jsDate(9281131021)=2264/2/9 11:57:1 +PASS jsDate matches +PASS timestampToDateTime.call(9281131021) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9313179344)=["2265","2","14","10","15","44"] +timestampFromDateTime.call(["2265","2","14","10","15","44"])=9313179344 +jsDate(9313179344)=2265/2/14 10:15:44 +PASS jsDate matches +PASS timestampToDateTime.call(9313179344) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9345227668)=["2266","2","20","8","34","28"] +timestampFromDateTime.call(["2266","2","20","8","34","28"])=9345227668 +jsDate(9345227668)=2266/2/20 8:34:28 +PASS jsDate matches +PASS timestampToDateTime.call(9345227668) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9376812283)=["2267","2","20","22","4","43"] +timestampFromDateTime.call(["2267","2","20","22","4","43"])=9376812283 +jsDate(9376812283)=2267/2/20 22:4:43 +PASS jsDate matches +PASS timestampToDateTime.call(9376812283) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9408860606)=["2268","2","26","20","23","26"] +timestampFromDateTime.call(["2268","2","26","20","23","26"])=9408860606 +jsDate(9408860606)=2268/2/26 20:23:26 +PASS jsDate matches +PASS timestampToDateTime.call(9408860606) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9440908930)=["2269","3","3","18","42","10"] +timestampFromDateTime.call(["2269","3","3","18","42","10"])=9440908930 +jsDate(9440908930)=2269/3/3 18:42:10 +PASS jsDate matches +PASS timestampToDateTime.call(9440908930) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9472493545)=["2270","3","4","8","12","25"] +timestampFromDateTime.call(["2270","3","4","8","12","25"])=9472493545 +jsDate(9472493545)=2270/3/4 8:12:25 +PASS jsDate matches +PASS timestampToDateTime.call(9472493545) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9504541868)=["2271","3","10","6","31","8"] +timestampFromDateTime.call(["2271","3","10","6","31","8"])=9504541868 +jsDate(9504541868)=2271/3/10 6:31:8 +PASS jsDate matches +PASS timestampToDateTime.call(9504541868) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9536590192)=["2272","3","15","4","49","52"] +timestampFromDateTime.call(["2272","3","15","4","49","52"])=9536590192 +jsDate(9536590192)=2272/3/15 4:49:52 +PASS jsDate matches +PASS timestampToDateTime.call(9536590192) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9568174807)=["2273","3","15","18","20","7"] +timestampFromDateTime.call(["2273","3","15","18","20","7"])=9568174807 +jsDate(9568174807)=2273/3/15 18:20:7 +PASS jsDate matches +PASS timestampToDateTime.call(9568174807) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9600223130)=["2274","3","21","16","38","50"] +timestampFromDateTime.call(["2274","3","21","16","38","50"])=9600223130 +jsDate(9600223130)=2274/3/21 16:38:50 +PASS jsDate matches +PASS timestampToDateTime.call(9600223130) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9632271454)=["2275","3","27","14","57","34"] +timestampFromDateTime.call(["2275","3","27","14","57","34"])=9632271454 +jsDate(9632271454)=2275/3/27 14:57:34 +PASS jsDate matches +PASS timestampToDateTime.call(9632271454) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9663856069)=["2276","3","27","4","27","49"] +timestampFromDateTime.call(["2276","3","27","4","27","49"])=9663856069 +jsDate(9663856069)=2276/3/27 4:27:49 +PASS jsDate matches +PASS timestampToDateTime.call(9663856069) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9695904392)=["2277","4","2","2","46","32"] +timestampFromDateTime.call(["2277","4","2","2","46","32"])=9695904392 +jsDate(9695904392)=2277/4/2 2:46:32 +PASS jsDate matches +PASS timestampToDateTime.call(9695904392) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9727952716)=["2278","4","8","1","5","16"] +timestampFromDateTime.call(["2278","4","8","1","5","16"])=9727952716 +jsDate(9727952716)=2278/4/8 1:5:16 +PASS jsDate matches +PASS timestampToDateTime.call(9727952716) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9759537331)=["2279","4","8","14","35","31"] +timestampFromDateTime.call(["2279","4","8","14","35","31"])=9759537331 +jsDate(9759537331)=2279/4/8 14:35:31 +PASS jsDate matches +PASS timestampToDateTime.call(9759537331) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9791585654)=["2280","4","13","12","54","14"] +timestampFromDateTime.call(["2280","4","13","12","54","14"])=9791585654 +jsDate(9791585654)=2280/4/13 12:54:14 +PASS jsDate matches +PASS timestampToDateTime.call(9791585654) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9823633978)=["2281","4","19","11","12","58"] +timestampFromDateTime.call(["2281","4","19","11","12","58"])=9823633978 +jsDate(9823633978)=2281/4/19 11:12:58 +PASS jsDate matches +PASS timestampToDateTime.call(9823633978) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9855218593)=["2282","4","20","0","43","13"] +timestampFromDateTime.call(["2282","4","20","0","43","13"])=9855218593 +jsDate(9855218593)=2282/4/20 0:43:13 +PASS jsDate matches +PASS timestampToDateTime.call(9855218593) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9887266916)=["2283","4","25","23","1","56"] +timestampFromDateTime.call(["2283","4","25","23","1","56"])=9887266916 +jsDate(9887266916)=2283/4/25 23:1:56 +PASS jsDate matches +PASS timestampToDateTime.call(9887266916) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9919315240)=["2284","4","30","21","20","40"] +timestampFromDateTime.call(["2284","4","30","21","20","40"])=9919315240 +jsDate(9919315240)=2284/4/30 21:20:40 +PASS jsDate matches +PASS timestampToDateTime.call(9919315240) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9950899855)=["2285","5","1","10","50","55"] +timestampFromDateTime.call(["2285","5","1","10","50","55"])=9950899855 +jsDate(9950899855)=2285/5/1 10:50:55 +PASS jsDate matches +PASS timestampToDateTime.call(9950899855) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(9982948178)=["2286","5","7","9","9","38"] +timestampFromDateTime.call(["2286","5","7","9","9","38"])=9982948178 +jsDate(9982948178)=2286/5/7 9:9:38 +PASS jsDate matches +PASS timestampToDateTime.call(9982948178) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10014996502)=["2287","5","13","7","28","22"] +timestampFromDateTime.call(["2287","5","13","7","28","22"])=10014996502 +jsDate(10014996502)=2287/5/13 7:28:22 +PASS jsDate matches +PASS timestampToDateTime.call(10014996502) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10046581117)=["2288","5","12","20","58","37"] +timestampFromDateTime.call(["2288","5","12","20","58","37"])=10046581117 +jsDate(10046581117)=2288/5/12 20:58:37 +PASS jsDate matches +PASS timestampToDateTime.call(10046581117) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10078629440)=["2289","5","18","19","17","20"] +timestampFromDateTime.call(["2289","5","18","19","17","20"])=10078629440 +jsDate(10078629440)=2289/5/18 19:17:20 +PASS jsDate matches +PASS timestampToDateTime.call(10078629440) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10110677764)=["2290","5","24","17","36","4"] +timestampFromDateTime.call(["2290","5","24","17","36","4"])=10110677764 +jsDate(10110677764)=2290/5/24 17:36:4 +PASS jsDate matches +PASS timestampToDateTime.call(10110677764) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10142262379)=["2291","5","25","7","6","19"] +timestampFromDateTime.call(["2291","5","25","7","6","19"])=10142262379 +jsDate(10142262379)=2291/5/25 7:6:19 +PASS jsDate matches +PASS timestampToDateTime.call(10142262379) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10174310702)=["2292","5","30","5","25","2"] +timestampFromDateTime.call(["2292","5","30","5","25","2"])=10174310702 +jsDate(10174310702)=2292/5/30 5:25:2 +PASS jsDate matches +PASS timestampToDateTime.call(10174310702) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10206359026)=["2293","6","5","3","43","46"] +timestampFromDateTime.call(["2293","6","5","3","43","46"])=10206359026 +jsDate(10206359026)=2293/6/5 3:43:46 +PASS jsDate matches +PASS timestampToDateTime.call(10206359026) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10237943641)=["2294","6","5","17","14","1"] +timestampFromDateTime.call(["2294","6","5","17","14","1"])=10237943641 +jsDate(10237943641)=2294/6/5 17:14:1 +PASS jsDate matches +PASS timestampToDateTime.call(10237943641) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10269991964)=["2295","6","11","15","32","44"] +timestampFromDateTime.call(["2295","6","11","15","32","44"])=10269991964 +jsDate(10269991964)=2295/6/11 15:32:44 +PASS jsDate matches +PASS timestampToDateTime.call(10269991964) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10302040288)=["2296","6","16","13","51","28"] +timestampFromDateTime.call(["2296","6","16","13","51","28"])=10302040288 +jsDate(10302040288)=2296/6/16 13:51:28 +PASS jsDate matches +PASS timestampToDateTime.call(10302040288) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10333624903)=["2297","6","17","3","21","43"] +timestampFromDateTime.call(["2297","6","17","3","21","43"])=10333624903 +jsDate(10333624903)=2297/6/17 3:21:43 +PASS jsDate matches +PASS timestampToDateTime.call(10333624903) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10365673226)=["2298","6","23","1","40","26"] +timestampFromDateTime.call(["2298","6","23","1","40","26"])=10365673226 +jsDate(10365673226)=2298/6/23 1:40:26 +PASS jsDate matches +PASS timestampToDateTime.call(10365673226) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10397721550)=["2299","6","28","23","59","10"] +timestampFromDateTime.call(["2299","6","28","23","59","10"])=10397721550 +jsDate(10397721550)=2299/6/28 23:59:10 +PASS jsDate matches +PASS timestampToDateTime.call(10397721550) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10429306165)=["2300","6","29","13","29","25"] +timestampFromDateTime.call(["2300","6","29","13","29","25"])=10429306165 +jsDate(10429306165)=2300/6/29 13:29:25 +PASS jsDate matches +PASS timestampToDateTime.call(10429306165) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10461354488)=["2301","7","5","11","48","8"] +timestampFromDateTime.call(["2301","7","5","11","48","8"])=10461354488 +jsDate(10461354488)=2301/7/5 11:48:8 +PASS jsDate matches +PASS timestampToDateTime.call(10461354488) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10493402812)=["2302","7","11","10","6","52"] +timestampFromDateTime.call(["2302","7","11","10","6","52"])=10493402812 +jsDate(10493402812)=2302/7/11 10:6:52 +PASS jsDate matches +PASS timestampToDateTime.call(10493402812) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10524987427)=["2303","7","11","23","37","7"] +timestampFromDateTime.call(["2303","7","11","23","37","7"])=10524987427 +jsDate(10524987427)=2303/7/11 23:37:7 +PASS jsDate matches +PASS timestampToDateTime.call(10524987427) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10557035750)=["2304","7","16","21","55","50"] +timestampFromDateTime.call(["2304","7","16","21","55","50"])=10557035750 +jsDate(10557035750)=2304/7/16 21:55:50 +PASS jsDate matches +PASS timestampToDateTime.call(10557035750) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10589084074)=["2305","7","22","20","14","34"] +timestampFromDateTime.call(["2305","7","22","20","14","34"])=10589084074 +jsDate(10589084074)=2305/7/22 20:14:34 +PASS jsDate matches +PASS timestampToDateTime.call(10589084074) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10620668689)=["2306","7","23","9","44","49"] +timestampFromDateTime.call(["2306","7","23","9","44","49"])=10620668689 +jsDate(10620668689)=2306/7/23 9:44:49 +PASS jsDate matches +PASS timestampToDateTime.call(10620668689) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10652717012)=["2307","7","29","8","3","32"] +timestampFromDateTime.call(["2307","7","29","8","3","32"])=10652717012 +jsDate(10652717012)=2307/7/29 8:3:32 +PASS jsDate matches +PASS timestampToDateTime.call(10652717012) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10684765336)=["2308","8","3","6","22","16"] +timestampFromDateTime.call(["2308","8","3","6","22","16"])=10684765336 +jsDate(10684765336)=2308/8/3 6:22:16 +PASS jsDate matches +PASS timestampToDateTime.call(10684765336) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10716349951)=["2309","8","3","19","52","31"] +timestampFromDateTime.call(["2309","8","3","19","52","31"])=10716349951 +jsDate(10716349951)=2309/8/3 19:52:31 +PASS jsDate matches +PASS timestampToDateTime.call(10716349951) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10748398274)=["2310","8","9","18","11","14"] +timestampFromDateTime.call(["2310","8","9","18","11","14"])=10748398274 +jsDate(10748398274)=2310/8/9 18:11:14 +PASS jsDate matches +PASS timestampToDateTime.call(10748398274) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10780446598)=["2311","8","15","16","29","58"] +timestampFromDateTime.call(["2311","8","15","16","29","58"])=10780446598 +jsDate(10780446598)=2311/8/15 16:29:58 +PASS jsDate matches +PASS timestampToDateTime.call(10780446598) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10812031213)=["2312","8","15","6","0","13"] +timestampFromDateTime.call(["2312","8","15","6","0","13"])=10812031213 +jsDate(10812031213)=2312/8/15 6:0:13 +PASS jsDate matches +PASS timestampToDateTime.call(10812031213) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10844079536)=["2313","8","21","4","18","56"] +timestampFromDateTime.call(["2313","8","21","4","18","56"])=10844079536 +jsDate(10844079536)=2313/8/21 4:18:56 +PASS jsDate matches +PASS timestampToDateTime.call(10844079536) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10876127860)=["2314","8","27","2","37","40"] +timestampFromDateTime.call(["2314","8","27","2","37","40"])=10876127860 +jsDate(10876127860)=2314/8/27 2:37:40 +PASS jsDate matches +PASS timestampToDateTime.call(10876127860) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10907712475)=["2315","8","27","16","7","55"] +timestampFromDateTime.call(["2315","8","27","16","7","55"])=10907712475 +jsDate(10907712475)=2315/8/27 16:7:55 +PASS jsDate matches +PASS timestampToDateTime.call(10907712475) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10939760798)=["2316","9","1","14","26","38"] +timestampFromDateTime.call(["2316","9","1","14","26","38"])=10939760798 +jsDate(10939760798)=2316/9/1 14:26:38 +PASS jsDate matches +PASS timestampToDateTime.call(10939760798) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(10971809122)=["2317","9","7","12","45","22"] +timestampFromDateTime.call(["2317","9","7","12","45","22"])=10971809122 +jsDate(10971809122)=2317/9/7 12:45:22 +PASS jsDate matches +PASS timestampToDateTime.call(10971809122) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11003393737)=["2318","9","8","2","15","37"] +timestampFromDateTime.call(["2318","9","8","2","15","37"])=11003393737 +jsDate(11003393737)=2318/9/8 2:15:37 +PASS jsDate matches +PASS timestampToDateTime.call(11003393737) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11035442060)=["2319","9","14","0","34","20"] +timestampFromDateTime.call(["2319","9","14","0","34","20"])=11035442060 +jsDate(11035442060)=2319/9/14 0:34:20 +PASS jsDate matches +PASS timestampToDateTime.call(11035442060) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11067490384)=["2320","9","18","22","53","4"] +timestampFromDateTime.call(["2320","9","18","22","53","4"])=11067490384 +jsDate(11067490384)=2320/9/18 22:53:4 +PASS jsDate matches +PASS timestampToDateTime.call(11067490384) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11099074999)=["2321","9","19","12","23","19"] +timestampFromDateTime.call(["2321","9","19","12","23","19"])=11099074999 +jsDate(11099074999)=2321/9/19 12:23:19 +PASS jsDate matches +PASS timestampToDateTime.call(11099074999) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11131123322)=["2322","9","25","10","42","2"] +timestampFromDateTime.call(["2322","9","25","10","42","2"])=11131123322 +jsDate(11131123322)=2322/9/25 10:42:2 +PASS jsDate matches +PASS timestampToDateTime.call(11131123322) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11163171646)=["2323","10","1","9","0","46"] +timestampFromDateTime.call(["2323","10","1","9","0","46"])=11163171646 +jsDate(11163171646)=2323/10/1 9:0:46 +PASS jsDate matches +PASS timestampToDateTime.call(11163171646) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11194756261)=["2324","9","30","22","31","1"] +timestampFromDateTime.call(["2324","9","30","22","31","1"])=11194756261 +jsDate(11194756261)=2324/9/30 22:31:1 +PASS jsDate matches +PASS timestampToDateTime.call(11194756261) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11226804584)=["2325","10","6","20","49","44"] +timestampFromDateTime.call(["2325","10","6","20","49","44"])=11226804584 +jsDate(11226804584)=2325/10/6 20:49:44 +PASS jsDate matches +PASS timestampToDateTime.call(11226804584) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11258852908)=["2326","10","12","19","8","28"] +timestampFromDateTime.call(["2326","10","12","19","8","28"])=11258852908 +jsDate(11258852908)=2326/10/12 19:8:28 +PASS jsDate matches +PASS timestampToDateTime.call(11258852908) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11290437523)=["2327","10","13","8","38","43"] +timestampFromDateTime.call(["2327","10","13","8","38","43"])=11290437523 +jsDate(11290437523)=2327/10/13 8:38:43 +PASS jsDate matches +PASS timestampToDateTime.call(11290437523) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11322485846)=["2328","10","18","6","57","26"] +timestampFromDateTime.call(["2328","10","18","6","57","26"])=11322485846 +jsDate(11322485846)=2328/10/18 6:57:26 +PASS jsDate matches +PASS timestampToDateTime.call(11322485846) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11354534170)=["2329","10","24","5","16","10"] +timestampFromDateTime.call(["2329","10","24","5","16","10"])=11354534170 +jsDate(11354534170)=2329/10/24 5:16:10 +PASS jsDate matches +PASS timestampToDateTime.call(11354534170) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11386118785)=["2330","10","24","18","46","25"] +timestampFromDateTime.call(["2330","10","24","18","46","25"])=11386118785 +jsDate(11386118785)=2330/10/24 18:46:25 +PASS jsDate matches +PASS timestampToDateTime.call(11386118785) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11418167108)=["2331","10","30","17","5","8"] +timestampFromDateTime.call(["2331","10","30","17","5","8"])=11418167108 +jsDate(11418167108)=2331/10/30 17:5:8 +PASS jsDate matches +PASS timestampToDateTime.call(11418167108) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11450215432)=["2332","11","4","15","23","52"] +timestampFromDateTime.call(["2332","11","4","15","23","52"])=11450215432 +jsDate(11450215432)=2332/11/4 15:23:52 +PASS jsDate matches +PASS timestampToDateTime.call(11450215432) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11481800047)=["2333","11","5","4","54","7"] +timestampFromDateTime.call(["2333","11","5","4","54","7"])=11481800047 +jsDate(11481800047)=2333/11/5 4:54:7 +PASS jsDate matches +PASS timestampToDateTime.call(11481800047) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11513848370)=["2334","11","11","3","12","50"] +timestampFromDateTime.call(["2334","11","11","3","12","50"])=11513848370 +jsDate(11513848370)=2334/11/11 3:12:50 +PASS jsDate matches +PASS timestampToDateTime.call(11513848370) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11545896694)=["2335","11","17","1","31","34"] +timestampFromDateTime.call(["2335","11","17","1","31","34"])=11545896694 +jsDate(11545896694)=2335/11/17 1:31:34 +PASS jsDate matches +PASS timestampToDateTime.call(11545896694) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11577481309)=["2336","11","16","15","1","49"] +timestampFromDateTime.call(["2336","11","16","15","1","49"])=11577481309 +jsDate(11577481309)=2336/11/16 15:1:49 +PASS jsDate matches +PASS timestampToDateTime.call(11577481309) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11609529632)=["2337","11","22","13","20","32"] +timestampFromDateTime.call(["2337","11","22","13","20","32"])=11609529632 +jsDate(11609529632)=2337/11/22 13:20:32 +PASS jsDate matches +PASS timestampToDateTime.call(11609529632) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11641577956)=["2338","11","28","11","39","16"] +timestampFromDateTime.call(["2338","11","28","11","39","16"])=11641577956 +jsDate(11641577956)=2338/11/28 11:39:16 +PASS jsDate matches +PASS timestampToDateTime.call(11641577956) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11673162571)=["2339","11","29","1","9","31"] +timestampFromDateTime.call(["2339","11","29","1","9","31"])=11673162571 +jsDate(11673162571)=2339/11/29 1:9:31 +PASS jsDate matches +PASS timestampToDateTime.call(11673162571) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11705210894)=["2340","12","3","23","28","14"] +timestampFromDateTime.call(["2340","12","3","23","28","14"])=11705210894 +jsDate(11705210894)=2340/12/3 23:28:14 +PASS jsDate matches +PASS timestampToDateTime.call(11705210894) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11737259218)=["2341","12","9","21","46","58"] +timestampFromDateTime.call(["2341","12","9","21","46","58"])=11737259218 +jsDate(11737259218)=2341/12/9 21:46:58 +PASS jsDate matches +PASS timestampToDateTime.call(11737259218) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11768843833)=["2342","12","10","11","17","13"] +timestampFromDateTime.call(["2342","12","10","11","17","13"])=11768843833 +jsDate(11768843833)=2342/12/10 11:17:13 +PASS jsDate matches +PASS timestampToDateTime.call(11768843833) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11800892156)=["2343","12","16","9","35","56"] +timestampFromDateTime.call(["2343","12","16","9","35","56"])=11800892156 +jsDate(11800892156)=2343/12/16 9:35:56 +PASS jsDate matches +PASS timestampToDateTime.call(11800892156) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11832940480)=["2344","12","21","7","54","40"] +timestampFromDateTime.call(["2344","12","21","7","54","40"])=11832940480 +jsDate(11832940480)=2344/12/21 7:54:40 +PASS jsDate matches +PASS timestampToDateTime.call(11832940480) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11864525095)=["2345","12","21","21","24","55"] +timestampFromDateTime.call(["2345","12","21","21","24","55"])=11864525095 +jsDate(11864525095)=2345/12/21 21:24:55 +PASS jsDate matches +PASS timestampToDateTime.call(11864525095) => timestampFromDateTime.call(...) matches + +timestampToDateTime.call(11896573418)=["2346","12","27","19","43","38"] +timestampFromDateTime.call(["2346","12","27","19","43","38"])=11896573418 +jsDate(11896573418)=2346/12/27 19:43:38 +PASS jsDate matches +PASS timestampToDateTime.call(11896573418) => timestampFromDateTime.call(...) matches + +---------- PASS - no failures detected ---------- diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-30.360937280Z--a00af22d07c87d96eeeb0ed583f8f6ac7812827e b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-30.360937280Z--a00af22d07c87d96eeeb0ed583f8f6ac7812827e new file mode 100644 index 0000000..1326d83 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-30.360937280Z--a00af22d07c87d96eeeb0ed583f8f6ac7812827e @@ -0,0 +1 @@ +{"address":"a00af22d07c87d96eeeb0ed583f8f6ac7812827e","crypto":{"cipher":"aes-128-ctr","ciphertext":"7746ca0958bde0c8404f27e102f2fbb74eae623786ec344362e3434934a55b7d","cipherparams":{"iv":"5fc7dce773e69818a2d08f293657dbad"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f3675b3f9a1f414e429249eecc41c3ea20c6023012362fe8bf9e4ea231fc3801"},"mac":"c1fc366ec058c62c29e0e1668f997e20d08a9e57c7335dcf0d6d38e9faddfca5"},"id":"e3f0faf2-6ec2-4f29-a14e-c48d2d751b94","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-58.104082316Z--a11aae29840fbb5c86e6fd4cf809eba183aef433 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-58.104082316Z--a11aae29840fbb5c86e6fd4cf809eba183aef433 new file mode 100644 index 0000000..aa5b3cb --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-58.104082316Z--a11aae29840fbb5c86e6fd4cf809eba183aef433 @@ -0,0 +1 @@ +{"address":"a11aae29840fbb5c86e6fd4cf809eba183aef433","crypto":{"cipher":"aes-128-ctr","ciphertext":"a025e7b46192578ac826200c281e6d7d83ba31c93c33c8d575dbe8fc1a75b1b9","cipherparams":{"iv":"b1e35272e6823a857e11627cfa20ffd6"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"0943b2a690f33601eba2a545435a3463d7d9b7ce96d15b544a0db14377ab5202"},"mac":"d2afc76e4fb19d01920e2822fd0cc760824b10e710ce565bdd1369d52fcdc741"},"id":"f1b73a4b-8229-4c3b-8844-f59f398087b0","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-21.169063367Z--a22ab8a9d641ce77e06d98b7d7065d324d3d6976 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-21.169063367Z--a22ab8a9d641ce77e06d98b7d7065d324d3d6976 new file mode 100644 index 0000000..3932072 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-21.169063367Z--a22ab8a9d641ce77e06d98b7d7065d324d3d6976 @@ -0,0 +1 @@ +{"address":"a22ab8a9d641ce77e06d98b7d7065d324d3d6976","crypto":{"cipher":"aes-128-ctr","ciphertext":"8a5a891ef2a10dc0d7faaa3bc01cd48d2bb38aca285f9acd73889f54e03ad017","cipherparams":{"iv":"17401904119a8f70861dfe9a9b02a463"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"e1e7f968847eaaf620f3c5e3541b6a3f0d8e00df9a9d470952eb6bf31cbb398b"},"mac":"de7767918e49ce2ec36b0dd8c85f8853f2b2db39da70f8b8a52d7d8c6856a6de"},"id":"baa6c875-74cf-4c02-ace7-c8c6aa32765f","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-41.707647638Z--a33a6c312d9ad0e0f2e95541beed0cc081621fd0 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-41.707647638Z--a33a6c312d9ad0e0f2e95541beed0cc081621fd0 new file mode 100644 index 0000000..677c783 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-41.707647638Z--a33a6c312d9ad0e0f2e95541beed0cc081621fd0 @@ -0,0 +1 @@ +{"address":"a33a6c312d9ad0e0f2e95541beed0cc081621fd0","crypto":{"cipher":"aes-128-ctr","ciphertext":"6291be87d8beb1a5a9833946c0727a93f531c341316d3ca32a97e36513b829bf","cipherparams":{"iv":"37e0e2897ff5de0a2b34ddbc7f67a7bd"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"2633c529cb47901bba6f3cf8acb8aa3f27d218e3120b1f0832f5acac7e12830a"},"mac":"b1ace4451045b2cb06507a719e7e9edb97b7c9ce38e42014472cbb4f52ed4d5f"},"id":"7ab0d4a9-c6b5-426f-9445-1604929628c2","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-39-04.584040707Z--a44a08d3f6933c69212114bb66e2df1813651844 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-39-04.584040707Z--a44a08d3f6933c69212114bb66e2df1813651844 new file mode 100644 index 0000000..b31da20 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-39-04.584040707Z--a44a08d3f6933c69212114bb66e2df1813651844 @@ -0,0 +1 @@ +{"address":"a44a08d3f6933c69212114bb66e2df1813651844","crypto":{"cipher":"aes-128-ctr","ciphertext":"0334a6431e1278ef00ec18262d71325fb6cbec744708bdd306757d23bf9665b2","cipherparams":{"iv":"707c645f21c317d506b7f0d3073d85a1"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"7bc76dc778baef6878f043da5461f40faa700d029b8dbde5a10a7899129e329a"},"mac":"ffb6282494f01133507fc97bf57d8a7644205e0dab33dc977bf809e541c8f41e"},"id":"356880ad-1c9d-4bd1-92ce-48de1a668c8f","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-01.013666678Z--a55a151eb00fded1634d27d1127b4be4627079ea b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-01.013666678Z--a55a151eb00fded1634d27d1127b4be4627079ea new file mode 100644 index 0000000..e728140 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-01.013666678Z--a55a151eb00fded1634d27d1127b4be4627079ea @@ -0,0 +1 @@ +{"address":"a55a151eb00fded1634d27d1127b4be4627079ea","crypto":{"cipher":"aes-128-ctr","ciphertext":"ee8985250e7b89990b8614f9ceec5f96f11e66ef147e2a689ac29bcdbab5142c","cipherparams":{"iv":"594d35ce8d73e0efb89ddc882f13d912"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"e9635fc62fb0b9db5c0ffa6cd415f7b58c3dc4b5d9af700aac347a568792dc82"},"mac":"6b035510432179623cbaa5d3306106d5c608695fde89d7ec2d3aff5f484a6376"},"id":"47bfbb81-5b55-4cf4-9289-80e2fe0fbd9c","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-37.426191216Z--a66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-37.426191216Z--a66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 new file mode 100644 index 0000000..8f16149 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-37.426191216Z--a66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 @@ -0,0 +1 @@ +{"address":"a66a85ede0cbe03694aa9d9de0bb19c99ff55bd9","crypto":{"cipher":"aes-128-ctr","ciphertext":"f1b8dfabcdc9da96c9ee44a0ee7005b17bcdeda702e7fb17624a35bd51252d28","cipherparams":{"iv":"c762e2bd794022892e1d99c7494b7a41"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"d92954d1c8073978d17c5943b72aa826108c8cc927b1097a7ea3ef71b02d15cc"},"mac":"dd118288bb676dca7a7607ff86ed02eccfa4dfac2ebef69bf52dc0304e1af465"},"id":"396c5807-24e8-4a78-a76e-5dfcd0e2dfe4","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-58.899396047Z--a77a2b9d4b1c010a22a7c565dc418cef683dbcec b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-58.899396047Z--a77a2b9d4b1c010a22a7c565dc418cef683dbcec new file mode 100644 index 0000000..a634564 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-58.899396047Z--a77a2b9d4b1c010a22a7c565dc418cef683dbcec @@ -0,0 +1 @@ +{"address":"a77a2b9d4b1c010a22a7c565dc418cef683dbcec","crypto":{"cipher":"aes-128-ctr","ciphertext":"6f4262c172be2e9053e556380e5ea842959e0ffa51c17fc270259832f3cfe91a","cipherparams":{"iv":"b056c35ee783e7bcdf58e70b717c8bf8"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"35a93f01a9cc1dcb323305b15cdd22ad899796f620783fab8512b0100eb478da"},"mac":"20088a8203dc6e2a8ff5288799700aaf969424912cdfd5b1e9262fd703ea2da8"},"id":"46a2e757-d4e9-40ba-aec4-6640d7b74347","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-09.150580614Z--a88a05d2b88283ce84c8325760b72a64591279a2 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-09.150580614Z--a88a05d2b88283ce84c8325760b72a64591279a2 new file mode 100644 index 0000000..2facc97 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-09.150580614Z--a88a05d2b88283ce84c8325760b72a64591279a2 @@ -0,0 +1 @@ +{"address":"a88a05d2b88283ce84c8325760b72a64591279a2","crypto":{"cipher":"aes-128-ctr","ciphertext":"3d3331aeb08de887031a50ec00c4385dc2f3ee28b3f720b788964b45a77321c7","cipherparams":{"iv":"c5024557ef11f71d86209aa5cb9c90bd"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"130cd49e03cbf0eccba0d430c7c545be2dd9ed78120b42a128974b63e644c283"},"mac":"e98487a07e49dcde74e890d1dd9ea51d07aa62ecf19d96c782599c265c5a90c7"},"id":"5083b6d1-3059-457f-bdae-6a413a222428","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-34.770098207Z--a99a0ae3354c06b1459fd441a32a3f71005d7da0 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-34.770098207Z--a99a0ae3354c06b1459fd441a32a3f71005d7da0 new file mode 100644 index 0000000..c92351b --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-34.770098207Z--a99a0ae3354c06b1459fd441a32a3f71005d7da0 @@ -0,0 +1 @@ +{"address":"a99a0ae3354c06b1459fd441a32a3f71005d7da0","crypto":{"cipher":"aes-128-ctr","ciphertext":"92983913294e4fac0d23b2aa87371c63538e3735fc99c9212f4b3db8301ecccf","cipherparams":{"iv":"cab44152a75c5abccdb1f90a849c84ca"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"29ac10474ba160267a637197d12e938ee313daa501f6b0883ae96da4c19f6155"},"mac":"224930b5688b9e0cc77d321610e440c32af3372fe4b17d8e451bf2c3c89ddf25"},"id":"47cc9299-fea0-46c6-88e8-452fb714ca4c","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-17.400859858Z--aaaa9de1e6c564446ebca0fd102d8bd92093c756 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-17.400859858Z--aaaa9de1e6c564446ebca0fd102d8bd92093c756 new file mode 100644 index 0000000..9ed8a8c --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-17.400859858Z--aaaa9de1e6c564446ebca0fd102d8bd92093c756 @@ -0,0 +1 @@ +{"address":"aaaa9de1e6c564446ebca0fd102d8bd92093c756","crypto":{"cipher":"aes-128-ctr","ciphertext":"525cb018c05b12bb038b9802c8d28dda40bdd8027a5a94efdfe5f06d13428020","cipherparams":{"iv":"31b96dade192e677db9d03ca2da3dd4b"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"aaf8e556d62452fb946046397c8c58545cbb1e118a3f3e3b8cc2995a2e9020a7"},"mac":"bbc30ecbf1ca76ee507c08db2dc07611b29a69a5f3de3bb2b0c92a1b8e0cb6b3"},"id":"9ae73070-0b07-472c-bfe5-e07cbe66f289","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-35.122799190Z--abba43e7594e3b76afb157989e93c6621497fd4b b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-35.122799190Z--abba43e7594e3b76afb157989e93c6621497fd4b new file mode 100644 index 0000000..4d6513a --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-35.122799190Z--abba43e7594e3b76afb157989e93c6621497fd4b @@ -0,0 +1 @@ +{"address":"abba43e7594e3b76afb157989e93c6621497fd4b","crypto":{"cipher":"aes-128-ctr","ciphertext":"9d93b2417788589c2bbc56d829189ee7014a131cde75ff222ed95765760e33e9","cipherparams":{"iv":"72adceb8556da2df85337eb7e3857e91"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f81be6c897007703d414b4849894395cecb982380791ff29b9742ee7ab1b9437"},"mac":"ed0dbee8cbde6219c7c15c501ca31146705c0d310301aa73311c0bf943712127"},"id":"be47d6a6-f747-4741-bdfd-33182d2f674d","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-51.178332229Z--acca534c9f62ab495bd986e002ddf0f054caae4f b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-51.178332229Z--acca534c9f62ab495bd986e002ddf0f054caae4f new file mode 100644 index 0000000..1766622 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-51.178332229Z--acca534c9f62ab495bd986e002ddf0f054caae4f @@ -0,0 +1 @@ +{"address":"acca534c9f62ab495bd986e002ddf0f054caae4f","crypto":{"cipher":"aes-128-ctr","ciphertext":"95204bfd49fad4e3ef709e55857b0fa9f0e9d03c1e2219a44408bddafd45ba72","cipherparams":{"iv":"9ae7d4de6b7d7d78fd0c6499dda0f35d"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"2be91d7a047ae89c934f2b09b541887ac8a7dfb99df658e05f9ee05f2c5ef478"},"mac":"d9abc981e0b3d7ca60d3138dce58e5529bb12fee092cdd77a0a93b453e22dd3b"},"id":"3cae58b4-bdd3-43ee-929c-b1eff57e10ad","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-14.034178720Z--adda9b762a00ff12711113bfdc36958b73d7f915 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-14.034178720Z--adda9b762a00ff12711113bfdc36958b73d7f915 new file mode 100644 index 0000000..01d6310 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-14.034178720Z--adda9b762a00ff12711113bfdc36958b73d7f915 @@ -0,0 +1 @@ +{"address":"adda9b762a00ff12711113bfdc36958b73d7f915","crypto":{"cipher":"aes-128-ctr","ciphertext":"0bacd07a24fee23bcb01e05f7f75ba8fc862500a8c76274dcdb85c6f46886623","cipherparams":{"iv":"e7ec110f1ff5d8bfc45f7d73e19dbd9f"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"b774e6680f20cafce454fc994ad2ba33afd3556feeea7f5338bcaadeb3559de3"},"mac":"fec0ec38202864975845c5602150c62b8ade0538cfdb9b6a0cdbaf48a916d18c"},"id":"b6b3a3ab-35fe-48aa-a74a-681a08cfea36","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-33.471449656Z--aeea63b5479b50f79583ec49dacdcf86ddeff392 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-33.471449656Z--aeea63b5479b50f79583ec49dacdcf86ddeff392 new file mode 100644 index 0000000..c79f607 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-33.471449656Z--aeea63b5479b50f79583ec49dacdcf86ddeff392 @@ -0,0 +1 @@ +{"address":"aeea63b5479b50f79583ec49dacdcf86ddeff392","crypto":{"cipher":"aes-128-ctr","ciphertext":"88e5fd79e85032bb427b082f9875de72b21aca1acb0370b59fe301306510f68f","cipherparams":{"iv":"da6522bfd41e2676def953ee017f5f23"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"a8770326e860c28a45d1aff231560bc00a69622dad0f50d9ff395ec1f6f1b453"},"mac":"128e84afe94656cc89e96180676607cfaae0c4b220eec2e11642b7cd38146226"},"id":"b6dcecff-9bbb-40c5-bcea-501e3d610c7b","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-51.697690594Z--affa4d3a80add8ce4018540e056dacb649589394 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-51.697690594Z--affa4d3a80add8ce4018540e056dacb649589394 new file mode 100644 index 0000000..613dde0 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-51.697690594Z--affa4d3a80add8ce4018540e056dacb649589394 @@ -0,0 +1 @@ +{"address":"affa4d3a80add8ce4018540e056dacb649589394","crypto":{"cipher":"aes-128-ctr","ciphertext":"575889b5c78941e143e3af18ab2fd614d6a36846dbc424bda006f40a8ccdd4ef","cipherparams":{"iv":"1a6fb0f7f7bbf9692568853037786fa2"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"4ec7f5ad42e5c55fd8eac0f0553a1e6a5c363d8e835fc048673560f9e36bfcfc"},"mac":"6373ec14230362fc815c2929b8058a83b9a2f3e6d3e92b35c2d2696a0ba4cf8d"},"id":"8af80842-e108-4256-b33f-9fa5fb5f6de5","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-46-38.500831000Z--b00bfde102270687324f9205b693859df64f8923 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-46-38.500831000Z--b00bfde102270687324f9205b693859df64f8923 new file mode 100644 index 0000000..3e5e325 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-46-38.500831000Z--b00bfde102270687324f9205b693859df64f8923 @@ -0,0 +1 @@ +{"address":"b00bfde102270687324f9205b693859df64f8923","crypto":{"cipher":"aes-128-ctr","ciphertext":"35a15a36140fe96dd1eca2b68fbbfd950e892edd5cb1885c99f0ef67ad83d93a","cipherparams":{"iv":"f1fe0fa1b348fb133087f82eb01780b8"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f152543f3b3ec82d834273256aff02ea0776323c31b3f1b5f2717e5bd428e9a3"},"mac":"851663b1e882a5443e64f886ae38aed51544f7603a73433d587272871316f5b8"},"id":"cb1bb6d8-9c68-46ce-93cb-36e33ffd19c6","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-13.633282000Z--b11be1d4ef8e94d01cb2695092a79d139a8dad98 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-13.633282000Z--b11be1d4ef8e94d01cb2695092a79d139a8dad98 new file mode 100644 index 0000000..1faa375 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-13.633282000Z--b11be1d4ef8e94d01cb2695092a79d139a8dad98 @@ -0,0 +1 @@ +{"address":"b11be1d4ef8e94d01cb2695092a79d139a8dad98","crypto":{"cipher":"aes-128-ctr","ciphertext":"4fcea88902f73ca1b8436f901116dd708e4f5523b377fd0712856f1aea29eb90","cipherparams":{"iv":"eb7e8d31dc6a2cfc97e246736d36e915"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"3b5af400423f21363f700cc06f83f59d5391812520572c76bcdab0f257f01651"},"mac":"1664521b7de10c689094f73b90f724ac864d56cbac4b84e7efd0730f70dba747"},"id":"f88012ab-cbc8-43b0-bd2f-0b7d2a3edc95","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-34.792913000Z--b22be2d9eef0d7e260cf96a64feea0b95ed3e74f b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-34.792913000Z--b22be2d9eef0d7e260cf96a64feea0b95ed3e74f new file mode 100644 index 0000000..b5973bc --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-34.792913000Z--b22be2d9eef0d7e260cf96a64feea0b95ed3e74f @@ -0,0 +1 @@ +{"address":"b22be2d9eef0d7e260cf96a64feea0b95ed3e74f","crypto":{"cipher":"aes-128-ctr","ciphertext":"832a92865948d045dd35a0f2bce83bc6de81549b9d42dbd65c7a7fcd85dd3bf6","cipherparams":{"iv":"05e0d8e5a40ea28f19d4b6476fc00c9b"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"3b62430be26cdee906d5478258e0bb3161c71c285ea7cda7086679d83a81ac9f"},"mac":"d201c1b1b483b0f35e6cd3c683aee09825fc99c4eb696ae3095a857a23cade03"},"id":"bc0436d0-09ff-4445-8ac7-9908950ff795","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-50-14.030093000Z--b33b7ecf5e47be3981c74d989d3af8b665b4b649 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-50-14.030093000Z--b33b7ecf5e47be3981c74d989d3af8b665b4b649 new file mode 100644 index 0000000..94b58c8 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-50-14.030093000Z--b33b7ecf5e47be3981c74d989d3af8b665b4b649 @@ -0,0 +1 @@ +{"address":"b33b7ecf5e47be3981c74d989d3af8b665b4b649","crypto":{"cipher":"aes-128-ctr","ciphertext":"3a3b04be39786bf87a9f4b4b2690379b4eca20b8ad4d0da2006411f05c07efe3","cipherparams":{"iv":"c815748114f2d09d6d15d3a00b3a483d"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"d89f0c41bed67c651bfe912ea7ead8cb413b1ee0a69143a1260bd0bcae40ac84"},"mac":"89230f76ec55390f350b5382ac5d37e13e77d2d161d7de04b8610df7b55a7581"},"id":"2dab1c9d-f601-4650-b48e-dcdff71f507e","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-51-02.743266000Z--b44b43d59b738b088b690ae276c1e979aba8268d b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-51-02.743266000Z--b44b43d59b738b088b690ae276c1e979aba8268d new file mode 100644 index 0000000..29be954 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-51-02.743266000Z--b44b43d59b738b088b690ae276c1e979aba8268d @@ -0,0 +1 @@ +{"address":"b44b43d59b738b088b690ae276c1e979aba8268d","crypto":{"cipher":"aes-128-ctr","ciphertext":"e6bbab4c2bfcfaa33bbafacae6cc571b5db9857f3a7fdab78e876476635e3a00","cipherparams":{"iv":"f093dbbc316014d016b2bc32bd32780b"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"0080c34c2d31eecb545ebea48d24ee707d9e553fcc99f5c552def09806fba6f8"},"mac":"3eef10bc5656f54f38f4948af7e17ad970e739647487a9d1ecc797caecf2c06d"},"id":"a6c44866-ec89-4c2d-94a9-750a4150f24a","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-16.250696000Z--b55b57d113b45481e31aaf03d6f4e5ad4ef325f8 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-16.250696000Z--b55b57d113b45481e31aaf03d6f4e5ad4ef325f8 new file mode 100644 index 0000000..d4bbda7 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-16.250696000Z--b55b57d113b45481e31aaf03d6f4e5ad4ef325f8 @@ -0,0 +1 @@ +{"address":"b55b57d113b45481e31aaf03d6f4e5ad4ef325f8","crypto":{"cipher":"aes-128-ctr","ciphertext":"2fce0fe5d7e583df0cef51e29bcc38dd0c398ae726875681e6d58cd82f462636","cipherparams":{"iv":"64d3586f82f429a940cb76913a3e5de0"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"6236c42555711facadffd9756963240c109fdf7a5b47fc2c136d4f597393c97e"},"mac":"3a523b8196c671c21e93d29c51dc5f44fb73aae24e79a8a22193d08241acb6de"},"id":"64956427-5805-4c06-bfaf-0ea4c2d22093","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-56.678333000Z--b66bcb4e473de80e2c8a47ced10c22c705a5e602 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-56.678333000Z--b66bcb4e473de80e2c8a47ced10c22c705a5e602 new file mode 100644 index 0000000..8fa9ba7 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-56.678333000Z--b66bcb4e473de80e2c8a47ced10c22c705a5e602 @@ -0,0 +1 @@ +{"address":"b66bcb4e473de80e2c8a47ced10c22c705a5e602","crypto":{"cipher":"aes-128-ctr","ciphertext":"fc80becce2d16f01c117c298bb24436e9eebfc43d07b76760ae62825a12569cc","cipherparams":{"iv":"42e5d0f5a5ea7b0e3e433edda6a4147b"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ab72efd6bdf0c9f07b272bc1a030db8918007b9b9faf3c8096e80db016c6dbe4"},"mac":"2b45bd7c8167b76c9c95c77747ac933318acaea2aade500f5394c5321f9a41c7"},"id":"45c4cf16-2bf0-46f3-bc41-1b582ba794fa","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-55-56.546405000Z--b77bbbaa7c1649547ae61de4b80b91568c28351a b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-55-56.546405000Z--b77bbbaa7c1649547ae61de4b80b91568c28351a new file mode 100644 index 0000000..b055ced --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-55-56.546405000Z--b77bbbaa7c1649547ae61de4b80b91568c28351a @@ -0,0 +1 @@ +{"address":"b77bbbaa7c1649547ae61de4b80b91568c28351a","crypto":{"cipher":"aes-128-ctr","ciphertext":"767d6658fb2fe43c47de4b40a9fc2ce7bddd2f518566276da20f9f389d38e142","cipherparams":{"iv":"85d12a9dea777bf7537261405af7a3ff"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"b72744837e610dd9384af2ccaac73cd90fb41c543427e18bf706ec53f2270502"},"mac":"fa6fe6e6996ec6683bbba4851c6544f2484f898f3a1b247612b8fb811612fd94"},"id":"e18c9c63-ce88-4b96-8085-88549589cccf","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-58-22.605806000Z--b88b728490b417e29b0784db30535db343830dba b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-58-22.605806000Z--b88b728490b417e29b0784db30535db343830dba new file mode 100644 index 0000000..3fa0afe --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-58-22.605806000Z--b88b728490b417e29b0784db30535db343830dba @@ -0,0 +1 @@ +{"address":"b88b728490b417e29b0784db30535db343830dba","crypto":{"cipher":"aes-128-ctr","ciphertext":"31e956f9396b0d179c1136a03cfa7fc3c8f0f980b48537836aacec7f61bc8886","cipherparams":{"iv":"5d2778c9221aab3c0525f562b2f87ef5"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"d9f0731deef314e2772397e838b65410fa26d282d927c8254b839a4eac42e1fe"},"mac":"8c1e4c56aba715e04f0f8ce48460f47f194c10d7a18ca501ba6d019fa85f1768"},"id":"a0038920-3917-43eb-b308-80f7e660f77b","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-59-11.614985000Z--b99b3d1f72edb05a0321db58eddcf83fd73c4ade b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-59-11.614985000Z--b99b3d1f72edb05a0321db58eddcf83fd73c4ade new file mode 100644 index 0000000..d5e45a0 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-59-11.614985000Z--b99b3d1f72edb05a0321db58eddcf83fd73c4ade @@ -0,0 +1 @@ +{"address":"b99b3d1f72edb05a0321db58eddcf83fd73c4ade","crypto":{"cipher":"aes-128-ctr","ciphertext":"05fd0fbb32d77fe2b2bc8f263b9537a55344c1c7548e523a4fb8c55d11994613","cipherparams":{"iv":"c111f6674336e452981b474d770d28e7"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"449f356632539f47beaff2a41cb55d28b00755aef0aaadf60ac1fed6a6fd94de"},"mac":"de231546e4b1b03da76dfab1f77b2658109234eddcd7e3c15da92d0931f5664f"},"id":"5bba5e7f-db58-45f4-adb4-c6d8a285b018","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-06.765694000Z--baab56da883edbe5314b8005be410022c510ccae b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-06.765694000Z--baab56da883edbe5314b8005be410022c510ccae new file mode 100644 index 0000000..9809c1c --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-06.765694000Z--baab56da883edbe5314b8005be410022c510ccae @@ -0,0 +1 @@ +{"address":"baab56da883edbe5314b8005be410022c510ccae","crypto":{"cipher":"aes-128-ctr","ciphertext":"2776d97b30f53bfda59941dc62a5e5267a383160e94e60c79877ad337b0d237f","cipherparams":{"iv":"c1d4d608e272f4fc02d8a9436161cae2"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"23244e4fd4394d6effe0c05af91af1db41b8e7ba7b953bf2bd8df10d549297a3"},"mac":"e3b0a4bc3cb9912247bc1285f2b5a2e4cd772872a1519efbd347c9fd3e1bde24"},"id":"c53d37a2-0791-4915-89d0-15beee16f8a2","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-29.951106000Z--bbbb9809de0456ce0e0cd660e6e4ceabef3f521c b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-29.951106000Z--bbbb9809de0456ce0e0cd660e6e4ceabef3f521c new file mode 100644 index 0000000..04a9661 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-29.951106000Z--bbbb9809de0456ce0e0cd660e6e4ceabef3f521c @@ -0,0 +1 @@ +{"address":"bbbb9809de0456ce0e0cd660e6e4ceabef3f521c","crypto":{"cipher":"aes-128-ctr","ciphertext":"60f89b1ca820a34e0d2c25321f338836ab3873efcc3ccefa99403bb8ef7d34ac","cipherparams":{"iv":"0ffce5b666507c9e1c910cdadd2b6661"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"facd3a865fc9d97ad636a1bd3e8ef540f2036ee4765468843a6786e6cb727aa7"},"mac":"dcbca27db50cd3ac35b75d28a17a50242d699b285ce822b9d409e1e927fa1913"},"id":"77d9c9bd-be5f-46de-861c-949cdf437610","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-29.293263000Z--bccb68dd0ac87ef290aef49870d155f076c87868 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-29.293263000Z--bccb68dd0ac87ef290aef49870d155f076c87868 new file mode 100644 index 0000000..959d4a8 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-29.293263000Z--bccb68dd0ac87ef290aef49870d155f076c87868 @@ -0,0 +1 @@ +{"address":"bccb68dd0ac87ef290aef49870d155f076c87868","crypto":{"cipher":"aes-128-ctr","ciphertext":"e2f82512052dc1e7ed9a435f08876b241f42332dfdfc96f6ee197310b2d50468","cipherparams":{"iv":"a12c55d704f3e2aa8b18eee04cbbddc0"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"91bbbf4f3301d395ebfffb741ffa1764ff198f7688f2211cd77f5b9b99d419d0"},"mac":"202a5b0fd250f90a786d01e9f17cd7eb431f5093abc74a96c6c0fd493844d56e"},"id":"f6728945-50eb-40d7-b74f-225210bdb27d","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-54.216243000Z--bddb726ee06906e104db210e6d0506f2b062e477 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-54.216243000Z--bddb726ee06906e104db210e6d0506f2b062e477 new file mode 100644 index 0000000..f70f986 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-54.216243000Z--bddb726ee06906e104db210e6d0506f2b062e477 @@ -0,0 +1 @@ +{"address":"bddb726ee06906e104db210e6d0506f2b062e477","crypto":{"cipher":"aes-128-ctr","ciphertext":"fc86d192ff984371fe9a307a94622f52b83d243df1c1e2c87c95cfe404cab9d0","cipherparams":{"iv":"abac565370e5ef73b3a300b993eef903"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"0e17376f4214ed015ec12f9531eb7087293a792a27cfc799a718a34b4a9f006f"},"mac":"37e419d92fe7afe29dce9facd3be51929a0121f6579040fca8b7a7eaeb4f8360"},"id":"cdbc98f8-59c3-4823-9f6f-f02e652315fb","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-08-54.756436000Z--beeb24ff18203658d0a1d4682ee3f36ad663ec87 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-08-54.756436000Z--beeb24ff18203658d0a1d4682ee3f36ad663ec87 new file mode 100644 index 0000000..9bf024d --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-08-54.756436000Z--beeb24ff18203658d0a1d4682ee3f36ad663ec87 @@ -0,0 +1 @@ +{"address":"beeb24ff18203658d0a1d4682ee3f36ad663ec87","crypto":{"cipher":"aes-128-ctr","ciphertext":"867f7f20c9bc0cc77e33f5ffe654ec64d700cbfe8b95a9cd35a035c669a4f7df","cipherparams":{"iv":"2ded8c674918626a2f8b0b2442f63b5e"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"9e48eb9d0e9d138512251dde8ccbed433616704bc88dc17d688199d24bfb504e"},"mac":"ea4a9704c4974fce6b85f3f95b31a1e64ed294c69ea2e5110f837ea73b85d595"},"id":"7af67eed-c600-4622-a939-6700bbd25c75","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-09-53.679255000Z--bffbd8f029ef0bd81cf754b53e8b3a5684f8b3ff b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-09-53.679255000Z--bffbd8f029ef0bd81cf754b53e8b3a5684f8b3ff new file mode 100644 index 0000000..e3a3b90 --- /dev/null +++ b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-09-53.679255000Z--bffbd8f029ef0bd81cf754b53e8b3a5684f8b3ff @@ -0,0 +1 @@ +{"address":"bffbd8f029ef0bd81cf754b53e8b3a5684f8b3ff","crypto":{"cipher":"aes-128-ctr","ciphertext":"74d1fbc0f815262e20f6dc089c7370c64678a56cc2ebf8bd54f0e8cff854e61f","cipherparams":{"iv":"46f9abced6bb053168b1cc1ed1c759a3"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ca6928880f930bc6ab285ccc798dc25de1540b059b885306825f7b98a8ffceb8"},"mac":"ec1dd0e7454ad21e9a22173e1209ea0355e96d583eb8fc4d4ff603de9155875b"},"id":"42466d6f-39e7-4b07-bafb-5409d60fc2bc","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/forge-std/.gitattributes b/typescript/packages/account-modules/lib/forge-std/.gitattributes new file mode 100644 index 0000000..27042d4 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/.gitattributes @@ -0,0 +1 @@ +src/Vm.sol linguist-generated diff --git a/typescript/packages/account-modules/lib/forge-std/.github/CODEOWNERS b/typescript/packages/account-modules/lib/forge-std/.github/CODEOWNERS new file mode 100644 index 0000000..63b25bb --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/.github/CODEOWNERS @@ -0,0 +1 @@ +* @danipopes @klkvr @mattsse @grandizzy @yash-atreya @zerosnacks diff --git a/typescript/packages/account-modules/lib/forge-std/.github/workflows/ci.yml b/typescript/packages/account-modules/lib/forge-std/.github/workflows/ci.yml new file mode 100644 index 0000000..c7a547c --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/.github/workflows/ci.yml @@ -0,0 +1,82 @@ +name: CI + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + +jobs: + build: + name: build +${{ matrix.toolchain }} ${{ matrix.flags }} + runs-on: ubuntu-latest + timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + toolchain: [stable, nightly] + flags: + - "" + - --via-ir + - --use solc:0.8.17 --via-ir + - --use solc:0.8.17 + - --use solc:0.8.0 + - --use solc:0.7.6 + - --use solc:0.7.0 + - --use solc:0.6.2 + - --use solc:0.6.12 + steps: + - uses: actions/checkout@v4 + - uses: foundry-rs/foundry-toolchain@v1 + - run: forge --version + - run: forge build --skip test --deny-warnings ${{ matrix.flags }} + # via-ir compilation time checks. + - if: contains(matrix.flags, '--via-ir') + run: forge build --skip test --deny-warnings ${{ matrix.flags }} --contracts 'test/compilation/*' + + test: + runs-on: ubuntu-latest + timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + toolchain: [stable, nightly] + steps: + - uses: actions/checkout@v4 + - uses: foundry-rs/foundry-toolchain@v1 + with: + version: ${{ matrix.toolchain }} + - run: forge --version + - run: forge test -vvv + + fmt: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + - uses: foundry-rs/foundry-toolchain@v1 + - run: forge --version + - run: forge fmt --check + + typos: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + - uses: crate-ci/typos@v1 + + ci-success: + runs-on: ubuntu-latest + if: always() + needs: + - build + - test + - fmt + - typos + timeout-minutes: 10 + steps: + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 + with: + jobs: ${{ toJSON(needs) }} diff --git a/typescript/packages/account-modules/lib/forge-std/.github/workflows/sync.yml b/typescript/packages/account-modules/lib/forge-std/.github/workflows/sync.yml new file mode 100644 index 0000000..9b170f0 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/.github/workflows/sync.yml @@ -0,0 +1,31 @@ +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@v4 + with: + fetch-depth: 0 + ref: v1 + + # The email is derived from the bots user id, + # found here: https://api.github.com/users/github-actions%5Bbot%5D + - 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/typescript/packages/account-modules/lib/forge-std/.gitignore b/typescript/packages/account-modules/lib/forge-std/.gitignore new file mode 100644 index 0000000..756106d --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/.gitignore @@ -0,0 +1,4 @@ +cache/ +out/ +.vscode +.idea diff --git a/typescript/packages/account-modules/lib/forge-std/CONTRIBUTING.md b/typescript/packages/account-modules/lib/forge-std/CONTRIBUTING.md new file mode 100644 index 0000000..89b75f3 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/CONTRIBUTING.md @@ -0,0 +1,193 @@ +## Contributing to Foundry + +Thanks for your interest in improving Foundry! + +There are multiple opportunities to contribute at any level. It doesn't matter if you are just getting started with Rust or are the most weathered expert, we can use your help. + +This document will help you get started. **Do not let the document intimidate you**. +It should be considered as a guide to help you navigate the process. + +The [dev Telegram][dev-tg] is available for any concerns you may have that are not covered in this guide. + +### Code of Conduct + +The Foundry project adheres to the [Rust Code of Conduct][rust-coc]. This code of conduct describes the _minimum_ behavior expected from all contributors. + +Instances of violations of the Code of Conduct can be reported by contacting the team at [me@gakonst.com](mailto:me@gakonst.com). + +### Ways to contribute + +There are fundamentally four ways an individual can contribute: + +1. **By opening an issue:** For example, if you believe that you have uncovered a bug + in Foundry, creating a new issue in the issue tracker is the way to report it. +2. **By adding context:** Providing additional context to existing issues, + such as screenshots and code snippets, which help resolve issues. +3. **By resolving issues:** Typically this is done in the form of either + demonstrating that the issue reported is not a problem after all, or more often, + by opening a pull request that fixes the underlying problem, in a concrete and + reviewable manner. + +**Anybody can participate in any stage of contribution**. We urge you to participate in the discussion +around bugs and participate in reviewing PRs. + +### Contributions Related to Spelling and Grammar + +At this time, we will not be accepting contributions that only fix spelling or grammatical errors in documentation, code or +elsewhere. + +### Asking for help + +If you have reviewed existing documentation and still have questions, or you are having problems, you can get help in the following ways: + +- **Asking in the support Telegram:** The [Foundry Support Telegram][support-tg] is a fast and easy way to ask questions. +- **Opening a discussion:** This repository comes with a discussions board where you can also ask for help. Click the "Discussions" tab at the top. + +As Foundry is still in heavy development, the documentation can be a bit scattered. +The [Foundry Book][foundry-book] is our current best-effort attempt at keeping up-to-date information. + +### Submitting a bug report + +When filing a new bug report in the issue tracker, you will be presented with a basic form to fill out. + +If you believe that you have uncovered a bug, please fill out the form to the best of your ability. Do not worry if you cannot answer every detail; just fill in what you can. Contributors will ask follow-up questions if something is unclear. + +The most important pieces of information we need in a bug report are: + +- The Foundry version you are on (and that it is up to date) +- The platform you are on (Windows, macOS, an M1 Mac or Linux) +- Code snippets if this is happening in relation to testing or building code +- Concrete steps to reproduce the bug + +In order to rule out the possibility of the bug being in your project, the code snippets should be as minimal +as possible. It is better if you can reproduce the bug with a small snippet as opposed to an entire project! + +See [this guide][mcve] on how to create a minimal, complete, and verifiable example. + +### Submitting a feature request + +When adding a feature request in the issue tracker, you will be presented with a basic form to fill out. + +Please include as detailed of an explanation as possible of the feature you would like, adding additional context if necessary. + +If you have examples of other tools that have the feature you are requesting, please include them as well. + +### Resolving an issue + +Pull requests are the way concrete changes are made to the code, documentation, and dependencies of Foundry. + +Even minor pull requests, such as those fixing wording, are greatly appreciated. Before making a large change, it is usually +a good idea to first open an issue describing the change to solicit feedback and guidance. This will increase +the likelihood of the PR getting merged. + +Please make sure that the following commands pass if you have changed the code: + +```sh +forge fmt --check +forge test -vvv +``` + +To make sure your changes are compatible with all compiler version targets, run the following commands: + +```sh +forge build --skip test --use solc:0.6.2 +forge build --skip test --use solc:0.6.12 +forge build --skip test --use solc:0.7.0 +forge build --skip test --use solc:0.7.6 +forge build --skip test --use solc:0.8.0 +``` + +The CI will also ensure that the code is formatted correctly and that the tests are passing across all compiler version targets. + +#### Adding cheatcodes + +Please follow the guide outlined in the [cheatcodes](https://github.com/foundry-rs/foundry/blob/master/docs/dev/cheatcodes.md#adding-a-new-cheatcode) documentation of Foundry. + +When making modifications to the native cheatcodes or adding new ones, please make sure to run [`./scripts/vm.py`](./scripts/vm.py) to update the cheatcodes in the [`src/Vm.sol`](./src/Vm.sol) file. + +By default the script will automatically generate the cheatcodes from the [`cheatcodes.json`](https://raw.githubusercontent.com/foundry-rs/foundry/master/crates/cheatcodes/assets/cheatcodes.json) file but alternatively you can provide a path to a JSON file containing the Vm interface, as generated by Foundry, with the `--from` flag. + +```sh +./scripts/vm.py --from path/to/cheatcodes.json +``` + +It is possible that the resulting [`src/Vm.sol`](./src/Vm.sol) file will have some changes that are not directly related to your changes, this is not a problem. + +#### Commits + +It is a recommended best practice to keep your changes as logically grouped as possible within individual commits. There is no limit to the number of commits any single pull request may have, and many contributors find it easier to review changes that are split across multiple commits. + +That said, if you have a number of commits that are "checkpoints" and don't represent a single logical change, please squash those together. + +#### Opening the pull request + +From within GitHub, opening a new pull request will present you with a template that should be filled out. Please try your best at filling out the details, but feel free to skip parts if you're not sure what to put. + +#### Discuss and update + +You will probably get feedback or requests for changes to your pull request. +This is a big part of the submission process, so don't be discouraged! Some contributors may sign off on the pull request right away, others may have more detailed comments or feedback. +This is a necessary part of the process in order to evaluate whether the changes are correct and necessary. + +**Any community member can review a PR, so you might get conflicting feedback**. +Keep an eye out for comments from code owners to provide guidance on conflicting feedback. + +#### Reviewing pull requests + +**Any Foundry community member is welcome to review any pull request**. + +All contributors who choose to review and provide feedback on pull requests have a responsibility to both the project and individual making the contribution. Reviews and feedback must be helpful, insightful, and geared towards improving the contribution as opposed to simply blocking it. If there are reasons why you feel the PR should not be merged, explain what those are. Do not expect to be able to block a PR from advancing simply because you say "no" without giving an explanation. Be open to having your mind changed. Be open to working _with_ the contributor to make the pull request better. + +Reviews that are dismissive or disrespectful of the contributor or any other reviewers are strictly counter to the Code of Conduct. + +When reviewing a pull request, the primary goals are for the codebase to improve and for the person submitting the request to succeed. **Even if a pull request is not merged, the submitter should come away from the experience feeling like their effort was not unappreciated**. Every PR from a new contributor is an opportunity to grow the community. + +##### Review a bit at a time + +Do not overwhelm new contributors. + +It is tempting to micro-optimize and make everything about relative performance, perfect grammar, or exact style matches. Do not succumb to that temptation.. + +Focus first on the most significant aspects of the change: + +1. Does this change make sense for Foundry? +2. Does this change make Foundry better, even if only incrementally? +3. Are there clear bugs or larger scale issues that need attending? +4. Are the commit messages readable and correct? If it contains a breaking change, is it clear enough? + +Note that only **incremental** improvement is needed to land a PR. This means that the PR does not need to be perfect, only better than the status quo. Follow-up PRs may be opened to continue iterating. + +When changes are necessary, _request_ them, do not _demand_ them, and **do not assume that the submitter already knows how to add a test or run a benchmark**. + +Specific performance optimization techniques, coding styles and conventions change over time. The first impression you give to a new contributor never does. + +Nits (requests for small changes that are not essential) are fine, but try to avoid stalling the pull request. Most nits can typically be fixed by the Foundry maintainers merging the pull request, but they can also be an opportunity for the contributor to learn a bit more about the project. + +It is always good to clearly indicate nits when you comment, e.g.: `Nit: change foo() to bar(). But this is not blocking`. + +If your comments were addressed but were not folded after new commits, or if they proved to be mistaken, please, [hide them][hiding-a-comment] with the appropriate reason to keep the conversation flow concise and relevant. + +##### Be aware of the person behind the code + +Be aware that _how_ you communicate requests and reviews in your feedback can have a significant impact on the success of the pull request. Yes, we may merge a particular change that makes Foundry better, but the individual might just not want to have anything to do with Foundry ever again. The goal is not just having good code. + +##### Abandoned or stale pull requests + +If a pull request appears to be abandoned or stalled, it is polite to first check with the contributor to see if they intend to continue the work before checking if they would mind if you took it over (especially if it just has nits left). When doing so, it is courteous to give the original contributor credit for the work they started, either by preserving their name and e-mail address in the commit log, or by using the `Author: ` or `Co-authored-by: ` metadata tag in the commits. + +_Adapted from the [ethers-rs contributing guide](https://github.com/gakonst/ethers-rs/blob/master/CONTRIBUTING.md)_. + +### Releasing + +Releases are automatically done by the release workflow when a tag is pushed, however, these steps still need to be taken: + +1. Ensure that the versions in the relevant `Cargo.toml` files are up-to-date. +2. Update documentation links +3. Perform a final audit for breaking changes. + +[rust-coc]: https://github.com/rust-lang/rust/blob/master/CODE_OF_CONDUCT.md +[dev-tg]: https://t.me/foundry_rs +[foundry-book]: https://github.com/foundry-rs/foundry-book +[support-tg]: https://t.me/foundry_support +[mcve]: https://stackoverflow.com/help/mcve +[hiding-a-comment]: https://help.github.com/articles/managing-disruptive-comments/#hiding-a-comment \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/forge-std/LICENSE-APACHE b/typescript/packages/account-modules/lib/forge-std/LICENSE-APACHE new file mode 100644 index 0000000..cf01a49 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/forge-std/LICENSE-MIT b/typescript/packages/account-modules/lib/forge-std/LICENSE-MIT new file mode 100644 index 0000000..28f9830 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/forge-std/README.md b/typescript/packages/account-modules/lib/forge-std/README.md new file mode 100644 index 0000000..51673e5 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/README.md @@ -0,0 +1,266 @@ +# 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://getfoundry.sh/reference/forge-std/overview/).** + +## 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 built-in 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 { + 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 addresses 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 + +Contains various assertions. + +### `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); +``` + +## Contributing + +See our [contributing guidelines](./CONTRIBUTING.md). + +## Getting Help + +First, see if the answer to your question can be found in [book](https://book.getfoundry.sh). + +If the answer is not there: + +- Join the [support Telegram](https://t.me/foundry_support) to get help, or +- Open a [discussion](https://github.com/foundry-rs/foundry/discussions/new/choose) with your question, or +- Open an issue with [the bug](https://github.com/foundry-rs/foundry/issues/new/choose) + +If you want to contribute, or follow along with contributor discussion, you can use our [main telegram](https://t.me/foundry_rs) to chat with us about the development of Foundry! + +## License + +Forge Standard Library is offered under either [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE) license. diff --git a/typescript/packages/account-modules/lib/forge-std/foundry.toml b/typescript/packages/account-modules/lib/forge-std/foundry.toml new file mode 100644 index 0000000..62ca21a --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/foundry.toml @@ -0,0 +1,23 @@ +[profile.default] +fs_permissions = [{ access = "read-write", path = "./"}] +optimizer = true +optimizer_runs = 200 + +[rpc_endpoints] +# The RPC URLs are modified versions of the default for testing initialization. +mainnet = "https://eth.merkle.io" # Different API key. +optimism_sepolia = "https://sepolia.optimism.io/" # Adds a trailing slash. +arbitrum_one_sepolia = "https://sepolia-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/typescript/packages/account-modules/lib/forge-std/package.json b/typescript/packages/account-modules/lib/forge-std/package.json new file mode 100644 index 0000000..74e5e66 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/package.json @@ -0,0 +1,16 @@ +{ + "name": "forge-std", + "version": "1.10.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/typescript/packages/account-modules/lib/forge-std/scripts/vm.py b/typescript/packages/account-modules/lib/forge-std/scripts/vm.py new file mode 100755 index 0000000..3cd047d --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/scripts/vm.py @@ -0,0 +1,646 @@ +#!/usr/bin/env python3 + +import argparse +import copy +import json +import re +import subprocess +from enum import Enum as PyEnum +from pathlib import Path +from typing import Callable +from urllib import request + +VoidFn = Callable[[], None] + +CHEATCODES_JSON_URL = "https://raw.githubusercontent.com/foundry-rs/foundry/master/crates/cheatcodes/assets/cheatcodes.json" +OUT_PATH = "src/Vm.sol" + +VM_SAFE_DOC = """\ +/// 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. +""" + +VM_DOC = """\ +/// 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. +""" + + +def main(): + parser = argparse.ArgumentParser( + description="Generate Vm.sol based on the cheatcodes json created by Foundry") + parser.add_argument( + "--from", + metavar="PATH", + dest="path", + required=False, + help="path to a json file containing the Vm interface, as generated by Foundry") + args = parser.parse_args() + json_str = request.urlopen(CHEATCODES_JSON_URL).read().decode("utf-8") if args.path is None else Path(args.path).read_text() + contract = Cheatcodes.from_json(json_str) + + ccs = contract.cheatcodes + ccs = list(filter(lambda cc: cc.status not in ["experimental", "internal"], ccs)) + ccs.sort(key=lambda cc: cc.func.id) + + safe = list(filter(lambda cc: cc.safety == "safe", ccs)) + safe.sort(key=CmpCheatcode) + unsafe = list(filter(lambda cc: cc.safety == "unsafe", ccs)) + unsafe.sort(key=CmpCheatcode) + assert len(safe) + len(unsafe) == len(ccs) + + prefix_with_group_headers(safe) + prefix_with_group_headers(unsafe) + + out = "" + + out += "// Automatically @generated by scripts/vm.py. Do not modify manually.\n\n" + + pp = CheatcodesPrinter( + spdx_identifier="MIT OR Apache-2.0", + solidity_requirement=">=0.6.2 <0.9.0", + abicoder_pragma=True, + ) + pp.p_prelude() + pp.prelude = False + out += pp.finish() + + out += "\n\n" + out += VM_SAFE_DOC + vm_safe = Cheatcodes( + # TODO: Custom errors were introduced in 0.8.4 + errors=[], # contract.errors + events=contract.events, + enums=contract.enums, + structs=contract.structs, + cheatcodes=safe, + ) + pp.p_contract(vm_safe, "VmSafe") + out += pp.finish() + + out += "\n\n" + out += VM_DOC + vm_unsafe = Cheatcodes( + errors=[], + events=[], + enums=[], + structs=[], + cheatcodes=unsafe, + ) + pp.p_contract(vm_unsafe, "Vm", "VmSafe") + out += pp.finish() + + # Compatibility with <0.8.0 + def memory_to_calldata(m: re.Match) -> str: + return " calldata " + m.group(1) + + out = re.sub(r" memory (.*returns)", memory_to_calldata, out) + + with open(OUT_PATH, "w") as f: + f.write(out) + + forge_fmt = ["forge", "fmt", OUT_PATH] + res = subprocess.run(forge_fmt) + assert res.returncode == 0, f"command failed: {forge_fmt}" + + print(f"Wrote to {OUT_PATH}") + + +class CmpCheatcode: + cheatcode: "Cheatcode" + + def __init__(self, cheatcode: "Cheatcode"): + self.cheatcode = cheatcode + + def __lt__(self, other: "CmpCheatcode") -> bool: + return cmp_cheatcode(self.cheatcode, other.cheatcode) < 0 + + def __eq__(self, other: "CmpCheatcode") -> bool: + return cmp_cheatcode(self.cheatcode, other.cheatcode) == 0 + + def __gt__(self, other: "CmpCheatcode") -> bool: + return cmp_cheatcode(self.cheatcode, other.cheatcode) > 0 + + +def cmp_cheatcode(a: "Cheatcode", b: "Cheatcode") -> int: + if a.group != b.group: + return -1 if a.group < b.group else 1 + if a.status != b.status: + return -1 if a.status < b.status else 1 + if a.safety != b.safety: + return -1 if a.safety < b.safety else 1 + if a.func.id != b.func.id: + return -1 if a.func.id < b.func.id else 1 + return 0 + + +# HACK: A way to add group header comments without having to modify printer code +def prefix_with_group_headers(cheats: list["Cheatcode"]): + s = set() + for i, cheat in enumerate(cheats): + if cheat.group in s: + continue + + s.add(cheat.group) + + c = copy.deepcopy(cheat) + c.func.description = "" + c.func.declaration = f"// ======== {group(c.group)} ========" + cheats.insert(i, c) + return cheats + + +def group(s: str) -> str: + if s == "evm": + return "EVM" + if s == "json": + return "JSON" + return s[0].upper() + s[1:] + + +class Visibility(PyEnum): + EXTERNAL: str = "external" + PUBLIC: str = "public" + INTERNAL: str = "internal" + PRIVATE: str = "private" + + def __str__(self): + return self.value + + +class Mutability(PyEnum): + PURE: str = "pure" + VIEW: str = "view" + NONE: str = "" + + def __str__(self): + return self.value + + +class Function: + id: str + description: str + declaration: str + visibility: Visibility + mutability: Mutability + signature: str + selector: str + selector_bytes: bytes + + def __init__( + self, + id: str, + description: str, + declaration: str, + visibility: Visibility, + mutability: Mutability, + signature: str, + selector: str, + selector_bytes: bytes, + ): + self.id = id + self.description = description + self.declaration = declaration + self.visibility = visibility + self.mutability = mutability + self.signature = signature + self.selector = selector + self.selector_bytes = selector_bytes + + @staticmethod + def from_dict(d: dict) -> "Function": + return Function( + d["id"], + d["description"], + d["declaration"], + Visibility(d["visibility"]), + Mutability(d["mutability"]), + d["signature"], + d["selector"], + bytes(d["selectorBytes"]), + ) + + +class Cheatcode: + func: Function + group: str + status: str + safety: str + + def __init__(self, func: Function, group: str, status: str, safety: str): + self.func = func + self.group = group + self.status = status + self.safety = safety + + @staticmethod + def from_dict(d: dict) -> "Cheatcode": + return Cheatcode( + Function.from_dict(d["func"]), + str(d["group"]), + str(d["status"]), + str(d["safety"]), + ) + + +class Error: + name: str + description: str + declaration: str + + def __init__(self, name: str, description: str, declaration: str): + self.name = name + self.description = description + self.declaration = declaration + + @staticmethod + def from_dict(d: dict) -> "Error": + return Error(**d) + + +class Event: + name: str + description: str + declaration: str + + def __init__(self, name: str, description: str, declaration: str): + self.name = name + self.description = description + self.declaration = declaration + + @staticmethod + def from_dict(d: dict) -> "Event": + return Event(**d) + + +class EnumVariant: + name: str + description: str + + def __init__(self, name: str, description: str): + self.name = name + self.description = description + + +class Enum: + name: str + description: str + variants: list[EnumVariant] + + def __init__(self, name: str, description: str, variants: list[EnumVariant]): + self.name = name + self.description = description + self.variants = variants + + @staticmethod + def from_dict(d: dict) -> "Enum": + return Enum( + d["name"], + d["description"], + list(map(lambda v: EnumVariant(**v), d["variants"])), + ) + + +class StructField: + name: str + ty: str + description: str + + def __init__(self, name: str, ty: str, description: str): + self.name = name + self.ty = ty + self.description = description + + +class Struct: + name: str + description: str + fields: list[StructField] + + def __init__(self, name: str, description: str, fields: list[StructField]): + self.name = name + self.description = description + self.fields = fields + + @staticmethod + def from_dict(d: dict) -> "Struct": + return Struct( + d["name"], + d["description"], + list(map(lambda f: StructField(**f), d["fields"])), + ) + + +class Cheatcodes: + errors: list[Error] + events: list[Event] + enums: list[Enum] + structs: list[Struct] + cheatcodes: list[Cheatcode] + + def __init__( + self, + errors: list[Error], + events: list[Event], + enums: list[Enum], + structs: list[Struct], + cheatcodes: list[Cheatcode], + ): + self.errors = errors + self.events = events + self.enums = enums + self.structs = structs + self.cheatcodes = cheatcodes + + @staticmethod + def from_dict(d: dict) -> "Cheatcodes": + return Cheatcodes( + errors=[Error.from_dict(e) for e in d["errors"]], + events=[Event.from_dict(e) for e in d["events"]], + enums=[Enum.from_dict(e) for e in d["enums"]], + structs=[Struct.from_dict(e) for e in d["structs"]], + cheatcodes=[Cheatcode.from_dict(e) for e in d["cheatcodes"]], + ) + + @staticmethod + def from_json(s) -> "Cheatcodes": + return Cheatcodes.from_dict(json.loads(s)) + + @staticmethod + def from_json_file(file_path: str) -> "Cheatcodes": + with open(file_path, "r") as f: + return Cheatcodes.from_dict(json.load(f)) + + +class Item(PyEnum): + ERROR: str = "error" + EVENT: str = "event" + ENUM: str = "enum" + STRUCT: str = "struct" + FUNCTION: str = "function" + + +class ItemOrder: + _list: list[Item] + + def __init__(self, list: list[Item]) -> None: + assert len(list) <= len(Item), "list must not contain more items than Item" + assert len(list) == len(set(list)), "list must not contain duplicates" + self._list = list + pass + + def get_list(self) -> list[Item]: + return self._list + + @staticmethod + def default() -> "ItemOrder": + return ItemOrder( + [ + Item.ERROR, + Item.EVENT, + Item.ENUM, + Item.STRUCT, + Item.FUNCTION, + ] + ) + + +class CheatcodesPrinter: + buffer: str + + prelude: bool + spdx_identifier: str + solidity_requirement: str + abicoder_v2: bool + + block_doc_style: bool + + indent_level: int + _indent_str: str + + nl_str: str + + items_order: ItemOrder + + def __init__( + self, + buffer: str = "", + prelude: bool = True, + spdx_identifier: str = "UNLICENSED", + solidity_requirement: str = "", + abicoder_pragma: bool = False, + block_doc_style: bool = False, + indent_level: int = 0, + indent_with: int | str = 4, + nl_str: str = "\n", + items_order: ItemOrder = ItemOrder.default(), + ): + self.prelude = prelude + self.spdx_identifier = spdx_identifier + self.solidity_requirement = solidity_requirement + self.abicoder_v2 = abicoder_pragma + self.block_doc_style = block_doc_style + self.buffer = buffer + self.indent_level = indent_level + self.nl_str = nl_str + + if isinstance(indent_with, int): + assert indent_with >= 0 + self._indent_str = " " * indent_with + elif isinstance(indent_with, str): + self._indent_str = indent_with + else: + assert False, "indent_with must be int or str" + + self.items_order = items_order + + def finish(self) -> str: + ret = self.buffer.rstrip() + self.buffer = "" + return ret + + def p_contract(self, contract: Cheatcodes, name: str, inherits: str = ""): + if self.prelude: + self.p_prelude(contract) + + self._p_str("interface ") + name = name.strip() + if name != "": + self._p_str(name) + self._p_str(" ") + if inherits != "": + self._p_str("is ") + self._p_str(inherits) + self._p_str(" ") + self._p_str("{") + self._p_nl() + self._with_indent(lambda: self._p_items(contract)) + self._p_str("}") + self._p_nl() + + def _p_items(self, contract: Cheatcodes): + for item in self.items_order.get_list(): + if item == Item.ERROR: + self.p_errors(contract.errors) + elif item == Item.EVENT: + self.p_events(contract.events) + elif item == Item.ENUM: + self.p_enums(contract.enums) + elif item == Item.STRUCT: + self.p_structs(contract.structs) + elif item == Item.FUNCTION: + self.p_functions(contract.cheatcodes) + else: + assert False, f"unknown item {item}" + + def p_prelude(self, contract: Cheatcodes | None = None): + self._p_str(f"// SPDX-License-Identifier: {self.spdx_identifier}") + self._p_nl() + + if self.solidity_requirement != "": + req = self.solidity_requirement + elif contract and len(contract.errors) > 0: + req = ">=0.8.4 <0.9.0" + else: + req = ">=0.6.0 <0.9.0" + self._p_str(f"pragma solidity {req};") + self._p_nl() + + if self.abicoder_v2: + self._p_str("pragma experimental ABIEncoderV2;") + self._p_nl() + + self._p_nl() + + def p_errors(self, errors: list[Error]): + for error in errors: + self._p_line(lambda: self.p_error(error)) + + def p_error(self, error: Error): + self._p_comment(error.description, doc=True) + self._p_line(lambda: self._p_str(error.declaration)) + + def p_events(self, events: list[Event]): + for event in events: + self._p_line(lambda: self.p_event(event)) + + def p_event(self, event: Event): + self._p_comment(event.description, doc=True) + self._p_line(lambda: self._p_str(event.declaration)) + + def p_enums(self, enums: list[Enum]): + for enum in enums: + self._p_line(lambda: self.p_enum(enum)) + + def p_enum(self, enum: Enum): + self._p_comment(enum.description, doc=True) + self._p_line(lambda: self._p_str(f"enum {enum.name} {{")) + self._with_indent(lambda: self.p_enum_variants(enum.variants)) + self._p_line(lambda: self._p_str("}")) + + def p_enum_variants(self, variants: list[EnumVariant]): + for i, variant in enumerate(variants): + self._p_indent() + self._p_comment(variant.description) + + self._p_indent() + self._p_str(variant.name) + if i < len(variants) - 1: + self._p_str(",") + self._p_nl() + + def p_structs(self, structs: list[Struct]): + for struct in structs: + self._p_line(lambda: self.p_struct(struct)) + + def p_struct(self, struct: Struct): + self._p_comment(struct.description, doc=True) + self._p_line(lambda: self._p_str(f"struct {struct.name} {{")) + self._with_indent(lambda: self.p_struct_fields(struct.fields)) + self._p_line(lambda: self._p_str("}")) + + def p_struct_fields(self, fields: list[StructField]): + for field in fields: + self._p_line(lambda: self.p_struct_field(field)) + + def p_struct_field(self, field: StructField): + self._p_comment(field.description) + self._p_indented(lambda: self._p_str(f"{field.ty} {field.name};")) + + def p_functions(self, cheatcodes: list[Cheatcode]): + for cheatcode in cheatcodes: + self._p_line(lambda: self.p_function(cheatcode.func)) + + def p_function(self, func: Function): + self._p_comment(func.description, doc=True) + self._p_line(lambda: self._p_str(func.declaration)) + + def _p_comment(self, s: str, doc: bool = False): + s = s.strip() + if s == "": + return + + s = map(lambda line: line.lstrip(), s.split("\n")) + if self.block_doc_style: + self._p_str("/*") + if doc: + self._p_str("*") + self._p_nl() + for line in s: + self._p_indent() + self._p_str(" ") + if doc: + self._p_str("* ") + self._p_str(line) + self._p_nl() + self._p_indent() + self._p_str(" */") + self._p_nl() + else: + first_line = True + for line in s: + if not first_line: + self._p_indent() + first_line = False + + if doc: + self._p_str("/// ") + else: + self._p_str("// ") + self._p_str(line) + self._p_nl() + + def _with_indent(self, f: VoidFn): + self._inc_indent() + f() + self._dec_indent() + + def _p_line(self, f: VoidFn): + self._p_indent() + f() + self._p_nl() + + def _p_indented(self, f: VoidFn): + self._p_indent() + f() + + def _p_indent(self): + for _ in range(self.indent_level): + self._p_str(self._indent_str) + + def _p_nl(self): + self._p_str(self.nl_str) + + def _p_str(self, txt: str): + self.buffer += txt + + def _inc_indent(self): + self.indent_level += 1 + + def _dec_indent(self): + self.indent_level -= 1 + + +if __name__ == "__main__": + main() diff --git a/typescript/packages/account-modules/lib/forge-std/src/Base.sol b/typescript/packages/account-modules/lib/forge-std/src/Base.sol new file mode 100644 index 0000000..5b618c6 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/Base.sol @@ -0,0 +1,42 @@ +// 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 { + /// @dev Cheat code address. + /// Calculated as `address(uint160(uint256(keccak256("hevm cheat code"))))`. + address internal constant VM_ADDRESS = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D; + /// @dev console.sol and console2.sol work by executing a staticcall to this address. + /// Calculated as `address(uint160(uint88(bytes11("console.log"))))`. + address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67; + /// @dev Used when deploying with create2. + /// Taken from https://github.com/Arachnid/deterministic-deployment-proxy. + address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + /// @dev The default address for tx.origin and msg.sender. + /// Calculated as `address(uint160(uint256(keccak256("foundry default caller"))))`. + address internal constant DEFAULT_SENDER = 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38; + /// @dev The address of the first contract `CREATE`d by a running test contract. + /// When running tests, each test contract is `CREATE`d by `DEFAULT_SENDER` with nonce 1. + /// Calculated as `VM.computeCreateAddress(VM.computeCreateAddress(DEFAULT_SENDER, 1), 1)`. + address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; + /// @dev Deterministic deployment address of the Multicall3 contract. + /// Taken from https://www.multicall3.com. + address internal constant MULTICALL3_ADDRESS = 0xcA11bde05977b3631167028862bE2a173976CA11; + /// @dev 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/typescript/packages/account-modules/lib/forge-std/src/Script.sol b/typescript/packages/account-modules/lib/forge-std/src/Script.sol new file mode 100644 index 0000000..a2e2aa1 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/Script.sol @@ -0,0 +1,28 @@ +// 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 {StdConstants} from "./StdConstants.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/typescript/packages/account-modules/lib/forge-std/src/StdAssertions.sol b/typescript/packages/account-modules/lib/forge-std/src/StdAssertions.sol new file mode 100644 index 0000000..4248170 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/StdAssertions.sol @@ -0,0 +1,764 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; +pragma experimental ABIEncoderV2; + +import {Vm} from "./Vm.sol"; + +abstract contract StdAssertions { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + event log(string); + event logs(bytes); + + event log_address(address); + event log_bytes32(bytes32); + event log_int(int256); + event log_uint(uint256); + 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, int256 val, uint256 decimals); + event log_named_decimal_uint(string key, uint256 val, uint256 decimals); + event log_named_int(string key, int256 val); + event log_named_uint(string key, uint256 val); + event log_named_bytes(string key, bytes val); + event log_named_string(string key, string val); + + 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); + + bytes32 private constant FAILED_SLOT = bytes32("failed"); + + bool private _failed; + + function failed() public view returns (bool) { + if (_failed) { + return true; + } else { + return vm.load(address(vm), FAILED_SLOT) != bytes32(0); + } + } + + function fail() internal virtual { + vm.store(address(vm), FAILED_SLOT, bytes32(uint256(1))); + _failed = true; + } + + function fail(string memory message) internal virtual { + fail(); + vm.assertTrue(false, message); + } + + function assertTrue(bool data) internal pure virtual { + if (!data) { + vm.assertTrue(data); + } + } + + function assertTrue(bool data, string memory err) internal pure virtual { + if (!data) { + vm.assertTrue(data, err); + } + } + + function assertFalse(bool data) internal pure virtual { + if (data) { + vm.assertFalse(data); + } + } + + function assertFalse(bool data, string memory err) internal pure virtual { + if (data) { + vm.assertFalse(data, err); + } + } + + function assertEq(bool left, bool right) internal pure virtual { + if (left != right) { + vm.assertEq(left, right); + } + } + + function assertEq(bool left, bool right, string memory err) internal pure virtual { + if (left != right) { + vm.assertEq(left, right, err); + } + } + + function assertEq(uint256 left, uint256 right) internal pure virtual { + if (left != right) { + vm.assertEq(left, right); + } + } + + function assertEq(uint256 left, uint256 right, string memory err) internal pure virtual { + if (left != right) { + vm.assertEq(left, right, err); + } + } + + function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertEqDecimal(left, right, decimals); + } + + function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertEqDecimal(left, right, decimals, err); + } + + function assertEq(int256 left, int256 right) internal pure virtual { + if (left != right) { + vm.assertEq(left, right); + } + } + + function assertEq(int256 left, int256 right, string memory err) internal pure virtual { + if (left != right) { + vm.assertEq(left, right, err); + } + } + + function assertEqDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertEqDecimal(left, right, decimals); + } + + function assertEqDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertEqDecimal(left, right, decimals, err); + } + + function assertEq(address left, address right) internal pure virtual { + if (left != right) { + vm.assertEq(left, right); + } + } + + function assertEq(address left, address right, string memory err) internal pure virtual { + if (left != right) { + vm.assertEq(left, right, err); + } + } + + function assertEq(bytes32 left, bytes32 right) internal pure virtual { + if (left != right) { + vm.assertEq(left, right); + } + } + + function assertEq(bytes32 left, bytes32 right, string memory err) internal pure virtual { + if (left != right) { + vm.assertEq(left, right, err); + } + } + + function assertEq32(bytes32 left, bytes32 right) internal pure virtual { + if (left != right) { + vm.assertEq(left, right); + } + } + + function assertEq32(bytes32 left, bytes32 right, string memory err) internal pure virtual { + if (left != right) { + vm.assertEq(left, right, err); + } + } + + function assertEq(string memory left, string memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(string memory left, string memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(bytes memory left, bytes memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bytes memory left, bytes memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(bool[] memory left, bool[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bool[] memory left, bool[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(uint256[] memory left, uint256[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(uint256[] memory left, uint256[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(int256[] memory left, int256[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(int256[] memory left, int256[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(address[] memory left, address[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(address[] memory left, address[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(bytes32[] memory left, bytes32[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bytes32[] memory left, bytes32[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(string[] memory left, string[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(string[] memory left, string[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(bytes[] memory left, bytes[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bytes[] memory left, bytes[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + // Legacy helper + function assertEqUint(uint256 left, uint256 right) internal pure virtual { + assertEq(left, right); + } + + function assertNotEq(bool left, bool right) internal pure virtual { + if (left == right) { + vm.assertNotEq(left, right); + } + } + + function assertNotEq(bool left, bool right, string memory err) internal pure virtual { + if (left == right) { + vm.assertNotEq(left, right, err); + } + } + + function assertNotEq(uint256 left, uint256 right) internal pure virtual { + if (left == right) { + vm.assertNotEq(left, right); + } + } + + function assertNotEq(uint256 left, uint256 right, string memory err) internal pure virtual { + if (left == right) { + vm.assertNotEq(left, right, err); + } + } + + function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertNotEqDecimal(left, right, decimals); + } + + function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) + internal + pure + virtual + { + vm.assertNotEqDecimal(left, right, decimals, err); + } + + function assertNotEq(int256 left, int256 right) internal pure virtual { + if (left == right) { + vm.assertNotEq(left, right); + } + } + + function assertNotEq(int256 left, int256 right, string memory err) internal pure virtual { + if (left == right) { + vm.assertNotEq(left, right, err); + } + } + + function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertNotEqDecimal(left, right, decimals); + } + + function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertNotEqDecimal(left, right, decimals, err); + } + + function assertNotEq(address left, address right) internal pure virtual { + if (left == right) { + vm.assertNotEq(left, right); + } + } + + function assertNotEq(address left, address right, string memory err) internal pure virtual { + if (left == right) { + vm.assertNotEq(left, right, err); + } + } + + function assertNotEq(bytes32 left, bytes32 right) internal pure virtual { + if (left == right) { + vm.assertNotEq(left, right); + } + } + + function assertNotEq(bytes32 left, bytes32 right, string memory err) internal pure virtual { + if (left == right) { + vm.assertNotEq(left, right, err); + } + } + + function assertNotEq32(bytes32 left, bytes32 right) internal pure virtual { + if (left == right) { + vm.assertNotEq(left, right); + } + } + + function assertNotEq32(bytes32 left, bytes32 right, string memory err) internal pure virtual { + if (left == right) { + vm.assertNotEq(left, right, err); + } + } + + function assertNotEq(string memory left, string memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(string memory left, string memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(bytes memory left, bytes memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bytes memory left, bytes memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(bool[] memory left, bool[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bool[] memory left, bool[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(uint256[] memory left, uint256[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(uint256[] memory left, uint256[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(int256[] memory left, int256[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(int256[] memory left, int256[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(address[] memory left, address[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(address[] memory left, address[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(bytes32[] memory left, bytes32[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bytes32[] memory left, bytes32[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(string[] memory left, string[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(string[] memory left, string[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(bytes[] memory left, bytes[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bytes[] memory left, bytes[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertLt(uint256 left, uint256 right) internal pure virtual { + if (left >= right) { + vm.assertLt(left, right); + } + } + + function assertLt(uint256 left, uint256 right, string memory err) internal pure virtual { + if (left >= right) { + vm.assertLt(left, right, err); + } + } + + function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertLtDecimal(left, right, decimals); + } + + function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertLtDecimal(left, right, decimals, err); + } + + function assertLt(int256 left, int256 right) internal pure virtual { + if (left >= right) { + vm.assertLt(left, right); + } + } + + function assertLt(int256 left, int256 right, string memory err) internal pure virtual { + if (left >= right) { + vm.assertLt(left, right, err); + } + } + + function assertLtDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertLtDecimal(left, right, decimals); + } + + function assertLtDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertLtDecimal(left, right, decimals, err); + } + + function assertGt(uint256 left, uint256 right) internal pure virtual { + if (left <= right) { + vm.assertGt(left, right); + } + } + + function assertGt(uint256 left, uint256 right, string memory err) internal pure virtual { + if (left <= right) { + vm.assertGt(left, right, err); + } + } + + function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertGtDecimal(left, right, decimals); + } + + function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertGtDecimal(left, right, decimals, err); + } + + function assertGt(int256 left, int256 right) internal pure virtual { + if (left <= right) { + vm.assertGt(left, right); + } + } + + function assertGt(int256 left, int256 right, string memory err) internal pure virtual { + if (left <= right) { + vm.assertGt(left, right, err); + } + } + + function assertGtDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertGtDecimal(left, right, decimals); + } + + function assertGtDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertGtDecimal(left, right, decimals, err); + } + + function assertLe(uint256 left, uint256 right) internal pure virtual { + if (left > right) { + vm.assertLe(left, right); + } + } + + function assertLe(uint256 left, uint256 right, string memory err) internal pure virtual { + if (left > right) { + vm.assertLe(left, right, err); + } + } + + function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertLeDecimal(left, right, decimals); + } + + function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertLeDecimal(left, right, decimals, err); + } + + function assertLe(int256 left, int256 right) internal pure virtual { + if (left > right) { + vm.assertLe(left, right); + } + } + + function assertLe(int256 left, int256 right, string memory err) internal pure virtual { + if (left > right) { + vm.assertLe(left, right, err); + } + } + + function assertLeDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertLeDecimal(left, right, decimals); + } + + function assertLeDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertLeDecimal(left, right, decimals, err); + } + + function assertGe(uint256 left, uint256 right) internal pure virtual { + if (left < right) { + vm.assertGe(left, right); + } + } + + function assertGe(uint256 left, uint256 right, string memory err) internal pure virtual { + if (left < right) { + vm.assertGe(left, right, err); + } + } + + function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertGeDecimal(left, right, decimals); + } + + function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertGeDecimal(left, right, decimals, err); + } + + function assertGe(int256 left, int256 right) internal pure virtual { + if (left < right) { + vm.assertGe(left, right); + } + } + + function assertGe(int256 left, int256 right, string memory err) internal pure virtual { + if (left < right) { + vm.assertGe(left, right, err); + } + } + + function assertGeDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertGeDecimal(left, right, decimals); + } + + function assertGeDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertGeDecimal(left, right, decimals, err); + } + + function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) internal pure virtual { + vm.assertApproxEqAbs(left, right, maxDelta); + } + + function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string memory err) + internal + pure + virtual + { + vm.assertApproxEqAbs(left, right, maxDelta, err); + } + + function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) + internal + pure + virtual + { + vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals); + } + + function assertApproxEqAbsDecimal( + uint256 left, + uint256 right, + uint256 maxDelta, + uint256 decimals, + string memory err + ) internal pure virtual { + vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals, err); + } + + function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) internal pure virtual { + vm.assertApproxEqAbs(left, right, maxDelta); + } + + function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string memory err) internal pure virtual { + vm.assertApproxEqAbs(left, right, maxDelta, err); + } + + function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) + internal + pure + virtual + { + vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals); + } + + function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals, string memory err) + internal + pure + virtual + { + vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals, err); + } + + function assertApproxEqRel( + uint256 left, + uint256 right, + uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% + ) internal pure virtual { + vm.assertApproxEqRel(left, right, maxPercentDelta); + } + + function assertApproxEqRel( + uint256 left, + uint256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + string memory err + ) internal pure virtual { + vm.assertApproxEqRel(left, right, maxPercentDelta, err); + } + + function assertApproxEqRelDecimal( + uint256 left, + uint256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals + ) internal pure virtual { + vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals); + } + + function assertApproxEqRelDecimal( + uint256 left, + uint256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals, + string memory err + ) internal pure virtual { + vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals, err); + } + + function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) internal pure virtual { + vm.assertApproxEqRel(left, right, maxPercentDelta); + } + + function assertApproxEqRel( + int256 left, + int256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + string memory err + ) internal pure virtual { + vm.assertApproxEqRel(left, right, maxPercentDelta, err); + } + + function assertApproxEqRelDecimal( + int256 left, + int256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals + ) internal pure virtual { + vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals); + } + + function assertApproxEqRelDecimal( + int256 left, + int256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals, + string memory err + ) internal pure virtual { + vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals, err); + } + + // Inherited from DSTest, not used but kept for backwards-compatibility + function checkEq0(bytes memory left, bytes memory right) internal pure returns (bool) { + return keccak256(left) == keccak256(right); + } + + function assertEq0(bytes memory left, bytes memory right) internal pure virtual { + assertEq(left, right); + } + + function assertEq0(bytes memory left, bytes memory right, string memory err) internal pure virtual { + assertEq(left, right, err); + } + + function assertNotEq0(bytes memory left, bytes memory right) internal pure virtual { + assertNotEq(left, right); + } + + function assertNotEq0(bytes memory left, bytes memory right, string memory err) internal pure virtual { + assertNotEq(left, right, err); + } + + 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); + revert("assertion failed"); + } + + 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); + revert("assertion failed"); + } + } +} diff --git a/typescript/packages/account-modules/lib/forge-std/src/StdChains.sol b/typescript/packages/account-modules/lib/forge-std/src/StdChains.sol new file mode 100644 index 0000000..0a872e7 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/StdChains.sol @@ -0,0 +1,286 @@ +// 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 + 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) { + 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' + // The upstream error thrown by forge for failing cheats changed so we check both the old and new versions + bytes memory oldNotFoundError = + abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias))); + bytes memory newNotFoundError = abi.encodeWithSignature( + "CheatcodeError(string)", string(abi.encodePacked("invalid rpc url: ", chainAlias)) + ); + bytes32 errHash = keccak256(err); + if ( + (errHash != keccak256(oldNotFoundError) && errHash != keccak256(newNotFoundError)) + || 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 `test_Rpcs` in `StdChains.t.sol` + setChainWithDefaultRpcUrl("anvil", ChainData("Anvil", 31337, "http://127.0.0.1:8545")); + setChainWithDefaultRpcUrl("mainnet", ChainData("Mainnet", 1, "https://eth.llamarpc.com")); + setChainWithDefaultRpcUrl( + "sepolia", ChainData("Sepolia", 11155111, "https://sepolia.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001") + ); + setChainWithDefaultRpcUrl("holesky", ChainData("Holesky", 17000, "https://rpc.holesky.ethpandaops.io")); + setChainWithDefaultRpcUrl("hoodi", ChainData("Hoodi", 560048, "https://rpc.hoodi.ethpandaops.io")); + setChainWithDefaultRpcUrl("optimism", ChainData("Optimism", 10, "https://mainnet.optimism.io")); + setChainWithDefaultRpcUrl( + "optimism_sepolia", ChainData("Optimism Sepolia", 11155420, "https://sepolia.optimism.io") + ); + setChainWithDefaultRpcUrl("arbitrum_one", ChainData("Arbitrum One", 42161, "https://arb1.arbitrum.io/rpc")); + setChainWithDefaultRpcUrl( + "arbitrum_one_sepolia", ChainData("Arbitrum One Sepolia", 421614, "https://sepolia-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_amoy", ChainData("Polygon Amoy", 80002, "https://rpc-amoy.polygon.technology") + ); + 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_sepolia", ChainData("Base Sepolia", 84532, "https://sepolia.base.org")); + setChainWithDefaultRpcUrl("base", ChainData("Base", 8453, "https://mainnet.base.org")); + setChainWithDefaultRpcUrl("blast_sepolia", ChainData("Blast Sepolia", 168587773, "https://sepolia.blast.io")); + setChainWithDefaultRpcUrl("blast", ChainData("Blast", 81457, "https://rpc.blast.io")); + setChainWithDefaultRpcUrl("fantom_opera", ChainData("Fantom Opera", 250, "https://rpc.ankr.com/fantom/")); + setChainWithDefaultRpcUrl( + "fantom_opera_testnet", ChainData("Fantom Opera Testnet", 4002, "https://rpc.ankr.com/fantom_testnet/") + ); + setChainWithDefaultRpcUrl("fraxtal", ChainData("Fraxtal", 252, "https://rpc.frax.com")); + setChainWithDefaultRpcUrl("fraxtal_testnet", ChainData("Fraxtal Testnet", 2522, "https://rpc.testnet.frax.com")); + setChainWithDefaultRpcUrl( + "berachain_bartio_testnet", ChainData("Berachain bArtio Testnet", 80084, "https://bartio.rpc.berachain.com") + ); + setChainWithDefaultRpcUrl("flare", ChainData("Flare", 14, "https://flare-api.flare.network/ext/C/rpc")); + setChainWithDefaultRpcUrl( + "flare_coston2", ChainData("Flare Coston2", 114, "https://coston2-api.flare.network/ext/C/rpc") + ); + + setChainWithDefaultRpcUrl("mode", ChainData("Mode", 34443, "https://mode.drpc.org")); + setChainWithDefaultRpcUrl("mode_sepolia", ChainData("Mode Sepolia", 919, "https://sepolia.mode.network")); + + setChainWithDefaultRpcUrl("zora", ChainData("Zora", 7777777, "https://zora.drpc.org")); + setChainWithDefaultRpcUrl( + "zora_sepolia", ChainData("Zora Sepolia", 999999999, "https://sepolia.rpc.zora.energy") + ); + + setChainWithDefaultRpcUrl("race", ChainData("Race", 6805, "https://racemainnet.io")); + setChainWithDefaultRpcUrl("race_sepolia", ChainData("Race Sepolia", 6806, "https://racemainnet.io")); + + setChainWithDefaultRpcUrl("metal", ChainData("Metal", 1750, "https://metall2.drpc.org")); + setChainWithDefaultRpcUrl("metal_sepolia", ChainData("Metal Sepolia", 1740, "https://testnet.rpc.metall2.com")); + + setChainWithDefaultRpcUrl("binary", ChainData("Binary", 624, "https://rpc.zero.thebinaryholdings.com")); + setChainWithDefaultRpcUrl( + "binary_sepolia", ChainData("Binary Sepolia", 625, "https://rpc.zero.thebinaryholdings.com") + ); + + setChainWithDefaultRpcUrl("orderly", ChainData("Orderly", 291, "https://rpc.orderly.network")); + setChainWithDefaultRpcUrl( + "orderly_sepolia", ChainData("Orderly Sepolia", 4460, "https://testnet-rpc.orderly.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/typescript/packages/account-modules/lib/forge-std/src/StdCheats.sol b/typescript/packages/account-modules/lib/forge-std/src/StdCheats.sol new file mode 100644 index 0000000..9f360de --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/StdCheats.sol @@ -0,0 +1,829 @@ +// 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 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 are reserved by Ethereum and may be on all EVM-compatible chains. + vm.assume(addr < address(0x1) || addr > address(0xff)); + + // 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 assumeUnusedAddress(address addr) internal view virtual { + uint256 size; + assembly { + size := extcodesize(addr) + } + vm.assume(size == 0); + + assumeNotPrecompile(addr); + assumeNotZeroAddress(addr); + assumeNotForgeAddress(addr); + } + + 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(vm.getBlockTimestamp() + time); + } + + function rewind(uint256 time) internal virtual { + vm.warp(vm.getBlockTimestamp() - 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_StdCheats("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_StdCheats(string memory p0) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string)", p0)); + status; + } +} diff --git a/typescript/packages/account-modules/lib/forge-std/src/StdConstants.sol b/typescript/packages/account-modules/lib/forge-std/src/StdConstants.sol new file mode 100644 index 0000000..2047d2b --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/StdConstants.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {IMulticall3} from "./interfaces/IMulticall3.sol"; +import {Vm} from "./Vm.sol"; + +library StdConstants { + /// @dev Cheat code address. + /// Calculated as `address(uint160(uint256(keccak256("hevm cheat code"))))`. + Vm internal constant VM = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); + /// @dev console.sol and console2.sol work by executing a staticcall to this address. + /// Calculated as `address(uint160(uint88(bytes11("console.log"))))`. + address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67; + /// @dev Used when deploying with create2. + /// Taken from https://github.com/Arachnid/deterministic-deployment-proxy. + address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + /// @dev The default address for tx.origin and msg.sender. + /// Calculated as `address(uint160(uint256(keccak256("foundry default caller"))))`. + address internal constant DEFAULT_SENDER = 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38; + /// @dev The address of the first contract `CREATE`d by a running test contract. + /// When running tests, each test contract is `CREATE`d by `DEFAULT_SENDER` with nonce 1. + /// Calculated as `VM.computeCreateAddress(VM.computeCreateAddress(DEFAULT_SENDER, 1), 1)`. + address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; + /// @dev Deterministic deployment address of the Multicall3 contract. + /// Taken from https://www.multicall3.com. + IMulticall3 internal constant MULTICALL3_ADDRESS = IMulticall3(0xcA11bde05977b3631167028862bE2a173976CA11); + /// @dev The order of the secp256k1 curve. + uint256 internal constant SECP256K1_ORDER = + 115792089237316195423570985008687907852837564279074904382605163141518161494337; +} diff --git a/typescript/packages/account-modules/lib/forge-std/src/StdError.sol b/typescript/packages/account-modules/lib/forge-std/src/StdError.sol new file mode 100644 index 0000000..a302191 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/forge-std/src/StdInvariant.sol b/typescript/packages/account-modules/lib/forge-std/src/StdInvariant.sol new file mode 100644 index 0000000..056db98 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/StdInvariant.sol @@ -0,0 +1,122 @@ +// 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 FuzzArtifactSelector { + string artifact; + 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; + + FuzzArtifactSelector[] private _targetedArtifactSelectors; + + FuzzSelector[] private _excludedSelectors; + 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 excludeSelector(FuzzSelector memory newExcludedSelector_) internal { + _excludedSelectors.push(newExcludedSelector_); + } + + 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(FuzzArtifactSelector 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 excludeSelectors() public view returns (FuzzSelector[] memory excludedSelectors_) { + excludedSelectors_ = _excludedSelectors; + } + + 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 (FuzzArtifactSelector[] 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/typescript/packages/account-modules/lib/forge-std/src/StdJson.sol b/typescript/packages/account-modules/lib/forge-std/src/StdJson.sol new file mode 100644 index 0000000..2a033c0 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/StdJson.sol @@ -0,0 +1,283 @@ +// 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(""); +// json.readUint(""); +// ``` +// To write: +// ``` +// using stdJson for string; +// string memory json = "json"; +// json.serialize("a", uint256(123)); +// string memory semiFinal = json.serialize("b", string("test")); +// string memory finalJson = json.serialize("c", semiFinal); +// finalJson.write(""); +// ``` + +library stdJson { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function keyExists(string memory json, string memory key) internal view returns (bool) { + return vm.keyExistsJson(json, key); + } + + 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 readUintOr(string memory json, string memory key, uint256 defaultValue) internal view returns (uint256) { + return keyExists(json, key) ? readUint(json, key) : defaultValue; + } + + function readUintArrayOr(string memory json, string memory key, uint256[] memory defaultValue) + internal + view + returns (uint256[] memory) + { + return keyExists(json, key) ? readUintArray(json, key) : defaultValue; + } + + function readIntOr(string memory json, string memory key, int256 defaultValue) internal view returns (int256) { + return keyExists(json, key) ? readInt(json, key) : defaultValue; + } + + function readIntArrayOr(string memory json, string memory key, int256[] memory defaultValue) + internal + view + returns (int256[] memory) + { + return keyExists(json, key) ? readIntArray(json, key) : defaultValue; + } + + function readBytes32Or(string memory json, string memory key, bytes32 defaultValue) + internal + view + returns (bytes32) + { + return keyExists(json, key) ? readBytes32(json, key) : defaultValue; + } + + function readBytes32ArrayOr(string memory json, string memory key, bytes32[] memory defaultValue) + internal + view + returns (bytes32[] memory) + { + return keyExists(json, key) ? readBytes32Array(json, key) : defaultValue; + } + + function readStringOr(string memory json, string memory key, string memory defaultValue) + internal + view + returns (string memory) + { + return keyExists(json, key) ? readString(json, key) : defaultValue; + } + + function readStringArrayOr(string memory json, string memory key, string[] memory defaultValue) + internal + view + returns (string[] memory) + { + return keyExists(json, key) ? readStringArray(json, key) : defaultValue; + } + + function readAddressOr(string memory json, string memory key, address defaultValue) + internal + view + returns (address) + { + return keyExists(json, key) ? readAddress(json, key) : defaultValue; + } + + function readAddressArrayOr(string memory json, string memory key, address[] memory defaultValue) + internal + view + returns (address[] memory) + { + return keyExists(json, key) ? readAddressArray(json, key) : defaultValue; + } + + function readBoolOr(string memory json, string memory key, bool defaultValue) internal view returns (bool) { + return keyExists(json, key) ? readBool(json, key) : defaultValue; + } + + function readBoolArrayOr(string memory json, string memory key, bool[] memory defaultValue) + internal + view + returns (bool[] memory) + { + return keyExists(json, key) ? readBoolArray(json, key) : defaultValue; + } + + function readBytesOr(string memory json, string memory key, bytes memory defaultValue) + internal + view + returns (bytes memory) + { + return keyExists(json, key) ? readBytes(json, key) : defaultValue; + } + + function readBytesArrayOr(string memory json, string memory key, bytes[] memory defaultValue) + internal + view + returns (bytes[] memory) + { + return keyExists(json, key) ? readBytesArray(json, key) : defaultValue; + } + + 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/typescript/packages/account-modules/lib/forge-std/src/StdMath.sol b/typescript/packages/account-modules/lib/forge-std/src/StdMath.sol new file mode 100644 index 0000000..459523b --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/forge-std/src/StdStorage.sol b/typescript/packages/account-modules/lib/forge-std/src/StdStorage.sol new file mode 100644 index 0000000..1627af7 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/StdStorage.sol @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {Vm} from "./Vm.sol"; + +struct FindData { + uint256 slot; + uint256 offsetLeft; + uint256 offsetRight; + bool found; +} + +struct StdStorage { + mapping(address => mapping(bytes4 => mapping(bytes32 => FindData))) finds; + bytes32[] _keys; + bytes4 _sig; + uint256 _depth; + address _target; + bytes32 _set; + bool _enable_packed_slots; + bytes _calldata; +} + +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"))))); + uint256 constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return bytes4(keccak256(bytes(sigStr))); + } + + function getCallParams(StdStorage storage self) internal view returns (bytes memory) { + if (self._calldata.length == 0) { + return flatten(self._keys); + } else { + return self._calldata; + } + } + + // Calls target contract with configured parameters + function callTarget(StdStorage storage self) internal view returns (bool, bytes32) { + bytes memory cd = abi.encodePacked(self._sig, getCallParams(self)); + (bool success, bytes memory rdat) = self._target.staticcall(cd); + bytes32 result = bytesToBytes32(rdat, 32 * self._depth); + + return (success, result); + } + + // Tries mutating slot value to determine if the targeted value is stored in it. + // If current value is 0, then we are setting slot value to type(uint256).max + // Otherwise, we set it to 0. That way, return value should always be affected. + function checkSlotMutatesCall(StdStorage storage self, bytes32 slot) internal returns (bool) { + bytes32 prevSlotValue = vm.load(self._target, slot); + (bool success, bytes32 prevReturnValue) = callTarget(self); + + bytes32 testVal = prevReturnValue == bytes32(0) ? bytes32(UINT256_MAX) : bytes32(0); + vm.store(self._target, slot, testVal); + + (, bytes32 newReturnValue) = callTarget(self); + + vm.store(self._target, slot, prevSlotValue); + + return (success && (prevReturnValue != newReturnValue)); + } + + // Tries setting one of the bits in slot to 1 until return value changes. + // Index of resulted bit is an offset packed slot has from left/right side + function findOffset(StdStorage storage self, bytes32 slot, bool left) internal returns (bool, uint256) { + for (uint256 offset = 0; offset < 256; offset++) { + uint256 valueToPut = left ? (1 << (255 - offset)) : (1 << offset); + vm.store(self._target, slot, bytes32(valueToPut)); + + (bool success, bytes32 data) = callTarget(self); + + if (success && (uint256(data) > 0)) { + return (true, offset); + } + } + return (false, 0); + } + + function findOffsets(StdStorage storage self, bytes32 slot) internal returns (bool, uint256, uint256) { + bytes32 prevSlotValue = vm.load(self._target, slot); + + (bool foundLeft, uint256 offsetLeft) = findOffset(self, slot, true); + (bool foundRight, uint256 offsetRight) = findOffset(self, slot, false); + + // `findOffset` may mutate slot value, so we are setting it to initial value + vm.store(self._target, slot, prevSlotValue); + return (foundLeft && foundRight, offsetLeft, offsetRight); + } + + function find(StdStorage storage self) internal returns (FindData storage) { + return find(self, true); + } + + /// @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, bool _clear) internal returns (FindData storage) { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes memory params = getCallParams(self); + + // calldata to test against + if (self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found) { + if (_clear) { + clear(self); + } + return self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))]; + } + vm.record(); + (, bytes32 callResult) = callTarget(self); + (bytes32[] memory reads,) = vm.accesses(address(who)); + + if (reads.length == 0) { + revert("stdStorage find(StdStorage): No storage use detected for target."); + } else { + for (uint256 i = reads.length; --i >= 0;) { + bytes32 prev = vm.load(who, reads[i]); + if (prev == bytes32(0)) { + emit WARNING_UninitedSlot(who, uint256(reads[i])); + } + + if (!checkSlotMutatesCall(self, reads[i])) { + continue; + } + + (uint256 offsetLeft, uint256 offsetRight) = (0, 0); + + if (self._enable_packed_slots) { + bool found; + (found, offsetLeft, offsetRight) = findOffsets(self, reads[i]); + if (!found) { + continue; + } + } + + // Check that value between found offsets is equal to the current call result + uint256 curVal = (uint256(prev) & getMaskByOffsets(offsetLeft, offsetRight)) >> offsetRight; + + if (uint256(callResult) != curVal) { + continue; + } + + emit SlotFound(who, fsig, keccak256(abi.encodePacked(params, field_depth)), uint256(reads[i])); + self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))] = + FindData(uint256(reads[i]), offsetLeft, offsetRight, true); + break; + } + } + + require( + self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found, + "stdStorage find(StdStorage): Slot(s) not found." + ); + + if (_clear) { + clear(self); + } + return self.finds[who][fsig][keccak256(abi.encodePacked(params, 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_calldata(StdStorage storage self, bytes memory _calldata) internal returns (StdStorage storage) { + self._calldata = _calldata; + 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 enable_packed_slots(StdStorage storage self) internal returns (StdStorage storage) { + self._enable_packed_slots = true; + 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) { + FindData storage data = find(self, false); + uint256 mask = getMaskByOffsets(data.offsetLeft, data.offsetRight); + uint256 value = (uint256(vm.load(self._target, bytes32(data.slot))) & mask) >> data.offsetRight; + clear(self); + return abi.encode(value); + } + + 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, true).slot - 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, true).slot - 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; + } + + function clear(StdStorage storage self) internal { + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + delete self._enable_packed_slots; + delete self._calldata; + } + + // Returns mask which contains non-zero bits for values between `offsetLeft` and `offsetRight` + // (slotValue & mask) >> offsetRight will be the value of the given packed variable + function getMaskByOffsets(uint256 offsetLeft, uint256 offsetRight) internal pure returns (uint256 mask) { + // mask = ((1 << (256 - (offsetRight + offsetLeft))) - 1) << offsetRight; + // using assembly because (1 << 256) causes overflow + assembly { + mask := shl(offsetRight, sub(shl(sub(256, add(offsetRight, offsetLeft)), 1), 1)) + } + } + + // Returns slot value with updated packed variable. + function getUpdatedSlotValue(bytes32 curValue, uint256 varValue, uint256 offsetLeft, uint256 offsetRight) + internal + pure + returns (bytes32 newValue) + { + return bytes32((uint256(curValue) & ~getMaskByOffsets(offsetLeft, offsetRight)) | (varValue << offsetRight)); + } +} + +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 find(self, true); + } + + function find(StdStorage storage self, bool _clear) internal returns (uint256) { + return stdStorageSafe.find(self, _clear).slot; + } + + 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 with_calldata(StdStorage storage self, bytes memory _calldata) internal returns (StdStorage storage) { + return stdStorageSafe.with_calldata(self, _calldata); + } + + function enable_packed_slots(StdStorage storage self) internal returns (StdStorage storage) { + return stdStorageSafe.enable_packed_slots(self); + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + return stdStorageSafe.depth(self, _depth); + } + + function clear(StdStorage storage self) internal { + stdStorageSafe.clear(self); + } + + 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; + bytes memory params = stdStorageSafe.getCallParams(self); + + if (!self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found) { + find(self, false); + } + FindData storage data = self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))]; + if ((data.offsetLeft + data.offsetRight) > 0) { + uint256 maxVal = 2 ** (256 - (data.offsetLeft + data.offsetRight)); + require( + uint256(set) < maxVal, + string( + abi.encodePacked( + "stdStorage find(StdStorage): Packed slot. We can't fit value greater than ", + vm.toString(maxVal) + ) + ) + ); + } + bytes32 curVal = vm.load(who, bytes32(data.slot)); + bytes32 valToSet = stdStorageSafe.getUpdatedSlotValue(curVal, uint256(set), data.offsetLeft, data.offsetRight); + + vm.store(who, bytes32(data.slot), valToSet); + + (bool success, bytes32 callResult) = stdStorageSafe.callTarget(self); + + if (!success || callResult != set) { + vm.store(who, bytes32(data.slot), curVal); + revert("stdStorage find(StdStorage): Failed to write value."); + } + clear(self); + } + + 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); + } +} diff --git a/typescript/packages/account-modules/lib/forge-std/src/StdStyle.sol b/typescript/packages/account-modules/lib/forge-std/src/StdStyle.sol new file mode 100644 index 0000000..d371e0c --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/forge-std/src/StdToml.sol b/typescript/packages/account-modules/lib/forge-std/src/StdToml.sol new file mode 100644 index 0000000..7ad3be2 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/StdToml.sol @@ -0,0 +1,283 @@ +// 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 TOML files +// To parse: +// ``` +// using stdToml for string; +// string memory toml = vm.readFile(""); +// toml.readUint(""); +// ``` +// To write: +// ``` +// using stdToml for string; +// string memory json = "json"; +// json.serialize("a", uint256(123)); +// string memory semiFinal = json.serialize("b", string("test")); +// string memory finalJson = json.serialize("c", semiFinal); +// finalJson.write(""); +// ``` + +library stdToml { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function keyExists(string memory toml, string memory key) internal view returns (bool) { + return vm.keyExistsToml(toml, key); + } + + function parseRaw(string memory toml, string memory key) internal pure returns (bytes memory) { + return vm.parseToml(toml, key); + } + + function readUint(string memory toml, string memory key) internal pure returns (uint256) { + return vm.parseTomlUint(toml, key); + } + + function readUintArray(string memory toml, string memory key) internal pure returns (uint256[] memory) { + return vm.parseTomlUintArray(toml, key); + } + + function readInt(string memory toml, string memory key) internal pure returns (int256) { + return vm.parseTomlInt(toml, key); + } + + function readIntArray(string memory toml, string memory key) internal pure returns (int256[] memory) { + return vm.parseTomlIntArray(toml, key); + } + + function readBytes32(string memory toml, string memory key) internal pure returns (bytes32) { + return vm.parseTomlBytes32(toml, key); + } + + function readBytes32Array(string memory toml, string memory key) internal pure returns (bytes32[] memory) { + return vm.parseTomlBytes32Array(toml, key); + } + + function readString(string memory toml, string memory key) internal pure returns (string memory) { + return vm.parseTomlString(toml, key); + } + + function readStringArray(string memory toml, string memory key) internal pure returns (string[] memory) { + return vm.parseTomlStringArray(toml, key); + } + + function readAddress(string memory toml, string memory key) internal pure returns (address) { + return vm.parseTomlAddress(toml, key); + } + + function readAddressArray(string memory toml, string memory key) internal pure returns (address[] memory) { + return vm.parseTomlAddressArray(toml, key); + } + + function readBool(string memory toml, string memory key) internal pure returns (bool) { + return vm.parseTomlBool(toml, key); + } + + function readBoolArray(string memory toml, string memory key) internal pure returns (bool[] memory) { + return vm.parseTomlBoolArray(toml, key); + } + + function readBytes(string memory toml, string memory key) internal pure returns (bytes memory) { + return vm.parseTomlBytes(toml, key); + } + + function readBytesArray(string memory toml, string memory key) internal pure returns (bytes[] memory) { + return vm.parseTomlBytesArray(toml, key); + } + + function readUintOr(string memory toml, string memory key, uint256 defaultValue) internal view returns (uint256) { + return keyExists(toml, key) ? readUint(toml, key) : defaultValue; + } + + function readUintArrayOr(string memory toml, string memory key, uint256[] memory defaultValue) + internal + view + returns (uint256[] memory) + { + return keyExists(toml, key) ? readUintArray(toml, key) : defaultValue; + } + + function readIntOr(string memory toml, string memory key, int256 defaultValue) internal view returns (int256) { + return keyExists(toml, key) ? readInt(toml, key) : defaultValue; + } + + function readIntArrayOr(string memory toml, string memory key, int256[] memory defaultValue) + internal + view + returns (int256[] memory) + { + return keyExists(toml, key) ? readIntArray(toml, key) : defaultValue; + } + + function readBytes32Or(string memory toml, string memory key, bytes32 defaultValue) + internal + view + returns (bytes32) + { + return keyExists(toml, key) ? readBytes32(toml, key) : defaultValue; + } + + function readBytes32ArrayOr(string memory toml, string memory key, bytes32[] memory defaultValue) + internal + view + returns (bytes32[] memory) + { + return keyExists(toml, key) ? readBytes32Array(toml, key) : defaultValue; + } + + function readStringOr(string memory toml, string memory key, string memory defaultValue) + internal + view + returns (string memory) + { + return keyExists(toml, key) ? readString(toml, key) : defaultValue; + } + + function readStringArrayOr(string memory toml, string memory key, string[] memory defaultValue) + internal + view + returns (string[] memory) + { + return keyExists(toml, key) ? readStringArray(toml, key) : defaultValue; + } + + function readAddressOr(string memory toml, string memory key, address defaultValue) + internal + view + returns (address) + { + return keyExists(toml, key) ? readAddress(toml, key) : defaultValue; + } + + function readAddressArrayOr(string memory toml, string memory key, address[] memory defaultValue) + internal + view + returns (address[] memory) + { + return keyExists(toml, key) ? readAddressArray(toml, key) : defaultValue; + } + + function readBoolOr(string memory toml, string memory key, bool defaultValue) internal view returns (bool) { + return keyExists(toml, key) ? readBool(toml, key) : defaultValue; + } + + function readBoolArrayOr(string memory toml, string memory key, bool[] memory defaultValue) + internal + view + returns (bool[] memory) + { + return keyExists(toml, key) ? readBoolArray(toml, key) : defaultValue; + } + + function readBytesOr(string memory toml, string memory key, bytes memory defaultValue) + internal + view + returns (bytes memory) + { + return keyExists(toml, key) ? readBytes(toml, key) : defaultValue; + } + + function readBytesArrayOr(string memory toml, string memory key, bytes[] memory defaultValue) + internal + view + returns (bytes[] memory) + { + return keyExists(toml, key) ? readBytesArray(toml, key) : defaultValue; + } + + 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.writeToml(jsonKey, path); + } + + function write(string memory jsonKey, string memory path, string memory valueKey) internal { + vm.writeToml(jsonKey, path, valueKey); + } +} diff --git a/typescript/packages/account-modules/lib/forge-std/src/StdUtils.sol b/typescript/packages/account-modules/lib/forge-std/src/StdUtils.sol new file mode 100644 index 0000000..9321df1 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/StdUtils.sol @@ -0,0 +1,208 @@ +// 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 pure virtual returns (uint256 result) { + result = _bound(x, min, max); + console2_log_StdUtils("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 pure virtual returns (int256 result) { + result = _bound(x, min, max); + console2_log_StdUtils("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 + function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) { + console2_log_StdUtils("computeCreateAddress is deprecated. Please use vm.computeCreateAddress instead."); + return vm.computeCreateAddress(deployer, nonce); + } + + function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) + internal + pure + virtual + returns (address) + { + console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead."); + return vm.computeCreate2Address(salt, initcodeHash, deployer); + } + + /// @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) { + console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead."); + return vm.computeCreate2Address(salt, initCodeHash); + } + + /// @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))); + } + + // This section is used to prevent the compilation of console, which shortens the compilation time when console is + // not used elsewhere. We also trick the compiler into letting us make the console log methods as `pure` to avoid + // any breaking changes to function signatures. + 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 = CONSOLE2_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function console2_log_StdUtils(string memory p0) private pure { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function console2_log_StdUtils(string memory p0, uint256 p1) private pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + } + + function console2_log_StdUtils(string memory p0, string memory p1) private pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } +} diff --git a/typescript/packages/account-modules/lib/forge-std/src/Test.sol b/typescript/packages/account-modules/lib/forge-std/src/Test.sol new file mode 100644 index 0000000..11b18f2 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/Test.sol @@ -0,0 +1,34 @@ +// 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 {StdConstants} from "./StdConstants.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 {stdToml} from "./StdToml.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {Vm} from "./Vm.sol"; + +// 📦 BOILERPLATE +import {TestBase} from "./Base.sol"; + +// ⭐️ TEST +abstract contract Test is TestBase, StdAssertions, StdChains, StdCheats, StdInvariant, StdUtils { + // Note: IS_TEST() must return true. + bool public IS_TEST = true; +} diff --git a/typescript/packages/account-modules/lib/forge-std/src/Vm.sol b/typescript/packages/account-modules/lib/forge-std/src/Vm.sol new file mode 100644 index 0000000..fc73cc1 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/Vm.sol @@ -0,0 +1,2468 @@ +// Automatically @generated by scripts/vm.py. Do not modify manually. + +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity >=0.6.2 <0.9.0; +pragma experimental ABIEncoderV2; + +/// 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 { + /// A modification applied to either `msg.sender` or `tx.origin`. Returned by `readCallers`. + enum CallerMode { + // No caller modification is currently active. + None, + // A one time broadcast triggered by a `vm.broadcast()` call is currently active. + Broadcast, + // A recurrent broadcast triggered by a `vm.startBroadcast()` call is currently active. + RecurrentBroadcast, + // A one time prank triggered by a `vm.prank()` call is currently active. + Prank, + // A recurrent prank triggered by a `vm.startPrank()` call is currently active. + RecurrentPrank + } + + /// The kind of account access that occurred. + enum AccountAccessKind { + // The account was called. + Call, + // The account was called via delegatecall. + DelegateCall, + // The account was called via callcode. + CallCode, + // The account was called via staticcall. + StaticCall, + // The account was created. + Create, + // The account was selfdestructed. + SelfDestruct, + // Synthetic access indicating the current context has resumed after a previous sub-context (AccountAccess). + Resume, + // The account's balance was read. + Balance, + // The account's codesize was read. + Extcodesize, + // The account's codehash was read. + Extcodehash, + // The account's code was copied. + Extcodecopy + } + + /// Forge execution contexts. + enum ForgeContext { + // Test group execution context (test, coverage or snapshot). + TestGroup, + // `forge test` execution context. + Test, + // `forge coverage` execution context. + Coverage, + // `forge snapshot` execution context. + Snapshot, + // Script group execution context (dry run, broadcast or resume). + ScriptGroup, + // `forge script` execution context. + ScriptDryRun, + // `forge script --broadcast` execution context. + ScriptBroadcast, + // `forge script --resume` execution context. + ScriptResume, + // Unknown `forge` execution context. + Unknown + } + + /// The transaction type (`txType`) of the broadcast. + enum BroadcastTxType { + // Represents a CALL broadcast tx. + Call, + // Represents a CREATE broadcast tx. + Create, + // Represents a CREATE2 broadcast tx. + Create2 + } + + /// An Ethereum log. Returned by `getRecordedLogs`. + struct Log { + // The topics of the log, including the signature, if any. + bytes32[] topics; + // The raw data of the log. + bytes data; + // The address of the log's emitter. + address emitter; + } + + /// An RPC URL and its alias. Returned by `rpcUrlStructs`. + struct Rpc { + // The alias of the RPC URL. + string key; + // The RPC URL. + string url; + } + + /// An RPC log object. Returned by `eth_getLogs`. + struct EthGetLogs { + // The address of the log's emitter. + address emitter; + // The topics of the log, including the signature, if any. + bytes32[] topics; + // The raw data of the log. + bytes data; + // The block hash. + bytes32 blockHash; + // The block number. + uint64 blockNumber; + // The transaction hash. + bytes32 transactionHash; + // The transaction index in the block. + uint64 transactionIndex; + // The log index. + uint256 logIndex; + // Whether the log was removed. + bool removed; + } + + /// A single entry in a directory listing. Returned by `readDir`. + struct DirEntry { + // The error message, if any. + string errorMessage; + // The path of the entry. + string path; + // The depth of the entry. + uint64 depth; + // Whether the entry is a directory. + bool isDir; + // Whether the entry is a symlink. + bool isSymlink; + } + + /// Metadata information about a file. + /// This structure is returned from the `fsMetadata` function and represents known + /// metadata about a file such as its permissions, size, modification + /// times, etc. + struct FsMetadata { + // True if this metadata is for a directory. + bool isDir; + // True if this metadata is for a symlink. + bool isSymlink; + // The size of the file, in bytes, this metadata is for. + uint256 length; + // True if this metadata is for a readonly (unwritable) file. + bool readOnly; + // The last modification time listed in this metadata. + uint256 modified; + // The last access time of this metadata. + uint256 accessed; + // The creation time listed in this metadata. + uint256 created; + } + + /// A wallet with a public and private key. + struct Wallet { + // The wallet's address. + address addr; + // The wallet's public key `X`. + uint256 publicKeyX; + // The wallet's public key `Y`. + uint256 publicKeyY; + // The wallet's private key. + uint256 privateKey; + } + + /// The result of a `tryFfi` call. + struct FfiResult { + // The exit code of the call. + int32 exitCode; + // The optionally hex-decoded `stdout` data. + bytes stdout; + // The `stderr` data. + bytes stderr; + } + + /// Information on the chain and fork. + struct ChainInfo { + // The fork identifier. Set to zero if no fork is active. + uint256 forkId; + // The chain ID of the current fork. + uint256 chainId; + } + + /// Information about a blockchain. + 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. + string rpcUrl; + } + + /// The result of a `stopAndReturnStateDiff` call. + struct AccountAccess { + // The chain and fork the access occurred. + ChainInfo chainInfo; + // The kind of account access that determines what the account is. + // If kind is Call, DelegateCall, StaticCall or CallCode, then the account is the callee. + // If kind is Create, then the account is the newly created account. + // If kind is SelfDestruct, then the account is the selfdestruct recipient. + // If kind is a Resume, then account represents a account context that has resumed. + AccountAccessKind kind; + // The account that was accessed. + // It's either the account created, callee or a selfdestruct recipient for CREATE, CALL or SELFDESTRUCT. + address account; + // What accessed the account. + address accessor; + // If the account was initialized or empty prior to the access. + // An account is considered initialized if it has code, a + // non-zero nonce, or a non-zero balance. + bool initialized; + // The previous balance of the accessed account. + uint256 oldBalance; + // The potential new balance of the accessed account. + // That is, all balance changes are recorded here, even if reverts occurred. + uint256 newBalance; + // Code of the account deployed by CREATE. + bytes deployedCode; + // Value passed along with the account access + uint256 value; + // Input data provided to the CREATE or CALL + bytes data; + // If this access reverted in either the current or parent context. + bool reverted; + // An ordered list of storage accesses made during an account access operation. + StorageAccess[] storageAccesses; + // Call depth traversed during the recording of state differences + uint64 depth; + } + + /// The storage accessed during an `AccountAccess`. + struct StorageAccess { + // The account whose storage was accessed. + address account; + // The slot that was accessed. + bytes32 slot; + // If the access was a write. + bool isWrite; + // The previous value of the slot. + bytes32 previousValue; + // The new value of the slot. + bytes32 newValue; + // If the access was reverted. + bool reverted; + } + + /// Gas used. Returned by `lastCallGas`. + struct Gas { + // The gas limit of the call. + uint64 gasLimit; + // The total gas used. + uint64 gasTotalUsed; + // DEPRECATED: The amount of gas used for memory expansion. Ref: + uint64 gasMemoryUsed; + // The amount of gas refunded. + int64 gasRefunded; + // The amount of gas remaining. + uint64 gasRemaining; + } + + /// The result of the `stopDebugTraceRecording` call + struct DebugStep { + // The stack before executing the step of the run. + // stack\[0\] represents the top of the stack. + // and only stack data relevant to the opcode execution is contained. + uint256[] stack; + // The memory input data before executing the step of the run. + // only input data relevant to the opcode execution is contained. + // e.g. for MLOAD, it will have memory\[offset:offset+32\] copied here. + // the offset value can be get by the stack data. + bytes memoryInput; + // The opcode that was accessed. + uint8 opcode; + // The call depth of the step. + uint64 depth; + // Whether the call end up with out of gas error. + bool isOutOfGas; + // The contract address where the opcode is running + address contractAddr; + } + + /// Represents a transaction's broadcast details. + struct BroadcastTxSummary { + // The hash of the transaction that was broadcasted + bytes32 txHash; + // Represent the type of transaction among CALL, CREATE, CREATE2 + BroadcastTxType txType; + // The address of the contract that was called or created. + // This is address of the contract that is created if the txType is CREATE or CREATE2. + address contractAddress; + // The block number the transaction landed in. + uint64 blockNumber; + // Status of the transaction, retrieved from the transaction receipt. + bool success; + } + + /// Holds a signed EIP-7702 authorization for an authority account to delegate to an implementation. + struct SignedDelegation { + // The y-parity of the recovered secp256k1 signature (0 or 1). + uint8 v; + // First 32 bytes of the signature. + bytes32 r; + // Second 32 bytes of the signature. + bytes32 s; + // The current nonce of the authority account at signing time. + // Used to ensure signature can't be replayed after account nonce changes. + uint64 nonce; + // Address of the contract implementation that will be delegated to. + // Gets encoded into delegation code: 0xef0100 || implementation. + address implementation; + } + + /// Represents a "potential" revert reason from a single subsequent call when using `vm.assumeNoReverts`. + /// Reverts that match will result in a FOUNDRY::ASSUME rejection, whereas unmatched reverts will be surfaced + /// as normal. + struct PotentialRevert { + // The allowed origin of the revert opcode; address(0) allows reverts from any address + address reverter; + // When true, only matches on the beginning of the revert data, otherwise, matches on entire revert data + bool partialMatch; + // The data to use to match encountered reverts + bytes revertData; + } + + /// An EIP-2930 access list item. + struct AccessListItem { + // The address to be added in access list. + address target; + // The storage keys to be added in access list. + bytes32[] storageKeys; + } + + // ======== Crypto ======== + + /// 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); + + /// 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); + + /// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language + /// at the derivation path `m/44'/60'/0'/0/{index}`. + function deriveKey(string calldata mnemonic, uint32 index, string calldata language) + external + pure + returns (uint256 privateKey); + + /// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language + /// at `{derivationPath}{index}`. + function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index, string calldata language) + external + pure + returns (uint256 privateKey); + + /// Derives secp256r1 public key from the provided `privateKey`. + function publicKeyP256(uint256 privateKey) external pure returns (uint256 publicKeyX, uint256 publicKeyY); + + /// Adds a private key to the local forge wallet and returns the address. + function rememberKey(uint256 privateKey) external returns (address keyAddr); + + /// Derive a set number of wallets from a mnemonic at the derivation path `m/44'/60'/0'/0/{0..count}`. + /// The respective private keys are saved to the local forge wallet for later use and their addresses are returned. + function rememberKeys(string calldata mnemonic, string calldata derivationPath, uint32 count) + external + returns (address[] memory keyAddrs); + + /// Derive a set number of wallets from a mnemonic in the specified language at the derivation path `m/44'/60'/0'/0/{0..count}`. + /// The respective private keys are saved to the local forge wallet for later use and their addresses are returned. + function rememberKeys( + string calldata mnemonic, + string calldata derivationPath, + string calldata language, + uint32 count + ) external returns (address[] memory keyAddrs); + + /// Signs data with a `Wallet`. + /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the + /// signature's `s` value, and the recovery id `v` in a single bytes32. + /// This format reduces the signature size from 65 to 64 bytes. + function signCompact(Wallet calldata wallet, bytes32 digest) external returns (bytes32 r, bytes32 vs); + + /// Signs `digest` with `privateKey` using the secp256k1 curve. + /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the + /// signature's `s` value, and the recovery id `v` in a single bytes32. + /// This format reduces the signature size from 65 to 64 bytes. + function signCompact(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 vs); + + /// Signs `digest` with signer provided to script using the secp256k1 curve. + /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the + /// signature's `s` value, and the recovery id `v` in a single bytes32. + /// This format reduces the signature size from 65 to 64 bytes. + /// If `--sender` is provided, the signer with provided address is used, otherwise, + /// if exactly one signer is provided to the script, that signer is used. + /// Raises error if signer passed through `--sender` does not match any unlocked signers or + /// if `--sender` is not provided and not exactly one signer is passed to the script. + function signCompact(bytes32 digest) external pure returns (bytes32 r, bytes32 vs); + + /// Signs `digest` with signer provided to script using the secp256k1 curve. + /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the + /// signature's `s` value, and the recovery id `v` in a single bytes32. + /// This format reduces the signature size from 65 to 64 bytes. + /// Raises error if none of the signers passed into the script have provided address. + function signCompact(address signer, bytes32 digest) external pure returns (bytes32 r, bytes32 vs); + + /// Signs `digest` with `privateKey` using the secp256r1 curve. + function signP256(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 s); + + /// Signs data with a `Wallet`. + function sign(Wallet calldata wallet, bytes32 digest) external returns (uint8 v, bytes32 r, bytes32 s); + + /// Signs `digest` with `privateKey` using the secp256k1 curve. + function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + + /// Signs `digest` with signer provided to script using the secp256k1 curve. + /// If `--sender` is provided, the signer with provided address is used, otherwise, + /// if exactly one signer is provided to the script, that signer is used. + /// Raises error if signer passed through `--sender` does not match any unlocked signers or + /// if `--sender` is not provided and not exactly one signer is passed to the script. + function sign(bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + + /// Signs `digest` with signer provided to script using the secp256k1 curve. + /// Raises error if none of the signers passed into the script have provided address. + function sign(address signer, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + + // ======== Environment ======== + + /// Gets the environment variable `name` and parses it as `address`. + /// Reverts if the variable was not found or could not be parsed. + function envAddress(string calldata name) external view returns (address value); + + /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value); + + /// Gets the environment variable `name` and parses it as `bool`. + /// Reverts if the variable was not found or could not be parsed. + function envBool(string calldata name) external view returns (bool value); + + /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value); + + /// Gets the environment variable `name` and parses it as `bytes32`. + /// Reverts if the variable was not found or could not be parsed. + function envBytes32(string calldata name) external view returns (bytes32 value); + + /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value); + + /// Gets the environment variable `name` and parses it as `bytes`. + /// Reverts if the variable was not found or could not be parsed. + function envBytes(string calldata name) external view returns (bytes memory value); + + /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value); + + /// Gets the environment variable `name` and returns true if it exists, else returns false. + function envExists(string calldata name) external view returns (bool result); + + /// Gets the environment variable `name` and parses it as `int256`. + /// Reverts if the variable was not found or could not be parsed. + function envInt(string calldata name) external view returns (int256 value); + + /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value); + + /// Gets the environment variable `name` and parses it as `bool`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, bool defaultValue) external view returns (bool value); + + /// Gets the environment variable `name` and parses it as `uint256`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, uint256 defaultValue) external view returns (uint256 value); + + /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, address[] calldata defaultValue) + external + view + returns (address[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue) + external + view + returns (bytes32[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, string[] calldata defaultValue) + external + view + returns (string[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue) + external + view + returns (bytes[] memory value); + + /// Gets the environment variable `name` and parses it as `int256`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, int256 defaultValue) external view returns (int256 value); + + /// Gets the environment variable `name` and parses it as `address`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, address defaultValue) external view returns (address value); + + /// Gets the environment variable `name` and parses it as `bytes32`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, bytes32 defaultValue) external view returns (bytes32 value); + + /// Gets the environment variable `name` and parses it as `string`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata defaultValue) external view returns (string memory value); + + /// Gets the environment variable `name` and parses it as `bytes`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, bytes calldata defaultValue) external view returns (bytes memory value); + + /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue) + external + view + returns (bool[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue) + external + view + returns (uint256[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue) + external + view + returns (int256[] memory value); + + /// Gets the environment variable `name` and parses it as `string`. + /// Reverts if the variable was not found or could not be parsed. + function envString(string calldata name) external view returns (string memory value); + + /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envString(string calldata name, string calldata delim) external view returns (string[] memory value); + + /// Gets the environment variable `name` and parses it as `uint256`. + /// Reverts if the variable was not found or could not be parsed. + function envUint(string calldata name) external view returns (uint256 value); + + /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value); + + /// Returns true if `forge` command was executed in given context. + function isContext(ForgeContext context) external view returns (bool result); + + /// Sets environment variables. + function setEnv(string calldata name, string calldata value) external; + + // ======== EVM ======== + + /// 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); + + /// Gets the address for a given private key. + function addr(uint256 privateKey) external pure returns (address keyAddr); + + /// Gets all the logs according to specified filter. + function eth_getLogs(uint256 fromBlock, uint256 toBlock, address target, bytes32[] calldata topics) + external + returns (EthGetLogs[] memory logs); + + /// Gets the current `block.blobbasefee`. + /// You should use this instead of `block.blobbasefee` if you use `vm.blobBaseFee`, as `block.blobbasefee` is assumed to be constant across a transaction, + /// and as a result will get optimized out by the compiler. + /// See https://github.com/foundry-rs/foundry/issues/6180 + function getBlobBaseFee() external view returns (uint256 blobBaseFee); + + /// Gets the current `block.number`. + /// You should use this instead of `block.number` if you use `vm.roll`, as `block.number` is assumed to be constant across a transaction, + /// and as a result will get optimized out by the compiler. + /// See https://github.com/foundry-rs/foundry/issues/6180 + function getBlockNumber() external view returns (uint256 height); + + /// Gets the current `block.timestamp`. + /// You should use this instead of `block.timestamp` if you use `vm.warp`, as `block.timestamp` is assumed to be constant across a transaction, + /// and as a result will get optimized out by the compiler. + /// See https://github.com/foundry-rs/foundry/issues/6180 + function getBlockTimestamp() external view returns (uint256 timestamp); + + /// 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); + + /// 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 nonce of an account. + function getNonce(address account) external view returns (uint64 nonce); + + /// Get the nonce of a `Wallet`. + function getNonce(Wallet calldata wallet) external returns (uint64 nonce); + + /// Gets the RLP encoded block header for a given block number. + /// Returns the block header in the same format as `cast block --raw`. + function getRawBlockHeader(uint256 blockNumber) external view returns (bytes memory rlpHeader); + + /// Gets all the recorded logs. + function getRecordedLogs() external returns (Log[] memory logs); + + /// Returns state diffs from current `vm.startStateDiffRecording` session. + function getStateDiff() external view returns (string memory diff); + + /// Returns state diffs from current `vm.startStateDiffRecording` session, in json format. + function getStateDiffJson() external view returns (string memory diff); + + /// Gets the gas used in the last call from the callee perspective. + function lastCallGas() external view returns (Gas memory gas); + + /// Loads a storage slot from an address. + function load(address target, bytes32 slot) external view returns (bytes32 data); + + /// Pauses gas metering (i.e. gas usage is not counted). Noop if already paused. + function pauseGasMetering() external; + + /// Records all storage reads and writes. Use `accesses` to get the recorded data. + /// Subsequent calls to `record` will clear the previous data. + function record() external; + + /// Record all the transaction logs. + function recordLogs() external; + + /// Reset gas metering (i.e. gas usage is set to gas limit). + function resetGasMetering() external; + + /// Resumes gas metering (i.e. gas usage is counted again). Noop if already on. + function resumeGasMetering() external; + + /// Performs an Ethereum JSON-RPC request to the current fork URL. + function rpc(string calldata method, string calldata params) external returns (bytes memory data); + + /// Performs an Ethereum JSON-RPC request to the given endpoint. + function rpc(string calldata urlOrAlias, string calldata method, string calldata params) + external + returns (bytes memory data); + + /// Records the debug trace during the run. + function startDebugTraceRecording() external; + + /// Starts recording all map SSTOREs for later retrieval. + function startMappingRecording() external; + + /// Record all account accesses as part of CREATE, CALL or SELFDESTRUCT opcodes in order, + /// along with the context of the calls + function startStateDiffRecording() external; + + /// Stop debug trace recording and returns the recorded debug trace. + function stopAndReturnDebugTraceRecording() external returns (DebugStep[] memory step); + + /// Returns an ordered array of all account accesses from a `vm.startStateDiffRecording` session. + function stopAndReturnStateDiff() external returns (AccountAccess[] memory accountAccesses); + + /// Stops recording all map SSTOREs for later retrieval and clears the recorded data. + function stopMappingRecording() external; + + /// Stops recording storage reads and writes. + function stopRecord() external; + + // ======== Filesystem ======== + + /// 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; + + /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the + /// artifact in the form of :: where and parts are optional. + function deployCode(string calldata artifactPath) external returns (address deployedAddress); + + /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the + /// artifact in the form of :: where and parts are optional. + /// Additionally accepts abi-encoded constructor arguments. + function deployCode(string calldata artifactPath, bytes calldata constructorArgs) + external + returns (address deployedAddress); + + /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the + /// artifact in the form of :: where and parts are optional. + /// Additionally accepts `msg.value`. + function deployCode(string calldata artifactPath, uint256 value) external returns (address deployedAddress); + + /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the + /// artifact in the form of :: where and parts are optional. + /// Additionally accepts abi-encoded constructor arguments and `msg.value`. + function deployCode(string calldata artifactPath, bytes calldata constructorArgs, uint256 value) + external + returns (address deployedAddress); + + /// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the + /// artifact in the form of :: where and parts are optional. + function deployCode(string calldata artifactPath, bytes32 salt) external returns (address deployedAddress); + + /// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the + /// artifact in the form of :: where and parts are optional. + /// Additionally accepts abi-encoded constructor arguments. + function deployCode(string calldata artifactPath, bytes calldata constructorArgs, bytes32 salt) + external + returns (address deployedAddress); + + /// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the + /// artifact in the form of :: where and parts are optional. + /// Additionally accepts `msg.value`. + function deployCode(string calldata artifactPath, uint256 value, bytes32 salt) + external + returns (address deployedAddress); + + /// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the + /// artifact in the form of :: where and parts are optional. + /// Additionally accepts abi-encoded constructor arguments and `msg.value`. + function deployCode(string calldata artifactPath, bytes calldata constructorArgs, uint256 value, bytes32 salt) + external + returns (address deployedAddress); + + /// Returns true if the given path points to an existing entity, else returns false. + function exists(string calldata path) external view returns (bool result); + + /// Performs a foreign function call via the terminal. + function ffi(string[] calldata commandInput) external returns (bytes memory 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); + + /// Gets the artifact path from code (aka. creation code). + function getArtifactPathByCode(bytes calldata code) external view returns (string memory path); + + /// Gets the artifact path from deployed code (aka. runtime code). + function getArtifactPathByDeployedCode(bytes calldata deployedCode) external view returns (string memory path); + + /// Returns the most recent broadcast for the given contract on `chainId` matching `txType`. + /// For example: + /// The most recent deployment can be fetched by passing `txType` as `CREATE` or `CREATE2`. + /// The most recent call can be fetched by passing `txType` as `CALL`. + function getBroadcast(string calldata contractName, uint64 chainId, BroadcastTxType txType) + external + view + returns (BroadcastTxSummary memory); + + /// Returns all broadcasts for the given contract on `chainId` with the specified `txType`. + /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. + function getBroadcasts(string calldata contractName, uint64 chainId, BroadcastTxType txType) + external + view + returns (BroadcastTxSummary[] memory); + + /// Returns all broadcasts for the given contract on `chainId`. + /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. + function getBroadcasts(string calldata contractName, uint64 chainId) + external + view + returns (BroadcastTxSummary[] memory); + + /// Gets the creation bytecode from an artifact file. Takes in the relative path to the json file or the path to the + /// artifact in the form of :: where and parts are optional. + 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 or the path to the + /// artifact in the form of :: where and parts are optional. + function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); + + /// Returns the most recent deployment for the current `chainId`. + function getDeployment(string calldata contractName) external view returns (address deployedAddress); + + /// Returns the most recent deployment for the given contract on `chainId` + function getDeployment(string calldata contractName, uint64 chainId) + external + view + returns (address deployedAddress); + + /// Returns all deployments for the given contract on `chainId` + /// Sorted in descending order of deployment time i.e descending order of BroadcastTxSummary.blockNumber. + /// The most recent deployment is the first element, and the oldest is the last. + function getDeployments(string calldata contractName, uint64 chainId) + external + view + returns (address[] memory deployedAddresses); + + /// Returns true if the path exists on disk and is pointing at a directory, else returns false. + function isDir(string calldata path) external view 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 view returns (bool result); + + /// Get the path of the current project root. + function projectRoot() external view returns (string memory path); + + /// Prompts the user for a string value in the terminal. + function prompt(string calldata promptText) external returns (string memory input); + + /// Prompts the user for an address in the terminal. + function promptAddress(string calldata promptText) external returns (address); + + /// Prompts the user for a hidden string value in the terminal. + function promptSecret(string calldata promptText) external returns (string memory input); + + /// Prompts the user for hidden uint256 in the terminal (usually pk). + function promptSecretUint(string calldata promptText) external returns (uint256); + + /// Prompts the user for uint256 in the terminal. + function promptUint(string calldata promptText) external returns (uint256); + + /// Reads the directory at the given path recursively, up to `maxDepth`. + /// `maxDepth` defaults to 1, meaning only the direct children of the given directory will be returned. + /// Follows symbolic links if `followLinks` is true. + function readDir(string calldata path) external view returns (DirEntry[] memory entries); + + /// See `readDir(string)`. + function readDir(string calldata path, uint64 maxDepth) external view returns (DirEntry[] memory entries); + + /// See `readDir(string)`. + 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; + + /// 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); + + /// Returns the time since unix epoch in milliseconds. + function unixTime() external view returns (uint256 milliseconds); + + /// 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; + + // ======== JSON ======== + + /// Checks if `key` exists in a JSON object. + function keyExistsJson(string calldata json, string calldata key) external view returns (bool); + + /// Parses a string of JSON data at `key` and coerces it to `address`. + function parseJsonAddress(string calldata json, string calldata key) external pure returns (address); + + /// Parses a string of JSON data at `key` and coerces it to `address[]`. + function parseJsonAddressArray(string calldata json, string calldata key) + external + pure + returns (address[] memory); + + /// Parses a string of JSON data at `key` and coerces it to `bool`. + function parseJsonBool(string calldata json, string calldata key) external pure returns (bool); + + /// Parses a string of JSON data at `key` and coerces it to `bool[]`. + function parseJsonBoolArray(string calldata json, string calldata key) external pure returns (bool[] memory); + + /// Parses a string of JSON data at `key` and coerces it to `bytes`. + function parseJsonBytes(string calldata json, string calldata key) external pure returns (bytes memory); + + /// Parses a string of JSON data at `key` and coerces it to `bytes32`. + function parseJsonBytes32(string calldata json, string calldata key) external pure returns (bytes32); + + /// Parses a string of JSON data at `key` and coerces it to `bytes32[]`. + function parseJsonBytes32Array(string calldata json, string calldata key) + external + pure + returns (bytes32[] memory); + + /// Parses a string of JSON data at `key` and coerces it to `bytes[]`. + function parseJsonBytesArray(string calldata json, string calldata key) external pure returns (bytes[] memory); + + /// Parses a string of JSON data at `key` and coerces it to `int256`. + function parseJsonInt(string calldata json, string calldata key) external pure returns (int256); + + /// Parses a string of JSON data at `key` and coerces it to `int256[]`. + function parseJsonIntArray(string calldata json, string calldata key) external pure returns (int256[] memory); + + /// Returns an array of all the keys in a JSON object. + function parseJsonKeys(string calldata json, string calldata key) external pure returns (string[] memory keys); + + /// Parses a string of JSON data at `key` and coerces it to `string`. + function parseJsonString(string calldata json, string calldata key) external pure returns (string memory); + + /// Parses a string of JSON data at `key` and coerces it to `string[]`. + function parseJsonStringArray(string calldata json, string calldata key) external pure returns (string[] memory); + + /// Parses a string of JSON data at `key` and coerces it to type array corresponding to `typeDescription`. + function parseJsonTypeArray(string calldata json, string calldata key, string calldata typeDescription) + external + pure + returns (bytes memory); + + /// Parses a string of JSON data and coerces it to type corresponding to `typeDescription`. + function parseJsonType(string calldata json, string calldata typeDescription) + external + pure + returns (bytes memory); + + /// Parses a string of JSON data at `key` and coerces it to type corresponding to `typeDescription`. + function parseJsonType(string calldata json, string calldata key, string calldata typeDescription) + external + pure + returns (bytes memory); + + /// Parses a string of JSON data at `key` and coerces it to `uint256`. + function parseJsonUint(string calldata json, string calldata key) external pure returns (uint256); + + /// Parses a string of JSON data at `key` and coerces it to `uint256[]`. + function parseJsonUintArray(string calldata json, string calldata key) external pure returns (uint256[] memory); + + /// ABI-encodes a JSON object. + function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData); + + /// ABI-encodes a JSON object at `key`. + function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData); + + /// See `serializeJson`. + function serializeAddress(string calldata objectKey, string calldata valueKey, address value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBool(string calldata objectKey, string calldata valueKey, bool value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeInt(string calldata objectKey, string calldata valueKey, int256 value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values) + external + returns (string memory json); + + /// Serializes a key and value to a JSON object stored in-memory that can be later written to a file. + /// 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); + + /// See `serializeJson`. + function serializeJsonType(string calldata typeDescription, bytes calldata value) + external + pure + returns (string memory json); + + /// See `serializeJson`. + function serializeJsonType( + string calldata objectKey, + string calldata valueKey, + string calldata typeDescription, + bytes calldata value + ) external returns (string memory json); + + /// See `serializeJson`. + function serializeString(string calldata objectKey, string calldata valueKey, string calldata value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeUintToHex(string calldata objectKey, string calldata valueKey, uint256 value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) + external + returns (string memory json); + + /// 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; + + /// Checks if `key` exists in a JSON object + /// `keyExists` is being deprecated in favor of `keyExistsJson`. It will be removed in future versions. + function keyExists(string calldata json, string calldata key) external view returns (bool); + + // ======== Scripting ======== + + /// Attach an EIP-4844 blob to the next call + function attachBlob(bytes calldata blob) external; + + /// Designate the next call as an EIP-7702 transaction + function attachDelegation(SignedDelegation calldata signedDelegation) external; + + /// Designate the next call as an EIP-7702 transaction, with optional cross-chain validity. + function attachDelegation(SignedDelegation calldata signedDelegation, bool crossChain) external; + + /// Takes a signed transaction and broadcasts it to the network. + function broadcastRawTransaction(bytes calldata data) external; + + /// Has the next call (at this call depth only) create transactions that can later be signed and sent onchain. + /// Broadcasting address is determined by checking the following in order: + /// 1. If `--sender` argument was provided, that address is used. + /// 2. If exactly one signer (e.g. private key, hw wallet, keystore) is set when `forge broadcast` is invoked, that signer is used. + /// 3. Otherwise, default foundry sender (1804c8AB1F12E6bbf3894d4083f33e07309d1f38) is used. + 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; + + /// Returns addresses of available unlocked wallets in the script environment. + function getWallets() external returns (address[] memory wallets); + + /// Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction + function signAndAttachDelegation(address implementation, uint256 privateKey) + external + returns (SignedDelegation memory signedDelegation); + + /// Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction for specific nonce + function signAndAttachDelegation(address implementation, uint256 privateKey, uint64 nonce) + external + returns (SignedDelegation memory signedDelegation); + + /// Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction, with optional cross-chain validity. + function signAndAttachDelegation(address implementation, uint256 privateKey, bool crossChain) + external + returns (SignedDelegation memory signedDelegation); + + /// Sign an EIP-7702 authorization for delegation + function signDelegation(address implementation, uint256 privateKey) + external + returns (SignedDelegation memory signedDelegation); + + /// Sign an EIP-7702 authorization for delegation for specific nonce + function signDelegation(address implementation, uint256 privateKey, uint64 nonce) + external + returns (SignedDelegation memory signedDelegation); + + /// Sign an EIP-7702 authorization for delegation, with optional cross-chain validity. + function signDelegation(address implementation, uint256 privateKey, bool crossChain) + external + returns (SignedDelegation memory signedDelegation); + + /// Has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain. + /// Broadcasting address is determined by checking the following in order: + /// 1. If `--sender` argument was provided, that address is used. + /// 2. If exactly one signer (e.g. private key, hw wallet, keystore) is set when `forge broadcast` is invoked, that signer is used. + /// 3. Otherwise, default foundry sender (1804c8AB1F12E6bbf3894d4083f33e07309d1f38) is used. + 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; + + // ======== String ======== + + /// Returns true if `search` is found in `subject`, false otherwise. + function contains(string calldata subject, string calldata search) external returns (bool result); + + /// Returns the index of the first occurrence of a `key` in an `input` string. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `key` is not found. + /// Returns 0 in case of an empty `key`. + function indexOf(string calldata input, string calldata key) external pure returns (uint256); + + /// Parses the given `string` into an `address`. + function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue); + + /// Parses the given `string` into a `bool`. + function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue); + + /// Parses the given `string` into `bytes`. + function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue); + + /// Parses the given `string` into a `bytes32`. + function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue); + + /// Parses the given `string` into a `int256`. + function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue); + + /// Parses the given `string` into a `uint256`. + function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue); + + /// Replaces occurrences of `from` in the given `string` with `to`. + function replace(string calldata input, string calldata from, string calldata to) + external + pure + returns (string memory output); + + /// Splits the given `string` into an array of strings divided by the `delimiter`. + function split(string calldata input, string calldata delimiter) external pure returns (string[] memory outputs); + + /// Converts the given `string` value to Lowercase. + function toLowercase(string calldata input) external pure returns (string memory output); + + /// Converts the given value to a `string`. + function toString(address value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(bytes calldata value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(bytes32 value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(bool value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(uint256 value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(int256 value) external pure returns (string memory stringifiedValue); + + /// Converts the given `string` value to Uppercase. + function toUppercase(string calldata input) external pure returns (string memory output); + + /// Trims leading and trailing whitespace from the given `string` value. + function trim(string calldata input) external pure returns (string memory output); + + // ======== Testing ======== + + /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. + /// Formats values with decimals in failure message. + function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertApproxEqAbsDecimal( + uint256 left, + uint256 right, + uint256 maxDelta, + uint256 decimals, + string calldata error + ) external pure; + + /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. + /// Formats values with decimals in failure message. + function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertApproxEqAbsDecimal( + int256 left, + int256 right, + uint256 maxDelta, + uint256 decimals, + string calldata error + ) external pure; + + /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. + function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) external pure; + + /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. + /// Includes error message into revert string on failure. + function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string calldata error) external pure; + + /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. + function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) external pure; + + /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. + /// Includes error message into revert string on failure. + function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string calldata error) external pure; + + /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Formats values with decimals in failure message. + function assertApproxEqRelDecimal(uint256 left, uint256 right, uint256 maxPercentDelta, uint256 decimals) + external + pure; + + /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertApproxEqRelDecimal( + uint256 left, + uint256 right, + uint256 maxPercentDelta, + uint256 decimals, + string calldata error + ) external pure; + + /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Formats values with decimals in failure message. + function assertApproxEqRelDecimal(int256 left, int256 right, uint256 maxPercentDelta, uint256 decimals) + external + pure; + + /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertApproxEqRelDecimal( + int256 left, + int256 right, + uint256 maxPercentDelta, + uint256 decimals, + string calldata error + ) external pure; + + /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta) external pure; + + /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Includes error message into revert string on failure. + function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta, string calldata error) + external + pure; + + /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) external pure; + + /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Includes error message into revert string on failure. + function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta, string calldata error) + external + pure; + + /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message. + function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message. + /// Includes error message into revert string on failure. + function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Asserts that two `int256` values are equal, formatting them with decimals in failure message. + function assertEqDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Asserts that two `int256` values are equal, formatting them with decimals in failure message. + /// Includes error message into revert string on failure. + function assertEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Asserts that two `bool` values are equal. + function assertEq(bool left, bool right) external pure; + + /// Asserts that two `bool` values are equal and includes error message into revert string on failure. + function assertEq(bool left, bool right, string calldata error) external pure; + + /// Asserts that two `string` values are equal. + function assertEq(string calldata left, string calldata right) external pure; + + /// Asserts that two `string` values are equal and includes error message into revert string on failure. + function assertEq(string calldata left, string calldata right, string calldata error) external pure; + + /// Asserts that two `bytes` values are equal. + function assertEq(bytes calldata left, bytes calldata right) external pure; + + /// Asserts that two `bytes` values are equal and includes error message into revert string on failure. + function assertEq(bytes calldata left, bytes calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bool` values are equal. + function assertEq(bool[] calldata left, bool[] calldata right) external pure; + + /// Asserts that two arrays of `bool` values are equal and includes error message into revert string on failure. + function assertEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `uint256 values are equal. + function assertEq(uint256[] calldata left, uint256[] calldata right) external pure; + + /// Asserts that two arrays of `uint256` values are equal and includes error message into revert string on failure. + function assertEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `int256` values are equal. + function assertEq(int256[] calldata left, int256[] calldata right) external pure; + + /// Asserts that two arrays of `int256` values are equal and includes error message into revert string on failure. + function assertEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure; + + /// Asserts that two `uint256` values are equal. + function assertEq(uint256 left, uint256 right) external pure; + + /// Asserts that two arrays of `address` values are equal. + function assertEq(address[] calldata left, address[] calldata right) external pure; + + /// Asserts that two arrays of `address` values are equal and includes error message into revert string on failure. + function assertEq(address[] calldata left, address[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bytes32` values are equal. + function assertEq(bytes32[] calldata left, bytes32[] calldata right) external pure; + + /// Asserts that two arrays of `bytes32` values are equal and includes error message into revert string on failure. + function assertEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `string` values are equal. + function assertEq(string[] calldata left, string[] calldata right) external pure; + + /// Asserts that two arrays of `string` values are equal and includes error message into revert string on failure. + function assertEq(string[] calldata left, string[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bytes` values are equal. + function assertEq(bytes[] calldata left, bytes[] calldata right) external pure; + + /// Asserts that two arrays of `bytes` values are equal and includes error message into revert string on failure. + function assertEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure; + + /// Asserts that two `uint256` values are equal and includes error message into revert string on failure. + function assertEq(uint256 left, uint256 right, string calldata error) external pure; + + /// Asserts that two `int256` values are equal. + function assertEq(int256 left, int256 right) external pure; + + /// Asserts that two `int256` values are equal and includes error message into revert string on failure. + function assertEq(int256 left, int256 right, string calldata error) external pure; + + /// Asserts that two `address` values are equal. + function assertEq(address left, address right) external pure; + + /// Asserts that two `address` values are equal and includes error message into revert string on failure. + function assertEq(address left, address right, string calldata error) external pure; + + /// Asserts that two `bytes32` values are equal. + function assertEq(bytes32 left, bytes32 right) external pure; + + /// Asserts that two `bytes32` values are equal and includes error message into revert string on failure. + function assertEq(bytes32 left, bytes32 right, string calldata error) external pure; + + /// Asserts that the given condition is false. + function assertFalse(bool condition) external pure; + + /// Asserts that the given condition is false and includes error message into revert string on failure. + function assertFalse(bool condition, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than or equal to second. + /// Formats values with decimals in failure message. + function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than or equal to second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be greater than or equal to second. + /// Formats values with decimals in failure message. + function assertGeDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects first value to be greater than or equal to second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertGeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than or equal to second. + function assertGe(uint256 left, uint256 right) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than or equal to second. + /// Includes error message into revert string on failure. + function assertGe(uint256 left, uint256 right, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be greater than or equal to second. + function assertGe(int256 left, int256 right) external pure; + + /// Compares two `int256` values. Expects first value to be greater than or equal to second. + /// Includes error message into revert string on failure. + function assertGe(int256 left, int256 right, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than second. + /// Formats values with decimals in failure message. + function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be greater than second. + /// Formats values with decimals in failure message. + function assertGtDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects first value to be greater than second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertGtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than second. + function assertGt(uint256 left, uint256 right) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than second. + /// Includes error message into revert string on failure. + function assertGt(uint256 left, uint256 right, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be greater than second. + function assertGt(int256 left, int256 right) external pure; + + /// Compares two `int256` values. Expects first value to be greater than second. + /// Includes error message into revert string on failure. + function assertGt(int256 left, int256 right, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be less than or equal to second. + /// Formats values with decimals in failure message. + function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects first value to be less than or equal to second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be less than or equal to second. + /// Formats values with decimals in failure message. + function assertLeDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects first value to be less than or equal to second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertLeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be less than or equal to second. + function assertLe(uint256 left, uint256 right) external pure; + + /// Compares two `uint256` values. Expects first value to be less than or equal to second. + /// Includes error message into revert string on failure. + function assertLe(uint256 left, uint256 right, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be less than or equal to second. + function assertLe(int256 left, int256 right) external pure; + + /// Compares two `int256` values. Expects first value to be less than or equal to second. + /// Includes error message into revert string on failure. + function assertLe(int256 left, int256 right, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be less than second. + /// Formats values with decimals in failure message. + function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects first value to be less than second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be less than second. + /// Formats values with decimals in failure message. + function assertLtDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects first value to be less than second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertLtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be less than second. + function assertLt(uint256 left, uint256 right) external pure; + + /// Compares two `uint256` values. Expects first value to be less than second. + /// Includes error message into revert string on failure. + function assertLt(uint256 left, uint256 right, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be less than second. + function assertLt(int256 left, int256 right) external pure; + + /// Compares two `int256` values. Expects first value to be less than second. + /// Includes error message into revert string on failure. + function assertLt(int256 left, int256 right, string calldata error) external pure; + + /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message. + function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message. + /// Includes error message into revert string on failure. + function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message. + function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message. + /// Includes error message into revert string on failure. + function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Asserts that two `bool` values are not equal. + function assertNotEq(bool left, bool right) external pure; + + /// Asserts that two `bool` values are not equal and includes error message into revert string on failure. + function assertNotEq(bool left, bool right, string calldata error) external pure; + + /// Asserts that two `string` values are not equal. + function assertNotEq(string calldata left, string calldata right) external pure; + + /// Asserts that two `string` values are not equal and includes error message into revert string on failure. + function assertNotEq(string calldata left, string calldata right, string calldata error) external pure; + + /// Asserts that two `bytes` values are not equal. + function assertNotEq(bytes calldata left, bytes calldata right) external pure; + + /// Asserts that two `bytes` values are not equal and includes error message into revert string on failure. + function assertNotEq(bytes calldata left, bytes calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bool` values are not equal. + function assertNotEq(bool[] calldata left, bool[] calldata right) external pure; + + /// Asserts that two arrays of `bool` values are not equal and includes error message into revert string on failure. + function assertNotEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `uint256` values are not equal. + function assertNotEq(uint256[] calldata left, uint256[] calldata right) external pure; + + /// Asserts that two arrays of `uint256` values are not equal and includes error message into revert string on failure. + function assertNotEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `int256` values are not equal. + function assertNotEq(int256[] calldata left, int256[] calldata right) external pure; + + /// Asserts that two arrays of `int256` values are not equal and includes error message into revert string on failure. + function assertNotEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure; + + /// Asserts that two `uint256` values are not equal. + function assertNotEq(uint256 left, uint256 right) external pure; + + /// Asserts that two arrays of `address` values are not equal. + function assertNotEq(address[] calldata left, address[] calldata right) external pure; + + /// Asserts that two arrays of `address` values are not equal and includes error message into revert string on failure. + function assertNotEq(address[] calldata left, address[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bytes32` values are not equal. + function assertNotEq(bytes32[] calldata left, bytes32[] calldata right) external pure; + + /// Asserts that two arrays of `bytes32` values are not equal and includes error message into revert string on failure. + function assertNotEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `string` values are not equal. + function assertNotEq(string[] calldata left, string[] calldata right) external pure; + + /// Asserts that two arrays of `string` values are not equal and includes error message into revert string on failure. + function assertNotEq(string[] calldata left, string[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bytes` values are not equal. + function assertNotEq(bytes[] calldata left, bytes[] calldata right) external pure; + + /// Asserts that two arrays of `bytes` values are not equal and includes error message into revert string on failure. + function assertNotEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure; + + /// Asserts that two `uint256` values are not equal and includes error message into revert string on failure. + function assertNotEq(uint256 left, uint256 right, string calldata error) external pure; + + /// Asserts that two `int256` values are not equal. + function assertNotEq(int256 left, int256 right) external pure; + + /// Asserts that two `int256` values are not equal and includes error message into revert string on failure. + function assertNotEq(int256 left, int256 right, string calldata error) external pure; + + /// Asserts that two `address` values are not equal. + function assertNotEq(address left, address right) external pure; + + /// Asserts that two `address` values are not equal and includes error message into revert string on failure. + function assertNotEq(address left, address right, string calldata error) external pure; + + /// Asserts that two `bytes32` values are not equal. + function assertNotEq(bytes32 left, bytes32 right) external pure; + + /// Asserts that two `bytes32` values are not equal and includes error message into revert string on failure. + function assertNotEq(bytes32 left, bytes32 right, string calldata error) external pure; + + /// Asserts that the given condition is true. + function assertTrue(bool condition) external pure; + + /// Asserts that the given condition is true and includes error message into revert string on failure. + function assertTrue(bool condition, string calldata error) external pure; + + /// If the condition is false, discard this run's fuzz inputs and generate new ones. + function assume(bool condition) external pure; + + /// Discard this run's fuzz inputs and generate new ones if next call reverted. + function assumeNoRevert() external pure; + + /// Discard this run's fuzz inputs and generate new ones if next call reverts with the potential revert parameters. + function assumeNoRevert(PotentialRevert calldata potentialRevert) external pure; + + /// Discard this run's fuzz inputs and generate new ones if next call reverts with the any of the potential revert parameters. + function assumeNoRevert(PotentialRevert[] calldata potentialReverts) external pure; + + /// Writes a breakpoint to jump to in the debugger. + function breakpoint(string calldata char) external pure; + + /// Writes a conditional breakpoint to jump to in the debugger. + function breakpoint(string calldata char, bool value) external pure; + + /// Returns true if the current Foundry version is greater than or equal to the given version. + /// The given version string must be in the format `major.minor.patch`. + /// This is equivalent to `foundryVersionCmp(version) >= 0`. + function foundryVersionAtLeast(string calldata version) external view returns (bool); + + /// Compares the current Foundry version with the given version string. + /// The given version string must be in the format `major.minor.patch`. + /// Returns: + /// -1 if current Foundry version is less than the given version + /// 0 if current Foundry version equals the given version + /// 1 if current Foundry version is greater than the given version + /// This result can then be used with a comparison operator against `0`. + /// For example, to check if the current Foundry version is greater than or equal to `1.0.0`: + /// `if (foundryVersionCmp("1.0.0") >= 0) { ... }` + function foundryVersionCmp(string calldata version) external view returns (int256); + + /// Returns a Chain struct for specific alias + function getChain(string calldata chainAlias) external view returns (Chain memory chain); + + /// Returns a Chain struct for specific chainId + function getChain(uint256 chainId) external view returns (Chain memory chain); + + /// Returns the Foundry version. + /// Format: -+.. + /// Sample output: 0.3.0-nightly+3cb96bde9b.1737036656.debug + /// Note: Build timestamps may vary slightly across platforms due to separate CI jobs. + /// For reliable version comparisons, use UNIX format (e.g., >= 1700000000) + /// to compare timestamps while ignoring minor time differences. + function getFoundryVersion() external view returns (string memory version); + + /// 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 as structs. + function rpcUrlStructs() external view returns (Rpc[] memory urls); + + /// Returns all rpc urls and their aliases `[alias, url][]`. + function rpcUrls() external view returns (string[2][] memory urls); + + /// Suspends execution of the main thread for `duration` milliseconds. + function sleep(uint256 duration) external; + + // ======== Toml ======== + + /// Checks if `key` exists in a TOML table. + function keyExistsToml(string calldata toml, string calldata key) external view returns (bool); + + /// Parses a string of TOML data at `key` and coerces it to `address`. + function parseTomlAddress(string calldata toml, string calldata key) external pure returns (address); + + /// Parses a string of TOML data at `key` and coerces it to `address[]`. + function parseTomlAddressArray(string calldata toml, string calldata key) + external + pure + returns (address[] memory); + + /// Parses a string of TOML data at `key` and coerces it to `bool`. + function parseTomlBool(string calldata toml, string calldata key) external pure returns (bool); + + /// Parses a string of TOML data at `key` and coerces it to `bool[]`. + function parseTomlBoolArray(string calldata toml, string calldata key) external pure returns (bool[] memory); + + /// Parses a string of TOML data at `key` and coerces it to `bytes`. + function parseTomlBytes(string calldata toml, string calldata key) external pure returns (bytes memory); + + /// Parses a string of TOML data at `key` and coerces it to `bytes32`. + function parseTomlBytes32(string calldata toml, string calldata key) external pure returns (bytes32); + + /// Parses a string of TOML data at `key` and coerces it to `bytes32[]`. + function parseTomlBytes32Array(string calldata toml, string calldata key) + external + pure + returns (bytes32[] memory); + + /// Parses a string of TOML data at `key` and coerces it to `bytes[]`. + function parseTomlBytesArray(string calldata toml, string calldata key) external pure returns (bytes[] memory); + + /// Parses a string of TOML data at `key` and coerces it to `int256`. + function parseTomlInt(string calldata toml, string calldata key) external pure returns (int256); + + /// Parses a string of TOML data at `key` and coerces it to `int256[]`. + function parseTomlIntArray(string calldata toml, string calldata key) external pure returns (int256[] memory); + + /// Returns an array of all the keys in a TOML table. + function parseTomlKeys(string calldata toml, string calldata key) external pure returns (string[] memory keys); + + /// Parses a string of TOML data at `key` and coerces it to `string`. + function parseTomlString(string calldata toml, string calldata key) external pure returns (string memory); + + /// Parses a string of TOML data at `key` and coerces it to `string[]`. + function parseTomlStringArray(string calldata toml, string calldata key) external pure returns (string[] memory); + + /// Parses a string of TOML data at `key` and coerces it to type array corresponding to `typeDescription`. + function parseTomlTypeArray(string calldata toml, string calldata key, string calldata typeDescription) + external + pure + returns (bytes memory); + + /// Parses a string of TOML data and coerces it to type corresponding to `typeDescription`. + function parseTomlType(string calldata toml, string calldata typeDescription) + external + pure + returns (bytes memory); + + /// Parses a string of TOML data at `key` and coerces it to type corresponding to `typeDescription`. + function parseTomlType(string calldata toml, string calldata key, string calldata typeDescription) + external + pure + returns (bytes memory); + + /// Parses a string of TOML data at `key` and coerces it to `uint256`. + function parseTomlUint(string calldata toml, string calldata key) external pure returns (uint256); + + /// Parses a string of TOML data at `key` and coerces it to `uint256[]`. + function parseTomlUintArray(string calldata toml, string calldata key) external pure returns (uint256[] memory); + + /// ABI-encodes a TOML table. + function parseToml(string calldata toml) external pure returns (bytes memory abiEncodedData); + + /// ABI-encodes a TOML table at `key`. + function parseToml(string calldata toml, string calldata key) external pure returns (bytes memory abiEncodedData); + + /// Takes serialized JSON, converts to TOML and write a serialized TOML to a file. + function writeToml(string calldata json, string calldata path) external; + + /// Takes serialized JSON, converts to TOML and write a serialized TOML table to an **existing** TOML file, replacing a value with key = + /// This is useful to replace a specific value of a TOML file, without having to parse the entire thing. + function writeToml(string calldata json, string calldata path, string calldata valueKey) external; + + // ======== Utilities ======== + + /// Compute the address of a contract created with CREATE2 using the given CREATE2 deployer. + function computeCreate2Address(bytes32 salt, bytes32 initCodeHash, address deployer) + external + pure + returns (address); + + /// Compute the address of a contract created with CREATE2 using the default CREATE2 deployer. + function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) external pure returns (address); + + /// Compute the address a contract will be deployed at for a given deployer address and nonce. + function computeCreateAddress(address deployer, uint256 nonce) external pure returns (address); + + /// Utility cheatcode to copy storage of `from` contract to another `to` contract. + function copyStorage(address from, address to) external; + + /// Generates the struct hash of the canonical EIP-712 type representation and its abi-encoded data. + /// Supports 2 different inputs: + /// 1. Name of the type (i.e. "PermitSingle"): + /// * requires previous binding generation with `forge bind-json`. + /// * bindings will be retrieved from the path configured in `foundry.toml`. + /// 2. String representation of the type (i.e. "Foo(Bar bar) Bar(uint256 baz)"). + /// * Note: the cheatcode will use the canonical type even if the input is malformated + /// with the wrong order of elements or with extra whitespaces. + function eip712HashStruct(string calldata typeNameOrDefinition, bytes calldata abiEncodedData) + external + pure + returns (bytes32 typeHash); + + /// Generates the struct hash of the canonical EIP-712 type representation and its abi-encoded data. + /// Requires previous binding generation with `forge bind-json`. + /// Params: + /// * `bindingsPath`: path where the output of `forge bind-json` is stored. + /// * `typeName`: Name of the type (i.e. "PermitSingle"). + /// * `abiEncodedData`: ABI-encoded data for the struct that is being hashed. + function eip712HashStruct(string calldata bindingsPath, string calldata typeName, bytes calldata abiEncodedData) + external + pure + returns (bytes32 typeHash); + + /// Generates the hash of the canonical EIP-712 type representation. + /// Supports 2 different inputs: + /// 1. Name of the type (i.e. "Transaction"): + /// * requires previous binding generation with `forge bind-json`. + /// * bindings will be retrieved from the path configured in `foundry.toml`. + /// 2. String representation of the type (i.e. "Foo(Bar bar) Bar(uint256 baz)"). + /// * Note: the cheatcode will output the canonical type even if the input is malformated + /// with the wrong order of elements or with extra whitespaces. + function eip712HashType(string calldata typeNameOrDefinition) external pure returns (bytes32 typeHash); + + /// Generates the hash of the canonical EIP-712 type representation. + /// Requires previous binding generation with `forge bind-json`. + /// Params: + /// * `bindingsPath`: path where the output of `forge bind-json` is stored. + /// * `typeName`: Name of the type (i.e. "Transaction"). + function eip712HashType(string calldata bindingsPath, string calldata typeName) + external + pure + returns (bytes32 typeHash); + + /// Generates a ready-to-sign digest of human-readable typed data following the EIP-712 standard. + function eip712HashTypedData(string calldata jsonData) external pure returns (bytes32 digest); + + /// Returns ENS namehash for provided string. + function ensNamehash(string calldata name) external pure returns (bytes32); + + /// Gets the label for the specified address. + function getLabel(address account) external view returns (string memory currentLabel); + + /// Labels an address in call traces. + function label(address account, string calldata newLabel) external; + + /// Pauses collection of call traces. Useful in cases when you want to skip tracing of + /// complex calls which are not useful for debugging. + function pauseTracing() external view; + + /// Returns a random `address`. + function randomAddress() external view returns (address); + + /// Returns a random `bool`. + function randomBool() external view returns (bool); + + /// Returns a random byte array value of the given length. + function randomBytes(uint256 len) external view returns (bytes memory); + + /// Returns a random fixed-size byte array of length 4. + function randomBytes4() external view returns (bytes4); + + /// Returns a random fixed-size byte array of length 8. + function randomBytes8() external view returns (bytes8); + + /// Returns a random `int256` value. + function randomInt() external view returns (int256); + + /// Returns a random `int256` value of given bits. + function randomInt(uint256 bits) external view returns (int256); + + /// Returns a random uint256 value. + function randomUint() external view returns (uint256); + + /// Returns random uint256 value between the provided range (=min..=max). + function randomUint(uint256 min, uint256 max) external view returns (uint256); + + /// Returns a random `uint256` value of given bits. + function randomUint(uint256 bits) external view returns (uint256); + + /// Unpauses collection of call traces. + function resumeTracing() external view; + + /// Utility cheatcode to set arbitrary storage for given target address. + function setArbitraryStorage(address target) external; + + /// Utility cheatcode to set arbitrary storage for given target address and overwrite + /// any storage slots that have been previously set. + function setArbitraryStorage(address target, bool overwrite) external; + + /// Set RNG seed. + function setSeed(uint256 seed) external; + + /// Randomly shuffles an array. + function shuffle(uint256[] calldata array) external returns (uint256[] memory); + + /// Sorts an array in ascending order. + function sort(uint256[] calldata array) external returns (uint256[] memory); + + /// Encodes a `bytes` value to a base64url string. + function toBase64URL(bytes calldata data) external pure returns (string memory); + + /// Encodes a `string` value to a base64url string. + function toBase64URL(string calldata data) external pure returns (string memory); + + /// Encodes a `bytes` value to a base64 string. + function toBase64(bytes calldata data) external pure returns (string memory); + + /// Encodes a `string` value to a base64 string. + function toBase64(string calldata data) external pure returns (string memory); +} + +/// 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 ======== + + /// Utility cheatcode to set an EIP-2930 access list for all subsequent transactions. + function accessList(AccessListItem[] calldata access) external; + + /// Returns the identifier of the currently active fork. Reverts if no fork is currently active. + function activeFork() external view returns (uint256 forkId); + + /// In forking mode, explicitly grant the given address cheatcode access. + function allowCheatcodes(address account) external; + + /// Sets `block.blobbasefee` + function blobBaseFee(uint256 newBlobBaseFee) external; + + /// Sets the blobhashes in the transaction. + /// Not available on EVM versions before Cancun. + /// If used on unsupported EVM versions it will revert. + function blobhashes(bytes32[] calldata hashes) external; + + /// Sets `block.chainid`. + function chainId(uint256 newChainId) external; + + /// Clears all mocked calls. + function clearMockedCalls() external; + + /// Clones a source account code, state, balance and nonce to a target account and updates in-memory EVM state. + function cloneAccount(address source, address target) external; + + /// Sets `block.coinbase`. + function coinbase(address newCoinbase) external; + + /// Marks the slots of an account and the account address as cold. + function cool(address target) external; + + /// Utility cheatcode to mark specific storage slot as cold, simulating no prior read. + function coolSlot(address target, bytes32 slot) external; + + /// 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 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 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 the latest block and returns the identifier of the fork. + function createSelectFork(string calldata urlOrAlias) 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); + + /// Sets an address' balance. + function deal(address account, uint256 newBalance) external; + + /// Removes the snapshot with the given ID created by `snapshot`. + /// Takes the snapshot ID to delete. + /// Returns `true` if the snapshot was successfully deleted. + /// Returns `false` if the snapshot does not exist. + function deleteStateSnapshot(uint256 snapshotId) external returns (bool success); + + /// Removes _all_ snapshots previously created by `snapshot`. + function deleteStateSnapshots() external; + + /// Sets `block.difficulty`. + /// Not available on EVM versions from Paris onwards. Use `prevrandao` instead. + /// Reverts if used on unsupported EVM versions. + function difficulty(uint256 newDifficulty) external; + + /// Dump a genesis JSON file's `allocs` to disk. + function dumpState(string calldata pathToStateJson) external; + + /// Sets an address' code. + function etch(address target, bytes calldata newRuntimeBytecode) external; + + /// Sets `block.basefee`. + function fee(uint256 newBasefee) external; + + /// Gets the blockhashes from the current transaction. + /// Not available on EVM versions before Cancun. + /// If used on unsupported EVM versions it will revert. + function getBlobhashes() external view returns (bytes32[] memory hashes); + + /// Returns true if the account is marked as persistent. + function isPersistent(address account) external view returns (bool persistent); + + /// Load a genesis JSON file's `allocs` into the in-memory EVM state. + function loadAllocs(string calldata pathToAllocsJson) 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; + + /// See `makePersistent(address)`. + function makePersistent(address account0, address account1) external; + + /// See `makePersistent(address)`. + function makePersistent(address account0, address account1, address account2) external; + + /// See `makePersistent(address)`. + function makePersistent(address[] calldata accounts) 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; + + /// Reverts a call to an address with specified revert data. + /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. + function mockCallRevert(address callee, bytes4 data, bytes calldata revertData) external; + + /// Reverts a call to an address with a specific `msg.value`, with specified revert data. + /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. + function mockCallRevert(address callee, uint256 msgValue, bytes4 data, bytes calldata revertData) 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; + + /// 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. + /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. + function mockCall(address callee, bytes4 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. + /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. + function mockCall(address callee, uint256 msgValue, bytes4 data, bytes calldata returnData) external; + + /// Mocks multiple calls to an address, returning specified data for each call. + function mockCalls(address callee, bytes calldata data, bytes[] calldata returnData) external; + + /// Mocks multiple calls to an address with a specific `msg.value`, returning specified data for each call. + function mockCalls(address callee, uint256 msgValue, bytes calldata data, bytes[] calldata returnData) external; + + /// Whenever a call is made to `callee` with calldata `data`, this cheatcode instead calls + /// `target` with the same calldata. This functionality is similar to a delegate call made to + /// `target` contract from `callee`. + /// Can be used to substitute a call to a function with another implementation that captures + /// the primary logic of the original function but is easier to reason about. + /// If calldata is not a strict match then partial match by selector is attempted. + function mockFunction(address callee, address target, bytes calldata data) external; + + /// Utility cheatcode to remove any EIP-2930 access list set by `accessList` cheatcode. + function noAccessList() external; + + /// Sets the *next* call's `msg.sender` to be the input address. + function prank(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 the *next* delegate call's `msg.sender` to be the input address. + function prank(address msgSender, bool delegateCall) external; + + /// Sets the *next* delegate call's `msg.sender` to be the input address, and the `tx.origin` to be the second input. + function prank(address msgSender, address txOrigin, bool delegateCall) 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.prevrandao`. + /// Not available on EVM versions before Paris. Use `difficulty` instead. + /// If used on unsupported EVM versions it will revert. + function prevrandao(uint256 newPrevrandao) 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); + + /// Resets the nonce of an account to 0 for EOAs and 1 for contract accounts. + function resetNonce(address account) external; + + /// Revert the state of the EVM to a previous snapshot + /// Takes the snapshot ID to revert to. + /// Returns `true` if the snapshot was successfully reverted. + /// Returns `false` if the snapshot does not exist. + /// **Note:** This does not automatically delete the snapshot. To delete the snapshot use `deleteStateSnapshot`. + function revertToState(uint256 snapshotId) external returns (bool success); + + /// Revert the state of the EVM to a previous snapshot and automatically deletes the snapshots + /// Takes the snapshot ID to revert to. + /// Returns `true` if the snapshot was successfully reverted and deleted. + /// Returns `false` if the snapshot does not exist. + function revertToStateAndDelete(uint256 snapshotId) external returns (bool success); + + /// Revokes persistent status from the address, previously added via `makePersistent`. + function revokePersistent(address account) external; + + /// See `revokePersistent(address)`. + function revokePersistent(address[] calldata accounts) external; + + /// Sets `block.height`. + function roll(uint256 newHeight) external; + + /// 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; + + /// Set blockhash for the current block. + /// It only sets the blockhash for blocks where `block.number - 256 <= number < block.number`. + function setBlockhash(uint256 blockNumber, bytes32 blockHash) 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; + + /// Snapshot capture the gas usage of the last call by name from the callee perspective. + function snapshotGasLastCall(string calldata name) external returns (uint256 gasUsed); + + /// Snapshot capture the gas usage of the last call by name in a group from the callee perspective. + function snapshotGasLastCall(string calldata group, string calldata name) external returns (uint256 gasUsed); + + /// Snapshot the current state of the evm. + /// Returns the ID of the snapshot that was created. + /// To revert a snapshot use `revertToState`. + function snapshotState() external returns (uint256 snapshotId); + + /// Snapshot capture an arbitrary numerical value by name. + /// The group name is derived from the contract name. + function snapshotValue(string calldata name, uint256 value) external; + + /// Snapshot capture an arbitrary numerical value by name in a group. + function snapshotValue(string calldata group, string calldata name, uint256 value) external; + + /// Sets all subsequent calls' `msg.sender` to be the input address until `stopPrank` is called. + function startPrank(address msgSender) 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; + + /// Sets all subsequent delegate calls' `msg.sender` to be the input address until `stopPrank` is called. + function startPrank(address msgSender, bool delegateCall) external; + + /// Sets all subsequent delegate 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, bool delegateCall) external; + + /// Start a snapshot capture of the current gas usage by name. + /// The group name is derived from the contract name. + function startSnapshotGas(string calldata name) external; + + /// Start a snapshot capture of the current gas usage by name in a group. + function startSnapshotGas(string calldata group, string calldata name) external; + + /// Resets subsequent calls' `msg.sender` to be `address(this)`. + function stopPrank() external; + + /// Stop the snapshot capture of the current gas by latest snapshot name, capturing the gas used since the start. + function stopSnapshotGas() external returns (uint256 gasUsed); + + /// Stop the snapshot capture of the current gas usage by name, capturing the gas used since the start. + /// The group name is derived from the contract name. + function stopSnapshotGas(string calldata name) external returns (uint256 gasUsed); + + /// Stop the snapshot capture of the current gas usage by name in a group, capturing the gas used since the start. + function stopSnapshotGas(string calldata group, string calldata name) external returns (uint256 gasUsed); + + /// Stores a value to an address' storage slot. + function store(address target, bytes32 slot, bytes32 value) 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; + + /// Sets `tx.gasprice`. + function txGasPrice(uint256 newGasPrice) external; + + /// Utility cheatcode to mark specific storage slot as warm, simulating a prior read. + function warmSlot(address target, bytes32 slot) external; + + /// Sets `block.timestamp`. + function warp(uint256 newTimestamp) external; + + /// `deleteSnapshot` is being deprecated in favor of `deleteStateSnapshot`. It will be removed in future versions. + function deleteSnapshot(uint256 snapshotId) external returns (bool success); + + /// `deleteSnapshots` is being deprecated in favor of `deleteStateSnapshots`. It will be removed in future versions. + function deleteSnapshots() external; + + /// `revertToAndDelete` is being deprecated in favor of `revertToStateAndDelete`. It will be removed in future versions. + function revertToAndDelete(uint256 snapshotId) external returns (bool success); + + /// `revertTo` is being deprecated in favor of `revertToState`. It will be removed in future versions. + function revertTo(uint256 snapshotId) external returns (bool success); + + /// `snapshot` is being deprecated in favor of `snapshotState`. It will be removed in future versions. + function snapshot() external returns (uint256 snapshotId); + + // ======== Testing ======== + + /// 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; + + /// 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; + + /// Expects the deployment of the specified bytecode by the specified address using the CREATE opcode + function expectCreate(bytes calldata bytecode, address deployer) external; + + /// Expects the deployment of the specified bytecode by the specified address using the CREATE2 opcode + function expectCreate2(bytes calldata bytecode, address deployer) external; + + /// Prepare an expected anonymous log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData.). + /// Call this function, then emit an anonymous 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 expectEmitAnonymous(bool checkTopic0, bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) + external; + + /// Same as the previous method, but also checks supplied address against emitting contract. + function expectEmitAnonymous( + bool checkTopic0, + bool checkTopic1, + bool checkTopic2, + bool checkTopic3, + bool checkData, + address emitter + ) external; + + /// Prepare an expected anonymous log with all topic and data checks enabled. + /// Call this function, then emit an anonymous 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 expectEmitAnonymous() external; + + /// Same as the previous method, but also checks supplied address against emitting contract. + function expectEmitAnonymous(address emitter) 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; + + /// Expect a given number of logs with the provided topics. + function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, uint64 count) external; + + /// Expect a given number of logs from a specific emitter with the provided topics. + function expectEmit( + bool checkTopic1, + bool checkTopic2, + bool checkTopic3, + bool checkData, + address emitter, + uint64 count + ) external; + + /// Expect a given number of logs with all topic and data checks enabled. + function expectEmit(uint64 count) external; + + /// Expect a given number of logs from a specific emitter with all topic and data checks enabled. + function expectEmit(address emitter, uint64 count) external; + + /// Expects an error on next call that starts with the revert data. + function expectPartialRevert(bytes4 revertData) external; + + /// Expects an error on next call to reverter address, that starts with the revert data. + function expectPartialRevert(bytes4 revertData, address reverter) external; + + /// Expects an error on next call with any revert data. + function expectRevert() external; + + /// Expects an error on next call that exactly matches the revert data. + function expectRevert(bytes4 revertData) external; + + /// Expects a `count` number of reverts from the upcoming calls from the reverter address that match the revert data. + function expectRevert(bytes4 revertData, address reverter, uint64 count) external; + + /// Expects a `count` number of reverts from the upcoming calls from the reverter address that exactly match the revert data. + function expectRevert(bytes calldata revertData, address reverter, uint64 count) external; + + /// Expects an error on next call that exactly matches the revert data. + function expectRevert(bytes calldata revertData) external; + + /// Expects an error with any revert data on next call to reverter address. + function expectRevert(address reverter) external; + + /// Expects an error from reverter address on next call, with any revert data. + function expectRevert(bytes4 revertData, address reverter) external; + + /// Expects an error from reverter address on next call, that exactly matches the revert data. + function expectRevert(bytes calldata revertData, address reverter) external; + + /// Expects a `count` number of reverts from the upcoming calls with any revert data or reverter. + function expectRevert(uint64 count) external; + + /// Expects a `count` number of reverts from the upcoming calls that match the revert data. + function expectRevert(bytes4 revertData, uint64 count) external; + + /// Expects a `count` number of reverts from the upcoming calls that exactly match the revert data. + function expectRevert(bytes calldata revertData, uint64 count) external; + + /// Expects a `count` number of reverts from the upcoming calls from the reverter address. + function expectRevert(address reverter, uint64 count) 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 level of a test. + function skip(bool skipTest) external; + + /// Marks a test as skipped with a reason. Must be called at the top level of a test. + function skip(bool skipTest, string calldata reason) external; + + /// Stops all safe memory expectation in the current subcontext. + function stopExpectSafeMemory() external; + + // ======== Utilities ======== + + /// Causes the next contract creation (via new) to fail and return its initcode in the returndata buffer. + /// This allows type-safe access to the initcode payload that would be used for contract creation. + /// Example usage: + /// vm.interceptInitcode(); + /// bytes memory initcode; + /// try new MyContract(param1, param2) { assert(false); } + /// catch (bytes memory interceptedInitcode) { initcode = interceptedInitcode; } + function interceptInitcode() external; +} diff --git a/typescript/packages/account-modules/lib/forge-std/src/console.sol b/typescript/packages/account-modules/lib/forge-std/src/console.sol new file mode 100644 index 0000000..4fdb667 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/console.sol @@ -0,0 +1,1560 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +library console { + address constant CONSOLE_ADDRESS = + 0x000000000000000000636F6e736F6c652e6c6f67; + + function _sendLogPayloadImplementation(bytes memory payload) internal view { + address consoleAddress = CONSOLE_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + pop( + staticcall( + gas(), + consoleAddress, + add(payload, 32), + mload(payload), + 0, + 0 + ) + ) + } + } + + function _castToPure( + function(bytes memory) internal view fnIn + ) internal pure returns (function(bytes memory) pure fnOut) { + assembly { + fnOut := fnIn + } + } + + function _sendLogPayload(bytes memory payload) internal pure { + _castToPure(_sendLogPayloadImplementation)(payload); + } + + 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)); + } +} diff --git a/typescript/packages/account-modules/lib/forge-std/src/console2.sol b/typescript/packages/account-modules/lib/forge-std/src/console2.sol new file mode 100644 index 0000000..03531d9 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/console2.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +import {console as console2} from "./console.sol"; diff --git a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC1155.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC1155.sol new file mode 100644 index 0000000..ffc8298 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC1155.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import {IERC165} from "./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/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC165.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC165.sol new file mode 100644 index 0000000..9af4bf8 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC20.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC20.sol new file mode 100644 index 0000000..ba40806 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC4626.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC4626.sol new file mode 100644 index 0000000..c645a0f --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC4626.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import {IERC20} from "./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 withdrawal 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 withdrawal. + /// - 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/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC6909.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC6909.sol new file mode 100644 index 0000000..6e11cb4 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC6909.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import {IERC165} from "./IERC165.sol"; + +/// @dev Required interface of an ERC-6909 compliant contract, as defined in +/// https://eips.ethereum.org/EIPS/eip-6909 +interface IERC6909 is IERC165 { + /// @dev Emitted when the allowance of a `spender` for an `owner` is set for a token of type `id`. + event Approval(address indexed owner, address indexed spender, uint256 indexed id, uint256 amount); + + /// @dev Emitted when `owner` grants or revokes operator status for a `spender`. + event OperatorSet(address indexed owner, address indexed spender, bool approved); + + /// @dev Emitted when `amount` tokens of type `id` are moved from `sender` to `receiver` initiated by `caller`. + event Transfer( + address caller, address indexed sender, address indexed receiver, uint256 indexed id, uint256 amount + ); + + ///@dev Returns the amount of tokens of type `id` owned by `owner`. + function balanceOf(address owner, uint256 id) external view returns (uint256); + + /// @dev Returns the amount of tokens of type `id` that `spender` is allowed to spend on behalf of `owner`. + /// NOTE: Does not include operator allowances. + function allowance(address owner, address spender, uint256 id) external view returns (uint256); + + /// @dev Returns true if `spender` is set as an operator for `owner`. + function isOperator(address owner, address spender) external view returns (bool); + + /// @dev Sets an approval to `spender` for `amount` tokens of type `id` from the caller's tokens. + /// Must return true. + function approve(address spender, uint256 id, uint256 amount) external returns (bool); + + /// @dev Grants or revokes unlimited transfer permission of any token id to `spender` for the caller's tokens. + /// Must return true. + function setOperator(address spender, bool approved) external returns (bool); + + /// @dev Transfers `amount` of token type `id` from the caller's account to `receiver`. + /// Must return true. + function transfer(address receiver, uint256 id, uint256 amount) external returns (bool); + + /// @dev Transfers `amount` of token type `id` from `sender` to `receiver`. + /// Must return true. + function transferFrom(address sender, address receiver, uint256 id, uint256 amount) external returns (bool); +} + +/// @dev Optional extension of {IERC6909} that adds metadata functions. +interface IERC6909Metadata is IERC6909 { + /// @dev Returns the name of the token of type `id`. + function name(uint256 id) external view returns (string memory); + + /// @dev Returns the ticker symbol of the token of type `id`. + function symbol(uint256 id) external view returns (string memory); + + /// @dev Returns the number of decimals for the token of type `id`. + function decimals(uint256 id) external view returns (uint8); +} + +/// @dev Optional extension of {IERC6909} that adds content URI functions. +interface IERC6909ContentURI is IERC6909 { + /// @dev Returns URI for the contract. + function contractURI() external view returns (string memory); + + /// @dev Returns the URI for the token of type `id`. + function tokenURI(uint256 id) external view returns (string memory); +} + +/// @dev Optional extension of {IERC6909} that adds a token supply function. +interface IERC6909TokenSupply is IERC6909 { + /// @dev Returns the total supply of the token of type `id`. + function totalSupply(uint256 id) external view returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC721.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC721.sol new file mode 100644 index 0000000..21a4a94 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC721.sol @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import {IERC165} from "./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/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7540.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7540.sol new file mode 100644 index 0000000..91a38ca --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7540.sol @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import {IERC7575} from "./IERC7575.sol"; + +/// @dev Interface of the base operator logic of ERC7540, as defined in +/// https://eips.ethereum.org/EIPS/eip-7540 +interface IERC7540Operator { + /** + * @dev The event emitted when an operator is set. + * + * @param controller The address of the controller. + * @param operator The address of the operator. + * @param approved The approval status. + */ + event OperatorSet(address indexed controller, address indexed operator, bool approved); + + /** + * @dev Sets or removes an operator for the caller. + * + * @param operator The address of the operator. + * @param approved The approval status. + * @return Whether the call was executed successfully or not + */ + function setOperator(address operator, bool approved) external returns (bool); + + /** + * @dev Returns `true` if the `operator` is approved as an operator for an `controller`. + * + * @param controller The address of the controller. + * @param operator The address of the operator. + * @return status The approval status + */ + function isOperator(address controller, address operator) external view returns (bool status); +} + +/// @dev Interface of the asynchronous deposit Vault interface of ERC7540, as defined in +/// https://eips.ethereum.org/EIPS/eip-7540 +interface IERC7540Deposit is IERC7540Operator { + event DepositRequest( + address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets + ); + /** + * @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit. + * + * - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow. + * - MUST revert if all of assets cannot be requested for deposit. + * - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller, + * approval of ERC-20 tokens from owner to sender is NOT enough. + * + * @param assets the amount of deposit assets to transfer from owner + * @param controller the controller of the request who will be able to operate the request + * @param owner the source of the deposit assets + * + * NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token. + */ + + function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId); + + /** + * @dev Returns the amount of requested assets in Pending state. + * + * - MUST NOT include any assets in Claimable state for deposit or mint. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input. + */ + function pendingDepositRequest(uint256 requestId, address controller) + external + view + returns (uint256 pendingAssets); + + /** + * @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint. + * + * - MUST NOT include any assets in Pending state. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input. + */ + function claimableDepositRequest(uint256 requestId, address controller) + external + view + returns (uint256 claimableAssets); + + /** + * @dev Mints shares Vault shares to receiver by claiming the Request of the controller. + * + * - MUST emit the Deposit event. + * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator. + */ + function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares); + + /** + * @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller. + * + * - MUST emit the Deposit event. + * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator. + */ + function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets); +} + +/// @dev Interface of the asynchronous deposit Vault interface of ERC7540, as defined in +/// https://eips.ethereum.org/EIPS/eip-7540 +interface IERC7540Redeem is IERC7540Operator { + event RedeemRequest( + address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets + ); + + /** + * @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem. + * + * - MUST support a redeem Request flow where the control of shares is taken from sender directly + * where msg.sender has ERC-20 approval over the shares of owner. + * - MUST revert if all of shares cannot be requested for redeem. + * + * @param shares the amount of shares to be redeemed to transfer from owner + * @param controller the controller of the request who will be able to operate the request + * @param owner the source of the shares to be redeemed + * + * NOTE: most implementations will require pre-approval of the Vault with the Vault's share token. + */ + function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId); + + /** + * @dev Returns the amount of requested shares in Pending state. + * + * - MUST NOT include any shares in Claimable state for redeem or withdraw. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input. + */ + function pendingRedeemRequest(uint256 requestId, address controller) + external + view + returns (uint256 pendingShares); + + /** + * @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw. + * + * - MUST NOT include any shares in Pending state for redeem or withdraw. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input. + */ + function claimableRedeemRequest(uint256 requestId, address controller) + external + view + returns (uint256 claimableShares); +} + +/// @dev Interface of the fully asynchronous Vault interface of ERC7540, as defined in +/// https://eips.ethereum.org/EIPS/eip-7540 +interface IERC7540 is IERC7540Deposit, IERC7540Redeem, IERC7575 {} diff --git a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7575.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7575.sol new file mode 100644 index 0000000..207e3e7 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7575.sol @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import {IERC165} from "./IERC165.sol"; + +/// @dev Interface of the ERC7575 "Multi-Asset ERC-4626 Vaults", as defined in +/// https://eips.ethereum.org/EIPS/eip-7575 +interface IERC7575 is IERC165 { + 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 address of the share token + * + * - MUST be an ERC-20 token contract. + * - MUST NOT revert. + */ + function share() external view returns (address shareTokenAddress); + + /** + * @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 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 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); +} + +/// @dev Interface of the ERC20 share token, as defined in +/// https://eips.ethereum.org/EIPS/eip-7575 +interface IERC7575Share is IERC165 { + event VaultUpdate(address indexed asset, address vault); + + /** + * @dev Returns the address of the Vault for the given asset. + * + * @param asset the ERC-20 token to deposit with into the Vault + */ + function vault(address asset) external view returns (address); +} diff --git a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IMulticall3.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IMulticall3.sol new file mode 100644 index 0000000..0d031b7 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/forge-std/src/safeconsole.sol b/typescript/packages/account-modules/lib/forge-std/src/safeconsole.sol new file mode 100644 index 0000000..87c475a --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/src/safeconsole.sol @@ -0,0 +1,13937 @@ +// 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; + /// @solidity memory-safe-assembly + assembly { + pureSendLogPayload := fnIn + } + pureSendLogPayload(offset, size); + } + + function _sendLogPayloadView(uint256 offset, uint256 size) private view { + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + assembly { + pureMemcopy := fnIn + } + pureMemcopy(fromOffset, toOffset, length); + } + + function _memcopyView(uint256 fromOffset, uint256 toOffset, uint256 length) private view { + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + assembly { + m0 := mload(sub(offset, 0x60)) + m1 := mload(sub(offset, 0x40)) + m2 := mload(sub(offset, 0x20)) + // Selector of `log(bytes)`. + mstore(sub(offset, 0x60), 0x0be77f56) + mstore(sub(offset, 0x40), 0x20) + mstore(sub(offset, 0x20), length) + } + _sendLogPayload(offset - 0x44, length + 0x44); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + assembly { + m0 := mload(add(endOffset, 0x00)) + m1 := mload(add(endOffset, 0x20)) + m2 := mload(add(endOffset, 0x40)) + } + _memcopy(offset, offset + 0x60, length); + /// @solidity memory-safe-assembly + assembly { + // Selector of `log(bytes)`. + mstore(add(offset, 0x00), 0x0be77f56) + mstore(add(offset, 0x20), 0x20) + mstore(add(offset, 0x40), length) + } + _sendLogPayload(offset + 0x1c, length + 0x44); + _memcopy(offset + 0x60, offset, length); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + // Selector of `log(address)`. + mstore(0x00, 0x2c2ecbc2) + mstore(0x20, p0) + } + _sendLogPayload(0x1c, 0x24); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + } + } + + function log(bool p0) internal pure { + bytes32 m0; + bytes32 m1; + /// @solidity memory-safe-assembly + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + // Selector of `log(bool)`. + mstore(0x00, 0x32458eed) + mstore(0x20, p0) + } + _sendLogPayload(0x1c, 0x24); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + } + } + + function log(uint256 p0) internal pure { + bytes32 m0; + bytes32 m1; + /// @solidity memory-safe-assembly + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + // Selector of `log(uint256)`. + mstore(0x00, 0xf82c50f1) + mstore(0x20, p0) + } + _sendLogPayload(0x1c, 0x24); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + } + } + + function log(bytes32 p0) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(address p0, bool p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(address p0, uint256 p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(bool p0, bool p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(bool p0, uint256 p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(uint256 p0, bool p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(uint256 p0, uint256 p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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/typescript/packages/account-modules/lib/forge-std/test/CommonBase.t.sol b/typescript/packages/account-modules/lib/forge-std/test/CommonBase.t.sol new file mode 100644 index 0000000..4a6eb34 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/CommonBase.t.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {CommonBase} from "../src/Base.sol"; +import {StdConstants} from "../src/StdConstants.sol"; +import {Test} from "../src/Test.sol"; + +contract CommonBaseTest is Test { + function testVmAddressValue() public pure { + assertEq(VM_ADDRESS, address(StdConstants.VM)); + } + + function testConsoleValue() public pure { + assertEq(CONSOLE, StdConstants.CONSOLE); + } + + function testCreate2FactoryValue() public pure { + assertEq(CREATE2_FACTORY, StdConstants.CREATE2_FACTORY); + } + + function testDefaultSenderValue() public pure { + assertEq(DEFAULT_SENDER, StdConstants.DEFAULT_SENDER); + } + + function testDefaultTestContractValue() public pure { + assertEq(DEFAULT_TEST_CONTRACT, StdConstants.DEFAULT_TEST_CONTRACT); + } + + function testMulticall3AddressValue() public pure { + assertEq(MULTICALL3_ADDRESS, address(StdConstants.MULTICALL3_ADDRESS)); + } + + function testSecp256k1OrderValue() public pure { + assertEq(SECP256K1_ORDER, StdConstants.SECP256K1_ORDER); + } + + function testUint256MaxValue() public pure { + assertEq(UINT256_MAX, type(uint256).max); + } + + function testVmValue() public pure { + assertEq(address(vm), address(StdConstants.VM)); + } +} diff --git a/typescript/packages/account-modules/lib/forge-std/test/StdAssertions.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdAssertions.t.sol new file mode 100644 index 0000000..acc0c1e --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/StdAssertions.t.sol @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {StdAssertions} from "../src/StdAssertions.sol"; +import {Vm} from "../src/Vm.sol"; + +interface VmInternal is Vm { + function _expectCheatcodeRevert(bytes memory message) external; +} + +contract StdAssertionsTest is StdAssertions { + string constant errorMessage = "User provided message"; + uint256 constant maxDecimals = 77; + + bool constant SHOULD_REVERT = true; + bool constant SHOULD_RETURN = false; + + bool constant STRICT_REVERT_DATA = true; + bool constant NON_STRICT_REVERT_DATA = false; + + VmInternal constant vm = VmInternal(address(uint160(uint256(keccak256("hevm cheat code"))))); + + 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)); + + assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); + } + + 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._expectCheatcodeRevert( + bytes( + string.concat( + "Call return data does not match: ", vm.toString(returnDataA), " != ", vm.toString(returnDataB) + ) + ) + ); + assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); + } + + 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)); + + assertEqCall(targetA, callDataA, targetB, callDataB, NON_STRICT_REVERT_DATA); + } + + 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._expectCheatcodeRevert( + bytes( + string.concat( + "Call revert data does not match: ", vm.toString(revertDataA), " != ", vm.toString(revertDataB) + ) + ) + ); + assertEqCall(targetA, callDataA, targetB, callDataB, STRICT_REVERT_DATA); + } + + 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.expectRevert(bytes("assertion failed")); + this.assertEqCallExternal(targetA, callDataA, targetB, callDataB, strictRevertData); + + vm.expectRevert(bytes("assertion failed")); + this.assertEqCallExternal(targetB, callDataB, targetA, callDataA, strictRevertData); + } + + // Helper function to test outcome of assertEqCall via `expect` cheatcodes + function assertEqCallExternal( + address targetA, + bytes memory callDataA, + address targetB, + bytes memory callDataB, + bool strictRevertData + ) public { + 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/typescript/packages/account-modules/lib/forge-std/test/StdChains.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdChains.t.sol new file mode 100644 index 0000000..d88069b --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/StdChains.t.sol @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {Test} from "../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://eth.merkle.io"); + assertEq(getChain("optimism_sepolia").rpcUrl, "https://sepolia.optimism.io/"); + assertEq(getChain("arbitrum_one_sepolia").rpcUrl, "https://sepolia-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://eth.merkle.io"); + + // 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"); + } + + // Named with a leading underscore to clarify this is not intended to be run as a normal test, + // and is intended to be used in the below `test_Rpcs` test. + 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. + // Currently commented out since this is slow and public RPCs are flaky, often resulting in failing CI. + // function test_Rpcs() public { + // _testRpc("mainnet"); + // _testRpc("sepolia"); + // _testRpc("holesky"); + // _testRpc("optimism"); + // _testRpc("optimism_sepolia"); + // _testRpc("arbitrum_one"); + // _testRpc("arbitrum_one_sepolia"); + // _testRpc("arbitrum_nova"); + // _testRpc("polygon"); + // _testRpc("polygon_amoy"); + // _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_sepolia"); + // _testRpc("base"); + // _testRpc("blast_sepolia"); + // _testRpc("blast"); + // _testRpc("fantom_opera"); + // _testRpc("fantom_opera_testnet"); + // _testRpc("fraxtal"); + // _testRpc("fraxtal_testnet"); + // _testRpc("berachain_bartio_testnet"); + // _testRpc("flare"); + // _testRpc("flare_coston2"); + // } + + function test_RevertIf_ChainNotFound() 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_RevertIf_SetChain_ChainIdExist_FirstTest() 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_RevertIf_ChainBubbleUp() public { + // We deploy a mock to properly test the revert. + StdChainsMock stdChainsMock = new StdChainsMock(); + + stdChainsMock.exposed_setChain("needs_undefined_env_var", ChainData("", 123456789, "")); + // Forge environment variable error. + vm.expectRevert(); + stdChainsMock.exposed_getChain("needs_undefined_env_var"); + } + + function test_RevertIf_SetChain_ChainIdExists_SecondTest() 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_RevertIf_SetEmptyAlias() 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_RevertIf_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_RevertIf_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_RevertIf_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_RevertIf_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_RevertIf_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", 9999999999999999999, "https://modified.chain/")); + vm.expectRevert("StdChains getChain(uint256): Chain with ID 123456789 not found."); + stdChainsMock.exposed_getChain(123456789); + + Chain memory modifiedChain = getChain(9999999999999999999); + assertEq(modifiedChain.name, "Modified Chain"); + assertEq(modifiedChain.chainId, 9999999999999999999); + assertEq(modifiedChain.rpcUrl, "https://modified.chain/"); + } + + function test_RevertIf_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(); + stdChainsMock.exposed_getChain(31337); + vm.expectRevert(); + stdChainsMock.exposed_getChain("sepolia"); + } +} diff --git a/typescript/packages/account-modules/lib/forge-std/test/StdCheats.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdCheats.t.sol new file mode 100644 index 0000000..57dbcc2 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/StdCheats.t.sol @@ -0,0 +1,639 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {StdCheats} from "../src/StdCheats.sol"; +import {Test} from "../src/Test.sol"; +import {stdJson} from "../src/StdJson.sol"; +import {stdToml} from "../src/StdToml.sol"; +import {IERC20} from "../src/interfaces/IERC20.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 test_DealToken() 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_RevertIf_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 pure { + 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 view { + 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 view { + 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(); + + 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_sepolia").chainId); + assertTrue( + addr < address(1) || (addr > address(9) && addr < address(0x4200000000000000000000000000000000000000)) + || addr > address(0x4200000000000000000000000000000000000800) + ); + } + + function testFuzz_AssumeNotForgeAddress(address addr) external pure { + assumeNotForgeAddress(addr); + assertTrue( + addr != address(vm) && addr != 0x000000000000000000636F6e736F6c652e6c6f67 + && addr != 0x4e59b44847b379578588920cA78FbF26c0B4956C + ); + } + + function test_RevertIf_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 USDC_BLACKLISTED_USER = 0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD; + address internal constant USDT_BLACKLISTED_USER = 0x8f8a8F4B54a2aAC7799d7bc81368aC27b852822A; + + MockUSDT public USDT; + MockUSDC public USDC; + + function setUp() public { + USDT = new MockUSDT(); + USDC = new MockUSDC(); + + USDC.setBlacklisted(USDC_BLACKLISTED_USER, true); + USDT.setBlacklisted(USDT_BLACKLISTED_USER, true); + } + + function test_RevertIf_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 view { + assumeNotBlacklisted(address(USDC), addr); + assumeNotBlacklisted(address(USDT), addr); + assertTrue(true); + } + + function test_RevertIf_AssumeNoBlacklisted_USDC() external { + // We deploy a mock version so we can properly test the revert. + StdCheatsMock stdCheatsMock = new StdCheatsMock(); + vm.expectRevert(); + stdCheatsMock.exposed_assumeNotBlacklisted(address(USDC), USDC_BLACKLISTED_USER); + } + + function testFuzz_AssumeNotBlacklisted_USDC(address addr) external view { + assumeNotBlacklisted(address(USDC), addr); + assertFalse(USDCLike(USDC).isBlacklisted(addr)); + } + + function test_RevertIf_AssumeNoBlacklisted_USDT() external { + // We deploy a mock version so we can properly test the revert. + StdCheatsMock stdCheatsMock = new StdCheatsMock(); + vm.expectRevert(); + stdCheatsMock.exposed_assumeNotBlacklisted(address(USDT), USDT_BLACKLISTED_USER); + } + + function testFuzz_AssumeNotBlacklisted_USDT(address addr) external view { + assumeNotBlacklisted(address(USDT), addr); + assertFalse(USDTLike(USDT).isBlackListed(addr)); + } +} + +/// @dev https://etherscan.io/token/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48#readProxyContract +interface USDCLike { + function isBlacklisted(address) external view returns (bool); +} + +/// @dev https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7#readContract +interface USDTLike { + function isBlackListed(address) external view returns (bool); +} + +contract MockUSDT is USDTLike { + mapping(address => bool) private blacklist; + + function isBlackListed(address addr) external view returns (bool) { + return blacklist[addr]; + } + + function setBlacklisted(address addr, bool value) external { + blacklist[addr] = value; + } +} + +contract MockUSDC is USDCLike { + mapping(address => bool) private blacklist; + + function isBlacklisted(address addr) external view returns (bool) { + return blacklist[addr]; + } + + function setBlacklisted(address addr, bool value) external { + blacklist[addr] = value; + } +} + +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; +} + +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/typescript/packages/account-modules/lib/forge-std/test/StdConstants.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdConstants.t.sol new file mode 100644 index 0000000..7a00530 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/StdConstants.t.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {StdConstants} from "../src/StdConstants.sol"; +import {Test} from "../src/Test.sol"; + +contract StdConstantsTest is Test { + function testVm() public view { + assertEq(StdConstants.VM.getBlockNumber(), 1); + } + + function testVmDerivation() public pure { + assertEq(address(StdConstants.VM), address(uint160(uint256(keccak256("hevm cheat code"))))); + } + + function testConsoleDerivation() public pure { + assertEq(StdConstants.CONSOLE, address(uint160(uint88(bytes11("console.log"))))); + } + + function testDefaultSender() public view { + assertEq(StdConstants.DEFAULT_SENDER, msg.sender); + } + + function testDefaultSenderDerivation() public pure { + assertEq(StdConstants.DEFAULT_SENDER, address(uint160(uint256(keccak256("foundry default caller"))))); + } + + function testDefaultTestContract() public { + assertEq(StdConstants.DEFAULT_TEST_CONTRACT, address(new Dummy())); + } + + function testDefaultTestContractDerivation() public view { + assertEq(address(this), StdConstants.VM.computeCreateAddress(StdConstants.DEFAULT_SENDER, 1)); + assertEq(StdConstants.DEFAULT_TEST_CONTRACT, StdConstants.VM.computeCreateAddress(address(this), 1)); + } +} + +contract Dummy {} diff --git a/typescript/packages/account-modules/lib/forge-std/test/StdError.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdError.t.sol new file mode 100644 index 0000000..29803d5 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/StdError.t.sol @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import {stdError} from "../src/StdError.sol"; +import {Test} from "../src/Test.sol"; + +contract StdErrorsTest is Test { + ErrorsTest test; + + function setUp() public { + test = new ErrorsTest(); + } + + function test_RevertIf_AssertionError() public { + vm.expectRevert(stdError.assertionError); + test.assertionError(); + } + + function test_RevertIf_ArithmeticError() public { + vm.expectRevert(stdError.arithmeticError); + test.arithmeticError(10); + } + + function test_RevertIf_DivisionError() public { + vm.expectRevert(stdError.divisionError); + test.divError(0); + } + + function test_RevertIf_ModError() public { + vm.expectRevert(stdError.divisionError); + test.modError(0); + } + + function test_RevertIf_EnumConversionError() public { + vm.expectRevert(stdError.enumConversionError); + test.enumConversion(1); + } + + function test_RevertIf_EncodeStgError() public { + vm.expectRevert(stdError.encodeStorageError); + test.encodeStgError(); + } + + function test_RevertIf_PopError() public { + vm.expectRevert(stdError.popError); + test.pop(); + } + + function test_RevertIf_IndexOOBError() public { + vm.expectRevert(stdError.indexOOBError); + test.indexOOBError(1); + } + + function test_RevertIf_MemOverflowError() public { + vm.expectRevert(stdError.memOverflowError); + test.mem(); + } + + function test_RevertIf_InternError() 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/typescript/packages/account-modules/lib/forge-std/test/StdJson.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdJson.t.sol new file mode 100644 index 0000000..6bedfcc --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/StdJson.t.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {Test, stdJson} from "../src/Test.sol"; + +contract StdJsonTest is Test { + using stdJson for string; + + string root; + string path; + + function setUp() public { + root = vm.projectRoot(); + path = string.concat(root, "/test/fixtures/test.json"); + } + + struct SimpleJson { + uint256 a; + string b; + } + + struct NestedJson { + uint256 a; + string b; + SimpleJson c; + } + + function test_readJson() public view { + string memory json = vm.readFile(path); + assertEq(json.readUint(".a"), 123); + } + + function test_writeJson() public { + string memory json = "json"; + json.serialize("a", uint256(123)); + string memory semiFinal = json.serialize("b", string("test")); + string memory finalJson = json.serialize("c", semiFinal); + finalJson.write(path); + + string memory json_ = vm.readFile(path); + bytes memory data = json_.parseRaw("$"); + NestedJson memory decodedData = abi.decode(data, (NestedJson)); + + assertEq(decodedData.a, 123); + assertEq(decodedData.b, "test"); + assertEq(decodedData.c.a, 123); + assertEq(decodedData.c.b, "test"); + } +} diff --git a/typescript/packages/account-modules/lib/forge-std/test/StdMath.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdMath.t.sol new file mode 100644 index 0000000..d1269a0 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/StdMath.t.sol @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import {stdMath} from "../src/StdMath.sol"; +import {Test, stdError} from "../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 pure { + 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 pure { + uint256 manualAbs = getAbs(a); + + uint256 abs = stdMath.abs(a); + + assertEq(abs, manualAbs); + } + + function test_GetDelta_Uint() external pure { + 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 pure { + uint256 manualDelta = a > b ? a - b : b - a; + + uint256 delta = stdMath.delta(a, b); + + assertEq(delta, manualDelta); + } + + function test_GetDelta_Int() external pure { + 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 pure { + 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 pure { + vm.assume(b != 0); + uint256 manualDelta = a > b ? a - b : 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 pure { + 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/typescript/packages/account-modules/lib/forge-std/test/StdStorage.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdStorage.t.sol new file mode 100644 index 0000000..46604f8 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/StdStorage.t.sol @@ -0,0 +1,488 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {stdStorage, StdStorage} from "../src/StdStorage.sol"; +import {Test} from "../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 testFuzz_StorageCheckedWriteMapPacked(address addr, uint128 value) public { + stdstore.enable_packed_slots().target(address(test)).sig(test.read_struct_lower.selector).with_key(addr) + .checked_write(value); + assertEq(test.read_struct_lower(addr), value); + + stdstore.enable_packed_slots().target(address(test)).sig(test.read_struct_upper.selector).with_key(addr) + .checked_write(value); + assertEq(test.read_struct_upper(addr), value); + } + + function test_StorageCheckedWriteMapPackedFullSuccess() 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 test_RevertStorageConst() public { + StorageTestTarget target = new StorageTestTarget(test); + + vm.expectRevert("stdStorage find(StdStorage): No storage use detected for target."); + target.expectRevertStorageConst(); + } + + function testFuzz_StorageNativePack(uint248 val1, uint248 val2, bool boolVal1, bool boolVal2) public { + stdstore.enable_packed_slots().target(address(test)).sig(test.tA.selector).checked_write(val1); + stdstore.enable_packed_slots().target(address(test)).sig(test.tB.selector).checked_write(boolVal1); + stdstore.enable_packed_slots().target(address(test)).sig(test.tC.selector).checked_write(boolVal2); + stdstore.enable_packed_slots().target(address(test)).sig(test.tD.selector).checked_write(val2); + + assertEq(test.tA(), val1); + assertEq(test.tB(), boolVal1); + assertEq(test.tC(), boolVal2); + assertEq(test.tD(), val2); + } + + 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_RevertIf_ReadingNonBoolValue() 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); + } + + function testFuzz_Packed(uint256 val, uint8 elemToGet) public { + // This function tries an assortment of packed slots, shifts meaning number of elements + // that are packed. Shiftsizes are the size of each element, i.e. 8 means a data type that is 8 bits, 16 == 16 bits, etc. + // Combined, these determine how a slot is packed. Making it random is too hard to avoid global rejection limit + // and make it performant. + + // change the number of shifts + for (uint256 i = 1; i < 5; i++) { + uint256 shifts = i; + + elemToGet = uint8(bound(elemToGet, 0, shifts - 1)); + + uint256[] memory shiftSizes = new uint256[](shifts); + for (uint256 j; j < shifts; j++) { + shiftSizes[j] = 8 * (j + 1); + } + + test.setRandomPacking(val); + + uint256 leftBits; + uint256 rightBits; + for (uint256 j; j < shiftSizes.length; j++) { + if (j < elemToGet) { + leftBits += shiftSizes[j]; + } else if (elemToGet != j) { + rightBits += shiftSizes[j]; + } + } + + // we may have some right bits unaccounted for + leftBits += 256 - (leftBits + shiftSizes[elemToGet] + rightBits); + // clear left bits, then clear right bits and realign + uint256 expectedValToRead = (val << leftBits) >> (leftBits + rightBits); + + uint256 readVal = stdstore.target(address(test)).enable_packed_slots().sig( + "getRandomPacked(uint8,uint8[],uint8)" + ).with_calldata(abi.encode(shifts, shiftSizes, elemToGet)).read_uint(); + + assertEq(readVal, expectedValToRead); + } + } + + function testFuzz_Packed2(uint256 nvars, uint256 seed) public { + // Number of random variables to generate. + nvars = bound(nvars, 1, 20); + + // This will decrease as we generate values in the below loop. + uint256 bitsRemaining = 256; + + // Generate a random value and size for each variable. + uint256[] memory vals = new uint256[](nvars); + uint256[] memory sizes = new uint256[](nvars); + uint256[] memory offsets = new uint256[](nvars); + + for (uint256 i = 0; i < nvars; i++) { + // Generate a random value and size. + offsets[i] = i == 0 ? 0 : offsets[i - 1] + sizes[i - 1]; + + uint256 nvarsRemaining = nvars - i; + uint256 maxVarSize = bitsRemaining - nvarsRemaining + 1; + sizes[i] = bound(uint256(keccak256(abi.encodePacked(seed, i + 256))), 1, maxVarSize); + bitsRemaining -= sizes[i]; + + uint256 maxVal; + uint256 varSize = sizes[i]; + assembly { + // mask = (1 << varSize) - 1 + maxVal := sub(shl(varSize, 1), 1) + } + vals[i] = bound(uint256(keccak256(abi.encodePacked(seed, i))), 0, maxVal); + } + + // Pack all values into the slot. + for (uint256 i = 0; i < nvars; i++) { + stdstore.enable_packed_slots().target(address(test)).sig("getRandomPacked(uint256,uint256)").with_key( + sizes[i] + ).with_key(offsets[i]).checked_write(vals[i]); + } + + // Verify the read data matches. + for (uint256 i = 0; i < nvars; i++) { + uint256 readVal = stdstore.enable_packed_slots().target(address(test)).sig( + "getRandomPacked(uint256,uint256)" + ).with_key(sizes[i]).with_key(offsets[i]).read_uint(); + + uint256 retVal = test.getRandomPacked(sizes[i], offsets[i]); + + assertEq(readVal, vals[i]); + assertEq(retVal, vals[i]); + } + } + + function testEdgeCaseArray() public { + stdstore.target(address(test)).sig("edgeCaseArray(uint256)").with_key(uint256(0)).checked_write(1); + assertEq(test.edgeCaseArray(0), 1); + } +} + +contract StorageTestTarget { + using stdStorage for StdStorage; + + StdStorage internal stdstore; + StorageTest internal test; + + constructor(StorageTest test_) { + test = test_; + } + + function expectRevertStorageConst() public { + stdstore.target(address(test)).sig("const()").find(); + } +} + +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"); + + uint256 randomPacking; + + // Array with length matching values of elements. + uint256[] public edgeCaseArray = [3, 3, 3]; + + 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; + } + + function setRandomPacking(uint256 val) public { + randomPacking = val; + } + + function _getMask(uint256 size) internal pure returns (uint256 mask) { + assembly { + // mask = (1 << size) - 1 + mask := sub(shl(size, 1), 1) + } + } + + function setRandomPacking(uint256 val, uint256 size, uint256 offset) public { + // Generate mask based on the size of the value + uint256 mask = _getMask(size); + // Zero out all bits for the word we're about to set + uint256 cleanedWord = randomPacking & ~(mask << offset); + // Place val in the correct spot of the cleaned word + randomPacking = cleanedWord | val << offset; + } + + function getRandomPacked(uint256 size, uint256 offset) public view returns (uint256) { + // Generate mask based on the size of the value + uint256 mask = _getMask(size); + // Shift to place the bits in the correct position, and use mask to zero out remaining bits + return (randomPacking >> offset) & mask; + } + + function getRandomPacked(uint8 shifts, uint8[] memory shiftSizes, uint8 elem) public view returns (uint256) { + require(elem < shifts, "!elem"); + uint256 leftBits; + uint256 rightBits; + + for (uint256 i; i < shiftSizes.length; i++) { + if (i < elem) { + leftBits += shiftSizes[i]; + } else if (elem != i) { + rightBits += shiftSizes[i]; + } + } + + // we may have some right bits unaccounted for + leftBits += 256 - (leftBits + shiftSizes[elem] + rightBits); + + // clear left bits, then clear right bits and realign + return (randomPacking << leftBits) >> (leftBits + rightBits); + } +} diff --git a/typescript/packages/account-modules/lib/forge-std/test/StdStyle.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdStyle.t.sol new file mode 100644 index 0000000..974e756 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/StdStyle.t.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {Test, console2, StdStyle} from "../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/typescript/packages/account-modules/lib/forge-std/test/StdToml.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdToml.t.sol new file mode 100644 index 0000000..5a45f4f --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/StdToml.t.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {Test, stdToml} from "../src/Test.sol"; + +contract StdTomlTest is Test { + using stdToml for string; + + string root; + string path; + + function setUp() public { + root = vm.projectRoot(); + path = string.concat(root, "/test/fixtures/test.toml"); + } + + struct SimpleToml { + uint256 a; + string b; + } + + struct NestedToml { + uint256 a; + string b; + SimpleToml c; + } + + function test_readToml() public view { + string memory json = vm.readFile(path); + assertEq(json.readUint(".a"), 123); + } + + function test_writeToml() public { + string memory json = "json"; + json.serialize("a", uint256(123)); + string memory semiFinal = json.serialize("b", string("test")); + string memory finalJson = json.serialize("c", semiFinal); + finalJson.write(path); + + string memory toml = vm.readFile(path); + bytes memory data = toml.parseRaw("$"); + NestedToml memory decodedData = abi.decode(data, (NestedToml)); + + assertEq(decodedData.a, 123); + assertEq(decodedData.b, "test"); + assertEq(decodedData.c.a, 123); + assertEq(decodedData.c.b, "test"); + } +} diff --git a/typescript/packages/account-modules/lib/forge-std/test/StdUtils.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdUtils.t.sol new file mode 100644 index 0000000..aee801b --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/StdUtils.t.sol @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {Test, StdUtils} from "../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 pure returns (int256) { + return bound(num, min, max); + } + + function exposed_bound(uint256 num, uint256 min, uint256 max) external pure 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 pure { + 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 pure { + 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 pure { + 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 testFuzz_Bound_DistributionIsEven(uint256 min, uint256 size) public pure { + 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 testFuzz_Bound(uint256 num, uint256 min, uint256 max) public pure { + 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 pure { + 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_RevertIf_BoundMaxLessThanMin() 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 testFuzz_RevertIf_BoundMaxLessThanMin(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 pure { + 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 pure { + 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 pure { + 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 testFuzz_BoundInt_DistributionIsEven(int256 min, uint256 size) public pure { + 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 testFuzz_BoundInt(int256 num, int256 min, int256 max) public pure { + 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 pure { + 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 pure { + 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_RevertIf_BoundIntMaxLessThanMin() 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 testFuzz_RevertIf_BoundIntMaxLessThanMin(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 pure { + 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 pure { + 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_RevertIf_BytesLengthExceeds32() 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 pure { + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + uint256 nonce = 14; + address createAddress = computeCreateAddress(deployer, nonce); + assertEq(createAddress, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); + } + + /*////////////////////////////////////////////////////////////////////////// + COMPUTE CREATE2 ADDRESS + //////////////////////////////////////////////////////////////////////////*/ + + function test_ComputeCreate2Address() external pure { + 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 pure { + 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_RevertIf_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_RevertIf_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/typescript/packages/account-modules/lib/forge-std/test/Vm.t.sol b/typescript/packages/account-modules/lib/forge-std/test/Vm.t.sol new file mode 100644 index 0000000..1cf81c4 --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/Vm.t.sol @@ -0,0 +1,18 @@ +// 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"; + +// These tests ensure that functions are never accidentally removed from a Vm interface, or +// inadvertently moved between Vm and VmSafe. These tests must be updated each time a function is +// added to or removed from Vm or VmSafe. +contract VmTest is Test { + function test_VmInterfaceId() public pure { + assertEq(type(Vm).interfaceId, bytes4(0xe835828d), "Vm"); + } + + function test_VmSafeInterfaceId() public pure { + assertEq(type(VmSafe).interfaceId, bytes4(0xf4408204), "VmSafe"); + } +} diff --git a/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationScript.sol b/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationScript.sol new file mode 100644 index 0000000..d3d88a0 --- /dev/null +++ b/typescript/packages/account-modules/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 {Script} from "../../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/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationScriptBase.sol b/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationScriptBase.sol new file mode 100644 index 0000000..65b5bed --- /dev/null +++ b/typescript/packages/account-modules/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 {ScriptBase} from "../../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/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationTest.sol b/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationTest.sol new file mode 100644 index 0000000..2a9dec5 --- /dev/null +++ b/typescript/packages/account-modules/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 {Test} from "../../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/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationTestBase.sol b/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationTestBase.sol new file mode 100644 index 0000000..32b3fc5 --- /dev/null +++ b/typescript/packages/account-modules/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 {TestBase} from "../../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/typescript/packages/account-modules/lib/forge-std/test/fixtures/broadcast.log.json b/typescript/packages/account-modules/lib/forge-std/test/fixtures/broadcast.log.json new file mode 100644 index 0000000..0a0200b --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/forge-std/test/fixtures/test.json b/typescript/packages/account-modules/lib/forge-std/test/fixtures/test.json new file mode 100644 index 0000000..caebf6d --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/fixtures/test.json @@ -0,0 +1,8 @@ +{ + "a": 123, + "b": "test", + "c": { + "a": 123, + "b": "test" + } +} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/forge-std/test/fixtures/test.toml b/typescript/packages/account-modules/lib/forge-std/test/fixtures/test.toml new file mode 100644 index 0000000..60692bc --- /dev/null +++ b/typescript/packages/account-modules/lib/forge-std/test/fixtures/test.toml @@ -0,0 +1,6 @@ +a = 123 +b = "test" + +[c] +a = 123 +b = "test" diff --git a/typescript/packages/account-modules/lib/modulekit/.changeset/README.md b/typescript/packages/account-modules/lib/modulekit/.changeset/README.md new file mode 100644 index 0000000..e5b6d8d --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/.changeset/README.md @@ -0,0 +1,8 @@ +# Changesets + +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works +with multi-package repos, or single-package repos to help you version and publish your code. You can +find the full documentation for it [in our repository](https://github.com/changesets/changesets) + +We have a quick list of common questions to get you started engaging with this project in +[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) diff --git a/typescript/packages/account-modules/lib/modulekit/.changeset/config.json b/typescript/packages/account-modules/lib/modulekit/.changeset/config.json new file mode 100644 index 0000000..91b6a95 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/.changeset/config.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", + "changelog": "@changesets/cli/changelog", + "commit": false, + "fixed": [], + "linked": [], + "access": "restricted", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "ignore": [] +} diff --git a/typescript/packages/account-modules/lib/modulekit/.env-example b/typescript/packages/account-modules/lib/modulekit/.env-example new file mode 100644 index 0000000..5f2a817 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/.env-example @@ -0,0 +1,2 @@ +MAINNET_RPC_URL= + diff --git a/typescript/packages/account-modules/lib/modulekit/.github/workflows/ci.yaml b/typescript/packages/account-modules/lib/modulekit/.github/workflows/ci.yaml new file mode 100644 index 0000000..9e66804 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/.github/workflows/ci.yaml @@ -0,0 +1,55 @@ +on: + workflow_dispatch: + push: + branches: + - "main" + pull_request: + +jobs: + lint: + uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-lint.yaml@main" + + build: + uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-build.yaml@main" + + test: + needs: ["lint", "build"] + uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-test.yaml@main" + with: + foundry-fuzz-runs: 5000 + foundry-profile: "test" + match-path: "test/**/*.sol" + foundry-verbosity: 3 + foundry-gas-limit: "18446744073709551615" + foundry-memory-limit: 2147483648 + secrets: + MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} + TESTNET_RPC_URL: ${{ secrets.TESTNET_RPC_URL }} + + test-simulate: + needs: ["lint", "build"] + uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-test-simulate.yaml@main" + with: + foundry-fuzz-runs: 5000 + foundry-profile: "test" + match-path: "test/**/*.sol" + foundry-verbosity: 3 + foundry-gas-limit: "18446744073709551615" + foundry-memory-limit: 2147483648 + secrets: + MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} + TESTNET_RPC_URL: ${{ secrets.TESTNET_RPC_URL }} + + test-multi-account: + needs: ["lint", "build"] + uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-test-multi-account.yaml@main" + with: + foundry-fuzz-runs: 5000 + foundry-profile: "test" + match-path: "test/**/*.sol" + foundry-verbosity: 3 + foundry-gas-limit: "18446744073709551615" + foundry-memory-limit: 2147483648 + secrets: + MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} + TESTNET_RPC_URL: ${{ secrets.TESTNET_RPC_URL }} diff --git a/typescript/packages/account-modules/lib/modulekit/.github/workflows/dependency.yml b/typescript/packages/account-modules/lib/modulekit/.github/workflows/dependency.yml new file mode 100644 index 0000000..992e855 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/.github/workflows/dependency.yml @@ -0,0 +1,88 @@ +name: Check Dependency Installation of ModuleKit + +on: + workflow_dispatch: + push: + branches: + - "main" + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1.2.0 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.0.6 + + - name: Pack the package + id: npm-pack + run: | + PACKAGE_NAME=$(npm pack) + echo "package=$PACKAGE_NAME" >> $GITHUB_ENV + + - name: Run npm test + run: | + mkdir test-npm-install + cd test-npm-install + npm init -y + npm install "../${{ env.package }}" + mkdir -p src + echo 'import "modulekit/ModuleKit.sol";' > src/TestImport.sol + echo '[profile.default] + evm_version = "cancun" + src = "src" + out = "out" + libs = ["node_modules"]' > foundry.toml + cp node_modules/@rhinestone/modulekit/remappings.txt remappings.txt + forge build + + - name: Run pnpm test + run: | + mkdir test-pnpm-install + cd test-pnpm-install + pnpm init + pnpm install "../${{ env.package }}" --shamefully-hoist + mkdir -p src + echo 'import "modulekit/ModuleKit.sol";' > src/TestImport.sol + echo '[profile.default] + evm_version = "cancun" + src = "src" + out = "out" + libs = ["node_modules"]' > foundry.toml + cp node_modules/@rhinestone/modulekit/remappings.txt remappings.txt + forge build + + - name: Run via-ir test + run: | + mkdir test-via-ir + cd test-via-ir + pnpm init + pnpm install "../${{ env.package }}" --shamefully-hoist + mkdir -p src + echo 'import "modulekit/ModuleKit.sol";' > src/TestImport.sol + echo '[profile.default] + evm_version = "cancun" + src = "src" + out = "out" + libs = ["node_modules"]' > foundry.toml + cp node_modules/@rhinestone/modulekit/remappings.txt remappings.txt + forge build --via-ir + + - name: Clean up + run: | + rm "${{ env.package }}" + rm -rf test-npm-install + rm -rf test-pnpm-install diff --git a/typescript/packages/account-modules/lib/modulekit/.gitignore b/typescript/packages/account-modules/lib/modulekit/.gitignore new file mode 100644 index 0000000..dad627c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/.gitignore @@ -0,0 +1,19 @@ +# Compiler files +cache/ +out/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +packages/modulekit/gas_calculations/*.json + + +# Dotenv file +.env +node_modules + +gas_calculations/**.json + +.DS_Store \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/modulekit/.npmrc b/typescript/packages/account-modules/lib/modulekit/.npmrc new file mode 100644 index 0000000..bf2e764 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/.npmrc @@ -0,0 +1 @@ +shamefully-hoist=true diff --git a/typescript/packages/account-modules/lib/modulekit/.solhint.json b/typescript/packages/account-modules/lib/modulekit/.solhint.json new file mode 100644 index 0000000..e6b6dbb --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/.solhint.json @@ -0,0 +1,19 @@ +{ + "extends": "solhint:recommended", + "rules": { + "avoid-low-level-calls": "off", + "code-complexity": ["error", 11], + "compiler-version": ["error", ">=0.8.0"], + "contract-name-camelcase": "off", + "const-name-snakecase": "off", + "func-name-mixedcase": "off", + "func-visibility": ["error", { "ignoreConstructors": true }], + "max-line-length": ["error", 123], + "named-parameters-mapping": "warn", + "no-empty-blocks": "off", + "not-rely-on-time": "off", + "one-contract-per-file": "off", + "var-name-mixedcase": "off", + "no-global-import": "off" + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/.solhintignore b/typescript/packages/account-modules/lib/modulekit/.solhintignore new file mode 100644 index 0000000..2a7a947 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/.solhintignore @@ -0,0 +1,5 @@ +node_modules/ +lib/ +src/integrations/interfaces/ +src/core/Licensing/ +test/ diff --git a/typescript/packages/account-modules/lib/modulekit/CHANGELOG.md b/typescript/packages/account-modules/lib/modulekit/CHANGELOG.md new file mode 100644 index 0000000..da13102 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/CHANGELOG.md @@ -0,0 +1,186 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Common Changelog](https://common-changelog.org/). + +[0.4.6]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.4.6 +[0.4.5]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.4.5 +[0.4.4]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.4.4 +[0.4.3]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.4.3 +[0.4.2]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.4.2 +[0.4.1]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.4.1 +[0.4.0]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.4.0 +[0.3.7]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.7 +[0.3.6]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.6 +[0.3.5]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.5 +[0.3.4]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.4 +[0.3.3]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.3 +[0.3.2]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.2 +[0.3.1]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.1 +[0.3.0]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.0 +[0.2.0]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.2.0 +[0.1.0]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.1.0 + +## [0.4.5] - 04-06-2024 + +### Fixed + +- Bugs in uninstall module functions + +## [0.4.4] - 04-06-2024 + +### Fixed + +- Specify correct Kernel version +- Dependency based CI + +## [0.4.3] - 30-05-2024 + +### Changed + +- Refactored multi-account handling +- Clean up compiler warnings and linting issues + +### Added + +- Kernel v3 support +- Factory base for accounts to use the Module Registry + +## [0.4.2] - 24-05-2024 + +### Fixed + +- Incorrectly parsing the account salt for call traces + +## [0.4.1] - 24-05-2024 + +### Changed + +- Integrated `Safe7579Launchpad` +- Cleaned up and standardized multi-account logic +- Removed redundant components + +### Added + +- Account factory template to guide integration of new accounts +- Multi-account ci +- Dependency installation ci + +## [0.4.0] - 21-05-2024 + +### Changed + +- `instance.expect4337Revert` now catches reverts in both validation and execution +- Gas calculations are now split by `_` on every thousand +- General restructuring of the codebase and split into multiple repositories + - Moved module bases and mocks to `@rhinestone/module-bases` + - Moved core modules to `@rhinestone/core-modules` + - Moved the Safe ERC-7579 adapter to `@rhinestone/safe7579` + +### Added + +- ERC-7484 support with interface, mock registry and registry adapter base +- Support for stateless validators +- Under-the-hood support for multi-hooks +- Base module for scheduling-based executors + +### Fixed + +- Bugs related to installation and uninstallation calldata +- Various other bugs + +## [0.3.7] - 09-03-2024 + +### Changed + +- Updated Registry Deployer + +## [0.3.6] - 09-03-2024 + +### Changed + +- Updated Registry Deployer + +## [0.3.5] - 09-03-2024 + +### Changed + +- Updated Registry Deployer + +## [0.3.4] - 05-03-2024 + +### Changed + +- Updated ERC-7579 reference implementation dependency to latest +- Simplified remappings +- Updated examples and tests + +## [0.3.3] - 29-02-2024 + +### Changed + +- Various bug fixes +- Updated ERC-7579 reference implementation dependency to latest + +## [0.3.2] - 28-02-2024 + +### Changed + +- Various bug fixes and improvements + +## [0.3.1] - 23-02-2024 + +### Changed + +- File structure: + - `packages` now includes the core components + - `examples` now includes the example modules + - `accounts` includes the account integrations (the ERC-7579 reference implementation is currently inside the `packages/modulekit` package) +- Support for the latest version of ERC-7579 +- Entrypoint address is now the official v0.7 EntryPoint address + +### Added + +- Module Examples are now in the `examples` folder + +## [0.3.0] - 01-02-2024 + +### Changed + +- Native ERC-7579 support +- Improved Folder structure +- Testing interface: + - `RhinestoneAccount` -> `AccountInstance` + - `install`, `uininstall` and `isInstalled` functions for module types have been collapsed into `installModule`, `uninstallModule` and `isModuleInstalled` respectively +- Safe suppport now via a Safe ERC7579 module (still experimental) + +### Added + +- Hooks and Fallbacks: `ERC7579HookBase` and `ERC7579FallbackBase` +- Module Bases +- Gas measurement helper: `instance.log4337Gas("identifier")` and `GAS=true forge test` +- ERC4337 rule validation support in Foundry: `SIMULATE=true forge test` + +### Removed + +- Unused components + +## [0.2.0] - 17-10-2023 + +### Changed + +- Folder structure for better readability +- Ported Rhinestone Manager to Singleton + +### Added + +- Biconomy account integration test helper +- Conditional Execution Manager +- DeFi integrations and actions +- Fallback handler + +### Removed + +- Recovery flow in Validator interface +- Various dependencies diff --git a/typescript/packages/account-modules/lib/modulekit/README.md b/typescript/packages/account-modules/lib/modulekit/README.md new file mode 100644 index 0000000..66510c3 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/README.md @@ -0,0 +1,137 @@ +# ModuleKit + +**A development kit for building and testing smart account modules** + +ModuleKit allows you to: + +- **Easily build smart account modules** with interfaces for: + - Validators + - Executors + - Hooks +- **Unit test** your modules using a dedicated helper library +- **Integration test** your modules using different modular ERC-4337 accounts and a helper library that abstracts away the complexity + +In-depth documentation is available at [docs.rhinestone.wtf](https://docs.rhinestone.wtf/modulekit/). + +> The ModuleKit is in active development and is subject to breaking changes. If you spot a bug, please take out an issue and we will fix it as soon as we can. + +## Using the ModuleKit + +### Installation + +#### Using our template + +Use the [module-template](https://github.com/rhinestonewtf/module-template) to create a new repo and install the dependencies: + +```bash +pnpm install +``` + +#### Using git submodules + +```bash +forge install rhinestonewtf/modulekit +cd lib/modulekit +pnpm install +``` + +#### Using a package manager + +```bash +pnpm install @rhinestone/modulekit --shamefully-hoist +cp node_modules/@rhinestone/modulekit/remappings.txt remappings.txt +``` + +### Usage + +The ModuleKit can be used to **build**, **test** and **deploy** smart account modules. The full documentation is available at [docs.rhinestone.wtf](https://docs.rhinestone.wtf/modulekit/), but the following aims to provide a quick overview. + +### Building modules + +Import Module bases from `modulekit/Modules.sol`. The core bases include: + +- `ERC7579ValidatorBase`: A base for building validators +- `ERC7579ExecutorBase`: A base for building executors +- `ERC7579HookBase`: A base for building hooks +- `ERC7579HookDestruct`: A base for building hooks with destructured calldata (e.g. `onExecute` or `onInstallModule`) +- `ERC7579FallbackBase`: A base for building fallbacks + +We also provide more advanced bases like: + +- `SchedulingBase`: A base for building schedule-based executors +- `ERC7484RegistryAdapter`: A base for querying the Module Registry + +### Testing modules + +The ModuleKit provides an integration test suite for testing your modules across different modular accounts. To use the test suite, inherit from `RhinestoneModuleKit` and create an account instance using `makeAccountInstance(accountName)`. To learn more about using this instance, visit the documentation for our [integration test suite](https://docs.rhinestone.wtf/modulekit/test/integration). + +You can then run the tests using the following commands: + +```bash +forge test +``` + +Using a different account type (one of `SAFE` and `KERNEL`): + +```bash +ACCOUNT_TYPE=SAFE forge test +``` + +To validate the ERC-4337 rules: + +```bash +SIMULATE=true forge test +``` + +To calculate gas consumption of modules using `instance.log4337Gas("identifier")`: + +```bash +GAS=true forge test +``` + +### Deploying modules + +To deploy modules using the [Module Registry](https://github.com/rhinestonewtf/registry/), you can use the `RegistryDeployer` in a foundry script. You can then deploy your module using the following command: + +```solidity +address module = deployModule({ + code: bytecode, + deployParams: deployParams, + salt: bytes32(0), + data: additionalData +}); +``` + +## Module Examples + +For module examples, check out our [core modules](https://github.com/rhinestonewtf/core-modules/) or our [experimental modules](https://github.com/rhinestonewtf/experimental-modules/) and for module inspiration see our [module idea list](https://rhinestone.notion.site/Module-ideas-for-product-inspo-338100a2c99540f490472b8aa839da11). For general examples, check out the [awesome modular accounts repo](https://github.com/rhinestonewtf/awesome-modular-accounts). + +## Using this repo + +To install dependencies, run: + +```bash +pnpm install +``` + +To build the project, run: + +```bash +pnpm build +``` + +To run tests, run: + +```bash +pnpm test +``` + +To run the linter, run: + +```bash +pnpm lint:sol +``` + +## Contributing + +For feature or change requests, feel free to open a PR, start a discussion or get in touch with us. diff --git a/typescript/packages/account-modules/lib/modulekit/docs/Accounts.md b/typescript/packages/account-modules/lib/modulekit/docs/Accounts.md new file mode 100644 index 0000000..ece9fbd --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/docs/Accounts.md @@ -0,0 +1,45 @@ +# Accounts + +ModuleKit currently supports the following accounts: + +- [ERC-7579 Reference Implementation](https://github.com/erc7579/erc7579-implementation) +- [Safe](https://github.com/safe-global/safe-smart-account) via [Safe7579](https://github.com/rhinestonewtf/safe7579) +- [Kernel](https://github.com/zerodevapp/kernel) + +To use different accounts, a developer can simply change the account on which their tests are run (the default is the ERC-7579 Reference Implementation). To do this, run: + +```bash +ACCOUNT_TYPE=... pnpm test +``` + +where the options are: + +- `DEFAULT`: The ERC-7579 Reference Implementation (note: this is equivalent to emitting the `ACCOUNT_TYPE` environment variable) +- `SAFE`: The Safe account +- `KERNEL`: The Kernel account + +## Differences + +While ModuleKit aims to abstract as much about the accounts away from the developer as possible, there are some differences between the accounts that are important to note. Further, the ModuleKit uses these accounts in a way that might not allow the developer to make use of all features that an account has or might be using a flow different from what will be used in production. To ensure that you benefit from the abstraction of these differences, use the ModuleKit provided helper functions, through the `ModuleKitHelpers` library, rather than creating these integration flows from scratch. This document is aimed at giving an overview of these differences. + +### ERC-7579 Reference Implementation + +The ERC-7579 Reference Implementation is a simple implementation of the ERC-7579 standard. It is fairly minimal and unopinionated and hence the ModuleKit uses it as the default account. It also does not provide any further features beyond what is required by the standard, so the ModuleKit uses all of its' features. + +### Safe + +The Safe7579 is an adapter to Safe accounts that allows them to become compatible with the standard. Concretely, this means that it will be installed as a fallback handler on the Safe. The Safe7579 is also fairly minimal, but there are some key differences to the ERC-7579 Reference Implementation: + +- The Safe7579 does not have access to the `msg.value` sent to the account. +- The Safe7579 stores the account config (ie installed modules) in the adapter itself rather than in the account. +- The Safe7579 has both global hooks that get called on every execution and signature specific hooks that get called based on the function signature of the target. +- The Safe7579 should be used with its' launchpad to bootstrap the Safe. This means that the first UserOperation will be sent to the `setUp` function, however this is abstracted away from the developer in the ModuleKit. + +### Kernel + +The Kernel is a more complex account that has a lot of unique features and design choices. The ModuleKit does not use all of these features and instead uses only those features that are shared by other accounts. The Kernel has the following differences: + +- It supports policies and signers, which are new module types that other accounts do not (yet) support. +- Hooks are related to both validators and executors where each of these has an associated hook. The ModuleKit uses a multiplexer as the hook for each of these so that global hooks can be emulated on the Kernel. Note, that this might differ from a production setup. +- Validators need to be assigned function selectors that they are allowed to validate. The ModuleKit abstracts this away from the developer and allows any validator to sign any UserOperation with any calldata. +- Kernel requires non-root validators with hooks to use `executeUserOp`. Hence, almost all transactions will use this function rather than the direct entrypoint into the account. diff --git a/typescript/packages/account-modules/lib/modulekit/foundry.toml b/typescript/packages/account-modules/lib/modulekit/foundry.toml new file mode 100644 index 0000000..a6c6894 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/foundry.toml @@ -0,0 +1,27 @@ +[profile.default] +solc_version = "0.8.25" +evm_version = "cancun" +src = "src" +out = "out" +script = "script" +libs = ["node_modules"] +fs_permissions = [{ access = "read", path = "out-optimized" }, { access = "read-write", path = "gas_calculations" }] +allow_paths = ["*", "/"] +ignored_warnings_from = ["node_modules", "src/integrations"] +gas_limit = "18446744073709551615" +memory_limit = 2147483648 +verbosity = 3 + +[rpc_endpoints] +mainnet = "${MAINNET_RPC_URL}" +testnet = "${TESTNET_RPC_URL}" + +[fmt] +bracket_spacing = true +int_types = "long" +line_length = 100 +multiline_func_header = "all" +number_underscore = "thousands" +quote_style = "double" +tab_width = 4 +wrap_comments = true diff --git a/typescript/packages/account-modules/lib/modulekit/gas_calculations/.gitkeep b/typescript/packages/account-modules/lib/modulekit/gas_calculations/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/typescript/packages/account-modules/lib/modulekit/octanerc.json b/typescript/packages/account-modules/lib/modulekit/octanerc.json new file mode 100644 index 0000000..bafdf8e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/octanerc.json @@ -0,0 +1,3 @@ +{ + "pathsToAnalyze": ["**/src/integrations/.*", "**/src/module-bases/.*"] +} diff --git a/typescript/packages/account-modules/lib/modulekit/package.json b/typescript/packages/account-modules/lib/modulekit/package.json new file mode 100644 index 0000000..69614a9 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/package.json @@ -0,0 +1,66 @@ +{ + "name": "@rhinestone/modulekit", + "version": "0.5.9", + "description": "A development kit for building and testing smart account modules.", + "license": "GPL-3.0", + "author": { + "name": "Rhinestone", + "url": "https://rhinestone.wtf" + }, + "scripts": { + "build": "forge build", + "fmt": "forge fmt", + "fmt:check": "forge fmt --check", + "build:optimized": "FOUNDRY_PROFILE=optimized forge build", + "build:smt": "FOUNDRY_PROFILE=smt forge build", + "clean": "rm -rf artifacts broadcast cache docs out out-optimized out-svg", + "gas:report": "forge test --gas-report --mp \"./test/integration/**/*.sol\" --nmt \"test(Fuzz)?_RevertWhen_\\w{1,}?\"", + "gas:snapshot": "forge snapshot --mp \"./test/integration/**/*.sol\" --nmt \"test(Fuzz)?_RevertWhen_\\w{1,}?\"", + "gas:snapshot:optimized": "pnpm run build:optimized && FOUNDRY_PROFILE=test-optimized forge snapshot --mp \"./test/integration/**/*.sol\" --nmt \"test(Fork)?(Fuzz)?_RevertWhen_\\w{1,}?\"", + "lint:sol": "forge fmt --check && pnpm solhint \"{script,src,test}/**/*.sol\"", + "test": "forge test", + "test:lite": "FOUNDRY_PROFILE=lite forge test", + "test:via-ir": "forge test --via-ir", + "test:optimized": "pnpm run build:optimized && FOUNDRY_PROFILE=test-optimized forge test", + "test:accounts": "forge test && ACCOUNT_TYPE=SAFE forge test && ACCOUNT_TYPE=KERNEL forge test && ACCOUNT_TYPE=NEXUS forge test", + "changeset": "changeset", + "changeset:release": "pnpm build && changeset publish", + "changeset:version": "changeset version && pnpm install --lockfile-only" + }, + "dependencies": { + "@ERC4337/account-abstraction": "github:kopy-kat/account-abstraction#develop", + "@ERC4337/account-abstraction-v0.6": "github:eth-infinitism/account-abstraction#v0.6.0", + "@prb/math": "^4.1.0", + "@rhinestone/erc4337-validation": "^0.0.5", + "@rhinestone/sentinellist": "github:rhinestonewtf/sentinellist", + "ds-test": "github:dapphub/ds-test", + "excessively-safe-call": "github:nomad-xyz/ExcessivelySafeCall", + "forge-std": "github:foundry-rs/forge-std", + "solady": "github:vectorized/solady", + "solarray": "github:sablier-labs/solarray", + "solhint": "^5.0.5" + }, + "devDependencies": { + "@changesets/cli": "^2.27.12" + }, + "files": [ + "src", + "foundry.toml", + "remappings.txt" + ], + "homepage": "https://docs.rhinestone.wtf/modulekit", + "repository": { + "type": "git", + "url": "git+https://github.com/rhinestonewtf/modulekit.git" + }, + "bugs": { + "url": "https://github.com/rhinestonewtf/modulekit/issues" + }, + "keywords": [ + "account abstraction", + "smart account modules" + ], + "publishConfig": { + "access": "public" + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/pnpm-lock.yaml b/typescript/packages/account-modules/lib/modulekit/pnpm-lock.yaml new file mode 100644 index 0000000..6c78dbc --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/pnpm-lock.yaml @@ -0,0 +1,4803 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@ERC4337/account-abstraction': + specifier: github:kopy-kat/account-abstraction#develop + version: accountabstraction@https://codeload.github.com/kopy-kat/account-abstraction/tar.gz/c5887153fbfe3ed09b2637cac39873f96d676f38(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)) + '@ERC4337/account-abstraction-v0.6': + specifier: github:eth-infinitism/account-abstraction#v0.6.0 + version: accountabstraction@https://codeload.github.com/eth-infinitism/account-abstraction/tar.gz/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)) + '@prb/math': + specifier: ^4.1.0 + version: 4.1.0 + '@rhinestone/erc4337-validation': + specifier: ^0.0.5 + version: 0.0.5(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)) + '@rhinestone/sentinellist': + specifier: github:rhinestonewtf/sentinellist + version: https://codeload.github.com/rhinestonewtf/sentinellist/tar.gz/e722c5cc68c570d535bc3c9f85b3ce90cdc38807 + ds-test: + specifier: github:dapphub/ds-test + version: https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0 + excessively-safe-call: + specifier: github:nomad-xyz/ExcessivelySafeCall + version: '@nomad-xyz/excessively-safe-call@https://codeload.github.com/nomad-xyz/ExcessivelySafeCall/tar.gz/81cd99ce3e69117d665d7601c330ea03b97acce0' + forge-std: + specifier: github:foundry-rs/forge-std + version: https://codeload.github.com/foundry-rs/forge-std/tar.gz/3b20d60d14b343ee4f908cb8079495c07f5e8981 + solady: + specifier: github:vectorized/solady + version: https://codeload.github.com/vectorized/solady/tar.gz/59f28399b7e9202bc6145b082bf7ff025b8b1ddc + solarray: + specifier: github:sablier-labs/solarray + version: https://codeload.github.com/sablier-labs/solarray/tar.gz/6bf10cb34cdace52a3ba5fe437e78cc82df92684 + solhint: + specifier: ^5.0.5 + version: 5.0.5(typescript@4.9.5) + devDependencies: + '@changesets/cli': + specifier: ^2.27.12 + version: 2.27.12 + +packages: + + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + '@babel/runtime@7.26.7': + resolution: {integrity: sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==} + engines: {node: '>=6.9.0'} + + '@changesets/apply-release-plan@7.0.8': + resolution: {integrity: sha512-qjMUj4DYQ1Z6qHawsn7S71SujrExJ+nceyKKyI9iB+M5p9lCL55afuEd6uLBPRpLGWQwkwvWegDHtwHJb1UjpA==} + + '@changesets/assemble-release-plan@6.0.5': + resolution: {integrity: sha512-IgvBWLNKZd6k4t72MBTBK3nkygi0j3t3zdC1zrfusYo0KpdsvnDjrMM9vPnTCLCMlfNs55jRL4gIMybxa64FCQ==} + + '@changesets/changelog-git@0.2.0': + resolution: {integrity: sha512-bHOx97iFI4OClIT35Lok3sJAwM31VbUM++gnMBV16fdbtBhgYu4dxsphBF/0AZZsyAHMrnM0yFcj5gZM1py6uQ==} + + '@changesets/cli@2.27.12': + resolution: {integrity: sha512-9o3fOfHYOvBnyEn0mcahB7wzaA3P4bGJf8PNqGit5PKaMEFdsRixik+txkrJWd2VX+O6wRFXpxQL8j/1ANKE9g==} + hasBin: true + + '@changesets/config@3.0.5': + resolution: {integrity: sha512-QyXLSSd10GquX7hY0Mt4yQFMEeqnO5z/XLpbIr4PAkNNoQNKwDyiSrx4yd749WddusH1v3OSiA0NRAYmH/APpQ==} + + '@changesets/errors@0.2.0': + resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} + + '@changesets/get-dependents-graph@2.1.2': + resolution: {integrity: sha512-sgcHRkiBY9i4zWYBwlVyAjEM9sAzs4wYVwJUdnbDLnVG3QwAaia1Mk5P8M7kraTOZN+vBET7n8KyB0YXCbFRLQ==} + + '@changesets/get-release-plan@4.0.6': + resolution: {integrity: sha512-FHRwBkY7Eili04Y5YMOZb0ezQzKikTka4wL753vfUA5COSebt7KThqiuCN9BewE4/qFGgF/5t3AuzXx1/UAY4w==} + + '@changesets/get-version-range-type@0.4.0': + resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} + + '@changesets/git@3.0.2': + resolution: {integrity: sha512-r1/Kju9Y8OxRRdvna+nxpQIsMsRQn9dhhAZt94FLDeu0Hij2hnOozW8iqnHBgvu+KdnJppCveQwK4odwfw/aWQ==} + + '@changesets/logger@0.1.1': + resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} + + '@changesets/parse@0.4.0': + resolution: {integrity: sha512-TS/9KG2CdGXS27S+QxbZXgr8uPsP4yNJYb4BC2/NeFUj80Rni3TeD2qwWmabymxmrLo7JEsytXH1FbpKTbvivw==} + + '@changesets/pre@2.0.1': + resolution: {integrity: sha512-vvBJ/If4jKM4tPz9JdY2kGOgWmCowUYOi5Ycv8dyLnEE8FgpYYUo1mgJZxcdtGGP3aG8rAQulGLyyXGSLkIMTQ==} + + '@changesets/read@0.6.2': + resolution: {integrity: sha512-wjfQpJvryY3zD61p8jR87mJdyx2FIhEcdXhKUqkja87toMrP/3jtg/Yg29upN+N4Ckf525/uvV7a4tzBlpk6gg==} + + '@changesets/should-skip-package@0.1.1': + resolution: {integrity: sha512-H9LjLbF6mMHLtJIc/eHR9Na+MifJ3VxtgP/Y+XLn4BF7tDTEN1HNYtH6QMcjP1uxp9sjaFYmW8xqloaCi/ckTg==} + + '@changesets/types@4.1.0': + resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} + + '@changesets/types@6.0.0': + resolution: {integrity: sha512-b1UkfNulgKoWfqyHtzKS5fOZYSJO+77adgL7DLRDr+/7jhChN+QcHnbjiQVOz/U+Ts3PGNySq7diAItzDgugfQ==} + + '@changesets/write@0.3.2': + resolution: {integrity: sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw==} + + '@ethereumjs/rlp@4.0.1': + resolution: {integrity: sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==} + engines: {node: '>=14'} + hasBin: true + + '@ethereumjs/util@8.1.0': + resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} + engines: {node: '>=14'} + + '@ethersproject/abi@5.7.0': + resolution: {integrity: sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==} + + '@ethersproject/abstract-provider@5.7.0': + resolution: {integrity: sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==} + + '@ethersproject/abstract-signer@5.7.0': + resolution: {integrity: sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==} + + '@ethersproject/address@5.7.0': + resolution: {integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==} + + '@ethersproject/base64@5.7.0': + resolution: {integrity: sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==} + + '@ethersproject/basex@5.7.0': + resolution: {integrity: sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==} + + '@ethersproject/bignumber@5.7.0': + resolution: {integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==} + + '@ethersproject/bytes@5.7.0': + resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==} + + '@ethersproject/constants@5.7.0': + resolution: {integrity: sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==} + + '@ethersproject/contracts@5.7.0': + resolution: {integrity: sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==} + + '@ethersproject/hash@5.7.0': + resolution: {integrity: sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==} + + '@ethersproject/hdnode@5.7.0': + resolution: {integrity: sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==} + + '@ethersproject/json-wallets@5.7.0': + resolution: {integrity: sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==} + + '@ethersproject/keccak256@5.7.0': + resolution: {integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==} + + '@ethersproject/logger@5.7.0': + resolution: {integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==} + + '@ethersproject/networks@5.7.1': + resolution: {integrity: sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==} + + '@ethersproject/pbkdf2@5.7.0': + resolution: {integrity: sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==} + + '@ethersproject/properties@5.7.0': + resolution: {integrity: sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==} + + '@ethersproject/providers@5.7.2': + resolution: {integrity: sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==} + + '@ethersproject/random@5.7.0': + resolution: {integrity: sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==} + + '@ethersproject/rlp@5.7.0': + resolution: {integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==} + + '@ethersproject/sha2@5.7.0': + resolution: {integrity: sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==} + + '@ethersproject/signing-key@5.7.0': + resolution: {integrity: sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==} + + '@ethersproject/solidity@5.7.0': + resolution: {integrity: sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==} + + '@ethersproject/strings@5.7.0': + resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==} + + '@ethersproject/transactions@5.7.0': + resolution: {integrity: sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==} + + '@ethersproject/units@5.7.0': + resolution: {integrity: sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==} + + '@ethersproject/wallet@5.7.0': + resolution: {integrity: sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==} + + '@ethersproject/web@5.7.1': + resolution: {integrity: sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==} + + '@ethersproject/wordlists@5.7.0': + resolution: {integrity: sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==} + + '@fastify/busboy@2.1.1': + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} + engines: {node: '>=14'} + + '@gnosis.pm/safe-contracts@1.3.0': + resolution: {integrity: sha512-1p+1HwGvxGUVzVkFjNzglwHrLNA67U/axP0Ct85FzzH8yhGJb4t9jDjPYocVMzLorDoWAfKicGy1akPY9jXRVw==} + peerDependencies: + ethers: ^5.1.4 + + '@manypkg/find-root@1.1.0': + resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} + + '@manypkg/get-packages@1.1.3': + resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + + '@metamask/eth-sig-util@4.0.1': + resolution: {integrity: sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==} + engines: {node: '>=12.0.0'} + + '@noble/curves@1.4.2': + resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} + + '@noble/hashes@1.2.0': + resolution: {integrity: sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==} + + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + + '@noble/hashes@1.7.1': + resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==} + engines: {node: ^14.21.3 || >=16} + + '@noble/secp256k1@1.7.1': + resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nomad-xyz/excessively-safe-call@https://codeload.github.com/nomad-xyz/ExcessivelySafeCall/tar.gz/81cd99ce3e69117d665d7601c330ea03b97acce0': + resolution: {tarball: https://codeload.github.com/nomad-xyz/ExcessivelySafeCall/tar.gz/81cd99ce3e69117d665d7601c330ea03b97acce0} + version: 0.0.1-rc.1 + + '@nomicfoundation/edr-darwin-arm64@0.6.5': + resolution: {integrity: sha512-A9zCCbbNxBpLgjS1kEJSpqxIvGGAX4cYbpDYCU2f3jVqOwaZ/NU761y1SvuCRVpOwhoCXqByN9b7HPpHi0L4hw==} + engines: {node: '>= 18'} + + '@nomicfoundation/edr-darwin-x64@0.6.5': + resolution: {integrity: sha512-x3zBY/v3R0modR5CzlL6qMfFMdgwd6oHrWpTkuuXnPFOX8SU31qq87/230f4szM+ukGK8Hi+mNq7Ro2VF4Fj+w==} + engines: {node: '>= 18'} + + '@nomicfoundation/edr-linux-arm64-gnu@0.6.5': + resolution: {integrity: sha512-HGpB8f1h8ogqPHTyUpyPRKZxUk2lu061g97dOQ/W4CxevI0s/qiw5DB3U3smLvSnBHKOzYS1jkxlMeGN01ky7A==} + engines: {node: '>= 18'} + + '@nomicfoundation/edr-linux-arm64-musl@0.6.5': + resolution: {integrity: sha512-ESvJM5Y9XC03fZg9KaQg3Hl+mbx7dsSkTIAndoJS7X2SyakpL9KZpOSYrDk135o8s9P9lYJdPOyiq+Sh+XoCbQ==} + engines: {node: '>= 18'} + + '@nomicfoundation/edr-linux-x64-gnu@0.6.5': + resolution: {integrity: sha512-HCM1usyAR1Ew6RYf5AkMYGvHBy64cPA5NMbaeY72r0mpKaH3txiMyydcHibByOGdQ8iFLWpyUdpl1egotw+Tgg==} + engines: {node: '>= 18'} + + '@nomicfoundation/edr-linux-x64-musl@0.6.5': + resolution: {integrity: sha512-nB2uFRyczhAvWUH7NjCsIO6rHnQrof3xcCe6Mpmnzfl2PYcGyxN7iO4ZMmRcQS7R1Y670VH6+8ZBiRn8k43m7A==} + engines: {node: '>= 18'} + + '@nomicfoundation/edr-win32-x64-msvc@0.6.5': + resolution: {integrity: sha512-B9QD/4DSSCFtWicO8A3BrsnitO1FPv7axB62wq5Q+qeJ50yJlTmyeGY3cw62gWItdvy2mh3fRM6L1LpnHiB77A==} + engines: {node: '>= 18'} + + '@nomicfoundation/edr@0.6.5': + resolution: {integrity: sha512-tAqMslLP+/2b2sZP4qe9AuGxG3OkQ5gGgHE4isUuq6dUVjwCRPFhAOhpdFl+OjY5P3yEv3hmq9HjUGRa2VNjng==} + engines: {node: '>= 18'} + + '@nomicfoundation/ethereumjs-common@4.0.4': + resolution: {integrity: sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==} + + '@nomicfoundation/ethereumjs-rlp@5.0.4': + resolution: {integrity: sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==} + engines: {node: '>=18'} + hasBin: true + + '@nomicfoundation/ethereumjs-tx@5.0.4': + resolution: {integrity: sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==} + engines: {node: '>=18'} + peerDependencies: + c-kzg: ^2.1.2 + peerDependenciesMeta: + c-kzg: + optional: true + + '@nomicfoundation/ethereumjs-util@9.0.4': + resolution: {integrity: sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==} + engines: {node: '>=18'} + peerDependencies: + c-kzg: ^2.1.2 + peerDependenciesMeta: + c-kzg: + optional: true + + '@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2': + resolution: {integrity: sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==} + engines: {node: '>= 12'} + + '@nomicfoundation/solidity-analyzer-darwin-x64@0.1.2': + resolution: {integrity: sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==} + engines: {node: '>= 12'} + + '@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.2': + resolution: {integrity: sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==} + engines: {node: '>= 12'} + + '@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.2': + resolution: {integrity: sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==} + engines: {node: '>= 12'} + + '@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.2': + resolution: {integrity: sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==} + engines: {node: '>= 12'} + + '@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.2': + resolution: {integrity: sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==} + engines: {node: '>= 12'} + + '@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.2': + resolution: {integrity: sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==} + engines: {node: '>= 12'} + + '@nomicfoundation/solidity-analyzer@0.1.2': + resolution: {integrity: sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==} + engines: {node: '>= 12'} + + '@nomiclabs/hardhat-etherscan@2.1.8': + resolution: {integrity: sha512-0+rj0SsZotVOcTLyDOxnOc3Gulo8upo0rsw/h+gBPcmtj91YqYJNhdARHoBxOhhE8z+5IUQPx+Dii04lXT14PA==} + deprecated: The @nomiclabs/hardhat-etherscan package is deprecated, please use @nomicfoundation/hardhat-verify instead + peerDependencies: + hardhat: ^2.0.4 + + '@openzeppelin/contracts@4.9.6': + resolution: {integrity: sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA==} + + '@openzeppelin/contracts@5.0.1': + resolution: {integrity: sha512-yQJaT5HDp9hYOOp4jTYxMsR02gdFZFXhewX5HW9Jo4fsqSVqqyIO/xTHdWDaKX5a3pv1txmf076Lziz+sO7L1w==} + + '@openzeppelin/contracts@5.2.0': + resolution: {integrity: sha512-bxjNie5z89W1Ea0NZLZluFh8PrFNn9DH8DQlujEok2yjsOlraUPKID5p1Wk3qdNbf6XkQ1Os2RvfiHrrXLHWKA==} + + '@pnpm/config.env-replace@1.1.0': + resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} + engines: {node: '>=12.22.0'} + + '@pnpm/network.ca-file@1.0.2': + resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} + engines: {node: '>=12.22.0'} + + '@pnpm/npm-conf@2.3.1': + resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==} + engines: {node: '>=12'} + + '@prb/math@4.1.0': + resolution: {integrity: sha512-ef5Xrlh3BeX4xT5/Wi810dpEPq2bYPndRxgFIaKSU1F/Op/s8af03kyom+mfU7gEpvfIZ46xu8W0duiHplbBMg==} + + '@rhinestone/erc4337-validation@0.0.5': + resolution: {integrity: sha512-+WzDOn7Cp7DGw4oLsnWtcfqMkLTJAfC3qdTCYcZdDuBuSNST/E+7Gsau+5Uu97IYgTc7suTo+5OiP5k+E2q79A==} + + '@rhinestone/sentinellist@https://codeload.github.com/rhinestonewtf/sentinellist/tar.gz/e722c5cc68c570d535bc3c9f85b3ce90cdc38807': + resolution: {tarball: https://codeload.github.com/rhinestonewtf/sentinellist/tar.gz/e722c5cc68c570d535bc3c9f85b3ce90cdc38807} + version: 1.0.1 + + '@scure/base@1.1.9': + resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==} + + '@scure/bip32@1.1.5': + resolution: {integrity: sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==} + + '@scure/bip32@1.4.0': + resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} + + '@scure/bip39@1.1.1': + resolution: {integrity: sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==} + + '@scure/bip39@1.3.0': + resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} + + '@sentry/core@5.30.0': + resolution: {integrity: sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==} + engines: {node: '>=6'} + + '@sentry/hub@5.30.0': + resolution: {integrity: sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==} + engines: {node: '>=6'} + + '@sentry/minimal@5.30.0': + resolution: {integrity: sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==} + engines: {node: '>=6'} + + '@sentry/node@5.30.0': + resolution: {integrity: sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==} + engines: {node: '>=6'} + + '@sentry/tracing@5.30.0': + resolution: {integrity: sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==} + engines: {node: '>=6'} + + '@sentry/types@5.30.0': + resolution: {integrity: sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==} + engines: {node: '>=6'} + + '@sentry/utils@5.30.0': + resolution: {integrity: sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==} + engines: {node: '>=6'} + + '@sindresorhus/is@5.6.0': + resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} + engines: {node: '>=14.16'} + + '@solidity-parser/parser@0.19.0': + resolution: {integrity: sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==} + + '@szmarczak/http-timer@5.0.1': + resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} + engines: {node: '>=14.16'} + + '@thehubbleproject/bls@0.5.1': + resolution: {integrity: sha512-g5zeMZ8js/yg6MjFoC+pt0eqfCL2jC46yLY1LbKNriyqftB1tE3jpG/FMMDIW3x9/yRg/AgUb8Nluqj15tQs+A==} + + '@typechain/hardhat@2.3.1': + resolution: {integrity: sha512-BQV8OKQi0KAzLXCdsPO0pZBNQQ6ra8A2ucC26uFX/kquRBtJu1yEyWnVSmtr07b5hyRoJRpzUeINLnyqz4/MAw==} + peerDependencies: + hardhat: ^2.0.10 + lodash: ^4.17.15 + typechain: ^5.1.2 + + '@types/bn.js@4.11.6': + resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} + + '@types/bn.js@5.1.6': + resolution: {integrity: sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/glob@7.2.0': + resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} + + '@types/http-cache-semantics@4.0.4': + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + + '@types/lru-cache@5.1.1': + resolution: {integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==} + + '@types/minimatch@5.1.2': + resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} + + '@types/mocha@9.1.1': + resolution: {integrity: sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@12.20.55': + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + + '@types/node@20.17.17': + resolution: {integrity: sha512-/WndGO4kIfMicEQLTi/mDANUu/iVUhT7KboZPdEqqHQ4aTS+3qT3U5gIqWDFV+XouorjfgGqvKILJeHhuQgFYg==} + + '@types/node@22.13.1': + resolution: {integrity: sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==} + + '@types/pbkdf2@3.1.2': + resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} + + '@types/prettier@2.7.3': + resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} + + '@types/qs@6.9.18': + resolution: {integrity: sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==} + + '@types/secp256k1@4.0.6': + resolution: {integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==} + + abbrev@1.0.9: + resolution: {integrity: sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==} + + accountabstraction@https://codeload.github.com/eth-infinitism/account-abstraction/tar.gz/7174d6d845618dbd11cee68eefa715f5263690b6: + resolution: {tarball: https://codeload.github.com/eth-infinitism/account-abstraction/tar.gz/7174d6d845618dbd11cee68eefa715f5263690b6} + version: 0.6.0 + + accountabstraction@https://codeload.github.com/kopy-kat/account-abstraction/tar.gz/c5887153fbfe3ed09b2637cac39873f96d676f38: + resolution: {tarball: https://codeload.github.com/kopy-kat/account-abstraction/tar.gz/c5887153fbfe3ed09b2637cac39873f96d676f38} + version: 0.7.0 + + adm-zip@0.4.16: + resolution: {integrity: sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==} + engines: {node: '>=0.3.0'} + + aes-js@3.0.0: + resolution: {integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==} + + aes-js@3.1.2: + resolution: {integrity: sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==} + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + amdefine@1.0.1: + resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==} + engines: {node: '>=0.4.2'} + + ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + antlr4@4.13.2: + resolution: {integrity: sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg==} + engines: {node: '>=16'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-back@1.0.4: + resolution: {integrity: sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw==} + engines: {node: '>=0.12.0'} + + array-back@2.0.0: + resolution: {integrity: sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==} + engines: {node: '>=4'} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + ast-parents@0.0.1: + resolution: {integrity: sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==} + + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + + async@1.5.2: + resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + + axios@0.21.4: + resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base-x@3.0.10: + resolution: {integrity: sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==} + + bech32@1.1.4: + resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} + + better-path-resolve@1.0.0: + resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} + engines: {node: '>=4'} + + bignumber.js@9.1.2: + resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + blakejs@1.2.1: + resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} + + bn.js@4.11.6: + resolution: {integrity: sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==} + + bn.js@4.12.1: + resolution: {integrity: sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==} + + bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + + boxen@5.1.2: + resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} + engines: {node: '>=10'} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + browser-stdout@1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + + browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + + bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + + bs58check@2.1.2: + resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + cacheable-lookup@7.0.0: + resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} + engines: {node: '>=14.16'} + + cacheable-request@10.2.14: + resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} + engines: {node: '>=14.16'} + + call-bind-apply-helpers@1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} + engines: {node: '>= 0.4'} + + call-bound@1.0.3: + resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + cbor@5.2.0: + resolution: {integrity: sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==} + engines: {node: '>=6.0.0'} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chardet@0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + ci-info@2.0.0: + resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + cipher-base@1.0.6: + resolution: {integrity: sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==} + engines: {node: '>= 0.10'} + + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + + cli-boxes@2.2.1: + resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} + engines: {node: '>=6'} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + command-exists@1.2.9: + resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} + + command-line-args@4.0.7: + resolution: {integrity: sha512-aUdPvQRAyBvQd2n7jXcsMDz68ckBJELXNzBybCHOibUWEg0mWTnaYCSRU8h9R+aNRSvDihJtssSRCiDRpLaezA==} + hasBin: true + + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + + cookie@0.4.2: + resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} + engines: {node: '>= 0.6'} + + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + + create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + death@1.1.0: + resolution: {integrity: sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==} + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + detect-indent@6.1.0: + resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} + engines: {node: '>=8'} + + diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + + difflib@0.2.4: + resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + ds-test@https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0: + resolution: {tarball: https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0} + version: 1.0.0 + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + elliptic@6.5.4: + resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} + + elliptic@6.6.1: + resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + encode-utf8@1.0.3: + resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} + + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escodegen@1.8.1: + resolution: {integrity: sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==} + engines: {node: '>=0.12.0'} + hasBin: true + + esprima@2.7.3: + resolution: {integrity: sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==} + engines: {node: '>=0.10.0'} + hasBin: true + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + estraverse@1.9.3: + resolution: {integrity: sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==} + engines: {node: '>=0.10.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + ethereum-bloom-filters@1.2.0: + resolution: {integrity: sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA==} + + ethereum-cryptography@0.1.3: + resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} + + ethereum-cryptography@1.2.0: + resolution: {integrity: sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==} + + ethereum-cryptography@2.2.1: + resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==} + + ethereumjs-abi@0.6.8: + resolution: {integrity: sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==} + deprecated: This library has been deprecated and usage is discouraged. + + ethereumjs-util@6.2.1: + resolution: {integrity: sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==} + + ethereumjs-util@7.1.5: + resolution: {integrity: sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==} + engines: {node: '>=10.0.0'} + + ethereumjs-wallet@1.0.2: + resolution: {integrity: sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA==} + deprecated: 'New package name format for new versions: @ethereumjs/wallet. Please update.' + + ethers@5.7.2: + resolution: {integrity: sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==} + + ethjs-unit@0.1.6: + resolution: {integrity: sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==} + engines: {node: '>=6.5.0', npm: '>=3'} + + ethjs-util@0.1.6: + resolution: {integrity: sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==} + engines: {node: '>=6.5.0', npm: '>=3'} + + evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + + extendable-error@0.1.7: + resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + + external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-uri@3.0.6: + resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + + fastq@1.19.0: + resolution: {integrity: sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==} + + fdir@6.4.3: + resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-replace@1.0.3: + resolution: {integrity: sha512-KrUnjzDCD9426YnCP56zGYy/eieTnhtK6Vn++j+JJzmlsWWwEkDnsyVF575spT6HJ6Ow9tlbT3TQTDsa+O4UWA==} + engines: {node: '>=4.0.0'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + + fmix@0.1.0: + resolution: {integrity: sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==} + + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/3b20d60d14b343ee4f908cb8079495c07f5e8981: + resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/3b20d60d14b343ee4f908cb8079495c07f5e8981} + version: 1.9.6 + + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/8a225d81aa8e2e013580564588c79abb65eacc9e: + resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/8a225d81aa8e2e013580564588c79abb65eacc9e} + version: 1.9.3 + + form-data-encoder@2.1.4: + resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} + engines: {node: '>= 14.17'} + + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + + fp-ts@1.19.3: + resolution: {integrity: sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.2.7: + resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + ghost-testrpc@0.0.2: + resolution: {integrity: sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==} + hasBin: true + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob@5.0.15: + resolution: {integrity: sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==} + deprecated: Glob versions prior to v9 are no longer supported + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + deprecated: Glob versions prior to v9 are no longer supported + + global-modules@2.0.0: + resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} + engines: {node: '>=6'} + + global-prefix@3.0.0: + resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} + engines: {node: '>=6'} + + globby@10.0.2: + resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==} + engines: {node: '>=8'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + got@12.6.1: + resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==} + engines: {node: '>=14.16'} + + graceful-fs@4.2.10: + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + handlebars@4.7.8: + resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} + engines: {node: '>=0.4.7'} + hasBin: true + + hardhat-deploy-ethers@0.3.0-beta.13: + resolution: {integrity: sha512-PdWVcKB9coqWV1L7JTpfXRCI91Cgwsm7KLmBcwZ8f0COSm1xtABHZTyz3fvF6p42cTnz1VM0QnfDvMFlIRkSNw==} + peerDependencies: + ethers: ^5.0.0 + hardhat: ^2.0.0 + + hardhat-deploy@0.11.45: + resolution: {integrity: sha512-aC8UNaq3JcORnEUIwV945iJuvBwi65tjHVDU3v6mOcqik7WAzHVCJ7cwmkkipsHrWysrB5YvGF1q9S1vIph83w==} + + hardhat@2.22.17: + resolution: {integrity: sha512-tDlI475ccz4d/dajnADUTRc1OJ3H8fpP9sWhXhBPpYsQOg8JHq5xrDimo53UhWPl7KJmAeDCm1bFG74xvpGRpg==} + hasBin: true + peerDependencies: + ts-node: '*' + typescript: '*' + peerDependenciesMeta: + ts-node: + optional: true + typescript: + optional: true + + has-flag@1.0.0: + resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==} + engines: {node: '>=0.10.0'} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hash-base@3.1.0: + resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} + engines: {node: '>=4'} + + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + heap@0.2.7: + resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} + + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + + http-cache-semantics@4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + http2-wrapper@2.2.1: + resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==} + engines: {node: '>=10.19.0'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + human-id@1.0.2: + resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + immutable@4.3.7: + resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imul@1.0.1: + resolution: {integrity: sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA==} + engines: {node: '>=0.10.0'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + interpret@1.4.0: + resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + engines: {node: '>= 0.10'} + + io-ts@1.10.4: + resolution: {integrity: sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hex-prefixed@1.0.0: + resolution: {integrity: sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==} + engines: {node: '>=6.5.0', npm: '>=3'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-obj@2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + + is-subdir@1.2.0: + resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} + engines: {node: '>=4'} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stream-stringify@3.1.6: + resolution: {integrity: sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==} + engines: {node: '>=7.10.1'} + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + jsonschema@1.5.0: + resolution: {integrity: sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==} + + keccak@3.0.4: + resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} + engines: {node: '>=10.0.0'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + latest-version@7.0.0: + resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==} + engines: {node: '>=14.16'} + + levn@0.3.0: + resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} + engines: {node: '>= 0.8.0'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + lowercase-keys@3.0.0: + resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lru_map@0.3.3: + resolution: {integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==} + + match-all@1.2.6: + resolution: {integrity: sha512-0EESkXiTkWzrQQntBu2uzKvLu6vVkUGz40nGPbSZuegcfE5UuSzNjLaIu76zJWuaT/2I3Z/8M06OlUOZLGwLlQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mcl-wasm@1.8.0: + resolution: {integrity: sha512-j6kekpd/i6XLHKgUPLPOqts3EUIw+lOFPdyQ4cqepONZ2R/dtfc3+DnYMJXKXw4JF8c6hfcBZ04gbYWOXurv+Q==} + engines: {node: '>=14.17'} + + md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + + memorystream@0.3.1: + resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} + engines: {node: '>= 0.10.0'} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micro-ftch@0.3.1: + resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + mimic-response@4.0.0: + resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + mnemonist@0.38.5: + resolution: {integrity: sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==} + + mocha@10.8.2: + resolution: {integrity: sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==} + engines: {node: '>= 14.0.0'} + hasBin: true + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + murmur-128@0.2.1: + resolution: {integrity: sha512-WseEgiRkI6aMFBbj8Cg9yBj/y+OdipwVC7zUo3W2W1JAJITwouUOtpqsmGSg67EQmwwSyod7hsVsWY5LsrfQVg==} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + node-addon-api@2.0.2: + resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} + + node-addon-api@5.1.0: + resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} + + node-emoji@1.11.0: + resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + nofilter@1.0.4: + resolution: {integrity: sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==} + engines: {node: '>=8'} + + nopt@3.0.6: + resolution: {integrity: sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==} + hasBin: true + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-url@8.0.1: + resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} + engines: {node: '>=14.16'} + + number-to-bn@1.7.0: + resolution: {integrity: sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==} + engines: {node: '>=6.5.0', npm: '>=3'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + obliterator@2.0.5: + resolution: {integrity: sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.8.3: + resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} + engines: {node: '>= 0.8.0'} + + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + + outdent@0.5.0: + resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + + p-cancelable@3.0.0: + resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} + engines: {node: '>=12.20'} + + p-filter@2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} + engines: {node: '>=8'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-map@2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + + p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json@8.1.1: + resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} + engines: {node: '>=14.16'} + + package-manager-detector@0.2.9: + resolution: {integrity: sha512-+vYvA/Y31l8Zk8dwxHhL3JfTuHPm6tlxM2A3GeQyl7ovYnSp1+mzAxClxaOr0qO1TtPxbQxetI7v5XqKLJZk7Q==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pbkdf2@3.1.2: + resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + engines: {node: '>=0.12'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + prelude-ls@1.1.2: + resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} + engines: {node: '>= 0.8.0'} + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + read-yaml-file@1.1.0: + resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} + engines: {node: '>=6'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + readdirp@4.1.1: + resolution: {integrity: sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==} + engines: {node: '>= 14.18.0'} + + rechoir@0.6.2: + resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} + engines: {node: '>= 0.10'} + + recursive-readdir@2.2.3: + resolution: {integrity: sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==} + engines: {node: '>=6.0.0'} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + registry-auth-token@5.0.3: + resolution: {integrity: sha512-1bpc9IyC+e+CNFRaWyn77tk4xGG4PPUyfakSmA6F6cvUDjrm58dfyJ3II+9yb10EDkHoy1LaPSmHaWLOH3m6HA==} + engines: {node: '>=14'} + + registry-url@6.0.1: + resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} + engines: {node: '>=12'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve@1.1.7: + resolution: {integrity: sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==} + + resolve@1.17.0: + resolution: {integrity: sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==} + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + responselike@3.0.0: + resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} + engines: {node: '>=14.16'} + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + ripemd160@2.0.2: + resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + + rlp@2.2.7: + resolution: {integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sc-istanbul@0.4.6: + resolution: {integrity: sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==} + hasBin: true + + scrypt-js@3.0.1: + resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} + + secp256k1@4.0.4: + resolution: {integrity: sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==} + engines: {node: '>=18.0.0'} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.1: + resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + engines: {node: '>=10'} + hasBin: true + + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + sha.js@2.4.11: + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shelljs@0.8.5: + resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} + engines: {node: '>=4'} + hasBin: true + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + + solady@https://codeload.github.com/vectorized/solady/tar.gz/59f28399b7e9202bc6145b082bf7ff025b8b1ddc: + resolution: {tarball: https://codeload.github.com/vectorized/solady/tar.gz/59f28399b7e9202bc6145b082bf7ff025b8b1ddc} + version: 0.1.6 + + solarray@https://codeload.github.com/sablier-labs/solarray/tar.gz/6bf10cb34cdace52a3ba5fe437e78cc82df92684: + resolution: {tarball: https://codeload.github.com/sablier-labs/solarray/tar.gz/6bf10cb34cdace52a3ba5fe437e78cc82df92684} + version: 1.0.0 + + solc@0.8.26: + resolution: {integrity: sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==} + engines: {node: '>=10.0.0'} + hasBin: true + + solhint@5.0.5: + resolution: {integrity: sha512-WrnG6T+/UduuzSWsSOAbfq1ywLUDwNea3Gd5hg6PS+pLUm8lz2ECNr0beX609clBxmDeZ3676AiA9nPDljmbJQ==} + hasBin: true + + solidity-coverage@0.8.14: + resolution: {integrity: sha512-ItAAObe5GaEOp20kXC2BZRnph+9P7Rtoqg2mQc2SXGEHgSDF2wWd1Wxz3ntzQWXkbCtIIGdJT918HG00cObwbA==} + hasBin: true + peerDependencies: + hardhat: ^2.11.0 + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.2.0: + resolution: {integrity: sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==} + engines: {node: '>=0.8.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + spawndamnit@3.0.1: + resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stacktrace-parser@0.1.10: + resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} + engines: {node: '>=6'} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-hex-prefix@1.0.0: + resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} + engines: {node: '>=6.5.0', npm: '>=3'} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@3.2.3: + resolution: {integrity: sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==} + engines: {node: '>=0.8.0'} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + table@6.9.0: + resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} + engines: {node: '>=10.0.0'} + + term-size@2.2.1: + resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} + engines: {node: '>=8'} + + test-value@2.1.0: + resolution: {integrity: sha512-+1epbAxtKeXttkGFMTX9H42oqzOTufR1ceCF+GYA5aOmvaPq9wd4PUS8329fn2RRLGNeUkgRLnVpycjx8DsO2w==} + engines: {node: '>=0.10.0'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + tinyglobby@0.2.10: + resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} + engines: {node: '>=12.0.0'} + + tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + ts-essentials@7.0.3: + resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==} + peerDependencies: + typescript: '>=3.7.0' + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tsort@0.0.1: + resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} + + tweetnacl-util@0.15.1: + resolution: {integrity: sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==} + + tweetnacl@1.0.3: + resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} + + type-check@0.3.2: + resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} + engines: {node: '>= 0.8.0'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@0.7.1: + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} + engines: {node: '>=8'} + + typechain@5.2.0: + resolution: {integrity: sha512-0INirvQ+P+MwJOeMct+WLkUE4zov06QxC96D+i3uGFEHoiSkZN70MKDQsaj8zkL86wQwByJReI2e7fOUwECFuw==} + hasBin: true + peerDependencies: + typescript: '>=4.1.0' + + typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + + typical@2.6.1: + resolution: {integrity: sha512-ofhi8kjIje6npGozTip9Fr8iecmYfEbS06i0JnIg+rh51KakryWF4+jX8lLKZVhy6N+ID45WYSFCxPOdTWCzNg==} + + uglify-js@3.19.3: + resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} + engines: {node: '>=0.8.0'} + hasBin: true + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + + undici@5.28.5: + resolution: {integrity: sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==} + engines: {node: '>=14.0'} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + utf8@3.0.0: + resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + web3-utils@1.10.4: + resolution: {integrity: sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==} + engines: {node: '>=8.0.0'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + widest-line@3.1.0: + resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} + engines: {node: '>=8'} + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + + workerpool@6.5.1: + resolution: {integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@7.4.6: + resolution: {integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==} + 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 + + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + 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 + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs-unparser@2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zksync-web3@0.14.4: + resolution: {integrity: sha512-kYehMD/S6Uhe1g434UnaMN+sBr9nQm23Ywn0EUP5BfQCsbjcr3ORuS68PosZw8xUTu3pac7G6YMSnNHk+fwzvg==} + deprecated: This package has been deprecated in favor of zksync-ethers@5.0.0 + peerDependencies: + ethers: ^5.7.0 + +snapshots: + + '@babel/code-frame@7.26.2': + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/helper-validator-identifier@7.25.9': {} + + '@babel/runtime@7.26.7': + dependencies: + regenerator-runtime: 0.14.1 + + '@changesets/apply-release-plan@7.0.8': + dependencies: + '@changesets/config': 3.0.5 + '@changesets/get-version-range-type': 0.4.0 + '@changesets/git': 3.0.2 + '@changesets/should-skip-package': 0.1.1 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + detect-indent: 6.1.0 + fs-extra: 7.0.1 + lodash.startcase: 4.4.0 + outdent: 0.5.0 + prettier: 2.8.8 + resolve-from: 5.0.0 + semver: 7.7.1 + + '@changesets/assemble-release-plan@6.0.5': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.2 + '@changesets/should-skip-package': 0.1.1 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + semver: 7.7.1 + + '@changesets/changelog-git@0.2.0': + dependencies: + '@changesets/types': 6.0.0 + + '@changesets/cli@2.27.12': + dependencies: + '@changesets/apply-release-plan': 7.0.8 + '@changesets/assemble-release-plan': 6.0.5 + '@changesets/changelog-git': 0.2.0 + '@changesets/config': 3.0.5 + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.2 + '@changesets/get-release-plan': 4.0.6 + '@changesets/git': 3.0.2 + '@changesets/logger': 0.1.1 + '@changesets/pre': 2.0.1 + '@changesets/read': 0.6.2 + '@changesets/should-skip-package': 0.1.1 + '@changesets/types': 6.0.0 + '@changesets/write': 0.3.2 + '@manypkg/get-packages': 1.1.3 + ansi-colors: 4.1.3 + ci-info: 3.9.0 + enquirer: 2.4.1 + external-editor: 3.1.0 + fs-extra: 7.0.1 + mri: 1.2.0 + p-limit: 2.3.0 + package-manager-detector: 0.2.9 + picocolors: 1.1.1 + resolve-from: 5.0.0 + semver: 7.7.1 + spawndamnit: 3.0.1 + term-size: 2.2.1 + + '@changesets/config@3.0.5': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.2 + '@changesets/logger': 0.1.1 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + micromatch: 4.0.8 + + '@changesets/errors@0.2.0': + dependencies: + extendable-error: 0.1.7 + + '@changesets/get-dependents-graph@2.1.2': + dependencies: + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + picocolors: 1.1.1 + semver: 7.7.1 + + '@changesets/get-release-plan@4.0.6': + dependencies: + '@changesets/assemble-release-plan': 6.0.5 + '@changesets/config': 3.0.5 + '@changesets/pre': 2.0.1 + '@changesets/read': 0.6.2 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/get-version-range-type@0.4.0': {} + + '@changesets/git@3.0.2': + dependencies: + '@changesets/errors': 0.2.0 + '@manypkg/get-packages': 1.1.3 + is-subdir: 1.2.0 + micromatch: 4.0.8 + spawndamnit: 3.0.1 + + '@changesets/logger@0.1.1': + dependencies: + picocolors: 1.1.1 + + '@changesets/parse@0.4.0': + dependencies: + '@changesets/types': 6.0.0 + js-yaml: 3.14.1 + + '@changesets/pre@2.0.1': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + + '@changesets/read@0.6.2': + dependencies: + '@changesets/git': 3.0.2 + '@changesets/logger': 0.1.1 + '@changesets/parse': 0.4.0 + '@changesets/types': 6.0.0 + fs-extra: 7.0.1 + p-filter: 2.1.0 + picocolors: 1.1.1 + + '@changesets/should-skip-package@0.1.1': + dependencies: + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/types@4.1.0': {} + + '@changesets/types@6.0.0': {} + + '@changesets/write@0.3.2': + dependencies: + '@changesets/types': 6.0.0 + fs-extra: 7.0.1 + human-id: 1.0.2 + prettier: 2.8.8 + + '@ethereumjs/rlp@4.0.1': {} + + '@ethereumjs/util@8.1.0': + dependencies: + '@ethereumjs/rlp': 4.0.1 + ethereum-cryptography: 2.2.1 + micro-ftch: 0.3.1 + + '@ethersproject/abi@5.7.0': + 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 + + '@ethersproject/abstract-provider@5.7.0': + dependencies: + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/networks': 5.7.1 + '@ethersproject/properties': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@ethersproject/web': 5.7.1 + + '@ethersproject/abstract-signer@5.7.0': + 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 + + '@ethersproject/address@5.7.0': + 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 + + '@ethersproject/base64@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + + '@ethersproject/basex@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/properties': 5.7.0 + + '@ethersproject/bignumber@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + bn.js: 5.2.1 + + '@ethersproject/bytes@5.7.0': + dependencies: + '@ethersproject/logger': 5.7.0 + + '@ethersproject/constants@5.7.0': + dependencies: + '@ethersproject/bignumber': 5.7.0 + + '@ethersproject/contracts@5.7.0': + 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 + + '@ethersproject/hash@5.7.0': + 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 + + '@ethersproject/hdnode@5.7.0': + 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 + + '@ethersproject/json-wallets@5.7.0': + 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 + + '@ethersproject/keccak256@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + js-sha3: 0.8.0 + + '@ethersproject/logger@5.7.0': {} + + '@ethersproject/networks@5.7.1': + dependencies: + '@ethersproject/logger': 5.7.0 + + '@ethersproject/pbkdf2@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/sha2': 5.7.0 + + '@ethersproject/properties@5.7.0': + dependencies: + '@ethersproject/logger': 5.7.0 + + '@ethersproject/providers@5.7.2': + 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.1 + '@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.1 + bech32: 1.1.4 + ws: 7.4.6 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@ethersproject/random@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + + '@ethersproject/rlp@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + + '@ethersproject/sha2@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + hash.js: 1.1.7 + + '@ethersproject/signing-key@5.7.0': + 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 + + '@ethersproject/solidity@5.7.0': + 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 + + '@ethersproject/strings@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/logger': 5.7.0 + + '@ethersproject/transactions@5.7.0': + 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 + + '@ethersproject/units@5.7.0': + dependencies: + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/logger': 5.7.0 + + '@ethersproject/wallet@5.7.0': + 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 + + '@ethersproject/web@5.7.1': + 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 + + '@ethersproject/wordlists@5.7.0': + 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 + + '@fastify/busboy@2.1.1': {} + + '@gnosis.pm/safe-contracts@1.3.0(ethers@5.7.2)': + dependencies: + ethers: 5.7.2 + + '@manypkg/find-root@1.1.0': + dependencies: + '@babel/runtime': 7.26.7 + '@types/node': 12.20.55 + find-up: 4.1.0 + fs-extra: 8.1.0 + + '@manypkg/get-packages@1.1.3': + dependencies: + '@babel/runtime': 7.26.7 + '@changesets/types': 4.1.0 + '@manypkg/find-root': 1.1.0 + fs-extra: 8.1.0 + globby: 11.1.0 + read-yaml-file: 1.1.0 + + '@metamask/eth-sig-util@4.0.1': + 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 + + '@noble/curves@1.4.2': + dependencies: + '@noble/hashes': 1.4.0 + + '@noble/hashes@1.2.0': {} + + '@noble/hashes@1.4.0': {} + + '@noble/hashes@1.7.1': {} + + '@noble/secp256k1@1.7.1': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.0 + + '@nomad-xyz/excessively-safe-call@https://codeload.github.com/nomad-xyz/ExcessivelySafeCall/tar.gz/81cd99ce3e69117d665d7601c330ea03b97acce0': {} + + '@nomicfoundation/edr-darwin-arm64@0.6.5': {} + + '@nomicfoundation/edr-darwin-x64@0.6.5': {} + + '@nomicfoundation/edr-linux-arm64-gnu@0.6.5': {} + + '@nomicfoundation/edr-linux-arm64-musl@0.6.5': {} + + '@nomicfoundation/edr-linux-x64-gnu@0.6.5': {} + + '@nomicfoundation/edr-linux-x64-musl@0.6.5': {} + + '@nomicfoundation/edr-win32-x64-msvc@0.6.5': {} + + '@nomicfoundation/edr@0.6.5': + dependencies: + '@nomicfoundation/edr-darwin-arm64': 0.6.5 + '@nomicfoundation/edr-darwin-x64': 0.6.5 + '@nomicfoundation/edr-linux-arm64-gnu': 0.6.5 + '@nomicfoundation/edr-linux-arm64-musl': 0.6.5 + '@nomicfoundation/edr-linux-x64-gnu': 0.6.5 + '@nomicfoundation/edr-linux-x64-musl': 0.6.5 + '@nomicfoundation/edr-win32-x64-msvc': 0.6.5 + + '@nomicfoundation/ethereumjs-common@4.0.4': + dependencies: + '@nomicfoundation/ethereumjs-util': 9.0.4 + transitivePeerDependencies: + - c-kzg + + '@nomicfoundation/ethereumjs-rlp@5.0.4': {} + + '@nomicfoundation/ethereumjs-tx@5.0.4': + dependencies: + '@nomicfoundation/ethereumjs-common': 4.0.4 + '@nomicfoundation/ethereumjs-rlp': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 + ethereum-cryptography: 0.1.3 + + '@nomicfoundation/ethereumjs-util@9.0.4': + dependencies: + '@nomicfoundation/ethereumjs-rlp': 5.0.4 + ethereum-cryptography: 0.1.3 + + '@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2': + optional: true + + '@nomicfoundation/solidity-analyzer-darwin-x64@0.1.2': + optional: true + + '@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.2': + optional: true + + '@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.2': + optional: true + + '@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.2': + optional: true + + '@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.2': + optional: true + + '@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.2': + optional: true + + '@nomicfoundation/solidity-analyzer@0.1.2': + optionalDependencies: + '@nomicfoundation/solidity-analyzer-darwin-arm64': 0.1.2 + '@nomicfoundation/solidity-analyzer-darwin-x64': 0.1.2 + '@nomicfoundation/solidity-analyzer-linux-arm64-gnu': 0.1.2 + '@nomicfoundation/solidity-analyzer-linux-arm64-musl': 0.1.2 + '@nomicfoundation/solidity-analyzer-linux-x64-gnu': 0.1.2 + '@nomicfoundation/solidity-analyzer-linux-x64-musl': 0.1.2 + '@nomicfoundation/solidity-analyzer-win32-x64-msvc': 0.1.2 + + '@nomiclabs/hardhat-etherscan@2.1.8(hardhat@2.22.17(typescript@4.9.5))': + dependencies: + '@ethersproject/abi': 5.7.0 + '@ethersproject/address': 5.7.0 + cbor: 5.2.0 + debug: 4.4.0(supports-color@8.1.1) + fs-extra: 7.0.1 + hardhat: 2.22.17(typescript@4.9.5) + node-fetch: 2.7.0 + semver: 6.3.1 + transitivePeerDependencies: + - encoding + - supports-color + + '@openzeppelin/contracts@4.9.6': {} + + '@openzeppelin/contracts@5.0.1': {} + + '@openzeppelin/contracts@5.2.0': {} + + '@pnpm/config.env-replace@1.1.0': {} + + '@pnpm/network.ca-file@1.0.2': + dependencies: + graceful-fs: 4.2.10 + + '@pnpm/npm-conf@2.3.1': + dependencies: + '@pnpm/config.env-replace': 1.1.0 + '@pnpm/network.ca-file': 1.0.2 + config-chain: 1.1.13 + + '@prb/math@4.1.0': {} + + '@rhinestone/erc4337-validation@0.0.5(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5))': + dependencies: + '@openzeppelin/contracts': 5.0.1 + account-abstraction: accountabstraction@https://codeload.github.com/kopy-kat/account-abstraction/tar.gz/c5887153fbfe3ed09b2637cac39873f96d676f38(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)) + account-abstraction-v0.6: accountabstraction@https://codeload.github.com/eth-infinitism/account-abstraction/tar.gz/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)) + ds-test: https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0 + forge-std: https://codeload.github.com/foundry-rs/forge-std/tar.gz/8a225d81aa8e2e013580564588c79abb65eacc9e + prettier: 2.8.8 + solady: https://codeload.github.com/vectorized/solady/tar.gz/59f28399b7e9202bc6145b082bf7ff025b8b1ddc + transitivePeerDependencies: + - bufferutil + - encoding + - ethers + - hardhat + - lodash + - supports-color + - typechain + - utf-8-validate + + '@rhinestone/sentinellist@https://codeload.github.com/rhinestonewtf/sentinellist/tar.gz/e722c5cc68c570d535bc3c9f85b3ce90cdc38807': + dependencies: + forge-std: https://codeload.github.com/foundry-rs/forge-std/tar.gz/3b20d60d14b343ee4f908cb8079495c07f5e8981 + + '@scure/base@1.1.9': {} + + '@scure/bip32@1.1.5': + dependencies: + '@noble/hashes': 1.2.0 + '@noble/secp256k1': 1.7.1 + '@scure/base': 1.1.9 + + '@scure/bip32@1.4.0': + dependencies: + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.9 + + '@scure/bip39@1.1.1': + dependencies: + '@noble/hashes': 1.2.0 + '@scure/base': 1.1.9 + + '@scure/bip39@1.3.0': + dependencies: + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.9 + + '@sentry/core@5.30.0': + dependencies: + '@sentry/hub': 5.30.0 + '@sentry/minimal': 5.30.0 + '@sentry/types': 5.30.0 + '@sentry/utils': 5.30.0 + tslib: 1.14.1 + + '@sentry/hub@5.30.0': + dependencies: + '@sentry/types': 5.30.0 + '@sentry/utils': 5.30.0 + tslib: 1.14.1 + + '@sentry/minimal@5.30.0': + dependencies: + '@sentry/hub': 5.30.0 + '@sentry/types': 5.30.0 + tslib: 1.14.1 + + '@sentry/node@5.30.0': + 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.2 + https-proxy-agent: 5.0.1 + lru_map: 0.3.3 + tslib: 1.14.1 + transitivePeerDependencies: + - supports-color + + '@sentry/tracing@5.30.0': + dependencies: + '@sentry/hub': 5.30.0 + '@sentry/minimal': 5.30.0 + '@sentry/types': 5.30.0 + '@sentry/utils': 5.30.0 + tslib: 1.14.1 + + '@sentry/types@5.30.0': {} + + '@sentry/utils@5.30.0': + dependencies: + '@sentry/types': 5.30.0 + tslib: 1.14.1 + + '@sindresorhus/is@5.6.0': {} + + '@solidity-parser/parser@0.19.0': {} + + '@szmarczak/http-timer@5.0.1': + dependencies: + defer-to-connect: 2.0.1 + + '@thehubbleproject/bls@0.5.1': + dependencies: + ethers: 5.7.2 + mcl-wasm: 1.8.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@typechain/hardhat@2.3.1(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5))': + dependencies: + fs-extra: 9.1.0 + hardhat: 2.22.17(typescript@4.9.5) + lodash: 4.17.21 + typechain: 5.2.0(typescript@4.9.5) + + '@types/bn.js@4.11.6': + dependencies: + '@types/node': 22.13.1 + + '@types/bn.js@5.1.6': + dependencies: + '@types/node': 22.13.1 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/glob@7.2.0': + dependencies: + '@types/minimatch': 5.1.2 + '@types/node': 22.13.1 + + '@types/http-cache-semantics@4.0.4': {} + + '@types/lru-cache@5.1.1': {} + + '@types/minimatch@5.1.2': {} + + '@types/mocha@9.1.1': {} + + '@types/ms@2.1.0': {} + + '@types/node@12.20.55': {} + + '@types/node@20.17.17': + dependencies: + undici-types: 6.19.8 + + '@types/node@22.13.1': + dependencies: + undici-types: 6.20.0 + + '@types/pbkdf2@3.1.2': + dependencies: + '@types/node': 22.13.1 + + '@types/prettier@2.7.3': {} + + '@types/qs@6.9.18': {} + + '@types/secp256k1@4.0.6': + dependencies: + '@types/node': 22.13.1 + + abbrev@1.0.9: {} + + accountabstraction@https://codeload.github.com/eth-infinitism/account-abstraction/tar.gz/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)): + dependencies: + '@gnosis.pm/safe-contracts': 1.3.0(ethers@5.7.2) + '@nomiclabs/hardhat-etherscan': 2.1.8(hardhat@2.22.17(typescript@4.9.5)) + '@openzeppelin/contracts': 4.9.6 + '@thehubbleproject/bls': 0.5.1 + '@typechain/hardhat': 2.3.1(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)) + '@types/mocha': 9.1.1 + ethereumjs-util: 7.1.5 + ethereumjs-wallet: 1.0.2 + hardhat-deploy: 0.11.45 + hardhat-deploy-ethers: 0.3.0-beta.13(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5)) + solidity-coverage: 0.8.14(hardhat@2.22.17(typescript@4.9.5)) + source-map-support: 0.5.21 + table: 6.9.0 + typescript: 4.9.5 + transitivePeerDependencies: + - bufferutil + - encoding + - ethers + - hardhat + - lodash + - supports-color + - typechain + - utf-8-validate + + accountabstraction@https://codeload.github.com/kopy-kat/account-abstraction/tar.gz/c5887153fbfe3ed09b2637cac39873f96d676f38(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)): + dependencies: + '@nomiclabs/hardhat-etherscan': 2.1.8(hardhat@2.22.17(typescript@4.9.5)) + '@openzeppelin/contracts': 5.2.0 + '@thehubbleproject/bls': 0.5.1 + '@typechain/hardhat': 2.3.1(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)) + '@types/debug': 4.1.12 + '@types/mocha': 9.1.1 + debug: 4.4.0(supports-color@8.1.1) + ethereumjs-util: 7.1.5 + ethereumjs-wallet: 1.0.2 + hardhat-deploy: 0.11.45 + hardhat-deploy-ethers: 0.3.0-beta.13(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5)) + solidity-coverage: 0.8.14(hardhat@2.22.17(typescript@4.9.5)) + source-map-support: 0.5.21 + table: 6.9.0 + typescript: 4.9.5 + transitivePeerDependencies: + - bufferutil + - encoding + - ethers + - hardhat + - lodash + - supports-color + - typechain + - utf-8-validate + + adm-zip@0.4.16: {} + + aes-js@3.0.0: {} + + aes-js@3.1.2: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.0(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.6 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + amdefine@1.0.1: + optional: true + + ansi-align@3.0.1: + dependencies: + string-width: 4.2.3 + + ansi-colors@4.1.3: {} + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-regex@5.0.1: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + antlr4@4.13.2: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + array-back@1.0.4: + dependencies: + typical: 2.6.1 + + array-back@2.0.0: + dependencies: + typical: 2.6.1 + + array-union@2.1.0: {} + + ast-parents@0.0.1: {} + + astral-regex@2.0.0: {} + + async@1.5.2: {} + + asynckit@0.4.0: {} + + at-least-node@1.0.0: {} + + axios@0.21.4(debug@4.4.0): + dependencies: + follow-redirects: 1.15.9(debug@4.4.0) + transitivePeerDependencies: + - debug + + balanced-match@1.0.2: {} + + base-x@3.0.10: + dependencies: + safe-buffer: 5.2.1 + + bech32@1.1.4: {} + + better-path-resolve@1.0.0: + dependencies: + is-windows: 1.0.2 + + bignumber.js@9.1.2: {} + + binary-extensions@2.3.0: {} + + blakejs@1.2.1: {} + + bn.js@4.11.6: {} + + bn.js@4.12.1: {} + + bn.js@5.2.1: {} + + boxen@5.1.2: + dependencies: + ansi-align: 3.0.1 + camelcase: 6.3.0 + chalk: 4.1.2 + cli-boxes: 2.2.1 + string-width: 4.2.3 + type-fest: 0.20.2 + widest-line: 3.1.0 + wrap-ansi: 7.0.0 + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + brorand@1.1.0: {} + + browser-stdout@1.3.1: {} + + browserify-aes@1.2.0: + dependencies: + buffer-xor: 1.0.3 + cipher-base: 1.0.6 + create-hash: 1.2.0 + evp_bytestokey: 1.0.3 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + bs58@4.0.1: + dependencies: + base-x: 3.0.10 + + bs58check@2.1.2: + dependencies: + bs58: 4.0.1 + create-hash: 1.2.0 + safe-buffer: 5.2.1 + + buffer-from@1.1.2: {} + + buffer-xor@1.0.3: {} + + bytes@3.1.2: {} + + cacheable-lookup@7.0.0: {} + + cacheable-request@10.2.14: + dependencies: + '@types/http-cache-semantics': 4.0.4 + get-stream: 6.0.1 + http-cache-semantics: 4.1.1 + keyv: 4.5.4 + mimic-response: 4.0.0 + normalize-url: 8.0.1 + responselike: 3.0.0 + + call-bind-apply-helpers@1.0.1: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.3: + dependencies: + call-bind-apply-helpers: 1.0.1 + get-intrinsic: 1.2.7 + + callsites@3.1.0: {} + + camelcase@6.3.0: {} + + cbor@5.2.0: + dependencies: + bignumber.js: 9.1.2 + nofilter: 1.0.4 + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chardet@0.7.0: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.1 + + ci-info@2.0.0: {} + + ci-info@3.9.0: {} + + cipher-base@1.0.6: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + + clean-stack@2.2.0: {} + + cli-boxes@2.2.1: {} + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + command-exists@1.2.9: {} + + command-line-args@4.0.7: + dependencies: + array-back: 2.0.0 + find-replace: 1.0.3 + typical: 2.6.1 + + commander@10.0.1: {} + + commander@8.3.0: {} + + concat-map@0.0.1: {} + + config-chain@1.1.13: + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + + cookie@0.4.2: {} + + cosmiconfig@8.3.6(typescript@4.9.5): + dependencies: + import-fresh: 3.3.1 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 4.9.5 + + create-hash@1.2.0: + dependencies: + cipher-base: 1.0.6 + inherits: 2.0.4 + md5.js: 1.3.5 + ripemd160: 2.0.2 + sha.js: 2.4.11 + + create-hmac@1.1.7: + dependencies: + cipher-base: 1.0.6 + create-hash: 1.2.0 + inherits: 2.0.4 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + death@1.1.0: {} + + debug@4.4.0(supports-color@8.1.1): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 + + decamelize@4.0.0: {} + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-extend@0.6.0: {} + + deep-is@0.1.4: {} + + defer-to-connect@2.0.1: {} + + delayed-stream@1.0.0: {} + + depd@2.0.0: {} + + detect-indent@6.1.0: {} + + diff@5.2.0: {} + + difflib@0.2.4: + dependencies: + heap: 0.2.7 + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + ds-test@https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + elliptic@6.5.4: + dependencies: + bn.js: 4.12.1 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + elliptic@6.6.1: + dependencies: + bn.js: 4.12.1 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + emoji-regex@8.0.0: {} + + encode-utf8@1.0.3: {} + + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + + env-paths@2.2.1: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + escalade@3.2.0: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@4.0.0: {} + + escodegen@1.8.1: + dependencies: + esprima: 2.7.3 + estraverse: 1.9.3 + esutils: 2.0.3 + optionator: 0.8.3 + optionalDependencies: + source-map: 0.2.0 + + esprima@2.7.3: {} + + esprima@4.0.1: {} + + estraverse@1.9.3: {} + + esutils@2.0.3: {} + + ethereum-bloom-filters@1.2.0: + dependencies: + '@noble/hashes': 1.7.1 + + ethereum-cryptography@0.1.3: + dependencies: + '@types/pbkdf2': 3.1.2 + '@types/secp256k1': 4.0.6 + blakejs: 1.2.1 + 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.4 + pbkdf2: 3.1.2 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + scrypt-js: 3.0.1 + secp256k1: 4.0.4 + setimmediate: 1.0.5 + + ethereum-cryptography@1.2.0: + dependencies: + '@noble/hashes': 1.2.0 + '@noble/secp256k1': 1.7.1 + '@scure/bip32': 1.1.5 + '@scure/bip39': 1.1.1 + + ethereum-cryptography@2.2.1: + dependencies: + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@scure/bip32': 1.4.0 + '@scure/bip39': 1.3.0 + + ethereumjs-abi@0.6.8: + dependencies: + bn.js: 4.12.1 + ethereumjs-util: 6.2.1 + + ethereumjs-util@6.2.1: + dependencies: + '@types/bn.js': 4.11.6 + bn.js: 4.12.1 + create-hash: 1.2.0 + elliptic: 6.6.1 + ethereum-cryptography: 0.1.3 + ethjs-util: 0.1.6 + rlp: 2.2.7 + + ethereumjs-util@7.1.5: + dependencies: + '@types/bn.js': 5.1.6 + bn.js: 5.2.1 + create-hash: 1.2.0 + ethereum-cryptography: 0.1.3 + rlp: 2.2.7 + + ethereumjs-wallet@1.0.2: + dependencies: + aes-js: 3.1.2 + bs58check: 2.1.2 + ethereum-cryptography: 0.1.3 + ethereumjs-util: 7.1.5 + randombytes: 2.1.0 + scrypt-js: 3.0.1 + utf8: 3.0.0 + uuid: 8.3.2 + + ethers@5.7.2: + 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 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + ethjs-unit@0.1.6: + dependencies: + bn.js: 4.11.6 + number-to-bn: 1.7.0 + + ethjs-util@0.1.6: + dependencies: + is-hex-prefixed: 1.0.0 + strip-hex-prefix: 1.0.0 + + evp_bytestokey@1.0.3: + dependencies: + md5.js: 1.3.5 + safe-buffer: 5.2.1 + + extendable-error@0.1.7: {} + + external-editor@3.1.0: + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-uri@3.0.6: {} + + fastq@1.19.0: + dependencies: + reusify: 1.0.4 + + fdir@6.4.3(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-replace@1.0.3: + dependencies: + array-back: 1.0.4 + test-value: 2.1.0 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat@5.0.2: {} + + fmix@0.1.0: + dependencies: + imul: 1.0.1 + + follow-redirects@1.15.9(debug@4.4.0): + optionalDependencies: + debug: 4.4.0(supports-color@8.1.1) + + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/3b20d60d14b343ee4f908cb8079495c07f5e8981: {} + + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/8a225d81aa8e2e013580564588c79abb65eacc9e: {} + + form-data-encoder@2.1.4: {} + + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + fp-ts@1.19.3: {} + + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fs-extra@7.0.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@9.1.0: + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.2.7: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@6.0.1: {} + + ghost-testrpc@0.0.2: + dependencies: + chalk: 2.4.2 + node-emoji: 1.11.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob@5.0.15: + dependencies: + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@8.1.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + + global-modules@2.0.0: + dependencies: + global-prefix: 3.0.0 + + global-prefix@3.0.0: + dependencies: + ini: 1.3.8 + kind-of: 6.0.3 + which: 1.3.1 + + globby@10.0.2: + dependencies: + '@types/glob': 7.2.0 + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + glob: 7.2.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + gopd@1.2.0: {} + + got@12.6.1: + dependencies: + '@sindresorhus/is': 5.6.0 + '@szmarczak/http-timer': 5.0.1 + cacheable-lookup: 7.0.0 + cacheable-request: 10.2.14 + decompress-response: 6.0.0 + form-data-encoder: 2.1.4 + get-stream: 6.0.1 + http2-wrapper: 2.2.1 + lowercase-keys: 3.0.0 + p-cancelable: 3.0.0 + responselike: 3.0.0 + + graceful-fs@4.2.10: {} + + graceful-fs@4.2.11: {} + + handlebars@4.7.8: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.19.3 + + hardhat-deploy-ethers@0.3.0-beta.13(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5)): + dependencies: + ethers: 5.7.2 + hardhat: 2.22.17(typescript@4.9.5) + + hardhat-deploy@0.11.45: + dependencies: + '@ethersproject/abi': 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/contracts': 5.7.0 + '@ethersproject/providers': 5.7.2 + '@ethersproject/solidity': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@ethersproject/wallet': 5.7.0 + '@types/qs': 6.9.18 + axios: 0.21.4(debug@4.4.0) + chalk: 4.1.2 + chokidar: 3.6.0 + debug: 4.4.0(supports-color@8.1.1) + enquirer: 2.4.1 + ethers: 5.7.2 + form-data: 4.0.1 + fs-extra: 10.1.0 + match-all: 1.2.6 + murmur-128: 0.2.1 + qs: 6.14.0 + zksync-web3: 0.14.4(ethers@5.7.2) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + hardhat@2.22.17(typescript@4.9.5): + dependencies: + '@ethersproject/abi': 5.7.0 + '@metamask/eth-sig-util': 4.0.1 + '@nomicfoundation/edr': 0.6.5 + '@nomicfoundation/ethereumjs-common': 4.0.4 + '@nomicfoundation/ethereumjs-tx': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 + '@nomicfoundation/solidity-analyzer': 0.1.2 + '@sentry/node': 5.30.0 + '@types/bn.js': 5.1.6 + '@types/lru-cache': 5.1.1 + adm-zip: 0.4.16 + aggregate-error: 3.1.0 + ansi-escapes: 4.3.2 + boxen: 5.1.2 + chokidar: 4.0.3 + ci-info: 2.0.0 + debug: 4.4.0(supports-color@8.1.1) + enquirer: 2.4.1 + env-paths: 2.2.1 + ethereum-cryptography: 1.2.0 + ethereumjs-abi: 0.6.8 + find-up: 5.0.0 + fp-ts: 1.19.3 + fs-extra: 7.0.1 + immutable: 4.3.7 + io-ts: 1.10.4 + json-stream-stringify: 3.1.6 + keccak: 3.0.4 + lodash: 4.17.21 + mnemonist: 0.38.5 + mocha: 10.8.2 + p-map: 4.0.0 + picocolors: 1.1.1 + raw-body: 2.5.2 + resolve: 1.17.0 + semver: 6.3.1 + solc: 0.8.26(debug@4.4.0) + source-map-support: 0.5.21 + stacktrace-parser: 0.1.10 + tinyglobby: 0.2.10 + tsort: 0.0.1 + undici: 5.28.5 + uuid: 8.3.2 + ws: 7.5.10 + optionalDependencies: + typescript: 4.9.5 + transitivePeerDependencies: + - bufferutil + - c-kzg + - supports-color + - utf-8-validate + + has-flag@1.0.0: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + hash-base@3.1.0: + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + safe-buffer: 5.2.1 + + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + he@1.2.0: {} + + heap@0.2.7: {} + + hmac-drbg@1.0.1: + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + http-cache-semantics@4.1.1: {} + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + http2-wrapper@2.2.1: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.0(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + human-id@1.0.2: {} + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + ignore@5.3.2: {} + + immutable@4.3.7: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imul@1.0.1: {} + + indent-string@4.0.0: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + ini@1.3.8: {} + + interpret@1.4.0: {} + + io-ts@1.10.4: + dependencies: + fp-ts: 1.19.3 + + is-arrayish@0.2.1: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hex-prefixed@1.0.0: {} + + is-number@7.0.0: {} + + is-plain-obj@2.1.0: {} + + is-subdir@1.2.0: + dependencies: + better-path-resolve: 1.0.0 + + is-unicode-supported@0.1.0: {} + + is-windows@1.0.2: {} + + isexe@2.0.0: {} + + js-sha3@0.8.0: {} + + js-tokens@4.0.0: {} + + js-yaml@3.14.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stream-stringify@3.1.6: {} + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + jsonschema@1.5.0: {} + + keccak@3.0.4: + dependencies: + node-addon-api: 2.0.2 + node-gyp-build: 4.8.4 + readable-stream: 3.6.2 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kind-of@6.0.3: {} + + latest-version@7.0.0: + dependencies: + package-json: 8.1.1 + + levn@0.3.0: + dependencies: + prelude-ls: 1.1.2 + type-check: 0.3.2 + + lines-and-columns@1.2.4: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.startcase@4.4.0: {} + + lodash.truncate@4.4.2: {} + + lodash@4.17.21: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + lowercase-keys@3.0.0: {} + + lru_map@0.3.3: {} + + match-all@1.2.6: {} + + math-intrinsics@1.1.0: {} + + mcl-wasm@1.8.0: + dependencies: + '@types/node': 20.17.17 + + md5.js@1.3.5: + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + memorystream@0.3.1: {} + + merge2@1.4.1: {} + + micro-ftch@0.3.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-response@3.1.0: {} + + mimic-response@4.0.0: {} + + minimalistic-assert@1.0.1: {} + + minimalistic-crypto-utils@1.0.1: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + mkdirp@1.0.4: {} + + mnemonist@0.38.5: + dependencies: + obliterator: 2.0.5 + + mocha@10.8.2: + dependencies: + ansi-colors: 4.1.3 + browser-stdout: 1.3.1 + chokidar: 3.6.0 + debug: 4.4.0(supports-color@8.1.1) + diff: 5.2.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 8.1.0 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 5.1.6 + ms: 2.1.3 + serialize-javascript: 6.0.2 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + workerpool: 6.5.1 + yargs: 16.2.0 + yargs-parser: 20.2.9 + yargs-unparser: 2.0.0 + + mri@1.2.0: {} + + ms@2.1.3: {} + + murmur-128@0.2.1: + dependencies: + encode-utf8: 1.0.3 + fmix: 0.1.0 + imul: 1.0.1 + + neo-async@2.6.2: {} + + node-addon-api@2.0.2: {} + + node-addon-api@5.1.0: {} + + node-emoji@1.11.0: + dependencies: + lodash: 4.17.21 + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-gyp-build@4.8.4: {} + + nofilter@1.0.4: {} + + nopt@3.0.6: + dependencies: + abbrev: 1.0.9 + + normalize-path@3.0.0: {} + + normalize-url@8.0.1: {} + + number-to-bn@1.7.0: + dependencies: + bn.js: 4.11.6 + strip-hex-prefix: 1.0.0 + + object-inspect@1.13.4: {} + + obliterator@2.0.5: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + optionator@0.8.3: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.3.0 + prelude-ls: 1.1.2 + type-check: 0.3.2 + word-wrap: 1.2.5 + + os-tmpdir@1.0.2: {} + + outdent@0.5.0: {} + + p-cancelable@3.0.0: {} + + p-filter@2.1.0: + dependencies: + p-map: 2.1.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-map@2.1.0: {} + + p-map@4.0.0: + dependencies: + aggregate-error: 3.1.0 + + p-try@2.2.0: {} + + package-json@8.1.1: + dependencies: + got: 12.6.1 + registry-auth-token: 5.0.3 + registry-url: 6.0.1 + semver: 7.7.1 + + package-manager-detector@0.2.9: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.26.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-type@4.0.0: {} + + pbkdf2@3.1.2: + dependencies: + create-hash: 1.2.0 + create-hmac: 1.1.7 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.2: {} + + pify@4.0.1: {} + + pluralize@8.0.0: {} + + prelude-ls@1.1.2: {} + + prettier@2.8.8: {} + + proto-list@1.2.4: {} + + punycode@2.3.1: {} + + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + + queue-microtask@1.2.3: {} + + quick-lru@5.1.1: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + raw-body@2.5.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + read-yaml-file@1.1.0: + dependencies: + graceful-fs: 4.2.11 + js-yaml: 3.14.1 + pify: 4.0.1 + strip-bom: 3.0.0 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + readdirp@4.1.1: {} + + rechoir@0.6.2: + dependencies: + resolve: 1.22.10 + + recursive-readdir@2.2.3: + dependencies: + minimatch: 3.1.2 + + regenerator-runtime@0.14.1: {} + + registry-auth-token@5.0.3: + dependencies: + '@pnpm/npm-conf': 2.3.1 + + registry-url@6.0.1: + dependencies: + rc: 1.2.8 + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + resolve-alpn@1.2.1: {} + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve@1.1.7: {} + + resolve@1.17.0: + dependencies: + path-parse: 1.0.7 + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + responselike@3.0.0: + dependencies: + lowercase-keys: 3.0.0 + + reusify@1.0.4: {} + + ripemd160@2.0.2: + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + + rlp@2.2.7: + dependencies: + bn.js: 5.2.1 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + sc-istanbul@0.4.6: + dependencies: + abbrev: 1.0.9 + async: 1.5.2 + escodegen: 1.8.1 + esprima: 2.7.3 + glob: 5.0.15 + handlebars: 4.7.8 + js-yaml: 3.14.1 + mkdirp: 0.5.6 + nopt: 3.0.6 + once: 1.4.0 + resolve: 1.1.7 + supports-color: 3.2.3 + which: 1.3.1 + wordwrap: 1.0.0 + + scrypt-js@3.0.1: {} + + secp256k1@4.0.4: + dependencies: + elliptic: 6.6.1 + node-addon-api: 5.1.0 + node-gyp-build: 4.8.4 + + semver@5.7.2: {} + + semver@6.3.1: {} + + semver@7.7.1: {} + + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + setimmediate@1.0.5: {} + + setprototypeof@1.2.0: {} + + sha.js@2.4.11: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shelljs@0.8.5: + dependencies: + glob: 7.2.3 + interpret: 1.4.0 + rechoir: 0.6.2 + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + signal-exit@4.1.0: {} + + slash@3.0.0: {} + + slice-ansi@4.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + + solady@https://codeload.github.com/vectorized/solady/tar.gz/59f28399b7e9202bc6145b082bf7ff025b8b1ddc: {} + + solarray@https://codeload.github.com/sablier-labs/solarray/tar.gz/6bf10cb34cdace52a3ba5fe437e78cc82df92684: {} + + solc@0.8.26(debug@4.4.0): + dependencies: + command-exists: 1.2.9 + commander: 8.3.0 + follow-redirects: 1.15.9(debug@4.4.0) + js-sha3: 0.8.0 + memorystream: 0.3.1 + semver: 5.7.2 + tmp: 0.0.33 + transitivePeerDependencies: + - debug + + solhint@5.0.5(typescript@4.9.5): + dependencies: + '@solidity-parser/parser': 0.19.0 + ajv: 6.12.6 + antlr4: 4.13.2 + ast-parents: 0.0.1 + chalk: 4.1.2 + commander: 10.0.1 + cosmiconfig: 8.3.6(typescript@4.9.5) + fast-diff: 1.3.0 + glob: 8.1.0 + ignore: 5.3.2 + js-yaml: 4.1.0 + latest-version: 7.0.0 + lodash: 4.17.21 + pluralize: 8.0.0 + semver: 7.7.1 + strip-ansi: 6.0.1 + table: 6.9.0 + text-table: 0.2.0 + optionalDependencies: + prettier: 2.8.8 + transitivePeerDependencies: + - typescript + + solidity-coverage@0.8.14(hardhat@2.22.17(typescript@4.9.5)): + dependencies: + '@ethersproject/abi': 5.7.0 + '@solidity-parser/parser': 0.19.0 + chalk: 2.4.2 + death: 1.1.0 + difflib: 0.2.4 + fs-extra: 8.1.0 + ghost-testrpc: 0.0.2 + global-modules: 2.0.0 + globby: 10.0.2 + hardhat: 2.22.17(typescript@4.9.5) + jsonschema: 1.5.0 + lodash: 4.17.21 + mocha: 10.8.2 + node-emoji: 1.11.0 + pify: 4.0.1 + recursive-readdir: 2.2.3 + sc-istanbul: 0.4.6 + semver: 7.7.1 + shelljs: 0.8.5 + web3-utils: 1.10.4 + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.2.0: + dependencies: + amdefine: 1.0.1 + optional: true + + source-map@0.6.1: {} + + spawndamnit@3.0.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + sprintf-js@1.0.3: {} + + stacktrace-parser@0.1.10: + dependencies: + type-fest: 0.7.1 + + statuses@2.0.1: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@3.0.0: {} + + strip-hex-prefix@1.0.0: + dependencies: + is-hex-prefixed: 1.0.0 + + strip-json-comments@2.0.1: {} + + strip-json-comments@3.1.1: {} + + supports-color@3.2.3: + dependencies: + has-flag: 1.0.0 + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + table@6.9.0: + dependencies: + ajv: 8.17.1 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + term-size@2.2.1: {} + + test-value@2.1.0: + dependencies: + array-back: 1.0.4 + typical: 2.6.1 + + text-table@0.2.0: {} + + tinyglobby@0.2.10: + dependencies: + fdir: 6.4.3(picomatch@4.0.2) + picomatch: 4.0.2 + + tmp@0.0.33: + dependencies: + os-tmpdir: 1.0.2 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + tr46@0.0.3: {} + + ts-essentials@7.0.3(typescript@4.9.5): + dependencies: + typescript: 4.9.5 + + tslib@1.14.1: {} + + tsort@0.0.1: {} + + tweetnacl-util@0.15.1: {} + + tweetnacl@1.0.3: {} + + type-check@0.3.2: + dependencies: + prelude-ls: 1.1.2 + + type-fest@0.20.2: {} + + type-fest@0.21.3: {} + + type-fest@0.7.1: {} + + typechain@5.2.0(typescript@4.9.5): + dependencies: + '@types/prettier': 2.7.3 + command-line-args: 4.0.7 + debug: 4.4.0(supports-color@8.1.1) + fs-extra: 7.0.1 + glob: 7.2.3 + js-sha3: 0.8.0 + lodash: 4.17.21 + mkdirp: 1.0.4 + prettier: 2.8.8 + ts-essentials: 7.0.3(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + + typescript@4.9.5: {} + + typical@2.6.1: {} + + uglify-js@3.19.3: + optional: true + + undici-types@6.19.8: {} + + undici-types@6.20.0: {} + + undici@5.28.5: + dependencies: + '@fastify/busboy': 2.1.1 + + universalify@0.1.2: {} + + universalify@2.0.1: {} + + unpipe@1.0.0: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + utf8@3.0.0: {} + + util-deprecate@1.0.2: {} + + uuid@8.3.2: {} + + web3-utils@1.10.4: + dependencies: + '@ethereumjs/util': 8.1.0 + bn.js: 5.2.1 + ethereum-bloom-filters: 1.2.0 + ethereum-cryptography: 2.2.1 + ethjs-unit: 0.1.6 + number-to-bn: 1.7.0 + randombytes: 2.1.0 + utf8: 3.0.0 + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which@1.3.1: + dependencies: + isexe: 2.0.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + widest-line@3.1.0: + dependencies: + string-width: 4.2.3 + + word-wrap@1.2.5: {} + + wordwrap@1.0.0: {} + + workerpool@6.5.1: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + ws@7.4.6: {} + + ws@7.5.10: {} + + y18n@5.0.8: {} + + yargs-parser@20.2.9: {} + + yargs-unparser@2.0.0: + dependencies: + camelcase: 6.3.0 + decamelize: 4.0.0 + flat: 5.0.2 + is-plain-obj: 2.1.0 + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + + yocto-queue@0.1.0: {} + + zksync-web3@0.14.4(ethers@5.7.2): + dependencies: + ethers: 5.7.2 diff --git a/typescript/packages/account-modules/lib/modulekit/remappings.txt b/typescript/packages/account-modules/lib/modulekit/remappings.txt new file mode 100644 index 0000000..556ee76 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/remappings.txt @@ -0,0 +1,12 @@ +erc4337-validation/=node_modules/@rhinestone/erc4337-validation/src/ +@ERC4337/=node_modules/@ERC4337/ +account-abstraction/=node_modules/@ERC4337/account-abstraction/contracts/ +account-abstraction-v0.6/=node_modules/@ERC4337/account-abstraction-v0.6/contracts/ +modulekit/=node_modules/@rhinestone/modulekit/src/ +@openzeppelin/=node_modules/@openzeppelin/ +ds-test/=node_modules/ds-test/src/ +forge-std/=node_modules/forge-std/src/ +solady/=node_modules/solady/src/ +solarray/=node_modules/solarray/src/ +@prb/math/=node_modules/@prb/math/src/ +ExcessivelySafeCall/=node_modules/excessively-safe-call/src/ \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/modulekit/src/Accounts.sol b/typescript/packages/account-modules/lib/modulekit/src/Accounts.sol new file mode 100644 index 0000000..42fa96f --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/Accounts.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/* solhint-disable no-unused-import */ + +/*////////////////////////////////////////////////////////////// + COMMON +//////////////////////////////////////////////////////////////*/ + +import { IERC7579Account } from "./accounts/common/interfaces/IERC7579Account.sol"; + +/*////////////////////////////////////////////////////////////// + 7579 REFERENCE +//////////////////////////////////////////////////////////////*/ + +import { IMSA } from "./accounts/erc7579/interfaces/IMSA.sol"; + +/*////////////////////////////////////////////////////////////// + KERNEL +//////////////////////////////////////////////////////////////*/ + +import { IERC7579Account as IKernelAccount } from "./accounts/kernel/interfaces/IERC7579Account.sol"; + +/*////////////////////////////////////////////////////////////// + SAFE +//////////////////////////////////////////////////////////////*/ + +import { ISafe7579 } from "./accounts/safe/interfaces/ISafe7579.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/Helpers.sol b/typescript/packages/account-modules/lib/modulekit/src/Helpers.sol new file mode 100644 index 0000000..abfcd14 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/Helpers.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/* solhint-disable no-unused-import */ + +/*////////////////////////////////////////////////////////////// + 4337 +//////////////////////////////////////////////////////////////*/ + +import { ERC4337Helpers } from "./test/utils/ERC4337Helpers.sol"; + +/*////////////////////////////////////////////////////////////// + 7579 REFERENCE +//////////////////////////////////////////////////////////////*/ + +import { ERC7579Helpers } from "./test/helpers/ERC7579Helpers.sol"; + +/*////////////////////////////////////////////////////////////// + KERNEL +//////////////////////////////////////////////////////////////*/ + +import { KernelHelpers } from "./test/helpers/KernelHelpers.sol"; + +/*////////////////////////////////////////////////////////////// + NEXUS +//////////////////////////////////////////////////////////////*/ + +import { NexusHelpers } from "./test/helpers/NexusHelpers.sol"; + +/*////////////////////////////////////////////////////////////// + SAFE +//////////////////////////////////////////////////////////////*/ + +import { SafeHelpers } from "./test/helpers/SafeHelpers.sol"; + +/*////////////////////////////////////////////////////////////// + UTIL +//////////////////////////////////////////////////////////////*/ + +import { ecdsaSign } from "./test/utils/ECDSA.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/Integrations.sol b/typescript/packages/account-modules/lib/modulekit/src/Integrations.sol new file mode 100644 index 0000000..1b50604 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/Integrations.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/* solhint-disable no-unused-import */ + +/*////////////////////////////////////////////////////////////// + ERCs +//////////////////////////////////////////////////////////////*/ + +import { ERC20Integration } from "./integrations/ERC20.sol"; +import { ERC721Integration } from "./integrations/ERC721.sol"; +import { ERC4626Integration } from "./integrations/ERC4626.sol"; + +/*////////////////////////////////////////////////////////////// + UNIV3 +//////////////////////////////////////////////////////////////*/ + +import { UniswapV3Integration, SWAPROUTER_ADDRESS } from "./integrations/uniswap/v3/Uniswap.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/Interfaces.sol b/typescript/packages/account-modules/lib/modulekit/src/Interfaces.sol new file mode 100644 index 0000000..bc6f3b2 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/Interfaces.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/* solhint-disable no-unused-import */ + +/*////////////////////////////////////////////////////////////// + ERCs/EIPs +//////////////////////////////////////////////////////////////*/ + +import { IERC1271, EIP1271_MAGIC_VALUE } from "./module-bases/interfaces/IERC1271.sol"; +import { IERC7484 } from "./module-bases/interfaces/IERC7484.sol"; +import { + IERC6682, + IERC3156FlashLender, + IERC3156FlashBorrower +} from "./module-bases/interfaces/Flashloan.sol"; +import { IERC712 } from "./module-bases/interfaces/IERC712.sol"; + +/*////////////////////////////////////////////////////////////// + MODULES +//////////////////////////////////////////////////////////////*/ + +import { IStatelessValidator } from "./module-bases/interfaces/IStatelessValidator.sol"; +import { IPolicy } from "./module-bases/interfaces/IPolicy.sol"; + +/*////////////////////////////////////////////////////////////// + TYPES +//////////////////////////////////////////////////////////////*/ + +import { FlashLoanType } from "./module-bases/interfaces/Flashloan.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/Mocks.sol b/typescript/packages/account-modules/lib/modulekit/src/Mocks.sol new file mode 100644 index 0000000..972caaf --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/Mocks.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/* solhint-disable no-unused-import */ + +/*////////////////////////////////////////////////////////////// + AUX +//////////////////////////////////////////////////////////////*/ + +import { MockRegistry } from "./module-bases/mocks/MockRegistry.sol"; +import { MockTarget } from "./module-bases/mocks/MockTarget.sol"; +import { MockHookMultiPlexer } from "./module-bases/mocks/MockHookMultiPlexer.sol"; +import { MockPolicy } from "./module-bases/mocks/MockPolicy.sol"; + +/*////////////////////////////////////////////////////////////// + MODULES +//////////////////////////////////////////////////////////////*/ + +import { MockValidator } from "./module-bases/mocks/MockValidator.sol"; +import { MockStatelessValidator } from "./module-bases/mocks/MockStatelessValidator.sol"; +import { MockHybridValidator } from "./module-bases/mocks/MockHybridValidator.sol"; +import { MockExecutor } from "./module-bases/mocks/MockExecutor.sol"; +import { MockHook } from "./module-bases/mocks/MockHook.sol"; +import { MockFallback } from "./module-bases/mocks/MockFallback.sol"; + +/*////////////////////////////////////////////////////////////// + TOKENS +//////////////////////////////////////////////////////////////*/ + +import { MockERC20 } from "./mocks/MockERC20.sol"; +import { MockERC721 } from "./mocks/MockERC721.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/ModuleKit.sol b/typescript/packages/account-modules/lib/modulekit/src/ModuleKit.sol new file mode 100644 index 0000000..f2c0b0f --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/ModuleKit.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/* solhint-disable no-unused-import */ + +/*////////////////////////////////////////////////////////////// + MODULEKIT +//////////////////////////////////////////////////////////////*/ + +import { + UserOpData, + AccountInstance, + RhinestoneModuleKit, + AccountType +} from "./test/RhinestoneModuleKit.sol"; +import { ModuleKitHelpers } from "./test/ModuleKitHelpers.sol"; + +/*////////////////////////////////////////////////////////////// + 4337 +////////////////////////////////////////////////////////////*/ + +import { PackedUserOperation } from "./external/ERC4337.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/Modules.sol b/typescript/packages/account-modules/lib/modulekit/src/Modules.sol new file mode 100644 index 0000000..e426671 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/Modules.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/* solhint-disable no-unused-import */ + +/*////////////////////////////////////////////////////////////// + INTERFACES +//////////////////////////////////////////////////////////////*/ + +import { + IValidator as IERC7579Validator, + IExecutor as IERC7579Executor, + IFallback as IERC7579Fallback, + IHook as IERC7579Hook, + IModule as IERC7579Module +} from "./accounts/common/interfaces/IERC7579Module.sol"; + +/*////////////////////////////////////////////////////////////// + BASES +//////////////////////////////////////////////////////////////*/ + +// Core +import { ERC7579ModuleBase } from "./module-bases/ERC7579ModuleBase.sol"; + +// Validators +import { ERC7579ValidatorBase } from "./module-bases/ERC7579ValidatorBase.sol"; +import { ERC7579StatelessValidatorBase } from "./module-bases/ERC7579StatelessValidatorBase.sol"; +import { ERC7579HybridValidatorBase } from "./module-bases/ERC7579HybridValidatorBase.sol"; + +// Executors +import { ERC7579ExecutorBase } from "./module-bases/ERC7579ExecutorBase.sol"; + +// Hooks +import { ERC7579HookBase } from "./module-bases/ERC7579HookBase.sol"; +import { ERC7579HookDestruct } from "./module-bases/ERC7579HookDestruct.sol"; +import { ERC7579HookDestructSingleHook } from "./module-bases/ERC7579HookDestructSingleHook.sol"; + +// Fallbacks +import { ERC7579FallbackBase } from "./module-bases/ERC7579FallbackBase.sol"; + +// Misc +import { SchedulingBase } from "./module-bases/SchedulingBase.sol"; +import { ERC7484RegistryAdapter } from "./module-bases/ERC7484RegistryAdapter.sol"; + +// Policies +import { ERC7579PolicyBase } from "./module-bases/ERC7579PolicyBase.sol"; +import { ERC1271Policy } from "./module-bases/ERC1271Policy.sol"; +import { ERC7579ActionPolicy } from "./module-bases/ERC7579ActionPolicy.sol"; +import { ERC7579UserOpPolicy } from "./module-bases/ERC7579UserOpPolicy.sol"; + +/*////////////////////////////////////////////////////////////// + UTIL +//////////////////////////////////////////////////////////////*/ + +import { TrustedForwarder } from "./module-bases/utils/TrustedForwarder.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC4337Account.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC4337Account.sol new file mode 100644 index 0000000..78510c4 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC4337Account.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { PackedUserOperation } from + "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; + +interface IERC4337Account { + /** + * Validate user's signature and nonce + * the entryPoint will make the call to the recipient only if this validation call returns + * successfully. + * signature failure should be reported by returning SIG_VALIDATION_FAILED (1). + * This allows making a "simulation call" without a valid signature + * Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to + * signal failure. + * + * @dev Must validate caller is the entryPoint. + * Must validate the signature and nonce + * @param userOp - The operation that is about to be executed. + * @param userOpHash - Hash of the user's request data. can be used as the basis for + * signature. + * @param missingAccountFunds - Missing funds on the account's deposit in the entrypoint. + * This is the minimum amount to transfer to the sender(entryPoint) + * to be + * able to make the call. The excess is left as a deposit in the + * entrypoint + * for future calls. Can be withdrawn anytime using + * "entryPoint.withdrawTo()". + * In case there is a paymaster in the request (or the current + * deposit is high + * enough), this value will be zero. + * @return validationData - Packaged ValidationData structure. use `_packValidationData` + * and + * `_unpackValidationData` to encode and decode. + * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark + * signature failure, + * otherwise, an address of an "authorizer" contract. + * <6-byte> validUntil - Last timestamp this operation is valid. 0 + * for "indefinite" + * <6-byte> validAfter - First timestamp this operation is valid + * If an account doesn't use time-range, it + * is enough to + * return SIG_VALIDATION_FAILED value (1) for + * signature failure. + * Note that the validation code cannot use block.timestamp (or + * block.number) directly. + */ + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash, + uint256 missingAccountFunds + ) + external + payable + returns (uint256 validationData); + + /** + * Account may implement this execute method. + * passing this methodSig at the beginning of callData will cause the entryPoint to pass the + * full UserOp (and hash) + * to the account. + * The account should skip the methodSig, and use the callData (and optionally, other UserOp + * fields) + * + * @param userOp - The operation that was just validated. + * @param userOpHash - Hash of the user's request data. + */ + function executeUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + payable; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Account.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Account.sol new file mode 100644 index 0000000..6bf4db0 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Account.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/* solhint-disable no-unused-import */ + +// Types +import { CallType, ExecType, ModeCode } from "../lib/ModeLib.sol"; + +// Structs +struct Execution { + address target; + uint256 value; + bytes callData; +} + +interface IERC7579Account { + event ModuleInstalled(uint256 moduleTypeId, address module); + event ModuleUninstalled(uint256 moduleTypeId, address module); + + /** + * @dev Executes a transaction on behalf of the account. + * This function is intended to be called by ERC-4337 EntryPoint.sol + * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf + * + * @dev MSA MUST implement this function signature. + * If a mode is requested that is not supported by the Account, it MUST revert + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data + */ + function execute(ModeCode mode, bytes calldata executionCalldata) external payable; + + /** + * @dev Executes a transaction on behalf of the account. + * This function is intended to be called by Executor Modules + * @dev Ensure adequate authorization control: i.e. onlyExecutorModule + * + * @dev MSA MUST implement this function signature. + * If a mode is requested that is not supported by the Account, it MUST revert + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data + */ + function executeFromExecutor( + ModeCode mode, + bytes calldata executionCalldata + ) + external + payable + returns (bytes[] memory returnData); + + /** + * @dev ERC-1271 isValidSignature + * This function is intended to be used to validate a smart account signature + * and may forward the call to a validator module + * + * @param hash The hash of the data that is signed + * @param data The data that is signed + */ + function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4); + + /** + * @dev installs a Module of a certain type on the smart account + * @dev Implement Authorization control of your chosing + * @param moduleTypeId the module type ID according the ERC-7579 spec + * @param module the module address + * @param initData arbitrary data that may be required on the module during `onInstall` + * initialization. + */ + function installModule( + uint256 moduleTypeId, + address module, + bytes calldata initData + ) + external + payable; + + /** + * @dev uninstalls a Module of a certain type on the smart account + * @dev Implement Authorization control of your chosing + * @param moduleTypeId the module type ID according the ERC-7579 spec + * @param module the module address + * @param deInitData arbitrary data that may be required on the module during `onUninstall` + * de-initialization. + */ + function uninstallModule( + uint256 moduleTypeId, + address module, + bytes calldata deInitData + ) + external + payable; + + /** + * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol) + * @param encodedMode the encoded mode + */ + function supportsExecutionMode(ModeCode encodedMode) external view returns (bool); + + /** + * Function to check if the account supports installation of a certain module type Id + * @param moduleTypeId the module type ID according the ERC-7579 spec + */ + function supportsModule(uint256 moduleTypeId) external view returns (bool); + + /** + * Function to check if the account has a certain module installed + * @param moduleTypeId the module type ID according the ERC-7579 spec + * Note: keep in mind that some contracts can be multiple module types at the same time. It + * thus may be necessary to query multiple module types + * @param module the module address + * @param additionalContext additional context data that the smart account may interpret to + * identifiy conditions under which the module is installed. + * usually this is not necessary, but for some special hooks that + * are stored in mappings, this param might be needed + */ + function isModuleInstalled( + uint256 moduleTypeId, + address module, + bytes calldata additionalContext + ) + external + view + returns (bool); + + /** + * @dev Returns the account id of the smart account + * @return accountImplementationId the account id of the smart account + * the accountId should be structured like so: + * "vendorname.accountname.semver" + */ + function accountId() external view returns (string memory accountImplementationId); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Module.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Module.sol new file mode 100644 index 0000000..25990c6 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Module.sol @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { PackedUserOperation } from + "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; + +// Constants +uint256 constant VALIDATION_SUCCESS = 0; +uint256 constant VALIDATION_FAILED = 1; +uint256 constant MODULE_TYPE_VALIDATOR = 1; +uint256 constant MODULE_TYPE_EXECUTOR = 2; +uint256 constant MODULE_TYPE_FALLBACK = 3; +uint256 constant MODULE_TYPE_HOOK = 4; +uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC1271 = 8; +uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC4337 = 9; + +interface IModule { + error ModuleAlreadyInitialized(address smartAccount); + error NotInitialized(address smartAccount); + + /** + * @dev This function is called by the smart account during installation of the module + * @param data arbitrary data that may be required on the module during `onInstall` + * initialization + * + * MUST revert on error (i.e. if module is already enabled) + */ + function onInstall(bytes calldata data) external; + + /** + * @dev This function is called by the smart account during uninstallation of the module + * @param data arbitrary data that may be required on the module during `onUninstall` + * de-initialization + * + * MUST revert on error + */ + function onUninstall(bytes calldata data) external; + + /** + * @dev Returns boolean value if module is a certain type + * @param moduleTypeId the module type ID according the ERC-7579 spec + * + * MUST return true if the module is of the given type and false otherwise + */ + function isModuleType(uint256 moduleTypeId) external view returns (bool); + + /** + * @dev Returns if the module was already initialized for a provided smartaccount + */ + function isInitialized(address smartAccount) external view returns (bool); +} + +interface IValidator is IModule { + error InvalidTargetAddress(address target); + + /** + * @dev Validates a transaction on behalf of the account. + * This function is intended to be called by the MSA during the ERC-4337 validaton phase + * Note: solely relying on bytes32 hash and signature is not sufficient for some + * validation implementations (i.e. SessionKeys often need access to userOp.calldata) + * @param userOp The user operation to be validated. The userOp MUST NOT contain any metadata. + * The MSA MUST clean up the userOp before sending it to the validator. + * @param userOpHash The hash of the user operation to be validated + * @return return value according to ERC-4337 + */ + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + payable + returns (uint256); + + /** + * Validator can be used for ERC-1271 validation + */ + function isValidSignatureWithSender( + address sender, + bytes32 hash, + bytes calldata data + ) + external + view + returns (bytes4); +} + +interface IExecutor is IModule { } + +interface IHook is IModule { + function preCheck( + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + external + returns (bytes memory hookData); + + function postCheck(bytes calldata hookData) external; +} + +interface IFallback is IModule { } + +interface IPolicy is IModule { + function checkUserOpPolicy( + bytes32 id, + PackedUserOperation calldata userOp + ) + external + payable + returns (uint256); + function checkSignaturePolicy( + bytes32 id, + address sender, + bytes32 hash, + bytes calldata sig + ) + external + view + returns (uint256); +} + +interface ISigner is IModule { + function checkUserOpSignature( + bytes32 id, + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + payable + returns (uint256); + function checkSignature( + bytes32 id, + address sender, + bytes32 hash, + bytes calldata sig + ) + external + view + returns (bytes4); +} + +interface IPreValidationHookERC1271 is IModule { + function preValidationHookERC1271( + address sender, + bytes32 hash, + bytes calldata data + ) + external + view + returns (bytes32 hookHash, bytes memory hookSignature); +} + +interface IPreValidationHookERC4337 is IModule { + function preValidationHookERC4337( + PackedUserOperation calldata userOp, + uint256 missingAccountFunds, + bytes32 userOpHash + ) + external + returns (bytes32 hookHash, bytes memory hookSignature); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/common/lib/ModeLib.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/common/lib/ModeLib.sol new file mode 100644 index 0000000..4500cd6 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/common/lib/ModeLib.sol @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +/** + * @title ModeLib + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) + * To allow smart accounts to be very simple, but allow for more complex execution, A custom mode + * encoding is used. + * Function Signature of execute function: + * function execute(ModeCode mode, bytes calldata executionCalldata) external payable; + * This allows for a single bytes32 to be used to encode the execution mode, calltype, execType and + * context. + * NOTE: Simple Account implementations only have to scope for the most significant byte. Account that + * implement + * more complex execution modes may use the entire bytes32. + * + * |--------------------------------------------------------------------| + * | CALLTYPE | EXECTYPE | UNUSED | ModeSelector | ModePayload | + * |--------------------------------------------------------------------| + * | 1 byte | 1 byte | 4 bytes | 4 bytes | 22 bytes | + * |--------------------------------------------------------------------| + * + * CALLTYPE: 1 byte + * CallType is used to determine how the executeCalldata paramter of the execute function has to be + * decoded. + * It can be either single, batch or delegatecall. In the future different calls could be added. + * CALLTYPE can be used by a validation module to determine how to decode . + * + * EXECTYPE: 1 byte + * ExecType is used to determine how the account should handle the execution. + * It can indicate if the execution should revert on failure or continue execution. + * In the future more execution modes may be added. + * Default Behavior (EXECTYPE = 0x00) is to revert on a single failed execution. If one execution in + * a batch fails, the entire batch is reverted + * + * UNUSED: 4 bytes + * Unused bytes are reserved for future use. + * + * ModeSelector: bytes4 + * The "optional" mode selector can be used by account vendors, to implement custom behavior in + * their accounts. + * the way a ModeSelector is to be calculated is bytes4(keccak256("vendorname.featurename")) + * this is to prevent collisions between different vendors, while allowing innovation and the + * development of new features without coordination between ERC-7579 implementing accounts + * + * ModePayload: 22 bytes + * Mode payload is used to pass additional data to the smart account execution, this may be + * interpreted depending on the ModeSelector + * + * ExecutionCallData: n bytes + * single, delegatecall or batch exec abi.encoded as bytes + */ + +// Custom type for improved developer experience +type ModeCode is bytes32; + +type CallType is bytes1; + +type ExecType is bytes1; + +type ModeSelector is bytes4; + +type ModePayload is bytes22; + +// Default CallType +CallType constant CALLTYPE_SINGLE = CallType.wrap(0x00); +// Batched CallType +CallType constant CALLTYPE_BATCH = CallType.wrap(0x01); +CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); +// @dev Implementing delegatecall is OPTIONAL! +// implement delegatecall with extreme care. +CallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF); + +// @dev default behavior is to revert on failure +// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure +// Since this is value 0x00, no additional encoding is required for simple accounts +ExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00); +// @dev account may elect to change execution behavior. For example "try exec" / "allow fail" +ExecType constant EXECTYPE_TRY = ExecType.wrap(0x01); + +ModeSelector constant MODE_DEFAULT = ModeSelector.wrap(bytes4(0x00000000)); +// Example declaration of a custom mode selector +ModeSelector constant MODE_OFFSET = ModeSelector.wrap(bytes4(keccak256("default.mode.offset"))); + +/** + * @dev ModeLib is a helper library to encode/decode ModeCodes + */ +library ModeLib { + function decode(ModeCode mode) + internal + pure + returns ( + CallType _calltype, + ExecType _execType, + ModeSelector _modeSelector, + ModePayload _modePayload + ) + { + // solhint-disable-next-line no-inline-assembly + assembly { + _calltype := mode + _execType := shl(8, mode) + _modeSelector := shl(48, mode) + _modePayload := shl(80, mode) + } + } + + function encode( + CallType callType, + ExecType execType, + ModeSelector mode, + ModePayload payload + ) + internal + pure + returns (ModeCode) + { + return ModeCode.wrap( + bytes32( + abi.encodePacked(callType, execType, bytes4(0), ModeSelector.unwrap(mode), payload) + ) + ); + } + + function encodeSimpleBatch() internal pure returns (ModeCode mode) { + mode = encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00)); + } + + function encodeSimpleSingle() internal pure returns (ModeCode mode) { + mode = encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00)); + } + + function getCallType(ModeCode mode) internal pure returns (CallType calltype) { + // solhint-disable-next-line no-inline-assembly + assembly { + calltype := mode + } + } +} + +using { eqModeSelector as == } for ModeSelector global; +using { eqCallType as == } for CallType global; +using { neqCallType as != } for CallType global; +using { eqExecType as == } for ExecType global; + +function eqCallType(CallType a, CallType b) pure returns (bool) { + return CallType.unwrap(a) == CallType.unwrap(b); +} + +function neqCallType(CallType a, CallType b) pure returns (bool) { + return CallType.unwrap(a) == CallType.unwrap(b); +} + +function eqExecType(ExecType a, ExecType b) pure returns (bool) { + return ExecType.unwrap(a) == ExecType.unwrap(b); +} + +function eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) { + return ModeSelector.unwrap(a) == ModeSelector.unwrap(b); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/ERC7579Factory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/ERC7579Factory.sol new file mode 100644 index 0000000..073078d --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/ERC7579Factory.sol @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IAccountFactory } from "../../accounts/factory/interface/IAccountFactory.sol"; +import { IMSA } from "./interfaces/IMSA.sol"; +import { IERC7579Account } from "../../accounts/common/interfaces/IERC7579Account.sol"; +import { + IERC7579Bootstrap, + BootstrapConfig as ERC7579BootstrapConfig +} from "../../accounts/erc7579/interfaces/IERC7579Bootstrap.sol"; + +// Precompiles +import { ERC7579Precompiles } from "../../deployment/precompiles/ERC7579Precompiles.sol"; + +contract ERC7579Factory is IAccountFactory, ERC7579Precompiles { + IERC7579Account public implementation; + IERC7579Bootstrap public bootstrapDefault; + + function init() public override { + implementation = deployERC7579Account(); + bootstrapDefault = deployERC7579Bootstrap(); + } + + function createAccount(bytes32 salt, bytes memory initCode) public override returns (address) { + return deployMSAPRoxy(salt, address(implementation), initCode); + } + + function createAccountWithModules( + bytes32 salt, + ERC7579BootstrapConfig[] calldata validators, + ERC7579BootstrapConfig[] calldata executors, + ERC7579BootstrapConfig calldata _fallback, + ERC7579BootstrapConfig[] calldata hooks + ) + public + payable + virtual + returns (address) + { + bytes memory initData = abi.encode( + bootstrapDefault, + abi.encodeCall(IERC7579Bootstrap.initMSA, (validators, executors, _fallback, hooks)) + ); + + address account = deployMSAPRoxy(salt, address(implementation), initData); + + return account; + } + + function getInitData(bytes memory initCode) public view returns (bytes memory _init) { + ( + ERC7579BootstrapConfig[] memory _validators, + ERC7579BootstrapConfig[] memory _executors, + ERC7579BootstrapConfig memory hook, + ERC7579BootstrapConfig[] memory fallbacks + ) = abi.decode( + initCode, + ( + ERC7579BootstrapConfig[], + ERC7579BootstrapConfig[], + ERC7579BootstrapConfig, + ERC7579BootstrapConfig[] + ) + ); + _init = abi.encode( + address(bootstrapDefault), + abi.encodeCall(IERC7579Bootstrap.initMSA, (_validators, _executors, hook, fallbacks)) + ); + } + + function getInitData( + IAccountFactory.ModuleInitData[] memory _validators, + IAccountFactory.ModuleInitData[] memory _executors, + IAccountFactory.ModuleInitData memory _hook, + IAccountFactory.ModuleInitData[] memory _fallbacks + ) + public + view + returns (bytes memory _init) + { + ERC7579BootstrapConfig[] memory validators = + abi.decode(abi.encode(_validators), (ERC7579BootstrapConfig[])); + ERC7579BootstrapConfig[] memory executors = + abi.decode(abi.encode(_executors), (ERC7579BootstrapConfig[])); + ERC7579BootstrapConfig memory hook = abi.decode(abi.encode(_hook), (ERC7579BootstrapConfig)); + ERC7579BootstrapConfig[] memory fallbacks = + abi.decode(abi.encode(_fallbacks), (ERC7579BootstrapConfig[])); + + _init = abi.encode( + address(bootstrapDefault), + abi.encodeCall(IERC7579Bootstrap.initMSA, (validators, executors, hook, fallbacks)) + ); + } + + function getAddress( + bytes32 salt, + bytes memory initCode + ) + public + view + override + returns (address) + { + bytes32 hash = keccak256( + abi.encodePacked( + bytes1(0xff), + address(this), + salt, + keccak256( + abi.encodePacked( + MSAPROXY_BYTECODE, + abi.encode( + address(implementation), + abi.encodeCall(IMSA.initializeAccount, initCode) + ) + ) + ) + ) + ); + + return address(uint160(uint256(hash))); + } + + function getInitData( + address validator, + bytes memory initData + ) + public + view + override + returns (bytes memory _init) + { + ERC7579BootstrapConfig[] memory _validators = new ERC7579BootstrapConfig[](1); + _validators[0].module = validator; + _validators[0].data = initData; + ERC7579BootstrapConfig[] memory _executors = new ERC7579BootstrapConfig[](0); + + ERC7579BootstrapConfig memory _hook; + + ERC7579BootstrapConfig[] memory _fallBacks = new ERC7579BootstrapConfig[](0); + _init = abi.encode( + address(bootstrapDefault), + abi.encodeCall(IERC7579Bootstrap.initMSA, (_validators, _executors, _hook, _fallBacks)) + ); + } + + function _getSalt(bytes32 _salt, bytes memory initCode) internal pure returns (bytes32 salt) { + salt = keccak256(abi.encodePacked(_salt, initCode)); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/helpers/ExecutionHelper.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/helpers/ExecutionHelper.sol new file mode 100644 index 0000000..2f803af --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/helpers/ExecutionHelper.sol @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +// Types +import { Execution } from "../../common/interfaces/IERC7579Account.sol"; + +/** + * @title Execution + * @dev This contract executes calls in the context of this contract. + * @author zeroknots.eth | rhinestone.wtf + * shoutout to solady (vectorized, ross) for this code + * https://github.com/Vectorized/solady/blob/main/src/accounts/ERC4337.sol + */ +contract ExecutionHelper { + error ExecutionFailed(); + + event TryExecuteUnsuccessful(uint256 batchExecutionindex, bytes result); + + function _execute(Execution[] calldata executions) internal returns (bytes[] memory result) { + uint256 length = executions.length; + result = new bytes[](length); + + for (uint256 i; i < length; i++) { + Execution calldata _exec = executions[i]; + result[i] = _execute(_exec.target, _exec.value, _exec.callData); + } + } + + function _tryExecute(Execution[] calldata executions) + internal + returns (bytes[] memory result) + { + uint256 length = executions.length; + result = new bytes[](length); + + for (uint256 i; i < length; i++) { + Execution calldata _exec = executions[i]; + bool success; + (success, result[i]) = _tryExecute(_exec.target, _exec.value, _exec.callData); + if (!success) emit TryExecuteUnsuccessful(i, result[i]); + } + } + + function _execute( + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + returns (bytes memory result) + { + /// @solidity memory-safe-assembly + // solhint-disable-next-line no-inline-assembly + assembly { + result := mload(0x40) + calldatacopy(result, callData.offset, callData.length) + if iszero(call(gas(), target, value, result, callData.length, codesize(), 0x00)) { + // Bubble up the revert if the call reverts. + returndatacopy(result, 0x00, returndatasize()) + revert(result, returndatasize()) + } + mstore(result, returndatasize()) // Store the length. + let o := add(result, 0x20) + returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. + mstore(0x40, add(o, returndatasize())) // Allocate the memory. + } + } + + function _tryExecute( + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + returns (bool success, bytes memory result) + { + /// @solidity memory-safe-assembly + // solhint-disable-next-line no-inline-assembly + assembly { + result := mload(0x40) + calldatacopy(result, callData.offset, callData.length) + success := call(gas(), target, value, result, callData.length, codesize(), 0x00) + mstore(result, returndatasize()) // Store the length. + let o := add(result, 0x20) + returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. + mstore(0x40, add(o, returndatasize())) // Allocate the memory. + } + } + + /// @dev Execute a delegatecall with `delegate` on this account. + function _executeDelegatecall( + address delegate, + bytes calldata callData + ) + internal + returns (bytes memory result) + { + /// @solidity memory-safe-assembly + // solhint-disable-next-line no-inline-assembly + assembly { + result := mload(0x40) + calldatacopy(result, callData.offset, callData.length) + // Forwards the `data` to `delegate` via delegatecall. + if iszero(delegatecall(gas(), delegate, result, callData.length, codesize(), 0x00)) { + // Bubble up the revert if the call reverts. + returndatacopy(result, 0x00, returndatasize()) + revert(result, returndatasize()) + } + mstore(result, returndatasize()) // Store the length. + let o := add(result, 0x20) + returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. + mstore(0x40, add(o, returndatasize())) // Allocate the memory. + } + } + + /// @dev Execute a delegatecall with `delegate` on this account and catch reverts. + function _tryExecuteDelegatecall( + address delegate, + bytes calldata callData + ) + internal + returns (bool success, bytes memory result) + { + /// @solidity memory-safe-assembly + // solhint-disable-next-line no-inline-assembly + assembly { + result := mload(0x40) + calldatacopy(result, callData.offset, callData.length) + // Forwards the `data` to `delegate` via delegatecall. + success := delegatecall(gas(), delegate, result, callData.length, codesize(), 0x00) + mstore(result, returndatasize()) // Store the length. + let o := add(result, 0x20) + returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. + mstore(0x40, add(o, returndatasize())) // Allocate the memory. + } + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IERC7579Bootstrap.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IERC7579Bootstrap.sol new file mode 100644 index 0000000..727a85e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IERC7579Bootstrap.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IModule } from "../../common/interfaces/IERC7579Module.sol"; + +// Structs +struct BootstrapConfig { + address module; + bytes data; +} + +interface IERC7579Bootstrap { + function singleInitMSA(IModule validator, bytes calldata data) external; + + /** + * This function is intended to be called by the MSA with a delegatecall. + * Make sure that the MSA already initilazed the linked lists in the ModuleManager prior to + * calling this function + */ + function initMSA( + BootstrapConfig[] calldata $valdiators, + BootstrapConfig[] calldata $executors, + BootstrapConfig calldata _hook, + BootstrapConfig[] calldata _fallbacks + ) + external; + + function _getInitMSACalldata( + BootstrapConfig[] calldata $valdiators, + BootstrapConfig[] calldata $executors, + BootstrapConfig calldata _hook, + BootstrapConfig[] calldata _fallbacks + ) + external + view + returns (bytes memory init); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IMSA.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IMSA.sol new file mode 100644 index 0000000..12a7810 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IMSA.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IERC7579Account } from "../../common/interfaces/IERC7579Account.sol"; +import { IERC4337Account } from "../../common/interfaces/IERC4337Account.sol"; + +// Types +import { CallType, ExecType } from "../../common/lib/ModeLib.sol"; + +interface IMSA is IERC7579Account, IERC4337Account { + // Error thrown when an unsupported ModuleType is requested + error UnsupportedModuleType(uint256 moduleTypeId); + // Error thrown when an execution with an unsupported CallType was made + error UnsupportedCallType(CallType callType); + // Error thrown when an execution with an unsupported ExecType was made + error UnsupportedExecType(ExecType execType); + // Error thrown when account initialization fails + error AccountInitializationFailed(); + // Error thrown when account installs/unistalls module with mismatched input `moduleTypeId` + error MismatchModuleTypeId(uint256 moduleTypeId); + + /** + * @dev Initializes the account. Function might be called directly, or by a Factory + * @param data. encoded data that can be used during the initialization phase + */ + function initializeAccount(bytes calldata data) external payable; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/lib/ExecutionLib.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/lib/ExecutionLib.sol new file mode 100644 index 0000000..862e39e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/lib/ExecutionLib.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { Execution } from "../../common/interfaces/IERC7579Account.sol"; + +/** + * Helper Library for decoding Execution calldata + * malloc for memory allocation is bad for gas. use this assembly instead + */ +library ExecutionLib { + error ERC7579DecodingError(); + + /** + * @notice Decode a batch of `Execution` executionBatch from a `bytes` calldata. + * @dev code is copied from solady's LibERC7579.sol + * https://github.com/Vectorized/solady/blob/740812cedc9a1fc11e17cb3d4569744367dedf19/src/accounts/LibERC7579.sol#L146 + * Credits to Vectorized and the Solady Team + */ + function decodeBatch(bytes calldata executionCalldata) + internal + pure + returns (Execution[] calldata executionBatch) + { + /// @solidity memory-safe-assembly + assembly { + let u := calldataload(executionCalldata.offset) + let s := add(executionCalldata.offset, u) + let e := sub(add(executionCalldata.offset, executionCalldata.length), 0x20) + executionBatch.offset := add(s, 0x20) + executionBatch.length := calldataload(s) + if or(shr(64, u), gt(add(s, shl(5, executionBatch.length)), e)) { + mstore(0x00, 0xba597e7e) // `DecodingError()`. + revert(0x1c, 0x04) + } + if executionBatch.length { + // Perform bounds checks on the decoded `executionBatch`. + // Loop runs out-of-gas if `executionBatch.length` is big enough to cause overflows. + for { let i := executionBatch.length } 1 { } { + i := sub(i, 1) + let p := calldataload(add(executionBatch.offset, shl(5, i))) + let c := add(executionBatch.offset, p) + let q := calldataload(add(c, 0x40)) + let o := add(c, q) + // forgefmt: disable-next-item + if or(shr(64, or(calldataload(o), or(p, q))), + or(gt(add(c, 0x40), e), gt(add(o, calldataload(o)), e))) { + mstore(0x00, 0xba597e7e) // `DecodingError()`. + revert(0x1c, 0x04) + } + if iszero(i) { break } + } + } + } + } + + function encodeBatch(Execution[] memory executions) + internal + pure + returns (bytes memory callData) + { + callData = abi.encode(executions); + } + + function decodeSingle(bytes calldata executionCalldata) + internal + pure + returns (address target, uint256 value, bytes calldata callData) + { + target = address(bytes20(executionCalldata[0:20])); + value = uint256(bytes32(executionCalldata[20:52])); + callData = executionCalldata[52:]; + } + + function encodeSingle( + address target, + uint256 value, + bytes memory callData + ) + internal + pure + returns (bytes memory userOpCalldata) + { + userOpCalldata = abi.encodePacked(target, value, callData); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/factory/interface/IAccountFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/factory/interface/IAccountFactory.sol new file mode 100644 index 0000000..5bbb32a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/factory/interface/IAccountFactory.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +interface IAccountFactory { + struct ModuleInitData { + address module; + bytes data; + } + + function init() external; + + function createAccount( + bytes32 salt, + bytes memory initCode + ) + external + returns (address account); + + function getAddress(bytes32 salt, bytes memory initCode) external returns (address); + + function getInitData( + address validator, + bytes memory initData + ) + external + returns (bytes memory init); + + function getInitData( + IAccountFactory.ModuleInitData[] memory validators, + IAccountFactory.ModuleInitData[] memory executors, + IAccountFactory.ModuleInitData memory hook, + IAccountFactory.ModuleInitData[] memory fallbacks + ) + external + returns (bytes memory _init); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/factory/template/FactoryTemplate.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/factory/template/FactoryTemplate.sol new file mode 100644 index 0000000..9a5d4ba --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/factory/template/FactoryTemplate.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +abstract contract FactoryTemplate { + constructor() { + // Deploy any required contracts + } + + function createAccountName( + bytes32 salt, + bytes memory initCode + ) + public + returns (address account) + { + // Deploy the account + } + + function getAddressAccountName( + bytes32 salt, + bytes memory initCode + ) + public + view + returns (address) + { + // Return the address of the account + } + + function getInitDataAccountName( + address validator, + bytes memory initData + ) + public + returns (bytes memory init) + { + // Return the init data + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/KernelFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/KernelFactory.sol new file mode 100644 index 0000000..3803ae9 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/KernelFactory.sol @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +import { IKernelFactory as IKernelAccountFactory } from + "../../accounts/kernel/interfaces/IKernelFactory.sol"; +import { IKernel } from "../../accounts/kernel/interfaces/IKernel.sol"; +import { ENTRYPOINT_ADDR } from "../../deployment/predeploy/EntryPoint.sol"; +import { ValidatorLib } from "../../accounts/kernel/lib/ValidationTypeLib.sol"; +import { ValidationId } from "../../accounts/kernel/types/Types.sol"; +import { IValidator } from "../../accounts/common/interfaces/IERC7579Module.sol"; +import { IHook } from "../../accounts/kernel/interfaces/IERC7579Module.sol"; +import { IAccountFactory } from "../../accounts/factory/interface/IAccountFactory.sol"; +import { MockHookMultiPlexer } from "../../Mocks.sol"; +import { KernelPrecompiles } from "../../deployment/precompiles/KernelPrecompiles.sol"; +import { + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK +} from "./types/Constants.sol"; + +struct ModuleBootstrapConfig { + address module; + bytes initData; +} + +contract KernelFactory is IAccountFactory, KernelPrecompiles { + IKernelAccountFactory public factory; + IKernel public kernelImpl; + MockHookMultiPlexer public hookMultiPlexer; + + function init() public override { + kernelImpl = deployKernel(ENTRYPOINT_ADDR); + factory = deployKernelFactory(address(kernelImpl)); + hookMultiPlexer = new MockHookMultiPlexer(); + } + + function createAccount( + bytes32 salt, + bytes memory data + ) + public + override + returns (address account) + { + account = factory.createAccount(data, salt); + } + + function getAddress(bytes32 salt, bytes memory data) public override returns (address) { + return factory.getAddress(data, salt); + } + + function getInitData( + address validator, + bytes memory initData + ) + public + view + override + returns (bytes memory _init) + { + ValidationId rootValidator = ValidatorLib.validatorToIdentifier(IValidator(validator)); + + _init = abi.encodeCall( + IKernel.initialize, + (rootValidator, IHook(address(hookMultiPlexer)), initData, hex"00", new bytes[](0)) + ); + } + + function getInitData( + IAccountFactory.ModuleInitData[] memory validators, + IAccountFactory.ModuleInitData[] memory executors, + IAccountFactory.ModuleInitData memory hook, + IAccountFactory.ModuleInitData[] memory fallbacks + ) + public + pure + override + returns (bytes memory _init) + { + address[] memory attesters = new address[](1); + attesters[0] = address(0x000000333034E9f539ce08819E12c1b8Cb29084d); + + ValidationId rootValidator = + ValidatorLib.validatorToIdentifier(IValidator(validators[0].module)); + // Encode the rest of the validators, executors and fallbacks are onInstall calls with the + // appropriate address and initData + bytes[] memory otherModules = + new bytes[](validators.length - 1 + executors.length + fallbacks.length); + uint256 index = 0; + for (uint256 i = 1; i < validators.length; i++) { + otherModules[index] = abi.encodeCall( + IKernel.installModule, + (MODULE_TYPE_VALIDATOR, validators[i].module, validators[i].data) + ); + index++; + } + for (uint256 i = 0; i < executors.length; i++) { + otherModules[index] = abi.encodeCall( + IKernel.installModule, + (MODULE_TYPE_EXECUTOR, executors[i].module, executors[i].data) + ); + index++; + } + for (uint256 i = 0; i < fallbacks.length; i++) { + otherModules[index] = abi.encodeCall( + IKernel.installModule, + (MODULE_TYPE_FALLBACK, fallbacks[i].module, fallbacks[i].data) + ); + index++; + } + _init = abi.encodeCall( + IKernel.initialize, + ( + rootValidator, + IHook(address(hook.module)), + validators[0].data, + hook.data, + otherModules + ) + ); + } + + function getInitData(bytes memory initData) public pure returns (bytes memory _init) { + ( + ModuleBootstrapConfig[] memory validators, + ModuleBootstrapConfig[] memory executors, + ModuleBootstrapConfig memory hook, + ModuleBootstrapConfig[] memory fallbacks + ) = abi.decode( + initData, + ( + ModuleBootstrapConfig[], + ModuleBootstrapConfig[], + ModuleBootstrapConfig, + ModuleBootstrapConfig[] + ) + ); + ValidationId rootValidator = + ValidatorLib.validatorToIdentifier(IValidator(validators[0].module)); + // Encode the rest of the validators, executors and fallbacks are onInstall calls with the + // appropriate address and initData + bytes[] memory otherModules = + new bytes[](validators.length - 1 + executors.length + fallbacks.length); + uint256 index = 0; + for (uint256 i = 1; i < validators.length; i++) { + otherModules[index] = abi.encodeCall( + IKernel.installModule, + (MODULE_TYPE_VALIDATOR, validators[i].module, validators[i].initData) + ); + index++; + } + for (uint256 i = 0; i < executors.length; i++) { + otherModules[index] = abi.encodeCall( + IKernel.installModule, + (MODULE_TYPE_EXECUTOR, executors[i].module, executors[i].initData) + ); + index++; + } + for (uint256 i = 0; i < fallbacks.length; i++) { + otherModules[index] = abi.encodeCall( + IKernel.installModule, + (MODULE_TYPE_FALLBACK, fallbacks[i].module, fallbacks[i].initData) + ); + index++; + } + _init = abi.encodeCall( + IKernel.initialize, + ( + rootValidator, + IHook(address(hook.module)), + validators[0].initData, + hook.initData, + otherModules + ) + ); + } + + function setHookMultiPlexer(address hook) public { + hookMultiPlexer = MockHookMultiPlexer(hook); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccount.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccount.sol new file mode 100644 index 0000000..3c071f5 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccount.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { PackedUserOperation } from + "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; +import "../types/Types.sol"; + +interface IAccount { + /** + * Validate user's signature and nonce + * the entryPoint will make the call to the recipient only if this validation call returns + * successfully. + * signature failure should be reported by returning SIG_VALIDATION_FAILED (1). + * This allows making a "simulation call" without a valid signature + * Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to + * signal failure. + * + * @dev Must validate caller is the entryPoint. + * Must validate the signature and nonce + * @param userOp - The operation that is about to be executed. + * @param userOpHash - Hash of the user's request data. can be used as the basis for + * signature. + * @param missingAccountFunds - Missing funds on the account's deposit in the entrypoint. + * This is the minimum amount to transfer to the sender(entryPoint) + * to be + * able to make the call. The excess is left as a deposit in the + * entrypoint + * for future calls. Can be withdrawn anytime using + * "entryPoint.withdrawTo()". + * In case there is a paymaster in the request (or the current + * deposit is high + * enough), this value will be zero. + * @return validationData - Packaged ValidationData structure. use `_packValidationData` + * and + * `_unpackValidationData` to encode and decode. + * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark + * signature failure, + * otherwise, an address of an "authorizer" contract. + * <6-byte> validUntil - Last timestamp this operation is valid. 0 + * for "indefinite" + * <6-byte> validAfter - First timestamp this operation is valid + * If an account doesn't use time-range, it + * is enough to + * return SIG_VALIDATION_FAILED value (1) for + * signature failure. + * Note that the validation code cannot use block.timestamp (or + * block.number) directly. + */ + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash, + uint256 missingAccountFunds + ) + external + payable + returns (ValidationData validationData); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccountExecute.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccountExecute.sol new file mode 100644 index 0000000..ca16aa4 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccountExecute.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { PackedUserOperation } from + "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; + +interface IAccountExecute { + /** + * Account may implement this execute method. + * passing this methodSig at the beginning of callData will cause the entryPoint to pass the + * full UserOp (and hash) + * to the account. + * The account should skip the methodSig, and use the callData (and optionally, other UserOp + * fields) + * + * @param userOp - The operation that was just validated. + * @param userOpHash - Hash of the user's request data. + */ + function executeUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + payable; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Account.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Account.sol new file mode 100644 index 0000000..b4080e5 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Account.sol @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/* solhint-disable no-unused-import */ + +// Types +import { CallType, ExecType, ExecMode } from "../lib/ExecLib.sol"; +import { PackedUserOperation } from + "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; + +// Structs +struct Execution { + address target; + uint256 value; + bytes callData; +} + +interface IERC7579Account { + event ModuleInstalled(uint256 moduleTypeId, address module); + event ModuleUninstalled(uint256 moduleTypeId, address module); + + /** + * @dev Executes a transaction on behalf of the account. + * This function is intended to be called by ERC-4337 EntryPoint.sol + * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf + * + * @dev MSA MUST implement this function signature. + * If a mode is requested that is not supported by the Account, it MUST revert + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data + */ + function execute(ExecMode mode, bytes calldata executionCalldata) external payable; + + /** + * @dev Executes a transaction on behalf of the account. + * This function is intended to be called by Executor Modules + * @dev Ensure adequate authorization control: i.e. onlyExecutorModule + * + * @dev MSA MUST implement this function signature. + * If a mode is requested that is not supported by the Account, it MUST revert + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data + */ + function executeFromExecutor( + ExecMode mode, + bytes calldata executionCalldata + ) + external + payable + returns (bytes[] memory returnData); + + /** + * @dev ERC-1271 isValidSignature + * This function is intended to be used to validate a smart account signature + * and may forward the call to a validator module + * + * @param hash The hash of the data that is signed + * @param data The data that is signed + */ + function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4); + + /** + * @dev installs a Module of a certain type on the smart account + * @dev Implement Authorization control of your choosing + * @param moduleTypeId the module type ID according the ERC-7579 spec + * @param module the module address + * @param initData arbitrary data that may be required on the module during `onInstall` + * initialization. + */ + function installModule( + uint256 moduleTypeId, + address module, + bytes calldata initData + ) + external + payable; + + /** + * @dev uninstalls a Module of a certain type on the smart account + * @dev Implement Authorization control of your choosing + * @param moduleTypeId the module type ID according the ERC-7579 spec + * @param module the module address + * @param deInitData arbitrary data that may be required on the module during `onUninstall` + * de-initialization. + */ + function uninstallModule( + uint256 moduleTypeId, + address module, + bytes calldata deInitData + ) + external + payable; + + /** + * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol) + * @param encodedMode the encoded mode + */ + function supportsExecutionMode(ExecMode encodedMode) external view returns (bool); + + /** + * Function to check if the account supports installation of a certain module type Id + * @param moduleTypeId the module type ID according the ERC-7579 spec + */ + function supportsModule(uint256 moduleTypeId) external view returns (bool); + + /** + * Function to check if the account has a certain module installed + * @param moduleTypeId the module type ID according the ERC-7579 spec + * Note: keep in mind that some contracts can be multiple module types at the same time. It + * thus may be necessary to query multiple module types + * @param module the module address + * @param additionalContext additional context data that the smart account may interpret to + * identify conditions under which the module is installed. + * usually this is not necessary, but for some special hooks that + * are stored in mappings, this param might be needed + */ + function isModuleInstalled( + uint256 moduleTypeId, + address module, + bytes calldata additionalContext + ) + external + view + returns (bool); + + /** + * @dev Returns the account id of the smart account + * @return accountImplementationId the account id of the smart account + * the accountId should be structured like so: + * "vendorname.accountname.semver" + */ + function accountId() external view returns (string memory accountImplementationId); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Module.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Module.sol new file mode 100644 index 0000000..90a7272 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Module.sol @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +// Types +import { PackedUserOperation } from + "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; + +interface IModule { + error ModuleAlreadyInitialized(address smartAccount); + error NotInitialized(address smartAccount); + + /** + * @dev This function is called by the smart account during installation of the module + * @param data arbitrary data that may be required on the module during `onInstall` + * initialization + * + * MUST revert on error (i.e. if module is already enabled) + */ + function onInstall(bytes calldata data) external payable; + + /** + * @dev This function is called by the smart account during uninstallation of the module + * @param data arbitrary data that may be required on the module during `onUninstall` + * de-initialization + * + * MUST revert on error + */ + function onUninstall(bytes calldata data) external payable; + + /** + * @dev Returns boolean value if module is a certain type + * @param moduleTypeId the module type ID according the ERC-7579 spec + * + * MUST return true if the module is of the given type and false otherwise + */ + function isModuleType(uint256 moduleTypeId) external view returns (bool); + + /** + * @dev Returns if the module was already initialized for a provided smartaccount + */ + function isInitialized(address smartAccount) external view returns (bool); +} + +interface IValidator is IModule { + error InvalidTargetAddress(address target); + + /** + * @dev Validates a transaction on behalf of the account. + * This function is intended to be called by the MSA during the ERC-4337 validation + * phase + * Note: solely relying on bytes32 hash and signature is not sufficient for some + * validation implementations (i.e. SessionKeys often need access to userOp.calldata) + * @param userOp The user operation to be validated. The userOp MUST NOT contain any metadata. + * The MSA MUST clean up the userOp before sending it to the validator. + * @param userOpHash The hash of the user operation to be validated + * @return return value according to ERC-4337 + */ + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + payable + returns (uint256); + + /** + * Validator can be used for ERC-1271 validation + */ + function isValidSignatureWithSender( + address sender, + bytes32 hash, + bytes calldata data + ) + external + view + returns (bytes4); +} + +interface IExecutor is IModule { } + +interface IHook is IModule { + function preCheck( + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + external + payable + returns (bytes memory hookData); + + function postCheck(bytes calldata hookData) external payable; +} + +interface IFallback is IModule { } + +interface IPolicy is IModule { + function checkUserOpPolicy( + bytes32 id, + PackedUserOperation calldata userOp + ) + external + payable + returns (uint256); + function checkSignaturePolicy( + bytes32 id, + address sender, + bytes32 hash, + bytes calldata sig + ) + external + view + returns (uint256); +} + +interface ISigner is IModule { + function checkUserOpSignature( + bytes32 id, + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + payable + returns (uint256); + function checkSignature( + bytes32 id, + address sender, + bytes32 hash, + bytes calldata sig + ) + external + view + returns (bytes4); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernel.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernel.sol new file mode 100644 index 0000000..aa2b408 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernel.sol @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IERC7579Account } from "./IERC7579Account.sol"; +import { IAccount, ValidationData } from "./IAccount.sol"; +import { IAccountExecute } from "./IAccountExecute.sol"; +import { IHook } from "./IERC7579Module.sol"; + +// Types +import { ValidationId, ValidationConfig } from "../lib/ValidationTypeLib.sol"; +import { PackedUserOperation } from + "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; +import { ExecMode } from "../lib/ExecLib.sol"; + +interface IKernel is IAccount, IAccountExecute, IERC7579Account { + function initialize( + ValidationId _rootValidator, + IHook hook, + bytes calldata validatorData, + bytes calldata hookData, + bytes[] calldata initConfig + ) + external; + + function upgradeTo(address _newImplementation) external payable; + + function onERC721Received( + address, + address, + uint256, + bytes calldata + ) + external + pure + returns (bytes4); + + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes calldata + ) + external + pure + returns (bytes4); + + function onERC1155BatchReceived( + address, + address, + uint256[] calldata, + uint256[] calldata, + bytes calldata + ) + external + pure + returns (bytes4); + + // validation part + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash, + uint256 missingAccountFunds + ) + external + payable + returns (ValidationData validationData); + + // --- Execution --- + function executeUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + payable; + + function executeFromExecutor( + ExecMode execMode, + bytes calldata executionCalldata + ) + external + payable + returns (bytes[] memory returnData); + + function execute(ExecMode execMode, bytes calldata executionCalldata) external payable; + + function isValidSignature( + bytes32 hash, + bytes calldata signature + ) + external + view + returns (bytes4); + + function installModule( + uint256 moduleType, + address module, + bytes calldata initData + ) + external + payable; + + function installValidations( + ValidationId[] calldata vIds, + ValidationConfig[] memory configs, + bytes[] calldata validationData, + bytes[] calldata hookData + ) + external + payable; + + function uninstallValidation( + ValidationId vId, + bytes calldata deinitData, + bytes calldata hookDeinitData + ) + external + payable; + + function invalidateNonce(uint32 nonce) external payable; + + function uninstallModule( + uint256 moduleType, + address module, + bytes calldata deInitData + ) + external + payable; + + function supportsModule(uint256 moduleTypeId) external pure returns (bool); + + function isModuleInstalled( + uint256 moduleType, + address module, + bytes calldata additionalContext + ) + external + view + returns (bool); + + function accountId() external pure returns (string memory accountImplementationId); + + function supportsExecutionMode(ExecMode mode) external pure returns (bool); + + function isAllowedSelector(ValidationId vId, bytes4 selector) external view returns (bool); + + function _toWrappedHash(bytes32 hash) external view returns (bytes32); + + function validationConfig(ValidationId vId) external view returns (ValidationConfig memory); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernelFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernelFactory.sol new file mode 100644 index 0000000..5118e31 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernelFactory.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +interface IKernelFactory { + function createAccount(bytes calldata data, bytes32 salt) external payable returns (address); + function getAddress(bytes calldata data, bytes32 salt) external returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IValidationManager.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IValidationManager.sol new file mode 100644 index 0000000..7266e5a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IValidationManager.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IHook, ISigner } from "../../../accounts/common/interfaces/IERC7579Module.sol"; + +// Types +import { PassFlag, PolicyData, ValidationId, PermissionId } from "../lib/ValidationTypeLib.sol"; + +// erc7579 plugins +struct ValidationConfig { + uint32 nonce; // 4 bytes + IHook hook; // 20 bytes address(1) : hook not required, address(0) : validator not installed +} + +struct PermissionConfig { + PassFlag permissionFlag; + ISigner signer; + PolicyData[] policyData; +} + +struct ValidationStorage { + ValidationId rootValidator; + uint32 currentNonce; + uint32 validNonceFrom; + mapping(ValidationId => ValidationConfig) validationConfig; + mapping(ValidationId => mapping(bytes4 => bool)) allowedSelectors; + // validation = validator | permission + // validator == 1 validator + // permission == 1 signer + N policies + mapping(PermissionId => PermissionConfig) permissionConfig; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ExecLib.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ExecLib.sol new file mode 100644 index 0000000..7e5c958 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ExecLib.sol @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { ExecMode, CallType, ExecType, ExecModeSelector, ExecModePayload } from "../types/Types.sol"; +import { + CALLTYPE_SINGLE, + CALLTYPE_BATCH, + EXECTYPE_DEFAULT, + EXEC_MODE_DEFAULT, + EXECTYPE_TRY, + CALLTYPE_DELEGATECALL +} from "../types/Constants.sol"; +import { Execution } from "../types/Structs.sol"; + +/** + * @dev ExecLib is a helper library for execution + */ +library ExecLib { + error ExecutionFailed(); + + event TryExecuteUnsuccessful(uint256 batchExecutionindex, bytes result); + + function execute( + ExecMode execMode, + bytes calldata executionCalldata + ) + internal + returns (bytes[] memory returnData) + { + (CallType callType, ExecType execType,,) = decode(execMode); + + // check if calltype is batch or single + if (callType == CALLTYPE_BATCH) { + // destructure executionCallData according to batched exec + Execution[] calldata executions = decodeBatch(executionCalldata); + // check if execType is revert or try + if (execType == EXECTYPE_DEFAULT) returnData = execute(executions); + else if (execType == EXECTYPE_TRY) returnData = tryExecute(executions); + else revert("Unsupported"); + } else if (callType == CALLTYPE_SINGLE) { + // destructure executionCallData according to single exec + (address target, uint256 value, bytes calldata callData) = + decodeSingle(executionCalldata); + returnData = new bytes[](1); + bool success; + // check if execType is revert or try + if (execType == EXECTYPE_DEFAULT) { + returnData[0] = execute(target, value, callData); + } else if (execType == EXECTYPE_TRY) { + (success, returnData[0]) = tryExecute(target, value, callData); + if (!success) emit TryExecuteUnsuccessful(0, returnData[0]); + } else { + revert("Unsupported"); + } + } else if (callType == CALLTYPE_DELEGATECALL) { + returnData = new bytes[](1); + address delegate = address(bytes20(executionCalldata[0:20])); + bytes calldata callData = executionCalldata[20:]; + bool success; + (success, returnData[0]) = executeDelegatecall(delegate, callData); + if (execType == EXECTYPE_TRY) { + if (!success) emit TryExecuteUnsuccessful(0, returnData[0]); + } else if (execType == EXECTYPE_DEFAULT) { + if (!success) revert("Delegatecall failed"); + } else { + revert("Unsupported"); + } + } else { + revert("Unsupported"); + } + } + + function execute(Execution[] calldata executions) internal returns (bytes[] memory result) { + uint256 length = executions.length; + result = new bytes[](length); + + for (uint256 i; i < length; i++) { + Execution calldata _exec = executions[i]; + result[i] = execute(_exec.target, _exec.value, _exec.callData); + } + } + + function tryExecute(Execution[] calldata executions) internal returns (bytes[] memory result) { + uint256 length = executions.length; + result = new bytes[](length); + + for (uint256 i; i < length; i++) { + Execution calldata _exec = executions[i]; + bool success; + (success, result[i]) = tryExecute(_exec.target, _exec.value, _exec.callData); + if (!success) emit TryExecuteUnsuccessful(i, result[i]); + } + } + + function execute( + address target, + uint256 value, + bytes calldata callData + ) + internal + returns (bytes memory result) + { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + calldatacopy(result, callData.offset, callData.length) + if iszero(call(gas(), target, value, result, callData.length, codesize(), 0x00)) { + // Bubble up the revert if the call reverts. + returndatacopy(result, 0x00, returndatasize()) + revert(result, returndatasize()) + } + mstore(result, returndatasize()) // Store the length. + let o := add(result, 0x20) + returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. + mstore(0x40, add(o, returndatasize())) // Allocate the memory. + } + } + + function tryExecute( + address target, + uint256 value, + bytes calldata callData + ) + internal + returns (bool success, bytes memory result) + { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + calldatacopy(result, callData.offset, callData.length) + success := call(gas(), target, value, result, callData.length, codesize(), 0x00) + mstore(result, returndatasize()) // Store the length. + let o := add(result, 0x20) + returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. + mstore(0x40, add(o, returndatasize())) // Allocate the memory. + } + } + + /// @dev Execute a delegatecall with `delegate` on this account. + function executeDelegatecall( + address delegate, + bytes calldata callData + ) + internal + returns (bool success, bytes memory result) + { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + calldatacopy(result, callData.offset, callData.length) + // Forwards the `data` to `delegate` via delegatecall. + success := delegatecall(gas(), delegate, result, callData.length, codesize(), 0x00) + mstore(result, returndatasize()) // Store the length. + let o := add(result, 0x20) + returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. + mstore(0x40, add(o, returndatasize())) // Allocate the memory. + } + } + + function decode(ExecMode mode) + internal + pure + returns ( + CallType _calltype, + ExecType _execType, + ExecModeSelector _modeSelector, + ExecModePayload _modePayload + ) + { + assembly { + _calltype := mode + _execType := shl(8, mode) + _modeSelector := shl(48, mode) + _modePayload := shl(80, mode) + } + } + + function encode( + CallType callType, + ExecType execType, + ExecModeSelector mode, + ExecModePayload payload + ) + internal + pure + returns (ExecMode) + { + return ExecMode.wrap( + bytes32( + abi.encodePacked( + callType, execType, bytes4(0), ExecModeSelector.unwrap(mode), payload + ) + ) + ); + } + + function encodeSimpleBatch() internal pure returns (ExecMode mode) { + mode = + encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, EXEC_MODE_DEFAULT, ExecModePayload.wrap(0x00)); + } + + function encodeSimpleSingle() internal pure returns (ExecMode mode) { + mode = + encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, EXEC_MODE_DEFAULT, ExecModePayload.wrap(0x00)); + } + + function getCallType(ExecMode mode) internal pure returns (CallType calltype) { + assembly { + calltype := mode + } + } + + function decodeBatch(bytes calldata callData) + internal + pure + returns (Execution[] calldata executionBatch) + { + /* + * Batch Call Calldata Layout + * Offset (in bytes) | Length (in bytes) | Contents + * 0x0 | 0x4 | bytes4 function selector + * 0x4 | - | + abi.encode(IERC7579Execution.Execution[]) + */ + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + let dataPointer := add(callData.offset, calldataload(callData.offset)) + + // Extract the ERC7579 Executions + executionBatch.offset := add(dataPointer, 32) + executionBatch.length := calldataload(dataPointer) + } + } + + function encodeBatch(Execution[] memory executions) + internal + pure + returns (bytes memory callData) + { + callData = abi.encode(executions); + } + + function decodeSingle(bytes calldata executionCalldata) + internal + pure + returns (address target, uint256 value, bytes calldata callData) + { + target = address(bytes20(executionCalldata[0:20])); + value = uint256(bytes32(executionCalldata[20:52])); + callData = executionCalldata[52:]; + } + + function encodeSingle( + address target, + uint256 value, + bytes memory callData + ) + internal + pure + returns (bytes memory userOpCalldata) + { + userOpCalldata = abi.encodePacked(target, value, callData); + } + + function doFallback2771Static(address fallbackHandler) + internal + view + returns (bool success, bytes memory result) + { + assembly { + function allocate(length) -> pos { + pos := mload(0x40) + mstore(0x40, add(pos, length)) + } + + let calldataPtr := allocate(calldatasize()) + calldatacopy(calldataPtr, 0, calldatasize()) + + // The msg.sender address is shifted to the left by 12 bytes to remove the padding + // Then the address without padding is stored right after the calldata + let senderPtr := allocate(20) + mstore(senderPtr, shl(96, caller())) + + // Add 20 bytes for the address appended add the end + success := + staticcall(gas(), fallbackHandler, calldataPtr, add(calldatasize(), 20), 0, 0) + + result := mload(0x40) + mstore(result, returndatasize()) // Store the length. + let o := add(result, 0x20) + returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. + mstore(0x40, add(o, returndatasize())) // Allocate the memory. + } + } + + function doFallback2771Call(address target) + internal + returns (bool success, bytes memory result) + { + assembly { + function allocate(length) -> pos { + pos := mload(0x40) + mstore(0x40, add(pos, length)) + } + + let calldataPtr := allocate(calldatasize()) + calldatacopy(calldataPtr, 0, calldatasize()) + + // The msg.sender address is shifted to the left by 12 bytes to remove the padding + // Then the address without padding is stored right after the calldata + let senderPtr := allocate(20) + mstore(senderPtr, shl(96, caller())) + + // Add 20 bytes for the address appended add the end + success := call(gas(), target, 0, calldataPtr, add(calldatasize(), 20), 0, 0) + + result := mload(0x40) + mstore(result, returndatasize()) // Store the length. + let o := add(result, 0x20) + returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. + mstore(0x40, add(o, returndatasize())) // Allocate the memory. + } + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ValidationTypeLib.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ValidationTypeLib.sol new file mode 100644 index 0000000..03ea29e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ValidationTypeLib.sol @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IValidator, IPolicy, IHook, ISigner } from "../../common/interfaces/IERC7579Module.sol"; + +// Types +import { + PassFlag, + ValidationType, + ValidationId, + ValidationMode, + PolicyData, + PermissionId +} from "../types/Types.sol"; +import { VALIDATION_TYPE_PERMISSION } from "../types/Constants.sol"; + +// erc7579 plugins +struct ValidationConfig { + uint32 nonce; // 4 bytes + IHook hook; // 20 bytes address(1) : hook not required, address(0) : validator not installed +} + +struct PermissionConfig { + PassFlag permissionFlag; + ISigner signer; + PolicyData[] policyData; +} + +struct ValidationStorage { + ValidationId rootValidator; + uint32 currentNonce; + uint32 validNonceFrom; + mapping(ValidationId => ValidationConfig) validationConfig; + mapping(ValidationId => mapping(bytes4 => bool)) allowedSelectors; + // validation = validator | permission + // validator == 1 validator + // permission == 1 signer + N policies + mapping(PermissionId => PermissionConfig) permissionConfig; +} + +library ValidatorLib { + function encodeFlag( + bool skipUserOp, + bool skipSignature + ) + internal + pure + returns (PassFlag flag) + { + assembly { + if skipUserOp { + flag := 0x0001000000000000000000000000000000000000000000000000000000000000 + } + if skipSignature { + flag := or(flag, 0x0002000000000000000000000000000000000000000000000000000000000000) + } + } + } + + function encodePolicyData( + bool skipUserOp, + bool skipSig, + address policy + ) + internal + pure + returns (PolicyData data) + { + assembly { + if skipUserOp { + data := 0x0001000000000000000000000000000000000000000000000000000000000000 + } + if skipSig { + data := or(data, 0x0002000000000000000000000000000000000000000000000000000000000000) + } + data := or(data, shl(80, policy)) + } + } + + function encodePermissionAsNonce( + bytes1 mode, + bytes4 permissionId, + uint16 nonceKey, + uint64 nonce + ) + internal + pure + returns (uint256 res) + { + return encodeAsNonce( + mode, + ValidationType.unwrap(VALIDATION_TYPE_PERMISSION), + bytes20(permissionId), + nonceKey, + nonce + ); + } + + function encodeAsNonce( + bytes1 mode, + bytes1 vType, + bytes20 ValidationIdWithoutType, + uint16 nonceKey, + uint64 nonce + ) + internal + pure + returns (uint256 res) + { + assembly { + res := nonce + res := or(res, shl(64, nonceKey)) + res := or(res, shr(16, ValidationIdWithoutType)) + res := or(res, shr(8, vType)) + res := or(res, mode) + } + } + + function encodeAsNonceKey( + bytes1 mode, + bytes1 vType, + bytes20 ValidationIdWithoutType, + uint16 nonceKey + ) + internal + pure + returns (uint192 res) + { + assembly { + res := or(nonceKey, shr(80, ValidationIdWithoutType)) + res := or(res, shr(72, vType)) + res := or(res, shr(64, mode)) + } + } + + function decodeNonce(uint256 nonce) + internal + pure + returns (ValidationMode mode, ValidationType vType, ValidationId identifier) + { + // 2bytes mode (1byte currentMode, 1byte type) + // 21bytes identifier + // 1byte mode | 1byte type | 20bytes identifierWithoutType | 2byte nonceKey | 8byte nonce + // == 32bytes + assembly { + mode := nonce + vType := shl(8, nonce) + identifier := shl(8, nonce) + switch shr(248, identifier) + case 0x0000000000000000000000000000000000000000000000000000000000000002 { + identifier := + and(identifier, 0xffffffffff000000000000000000000000000000000000000000000000000000) + } + } + } + + function decodeSignature(bytes calldata signature) + internal + pure + returns (ValidationId vId, bytes calldata sig) + { + assembly { + vId := calldataload(signature.offset) + switch shr(248, vId) + case 0 { + // sudo mode + vId := 0x00 + sig.offset := add(signature.offset, 1) + sig.length := sub(signature.length, 1) + } + case 1 { + // validator mode + sig.offset := add(signature.offset, 21) + sig.length := sub(signature.length, 21) + } + case 2 { + vId := and(vId, 0xffffffffff000000000000000000000000000000000000000000000000000000) + sig.offset := add(signature.offset, 5) + sig.length := sub(signature.length, 5) + } + default { revert(0x00, 0x00) } + } + } + + function decodePolicyData(PolicyData data) + internal + pure + returns (PassFlag flag, IPolicy policy) + { + assembly { + flag := data + policy := shr(80, data) + } + } + + function validatorToIdentifier(IValidator validator) internal pure returns (ValidationId vId) { + assembly { + vId := 0x0100000000000000000000000000000000000000000000000000000000000000 + vId := or(vId, shl(88, validator)) + } + } + + function getType(ValidationId validator) internal pure returns (ValidationType vType) { + assembly { + vType := validator + } + } + + function getValidator(ValidationId validator) internal pure returns (IValidator v) { + assembly { + v := shr(88, validator) + } + } + + function getPermissionId(ValidationId validator) internal pure returns (PermissionId id) { + assembly { + id := shl(8, validator) + } + } + + function permissionToIdentifier(PermissionId permissionId) + internal + pure + returns (ValidationId vId) + { + assembly { + vId := 0x0200000000000000000000000000000000000000000000000000000000000000 + vId := or(vId, shr(8, permissionId)) + } + } + + function getPolicy(PolicyData data) internal pure returns (IPolicy vId) { + assembly { + vId := shr(80, data) + } + } + + function getPermissionSkip(PolicyData data) internal pure returns (PassFlag flag) { + assembly { + flag := data + } + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/mock/MockFallback.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/mock/MockFallback.sol new file mode 100644 index 0000000..e078530 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/mock/MockFallback.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/* solhint-disable no-unused-import */ + +// Interfaces +import { IERC7579Account } from "../interfaces/IERC7579Account.sol"; +import { IFallback } from "../interfaces/IERC7579Module.sol"; + +// Types +import { CallType, ExecType, ExecMode, ExecLib } from "../lib/ExecLib.sol"; +import { EXEC_MODE_DEFAULT } from "../types/Constants.sol"; + +contract Callee { + address public lastCaller; + + function calleeTest() external { + lastCaller = msg.sender; + } +} + +contract MockFallback is IFallback { + mapping(address account => bytes accountData) public data; + + uint256 public valueStored; + + bool public isExecutor; + + Callee public callee; + + constructor() { + callee = new Callee(); + } + + function setExecutorMode(bool _isExecutor) external payable { + isExecutor = _isExecutor; + } + + function onInstall(bytes calldata _data) external payable override { + data[msg.sender] = _data; + } + + function onUninstall(bytes calldata) external payable override { + delete data[msg.sender]; + } + + function isModuleType(uint256 moduleTypeId) external view override returns (bool) { + return moduleTypeId == 3 || (isExecutor && moduleTypeId == 2); + } + + function isInitialized(address smartAccount) external view override returns (bool) { + return data[smartAccount].length > 0; + } + + function fallbackFunction(uint256 v) external pure returns (uint256) { + return v * v; + } + + function getData() external view returns (bytes memory) { + return data[msg.sender]; + } + + function getCaller() external pure returns (address) { + return address(bytes20(msg.data[msg.data.length - 20:])); + } + + function setData(uint256 value) external { + valueStored = value; + if (isExecutor) { + IERC7579Account(msg.sender).executeFromExecutor( + ExecLib.encodeSimpleSingle(), + ExecLib.encodeSingle( + address(callee), 0, abi.encodeWithSelector(Callee.calleeTest.selector) + ) + ); + } + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Constants.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Constants.sol new file mode 100644 index 0000000..607b736 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Constants.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +import { CallType, ExecType, ExecModeSelector } from "./Types.sol"; +import { PassFlag, ValidationMode, ValidationType } from "./Types.sol"; +import { ValidationData } from "./Types.sol"; + +// --- ERC7579 calltypes --- +// Default CallType +CallType constant CALLTYPE_SINGLE = CallType.wrap(0x00); +// Batched CallType +CallType constant CALLTYPE_BATCH = CallType.wrap(0x01); +CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); +// @dev Implementing delegatecall is OPTIONAL! +// implement delegatecall with extreme care. +CallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF); + +// --- ERC7579 exectypes --- +// @dev default behavior is to revert on failure +// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure +// Since this is value 0x00, no additional encoding is required for simple accounts +ExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00); +// @dev account may elect to change execution behavior. For example "try exec" / "allow fail" +ExecType constant EXECTYPE_TRY = ExecType.wrap(0x01); + +// --- ERC7579 mode selector --- +ExecModeSelector constant EXEC_MODE_DEFAULT = ExecModeSelector.wrap(bytes4(0x00000000)); + +// --- Kernel permission skip flags --- +PassFlag constant SKIP_USEROP = PassFlag.wrap(0x0001); +PassFlag constant SKIP_SIGNATURE = PassFlag.wrap(0x0002); + +// --- Kernel validation modes --- +ValidationMode constant VALIDATION_MODE_DEFAULT = ValidationMode.wrap(0x00); +ValidationMode constant VALIDATION_MODE_ENABLE = ValidationMode.wrap(0x01); +ValidationMode constant VALIDATION_MODE_INSTALL = ValidationMode.wrap(0x02); + +// --- Kernel validation types --- +ValidationType constant VALIDATION_TYPE_ROOT = ValidationType.wrap(0x00); +ValidationType constant VALIDATION_TYPE_VALIDATOR = ValidationType.wrap(0x01); +ValidationType constant VALIDATION_TYPE_PERMISSION = ValidationType.wrap(0x02); + +// --- storage slots --- +// bytes32(uint256(keccak256('kernel.v3.selector')) - 1) +bytes32 constant SELECTOR_MANAGER_STORAGE_SLOT = + 0x7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b; +// bytes32(uint256(keccak256('kernel.v3.executor')) - 1) +bytes32 constant EXECUTOR_MANAGER_STORAGE_SLOT = + 0x1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b86; +// bytes32(uint256(keccak256('kernel.v3.hook')) - 1) +bytes32 constant HOOK_MANAGER_STORAGE_SLOT = + 0x4605d5f70bb605094b2e761eccdc27bed9a362d8612792676bf3fb9b12832ffc; +// bytes32(uint256(keccak256('kernel.v3.validation')) - 1) +bytes32 constant VALIDATION_MANAGER_STORAGE_SLOT = + 0x7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f; +bytes32 constant ERC1967_IMPLEMENTATION_SLOT = + 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + +// --- Kernel validation nonce incremental size limit --- +uint32 constant MAX_NONCE_INCREMENT_SIZE = 10; + +// -- EIP712 type hash --- +bytes32 constant ENABLE_TYPE_HASH = + 0xb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c505; +bytes32 constant KERNEL_WRAPPER_TYPE_HASH = + 0x1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c83; + +// --- ERC constants --- +// ERC4337 constants +uint256 constant SIG_VALIDATION_FAILED_UINT = 1; +uint256 constant SIG_VALIDATION_SUCCESS_UINT = 0; +ValidationData constant SIG_VALIDATION_FAILED = ValidationData.wrap(SIG_VALIDATION_FAILED_UINT); + +// ERC-1271 constants +bytes4 constant ERC1271_MAGICVALUE = 0x1626ba7e; +bytes4 constant ERC1271_INVALID = 0xffffffff; + +uint256 constant MODULE_TYPE_VALIDATOR = 1; +uint256 constant MODULE_TYPE_EXECUTOR = 2; +uint256 constant MODULE_TYPE_FALLBACK = 3; +uint256 constant MODULE_TYPE_HOOK = 4; +uint256 constant MODULE_TYPE_POLICY = 5; +uint256 constant MODULE_TYPE_SIGNER = 6; diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Structs.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Structs.sol new file mode 100644 index 0000000..edf9dbe --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Structs.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +struct Execution { + address target; + uint256 value; + bytes callData; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Types.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Types.sol new file mode 100644 index 0000000..e1e7196 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Types.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Custom type for improved developer experience +type ExecMode is bytes32; + +type CallType is bytes1; + +type ExecType is bytes1; + +type ExecModeSelector is bytes4; + +type ExecModePayload is bytes22; + +using { eqModeSelector as == } for ExecModeSelector global; +using { eqCallType as == } for CallType global; +using { notEqCallType as != } for CallType global; +using { eqExecType as == } for ExecType global; + +function eqCallType(CallType a, CallType b) pure returns (bool) { + return CallType.unwrap(a) == CallType.unwrap(b); +} + +function notEqCallType(CallType a, CallType b) pure returns (bool) { + return CallType.unwrap(a) != CallType.unwrap(b); +} + +function eqExecType(ExecType a, ExecType b) pure returns (bool) { + return ExecType.unwrap(a) == ExecType.unwrap(b); +} + +function eqModeSelector(ExecModeSelector a, ExecModeSelector b) pure returns (bool) { + return ExecModeSelector.unwrap(a) == ExecModeSelector.unwrap(b); +} + +type ValidationMode is bytes1; + +type ValidationId is bytes21; + +type ValidationType is bytes1; + +type PermissionId is bytes4; + +type PolicyData is bytes22; // 2bytes for flag on skip, 20 bytes for validator address + +type PassFlag is bytes2; + +using { vModeEqual as == } for ValidationMode global; +using { vTypeEqual as == } for ValidationType global; +using { vIdentifierEqual as == } for ValidationId global; +using { vModeNotEqual as != } for ValidationMode global; +using { vTypeNotEqual as != } for ValidationType global; +using { vIdentifierNotEqual as != } for ValidationId global; + +// nonce = uint192(key) + nonce +// key = mode + (vtype + validationDataWithoutType) + 2bytes parallelNonceKey +// key = 0x00 + 0x00 + 0x000 .. 00 + 0x0000 +// key = 0x00 + 0x01 + 0x1234...ff + 0x0000 +// key = 0x00 + 0x02 + ( ) + 0x000 + +function vModeEqual(ValidationMode a, ValidationMode b) pure returns (bool) { + return ValidationMode.unwrap(a) == ValidationMode.unwrap(b); +} + +function vModeNotEqual(ValidationMode a, ValidationMode b) pure returns (bool) { + return ValidationMode.unwrap(a) != ValidationMode.unwrap(b); +} + +function vTypeEqual(ValidationType a, ValidationType b) pure returns (bool) { + return ValidationType.unwrap(a) == ValidationType.unwrap(b); +} + +function vTypeNotEqual(ValidationType a, ValidationType b) pure returns (bool) { + return ValidationType.unwrap(a) != ValidationType.unwrap(b); +} + +function vIdentifierEqual(ValidationId a, ValidationId b) pure returns (bool) { + return ValidationId.unwrap(a) == ValidationId.unwrap(b); +} + +function vIdentifierNotEqual(ValidationId a, ValidationId b) pure returns (bool) { + return ValidationId.unwrap(a) != ValidationId.unwrap(b); +} + +type ValidationData is uint256; + +type ValidAfter is uint48; + +type ValidUntil is uint48; + +function getValidationResult(ValidationData validationData) pure returns (address result) { + // solhint-disable-next-line no-inline-assembly + assembly { + result := validationData + } +} + +function packValidationData(ValidAfter validAfter, ValidUntil validUntil) pure returns (uint256) { + return uint256(ValidAfter.unwrap(validAfter)) << 208 + | uint256(ValidUntil.unwrap(validUntil)) << 160; +} + +function parseValidationData(uint256 validationData) + pure + returns (ValidAfter validAfter, ValidUntil validUntil, address result) +{ + // solhint-disable-next-line no-inline-assembly + assembly { + result := validationData + validUntil := and(shr(160, validationData), 0xffffffffffff) + switch iszero(validUntil) + case 1 { validUntil := 0xffffffffffff } + validAfter := shr(208, validationData) + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/NexusFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/NexusFactory.sol new file mode 100644 index 0000000..14582c0 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/NexusFactory.sol @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IAccountFactory } from "../factory/interface/IAccountFactory.sol"; +import { INexusAccountFactory } from "../nexus/interfaces/INexusAccountFactory.sol"; +import { + INexusBootstrap, + BootstrapConfig as NexusBootstrapConfig +} from "../nexus/interfaces/INexusBootstrap.sol"; +import { IERC7484 } from "../../Interfaces.sol"; +import { INexus } from "./interfaces/INexus.sol"; + +// Constants +import { ENTRYPOINT_ADDR } from "../../deployment/predeploy/EntryPoint.sol"; +import { REGISTRY_ADDR } from "../../deployment/predeploy/Registry.sol"; + +// Utils +import { NexusPrecompiles } from "../../deployment/precompiles/NexusPrecompiles.sol"; + +contract NexusFactory is IAccountFactory, NexusPrecompiles { + INexusAccountFactory public factory; + INexusBootstrap public bootstrapDefault; + address public nexusImpl; + + function init() public override { + // Deploy precompiled contracts + nexusImpl = deployNexus(ENTRYPOINT_ADDR); + factory = deployNexusAccountFactory(nexusImpl, address(this)); + bootstrapDefault = deployNexusBootstrap(); + } + + function createAccount( + bytes32 salt, + bytes memory initCode + ) + public + override + returns (address account) + { + return deployNexusProxy(salt, nexusImpl, initCode); + } + + function getAddress( + bytes32 salt, + bytes memory initCode + ) + public + view + override + returns (address) + { + bytes32 hash = keccak256( + abi.encodePacked( + bytes1(0xff), + address(this), + salt, + keccak256( + abi.encodePacked( + NEXUS_PROXY_BYTECODE, + abi.encode( + address(nexusImpl), abi.encodeCall(INexus.initializeAccount, initCode) + ) + ) + ) + ) + ); + + return address(uint160(uint256(hash))); + } + + function getInitData( + address validator, + bytes memory initData + ) + public + view + override + returns (bytes memory _init) + { + NexusBootstrapConfig memory config = + NexusBootstrapConfig({ module: validator, data: initData }); + + address[] memory attesters = new address[](1); + attesters[0] = address(0x000000333034E9f539ce08819E12c1b8Cb29084d); + + return bootstrapDefault.getInitNexusWithSingleValidatorCalldata( + config, IERC7484(REGISTRY_ADDR), attesters, 1 + ); + } + + function createAccountWithModules( + bytes32 salt, + NexusBootstrapConfig[] calldata validators, + NexusBootstrapConfig[] calldata executors, + NexusBootstrapConfig calldata hook, + NexusBootstrapConfig[] calldata fallbacks + ) + public + payable + virtual + returns (address) + { + address[] memory attesters = new address[](1); + attesters[0] = address(0x000000333034E9f539ce08819E12c1b8Cb29084d); + + bytes memory initData = abi.encode( + bootstrapDefault, + abi.encodeCall( + INexusBootstrap.initNexus, + (validators, executors, hook, fallbacks, IERC7484(REGISTRY_ADDR), attesters, 1) + ) + ); + + address account = deployNexusProxy(salt, nexusImpl, initData); + + return account; + } + + function getInitData( + IAccountFactory.ModuleInitData[] memory _validators, + IAccountFactory.ModuleInitData[] memory _executors, + IAccountFactory.ModuleInitData memory _hook, + IAccountFactory.ModuleInitData[] memory _fallbacks + ) + public + view + override + returns (bytes memory _init) + { + NexusBootstrapConfig[] memory validators = + abi.decode(abi.encode(_validators), (NexusBootstrapConfig[])); + NexusBootstrapConfig[] memory executors = + abi.decode(abi.encode(_executors), (NexusBootstrapConfig[])); + NexusBootstrapConfig memory hook = abi.decode(abi.encode(_hook), (NexusBootstrapConfig)); + NexusBootstrapConfig[] memory fallbacks = + abi.decode(abi.encode(_fallbacks), (NexusBootstrapConfig[])); + + address[] memory attesters = new address[](1); + attesters[0] = address(0x000000333034E9f539ce08819E12c1b8Cb29084d); + + _init = abi.encode( + address(bootstrapDefault), + abi.encodeCall( + INexusBootstrap.initNexus, + (validators, executors, hook, fallbacks, IERC7484(REGISTRY_ADDR), attesters, 1) + ) + ); + } + + function getInitData(bytes memory initData) public view returns (bytes memory _init) { + ( + NexusBootstrapConfig[] memory validators, + NexusBootstrapConfig[] memory executors, + NexusBootstrapConfig memory hook, + NexusBootstrapConfig[] memory fallbacks + ) = abi.decode( + initData, + ( + NexusBootstrapConfig[], + NexusBootstrapConfig[], + NexusBootstrapConfig, + NexusBootstrapConfig[] + ) + ); + address[] memory attesters = new address[](1); + attesters[0] = address(0x000000333034E9f539ce08819E12c1b8Cb29084d); + + _init = abi.encode( + address(bootstrapDefault), + abi.encodeCall( + INexusBootstrap.initNexus, + (validators, executors, hook, fallbacks, IERC7484(REGISTRY_ADDR), attesters, 1) + ) + ); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexus.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexus.sol new file mode 100644 index 0000000..529f44f --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexus.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// ────────────────────────────────────────────────────────────────────────────── +// _ __ _ __ +// / | / /__ | |/ /_ _______ +// / |/ / _ \| / / / / ___/ +// / /| / __/ / /_/ (__ ) +// /_/ |_/\___/_/|_\__,_/____/ +// +// ────────────────────────────────────────────────────────────────────────────── +// Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, +// developed by Biconomy. +// Learn more at https://biconomy.io. To report security issues, please contact us at: +// security@biconomy.io + +import { IERC4337Account } from "../../common/interfaces/IERC4337Account.sol"; +import { IERC7579Account } from "../../common/interfaces/IERC7579Account.sol"; + +/// @title Nexus - INexus Interface +/// @notice Integrates ERC-4337 and ERC-7579 standards to manage smart accounts within the Nexus +/// suite. +/// @dev Consolidates ERC-4337 user operations and ERC-7579 configurations into a unified interface +/// for smart account management. +/// It extends both IERC4337Account and IERC7579Account, enhancing modular capabilities and +/// supporting advanced contract architectures. +/// Includes error definitions for robust handling of common issues such as unsupported module types +/// and execution failures. +/// The initialize function sets up the account with validators and configurations, ensuring +/// readiness for use. +/// @author @livingrockrises | Biconomy | chirag@biconomy.io +/// @author @aboudjem | Biconomy | adam.boudjemaa@biconomy.io +/// @author @filmakarov | Biconomy | filipp.makarov@biconomy.io +/// @author @zeroknots | Rhinestone.wtf | zeroknots.eth +/// Special thanks to the Solady team for foundational contributions: +/// https://github.com/Vectorized/solady +interface INexus is IERC4337Account, IERC7579Account { + /// @notice Initializes the smart account with a validator and custom data. + /// @dev This method sets up the account for operation, linking it with a validator and + /// initializing it with specific data. + /// Can be called directly or via a factory. + /// @param initData Encoded data used for the account's configuration during initialization. + function initializeAccount(bytes calldata initData) external payable; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusAccountFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusAccountFactory.sol new file mode 100644 index 0000000..00265ba --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusAccountFactory.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +interface INexusAccountFactory { + /// @notice Creates a new Nexus account with the provided initialization data. + /// @param initData Initialization data to be called on the new Smart Account. + /// @param salt Unique salt for the Smart Account creation. + /// @return The address of the newly created Nexus account. + function createAccount( + bytes calldata initData, + bytes32 salt + ) + external + payable + returns (address payable); + + /// @notice Computes the expected address of a Nexus contract using the factory's deterministic + /// deployment algorithm. + /// @param initData Initialization data to be called on the new Smart Account. + /// @param salt Unique salt for the Smart Account creation. + /// @return expectedAddress The expected address at which the Nexus contract will be deployed if + /// the provided parameters are used. + function computeAccountAddress( + bytes calldata initData, + bytes32 salt + ) + external + view + returns (address payable expectedAddress); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusBootstrap.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusBootstrap.sol new file mode 100644 index 0000000..e973811 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusBootstrap.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IModule as IERC7579Module } from "../../../accounts/common/interfaces/IERC7579Module.sol"; +import { IERC7484 } from "../../../Interfaces.sol"; + +// Structs +struct BootstrapConfig { + address module; + bytes data; +} + +interface INexusBootstrap { + /// @notice Initializes the Nexus account with a single validator. + /// @dev Intended to be called by the Nexus with a delegatecall. + /// @param validator The address of the validator module. + /// @param data The initialization data for the validator module. + function initNexusWithSingleValidator( + IERC7579Module validator, + bytes calldata data, + IERC7484 registry, + address[] calldata attesters, + uint8 threshold + ) + external; + + /// @notice Initializes the Nexus account with multiple modules. + /// @dev Intended to be called by the Nexus with a delegatecall. + /// @param validators The configuration array for validator modules. + /// @param executors The configuration array for executor modules. + /// @param hook The configuration for the hook module. + /// @param fallbacks The configuration array for fallback handler modules. + function initNexus( + BootstrapConfig[] calldata validators, + BootstrapConfig[] calldata executors, + BootstrapConfig calldata hook, + BootstrapConfig[] calldata fallbacks, + IERC7484 registry, + address[] calldata attesters, + uint8 threshold + ) + external; + + /// @notice Initializes the Nexus account with a scoped set of modules. + /// @dev Intended to be called by the Nexus with a delegatecall. + /// @param validators The configuration array for validator modules. + /// @param hook The configuration for the hook module. + function initNexusScoped( + BootstrapConfig[] calldata validators, + BootstrapConfig calldata hook, + IERC7484 registry, + address[] calldata attesters, + uint8 threshold + ) + external; + + /// @notice Prepares calldata for the initNexus function. + /// @param validators The configuration array for validator modules. + /// @param executors The configuration array for executor modules. + /// @param hook The configuration for the hook module. + /// @param fallbacks The configuration array for fallback handler modules. + /// @return init The prepared calldata for initNexus. + function getInitNexusCalldata( + BootstrapConfig[] calldata validators, + BootstrapConfig[] calldata executors, + BootstrapConfig calldata hook, + BootstrapConfig[] calldata fallbacks, + IERC7484 registry, + address[] calldata attesters, + uint8 threshold + ) + external + view + returns (bytes memory init); + + /// @notice Prepares calldata for the initNexusScoped function. + /// @param validators The configuration array for validator modules. + /// @param hook The configuration for the hook module. + /// @return init The prepared calldata for initNexusScoped. + function getInitNexusScopedCalldata( + BootstrapConfig[] calldata validators, + BootstrapConfig calldata hook, + IERC7484 registry, + address[] calldata attesters, + uint8 threshold + ) + external + view + returns (bytes memory init); + + /// @notice Prepares calldata for the initNexusWithSingleValidator function. + /// @param validator The configuration for the validator module. + /// @return init The prepared calldata for initNexusWithSingleValidator. + function getInitNexusWithSingleValidatorCalldata( + BootstrapConfig calldata validator, + IERC7484 registry, + address[] calldata attesters, + uint8 threshold + ) + external + view + returns (bytes memory init); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/SafeFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/SafeFactory.sol new file mode 100644 index 0000000..58f5596 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/SafeFactory.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { ISafe7579 } from "../../accounts/safe/interfaces/ISafe7579.sol"; +import { + ISafe7579Launchpad, ModuleInit +} from "../../accounts/safe/interfaces/ISafe7579Launchpad.sol"; +import { IAccountFactory } from "../../accounts/factory/interface/IAccountFactory.sol"; +import { ISafeProxyFactory } from "./interfaces/ISafeProxyFactory.sol"; + +// Utils +import { ENTRYPOINT_ADDR } from "../../deployment/predeploy/EntryPoint.sol"; +import { REGISTRY_ADDR } from "../../deployment/predeploy/Registry.sol"; +import { makeAddr } from "../../test/utils/Vm.sol"; +import { Solarray } from "solarray/Solarray.sol"; + +// Precompiles +import { Safe7579Precompiles } from "../../deployment/precompiles/Safe7579Precompiles.sol"; + +contract SafeFactory is IAccountFactory, Safe7579Precompiles { + // singletons + ISafe7579 public safe7579; + ISafe7579Launchpad public launchpad; + address public safeSingleton; + ISafeProxyFactory public safeProxyFactory; + + function init() public override { + safe7579 = deploySafe7579(); + launchpad = deploySafe7579Launchpad(ENTRYPOINT_ADDR, REGISTRY_ADDR); + safeSingleton = deploySafeSingleton(); + safeProxyFactory = deploySafeProxyFactory(); + } + + function createAccount( + bytes32 salt, + bytes memory initCode + ) + public + override + returns (address safe) + { + ISafe7579Launchpad.InitData memory initData = + abi.decode(initCode, (ISafe7579Launchpad.InitData)); + bytes32 initHash = launchpad.hash(initData); + + bytes memory factoryInitializer = + abi.encodeCall(ISafe7579Launchpad.preValidationSetup, (initHash, address(0), "")); + + safe = address( + safeProxyFactory.createProxyWithNonce( + address(launchpad), factoryInitializer, uint256(salt) + ) + ); + } + + function getAddress( + bytes32 salt, + bytes memory initCode + ) + public + view + override + returns (address) + { + ISafe7579Launchpad.InitData memory initData = + abi.decode(initCode, (ISafe7579Launchpad.InitData)); + bytes32 initHash = launchpad.hash(initData); + + bytes memory factoryInitializer = + abi.encodeCall(ISafe7579Launchpad.preValidationSetup, (initHash, address(0), "")); + + return launchpad.predictSafeAddress({ + singleton: address(launchpad), + safeProxyFactory: address(safeProxyFactory), + creationCode: SAFE_PROXY_BYTECODE, + salt: salt, + factoryInitializer: factoryInitializer + }); + } + + function getInitData( + address validator, + bytes memory initData + ) + public + view + override + returns (bytes memory _init) + { + ModuleInit[] memory validators = new ModuleInit[](1); + validators[0] = ModuleInit({ module: address(validator), initData: initData }); + ModuleInit[] memory executors = new ModuleInit[](0); + ModuleInit[] memory fallbacks = new ModuleInit[](0); + ModuleInit[] memory hooks = new ModuleInit[](0); + + ISafe7579Launchpad.InitData memory initDataSafe = ISafe7579Launchpad.InitData({ + singleton: address(safeSingleton), + owners: Solarray.addresses(makeAddr("owner1")), + threshold: 1, + setupTo: address(launchpad), + setupData: abi.encodeCall( + ISafe7579Launchpad.initSafe7579, + ( + address(safe7579), + executors, + fallbacks, + hooks, + Solarray.addresses(makeAddr("attester1"), makeAddr("attester2")), + 2 + ) + ), + safe7579: ISafe7579(safe7579), + validators: validators, + callData: "" + }); + _init = abi.encode(initDataSafe); + } + + function getInitData( + IAccountFactory.ModuleInitData[] memory _validators, + IAccountFactory.ModuleInitData[] memory _executors, + IAccountFactory.ModuleInitData memory _hook, + IAccountFactory.ModuleInitData[] memory _fallbacks + ) + public + view + returns (bytes memory _init) + { + ModuleInit[] memory validators = abi.decode(abi.encode(_validators), (ModuleInit[])); + ModuleInit[] memory executors = abi.decode(abi.encode(_executors), (ModuleInit[])); + ModuleInit memory hook = abi.decode(abi.encode(_hook), (ModuleInit)); + ModuleInit[] memory hooks = new ModuleInit[](1); + hooks[0] = hook; + ModuleInit[] memory fallbacks = abi.decode(abi.encode(_fallbacks), (ModuleInit[])); + + ISafe7579Launchpad.InitData memory initDataSafe = ISafe7579Launchpad.InitData({ + singleton: address(safeSingleton), + owners: Solarray.addresses(makeAddr("owner1")), + threshold: 1, + setupTo: address(launchpad), + setupData: abi.encodeCall( + ISafe7579Launchpad.initSafe7579, + ( + address(safe7579), + executors, + fallbacks, + hooks, + Solarray.addresses(makeAddr("attester1"), makeAddr("attester2")), + 2 + ) + ), + safe7579: ISafe7579(safe7579), + validators: validators, + callData: "" + }); + _init = abi.encode(initDataSafe); + } + + function getInitData(bytes memory initData) public view returns (bytes memory _init) { + ( + ModuleInit[] memory validators, + ModuleInit[] memory executors, + ModuleInit[] memory hooks, + ModuleInit[] memory fallbacks + ) = abi.decode(initData, (ModuleInit[], ModuleInit[], ModuleInit[], ModuleInit[])); + ISafe7579Launchpad.InitData memory initDataSafe = ISafe7579Launchpad.InitData({ + singleton: address(safeSingleton), + owners: Solarray.addresses(makeAddr("owner1")), + threshold: 1, + setupTo: address(launchpad), + setupData: abi.encodeCall( + ISafe7579Launchpad.initSafe7579, + ( + address(safe7579), + executors, + fallbacks, + hooks, + Solarray.addresses(makeAddr("attester1"), makeAddr("attester2")), + 2 + ) + ), + safe7579: ISafe7579(safe7579), + validators: validators, + callData: "" + }); + + _init = abi.encode(initDataSafe); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7484.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7484.sol new file mode 100644 index 0000000..2c756f7 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7484.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +interface IERC7484 { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Check with Registry internal attesters */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function check(address module) external view; + + function checkForAccount(address smartAccount, address module) external view; + + function check(address module, uint256 moduleType) external view; + + function checkForAccount( + address smartAccount, + address module, + uint256 moduleType + ) + external + view; + + /** + * Allows Smart Accounts - the end users of the registry - to appoint + * one or many attesters as trusted. + * @dev this function reverts, if address(0), or duplicates are provided in attesters[] + * + * @param threshold The minimum number of attestations required for a module + * to be considered secure. + * @param attesters The addresses of the attesters to be trusted. + */ + function trustAttesters(uint8 threshold, address[] calldata attesters) external; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Check with external attester(s) */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function check(address module, address[] calldata attesters, uint256 threshold) external view; + + function check( + address module, + uint256 moduleType, + address[] calldata attesters, + uint256 threshold + ) + external + view; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7579Account.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7579Account.sol new file mode 100644 index 0000000..50a5a2e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7579Account.sol @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { CallType, ExecType, ModeCode } from "../../common/lib/ModeLib.sol"; + +// Structs +struct Execution { + address target; + uint256 value; + bytes callData; +} + +interface IERC7579AccountEvents { + event ModuleInstalled(uint256 moduleTypeId, address module); + event ModuleUninstalled(uint256 moduleTypeId, address module); +} + +interface IERC7579AccountView { + /** + * @dev Returns the account id of the smart account + * @return accountImplementationId the account id of the smart account + * the accountId should be structured like so: + * "vendorname.accountname.semver" + */ + function accountId() external view returns (string memory accountImplementationId); + + /** + * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol) + * @param encodedMode the encoded mode + */ + function supportsExecutionMode(ModeCode encodedMode) external view returns (bool); + + /** + * Function to check if the account supports installation of a certain module type Id + * @param moduleTypeId the module type ID according the ERC-7579 spec + */ + function supportsModule(uint256 moduleTypeId) external view returns (bool); +} + +interface IERC7579Account is IERC7579AccountEvents, IERC7579AccountView { + // Error thrown when an unsupported ModuleType is requested + error UnsupportedModuleType(uint256 moduleTypeId); + // Error thrown when an execution with an unsupported CallType was made + error UnsupportedCallType(CallType callType); + // Error thrown when an execution with an unsupported ExecType was made + error UnsupportedExecType(ExecType execType); + /** + * @dev Executes a transaction on behalf of the account. + * This function is intended to be called by ERC-4337 EntryPoint.sol + * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf + * + * @dev MSA MUST implement this function signature. + * If a mode is requested that is not supported by the Account, it MUST revert + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data + */ + + function execute(ModeCode mode, bytes calldata executionCalldata) external; + + /** + * @dev Executes a transaction on behalf of the account. + * This function is intended to be called by Executor Modules + * @dev Ensure adequate authorization control: i.e. onlyExecutorModule + * + * @dev MSA MUST implement this function signature. + * If a mode is requested that is not supported by the Account, it MUST revert + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data + */ + function executeFromExecutor( + ModeCode mode, + bytes calldata executionCalldata + ) + external + returns (bytes[] memory returnData); + + /** + * @dev ERC-1271 isValidSignature + * This function is intended to be used to validate a smart account signature + * and may forward the call to a validator module + * + * @param hash The hash of the data that is signed + * @param data The data that is signed + */ + function isValidSignature(bytes32 hash, bytes calldata data) external returns (bytes4); + + /** + * @dev installs a Module of a certain type on the smart account + * @dev Implement Authorization control of your chosing + * @param moduleTypeId the module type ID according the ERC-7579 spec + * @param module the module address + * @param initData arbitrary data that may be required on the module during `onInstall` + * initialization. + */ + function installModule( + uint256 moduleTypeId, + address module, + bytes calldata initData + ) + external; + + /** + * @dev uninstalls a Module of a certain type on the smart account + * @dev Implement Authorization control of your chosing + * @param moduleTypeId the module type ID according the ERC-7579 spec + * @param module the module address + * @param deInitData arbitrary data that may be required on the module during `onUninstall` + * de-initialization. + */ + function uninstallModule( + uint256 moduleTypeId, + address module, + bytes calldata deInitData + ) + external; + + /** + * Function to check if the account has a certain module installed + * @param moduleTypeId the module type ID according the ERC-7579 spec + * Note: keep in mind that some contracts can be multiple module types at the same time. It + * thus may be necessary to query multiple module types + * @param module the module address + * @param additionalContext additional context data that the smart account may interpret to + * identifiy conditions under which the module is installed. + * usually this is not necessary, but for some special hooks that + * are stored in mappings, this param might be needed + */ + function isModuleInstalled( + uint256 moduleTypeId, + address module, + bytes calldata additionalContext + ) + external + view + returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579.sol new file mode 100644 index 0000000..754bfc3 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579.sol @@ -0,0 +1,268 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IERC7579Account } from "./IERC7579Account.sol"; +import { ISafeOp } from "./ISafeOp.sol"; + +// Types +import "../types/DataTypes.sol"; +import { ModeCode } from "../../common/lib/ModeLib.sol"; +import { PackedUserOperation } from + "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; + +/** + * @title ERC7579 Adapter for Safe accounts. + * creates full ERC7579 compliance to Safe accounts + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) + */ +interface ISafe7579 is IERC7579Account, ISafeOp { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Validation */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /** + * ERC4337 v0.7 validation function + * @dev expects that a ERC7579 validator module is encoded within the UserOp nonce. + * if no validator module is provided, it will fallback to validate the transaction with + * Safe's signers + */ + function validateUserOp( + PackedUserOperation memory userOp, + bytes32 userOpHash, + uint256 missingAccountFunds + ) + external + returns (uint256 packedValidSig); + + /** + * Will use Safe's signed messages or checkSignatures features or ERC7579 validation modules + * if no signature is provided, it makes use of Safe's signedMessages + * if address(0) or a non-installed validator module is provided, it will use Safe's + * checkSignatures + * if a valid validator module is provided, it will use the module's validateUserOp function + * @param hash message hash of ERC1271 request + * @param data abi.encodePacked(address validationModule, bytes signatures) + */ + function isValidSignature( + bytes32 hash, + bytes memory data + ) + external + view + returns (bytes4 magicValue); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Executions */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /** + * @dev Executes a transaction on behalf of the Safe account. + * This function is intended to be called by ERC-4337 EntryPoint.sol + * @dev If a global hook and/or selector hook is set, it will be called + * @dev AccessControl: only Self of Entrypoint can install modules + * Safe7579 supports the following feature set: + * CallTypes: + * - CALLTYPE_SINGLE + * - CALLTYPE_BATCH + * - CALLTYPE_DELEGATECALL + * ExecTypes: + * - EXECTYPE_DEFAULT (revert if not successful) + * - EXECTYPE_TRY + * If a different mode is selected, this function will revert + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data + */ + function execute(ModeCode mode, bytes memory executionCalldata) external; + + /** + * @dev Executes a transaction on behalf of the Safe account. + * This function is intended to be called by executor modules + * @dev If a global hook and/or selector hook is set, it will be called + * @dev AccessControl: only enabled executor modules + * Safe7579 supports the following feature set: + * CallTypes: + * - CALLTYPE_SINGLE + * - CALLTYPE_BATCH + * - CALLTYPE_DELEGATECALL + * ExecTypes: + * - EXECTYPE_DEFAULT (revert if not successful) + * - EXECTYPE_TRY + * If a different mode is selected, this function will revert + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data + */ + function executeFromExecutor( + ModeCode mode, + bytes memory executionCalldata + ) + external + returns (bytes[] memory returnDatas); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Manage Modules */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /** + * Installs a 7579 Module of a certain type on the smart account + * @dev The module has to be initialized from msg.sender == SafeProxy, we thus use a + * delegatecall to DCUtil, which calls the onInstall/onUninstall function on the ERC7579 + * module and emits the ModuleInstall/ModuleUnintall events + * @dev AccessControl: only Self of Entrypoint can install modules + * @dev If the safe set a registry, ERC7484 registry will be queried before installing + * @dev If a global hook and/or selector hook is set, it will be called + * @param moduleType the module type ID according the ERC-7579 spec + * Note: MULTITYPE_MODULE (uint(0)) is a special type to install a module with + * multiple types + * @param module the module address + * @param initData arbitrary data that may be required on the module during `onInstall` + * initialization. + */ + function installModule(uint256 moduleType, address module, bytes memory initData) external; + + /** + * Uninstalls a Module of a certain type on the smart account. + * @dev The module has to be initialized from msg.sender == SafeProxy, we thus use a + * delegatecall to DCUtil, which calls the onInstall/onUninstall function on the ERC7579 + * module and emits the ModuleInstall/ModuleUnintall events + * @dev AccessControl: only Self of Entrypoint can install modules + * @dev If a global hook and/or selector hook is set, it will be called + * @param moduleType the module type ID according the ERC-7579 spec + * @param module the module address + * @param deInitData arbitrary data that may be required on the module during `onUninstall` + * de-initialization. + */ + function uninstallModule( + uint256 moduleType, + address module, + bytes memory deInitData + ) + external; + + /** + * Function to check if the account has a certain module installed + * @param moduleType the module type ID according the ERC-7579 spec + * Note: keep in mind that some contracts can be multiple module types at the same time. It + * thus may be necessary to query multiple module types + * @param module the module address + * @param additionalContext additional context data that the smart account may interpret to + * identifiy conditions under which the module is installed. + * usually this is not necessary, but for some special hooks that + * are stored in mappings, this param might be needed + */ + function isModuleInstalled( + uint256 moduleType, + address module, + bytes memory additionalContext + ) + external + view + returns (bool); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Initialize Safe7579 */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /** + * This function can be called by the Launchpad.initSafe7579() or by already existing Safes that + * want to use Safe7579 + * if this is called by the Launchpad, it is expected that launchpadValidators() was called + * previously, and the param validators is empty + * @param validators validator modules and initData + * @param executors executor modules and initData + * @param executors executor modules and initData + * @param fallbacks fallback modules and initData + * @param hooks hook module and initData + * @param registryInit (OPTIONAL) registry, attesters and threshold for IERC7484 Registry + * If not provided, the registry will be set to the zero address, and no + * registry checks will be performed + */ + function initializeAccount( + ModuleInit[] memory validators, + ModuleInit[] memory executors, + ModuleInit[] memory fallbacks, + ModuleInit[] memory hooks, + RegistryInit memory registryInit + ) + external; + + /** + * This function is intended to be called by Launchpad.validateUserOp() + * @dev it will initialize the SentinelList4337 list for validators, and sstore all + * validators + * @dev Since this function has to be 4337 compliant (storage access), only validator storage is acccess + * @dev Note: this function DOES NOT call onInstall() on the validator modules or emit + * ModuleInstalled events. this has to be done by the launchpad + */ + function initializeAccountWithValidators(ModuleInit[] memory validators) external; + + /** + * Configure the Safe7579 with a IERC7484 registry + * @param registry IERC7484 registry + * @param attesters list of attesters + * @param threshold number of attesters required + */ + function setRegistry(IERC7484 registry, address[] memory attesters, uint8 threshold) external; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Query Account Details */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + function getValidatorsPaginated( + address cursor, + uint256 pageSize + ) + external + view + returns (address[] memory array, address next); + + /** + * Get the current active global hook + */ + function getActiveHook() external view returns (address hook); + + /** + * Get the current active selector hook + */ + function getActiveHook(bytes4 selector) external view returns (address hook); + + function getExecutorsPaginated( + address cursor, + uint256 size + ) + external + view + returns (address[] memory array, address next); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Query Misc */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /** + * Safe7579 is using validator selection encoding in the userop nonce. + * to make it easier for SDKs / devs to integrate, this function can be + * called to get the next nonce for a specific validator + * @param safe address of safe account + * @param validator ERC7579 validator to encode + */ + function getNonce(address safe, address validator) external view returns (uint256 nonce); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Custom Errors */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + error InvalidModule(address module); + error InvalidModuleType(address module, uint256 moduleType); + + // fallback handlers + error InvalidInput(); + error InvalidCallType(CallType callType); + error NoFallbackHandler(bytes4 msgSig); + error InvalidFallbackHandler(bytes4 msgSig); + error FallbackInstalled(bytes4 msgSig); + + // Hooks + error HookAlreadyInstalled(address currentHook); + error InvalidHookType(); + + // Registry Adapter + event ERC7484RegistryConfigured(address indexed smartAccount, IERC7484 indexed registry); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579Launchpad.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579Launchpad.sol new file mode 100644 index 0000000..ba6912f --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579Launchpad.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { + IAccount, + PackedUserOperation +} from "@ERC4337/account-abstraction/contracts/interfaces/IAccount.sol"; +import { ISafe7579 } from "./ISafe7579.sol"; + +// Types +import { ModuleInit } from "../types/DataTypes.sol"; + +interface ISafe7579Launchpad is IAccount { + /** + * @notice The keccak256 hash of the EIP-712 InitData struct, representing the structure + */ + struct InitData { + address singleton; + address[] owners; + uint256 threshold; + address setupTo; + bytes setupData; + ISafe7579 safe7579; + ModuleInit[] validators; + bytes callData; + } + + /** + * This function is intended to be delegatecalled by the ISafe.setup function. It configures the + * Safe7579 for the user for all module types except validators, which were initialized in the + * validateUserOp function. + */ + function initSafe7579( + address safe7579, + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit[] calldata hooks, + address[] calldata attesters, + uint8 threshold + ) + external; + + /** + * This function allows existing safe accounts to add the Safe7579 adapter to their account + */ + function addSafe7579( + address safe7579, + ModuleInit[] calldata validators, + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit[] calldata hooks, + address[] calldata attesters, + uint8 threshold + ) + external; + + /** + * SafeProxyFactory will create a SafeProxy and using this contract as the singleton + * implementation and call this function to initialize the account. + * will write initHash into SafeProxy storage + * @param initHash will be calculated offchain using this.hash(InitData) + * @param to optional parameter for a delegatecall + * @param preInit optional parameter for a delegatecall + */ + function preValidationSetup(bytes32 initHash, address to, bytes calldata preInit) external; + + /** + * Upon creation of SafeProxy by SafeProxyFactory, EntryPoint invokes this function to verify + * the transaction. It ensures that only this.setupSafe() can be called by EntryPoint during + * execution. The function validates the hash of InitData in userOp.callData against the hash + * stored in preValidationSetup. This function abides by ERC4337 storage restrictions, allowing + * Safe7579 adapter initialization only in Validation Modules compliant with 4337. It installs + * validators from InitData onto the Safe7579 adapter for the account. When called by EP, the + * SafeProxy singleton address remains unupgraded to SafeSingleton, preventing + * execTransactionFromModule by Safe7579 Adapter. Initialization of Validator Modules is + * achieved through a direct call to onInstall(). This delegatecalled function initializes the + * Validator Module with the correct msg.sender. Once all validator modules are set up, they can + * be used to validate the userOp. Parameters include userOp (EntryPoint v0.7 userOp), + * userOpHash, and missingAccountFunds representing the gas payment required. + * + * @param userOp EntryPoint v0.7 userOp. + * @param userOpHash hash of userOp + * @param missingAccountFunds amount of gas that has to be paid + * @return validationData 4337 packed validation data returned by the validator module + */ + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash, + uint256 missingAccountFunds + ) + external + returns (uint256 validationData); + + /** + * During the execution phase of ERC4337, this function upgrades the SafeProxy to the actual + * SafeSingleton implementation. Subsequently, it invokes the ISafe.setup() function to + * initialize the Safe Account. The setup() function should ensure the completion of Safe7579 + * Adapter initialization with InitData.setupTo as address(this) and InitData.setupData encoding + * the call to this.initSafe7579(). SafeProxy.setup() delegatecalls this function to install + * executors, fallbacks, hooks, and registry configurations on the Safe7579 adapter. As this + * occurs in the ERC4337 execution phase, storage restrictions are not applicable. + * + * @param initData initData to initialize the Safe and Safe7579 Adapter + */ + function setupSafe(InitData calldata initData) external; + + function getInitHash() external view returns (bytes32); + + /** + * Helper function that can be used offchain to predict the counterfactual Safe address. + * @dev factoryInitializer is expected to be: + * abi.encodeCall(Safe7579Launchpad.preValidationSetup, (initHash, to, callData)); + */ + function predictSafeAddress( + address singleton, + address safeProxyFactory, + bytes memory creationCode, + bytes32 salt, + bytes memory factoryInitializer + ) + external + pure + returns (address safeProxy); + + /** + * Create unique InitData hash. Using all params but excluding data.callData from hash + */ + function hash(InitData memory data) external pure returns (bytes32); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeOp.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeOp.sol new file mode 100644 index 0000000..b9a0a90 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeOp.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol"; + +bytes32 constant SAFE_OP_TYPEHASH = + 0xc03dfc11d8b10bf9cf703d558958c8c42777f785d998c62060d85a4f0ef6ea7f; + +interface ISafeOp { + /** + * @notice The EIP-712 type-hash for a SafeOp, representing the structure of a User Operation + * for + * the Safe. + * {address} safe - The address of the safe on which the operation is performed. + * {uint256} nonce - A unique number associated with the user operation, preventing replay + * attacks + * by ensuring each operation is unique. + * {bytes} initCode - The packed encoding of a factory address and its factory-specific data + * for + * creating a new Safe account. + * {bytes} callData - The bytes representing the data of the function call to be executed. + * {uint128} verificationGasLimit - The maximum amount of gas allowed for the verification + * process. + * {uint128} callGasLimit - The maximum amount of gas allowed for executing the function call. + * {uint256} preVerificationGas - The amount of gas allocated for pre-verification steps before + * executing the main operation. + * {uint128} maxPriorityFeePerGas - The maximum priority fee per gas that the user is willing + * to + * pay for the transaction. + * {uint128} maxFeePerGas - The maximum fee per gas that the user is willing to pay for the + * transaction. + * {bytes} paymasterAndData - The packed encoding of a paymaster address and its + * paymaster-specific + * data for sponsoring the user operation. + * {uint48} validAfter - A timestamp representing from when the user operation is valid. + * {uint48} validUntil - A timestamp representing until when the user operation is valid, or 0 + * to + * indicated "forever". + * {address} entryPoint - The address of the entry point that will execute the user operation. + * @dev When validating the user operation, the signature timestamps are pre-pended to the + * signature + * bytes. Equal to: + * keccak256( + * "SafeOp(address safe,uint256 nonce,bytes initCode,bytes callData,uint128 + * verificationGasLimit,uint128 callGasLimit,uint256 preVerificationGas,uint128 + * maxPriorityFeePerGas,uint128 maxFeePerGas,bytes paymasterAndData,uint48 validAfter,uint48 + * validUntil,address entryPoint)" + * ) = 0xc03dfc11d8b10bf9cf703d558958c8c42777f785d998c62060d85a4f0ef6ea7f + */ + struct EncodedSafeOpStruct { + bytes32 typeHash; + address safe; + uint256 nonce; + bytes32 initCodeHash; + bytes32 callDataHash; + uint128 verificationGasLimit; + uint128 callGasLimit; + uint256 preVerificationGas; + uint128 maxPriorityFeePerGas; + uint128 maxFeePerGas; + bytes32 paymasterAndDataHash; + uint48 validAfter; + uint48 validUntil; + address entryPoint; + } + + function domainSeparator() external view returns (bytes32); + + function getSafeOp( + PackedUserOperation calldata userOp, + address entryPoint + ) + external + view + returns ( + bytes memory operationData, + uint48 validAfter, + uint48 validUntil, + bytes calldata signatures + ); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeProxyFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeProxyFactory.sol new file mode 100644 index 0000000..aecb094 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeProxyFactory.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +interface ISafeProxyFactory { + function proxyCreationCode() external pure returns (bytes memory); + + function createProxyWithNonce( + address _singleton, + bytes memory initializer, + uint256 saltNonce + ) + external + returns (address proxy); + + function createChainSpecificProxyWithNonce( + address _singleton, + bytes memory initializer, + uint256 saltNonce + ) + external + returns (address proxy); + + function createProxyWithCallback( + address _singleton, + bytes memory initializer, + uint256 saltNonce, + address callback + ) + external + returns (address proxy); + + function getChainId() external view returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/types/DataTypes.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/types/DataTypes.sol new file mode 100644 index 0000000..3e755a3 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/types/DataTypes.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IERC7484 } from "../interfaces/IERC7484.sol"; + +// Types +import { CallType } from "../../common/lib/ModeLib.sol"; + +struct FallbackHandler { + address handler; + CallType calltype; +} + +enum HookType { + GLOBAL, + SIG +} + +struct ModuleInit { + address module; + bytes initData; +} + +struct RegistryInit { + IERC7484 registry; + address[] attesters; + uint8 threshold; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/BytecodeDeployer.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/BytecodeDeployer.sol new file mode 100644 index 0000000..a357a0c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/BytecodeDeployer.sol @@ -0,0 +1,32 @@ +// // SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/// @dev Deploys contracts using CREATE and CREATE2 +contract BytecodeDeployer { + /// @notice Deploys a contract using CREATE, reverts on failure + function _deploy(bytes memory creationBytecode) internal returns (address contractAddress) { + // solhint-disable-next-line no-inline-assembly + assembly { + contractAddress := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) + } + // solhint-disable-next-line gas-custom-errors + require(contractAddress != address(0), "Deployer: deployment failed"); + } + + /// @notice Deploys a contract using CREATE2, reverts on failure + function _deploy2( + bytes memory creationBytecode, + bytes32 salt + ) + internal + returns (address contractAddress) + { + // solhint-disable-next-line no-inline-assembly + assembly { + contractAddress := + create2(0, add(creationBytecode, 0x20), mload(creationBytecode), salt) + } + // solhint-disable-next-line gas-custom-errors + require(contractAddress != address(0), "Deployer: deployment failed"); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/ERC7579Precompiles.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/ERC7579Precompiles.sol new file mode 100644 index 0000000..335c438 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/ERC7579Precompiles.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IERC7579Account } from "../../accounts/common/interfaces/IERC7579Account.sol"; +import { IERC7579Bootstrap } from "../../accounts/erc7579/interfaces/IERC7579Bootstrap.sol"; +import { IMSA } from "../../accounts/erc7579/interfaces/IMSA.sol"; + +// Utils +import { BytecodeDeployer } from "./BytecodeDeployer.sol"; + +interface RhinestoneBootstrap { + function init() external; +} + +/// @notice Precompiled erc7579 contracts +contract ERC7579Precompiles is BytecodeDeployer { + /*////////////////////////////////////////////////////////////// + DEPLOY + //////////////////////////////////////////////////////////////*/ + + function deployERC7579Account() internal returns (IERC7579Account) { + return IERC7579Account(_deploy(ERC7579_BYTECODE)); + } + + function deployMSAPRoxy( + bytes32 salt, + address implementation, + bytes memory initCode + ) + internal + returns (address) + { + return _deploy2( + bytes.concat( + MSAPROXY_BYTECODE, + abi.encode( + implementation, + abi.encodeWithSelector(IMSA.initializeAccount.selector, initCode) + ) + ), + salt + ); + } + + function deployERC7579Bootstrap() internal returns (IERC7579Bootstrap) { + return IERC7579Bootstrap(_deploy(ERC7579_BOOTSTRAP_BYTECODE)); + } + + function deployRhinestoneBootstrap() internal returns (RhinestoneBootstrap) { + return RhinestoneBootstrap(_deploy(ERC7579_RHINESTONE_TRAMPOLOINE_BYTECODE)); + } + + /*////////////////////////////////////////////////////////////// + BYTECODES + //////////////////////////////////////////////////////////////*/ + + /* solhint-disable max-line-length */ + bytes public constant ERC7579_BYTECODE = + hex"6080604052348015600e575f5ffd5b506175818061001c5f395ff3fe60806040526004361061012d575f3560e01c80639517e29f116100aa578063d691c9641161006e578063d691c96414610620578063e9ae5c5314610650578063ea5f61d01461066c578063eab77e17146106a9578063eac9b20d146106d1578063f2dc691d1461070d57610134565b80639517e29f146105585780639cfd7cff14610574578063a71763a81461059e578063b0d691fe146105ba578063d03c7914146105e457610134565b8063492a88a2116100f1578063492a88a21461048f5780634b6a1419146104b95780635faac46b146104d55780638626e88b146105125780638dd7712f1461053c57610134565b80630a664dba14610381578063112d3a7d146103ab5780631626ba7e146103e757806319822f7c146104235780631de6f24f1461045357610134565b3661013457005b5f3560e01c63bc197c81811463f23a6e6182141763150b7a028214171561015f57806020526020603cf35b505f610169610749565b6002015f5f357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f2090505f815f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f825f0160149054906101000a900460f81b90505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036102ab575f357fffffffff00000000000000000000000000000000000000000000000000000000166040517f48c9ceda0000000000000000000000000000000000000000000000000000000081526004016102a29190615b6c565b60405180910390fd5b6102b98160fe60f81b610777565b15610315576102d4565b5f6040519050818101604052919050565b6102dd366102c3565b365f82376102eb60146102c3565b3360601b81525f5f6014360184875afa6103043d6102c3565b3d5f823e81610311573d81fd5b3d81f35b610322815f60f81b610777565b1561037f5761033d565b5f6040519050818101604052919050565b6103463661032c565b365f8237610354601461032c565b3360601b81525f5f60143601845f885af161036e3d61032c565b3d5f823e8161037b573d81fd5b3d81f35b005b34801561038c575f5ffd5b506103956107c7565b6040516103a29190615bc4565b60405180910390f35b3480156103b6575f5ffd5b506103d160048036038101906103cc9190615cac565b6107d5565b6040516103de9190615d37565b60405180910390f35b3480156103f2575f5ffd5b5061040d60048036038101906104089190615d83565b610876565b60405161041a9190615b6c565b60405180910390f35b61043d6004803603810190610438919061606d565b610a3d565b60405161044a91906160e8565b60405180910390f35b34801561045e575f5ffd5b5061047960048036038101906104749190616101565b610bf2565b6040516104869190615bc4565b60405180910390f35b34801561049a575f5ffd5b506104a3610c03565b6040516104b09190615d37565b60405180910390f35b6104d360048036038101906104ce919061612c565b610c78565b005b3480156104e0575f5ffd5b506104fb60048036038101906104f69190616177565b610d66565b60405161050992919061626c565b60405180910390f35b34801561051d575f5ffd5b50610526610d97565b6040516105339190616351565b60405180910390f35b61055660048036038101906105519190616394565b610e13565b005b610572600480360381019061056d9190615cac565b610f4d565b005b34801561057f575f5ffd5b5061058861161e565b604051610595919061644e565b60405180910390f35b6105b860048036038101906105b39190615cac565b61165b565b005b3480156105c5575f5ffd5b506105ce611a32565b6040516105db9190615bc4565b60405180910390f35b3480156105ef575f5ffd5b5061060a60048036038101906106059190616498565b611a49565b6040516106179190615d37565b60405180910390f35b61063a600480360381019061063591906164c3565b611b04565b604051610647919061662d565b60405180910390f35b61066a600480360381019061066591906164c3565b61252d565b005b348015610677575f5ffd5b50610692600480360381019061068d9190616177565b612c31565b6040516106a092919061626c565b60405180910390f35b3480156106b4575f5ffd5b506106cf60048036038101906106ca9190616713565b612c63565b005b3480156106dc575f5ffd5b506106f760048036038101906106f291906167ae565b612dc0565b6040516107049190616851565b60405180910390f35b348015610718575f5ffd5b50610733600480360381019061072e9190616101565b612ee0565b6040516107409190615d37565b60405180910390f35b5f5f7fe3a55571e8f241b58442871487cc151a8cb048bb4ad24e833467f724ec89a9005f1b90508091505090565b5f817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b5f6107d0612f4b565b905090565b5f600185036107ee576107e784612f7a565b905061086e565b60028503610806576107ff84612fa3565b905061086e565b6003850361082d57610826838381019061082091906167ae565b85612fcd565b905061086e565b600485036108455761083e84613083565b905061086e565b60088514806108545750600985145b1561086a5761086384866130c1565b905061086e565b5f90505b949350505050565b5f5f83835f9060149261088b93929190616872565b9061089691906168ed565b60601c90506108a481612f7a565b61098f576108b0613101565b610952575f61090a6108c18761311e565b86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505061314e565b90503073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361095057631626ba7e60e01b92505050610a36565b505b806040517fb927fe5e0000000000000000000000000000000000000000000000000000000081526004016109869190615bc4565b60405180910390fd5b60606109ad86868660149080926109a893929190616872565b6131df565b80925081975050508173ffffffffffffffffffffffffffffffffffffffff1663f551e2ee3388846040518463ffffffff1660e01b81526004016109f2939291906169a2565b602060405180830381865afa158015610a0d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a3191906169f2565b925050505b9392505050565b5f610a46611a32565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610aaa576040517fac52ccbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815f5f866020015190508060601c9150610ac382612f7a565b610b4257610acf613101565b610b37575f610aeb610ae08861311e565b89610100015161314e565b90503073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610b2c5760019450505050610bda565b5f9450505050610bda565b600193505050610bda565b610b4d868887613306565b886101000181905281975050508173ffffffffffffffffffffffffffffffffffffffff16639700320388886040518363ffffffff1660e01b8152600401610b95929190616b03565b6020604051808303815f875af1158015610bb1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bd59190616b45565b935050505b8015610bea575f385f3884335af1505b509392505050565b5f610bfc826133e8565b9050919050565b5f3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c69576040517f0e93a1f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c71613492565b6001905090565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610cb457610cb36134bc565b5b610cbc613532565b5f7feadcdba66a79ab5dce91622d1d75c8cff5cff0b96944c3bf1072cd08ce018329303f1490508015610d4057610d147fe3a55571e8f241b58442871487cc151a8cb048bb4ad24e833467f724ec89a9005f1b613557565b610d3f7fcd97a6611018468306afd07ac8b14141bc76df8b844b3bcba1768d81e45982005f1b613557565b5b5f5f8484810190610d519190616bab565b91509150610d5f82826135a6565b5050505050565b60605f5f610d72610749565b5f019050610d8b85858361361b9092919063ffffffff16565b92509250509250929050565b60605f7fc473de86d0138e06e4d4918a106463a7cc005258d2e21915272bcb4594c189009050805f01805480602002602001604051908101604052809291908181526020018280548015610e0857602002820191905f5260205f20905b815481526020019060010190808311610df4575b505050505091505090565b610e1b611a32565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610e7f576040517fac52ccbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b365f838060600190610e919190616c11565b6004908092610ea293929190616872565b915091505f3073ffffffffffffffffffffffffffffffffffffffff168383604051610ece929190616ca1565b5f60405180830381855af49150503d805f8114610f06576040519150601f19603f3d011682016040523d82523d5f602084013e610f0b565b606091505b5050905080610f46576040517facfdb44400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b610f55611a32565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480610fb957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b610fef576040517fac52ccbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610ff8612f4b565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036112ae5783855f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146110ee578073ffffffffffffffffffffffffffffffffffffffff166396fb721784846040518363ffffffff1660e01b81526004016110c1929190616cb9565b5f6040518083038186803b1580156110d7575f5ffd5b505afa1580156110e9573d5f5f3e3d5ffd5b505050505b8673ffffffffffffffffffffffffffffffffffffffff1663ecd05961896040518263ffffffff1660e01b815260040161112791906160e8565b602060405180830381865afa158015611142573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111669190616d0a565b6111a757876040517fd393448a00000000000000000000000000000000000000000000000000000000815260040161119e91906160e8565b60405180910390fd5b600188036111bf576111ba87878761393e565b61126d565b600288036111d7576111d28787876139cc565b61126c565b600388036111ef576111ea878787613a5b565b61126b565b6004880361120757611202878787613cb8565b61126a565b60088814806112165750600988145b1561122c5761122787898888613daa565b611269565b876040517f41c38b3000000000000000000000000000000000000000000000000000000000815260040161126091906160e8565b60405180910390fd5b5b5b5b5b7fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123888860405161129e929190616d35565b60405180910390a1505050611617565b5f8173ffffffffffffffffffffffffffffffffffffffff1663d68f602533345f366040518563ffffffff1660e01b81526004016112ee9493929190616d88565b5f604051808303815f875af1158015611309573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906113319190616e34565b905084865f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146113f4578073ffffffffffffffffffffffffffffffffffffffff166396fb721784846040518363ffffffff1660e01b81526004016113c7929190616cb9565b5f6040518083038186803b1580156113dd575f5ffd5b505afa1580156113ef573d5f5f3e3d5ffd5b505050505b8773ffffffffffffffffffffffffffffffffffffffff1663ecd059618a6040518263ffffffff1660e01b815260040161142d91906160e8565b602060405180830381865afa158015611448573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061146c9190616d0a565b6114ad57886040517fd393448a0000000000000000000000000000000000000000000000000000000081526004016114a491906160e8565b60405180910390fd5b600189036114c5576114c088888861393e565b611573565b600289036114dd576114d88888886139cc565b611572565b600389036114f5576114f0888888613a5b565b611571565b6004890361150d57611508888888613cb8565b611570565b600889148061151c5750600989145b156115325761152d888a8989613daa565b61156f565b886040517f41c38b3000000000000000000000000000000000000000000000000000000000815260040161156691906160e8565b60405180910390fd5b5b5b5b5b7fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef12389896040516115a4929190616d35565b60405180910390a15050508173ffffffffffffffffffffffffffffffffffffffff1663173bf7da826040518263ffffffff1660e01b81526004016115e89190616e7b565b5f604051808303815f87803b1580156115ff575f5ffd5b505af1158015611611573d5f5f3e3d5ffd5b50505050505b5050505050565b60606040518060400160405280601b81526020017f754d53412e616476616e6365642f77697468486f6f6b2e76302e310000000000815250905090565b611663611a32565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806116c757503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b6116fd576040517fac52ccbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611706612f4b565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361183f57600185036117535761174e848484613f6f565b611801565b6002850361176b57611766848484614014565b611800565b600385036117835761177e8484846140ba565b6117ff565b6004850361179b5761179684848461447d565b6117fe565b60088514806117aa5750600985145b156117c0576117bb848685856144f3565b6117fd565b846040517f41c38b300000000000000000000000000000000000000000000000000000000081526004016117f491906160e8565b60405180910390fd5b5b5b5b5b7f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e8585604051611832929190616d35565b60405180910390a1611a2b565b5f8173ffffffffffffffffffffffffffffffffffffffff1663d68f602533345f366040518563ffffffff1660e01b815260040161187f9493929190616d88565b5f604051808303815f875af115801561189a573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906118c29190616e34565b9050600186036118dc576118d7858585613f6f565b61198a565b600286036118f4576118ef858585614014565b611989565b6003860361190c576119078585856140ba565b611988565b600486036119245761191f85858561447d565b611987565b60088614806119335750600986145b1561194957611944858786866144f3565b611986565b856040517f41c38b3000000000000000000000000000000000000000000000000000000000815260040161197d91906160e8565b60405180910390fd5b5b5b5b5b7f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e86866040516119bb929190616d35565b60405180910390a18173ffffffffffffffffffffffffffffffffffffffff1663173bf7da826040518263ffffffff1660e01b81526004016119fc9190616e7b565b5f604051808303815f87803b158015611a13575f5ffd5b505af1158015611a25573d5f5f3e3d5ffd5b50505050505b5050505050565b5f6f71727de22e5e9d8baf0edac6f37da032905090565b5f5f5f611a5584614726565b505091509150611a6982600160f81b610777565b15611a775760019250611aba565b611a84825f60f81b610777565b15611a925760019250611ab9565b611aa08260ff60f81b610777565b15611aae5760019250611ab8565b5f92505050611aff565b5b5b611ac7815f60f81b614746565b15611ad55760019250611afc565b611ae381600160f81b614746565b15611af15760019250611afb565b5f92505050611aff565b5b50505b919050565b60605f611b0f610749565b6001019050611b27338261479690919063ffffffff16565b611b6857336040517fb927fe5e000000000000000000000000000000000000000000000000000000008152600401611b5f9190615bc4565b60405180910390fd5b5f611b71612f4b565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611ff1573360025f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611c68578073ffffffffffffffffffffffffffffffffffffffff166396fb721784846040518363ffffffff1660e01b8152600401611c3b929190616cb9565b5f6040518083038186803b158015611c51575f5ffd5b505afa158015611c63573d5f5f3e3d5ffd5b505050505b5f5f611c738b614726565b505091509150611c8782600160f81b610777565b15611d2857365f611c988c8c614865565b91509150611ca9835f60f81b614746565b15611cbf57611cb8828261490e565b9950611d21565b611ccd83600160f81b614746565b15611ce357611cdc82826149fc565b9950611d20565b826040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611d179190616eaa565b60405180910390fd5b5b5050611fe7565b611d35825f60f81b610777565b15611eca575f5f365f611d488e8e614b49565b9350935093509350600167ffffffffffffffff811115611d6b57611d6a615df4565b5b604051908082528060200260200182016040528015611d9e57816020015b6060815260200190600190039081611d895790505b509b505f611daf865f60f81b614746565b15611de357611dc085858585614bb3565b8d5f81518110611dd357611dd2616ec3565b5b6020026020010181905250611ec0565b611df186600160f81b614746565b15611e8257611e0285858585614bec565b8e5f81518110611e1557611e14616ec3565b5b60200260200101819052819250505080611e7d577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb75f8e5f81518110611e5e57611e5d616ec3565b5b6020026020010151604051611e74929190616f32565b60405180910390a15b611ebf565b856040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611eb69190616eaa565b60405180910390fd5b5b5050505050611fe6565b611ed88260ff60f81b610777565b15611fa8575f8a8a5f90601492611ef193929190616872565b90611efc91906168ed565b60601c9050365f8c8c6014908092611f1693929190616872565b91509150611f27845f60f81b614746565b15611f3d57611f37838383614c1d565b50611fa0565b611f4b84600160f81b614746565b15611f6257611f5b838383614c54565b5050611f9f565b836040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611f969190616eaa565b60405180910390fd5b5b505050611fe5565b816040517fb96fcfe4000000000000000000000000000000000000000000000000000000008152600401611fdc9190616f6f565b60405180910390fd5b5b5b5050505050612524565b5f8173ffffffffffffffffffffffffffffffffffffffff1663d68f602533345f366040518563ffffffff1660e01b81526004016120319493929190616d88565b5f604051808303815f875af115801561204c573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906120749190616e34565b90503360025f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612138578073ffffffffffffffffffffffffffffffffffffffff166396fb721784846040518363ffffffff1660e01b815260040161210b929190616cb9565b5f6040518083038186803b158015612121575f5ffd5b505afa158015612133573d5f5f3e3d5ffd5b505050505b5f5f6121438c614726565b50509150915061215782600160f81b610777565b156121f857365f6121688d8d614865565b91509150612179835f60f81b614746565b1561218f57612188828261490e565b9a506121f1565b61219d83600160f81b614746565b156121b3576121ac82826149fc565b9a506121f0565b826040517f1187dc060000000000000000000000000000000000000000000000000000000081526004016121e79190616eaa565b60405180910390fd5b5b50506124b7565b612205825f60f81b610777565b1561239a575f5f365f6122188f8f614b49565b9350935093509350600167ffffffffffffffff81111561223b5761223a615df4565b5b60405190808252806020026020018201604052801561226e57816020015b60608152602001906001900390816122595790505b509c505f61227f865f60f81b614746565b156122b35761229085858585614bb3565b8e5f815181106122a3576122a2616ec3565b5b6020026020010181905250612390565b6122c186600160f81b614746565b15612352576122d285858585614bec565b8f5f815181106122e5576122e4616ec3565b5b6020026020010181905281925050508061234d577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb75f8f5f8151811061232e5761232d616ec3565b5b6020026020010151604051612344929190616f32565b60405180910390a15b61238f565b856040517f1187dc060000000000000000000000000000000000000000000000000000000081526004016123869190616eaa565b60405180910390fd5b5b50505050506124b6565b6123a88260ff60f81b610777565b15612478575f8b8b5f906014926123c193929190616872565b906123cc91906168ed565b60601c9050365f8d8d60149080926123e693929190616872565b915091506123f7845f60f81b614746565b1561240d57612407838383614c1d565b50612470565b61241b84600160f81b614746565b156124325761242b838383614c54565b505061246f565b836040517f1187dc060000000000000000000000000000000000000000000000000000000081526004016124669190616eaa565b60405180910390fd5b5b5050506124b5565b816040517fb96fcfe40000000000000000000000000000000000000000000000000000000081526004016124ac9190616f6f565b60405180910390fd5b5b5b50505050508173ffffffffffffffffffffffffffffffffffffffff1663173bf7da826040518263ffffffff1660e01b81526004016124f59190616e7b565b5f604051808303815f87803b15801561250c575f5ffd5b505af115801561251e573d5f5f3e3d5ffd5b50505050505b50509392505050565b612535611a32565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061259957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b6125cf576040517fac52ccbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6125d8612f4b565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036128a8575f5f61261886614726565b50509150915061262c82600160f81b610777565b156126cb57365f61263d8787614865565b9150915061264e835f60f81b614746565b156126635761265d828261490e565b506126c4565b61267183600160f81b614746565b156126865761268082826149fc565b506126c3565b826040517f1187dc060000000000000000000000000000000000000000000000000000000081526004016126ba9190616eaa565b60405180910390fd5b5b50506128a1565b6126d8825f60f81b610777565b15612784575f5f365f6126eb8989614b49565b9350935093509350612700855f60f81b614746565b156127175761271184848484614bb3565b5061277b565b61272585600160f81b614746565b1561273d5761273684848484614bec565b505061277a565b846040517f1187dc060000000000000000000000000000000000000000000000000000000081526004016127719190616eaa565b60405180910390fd5b5b505050506128a0565b6127928260ff60f81b610777565b15612862575f85855f906014926127ab93929190616872565b906127b691906168ed565b60601c9050365f878760149080926127d093929190616872565b915091506127e1845f60f81b614746565b156127f7576127f1838383614c1d565b5061285a565b61280584600160f81b614746565b1561281c57612815838383614c54565b5050612859565b836040517f1187dc060000000000000000000000000000000000000000000000000000000081526004016128509190616eaa565b60405180910390fd5b5b50505061289f565b816040517fb96fcfe40000000000000000000000000000000000000000000000000000000081526004016128969190616f6f565b60405180910390fd5b5b5b5050612c2b565b5f8173ffffffffffffffffffffffffffffffffffffffff1663d68f602533345f366040518563ffffffff1660e01b81526004016128e89493929190616d88565b5f604051808303815f875af1158015612903573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061292b9190616e34565b90505f5f61293887614726565b50509150915061294c82600160f81b610777565b156129eb57365f61295d8888614865565b9150915061296e835f60f81b614746565b156129835761297d828261490e565b506129e4565b61299183600160f81b614746565b156129a6576129a082826149fc565b506129e3565b826040517f1187dc060000000000000000000000000000000000000000000000000000000081526004016129da9190616eaa565b60405180910390fd5b5b5050612bc1565b6129f8825f60f81b610777565b15612aa4575f5f365f612a0b8a8a614b49565b9350935093509350612a20855f60f81b614746565b15612a3757612a3184848484614bb3565b50612a9b565b612a4585600160f81b614746565b15612a5d57612a5684848484614bec565b5050612a9a565b846040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401612a919190616eaa565b60405180910390fd5b5b50505050612bc0565b612ab28260ff60f81b610777565b15612b82575f86865f90601492612acb93929190616872565b90612ad691906168ed565b60601c9050365f88886014908092612af093929190616872565b91509150612b01845f60f81b614746565b15612b1757612b11838383614c1d565b50612b7a565b612b2584600160f81b614746565b15612b3c57612b35838383614c54565b5050612b79565b836040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401612b709190616eaa565b60405180910390fd5b5b505050612bbf565b816040517fb96fcfe4000000000000000000000000000000000000000000000000000000008152600401612bb69190616f6f565b60405180910390fd5b5b5b50508173ffffffffffffffffffffffffffffffffffffffff1663173bf7da826040518263ffffffff1660e01b8152600401612bfc9190616e7b565b5f604051808303815f87803b158015612c13575f5ffd5b505af1158015612c25573d5f5f3e3d5ffd5b50505050505b50505050565b60605f5f612c3d610749565b6001019050612c5785858361361b9092919063ffffffff16565b92509250509250929050565b612c6b611a32565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480612ccf57503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b612d05576040517fac52ccbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f838390501115612dba578373ffffffffffffffffffffffffffffffffffffffff1663f05c04e18285856040518463ffffffff1660e01b8152600401612d8c9392919061701d565b5f604051808303815f87803b158015612da3575f5ffd5b505af1158015612db5573d5f5f3e3d5ffd5b505050505b50505050565b612dc8615ae2565b612dd0610749565b6002015f837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f206040518060400160405290815f82015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f820160149054906101000a900460f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815250509050919050565b5f60018203612ef25760019050612f46565b60028203612f035760019050612f46565b60038203612f145760019050612f46565b60048203612f255760019050612f46565b6008821480612f345750600982145b15612f425760019050612f46565b5f90505b919050565b5f5f7fcd97a6611018468306afd07ac8b14141bc76df8b844b3bcba1768d81e45982005f1b9050805491505090565b5f5f612f84610749565b5f019050612f9b838261479690919063ffffffff16565b915050919050565b5f5f612fad610749565b6001019050612fc5838261479690919063ffffffff16565b915050919050565b5f5f612fd7610749565b6002015f857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f2090508273ffffffffffffffffffffffffffffffffffffffff16815f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161491505092915050565b5f8173ffffffffffffffffffffffffffffffffffffffff166130a3612f4b565b73ffffffffffffffffffffffffffffffffffffffff16149050919050565b5f8273ffffffffffffffffffffffffffffffffffffffff166130e2836133e8565b73ffffffffffffffffffffffffffffffffffffffff1614905092915050565b5f5f61310b610749565b9050613118815f01614c83565b91505090565b5f816020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c6004209050919050565b5f6040516001156131d857825160408114613171576041811461319057506131cb565b6040840151601b8160ff1c016020528060011b60011c606052506131a3565b60608401515f1a60205260408401516060525b50835f5260208301516040526020600160805f60015afa5191505f606052806040523d6131d8575b638baa579f5f526004601cfd5b5092915050565b5f60605f6131ed60086133e8565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036132775785858581818080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050509050905092509250506132fe565b8073ffffffffffffffffffffffffffffffffffffffff16637a0468b7338888886040518563ffffffff1660e01b81526004016132b6949392919061704d565b5f60405180830381865afa1580156132d0573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906132f8919061709f565b92509250505b935093915050565b5f60605f61331460096133e8565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361335a578585610100015192509250506133e0565b8073ffffffffffffffffffffffffffffffffffffffff1663e24f8f938686896040518463ffffffff1660e01b8152600401613397939291906170f9565b5f604051808303815f875af11580156133b2573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906133da919061709f565b92509250505b935093915050565b5f5f6133f2614d19565b90506008830361342757805f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505061348d565b6009830361345b57806001015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505061348d565b6040517f5691922f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b61349a614d47565b6134a2614e67565b6134b26134ad612f4b565b614f88565b6134ba613532565b565b5f60ff5f1b1960017ff63b257b7881773a84d328ab92140e19ab791f7b439c76ba9837aa0d6ad30af05f1c6134f19190617162565b60405160200161350191906160e8565b60405160208183030381529060405280519060200120169050805c8061352e5763aed595955f526004601cfd5b5050565b5f61353b610749565b905061354981600101615068565b613554815f01615068565b50565b5f7fc473de86d0138e06e4d4918a106463a7cc005258d2e21915272bcb4594c189009050805f0182908060018154018082558091505060019003905f5260205f20015f90919091909150555050565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040516135cc91906171c5565b5f60405180830381855af49150503d805f8114613604576040519150601f19603f3d011682016040523d82523d5f602084013e613609565b606091505b5050905080613616575f5ffd5b505050565b60605f600173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415801561366257506136608585614796565b155b156136a457836040517f7c84ecfb00000000000000000000000000000000000000000000000000000000815260040161369b9190615bc4565b60405180910390fd5b5f83036136dd576040517ff725081700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8267ffffffffffffffff8111156136f7576136f6615df4565b5b6040519080825280602002602001820160405280156137255781602001602082028036833780820191505090505b5091505f5f9050855f015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156137f65750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b801561380157508381105b156138c7578183828151811061381a57613819616ec3565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050855f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16915080806138bf906171db565b91505061378d565b600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415801561390357505f81115b1561393257826001826139169190617162565b8151811061392757613926616ec3565b5b602002602001015191505b80835250935093915050565b5f613947610749565b5f01905061395e848261512990919063ffffffff16565b8373ffffffffffffffffffffffffffffffffffffffff16636d61fe7084846040518363ffffffff1660e01b8152600401613999929190617222565b5f604051808303815f87803b1580156139b0575f5ffd5b505af11580156139c2573d5f5f3e3d5ffd5b5050505050505050565b5f6139d5610749565b60010190506139ed848261512990919063ffffffff16565b8373ffffffffffffffffffffffffffffffffffffffff16636d61fe7084846040518363ffffffff1660e01b8152600401613a28929190617222565b5f604051808303815f87803b158015613a3f575f5ffd5b505af1158015613a51573d5f5f3e3d5ffd5b5050505050505050565b5f82825f90600492613a6f93929190616872565b90613a7a9190617244565b90505f83836004818110613a9157613a90616ec3565b5b9050013560f81c60f81b90505f84846005908092613ab193929190616872565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050509050613afe836153f9565b15613b3e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613b35906172ec565b60405180910390fd5b60405180604001604052808773ffffffffffffffffffffffffffffffffffffffff168152602001837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815250613b93610749565b6002015f857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151815f0160146101000a81548160ff021916908360f81c02179055509050508573ffffffffffffffffffffffffffffffffffffffff16636d61fe70826040518263ffffffff1660e01b8152600401613c839190616e7b565b5f604051808303815f87803b158015613c9a575f5ffd5b505af1158015613cac573d5f5f3e3d5ffd5b50505050505050505050565b5f613cc1612f4b565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614613d3357806040517f741cbe03000000000000000000000000000000000000000000000000000000008152600401613d2a9190615bc4565b60405180910390fd5b613d3c846154af565b8373ffffffffffffffffffffffffffffffffffffffff16636d61fe7084846040518363ffffffff1660e01b8152600401613d77929190617222565b5f604051808303815f87803b158015613d8e575f5ffd5b505af1158015613da0573d5f5f3e3d5ffd5b5050505050505050565b5f613db3614d19565b90505f613dbf856133e8565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614613e3157806040517f786ae235000000000000000000000000000000000000000000000000000000008152600401613e289190615bc4565b60405180910390fd5b613e3b86866154dc565b60088503613ed257815f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636d61fe7085856040518363ffffffff1660e01b8152600401613ea0929190617222565b5f604051808303815f87803b158015613eb7575f5ffd5b505af1158015613ec9573d5f5f3e3d5ffd5b50505050613f67565b60098503613f6657816001015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636d61fe7085856040518363ffffffff1660e01b8152600401613f38929190617222565b5f604051808303815f87803b158015613f4f575f5ffd5b505af1158015613f61573d5f5f3e3d5ffd5b505050505b5b505050505050565b5f613f78610749565b5f0190505f5f8484810190613f8d9190616bab565b91509150613fa68287856155bc9092919063ffffffff16565b8573ffffffffffffffffffffffffffffffffffffffff16638a91b0e3826040518263ffffffff1660e01b8152600401613fdf9190616e7b565b5f604051808303815f87803b158015613ff6575f5ffd5b505af1158015614008573d5f5f3e3d5ffd5b50505050505050505050565b5f61401d610749565b60010190505f5f84848101906140339190616bab565b9150915061404c8287856155bc9092919063ffffffff16565b8573ffffffffffffffffffffffffffffffffffffffff16638a91b0e3826040518263ffffffff1660e01b81526004016140859190616e7b565b5f604051808303815f87803b15801561409c575f5ffd5b505af11580156140ae573d5f5f3e3d5ffd5b50505050505050505050565b5f82825f906004926140ce93929190616872565b906140d99190617244565b90505f838360049080926140ef93929190616872565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050905061413c826153f9565b61417b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161417290617354565b60405180910390fd5b5f614184610749565b6002015f847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f206040518060400160405290815f82015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f820160149054906101000a900460f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152505090508573ffffffffffffffffffffffffffffffffffffffff16815f015173ffffffffffffffffffffffffffffffffffffffff1614614300576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016142f7906173e2565b60405180910390fd5b60405180604001604052805f73ffffffffffffffffffffffffffffffffffffffff1681526020015f60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815250614358610749565b6002015f857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151815f0160146101000a81548160ff021916908360f81c02179055509050508573ffffffffffffffffffffffffffffffffffffffff16638a91b0e3836040518263ffffffff1660e01b81526004016144489190616e7b565b5f604051808303815f87803b15801561445f575f5ffd5b505af1158015614471573d5f5f3e3d5ffd5b50505050505050505050565b6144865f6154af565b8273ffffffffffffffffffffffffffffffffffffffff16638a91b0e383836040518363ffffffff1660e01b81526004016144c1929190617222565b5f604051808303815f87803b1580156144d8575f5ffd5b505af11580156144ea573d5f5f3e3d5ffd5b50505050505050565b5f6144fc614d19565b905060088414801561455b57508473ffffffffffffffffffffffffffffffffffffffff16815f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b156145ef57805f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638a91b0e384846040518363ffffffff1660e01b81526004016145bd929190617222565b5f604051808303815f87803b1580156145d4575f5ffd5b505af11580156145e6573d5f5f3e3d5ffd5b50505050614715565b60098414801561464d57508473ffffffffffffffffffffffffffffffffffffffff16816001015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b156146e257806001015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638a91b0e384846040518363ffffffff1660e01b81526004016146b0929190617222565b5f604051808303815f87803b1580156146c7575f5ffd5b505af11580156146d9573d5f5f3e3d5ffd5b50505050614714565b6040517f5691922f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b61471f5f856154dc565b5050505050565b5f5f5f5f8493508460081b92508460301b91508460501b90509193509193565b5f817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b5f8173ffffffffffffffffffffffffffffffffffffffff16600173ffffffffffffffffffffffffffffffffffffffff161415801561485d57505f73ffffffffffffffffffffffffffffffffffffffff16835f015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b905092915050565b365f833580850160208587010360208201945081359350808460051b8301118360401c171561489b5763ba597e7e5f526004601cfd5b831561490457835b600115614902576001810390508060051b86013580870160408101358082018581358201118660408501111782851782351760401c17156148eb5763ba597e7e5f526004601cfd5b846148f95750505050614902565b505050506148a3565b505b5050509250929050565b60605f8383905090508067ffffffffffffffff81111561493157614930615df4565b5b60405190808252806020026020018201604052801561496457816020015b606081526020019060019003908161494f5790505b5091505f5b818110156149f4573685858381811061498557614984616ec3565b5b90506020028101906149979190617400565b90506149c8815f0160208101906149ae9190617427565b82602001358380604001906149c39190616c11565b614bb3565b8483815181106149db576149da616ec3565b5b6020026020010181905250508080600101915050614969565b505092915050565b60605f8383905090508067ffffffffffffffff811115614a1f57614a1e615df4565b5b604051908082528060200260200182016040528015614a5257816020015b6060815260200190600190039081614a3d5790505b5091505f5b81811015614b415736858583818110614a7357614a72616ec3565b5b9050602002810190614a859190617400565b90505f614ab7825f016020810190614a9d9190617427565b8360200135848060400190614ab29190616c11565b614bec565b868581518110614aca57614ac9616ec3565b5b60200260200101819052819250505080614b32577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb783868581518110614b1357614b12616ec3565b5b6020026020010151604051614b29929190617452565b60405180910390a15b50508080600101915050614a57565b505092915050565b5f5f365f85855f90601492614b6093929190616872565b90614b6b91906168ed565b60601c93508585601490603492614b8493929190616872565b90614b8f9190617480565b5f1c925085856034908092614ba693929190616872565b9150915092959194509250565b60606040519050818382375f38838387895af1614bd2573d5f823e3d81fd5b3d8152602081013d5f823e3d810160405250949350505050565b5f60606040519050828482375f388483888a5af191503d8152602081013d5f823e3d81016040525094509492505050565b60606040519050818382375f388383875af4614c3b573d5f823e3d81fd5b3d8152602081013d5f823e3d8101604052509392505050565b5f60606040519050828482375f388483885af491503d8152602081013d5f823e3d810160405250935093915050565b5f5f73ffffffffffffffffffffffffffffffffffffffff16825f015f600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614159050919050565b5f5f7f088e45215d3756b04bd240e41d75700a696139d5b53082481ffc3914e48400005f1b90508091505090565b5f614d50610749565b5f0190505f614d6960018361588b90919063ffffffff16565b90505b600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614614e5a578073ffffffffffffffffffffffffffffffffffffffff16638a91b0e36040518163ffffffff1660e01b8152600401614dd790617501565b5f604051808303815f87803b158015614dee575f5ffd5b505af1925050508015614dff575060015b614e3f577f6c31ee2929752d85a6dc461efcf817aa81394aff41db1856ebfd71679fffc57081604051614e32919061751f565b60405180910390a1614e40565b5b614e53818361588b90919063ffffffff16565b9050614d6c565b614e6382615962565b5050565b5f614e70610749565b60010190505f614e8a60018361588b90919063ffffffff16565b90505b600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614614f7b578073ffffffffffffffffffffffffffffffffffffffff16638a91b0e36040518163ffffffff1660e01b8152600401614ef890617501565b5f604051808303815f87803b158015614f0f575f5ffd5b505af1925050508015614f20575060015b614f60577ffdea4600cf09065ff861064d4cd43cde3fae2134d9fbe6d66fd77cc67135c88281604051614f53919061751f565b60405180910390a1614f61565b5b614f74818361588b90919063ffffffff16565b9050614e8d565b614f8482615962565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614615065578073ffffffffffffffffffffffffffffffffffffffff16638a91b0e36040518163ffffffff1660e01b8152600401614ff290617501565b5f604051808303815f87803b158015615009575f5ffd5b505af192505050801561501a575060015b61505a577f57af23cbd8e148da6020d15e1ff9fb3c531aa9003d6bab6915013a7d8fd032368160405161504d919061751f565b60405180910390a161505b565b5b6150645f6154af565b5b50565b61507181614c83565b156150a8576040517f53c85e6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001815f015f600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16148061518f5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b156151d157806040517f7c84ecfb0000000000000000000000000000000000000000000000000000000081526004016151c89190615bc4565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16825f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461529e57806040517f40d3d1a40000000000000000000000000000000000000000000000000000000081526004016152959190615bc4565b60405180910390fd5b815f015f600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16825f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080825f015f600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b5f5f615403610749565b6002015f847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f2090505f73ffffffffffffffffffffffffffffffffffffffff16815f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415915050919050565b5f7fcd97a6611018468306afd07ac8b14141bc76df8b844b3bcba1768d81e45982005f1b90508181555050565b5f6154e5614d19565b9050600882036155355782815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506155b7565b600982036155845782816001015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506155b6565b6040517f5691922f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b505050565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614806156225750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b1561566457816040517f7c84ecfb00000000000000000000000000000000000000000000000000000000815260040161565b9190615bc4565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16835f015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461573157806040517f7c84ecfb0000000000000000000000000000000000000000000000000000000081526004016157289190615bc4565b60405180910390fd5b825f015f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16835f015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f835f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505050565b5f5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036158fc57816040517f7c84ecfb0000000000000000000000000000000000000000000000000000000081526004016158f39190615bc4565b60405180910390fd5b825f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905092915050565b5f815f015f600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614615ade575f819050825f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505f835f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506159c5565b5050565b60405180604001604052805f73ffffffffffffffffffffffffffffffffffffffff1681526020015f7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681525090565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b615b6681615b32565b82525050565b5f602082019050615b7f5f830184615b5d565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f615bae82615b85565b9050919050565b615bbe81615ba4565b82525050565b5f602082019050615bd75f830184615bb5565b92915050565b5f604051905090565b5f5ffd5b5f5ffd5b5f819050919050565b615c0081615bee565b8114615c0a575f5ffd5b50565b5f81359050615c1b81615bf7565b92915050565b615c2a81615ba4565b8114615c34575f5ffd5b50565b5f81359050615c4581615c21565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112615c6c57615c6b615c4b565b5b8235905067ffffffffffffffff811115615c8957615c88615c4f565b5b602083019150836001820283011115615ca557615ca4615c53565b5b9250929050565b5f5f5f5f60608587031215615cc457615cc3615be6565b5b5f615cd187828801615c0d565b9450506020615ce287828801615c37565b935050604085013567ffffffffffffffff811115615d0357615d02615bea565b5b615d0f87828801615c57565b925092505092959194509250565b5f8115159050919050565b615d3181615d1d565b82525050565b5f602082019050615d4a5f830184615d28565b92915050565b5f819050919050565b615d6281615d50565b8114615d6c575f5ffd5b50565b5f81359050615d7d81615d59565b92915050565b5f5f5f60408486031215615d9a57615d99615be6565b5b5f615da786828701615d6f565b935050602084013567ffffffffffffffff811115615dc857615dc7615bea565b5b615dd486828701615c57565b92509250509250925092565b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b615e2a82615de4565b810181811067ffffffffffffffff82111715615e4957615e48615df4565b5b80604052505050565b5f615e5b615bdd565b9050615e678282615e21565b919050565b5f5ffd5b5f5ffd5b5f67ffffffffffffffff821115615e8e57615e8d615df4565b5b615e9782615de4565b9050602081019050919050565b828183375f83830152505050565b5f615ec4615ebf84615e74565b615e52565b905082815260208101848484011115615ee057615edf615e70565b5b615eeb848285615ea4565b509392505050565b5f82601f830112615f0757615f06615c4b565b5b8135615f17848260208601615eb2565b91505092915050565b5f6101208284031215615f3657615f35615de0565b5b615f41610120615e52565b90505f615f5084828501615c37565b5f830152506020615f6384828501615c0d565b602083015250604082013567ffffffffffffffff811115615f8757615f86615e6c565b5b615f9384828501615ef3565b604083015250606082013567ffffffffffffffff811115615fb757615fb6615e6c565b5b615fc384828501615ef3565b6060830152506080615fd784828501615d6f565b60808301525060a0615feb84828501615c0d565b60a08301525060c0615fff84828501615d6f565b60c08301525060e082013567ffffffffffffffff81111561602357616022615e6c565b5b61602f84828501615ef3565b60e08301525061010082013567ffffffffffffffff81111561605457616053615e6c565b5b61606084828501615ef3565b6101008301525092915050565b5f5f5f6060848603121561608457616083615be6565b5b5f84013567ffffffffffffffff8111156160a1576160a0615bea565b5b6160ad86828701615f20565b93505060206160be86828701615d6f565b92505060406160cf86828701615c0d565b9150509250925092565b6160e281615bee565b82525050565b5f6020820190506160fb5f8301846160d9565b92915050565b5f6020828403121561611657616115615be6565b5b5f61612384828501615c0d565b91505092915050565b5f5f6020838503121561614257616141615be6565b5b5f83013567ffffffffffffffff81111561615f5761615e615bea565b5b61616b85828601615c57565b92509250509250929050565b5f5f6040838503121561618d5761618c615be6565b5b5f61619a85828601615c37565b92505060206161ab85828601615c0d565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6161e781615ba4565b82525050565b5f6161f883836161de565b60208301905092915050565b5f602082019050919050565b5f61621a826161b5565b61622481856161bf565b935061622f836161cf565b805f5b8381101561625f57815161624688826161ed565b975061625183616204565b925050600181019050616232565b5085935050505092915050565b5f6040820190508181035f8301526162848185616210565b90506162936020830184615bb5565b9392505050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6162cc81615d50565b82525050565b5f6162dd83836162c3565b60208301905092915050565b5f602082019050919050565b5f6162ff8261629a565b61630981856162a4565b9350616314836162b4565b805f5b8381101561634457815161632b88826162d2565b9750616336836162e9565b925050600181019050616317565b5085935050505092915050565b5f6020820190508181035f83015261636981846162f5565b905092915050565b5f5ffd5b5f610120828403121561638b5761638a616371565b5b81905092915050565b5f5f604083850312156163aa576163a9615be6565b5b5f83013567ffffffffffffffff8111156163c7576163c6615bea565b5b6163d385828601616375565b92505060206163e485828601615d6f565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f616420826163ee565b61642a81856163f8565b935061643a818560208601616408565b61644381615de4565b840191505092915050565b5f6020820190508181035f8301526164668184616416565b905092915050565b61647781615d50565b8114616481575f5ffd5b50565b5f813590506164928161646e565b92915050565b5f602082840312156164ad576164ac615be6565b5b5f6164ba84828501616484565b91505092915050565b5f5f5f604084860312156164da576164d9615be6565b5b5f6164e786828701616484565b935050602084013567ffffffffffffffff81111561650857616507615bea565b5b61651486828701615c57565b92509250509250925092565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f81519050919050565b5f82825260208201905092915050565b5f61656d82616549565b6165778185616553565b9350616587818560208601616408565b61659081615de4565b840191505092915050565b5f6165a68383616563565b905092915050565b5f602082019050919050565b5f6165c482616520565b6165ce818561652a565b9350836020820285016165e08561653a565b805f5b8581101561661b57848403895281516165fc858261659b565b9450616607836165ae565b925060208a019950506001810190506165e3565b50829750879550505050505092915050565b5f6020820190508181035f83015261664581846165ba565b905092915050565b5f61665782615ba4565b9050919050565b6166678161664d565b8114616671575f5ffd5b50565b5f813590506166828161665e565b92915050565b5f5f83601f84011261669d5761669c615c4b565b5b8235905067ffffffffffffffff8111156166ba576166b9615c4f565b5b6020830191508360208202830111156166d6576166d5615c53565b5b9250929050565b5f60ff82169050919050565b6166f2816166dd565b81146166fc575f5ffd5b50565b5f8135905061670d816166e9565b92915050565b5f5f5f5f6060858703121561672b5761672a615be6565b5b5f61673887828801616674565b945050602085013567ffffffffffffffff81111561675957616758615bea565b5b61676587828801616688565b93509350506040616778878288016166ff565b91505092959194509250565b61678d81615b32565b8114616797575f5ffd5b50565b5f813590506167a881616784565b92915050565b5f602082840312156167c3576167c2615be6565b5b5f6167d08482850161679a565b91505092915050565b5f7fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b5f61680e826167d9565b9050919050565b61681e81616804565b82525050565b604082015f8201516168385f8501826161de565b50602082015161684b6020850182616815565b50505050565b5f6040820190506168645f830184616824565b92915050565b5f5ffd5b5f5ffd5b5f5f858511156168855761688461686a565b5b838611156168965761689561686e565b5b6001850283019150848603905094509492505050565b5f82905092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b5f82821b905092915050565b5f6168f883836168ac565b8261690381356168b6565b925060148210156169435761693e7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000836014036008026168e1565b831692505b505092915050565b61695481615d50565b82525050565b5f82825260208201905092915050565b5f61697482616549565b61697e818561695a565b935061698e818560208601616408565b61699781615de4565b840191505092915050565b5f6060820190506169b55f830186615bb5565b6169c2602083018561694b565b81810360408301526169d4818461696a565b9050949350505050565b5f815190506169ec81616784565b92915050565b5f60208284031215616a0757616a06615be6565b5b5f616a14848285016169de565b91505092915050565b616a2681615bee565b82525050565b5f61012083015f830151616a425f8601826161de565b506020830151616a556020860182616a1d565b5060408301518482036040860152616a6d8282616563565b91505060608301518482036060860152616a878282616563565b9150506080830151616a9c60808601826162c3565b5060a0830151616aaf60a0860182616a1d565b5060c0830151616ac260c08601826162c3565b5060e083015184820360e0860152616ada8282616563565b915050610100830151848203610100860152616af68282616563565b9150508091505092915050565b5f6040820190508181035f830152616b1b8185616a2c565b9050616b2a602083018461694b565b9392505050565b5f81519050616b3f81615bf7565b92915050565b5f60208284031215616b5a57616b59615be6565b5b5f616b6784828501616b31565b91505092915050565b5f616b7a82615b85565b9050919050565b616b8a81616b70565b8114616b94575f5ffd5b50565b5f81359050616ba581616b81565b92915050565b5f5f60408385031215616bc157616bc0615be6565b5b5f616bce85828601616b97565b925050602083013567ffffffffffffffff811115616bef57616bee615bea565b5b616bfb85828601615ef3565b9150509250929050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83356001602003843603038112616c2d57616c2c616c05565b5b80840192508235915067ffffffffffffffff821115616c4f57616c4e616c09565b5b602083019250600182023603831315616c6b57616c6a616c0d565b5b509250929050565b5f81905092915050565b5f616c888385616c73565b9350616c95838584615ea4565b82840190509392505050565b5f616cad828486616c7d565b91508190509392505050565b5f604082019050616ccc5f830185615bb5565b616cd960208301846160d9565b9392505050565b616ce981615d1d565b8114616cf3575f5ffd5b50565b5f81519050616d0481616ce0565b92915050565b5f60208284031215616d1f57616d1e615be6565b5b5f616d2c84828501616cf6565b91505092915050565b5f604082019050616d485f8301856160d9565b616d556020830184615bb5565b9392505050565b5f616d67838561695a565b9350616d74838584615ea4565b616d7d83615de4565b840190509392505050565b5f606082019050616d9b5f830187615bb5565b616da860208301866160d9565b8181036040830152616dbb818486616d5c565b905095945050505050565b5f616dd8616dd384615e74565b615e52565b905082815260208101848484011115616df457616df3615e70565b5b616dff848285616408565b509392505050565b5f82601f830112616e1b57616e1a615c4b565b5b8151616e2b848260208601616dc6565b91505092915050565b5f60208284031215616e4957616e48615be6565b5b5f82015167ffffffffffffffff811115616e6657616e65615bea565b5b616e7284828501616e07565b91505092915050565b5f6020820190508181035f830152616e93818461696a565b905092915050565b616ea481616804565b82525050565b5f602082019050616ebd5f830184616e9b565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f819050919050565b5f819050919050565b5f616f1c616f17616f1284616ef0565b616ef9565b615bee565b9050919050565b616f2c81616f02565b82525050565b5f604082019050616f455f830185616f23565b8181036020830152616f57818461696a565b90509392505050565b616f6981616804565b82525050565b5f602082019050616f825f830184616f60565b92915050565b616f91816166dd565b82525050565b5f819050919050565b5f616fae6020840184615c37565b905092915050565b5f602082019050919050565b5f616fcd83856161bf565b9350616fd882616f97565b805f5b8581101561701057616fed8284616fa0565b616ff788826161ed565b975061700283616fb6565b925050600181019050616fdb565b5085925050509392505050565b5f6040820190506170305f830186616f88565b8181036020830152617043818486616fc2565b9050949350505050565b5f6060820190506170605f830187615bb5565b61706d602083018661694b565b8181036040830152617080818486616d5c565b905095945050505050565b5f8151905061709981615d59565b92915050565b5f5f604083850312156170b5576170b4615be6565b5b5f6170c28582860161708b565b925050602083015167ffffffffffffffff8111156170e3576170e2615bea565b5b6170ef85828601616e07565b9150509250929050565b5f6060820190508181035f8301526171118186616a2c565b905061712060208301856160d9565b61712d604083018461694b565b949350505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61716c82615bee565b915061717783615bee565b925082820390508181111561718f5761718e617135565b5b92915050565b5f61719f82616549565b6171a98185616c73565b93506171b9818560208601616408565b80840191505092915050565b5f6171d08284617195565b915081905092915050565b5f6171e582615bee565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361721757617216617135565b5b600182019050919050565b5f6020820190508181035f83015261723b818486616d5c565b90509392505050565b5f61724f83836168ac565b8261725a8135615b32565b9250600482101561729a576172957fffffffff00000000000000000000000000000000000000000000000000000000836004036008026168e1565b831692505b505092915050565b7f46756e6374696f6e2073656c6563746f7220616c7265616479207573656400005f82015250565b5f6172d6601e836163f8565b91506172e1826172a2565b602082019050919050565b5f6020820190508181035f830152617303816172ca565b9050919050565b7f46756e6374696f6e2073656c6563746f72206e6f7420757365640000000000005f82015250565b5f61733e601a836163f8565b91506173498261730a565b602082019050919050565b5f6020820190508181035f83015261736b81617332565b9050919050565b7f46756e6374696f6e2073656c6563746f72206e6f7420757365642062792074685f8201527f69732068616e646c657200000000000000000000000000000000000000000000602082015250565b5f6173cc602a836163f8565b91506173d782617372565b604082019050919050565b5f6020820190508181035f8301526173f9816173c0565b9050919050565b5f8235600160600383360303811261741b5761741a616c05565b5b80830191505092915050565b5f6020828403121561743c5761743b615be6565b5b5f61744984828501615c37565b91505092915050565b5f6040820190506174655f8301856160d9565b8181036020830152617477818461696a565b90509392505050565b5f61748b83836168ac565b826174968135615d50565b925060208210156174d6576174d17fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff836020036008026168e1565b831692505b505092915050565b50565b5f6174ec5f8361695a565b91506174f7826174de565b5f82019050919050565b5f6020820190508181035f830152617518816174e1565b9050919050565b5f6040820190506175325f830184615bb5565b8181036020830152617543816174e1565b90509291505056fea2646970667358221220a3ab10abccfc1e4991ad9a5f687ec3515e4bba3b7da0e732e5f7a7255be4dc6964736f6c634300081c0033"; + bytes public constant ERC7579_BOOTSTRAP_BYTECODE = + hex"6080604052348015600e575f5ffd5b506123028061001c5f395ff3fe60806040526004361061007e575f3560e01c80636b0d5cc41161004d5780636b0d5cc41461039d578063b0d691fe146103c5578063ea5f61d0146103ef578063eac9b20d1461042c57610085565b80630a664dba146102d25780635e87556d146102fc5780635faac46b14610338578063642219af1461037557610085565b3661008557005b5f3560e01c63bc197c81811463f23a6e6182141763150b7a02821417156100b057806020526020603cf35b505f6100ba610468565b6002015f5f357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f2090505f815f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f825f0160149054906101000a900460f81b90505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036101fc575f357fffffffff00000000000000000000000000000000000000000000000000000000166040517f48c9ceda0000000000000000000000000000000000000000000000000000000081526004016101f39190611706565b60405180910390fd5b61020a8160fe60f81b610496565b1561026657610225565b5f6040519050818101604052919050565b61022e36610214565b365f823761023c6014610214565b3360601b81525f5f6014360184875afa6102553d610214565b3d5f823e81610262573d81fd5b3d81f35b610273815f60f81b610496565b156102d05761028e565b5f6040519050818101604052919050565b6102973661027d565b365f82376102a5601461027d565b3360601b81525f5f60143601845f885af16102bf3d61027d565b3d5f823e816102cc573d81fd5b3d81f35b005b3480156102dd575f5ffd5b506102e66104e6565b6040516102f3919061175e565b60405180910390f35b348015610307575f5ffd5b50610322600480360381019061031d9190611802565b6104f4565b60405161032f9190611952565b60405180910390f35b348015610343575f5ffd5b5061035e600480360381019061035991906119cf565b61059f565b60405161036c929190611ac4565b60405180910390f35b348015610380575f5ffd5b5061039b60048036038101906103969190611802565b6105d0565b005b3480156103a8575f5ffd5b506103c360048036038101906103be9190611b82565b6108c3565b005b3480156103d0575f5ffd5b506103d96108d3565b6040516103e6919061175e565b60405180910390f35b3480156103fa575f5ffd5b50610415600480360381019061041091906119cf565b6108ea565b604051610423929190611ac4565b60405180910390f35b348015610437575f5ffd5b50610452600480360381019061044d9190611c09565b61091c565b60405161045f9190611cac565b60405180910390f35b5f5f7fe3a55571e8f241b58442871487cc151a8cb048bb4ad24e833467f724ec89a9005f1b90508091505090565b5f817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b5f6104ef610a3c565b905090565b6060303073ffffffffffffffffffffffffffffffffffffffff1663642219af8a8a8a8a8a8a8a6040516024016105309796959493929190611efc565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051602001610583929190611f61565b6040516020818303038152906040529050979650505050505050565b60605f5f6105ab610468565b5f0190506105c4858583610a6b9092919063ffffffff16565b92509250509250929050565b5f5b8787905081101561065c5761064f8888838181106105f3576105f2611f8f565b5b90506020028101906106059190611fc8565b5f0160208101906106169190611fef565b89898481811061062957610628611f8f565b5b905060200281019061063b9190611fc8565b806020019061064a919061201a565b610d8e565b80806001019150506105d2565b505f5b85859050811015610753575f73ffffffffffffffffffffffffffffffffffffffff1686868381811061069457610693611f8f565b5b90506020028101906106a69190611fc8565b5f0160208101906106b79190611fef565b73ffffffffffffffffffffffffffffffffffffffff160315610746576107458686838181106106e9576106e8611f8f565b5b90506020028101906106fb9190611fc8565b5f01602081019061070c9190611fef565b87878481811061071f5761071e611f8f565b5b90506020028101906107319190611fc8565b8060200190610740919061201a565b610e1c565b5b808060010191505061065f565b505f73ffffffffffffffffffffffffffffffffffffffff16835f01602081019061077d9190611fef565b73ffffffffffffffffffffffffffffffffffffffff16146107c3576107c2835f0160208101906107ad9190611fef565b8480602001906107bd919061201a565b610eab565b5b5f5b828290508110156108b9575f73ffffffffffffffffffffffffffffffffffffffff168383838181106107fa576107f9611f8f565b5b905060200281019061080c9190611fc8565b5f01602081019061081d9190611fef565b73ffffffffffffffffffffffffffffffffffffffff1603156108ac576108ab83838381811061084f5761084e611f8f565b5b90506020028101906108619190611fc8565b5f0160208101906108729190611fef565b84848481811061088557610884611f8f565b5b90506020028101906108979190611fc8565b80602001906108a6919061201a565b610f9d565b5b80806001019150506107c5565b5050505050505050565b6108ce838383610d8e565b505050565b5f6f71727de22e5e9d8baf0edac6f37da032905090565b60605f5f6108f6610468565b6001019050610910858583610a6b9092919063ffffffff16565b92509250509250929050565b61092461167c565b61092c610468565b6002015f837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f206040518060400160405290815f82015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f820160149054906101000a900460f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815250509050919050565b5f5f7fcd97a6611018468306afd07ac8b14141bc76df8b844b3bcba1768d81e45982005f1b9050805491505090565b60605f600173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614158015610ab25750610ab085856111fa565b155b15610af457836040517f7c84ecfb000000000000000000000000000000000000000000000000000000008152600401610aeb919061175e565b60405180910390fd5b5f8303610b2d576040517ff725081700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8267ffffffffffffffff811115610b4757610b4661207c565b5b604051908082528060200260200182016040528015610b755781602001602082028036833780820191505090505b5091505f5f9050855f015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610c465750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b8015610c5157508381105b15610d175781838281518110610c6a57610c69611f8f565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050855f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691508080610d0f906120d6565b915050610bdd565b600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610d5357505f81115b15610d825782600182610d66919061211d565b81518110610d7757610d76611f8f565b5b602002602001015191505b80835250935093915050565b5f610d97610468565b5f019050610dae84826112c990919063ffffffff16565b8373ffffffffffffffffffffffffffffffffffffffff16636d61fe7084846040518363ffffffff1660e01b8152600401610de992919061217c565b5f604051808303815f87803b158015610e00575f5ffd5b505af1158015610e12573d5f5f3e3d5ffd5b5050505050505050565b5f610e25610468565b6001019050610e3d84826112c990919063ffffffff16565b8373ffffffffffffffffffffffffffffffffffffffff16636d61fe7084846040518363ffffffff1660e01b8152600401610e7892919061217c565b5f604051808303815f87803b158015610e8f575f5ffd5b505af1158015610ea1573d5f5f3e3d5ffd5b5050505050505050565b5f610eb4610a3c565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610f2657806040517f741cbe03000000000000000000000000000000000000000000000000000000008152600401610f1d919061175e565b60405180910390fd5b610f2f84611599565b8373ffffffffffffffffffffffffffffffffffffffff16636d61fe7084846040518363ffffffff1660e01b8152600401610f6a92919061217c565b5f604051808303815f87803b158015610f81575f5ffd5b505af1158015610f93573d5f5f3e3d5ffd5b5050505050505050565b5f82825f90600492610fb1939291906121a6565b90610fbc91906121f6565b90505f83836004818110610fd357610fd2611f8f565b5b9050013560f81c60f81b90505f84846005908092610ff3939291906121a6565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050509050611040836115c6565b15611080576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611077906122ae565b60405180910390fd5b60405180604001604052808773ffffffffffffffffffffffffffffffffffffffff168152602001837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152506110d5610468565b6002015f857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151815f0160146101000a81548160ff021916908360f81c02179055509050508573ffffffffffffffffffffffffffffffffffffffff16636d61fe70826040518263ffffffff1660e01b81526004016111c59190611952565b5f604051808303815f87803b1580156111dc575f5ffd5b505af11580156111ee573d5f5f3e3d5ffd5b50505050505050505050565b5f8173ffffffffffffffffffffffffffffffffffffffff16600173ffffffffffffffffffffffffffffffffffffffff16141580156112c157505f73ffffffffffffffffffffffffffffffffffffffff16835f015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16148061132f5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b1561137157806040517f7c84ecfb000000000000000000000000000000000000000000000000000000008152600401611368919061175e565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16825f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461143e57806040517f40d3d1a4000000000000000000000000000000000000000000000000000000008152600401611435919061175e565b60405180910390fd5b815f015f600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16825f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080825f015f600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b5f7fcd97a6611018468306afd07ac8b14141bc76df8b844b3bcba1768d81e45982005f1b90508181555050565b5f5f6115d0610468565b6002015f847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f2090505f73ffffffffffffffffffffffffffffffffffffffff16815f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415915050919050565b60405180604001604052805f73ffffffffffffffffffffffffffffffffffffffff1681526020015f7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681525090565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b611700816116cc565b82525050565b5f6020820190506117195f8301846116f7565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6117488261171f565b9050919050565b6117588161173e565b82525050565b5f6020820190506117715f83018461174f565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f8401126117a05761179f61177f565b5b8235905067ffffffffffffffff8111156117bd576117bc611783565b5b6020830191508360208202830111156117d9576117d8611787565b5b9250929050565b5f5ffd5b5f604082840312156117f9576117f86117e0565b5b81905092915050565b5f5f5f5f5f5f5f6080888a03121561181d5761181c611777565b5b5f88013567ffffffffffffffff81111561183a5761183961177b565b5b6118468a828b0161178b565b9750975050602088013567ffffffffffffffff8111156118695761186861177b565b5b6118758a828b0161178b565b9550955050604088013567ffffffffffffffff8111156118985761189761177b565b5b6118a48a828b016117e4565b935050606088013567ffffffffffffffff8111156118c5576118c461177b565b5b6118d18a828b0161178b565b925092505092959891949750929550565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f611924826118e2565b61192e81856118ec565b935061193e8185602086016118fc565b6119478161190a565b840191505092915050565b5f6020820190508181035f83015261196a818461191a565b905092915050565b61197b8161173e565b8114611985575f5ffd5b50565b5f8135905061199681611972565b92915050565b5f819050919050565b6119ae8161199c565b81146119b8575f5ffd5b50565b5f813590506119c9816119a5565b92915050565b5f5f604083850312156119e5576119e4611777565b5b5f6119f285828601611988565b9250506020611a03858286016119bb565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b611a3f8161173e565b82525050565b5f611a508383611a36565b60208301905092915050565b5f602082019050919050565b5f611a7282611a0d565b611a7c8185611a17565b9350611a8783611a27565b805f5b83811015611ab7578151611a9e8882611a45565b9750611aa983611a5c565b925050600181019050611a8a565b5085935050505092915050565b5f6040820190508181035f830152611adc8185611a68565b9050611aeb602083018461174f565b9392505050565b5f611afc8261173e565b9050919050565b611b0c81611af2565b8114611b16575f5ffd5b50565b5f81359050611b2781611b03565b92915050565b5f5f83601f840112611b4257611b4161177f565b5b8235905067ffffffffffffffff811115611b5f57611b5e611783565b5b602083019150836001820283011115611b7b57611b7a611787565b5b9250929050565b5f5f5f60408486031215611b9957611b98611777565b5b5f611ba686828701611b19565b935050602084013567ffffffffffffffff811115611bc757611bc661177b565b5b611bd386828701611b2d565b92509250509250925092565b611be8816116cc565b8114611bf2575f5ffd5b50565b5f81359050611c0381611bdf565b92915050565b5f60208284031215611c1e57611c1d611777565b5b5f611c2b84828501611bf5565b91505092915050565b5f7fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b5f611c6982611c34565b9050919050565b611c7981611c5f565b82525050565b604082015f820151611c935f850182611a36565b506020820151611ca66020850182611c70565b50505050565b5f604082019050611cbf5f830184611c7f565b92915050565b5f82825260208201905092915050565b5f819050919050565b5f611cec6020840184611988565b905092915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83356001602003843603038112611d1c57611d1b611cfc565b5b83810192508235915060208301925067ffffffffffffffff821115611d4457611d43611cf4565b5b600182023603831315611d5a57611d59611cf8565b5b509250929050565b5f82825260208201905092915050565b828183375f83830152505050565b5f611d8b8385611d62565b9350611d98838584611d72565b611da18361190a565b840190509392505050565b5f60408301611dbd5f840184611cde565b611dc95f860182611a36565b50611dd76020840184611d00565b8583036020870152611dea838284611d80565b925050508091505092915050565b5f611e038383611dac565b905092915050565b5f82356001604003833603038112611e2657611e25611cfc565b5b82810191505092915050565b5f602082019050919050565b5f611e498385611cc5565b935083602084028501611e5b84611cd5565b805f5b87811015611e9e578484038952611e758284611e0b565b611e7f8582611df8565b9450611e8a83611e32565b925060208a01995050600181019050611e5e565b50829750879450505050509392505050565b5f60408301611ec15f840184611cde565b611ecd5f860182611a36565b50611edb6020840184611d00565b8583036020870152611eee838284611d80565b925050508091505092915050565b5f6080820190508181035f830152611f1581898b611e3e565b90508181036020830152611f2a818789611e3e565b90508181036040830152611f3e8186611eb0565b90508181036060830152611f53818486611e3e565b905098975050505050505050565b5f604082019050611f745f83018561174f565b8181036020830152611f86818461191a565b90509392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f82356001604003833603038112611fe357611fe2611fbc565b5b80830191505092915050565b5f6020828403121561200457612003611777565b5b5f61201184828501611988565b91505092915050565b5f5f8335600160200384360303811261203657612035611fbc565b5b80840192508235915067ffffffffffffffff82111561205857612057611fc0565b5b60208301925060018202360383131561207457612073611fc4565b5b509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6120e08261199c565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612112576121116120a9565b5b600182019050919050565b5f6121278261199c565b91506121328361199c565b925082820390508181111561214a576121496120a9565b5b92915050565b5f61215b83856118ec565b9350612168838584611d72565b6121718361190a565b840190509392505050565b5f6020820190508181035f830152612195818486612150565b90509392505050565b5f5ffd5b5f5ffd5b5f5f858511156121b9576121b861219e565b5b838611156121ca576121c96121a2565b5b6001850283019150848603905094509492505050565b5f82905092915050565b5f82821b905092915050565b5f61220183836121e0565b8261220c81356116cc565b9250600482101561224c576122477fffffffff00000000000000000000000000000000000000000000000000000000836004036008026121ea565b831692505b505092915050565b5f82825260208201905092915050565b7f46756e6374696f6e2073656c6563746f7220616c7265616479207573656400005f82015250565b5f612298601e83612254565b91506122a382612264565b602082019050919050565b5f6020820190508181035f8301526122c58161228c565b905091905056fea2646970667358221220b90741b9c42163f6c8d87ffeafdf59adca32d114497979a80f2aabbe52604d3764736f6c634300081c0033"; + bytes public constant ERC7579_RHINESTONE_TRAMPOLOINE_BYTECODE = + hex"6080604052348015600e575f5ffd5b5061081d8061001c5f395ff3fe608060405260043610610058575f3560e01c80630a664dba146101b55780635faac46b146101e6578063b0d691fe14610213578063e1c7392a14610235578063ea5f61d014610249578063eac9b20d146102685761005f565b3661005f57005b5f3560e01c63bc197c81811463f23a6e6182141763150b7a028214171561008a57806020526020603cf35b505f80356001600160e01b03191681527ff88ce1fdb7fb1cbd3282e49729100fa3f2d6ee9f797961fe4fb1871cea89ea046020526040902080546001600160a01b03811690600160a01b900460f81b8161010957604051632464e76d60e11b81526001600160e01b03195f351660048201526024015b60405180910390fd5b61011781607f60f91b61032e565b156101685760408051368101909152365f823760408051601481019091523360601b90525f803660140183865afa90506101573d60408051918201905290565b3d5f823e81610164573d81fd5b3d81f35b610172815f61032e565b156101b35760408051368101909152365f823760408051601481019091523360601b90525f80366014018382875af190506101573d60408051918201905290565b005b3480156101c0575f5ffd5b506101c9610345565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101f1575f5ffd5b5061020561020036600461068d565b610373565b6040516101dd9291906106c2565b34801561021e575f5ffd5b506f71727de22e5e9d8baf0edac6f37da0326101c9565b348015610240575f5ffd5b506101b36103ae565b348015610254575f5ffd5b5061020561026336600461068d565b610480565b348015610273575f5ffd5b50610300610282366004610724565b6040805180820182525f80825260209182018190526001600160e01b03199390931683527ff88ce1fdb7fb1cbd3282e49729100fa3f2d6ee9f797961fe4fb1871cea89ea048152918190208151808301909252546001600160a01b0381168252600160a01b900460f81b6001600160f81b0319169181019190915290565b6040805182516001600160a01b031681526020928301516001600160f81b03191692810192909252016101dd565b6001600160f81b0319828116908216145b92915050565b5f61036e7f36e05829dd1b9a4411d96a3549582172d7f071c1c0db5c573fcf94eb284316085490565b905090565b60605f7ff88ce1fdb7fb1cbd3282e49729100fa3f2d6ee9f797961fe4fb1871cea89ea026103a28186866104ab565b92509250509250929050565b6103ea7334dedac925c00d63bd91800ff821e535fe59d6f57f36e05829dd1b9a4411d96a3549582172d7f071c1c0db5c573fcf94eb2843160855565b60408051737066f491ce8b5f782f315dfbd549f2107a32641360611b60208201528151601481830301815260348201928390526306d61fe760e41b9092527334dedac925c00d63bd91800ff821e535fe59d6f591636d61fe7091610451919060380161074b565b5f604051808303815f87803b158015610468575f5ffd5b505af115801561047a573d5f5f3e3d5ffd5b50505050565b60605f7ff88ce1fdb7fb1cbd3282e49729100fa3f2d6ee9f797961fe4fb1871cea89ea036103a28186865b60605f6001600160a01b0384166001148015906104cf57506104cd8585610653565b155b156104f857604051637c84ecfb60e01b81526001600160a01b0385166004820152602401610100565b825f036105185760405163f725081760e01b815260040160405180910390fd5b8267ffffffffffffffff81111561053157610531610780565b60405190808252806020026020018201604052801561055a578160200160208202803683370190505b506001600160a01b038086165f90815260208890526040812054929450911691505b6001600160a01b0382161580159061059e57506001600160a01b038216600114155b80156105a957508381105b1561060257818382815181106105c1576105c1610794565b6001600160a01b039283166020918202929092018101919091529281165f9081529287905260409092205490911690806105fa816107bc565b91505061057c565b6001600160a01b03821660011480159061061b57505f81115b15610647578261062c6001836107d4565b8151811061063c5761063c610794565b602002602001015191505b80835250935093915050565b5f60016001600160a01b0383161480159061068657506001600160a01b038281165f908152602085905260409020541615155b9392505050565b5f5f6040838503121561069e575f5ffd5b82356001600160a01b03811681146106b4575f5ffd5b946020939093013593505050565b604080825283519082018190525f9060208501906060840190835b818110156107045783516001600160a01b03168352602093840193909201916001016106dd565b50506001600160a01b039490941660209390930192909252509092915050565b5f60208284031215610734575f5ffd5b81356001600160e01b031981168114610686575f5ffd5b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f600182016107cd576107cd6107a8565b5060010190565b8181038181111561033f5761033f6107a856fea26469706673582212208b8d179eb9f1d514092184d86650903af803b01f367d0d2440620538d93230ac64736f6c634300081b0033"; + bytes public constant MSAPROXY_BYTECODE = + hex"60806040526040516107983803806107988339818101604052810190610025919061054b565b61003361004a60201b60201c565b61004382826100af60201b60201c565b50506106b8565b5f60ff5f1b1960017ff63b257b7881773a84d328ab92140e19ab791f7b439c76ba9837aa0d6ad30af05f1c61007f91906105db565b60405160200161008f919061061d565b604051602081830303815290604052805190602001201690506001815d50565b6100be8261013360201b60201c565b8173ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a25f815111156101205761011a828261020260201b60201c565b5061012f565b61012e61028860201b60201c565b5b5050565b5f8173ffffffffffffffffffffffffffffffffffffffff163b0361018e57806040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526004016101859190610645565b60405180910390fd5b806101c07f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5f1b6102c460201b60201c565b5f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60605f5f8473ffffffffffffffffffffffffffffffffffffffff168460405161022b91906106a2565b5f60405180830381855af49150503d805f8114610263576040519150601f19603f3d011682016040523d82523d5f602084013e610268565b606091505b509150915061027e8583836102cd60201b60201c565b9250505092915050565b5f3411156102c2576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f819050919050565b6060826102e8576102e38261036060201b60201c565b610358565b5f825114801561030e57505f8473ffffffffffffffffffffffffffffffffffffffff163b145b1561035057836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016103479190610645565b60405180910390fd5b819050610359565b5b9392505050565b5f815111156103725780518082602001fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f604051905090565b5f5ffd5b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6103de826103b5565b9050919050565b6103ee816103d4565b81146103f8575f5ffd5b50565b5f81519050610409816103e5565b92915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61045d82610417565b810181811067ffffffffffffffff8211171561047c5761047b610427565b5b80604052505050565b5f61048e6103a4565b905061049a8282610454565b919050565b5f67ffffffffffffffff8211156104b9576104b8610427565b5b6104c282610417565b9050602081019050919050565b8281835e5f83830152505050565b5f6104ef6104ea8461049f565b610485565b90508281526020810184848401111561050b5761050a610413565b5b6105168482856104cf565b509392505050565b5f82601f8301126105325761053161040f565b5b81516105428482602086016104dd565b91505092915050565b5f5f60408385031215610561576105606103ad565b5b5f61056e858286016103fb565b925050602083015167ffffffffffffffff81111561058f5761058e6103b1565b5b61059b8582860161051e565b9150509250929050565b5f819050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6105e5826105a5565b91506105f0836105a5565b9250828203905081811115610608576106076105ae565b5b92915050565b610617816105a5565b82525050565b5f6020820190506106305f83018461060e565b92915050565b61063f816103d4565b82525050565b5f6020820190506106585f830184610636565b92915050565b5f81519050919050565b5f81905092915050565b5f61067c8261065e565b6106868185610668565b93506106968185602086016104cf565b80840191505092915050565b5f6106ad8284610672565b915081905092915050565b60d4806106c45f395ff3fe6080604052600a600c565b005b60186014601a565b6026565b565b5f60216044565b905090565b365f5f375f5f365f845af43d5f5f3e805f81146040573d5ff35b3d5ffd5b5f606e7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5f1b6095565b5f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b5f81905091905056fea2646970667358221220c1de7109ed587fe9e758c24d4d24494182d4b6d7c4bdda4e7a5f1fea44ff709564736f6c634300081c0033"; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/KernelPrecompiles.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/KernelPrecompiles.sol new file mode 100644 index 0000000..5bb8cf0 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/KernelPrecompiles.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IKernel } from "../../accounts/kernel/interfaces/IKernel.sol"; +import { IKernelFactory } from "../../accounts/kernel/interfaces/IKernelFactory.sol"; + +// Types +import { ValidationId } from "../../accounts/kernel/types/Types.sol"; + +// Utils +import { label } from "../../test/utils/Vm.sol"; +import { BytecodeDeployer } from "./BytecodeDeployer.sol"; + +interface ISetSelector is IKernel { + function setSelector(ValidationId vId, bytes4 selector, bool allowed) external; +} + +/// @notice Precompiled Kernel contracts +contract KernelPrecompiles is BytecodeDeployer { + /*////////////////////////////////////////////////////////////// + DEPLOY + //////////////////////////////////////////////////////////////*/ + + function deployKernel(address entrypoint) internal returns (IKernel kernel) { + // Concat constructor params to bytecode + bytes memory creationBytecode = bytes.concat(KERNEL_BYTECODE, abi.encode(entrypoint)); + kernel = IKernel(_deploy(creationBytecode)); + label(address(kernel), "Kernel"); + } + + function deployKernelWithSetSelector(address entrypoint) + internal + returns (ISetSelector kernel) + { + // Concat constructor params to bytecode + bytes memory creationBytecode = + bytes.concat(KERNEL_WITH_SETSELECTOR_BYTECODE, abi.encode(entrypoint)); + kernel = ISetSelector(_deploy(creationBytecode)); + label(address(kernel), "SetSelector"); + } + + function deployKernelFactory(address kernelImpl) + internal + returns (IKernelFactory kernelFactory) + { + // Concat constructor params to bytecode + bytes memory creationBytecode = + bytes.concat(KERNEL_FACTORY_BYTECODE, abi.encode(kernelImpl)); + kernelFactory = IKernelFactory(_deploy(creationBytecode)); + label(address(kernelFactory), "KernelFactory"); + } + + /*////////////////////////////////////////////////////////////// + BYTECODES + //////////////////////////////////////////////////////////////*/ + + /* solhint-disable max-line-length */ + bytes public constant KERNEL_BYTECODE = + hex"61014060405234801561001157600080fd5b506040516172093803806172098339810160408190526100309161015a565b306080524660a05260608061007a604080518082018252600681526512d95c9b995b60d21b60208083019190915282518084019093526005835264302e332e3160d81b9083015291565b815160209283012081519183019190912060c082905260e0819052604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8152808501939093528281019190915246606083015230608083015260a0909120610100526001600160a01b03851661012052805163deadbeef60e01b92810192909252805160048184030181526024909201905261011b9250905061018a565b7f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f80546001600160a81b03191660589290921c919091179055506101c8565b60006020828403121561016c57600080fd5b81516001600160a01b038116811461018357600080fd5b9392505050565b805160208201516001600160581b03198116919060158210156101c1576001600160581b0319601583900360031b81901b82161692505b5050919050565b60805160a05160c05160e0516101005161012051616fa5610264600039600081816102ef0152818161069401528181610cb701528181610fec015281816111b6015281816115a301528181611a7101528181611b9501528181611d590152818161253901528181612e6b015261303c0152600061465b01526000614715015260006146ef0152600061469f0152600061467c0152616fa56000f3fe6080604052600436106101d15760003560e01c80639517e29f116100f7578063c3e5897811610095578063e9ae5c5311610064578063e9ae5c53146107ef578063f1f7f0f914610802578063f23a6e6114610830578063f2dc691d1461085d57610210565b8063c3e589781461076f578063d03c79141461079c578063d691c964146107bc578063e6f3d50a146107dc57610210565b8063a71763a8116100d1578063a71763a8146106ce578063adb610a3146106e1578063b8afe17d146106f6578063bc197c811461074057610210565b80639517e29f1461062a5780639cfd7cff1461063d578063a65d69d41461068257610210565b806352141cd91161016f57806384b0196e1161013e57806384b0196e146105b25780638dd7712f146105da57806390ef8862146105ed5780639198bdf51461061757610210565b806352141cd9146104ed57806357b3a5f4146105005780636e6fa0c61461055a578063721e67f41461057a57610210565b806319822f7c116101ab57806319822f7c146104845780631f1b92e3146104a55780633659cfe6146104ba5780633c3b752b146104cd57610210565b8063112d3a7d146103ea578063150b7a021461041f5780631626ba7e1461046457610210565b3661021057604080513381523460208201527f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f88525874910160405180910390a1005b60006102276000356001600160e01b03191661087d565b604080516060808201835283546001600160a01b039081168084526001909501549081166020840152600160a01b900460f81b6001600160f81b03191692820192909252925060009161028d57604051631cd4b64760e21b815260040160405180910390fd5b82516060906001600160a01b03166001148015906102b6575083516001600160a01b0390811614155b156102d15783516102ca90346000366108b7565b905061032d565b83516001600160a01b03908116900361032d57336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461032d576040516348f5c3ed60e01b815260040160405180910390fd5b604084015161033d90600061093c565b156103595761034f8460200151610953565b909350915061039e565b6040840151610370906001600160f81b031961093c565b156103855761034f84602001516000366109a3565b604051632d6a6bb760e01b815260040160405180910390fd5b826103ab57815160208301fd5b83516001600160a01b03166001148015906103d1575083516001600160a01b0390811614155b156103e25783516103e290826109d2565b815160208301f35b3480156103f657600080fd5b5061040a610405366004615f19565b610a34565b60405190151581526020015b60405180910390f35b34801561042b57600080fd5b5061044b61043a366004615f74565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001610416565b34801561047057600080fd5b5061044b61047f366004615fe6565b610b09565b61049761049236600461604a565b610caa565b604051908152602001610416565b6104b86104b33660046160ab565b610fc5565b005b6104b86104c83660046160c6565b61119c565b3480156104d957600080fd5b506104b86104e836600461613f565b6113b5565b6104b86104fb366004616205565b611589565b34801561050c57600080fd5b5061052061051b3660046162b1565b61191e565b6040805182516001600160a01b03908116825260208085015190911690820152918101516001600160f81b03191690820152606001610416565b34801561056657600080fd5b5061040a6105753660046162ce565b61198a565b34801561058657600080fd5b5061059a6105953660046160c6565b6119d2565b60405190516001600160a01b03168152602001610416565b3480156105be57600080fd5b506105c7611a08565b6040516104169796959493929190616355565b6104b86105e83660046163ed565b611a66565b3480156105f957600080fd5b50610602611b5e565b60405163ffffffff9091168152602001610416565b6104b86106253660046164c2565b611b7b565b6104b8610638366004615f19565b611d3f565b34801561064957600080fd5b5060408051808201825260168152756b65726e656c2e616476616e6365642e76302e332e3160501b60208201529051610416919061663d565b34801561068e57600080fd5b506106b67f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610416565b6104b86106dc366004615f19565b61251f565b3480156106ed57600080fd5b50610602612b78565b34801561070257600080fd5b50610716610711366004616650565b612b95565b60408051825163ffffffff1681526020928301516001600160a01b03169281019290925201610416565b34801561074c57600080fd5b5061044b61075b36600461666b565b63bc197c8160e01b98975050505050505050565b34801561077b57600080fd5b5061078f61078a3660046162b1565b612bfd565b604051610416919061671f565b3480156107a857600080fd5b5061040a6107b73660046167a2565b612cd9565b6107cf6107ca366004615fe6565b612dc6565b60405161041691906167bb565b6104b86107ea366004616820565b612e51565b6104b86107fd366004615fe6565b613022565b34801561080e57600080fd5b506108176131db565b6040516001600160581b03199091168152602001610416565b34801561083c57600080fd5b5061044b61084b366004616887565b63f23a6e6160e01b9695505050505050565b34801561086957600080fd5b5061040a6108783660046167a2565b6131ee565b6001600160e01b03191660009081527f7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b6020526040902090565b60405163d68f602560e01b81526060906001600160a01b0386169063d68f6025906108ec90339088908890889060040161690d565b6000604051808303816000875af115801561090b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109339190810190616966565b95945050505050565b6001600160f81b0319828116908216145b92915050565b6000606060408051368101909152366000823760408051601481019091523360601b9052600080366014018382885af192505060405190503d8152602081013d6000823e3d810160405250915091565b604051600090828482376000388483885af491503d8152602081013d6000823e3d810160405250935093915050565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906109fe90849060040161663d565b600060405180830381600087803b158015610a1857600080fd5b505af1158015610a2c573d6000803e3d6000fd5b505050505050565b600060018503610a91576000610a4861320e565b6001016000610a5d8760581b600160f81b1790565b6001600160581b0319168152602081019190915260400160002054600160201b90046001600160a01b031614159050610b01565b60028503610ab7576000610aa485613232565b546001600160a01b031614159050610b01565b60038503610afd576001600160a01b038416610ae8610ada6004600086886169d8565b610ae391616a02565b61087d565b600101546001600160a01b0316149050610b01565b5060005b949350505050565b600080610b1461320e565b90506000366000610b25878761326b565b925092509250610b3c610b358490565b600061093c565b15610b4957835460581b92505b6001600160581b031983166000908152600185016020526040902054600160201b90046001600160a01b0316610b9257604051631a0a9b9f60e21b815260040160405180910390fd5b610ba083600160f81b61093c565b15610c3a576000610bb18460581c90565b9050806001600160a01b031663f551e2ee33610bcc8c6132d8565b86866040518563ffffffff1660e01b8152600401610bed949392919061690d565b602060405180830381865afa158015610c0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2e9190616a3a565b95505050505050610ca3565b6000610c468460081b90565b6001600160e01b03198116600090815260038701602052604090205490915060f01b600160f11b811615610c8d57604051635b71057960e01b815260040160405180910390fd5b610c9a82338c878761332e565b96505050505050505b9392505050565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610cf5576040516348f5c3ed60e01b815260040160405180910390fd5b6000610cff61320e565b90506000806000610d13886020013561342c565b91945092509050610d2582600061093c565b15610d315750825460581b5b610d3d83828a8a61345a565b6001600160581b031982166000908152600186016020908152604080832081518083019092525463ffffffff81168252600160201b90046001600160a01b031691810191909152919650610d92908490613656565b8015610db057508454815163ffffffff600160c81b90920482169116105b15610dce57604051633ab3447f60e11b815260040160405180910390fd5b60208101516001600160a01b038116610dfa57604051631a0a9b9f60e21b815260040160405180910390fd5b600089815260208190526040902080546001600160a01b0319166001600160a01b03831690811790915560001901610ec257610e37846000613656565b8015610e9f57506001600160581b031983166000908152600287016020526040812090610e6760608d018d616a57565b610e76916004916000916169d8565b610e7f91616a02565b6001600160e01b031916815260208101919091526040016000205460ff16155b15610ebd57604051631a0a9b9f60e21b815260040160405180910390fd5b610fa8565b610ecd846000613656565b8015610f3557506001600160581b031983166000908152600287016020526040812090610efd60608d018d616a57565b610f0c916008916004916169d8565b610f1591616a02565b6001600160e01b031916815260208101919091526040016000205460ff16155b15610f5357604051631a0a9b9f60e21b815260040160405180910390fd5b638dd7712f60e01b610f6860608c018c616a57565b610f77916004916000916169d8565b610f8091616a02565b6001600160e01b03191614610fa85760405163dbbb044b60e01b815260040160405180910390fd5b8715610fb857343434348b335af1505b5050505050509392505050565b6000610fdf610fd261320e565b546001600160a81b031690565b9050336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480159061101a5750333014155b1561118f5760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015611063573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110879190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f6025906110c190339034908690369060040161690d565b6000604051808303816000875af11580156110e0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111089190810190616966565b905061111383613669565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061113f90849060040161663d565b600060405180830381600087803b15801561115957600080fd5b505af115801561116d573d6000803e3d6000fd5b50505050505050565b6040516348f5c3ed60e01b815260040160405180910390fd5b61119882613669565b5050565b60006111a9610fd261320e565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015906111e45750333014155b156113595760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa15801561122d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112519190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f60259061128b90339034908690369060040161690d565b6000604051808303816000875af11580156112aa573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112d29190810190616966565b9050827f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55826001600160a01b03167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a2604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061113f90849060040161663d565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8290556040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a25050565b60006113bf61320e565b805490915060581b6001600160581b031916156114195760405162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b60448201526064015b60405180910390fd5b6001600160581b0319891661144157604051631a0a9b9f60e21b815260040160405180910390fd5b8861145081600160f81b613656565b8015611465575061146581600160f91b613656565b15611483576040516361c4e91b60e11b815260040160405180910390fd5b61148c8a61374b565b60408051808201909152600181526001600160a01b038a166020820152825463ffffffff60a81b1916600160a81b1783556114cb8b828b8b8b8b6137ad565b60005b8481101561157b576000308787848181106114eb576114eb616abf565b90506020028101906114fd9190616a57565b60405161150b929190616ad5565b6000604051808303816000865af19150503d8060008114611548576040519150601f19603f3d011682016040523d82523d6000602084013e61154d565b606091505b505090508061157257604051636534eae560e11b815260048101839052602401611410565b506001016114ce565b505050505050505050505050565b6000611596610fd261320e565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015906115d15750333014155b1561181d5760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa15801561161a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163e9190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f60259061167890339034908690369060040161690d565b6000604051808303816000875af1158015611697573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116bf9190810190616966565b905060006116cb61320e565b90506001600160581b031989166116f557604051631a0a9b9f60e21b815260040160405180910390fd5b8861170481600160f81b613656565b8015611719575061171981600160f91b613656565b15611737576040516361c4e91b60e11b815260040160405180910390fd5b6117408a61374b565b600061174a61320e565b6001600160581b03198c1660009081526001919091016020526040902054600160201b90046001600160a01b0316036117b757604080518082019091528254600160a81b900463ffffffff1681526001600160a01b038a1660208201526117b58b828b8b8b8b6137ad565b505b5050604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906117e590849060040161663d565b600060405180830381600087803b1580156117ff57600080fd5b505af1158015611813573d6000803e3d6000fd5b505050505061116d565b600061182761320e565b90506001600160581b0319881661185157604051631a0a9b9f60e21b815260040160405180910390fd5b8761186081600160f81b613656565b8015611875575061187581600160f91b613656565b15611893576040516361c4e91b60e11b815260040160405180910390fd5b61189c8961374b565b60006118a661320e565b6001600160581b03198b1660009081526001919091016020526040902054600160201b90046001600160a01b03160361191357604080518082019091528254600160a81b900463ffffffff1681526001600160a01b03891660208201526119118a828a8a8a8a6137ad565b505b505050505050505050565b60408051606081018252600080825260208201819052918101919091526119448261087d565b6040805160608101825282546001600160a01b0390811682526001909301549283166020820152600160a01b90920460f81b6001600160f81b0319169082015292915050565b600061199461320e565b6001600160581b031984166000908152600291909101602090815260408083206001600160e01b03198616845290915290205460ff16905092915050565b6040805160208101909152600081526119ea82613232565b604080516020810190915290546001600160a01b0316815292915050565b600f60f81b6060806000808083611a54604080518082018252600681526512d95c9b995b60d21b60208083019190915282518084019093526005835264302e332e3160d81b9083015291565b97989097965046955030945091925090565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611aaf576040516348f5c3ed60e01b815260040160405180910390fd5b6000818152602081905260409020546060906001600160a01b031660018114611afa57611af78134611ae46060880188616a57565b611af29160049082906169d8565b6108b7565b91505b600080611b2130611b0e6060890189616a57565b611b1c9160049082906169d8565b6109a3565b9150915081611b435760405163f21e646b60e01b815260040160405180910390fd5b6001600160a01b038316600114610a2c57610a2c83856109d2565b6000611b6861320e565b54600160c81b900463ffffffff16919050565b6000611b88610fd261320e565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801590611bc35750333014155b15611d265760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015611c0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c309190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f602590611c6a90339034908690369060040161690d565b6000604051808303816000875af1158015611c89573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611cb19190810190616966565b9050611cc2898989898989896139fc565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da90611cee90849060040161663d565b600060405180830381600087803b158015611d0857600080fd5b505af1158015611d1c573d6000803e3d6000fd5b5050505050611d35565b611d35888888888888886139fc565b5050505050505050565b6000611d4c610fd261320e565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801590611d875750333014155b156122265760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015611dd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df49190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f602590611e2e90339034908690369060040161690d565b6000604051808303816000875af1158015611e4d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e759190810190616966565b905060018603611fb2576000611e8961320e565b90506000611e9d8760581b600160f81b1790565b82546001600160581b03198216600090815260018501602052604090205491925063ffffffff600160a81b9091048116911603611efd578154600163ffffffff600160a81b808404821692909201160263ffffffff60a81b199091161782555b604080518082019091528254600160a81b900463ffffffff16815260009060208101611f2c6014848a8c6169d8565b611f3591616ae5565b60601c9052905060148781013588016034818101929182013591818b01358b0180830192908201359160548d01358d01918201910135611f798888888888886137ad565b6004819003611fa457611fa488611f946004600085876169d8565b611f9d91616a02565b6001613aa0565b5050505050505050506121c2565b6002860361201957601484810135850160348181019291820135918188013588019182019181013590600090611fea90828a8c6169d8565b611ff391616ae5565b60601c90506120048a868684613b33565b61200f818484613b99565b50505050506121c2565b600386036120a9576018848101358501603881810192918201359181880135880191820191013561207c612051600460008a8c6169d8565b61205a91616a02565b8a612069601860048c8e6169d8565b61207291616ae5565b60601c8787613d6a565b6120a061208d601860048a8c6169d8565b61209691616ae5565b60601c8383613b99565b505050506121c2565b6004860361213d576040516306d61fe760e41b81526001600160a01b03861690636d61fe70906120df9087908790600401616b25565b600060405180830381600087803b1580156120f957600080fd5b505af115801561210d573d6000803e3d6000fd5b50505050600080516020616f658339815191528686604051612130929190616b39565b60405180910390a16121c2565b60058603612173576040516306d61fe760e41b81526001600160a01b03861690636d61fe70906120df9087908790600401616b25565b600686036121a9576040516306d61fe760e41b81526001600160a01b03861690636d61fe70906120df9087908790600401616b25565b604051631092ef5760e11b815260040160405180910390fd5b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906121ee90849060040161663d565b600060405180830381600087803b15801561220857600080fd5b505af115801561221c573d6000803e3d6000fd5b5050505050612518565b6001850361235157600061223861320e565b9050600061224c8660581b600160f81b1790565b82546001600160581b03198216600090815260018501602052604090205491925063ffffffff600160a81b90910481169116036122ac578154600163ffffffff600160a81b808404821692909201160263ffffffff60a81b199091161782555b604080518082019091528254600160a81b900463ffffffff168152600090602081016122db601484898b6169d8565b6122e491616ae5565b60601c9052905060148681013587016034818101929182013591818a01358a0180830192908201359160548c01358c019182019101356123288888888888886137ad565b60048190036123435761234388611f946004600085876169d8565b505050505050505050612518565b600285036123ae576014838101358401603481810192918201359181870135870191820191810135906000906123899082898b6169d8565b61239291616ae5565b60601c90506123a389868684613b33565b61221c818484613b99565b6003850361241857601883810135840160388181019291820135918187013587019182019101356123fe6123e660046000898b6169d8565b6123ef91616a02565b89612069601860048b8d6169d8565b61240f61208d60186004898b6169d8565b50505050612518565b600485036124ac576040516306d61fe760e41b81526001600160a01b03851690636d61fe709061244e9086908690600401616b25565b600060405180830381600087803b15801561246857600080fd5b505af115801561247c573d6000803e3d6000fd5b50505050600080516020616f65833981519152858560405161249f929190616b39565b60405180910390a1612518565b600585036124e2576040516306d61fe760e41b81526001600160a01b03851690636d61fe709061244e9086908690600401616b25565b600685036121a9576040516306d61fe760e41b81526001600160a01b03851690636d61fe709061244e9086908690600401616b25565b5050505050565b600061252c610fd261320e565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015906125675750333014155b156128ed5760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa1580156125b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d49190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f60259061260e90339034908690369060040161690d565b6000604051808303816000875af115801561262d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126559190810190616966565b9050856001036126855760006126718660581b600160f81b1790565b905061267e818686613edb565b50506121c2565b8560020361269e5761269885858561401f565b506121c2565b856003036126d65760006126b560048286886169d8565b6126be91616a02565b905061267e816126d1866004818a6169d8565b6140bb565b856004036127f35760006126e861320e565b5460581b90506001600160a01b03861661270061320e565b6001600160581b0319831660009081526001919091016020526040902054600160201b90046001600160a01b03160361278557600161273d61320e565b6001600160581b0319831660009081526001919091016020526040902080546001600160a01b0392909216600160201b02640100000000600160c01b03199092169190911790555b6127c58686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141a192505050565b50600080516020616f8583398151915287876040516127e5929190616b39565b60405180910390a1506121c2565b856005036128db57600061280561320e565b5460581b9050600061281a60208287896169d8565b61282391616b50565b9050612834825b600160f91b61093c565b1561286c576128438260081b90565b6001600160e01b031916810361286c576040516313002bdd60e31b815260040160405180910390fd5b6128ac8787878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141a192505050565b50600080516020616f8583398151915288886040516128cc929190616b39565b60405180910390a150506121c2565b856006036121a957600061280561320e565b8460010361291b5760006129078560581b600160f81b1790565b9050612914818585613edb565b5050612518565b846002036129345761292e84848461401f565b50612518565b8460030361296757600061294b60048285876169d8565b61295491616a02565b9050612914816126d185600481896169d8565b84600403612a8457600061297961320e565b5460581b90506001600160a01b03851661299161320e565b6001600160581b0319831660009081526001919091016020526040902054600160201b90046001600160a01b031603612a165760016129ce61320e565b6001600160581b0319831660009081526001919091016020526040902080546001600160a01b0392909216600160201b02640100000000600160c01b03199092169190911790555b612a568585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141a192505050565b50600080516020616f858339815191528686604051612a76929190616b39565b60405180910390a150612518565b84600503612b66576000612a9661320e565b5460581b90506000612aab60208286886169d8565b612ab491616b50565b9050612abf8261282a565b15612af757612ace8260081b90565b6001600160e01b0319168103612af7576040516313002bdd60e31b815260040160405180910390fd5b612b378686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141a192505050565b50600080516020616f858339815191528787604051612b57929190616b39565b60405180910390a15050612518565b846006036121a9576000612a9661320e565b6000612b8261320e565b54600160a81b900463ffffffff16919050565b6040805180820190915260008082526020820152612bb161320e565b6001600160581b03199290921660009081526001909201602090815260409283902083518085019094525463ffffffff81168452600160201b90046001600160a01b0316908301525090565b60408051606080820183526000808352602083015291810191909152612c2161320e565b6001600160e01b03198316600090815260039190910160209081526040918290208251606081018452815460f081901b6001600160f01b03191682526201000090046001600160a01b03168184015260018201805485518186028101860187528181529295939493860193830182828015612cc957602002820191906000526020600020905b815460501b6001600160501b0319168152600190910190602001808311612ca7575b5050505050815250509050919050565b600081600881901b603082901b605083901b612cf984600160f81b613656565b8015612d0b5750612d0b846000613656565b8015612d245750612d24846001600160f81b0319613656565b8015612d395750612d3984607f60f91b613656565b15612d4a5750600095945050505050565b6001600160f81b03198316600160f81b14801590612d7157506001600160f81b0319831615155b15612d825750600095945050505050565b6001600160e01b0319821615612d9e5750600095945050505050565b6001600160501b0319811615612dba5750600095945050505050565b50600195945050505050565b60606000612dd333613232565b546001600160a01b0316905080612dfd5760405163710c949760e01b815260040160405180910390fd5b60606001600160a01b038216600114612e2057612e1d82346000366108b7565b90505b612e2b868686614248565b92506001600160a01b038216600114612e4857612e4882826109d2565b50509392505050565b6000612e5e610fd261320e565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801590612e995750333014155b156130085760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015612ee2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f069190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f602590612f4090339034908690369060040161690d565b6000604051808303816000875af1158015612f5f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612f879190810190616966565b90506000612f96888888613edb565b9050612fa3818686614590565b50604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da90612fd090849060040161663d565b600060405180830381600087803b158015612fea57600080fd5b505af1158015612ffe573d6000803e3d6000fd5b5050505050610a2c565b6000613015878787613edb565b905061116d818585614590565b600061302f610fd261320e565b9050336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480159061306a5750333014155b156131ca5760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa1580156130b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130d79190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f60259061311190339034908690369060040161690d565b6000604051808303816000875af1158015613130573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526131589190810190616966565b9050613165858585614248565b50604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061319290849060040161663d565b600060405180830381600087803b1580156131ac57600080fd5b505af11580156131c0573d6000803e3d6000fd5b50505050506131d5565b612518848484614248565b50505050565b60006131e561320e565b5460581b919050565b6000600782101561320157506001919050565b506000919050565b919050565b7f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f90565b6001600160a01b031660009081527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b866020526040902090565b813536600060f883901c801561329057600181146132a557600281146132b657600080fd5b600093506001860192506001850391506132d0565b6015860192506015850391506132d0565b6001600160d81b0319841693506005860192506005850391505b509250925092565b604080517f1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c83602082015290810182905260009061094d906060015b60405160208183030381529060405280519060200120614659565b60008060003660006133438a8a8a8a8a614771565b93509350935093506000806133578561487d565b50915091508165ffffffffffff1642108061337957508065ffffffffffff1642115b1561339557506001600160e01b03199550610933945050505050565b6001600160a01b03861663392dffaf6001600160e01b03198e168d6133b98e6132d8565b88886040518663ffffffff1660e01b81526004016133db959493929190616b6e565b602060405180830381865afa1580156133f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061341c9190616a3a565b9c9b505050505050505050505050565b80600881901b8060ff60f084901c166001198101613452576001600160d81b0319821691505b509193909250565b60008061346561320e565b9050600061347285616bf8565b9050366000613485610100880188616a57565b909250905061349889600160f81b61093c565b156134f6576134b4886134af6101008a018a616a57565b6148b0565b604080516020601f8401819004810282018101909252828152939850919450925083908390819084018382808284376000920191909152505050506101008401525b8761350581600160f81b61093c565b156135945761358d866135188b60581c90565b6001600160a01b03166397003203878b6040518363ffffffff1660e01b8152600401613545929190616d9b565b6020604051808303816000875af1158015613564573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135889190616dbd565b6148dd565b9550613649565b60006135a08a60081b90565b6001600160e01b03198116600090815260038801602052604090205490915060f01b600160f01b16156135e6576040516314b9743f60e01b815260040160405180910390fd5b6000806135f58388888861499b565b9150915061360389836148dd565b985061364389826001600160a01b0316630ccab7a1866001600160e01b0319168b8f6040518463ffffffff1660e01b815260040161354593929190616dd6565b98505050505b5050505050949350505050565b6001600160f81b03199081169116141590565b600061367361320e565b805490915063ffffffff8084169161369591600a91600160a81b900416616dff565b63ffffffff1610156136ba5760405163e60fd64760e01b815260040160405180910390fd5b805463ffffffff600160c81b9091048116908316116136ec57604051633ab3447f60e11b815260040160405180910390fd5b805463ffffffff60c81b1916600160c81b63ffffffff8481168202929092178084559081048216600160a81b909104909116101561119857805463ffffffff60a81b198116600160c81b90910463ffffffff16600160a81b0217905550565b600061375561320e565b80546001600160a81b031916605884901c1781556040516001600160581b0319841681529091507f6789ec0c85d6458d897a36a70129b101f8b4d84c6e218046c3107373dbcbae889060200160405180910390a15050565b60006137b761320e565b80546001600160581b03198916600090815260018301602052604090205491925063ffffffff600160a81b9091048116911603613817578054600163ffffffff600160a81b808404821692909201160263ffffffff60a81b199091161781555b60208601516001600160a01b031661383157600160208701525b85518154600160a81b900463ffffffff9081169116141580613879575085516001600160581b03198816600090815260018301602052604090205463ffffffff918216911610155b1561389757604051633ab3447f60e11b815260040160405180910390fd5b6001600160581b03198716600090815260018083016020908152604090922088518154938a01516001600160a01b0316600160201b81026001600160c01b031990951663ffffffff90921691909117939093179055146139005761390086602001518484613b99565b8661390f81600160f81b61093c565b156139b15760006139208960581c90565b6040516306d61fe760e41b81529091506001600160a01b03821690636d61fe7090613951908a908a90600401616b25565b600060405180830381600087803b15801561396b57600080fd5b505af115801561397f573d6000803e3d6000fd5b50505050600080516020616f658339815191526001826040516139a3929190616b39565b60405180910390a150611d35565b6139bf81600160f91b61093c565b156139e35760006139d08960081b90565b90506139dd818888614c7b565b50611d35565b6040516361c4e91b60e11b815260040160405180910390fd5b60005b86811015611d3557613a98888883818110613a1c57613a1c616abf565b9050602002016020810190613a319190616650565b878381518110613a4357613a43616abf565b6020026020010151878785818110613a5d57613a5d616abf565b9050602002810190613a6f9190616a57565b878787818110613a8157613a81616abf565b9050602002810190613a939190616a57565b6137ad565b6001016139ff565b6000613aaa61320e565b6001600160581b03198516600081815260028301602090815260408083206001600160e01b0319891680855290835292819020805488151560ff1990911681179091558151938452918301939093528183015290519192507f9d17cd6d095ac90a655405ab29f30a7ee7e88ef3974c1bf7544bf591043bb71a919081900360600190a150505050565b613b3d84826150d4565b6040516306d61fe760e41b81526001600160a01b03851690636d61fe7090613b6b9086908690600401616b25565b600060405180830381600087803b158015613b8557600080fd5b505af1158015611d35573d6000803e3d6000fd5b6001600160a01b0383161580613bb857506001600160a01b0383166001145b15613bc257505050565b60405163d60b347f60e01b81523060048201526001600160a01b0384169063d60b347f90602401602060405180830381865afa158015613c06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2a9190616a9d565b613c9e576001600160a01b038316636d61fe70613c4a83600181876169d8565b6040518363ffffffff1660e01b8152600401613c67929190616b25565b600060405180830381600087803b158015613c8157600080fd5b505af1158015613c95573d6000803e3d6000fd5b50505050613d3d565b6001600160f81b03198282600081613cb857613cb8616abf565b9050013560f81c60f81b6001600160f81b03191603613d3d576001600160a01b038316636d61fe70613ced83600181876169d8565b6040518363ffffffff1660e01b8152600401613d0a929190616b25565b600060405180830381600087803b158015613d2457600080fd5b505af1158015613d38573d6000803e3d6000fd5b505050505b600080516020616f65833981519152600484604051613d5d929190616b39565b60405180910390a1505050565b6001600160a01b038316613d83576001600160a01b0392505b6000613d8e8661087d565b9050600083836000818110613da557613da5616abf565b9050013560f81c60f81b9050613dbf81600060f81b61093c565b15613e5c576001600160a01b038616636d61fe70613de085600181896169d8565b6040518363ffffffff1660e01b8152600401613dfd929190616b25565b600060405180830381600087803b158015613e1757600080fd5b505af1158015613e2b573d6000803e3d6000fd5b50505050600080516020616f65833981519152600387604051613e4f929190616b39565b60405180910390a1613e8c565b613e6e816001600160f81b0319613656565b15613e8c57604051632d6a6bb760e01b815260040160405180910390fd5b81546001600160a01b039586166001600160a01b03199091161782556001909101805460f89290921c600160a01b026001600160a81b0319909216959094169490941793909317909155505050565b600080613ee661320e565b805490915060581b6001600160581b031990811690861603613f1b576040516313002bdd60e31b815260040160405180910390fd5b6001600160581b03198516600090815260018201602052604090208054640100000000600160c01b03198116909155600160201b90046001600160a01b0316915084613f6b81600160f81b61093c565b15613fed576000613f7c8760581c90565b9050613fbe8187878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141a192505050565b50600080516020616f85833981519152600182604051613fdf929190616b39565b60405180910390a150612e48565b613ffb81600160f91b61093c565b156139e357600061400c8760081b90565b905061401981878761512e565b50612e48565b60008061402b85613232565b80546001600160a01b031981168255604080516020601f88018190048102820181019092528681526001600160a01b03909216945091925061408a9187919087908790819084018382808284376000920191909152506141a192505050565b50600080516020616f858339815191526002866040516140ab929190616b39565b60405180910390a1509392505050565b6000806140c78561087d565b80546001600160a01b03198116825560018201546001600160a01b03909116935090915061410090600160a01b900460f81b600061093c565b15614189576001810154604080516020601f8701819004810282018101909252858152614151926001600160a01b03169187908790819084018382808284376000920191909152506141a192505050565b506001810154604051600080516020616f8583398151915291614180916003916001600160a01b031690616b39565b60405180910390a15b60010180546001600160a81b03191690559392505050565b60006141fb835a600080638a91b0e360e01b876040516024016141c4919061663d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526152f8565b50604080516001600160a01b038616815282151560208201529192507f2b82f87bf66300af618a9621d3f221edfab735f5bacb4e004cce1b62375396c3910160405180910390a192915050565b606083600881901b61425e82600160f81b61093c565b156142e8578435850160208101903561427883600061093c565b1561428e576142878282615382565b94506142e1565b61429c83600160f81b61093c565b156142ab576142878282615452565b60405162461bcd60e51b815260206004820152600b60248201526a155b9cdd5c1c1bdc9d195960aa1b6044820152606401611410565b5050612e48565b6142f382600061093c565b1561442157600080366000614308898961557f565b6040805160018082528183019092529498509296509094509250816020015b6060815260200190600190039081614327579050509650600061434a868261093c565b1561437e5761435b858585856155d0565b8860008151811061436e5761436e616abf565b6020026020010181905250614417565b61438c86600160f81b61093c565b156142ab5761439d85858585615606565b896000815181106143b0576143b0616abf565b6020908102919091010152905080614417577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb76000896000815181106143f8576143f8616abf565b602002602001015160405161440e929190616e29565b60405180910390a15b5050505050612e48565b614433826001600160f81b031961093c565b156142ab5760408051600180825281830190925290816020015b606081526020019060019003908161444d579050509250600061447360148287896169d8565b61447c91616ae5565b60601c9050366000614491876014818b6169d8565b9150915060006144a28484846109a3565b886000815181106144b5576144b5616abf565b602090810291909101015290506144d085600160f81b61093c565b15614534578061452f577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb760008860008151811061451057614510616abf565b6020026020010151604051614526929190616e29565b60405180910390a15b614587565b61453f85600061093c565b156142ab578061452f5760405162461bcd60e51b815260206004820152601360248201527211195b1959d85d1958d85b1b0819985a5b1959606a1b6044820152606401611410565b50505050612e48565b6001600160a01b03831615806145af57506001600160a01b0383166001145b156145b957505050565b6001600160f81b031982826000816145d3576145d3616abf565b9050013560f81c60f81b6001600160f81b0319160361463957614637836145fd83600181876169d8565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141a192505050565b505b600080516020616f85833981519152600484604051613d5d929190616b39565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030147f000000000000000000000000000000000000000000000000000000000000000046141661474c5750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f000000000000000000000000000000000000000000000000000000000000000060208201527f00000000000000000000000000000000000000000000000000000000000000009181019190915246606082015230608082015260a090205b67190100000000000060005280601a5281603a52604260182090506000603a52919050565b6000803660008061478061320e565b60408051610120810182526000808252602082018190529181018290526080810182905260a0810191909152606060c082018190526001600160e01b03198d16908201526001600160a01b038b1660e082015261010081018a90529091506147ea81838a8a615637565b878760008181106147fd576147fd616abf565b9091013560f81c60ff1490506148265760405163b32eeb6960e01b815260040160405180910390fd5b614833876001818b6169d8565b60608301516001600160e01b0319166000908152600394909401602052604093849020549390920151620100009093046001600160a01b03169c929b509950975095505050505050565b600060a082901c65ffffffffffff1682811560001981016148a25765ffffffffffff92505b508360d01c92509193909250565b60003660006148c08686866158a4565b925050506094830135830160348101906014013593509350939050565b600081830160601b8260601b81148460601b8214176001600160a01b03848618161517600181146149115760019250614993565b6001600160d01b031980851690861681811881831102188686176001600160a01b031617935065ffffffffffff60a01b861690816149565765ffffffffffff60a01b91505b5065ffffffffffff60a01b851680614974575065ffffffffffff60a01b5b80821890821102188061498d575065ffffffffffff60a01b5b92909217915b505092915050565b60008060006149a861320e565b6001600160e01b03198816600090815260038201602052604081209192506001909101905b8154811015614bbf57600080614a068484815481106149ee576149ee616abf565b60009182526020909120015460501b90605082901c90565b91509150600089896000818110614a1f57614a1f616abf565b919091013560f81c915050838103614ab2576000614a41600960018c8e6169d8565b614a4a91616e42565b60c01c9050614a5f6009808301908c8e6169d8565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101008d0152614aa88a60098301818e6169d8565b9a509a5050614aec565b838160ff161015614ad657604051630760bdcf60e11b815260040160405180910390fd5b6040805160208101909152600081526101008c01525b600160f01b8316600003614bb4576000826001600160a01b0316637129edce8e6001600160e01b0319168e6040518363ffffffff1660e01b8152600401614b34929190616e78565b6020604051808303816000875af1158015614b53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b779190616dbd565b9050806001600160a01b03811615614ba557604051631f24c1fb60e11b815260048101879052602401611410565b614baf8a836148dd565b995050505b5050506001016149cd565b5085856000818110614bd357614bd3616abf565b9091013560f81c60ff149050614bfc5760405163b32eeb6960e01b815260040160405180910390fd5b614c0985600181896169d8565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052506101008c01949094525050506001600160e01b03198916815260039092016020525060409020546001600160a01b036201000090910416905094509492505050565b6000614c8561320e565b90508235830160208101903560fe811180614c9e575080155b15614cbc5760405163b62d956d60e01b815260040160405180910390fd5b6001600160e01b03198616600090815260038401602052604090206001015415614d0a576001600160e01b0319861660009081526003840160205260408120614d0a91600190910190615e77565b60005b6000198201811015614efe576001600160e01b0319871660009081526003850160205260409020600101838383818110614d4957614d49616abf565b9050602002810190614d5b9190616a57565b614d6a916016916000916169d8565b614d7391616e91565b81546001810183556000928352602090922090910180546001600160b01b03191660509290921c919091179055828282818110614db257614db2616abf565b9050602002810190614dc49190616a57565b614dd3916016916002916169d8565b614ddc91616ae5565b60601c636d61fe706001600160e01b03198916858585818110614e0157614e01616abf565b9050602002810190614e139190616a57565b614e219160169082906169d8565b604051602001614e3393929190616ec7565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401614e5e919061663d565b600060405180830381600087803b158015614e7857600080fd5b505af1158015614e8c573d6000803e3d6000fd5b50505050600080516020616f658339815191526005848484818110614eb357614eb3616abf565b9050602002810190614ec59190616a57565b614ed4916016916002916169d8565b614edd91616ae5565b60601c604051614eee929190616b39565b60405180910390a1600101614d0d565b50600082826000198101818110614f1757614f17616abf565b9050602002810190614f299190616a57565b614f38916016916002916169d8565b614f4191616ae5565b6001600160e01b031988166000908152600386016020526040902080546201000060609390931c92830262010000600160b01b0319909116179055905082826000198101818110614f9457614f94616abf565b9050602002810190614fa69190616a57565b614fb5916002916000916169d8565b614fbe91616ee1565b6001600160e01b0319881660008181526003870160205260409020805461ffff191660f09390931c929092179091556001600160a01b03821690636d61fe70908585600019810181811061501457615014616abf565b90506020028101906150269190616a57565b6150349160169082906169d8565b60405160200161504693929190616ec7565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401615071919061663d565b600060405180830381600087803b15801561508b57600080fd5b505af115801561509f573d6000803e3d6000fd5b50505050600080516020616f658339815191526006826040516150c3929190616b39565b60405180910390a150505050505050565b6001600160a01b0381166150e6575060015b60006150f183613232565b80546001600160a01b0319166001600160a01b038416178155604051909150600080516020616f6583398151915290613d5d906002908690616b39565b81358201602081019035600061514261320e565b6001600160e01b031987166000908152600391909101602052604090206001808201549192500182146151885760405163013dcc8d60e31b815260040160405180910390fd5b6001810160005b815481101561523d5760006151af8383815481106149ee576149ee616abf565b91505061520b818a6001600160e01b0319168888868181106151d3576151d3616abf565b90506020028101906151e59190616a57565b6040516020016151f793929190616ec7565b6040516020818303038152906040526141a1565b50600080516020616f8583398151915260058260405161522c929190616b39565b60405180910390a15060010161518f565b5061524661320e565b6001600160e01b0319881660009081526003919091016020526040812061527291600190910190615e77565b81546152a8906201000090046001600160a01b03166001600160e01b03198916868660001981018181106151d3576151d3616abf565b508154604051600080516020616f85833981519152916152da916006916201000090046001600160a01b031690616b39565b60405180910390a15080546001600160b01b03191690555050505050565b6000606060008060008661ffff166001600160401b0381111561531d5761531d616431565b6040519080825280601f01601f191660200182016040528015615347576020820181803683370190505b5090506000808751602089018b8e8ef191503d925086831115615368578692505b828152826000602083013e90999098509650505050505050565b606081806001600160401b0381111561539d5761539d616431565b6040519080825280602002602001820160405280156153d057816020015b60608152602001906001900390816153bb5790505b50915060005b8181101561499357368585838181106153f1576153f1616abf565b90506020028101906154039190616f17565b905061542c61541560208301836160c6565b60208301356154276040850185616a57565b6155d0565b84838151811061543e5761543e616abf565b6020908102919091010152506001016153d6565b606081806001600160401b0381111561546d5761546d616431565b6040519080825280602002602001820160405280156154a057816020015b606081526020019060019003908161548b5790505b50915060005b8181101561499357368585838181106154c1576154c1616abf565b90506020028101906154d39190616f17565b905060006154fe6154e760208401846160c6565b60208401356154f96040860186616a57565b615606565b86858151811061551057615510616abf565b6020908102919091010152905080615575577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb78386858151811061555657615556616abf565b602002602001015160405161556c929190616e29565b60405180910390a15b50506001016154a6565b600080368161559160148287896169d8565b61559a91616ae5565b60601c93506155ad6034601487896169d8565b6155b691616b50565b92506155c585603481896169d8565b949793965094505050565b60405181838237600038838387895af16155ed573d6000823e3d81fd5b3d8152602081013d6000823e3d01604052949350505050565b604051600090828482376000388483888a5af191503d8152602081013d6000823e3d81016040525094509492505050565b60608401516001600160e01b03191660009081526003840160205260408120600101905b8154811015610a2c576156798282815481106149ee576149ee616abf565b6001600160a01b031660a08801526001600160f01b031916608087015283836000816156a7576156a7616abf565b919091013560f81c8088528290039050615744576156c96009600185876169d8565b6156d291616e42565b60c01c602087018190526156ed9060099081019085876169d8565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050505060c0870152602086015161573b90849060090181876169d8565b935093506157b0565b855160ff1681111561576957604051630760bdcf60e11b815260040160405180910390fd5b61577660008085876169d8565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050505060c08701525b6080860151600160f11b1660000361589c5760a0860151606087015160e088015161010089015160c08a015160405163184dfdbb60e11b81526000956001600160a01b03169463309bfb7694615817946001600160e01b0319909216939092600401616f37565b602060405180830381865afa158015615834573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906158589190616dbd565b9050806001600160a01b0381161561588657604051631f24c1fb60e11b815260048101849052602401611410565b6158948860400151836148dd565b604089015250505b60010161565b565b600036600080366000366000366000806158bf8e8e8e61592a565b9750975097509750975097509750975060748d013560348e0101995060208a033598506158ed818b8b615adf565b9a506158fd8e89898989896137ad565b6159078383615c7f565b6159198e611f946004600086886169d8565b505050505050505050509392505050565b604080518082019091526000808252602082015236600036600036600080600061595261320e565b9050615962601460008c8e6169d8565b61596b91616ae5565b60601c89602001906001600160a01b031690816001600160a01b0316815250508060000160159054906101000a900463ffffffff16896000019063ffffffff16908163ffffffff168152505060148b013560348c010197506020880335965060348b013560348c010195506020860335945060548b013560348c0101935060208403359250615acf7fb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c50560001b8d8360000160159054906101000a900463ffffffff168c602001518c8c604051615a42929190616ad5565b60405180910390208b8b604051615a5a929190616ad5565b60405180910390208a8a604051615a72929190616ad5565b6040805191829003822060208301989098526001600160581b03199096169581019590955263ffffffff90931660608501526001600160a01b03909116608084015260a083015260c082015260e081019190915261010001613313565b9150509397509397509397509397565b600080615aea61320e565b805490915060581b6000615b0282600160f81b61093c565b15615b8e578254604051637aa8f17760e11b81526001600160a81b038216916001600160a01b03169063f551e2ee90615b459030908c908c908c9060040161690d565b602060405180830381865afa158015615b62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615b869190616a3a565b915050615c44565b615b9c82600160f91b61093c565b156139e357825460601b6000615bb582308b8b8b614771565b60405163392dffaf60e01b8152919b5099509097509091506001600160a01b0382169063392dffaf90615bfe906001600160e01b031986169030908e908e908e90600401616b6e565b602060405180830381865afa158015615c1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615c3f9190616a3a565b925050505b630b135d3f60e11b6001600160e01b0319821614615c75576040516362467c7760e11b815260040160405180910390fd5b5050509392505050565b6000615c8e60048284866169d8565b615c9791616a02565b905060048210615e7257602c8210615e2b57366000818180615cbd60186004898b6169d8565b615cc691616ae5565b60601c9050602c880135604c890101945060208503359350604c880135604c890101925060208303359150615d1b85856000818110615d0757615d07616abf565b9050013560f81c60f81b600060f81b61093c565b8015615d8b575060405163ecd0596160e01b8152600260048201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015615d67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615d8b9190616a9d565b15615de157606c8801358801604c810190602c01356000615daf60148284866169d8565b615db891616ae5565b60601c9050615dc784826150d4565b615ddd81615dd884601481886169d8565b613b99565b5050505b615e078682615df4602c60188c8e6169d8565b615dfd91616ae5565b60601c8888613d6a565b611d35615e18602c60188a8c6169d8565b615e2191616ae5565b60601c8484613b99565b60048214615e725760405162461bcd60e51b8152602060048201526014602482015273496e76616c69642073656c6563746f724461746160601b6044820152606401611410565b505050565b5080546000825590600052602060002090810190615e959190615e98565b50565b5b80821115615ead5760008155600101615e99565b5090565b6001600160a01b0381168114615e9557600080fd5b803561320981615eb1565b60008083601f840112615ee357600080fd5b5081356001600160401b03811115615efa57600080fd5b602083019150836020828501011115615f1257600080fd5b9250929050565b60008060008060608587031215615f2f57600080fd5b843593506020850135615f4181615eb1565b925060408501356001600160401b03811115615f5c57600080fd5b615f6887828801615ed1565b95989497509550505050565b600080600080600060808688031215615f8c57600080fd5b8535615f9781615eb1565b94506020860135615fa781615eb1565b93506040860135925060608601356001600160401b03811115615fc957600080fd5b615fd588828901615ed1565b969995985093965092949392505050565b600080600060408486031215615ffb57600080fd5b8335925060208401356001600160401b0381111561601857600080fd5b61602486828701615ed1565b9497909650939450505050565b6000610120828403121561604457600080fd5b50919050565b60008060006060848603121561605f57600080fd5b83356001600160401b0381111561607557600080fd5b61608186828701616031565b9660208601359650604090950135949350505050565b803563ffffffff8116811461320957600080fd5b6000602082840312156160bd57600080fd5b610ca382616097565b6000602082840312156160d857600080fd5b8135610ca381615eb1565b80356001600160581b03198116811461320957600080fd5b60008083601f84011261610d57600080fd5b5081356001600160401b0381111561612457600080fd5b6020830191508360208260051b8501011115615f1257600080fd5b60008060008060008060008060a0898b03121561615b57600080fd5b616164896160e3565b9750602089013561617481615eb1565b965060408901356001600160401b0381111561618f57600080fd5b61619b8b828c01615ed1565b90975095505060608901356001600160401b038111156161ba57600080fd5b6161c68b828c01615ed1565b90955093505060808901356001600160401b038111156161e557600080fd5b6161f18b828c016160fb565b999c989b5096995094979396929594505050565b6000806000806000806080878903121561621e57600080fd5b616227876160e3565b9550602087013561623781615eb1565b945060408701356001600160401b0381111561625257600080fd5b61625e89828a01615ed1565b90955093505060608701356001600160401b0381111561627d57600080fd5b61628989828a01615ed1565b979a9699509497509295939492505050565b6001600160e01b031981168114615e9557600080fd5b6000602082840312156162c357600080fd5b8135610ca38161629b565b600080604083850312156162e157600080fd5b6162ea836160e3565b915060208301356162fa8161629b565b809150509250929050565b60005b83811015616320578181015183820152602001616308565b50506000910152565b60008151808452616341816020860160208601616305565b601f01601f19169290920160200192915050565b60ff60f81b8816815260e06020820152600061637460e0830189616329565b82810360408401526163868189616329565b606084018890526001600160a01b038716608085015260a0840186905283810360c08501528451808252602080870193509091019060005b818110156163dc5783518352602093840193909201916001016163be565b50909b9a5050505050505050505050565b6000806040838503121561640057600080fd5b82356001600160401b0381111561641657600080fd5b61642285828601616031565b95602094909401359450505050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171561646957616469616431565b60405290565b60405161012081016001600160401b038111828210171561646957616469616431565b604051601f8201601f191681016001600160401b03811182821017156164ba576164ba616431565b604052919050565b60008060008060008060006080888a0312156164dd57600080fd5b87356001600160401b038111156164f357600080fd5b6164ff8a828b016160fb565b90985096505060208801356001600160401b0381111561651e57600080fd5b8801601f81018a1361652f57600080fd5b80356001600160401b0381111561654857616548616431565b61655760208260051b01616492565b8082825260208201915060208360061b85010192508c83111561657957600080fd5b6020840193505b828410156165d5576040848e03121561659857600080fd5b6165a0616447565b6165a985616097565b815260208501356165b981615eb1565b8060208301525080835250602082019150604084019350616580565b975050505060408801356001600160401b038111156165f357600080fd5b6165ff8a828b016160fb565b90955093505060608801356001600160401b0381111561661e57600080fd5b61662a8a828b016160fb565b989b979a50959850939692959293505050565b602081526000610ca36020830184616329565b60006020828403121561666257600080fd5b610ca3826160e3565b60008060008060008060008060a0898b03121561668757600080fd5b883561669281615eb1565b975060208901356166a281615eb1565b965060408901356001600160401b038111156166bd57600080fd5b6166c98b828c016160fb565b90975095505060608901356001600160401b038111156166e857600080fd5b6166f48b828c016160fb565b90955093505060808901356001600160401b0381111561671357600080fd5b6161f18b828c01615ed1565b602080825282516001600160f01b03191682820152828101516001600160a01b03166040808401919091528301516060808401528051608084018190526000929190910190829060a08501905b808310156167985783516001600160501b0319168252602093840193600193909301929091019061676c565b5095945050505050565b6000602082840312156167b457600080fd5b5035919050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b8281101561681457603f198786030184526167ff858351616329565b945060209384019391909101906001016167e3565b50929695505050505050565b60008060008060006060868803121561683857600080fd5b616841866160e3565b945060208601356001600160401b0381111561685c57600080fd5b61686888828901615ed1565b90955093505060408601356001600160401b03811115615fc957600080fd5b60008060008060008060a087890312156168a057600080fd5b86356168ab81615eb1565b955060208701356168bb81615eb1565b9450604087013593506060870135925060808701356001600160401b0381111561627d57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60018060a01b03851681528360208201526060604082015260006169356060830184866168e4565b9695505050505050565b60006001600160401b0382111561695857616958616431565b50601f01601f191660200190565b60006020828403121561697857600080fd5b81516001600160401b0381111561698e57600080fd5b8201601f8101841361699f57600080fd5b80516169b26169ad8261693f565b616492565b8181528560208385010111156169c757600080fd5b610933826020830160208601616305565b600080858511156169e857600080fd5b838611156169f557600080fd5b5050820193919092039150565b80356001600160e01b03198116906004841015616a33576001600160e01b0319600485900360031b81901b82161691505b5092915050565b600060208284031215616a4c57600080fd5b8151610ca38161629b565b6000808335601e19843603018112616a6e57600080fd5b8301803591506001600160401b03821115616a8857600080fd5b602001915036819003821315615f1257600080fd5b600060208284031215616aaf57600080fd5b81518015158114610ca357600080fd5b634e487b7160e01b600052603260045260246000fd5b8183823760009101908152919050565b80356bffffffffffffffffffffffff198116906014841015616a33576bffffffffffffffffffffffff1960149490940360031b84901b1690921692915050565b602081526000610b016020830184866168e4565b9182526001600160a01b0316602082015260400190565b8035602083101561094d57600019602084900360031b1b1692915050565b85815260018060a01b0385166020820152836040820152608060608201526000616b9c6080830184866168e4565b979650505050505050565b600082601f830112616bb857600080fd5b8135616bc66169ad8261693f565b818152846020838601011115616bdb57600080fd5b816020850160208301376000918101602001919091529392505050565b60006101208236031215616c0b57600080fd5b616c1361646f565b616c1c83615ec6565b81526020838101359082015260408301356001600160401b03811115616c4157600080fd5b616c4d36828601616ba7565b60408301525060608301356001600160401b03811115616c6c57600080fd5b616c7836828601616ba7565b6060830152506080838101359082015260a0808401359082015260c0808401359082015260e08301356001600160401b03811115616cb557600080fd5b616cc136828601616ba7565b60e0830152506101008301356001600160401b03811115616ce157600080fd5b616ced36828601616ba7565b6101008301525092915050565b80516001600160a01b0316825260208101516020830152600060408201516101206040850152616d2e610120850182616329565b905060608301518482036060860152616d478282616329565b9150506080830151608085015260a083015160a085015260c083015160c085015260e083015184820360e0860152616d7f8282616329565b9150506101008301518482036101008601526109338282616329565b604081526000616dae6040830185616cfa565b90508260208301529392505050565b600060208284031215616dcf57600080fd5b5051919050565b838152606060208201526000616def6060830185616cfa565b9050826040830152949350505050565b63ffffffff818116838216019081111561094d57634e487b7160e01b600052601160045260246000fd5b828152604060208201526000610b016040830184616329565b80356001600160c01b03198116906008841015616a33576001600160c01b031960089490940360031b84901b1690921692915050565b828152604060208201526000610b016040830184616cfa565b80356001600160501b03198116906016841015616a33576001600160501b031960169490940360031b84901b1690921692915050565b838152818360208301376000910160200190815292915050565b80356001600160f01b03198116906002841015616a33576001600160f01b031960029490940360031b84901b1690921692915050565b60008235605e19833603018112616f2d57600080fd5b9190910192915050565b84815260018060a01b0384166020820152826040820152608060608201526000616935608083018461632956fed21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e"; + bytes public constant KERNEL_WITH_SETSELECTOR_BYTECODE = + hex"61014060405234801561001157600080fd5b506040516172913803806172918339810160408190526100309161015a565b306080524660a05260608061007a604080518082018252600681526512d95c9b995b60d21b60208083019190915282518084019093526005835264302e332e3160d81b9083015291565b815160209283012081519183019190912060c082905260e0819052604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8152808501939093528281019190915246606083015230608083015260a0909120610100526001600160a01b03851661012052805163deadbeef60e01b92810192909252805160048184030181526024909201905261011b9250905061018a565b7f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f80546001600160a81b03191660589290921c919091179055506101c8565b60006020828403121561016c57600080fd5b81516001600160a01b038116811461018357600080fd5b9392505050565b805160208201516001600160581b03198116919060158210156101c1576001600160581b0319601583900360031b81901b82161692505b5050919050565b60805160a05160c05160e051610100516101205161702d610264600039600081816102fa015281816106bf01528181610ce201528181611017015281816111e1015281816115de01528181611aac01528181611bd001528181611d940152818161257401528181612ea6015261307701526000614696015260006147500152600061472a015260006146da015260006146b7015261702d6000f3fe6080604052600436106101dc5760003560e01c80639198bdf511610102578063c3e5897811610095578063e9ae5c5311610064578063e9ae5c531461081a578063f1f7f0f91461082d578063f23a6e611461085b578063f2dc691d146108885761021b565b8063c3e589781461079a578063d03c7914146107c7578063d691c964146107e7578063e6f3d50a146108075761021b565b8063a71763a8116100d1578063a71763a8146106f9578063adb610a31461070c578063b8afe17d14610721578063bc197c811461076b5761021b565b80639198bdf5146106425780639517e29f146106555780639cfd7cff14610668578063a65d69d4146106ad5761021b565b80633c3b752b1161017a578063721e67f411610149578063721e67f4146105a557806384b0196e146105dd5780638dd7712f1461060557806390ef8862146106185761021b565b80633c3b752b146104f857806352141cd91461051857806357b3a5f41461052b5780636e6fa0c6146105855761021b565b806319822f7c116101b657806319822f7c1461048f5780631f1b92e3146104b05780633659cfe6146104c557806337bb6ef2146104d85761021b565b8063112d3a7d146103f5578063150b7a021461042a5780631626ba7e1461046f5761021b565b3661021b57604080513381523460208201527f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f88525874910160405180910390a1005b60006102326000356001600160e01b0319166108a8565b604080516060808201835283546001600160a01b039081168084526001909501549081166020840152600160a01b900460f81b6001600160f81b03191692820192909252925060009161029857604051631cd4b64760e21b815260040160405180910390fd5b82516060906001600160a01b03166001148015906102c1575083516001600160a01b0390811614155b156102dc5783516102d590346000366108e2565b9050610338565b83516001600160a01b03908116900361033857336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610338576040516348f5c3ed60e01b815260040160405180910390fd5b6040840151610348906000610967565b156103645761035a846020015161097e565b90935091506103a9565b604084015161037b906001600160f81b0319610967565b156103905761035a84602001516000366109ce565b604051632d6a6bb760e01b815260040160405180910390fd5b826103b657815160208301fd5b83516001600160a01b03166001148015906103dc575083516001600160a01b0390811614155b156103ed5783516103ed90826109fd565b815160208301f35b34801561040157600080fd5b50610415610410366004615f4f565b610a5f565b60405190151581526020015b60405180910390f35b34801561043657600080fd5b50610456610445366004615faa565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001610421565b34801561047b57600080fd5b5061045661048a36600461601c565b610b34565b6104a261049d366004616080565b610cd5565b604051908152602001610421565b6104c36104be3660046160e1565b610ff0565b005b6104c36104d33660046160fc565b6111c7565b3480156104e457600080fd5b506104c36104f3366004616155565b6113e0565b34801561050457600080fd5b506104c36105133660046161e2565b6113f0565b6104c36105263660046162a8565b6115c4565b34801561053757600080fd5b5061054b61054636600461633e565b611959565b6040805182516001600160a01b03908116825260208085015190911690820152918101516001600160f81b03191690820152606001610421565b34801561059157600080fd5b506104156105a036600461635b565b6119c5565b3480156105b157600080fd5b506105c56105c03660046160fc565b611a0d565b60405190516001600160a01b03168152602001610421565b3480156105e957600080fd5b506105f2611a43565b60405161042197969594939291906163e2565b6104c361061336600461647a565b611aa1565b34801561062457600080fd5b5061062d611b99565b60405163ffffffff9091168152602001610421565b6104c361065036600461654f565b611bb6565b6104c3610663366004615f4f565b611d7a565b34801561067457600080fd5b5060408051808201825260168152756b65726e656c2e616476616e6365642e76302e332e3160501b6020820152905161042191906166ca565b3480156106b957600080fd5b506106e17f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610421565b6104c3610707366004615f4f565b61255a565b34801561071857600080fd5b5061062d612bb3565b34801561072d57600080fd5b5061074161073c3660046166dd565b612bd0565b60408051825163ffffffff1681526020928301516001600160a01b03169281019290925201610421565b34801561077757600080fd5b506104566107863660046166f8565b63bc197c8160e01b98975050505050505050565b3480156107a657600080fd5b506107ba6107b536600461633e565b612c38565b60405161042191906167ac565b3480156107d357600080fd5b506104156107e236600461682f565b612d14565b6107fa6107f536600461601c565b612e01565b6040516104219190616848565b6104c36108153660046168ad565b612e8c565b6104c361082836600461601c565b61305d565b34801561083957600080fd5b50610842613216565b6040516001600160581b03199091168152602001610421565b34801561086757600080fd5b50610456610876366004616914565b63f23a6e6160e01b9695505050505050565b34801561089457600080fd5b506104156108a336600461682f565b613229565b6001600160e01b03191660009081527f7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b6020526040902090565b60405163d68f602560e01b81526060906001600160a01b0386169063d68f60259061091790339088908890889060040161699a565b6000604051808303816000875af1158015610936573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261095e91908101906169f3565b95945050505050565b6001600160f81b0319828116908216145b92915050565b6000606060408051368101909152366000823760408051601481019091523360601b9052600080366014018382885af192505060405190503d8152602081013d6000823e3d810160405250915091565b604051600090828482376000388483885af491503d8152602081013d6000823e3d810160405250935093915050565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da90610a299084906004016166ca565b600060405180830381600087803b158015610a4357600080fd5b505af1158015610a57573d6000803e3d6000fd5b505050505050565b600060018503610abc576000610a73613249565b6001016000610a888760581b600160f81b1790565b6001600160581b0319168152602081019190915260400160002054600160201b90046001600160a01b031614159050610b2c565b60028503610ae2576000610acf8561326d565b546001600160a01b031614159050610b2c565b60038503610b28576001600160a01b038416610b13610b05600460008688616a65565b610b0e91616a8f565b6108a8565b600101546001600160a01b0316149050610b2c565b5060005b949350505050565b600080610b3f613249565b90506000366000610b5087876132a6565b925092509250610b67610b608490565b6000610967565b15610b7457835460581b92505b6001600160581b031983166000908152600185016020526040902054600160201b90046001600160a01b0316610bbd57604051631a0a9b9f60e21b815260040160405180910390fd5b610bcb83600160f81b610967565b15610c65576000610bdc8460581c90565b9050806001600160a01b031663f551e2ee33610bf78c613313565b86866040518563ffffffff1660e01b8152600401610c18949392919061699a565b602060405180830381865afa158015610c35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c599190616ac7565b95505050505050610cce565b6000610c718460081b90565b6001600160e01b03198116600090815260038701602052604090205490915060f01b600160f11b811615610cb857604051635b71057960e01b815260040160405180910390fd5b610cc582338c8787613369565b96505050505050505b9392505050565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d20576040516348f5c3ed60e01b815260040160405180910390fd5b6000610d2a613249565b90506000806000610d3e8860200135613467565b91945092509050610d50826000610967565b15610d5c5750825460581b5b610d6883828a8a613495565b6001600160581b031982166000908152600186016020908152604080832081518083019092525463ffffffff81168252600160201b90046001600160a01b031691810191909152919650610dbd908490613691565b8015610ddb57508454815163ffffffff600160c81b90920482169116105b15610df957604051633ab3447f60e11b815260040160405180910390fd5b60208101516001600160a01b038116610e2557604051631a0a9b9f60e21b815260040160405180910390fd5b600089815260208190526040902080546001600160a01b0319166001600160a01b03831690811790915560001901610eed57610e62846000613691565b8015610eca57506001600160581b031983166000908152600287016020526040812090610e9260608d018d616ae4565b610ea191600491600091616a65565b610eaa91616a8f565b6001600160e01b031916815260208101919091526040016000205460ff16155b15610ee857604051631a0a9b9f60e21b815260040160405180910390fd5b610fd3565b610ef8846000613691565b8015610f6057506001600160581b031983166000908152600287016020526040812090610f2860608d018d616ae4565b610f3791600891600491616a65565b610f4091616a8f565b6001600160e01b031916815260208101919091526040016000205460ff16155b15610f7e57604051631a0a9b9f60e21b815260040160405180910390fd5b638dd7712f60e01b610f9360608c018c616ae4565b610fa291600491600091616a65565b610fab91616a8f565b6001600160e01b03191614610fd35760405163dbbb044b60e01b815260040160405180910390fd5b8715610fe357343434348b335af1505b5050505050509392505050565b600061100a610ffd613249565b546001600160a81b031690565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015906110455750333014155b156111ba5760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa15801561108e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b29190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f6025906110ec90339034908690369060040161699a565b6000604051808303816000875af115801561110b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261113391908101906169f3565b905061113e836136a4565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061116a9084906004016166ca565b600060405180830381600087803b15801561118457600080fd5b505af1158015611198573d6000803e3d6000fd5b50505050505050565b6040516348f5c3ed60e01b815260040160405180910390fd5b6111c3826136a4565b5050565b60006111d4610ffd613249565b9050336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480159061120f5750333014155b156113845760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015611258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127c9190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f6025906112b690339034908690369060040161699a565b6000604051808303816000875af11580156112d5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112fd91908101906169f3565b9050827f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55826001600160a01b03167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a2604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061116a9084906004016166ca565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8290556040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a25050565b6113eb838383613786565b505050565b60006113fa613249565b805490915060581b6001600160581b031916156114545760405162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b60448201526064015b60405180910390fd5b6001600160581b0319891661147c57604051631a0a9b9f60e21b815260040160405180910390fd5b8861148b81600160f81b613691565b80156114a057506114a081600160f91b613691565b156114be576040516361c4e91b60e11b815260040160405180910390fd5b6114c78a613819565b60408051808201909152600181526001600160a01b038a166020820152825463ffffffff60a81b1916600160a81b1783556115068b828b8b8b8b61387b565b60005b848110156115b65760003087878481811061152657611526616b47565b90506020028101906115389190616ae4565b604051611546929190616b5d565b6000604051808303816000865af19150503d8060008114611583576040519150601f19603f3d011682016040523d82523d6000602084013e611588565b606091505b50509050806115ad57604051636534eae560e11b81526004810183905260240161144b565b50600101611509565b505050505050505050505050565b60006115d1610ffd613249565b9050336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480159061160c5750333014155b156118585760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015611655573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116799190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f6025906116b390339034908690369060040161699a565b6000604051808303816000875af11580156116d2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116fa91908101906169f3565b90506000611706613249565b90506001600160581b0319891661173057604051631a0a9b9f60e21b815260040160405180910390fd5b8861173f81600160f81b613691565b8015611754575061175481600160f91b613691565b15611772576040516361c4e91b60e11b815260040160405180910390fd5b61177b8a613819565b6000611785613249565b6001600160581b03198c1660009081526001919091016020526040902054600160201b90046001600160a01b0316036117f257604080518082019091528254600160a81b900463ffffffff1681526001600160a01b038a1660208201526117f08b828b8b8b8b61387b565b505b5050604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906118209084906004016166ca565b600060405180830381600087803b15801561183a57600080fd5b505af115801561184e573d6000803e3d6000fd5b5050505050611198565b6000611862613249565b90506001600160581b0319881661188c57604051631a0a9b9f60e21b815260040160405180910390fd5b8761189b81600160f81b613691565b80156118b057506118b081600160f91b613691565b156118ce576040516361c4e91b60e11b815260040160405180910390fd5b6118d789613819565b60006118e1613249565b6001600160581b03198b1660009081526001919091016020526040902054600160201b90046001600160a01b03160361194e57604080518082019091528254600160a81b900463ffffffff1681526001600160a01b038916602082015261194c8a828a8a8a8a61387b565b505b505050505050505050565b604080516060810182526000808252602082018190529181019190915261197f826108a8565b6040805160608101825282546001600160a01b0390811682526001909301549283166020820152600160a01b90920460f81b6001600160f81b0319169082015292915050565b60006119cf613249565b6001600160581b031984166000908152600291909101602090815260408083206001600160e01b03198616845290915290205460ff16905092915050565b604080516020810190915260008152611a258261326d565b604080516020810190915290546001600160a01b0316815292915050565b600f60f81b6060806000808083611a8f604080518082018252600681526512d95c9b995b60d21b60208083019190915282518084019093526005835264302e332e3160d81b9083015291565b97989097965046955030945091925090565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611aea576040516348f5c3ed60e01b815260040160405180910390fd5b6000818152602081905260409020546060906001600160a01b031660018114611b3557611b328134611b1f6060880188616ae4565b611b2d916004908290616a65565b6108e2565b91505b600080611b5c30611b496060890189616ae4565b611b57916004908290616a65565b6109ce565b9150915081611b7e5760405163f21e646b60e01b815260040160405180910390fd5b6001600160a01b038316600114610a5757610a5783856109fd565b6000611ba3613249565b54600160c81b900463ffffffff16919050565b6000611bc3610ffd613249565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801590611bfe5750333014155b15611d615760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015611c47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c6b9190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f602590611ca590339034908690369060040161699a565b6000604051808303816000875af1158015611cc4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611cec91908101906169f3565b9050611cfd89898989898989613aca565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da90611d299084906004016166ca565b600060405180830381600087803b158015611d4357600080fd5b505af1158015611d57573d6000803e3d6000fd5b5050505050611d70565b611d7088888888888888613aca565b5050505050505050565b6000611d87610ffd613249565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801590611dc25750333014155b156122615760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015611e0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2f9190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f602590611e6990339034908690369060040161699a565b6000604051808303816000875af1158015611e88573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611eb091908101906169f3565b905060018603611fed576000611ec4613249565b90506000611ed88760581b600160f81b1790565b82546001600160581b03198216600090815260018501602052604090205491925063ffffffff600160a81b9091048116911603611f38578154600163ffffffff600160a81b808404821692909201160263ffffffff60a81b199091161782555b604080518082019091528254600160a81b900463ffffffff16815260009060208101611f676014848a8c616a65565b611f7091616b6d565b60601c9052905060148781013588016034818101929182013591818b01358b0180830192908201359160548d01358d01918201910135611fb488888888888861387b565b6004819003611fdf57611fdf88611fcf600460008587616a65565b611fd891616a8f565b6001613786565b5050505050505050506121fd565b600286036120545760148481013585016034818101929182013591818801358801918201918101359060009061202590828a8c616a65565b61202e91616b6d565b60601c905061203f8a868684613b6e565b61204a818484613bd4565b50505050506121fd565b600386036120e457601884810135850160388181019291820135918188013588019182019101356120b761208c600460008a8c616a65565b61209591616a8f565b8a6120a4601860048c8e616a65565b6120ad91616b6d565b60601c8787613da5565b6120db6120c8601860048a8c616a65565b6120d191616b6d565b60601c8383613bd4565b505050506121fd565b60048603612178576040516306d61fe760e41b81526001600160a01b03861690636d61fe709061211a9087908790600401616bad565b600060405180830381600087803b15801561213457600080fd5b505af1158015612148573d6000803e3d6000fd5b50505050600080516020616fed833981519152868660405161216b929190616bc1565b60405180910390a16121fd565b600586036121ae576040516306d61fe760e41b81526001600160a01b03861690636d61fe709061211a9087908790600401616bad565b600686036121e4576040516306d61fe760e41b81526001600160a01b03861690636d61fe709061211a9087908790600401616bad565b604051631092ef5760e11b815260040160405180910390fd5b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906122299084906004016166ca565b600060405180830381600087803b15801561224357600080fd5b505af1158015612257573d6000803e3d6000fd5b5050505050612553565b6001850361238c576000612273613249565b905060006122878660581b600160f81b1790565b82546001600160581b03198216600090815260018501602052604090205491925063ffffffff600160a81b90910481169116036122e7578154600163ffffffff600160a81b808404821692909201160263ffffffff60a81b199091161782555b604080518082019091528254600160a81b900463ffffffff16815260009060208101612316601484898b616a65565b61231f91616b6d565b60601c9052905060148681013587016034818101929182013591818a01358a0180830192908201359160548c01358c0191820191013561236388888888888861387b565b600481900361237e5761237e88611fcf600460008587616a65565b505050505050505050612553565b600285036123e9576014838101358401603481810192918201359181870135870191820191810135906000906123c49082898b616a65565b6123cd91616b6d565b60601c90506123de89868684613b6e565b612257818484613bd4565b60038503612453576018838101358401603881810192918201359181870135870191820191013561243961242160046000898b616a65565b61242a91616a8f565b896120a4601860048b8d616a65565b61244a6120c860186004898b616a65565b50505050612553565b600485036124e7576040516306d61fe760e41b81526001600160a01b03851690636d61fe70906124899086908690600401616bad565b600060405180830381600087803b1580156124a357600080fd5b505af11580156124b7573d6000803e3d6000fd5b50505050600080516020616fed83398151915285856040516124da929190616bc1565b60405180910390a1612553565b6005850361251d576040516306d61fe760e41b81526001600160a01b03851690636d61fe70906124899086908690600401616bad565b600685036121e4576040516306d61fe760e41b81526001600160a01b03851690636d61fe70906124899086908690600401616bad565b5050505050565b6000612567610ffd613249565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015906125a25750333014155b156129285760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa1580156125eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061260f9190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f60259061264990339034908690369060040161699a565b6000604051808303816000875af1158015612668573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261269091908101906169f3565b9050856001036126c05760006126ac8660581b600160f81b1790565b90506126b9818686613f16565b50506121fd565b856002036126d9576126d385858561405a565b506121fd565b856003036127115760006126f06004828688616a65565b6126f991616a8f565b90506126b98161270c866004818a616a65565b6140f6565b8560040361282e576000612723613249565b5460581b90506001600160a01b03861661273b613249565b6001600160581b0319831660009081526001919091016020526040902054600160201b90046001600160a01b0316036127c0576001612778613249565b6001600160581b0319831660009081526001919091016020526040902080546001600160a01b0392909216600160201b02640100000000600160c01b03199092169190911790555b6128008686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141dc92505050565b5060008051602061700d8339815191528787604051612820929190616bc1565b60405180910390a1506121fd565b85600503612916576000612840613249565b5460581b905060006128556020828789616a65565b61285e91616bd8565b905061286f825b600160f91b610967565b156128a75761287e8260081b90565b6001600160e01b03191681036128a7576040516313002bdd60e31b815260040160405180910390fd5b6128e78787878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141dc92505050565b5060008051602061700d8339815191528888604051612907929190616bc1565b60405180910390a150506121fd565b856006036121e4576000612840613249565b846001036129565760006129428560581b600160f81b1790565b905061294f818585613f16565b5050612553565b8460020361296f5761296984848461405a565b50612553565b846003036129a25760006129866004828587616a65565b61298f91616a8f565b905061294f8161270c8560048189616a65565b84600403612abf5760006129b4613249565b5460581b90506001600160a01b0385166129cc613249565b6001600160581b0319831660009081526001919091016020526040902054600160201b90046001600160a01b031603612a51576001612a09613249565b6001600160581b0319831660009081526001919091016020526040902080546001600160a01b0392909216600160201b02640100000000600160c01b03199092169190911790555b612a918585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141dc92505050565b5060008051602061700d8339815191528686604051612ab1929190616bc1565b60405180910390a150612553565b84600503612ba1576000612ad1613249565b5460581b90506000612ae66020828688616a65565b612aef91616bd8565b9050612afa82612865565b15612b3257612b098260081b90565b6001600160e01b0319168103612b32576040516313002bdd60e31b815260040160405180910390fd5b612b728686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141dc92505050565b5060008051602061700d8339815191528787604051612b92929190616bc1565b60405180910390a15050612553565b846006036121e4576000612ad1613249565b6000612bbd613249565b54600160a81b900463ffffffff16919050565b6040805180820190915260008082526020820152612bec613249565b6001600160581b03199290921660009081526001909201602090815260409283902083518085019094525463ffffffff81168452600160201b90046001600160a01b0316908301525090565b60408051606080820183526000808352602083015291810191909152612c5c613249565b6001600160e01b03198316600090815260039190910160209081526040918290208251606081018452815460f081901b6001600160f01b03191682526201000090046001600160a01b03168184015260018201805485518186028101860187528181529295939493860193830182828015612d0457602002820191906000526020600020905b815460501b6001600160501b0319168152600190910190602001808311612ce2575b5050505050815250509050919050565b600081600881901b603082901b605083901b612d3484600160f81b613691565b8015612d465750612d46846000613691565b8015612d5f5750612d5f846001600160f81b0319613691565b8015612d745750612d7484607f60f91b613691565b15612d855750600095945050505050565b6001600160f81b03198316600160f81b14801590612dac57506001600160f81b0319831615155b15612dbd5750600095945050505050565b6001600160e01b0319821615612dd95750600095945050505050565b6001600160501b0319811615612df55750600095945050505050565b50600195945050505050565b60606000612e0e3361326d565b546001600160a01b0316905080612e385760405163710c949760e01b815260040160405180910390fd5b60606001600160a01b038216600114612e5b57612e5882346000366108e2565b90505b612e66868686614283565b92506001600160a01b038216600114612e8357612e8382826109fd565b50509392505050565b6000612e99610ffd613249565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801590612ed45750333014155b156130435760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015612f1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f419190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f602590612f7b90339034908690369060040161699a565b6000604051808303816000875af1158015612f9a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612fc291908101906169f3565b90506000612fd1888888613f16565b9050612fde8186866145cb565b50604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061300b9084906004016166ca565b600060405180830381600087803b15801561302557600080fd5b505af1158015613039573d6000803e3d6000fd5b5050505050610a57565b6000613050878787613f16565b90506111988185856145cb565b600061306a610ffd613249565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015906130a55750333014155b156132055760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa1580156130ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131129190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f60259061314c90339034908690369060040161699a565b6000604051808303816000875af115801561316b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261319391908101906169f3565b90506131a0858585614283565b50604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906131cd9084906004016166ca565b600060405180830381600087803b1580156131e757600080fd5b505af11580156131fb573d6000803e3d6000fd5b5050505050613210565b612553848484614283565b50505050565b6000613220613249565b5460581b919050565b6000600782101561323c57506001919050565b506000919050565b919050565b7f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f90565b6001600160a01b031660009081527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b866020526040902090565b813536600060f883901c80156132cb57600181146132e057600281146132f157600080fd5b6000935060018601925060018503915061330b565b60158601925060158503915061330b565b6001600160d81b0319841693506005860192506005850391505b509250925092565b604080517f1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c836020820152908101829052600090610978906060015b60405160208183030381529060405280519060200120614694565b600080600036600061337e8a8a8a8a8a6147ac565b9350935093509350600080613392856148b8565b50915091508165ffffffffffff164210806133b457508065ffffffffffff1642115b156133d057506001600160e01b0319955061095e945050505050565b6001600160a01b03861663392dffaf6001600160e01b03198e168d6133f48e613313565b88886040518663ffffffff1660e01b8152600401613416959493929190616bf6565b602060405180830381865afa158015613433573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134579190616ac7565b9c9b505050505050505050505050565b80600881901b8060ff60f084901c16600119810161348d576001600160d81b0319821691505b509193909250565b6000806134a0613249565b905060006134ad85616c80565b90503660006134c0610100880188616ae4565b90925090506134d389600160f81b610967565b15613531576134ef886134ea6101008a018a616ae4565b6148eb565b604080516020601f8401819004810282018101909252828152939850919450925083908390819084018382808284376000920191909152505050506101008401525b8761354081600160f81b610967565b156135cf576135c8866135538b60581c90565b6001600160a01b03166397003203878b6040518363ffffffff1660e01b8152600401613580929190616e23565b6020604051808303816000875af115801561359f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135c39190616e45565b614918565b9550613684565b60006135db8a60081b90565b6001600160e01b03198116600090815260038801602052604090205490915060f01b600160f01b1615613621576040516314b9743f60e01b815260040160405180910390fd5b600080613630838888886149d6565b9150915061363e8983614918565b985061367e89826001600160a01b0316630ccab7a1866001600160e01b0319168b8f6040518463ffffffff1660e01b815260040161358093929190616e5e565b98505050505b5050505050949350505050565b6001600160f81b03199081169116141590565b60006136ae613249565b805490915063ffffffff808416916136d091600a91600160a81b900416616e87565b63ffffffff1610156136f55760405163e60fd64760e01b815260040160405180910390fd5b805463ffffffff600160c81b90910481169083161161372757604051633ab3447f60e11b815260040160405180910390fd5b805463ffffffff60c81b1916600160c81b63ffffffff8481168202929092178084559081048216600160a81b90910490911610156111c357805463ffffffff60a81b198116600160c81b90910463ffffffff16600160a81b0217905550565b6000613790613249565b6001600160581b03198516600081815260028301602090815260408083206001600160e01b0319891680855290835292819020805488151560ff1990911681179091558151938452918301939093528183015290519192507f9d17cd6d095ac90a655405ab29f30a7ee7e88ef3974c1bf7544bf591043bb71a919081900360600190a150505050565b6000613823613249565b80546001600160a81b031916605884901c1781556040516001600160581b0319841681529091507f6789ec0c85d6458d897a36a70129b101f8b4d84c6e218046c3107373dbcbae889060200160405180910390a15050565b6000613885613249565b80546001600160581b03198916600090815260018301602052604090205491925063ffffffff600160a81b90910481169116036138e5578054600163ffffffff600160a81b808404821692909201160263ffffffff60a81b199091161781555b60208601516001600160a01b03166138ff57600160208701525b85518154600160a81b900463ffffffff9081169116141580613947575085516001600160581b03198816600090815260018301602052604090205463ffffffff918216911610155b1561396557604051633ab3447f60e11b815260040160405180910390fd5b6001600160581b03198716600090815260018083016020908152604090922088518154938a01516001600160a01b0316600160201b81026001600160c01b031990951663ffffffff90921691909117939093179055146139ce576139ce86602001518484613bd4565b866139dd81600160f81b610967565b15613a7f5760006139ee8960581c90565b6040516306d61fe760e41b81529091506001600160a01b03821690636d61fe7090613a1f908a908a90600401616bad565b600060405180830381600087803b158015613a3957600080fd5b505af1158015613a4d573d6000803e3d6000fd5b50505050600080516020616fed833981519152600182604051613a71929190616bc1565b60405180910390a150611d70565b613a8d81600160f91b610967565b15613ab1576000613a9e8960081b90565b9050613aab818888614cb6565b50611d70565b6040516361c4e91b60e11b815260040160405180910390fd5b60005b86811015611d7057613b66888883818110613aea57613aea616b47565b9050602002016020810190613aff91906166dd565b878381518110613b1157613b11616b47565b6020026020010151878785818110613b2b57613b2b616b47565b9050602002810190613b3d9190616ae4565b878787818110613b4f57613b4f616b47565b9050602002810190613b619190616ae4565b61387b565b600101613acd565b613b78848261510f565b6040516306d61fe760e41b81526001600160a01b03851690636d61fe7090613ba69086908690600401616bad565b600060405180830381600087803b158015613bc057600080fd5b505af1158015611d70573d6000803e3d6000fd5b6001600160a01b0383161580613bf357506001600160a01b0383166001145b15613bfd57505050565b60405163d60b347f60e01b81523060048201526001600160a01b0384169063d60b347f90602401602060405180830381865afa158015613c41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c659190616b2a565b613cd9576001600160a01b038316636d61fe70613c858360018187616a65565b6040518363ffffffff1660e01b8152600401613ca2929190616bad565b600060405180830381600087803b158015613cbc57600080fd5b505af1158015613cd0573d6000803e3d6000fd5b50505050613d78565b6001600160f81b03198282600081613cf357613cf3616b47565b9050013560f81c60f81b6001600160f81b03191603613d78576001600160a01b038316636d61fe70613d288360018187616a65565b6040518363ffffffff1660e01b8152600401613d45929190616bad565b600060405180830381600087803b158015613d5f57600080fd5b505af1158015613d73573d6000803e3d6000fd5b505050505b600080516020616fed833981519152600484604051613d98929190616bc1565b60405180910390a1505050565b6001600160a01b038316613dbe576001600160a01b0392505b6000613dc9866108a8565b9050600083836000818110613de057613de0616b47565b9050013560f81c60f81b9050613dfa81600060f81b610967565b15613e97576001600160a01b038616636d61fe70613e1b8560018189616a65565b6040518363ffffffff1660e01b8152600401613e38929190616bad565b600060405180830381600087803b158015613e5257600080fd5b505af1158015613e66573d6000803e3d6000fd5b50505050600080516020616fed833981519152600387604051613e8a929190616bc1565b60405180910390a1613ec7565b613ea9816001600160f81b0319613691565b15613ec757604051632d6a6bb760e01b815260040160405180910390fd5b81546001600160a01b039586166001600160a01b03199091161782556001909101805460f89290921c600160a01b026001600160a81b0319909216959094169490941793909317909155505050565b600080613f21613249565b805490915060581b6001600160581b031990811690861603613f56576040516313002bdd60e31b815260040160405180910390fd5b6001600160581b03198516600090815260018201602052604090208054640100000000600160c01b03198116909155600160201b90046001600160a01b0316915084613fa681600160f81b610967565b15614028576000613fb78760581c90565b9050613ff98187878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141dc92505050565b5060008051602061700d83398151915260018260405161401a929190616bc1565b60405180910390a150612e83565b61403681600160f91b610967565b15613ab15760006140478760081b90565b9050614054818787615169565b50612e83565b6000806140668561326d565b80546001600160a01b031981168255604080516020601f88018190048102820181019092528681526001600160a01b0390921694509192506140c59187919087908790819084018382808284376000920191909152506141dc92505050565b5060008051602061700d8339815191526002866040516140e6929190616bc1565b60405180910390a1509392505050565b600080614102856108a8565b80546001600160a01b03198116825560018201546001600160a01b03909116935090915061413b90600160a01b900460f81b6000610967565b156141c4576001810154604080516020601f870181900481028201810190925285815261418c926001600160a01b03169187908790819084018382808284376000920191909152506141dc92505050565b50600181015460405160008051602061700d833981519152916141bb916003916001600160a01b031690616bc1565b60405180910390a15b60010180546001600160a81b03191690559392505050565b6000614236835a600080638a91b0e360e01b876040516024016141ff91906166ca565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152615333565b50604080516001600160a01b038616815282151560208201529192507f2b82f87bf66300af618a9621d3f221edfab735f5bacb4e004cce1b62375396c3910160405180910390a192915050565b606083600881901b61429982600160f81b610967565b1561432357843585016020810190356142b3836000610967565b156142c9576142c282826153bd565b945061431c565b6142d783600160f81b610967565b156142e6576142c2828261548d565b60405162461bcd60e51b815260206004820152600b60248201526a155b9cdd5c1c1bdc9d195960aa1b604482015260640161144b565b5050612e83565b61432e826000610967565b1561445c5760008036600061434389896155ba565b6040805160018082528183019092529498509296509094509250816020015b606081526020019060019003908161436257905050965060006143858682610967565b156143b9576143968585858561560b565b886000815181106143a9576143a9616b47565b6020026020010181905250614452565b6143c786600160f81b610967565b156142e6576143d885858585615641565b896000815181106143eb576143eb616b47565b6020908102919091010152905080614452577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb760008960008151811061443357614433616b47565b6020026020010151604051614449929190616eb1565b60405180910390a15b5050505050612e83565b61446e826001600160f81b0319610967565b156142e65760408051600180825281830190925290816020015b606081526020019060019003908161448857905050925060006144ae6014828789616a65565b6144b791616b6d565b60601c90503660006144cc876014818b616a65565b9150915060006144dd8484846109ce565b886000815181106144f0576144f0616b47565b6020908102919091010152905061450b85600160f81b610967565b1561456f578061456a577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb760008860008151811061454b5761454b616b47565b6020026020010151604051614561929190616eb1565b60405180910390a15b6145c2565b61457a856000610967565b156142e6578061456a5760405162461bcd60e51b815260206004820152601360248201527211195b1959d85d1958d85b1b0819985a5b1959606a1b604482015260640161144b565b50505050612e83565b6001600160a01b03831615806145ea57506001600160a01b0383166001145b156145f457505050565b6001600160f81b0319828260008161460e5761460e616b47565b9050013560f81c60f81b6001600160f81b0319160361467457614672836146388360018187616a65565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141dc92505050565b505b60008051602061700d833981519152600484604051613d98929190616bc1565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030147f00000000000000000000000000000000000000000000000000000000000000004614166147875750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f000000000000000000000000000000000000000000000000000000000000000060208201527f00000000000000000000000000000000000000000000000000000000000000009181019190915246606082015230608082015260a090205b67190100000000000060005280601a5281603a52604260182090506000603a52919050565b600080366000806147bb613249565b60408051610120810182526000808252602082018190529181018290526080810182905260a0810191909152606060c082018190526001600160e01b03198d16908201526001600160a01b038b1660e082015261010081018a905290915061482581838a8a615672565b8787600081811061483857614838616b47565b9091013560f81c60ff1490506148615760405163b32eeb6960e01b815260040160405180910390fd5b61486e876001818b616a65565b60608301516001600160e01b0319166000908152600394909401602052604093849020549390920151620100009093046001600160a01b03169c929b509950975095505050505050565b600060a082901c65ffffffffffff1682811560001981016148dd5765ffffffffffff92505b508360d01c92509193909250565b60003660006148fb8686866158df565b925050506094830135830160348101906014013593509350939050565b600081830160601b8260601b81148460601b8214176001600160a01b038486181615176001811461494c57600192506149ce565b6001600160d01b031980851690861681811881831102188686176001600160a01b031617935065ffffffffffff60a01b861690816149915765ffffffffffff60a01b91505b5065ffffffffffff60a01b8516806149af575065ffffffffffff60a01b5b8082189082110218806149c8575065ffffffffffff60a01b5b92909217915b505092915050565b60008060006149e3613249565b6001600160e01b03198816600090815260038201602052604081209192506001909101905b8154811015614bfa57600080614a41848481548110614a2957614a29616b47565b60009182526020909120015460501b90605082901c90565b91509150600089896000818110614a5a57614a5a616b47565b919091013560f81c915050838103614aed576000614a7c600960018c8e616a65565b614a8591616eca565b60c01c9050614a9a6009808301908c8e616a65565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101008d0152614ae38a60098301818e616a65565b9a509a5050614b27565b838160ff161015614b1157604051630760bdcf60e11b815260040160405180910390fd5b6040805160208101909152600081526101008c01525b600160f01b8316600003614bef576000826001600160a01b0316637129edce8e6001600160e01b0319168e6040518363ffffffff1660e01b8152600401614b6f929190616f00565b6020604051808303816000875af1158015614b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bb29190616e45565b9050806001600160a01b03811615614be057604051631f24c1fb60e11b81526004810187905260240161144b565b614bea8a83614918565b995050505b505050600101614a08565b5085856000818110614c0e57614c0e616b47565b9091013560f81c60ff149050614c375760405163b32eeb6960e01b815260040160405180910390fd5b614c448560018189616a65565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052506101008c01949094525050506001600160e01b03198916815260039092016020525060409020546001600160a01b036201000090910416905094509492505050565b6000614cc0613249565b90508235830160208101903560fe811180614cd9575080155b15614cf75760405163b62d956d60e01b815260040160405180910390fd5b6001600160e01b03198616600090815260038401602052604090206001015415614d45576001600160e01b0319861660009081526003840160205260408120614d4591600190910190615ead565b60005b6000198201811015614f39576001600160e01b0319871660009081526003850160205260409020600101838383818110614d8457614d84616b47565b9050602002810190614d969190616ae4565b614da591601691600091616a65565b614dae91616f19565b81546001810183556000928352602090922090910180546001600160b01b03191660509290921c919091179055828282818110614ded57614ded616b47565b9050602002810190614dff9190616ae4565b614e0e91601691600291616a65565b614e1791616b6d565b60601c636d61fe706001600160e01b03198916858585818110614e3c57614e3c616b47565b9050602002810190614e4e9190616ae4565b614e5c916016908290616a65565b604051602001614e6e93929190616f4f565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401614e9991906166ca565b600060405180830381600087803b158015614eb357600080fd5b505af1158015614ec7573d6000803e3d6000fd5b50505050600080516020616fed8339815191526005848484818110614eee57614eee616b47565b9050602002810190614f009190616ae4565b614f0f91601691600291616a65565b614f1891616b6d565b60601c604051614f29929190616bc1565b60405180910390a1600101614d48565b50600082826000198101818110614f5257614f52616b47565b9050602002810190614f649190616ae4565b614f7391601691600291616a65565b614f7c91616b6d565b6001600160e01b031988166000908152600386016020526040902080546201000060609390931c92830262010000600160b01b0319909116179055905082826000198101818110614fcf57614fcf616b47565b9050602002810190614fe19190616ae4565b614ff091600291600091616a65565b614ff991616f69565b6001600160e01b0319881660008181526003870160205260409020805461ffff191660f09390931c929092179091556001600160a01b03821690636d61fe70908585600019810181811061504f5761504f616b47565b90506020028101906150619190616ae4565b61506f916016908290616a65565b60405160200161508193929190616f4f565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016150ac91906166ca565b600060405180830381600087803b1580156150c657600080fd5b505af11580156150da573d6000803e3d6000fd5b50505050600080516020616fed8339815191526006826040516150fe929190616bc1565b60405180910390a150505050505050565b6001600160a01b038116615121575060015b600061512c8361326d565b80546001600160a01b0319166001600160a01b038416178155604051909150600080516020616fed83398151915290613d98906002908690616bc1565b81358201602081019035600061517d613249565b6001600160e01b031987166000908152600391909101602052604090206001808201549192500182146151c35760405163013dcc8d60e31b815260040160405180910390fd5b6001810160005b81548110156152785760006151ea838381548110614a2957614a29616b47565b915050615246818a6001600160e01b03191688888681811061520e5761520e616b47565b90506020028101906152209190616ae4565b60405160200161523293929190616f4f565b6040516020818303038152906040526141dc565b5060008051602061700d833981519152600582604051615267929190616bc1565b60405180910390a1506001016151ca565b50615281613249565b6001600160e01b031988166000908152600391909101602052604081206152ad91600190910190615ead565b81546152e3906201000090046001600160a01b03166001600160e01b031989168686600019810181811061520e5761520e616b47565b50815460405160008051602061700d83398151915291615315916006916201000090046001600160a01b031690616bc1565b60405180910390a15080546001600160b01b03191690555050505050565b6000606060008060008661ffff166001600160401b03811115615358576153586164be565b6040519080825280601f01601f191660200182016040528015615382576020820181803683370190505b5090506000808751602089018b8e8ef191503d9250868311156153a3578692505b828152826000602083013e90999098509650505050505050565b606081806001600160401b038111156153d8576153d86164be565b60405190808252806020026020018201604052801561540b57816020015b60608152602001906001900390816153f65790505b50915060005b818110156149ce573685858381811061542c5761542c616b47565b905060200281019061543e9190616f9f565b905061546761545060208301836160fc565b60208301356154626040850185616ae4565b61560b565b84838151811061547957615479616b47565b602090810291909101015250600101615411565b606081806001600160401b038111156154a8576154a86164be565b6040519080825280602002602001820160405280156154db57816020015b60608152602001906001900390816154c65790505b50915060005b818110156149ce57368585838181106154fc576154fc616b47565b905060200281019061550e9190616f9f565b9050600061553961552260208401846160fc565b60208401356155346040860186616ae4565b615641565b86858151811061554b5761554b616b47565b60209081029190910101529050806155b0577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb78386858151811061559157615591616b47565b60200260200101516040516155a7929190616eb1565b60405180910390a15b50506001016154e1565b60008036816155cc6014828789616a65565b6155d591616b6d565b60601c93506155e8603460148789616a65565b6155f191616bd8565b92506156008560348189616a65565b949793965094505050565b60405181838237600038838387895af1615628573d6000823e3d81fd5b3d8152602081013d6000823e3d01604052949350505050565b604051600090828482376000388483888a5af191503d8152602081013d6000823e3d81016040525094509492505050565b60608401516001600160e01b03191660009081526003840160205260408120600101905b8154811015610a57576156b4828281548110614a2957614a29616b47565b6001600160a01b031660a08801526001600160f01b031916608087015283836000816156e2576156e2616b47565b919091013560f81c808852829003905061577f57615704600960018587616a65565b61570d91616eca565b60c01c60208701819052615728906009908101908587616a65565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050505060c087015260208601516157769084906009018187616a65565b935093506157eb565b855160ff168111156157a457604051630760bdcf60e11b815260040160405180910390fd5b6157b16000808587616a65565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050505060c08701525b6080860151600160f11b166000036158d75760a0860151606087015160e088015161010089015160c08a015160405163184dfdbb60e11b81526000956001600160a01b03169463309bfb7694615852946001600160e01b0319909216939092600401616fbf565b602060405180830381865afa15801561586f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906158939190616e45565b9050806001600160a01b038116156158c157604051631f24c1fb60e11b81526004810184905260240161144b565b6158cf886040015183614918565b604089015250505b600101615696565b600036600080366000366000366000806158fa8e8e8e615965565b9750975097509750975097509750975060748d013560348e0101995060208a03359850615928818b8b615b1a565b9a506159388e898989898961387b565b6159428383615cba565b6159548e611fcf600460008688616a65565b505050505050505050509392505050565b604080518082019091526000808252602082015236600036600036600080600061598d613249565b905061599d601460008c8e616a65565b6159a691616b6d565b60601c89602001906001600160a01b031690816001600160a01b0316815250508060000160159054906101000a900463ffffffff16896000019063ffffffff16908163ffffffff168152505060148b013560348c010197506020880335965060348b013560348c010195506020860335945060548b013560348c0101935060208403359250615b0a7fb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c50560001b8d8360000160159054906101000a900463ffffffff168c602001518c8c604051615a7d929190616b5d565b60405180910390208b8b604051615a95929190616b5d565b60405180910390208a8a604051615aad929190616b5d565b6040805191829003822060208301989098526001600160581b03199096169581019590955263ffffffff90931660608501526001600160a01b03909116608084015260a083015260c082015260e08101919091526101000161334e565b9150509397509397509397509397565b600080615b25613249565b805490915060581b6000615b3d82600160f81b610967565b15615bc9578254604051637aa8f17760e11b81526001600160a81b038216916001600160a01b03169063f551e2ee90615b809030908c908c908c9060040161699a565b602060405180830381865afa158015615b9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615bc19190616ac7565b915050615c7f565b615bd782600160f91b610967565b15613ab157825460601b6000615bf082308b8b8b6147ac565b60405163392dffaf60e01b8152919b5099509097509091506001600160a01b0382169063392dffaf90615c39906001600160e01b031986169030908e908e908e90600401616bf6565b602060405180830381865afa158015615c56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615c7a9190616ac7565b925050505b630b135d3f60e11b6001600160e01b0319821614615cb0576040516362467c7760e11b815260040160405180910390fd5b5050509392505050565b6000615cc96004828486616a65565b615cd291616a8f565b9050600482106113eb57602c8210615e6657366000818180615cf860186004898b616a65565b615d0191616b6d565b60601c9050602c880135604c890101945060208503359350604c880135604c890101925060208303359150615d5685856000818110615d4257615d42616b47565b9050013560f81c60f81b600060f81b610967565b8015615dc6575060405163ecd0596160e01b8152600260048201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015615da2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615dc69190616b2a565b15615e1c57606c8801358801604c810190602c01356000615dea6014828486616a65565b615df391616b6d565b60601c9050615e02848261510f565b615e1881615e138460148188616a65565b613bd4565b5050505b615e428682615e2f602c60188c8e616a65565b615e3891616b6d565b60601c8888613da5565b611d70615e53602c60188a8c616a65565b615e5c91616b6d565b60601c8484613bd4565b600482146113eb5760405162461bcd60e51b8152602060048201526014602482015273496e76616c69642073656c6563746f724461746160601b604482015260640161144b565b5080546000825590600052602060002090810190615ecb9190615ece565b50565b5b80821115615ee35760008155600101615ecf565b5090565b6001600160a01b0381168114615ecb57600080fd5b803561324481615ee7565b60008083601f840112615f1957600080fd5b5081356001600160401b03811115615f3057600080fd5b602083019150836020828501011115615f4857600080fd5b9250929050565b60008060008060608587031215615f6557600080fd5b843593506020850135615f7781615ee7565b925060408501356001600160401b03811115615f9257600080fd5b615f9e87828801615f07565b95989497509550505050565b600080600080600060808688031215615fc257600080fd5b8535615fcd81615ee7565b94506020860135615fdd81615ee7565b93506040860135925060608601356001600160401b03811115615fff57600080fd5b61600b88828901615f07565b969995985093965092949392505050565b60008060006040848603121561603157600080fd5b8335925060208401356001600160401b0381111561604e57600080fd5b61605a86828701615f07565b9497909650939450505050565b6000610120828403121561607a57600080fd5b50919050565b60008060006060848603121561609557600080fd5b83356001600160401b038111156160ab57600080fd5b6160b786828701616067565b9660208601359650604090950135949350505050565b803563ffffffff8116811461324457600080fd5b6000602082840312156160f357600080fd5b610cce826160cd565b60006020828403121561610e57600080fd5b8135610cce81615ee7565b80356001600160581b03198116811461324457600080fd5b6001600160e01b031981168114615ecb57600080fd5b8015158114615ecb57600080fd5b60008060006060848603121561616a57600080fd5b61617384616119565b9250602084013561618381616131565b9150604084013561619381616147565b809150509250925092565b60008083601f8401126161b057600080fd5b5081356001600160401b038111156161c757600080fd5b6020830191508360208260051b8501011115615f4857600080fd5b60008060008060008060008060a0898b0312156161fe57600080fd5b61620789616119565b9750602089013561621781615ee7565b965060408901356001600160401b0381111561623257600080fd5b61623e8b828c01615f07565b90975095505060608901356001600160401b0381111561625d57600080fd5b6162698b828c01615f07565b90955093505060808901356001600160401b0381111561628857600080fd5b6162948b828c0161619e565b999c989b5096995094979396929594505050565b600080600080600080608087890312156162c157600080fd5b6162ca87616119565b955060208701356162da81615ee7565b945060408701356001600160401b038111156162f557600080fd5b61630189828a01615f07565b90955093505060608701356001600160401b0381111561632057600080fd5b61632c89828a01615f07565b979a9699509497509295939492505050565b60006020828403121561635057600080fd5b8135610cce81616131565b6000806040838503121561636e57600080fd5b61637783616119565b9150602083013561638781616131565b809150509250929050565b60005b838110156163ad578181015183820152602001616395565b50506000910152565b600081518084526163ce816020860160208601616392565b601f01601f19169290920160200192915050565b60ff60f81b8816815260e06020820152600061640160e08301896163b6565b828103604084015261641381896163b6565b606084018890526001600160a01b038716608085015260a0840186905283810360c08501528451808252602080870193509091019060005b8181101561646957835183526020938401939092019160010161644b565b50909b9a5050505050505050505050565b6000806040838503121561648d57600080fd5b82356001600160401b038111156164a357600080fd5b6164af85828601616067565b95602094909401359450505050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156164f6576164f66164be565b60405290565b60405161012081016001600160401b03811182821017156164f6576164f66164be565b604051601f8201601f191681016001600160401b0381118282101715616547576165476164be565b604052919050565b60008060008060008060006080888a03121561656a57600080fd5b87356001600160401b0381111561658057600080fd5b61658c8a828b0161619e565b90985096505060208801356001600160401b038111156165ab57600080fd5b8801601f81018a136165bc57600080fd5b80356001600160401b038111156165d5576165d56164be565b6165e460208260051b0161651f565b8082825260208201915060208360061b85010192508c83111561660657600080fd5b6020840193505b82841015616662576040848e03121561662557600080fd5b61662d6164d4565b616636856160cd565b8152602085013561664681615ee7565b806020830152508083525060208201915060408401935061660d565b975050505060408801356001600160401b0381111561668057600080fd5b61668c8a828b0161619e565b90955093505060608801356001600160401b038111156166ab57600080fd5b6166b78a828b0161619e565b989b979a50959850939692959293505050565b602081526000610cce60208301846163b6565b6000602082840312156166ef57600080fd5b610cce82616119565b60008060008060008060008060a0898b03121561671457600080fd5b883561671f81615ee7565b9750602089013561672f81615ee7565b965060408901356001600160401b0381111561674a57600080fd5b6167568b828c0161619e565b90975095505060608901356001600160401b0381111561677557600080fd5b6167818b828c0161619e565b90955093505060808901356001600160401b038111156167a057600080fd5b6162948b828c01615f07565b602080825282516001600160f01b03191682820152828101516001600160a01b03166040808401919091528301516060808401528051608084018190526000929190910190829060a08501905b808310156168255783516001600160501b031916825260209384019360019390930192909101906167f9565b5095945050505050565b60006020828403121561684157600080fd5b5035919050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b828110156168a157603f1987860301845261688c8583516163b6565b94506020938401939190910190600101616870565b50929695505050505050565b6000806000806000606086880312156168c557600080fd5b6168ce86616119565b945060208601356001600160401b038111156168e957600080fd5b6168f588828901615f07565b90955093505060408601356001600160401b03811115615fff57600080fd5b60008060008060008060a0878903121561692d57600080fd5b863561693881615ee7565b9550602087013561694881615ee7565b9450604087013593506060870135925060808701356001600160401b0381111561632057600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60018060a01b03851681528360208201526060604082015260006169c2606083018486616971565b9695505050505050565b60006001600160401b038211156169e5576169e56164be565b50601f01601f191660200190565b600060208284031215616a0557600080fd5b81516001600160401b03811115616a1b57600080fd5b8201601f81018413616a2c57600080fd5b8051616a3f616a3a826169cc565b61651f565b818152856020838501011115616a5457600080fd5b61095e826020830160208601616392565b60008085851115616a7557600080fd5b83861115616a8257600080fd5b5050820193919092039150565b80356001600160e01b03198116906004841015616ac0576001600160e01b0319600485900360031b81901b82161691505b5092915050565b600060208284031215616ad957600080fd5b8151610cce81616131565b6000808335601e19843603018112616afb57600080fd5b8301803591506001600160401b03821115616b1557600080fd5b602001915036819003821315615f4857600080fd5b600060208284031215616b3c57600080fd5b8151610cce81616147565b634e487b7160e01b600052603260045260246000fd5b8183823760009101908152919050565b80356bffffffffffffffffffffffff198116906014841015616ac0576bffffffffffffffffffffffff1960149490940360031b84901b1690921692915050565b602081526000610b2c602083018486616971565b9182526001600160a01b0316602082015260400190565b8035602083101561097857600019602084900360031b1b1692915050565b85815260018060a01b0385166020820152836040820152608060608201526000616c24608083018486616971565b979650505050505050565b600082601f830112616c4057600080fd5b8135616c4e616a3a826169cc565b818152846020838601011115616c6357600080fd5b816020850160208301376000918101602001919091529392505050565b60006101208236031215616c9357600080fd5b616c9b6164fc565b616ca483615efc565b81526020838101359082015260408301356001600160401b03811115616cc957600080fd5b616cd536828601616c2f565b60408301525060608301356001600160401b03811115616cf457600080fd5b616d0036828601616c2f565b6060830152506080838101359082015260a0808401359082015260c0808401359082015260e08301356001600160401b03811115616d3d57600080fd5b616d4936828601616c2f565b60e0830152506101008301356001600160401b03811115616d6957600080fd5b616d7536828601616c2f565b6101008301525092915050565b80516001600160a01b0316825260208101516020830152600060408201516101206040850152616db66101208501826163b6565b905060608301518482036060860152616dcf82826163b6565b9150506080830151608085015260a083015160a085015260c083015160c085015260e083015184820360e0860152616e0782826163b6565b91505061010083015184820361010086015261095e82826163b6565b604081526000616e366040830185616d82565b90508260208301529392505050565b600060208284031215616e5757600080fd5b5051919050565b838152606060208201526000616e776060830185616d82565b9050826040830152949350505050565b63ffffffff818116838216019081111561097857634e487b7160e01b600052601160045260246000fd5b828152604060208201526000610b2c60408301846163b6565b80356001600160c01b03198116906008841015616ac0576001600160c01b031960089490940360031b84901b1690921692915050565b828152604060208201526000610b2c6040830184616d82565b80356001600160501b03198116906016841015616ac0576001600160501b031960169490940360031b84901b1690921692915050565b838152818360208301376000910160200190815292915050565b80356001600160f01b03198116906002841015616ac0576001600160f01b031960029490940360031b84901b1690921692915050565b60008235605e19833603018112616fb557600080fd5b9190910192915050565b84815260018060a01b03841660208201528260408201526080606082015260006169c260808301846163b656fed21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e"; + bytes public constant KERNEL_FACTORY_BYTECODE = + hex"60a0604052348015600f57600080fd5b506040516104ce3803806104ce833981016040819052602c91603c565b6001600160a01b0316608052606a565b600060208284031215604d57600080fd5b81516001600160a01b0381168114606357600080fd5b9392505050565b60805161043d6100916000396000818160870152818160f10152610159015261043d6000f3fe6080604052600436106100345760003560e01c806348aac392146100395780635c60da1b14610075578063ea6d13ac146100a9575b600080fd5b34801561004557600080fd5b506100596100543660046103a2565b6100bc565b6040516001600160a01b03909116815260200160405180910390f35b34801561008157600080fd5b506100597f000000000000000000000000000000000000000000000000000000000000000081565b6100596100b73660046103a2565b610120565b6000808484846040516020016100d49392919061041b565b6040516020818303038152906040528051906020012090506101177f00000000000000000000000000000000000000000000000000000000000000008230610213565b95945050505050565b6000808484846040516020016101389392919061041b565b60405160208183030381529060405280519060200120905060008061017e347f00000000000000000000000000000000000000000000000000000000000000008561029c565b9150915081610209576000816001600160a01b031688886040516101a392919061042d565b6000604051808303816000865af19150503d80600081146101e0576040519150601f19603f3d011682016040523d82523d6000602084013e6101e5565b606091505b50509050806102075760405163487e630960e11b815260040160405180910390fd5b505b9695505050505050565b60008061028f85604080517fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f360609081527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e20768352616009602052601e9390935268603d3d8160223d3973600a52605f6021209152600090915290565b9050610117818585610380565b6000806040517fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f36060527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e207660405261600960205284601e5268603d3d8160223d3973600a52605f60212060358201523060581b815260ff8153836015820152605581209150813b6103485783605f602188f59150816103435763301164256000526004601cfd5b61036e565b60019250851561036e5760003860003889865af161036e5763b12d13eb6000526004601cfd5b80604052506000606052935093915050565b600060ff60005350603592835260601b60015260155260556000908120915290565b6000806000604084860312156103b757600080fd5b833567ffffffffffffffff8111156103ce57600080fd5b8401601f810186136103df57600080fd5b803567ffffffffffffffff8111156103f657600080fd5b86602082840101111561040857600080fd5b6020918201979096509401359392505050565b82848237909101908152602001919050565b818382376000910190815291905056"; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/NexusPrecompiles.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/NexusPrecompiles.sol new file mode 100644 index 0000000..6a82de4 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/NexusPrecompiles.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { INexusAccountFactory } from "../../accounts/nexus/interfaces/INexusAccountFactory.sol"; +import { INexusBootstrap } from "../../accounts/nexus/interfaces/INexusBootstrap.sol"; +import { INexus } from "../../accounts/nexus/interfaces/INexus.sol"; + +// Utils +import { label } from "../../test/utils/Vm.sol"; +import { BytecodeDeployer } from "./BytecodeDeployer.sol"; + +/// @notice Nexus contracts precompiled using --via-ir +contract NexusPrecompiles is BytecodeDeployer { + /*////////////////////////////////////////////////////////////// + DEPLOY + //////////////////////////////////////////////////////////////*/ + + /// @notice Deploys Nexus from --via-ir precompiled bytecode + function deployNexus(address anEntryPoint) public returns (address nexus) { + // Concat constructor params to bytecode + bytes memory creationBytecode = bytes.concat(NEXUS_BYTECODE, abi.encode(anEntryPoint)); + // Deploy contract + nexus = _deploy(creationBytecode); + // Label contract + label(nexus, "Nexus"); + } + + /// @notice Deploys NexusProxy from --via-ir precompiled bytecode + function deployNexusProxy( + bytes32 salt, + address implementation, + bytes memory initCode + ) + internal + returns (address) + { + return _deploy2( + bytes.concat( + NEXUS_PROXY_BYTECODE, + abi.encode( + implementation, + abi.encodeWithSelector(INexus.initializeAccount.selector, initCode) + ) + ), + salt + ); + } + + /// @notice Deploys NexusAccountFactory from --via-ir precompiled bytecode + function deployNexusAccountFactory( + address implementation, + address owner + ) + public + returns (INexusAccountFactory factory) + { + // Concat constructor params to bytecode + bytes memory creationBytecode = + bytes.concat(NEXUS_ACCOUNT_FACTORY_BYTECODE, abi.encode(implementation, owner)); + // Deploy contract + factory = INexusAccountFactory(_deploy(creationBytecode)); + // Label contract + label(address(factory), "NexusAccountFactory"); + } + + /// @notice Deploys the NexusBootstrap contract from --via-ir precompiled bytecode + function deployNexusBootstrap() public returns (INexusBootstrap bootstrap) { + // Deploy contract + bootstrap = INexusBootstrap(_deploy(NEXUS_BOOTSTRAP_BYTECODE)); + // Label contract + label(address(bootstrap), "NexusBootstrap"); + } + + /*////////////////////////////////////////////////////////////// + BYTECODES + //////////////////////////////////////////////////////////////*/ + + /* solhint-disable max-line-length */ + bytes public constant NEXUS_BYTECODE = + hex"6101606040523061014052348015610015575f5ffd5b50604051615904380380615904833981016040819052610034916101d4565b306080524660a05260608061007d6040805180820182526005808252644e6578757360d81b602080840191909152835180850190945290835264312e302e3160d81b9083015291565b815160209283012081519183019190912060c082905260e0819052604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8152938401929092529082015246606082015230608082015260a090206101005250506001600160a01b038116610107576040516307e355bf60e31b815260040160405180910390fd5b6001600160a01b0381166101205261011d610123565b50610201565b7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0061016d7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01610179565b61017681610179565b50565b60015f908152602082905260409020546001600160a01b0316156101b0576040516329e42f3360e11b815260040160405180910390fd5b60015f818152602092909252604090912080546001600160a01b0319169091179055565b5f602082840312156101e4575f5ffd5b81516001600160a01b03811681146101fa575f5ffd5b9392505050565b60805160a05160c05160e05161010051610120516101405161562d6102d75f395f818161111801526127d101525f818161062a01528181610adf01528181610d7201528181610eae01528181610ef90152818161125b0152818161156b0152818161161101528181611ae201528181611b320152818161209e0152818161211a0152818161232f01526138b101525f818161260c01526128c301525f81816126c6015261297d01525f81816126a0015261295701525f8181612650015261290701525f818161262d01526128e4015261562d5ff3fe6080604052600436106101db575f3560e01c80638dd7712f11610101578063cd64f80a11610094578063e9ae5c5311610063578063e9ae5c53146106f2578063ea5f61d014610705578063eab77e1714610724578063f2dc691d14610737576101e2565b8063cd64f80a14610681578063d03c791414610694578063d691c964146106b3578063d86f2b3c146106d3576101e2565b8063aaf10f42116100d0578063aaf10f4214610608578063b0d691fe1461061c578063b46b61a91461064e578063c399ec881461066d576101e2565b80638dd7712f146105845780639517e29f146105975780639cfd7cff146105aa578063a71763a8146105f5576101e2565b80634b6a1419116101795780635faac46b116101485780635faac46b146104f35780636575f6aa146105205780637b1039991461053f57806384b0196e1461055d576101e2565b80634b6a1419146104a65780634d44560d146104b95780634f1ef286146104cc57806352d1902d146104df576101e2565b806319822f7c116101b557806319822f7c146103a95780633644e515146103d6578063481ddd23146103ea5780634a58db191461049c576101e2565b80630a664dba14610311578063112d3a7d146103425780631626ba7e14610371576101e2565b366101e257005b5f3660605f6102055f5160206155a65f395f51905f52546001600160a01b031690565b90506001600160a01b0381166102265761021f8484610756565b9150610305565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f60259061025a9033903490869036906004016148ba565b5f604051808303815f875af1158015610275573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261029c9190810190614982565b90506102a88585610756565b9250604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906102d6908490600401614a2a565b5f604051808303815f87803b1580156102ed575f5ffd5b505af11580156102ff573d5f5f3e3d5ffd5b50505050505b50915050805190602001f35b34801561031c575f5ffd5b5061032561096f565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561034d575f5ffd5b5061036161035c366004614aa0565b610993565b6040519015158152602001610339565b34801561037c575f5ffd5b5061039061038b366004614af8565b6109ab565b6040516001600160e01b03199091168152602001610339565b3480156103b4575f5ffd5b506103c86103c3366004614b57565b610ad2565b604051908152602001610339565b3480156103e1575f5ffd5b506103c8610d67565b3480156103f5575f5ffd5b50610474610404366004614bb6565b6001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260209081526040918290208251808401909352546001600160a01b038116808452600160a01b90910460f81b6001600160f81b031916929091018290529091565b604080516001600160f81b031990931683526001600160a01b03909116602083015201610339565b6104a4610d70565b005b6104a46104b4366004614bd1565b610da4565b6104a46104c7366004614c04565b610ea3565b6104a46104da366004614c2e565b610f58565b3480156104ea575f5ffd5b506103c8611115565b3480156104fe575f5ffd5b5061051261050d366004614c04565b611172565b604051610339929190614c66565b34801561052b575f5ffd5b506103c861053a366004614cc5565b611198565b34801561054a575f5ffd5b505f54610325906001600160a01b031681565b348015610568575f5ffd5b506105716111a8565b6040516103399796959493929190614cdc565b6104a4610592366004614d76565b611250565b6104a46105a5366004614aa0565b611560565b3480156105b5575f5ffd5b50604080518082018252601481527f6269636f6e6f6d792e6e657875732e312e302e30000000000000000000000000602082015290516103399190614a2a565b6104a4610603366004614aa0565b611606565b348015610613575f5ffd5b50610325611907565b348015610627575f5ffd5b507f0000000000000000000000000000000000000000000000000000000000000000610325565b348015610659575f5ffd5b50610390610668366004614af8565b61193e565b348015610678575f5ffd5b506103c8611ade565b6104a461068f366004614c2e565b611b27565b34801561069f575f5ffd5b506103616106ae366004614cc5565b611d62565b6106c66106c1366004614af8565b611dd0565b6040516103399190614db8565b3480156106de575f5ffd5b506103c86106ed366004614e1b565b61204e565b6104a4610700366004614af8565b61210f565b348015610710575f5ffd5b5061051261071f366004614c04565b6122f6565b6104a4610732366004614e52565b612324565b348015610742575f5ffd5b50610361610751366004614cc5565b612383565b5f80356001600160e01b03191681527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260408120805460609291906001600160a01b03811690600160a01b900460f81b81156108d3576001600160f81b03198116607f60f91b0361082c57816001600160a01b03166107d888886123dd565b6040516107e59190614eed565b5f60405180830381855afa9150503d805f811461081d576040519150601f19603f3d011682016040523d82523d5f602084013e610822565b606091505b50955093506108c1565b6001600160f81b0319811661089757816001600160a01b03163461085089896123dd565b60405161085d9190614eed565b5f6040518083038185875af1925050503d805f811461081d576040519150601f19603f3d011682016040523d82523d5f602084013e610822565b604051632e5bf3f960e21b81526001600160f81b0319821660048201526024015b60405180910390fd5b836108ce57845160208601fd5b610965565b5f3560e01c63150b7a02811463f23a6e61821463bc197c81831417171561091257600194506040519550600486528060e01b6020870152602486016040525b6001600160e01b03195f351685610962576040517f08c63e270000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016108b8565b50505b5050505092915050565b5f61098e5f5160206155a65f395f51905f52546001600160a01b031690565b905090565b5f6109a085858585612412565b90505b949350505050565b5f8181036109e4576109c061ffff8319614f17565b6109cc90617739614f36565b84036109e4576109dd84848461193e565b9050610acb565b5f6109f26014828587614f4d565b6109fb91614f74565b60601c9050610a09816124d1565b8190610a345760405163342cf00f60e11b81526001600160a01b0390911660048201526024016108b8565b506001600160a01b03811663f551e2ee3387610a53876014818b614f4d565b6040518563ffffffff1660e01b8152600401610a7294939291906148ba565b602060405180830381865afa925050508015610aab575060408051601f3d908101601f19168201909252610aa891810190614fb4565b60015b610ac057506001600160e01b03199050610acb565b9150610acb9050565b505b9392505050565b5f81336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610b1d57604051635629665f60e11b815260040160405180910390fd5b5f602086013560401c6001600160a01b03169050600160f81b602087013560031a60f81b03610c4d575f610b508761501c565b9050610b6986610b646101008a018a61511c565b6124e9565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250505050610100820152610bab826124d1565b8290610bd65760405163342cf00f60e11b81526001600160a01b0390911660048201526024016108b8565b50604051639700320360e01b81526001600160a01b03831690639700320390610c059084908a9060040161515f565b6020604051808303815f875af1158015610c21573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c45919061522b565b935050610d4f565b610c56816124d1565b15610cd057604051639700320360e01b81526001600160a01b03821690639700320390610c899089908990600401615359565b6020604051808303815f875af1158015610ca5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cc9919061522b565b9250610d4f565b60015f525f5160206155865f395f51905f526020527ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7546001600160a01b0316610d2b57610cc9610d2561010088018861511c565b87612576565b60405163342cf00f60e11b81526001600160a01b03821660048201526024016108b8565b508015610ac9575f385f3884335af150509392505050565b5f61098e61260a565b7f00000000000000000000000000000000000000000000000000000000000000005f38818134855af1610da1575f38fd5b50565b333014610db357610db36126ff565b610dbb612738565b5f80610dc98385018561537a565b915091505f826001600160a01b031682604051610de69190614eed565b5f60405180830381855af49150503d805f8114610e1e576040519150601f19603f3d011682016040523d82523d5f602084013e610e23565b606091505b5050905080610e5e576040517f315927c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e66612778565b610e9c576040517fc4d0a0b100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480610ed957503330145b610ef657604051635629665f60e11b815260040160405180910390fd5b5f7f0000000000000000000000000000000000000000000000000000000000000000905060405183601452826034526f205c28780000000000000000000000005f525f38604460105f865af1610f4e573d5f823e3d81fd5b505f603452505050565b5f610f775f5160206155a65f395f51905f52546001600160a01b031690565b90506001600160a01b038116610fe4576001600160a01b038416610fae5760405163325c055b60e21b815260040160405180910390fd5b833b151580610fd05760405163325c055b60e21b815260040160405180910390fd5b843055610fde8585856127cf565b5061110f565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f6025906110189033903490869036906004016148ba565b5f604051808303815f875af1158015611033573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261105a9190810190614982565b90506001600160a01b0385166110835760405163325c055b60e21b815260040160405180910390fd5b843b1515806110a55760405163325c055b60e21b815260040160405180910390fd5b8530556110b38686866127cf565b50604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906110e0908490600401614a2a565b5f604051808303815f87803b1580156110f7575f5ffd5b505af1158015611109573d5f5f3e3d5ffd5b50505050505b50505050565b5f7f000000000000000000000000000000000000000000000000000000000000000030811461114b57639f03a0265f526004601cfd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91505090565b60605f61118d5f5160206155865f395f51905f5285856128a7565b909590945092505050565b5f6111a2826128c1565b92915050565b7f0f000000000000000000000000000000000000000000000000000000000000006060805f80808361123e60408051808201825260058082527f4e6578757300000000000000000000000000000000000000000000000000000060208084019190915283518085019094529083527f312e302e310000000000000000000000000000000000000000000000000000009083015291565b97989097965046955030945091925090565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461129957604051635629665f60e11b815260040160405180910390fd5b5f6112b85f5160206155a65f395f51905f52546001600160a01b031690565b90506001600160a01b0381166113c657365f6112d7606086018661511c565b6112e5916004908290614f4d565b915091505f5f306001600160a01b031684846040516113059291906153c7565b5f60405180830381855af49150503d805f811461133d576040519150601f19603f3d011682016040523d82523d5f602084013e611342565b606091505b5091509150811561138b577fd3fddfd1276d1cc278f10907710a44474a32f917b2fcfa198f46ca7689215e2f878260405161137e9291906153d6565b60405180910390a16113bd565b6040517facfdb44400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f6025906113fa9033903490869036906004016148ba565b5f604051808303815f875af1158015611415573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261143c9190810190614982565b9050365f61144d606087018761511c565b61145b916004908290614f4d565b915091505f5f306001600160a01b0316848460405161147b9291906153c7565b5f60405180830381855af49150503d805f81146114b3576040519150601f19603f3d011682016040523d82523d5f602084013e6114b8565b606091505b5091509150811561138b577fd3fddfd1276d1cc278f10907710a44474a32f917b2fcfa198f46ca7689215e2f88826040516114f49291906153d6565b60405180910390a15050604051630b9dfbed60e11b81526001600160a01b038516925063173bf7da915061152c908490600401614a2a565b5f604051808303815f87803b158015611543575f5ffd5b505af1158015611555573d5f5f3e3d5ffd5b50505050505b505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061159657503330145b6115b357604051635629665f60e11b815260040160405180910390fd5b6115bf848484846129d7565b604080518581526001600160a01b03851660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123910160405180910390a150505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061163c57503330145b61165957604051635629665f60e11b815260040160405180910390fd5b5f6116785f5160206155a65f395f51905f52546001600160a01b031690565b90506001600160a01b03811661175b5761169485858585612412565b858590916116c757604051635f300b3960e11b815260048101929092526001600160a01b031660248201526044016108b8565b5050604080518681526001600160a01b03861660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e910160405180910390a1600185036117225761171d848484612bbc565b610e9c565b600285036117355761171d848484612c8a565b600385036117485761171d848484612d23565b6004850361171d5761171d848484612e2a565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f60259061178f9033903490869036906004016148ba565b5f604051808303815f875af11580156117aa573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526117d19190810190614982565b90506117df86868686612412565b8686909161181257604051635f300b3960e11b815260048101929092526001600160a01b031660248201526044016108b8565b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e910160405180910390a16001860361186d57611868858585612bbc565b6118a6565b6002860361188057611868858585612c8a565b6003860361189357611868858585612d23565b600486036118a6576118a6858585612e2a565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906118d2908490600401614a2a565b5f604051808303815f87803b1580156118e9575f5ffd5b505af11580156118fb573d5f5f3e3d5ffd5b50505050505050505050565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b03811661193b575030545b90565b60015f9081525f5160206155865f395f51905f5260208190527ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7548291906001600160a01b03165b6001600160a01b038116158015906119a857506001600160a01b038116600114155b15611ab3576040517ff551e2ee0000000000000000000000000000000000000000000000000000000081525f906001600160a01b0383169063f551e2ee906119fa9033908c908c908c906004016148ba565b602060405180830381865afa158015611a15573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a399190614fb4565b90507fffff00000000000000000000000000000000000000000000000000000000000081167f7739000000000000000000000000000000000000000000000000000000000000148015611a9857506001600160e01b0319808516908216115b15611aa1578093505b611aab8383612e67565b915050611986565b50506001600160e01b0319811615611acb5780611ad5565b6001600160e01b03195b95945050505050565b5f5f7f00000000000000000000000000000000000000000000000000000000000000009050306020526370a082315f526020806024601c845afa601f3d11166020510291505090565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611b7057604051635629665f60e11b815260040160405180910390fd5b611b7d6004848484612412565b6004849091611bb157604051635f300b3960e11b815260048101929092526001600160a01b031660248201526044016108b8565b50505f611bc85f5160206155865f395f51905f5290565b6001600160a01b0385165f908152600482016020526040812054919250819003611c48576001600160a01b0385165f81815260048401602090815260409182902042908190558251938452908301527f2841d18703faaff388732165e48fe431468531b1b1e626b1b7cbcbfc0d79c74091015b60405180910390a1610e9c565b611c56620151806003614f36565b611c6090826153fa565b4210611cb9576001600160a01b0385165f81815260048401602090815260409182902042908190558251938452908301527fcbd44a75f6935b5837022648b6c8487db984701200c5381c7c0f8c2b1d69b9da9101611c3b565b611cc662015180826153fa565b4210611d30576001600160a01b0385165f908152600483016020526040812055611cf1858585612e2a565b60408051600481526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e9101611c3b565b6040517f07f2f2d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81600881901b6001600160f81b031982161580611d8d57506001600160f81b03198216600160f81b145b80611da157506001600160f81b0319808316145b80156109a357506001600160f81b0319811615806109a357506001600160f81b03198116600160f81b146109a3565b6060611dee335f5160206155865f395f51905f525b60010190612eba565b3390611e32576040517fb927fe5e0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016108b8565b505f611e525f5160206155a65f395f51905f52546001600160a01b031690565b90506001600160a01b038116611f0057336002611e6f8282612ef2565b86600881901b6001600160f81b03198216611e9657611e8f888883612f74565b9550611ef7565b6001600160f81b03198216600160f81b03611eb657611e8f8888836130c9565b6001600160f81b031980831603611ed257611e8f888883613142565b604051632e5bf3f960e21b81526001600160f81b0319831660048201526024016108b8565b50505050610ac9565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f602590611f349033903490869036906004016148ba565b5f604051808303815f875af1158015611f4f573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611f769190810190614982565b9050336002611f858282612ef2565b87600881901b6001600160f81b03198216611fac57611fa5898983612f74565b9650611fe8565b6001600160f81b03198216600160f81b03611fcc57611fa58989836130c9565b6001600160f81b031980831603611ed257611fa5898983613142565b5050604051630b9dfbed60e11b81526001600160a01b038516925063173bf7da9150612018908490600401614a2a565b5f604051808303815f87803b15801561202f575f5ffd5b505af1158015612041573d5f5f3e3d5ffd5b5050505050509392505050565b6040517f35567e1a00000000000000000000000000000000000000000000000000000000815230600482015277ffffffffffffffffffffffffffffffffffffffffffffffff821660248201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906335567e1a90604401602060405180830381865afa1580156120eb573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111a2919061522b565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461215857604051635629665f60e11b815260040160405180910390fd5b5f6121775f5160206155a65f395f51905f52546001600160a01b031690565b90506001600160a01b0381166121ef5783600881901b6001600160f81b031982166121ac576121a7858583613290565b6121e8565b6001600160f81b03198216600160f81b036121cc576121a785858361335c565b6001600160f81b031980831603611ed2576121a78585836133c9565b505061110f565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f6025906122239033903490869036906004016148ba565b5f604051808303815f875af115801561223e573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526122659190810190614982565b905084600881901b6001600160f81b0319821661228c57612287868683613290565b6122c8565b6001600160f81b03198216600160f81b036122ac5761228786868361335c565b6001600160f81b031980831603611ed2576122878686836133c9565b5050604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906110e0908490600401614a2a565b60605f61118d7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0185856128a7565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061235a57503330145b61237757604051635629665f60e11b815260040160405180910390fd5b61110f8484848461346d565b5f6001820361239457506001919050565b600282036123a457506001919050565b600382036123b457506001919050565b600482036123c457506001919050565b816123d157506001919050565b505f919050565b919050565b6060604080513681016020019091529050601436018152365f602083013760408051601481019091523360601b905292915050565b5f6001850361242b57612424846124d1565b90506109a3565b6002850361243c576124248461353f565b600385036124b9575f6004831061246a5761245a60045f8587614f4d565b6124639161540d565b905061246d565b505f5b6001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260409020546001600160a01b0385811691161490506109a3565b600485036124ca5761242484613557565b505f6109a3565b5f6111a25f5160206155865f395f51905f5283612eba565b365f5f5f365f365f6124fb8a8a613590565b909e509c50949a5092985090965094509250905061252661251f87878e88886135e4565b8383613679565b61255c576040517f46fdc33300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612568858786866129d7565b505050505050935093915050565b5f5f6125e46125a9846020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c60042090565b86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061378d92505050565b9050306001600160a01b038216036125ff575f915050610acb565b506001949350505050565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030147f000000000000000000000000000000000000000000000000000000000000000046141661193b5750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f000000000000000000000000000000000000000000000000000000000000000060208201527f00000000000000000000000000000000000000000000000000000000000000009181019190915246606082015230608082015260a0902090565b7f90b772c2cb8a51aa7a8a65fc23543c6d022d5b3f8e2b92eed79fba7eef829300805c806127345763aed595955f526004601cfd5b5050565b5f5160206155865f395f51905f5261276f7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01613832565b610da181613832565b5f6001612794815f5160206155865f395f51905f525b90612e67565b6001600160a01b03161415801561098e57505f6127bf60015f5160206155865f395f51905f5261278e565b6001600160a01b03161415905090565b7f000000000000000000000000000000000000000000000000000000000000000030810361280457639f03a0265f526004601cfd5b61280d846138a6565b8360601b60601c93506352d1902d6001527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80602060016004601d895afa511461285f576355299b496001526004601dfd5b847fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f38a2849055811561110f57604051828482375f388483885af4610e9c573d5f823e3d81fd5b60605f6128b58585856138f9565b90969095509350505050565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030147f00000000000000000000000000000000000000000000000000000000000000004614166129b45750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f000000000000000000000000000000000000000000000000000000000000000060208201527f00000000000000000000000000000000000000000000000000000000000000009181019190915246606082015230608082015260a090205b6719010000000000005f5280601a5281603a52604260182090505f603a52919050565b5f6129f65f5160206155a65f395f51905f52546001600160a01b031690565b90506001600160a01b038116612aa5576001600160a01b038416612a2d57604051635316c18d60e01b815260040160405180910390fd5b60018503612a405761171d848484613aba565b60028503612a535761171d848484613b93565b60038503612a665761171d848484613c51565b60048503612a795761171d848484613fa5565b84612a895761171d8484846140fc565b6040516304c1896960e11b8152600481018690526024016108b8565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f602590612ad99033903490869036906004016148ba565b5f604051808303815f875af1158015612af4573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612b1b9190810190614982565b90506001600160a01b038516612b4457604051635316c18d60e01b815260040160405180910390fd5b60018603612b5757611868858585613aba565b60028603612b6a57611868858585613b93565b60038603612b7d57611868858585613c51565b60048603612b9057611868858585613fa5565b85612ba0576118688585856140fc565b6040516304c1896960e11b8152600481018790526024016108b8565b5f5160206155865f395f51905f525f80612bd88585018661537a565b9092509050612be8838388614255565b612bf0612778565b612c26576040517fcc319d8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115555a5f5f638a91b0e360e01b85604051602401612c459190614a2a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b038b1693929190614328565b5f80612c988385018561537a565b91509150612cbf8286612cb55f5160206155865f395f51905f5290565b6001019190614255565b6113bd5a5f5f638a91b0e360e01b85604051602401612cde9190614a2a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b038a1693929190614328565b604080518082019091525f80825260208201525f5160206155865f395f51905f526002015f612d556004828688614f4d565b612d5e9161540d565b6001600160e01b03191681526020808201929092526040015f2082518154939092015160f81c600160a01b0274ffffffffffffffffffffffffffffffffffffffffff199093166001600160a01b0390921691909117919091179055610e9c5a5f80638a91b0e360e01b612dd4866004818a614f4d565b604051602401612de5929190615442565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b03881693929190614328565b5f5160206155a65f395f51905f5280546001600160a01b0319169055610e9c5a5f5f638a91b0e360e01b8686604051602401612de5929190615442565b5f6001600160a01b038216612e9a57604051637c84ecfb60e01b81526001600160a01b03831660048201526024016108b8565b506001600160a01b039081165f9081526020929092526040909120541690565b5f60016001600160a01b03831614801590610acb5750506001600160a01b039081165f90815260209290925260409091205416151590565b5f546001600160a01b0316801561155b576040517f96fb72170000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490528216906396fb7217906044015f6040518083038186803b158015612f62575f5ffd5b505afa1580156113bd573d5f5f3e3d5ffd5b60605f5f365f612f8488886143ae565b6040805160018082528183019092529498509296509094509250816020015b6060815260200190600190039081612fa357509095505f90506001600160f81b03198716612ff957612fd7858585856143fe565b865f81518110612fe957612fe9615455565b60200260200101819052506130bd565b6001600160f81b03198716600160f81b036130985761301a85858585614431565b875f8151811061302c5761302c615455565b6020908102919091010152905080613093577fb5282692b8c578af7fb880895d599035496b5e64d1f14bf428a1ed3bc406f6628383885f8151811061307357613073615455565b602002602001015160405161308a93929190615469565b60405180910390a15b6130bd565b6040516308c3ee0360e11b81526001600160f81b0319881660048201526024016108b8565b50505050509392505050565b6060833584016020810190356001600160f81b031984166130f5576130ee828261445f565b9250613139565b6001600160f81b03198416600160f81b03613114576130ee8282614535565b6040516308c3ee0360e11b81526001600160f81b0319851660048201526024016108b8565b50509392505050565b60605f365f613151878761466c565b6040805160018082528183019092529396509194509250816020015b606081526020019060019003908161316d57509094505f90506001600160f81b031986166131c2576131a08484846146a2565b855f815181106131b2576131b2615455565b6020026020010181905250613285565b6001600160f81b03198616600160f81b03613260576131e28484846146d3565b865f815181106131f4576131f4615455565b602090810291909101015290508061325b577f5bd4c60b4b38b664d8fb5944eb974e3d85083d79afe5ce934ccabcc913707c108383875f8151811061323b5761323b615455565b602002602001015160405161325293929190615469565b60405180910390a15b613285565b6040516308c3ee0360e11b81526001600160f81b0319871660048201526024016108b8565b505050509392505050565b5f5f365f61329e87876143ae565b929650909450925090506001600160f81b031985166132c8576132c3848484846146ff565b6113bd565b6001600160f81b03198516600160f81b03613337575f5f6132eb86868686614431565b9150915081613330577fb5282692b8c578af7fb880895d599035496b5e64d1f14bf428a1ed3bc406f66284848360405161332793929190615469565b60405180910390a15b50506113bd565b6040516308c3ee0360e11b81526001600160f81b0319861660048201526024016108b8565b823583016020810190356001600160f81b0319831661337f5761171d8282614723565b6001600160f81b03198316600160f81b036133a45761339e8282614535565b50610e9c565b6040516308c3ee0360e11b81526001600160f81b0319841660048201526024016108b8565b5f365f6133d6868661466c565b919450925090506001600160f81b031984166133fc576133f7838383614783565b613465565b6001600160f81b03198416600160f81b03613114575f5f61341e8585856146d3565b9150915081611555577f5bd4c60b4b38b664d8fb5944eb974e3d85083d79afe5ce934ccabcc913707c1084848360405161345a93929190615469565b60405180910390a150505b505050505050565b5f80546001600160a01b0319166001600160a01b03861690811790915515613506576040517ff05c04e10000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063f05c04e1906134d89084908790879060040161548e565b5f604051808303815f87803b1580156134ef575f5ffd5b505af1158015613501573d5f5f3e3d5ffd5b505050505b6040516001600160a01b038516907ff98c8404c5b1bfef2e6ba9233c6e88845aedfd36eea8b192725d8c199571cf32905f90a250505050565b5f6111a2825f5160206155865f395f51905f52611de5565b5f816001600160a01b03166135805f5160206155a65f395f51905f52546001600160a01b031690565b6001600160a01b03161492915050565b813560601c6014830135603880850190603486013560e090811c91603c838901818101939281013590921c9136915f9184018b9003016135d28a82818e614f4d565b92509250509295985092959890939650565b5f6040518060800160405280605b81526020016155c6605b91398051906020012086868686866040516136189291906153c7565b60405190819003812061365895949392916020019485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b60405160208183030381529060405280519060200120905095945050505050565b5f806136886014828587614f4d565b61369191614f74565b60601c905061369f816124d1565b6136c75760405163342cf00f60e11b81526001600160a01b03821660048201526024016108b8565b5f6136d1866128c1565b90506001600160a01b03821663f551e2ee30836136f1886014818c614f4d565b6040518563ffffffff1660e01b815260040161371094939291906148ba565b602060405180830381865afa925050508015613749575060408051601f3d908101601f1916820190925261374691810190614fb4565b60015b613757575f92505050610acb565b6001600160e01b0319167f1626ba7e00000000000000000000000000000000000000000000000000000000149250610acb915050565b5f6040518251604081146137a957604181146137e3575061381e565b604084015160ff81901c601b016020527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166060526137f6565b60608401515f1a60205260408401516060525b50835f5260208301516040526020600160805f60015afa5191505f606052806040523d61382b575b638baa579f5f526004601cfd5b5092915050565b60015f908152602082905260409020546001600160a01b031615613882576040517f53c85e6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015f818152602092909252604090912080546001600160a01b0319169091179055565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806138dc57503330145b610da157604051635629665f60e11b815260040160405180910390fd5b60605f6001600160a01b03841660011480159061391d575061391b8585612eba565b155b1561394657604051637c84ecfb60e01b81526001600160a01b03851660048201526024016108b8565b825f0361397f576040517ff725081700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8267ffffffffffffffff811115613998576139986148ec565b6040519080825280602002602001820160405280156139c1578160200160208202803683370190505b506001600160a01b038086165f90815260208890526040812054929450911691505b6001600160a01b03821615801590613a0557506001600160a01b038216600114155b8015613a1057508381105b15613a695781838281518110613a2857613a28615455565b6001600160a01b039283166020918202929092018101919091529281165f908152928790526040909220549091169080613a61816154e5565b9150506139e3565b6001600160a01b038216600114801590613a8257505f81115b15613aae5782613a936001836154fd565b81518110613aa357613aa3615455565b602002602001015191505b80835250935093915050565b826001613ac78282612ef2565b60405163ecd0596160e01b8152600160048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015613b0a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b2e9190615510565b613b4e576040516369c9a24560e11b8152600160048201526024016108b8565b613b655f5160206155865f395f51905f52866147a5565b6040516306d61fe760e41b81526001600160a01b03861690636d61fe70906110e09087908790600401615442565b826002613ba08282612ef2565b60405163ecd0596160e01b8152600260048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015613be3573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613c079190615510565b613c27576040516369c9a24560e11b8152600260048201526024016108b8565b613b657f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01866147a5565b826003613c5e8282612ef2565b60405163ecd0596160e01b8152600360048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015613ca1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613cc59190615510565b613ce5576040516369c9a24560e11b8152600360048201526024016108b8565b5f613cf36004828688614f4d565b613cfc9161540d565b90505f85856004818110613d1257613d12615455565b909101356001600160f81b031916915050801580613d3d57506001600160f81b03198116607f60f91b145b613d73576040517f867a1dcf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613d81866005818a614f4d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152509293505050506001600160e01b031983166306d61fe760e41b1480613de657506001600160e01b03198316638a91b0e360e01b145b80613df957506001600160e01b03198316155b15613e30576040517fc001660b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160e01b031983165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f02602052604090205483906001600160a01b031615613eb7576040517fa56a04dd0000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016108b8565b506040805180820182526001600160a01b038a81168083526001600160f81b0319861660208085019182526001600160e01b031989165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0290915285902093518454915160f81c600160a01b0274ffffffffffffffffffffffffffffffffffffffffff199092169316929092179190911790915590516306d61fe760e41b8152636d61fe7090613f6e908490600401614a2a565b5f604051808303815f87803b158015613f85575f5ffd5b505af1158015613f97573d5f5f3e3d5ffd5b505050505050505050505050565b826004613fb28282612ef2565b60405163ecd0596160e01b81526004808201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015613ff4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906140189190615510565b614037576040516369c9a24560e11b81526004818101526024016108b8565b5f6140565f5160206155a65f395f51905f52546001600160a01b031690565b9050806001600160a01b038116156140a6576040517f741cbe030000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016108b8565b505f5160206155a65f395f51905f5280546001600160a01b0319166001600160a01b0388161790556040516306d61fe760e41b81526001600160a01b03871690636d61fe70906118d29088908890600401615442565b81358201602081810191359084810135850190810190358281811461414d576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b81811015611109575f86868381811061416a5761416a615455565b905060200201359050600181036141ad576141a88a86868581811061419157614191615455565b90506020028101906141a3919061511c565b613aba565b61424c565b600281036141e2576141a88a8686858181106141cb576141cb615455565b90506020028101906141dd919061511c565b613b93565b60038103614217576141a88a86868581811061420057614200615455565b9050602002810190614212919061511c565b613c51565b6004810361424c5761424c8a86868581811061423557614235615455565b9050602002810190614247919061511c565b613fa5565b5060010161414f565b6001600160a01b038116158061427457506001600160a01b0381166001145b1561429d57604051637c84ecfb60e01b81526001600160a01b03831660048201526024016108b8565b6001600160a01b038281165f908152602085905260409020548116908216146142e457604051637c84ecfb60e01b81526001600160a01b03821660048201526024016108b8565b6001600160a01b039081165f8181526020949094526040808520805494841686529085208054949093166001600160a01b0319948516179092559092528154169055565b5f60605f5f5f8661ffff1667ffffffffffffffff81111561434b5761434b6148ec565b6040519080825280601f01601f191660200182016040528015614375576020820181803683370190505b5090505f5f8751602089018b8e8ef191503d925086831115614395578692505b828152825f602083013e90999098509650505050505050565b5f8036816143bf6014828789614f4d565b6143c891614f74565b60601c93506143db603460148789614f4d565b6143e49161552f565b92506143f38560348189614f4d565b949793965094505050565b604051818382375f38838387895af1614419573d5f823e3d81fd5b3d8152602081013d5f823e3d01604052949350505050565b6040515f90828482375f388483888a5af191503d8152602081013d5f823e3d81016040525094509492505050565b60608167ffffffffffffffff81111561447a5761447a6148ec565b6040519080825280602002602001820160405280156144ad57816020015b60608152602001906001900390816144985790505b509050365f5b8381101561452d578484828181106144cd576144cd615455565b90506020028101906144df919061554c565b91506145086144f1602084018461556a565b6020840135614503604086018661511c565b6143fe565b83828151811061451a5761451a615455565b60209081029190910101526001016144b3565b505092915050565b60608167ffffffffffffffff811115614550576145506148ec565b60405190808252806020026020018201604052801561458357816020015b606081526020019060019003908161456e5790505b509050365f5b8381101561452d578484828181106145a3576145a3615455565b90506020028101906145b5919061554c565b91505f6145df6145c8602085018561556a565b60208501356145da604087018761511c565b614431565b8584815181106145f1576145f1615455565b6020908102919091010152905080614663577fb5282692b8c578af7fb880895d599035496b5e64d1f14bf428a1ed3bc406f662614631604085018561511c565b86858151811061464357614643615455565b602002602001015160405161465a93929190615469565b60405180910390a15b50600101614589565b5f368161467c6014828688614f4d565b61468591614f74565b60601c92506146978460148188614f4d565b915091509250925092565b604051818382375f388383875af46146bc573d5f823e3d81fd5b3d8152602081013d5f823e3d016040529392505050565b6040515f90828482375f388483885af491503d8152602081013d5f823e3d810160405250935093915050565b604051818382375f38838387895af161471a573d5f823e3d81fd5b01604052505050565b365f5b8281101561110f5783838281811061474057614740615455565b9050602002810190614752919061554c565b915061477b614764602084018461556a565b6020840135614776604086018661511c565b6146ff565b600101614726565b604051818382375f388383875af461479d573d5f823e3d81fd5b016040525050565b6001600160a01b03811615806147c457506001600160a01b0381166001145b156147ed57604051637c84ecfb60e01b81526001600160a01b03821660048201526024016108b8565b6001600160a01b038181165f908152602084905260409020541615614849576040517f40d3d1a40000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108b8565b60015f818152602093909352604080842080546001600160a01b039485168087529286208054959091166001600160a01b03199586161790559190935280549091169091179055565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b0385168152836020820152606060408201525f6148e2606083018486614892565b9695505050505050565b634e487b7160e01b5f52604160045260245ffd5b604051610120810167ffffffffffffffff81118282101715614924576149246148ec565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614953576149536148ec565b604052919050565b5f67ffffffffffffffff821115614974576149746148ec565b50601f01601f191660200190565b5f60208284031215614992575f5ffd5b815167ffffffffffffffff8111156149a8575f5ffd5b8201601f810184136149b8575f5ffd5b80516149cb6149c68261495b565b61492a565b8181528560208385010111156149df575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610acb60208301846149fc565b6001600160a01b0381168114610da1575f5ffd5b80356123d881614a3c565b5f5f83601f840112614a6b575f5ffd5b50813567ffffffffffffffff811115614a82575f5ffd5b602083019150836020828501011115614a99575f5ffd5b9250929050565b5f5f5f5f60608587031215614ab3575f5ffd5b843593506020850135614ac581614a3c565b9250604085013567ffffffffffffffff811115614ae0575f5ffd5b614aec87828801614a5b565b95989497509550505050565b5f5f5f60408486031215614b0a575f5ffd5b83359250602084013567ffffffffffffffff811115614b27575f5ffd5b614b3386828701614a5b565b9497909650939450505050565b5f6101208284031215614b51575f5ffd5b50919050565b5f5f5f60608486031215614b69575f5ffd5b833567ffffffffffffffff811115614b7f575f5ffd5b614b8b86828701614b40565b9660208601359650604090950135949350505050565b6001600160e01b031981168114610da1575f5ffd5b5f60208284031215614bc6575f5ffd5b8135610acb81614ba1565b5f5f60208385031215614be2575f5ffd5b823567ffffffffffffffff811115614bf8575f5ffd5b6128b585828601614a5b565b5f5f60408385031215614c15575f5ffd5b8235614c2081614a3c565b946020939093013593505050565b5f5f5f60408486031215614c40575f5ffd5b8335614c4b81614a3c565b9250602084013567ffffffffffffffff811115614b27575f5ffd5b604080825283519082018190525f9060208501906060840190835b81811015614ca85783516001600160a01b0316835260209384019390920191600101614c81565b505080925050506001600160a01b03831660208301529392505050565b5f60208284031215614cd5575f5ffd5b5035919050565b6001600160f81b03198816815260e060208201525f614cfe60e08301896149fc565b8281036040840152614d1081896149fc565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015614d65578351835260209384019390920191600101614d47565b50909b9a5050505050505050505050565b5f5f60408385031215614d87575f5ffd5b823567ffffffffffffffff811115614d9d575f5ffd5b614da985828601614b40565b95602094909401359450505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015614e0f57603f19878603018452614dfa8583516149fc565b94506020938401939190910190600101614dde565b50929695505050505050565b5f60208284031215614e2b575f5ffd5b813577ffffffffffffffffffffffffffffffffffffffffffffffff81168114610acb575f5ffd5b5f5f5f5f60608587031215614e65575f5ffd5b8435614e7081614a3c565b9350602085013567ffffffffffffffff811115614e8b575f5ffd5b8501601f81018713614e9b575f5ffd5b803567ffffffffffffffff811115614eb1575f5ffd5b8760208260051b8401011115614ec5575f5ffd5b60209190910193509150604085013560ff81168114614ee2575f5ffd5b939692955090935050565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52601160045260245ffd5b5f82614f3157634e487b7160e01b5f52601260045260245ffd5b500490565b80820281158282048414176111a2576111a2614f03565b5f5f85851115614f5b575f5ffd5b83861115614f67575f5ffd5b5050820193919092039150565b80356bffffffffffffffffffffffff19811690601484101561382b576bffffffffffffffffffffffff1960149490940360031b84901b1690921692915050565b5f60208284031215614fc4575f5ffd5b8151610acb81614ba1565b5f82601f830112614fde575f5ffd5b8135614fec6149c68261495b565b818152846020838601011115615000575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f610120823603121561502d575f5ffd5b615035614900565b61503e83614a50565b815260208381013590820152604083013567ffffffffffffffff811115615063575f5ffd5b61506f36828601614fcf565b604083015250606083013567ffffffffffffffff81111561508e575f5ffd5b61509a36828601614fcf565b6060830152506080838101359082015260a0808401359082015260c0808401359082015260e083013567ffffffffffffffff8111156150d7575f5ffd5b6150e336828601614fcf565b60e08301525061010083013567ffffffffffffffff811115615103575f5ffd5b61510f36828601614fcf565b6101008301525092915050565b5f5f8335601e19843603018112615131575f5ffd5b83018035915067ffffffffffffffff82111561514b575f5ffd5b602001915036819003821315614a99575f5ffd5b604081526151796040820184516001600160a01b03169052565b602083015160608201525f6040840151610120608084015261519f6101608401826149fc565b90506060850151603f198483030160a08501526151bc82826149fc565b915050608085015160c084015260a085015160e084015260c085015161010084015260e0850151603f19848303016101208501526151fa82826149fc565b915050610100850151603f198483030161014085015261521a82826149fc565b925050508260208301529392505050565b5f6020828403121561523b575f5ffd5b5051919050565b5f5f8335601e19843603018112615257575f5ffd5b830160208101925035905067ffffffffffffffff811115615276575f5ffd5b803603821315614a99575f5ffd5b61529e8261529183614a50565b6001600160a01b03169052565b602081810135908301525f6152b66040830183615242565b61012060408601526152cd61012086018284614892565b9150506152dd6060840184615242565b85830360608701526152f0838284614892565b6080868101359088015260a0808701359088015260c08087013590880152925061532091505060e0840184615242565b85830360e0870152615333838284614892565b92505050615345610100840184615242565b8583036101008701526148e2838284614892565b604081525f61536b6040830185615284565b90508260208301529392505050565b5f5f6040838503121561538b575f5ffd5b823561539681614a3c565b9150602083013567ffffffffffffffff8111156153b1575f5ffd5b6153bd85828601614fcf565b9150509250929050565b818382375f9101908152919050565b604081525f6153e86040830185615284565b8281036020840152611ad581856149fc565b808201808211156111a2576111a2614f03565b80356001600160e01b0319811690600484101561382b576001600160e01b0319808560040360031b1b82161691505092915050565b602081525f6109a3602083018486614892565b634e487b7160e01b5f52603260045260245ffd5b604081525f61547c604083018587614892565b82810360208401526148e281856149fc565b60ff8416815260406020820181905281018290525f8360608301825b858110156154da5782356154bd81614a3c565b6001600160a01b03168252602092830192909101906001016154aa565b509695505050505050565b5f600182016154f6576154f6614f03565b5060010190565b818103818111156111a2576111a2614f03565b5f60208284031215615520575f5ffd5b81518015158114610acb575f5ffd5b803560208310156111a2575f19602084900360031b1b1692915050565b5f8235605e19833603018112615560575f5ffd5b9190910192915050565b5f6020828403121561557a575f5ffd5b8135610acb81614a3c56fe0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f000bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f034d6f64756c65456e61626c654d6f64652861646472657373206d6f64756c652c75696e74323536206d6f64756c65547970652c6279746573333220757365724f70486173682c6279746573333220696e6974446174614861736829a164736f6c634300081b000a"; + bytes public constant NEXUS_ACCOUNT_FACTORY_BYTECODE = + hex"60a060405234801561000f575f5ffd5b50604051610fe5380380610fe583398101604081905261002e916100f1565b8061003881610099565b506001600160a01b03821661006057604051630abd577760e01b815260040160405180910390fd5b6001600160a01b038116610087576040516342bcdf7f60e11b815260040160405180910390fd5b506001600160a01b0316608052610122565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b80516001600160a01b03811681146100ec575f5ffd5b919050565b5f5f60408385031215610102575f5ffd5b61010b836100d6565b9150610119602084016100d6565b90509250929050565b608051610e9e6101475f395f818160ed015281816104a801526105ca0152610e9e5ff3fe6080604052600436106100ce575f3560e01c80638da5cb5b1161007c578063f04e283e11610057578063f04e283e146101b8578063f2fde38b146101cb578063fafa2b42146101de578063fee81cf4146101fd575f5ffd5b80638da5cb5b1461016e578063b36f970514610186578063ea6d13ac146101a5575f5ffd5b80634a1ce599116100ac5780634a1ce5991461013f57806354d1f13d1461015e578063715018a614610166575f5ffd5b806325692962146100d2578063290ab984146100dc578063451711591461012c575b5f5ffd5b6100da61023c565b005b3480156100e7575f5ffd5b5061010f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6100da61013a366004610913565b610289565b34801561014a575f5ffd5b506100da610159366004610952565b610332565b6100da6103b2565b6100da6103eb565b348015610179575f5ffd5b50638b78c6d8195461010f565b348015610191575f5ffd5b506100da6101a0366004610974565b6103fe565b61010f6101b33660046109a0565b6104a0565b6100da6101c6366004610952565b610561565b6100da6101d9366004610952565b61059e565b3480156101e9575f5ffd5b5061010f6101f83660046109a0565b6105c4565b348015610208575f5ffd5b5061022e610217366004610952565b63389a75e1600c9081525f91909152602090205490565b604051908152602001610123565b5f6202a30067ffffffffffffffff164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f5fa250565b61029161062d565b6001600160a01b0382166102b8576040516391fdf19160e01b815260040160405180910390fd5b6040517f0396cb6000000000000000000000000000000000000000000000000000000000815263ffffffff821660048201526001600160a01b03831690630396cb609034906024015f604051808303818588803b158015610317575f5ffd5b505af1158015610329573d5f5f3e3d5ffd5b50505050505050565b61033a61062d565b6001600160a01b038116610361576040516391fdf19160e01b815260040160405180910390fd5b806001600160a01b031663bb9fe6bf6040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610399575f5ffd5b505af11580156103ab573d5f5f3e3d5ffd5b5050505050565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f5fa2565b6103f361062d565b6103fc5f610647565b565b61040661062d565b6001600160a01b03821661042d576040516391fdf19160e01b815260040160405180910390fd5b6040517fc23a5cea0000000000000000000000000000000000000000000000000000000081526001600160a01b03828116600483015283169063c23a5cea906024015f604051808303815f87803b158015610486575f5ffd5b505af1158015610498573d5f5f3e3d5ffd5b505050505050565b5f5f5f6105037f00000000000000000000000000000000000000000000000000000000000000008588888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061068492505050565b91509150816105585783868660405161051d929190610a12565b604051908190038120906001600160a01b038416907f47e5b5fc3bda028416e26dcf66ca5186488c0717e8ab55bb01806113f1839d58905f90a45b95945050505050565b61056961062d565b63389a75e1600c52805f526020600c20805442111561058f57636f5e88185f526004601cfd5b5f905561059b81610647565b50565b6105a661062d565b8060601b6105bb57637448fbae5f526004601cfd5b61059b81610647565b5f6106257f00000000000000000000000000000000000000000000000000000000000000008386868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506107c792505050565b949350505050565b638b78c6d8195433146103fc576382b429005f526004601cfd5b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b5f5f6106918585856107c7565b90505f816001600160a01b03163b1191508161073457833486856040516024016106bb9190610a4f565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16634b6a141960e01b17905251610704906108f2565b61070f929190610a61565b82906040518091039083f59150508015801561072d573d5f5f3e3d5ffd5b50506107bf565b5f816001600160a01b0316346040515f6040518083038185875af1925050503d805f811461077d576040519150601f19603f3d011682016040523d82523d5f602084013e610782565b606091505b50509050806107bd576040517f6d963f8800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b935093915050565b5f5f604051806020016107d9906108f2565b6020820181038252601f19601f8201166040525085846040516024016107ff9190610a4f565b60408051601f19818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16634b6a141960e01b179052905161084d93929101610a61565b60408051601f198184030181529082905261086b9291602001610a99565b60408051601f1981840301815282825280516020918201207fff00000000000000000000000000000000000000000000000000000000000000828501523060601b6bffffffffffffffffffffffff19166021850152603584019790975260558084019790975281518084039097018752607590920190528451940193909320949350505050565b6103e480610aae83390190565b6001600160a01b038116811461059b575f5ffd5b5f5f60408385031215610924575f5ffd5b823561092f816108ff565b9150602083013563ffffffff81168114610947575f5ffd5b809150509250929050565b5f60208284031215610962575f5ffd5b813561096d816108ff565b9392505050565b5f5f60408385031215610985575f5ffd5b8235610990816108ff565b91506020830135610947816108ff565b5f5f5f604084860312156109b2575f5ffd5b833567ffffffffffffffff8111156109c8575f5ffd5b8401601f810186136109d8575f5ffd5b803567ffffffffffffffff8111156109ee575f5ffd5b8660208284010111156109ff575f5ffd5b6020918201979096509401359392505050565b818382375f9101908152919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61096d6020830184610a21565b6001600160a01b0383168152604060208201525f6106256040830184610a21565b5f81518060208401855e5f93019283525090919050565b5f610625610aa78386610a82565b84610a8256fe60806040526040516103e43803806103e48339810160408190526100229161026c565b61002a61003b565b6100348282610063565b5050610351565b7f90b772c2cb8a51aa7a8a65fc23543c6d022d5b3f8e2b92eed79fba7eef8293006001815d50565b61006c826100c1565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156100b5576100b0828261013c565b505050565b6100bd6101af565b5050565b806001600160a01b03163b5f036100fb57604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f5f846001600160a01b031684604051610158919061033b565b5f60405180830381855af49150503d805f8114610190576040519150601f19603f3d011682016040523d82523d5f602084013e610195565b606091505b5090925090506101a68583836101d0565b95945050505050565b34156101ce5760405163b398979f60e01b815260040160405180910390fd5b565b6060826101e5576101e08261022f565b610228565b81511580156101fc57506001600160a01b0384163b155b1561022557604051639996b31560e01b81526001600160a01b03851660048201526024016100f2565b50805b9392505050565b80511561023f5780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b634e487b7160e01b5f52604160045260245ffd5b5f5f6040838503121561027d575f5ffd5b82516001600160a01b0381168114610293575f5ffd5b60208401519092506001600160401b038111156102ae575f5ffd5b8301601f810185136102be575f5ffd5b80516001600160401b038111156102d7576102d7610258565b604051601f8201601f19908116603f011681016001600160401b038111828210171561030557610305610258565b60405281815282820160200187101561031c575f5ffd5b8160208401602083015e5f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b60878061035d5f395ff3fe6080604052600a600c565b005b60186014601a565b605d565b565b5f60587f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b905090565b365f5f375f5f365f845af43d5f5f3e8080156076573d5ff35b3d5ffdfea164736f6c634300081b000aa164736f6c634300081b000a"; + bytes public constant NEXUS_BOOTSTRAP_BYTECODE = + hex"610120604052348015600f575f5ffd5b50306080524660a0526060806061604080518082018252600e81526d04e65787573426f6f7473747261760941b602080830191909152825180840190935260058352640312e302e360dc1b9083015291565b815160209283012081519183019190912060c082905260e0819052604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8152938401929092529082015246606082015230608082015260a09020610100525060c99050565b60805160a05160c05160e051610100516122b36100f75f395f50505f50505f50505f50505f50506122b35ff3fe6080604052600436106100ca575f3560e01c8063837b892e116100735780639e2533ed1161004d5780639e2533ed1461040d578063d6fe71f11461042c578063ea5f61d01461043f576100d1565b8063837b892e1461039b57806384b0196e146103c757806385a924cc146103ee576100d1565b806355470cf1116100a457806355470cf11461033d5780635faac46b146103505780637b1039991461037d576100d1565b806301fe9ff2146102455780630a664dba1461025a578063481ddd231461028b576100d1565b366100d157005b5f3660605f6101077f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03546001600160a01b031690565b90506001600160a01b03811661012857610121848461045e565b9150610239565b6040517fd68f60250000000000000000000000000000000000000000000000000000000081525f906001600160a01b0383169063d68f60259061017590339034908690369060040161188d565b5f604051808303815f875af1158015610190573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526101b791908101906118d3565b90506101c3858561045e565b92506040517f173bf7da0000000000000000000000000000000000000000000000000000000081526001600160a01b0383169063173bf7da9061020a9084906004016119b4565b5f604051808303815f87803b158015610221575f5ffd5b505af1158015610233573d5f5f3e3d5ffd5b50505050505b50915050805190602001f35b610258610253366004611a45565b61068e565b005b348015610265575f5ffd5b5061026e6106ae565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610296575f5ffd5b506103156102a5366004611b16565b6001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260209081526040918290208251808401909352546001600160a01b038116808452600160a01b90910460f81b6001600160f81b031916929091018290529091565b604080516001600160f81b031990931683526001600160a01b03909116602083015201610282565b61025861034b366004611b53565b6106e5565b34801561035b575f5ffd5b5061036f61036a366004611bc7565b6107ae565b604051610282929190611bf1565b348015610388575f5ffd5b505f5461026e906001600160a01b031681565b3480156103a6575f5ffd5b506103ba6103b5366004611c50565b6107e7565b60405161028291906119b4565b3480156103d2575f5ffd5b506103db61087c565b6040516102829796959493929190611cdd565b3480156103f9575f5ffd5b506103ba610408366004611b53565b610924565b348015610418575f5ffd5b506103ba610427366004611d77565b6109ad565b61025861043a366004611d77565b610a42565b34801561044a575f5ffd5b5061036f610459366004611bc7565b610c6e565b5f80356001600160e01b03191681527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260408120805460609291906001600160a01b03811690600160a01b900460f81b81156105f2576104c581607f60f91b610c9c565b1561053257816001600160a01b03166104de8888610cb3565b6040516104eb9190611e90565b5f60405180830381855afa9150503d805f8114610523576040519150601f19603f3d011682016040523d82523d5f602084013e610528565b606091505b50955093506105e0565b61053c815f610c9c565b1561059d57816001600160a01b0316346105568989610cb3565b6040516105639190611e90565b5f6040518083038185875af1925050503d805f8114610523576040519150601f19603f3d011682016040523d82523d5f602084013e610528565b6040517fb96fcfe40000000000000000000000000000000000000000000000000000000081526001600160f81b0319821660048201526024015b60405180910390fd5b836105ed57845160208601fd5b610684565b5f3560e01c63150b7a02811463f23a6e61821463bc197c81831417171561063157600194506040519550600486528060e01b6020870152602486016040525b6001600160e01b03195f351685610681576040517f08c63e270000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016105d7565b50505b5050505092915050565b61069a84848484610ce8565b6106a5878787610dc7565b50505050505050565b5f6106e07f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03546001600160a01b031690565b905090565b6106f184848484610ce8565b5f5b8681101561076f5761076788888381811061071057610710611ea6565b90506020028101906107229190611eba565b610730906020810190611ed8565b89898481811061074257610742611ea6565b90506020028101906107549190611eba565b610762906020810190611ef3565b610dc7565b6001016106f3565b505f61077e6020870187611ed8565b6001600160a01b0316146106a5576106a561079c6020870187611ed8565b6107a96020880188611ef3565b610ee7565b60605f6107dc7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0085856110a6565b909590945092505050565b606030806301fe9ff26107fd60208a018a611ed8565b61080a60208b018b611ef3565b8a8a8a8a6040516024016108249796959493929190611f7e565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050604051602001610862929190611fda565b604051602081830303815290604052905095945050505050565b7f0f000000000000000000000000000000000000000000000000000000000000006060805f808083610912604080518082018252600e81527f4e65787573426f6f7473747261700000000000000000000000000000000000006020808301919091528251808401909352600583527f312e302e300000000000000000000000000000000000000000000000000000009083015291565b97989097965046955030945091925090565b606030306001600160a01b03166355470cf18a8a8a8a8a8a8a60405160240161095397969594939291906120e4565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050604051602001610991929190611fda565b6040516020818303038152906040529050979650505050505050565b606030306001600160a01b031663d6fe71f18e8e8e8e8e8e8e8e8e8e8e6040516024016109e49b9a9998979695949392919061212d565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050604051602001610a22929190611fda565b60405160208183030381529060405290509b9a5050505050505050505050565b610a4e84848484610ce8565b5f5b8a811015610aa757610a9f8c8c83818110610a6d57610a6d611ea6565b9050602002810190610a7f9190611eba565b610a8d906020810190611ed8565b8d8d8481811061074257610742611ea6565b600101610a50565b505f5b88811015610b67575f8a8a83818110610ac557610ac5611ea6565b9050602002810190610ad79190611eba565b610ae5906020810190611ed8565b6001600160a01b031614610b5f57610b5f8a8a83818110610b0857610b08611ea6565b9050602002810190610b1a9190611eba565b610b28906020810190611ed8565b8b8b84818110610b3a57610b3a611ea6565b9050602002810190610b4c9190611eba565b610b5a906020810190611ef3565b6110c0565b600101610aaa565b505f610b766020890189611ed8565b6001600160a01b031614610ba157610ba1610b946020890189611ed8565b6107a960208a018a611ef3565b5f5b85811015610c60575f878783818110610bbe57610bbe611ea6565b9050602002810190610bd09190611eba565b610bde906020810190611ed8565b6001600160a01b031614610c5857610c58878783818110610c0157610c01611ea6565b9050602002810190610c139190611eba565b610c21906020810190611ed8565b888884818110610c3357610c33611ea6565b9050602002810190610c459190611eba565b610c53906020810190611ef3565b61117e565b600101610ba3565b505050505050505050505050565b60605f6107dc7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0185856110a6565b6001600160f81b0319828116908216145b92915050565b6060604080513681016020019091529050601436018152365f602083013760408051601481019091523360601b905292915050565b5f805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03861690811790915515610d8e576040517ff05c04e10000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063f05c04e190610d60908490879087906004016121bc565b5f604051808303815f87803b158015610d77575f5ffd5b505af1158015610d89573d5f5f3e3d5ffd5b505050505b6040516001600160a01b038516907ff98c8404c5b1bfef2e6ba9233c6e88845aedfd36eea8b192725d8c199571cf32905f90a250505050565b826001610dd482826114e9565b60405163ecd0596160e01b8152600160048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015610e17573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e3b91906121d8565b610e5b576040516369c9a24560e11b8152600160048201526024016105d7565b610e857f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0086611570565b6040516306d61fe760e41b81526001600160a01b03861690636d61fe7090610eb390879087906004016121f7565b5f604051808303815f87803b158015610eca575f5ffd5b505af1158015610edc573d5f5f3e3d5ffd5b505050505050505050565b826004610ef482826114e9565b60405163ecd0596160e01b81526004808201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015610f36573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f5a91906121d8565b610f79576040516369c9a24560e11b81526004818101526024016105d7565b5f610fab7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03546001600160a01b031690565b9050806001600160a01b03811615610ffb576040517f741cbe030000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016105d7565b507f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0388161790556040516306d61fe760e41b81526001600160a01b03871690636d61fe709061107190889088906004016121f7565b5f604051808303815f87803b158015611088575f5ffd5b505af115801561109a573d5f5f3e3d5ffd5b50505050505050505050565b60605f6110b485858561166a565b90969095509350505050565b8260026110cd82826114e9565b60405163ecd0596160e01b8152600260048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015611110573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061113491906121d8565b611154576040516369c9a24560e11b8152600260048201526024016105d7565b610e857f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0186611570565b82600361118b82826114e9565b60405163ecd0596160e01b8152600360048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa1580156111ce573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111f291906121d8565b611212576040516369c9a24560e11b8152600360048201526024016105d7565b5f611220600482868861220a565b61122991612231565b90505f8585600481811061123f5761123f611ea6565b9050013560f81c60f81b9050611258815f60f81b610c9c565b8061126c575061126c81607f60f91b610c9c565b6112a2576040517f867a1dcf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112b0866005818a61220a565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152509293505050506001600160e01b031983166306d61fe760e41b148061132e57506001600160e01b031983167f8a91b0e300000000000000000000000000000000000000000000000000000000145b8061134157506001600160e01b03198316155b15611378576040517fc001660b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160e01b031983165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f02602052604090205483906001600160a01b0316156113ff576040517fa56a04dd0000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016105d7565b506040805180820182526001600160a01b038a81168083526001600160f81b0319861660208085019182526001600160e01b031989165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0290915285902093518454915160f81c600160a01b027fffffffffffffffffffffff0000000000000000000000000000000000000000009092169316929092179190911790915590516306d61fe760e41b8152636d61fe70906114c09084906004016119b4565b5f604051808303815f87803b1580156114d7575f5ffd5b505af1158015610c60573d5f5f3e3d5ffd5b5f546001600160a01b0316801561156b576040517f96fb72170000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490528216906396fb7217906044015f6040518083038186803b158015611559575f5ffd5b505afa1580156106a5573d5f5f3e3d5ffd5b505050565b6001600160a01b038116158061158f57506001600160a01b0381166001145b156115b857604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105d7565b6001600160a01b038181165f908152602084905260409020541615611614576040517f40d3d1a40000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016105d7565b60015f818152602093909352604080842080546001600160a01b0394851680875292862080549590911673ffffffffffffffffffffffffffffffffffffffff199586161790559190935280549091169091179055565b60605f6001600160a01b03841660011480159061168e575061168c858561182b565b155b156116b757604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105d7565b825f036116f0576040517ff725081700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8267ffffffffffffffff811115611709576117096118bf565b604051908082528060200260200182016040528015611732578160200160208202803683370190505b506001600160a01b038086165f90815260208890526040812054929450911691505b6001600160a01b0382161580159061177657506001600160a01b038216600114155b801561178157508381105b156117da578183828151811061179957611799611ea6565b6001600160a01b039283166020918202929092018101919091529281165f9081529287905260409092205490911690806117d28161227b565b915050611754565b6001600160a01b0382166001148015906117f357505f81115b1561181f5782611804600183612293565b8151811061181457611814611ea6565b602002602001015191505b80835250935093915050565b5f60016001600160a01b0383161480159061185e57506001600160a01b038281165f908152602085905260409020541615155b9392505050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b0385168152836020820152606060408201525f6118b5606083018486611865565b9695505050505050565b634e487b7160e01b5f52604160045260245ffd5b5f602082840312156118e3575f5ffd5b815167ffffffffffffffff8111156118f9575f5ffd5b8201601f81018413611909575f5ffd5b805167ffffffffffffffff811115611923576119236118bf565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715611952576119526118bf565b604052818152828201602001861015611969575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61185e6020830184611986565b6001600160a01b03811681146119da575f5ffd5b50565b80356119e8816119c6565b919050565b5f5f83601f8401126119fd575f5ffd5b50813567ffffffffffffffff811115611a14575f5ffd5b6020830191508360208260051b8501011115611a2e575f5ffd5b9250929050565b803560ff811681146119e8575f5ffd5b5f5f5f5f5f5f5f60a0888a031215611a5b575f5ffd5b8735611a66816119c6565b9650602088013567ffffffffffffffff811115611a81575f5ffd5b8801601f81018a13611a91575f5ffd5b803567ffffffffffffffff811115611aa7575f5ffd5b8a6020828401011115611ab8575f5ffd5b60209190910196509450611ace604089016119dd565b9350606088013567ffffffffffffffff811115611ae9575f5ffd5b611af58a828b016119ed565b9094509250611b08905060808901611a35565b905092959891949750929550565b5f60208284031215611b26575f5ffd5b81356001600160e01b03198116811461185e575f5ffd5b5f60408284031215611b4d575f5ffd5b50919050565b5f5f5f5f5f5f5f60a0888a031215611b69575f5ffd5b873567ffffffffffffffff811115611b7f575f5ffd5b611b8b8a828b016119ed565b909850965050602088013567ffffffffffffffff811115611baa575f5ffd5b611bb68a828b01611b3d565b9550506040880135611ace816119c6565b5f5f60408385031215611bd8575f5ffd5b8235611be3816119c6565b946020939093013593505050565b604080825283519082018190525f9060208501906060840190835b81811015611c335783516001600160a01b0316835260209384019390920191600101611c0c565b505080925050506001600160a01b03831660208301529392505050565b5f5f5f5f5f60808688031215611c64575f5ffd5b853567ffffffffffffffff811115611c7a575f5ffd5b611c8688828901611b3d565b9550506020860135611c97816119c6565b9350604086013567ffffffffffffffff811115611cb2575f5ffd5b611cbe888289016119ed565b9094509250611cd1905060608701611a35565b90509295509295909350565b6001600160f81b03198816815260e060208201525f611cff60e0830189611986565b8281036040840152611d118189611986565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015611d66578351835260209384019390920191600101611d48565b50909b9a5050505050505050505050565b5f5f5f5f5f5f5f5f5f5f5f60e08c8e031215611d91575f5ffd5b8b3567ffffffffffffffff811115611da7575f5ffd5b611db38e828f016119ed565b909c509a505060208c013567ffffffffffffffff811115611dd2575f5ffd5b611dde8e828f016119ed565b909a5098505060408c013567ffffffffffffffff811115611dfd575f5ffd5b611e098e828f01611b3d565b97505060608c013567ffffffffffffffff811115611e25575f5ffd5b611e318e828f016119ed565b9097509550611e44905060808d016119dd565b935060a08c013567ffffffffffffffff811115611e5f575f5ffd5b611e6b8e828f016119ed565b9094509250611e7e905060c08d01611a35565b90509295989b509295989b9093969950565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52603260045260245ffd5b5f8235603e19833603018112611ece575f5ffd5b9190910192915050565b5f60208284031215611ee8575f5ffd5b813561185e816119c6565b5f5f8335601e19843603018112611f08575f5ffd5b83018035915067ffffffffffffffff821115611f22575f5ffd5b602001915036819003821315611a2e575f5ffd5b8183526020830192505f815f5b84811015611f74578135611f56816119c6565b6001600160a01b031686526020958601959190910190600101611f43565b5093949350505050565b6001600160a01b038816815260a060208201525f611fa060a08301888a611865565b6001600160a01b03871660408401528281036060840152611fc2818688611f36565b91505060ff8316608083015298975050505050505050565b6001600160a01b0383168152604060208201525f611ffb6040830184611986565b949350505050565b5f813561200f816119c6565b6001600160a01b03168352602082013536839003601e19018112612031575f5ffd5b820160208101903567ffffffffffffffff81111561204d575f5ffd5b80360382131561205b575f5ffd5b60406020860152612070604086018284611865565b95945050505050565b5f8383855260208501945060208460051b820101835f5b868110156120d857838303601f19018852813536879003603e190181126120b5575f5ffd5b6120c184888301612003565b6020998a0199909450929092019150600101612090565b50909695505050505050565b60a081525f6120f760a08301898b612079565b82810360208401526121098189612003565b90506001600160a01b03871660408401528281036060840152611fc2818688611f36565b60e081525f61214060e083018d8f612079565b8281036020840152612153818c8e612079565b90508281036040840152612167818b612003565b9050828103606084015261217c81898b612079565b90506001600160a01b038716608084015282810360a08401526121a0818688611f36565b91505060ff831660c08301529c9b505050505050505050505050565b60ff84168152604060208201525f612070604083018486611f36565b5f602082840312156121e8575f5ffd5b8151801515811461185e575f5ffd5b602081525f611ffb602083018486611865565b5f5f85851115612218575f5ffd5b83861115612224575f5ffd5b5050820193919092039150565b80356001600160e01b03198116906004841015612260576001600160e01b0319808560040360031b1b82161691505b5092915050565b634e487b7160e01b5f52601160045260245ffd5b5f6001820161228c5761228c612267565b5060010190565b81810381811115610cad57610cad61226756fea164736f6c634300081b000a"; + bytes public constant NEXUS_PROXY_BYTECODE = + hex"60806040526040516103e43803806103e48339810160408190526100229161026c565b61002a61003b565b6100348282610063565b5050610351565b7f90b772c2cb8a51aa7a8a65fc23543c6d022d5b3f8e2b92eed79fba7eef8293006001815d50565b61006c826100c1565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156100b5576100b0828261013c565b505050565b6100bd6101af565b5050565b806001600160a01b03163b5f036100fb57604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f5f846001600160a01b031684604051610158919061033b565b5f60405180830381855af49150503d805f8114610190576040519150601f19603f3d011682016040523d82523d5f602084013e610195565b606091505b5090925090506101a68583836101d0565b95945050505050565b34156101ce5760405163b398979f60e01b815260040160405180910390fd5b565b6060826101e5576101e08261022f565b610228565b81511580156101fc57506001600160a01b0384163b155b1561022557604051639996b31560e01b81526001600160a01b03851660048201526024016100f2565b50805b9392505050565b80511561023f5780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b634e487b7160e01b5f52604160045260245ffd5b5f5f6040838503121561027d575f5ffd5b82516001600160a01b0381168114610293575f5ffd5b60208401519092506001600160401b038111156102ae575f5ffd5b8301601f810185136102be575f5ffd5b80516001600160401b038111156102d7576102d7610258565b604051601f8201601f19908116603f011681016001600160401b038111828210171561030557610305610258565b60405281815282820160200187101561031c575f5ffd5b8160208401602083015e5f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b60878061035d5f395ff3fe6080604052600a600c565b005b60186014601a565b605d565b565b5f60587f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b905090565b365f5f375f5f365f845af43d5f5f3e8080156076573d5ff35b3d5ffdfea164736f6c634300081b000a"; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/Safe7579Precompiles.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/Safe7579Precompiles.sol new file mode 100644 index 0000000..0f8e6c8 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/Safe7579Precompiles.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { ISafe7579 } from "../../accounts/safe/interfaces/ISafe7579.sol"; +import { ISafe7579Launchpad } from "../../accounts/safe/interfaces/ISafe7579Launchpad.sol"; +import { ISafeProxyFactory } from "../../accounts/safe/interfaces/ISafeProxyFactory.sol"; + +// Utils +import { label } from "../../test/utils/Vm.sol"; +import { BytecodeDeployer } from "./BytecodeDeployer.sol"; + +/// @notice Precompiled Safe7579 contracts +contract Safe7579Precompiles is BytecodeDeployer { + /*////////////////////////////////////////////////////////////// + DEPLOY + //////////////////////////////////////////////////////////////*/ + + function deploySafe7579() internal returns (ISafe7579 safe) { + safe = ISafe7579(_deploy(SAFE7579_BYTECODE)); + label(address(safe), "Safe7579"); + } + + function deploySafe7579Launchpad( + address entrypoint, + address registry + ) + internal + returns (ISafe7579Launchpad safeLaunchpad) + { + // Concat constructor params to bytecode + bytes memory creationBytecode = + bytes.concat(SAFE7579_LAUNCHPAD_BYTECODE, abi.encode(entrypoint, registry)); + safeLaunchpad = ISafe7579Launchpad(_deploy(creationBytecode)); + label(address(safeLaunchpad), "Safe7579Launchpad"); + } + + function deploySafeSingleton() internal returns (address safeSingleton) { + safeSingleton = _deploy(SAFE_SINGLETON_BYTECODE); + label(safeSingleton, "SafeSingleton"); + } + + function deploySafeProxyFactory() internal returns (ISafeProxyFactory safeProxyFactory) { + safeProxyFactory = ISafeProxyFactory(_deploy(SAFE_PROXY_FACTORY_BYTECODE)); + label(address(safeProxyFactory), "SafeProxyFactory"); + } + + /*////////////////////////////////////////////////////////////// + BYTECODES + //////////////////////////////////////////////////////////////*/ + + /* solhint-disable max-line-length */ + bytes public constant SAFE7579_BYTECODE = + hex"60a060405234801561000f575f5ffd5b5060405161001c90610047565b604051809103905ff080158015610035573d5f5f3e3d5ffd5b506001600160a01b0316608052610054565b610988806153b883390190565b6080516152ff6100b95f395f81816112750152818161148a0152818161160a01528181611e3c0152818161242f015281816125080152818161259e01528181612634015281816138ef015281816139a601528181613dcf0152613ee701526152ff5ff3fe608060405260043610610138575f3560e01c8063a71763a8116100aa578063d828435d1161006e578063d828435d146104b7578063e9ae5c53146104d6578063ea5f61d0146104f5578063eab77e1714610514578063f2dc691d14610533578063f698da25146105525761013f565b8063a71763a8146103e2578063b0d691fe14610401578063b875d5d814610423578063d03c79141461046c578063d691c9641461048b5761013f565b8063540fb4f9116100fc578063540fb4f9146102dc57806355d559f4146102fd5780635faac46b1461032c57806379aad60e146103595780639517e29f146103785780639cfd7cff146103975761013f565b80630a664dba146101e7578063112d3a7d146102295780631626ba7e1461025857806319822f7c14610290578063236b58a1146102bd5761013f565b3661013f57005b5f3660605f3560e01c63bc197c81811463f23a6e6182141763150b7a028214171561016e57806020526020603cf35b50335f818152600460209081526040808320546001600160e01b031984351680855260058452828520958552949092528220546001600160a01b0391821692911690806101bb8484610566565b915091506101c98888610621565b95506101d784848484610730565b5050505050915050805190602001f35b3480156101f2575f5ffd5b50335f908152600460205260409020546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b348015610234575f5ffd5b5061024861024336600461419d565b6107b1565b6040519015158152602001610220565b348015610263575f5ffd5b506102776102723660046141f4565b610843565b6040516001600160e01b03199091168152602001610220565b34801561029b575f5ffd5b506102af6102aa36600461441e565b610bd8565b604051908152602001610220565b3480156102c8575f5ffd5b5061020c6102d7366004614467565b610d04565b3480156102e7575f5ffd5b506102fb6102f63660046144d4565b610d6d565b005b348015610308575f5ffd5b5061031c6103173660046145c5565b610e1d565b6040516102209493929190614641565b348015610337575f5ffd5b5061034b61034636600461468c565b610fde565b6040516102209291906146b6565b348015610364575f5ffd5b506102fb610373366004614718565b610ff9565b348015610383575f5ffd5b506102fb61039236600461419d565b6110fc565b3480156103a2575f5ffd5b50604080518082018252601a81527f7268696e6573746f6e652e73616665373537392e76312e302e30000000000000602082015290516102209190614756565b3480156103ed575f5ffd5b506102fb6103fc36600461419d565b6112e5565b34801561040c575f5ffd5b506f71727de22e5e9d8baf0edac6f37da03261020c565b34801561042e575f5ffd5b5061020c61043d36600461477d565b6001600160e01b0319165f9081526005602090815260408083203384529091529020546001600160a01b031690565b348015610477575f5ffd5b50610248610486366004614467565b611648565b348015610496575f5ffd5b506104aa6104a53660046141f4565b6116f3565b6040516102209190614798565b3480156104c2575f5ffd5b506102af6104d13660046147fb565b6117db565b3480156104e1575f5ffd5b506102fb6104f03660046141f4565b611878565b348015610500575f5ffd5b5061034b61050f36600461468c565b611c11565b34801561051f575f5ffd5b506102fb61052e366004614837565b611c21565b34801561053e575f5ffd5b5061024861054d366004614467565b611c90565b34801561055d575f5ffd5b506102af611cd8565b6060806001600160a01b038416156105e4576105cb33855f610586611d30565b345f3660405160240161059c94939291906148c1565b60408051601f198184030181529190526020810180516001600160e01b031663d68f602560e01b179052611d3c565b9150818060200190518101906105e1919061493f565b91505b6001600160a01b0383161561061a5761060133845f610586611d30565b905080806020019051810190610617919061493f565b90505b9250929050565b5f80356001600160e01b031916815260036020908152604080832033845290915290208054606091906001600160a01b03811690600160a01b900460f81b8161068f57604051632464e76d60e11b81526001600160e01b03195f351660048201526024015b60405180910390fd5b61069d81607f60f91b611dde565b156106e1576106d7338388886106b1611d30565b6040516020016106c393929190614970565b604051602081830303815290604052611df0565b935050505061072a565b6106eb815f611dde565b15610726576106d733835f8989610700611d30565b60405160200161071293929190614970565b604051602081830303815290604052611d3c565b5050505b92915050565b6001600160a01b038416156107855761078533855f856040516024016107569190614756565b60408051601f198184030181529190526020810180516001600160e01b0316630b9dfbed60e11b179052611ec1565b6001600160a01b038316156107ab576107ab33845f846040516024016107569190614756565b50505050565b5f600185036107e257336001600160a01b038516036107d25750600161083b565b6107db84611f5c565b905061083b565b600285036107f3576107db84611f69565b60038503610806576107db848484611f76565b60048503610819576107db848484611fc0565b60088514806108285750600985145b15610838576107db848484611ff9565b505f5b949350505050565b5f338282036109ee5761085f610857611d30565b868686612069565b50809550505f610928826001600160a01b031663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108a4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108c89190614996565b60408051602081018a90527f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca91015b60408051601f1981840301815282825280516020918201209083015201604051602081830303815290604052612140565b8051602090910120604051635ae6bd3760e01b8152600481018290529091506001600160a01b03831690635ae6bd3790602401602060405180830381865afa158015610976573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061099a9190614996565b5f036109dc5760405162461bcd60e51b815260206004820152601160248201527012185cda081b9bdd08185c1c1c9bdd9959607a1b6044820152606401610686565b50630b135d3f60e11b9150610bd19050565b5f6109fc60148286886149ad565b610a05916149d4565b60601c90506060610a2a610a17611d30565b88610a25886014818c6149ad565b612069565b90975090506001600160a01b0382161580610a4b5750610a4982611f5c565b155b15610b63575f610ae7846001600160a01b031663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a90573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ab49190614996565b60408051602081018c90527f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca91016108f7565b8051602082012060405163934f3a1160e01b8152919250906001600160a01b0386169063934f3a1190610b2290849086908890600401614a21565b5f6040518083038186803b158015610b38575f5ffd5b505afa158015610b4a573d5f5f3e3d5ffd5b50630b135d3f60e11b9850610bd1975050505050505050565b5f610bb43384610b71611d30565b8b86604051602401610b8593929190614a4b565b60408051601f198184030181529190526020810180516001600160e01b0316637aa8f17760e11b179052611df0565b905080806020019051810190610bca9190614a7a565b9450505050505b9392505050565b5f6f71727de22e5e9d8baf0edac6f37da032610bf2611d30565b6001600160a01b031614610c1957604051635629665f60e11b815260040160405180910390fd5b6020840151606081901c90610c2f8587866121ba565b61010088015294506001600160a01b0382161580610c535750610c5182611f5c565b155b15610c6857610c6186612258565b9250610ccb565b5f610cb133845f8a8a604051602401610c82929190614b35565b60408051601f198184030181529190526020810180516001600160e01b0316639700320360e01b179052611d3c565b905080806020019051810190610cc79190614996565b9350505b8315610cfb57610cfb336f71727de22e5e9d8baf0edac6f37da0328660405180602001604052805f815250611ec1565b50509392505050565b5f60098203610d2a575050335f908152600660205260409020546001600160a01b031690565b60088203610d4f575050335f908152600760205260409020546001600160a01b031690565b604051635691922f60e01b815260040160405180910390fd5b919050565b6f71727de22e5e9d8baf0edac6f37da032610d86611d30565b6001600160a01b03161480610db35750610d9e611d30565b6001600160a01b0316336001600160a01b0316145b610dd057604051635629665f60e11b815260040160405180910390fd5b610e02610de06020830183614b56565b610ded6020840184614b71565b610dfd6060860160408701614bb6565b612303565b610e1289898989898989896123b7565b505050505050505050565b6101008201516060905f9081908390610e38818460066126a2565b610e4190614bcf565b60d01c9350610e53816006600c6126a2565b610e5c90614bcf565b60d01c9250610e6c81600c612707565b9150505f604051806101c001604052807fc03dfc11d8b10bf9cf703d558958c8c42777f785d998c62060d85a4f0ef6ea7f5f1b8152602001885f01516001600160a01b031681526020018860200151815260200188604001518051906020012081526020018860600151805190602001208152602001610eeb89612715565b6001600160801b03168152602001610f0289612724565b6001600160801b031681526020018860a001518152602001610f2389612739565b6001600160801b03168152602001610f3a89612748565b6001600160801b0316815260e089015180516020918201209082015265ffffffffffff8087166040830152851660608201526001600160a01b0388166080909101526101c08120909150601960f81b600160f81b610f96611cd8565b6040516001600160f81b031993841660208201529290911660218301526022820152604281018290526062016040516020818303038152906040529550505092959194509250565b60605f610fee600133868661275d565b915091509250929050565b6f71727de22e5e9d8baf0edac6f37da032611012611d30565b6001600160a01b0316148061103f575061102a611d30565b6001600160a01b0316336001600160a01b0316145b61105c57604051635629665f60e11b815260040160405180910390fd5b61106760013361291c565b6110f857611076600133612947565b805f5b818110156110cb573684848381811061109457611094614c09565b90506020028101906110a69190614c1d565b90506110c2336110b96020840184614b56565b600191906129a6565b50600101611079565b5060405133907ff48581d8a62b775b74f2fb67f1d5806a9a356fbcc598040ab3071d3e37af40c2905f90a2505b5050565b335f908152600460209081526040808320547fd00bcad91b775f25eb0aee15808d12dfdaa6dc5a7d6b754e26f9c205d2a3b8df909252822054639517e29f60e01b926001600160a01b039283169290911690806111598484610566565b915091506111746f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316611185611d30565b6001600160a01b031614806111b2575061119d611d30565b6001600160a01b0316336001600160a01b0316145b6111cf57604051635629665f60e11b815260040160405180910390fd5b606060018a036111eb576111e4898989612a99565b905061126f565b60028a036111fe576111e4898989612af4565b60038a03611211576111e4898989612b0f565b60048a03611224576111e4898989612c8a565b89611234576111e4898989612e07565b60088a1480611243575060098a145b15611253576111e4898989612fb5565b60405163041c38b360e41b8152600481018b9052602401610686565b6112d8337f00000000000000000000000000000000000000000000000000000000000000008c8c856040516024016112a993929190614c3b565b60408051601f198184030181529190526020810180516001600160e01b0316639517e29f60e01b179052612ff0565b50610e1284848484610730565b335f908152600460209081526040808320547fc45a7acaba78a7b4c4432b604d301355b314c0a7811768a1ee2563c9d34ca4e09092529091205484916314e2ec7560e31b916001600160a01b0391821691908116908416821480159061135d5750806001600160a01b0316846001600160a01b031614155b15611501575f5f61136e8484610566565b915091506113896f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b031661139a611d30565b6001600160a01b031614806113c757506113b2611d30565b6001600160a01b0316336001600160a01b0316145b6113e457604051635629665f60e11b815260040160405180910390fd5b606060018b03611400576113f98a8a8a613085565b9050611484565b60028b03611413576113f98a8a8a6130a5565b60038b03611426576113f98a8a8a6130c5565b60048b03611439576113f98a8a8a61310f565b8a611449576113f98a8a8a6131c3565b60088b1480611458575060098b145b15611468576113f98a8a8a613314565b60405163041c38b360e41b8152600481018c9052602401610686565b6114ed337f00000000000000000000000000000000000000000000000000000000000000008d8d856040516024016114be93929190614c3b565b60408051601f198184030181529190526020810180516001600160e01b0316637827252560e01b17905261337a565b506114fa84848484610730565b505061163e565b6f71727de22e5e9d8baf0edac6f37da03261151a611d30565b6001600160a01b031614806115475750611532611d30565b6001600160a01b0316336001600160a01b0316145b61156457604051635629665f60e11b815260040160405180910390fd5b60606001890361158057611579888888613085565b9050611604565b60028903611593576115798888886130a5565b600389036115a6576115798888886130c5565b600489036115b95761157988888861310f565b886115c9576115798888886131c3565b60088914806115d85750600989145b156115e857611579888888613314565b60405163041c38b360e41b8152600481018a9052602401610686565b610e12337f00000000000000000000000000000000000000000000000000000000000000008b8b856040516024016114be93929190614c3b565b5050505050505050565b5f81600881901b61165d82600160f81b611dde565b1561166b57600192506116ac565b611675825f611dde565b1561168357600192506116ac565b611695826001600160f81b0319611dde565b156116a357600192506116ac565b505f9392505050565b8280156116be57506116be815f611dde565b156116ca575050919050565b8280156116e057506116e081600160f81b611dde565b156116a3575050919050565b5050919050565b6060611705611700611d30565b611f69565b61173657611711611d30565b604051635c93ff2f60e11b81526001600160a01b039091166004820152602401610686565b335f908152600460209081526040808320547f4162c930ade27880570b0eb31efbc8a626b97e81a40ced27163509dfe16398829092528220546335a4725960e21b926001600160a01b039283169290911690806117938484610566565b9150915061179f611d30565b60026117ab828261342a565b8a600881901b6117bd81838e8e6134b0565b9950505050506117cf84848484610730565b50505050509392505050565b5f602082901b640100000000600160c01b03166f71727de22e5e9d8baf0edac6f37da032604051631aab3f0d60e11b81526001600160a01b0386811660048301526001600160c01b038416602483015291909116906335567e1a90604401602060405180830381865afa158015611854573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061083b9190614996565b335f908152600460209081526040808320547fccfe1b2bef70acd8e661aeb5430e147f4c75cb320972acba718a28da428e1a3090925282205463e9ae5c5360e01b926001600160a01b039283169290911690806118d58484610566565b915091506118f06f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316611901611d30565b6001600160a01b0316148061192e5750611919611d30565b6001600160a01b0316336001600160a01b0316145b61194b57604051635629665f60e11b815260040160405180910390fd5b87600881901b3361195c825f611dde565b15611ab45761196f83600160f81b611dde565b1561199657365f6119808c8c613853565b9150915061198f8383836138e9565b5050611c02565b6119a0835f611dde565b15611a05575f5f365f6119b38e8e613950565b93509350935093506119fc85858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ec192505050565b50505050611c02565b611a17836001600160f81b0319611dde565b15611a99575f611a2a6014828c8e6149ad565b611a33916149d4565b60601c9050365f8c8c6014908092611a4d939291906149ad565b91509150611a91848484848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612ff092505050565b505050611c02565b82604051632e5bf3f960e21b81526004016106869190614c64565b611ac282600160f81b611dde565b15611be757611ad583600160f81b611dde565b15611af557365f611ae68c8c613853565b9150915061198f8383836139a0565b611aff835f611dde565b15611b5b575f5f365f611b128e8e613950565b93509350935093506119fc85858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250613a0792505050565b611b6d836001600160f81b0319611dde565b15611a99575f611b806014828c8e6149ad565b611b89916149d4565b60601c9050365f8c8c6014908092611ba3939291906149ad565b91509150611a91848484848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061337a92505050565b816040516308c3ee0360e11b81526004016106869190614c64565b50505061163e84848484610730565b60605f610fee600233868661275d565b6f71727de22e5e9d8baf0edac6f37da032611c3a611d30565b6001600160a01b03161480611c675750611c52611d30565b6001600160a01b0316336001600160a01b0316145b611c8457604051635629665f60e11b815260040160405180910390fd5b6107ab84848484612303565b5f60018203611ca157506001919050565b60028203611cb157506001919050565b60038203611cc157506001919050565b60048203611cd157506001919050565b505f919050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218602082015246918101919091523060608201525f9060800160405160208183030381529060405280519060200120905090565b60131936013560601c90565b60605f856001600160a01b0316635229073f8686865f6040518563ffffffff1660e01b8152600401611d719493929190614cad565b5f604051808303815f875af1158015611d8c573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611db39190810190614cf1565b9250905080611dd557604051632b3f6d1160e21b815260040160405180910390fd5b50949350505050565b6001600160f81b031990811691161490565b60605f8383604051602401611e06929190614d3b565b60408051601f198184030181529181526020820180516001600160e01b0316636a22165760e01b179052519091505f90611e66907f0000000000000000000000000000000000000000000000000000000000000000908490602401614d3b565b60408051601f19818403018152919052602080820180516001600160e01b031663b4faba0960e01b178152825192935090915f91895afa5060203d036040519350808401604052806020853e505f51610cfb57825160208401fd5b60405163468721a760e01b81525f906001600160a01b0386169063468721a790611ef5908790879087908790600401614cad565b6020604051808303815f875af1158015611f11573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f359190614d5e565b905080611f5557604051632b3f6d1160e21b815260040160405180910390fd5b5050505050565b5f61072a60013384613ab7565b5f61072a60023384613ab7565b5f80611f848385018561477d565b6001600160e01b0319165f9081526003602090815260408083203384529091529020546001600160a01b03908116908616149150509392505050565b5f8080611fcf84860186614d85565b915091505f611fde8383613af9565b6001600160a01b039081169088161493505050509392505050565b5f8061200783850185614467565b905060098103612035575050335f908152600660205260409020546001600160a01b03848116911614610bd1565b60088103610d4f575050335f908152600760205260409020546001600160a01b03848116911614610bd1565b509392505050565b5f60605f6120776008610d04565b90506001600160a01b0381166120ce5785858581818080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525095985091965061213795505050505050565b5f61211a33838a8a8a8a6040516024016120eb94939291906148c1565b60408051601f198184030181529190526020810180516001600160e01b0316637a0468b760e01b179052611df0565b9050808060200190518101906121309190614daf565b9350935050505b94509492505050565b6060601960f81b600160f81b858585604051602001612160929190614ddd565b60408051808303601f190181529082905280516020918201206001600160f81b0319958616918301919091529290931660218401526022830152604282015260620160405160208183030381529060405290509392505050565b5f60605f6121c86009610d04565b90506001600160a01b0381166121e8575050506101008201518390612250565b5f61223333835f89898c60405160240161220493929190614dfd565b60408051601f198184030181529190526020810180516001600160e01b031663e24f8f9360e01b179052611d3c565b9050808060200190518101906122499190614daf565b9350935050505b935093915050565b5f80808080612277866f71727de22e5e9d8baf0edac6f37da032610e1d565b8351602085012060405163934f3a1160e01b81529498509296509094509250339163934f3a11916122ae9188908690600401614a21565b5f6040518083038186803b1580156122c4575f5ffd5b505afa9250505080156122d5575060015b6122ec576122e560018385613b8c565b94506122fa565b6122f75f8385613b8c565b94505b50505050919050565b335f90815260208190526040902080546001600160a01b0319166001600160a01b0386169081179091551561237c5761237c33855f84878760405160240161234d93929190614e21565b60408051601f198184030181529190526020810180516001600160e01b031663f05c04e160e01b179052611ec1565b6040516001600160a01b0385169033907f9452c8fb077c3ea8f28a77c87488af657b1e44d010ad9a5992d73870da040e94905f90a350505050565b6060876123c560013361291c565b61247f576123d4600133612947565b5f5b8181101561247957368b8b838181106123f1576123f1614c09565b90506020028101906124039190614c1d565b90506124276124156020830183614b56565b6124226020840184614e78565b612a99565b9350612470337f0000000000000000000000000000000000000000000000000000000000000000600161245d6020860186614b56565b886040516024016112a993929190614c3b565b506001016123d6565b506124a0565b80156124a05760405163d8e3ed1b60e01b8152336004820152602401610686565b6124ab600233612947565b50855f5b8181101561253f57368989838181106124ca576124ca614c09565b90506020028101906124dc9190614c1d565b90506125006124ee6020830183614b56565b6124fb6020840184614e78565b612af4565b9350612536337f0000000000000000000000000000000000000000000000000000000000000000600261245d6020860186614b56565b506001016124af565b508490505f5b818110156125d5573687878381811061256057612560614c09565b90506020028101906125729190614c1d565b90506125966125846020830183614b56565b6125916020840184614e78565b612b0f565b93506125cc337f0000000000000000000000000000000000000000000000000000000000000000600361245d6020860186614b56565b50600101612545565b508290505f5b8181101561266b57368585838181106125f6576125f6614c09565b90506020028101906126089190614c1d565b905061262c61261a6020830183614b56565b6126276020840184614e78565b612c8a565b9350612662337f0000000000000000000000000000000000000000000000000000000000000000600461245d6020860186614b56565b506001016125db565b5060405133907ff48581d8a62b775b74f2fb67f1d5806a9a356fbcc598040ab3071d3e37af40c2905f90a250505050505050505050565b606083518281116126b1578092505b8381116126bc578093505b5081831015610bd15750604051828203848401601f19601f830181165b82810151858201528101806126d9575050508060208301015f81526020810160405250808252509392505050565b6060610bd183835f196126a2565b5f61072a826080015160801c90565b5f61072a82608001516001600160801b031690565b5f61072a8260c0015160801c90565b5f61072a8260c001516001600160801b031690565b60605f6001600160a01b0384166001148015906127825750612780868686613ab7565b155b156127ab57604051637c84ecfb60e01b81526001600160a01b0385166004820152602401610686565b825f036127cb5760405163f725081760e01b815260040160405180910390fd5b826001600160401b038111156127e3576127e361423b565b60405190808252806020026020018201604052801561280c578160200160208202803683370190505b506001600160a01b038086165f908152602089815260408083208a85168452909152812054929450911691505b6001600160a01b0382161580159061285b57506001600160a01b038216600114155b801561286657508381105b156128ca578183828151811061287e5761287e614c09565b6001600160a01b039283166020918202929092018101919091529281165f90815288845260408082208984168352909452929092205490911690806128c281614ece565b915050612839565b6001600160a01b0382166001148015906128e357505f81115b1561290f57826128f4600183614ee6565b8151811061290457612904614c09565b602002602001015191505b8083525094509492505050565b60015f908152602092835260408082206001600160a01b039384168352909352919091205416151590565b612951828261291c565b1561296f576040516329e42f3360e11b815260040160405180910390fd5b60015f818152602093845260408082206001600160a01b0394909416825292909352912080546001600160a01b0319169091179055565b6001600160a01b03811615806129c557506001600160a01b0381166001145b156129ee57604051637c84ecfb60e01b81526001600160a01b0382166004820152602401610686565b6001600160a01b038181165f9081526020858152604080832086851684529091529020541615612a3c57604051631034f46960e21b81526001600160a01b0382166004820152602401610686565b60015f908152602084815260408083206001600160a01b039586168085528184528285208054968816808752988552838620918652908452919093208054949095166001600160a01b031994851617909455528154169091179055565b6060836001612aa8828261342a565b612ab4600133886129a6565b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250929998505050505050505050565b6060836002612b03828261342a565b612ab4600233886129a6565b6060836003612b1e828261342a565b5f8080612b2d87890189614ef9565b919450925090506001600160e01b031983166306d61fe760e41b1480612b6357506001600160e01b03198316638a91b0e360e01b145b15612b8d576040516379bd117b60e01b81526001600160e01b031984166004820152602401610686565b612b97825f611dde565b8015612bac5750612bac82607f60f91b611dde565b15612bcc57816040516376087dc160e01b81526004016106869190614c64565b6001600160e01b031983165f9081526003602090815260408083203384529091529020546001600160a01b031615612c23576040516374420d1560e01b81526001600160e01b031984166004820152602401610686565b6001600160e01b03199092165f908152600360209081526040808320338452909152902080546001600160a01b038a166001600160a01b031960f89490941c600160a01b02939093166001600160a81b031990911617919091179055925050509392505050565b6060836004612c99828261342a565b5f8080612ca887890189614f62565b919450925090505f80846001811115612cc357612cc3614c79565b148015612cd857506001600160e01b03198316155b15612d4c5750335f908152600460205260409020546001600160a01b03168015612d205760405163741cbe0360e01b81526001600160a01b0382166004820152602401610686565b335f90815260046020526040902080546001600160a01b0319166001600160a01b038c16179055612dfa565b6001846001811115612d6057612d60614c79565b03610d4f57506001600160e01b031982165f9081526005602090815260408083203384529091529020546001600160a01b03168015612dbd5760405163741cbe0360e01b81526001600160a01b0382166004820152602401610686565b6001600160e01b031983165f908152600560209081526040808320338452909152902080546001600160a01b0319166001600160a01b038c161790555b5098975050505050505050565b60608235830160208181019135908581013586018082019190359060408801358801908101903584838114612e4f5760405163b4fa3fb360e01b815260040160405180910390fd5b5f5b81811015612f6f575f888883818110612e6c57612e6c614c09565b90506020020135905060018103612eab57612ea58d888885818110612e9357612e93614c09565b90506020028101906124229190614e78565b50612f66565b60028103612edb57612ea58d888885818110612ec957612ec9614c09565b90506020028101906124fb9190614e78565b60038103612f0b57612ea58d888885818110612ef957612ef9614c09565b90506020028101906125919190614e78565b60048103612f3b57612ea58d888885818110612f2957612f29614c09565b90506020028101906126279190614e78565b60405163484d218160e01b81526001600160a01b038e16600482015260248101829052604401610686565b50600101612e51565b5082828080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250929e9d5050505050505050505050505050565b60605f612fc483850185614f8d565b925090506008198101612fdf57612fda85613bc2565b612061565b60088103610d4f57612fda85613c4a565b60405163468721a760e01b81525f906001600160a01b0385169063468721a79061302590869085908790600190600401614cad565b6020604051808303815f875af1158015613041573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130659190614d5e565b9050806107ab57604051632b3f6d1160e21b815260040160405180910390fd5b60605f61309483850185614fc6565b925090506120616001338388613cd2565b60605f6130b483850185614fc6565b925090506120616002338388613cd2565b60605f6130d483850185614ffc565b6001600160e01b03199091165f908152600360209081526040808320338452909152902080546001600160a01b031916905595945050505050565b60605f8061311f84860186614f62565b945090925090505f82600181111561313957613139614c79565b14801561314e57506001600160e01b03198116155b1561317457335f90815260046020526040902080546001600160a01b0319169055610cfb565b600182600181111561318857613188614c79565b03610d4f576001600160e01b031981165f908152600560209081526040808320338452909152902080546001600160a01b0319169055610cfb565b6060823583016020818101913590858101358601808201919035906040880135880190810190358483811461320b5760405163b4fa3fb360e01b815260040160405180910390fd5b5f5b81811015612f6f575f88888381811061322857613228614c09565b9050602002013590506001810361326c576132668d88888581811061324f5761324f614c09565b90506020028101906132619190614e78565b613085565b5061330b565b600281036132a1576132668d88888581811061328a5761328a614c09565b905060200281019061329c9190614e78565b6130a5565b600381036132d6576132668d8888858181106132bf576132bf614c09565b90506020028101906132d19190614e78565b6130c5565b60048103612f3b576132668d8888858181106132f4576132f4614c09565b90506020028101906133069190614e78565b61310f565b5060010161320d565b60605f61332383850185614f8d565b92509050600819810161335157335f90815260066020526040902080546001600160a01b0319169055612061565b60088103610d4f57335f90815260076020526040902080546001600160a01b0319169055612061565b60405163468721a760e01b81525f906001600160a01b0385169063468721a7906133af90869085908790600190600401614cad565b6020604051808303815f875af11580156133cb573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133ef9190614d5e565b9050806107ab57604080516001600160a01b03861681525f60208201525f5160206152aa5f395f51905f52910160405180910390a150505050565b335f908152602081905260409020546001600160a01b031680156134ab5760405163529562a160e01b81523360048201526001600160a01b0384811660248301526044820184905282169063529562a1906064015f6040518083038186803b158015613494575f5ffd5b505afa1580156134a6573d5f5f3e3d5ffd5b505050505b505050565b60606134bc855f611dde565b156136a5576134cf84600160f81b611dde565b156134f857365f6134e08585613853565b915091506134ef338383613dc7565b9250505061083b565b613502845f611dde565b156135b2575f5f365f6135158787613950565b6040805160018082528183019092529498509296509094509250816020015b606081526020019060019003908161353457905050945061358c33858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611d3c92505050565b855f8151811061359e5761359e614c09565b60200260200101819052505050505061083b565b6135c4846001600160f81b0319611dde565b1561368a575f6135d760148285876149ad565b6135e0916149d4565b60601c9050365f6135f485601481896149ad565b604080516001808252818301909252929450909250816020015b606081526020019060019003908161360e579050509350613665338484848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250613e4392505050565b845f8151811061367757613677614c09565b602002602001018190525050505061083b565b83604051632e5bf3f960e21b81526004016106869190614c64565b6136b385600160f81b611dde565b15613838576136c684600160f81b611dde565b156136f157365f6136d78585613853565b915091506136e6338383613edd565b935061083b92505050565b6136fb845f611dde565b15613785575f5f365f61370e8787613950565b6040805160018082528183019092529498509296509094509250816020015b606081526020019060019003908161372d57905050945061358c33858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250613fd092505050565b613797846001600160f81b0319611dde565b1561368a575f6137aa60148285876149ad565b6137b3916149d4565b60601c9050365f6137c785601481896149ad565b604080516001808252818301909252929450909250816020015b60608152602001906001900390816137e1579050509350613665338484848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061408792505050565b846040516308c3ee0360e11b81526004016106869190614c64565b365f833580850160208587010360208201945081359350808460051b8301118360401c17156138895763ba597e7e5f526004601cfd5b83156138df578392505b6001830392508260051b850135915081850160408101358082018381358201118460408501111782861782351760401c17156138d65763ba597e7e5f526004601cfd5b50505082613893575b5050509250929050565b6134ab837f00000000000000000000000000000000000000000000000000000000000000008484604051602401613921929190615018565b60408051601f198184030181529190526020810180516001600160e01b0316633f707e6b60e01b179052612ff0565b5f80368161396160148287896149ad565b61396a916149d4565b60601c935061397d6034601487896149ad565b613986916150f8565b925061399585603481896149ad565b949793965094505050565b6134ab837f000000000000000000000000000000000000000000000000000000000000000084846040516024016139d8929190615018565b60408051601f198184030181529190526020810180516001600160e01b0316632864481160e11b17905261337a565b60405163468721a760e01b81525f906001600160a01b0386169063468721a790613a3b908790879087908790600401614cad565b6020604051808303815f875af1158015613a57573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a7b9190614d5e565b905080611f5557604080516001600160a01b03871681525f60208201525f5160206152aa5f395f51905f52910160405180910390a15050505050565b5f60016001600160a01b0383161480159061083b5750506001600160a01b039081165f9081526020938452604080822093831682529290935291205416151590565b5f80836001811115613b0d57613b0d614c79565b148015613b2257506001600160e01b03198216155b15613b415750335f908152600460205260409020546001600160a01b03165b6001836001811115613b5557613b55614c79565b0361072a57506001600160e01b0319165f9081526005602090815260408083203384529091529020546001600160a01b0316919050565b5f60d08265ffffffffffff16901b60a08465ffffffffffff16901b85613bb2575f613bb5565b60015b60ff161717949350505050565b806009613bcf828261342a565b335f908152600660205260409020546001600160a01b03168015613c185760405163b9aa8b3f60e01b81526001600160a01b038216600482015260096024820152604401610686565b5050335f90815260066020526040902080546001600160a01b0319166001600160a01b03939093169290921790915550565b806008613c57828261342a565b335f908152600760205260409020546001600160a01b03168015613ca05760405163b9aa8b3f60e01b81526001600160a01b038216600482015260086024820152604401610686565b5050335f90815260076020526040902080546001600160a01b0319166001600160a01b03939093169290921790915550565b6001600160a01b0381161580613cf157506001600160a01b0381166001145b15613d1a57604051637c84ecfb60e01b81526001600160a01b0383166004820152602401610686565b6001600160a01b038281165f908152602086815260408083208785168452909152902054811690821614613d6c57604051637c84ecfb60e01b81526001600160a01b0382166004820152602401610686565b6001600160a01b039081165f908152602085815260408083209584168084528683528184208054968616855297835281842090845282529091208054939092166001600160a01b031993841617909155919091528154169055565b6060613e30847f00000000000000000000000000000000000000000000000000000000000000008585604051602401613e01929190615018565b60408051601f198184030181529190526020810180516001600160e01b0316636108557360e01b179052613e43565b80602001905181019061083b91906151bf565b60605f846001600160a01b0316635229073f855f8660016040518563ffffffff1660e01b8152600401613e799493929190614cad565b5f604051808303815f875af1158015613e94573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052613ebb9190810190614cf1565b925090508061206157604051632b3f6d1160e21b815260040160405180910390fd5b6060805f613f48867f00000000000000000000000000000000000000000000000000000000000000008787604051602401613f19929190615018565b60408051601f198184030181529190526020810180516001600160e01b0316639abb6e1760e01b179052614087565b905080806020019051810190613f5e91906151f0565b815191945092505f5b81811015613fc557848181518110613f8157613f81614c09565b6020026020010151613fbd57604080516001600160a01b038a168152602081018390525f5160206152aa5f395f51905f52910160405180910390a15b600101613f67565b505050935093915050565b60605f856001600160a01b0316635229073f8686865f6040518563ffffffff1660e01b81526004016140059493929190614cad565b5f604051808303815f875af1158015614020573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526140479190810190614cf1565b9250905080611dd557604080516001600160a01b03881681525f60208201525f5160206152aa5f395f51905f52910160405180910390a150949350505050565b60605f846001600160a01b0316635229073f855f8660016040518563ffffffff1660e01b81526004016140bd9493929190614cad565b5f604051808303815f875af11580156140d8573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526140ff9190810190614cf1565b925090508061206157604080516001600160a01b03871681525f60208201525f5160206152aa5f395f51905f52910160405180910390a1509392505050565b6001600160a01b0381168114614152575f5ffd5b50565b8035610d688161413e565b5f5f83601f840112614170575f5ffd5b5081356001600160401b03811115614186575f5ffd5b60208301915083602082850101111561061a575f5ffd5b5f5f5f5f606085870312156141b0575f5ffd5b8435935060208501356141c28161413e565b925060408501356001600160401b038111156141dc575f5ffd5b6141e887828801614160565b95989497509550505050565b5f5f5f60408486031215614206575f5ffd5b8335925060208401356001600160401b03811115614222575f5ffd5b61422e86828701614160565b9497909650939450505050565b634e487b7160e01b5f52604160045260245ffd5b60405161012081016001600160401b03811182821017156142725761427261423b565b60405290565b604051601f8201601f191681016001600160401b03811182821017156142a0576142a061423b565b604052919050565b5f6001600160401b038211156142c0576142c061423b565b50601f01601f191660200190565b5f82601f8301126142dd575f5ffd5b81356142f06142eb826142a8565b614278565b818152846020838601011115614304575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f6101208284031215614331575f5ffd5b61433961424f565b905061434482614155565b81526020828101359082015260408201356001600160401b03811115614368575f5ffd5b614374848285016142ce565b60408301525060608201356001600160401b03811115614392575f5ffd5b61439e848285016142ce565b6060830152506080828101359082015260a0808301359082015260c0808301359082015260e08201356001600160401b038111156143da575f5ffd5b6143e6848285016142ce565b60e0830152506101008201356001600160401b03811115614405575f5ffd5b614411848285016142ce565b6101008301525092915050565b5f5f5f60608486031215614430575f5ffd5b83356001600160401b03811115614445575f5ffd5b61445186828701614320565b9660208601359650604090950135949350505050565b5f60208284031215614477575f5ffd5b5035919050565b5f5f83601f84011261448e575f5ffd5b5081356001600160401b038111156144a4575f5ffd5b6020830191508360208260051b850101111561061a575f5ffd5b5f606082840312156144ce575f5ffd5b50919050565b5f5f5f5f5f5f5f5f5f60a08a8c0312156144ec575f5ffd5b89356001600160401b03811115614501575f5ffd5b61450d8c828d0161447e565b909a5098505060208a01356001600160401b0381111561452b575f5ffd5b6145378c828d0161447e565b90985096505060408a01356001600160401b03811115614555575f5ffd5b6145618c828d0161447e565b90965094505060608a01356001600160401b0381111561457f575f5ffd5b61458b8c828d0161447e565b90945092505060808a01356001600160401b038111156145a9575f5ffd5b6145b58c828d016144be565b9150509295985092959850929598565b5f5f604083850312156145d6575f5ffd5b82356001600160401b038111156145eb575f5ffd5b6145f785828601614320565b92505060208301356146088161413e565b809150509250929050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b608081525f6146536080830187614613565b65ffffffffffff8616602084015265ffffffffffff8516604084015282810360608401526146818185614613565b979650505050505050565b5f5f6040838503121561469d575f5ffd5b82356146a88161413e565b946020939093013593505050565b604080825283519082018190525f9060208501906060840190835b818110156146f85783516001600160a01b03168352602093840193909201916001016146d1565b50506001600160a01b039490941660209390930192909252509092915050565b5f5f60208385031215614729575f5ffd5b82356001600160401b0381111561473e575f5ffd5b61474a8582860161447e565b90969095509350505050565b602081525f610bd16020830184614613565b6001600160e01b031981168114614152575f5ffd5b5f6020828403121561478d575f5ffd5b8135610bd181614768565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b828110156147ef57603f198786030184526147da858351614613565b945060209384019391909101906001016147be565b50929695505050505050565b5f5f6040838503121561480c575f5ffd5b82356148178161413e565b915060208301356146088161413e565b803560ff81168114610d68575f5ffd5b5f5f5f5f6060858703121561484a575f5ffd5b84356148558161413e565b935060208501356001600160401b0381111561486f575f5ffd5b61487b8782880161447e565b909450925061488e905060408601614827565b905092959194509250565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b60018060a01b0385168152836020820152606060408201525f6148e8606083018486614899565b9695505050505050565b5f82601f830112614901575f5ffd5b815161490f6142eb826142a8565b818152846020838601011115614923575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b5f6020828403121561494f575f5ffd5b81516001600160401b03811115614964575f5ffd5b61083b848285016148f2565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b5f602082840312156149a6575f5ffd5b5051919050565b5f5f858511156149bb575f5ffd5b838611156149c7575f5ffd5b5050820193919092039150565b80356bffffffffffffffffffffffff198116906014841015614a1a576bffffffffffffffffffffffff196bffffffffffffffffffffffff198560140360031b1b82161691505b5092915050565b838152606060208201525f614a396060830185614613565b82810360408401526148e88185614613565b60018060a01b0384168152826020820152606060408201525f614a716060830184614613565b95945050505050565b5f60208284031215614a8a575f5ffd5b8151610bd181614768565b80516001600160a01b03168252602081015160208301525f60408201516101206040850152614ac8610120850182614613565b905060608301518482036060860152614ae18282614613565b9150506080830151608085015260a083015160a085015260c083015160c085015260e083015184820360e0860152614b198282614613565b915050610100830151848203610100860152614a718282614613565b604081525f614b476040830185614a95565b90508260208301529392505050565b5f60208284031215614b66575f5ffd5b8135610bd18161413e565b5f5f8335601e19843603018112614b86575f5ffd5b8301803591506001600160401b03821115614b9f575f5ffd5b6020019150600581901b360382131561061a575f5ffd5b5f60208284031215614bc6575f5ffd5b610bd182614827565b805160208201516001600160d01b03198116919060068210156116ec576001600160d01b031960069290920360031b82901b161692915050565b634e487b7160e01b5f52603260045260245ffd5b5f8235603e19833603018112614c31575f5ffd5b9190910192915050565b8381526001600160a01b03831660208201526060604082018190525f90614a7190830184614613565b6001600160f81b031991909116815260200190565b634e487b7160e01b5f52602160045260245ffd5b60028110614ca957634e487b7160e01b5f52602160045260245ffd5b9052565b60018060a01b0385168152836020820152608060408201525f614cd36080830185614613565b9050614a716060830184614c8d565b80518015158114610d68575f5ffd5b5f5f60408385031215614d02575f5ffd5b614d0b83614ce2565b915060208301516001600160401b03811115614d25575f5ffd5b614d31858286016148f2565b9150509250929050565b6001600160a01b03831681526040602082018190525f9061083b90830184614613565b5f60208284031215614d6e575f5ffd5b610bd182614ce2565b803560028110610d68575f5ffd5b5f5f60408385031215614d96575f5ffd5b614d9f83614d77565b9150602083013561460881614768565b5f5f60408385031215614dc0575f5ffd5b825160208401519092506001600160401b03811115614d25575f5ffd5b8281525f82518060208501602085015e5f92016020019182525092915050565b606081525f614e0f6060830186614a95565b60208301949094525060400152919050565b60ff8416815260406020820181905281018290525f8360608301825b85811015614e6d578235614e508161413e565b6001600160a01b0316825260209283019290910190600101614e3d565b509695505050505050565b5f5f8335601e19843603018112614e8d575f5ffd5b8301803591506001600160401b03821115614ea6575f5ffd5b60200191503681900382131561061a575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b5f60018201614edf57614edf614eba565b5060010190565b8181038181111561072a5761072a614eba565b5f5f5f60608486031215614f0b575f5ffd5b8335614f1681614768565b925060208401356001600160f81b031981168114614f32575f5ffd5b915060408401356001600160401b03811115614f4c575f5ffd5b614f58868287016142ce565b9150509250925092565b5f5f5f60608486031215614f74575f5ffd5b614f7d84614d77565b92506020840135614f3281614768565b5f5f60408385031215614f9e575f5ffd5b8235915060208301356001600160401b03811115614fba575f5ffd5b614d31858286016142ce565b5f5f60408385031215614fd7575f5ffd5b8235614fe28161413e565b915060208301356001600160401b03811115614fba575f5ffd5b5f5f6040838503121561500d575f5ffd5b8235614fe281614768565b602080825281018290525f6040600584901b830181019083018583605e1936839003015b878210156150eb57868503603f19018452823581811261505a575f5ffd5b890180356150678161413e565b6001600160a01b0316865260208181013590870152604081013536829003601e19018112615093575f5ffd5b016020810190356001600160401b038111156150ad575f5ffd5b8036038213156150bb575f5ffd5b606060408801526150d0606088018284614899565b9650505060208301925060208401935060018201915061503c565b5092979650505050505050565b8035602083101561072a575f19602084900360031b1b1692915050565b5f6001600160401b0382111561512d5761512d61423b565b5060051b60200190565b5f82601f830112615146575f5ffd5b81516151546142eb82615115565b8082825260208201915060208360051b860101925085831115615175575f5ffd5b602085015b838110156151b55780516001600160401b03811115615197575f5ffd5b6151a6886020838a01016148f2565b8452506020928301920161517a565b5095945050505050565b5f602082840312156151cf575f5ffd5b81516001600160401b038111156151e4575f5ffd5b61083b84828501615137565b5f5f60408385031215615201575f5ffd5b82516001600160401b03811115615216575f5ffd5b8301601f81018513615226575f5ffd5b80516152346142eb82615115565b8082825260208201915060208360051b850101925087831115615255575f5ffd5b6020840193505b8284101561527e5761526d84614ce2565b82526020938401939091019061525c565b8095505050505060208301516001600160401b0381111561529d575f5ffd5b614d318582860161513756feb8bc84bd77f5eb08210b8eb20fd63b3ec6a7992d277ab94663bae0e066f792aca264697066735822122057e35612c96749b4d4d6b3f02cc1e78c7c3495436185ad1901de41fed60d2a6464736f6c634300081c00336080604052348015600e575f5ffd5b5061096c8061001c5f395ff3fe608060405234801561000f575f5ffd5b506004361061007a575f3560e01c80636a221657116100585780636a221657146100cf57806378272525146100e25780639517e29f146100f55780639abb6e1714610108575f5ffd5b80633f707e6b1461007e57806350c890221461009357806361085573146100a6575b5f5ffd5b61009161008c3660046105a0565b610129565b005b6100916100a13660046105a0565b610192565b6100b96100b43660046105a0565b6101f6565b6040516100c6919061068b565b60405180910390f35b6100916100dd3660046106d3565b6102b7565b6100916100f0366004610797565b6102d8565b610091610103366004610797565b61037c565b61011b6101163660046105a0565b610416565b6040516100c692919061081a565b805f5b8181101561018c573684848381811061014757610147610873565b90506020028101906101599190610887565b905061018261016b60208301836108a5565b602083013561017d60408501856108be565b61053f565b505060010161012c565b50505050565b805f5b8181101561018c57368484838181106101b0576101b0610873565b90506020028101906101c29190610887565b90506101eb6101d460208301836108a5565b60208301356101e660408501856108be565b610572565b505050600101610195565b6060818067ffffffffffffffff811115610212576102126106bf565b60405190808252806020026020018201604052801561024557816020015b60608152602001906001900390816102305790505b5091505f5b818110156102af573685858381811061026557610265610873565b90506020028101906102779190610887565b905061028961016b60208301836108a5565b84838151811061029b5761029b610873565b60209081029190910101525060010161024a565b505092915050565b6040515f5f835160208501865afa3d5f833e80156102d3573d82f35b503d81fd5b604051638a91b0e360e01b81526001600160a01b03841690638a91b0e3906103069085908590600401610908565b5f604051808303815f87803b15801561031d575f5ffd5b505af115801561032f573d5f5f3e3d5ffd5b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e93500190505b60405180910390a150505050565b6040516306d61fe760e41b81526001600160a01b03841690636d61fe70906103aa9085908590600401610908565b5f604051808303815f87803b1580156103c1575f5ffd5b505af11580156103d3573d5f5f3e3d5ffd5b5050604080518781526001600160a01b03871660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905061036e565b606080828067ffffffffffffffff811115610433576104336106bf565b60405190808252806020026020018201604052801561046657816020015b60608152602001906001900390816104515790505b5091508067ffffffffffffffff811115610482576104826106bf565b6040519080825280602002602001820160405280156104ab578160200160208202803683370190505b5092505f5b8181101561053657368686838181106104cb576104cb610873565b90506020028101906104dd9190610887565b90506104ef6101d460208301836108a5565b86848151811061050157610501610873565b6020026020010186858151811061051a5761051a610873565b60209081029190910101919091529015159052506001016104b0565b50509250929050565b604051818382375f38838387895af161055a573d5f823e3d81fd5b3d8152602081013d5f823e3d01604052949350505050565b6040515f90828482375f388483888a5af191503d8152602081013d5f823e3d81016040525094509492505050565b5f5f602083850312156105b1575f5ffd5b823567ffffffffffffffff8111156105c7575f5ffd5b8301601f810185136105d7575f5ffd5b803567ffffffffffffffff8111156105ed575f5ffd5b8560208260051b8401011115610601575f5ffd5b6020919091019590945092505050565b5f82825180855260208501945060208160051b830101602085015f5b8381101561067f57601f19858403018852815180518085528060208301602087015e5f602082870101526020601f19601f8301168601019450505060208201915060208801975060018101905061062d565b50909695505050505050565b602081525f61069d6020830184610611565b9392505050565b80356001600160a01b03811681146106ba575f5ffd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156106e4575f5ffd5b6106ed836106a4565b9150602083013567ffffffffffffffff811115610708575f5ffd5b8301601f81018513610718575f5ffd5b803567ffffffffffffffff811115610732576107326106bf565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610761576107616106bf565b604052818152828201602001871015610778575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f5f5f5f606085870312156107aa575f5ffd5b843593506107ba602086016106a4565b9250604085013567ffffffffffffffff8111156107d5575f5ffd5b8501601f810187136107e5575f5ffd5b803567ffffffffffffffff8111156107fb575f5ffd5b87602082840101111561080c575f5ffd5b949793965060200194505050565b604080825283519082018190525f9060208501906060840190835b818110156108555783511515835260209384019390920191600101610835565b505083810360208501526108698186610611565b9695505050505050565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e1983360301811261089b575f5ffd5b9190910192915050565b5f602082840312156108b5575f5ffd5b61069d826106a4565b5f5f8335601e198436030181126108d3575f5ffd5b83018035915067ffffffffffffffff8211156108ed575f5ffd5b602001915036819003821315610901575f5ffd5b9250929050565b60208152816020820152818360408301375f818301604090810191909152601f909201601f1916010191905056fea264697066735822122022c9b200e3f870ce04690a2b55157c10e84d8f3789b97d1df9409e173a99a39764736f6c634300081c0033"; + bytes public constant SAFE7579_LAUNCHPAD_BYTECODE = + hex"60e060405234801561000f575f5ffd5b50604051612d0b380380612d0b83398101604081905261002e91610087565b6001600160a01b03821661005557604051632039d3c960e01b815260040160405180910390fd5b306080526001600160a01b0391821660a0521660c0526100bf565b6001600160a01b0381168114610084575f5ffd5b50565b5f5f60408385031215610098575f5ffd5b82516100a381610070565b60208401519092506100b481610070565b809150509250929050565b60805160a05160c051612beb6101205f395f8181610151015281816104720152610ede01525f81816101a10152818161059901528181610fb901526112e701525f818160f0015281816105440152818161095501526110210152612beb5ff3fe6080604052600436106100e7575f3560e01c8063663c87d811610087578063d78343d911610057578063d78343d914610335578063d9ed0e8f14610354578063f2dc691d14610373578063f698da2514610392575f5ffd5b8063663c87d81461027d578063928107f91461029c5780639cfd7cff146102bb578063d03c791414610306575f5ffd5b806319822f7c116100c257806319822f7c146101e25780633c9de1b81461020f5780634fff40e11461022f57806355d559f41461024e575f5ffd5b806306433b1b14610140578063137e051e1461019057806315cca638146101c3575f5ffd5b3661013c575f547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161461013a576040516308e3edd160e41b815260040160405180910390fd5b005b5f5ffd5b34801561014b575f5ffd5b506101737f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019b575f5ffd5b506101737f000000000000000000000000000000000000000000000000000000000000000081565b3480156101ce575f5ffd5b5061013a6101dd36600461198b565b6103a6565b3480156101ed575f5ffd5b506102016101fc366004611a75565b61053f565b604051908152602001610187565b34801561021a575f5ffd5b505f516020612b965f395f51905f5254610201565b34801561023a575f5ffd5b5061013a610249366004611ac3565b610951565b348015610259575f5ffd5b5061026d610268366004611c70565b610a79565b6040516101879493929190611dd4565b348015610288575f5ffd5b50610173610297366004611e1f565b610c3a565b3480156102a7575f5ffd5b506102016102b636600461200f565b610d13565b3480156102c6575f5ffd5b50604080518082018252601a81527f7268696e6573746f6e652e73616665373537392e76312e302e30000000000000602082015290516101879190612135565b348015610311575f5ffd5b50610325610320366004612147565b610d64565b6040519015158152602001610187565b348015610340575f5ffd5b5061013a61034f36600461215e565b610e12565b34801561035f575f5ffd5b5061013a61036e36600461227e565b610fae565b34801561037e575f5ffd5b5061032561038d366004612147565b611226565b34801561039d575f5ffd5b50610201611273565b3330146103c657604051630a57d61d60e01b815260040160405180910390fd5b60405163610b592560e01b81526001600160a01b038b166004820152309063610b5925906024015f604051808303815f87803b158015610404575f5ffd5b505af1158015610416573d5f5f3e3d5ffd5b5050604080515f8082526020820190925230935063540fb4f992509061045e565b604080518082019091525f8152606060208201528152602001906001900390816104375790505b508b8b8b8b8b8b60405180606001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018d8d808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050509082525060ff8c166020909101526040516001600160e01b031960e08b901b1681526105069897969594939291906004016124a8565b5f604051808303815f87803b15801561051d575f5ffd5b505af115801561052f573d5f5f3e3d5ffd5b5050505050505050505050505050565b5f80547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161461058e576040516308e3edd160e41b815260040160405180910390fd5b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146105d757604051632039d3c960e01b815260040160405180910390fd5b6105e4606085018561251a565b6105f2916004915f9161255c565b6105fb91612583565b6001600160e01b03191663d9ed0e8f60e01b1461062b5760405163c3d40f7760e01b815260040160405180910390fd5b5f610639606086018661251a565b61064791600490829061255c565b810190610654919061200f565b905061066b5f516020612b965f395f51905f525490565b61067482610d13565b146106925760405163278328b160e21b815260040160405180910390fd5b5f5f866020013590508060601c91505f8360a001516001600160a01b03168460c001516040516024016106c591906125bb565b60408051601f19818403018152918152602080830180516001600160e01b0316633cd56b0760e11b17905290516106ff92913391016125e4565b60408051601f19818403018152908290526107199161260b565b5f604051808303815f865af19150503d805f8114610752576040519150601f19603f3d011682016040523d82523d5f602084013e610757565b606091505b50509050806107795760405163c3d40f7760e01b815260040160405180910390fd5b60c0840151515f90815b81811015610893575f8760c0015182815181106107a2576107a2612616565b60200260200101515f01519050806001600160a01b0316636d61fe708960c0015184815181106107d4576107d4612616565b6020026020010151602001516040518263ffffffff1660e01b81526004016107fc9190612135565b5f604051808303815f87803b158015610813575f5ffd5b505af1158015610825573d5f5f3e3d5ffd5b505060408051600181526001600160a01b03851660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905060405180910390a1866001600160a01b0316816001600160a01b03160361088a57600193505b50600101610783565b50811561090f57604051639700320360e01b81526001600160a01b038616906397003203906108c8908d908d90600401612709565b6020604051808303815f875af11580156108e4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610908919061272a565b9650610934565b5f5f5f61091c898e6112cb565b92509250925061092e83158383611437565b99505050505b8715610944575f5f5f5f8b335af1505b5050505050509392505050565b5f547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161461099f576040516308e3edd160e41b815260040160405180910390fd5b5f6109b55f516020612b965f395f51905f525490565b146109d35760405163d4d496e560e01b815260040160405180910390fd5b6109e8845f516020612b965f395f51905f5255565b6001600160a01b03831615610a73575f836001600160a01b03168383604051610a12929190612741565b5f60405180830381855af49150503d805f8114610a4a576040519150601f19603f3d011682016040523d82523d5f602084013e610a4f565b606091505b5050905080610a7157604051631f57fed560e31b815260040160405180910390fd5b505b50505050565b6101008201516060905f9081908390610a948184600661146f565b610a9d90612750565b60d01c9350610aaf816006600c61146f565b610ab890612750565b60d01c9250610ac881600c6114d4565b9150505f604051806101c001604052807fc03dfc11d8b10bf9cf703d558958c8c42777f785d998c62060d85a4f0ef6ea7f5f1b8152602001885f01516001600160a01b031681526020018860200151815260200188604001518051906020012081526020018860600151805190602001208152602001610b47896114e2565b6001600160801b03168152602001610b5e896114f7565b6001600160801b031681526020018860a001518152602001610b7f8961150c565b6001600160801b03168152602001610b968961151b565b6001600160801b0316815260e089015180516020918201209082015265ffffffffffff8087166040830152851660608201526001600160a01b0388166080909101526101c08120909150601960f81b600160f81b610bf2611273565b6040516001600160f81b031993841660208201529290911660218301526022820152604281018290526062016040516020818303038152906040529550505092959194509250565b5f818051906020012083604051602001610c5e929190918252602082015260400190565b60405160208183030381529060405280519060200120925060ff60f81b858486896001600160a01b0316604051602001610c9992919061278a565b60405160208183030381529060405280519060200120604051602001610cf194939291906001600160f81b031994909416845260609290921b6001600160601b03191660018401526015830152603582015260550190565b60408051601f1981840301815291905280516020909101209695505050505050565b80516020808301516040808501516060860151608087015160a088015160c089015194515f98610d479890979691016127a2565b604051602081830303815290604052805190602001209050919050565b5f81600881901b6001600160f81b03198216600160f81b03610d895760019250610dc4565b6001600160f81b03198216610da15760019250610dc4565b6001600160f81b031980831603610dbb5760019250610dc4565b505f9392505050565b828015610dd957506001600160f81b03198116155b15610de5575050919050565b828015610dff57506001600160f81b03198116600160f81b145b15610dbb575050919050565b5050919050565b60405163610b592560e01b81526001600160a01b038d166004820152309063610b5925906024015f604051808303815f87803b158015610e50575f5ffd5b505af1158015610e62573d5f5f3e3d5ffd5b505060405163f08a032360e01b81526001600160a01b038f16600482015230925063f08a032391506024015f604051808303815f87803b158015610ea4575f5ffd5b505af1158015610eb6573d5f5f3e3d5ffd5b50505050306001600160a01b031663540fb4f98c8c8c8c8c8c8c8c60405180606001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018e8e808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050509082525060ff8d166020909101526040516001600160e01b031960e08c901b168152610f739998979695949392919060040161281e565b5f604051808303815f87803b158015610f8a575f5ffd5b505af1158015610f9c573d5f5f3e3d5ffd5b50505050505050505050505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610ff757604051632039d3c960e01b815260040160405180910390fd5b6110046020820182612892565b5f80546001600160a01b0319166001600160a01b039283161790557f0000000000000000000000000000000000000000000000000000000000000000166110516080830160608401612892565b6001600160a01b03161461107857604051633007073760e01b815260040160405180910390fd5b6302b994c760e31b61108d608083018361251a565b61109b916004915f9161255c565b6110a491612583565b6001600160e01b031916146110cc57604051633007073760e01b815260040160405180910390fd5b3063b63e800d6110df60208401846128ad565b60408501356110f46080870160608801612892565b611101608088018861251a565b61111160c08a0160a08b01612892565b5f5f5f6040518b63ffffffff1660e01b81526004016111399a999897969594939291906128f2565b5f604051808303815f87803b158015611150575f5ffd5b505af1158015611162573d5f5f3e3d5ffd5b50505f5f516020612b965f395f51905f52555061117c9050565b5f8061118e60c0840160a08501612892565b6001600160a01b03166111a460e085018561251a565b306040516020016111b7939291906129a8565b60408051601f19818403018152908290526111d19161260b565b5f604051808303815f865af19150503d805f811461120a576040519150601f19603f3d011682016040523d82523d5f602084013e61120f565b606091505b50915091508161122157805160208201fd5b505050565b5f6001820361123757506001919050565b6002820361124757506001919050565b6003820361125757506001919050565b6004820361126757506001919050565b505f919050565b919050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218602082015246918101919091523060608201525f9060800160405160208183030381529060405280519060200120905090565b5f5f5f6060808660a001516001600160a01b03166355d559f4877f00000000000000000000000000000000000000000000000000000000000000006040518363ffffffff1660e01b81526004016113239291906129c9565b5f60405180830381865afa15801561133d573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526113649190810190612a54565b8351602085012060408c0151929850929650929450919250905f9061138c9083908590611530565b9050611397816116de565b60208901516113a5816116de565b6113ae816116ea565b80515f805b82811015611424575f6113e88583815181106113d1576113d1612616565b6020026020010151876116f390919063ffffffff16565b509050801561141b57826113fb81612aeb565b9350508d60400151831061141b5760019b50505050505050505050611430565b506001016113b3565b505f9950505050505050505b9250925092565b5f60d08265ffffffffffff16901b60a08465ffffffffffff16901b8561145d575f611460565b60015b60ff16171790505b9392505050565b6060835182811161147e578092505b838111611489578093505b50818310156114685750604051828203848401601f19601f830181165b82810151858201528101806114a6575050508060208301015f81526020810160405250808252509392505050565b606061146883835f1961146f565b5f6114f1826080015160801c90565b92915050565b5f6114f182608001516001600160801b031690565b5f6114f18260c0015160801c90565b5f6114f18260c001516001600160801b031690565b81516060905f611541604183612b03565b9050806001600160401b0381111561155b5761155b611b46565b604051908082528060200260200182016040528015611584578160200160208202803683370190505b509250838110156115a857604051638baa579f60e01b815260040160405180910390fd5b5f5f5b828110156116b2575f5f5f5f6115d88b8660410201602081015160408201516060909201515f1a92909190565b9250925092508260ff165f036115fc576115f58c8c84848c611714565b935061165a565b601e8360ff16111561164b576115f56116398d6020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c60042090565b611644600486612b22565b84846117dc565b6116578c8484846117dc565b93505b6001600160a01b03841615611677578561167381612aeb565b9650505b8389868151811061168a5761168a612616565b6001600160a01b03909216602092830291909101909101525050600190920191506115ab9050565b50848110156116d457604051638baa579f60e01b815260040160405180910390fd5b5050509392505050565b6116e781611816565b50565b6116e78161186b565b5f8061170984846001600160a01b03165f6118b4565b909590945092505050565b838201602001518390826117288583612b3b565b611733906020612b3b565b1115611742575f9150506117d3565b604051630b135d3f60e11b808252878601602001916001600160a01b03851690631626ba7e90611778908c908690600401612b4e565b602060405180830381865afa158015611793573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117b79190612b6e565b6001600160e01b031916146117d0575f925050506117d3565b50505b95945050505050565b5f604051855f5260ff851660205283604052826060526020604060805f60015afa505f6060523d6060185191508060405250949350505050565b80515f82528060051b8201601f19602084015b602001828111611864578051828201805182811161184957505050611829565b5b60208201528301805182811161184a575060200152611829565b5050509052565b60028151106116e7576020810160408201600183510160051b83015b815183511461189b57602083019250815183525b60208201915080820361188757505081900360051c9052565b5f5f5f19600186515f87870197505b81830160011c94508460051b89015187019050878114828411176118fd578088116118f25783850191506118c3565b6001850192506118c3565b84151597148716989290930190950295509350505050565b6001600160a01b03811681146116e7575f5ffd5b803561126e81611915565b5f5f83601f840112611944575f5ffd5b5081356001600160401b0381111561195a575f5ffd5b6020830191508360208260051b8501011115611974575f5ffd5b9250929050565b803560ff8116811461126e575f5ffd5b5f5f5f5f5f5f5f5f5f5f60c08b8d0312156119a4575f5ffd5b6119ad8b611929565b995060208b01356001600160401b038111156119c7575f5ffd5b6119d38d828e01611934565b909a5098505060408b01356001600160401b038111156119f1575f5ffd5b6119fd8d828e01611934565b90985096505060608b01356001600160401b03811115611a1b575f5ffd5b611a278d828e01611934565b90965094505060808b01356001600160401b03811115611a45575f5ffd5b611a518d828e01611934565b9094509250611a64905060a08c0161197b565b90509295989b9194979a5092959850565b5f5f5f60608486031215611a87575f5ffd5b83356001600160401b03811115611a9c575f5ffd5b84016101208187031215611aae575f5ffd5b95602085013595506040909401359392505050565b5f5f5f5f60608587031215611ad6575f5ffd5b843593506020850135611ae881611915565b925060408501356001600160401b03811115611b02575f5ffd5b8501601f81018713611b12575f5ffd5b80356001600160401b03811115611b27575f5ffd5b876020828401011115611b38575f5ffd5b949793965060200194505050565b634e487b7160e01b5f52604160045260245ffd5b60405161012081016001600160401b0381118282101715611b7d57611b7d611b46565b60405290565b604080519081016001600160401b0381118282101715611b7d57611b7d611b46565b60405161010081016001600160401b0381118282101715611b7d57611b7d611b46565b604051601f8201601f191681016001600160401b0381118282101715611bf057611bf0611b46565b604052919050565b5f6001600160401b03821115611c1057611c10611b46565b50601f01601f191660200190565b5f82601f830112611c2d575f5ffd5b8135611c40611c3b82611bf8565b611bc8565b818152846020838601011115611c54575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f60408385031215611c81575f5ffd5b82356001600160401b03811115611c96575f5ffd5b83016101208186031215611ca8575f5ffd5b611cb0611b5a565b611cb982611929565b81526020828101359082015260408201356001600160401b03811115611cdd575f5ffd5b611ce987828501611c1e565b60408301525060608201356001600160401b03811115611d07575f5ffd5b611d1387828501611c1e565b6060830152506080828101359082015260a0808301359082015260c0808301359082015260e08201356001600160401b03811115611d4f575f5ffd5b611d5b87828501611c1e565b60e0830152506101008201356001600160401b03811115611d7a575f5ffd5b611d8687828501611c1e565b610100830152509250611d9d905060208401611929565b90509250929050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b608081525f611de66080830187611da6565b65ffffffffffff8616602084015265ffffffffffff851660408401528281036060840152611e148185611da6565b979650505050505050565b5f5f5f5f5f60a08688031215611e33575f5ffd5b8535611e3e81611915565b94506020860135611e4e81611915565b935060408601356001600160401b03811115611e68575f5ffd5b611e7488828901611c1e565b9350506060860135915060808601356001600160401b03811115611e96575f5ffd5b611ea288828901611c1e565b9150509295509295909350565b5f6001600160401b03821115611ec757611ec7611b46565b5060051b60200190565b5f82601f830112611ee0575f5ffd5b8135611eee611c3b82611eaf565b8082825260208201915060208360051b860101925085831115611f0f575f5ffd5b602085015b83811015611f35578035611f2781611915565b835260209283019201611f14565b5095945050505050565b5f82601f830112611f4e575f5ffd5b8135611f5c611c3b82611eaf565b8082825260208201915060208360051b860101925085831115611f7d575f5ffd5b602085015b83811015611f355780356001600160401b03811115611f9f575f5ffd5b86016040818903601f19011215611fb4575f5ffd5b611fbc611b83565b6020820135611fca81611915565b815260408201356001600160401b03811115611fe4575f5ffd5b611ff38a602083860101611c1e565b6020830152508085525050602083019250602081019050611f82565b5f6020828403121561201f575f5ffd5b81356001600160401b03811115612034575f5ffd5b82016101008185031215612046575f5ffd5b61204e611ba5565b61205782611929565b815260208201356001600160401b03811115612071575f5ffd5b61207d86828501611ed1565b6020830152506040828101359082015261209960608301611929565b606082015260808201356001600160401b038111156120b6575f5ffd5b6120c286828501611c1e565b6080830152506120d460a08301611929565b60a082015260c08201356001600160401b038111156120f1575f5ffd5b6120fd86828501611f3f565b60c08301525060e08201356001600160401b0381111561211b575f5ffd5b61212786828501611c1e565b60e083015250949350505050565b602081525f6114686020830184611da6565b5f60208284031215612157575f5ffd5b5035919050565b5f5f5f5f5f5f5f5f5f5f5f5f60e08d8f031215612179575f5ffd5b6121828d611929565b9b506001600160401b0360208e0135111561219b575f5ffd5b6121ab8e60208f01358f01611934565b909b5099506001600160401b0360408e013511156121c7575f5ffd5b6121d78e60408f01358f01611934565b90995097506001600160401b0360608e013511156121f3575f5ffd5b6122038e60608f01358f01611934565b90975095506001600160401b0360808e0135111561221f575f5ffd5b61222f8e60808f01358f01611934565b90955093506001600160401b0360a08e0135111561224b575f5ffd5b61225b8e60a08f01358f01611934565b909350915061226c60c08e0161197b565b90509295989b509295989b509295989b565b5f6020828403121561228e575f5ffd5b81356001600160401b038111156122a3575f5ffd5b82016101008185031215611468575f5ffd5b5f82825180855260208501945060208160051b830101602085015f5b8381101561232357848303601f19018852815180516001600160a01b0316845260209081015160409185018290529061230c90850182611da6565b6020998a01999094509290920191506001016122d1565b50909695505050505050565b5f5f8335601e19843603018112612344575f5ffd5b83016020810192503590506001600160401b03811115612362575f5ffd5b803603821315611974575f5ffd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f8383855260208501945060208460051b820101835f5b8681101561232357838303601f19018852813536879003603e190181126123d4575f5ffd5b860180356123e181611915565b6001600160a01b031684526123f9602082018261232f565b915060406020860152612410604086018383612370565b60209a8b019a909550939093019250506001016123af565b5f8151808452602084019350602083015f5b828110156124615781516001600160a01b031686526020958601959091019060010161243a565b5093949350505050565b60018060a01b0381511682525f6020820151606060208501526124916060850182612428565b60409384015160ff16949093019390935250919050565b60a081525f6124ba60a083018b6122b5565b82810360208401526124cd818a8c612398565b905082810360408401526124e281888a612398565b905082810360608401526124f7818688612398565b9050828103608084015261250b818561246b565b9b9a5050505050505050505050565b5f5f8335601e1984360301811261252f575f5ffd5b8301803591506001600160401b03821115612548575f5ffd5b602001915036819003821315611974575f5ffd5b5f5f8585111561256a575f5ffd5b83861115612576575f5ffd5b5050820193919092039150565b80356001600160e01b031981169060048410156125b4576001600160e01b0319600485900360031b81901b82161691505b5092915050565b602081525f61146860208301846122b5565b5f81518060208401855e5f93019283525090919050565b5f6125ef82856125cd565b60609390931b6001600160601b03191683525050601401919050565b5f61146882846125cd565b634e487b7160e01b5f52603260045260245ffd5b6126448261263783611929565b6001600160a01b03169052565b602081810135908301525f61265c604083018361232f565b610120604086015261267361012086018284612370565b915050612683606084018461232f565b8583036060870152612696838284612370565b6080868101359088015260a0808701359088015260c0808701359088015292506126c691505060e084018461232f565b85830360e08701526126d9838284612370565b925050506126eb61010084018461232f565b8583036101008701526126ff838284612370565b9695505050505050565b604081525f61271b604083018561262a565b90508260208301529392505050565b5f6020828403121561273a575f5ffd5b5051919050565b818382375f9101908152919050565b805160208201516001600160d01b0319811691906006821015610e0b576001600160d01b031960069290920360031b82901b161692915050565b5f61279582856125cd565b9283525050602001919050565b6001600160a01b038816815260e0602082018190525f906127c590830189612428565b604083018890526001600160a01b038716606084015282810360808401526127ed8187611da6565b6001600160a01b03861660a085015283810360c0850152905061281081856122b5565b9a9950505050505050505050565b60a081525f61283160a083018b8d612398565b8281036020840152612844818a8c612398565b9050828103604084015261285981888a612398565b9050828103606084015261286e818688612398565b90508281036080840152612882818561246b565b9c9b505050505050505050505050565b5f602082840312156128a2575f5ffd5b813561146881611915565b5f5f8335601e198436030181126128c2575f5ffd5b8301803591506001600160401b038211156128db575f5ffd5b6020019150600581901b3603821315611974575f5ffd5b61010080825281018a90525f8b6101208301825b8d81101561293657823561291981611915565b6001600160a01b0316825260209283019290910190600101612906565b508b6020850152612952604085018c6001600160a01b03169052565b8381036060850152612965818a8c612370565b9250505061297e60808301876001600160a01b03169052565b6001600160a01b03851660a08301528360c083015261250b60e08301846001600160a01b03169052565b8284823760609190911b6001600160601b0319169101908152601401919050565b604081525f6129db604083018561262a565b905060018060a01b03831660208301529392505050565b5f82601f830112612a01575f5ffd5b8151612a0f611c3b82611bf8565b818152846020838601011115612a23575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b805165ffffffffffff8116811461126e575f5ffd5b5f5f5f5f60808587031215612a67575f5ffd5b84516001600160401b03811115612a7c575f5ffd5b612a88878288016129f2565b945050612a9760208601612a3f565b9250612aa560408601612a3f565b915060608501516001600160401b03811115612abf575f5ffd5b612acb878288016129f2565b91505092959194509250565b634e487b7160e01b5f52601160045260245ffd5b5f60018201612afc57612afc612ad7565b5060010190565b5f82612b1d57634e487b7160e01b5f52601260045260245ffd5b500490565b60ff82811682821603908111156114f1576114f1612ad7565b808201808211156114f1576114f1612ad7565b828152604060208201525f612b666040830184611da6565b949350505050565b5f60208284031215612b7e575f5ffd5b81516001600160e01b031981168114611468575f5ffdfe982e06ee6a56dfc0f1ac189a5d23506361ca0a3ce45a9c7b8d33d65d43746a24a2646970667358221220cbd281b9702b507f3035a563b8dd778e1de241408898a1097f986f9f583f684964736f6c634300081c0033"; + bytes public constant SAFE_PROXY_BYTECODE = + hex"6080604052348015600e575f5ffd5b50604051610163380380610163833981016040819052602b9160b2565b6001600160a01b038116608f5760405162461bcd60e51b815260206004820152602260248201527f496e76616c69642073696e676c65746f6e20616464726573732070726f766964604482015261195960f21b606482015260840160405180910390fd5b5f80546001600160a01b0319166001600160a01b039290921691909117905560dd565b5f6020828403121560c1575f5ffd5b81516001600160a01b038116811460d6575f5ffd5b9392505050565b607a806100e95f395ff3fe60806040525f80546001600160a01b03169035632cf35bc960e11b01602657805f5260205ff35b365f5f375f5f365f845af490503d5f5f3e80603f573d5ffd5b503d5ff3fea2646970667358221220640def201af13e0821a9dcaf5c656634c958a7cf37a69d829387126c436276e364736f6c634300081c0033"; + bytes public constant SAFE_SINGLETON_BYTECODE = + hex"6080604052348015600e575f80fd5b506001600455612fad806100215f395ff3fe6080604052600436106101d0575f3560e01c8063affed0e0116100f6578063e19a9dd911610094578063f08a032311610063578063f08a0323146105d2578063f698da25146105f1578063f8dc5dd914610605578063ffa1ad74146106245761020c565b8063e19a9dd914610561578063e318b52b14610580578063e75235b81461059f578063e86637db146105b35761020c565b8063cc2f8452116100d0578063cc2f8452146104d7578063d4d9bdcd14610504578063d8d11f7814610523578063e009cfde146105425761020c565b8063affed0e014610484578063b4faba0914610499578063b63e800d146104b85761020c565b80635624b25b1161016e5780636a7612021161013d5780636a761202146103fb5780637d8329741461040e578063934f3a1114610444578063a0e67e2b146104635761020c565b80635624b25b146103665780635ae6bd3714610392578063610b5925146103bd578063694e80c3146103dc5761020c565b80632f54bf6e116101aa5780632f54bf6e146102df5780633408e470146102fe578063468721a71461031a5780635229073f146103395761020c565b80630d582f131461026b57806312fb68e01461028c5780632d9ad53d146102ab5761020c565b3661020c5760405134815233907f3d0ce9bfc3ed7d6862dbb28b2dea94561fe714a1b4d019aa8af39730d1ad7c3d9060200160405180910390a2005b348015610217575f80fd5b507f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d580548061024257005b365f80373360601b36525f80601436015f80855af190503d5f803e80610266573d5ffd5b503d5ff35b348015610276575f80fd5b5061028a610285366004612507565b610654565b005b348015610297575f80fd5b5061028a6102a63660046125ce565b6107a9565b3480156102b6575f80fd5b506102ca6102c536600461263e565b610c3a565b60405190151581526020015b60405180910390f35b3480156102ea575f80fd5b506102ca6102f936600461263e565b610c73565b348015610309575f80fd5b50465b6040519081526020016102d6565b348015610325575f80fd5b506102ca610334366004612667565b610ca9565b348015610344575f80fd5b50610358610353366004612667565b610d7d565b6040516102d69291906126fb565b348015610371575f80fd5b50610385610380366004612715565b610db1565b6040516102d69190612735565b34801561039d575f80fd5b5061030c6103ac366004612747565b60076020525f908152604090205481565b3480156103c8575f80fd5b5061028a6103d736600461263e565b610e2b565b3480156103e7575f80fd5b5061028a6103f6366004612747565b610f62565b6102ca6104093660046127a3565b611000565b348015610419575f80fd5b5061030c610428366004612507565b600860209081525f928352604080842090915290825290205481565b34801561044f575f80fd5b5061028a61045e366004612873565b611339565b34801561046e575f80fd5b50610477611383565b6040516102d6919061291e565b34801561048f575f80fd5b5061030c60055481565b3480156104a4575f80fd5b5061028a6104b3366004612930565b611471565b3480156104c3575f80fd5b5061028a6104d236600461297d565b611490565b3480156104e2575f80fd5b506104f66104f1366004612507565b61158f565b6040516102d6929190612a67565b34801561050f575f80fd5b5061028a61051e366004612747565b611747565b34801561052e575f80fd5b5061030c61053d366004612a90565b6117da565b34801561054d575f80fd5b5061028a61055c366004612b49565b611806565b34801561056c575f80fd5b5061028a61057b36600461263e565b611926565b34801561058b575f80fd5b5061028a61059a366004612b80565b611a39565b3480156105aa575f80fd5b5060045461030c565b3480156105be575f80fd5b506103856105cd366004612a90565b611c10565b3480156105dd575f80fd5b5061028a6105ec36600461263e565b611ce7565b3480156105fc575f80fd5b5061030c611d2e565b348015610610575f80fd5b5061028a61061f366004612bc8565b611d84565b34801561062f575f80fd5b5061038560405180604001604052806005815260200164312e342e3160d81b81525081565b61065c611eec565b6001600160a01b0382161580159061067e57506001600160a01b038216600114155b801561069357506001600160a01b0382163014155b6106b85760405162461bcd60e51b81526004016106af90612c06565b60405180910390fd5b6001600160a01b038281165f9081526002602052604090205416156106ef5760405162461bcd60e51b81526004016106af90612c25565b60026020527fe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e080546001600160a01b038481165f818152604081208054939094166001600160a01b03199384161790935560018352835490911617909155600380549161075b83612c58565b90915550506040516001600160a01b038316907f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea26905f90a280600454146107a5576107a581610f62565b5050565b6107b4816041611f25565b825110156107ec5760405162461bcd60e51b8152602060048201526005602482015264047533032360dc1b60448201526064016106af565b5f80805f805f5b86811015610c2e576041818102890160208101516040820151919092015160ff16955090935091505f8490036109fe57885160208a01208a146108605760405162461bcd60e51b8152602060048201526005602482015264475330323760d81b60448201526064016106af565b9193508391610870876041611f25565b8210156108a75760405162461bcd60e51b8152602060048201526005602482015264475330323160d81b60448201526064016106af565b87516108b4836020611f5c565b11156108ea5760405162461bcd60e51b815260206004820152600560248201526423a998191960d91b60448201526064016106af565b60208289018101518951909161090d908390610907908790611f5c565b90611f5c565b11156109435760405162461bcd60e51b8152602060048201526005602482015264475330323360d81b60448201526064016106af565b6040516320c13b0b60e01b8082528a8501602001916001600160a01b038916906320c13b0b90610979908f908690600401612c70565b602060405180830381865afa158015610994573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109b89190612c94565b6001600160e01b031916146109f75760405162461bcd60e51b815260206004820152600560248201526411d4cc0c8d60da1b60448201526064016106af565b5050610b9e565b8360ff16600103610a7f579193508391336001600160a01b0384161480610a4657506001600160a01b0385165f9081526008602090815260408083208d845290915290205415155b610a7a5760405162461bcd60e51b8152602060048201526005602482015264475330323560d81b60448201526064016106af565b610b9e565b601e8460ff161115610b41576040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c81018b9052600190605c0160405160208183030381529060405280519060200120600486610ae49190612cbb565b604080515f8152602081018083529390935260ff90911690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015610b30573d5f803e3d5ffd5b505050602060405103519450610b9e565b604080515f8152602081018083528c905260ff861691810191909152606081018490526080810183905260019060a0016020604051602081039080840390855afa158015610b91573d5f803e3d5ffd5b5050506020604051035194505b856001600160a01b0316856001600160a01b0316118015610bd757506001600160a01b038581165f908152600260205260409020541615155b8015610bed57506001600160a01b038516600114155b610c215760405162461bcd60e51b815260206004820152600560248201526423a998191b60d91b60448201526064016106af565b93945084936001016107f3565b50505050505050505050565b5f60016001600160a01b03831614801590610c6d57506001600160a01b038281165f908152600160205260409020541615155b92915050565b5f6001600160a01b038216600114801590610c6d5750506001600160a01b039081165f9081526002602052604090205416151590565b5f33600114801590610cd15750335f908152600160205260409020546001600160a01b031615155b610d055760405162461bcd60e51b815260206004820152600560248201526411d4cc4c0d60da1b60448201526064016106af565b610d13858585855f19611f76565b90508015610d4a5760405133907f6895c13664aa4f67288b25d7a21d7aaa34916e355fb9b6fae0a139a9085becb8905f90a2610d75565b60405133907facd2c8702804128fdb0db2bb49f6d127dd0181c13fd45dbfe16de0930e2bd375905f90a25b949350505050565b5f6060610d8c86868686610ca9565b915060405160203d0181016040523d81523d5f602083013e8091505094509492505050565b60605f610dbf836020612cd4565b67ffffffffffffffff811115610dd757610dd7612531565b6040519080825280601f01601f191660200182016040528015610e01576020820181803683370190505b5090505f5b83811015610e235784810154602080830284010152600101610e06565b509392505050565b610e33611eec565b6001600160a01b03811615801590610e5557506001600160a01b038116600114155b610e895760405162461bcd60e51b8152602060048201526005602482015264475331303160d81b60448201526064016106af565b6001600160a01b038181165f908152600160205260409020541615610ed85760405162461bcd60e51b815260206004820152600560248201526423a998981960d91b60448201526064016106af565b600160208190527fcc69885fda6bcc1a4ace058b4a62bf5e179ea78fd58a1ccd71c22cc9b688792f80546001600160a01b038481165f81815260408082208054949095166001600160a01b031994851617909455948552835490911681179092555190917fecdf3a3effea5783a3c4c2140e677577666428d44ed9d474a0b3a4c9943f844091a250565b610f6a611eec565b600354811115610f8c5760405162461bcd60e51b81526004016106af90612ceb565b6001811015610fc55760405162461bcd60e51b815260206004820152600560248201526423a999181960d91b60448201526064016106af565b60048190556040518181527f610f7ff2b304ae8903c3de74c60c6ab1f7d6226b3f52c5161905bb5ad4039c939060200160405180910390a150565b5f805f6110188e8e8e8e8e8e8e8e8e8e600554611c10565b600580549192505f61102983612c58565b9091555050805160208201209150611042828286611339565b505f61106c7f4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c85490565b90506001600160a01b038116156110ed57806001600160a01b03166375f0bb528f8f8f8f8f8f8f8f8f8f8f336040518d63ffffffff1660e01b81526004016110bf9c9b9a99989796959493929190612d3e565b5f604051808303815f87803b1580156110d6575f80fd5b505af11580156110e8573d5f803e3d5ffd5b505050505b6111196110fc8a6109c4612e01565b603f6111098c6040612cd4565b6111139190612e14565b90611fba565b611125906101f4612e01565b5a101561115c5760405162461bcd60e51b8152602060048201526005602482015264047533031360dc1b60448201526064016106af565b5f5a90506111ca8f8f8f8f8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050508e8c5f146111b7578e611f76565b6109c45a6111c59190612e33565b611f76565b93506111d75a8290611fd0565b905083806111e457508915155b806111ee57508715155b6112225760405162461bcd60e51b8152602060048201526005602482015264475330313360d81b60448201526064016106af565b5f881561123957611236828b8b8b8b611fe8565b90505b841561127e57837f442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e8260405161127191815260200190565b60405180910390a26112b9565b837f23428b18acfb3ea64b08dc0c1d296ea9c09702c09083ca5272e64d115b687d23826040516112b091815260200190565b60405180910390a25b50506001600160a01b0381161561132857604051631264e26d60e31b81526004810183905283151560248201526001600160a01b038216906393271368906044015f604051808303815f87803b158015611311575f80fd5b505af1158015611323573d5f803e3d5ffd5b505050505b50509b9a5050505050505050505050565b600454806113715760405162461bcd60e51b8152602060048201526005602482015264475330303160d81b60448201526064016106af565b61137d848484846107a9565b50505050565b60605f60035467ffffffffffffffff8111156113a1576113a1612531565b6040519080825280602002602001820160405280156113ca578160200160208202803683370190505b5060015f90815260026020527fe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e054919250906001600160a01b03165b6001600160a01b038116600114611469578083838151811061142a5761142a612e46565b6001600160a01b039283166020918202929092018101919091529181165f9081526002909252604090912054168161146181612c58565b925050611406565b509092915050565b5f80825160208401855af4805f52503d6020523d5f60403e60403d015ffd5b6114cd8a8a808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152508c92506120ec915050565b6001600160a01b038416156114e5576114e5846122c2565b6115248787878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061232692505050565b811561153a57611538825f60018685611fe8565b505b336001600160a01b03167f141df868a6331af528e38c83b7aa03edc19be66e37ae67f9285bf4f8e3c6a1a88b8b8b8b8960405161157b959493929190612e5a565b60405180910390a250505050505050505050565b60605f6001600160a01b038416600114806115ae57506115ae84610c3a565b6115e25760405162461bcd60e51b8152602060048201526005602482015264475331303560d81b60448201526064016106af565b5f83116116195760405162461bcd60e51b815260206004820152600560248201526423a998981b60d91b60448201526064016106af565b8267ffffffffffffffff81111561163257611632612531565b60405190808252806020026020018201604052801561165b578160200160208202803683370190505b506001600160a01b038086165f90815260016020526040812054929450911691505b6001600160a01b0382161580159061169f57506001600160a01b038216600114155b80156116aa57508381105b1561170457818382815181106116c2576116c2612e46565b6001600160a01b039283166020918202929092018101919091529281165f908152600190935260409092205490911690806116fc81612c58565b91505061167d565b6001600160a01b03821660011461173c5782611721600183612e33565b8151811061173157611731612e46565b602002602001015191505b808352509250929050565b335f908152600260205260409020546001600160a01b03166117935760405162461bcd60e51b8152602060048201526005602482015264047533033360dc1b60448201526064016106af565b335f818152600860209081526040808320858452909152808220600190555183917ff2a0eb156472d1440255b0d7c1e19cc07115d1051fe605b0dce69acfec884d9c91a350565b5f6117ee8c8c8c8c8c8c8c8c8c8c8c611c10565b8051906020012090509b9a5050505050505050505050565b61180e611eec565b6001600160a01b0381161580159061183057506001600160a01b038116600114155b6118645760405162461bcd60e51b8152602060048201526005602482015264475331303160d81b60448201526064016106af565b6001600160a01b038281165f908152600160205260409020548116908216146118b75760405162461bcd60e51b8152602060048201526005602482015264475331303360d81b60448201526064016106af565b6001600160a01b038181165f81815260016020526040808220805487861684528284208054919096166001600160a01b0319918216179095558383528054909416909355915190917faab4fa2b463f581b2b32cb3b7e3b704b9ce37cc209b5fb4d77e593ace405427691a25050565b61192e611eec565b6001600160a01b038116156119de576040516301ffc9a760e01b815263736bd41d60e11b60048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa158015611986573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119aa9190612ec5565b6119de5760405162461bcd60e51b8152602060048201526005602482015264047533330360dc1b60448201526064016106af565b7f4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c88181556040516001600160a01b038316907f1151116914515bc0891ff9047a6cb32cf902546f83066499bcf8ba33d2353fa2905f90a25050565b611a41611eec565b6001600160a01b03811615801590611a6357506001600160a01b038116600114155b8015611a7857506001600160a01b0381163014155b611a945760405162461bcd60e51b81526004016106af90612c06565b6001600160a01b038181165f908152600260205260409020541615611acb5760405162461bcd60e51b81526004016106af90612c25565b6001600160a01b03821615801590611aed57506001600160a01b038216600114155b611b095760405162461bcd60e51b81526004016106af90612c06565b6001600160a01b038381165f90815260026020526040902054811690831614611b5c5760405162461bcd60e51b8152602060048201526005602482015264475332303560d81b60448201526064016106af565b6001600160a01b038281165f81815260026020526040808220805486861680855283852080549288166001600160a01b03199384161790559589168452828420805482169096179095558383528054909416909355915190917ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf91a26040516001600160a01b038216907f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea26905f90a2505050565b60605f7fbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d85f1b8d8d8d8d604051611c48929190612ee4565b604051908190038120611c6e949392918e908e908e908e908e908e908e90602001612ef3565b60408051601f1981840301815291905280516020909101209050601960f81b600160f81b611c9a611d2e565b6040516001600160f81b031993841660208201529290911660218301526022820152604281018290526062016040516020818303038152906040529150509b9a5050505050505050505050565b611cef611eec565b611cf8816122c2565b6040516001600160a01b038216907f5ac6c46c93c8d0e53714ba3b53db3e7c046da994313d7ed0d192028bc7c228b0905f90a250565b5f7f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692184660408051602081019390935282015230606082015260800160405160208183030381529060405280519060200120905090565b611d8c611eec565b806001600354611d9c9190612e33565b1015611dba5760405162461bcd60e51b81526004016106af90612ceb565b6001600160a01b03821615801590611ddc57506001600160a01b038216600114155b611df85760405162461bcd60e51b81526004016106af90612c06565b6001600160a01b038381165f90815260026020526040902054811690831614611e4b5760405162461bcd60e51b8152602060048201526005602482015264475332303560d81b60448201526064016106af565b6001600160a01b038281165f81815260026020526040808220805488861684529183208054929095166001600160a01b03199283161790945591815282549091169091556003805491611e9d83612f62565b90915550506040516001600160a01b038316907ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf905f90a28060045414611ee757611ee781610f62565b505050565b333014611f235760405162461bcd60e51b8152602060048201526005602482015264475330333160d81b60448201526064016106af565b565b5f825f03611f3457505f610c6d565b5f611f3f8385612cd4565b905082611f4c8583612e14565b14611f55575f80fd5b9392505050565b5f80611f688385612e01565b905083811015611f55575f80fd5b5f6001836001811115611f8b57611f8b612d0a565b03611fa2575f808551602087018986f49050611fb1565b5f80855160208701888a87f190505b95945050505050565b5f81831015611fc95781611f55565b5090919050565b5f82821115611fdd575f80fd5b5f610d758385612e33565b5f806001600160a01b03831615611fff5782612001565b325b90506001600160a01b038416612093576120333a8610612021573a612023565b855b61202d8989611f5c565b90611f25565b6040519092506001600160a01b0382169083156108fc029084905f818181858888f1935050505061208e5760405162461bcd60e51b8152602060048201526005602482015264475330313160d81b60448201526064016106af565b6120e2565b6120a18561202d8989611f5c565b91506120ae848284612454565b6120e25760405162461bcd60e51b815260206004820152600560248201526423a998189960d91b60448201526064016106af565b5095945050505050565b600454156121245760405162461bcd60e51b8152602060048201526005602482015264047533230360dc1b60448201526064016106af565b81518111156121455760405162461bcd60e51b81526004016106af90612ceb565b600181101561217e5760405162461bcd60e51b815260206004820152600560248201526423a999181960d91b60448201526064016106af565b60015f5b8351811015612290575f84828151811061219e5761219e612e46565b602002602001015190505f6001600160a01b0316816001600160a01b0316141580156121d457506001600160a01b038116600114155b80156121e957506001600160a01b0381163014155b80156122075750806001600160a01b0316836001600160a01b031614155b6122235760405162461bcd60e51b81526004016106af90612c06565b6001600160a01b038181165f90815260026020526040902054161561225a5760405162461bcd60e51b81526004016106af90612c25565b6001600160a01b039283165f90815260026020526040902080546001600160a01b03191693821693909317909255600101612182565b506001600160a01b03165f90815260026020526040902080546001600160a01b03191660011790559051600355600455565b306001600160a01b038216036123025760405162461bcd60e51b8152602060048201526005602482015264047533430360dc1b60448201526064016106af565b7f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d555565b60015f8190526020527fcc69885fda6bcc1a4ace058b4a62bf5e179ea78fd58a1ccd71c22cc9b688792f546001600160a01b03161561238f5760405162461bcd60e51b8152602060048201526005602482015264047533130360dc1b60448201526064016106af565b60015f81905260208190527fcc69885fda6bcc1a4ace058b4a62bf5e179ea78fd58a1ccd71c22cc9b688792f80546001600160a01b03191690911790556001600160a01b038216156107a557813b6124115760405162461bcd60e51b815260206004820152600560248201526423a998181960d91b60448201526064016106af565b612420825f8360015f19611f76565b6107a55760405162461bcd60e51b8152602060048201526005602482015264047533030360dc1b60448201526064016106af565b604080516001600160a01b03841660248201526044808201849052825180830390910181526064909101909152602080820180516001600160e01b031663a9059cbb60e01b17815282515f93929184919082896127105a03f13d80156124c457602081146124cc575f93506124d6565b8193506124d6565b5f51158215171593505b5050509392505050565b6001600160a01b03811681146124f4575f80fd5b50565b8035612502816124e0565b919050565b5f8060408385031215612518575f80fd5b8235612523816124e0565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f830112612554575f80fd5b813567ffffffffffffffff8082111561256f5761256f612531565b604051601f8301601f19908116603f0116810190828211818310171561259757612597612531565b816040528381528660208588010111156125af575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f805f80608085870312156125e1575f80fd5b84359350602085013567ffffffffffffffff808211156125ff575f80fd5b61260b88838901612545565b94506040870135915080821115612620575f80fd5b5061262d87828801612545565b949793965093946060013593505050565b5f6020828403121561264e575f80fd5b8135611f55816124e0565b803560028110612502575f80fd5b5f805f806080858703121561267a575f80fd5b8435612685816124e0565b935060208501359250604085013567ffffffffffffffff8111156126a7575f80fd5b6126b387828801612545565b9250506126c260608601612659565b905092959194509250565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b8215158152604060208201525f610d7560408301846126cd565b5f8060408385031215612726575f80fd5b50508035926020909101359150565b602081525f611f5560208301846126cd565b5f60208284031215612757575f80fd5b5035919050565b5f8083601f84011261276e575f80fd5b50813567ffffffffffffffff811115612785575f80fd5b60208301915083602082850101111561279c575f80fd5b9250929050565b5f805f805f805f805f805f6101408c8e0312156127be575f80fd5b6127c78c6124f7565b9a5060208c0135995067ffffffffffffffff8060408e013511156127e9575f80fd5b6127f98e60408f01358f0161275e565b909a50985061280a60608e01612659565b975060808d0135965060a08d0135955060c08d0135945061282d60e08e016124f7565b935061283c6101008e016124f7565b9250806101208e0135111561284f575f80fd5b506128618d6101208e01358e01612545565b90509295989b509295989b9093969950565b5f805f60608486031215612885575f80fd5b83359250602084013567ffffffffffffffff808211156128a3575f80fd5b6128af87838801612545565b935060408601359150808211156128c4575f80fd5b506128d186828701612545565b9150509250925092565b5f815180845260208085019450602084015f5b838110156129135781516001600160a01b0316875295820195908201906001016128ee565b509495945050505050565b602081525f611f5560208301846128db565b5f8060408385031215612941575f80fd5b823561294c816124e0565b9150602083013567ffffffffffffffff811115612967575f80fd5b61297385828601612545565b9150509250929050565b5f805f805f805f805f806101008b8d031215612997575f80fd5b8a3567ffffffffffffffff808211156129ae575f80fd5b818d0191508d601f8301126129c1575f80fd5b8135818111156129cf575f80fd5b8e60208260051b85010111156129e3575f80fd5b60208381019d50909b508d013599506129fe60408e016124f7565b985060608d0135915080821115612a13575f80fd5b50612a208d828e0161275e565b9097509550612a33905060808c016124f7565b9350612a4160a08c016124f7565b925060c08b01359150612a5660e08c016124f7565b90509295989b9194979a5092959850565b604081525f612a7960408301856128db565b905060018060a01b03831660208301529392505050565b5f805f805f805f805f805f6101408c8e031215612aab575f80fd5b8b35612ab6816124e0565b9a5060208c0135995060408c013567ffffffffffffffff811115612ad8575f80fd5b612ae48e828f0161275e565b909a509850612af7905060608d01612659565b965060808c0135955060a08c0135945060c08c0135935060e08c0135612b1c816124e0565b92506101008c0135612b2d816124e0565b809250506101208c013590509295989b509295989b9093969950565b5f8060408385031215612b5a575f80fd5b8235612b65816124e0565b91506020830135612b75816124e0565b809150509250929050565b5f805f60608486031215612b92575f80fd5b8335612b9d816124e0565b92506020840135612bad816124e0565b91506040840135612bbd816124e0565b809150509250925092565b5f805f60608486031215612bda575f80fd5b8335612be5816124e0565b92506020840135612bf5816124e0565b929592945050506040919091013590565b602080825260059082015264475332303360d81b604082015260600190565b60208082526005908201526411d4cc8c0d60da1b604082015260600190565b634e487b7160e01b5f52601160045260245ffd5b5f60018201612c6957612c69612c44565b5060010190565b604081525f612c8260408301856126cd565b8281036020840152611fb181856126cd565b5f60208284031215612ca4575f80fd5b81516001600160e01b031981168114611f55575f80fd5b60ff8281168282160390811115610c6d57610c6d612c44565b8082028115828204841417610c6d57610c6d612c44565b602080825260059082015264475332303160d81b604082015260600190565b634e487b7160e01b5f52602160045260245ffd5b60028110612d3a57634e487b7160e01b5f52602160045260245ffd5b9052565b6001600160a01b038d168152602081018c90526101606040820181905281018a90525f6101808b8d828501375f838d01820152601f8c01601f19168301612d88606085018d612d1e565b8a60808501528960a08501528860c0850152612daf60e08501896001600160a01b03169052565b6001600160a01b0387166101008501528184820301610120850152612dd6828201876126cd565b92505050612df06101408301846001600160a01b03169052565b9d9c50505050505050505050505050565b80820180821115610c6d57610c6d612c44565b5f82612e2e57634e487b7160e01b5f52601260045260245ffd5b500490565b81810381811115610c6d57610c6d612c44565b634e487b7160e01b5f52603260045260245ffd5b608080825281018590525f8660a08301825b88811015612e9c578235612e7f816124e0565b6001600160a01b0316825260209283019290910190600101612e6c565b50602084019690965250506001600160a01b039283166040820152911660609091015292915050565b5f60208284031215612ed5575f80fd5b81518015158114611f55575f80fd5b818382375f9101908152919050565b8b81526001600160a01b038b81166020830152604082018b9052606082018a9052610160820190612f27608084018b612d1e565b60a083019890985260c082019690965260e0810194909452918516610100840152909316610120820152610140019190915295945050505050565b5f81612f7057612f70612c44565b505f19019056fea2646970667358221220d98ce5a63765aa68dee25f430f678dd1c6cba6c1883c4942b2363d367a9039f464736f6c63430008190033"; + bytes public constant SAFE_PROXY_FACTORY_BYTECODE = + hex"6080604052348015600e575f5ffd5b506107668061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610055575f3560e01c80631688f0b9146100595780633408e4701461008957806353e5d93514610097578063d18af54d146100ac578063ec9e80bb146100bf575b5f5ffd5b61006c610067366004610472565b6100d2565b6040516001600160a01b0390911681526020015b60405180910390f35b604051468152602001610080565b61009f610166565b60405161008091906104f6565b61006c6100ba36600461050f565b610190565b61006c6100cd366004610472565b61025f565b5f5f8380519060200120836040516020016100f7929190918252602082015260400190565b60405160208183030381529060405280519060200120905061011a858583610290565b6040516001600160a01b038781168252919350908316907f4f51faf6c4561ff95f067657e43439f0f856d97c04d9ec9070a6199ad418e2359060200160405180910390a2509392505050565b606060405180602001610178906103af565b601f1982820381018352601f90910116604052919050565b5f5f83836040516020016101c092919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b604051602081830303815290604052805190602001205f1c90506101e58686836100d2565b91506001600160a01b03831615610256576040516303ca56a360e31b81526001600160a01b03841690631e52b518906102289085908a908a908a90600401610577565b5f604051808303815f87803b15801561023f575f5ffd5b505af1158015610251573d5f5f3e3d5ffd5b505050505b50949350505050565b5f5f8380519060200120836102714690565b60408051602081019490945283019190915260608201526080016100f7565b5f833b6102e45760405162461bcd60e51b815260206004820152601f60248201527f53696e676c65746f6e20636f6e7472616374206e6f74206465706c6f7965640060448201526064015b60405180910390fd5b5f604051806020016102f5906103af565b601f1982820381018352601f90910116604081905261032291906001600160a01b038816906020016105b3565b6040516020818303038152906040529050828151826020015ff591506001600160a01b03821661038a5760405162461bcd60e51b815260206004820152601360248201527210dc99585d194c8818d85b1b0819985a5b1959606a1b60448201526064016102db565b8351156103a7575f5f5f8651602088015f875af1036103a7575f5ffd5b509392505050565b610163806105ce83390190565b6001600160a01b03811681146103d0575f5ffd5b50565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126103f6575f5ffd5b813567ffffffffffffffff811115610410576104106103d3565b604051601f8201601f19908116603f0116810167ffffffffffffffff8111828210171561043f5761043f6103d3565b604052818152838201602001851015610456575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f5f60608486031215610484575f5ffd5b833561048f816103bc565b9250602084013567ffffffffffffffff8111156104aa575f5ffd5b6104b6868287016103e7565b93969395505050506040919091013590565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61050860208301846104c8565b9392505050565b5f5f5f5f60808587031215610522575f5ffd5b843561052d816103bc565b9350602085013567ffffffffffffffff811115610548575f5ffd5b610554878288016103e7565b93505060408501359150606085013561056c816103bc565b939692955090935050565b6001600160a01b038581168252841660208201526080604082018190525f906105a2908301856104c8565b905082606083015295945050505050565b5f83518060208601845e919091019182525060200191905056fe6080604052348015600e575f5ffd5b50604051610163380380610163833981016040819052602b9160b2565b6001600160a01b038116608f5760405162461bcd60e51b815260206004820152602260248201527f496e76616c69642073696e676c65746f6e20616464726573732070726f766964604482015261195960f21b606482015260840160405180910390fd5b5f80546001600160a01b0319166001600160a01b039290921691909117905560dd565b5f6020828403121560c1575f5ffd5b81516001600160a01b038116811460d6575f5ffd5b9392505050565b607a806100e95f395ff3fe60806040525f80546001600160a01b03169035632cf35bc960e11b01602657805f5260205ff35b365f5f375f5f365f845af490503d5f5f3e80603f573d5ffd5b503d5ff3fea2646970667358221220640def201af13e0821a9dcaf5c656634c958a7cf37a69d829387126c436276e364736f6c634300081c0033a2646970667358221220e6be85b164b5d425d66785699e181cd85bffd8ff4fcbc6d6b2c6e7b4dacdeb4664736f6c634300081c0033"; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/SmartSessionsPrecompiles.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/SmartSessionsPrecompiles.sol new file mode 100644 index 0000000..853ccf6 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/SmartSessionsPrecompiles.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/* solhint-disable max-line-length */ +import { etch } from "../../test/utils/Vm.sol"; + +// Interfaces +import { ISmartSession } from "../../integrations/interfaces/ISmartSession.sol"; + +/// @dev Preset smart session contract address +address constant SMARTSESSION_ADDR = 0x0000000071727De22e5E9D8bAF0EDAc6F37da034; + +function etchSmartSessions() returns (ISmartSession) { + etch(address(SMARTSESSION_ADDR), SMART_SESSION_DEPLOYED_BYTECODE); + return ISmartSession(SMARTSESSION_ADDR); +} + +/*////////////////////////////////////////////////////////////// + BYTECODES +//////////////////////////////////////////////////////////////*/ + +bytes constant SMART_SESSION_DEPLOYED_BYTECODE = + hex"608060405234801561001057600080fd5b506004361061025c5760003560e01c80639700320311610145578063d527ed6e116100bd578063f551e2ee1161008c578063f77a7eac11610071578063f77a7eac14610587578063f867b08e1461059a578063f9b80369146105ad57600080fd5b8063f551e2ee14610530578063f55af6d11461057457600080fd5b8063d527ed6e146104d0578063d60b347f146104e3578063d620c85a146104f6578063ecd059611461051c57600080fd5b8063adbc532f11610114578063c9a5ec39116100f9578063c9a5ec3914610497578063d056b06d146104aa578063d0e6f608146104bd57600080fd5b8063adbc532f14610471578063af29e6b21461048457600080fd5b80639700320314610418578063a67c714e1461042b578063a7ef62051461043e578063a9fa4b441461045157600080fd5b8063454c9d82116101d85780636d61fe70116101a7578063795f92691161018c578063795f9269146103be5780638a91b0e3146103f257806396e729621461040557600080fd5b80636d61fe70146103985780636e79eee0146103ab57600080fd5b8063454c9d821461033e578063496c8a91146103515780634e33ad2e1461037257806367bb29c41461038557600080fd5b806328f7392d1161022f57806330ce43401161021457806330ce4340146102f8578063364d240f1461030b57806344d1628c1461031e57600080fd5b806328f7392d146102d05780632dadb5e9146102e557600080fd5b806309e5aef8146102615780630ac8f150146102895780631097109e146102aa5780632445e73e146102bd575b600080fd5b61027461026f3660046145c3565b6105c0565b60405190151581526020015b60405180910390f35b61029c61029736600461460d565b6105ef565b604051908152602001610280565b6102746102b836600461468d565b610600565b6102746102cb36600461468d565b610610565b6102e36102de3660046146e9565b610620565b005b6102746102f336600461468d565b6106ce565b6102746103063660046148aa565b6106de565b6102e3610319366004614903565b61070c565b61033161032c366004614982565b610802565b60405161028091906149ae565b6102e361034c366004614b00565b61081d565b61036461035f366004614982565b610883565b604051610280929190614b8d565b6102e3610380366004614cbe565b6108c5565b61029c610393366004614ded565b61091e565b6102e36103a6366004614f6d565b610955565b6102e36103b9366004614faf565b6109bd565b61029c6103cc366004614fea565b6000918252602082815260408084206001600160a01b0393909316845291905290205490565b6102e3610400366004614f6d565b610aae565b6102e361041336600461500f565b610aea565b61029c610426366004615031565b610bb9565b610331610439366004614982565b610d55565b61027461044c36600461506e565b610d70565b61046461045f366004614982565b610d89565b60405161028091906150b0565b61027461047f366004614fea565b610da4565b6102746104923660046150e8565b610db2565b6102746104a5366004614fea565b610dcb565b6102e36104b836600461511d565b610df6565b6104646104cb366004614982565b610e54565b6103316104de3660046150e8565b610e6f565b6102746104f1366004615169565b610e9d565b7fd620c85a0000000000000000000000000000000000000000000000000000000061029c565b61027461052a366004615186565b60011490565b61054361053e36600461519f565b610eb4565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610280565b6104646105823660046151ef565b610f1a565b61027461059536600461506e565b611179565b6102e36105a8366004615186565b611192565b6102e36105bb366004615186565b6112e8565b600082815260036020908152604080832086845290915281206105e4908684611363565b90505b949350505050565b60006105fa82611394565b92915050565b60006105e46002858786866113e5565b60006105e46001858786866113e5565b61062c6005338461147d565b151560000361066f576040517f92d69f9c000000000000000000000000000000000000000000000000000000008152600481018390526024015b60405180910390fd5b61068f61067c8280615225565b6106859161528d565b60079084336114a9565b6106ca6003836106a66106a186611508565b611543565b6106b36020860186615225565b6106bc9161529a565b60029392919033600161154f565b5050565b60006105e4600385878686611709565b6000610702846106ed846117d5565b6000868152600760205260409020919061147d565b90505b9392505050565b6107186005338761147d565b1515600003610756576040517f92d69f9c00000000000000000000000000000000000000000000000000000000815260048101869052602401610666565b60005b818110156107ea5760006107c4848484818110610778576107786152a7565b905060200281019061078a91906152d6565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506117d592505050565b60008881526007602052604090209091506107e09033836117e8565b5050600101610759565b506107fb60026003338888886117f5565b5050505050565b60008181526001602052604090206060906107059084611897565b6108296005338461147d565b1515600003610867576040517f92d69f9c00000000000000000000000000000000000000000000000000000000815260048101839052602401610666565b6106ca60018361087681611543565b600192919085338561154f565b60008181526008602090815260408083206001600160a01b03808716855292529091208054909116906060906108bb600182016118a5565b9150509250929050565b6108d16005338461147d565b151560000361090f576040517f92d69f9c00000000000000000000000000000000000000000000000000000000815260048101839052602401610666565b6106ca600383833360016118b0565b6000848152602081815260408083206001600160a01b038716845290915281205461094b84868584611a41565b9695505050505050565b6000610962600533611a50565b111561099c576040517fbcf00e1d000000000000000000000000000000000000000000000000000000008152336004820152602401610666565b60008190036109a9575050565b813582016020810190356107fb8282610f1a565b6109c96005338661147d565b1515600003610a07576040517f92d69f9c00000000000000000000000000000000000000000000000000000000815260048101859052602401610666565b6000838152600360205260409020610a24906002338786866117f5565b60008381526003602090815260408083208784529091529020610a479033611a50565b600003610aa8576000848152600460205260409020610a679033856117e8565b506040805185815260208101859052338183015290517ffb5966a10bbfa837a7964784b0eb92d624218037b24ae5d1aeae23157f21453f9181900360600190a15b50505050565b6000610abb600533611a50565b905060005b81811015610aa8576000610ad660053383611a5c565b9050610ae181611192565b50600101610ac0565b610af66005338461147d565b1515600003610b34576040517f92d69f9c00000000000000000000000000000000000000000000000000000000815260048101839052602401610666565b60008181526003602090815260408083208584529091529020610b579033611a69565b6000828152600460205260409020610b709033836117e8565b50604080518381526020810183905233918101919091527ffb5966a10bbfa837a7964784b0eb92d624218037b24ae5d1aeae23157f21453f906060015b60405180910390a15050565b600080610bc96020850185615169565b90506001600160a01b0381163314610c18576040517f04a4ab940000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610666565b6000803681610c33610c2e6101008a018a6152d6565b611a73565b9350935093509350610c55846002811115610c5057610c5061533b565b611b08565b15610cac57610ca583888a610c9f86868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b2592505050565b89611b43565b9550610d4a565b610cc6846002811115610cc157610cc161533b565b611fcb565b15610d1657610cd361451e565b6060610cdf8484611fef565b60408201519193509150610cf290612056565b9450610d0082868989612079565b610d0d858a8c848b611b43565b97505050610d4a565b836040517f97dc33dc000000000000000000000000000000000000000000000000000000008152600401610666919061536a565b505050505092915050565b60008181526002602052604090206060906107059084611897565b6000828152600260205260408120610702908584611363565b60008181526004602052604090206060906107059084611897565b60006107056005838561147d565b600082815260046020526040812061070290858461147d565b60008281526008602090815260408083206001600160a01b0380861685529252822054161515610705565b610e026005338561147d565b1515600003610e40576040517f92d69f9c00000000000000000000000000000000000000000000000000000000815260048101849052602401610666565b610e4f600180338686866117f5565b505050565b60008181526007602052604090206060906107059084611897565b60008181526003602090815260408083208584529091529020606090610e959085611897565b509392505050565b600080610eab600584611a50565b15159392505050565b6000306001600160a01b03861603610eed57507fffffffff000000000000000000000000000000000000000000000000000000006105e7565b6000610f038686610efe87876122a7565b6122dd565b15600003631626ba7e1760e01b9695505050505050565b6060816000819003610f58576040517f5cb045db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff811115610f7157610f71614737565b604051908082528060200260200182016040528015610f9a578160200160208202803683370190505b50915060005b818110156111715736858583818110610fbb57610fbb6152a7565b9050602002810190610fcd9190615384565b90506000610fda82611394565b905061100e600182610feb81611543565b610ff86060870187615225565b6110019161529a565b600193929190338561154f565b61103b6003826110206106a185611508565b61102d60808701876153c2565b6106b3906020810190615225565b61106861104b60808401846153c2565b6110559080615225565b61105e9161528d565b60079083336114a9565b61108e8161107960a0850185615225565b611082916153f6565b600391903360016118b0565b61109a600533836124c4565b506110fd81336110ad6020860186615169565b6110ba60208701876152d6565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250600896959493925060019150506124d1565b80858481518110611110576111106152a7565b6020026020010181815250507fc5c98ce9477fc2c88a84abed218cda086be8442fc2eecb9e1ce33941d28741b6813360405161115f9291909182526001600160a01b0316602082015260400190565b60405180910390a15050600101610fa0565b505092915050565b6000828152600160205260408120610702908584611363565b806111cc576040517f92d69f9c00000000000000000000000000000000000000000000000000000000815260048101829052602401610666565b60008181526001602052604090206111e49033611a69565b60008181526002602052604090206111fc9033611a69565b60008181526004602052604081206112149033611a50565b905060005b8181101561126957600083815260046020526040812061123a903384611a5c565b600081815260036020908152604080832088845290915290209091506112609033611a69565b50600101611219565b5060008281526004602052604090206112829033611a69565b61128e600883336126ea565b61129a600533846117e8565b5060008281526007602052604090206112b39033611a69565b604080518381523360208201527f1ff4377bcf87e5e9c2ec7fdc4732408c1073dd4b9f49e719d783b1e4fb0f62819101610bad565b60008181526020818152604080832033845290915281208054908261130c83615432565b9091555090507fb21cd80665df6c8932e067c1fb0835dc3bc61d85bcab4c90a9992b692d8e17e2823361134084600161546a565b604080519384526001600160a01b03909216602084015290820152606001610bad565b6001600160a01b03818116600090815260018501602090815260408083209386168352929052908120541515610702565b60006113a36020830183615169565b6113b060208401846152d6565b84604001356040516020016113c894939291906154a8565b604051602081830303815290604052805190602001209050919050565b6000818082036113f9576001915050611474565b60005b8181101561146d576000858583818110611418576114186152a7565b905060200281019061142a91906153c2565b611433906154dc565b805160008a815260208c90526040902091925090611452908983611363565b611463576000945050505050611474565b50506001016113fc565b5060019150505b95945050505050565b600081815260018401602090815260408083206001600160a01b03861684529091528120541515610702565b825160005b818110156115005760006114da8683815181106114cd576114cd6152a7565b60200260200101516117d5565b60008681526020899052604090209091506114f69085836124c4565b50506001016114ae565b505050505050565b6040517f455243313237313a2000000000000000000000000000000000000000000000006020820152602981018290526000906049016113c8565b60006105fa8233612782565b825160005b818110156116fe576000858281518110611570576115706152a7565b60209081029190910101515190506115916001600160a01b0382168a6127dd565b831561161f576040517f4c13560c0000000000000000000000000000000000000000000000000000000081526001600160a01b038087166004830152821660248201526e69e2a187aeffb852bf3ccdc95151b290634c13560c9060440160006040518083038186803b15801561160657600080fd5b505afa15801561161a573d6000803e3d6000fd5b505050505b600088815260208b905260409020611638908683612a1c565b50806001600160a01b031663989c9e46868989868151811061165c5761165c6152a7565b6020026020010151602001516040518463ffffffff1660e01b8152600401611686939291906154e8565b600060405180830381600087803b1580156116a057600080fd5b505af11580156116b4573d6000803e3d6000fd5b505050507f1c5ea73ef804151087de6d0ce7a77287b15cfc4f51654cac5bfe6c558547f827888a83886040516116ed9493929190615510565b60405180910390a150600101611554565b505050505050505050565b60008180820361171d576001915050611474565b60005b8181101561146d573685858381811061173b5761173b6152a7565b905060200281019061174d919061554c565b905060006117806117616020840184615580565b6117716040850160208601615169565b6001600160a01b031690612a32565b90506117ba89896117946040860186615225565b8e60000160008781526020019081526020016000206113e590949392919063ffffffff16565b6117cb576000945050505050611474565b5050600101611720565b6000816040516020016113c8919061559d565b6000610702848484612a94565b8060005b8181101561188d576000848483818110611815576118156152a7565b905060200201602081019061182a9190615169565b600087815260208b905260409020909150611846908883612b79565b507fb2a53c8ed9d14361634fc2a7835a222e5dbec408b6cef4e06768e844613fa7548689838a60405161187c9493929190615510565b60405180910390a1506001016117f9565b5050505050505050565b606060006105e78484612b8f565b60606105fa82612b9b565b836118ea576040517f526d0da500000000000000000000000000000000000000000000000000000000815260048101859052602401610666565b825160005b81811015611a3857600085828151811061190b5761190b6152a7565b6020026020010151905060006001600160a01b031681602001516001600160a01b03161480611946575060208101516001600160a01b031630145b1561197d576040517fe068d3a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602082015160009161199a916001600160a01b031690612a32565b9050806119d3576040517fe068d3a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600088815260018a01602052604090206119ee9087836124c4565b50611a2e6002896119ff8185612c65565b85604001518a8a8f600001600089815260200190815260200160002061154f909695949392919063ffffffff16565b50506001016118ef565b50505050505050565b60006105e48585308686612c7a565b60006107058383612d70565b6000610702848484612d7c565b6106ca8282612d89565b6000803681611a8560018287896155af565b611a8e916155d9565b60f81c6002811115611aa257611aa261533b565b9350611ab9846002811115610cc157610cc161533b565b15611ad457611acb85600181896155af565b91509150611aff565b611ae26021600187896155af565b611aeb9161563f565b9250611afa85602181896155af565b915091505b92959194509250565b6000805b826002811115611b1e57611b1e61533b565b1492915050565b6060611b3082612dd9565b8060200190518101906105fa91906156c2565b6000611b516005838861147d565b611b8a576040517f526d0da500000000000000000000000000000000000000000000000000000000815260048101879052602401610666565b611c0e8487611b9881611543565b87604051602401611baa92919061575b565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f7129edce0000000000000000000000000000000000000000000000000000000017905260019291906000612e98565b90506000611c1f60608601866152d6565b611c2e916004916000916155af565b611c37916158ad565b90507f1651a3ad000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601611e3657600080611c9a611c9560608901896152d6565b612f5c565b90925090507fff00000000000000000000000000000000000000000000000000000000000000811615611cf9576040517f6c4872f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fff0000000000000000000000000000000000000000000000000000000000000082167f010000000000000000000000000000000000000000000000000000000000000003611d6157611d5a611d536003898c6001612f86565b859061306f565b9350611e2f565b7fff000000000000000000000000000000000000000000000000000000000000008216611dfd576000803681611dbc611db7611da060608e018e6152d6565b506024818101359091019081019160049091013590565b613198565b9350935093509350611df2611deb8c8f87878787600160036000016131de90979695949392919063ffffffff16565b899061306f565b975050505050611e2f565b6040517f6c4872f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050611f9e565b7f72288ed1000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601611eb1576040517f6c4872f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611eeb611ec360608801886152d6565b611ed2916004916000916155af565b611edb916158ad565b6001600160a01b03861690612a32565b9050611f9a611f93878a611eff8186612c65565b88806000611f1060608f018f6152d6565b604051602401611f2596959493929190615912565b60408051601f19818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f05c008950000000000000000000000000000000000000000000000000000000017905260008881526003909152209291906001612e98565b849061306f565b9250505b6000611fae600888868b8961357f565b905080611fc057600192505050611474565b505095945050505050565b60006001826002811115611fe157611fe161533b565b14806105fa57506002611b0c565b611ff761451e565b606061203884848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612dd992505050565b80602001905181019061204b9190615d84565b909590945092505050565b60008160000151826020015183604001516040516020016113c893929190615e8a565b6000838152602081815260408083206001600160a01b03861684529091528120805490826120a683615432565b90915550905060006120ba8685848661368f565b60608701516040517f1626ba7e000000000000000000000000000000000000000000000000000000008082529293506001600160a01b03871691631626ba7e91612108918691600401615ebc565b602060405180830381865afa158015612125573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121499190615ed5565b7fffffffff0000000000000000000000000000000000000000000000000000000016146121b4576040517f3ca8ef0c0000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260248101829052604401610666565b60006121d08460028111156121cb576121cb61533b565b6137a0565b90506121f76001876121e181611543565b60408b0151606001516001939291908a8761154f565b6040870151608001515161220f9060079088886114a9565b61223b6003876122216106a18a611508565b60408b015160800151602001516002939291908a8761154f565b604087015160a0015161225490600390889088856118b0565b60008681526008602090815260408083206001600160a01b03808a1685529252909120541661229b576040870151805160209091015161229b9160089189918991866124d1565b61188d600533886124c4565b36600083839150915061ffff60605119046164920260208203830135036122d657506040810135016020810190355b9250929050565b6000806122e86137a9565b604051909150849084908183017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe013560f01c8060420180880389016119016000526040816020378215828a10178b6042601e2018171561234e57600096505050612495565b7f5479706564446174615369676e280000000000000000000000000000000000008452600e8401836040830182376040820196508395506f07fffffe000000000000010000000000815160001a1c6028858301525b6028825160001a146123cb578065120100000001835160001a1c1790506001820191506123a3565b7f20636f6e74656e74732c627974657331206669656c64732c737472696e67206e82527f616d652c737472696e672076657273696f6e2c75696e7432353620636861696e60208301527f49642c6164647265737320766572696679696e67436f6e74726163742c62797460408301527f657333322073616c742c75696e743235365b5d20657874656e73696f6e7329006060830152607f82019150846040840183376040838a37908401859003852088526101208820604052600116604201601e209a5050909603955b50604052826124aa57600093505050506105e7565b6124b8888888888686613883565b98975050505050505050565b60006107028484846139c7565b6001600160a01b038316158061256657506040517fecd05961000000000000000000000000000000000000000000000000000000008152600760048201526001600160a01b0384169063ecd0596190602401602060405180830381865afa158015612540573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125649190615ef2565b155b156125a8576040517fa7eae1120000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610666565b801561263d576040517f529562a10000000000000000000000000000000000000000000000000000000081526001600160a01b03808616600483015284166024820152600760448201526e69e2a187aeffb852bf3ccdc95151b29063529562a19060640160006040518083038186803b15801561262457600080fd5b505afa158015612638573d6000803e3d6000fd5b505050505b6000858152602087815260408083206001600160a01b038881168552925290912080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169185169190911781556126986001820184613a50565b604080518781526001600160a01b03868116602083015287168183015290517f9e1deb1dcdedd38e68d5543a9a6be8416a0e0a5627628e47780bd6ef8abc1a3c9181900360600190a150505050505050565b6000828152602084815260408083206001600160a01b03858116808652918452938290208054835188815295169385019390935290830152907f1b8b78a1623842b0534f626565151ce282cc88268c30bf8d525c59d0c22f21db9060600160405180910390a180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168155610aa860018201613aae565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606083901b166020820152603481018390526000906054015b60405160208183030381529060405280519060200120905092915050565b600060018260038111156127f3576127f361533b565b036128a1576040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f7129edce0000000000000000000000000000000000000000000000000000000060048201526001600160a01b038416906301ffc9a7906024015b602060405180830381865afa158015612876573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061289a9190615ef2565b90506129da565b60028260038111156128b5576128b561533b565b0361291f576040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f05c008950000000000000000000000000000000000000000000000000000000060048201526001600160a01b038416906301ffc9a790602401612859565b60038260038111156129335761293361533b565b0361299d576040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527fcbf345050000000000000000000000000000000000000000000000000000000060048201526001600160a01b038416906301ffc9a790602401612859565b6040517f6a01dd010000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610666565b80610e4f576040517f6a01dd010000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610666565b600061070284846001600160a01b0385166139c7565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b1660208201527fffffffff00000000000000000000000000000000000000000000000000000000821660348201526000906038016127bf565b600081815260018401602090815260408083206001600160a01b03861684529091528120548015612b6f576000612acc600183615f14565b905060006001612adc8888613ad0565b612ae69190615f14565b9050808214612b32576000612afc888884613ae4565b9050612b0a88888584613af1565b600090815260018801602090815260408083206001600160a01b038a16845290915290208390555b612b3c8787613afd565b50505060008281526001808601602090815260408084206001600160a01b03881685529091528220919091559050610705565b6000915050610705565b600061070284846001600160a01b038516612a94565b60606107058383613b07565b80546060906000612bad602083615f27565b612bb890600161546a565b90506001840160008267ffffffffffffffff811115612bd957612bd9614737565b604051908082528060200260200182016040528015612c02578160200160208202803683370190505b50905060005b83811015612c3f57600081840154905080838381518110612c2b57612c2b6152a7565b602090810291909101015250600101612c08565b5080604051602001612c519190615f62565b604080519190529384525091949350505050565b6000610705612c748484613b13565b33612782565b60007f45f5f60cec99c2d0a0198ec513b02d6926b8ec63dfaf7e9afba954108dd97ebd8585856002811115612cb157612cb161533b565b895160408b01516020808d0151805191012060608d0151612cd190613b2f565b612cde8e60800151613baa565b612ceb8f60a00151613c26565b60408051602081019b909b526001600160a01b03998a16908b015296881660608a015260ff90951660808901529590921660a087015260c086015260e085015261010084019290925261012083019190915261014082015261016081018390526101800160405160208183030381529060405280519060200120905095945050505050565b60006107058383613ad0565b6000610702848484613ae4565b6000612d958383612d70565b905060015b818111610aa8576000612db78585612db28587615f14565b612d7c565b9050612dc4858583612a94565b50508080612dd190615432565b915050612d9a565b60405181516020838101938184019201015b80841015612e7f5783518060001a8060051c80612e1e575060018681015185529581016002019593019092019150612deb565b600781148360011a600701821881028218600201600185836001011a85601f1660081b01018088036020821860208311028218915060005b818101518a8201528201838110612e56579a84016002019a988301985050505050505050612deb565b50601f1982820301825260008152602001604052919050565b600080612ebf612eab6020880188615169565b600087815260208a90526040902090611897565b805190915080841115612f01576040517f1c792c0500000000000000000000000000000000000000000000000000000000815260048101879052602401610666565b60005b81811015612f5057612f46611d538888868581518110612f2657612f266152a7565b60200260200101516001600160a01b0316613c829092919063ffffffff16565b9350600101612f04565b50505095945050505050565b60008080612f6e6024600486886155af565b612f779161563f565b95600887901b95509350505050565b60003681612fab612f9d611da060608901896152d6565b508035016020810191903590565b9092509050806000819003612fec576040517f56d93c1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015613063573684848381811061300a5761300a6152a7565b905060200281019061301c919061554c565b9050600061304b8b8b8b6130336020870187615169565b602087013561304560408901896152d6565b8f6131de565b9050613057878261306f565b96505050600101612fef565b50505050949350505050565b600081830160601b8260601b81148460601b8214176001600160a01b03848618161517600181146130a35760019250611171565b7fffffffffffff000000000000000000000000000000000000000000000000000080851690861681811881831102188686176001600160a01b031617935079ffffffffffff0000000000000000000000000000000000000000861690816131225779ffffffffffff000000000000000000000000000000000000000091505b5079ffffffffffff0000000000000000000000000000000000000000851680613162575079ffffffffffff00000000000000000000000000000000000000005b80821890821102188061318c575079ffffffffffff00000000000000000000000000000000000000005b92909217949350505050565b60008036816131aa60148287896155af565b6131b391615f98565b60601c93506131c66034601487896155af565b6131cf9161563f565b9250611afa85603481896155af565b600080600484101561321157507fffffffff0000000000000000000000000000000000000000000000000000000061322b565b61321f6004600086886155af565b613228916158ad565b90505b7fffffffff0000000000000000000000000000000000000000000000000000000081167fe9ae5c5300000000000000000000000000000000000000000000000000000000148015613299575061328460208a018a615169565b6001600160a01b0316876001600160a01b0316145b156132d0576040517f540733ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001600160a01b03881601613332576040517f82d5d76a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006133476001600160a01b03891683612a32565b90506133e78a8a6133588185612c65565b61336560208f018f615169565b8c8c8c8c60405160240161337e96959493929190615912565b6040516020818303038152906040526305c0089560e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050878f6000878152602001908152602001600020613d4490949392919063ffffffff16565b92506350ffbaad8303613571576040516c0100000000000000000000000060208201527c0100000000000000000000000000000000000000000000000000000000603482015261356e908b908b9061346190603801604051602081830303815290604052805190602001208d612c6590919063ffffffff16565b61346e60208f018f615169565b8c8c8c8c60405160240161348796959493929190615912565b6040516020818303038152906040526305c0089560e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050878f600060018060e01b60405160200161353992919060609290921b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001682527fffffffff0000000000000000000000000000000000000000000000000000000016601482015260180190565b604051602081830303815290604052805190602001208152602001908152602001600020612e9890949392919063ffffffff16565b92505b505098975050505050505050565b6000828152602086815260408083206001600160a01b038088168552925282205416806135ea576040517f6aeeaff8000000000000000000000000000000000000000000000000000000008152600481018590526001600160a01b0386166024820152604401610666565b6000848152602088815260408083206001600160a01b03898116855292529091209082169063940d38409088908690613625906001016118a5565b6040518463ffffffff1660e01b815260040161364393929190615ffd565b602060405180830381865afa158015613660573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136849190615ef2565b979650505050505050565b604084015160009081906136a590868587611a41565b905060008660200151876000015160ff16815181106136c6576136c66152a7565b602002602001015160000151905060008760200151886000015160ff16815181106136f3576136f36152a7565b6020026020010151602001519050468267ffffffffffffffff1614613750576040517fe75e237900000000000000000000000000000000000000000000000000000000815267ffffffffffffffff83166004820152602401610666565b828114613793576040517f0b08d5be0000000000000000000000000000000000000000000000000000000081526004810182905260248101849052604401610666565b6124b88860200151613ddf565b60006001611b0c565b600080600080600080600080336001600160a01b03166384b0196e6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156137f3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261381b9190810190616086565b604080516101208101825260009890981a60f81b9088015285516020968701206060880152845194860194909420608087015260a08601929092526001600160a01b031660c085015260e0840152805160051b91012061010082015298975050505050505050565b6000806138c584848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506117d592505050565b905060006138d6602082888a6155af565b6138df9161563f565b90506138ee866020818a6155af565b90975095506138ff6005338361147d565b61390e5760009250505061094b565b600081815260076020526040902061392790338461147d565b6139365760009250505061094b565b600061395d338b8b8b8b8761394d6106a18a611508565b6002969594939291906000613f04565b905080613970576000935050505061094b565b6139b98933848b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060089695949392505061357f9050565b9a9950505050505050505050565b600081815260018401602090815260408083206001600160a01b0386168452909152812054613a48576000838152602085815260409091208054600101918202810184905555613a178484613ad0565b60008381526001808701602090815260408084206001600160a01b0389168552909152909120919091559050610705565b506000610705565b61014081511115613a6057600080fd5b6060613a6b82614027565b90845580519091506001840160005b82811015611500576000848281518110613a9657613a966152a7565b60209081029190910101518383015550600101613a7a565b600080825560018201905b600a811015610e4f57600082820155600101613ab9565b600081815260208390526040812054610705565b60006107028484846140e0565b610aa8848484846140f8565b6106ca8282614111565b6060610705838361416e565b60408051602081018490529081018290526000906060016127bf565b805160009081613b4f8260408051828152600190920160051b8201905290565b905060005b82811015613b9a57613b9181613b82878481518110613b7557613b756152a7565b602002602001015161420a565b600190910160051b8401528290565b50600101613b54565b50805160051b60208201206105e7565b6040805160038152608081019091527fdd8bf2f9b88fa557b2cb00ffd37dc4a3b8f3ff1d0d9e03c6f7c183f38869e91d6020820152600090613c036001613bf48560000151614275565b600190910160051b8301528190565b50613c166002613bf48560200151613b2f565b50805160051b6020820120610705565b805160009081613c468260408051828152600190920160051b8201905290565b905060005b82811015613b9a57613c7981613b82878481518110613c6c57613c6c6152a7565b60200260200101516142ff565b50600101613c4b565b60008080613cbd6001600160a01b0387167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360208861438e565b91509150600082613cde5763f427075260005260208201516020526024601cfd5b5060208101519250826001600160a01b03811615613d3a576040517f3b577361000000000000000000000000000000000000000000000000000000008152600481018790526001600160a01b0388166024820152604401610666565b5050509392505050565b600080613d57612eab6020880188615169565b805190915080841115613d72576350ffbaad92505050611474565b60005b81811015613da157613d97611d538888868581518110612f2657612f266152a7565b9350600101613d75565b506350ffbaad8303611fc0576040517f2d39e3f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000807f9af9262be547d4cc9dd06591bab37efd72d2b9d5fca173afd326b5b5410dac18613e0c84614419565b60408051602081019390935282015260600160408051601f1981840301815282825280516020918201207fb03948446334eb9b2196d5eb166f69b9d49403eb4a12f36de8d3f9f3cb8e15c3918401919091527f174e195918c922f8ce2a6d59c7e3e4eb4908dcdb2e305d06e24a973039099ed4918301919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606083015291506107059060800160408051601f198184030181529082905280516020909101207f190100000000000000000000000000000000000000000000000000000000000082526002820152602281018390526042902090565b600083815260208a9052604081208190613f1e908b611897565b805190915080841115613f60576040517f1c792c0500000000000000000000000000000000000000000000000000000000815260048101879052602401610666565b60005b8181101561401657828181518110613f7d57613f7d6152a7565b60200260200101516001600160a01b031663cbf34505878d8f8e8e8e6040518763ffffffff1660e01b8152600401613fba96959493929190615912565b602060405180830381865afa158015613fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ffb9190615ef2565b93508361400e576000935050505061401a565b600101613f63565b5050505b9998505050505050505050565b8051606061014082111561403a57600080fd5b6000614047602084615f27565b61405290600161546a565b90508067ffffffffffffffff81111561406d5761406d614737565b604051908082528060200260200182016040528015614096578160200160208202803683370190505b50915060005b818110156140d9576000602060018301028601519050808483815181106140c5576140c56152a7565b60209081029190910101525060010161409c565b5050915091565b60008281526020849052604081206107029083614475565b6000838152602085905260409020610aa890838361449d565b6000818152602083905260408120805490918190036141305750505050565b6141468261413f600184615f14565b600061449d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190555050565b60008181526020839052604090208054606091908067ffffffffffffffff81111561419b5761419b614737565b6040519080825280602002602001820160405280156141c4578160200160208202803683370190505b50925060005b81811015614201576141dc8382614475565b8482815181106141ee576141ee6152a7565b60209081029190910101526001016141ca565b50505092915050565b80516020808301518051908201206040516000936113c8937fdddac12cd8b10a071bea04226e97ac9490698394e19224abc47a5cfeeeb6ee97939192019283526001600160a01b03919091166020830152604082015260600190565b60019190910160051b82015290565b8051600090816142958260408051828152600190920160051b8201905290565b905060005b82811015613b9a576142f6818683815181106142b8576142b86152a7565b60200260200101516040516020016142d0919061559d565b60405160208183030381529060405280519060200120846142669092919063ffffffff16565b5060010161429a565b60007f35809859dccf8877c407a59527c2f00fb81ca9c198ebcb0c832c3deaa38d350260001b8260000151836020015161433c8560400151613b2f565b6040805160208101959095527fffffffff00000000000000000000000000000000000000000000000000000000909316928401929092526001600160a01b03166060830152608082015260a0016113c8565b6000606060008060008661ffff1667ffffffffffffffff8111156143b4576143b4614737565b6040519080825280601f01601f1916602001820160405280156143de576020820181803683370190505b5090506000808751602089018b8e8ef191503d9250868311156143ff578692505b828152826000602083013e90999098509650505050505050565b8051600090816144398260408051828152600190920160051b8201905290565b905060005b82811015613b9a5761446c81613b8287848151811061445f5761445f6152a7565b60200260200101516144c7565b5060010161443e565b60008254821061449157638277484f600052816020526024601cfd5b50600101602002015490565b825482106144b757638277484f600052816020526024601cfd5b8060018301602002840155505050565b80516020808301516040516000936113c8937f9c5d301c45209fe15c8bb85bc08d4234ac9e1d48c0d22b7ab701ae25e640086b9391920192835267ffffffffffffffff919091166020830152604082015260600190565b60408051608081018252600081526060602082015290810161453e61454b565b8152602001606081525090565b6040518060c0016040528060006001600160a01b0316815260200160608152602001600080191681526020016060815260200161453e604051806040016040528060608152602001606081525090565b6001600160a01b03811681146145b057600080fd5b50565b80356145be8161459b565b919050565b600080600080608085870312156145d957600080fd5b84356145e48161459b565b9350602085013592506040850135915060608501356146028161459b565b939692955090935050565b60006020828403121561461f57600080fd5b813567ffffffffffffffff81111561463657600080fd5b820160c0818503121561070557600080fd5b60008083601f84011261465a57600080fd5b50813567ffffffffffffffff81111561467257600080fd5b6020830191508360208260051b85010111156122d657600080fd5b600080600080606085870312156146a357600080fd5b84356146ae8161459b565b935060208501359250604085013567ffffffffffffffff8111156146d157600080fd5b6146dd87828801614648565b95989497509550505050565b600080604083850312156146fc57600080fd5b82359150602083013567ffffffffffffffff81111561471a57600080fd5b83016040818603121561472c57600080fd5b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561478957614789614737565b60405290565b6040516060810167ffffffffffffffff8111828210171561478957614789614737565b60405160c0810167ffffffffffffffff8111828210171561478957614789614737565b6040516080810167ffffffffffffffff8111828210171561478957614789614737565b604051601f8201601f1916810167ffffffffffffffff8111828210171561482157614821614737565b604052919050565b600067ffffffffffffffff82111561484357614843614737565b50601f01601f191660200190565b600082601f83011261486257600080fd5b813560208301600061487b61487684614829565b6147f8565b905082815285838301111561488f57600080fd5b82826020830137600092810160200192909252509392505050565b6000806000606084860312156148bf57600080fd5b83356148ca8161459b565b925060208401359150604084013567ffffffffffffffff8111156148ed57600080fd5b6148f986828701614851565b9150509250925092565b60008060008060006060868803121561491b57600080fd5b85359450602086013567ffffffffffffffff81111561493957600080fd5b61494588828901614648565b909550935050604086013567ffffffffffffffff81111561496557600080fd5b61497188828901614648565b969995985093965092949392505050565b6000806040838503121561499557600080fd5b82356149a08161459b565b946020939093013593505050565b602080825282518282018190526000918401906040840190835b818110156149ef5783516001600160a01b03168352602093840193909201916001016149c8565b509095945050505050565b600067ffffffffffffffff821115614a1457614a14614737565b5060051b60200190565b600060408284031215614a3057600080fd5b614a38614766565b90508135614a458161459b565b8152602082013567ffffffffffffffff811115614a6157600080fd5b614a6d84828501614851565b60208301525092915050565b6000614a87614876846149fa565b838152905060208101600584901b830185811115614aa457600080fd5b835b81811015613d3a57803567ffffffffffffffff811115614ac557600080fd5b614ad188828801614a1e565b84525060209283019201614aa6565b600082601f830112614af157600080fd5b61070583833560208501614a79565b60008060408385031215614b1357600080fd5b82359150602083013567ffffffffffffffff811115614b3157600080fd5b6108bb85828601614ae0565b60005b83811015614b58578181015183820152602001614b40565b50506000910152565b60008151808452614b79816020860160208601614b3d565b601f01601f19169290920160200192915050565b6001600160a01b03831681526040602082015260006107026040830184614b61565b7fffffffff00000000000000000000000000000000000000000000000000000000811681146145b057600080fd5b6000614beb614876846149fa565b838152905060208101600584901b830185811115614c0857600080fd5b835b81811015613d3a57803567ffffffffffffffff811115614c2957600080fd5b850160608189031215614c3b57600080fd5b614c4361478f565b8135614c4e81614baf565b81526020820135614c5e8161459b565b6020820152604082013567ffffffffffffffff811115614c7d57600080fd5b614c898a828501614ae0565b60408301525084525060209283019201614c0a565b600082601f830112614caf57600080fd5b61070583833560208501614bdd565b60008060408385031215614cd157600080fd5b82359150602083013567ffffffffffffffff811115614cef57600080fd5b6108bb85828601614c9e565b6000614d09614876846149fa565b838152905060208101600584901b830185811115614d2657600080fd5b835b81811015613d3a57803567ffffffffffffffff811115614d4757600080fd5b614d5388828801614851565b84525060209283019201614d28565b600060408284031215614d7457600080fd5b614d7c614766565b9050813567ffffffffffffffff811115614d9557600080fd5b8201601f81018413614da657600080fd5b614db584823560208401614cfb565b825250602082013567ffffffffffffffff811115614dd257600080fd5b614a6d84828501614ae0565b8035600381106145be57600080fd5b60008060008060808587031215614e0357600080fd5b843593506020850135614e158161459b565b9250604085013567ffffffffffffffff811115614e3157600080fd5b850160c08188031215614e4357600080fd5b614e4b6147b2565b614e54826145b3565b8152602082013567ffffffffffffffff811115614e7057600080fd5b614e7c89828501614851565b60208301525060408281013590820152606082013567ffffffffffffffff811115614ea657600080fd5b614eb289828501614ae0565b606083015250608082013567ffffffffffffffff811115614ed257600080fd5b614ede89828501614d62565b60808301525060a082013567ffffffffffffffff811115614efe57600080fd5b614f0a89828501614c9e565b60a0830152509250614f20905060608601614dde565b905092959194509250565b60008083601f840112614f3d57600080fd5b50813567ffffffffffffffff811115614f5557600080fd5b6020830191508360208285010111156122d657600080fd5b60008060208385031215614f8057600080fd5b823567ffffffffffffffff811115614f9757600080fd5b614fa385828601614f2b565b90969095509350505050565b60008060008060608587031215614fc557600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156146d157600080fd5b60008060408385031215614ffd57600080fd5b82359150602083013561472c8161459b565b6000806040838503121561502257600080fd5b50508035926020909101359150565b6000806040838503121561504457600080fd5b823567ffffffffffffffff81111561505b57600080fd5b830161012081860312156149a057600080fd5b60008060006060848603121561508357600080fd5b833561508e8161459b565b92506020840135915060408401356150a58161459b565b809150509250925092565b602080825282518282018190526000918401906040840190835b818110156149ef5783518352602093840193909201916001016150ca565b6000806000606084860312156150fd57600080fd5b83356151088161459b565b95602085013595506040909401359392505050565b60008060006040848603121561513257600080fd5b83359250602084013567ffffffffffffffff81111561515057600080fd5b61515c86828701614648565b9497909650939450505050565b60006020828403121561517b57600080fd5b81356107058161459b565b60006020828403121561519857600080fd5b5035919050565b600080600080606085870312156151b557600080fd5b84356151c08161459b565b935060208501359250604085013567ffffffffffffffff8111156151e357600080fd5b6146dd87828801614f2b565b6000806020838503121561520257600080fd5b823567ffffffffffffffff81111561521957600080fd5b614fa385828601614648565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261525a57600080fd5b83018035915067ffffffffffffffff82111561527557600080fd5b6020019150600581901b36038213156122d657600080fd5b6000610705368484614cfb565b6000610705368484614a79565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261530b57600080fd5b83018035915067ffffffffffffffff82111561532657600080fd5b6020019150368190038213156122d657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b602081016003831061537e5761537e61533b565b91905290565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff418336030181126153b857600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18336030181126153b857600080fd5b6000610705368484614bdd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361546357615463615403565b5060010190565b808201808211156105fa576105fa615403565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b6001600160a01b03851681526060602082015260006154cb60608301858761547d565b905082604083015295945050505050565b60006105fa3683614a1e565b6001600160a01b03841681528260208201526060604082015260006105e46060830184614b61565b84815260808101600485106155275761552761533b565b60208201949094526001600160a01b0392831660408201529116606090910152919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa18336030181126153b857600080fd5b60006020828403121561559257600080fd5b813561070581614baf565b600082516153b8818460208701614b3d565b600080858511156155bf57600080fd5b838611156155cc57600080fd5b5050820193919092039150565b80357fff000000000000000000000000000000000000000000000000000000000000008116906001841015615638577fff00000000000000000000000000000000000000000000000000000000000000808560010360031b1b82161691505b5092915050565b803560208310156105fa577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b600082601f83011261568c57600080fd5b81516020830160006156a061487684614829565b90508281528583830111156156b457600080fd5b611474836020830184614b3d565b6000602082840312156156d457600080fd5b815167ffffffffffffffff8111156156eb57600080fd5b6105e78482850161567b565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261572c57600080fd5b830160208101925035905067ffffffffffffffff81111561574c57600080fd5b8036038213156122d657600080fd5b8281526040602082015261578260408201615775846145b3565b6001600160a01b03169052565b60208201356060820152600061579b60408401846156f7565b61012060808501526157b26101608501828461547d565b9150506157c260608501856156f7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08584030160a08601526157f783828461547d565b608087013560c08781019190915260a088013560e0808901919091529088013561010088015290935061582f925086019050856156f7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08584030161012086015261586583828461547d565b925050506158776101008501856156f7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08584030161014086015261368483828461547d565b80357fffffffff000000000000000000000000000000000000000000000000000000008116906004841015615638577fffffffff00000000000000000000000000000000000000000000000000000000808560040360031b1b82161691505092915050565b8681526001600160a01b03861660208201526001600160a01b038516604082015283606082015260a0608082015260006124b860a08301848661547d565b600082601f83011261596157600080fd5b815161596f614876826149fa565b8082825260208201915060208360061b86010192508583111561599157600080fd5b602085015b838110156159ea57604081880312156159ae57600080fd5b6159b6614766565b815167ffffffffffffffff811681146159ce57600080fd5b8152602082810151818301529084529290920191604001615996565b5095945050505050565b80516145be8161459b565b600082601f830112615a1057600080fd5b8151615a1e614876826149fa565b8082825260208201915060208360051b860101925085831115615a4057600080fd5b602085015b838110156159ea57805167ffffffffffffffff811115615a6457600080fd5b86016040818903601f19011215615a7a57600080fd5b615a82614766565b6020820151615a908161459b565b8152604082015167ffffffffffffffff811115615aac57600080fd5b615abb8a60208386010161567b565b6020830152508085525050602083019250602081019050615a45565b600060408284031215615ae957600080fd5b615af1614766565b9050815167ffffffffffffffff811115615b0a57600080fd5b8201601f81018413615b1b57600080fd5b8051615b29614876826149fa565b8082825260208201915060208360051b850101925086831115615b4b57600080fd5b602084015b83811015615b8d57805167ffffffffffffffff811115615b6f57600080fd5b615b7e8960208389010161567b565b84525060209283019201615b50565b508452505050602082015167ffffffffffffffff811115615bad57600080fd5b614a6d848285016159ff565b600082601f830112615bca57600080fd5b8151615bd8614876826149fa565b8082825260208201915060208360051b860101925085831115615bfa57600080fd5b602085015b838110156159ea57805167ffffffffffffffff811115615c1e57600080fd5b86016060818903601f19011215615c3457600080fd5b615c3c61478f565b6020820151615c4a81614baf565b81526040820151615c5a8161459b565b6020820152606082015167ffffffffffffffff811115615c7957600080fd5b615c888a6020838601016159ff565b60408301525084525060209283019201615bff565b600060c08284031215615caf57600080fd5b615cb76147b2565b9050615cc2826159f4565b8152602082015167ffffffffffffffff811115615cde57600080fd5b615cea8482850161567b565b60208301525060408281015190820152606082015167ffffffffffffffff811115615d1457600080fd5b615d20848285016159ff565b606083015250608082015167ffffffffffffffff811115615d4057600080fd5b615d4c84828501615ad7565b60808301525060a082015167ffffffffffffffff811115615d6c57600080fd5b615d7884828501615bb9565b60a08301525092915050565b60008060408385031215615d9757600080fd5b825167ffffffffffffffff811115615dae57600080fd5b830160808186031215615dc057600080fd5b615dc86147d5565b815160ff81168114615dd957600080fd5b8152602082015167ffffffffffffffff811115615df557600080fd5b615e0187828501615950565b602083015250604082015167ffffffffffffffff811115615e2157600080fd5b615e2d87828501615c9d565b604083015250606082015167ffffffffffffffff811115615e4d57600080fd5b615e598782850161567b565b6060830152508093505050602083015167ffffffffffffffff811115615e7e57600080fd5b6108bb8582860161567b565b6001600160a01b0384168152606060208201526000615eac6060830185614b61565b9050826040830152949350505050565b8281526040602082015260006107026040830184614b61565b600060208284031215615ee757600080fd5b815161070581614baf565b600060208284031215615f0457600080fd5b8151801515811461070557600080fd5b818103818111156105fa576105fa615403565b600082615f5d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8151600090829060208501835b82811015615f8d578151845260209384019390910190600101615f6f565b509195945050505050565b80357fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008116906014841015615638577fffffffffffffffffffffffffffffffffffffffff000000000000000000000000808560140360031b1b82161691505092915050565b8381526060602082015260006160166060830185614b61565b828103604084015261094b8185614b61565b600082601f83011261603957600080fd5b8151616047614876826149fa565b8082825260208201915060208360051b86010192508583111561606957600080fd5b602085015b838110156159ea57805183526020928301920161606e565b600080600080600080600060e0888a0312156160a157600080fd5b87517fff00000000000000000000000000000000000000000000000000000000000000811681146160d157600080fd5b602089015190975067ffffffffffffffff8111156160ee57600080fd5b6160fa8a828b0161567b565b965050604088015167ffffffffffffffff81111561611757600080fd5b6161238a828b0161567b565b60608a0151909650945061613b9050608089016159f4565b60a089015160c08a0151919450925067ffffffffffffffff81111561615f57600080fd5b61616b8a828b01616028565b9150509295989194975092955056fea164736f6c634300081b000a"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/EntryPoint.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/EntryPoint.sol new file mode 100644 index 0000000..3c71244 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/EntryPoint.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Utils +import { etch } from "../../test/utils/Vm.sol"; + +// Interfaces +import { IEntryPoint } from "../../external/ERC4337.sol"; + +// External Dependencies +import { SenderCreator } from "@ERC4337/account-abstraction/contracts/core/EntryPoint.sol"; +import { EntryPointSimulations } from + "@ERC4337/account-abstraction/contracts/core/EntryPointSimulations.sol"; + +contract EntryPointSimulationsPatch is EntryPointSimulations { + address public _entrypointAddr = address(this); + + SenderCreator public _newSenderCreator; + + function init(address entrypointAddr) public { + _entrypointAddr = entrypointAddr; + initSenderCreator(); + } + + function initSenderCreator() internal override { + //this is the address of the first contract created with CREATE by this address. + address createdObj = address( + uint160(uint256(keccak256(abi.encodePacked(hex"d694", _entrypointAddr, hex"01")))) + ); + _newSenderCreator = SenderCreator(createdObj); + } + + function senderCreator() internal view virtual override returns (SenderCreator) { + return _newSenderCreator; + } +} + +/// @dev Preset entrypoint address +address constant ENTRYPOINT_ADDR = 0x0000000071727De22E5E9d8BAf0edAc6f37da032; + +function etchEntrypoint() returns (IEntryPoint) { + address payable entryPoint = payable(address(new EntryPointSimulationsPatch())); + etch(ENTRYPOINT_ADDR, entryPoint.code); + EntryPointSimulationsPatch(payable(ENTRYPOINT_ADDR)).init(entryPoint); + + return IEntryPoint(ENTRYPOINT_ADDR); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/MockFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/MockFactory.sol new file mode 100644 index 0000000..66592f5 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/MockFactory.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; +/* solhint-enable no-unused-import */ + +// Dependencies +import { MockUniswap, ISwapRouter } from "../../integrations/uniswap/MockUniswap.sol"; +import { SWAPROUTER_ADDRESS } from "../../integrations/uniswap/helpers/MainnetAddresses.sol"; + +// Utils +import { etch } from "../../test/utils/Vm.sol"; + +contract MockFactory { + ISwapRouter public uniswap; + + constructor() { + if (SWAPROUTER_ADDRESS.code.length == 0) { + MockUniswap _mockUniswap = new MockUniswap(); + etch(SWAPROUTER_ADDRESS, address(_mockUniswap).code); + uniswap = ISwapRouter(SWAPROUTER_ADDRESS); + } + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/Registry.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/Registry.sol new file mode 100644 index 0000000..3557324 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/Registry.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IERC7484 } from "../../Interfaces.sol"; + +// Mocks +import { MockRegistry } from "../../Mocks.sol"; + +// Utils +import { etch } from "../../test/utils/Vm.sol"; + +/// @dev Preset registry address +address constant REGISTRY_ADDR = 0x000000000069E2a187AEFFb852bF3cCdC95151B2; + +function etchRegistry() returns (IERC7484) { + address _registry = address(new MockRegistry()); + etch(REGISTRY_ADDR, _registry.code); + return IERC7484(REGISTRY_ADDR); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/RegistryDeployer.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/RegistryDeployer.sol new file mode 100644 index 0000000..1d09abf --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/RegistryDeployer.sol @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IRegistry, IExternalResolver } from "./interfaces/IRegistry.sol"; +import { IExternalSchemaValidator } from "./interfaces/IExternalSchemaValidator.sol"; + +// Types +import { + ResolverRecord, + ModuleRecord, + ResolverUID, + AttestationRecord, + AttestationRequest, + ModuleType, + SchemaUID, + SchemaRecord +} from "./types/DataTypes.sol"; + +/// @dev Preset registry address +address constant REGISTRY_ADDR = 0x000000000069E2a187AEFFb852bF3cCdC95151B2; + +contract RegistryDeployer { + IRegistry internal registry = IRegistry(REGISTRY_ADDR); + + // Default resolver + ResolverUID internal resolverUID = + ResolverUID.wrap(0xdbca873b13c783c0c9c6ddfc4280e505580bf6cc3dac83f8a0f7b44acaafca4f); + + SchemaUID internal schemaUID = + SchemaUID.wrap(0x93d46fcca4ef7d66a413c7bde08bb1ff14bacbd04c4069bb24cd7c21729d7bf1); + + address internal mockAttester = 0xA4C777199658a41688E9488c4EcbD7a2925Cc23A; + + error InvalidResolver(); + + /*////////////////////////////////////////////////////////////// + DEPLOYMENT + //////////////////////////////////////////////////////////////*/ + + function deployModule( + bytes memory initCode, + bytes32 salt, + bytes memory metadata, + bytes memory resolverContext + ) + public + returns (address moduleAddr) + { + ResolverUID _resolverUID = findResolver(); + moduleAddr = registry.deployModule({ + resolverUID: _resolverUID, + initCode: initCode, + salt: salt, + metadata: metadata, + resolverContext: resolverContext + }); + } + + function deployModuleViaFactory( + address factory, + bytes memory callOnFactory, + bytes memory metadata, + bytes memory resolverContext + ) + public + returns (address moduleAddr) + { + ResolverUID _resolverUID = findResolver(); + moduleAddr = registry.deployViaFactory({ + factory: factory, + callOnFactory: callOnFactory, + metadata: metadata, + resolverUID: _resolverUID, + resolverContext: resolverContext + }); + } + + function predictModuleAddress( + bytes32 salt, + bytes memory initCode + ) + public + view + returns (address) + { + return registry.calcModuleAddress(salt, initCode); + } + + /*////////////////////////////////////////////////////////////// + REGISTRATION + //////////////////////////////////////////////////////////////*/ + + function registerModule( + address module, + bytes memory metadata, + bytes memory resolverContext + ) + public + { + ResolverUID _resolverUID = findResolver(); + registry.registerModule({ + resolverUID: _resolverUID, + moduleAddress: module, + metadata: metadata, + resolverContext: resolverContext + }); + } + + function findModule(address moduleAddress) public view returns (ModuleRecord memory) { + return registry.findModule(moduleAddress); + } + + /*////////////////////////////////////////////////////////////// + ATTESTATION + //////////////////////////////////////////////////////////////*/ + + function mockAttestToModule( + address module, + bytes memory attestationData, + ModuleType[] memory moduleTypes + ) + public + { + // solhint-disable-next-line gas-custom-errors + require(isContract(mockAttester), "MockAttester not deployed"); + + SchemaUID _schemaUID = findSchema(); + AttestationRequest memory request = AttestationRequest({ + moduleAddress: module, + expirationTime: 0, + data: attestationData, + moduleTypes: moduleTypes + }); + (bool success,) = mockAttester.call( + abi.encodeWithSignature( + "attest(address,bytes32,(address,uint48,bytes,uint256[]))", + REGISTRY_ADDR, + _schemaUID, + request + ) + ); + + // solhint-disable-next-line gas-custom-errors + require(success, "Mock attestation failed"); + } + + function isModuleAttestedMock(address module) public view returns (bool) { + AttestationRecord memory attestation = + registry.findAttestation({ module: module, attester: mockAttester }); + return attestation.time > 0 && attestation.expirationTime < block.timestamp + && attestation.revocationTime == 0; + } + + /*////////////////////////////////////////////////////////////// + MANAGEMENT + //////////////////////////////////////////////////////////////*/ + + function findResolver() public view returns (ResolverUID _resolverUID) { + _resolverUID = resolverUID; + ResolverRecord memory resolver = registry.findResolver(resolverUID); + if (address(resolver.resolver) == address(0)) { + revert InvalidResolver(); + } + } + + function registerResolver(address resolver) public returns (ResolverUID _resolverUID) { + _resolverUID = registry.registerResolver(IExternalResolver(resolver)); + } + + function findSchema() public view returns (SchemaUID _schemaUID) { + _schemaUID = schemaUID; + SchemaRecord memory schema = registry.findSchema(schemaUID); + if (schema.registeredAt == 0) { + revert InvalidResolver(); + } + } + + function registerSchema( + string memory schema, + address validator + ) + public + returns (SchemaUID _schemaUID) + { + _schemaUID = registry.registerSchema({ + schema: schema, + validator: IExternalSchemaValidator(validator) + }); + } + + function setRegistry(address _registry) public { + registry = IRegistry(_registry); + } + + function setResolverUID(ResolverUID _resolverUID) public { + resolverUID = _resolverUID; + } + + function setSchemaUID(SchemaUID _schemaUID) public { + schemaUID = _schemaUID; + } + + /*////////////////////////////////////////////////////////////// + OTHER + //////////////////////////////////////////////////////////////*/ + + function isContract(address _addr) internal view returns (bool _isContract) { + uint32 size; + // solhint-disable-next-line no-inline-assembly + assembly { + size := extcodesize(_addr) + } + return (size > 0); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IERC7484.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IERC7484.sol new file mode 100644 index 0000000..152a069 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IERC7484.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +// Types +import { ModuleType } from "../types/DataTypes.sol"; + +interface IERC7484 { + event NewTrustedAttesters(address indexed smartAccount); + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Check with Registry internal attesters */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function check(address module) external view; + + function checkForAccount(address smartAccount, address module) external view; + + function check(address module, ModuleType moduleType) external view; + + function checkForAccount( + address smartAccount, + address module, + ModuleType moduleType + ) + external + view; + + /** + * Allows Smart Accounts - the end users of the registry - to appoint + * one or many attesters as trusted. + * @dev this function reverts, if address(0), or duplicates are provided in attesters[] + * + * @param threshold The minimum number of attestations required for a module + * to be considered secure. + * @param attesters The addresses of the attesters to be trusted. + */ + function trustAttesters(uint8 threshold, address[] calldata attesters) external; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Check with external attester(s) */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function check(address module, address[] calldata attesters, uint256 threshold) external view; + + function check( + address module, + ModuleType moduleType, + address[] calldata attesters, + uint256 threshold + ) + external + view; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalResolver.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalResolver.sol new file mode 100644 index 0000000..bdaa2f3 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalResolver.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +// Interfaces +import { IERC165 } from "forge-std/interfaces/IERC165.sol"; + +// Types +import { AttestationRecord, ModuleRecord } from "../types/DataTypes.sol"; + +/** + * @title The interface of an optional schema resolver. + * @dev The resolver is responsible for validating the schema and attestation data. + * @dev The resolver is also responsible for processing the attestation and revocation requests. + * + */ +interface IExternalResolver is IERC165 { + /** + * @dev Processes an attestation and verifies whether it's valid. + * + * @param attestation The new attestation. + * + * @return Whether the attestation is valid. + */ + function resolveAttestation(AttestationRecord calldata attestation) + external + payable + returns (bool); + + function resolveAttestation(AttestationRecord[] calldata attestation) + external + payable + returns (bool); + + /** + * @dev Processes an attestation revocation and verifies if it can be revoked. + * + * @param attestation The existing attestation to be revoked. + * + * @return Whether the attestation can be revoked. + */ + function resolveRevocation(AttestationRecord calldata attestation) + external + payable + returns (bool); + function resolveRevocation(AttestationRecord[] calldata attestation) + external + payable + returns (bool); + + /** + * @dev Processes a Module Registration + * + * @param sender The msg.sender of the module registration + * @param moduleAddress address of the module + * @param record Module registration artefact + * + * @return Whether the registration is valid + */ + function resolveModuleRegistration( + address sender, + address moduleAddress, + ModuleRecord calldata record, + bytes calldata resolverContext + ) + external + payable + returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalSchemaValidator.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalSchemaValidator.sol new file mode 100644 index 0000000..7d84a3d --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalSchemaValidator.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +// Interfaces +import { IERC165 } from "forge-std/interfaces/IERC165.sol"; + +// Types +import { AttestationRecord } from "../types/DataTypes.sol"; + +/** + * @title The interface of an optional schema resolver. + */ +interface IExternalSchemaValidator is IERC165 { + /** + * @notice Validates an attestation request. + */ + function validateSchema(AttestationRecord calldata attestation) external returns (bool); + + /** + * @notice Validates an array of attestation requests. + */ + function validateSchema(AttestationRecord[] calldata attestations) external returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IRegistry.sol new file mode 100644 index 0000000..003afed --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IRegistry.sol @@ -0,0 +1,419 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +// Interfaces +import { IExternalSchemaValidator } from "./IExternalSchemaValidator.sol"; +import { IExternalResolver } from "./IExternalResolver.sol"; +import { IERC7484 } from "./IERC7484.sol"; + +// Types +import { + AttestationDataRef, + AttestationRecord, + AttestationRequest, + ModuleRecord, + ResolverUID, + ResolverRecord, + RevocationRequest, + SchemaUID, + SchemaRecord +} from "../types/DataTypes.sol"; + +/** + * Interface definition of all features of the registry: + * - Register Schemas + * - Register External Resolvers + * - Register Modules + * - Make Attestations + * - Make Revocations + * - Delegate Trust to Attester(s) + * + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) + */ +interface IRegistry is IERC7484 { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Smart Account - Trust Management */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + error InvalidResolver(IExternalResolver resolver); + error InvalidResolverUID(ResolverUID uid); + error InvalidTrustedAttesterInput(); + error NoTrustedAttestersFound(); + error RevokedAttestation(address attester); + error InvalidModuleType(); + error AttestationNotFound(); + + error InsufficientAttestations(); + + /** + * Get trusted attester for a specific Smart Account + * @param smartAccount The address of the Smart Account + */ + function findTrustedAttesters(address smartAccount) + external + view + returns (address[] memory attesters); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Attestations */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + event Revoked(address indexed moduleAddress, address indexed revoker, SchemaUID schema); + event Attested( + address indexed moduleAddress, + address indexed attester, + SchemaUID schemaUID, + AttestationDataRef indexed sstore2Pointer + ); + + error AlreadyRevoked(); + error AlreadyAttested(); + error ModuleNotFoundInRegistry(address module); + error AccessDenied(); + error InvalidAttestation(); + error InvalidExpirationTime(); + error DifferentResolvers(); + error InvalidSignature(); + error InvalidModuleTypes(); + + /** + * Allows `msg.sender` to attest to multiple modules' security status. + * The `AttestationRequest.Data` provided should match the attestation + * schema defined by the Schema corresponding to the SchemaUID + * + * @dev This function will revert if the same module is attested twice by the same attester. + * If you want to re-attest, you have to revoke your attestation first, and then attest + * again. + * + * @param schemaUID The SchemaUID of the schema the attestation is based on. + * @param request a single AttestationRequest + */ + function attest(SchemaUID schemaUID, AttestationRequest calldata request) external; + + /** + * Allows `msg.sender` to attest to multiple modules' security status. + * The `AttestationRequest.Data` provided should match the attestation + * schema defined by the Schema corresponding to the SchemaUID + * + * @dev This function will revert if the same module is attested twice by the same attester. + * If you want to re-attest, you have to revoke your attestation first, and then attest + * again. + * + * @param schemaUID The SchemaUID of the schema the attestation is based on. + * @param requests An array of AttestationRequest + */ + function attest(SchemaUID schemaUID, AttestationRequest[] calldata requests) external; + + /** + * Allows attester to attest by signing an `AttestationRequest` (`ECDSA` or `ERC1271`) + * The `AttestationRequest.Data` provided should match the attestation + * schema defined by the Schema corresponding to the SchemaUID + * + * @dev This function will revert if the same module is attested twice by the same attester. + * If you want to re-attest, you have to revoke your attestation first, and then attest + * again. + * + * @param schemaUID The SchemaUID of the schema the attestation is based on. + * @param attester The address of the attester + * @param request An AttestationRequest + * @param signature The signature of the attester. ECDSA or ERC1271 + */ + function attest( + SchemaUID schemaUID, + address attester, + AttestationRequest calldata request, + bytes calldata signature + ) + external; + + /** + * Allows attester to attest by signing an `AttestationRequest` (`ECDSA` or `ERC1271`) + * The `AttestationRequest.Data` provided should match the attestation + * schema defined by the Schema corresponding to the SchemaUID + * + * @dev This function will revert if the same module is attested twice by the same attester. + * If you want to re-attest, you have to revoke your attestation first, and then attest + * again. + * + * @param schemaUID The SchemaUID of the schema the attestation is based on. + * @param attester The address of the attester + * @param requests An array of AttestationRequest + * @param signature The signature of the attester. ECDSA or ERC1271 + */ + function attest( + SchemaUID schemaUID, + address attester, + AttestationRequest[] calldata requests, + bytes calldata signature + ) + external; + + /** + * Getter function to get AttestationRequest made by one attester + */ + function findAttestation( + address module, + address attester + ) + external + view + returns (AttestationRecord memory attestation); + + /** + * Getter function to get AttestationRequest made by multiple attesters + */ + function findAttestations( + address module, + address[] calldata attesters + ) + external + view + returns (AttestationRecord[] memory attestations); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Revocations */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /** + * Allows `msg.sender` to revoke an attestation made by the same `msg.sender` + * + * @dev this function will revert if the attestation is not found + * @dev this function will revert if the attestation is already revoked + * + * @param request single RevocationRequest + */ + function revoke(RevocationRequest calldata request) external; + + /** + * Allows msg.sender to revoke multiple attestation made by the same msg.sender + * + * @dev this function will revert if the attestation is not found + * @dev this function will revert if the attestation is already revoked + * + * @param requests the RevocationRequests + */ + function revoke(RevocationRequest[] calldata requests) external; + + /** + * Allows attester to revoke an attestation by signing an `RevocationRequest` (`ECDSA` or + * `ERC1271`) + * + * @param attester the signer / revoker + * @param request single RevocationRequest + * @param signature ECDSA or ERC1271 signature + */ + function revoke( + address attester, + RevocationRequest calldata request, + bytes calldata signature + ) + external; + + /** + * Allows attester to revoke an attestation by signing an `RevocationRequest` (`ECDSA` or + * `ERC1271`) + * @dev if you want to revoke multiple attestations, but from different attesters, call this + * function multiple times + * + * @param attester the signer / revoker + * @param requests array of RevocationRequests + * @param signature ECDSA or ERC1271 signature + */ + function revoke( + address attester, + RevocationRequest[] calldata requests, + bytes calldata signature + ) + external; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Module Registration */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + // Event triggered when a module is deployed. + event ModuleRegistration(address indexed implementation); + + error AlreadyRegistered(address module); + error InvalidDeployment(); + error ModuleAddressIsNotContract(address moduleAddress); + error FactoryCallFailed(address factory); + + /** + * Module Developers can deploy their module Bytecode directly via the registry. + * This registry implements a `CREATE2` factory, that allows module developers to register and + * deploy module bytecode + * @param salt The salt to be used in the `CREATE2` factory. This adheres to + * Pr000xy/Create2Factory.sol salt formatting. + * The salt's first bytes20 should be the address of the sender + * or bytes20(0) to bypass the check (this will lose replay protection) + * @param resolverUID The resolverUID to be used in the `CREATE2` factory + * @param initCode The initCode to be used in the `CREATE2` factory + * @param metadata The metadata to be stored on the registry. + * This field is optional, and might be used by the module developer to store + * additional + * information about the module or facilitate business logic with the Resolver stub + * @param resolverContext bytes that will be passed to the resolver contract + */ + function deployModule( + bytes32 salt, + ResolverUID resolverUID, + bytes calldata initCode, + bytes calldata metadata, + bytes calldata resolverContext + ) + external + payable + returns (address moduleAddress); + + /** + * In order to make the integration into existing business logics possible, + * the Registry is able to utilize external factories that can be utilized to deploy the + * modules. + * @dev Registry can use other factories to deploy the module. + * @dev Note that this function will call the external factory via the FactoryTrampoline + * contract. + * Factory MUST not assume that msg.sender == registry + * @dev This function is used to deploy and register a module using a factory contract. + * Since one of the parameters of this function is a unique resolverUID and any + * registered module address can only be registered once, + * using this function is of risk for a frontrun attack + */ + function deployViaFactory( + address factory, + bytes calldata callOnFactory, + bytes calldata metadata, + ResolverUID resolverUID, + bytes calldata resolverContext + ) + external + payable + returns (address moduleAddress); + + /** + * Already deployed module addresses can be registered on the registry + * @dev This function is used to deploy and register an already deployed module. + * Since one of the parameters of this function is a unique resolverUID and any + * registered module address can only be registered once, + * using this function is of risk for a frontrun attack + * @dev the sender address of this registration is set to address(0) since anyone can invoke + * this function + * @param resolverUID The resolverUID to be used for the module + * @param moduleAddress The address of the module to be registered + * @param metadata The metadata to be stored on the registry. + * This field is optional, and might be used by the module developer to store + * additional + * information about the module or facilitate business logic with the Resolver stub + * @param resolverContext bytes that will be passed to the resolver contract + */ + function registerModule( + ResolverUID resolverUID, + address moduleAddress, + bytes calldata metadata, + bytes calldata resolverContext + ) + external; + + /** + * in conjunction with the deployModule() function, this function let's you + * predict the address of a CREATE2 module deployment + * @param salt CREATE2 salt + * @param initCode module initcode + * @return moduleAddress counterfactual address of the module deployment + */ + function calcModuleAddress( + bytes32 salt, + bytes calldata initCode + ) + external + view + returns (address); + + /** + * Getter function to get the stored ModuleRecord for a specific module address. + * @param moduleAddress The address of the module + */ + function findModule(address moduleAddress) + external + view + returns (ModuleRecord memory moduleRecord); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Manage Schemas */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + event SchemaRegistered(SchemaUID indexed uid, address indexed registerer); + + error SchemaAlreadyExists(SchemaUID uid); + + error InvalidSchema(); + error InvalidSchemaValidator(IExternalSchemaValidator validator); + + /** + * Register Schema and (optional) external `IExternalSchemaValidator` + * A Schema describe the structure of the data of attestations + * every attestation made on this registry, will reference a SchemaUID to + * make it possible to decode attestation data in human readable form + * overwriting a schema is not allowed, and will revert + * @param schema ABI schema used to encode attestations that are made with this schema + * @param validator (optional) external schema validator that will be used to validate + * attestations. + * use address(0), if you don't need an external validator + * @return uid SchemaUID of the registered schema + */ + function registerSchema( + string calldata schema, + IExternalSchemaValidator validator // OPTIONAL + ) + external + returns (SchemaUID uid); + + /** + * Getter function to retrieve SchemaRecord + */ + function findSchema(SchemaUID uid) external view returns (SchemaRecord memory record); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Manage Resolvers */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + event NewResolver(ResolverUID indexed uid, address indexed resolver); + event NewResolverOwner(ResolverUID indexed uid, address newOwner); + + error ResolverAlreadyExists(); + + /** + * Allows Marketplace Agents to register external resolvers. + * @param resolver external resolver contract + * @return uid ResolverUID of the registered resolver + */ + function registerResolver(IExternalResolver resolver) external returns (ResolverUID uid); + + /** + * Entities that previously registered an external resolver, may update the implementation + * address. + * @param uid The UID of the resolver. + * @param resolver The new resolver implementation address. + */ + function setResolver(ResolverUID uid, IExternalResolver resolver) external; + + /** + * Transfer ownership of resolverUID to a new address + * @param uid The UID of the resolver to transfer ownership for + * @param newOwner The address of the new owner + */ + function transferResolverOwnership(ResolverUID uid, address newOwner) external; + + /** + * Getter function to get the ResolverRecord of a registered resolver + * @param uid The UID of the resolver. + */ + function findResolver(ResolverUID uid) external view returns (ResolverRecord memory record); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Stub Errors */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + error ExternalError_SchemaValidation(); + error ExternalError_ResolveAttestation(); + error ExternalError_ResolveRevocation(); + error ExternalError_ModuleRegistration(); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/types/DataTypes.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/types/DataTypes.sol new file mode 100644 index 0000000..0343305 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/types/DataTypes.sol @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IExternalSchemaValidator } from "../interfaces/IExternalSchemaValidator.sol"; +import { IExternalResolver } from "../interfaces/IExternalResolver.sol"; + +/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ +/* Storage Structs */ +/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + +struct AttestationRecord { + uint48 time; // The time when the attestation was created (Unix timestamp). + uint48 expirationTime; // The time when the attestation expires (Unix timestamp). + uint48 revocationTime; // The time when the attestation was revoked (Unix timestamp). + PackedModuleTypes moduleTypes; // bit-wise encoded module types. See ModuleTypeLib + address moduleAddress; // The implementation address of the module that is being attested. + address attester; // The attesting account. + AttestationDataRef dataPointer; // SSTORE2 pointer to the attestation data. + SchemaUID schemaUID; // The unique identifier of the schema. +} + +struct ModuleRecord { + ResolverUID resolverUID; // The unique identifier of the resolver. + address sender; // The address of the sender who deployed the contract + bytes metadata; // Additional data related to the contract deployment +} + +struct SchemaRecord { + uint48 registeredAt; // The time when the schema was registered (Unix timestamp). + IExternalSchemaValidator validator; // Optional external schema validator. + string schema; // Custom specification of the schema (e.g., an ABI). +} + +struct ResolverRecord { + IExternalResolver resolver; // Optional resolver. + address resolverOwner; // The address of the account used to register the resolver. +} + +// Struct that represents a trusted attester. +struct TrustedAttesterRecord { + uint8 attesterCount; // number of attesters in the linked list + uint8 threshold; // minimum number of attesters required + address attester; // first attester in linked list. (packed to save gas) + mapping(address attester => mapping(address account => address linkedAttester)) linkedAttesters; +} + +/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ +/* Attestation / Revocation Requests */ +/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + +/** + * @dev A struct representing the arguments of the attestation request. + */ +struct AttestationRequest { + address moduleAddress; // The moduleAddress of the attestation. + uint48 expirationTime; // The time when the attestation expires (Unix timestamp). + bytes data; // Custom attestation data. + ModuleType[] moduleTypes; // optional: The type(s) of the module. +} + +/** + * @dev A struct representing the arguments of the revocation request. + */ +struct RevocationRequest { + address moduleAddress; // The module address. +} + +/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ +/* Custom Types */ +/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + +//---------------------- SchemaUID ------------------------------| +type SchemaUID is bytes32; + +using { schemaEq as == } for SchemaUID global; +using { schemaNotEq as != } for SchemaUID global; + +function schemaEq(SchemaUID uid1, SchemaUID uid2) pure returns (bool) { + return SchemaUID.unwrap(uid1) == SchemaUID.unwrap(uid2); +} + +function schemaNotEq(SchemaUID uid1, SchemaUID uid2) pure returns (bool) { + return SchemaUID.unwrap(uid1) != SchemaUID.unwrap(uid2); +} + +//--------------------- ResolverUID -----------------------------| +type ResolverUID is bytes32; + +using { resolverEq as == } for ResolverUID global; +using { resolverNotEq as != } for ResolverUID global; + +function resolverEq(ResolverUID uid1, ResolverUID uid2) pure returns (bool) { + return ResolverUID.unwrap(uid1) == ResolverUID.unwrap(uid2); +} + +function resolverNotEq(ResolverUID uid1, ResolverUID uid2) pure returns (bool) { + return ResolverUID.unwrap(uid1) != ResolverUID.unwrap(uid2); +} + +type AttestationDataRef is address; + +using { attestationDataRefEq as == } for AttestationDataRef global; + +function attestationDataRefEq( + AttestationDataRef uid1, + AttestationDataRef uid2 +) + pure + returns (bool) +{ + return AttestationDataRef.unwrap(uid1) == AttestationDataRef.unwrap(uid2); +} + +type PackedModuleTypes is uint32; + +type ModuleType is uint256; + +using { moduleTypeEq as == } for ModuleType global; +using { moduleTypeNeq as != } for ModuleType global; + +function moduleTypeEq(ModuleType uid1, ModuleType uid2) pure returns (bool) { + return ModuleType.unwrap(uid1) == ModuleType.unwrap(uid2); +} + +function moduleTypeNeq(ModuleType uid1, ModuleType uid2) pure returns (bool) { + return ModuleType.unwrap(uid1) != ModuleType.unwrap(uid2); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/external/ERC4337.sol b/typescript/packages/account-modules/lib/modulekit/src/external/ERC4337.sol new file mode 100644 index 0000000..65296e5 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/external/ERC4337.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/* solhint-disable no-unused-import */ + +/*////////////////////////////////////////////////////////////// + USEROP +//////////////////////////////////////////////////////////////*/ + +import { PackedUserOperation } from + "@ERC4337/account-abstraction/contracts/interfaces/PackedUserOperation.sol"; +import { UserOperationLib } from "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; + +/*////////////////////////////////////////////////////////////// + ENTRYPOINT +//////////////////////////////////////////////////////////////*/ + +import { EntryPointSimulations } from + "@ERC4337/account-abstraction/contracts/core/EntryPointSimulations.sol"; + +/*////////////////////////////////////////////////////////////// + VALIDATION +//////////////////////////////////////////////////////////////*/ + +import { + ValidationData, + _packValidationData +} from "@ERC4337/account-abstraction/contracts/core/Helpers.sol"; + +/*////////////////////////////////////////////////////////////// + INTERFACES +//////////////////////////////////////////////////////////////*/ + +import { IStakeManager } from "@ERC4337/account-abstraction/contracts/interfaces/IStakeManager.sol"; +import { IAccount as IERC4337 } from + "@ERC4337/account-abstraction/contracts/interfaces/IAccount.sol"; +import { IAccountExecute } from + "@ERC4337/account-abstraction/contracts/interfaces/IAccountExecute.sol"; +import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/IEntryPoint.sol"; +import { IEntryPointSimulations } from + "@ERC4337/account-abstraction/contracts/interfaces/IEntryPointSimulations.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC20.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC20.sol new file mode 100644 index 0000000..94686d8 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC20.sol @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IERC20 } from "forge-std/interfaces/IERC20.sol"; + +// Types +import { Execution } from "../accounts/erc7579/lib/ExecutionLib.sol"; + +// Dependencies +import { ERC7579Exec } from "./ERC7579Exec.sol"; + +library ERC20Integration { + using ERC7579Exec for address; + + error SafeERC20TransferFailed(); + + function safeApprove( + IERC20 token, + address spender, + uint256 amount + ) + internal + pure + returns (Execution memory exec0, Execution memory exec1) + { + exec0 = Execution({ + target: address(token), + value: 0, + callData: abi.encodeCall(IERC20.approve, (spender, 0)) + }); + exec1 = Execution({ + target: address(token), + value: 0, + callData: abi.encodeCall(IERC20.approve, (spender, amount)) + }); + } + + function approve( + IERC20 token, + address spender, + uint256 amount + ) + internal + pure + returns (Execution memory exec) + { + exec = Execution({ + target: address(token), + value: 0, + callData: abi.encodeCall(IERC20.approve, (spender, amount)) + }); + } + + function safeTransfer(IERC20 token, address to, uint256 amount) internal { + safeTransfer(token, msg.sender, to, amount); + } + + function safeTransfer(IERC20 token, address account, address to, uint256 amount) internal { + bytes memory ret = account.exec7579({ + to: address(token), + value: 0, + data: abi.encodeCall(IERC20.transfer, (to, amount)) + }); + if (ret.length != 0) { + bool success = abi.decode(ret, (bool)); + if (!success) revert SafeERC20TransferFailed(); + } + } + + function safeTransferFrom(IERC20 token, address from, address to, uint256 amount) internal { + safeTransferFrom(token, msg.sender, from, to, amount); + } + + function safeTransferFrom( + IERC20 token, + address account, + address from, + address to, + uint256 amount + ) + internal + { + bytes memory ret = account.exec7579({ + to: address(token), + value: 0, + data: abi.encodeCall(IERC20.transferFrom, (from, to, amount)) + }); + + bytes[] memory retValues = abi.decode(ret, (bytes[])); + if (retValues[0].length != 0) { + bool success = abi.decode(retValues[0], (bool)); + if (!success) revert SafeERC20TransferFailed(); + } + } + + function transfer( + IERC20 token, + address to, + uint256 amount + ) + internal + pure + returns (Execution memory exec) + { + exec = Execution({ + target: address(token), + value: 0, + callData: abi.encodeCall(IERC20.transfer, (to, amount)) + }); + } + + function transferFrom( + IERC20 token, + address from, + address to, + uint256 amount + ) + internal + pure + returns (Execution memory exec) + { + exec = Execution({ + target: address(token), + value: 0, + callData: abi.encodeCall(IERC20.transferFrom, (from, to, amount)) + }); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC4626.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC4626.sol new file mode 100644 index 0000000..e9883e8 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC4626.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IERC4626 } from "forge-std/interfaces/IERC4626.sol"; + +// Types +import { Execution } from "../accounts/erc7579/lib/ExecutionLib.sol"; + +library ERC4626Integration { + function deposit( + IERC4626 vault, + uint256 assets, + address receiver + ) + internal + pure + returns (Execution memory exec) + { + exec = Execution({ + target: address(vault), + value: 0, + callData: abi.encodeCall(IERC4626.deposit, (assets, receiver)) + }); + } + + function mint( + IERC4626 vault, + uint256 shares, + address receiver + ) + internal + pure + returns (Execution memory exec) + { + exec = Execution({ + target: address(vault), + value: 0, + callData: abi.encodeCall(IERC4626.mint, (shares, receiver)) + }); + } + + function withdraw( + IERC4626 vault, + uint256 assets, + address receiver, + address owner + ) + internal + pure + returns (Execution memory exec) + { + exec = Execution({ + target: address(vault), + value: 0, + callData: abi.encodeCall(IERC4626.withdraw, (assets, receiver, owner)) + }); + } + + function redeem( + IERC4626 vault, + uint256 shares, + address receiver, + address owner + ) + internal + pure + returns (Execution memory exec) + { + exec = Execution({ + target: address(vault), + value: 0, + callData: abi.encodeCall(IERC4626.redeem, (shares, receiver, owner)) + }); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC721.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC721.sol new file mode 100644 index 0000000..73ca531 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC721.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IERC721 } from "forge-std/interfaces/IERC721.sol"; + +// Types +import { Execution } from "../accounts/erc7579/lib/ExecutionLib.sol"; + +library ERC721Integration { + function approve( + IERC721 token, + address spender, + uint256 tokenId + ) + internal + pure + returns (Execution memory exec) + { + exec = Execution({ + target: address(token), + value: 0, + callData: abi.encodeCall(IERC721.approve, (spender, tokenId)) + }); + } + + function transferFrom( + IERC721 token, + address from, + address to, + uint256 tokenId + ) + internal + pure + returns (Execution memory exec) + { + exec = Execution({ + target: address(token), + value: 0, + callData: abi.encodeCall(IERC721.transferFrom, (from, to, tokenId)) + }); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC7579Exec.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC7579Exec.sol new file mode 100644 index 0000000..a6ba148 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC7579Exec.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +// Libraries +import { + Execution, + ExecutionLib as ERC7579ExecutionLib +} from "../accounts/erc7579/lib/ExecutionLib.sol"; +import { + ModeLib as ERC7579ModeLib, + CALLTYPE_SINGLE, + CALLTYPE_BATCH, + EXECTYPE_DEFAULT, + CALLTYPE_DELEGATECALL, + MODE_DEFAULT, + ModePayload, + ModeCode +} from "../accounts/common/lib/ModeLib.sol"; + +// Interfaces +import { IERC7579Account } from "../accounts/common/interfaces/IERC7579Account.sol"; + +library ERC7579Exec { + function exec7579( + address account, + address to, + uint256 value, + bytes memory data + ) + internal + returns (bytes memory result) + { + ModeCode modeCode = ERC7579ModeLib.encode({ + callType: CALLTYPE_SINGLE, + execType: EXECTYPE_DEFAULT, + mode: MODE_DEFAULT, + payload: ModePayload.wrap(bytes22(0)) + }); + + return IERC7579Account(account).executeFromExecutor( + modeCode, ERC7579ExecutionLib.encodeSingle(to, value, data) + )[0]; + } + + function exec7579( + address to, + uint256 value, + bytes memory data + ) + internal + returns (bytes memory result) + { + return exec7579(msg.sender, to, value, data); + } + + function exec7579( + address account, + Execution[] memory execs + ) + internal + returns (bytes[] memory results) + { + ModeCode modeCode = ERC7579ModeLib.encode({ + callType: CALLTYPE_BATCH, + execType: EXECTYPE_DEFAULT, + mode: MODE_DEFAULT, + payload: ModePayload.wrap(bytes22(0)) + }); + results = IERC7579Account(account).executeFromExecutor( + modeCode, ERC7579ExecutionLib.encodeBatch(execs) + ); + } + + function exec7579(Execution[] memory execs) internal returns (bytes[] memory results) { + return exec7579(msg.sender, execs); + } + + // Note: Not every account will support delegatecalls + function exec7579( + address account, + address delegateTarget, + bytes memory callData + ) + internal + returns (bytes[] memory results) + { + ModeCode modeCode = ERC7579ModeLib.encode({ + callType: CALLTYPE_DELEGATECALL, + execType: EXECTYPE_DEFAULT, + mode: MODE_DEFAULT, + payload: ModePayload.wrap(bytes22(0)) + }); + results = IERC7579Account(account).executeFromExecutor( + modeCode, abi.encodePacked(delegateTarget, callData) + ); + } + + // Note: Not every account will support delegatecalls + function exec7579( + address delegateTarget, + bytes memory callData + ) + internal + returns (bytes[] memory results) + { + return exec7579(msg.sender, delegateTarget, callData); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IBotRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IBotRegistry.sol new file mode 100644 index 0000000..5bdda17 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IBotRegistry.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IBotRegistry { + function botList(address) public view virtual returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDFSRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDFSRegistry.sol new file mode 100644 index 0000000..b9b6fd8 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDFSRegistry.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IDFSRegistry { + function getAddr(bytes4 _id) public view virtual returns (address); + + function addNewContract( + bytes32 _id, + address _contractAddr, + uint256 _waitPeriod + ) + public + virtual; + + function startContractChange(bytes32 _id, address _newContractAddr) public virtual; + + function approveContractChange(bytes32 _id) public virtual; + + function cancelContractChange(bytes32 _id) public virtual; + + function changeWaitPeriod(bytes32 _id, uint256 _newWaitPeriod) public virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDSProxy.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDSProxy.sol new file mode 100644 index 0000000..470ed87 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDSProxy.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IDSProxy { + // function execute(bytes memory _code, bytes memory _data) + // public + // payable + // virtual + // returns (address, bytes32); + + function execute( + address _target, + bytes memory _data + ) + public + payable + virtual + returns (bytes32); + + function setCache(address _cacheAddr) public payable virtual returns (bool); + + function owner() public view virtual returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC20.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC20.sol new file mode 100644 index 0000000..6cddc56 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC20.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface IERC20 { + function name() external view returns (string memory); + function symbol() external view returns (string memory); + function decimals() external view returns (uint256 digits); + function totalSupply() external view returns (uint256 supply); + + function balanceOf(address _owner) external view returns (uint256 balance); + + function transfer(address _to, uint256 _value) external returns (bool success); + + function transferFrom( + address _from, + address _to, + uint256 _value + ) + external + returns (bool success); + + function approve(address _spender, uint256 _value) external returns (bool success); + + function allowance( + address _owner, + address _spender + ) + external + view + returns (uint256 remaining); + + event Approval(address indexed _owner, address indexed _spender, uint256 _value); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC4626.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC4626.sol new file mode 100644 index 0000000..48b3534 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC4626.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +import "./IERC20.sol"; + +interface IERC4626 is 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 previewDeposit(uint256 _assets) external view returns (uint256 shares); + function previewMint(uint256 _shares) external view returns (uint256 assets); + function previewWithdraw(uint256 _assets) external view returns (uint256 shares); + function previewRedeem(uint256 _shares) external view returns (uint256 assets); + + function asset() external view returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721.sol new file mode 100644 index 0000000..2abd072 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface IERC721 { + function balanceOf(address owner) external view returns (uint256 balance); + function ownerOf(uint256 tokenId) external view returns (address owner); + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) + external; + function safeTransferFrom(address from, address to, uint256 tokenId) external; + function transferFrom(address from, address to, uint256 tokenId) external; + function approve(address to, uint256 tokenId) external; + function setApprovalForAll(address operator, bool _approved) external; + function getApproved(uint256 tokenId) external view returns (address operator); + function isApprovedForAll(address owner, address operator) external view returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721Enumerable.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721Enumerable.sol new file mode 100644 index 0000000..0b1b2d9 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721Enumerable.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +import "./IERC721.sol"; + +interface IERC721Enumerable is IERC721 { + function totalSupply() external view returns (uint256); + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); + function tokenByIndex(uint256 index) external view returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IFLParamGetter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IFLParamGetter.sol new file mode 100644 index 0000000..43ed7a8 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IFLParamGetter.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IFLParamGetter { + function getFlashLoanParams(bytes memory _data) + public + view + virtual + returns (address[] memory tokens, uint256[] memory amount, uint256[] memory modes); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IGasToken.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IGasToken.sol new file mode 100644 index 0000000..3ca6f7c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IGasToken.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +import "./IERC20.sol"; + +abstract contract IGasToken is IERC20 { + function free(uint256 value) public virtual returns (bool success); + + function freeUpTo(uint256 value) public virtual returns (uint256 freed); + + function freeFrom(address from, uint256 value) public virtual returns (bool success); + + function freeFromUpTo(address from, uint256 value) public virtual returns (uint256 freed); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ILendingPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ILendingPool.sol new file mode 100644 index 0000000..0e8e6ec --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ILendingPool.sol @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract ILendingPool { + function flashLoan( + address payable _receiver, + address _reserve, + uint256 _amount, + bytes calldata _params + ) + external + virtual; + + function deposit( + address _reserve, + uint256 _amount, + uint16 _referralCode + ) + external + payable + virtual; + + function setUserUseReserveAsCollateral( + address _reserve, + bool _useAsCollateral + ) + external + virtual; + + function borrow( + address _reserve, + uint256 _amount, + uint256 _interestRateMode, + uint16 _referralCode + ) + external + virtual; + + function repay( + address _reserve, + uint256 _amount, + address payable _onBehalfOf + ) + external + payable + virtual; + + function swapBorrowRateMode(address _reserve) external virtual; + + function getReserves() external view virtual returns (address[] memory); + + /// @param _reserve underlying token address + function getReserveData(address _reserve) + external + view + virtual + returns ( + uint256 totalLiquidity, // reserve total liquidity + uint256 availableLiquidity, // reserve available liquidity for borrowing + uint256 totalBorrowsStable, // total amount of outstanding borrows at Stable rate + uint256 totalBorrowsVariable, // total amount of outstanding borrows at Variable rate + uint256 liquidityRate, // current deposit APY of the reserve for depositors, in Ray + // units. + uint256 variableBorrowRate, // current variable rate APY of the reserve pool, in Ray + // units. + uint256 stableBorrowRate, // current stable rate APY of the reserve pool, in Ray units. + uint256 averageStableBorrowRate, // current average stable borrow rate + uint256 utilizationRate, // expressed as total borrows/total liquidity. + uint256 liquidityIndex, // cumulative liquidity index + uint256 variableBorrowIndex, // cumulative variable borrow index + address aTokenAddress, // aTokens contract address for the specific _reserve + uint40 lastUpdateTimestamp + ); // timestamp of the last update of reserve data + + /// @param _user users address + function getUserAccountData(address _user) + external + view + virtual + returns ( + uint256 totalLiquidityETH, // user aggregated deposits across all the reserves. In Wei + uint256 totalCollateralETH, // user aggregated collateral across all the reserves. In + // Wei + uint256 totalBorrowsETH, // user aggregated outstanding borrows across all the reserves. + // In Wei + uint256 totalFeesETH, // user aggregated current outstanding fees in ETH. In Wei + uint256 availableBorrowsETH, // user available amount to borrow in ETH + uint256 currentLiquidationThreshold, // user current average liquidation threshold + // across all the collaterals deposited + uint256 ltv, // user average Loan-to-Value between all the collaterals + uint256 healthFactor + ); // user current Health Factor + + /// @param _reserve underlying token address + /// @param _user users address + function getUserReserveData( + address _reserve, + address _user + ) + external + view + virtual + returns ( + uint256 currentATokenBalance, // user current reserve aToken balance + uint256 currentBorrowBalance, // user current reserve outstanding borrow balance + uint256 principalBorrowBalance, // user balance of borrowed asset + uint256 borrowRateMode, // user borrow rate mode either Stable or Variable + uint256 borrowRate, // user current borrow rate APY + uint256 liquidityRate, // user current earn rate on _reserve + uint256 originationFee, // user outstanding loan origination fee + uint256 variableBorrowIndex, // user variable cumulative index + uint256 lastUpdateTimestamp, // Timestamp of the last data update + bool usageAsCollateralEnabled + ); // Whether the user's current reserve is enabled as a collateral + + function getReserveConfigurationData(address _reserve) + external + view + virtual + returns ( + uint256 ltv, + uint256 liquidationThreshold, + uint256 liquidationBonus, + address rateStrategyAddress, + bool usageAsCollateralEnabled, + bool borrowingEnabled, + bool stableBorrowRateEnabled, + bool isActive + ); + + // ------------------ LendingPoolCoreData ------------------------ + function getReserveATokenAddress(address _reserve) public view virtual returns (address); + + function getReserveConfiguration(address _reserve) + external + view + virtual + returns (uint256, uint256, uint256, bool); + + function getUserUnderlyingAssetBalance( + address _reserve, + address _user + ) + public + view + virtual + returns (uint256); + + function getReserveCurrentLiquidityRate(address _reserve) + public + view + virtual + returns (uint256); + + function getReserveCurrentVariableBorrowRate(address _reserve) + public + view + virtual + returns (uint256); + + function getReserveTotalLiquidity(address _reserve) public view virtual returns (uint256); + + function getReserveAvailableLiquidity(address _reserve) public view virtual returns (uint256); + + function getReserveTotalBorrowsVariable(address _reserve) + public + view + virtual + returns (uint256); + + // ---------------- LendingPoolDataProvider --------------------- + function calculateUserGlobalData(address _user) + public + view + virtual + returns ( + uint256 totalLiquidityBalanceETH, + uint256 totalCollateralBalanceETH, + uint256 totalBorrowBalanceETH, + uint256 totalFeesETH, + uint256 currentLtv, + uint256 currentLiquidationThreshold, + uint256 healthFactor, + bool healthFactorBelowThreshold + ); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IMCDPriceVerifier.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IMCDPriceVerifier.sol new file mode 100644 index 0000000..7341c60 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IMCDPriceVerifier.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IMCDPriceVerifier { + function verifyVaultNextPrice( + uint256 _nextPrice, + uint256 _cdpId + ) + public + view + virtual + returns (bool); + function verifyNextPrice(uint256 _nextPrice, bytes32 _ilk) public view virtual returns (bool); + function setAuthorized(address _address, bool _allowed) public virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyERC20.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyERC20.sol new file mode 100644 index 0000000..35edd40 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyERC20.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface IProxyERC20 { + function target() external returns (address); + function tokenState() external returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyRegistry.sol new file mode 100644 index 0000000..09acf2a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyRegistry.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IProxyRegistry { + function proxies(address _owner) public view virtual returns (address); + function build(address) public virtual returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISmartSession.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISmartSession.sol new file mode 100644 index 0000000..36fefb3 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISmartSession.sol @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +// Interfaces +import { IModule } from "../../accounts/common/interfaces/IERC7579Module.sol"; + +// Types +import { PackedUserOperation } from "../../external/ERC4337.sol"; + +/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ +/* Custom Types & Constants */ +/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + +type PermissionId is bytes32; + +type ActionId is bytes32; + +type ValidationData is uint256; + +using { permissionIdEq as == } for PermissionId global; +using { permissionIdNeq as != } for PermissionId global; + +function permissionIdEq(PermissionId uid1, PermissionId uid2) pure returns (bool) { + return PermissionId.unwrap(uid1) == PermissionId.unwrap(uid2); +} + +function permissionIdNeq(PermissionId uid1, PermissionId uid2) pure returns (bool) { + return PermissionId.unwrap(uid1) != PermissionId.unwrap(uid2); +} + +/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ +/* Parameters */ +/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + +enum SmartSessionMode { + USE, + ENABLE, + UNSAFE_ENABLE +} + +enum PolicyType { + NA, + USER_OP, + ACTION, + ERC1271 +} + +struct EnableSession { + uint8 chainDigestIndex; + ChainDigest[] hashesAndChainIds; + Session sessionToEnable; + // in order to enable a session, the smart account has to sign a digest. The signature for this + // is stored here. + bytes permissionEnableSig; +} + +struct ChainDigest { + uint64 chainId; + bytes32 sessionDigest; +} + +// Action data is a struct that contains the actionId and the policies that are associated with this +// action. +struct ActionData { + bytes4 actionTargetSelector; + address actionTarget; + PolicyData[] actionPolicies; +} + +// Policy data is a struct that contains the policy address and the initialization data for the +// policy. +struct PolicyData { + address policy; + bytes initData; +} + +struct ERC7739Data { + string[] allowedERC7739Content; + PolicyData[] erc1271Policies; +} + +/** + * + * Represents a Session structure with various attributes for managing user operations and policies. + * + * Attributes: + * sessionValidator (ISessionValidator): The validator contract for signing user operations. + * Every userOp must be signed by the session key "owner". The signature is validated + * via a stateless external contract (ISessionValidator) that can implement different + * means of validation. + * + * sessionValidatorInitData (bytes): Initialization data for the ISessionValidator contract. + * The ISessionValidator contract can be configured with different parameters that are + * passed in this field. + * + * salt (bytes32): A unique identifier to prevent collision between sessions. + * A session key owner can have multiple sessions with the same parameters. To facilitate + * this, a salt is necessary to avoid collision. + * + * userOpPolicies (PolicyData[]): An array of policy data for user operations. + * When every session can have multiple policies set. + * + * erc7739Policies (ERC7739Data): ERC1271 Policies specific to the ERC7739 standard. + * + * actions (ActionData[]): An array of action data for specifying function-specific policies. + * A common use case of session keys is to scope access to a specific target and function + * selector. SmartSession calls this "Action". With ActionData, we can specify policies + * that are only run if a 7579 execution contains a specific action. + */ +struct Session { + ISessionValidator sessionValidator; + bytes sessionValidatorInitData; + bytes32 salt; + PolicyData[] userOpPolicies; + ERC7739Data erc7739Policies; + ActionData[] actions; +} + +/** + * @title ISmartSession + * @author Filipp Makarov (Biconomy) & zeroknots.eth (Rhinestone) + * @dev A collaborative effort between Rhinestone and Biconomy to create a powerful + * and flexible session key management system for ERC-4337 and ERC-7579 accounts. + * SmartSession is an advanced module for ERC-4337 and ERC-7579 compatible smart contract wallets, + * enabling granular + * control over session keys. It allows users to create and manage temporary, limited-permission + * access to their + * accounts through configurable policies. The module supports various policy types, including user + * operation + * validation, action-specific policies, and ERC-1271 signature validation. SmartSession implements + * a unique "enable + * flow" that allows session keys to be created within the first user operation, enhancing security + * and user experience. + * It uses a nested EIP-712 approach for signature validation, providing phishing resistance and + * compatibility with + * existing wallet interfaces. The module also supports batched executions and integrates with + * external policy contracts + * for flexible permission management. Overall, SmartSession offers a comprehensive solution for + * secure, temporary + * account access in the evolving landscape of account abstraction. + */ +interface ISmartSession { + error AssociatedArray_OutOfBounds(uint256 index); + error ChainIdMismatch(uint64 providedChainId); + error HashIndexOutOfBounds(uint256 index); + error HashMismatch(bytes32 providedHash, bytes32 computedHash); + error InvalidData(); + error InvalidActionId(); + error NoExecutionsInBatch(); + error InvalidTarget(); + error InvalidEnableSignature(address account, bytes32 hash); + error InvalidISessionValidator(ISessionValidator sessionValidator); + error InvalidSelfCall(); + error InvalidSession(PermissionId permissionId); + error InvalidSessionKeySignature( + PermissionId permissionId, address sessionValidator, address account, bytes32 userOpHash + ); + error SmartSessionModuleAlreadyInstalled(address account); + error InvalidPermissionId(PermissionId permissionId); + error InvalidCallTarget(); + error InvalidUserOpSender(address sender); + error NoPoliciesSet(PermissionId permissionId); + error PartlyEnabledActions(); + error PartlyEnabledPolicies(); + error PolicyViolation(PermissionId permissionId, address policy); + error SignerNotFound(PermissionId permissionId, address account); + error UnsupportedExecutionType(); + error UnsupportedPolicy(address policy); + error UnsupportedSmartSessionMode(SmartSessionMode mode); + error ForbiddenValidationData(); + + event NonceIterated(PermissionId permissionId, address account, uint256 newValue); + event SessionValidatorEnabled( + PermissionId permissionId, address sessionValidator, address smartAccount + ); + event SessionValidatorDisabled( + PermissionId permissionId, address sessionValidator, address smartAccount + ); + event PolicyDisabled( + PermissionId permissionId, PolicyType policyType, address policy, address smartAccount + ); + event ActionIdDisabled(PermissionId permissionId, ActionId actionId, address smartAccount); + event PolicyEnabled( + PermissionId permissionId, PolicyType policyType, address policy, address smartAccount + ); + event SessionCreated(PermissionId permissionId, address account); + event SessionRemoved(PermissionId permissionId, address smartAccount); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ERC7579 */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /** + * ERC4337/ERC7579 validation function + * the primary purpose of this function, is to validate if a userOp forwarded by a 7579 account + * is valid. + * This function will dissect the userop.signature field, and parse out the provided + * PermissionId, which identifies + * a + * unique ID of a dapp for a specific user. n Policies and one Signer contract are mapped to + * this Id and will be + * checked. Only UserOps that pass policies and signer checks, are considered valid. + * Enable Flow: + * SmartSessions allows session keys to be created within the "first" UserOp. If the enable + * flow is chosen, the + * EnableSession data, which is packed in userOp.signature is parsed, and stored in the + * SmartSession storage. + * + */ + function validateUserOp( + PackedUserOperation memory userOp, + bytes32 userOpHash + ) + external + returns (ValidationData vd); + /** + * ERC7579 compliant onInstall function. + * expected to abi.encode(Session[]) for the enable data + * + * Note: It's possible to install the smartsession module with data = "" + */ + function onInstall(bytes memory data) external; + + /** + * ERC7579 compliant uninstall function. + * will wipe all configIds and associated Policies / Signers + */ + function onUninstall(bytes memory) external; + + /** + * ERC7579 compliant ERC1271 function + * this function allows session keys to sign ERC1271 requests. + */ + function isValidSignatureWithSender( + address sender, + bytes32 hash, + bytes memory signature + ) + external + view + returns (bytes4 result); + + function isInitialized(address smartAccount) external view returns (bool); + function isModuleType(uint256 typeID) external pure returns (bool); + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Manage Sessions */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + function enableActionPolicies( + PermissionId permissionId, + ActionData[] memory actionPolicies + ) + external; + function enableERC1271Policies( + PermissionId permissionId, + ERC7739Data calldata erc1271Policies + ) + external; + function enableSessions(Session[] memory sessions) + external + returns (PermissionId[] memory permissionIds); + function enableUserOpPolicies( + PermissionId permissionId, + PolicyData[] memory userOpPolicies + ) + external; + function disableActionPolicies( + PermissionId permissionId, + ActionId actionId, + address[] memory policies + ) + external; + function disableActionId(PermissionId permissionId, ActionId actionId) external; + function disableERC1271Policies( + PermissionId permissionId, + address[] memory policies, + string[] calldata contents + ) + external; + function disableUserOpPolicies(PermissionId permissionId, address[] memory policies) external; + function removeSession(PermissionId permissionId) external; + function revokeEnableSignature(PermissionId permissionId) external; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* View Functions */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function getSessionDigest( + PermissionId permissionId, + address account, + Session memory data, + SmartSessionMode mode + ) + external + view + returns (bytes32); + + function getNonce(PermissionId permissionId, address account) external view returns (uint256); + function getPermissionId(Session memory session) + external + pure + returns (PermissionId permissionId); + function isPermissionEnabled( + PermissionId permissionId, + address account + ) + external + view + returns (bool); + function isISessionValidatorSet( + PermissionId permissionId, + address account + ) + external + view + returns (bool); + function areUserOpPoliciesEnabled( + address account, + PermissionId permissionId, + PolicyData[] calldata userOpPolicies + ) + external + view + returns (bool); + function areERC1271PoliciesEnabled( + address account, + PermissionId permissionId, + PolicyData[] calldata erc1271Policies + ) + external + view + returns (bool); + function areActionsEnabled( + address account, + PermissionId permissionId, + ActionData[] calldata actions + ) + external + view + returns (bool); +} + +/** + * ISessionValidator is a contract that validates signatures for a given session. + * this interface expects to validate the signature in a stateless way. + * all parameters required to validate the signature are passed in the function call. + * Only one ISessionValidator is responsible to validate a userOp. + * if you want to use multiple validators, you can create a ISessionValidator that aggregates + * multiple signatures that + * are packed into userOp.signature + * It is used to validate the signature of a session. + * hash The userOp hash + * sig The signature of userOp + * data the config data that is used to validate the signature + */ +interface ISessionValidator is IModule { + function validateSignatureWithData( + bytes32 hash, + bytes calldata sig, + bytes calldata data + ) + external + view + returns (bool validSig); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISubscriptions.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISubscriptions.sol new file mode 100644 index 0000000..d6ee534 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISubscriptions.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface ISubscriptions { + function unsubscribe() external; + function unsubscribe(uint256 _cdpId) external; + function subscribersPos(uint256) external view returns (uint256 arrPos, bool subscribed); + function subscribersPos(address) external view returns (uint256 arrPos, bool subscribed); + function isSubscribed(address _user) external view returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ITrigger.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ITrigger.sol new file mode 100644 index 0000000..491425d --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ITrigger.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract ITrigger { + function isTriggered(bytes memory, bytes memory) public virtual returns (bool); + function isChangeable() public virtual returns (bool); + function changedSubData(bytes memory) public virtual returns (bytes memory); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IWETH.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IWETH.sol new file mode 100644 index 0000000..a7128f1 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IWETH.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +import "forge-std/interfaces/IERC20.sol"; + +abstract contract IWETH { + function allowance(address, address) public view virtual returns (uint256); + + function balanceOf(address) public view virtual returns (uint256); + + function approve(address, uint256) public virtual; + + function transfer(address, uint256) public virtual returns (bool); + + function transferFrom(address, address, uint256) public virtual returns (bool); + + function deposit() public payable virtual; + + function withdraw(uint256) public virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/ICBETH.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/ICBETH.sol new file mode 100644 index 0000000..5247f31 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/ICBETH.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface ICBETH { + function exchangeRate() external view returns (uint256 wethAmountPerCBETH); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IRETH.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IRETH.sol new file mode 100644 index 0000000..90dbbec --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IRETH.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface IRETH { + function getEthValue(uint256 rethAmount) external view returns (uint256 wethAmount); + function getRethValue(uint256 wethAmount) external view returns (uint256 rethAmount); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IWstETH.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IWstETH.sol new file mode 100644 index 0000000..9f8398d --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IWstETH.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface IWstETH { + function getStETHByWstETH(uint256 wstethAmount) external view returns (uint256 wethAmount); + function getWstETHByStETH(uint256 wethAmount) external view returns (uint256 wstethAmount); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IAToken.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IAToken.sol new file mode 100644 index 0000000..7b4f5f6 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IAToken.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IAToken { + function redeem(uint256 _amount) external virtual; + function balanceOf(address _owner) external view virtual returns (uint256 balance); + function UNDERLYING_ASSET_ADDRESS() external view virtual returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendToAaveMigrator.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendToAaveMigrator.sol new file mode 100644 index 0000000..e5c69f6 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendToAaveMigrator.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract ILendToAaveMigrator { + function migrateFromLEND(uint256 amount) external virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPool.sol new file mode 100644 index 0000000..30eb802 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPool.sol @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +abstract contract ILendingPool { + function flashLoan( + address payable _receiver, + address _reserve, + uint256 _amount, + bytes calldata _params + ) + external + virtual; + function deposit( + address _reserve, + uint256 _amount, + uint16 _referralCode + ) + external + payable + virtual; + function setUserUseReserveAsCollateral( + address _reserve, + bool _useAsCollateral + ) + external + virtual; + function borrow( + address _reserve, + uint256 _amount, + uint256 _interestRateMode, + uint16 _referralCode + ) + external + virtual; + function repay( + address _reserve, + uint256 _amount, + address payable _onBehalfOf + ) + external + payable + virtual; + function swapBorrowRateMode(address _reserve) external virtual; + function getReserves() external view virtual returns (address[] memory); + + /// @param _reserve underlying token address + function getReserveData(address _reserve) + external + view + virtual + returns ( + uint256 totalLiquidity, // reserve total liquidity + uint256 availableLiquidity, // reserve available liquidity for borrowing + uint256 totalBorrowsStable, // total amount of outstanding borrows at Stable rate + uint256 totalBorrowsVariable, // total amount of outstanding borrows at Variable rate + uint256 liquidityRate, // current deposit APY of the reserve for depositors, in Ray + // units. + uint256 variableBorrowRate, // current variable rate APY of the reserve pool, in Ray + // units. + uint256 stableBorrowRate, // current stable rate APY of the reserve pool, in Ray units. + uint256 averageStableBorrowRate, // current average stable borrow rate + uint256 utilizationRate, // expressed as total borrows/total liquidity. + uint256 liquidityIndex, // cumulative liquidity index + uint256 variableBorrowIndex, // cumulative variable borrow index + address aTokenAddress, // aTokens contract address for the specific _reserve + uint40 lastUpdateTimestamp + ); // timestamp of the last update of reserve data + + /// @param _user users address + function getUserAccountData(address _user) + external + view + virtual + returns ( + uint256 totalLiquidityETH, // user aggregated deposits across all the reserves. In Wei + uint256 totalCollateralETH, // user aggregated collateral across all the reserves. In + // Wei + uint256 totalBorrowsETH, // user aggregated outstanding borrows across all the reserves. + // In Wei + uint256 totalFeesETH, // user aggregated current outstanding fees in ETH. In Wei + uint256 availableBorrowsETH, // user available amount to borrow in ETH + uint256 currentLiquidationThreshold, // user current average liquidation threshold + // across all the collaterals deposited + uint256 ltv, // user average Loan-to-Value between all the collaterals + uint256 healthFactor + ); // user current Health Factor + + /// @param _reserve underlying token address + /// @param _user users address + function getUserReserveData( + address _reserve, + address _user + ) + external + view + virtual + returns ( + uint256 currentATokenBalance, // user current reserve aToken balance + uint256 currentBorrowBalance, // user current reserve outstanding borrow balance + uint256 principalBorrowBalance, // user balance of borrowed asset + uint256 borrowRateMode, // user borrow rate mode either Stable or Variable + uint256 borrowRate, // user current borrow rate APY + uint256 liquidityRate, // user current earn rate on _reserve + uint256 originationFee, // user outstanding loan origination fee + uint256 variableBorrowIndex, // user variable cumulative index + uint256 lastUpdateTimestamp, // Timestamp of the last data update + bool usageAsCollateralEnabled + ); // Whether the user's current reserve is enabled as a collateral + + function getReserveConfigurationData(address _reserve) + external + view + virtual + returns ( + uint256 ltv, + uint256 liquidationThreshold, + uint256 liquidationBonus, + address rateStrategyAddress, + bool usageAsCollateralEnabled, + bool borrowingEnabled, + bool stableBorrowRateEnabled, + bool isActive + ); + + // ------------------ LendingPoolCoreData ------------------------ + function getReserveATokenAddress(address _reserve) public view virtual returns (address); + function getReserveConfiguration(address _reserve) + external + view + virtual + returns (uint256, uint256, uint256, bool); + function getUserUnderlyingAssetBalance( + address _reserve, + address _user + ) + public + view + virtual + returns (uint256); + + function getReserveCurrentLiquidityRate(address _reserve) + public + view + virtual + returns (uint256); + function getReserveCurrentVariableBorrowRate(address _reserve) + public + view + virtual + returns (uint256); + function getReserveCurrentStableBorrowRate(address _reserve) + public + view + virtual + returns (uint256); + function getReserveTotalLiquidity(address _reserve) public view virtual returns (uint256); + function getReserveAvailableLiquidity(address _reserve) public view virtual returns (uint256); + function getReserveTotalBorrowsVariable(address _reserve) + public + view + virtual + returns (uint256); + + // ---------------- LendingPoolDataProvider --------------------- + function calculateUserGlobalData(address _user) + public + view + virtual + returns ( + uint256 totalLiquidityBalanceETH, + uint256 totalCollateralBalanceETH, + uint256 totalBorrowBalanceETH, + uint256 totalFeesETH, + uint256 currentLtv, + uint256 currentLiquidationThreshold, + uint256 healthFactor, + bool healthFactorBelowThreshold + ); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPoolAddressesProvider.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPoolAddressesProvider.sol new file mode 100644 index 0000000..5159835 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPoolAddressesProvider.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract ILendingPoolAddressesProvider { + function getLendingPool() public view virtual returns (address); + + function setLendingPoolImpl(address _pool) public virtual; + + function getLendingPoolCore() public view virtual returns (address payable); + + function setLendingPoolCoreImpl(address _lendingPoolCore) public virtual; + + function getLendingPoolConfigurator() public view virtual returns (address); + + function setLendingPoolConfiguratorImpl(address _configurator) public virtual; + + function getLendingPoolDataProvider() public view virtual returns (address); + + function setLendingPoolDataProviderImpl(address _provider) public virtual; + + function getLendingPoolParametersProvider() public view virtual returns (address); + + function setLendingPoolParametersProviderImpl(address _parametersProvider) public virtual; + + function getTokenDistributor() public view virtual returns (address); + + function setTokenDistributor(address _tokenDistributor) public virtual; + + function getFeeProvider() public view virtual returns (address); + + function setFeeProviderImpl(address _feeProvider) public virtual; + + function getLendingPoolLiquidationManager() public view virtual returns (address); + + function setLendingPoolLiquidationManager(address _manager) public virtual; + + function getLendingPoolManager() public view virtual returns (address); + + function setLendingPoolManager(address _lendingPoolManager) public virtual; + + function getPriceOracle() public view virtual returns (address); + + function setPriceOracle(address _priceOracle) public virtual; + + function getLendingRateOracle() public view virtual returns (address); + + function setLendingRateOracle(address _lendingRateOracle) public virtual; +} + +library EthAddressLib { + function ethAddress() internal pure returns (address) { + return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IStkAave.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IStkAave.sol new file mode 100644 index 0000000..abd0157 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IStkAave.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IStkAave { + function cooldown() external virtual; + function redeem(address to, uint256 amount) external virtual; + function REWARD_TOKEN() external view virtual returns (address); + function stake(address onBehalfOf, uint256 amount) external virtual; + function claimRewards(address to, uint256 amount) external virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveIncentivesController.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveIncentivesController.sol new file mode 100644 index 0000000..6007d8f --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveIncentivesController.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.8.10; +pragma experimental ABIEncoderV2; + +interface IAaveIncentivesController { + event RewardsAccrued(address indexed user, uint256 amount); + + event RewardsClaimed( + address indexed user, address indexed to, address indexed claimer, uint256 amount + ); + + event ClaimerSet(address indexed user, address indexed claimer); + + /** + * @dev Whitelists an address to claim the rewards on behalf of another address + * @param user The address of the user + * @param claimer The address of the claimer + */ + function setClaimer(address user, address claimer) external; + + /** + * @dev Returns the whitelisted claimer for a certain address (0x0 if not set) + * @param user The address of the user + * @return The claimer address + */ + function getClaimer(address user) external view returns (address); + + /** + * @dev Configure assets for a certain rewards emission + * @param assets The assets to incentivize + * @param emissionsPerSecond The emission for each asset + */ + function configureAssets( + address[] calldata assets, + uint256[] calldata emissionsPerSecond + ) + external; + + /** + * @dev Called by the corresponding asset on any update that affects the rewards distribution + * @param asset The address of the user + * @param userBalance The balance of the user of the asset in the lending pool + * @param totalSupply The total supply of the asset in the lending pool + * + */ + function handleAction(address asset, uint256 userBalance, uint256 totalSupply) external; + + /** + * @dev Returns the total of rewards of an user, already accrued + not yet accrued + * @param user The address of the user + * @return The rewards + * + */ + function getRewardsBalance( + address[] calldata assets, + address user + ) + external + view + returns (uint256); + + /** + * @dev Claims reward for an user, on all the assets of the lending pool, accumulating the + * pending rewards + * @param amount Amount of rewards to claim + * @param to Address that will be receiving the rewards + * @return Rewards claimed + * + */ + function claimRewards( + address[] calldata assets, + uint256 amount, + address to + ) + external + returns (uint256); + + /** + * @dev Claims reward for an user on behalf, on all the assets of the lending pool, accumulating + * the pending rewards. The caller must + * be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager + * @param amount Amount of rewards to claim + * @param user Address to check and claim rewards + * @param to Address that will be receiving the rewards + * @return Rewards claimed + * + */ + function claimRewardsOnBehalf( + address[] calldata assets, + uint256 amount, + address user, + address to + ) + external + returns (uint256); + + /** + * @dev returns the unclaimed rewards of the user + * @param user the address of the user + * @return the unclaimed user rewards + */ + function getUserUnclaimedRewards(address user) external view returns (uint256); + + /** + * @dev for backward compatibility with previous implementation of the Incentives controller + */ + function REWARD_TOKEN() external view returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveProtocolDataProviderV2.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveProtocolDataProviderV2.sol new file mode 100644 index 0000000..4adde7c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveProtocolDataProviderV2.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IAaveProtocolDataProviderV2 { + struct TokenData { + string symbol; + address tokenAddress; + } + + function getAllReservesTokens() external view virtual returns (TokenData[] memory); + + function getAllATokens() external view virtual returns (TokenData[] memory); + + function getReserveConfigurationData(address asset) + external + view + virtual + returns ( + uint256 decimals, + uint256 ltv, + uint256 liquidationThreshold, + uint256 liquidationBonus, + uint256 reserveFactor, + bool usageAsCollateralEnabled, + bool borrowingEnabled, + bool stableBorrowRateEnabled, + bool isActive, + bool isFrozen + ); + + function getReserveData(address asset) + external + view + virtual + returns ( + uint256 availableLiquidity, + uint256 totalStableDebt, + uint256 totalVariableDebt, + uint256 liquidityRate, + uint256 variableBorrowRate, + uint256 stableBorrowRate, + uint256 averageStableBorrowRate, + uint256 liquidityIndex, + uint256 variableBorrowIndex, + uint40 lastUpdateTimestamp + ); + + function getUserReserveData( + address asset, + address user + ) + external + view + virtual + returns ( + uint256 currentATokenBalance, + uint256 currentStableDebt, + uint256 currentVariableDebt, + uint256 principalStableDebt, + uint256 scaledVariableDebt, + uint256 stableBorrowRate, + uint256 liquidityRate, + uint40 stableRateLastUpdated, + bool usageAsCollateralEnabled + ); + + function getReserveTokensAddresses(address asset) + external + view + virtual + returns ( + address aTokenAddress, + address stableDebtTokenAddress, + address variableDebtTokenAddress + ); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolAddressesProviderV2.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolAddressesProviderV2.sol new file mode 100644 index 0000000..4819a5a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolAddressesProviderV2.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.8.10; + +interface ILendingPoolAddressesProviderV2 { + event LendingPoolUpdated(address indexed newAddress); + event ConfigurationAdminUpdated(address indexed newAddress); + event EmergencyAdminUpdated(address indexed newAddress); + event LendingPoolConfiguratorUpdated(address indexed newAddress); + event LendingPoolCollateralManagerUpdated(address indexed newAddress); + event PriceOracleUpdated(address indexed newAddress); + event LendingRateOracleUpdated(address indexed newAddress); + event ProxyCreated(bytes32 id, address indexed newAddress); + event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy); + + function setAddress(bytes32 id, address newAddress) external; + + function setAddressAsProxy(bytes32 id, address impl) external; + + function getAddress(bytes32 id) external view returns (address); + + function getLendingPool() external view returns (address); + + function setLendingPoolImpl(address pool) external; + + function getLendingPoolConfigurator() external view returns (address); + + function setLendingPoolConfiguratorImpl(address configurator) external; + + function getLendingPoolCollateralManager() external view returns (address); + + function setLendingPoolCollateralManager(address manager) external; + + function getPoolAdmin() external view returns (address); + + function setPoolAdmin(address admin) external; + + function getEmergencyAdmin() external view returns (address); + + function setEmergencyAdmin(address admin) external; + + function getPriceOracle() external view returns (address); + + function setPriceOracle(address priceOracle) external; + + function getLendingRateOracle() external view returns (address); + + function setLendingRateOracle(address lendingRateOracle) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolV2.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolV2.sol new file mode 100644 index 0000000..733e18c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolV2.sol @@ -0,0 +1,517 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.8.10; + +import "./ILendingPoolAddressesProviderV2.sol"; + +library DataTypes { + // refer to the whitepaper, section 1.1 basic concepts for a formal description of these + // properties. + struct ReserveData { + //stores the reserve configuration + ReserveConfigurationMap configuration; + //the liquidity index. Expressed in ray + uint128 liquidityIndex; + //variable borrow index. Expressed in ray + uint128 variableBorrowIndex; + //the current supply rate. Expressed in ray + uint128 currentLiquidityRate; + //the current variable borrow rate. Expressed in ray + uint128 currentVariableBorrowRate; + //the current stable borrow rate. Expressed in ray + uint128 currentStableBorrowRate; + uint40 lastUpdateTimestamp; + //tokens addresses + address aTokenAddress; + address stableDebtTokenAddress; + address variableDebtTokenAddress; + //address of the interest rate strategy + address interestRateStrategyAddress; + //the id of the reserve. Represents the position in the list of the active reserves + uint8 id; + } + + struct ReserveConfigurationMap { + //bit 0-15: LTV + //bit 16-31: Liq. threshold + //bit 32-47: Liq. bonus + //bit 48-55: Decimals + //bit 56: Reserve is active + //bit 57: reserve is frozen + //bit 58: borrowing is enabled + //bit 59: stable rate borrowing enabled + //bit 60-63: reserved + //bit 64-79: reserve factor + uint256 data; + } + + struct UserConfigurationMap { + uint256 data; + } + + enum InterestRateMode { + NONE, + STABLE, + VARIABLE + } +} + +interface ILendingPoolV2 { + /** + * @dev Emitted on deposit() + * @param reserve The address of the underlying asset of the reserve + * @param user The address initiating the deposit + * @param onBehalfOf The beneficiary of the deposit, receiving the aTokens + * @param amount The amount deposited + * @param referral The referral code used + * + */ + event Deposit( + address indexed reserve, + address user, + address indexed onBehalfOf, + uint256 amount, + uint16 indexed referral + ); + + /** + * @dev Emitted on withdraw() + * @param reserve The address of the underlyng asset being withdrawn + * @param user The address initiating the withdrawal, owner of aTokens + * @param to Address that will receive the underlying + * @param amount The amount to be withdrawn + * + */ + event Withdraw( + address indexed reserve, address indexed user, address indexed to, uint256 amount + ); + + /** + * @dev Emitted on borrow() and flashLoan() when debt needs to be opened + * @param reserve The address of the underlying asset being borrowed + * @param user The address of the user initiating the borrow(), receiving the funds on borrow() + * or just + * initiator of the transaction on flashLoan() + * @param onBehalfOf The address that will be getting the debt + * @param amount The amount borrowed out + * @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable + * @param borrowRate The numeric rate at which the user has borrowed + * @param referral The referral code used + * + */ + event Borrow( + address indexed reserve, + address user, + address indexed onBehalfOf, + uint256 amount, + uint256 borrowRateMode, + uint256 borrowRate, + uint16 indexed referral + ); + + /** + * @dev Emitted on repay() + * @param reserve The address of the underlying asset of the reserve + * @param user The beneficiary of the repayment, getting his debt reduced + * @param repayer The address of the user initiating the repay(), providing the funds + * @param amount The amount repaid + * + */ + event Repay( + address indexed reserve, address indexed user, address indexed repayer, uint256 amount + ); + + /** + * @dev Emitted on swapBorrowRateMode() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user swapping his rate mode + * @param rateMode The rate mode that the user wants to swap to + * + */ + event Swap(address indexed reserve, address indexed user, uint256 rateMode); + + /** + * @dev Emitted on setUserUseReserveAsCollateral() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user enabling the usage as collateral + * + */ + event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); + + /** + * @dev Emitted on setUserUseReserveAsCollateral() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user enabling the usage as collateral + * + */ + event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); + + /** + * @dev Emitted on rebalanceStableBorrowRate() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user for which the rebalance has been executed + * + */ + event RebalanceStableBorrowRate(address indexed reserve, address indexed user); + + /** + * @dev Emitted on flashLoan() + * @param target The address of the flash loan receiver contract + * @param initiator The address initiating the flash loan + * @param asset The address of the asset being flash borrowed + * @param amount The amount flash borrowed + * @param premium The fee flash borrowed + * @param referralCode The referral code used + * + */ + event FlashLoan( + address indexed target, + address indexed initiator, + address indexed asset, + uint256 amount, + uint256 premium, + uint16 referralCode + ); + + /** + * @dev Emitted when the pause is triggered. + */ + event Paused(); + + /** + * @dev Emitted when the pause is lifted. + */ + event Unpaused(); + + /** + * @dev Emitted when a borrower is liquidated. This event is emitted by the LendingPool via + * LendingPoolCollateral manager using a DELEGATECALL + * This allows to have the events in the generated ABI for LendingPool. + * @param collateralAsset The address of the underlying asset used as collateral, to receive as + * result of the liquidation + * @param debtAsset The address of the underlying borrowed asset to be repaid with the + * liquidation + * @param user The address of the borrower getting liquidated + * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover + * @param liquidatedCollateralAmount The amount of collateral received by the liiquidator + * @param liquidator The address of the liquidator + * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, + * `false` if he wants + * to receive the underlying collateral asset directly + * + */ + event LiquidationCall( + address indexed collateralAsset, + address indexed debtAsset, + address indexed user, + uint256 debtToCover, + uint256 liquidatedCollateralAmount, + address liquidator, + bool receiveAToken + ); + + /** + * @dev Emitted when the state of a reserve is updated. NOTE: This event is actually declared + * in the ReserveLogic library and emitted in the updateInterestRates() function. Since the + * function is internal, + * the event will actually be fired by the LendingPool contract. The event is therefore + * replicated here so it + * gets added to the LendingPool ABI + * @param reserve The address of the underlying asset of the reserve + * @param liquidityRate The new liquidity rate + * @param stableBorrowRate The new stable borrow rate + * @param variableBorrowRate The new variable borrow rate + * @param liquidityIndex The new liquidity index + * @param variableBorrowIndex The new variable borrow index + * + */ + event ReserveDataUpdated( + address indexed reserve, + uint256 liquidityRate, + uint256 stableBorrowRate, + uint256 variableBorrowRate, + uint256 liquidityIndex, + uint256 variableBorrowIndex + ); + + /** + * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying + * aTokens. + * - E.g. User deposits 100 USDC and gets in return 100 aUSDC + * @param asset The address of the underlying asset to deposit + * @param amount The amount to be deposited + * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user + * wants to receive them on his own wallet, or a different address if the beneficiary of + * aTokens + * is a different wallet + * @param referralCode Code used to register the integrator originating the operation, for + * potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * + */ + function deposit( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode + ) + external; + + /** + * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent + * aTokens owned + * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC + * @param asset The address of the underlying asset to withdraw + * @param amount The underlying amount to be withdrawn + * - Send the value type(uint256).max in order to withdraw the whole aToken balance + * @param to Address that will receive the underlying, same as msg.sender if the user + * wants to receive it on his own wallet, or a different address if the beneficiary is a + * different wallet + * + */ + function withdraw(address asset, uint256 amount, address to) external; + + /** + * @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided + * that the borrower + * already deposited enough collateral, or he was given enough allowance by a credit delegator + * on the + * corresponding debt token (StableDebtToken or VariableDebtToken) + * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC + * in his wallet + * and 100 stable/variable debt tokens, depending on the `interestRateMode` + * @param asset The address of the underlying asset to borrow + * @param amount The amount to be borrowed + * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for + * Stable, 2 for Variable + * @param referralCode Code used to register the integrator originating the operation, for + * potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * @param onBehalfOf Address of the user who will receive the debt. Should be the address of the + * borrower itself + * calling the function if he wants to borrow against his own collateral, or the address of the + * credit delegator + * if he has been given credit delegation allowance + * + */ + function borrow( + address asset, + uint256 amount, + uint256 interestRateMode, + uint16 referralCode, + address onBehalfOf + ) + external; + + /** + * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens + * owned + * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` + * address + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the + * specific `debtMode` + * @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, + * 2 for Variable + * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the + * address of the + * user calling the function if he wants to reduce/remove his own debt, or the address of any + * other + * other borrower whose debt should be removed + * + */ + function repay(address asset, uint256 amount, uint256 rateMode, address onBehalfOf) external; + + /** + * @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa + * @param asset The address of the underlying asset borrowed + * @param rateMode The rate mode that the user wants to swap to + * + */ + function swapBorrowRateMode(address asset, uint256 rateMode) external; + + /** + * @dev Rebalances the stable interest rate of a user to the current stable rate defined on the + * reserve. + * - Users can be rebalanced if the following conditions are satisfied: + * 1. Usage ratio is above 95% + * 2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which + * means that too much has been + * borrowed at a stable rate and depositors are not earning enough + * @param asset The address of the underlying asset borrowed + * @param user The address of the user to be rebalanced + * + */ + function rebalanceStableBorrowRate(address asset, address user) external; + + /** + * @dev Allows depositors to enable/disable a specific deposited asset as collateral + * @param asset The address of the underlying asset deposited + * @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` + * otherwise + * + */ + function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external; + + /** + * @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1 + * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, + * and receives + * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk + * @param collateralAsset The address of the underlying asset used as collateral, to receive as + * result of the liquidation + * @param debtAsset The address of the underlying borrowed asset to be repaid with the + * liquidation + * @param user The address of the borrower getting liquidated + * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover + * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, + * `false` if he wants + * to receive the underlying collateral asset directly + * + */ + function liquidationCall( + address collateralAsset, + address debtAsset, + address user, + uint256 debtToCover, + bool receiveAToken + ) + external; + + /** + * @dev Allows smartcontracts to access the liquidity of the pool within one transaction, + * as long as the amount taken plus a fee is returned. + * IMPORTANT There are security concerns for developers of flashloan receiver contracts that + * must be kept into consideration. + * For further details please visit https://developers.aave.com + * @param receiverAddress The address of the contract receiving the funds, implementing the + * IFlashLoanReceiver interface + * @param assets The addresses of the assets being flash-borrowed + * @param amounts The amounts amounts being flash-borrowed + * @param modes Types of the debt to open if the flash loan is not returned: + * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver + * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the + * `onBehalfOf` address + * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the + * `onBehalfOf` address + * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 + * or 2 + * @param params Variadic packed params to pass to the receiver as extra information + * @param referralCode Code used to register the integrator originating the operation, for + * potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * + */ + function flashLoan( + address receiverAddress, + address[] calldata assets, + uint256[] calldata amounts, + uint256[] calldata modes, + address onBehalfOf, + bytes calldata params, + uint16 referralCode + ) + external; + + /** + * @dev Returns the user account data across all the reserves + * @param user The address of the user + * @return totalCollateralETH the total collateral in ETH of the user + * @return totalDebtETH the total debt in ETH of the user + * @return availableBorrowsETH the borrowing power left of the user + * @return currentLiquidationThreshold the liquidation threshold of the user + * @return ltv the loan to value of the user + * @return healthFactor the current health factor of the user + * + */ + function getUserAccountData(address user) + external + view + returns ( + uint256 totalCollateralETH, + uint256 totalDebtETH, + uint256 availableBorrowsETH, + uint256 currentLiquidationThreshold, + uint256 ltv, + uint256 healthFactor + ); + + function initReserve( + address reserve, + address aTokenAddress, + address stableDebtAddress, + address variableDebtAddress, + address interestRateStrategyAddress + ) + external; + + function setReserveInterestRateStrategyAddress( + address reserve, + address rateStrategyAddress + ) + external; + + function setConfiguration(address reserve, uint256 configuration) external; + + /** + * @dev Returns the configuration of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The configuration of the reserve + * + */ + function getConfiguration(address asset) + external + view + returns (DataTypes.ReserveConfigurationMap memory); + + /** + * @dev Returns the configuration of the user across all the reserves + * @param user The user address + * @return The configuration of the user + * + */ + function getUserConfiguration(address user) + external + view + returns (DataTypes.UserConfigurationMap memory); + + /** + * @dev Returns the normalized income normalized income of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The reserve's normalized income + */ + function getReserveNormalizedIncome(address asset) external view returns (uint256); + + /** + * @dev Returns the normalized variable debt per unit of asset + * @param asset The address of the underlying asset of the reserve + * @return The reserve normalized variable debt + */ + function getReserveNormalizedVariableDebt(address asset) external view returns (uint256); + + /** + * @dev Returns the state and configuration of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The state of the reserve + * + */ + function getReserveData(address asset) external view returns (DataTypes.ReserveData memory); + + function finalizeTransfer( + address asset, + address from, + address to, + uint256 amount, + uint256 balanceFromAfter, + uint256 balanceToBefore + ) + external; + + function getReservesList() external view returns (address[] memory); + + function getAddressesProvider() external view returns (ILendingPoolAddressesProviderV2); + + function setPause(bool val) external; + + function paused() external view returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IPriceOracleGetterAave.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IPriceOracleGetterAave.sol new file mode 100644 index 0000000..08946c2 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IPriceOracleGetterAave.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: agpl-3.0 + +pragma solidity ^0.8.10; + +abstract contract IPriceOracleGetterAave { + function getAssetPrice(address _asset) external view virtual returns (uint256); + function getAssetsPrices(address[] calldata _assets) + external + view + virtual + returns (uint256[] memory); + function getSourceOfAsset(address _asset) external view virtual returns (address); + function getFallbackOracle() external view virtual returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IStakedToken.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IStakedToken.sol new file mode 100644 index 0000000..7797957 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IStakedToken.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IStakedToken { + function getTotalRewardsBalance(address) external view returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/DataTypes.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/DataTypes.sol new file mode 100644 index 0000000..d65eced --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/DataTypes.sol @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.10; + +library DataTypes { + struct ReserveData { + //stores the reserve configuration + ReserveConfigurationMap configuration; + //the liquidity index. Expressed in ray + uint128 liquidityIndex; + //the current supply rate. Expressed in ray + uint128 currentLiquidityRate; + //variable borrow index. Expressed in ray + uint128 variableBorrowIndex; + //the current variable borrow rate. Expressed in ray + uint128 currentVariableBorrowRate; + //the current stable borrow rate. Expressed in ray + uint128 currentStableBorrowRate; + //timestamp of last update + uint40 lastUpdateTimestamp; + //the id of the reserve. Represents the position in the list of the active reserves + uint16 id; + //aToken address + address aTokenAddress; + //stableDebtToken address + address stableDebtTokenAddress; + //variableDebtToken address + address variableDebtTokenAddress; + //address of the interest rate strategy + address interestRateStrategyAddress; + //the current treasury balance, scaled + uint128 accruedToTreasury; + //the outstanding unbacked aTokens minted through the bridging feature + uint128 unbacked; + //the outstanding debt borrowed against this asset in isolation mode + uint128 isolationModeTotalDebt; + } + + struct ReserveConfigurationMap { + //bit 0-15: LTV + //bit 16-31: Liq. threshold + //bit 32-47: Liq. bonus + //bit 48-55: Decimals + //bit 56: reserve is active + //bit 57: reserve is frozen + //bit 58: borrowing is enabled + //bit 59: stable rate borrowing enabled + //bit 60: asset is paused + //bit 61: borrowing in isolation mode is enabled + //bit 62-63: reserved + //bit 64-79: reserve factor + //bit 80-115 borrow cap in whole tokens, borrowCap == 0 => no cap + //bit 116-151 supply cap in whole tokens, supplyCap == 0 => no cap + //bit 152-167 liquidation protocol fee + //bit 168-175 eMode category + //bit 176-211 unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled + //bit 212-251 debt ceiling for isolation mode with + // (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals + //bit 252-255 unused + uint256 data; + } + + struct UserConfigurationMap { + /** + * @dev Bitmap of the users collaterals and borrows. It is divided in pairs of bits, one + * pair per asset. + * The first bit indicates if an asset is used as collateral by the user, the second whether + * an + * asset is borrowed by the user. + */ + uint256 data; + } + + struct EModeCategory { + // each eMode category has a custom ltv and liquidation threshold + uint16 ltv; + uint16 liquidationThreshold; + uint16 liquidationBonus; + // each eMode category may or may not have a custom oracle to override the individual assets + // price oracles + address priceSource; + string label; + } + + enum InterestRateMode { + NONE, + STABLE, + VARIABLE + } + + struct ReserveCache { + uint256 currScaledVariableDebt; + uint256 nextScaledVariableDebt; + uint256 currPrincipalStableDebt; + uint256 currAvgStableBorrowRate; + uint256 currTotalStableDebt; + uint256 nextAvgStableBorrowRate; + uint256 nextTotalStableDebt; + uint256 currLiquidityIndex; + uint256 nextLiquidityIndex; + uint256 currVariableBorrowIndex; + uint256 nextVariableBorrowIndex; + uint256 currLiquidityRate; + uint256 currVariableBorrowRate; + uint256 reserveFactor; + ReserveConfigurationMap reserveConfiguration; + address aTokenAddress; + address stableDebtTokenAddress; + address variableDebtTokenAddress; + uint40 reserveLastUpdateTimestamp; + uint40 stableDebtLastUpdateTimestamp; + } + + struct ExecuteLiquidationCallParams { + uint256 reservesCount; + uint256 debtToCover; + address collateralAsset; + address debtAsset; + address user; + bool receiveAToken; + address priceOracle; + uint8 userEModeCategory; + address priceOracleSentinel; + } + + struct ExecuteSupplyParams { + address asset; + uint256 amount; + address onBehalfOf; + uint16 referralCode; + } + + struct ExecuteBorrowParams { + address asset; + address user; + address onBehalfOf; + uint256 amount; + InterestRateMode interestRateMode; + uint16 referralCode; + bool releaseUnderlying; + uint256 maxStableRateBorrowSizePercent; + uint256 reservesCount; + address oracle; + uint8 userEModeCategory; + address priceOracleSentinel; + } + + struct ExecuteRepayParams { + address asset; + uint256 amount; + InterestRateMode interestRateMode; + address onBehalfOf; + bool useATokens; + } + + struct ExecuteWithdrawParams { + address asset; + uint256 amount; + address to; + uint256 reservesCount; + address oracle; + uint8 userEModeCategory; + } + + struct ExecuteSetUserEModeParams { + uint256 reservesCount; + address oracle; + uint8 categoryId; + } + + struct FinalizeTransferParams { + address asset; + address from; + address to; + uint256 amount; + uint256 balanceFromBefore; + uint256 balanceToBefore; + uint256 reservesCount; + address oracle; + uint8 fromEModeCategory; + } + + struct FlashloanParams { + address receiverAddress; + address[] assets; + uint256[] amounts; + uint256[] interestRateModes; + address onBehalfOf; + bytes params; + uint16 referralCode; + uint256 flashLoanPremiumToProtocol; + uint256 flashLoanPremiumTotal; + uint256 maxStableRateBorrowSizePercent; + uint256 reservesCount; + address addressesProvider; + uint8 userEModeCategory; + bool isAuthorizedFlashBorrower; + } + + struct FlashloanSimpleParams { + address receiverAddress; + address asset; + uint256 amount; + bytes params; + uint16 referralCode; + uint256 flashLoanPremiumToProtocol; + uint256 flashLoanPremiumTotal; + } + + struct FlashLoanRepaymentParams { + uint256 amount; + uint256 totalPremium; + uint256 flashLoanPremiumToProtocol; + address asset; + address receiverAddress; + uint16 referralCode; + } + + struct CalculateUserAccountDataParams { + UserConfigurationMap userConfig; + uint256 reservesCount; + address user; + address oracle; + uint8 userEModeCategory; + } + + struct ValidateBorrowParams { + ReserveCache reserveCache; + UserConfigurationMap userConfig; + address asset; + address userAddress; + uint256 amount; + InterestRateMode interestRateMode; + uint256 maxStableLoanPercent; + uint256 reservesCount; + address oracle; + uint8 userEModeCategory; + address priceOracleSentinel; + bool isolationModeActive; + address isolationModeCollateralAddress; + uint256 isolationModeDebtCeiling; + } + + struct ValidateLiquidationCallParams { + ReserveCache debtReserveCache; + uint256 totalDebt; + uint256 healthFactor; + address priceOracleSentinel; + } + + struct CalculateInterestRatesParams { + uint256 unbacked; + uint256 liquidityAdded; + uint256 liquidityTaken; + uint256 totalStableDebt; + uint256 totalVariableDebt; + uint256 averageStableBorrowRate; + uint256 reserveFactor; + address reserve; + address aToken; + } + + struct InitReserveParams { + address asset; + address aTokenAddress; + address stableDebtAddress; + address variableDebtAddress; + address interestRateStrategyAddress; + uint16 reservesCount; + uint16 maxNumberReserves; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveProtocolDataProvider.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveProtocolDataProvider.sol new file mode 100644 index 0000000..44c4f12 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveProtocolDataProvider.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity ^0.8.10; + +interface IAaveProtocolDataProvider { + /** + * @notice Returns the user data in a reserve + * @param asset The address of the underlying asset of the reserve + * @param user The address of the user + * @return currentATokenBalance The current AToken balance of the user + * @return currentStableDebt The current stable debt of the user + * @return currentVariableDebt The current variable debt of the user + * @return principalStableDebt The principal stable debt of the user + * @return scaledVariableDebt The scaled variable debt of the user + * @return stableBorrowRate The stable borrow rate of the user + * @return liquidityRate The liquidity rate of the reserve + * @return stableRateLastUpdated The timestamp of the last update of the user stable rate + * @return usageAsCollateralEnabled True if the user is using the asset as collateral, false + * otherwise + * + */ + function getUserReserveData( + address asset, + address user + ) + external + view + returns ( + uint256 currentATokenBalance, + uint256 currentStableDebt, + uint256 currentVariableDebt, + uint256 principalStableDebt, + uint256 scaledVariableDebt, + uint256 stableBorrowRate, + uint256 liquidityRate, + uint40 stableRateLastUpdated, + bool usageAsCollateralEnabled + ); + function getSiloedBorrowing(address asset) external view returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveV3Oracle.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveV3Oracle.sol new file mode 100644 index 0000000..6d97442 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveV3Oracle.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity ^0.8.10; + +import { IPriceOracleGetter } from "./IPriceOracleGetter.sol"; +import { IPoolAddressesProvider } from "./IPoolAddressesProvider.sol"; + +interface IAaveV3Oracle is IPriceOracleGetter { + /** + * @dev Emitted after the base currency is set + * @param baseCurrency The base currency of used for price quotes + * @param baseCurrencyUnit The unit of the base currency + */ + event BaseCurrencySet(address indexed baseCurrency, uint256 baseCurrencyUnit); + + /** + * @dev Emitted after the price source of an asset is updated + * @param asset The address of the asset + * @param source The price source of the asset + */ + event AssetSourceUpdated(address indexed asset, address indexed source); + + /** + * @dev Emitted after the address of fallback oracle is updated + * @param fallbackOracle The address of the fallback oracle + */ + event FallbackOracleUpdated(address indexed fallbackOracle); + + /** + * @notice Returns the PoolAddressesProvider + * @return The address of the PoolAddressesProvider contract + */ + function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider); + + /** + * @notice Sets or replaces price sources of assets + * @param assets The addresses of the assets + * @param sources The addresses of the price sources + */ + function setAssetSources(address[] calldata assets, address[] calldata sources) external; + + /** + * @notice Sets the fallback oracle + * @param fallbackOracle The address of the fallback oracle + */ + function setFallbackOracle(address fallbackOracle) external; + + /** + * @notice Returns a list of prices from a list of assets addresses + * @param assets The list of assets addresses + * @return The prices of the given assets + */ + function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory); + + /** + * @notice Returns the address of the source for an asset address + * @param asset The address of the asset + * @return The address of the source + */ + function getSourceOfAsset(address asset) external view returns (address); + + /** + * @notice Returns the address of the fallback oracle + * @return The address of the fallback oracle + */ + function getFallbackOracle() external view returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IL2PoolV3.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IL2PoolV3.sol new file mode 100644 index 0000000..1ae63ad --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IL2PoolV3.sol @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: AGPL-3.0 +import "./IPoolV3.sol"; + +pragma solidity ^0.8.10; + +interface IL2PoolV3 is IPoolV3 { + /** + * @notice Calldata efficient wrapper of the supply function on behalf of the caller + * @param args Arguments for the supply function packed in one bytes32 + * 96 bits 16 bits 128 bits 16 bits + * | 0-padding | referralCode | shortenedAmount | assetId | + * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value + * will be expanded to + * type(uint256).max + * @dev assetId is the index of the asset in the reservesList. + */ + function supply(bytes32 args) external; + + /** + * @notice Calldata efficient wrapper of the supplyWithPermit function on behalf of the caller + * @param args Arguments for the supply function packed in one bytes32 + * 56 bits 8 bits 32 bits 16 bits 128 bits 16 bits + * | 0-padding | permitV | shortenedDeadline | referralCode | shortenedAmount | assetId | + * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value + * will be expanded to + * type(uint256).max + * @dev assetId is the index of the asset in the reservesList. + * @param r The R parameter of ERC712 permit sig + * @param s The S parameter of ERC712 permit sig + */ + function supplyWithPermit(bytes32 args, bytes32 r, bytes32 s) external; + + /** + * @notice Calldata efficient wrapper of the withdraw function, withdrawing to the caller + * @param args Arguments for the withdraw function packed in one bytes32 + * 112 bits 128 bits 16 bits + * | 0-padding | shortenedAmount | assetId | + * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value + * will be expanded to + * type(uint256).max + * @dev assetId is the index of the asset in the reservesList. + */ + function withdraw(bytes32 args) external; + + /** + * @notice Calldata efficient wrapper of the borrow function, borrowing on behalf of the caller + * @param args Arguments for the borrow function packed in one bytes32 + * 88 bits 16 bits 8 bits 128 bits 16 bits + * | 0-padding | referralCode | shortenedInterestRateMode | shortenedAmount | assetId | + * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value + * will be expanded to + * type(uint256).max + * @dev assetId is the index of the asset in the reservesList. + */ + function borrow(bytes32 args) external; + + /** + * @notice Calldata efficient wrapper of the repay function, repaying on behalf of the caller + * @param args Arguments for the repay function packed in one bytes32 + * 104 bits 8 bits 128 bits 16 bits + * | 0-padding | shortenedInterestRateMode | shortenedAmount | assetId | + * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value + * will be expanded to + * type(uint256).max + * @dev assetId is the index of the asset in the reservesList. + * @return The final amount repaid + */ + function repay(bytes32 args) external returns (uint256); + + /** + * @notice Calldata efficient wrapper of the repayWithPermit function, repaying on behalf of the + * caller + * @param args Arguments for the repayWithPermit function packed in one bytes32 + * 64 bits 8 bits 32 bits 8 bits 128 bits 16 + * bits + * | 0-padding | permitV | shortenedDeadline | shortenedInterestRateMode | shortenedAmount | + * assetId | + * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value + * will be expanded to + * type(uint256).max + * @dev assetId is the index of the asset in the reservesList. + * @param r The R parameter of ERC712 permit sig + * @param s The S parameter of ERC712 permit sig + * @return The final amount repaid + */ + function repayWithPermit(bytes32 args, bytes32 r, bytes32 s) external returns (uint256); + + /** + * @notice Calldata efficient wrapper of the repayWithATokens function + * @param args Arguments for the repayWithATokens function packed in one bytes32 + * 104 bits 8 bits 128 bits 16 bits + * | 0-padding | shortenedInterestRateMode | shortenedAmount | assetId | + * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value + * will be expanded to + * type(uint256).max + * @dev assetId is the index of the asset in the reservesList. + * @return The final amount repaid + */ + function repayWithATokens(bytes32 args) external returns (uint256); + + /** + * @notice Calldata efficient wrapper of the swapBorrowRateMode function + * @param args Arguments for the swapBorrowRateMode function packed in one bytes32 + * 232 bits 8 bits 16 bits + * | 0-padding | shortenedInterestRateMode | assetId | + * @dev assetId is the index of the asset in the reservesList. + */ + function swapBorrowRateMode(bytes32 args) external; + + /** + * @notice Calldata efficient wrapper of the rebalanceStableBorrowRate function + * @param args Arguments for the rebalanceStableBorrowRate function packed in one bytes32 + * 80 bits 160 bits 16 bits + * | 0-padding | user address | assetId | + * @dev assetId is the index of the asset in the reservesList. + */ + function rebalanceStableBorrowRate(bytes32 args) external; + + /** + * @notice Calldata efficient wrapper of the setUserUseReserveAsCollateral function + * @param args Arguments for the setUserUseReserveAsCollateral function packed in one bytes32 + * 239 bits 1 bit 16 bits + * | 0-padding | useAsCollateral | assetId | + * @dev assetId is the index of the asset in the reservesList. + */ + function setUserUseReserveAsCollateral(bytes32 args) external; + + /** + * @notice Calldata efficient wrapper of the liquidationCall function + * @param args1 part of the arguments for the liquidationCall function packed in one bytes32 + * 64 bits 160 bits 16 bits 16 bits + * | 0-padding | user address | debtAssetId | collateralAssetId | + * @param args2 part of the arguments for the liquidationCall function packed in one bytes32 + * 127 bits 1 bit 128 bits + * | 0-padding | receiveAToken | shortenedDebtToCover | + * @dev the shortenedDebtToCover is cast to 256 bits at decode time, + * if type(uint128).max the value will be expanded to type(uint256).max + */ + function liquidationCall(bytes32 args1, bytes32 args2) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolAddressesProvider.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolAddressesProvider.sol new file mode 100644 index 0000000..cc8135b --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolAddressesProvider.sol @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity ^0.8.10; + +interface IPoolAddressesProvider { + /** + * @dev Emitted when the market identifier is updated. + * @param oldMarketId The old id of the market + * @param newMarketId The new id of the market + */ + event MarketIdSet(string indexed oldMarketId, string indexed newMarketId); + + /** + * @dev Emitted when the pool is updated. + * @param oldAddress The old address of the Pool + * @param newAddress The new address of the Pool + */ + event PoolUpdated(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when the pool configurator is updated. + * @param oldAddress The old address of the PoolConfigurator + * @param newAddress The new address of the PoolConfigurator + */ + event PoolConfiguratorUpdated(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when the price oracle is updated. + * @param oldAddress The old address of the PriceOracle + * @param newAddress The new address of the PriceOracle + */ + event PriceOracleUpdated(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when the ACL manager is updated. + * @param oldAddress The old address of the ACLManager + * @param newAddress The new address of the ACLManager + */ + event ACLManagerUpdated(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when the ACL admin is updated. + * @param oldAddress The old address of the ACLAdmin + * @param newAddress The new address of the ACLAdmin + */ + event ACLAdminUpdated(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when the price oracle sentinel is updated. + * @param oldAddress The old address of the PriceOracleSentinel + * @param newAddress The new address of the PriceOracleSentinel + */ + event PriceOracleSentinelUpdated(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when the pool data provider is updated. + * @param oldAddress The old address of the PoolDataProvider + * @param newAddress The new address of the PoolDataProvider + */ + event PoolDataProviderUpdated(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when a new proxy is created. + * @param id The identifier of the proxy + * @param proxyAddress The address of the created proxy contract + * @param implementationAddress The address of the implementation contract + */ + event ProxyCreated( + bytes32 indexed id, address indexed proxyAddress, address indexed implementationAddress + ); + + /** + * @dev Emitted when a new non-proxied contract address is registered. + * @param id The identifier of the contract + * @param oldAddress The address of the old contract + * @param newAddress The address of the new contract + */ + event AddressSet(bytes32 indexed id, address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when the implementation of the proxy registered with id is updated + * @param id The identifier of the contract + * @param proxyAddress The address of the proxy contract + * @param oldImplementationAddress The address of the old implementation contract + * @param newImplementationAddress The address of the new implementation contract + */ + event AddressSetAsProxy( + bytes32 indexed id, + address indexed proxyAddress, + address oldImplementationAddress, + address indexed newImplementationAddress + ); + + /** + * @notice Returns the id of the Aave market to which this contract points to. + * @return The market id + * + */ + function getMarketId() external view returns (string memory); + + /** + * @notice Associates an id with a specific PoolAddressesProvider. + * @dev This can be used to create an onchain registry of PoolAddressesProviders to + * identify and validate multiple Aave markets. + * @param newMarketId The market id + */ + function setMarketId(string calldata newMarketId) external; + + /** + * @notice Returns an address by its identifier. + * @dev The returned address might be an EOA or a contract, potentially proxied + * @dev It returns ZERO if there is no registered address with the given id + * @param id The id + * @return The address of the registered for the specified id + */ + function getAddress(bytes32 id) external view returns (address); + + /** + * @notice General function to update the implementation of a proxy registered with + * certain `id`. If there is no proxy registered, it will instantiate one and + * set as implementation the `newImplementationAddress`. + * @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit + * setter function, in order to avoid unexpected consequences + * @param id The id + * @param newImplementationAddress The address of the new implementation + */ + function setAddressAsProxy(bytes32 id, address newImplementationAddress) external; + + /** + * @notice Sets an address for an id replacing the address saved in the addresses map. + * @dev IMPORTANT Use this function carefully, as it will do a hard replacement + * @param id The id + * @param newAddress The address to set + */ + function setAddress(bytes32 id, address newAddress) external; + + /** + * @notice Returns the address of the Pool proxy. + * @return The Pool proxy address + * + */ + function getPool() external view returns (address); + + /** + * @notice Updates the implementation of the Pool, or creates a proxy + * setting the new `pool` implementation when the function is called for the first time. + * @param newPoolImpl The new Pool implementation + * + */ + function setPoolImpl(address newPoolImpl) external; + + /** + * @notice Returns the address of the PoolConfigurator proxy. + * @return The PoolConfigurator proxy address + * + */ + function getPoolConfigurator() external view returns (address); + + /** + * @notice Updates the implementation of the PoolConfigurator, or creates a proxy + * setting the new `PoolConfigurator` implementation when the function is called for the first + * time. + * @param newPoolConfiguratorImpl The new PoolConfigurator implementation + * + */ + function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external; + + /** + * @notice Returns the address of the price oracle. + * @return The address of the PriceOracle + */ + function getPriceOracle() external view returns (address); + + /** + * @notice Updates the address of the price oracle. + * @param newPriceOracle The address of the new PriceOracle + */ + function setPriceOracle(address newPriceOracle) external; + + /** + * @notice Returns the address of the ACL manager. + * @return The address of the ACLManager + */ + function getACLManager() external view returns (address); + + /** + * @notice Updates the address of the ACL manager. + * @param newAclManager The address of the new ACLManager + * + */ + function setACLManager(address newAclManager) external; + + /** + * @notice Returns the address of the ACL admin. + * @return The address of the ACL admin + */ + function getACLAdmin() external view returns (address); + + /** + * @notice Updates the address of the ACL admin. + * @param newAclAdmin The address of the new ACL admin + */ + function setACLAdmin(address newAclAdmin) external; + + /** + * @notice Returns the address of the price oracle sentinel. + * @return The address of the PriceOracleSentinel + */ + function getPriceOracleSentinel() external view returns (address); + + /** + * @notice Updates the address of the price oracle sentinel. + * @param newPriceOracleSentinel The address of the new PriceOracleSentinel + * + */ + function setPriceOracleSentinel(address newPriceOracleSentinel) external; + + /** + * @notice Returns the address of the data provider. + * @return The address of the DataProvider + */ + function getPoolDataProvider() external view returns (address); + + /** + * @notice Updates the address of the data provider. + * @param newDataProvider The address of the new DataProvider + * + */ + function setPoolDataProvider(address newDataProvider) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolV3.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolV3.sol new file mode 100644 index 0000000..847fa5f --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolV3.sol @@ -0,0 +1,867 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity ^0.8.10; + +import { IPoolAddressesProvider } from "./IPoolAddressesProvider.sol"; +import { DataTypes } from "./DataTypes.sol"; + +interface IPoolV3 { + /** + * @dev Emitted on mintUnbacked() + * @param reserve The address of the underlying asset of the reserve + * @param user The address initiating the supply + * @param onBehalfOf The beneficiary of the supplied assets, receiving the aTokens + * @param amount The amount of supplied assets + * @param referralCode The referral code used + * + */ + event MintUnbacked( + address indexed reserve, + address user, + address indexed onBehalfOf, + uint256 amount, + uint16 indexed referralCode + ); + + /** + * @dev Emitted on backUnbacked() + * @param reserve The address of the underlying asset of the reserve + * @param backer The address paying for the backing + * @param amount The amount added as backing + * @param fee The amount paid in fees + * + */ + event BackUnbacked( + address indexed reserve, address indexed backer, uint256 amount, uint256 fee + ); + + /** + * @dev Emitted on supply() + * @param reserve The address of the underlying asset of the reserve + * @param user The address initiating the supply + * @param onBehalfOf The beneficiary of the supply, receiving the aTokens + * @param amount The amount supplied + * @param referralCode The referral code used + * + */ + event Supply( + address indexed reserve, + address user, + address indexed onBehalfOf, + uint256 amount, + uint16 indexed referralCode + ); + + /** + * @dev Emitted on withdraw() + * @param reserve The address of the underlying asset being withdrawn + * @param user The address initiating the withdrawal, owner of aTokens + * @param to The address that will receive the underlying + * @param amount The amount to be withdrawn + * + */ + event Withdraw( + address indexed reserve, address indexed user, address indexed to, uint256 amount + ); + + /** + * @dev Emitted on borrow() and flashLoan() when debt needs to be opened + * @param reserve The address of the underlying asset being borrowed + * @param user The address of the user initiating the borrow(), receiving the funds on borrow() + * or just + * initiator of the transaction on flashLoan() + * @param onBehalfOf The address that will be getting the debt + * @param amount The amount borrowed out + * @param interestRateMode The rate mode: 1 for Stable, 2 for Variable + * @param borrowRate The numeric rate at which the user has borrowed, expressed in ray + * @param referralCode The referral code used + * + */ + event Borrow( + address indexed reserve, + address user, + address indexed onBehalfOf, + uint256 amount, + DataTypes.InterestRateMode interestRateMode, + uint256 borrowRate, + uint16 indexed referralCode + ); + + /** + * @dev Emitted on repay() + * @param reserve The address of the underlying asset of the reserve + * @param user The beneficiary of the repayment, getting his debt reduced + * @param repayer The address of the user initiating the repay(), providing the funds + * @param amount The amount repaid + * @param useATokens True if the repayment is done using aTokens, `false` if done with + * underlying asset directly + * + */ + event Repay( + address indexed reserve, + address indexed user, + address indexed repayer, + uint256 amount, + bool useATokens + ); + + /** + * @dev Emitted on swapBorrowRateMode() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user swapping his rate mode + * @param interestRateMode The current interest rate mode of the position being swapped: 1 for + * Stable, 2 for Variable + * + */ + event SwapBorrowRateMode( + address indexed reserve, address indexed user, DataTypes.InterestRateMode interestRateMode + ); + + /** + * @dev Emitted on borrow(), repay() and liquidationCall() when using isolated assets + * @param asset The address of the underlying asset of the reserve + * @param totalDebt The total isolation mode debt for the reserve + */ + event IsolationModeTotalDebtUpdated(address indexed asset, uint256 totalDebt); + + /** + * @dev Emitted when the user selects a certain asset category for eMode + * @param user The address of the user + * @param categoryId The category id + * + */ + event UserEModeSet(address indexed user, uint8 categoryId); + + /** + * @dev Emitted on setUserUseReserveAsCollateral() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user enabling the usage as collateral + * + */ + event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); + + /** + * @dev Emitted on setUserUseReserveAsCollateral() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user enabling the usage as collateral + * + */ + event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); + + /** + * @dev Emitted on rebalanceStableBorrowRate() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user for which the rebalance has been executed + * + */ + event RebalanceStableBorrowRate(address indexed reserve, address indexed user); + + /** + * @dev Emitted on flashLoan() + * @param target The address of the flash loan receiver contract + * @param initiator The address initiating the flash loan + * @param asset The address of the asset being flash borrowed + * @param amount The amount flash borrowed + * @param interestRateMode The flashloan mode: 0 for regular flashloan, 1 for Stable debt, 2 for + * Variable debt + * @param premium The fee flash borrowed + * @param referralCode The referral code used + * + */ + event FlashLoan( + address indexed target, + address initiator, + address indexed asset, + uint256 amount, + DataTypes.InterestRateMode interestRateMode, + uint256 premium, + uint16 indexed referralCode + ); + + /** + * @dev Emitted when a borrower is liquidated. + * @param collateralAsset The address of the underlying asset used as collateral, to receive as + * result of the liquidation + * @param debtAsset The address of the underlying borrowed asset to be repaid with the + * liquidation + * @param user The address of the borrower getting liquidated + * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover + * @param liquidatedCollateralAmount The amount of collateral received by the liquidator + * @param liquidator The address of the liquidator + * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` + * if he wants + * to receive the underlying collateral asset directly + * + */ + event LiquidationCall( + address indexed collateralAsset, + address indexed debtAsset, + address indexed user, + uint256 debtToCover, + uint256 liquidatedCollateralAmount, + address liquidator, + bool receiveAToken + ); + + /** + * @dev Emitted when the state of a reserve is updated. + * @param reserve The address of the underlying asset of the reserve + * @param liquidityRate The next liquidity rate + * @param stableBorrowRate The next stable borrow rate + * @param variableBorrowRate The next variable borrow rate + * @param liquidityIndex The next liquidity index + * @param variableBorrowIndex The next variable borrow index + * + */ + event ReserveDataUpdated( + address indexed reserve, + uint256 liquidityRate, + uint256 stableBorrowRate, + uint256 variableBorrowRate, + uint256 liquidityIndex, + uint256 variableBorrowIndex + ); + + /** + * @dev Emitted when the protocol treasury receives minted aTokens from the accrued interest. + * @param reserve The address of the reserve + * @param amountMinted The amount minted to the treasury + * + */ + event MintedToTreasury(address indexed reserve, uint256 amountMinted); + + /** + * @dev Mints an `amount` of aTokens to the `onBehalfOf` + * @param asset The address of the underlying asset to mint + * @param amount The amount to mint + * @param onBehalfOf The address that will receive the aTokens + * @param referralCode Code used to register the integrator originating the operation, for + * potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * + */ + function mintUnbacked( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode + ) + external; + + /** + * @dev Back the current unbacked underlying with `amount` and pay `fee`. + * @param asset The address of the underlying asset to back + * @param amount The amount to back + * @param fee The amount paid in fees + * + */ + function backUnbacked(address asset, uint256 amount, uint256 fee) external; + + /** + * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return + * overlying aTokens. + * - E.g. User supplies 100 USDC and gets in return 100 aUSDC + * @param asset The address of the underlying asset to supply + * @param amount The amount to be supplied + * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user + * wants to receive them on his own wallet, or a different address if the beneficiary of + * aTokens + * is a different wallet + * @param referralCode Code used to register the integrator originating the operation, for + * potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * + */ + function supply( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode + ) + external; + + /** + * @notice Supply with transfer approval of asset to be supplied done via permit function + * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713 + * @param asset The address of the underlying asset to supply + * @param amount The amount to be supplied + * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user + * wants to receive them on his own wallet, or a different address if the beneficiary of + * aTokens + * is a different wallet + * @param deadline The deadline timestamp that the permit is valid + * @param referralCode Code used to register the integrator originating the operation, for + * potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * @param permitV The V parameter of ERC712 permit sig + * @param permitR The R parameter of ERC712 permit sig + * @param permitS The S parameter of ERC712 permit sig + * + */ + function supplyWithPermit( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode, + uint256 deadline, + uint8 permitV, + bytes32 permitR, + bytes32 permitS + ) + external; + + /** + * @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent + * aTokens owned + * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC + * @param asset The address of the underlying asset to withdraw + * @param amount The underlying amount to be withdrawn + * - Send the value type(uint256).max in order to withdraw the whole aToken balance + * @param to The address that will receive the underlying, same as msg.sender if the user + * wants to receive it on his own wallet, or a different address if the beneficiary is a + * different wallet + * @return The final amount withdrawn + * + */ + function withdraw(address asset, uint256 amount, address to) external returns (uint256); + + /** + * @notice Allows users to borrow a specific `amount` of the reserve underlying asset, provided + * that the borrower + * already supplied enough collateral, or he was given enough allowance by a credit delegator on + * the + * corresponding debt token (StableDebtToken or VariableDebtToken) + * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC + * in his wallet + * and 100 stable/variable debt tokens, depending on the `interestRateMode` + * @param asset The address of the underlying asset to borrow + * @param amount The amount to be borrowed + * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for + * Stable, 2 for Variable + * @param referralCode The code used to register the integrator originating the operation, for + * potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * @param onBehalfOf The address of the user who will receive the debt. Should be the address of + * the borrower itself + * calling the function if he wants to borrow against his own collateral, or the address of the + * credit delegator + * if he has been given credit delegation allowance + * + */ + function borrow( + address asset, + uint256 amount, + uint256 interestRateMode, + uint16 referralCode, + address onBehalfOf + ) + external; + + /** + * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens + * owned + * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` + * address + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the + * specific `debtMode` + * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for + * Stable, 2 for Variable + * @param onBehalfOf The address of the user who will get his debt reduced/removed. Should be + * the address of the + * user calling the function if he wants to reduce/remove his own debt, or the address of any + * other + * other borrower whose debt should be removed + * @return The final amount repaid + * + */ + function repay( + address asset, + uint256 amount, + uint256 interestRateMode, + address onBehalfOf + ) + external + returns (uint256); + + /** + * @notice Repay with transfer approval of asset to be repaid done via permit function + * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713 + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the + * specific `debtMode` + * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for + * Stable, 2 for Variable + * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the + * address of the + * user calling the function if he wants to reduce/remove his own debt, or the address of any + * other + * other borrower whose debt should be removed + * @param deadline The deadline timestamp that the permit is valid + * @param permitV The V parameter of ERC712 permit sig + * @param permitR The R parameter of ERC712 permit sig + * @param permitS The S parameter of ERC712 permit sig + * @return The final amount repaid + * + */ + function repayWithPermit( + address asset, + uint256 amount, + uint256 interestRateMode, + address onBehalfOf, + uint256 deadline, + uint8 permitV, + bytes32 permitR, + bytes32 permitS + ) + external + returns (uint256); + + /** + * @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning + * the + * equivalent debt tokens + * - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable/stable debt tokens + * @dev Passing uint256.max as amount will clean up any residual aToken dust balance, if the + * user aToken + * balance is not enough to cover the whole debt + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the + * specific `debtMode` + * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for + * Stable, 2 for Variable + * @return The final amount repaid + * + */ + function repayWithATokens( + address asset, + uint256 amount, + uint256 interestRateMode + ) + external + returns (uint256); + + /** + * @notice Allows a borrower to swap his debt between stable and variable mode, or vice versa + * @param asset The address of the underlying asset borrowed + * @param interestRateMode The current interest rate mode of the position being swapped: 1 for + * Stable, 2 for Variable + * + */ + function swapBorrowRateMode(address asset, uint256 interestRateMode) external; + + /** + * @notice Rebalances the stable interest rate of a user to the current stable rate defined on + * the reserve. + * - Users can be rebalanced if the following conditions are satisfied: + * 1. Usage ratio is above 95% + * 2. the current supply APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which + * means that too + * much has been borrowed at a stable rate and suppliers are not earning enough + * @param asset The address of the underlying asset borrowed + * @param user The address of the user to be rebalanced + * + */ + function rebalanceStableBorrowRate(address asset, address user) external; + + /** + * @notice Allows suppliers to enable/disable a specific supplied asset as collateral + * @param asset The address of the underlying asset supplied + * @param useAsCollateral True if the user wants to use the supply as collateral, false + * otherwise + * + */ + function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external; + + /** + * @notice Function to liquidate a non-healthy position collateral-wise, with Health Factor + * below 1 + * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, + * and receives + * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk + * @param collateralAsset The address of the underlying asset used as collateral, to receive as + * result of the liquidation + * @param debtAsset The address of the underlying borrowed asset to be repaid with the + * liquidation + * @param user The address of the borrower getting liquidated + * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover + * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` + * if he wants + * to receive the underlying collateral asset directly + * + */ + function liquidationCall( + address collateralAsset, + address debtAsset, + address user, + uint256 debtToCover, + bool receiveAToken + ) + external; + + /** + * @notice Allows smartcontracts to access the liquidity of the pool within one transaction, + * as long as the amount taken plus a fee is returned. + * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts + * that must be kept + * into consideration. For further details please visit https://developers.aave.com + * @param receiverAddress The address of the contract receiving the funds, implementing + * IFlashLoanReceiver interface + * @param assets The addresses of the assets being flash-borrowed + * @param amounts The amounts of the assets being flash-borrowed + * @param interestRateModes Types of the debt to open if the flash loan is not returned: + * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver + * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the + * `onBehalfOf` address + * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the + * `onBehalfOf` address + * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 + * or 2 + * @param params Variadic packed params to pass to the receiver as extra information + * @param referralCode The code used to register the integrator originating the operation, for + * potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * + */ + function flashLoan( + address receiverAddress, + address[] calldata assets, + uint256[] calldata amounts, + uint256[] calldata interestRateModes, + address onBehalfOf, + bytes calldata params, + uint16 referralCode + ) + external; + + /** + * @notice Allows smartcontracts to access the liquidity of the pool within one transaction, + * as long as the amount taken plus a fee is returned. + * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts + * that must be kept + * into consideration. For further details please visit https://developers.aave.com + * @param receiverAddress The address of the contract receiving the funds, implementing + * IFlashLoanSimpleReceiver interface + * @param asset The address of the asset being flash-borrowed + * @param amount The amount of the asset being flash-borrowed + * @param params Variadic packed params to pass to the receiver as extra information + * @param referralCode The code used to register the integrator originating the operation, for + * potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * + */ + function flashLoanSimple( + address receiverAddress, + address asset, + uint256 amount, + bytes calldata params, + uint16 referralCode + ) + external; + + /** + * @notice Returns the user account data across all the reserves + * @param user The address of the user + * @return totalCollateralBase The total collateral of the user in the base currency used by the + * price feed + * @return totalDebtBase The total debt of the user in the base currency used by the price feed + * @return availableBorrowsBase The borrowing power left of the user in the base currency used + * by the price feed + * @return currentLiquidationThreshold The liquidation threshold of the user + * @return ltv The loan to value of The user + * @return healthFactor The current health factor of the user + * + */ + function getUserAccountData(address user) + external + view + returns ( + uint256 totalCollateralBase, + uint256 totalDebtBase, + uint256 availableBorrowsBase, + uint256 currentLiquidationThreshold, + uint256 ltv, + uint256 healthFactor + ); + + /** + * @notice Initializes a reserve, activating it, assigning an aToken and debt tokens and an + * interest rate strategy + * @dev Only callable by the PoolConfigurator contract + * @param asset The address of the underlying asset of the reserve + * @param aTokenAddress The address of the aToken that will be assigned to the reserve + * @param stableDebtAddress The address of the StableDebtToken that will be assigned to the + * reserve + * @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the + * reserve + * @param interestRateStrategyAddress The address of the interest rate strategy contract + * + */ + function initReserve( + address asset, + address aTokenAddress, + address stableDebtAddress, + address variableDebtAddress, + address interestRateStrategyAddress + ) + external; + + /** + * @notice Drop a reserve + * @dev Only callable by the PoolConfigurator contract + * @param asset The address of the underlying asset of the reserve + * + */ + function dropReserve(address asset) external; + + /** + * @notice Updates the address of the interest rate strategy contract + * @dev Only callable by the PoolConfigurator contract + * @param asset The address of the underlying asset of the reserve + * @param rateStrategyAddress The address of the interest rate strategy contract + * + */ + function setReserveInterestRateStrategyAddress( + address asset, + address rateStrategyAddress + ) + external; + + /** + * @notice Sets the configuration bitmap of the reserve as a whole + * @dev Only callable by the PoolConfigurator contract + * @param asset The address of the underlying asset of the reserve + * @param configuration The new configuration bitmap + * + */ + function setConfiguration( + address asset, + DataTypes.ReserveConfigurationMap calldata configuration + ) + external; + + /** + * @notice Returns the configuration of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The configuration of the reserve + * + */ + function getConfiguration(address asset) + external + view + returns (DataTypes.ReserveConfigurationMap memory); + + /** + * @notice Returns the configuration of the user across all the reserves + * @param user The user address + * @return The configuration of the user + * + */ + function getUserConfiguration(address user) + external + view + returns (DataTypes.UserConfigurationMap memory); + + /** + * @notice Returns the normalized income normalized income of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The reserve's normalized income + */ + function getReserveNormalizedIncome(address asset) external view returns (uint256); + + /** + * @notice Returns the normalized variable debt per unit of asset + * @param asset The address of the underlying asset of the reserve + * @return The reserve normalized variable debt + */ + function getReserveNormalizedVariableDebt(address asset) external view returns (uint256); + + /** + * @notice Returns the state and configuration of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The state and configuration data of the reserve + * + */ + function getReserveData(address asset) external view returns (DataTypes.ReserveData memory); + + /** + * @notice Validates and finalizes an aToken transfer + * @dev Only callable by the overlying aToken of the `asset` + * @param asset The address of the underlying asset of the aToken + * @param from The user from which the aTokens are transferred + * @param to The user receiving the aTokens + * @param amount The amount being transferred/withdrawn + * @param balanceFromBefore The aToken balance of the `from` user before the transfer + * @param balanceToBefore The aToken balance of the `to` user before the transfer + */ + function finalizeTransfer( + address asset, + address from, + address to, + uint256 amount, + uint256 balanceFromBefore, + uint256 balanceToBefore + ) + external; + + /** + * @notice Returns the list of the initialized reserves + * @dev It does not include dropped reserves + * @return The addresses of the reserves + * + */ + function getReservesList() external view returns (address[] memory); + + /** + * @notice Returns the PoolAddressesProvider connected to this contract + * @return The address of the PoolAddressesProvider + * + */ + function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider); + + /** + * @notice Updates the protocol fee on the bridging + * @param bridgeProtocolFee The part of the premium sent to the protocol treasury + */ + function updateBridgeProtocolFee(uint256 bridgeProtocolFee) external; + + /** + * @notice Updates flash loan premiums. Flash loan premium consists of two parts: + * - A part is sent to aToken holders as extra, one time accumulated interest + * - A part is collected by the protocol treasury + * @dev The total premium is calculated on the total borrowed amount + * @dev The premium to protocol is calculated on the total premium, being a percentage of + * `flashLoanPremiumTotal` + * @dev Only callable by the PoolConfigurator contract + * @param flashLoanPremiumTotal The total premium, expressed in bps + * @param flashLoanPremiumToProtocol The part of the premium sent to the protocol treasury, + * expressed in bps + */ + function updateFlashloanPremiums( + uint128 flashLoanPremiumTotal, + uint128 flashLoanPremiumToProtocol + ) + external; + + /** + * @notice Configures a new category for the eMode. + * @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same + * category. + * The category 0 is reserved as it's the default for volatile assets + * @param id The id of the category + * @param config The configuration of the category + */ + function configureEModeCategory(uint8 id, DataTypes.EModeCategory memory config) external; + + /** + * @notice Returns the data of an eMode category + * @param id The id of the category + * @return The configuration data of the category + */ + function getEModeCategoryData(uint8 id) + external + view + returns (DataTypes.EModeCategory memory); + + /** + * @notice Allows a user to use the protocol in eMode + * @param categoryId The id of the category + */ + function setUserEMode(uint8 categoryId) external; + + /** + * @notice Returns the eMode the user is using + * @param user The address of the user + * @return The eMode id + */ + function getUserEMode(address user) external view returns (uint256); + + /** + * @notice Resets the isolation mode total debt of the given asset to zero + * @dev It requires the given asset has zero debt ceiling + * @param asset The address of the underlying asset to reset the isolationModeTotalDebt + */ + function resetIsolationModeTotalDebt(address asset) external; + + /** + * @notice Returns the percentage of available liquidity that can be borrowed at once at stable + * rate + * @return The percentage of available liquidity to borrow, expressed in bps + */ + function MAX_STABLE_RATE_BORROW_SIZE_PERCENT() external view returns (uint256); + + /** + * @notice Returns the total fee on flash loans + * @return The total fee on flashloans + */ + function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128); + + /** + * @notice Returns the part of the bridge fees sent to protocol + * @return The bridge fee sent to the protocol treasury + */ + function BRIDGE_PROTOCOL_FEE() external view returns (uint256); + + /** + * @notice Returns the part of the flashloan fees sent to protocol + * @return The flashloan fee sent to the protocol treasury + */ + function FLASHLOAN_PREMIUM_TO_PROTOCOL() external view returns (uint128); + + /** + * @notice Returns the maximum number of reserves supported to be listed in this Pool + * @return The maximum number of reserves supported + */ + function MAX_NUMBER_RESERVES() external view returns (uint16); + + /** + * @notice Mints the assets accrued through the reserve factor to the treasury in the form of + * aTokens + * @param assets The list of reserves for which the minting needs to be executed + * + */ + function mintToTreasury(address[] calldata assets) external; + + /** + * @notice Rescue and transfer tokens locked in this contract + * @param token The address of the token + * @param to The address of the recipient + * @param amount The amount of token to transfer + */ + function rescueTokens(address token, address to, uint256 amount) external; + + /** + * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return + * overlying aTokens. + * - E.g. User supplies 100 USDC and gets in return 100 aUSDC + * @dev Deprecated: Use the `supply` function instead + * @param asset The address of the underlying asset to supply + * @param amount The amount to be supplied + * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user + * wants to receive them on his own wallet, or a different address if the beneficiary of + * aTokens + * is a different wallet + * @param referralCode Code used to register the integrator originating the operation, for + * potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * + */ + function deposit( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode + ) + external; + + /** + * @notice Returns the address of the underlying asset of a reserve by the reserve id as stored + * in the DataTypes.ReserveData struct + * @param id The id of the reserve as stored in the DataTypes.ReserveData struct + * @return The address of the reserve associated with id + * + */ + function getReserveAddressById(uint16 id) external view returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleGetter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleGetter.sol new file mode 100644 index 0000000..51b7652 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleGetter.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity ^0.8.10; + +interface IPriceOracleGetter { + /** + * @notice Returns the base currency address + * @dev Address 0x0 is reserved for USD as base currency. + * @return Returns the base currency address. + * + */ + function BASE_CURRENCY() external view returns (address); + + /** + * @notice Returns the base currency unit + * @dev 1 ether for ETH, 1e8 for USD. + * @return Returns the base currency unit. + * + */ + function BASE_CURRENCY_UNIT() external view returns (uint256); + + /** + * @notice Returns the asset price in the base currency + * @param asset The address of the asset + * @return The price of the asset + * + */ + function getAssetPrice(address asset) external view returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleSentinel.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleSentinel.sol new file mode 100644 index 0000000..5673dc8 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleSentinel.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity ^0.8.0; + +interface IPriceOracleSentinel { + /** + * @dev Emitted after the sequencer oracle is updated + * @param newSequencerOracle The new sequencer oracle + */ + event SequencerOracleUpdated(address newSequencerOracle); + + /** + * @dev Emitted after the grace period is updated + * @param newGracePeriod The new grace period value + */ + event GracePeriodUpdated(uint256 newGracePeriod); + + /** + * @notice Returns true if the `borrow` operation is allowed. + * @dev Operation not allowed when PriceOracle is down or grace period not passed. + * @return True if the `borrow` operation is allowed, false otherwise. + */ + function isBorrowAllowed() external view returns (bool); + + /** + * @notice Returns true if the `liquidation` operation is allowed. + * @dev Operation not allowed when PriceOracle is down or grace period not passed. + * @return True if the `liquidation` operation is allowed, false otherwise. + */ + function isLiquidationAllowed() external view returns (bool); + + /** + * @notice Updates the address of the sequencer oracle + * @param newSequencerOracle The address of the new Sequencer Oracle to use + */ + function setSequencerOracle(address newSequencerOracle) external; + + /** + * @notice Updates the duration of the grace period + * @param newGracePeriod The value of the new grace period duration + */ + function setGracePeriod(uint256 newGracePeriod) external; + + /** + * @notice Returns the SequencerOracle + * @return The address of the sequencer oracle contract + */ + function getSequencerOracle() external view returns (address); + + /** + * @notice Returns the grace period + * @return The duration of the grace period + */ + function getGracePeriod() external view returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsController.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsController.sol new file mode 100644 index 0000000..e9f7c73 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsController.sol @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.8.10; + +import { IRewardsDistributor } from "./IRewardsDistributor.sol"; + +interface IRewardsController is IRewardsDistributor { + /** + * @dev Emitted when a new address is whitelisted as claimer of rewards on behalf of a user + * @param user The address of the user + * @param claimer The address of the claimer + */ + event ClaimerSet(address indexed user, address indexed claimer); + + /** + * @dev Emitted when rewards are claimed + * @param user The address of the user rewards has been claimed on behalf of + * @param reward The address of the token reward is claimed + * @param to The address of the receiver of the rewards + * @param claimer The address of the claimer + * @param amount The amount of rewards claimed + */ + event RewardsClaimed( + address indexed user, + address indexed reward, + address indexed to, + address claimer, + uint256 amount + ); + + /** + * @dev Emitted when a transfer strategy is installed for the reward distribution + * @param reward The address of the token reward + * @param transferStrategy The address of TransferStrategy contract + */ + event TransferStrategyInstalled(address indexed reward, address indexed transferStrategy); + + /** + * @dev Emitted when the reward oracle is updated + * @param reward The address of the token reward + * @param rewardOracle The address of oracle + */ + event RewardOracleUpdated(address indexed reward, address indexed rewardOracle); + + /** + * @dev Whitelists an address to claim the rewards on behalf of another address + * @param user The address of the user + * @param claimer The address of the claimer + */ + function setClaimer(address user, address claimer) external; + + /** + * @dev Get the price aggregator oracle address + * @param reward The address of the reward + * @return The price oracle of the reward + */ + function getRewardOracle(address reward) external view returns (address); + + /** + * @dev Returns the whitelisted claimer for a certain address (0x0 if not set) + * @param user The address of the user + * @return The claimer address + */ + function getClaimer(address user) external view returns (address); + + /** + * @dev Returns the Transfer Strategy implementation contract address being used for a reward + * address + * @param reward The address of the reward + * @return The address of the TransferStrategy contract + */ + function getTransferStrategy(address reward) external view returns (address); + + /** + * @dev Called by the corresponding asset on any update that affects the rewards distribution + * @param user The address of the user + * @param userBalance The user balance of the asset + * @param totalSupply The total supply of the asset + * + */ + function handleAction(address user, uint256 userBalance, uint256 totalSupply) external; + + /** + * @dev Claims reward for a user to the desired address, on all the assets of the pool, + * accumulating the pending rewards + * @param assets List of assets to check eligible distributions before claiming rewards + * @param amount The amount of rewards to claim + * @param to The address that will be receiving the rewards + * @param reward The address of the reward token + * @return The amount of rewards claimed + * + */ + function claimRewards( + address[] calldata assets, + uint256 amount, + address to, + address reward + ) + external + returns (uint256); + + /** + * @dev Claims reward for a user on behalf, on all the assets of the pool, accumulating the + * pending rewards. The + * caller must be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager + * @param assets The list of assets to check eligible distributions before claiming rewards + * @param amount The amount of rewards to claim + * @param user The address to check and claim rewards + * @param to The address that will be receiving the rewards + * @param reward The address of the reward token + * @return The amount of rewards claimed + * + */ + function claimRewardsOnBehalf( + address[] calldata assets, + uint256 amount, + address user, + address to, + address reward + ) + external + returns (uint256); + + /** + * @dev Claims reward for msg.sender, on all the assets of the pool, accumulating the pending + * rewards + * @param assets The list of assets to check eligible distributions before claiming rewards + * @param amount The amount of rewards to claim + * @param reward The address of the reward token + * @return The amount of rewards claimed + * + */ + function claimRewardsToSelf( + address[] calldata assets, + uint256 amount, + address reward + ) + external + returns (uint256); + + /** + * @dev Claims all rewards for a user to the desired address, on all the assets of the pool, + * accumulating the pending rewards + * @param assets The list of assets to check eligible distributions before claiming rewards + * @param to The address that will be receiving the rewards + * @return rewardsList List of addresses of the reward tokens + * @return claimedAmounts List that contains the claimed amount per reward, following same order + * as "rewardList" + * + */ + function claimAllRewards( + address[] calldata assets, + address to + ) + external + returns (address[] memory rewardsList, uint256[] memory claimedAmounts); + + /** + * @dev Claims all rewards for a user on behalf, on all the assets of the pool, accumulating the + * pending rewards. The caller must + * be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager + * @param assets The list of assets to check eligible distributions before claiming rewards + * @param user The address to check and claim rewards + * @param to The address that will be receiving the rewards + * @return rewardsList List of addresses of the reward tokens + * @return claimedAmounts List that contains the claimed amount per reward, following same order + * as "rewardsList" + * + */ + function claimAllRewardsOnBehalf( + address[] calldata assets, + address user, + address to + ) + external + returns (address[] memory rewardsList, uint256[] memory claimedAmounts); + + /** + * @dev Claims all reward for msg.sender, on all the assets of the pool, accumulating the + * pending rewards + * @param assets The list of assets to check eligible distributions before claiming rewards + * @return rewardsList List of addresses of the reward tokens + * @return claimedAmounts List that contains the claimed amount per reward, following same order + * as "rewardsList" + * + */ + function claimAllRewardsToSelf(address[] calldata assets) + external + returns (address[] memory rewardsList, uint256[] memory claimedAmounts); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsDistributor.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsDistributor.sol new file mode 100644 index 0000000..52b4ba1 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsDistributor.sol @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.8.10; + +interface IRewardsDistributor { + /** + * @dev Emitted when the configuration of the rewards of an asset is updated. + * @param asset The address of the incentivized asset + * @param reward The address of the reward token + * @param oldEmission The old emissions per second value of the reward distribution + * @param newEmission The new emissions per second value of the reward distribution + * @param oldDistributionEnd The old end timestamp of the reward distribution + * @param newDistributionEnd The new end timestamp of the reward distribution + * @param assetIndex The index of the asset distribution + */ + event AssetConfigUpdated( + address indexed asset, + address indexed reward, + uint256 oldEmission, + uint256 newEmission, + uint256 oldDistributionEnd, + uint256 newDistributionEnd, + uint256 assetIndex + ); + + /** + * @dev Emitted when rewards of an asset are accrued on behalf of a user. + * @param asset The address of the incentivized asset + * @param reward The address of the reward token + * @param user The address of the user that rewards are accrued on behalf of + * @param assetIndex The index of the asset distribution + * @param userIndex The index of the asset distribution on behalf of the user + * @param rewardsAccrued The amount of rewards accrued + */ + event Accrued( + address indexed asset, + address indexed reward, + address indexed user, + uint256 assetIndex, + uint256 userIndex, + uint256 rewardsAccrued + ); + + /** + * @dev Emitted when the emission manager address is updated. + * @param oldEmissionManager The address of the old emission manager + * @param newEmissionManager The address of the new emission manager + */ + event EmissionManagerUpdated( + address indexed oldEmissionManager, address indexed newEmissionManager + ); + + /** + * @dev Sets the end date for the distribution + * @param asset The asset to incentivize + * @param reward The reward token that incentives the asset + * @param newDistributionEnd The end date of the incentivization, in unix time format + * + */ + function setDistributionEnd( + address asset, + address reward, + uint32 newDistributionEnd + ) + external; + + /** + * @dev Sets the emission per second of a set of reward distributions + * @param asset The asset is being incentivized + * @param rewards List of reward addresses are being distributed + * @param newEmissionsPerSecond List of new reward emissions per second + */ + function setEmissionPerSecond( + address asset, + address[] calldata rewards, + uint88[] calldata newEmissionsPerSecond + ) + external; + + /** + * @dev Gets the end date for the distribution + * @param asset The incentivized asset + * @param reward The reward token of the incentivized asset + * @return The timestamp with the end of the distribution, in unix time format + * + */ + function getDistributionEnd(address asset, address reward) external view returns (uint256); + + /** + * @dev Returns the index of a user on a reward distribution + * @param user Address of the user + * @param asset The incentivized asset + * @param reward The reward token of the incentivized asset + * @return The current user asset index, not including new distributions + * + */ + function getUserAssetIndex( + address user, + address asset, + address reward + ) + external + view + returns (uint256); + + /** + * @dev Returns the configuration of the distribution reward for a certain asset + * @param asset The incentivized asset + * @param reward The reward token of the incentivized asset + * @return The index of the asset distribution + * @return The emission per second of the reward distribution + * @return The timestamp of the last update of the index + * @return The timestamp of the distribution end + * + */ + function getRewardsData( + address asset, + address reward + ) + external + view + returns (uint256, uint256, uint256, uint256); + + /** + * @dev Returns the list of available reward token addresses of an incentivized asset + * @param asset The incentivized asset + * @return List of rewards addresses of the input asset + * + */ + function getRewardsByAsset(address asset) external view returns (address[] memory); + + /** + * @dev Returns the list of available reward addresses + * @return List of rewards supported in this contract + * + */ + function getRewardsList() external view returns (address[] memory); + + /** + * @dev Returns the accrued rewards balance of a user, not including virtually accrued rewards + * since last distribution. + * @param user The address of the user + * @param reward The address of the reward token + * @return Unclaimed rewards, not including new distributions + * + */ + function getUserAccruedRewards(address user, address reward) external view returns (uint256); + + /** + * @dev Returns a single rewards balance of a user, including virtually accrued and unrealized + * claimable rewards. + * @param assets List of incentivized assets to check eligible distributions + * @param user The address of the user + * @param reward The address of the reward token + * @return The rewards amount + * + */ + function getUserRewards( + address[] calldata assets, + address user, + address reward + ) + external + view + returns (uint256); + + /** + * @dev Returns a list all rewards of a user, including already accrued and unrealized claimable + * rewards + * @param assets List of incentivized assets to check eligible distributions + * @param user The address of the user + * @return The list of reward addresses + * @return The list of unclaimed amount of rewards + * + */ + function getAllUserRewards( + address[] calldata assets, + address user + ) + external + view + returns (address[] memory, uint256[] memory); + + /** + * @dev Returns the decimals of an asset to calculate the distribution delta + * @param asset The address to retrieve decimals + * @return The decimals of an underlying asset + */ + function getAssetDecimals(address asset) external view returns (uint8); + + /** + * @dev Returns the address of the emission manager + * @return The address of the EmissionManager + */ + function getEmissionManager() external view returns (address); + + /** + * @dev Updates the address of the emission manager + * @param emissionManager The address of the new EmissionManager + */ + function setEmissionManager(address emissionManager) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoanRecipient.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoanRecipient.sol new file mode 100644 index 0000000..d5c07b4 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoanRecipient.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IFlashLoanRecipient { + /** + * @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the + * recipient. + * + * At the time of the call, the Vault will have transferred `amounts` for `tokens` to the + * recipient. Before this + * call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token + * back to the + * Vault, or else the entire flash loan will revert. + * + * `userData` is the same value passed in the `IVault.flashLoan` call. + */ + function receiveFlashLoan( + address[] memory tokens, + uint256[] memory amounts, + uint256[] memory feeAmounts, + bytes memory userData + ) + external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoans.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoans.sol new file mode 100644 index 0000000..45f70e2 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoans.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IFlashLoans { + function flashLoan( + address recipient, + address[] memory tokens, + uint256[] memory amounts, + bytes memory userData + ) + external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IMerkleRedeem.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IMerkleRedeem.sol new file mode 100644 index 0000000..fb2b316 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IMerkleRedeem.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; +pragma experimental ABIEncoderV2; + +interface IMerkleRedeem { + struct Claim { + uint256 week; + uint256 balance; + bytes32[] merkleProof; + } + + function claimWeeks(address _liquidityProvider, Claim[] memory claims) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IPool.sol new file mode 100644 index 0000000..2b035fc --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IPool.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IPool { + function getPoolId() external view returns (bytes32); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IVault.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IVault.sol new file mode 100644 index 0000000..e293711 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IVault.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; +pragma experimental ABIEncoderV2; + +interface IAsset { } + +interface IVault { + function joinPool( + bytes32 poolId, + address sender, + address recipient, + JoinPoolRequest memory request + ) + external + payable; + + struct JoinPoolRequest { + IAsset[] assets; + uint256[] maxAmountsIn; + bytes userData; + bool fromInternalBalance; + } + + function exitPool( + bytes32 poolId, + address sender, + address payable recipient, + ExitPoolRequest memory request + ) + external; + + struct ExitPoolRequest { + IAsset[] assets; + uint256[] minAmountsOut; + bytes userData; + bool toInternalBalance; + } + + function getPoolTokens(bytes32 poolId) + external + view + returns (address[] memory tokens, uint256[] memory balances, uint256 lastChangeBlock); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/bprotocol/IBAMM.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/bprotocol/IBAMM.sol new file mode 100644 index 0000000..c1bd8e0 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/bprotocol/IBAMM.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IBAMM { + function deposit(uint256) external; + function withdraw(uint256) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IAggregatorV3.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IAggregatorV3.sol new file mode 100644 index 0000000..c1df605 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IAggregatorV3.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IAggregatorV3 { + function decimals() external view returns (uint8); + + function description() external view returns (string memory); + + function version() external view returns (uint256); + + // getRoundData and latestRoundData should both raise "No data present" + // if they do not have data to report, instead of returning unset values + // which could be misinterpreted as actual reported values. + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); + + function latestRoundData() + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); + + function latestAnswer() external view returns (uint256); + + function getTimestamp(uint256 _roundId) external view returns (uint256); + + function phaseId() external view returns (uint16); + + function phaseAggregators(uint16 _phaseId) external view returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IFeedRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IFeedRegistry.sol new file mode 100644 index 0000000..af2dc7a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IFeedRegistry.sol @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IFeedRegistry { + struct Phase { + uint16 phaseId; + uint80 startingAggregatorRoundId; + uint80 endingAggregatorRoundId; + } + + event FeedProposed( + address indexed asset, + address indexed denomination, + address indexed proposedAggregator, + address currentAggregator, + address sender + ); + event FeedConfirmed( + address indexed asset, + address indexed denomination, + address indexed latestAggregator, + address previousAggregator, + uint16 nextPhaseId, + address sender + ); + + // V3 AggregatorV3Interface + + function decimals(address base, address quote) external view returns (uint8); + + function description(address base, address quote) external view returns (string memory); + + function version(address base, address quote) external view returns (uint256); + + function latestRoundData( + address base, + address quote + ) + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); + + function getRoundData( + address base, + address quote, + uint80 _roundId + ) + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); + + // V2 AggregatorInterface + + function latestAnswer(address base, address quote) external view returns (int256 answer); + + function latestTimestamp( + address base, + address quote + ) + external + view + returns (uint256 timestamp); + + function latestRound(address base, address quote) external view returns (uint256 roundId); + + function getAnswer( + address base, + address quote, + uint256 roundId + ) + external + view + returns (int256 answer); + + function getTimestamp( + address base, + address quote, + uint256 roundId + ) + external + view + returns (uint256 timestamp); + + function isFeedEnabled(address aggregator) external view returns (bool); + + function getPhase( + address base, + address quote, + uint16 phaseId + ) + external + view + returns (Phase memory phase); + + // Round helpers + + function getPhaseRange( + address base, + address quote, + uint16 phaseId + ) + external + view + returns (uint80 startingRoundId, uint80 endingRoundId); + + function getPreviousRoundId( + address base, + address quote, + uint80 roundId + ) + external + view + returns (uint80 previousRoundId); + + function getNextRoundId( + address base, + address quote, + uint80 roundId + ) + external + view + returns (uint80 nextRoundId); + + // Feed management + + function proposeFeed(address base, address quote, address aggregator) external; + + function confirmFeed(address base, address quote, address aggregator) external; + + // Proposed aggregator + + function proposedGetRoundData( + address base, + address quote, + uint80 roundId + ) + external + view + returns ( + uint80 id, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); + + function proposedLatestRoundData( + address base, + address quote + ) + external + view + returns ( + uint80 id, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); + + // Phases + function getCurrentPhaseId( + address base, + address quote + ) + external + view + returns (uint16 currentPhaseId); + + function getFeed(address base, address quote) external view returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IPhaseAggregator.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IPhaseAggregator.sol new file mode 100644 index 0000000..1a4f7bc --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IPhaseAggregator.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IPhaseAggregator { + function latestRoundData() + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICToken.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICToken.sol new file mode 100644 index 0000000..3bac54c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICToken.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +import "../IERC20.sol"; + +abstract contract ICToken is IERC20 { + function mint(uint256 mintAmount) external virtual returns (uint256); + function mint() external payable virtual; + + function accrueInterest() public virtual returns (uint256); + + function redeem(uint256 redeemTokens) external virtual returns (uint256); + + function redeemUnderlying(uint256 redeemAmount) external virtual returns (uint256); + + function borrow(uint256 borrowAmount) external virtual returns (uint256); + function borrowIndex() public view virtual returns (uint256); + function borrowBalanceStored(address) public view virtual returns (uint256); + + function repayBorrow(uint256 repayAmount) external virtual returns (uint256); + + function repayBorrow() external payable virtual; + + function repayBorrowBehalf( + address borrower, + uint256 repayAmount + ) + external + virtual + returns (uint256); + + function repayBorrowBehalf(address borrower) external payable virtual; + + function liquidateBorrow( + address borrower, + uint256 repayAmount, + address cTokenCollateral + ) + external + virtual + returns (uint256); + + function liquidateBorrow(address borrower, address cTokenCollateral) external payable virtual; + + function exchangeRateCurrent() external virtual returns (uint256); + + function supplyRatePerBlock() external virtual returns (uint256); + + function borrowRatePerBlock() external virtual returns (uint256); + + function totalReserves() external virtual returns (uint256); + + function reserveFactorMantissa() external virtual returns (uint256); + + function borrowBalanceCurrent(address account) external virtual returns (uint256); + + function totalBorrowsCurrent() external virtual returns (uint256); + + function getCash() external virtual returns (uint256); + + function balanceOfUnderlying(address owner) external virtual returns (uint256); + + function underlying() external virtual returns (address); + + function getAccountSnapshot(address account) + external + view + virtual + returns (uint256, uint256, uint256, uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICompoundOracle.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICompoundOracle.sol new file mode 100644 index 0000000..c7fa324 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICompoundOracle.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract ICompoundOracle { + function getUnderlyingPrice(address cToken) external view virtual returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/IComptroller.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/IComptroller.sol new file mode 100644 index 0000000..a6f4699 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/IComptroller.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IComptroller { + struct CompMarketState { + uint224 index; + uint32 block; + } + + mapping(address => uint256) public compSpeeds; + + mapping(address => uint256) public borrowCaps; + + mapping(address => uint256) public compBorrowSpeeds; + mapping(address => uint256) public compSupplySpeeds; + + function claimComp(address holder) public virtual; + function claimComp(address holder, address[] memory cTokens) public virtual; + function claimComp( + address[] memory holders, + address[] memory cTokens, + bool borrowers, + bool suppliers + ) + public + virtual; + + function compSupplyState(address) public view virtual returns (CompMarketState memory); + function compSupplierIndex(address, address) public view virtual returns (uint256); + function compAccrued(address) public view virtual returns (uint256); + + function compBorrowState(address) public view virtual returns (CompMarketState memory); + function compBorrowerIndex(address, address) public view virtual returns (uint256); + + function enterMarkets(address[] calldata cTokens) external virtual returns (uint256[] memory); + + function exitMarket(address cToken) external virtual returns (uint256); + + function getAssetsIn(address account) external view virtual returns (address[] memory); + + function markets(address account) public view virtual returns (bool, uint256); + + function getAccountLiquidity(address account) + external + view + virtual + returns (uint256, uint256, uint256); + + function oracle() public view virtual returns (address); + + function mintGuardianPaused(address cToken) external view virtual returns (bool); + function borrowGuardianPaused(address cToken) external view virtual returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/IComet.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/IComet.sol new file mode 100644 index 0000000..ab3c471 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/IComet.sol @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IComet { + struct AssetInfo { + uint8 offset; + address asset; + address priceFeed; + uint64 scale; + uint64 borrowCollateralFactor; + uint64 liquidateCollateralFactor; + uint64 liquidationFactor; + uint128 supplyCap; + } + + struct TotalsCollateral { + uint128 totalSupplyAsset; + uint128 _reserved; + } + + struct UserCollateral { + uint128 balance; + uint128 _reserved; + } + + struct UserBasic { + int104 principal; + uint64 baseTrackingIndex; + uint64 baseTrackingAccrued; + uint16 assetsIn; + uint8 _reserved; + } + + struct TotalsBasic { + uint64 baseSupplyIndex; + uint64 baseBorrowIndex; + uint64 trackingSupplyIndex; + uint64 trackingBorrowIndex; + uint104 totalSupplyBase; + uint104 totalBorrowBase; + uint40 lastAccrualTime; + uint8 pauseFlags; + } + + function totalsBasic() public view virtual returns (TotalsBasic memory); + + function totalsCollateral(address) public virtual returns (TotalsCollateral memory); + + function supply(address asset, uint256 amount) external virtual; + function supplyTo(address dst, address asset, uint256 amount) external virtual; + function supplyFrom( + address from, + address dst, + address asset, + uint256 amount + ) + external + virtual; + + function transfer(address dst, uint256 amount) external virtual returns (bool); + function transferFrom( + address src, + address dst, + uint256 amount + ) + external + virtual + returns (bool); + + function transferAsset(address dst, address asset, uint256 amount) external virtual; + function transferAssetFrom( + address src, + address dst, + address asset, + uint256 amount + ) + external + virtual; + + function withdraw(address asset, uint256 amount) external virtual; + function withdrawTo(address to, address asset, uint256 amount) external virtual; + function withdrawFrom( + address src, + address to, + address asset, + uint256 amount + ) + external + virtual; + + function accrueAccount(address account) external virtual; + function getSupplyRate(uint256 utilization) public view virtual returns (uint64); + function getBorrowRate(uint256 utilization) public view virtual returns (uint64); + function getUtilization() public view virtual returns (uint256); + + function governor() external view virtual returns (address); + function baseToken() external view virtual returns (address); + function baseTokenPriceFeed() external view virtual returns (address); + + function balanceOf(address account) public view virtual returns (uint256); + function collateralBalanceOf( + address account, + address asset + ) + external + view + virtual + returns (uint128); + function borrowBalanceOf(address account) public view virtual returns (uint256); + function totalSupply() external view virtual returns (uint256); + + function numAssets() public view virtual returns (uint8); + function getAssetInfo(uint8 i) public view virtual returns (AssetInfo memory); + function getAssetInfoByAddress(address asset) public view virtual returns (AssetInfo memory); + function getPrice(address priceFeed) public view virtual returns (uint256); + + function allow(address manager, bool isAllowed) external virtual; + function allowance(address owner, address spender) external view virtual returns (uint256); + + function isSupplyPaused() external view virtual returns (bool); + function isTransferPaused() external view virtual returns (bool); + function isWithdrawPaused() external view virtual returns (bool); + function isAbsorbPaused() external view virtual returns (bool); + function baseIndexScale() external pure virtual returns (uint64); + + function userBasic(address) external view virtual returns (UserBasic memory); + function userCollateral( + address, + address + ) + external + view + virtual + returns (UserCollateral memory); + function priceScale() external pure virtual returns (uint64); + function factorScale() external pure virtual returns (uint64); + + function baseBorrowMin() external pure virtual returns (uint256); + function baseTrackingBorrowSpeed() external pure virtual returns (uint256); + function baseTrackingSupplySpeed() external pure virtual returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometExt.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometExt.sol new file mode 100644 index 0000000..7263313 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometExt.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract ICometExt { + function allow(address manager, bool isAllowed) external virtual; + function collateralBalanceOf( + address account, + address asset + ) + external + view + virtual + returns (uint128); + function allowance(address owner, address spender) external view virtual returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometRewards.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometRewards.sol new file mode 100644 index 0000000..dc71e95 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometRewards.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract ICometRewards { + struct RewardConfig { + address token; + uint64 rescaleFactor; + bool shouldUpscale; + } + + struct RewardOwed { + address token; + uint256 owed; + } + + function rewardConfig(address) external virtual returns (RewardConfig memory); + + function claimTo(address comet, address src, address to, bool shouldAccrue) external virtual; + + function rewardsClaimed( + address _market, + address _user + ) + external + view + virtual + returns (uint256); + function getRewardOwed( + address _market, + address _user + ) + external + virtual + returns (RewardOwed memory); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBaseRewardPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBaseRewardPool.sol new file mode 100644 index 0000000..842762a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBaseRewardPool.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: SEE LICENSE IN LICENSE +pragma solidity ^0.8.10; + +interface IBaseRewardPool { + function extraRewardsLength() external view returns (uint256); + function extraRewards(uint256) external view returns (address); + + function earned(address) external view returns (uint256); + function balanceOf(address) external view returns (uint256); + + function getReward(address, bool) external returns (bool); + function stakeFor(address, uint256) external; + + function withdraw(uint256, bool) external returns (bool); + function withdrawAndUnwrap(uint256, bool) external returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBooster.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBooster.sol new file mode 100644 index 0000000..c6811df --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBooster.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: SEE LICENSE IN LICENSE +pragma solidity ^0.8.10; + +interface IBooster { + struct PoolInfo { + address lpToken; + address token; + address gauge; + address crvRewards; + address stash; + bool shutdown; + } + + function poolInfo(uint256) external view returns (PoolInfo memory); + function deposit(uint256, uint256, bool) external returns (bool); + function withdraw(uint256, uint256) external returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IConvexToken.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IConvexToken.sol new file mode 100644 index 0000000..982c5ce --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IConvexToken.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +import "../../interfaces/IERC20.sol"; + +interface IConvexToken is IERC20 { + function reductionPerCliff() external view returns (uint256); + function totalCliffs() external view returns (uint256); + function maxSupply() external view returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IRewardPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IRewardPool.sol new file mode 100644 index 0000000..023e762 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IRewardPool.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IRewardPool { + function rewardToken() external view returns (address); + function earned(address) external view returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IAddressProvider.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IAddressProvider.sol new file mode 100644 index 0000000..91aee49 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IAddressProvider.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; +pragma experimental ABIEncoderV2; + +interface IAddressProvider { + function admin() external view returns (address); + function get_registry() external view returns (address); + function get_address(uint256 _id) external view returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurve3PoolZap.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurve3PoolZap.sol new file mode 100644 index 0000000..87a6110 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurve3PoolZap.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface ICurve3PoolZap { + function add_liquidity(address, uint256[4] memory, uint256) external; + function remove_liquidity(address, uint256, uint256[4] memory) external; + function remove_liquidity_one_coin(address, uint256, int128, uint256) external; + function remove_liquidity_imbalance(address, uint256[4] memory, uint256) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurveFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurveFactory.sol new file mode 100644 index 0000000..ce5f462 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurveFactory.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface ICurveFactoryLP { + function minter() external view returns (address); + function name() external view returns (string memory); +} + +interface ICurveFactoryPool { + function token() external view returns (address); + function factory() external view returns (address); + function get_virtual_price() external view returns (uint256); +} + +interface ICurveFactory { + function get_coins(address) external view returns (address[2] memory); + function get_decimals(address) external view returns (uint256[2] memory); + function get_balances(address) external view returns (uint256[2] memory); + function get_gauge(address) external view returns (address); +} + +interface IGaugeController { + function gauge_types(address) external view returns (int128); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IDepositZap.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IDepositZap.sol new file mode 100644 index 0000000..cce1e91 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IDepositZap.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IDepositZap { + function pool() external view returns (address); + function curve() external view returns (address); + function token() external view returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IFeeDistributor.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IFeeDistributor.sol new file mode 100644 index 0000000..89fe0c3 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IFeeDistributor.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; +pragma experimental ABIEncoderV2; + +interface IFeeDistributor { + function claim(address) external returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ILiquidityGauge.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ILiquidityGauge.sol new file mode 100644 index 0000000..6f72113 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ILiquidityGauge.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; +pragma experimental ABIEncoderV2; + +interface ILiquidityGauge { + function lp_token() external view returns (address); + function balanceOf(address) external view returns (uint256); + + function deposit(uint256 _amount, address _receiver) external; + function approved_to_deposit( + address _depositor, + address _recipient + ) + external + view + returns (bool); + function set_approve_deposit(address _depositor, bool _canDeposit) external; + + function withdraw(uint256 _amount) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IMinter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IMinter.sol new file mode 100644 index 0000000..5dd0196 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IMinter.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; +pragma experimental ABIEncoderV2; + +interface IMinter { + function mint(address _gaugeAddr) external; + function mint_many(address[8] memory _gaugeAddrs) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IRegistry.sol new file mode 100644 index 0000000..656efa3 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IRegistry.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IRegistry { + function get_lp_token(address) external view returns (address); + function get_pool_from_lp_token(address) external view returns (address); + function get_pool_name(address) external view returns (string memory); + function get_coins(address) external view returns (address[8] memory); + function get_n_coins(address) external view returns (uint256[2] memory); + function get_underlying_coins(address) external view returns (address[8] memory); + function get_decimals(address) external view returns (uint256[8] memory); + function get_underlying_decimals(address) external view returns (uint256[8] memory); + function get_balances(address) external view returns (uint256[8] memory); + function get_underlying_balances(address) external view returns (uint256[8] memory); + function get_virtual_price_from_lp_token(address) external view returns (uint256); + function get_gauges(address) external view returns (address[10] memory, int128[10] memory); + function pool_count() external view returns (uint256); + function pool_list(uint256) external view returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ISwaps.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ISwaps.sol new file mode 100644 index 0000000..f04a43a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ISwaps.sol @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; +pragma experimental ABIEncoderV2; + +interface ISwaps { + ///@notice Perform an exchange using the pool that offers the best rate + ///@dev Prior to calling this function, the caller must approve + /// this contract to transfer `_amount` coins from `_from` + /// Does NOT check rates in factory-deployed pools + ///@param _from Address of coin being sent + ///@param _to Address of coin being received + ///@param _amount Quantity of `_from` being sent + ///@param _expected Minimum quantity of `_from` received + /// in order for the transaction to succeed + ///@param _receiver Address to transfer the received tokens to + ///@return uint256 Amount received + function exchange_with_best_rate( + address _from, + address _to, + uint256 _amount, + uint256 _expected, + address _receiver + ) + external + payable + returns (uint256); + + ///@notice Perform an exchange using a specific pool + ///@dev Prior to calling this function, the caller must approve + /// this contract to transfer `_amount` coins from `_from` + /// Works for both regular and factory-deployed pools + ///@param _pool Address of the pool to use for the swap + ///@param _from Address of coin being sent + ///@param _to Address of coin being received + ///@param _amount Quantity of `_from` being sent + ///@param _expected Minimum quantity of `_from` received + /// in order for the transaction to succeed + ///@param _receiver Address to transfer the received tokens to + ///@return uint256 Amount received + function exchange( + address _pool, + address _from, + address _to, + uint256 _amount, + uint256 _expected, + address _receiver + ) + external + payable + returns (uint256); + + ///@notice Find the pool offering the best rate for a given swap. + ///@dev Checks rates for regular and factory pools + ///@param _from Address of coin being sent + ///@param _to Address of coin being received + ///@param _amount Quantity of `_from` being sent + ///@param _exclude_pools A list of up to 8 addresses which shouldn't be returned + ///@return Pool address, amount received + function get_best_rate( + address _from, + address _to, + uint256 _amount, + address[8] memory _exclude_pools + ) + external + view + returns (address, uint256); + + ///@notice Get the current number of coins received in an exchange + ///@dev Works for both regular and factory-deployed pools + ///@param _pool Pool address + ///@param _from Address of coin to be sent + ///@param _to Address of coin to be received + ///@param _amount Quantity of `_from` to be sent + ///@return Quantity of `_to` to be received + function get_exchange_amount( + address _pool, + address _from, + address _to, + uint256 _amount + ) + external + view + returns (uint256); + + ///@notice Get the current number of coins required to receive the given amount in an exchange + ///@param _pool Pool address + ///@param _from Address of coin to be sent + ///@param _to Address of coin to be received + ///@param _amount Quantity of `_to` to be received + ///@return Quantity of `_from` to be sent + function get_input_amount( + address _pool, + address _from, + address _to, + uint256 _amount + ) + external + view + returns (uint256); + + ///@notice Get the current number of coins required to receive the given amount in an exchange + ///@param _pool Pool address + ///@param _from Address of coin to be sent + ///@param _to Address of coin to be received + ///@param _amounts Quantity of `_to` to be received + ///@return Quantity of `_from` to be sent + function get_exchange_amounts( + address _pool, + address _from, + address _to, + uint256[] memory _amounts + ) + external + view + returns (uint256[] memory); + + ///@notice Set calculator contract + ///@dev Used to calculate `get_dy` for a pool + ///@param _pool Pool address + ///@return `CurveCalc` address + function get_calculator(address _pool) external view returns (address); + + /// @notice Perform up to four swaps in a single transaction + /// @dev Routing and swap params must be determined off-chain. This + /// functionality is designed for gas efficiency over ease-of-use. + /// @param _route Array of [initial token, pool, token, pool, token, ...] + /// The array is iterated until a pool address of 0x00, then the last + /// given token is transferred to `_receiver` + /// @param _swap_params Multidimensional array of [i, j, swap type] where i and j are the + /// correct + /// values for the n'th pool in `_route`. The swap type should be 1 for + /// a stableswap `exchange`, 2 for stableswap `exchange_underlying`, 3 + /// for a cryptoswap `exchange`, 4 for a cryptoswap `exchange_underlying`, + /// 5 for Polygon factory metapools `exchange_underlying`, 6-8 for + /// underlying coin -> LP token "exchange" (actually `add_liquidity`), 9 and 10 + /// for LP token -> underlying coin "exchange" (actually `remove_liquidity_one_coin`) + /// @param _amount The amount of `_route[0]` token being sent. + /// @param _expected The minimum amount received after the final swap. + /// @param _pools Array of pools for swaps via zap contracts. This parameter is only needed for + /// Polygon meta-factories underlying swaps. + /// @param _receiver Address to transfer the final output token to. + /// @return Received amount of the final output token + function exchange_multiple( + address[9] memory _route, + uint256[3][4] memory _swap_params, + uint256 _amount, + uint256 _expected, + address[4] memory _pools, + address _receiver + ) + external + payable + returns (uint256); + + function exchange_multiple( + address[9] memory _route, + uint256[3][4] memory _swap_params, + uint256 _amount, + uint256 _expected + ) + external + payable + returns (uint256); + + function get_exchange_multiple_amount( + address[9] memory _route, + uint256[3][4] memory _swap_params, + uint256 _amount + ) + external + view + returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IVotingEscrow.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IVotingEscrow.sol new file mode 100644 index 0000000..b46d15e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IVotingEscrow.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; +pragma experimental ABIEncoderV2; + +interface IVotingEscrow { + function create_lock(uint256 _amount, uint256 _unlockTime) external; + function increase_amount(uint256 _amount) external; + function increase_unlock_time(uint256 _unlockTime) external; + function withdraw() external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/stethPool/ICurveStethPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/stethPool/ICurveStethPool.sol new file mode 100644 index 0000000..92fcabd --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/stethPool/ICurveStethPool.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface ICurveStethPool { + function add_liquidity(uint256[2] memory, uint256) external payable returns (uint256); + function remove_liquidity(uint256, uint256[2] memory) external returns (uint256[2] memory); + function remove_liquidity_imbalance(uint256[2] memory, uint256) external returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curveusd/ICurveUsd.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curveusd/ICurveUsd.sol new file mode 100644 index 0000000..cf8564a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curveusd/ICurveUsd.sol @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface ICrvUsdController { + function create_loan( + uint256 _collateralAmount, + uint256 _debtAmount, + uint256 _nBands + ) + external + payable; + function create_loan_extended( + uint256 _collateralAmount, + uint256 _debtAmount, + uint256 _nBands, + address _callbacker, + uint256[] memory _callbackArgs + ) + external + payable; + + /// @dev all functions below: if _collateralAmount is 0 will just return + function add_collateral(uint256 _collateralAmount) external payable; + function add_collateral(uint256 _collateralAmount, address _for) external payable; + + function remove_collateral(uint256 _collateralAmount) external; + /// @param _useEth relevant only for ETH collateral pools (currently not deployed) + function remove_collateral(uint256 _collateralAmount, bool _useEth) external; + + /// @dev all functions below: if _debtAmount is 0 will just return + function borrow_more(uint256 _collateralAmount, uint256 _debtAmount) external payable; + + /// @dev if _debtAmount > debt will do full repay + function repay(uint256 _debtAmount) external payable; + function repay(uint256 _debtAmount, address _for) external payable; + /// @param _maxActiveBand Don't allow active band to be higher than this (to prevent + /// front-running the repay) + function repay(uint256 _debtAmount, address _for, int256 _maxActiveBand) external payable; + function repay( + uint256 _debtAmount, + address _for, + int256 _maxActiveBand, + bool _useEth + ) + external + payable; + function repay_extended(address _callbacker, uint256[] memory _callbackArgs) external; + + function liquidate(address user, uint256 min_x) external; + function liquidate(address user, uint256 min_x, bool _useEth) external; + function liquidate_extended( + address user, + uint256 min_x, + uint256 frac, + bool use_eth, + address callbacker, + uint256[] memory _callbackArgs + ) + external; + + /// GETTERS + function amm() external view returns (address); + function monetary_policy() external view returns (address); + function collateral_token() external view returns (address); + function debt(address) external view returns (uint256); + function total_debt() external view returns (uint256); + function health_calculator( + address, + int256, + int256, + bool, + uint256 + ) + external + view + returns (int256); + function health_calculator(address, int256, int256, bool) external view returns (int256); + function health(address) external view returns (int256); + function health(address, bool) external view returns (int256); + function max_borrowable( + uint256 collateralAmount, + uint256 nBands + ) + external + view + returns (uint256); + function min_collateral(uint256 debtAmount, uint256 nBands) external view returns (uint256); + function calculate_debt_n1(uint256, uint256, uint256) external view returns (int256); + function minted() external view returns (uint256); + function redeemed() external view returns (uint256); + function amm_price() external view returns (uint256); + function user_state(address) external view returns (uint256[4] memory); + function user_prices(address) external view returns (uint256[2] memory); + function loan_exists(address) external view returns (bool); + function liquidation_discount() external view returns (uint256); +} + +interface ICrvUsdControllerFactory { + function get_controller(address) external view returns (address); + function debt_ceiling(address) external view returns (uint256); +} + +interface ILLAMMA { + function active_band_with_skip() external view returns (int256); + function get_sum_xy(address) external view returns (uint256[2] memory); + function get_xy(address) external view returns (uint256[][2] memory); + function get_p() external view returns (uint256); + function read_user_tick_numbers(address) external view returns (int256[2] memory); + function p_oracle_up(int256) external view returns (uint256); + function p_oracle_down(int256) external view returns (uint256); + function p_current_up(int256) external view returns (uint256); + function p_current_down(int256) external view returns (uint256); + function bands_x(int256) external view returns (uint256); + function bands_y(int256) external view returns (uint256); + function get_base_price() external view returns (uint256); + function price_oracle() external view returns (uint256); + function active_band() external view returns (int256); + function A() external view returns (uint256); + function min_band() external view returns (int256); + function max_band() external view returns (int256); + function rate() external view returns (uint256); + function exchange( + uint256 i, + uint256 j, + uint256 in_amount, + uint256 min_amount + ) + external + returns (uint256[2] memory); + function coins(uint256 i) external view returns (address); + function user_state(address _user) external view returns (uint256[4] memory); +} + +interface IAGG { + function rate() external view returns (uint256); + function rate0() external view returns (uint256); + function target_debt_fraction() external view returns (uint256); + function sigma() external view returns (int256); + function peg_keepers(uint256) external view returns (address); +} + +interface IPegKeeper { + function debt() external view returns (uint256); +} + +interface ICurveUsdSwapper { + function encodeSwapParams( + uint256[3][4] memory swapParams, + uint32 gasUsed, + uint32 dfsFeeDivider, + uint8 useSteth + ) + external + pure + returns (uint256 encoded); + function setAdditionalRoutes(address[6] memory _additionalRoutes) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/dydx/ISoloMargin.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/dydx/ISoloMargin.sol new file mode 100644 index 0000000..f0eab06 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/dydx/ISoloMargin.sol @@ -0,0 +1,463 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.10; + +library Account { + enum Status { + Normal, + Liquid, + Vapor + } + + struct Info { + address owner; // The address that owns the account + uint256 number; // A nonce that allows a single address to control many accounts + } + + struct Storage { + mapping(uint256 => Types.Par) balances; // Mapping from marketId to principal + Status status; + } +} + +library Actions { + enum ActionType { + Deposit, // supply tokens + Withdraw, // borrow tokens + Transfer, // transfer balance between accounts + Buy, // buy an amount of some token (public virtually) + Sell, // sell an amount of some token (public virtually) + Trade, // trade tokens against another account + Liquidate, // liquidate an undercollateralized or expiring account + Vaporize, // use excess tokens to zero-out a completely negative account + Call // send arbitrary data to an address + + } + + enum AccountLayout { + OnePrimary, + TwoPrimary, + PrimaryAndSecondary + } + + enum MarketLayout { + ZeroMarkets, + OneMarket, + TwoMarkets + } + + struct ActionArgs { + ActionType actionType; + uint256 accountId; + Types.AssetAmount amount; + uint256 primaryMarketId; + uint256 secondaryMarketId; + address otherAddress; + uint256 otherAccountId; + bytes data; + } + + struct DepositArgs { + Types.AssetAmount amount; + Account.Info account; + uint256 market; + address from; + } + + struct WithdrawArgs { + Types.AssetAmount amount; + Account.Info account; + uint256 market; + address to; + } + + struct TransferArgs { + Types.AssetAmount amount; + Account.Info accountOne; + Account.Info accountTwo; + uint256 market; + } + + struct BuyArgs { + Types.AssetAmount amount; + Account.Info account; + uint256 makerMarket; + uint256 takerMarket; + address exchangeWrapper; + bytes orderData; + } + + struct SellArgs { + Types.AssetAmount amount; + Account.Info account; + uint256 takerMarket; + uint256 makerMarket; + address exchangeWrapper; + bytes orderData; + } + + struct TradeArgs { + Types.AssetAmount amount; + Account.Info takerAccount; + Account.Info makerAccount; + uint256 inputMarket; + uint256 outputMarket; + address autoTrader; + bytes tradeData; + } + + struct LiquidateArgs { + Types.AssetAmount amount; + Account.Info solidAccount; + Account.Info liquidAccount; + uint256 owedMarket; + uint256 heldMarket; + } + + struct VaporizeArgs { + Types.AssetAmount amount; + Account.Info solidAccount; + Account.Info vaporAccount; + uint256 owedMarket; + uint256 heldMarket; + } + + struct CallArgs { + Account.Info account; + address callee; + bytes data; + } +} + +library Decimal { + struct D256 { + uint256 value; + } +} + +library Interest { + struct Rate { + uint256 value; + } + + struct Index { + uint96 borrow; + uint96 supply; + uint32 lastUpdate; + } +} + +library Monetary { + struct Price { + uint256 value; + } + + struct Value { + uint256 value; + } +} + +library Storage { + // All information necessary for tracking a market + struct Market { + // Contract address of the associated ERC20 token + address token; + // Total aggregated supply and borrow amount of the entire market + Types.TotalPar totalPar; + // Interest index of the market + Interest.Index index; + // Contract address of the price oracle for this market + address priceOracle; + // Contract address of the interest setter for this market + address interestSetter; + // Multiplier on the marginRatio for this market + Decimal.D256 marginPremium; + // Multiplier on the liquidationSpread for this market + Decimal.D256 spreadPremium; + // Whether additional borrows are allowed for this market + bool isClosing; + } + + // The global risk parameters that govern the health and security of the system + struct RiskParams { + // Required ratio of over-collateralization + Decimal.D256 marginRatio; + // Percentage penalty incurred by liquidated accounts + Decimal.D256 liquidationSpread; + // Percentage of the borrower's interest fee that gets passed to the suppliers + Decimal.D256 earningsRate; + // The minimum absolute borrow value of an account + // There must be sufficient incentivize to liquidate undercollateralized accounts + Monetary.Value minBorrowedValue; + } + + // The maximum RiskParam values that can be set + struct RiskLimits { + uint64 marginRatioMax; + uint64 liquidationSpreadMax; + uint64 earningsRateMax; + uint64 marginPremiumMax; + uint64 spreadPremiumMax; + uint128 minBorrowedValueMax; + } + + // The entire storage state of Solo + struct State { + // number of markets + uint256 numMarkets; + // marketId => Market + mapping(uint256 => Market) markets; + // owner => account number => Account + mapping(address => mapping(uint256 => Account.Storage)) accounts; + // Addresses that can control other users accounts + mapping(address => mapping(address => bool)) operators; + // Addresses that can control all users accounts + mapping(address => bool) globalOperators; + // mutable risk parameters of the system + RiskParams riskParams; + // immutable risk limits of the system + RiskLimits riskLimits; + } +} + +library Types { + enum AssetDenomination { + Wei, // the amount is denominated in wei + Par // the amount is denominated in par + + } + + enum AssetReference { + Delta, // the amount is given as a delta from the current value + Target // the amount is given as an exact number to end up at + + } + + struct AssetAmount { + bool sign; // true if positive + AssetDenomination denomination; + AssetReference ref; + uint256 value; + } + + struct TotalPar { + uint128 borrow; + uint128 supply; + } + + struct Par { + bool sign; // true if positive + uint128 value; + } + + struct Wei { + bool sign; // true if positive + uint256 value; + } +} + +abstract contract ISoloMargin { + struct OperatorArg { + address operator; + bool trusted; + } + + function ownerSetSpreadPremium( + uint256 marketId, + Decimal.D256 memory spreadPremium + ) + public + virtual; + + function getIsGlobalOperator(address operator) public view virtual returns (bool); + + function getMarketTokenAddress(uint256 marketId) public view virtual returns (address); + + function ownerSetInterestSetter(uint256 marketId, address interestSetter) public virtual; + + function getAccountValues(Account.Info memory account) + public + view + virtual + returns (Monetary.Value memory, Monetary.Value memory); + + function getMarketPriceOracle(uint256 marketId) public view virtual returns (address); + + function getMarketInterestSetter(uint256 marketId) public view virtual returns (address); + + function getMarketSpreadPremium(uint256 marketId) + public + view + virtual + returns (Decimal.D256 memory); + + function getNumMarkets() public view virtual returns (uint256); + + function ownerWithdrawUnsupportedTokens( + address token, + address recipient + ) + public + virtual + returns (uint256); + + function ownerSetMinBorrowedValue(Monetary.Value memory minBorrowedValue) public virtual; + + function ownerSetLiquidationSpread(Decimal.D256 memory spread) public virtual; + + function ownerSetEarningsRate(Decimal.D256 memory earningsRate) public virtual; + + function getIsLocalOperator(address, address) public view virtual returns (bool); + + function getAccountPar( + Account.Info memory account, + uint256 marketId + ) + public + view + virtual + returns (Types.Par memory); + + function ownerSetMarginPremium( + uint256 marketId, + Decimal.D256 memory marginPremium + ) + public + virtual; + + function getMarginRatio() public view virtual returns (Decimal.D256 memory); + + function getMarketCurrentIndex(uint256 marketId) + public + view + virtual + returns (Interest.Index memory); + + function getMarketIsClosing(uint256 marketId) public view virtual returns (bool); + + function getRiskParams() public view virtual returns (Storage.RiskParams memory); + + function getAccountBalances(Account.Info memory account) + public + view + virtual + returns (address[] memory, Types.Par[] memory, Types.Wei[] memory); + + function renounceOwnership() public virtual; + + function getMinBorrowedValue() public view virtual returns (Monetary.Value memory); + + function setOperators(OperatorArg[] memory args) public virtual; + + function getMarketPrice(uint256 marketId) public view virtual returns (address); + + function owner() public view virtual returns (address); + + function isOwner() public view virtual returns (bool); + + function ownerWithdrawExcessTokens( + uint256 marketId, + address recipient + ) + public + virtual + returns (uint256); + + function ownerAddMarket( + address token, + address priceOracle, + address interestSetter, + Decimal.D256 memory marginPremium, + Decimal.D256 memory spreadPremium + ) + public + virtual; + + function operate( + Account.Info[] memory accounts, + Actions.ActionArgs[] memory actions + ) + public + virtual; + + function getMarketWithInfo(uint256 marketId) + public + view + virtual + returns ( + Storage.Market memory, + Interest.Index memory, + Monetary.Price memory, + Interest.Rate memory + ); + + function ownerSetMarginRatio(Decimal.D256 memory ratio) public virtual; + + function getLiquidationSpread() public view virtual returns (Decimal.D256 memory); + + function getAccountWei( + Account.Info memory account, + uint256 marketId + ) + public + view + virtual + returns (Types.Wei memory); + + function getMarketTotalPar(uint256 marketId) + public + view + virtual + returns (Types.TotalPar memory); + + function getLiquidationSpreadForPair( + uint256 heldMarketId, + uint256 owedMarketId + ) + public + view + virtual + returns (Decimal.D256 memory); + + function getNumExcessTokens(uint256 marketId) public view virtual returns (Types.Wei memory); + + function getMarketCachedIndex(uint256 marketId) + public + view + virtual + returns (Interest.Index memory); + + function getAccountStatus(Account.Info memory account) public view virtual returns (uint8); + + function getEarningsRate() public view virtual returns (Decimal.D256 memory); + + function ownerSetPriceOracle(uint256 marketId, address priceOracle) public virtual; + + function getRiskLimits() public view virtual returns (Storage.RiskLimits memory); + + function getMarket(uint256 marketId) public view virtual returns (Storage.Market memory); + + function ownerSetIsClosing(uint256 marketId, bool isClosing) public virtual; + + function ownerSetGlobalOperator(address operator, bool approved) public virtual; + + function transferOwnership(address newOwner) public virtual; + + function getAdjustedAccountValues(Account.Info memory account) + public + view + virtual + returns (Monetary.Value memory, Monetary.Value memory); + + function getMarketMarginPremium(uint256 marketId) + public + view + virtual + returns (Decimal.D256 memory); + + function getMarketInterestRate(uint256 marketId) + public + view + virtual + returns (Interest.Rate memory); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IDToken.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IDToken.sol new file mode 100644 index 0000000..9002e84 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IDToken.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IDToken { + function flashLoan(uint256 amount, bytes calldata data) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IEulerMarkets.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IEulerMarkets.sol new file mode 100644 index 0000000..dc22050 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IEulerMarkets.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IEulerMarkets { + function underlyingToDToken(address underlying) external view returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeV3.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeV3.sol new file mode 100644 index 0000000..a355aee --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeV3.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface IExchangeV3 { + function sell( + address _srcAddr, + address _destAddr, + uint256 _srcAmount, + bytes memory _additionalData + ) + external + returns (uint256); + + function buy( + address _srcAddr, + address _destAddr, + uint256 _destAmount, + bytes memory _additionalData + ) + external + returns (uint256); + + function getSellRate( + address _srcAddr, + address _destAddr, + uint256 _srcAmount, + bytes memory _additionalData + ) + external + returns (uint256); + + function getBuyRate( + address _srcAddr, + address _destAddr, + uint256 _srcAmount, + bytes memory _additionalData + ) + external + returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeWrapper.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeWrapper.sol new file mode 100644 index 0000000..cfa9538 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeWrapper.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface IExchangeWrapper { + function sell( + address _srcAddr, + address _destAddr, + uint256 _srcAmount, + bytes memory _additionalData + ) + external + payable + returns (uint256); + + function buy( + address _srcAddr, + address _destAddr, + uint256 _destAmount, + bytes memory _additionalData + ) + external + payable + returns (uint256); + + function getSellRate( + address _srcAddr, + address _destAddr, + uint256 _srcAmount, + bytes memory _additionalData + ) + external + view + returns (uint256); + + function getBuyRate( + address _srcAddr, + address _destAddr, + uint256 _srcAmount, + bytes memory _additionalData + ) + external + view + returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IKyberNetworkProxy.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IKyberNetworkProxy.sol new file mode 100644 index 0000000..385f8a6 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IKyberNetworkProxy.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +import "../IERC20.sol"; + +abstract contract KyberNetworkProxyInterface { + function maxGasPrice() external view virtual returns (uint256); + + function getUserCapInWei(address user) external view virtual returns (uint256); + + function getUserCapInTokenWei( + address user, + IERC20 token + ) + external + view + virtual + returns (uint256); + + function enabled() external view virtual returns (bool); + + function info(bytes32 id) external view virtual returns (uint256); + + function getExpectedRate( + IERC20 src, + IERC20 dest, + uint256 srcQty + ) + public + view + virtual + returns (uint256 expectedRate, uint256 slippageRate); + + function tradeWithHint( + IERC20 src, + uint256 srcAmount, + IERC20 dest, + address destAddress, + uint256 maxDestAmount, + uint256 minConversionRate, + address walletId, + bytes memory hint + ) + public + payable + virtual + returns (uint256); + + function trade( + IERC20 src, + uint256 srcAmount, + IERC20 dest, + address destAddress, + uint256 maxDestAmount, + uint256 minConversionRate, + address walletId + ) + public + payable + virtual + returns (uint256); + + function swapEtherToToken( + IERC20 token, + uint256 minConversionRate + ) + external + payable + virtual + returns (uint256); + + function swapTokenToEther( + IERC20 token, + uint256 tokenQty, + uint256 minRate + ) + external + payable + virtual + returns (uint256); + + function swapTokenToToken( + IERC20 src, + uint256 srcAmount, + IERC20 dest, + uint256 minConversionRate + ) + public + virtual + returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOasis.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOasis.sol new file mode 100644 index 0000000..e96ee2a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOasis.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IOasis { + function getBuyAmount( + address tokenToBuy, + address tokenToPay, + uint256 amountToPay + ) + external + view + virtual + returns (uint256 amountBought); + + function getPayAmount( + address tokenToPay, + address tokenToBuy, + uint256 amountToBuy + ) + public + view + virtual + returns (uint256 amountPaid); + + function sellAllAmount( + address pay_gem, + uint256 pay_amt, + address buy_gem, + uint256 min_fill_amount + ) + public + virtual + returns (uint256 fill_amt); + + function buyAllAmount( + address buy_gem, + uint256 buy_amt, + address pay_gem, + uint256 max_fill_amount + ) + public + virtual + returns (uint256 fill_amt); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOffchainWrapper.sol.bak b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOffchainWrapper.sol.bak new file mode 100644 index 0000000..c23b913 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOffchainWrapper.sol.bak @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +import "../../exchangeV3/DFSExchangeData.sol"; + +abstract contract IOffchainWrapper is DFSExchangeData { + function takeOrder( + ExchangeData memory _exData, + ExchangeActionType _type + ) + public + payable + virtual + returns (bool success, uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IPair.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IPair.sol new file mode 100644 index 0000000..ca0102b --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IPair.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +import "../IERC20.sol"; + +abstract contract IPair is IERC20 { + function token0() external view virtual returns (address); + function token1() external view virtual returns (address); + function getReserves() + external + view + virtual + returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); + function price0CumulativeLast() external view virtual returns (uint256); + function price1CumulativeLast() external view virtual returns (uint256); + function kLast() external view virtual returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IQuoter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IQuoter.sol new file mode 100644 index 0000000..a559f3c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IQuoter.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.10; + +/// @title Quoter Interface +/// @notice Supports quoting the calculated amounts from exact input or exact output swaps +/// @dev These functions are not marked view because they rely on calling non-view functions and +/// reverting +/// to compute the result. They are also not gas efficient and should not be called on-chain. +interface IQuoter { + /// @notice Returns the amount out received for a given exact input swap without executing the + /// swap + /// @param path The path of the swap, i.e. each token pair and the pool fee + /// @param amountIn The amount of the first token to swap + /// @return amountOut The amount of the last token that would be received + function quoteExactInput( + bytes memory path, + uint256 amountIn + ) + external + returns (uint256 amountOut); + + /// @notice Returns the amount out received for a given exact input but for a swap of a single + /// pool + /// @param tokenIn The token being swapped in + /// @param tokenOut The token being swapped out + /// @param fee The fee of the token pool to consider for the pair + /// @param amountIn The desired input amount + /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountOut The amount of `tokenOut` that would be received + function quoteExactInputSingle( + address tokenIn, + address tokenOut, + uint24 fee, + uint256 amountIn, + uint160 sqrtPriceLimitX96 + ) + external + returns (uint256 amountOut); + + /// @notice Returns the amount in required for a given exact output swap without executing the + /// swap + /// @param path The path of the swap, i.e. each token pair and the pool fee + /// @param amountOut The amount of the last token to receive + /// @return amountIn The amount of first token required to be paid + function quoteExactOutput( + bytes memory path, + uint256 amountOut + ) + external + returns (uint256 amountIn); + + /// @notice Returns the amount in required to receive the given exact output amount but for a + /// swap of a single pool + /// @param tokenIn The token being swapped in + /// @param tokenOut The token being swapped out + /// @param fee The fee of the token pool to consider for the pair + /// @param amountOut The desired output amount + /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountIn The amount required as the input for the swap in order to receive + /// `amountOut` + function quoteExactOutputSingle( + address tokenIn, + address tokenOut, + uint24 fee, + uint256 amountOut, + uint160 sqrtPriceLimitX96 + ) + external + returns (uint256 amountIn); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/ISwapRouter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/ISwapRouter.sol new file mode 100644 index 0000000..c00309a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/ISwapRouter.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.10; + +/// @title Callback for IUniswapV3PoolActions#swap +/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface +interface IUniswapV3SwapCallback { + /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. + /// @dev In the implementation you must pay the pool tokens owed for the swap. + /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical + /// UniswapV3Factory. + /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. + /// @param amount0Delta The amount of token0 that was sent (negative) or must be received + /// (positive) by the pool by + /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. + /// @param amount1Delta The amount of token1 that was sent (negative) or must be received + /// (positive) by the pool by + /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. + /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call + function uniswapV3SwapCallback( + int256 amount0Delta, + int256 amount1Delta, + bytes calldata data + ) + external; +} + +/// @title Router token swapping functionality +/// @notice Functions for swapping tokens via Uniswap V3 +interface ISwapRouter is IUniswapV3SwapCallback { + struct ExactInputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 deadline; + uint256 amountIn; + uint256 amountOutMinimum; + uint160 sqrtPriceLimitX96; + } + + /// @notice Swaps `amountIn` of one token for as much as possible of another token + /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in + /// calldata + /// @return amountOut The amount of the received token + function exactInputSingle(ExactInputSingleParams calldata params) + external + payable + returns (uint256 amountOut); + + struct ExactInputParams { + bytes path; + address recipient; + uint256 deadline; + uint256 amountIn; + uint256 amountOutMinimum; + } + + /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified + /// path + /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` + /// in calldata + /// @return amountOut The amount of the received token + function exactInput(ExactInputParams calldata params) + external + payable + returns (uint256 amountOut); + + struct ExactOutputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 deadline; + uint256 amountOut; + uint256 amountInMaximum; + uint160 sqrtPriceLimitX96; + } + + /// @notice Swaps as little as possible of one token for `amountOut` of another token + /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in + /// calldata + /// @return amountIn The amount of the input token + function exactOutputSingle(ExactOutputSingleParams calldata params) + external + payable + returns (uint256 amountIn); + + struct ExactOutputParams { + bytes path; + address recipient; + uint256 deadline; + uint256 amountOut; + uint256 amountInMaximum; + } + + /// @notice Swaps as little as possible of one token for `amountOut` of another along the + /// specified path (reversed) + /// @param params The parameters necessary for the multi-hop swap, encoded as + /// `ExactOutputParams` in calldata + /// @return amountIn The amount of the input token + function exactOutput(ExactOutputParams calldata params) + external + payable + returns (uint256 amountIn); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IUniswapRouter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IUniswapRouter.sol new file mode 100644 index 0000000..d1587a0 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IUniswapRouter.sol @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IUniswapRouter { + function swapExactTokensForETH( + uint256 amountIn, + uint256 amountOutMin, + address[] calldata path, + address to, + uint256 deadline + ) + external + virtual + returns (uint256[] memory amounts); + + function swapExactTokensForTokens( + uint256 amountIn, + uint256 amountOutMin, + address[] calldata path, + address to, + uint256 deadline + ) + external + virtual + returns (uint256[] memory amounts); + + function swapTokensForExactETH( + uint256 amountOut, + uint256 amountInMax, + address[] calldata path, + address to, + uint256 deadline + ) + external + virtual + returns (uint256[] memory amounts); + + function swapTokensForExactTokens( + uint256 amountOut, + uint256 amountInMax, + address[] calldata path, + address to, + uint256 deadline + ) + external + virtual + returns (uint256[] memory amounts); + + function addLiquidity( + address tokenA, + address tokenB, + uint256 amountADesired, + uint256 amountBDesired, + uint256 amountAMin, + uint256 amountBMin, + address to, + uint256 deadline + ) + external + virtual + returns (uint256 amountA, uint256 amountB, uint256 liquidity); + + function addLiquidityETH( + address token, + uint256 amountTokenDesired, + uint256 amountTokenMin, + uint256 amountETHMin, + address to, + uint256 deadline + ) + external + payable + virtual + returns (uint256 amountToken, uint256 amountETH, uint256 liquidity); + + function removeLiquidity( + address tokenA, + address tokenB, + uint256 liquidity, + uint256 amountAMin, + uint256 amountBMin, + address to, + uint256 deadline + ) + external + virtual + returns (uint256 amountA, uint256 amountB); + + function quote( + uint256 amountA, + uint256 reserveA, + uint256 reserveB + ) + public + pure + virtual + returns (uint256 amountB); + + function getAmountsOut( + uint256 amountIn, + address[] memory path + ) + public + view + virtual + returns (uint256[] memory amounts); + + function getAmountsIn( + uint256 amountOut, + address[] memory path + ) + public + view + virtual + returns (uint256[] memory amounts); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashBorrower.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashBorrower.sol new file mode 100644 index 0000000..3b95b5d --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashBorrower.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +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/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashLender.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashLender.sol new file mode 100644 index 0000000..28dcf8c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashLender.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +import "./IERC3156FlashBorrower.sol"; + +interface IERC3156FlashLender { + /** + * @dev The amount of currency available to be lent. + * @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/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IFlashLoanBase.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IFlashLoanBase.sol new file mode 100644 index 0000000..353f976 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IFlashLoanBase.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +abstract contract IFlashLoanBase { + struct FlashLoanParams { + address[] tokens; + uint256[] amounts; + uint256[] modes; + address onBehalfOf; + address flParamGetterAddr; + bytes flParamGetterData; + bytes recipeData; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniPool.sol new file mode 100644 index 0000000..149c713 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniPool.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.10; + +interface IGUniPool { + function token0() external view returns (address); + function token1() external view returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniRouter02.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniRouter02.sol new file mode 100644 index 0000000..384e927 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniRouter02.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.10; +pragma abicoder v2; + +interface IGUniRouter02 { + function removeLiquidity( + address pool, + uint256 burnAmount, + uint256 amount0Min, + uint256 amount1Min, + address receiver + ) + external + returns (uint256 amount0, uint256 amount1, uint128 liquidityBurned); + + function rebalanceAndAddLiquidity( + address pool, + uint256 amount0In, + uint256 amount1In, + uint256 amountSwap, + bool zeroForOne, + address[] memory swapActions, + bytes[] memory swapDatas, + uint256 amount0Min, + uint256 amount1Min, + address receiver + ) + external + returns (uint256 amount0, uint256 amount1, uint256 mintAmount); + + function addLiquidity( + address pool, + uint256 amount0Max, + uint256 amount1Max, + uint256 amount0Min, + uint256 amount1Min, + address receiver + ) + external + returns (uint256 amount0, uint256 amount1, uint256 mintAmount); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaAccountV2.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaAccountV2.sol new file mode 100644 index 0000000..4674f1c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaAccountV2.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; +pragma abicoder v2; + +interface IInstaAccountV2 { + function cast(string[] memory, bytes[] memory, address) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaIndex.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaIndex.sol new file mode 100644 index 0000000..e82d80a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaIndex.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IInstaIndex { + function build( + address _owner, + uint256 accountVersion, + address _origin + ) + external + returns (address _account); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaMakerDAOMerkleDistributor.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaMakerDAOMerkleDistributor.sol new file mode 100644 index 0000000..7ad6a1e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaMakerDAOMerkleDistributor.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IInstaMakerDAOMerkleDistributor { + function claim( + uint256 index, + uint256 vaultId, + address dsa, + address owner, + uint256 rewardAmount, + uint256 networthAmount, + bytes32[] calldata merkleProof + ) + external; + + function getPosition( + uint256 id, + uint256 rewardAmount, + uint256 networthAmount + ) + external + view + returns (uint256 claimableRewardAmount, uint256 claimableNetworth); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IAggregationExecutor.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IAggregationExecutor.sol new file mode 100644 index 0000000..814ded6 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IAggregationExecutor.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IAggregationExecutor { + function callBytes(bytes calldata data) external payable; // 0xd9c45357 + + // callbytes per swap sequence + function swapSingleSequence(bytes calldata data) external; + + function finalTransactionProcessing( + address tokenIn, + address tokenOut, + address to, + bytes calldata destTokenFeeData + ) + external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IExecutorHelper.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IExecutorHelper.sol new file mode 100644 index 0000000..d901ed2 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IExecutorHelper.sol @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IExecutorHelper { + struct Swap { + bytes data; + bytes4 functionSelector; + } + + struct SwapExecutorDescription { + Swap[][] swapSequences; + address tokenIn; + address tokenOut; + uint256 minTotalAmountOut; + address to; + uint256 deadline; + bytes destTokenFeeData; + } + + struct UniSwap { + address pool; + address tokenIn; + address tokenOut; + address recipient; + uint256 collectAmount; // amount that should be transferred to the pool + uint32 swapFee; + uint32 feePrecision; + uint32 tokenWeightInput; + } + + struct StableSwap { + address pool; + address tokenFrom; + address tokenTo; + uint8 tokenIndexFrom; + uint8 tokenIndexTo; + uint256 dx; + uint256 poolLength; + address poolLp; + bool isSaddle; // true: saddle, false: stable + } + + struct CurveSwap { + address pool; + address tokenFrom; + address tokenTo; + int128 tokenIndexFrom; + int128 tokenIndexTo; + uint256 dx; + bool usePoolUnderlying; + bool useTriCrypto; + } + + struct UniswapV3KSElastic { + address recipient; + address pool; + address tokenIn; + address tokenOut; + uint256 swapAmount; + uint160 sqrtPriceLimitX96; + bool isUniV3; // true = UniV3, false = KSElastic + } + + struct BalancerV2 { + address vault; + bytes32 poolId; + address assetIn; + address assetOut; + uint256 amount; + } + + struct DODO { + address recipient; + address pool; + address tokenFrom; + address tokenTo; + uint256 amount; + address sellHelper; + bool isSellBase; + bool isVersion2; + } + + struct GMX { + address vault; + address tokenIn; + address tokenOut; + uint256 amount; + address receiver; + } + + struct Synthetix { + address synthetixProxy; + address tokenIn; + address tokenOut; + bytes32 sourceCurrencyKey; + uint256 sourceAmount; + bytes32 destinationCurrencyKey; + bool useAtomicExchange; + } + + struct Platypus { + address pool; + address tokenIn; + address tokenOut; + address recipient; + uint256 collectAmount; // amount that should be transferred to the pool + } + + struct PSM { + address router; + address tokenIn; + address tokenOut; + uint256 amountIn; + address recipient; + } + + struct WSTETH { + address pool; + uint256 amount; + bool isWrapping; + } + + struct Maverick { + address pool; + address tokenIn; + address tokenOut; + address recipient; + uint256 swapAmount; + uint256 sqrtPriceLimitD18; + } + + struct SyncSwap { + bytes _data; + address vault; + address tokenIn; + address pool; + uint256 collectAmount; + } + + struct AlgebraV1 { + address recipient; + address pool; + address tokenIn; + address tokenOut; + uint256 swapAmount; + uint160 sqrtPriceLimitX96; + uint256 senderFeeOnTransfer; // [ FoT_FLAG(1 bit) ... SENDER_ADDRESS(160 bits) ] + } + + struct BalancerBatch { + address vault; + bytes32[] poolIds; + address[] path; // swap path from assetIn to assetOut + bytes[] userDatas; + uint256 amountIn; // assetIn amount + } + + struct Mantis { + address pool; + address tokenIn; + address tokenOut; + uint256 amount; + address recipient; + } + + struct IziSwap { + address pool; + address tokenIn; + address tokenOut; + address recipient; + uint256 swapAmount; + int24 limitPoint; + } + + function executeUniswap( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeStableSwap( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeCurve( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeKSClassic( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeUniV3KSElastic( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeRfq( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeBalV2( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeDODO( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeVelodrome( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeGMX( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executePlatypus( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeWrappedstETH( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeStEth( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeSynthetix( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeHashflow( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executePSM( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeFrax( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeCamelot( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeKyberLimitOrder( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeMaverick( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeSyncSwap( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeAlgebraV1( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeBalancerBatch( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeWombat( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeMantis( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); + + function executeIziSwap( + bytes memory data, + uint256 flagsAndPrevAmountOut + ) + external + payable + returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IMetaAggregationRouterV2.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IMetaAggregationRouterV2.sol new file mode 100644 index 0000000..219efab --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IMetaAggregationRouterV2.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +import { IERC20 } from "../IERC20.sol"; +import { IAggregationExecutor } from "./IAggregationExecutor.sol"; + +interface IMetaAggregationRouterV2 { + struct SwapDescriptionV2 { + IERC20 srcToken; + IERC20 dstToken; + address[] srcReceivers; // transfer src token to these addresses, default + uint256[] srcAmounts; + address[] feeReceivers; + uint256[] feeAmounts; + address dstReceiver; + uint256 amount; + uint256 minReturnAmount; + uint256 flags; + bytes permit; + } + + /// @dev use for swapGeneric and swap to avoid stack too deep + struct SwapExecutionParams { + address callTarget; // call this address + address approveTarget; // approve this address if _APPROVE_FUND set + bytes targetData; + SwapDescriptionV2 desc; + bytes clientData; + } + + function swap(SwapExecutionParams calldata execution) + external + payable + returns (uint256, uint256); + + function swapSimpleMode( + IAggregationExecutor caller, + SwapDescriptionV2 memory desc, + bytes calldata executorData, + bytes calldata clientData + ) + external + returns (uint256, uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/lido/IWStEth.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/lido/IWStEth.sol new file mode 100644 index 0000000..7f329b6 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/lido/IWStEth.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +// Interface for wrapping and unwrapping StEth +interface IWStEth { + function wrap(uint256 _stETHAmount) external returns (uint256); + function unwrap(uint256 _wstETHAmount) external returns (uint256); + function stEthPerToken() external view returns (uint256); + function tokensPerStEth() external view returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFT.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFT.sol new file mode 100644 index 0000000..da0e374 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFT.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +import "../IERC721Enumerable.sol"; + +interface IBondNFT is IERC721Enumerable { + struct BondExtraData { + uint80 initialHalfDna; + uint80 finalHalfDna; + uint32 troveSize; // Debt in LUSD + uint32 lqtyAmount; // Holding LQTY, staking or deposited into Pickle + uint32 curveGaugeSlopes; // For 3CRV and Frax pools combined + } + + function getBondAmount(uint256 _tokenID) external view returns (uint256 amount); + function getBondStartTime(uint256 _tokenID) external view returns (uint256 startTime); + function getBondEndTime(uint256 _tokenID) external view returns (uint256 endTime); + function getBondInitialHalfDna(uint256 _tokenID) + external + view + returns (uint80 initialHalfDna); + function getBondInitialDna(uint256 _tokenID) external view returns (uint256 initialDna); + function getBondFinalHalfDna(uint256 _tokenID) external view returns (uint80 finalHalfDna); + function getBondFinalDna(uint256 _tokenID) external view returns (uint256 finalDna); + function getBondStatus(uint256 _tokenID) external view returns (uint8 status); + function getBondExtraData(uint256 _tokenID) external view returns (BondExtraData memory); + function tokenURI(uint256 _tokenID) external view returns (string memory); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFTArtwork.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFTArtwork.sol new file mode 100644 index 0000000..6058725 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFTArtwork.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +import "./IBondNFT.sol"; + +interface IBondNFTArtwork { + function tokenURI( + uint256 _tokenID, + IBondNFT.BondExtraData calldata _bondExtraData + ) + external + view + returns (string memory); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBorrowerOperations.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBorrowerOperations.sol new file mode 100644 index 0000000..830d0ce --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBorrowerOperations.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +// Common interface for the Trove Manager. +interface IBorrowerOperations { + // --- Events --- + + event TroveManagerAddressChanged(address _newTroveManagerAddress); + event ActivePoolAddressChanged(address _activePoolAddress); + event DefaultPoolAddressChanged(address _defaultPoolAddress); + event StabilityPoolAddressChanged(address _stabilityPoolAddress); + event GasPoolAddressChanged(address _gasPoolAddress); + event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress); + event PriceFeedAddressChanged(address _newPriceFeedAddress); + event SortedTrovesAddressChanged(address _sortedTrovesAddress); + event LUSDTokenAddressChanged(address _lusdTokenAddress); + event LQTYStakingAddressChanged(address _lqtyStakingAddress); + + event TroveCreated(address indexed _borrower, uint256 arrayIndex); + event TroveUpdated( + address indexed _borrower, uint256 _debt, uint256 _coll, uint256 stake, uint8 operation + ); + event LUSDBorrowingFeePaid(address indexed _borrower, uint256 _LUSDFee); + + // --- Functions --- + + function openTrove( + uint256 _maxFee, + uint256 _LUSDAmount, + address _upperHint, + address _lowerHint + ) + external + payable; + + function addColl(address _upperHint, address _lowerHint) external payable; + + function moveETHGainToTrove( + address _user, + address _upperHint, + address _lowerHint + ) + external + payable; + + function withdrawColl(uint256 _amount, address _upperHint, address _lowerHint) external; + + function withdrawLUSD( + uint256 _maxFee, + uint256 _amount, + address _upperHint, + address _lowerHint + ) + external; + + function repayLUSD(uint256 _amount, address _upperHint, address _lowerHint) external; + + function closeTrove() external; + + function adjustTrove( + uint256 _maxFee, + uint256 _collWithdrawal, + uint256 _debtChange, + bool isDebtIncrease, + address _upperHint, + address _lowerHint + ) + external + payable; + + function claimCollateral() external; + + function getCompositeDebt(uint256 _debt) external pure returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IChickenBondManager.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IChickenBondManager.sol new file mode 100644 index 0000000..ccc4b72 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IChickenBondManager.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface IChickenBondManager { + // Valid values for `status` returned by `getBondData()` + enum BondStatus { + nonExistent, + active, + chickenedOut, + chickenedIn + } + + struct BondData { + uint256 lusdAmount; + uint64 claimedBLUSD; // In BLUSD units without decimals + uint64 startTime; + uint64 endTime; // Timestamp of chicken in/out event + BondStatus status; + } + + function lusdToken() external view returns (address); + function bLUSDToken() external view returns (address); + function curvePool() external view returns (address); + function bammSPVault() external view returns (address); + function yearnCurveVault() external view returns (address); + + function countChickenIn() external view returns (uint256); + function countChickenOut() external view returns (uint256); + + // constants + function INDEX_OF_LUSD_TOKEN_IN_CURVE_POOL() external pure returns (int128); + function CHICKEN_IN_AMM_FEE() external view returns (uint256); + + function createBond(uint256 _lusdAmount) external returns (uint256); + function createBondWithPermit( + address owner, + uint256 amount, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) + external + returns (uint256); + function chickenOut(uint256 _bondID, uint256 _minLUSD) external; + function chickenIn(uint256 _bondID) external; + function redeem( + uint256 _bLUSDToRedeem, + uint256 _minLUSDFromBAMMSPVault + ) + external + returns (uint256, uint256); + + // getters + function calcRedemptionFeePercentage(uint256 _fractionOfBLUSDToRedeem) + external + view + returns (uint256); + function getBondData(uint256 _bondID) external view returns (BondData memory); + function getLUSDToAcquire(uint256 _bondID) external view returns (uint256); + function calcAccruedBLUSD(uint256 _bondID) external view returns (uint256); + function calcBondBLUSDCap(uint256 _bondID) external view returns (uint256); + function getLUSDInBAMMSPVault() external view returns (uint256); + function calcTotalYearnCurveVaultShareValue() external view returns (uint256); + function calcTotalLUSDValue() external view returns (uint256); + function getPendingLUSD() external view returns (uint256); + function getAcquiredLUSDInSP() external view returns (uint256); + function getAcquiredLUSDInCurve() external view returns (uint256); + function getTotalAcquiredLUSD() external view returns (uint256); + function getPermanentLUSD() external view returns (uint256); + function getOwnedLUSDInSP() external view returns (uint256); + function getOwnedLUSDInCurve() external view returns (uint256); + function calcSystemBackingRatio() external view returns (uint256); + function calcUpdatedAccrualParameter() external view returns (uint256); + function getBAMMLUSDDebt() external view returns (uint256); + function getOpenBondCount() external view returns (uint256); + function getTreasury() + external + view + returns (uint256 _pendingLUSD, uint256 _totalAcquiredLUSD, uint256 _permanentLUSD); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ICollSurplusPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ICollSurplusPool.sol new file mode 100644 index 0000000..86bb605 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ICollSurplusPool.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface ICollSurplusPool { + // --- Events --- + + event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress); + event TroveManagerAddressChanged(address _newTroveManagerAddress); + event ActivePoolAddressChanged(address _newActivePoolAddress); + + event CollBalanceUpdated(address indexed _account, uint256 _newBalance); + event EtherSent(address _to, uint256 _amount); + + // --- Contract setters --- + + function setAddresses( + address _borrowerOperationsAddress, + address _troveManagerAddress, + address _activePoolAddress + ) + external; + + function getETH() external view returns (uint256); + + function getCollateral(address _account) external view returns (uint256); + + function accountSurplus(address _account, uint256 _amount) external; + + function claimColl(address _account) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IHintHelpers.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IHintHelpers.sol new file mode 100644 index 0000000..4741924 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IHintHelpers.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface IHintHelpers { + function getRedemptionHints( + uint256 _LUSDamount, + uint256 _price, + uint256 _maxIterations + ) + external + view + returns ( + address firstRedemptionHint, + uint256 partialRedemptionHintNICR, + uint256 truncatedLUSDamount + ); + + function getApproxHint( + uint256 _CR, + uint256 _numTrials, + uint256 _inputRandomSeed + ) + external + view + returns (address hintAddress, uint256 diff, uint256 latestRandomSeed); + + function computeNominalCR(uint256 _coll, uint256 _debt) external pure returns (uint256); + + function computeCR( + uint256 _coll, + uint256 _debt, + uint256 _price + ) + external + pure + returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ILQTYStaking.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ILQTYStaking.sol new file mode 100644 index 0000000..7b58de2 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ILQTYStaking.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface ILQTYStaking { + // --- Events -- + + event LQTYTokenAddressSet(address _lqtyTokenAddress); + event LUSDTokenAddressSet(address _lusdTokenAddress); + event TroveManagerAddressSet(address _troveManager); + event BorrowerOperationsAddressSet(address _borrowerOperationsAddress); + event ActivePoolAddressSet(address _activePoolAddress); + + event StakeChanged(address indexed staker, uint256 newStake); + event StakingGainsWithdrawn(address indexed staker, uint256 LUSDGain, uint256 ETHGain); + event F_ETHUpdated(uint256 _F_ETH); + event F_LUSDUpdated(uint256 _F_LUSD); + event TotalLQTYStakedUpdated(uint256 _totalLQTYStaked); + event EtherSent(address _account, uint256 _amount); + event StakerSnapshotsUpdated(address _staker, uint256 _F_ETH, uint256 _F_LUSD); + + // --- Functions --- + + function setAddresses( + address _lqtyTokenAddress, + address _lusdTokenAddress, + address _troveManagerAddress, + address _borrowerOperationsAddress, + address _activePoolAddress + ) + external; + + function stake(uint256 _LQTYamount) external; + + function unstake(uint256 _LQTYamount) external; + + function increaseF_ETH(uint256 _ETHFee) external; + + function increaseF_LUSD(uint256 _LQTYFee) external; + + function getPendingETHGain(address _user) external view returns (uint256); + + function getPendingLUSDGain(address _user) external view returns (uint256); + + function stakes(address) external view returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IPriceFeed.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IPriceFeed.sol new file mode 100644 index 0000000..9334a2f --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IPriceFeed.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface IPriceFeed { + function lastGoodPrice() external pure returns (uint256); + function fetchPrice() external returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ISortedTroves.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ISortedTroves.sol new file mode 100644 index 0000000..8e1fdc3 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ISortedTroves.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +// Common interface for the SortedTroves Doubly Linked List. +interface ISortedTroves { + // --- Events --- + + event SortedTrovesAddressChanged(address _sortedDoublyLLAddress); + event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress); + event NodeAdded(address _id, uint256 _NICR); + event NodeRemoved(address _id); + + // --- Functions --- + + function setParams( + uint256 _size, + address _TroveManagerAddress, + address _borrowerOperationsAddress + ) + external; + + function insert(address _id, uint256 _ICR, address _prevId, address _nextId) external; + + function remove(address _id) external; + + function reInsert(address _id, uint256 _newICR, address _prevId, address _nextId) external; + + function contains(address _id) external view returns (bool); + + function isFull() external view returns (bool); + + function isEmpty() external view returns (bool); + + function getSize() external view returns (uint256); + + function getMaxSize() external view returns (uint256); + + function getFirst() external view returns (address); + + function getLast() external view returns (address); + + function getNext(address _id) external view returns (address); + + function getPrev(address _id) external view returns (address); + + function validInsertPosition( + uint256 _ICR, + address _prevId, + address _nextId + ) + external + view + returns (bool); + + function findInsertPosition( + uint256 _ICR, + address _prevId, + address _nextId + ) + external + view + returns (address, address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IStabilityPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IStabilityPool.sol new file mode 100644 index 0000000..bd92aad --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IStabilityPool.sol @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IStabilityPool { + // --- Events --- + + event StabilityPoolETHBalanceUpdated(uint256 _newBalance); + event StabilityPoolLUSDBalanceUpdated(uint256 _newBalance); + + event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress); + event TroveManagerAddressChanged(address _newTroveManagerAddress); + event ActivePoolAddressChanged(address _newActivePoolAddress); + event DefaultPoolAddressChanged(address _newDefaultPoolAddress); + event LUSDTokenAddressChanged(address _newLUSDTokenAddress); + event SortedTrovesAddressChanged(address _newSortedTrovesAddress); + event PriceFeedAddressChanged(address _newPriceFeedAddress); + event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress); + + event P_Updated(uint256 _P); + event S_Updated(uint256 _S, uint128 _epoch, uint128 _scale); + event G_Updated(uint256 _G, uint128 _epoch, uint128 _scale); + event EpochUpdated(uint128 _currentEpoch); + event ScaleUpdated(uint128 _currentScale); + + event FrontEndRegistered(address indexed _frontEnd, uint256 _kickbackRate); + event FrontEndTagSet(address indexed _depositor, address indexed _frontEnd); + + event DepositSnapshotUpdated(address indexed _depositor, uint256 _P, uint256 _S, uint256 _G); + event FrontEndSnapshotUpdated(address indexed _frontEnd, uint256 _P, uint256 _G); + event UserDepositChanged(address indexed _depositor, uint256 _newDeposit); + event FrontEndStakeChanged( + address indexed _frontEnd, uint256 _newFrontEndStake, address _depositor + ); + + event ETHGainWithdrawn(address indexed _depositor, uint256 _ETH, uint256 _LUSDLoss); + event LQTYPaidToDepositor(address indexed _depositor, uint256 _LQTY); + event LQTYPaidToFrontEnd(address indexed _frontEnd, uint256 _LQTY); + event EtherSent(address _to, uint256 _amount); + + // --- Functions --- + + /* + * Called only once on init, to set addresses of other Liquity contracts + * Callable only by owner, renounces ownership at the end + */ + function setAddresses( + address _borrowerOperationsAddress, + address _troveManagerAddress, + address _activePoolAddress, + address _lusdTokenAddress, + address _sortedTrovesAddress, + address _priceFeedAddress, + address _communityIssuanceAddress + ) + external; + + /* + * Initial checks: + * - Frontend is registered or zero address + * - Sender is not a registered frontend + * - _amount is not zero + * --- + * - Triggers a LQTY issuance, based on time passed since the last issuance. The LQTY issuance is + shared between *all* depositors and front ends + * - Tags the deposit with the provided front end tag param, if it's a new deposit + * - Sends depositor's accumulated gains (LQTY, ETH) to depositor + * - Sends the tagged front end's accumulated LQTY gains to the tagged front end + * - Increases deposit and tagged front end's stake, and takes new snapshots for each. + */ + function provideToSP(uint256 _amount, address _frontEndTag) external; + + /* + * Initial checks: + * - _amount is zero or there are no under collateralized troves left in the system + * - User has a non zero deposit + * --- + * - Triggers a LQTY issuance, based on time passed since the last issuance. The LQTY issuance is + shared between *all* depositors and front ends + * - Removes the deposit's front end tag if it is a full withdrawal + * - Sends all depositor's accumulated gains (LQTY, ETH) to depositor + * - Sends the tagged front end's accumulated LQTY gains to the tagged front end + * - Decreases deposit and tagged front end's stake, and takes new snapshots for each. + * + * If _amount > userDeposit, the user withdraws all of their compounded deposit. + */ + function withdrawFromSP(uint256 _amount) external; + + /* + * Initial checks: + * - User has a non zero deposit + * - User has an open trove + * - User has some ETH gain + * --- + * - Triggers a LQTY issuance, based on time passed since the last issuance. The LQTY issuance is + shared between *all* depositors and front ends + * - Sends all depositor's LQTY gain to depositor + * - Sends all tagged front end's LQTY gain to the tagged front end + * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove + * - Leaves their compounded deposit in the Stability Pool + * - Updates snapshots for deposit and tagged front end stake + */ + function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external; + + /* + * Initial checks: + * - Frontend (sender) not already registered + * - User (sender) has no deposit + * - _kickbackRate is in the range [0, 100%] + * --- + * Front end makes a one-time selection of kickback rate upon registering + */ + function registerFrontEnd(uint256 _kickbackRate) external; + + /* + * Initial checks: + * - Caller is TroveManager + * --- + * Cancels out the specified debt against the LUSD contained in the Stability Pool (as far as + possible) + * and transfers the Trove's ETH collateral from ActivePool to StabilityPool. + * Only called by liquidation functions in the TroveManager. + */ + function offset(uint256 _debt, uint256 _coll) external; + + /* + * Returns the total amount of ETH held by the pool, accounted in an internal variable instead of + `balance`, + * to exclude edge cases like ETH received from a self-destruct. + */ + function getETH() external view returns (uint256); + + /* + * Returns LUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is + offset. + */ + function getTotalLUSDDeposits() external view returns (uint256); + + /* + * Calculates the ETH gain earned by the deposit since its last snapshots were taken. + */ + function getDepositorETHGain(address _depositor) external view returns (uint256); + + /* + * Calculate the LQTY gain earned by a deposit since its last snapshots were taken. + * If not tagged with a front end, the depositor gets a 100% cut of what their deposit earned. + * Otherwise, their cut of the deposit's earnings is equal to the kickbackRate, set by the front + end through + * which they made their deposit. + */ + function getDepositorLQTYGain(address _depositor) external view returns (uint256); + + /* + * Return the LQTY gain earned by the front end. + */ + function getFrontEndLQTYGain(address _frontEnd) external view returns (uint256); + + /* + * Return the user's compounded deposit. + */ + function getCompoundedLUSDDeposit(address _depositor) external view returns (uint256); + + /* + * Return the front end's compounded stake. + * + * The front end's compounded stake is equal to the sum of its depositors' compounded deposits. + */ + function getCompoundedFrontEndStake(address _frontEnd) external view returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ITroveManager.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ITroveManager.sol new file mode 100644 index 0000000..1cca992 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ITroveManager.sol @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +// Common interface for the Trove Manager. +interface ITroveManager { + // --- Events --- + + event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress); + event PriceFeedAddressChanged(address _newPriceFeedAddress); + event LUSDTokenAddressChanged(address _newLUSDTokenAddress); + event ActivePoolAddressChanged(address _activePoolAddress); + event DefaultPoolAddressChanged(address _defaultPoolAddress); + event StabilityPoolAddressChanged(address _stabilityPoolAddress); + event GasPoolAddressChanged(address _gasPoolAddress); + event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress); + event SortedTrovesAddressChanged(address _sortedTrovesAddress); + event LQTYTokenAddressChanged(address _lqtyTokenAddress); + event LQTYStakingAddressChanged(address _lqtyStakingAddress); + + event Liquidation( + uint256 _liquidatedDebt, + uint256 _liquidatedColl, + uint256 _collGasCompensation, + uint256 _LUSDGasCompensation + ); + event Redemption( + uint256 _attemptedLUSDAmount, uint256 _actualLUSDAmount, uint256 _ETHSent, uint256 _ETHFee + ); + event TroveUpdated( + address indexed _borrower, uint256 _debt, uint256 _coll, uint256 stake, uint8 operation + ); + event TroveLiquidated(address indexed _borrower, uint256 _debt, uint256 _coll, uint8 operation); + event BaseRateUpdated(uint256 _baseRate); + event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime); + event TotalStakesUpdated(uint256 _newTotalStakes); + event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot); + event LTermsUpdated(uint256 _L_ETH, uint256 _L_LUSDDebt); + event TroveSnapshotsUpdated(uint256 _L_ETH, uint256 _L_LUSDDebt); + event TroveIndexUpdated(address _borrower, uint256 _newIndex); + + function getTroveOwnersCount() external view returns (uint256); + + function getTroveFromTroveOwnersArray(uint256 _index) external view returns (address); + + function getNominalICR(address _borrower) external view returns (uint256); + function getCurrentICR(address _borrower, uint256 _price) external view returns (uint256); + + function liquidate(address _borrower) external; + + function liquidateTroves(uint256 _n) external; + + function batchLiquidateTroves(address[] calldata _troveArray) external; + + function redeemCollateral( + uint256 _LUSDAmount, + address _firstRedemptionHint, + address _upperPartialRedemptionHint, + address _lowerPartialRedemptionHint, + uint256 _partialRedemptionHintNICR, + uint256 _maxIterations, + uint256 _maxFee + ) + external; + + function updateStakeAndTotalStakes(address _borrower) external returns (uint256); + + function updateTroveRewardSnapshots(address _borrower) external; + + function addTroveOwnerToArray(address _borrower) external returns (uint256 index); + + function applyPendingRewards(address _borrower) external; + + function getPendingETHReward(address _borrower) external view returns (uint256); + + function getPendingLUSDDebtReward(address _borrower) external view returns (uint256); + + function hasPendingRewards(address _borrower) external view returns (bool); + + function getEntireDebtAndColl(address _borrower) + external + view + returns ( + uint256 debt, + uint256 coll, + uint256 pendingLUSDDebtReward, + uint256 pendingETHReward + ); + + function closeTrove(address _borrower) external; + + function removeStake(address _borrower) external; + + function getRedemptionRate() external view returns (uint256); + function getRedemptionRateWithDecay() external view returns (uint256); + + function getRedemptionFeeWithDecay(uint256 _ETHDrawn) external view returns (uint256); + + function getBorrowingRate() external view returns (uint256); + function getBorrowingRateWithDecay() external view returns (uint256); + + function getBorrowingFee(uint256 LUSDDebt) external view returns (uint256); + function getBorrowingFeeWithDecay(uint256 _LUSDDebt) external view returns (uint256); + + function decayBaseRateFromBorrowing() external; + + function getTroveStatus(address _borrower) external view returns (uint256); + + function getTroveStake(address _borrower) external view returns (uint256); + + function getTroveDebt(address _borrower) external view returns (uint256); + + function getTroveColl(address _borrower) external view returns (uint256); + + function setTroveStatus(address _borrower, uint256 num) external; + + function increaseTroveColl( + address _borrower, + uint256 _collIncrease + ) + external + returns (uint256); + + function decreaseTroveColl( + address _borrower, + uint256 _collDecrease + ) + external + returns (uint256); + + function increaseTroveDebt( + address _borrower, + uint256 _debtIncrease + ) + external + returns (uint256); + + function decreaseTroveDebt( + address _borrower, + uint256 _collDecrease + ) + external + returns (uint256); + + function getTCR(uint256 _price) external view returns (uint256); + + function checkRecoveryMode(uint256 _price) external view returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICat.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICat.sol new file mode 100644 index 0000000..ee6dfc0 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICat.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract ICat { + struct Ilk { + address flip; // Liquidator + uint256 chop; // Liquidation Penalty [ray] + uint256 lump; // Liquidation Quantity [wad] + } + + mapping(bytes32 => Ilk) public ilks; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICdpRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICdpRegistry.sol new file mode 100644 index 0000000..8ed91fd --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICdpRegistry.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +import "./IVat.sol"; +import "./IGem.sol"; + +abstract contract ICdpRegistry { + function open(bytes32 ilk, address usr) public virtual returns (uint256); + + function cdps(bytes32, address) public view virtual returns (uint256); + function owns(uint256) public view virtual returns (address); + function ilks(uint256) public view virtual returns (bytes32); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropJoin.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropJoin.sol new file mode 100644 index 0000000..9303f9a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropJoin.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +import "./IJoin.sol"; + +abstract contract ICropJoin is IJoin { + function bonus() external virtual returns (IGem); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropper.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropper.sol new file mode 100644 index 0000000..8420d81 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropper.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface ICropper { + function proxy(address) external view returns (address); + function getOrCreateProxy(address) external returns (address); + function join(address, address, uint256) external; + function exit(address, address, uint256) external; + function flee(address, address, uint256) external; + function frob(bytes32, address, address, address, int256, int256) external; + function quit(bytes32, address, address) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDSPause.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDSPause.sol new file mode 100644 index 0000000..0b26486 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDSPause.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IDSPause { + function plot(address usr, bytes32 tag, bytes memory fax, uint256 eta) public virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDaiJoin.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDaiJoin.sol new file mode 100644 index 0000000..16693df --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDaiJoin.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +import "./IVat.sol"; +import "./IGem.sol"; + +abstract contract IDaiJoin { + function vat() public virtual returns (IVat); + function dai() public virtual returns (IGem); + function join(address, uint256) public payable virtual; + function exit(address, uint256) public virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDssSpell.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDssSpell.sol new file mode 100644 index 0000000..ec45430 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDssSpell.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IDssSpell { + function cast() public virtual; + function done() public view virtual returns (bool); + function nextCastTime() public view virtual returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGem.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGem.sol new file mode 100644 index 0000000..1ddcb52 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGem.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IGem { + function dec() public virtual returns (uint256); + function gem() public virtual returns (IGem); + function join(address, uint256) public payable virtual; + function exit(address, uint256) public virtual; + + function approve(address, uint256) public virtual; + function transfer(address, uint256) public virtual returns (bool); + function transferFrom(address, address, uint256) public virtual returns (bool); + function deposit() public payable virtual; + function withdraw(uint256) public virtual; + function allowance(address, address) public virtual returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGetCdps.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGetCdps.sol new file mode 100644 index 0000000..28d6af6 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGetCdps.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +abstract contract IGetCdps { + function getCdpsAsc( + address manager, + address guy + ) + external + view + virtual + returns (uint256[] memory ids, address[] memory urns, bytes32[] memory ilks); + + function getCdpsDesc( + address manager, + address guy + ) + external + view + virtual + returns (uint256[] memory ids, address[] memory urns, bytes32[] memory ilks); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJoin.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJoin.sol new file mode 100644 index 0000000..d857aaa --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJoin.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +import "./IGem.sol"; + +abstract contract IJoin { + bytes32 public ilk; + + function dec() public view virtual returns (uint256); + function gem() public view virtual returns (IGem); + function join(address, uint256) public payable virtual; + function exit(address, uint256) public virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJug.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJug.sol new file mode 100644 index 0000000..f1b0595 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJug.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IJug { + struct Ilk { + uint256 duty; + uint256 rho; + } + + mapping(bytes32 => Ilk) public ilks; + + function drip(bytes32) public virtual returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IManager.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IManager.sol new file mode 100644 index 0000000..85fb930 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IManager.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IManager { + function last(address) public virtual returns (uint256); + function cdpCan(address, uint256, address) public view virtual returns (uint256); + function ilks(uint256) public view virtual returns (bytes32); + function owns(uint256) public view virtual returns (address); + function urns(uint256) public view virtual returns (address); + function vat() public view virtual returns (address); + function open(bytes32, address) public virtual returns (uint256); + function give(uint256, address) public virtual; + function cdpAllow(uint256, address, uint256) public virtual; + function urnAllow(address, uint256) public virtual; + function frob(uint256, int256, int256) public virtual; + function flux(uint256, address, uint256) public virtual; + function move(uint256, address, uint256) public virtual; + function exit(address, uint256, address, uint256) public virtual; + function quit(uint256, address) public virtual; + function enter(address, uint256) public virtual; + function shift(uint256, uint256) public virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IOsm.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IOsm.sol new file mode 100644 index 0000000..fe1653b --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IOsm.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +abstract contract IOsm { + mapping(address => uint256) public bud; + + function peep() external view virtual returns (bytes32, bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPipInterface.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPipInterface.sol new file mode 100644 index 0000000..7899a7e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPipInterface.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IPipInterface { + function read() public virtual returns (bytes32); + function poke() external virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPot.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPot.sol new file mode 100644 index 0000000..c796eb5 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPot.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IPot { + function pie(address) external view returns (uint256); + function vat() external view returns (address); + function chi() external view returns (uint256); + function rho() external view returns (uint256); + function drip() external returns (uint256); + function join(uint256) external; + function exit(uint256) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ISpotter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ISpotter.sol new file mode 100644 index 0000000..b39cc74 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ISpotter.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +import "./IPipInterface.sol"; + +abstract contract ISpotter { + struct Ilk { + IPipInterface pip; + uint256 mat; + } + + mapping(bytes32 => Ilk) public ilks; + + uint256 public par; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IVat.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IVat.sol new file mode 100644 index 0000000..a184829 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IVat.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IVat { + struct Urn { + uint256 ink; // Locked Collateral [wad] + uint256 art; // Normalised Debt [wad] + } + + struct Ilk { + uint256 Art; // Total Normalised Debt [wad] + uint256 rate; // Accumulated Rates [ray] + uint256 spot; // Price with Safety Margin [ray] + uint256 line; // Debt Ceiling [rad] + uint256 dust; // Urn Debt Floor [rad] + } + + mapping(bytes32 => mapping(address => Urn)) public urns; + mapping(bytes32 => Ilk) public ilks; + mapping(bytes32 => mapping(address => uint256)) public gem; // [wad] + + function can(address, address) public view virtual returns (uint256); + function dai(address) public view virtual returns (uint256); + function frob(bytes32, address, address, address, int256, int256) public virtual; + function hope(address) public virtual; + function nope(address) public virtual; + function move(address, address, uint256) public virtual; + function fork(bytes32, address, address, int256, int256) public virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorpho.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorpho.sol new file mode 100644 index 0000000..b3d3eae --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorpho.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GNU AGPLv3 +pragma solidity ^0.8.0; + +import "./MorphoTypes.sol"; + +interface IMorpho { + /// STORAGE /// + + function NO_REFERRAL_CODE() external view returns (uint8); + function VARIABLE_INTEREST_MODE() external view returns (uint8); + function MAX_BASIS_POINTS() external view returns (uint16); + function DEFAULT_LIQUIDATION_CLOSE_FACTOR() external view returns (uint16); + function HEALTH_FACTOR_LIQUIDATION_THRESHOLD() external view returns (uint256); + function MAX_NB_OF_MARKETS() external view returns (uint256); + function BORROWING_MASK() external view returns (bytes32); + function ONE() external view returns (bytes32); + + function isClaimRewardsPaused() external view returns (bool); + function defaultMaxGasForMatching() external view returns (Types.MaxGasForMatching memory); + function maxSortedUsers() external view returns (uint256); + function supplyBalanceInOf( + address, + address + ) + external + view + returns (Types.SupplyBalance memory); + function borrowBalanceInOf( + address, + address + ) + external + view + returns (Types.BorrowBalance memory); + function deltas(address) external view returns (Types.Delta memory); + function market(address) external view returns (Types.Market memory); + function p2pSupplyIndex(address) external view returns (uint256); + function p2pBorrowIndex(address) external view returns (uint256); + function poolIndexes(address) external view returns (Types.PoolIndexes memory); + function interestRatesManager() external view returns (address); + function rewardsManager() external view returns (address); + function entryPositionsManager() external view returns (address); + function exitPositionsManager() external view returns (address); + function aaveIncentivesController() external view returns (address); + function addressesProvider() external view returns (address); + function incentivesVault() external view returns (address); + function pool() external view returns (address); + function treasuryVault() external view returns (address); + function borrowMask(address) external view returns (bytes32); + function userMarkets(address) external view returns (bytes32); + + /// UTILS /// + + function updateIndexes(address _poolToken) external; + + /// GETTERS /// + + function getMarketsCreated() external view returns (address[] memory marketsCreated_); + function getHead( + address _poolToken, + Types.PositionType _positionType + ) + external + view + returns (address head); + function getNext( + address _poolToken, + Types.PositionType _positionType, + address _user + ) + external + view + returns (address next); + + /// GOVERNANCE /// + + function setMaxSortedUsers(uint256 _newMaxSortedUsers) external; + function setDefaultMaxGasForMatching(Types.MaxGasForMatching memory _maxGasForMatching) + external; + function setTreasuryVault(address _newTreasuryVaultAddress) external; + function setIncentivesVault(address _newIncentivesVault) external; + function setRewardsManager(address _rewardsManagerAddress) external; + function setP2PDisabledStatus(address _poolToken, bool _isP2PDisabled) external; + function setReserveFactor(address _poolToken, uint256 _newReserveFactor) external; + function setP2PIndexCursor(address _poolToken, uint16 _p2pIndexCursor) external; + function setPauseStatusForAllMarkets(bool _newStatus) external; + function setClaimRewardsPauseStatus(bool _newStatus) external; + function setPauseStatus(address _poolToken, bool _newStatus) external; + function setPartialPauseStatus(address _poolToken, bool _newStatus) external; + function setExitPositionsManager(address _exitPositionsManager) external; + function setEntryPositionsManager(address _entryPositionsManager) external; + function setInterestRatesManager(address _interestRatesManager) external; + function claimToTreasury( + address[] calldata _poolTokens, + uint256[] calldata _amounts + ) + external; + function createMarket( + address _underlyingToken, + uint16 _reserveFactor, + uint16 _p2pIndexCursor + ) + external; + + /// USERS /// + + function supply(address _poolToken, uint256 _amount) external; + function supply(address _poolToken, address _onBehalf, uint256 _amount) external; + function supply( + address _poolToken, + address _onBehalf, + uint256 _amount, + uint256 _maxGasForMatching + ) + external; + function borrow(address _poolToken, uint256 _amount) external; + function borrow(address _poolToken, uint256 _amount, uint256 _maxGasForMatching) external; + function withdraw(address _poolToken, uint256 _amount) external; + function withdraw(address _poolToken, uint256 _amount, address _receiver) external; + function repay(address _poolToken, uint256 _amount) external; + function repay(address _poolToken, address _onBehalf, uint256 _amount) external; + function liquidate( + address _poolTokenBorrowed, + address _poolTokenCollateral, + address _borrower, + uint256 _amount + ) + external; + function claimRewards( + address[] calldata _assets, + bool _tradeForMorphoToken + ) + external + returns (uint256 claimedAmount); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV2Lens.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV2Lens.sol new file mode 100644 index 0000000..0630363 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV2Lens.sol @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GNU AGPLv3 +pragma solidity >=0.8.0; + +import "./MorphoTypes.sol"; + +interface IMorphoAaveV2Lens { + /// STORAGE /// + + function DEFAULT_LIQUIDATION_CLOSE_FACTOR() external view returns (uint16); + + function HEALTH_FACTOR_LIQUIDATION_THRESHOLD() external view returns (uint256); + + function ST_ETH() external view returns (address); + + function ST_ETH_BASE_REBASE_INDEX() external view returns (uint256); + + function morpho() external view returns (address); + + function addressesProvider() external view returns (address); + + function pool() external view returns (address); + + /// GENERAL /// + + function getTotalSupply() + external + view + returns (uint256 p2pSupplyAmount, uint256 poolSupplyAmount, uint256 totalSupplyAmount); + + function getTotalBorrow() + external + view + returns (uint256 p2pBorrowAmount, uint256 poolBorrowAmount, uint256 totalBorrowAmount); + + /// MARKETS /// + + function isMarketCreated(address _poolToken) external view returns (bool); + + /// @dev Deprecated. + function isMarketCreatedAndNotPaused(address _poolToken) external view returns (bool); + + /// @dev Deprecated. + function isMarketCreatedAndNotPausedNorPartiallyPaused(address _poolToken) + external + view + returns (bool); + + function getAllMarkets() external view returns (address[] memory marketsCreated_); + + function getMainMarketData(address _poolToken) + external + view + returns ( + uint256 avgSupplyRatePerYear, + uint256 avgBorrowRatePerYear, + uint256 p2pSupplyAmount, + uint256 p2pBorrowAmount, + uint256 poolSupplyAmount, + uint256 poolBorrowAmount + ); + + function getAdvancedMarketData(address _poolToken) + external + view + returns ( + Types.Indexes memory indexes, + uint32 lastUpdateTimestamp, + uint256 p2pSupplyDelta, + uint256 p2pBorrowDelta + ); + + function getMarketConfiguration(address _poolToken) + external + view + returns ( + address underlying, + bool isCreated, + bool isP2PDisabled, + bool isPaused, + bool isPartiallyPaused, + uint16 reserveFactor, + uint16 p2pIndexCursor, + uint256 loanToValue, + uint256 liquidationThreshold, + uint256 liquidationBonus, + uint256 decimals + ); + + function getMarketPauseStatus(address _poolToken) + external + view + returns (Types.MarketPauseStatus memory); + + function getTotalMarketSupply(address _poolToken) + external + view + returns (uint256 p2pSupplyAmount, uint256 poolSupplyAmount); + + function getTotalMarketBorrow(address _poolToken) + external + view + returns (uint256 p2pBorrowAmount, uint256 poolBorrowAmount); + + /// INDEXES /// + + function getCurrentP2PSupplyIndex(address _poolToken) external view returns (uint256); + + function getCurrentP2PBorrowIndex(address _poolToken) external view returns (uint256); + + function getIndexes(address _poolToken) external view returns (Types.Indexes memory indexes); + + /// USERS /// + + function getEnteredMarkets(address _user) + external + view + returns (address[] memory enteredMarkets); + + function getUserHealthFactor(address _user) external view returns (uint256 healthFactor); + + function getUserBalanceStates(address _user) + external + view + returns (Types.LiquidityData memory assetData); + + function getCurrentSupplyBalanceInOf( + address _poolToken, + address _user + ) + external + view + returns (uint256 balanceInP2P, uint256 balanceOnPool, uint256 totalBalance); + + function getCurrentBorrowBalanceInOf( + address _poolToken, + address _user + ) + external + view + returns (uint256 balanceInP2P, uint256 balanceOnPool, uint256 totalBalance); + + function getUserMaxCapacitiesForAsset( + address _user, + address _poolToken + ) + external + view + returns (uint256 withdrawable, uint256 borrowable); + + function getUserHypotheticalBalanceStates( + address _user, + address _poolToken, + uint256 _withdrawnAmount, + uint256 _borrowedAmount + ) + external + view + returns (Types.LiquidityData memory assetData); + + function getUserHypotheticalHealthFactor( + address _user, + address _poolToken, + uint256 _withdrawnAmount, + uint256 _borrowedAmount + ) + external + view + returns (uint256 healthFactor); + + function getUserLiquidityDataForAsset( + address _user, + address _poolToken, + address _oracle + ) + external + view + returns (Types.AssetLiquidityData memory assetData); + + function isLiquidatable(address _user) external view returns (bool); + + function isLiquidatable(address _user, address _poolToken) external view returns (bool); + + function computeLiquidationRepayAmount( + address _user, + address _poolTokenBorrowed, + address _poolTokenCollateral + ) + external + view + returns (uint256 toRepay); + + /// RATES /// + + function getNextUserSupplyRatePerYear( + address _poolToken, + address _user, + uint256 _amount + ) + external + view + returns ( + uint256 nextSupplyRatePerYear, + uint256 balanceInP2P, + uint256 balanceOnPool, + uint256 totalBalance + ); + + function getNextUserBorrowRatePerYear( + address _poolToken, + address _user, + uint256 _amount + ) + external + view + returns ( + uint256 nextBorrowRatePerYear, + uint256 balanceInP2P, + uint256 balanceOnPool, + uint256 totalBalance + ); + + function getCurrentUserSupplyRatePerYear( + address _poolToken, + address _user + ) + external + view + returns (uint256); + + function getCurrentUserBorrowRatePerYear( + address _poolToken, + address _user + ) + external + view + returns (uint256); + + function getAverageSupplyRatePerYear(address _poolToken) + external + view + returns (uint256 avgSupplyRatePerYear, uint256 p2pSupplyAmount, uint256 poolSupplyAmount); + + function getAverageBorrowRatePerYear(address _poolToken) + external + view + returns (uint256 avgBorrowRatePerYear, uint256 p2pBorrowAmount, uint256 poolBorrowAmount); + + function getRatesPerYear(address _poolToken) + external + view + returns ( + uint256 p2pSupplyRate, + uint256 p2pBorrowRate, + uint256 poolSupplyRate, + uint256 poolBorrowRate + ); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV3.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV3.sol new file mode 100644 index 0000000..c61d211 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV3.sol @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.10; + +import { Types } from "./MorphoTypesAaveV3.sol"; + +interface IMorphoGetters { + function DOMAIN_SEPARATOR() external view returns (bytes32); + function pool() external view returns (address); + function addressesProvider() external view returns (address); + function eModeCategoryId() external view returns (uint256); + + function market(address underlying) external view returns (Types.Market memory); + function marketsCreated() external view returns (address[] memory); + + function scaledCollateralBalance( + address underlying, + address user + ) + external + view + returns (uint256); + function scaledP2PBorrowBalance( + address underlying, + address user + ) + external + view + returns (uint256); + function scaledP2PSupplyBalance( + address underlying, + address user + ) + external + view + returns (uint256); + function scaledPoolBorrowBalance( + address underlying, + address user + ) + external + view + returns (uint256); + function scaledPoolSupplyBalance( + address underlying, + address user + ) + external + view + returns (uint256); + + function supplyBalance(address underlying, address user) external view returns (uint256); + function borrowBalance(address underlying, address user) external view returns (uint256); + function collateralBalance(address underlying, address user) external view returns (uint256); + + function userCollaterals(address user) external view returns (address[] memory); + function userBorrows(address user) external view returns (address[] memory); + + function isManaging(address delegator, address manager) external view returns (bool); + function userNonce(address user) external view returns (uint256); + + function defaultIterations() external view returns (Types.Iterations memory); + function positionsManager() external view returns (address); + function rewardsManager() external view returns (address); + function treasuryVault() external view returns (address); + + function isClaimRewardsPaused() external view returns (bool); + + function updatedIndexes(address underlying) external view returns (Types.Indexes256 memory); + function liquidityData(address user) external view returns (Types.LiquidityData memory); + function getNext( + address underlying, + Types.Position position, + address user + ) + external + view + returns (address); + function getBucketsMask( + address underlying, + Types.Position position + ) + external + view + returns (uint256); +} + +interface IMorphoSetters { + function createMarket( + address underlying, + uint16 reserveFactor, + uint16 p2pIndexCursor + ) + external; + function increaseP2PDeltas(address underlying, uint256 amount) external; + function claimToTreasury(address[] calldata underlyings, uint256[] calldata amounts) external; + + function setPositionsManager(address positionsManager) external; + function setRewardsManager(address rewardsManager) external; + function setTreasuryVault(address treasuryVault) external; + function setDefaultIterations(Types.Iterations memory defaultIterations) external; + function setP2PIndexCursor(address underlying, uint16 p2pIndexCursor) external; + function setReserveFactor(address underlying, uint16 newReserveFactor) external; + + function setIsClaimRewardsPaused(bool isPaused) external; + function setIsPaused(address underlying, bool isPaused) external; + function setIsPausedForAllMarkets(bool isPaused) external; + function setIsSupplyPaused(address underlying, bool isPaused) external; + function setIsSupplyCollateralPaused(address underlying, bool isPaused) external; + function setIsBorrowPaused(address underlying, bool isPaused) external; + function setIsRepayPaused(address underlying, bool isPaused) external; + function setIsWithdrawPaused(address underlying, bool isPaused) external; + function setIsWithdrawCollateralPaused(address underlying, bool isPaused) external; + function setIsLiquidateBorrowPaused(address underlying, bool isPaused) external; + function setIsLiquidateCollateralPaused(address underlying, bool isPaused) external; + function setIsP2PDisabled(address underlying, bool isP2PDisabled) external; + function setIsDeprecated(address underlying, bool isDeprecated) external; +} + +interface IMorphoAaveV3 is IMorphoGetters, IMorphoSetters { + function initialize( + address addressesProvider, + uint8 eModeCategoryId, + address newPositionsManager, + Types.Iterations memory newDefaultIterations + ) + external; + + function supply( + address underlying, + uint256 amount, + address onBehalf, + uint256 maxIterations + ) + external + returns (uint256 supplied); + function supplyWithPermit( + address underlying, + uint256 amount, + address onBehalf, + uint256 maxIterations, + uint256 deadline, + Types.Signature calldata signature + ) + external + returns (uint256 supplied); + function supplyCollateral( + address underlying, + uint256 amount, + address onBehalf + ) + external + returns (uint256 supplied); + function supplyCollateralWithPermit( + address underlying, + uint256 amount, + address onBehalf, + uint256 deadline, + Types.Signature calldata signature + ) + external + returns (uint256 supplied); + + function borrow( + address underlying, + uint256 amount, + address onBehalf, + address receiver, + uint256 maxIterations + ) + external + returns (uint256 borrowed); + + function repay( + address underlying, + uint256 amount, + address onBehalf + ) + external + returns (uint256 repaid); + function repayWithPermit( + address underlying, + uint256 amount, + address onBehalf, + uint256 deadline, + Types.Signature calldata signature + ) + external + returns (uint256 repaid); + + function withdraw( + address underlying, + uint256 amount, + address onBehalf, + address receiver, + uint256 maxIterations + ) + external + returns (uint256 withdrawn); + function withdrawCollateral( + address underlying, + uint256 amount, + address onBehalf, + address receiver + ) + external + returns (uint256 withdrawn); + + function approveManager(address manager, bool isAllowed) external; + function approveManagerWithSig( + address delegator, + address manager, + bool isAllowed, + uint256 nonce, + uint256 deadline, + Types.Signature calldata signature + ) + external; + + function isManagedBy(address delegator, address manager) external view returns (bool); + + function liquidate( + address underlyingBorrowed, + address underlyingCollateral, + address user, + uint256 amount + ) + external + returns (uint256 repaid, uint256 seized); + + function claimRewards( + address[] calldata assets, + address onBehalf + ) + external + returns (address[] memory rewardTokens, uint256[] memory claimedAmounts); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IRewardsDistributor.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IRewardsDistributor.sol new file mode 100644 index 0000000..676f222 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IRewardsDistributor.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IRewardsDistributor { + function claimed(address account) external view returns (uint256); + + function claim(address _account, uint256 _claimable, bytes32[] calldata _proof) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypes.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypes.sol new file mode 100644 index 0000000..6879fc1 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypes.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GNU AGPLv3 +pragma solidity ^0.8.0; + +/// @title Types. +/// @author Morpho Labs. +/// @custom:contact security@morpho.xyz +/// @dev Common types and structs used in Morpho contracts. +library Types { + /// ENUMS /// + + enum PositionType { + SUPPLIERS_IN_P2P, + SUPPLIERS_ON_POOL, + BORROWERS_IN_P2P, + BORROWERS_ON_POOL + } + + /// STRUCTS /// + + struct SupplyBalance { + uint256 inP2P; // In peer-to-peer supply scaled unit, a unit that grows in underlying value, + // to keep track of the interests earned by suppliers in peer-to-peer. Multiply by the + // peer-to-peer supply index to get the underlying amount. + uint256 onPool; // In pool supply scaled unit. Multiply by the pool supply index to get the + // underlying amount. + } + + struct BorrowBalance { + uint256 inP2P; // In peer-to-peer borrow scaled unit, a unit that grows in underlying value, + // to keep track of the interests paid by borrowers in peer-to-peer. Multiply by the + // peer-to-peer borrow index to get the underlying amount. + uint256 onPool; // In pool borrow scaled unit, a unit that grows in value, to keep track of + // the debt increase when borrowers are on Aave. Multiply by the pool borrow index to + // get the underlying amount. + } + + struct Indexes { + uint256 p2pSupplyIndex; // The peer-to-peer supply index (in ray), used to multiply the + // scaled peer-to-peer supply balance and get the peer-to-peer supply balance (in + // underlying). + uint256 p2pBorrowIndex; // The peer-to-peer borrow index (in ray), used to multiply the + // scaled peer-to-peer borrow balance and get the peer-to-peer borrow balance (in + // underlying). + uint256 poolSupplyIndex; // The pool supply index (in ray), used to multiply the scaled pool + // supply balance and get the pool supply balance (in underlying). + uint256 poolBorrowIndex; // The pool borrow index (in ray), used to multiply the scaled pool + // borrow balance and get the pool borrow balance (in underlying). + } + + // Max gas to consume during the matching process for supply, borrow, withdraw and repay + // functions. + struct MaxGasForMatching { + uint64 supply; + uint64 borrow; + uint64 withdraw; + uint64 repay; + } + + struct Delta { + uint256 p2pSupplyDelta; // Difference between the stored peer-to-peer supply amount and the + // real peer-to-peer supply amount (in pool supply unit). + uint256 p2pBorrowDelta; // Difference between the stored peer-to-peer borrow amount and the + // real peer-to-peer borrow amount (in pool borrow unit). + uint256 p2pSupplyAmount; // Sum of all stored peer-to-peer supply (in peer-to-peer supply + // unit). + uint256 p2pBorrowAmount; // Sum of all stored peer-to-peer borrow (in peer-to-peer borrow + // unit). + } + + struct AssetLiquidityData { + uint256 decimals; // The number of decimals of the underlying token. + uint256 tokenUnit; // The token unit considering its decimals. + uint256 liquidationThreshold; // The liquidation threshold applied on this token (in basis + // point). + uint256 ltv; // The LTV applied on this token (in basis point). + uint256 underlyingPrice; // The price of the token (in ETH). + uint256 collateralEth; // The collateral value of the asset (in ETH). + uint256 debtEth; // The debt value of the asset (in ETH). + } + + struct LiquidityData { + uint256 collateralEth; // The collateral value (in ETH). + uint256 borrowableEth; // The maximum debt value allowed to borrow (in ETH). + uint256 maxDebtEth; // The maximum debt value allowed before being liquidatable (in ETH). + uint256 debtEth; // The debt value (in ETH). + } + + // Variables are packed together to save gas (will not exceed their limit during Morpho's + // lifetime). + struct PoolIndexes { + uint32 lastUpdateTimestamp; // The last time the local pool and peer-to-peer indexes were + // updated. + uint112 poolSupplyIndex; // Last pool supply index. Note that for the stEth market, the pool + // supply index is tweaked to take into account the staking rewards. + uint112 poolBorrowIndex; // Last pool borrow index. Note that for the stEth market, the pool + // borrow index is tweaked to take into account the staking rewards. + } + + struct Market { + address underlyingToken; // The address of the market's underlying token. + uint16 reserveFactor; // Proportion of the additional interest earned being matched + // peer-to-peer on Morpho compared to being on the pool. It is sent to the DAO for each + // market. The default value is 0. In basis point (100% = 10 000). + uint16 p2pIndexCursor; // Position of the peer-to-peer rate in the pool's spread. Determine + // the weights of the weighted arithmetic average in the indexes computations ((1 - + // p2pIndexCursor) * r^S + p2pIndexCursor * r^B) (in basis point). + bool isCreated; // Whether or not this market is created. + bool isPaused; // Deprecated. + bool isPartiallyPaused; // Deprecated. + bool isP2PDisabled; // Whether the peer-to-peer market is open or not. + } + + struct MarketPauseStatus { + bool isSupplyPaused; // Whether the supply is paused or not. + bool isBorrowPaused; // Whether the borrow is paused or not + bool isWithdrawPaused; // Whether the withdraw is paused or not. Note that a "withdraw" is + // still possible using a liquidation (if not paused). + bool isRepayPaused; // Whether the repay is paused or not. Note that a "repay" is still + // possible using a liquidation (if not paused). + bool isLiquidateCollateralPaused; // Whether the liquidation on this market as collateral is + // paused or not. + bool isLiquidateBorrowPaused; // Whether the liquidatation on this market as borrow is + // paused or not. + bool isDeprecated; // Whether a market is deprecated or not. + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypesAaveV3.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypesAaveV3.sol new file mode 100644 index 0000000..707d712 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypesAaveV3.sol @@ -0,0 +1,991 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.10; + +library BucketDLL { + /// STRUCTS /// + + struct Account { + address prev; + address next; + } + + struct List { + mapping(address => Account) accounts; + } + + /// INTERNAL /// + + /// @notice Returns the address at the head of the `_list`. + /// @param _list The list from which to get the head. + /// @return The address of the head. + function getHead(List storage _list) internal view returns (address) { + return _list.accounts[address(0)].next; + } + + /// @notice Returns the address at the tail of the `_list`. + /// @param _list The list from which to get the tail. + /// @return The address of the tail. + function getTail(List storage _list) internal view returns (address) { + return _list.accounts[address(0)].prev; + } + + /// @notice Returns the next id address from the current `_id`. + /// @param _list The list to search in. + /// @param _id The address of the current account. + /// @return The address of the next account. + function getNext(List storage _list, address _id) internal view returns (address) { + return _list.accounts[_id].next; + } + + /// @notice Returns the previous id address from the current `_id`. + /// @param _list The list to search in. + /// @param _id The address of the current account. + /// @return The address of the previous account. + function getPrev(List storage _list, address _id) internal view returns (address) { + return _list.accounts[_id].prev; + } + + /// @notice Removes an account of the `_list`. + /// @dev This function should not be called with `_id` equal to address 0. + /// @param _list The list to search in. + /// @param _id The address of the account. + /// @return Whether the bucket is empty after removal. + function remove(List storage _list, address _id) internal returns (bool) { + Account memory account = _list.accounts[_id]; + address prev = account.prev; + address next = account.next; + + _list.accounts[prev].next = next; + _list.accounts[next].prev = prev; + + delete _list.accounts[_id]; + + return (prev == address(0) && next == address(0)); + } + + /// @notice Inserts an account in the `_list`. + /// @dev This function should not be called with `_id` equal to address 0. + /// @param _list The list to search in. + /// @param _id The address of the account. + /// @param _head Tells whether to insert at the head or at the tail of the list. + /// @return Whether the bucket was empty before insertion. + function insert(List storage _list, address _id, bool _head) internal returns (bool) { + if (_head) { + address head = _list.accounts[address(0)].next; + _list.accounts[address(0)].next = _id; + _list.accounts[head].prev = _id; + _list.accounts[_id].next = head; + return head == address(0); + } else { + address tail = _list.accounts[address(0)].prev; + _list.accounts[address(0)].prev = _id; + _list.accounts[tail].next = _id; + _list.accounts[_id].prev = tail; + return tail == address(0); + } + } +} + +library LogarithmicBuckets { + using BucketDLL for BucketDLL.List; + + struct Buckets { + mapping(uint256 => BucketDLL.List) buckets; + mapping(address => uint256) valueOf; + uint256 bucketsMask; + } + + /// ERRORS /// + + /// @notice Thrown when the address is zero at insertion. + error ZeroAddress(); + + /// @notice Thrown when 0 value is inserted. + error ZeroValue(); + + /// INTERNAL /// + + /// @notice Updates an account in the `_buckets`. + /// @param _buckets The buckets to update. + /// @param _id The address of the account. + /// @param _newValue The new value of the account. + /// @param _head Indicates whether to insert the new values at the head or at the tail of the + /// buckets list. + function update( + Buckets storage _buckets, + address _id, + uint256 _newValue, + bool _head + ) + internal + { + if (_id == address(0)) revert ZeroAddress(); + uint256 value = _buckets.valueOf[_id]; + _buckets.valueOf[_id] = _newValue; + + if (value == 0) { + if (_newValue == 0) revert ZeroValue(); + _insert(_buckets, _id, computeBucket(_newValue), _head); + return; + } + + uint256 currentBucket = computeBucket(value); + if (_newValue == 0) { + _remove(_buckets, _id, currentBucket); + return; + } + + uint256 newBucket = computeBucket(_newValue); + if (newBucket != currentBucket) { + _remove(_buckets, _id, currentBucket); + _insert(_buckets, _id, newBucket, _head); + } + } + + /// @notice Returns the address in `_buckets` that is a candidate for matching the value + /// `_value`. + /// @param _buckets The buckets to get the head. + /// @param _value The value to match. + /// @return The address of the head. + function getMatch(Buckets storage _buckets, uint256 _value) internal view returns (address) { + uint256 bucketsMask = _buckets.bucketsMask; + if (bucketsMask == 0) return address(0); + uint256 lowerMask = setLowerBits(_value); + + uint256 next = nextBucket(lowerMask, bucketsMask); + + if (next != 0) return _buckets.buckets[next].getHead(); + + uint256 prev = prevBucket(lowerMask, bucketsMask); + + return _buckets.buckets[prev].getHead(); + } + + /// PRIVATE /// + + /// @notice Removes an account in the `_buckets`. + /// @dev Does not update the value. + /// @param _buckets The buckets to modify. + /// @param _id The address of the account to remove. + /// @param _bucket The mask of the bucket where to remove. + function _remove(Buckets storage _buckets, address _id, uint256 _bucket) private { + if (_buckets.buckets[_bucket].remove(_id)) _buckets.bucketsMask &= ~_bucket; + } + + /// @notice Inserts an account in the `_buckets`. + /// @dev Expects that `_id` != 0. + /// @dev Does not update the value. + /// @param _buckets The buckets to modify. + /// @param _id The address of the account to update. + /// @param _bucket The mask of the bucket where to insert. + /// @param _head Whether to insert at the head or at the tail of the list. + function _insert(Buckets storage _buckets, address _id, uint256 _bucket, bool _head) private { + if (_buckets.buckets[_bucket].insert(_id, _head)) _buckets.bucketsMask |= _bucket; + } + + /// PURE HELPERS /// + + /// @notice Returns the bucket in which the given value would fall. + function computeBucket(uint256 _value) internal pure returns (uint256) { + uint256 lowerMask = setLowerBits(_value); + return lowerMask ^ (lowerMask >> 1); + } + + /// @notice Sets all the bits lower than (or equal to) the highest bit in the input. + /// @dev This is the same as rounding the input the nearest upper value of the form `2 ** n - + /// 1`. + function setLowerBits(uint256 x) internal pure returns (uint256 y) { + assembly { + x := or(x, shr(1, x)) + x := or(x, shr(2, x)) + x := or(x, shr(4, x)) + x := or(x, shr(8, x)) + x := or(x, shr(16, x)) + x := or(x, shr(32, x)) + x := or(x, shr(64, x)) + y := or(x, shr(128, x)) + } + } + + /// @notice Returns the following bucket which contains greater values. + /// @dev The bucket returned is the lowest that is in `bucketsMask` and not in `lowerMask`. + function nextBucket( + uint256 lowerMask, + uint256 bucketsMask + ) + internal + pure + returns (uint256 bucket) + { + assembly { + let higherBucketsMask := and(not(lowerMask), bucketsMask) + bucket := and(higherBucketsMask, add(not(higherBucketsMask), 1)) + } + } + + /// @notice Returns the preceding bucket which contains smaller values. + /// @dev The bucket returned is the highest that is in both `bucketsMask` and `lowerMask`. + function prevBucket(uint256 lowerMask, uint256 bucketsMask) internal pure returns (uint256) { + uint256 lowerBucketsMask = setLowerBits(lowerMask & bucketsMask); + return lowerBucketsMask ^ (lowerBucketsMask >> 1); + } +} + +library DataTypesAaveV3 { + struct ReserveData { + //stores the reserve configuration + ReserveConfigurationMap configuration; + //the liquidity index. Expressed in ray + uint128 liquidityIndex; + //the current supply rate. Expressed in ray + uint128 currentLiquidityRate; + //variable borrow index. Expressed in ray + uint128 variableBorrowIndex; + //the current variable borrow rate. Expressed in ray + uint128 currentVariableBorrowRate; + //the current stable borrow rate. Expressed in ray + uint128 currentStableBorrowRate; + //timestamp of last update + uint40 lastUpdateTimestamp; + //the id of the reserve. Represents the position in the list of the active reserves + uint16 id; + //aToken address + address aTokenAddress; + //stableDebtToken address + address stableDebtTokenAddress; + //variableDebtToken address + address variableDebtTokenAddress; + //address of the interest rate strategy + address interestRateStrategyAddress; + //the current treasury balance, scaled + uint128 accruedToTreasury; + //the outstanding unbacked aTokens minted through the bridging feature + uint128 unbacked; + //the outstanding debt borrowed against this asset in isolation mode + uint128 isolationModeTotalDebt; + } + + struct ReserveConfigurationMap { + //bit 0-15: LTV + //bit 16-31: Liq. threshold + //bit 32-47: Liq. bonus + //bit 48-55: Decimals + //bit 56: reserve is active + //bit 57: reserve is frozen + //bit 58: borrowing is enabled + //bit 59: stable rate borrowing enabled + //bit 60: asset is paused + //bit 61: borrowing in isolation mode is enabled + //bit 62-63: reserved + //bit 64-79: reserve factor + //bit 80-115 borrow cap in whole tokens, borrowCap == 0 => no cap + //bit 116-151 supply cap in whole tokens, supplyCap == 0 => no cap + //bit 152-167 liquidation protocol fee + //bit 168-175 eMode category + //bit 176-211 unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled + //bit 212-251 debt ceiling for isolation mode with + // (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals + //bit 252-255 unused + uint256 data; + } + + struct UserConfigurationMap { + /** + * @dev Bitmap of the users collaterals and borrows. It is divided in pairs of bits, one + * pair per asset. + * The first bit indicates if an asset is used as collateral by the user, the second whether + * an + * asset is borrowed by the user. + */ + uint256 data; + } + + struct EModeCategory { + // each eMode category has a custom ltv and liquidation threshold + uint16 ltv; + uint16 liquidationThreshold; + uint16 liquidationBonus; + // each eMode category may or may not have a custom oracle to override the individual assets + // price oracles + address priceSource; + string label; + } + + enum InterestRateMode { + NONE, + STABLE, + VARIABLE + } + + struct ReserveCache { + uint256 currScaledVariableDebt; + uint256 nextScaledVariableDebt; + uint256 currPrincipalStableDebt; + uint256 currAvgStableBorrowRate; + uint256 currTotalStableDebt; + uint256 nextAvgStableBorrowRate; + uint256 nextTotalStableDebt; + uint256 currLiquidityIndex; + uint256 nextLiquidityIndex; + uint256 currVariableBorrowIndex; + uint256 nextVariableBorrowIndex; + uint256 currLiquidityRate; + uint256 currVariableBorrowRate; + uint256 reserveFactor; + ReserveConfigurationMap reserveConfiguration; + address aTokenAddress; + address stableDebtTokenAddress; + address variableDebtTokenAddress; + uint40 reserveLastUpdateTimestamp; + uint40 stableDebtLastUpdateTimestamp; + } + + struct ExecuteLiquidationCallParams { + uint256 reservesCount; + uint256 debtToCover; + address collateralAsset; + address debtAsset; + address user; + bool receiveAToken; + address priceOracle; + uint8 userEModeCategory; + address priceOracleSentinel; + } + + struct ExecuteSupplyParams { + address asset; + uint256 amount; + address onBehalfOf; + uint16 referralCode; + } + + struct ExecuteBorrowParams { + address asset; + address user; + address onBehalfOf; + uint256 amount; + InterestRateMode interestRateMode; + uint16 referralCode; + bool releaseUnderlying; + uint256 maxStableRateBorrowSizePercent; + uint256 reservesCount; + address oracle; + uint8 userEModeCategory; + address priceOracleSentinel; + } + + struct ExecuteRepayParams { + address asset; + uint256 amount; + InterestRateMode interestRateMode; + address onBehalfOf; + bool useATokens; + } + + struct ExecuteWithdrawParams { + address asset; + uint256 amount; + address to; + uint256 reservesCount; + address oracle; + uint8 userEModeCategory; + } + + struct ExecuteSetUserEModeParams { + uint256 reservesCount; + address oracle; + uint8 categoryId; + } + + struct FinalizeTransferParams { + address asset; + address from; + address to; + uint256 amount; + uint256 balanceFromBefore; + uint256 balanceToBefore; + uint256 reservesCount; + address oracle; + uint8 fromEModeCategory; + } + + struct FlashloanParams { + address receiverAddress; + address[] assets; + uint256[] amounts; + uint256[] interestRateModes; + address onBehalfOf; + bytes params; + uint16 referralCode; + uint256 flashLoanPremiumToProtocol; + uint256 flashLoanPremiumTotal; + uint256 maxStableRateBorrowSizePercent; + uint256 reservesCount; + address addressesProvider; + uint8 userEModeCategory; + bool isAuthorizedFlashBorrower; + } + + struct FlashloanSimpleParams { + address receiverAddress; + address asset; + uint256 amount; + bytes params; + uint16 referralCode; + uint256 flashLoanPremiumToProtocol; + uint256 flashLoanPremiumTotal; + } + + struct FlashLoanRepaymentParams { + uint256 amount; + uint256 totalPremium; + uint256 flashLoanPremiumToProtocol; + address asset; + address receiverAddress; + uint16 referralCode; + } + + struct CalculateUserAccountDataParams { + UserConfigurationMap userConfig; + uint256 reservesCount; + address user; + address oracle; + uint8 userEModeCategory; + } + + struct ValidateBorrowParams { + ReserveCache reserveCache; + UserConfigurationMap userConfig; + address asset; + address userAddress; + uint256 amount; + InterestRateMode interestRateMode; + uint256 maxStableLoanPercent; + uint256 reservesCount; + address oracle; + uint8 userEModeCategory; + address priceOracleSentinel; + bool isolationModeActive; + address isolationModeCollateralAddress; + uint256 isolationModeDebtCeiling; + } + + struct ValidateLiquidationCallParams { + ReserveCache debtReserveCache; + uint256 totalDebt; + uint256 healthFactor; + address priceOracleSentinel; + } + + struct CalculateInterestRatesParams { + uint256 unbacked; + uint256 liquidityAdded; + uint256 liquidityTaken; + uint256 totalStableDebt; + uint256 totalVariableDebt; + uint256 averageStableBorrowRate; + uint256 reserveFactor; + address reserve; + address aToken; + } + + struct InitReserveParams { + address asset; + address aTokenAddress; + address stableDebtAddress; + address variableDebtAddress; + address interestRateStrategyAddress; + uint16 reservesCount; + uint16 maxNumberReserves; + } +} + +interface IPriceOracleGetter { + /** + * @notice Returns the base currency address + * @dev Address 0x0 is reserved for USD as base currency. + * @return Returns the base currency address. + */ + function BASE_CURRENCY() external view returns (address); + + /** + * @notice Returns the base currency unit + * @dev 1 ether for ETH, 1e8 for USD. + * @return Returns the base currency unit. + */ + function BASE_CURRENCY_UNIT() external view returns (uint256); + + /** + * @notice Returns the asset price in the base currency + * @param asset The address of the asset + * @return The price of the asset + */ + function getAssetPrice(address asset) external view returns (uint256); +} + +interface IAavePoolAddressesProvider { + /** + * @dev Emitted when the market identifier is updated. + * @param oldMarketId The old id of the market + * @param newMarketId The new id of the market + */ + event MarketIdSet(string indexed oldMarketId, string indexed newMarketId); + + /** + * @dev Emitted when the pool is updated. + * @param oldAddress The old address of the Pool + * @param newAddress The new address of the Pool + */ + event PoolUpdated(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when the pool configurator is updated. + * @param oldAddress The old address of the PoolConfigurator + * @param newAddress The new address of the PoolConfigurator + */ + event PoolConfiguratorUpdated(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when the price oracle is updated. + * @param oldAddress The old address of the PriceOracle + * @param newAddress The new address of the PriceOracle + */ + event PriceOracleUpdated(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when the ACL manager is updated. + * @param oldAddress The old address of the ACLManager + * @param newAddress The new address of the ACLManager + */ + event ACLManagerUpdated(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when the ACL admin is updated. + * @param oldAddress The old address of the ACLAdmin + * @param newAddress The new address of the ACLAdmin + */ + event ACLAdminUpdated(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when the price oracle sentinel is updated. + * @param oldAddress The old address of the PriceOracleSentinel + * @param newAddress The new address of the PriceOracleSentinel + */ + event PriceOracleSentinelUpdated(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when the pool data provider is updated. + * @param oldAddress The old address of the PoolDataProvider + * @param newAddress The new address of the PoolDataProvider + */ + event PoolDataProviderUpdated(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when a new proxy is created. + * @param id The identifier of the proxy + * @param proxyAddress The address of the created proxy contract + * @param implementationAddress The address of the implementation contract + */ + event ProxyCreated( + bytes32 indexed id, address indexed proxyAddress, address indexed implementationAddress + ); + + /** + * @dev Emitted when a new non-proxied contract address is registered. + * @param id The identifier of the contract + * @param oldAddress The address of the old contract + * @param newAddress The address of the new contract + */ + event AddressSet(bytes32 indexed id, address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when the implementation of the proxy registered with id is updated + * @param id The identifier of the contract + * @param proxyAddress The address of the proxy contract + * @param oldImplementationAddress The address of the old implementation contract + * @param newImplementationAddress The address of the new implementation contract + */ + event AddressSetAsProxy( + bytes32 indexed id, + address indexed proxyAddress, + address oldImplementationAddress, + address indexed newImplementationAddress + ); + + /** + * @notice Returns the id of the Aave market to which this contract points to. + * @return The market id + */ + function getMarketId() external view returns (string memory); + + /** + * @notice Associates an id with a specific PoolAddressesProvider. + * @dev This can be used to create an onchain registry of PoolAddressesProviders to + * identify and validate multiple Aave markets. + * @param newMarketId The market id + */ + function setMarketId(string calldata newMarketId) external; + + /** + * @notice Returns an address by its identifier. + * @dev The returned address might be an EOA or a contract, potentially proxied + * @dev It returns ZERO if there is no registered address with the given id + * @param id The id + * @return The address of the registered for the specified id + */ + function getAddress(bytes32 id) external view returns (address); + + /** + * @notice General function to update the implementation of a proxy registered with + * certain `id`. If there is no proxy registered, it will instantiate one and + * set as implementation the `newImplementationAddress`. + * @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit + * setter function, in order to avoid unexpected consequences + * @param id The id + * @param newImplementationAddress The address of the new implementation + */ + function setAddressAsProxy(bytes32 id, address newImplementationAddress) external; + + /** + * @notice Sets an address for an id replacing the address saved in the addresses map. + * @dev IMPORTANT Use this function carefully, as it will do a hard replacement + * @param id The id + * @param newAddress The address to set + */ + function setAddress(bytes32 id, address newAddress) external; + + /** + * @notice Returns the address of the Pool proxy. + * @return The Pool proxy address + */ + function getPool() external view returns (address); + + /** + * @notice Updates the implementation of the Pool, or creates a proxy + * setting the new `pool` implementation when the function is called for the first time. + * @param newPoolImpl The new Pool implementation + */ + function setPoolImpl(address newPoolImpl) external; + + /** + * @notice Returns the address of the PoolConfigurator proxy. + * @return The PoolConfigurator proxy address + */ + function getPoolConfigurator() external view returns (address); + + /** + * @notice Updates the implementation of the PoolConfigurator, or creates a proxy + * setting the new `PoolConfigurator` implementation when the function is called for the first + * time. + * @param newPoolConfiguratorImpl The new PoolConfigurator implementation + */ + function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external; + + /** + * @notice Returns the address of the price oracle. + * @return The address of the PriceOracle + */ + function getPriceOracle() external view returns (address); + + /** + * @notice Updates the address of the price oracle. + * @param newPriceOracle The address of the new PriceOracle + */ + function setPriceOracle(address newPriceOracle) external; + + /** + * @notice Returns the address of the ACL manager. + * @return The address of the ACLManager + */ + function getACLManager() external view returns (address); + + /** + * @notice Updates the address of the ACL manager. + * @param newAclManager The address of the new ACLManager + */ + function setACLManager(address newAclManager) external; + + /** + * @notice Returns the address of the ACL admin. + * @return The address of the ACL admin + */ + function getACLAdmin() external view returns (address); + + /** + * @notice Updates the address of the ACL admin. + * @param newAclAdmin The address of the new ACL admin + */ + function setACLAdmin(address newAclAdmin) external; + + /** + * @notice Returns the address of the price oracle sentinel. + * @return The address of the PriceOracleSentinel + */ + function getPriceOracleSentinel() external view returns (address); + + /** + * @notice Updates the address of the price oracle sentinel. + * @param newPriceOracleSentinel The address of the new PriceOracleSentinel + */ + function setPriceOracleSentinel(address newPriceOracleSentinel) external; + + /** + * @notice Returns the address of the data provider. + * @return The address of the DataProvider + */ + function getPoolDataProvider() external view returns (address); + + /** + * @notice Updates the address of the data provider. + * @param newDataProvider The address of the new DataProvider + */ + function setPoolDataProvider(address newDataProvider) external; +} + +interface IAaveOracle is IPriceOracleGetter { + /** + * @dev Emitted after the base currency is set + * @param baseCurrency The base currency of used for price quotes + * @param baseCurrencyUnit The unit of the base currency + */ + event BaseCurrencySet(address indexed baseCurrency, uint256 baseCurrencyUnit); + + /** + * @dev Emitted after the price source of an asset is updated + * @param asset The address of the asset + * @param source The price source of the asset + */ + event AssetSourceUpdated(address indexed asset, address indexed source); + + /** + * @dev Emitted after the address of fallback oracle is updated + * @param fallbackOracle The address of the fallback oracle + */ + event FallbackOracleUpdated(address indexed fallbackOracle); + + /** + * @notice Returns the PoolAddressesProvider + * @return The address of the PoolAddressesProvider contract + */ + function ADDRESSES_PROVIDER() external view returns (IAavePoolAddressesProvider); + + /** + * @notice Sets or replaces price sources of assets + * @param assets The addresses of the assets + * @param sources The addresses of the price sources + */ + function setAssetSources(address[] calldata assets, address[] calldata sources) external; + + /** + * @notice Sets the fallback oracle + * @param fallbackOracle The address of the fallback oracle + */ + function setFallbackOracle(address fallbackOracle) external; + + /** + * @notice Returns a list of prices from a list of assets addresses + * @param assets The list of assets addresses + * @return The prices of the given assets + */ + function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory); + + /** + * @notice Returns the address of the source for an asset address + * @param asset The address of the asset + * @return The address of the source + */ + function getSourceOfAsset(address asset) external view returns (address); + + /** + * @notice Returns the address of the fallback oracle + * @return The address of the fallback oracle + */ + function getFallbackOracle() external view returns (address); +} + +/// @title Type +/// @author Morpho Labs +/// @custom:contact security@morpho.xyz +/// @notice Library exposing all Types used in Morpho. +library Types { + /* ENUMS */ + + enum Position { + POOL_SUPPLIER, + P2P_SUPPLIER, + POOL_BORROWER, + P2P_BORROWER + } + + /* NESTED STRUCTS */ + + struct MarketSideDelta { + uint256 scaledDelta; // In pool unit. + uint256 scaledP2PTotal; // In peer-to-peer unit. + } + + struct Deltas { + MarketSideDelta supply; + MarketSideDelta borrow; + } + + struct MarketSideIndexes { + uint128 poolIndex; + uint128 p2pIndex; + } + + struct Indexes { + MarketSideIndexes supply; + MarketSideIndexes borrow; + } + + struct PauseStatuses { + bool isP2PDisabled; + bool isSupplyPaused; + bool isSupplyCollateralPaused; + bool isBorrowPaused; + bool isWithdrawPaused; + bool isWithdrawCollateralPaused; + bool isRepayPaused; + bool isLiquidateCollateralPaused; + bool isLiquidateBorrowPaused; + bool isDeprecated; + } + + /* STORAGE STRUCTS */ + + // This market struct is able to be passed into memory. + struct Market { + // SLOT 0-1 + Indexes indexes; + // SLOT 2-5 + Deltas deltas; // 1024 bits + // SLOT 6 + address underlying; // 160 bits + PauseStatuses pauseStatuses; // 80 bits + bool isCollateral; // 8 bits + // SLOT 7 + address variableDebtToken; // 160 bits + uint32 lastUpdateTimestamp; // 32 bits + uint16 reserveFactor; // 16 bits + uint16 p2pIndexCursor; // 16 bits + // SLOT 8 + address aToken; // 160 bits + // SLOT 9 + address stableDebtToken; // 160 bits + // SLOT 10 + uint256 idleSupply; // 256 bits + } + + // Contains storage-only dynamic arrays and mappings. + struct MarketBalances { + LogarithmicBuckets.Buckets poolSuppliers; // In pool unit. + LogarithmicBuckets.Buckets p2pSuppliers; // In peer-to-peer unit. + LogarithmicBuckets.Buckets poolBorrowers; // In pool unit. + LogarithmicBuckets.Buckets p2pBorrowers; // In peer-to-peer unit. + mapping(address => uint256) collateral; // In pool unit. + } + + struct Iterations { + uint128 repay; + uint128 withdraw; + } + + /* STACK AND RETURN STRUCTS */ + + struct LiquidityData { + uint256 borrowable; // The maximum debt value allowed to borrow (in base currency). + uint256 maxDebt; // The maximum debt value allowed before being liquidatable (in base + // currency). + uint256 debt; // The debt value (in base currency). + } + + struct IndexesParams { + MarketSideIndexes256 lastSupplyIndexes; + MarketSideIndexes256 lastBorrowIndexes; + uint256 poolSupplyIndex; // The current pool supply index. + uint256 poolBorrowIndex; // The current pool borrow index. + uint256 reserveFactor; // The reserve factor percentage (10 000 = 100%). + uint256 p2pIndexCursor; // The peer-to-peer index cursor (10 000 = 100%). + Deltas deltas; // The deltas and peer-to-peer amounts. + uint256 proportionIdle; // in ray. + } + + struct GrowthFactors { + uint256 poolSupplyGrowthFactor; // The pool's supply index growth factor (in ray). + uint256 p2pSupplyGrowthFactor; // Peer-to-peer supply index growth factor (in ray). + uint256 poolBorrowGrowthFactor; // The pool's borrow index growth factor (in ray). + uint256 p2pBorrowGrowthFactor; // Peer-to-peer borrow index growth factor (in ray). + } + + struct MarketSideIndexes256 { + uint256 poolIndex; + uint256 p2pIndex; + } + + struct Indexes256 { + MarketSideIndexes256 supply; + MarketSideIndexes256 borrow; + } + + struct Signature { + uint8 v; + bytes32 r; + bytes32 s; + } + + struct MatchingEngineVars { + address underlying; + MarketSideIndexes256 indexes; + uint256 amount; + uint256 maxIterations; + bool borrow; + function (address, address, uint256, uint256, bool) returns (uint256, uint256) updateDS; // This + // function will be used to update the data-structure. + bool demoting; // True for demote, False for promote. + function(uint256, uint256, MarketSideIndexes256 memory, uint256) + pure returns (uint256, uint256, uint256) step; // This function will be used to decide + // whether to use the algorithm for promoting or for demoting. + } + + struct LiquidityVars { + address user; + IAaveOracle oracle; + DataTypesAaveV3.EModeCategory eModeCategory; + } + + struct PromoteVars { + address underlying; + uint256 amount; + uint256 p2pIndex; + uint256 maxIterations; + function(address, uint256, uint256) returns (uint256, uint256) promote; + } + + struct BorrowWithdrawVars { + uint256 onPool; + uint256 inP2P; + uint256 toWithdraw; + uint256 toBorrow; + } + + struct SupplyRepayVars { + uint256 onPool; + uint256 inP2P; + uint256 toSupply; + uint256 toRepay; + } + + struct LiquidateVars { + uint256 closeFactor; + uint256 seized; + } + + struct AmountToSeizeVars { + uint256 liquidationBonus; + uint256 borrowedTokenUnit; + uint256 collateralTokenUnit; + uint256 borrowedPrice; + uint256 collateralPrice; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/IBoostedVaultWithLockup.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/IBoostedVaultWithLockup.sol new file mode 100644 index 0000000..889bb64 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/IBoostedVaultWithLockup.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IBoostedVaultWithLockup { + function rawBalanceOf(address) external view returns (uint256); + + // @dev Stakes a given amount of the StakingToken for the sender + // @param _amount Units of StakingToken + function stake(uint256 _amount) external; + + // @dev Stakes a given amount of the StakingToken for a given beneficiary + // @param _beneficiary Staked tokens are credited to this address + // @param _amount Units of StakingToken + function stake(address _beneficiary, uint256 _amount) external; + + // @dev Withdraws stake from pool and claims any unlocked rewards. + // Note, this function is costly - the args for _claimRewards + // should be determined off chain and then passed to other fn + function exit() external; + + // @dev Withdraws stake from pool and claims any unlocked rewards. + // @param _first Index of the first array element to claim + // @param _last Index of the last array element to claim + function exit(uint256 _first, uint256 _last) external; + + // @dev Withdraws given stake amount from the pool + // @param _amount Units of the staked token to withdraw + function withdraw(uint256 _amount) external; + + // @dev Claims only the tokens that have been immediately unlocked, not including + // those that are in the lockers. + function claimReward() external; + + // @dev Claims all unlocked rewards for sender. + // Note, this function is costly - the args for _claimRewards + // should be determined off chain and then passed to other fn + function claimRewards() external; + + // @dev Claims all unlocked rewards for sender. Both immediately unlocked + // rewards and also locked rewards past their time lock. + // @param _first Index of the first array element to claim + // @param _last Index of the last array element to claim + function claimRewards(uint256 _first, uint256 _last) external; + + // @dev Pokes a given account to reset the boost + function pokeBoost(address _account) external; + + // @dev Gets the RewardsToken + function getRewardToken() external view returns (address); + + // @dev Gets the last applicable timestamp for this reward period + function lastTimeRewardApplicable() external view returns (uint256); + + // @dev Calculates the amount of unclaimed rewards per token since last update, + // and sums with stored to give the new cumulative reward per token + // @return 'Reward' per staked token + function rewardPerToken() external view returns (uint256); + + // @dev Returned the units of IMMEDIATELY claimable rewards a user has to receive. Note - this + // does NOT include the majority of rewards which will be locked up. + // @param _account User address + // @return Total reward amount earned + function earned(address _account) external view returns (uint256); + + // @dev Calculates all unclaimed reward data, finding both immediately unlocked rewards + // and those that have passed their time lock. + // @param _account User address + // @return amount Total units of unclaimed rewards + // @return first Index of the first userReward that has unlocked + // @return last Index of the last userReward that has unlocked + function unclaimedRewards(address _account) + external + view + returns (uint256 amount, uint256 first, uint256 last); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ISavingsContractV2.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ISavingsContractV2.sol new file mode 100644 index 0000000..6410152 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ISavingsContractV2.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface ISavingsContractV2 { + // DEPRECATED but still backwards compatible + function redeem(uint256 _amount) external returns (uint256 massetReturned); + + function creditBalances(address) external view returns (uint256); // V1 & V2 (use balanceOf) + + // -------------------------------------------- + + function approve(address, uint256) external; + function depositInterest(uint256 _amount) external; // V1 & V2 + + function depositSavings(uint256 _amount) external returns (uint256 creditsIssued); // V1 & V2 + + function depositSavings( + uint256 _amount, + address _beneficiary + ) + external + returns (uint256 creditsIssued); // V2 + + function redeemCredits(uint256 _amount) external returns (uint256 underlyingReturned); // V2 + + function redeemUnderlying(uint256 _amount) external returns (uint256 creditsBurned); // V2 + + function exchangeRate() external view returns (uint256); // V1 & V2 + + function balanceOfUnderlying(address _user) external view returns (uint256 balance); // V2 + + function underlyingToCredits(uint256 _credits) external view returns (uint256 underlying); // V2 + + function creditsToUnderlying(uint256 _underlying) external view returns (uint256 credits); // V2 +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ImAsset.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ImAsset.sol new file mode 100644 index 0000000..40c96cb --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ImAsset.sol @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; +pragma experimental ABIEncoderV2; + +// Status of the Basset - has it broken its peg? +enum BassetStatus { + Default, + Normal, + BrokenBelowPeg, + BrokenAbovePeg, + Blacklisted, + Liquidating, + Liquidated, + Failed +} + +struct BassetPersonal { + // Address of the bAsset + address addr; + // Address of the bAsset + address integrator; + // An ERC20 can charge transfer fee, for example USDT, DGX tokens. + bool hasTxFee; // takes a byte in storage + // Status of the bAsset + BassetStatus status; +} + +struct BassetData { + // 1 Basset * ratio / ratioScale == x Masset (relative value) + // If ratio == 10e8 then 1 bAsset = 10 mAssets + // A ratio is divised as 10^(18-tokenDecimals) * measurementMultiple(relative value of 1 base + // unit) + uint128 ratio; + // Amount of the Basset that is held in Collateral + uint128 vaultBalance; +} + +interface ImAsset { + // Mint + function mint( + address _input, + uint256 _inputQuantity, + uint256 _minOutputQuantity, + address _recipient + ) + external + returns (uint256 mintOutput); + + function mintMulti( + address[] calldata _inputs, + uint256[] calldata _inputQuantities, + uint256 _minOutputQuantity, + address _recipient + ) + external + returns (uint256 mintOutput); + + function getMintOutput( + address _input, + uint256 _inputQuantity + ) + external + view + returns (uint256 mintOutput); + + function getMintMultiOutput( + address[] calldata _inputs, + uint256[] calldata _inputQuantities + ) + external + view + returns (uint256 mintOutput); + + // Swaps + function swap( + address _input, + address _output, + uint256 _inputQuantity, + uint256 _minOutputQuantity, + address _recipient + ) + external + returns (uint256 swapOutput); + + function getSwapOutput( + address _input, + address _output, + uint256 _inputQuantity + ) + external + view + returns (uint256 swapOutput); + + // Redemption + function redeem( + address _output, + uint256 _mAssetQuantity, + uint256 _minOutputQuantity, + address _recipient + ) + external + returns (uint256 outputQuantity); + + function redeemMasset( + uint256 _mAssetQuantity, + uint256[] calldata _minOutputQuantities, + address _recipient + ) + external + returns (uint256[] memory outputQuantities); + + function redeemExactBassets( + address[] calldata _outputs, + uint256[] calldata _outputQuantities, + uint256 _maxMassetQuantity, + address _recipient + ) + external + returns (uint256 mAssetRedeemed); + + function getRedeemOutput( + address _output, + uint256 _mAssetQuantity + ) + external + view + returns (uint256 bAssetOutput); + + function getRedeemExactBassetsOutput( + address[] calldata _outputs, + uint256[] calldata _outputQuantities + ) + external + view + returns (uint256 mAssetAmount); + + // Views + function getBasket() external view returns (bool, bool); + + function getBasset(address _token) + external + view + returns (BassetPersonal memory personal, BassetData memory data); + + function getBassets() + external + view + returns (BassetPersonal[] memory personal, BassetData[] memory data); + + function bAssetIndexes(address) external view returns (uint8); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IQiDaoRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IQiDaoRegistry.sol new file mode 100644 index 0000000..7eeed30 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IQiDaoRegistry.sol @@ -0,0 +1,2 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IStablecoin.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IStablecoin.sol new file mode 100644 index 0000000..b6fd804 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IStablecoin.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IStablecoin { + function getDebtCeiling() external view returns (uint256); + + function balanceOf(address account) external view returns (uint256); + + function getClosingFee() external view returns (uint256); + + function getOpeningFee() external view returns (uint256); + + function getTokenPriceSource() external view returns (uint256); + + function getEthPriceSource() external view returns (uint256); + + function createVault() external returns (uint256); + + function destroyVault(uint256 vaultID) external; + + function transferVault(uint256 vaultID, address to) external; + + function depositCollateral(uint256 vaultID) external payable; + + function depositCollateral(uint256 vaultID, uint256 amount) external payable; + + function withdrawCollateral(uint256 vaultID, uint256 amount) external; + + function borrowToken(uint256 vaultID, uint256 amount) external; + + function vaultDebt(uint256 vaultId) external view returns (uint256); + + function payBackToken(uint256 vaultID, uint256 amount) external; + + function buyRiskyVault(uint256 vaultID) external; + + function collateral() external view returns (address); + + function tokenOfOwnerByIndex( + address owner, + uint256 index + ) + external + view + returns (uint256 tokenId); + + function vaultCollateral(uint256 vaultId) external view returns (uint256 collAmount); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundController.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundController.sol new file mode 100644 index 0000000..b9f474e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundController.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface IFundController { + function fuseAssets(uint8, string memory) external view returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundManager.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundManager.sol new file mode 100644 index 0000000..653f90d --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundManager.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface IFundManager { + function depositTo(address to, string memory currencyCode, uint256 amount) external; + function withdraw(string calldata currencyCode, uint256 amount) external returns (uint256); + function getRawFundBalance(string memory currencyCode) external returns (uint256); + function rariFundToken() external view returns (address); + function getFundBalance() external returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundProxy.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundProxy.sol new file mode 100644 index 0000000..5112045 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundProxy.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface IFundProxy { + function getRawFundBalancesAndPrices() + external + returns ( + string[] memory, + uint256[] memory, + uint8[][] memory, + uint256[][] memory, + uint256[] memory + ); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFuseAsset.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFuseAsset.sol new file mode 100644 index 0000000..be49e27 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFuseAsset.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +interface IFuseAsset { + function getCash() external returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IBasicTokenAdapters.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IBasicTokenAdapters.sol new file mode 100644 index 0000000..f4ba13b --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IBasicTokenAdapters.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IBasicTokenAdapters { + bytes32 public collateralType; + + function decimals() public view virtual returns (uint256); + function collateral() public view virtual returns (address); + function join(address, uint256) public payable virtual; + function exit(address, uint256) public virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ICoinJoin.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ICoinJoin.sol new file mode 100644 index 0000000..7c9df67 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ICoinJoin.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +abstract contract ICoinJoin { + uint256 public decimals; + + function join(address account, uint256 wad) external virtual; + + function exit(address account, uint256 wad) external virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IFSMWrapper.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IFSMWrapper.sol new file mode 100644 index 0000000..a522364 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IFSMWrapper.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IFSMWrapper { + function getNextResultWithValidity() external view returns (uint256 price, bool valid); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IGetSafes.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IGetSafes.sol new file mode 100644 index 0000000..3a61962 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IGetSafes.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IGetSafes { + function getSafesAsc( + address manager, + address guy + ) + external + view + virtual + returns (uint256[] memory ids, address[] memory safes, bytes32[] memory collateralTypes); + function getSafesDesc( + address manager, + address guy + ) + external + view + virtual + returns (uint256[] memory ids, address[] memory safes, bytes32[] memory collateralTypes); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IMedianOracle.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IMedianOracle.sol new file mode 100644 index 0000000..c425d26 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IMedianOracle.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IMedianOracle { + function read() external view virtual returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IOracleRelayer.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IOracleRelayer.sol new file mode 100644 index 0000000..4a3319d --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IOracleRelayer.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IOracleRelayer { + struct CollateralType { + address orcl; + uint256 safetyCRatio; + } + + mapping(bytes32 => CollateralType) public collateralTypes; + + function redemptionPrice() public virtual returns (uint256); + + uint256 public redemptionRate; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEEngine.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEEngine.sol new file mode 100644 index 0000000..bee8b78 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEEngine.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract ISAFEEngine { + struct SAFE { + uint256 lockedCollateral; + uint256 generatedDebt; + } + + struct CollateralType { + // Total debt issued for this specific collateral type + uint256 debtAmount; // [wad] + // Accumulator for interest accrued on this collateral type + uint256 accumulatedRate; // [ray] + // Floor price at which a SAFE is allowed to generate debt + uint256 safetyPrice; // [ray] + // Maximum amount of debt that can be generated with this collateral type + uint256 debtCeiling; // [rad] + // Minimum amount of debt that must be generated by a SAFE using this collateral + uint256 debtFloor; // [rad] + // Price at which a SAFE gets liquidated + uint256 liquidationPrice; // [ray] + } + + mapping(bytes32 => mapping(address => SAFE)) public safes; + mapping(bytes32 => CollateralType) public collateralTypes; + mapping(bytes32 => mapping(address => uint256)) public tokenCollateral; + + function safeRights(address, address) public view virtual returns (uint256); + function coinBalance(address) public view virtual returns (uint256); + function modifySAFECollateralization( + bytes32, + address, + address, + address, + int256, + int256 + ) + public + virtual; + function approveSAFEModification(address) public virtual; + function transferInternalCoins(address, address, uint256) public virtual; + function transferSAFECollateralAndDebt( + bytes32, + address, + address, + int256, + int256 + ) + public + virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEManager.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEManager.sol new file mode 100644 index 0000000..7fbc03c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEManager.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract ISAFEManager { + function lastSAFEID(address) public view virtual returns (uint256); + function safeCan(address, uint256, address) public view virtual returns (uint256); + function collateralTypes(uint256) public view virtual returns (bytes32); + function ownsSAFE(uint256) public view virtual returns (address); + function safes(uint256) public view virtual returns (address); + function safeEngine() public view virtual returns (address); + function openSAFE(bytes32, address) public virtual returns (uint256); + function transferSAFEOwnership(uint256, address) public virtual; + function allowSAFE(uint256, address, uint256) public virtual; + function handlerAllowed(address, uint256) public virtual; + function modifySAFECollateralization(uint256, int256, int256) public virtual; + function transferCollateral(uint256, address, uint256) public virtual; + function transferInternalCoins(uint256, address, uint256) public virtual; + function quitSystem(uint256, address) public virtual; + function enterSystem(address, uint256) public virtual; + function moveSAFE(uint256, uint256) public virtual; + function safeCount(address) public view virtual returns (uint256); + function safei() public view virtual returns (uint256); + function protectSAFE(uint256, address, address) public virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFESaviour.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFESaviour.sol new file mode 100644 index 0000000..882b7c8 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFESaviour.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract ISAFESaviour { + function deposit(uint256 safeID, uint256 lpTokenAmount) public virtual; + function withdraw(uint256 safeID, uint256 lpTokenAmount, address dst) public virtual; + function lpToken() public view virtual returns (address); + function lpTokenCover(address) public view virtual returns (uint256); + function getReserves(uint256, address) public virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ITaxCollector.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ITaxCollector.sol new file mode 100644 index 0000000..901fe0c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ITaxCollector.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract ITaxCollector { + struct CollateralType { + uint256 stabilityFee; + uint256 updateTime; + } + + mapping(bytes32 => CollateralType) public collateralTypes; + + function taxSingle(bytes32) public virtual returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/spark/IsDAI.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/spark/IsDAI.sol new file mode 100644 index 0000000..52746fe --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/spark/IsDAI.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +import "../IERC20.sol"; + +interface IsDAI is IERC20 { + function deposit(uint256 _amount, address _receiver) external; + function mint(uint256 _shares, address _receiver) external; + function withdraw(uint256 _amount, address _receiver, address _owner) external; + function redeem(uint256 _shares, address _receiver, address _owner) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/strategy/ISubStorage.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/strategy/ISubStorage.sol new file mode 100644 index 0000000..8bd5c8b --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/strategy/ISubStorage.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract ISubStorage { + function updateSubTriggerData( + uint256 _subId, + bytes memory _triggerData, + uint256 _triggerNum + ) + public + virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Factory.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Factory.sol new file mode 100644 index 0000000..a45a9dc --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Factory.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IUniswapV2Factory { + function getPair(address tokenA, address tokenB) external view virtual returns (address pair); + function allPairs(uint256) external view virtual returns (address pair); + function allPairsLength() external view virtual returns (uint256); + function feeTo() external view virtual returns (address); + function feeToSetter() external view virtual returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Pair.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Pair.sol new file mode 100644 index 0000000..1c692b3 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Pair.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IUniswapV2Pair { + function token0() external view returns (address); + function token1() external view returns (address); + function getReserves() + external + view + returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IQuoter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IQuoter.sol new file mode 100644 index 0000000..49d924b --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IQuoter.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.8.4; + +/// @title Quoter Interface +/// @notice Supports quoting the calculated amounts from exact input or exact output swaps +/// @dev These functions are not marked view because they rely on calling non-view functions and +/// reverting +/// to compute the result. They are also not gas efficient and should not be called on-chain. +interface IQuoter { + /// @notice Returns the amount out received for a given exact input swap without executing the + /// swap + /// @param path The path of the swap, i.e. each token pair and the pool fee + /// @param amountIn The amount of the first token to swap + /// @return amountOut The amount of the last token that would be received + function quoteExactInput( + bytes memory path, + uint256 amountIn + ) + external + returns (uint256 amountOut); + + /// @notice Returns the amount out received for a given exact input but for a swap of a single + /// pool + /// @param tokenIn The token being swapped in + /// @param tokenOut The token being swapped out + /// @param fee The fee of the token pool to consider for the pair + /// @param amountIn The desired input amount + /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountOut The amount of `tokenOut` that would be received + function quoteExactInputSingle( + address tokenIn, + address tokenOut, + uint24 fee, + uint256 amountIn, + uint160 sqrtPriceLimitX96 + ) + external + returns (uint256 amountOut); + + /// @notice Returns the amount in required for a given exact output swap without executing the + /// swap + /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be + /// provided in reverse order + /// @param amountOut The amount of the last token to receive + /// @return amountIn The amount of first token required to be paid + function quoteExactOutput( + bytes memory path, + uint256 amountOut + ) + external + returns (uint256 amountIn); + + /// @notice Returns the amount in required to receive the given exact output amount but for a + /// swap of a single pool + /// @param tokenIn The token being swapped in + /// @param tokenOut The token being swapped out + /// @param fee The fee of the token pool to consider for the pair + /// @param amountOut The desired output amount + /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountIn The amount required as the input for the swap in order to receive + /// `amountOut` + function quoteExactOutputSingle( + address tokenIn, + address tokenOut, + uint24 fee, + uint256 amountOut, + uint160 sqrtPriceLimitX96 + ) + external + returns (uint256 amountIn); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/ISwapRouter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/ISwapRouter.sol new file mode 100644 index 0000000..f9e95b1 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/ISwapRouter.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.8.4; +pragma abicoder v2; + +import { IUniswapV3SwapCallback } from "./IUniswapV3SwapCallback.sol"; + +/// @title Router token swapping functionality +/// @notice Functions for swapping tokens via Uniswap V3 +interface ISwapRouter is IUniswapV3SwapCallback { + struct ExactInputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 deadline; + uint256 amountIn; + uint256 amountOutMinimum; + uint160 sqrtPriceLimitX96; + } + + /// @notice Swaps `amountIn` of one token for as much as possible of another token + /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in + /// calldata + /// @return amountOut The amount of the received token + function exactInputSingle(ExactInputSingleParams calldata params) + external + payable + returns (uint256 amountOut); + + struct ExactInputParams { + bytes path; + address recipient; + uint256 deadline; + uint256 amountIn; + uint256 amountOutMinimum; + } + + /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified + /// path + /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` + /// in calldata + /// @return amountOut The amount of the received token + function exactInput(ExactInputParams calldata params) + external + payable + returns (uint256 amountOut); + + struct ExactOutputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 deadline; + uint256 amountOut; + uint256 amountInMaximum; + uint160 sqrtPriceLimitX96; + } + + /// @notice Swaps as little as possible of one token for `amountOut` of another token + /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in + /// calldata + /// @return amountIn The amount of the input token + function exactOutputSingle(ExactOutputSingleParams calldata params) + external + payable + returns (uint256 amountIn); + + struct ExactOutputParams { + bytes path; + address recipient; + uint256 deadline; + uint256 amountOut; + uint256 amountInMaximum; + } + + /// @notice Swaps as little as possible of one token for `amountOut` of another along the + /// specified path (reversed) + /// @param params The parameters necessary for the multi-hop swap, encoded as + /// `ExactOutputParams` in calldata + /// @return amountIn The amount of the input token + function exactOutput(ExactOutputParams calldata params) + external + payable + returns (uint256 amountIn); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Factory.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Factory.sol new file mode 100644 index 0000000..1b762e8 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Factory.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IUniswapV3Factory { + function getPool( + address token0, + address token1, + uint24 fee + ) + external + view + virtual + returns (address poolAddress); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3FlashCallback.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3FlashCallback.sol new file mode 100644 index 0000000..dd6eb78 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3FlashCallback.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.10; + +interface IUniswapV3FlashCallback { + function uniswapV3FlashCallback(uint256 fee0, uint256 fee1, bytes memory data) external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3NonfungiblePositionManager.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3NonfungiblePositionManager.sol new file mode 100644 index 0000000..b48467e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3NonfungiblePositionManager.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.10; + +abstract contract IUniswapV3NonfungiblePositionManager { + struct MintParams { + address token0; + address token1; + uint24 fee; + int24 tickLower; + int24 tickUpper; + uint256 amount0Desired; + uint256 amount1Desired; + uint256 amount0Min; + uint256 amount1Min; + address recipient; + uint256 deadline; + } + + function mint(MintParams calldata params) + external + payable + virtual + returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); + + struct IncreaseLiquidityParams { + uint256 tokenId; + uint256 amount0Desired; + uint256 amount1Desired; + uint256 amount0Min; + uint256 amount1Min; + uint256 deadline; + } + + function increaseLiquidity(IncreaseLiquidityParams calldata params) + external + payable + virtual + returns (uint128 liquidity, uint256 amount0, uint256 amount1); + + struct DecreaseLiquidityParams { + uint256 tokenId; + uint128 liquidity; + uint256 amount0Min; + uint256 amount1Min; + uint256 deadline; + } + + function decreaseLiquidity(DecreaseLiquidityParams calldata params) + external + payable + virtual + returns (uint256 amount0, uint256 amount1); + + struct CollectParams { + uint256 tokenId; + address recipient; + uint128 amount0Max; + uint128 amount1Max; + } + + function collect(CollectParams calldata params) + external + payable + virtual + returns (uint256 amount0, uint256 amount1); + + function positions(uint256 tokenId) + external + view + virtual + returns ( + uint96 nonce, + address operator, + address token0, + address token1, + uint24 fee, + int24 tickLower, + int24 tickUpper, + uint128 liquidity, + uint256 feeGrowthInside0LastX128, + uint256 feeGrowthInside1LastX128, + uint128 tokensOwed0, + uint128 tokensOwed1 + ); + function balanceOf(address owner) external view virtual returns (uint256 balance); + function tokenOfOwnerByIndex( + address owner, + uint256 index + ) + external + view + virtual + returns (uint256 tokenId); + function approve(address to, uint256 tokenId) public virtual; + + /// @notice Creates a new pool if it does not exist, then initializes if not initialized + /// @dev This method can be bundled with others via IMulticall for the first action (e.g. mint) + /// performed against a pool + /// @param token0 The contract address of token0 of the pool + /// @param token1 The contract address of token1 of the pool + /// @param fee The fee amount of the v3 pool for the specified token pair + /// @param sqrtPriceX96 The initial square root price of the pool as a Q64.96 value + /// @return pool Returns the pool address based on the pair of tokens and fee, will return the + /// newly created pool address if necessary + function createAndInitializePoolIfNecessary( + address token0, + address token1, + uint24 fee, + uint160 sqrtPriceX96 + ) + external + payable + virtual + returns (address pool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Pool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Pool.sol new file mode 100644 index 0000000..4c4d99a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Pool.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IUniswapV3Pool { + struct Slot0 { + // the current price + uint160 sqrtPriceX96; + // the current tick + int24 tick; + // the most-recently updated index of the observations array + uint16 observationIndex; + // the current maximum number of observations that are being stored + uint16 observationCardinality; + // the next maximum number of observations to store, triggered in observations.write + uint16 observationCardinalityNext; + // the current protocol fee as a percentage of the swap fee taken on withdrawal + // represented as an integer denominator (1/x)% + uint8 feeProtocol; + // whether the pool is locked + bool unlocked; + } + + function slot0() external view virtual returns (Slot0 memory); + + function fee() external view virtual returns (uint24 fee); + + function flash( + address recipient, + uint256 amount0, + uint256 amount1, + bytes memory data + ) + external + virtual; + + function token0() external view virtual returns (address); + function token1() external view virtual returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3SwapCallback.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3SwapCallback.sol new file mode 100644 index 0000000..457bcee --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3SwapCallback.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.8.0; + +/// @title Callback for IUniswapV3PoolActions#swap +/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface +interface IUniswapV3SwapCallback { + /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. + /// @dev In the implementation you must pay the pool tokens owed for the swap. + /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical + /// UniswapV3Factory. + /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. + /// @param amount0Delta The amount of token0 that was sent (negative) or must be received + /// (positive) by the pool by + /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. + /// @param amount1Delta The amount of token1 that was sent (negative) or must be received + /// (positive) by the pool by + /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. + /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call + function uniswapV3SwapCallback( + int256 amount0Delta, + int256 amount1Delta, + bytes calldata data + ) + external; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYVault.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYVault.sol new file mode 100644 index 0000000..a393f1a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYVault.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.0 <0.9.0; + +interface IYVault { + function withdraw(uint256 _shares) external; + function deposit(uint256 _amount, address _recipient) external; + function token() external view returns (address); + + function totalSupply() external view returns (uint256); + function totalAssets() external view returns (uint256); + function withdrawalQueue(uint256 i) external view returns (address); + + function strategies(address) + external + view + returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYearnRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYearnRegistry.sol new file mode 100644 index 0000000..5df2617 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYearnRegistry.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +abstract contract IYearnRegistry { + function latestVault(address) external view virtual returns (address); + function numVaults(address) external view virtual returns (uint256); + function vaults(address, uint256) external view virtual returns (address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/registry/ExampleFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/registry/ExampleFactory.sol new file mode 100644 index 0000000..70d77a1 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/registry/ExampleFactory.sol @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IMSA } from "../../accounts/erc7579/interfaces/IMSA.sol"; +import { + IERC7579Bootstrap, + BootstrapConfig +} from "../../accounts/erc7579/interfaces/IERC7579Bootstrap.sol"; +import { IModule as IERC7579Module } from "../../accounts/common/interfaces/IERC7579Module.sol"; + +// Dependencies +import { FactoryBase } from "./FactoryBase.sol"; + +// Precompiles +import { ERC7579Precompiles } from "../../deployment/precompiles/ERC7579Precompiles.sol"; + +contract ExampleFactory is FactoryBase, ERC7579Precompiles { + address public immutable IMPLEMENTATION; + address public immutable BOOTSTRAP; + + constructor( + address _msaImplementation, + address _bootstrap, + address _registry, + address[] memory _trustedAttesters, + uint8 _threshold + ) + FactoryBase(_registry, _trustedAttesters, _threshold) + { + IMPLEMENTATION = _msaImplementation; + BOOTSTRAP = _bootstrap; + } + + function createAccount( + bytes32 salt, + address validator, + bytes calldata validatorInitData + ) + public + payable + virtual + returns (address) + { + _checkRegistry(validator, 1); + + bytes memory initData = abi.encode( + BOOTSTRAP, + abi.encodeCall( + IERC7579Bootstrap.singleInitMSA, (IERC7579Module(validator), validatorInitData) + ) + ); + + address account = deployMSAPRoxy(salt, IMPLEMENTATION, initData); + + return account; + } + + function getAddress( + bytes32 salt, + address validator, + bytes calldata validatorInitData + ) + public + virtual + returns (address) + { + _checkRegistry(validator, 1); + + bytes memory initData = abi.encode( + BOOTSTRAP, + abi.encodeCall( + IERC7579Bootstrap.singleInitMSA, (IERC7579Module(validator), validatorInitData) + ) + ); + + bytes32 hash = keccak256( + abi.encodePacked( + bytes1(0xff), + address(this), + salt, + keccak256( + abi.encodePacked( + MSAPROXY_BYTECODE, + abi.encode(IMPLEMENTATION, abi.encodeCall(IMSA.initializeAccount, initData)) + ) + ) + ) + ); + + return address(uint160(uint256(hash))); + } + + function getAddress( + bytes32 salt, + bytes memory initData + ) + public + view + virtual + returns (address) + { + bytes32 hash = keccak256( + abi.encodePacked( + bytes1(0xff), + address(this), + salt, + keccak256( + abi.encodePacked( + MSAPROXY_BYTECODE, + abi.encode(IMPLEMENTATION, abi.encodeCall(IMSA.initializeAccount, initData)) + ) + ) + ) + ); + + return address(uint160(uint256(hash))); + } + + function getInitCode( + bytes32 salt, + address validator, + bytes calldata validatorInitData + ) + public + view + virtual + returns (bytes memory initCode) + { + initCode = abi.encodePacked( + address(this), abi.encodeCall(this.createAccount, (salt, validator, validatorInitData)) + ); + } + + function _getSalt( + bytes32 _salt, + address validator, + bytes calldata validatorInitData + ) + public + pure + virtual + returns (bytes32 salt) + { + salt = keccak256(abi.encodePacked(_salt, validator, validatorInitData)); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/registry/FactoryBase.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/registry/FactoryBase.sol new file mode 100644 index 0000000..d091fa5 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/registry/FactoryBase.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IERC7484 } from "../../Interfaces.sol"; + +abstract contract FactoryBase { + IERC7484 public immutable REGISTRY; + + address[] public trustedAttesters; + uint8 public threshold; + + constructor(address _registry, address[] memory _trustedAttesters, uint8 _threshold) { + REGISTRY = IERC7484(_registry); + trustedAttesters = _trustedAttesters; + threshold = _threshold; + } + + function _checkRegistry(address module, uint256 moduleType) internal view { + REGISTRY.check(module, moduleType, trustedAttesters, threshold); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/MockUniswap.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/MockUniswap.sol new file mode 100644 index 0000000..180e051 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/MockUniswap.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { ISwapRouter } from "../interfaces/uniswap/v3/ISwapRouter.sol"; + +contract MockUniswap is ISwapRouter { + function uniswapV3SwapCallback( + int256 amount0Delta, + int256 amount1Delta, + bytes calldata data + ) + external + override + { } + + function exactInputSingle(ExactInputSingleParams calldata params) + external + payable + override + returns (uint256 amountOut) + { + return params.amountIn; + } + + function exactInput(ExactInputParams calldata params) + external + payable + override + returns (uint256 amountOut) + { + return params.amountIn; + } + + function exactOutputSingle(ExactOutputSingleParams calldata params) + external + payable + override + returns (uint256 amountIn) + { + return params.amountOut; + } + + function exactOutput(ExactOutputParams calldata params) + external + payable + override + returns (uint256 amountIn) + { + return params.amountOut; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/helpers/MainnetAddresses.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/helpers/MainnetAddresses.sol new file mode 100644 index 0000000..841d7c0 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/helpers/MainnetAddresses.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +address payable constant SWAPROUTER_ADDRESS = payable(0xE592427A0AEce92De3Edee1F18E0157C05861564); +uint24 constant SWAPROUTER_DEFAULTFEE = 3000; +address constant QUOTER_ADDRESS = 0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6; +address constant FACTORY_ADDRESS = 0x1F98431c8aD98523631AE4a59f267346ea31F984; diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/v3/Uniswap.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/v3/Uniswap.sol new file mode 100644 index 0000000..eed3435 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/v3/Uniswap.sol @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Helpers +import { + SWAPROUTER_ADDRESS, + SWAPROUTER_DEFAULTFEE, + FACTORY_ADDRESS +} from "../helpers/MainnetAddresses.sol"; + +// Interfaces +import { ISwapRouter } from "../../interfaces/uniswap/v3/ISwapRouter.sol"; +import { IUniswapV3Factory } from "../../interfaces/uniswap/v3/IUniswapV3Factory.sol"; +import { IUniswapV3Pool } from "../../interfaces/uniswap/v3/IUniswapV3Pool.sol"; +import { IERC20 } from "forge-std/interfaces/IERC20.sol"; + +// Dependencies +import { ERC20Integration } from "../../ERC20.sol"; + +// Types +import { Execution } from "../../../accounts/erc7579/lib/ExecutionLib.sol"; + +/// @author zeroknots +library UniswapV3Integration { + using ERC20Integration for IERC20; + + error PoolDoesNotExist(); + + function approveAndSwap( + address smartAccount, + IERC20 tokenIn, + IERC20 tokenOut, + uint256 amountIn, + uint160 sqrtPriceLimitX96 + ) + internal + view + returns (Execution[] memory exec) + { + exec = new Execution[](3); + (exec[0], exec[1]) = ERC20Integration.safeApprove(tokenIn, SWAPROUTER_ADDRESS, amountIn); + exec[2] = swapExactInputSingle(smartAccount, tokenIn, tokenOut, amountIn, sqrtPriceLimitX96); + } + + function swapExactInputSingle( + address smartAccount, + IERC20 tokenIn, + IERC20 tokenOut, + uint256 amountIn, + uint160 sqrtPriceLimitX96 + ) + internal + view + returns (Execution memory exec) + { + exec = Execution({ + target: SWAPROUTER_ADDRESS, + value: 0, + callData: abi.encodeCall( + ISwapRouter.exactInputSingle, + ( + ISwapRouter.ExactInputSingleParams({ + tokenIn: address(tokenIn), + tokenOut: address(tokenOut), + fee: SWAPROUTER_DEFAULTFEE, + recipient: smartAccount, + deadline: block.timestamp, + amountIn: amountIn, + amountOutMinimum: 0, + sqrtPriceLimitX96: sqrtPriceLimitX96 + }) + ) + ) + }); + } + + function swapExactOutputSingle( + address smartAccount, + IERC20 tokenIn, + IERC20 tokenOut, + uint256 amountOut, + uint256 amountInMaximum + ) + internal + view + returns (Execution memory exec) + { + exec = Execution({ + target: SWAPROUTER_ADDRESS, + value: 0, + callData: abi.encodeCall( + ISwapRouter.exactOutputSingle, + ( + ISwapRouter.ExactOutputSingleParams({ + tokenIn: address(tokenIn), + tokenOut: address(tokenOut), + fee: SWAPROUTER_DEFAULTFEE, + recipient: smartAccount, + deadline: block.timestamp, + amountOut: amountOut, + amountInMaximum: amountInMaximum, + sqrtPriceLimitX96: 0 + }) + ) + ) + }); + } + + function getPoolAddress( + address token0, + address token1 + ) + public + view + returns (address poolAddress) + { + IUniswapV3Factory factory = IUniswapV3Factory(FACTORY_ADDRESS); + poolAddress = factory.getPool(token0, token1, SWAPROUTER_DEFAULTFEE); + if (poolAddress == address(0)) { + revert PoolDoesNotExist(); + } + return poolAddress; + } + + function getSqrtPriceX96(address poolAddress) public view returns (uint160 sqrtPriceX96) { + IUniswapV3Pool pool = IUniswapV3Pool(poolAddress); + IUniswapV3Pool.Slot0 memory slot0 = pool.slot0(); + sqrtPriceX96 = slot0.sqrtPriceX96; + } + + function sqrtPriceX96toPriceRatio(uint160 sqrtPriceX96) + internal + pure + returns (uint256 priceRatio) + { + uint256 decodedSqrtPrice = (sqrtPriceX96 * 10 ** 9) / (2 ** 96); + priceRatio = decodedSqrtPrice * decodedSqrtPrice; + } + + function priceRatioToPrice( + uint256 priceRatio, + address poolAddress, + address tokenSwappedFrom + ) + internal + view + returns (uint256 price) + { + IUniswapV3Pool pool = IUniswapV3Pool(poolAddress); + address poolToken0 = pool.token0(); + address poolToken1 = pool.token1(); + uint256 token0Decimals = IERC20(poolToken0).decimals(); + uint256 token1Decimals = IERC20(poolToken1).decimals(); + + bool swapToken0to1 = (tokenSwappedFrom == poolToken0); + if (swapToken0to1) { + price = (10 ** token1Decimals * 10 ** 18) / priceRatio; + } else { + price = (priceRatio * 10 ** token0Decimals) / 10 ** 18; + } + return price; + } + + function priceRatioToSqrtPriceX96(uint256 priceRatio) internal pure returns (uint160) { + // Scale priceRatio to 18 decimals for precision + uint256 sqrtPriceRatio = sqrt256(priceRatio); + + uint256 sqrtPriceX96 = (sqrtPriceRatio * 2 ** 96) / 1e9; // Adjust back from the scaling + + return uint160(sqrtPriceX96); + } + + function checkTokenOrder( + address tokenSwappedFrom, + address poolAddress + ) + internal + view + returns (bool swapToken0to1) + { + address poolToken0 = IUniswapV3Pool(poolAddress).token0(); + swapToken0to1 = (tokenSwappedFrom == poolToken0); + } + + function sqrt256(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; + } + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC20.sol b/typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC20.sol new file mode 100644 index 0000000..dc66d41 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC20.sol @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +import { IERC20 } from "forge-std/interfaces/IERC20.sol"; + +/// @notice This is a mock contract of the ERC20 standard for testing purposes only, it SHOULD NOT +/// be used in production. +/// @dev Forked from: +/// https://github.com/transmissions11/solmate/blob/0384dbaaa4fcb5715738a9254a7c0a4cb62cf458/src/tokens/ERC20.sol +contract MockERC20 is IERC20 { + /*////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string internal _name; + + string internal _symbol; + + uint8 internal _decimals; + + function name() external view override returns (string memory) { + return _name; + } + + function symbol() external view override returns (string memory) { + return _symbol; + } + + function decimals() external view override returns (uint8) { + return _decimals; + } + + /*////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 internal _totalSupply; + + mapping(address => uint256) internal _balanceOf; + + mapping(address => mapping(address => uint256)) internal _allowance; + + function totalSupply() external view override returns (uint256) { + return _totalSupply; + } + + function balanceOf(address owner) external view override returns (uint256) { + return _balanceOf[owner]; + } + + function allowance(address owner, address spender) external view override returns (uint256) { + return _allowance[owner][spender]; + } + + /*////////////////////////////////////////////////////////////// + EIP-2612 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 internal INITIAL_CHAIN_ID; + + bytes32 internal INITIAL_DOMAIN_SEPARATOR; + + mapping(address => uint256) public nonces; + + /*////////////////////////////////////////////////////////////// + INITIALIZE + //////////////////////////////////////////////////////////////*/ + + /// @dev A bool to track whether the contract has been initialized. + bool private initialized; + + /// @dev To hide constructor warnings across solc versions due to different constructor + /// visibility requirements and + /// syntaxes, we add an initialization function that can be called only once. + function initialize(string memory name_, string memory symbol_, uint8 decimals_) public { + require(!initialized, "ALREADY_INITIALIZED"); + + _name = name_; + _symbol = symbol_; + _decimals = decimals_; + + INITIAL_CHAIN_ID = _pureChainId(); + INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); + + initialized = true; + } + + /*////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 amount) public virtual override returns (bool) { + _allowance[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + + return true; + } + + function transfer(address to, uint256 amount) public virtual override returns (bool) { + _balanceOf[msg.sender] = _sub(_balanceOf[msg.sender], amount); + _balanceOf[to] = _add(_balanceOf[to], amount); + + emit Transfer(msg.sender, to, amount); + + return true; + } + + function transferFrom( + address from, + address to, + uint256 amount + ) + public + virtual + override + returns (bool) + { + uint256 allowed = _allowance[from][msg.sender]; // Saves gas for limited approvals. + + if (allowed != ~uint256(0)) _allowance[from][msg.sender] = _sub(allowed, amount); + + _balanceOf[from] = _sub(_balanceOf[from], amount); + _balanceOf[to] = _add(_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"); + + 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 + _pureChainId() == 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"), + _pureChainId(), + address(this) + ) + ); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL MINT/BURN LOGIC + //////////////////////////////////////////////////////////////*/ + + function _mint(address to, uint256 amount) internal virtual { + _totalSupply = _add(_totalSupply, amount); + _balanceOf[to] = _add(_balanceOf[to], amount); + + emit Transfer(address(0), to, amount); + } + + function _burn(address from, uint256 amount) internal virtual { + _balanceOf[from] = _sub(_balanceOf[from], amount); + _totalSupply = _sub(_totalSupply, amount); + + emit Transfer(from, address(0), amount); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL SAFE MATH LOGIC + //////////////////////////////////////////////////////////////*/ + + function _add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "ERC20: addition overflow"); + return c; + } + + function _sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(a >= b, "ERC20: subtraction underflow"); + return a - b; + } + + /*////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////*/ + + // 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(); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC721.sol b/typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC721.sol new file mode 100644 index 0000000..46ae594 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC721.sol @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +import { IERC721Metadata, IERC721TokenReceiver } from "forge-std/interfaces/IERC721.sol"; + +/// @notice This is a mock contract of the ERC721 standard for testing purposes only, it SHOULD NOT +/// be used in production. +/// @dev Forked from: +/// https://github.com/transmissions11/solmate/blob/0384dbaaa4fcb5715738a9254a7c0a4cb62cf458/src/tokens/ERC721.sol +contract MockERC721 is IERC721Metadata { + /*////////////////////////////////////////////////////////////// + METADATA STORAGE/LOGIC + //////////////////////////////////////////////////////////////*/ + + string internal _name; + + string internal _symbol; + + function name() external view override returns (string memory) { + return _name; + } + + function symbol() external view override returns (string memory) { + return _symbol; + } + + function tokenURI(uint256 id) public view virtual override returns (string memory) { } + + /*////////////////////////////////////////////////////////////// + ERC721 BALANCE/OWNER STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(uint256 => address) internal _ownerOf; + + mapping(address => uint256) internal _balanceOf; + + function ownerOf(uint256 id) public view virtual override returns (address owner) { + require((owner = _ownerOf[id]) != address(0), "NOT_MINTED"); + } + + function balanceOf(address owner) public view virtual override returns (uint256) { + require(owner != address(0), "ZERO_ADDRESS"); + + return _balanceOf[owner]; + } + + /*////////////////////////////////////////////////////////////// + ERC721 APPROVAL STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(uint256 => address) internal _getApproved; + + mapping(address => mapping(address => bool)) internal _isApprovedForAll; + + function getApproved(uint256 id) public view virtual override returns (address) { + return _getApproved[id]; + } + + function isApprovedForAll( + address owner, + address operator + ) + public + view + virtual + override + returns (bool) + { + return _isApprovedForAll[owner][operator]; + } + + /*////////////////////////////////////////////////////////////// + INITIALIZE + //////////////////////////////////////////////////////////////*/ + + /// @dev A bool to track whether the contract has been initialized. + bool private initialized; + + /// @dev To hide constructor warnings across solc versions due to different constructor + /// visibility requirements and + /// syntaxes, we add an initialization function that can be called only once. + function initialize(string memory name_, string memory symbol_) public { + require(!initialized, "ALREADY_INITIALIZED"); + + _name = name_; + _symbol = symbol_; + + initialized = true; + } + + /*////////////////////////////////////////////////////////////// + ERC721 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 id) public payable virtual override { + 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 override { + _isApprovedForAll[msg.sender][operator] = approved; + + emit ApprovalForAll(msg.sender, operator, approved); + } + + function transferFrom(address from, address to, uint256 id) public payable virtual override { + 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. + _balanceOf[from]--; + + _balanceOf[to]++; + + _ownerOf[id] = to; + + delete _getApproved[id]; + + emit Transfer(from, to, id); + } + + function safeTransferFrom( + address from, + address to, + uint256 id + ) + public + payable + virtual + override + { + transferFrom(from, to, id); + + require( + !_isContract(to) + || IERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") + == IERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function safeTransferFrom( + address from, + address to, + uint256 id, + bytes memory data + ) + public + payable + virtual + override + { + transferFrom(from, to, id); + + require( + !_isContract(to) + || IERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) + == IERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + /*////////////////////////////////////////////////////////////// + ERC165 LOGIC + //////////////////////////////////////////////////////////////*/ + + function supportsInterface(bytes4 interfaceId) public view virtual override 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. + + _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"); + + _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( + !_isContract(to) + || IERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") + == IERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function _safeMint(address to, uint256 id, bytes memory data) internal virtual { + _mint(to, id); + + require( + !_isContract(to) + || IERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) + == IERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + /*////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////*/ + + function _isContract(address _addr) private view returns (bool) { + uint256 codeLength; + + // Assembly required for versions < 0.8.0 to check extcodesize. + assembly { + codeLength := extcodesize(_addr) + } + + return codeLength > 0; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC1271Policy.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC1271Policy.sol new file mode 100644 index 0000000..746ef48 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC1271Policy.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { ERC7579PolicyBase } from "./ERC7579PolicyBase.sol"; +import { ConfigId, I1271Policy } from "./interfaces/IPolicy.sol"; + +abstract contract ERC1271Policy is ERC7579PolicyBase, I1271Policy { + function check1271SignedAction( + ConfigId id, + address requestSender, + address account, + bytes32 hash, + bytes calldata signature + ) + external + view + virtual + returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7484RegistryAdapter.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7484RegistryAdapter.sol new file mode 100644 index 0000000..9893ce2 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7484RegistryAdapter.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { IERC7484 } from "./interfaces/IERC7484.sol"; + +abstract contract ERC7484RegistryAdapter { + // registry address + IERC7484 public immutable REGISTRY; + + /** + * Contract constructor + * @dev sets the registry as an immutable variable + * + * @param _registry The registry address + */ + constructor(IERC7484 _registry) { + // set the registry + REGISTRY = _registry; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ActionPolicy.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ActionPolicy.sol new file mode 100644 index 0000000..4e0f684 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ActionPolicy.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { ERC7579PolicyBase } from "./ERC7579PolicyBase.sol"; +import { ConfigId, IActionPolicy } from "./interfaces/IPolicy.sol"; + +abstract contract ERC7579ActionPolicy is ERC7579PolicyBase, IActionPolicy { + function checkAction( + ConfigId id, + address account, + address target, + uint256 value, + bytes calldata data + ) + external + virtual + returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ExecutorBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ExecutorBase.sol new file mode 100644 index 0000000..7dcc04b --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ExecutorBase.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { IExecutor as IERC7579Executor } from "../accounts/common/interfaces/IERC7579Module.sol"; +import { IERC7579Account } from "../accounts/common/interfaces/IERC7579Account.sol"; +import { + Execution, + ExecutionLib as ERC7579ExecutionLib +} from "../accounts/erc7579/lib/ExecutionLib.sol"; +import { + ModeCode, + ModeLib as ERC7579ModeLib, + CALLTYPE_SINGLE, + EXECTYPE_DEFAULT, + MODE_DEFAULT, + ModePayload, + CALLTYPE_BATCH, + EXECTYPE_DEFAULT, + MODE_DEFAULT, + CALLTYPE_DELEGATECALL +} from "../accounts/common/lib/ModeLib.sol"; +import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; + +abstract contract ERC7579ExecutorBase is IERC7579Executor, ERC7579ModuleBase { + function _execute( + address account, + address to, + uint256 value, + bytes memory data + ) + internal + returns (bytes memory result) + { + ModeCode modeCode = ERC7579ModeLib.encode({ + callType: CALLTYPE_SINGLE, + execType: EXECTYPE_DEFAULT, + mode: MODE_DEFAULT, + payload: ModePayload.wrap(bytes22(0)) + }); + + return IERC7579Account(account).executeFromExecutor( + modeCode, ERC7579ExecutionLib.encodeSingle(to, value, data) + )[0]; + } + + function _execute( + address to, + uint256 value, + bytes memory data + ) + internal + returns (bytes memory result) + { + return _execute(msg.sender, to, value, data); + } + + function _execute( + address account, + Execution[] memory execs + ) + internal + returns (bytes[] memory results) + { + ModeCode modeCode = ERC7579ModeLib.encode({ + callType: CALLTYPE_BATCH, + execType: EXECTYPE_DEFAULT, + mode: MODE_DEFAULT, + payload: ModePayload.wrap(bytes22(0)) + }); + results = IERC7579Account(account).executeFromExecutor( + modeCode, ERC7579ExecutionLib.encodeBatch(execs) + ); + } + + function _execute(Execution[] memory execs) internal returns (bytes[] memory results) { + return _execute(msg.sender, execs); + } + + // Note: Not every account will support delegatecalls + function _executeDelegateCall( + address account, + address delegateTarget, + bytes memory callData + ) + internal + returns (bytes[] memory results) + { + ModeCode modeCode = ERC7579ModeLib.encode({ + callType: CALLTYPE_DELEGATECALL, + execType: EXECTYPE_DEFAULT, + mode: MODE_DEFAULT, + payload: ModePayload.wrap(bytes22(0)) + }); + results = IERC7579Account(account).executeFromExecutor( + modeCode, abi.encodePacked(delegateTarget, callData) + ); + } + + // Note: Not every account will support delegatecalls + function _executeDelegateCall( + address delegateTarget, + bytes memory callData + ) + internal + returns (bytes[] memory results) + { + return _executeDelegateCall(msg.sender, delegateTarget, callData); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579FallbackBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579FallbackBase.sol new file mode 100644 index 0000000..e071370 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579FallbackBase.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { IFallback as IERC7579Fallback } from "../accounts/common/interfaces/IERC7579Module.sol"; +import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; + +abstract contract ERC7579FallbackBase is IERC7579Fallback, ERC7579ModuleBase { + /** + * @notice Allows fetching the original caller address. + * @dev This is only reliable in combination with a FallbackManager that supports this (e.g. Safe + * contract >=1.3.0). + * When using this functionality make sure that the linked _manager (aka msg.sender) + * supports this. + * This function does not rely on a trusted forwarder. Use the returned value only to + * check information against the calling manager. + * @return sender Original caller address. + */ + function _msgSender() internal pure returns (address sender) { + // The assembly code is more direct than the Solidity version using `abi.decode`. + /* solhint-disable no-inline-assembly */ + /// @solidity memory-safe-assembly + assembly { + sender := shr(96, calldataload(sub(calldatasize(), 20))) + } + /* solhint-enable no-inline-assembly */ + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookBase.sol new file mode 100644 index 0000000..342c3f8 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookBase.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { IHook as IERC7579Hook } from "../accounts/common/interfaces/IERC7579Module.sol"; +import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; +import { TrustedForwarder } from "./utils/TrustedForwarder.sol"; + +abstract contract ERC7579HookBase is IERC7579Hook, ERC7579ModuleBase, TrustedForwarder { + /** + * Precheck hook + * + * @param msgSender sender of the transaction + * @param msgValue value of the transaction + * @param msgData data of the transaction + * + * @return hookData data for the postcheck hook + */ + function preCheck( + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + external + virtual + returns (bytes memory hookData) + { + // route to internal function + return _preCheck(_getAccount(), msgSender, msgValue, msgData); + } + + /** + * Postcheck hook + * + * @param hookData data from the precheck hook + */ + function postCheck(bytes calldata hookData) external virtual { + // route to internal function + _postCheck(_getAccount(), hookData); + } + + /** + * Precheck hook + * + * @param account account of the transaction + * @param msgSender sender of the transaction + * @param msgValue value of the transaction + * @param msgData data of the transaction + * + * @return hookData data for the postcheck hook + */ + function _preCheck( + address account, + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + internal + virtual + returns (bytes memory hookData); + + /** + * Postcheck hook + * + * @param account account of the transaction + * @param hookData data from the precheck hook + */ + function _postCheck(address account, bytes calldata hookData) internal virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestruct.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestruct.sol new file mode 100644 index 0000000..a67143f --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestruct.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { IERC7579Account } from "../accounts/common/interfaces/IERC7579Account.sol"; +import { IHook as IERC7579Hook } from "../accounts/common/interfaces/IERC7579Module.sol"; +import { ExecutionLib, Execution } from "../accounts/erc7579/lib/ExecutionLib.sol"; +import { + ModeLib, + CallType, + ModeCode, + CALLTYPE_SINGLE, + CALLTYPE_BATCH, + CALLTYPE_DELEGATECALL +} from "../accounts/common/lib/ModeLib.sol"; +import { IAccountExecute } from "../external/ERC4337.sol"; +import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; +import { TrustedForwarder } from "./utils/TrustedForwarder.sol"; + +uint256 constant EXECUSEROP_OFFSET = 164; +uint256 constant EXEC_OFFSET = 100; +uint256 constant INSTALL_OFFSET = 132; + +abstract contract ERC7579HookDestruct is IERC7579Hook, ERC7579ModuleBase, TrustedForwarder { + error HookInvalidSelector(); + error InvalidCallType(); + + /*////////////////////////////////////////////////////////////////////////// + CALLDATA DECODING + //////////////////////////////////////////////////////////////////////////*/ + + function preCheck( + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + external + virtual + override + returns (bytes memory hookData) + { + bytes4 selector = bytes4(msgData[0:4]); + + if (selector == IAccountExecute.executeUserOp.selector) { + uint256 offset = + uint256(bytes32(msgData[EXECUSEROP_OFFSET:EXECUSEROP_OFFSET + 32])) + 68; + uint256 paramLen = uint256(bytes32(msgData[offset:offset + 32])); + offset += 32; + bytes calldata _msgData = msgData[offset:offset + paramLen]; + return _decodeCallData(msgSender, msgValue, _msgData); + } else { + return _decodeCallData(msgSender, msgValue, msgData); + } + } + + function _decodeCallData( + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + internal + returns (bytes memory hookData) + { + bytes4 selector = bytes4(msgData[0:4]); + if (selector == IERC7579Account.execute.selector) { + return _handle4337Executions(msgSender, msgData); + } else if (selector == IERC7579Account.executeFromExecutor.selector) { + return _handleExecutorExecutions(msgSender, msgData); + } else if (selector == IERC7579Account.installModule.selector) { + uint256 paramLen = msgData.length > INSTALL_OFFSET + ? uint256(bytes32(msgData[INSTALL_OFFSET - 32:INSTALL_OFFSET])) + : uint256(0); + bytes calldata initData = msgData.length > INSTALL_OFFSET + ? msgData[INSTALL_OFFSET:INSTALL_OFFSET + paramLen] + : msgData[0:0]; + uint256 moduleType = uint256(bytes32(msgData[4:36])); + address module = address(bytes20((msgData[48:68]))); + return onInstallModule(_getAccount(), msgSender, moduleType, module, initData); + } else if (selector == IERC7579Account.uninstallModule.selector) { + uint256 paramLen = msgData.length > INSTALL_OFFSET + ? uint256(bytes32(msgData[INSTALL_OFFSET - 32:INSTALL_OFFSET])) + : uint256(0); + bytes calldata initData = msgData.length > INSTALL_OFFSET + ? msgData[INSTALL_OFFSET:INSTALL_OFFSET + paramLen] + : msgData[0:0]; + + uint256 moduleType = uint256(bytes32(msgData[4:36])); + address module = address(bytes20((msgData[48:68]))); + + return onUninstallModule(_getAccount(), msgSender, moduleType, module, initData); + } else { + return onUnknownFunction(_getAccount(), msgSender, msgValue, msgData); + } + } + + function _handle4337Executions( + address msgSender, + bytes calldata msgData + ) + internal + returns (bytes memory hookData) + { + uint256 paramLen = uint256(bytes32(msgData[EXEC_OFFSET - 32:EXEC_OFFSET])); + bytes calldata encodedExecutions = msgData[EXEC_OFFSET:EXEC_OFFSET + paramLen]; + + ModeCode mode = ModeCode.wrap(bytes32(msgData[4:36])); + CallType calltype = ModeLib.getCallType(mode); + + if (calltype == CALLTYPE_SINGLE) { + (address to, uint256 value, bytes calldata callData) = + ExecutionLib.decodeSingle(encodedExecutions); + return onExecute(_getAccount(), msgSender, to, value, callData); + } else if (calltype == CALLTYPE_BATCH) { + Execution[] calldata execs = ExecutionLib.decodeBatch(encodedExecutions); + return onExecuteBatch(_getAccount(), msgSender, execs); + } else if (calltype == CALLTYPE_DELEGATECALL) { + address to = address(bytes20(encodedExecutions[0:20])); + bytes calldata callData = encodedExecutions[20:]; + return onExecuteDelegateCall(_getAccount(), msgSender, to, callData); + } else { + revert InvalidCallType(); + } + } + + function _handleExecutorExecutions( + address msgSender, + bytes calldata msgData + ) + internal + returns (bytes memory hookData) + { + uint256 paramLen = uint256(bytes32(msgData[EXEC_OFFSET - 32:EXEC_OFFSET])); + bytes calldata encodedExecutions = msgData[EXEC_OFFSET:EXEC_OFFSET + paramLen]; + + ModeCode mode = ModeCode.wrap(bytes32(msgData[4:36])); + CallType calltype = ModeLib.getCallType(mode); + + if (calltype == CALLTYPE_SINGLE) { + (address to, uint256 value, bytes calldata callData) = + ExecutionLib.decodeSingle(encodedExecutions); + return onExecuteFromExecutor(_getAccount(), msgSender, to, value, callData); + } else if (calltype == CALLTYPE_BATCH) { + Execution[] calldata execs = ExecutionLib.decodeBatch(encodedExecutions); + return onExecuteBatchFromExecutor(_getAccount(), msgSender, execs); + } else if (calltype == CALLTYPE_DELEGATECALL) { + address to = address(bytes20(encodedExecutions[0:20])); + bytes calldata callData = encodedExecutions[20:]; + return onExecuteDelegateCallFromExecutor(_getAccount(), msgSender, to, callData); + } else { + revert InvalidCallType(); + } + } + + function postCheck(bytes calldata hookData) external virtual override { + onPostCheck(_getAccount(), hookData); + } + + /*////////////////////////////////////////////////////////////////////////// + EXECUTION + //////////////////////////////////////////////////////////////////////////*/ + + function onExecute( + address account, + address msgSender, + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + returns (bytes memory hookData) + { } + + function onExecuteBatch( + address account, + address msgSender, + Execution[] calldata + ) + internal + virtual + returns (bytes memory hookData) + { } + + function onExecuteDelegateCall( + address account, + address msgSender, + address target, + bytes calldata callData + ) + internal + virtual + returns (bytes memory hookData) + { } + + function onExecuteFromExecutor( + address account, + address msgSender, + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + returns (bytes memory hookData) + { } + + function onExecuteBatchFromExecutor( + address account, + address msgSender, + Execution[] calldata + ) + internal + virtual + returns (bytes memory hookData) + { } + + function onExecuteDelegateCallFromExecutor( + address account, + address msgSender, + address target, + bytes calldata callData + ) + internal + virtual + returns (bytes memory hookData) + { } + + /*////////////////////////////////////////////////////////////////////////// + CONFIG + //////////////////////////////////////////////////////////////////////////*/ + + function onInstallModule( + address account, + address msgSender, + uint256 moduleType, + address module, + bytes calldata initData + ) + internal + virtual + returns (bytes memory hookData) + { } + + function onUninstallModule( + address account, + address msgSender, + uint256 moduleType, + address module, + bytes calldata deInitData + ) + internal + virtual + returns (bytes memory hookData) + { } + + /*////////////////////////////////////////////////////////////////////////// + UNKNOWN FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function onUnknownFunction( + address account, + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + internal + virtual + returns (bytes memory hookData) + { } + + /*////////////////////////////////////////////////////////////////////////// + POSTCHECK + //////////////////////////////////////////////////////////////////////////*/ + + function onPostCheck(address account, bytes calldata hookData) internal virtual { } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestructSingleHook.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestructSingleHook.sol new file mode 100644 index 0000000..fbc21d6 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestructSingleHook.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { IERC7579Account } from "../accounts/common/interfaces/IERC7579Account.sol"; +import { IHook as IERC7579Hook } from "../accounts/common/interfaces/IERC7579Module.sol"; +import { ExecutionLib, Execution } from "../accounts/erc7579/lib/ExecutionLib.sol"; +import { + ModeLib, + CallType, + ModeCode, + CALLTYPE_SINGLE, + CALLTYPE_BATCH, + CALLTYPE_DELEGATECALL +} from "../accounts/common/lib/ModeLib.sol"; +import { IAccountExecute } from "../external/ERC4337.sol"; +import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; +import { TrustedForwarder } from "./utils/TrustedForwarder.sol"; + +uint256 constant EXECUSEROP_OFFSET = 164; +uint256 constant EXEC_OFFSET = 100; +uint256 constant INSTALL_OFFSET = 132; + +abstract contract ERC7579HookDestructSingleHook is IERC7579Hook, ERC7579ModuleBase { + error HookInvalidSelector(); + error InvalidCallType(); + + /*////////////////////////////////////////////////////////////////////////// + CALLDATA DECODING + //////////////////////////////////////////////////////////////////////////*/ + + function preCheck( + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + external + virtual + override + returns (bytes memory hookData) + { + bytes4 selector = bytes4(msgData[0:4]); + + if (selector == IAccountExecute.executeUserOp.selector) { + uint256 offset = + uint256(bytes32(msgData[EXECUSEROP_OFFSET:EXECUSEROP_OFFSET + 32])) + 68; + uint256 paramLen = uint256(bytes32(msgData[offset:offset + 32])); + offset += 32; + bytes calldata _msgData = msgData[offset:offset + paramLen]; + return _decodeCallData(msgSender, msgValue, _msgData); + } else { + return _decodeCallData(msgSender, msgValue, msgData); + } + } + + function _decodeCallData( + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + internal + returns (bytes memory hookData) + { + bytes4 selector = bytes4(msgData[0:4]); + if (selector == IERC7579Account.execute.selector) { + return _handle4337Executions(msgSender, msgData); + } else if (selector == IERC7579Account.executeFromExecutor.selector) { + return _handleExecutorExecutions(msgSender, msgData); + } else if (selector == IERC7579Account.installModule.selector) { + uint256 paramLen = msgData.length > INSTALL_OFFSET + ? uint256(bytes32(msgData[INSTALL_OFFSET - 32:INSTALL_OFFSET])) + : uint256(0); + bytes calldata initData = msgData.length > INSTALL_OFFSET + ? msgData[INSTALL_OFFSET:INSTALL_OFFSET + paramLen] + : msgData[0:0]; + uint256 moduleType = uint256(bytes32(msgData[4:36])); + address module = address(bytes20((msgData[48:68]))); + return onInstallModule(msg.sender, msgSender, moduleType, module, initData); + } else if (selector == IERC7579Account.uninstallModule.selector) { + uint256 paramLen = msgData.length > INSTALL_OFFSET + ? uint256(bytes32(msgData[INSTALL_OFFSET - 32:INSTALL_OFFSET])) + : uint256(0); + bytes calldata initData = msgData.length > INSTALL_OFFSET + ? msgData[INSTALL_OFFSET:INSTALL_OFFSET + paramLen] + : msgData[0:0]; + + uint256 moduleType = uint256(bytes32(msgData[4:36])); + address module = address(bytes20((msgData[48:68]))); + + return onUninstallModule(msg.sender, msgSender, moduleType, module, initData); + } else { + return onUnknownFunction(msg.sender, msgSender, msgValue, msgData); + } + } + + function _handle4337Executions( + address msgSender, + bytes calldata msgData + ) + internal + returns (bytes memory hookData) + { + uint256 paramLen = uint256(bytes32(msgData[EXEC_OFFSET - 32:EXEC_OFFSET])); + bytes calldata encodedExecutions = msgData[EXEC_OFFSET:EXEC_OFFSET + paramLen]; + + ModeCode mode = ModeCode.wrap(bytes32(msgData[4:36])); + CallType calltype = ModeLib.getCallType(mode); + + if (calltype == CALLTYPE_SINGLE) { + (address to, uint256 value, bytes calldata callData) = + ExecutionLib.decodeSingle(encodedExecutions); + return onExecute(msg.sender, msgSender, to, value, callData); + } else if (calltype == CALLTYPE_BATCH) { + Execution[] calldata execs = ExecutionLib.decodeBatch(encodedExecutions); + return onExecuteBatch(msg.sender, msgSender, execs); + } else if (calltype == CALLTYPE_DELEGATECALL) { + address to = address(bytes20(encodedExecutions[0:20])); + bytes calldata callData = encodedExecutions[20:]; + return onExecuteDelegateCall(msg.sender, msgSender, to, callData); + } else { + revert InvalidCallType(); + } + } + + function _handleExecutorExecutions( + address msgSender, + bytes calldata msgData + ) + internal + returns (bytes memory hookData) + { + uint256 paramLen = uint256(bytes32(msgData[EXEC_OFFSET - 32:EXEC_OFFSET])); + bytes calldata encodedExecutions = msgData[EXEC_OFFSET:EXEC_OFFSET + paramLen]; + + ModeCode mode = ModeCode.wrap(bytes32(msgData[4:36])); + CallType calltype = ModeLib.getCallType(mode); + + if (calltype == CALLTYPE_SINGLE) { + (address to, uint256 value, bytes calldata callData) = + ExecutionLib.decodeSingle(encodedExecutions); + return onExecuteFromExecutor(msg.sender, msgSender, to, value, callData); + } else if (calltype == CALLTYPE_BATCH) { + Execution[] calldata execs = ExecutionLib.decodeBatch(encodedExecutions); + return onExecuteBatchFromExecutor(msg.sender, msgSender, execs); + } else if (calltype == CALLTYPE_DELEGATECALL) { + address to = address(bytes20(encodedExecutions[0:20])); + bytes calldata callData = encodedExecutions[20:]; + return onExecuteDelegateCallFromExecutor(msg.sender, msgSender, to, callData); + } else { + revert InvalidCallType(); + } + } + + function postCheck(bytes calldata hookData) external virtual override { + onPostCheck(msg.sender, hookData); + } + + /*////////////////////////////////////////////////////////////////////////// + EXECUTION + //////////////////////////////////////////////////////////////////////////*/ + + function onExecute( + address account, + address msgSender, + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + returns (bytes memory hookData) + { } + + function onExecuteBatch( + address account, + address msgSender, + Execution[] calldata + ) + internal + virtual + returns (bytes memory hookData) + { } + + function onExecuteDelegateCall( + address account, + address msgSender, + address target, + bytes calldata callData + ) + internal + virtual + returns (bytes memory hookData) + { } + + function onExecuteFromExecutor( + address account, + address msgSender, + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + returns (bytes memory hookData) + { } + + function onExecuteBatchFromExecutor( + address account, + address msgSender, + Execution[] calldata + ) + internal + virtual + returns (bytes memory hookData) + { } + + function onExecuteDelegateCallFromExecutor( + address account, + address msgSender, + address target, + bytes calldata callData + ) + internal + virtual + returns (bytes memory hookData) + { } + + /*////////////////////////////////////////////////////////////////////////// + CONFIG + //////////////////////////////////////////////////////////////////////////*/ + + function onInstallModule( + address account, + address msgSender, + uint256 moduleType, + address module, + bytes calldata initData + ) + internal + virtual + returns (bytes memory hookData) + { } + + function onUninstallModule( + address account, + address msgSender, + uint256 moduleType, + address module, + bytes calldata deInitData + ) + internal + virtual + returns (bytes memory hookData) + { } + + /*////////////////////////////////////////////////////////////////////////// + UNKNOWN FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function onUnknownFunction( + address account, + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + internal + virtual + returns (bytes memory hookData) + { } + + /*////////////////////////////////////////////////////////////////////////// + POSTCHECK + //////////////////////////////////////////////////////////////////////////*/ + + function onPostCheck(address account, bytes calldata hookData) internal virtual { } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HybridValidatorBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HybridValidatorBase.sol new file mode 100644 index 0000000..a3d157a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HybridValidatorBase.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +/* solhint-disable no-unused-import */ + +import { + PackedUserOperation, + _packValidationData as _packValidationData4337 +} from "../external/ERC4337.sol"; +import { ERC7579ValidatorBase } from "./ERC7579ValidatorBase.sol"; +import { ERC7579StatelessValidatorBase } from "./ERC7579StatelessValidatorBase.sol"; + +/// @notice Base contract for hybrid validators, which are both stateful and stateless. +abstract contract ERC7579HybridValidatorBase is + ERC7579ValidatorBase, + ERC7579StatelessValidatorBase +{ } diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ModuleBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ModuleBase.sol new file mode 100644 index 0000000..e7e5ca8 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ModuleBase.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { IModule as IERC7579Module } from "../accounts/common/interfaces/IERC7579Module.sol"; +import { + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK, + MODULE_TYPE_HOOK, + MODULE_TYPE_POLICY, + MODULE_TYPE_SIGNER, + MODULE_TYPE_STATELESS_VALIDATOR +} from "./utils/ERC7579Constants.sol"; + +abstract contract ERC7579ModuleBase is IERC7579Module { + uint256 internal constant TYPE_VALIDATOR = MODULE_TYPE_VALIDATOR; + uint256 internal constant TYPE_EXECUTOR = MODULE_TYPE_EXECUTOR; + uint256 internal constant TYPE_FALLBACK = MODULE_TYPE_FALLBACK; + uint256 internal constant TYPE_HOOK = MODULE_TYPE_HOOK; + uint256 internal constant TYPE_POLICY = MODULE_TYPE_POLICY; + uint256 internal constant TYPE_SIGNER = MODULE_TYPE_SIGNER; + uint256 internal constant TYPE_STATELESS_VALIDATOR = MODULE_TYPE_STATELESS_VALIDATOR; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579PolicyBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579PolicyBase.sol new file mode 100644 index 0000000..df6c98f --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579PolicyBase.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; +import { IPolicy, ConfigId } from "./interfaces/IPolicy.sol"; + +abstract contract ERC7579PolicyBase is ERC7579ModuleBase, IPolicy { + function initializeWithMultiplexer( + address account, + ConfigId configId, + bytes calldata initData + ) + external + virtual; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579StatelessValidatorBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579StatelessValidatorBase.sol new file mode 100644 index 0000000..272d28a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579StatelessValidatorBase.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; +import { IStatelessValidator } from "./interfaces/IStatelessValidator.sol"; + +abstract contract ERC7579StatelessValidatorBase is ERC7579ModuleBase, IStatelessValidator { + function validateSignatureWithData( + bytes32, + bytes calldata, + bytes calldata + ) + external + view + virtual + returns (bool validSig); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579UserOpPolicy.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579UserOpPolicy.sol new file mode 100644 index 0000000..2d545bf --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579UserOpPolicy.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { ERC7579PolicyBase } from "./ERC7579PolicyBase.sol"; +import { ConfigId, IUserOpPolicy } from "./interfaces/IPolicy.sol"; +import { PackedUserOperation } from "../external/ERC4337.sol"; + +abstract contract ERC7579UserOpPolicy is ERC7579PolicyBase, IUserOpPolicy { + function checkUserOp( + ConfigId id, + PackedUserOperation calldata userOp + ) + external + virtual + returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorBase.sol new file mode 100644 index 0000000..8c23254 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorBase.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { + PackedUserOperation, + _packValidationData as _packValidationData4337 +} from "../external/ERC4337.sol"; +import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; + +abstract contract ERC7579ValidatorBase is ERC7579ModuleBase { + type ValidationData is uint256; + + ValidationData internal constant VALIDATION_SUCCESS = ValidationData.wrap(0); + ValidationData internal constant VALIDATION_FAILED = ValidationData.wrap(1); + bytes4 internal constant EIP1271_SUCCESS = 0x1626ba7e; + bytes4 internal constant EIP1271_FAILED = 0xFFFFFFFF; + + /** + * Helper to pack the return value for validateUserOp, when not using an aggregator. + * @param sigFailed - True for signature failure, false for success. + * @param validUntil - Last timestamp this UserOperation is valid (or zero for + * infinite). + * @param validAfter - First timestamp this UserOperation is valid. + */ + function _packValidationData( + bool sigFailed, + uint48 validUntil, + uint48 validAfter + ) + internal + pure + returns (ValidationData) + { + return ValidationData.wrap(_packValidationData4337(sigFailed, validUntil, validAfter)); + } + + function _unpackValidationData(ValidationData _packedData) + internal + pure + returns (bool sigFailed, uint48 validUntil, uint48 validAfter) + { + uint256 packedData = ValidationData.unwrap(_packedData); + sigFailed = (packedData & 1) == 1; + validUntil = uint48((packedData >> 160) & ((1 << 48) - 1)); + validAfter = uint48((packedData >> (160 + 48)) & ((1 << 48) - 1)); + } + + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + virtual + returns (ValidationData); + + function isValidSignatureWithSender( + address sender, + bytes32 hash, + bytes calldata data + ) + external + view + virtual + returns (bytes4); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorMaster.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorMaster.sol new file mode 100644 index 0000000..619d03c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorMaster.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { + PackedUserOperation, + _packValidationData as _packValidationData4337 +} from "../external/ERC4337.sol"; +import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; + +abstract contract ERC7579ValidatorBase is ERC7579ModuleBase { + type ValidationData is uint256; + + ValidationData internal constant VALIDATION_FAILED = ValidationData.wrap(1); + bytes4 internal constant EIP1271_SUCCESS = 0x1626ba7e; + bytes4 internal constant EIP1271_FAILED = 0xFFFFFFFF; + + modifier notInitialized() virtual; + modifier alreadyInitialized() virtual; + + // Modules may be intalled without being added to the account + function onInstall(bytes calldata data) external virtual override notInitialized { + _onInstall(data); + } + + function onUninstall(bytes calldata data) external virtual override alreadyInitialized { + _onUninstall(data); + } + + function _onInstall(bytes calldata data) internal virtual; + function _onUninstall(bytes calldata data) internal virtual; + + /** + * Helper to pack the return value for validateUserOp, when not using an aggregator. + * @param sigFailed - True for signature failure, false for success. + * @param validUntil - Last timestamp this UserOperation is valid (or zero for + * infinite). + * @param validAfter - First timestamp this UserOperation is valid. + */ + function _packValidationData( + bool sigFailed, + uint48 validUntil, + uint48 validAfter + ) + internal + pure + returns (ValidationData) + { + return ValidationData.wrap(_packValidationData4337(sigFailed, validUntil, validAfter)); + } + + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + virtual + returns (ValidationData); + + function isValidSignatureWithSender( + address sender, + bytes32 hash, + bytes calldata data + ) + external + view + virtual + returns (bytes4); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/SchedulingBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/SchedulingBase.sol new file mode 100644 index 0000000..a8354b5 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/SchedulingBase.sol @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { ERC7579ExecutorBase } from "./ERC7579ExecutorBase.sol"; + +abstract contract SchedulingBase is ERC7579ExecutorBase { + /*////////////////////////////////////////////////////////////////////////// + CONSTANTS & STORAGE + //////////////////////////////////////////////////////////////////////////*/ + + error InvalidExecution(); + + event ExecutionAdded(address indexed smartAccount, uint256 indexed jobId); + event ExecutionTriggered(address indexed smartAccount, uint256 indexed jobId); + event ExecutionStatusUpdated(address indexed smartAccount, uint256 indexed jobId); + event ExecutionsCancelled(address indexed smartAccount); + + mapping(address smartAccount => mapping(uint256 jobId => ExecutionConfig)) public executionLog; + + mapping(address smartAccount => uint256 jobCount) public accountJobCount; + + struct ExecutionConfig { + uint48 executeInterval; + uint16 numberOfExecutions; + uint16 numberOfExecutionsCompleted; + uint48 startDate; + bool isEnabled; + uint48 lastExecutionTime; + bytes executionData; + } + + struct ExecutorAccess { + uint256 jobId; + } + + /*////////////////////////////////////////////////////////////////////////// + CONFIG + //////////////////////////////////////////////////////////////////////////*/ + + function _onInstall(bytes calldata packedSchedulingData) internal { + address account = msg.sender; + if (isInitialized(account)) { + revert ModuleAlreadyInitialized(account); + } + + _createExecution({ orderData: packedSchedulingData }); + } + + function _onUninstall() internal { + address account = msg.sender; + + uint256 count = accountJobCount[account]; + for (uint256 i = 1; i <= count; i++) { + delete executionLog[account][i]; + } + accountJobCount[account] = 0; + + emit ExecutionsCancelled(account); + } + + function isInitialized(address smartAccount) public view returns (bool) { + return accountJobCount[smartAccount] != 0; + } + + function addOrder(bytes calldata orderData) external { + address account = msg.sender; + if (!isInitialized(account)) revert NotInitialized(account); + + _createExecution({ orderData: orderData }); + } + + function toggleOrder(uint256 jobId) external { + address account = msg.sender; + + ExecutionConfig storage executionConfig = executionLog[account][jobId]; + + if (executionConfig.numberOfExecutions == 0) { + revert InvalidExecution(); + } + + executionConfig.isEnabled = !executionConfig.isEnabled; + + emit ExecutionStatusUpdated(account, jobId); + } + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL + //////////////////////////////////////////////////////////////////////////*/ + + function _createExecution(bytes calldata orderData) internal { + address account = msg.sender; + + uint256 jobId = accountJobCount[account] + 1; + accountJobCount[account]++; + + // prevent user from supplying an invalid number of execution (0) + uint16 nrOfExecutions = uint16(bytes2(orderData[6:8])); + if (nrOfExecutions == 0) revert InvalidExecution(); + + executionLog[account][jobId] = ExecutionConfig({ + numberOfExecutionsCompleted: 0, + isEnabled: true, + lastExecutionTime: 0, + executeInterval: uint48(bytes6(orderData[0:6])), + numberOfExecutions: nrOfExecutions, + startDate: uint48(bytes6(orderData[8:14])), + executionData: orderData[14:] + }); + + emit ExecutionAdded(account, jobId); + } + + function _isExecutionValid(uint256 jobId) internal view { + ExecutionConfig storage executionConfig = executionLog[msg.sender][jobId]; + + if (!executionConfig.isEnabled) { + revert InvalidExecution(); + } + + if (executionConfig.lastExecutionTime + executionConfig.executeInterval > block.timestamp) { + revert InvalidExecution(); + } + + if (executionConfig.numberOfExecutionsCompleted >= executionConfig.numberOfExecutions) { + revert InvalidExecution(); + } + + if (executionConfig.startDate > block.timestamp) { + revert InvalidExecution(); + } + } + + modifier canExecute(uint256 jobId) { + _isExecutionValid(jobId); + _; + } + + /*////////////////////////////////////////////////////////////////////////// + METADATA + //////////////////////////////////////////////////////////////////////////*/ + + function isModuleType(uint256 typeID) external pure override returns (bool) { + return typeID == TYPE_EXECUTOR; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/Flashloan.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/Flashloan.sol new file mode 100644 index 0000000..e52e59d --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/Flashloan.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +enum FlashLoanType { + ERC20, + ERC721 +} + +interface IERC6682 { + function flashFeeToken() external view returns (address); + function flashFee(address token, uint256 tokenId) external view returns (uint256); + function availableForFlashLoan(address token, uint256 tokenId) external view returns (bool); +} + +/** + * @dev Interface of the ERC3156 FlashLender, as defined in + * https://eips.ethereum.org/EIPS/eip-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); +} + +/** + * @dev Interface of the ERC3156 FlashBorrower, as defined in + * https://eips.ethereum.org/EIPS/eip-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/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC1271.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC1271.sol new file mode 100644 index 0000000..2bce20b --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC1271.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +// bytes4(keccak256("isValidSignature(bytes32,bytes)") +bytes4 constant EIP1271_MAGIC_VALUE = 0x1626ba7e; + +interface IERC1271 { + /** + * @dev Should return whether the signature provided is valid for the provided data + * @param _dataHash Arbitrary length data signed on behalf of address(this) + * @param _signature Signature byte array associated with _data + * + * MUST return the bytes4 magic value 0x1626ba7e when function passes. + * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > + * 0.5) + * MUST allow external calls + */ + function isValidSignature( + bytes32 _dataHash, + bytes calldata _signature + ) + external + view + returns (bytes4); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC712.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC712.sol new file mode 100644 index 0000000..9b88f2c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC712.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +interface IERC712 { + function domainSeparator() external view returns (bytes32); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC7484.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC7484.sol new file mode 100644 index 0000000..bc07019 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC7484.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IERC7484 { + event NewTrustedAttesters(); + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Check with Registry internal attesters */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function check(address module) external view; + + function checkForAccount(address smartAccount, address module) external view; + + function check(address module, uint256 moduleType) external view; + + function checkForAccount( + address smartAccount, + address module, + uint256 moduleType + ) + external + view; + + /** + * Allows Smart Accounts - the end users of the registry - to appoint + * one or many attesters as trusted. + * @dev this function reverts, if address(0), or duplicates are provided in attesters[] + * + * @param threshold The minimum number of attestations required for a module + * to be considered secure. + * @param attesters The addresses of the attesters to be trusted. + */ + function trustAttesters(uint8 threshold, address[] calldata attesters) external; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Check with external attester(s) */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function check(address module, address[] calldata attesters, uint256 threshold) external view; + + function check( + address module, + uint256 moduleType, + address[] calldata attesters, + uint256 threshold + ) + external + view; +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IPolicy.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IPolicy.sol new file mode 100644 index 0000000..63e1829 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IPolicy.sol @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +// solhint-disable no-unused-import +import { PackedUserOperation, _packValidationData } from "../../external/ERC4337.sol"; +import { + IModule as IERC7579Module, + VALIDATION_SUCCESS, + VALIDATION_FAILED +} from "../../accounts/common/interfaces/IERC7579Module.sol"; +import { IERC165 } from "forge-std/interfaces/IERC165.sol"; + +type ConfigId is bytes32; + +/** + * IPolicy are external contracts that enforce policies / permission on 4337/7579 executions + * Since it's not the account calling into this contract, and check functions are called during the + * ERC4337 validation + * phase, IPolicy implementations MUST follow ERC4337 storage and opcode restrictions + * A recommend storage layout to store policy related data: + * mapping(id => msg.sender => userOp.sender(account) => state) + * ^ smartSession ^ smart account (associated storage) + */ +interface IPolicy is IERC165, IERC7579Module { + function isInitialized(address account, ConfigId configId) external view returns (bool); + function isInitialized( + address account, + address mulitplexer, + ConfigId configId + ) + external + view + returns (bool); + + /** + * This function may be called by the multiplexer (SmartSessions) without deinitializing first. + * Policies MUST overwrite the current state when this happens + */ + function initializeWithMultiplexer( + address account, + ConfigId configId, + bytes calldata initData + ) + external; +} + +/** + * IUserOpPolicy is a policy that enforces restrictions on user operations. It is called during the + * validation phase + * of the ERC4337 execution. + * Use this policy to enforce restrictions on user operations (userOp.gas, Time based restrictions). + * The checkUserOpPolicy function should return a uint256 value that represents the policy's + * decision. + * The policy's decision should be one of the following: + * - VALIDATION_SUCCESS: The user operation is allowed. + * - VALIDATION_FAILED: The user operation is not allowed. + */ +interface IUserOpPolicy is IPolicy { + function checkUserOpPolicy( + ConfigId id, + PackedUserOperation calldata userOp + ) + external + returns (uint256); +} + +/** + * IActionPolicy is a policy that enforces restrictions on actions. It is called during the + * validation phase + * of the ERC4337 execution. + * ERC7579 accounts natively support batched executions. So in one userOp, multiple actions can be + * executed. + * SmartSession will destruct the execution batch, and call the policy for each action, if the + * policy is installed for + * the actionId for the account. + * Use this policy to enforce restrictions on individual actions (i.e. transfers, approvals, etc). + * The checkAction function should return a uint256 value that represents the policy's decision. + * The policy's decision should be one of the following: + * - VALIDATION_SUCCESS: The action is allowed. + * - VALIDATION_FAILED: The action is not allowed. + */ +interface IActionPolicy is IPolicy { + function checkAction( + ConfigId id, + address account, + address target, + uint256 value, + bytes calldata data + ) + external + returns (uint256); +} + +/** + * I1271Policy is a policy that enforces restrictions on 1271 signed actions. It is called during an + * ERC1271 signature + * validation + */ +interface I1271Policy is IPolicy { + // request sender is probably protocol, so can introduce policies based on it. + function check1271SignedAction( + ConfigId id, + address requestSender, + address account, + bytes32 hash, + bytes calldata signature + ) + external + view + returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IStatelessValidator.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IStatelessValidator.sol new file mode 100644 index 0000000..59c367e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IStatelessValidator.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +interface IStatelessValidator { + function validateSignatureWithData( + bytes32 hash, + bytes calldata signature, + bytes calldata data + ) + external + view + returns (bool); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockExecutor.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockExecutor.sol new file mode 100644 index 0000000..f77c19d --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockExecutor.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import { ERC7579ExecutorBase } from "../ERC7579ExecutorBase.sol"; +// solhint-disable-next-line no-unused-import +import { IERC7579Account } from "../../accounts/common/interfaces/IERC7579Account.sol"; + +contract MockExecutor is ERC7579ExecutorBase { + function onInstall(bytes calldata data) external override { } + + function onUninstall(bytes calldata data) external override { } + + function exec( + address account, + address to, + uint256 value, + bytes calldata callData + ) + external + returns (bytes memory) + { + return _execute(account, to, value, callData); + } + + function isModuleType(uint256 typeID) external pure override returns (bool) { + return typeID == TYPE_EXECUTOR; + } + + function isInitialized( + address // smartAccount + ) + external + pure + returns (bool) + { + return false; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockFallback.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockFallback.sol new file mode 100644 index 0000000..d140019 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockFallback.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import { ERC7579FallbackBase } from "../ERC7579FallbackBase.sol"; + +contract MockFallback is ERC7579FallbackBase { + function onInstall(bytes calldata data) external override { } + + function onUninstall(bytes calldata data) external override { } + + function targetFunction() external pure returns (bool) { + return true; + } + + function isModuleType(uint256 typeID) external pure returns (bool) { + return typeID == TYPE_FALLBACK; + } + + function isInitialized( + address // smartAccount + ) + external + pure + returns (bool) + { + return false; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHook.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHook.sol new file mode 100644 index 0000000..6906f9e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHook.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import { ERC7579HookBase } from "../ERC7579HookBase.sol"; + +contract MockHook is ERC7579HookBase { + function onInstall(bytes calldata data) external override { } + + function onUninstall(bytes calldata data) external override { } + + function _preCheck( + address account, + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + internal + override + returns (bytes memory hookData) + { } + function _postCheck(address account, bytes calldata hookData) internal override { } + + function isInitialized( + address // smartAccount + ) + external + pure + returns (bool) + { + return false; + } + + function isModuleType(uint256 typeID) external pure returns (bool) { + return typeID == TYPE_HOOK; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHookMultiPlexer.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHookMultiPlexer.sol new file mode 100644 index 0000000..0362dd0 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHookMultiPlexer.sol @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import { ERC7579HookBase } from "../ERC7579HookBase.sol"; + +contract MockHookMultiPlexer is ERC7579HookBase { + error PreCheckFailed(address hook); + error PostCheckFailed(address hook); + + struct Hook { + address hook; + bool isInitialized; + } + + mapping(address account => Hook[] hookData) public hooks; + + function onInstall(bytes calldata data) external override { + if (data.length == 0) return; + (address[] memory _hooks) = abi.decode(data, (address[])); + for (uint256 i = 0; i < _hooks.length; i++) { + Hook memory _hook = Hook(_hooks[i], true); + hooks[msg.sender].push(_hook); + } + } + + function onUninstall(bytes calldata) external override { + delete hooks[msg.sender]; + } + + function addHook(address hook) external { + Hook memory _hook = Hook(hook, false); + hooks[msg.sender].push(_hook); + } + + function removeHook(address hook) external { + Hook[] storage _hooks = hooks[msg.sender]; + for (uint256 i = 0; i < _hooks.length; i++) { + if (_hooks[i].hook == hook) { + _hooks[i] = _hooks[_hooks.length - 1]; + _hooks.pop(); + break; + } + } + } + + function isHookInstalled(address account, address hook) external view returns (bool) { + Hook[] memory _hooks = hooks[account]; + for (uint256 i = 0; i < _hooks.length; i++) { + if (_hooks[i].hook == hook) return true; + } + return false; + } + + function _preCheck( + address account, + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + internal + override + returns (bytes memory hookData) + { + uint256 length = hooks[account].length; + if (length == 0) return hookData; + + bytes[] memory _hookData = new bytes[](length); + for (uint256 i = 0; i < length; i++) { + Hook storage _hook = hooks[account][i]; + if (!_hook.isInitialized) { + _hook.isInitialized = true; + } + (bool success, bytes memory _ret) = _hook.hook.call( + abi.encodePacked( + abi.encodeCall(ERC7579HookBase.preCheck, (msgSender, msgValue, msgData)), + address(this), + msg.sender + ) + ); + if (!success) revert PreCheckFailed(_hook.hook); + _hookData[i] = abi.decode(_ret, (bytes)); + } + hookData = abi.encode(_hookData); + } + + function _postCheck(address account, bytes calldata hookData) internal override { + uint256 length = hooks[account].length; + if (length == 0) return; + + bytes[] memory _hookData = new bytes[](length); + if (hookData.length != 0) { + _hookData = abi.decode(hookData, (bytes[])); + } + for (uint256 i = 0; i < length; i++) { + Hook storage _hook = hooks[account][i]; + if (_hook.isInitialized) { + (bool success,) = _hook.hook.call( + abi.encodePacked( + abi.encodeCall(ERC7579HookBase.postCheck, (_hookData[i])), + address(this), + msg.sender + ) + ); + if (!success) revert PostCheckFailed(_hook.hook); + } + } + } + + function isInitialized(address smartAccount) external view returns (bool) { + return hooks[smartAccount].length > 0; + } + + function isModuleType(uint256 typeID) external pure returns (bool) { + return typeID == TYPE_HOOK; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHybridValidator.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHybridValidator.sol new file mode 100644 index 0000000..fa9a5ae --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHybridValidator.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import { ERC7579HybridValidatorBase } from "../ERC7579HybridValidatorBase.sol"; +import { PackedUserOperation } from "../../external/ERC4337.sol"; + +contract MockHybridValidator is ERC7579HybridValidatorBase { + function onInstall(bytes calldata data) external virtual override { } + + function onUninstall(bytes calldata data) external virtual override { } + + function validateUserOp( + PackedUserOperation calldata, // userOp + bytes32 // userOpHash + ) + external + virtual + override + returns (ValidationData) + { + return + _packValidationData({ sigFailed: false, validUntil: type(uint48).max, validAfter: 0 }); + } + + function isValidSignatureWithSender( + address, // sender + bytes32, // hash + bytes calldata // data + ) + external + view + virtual + override + returns (bytes4) + { + return EIP1271_SUCCESS; + } + + function isModuleType(uint256 typeID) external pure override returns (bool) { + return typeID == TYPE_VALIDATOR || typeID == TYPE_STATELESS_VALIDATOR; + } + + function isInitialized( + address // smartAccount + ) + external + pure + returns (bool) + { + return false; + } + + function validateSignatureWithData( + bytes32, + bytes calldata, + bytes calldata + ) + external + pure + override + returns (bool validSig) + { + return true; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockPolicy.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockPolicy.sol new file mode 100644 index 0000000..398da15 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockPolicy.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import { PackedUserOperation } from + "@ERC4337/account-abstraction/contracts/interfaces/PackedUserOperation.sol"; + +contract MockPolicy { + mapping(address account => uint256 validation) public validationData; + mapping( + bytes32 id => mapping(address msgSender => mapping(address userOpSender => uint256 calls)) + ) public userOpState; + mapping( + bytes32 id => mapping(address msgSender => mapping(address userOpSender => uint256 calls)) + ) public actionState; + + function setValidationData(address account, uint256 validation) external { + validationData[account] = validation; + } + + function initializeWithMultiplexer( + address account, + bytes32 configId, + bytes calldata + ) + external + { + userOpState[configId][msg.sender][account] = 1; + } + + function checkUserOpPolicy( + bytes32 id, + PackedUserOperation calldata userOp + ) + external + returns (uint256) + { + userOpState[id][msg.sender][userOp.sender] += 1; + return validationData[userOp.sender]; + } + + function checkAction( + bytes32 id, + address account, + address, + uint256, + bytes calldata + ) + external + returns (uint256) + { + actionState[id][msg.sender][account] += 1; + return validationData[account]; + } + + function supportsInterface(bytes4) external pure returns (bool) { + return true; + } + + function check1271SignedAction( + bytes32, + address, + address, + bytes32, + bytes calldata + ) + external + pure + returns (bool) + { + return true; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockRegistry.sol new file mode 100644 index 0000000..4f1c092 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockRegistry.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import { IERC7484 } from "../interfaces/IERC7484.sol"; + +/// @title MockRegistry +/// @author zeroknots +contract MockRegistry is IERC7484 { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Check with Registry internal attesters */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + function check(address module) external view { } + + function checkForAccount(address smartAccount, address module) external view { } + + function check(address module, uint256 moduleType) external view { } + + function checkForAccount( + address smartAccount, + address module, + uint256 moduleType + ) + external + view + { } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Check with external attester(s) */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function check(address module, address[] calldata attesters, uint256 threshold) external view { } + + function check( + address module, + uint256 moduleType, + address[] calldata attesters, + uint256 threshold + ) + external + view + { } + + function trustAttesters(uint8 threshold, address[] calldata attesters) external { } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockStatelessValidator.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockStatelessValidator.sol new file mode 100644 index 0000000..835469e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockStatelessValidator.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import { ERC7579StatelessValidatorBase } from "../ERC7579StatelessValidatorBase.sol"; + +contract MockStatelessValidator is ERC7579StatelessValidatorBase { + function onInstall(bytes calldata data) external virtual { } + + function onUninstall(bytes calldata data) external virtual { } + + function isModuleType(uint256 typeID) external pure returns (bool) { + return typeID == 7; + } + + function isInitialized(address) external pure returns (bool) { + return true; + } + + function validateSignatureWithData( + bytes32, + bytes calldata, + bytes calldata + ) + external + pure + override + returns (bool validSig) + { + return true; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockTarget.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockTarget.sol new file mode 100644 index 0000000..12a3ef5 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockTarget.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +contract MockTarget { + error Unauthorized(); + + uint256 public value; + + function set(uint256 _value) public payable returns (uint256) { + value = _value; + return _value; + } + + function setAccessControl(uint256 _value) public returns (uint256) { + if (msg.sender != address(this)) { + revert Unauthorized(); + } + value = _value; + return _value; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockValidator.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockValidator.sol new file mode 100644 index 0000000..0b77c2f --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockValidator.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +/* solhint-disable no-unused-vars */ +import { ERC7579ValidatorBase } from "../ERC7579ValidatorBase.sol"; +import { PackedUserOperation } from "../../external/ERC4337.sol"; + +contract MockValidator is ERC7579ValidatorBase { + function onInstall(bytes calldata data) external virtual override { } + + function onUninstall(bytes calldata data) external virtual override { } + + function validateUserOp( + PackedUserOperation calldata, // userOp + bytes32 // userOpHash + ) + external + virtual + override + returns (ValidationData) + { + return + _packValidationData({ sigFailed: false, validUntil: type(uint48).max, validAfter: 0 }); + } + + function isValidSignatureWithSender( + address, // sender + bytes32, // hash + bytes calldata // data + ) + external + view + virtual + override + returns (bytes4) + { + return EIP1271_SUCCESS; + } + + function isModuleType(uint256 typeID) external pure override returns (bool) { + return typeID == TYPE_VALIDATOR; + } + + function isInitialized( + address // smartAccount + ) + external + pure + returns (bool) + { + return false; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579Constants.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579Constants.sol new file mode 100644 index 0000000..e075df5 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579Constants.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +uint256 constant MODULE_TYPE_VALIDATOR = 1; +uint256 constant MODULE_TYPE_EXECUTOR = 2; +uint256 constant MODULE_TYPE_FALLBACK = 3; +uint256 constant MODULE_TYPE_HOOK = 4; +uint256 constant MODULE_TYPE_POLICY = 5; +uint256 constant MODULE_TYPE_SIGNER = 6; +uint256 constant MODULE_TYPE_STATELESS_VALIDATOR = 7; +uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC1271 = 8; +uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC4337 = 9; diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579ValidatorLib.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579ValidatorLib.sol new file mode 100644 index 0000000..cfc4173 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579ValidatorLib.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +// solhint-disable-next-line no-unused-import +import { IERC7579Account, Execution } from "../../accounts/common/interfaces/IERC7579Account.sol"; +import { PackedUserOperation, UserOperationLib } from "../../external/ERC4337.sol"; + +enum ACCOUNT_EXEC_TYPE { + EXEC_SINGLE, + EXEC_BATCH, + EXEC_SINGLE_FROM_EXECUTOR, + EXEC_BATCH_FROM_EXECUTOR, + UNINSTALL_HOOK, + INSTALL_VALIDATOR, + INSTALL_EXECUTOR, + ERROR +} + +library ERC7579ValidatorLib { + error InvalidExecutionType(); + + function decodeExecType(PackedUserOperation calldata _ops) + internal + pure + returns (ACCOUNT_EXEC_TYPE _type) + { + return decodeExecType(_ops.callData); + } + + function decodeExecType(bytes calldata userOpCalldata) + internal + pure + returns (ACCOUNT_EXEC_TYPE _type) + { + // bytes4 functionSig = bytes4(userOpCalldata[:4]); + + // if (IERC7579Account.execute.selector == functionSig) { + // _type = ACCOUNT_EXEC_TYPE.EXEC_SINGLE; + // } else if (IERC7579Account.executeBatch.selector == functionSig) { + // _type = ACCOUNT_EXEC_TYPE.EXEC_BATCH; + // } else if (IERC7579Account.executeFromExecutor.selector == functionSig) { + // _type = ACCOUNT_EXEC_TYPE.EXEC_SINGLE_FROM_EXECUTOR; + // } else if (IERC7579Account.executeBatchFromExecutor.selector == functionSig) { + // _type = ACCOUNT_EXEC_TYPE.EXEC_BATCH_FROM_EXECUTOR; + // } else if (IERC7579Account.installValidator.selector == functionSig) { + // _type = ACCOUNT_EXEC_TYPE.INSTALL_VALIDATOR; + // } else if (IERC7579Account.installExecutor.selector == functionSig) { + // _type = ACCOUNT_EXEC_TYPE.INSTALL_EXECUTOR; + // } else if (IERC7579Account.uninstallHook.selector == functionSig) { + // _type = ACCOUNT_EXEC_TYPE.UNINSTALL_HOOK; + // } else { + // _type = ACCOUNT_EXEC_TYPE.ERROR; + // } + } + + function decodeCalldataBatch(bytes calldata userOpCalldata) + internal + pure + returns (Execution[] calldata executionBatch) + { + /* + * Batch Call Calldata Layout + * Offset (in bytes) | Length (in bytes) | Contents + * 0x0 | 0x4 | bytes4 function selector + * 0x4 | - | + abi.encode(Execution[]) + */ + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + let offset := add(userOpCalldata.offset, 0x4) + let baseOffset := offset + + let dataPointer := add(baseOffset, calldataload(offset)) + + // Extract the ERC7579 Executions + executionBatch.offset := add(dataPointer, 32) + executionBatch.length := calldataload(dataPointer) + } + } + + function decodeCalldataSingle(bytes calldata userOpCalldata) + internal + pure + returns (address destination, uint256 value, bytes calldata callData) + { + bytes calldata accountExecCallData = userOpCalldata[4:]; + destination = address(bytes20(accountExecCallData[12:32])); + value = uint256(bytes32(accountExecCallData[32:64])); + callData = accountExecCallData[128:userOpCalldata.length - 32]; + } + + function decodeConfig(bytes calldata callData) + internal + pure + returns (address module, bytes calldata _callData) + { + module = address(bytes20(callData[12:32])); + _callData = callData[32:]; + } + + function validateWith( + PackedUserOperation calldata userOp, + function(PackedUserOperation calldata,address,uint256,bytes calldata) internal returns(uint48,uint48) + validationFunction + ) + internal + returns (uint48 validUntil, uint48 validAfter) + { + ACCOUNT_EXEC_TYPE _type = decodeExecType(userOp); + + address target; + uint256 value; + bytes calldata callData; + if (ACCOUNT_EXEC_TYPE.EXEC_SINGLE == _type) { + (target, value, callData) = decodeCalldataSingle(userOp.callData); + (validUntil, validAfter) = validationFunction(userOp, target, value, callData); + } else if (ACCOUNT_EXEC_TYPE.EXEC_BATCH == _type) { + Execution[] calldata executionBatch = decodeCalldataBatch(userOp.callData); + uint256 length = executionBatch.length; + for (uint256 i; i < length; i++) { + Execution calldata execution = executionBatch[i]; + (target, value, callData) = (execution.target, execution.value, execution.callData); + (uint256 _newValidUntil, uint256 _newValidAfter) = + validationFunction(userOp, target, value, callData); + (validUntil, validAfter) = + getValidUntil(validUntil, validAfter, _newValidUntil, _newValidAfter); + } + } else { + revert InvalidExecutionType(); + } + } +} + +abstract contract Decoder { + using ERC7579ValidatorLib for *; + using UserOperationLib for *; + + function validate(PackedUserOperation calldata userOp) internal { + ACCOUNT_EXEC_TYPE accountExecType = userOp.callData.decodeExecType(); + address smartAccount = userOp.getSender(); + + if (ACCOUNT_EXEC_TYPE.EXEC_SINGLE == accountExecType) { + (address target, uint256 value, bytes calldata data) = + ERC7579ValidatorLib.decodeCalldataSingle(userOp.callData); + onValidate(smartAccount, target, value, data); + } else if (ACCOUNT_EXEC_TYPE.EXEC_BATCH == accountExecType) { + Execution[] calldata executionBatch = + ERC7579ValidatorLib.decodeCalldataBatch(userOp.callData); + uint256 length; + for (uint256 i; i < length; i++) { + Execution calldata execution = executionBatch[i]; + onValidate(smartAccount, execution.target, execution.value, execution.callData); + } + } else { + revert ERC7579ValidatorLib.InvalidExecutionType(); + } + } + + function onValidate( + address smartAccount, + address target, + uint256 value, + bytes calldata data + ) + internal + virtual + returns (bytes[] memory); +} + +function getValidUntil( + uint256 maxValidUntil, + uint256 minValidAfter, + uint256 newValidUntil, + uint256 newValidAfter +) + pure + returns (uint48 _maxValidUntil, uint48 _minValidAfter) +{ + if (newValidUntil > maxValidUntil) { + _maxValidUntil = uint48(newValidUntil); + } else { + _maxValidUntil = uint48(maxValidUntil); + } + + if (newValidAfter > minValidAfter) { + _minValidAfter = uint48(newValidAfter); + } else { + _minValidAfter = uint48(minValidAfter); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/TrustedForwarder.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/TrustedForwarder.sol new file mode 100644 index 0000000..da84eec --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/TrustedForwarder.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +abstract contract TrustedForwarder { + // account => trustedForwarder + mapping(address account => address trustedForwarder) public trustedForwarder; + + /** + * Set the trusted forwarder for an account + * + * @param forwarder The address of the trusted forwarder + */ + function setTrustedForwarder(address forwarder) external { + trustedForwarder[msg.sender] = forwarder; + } + + /** + * Clear the trusted forwarder for an account + */ + function clearTrustedForwarder() public { + trustedForwarder[msg.sender] = address(0); + } + + /** + * Check if a forwarder is trusted for an account + * + * @param forwarder The address of the forwarder + * @param account The address of the account + * + * @return true if the forwarder is trusted for the account + */ + function isTrustedForwarder(address forwarder, address account) public view returns (bool) { + return forwarder == trustedForwarder[account]; + } + + /** + * Get the sender of the transaction + * + * @return account the sender of the transaction + */ + function _getAccount() internal view returns (address account) { + account = msg.sender; + address _account; + address forwarder; + if (msg.data.length >= 40) { + // solhint-disable-next-line no-inline-assembly + assembly { + _account := shr(96, calldataload(sub(calldatasize(), 20))) + forwarder := shr(96, calldataload(sub(calldatasize(), 40))) + } + if (forwarder == msg.sender && isTrustedForwarder(forwarder, _account)) { + account = _account; + } + } + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/Auxiliary.sol b/typescript/packages/account-modules/lib/modulekit/src/test/Auxiliary.sol new file mode 100644 index 0000000..89831ee --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/Auxiliary.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IEntryPoint, PackedUserOperation } from "../external/ERC4337.sol"; +import { IERC7579Bootstrap } from "../accounts/erc7579/interfaces/IERC7579Bootstrap.sol"; +import { IERC7484 } from "../Interfaces.sol"; +import { ISmartSession } from "../integrations/interfaces/ISmartSession.sol"; + +// Deployments +import { etchEntrypoint } from "../deployment/predeploy/EntryPoint.sol"; +import { etchSmartSessions } from "../deployment/precompiles/SmartSessionsPrecompiles.sol"; +import { etchRegistry } from "../deployment/predeploy/Registry.sol"; + +// External Dependencies +import { EntryPointSimulations } from + "@ERC4337/account-abstraction/contracts/core/EntryPointSimulations.sol"; +import { IEntryPointSimulations } from + "@ERC4337/account-abstraction/contracts/interfaces/IEntryPointSimulations.sol"; + +// Mocks +import { MockFactory } from "../deployment/predeploy/MockFactory.sol"; + +// Utils +import { UserOpGasLog } from "./utils/gas/UserOpGasLog.sol"; +import "./utils/Vm.sol"; +import "./utils/Log.sol"; + +/// @notice Auxiliary structs to hold all the necessary auxiliary contracts for testing. +/// @param entrypoint The entrypoint contract. +/// @param gasSimulation The gas simulation contract. +/// @param registry The registry contract. +/// @param mockFactory The mock factory contract. +/// @param smartSession The smart session contract. +struct Auxiliary { + IEntryPoint entrypoint; + UserOpGasLog gasSimulation; + IERC7484 registry; + MockFactory mockFactory; + ISmartSession smartSession; +} + +/// @notice Auxiliary factory to deploy all the necessary auxiliary contracts for testing. +contract AuxiliaryFactory { + /// @notice Stores the auxiliary contracts. + Auxiliary public auxiliary; + + /// @notice Initializes and labels all the auxiliary contracts. + function init() internal virtual { + auxiliary.mockFactory = new MockFactory(); + label(address(auxiliary.mockFactory), "Mock Factory"); + auxiliary.gasSimulation = new UserOpGasLog(); + auxiliary.entrypoint = etchEntrypoint(); + label(address(auxiliary.entrypoint), "EntryPoint"); + auxiliary.registry = etchRegistry(); + label(address(auxiliary.registry), "ERC7484Registry"); + auxiliary.smartSession = etchSmartSessions(); + label(address(auxiliary.smartSession), "SmartSession"); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/ModuleKitHelpers.sol b/typescript/packages/account-modules/lib/modulekit/src/test/ModuleKitHelpers.sol new file mode 100644 index 0000000..55252ec --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/ModuleKitHelpers.sol @@ -0,0 +1,1322 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { + AccountInstance, + UserOpData, + ExecutionReturnData, + AccountType, + DEFAULT, + SAFE, + NEXUS, + KERNEL, + CUSTOM +} from "./RhinestoneModuleKit.sol"; +import { PackedUserOperation } from "../external/ERC4337.sol"; +import { MODULE_TYPE_HOOK } from "../accounts/common/interfaces/IERC7579Module.sol"; +import { Execution } from "../accounts/erc7579/lib/ExecutionLib.sol"; +import { + Session, + PermissionId, + ActionData, + PolicyData, + ERC7739Data, + ISessionValidator, + SmartSessionMode, + ISmartSession, + EnableSession, + ChainDigest +} from "../integrations/interfaces/ISmartSession.sol"; +import { Solarray } from "solarray/Solarray.sol"; + +// Helpers +import { ERC4337Helpers } from "./utils/ERC4337Helpers.sol"; +import { HelperBase } from "./helpers/HelperBase.sol"; +import { KernelHelpers } from "./helpers/KernelHelpers.sol"; + +// Utils +import { + prank, + VmSafe, + startStateDiffRecording as vmStartStateDiffRecording, + stopAndReturnStateDiff as vmStopAndReturnStateDiff, + getMappingKeyAndParentOf, + envOr, + setEnv +} from "./utils/Vm.sol"; +import { + getAccountType as getAccountTypeFromStorage, + writeAccountType, + writeExpectRevert, + writeGasIdentifier, + writeSimulateUserOp, + writeStorageCompliance, + getStorageCompliance, + getSimulateUserOp, + writeAccountEnv, + getFactory, + getHelper as getHelperFromStorage, + getAccountEnv as getAccountEnvFromStorage, + getInstalledModules as getInstalledModulesFromStorage, + writeInstalledModule as writeInstalledModuleToStorage, + removeInstalledModule as removeInstalledModuleFromStorage, + InstalledModule +} from "./utils/Storage.sol"; +import { recordLogs, VmSafe, getRecordedLogs } from "./utils/Vm.sol"; + +// Libraries +import { EncodeLib, HashLib } from "../test/helpers/SmartSessionHelpers.sol"; + +/// @notice A library that contains helper functions for building, testing, deploying, and +/// interacting with ERC7579 accounts and modules +library ModuleKitHelpers { + /*////////////////////////////////////////////////////////////////////////// + ERRORS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Thrown when an invalid account type is provided, currently only DEFAULT, SAFE, + /// KERNEL, CUSTOM, and NEXUS are supported account types + error InvalidAccountType(); + + /// @notice Thrown when the smart sessions module is not installed + error SmartSessionNotInstalled(); + + /*////////////////////////////////////////////////////////////////////////// + LIBRARIES + //////////////////////////////////////////////////////////////////////////*/ + + using ModuleKitHelpers for AccountInstance; + using ModuleKitHelpers for UserOpData; + using ModuleKitHelpers for AccountType; + + /*////////////////////////////////////////////////////////////////////////// + EXECUTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Executes userOps on the entrypoint + /// @param userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint + /// @return ExecutionReturnData struct containing the logs from the execution + function execUserOps(UserOpData memory userOpData) + internal + returns (ExecutionReturnData memory) + { + // Send userOp to entrypoint + return ERC4337Helpers.exec4337(userOpData.userOp, userOpData.entrypoint); + } + + /// @notice Configures a userOp to execute a single operation + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param target The address of the contract to call + /// @param value The amount of ether to send + /// @param callData The data to send to the contract + /// @param txValidator The address of the transaction validator + /// @return userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint + function getExecOps( + AccountInstance memory instance, + address target, + uint256 value, + bytes memory callData, + address txValidator + ) + internal + returns (UserOpData memory userOpData) + { + bytes memory erc7579ExecCall = + HelperBase(instance.accountHelper).encode(target, value, callData); + (userOpData.userOp, userOpData.userOpHash) = + HelperBase(instance.accountHelper).execUserOp(instance, erc7579ExecCall, txValidator); + userOpData.entrypoint = instance.aux.entrypoint; + } + + /// @notice Configures a userOp to execute multiple operations + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param executions An array of Execution structs containing the target, value, and callData + /// @param txValidator The address of the transaction validator + /// @return userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint + function getExecOps( + AccountInstance memory instance, + Execution[] memory executions, + address txValidator + ) + internal + returns (UserOpData memory userOpData) + { + bytes memory erc7579ExecCall = HelperBase(instance.accountHelper).encode(executions); + (userOpData.userOp, userOpData.userOpHash) = + HelperBase(instance.accountHelper).execUserOp(instance, erc7579ExecCall, txValidator); + userOpData.entrypoint = instance.aux.entrypoint; + } + + /// @notice Configures a userOp to execute a single operation, signs it with the default + /// signature, and sends it to the entrypoint for execution + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param target The address of the contract to call + /// @param value The amount of ether to send + /// @param callData The data to send to the contract + /// @return userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint + function exec( + AccountInstance memory instance, + address target, + uint256 value, + bytes memory callData + ) + internal + returns (UserOpData memory userOpData) + { + // Get userOpData + userOpData = + instance.getExecOps(target, value, callData, address(instance.defaultValidator)); + // Sign userOp with default signature + userOpData = userOpData.signDefault(); + userOpData.entrypoint = instance.aux.entrypoint; + // Send userOp to entrypoint + userOpData.execUserOps(); + } + + /// @notice Executes a single operation on the entrypoint with value 0 + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param target The address of the contract to call + /// @param callData The data to send to the contract + function exec( + AccountInstance memory instance, + address target, + bytes memory callData + ) + internal + returns (UserOpData memory userOpData) + { + return exec(instance, target, 0, callData); + } + + /*////////////////////////////////////////////////////////////// + HOOKS + //////////////////////////////////////////////////////////////*/ + + /// @notice A hook used to initiate state diff recording before installing a module + function preEnvHook() internal { + if (envOr("COMPLIANCE", false) || getStorageCompliance()) { + // Start state diff recording + vmStartStateDiffRecording(); + } + } + + /// @notice A hook used to stop state diff recording and verify that storage was cleared after + /// uninstalling a module + function postEnvHook(AccountInstance memory instance, bytes memory data) internal { + if (envOr("COMPLIANCE", false) || getStorageCompliance()) { + address module = abi.decode(data, (address)); + // Stop state diff recording and return account accesses + VmSafe.AccountAccess[] memory accountAccesses = vmStopAndReturnStateDiff(); + // Check if storage was cleared + verifyModuleStorageWasCleared(instance, accountAccesses, module); + } + } + + /*////////////////////////////////////////////////////////////////////////// + MODULE CONFIG + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Installs a module on an account by generating a userOp and sending it to the + /// entrypoint + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param moduleTypeId The type of the module to install + /// @param module The address of the module to install + /// @param data Arbitrary data that may be required on the module during `onInstall` + /// initialization + /// @return userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint + function installModule( + AccountInstance memory instance, + uint256 moduleTypeId, + address module, + bytes memory data + ) + internal + returns (UserOpData memory userOpData) + { + // Run preEnvHook + preEnvHook(); + userOpData = instance.getInstallModuleOps( + moduleTypeId, module, data, address(instance.defaultValidator) + ); + // sign userOp with default signature + userOpData = userOpData.signDefault(); + userOpData.entrypoint = instance.aux.entrypoint; + // send userOp to entrypoint + userOpData.execUserOps(); + } + + /// @notice Uninstalls a module on an account by generating a userOp and sending it to the + /// entrypoint + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param moduleTypeId The type of the module to uninstall + /// @param module The address of the module to uninstall + /// @param data Arbitrary data that may be required on the module during `onUninstall` + /// de-initialization + /// @return userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint + function uninstallModule( + AccountInstance memory instance, + uint256 moduleTypeId, + address module, + bytes memory data + ) + internal + returns (UserOpData memory userOpData) + { + userOpData = instance.getUninstallModuleOps( + moduleTypeId, module, data, address(instance.defaultValidator) + ); + // sign userOp with default signature + userOpData = userOpData.signDefault(); + userOpData.entrypoint = instance.aux.entrypoint; + + // send userOp to entrypoint + userOpData.execUserOps(); + // Run postEnvHook + postEnvHook(instance, abi.encode(module)); + } + + /// @notice Checks if a module is installed on an account + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param moduleTypeId The type of the module to check + /// @param module The address of the module to check + /// @return bool True if the module is installed, false otherwise + function isModuleInstalled( + AccountInstance memory instance, + uint256 moduleTypeId, + address module + ) + internal + returns (bool) + { + return instance.account.code.length > 0 + && HelperBase(instance.accountHelper).isModuleInstalled(instance, moduleTypeId, module); + } + + /// @notice Checks if a module is installed on an account by using additional data + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param moduleTypeId The type of the module to check + /// @param module The address of the module to check + /// @param data Arbitrary data that may be required + function isModuleInstalled( + AccountInstance memory instance, + uint256 moduleTypeId, + address module, + bytes memory data + ) + internal + returns (bool) + { + return HelperBase(instance.accountHelper).isModuleInstalled( + instance, moduleTypeId, module, data + ); + } + + /// @notice Gets the data required to install a module + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param moduleTypeId The type of the module to install + /// @param module The address of the module to install + /// @param data Arbitrary data that may be required on the module during `onInstall` + /// initialization + /// @return bytes The data required to install the module + function getInstallModuleData( + AccountInstance memory instance, + uint256 moduleTypeId, + address module, + bytes memory data + ) + internal + view + returns (bytes memory) + { + return HelperBase(instance.accountHelper).getInstallModuleData( + instance, moduleTypeId, module, data + ); + } + + /// @notice Gets the data required to uninstall a module + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param moduleTypeId The type of the module to uninstall + /// @param module The address of the module to uninstall + /// @param data Arbitrary data that may be required on the module during `onUninstall` + /// de-initialization + /// @return bytes The data required to uninstall the module + function getUninstallModuleData( + AccountInstance memory instance, + uint256 moduleTypeId, + address module, + bytes memory data + ) + internal + view + returns (bytes memory) + { + return HelperBase(instance.accountHelper).getUninstallModuleData( + instance, moduleTypeId, module, data + ); + } + + /// @notice Generates a userOp to install a module on an account + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param module The address of the module to install + /// @param initData Arbitrary data that may be required on the module during `onInstall` + /// initialization + /// @param txValidator The address of the transaction validator + /// @return userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint + function getInstallModuleOps( + AccountInstance memory instance, + uint256 moduleType, + address module, + bytes memory initData, + address txValidator + ) + internal + returns (UserOpData memory userOpData) + { + // get userOp with correct nonce for selected txValidator + (userOpData.userOp, userOpData.userOpHash) = HelperBase(instance.accountHelper) + .configModuleUserOp(instance, moduleType, module, initData, true, txValidator); + userOpData.entrypoint = instance.aux.entrypoint; + } + + /// @notice Generates a userOp to uninstall a module on an account + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param module The address of the module to uninstall + /// @param initData Arbitrary data that may be required on the module during `onUninstall` + /// de-initialization + /// @param txValidator The address of the transaction validator + /// @return userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint + function getUninstallModuleOps( + AccountInstance memory instance, + uint256 moduleType, + address module, + bytes memory initData, + address txValidator + ) + internal + returns (UserOpData memory userOpData) + { + // get userOp with correct nonce for selected txValidator + (userOpData.userOp, userOpData.userOpHash) = HelperBase(instance.accountHelper) + .configModuleUserOp(instance, moduleType, module, initData, false, txValidator); + userOpData.entrypoint = instance.aux.entrypoint; + } + + /// @notice Gets all installed modules on an account + /// @param instance AccountInstance struct containing the account and accountHelper + /// @return InstalledModule[] An array of InstalledModule structs containing the module type and + /// address + function getInstalledModules(AccountInstance memory instance) + internal + view + returns (InstalledModule[] memory) + { + return getInstalledModulesFromStorage(instance.account); + } + + /// @notice Writes an installed module struct data to storage + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param module InstalledModule struct containing the module type and address + function writeInstalledModule( + AccountInstance memory instance, + InstalledModule memory module + ) + internal + { + writeInstalledModuleToStorage(module, instance.account); + } + + /// @notice Removes an installed module from storage + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param moduleType The type of the module to remove + /// @param moduleAddress The address of the module to remove + function removeInstalledModule( + AccountInstance memory instance, + uint256 moduleType, + address moduleAddress + ) + internal + { + // Get installed modules for account + InstalledModule[] memory installedModules = getInstalledModules(instance); + // Find module to remove (not super scalable at high module counts) + for (uint256 i; i < installedModules.length; i++) { + if ( + installedModules[i].moduleType == moduleType + && installedModules[i].moduleAddress == moduleAddress + ) { + // Remove module from storage + removeInstalledModuleFromStorage(i, instance.account); + return; + } + } + } + + /// @notice Starts recording the state diff + function startStateDiffRecording(AccountInstance memory) internal { + vmStartStateDiffRecording(); + } + + /// @notice Stop recording the state diff and return the account accesses + /// @return VmSafe.AccountAccess[] An array of AccountAccess structs containing the account + function stopAndReturnStateDiff(AccountInstance memory) + internal + returns (VmSafe.AccountAccess[] memory) + { + return vmStopAndReturnStateDiff(); + } + + /// @notice Verifies from an accountAccesses array that storage was correctly cleared after + /// uninstalling a module, reverts if storage was not cleared correctly + /// @param accountAccesses An array of AccountAccess structs containing the account + /// @param module The address of the module to check + function verifyModuleStorageWasCleared( + AccountInstance memory, + VmSafe.AccountAccess[] memory accountAccesses, + address module + ) + internal + view + { + bytes32[] memory seenSlots = new bytes32[](1000); + bytes32[] memory finalValues = new bytes32[](1000); + uint256 numSlots; + + // Loop through account accesses + for (uint256 i; i < accountAccesses.length; i++) { + // Skip tests + if (accountAccesses[i].accessor == address(this)) { + continue; + } + + // If we are accessing the storage of the module check writes and clears + if (accountAccesses[i].account == module) { + // Process all storage accesses for this module + for (uint256 j; j < accountAccesses[i].storageAccesses.length; j++) { + VmSafe.StorageAccess memory access = accountAccesses[i].storageAccesses[j]; + + // Skip reads + if (!access.isWrite) { + continue; + } + + // Find if we've seen this slot + bool found; + for (uint256 k; k < numSlots; k++) { + if (seenSlots[k] == access.slot) { + finalValues[k] = access.newValue; + found = true; + break; + } + } + + // If not seen, add it + if (!found) { + seenSlots[numSlots] = access.slot; + finalValues[numSlots] = access.newValue; + numSlots++; + } + } + } + } + + // Check if any slot's final value is non-zero + for (uint256 i; i < numSlots; i++) { + if (finalValues[i] != bytes32(0)) { + revert("Storage not cleared after uninstalling module"); + } + } + } + + /*////////////////////////////////////////////////////////////////////////// + CONTROL FLOW + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Sets the expect revert flag to true + function expect4337Revert(AccountInstance memory) internal { + writeExpectRevert(""); + } + + /// @notice Sets the expect revert flag to true for a given selector + /// @param selector The selector of the function that is expected to revert + function expect4337Revert(AccountInstance memory, bytes4 selector) internal { + writeExpectRevert(abi.encodePacked(selector)); + } + + /// @notice Sets the expect revert flag to true for a given message + /// @param message The message that is expected to revert + function expect4337Revert(AccountInstance memory, bytes memory message) internal { + writeExpectRevert(message); + } + + /// @notice Logs the gas used by an ERC-4337 transaction + /// @dev needs to be called before an exec4337 call + /// @dev the id needs to be unique across your tests, otherwise the gas calculations will + /// overwrite each other + /// @param id Identifier for the gas calculation, which will be used as the filename + function log4337Gas(AccountInstance memory, /* instance */ string memory id) internal { + writeGasIdentifier(id); + } + + /// @notice Writes the simulate user op flag to storage + /// @param value The value to write to storage (true or false) + function simulateUserOp(AccountInstance memory, bool value) internal { + writeSimulateUserOp(value); + string memory strValue = value ? "true" : "false"; + setEnv("SIMULATE", strValue); + } + + /// @notice Writes the storage compliance flag to storage + /// @param value The value to write to storage (true or false) + function storageCompliance(AccountInstance memory, bool value) internal { + writeStorageCompliance(value); + } + + /*////////////////////////////////////////////////////////////////////////// + ACCOUNT UTILS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Converts an AccountType enum to a string + /// @param _accountType The AccountType enum to convert + /// @return accountType The string representation of the AccountType + function toString(AccountType _accountType) internal pure returns (string memory accountType) { + if (_accountType == AccountType.DEFAULT) { + return DEFAULT; + } else if (_accountType == AccountType.SAFE) { + return SAFE; + } else if (_accountType == AccountType.KERNEL) { + return KERNEL; + } else if (_accountType == AccountType.CUSTOM) { + return CUSTOM; + } else if (_accountType == AccountType.NEXUS) { + return NEXUS; + } else { + revert InvalidAccountType(); + } + } + + /// @notice Converts a string to an AccountType enum + /// @param _accountType The string to convert + /// @return accountType The AccountType enum + function toAccountType(string memory _accountType) + internal + pure + returns (AccountType accountType) + { + if (keccak256(abi.encodePacked(_accountType)) == keccak256(abi.encodePacked(DEFAULT))) { + return AccountType.DEFAULT; + } else if (keccak256(abi.encodePacked(_accountType)) == keccak256(abi.encodePacked(SAFE))) { + return AccountType.SAFE; + } else if (keccak256(abi.encodePacked(_accountType)) == keccak256(abi.encodePacked(KERNEL))) + { + return AccountType.KERNEL; + } else if (keccak256(abi.encodePacked(_accountType)) == keccak256(abi.encodePacked(CUSTOM))) + { + return AccountType.CUSTOM; + } else if (keccak256(abi.encodePacked(_accountType)) == keccak256(abi.encodePacked(NEXUS))) + { + return AccountType.NEXUS; + } else { + revert InvalidAccountType(); + } + } + + /// @notice Deploys an account, writes installed modules to storage from recorded logs + /// @param instance AccountInstance struct containing the account and accountHelper + function deployAccount(AccountInstance memory instance) internal { + // Record logs to track installed modules + recordLogs(); + // Deploy account + HelperBase(instance.accountHelper).deployAccount(instance); + // Parse logs and determine if a module was installed + VmSafe.Log[] memory logs = getRecordedLogs(); + for (uint256 i; i < logs.length; i++) { + // ModuleInstalled(uint256, address) + if ( + logs[i].topics[0] + == 0xd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123 + ) { + (uint256 moduleType, address module) = abi.decode(logs[i].data, (uint256, address)); + writeInstalledModuleToStorage(InstalledModule(moduleType, module), logs[i].emitter); + } + } + } + + /// @notice Sets the account type in storage + /// @param env The AccountType enum to set + function setAccountType(AccountInstance memory, AccountType env) internal { + setAccountType(env); + } + + /// @notice Sets the account type in storage + /// @param env The AccountType enum to set + function setAccountType(AccountType env) internal { + writeAccountType(env.toString()); + } + + /// @notice Sets the account type in storage from a string + /// @param env The string to set + function setAccountEnv(AccountInstance memory, string memory env) internal { + setAccountEnv(env); + } + + /// @notice Sets the account type in storage from a string + /// @param env The string to set + function setAccountEnv(string memory env) internal { + _setAccountEnv(env); + } + + /// @notice Sets the account type in storage from an enum + /// @param env The AccountType enum to set + function setAccountEnv(AccountType env) internal { + _setAccountEnv(env.toString()); + } + + /// @notice Gets the account type from storage + /// @return accountType The account type + function getAccountType() internal view returns (AccountType accountType) { + bytes32 accountTypeHash = getAccountTypeFromStorage(); + if (accountTypeHash == keccak256(abi.encodePacked(DEFAULT))) { + return AccountType.DEFAULT; + } else if (accountTypeHash == keccak256(abi.encodePacked(SAFE))) { + return AccountType.SAFE; + } else if (accountTypeHash == keccak256(abi.encodePacked(KERNEL))) { + return AccountType.KERNEL; + } else if (accountTypeHash == keccak256(abi.encodePacked(CUSTOM))) { + return AccountType.CUSTOM; + } else if (accountTypeHash == keccak256(abi.encodePacked(NEXUS))) { + return AccountType.NEXUS; + } else { + revert InvalidAccountType(); + } + } + + /// @notice Gets the account type from storage for an AccountInstance + function getAccountType(AccountInstance memory) + internal + view + returns (AccountType accountType) + { + return getAccountType(); + } + + /// @notice Sets the account type in storage from a string + function _setAccountEnv(string memory env) private { + address factory = getFactory(env); + address helper = getHelperFromStorage(env); + if (keccak256(abi.encodePacked(env)) == keccak256(abi.encodePacked(DEFAULT))) { + writeAccountEnv(env, factory, helper); + } else if (keccak256(abi.encodePacked(env)) == keccak256(abi.encodePacked(SAFE))) { + writeAccountEnv(env, factory, helper); + } else if (keccak256(abi.encodePacked(env)) == keccak256(abi.encodePacked(KERNEL))) { + writeAccountEnv(env, factory, helper); + } else if (keccak256(abi.encodePacked(env)) == keccak256(abi.encodePacked(CUSTOM))) { + writeAccountEnv(env, factory, helper); + } else if (keccak256(abi.encodePacked(env)) == keccak256(abi.encodePacked(NEXUS))) { + writeAccountEnv(env, factory, helper); + } else { + revert InvalidAccountType(); + } + } + + /// @notice Gets the account environment from storage + function getAccountEnv() internal view returns (AccountType env, address, address) { + (bytes32 envHash, address factory, address helper) = getAccountEnvFromStorage(); + if (envHash == keccak256(abi.encodePacked(DEFAULT))) { + return (AccountType.DEFAULT, factory, helper); + } else if (envHash == keccak256(abi.encodePacked(SAFE))) { + return (AccountType.SAFE, factory, helper); + } else if (envHash == keccak256(abi.encodePacked(KERNEL))) { + return (AccountType.KERNEL, factory, helper); + } else if (envHash == keccak256(abi.encodePacked(CUSTOM))) { + return (AccountType.CUSTOM, factory, helper); + } else if (envHash == keccak256(abi.encodePacked(NEXUS))) { + return (AccountType.NEXUS, factory, helper); + } else { + revert InvalidAccountType(); + } + } + + /// @notice Gets the account environment from storage for an AccountInstance + function getAccountEnv(AccountInstance memory) + internal + view + returns (AccountType env, address, address) + { + return getAccountEnv(); + } + + /// @notice Gets the helper from storage for an AccountType + /// @param env The AccountType enum to get the helper for + /// @return address The address of the helper + function getHelper(AccountType env) internal view returns (address) { + if (env == AccountType.DEFAULT) { + return getHelperFromStorage(DEFAULT); + } else if (env == AccountType.SAFE) { + return getHelperFromStorage(SAFE); + } else if (env == AccountType.KERNEL) { + return getHelperFromStorage(KERNEL); + } else if (env == AccountType.CUSTOM) { + return getHelperFromStorage(CUSTOM); + } else if (env == AccountType.NEXUS) { + return getHelperFromStorage(NEXUS); + } else { + revert InvalidAccountType(); + } + } + + /// @dev Used to deploy an account if it has not been deployed + modifier withAccountDeployed(AccountInstance memory instance) { + if (instance.account.code.length == 0) { + deployAccount(instance); + } + _; + } + + /*////////////////////////////////////////////////////////////////////////// + SIGNATURE UTILS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Checks if a signature is valid by calling the accountHelper of the account instance + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param validator The address of the validator + /// @param hash The hash to validate + /// @param signature The signature to validate + /// @return bool True if the signature is valid, false otherwise + function isValidSignature( + AccountInstance memory instance, + address validator, + bytes32 hash, + bytes memory signature + ) + internal + returns (bool) + { + return HelperBase(instance.accountHelper).isValidSignature( + instance, validator, hash, signature + ); + } + + /// @notice Formats a hash for ERC-1271 validation by calling the accountHelper of the account + /// instance + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param validator The address of the validator + /// @param hash The hash to format + /// @return bytes32 The formatted hash + function formatERC1271Hash( + AccountInstance memory instance, + address validator, + bytes32 hash + ) + internal + returns (bytes32) + { + return HelperBase(instance.accountHelper).formatERC1271Hash(instance, validator, hash); + } + + /// @notice Formats a signature for ERC-1271 validation by calling the accountHelper of the + /// account instance + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param validator The address of the validator + /// @param signature The signature to format + /// @return bytes The formatted signature + function formatERC1271Signature( + AccountInstance memory instance, + address validator, + bytes memory signature + ) + internal + returns (bytes memory) + { + return HelperBase(instance.accountHelper).formatERC1271Signature( + instance, validator, signature + ); + } + + /// @notice Adds a default signature to a UserOpData struct + /// @param userOpData UserOpData struct with the default signature added + function signDefault(UserOpData memory userOpData) internal pure returns (UserOpData memory) { + userOpData.userOp.signature = "DEFAULT SIGNATURE"; + return userOpData; + } + + /// @notice Signs a hash with a default signature + /// @param hash The hash to sign + /// @return bytes The signature + function ecdsaSignDefault(bytes32 hash) internal pure returns (bytes memory) { + (uint8 v, bytes32 r, bytes32 s) = (27, hash, hash); + return abi.encodePacked(r, s, v); + } + + /*////////////////////////////////////////////////////////////// + SMART SESSIONS + //////////////////////////////////////////////////////////////*/ + + /// @dev Makes sure the smart sessions module is installed + modifier withSmartSessionsInstalled(AccountInstance memory instance) { + if (!instance.isModuleInstalled(1, address(instance.smartSession))) { + revert SmartSessionNotInstalled(); + } + _; + } + + /// @notice Adds a session to the account with the default validator + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param session The session to add + function addSession( + AccountInstance memory instance, + Session memory session + ) + internal + withAccountDeployed(instance) + returns (PermissionId permissionIds) + { + // Check if smart sessions module is already installed + if (!instance.isModuleInstalled(1, address(instance.smartSession))) { + // Install smart sessions module + instance.installModule(1, address(instance.smartSession), ""); + } + // Enable session + Session[] memory sessions = new Session[](1); + sessions[0] = session; + prank(instance.account); + permissionIds = instance.smartSession.enableSessions(sessions)[0]; + } + + /// @notice Adds a session to the account with the default validator + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param salt The salt to use for the session + /// @param userOpPolicies The user operation policies to use for the session + /// @param erc7739Policy The ERC-7739 policy to use for the session + /// @param actionDatas The action datas to use for the session + /// @return permissionIds The permission id of the Session + function addSession( + AccountInstance memory instance, + bytes32 salt, + PolicyData[] memory userOpPolicies, + ERC7739Data memory erc7739Policy, + ActionData[] memory actionDatas + ) + internal + withAccountDeployed(instance) + returns (PermissionId permissionIds) + { + // Check if smart sessions module is already installed + if (!instance.isModuleInstalled(1, address(instance.smartSession))) { + // Install smart sessions module + instance.installModule(1, address(instance.smartSession), ""); + } + // Setup session data + Session memory session = Session( + ISessionValidator(address(instance.defaultSessionValidator)), + "mockInitData", + salt, + userOpPolicies, + erc7739Policy, + actionDatas + ); + // Enable session + return instance.addSession(session); + } + + /// @notice Removes a session from the account + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param permissionId The permission id of the session to remove + function removeSession( + AccountInstance memory instance, + PermissionId permissionId + ) + internal + withAccountDeployed(instance) + withSmartSessionsInstalled(instance) + { + // Remove session + prank(instance.account); + instance.smartSession.removeSession(permissionId); + } + + /// @notice Checks if a permission is enabled + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param permissionId The permission id to check + /// @return bool True if the permission is enabled, false otherwise + function isPermissionEnabled( + AccountInstance memory instance, + PermissionId permissionId + ) + internal + withAccountDeployed(instance) + withSmartSessionsInstalled(instance) + returns (bool) + { + // Check if session is enabled + return instance.smartSession.isPermissionEnabled(permissionId, instance.account); + } + + /// @notice Gets the permission id of a session + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param session The session to get the permission id of + /// @return permissionId The permission id of the session + function getPermissionId( + AccountInstance memory instance, + Session memory session + ) + internal + withSmartSessionsInstalled(instance) + returns (PermissionId permissionId) + { + // Check if smart sessions module is installed + if (!instance.isModuleInstalled(1, address(instance.smartSession))) { + revert SmartSessionNotInstalled(); + } + return instance.smartSession.getPermissionId(session); + } + + /// @notice Gets the session digest + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param session The session to get the digest of + /// @param mode The SmartSessionMode to use + /// @return bytes32 The session digest + function getSessionDigest( + AccountInstance memory instance, + Session memory session, + SmartSessionMode mode + ) + internal + withSmartSessionsInstalled(instance) + returns (bytes32) + { + return instance.smartSession.getSessionDigest( + getPermissionId(instance, session), instance.account, session, mode + ); + } + + /// @notice Gets the session nonce + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param permissionId The permission id of the session to get the nonce of + /// @return uint256 The session nonce + function getSessionNonce( + AccountInstance memory instance, + PermissionId permissionId + ) + internal + withSmartSessionsInstalled(instance) + returns (uint256) + { + return instance.smartSession.getNonce(permissionId, instance.account); + } + + /// @notice Encodes a signature for a user operation using the correct format + /// @param instance AccountInstance struct + /// @param userOperation The user operation to encode the signature for + /// @param mode The SmartSessionMode to use + /// @param session The session to use + /// @return bytes The encoded signature + function encodeSignature( + AccountInstance memory instance, + PackedUserOperation memory userOperation, + SmartSessionMode mode, + Session memory session + ) + internal + returns (bytes memory) + { + // Get permission id + PermissionId permissionId = getPermissionId(instance, session); + // Encode based on mode + if (mode == SmartSessionMode.USE) { + return EncodeLib.encodeUse(permissionId, userOperation.signature); + } else { + revert("Missing signFunction and validator params"); + } + } + + /// @notice Encodes the signature for a user operation using the correct format and passed + /// signing function and validator + /// @param instance AccountInstance struct + /// @param userOperation The user operation to encode the signature for + /// @param mode The SmartSessionMode to use + /// @param session The session to use + /// @param signFunction The signing function to use + /// @param validator The validator to use + /// @return bytes The encoded signature + function encodeSignature( + AccountInstance memory instance, + PackedUserOperation memory userOperation, + SmartSessionMode mode, + Session memory session, + function (bytes32) internal returns (bytes memory) signFunction, + address validator + ) + internal + returns (bytes memory) + { + // Get permission id + PermissionId permissionId = getPermissionId(instance, session); + // Encode based on mode + if (mode == SmartSessionMode.USE) { + return EncodeLib.encodeUse(permissionId, userOperation.signature); + } else { + // Create enable session data + EnableSession memory enableData = makeMultiChainEnableData(instance, session, mode); + // Get the hash + bytes32 hash = HashLib.multichainDigest(enableData.hashesAndChainIds); + // Sign the enable hash + enableData.permissionEnableSig = abi.encodePacked(validator, signFunction(hash)); + // Encode based on mode + if (mode == SmartSessionMode.UNSAFE_ENABLE) { + return EncodeLib.encodeUnsafeEnable(userOperation.signature, enableData); + } else { + return EncodeLib.encodeEnable(userOperation.signature, enableData); + } + } + } + + /// @notice Encodes the signature for a user operation using the USE mode + /// @param instance AccountInstance struct + /// @param userOperation The user operation to encode the signature for + /// @param session The session to use + /// @return bytes The encoded signature + function encodeSignatureUseMode( + AccountInstance memory instance, + PackedUserOperation memory userOperation, + Session memory session + ) + internal + returns (bytes memory) + { + return instance.encodeSignature( + userOperation, + SmartSessionMode.USE, + session, + ecdsaSignDefault, // Irrelevant in use mode + address(0) // Irrelevant in use mode + ); + } + + /// @notice Encodes the signature for a user operation using the ENABLE mode + /// @param instance AccountInstance struct + /// @param userOperation The user operation to encode the signature for + /// @param session The session to use + /// @param signFunction The signing function to use + /// @param validator The validator to use + /// @return bytes The encoded signature + function encodeSignatureEnableMode( + AccountInstance memory instance, + PackedUserOperation memory userOperation, + Session memory session, + function (bytes32) internal returns (bytes memory) signFunction, + address validator + ) + internal + returns (bytes memory) + { + return instance.encodeSignature( + userOperation, SmartSessionMode.ENABLE, session, signFunction, validator + ); + } + + /// @notice Encodes the signature for a user operation using the UNSAFE_ENABLE mode + /// @param instance AccountInstance struct + /// @param userOperation The user operation to encode the signature for + /// @param session The session to use + /// @param signFunction The signing function to use + /// @param validator The validator to use + /// @return bytes The encoded signature + function encodeSignatureUnsafeEnableMode( + AccountInstance memory instance, + PackedUserOperation memory userOperation, + Session memory session, + function (bytes32) internal returns (bytes memory) signFunction, + address validator + ) + internal + returns (bytes memory) + { + return instance.encodeSignature( + userOperation, SmartSessionMode.UNSAFE_ENABLE, session, signFunction, validator + ); + } + + /// @notice Checks if a session is enabled + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param session The session to check + /// @return bool True if the session is enabled, false otherwise + function isSessionEnabled( + AccountInstance memory instance, + Session memory session + ) + internal + withSmartSessionsInstalled(instance) + returns (bool) + { + // Get permission id + PermissionId permissionId = getPermissionId(instance, session); + return instance.smartSession.isISessionValidatorSet(permissionId, instance.account) + && instance.smartSession.areUserOpPoliciesEnabled( + instance.account, permissionId, session.userOpPolicies + ) + && instance.smartSession.areActionsEnabled(instance.account, permissionId, session.actions) + && instance.smartSession.areERC1271PoliciesEnabled( + instance.account, permissionId, session.erc7739Policies.erc1271Policies + ); + } + + /// @dev Kernel requires us to temporarily disable the hook multiplexer to use smart sessions + modifier withHookFixForKernel(AccountInstance memory instance) { + // Check if account is KERNEL + if (instance.accountType == AccountType.KERNEL) { + // Cache hook multiplexer + address hookMultiplexer = + KernelHelpers(instance.accountHelper).getHookMultiPlexer(instance); + // Uninstall MockHookMultiplexer + instance.uninstallModule(MODULE_TYPE_HOOK, hookMultiplexer, ""); + // Set hook multiplexer to address(1) + KernelHelpers(instance.accountHelper).setHookMultiPlexer(instance, address(1)); + _; + // Set hook multiplexer back to MockHookMultiplexer + KernelHelpers(instance.accountHelper).setHookMultiPlexer(instance, hookMultiplexer); + // Reinstall MockHookMultiplexer + instance.installModule(MODULE_TYPE_HOOK, hookMultiplexer, ""); + } else { + _; + } + } + + /// @notice Uses a session to execute a user operation + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param session The session to use + /// @param target The target address of the user operation + /// @param value The value of the user operation + /// @param callData The call data of the user operation + function useSession( + AccountInstance memory instance, + Session memory session, + address target, + uint256 value, + bytes memory callData + ) + internal + withHookFixForKernel(instance) + { + // Check if smart sessions module is already installed + if (!instance.isModuleInstalled(1, address(instance.smartSession))) { + // Install smart sessions module + instance.installModule(1, address(instance.smartSession), ""); + } + + // Get user ops + UserOpData memory userOpData = + instance.getExecOps(target, value, callData, address(instance.smartSession)); + + // Get permission id + PermissionId permissionId = getPermissionId(instance, session); + + // Check if session is enabled and enable if not + if (!isSessionEnabled(instance, session)) { + prank(instance.account); + Session[] memory sessions = new Session[](1); + sessions[0] = session; + instance.smartSession.enableSessions(sessions); + } + + // Sign user op + userOpData.userOp.signature = EncodeLib.encodeUse(permissionId, userOpData.userOp.signature); + + // Execute user op + userOpData.execUserOps(); + } + + /// @notice Uses a session to execute a batch of user operations + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param session The session to use + /// @param executions The executions to execute + function useSession( + AccountInstance memory instance, + Session memory session, + Execution[] memory executions + ) + internal + withHookFixForKernel(instance) + { + // Check if smart sessions module is already installed + if (!instance.isModuleInstalled(1, address(instance.smartSession))) { + // Install smart sessions module + instance.installModule(1, address(instance.smartSession), ""); + } + + // Get user ops for multiple executions + UserOpData memory userOpData = + instance.getExecOps(executions, address(instance.smartSession)); + + // Get permission id + PermissionId permissionId = getPermissionId(instance, session); + + // Check if session is enabled and enable if not + if (!isSessionEnabled(instance, session)) { + prank(instance.account); + Session[] memory sessions = new Session[](1); + sessions[0] = session; + instance.smartSession.enableSessions(sessions); + } + + // Sign user op + userOpData.userOp.signature = EncodeLib.encodeUse(permissionId, userOpData.userOp.signature); + + // Execute user op + userOpData.execUserOps(); + } + + /// @notice Creates multi-chain enable data for a session + /// @param instance AccountInstance struct containing the account and accountHelper + /// @param session The session to enable + /// @param mode The SmartSessionMode to use + /// @return enableData The enable session data + function makeMultiChainEnableData( + AccountInstance memory instance, + Session memory session, + SmartSessionMode mode + ) + internal + returns (EnableSession memory enableData) + { + PermissionId permissionId = instance.getPermissionId(session); + bytes32 sessionDigest = instance.smartSession.getSessionDigest({ + permissionId: permissionId, + account: instance.account, + data: session, + mode: mode + }); + + ChainDigest[] memory chainDigests = ModuleKitHelpers.encodeHashesAndChainIds( + Solarray.uint64s(181_818, uint64(block.chainid), 777), + Solarray.bytes32s(sessionDigest, sessionDigest, sessionDigest) + ); + + enableData = EnableSession({ + chainDigestIndex: 1, + hashesAndChainIds: chainDigests, + sessionToEnable: session, + permissionEnableSig: "" + }); + } + + /// @dev Encodes hashes and chain ids to a ChainDigest array + /// @param chainIds The chain ids to encode + /// @param hashes The hashes to encode + /// @return ChainDigest[] The encoded ChainDigest array + function encodeHashesAndChainIds( + uint64[] memory chainIds, + bytes32[] memory hashes + ) + internal + pure + returns (ChainDigest[] memory) + { + uint256 length = chainIds.length; + ChainDigest[] memory hashesAndChainIds = new ChainDigest[](length); + for (uint256 i; i < length; i++) { + hashesAndChainIds[i] = ChainDigest({ chainId: chainIds[i], sessionDigest: hashes[i] }); + } + return hashesAndChainIds; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/RhinestoneModuleKit.sol b/typescript/packages/account-modules/lib/modulekit/src/test/RhinestoneModuleKit.sol new file mode 100644 index 0000000..069e9e5 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/RhinestoneModuleKit.sol @@ -0,0 +1,471 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Factories +import { SafeFactory } from "../accounts/safe/SafeFactory.sol"; +import { ERC7579Factory } from "../accounts/erc7579/ERC7579Factory.sol"; +import { KernelFactory } from "../accounts/kernel/KernelFactory.sol"; +import { NexusFactory } from "../accounts/nexus/NexusFactory.sol"; + +// Auxiliaries +import { Auxiliary, AuxiliaryFactory } from "./Auxiliary.sol"; + +// Helpers +import { HelperBase } from "./helpers/HelperBase.sol"; +import { ERC7579Helpers } from "./helpers/ERC7579Helpers.sol"; +import { SafeHelpers } from "./helpers/SafeHelpers.sol"; +import { KernelHelpers } from "./helpers/KernelHelpers.sol"; +import { NexusHelpers } from "./helpers/NexusHelpers.sol"; +import { ModuleKitHelpers } from "./ModuleKitHelpers.sol"; + +// Interfaces +import { IAccountFactory } from "../accounts/factory/interface/IAccountFactory.sol"; +import { PackedUserOperation, IStakeManager, IEntryPoint } from "../external/ERC4337.sol"; +import { ISmartSession, ISessionValidator } from "../integrations/interfaces/ISmartSession.sol"; +import { IValidator as IERC7579Validator } from "../accounts/common/interfaces/IERC7579Module.sol"; + +// Deployment +import { ENTRYPOINT_ADDR } from "../deployment/predeploy/EntryPoint.sol"; +import { SMARTSESSION_ADDR } from "../deployment/precompiles/SmartSessionsPrecompiles.sol"; + +// Mocks +import { MockValidator, MockStatelessValidator } from "../Mocks.sol"; + +// Utils +import { envOr, prank, label, deal, toString } from "../test/utils/Vm.sol"; +import { VmSafe } from "./utils/Vm.sol"; +import { + getAccountEnv, + getHelper, + getFactory, + getAccountType, + writeAccountEnv, + writeFactory, + writeHelper +} from "./utils/Storage.sol"; + +/*////////////////////////////////////////////////////////////// + CONSTANTS +//////////////////////////////////////////////////////////////*/ + +string constant DEFAULT = "DEFAULT"; +string constant SAFE = "SAFE"; +string constant KERNEL = "KERNEL"; +string constant CUSTOM = "CUSTOM"; +string constant NEXUS = "NEXUS"; + +/*////////////////////////////////////////////////////////////// + ENUMS +//////////////////////////////////////////////////////////////*/ + +/// @notice Currently supported account types +enum AccountType { + DEFAULT, + SAFE, + KERNEL, + CUSTOM, + NEXUS +} + +/*////////////////////////////////////////////////////////////// + STRUCTS +//////////////////////////////////////////////////////////////*/ + +/// @title AccountInstance +/// @notice A struct that contains all the necessary information for an account used during testing +/// @param account The address of the account +/// @param accountType The type of the account +/// @param accountHelper The address of the account helper +/// @param aux Auxiliary contracts +/// @param defaultValidator The default validator address +/// @param salt The salt used to create the account +/// @param initCode The init code used to create the account +/// @param accountFactory The address of the account factory +/// @param smartSession The address of the smart session contract +/// @param defaultSessionValidator The default session validator address +struct AccountInstance { + address account; + AccountType accountType; + address accountHelper; + Auxiliary aux; + IERC7579Validator defaultValidator; + bytes32 salt; + bytes initCode; + address accountFactory; + ISmartSession smartSession; + ISessionValidator defaultSessionValidator; +} + +/// @title UserOpData +/// @param userOp The user operation +/// @param userOpHash The hash of the user operation +/// @param entrypoint The entrypoint contract +struct UserOpData { + PackedUserOperation userOp; + bytes32 userOpHash; + IEntryPoint entrypoint; +} + +/// @title ExecutionReturnData +/// @param logs Execution logs +struct ExecutionReturnData { + VmSafe.Log[] logs; +} + +/// @title RhinestoneModuleKit +/// @notice A development kit for building and testing smart account modules +contract RhinestoneModuleKit is AuxiliaryFactory { + /*////////////////////////////////////////////////////////////// + LIBRARIES + //////////////////////////////////////////////////////////////*/ + + using ModuleKitHelpers for *; + + /*////////////////////////////////////////////////////////////// + STORAGE + //////////////////////////////////////////////////////////////*/ + + /// @notice The default validator used for testing + MockValidator public _defaultValidator; + /// @notice The default stateless validator used for testing smart sessions + MockStatelessValidator public _defaultSessionValidator; + /// @notice Whether the module kit has been initialized on a specific chain + mapping(uint256 chainId => bool initialized) public isInit; + + /*////////////////////////////////////////////////////////////// + INIT + //////////////////////////////////////////////////////////////*/ + + /// @notice Initialize the module kit with the provided environment, deploy the factories, + /// helpers, and validators, and stake them on the entrypoint + function _initializeModuleKit(string memory _env) internal { + // Init + super.init(); + isInit[block.chainid] = true; + + // Factories + writeFactory(address(new ERC7579Factory()), DEFAULT); + writeFactory(address(new SafeFactory()), SAFE); + writeFactory(address(new KernelFactory()), KERNEL); + writeFactory(address(new NexusFactory()), NEXUS); + writeFactory(address(new ERC7579Factory()), CUSTOM); + + // Helpers + writeHelper(address(new ERC7579Helpers()), DEFAULT); + writeHelper(address(new SafeHelpers()), SAFE); + writeHelper(address(new KernelHelpers()), KERNEL); + writeHelper(address(new NexusHelpers()), NEXUS); + writeHelper(address(new ERC7579Helpers()), CUSTOM); + + // Initialize factories + IAccountFactory safeFactory = IAccountFactory(getFactory(SAFE)); + IAccountFactory kernelFactory = IAccountFactory(getFactory(KERNEL)); + IAccountFactory erc7579Factory = IAccountFactory(getFactory(DEFAULT)); + IAccountFactory nexusFactory = IAccountFactory(getFactory(NEXUS)); + IAccountFactory customFactory = IAccountFactory(getFactory(CUSTOM)); + safeFactory.init(); + kernelFactory.init(); + erc7579Factory.init(); + nexusFactory.init(); + customFactory.init(); + + // Label factories + label(address(safeFactory), "SafeFactory"); + label(address(kernelFactory), "KernelFactory"); + label(address(erc7579Factory), "ERC7579Factory"); + label(address(nexusFactory), "NexusFactory"); + label(address(customFactory), "CustomFactory"); + + // Stake factory on EntryPoint + deal(address(safeFactory), 10 ether); + deal(address(kernelFactory), 10 ether); + deal(address(erc7579Factory), 10 ether); + deal(address(nexusFactory), 10 ether); + deal(address(customFactory), 10 ether); + + // Stake on EntryPoint + prank(address(safeFactory)); + IStakeManager(ENTRYPOINT_ADDR).addStake{ value: 10 ether }(100_000); + prank(address(kernelFactory)); + IStakeManager(ENTRYPOINT_ADDR).addStake{ value: 10 ether }(100_000); + prank(address(erc7579Factory)); + IStakeManager(ENTRYPOINT_ADDR).addStake{ value: 10 ether }(100_000); + prank(address(nexusFactory)); + IStakeManager(ENTRYPOINT_ADDR).addStake{ value: 10 ether }(100_000); + + // Set env + ModuleKitHelpers.setAccountEnv(_env); + + // Set factory + IAccountFactory accountFactory = IAccountFactory(getFactory(_env)); + label(address(accountFactory), "AccountFactory"); + + // Set default validator + _defaultValidator = new MockValidator(); + label(address(_defaultValidator), "DefaultValidator"); + + // Set session validator + _defaultSessionValidator = new MockStatelessValidator(); + label(address(_defaultSessionValidator), "SessionValidator"); + } + + /*////////////////////////////////////////////////////////////// + ACCOUNT INSTANCE + //////////////////////////////////////////////////////////////*/ + + /// @notice Create an account instance with the provided salt + /// @param salt The salt used to create the account + /// @return instance The account instance + function makeAccountInstance(bytes32 salt) + internal + initializeModuleKit + returns (AccountInstance memory instance) + { + (AccountType env, address accountFactoryAddress, address accountHelper) = + ModuleKitHelpers.getAccountEnv(); + IAccountFactory accountFactory = IAccountFactory(accountFactoryAddress); + bytes memory initData = accountFactory.getInitData(address(_defaultValidator), ""); + address account = accountFactory.getAddress(salt, initData); + bytes memory initCode = abi.encodePacked( + address(accountFactory), abi.encodeCall(accountFactory.createAccount, (salt, initData)) + ); + + label(address(account), toString(salt)); + deal(account, 10 ether); + instance = _makeAccountInstance({ + salt: salt, + accountType: env, + helper: accountHelper, + account: account, + initCode: initCode, + validator: address(_defaultValidator), + accountFactory: address(accountFactory), + sessionValidator: address(_defaultSessionValidator) + }); + } + + // @notice Create an account instance with the provided salt, account, and init code + // @param salt The salt used to create the account + // @param account The address of the account + // @param initCode The init code used to create the account + function makeAccountInstance( + bytes32 salt, + address account, + bytes memory initCode + ) + internal + initializeModuleKit + returns (AccountInstance memory instance) + { + address accountHelper = ModuleKitHelpers.getHelper(ModuleKitHelpers.getAccountType()); + instance = makeAccountInstance({ + salt: salt, + helper: accountHelper, + account: account, + initCode: initCode + }); + } + + /// @notice Create an account instance with the provided salt, account,executors, validators, + /// hook, and fallback arrays + /// @param salt The salt used to create the account + /// @param validators The array of ModuleInitData for validators + /// @param executors The array of ModuleInitData for executors + /// @param hook The ModuleInitData for the hook + /// @param fallbacks The array of ModuleInitData for fallbacks + /// @return instance The account instance + function makeAccountInstance( + bytes32 salt, + IAccountFactory.ModuleInitData[] memory validators, + IAccountFactory.ModuleInitData[] memory executors, + IAccountFactory.ModuleInitData memory hook, + IAccountFactory.ModuleInitData[] memory fallbacks + ) + internal + initializeModuleKit + returns (AccountInstance memory instance) + { + (, address accountFactoryAddress, address accountHelper) = ModuleKitHelpers.getAccountEnv(); + IAccountFactory accountFactory = IAccountFactory(accountFactoryAddress); + bytes memory initData = accountFactory.getInitData(validators, executors, hook, fallbacks); + address account = accountFactory.getAddress(salt, initData); + bytes memory initCode = abi.encodePacked( + address(accountFactory), abi.encodeCall(accountFactory.createAccount, (salt, initData)) + ); + label(address(account), toString(salt)); + deal(account, 10 ether); + instance = makeAccountInstance({ + salt: salt, + helper: accountHelper, + account: account, + initCode: initCode, + defaultValidator: address(validators[0].module), + defaultSessionValidator: address(executors[0].module) + }); + } + + /// @notice Create an account instance with the provided salt, account, init code, and helper. + /// Funds the account with 10 ether. + /// @param salt The salt used to create the account + /// @param account The address of the account + /// @param initCode The init code used to create the account + /// @param helper The address of the account helper + /// @return instance The account instance + function makeAccountInstance( + bytes32 salt, + address account, + bytes memory initCode, + address helper + ) + internal + initializeModuleKit + returns (AccountInstance memory instance) + { + label(address(account), toString(salt)); + deal(account, 10 ether); + + address _factory; + assembly { + _factory := mload(add(initCode, 20)) + } + + AccountType env = ModuleKitHelpers.getAccountType(); + + instance = _makeAccountInstance({ + salt: salt, + accountType: env, + helper: helper, + account: account, + initCode: initCode, + validator: address(_defaultValidator), + accountFactory: _factory, + sessionValidator: address(_defaultSessionValidator) + }); + + ModuleKitHelpers.setAccountType(AccountType.CUSTOM); + } + + /// @notice Create an account instance with the provided salt, account, init code, helper, + /// default validator, + /// and default session validator. Funds the account with 10 ether. + /// @param salt The salt used to create the account + /// @param account The address of the account + /// @param initCode The init code used to create the account + /// @param helper The address of the account helper + /// @param defaultValidator The address of the default validator + /// @param defaultSessionValidator The address of the default session validator + /// @return instance The account instance + function makeAccountInstance( + bytes32 salt, + address account, + bytes memory initCode, + address helper, + address defaultValidator, + address defaultSessionValidator + ) + internal + initializeModuleKit + returns (AccountInstance memory instance) + { + label(address(account), toString(salt)); + deal(account, 10 ether); + + address _factory; + assembly { + _factory := mload(add(initCode, 20)) + } + + AccountType env = instance.getAccountType(); + + instance = _makeAccountInstance({ + salt: salt, + accountType: env, + helper: helper, + account: account, + initCode: initCode, + validator: defaultValidator, + accountFactory: _factory, + sessionValidator: defaultSessionValidator + }); + ModuleKitHelpers.setAccountType(AccountType.CUSTOM); + } + + /// @notice Create an account instance with the provided salt, account, init code, account + /// factory, validator, session validator, account type, and helper + /// @param salt The salt used to create the account + /// @param account The address of the account + /// @param initCode The init code used to create the account + /// @param accountFactory The address of the account factory + /// @param validator The address of the validator + /// @param sessionValidator The address of the session validator + /// @param accountType The type of the account + /// @param helper The address of the account helper + /// @return instance The account instance + function _makeAccountInstance( + bytes32 salt, + address account, + bytes memory initCode, + address accountFactory, + address validator, + address sessionValidator, + AccountType accountType, + address helper + ) + internal + view + returns (AccountInstance memory instance) + { + instance = AccountInstance({ + accountType: accountType, + accountHelper: helper, + account: account, + aux: auxiliary, + salt: salt, + defaultValidator: IERC7579Validator(validator), + initCode: initCode, + accountFactory: accountFactory, + smartSession: ISmartSession(SMARTSESSION_ADDR), + defaultSessionValidator: ISessionValidator(sessionValidator) + }); + } + + /*////////////////////////////////////////////////////////////// + MODIFIERS + //////////////////////////////////////////////////////////////*/ + + /// @dev Initialize the module kit with the provided environment if it has not been initialized + modifier initializeModuleKit() { + if (!isInit[block.chainid]) { + string memory _env = envOr("ACCOUNT_TYPE", DEFAULT); + _initializeModuleKit(_env); + } + _; + } + + /// @dev Set the account type for a function, and restore the previous account type + /// after the function call. Useful for testing different account types in the same test + /// @param env The account type to set + modifier usingAccountEnv(AccountType env) { + // If the module kit is not initialized, initialize it + if (!isInit[block.chainid]) { + _initializeModuleKit(env.toString()); + } else { + // Cache the current env to restore it after the function call + (AccountType _oldEnv, address _oldAccountFactory, address _oldAccountHelper) = + ModuleKitHelpers.getAccountEnv(); + // Set the new env + ModuleKitHelpers.setAccountEnv(env); + _; + // Restore the old env + ModuleKitHelpers.setAccountEnv(_oldEnv); + } + } + + /// @notice Verify that the storage of a module was cleared after a function call + modifier withModuleStorageClearValidation(AccountInstance memory instance, address module) { + instance.startStateDiffRecording(); + _; + VmSafe.AccountAccess[] memory accountAccess = instance.stopAndReturnStateDiff(); + instance.verifyModuleStorageWasCleared(accountAccess, module); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/ERC7579Helpers.sol b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/ERC7579Helpers.sol new file mode 100644 index 0000000..17ef9b1 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/ERC7579Helpers.sol @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { AccountInstance } from "../RhinestoneModuleKit.sol"; +import { CallType } from "../../accounts/common/lib/ModeLib.sol"; + +// Dependencies +import { HelperBase } from "./HelperBase.sol"; + +// Interfaces +import { IAccountModulesPaginated } from "./interfaces/IAccountModulesPaginated.sol"; +import { IERC1271, EIP1271_MAGIC_VALUE } from "../../Interfaces.sol"; + +/// @notice Helper functions for ERC7579 reference implementation based Accounts +contract ERC7579Helpers is HelperBase { + /*////////////////////////////////////////////////////////////////////////// + MODULE CONFIG + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice get callData to uninstall a validator on an ERC7579 Account + /// @param instance AccountInstance the account instance to uninstall the validator from + /// @param module address the address of the module to uninstall + /// @param initData bytes the data to pass to the module + function getUninstallValidatorData( + AccountInstance memory instance, + address module, + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory data) + { + // get previous validator in sentinel list + address previous; + + (address[] memory array,) = + IAccountModulesPaginated(instance.account).getValidatorsPaginated(address(0x1), 100); + + if (array.length == 1) { + previous = address(0x1); + } else if (array[0] == module) { + previous = address(0x1); + } else { + for (uint256 i = 1; i < array.length; i++) { + if (array[i] == module) previous = array[i - 1]; + } + } + data = abi.encode(previous, initData); + } + + /// @notice get callData to install a validator on an ERC7579 Account + /// @param instance AccountInstance the account instance to install the validator on + /// @param module address the address of the module to install + /// @param initData bytes the data to pass to the module + function getUninstallExecutorData( + AccountInstance memory instance, + address module, + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory data) + { + // get previous executor in sentinel list + address previous; + + (address[] memory array,) = + IAccountModulesPaginated(instance.account).getExecutorsPaginated(address(0x1), 100); + + if (array.length == 1) { + previous = address(0x1); + } else if (array[0] == module) { + previous = address(0x1); + } else { + for (uint256 i = 1; i < array.length; i++) { + if (array[i] == module) previous = array[i - 1]; + } + } + data = abi.encode(previous, initData); + } + + /// @notice get callData to install a fallback on an ERC7579 Account + /// @param initData bytes the data to pass to the module + function getInstallFallbackData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + pure + virtual + override + returns (bytes memory data) + { + (bytes4 selector, CallType callType, bytes memory _initData) = + abi.decode(initData, (bytes4, CallType, bytes)); + data = abi.encodePacked(selector, callType, _initData); + } + + /// @notice get callData to uninstall a fallback on an ERC7579 Account + /// @param initData bytes the data to pass to the module + function getUninstallFallbackData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + pure + virtual + override + returns (bytes memory data) + { + (bytes4 selector,, bytes memory _initData) = abi.decode(initData, (bytes4, CallType, bytes)); + data = abi.encodePacked(selector, _initData); + } + + /*////////////////////////////////////////////////////////////////////////// + SIGNATURE UTILS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Check if a signature is valid for an account, returns true if isValidSignature + /// returns EIP1271_MAGIC_VALUE + /// @param instance AccountInstance the account instance to check the signature on + /// @param validator address the address of the validator + /// @param hash bytes32 the hash to check the signature against + /// @param signature bytes the signature to check + function isValidSignature( + AccountInstance memory instance, + address validator, + bytes32 hash, + bytes memory signature + ) + public + virtual + override + deployAccountForAction(instance) + returns (bool isValid) + { + isValid = IERC1271(instance.account).isValidSignature( + hash, abi.encodePacked(validator, signature) + ) == EIP1271_MAGIC_VALUE; + } + + /// @notice Format a ERC1271 signature for an account + /// @param validator address the address of the validator + /// @param signature bytes the signature to format + function formatERC1271Signature( + AccountInstance memory, // instance + address validator, + bytes memory signature + ) + public + virtual + override + returns (bytes memory) + { + return abi.encodePacked(validator, signature); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/HelperBase.sol b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/HelperBase.sol new file mode 100644 index 0000000..6e7bcfd --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/HelperBase.sol @@ -0,0 +1,661 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Interfaces +import { IERC7579Account } from "../../accounts/common/interfaces/IERC7579Account.sol"; +import { + IModule as IERC7579Module, + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_HOOK, + MODULE_TYPE_FALLBACK, + MODULE_TYPE_PREVALIDATION_HOOK_ERC1271, + MODULE_TYPE_PREVALIDATION_HOOK_ERC4337 +} from "../../accounts/common/interfaces/IERC7579Module.sol"; +import { IERC1271, EIP1271_MAGIC_VALUE } from "../../Interfaces.sol"; + +// Libraries +import { + ModeLib, + ModeCode, + CALLTYPE_SINGLE, + CALLTYPE_BATCH, + MODE_DEFAULT, + EXECTYPE_DEFAULT, + CALLTYPE_BATCH, + ModePayload +} from "../../accounts/common/lib/ModeLib.sol"; + +// Types +import { PackedUserOperation } from "../../external/ERC4337.sol"; +import { AccountInstance } from "../RhinestoneModuleKit.sol"; +import { Execution } from "../../accounts/erc7579/lib/ExecutionLib.sol"; + +// Utils +import "../utils/Vm.sol"; + +/// @dev Base helper that includes common functions for different ERC7579 Account implementations +abstract contract HelperBase { + /*////////////////////////////////////////////////////////////////////////// + EXECUTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Gets userOp and userOpHash for an executing calldata on an account instance + /// @param instance AccountInstance the account instance to execute the userop for + /// @param callData bytes the calldata to execute + /// @param txValidator address the address of the validator + /// @return userOp PackedUserOperation the packed user operation + /// @return userOpHash bytes32 the hash of the user operation + function execUserOp( + AccountInstance memory instance, + bytes memory callData, + address txValidator + ) + public + virtual + returns (PackedUserOperation memory userOp, bytes32 userOpHash) + { + bytes memory initCode; + bool notDeployedYet = instance.account.code.length == 0; + if (notDeployedYet) { + initCode = instance.initCode; + } + + userOp = PackedUserOperation({ + sender: instance.account, + nonce: getNonce(instance, callData, txValidator), + initCode: initCode, + callData: callData, + accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), + preVerificationGas: 2e6, + gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), + paymasterAndData: bytes(""), + signature: bytes("") + }); + + userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); + } + + /*////////////////////////////////////////////////////////////////////////// + MODULE CONFIG + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Configures a userop for an account instance to install or uninstall a module + /// @param instance AccountInstance the account instance to configure the userop for + /// @param moduleType uint256 the type of the module + /// @param module address the address of the module + /// @param initData bytes the data to pass to the module + /// @param isInstall bool whether to install or uninstall the module + /// @param txValidator address the address of the validator + /// @return userOp PackedUserOperation the packed user operation + /// @return userOpHash bytes32 the hash of the user operation + function configModuleUserOp( + AccountInstance memory instance, + uint256 moduleType, + address module, + bytes memory initData, + bool isInstall, + address txValidator + ) + public + virtual + returns (PackedUserOperation memory userOp, bytes32 userOpHash) + { + bytes memory initCode; + if (instance.account.code.length == 0) { + initCode = instance.initCode; + } + bytes memory callData; + if (isInstall) { + initData = getInstallModuleData(instance, moduleType, module, initData); + callData = getInstallModuleCallData(instance, moduleType, module, initData); + } else { + initData = getUninstallModuleData(instance, moduleType, module, initData); + callData = getUninstallModuleCallData(instance, moduleType, module, initData); + } + + userOp = PackedUserOperation({ + sender: instance.account, + nonce: getNonce(instance, callData, txValidator), + initCode: initCode, + callData: callData, + accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), + preVerificationGas: 2e6, + gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), + paymasterAndData: bytes(""), + signature: bytes("") + }); + + userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); + } + + /// @notice get callData to install a module on an ERC7579 Account + /// @param moduleType uint256 the type of the module + /// @param module address the address of the module to install + /// @param initData bytes the data to pass to the module + /// @return callData bytes the callData to install the module + function getInstallModuleCallData( + AccountInstance memory, // instance + uint256 moduleType, + address module, + bytes memory initData + ) + public + view + virtual + returns (bytes memory callData) + { + callData = abi.encodeCall(IERC7579Account.installModule, (moduleType, module, initData)); + } + + /// @notice get callData to uninstall a module on an ERC7579 Account + /// @param moduleType uint256 the type of the module + /// @param module address the address of the module to uninstall + /// @param initData bytes the data to pass to the module + /// @return callData bytes the callData to uninstall the module + function getUninstallModuleCallData( + AccountInstance memory, // instance + uint256 moduleType, + address module, + bytes memory initData + ) + public + view + virtual + returns (bytes memory callData) + { + callData = abi.encodeCall(IERC7579Account.uninstallModule, (moduleType, module, initData)); + } + + /// @notice get callData to install a validator on an ERC7579 Account + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to install the validator + function getInstallValidatorData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + returns (bytes memory data) + { + data = initData; + } + + /// @notice get callData to uninstall a validator on an ERC7579 Account + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to uninstall the validator + function getUninstallValidatorData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + returns (bytes memory data) + { + data = initData; + } + + /// @notice get callData to install executor on an ERC7579 Account + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to install the executor + function getInstallExecutorData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + returns (bytes memory data) + { + data = initData; + } + + /// @notice get callData to uninstall executor on an ERC7579 Account + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to uninstall the executor + function getUninstallExecutorData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + returns (bytes memory data) + { + data = initData; + } + + /// @notice get callData to install hook on an ERC7579 Account + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to install the hook + function getInstallHookData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + returns (bytes memory data) + { + data = initData; + } + + /// @notice get callData to uninstall hook on an ERC7579 Account + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to uninstall the hook + function getUninstallHookData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + pure + virtual + returns (bytes memory data) + { + data = initData; + } + + /// @notice get callData to install fallback on an ERC7579 Account + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to install the fallback + function getInstallFallbackData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + returns (bytes memory data) + { + data = initData; + } + + /// @notice get callData to uninstall fallback on an ERC7579 Account + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to uninstall the fallback + function getUninstallFallbackData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + pure + virtual + returns (bytes memory data) + { + data = initData; + } + + /// @notice get callData to install an ERC1271 prevalidation hook + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to install the prevalidation hook ERC1271 + function getInstallPrevalidationHookERC1271Data( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + returns (bytes memory data) + { + data = initData; + } + + /// @notice get callData to install an ERC4337 prevalidation hook ERC4337 + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to install the prevalidation hook ERC4337 + function getInstallPrevalidationHookERC4337Data( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + returns (bytes memory data) + { + data = initData; + } + + /// @notice get callData to uninstall an ERC1271 prevalidation hook + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to uninstall the prevalidation hook ERC1271 + function getUninstallPrevalidationHookERC1271Data( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + returns (bytes memory data) + { + data = initData; + } + + /// @notice get callData to uninstall an ERC4337 prevalidation hook + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to uninstall the prevalidation hook ERC4337 + function getUninstallPrevalidationHookERC4337Data( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + returns (bytes memory data) + { + data = initData; + } + + /*////////////////////////////////////////////////////////////////////////// + MODULE UTILS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Checks if a module is installed on an ERC7579 Account + /// @param instance AccountInstance the account instance to check the module on + /// @param moduleTypeId uint256 the type of the module + /// @param module address the address of the module to check + /// @return bool whether the module is installed + function isModuleInstalled( + AccountInstance memory instance, + uint256 moduleTypeId, + address module + ) + public + virtual + deployAccountForAction(instance) + returns (bool) + { + return isModuleInstalled(instance, moduleTypeId, module, ""); + } + + /// @notice Checks if a module is installed on an ERC7579 Account + /// @param instance AccountInstance the account instance to check the module on + /// @param moduleTypeId uint256 the type of the module + /// @param module address the address of the module to check + /// @param additionalContext bytes additional context to pass to the module + /// @return bool whether the module is installed + function isModuleInstalled( + AccountInstance memory instance, + uint256 moduleTypeId, + address module, + bytes memory additionalContext + ) + public + virtual + deployAccountForAction(instance) + returns (bool) + { + return IERC7579Account(instance.account).isModuleInstalled( + moduleTypeId, module, additionalContext + ); + } + + /// @notice Gets the data to install a module on an ERC7579 Account, based on the module type + /// @param instance AccountInstance the account instance to install the module on + /// @param moduleType uint256 the type of the module + /// @param module address the address of the module to install + /// @param initData bytes the data to pass to the module + /// @return data bytes the data to install the module + function getInstallModuleData( + AccountInstance memory instance, + uint256 moduleType, + address module, + bytes memory initData + ) + public + view + virtual + returns (bytes memory) + { + if (moduleType == MODULE_TYPE_VALIDATOR) { + return getInstallValidatorData(instance, module, initData); + } else if (moduleType == MODULE_TYPE_EXECUTOR) { + return getInstallExecutorData(instance, module, initData); + } else if (moduleType == MODULE_TYPE_HOOK) { + return getInstallHookData(instance, module, initData); + } else if (moduleType == MODULE_TYPE_FALLBACK) { + return getInstallFallbackData(instance, module, initData); + } else if (moduleType == MODULE_TYPE_PREVALIDATION_HOOK_ERC1271) { + return getInstallPrevalidationHookERC1271Data(instance, module, initData); + } else if (moduleType == MODULE_TYPE_PREVALIDATION_HOOK_ERC4337) { + return getInstallPrevalidationHookERC4337Data(instance, module, initData); + } else { + revert("Invalid module type"); + } + } + + /// @notice Gets the data to uninstall a module on an ERC7579 Account, based on the module type + /// @param instance AccountInstance the account instance to uninstall the module from + /// @param moduleType uint256 the type of the module + /// @param module address the address of the module to uninstall + /// @param initData bytes the data to pass to the module + /// @return data bytes the data to uninstall the module + function getUninstallModuleData( + AccountInstance memory instance, + uint256 moduleType, + address module, + bytes memory initData + ) + public + view + virtual + returns (bytes memory) + { + if (moduleType == MODULE_TYPE_VALIDATOR) { + return getUninstallValidatorData(instance, module, initData); + } else if (moduleType == MODULE_TYPE_EXECUTOR) { + return getUninstallExecutorData(instance, module, initData); + } else if (moduleType == MODULE_TYPE_HOOK) { + return getUninstallHookData(instance, module, initData); + } else if (moduleType == MODULE_TYPE_FALLBACK) { + return getUninstallFallbackData(instance, module, initData); + } else if (moduleType == MODULE_TYPE_PREVALIDATION_HOOK_ERC1271) { + return getUninstallPrevalidationHookERC1271Data(instance, module, initData); + } else if (moduleType == MODULE_TYPE_PREVALIDATION_HOOK_ERC4337) { + return getUninstallPrevalidationHookERC4337Data(instance, module, initData); + } else { + revert("Invalid module type"); + } + } + + /*////////////////////////////////////////////////////////////////////////// + SIGNATURE UTILS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Checks if a signature is valid for an account instance + /// @param instance AccountInstance the account instance to check the signature on + /// @param hash bytes32 the hash to check the signature against + /// @param signature bytes the signature to check + /// @return isValid bool whether the signature is valid, returns true if isValidSignature + /// returns EIP1271_MAGIC_VALUE + function isValidSignature( + AccountInstance memory instance, + address, // validator + bytes32 hash, + bytes memory signature + ) + public + virtual + deployAccountForAction(instance) + returns (bool isValid) + { + isValid = + IERC1271(instance.account).isValidSignature(hash, signature) == EIP1271_MAGIC_VALUE; + } + + /// @notice Formats a hash for an ERC1271 signature + /// @param hash bytes32 the hash to format + /// @return bytes32 the formatted hash + function formatERC1271Hash( + AccountInstance memory, // instance + address, //validator + bytes32 hash + ) + public + virtual + returns (bytes32) + { + return hash; + } + + /// @notice Formats a signature for an ERC1271 signature + /// @param signature bytes the signature to format + /// @return bytes the formatted signature + function formatERC1271Signature( + AccountInstance memory, // instance + address, // validator + bytes memory signature + ) + public + virtual + returns (bytes memory) + { + return signature; + } + + /*////////////////////////////////////////////////////////////////////////// + ACCOUNT UTILS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Deploys an account instance, if it has not been deployed yet + /// reverts if no initCode is provided + /// @param instance AccountInstance the account instance to deploy + function deployAccount(AccountInstance memory instance) public virtual { + if (instance.account.code.length == 0) { + if (instance.initCode.length == 0) { + revert("deployAccount: no initCode provided"); + } else { + bytes memory initCode = instance.initCode; + assembly { + let factory := mload(add(initCode, 20)) + let success := call(gas(), factory, 0, add(initCode, 52), mload(initCode), 0, 0) + if iszero(success) { revert(0, 0) } + } + } + } + } + + /// @notice Deploys an account instance, if it has not been deployed yet, and reverts to the + /// snapshot after the action + modifier deployAccountForAction(AccountInstance memory instance) { + bool isAccountDeployed = instance.account.code.length != 0; + uint256 snapShotId; + if (!isAccountDeployed) { + snapShotId = snapshot(); + deployAccount(instance); + } + + _; + + if (!isAccountDeployed) { + revertTo(snapShotId); + } + } + + /*////////////////////////////////////////////////////////////////////////// + UTILS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Encode a single ERC7579 Execution Transaction + /// @param target address the target + /// @param value uint256 the value + /// @param callData bytes the callData of the call + /// @return erc7579Tx bytes the encoded ERC7579 transaction + function encode( + address target, + uint256 value, + bytes memory callData + ) + public + pure + virtual + returns (bytes memory erc7579Tx) + { + ModeCode mode = ModeLib.encode({ + callType: CALLTYPE_SINGLE, + execType: EXECTYPE_DEFAULT, + mode: MODE_DEFAULT, + payload: ModePayload.wrap(bytes22(0)) + }); + bytes memory data = abi.encodePacked(target, value, callData); + return abi.encodeCall(IERC7579Account.execute, (mode, data)); + } + + /// @notice Encode a batch of ERC7579 Execution Transactions + /// @param executions Execution[] the array of executions + /// @return erc7579Tx bytes the encoded ERC7579 transaction + function encode(Execution[] memory executions) + public + pure + virtual + returns (bytes memory erc7579Tx) + { + ModeCode mode = ModeLib.encode({ + callType: CALLTYPE_BATCH, + execType: EXECTYPE_DEFAULT, + mode: MODE_DEFAULT, + payload: ModePayload.wrap(bytes22(0)) + }); + return abi.encodeCall(IERC7579Account.execute, (mode, abi.encode(executions))); + } + + /// @notice Convert arrays of targets, values, and callDatas to an array of Executions + /// @param targets address[] the array of targets + /// @param values uint256[] the array of values + /// @param callDatas bytes[] the array of callDatas + /// @return executions Execution[] the array of encoded executions + function toExecutions( + address[] memory targets, + uint256[] memory values, + bytes[] memory callDatas + ) + public + pure + virtual + returns (Execution[] memory executions) + { + executions = new Execution[](targets.length); + if (targets.length != values.length && values.length != callDatas.length) { + revert("Length Mismatch"); + } + + for (uint256 i; i < targets.length; i++) { + executions[i] = + Execution({ target: targets[i], value: values[i], callData: callDatas[i] }); + } + } + + /*////////////////////////////////////////////////////////////////////////// + NONCE + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Get the nonce for an account instance + /// @param instance AccountInstance the account instance to get the nonce for + /// @param txValidator address the address of the validator + /// @return nonce uint256 the nonce + function getNonce( + AccountInstance memory instance, + bytes memory, + address txValidator + ) + public + virtual + returns (uint256 nonce) + { + uint192 key = uint192(bytes24(bytes20(address(txValidator)))); + nonce = instance.aux.entrypoint.getNonce(address(instance.account), key); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/KernelHelpers.sol b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/KernelHelpers.sol new file mode 100644 index 0000000..f8a7410 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/KernelHelpers.sol @@ -0,0 +1,584 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { AccountInstance } from "../RhinestoneModuleKit.sol"; +import { ValidationType, ValidationMode, ValidationId } from "../../accounts/kernel/types/Types.sol"; +import { + VALIDATION_TYPE_PERMISSION, + VALIDATION_TYPE_ROOT, + VALIDATION_TYPE_VALIDATOR, + VALIDATION_MODE_DEFAULT, + VALIDATION_MODE_ENABLE, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_HOOK, + MODULE_TYPE_VALIDATOR, + KERNEL_WRAPPER_TYPE_HASH +} from "../../accounts/kernel/types/Constants.sol"; +import { CallType } from "../../accounts/common/lib/ModeLib.sol"; +import { Execution } from "../../accounts/erc7579/lib/ExecutionLib.sol"; +import { PackedUserOperation } from "../../external/ERC4337.sol"; + +// Libraries +import { ValidatorLib, ValidationConfig } from "../../accounts/kernel/lib/ValidationTypeLib.sol"; + +// Deployments +import { ENTRYPOINT_ADDR } from "../../deployment/predeploy/EntryPoint.sol"; +import { KernelPrecompiles, ISetSelector } from "../../deployment/precompiles/KernelPrecompiles.sol"; + +// Interfaces +import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/IEntryPoint.sol"; +import { IERC7579Account } from "../../accounts/kernel/interfaces/IERC7579Account.sol"; +import { IKernel } from "../../accounts/kernel/interfaces/IKernel.sol"; +import { IValidator, IModule } from "../../accounts/common/interfaces/IERC7579Module.sol"; +import { IERC1271, EIP1271_MAGIC_VALUE } from "../../Interfaces.sol"; + +// Mocks +import { MockFallback } from "../../accounts/kernel/mock/MockFallback.sol"; +import { MockHookMultiPlexer } from "../../Mocks.sol"; + +// Dependencies +import { HelperBase } from "./HelperBase.sol"; +import { TrustedForwarder } from "../../Modules.sol"; +import { KernelFactory } from "../../accounts/kernel/KernelFactory.sol"; + +// Utils +import { etch } from "../utils/Vm.sol"; + +// External Dependencies +import { EIP712 } from "solady/utils/EIP712.sol"; + +/// @notice Helper functions for the Kernel ERC7579 account implementation +contract KernelHelpers is HelperBase, KernelPrecompiles { + /*////////////////////////////////////////////////////////////////////////// + EXECUTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Gets userOp and userOpHash for an executing calldata on an account instance + /// @param instance AccountInstance the account instance to execute the userop for + /// @param callData bytes the calldata to execute + /// @param txValidator address the address of the validator + /// @return userOp PackedUserOperation the packed user operation + /// @return userOpHash bytes32 the hash of the user operation + function execUserOp( + AccountInstance memory instance, + bytes memory callData, + address txValidator + ) + public + virtual + override + returns (PackedUserOperation memory userOp, bytes32 userOpHash) + { + bytes memory initCode; + bool notDeployedYet = instance.account.code.length == 0; + if (notDeployedYet) { + initCode = instance.initCode; + } + uint256 nonce = getNonce(instance, callData, txValidator); + + address execHook = getExecHook(instance, txValidator); + if (execHook != address(0) && execHook != address(1)) { + callData = abi.encodePacked(IKernel.executeUserOp.selector, callData); + } + + userOp = PackedUserOperation({ + sender: instance.account, + nonce: nonce, + initCode: initCode, + callData: callData, + accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), + preVerificationGas: 2e6, + gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), + paymasterAndData: bytes(""), + signature: bytes("") + }); + + userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); + } + + /*////////////////////////////////////////////////////////////////////////// + NONCE + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Gets the nonce for an account instance + /// @param instance AccountInstance the account instance to get the nonce for + /// @param callData bytes the calldata to execute + /// @param txValidator address the address of the validator + function getNonce( + AccountInstance memory instance, + bytes memory callData, + address txValidator + ) + public + virtual + override + returns (uint256 nonce) + { + ValidationType vType; + if (txValidator == address(instance.defaultValidator)) { + vType = VALIDATION_TYPE_ROOT; + } else { + enableValidator(instance, callData, txValidator); + vType = VALIDATION_TYPE_VALIDATOR; + } + nonce = encodeNonce(vType, false, instance.account, txValidator); + } + + /// @notice Encodes the nonce for an account instance in the Kernel format + /// @param vType ValidationType the validation type + /// @param enable bool whether to enable the validator + /// @param account address the address of the account + /// @param validator address the address of the validator + /// @return nonce uint256 the encoded nonce + function encodeNonce( + ValidationType vType, + bool enable, + address account, + address validator + ) + public + view + returns (uint256 nonce) + { + uint192 nonceKey = 0; + if (vType == VALIDATION_TYPE_ROOT) { + nonceKey = 0; + } else if (vType == VALIDATION_TYPE_VALIDATOR) { + ValidationMode mode = VALIDATION_MODE_DEFAULT; + if (enable) { + mode = VALIDATION_MODE_ENABLE; + } + nonceKey = ValidatorLib.encodeAsNonceKey( + ValidationMode.unwrap(mode), + ValidationType.unwrap(vType), + bytes20(validator), + 0 // parallel key + ); + } else { + revert("Invalid validation type"); + } + return IEntryPoint(ENTRYPOINT_ADDR).getNonce(account, nonceKey); + } + + /*////////////////////////////////////////////////////////////////////////// + MODULE CONFIG + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Configures a userop for an account instance to install or uninstall a module + /// @param instance AccountInstance the account instance to configure the userop for + /// @param moduleType uint256 the type of the module + /// @param module address the address of the module + /// @param initData bytes the data to pass to the module + /// @param isInstall bool whether to install or uninstall the module + /// @param txValidator address the address of the validator + /// @return userOp PackedUserOperation the packed user operation + /// @return userOpHash bytes32 the hash of the user operation + function configModuleUserOp( + AccountInstance memory instance, + uint256 moduleType, + address module, + bytes memory initData, + bool isInstall, + address txValidator + ) + public + virtual + override + returns (PackedUserOperation memory userOp, bytes32 userOpHash) + { + bytes memory initCode; + if (instance.account.code.length == 0) { + initCode = instance.initCode; + } + bytes memory callData; + if (isInstall) { + initData = getInstallModuleData({ + instance: instance, + moduleType: moduleType, + module: module, + initData: initData + }); + callData = getInstallModuleCallData({ + instance: instance, + moduleType: moduleType, + module: module, + initData: initData + }); + } else { + initData = getUninstallModuleData({ + instance: instance, + moduleType: moduleType, + module: module, + initData: initData + }); + callData = getUninstallModuleCallData({ + instance: instance, + moduleType: moduleType, + module: module, + initData: initData + }); + } + + address execHook = getExecHook(instance, txValidator); + if (execHook != address(0) && execHook != address(1)) { + callData = abi.encodePacked(IKernel.executeUserOp.selector, callData); + } + + userOp = PackedUserOperation({ + sender: instance.account, + nonce: getNonce(instance, callData, txValidator), + initCode: initCode, + callData: callData, + accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), + preVerificationGas: 2e6, + gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), + paymasterAndData: bytes(""), + signature: bytes("") + }); + + userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); + } + + /// @notice Enables a validator for an account instance + /// @param instance AccountInstance the account instance to enable the validator for + /// @param callData bytes the calldata to execute + /// @param txValidator address the address of the validator + function enableValidator( + AccountInstance memory instance, + bytes memory callData, + address txValidator + ) + internal + deployAccountForAction(instance) + { + ValidationId vId = ValidatorLib.validatorToIdentifier(IValidator(txValidator)); + bytes4 selector; + assembly { + selector := mload(add(callData, 32)) + } + bool isAllowedSelector = IKernel(payable(instance.account)).isAllowedSelector(vId, selector); + if (!isAllowedSelector) { + bytes memory accountCode = instance.account.code; + address _setSelector = address(deployKernelWithSetSelector(ENTRYPOINT_ADDR)); + etch(instance.account, _setSelector.code); + ISetSelector(payable(instance.account)).setSelector(vId, selector, true); + etch(instance.account, accountCode); + } + } + + /// @notice Gets the data to install a validator on an account instance + /// @dev + /// https://github.com/zerodevapp/kernel/blob/a807c8ec354a77ebb7cdb73c5be9dd315cda0df2/../../Kernel.sol#L311-L321 + /// @param instance AccountInstance the account instance to install the validator on + /// implementation) + /// @param initData the data to pass to the validator + /// @return data the data to install the validator + function getInstallValidatorData( + AccountInstance memory instance, + address, // module + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory data) + { + data = abi.encodePacked( + getHookMultiPlexer(instance), abi.encode(initData, hex"00", bytes(hex"00000001")) + ); + } + + /// @notice Gets the data to install an executor on an account instance + /// @dev + /// https://github.com/zerodevapp/kernel/blob/a807c8ec354a77ebb7cdb73c5be9dd315cda0df2/../../Kernel.sol#L324-L334 + /// @param instance AccountInstance the account instance to install the executor on + /// @param initData the data to pass to the executor + /// @return data the data to install the executor + function getInstallExecutorData( + AccountInstance memory instance, + address, // module + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory data) + { + data = abi.encodePacked( + getHookMultiPlexer(instance), abi.encode(initData, abi.encodePacked(bytes1(0x00), "")) + ); + } + + /// @notice Gets the data to install a fallback on an account instance + /// @dev + /// https://github.com/zerodevapp/kernel/blob/a807c8ec354a77ebb7cdb73c5be9dd315cda0df2/../../Kernel.sol#L336-L345 + /// @param instance AccountInstance the account instance to install the fallback on + /// @param initData the data to pass to the fallback + /// @return data the data to install the fallback + function getInstallFallbackData( + AccountInstance memory instance, + address, // module + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory data) + { + (bytes4 selector, CallType callType, bytes memory _initData) = + abi.decode(initData, (bytes4, CallType, bytes)); + data = abi.encodePacked( + selector, + getHookMultiPlexer(instance), + abi.encode(abi.encodePacked(callType, _initData), abi.encodePacked(bytes1(0x00), "")) + ); + } + + /// @notice Gets the data to uninstall a fallback on an account instance + /// @dev + /// https://github.com/zerodevapp/kernel/blob/a807c8ec354a77ebb7cdb73c5be9dd315cda0df2/../../Kernel.sol#L402-L403 + /// @param initData the data to pass to the fallback + /// @return data the data to uninstall the fallback + function getUninstallFallbackData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + pure + virtual + override + returns (bytes memory data) + { + (bytes4 selector,, bytes memory _initData) = abi.decode(initData, (bytes4, CallType, bytes)); + data = abi.encodePacked(selector, _initData); + } + + /// @notice Gets the data to install a module on an account instance + /// @param instance AccountInstance the account instance to install the module on + /// @param moduleType uint256 the type of the module + /// @param module address the address of the module to install + /// @param initData bytes the data to pass to the module + /// @return callData the data to install the module + function getInstallModuleCallData( + AccountInstance memory instance, + uint256 moduleType, + address module, + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory callData) + { + if (moduleType == MODULE_TYPE_HOOK) { + Execution[] memory executions = new Execution[](3); + executions[0] = Execution({ + target: getHookMultiPlexer(instance), + value: 0, + callData: abi.encodeCall(MockHookMultiPlexer.addHook, (module)) + }); + executions[1] = Execution({ + target: module, + value: 0, + callData: abi.encodeCall(IModule.onInstall, (initData)) + }); + executions[2] = Execution({ + target: module, + value: 0, + callData: abi.encodeCall( + TrustedForwarder.setTrustedForwarder, (getHookMultiPlexer(instance)) + ) + }); + callData = encode({ executions: executions }); + } else { + callData = abi.encodeCall(IERC7579Account.installModule, (moduleType, module, initData)); + } + } + + /// @notice Gets the data to uninstall a module on an account instance + /// @param instance AccountInstance the account instance to uninstall the module from + /// @param moduleType uint256 the type of the module + /// @param module address the address of the module to uninstall + /// @param initData bytes the data to pass to the module + /// @return callData the data to uninstall the module + function getUninstallModuleCallData( + AccountInstance memory instance, + uint256 moduleType, + address module, + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory callData) + { + if (moduleType == MODULE_TYPE_HOOK) { + Execution[] memory executions = new Execution[](3); + executions[0] = Execution({ + target: getHookMultiPlexer(instance), + value: 0, + callData: abi.encodeCall(MockHookMultiPlexer.removeHook, (module)) + }); + executions[1] = Execution({ + target: module, + value: 0, + callData: abi.encodeCall(IModule.onUninstall, (initData)) + }); + executions[2] = Execution({ + target: module, + value: 0, + callData: abi.encodeCall(TrustedForwarder.clearTrustedForwarder, ()) + }); + callData = encode({ executions: executions }); + } else { + callData = + abi.encodeCall(IERC7579Account.uninstallModule, (moduleType, module, initData)); + } + } + + /// @notice Checks if a module is installed on an account instance + /// @param instance AccountInstance the account instance to check the module on + /// @param moduleTypeId uint256 the type of the module + /// @param module address the address of the module to check + /// @param data bytes the data to pass to the module + /// @return bool whether the module is installed + function isModuleInstalled( + AccountInstance memory instance, + uint256 moduleTypeId, + address module, + bytes memory data + ) + public + virtual + override + deployAccountForAction(instance) + returns (bool) + { + if (moduleTypeId == MODULE_TYPE_HOOK) { + return MockHookMultiPlexer(getHookMultiPlexer(instance)).isHookInstalled( + instance.account, module + ); + } + + return IERC7579Account(instance.account).isModuleInstalled(moduleTypeId, module, data); + } + + /*////////////////////////////////////////////////////////////////////////// + SIGNATURE UTILS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Checks if a signature is valid for an account instance + /// @param instance AccountInstance the account instance to check the signature on + /// @param validator address the address of the validator + /// @param hash bytes32 the hash of the data that is signed + /// @param signature bytes the signature to check + /// @return isValid bool whether the signature is valid, return true if isValidSignature return + /// EIP1271_MAGIC_VALUE + function isValidSignature( + AccountInstance memory instance, + address validator, + bytes32 hash, + bytes memory signature + ) + public + virtual + override + deployAccountForAction(instance) + returns (bool isValid) + { + isValid = IERC1271(instance.account).isValidSignature( + hash, + abi.encodePacked(ValidatorLib.validatorToIdentifier(IValidator(validator)), signature) + ) == EIP1271_MAGIC_VALUE; + } + + /// @notice Formats a ERC1271 hash for an account instance + /// @param instance AccountInstance the account instance to format the signature for + /// @param hash bytes32 the hash to format + /// @return bytes the formatted signature hash + function formatERC1271Hash( + AccountInstance memory instance, + address, // validator + bytes32 hash + ) + public + virtual + override + deployAccountForAction(instance) + returns (bytes32) + { + return IKernel(payable(instance.account))._toWrappedHash(hash); + } + + /// @notice Formats an ERC1271 signature for an account instance + /// @param validator address the address of the validator + /// @param signature bytes the signature to format + /// @return bytes the formatted signature + function formatERC1271Signature( + AccountInstance memory, // instance + address validator, + bytes memory signature + ) + public + virtual + override + returns (bytes memory) + { + return + abi.encodePacked(ValidatorLib.validatorToIdentifier(IValidator(validator)), signature); + } + + /*////////////////////////////////////////////////////////////// + HOOK MULTIPLEXER + //////////////////////////////////////////////////////////////*/ + + /// @notice Gets the hook multiplexer for an account instance + /// @param instance AccountInstance the account instance to get the hook multiplexer for + /// @return address the address of the hook multiplexer + function getHookMultiPlexer(AccountInstance memory instance) public view returns (address) { + return address(KernelFactory(instance.accountFactory).hookMultiPlexer()); + } + + /// @notice Sets the hook multiplexer for an account instance + /// @param instance AccountInstance the account instance to set the hook multiplexer for + /// @param hookMultiPlexer address the address of the hook multiplexer + function setHookMultiPlexer( + AccountInstance memory instance, + address hookMultiPlexer + ) + public + virtual + deployAccountForAction(instance) + { + KernelFactory(instance.accountFactory).setHookMultiPlexer(hookMultiPlexer); + } + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Gets the exec hook for an account instance + /// @param instance AccountInstance the account instance to get the exec hook for + /// @param txValidator address the address of the validator + /// @return address the address of the exec hook + function getExecHook( + AccountInstance memory instance, + address txValidator + ) + internal + deployAccountForAction(instance) + returns (address) + { + ValidationId vId = ValidatorLib.validatorToIdentifier(IValidator(txValidator)); + ValidationConfig memory validationConfig = + IKernel(payable(instance.account)).validationConfig(vId); + return address(validationConfig.hook); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/NexusHelpers.sol b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/NexusHelpers.sol new file mode 100644 index 0000000..4fe0f65 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/NexusHelpers.sol @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { PackedUserOperation } from "../../external/ERC4337.sol"; +import { AccountInstance } from "../RhinestoneModuleKit.sol"; +import { CallType } from "../../accounts/common/lib/ModeLib.sol"; + +// Interfaces +import { IAccountModulesPaginated } from "./interfaces/IAccountModulesPaginated.sol"; +import { IERC1271, EIP1271_MAGIC_VALUE } from "../../Interfaces.sol"; + +// Dependencies +import { HelperBase } from "./HelperBase.sol"; + +/// @notice Helper functions for the Nexus ERC7579 implementation +contract NexusHelpers is HelperBase { + /*////////////////////////////////////////////////////////////////////////// + EXECUTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Gets userOp and userOpHash for an executing calldata on an account instance + /// @param instance AccountInstance the account instance to execute the callData on + /// @param callData bytes the calldata to execute + /// @param txValidator address the address of the validator + /// @return userOp PackedUserOperation the user operation + /// @return userOpHash bytes32 the hash of the user operation + function execUserOp( + AccountInstance memory instance, + bytes memory callData, + address txValidator + ) + public + view + override + returns (PackedUserOperation memory userOp, bytes32 userOpHash) + { + bytes memory initCode; + bool notDeployedYet = instance.account.code.length == 0; + if (notDeployedYet) { + initCode = instance.initCode; + } + + userOp = PackedUserOperation({ + sender: instance.account, + nonce: getNonce(instance, 0x00, txValidator), + initCode: initCode, + callData: callData, + accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), + preVerificationGas: 2e6, + gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), + paymasterAndData: bytes(""), + signature: bytes("") + }); + + userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); + } + + /*////////////////////////////////////////////////////////////// + NONCE + //////////////////////////////////////////////////////////////*/ + + /// @notice Gets the nonce for an account instance + /// @param instance AccountInstance the account instance to get the nonce for + /// @param vMode bytes1 the mode of the validator + /// @param validator address the address of the validator + /// @return nonce uint256 the nonce + function getNonce( + AccountInstance memory instance, + bytes1 vMode, + address validator + ) + internal + view + returns (uint256 nonce) + { + uint192 key = makeNonceKey(vMode, validator); + nonce = instance.aux.entrypoint.getNonce(address(instance.account), key); + } + + /// @notice Makes a nonce key for an account instance + /// @param vMode bytes1 the mode of the validator + /// @param validator address the address of the validator + function makeNonceKey(bytes1 vMode, address validator) internal pure returns (uint192 key) { + // solhint-disable-next-line no-inline-assembly + assembly { + key := or(shr(88, vMode), validator) + } + } + + /*////////////////////////////////////////////////////////////////////////// + MODULE CONFIG + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Configures a userop for an account instance to install or uninstall a module + /// @param instance AccountInstance the account instance to configure the userop for + /// @param moduleType uint256 the type of the module + /// @param module address the address of the module + /// @param initData data the data to pass to the module + /// @param isInstall bool whether to install or uninstall the module + /// @param txValidator address the address of the validator + /// @return userOp PackedUserOperation the packed user operation + /// @return userOpHash bytes32 the hash of the user operation + function configModuleUserOp( + AccountInstance memory instance, + uint256 moduleType, + address module, + bytes memory initData, + bool isInstall, + address txValidator + ) + public + view + override + returns (PackedUserOperation memory userOp, bytes32 userOpHash) + { + bytes memory initCode; + if (instance.account.code.length == 0) { + initCode = instance.initCode; + } + bytes memory callData; + if (isInstall) { + initData = getInstallModuleData(instance, moduleType, module, initData); + callData = getInstallModuleCallData(instance, moduleType, module, initData); + } else { + initData = getUninstallModuleData(instance, moduleType, module, initData); + callData = getUninstallModuleCallData(instance, moduleType, module, initData); + } + + userOp = PackedUserOperation({ + sender: instance.account, + nonce: getNonce(instance, 0x00, txValidator), + initCode: initCode, + callData: callData, + accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), + preVerificationGas: 2e6, + gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), + paymasterAndData: bytes(""), + signature: bytes("") + }); + + userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); + } + + /// @notice Gets the data to install a validator on an account instance + /// @param instance AccountInstance the account instance to install the validator on + /// @param initData the data to pass to the validator + /// @return data the data to install the validator + function getUninstallValidatorData( + AccountInstance memory instance, + address module, + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory data) + { + // get previous validator in sentinel list + address previous; + + (address[] memory array,) = + IAccountModulesPaginated(instance.account).getValidatorsPaginated(address(0x1), 100); + + if (array.length == 1) { + previous = address(0x1); + } else if (array[0] == module) { + previous = address(0x1); + } else { + for (uint256 i = 1; i < array.length; i++) { + if (array[i] == module) previous = array[i - 1]; + } + } + data = abi.encode(previous, initData); + } + + /// @notice Gets the data to install a validator on an account instance + /// @param instance AccountInstance the account instance to install the validator on + /// @param initData the data to pass to the validator + /// @return data the data to install the validator + function getUninstallExecutorData( + AccountInstance memory instance, + address module, + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory data) + { + // get previous executor in sentinel list + address previous; + + (address[] memory array,) = + IAccountModulesPaginated(instance.account).getExecutorsPaginated(address(0x1), 100); + + if (array.length == 1) { + previous = address(0x1); + } else if (array[0] == module) { + previous = address(0x1); + } else { + for (uint256 i = 1; i < array.length; i++) { + if (array[i] == module) previous = array[i - 1]; + } + } + data = abi.encode(previous, initData); + } + + /// @notice Gets the data to install a fallback on an account instance + /// @param initData the data to pass to the module + /// @return data the data to install the fallback + function getInstallFallbackData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + pure + virtual + override + returns (bytes memory data) + { + (bytes4 selector, CallType callType, bytes memory _initData) = + abi.decode(initData, (bytes4, CallType, bytes)); + data = abi.encodePacked(selector, callType, _initData); + } + + /// @notice Gets the data to uninstall a fallback on an account instance + /// @param initData the data to pass to the module + /// @return data the data to uninstall the fallback + function getUninstallFallbackData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + pure + virtual + override + returns (bytes memory data) + { + (bytes4 selector,, bytes memory _initData) = abi.decode(initData, (bytes4, CallType, bytes)); + data = abi.encodePacked(selector, _initData); + } + + /*////////////////////////////////////////////////////////////////////////// + SIGNATURE UTILS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Checks if a signature is valid for an account instance + /// @param instance AccountInstance the account instance to check the signature on + /// @param validator address the address of the validator + /// @param hash bytes32 the hash of the data that is signed + /// @param signature bytes the signature to check + /// @return isValid bool whether the signature is valid, return true if isValidSignature return + /// EIP1271_MAGIC_VALUE + function isValidSignature( + AccountInstance memory instance, + address validator, + bytes32 hash, + bytes memory signature + ) + public + virtual + override + deployAccountForAction(instance) + returns (bool isValid) + { + isValid = IERC1271(instance.account).isValidSignature( + hash, abi.encodePacked(validator, signature) + ) == EIP1271_MAGIC_VALUE; + } + + /// @notice Formats an ERC1271 signature for an account instance + /// @param validator address the address of the validator + /// @param signature bytes the signature to format + /// @return bytes the formatted signature + function formatERC1271Signature( + AccountInstance memory, // instance + address validator, + bytes memory signature + ) + public + virtual + override + returns (bytes memory) + { + return abi.encodePacked(validator, signature); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/SafeHelpers.sol b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/SafeHelpers.sol new file mode 100644 index 0000000..d2bf3be --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/SafeHelpers.sol @@ -0,0 +1,535 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { AccountInstance } from "../RhinestoneModuleKit.sol"; +import { PackedUserOperation } from "../../external/ERC4337.sol"; +import { + MODULE_TYPE_HOOK, + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK, + MODULE_TYPE_PREVALIDATION_HOOK_ERC1271, + MODULE_TYPE_PREVALIDATION_HOOK_ERC4337 +} from "../../accounts/common/interfaces/IERC7579Module.sol"; +import { HookType } from "../../accounts/safe/types/DataTypes.sol"; +import { CALLTYPE_STATIC } from "../../accounts/common/lib/ModeLib.sol"; +import { CallType } from "../../accounts/common/lib/ModeLib.sol"; + +// Dependencies +import { HelperBase } from "./HelperBase.sol"; +import { SafeFactory } from "../../accounts/safe/SafeFactory.sol"; + +// Interfaces +import { ISafe7579Launchpad } from "../../accounts/safe/interfaces/ISafe7579Launchpad.sol"; +import { IERC7579Account } from "../../accounts/common/interfaces/IERC7579Account.sol"; +import { IAccountFactory } from "../../accounts/factory/interface/IAccountFactory.sol"; +import { IAccountModulesPaginated } from "./interfaces/IAccountModulesPaginated.sol"; +import { IERC1271, EIP1271_MAGIC_VALUE, IERC712 } from "../../Interfaces.sol"; + +// Libraries +import { LibBytes } from "solady/utils/LibBytes.sol"; + +// Utils +import { startPrank, stopPrank } from "../utils/Vm.sol"; + +/// @notice Helper functions for the Safe7579 implementation +contract SafeHelpers is HelperBase { + /*////////////////////////////////////////////////////////////////////////// + CONSTANTS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice The typehash for EIP712 Safe messages + bytes32 constant SAFE_MSG_TYPEHASH = + 0x60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca; + + /*////////////////////////////////////////////////////////////////////////// + EXECUTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Gets userOp and userOpHash for an executing calldata on an account instance + /// @param instance AccountInstance the account instance to execute the callData on + /// @param callData bytes the calldata to execute + /// @param txValidator address the address of the validator + /// @return userOp PackedUserOperation the user operation + /// @return userOpHash bytes32 the hash of the user operation + function execUserOp( + AccountInstance memory instance, + bytes memory callData, + address txValidator + ) + public + virtual + override + returns (PackedUserOperation memory userOp, bytes32 userOpHash) + { + bytes memory initCode; + bool notDeployedYet = instance.account.code.length == 0; + if (notDeployedYet) { + initCode = instance.initCode; + } + + if (initCode.length != 0) { + (initCode, callData) = _getInitCallData(instance.salt, initCode, callData); + } + + userOp = PackedUserOperation({ + sender: instance.account, + nonce: getNonce(instance, callData, txValidator), + initCode: initCode, + callData: callData, + accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), + preVerificationGas: 2e6, + gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), + paymasterAndData: bytes(""), + signature: bytes("") + }); + + userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); + } + + /*////////////////////////////////////////////////////////////////////////// + MODULE CONFIG + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Configures a userop for an account instance to install or uninstall a module + /// @param instance AccountInstance the account instance to configure the userop for + /// @param moduleType uint256 the type of the module + /// @param module address the address of the module + /// @param initData bytes the data to pass to the module + /// @param isInstall bool whether to install or uninstall the module + /// @param txValidator address the address of the validator + /// @return userOp PackedUserOperation the packed user operation + /// @return userOpHash bytes32 the hash of the user operation + function configModuleUserOp( + AccountInstance memory instance, + uint256 moduleType, + address module, + bytes memory initData, + bool isInstall, + address txValidator + ) + public + virtual + override + returns (PackedUserOperation memory userOp, bytes32 userOpHash) + { + bytes memory initCode; + if (instance.account.code.length == 0) { + initCode = instance.initCode; + } + + bytes memory callData; + if (isInstall) { + initData = getInstallModuleData({ + instance: instance, + moduleType: moduleType, + module: module, + initData: initData + }); + callData = abi.encodeCall(IERC7579Account.installModule, (moduleType, module, initData)); + } else { + initData = getUninstallModuleData({ + instance: instance, + moduleType: moduleType, + module: module, + initData: initData + }); + callData = + abi.encodeCall(IERC7579Account.uninstallModule, (moduleType, module, initData)); + } + + if (initCode.length != 0) { + (initCode, callData) = _getInitCallData(instance.salt, initCode, callData); + } + + userOp = PackedUserOperation({ + sender: instance.account, + nonce: getNonce(instance, callData, txValidator), + initCode: initCode, + callData: callData, + accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), + preVerificationGas: 2e6, + gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), + paymasterAndData: bytes(""), + signature: bytes("") + }); + + userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); + } + + /// @notice Gets the data to install a validator on an account instance + /// @param instance AccountInstance the account instance to install the validator on + /// @param initData the data to pass to the validator + /// @return data the data to install the validator + function getUninstallValidatorData( + AccountInstance memory instance, + address module, + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory data) + { + // get previous validator in sentinel list + address previous; + + (address[] memory array,) = + IAccountModulesPaginated(instance.account).getValidatorsPaginated(address(0x1), 100); + + if (array.length == 1) { + previous = address(0x1); + } else if (array[0] == module) { + previous = address(0x1); + } else { + for (uint256 i = 1; i < array.length; i++) { + if (array[i] == module) previous = array[i - 1]; + } + } + data = abi.encode(previous, initData); + } + + /// @notice Gets the data to install an executor on an account instance + /// @param instance AccountInstance the account instance to install the executor on + /// @param initData the data to pass to the executor + /// @return data the data to install the executor + function getUninstallExecutorData( + AccountInstance memory instance, + address module, + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory data) + { + // get previous executor in sentinel list + address previous; + + (address[] memory array,) = + IAccountModulesPaginated(instance.account).getExecutorsPaginated(address(0x1), 100); + + if (array.length == 1) { + previous = address(0x1); + } else if (array[0] == module) { + previous = address(0x1); + } else { + for (uint256 i = 1; i < array.length; i++) { + if (array[i] == module) previous = array[i - 1]; + } + } + data = abi.encode(previous, initData); + } + + /// @notice Gets the data to install a hook on an account instance + /// @param initData the data to pass to the hook + /// @return data the data to install the hook + function getInstallHookData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory data) + { + data = abi.encode(HookType.GLOBAL, bytes4(0x0), initData); + } + + /// @notice Gets the data to uninstall a hook on an account instance + /// @param initData the data to pass to the hook + /// @return data the data to uninstall the hook + function getUninstallHookData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + pure + virtual + override + returns (bytes memory data) + { + data = abi.encode(HookType.GLOBAL, bytes4(0x0), initData); + } + + /// @notice Gets the data to install a fallback on an account instance + /// @param initData the data to pass to the fallback + /// @return data the data to install the fallback + function getUninstallFallbackData( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + pure + virtual + override + returns (bytes memory data) + { + (bytes4 selector,, bytes memory _initData) = abi.decode(initData, (bytes4, CallType, bytes)); + data = abi.encode(selector, _initData); + } + + /// @notice get callData to install an ERC1271 prevalidation hook + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to install the prevalidation hook ERC1271 + function getInstallPrevalidationHookERC1271Data( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory data) + { + data = abi.encode(MODULE_TYPE_PREVALIDATION_HOOK_ERC1271, initData); + } + + /// @notice get callData to install an ERC4337 prevalidation hook ERC4337 + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to install the prevalidation hook ERC4337 + function getInstallPrevalidationHookERC4337Data( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory data) + { + data = abi.encode(MODULE_TYPE_PREVALIDATION_HOOK_ERC4337, initData); + } + + /// @notice get callData to uninstall an ERC1271 prevalidation hook + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to uninstall the prevalidation hook ERC1271 + function getUninstallPrevalidationHookERC1271Data( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory data) + { + data = abi.encode(MODULE_TYPE_PREVALIDATION_HOOK_ERC1271, initData); + } + + /// @notice get callData to uninstall an ERC4337 prevalidation hook + /// @param initData bytes the data to pass to the module + /// @return data bytes the callData to uninstall the prevalidation hook ERC4337 + function getUninstallPrevalidationHookERC4337Data( + AccountInstance memory, // instance + address, // module + bytes memory initData + ) + public + view + virtual + override + returns (bytes memory data) + { + data = abi.encode(MODULE_TYPE_PREVALIDATION_HOOK_ERC4337, initData); + } + + /// @notice Checks if a module is installed on an account instance + /// @param instance AccountInstance the account instance to check + /// @param moduleTypeId uint256 the type of the module + /// @param module address the address of the module + /// @param data bytes the data to pass to the module + /// @return bool whether the module is installed + function isModuleInstalled( + AccountInstance memory instance, + uint256 moduleTypeId, + address module, + bytes memory data + ) + public + virtual + override + deployAccountForAction(instance) + returns (bool) + { + if (moduleTypeId == MODULE_TYPE_HOOK) { + data = abi.encode(HookType.GLOBAL, bytes4(0x0), data); + } + + if ( + moduleTypeId == MODULE_TYPE_PREVALIDATION_HOOK_ERC4337 + || moduleTypeId == MODULE_TYPE_PREVALIDATION_HOOK_ERC1271 + ) { + data = abi.encode(moduleTypeId, data); + } + + return IERC7579Account(instance.account).isModuleInstalled(moduleTypeId, module, data); + } + + /*////////////////////////////////////////////////////////////////////////// + SIGNATURE UTILS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Checks if a signature is valid for an account instance + /// @param instance AccountInstance the account instance to check the signature on + /// @param validator address the address of the validator + /// @param hash bytes32 the hash to check the signature against + /// @param signature bytes the signature to check + /// @return isValid bool whether the signature is valid, returns true if isValidSignature + /// returns EIP1271_MAGIC_VALUE + function isValidSignature( + AccountInstance memory instance, + address validator, + bytes32 hash, + bytes memory signature + ) + public + virtual + override + deployAccountForAction(instance) + returns (bool isValid) + { + isValid = IERC1271(instance.account).isValidSignature( + hash, abi.encodePacked(validator, signature) + ) == EIP1271_MAGIC_VALUE; + } + + /// @notice Format a Safe compatible hash for an account instance + /// @param instance AccountInstance the account instance to format the hash for + /// @param hash bytes32 the hash to format + /// @return bytes32 the formatted hash + function formatERC1271Hash( + AccountInstance memory instance, + address validator, + bytes32 hash + ) + public + virtual + override + deployAccountForAction(instance) + returns (bytes32) + { + // Revert if validator is installed + if (isModuleInstalled(instance, MODULE_TYPE_VALIDATOR, validator, "")) { + revert("formatERC1271Hash: validator is installed"); + } + bytes memory messageData = abi.encodePacked( + bytes1(0x19), + bytes1(0x01), + IERC712(instance.account).domainSeparator(), + keccak256(abi.encodePacked(SAFE_MSG_TYPEHASH, abi.encode(keccak256(abi.encode(hash))))) + ); + return keccak256(messageData); + } + + /// @notice Format a ERC1271 signature for an account + /// @param validator address the address of the validator + /// @param signature bytes the signature to format + /// @return bytes the formatted signature + function formatERC1271Signature( + AccountInstance memory, // instance + address validator, + bytes memory signature + ) + public + virtual + override + returns (bytes memory) + { + return abi.encodePacked(validator, signature); + } + + /*////////////////////////////////////////////////////////////////////////// + ACCOUNT UTILS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Deploys an account instance if it has not been deployed yet + /// reverts if no initCode is provided + /// @param instance AccountInstance the account instance to deploy + function deployAccount(AccountInstance memory instance) public virtual override { + if (instance.account.code.length == 0) { + if (instance.initCode.length == 0) { + revert("deployAccount: no initCode provided"); + } else { + (bytes memory initCode, bytes memory callData) = _getInitCallData( + instance.salt, + instance.initCode, + encode({ target: address(0), value: 0 wei, callData: "" }) + ); + assembly { + let factory := mload(add(initCode, 20)) + let success := call(gas(), factory, 0, add(initCode, 52), mload(initCode), 0, 0) + if iszero(success) { revert(0, 0) } + } + PackedUserOperation memory userOp = PackedUserOperation({ + sender: instance.account, + nonce: getNonce(instance, callData, address(instance.defaultValidator)), + initCode: "", + callData: callData, + accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), + preVerificationGas: 2e6, + gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), + paymasterAndData: bytes(""), + signature: bytes("") + }); + bytes32 userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); + bytes memory userOpValidationCallData = + abi.encodeCall(ISafe7579Launchpad.validateUserOp, (userOp, userOpHash, 0)); + startPrank(address(instance.aux.entrypoint)); + (bool success,) = instance.account.call(userOpValidationCallData); + if (!success) { + revert("deployAccount: failed to call account"); + } + + (success,) = instance.account.call(callData); + + if (!success) { + revert("deployAccount: failed to call account"); + } + stopPrank(); + } + } + } + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Gets the initCode and callData for a new account instance + /// @param salt bytes32 the salt for the account instance + /// @param originalInitCode bytes the original initCode for the account instance + /// @param erc4337CallData bytes the callData for the ERC4337 call + function _getInitCallData( + bytes32 salt, + bytes memory originalInitCode, + bytes memory erc4337CallData + ) + public + pure + returns (bytes memory initCode, bytes memory callData) + { + // TODO: refactor this to decode the initcode + address factory; + assembly { + factory := mload(add(originalInitCode, 20)) + } + bytes memory initData2 = LibBytes.slice(originalInitCode, 120, originalInitCode.length); + ISafe7579Launchpad.InitData memory initData = + abi.decode(initData2, (ISafe7579Launchpad.InitData)); + initData.callData = erc4337CallData; + initCode = abi.encodePacked( + factory, abi.encodeCall(SafeFactory.createAccount, (salt, abi.encode(initData))) + ); + callData = abi.encodeCall(ISafe7579Launchpad.setupSafe, (initData)); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/SmartSessionHelpers.sol b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/SmartSessionHelpers.sol new file mode 100644 index 0000000..d1cf72e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/SmartSessionHelpers.sol @@ -0,0 +1,393 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +/// @dev A collection of smart session related libraries, vendored from +/// https://github.com/erc7579/smartsessions + +// Interfaces +import { + SmartSessionMode, + PermissionId, + EnableSession, + ChainDigest, + Session, + PolicyData, + ActionData, + ERC7739Data +} from "../../integrations/interfaces/ISmartSession.sol"; + +// Libraries +import { LibZip } from "solady/utils/LibZip.sol"; +import { EfficientHashLib } from "solady/utils/EfficientHashLib.sol"; +import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; + +// Types +import { ModeCode as ExecutionMode } from "../../accounts/common/lib/ModeLib.sol"; + +library SmartSessionModeLib { + function isUseMode(SmartSessionMode mode) internal pure returns (bool) { + return mode == SmartSessionMode.USE; + } + + function isEnableMode(SmartSessionMode mode) internal pure returns (bool) { + return (mode == SmartSessionMode.ENABLE || mode == SmartSessionMode.UNSAFE_ENABLE); + } + + function useRegistry(SmartSessionMode mode) internal pure returns (bool) { + return (mode == SmartSessionMode.ENABLE); + } +} + +library EncodeLib { + using LibZip for bytes; + using EncodeLib for *; + using SmartSessionModeLib for SmartSessionMode; + + error ChainIdAndHashesLengthMismatch(uint256 chainIdsLength, uint256 hashesLength); + + function unpackMode(bytes calldata packed) + internal + pure + returns (SmartSessionMode mode, PermissionId permissionId, bytes calldata data) + { + mode = SmartSessionMode(uint8(bytes1(packed[:1]))); + if (mode.isEnableMode()) { + data = packed[1:]; + } else { + permissionId = PermissionId.wrap(bytes32(packed[1:33])); + data = packed[33:]; + } + } + + function encodeUse( + PermissionId permissionId, + bytes memory sig + ) + internal + pure + returns (bytes memory userOpSig) + { + userOpSig = + abi.encodePacked(SmartSessionMode.USE, permissionId, abi.encode(sig).flzCompress()); + } + + function decodeUse(bytes memory packedSig) internal pure returns (bytes memory signature) { + (signature) = abi.decode(packedSig.flzDecompress(), (bytes)); + } + + function encodeUnsafeEnable( + bytes memory sig, + EnableSession memory enableData + ) + internal + pure + returns (bytes memory packedSig) + { + packedSig = abi.encodePacked( + SmartSessionMode.UNSAFE_ENABLE, abi.encode(enableData, sig).flzCompress() + ); + } + + function encodeEnable( + bytes memory sig, + EnableSession memory enableData + ) + internal + pure + returns (bytes memory packedSig) + { + packedSig = + abi.encodePacked(SmartSessionMode.ENABLE, abi.encode(enableData, sig).flzCompress()); + } + + function decodeEnable(bytes calldata packedSig) + internal + pure + returns (EnableSession memory enableData, bytes memory signature) + { + (enableData, signature) = abi.decode(packedSig.flzDecompress(), (EnableSession, bytes)); + } +} + +// Typehashes +string constant POLICY_DATA_NOTATION = "PolicyData(address policy,bytes initData)"; +string constant ACTION_DATA_NOTATION = + "ActionData(address actionTarget, bytes4 actionTargetSelector,PolicyData[] actionPolicies)"; +string constant ERC7739_DATA_NOTATION = + "ERC7739Data(string[] allowedERC7739Content,PolicyData[] erc1271Policies)"; + +bytes32 constant POLICY_DATA_TYPEHASH = keccak256(bytes(POLICY_DATA_NOTATION)); +bytes32 constant ACTION_DATA_TYPEHASH = keccak256(bytes(ACTION_DATA_NOTATION)); +bytes32 constant ERC7739_DATA_TYPEHASH = keccak256(bytes(ERC7739_DATA_NOTATION)); + +string constant SESSION_NOTATION = + "Session(address account,address smartSession,uint8 mode,address sessionValidator,bytes32 salt,bytes sessionValidatorInitData,PolicyData[] userOpPolicies,ERC7739Data erc7739Policies,ActionData[] actions)"; +string constant CHAIN_SESSION_NOTATION = "ChainSession(uint64 chainId,Session session)"; +string constant MULTI_CHAIN_SESSION_NOTATION = + "MultiChainSession(ChainSession[] sessionsAndChainIds)"; + +bytes32 constant SESSION_TYPEHASH = keccak256( + abi.encodePacked( + bytes(SESSION_NOTATION), + bytes(POLICY_DATA_NOTATION), + bytes(ACTION_DATA_NOTATION), + bytes(ERC7739_DATA_NOTATION) + ) +); + +bytes32 constant CHAIN_SESSION_TYPEHASH = keccak256( + abi.encodePacked( + bytes(CHAIN_SESSION_NOTATION), + bytes(SESSION_NOTATION), + bytes(POLICY_DATA_NOTATION), + bytes(ACTION_DATA_NOTATION), + bytes(ERC7739_DATA_NOTATION) + ) +); + +bytes32 constant MULTICHAIN_SESSION_TYPEHASH = keccak256( + abi.encodePacked( + bytes(MULTI_CHAIN_SESSION_NOTATION), + bytes(CHAIN_SESSION_NOTATION), + bytes(SESSION_NOTATION), + bytes(POLICY_DATA_NOTATION), + bytes(ACTION_DATA_NOTATION), + bytes(ERC7739_DATA_NOTATION) + ) +); + +/// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address +/// verifyingContract)")`. +bytes32 constant _DOMAIN_TYPEHASH = + 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; + +// keccak256(abi.encode(_DOMAIN_TYPEHASH, keccak256("SmartSession"), keccak256(""), 0, address(0))); +// One should use the same domain separator where possible +// or provide the following EIP712Domain struct to the signTypedData() function +// Name: "SmartSession" (string) +// Version: "" (string) +// ChainId: 0 (uint256) +// VerifyingContract: address(0) (address) +// it is introduced for compatibility with signTypedData() +// all the critical data such as chainId and verifyingContract are included +// in session hashes +// https://docs.metamask.io/wallet/reference/eth_signtypeddata_v4 +bytes32 constant _DOMAIN_SEPARATOR = + 0xa82dd76056d04dc31e30c73f86aa4966336112e8b5e9924bb194526b08c250c1; + +library HashLib { + error ChainIdMismatch(uint64 providedChainId); + error HashMismatch(bytes32 providedHash, bytes32 computedHash); + + using EfficientHashLib for bytes32; + using HashLib for *; + + /** + * Mimics SignTypedData() behaviour + * 1. hashStruct(Session) + * 2. hashStruct(ChainSession) + * 3. abi.encodePacked hashStruct's for 2) together + * 4. Hash it together with MULTI_CHAIN_SESSION_TYPEHASH + * as it was MultiChainSession struct + * 5. Add multichain domain separator + * This method doest same, just w/o 1. as it is already provided to us as a digest + */ + function multichainDigest(ChainDigest[] memory hashesAndChainIds) + internal + pure + returns (bytes32) + { + bytes32 structHash = keccak256( + abi.encode(MULTICHAIN_SESSION_TYPEHASH, hashesAndChainIds.hashChainDigestArray()) + ); + + return MessageHashUtils.toTypedDataHash(_DOMAIN_SEPARATOR, structHash); + } + + /** + * Hash array of ChainDigest structs + */ + function hashChainDigestArray(ChainDigest[] memory chainDigestArray) + internal + pure + returns (bytes32) + { + uint256 length = chainDigestArray.length; + bytes32[] memory hashes = new bytes32[](length); + for (uint256 i; i < length; i++) { + hashes[i] = chainDigestArray[i].hashChainDigestMimicRPC(); + } + return keccak256(abi.encodePacked(hashes)); + } + + /** + * We have session digests, not full Session structs + * However to mimic signTypedData() behaviour, we need to use CHAIN_SESSION_TYPEHASH + * not CHAIN_DIGEST_TYPEHASH. We just use the ready session digest instead of rebuilding it + */ + function hashChainDigestMimicRPC(ChainDigest memory chainDigest) + internal + pure + returns (bytes32) + { + return keccak256( + abi.encode( + CHAIN_SESSION_TYPEHASH, + chainDigest.chainId, + chainDigest.sessionDigest // this is the digest obtained using sessionDigest() + // we just do not rebuild it here for all sessions, but receive it from + // off-chain + ) + ); + } + + /** + * Hashes the data from the Session struct with some security critical data + * such as nonce, account address, smart session address, and mode + */ + function sessionDigest( + Session memory session, + address account, + SmartSessionMode mode, + uint256 nonce + ) + internal + view + returns (bytes32) + { + return _sessionDigest(session, account, address(this), mode, nonce); + } + + /** + * Should never be used directly on-chain, only via sessionDigest() + * Only for external use - to be able to pass smartSession when + * testing for different chains which may have different addresses for + * the Smart Session contract + * It is exactly how signTypedData will hash such an object + * when this object is an inner struct + * It won't use eip712 domain for it as it is inner struct + */ + function _sessionDigest( + Session memory session, + address account, + address smartSession, // for testing purposes + SmartSessionMode mode, + uint256 nonce + ) + internal + pure + returns (bytes32 _hash) + { + // chainId is not needed as it is in the ChainSession + _hash = keccak256( + abi.encode( + SESSION_TYPEHASH, + account, + smartSession, + uint8(mode), // Include mode as uint8 + address(session.sessionValidator), + session.salt, + keccak256(session.sessionValidatorInitData), + session.userOpPolicies.hashPolicyDataArray(), + session.erc7739Policies.hashERC7739Data(), + session.actions.hashActionDataArray(), + nonce + ) + ); + } + + function hashPolicyData(PolicyData memory policyData) internal pure returns (bytes32) { + return keccak256( + abi.encode(POLICY_DATA_TYPEHASH, policyData.policy, keccak256(policyData.initData)) + ); + } + + function hashPolicyDataArray(PolicyData[] memory policyDataArray) + internal + pure + returns (bytes32) + { + uint256 length = policyDataArray.length; + bytes32[] memory hashes = new bytes32[](length); + for (uint256 i; i < length; i++) { + hashes[i] = policyDataArray[i].hashPolicyData(); + } + return keccak256(abi.encodePacked(hashes)); + } + + function hashActionData(ActionData memory actionData) internal pure returns (bytes32) { + return keccak256( + abi.encode( + ACTION_DATA_TYPEHASH, + actionData.actionTargetSelector, + actionData.actionTarget, + hashPolicyDataArray(actionData.actionPolicies) + ) + ); + } + + function hashActionDataArray(ActionData[] memory actionDataArray) + internal + pure + returns (bytes32) + { + uint256 length = actionDataArray.length; + bytes32[] memory hashes = new bytes32[](length); + for (uint256 i; i < length; i++) { + hashes[i] = actionDataArray[i].hashActionData(); + } + return keccak256(abi.encodePacked(hashes)); + } + + function hashERC7739Data(ERC7739Data memory erc7739Data) internal pure returns (bytes32) { + return keccak256( + abi.encode( + ERC7739_DATA_TYPEHASH, + erc7739Data.allowedERC7739Content.hashStringArray(), + erc7739Data.erc1271Policies.hashPolicyDataArray() + ) + ); + } + + function hashStringArray(string[] memory stringArray) internal pure returns (bytes32) { + uint256 length = stringArray.length; + bytes32[] memory hashes = new bytes32[](length); + for (uint256 i; i < length; i++) { + hashes[i] = keccak256(abi.encodePacked(stringArray[i])); + } + return keccak256(abi.encodePacked(hashes)); + } + + function hashERC7739Content(string memory content) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(content)); + } + + function getAndVerifyDigest( + EnableSession memory enableData, + address account, + uint256 nonce, + SmartSessionMode mode + ) + internal + view + returns (bytes32 digest) + { + bytes32 computedHash = enableData.sessionToEnable.sessionDigest(account, mode, nonce); + + uint64 providedChainId = enableData.hashesAndChainIds[enableData.chainDigestIndex].chainId; + bytes32 providedHash = + enableData.hashesAndChainIds[enableData.chainDigestIndex].sessionDigest; + + if (providedChainId != block.chainid) { + revert ChainIdMismatch(providedChainId); + } + + // ensure digest we've built from the sessionToEnable is included into + // the list of digests that were signed + if (providedHash != computedHash) { + revert HashMismatch(providedHash, computedHash); + } + + digest = enableData.hashesAndChainIds.multichainDigest(); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/interfaces/IAccountModulesPaginated.sol b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/interfaces/IAccountModulesPaginated.sol new file mode 100644 index 0000000..1d9c50c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/interfaces/IAccountModulesPaginated.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +interface IAccountModulesPaginated { + function getValidatorsPaginated( + address, + uint256 + ) + external + view + returns (address[] memory, address); + + function getExecutorsPaginated( + address, + uint256 + ) + external + view + returns (address[] memory, address); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/ECDSA.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/ECDSA.sol new file mode 100644 index 0000000..28fbfad --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/utils/ECDSA.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Utils +import { sign as vmSign } from "./Vm.sol"; + +function ecdsaSign(uint256 privKey, bytes32 digest) pure returns (bytes memory signature) { + (uint8 v, bytes32 r, bytes32 s) = vmSign(privKey, digest); + return abi.encodePacked(r, s, v); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/ERC4337Helpers.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/ERC4337Helpers.sol new file mode 100644 index 0000000..b0c76f6 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/utils/ERC4337Helpers.sol @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { + PackedUserOperation, + IEntryPoint, + IEntryPointSimulations, + IStakeManager +} from "../../external/ERC4337.sol"; +import { ExecutionReturnData } from "../RhinestoneModuleKit.sol"; + +// Deployments +import { ENTRYPOINT_ADDR } from "../../deployment/predeploy/EntryPoint.sol"; + +// Utils +import "./Vm.sol"; +import "./Log.sol"; + +// Dependencies +import "./gas/GasCalculations.sol"; +import { GasParser } from "./gas/GasParser.sol"; +import { + getSimulateUserOp, + getExpectRevert, + getExpectRevertMessage, + clearExpectRevert, + getGasIdentifier, + writeGasIdentifier, + writeInstalledModule, + getInstalledModules, + removeInstalledModule, + InstalledModule +} from "./Storage.sol"; + +// External Dependencies +import { Simulator } from "erc4337-validation/Simulator.sol"; + +/// @notice A library that contains helper functions for ERC-4337 operations +library ERC4337Helpers { + using Simulator for PackedUserOperation; + + error UserOperationReverted( + bytes32 userOpHash, address sender, string senderLabel, uint256 nonce, bytes revertReason + ); + error InvalidRevertMessage(bytes4 expected, bytes4 reason); + error InvalidRevertMessageBytes(bytes expected, bytes reason); + + struct ExecutionContext { + uint256 isExpectRevert; + address payable beneficiary; + bytes userOpCalldata; + bool success; + bytes returnData; + } + + function exec4337( + PackedUserOperation[] memory userOps, + IEntryPoint onEntryPoint + ) + internal + returns (ExecutionReturnData memory executionData) + { + // Initialize execution context + ExecutionContext memory ctx = ExecutionContext({ + isExpectRevert: getExpectRevert(), + beneficiary: payable(address(0x69)), + userOpCalldata: "", + success: false, + returnData: "" + }); + + // Handle simulation + if (envOr("SIMULATE", false) || getSimulateUserOp()) { + bool simulationSuccess = userOps[0].simulateUserOp(address(onEntryPoint)); + if (ctx.isExpectRevert == 0) { + require(simulationSuccess, "UserOperation simulation failed"); + } + } + + // Record logs for revert detection + recordLogs(); + + // Prepare and execute userOps + ctx.userOpCalldata = abi.encodeCall(IEntryPoint.handleOps, (userOps, ctx.beneficiary)); + (ctx.success, ctx.returnData) = address(onEntryPoint).call(ctx.userOpCalldata); + + if (ctx.isExpectRevert == 0) { + require(ctx.success, "UserOperation execution failed"); + } else if (ctx.isExpectRevert == 2 && !ctx.success) { + checkRevertMessage(ctx.returnData); + } + + // Process logs + VmSafe.Log[] memory logs = getRecordedLogs(); + executionData = ExecutionReturnData(logs); + uint256 totalUserOpGas = 0; + + for (uint256 i; i < logs.length; i++) { + if ( + logs[i].topics[0] + == 0x49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f + ) { + (uint256 nonce, bool userOpSuccess,, uint256 actualGasUsed) = + abi.decode(logs[i].data, (uint256, bool, uint256, uint256)); + totalUserOpGas = actualGasUsed; + + if (!userOpSuccess) { + bytes32 userOpHash = logs[i].topics[1]; + if (ctx.isExpectRevert == 0) { + bytes memory revertReason = getUserOpRevertReason(logs, userOpHash); + address account = address(bytes20(logs[i].topics[2])); + revert UserOperationReverted( + userOpHash, account, getLabel(account), nonce, revertReason + ); + } else { + if (ctx.isExpectRevert == 2) { + checkRevertMessage(getUserOpRevertReason(logs, userOpHash)); + } + clearExpectRevert(); + } + } + } + // Handle module events + else if ( + logs[i].topics[0] + == 0xd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123 + ) { + (uint256 moduleType, address module) = abi.decode(logs[i].data, (uint256, address)); + writeInstalledModule(InstalledModule(moduleType, module), logs[i].emitter); + } else if ( + logs[i].topics[0] + == 0x341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e + ) { + (uint256 moduleType, address module) = abi.decode(logs[i].data, (uint256, address)); + InstalledModule[] memory installedModules = getInstalledModules(logs[i].emitter); + for (uint256 j; j < installedModules.length; j++) { + if ( + installedModules[j].moduleAddress == module + && installedModules[j].moduleType == moduleType + ) { + removeInstalledModule(j, logs[i].emitter); + break; + } + } + } + } + + // Handle gas calculations + string memory gasIdentifier = getGasIdentifier(); + if ( + envOr("GAS", false) && bytes(gasIdentifier).length > 0 + && bytes(gasIdentifier).length < 50 + ) { + calculateGas(userOps, onEntryPoint, ctx.beneficiary, gasIdentifier, totalUserOpGas); + } + + // Emit events + for (uint256 i; i < userOps.length; i++) { + emit ModuleKitLogs.ModuleKit_Exec4337(userOps[i].sender); + } + } + + // Original helper functions unchanged + function exec4337( + PackedUserOperation memory userOp, + IEntryPoint onEntryPoint + ) + internal + returns (ExecutionReturnData memory logs) + { + PackedUserOperation[] memory userOps = new PackedUserOperation[](1); + userOps[0] = userOp; + return exec4337(userOps, onEntryPoint); + } + + function getUserOpRevertReason( + VmSafe.Log[] memory logs, + bytes32 userOpHash + ) + internal + pure + returns (bytes memory revertReason) + { + for (uint256 i; i < logs.length; i++) { + if ( + logs[i].topics[0] + == 0x1c4fada7374c0a9ee8841fc38afe82932dc0f8e69012e927f061a8bae611a201 + && logs[i].topics[1] == userOpHash + ) { + (, revertReason) = abi.decode(logs[i].data, (uint256, bytes)); + } + } + } + + function checkRevertMessage(bytes memory actualReason) internal view { + bytes memory revertMessage = getExpectRevertMessage(); + if (actualReason.length >= 4) { + bytes4 actual = bytes4(actualReason); + bytes4 expected = bytes4(revertMessage); + if (actual == bytes4(0x65c8fd4d)) { + return parseFailedOpWithRevert(actualReason, revertMessage); + } else if (actual != expected) { + revert InvalidRevertMessageBytes(revertMessage, actualReason); + } + return; + } + if (revertMessage.length != actualReason.length) { + revert InvalidRevertMessageBytes(revertMessage, actualReason); + } + } + + function parseFailedOpWithRevert( + bytes memory actualReason, + bytes memory revertMessage + ) + internal + pure + { + uint256 bytesOffset; + assembly { + let ptr := add(actualReason, 0x20) + ptr := add(ptr, 0x04) + ptr := add(ptr, 0x40) + bytesOffset := mload(ptr) + } + + bytes memory actual; + assembly { + let ptr := add(actualReason, 0x20) + ptr := add(ptr, 0x04) + ptr := add(ptr, bytesOffset) + let innerLength := mload(ptr) + + actual := mload(0x40) + mstore(actual, innerLength) + + let srcPtr := add(ptr, 0x20) + let destPtr := add(actual, 0x20) + mstore(destPtr, mload(srcPtr)) + + mstore(0x40, add(add(actual, 0x20), innerLength)) + } + + if (revertMessage.length == 4) { + bytes4 expected = bytes4(revertMessage); + if (expected != bytes4(actual)) { + revert InvalidRevertMessage(expected, bytes4(actual)); + } + } else { + if (keccak256(actual) != keccak256(revertMessage)) { + revert InvalidRevertMessageBytes(revertMessage, actual); + } + } + } + + function calculateGas( + PackedUserOperation[] memory userOps, + IEntryPoint onEntryPoint, + address beneficiary, + string memory gasIdentifier, + uint256 totalUserOpGas + ) + internal + { + bytes memory userOpCalldata = + abi.encodeWithSelector(onEntryPoint.handleOps.selector, userOps, beneficiary); + GasParser.parseAndWriteGas( + userOpCalldata, address(onEntryPoint), gasIdentifier, userOps[0].sender, totalUserOpGas + ); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/Log.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/Log.sol new file mode 100644 index 0000000..080e769 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/utils/Log.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +library ModuleKitLogs { + /* solhint-disable event-name-camelcase */ + event ModuleKit_NewAccount(address account, string accountType); + event ModuleKit_Exec4337(address sender); + + event ModuleKit_AddExecutor(address account, address executor); + event ModuleKit_RemoveExecutor(address account, address executor); + + event ModuleKit_AddValidator(address account, address validator); + event ModuleKit_RemoveValidator(address account, address validator); + + event ModuleKit_SetFallback(address account, bytes4 functionSig, address handler); + + event ModuleKit_SetCondition(address account, address executor); + /* solhint-enable event-name-camelcase */ +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/Storage.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/Storage.sol new file mode 100644 index 0000000..945caaa --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/utils/Storage.sol @@ -0,0 +1,413 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/*////////////////////////////////////////////////////////////// + EXPECT REVERT +//////////////////////////////////////////////////////////////*/ + +function writeExpectRevert(bytes memory message) { + uint256 value = 1; + bytes32 slot = keccak256("ModuleKit.ExpectMessageSlot"); + + if (message.length > 0) { + value = 2; + assembly { + sstore(slot, message) + } + } + + slot = keccak256("ModuleKit.ExpectSlot"); + assembly { + sstore(slot, value) + } +} + +function getExpectRevert() view returns (uint256 value) { + bytes32 slot = keccak256("ModuleKit.ExpectSlot"); + assembly { + value := sload(slot) + } +} + +function getExpectRevertMessage() view returns (bytes memory data) { + bytes32 slot = keccak256("ModuleKit.ExpectMessageSlot"); + assembly { + data := sload(slot) + } +} + +function clearExpectRevert() { + bytes32 slot = keccak256("ModuleKit.ExpectSlot"); + assembly { + sstore(slot, 0) + } + + slot = keccak256("ModuleKit.ExpectMessageSlot"); + assembly { + sstore(slot, 0) + } +} + +/*////////////////////////////////////////////////////////////// + GAS IDENTIFIER +//////////////////////////////////////////////////////////////*/ + +function writeGasIdentifier(string memory id) { + bytes32 slot = keccak256("ModuleKit.GasIdentifierSlot"); + writeString(slot, id); +} + +function getGasIdentifier() view returns (string memory id) { + bytes32 slot = keccak256("ModuleKit.GasIdentifierSlot"); + id = readString(slot); +} + +/*////////////////////////////////////////////////////////////// + SIMULATE OP +//////////////////////////////////////////////////////////////*/ + +function writeSimulateUserOp(bool value) { + bytes32 slot = keccak256("ModuleKit.SimulateUserOp"); + assembly { + sstore(slot, value) + } +} + +function getSimulateUserOp() view returns (bool value) { + bytes32 slot = keccak256("ModuleKit.SimulateUserOp"); + assembly { + value := sload(slot) + } +} + +/*////////////////////////////////////////////////////////////// + STORAGE COMPLIANCE +//////////////////////////////////////////////////////////////*/ + +function writeStorageCompliance(bool value) { + bytes32 slot = keccak256("ModuleKit.StorageCompliance"); + assembly { + sstore(slot, value) + } +} + +function getStorageCompliance() view returns (bool value) { + bytes32 slot = keccak256("ModuleKit.StorageCompliance"); + assembly { + value := sload(slot) + } +} + +/*////////////////////////////////////////////////////////////// + ACCOUNT ENV +//////////////////////////////////////////////////////////////*/ + +function writeAccountEnv(string memory env, address factory, address helper) { + bytes32 envSlot = keccak256("ModuleKit.AccountTypeSlot"); + bytes32 factorySlot = keccak256("ModuleKit.AccountFactorySlot"); + bytes32 helperSlot = keccak256("ModuleKit.HelperSlot"); + bytes32 envHash = keccak256(abi.encodePacked(env)); + assembly { + sstore(envSlot, envHash) + sstore(factorySlot, factory) + sstore(helperSlot, helper) + } +} + +function getAccountEnv() view returns (bytes32 env, address factory, address helper) { + bytes32 envSlot = keccak256("ModuleKit.AccountTypeSlot"); + bytes32 factorySlot = keccak256("ModuleKit.AccountFactorySlot"); + bytes32 helperSlot = keccak256("ModuleKit.HelperSlot"); + assembly { + env := sload(envSlot) + factory := sload(factorySlot) + helper := sload(helperSlot) + } +} + +/*////////////////////////////////////////////////////////////// + ACCOUNT TYPE +//////////////////////////////////////////////////////////////*/ + +function writeAccountType(string memory accountType) { + bytes32 slot = keccak256("ModuleKit.AccountTypeSlot"); + bytes32 accountTypeHash = keccak256(abi.encodePacked(accountType)); + assembly { + sstore(slot, accountTypeHash) + } +} + +function getAccountType() view returns (bytes32 accountType) { + bytes32 slot = keccak256("ModuleKit.AccountTypeSlot"); + assembly { + accountType := sload(slot) + } +} + +/*////////////////////////////////////////////////////////////// + FACTORY +//////////////////////////////////////////////////////////////*/ + +function writeFactory(address factory, string memory factoryType) { + bytes32 slot = keccak256(abi.encode("ModuleKit.", factoryType, "FactorySlot")); + assembly { + sstore(slot, factory) + } +} + +function getFactory(string memory factoryType) view returns (address factory) { + bytes32 slot = keccak256(abi.encode("ModuleKit.", factoryType, "FactorySlot")); + assembly { + factory := sload(slot) + } +} + +/*////////////////////////////////////////////////////////////// + HELPER +//////////////////////////////////////////////////////////////*/ + +function writeHelper(address helper, string memory helperType) { + bytes32 slot = keccak256(abi.encode("ModuleKit.", helperType, "HelperSlot")); + assembly { + sstore(slot, helper) + } +} + +function getHelper(string memory helperType) view returns (address helper) { + bytes32 slot = keccak256(abi.encode("ModuleKit.", helperType, "HelperSlot")); + assembly { + helper := sload(slot) + } +} + +/*////////////////////////////////////////////////////////////// + INSTALLED MODULE +//////////////////////////////////////////////////////////////*/ + +struct InstalledModule { + uint256 moduleType; + address moduleAddress; +} + +// Adds new address to the installed module linked list for the given account +// The list is stored in storage as a linked list in the following format: +// --------------------------------------------------------------------- +// | Slot | Value | +// |----------------------------------------------------------|--------| +// | keccak256(abi.encode("ModuleKit.InstalledModuleSlot.")); | length | +// | keccak256(abi.encode("ModuleKit.InstalledModuleHead.")); | head | +// | keccak256(abi.encode("ModuleKit.InstalledModuleTail.")); | tail | +// | keccak256(abi.encode(lengthSlot)) - initially X | element| +// --------------------------------------------------------------------- +// +// The elements are stored in the following way: +// -------------------------- +// | Slot | Value | +// |------------------------| +// | X | moduleType | +// | X + 0x20 | moduleAddr | +// | X + 0x40 | prev | +// | X + 0x60 | next | +// -------------------------- +function writeInstalledModule(InstalledModule memory module, address account) { + bytes32 lengthSlot = keccak256( + abi.encode("ModuleKit.InstalledModuleSlot.", keccak256(abi.encodePacked(account))) + ); + bytes32 headSlot = keccak256( + abi.encode("ModuleKit.InstalledModuleHead.", keccak256(abi.encodePacked(account))) + ); + bytes32 tailSlot = + keccak256(abi.encode("ModuleKit.InstalledModuleTail", keccak256(abi.encodePacked(account)))); + bytes32 elementSlot = keccak256(abi.encode(lengthSlot)); + uint256 moduleType = module.moduleType; + address moduleAddress = module.moduleAddress; + assembly { + // Get the length of the array + let length := sload(lengthSlot) + let nextSlot + let oldTail + switch iszero(length) + case 1 { + // If length is zero, set element slot to head and tail + sstore(headSlot, elementSlot) + sstore(tailSlot, elementSlot) + oldTail := elementSlot + nextSlot := elementSlot + } + default { + oldTail := sload(tailSlot) + // Set the new elemeont slot to the old tail + 0x80 + elementSlot := add(oldTail, 0x80) + // Set the old tail next slot to the new element slot + sstore(add(oldTail, 0x60), elementSlot) + // Update tailSlot to point to the new element slot + sstore(tailSlot, elementSlot) + // Set nextSlot to the head slot + nextSlot := sload(headSlot) + } + // Update the length of the list + sstore(lengthSlot, add(length, 1)) + // Store the module type and address in the new slot + sstore(elementSlot, moduleType) + sstore(add(elementSlot, 0x20), moduleAddress) + // Store the old tail as the prev slot + sstore(add(elementSlot, 0x40), oldTail) + // Store the head as the next slot + sstore(add(elementSlot, 0x60), nextSlot) + } +} + +// Removes a specific installed module +function removeInstalledModule(uint256 index, address account) { + bytes32 lengthSlot = keccak256( + abi.encode("ModuleKit.InstalledModuleSlot.", keccak256(abi.encodePacked(account))) + ); + bytes32 headSlot = keccak256( + abi.encode("ModuleKit.InstalledModuleHead.", keccak256(abi.encodePacked(account))) + ); + bytes32 tailSlot = keccak256( + abi.encode("ModuleKit.InstalledModuleTail.", keccak256(abi.encodePacked(account))) + ); + assembly { + // Get the length of the list + let length := sload(lengthSlot) + // Get the initial element slot + let elementSlot := sload(headSlot) + // Ensure the index is within bounds + if lt(index, length) { + // Traverse to the node to remove + for { let i := 0 } lt(i, index) { i := add(i, 1) } { + elementSlot := sload(add(elementSlot, 0x60)) + } + + // Get the previous and next slots + let prevSlot := sload(add(elementSlot, 0x40)) + let nextSlot := sload(add(elementSlot, 0x60)) + + // Update the previous slot's next pointer + sstore(add(prevSlot, 0x60), nextSlot) + // Update the next slot's previous pointer + sstore(add(nextSlot, 0x40), prevSlot) + + // Handle removing the head + if eq(elementSlot, sload(headSlot)) { sstore(headSlot, nextSlot) } + + // Handle removing the tail + if eq(elementSlot, sload(tailSlot)) { sstore(tailSlot, prevSlot) } + + // Clear the removed node + sstore(elementSlot, 0) + sstore(add(elementSlot, 0x20), 0) + sstore(add(elementSlot, 0x40), 0) + sstore(add(elementSlot, 0x60), 0) + + // Update the length of the list + sstore(lengthSlot, sub(length, 1)) + } + } +} + +// Returns all installed modules for the given account +function getInstalledModules(address account) view returns (InstalledModule[] memory modules) { + bytes32 lengthSlot = keccak256( + abi.encode("ModuleKit.InstalledModuleSlot.", keccak256(abi.encodePacked(account))) + ); + bytes32 headSlot = keccak256( + abi.encode("ModuleKit.InstalledModuleHead.", keccak256(abi.encodePacked(account))) + ); + assembly { + // Get the length of the array from storage + let length := sload(lengthSlot) + + // Each struct is 64 bytes (32 bytes for moduleType and 32 bytes for moduleAddress) + let structSize := 0x40 // 64 bytes + let size := mul(length, structSize) // Total size for structs + let totalSize := add(add(size, 0x40), mul(0x20, length)) + + // Allocate memory for the array + let freeMemoryPtr := mload(0x40) + modules := freeMemoryPtr + + // Store the length of the array in the first 32 bytes of memory + mstore(modules, length) + + // Update the free memory pointer to the end of the allocated memory + mstore(0x40, add(freeMemoryPtr, totalSize)) + + // Get the head of the linked list + let storageLocation := sload(headSlot) + + // Copy the structs from storage to memory + for { let i := 0 } lt(i, length) { i := add(i, 1) } { + // Calculate memory location for this struct + let structLocation := + add(add(freeMemoryPtr, add(0x40, mul(i, structSize))), mul(0x20, length)) + + // Load the moduleType and moduleAddress from storage + let moduleType := sload(storageLocation) + let moduleAddress := sload(add(storageLocation, 0x20)) + + // Store the structLocation into memory + mstore(add(freeMemoryPtr, add(0x20, mul(i, 0x20))), structLocation) + + // Store the moduleType and moduleAddress into memory + mstore(structLocation, moduleType) + mstore(add(structLocation, 0x20), moduleAddress) + + // Move to the next element in the linked list + storageLocation := sload(add(storageLocation, 0x60)) + } + } +} + +/*////////////////////////////////////////////////////////////// + STRING STORAGE +//////////////////////////////////////////////////////////////*/ + +function writeString(bytes32 slot, string memory value) { + bytes memory strBytes = bytes(value); + uint256 length = strBytes.length; + + // Store the length of the string at the initial slot + assembly { + sstore(slot, length) + } + + // Store the actual string bytes in packed form + for (uint256 i = 0; i < length; i += 32) { + bytes32 data; + for (uint256 j = 0; j < 32 && i + j < length; j++) { + data |= bytes32(uint256(uint8(strBytes[i + j])) << (248 - j * 8)); + } + bytes32 charSlot = keccak256(abi.encodePacked(slot, i / 32)); + assembly { + sstore(charSlot, data) + } + } +} + +function readString(bytes32 slot) view returns (string memory) { + uint256 length; + + // Load the length of the string from the initial slot + assembly { + length := sload(slot) + } + + // Allocate memory for the string bytes + bytes memory strBytes = new bytes(length); + + // Load the actual string bytes from storage in packed form + for (uint256 i = 0; i < length; i += 32) { + bytes32 charSlot = keccak256(abi.encodePacked(slot, i / 32)); + bytes32 data; + assembly { + data := sload(charSlot) + } + for (uint256 j = 0; j < 32 && i + j < length; j++) { + strBytes[i + j] = bytes1(uint8(uint256(data >> (248 - j * 8)))); + } + } + + return string(strBytes); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/Vm.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/Vm.sol new file mode 100644 index 0000000..ac2251c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/utils/Vm.sol @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +import { Vm, VmSafe } from "forge-std/Vm.sol"; + +address constant VM_ADDR = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D; + +function makeAddrAndKey(string memory name) returns (address addr, uint256 privateKey) { + privateKey = uint256(keccak256(abi.encodePacked(name))); + addr = Vm(VM_ADDR).addr(privateKey); + Vm(VM_ADDR).label(addr, name); +} + +function makeAddr(string memory name) pure returns (address addr) { + uint256 privateKey = uint256(keccak256(abi.encodePacked(name))); + addr = Vm(VM_ADDR).addr(privateKey); + // Vm(VM_ADDR).label(addr, name); +} + +function getAddr(uint256 pk) pure returns (address) { + return Vm(VM_ADDR).addr(pk); +} + +function sign(uint256 pk, bytes32 msgHash) pure returns (uint8 v, bytes32 r, bytes32 s) { + return Vm(VM_ADDR).sign(pk, msgHash); +} + +function etch(address target, bytes memory runtimeBytecode) { + Vm(VM_ADDR).etch(target, runtimeBytecode); +} + +function label(address _addr, string memory _label) { + Vm(VM_ADDR).label(_addr, _label); +} + +function getLabel(address addr) view returns (string memory) { + return Vm(VM_ADDR).getLabel(addr); +} + +function deal(address _addr, uint256 amount) { + Vm(VM_ADDR).deal(_addr, amount); +} + +function expectEmit() { + Vm(VM_ADDR).expectEmit(); +} + +function expectRevert() { + Vm(VM_ADDR).expectRevert(); +} + +function expectRevert(bytes4 message) { + Vm(VM_ADDR).expectRevert(message); +} + +function recordLogs() { + Vm(VM_ADDR).recordLogs(); +} + +function getRecordedLogs() returns (VmSafe.Log[] memory) { + return Vm(VM_ADDR).getRecordedLogs(); +} + +function prank(address _addr) { + Vm(VM_ADDR).prank(_addr); +} + +function startPrank(address _addr) { + Vm(VM_ADDR).startPrank(_addr); +} + +function stopPrank() { + Vm(VM_ADDR).stopPrank(); +} + +function accesses(address _addr) returns (bytes32[] memory, bytes32[] memory) { + return Vm(VM_ADDR).accesses(_addr); +} + +function store(address account, bytes32 key, bytes32 entry) { + Vm(VM_ADDR).store(account, key, entry); +} + +function record() { + Vm(VM_ADDR).record(); +} + +function load(address account, bytes32 key) view returns (bytes32) { + return Vm(VM_ADDR).load(account, key); +} + +function snapshot() returns (uint256) { + return Vm(VM_ADDR).snapshotState(); +} + +function revertTo(uint256 id) returns (bool) { + return Vm(VM_ADDR).revertToState(id); +} + +function startStateDiffRecording() { + Vm(VM_ADDR).startStateDiffRecording(); +} + +function stopAndReturnStateDiff() returns (VmSafe.AccountAccess[] memory) { + return Vm(VM_ADDR).stopAndReturnStateDiff(); +} + +function envOr(string memory name, string memory defaultValue) view returns (string memory value) { + return Vm(VM_ADDR).envOr(name, defaultValue); +} + +function envOr(string memory name, bool defaultValue) view returns (bool value) { + return Vm(VM_ADDR).envOr(name, defaultValue); +} + +function setEnv(string memory key, string memory value) { + Vm(VM_ADDR).setEnv(key, value); +} + +function envBool(string memory key) view returns (bool value) { + return Vm(VM_ADDR).envBool(key); +} + +function serializeUint( + string memory objectKey, + string memory valueKey, + uint256 value +) + returns (string memory json) +{ + return Vm(VM_ADDR).serializeUint(objectKey, valueKey, value); +} + +function serializeString( + string memory objectKey, + string memory valueKey, + string memory value +) + returns (string memory json) +{ + return Vm(VM_ADDR).serializeString(objectKey, valueKey, value); +} + +function writeJson(string memory json, string memory path) { + Vm(VM_ADDR).writeJson(json, path); +} + +function readFile(string memory path) view returns (string memory) { + return Vm(VM_ADDR).readFile(path); +} + +function exists(string memory path) view returns (bool) { + return Vm(VM_ADDR).exists(path); +} + +function toString(uint256 input) pure returns (string memory) { + return Vm(VM_ADDR).toString(input); +} + +function toString(int256 input) pure returns (string memory) { + return Vm(VM_ADDR).toString(input); +} + +function toString(bytes memory input) pure returns (string memory) { + return Vm(VM_ADDR).toString(input); +} + +function toString(bytes32 input) pure returns (string memory) { + bytes memory _bytes = new bytes(32); + for (uint256 i = 0; i < 32; i++) { + _bytes[i] = input[i]; + } + return string(_bytes); +} + +function parseJson(string memory json, string memory key) pure returns (bytes memory) { + return Vm(VM_ADDR).parseJson(json, key); +} + +function parseJson(string memory json) pure returns (bytes memory) { + return Vm(VM_ADDR).parseJson(json); +} + +function parseJsonKeys(string memory json, string memory key) pure returns (string[] memory keys) { + return Vm(VM_ADDR).parseJsonKeys(json, key); +} + +function parseUint(string memory stringifiedValue) pure returns (uint256 parsedValue) { + return Vm(VM_ADDR).parseUint(stringifiedValue); +} + +function startMappingRecording() { + Vm(VM_ADDR).startMappingRecording(); +} + +function stopMappingRecording() { + Vm(VM_ADDR).stopMappingRecording(); +} + +function getMappingKeyAndParentOf(address target, bytes32 slot) returns (bool, bytes32, bytes32) { + return Vm(VM_ADDR).getMappingKeyAndParentOf(target, slot); +} + +function getMappingSlotAt(address target, bytes32 slot, uint256 idx) returns (bytes32) { + return Vm(VM_ADDR).getMappingSlotAt(target, slot, idx); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasCalculations.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasCalculations.sol new file mode 100644 index 0000000..f5a0bf1 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasCalculations.sol @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// External Dependencies +import { UD60x18, ud, intoUint256 } from "@prb/math/UD60x18.sol"; +import { PRBMathCastingUint256 } from "@prb/math/casting/Uint256.sol"; +import { LibZip } from "solady/utils/LibZip.sol"; + +// Utils +import { parseJson, toString } from "../Vm.sol"; + +/// @title GasCalculations +/// @dev This contract is used for calculating gas consumption in different phases of a transaction. +struct GasCalculations { + uint256 creation; + uint256 validation; + uint256 execution; + uint256 total; + uint256 arbitrum; + uint256 opStack; +} + +/// @notice Calculate the gas cost of calldata. +/// @param data The calldata to be sent. +/// @return calldataGas The gas cost of the calldata. +function getCallDataGas(bytes memory data) pure returns (uint256 calldataGas) { + for (uint256 i = 0; i < data.length; i++) { + if (data[i] == 0x00) { + calldataGas += 4; + } else { + calldataGas += 16; + } + } +} + +/// @notice Calculate the gas cost of calldata on Arbitrum L1. +/// @param data The calldata to be sent. +/// @return calldataGas The gas cost of the calldata on Arbitrum L1. +function getArbitrumL1Gas(bytes memory data) pure returns (uint256 calldataGas) { + bytes memory compressed = LibZip.flzCompress(data); + calldataGas = getCallDataGas(compressed); +} + +/// @notice Calculate the gas cost of calldata on OpStack L1. +/// @param data The calldata to be sent. +/// @return calldataGas The gas cost of the calldata on OpStack L1. +function getOpStackL1Gas(bytes memory data) pure returns (uint256 calldataGas) { + uint256 opStackConstant = 2028; + UD60x18 opStackScalar = ud(0.684e18); + + calldataGas = intoUint256( + PRBMathCastingUint256.intoUD60x18(getCallDataGas(data)).mul(opStackScalar) + ) + opStackConstant; +} + +/// @notice Parse the previous gas report from a file. +/// @param fileContent The content of the file. +/// @return prevGasCalculations The previous gas calculations. +function parsePrevGasReport(string memory fileContent) + pure + returns (GasCalculations memory prevGasCalculations) +{ + prevGasCalculations.total = parseUintFromASCII(parseJson(fileContent, ".Total")); + prevGasCalculations.creation = parseUintFromASCII(parseJson(fileContent, ".Phases.Creation")); + prevGasCalculations.validation = + parseUintFromASCII(parseJson(fileContent, ".Phases.Validation")); + prevGasCalculations.execution = parseUintFromASCII(parseJson(fileContent, ".Phases.Execution")); + prevGasCalculations.arbitrum = parseUintFromASCII(parseJson(fileContent, ".Calldata.Arbitrum")); + prevGasCalculations.opStack = parseUintFromASCII(parseJson(fileContent, ".Calldata.OP-Stack")); +} + +/// @notice Parse a uint256 from ASCII. +/// @param ascii The ASCII to be parsed. +/// @return _ret The parsed uint256. +function parseUintFromASCII(bytes memory ascii) pure returns (uint256 _ret) { + bytes memory prevTotal; + uint256 offset = ascii.length > 32 ? 32 : 0; + for (uint256 i; i < ascii.length; i++) { + if (ascii[i] == 0x28) { + break; + } else { + if (i >= offset) { + prevTotal = abi.encodePacked(prevTotal, ascii[i]); + } + } + } + uint256 j = 1; + for (uint256 i = prevTotal.length - 1; i > 0; i--) { + if (uint8(prevTotal[i]) >= 48 && uint8(prevTotal[i]) <= 57) { + _ret += (uint8(prevTotal[i]) - 48) * j; + j *= 10; + } + } +} + +/// @notice Format the gas value. +/// @param prevValue The previous gas value. +/// @param newValue The new gas value. +/// @return formattedValue The formatted gas value. +function formatGasValue( + uint256 prevValue, + uint256 newValue +) + pure + returns (string memory formattedValue) +{ + if (prevValue == 0) { + formattedValue = string.concat(formatGas(int256(newValue)), " gas"); + } else { + formattedValue = string.concat( + formatGas(int256(newValue)), + " gas (diff: ", + formatGas(int256(newValue) - int256(prevValue)), + ")" + ); + } +} + +/// @notice Format the gas value with underscores for readability. +/// @param value The gas value to be formatted. +/// @return The formatted gas value. +function formatGas(int256 value) pure returns (string memory) { + string memory str = toString(value); + bytes memory bStr = bytes(str); + bytes memory result = new bytes(bStr.length + (bStr.length - 1) / 3); + + uint256 j = result.length; + for (uint256 i = 0; i < bStr.length; i++) { + if (i > 0 && i % 3 == 0) { + result[--j] = "_"; + } + result[--j] = bStr[bStr.length - i - 1]; + } + + return string(result); +} + +interface GasDebug { + function getGasConsumed(address account, uint256 phase) external view returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasParser.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasParser.sol new file mode 100644 index 0000000..5f5b6b1 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasParser.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Utils +import "../Vm.sol"; +import "../Log.sol"; + +// Dependencies +import "./GasCalculations.sol"; +import { writeGasIdentifier } from "../Storage.sol"; + +library GasParser { + function parseAndWriteGas( + bytes memory userOpCalldata, + address entrypoint, + string memory gasIdentifier, + address sender, + uint256 totalUserOpGas + ) + internal + { + string memory fileName = string.concat("./gas_calculations/", gasIdentifier, ".json"); + + GasCalculations memory gasCalculations = GasCalculations({ + creation: GasDebug(entrypoint).getGasConsumed(sender, 0), + validation: GasDebug(entrypoint).getGasConsumed(sender, 1), + execution: GasDebug(entrypoint).getGasConsumed(sender, 2), + total: totalUserOpGas, + arbitrum: getArbitrumL1Gas(userOpCalldata), + opStack: getOpStackL1Gas(userOpCalldata) + }); + + GasCalculations memory prevGasCalculations; + + if (exists(fileName)) { + string memory fileContent = readFile(fileName); + prevGasCalculations = parsePrevGasReport(fileContent); + } + + string memory finalJson = + formatGasToWrite(gasIdentifier, prevGasCalculations, gasCalculations); + + writeJson(finalJson, fileName); + writeGasIdentifier(""); + } + + function formatGasToWrite( + string memory gasIdentifier, + GasCalculations memory prevGasCalculations, + GasCalculations memory gasCalculations + ) + internal + returns (string memory finalJson) + { + string memory jsonObj = string(abi.encodePacked(gasIdentifier)); + + // total gas used + serializeString( + jsonObj, + "Total", + formatGasValue({ prevValue: prevGasCalculations.total, newValue: gasCalculations.total }) + ); + + // ERC-4337 phases gas used + string memory phasesObj = "phases"; + serializeString( + phasesObj, + "Creation", + formatGasValue({ + prevValue: prevGasCalculations.creation, + newValue: gasCalculations.creation + }) + ); + serializeString( + phasesObj, + "Validation", + formatGasValue({ + prevValue: prevGasCalculations.validation, + newValue: gasCalculations.validation + }) + ); + string memory phasesOutput = serializeString( + phasesObj, + "Execution", + formatGasValue({ + prevValue: prevGasCalculations.execution, + newValue: gasCalculations.execution + }) + ); + + // L2-L1 calldata gas used + string memory l2sObj = "l2s"; + serializeString( + l2sObj, + "OP-Stack", + formatGasValue({ + prevValue: prevGasCalculations.opStack, + newValue: gasCalculations.opStack + }) + ); + string memory l2sOutput = serializeString( + l2sObj, + "Arbitrum", + formatGasValue({ + prevValue: prevGasCalculations.arbitrum, + newValue: gasCalculations.arbitrum + }) + ); + + serializeString(jsonObj, "Phases", phasesOutput); + finalJson = serializeString(jsonObj, "Calldata", l2sOutput); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/UserOpGasLog.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/UserOpGasLog.sol new file mode 100644 index 0000000..7da0b60 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/UserOpGasLog.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Types +import { + PackedUserOperation, + EntryPointSimulations, + IEntryPointSimulations +} from "src/external/ERC4337.sol"; + +// Utils +import "../Log.sol"; + +contract UserOpGasLog { + EntryPointSimulations public immutable simulation = new EntryPointSimulations(); + + struct GasLog { + uint256 gasValidation; + uint256 gasExecution; + } + + mapping(bytes32 userOpHash => GasLog log) internal _log; + + function getLog(bytes32 userOpHash) + external + view + returns (uint256 gasValidation, uint256 gasExecution) + { + GasLog memory log = _log[userOpHash]; + return (log.gasValidation, log.gasExecution); + } + + function calcValidationGas( + PackedUserOperation memory userOp, + bytes32 userOpHash, + address, /* sender */ + bytes memory /* initCode */ + ) + external + returns (uint256 gasValidation) + { + IEntryPointSimulations.ValidationResult memory validationResult = + simulation.simulateValidation(userOp); + + gasValidation = validationResult.returnInfo.preOpGas; + + _log[userOpHash].gasValidation = gasValidation; + } + + function calcExecutionGas( + PackedUserOperation memory userOp, + bytes32 userOpHash, + address sender, + bytes memory initCode + ) + external + returns (uint256 gasExecution) + { + IEntryPointSimulations.ExecutionResult memory executionResult = + simulation.simulateHandleOp(userOp, sender, initCode); + + gasExecution = executionResult.paid; + // gasValidation = executionResult.gasUsedInValidation; + + // _log[userOpHash].gasValidation = executionResult.gasUsedInValidation; + _log[userOpHash].gasExecution = gasExecution; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/test/BaseTest.t.sol b/typescript/packages/account-modules/lib/modulekit/test/BaseTest.t.sol new file mode 100644 index 0000000..fdb307d --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/test/BaseTest.t.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +import "forge-std/Test.sol"; +import "src/ModuleKit.sol"; +import "src/Accounts.sol"; +import "src/Mocks.sol"; +import { Execution } from "src/accounts/erc7579/lib/ExecutionLib.sol"; + +contract BaseTest is RhinestoneModuleKit, Test { + using ModuleKitHelpers for AccountInstance; + + AccountInstance internal instance; + AccountInstance internal instanceSafe; + + address recipient; + + function setUp() public virtual { + instance = makeAccountInstance("account1"); + + // MockValidator defaultValidator = new MockValidator(); + // MockExecutor defaultExecutor = new MockExecutor(); + vm.deal(instanceSafe.account, 1000 ether); + vm.deal(instance.account, 2 ether); + + recipient = makeAddr("recipient"); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/test/Diff.t.sol b/typescript/packages/account-modules/lib/modulekit/test/Diff.t.sol new file mode 100644 index 0000000..f66e88a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/test/Diff.t.sol @@ -0,0 +1,910 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +import "src/ModuleKit.sol"; +import "./BaseTest.t.sol"; +import "src/Mocks.sol"; +import { ExecutionReturnData } from "src/test/RhinestoneModuleKit.sol"; +import { + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_HOOK, + MODULE_TYPE_FALLBACK, + VALIDATION_SUCCESS, + VALIDATION_FAILED +} from "src/accounts/common/interfaces/IERC7579Module.sol"; +import { CALLTYPE_SINGLE } from "src/accounts/common/lib/ModeLib.sol"; +import { getAccountType, InstalledModule } from "src/test/utils/Storage.sol"; +import { toString } from "src/test/utils/Vm.sol"; +import { MockValidatorFalse } from "test/mocks/MockValidatorFalse.sol"; +import { MockK1Validator, VALIDATION_SUCCESS } from "test/mocks/MockK1Validator.sol"; +import { MockK1ValidatorUncompliantUninstall } from + "test/mocks/MockK1ValidatorUncompliantUninstall.sol"; +import { VmSafe } from "src/test/utils/Vm.sol"; +import { IAccountFactory } from "src/accounts/factory/interface/IAccountFactory.sol"; + +contract ERC7579DifferentialModuleKitLibTest is BaseTest { + using ModuleKitHelpers for *; + + MockValidator internal validator; + MockValidatorFalse internal validatorFalse; + MockExecutor internal executor; + MockFallback internal fallbackHandler; + MockHook internal hook; + MockTarget internal mockTarget; + + MockERC20 internal token; + address module; + + function setUp() public override { + super.setUp(); + // Setup account + instance = makeAccountInstance("account1"); + + // Setup modules + validator = new MockValidator(); + validatorFalse = new MockValidatorFalse(); + hook = new MockHook(); + executor = new MockExecutor(); + fallbackHandler = new MockFallback(); + mockTarget = new MockTarget(); + + // Setup aux + token = new MockERC20(); + token.initialize("Mock Token", "MTK", 18); + deal(address(token), instance.account, 100 ether); + vm.deal(instance.account, 1000 ether); + instance.simulateUserOp(false); + } + + function test_transfer() public { + UserOpData memory data = instance.exec({ target: recipient, value: 1 ether, callData: "" }); + assertTrue(data.userOpHash != ""); + assertTrue(recipient.balance == 1 ether); + assertTrue(data.userOp.sender == instance.account); + } + + /*////////////////////////////////////////////////////////////////////////// + make instance + //////////////////////////////////////////////////////////////////////////*/ + + function test_makeAccountInstance() public { + AccountInstance memory newInstance = makeAccountInstance("newSalt"); + assertTrue(newInstance.account.code.length == 0); + newInstance.deployAccount(); + assertTrue(newInstance.account.code.length > 0); + } + + function test_makeAccountInstance_withModules() public { + AccountType env = ModuleKitHelpers.getAccountType(); + // AccountInstance memory newInstance = makeAccountInstance("newSalt"); + // assertTrue(newInstance.account.code.length == 0); + // newInstance.deployAccount(); + // assertTrue(newInstance.account.code.length > 0); + // Deploy executors, validators, hooks and fallbacks and setup ModuleInit data + IAccountFactory.ModuleInitData[] memory validators = new IAccountFactory.ModuleInitData[](1); + validators[0] = + IAccountFactory.ModuleInitData({ module: address(validator), data: abi.encode(0x123) }); + IAccountFactory.ModuleInitData[] memory executors = new IAccountFactory.ModuleInitData[](1); + executors[0] = IAccountFactory.ModuleInitData({ + module: address(executor), + data: env == AccountType.KERNEL ? abi.encodePacked(bytes20(0)) : abi.encodePacked("") + }); + IAccountFactory.ModuleInitData memory _hook = IAccountFactory.ModuleInitData({ + module: address(hook), + data: env == AccountType.SAFE + ? abi.encode(bytes1(0), bytes4(0), abi.encode(0x123)) + : abi.encode(0x123) + }); + IAccountFactory.ModuleInitData[] memory fallbacks = new IAccountFactory.ModuleInitData[](1); + fallbacks[0] = IAccountFactory.ModuleInitData({ + module: address(fallbackHandler), + data: env == AccountType.KERNEL + ? abi.encodePacked( + bytes4(0), + bytes20(0), + abi.encode(abi.encodePacked(hex"00", "fallbackData"), abi.encodePacked("")) + ) + : env == AccountType.SAFE || env == AccountType.NEXUS + ? abi.encode(bytes4(0x12345678), bytes1(0), abi.encode(0x123)) + : abi.encode(0x123) + }); + // Create account instance + AccountInstance memory newInstance2 = makeAccountInstance({ + salt: "newSalt2", + validators: validators, + executors: executors, + hook: _hook, + fallbacks: fallbacks + }); + assertTrue(newInstance2.account.code.length == 0); + newInstance2.deployAccount(); + assertTrue(newInstance2.account.code.length > 0); + } + + /*////////////////////////////////////////////////////////////////////////// + exec + //////////////////////////////////////////////////////////////////////////*/ + + function testexec__Given__TwoInputs() public { + // Create userOperation fields + address receiver = makeAddr("receiver"); + uint256 value = 10 gwei; + bytes memory callData = + abi.encodeWithSignature("transfer(address,uint256)", receiver, value); + + // Create userOperation + instance.exec({ target: address(token), callData: callData }); + + // Validate userOperation + assertEq(token.balanceOf(receiver), value, "Receiver should have 10 gwei in tokens"); + } + + function testexec__Given__ThreeInputs() public { + // Create userOperation fields + address receiver = makeAddr("receiver"); + uint256 value = 10 gwei; + bytes memory callData = ""; + + // Create userOperation + instance.exec({ target: receiver, value: value, callData: callData }); + + // Validate userOperation + assertEq(receiver.balance, value, "Receiver should have 10 gwei"); + } + + function testexec__Given__FourInputs() public { + // Create userOperation fields + address receiver = makeAddr("receiver"); + uint256 value = 10 gwei; + bytes memory callData = ""; + // bytes memory signature = ""; + + // Create userOperation + ExecutionReturnData memory executionData = instance.getExecOps({ + target: receiver, + value: value, + callData: callData, + txValidator: address(instance.defaultValidator) + }).execUserOps(); + + // Validate Logs + assertTrue(executionData.logs.length >= 5); + + // Validate userOperation + assertEq(receiver.balance, value, "Receiver should have 10 gwei"); + } + + function testexec__RevertWhen__ValidationFails() public { + // No revert reason + _revertWhen__ValidationFails(""); + + // Revert selector + _revertWhen__ValidationFails(abi.encodePacked(bytes4(0x220266b6))); + + // Revert message + _revertWhen__ValidationFails( + abi.encodeWithSignature("FailedOp(uint256,string)", 0, "AA24 signature error") + ); + } + + function testexec__RevertWhen__ValidationReverts() public { + // No revert reason + _revertWhen__ValidationReverts(""); + + // Revert message + bytes memory revertMessage; + + AccountType env = ModuleKitHelpers.getAccountType(); + + // Revert selector + _revertWhen__ValidationReverts( + abi.encodePacked(bytes4(env == AccountType.SAFE ? 0xacfdb444 : 0x0)) + ); + + if (env == AccountType.SAFE) { + revertMessage = abi.encodePacked(bytes4(0xacfdb444)); + } else { + revertMessage = abi.encodePacked(bytes4(0x0)); + } + + _revertWhen__ValidationReverts(revertMessage); + } + + function testexec__RevertWhen__UserOperationFails() public { + // Deploy the account first + testexec__Given__TwoInputs(); + + // No revert reason + _revertWhen__UserOperationFails(""); + + bytes memory revertSelector; + bytes memory revertMessage; + + AccountType env = ModuleKitHelpers.getAccountType(); + if (env == AccountType.SAFE) { + revertSelector = abi.encodePacked(bytes4(0xacfdb444)); + revertMessage = abi.encodePacked(bytes4(0xacfdb444)); + } else if (env == AccountType.KERNEL) { + revertSelector = abi.encodePacked(bytes4(0xf21e646b)); + revertMessage = abi.encodePacked(bytes4(0xf21e646b)); + } else { + revertSelector = abi.encodePacked(bytes4(0x82b42900)); + revertMessage = abi.encodePacked(bytes4(0x82b42900)); + } + + // Revert selector + _revertWhen__UserOperationFails(revertSelector); + + // Revert message + _revertWhen__UserOperationFails(revertMessage); + } + + /*////////////////////////////////////////////////////////////////////////// + MODULES + //////////////////////////////////////////////////////////////////////////*/ + + function testAddValidator() public { + address newValidator = address(new MockValidator()); + address newValidator1 = address(new MockValidator()); + vm.label(newValidator, "2nd validator"); + + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: newValidator, + data: "" + }); + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: newValidator1, + data: "" + }); + + bool validatorEnabled = instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, newValidator); + assertTrue(validatorEnabled); + bool validator1Enabled = instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, newValidator1); + assertTrue(validator1Enabled); + } + + function test_getInstalledModules() public whenEnvIsNotKernel { + address newValidator = address(new MockValidator()); + address newValidator1 = address(new MockValidator()); + vm.label(newValidator, "2nd validator"); + + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: newValidator, + data: "" + }); + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: newValidator1, + data: "" + }); + + // Assert installed modules + this._getModulesAndAssert( + abi.encode( + 2, [newValidator, newValidator1], [MODULE_TYPE_VALIDATOR, MODULE_TYPE_VALIDATOR] + ), + instance + ); + + address newExecutor = address(new MockExecutor()); + instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: newExecutor, data: "" }); + + // Assert installed modules + this._getModulesAndAssert( + abi.encode( + 3, + [newValidator, newValidator1, newExecutor], + [MODULE_TYPE_VALIDATOR, MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR] + ), + instance + ); + } + + function test_getInstalledModules_DifferentInstances() public whenEnvIsNotKernel { + address newValidator = address(new MockValidator()); + address newValidator1 = address(new MockValidator()); + vm.label(newValidator, "2nd validator"); + + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: newValidator, + data: "" + }); + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: newValidator1, + data: "" + }); + + // Assert installed modules + this._getModulesAndAssert( + abi.encode( + 2, [newValidator, newValidator1], [MODULE_TYPE_VALIDATOR, MODULE_TYPE_VALIDATOR] + ), + instance + ); + + address newExecutor = address(new MockExecutor()); + instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: newExecutor, data: "" }); + + // Assert installed modules + this._getModulesAndAssert( + abi.encode( + 3, + [newValidator, newValidator1, newExecutor], + [MODULE_TYPE_VALIDATOR, MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR] + ), + instance + ); + + // Deploy new instance using current env + AccountInstance memory newInstance = makeAccountInstance("newSalt"); + assertTrue(newInstance.account.code.length == 0); + newInstance.deployAccount(); + assertTrue(newInstance.account.code.length > 0); + + // Install modules on new instance + newInstance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: newValidator, + data: "" + }); + newInstance.installModule({ + moduleTypeId: MODULE_TYPE_EXECUTOR, + module: newExecutor, + data: "" + }); + + // Assert installed modules on new instance + this._getModulesAndAssert( + abi.encode( + 2, [newValidator, newExecutor], [MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR] + ), + newInstance + ); + + // Old instance modules should still be the same + this._getModulesAndAssert( + abi.encode( + 3, + [newValidator, newValidator1, newExecutor], + [MODULE_TYPE_VALIDATOR, MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR] + ), + instance + ); + } + + function test_getInstalledModules_AfterUninstall() public whenEnvIsNotKernel { + address newValidator = address(new MockValidator()); + address newValidator1 = address(new MockValidator()); + vm.label(newValidator, "2nd validator"); + + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: newValidator, + data: "" + }); + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: newValidator1, + data: "" + }); + + // Assert installed modules + this._getModulesAndAssert( + abi.encode( + 2, [newValidator, newValidator1], [MODULE_TYPE_VALIDATOR, MODULE_TYPE_VALIDATOR] + ), + instance + ); + + address newExecutor = address(new MockExecutor()); + instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: newExecutor, data: "" }); + + // Assert installed modules + this._getModulesAndAssert( + abi.encode( + 3, // length + [newValidator, newValidator1, newExecutor], // expectedAddresses + [MODULE_TYPE_VALIDATOR, MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR] // expectedTypes + ), + instance + ); + + // Uninstall module + instance.uninstallModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: newValidator, + data: "" + }); + + // Assert installed modules + this._getModulesAndAssert( + abi.encode( + 2, [newValidator1, newExecutor], [MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR] + ), + instance + ); + } + + function testRemoveValidator() public { + address newValidator = address(new MockValidator()); + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: newValidator, + data: "" + }); + bool validatorEnabled = instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, newValidator); + assertTrue(validatorEnabled); + + instance.uninstallModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: newValidator, + data: "" + }); + validatorEnabled = instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, newValidator); + assertFalse(validatorEnabled); + } + + function testAddExecutor() public { + address newExecutor = address(new MockExecutor()); + + instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: newExecutor, data: "" }); + bool executorEnabled = instance.isModuleInstalled(MODULE_TYPE_EXECUTOR, newExecutor); + assertTrue(executorEnabled); + } + + function testRemoveExecutor() public { + address newExecutor = address(new MockExecutor()); + + instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: newExecutor, data: "" }); + bool executorEnabled = instance.isModuleInstalled(MODULE_TYPE_EXECUTOR, newExecutor); + assertTrue(executorEnabled); + + instance.uninstallModule({ + moduleTypeId: MODULE_TYPE_EXECUTOR, + module: newExecutor, + data: "" + }); + executorEnabled = instance.isModuleInstalled(MODULE_TYPE_EXECUTOR, newExecutor); + assertFalse(executorEnabled); + } + + function testAddHook() public { + instance.installModule({ moduleTypeId: MODULE_TYPE_HOOK, module: address(hook), data: "" }); + + bool hookEnabled = instance.isModuleInstalled(MODULE_TYPE_HOOK, address(hook)); + assertTrue(hookEnabled); + } + + function testRemoveHook() public { + instance.installModule({ moduleTypeId: MODULE_TYPE_HOOK, module: address(hook), data: "" }); + + bool hookEnabled = instance.isModuleInstalled(MODULE_TYPE_HOOK, address(hook)); + assertTrue(hookEnabled); + + instance.uninstallModule({ moduleTypeId: MODULE_TYPE_HOOK, module: address(hook), data: "" }); + hookEnabled = instance.isModuleInstalled(MODULE_TYPE_HOOK, address(hook)); + assertFalse(hookEnabled); + } + + function testAddFallback() public { + bytes memory fallbackData = abi.encode(bytes4(keccak256("foo()")), CALLTYPE_SINGLE, ""); + + instance.installModule({ + moduleTypeId: MODULE_TYPE_FALLBACK, + module: address(fallbackHandler), + data: fallbackData + }); + + bool fallbackEnabled = + instance.isModuleInstalled(MODULE_TYPE_FALLBACK, address(fallbackHandler), fallbackData); + assertTrue(fallbackEnabled); + } + + function testRemoveFallback() public { + bytes memory fallbackData = abi.encode(bytes4(keccak256("foo()")), CALLTYPE_SINGLE, ""); + + instance.installModule({ + moduleTypeId: MODULE_TYPE_FALLBACK, + module: address(fallbackHandler), + data: fallbackData + }); + + bool fallbackEnabled = + instance.isModuleInstalled(MODULE_TYPE_FALLBACK, address(fallbackHandler), fallbackData); + assertTrue(fallbackEnabled); + + instance.uninstallModule({ + moduleTypeId: MODULE_TYPE_FALLBACK, + module: address(fallbackHandler), + data: fallbackData + }); + fallbackEnabled = + instance.isModuleInstalled(MODULE_TYPE_FALLBACK, address(fallbackHandler), fallbackData); + assertFalse(fallbackEnabled); + } + + /*////////////////////////////////////////////////////////////////////////// + UTILS + //////////////////////////////////////////////////////////////////////////*/ + + function testGetUserOpHash() public { + // Create userOperation fields + address receiver = makeAddr("receiver"); + uint256 value = 10 gwei; + bytes memory callData = abi.encode(true); + + // Create userOperation hash using lib + UserOpData memory userOpData = instance.getExecOps({ + target: receiver, + value: value, + callData: callData, + txValidator: address(instance.defaultValidator) + }); + bytes32 entryPointUserOpHash = instance.aux.entrypoint.getUserOpHash(userOpData.userOp); + + // Validate userOperation + assertEq(userOpData.userOpHash, entryPointUserOpHash); + } + + function testDeployAccount() public { + AccountInstance memory newInstance = makeAccountInstance("new"); + assertTrue(newInstance.account.code.length == 0); + + newInstance.deployAccount(); + + assertTrue(newInstance.account.code.length > 0); + } + + function testWriteGas() public { + string memory gasIdentifier = "testWriteGas"; + string memory rootDir = "gas_calculations"; + string memory fileName = string.concat(rootDir, "/", gasIdentifier, ".json"); + assertTrue(vm.isDir("gas_calculations")); + if (vm.isFile(fileName)) { + vm.removeFile(fileName); + } + assertFalse(vm.isFile(fileName)); + + vm.setEnv("GAS", "true"); + + instance.log4337Gas("testWriteGas"); + testexec__Given__TwoInputs(); + assertTrue(vm.isFile(fileName)); + } + + function testSimulateUserOp() public { + instance.simulateUserOp(true); + testexec__Given__TwoInputs(); + } + + function testERC1271() public { + bytes32 unformattedHash = keccak256("test"); + + bool isValid = instance.isValidSignature({ + validator: address(instance.defaultValidator), + hash: unformattedHash, + signature: bytes("test") + }); + assertTrue(isValid); + } + + function testUsingAccountEnv() public { + string[] memory envs = new string[](6); + envs[0] = "DEFAULT"; + envs[1] = "SAFE"; + envs[2] = "KERNEL"; + envs[3] = "NEXUS"; + envs[4] = "CUSTOM"; + envs[5] = "INVALID"; + + for (uint256 i = 0; i < envs.length; i++) { + string memory env = envs[i]; + if (keccak256(abi.encodePacked(env)) == keccak256(abi.encodePacked("INVALID"))) { + vm.expectRevert(ModuleKitHelpers.InvalidAccountType.selector); + this._usingAccountEnv(env); + } else { + _usingAccountEnv(env); + } + } + } + + function testUsingAccountEnv_ModuleKitUninitialized() public { + isInit[block.chainid] = false; + _usingAccountEnv("DEFAULT"); + } + + function testSetAccountEnv() public { + // Deploy using current env + AccountInstance memory oldEnvInstance = makeAccountInstance("sameSalt"); + assertTrue(oldEnvInstance.account.code.length == 0); + oldEnvInstance.deployAccount(); + assertTrue(oldEnvInstance.account.code.length > 0); + + // Load env + (bytes32 envHash) = getAccountType(); + + // Switch env + string memory newEnv = envHash == keccak256(abi.encodePacked("KERNEL")) ? "SAFE" : "KERNEL"; + instance.setAccountEnv(newEnv); + + // Deploy using new env + AccountInstance memory newEnvInstance = makeAccountInstance("sameSalt"); + assertTrue(newEnvInstance.account.code.length == 0); + newEnvInstance.deployAccount(); + assertTrue(newEnvInstance.account.code.length > 0); + } + + function testSetAccountEnv_RevertsWhen_InvalidAccountType() public { + vm.expectRevert(ModuleKitHelpers.InvalidAccountType.selector); + this.callSetAccountENVInvalid(); + } + + /*////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////*/ + + function callSetAccountENVInvalid() public { + instance.setAccountEnv("INVALID"); + } + + function _usingAccountEnv(string memory env) public usingAccountEnv(env.toAccountType()) { + AccountInstance memory newInstance = makeAccountInstance(keccak256(abi.encode(env))); + assertTrue(newInstance.account.code.length == 0); + + newInstance.deployAccount(); + + assertTrue(newInstance.account.code.length > 0); + } + + function _getModulesAndAssert( + bytes calldata expectedResultBytes, + AccountInstance memory _instance + ) + public + view + { + InstalledModule[] memory modules = _instance.getInstalledModules(); + // Parse length + uint256 length = abi.decode(expectedResultBytes[0:32], (uint256)); + // Parse addresses and types + address[] memory expectedAddresses = new address[](length); + uint256[] memory expectedTypes = new uint256[](length); + for (uint256 i = 0; i < length; i++) { + expectedAddresses[i] = + abi.decode(expectedResultBytes[32 + i * 32:64 + i * 32], (address)); + expectedTypes[i] = abi.decode( + expectedResultBytes[32 + length * 32 + i * 32:64 + length * 32 + i * 32], (uint256) + ); + } + // Assert expected modules length + assertTrue( + modules.length == length + (instance.getAccountType() == AccountType.SAFE ? 1 : 0) + ); + // AccountType.SAFE has 1 extra module added during setup, skip it + uint256 index = instance.getAccountType() == AccountType.SAFE ? 1 : 0; + for (uint256 i = 0; i < length; i++) { + assertTrue(modules[index + i].moduleAddress == expectedAddresses[i]); + assertTrue(modules[index + i].moduleType == expectedTypes[i]); + } + } + + function test_verifyModuleStorageWasCleared() public { + // Set simulate mode to false + instance.simulateUserOp(false); + // Install a module + module = address(new MockK1Validator()); + // Start state diff recording + instance.startStateDiffRecording(); + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: module, + data: abi.encode(instance.account) + }); + // Uninstall the module + instance.uninstallModule({ moduleTypeId: MODULE_TYPE_VALIDATOR, module: module, data: "" }); + // Stop state diff recording + VmSafe.AccountAccess[] memory accountAccesses = instance.stopAndReturnStateDiff(); + // Assert that the module storage was cleared + instance.verifyModuleStorageWasCleared(accountAccesses, module); + } + + function test_verifyModuleStorageWasCleared_RevertsWhen_NotCleared_UsingComplianceFlag() + public + { + // Set simulate mode to false + instance.simulateUserOp(false); + // Set compliance flag + instance.storageCompliance(true); + + // Install a module + module = address(new MockK1ValidatorUncompliantUninstall()); + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: module, + data: abi.encode(0xffffffffffffffffffff) + }); + // Assert module storage + assertEq( + address(0xffffffffffffffffffff), + MockK1Validator(module).smartAccountOwners(address(instance.account)) + ); + // Expect revert + vm.expectRevert(); + this.__revertWhen_verifyModuleStorageWasCleared_NotCleared(); + } + + function test_verifyModuleStorageWasCleared_RevertsWhen_NotCleared() public { + // Set simulate mode to false + instance.simulateUserOp(false); + // Install a module + module = address(new MockK1ValidatorUncompliantUninstall()); + // Start state diff recording + instance.startStateDiffRecording(); + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: module, + data: abi.encode(0xffffffffffffffffffff) + }); + // Assert module storage + assertEq( + address(0xffffffffffffffffffff), + MockK1Validator(module).smartAccountOwners(address(instance.account)) + ); + // Uninstall the module + instance.uninstallModule({ moduleTypeId: MODULE_TYPE_VALIDATOR, module: module, data: "" }); + // Stop state diff recording + VmSafe.AccountAccess[] memory accountAccesses = instance.stopAndReturnStateDiff(); + // Expect revert + vm.expectRevert(); + // Assert that the module storage was cleared + this.callVerifyStorageWasNotCleared(instance, module, accountAccesses); + } + + function __revertWhen_verifyModuleStorageWasCleared_NotCleared() public { + // Uninstall + instance.uninstallModule({ moduleTypeId: MODULE_TYPE_VALIDATOR, module: module, data: "" }); + } + + function test_withModuleStorageClearValidation() + public + withModuleStorageClearValidation(instance, module) + { + // Set simulate mode to false + instance.simulateUserOp(false); + // Install a module + module = address(new MockK1Validator()); + // Install the module + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: module, + data: abi.encode(VALIDATION_FAILED) + }); + // Uninstall the module + instance.uninstallModule({ moduleTypeId: MODULE_TYPE_VALIDATOR, module: module, data: "" }); + } + + /*////////////////////////////////////////////////////////////// + EXPECT REVERT + //////////////////////////////////////////////////////////////*/ + + function _revertWhen__ValidationFails(bytes memory revertReason) public { + // Create userOperation fields + address receiver = makeAddr("receiver"); + uint256 value = 10 gwei; + bytes memory callData = ""; + + if (!instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, address(validatorFalse))) { + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: address(validatorFalse), + data: "" + }); + } + + // Expect the revert + if (revertReason.length == 0) { + instance.expect4337Revert(); + } else if (revertReason.length == 4) { + instance.expect4337Revert(bytes4(revertReason)); + } else { + instance.expect4337Revert(revertReason); + } + + // Create userOperation + instance.getExecOps({ + target: receiver, + value: value, + callData: callData, + txValidator: address(validatorFalse) + }).execUserOps(); + } + + function _revertWhen__ValidationReverts(bytes memory revertReason) public { + address revertingValidator = makeAddr("revertingValidator"); + + if (!instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, revertingValidator)) { + vm.etch(revertingValidator, address(validator).code); + + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: revertingValidator, + data: "" + }); + + vm.etch(revertingValidator, hex"fd"); + } + + // Create userOperation fields + address receiver = makeAddr("receiver"); + uint256 value = 10 gwei; + bytes memory callData = ""; + + // Expect the revert + if (revertReason.length == 0) { + instance.expect4337Revert(); + } else if (revertReason.length == 4) { + instance.expect4337Revert(bytes4(revertReason)); + } else { + instance.expect4337Revert(revertReason); + } + + // Create userOperation + instance.getExecOps({ + target: receiver, + value: value, + callData: callData, + txValidator: revertingValidator + }).execUserOps(); + } + + function _revertWhen__UserOperationFails(bytes memory revertReason) public { + // Create userOperation fields + bytes memory callData = abi.encodeWithSelector(MockTarget.setAccessControl.selector, 2); + + // Expect the revert + if (revertReason.length == 0) { + instance.expect4337Revert(); + } else if (revertReason.length == 4) { + instance.expect4337Revert(bytes4(revertReason)); + } else { + instance.expect4337Revert(revertReason); + } + + // Create userOperation + instance.exec({ target: address(mockTarget), callData: callData, value: 0 }); + } + + /*////////////////////////////////////////////////////////////// + MODIFIERS + //////////////////////////////////////////////////////////////*/ + + // Used to skip tests when env is kernel as they don't emit events on module installation + modifier whenEnvIsNotKernel() { + AccountType env = ModuleKitHelpers.getAccountType(); + if (env == AccountType.KERNEL) { + return; + } + _; + } + + /*////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////*/ + + function callVerifyStorageWasNotCleared( + AccountInstance memory _instance, + address _module, + VmSafe.AccountAccess[] memory _accountAccesses + ) + public + view + { + _instance.verifyModuleStorageWasCleared(_accountAccesses, _module); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/test/GasCalculationsTest.sol b/typescript/packages/account-modules/lib/modulekit/test/GasCalculationsTest.sol new file mode 100644 index 0000000..9984ce7 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/test/GasCalculationsTest.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "ds-test/test.sol"; +import "src/test/utils/gas/GasCalculations.sol"; + +contract GasCalculationsTest is DSTest { + function test_formatGasValue() public { + uint256 prevValue = 37_054; + uint256 newValue = 187_170; + + string memory result = formatGasValue(prevValue, newValue); + + // Log the result + emit log_named_string("Result", result); + } + + function test_formatGas() public { + int256 value = 2_550_948; + + string memory result = formatGas(value); + + // Log the result + emit log_named_string("Result", result); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/test/RegistryDeployer.t.sol b/typescript/packages/account-modules/lib/modulekit/test/RegistryDeployer.t.sol new file mode 100644 index 0000000..cc3c506 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/test/RegistryDeployer.t.sol @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +import "./BaseTest.t.sol"; +import { + RegistryDeployer, + REGISTRY_ADDR, + ResolverUID, + SchemaUID, + ModuleRecord, + ModuleType +} from "src/deployment/registry/RegistryDeployer.sol"; +import { MockValidator } from "src/Mocks.sol"; + +contract RegistryDeployerTest is RegistryDeployer, BaseTest { + uint256 internal mainnetFork; + uint256 internal testnetFork; + + function setUp() public override { + super.setUp(); + + string memory MAINNET_RPC_URL = vm.envString("MAINNET_RPC_URL"); + mainnetFork = vm.createFork(MAINNET_RPC_URL); + + string memory TESTNET_RPC_URL = vm.envString("TESTNET_RPC_URL"); + testnetFork = vm.createFork(TESTNET_RPC_URL); + } + + function testDeployModule() public onMainnet { + // Setup module bytecode, deploy params, and data + bytes memory initCode = type(MockValidator).creationCode; + bytes32 salt = bytes32(0); + bytes memory metadata = hex"41414141414141"; + bytes memory resolverContext = ""; + + // Deploy module + address module = deployModule({ + initCode: initCode, + salt: salt, + metadata: metadata, + resolverContext: resolverContext + }); + + assertEq(module, predictModuleAddress({ salt: salt, initCode: initCode })); + assertGt(module.code.length, 0); + + ModuleRecord memory moduleRecord = findModule(module); + assertEq(ResolverUID.unwrap(moduleRecord.resolverUID), ResolverUID.unwrap(resolverUID)); + assertEq(moduleRecord.metadata, metadata); + } + + function testDeployModuleViaFactory() public onMainnet { + bytes32 salt = bytes32(0); + address factory = address(this); + bytes memory callOnFactory = abi.encodeCall(this.deploy, (salt)); + bytes memory metadata = hex"41414141414141"; + bytes memory resolverContext = ""; + + address module = deployModuleViaFactory({ + factory: factory, + callOnFactory: callOnFactory, + metadata: metadata, + resolverContext: resolverContext + }); + + assertEq(module, predictAddress(salt)); + assertGt(module.code.length, 0); + + ModuleRecord memory moduleRecord = findModule(module); + assertEq(ResolverUID.unwrap(moduleRecord.resolverUID), ResolverUID.unwrap(resolverUID)); + assertEq(moduleRecord.metadata, metadata); + } + + function testRegisterModule() public onMainnet { + address module = address(new MockValidator()); + + ModuleRecord memory moduleRecord = findModule(module); + assertEq(ResolverUID.unwrap(moduleRecord.resolverUID), bytes32(0)); + assertEq(moduleRecord.metadata, ""); + + bytes memory metadata = hex"41414141414141"; + bytes memory resolverContext = ""; + + registerModule({ module: module, metadata: metadata, resolverContext: resolverContext }); + + moduleRecord = findModule(module); + assertEq(ResolverUID.unwrap(moduleRecord.resolverUID), ResolverUID.unwrap(resolverUID)); + assertEq(moduleRecord.metadata, metadata); + } + + function testMockAttestModule() public onTestnet { + deployModule(); + + bytes memory initCode = type(MockValidator).creationCode; + bytes32 salt = bytes32(0); + + address module = predictModuleAddress({ salt: salt, initCode: initCode }); + + bytes memory attestationData = hex"41414141414141"; + ModuleType[] memory moduleTypes = new ModuleType[](1); + moduleTypes[0] = ModuleType.wrap(1); + + mockAttestToModule({ + module: module, + attestationData: attestationData, + moduleTypes: moduleTypes + }); + + assertTrue(isModuleAttestedMock(module)); + } + + function testFindResolver() public onMainnet { + ResolverUID _resolverUID = findResolver(); + assertEq(ResolverUID.unwrap(_resolverUID), ResolverUID.unwrap(resolverUID)); + } + + function testRegisterResolver() public onMainnet { + ResolverUID _resolverUID = registerResolver(address(this)); + setResolverUID(_resolverUID); + findResolver(); + } + + function testFindSchema() public onMainnet { + SchemaUID _schemaUID = findSchema(); + assertEq(SchemaUID.unwrap(_schemaUID), SchemaUID.unwrap(schemaUID)); + } + + function testRegisterSchema() public onMainnet { + SchemaUID _schemaUID = registerSchema({ schema: "schema", validator: address(this) }); + setSchemaUID(_schemaUID); + findSchema(); + } + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL + //////////////////////////////////////////////////////////////////////////*/ + + function deployModule() internal { + // Setup module bytecode, deploy params, and data + bytes memory initCode = type(MockValidator).creationCode; + bytes32 salt = bytes32(0); + bytes memory metadata = hex"41414141414141"; + bytes memory resolverContext = ""; + + // Deploy module + address module = deployModule({ + initCode: initCode, + salt: salt, + metadata: metadata, + resolverContext: resolverContext + }); + + assertEq(module, predictModuleAddress({ salt: salt, initCode: initCode })); + assertGt(module.code.length, 0); + + ModuleRecord memory moduleRecord = findModule(module); + assertEq(ResolverUID.unwrap(moduleRecord.resolverUID), ResolverUID.unwrap(resolverUID)); + assertEq(moduleRecord.metadata, metadata); + } + + /*////////////////////////////////////////////////////////////////////////// + MODIFIERS + //////////////////////////////////////////////////////////////////////////*/ + + modifier onMainnet() { + vm.selectFork(mainnetFork); + vm.rollFork(20_626_383); + _; + } + + modifier onTestnet() { + vm.selectFork(testnetFork); + vm.rollFork(6_586_870); + _; + } + + /*////////////////////////////////////////////////////////////////////////// + CALLBACKS + //////////////////////////////////////////////////////////////////////////*/ + + function deploy(bytes32 salt) external returns (address) { + return address(new MockValidator{ salt: salt }()); + } + + function predictAddress(bytes32 salt) public view returns (address) { + bytes32 hash = keccak256( + abi.encodePacked( + bytes1(0xff), address(this), salt, keccak256(type(MockValidator).creationCode) + ) + ); + return address(uint160(uint256(hash))); + } + + function supportsInterface( + bytes4 // interfaceID + ) + external + pure + returns (bool) + { + return true; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/test/integrations/ExampleFactory.t.sol b/typescript/packages/account-modules/lib/modulekit/test/integrations/ExampleFactory.t.sol new file mode 100644 index 0000000..f61374a --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/test/integrations/ExampleFactory.t.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +import { BaseTest } from "test/BaseTest.t.sol"; +import { IERC7579Account } from "src/accounts/common/interfaces/IERC7579Account.sol"; +import { IERC7579Bootstrap } from "src/accounts/erc7579/interfaces/IERC7579Bootstrap.sol"; +import { ExampleFactory } from "src/integrations/registry/ExampleFactory.sol"; +import { ModuleKitHelpers } from "src/ModuleKit.sol"; +import { IStakeManager } from "src/external/ERC4337.sol"; +import { ENTRYPOINT_ADDR } from "src/deployment/predeploy/EntryPoint.sol"; +import { getHelper } from "src/test/utils/Storage.sol"; +import { AccountType } from "src/test/RhinestoneModuleKit.sol"; +import { ERC7579Precompiles } from "src/deployment/precompiles/ERC7579Precompiles.sol"; + +contract ExampleFactoryTest is BaseTest, ERC7579Precompiles { + using ModuleKitHelpers for *; + + IERC7579Account implementation; + IERC7579Bootstrap bootstrap; + ExampleFactory factory; + + function setUp() public override { + super.setUp(); + + implementation = deployERC7579Account(); + vm.label(address(implementation), "AccountSingleton"); + bootstrap = deployERC7579Bootstrap(); + vm.label(address(bootstrap), "Bootstrap"); + address[] memory trustedAttesters = new address[](2); + trustedAttesters[0] = makeAddr("attester1"); + trustedAttesters[1] = makeAddr("attester2"); + uint8 threshold = 2; + + factory = new ExampleFactory( + address(implementation), + address(bootstrap), + address(instance.aux.registry), + trustedAttesters, + threshold + ); + vm.label(address(factory), "ExampleFactory"); + + vm.deal(address(factory), 10 ether); + vm.prank(address(factory)); + IStakeManager(ENTRYPOINT_ADDR).addStake{ value: 10 ether }(100_000); + } + + function test_createAccount() public { + address account = + factory.createAccount(keccak256("1"), address(instance.defaultValidator), ""); + assertTrue(account != address(0)); + assertEq(IERC7579Account(payable(account)).accountId(), "uMSA.advanced/withHook.v0.1"); + } + + function test_userOpFlow() public { + bytes32 salt = bytes32(bytes("newAccount")); + address account = factory.getAddress(salt, address(instance.defaultValidator), ""); + bytes memory initCode = factory.getInitCode(salt, address(instance.defaultValidator), ""); + address erc7579Helper = ModuleKitHelpers.getHelper(AccountType.DEFAULT); + + instance = makeAccountInstance({ + salt: salt, + helper: erc7579Helper, + account: account, + initCode: initCode + }); + + address target = makeAddr("target"); + uint256 value = 1 ether; + + instance.exec({ target: target, value: value, callData: "" }); + + assertTrue(target.balance == value); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/test/integrations/SmartSession.t.sol b/typescript/packages/account-modules/lib/modulekit/test/integrations/SmartSession.t.sol new file mode 100644 index 0000000..5131bdd --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/test/integrations/SmartSession.t.sol @@ -0,0 +1,405 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +// Constants +import { MODULE_TYPE_VALIDATOR } from "src/accounts/common/interfaces/IERC7579Module.sol"; + +// Libraries +import { ModuleKitHelpers, AccountInstance } from "src/ModuleKit.sol"; +import { ecdsaSign } from "src/Helpers.sol"; + +// Mocks +import { MockPolicy, MockTarget } from "src/Mocks.sol"; +import { MockK1Validator } from "test/mocks/MockK1Validator.sol"; + +// Tests +import { BaseTest } from "../BaseTest.t.sol"; + +// Types +import { + PermissionId, + PolicyData, + ActionData, + ERC7739Data, + Session, + ISessionValidator +} from "src/integrations/interfaces/ISmartSession.sol"; +import { Execution } from "src/accounts/erc7579/lib/ExecutionLib.sol"; +import { UserOpData, PackedUserOperation } from "src/test/RhinestoneModuleKit.sol"; + +/// @dev Tests for smart session integration within the RhinestoneModuleKit +contract SmartSessionTest is BaseTest { + /*////////////////////////////////////////////////////////////// + LIBRARIES + //////////////////////////////////////////////////////////////*/ + + using ModuleKitHelpers for AccountInstance; + using ModuleKitHelpers for UserOpData; + + /*////////////////////////////////////////////////////////////// + VARIABLES + //////////////////////////////////////////////////////////////*/ + + // @dev A policy contract that allows any action + MockPolicy mockPolicy; + // @@dev A mock target contract + MockTarget target; + // @dev Owner account + Account owner; + + /*////////////////////////////////////////////////////////////// + SETUP + //////////////////////////////////////////////////////////////*/ + + function setUp() public override { + super.setUp(); + // Deploy mock policy + mockPolicy = new MockPolicy(); + // Set the policy to allow any action + mockPolicy.setValidationData(address(instance.account), 0); + // Deploy mock target + target = new MockTarget(); + } + + /*////////////////////////////////////////////////////////////// + TESTS + //////////////////////////////////////////////////////////////*/ + + function test_isModuleType() public view { + // Check if the module type is correct + assertTrue( + auxiliary.smartSession.isModuleType(1) // ERC7579_MODULE_TYPE_VALIDATOR; + ); + } + + function test_installModule() public { + // Check if the module is not installed + assertFalse( + instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, address(auxiliary.smartSession)) + ); + // Install a module + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: address(auxiliary.smartSession), + data: "" + }); + // Check if the module is installed + assertTrue( + instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, address(auxiliary.smartSession)) + ); + } + + function test_addSession() public { + // Add a session + PermissionId permissionIds = instance.addSession({ + salt: bytes32("salt1"), + userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), + erc7739Policy: _getEmptyERC7739Data( + "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) + ), + actionDatas: _getEmptyActionDatas( + address(target), MockTarget.set.selector, address(mockPolicy) + ) + }); + // Check if the session is enabled + assertTrue(instance.isPermissionEnabled(permissionIds)); + } + + function test_addSession_preInstalled() public { + // Install smart session + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: address(auxiliary.smartSession), + data: "" + }); + // Add a session + PermissionId permissionIds = instance.addSession({ + salt: bytes32("salt1"), + userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), + erc7739Policy: _getEmptyERC7739Data( + "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) + ), + actionDatas: _getEmptyActionDatas( + address(target), MockTarget.set.selector, address(mockPolicy) + ) + }); + // Check if the session is enabled + assertTrue(instance.isPermissionEnabled(permissionIds)); + } + + function test_removeSession() public { + // Add a session + PermissionId permissionIds = instance.addSession({ + salt: bytes32("salt1"), + userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), + erc7739Policy: _getEmptyERC7739Data( + "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) + ), + actionDatas: _getEmptyActionDatas( + address(target), MockTarget.set.selector, address(mockPolicy) + ) + }); + // Check if the session is enabled + assertTrue(instance.isPermissionEnabled(permissionIds)); + // Remove the session + instance.removeSession(permissionIds); + // Check if the session is disabled + assertFalse(instance.isPermissionEnabled(permissionIds)); + } + + function test_getPermissionId() public { + // Setup session data + Session memory session = Session({ + sessionValidator: ISessionValidator(address(instance.defaultSessionValidator)), + salt: "mockSalt", + sessionValidatorInitData: "mockInitData", + userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), + erc7739Policies: _getEmptyERC7739Data( + "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) + ), + actions: _getEmptyActionDatas(address(target), MockTarget.set.selector, address(mockPolicy)) + }); + + // Add a session + PermissionId permissionIds = instance.addSession({ session: session }); + // Get the permission id + PermissionId permissionId = instance.getPermissionId(session); + + // Check if the permission id is correct + assertTrue(permissionIds == permissionId); + } + + function test_useSession() public { + // Setup calldata to execute + bytes memory callData = abi.encodeWithSelector(MockTarget.set.selector, (1337)); + + // Setup session data + Session memory session = Session({ + sessionValidator: ISessionValidator(address(instance.defaultSessionValidator)), + salt: "mockSalt", + sessionValidatorInitData: "mockInitData", + userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), + erc7739Policies: _getEmptyERC7739Data( + "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) + ), + actions: _getEmptyActionDatas(address(target), MockTarget.set.selector, address(mockPolicy)) + }); + + // Use the session + instance.useSession(session, address(target), 0, /* value */ callData); + + // Check if the value was set + assertTrue(target.value() == 1337); + } + + function test_useSession_batchExecutions() public { + // Setup calldata to execute multiple operations + bytes memory callData1 = abi.encodeWithSelector(MockTarget.set.selector, (1337)); + bytes memory callData2 = abi.encodeWithSelector(MockTarget.set.selector, (7331)); + + // Create executions array + Execution[] memory executions = new Execution[](2); + executions[0] = Execution({ target: address(target), value: 0, callData: callData1 }); + executions[1] = Execution({ target: address(target), value: 0, callData: callData2 }); + + // Setup session data + Session memory session = Session({ + sessionValidator: ISessionValidator(address(instance.defaultSessionValidator)), + salt: "mockSalt", + sessionValidatorInitData: "mockInitData", + userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), + erc7739Policies: _getEmptyERC7739Data( + "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) + ), + actions: _getEmptyActionDatas(address(target), MockTarget.set.selector, address(mockPolicy)) + }); + + // Use the session with multiple executions + instance.useSession(session, executions); + + // Check if the second execution's value was set (since it was the last one) + assertEq(target.value(), 7331, "Target value should be set to last execution value"); + } + + function test_encodeSignatureEnableMode() public { + // Deploy MockK1Validator + MockK1Validator mockK1Validator = new MockK1Validator(); + + // Make an owner + owner = makeAccount("owner"); + + // Install validator + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: address(mockK1Validator), + data: abi.encode(owner.addr) + }); + + // Install smart session + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: address(auxiliary.smartSession), + data: "" + }); + + // Setup calldata to execute + bytes memory callData = abi.encodeWithSelector(MockTarget.set.selector, (1337)); + + // Get exec user ops + UserOpData memory userOpData = instance.getExecOps({ + target: address(target), + value: 0, + callData: callData, + txValidator: address(instance.defaultValidator) + }); + + // Setup session data + Session memory session = Session({ + sessionValidator: ISessionValidator(address(instance.defaultSessionValidator)), + salt: "mockSalt", + sessionValidatorInitData: "mockInitData", + userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), + erc7739Policies: _getEmptyERC7739Data( + "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) + ), + actions: _getEmptyActionDatas(address(target), MockTarget.set.selector, address(mockPolicy)) + }); + + // Get enable mode signature + bytes memory signature = instance.encodeSignatureEnableMode( + userOpData.userOp, session, _signWithOwner, address(mockK1Validator) + ); + + // Update the user op signature + userOpData.userOp.signature = signature; + + // Execute user ops + userOpData.execUserOps(); + } + + function test_encodeSignatureUnsafeEnableMode() public { + // Deploy MockK1Validator + MockK1Validator mockK1Validator = new MockK1Validator(); + + // Make an owner + owner = makeAccount("owner"); + + // Install validator + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: address(mockK1Validator), + data: abi.encode(owner.addr) + }); + + // Install smart session + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: address(auxiliary.smartSession), + data: "" + }); + + // Setup calldata to execute + bytes memory callData = abi.encodeWithSelector(MockTarget.set.selector, (1337)); + + // Get exec user ops + UserOpData memory userOpData = instance.getExecOps({ + target: address(target), + value: 0, + callData: callData, + txValidator: address(instance.defaultValidator) + }); + + // Setup session data + Session memory session = Session({ + sessionValidator: ISessionValidator(address(instance.defaultSessionValidator)), + salt: "mockSalt", + sessionValidatorInitData: "mockInitData", + userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), + erc7739Policies: _getEmptyERC7739Data( + "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) + ), + actions: _getEmptyActionDatas(address(target), MockTarget.set.selector, address(mockPolicy)) + }); + + // Get enable mode signature + bytes memory signature = instance.encodeSignatureUnsafeEnableMode( + userOpData.userOp, session, _signWithOwner, address(mockK1Validator) + ); + + // Update the user op signature + userOpData.userOp.signature = signature; + + // Execute user ops + userOpData.execUserOps(); + } + + /*////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////*/ + + function _signWithOwner(bytes32 hash) internal view returns (bytes memory) { + // Sign the hash with the owner + bytes memory signature = ecdsaSign(owner.key, hash); + // Return the signature + return signature; + } + + function _getEmptyPolicyDatas(address policyContract) + internal + pure + returns (PolicyData[] memory policyDatas) + { + policyDatas = new PolicyData[](1); + policyDatas[0] = _getEmptyPolicyData(policyContract); + } + + function _getEmptyPolicyData(address policyContract) + internal + pure + returns (PolicyData memory) + { + return PolicyData({ policy: policyContract, initData: "" }); + } + + function _getEmptyActionData( + address actionTarget, + bytes4 actionSelector, + address policyContract + ) + internal + pure + returns (ActionData memory) + { + return ActionData({ + actionTargetSelector: actionSelector, + actionTarget: actionTarget, + actionPolicies: _getEmptyPolicyDatas(policyContract) + }); + } + + function _getEmptyActionDatas( + address actionTarget, + bytes4 actionSelector, + address policyContract + ) + internal + pure + returns (ActionData[] memory actionDatas) + { + actionDatas = new ActionData[](1); + actionDatas[0] = _getEmptyActionData(actionTarget, actionSelector, policyContract); + } + + function _getEmptyERC7739Data( + string memory content, + PolicyData[] memory erc1271Policies + ) + internal + pure + returns (ERC7739Data memory) + { + string[] memory contents = new string[](1); + contents[0] = content; + return ERC7739Data({ allowedERC7739Content: contents, erc1271Policies: erc1271Policies }); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/test/integrations/SwapTest.t.sol b/typescript/packages/account-modules/lib/modulekit/test/integrations/SwapTest.t.sol new file mode 100644 index 0000000..8b20338 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/test/integrations/SwapTest.t.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +import "test/BaseTest.t.sol"; +import "src/ModuleKit.sol"; +import { ERC7579ExecutorBase } from "src/Modules.sol"; +import { IERC20 } from "forge-std/interfaces/IERC20.sol"; +import { UniswapV3Integration } from "src/integrations/uniswap/v3/Uniswap.sol"; + +contract TestUniswap is BaseTest { + using ModuleKitHelpers for AccountInstance; + using UniswapV3Integration for *; + + IERC20 tokenA; + IERC20 tokenB; + MockERC20 mockTokenA; + MockERC20 mockTokenB; + + uint256 amountIn = 100_000_000; // Example: 100 tokens of tokenA + uint32 slippage = 1; // 0.1% slippage + + address internal constant USDC_HOLDER = 0x4B16c5dE96EB2117bBE5fd171E4d203624B014aa; // account + // with USDC holdings + address internal constant WETH_HOLDER = 0x57757E3D981446D585Af0D9Ae4d7DF6D64647806; // account + // with WETH holdings + + address constant USDC_ADDRESS = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + + function setUp() public override { + string memory MAINNET_RPC_URL = vm.envString("MAINNET_RPC_URL"); + vm.createSelectFork(MAINNET_RPC_URL); + vm.rollFork(20_426_591); + instance = makeAccountInstance("account1"); + assertTrue(instance.account != address(0)); + + tokenA = IERC20(USDC_ADDRESS); + tokenB = IERC20(WETH_ADDRESS); + + _fundAccountWithTokenA(amountIn); + vm.deal(instance.account, 1 ether); + assertTrue(instance.account.balance == 1 ether); + instance.simulateUserOp(false); + } + + function _fundAccountWithTokenA(uint256 amount) internal { + vm.startPrank(USDC_HOLDER); + bool success = tokenA.transfer(instance.account, amount); + require(success, "Failed to transfer tokenA to account"); + vm.stopPrank(); + } + + function testApproveAndSwap() public { + address poolAddress = UniswapV3Integration.getPoolAddress(address(tokenA), address(tokenB)); + uint160 sqrtPriceX96 = UniswapV3Integration.getSqrtPriceX96(poolAddress); + + uint256 priceRatio = UniswapV3Integration.sqrtPriceX96toPriceRatio(sqrtPriceX96); + + UniswapV3Integration.priceRatioToPrice(priceRatio, poolAddress, address(tokenA)); + + bool swapToken0to1 = UniswapV3Integration.checkTokenOrder(address(tokenA), poolAddress); + + uint256 priceRatioLimit; + if (swapToken0to1) { + priceRatioLimit = (priceRatio * (1000 - slippage)) / 1000; + } else { + priceRatioLimit = (priceRatio * (1000 + slippage)) / 1000; + } + + UniswapV3Integration.priceRatioToPrice(priceRatioLimit, poolAddress, address(tokenA)); + + uint160 sqrtPriceLimitX96 = UniswapV3Integration.priceRatioToSqrtPriceX96(priceRatioLimit); + + uint256 initialAccountBalanceA = tokenA.balanceOf(instance.account); + uint256 initialAccountBalanceB = tokenB.balanceOf(instance.account); + + Execution[] memory swap = UniswapV3Integration.approveAndSwap( + instance.account, tokenA, tokenB, amountIn, sqrtPriceLimitX96 + ); + + for (uint256 i = 0; i < swap.length; i++) { + instance.exec({ + target: swap[i].target, + value: swap[i].value, + callData: swap[i].callData + }); + } + + uint256 finalAccountBalanceA = tokenA.balanceOf(instance.account); + uint256 finalAccountBalanceB = tokenB.balanceOf(instance.account); + + sqrtPriceX96 = UniswapV3Integration.getSqrtPriceX96(poolAddress); + + require( + finalAccountBalanceA < initialAccountBalanceA, + "Token A balance in account did not decrease" + ); + require( + finalAccountBalanceB > initialAccountBalanceB, + "Token B balance in account did not increase" + ); + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1Validator.sol b/typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1Validator.sol new file mode 100644 index 0000000..07c2e5e --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1Validator.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +import { + IValidator, + VALIDATION_SUCCESS, + VALIDATION_FAILED, + MODULE_TYPE_VALIDATOR +} from "src/accounts/common/interfaces/IERC7579Module.sol"; +import { PackedUserOperation } from "src/external/ERC4337.sol"; +import { ECDSA } from "solady/utils/ECDSA.sol"; +import { SignatureCheckerLib } from "solady/utils/SignatureCheckerLib.sol"; +import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; +import { EIP1271_MAGIC_VALUE, IERC1271 } from "src/module-bases/interfaces/IERC1271.sol"; + +contract MockK1Validator is IValidator { + bytes4 constant ERC1271_INVALID = 0xffffffff; + mapping(address => address) public smartAccountOwners; + + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + payable + returns (uint256 validation) + { + return ECDSA.recover(MessageHashUtils.toEthSignedMessageHash(userOpHash), userOp.signature) + == smartAccountOwners[msg.sender] ? VALIDATION_SUCCESS : VALIDATION_FAILED; + } + + function isValidSignatureWithSender( + address, + bytes32 hash, + bytes calldata signature + ) + external + view + returns (bytes4) + { + return ECDSA.recover(MessageHashUtils.toEthSignedMessageHash(hash), signature) + == smartAccountOwners[msg.sender] ? EIP1271_MAGIC_VALUE : ERC1271_INVALID; + } + + function onInstall(bytes calldata data) external { + address owner = abi.decode(data, (address)); + smartAccountOwners[msg.sender] = owner; + } + + function onUninstall(bytes calldata data) external { + data; + delete smartAccountOwners[msg.sender]; + } + + function isModuleType(uint256 moduleTypeId) external pure returns (bool) { + return moduleTypeId == MODULE_TYPE_VALIDATOR; + } + + function isOwner(address account, address owner) external view returns (bool) { + return smartAccountOwners[account] == owner; + } + + function isInitialized(address) external pure returns (bool) { + return false; + } + + function getOwner(address account) external view returns (address) { + return smartAccountOwners[account]; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1ValidatorUncompliantUninstall.sol b/typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1ValidatorUncompliantUninstall.sol new file mode 100644 index 0000000..5c0f16c --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1ValidatorUncompliantUninstall.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +import { + IValidator, + VALIDATION_SUCCESS, + VALIDATION_FAILED, + MODULE_TYPE_VALIDATOR +} from "src/accounts/common/interfaces/IERC7579Module.sol"; +import { PackedUserOperation } from "src/external/ERC4337.sol"; +import { ECDSA } from "solady/utils/ECDSA.sol"; +import { SignatureCheckerLib } from "solady/utils/SignatureCheckerLib.sol"; +import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; +import { EIP1271_MAGIC_VALUE, IERC1271 } from "src/module-bases/interfaces/IERC1271.sol"; + +contract MockK1ValidatorUncompliantUninstall is IValidator { + bytes4 constant ERC1271_INVALID = 0xffffffff; + mapping(address => address) public smartAccountOwners; + + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + payable + returns (uint256 validation) + { + return ECDSA.recover(MessageHashUtils.toEthSignedMessageHash(userOpHash), userOp.signature) + == smartAccountOwners[msg.sender] ? VALIDATION_SUCCESS : VALIDATION_FAILED; + } + + function isValidSignatureWithSender( + address, + bytes32 hash, + bytes calldata signature + ) + external + view + returns (bytes4) + { + return ECDSA.recover(MessageHashUtils.toEthSignedMessageHash(hash), signature) + == smartAccountOwners[msg.sender] ? EIP1271_MAGIC_VALUE : ERC1271_INVALID; + } + + function onInstall(bytes calldata data) external { + address owner = abi.decode(data, (address)); + smartAccountOwners[msg.sender] = owner; + } + + function onUninstall(bytes calldata data) external pure { + data; + } + + function isModuleType(uint256 moduleTypeId) external pure returns (bool) { + return moduleTypeId == MODULE_TYPE_VALIDATOR; + } + + function isOwner(address account, address owner) external view returns (bool) { + return smartAccountOwners[account] == owner; + } + + function isInitialized(address) external pure returns (bool) { + return false; + } + + function getOwner(address account) external view returns (address) { + return smartAccountOwners[account]; + } +} diff --git a/typescript/packages/account-modules/lib/modulekit/test/mocks/MockValidatorFalse.sol b/typescript/packages/account-modules/lib/modulekit/test/mocks/MockValidatorFalse.sol new file mode 100644 index 0000000..e255952 --- /dev/null +++ b/typescript/packages/account-modules/lib/modulekit/test/mocks/MockValidatorFalse.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +/* solhint-disable no-unused-vars */ +import { ERC7579StatelessValidatorBase } from "src/Modules.sol"; +import { ERC7579ValidatorBase } from "src/Modules.sol"; +import { PackedUserOperation } from "src/external/ERC4337.sol"; + +contract MockValidatorFalse is ERC7579StatelessValidatorBase, ERC7579ValidatorBase { + function onInstall(bytes calldata data) external virtual override { } + + function onUninstall(bytes calldata data) external virtual override { } + + function validateUserOp( + PackedUserOperation calldata, // userOp + bytes32 // userOpHash + ) + external + virtual + override + returns (ValidationData) + { + return _packValidationData({ sigFailed: true, validUntil: type(uint48).max, validAfter: 0 }); + } + + function isValidSignatureWithSender( + address, // sender + bytes32, // hash + bytes calldata // signature + ) + external + view + virtual + override + returns (bytes4) + { + return EIP1271_FAILED; + } + + function isModuleType(uint256 typeID) external pure override returns (bool) { + return typeID == TYPE_VALIDATOR; + } + + function isInitialized( + address // smartAccount + ) + external + pure + returns (bool) + { + return false; + } + + function validateSignatureWithData( + bytes32, + bytes calldata, + bytes calldata + ) + external + pure + override + returns (bool validSig) + { + return false; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.changeset/config.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/.changeset/config.json new file mode 100644 index 0000000..66794fa --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/.codecov.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.codecov.yml new file mode 100644 index 0000000..4cec4ef --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/.codecov.yml @@ -0,0 +1,16 @@ +comment: off +github_checks: + annotations: false +coverage: + status: + patch: + default: + target: 95% + only_pulls: true + project: + default: + threshold: 1% +ignore: + - "test" + - "contracts/mocks" + - "contracts/vendor" diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.editorconfig b/typescript/packages/account-modules/lib/openzeppelin-contracts/.editorconfig new file mode 100644 index 0000000..f162e8d --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/bug_report.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..35ad097 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..4018cef --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/feature_request.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..ff596b0 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..2394518 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml new file mode 100644 index 0000000..78c286c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml @@ -0,0 +1,51 @@ +name: Compare gas costs +description: Compare gas costs between branches +inputs: + token: + description: GitHub token, required to access GitHub API + required: true + report: + description: Path to the report to compare + required: false + default: gasReporterOutput.json + out_report: + description: Path to save the output report + required: false + default: ${{ github.ref_name }}.gasreport.json + ref_report: + description: Path to the reference report for comparison + 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@v4 + with: + name: gasreport + overwrite: true + path: ${{ inputs.out_report }} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/setup/action.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/setup/action.yml new file mode 100644 index 0000000..3c5fc60 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/setup/action.yml @@ -0,0 +1,22 @@ +name: Setup +description: Common environment setup + +runs: + using: composite + steps: + - uses: actions/setup-node@v4 + with: + node-version: 20.x + - uses: actions/cache@v4 + 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: stable diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/storage-layout/action.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/storage-layout/action.yml new file mode 100644 index 0000000..fb68d5f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/storage-layout/action.yml @@ -0,0 +1,57 @@ +name: Compare storage layouts +description: Compare storage layouts between branches +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@v4 + with: + name: layout + overwrite: true + path: ${{ inputs.out_layout }} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/actionlint.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/actionlint.yml new file mode 100644 index 0000000..3e42c8a --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/changeset.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/changeset.yml new file mode 100644 index 0000000..efc5c53 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/checks.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/checks.yml new file mode 100644 index 0000000..6aca7f3 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/checks.yml @@ -0,0 +1,132 @@ +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=8192 + +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 + # Needed for "eth-gas-reporter" to produce a "gasReporterOutput.json" as documented in + # https://github.com/cgewecke/eth-gas-reporter/blob/v0.2.27/docs/gasReporterOutput.md + CI: true + 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 pragma consistency between files + run: npm run test:pragma + - name: Check procedurally 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@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 pragma consistency between files + run: npm run test:pragma + - name: Check storage layout + uses: ./.github/actions/storage-layout + 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 -vvv + + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - name: Run coverage + run: npm run coverage + - uses: codecov/codecov-action@v5 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + harnesses: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - name: Compile harnesses + run: | + make -C certora apply + npm run compile:harnesses + + slither: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - uses: crytic/slither-action@v0.4.1 + + codespell: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run CodeSpell + uses: codespell-project/actions-codespell@v2.1 + with: + check_hidden: true + check_filenames: true + skip: package-lock.json,*.pdf,vendor diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/docs.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/docs.yml new file mode 100644 index 0000000..04b8131 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/formal-verification.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/formal-verification.yml new file mode 100644 index 0000000..86acca7 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/formal-verification.yml @@ -0,0 +1,86 @@ +name: formal verification + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - labeled + workflow_dispatch: {} + +env: + PIP_VERSION: '3.11' + 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@v5 + with: + python-version: ${{ env.PIP_VERSION }} + cache: 'pip' + cache-dependency-path: 'fv-requirements.txt' + - name: Install python packages + run: pip install -r fv-requirements.txt + - name: Install java + uses: actions/setup-java@v4 + 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 }} + + halmos: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - name: Install python + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PIP_VERSION }} + cache: 'pip' + cache-dependency-path: 'fv-requirements.txt' + - name: Install python packages + run: pip install -r fv-requirements.txt + - name: Run Halmos + run: halmos --match-test '^symbolic|^testSymbolic' -vv diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/release-cycle.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/release-cycle.yml new file mode 100644 index 0000000..02d5478 --- /dev/null +++ b/typescript/packages/account-modules/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@v7 + 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@v7 + 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@v7 + 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@v7 + 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 + id-token: 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@v4 + 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 }} + NPM_CONFIG_PROVENANCE: true + - name: Create Github Release + uses: actions/github-script@v7 + 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 + uses: actions/download-artifact@v4 + 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@v7 + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/upgradeable.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/upgradeable.yml new file mode 100644 index 0000000..46bf15a --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/.gitignore b/typescript/packages/account-modules/lib/openzeppelin-contracts/.gitignore new file mode 100644 index 0000000..50f1bf5 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/.gitignore @@ -0,0 +1,67 @@ +*.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 + +# macOS +.DS_Store + +# IntelliJ IDE +.idea + +# docs artifacts +docs/modules/api +build/site + +# 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/typescript/packages/account-modules/lib/openzeppelin-contracts/.gitmodules b/typescript/packages/account-modules/lib/openzeppelin-contracts/.gitmodules new file mode 100644 index 0000000..4939cd2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/.gitmodules @@ -0,0 +1,10 @@ +[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 +[submodule "lib/halmos-cheatcodes"] + path = lib/halmos-cheatcodes + url = https://github.com/a16z/halmos-cheatcodes diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.husky/pre-commit b/typescript/packages/account-modules/lib/openzeppelin-contracts/.husky/pre-commit new file mode 100755 index 0000000..4738b05 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/.husky/pre-commit @@ -0,0 +1,2 @@ +npm run test:generation +npx lint-staged diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.mocharc.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/.mocharc.js new file mode 100644 index 0000000..920662d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/.mocharc.js @@ -0,0 +1,4 @@ +module.exports = { + require: 'hardhat/register', + timeout: 4000, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.prettierrc b/typescript/packages/account-modules/lib/openzeppelin-contracts/.prettierrc new file mode 100644 index 0000000..39c004c --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/.solcover.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/.solcover.js new file mode 100644 index 0000000..f079998 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/.solcover.js @@ -0,0 +1,21 @@ +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, + }, + // Work around stack too deep for coverage + configureYulOptimizer: true, + solcOptimizerDetails: { + yul: true, + yulDetails: { + optimizerSteps: '', + }, + }, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/CHANGELOG.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/CHANGELOG.md new file mode 100644 index 0000000..c608394 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/CHANGELOG.md @@ -0,0 +1,1278 @@ +# Changelog + + +## 5.4.0 (2025-07-17) + +### Breaking changes + +- Update minimum pragma to 0.8.24 in `SignatureChecker`, `Governor` and Governor's extensions. ([#5716](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5716)). + +### Pragma changes + +- Reduced pragma requirement of interface files + +### Changes by category + +#### Account + +- `Account`: Added a simple ERC-4337 account implementation with minimal logic to process user operations. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657)) +- `AccountERC7579`: Extension of `Account` that implements support for ERC-7579 modules of type executor, validator, and fallback handler. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657)) +- `AccountERC7579Hooked`: Extension of `AccountERC7579` that implements support for ERC-7579 hook modules. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657)) +- `EIP7702Utils`: Add a library for checking if an address has an EIP-7702 delegation in place. ([#5587](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5587)) +- `IERC7821`, `ERC7821`: Interface and logic for minimal batch execution. No support for additional `opData` is included. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657)) + +#### Governance + +- `GovernorNoncesKeyed`: Extension of `Governor` that adds support for keyed nonces when voting by sig. ([#5574](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5574)) + +#### Tokens + +- `ERC20Bridgeable`: Implementation of ERC-7802 that makes an ERC-20 compatible with crosschain bridges. ([#5739](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5739)) + +#### Cryptography + +##### Signers + +- `AbstractSigner`, `SignerECDSA`, `SignerP256`, and `SignerRSA`: Add an abstract contract and various implementations for contracts that deal with signature verification. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657)) +- `SignerERC7702`: Implementation of `AbstractSigner` for Externally Owned Accounts (EOAs). Useful with ERC-7702. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657)) +- `SignerERC7913`: Abstract signer that verifies signatures using the ERC-7913 workflow. ([#5659](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5659)) +- `MultiSignerERC7913`: Implementation of `AbstractSigner` that supports multiple ERC-7913 signers with a threshold-based signature verification system. ([#5659](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5659)) +- `MultiSignerERC7913Weighted`: Extension of `MultiSignerERC7913` that supports assigning different weights to each signer, enabling more flexible governance schemes. ([#5741](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5741)) + +##### Verifiers + +- `ERC7913P256Verifier` and `ERC7913RSAVerifier`: Ready to use ERC-7913 verifiers that implement key verification for P256 (secp256r1) and RSA keys. ([#5659](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5659)) + +##### Other + +- `SignatureChecker`: Add support for ERC-7913 signatures alongside existing ECDSA and ERC-1271 signature verification. ([#5659](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5659)) +- `ERC7739`: An abstract contract to validate signatures following the rehashing scheme from `ERC7739Utils`. ([#5664](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5664)) +- `ERC7739Utils`: Add a library that implements a defensive rehashing mechanism to prevent replayability of smart contract signatures based on the ERC-7739. ([#5664](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5664)) + +#### Structures + +- `EnumerableMap`: Add support for `BytesToBytesMap` type. ([#5658](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5658)) +- `EnumerableMap`: Add `keys(uint256,uint256)` that returns a subset (slice) of the keys in the map. ([#5713](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5713)) +- `EnumerableSet`: Add support for `StringSet` and `BytesSet` types. ([#5658](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5658)) +- `EnumerableSet`: Add `values(uint256,uint256)` that returns a subset (slice) of the values in the set. ([#5713](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5713)) + +#### Utils + +- `Arrays`: Add `unsafeAccess`, `unsafeMemoryAccess` and `unsafeSetLength` for `bytes[]` and `string[]`. ([#5568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5568)) +- `Blockhash`: Add a library that provides access to historical block hashes using EIP-2935's history storage, extending the standard 256-block limit to 8191 blocks. ([#5642](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5642)) +- `Bytes`: Fix `lastIndexOf(bytes,byte,uint256)` with empty buffers and finite position to correctly return `type(uint256).max` instead of accessing uninitialized memory sections. ([#5797](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5797)) + +## 5.3.0 (2025-04-09) + +### Breaking Changes + +- Replace `GovernorCountingOverridable.VoteReceipt` struct parameter member names `hasOverriden` and `overridenWeight` for `hasOverridden` and `overriddenWeight` respectively. + +#### Custom error changes + +- Replace `GovernorAlreadyOverridenVote` with `GovernorAlreadyOverriddenVote`. +- Replace `GovernorOnlyProposer` with `GovernorUnableToCancel`. + +### Changes by category + +#### Account + +- `ERC4337Utils`: Update the `hash` function to call `getUserOpHash` on the specified entrypoint and add an `ENTRYPOINT_V08` constant. ([#5614](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5614)) +- `ERC7579Utils`: Add ABI decoding checks on calldata bounds within `decodeBatch`. ([#5371](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5371)) +- `ERC7579Utils`: Replace `address(0)` with `address(this)` during execution for calldata compression efficiency. ([#5614](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5614)) + +#### Governance + +- `IGovernor`: Add the `getProposalId` function to the governor interface. ([#5290](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5290)) +- `GovernorProposalGuardian`: Add a governance extension that defines a proposal guardian who can cancel proposals at any stage in their lifecycle. ([#5303](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5303)) +- `GovernorSequentialProposalId`: Adds a `Governor` extension that sequentially numbers proposal ids instead of using the hash. ([#5290](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5290)) +- `GovernorSuperQuorum`: Add a governance extension to support a super quorum. Proposals that meet the super quorum (and have a majority of for votes) advance to the `Succeeded` state before the proposal deadline. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) +- `GovernorVotesSuperQuorumFraction`: Add a variant of the `GovernorSuperQuorum` extensions where the super quorum is expressed as a fraction of the total supply. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) +- `TimelockController`: Receive function is now virtual. ([#5509](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5509)) + +#### Structures + +- `EnumerableSet`: Add `clear` function to EnumerableSets which deletes all values in the set. ([#5486](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5486)) +- `EnumerableMap`: Add `clear` function to EnumerableMaps which deletes all entries in the map. ([#5486](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5486)) +- `MerkleTree`: Add an update function that replaces a previously inserted leaf with a new value, updating the tree root along the way. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) + +#### Tokens + +- `ERC4626`: Use the `asset` getter in `totalAssets`, `_deposit` and `_withdraw`. ([#5322](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5322)) +- `IERC6909`: Add the interface for ERC-6909. ([#5343](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5343)) +- `ERC6909`: Add a standard implementation of ERC6909. ([#5394](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5394)) +- `ERC6909TokenSupply`: Add an extension of ERC6909 which tracks total supply for each token id. ([#5394](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5394)) +- `ERC6909Metadata`: Add an extension of ERC6909 which adds metadata functionality. ([#5394](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5394)) +- `ERC6909ContentURI`: Add an extension of ERC6909 which adds content URI functionality. ([#5394](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5394)) +- `SafeERC20`: Add `trySafeTransfer` and `trySafeTransferFrom` that do not revert and return false if the transfer is not successful. ([#5483](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5483)) + +#### Other + +- `Address`: bubble up revert data on `sendValue` failed call. ([#5379](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5379)) +- `Calldata`: Library with `emptyBytes` and `emptyString` functions to generate empty `bytes` and `string` calldata types. ([#5422](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5422)) +- `ERC2771Forwarder`: Expose the `_isTrustedByTarget` internal function to check whether a target trusts the forwarder. ([#5416](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5416)) +- `Hashes`: Expose `efficientKeccak256` for hashing non-commutative pairs of bytes32 without allocating extra memory. ([#5442](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5442)) +- `Initializable`: Add `_initializableStorageSlot` function that returns a pointer to the storage struct. The function allows customizing with a custom storage slot with an `override`. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) +- `Math`: Add `add512`, `mul512` and `mulShr`. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) +- `Math`: Add saturating arithmetic operations `saturatingAdd`, `saturatingSub` and `saturatingMul`. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) +- `MessageHashUtils`: Add `toDataWithIntendedValidatorHash(address, bytes32)`. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) +- `P256`: Adjust precompile detection in `verifyNative` to consider empty `returndata` on invalid verification. Previously, invalid signatures would've reverted with a `MissingPrecompile` error in chains with RIP-7212 support. ([#5620](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5620)) +- `Pausable`: Stop explicitly setting `paused` to `false` during construction. ([#5448](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5448)) +- `Strings`: Add `espaceJSON` that escapes special characters in JSON strings. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) + +## 5.2.0 (2025-01-08) + +### Breaking Changes + +#### Custom error changes + +This version comes with changes to the custom error identifiers. Contracts previously depending on the following errors should be replaced accordingly: + +- Replace `Errors.FailedCall` with a bubbled-up revert reason in `Address.sendValue`. + +### Changes by category + +#### General + +- Update some pragma directives to ensure that all file requirements match that of the files they import. ([#5273](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5273)) + +#### Account + +- `ERC4337Utils`: Add a reusable library to manipulate user operations and interact with ERC-4337 contracts ([#5274](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5274)) +- `ERC7579Utils`: Add a reusable library to interact with ERC-7579 modular accounts ([#5274](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5274)) + +#### Governance + +- `GovernorCountingOverridable`: Add a governor counting module that enables token holders to override the vote of their delegate. ([#5192](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5192)) +- `VotesExtended`: Create an extension of `Votes` which checkpoints balances and delegates. ([#5192](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5192)) + +### Proxy + +- `Clones`: Add `cloneWithImmutableArgs` and `cloneDeterministicWithImmutableArgs` variants that create clones with per-instance immutable arguments. The immutable arguments can be retrieved using `fetchCloneArgs`. The corresponding `predictDeterministicWithImmutableArgs` function is also included. ([#5109](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5109)) + +### Tokens + +- `ERC1363Utils`: Add helper similar to the existing `ERC721Utils` and `ERC1155Utils` ([#5133](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5133)) + +### Utils + +- `Address`: bubble up revert data on `sendValue` failed call ([#5418](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5418)) +- `Bytes`: Add a library of common operations that operate on `bytes` objects. ([#5252](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5252)) +- `CAIP2` and `CAIP10`: Add libraries for formatting and parsing CAIP-2 and CAIP-10 identifiers. ([#5252](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5252)) +- `NoncesKeyed`: Add a variant of `Nonces` that implements the ERC-4337 entrypoint nonce system. ([#5272](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5272)) +- `Packing`: Add variants for packing `bytes10` and `bytes22` ([#5274](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5274)) +- `Strings`: Add `parseUint`, `parseInt`, `parseHexUint` and `parseAddress` to parse strings into numbers and addresses. Also provide variants of these functions that parse substrings, and `tryXxx` variants that do not revert on invalid input. ([#5166](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5166)) + +## 5.1.0 (2024-10-17) + +### Breaking changes + +- `ERC1967Utils`: Removed duplicate declaration of the `Upgraded`, `AdminChanged` and `BeaconUpgraded` events. These events are still available through the `IERC1967` interface located under the `contracts/interfaces/` directory. Minimum pragma version is now 0.8.21. +- `Governor`, `GovernorCountingSimple`: The `_countVote` virtual function now returns an `uint256` with the total votes cast. This change allows for more flexibility for partial and fractional voting. Upgrading users may get a compilation error that can be fixed by adding a return statement to the `_countVote` function. + +#### Custom error changes + +This version comes with changes to the custom error identifiers. Contracts previously depending on the following errors should be replaced accordingly: + +- Replace `Address.FailedInnerCall` with `Errors.FailedCall` +- Replace `Address.AddressInsufficientBalance` with `Errors.InsufficientBalance` +- Replace `Clones.Create2InsufficientBalance` with `Errors.InsufficientBalance` +- Replace `Clones.ERC1167FailedCreateClone` with `Errors.FailedDeployment` +- Replace `Clones.Create2FailedDeployment` with `Errors.FailedDeployment` +- `SafeERC20`: Replace `Address.AddressEmptyCode` with `SafeERC20FailedOperation` if there is no code at the token's address. +- `SafeERC20`: Replace generic `Error(string)` with `SafeERC20FailedOperation` if the returned data can't be decoded as `bool`. +- `SafeERC20`: Replace generic `SafeERC20FailedOperation` with the revert message from the contract call if it fails. + +### Changes by category + +#### General + +- `AccessManager`, `VestingWallet`, `TimelockController` and `ERC2771Forwarder`: Added a public `initializer` function in their corresponding upgradeable variants. ([#5008](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5008)) + +#### Access + +- `AccessControlEnumerable`: Add a `getRoleMembers` method to return all accounts that have `role`. ([#4546](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4546)) +- `AccessManager`: Allow the `onlyAuthorized` modifier to restrict functions added to the manager. ([#5014](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5014)) + +#### Finance + +- `VestingWalletCliff`: Add an extension of the `VestingWallet` contract with an added cliff. ([#4870](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4870)) + +#### Governance + +- `GovernorCountingFractional`: Add a governor counting module that allows distributing voting power amongst 3 options (For, Against, Abstain). ([#5045](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5045)) +- `Votes`: Set `_moveDelegateVotes` visibility to internal instead of private. ([#5007](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5007)) + +#### Proxy + +- `Clones`: Add version of `clone` and `cloneDeterministic` that support sending value at creation. ([#4936](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4936)) +- `TransparentUpgradeableProxy`: Make internal `_proxyAdmin()` getter have `view` visibility. ([#4688](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4688)) +- `ProxyAdmin`: Fixed documentation for `UPGRADE_INTERFACE_VERSION` getter. ([#5031](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5031)) + +#### Tokens + +- `ERC1363`: Add implementation of the token payable standard allowing execution of contract code after transfers and approvals. ([#4631](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4631)) +- `ERC20TemporaryApproval`: Add an ERC-20 extension that implements temporary approval using transient storage, based on ERC7674 (draft). ([#5071](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5071)) +- `SafeERC20`: Add "relaxed" function for interacting with ERC-1363 functions in a way that is compatible with EOAs. ([#4631](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4631)) +- `SafeERC20`: Document risks of `safeIncreaseAllowance` and `safeDecreaseAllowance` when associated with ERC-7674. ([#5262](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5262)) +- `ERC721Utils` and `ERC1155Utils`: Add reusable libraries with functions to perform acceptance checks on `IERC721Receiver` and `IERC1155Receiver` implementers. ([#4845](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4845)) +- `ERC1363Utils`: Add helper similar to the existing ERC721Utils and ERC1155Utils. ([#5133](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5133)) + +#### Utils + +- `Arrays`: add a `sort` functions for `address[]`, `bytes32[]` and `uint256[]` memory arrays. ([#4846](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4846)) +- `Arrays`: add new functions `lowerBound`, `upperBound`, `lowerBoundMemory` and `upperBoundMemory` for lookups in sorted arrays with potential duplicates. ([#4842](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4842)) +- `Arrays`: deprecate `findUpperBound` in favor of the new `lowerBound`. ([#4842](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4842)) +- `Base64`: Add `encodeURL` following section 5 of RFC4648 for URL encoding ([#4822](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4822)) +- `Comparator`: A library of comparator functions, useful for customizing the behavior of the Heap structure. ([#5084](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5084)) +- `Create2`: Bubbles up returndata from a deployed contract that reverted during construction. ([#5052](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5052)) +- `Create2`, `Clones`: Mask `computeAddress` and `cloneDeterministic` outputs to produce a clean value for an `address` type (i.e. only use 20 bytes) ([#4941](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4941)) +- `Errors`: New library of common custom errors. ([#4936](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4936)) +- `Hashes`: A library with commonly used hash functions. ([#3617](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3617)) +- `Packing`: Added a new utility for packing, extracting and replacing bytesXX values. ([#4992](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4992)) +- `Panic`: Add a library for reverting with panic codes. ([#3298](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3298)) +- `ReentrancyGuardTransient`: Added a variant of `ReentrancyGuard` that uses transient storage. ([#4988](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4988)) +- `Strings`: Added a utility function for converting an address to checksummed string. ([#5067](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5067)) +- `SlotDerivation`: Add a library of methods for derivating common storage slots. ([#4975](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4975)) +- `TransientSlot`: Add primitives for operating on the transient storage space using a typed-slot representation. ([#4980](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4980)) + +##### Cryptography + +- `SignatureChecker`: refactor `isValidSignatureNow` to avoid validating ECDSA signatures if there is code deployed at the signer's address. ([#4951](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4951)) +- `MerkleProof`: Add variations of `verify`, `processProof`, `multiProofVerify` and `processMultiProof` (and equivalent calldata version) with support for custom hashing functions. ([#4887](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4887)) +- `P256`: Library for verification and public key recovery of P256 (aka secp256r1) signatures. ([#4881](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4881)) +- `RSA`: Library to verify signatures according to RFC 8017 Signature Verification Operation ([#4952](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4952)) + +#### Math + +- `Math`: add an `invMod` function to get the modular multiplicative inverse of a number in Z/nZ. ([#4839](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4839)) +- `Math`: Add `modExp` function that exposes the `EIP-198` precompile. Includes `uint256` and `bytes memory` versions. ([#3298](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3298)) +- `Math`: Custom errors replaced with native panic codes. ([#3298](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3298)) +- `Math`, `SignedMath`: Add a branchless `ternary` function that computes`cond ? a : b` in constant gas cost. ([#4976](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4976)) +- `SafeCast`: Add `toUint(bool)` for operating on `bool` values as `uint256`. ([#4878](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4878)) + +#### Structures + +- `CircularBuffer`: Add a data structure that stores the last `N` values pushed to it. ([#4913](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4913)) +- `DoubleEndedQueue`: Custom errors replaced with native panic codes. ([#4872](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4872)) +- `EnumerableMap`: add `UintToBytes32Map`, `AddressToAddressMap`, `AddressToBytes32Map` and `Bytes32ToAddressMap`. ([#4843](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4843)) +- `Heap`: A data structure that implements a heap-based priority queue. ([#5084](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5084)) +- `MerkleTree`: A data structure that allows inserting elements into a merkle tree and updating its root hash. ([#3617](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3617)) + +## 5.0.2 (2024-02-29) + +- `Base64`: Fix issue where dirty memory located just after the input buffer is affecting the result. ([#4926](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4926)) + +## 5.0.1 (2023-12-07) + +- `ERC2771Context` and `Context`: Introduce a `_contextPrefixLength()` getter, used to trim extra information appended to `msg.data`. +- `Multicall`: Make aware of non-canonical context (i.e. `msg.sender` is not `_msgSender()`), allowing compatibility with `ERC2771Context`. + +## 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), [#4489](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4489)) +- 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)`. + +#### More about ERC1155 + +Batch transfers will now emit `TransferSingle` if the batch consists of a single token, while in previous versions the `TransferBatch` event would be used for all transfers initiated through `safeBatchTransferFrom`. Both behaviors are compliant with the ERC-1155 specification. + +#### ERC165Storage + +Users that were registering EIP-165 interfaces with `_registerInterface` from `ERC165Storage` should instead do 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); +} +``` + +#### SafeMath + +Methods in SafeMath superseded by native overflow checks in Solidity 0.8.0 were removed along with operations providing an interface for revert strings. The remaining methods were moved to `utils/Math.sol`. + +```diff +- import "@openzeppelin/contracts/utils/math/SafeMath.sol"; ++ import "@openzeppelin/contracts/utils/math/Math.sol"; + + function tryOperations(uint256 x, uint256 y) external view { +- (bool overflowsAdd, uint256 resultAdd) = SafeMath.tryAdd(x, y); ++ (bool overflowsAdd, uint256 resultAdd) = Math.tryAdd(x, y); +- (bool overflowsSub, uint256 resultSub) = SafeMath.trySub(x, y); ++ (bool overflowsSub, uint256 resultSub) = Math.trySub(x, y); +- (bool overflowsMul, uint256 resultMul) = SafeMath.tryMul(x, y); ++ (bool overflowsMul, uint256 resultMul) = Math.tryMul(x, y); +- (bool overflowsDiv, uint256 resultDiv) = SafeMath.tryDiv(x, y); ++ (bool overflowsDiv, uint256 resultDiv) = Math.tryDiv(x, y); + // ... + } +``` + +#### 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 was changed. This is the case for `Initializable` and all the upgradeable contracts since they now use namespaced storage locations. Any system relying on storage locations for retrieving data or detecting capabilities should be updated to support these new locations. + +## 4.9.6 (2024-02-29) + +- `Base64`: Fix issue where dirty memory located just after the input buffer is affecting the result. ([#4929](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4929)) + +## 4.9.5 (2023-12-08) + +- `Multicall`: Make aware of non-canonical context (i.e. `msg.sender` is not `_msgSender()`), allowing compatibility with `ERC2771Context`. Patch duplicated `Address.functionDelegateCall` in v4.9.4 (removed). + +## 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 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/typescript/packages/account-modules/lib/openzeppelin-contracts/CODE_OF_CONDUCT.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..f7cdce9 --- /dev/null +++ b/typescript/packages/account-modules/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, socioeconomic 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/typescript/packages/account-modules/lib/openzeppelin-contracts/CONTRIBUTING.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/CONTRIBUTING.md new file mode 100644 index 0000000..1a44cc2 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/FUNDING.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/FUNDING.json new file mode 100644 index 0000000..0a362ba --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/FUNDING.json @@ -0,0 +1,10 @@ +{ + "drips": { + "ethereum": { + "ownedBy": "0xAeb37910f93486C85A1F8F994b67E8187554d664" + } + }, + "opRetro": { + "projectId": "0x939241afa4c4b9e1dda6b8250baa8f04fa8b0debce738cfd324c0b18f9926d25" + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/GUIDELINES.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/GUIDELINES.md new file mode 100644 index 0000000..deafed0 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/GUIDELINES.md @@ -0,0 +1,155 @@ +# 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 is just as important (if not more so) than the code itself, and should be written to 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 workflows](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. ERC-20) 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 ..., { + ``` + +* Return values are generally not named, unless they are not immediately clear or there are multiple return values. + + ```solidity + function expiration() public view returns (uint256) { // Good + function hasRole() public view returns (bool isMember, uint32 currentDelay) { // Good + ``` + +* 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/typescript/packages/account-modules/lib/openzeppelin-contracts/LICENSE b/typescript/packages/account-modules/lib/openzeppelin-contracts/LICENSE new file mode 100644 index 0000000..367f411 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016-2025 Zeppelin Group Ltd + +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/typescript/packages/account-modules/lib/openzeppelin-contracts/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/README.md new file mode 100644 index 0000000..2f92281 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/README.md @@ -0,0 +1,108 @@ +# OpenZeppelin + +[![Github Release](https://img.shields.io/github/v/tag/OpenZeppelin/openzeppelin-contracts.svg?filter=v*&sort=semver&label=github)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/latest) +[![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://forum.openzeppelin.com/) + +**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 mission-critical developer security platform to code, audit, deploy, monitor, and operate with confidence. + +> [!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 (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' 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/typescript/packages/account-modules/lib/openzeppelin-contracts/RELEASING.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/RELEASING.md new file mode 100644 index 0000000..6820d40 --- /dev/null +++ b/typescript/packages/account-modules/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 consistent and reliable. + +## Changesets + +[Changesets](https://github.com/changesets/changesets/) are 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/typescript/packages/account-modules/lib/openzeppelin-contracts/SECURITY.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/SECURITY.md new file mode 100644 index 0000000..0d09b3e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/SECURITY.md @@ -0,0 +1,43 @@ +# 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. Learn more about release candidates at [`RELEASING.md`](./RELEASING.md). + +## 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 | +| ------- | ----------------------- | -------------------- | +| 5.x | :white_check_mark: | :white_check_mark: | +| 4.9 | :white_check_mark: | :x: | +| 3.4 | :white_check_mark: | :x: | +| 2.5 | :x: | :x: | +| < 2.0 | :x: | :x: | + +Note as well that the Solidity language itself only guarantees security updates for the latest release. + +## Legal + +Blockchain is a nascent technology and carries a high level of risk and uncertainty. OpenZeppelin makes certain software available under open source licenses, which disclaim all warranties in relation to the project and which limits the liability of OpenZeppelin. Subject to any particular licensing terms, your use of the project is governed by the terms found at [www.openzeppelin.com/tos](https://www.openzeppelin.com/tos) (the "Terms"). As set out in the Terms, you are solely responsible for any use of the project and you assume all risks associated with any such use. This Security Policy in no way evidences or represents an ongoing duty by any contributor, including OpenZeppelin, to correct any issues or vulnerabilities or alert you to all or any of the risks of utilizing the project. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2017-03.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2017-03.md new file mode 100644 index 0000000..d54174e --- /dev/null +++ b/typescript/packages/account-modules/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 warranties 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 bug free 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 executed 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 prime time. 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 recommend 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 is 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/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2018-10.pdf b/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2018-10.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d5bf12741c8a6d44ed597de7204fde72d91dec35 GIT binary patch literal 1000527 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
    7sZejb^ebhvd`}ug{GNT#cAH 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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 z299bkUuyCSkt&y6pO1G1A@&eod__0#2u^#5ZlPjSZsAK4`4kWqNz?lrjZ{<%%GJRa zDQukr=;Rvo

    ^CJE9mFB0a-Fbn4;Bxwv*As7xDygo?RFOfXCDXJVs>x90tPYh^NB zE07bJI(d2N5BY{Hh_@n{0=c-o<;3btBwvavHyy4_D&foV`*5ra+Q80X9$h;Khq+gBbOkuB@s#;?d9#+|7fz7)s z3)knH4V&RKE)I<)v%1648-mA^-eZ^U7md}GvQ>4k#GA{VDi<&CQa~etZOYzsw<%L_%(|`K?VBB@!Vh;1?p@>c=MOl0 zP4&gBa{!CUVs4Www|EB+XgZG6ifUHq>1rgB;l`dqkMm1^ha1?^tXI|-_u7V z+pnLjS;$Jc6ySJ~XxPZGd-|ee2*18R+m~PrNKC!=*SFIu$#(k+(vO%ORv54bt$n0Z z8LwB^cPZkWY$ooIpPTE<@Nnt%_9#{f8JPi+U1vm8KgZYHxC-{fpUg~3MNU5X3iG_v zZw(}!BwL=!+1a?)lRTDQAkzBM?0GXlF|O^~Tqgx2#qRG*`cq8tE089}ztS`IoumGd zq<_zy8T1T4z=>atG%@~_4zcgl^ydQp4Mj}( z|8{*Uk1jCdMBK(jSqg@5hmU1pWmD{^5P=pC(P;-OK-{+Vu2{|CJ;) zAC6Iv;GSN-*T00jQ_+Bk1~yJVR){Bq|dn4vfuSDo`BsTdbZ;*OKE zz3JrwbcNINQ!y_Z#XHbEz%q%C=Vn)ApQUmtqOhM|53X~>I(%PtHTLJjlsB{JEbmI{ z2&HCxO*-5~Ra2aelP^5A6KX9o=*@0-*`Dw<@ zkZr7)-*9xbi#){pFENz!Amg=zt;IR|9`ZF0!u1;hX@8E$C6LUo$R4T7@F!cV&xy_m z1V5Ydd*-xmm8y%Ip}Xo*h)e(v8jRAGlbd13Ma(ugu=WCW03s2u8IdB%74rd}*J{Ek zpp#kuJW)%4$fV7g^C@^-wj-4XfJ<#re~_Ar_K4HfTH|Rz+fWZ!ZIV4;SRSpWJd&qc zB_297kr|GfY(7^dukf>VOa#icC=h>hnT>=JO9&)6lxw$lWKp`~O(Xd*le%m`zC(;H z?ewRNT|AQW#3gKwi3PfdK7-rc;3d+`Qll8hL^%fOcl=t3n91j%S#CEBE&!RWC=`_X z14V1_d1{dW_!V!wDnH)glHd*Wx}>V)Y&e5EIN=;N}88&)Ckb;e$CWlURY-*mcj>%CQ^W>h}hRtKL-xqW+L?FZoLHgR>AAMgXFp&-B6s zW16seRYU>monfMli5Ygg0eO~V{oACD3Qui;QjO;IHUg5wG$3&`z4D->C6SCXYMgaM zK54osu+^KHcg%+y=er}1CPMfo^2s()dm6R6_(p+!;G7RXSqLp1a%^(RubXZLr*e}O zNjex)V4u#AEFj$ENP!n~Et-@OnQ=^|0g76F0V%oVtVWE4o5qrhEFgrx+mQSkWuqqc zrK@SOk&0-Yd1q{8KPm&g=mR%q+D>4l=@r=t2ezx|3dAi@{eftjLhsP(A}Wa2w4*=;i*dmV1m-&R zhtLJMg?DSZ2W$Ct(Psm7BXuX6V)8gF2swwkTY?87BI68dg z_>}Fpo@F%=sI2BS2q1z?tqPixeW#=`%`tcVK)PXAqTPzQuv7U}A;fkOO05CR5#bE< z@p>p|Df%-zcZ+0Ox%6Pk1i#>?jPJ!RDPZ^XLPr?hAB5Hpjug2(o~TtWSj0Qg5tkVf zhs(`Ta%CrDWS4v;#-B* zWND!DP5>-dZEA=x8Cf6>LIKXRD1oHKWcPzNXL-9xASE)2Zq&jsW6#1by*ZU*E=?eX zF=3Bt&o*}kyreZ&BNS@U=M9|$&5&?>mp%T}lTCsG$=-YXu+FLd!}JUMlz|0{d=Alx z8I!JbVQu8fNrDIxUzWR!$d40Qmh!d6Ky%YZD7!o#Mr<@(S2!lDSBX^EXy-*W<&IZ! z06!{Ter)SW6GbZn;`%5z>=J}i6y1WtGX{WDI3yp-a_`KE>2VE)V-*-A(|7^1ICoQ) z+kh1>R~Lg+G}%Q#mF1$i_{rMUO?KIQQ+n@M)~VCC0xi3H%4KS|^T36Iy~5hSt13QU zGZ}{5UA>Zd3{tHAVa^JTg8ZFE){3i!xNGK}JsD(hVGzEer1`coS$1kx(n<)t$z5Rk$Y?#D6D>fqY98`|w+$ zSW$t>zY@i$5dWPhMlCI+n%kRaYC!|M7d=-3VSw_rC&5*>m!BdjWq94)(=LHewaUy* z_)>{77sr4tuGV_xGn*JsTT5kMQzg>v|0IfmlS}??iDmkeuBPu7?*D8~|AC2rJDAAy zCtXe7OWQvJ|9Y&6>4&+rKZ1$hk0bvG{0j>F!z=Ya4HKDuI6D8_q)1Q8@?W+!Wy?iD zIFH-%x&Augf>ziLTHFbRWNhIOFw*f1QcP7kHNvV*Qox5(4p(bOXJrv_a&K{)@_UD! z{Q828c(}C%bou75;OM`@47VsG&}g(tvkF%xNswBZ0q=`^{N{ zPAq5loYsJtR(Q(n!#ZeDeLQ-*z($QIe2YcBvl7-G2!sU~V&~nkqLJmC?}4T1NB5#P z!!e-b)5*J#mY{qDPG(1|o72hLBwsK4%x=X8!tj9_SoTA0BbzD6wgjothTImE!JwIg zdZi}GRGq}GmGJBF&D^~{tI#78VM5$R#g6pTrAd4@ua-el;T)Ej1(sRtQMoK~^|* zao>ovX4Osloc?WR8lb>ET?UNkv-&j-#~>Z&I(r zMt<&6;F#=0s_-u00nSvXv%vC&@x!*uQ1p$!YQr5<3k&osocnHi)xoW5I^Sv%QSgBN z5;Rz~HFmxOR8iD8RtUs39-7q4@{0E~*T*-d(W@%%kE+nIehw*l=ij&jyDJP350u>j z=T}eTEnP=u5;;1OU>cQ@l1sK0^0tHOc9!?`@IE%=qC|Tpw(4Ex$mQovbkOLY=BVn} zBI*+G3q@6z8*u@b8~596mqIi|VFOCGP-77MvRCZ1kMC#RGwxDWGw?Z>RtbgL*lW4; zV`?fyet@+}WccES4sD~tba`mxa!SQu+aZ@^qoTA!A3NWD5@oM zD)kcLLy>hHVhG5It4ah+whhI1GXFK+!nKz!a65}&tSoAzL$j33rNLR;V;4zv(z_|p zo=`g-bYs0m2a0?Xo9FCR8rQ?sqC-+!IbY{0W5XuV@1aCw-`5#)%mlqXnR+LeL93_+ z0n1|K=p*ec;h|CDRc_Pxk6UV{DSzS-&_508#5t+s-6#>ZV7>+a=5BUsP6?m zwss08d7%-9Q3FZO?g8&3gkpfSR3UUeA#ioacC>AQ(n})?>mIRQj`~AbtKFaRE~nVZ z4xgD)Io7(Wd8F;=sHc}Zav~e!yoX)NFN?2KA8=FA5tI`Li!3}qilLW?h{{&0H17r0 z+s~`|G!JPUCip?FX2_P5Y#&gc5Nq!Qj4T8snU0Jzh>F@ys_sb2Paor;II42=+y8_0 zAxcUbR{$W-)*NMbye)hib(>RV)z~gDwZef;uAx07qTd>Bm~XRLnV8pht{Mt-W5#*D zy@JN}d_%OK;YmnEA+RBleK@>xqR7e7J-O(p8-;|E_LC1|)|evSb~0kN(x6$MiH_Q2=bgv+0irpTkxlpcXUczHllPwqEYb!Ll|KnzS1d@?axPfOkikM z7SW>JMcfVX6L(j_!0Tfj_r<1D99SHgqAF5P>-Q7#^&{UtsCb+>iBpImjS4%Icu_jp zR3lR?V%);K^{e%IWM0pgWiXM=Nd7D!w6dcoQJf4*H4&UoTq~07QsrRu5l~#zh_9Bc zmNpW7t^hqjm@~r80wC`VN22masGB@V=nsS(v{)%hev?eJ!-~;`N29~ja$4JfIr%w( zRlogr>H>L#_Ef(45G?trG<%O@fSsfud=C5L+^%;4Yd~FS z0iaUh7>@s@lu=@guhN*#Qfcdb@ElfiqyoU8ZUZFRVH!J!OqQ&r;iKX_`c%&|Zz({Y zXmMR+UJy%mxL}xgng!EIO&!#`?UnNnP!o*G_<8<)CY;8tx&r8osrkNIVL^P)v^bf? zK=WBG_jL5s@-{Y$pMl^G2Ht6z*g%th@XtY%XTmblstUmq(+r(c;x~9pB>dLKK0LI@ z7#~r1^VtM%L9cMu<*4!2VfQ)nWA*vheaJL9e=zN?cia8yyu$oY^_Nar$xzNsTwpTF z*4c$uY(uvApVgKSx!skE1JDKRHjP3-=zXcX*yejvymHFGW;uoIkz~*u61c$ZYgx0$ ze24J74)D6qGvQ4P8|f-0Qa9pzff_3MsWe*p_nu&Usp4QC7wh8{UF}?&3Qip!k1bx| z-ES{En)yA=PfzPlEgbh4N@-O*n%b5<+nuiWM_<|>sZ^e7T3c4QGkW{npFNyyo12$b zSB}T$=MP#0=LNv3T1yMSybyYpK`RjQGwgwF&M}VAc`grcE^n|Nw$WWGn~T~2_}=g^ z6^DW}iLizGa)xhhPrrP7@0YW+`GT(GWwiAQ|03VOx`xmlXym`=`7MsRlVOeF_nXI` z!kk}$&wX1;|JRL`(*BDK{qkd_-(&9o-6i}d-1!yw9P?l4-~7J(;OBVfZ#!1X`~%YY zPYM72X=2QOrCam+>VuyP_+Na^SobeT6YCBBKhwl=|KG&_Z6(q3|KW20 z7wr3m`=`7A^}2iJKj{VgUfTW<_!kuT2QSzk@wxBEk$(jK1qJ>Awf$*6$Na<5`R9C& zj+O1d(!>@mFj(N+XTOh?24k)Oc6(9Io4fF;eBkj$5m;vpUdNBb5&|D@KRv4x6K$^A za8j(TT-dhv?`AMG;1*}qzI$D24+XNh_SjfV;x}3;CvNu?nn4r{gFu|>x5d=+peK2G zeQ}|GenBRf#j$2G6lKt9gwgZ}sc&tq6!L;EJggrKXeGCXI5@18`2;!TBuF!oIZhJO zTY%^v)9$BMfkK2~7{rf!WMqTvC_;^DBHnr4fwDE{6Z?insj`x)l(Vj6LW;%_wAUvS zYz&=brA^9RkVyDmHFd(NQ48C>Z#l?t*x+#=^QF)It#aG44BWVS?aYhqy@yQ~8e;yi zC-Ls^M2;tv4zlcE<&Ejc z0(fq;4+(Z{npUgj2CC*A{eAa~w#_?!Y~*#howxX9u_1G)ZHDF?Bl?Bz8mEIhca)N^ zDle>A%Y?fz=)_g$l4xig+)lNa9rjNzDy&bnD5BvmXhQ&u1n8I=h#FxVcQ>=nkqaST z6$)Y30l+|G*Wfbr5kBZ~fU>b&y=B$H>9*`(>1Rp5?{>ZZP@KjBar?~MYZb2Ys>PJj zy`egih5LFOd%j8!el-VqSG~_eJUUhQr6-^5%uEeCasV&Eaqs{HWCNiQ6|iI-0X+YU zHSs2MC6AeaWJ0`du%d32ilcPx&bD}ML7&+)y*GRv?K)bxYizuwikn?Gz8V?QD!GiJ zf8Yq5H8_3|8bzh6bQk`rD2_rsl-hixqC?H+8r}G3Q;wmbK7-FKqSb;fp_qo-XvvPt zAZP-q%&-~(j_#HU2?3X%50rxer(tFZ^>7BuV~{7xKW`{cH-W&bU%>GC9t#1ZFvb94 zZe?^9+Szf~CAV|p`Uz0TQYi!1AkQ6XG?Pj@b_jn-)xfm&-g3V380+6=`2V5evP5XG@)srxGLaC@OHy?5GUF zeU!*BK7*6(DThQ7Q!o~`>!tZBGfCxfikZWwM>!AK1Fl+_uC`ru)}g`fmp{H+3Xk!^ z@>i8a_C%}auuBipiwiAPN$T&h)O%ttN~lEk3HQ+|IODLimbWfh*_iL?^vXkI#hG-A zC0J@Hb9+j2+bST=$ph&?62ctlFe&#=G@(}Np1Z&j(6G`a&AdhDRY}c(O#Y~YAQJ_2 z(Hj??S8x;=XIq1rsH^?8Q%{+8d&UzO$;u5cx#nGs-9)iXe-`z|5fVwkgo#i}dahr$ zrm6Rm=6gaYTx zS)lf`&xMh7F=7-HwH=`;Z(W+f^7qDpSIYrT@Iy@~J5n(d)p84vwD4ymq06xa)iSW& z0+p?lGSn^z@+leBqnt=Ea?Dpqu5{?9l^1i=3Y$+GG-l{7f$gT{7FCY;n^WoxC2W8r zQzH~EfX4K`N)ox#UMRa1gc}G9rHl2esZ_CJz2jQ!IV;C1+i%E*Pwmx}-=9%UR{9c^ zIK+|uZKHwqC};TNONU!YL55Q@2`On2*)-QnLlIaJMBj0ty%Q60ad2U?V3mAWkE1E! z2Ps8)U>|zCflhgNnov18K8eA-RHFnrYbklXf@@{Lx6#>aa(gq<^zmDqj0v=;kxjI^ z^v1fPkr#@0>2e?5@e>IKKG*>zI(iQ1mz5~qG?kfH%v_9~U z@alLV)H42f(V7N&`f~ek^x<{`Zk1KC2`-e1B9z9QmGZG+SwH5aXR<;X?GI85DE>0WIK^z+7^_wfNY$)&vq z5YhpnfVCBb8G_taLqO~SqKLg47rx4#yx(9pgU{cd=6gW3U~xZBi|nO>Sfr5DbrTf8 zp^-L??>Q&6U~gVsYH4j*h=`8fe{yJ5E@idZ-cFw8N~GpLoE<()zTV#1agdOd`hsFBgXxQC2bD=Gl#2wr%d76( z@Hxco;G)I*Agx8yYtUdUgSdpK8I%ZZ<~B{Ve5Ei|)**KkUp6$A zA8crUezE2M&(Qqmf6uhq-;#^}eu@3TrNn1!XZum#hTqcM%F;sL!VZ^}hTqc6(ni)w zTUVdvgT8~YuD*;AAIq;yR5b?s;rjrD%}7UK_l)|^s~lb*uA#?)=V&PB>&>*G=?4o6+Z8BnMEw!ORS@_>Jm>2dAl9Hisr zG{JB}14lWza(BWjj>XfI(FqNYB{qqjJx&49u(<=>JUiQsv7pZ^SI~|RQ*(z= z^Ci=voH_iO-Zt@T^H|;HpGlwW&#+K_EULRzKXa_=+7zG-K+gH1jD;*g`%Nrij)58m!_NkY*B%R&<4R@YqJM~Ni%Kc)s zAG9*oK@3`30NvDVIXcKVHsAvU9l3uH^mtWo;kosKenQsyB2cB~qinf`wghu>ud;+| z4#=mWbQ<15&zCXcXhOi)f*C$q@Wf#*>MtCZkhWy{45G?E#~i7$c={O`;Q6)Fe7H zqm@jB37pHas$jmE{YLEYPzbt2OSGkVz-ZcbU2&<$S(bQk>Pdpt3zw8iW9=>nL2($S zxVR2%uu`38MXScb%!~>nJRw1L@g3FP2Twd*n;kjl3;`EHW|k;*qb`qce_og;iP^6p zJ%k{h;ea{@9h*Ri6FL!EVm%o==ab;aIu*C^? zf+en4YSr0;5ssgo1#^Vb-nFp$bdN82mb?NxNefswE7I)$xwCS}_nly4%eqLVQaU#ok6nNp09KvUUlhjAzPnAS`Kr z)$?-NwPrQgG)e1BTa{vhU>kj~dCjH@Av6JVXn9pj@9C!F>)<9kSvF1JG=b(Q7s2ps z1+K9WN2_7fJDh+{@RJ2R^F;{Hf+*kXiMACTE}tDckB4`0^Iry9_@%aQ`bA22XX+#aiOaRj%bU&go5IcJypanwmv7bY@nkX zG=II3CPGWJE_gb}q|k0fI?P*|3ZpykRJH9MC|f12K}g2nUy&3B>8X{d8^K@Pb_>u4 zY;5ml|8Qct4HN%364brT-Mnqp_=SgE?WDTr+ehMU-P>)88&-{{foy6g&2is88msEQ z)?9ghMU`w|KK%XK`vZagGqqR9M%($%6<;Psn*Vt!{n=VOI@bx^feQuPd9@lNX6p;r zrS;OR*eOh?rAZup=Yl(g_(>TXZETV*BUf8^IEGlx6!Y7M?5SU;~f|N}?n> zf$DlA68K}2EG&hZ#SnH_X;i|4fe*{;#j?+UQ*MHTzklWar1kRqwGO%;;+YFE4B=TcpzqxsjF- zoBhh{dIaRf4fo;Iy2?~cuSwr! z-#+Alzkc<@0#vAXu5BT4KyjiGhwLsdG8M%0>b`PtY4I|81yi1oSa(Fy&Cak;eOiFq zNnrfcB}>7M6GwDRf@uTOIPu_LT|G^nsEvz1L)im&PNn*!3W_))fcZrLBAgae9vkzW zI#D-0=LRz)>iUGsdi2J2HtWae1N!(XijUR^W!aqvO|(b&wI}`;rL&)YxJM-fC86fx zDqrd4q;>V$r;x{O{;)f1UlXg84~`wVdW2haq|E>>p5IDoE_4ll4me;r#TR{;AI>(s z+jc3V3+x42C3DkeTYa=?H~4;`q^nOWlAckNQe|40Omi8Rf5{`$C!yDlb;(0{3l-{d zdVja;vbm~i9UgL3eDLZkUul*ed{t;C578fHDUYXjrm8Es+ zyG3D-8G))E-^})N!Yr(~i$6w1aK*n#!kx1|+|i#0(=2{imoH33<)ms@x@MtJrj3;p zLg$?IU5b+!QBCHlNhwKni0`&cRddm1)Hx8eYtO^sQSaI#VMWb+KyHbCSo$t{7E zkwY>X2%zrIrt|C!hj$j^{$gmehJhD+H;X^1Yo@Cs94sf}`*Jabae;h#+Hg@zN4m7x z%YjJe6`Hgt!9x%^uoKEA*EsdD(qRdy!h^<_Uy<;{%&(n)hzI_-p`TjjizUx!f-c4# zRTVy0vi;?)>ON2wWwPdM%f0h^OY7W?Zx1|te zx4@w^V%o%7%iQCt!F}7CNBkp>x%1r+^tB0D?D+O5;$tH#%}=2uzJ6{rg$Vx!V9}?R zEeFm+s02o)7shki{#bducR(zK7q1A-g~^<;2C&aBl;V;Zi%)M@l8b~k3e9h6uGclQ z&*74W1aK(dlqo|V!IjEP2~VLvqE0DKO>vLr-MU6TsRK`YsH{4@KZHQEa1<_s4~P$% zx{&RfbRN1TWaJO3LN~xPvC9j@Bqe8_2*o;is{~k{q~Ct%nhJ)9*`5xE@C?%`uN0&Y zFNo)YCPU*?K&Zl1avC(9$=K}1?-%926fTh46U{TLT zq{buCAzR|F=oKgt+XxGzBPJ9!BdyrVbf&1W%u~=Gr-+9+j~W%zwQ*{Y=+hzH-_1Ce zb>~u7LSMkFc4#@E)f&U4J2Uk~CoMv2pD5{TM31-XdY}kfpm#G)Pi~LDVH9jars#|t zfSj?@jG(l2sK}3axL|C$b5Ju@WXYl*&>`qgM_B2o3V6WQFlwS^I1{2Sx6i|aVs6_` zAFHjrZD^#@V{#ibh%WzDT6m|aGC;)gQFqHk;TiyF(`~Kp? z+kksJ+2Z`ZrF%i~8TAI;FEyGIj77%@>5wZqmh)>)0l}$)fKX8T54E(^Fjns(7|ABp zKDQ}I)7J2-I(OYen!`K2^?bjiA-4hW@AV$cU8~w%oy{x3X5*3QY{#SK9S`q2U0*0p!l%^4Z?uDpuly=K?npW>~=^!G`}mBkz)NG|>qAqu5)m&eNHpyFW}{ z*nfs@f;O&N^tANvY1rSs{1xQ89KYPz|6LHA{Wqfi_iRF8{lb z{uS0W*ngRg|Jy?P+s^(xr2nDzdiI~7!e4D&gZw*z9>HA4uUuBsI?dG&g#{Zw~|hL;0@LDW%jO53&EE`0v+-`)_{v z7tAkz694^EfbbJ&`16$Vzx5OT}!T&qq^%ESXo$Cz1$ zqW|NiR7Qy(V zN!HX_L-d%KN}Z#OJf2z_0Q|}!GDwPvy8Aq$HORO^@TW72#bqo$U0tj30yc2t{Y6`h~H`jTNb#0z&b0*f5Rkz6yqqFi- z7Yqp1S>sF+{df~#NI1`|RMSivDdDbm{h2)}9ceZ|cJ+Wbcw1uEvFed`Fsxp* zQBJ$TZ>wz#quE5{aP{-O_T2H(A_PU6N@6CoyZO*G>j3#nmfB>6k35x9UWM98RJ(hRdTnQq_k@a5;vy7k-*sK| zvHRsgj#Git?Y3PbYmBwIl6>J8BaE_7+;+^tcHXNP^@K=PYLdh;e&MIf3nw}$X4mU) zrVZWJhL1%JF({eqdiNJS{MWt>tz}JrfLXZ0?wkMl)D^AZ|sgq(G!Riz|yr zjhWAo36PdCAL1yNZNWTXW1_X`Hph2?rO^kvYcKuBWgnU0j!ZpQq6U3S&FC1kw#y*{&s-TUVXq3<*T5F^TJr;SY%qBgQDq~^b!+Iz)z)5@JW7r-54o37=gj+-8(q2G7bm?@X?)mBu# z&q2pFczF%Kzct*e&l$g##oSD079)aTapCIIYQ&yFK8UAqtBO>R=6n3DoVhKm&DZF% z3~b-xoM~}@=ok%=X`ggF*IKej!tNN$xI^Krn~ia~eBI0d=q!!H7eZ6bSlLIDS_%&< zs)`t*8Rt@?3axluBa$)>9WSeXt?I!Rm4|>zO^pW6$Gw@vDr;N8 zeeLOa#n@MJKy{Ts#+l&S&6NA@0=8WD;Ikz4geqI1TzCS%L#Sd$o)G#9xr?ic z_K`T-;C;Is)W_`BEg*cB8BXxi?oWl5DB)!Wyh`aMCG1MQuFL##w5ynMCGFODdgNlNkJFGppSv47Y8>62BiM1%({70@(cvjFT~W) z1P*KhC@`M`pE1!VLC8k4Ypy{1O9Q02nIQ$g8#MCJYF{&v)*ErSE`_ooGHW=4@^%t4 z`$|95Ddzeg6>s%C1%7anC%39K6+h^iv(pUA@&9l)wX)XNHQEha=;SZC6>XKct0sAP z#Y!c4bfpQ@&QS&aC3TS|TVg2K(JGaiyMdu`l-6|B&dMrTP6-`&N4l2Awb`mmsSTys zYVneT@>JtoQCwu!z1+GmJxjztSygldrgC7Ru|elMU91=C@?THXpZU4j^~8V-MQ|+i zbTS5x_5fEchBvtP3+4Oe^QWJ6=;Q$=MkW&0rZ(K%bOOSHB6`2d@0_fSf04(%{Z81% zNXf*}5nyfR@TR0=qW@*m^v_AnKTbp59^h=?XhJ7$Vqk1y&-?a4r)c6}<797S^0qS; zHn#tX)ci$6#lMQ9|CR#$p4|N3!nc34<=@vHnVA3WA^o3q;{P~}|0$$@6P^DVyZMh5 z75^%R{=*Rd=X>Wl{++7uU)Rn5W$*m|6H)PVUB;B$+xmvnE~Vrj53&EEdgs@M`)}(0 z7fjuMf@=SS%`nmbGPM0Sz<;>_GtvK~-ub5i{)yrIIga@+UHwm^t4#F&8b@Pf`NwLk zYr0PKSMwfvxWF@S7`$bnnzSBSLU~RI4of_lJD|vl{J=ieP=|qKHD@76l!f;{evo-f zWiH>%wSirx`5n@K-DoFC?-7K^`8MfhSN?@FuCa2(bV@-yu+2%9y}=tQw-R_KVU}YO zrY-Ir&uKt=w1~a;=hg9+?M^Mj=RRmJ5Ry~~YIyELrEhdRgadwfn!~M9$DdO8zF9>; zsT@X)Gn1;P=dp?}MUk8L&GNr|orSu-&FWNm(LYVCeX1~QQY2GZS@zhw{GppOBG~IT zge)12`_;|!gd#Ax#1miC$mS30z%czgz=k`2H@yM@iz4~12{O^yO9eR+ZdWqyeYJ8 zZ7of#elgm-xn6$RgR+g7gs_Z(E#2QYq7znoPfz#DA%#sGjO+onjyCqcW&yu<1HNtg z%isKxF);pStNHaT)wJlfSQr>}IM}rq+1Pb-czJ)hTmNz`za$brt#%4H82xef^YXCKv%h(MetU<8k(rrJ)Y9NB2YLJccBo%x*)$BStnXpKJ z8Qf*X@0=1Z8aw#~-ievz7{jp>L3kK*rr}Y_Ipv@b;Z^}P2&xds?fRMCfpsltviQEJN# z3hi}ri6F72_qekc5C>ZjX@;BCXUhRF_Nf+atCyG1b8HWOh*R$?KIj>PhHeXs1P;V0 z79Oi2`<~i=*zqNFS7vtakhCIvt-!4q{+jX|lKE7p03=}+&j;}Y0IOGWki{DB%`h>GQ)yJld9J)D66juA*%nwEWabh0Pk_`ZujkR1J8LuTE zR|IfeD*9IlaCPVdihDo!Hn0ab4h&mILvQ|7e|woY=U_^GGhtZT_6=9@1)b*dceL$5 z59oW@qaRFHxHh}8LPlN@aGYs*g()FW9E&4(P8tA-%pLum=tzwCLf~ z&qMRD2Hp_lYOYZAVJ~QY>QFX_5IX--1>f9q;Nb}3^2z^8;?A00AnsiE6>?euakV>k zGZb=i2OKmvtc1SBcH6m>z9;CZoPQ?J3+6S5F_~?bw(rY35FZgLV_H>e!ksOXL&7Dp zs|2F9z)*>unrH}PukdG9;wxJFOrjlLxexPnLIXBo#Q_Dx#{v`CIz)6*Ur9c<0s(RZ z-&_)Fflu4nHh#3e-tZ};=I^dQmo~v`Woh#FJ_7jXbQxv`k}G8*4$>-WWvxo%ZdyP4 zUPa^v!b;3F<2?<>6}u^%aUeTYiF@F3tU!6Zzm5J*5g>pMDIm8XT+z%|c;J_tg%%w< z$(e@kZHVGTSqfGG!Sbn{os4X@r9o$}PBqg8GUiMTcIcu!V~Ip(2qh#A>rU5gFQjgY zcf0qYQ4e+^`T&q_lt$te#rb}{+-cY$8`hEkD%*#rnt`A87DC@(3K$V`b{Y~x7DiCd z610UM2aj&*$j{*t-H8AUPvuU4qAf{P!X4tli&RgK&D^Tm3&B%67ysLQ$+&`q)prc` zuH!-daoT6ewg6Uhgq}H|RnkmwbqA`C8MnZTVei-rdc~wU_$~UFKrIs`ai=k(ay}#> zK{myn>W^9y9GkdQH(AJ9W!+ZalAN?fx^SL4aBsL)pXzod+H5(se`32(T^nnA2zn^G zH`BJzepgAF)Ffa*Zlyk3-D;rIQyAD9xEGiiSObxF5u-=*tf{3Q%~1Y1>yC+z>r3R< z9thWa5N^-5FFn|upKSKD-Pzystc(+=Z{1F>C_moxcUi-QwM(d3=-`mH7A*aplz3GIJixDe~VGYu; z*F6zX2unq$%+0I!+CSC$?C?M=Rn1n705pLt-y#!6P@$}qqcX|D``s#A#F9+CB;qQm2By=z<^Il76e10VHx+PZ}D&co77p{)XPMI#T9|C3vT8@xj zL8tlOF81!gUUgG&|a;mZ3GkdZ0#WOQY8MHQZ z>6~(^a$Kd-x%;u|geNAKf%`5T4&fdA^}6HMeN88hhezb2*Q!p27$-bI>*mJI3FPhB za+{f%MVL#_eyf#Cgx2c2%ExyW7Nu$`73JzR?d|1`8X-bPJDcb@R~nI`y4&-syiIF$ zJw0AHA6B`zd7FGjwm6$?sQ~tO*Wxi+P4}2hskYOwy+*2#%so=fT$ZDe?WARUkcZi} zn|pI=ZL6M{8MsisU2V%eLltHuKH8TgGWONTph>V)#>yWwPwSqiW6Evd7;0NW(cT32 zMt$%IqZP$KTEJtiV;RXt^LU1_la*Hu;{fGO#pXU)FZY2X0;v1e4BGhvc)2Q--P1&+ z84?-I0v**9=0O=G&WwGBOvpN$jH<$mn!TZDuKac6YFy4aQ@l>gTN+iFx`x$NE32*- zNStbip3CMoFV(v0CAQ?d>868NjbZGvRqiKT1FlmuA5H4Xg#7xNM-Jrj0w)bi`VC}) zA_8@@I&Zc+vv0MJ&)ti5Y*o%?`;=65&;%QWuRzixbe>1;)0bUNGo|=p)wc=_PCxXs z8ca8ozf57jaOVp7@dd3`zR0S{=obAjp9WJ0f=Ao~>3`)(N1|0 z5cA%pLFJ}>dUvd{auZThw4gFLm(AGTLIdSXcWF0xF+mNn77e7z_;Qn3hV6uMT`GZX zPk8mV!&CoE*5LpI<_1uE(IRc|rtj?JyFwwgl&jH(M*RTZz}}Qq#uC*qE`tgum%Tdb zuM9yT_92?46(_YHsf$%LXm}U(d~M2?;RP1#5x`E18Uw-{+FGu*t?JW6+XC#ZFiI;1 zliq#qR((lk`uqxeYoQ9HhU{}o ztmry2)2Z(?tG{6V5YDh0zXPXej`};`JAXSD{N5&&Id%9_hz&(bnC7eZ2pjan03tXG zt~;z%NxAT_a9R|T+1a={Rm#BX>Dg_^h}Q4p@KJ$)N?aq67N7<)wt#IIl-=U#N_+}r zb!)`FaZu|Xo})K3Dw#jUo=nVwjkkITY23+gWGflI)syDgKQRm{D~Y;!=W=>J0w{MF8y$N$ z;#BP*LFMHjp0FS_8YTzRmH}}Nf`L5gaqNjJ zcx-49nId|7gPVwgYJ3nAe4j;2)r!kJHj?vvn~q)2aNKdHUg|wnlZjb@wD+DkvDA0L z>&-x@*zj+mQ9;6=+P#@$@o>;&L>qh|eUkfDf`F2qCUB=EsVdN{^QKE}U0@yz2>C3B zr2^XF3I@%w5;6ASD+buS22(1$RrxtWdx*7Ot|KG07RYpjZUX{`=0 z_y~Cs?BFc3hQ~J~M3z&Uusx<7dk|{&;}VfrMaHPWJEP`~T8+glH98ToSk8(&EtkgJ zRT!43GR%n*nOQ6{vW}mo;NY8EpQh1iePQTo{}JCerV$~u)n>Gjui`$I8xvOq;t<|p zbuHtvE|a14SgunXTSJrQr79jDra$Iavc{+;m611EB3*Z%f2ns#^a`TUCY*5pid#{r zb6=@_Y5hnej_m63n&KJM8ULiaK;79OR(xIXDFCDD#`$U4Ylg}Jp<#RU91IV{1#}JE zBmerEYX0q|_EqJ>k|5EEg1tOeOK}VYSLO1OdQC_|yrt&yKoW};)pUK~EeQl0;?O~cIMgo*?JW|O$VSmP#PAvywus_KB)OIRn_fMq6WH;?a5a9p(YnyillE4XZ^e1@g+be!+lYQ(O( zN?lMWGAAX&E%DD@9fdF8mt;Fa>2fsFaag;;=cYOOk`&*0&n|gldE;n?(iJ6quii?U zrgWCRpu$!99=}EP(Q6O`O%M9jZ%eKAFm@kJPh@SXc&iLxa_E7kC$w8Yp#01^z*l;& zNlE3!|4d^xXdnKe0D%I(&SW%nzL;{H>tpqI-z}*DC1>4>;Q_5%iMIm^El!8h89D8m zyd6+x7zeE@{V0(@^*MCvjJiwZ0&S;at>|9zJa9|RoUg(=XshfXk;R3wGnKW%P5XjH zxnqx`uPRT*B8j3iv2g-ra>x1((a!_Juk(Pa6IGWXT0S9UpRpJxA7- z1d$1GQAG6JKs^#u-17qcnOy(f_f7u`3Le$^$`0{>eaEHEoRc9XHk`qDtf-5OwK>(b z6ox#)&bo$%Syf(ExLG_!xe8XL`-F7aBSIrdIoV6sW_IgdPJ_ZJ(J3f9rv7Op|0vg> z_I5ovoEqkNBSPMEJx?WeONe(A=~HG8%{9hO6XJzVE8FyOJ4H+qOlXY$0O7PtbT=Mk z$yE37r?`}Q4g=yOIJW`u6cmPqkrUuHo@$@2pksskt-8QW>5vTJYXB4LC)aF3KkZ`NGlKC@z-Y@)Sx2>bS2FkF=8%`>{MTH2EV_ zzUx#q#(wwb3jHbmEc6h$_xM;D(Kli-UFxQxE`50lLe9Btv9e@KTAHS&rtM0lWF24c zXH{lq%s$1l=Rz!)Mt6Mu*uVHO+q4#c0SzZnnsUf)v_pA{=c3rCWOgXGCbwOr`} zE(AYmF;g5n@FO8WEmJesT^~dyk$Ez?IQ_k>^93FX+R>)cMKqRZuSBtcpLjUt7E8WR z00jI%agGrsc`2$&@_M?jZq(@Iys0g2NSs`Hj5{MS>$Cay-YD=AXI-GC>Lg_KCjBC= zorBOiQ)*lrfz_i)bRv{ljE1WFcnV~AY!vmF{5M@y(Kxj(wRCDWR6)qJSGLZKB-e#x z_aQs8VK#F;vN6AXeBno2KCSkRD0x&2I`ynrB2X95JAh|UHb?Lim`Qe-kh@dbNj3Rg zuRb000|R!y3*SBasfVrILa2~dkZfCM-HD5)Q(ZVUxDFEdH+Q=7dcR}g&!mQM5`eOH z7#i5N##ub@+fc7GWMI7be)Xgu+zccxJkT2H-SfRO{nmn-62t88up%gkWIzpac>IEc zh+ki-(-YUGr!1t+5%j)Z$(-W`W@Oh#PorMdHAhJuHh4l75Wn;Cz*UA?Tgs9qrD;eC$PVlSxKaZ8=lCN*d$-Pgj5;B1XB;jN9|vR}P~Ax0f2 zOqwt*0k#cjF&Er4S{@*biG^BLRkG(L;SdtVN?fdQ!R)t`uSCQ;N}#gz2tW^@^EZ8; z2256s>STd#up48CHIzr;0*LClkKA*hy`_(=;TIauqx%p_CoohwQhaShB;TC2ML9fM zrJ+CBKNOT=*TAVJ;hmBduDuuo-HnB@$i{OMzBkiDX|uR3EX9lZruNDf^(4_8{BMW(ixa=3#Up}C9kH0%!X5C zRh_lm@JRt)pbIx_fe5@tO!-!cl2m6iF08WIUHF=b(LwtIn~HBjNjbHulAyb^9^q4f z+eIl8EzM+<1n!A8_2^o{7;_sVhv(u`#88~jbsnCM<{q{9d>Pb9CNfpg>>{D5(?h$s z#7XnDZg>!_)iQDpUkT^j9C`V8@JO^o)9_27N`%`b&!jIEZ5Qkb#+gXc6B53#7Z6)-oLUY9wWQ?;PeB6AJD$()CO1adGpckj1XHV)JZ|*X5A8?b&-PZ!EyP7#|rjAyI2TCJ`P`KuG z@@kjj)I9wbkU||C+Mz(TXz5dFUF!ySo*Jtu-z}q<*WG4EboCtr;q8aH~nf|esA|BHFW?Eli{pE>Y6Th0)T|oms@w8jHzo#+G z<`2uYO_$mDP?KSd@@85W3XLDokDP!{X;3a%Zx#T|RwfE?Iykr20v}N?)oIIoD;jfu3M~ zqOA!VG6G0oV4<5XhLRc+2@8MfqKD$#=pD>F>40t(eFTayCNk-SAEP^zR^~0%iZ$Ip zAq{?xTqWvanvLm|p^sneU8qYZloMffH|rrtlHd#zaGwIPU1^3cYed}cs(F{*D>zA7 zNvaI6Gv=`RYi|%MMas%j&<~}uXDb@R+LN90Eujgg2!$>6 zgbJ!cZ9^*1T4>0%Z=QBPm^j=Yg8V2PASoSg(u#f_g^J@lyzCjo+Sg9kdv&n4<4AEd znCOb6(P6A;1I9dEVA!?z7DcgoUSlICeTGu$I?N4VCjoziejGhqo{H~JtCLy0zGK;z=UXUx~)Eu=` zgAZ$QFOG3SSfU)Lp*LoVfiJaeIG}`z=RCt-K&}{xS2PG0IIx;TZdiUF2jqL%&R&Ex zG>ngECk1x;zz{28G~_TK0?+CIGW8gk_6i`PBRcEWpp0}mVY>0yD4=n}>jY@hY(G9! zK3CSgq}mn|==HK-jwhSAwlTaqJ#2qQC&Zg(=MXhYyucN@4YUntyn%^OYAY}TDKVmu z$DLql$CWW*F-uGhF4y*0&}ac55!y)r+X>I}ZW@(K*RYQwb$t%L3UjZ}3$lya&qy_4 zSaYyfsR9mWz&&P=J!=l-J!)s=)}7tD(FEbcrw5Si)Y zRf$FqYti^YA$h0NWfu#4lqWyZ^3qJ_gdnHVZ?=5tkoJvYgA_mLAwVt`L^YM1xJ5$kAT_c@ zxN@HhJ&*%|S4H2C9oZPJcb%2;QxwYdc`8X0tKH6+BJ%?I*zadQh467y_&`&X-0$Z~ zv7zikGEOO=#M^p0zPrB70S4k=m$(DKa?_lrYbxR+gOG)0hZI1I%4vzp*?VUc$Hi36 z2RhZQwjiEPcbZ%exvdx(4aS{pmV8#Q+U+LYgnb)(gf* zl4CkOYl4He<$R&4m;RU?&Te7 zzXC=cI91JG(A$dw8;FQG?UJH1mBk@eewetw=pgwefw?yT*wNwEb?nM~TMqBII2k^d>8(dU9QauX%tY^!Z=WM*PI6nA z9LYA{{;{E@fxd>TVucoV<(JM*>RB+{q;%XJum{kCtO83v5BdX~F_v`Wi#}3ClV=%l z3vR+_5;WLC0QwVT;YmD%ja(zNzoj1MaX})Vl2I>cL*Y1mn|?J_#x)NWuG+plU(-K}z73`+(c)><70O zrbF$6Y&r&x; z-EfmWAaFqO3dzKOJQ?{(Wc7Ph>t8{r{I_RxOB*;i%GekKOaUgwiW!&#W z_DXZS_*^=~r|{N_aXvjG0SN5neEYReU%phbp5EwApflKh0S^*NwFDu+CbMe{u2YD}GsH0IKfaAIql z8i~feBz!o(0%s0?&1|8ws&Tv8?B=23|KZxzbw96{+6Fske#q8OF#b8wn~C}K?DeH@ z_l{2E>J>IaHNC9g*W6cPm$)6rWAGU#GWDAppPpwXGn8ihx@BCtR?^0SlSbcINoYgj zG3gIBC8`9OP#pTOl3jA~3g)*G9*_K06dWg1*FxHJG`aP#7jp7Yruo zX^qLUS=&UuWx>yMtNv_kXAq(-=Q)k1`=dc&`{4}UPFG!F7;O9Vw3?-6MG)Cl+*UIP zsw24sqBlxyBiBqT^jkjR&;sk!p3gRqz+7f&C_zPAn)IhZNq`zO$z(x#e@E99j9G{D z*LmaKL|#%}A?DCE2a$E|a%i-<)u!I>AoZg0y=QmFtd+y4=U)q8JluY~qR~LP-GuAX z`%&;nC~-SoK(C<8_hIi@Y>9M|N>W6h#UCBjx6Ai8Z@>Gq1CTG$&#?8=qLe;~kFwU=2ite~1xzL??Z zK7t|DuydgvgVq_CLCGYy$uE^d^NLk_0Vz^V%4FY@J@K|&F$2}JDMf?%wsq9Vvfp6Od^0)>Dv ze!M`JUsriXU_TMH;(o-?iJ$@5I}!BkVwqhD^z_1cP2eLM;GmT-C}*$SD0XAtK4Ouz zG>q<0U%?`MJD~2*z+o&Iyrgt|XFa&odi>oe=Q8IzNX5BmcjsnFUCIQjNLBzSsVYcWlkigtuLt3+frcoI{P`D39Lm}qv~Pwl(Yw)Th% zp-_3WU)~4cs~|w8)au^Va_1{1EL_`*_{9$2k3ty}=+`lJyNchyXk^mR>CoV|=ToM) zOGZoRm!q$1Hn-IZqSgw-6^#j2P(F#Ex60^^^f>{P;8SLx+P%5JQv!rWl!w9RQ^Mw< zs`I}pn7$Jzgi}o!j)ToRj`4QDV#HXn9UivCW(D^(IqPGoPsdWxwkF;0&UZj_>GlI& z>BTPbc+W-m)mnbraP*S8FELYYqoQ#jzYBcZ+f@$gQL&bp_*$V!!A|N2w*TnM)8Xsd@*W090_*BWejq{8}yRoXAum&Ayq5Nsw&0XDQ((U9WB#grZ3bS#&@HY z^15xcTnYKY5~a&YG^Ynf*ao8@eH-4@?bT3|BI| zu_|c|2a$Wf{d3d>eV~gsLfYVSO{j6TNq_1qwu76z3@O+FnwT&nP(^0PdnH82;fG*g zO%g`PDHM!3Npx}?C+bRE)fKL(d+ux9bqg0@y*JVI(iu~li1cCe_|3ryV$m)KmPcoj zLd>xpwnt|b*x};gQlG=JQd;EfhxX}DkvE)pa_1hl_**PT9)sB|OADyJ98v?y_avgv zZk%Viq>>1a2N7a+8dW)cbL5(bCz<1R?)52zEu{J7-34KZB&25VnKr{!w&Ra@TO)y` zR>j3`N8LpuDOKUad3c=3zMbNE+5M7g^xl6k%ahw~u-N z@ns7XamS(>{=oMm&U+t3C!nt+3*e=L9~4~P^|!$p#`tc`wvjn1^yNxr=aq6JWOKUCFKFU@6uoHR3PX0NunIK!@?S|&Ez&$A zuAseEn@z;Do@LXk-J_ENoO8l5%%8o#kus{xpjo82(swjc)-DV-XE4Nl5I+2)c;u}rI~vBsC>jM+zJvL+m^Q>oSNt{HNTob40!Sxpkq z<7BHLc7_)6QoD-N`TkLnuaGvrSz2i^M*cv)wBuDd)#_Px7e}cnJWd@0u#DmaN`35L zZ6zg)3;S&x)s+d$HS!9c2xW;zh00`~4VV-U$Q8~vP1ZzEtAA3Tjo+OWKs-Yr5lDuH zc1;0CX*4Lf(`kc2K-HYsB(JP32ORN<%?|<{pJrd8gSRYz2bT8=clz8w%S7 ztBT!p(cJuDJ06r0TjdMhv@TEWO7OT?gtdygR8f0y^=OtT-N9uLLiwT>F-ua~Q_o4; zybb*5)qc|Ix3-?w)ANFd>8Pw*m(i}fEZ!5Jjt&d&Z;32v>uYQHubvN=O?vP?o=a>= zKC4~cZCy6BHqX;?RqN|(9lR^v?G}}ljct{Kl|T{wfy3wnAE3Ybp6U6yj5;yy^zj{z z1hc#qOz8a4@bKg^ir`|iM3y{(;~UsCC%>csB}(%ti00v9baR_7A9-_llgpm3#`iqy zg|hDRWCdEkIfDVZsp*T}o1@n(kiz2+6J^Ff1y_Fs7RmTO8?^s{U;ZbDJhZ-9u~>^TLp$cLs|c+MH849f5KP4XOZl0#e`Yj0!+*P=FDUM#g_-L zbTqO5#lz=lB5Y!0V{AhAueII(rjacFZW_t>3!C|O(MZ;Rj+6gS8p*&z8T>vpsUrl^ zs-YfA@c-Mh*jWC&W~tO+kVa$ybAW@<*j5akO?ge9dg70dMb{|$K+*`5gnvB7{$$Dh zXDH*>cKa`k{OiF;#-AYLKMn9tOzV&O?Qc)m`!9_Ak7HGgKS9QS8sMLp)_(*17lM(D zKXJu>8AdYwG3@ciBWhMQxJ^i}m3m*JWRR3_J5dn9Rx0vY0b$Goz~I9@NkA`mc=m&DR^YWv!zb6t&3ZA~L98*RtMknuSbY#ax~(4YLEVmyU@KTg zmaImMACF8P?T9NW%=AB8bNtZk=&SGDTDzK`hY|c%eR>x~-M@0HLv$}Rcc%$uctyp^ z?pB`B@ltbwX{V0g4yG?9+OsZ(3Uy{veD${veuzD%c6rrb85(TXVm#j(TXQ7?`Xd*!i1H?Fh5W}`6yQ~Y<~6u7J?BflX1qRD8`4*a za?E4m<@SzdWWnO&Q6D;MHodj_y}45@u^w44>oH?qD||cN5+`YkZ?icQS_BwEklw-w zUpCcrVXZ%#O%g@O0`rFRzxMCztedH}(6QQ_A3H4HS@|~@8S|-bFC>rGRII*YZeOx9 zy~-Yca}v515xDLvzv5aSmvK0FYFDi_Id(D0JSBCouJl>*T&CZFAZ~&O33*D09?JrD z<;kvm@rAe#Hw>*DMq=I_^Ji((sNx&==*e2 z%j%8SVB(<_6w8vV(Wp3r`zk9vHuZdVPUKj~#-!9aCf)Y9;`QYtIDCJooN%#yS&@j) zIzVo{M80EM+)0Aa#sgNtLfz>Hj;?=!Mtx4AAA{VS@Jdb% zWHpR?7$8O9tGt+^zMyUoC%ziiNW7vv-WURYHK~KCx;)bCZfuyb*fJ7!h7$JJUWl{k zq;Ec1m2RD&PI#;B|Fiyb`l4q*Vr+Ce0Ta~vJ$qjY=tZ~6*NJ!gJfJhCq|z*54sAB zMo!9yOPCHv6hidc1ApGEFr6sEP3@yv1_*6da^7)#eMvI zKZuoQH&|uGt<&{5NY{kXYab*LAi*rc&CB~iN754{GUx^g@|?+nJ(Ek}vVY$pU0o|ztR%B@xLe!|&m$F? zr<|jPozOS)Q-MK3Ker027N2tfCUF<3RjE{+b~Z9$rGj;609p`^VGHMi=5nEDOGOoB zpK7Y!94)elS>uUmC6nKZB#wiAyJ~h7bFUdN=J#m**%MkJDAF>FSs$fhH6rHdZ-d-s z&Gyv%PH;zrJc6BzM@H$WPd5ucjFv`jV88Q2YFMVMT-Fq@SmlTp5LvM>D%1G5%G4B| z3A?;Z?=2@Dg1P#9@$Ue+#)T&F&kI+8VvnkbKJ=oTPm#6cvYmb%ZpKn?irCZP6#My^+LudhSnIt(gJD*$ z8q0Uo%$fCBu#ESk4w5hv{sDq&V>cz?OKnL@40u@?&hdCUM#X5Q&O4iw3ueH}_x9@X zl7o*CL&XAQ>>wl+yfHlbs%nw!$nl3Y`OcdI+0`jt>iSC1EjVR$fBn??7Zy9KCx zlt%l40$hv%{28%AEG3T$$lIzH9(#WTGC9(a?2!2#(p1}9g&p=Qb5@&Mg#vGpyKgtu25E5YFO+J8M z-fQp2t;C@w>tbaMsyTE|AkI#%>uCzXt%wB!qUFG9wZIlbn$_p59$?iSqLT>`;^1P#GIlFrPer#kcYzpCG= z$@lgRRB_MY?6dD)oRz(w-&$+;s&Q@<22$8sX^)Dx>h?61Zc)D#mavDsfi>e@>PKP7 z49Rf_NZU0k7KU`>AK%lj*vMew>=*?@JRMH7iy zxd(~j>Cc-R{dsT^ERNFs+ocfL@GY{DaS6j3_6kNam_a`bWAOaGCh83Y!NHlB@$3(; zviM-hRJ2*iMJQ5&b{E0TvR}~de6bk>qAJ8808cwDg9oC>SGv(N@`;~s+}LKf25WH* z+M!o@*%HM5Oy_7}cGl?X*tWrQ#naIH=J@_|%)R^V!~N%^AhFMBAAHNaJnt)SKb{5Y zc(2`mx=+-4aJ)Uc{2ZcXC4cbd*(U;gon!npp6Y{x%NP9v%7n*CSdo$xnBrW5)W~TdTmL(0s&kFF+&R&sIxTTi#6O`bV`? zAc3^rUwA*ntxT<*zV)!g!dxoHQ004&;OR{n5V%KTGK^edo0=HF=DpJN^W6Z&KM z{|WkI{wX*570@5^*HzYE#f_edSAA{lmqUNdKft125B)L!m64=hIp=>c;lHClGw#0t z{l%t$!7=WPsoGAYlJCB9StkHeFcnLTI5)!&%lmD+q94)Ujd!iW4HN@F8l0N&kA3W) z3{(3yZhxb{Ul08;|A6%V6B+vE+x|B2FKFN&klueZ@DBv(=P>ARw)GOJ97Hu=%h#ohLLo`BQ+HpIyNvHe`Y<5FV2FzR@UEK0Qb{*c4c$7Osr1g990M%Je9S|{=mm}B z^Q!RYa8Rg?!L;3IU_d&ei4L$|n4YujX`MAWerc4#mhu9w3BseE971+;dPKOYUST+2 znNL+Ln94?@Y0S6{T|6nA?Of1yN%6vB5llg1~zj^wZ z^O<*iD=Js({`)vZ(@84tsrReBXuFzP1YS*zJhbFmk_S4wiSQ9~y8!X!z!qcUQ{G2d z9c_&yrI$*93wZZbH_KBEc@z;qQ*j+WTbi_?6Z{5H%3uoETri*#V0yw5>JI3!Z*oW$ zBLi4H$SX@STSBtRzd^(lX*&_!KHKhrcxt(?oogc_wF}S z*~N{fK!CeGc=m|$`8XY(VqTaamIa&0j#=#v>~7@qKxk=(9bM~b)|q!@zTg7KYj*VpS7ClhwfC};phL*3!;DX7o{SHXKqt}s$&(bLG&y8BpQ@A-I%Xiz$Dr!&o_)9!B6-xR+@N&waJ zI<;(y{UpfvnSJ6Kd~EWGSK?|zBm{6A?%x!P!w(8vHZce9AyRu$h(SZa+GX#h=SoXc z#VjV%%AYOuwNW#t&|?nWw_IjKLwZQ@RwI-qDDZ!vjLu~WuzUeE8d!W@InJ7(-oLq) znN~7HXJom*9a|o`_hqFn9a5iuDUtIq1{Y(+jB5j0sZC?yqK7LZu6pi{IzNf&R=ZuZ z;a*eO-2^=@N2TjE4ZnuW^LKAXp2y#~%i+xljr+HG`dO)FDl`)8X}){gK`^H`#1x`j zngESz&7xX3dK&()v2D7&*IpOP)9UH#XTuqbGeD@n^(YTD;RpqpN0g2R3O@%a?MQ^w za}hZyc}uKz(ON3SG^juk+$Sr4@NpbP+?-HFX;m#X=%c6<^+bZ&oH*`K@nI2}$xGbY z50`iiEB*Ymqe^oj*%(DPq16z<0%3!6L&8YrVhiS>sWUnFt2e3@z?qisU%||SFigCb z=P4`i6iZN^tl%a{K-)cRG}s8zrA}-rQO(CmubJhQvt4n5FRt(;v)0io`XIsM1zjwe ziT$AuWZ)xnmGMsXb9-jnb|}NP+eM;xbONln_}k0NUWmE*FEG+oF+NC{WUeULX+elX z&cqwon)&*}HDy!Z*_LrbObpw{mACvp@|GaLO3NDOfr&N^msY>oc#J2`ikwy_Qo@%v=FWcqxn@?qmwi2v z=9<3HYA{lsg)pEb!zrOKCc1kL2iH;{-);6wX%|Lrxs+l3E-u+>RE8mOEK$>HW&_y! zkpb9dVJc?7J$3(uYRD=E7}@Me<;z<3xa*PJYYyYbNjoz@q-3U3*xO2lSJCJ-c<~YG z(}qzn+IA>yQ1;VUQyIHm$htTziB=viS|A_LPV%@!@?3--LINJxv)fVa_Z~NoK_o4A%ct81TOcjm{uSPB9`4SMXAV~n znOZv5)=s63!MdVM0TG0XC6LC81@7w)ai7EAULSwCJyrP}WxddFRgp@;KL8+Q zBru`s8Mw<4@7WT6=k4hB$Q%;CIlYgwj;lKNko?RSY>oxKl$ilY3cd0HQ5PWd;P?3t zm%c1NWl_HZUi^-a{vy2iKe4D^V>>2hmY=ezUjZ+&{FT9?-xdJBAYNqo0Z9FNc#-9= z3=aL~pnh(`{{p=DkH|u)duoC|_OX95@a)^T{Y{^KJ^IA*Cj-yE`L@3e{0kcR2W?P)Lc zYKyvkpW5Kpz;M1@w(%Vz#9WccUn>tD+a%54Ct8{*;lw(*j$Dp<;Cf~9cb+_L&B_>w zq4I|OK??+-!ntJd4IkH{$4AI+O*)NYR2yy#S6{@H2VUE$?TIva4bi{u~ zUb}*;W*}}vV!7!5aQ;?6*6z|UZ6?dnmd=m9U{OE`DsU+MwXb{sA+KZA6qG{ldWiP6 zz`0w-a?Mg=7`9^GP&FeDs%Eyj5p;uf9UTH$G>}Z9uQ6J{qhtpJ}K*G{HogOCPq7byaw*=P(;DORQ_@z?ks)e5nc+a5W05m zn^VQedhZ;u3PfhJ(z!D#Pp-MvmDfut9r&(>jBNPLyL;UjU!MmDQ(8%y zHJa&i%BzdhN@?!~tVF(ic}J4w;<2s9nsh`m0>Yb`xsTgo(q8mADjY&yu?TER5hbb{ zh!}cL52{Fd1U&y*Ab!{@Q80f8or&c0qG~oa9j=$g@~f}~L}$q?b3gxV3pLs88ySdT zIMej^%sO9=A^4IVIkei`=h9q*S|w)-FCqnTpK5GlsuPUBzN=+(%Y&VMGfqQ&G0uh6 zUN{#x6>{-m52MgRJU?B@JkJ8&J#f2chvk?W%ST(y-I8RNuxJj3`g1SY>-SjI?$ULu z%rMf2Nrq?-m}i*etkzxVx>F9#Ba{w_UG%B41t)XvL~2(6(*wtF-Q3Ho&XuN5!8Xi6 zBWwP*n7T0YC#l)dd|-1EJtJo6#md?f+8Uj>b15IAVJaO5U~Yqf^szy|kVd4DCNxv0 z>cXG&`8lQ$X-eA?T%p)~Vd!7x#}{8GJb?|#G4!pfI^>e9>{C&3MNZAGNe2h6F?TD7 zg=a#9%w)1i6{{gf*bJ$Zvhw!~S@SB!W{*u)$eW%cea{V@JTy00tH6o#(TJ<-nfqI* zeskm5QvkudNmkX%nuX&0NCL_eH-?ji5xiO@yoqB;S}A82lo4IPM0oQvvMvNQVyYS& z*s+GOt=!qL9t9IM!lOtp=3@HJo1kd0*L;8!xEBb^=1#ly<>(Cxd6W^#c+|^f_myyX zb}V%VflCgYc5)ISNd)B2fti`o7@dTVR;q>Etzqch<7xKEI1vJ_m5Fmtx9gq#UJFB9cT-d3NmHDhN~c6Vc&|Z zsGplz}uQ5P(kl}oJfVz*0V)P^>b_B~^ScX?wR$m&Y(9$fRzw9l1Vz6cpo z8fDInz&!N%fw`7_mD1sUv=fq~BTC7RNc@rIB#98+TLLcPN;i*_jPv}iwwPPLjS&mR>zI)80NQ)ltSXsro zFsPZ}^SC5jS7fMgPeVA9`x=?Oi@ zQDo0pwJcxP(Y6eYi`&05Zc{5`*9rZky;eTgt5dSPJllWZcp8yZn(XQ6+;;7C^YLJL zw7sE3|7QB*+3LsgWcu#qPe}yj^GRt3X^ysTZce<(T`D`siM$17B&JoxQR@M_01@QtcXuNrg0JhY3Hg(+UK0OD7x)ggYhb+xEL&}esV zD2|O3SNM=QUV@$8#v=2W;t(0?~Krz zhE$CR5@Xfot1U{8zUHhgsPiX{c(8n^{WADsAm?uNy<9*AZ9MN&%}vKuQsh5=Dt{m) zzaIBu{VO9QzeO1S+=TxH+^hL}Se?`bHU1x4^G`-yeH*vGSIxiRs`*bwU48Rye;fGM zGw`>{4Brj+pSahz`N-b}{sj&E1H$^#+>7mpx%1Dt7ZU^L?=xzXmaU$+SKy~hRQE;n z!O#yUkf1;oWLAFl;$fJS6KVefU)DOAPOb}DA+b$W$OEyW+#a`acP3w4eQm}dUg0%)4*PV)xg~c6(mc%!rtn;Yk#a%eYgW>C3v^D26`}td=5_1 zHwyWwz;{6OHRMSaAI2MJ;P;7@5X@CgyTsy4O{ik51%hSz6FuHJW}JJjV6)@>ILEU+ znoWd=D-cD3-HFntdK0h`tn0esD7dgG4Yfi$0?ed2B=O`Nm`v7YK_h;~;`Co^{&kY( z9TNMEQnJ#qJESBy<8t}?t^iPCS4!YL_a#*}b<=rgyc9w=(W%Q?MrL*VG~j(9fnNM> zf2Qhpv(dyRy{4LPxs8{MvdM`0QzO}^43``YfrCnf41nSEQ3#7nsh0dBQBbi;mX}C? zjTo2d(dghr3QUCG(k41RHT(Rnkk8oysyMNFAY0ZJs7Rk=04@e)*rHRBso6l2>hq=C zXtVhksC2oH6UqFp7SN#wRyBt5Xek@~M;leFx^$I0Djebh+13h1c$%N)GkT&xhY7YnKo3x$V2y zU-Q!RW0_sL48Xfzo1MZEiC!E?w=)PTess>)(e&n>uSj@+9e?(y)!KR&8Lj>fokm(g zwiX8zMGrrM1KJaE#tN1hV?IKbhAhOIn5*%1u6Rd=alAWTM4(`M;k?{|^H@eEZjO_=k$Jj+Cff;yPo>BQCO9D-eQevhmn-( zCP)X(7l63MS|c(KlnYS`pTv$ZgA(bQW;`lO-h_zINRt?&WI$f9YGJ9~rv+Y;r0i%v zHLzSq%W?%=rd6)s@%wPxrt)Lwbr=%kKGk3N=p?hz~aAei}$5l4o_%glD)u>a=L{Vqy z6y#m?L=%MEitAw8uA&E*|JdPP3A!!*jDlOx+IJ>?FxG%tiH}cX9g~4 zdfVaFU4{J-)NgSsXFsQi)1^x#Q8*SvjUt57eOo_1kW{b>eRT_|Mo-RHBT^MwIgtf9 zxmW^ZPe8)&H3zjBgIX$!CYn5t86j$D8cD3EV==E;kFF8^mgk?S_q!(NWi!D~`67&<1Vgk7J@fm|Xx5dUl zFO=HOns^O$cp*jv3Bu)G-4G^hCmzzhfSx{;r2sW#GfKhmU9PNai)Olr25#n6+6{nG zjlpnBbZukk1pXu<4Nj1o-BaTGD7Ulh>h0j=3>{Ts4O#ZqAGa2DjXc&$2tZE|yI{#FfGVRn3jfgPlvr_-uWxF`wgxtNw1l9#xa%A4Y=YRuA+Vcg+x=YIb| zRL32beUgf2RySbBHFQISD~ZqTYmA+bN2QzN<{w47sA}{3(of}(&_eU!B*S{_w$hYv z0BsMNI@&L7C;6cfW@zT~(D$VdOwpvFtKYm-Fw0(rLb6PFUj!W|%ysB1FLgma66t$2qBsK#s}d*LDfxV z`r5P6O4q~%a2kOVZciYEI?pi3Zr^k{X^RTJtjDJ@Z~E@?JE5P|}Tvy|lDu#FW+oOs2~&o3`G zxJml9TfEtO5oEOWP?b|zh+38{57i73Can4h!vKhT2e|yh1tr^03D2(p?byFgoBpcA z$?tm!{5)~;7YSBl`zi7H6`&paZ@G_u4Yd1KEdS@k=fAcL9@`I?=huUFY=32j`u8nb ze)d%U8?45cFZEv;88|#sF*9^9C1hk`_*dk_Q-ReD0HUO*geU+A2mkil(XsK!2(WQTaM95TX$eWl zDX6Haun6cF=qMS;D5)sFHUb0z0RasOjRFmgLWzxzP5J-)dh7roK>{cNE+9a}0AM5_ z5G0_-9st%;SHHdh|9U<36a@I`6eA)42m}Ne!gi7*XZ)d}4?N zCsAYddAB1QpZIZ)e} ztg6Q)0PNGHPsfk|e1OW}uzq}1Vq!pOUG*@TXZDu%VrripK(mWUEB)d^UX1y5QTJ1w z>EXm!>&mdwFwtbH?8GaFy!z*Ii6RuWcP`-pfscUvSC%Z3O4X+3l%yP%!W1ODG)5kt z6520t@B?#8YXw9MWEVcvII&|batLea}`Fu1_675RAq6jrcI>g#Mwiz9Ei9+wTz zyF{3Wyx46qJTNj^MYg>$VIDCcNaScO3L;b@9q77t`5?28UyJ z--65RH?dps5-jY+8fmpQak)9ivXEc0R)Y&kJ4DAdwGKHW)m5DrL%Rr_OHaW%U)Sy? zNC2)=7#9Ndb6uUNh*j^A>vA6JcPnq4TNLNTR|8E9**TX09az_ZO8OV>Duw&D^OM76 zua4?EghdMH{xRyH!u-Gc5$JL8j~&UMgu~w)@Zaq4*JFp@c7^*BaQNFK>2Cx7f(HHp z4*w_m|7~IOw}F2_1OKp|77`$2q-XeT7AE52Ag18(RI2)!f!^1nyu4pM{8tMzvN5y& zuwwfU^q-UChq;@0$cV~vo&{XLa#uI&Kd*NatijIkYzwXc0zL91KQQB|Ly zHva>!Vay?Y^&(fgR=pGHVOe0(bV2i2(M@d*i0$K>Yl5Zf_oKHNj~a5|-d^t(@9#!! zT1avdD;XZnXv_2b9v`odjyG>r3|($}E%SwoJ7v+lY$5LI(Mb{COP^!jm|g8_b2}KG zRYia3Q;{3ope_;bPa7~LBRFw(DA@!tnrSRh@C#LxHxi0wehwBuHk>e3Y&1bINT!Cr z?-xcgoM2;!bs+}bohWv*u{mHzhN}jC9}@~4Y!(=KA>eHY-4(Mf$x#h^LsD02v+oBJ z|NUJ=+0(o4m;1B#v;*%c9O?9$1tq*f@^kc?BFcrL5rXWfMbYmyJ8w2K-v+)2r#5ZQ!LPppFi$dOocjGSZ+-4{4K9h+G?71{jnW z&MG@;^v&+T);@w35P_ZB&fO+bHW4SOid==Sv)%~-wVkD>o=&5SN z*av6{}5FFmV}dtybl)zlW-tSJ-w%O=ul)D ztwj9@aaEP*!~kIB=701Ni2m#00aijzGl$=Lh^i_irb$#7+}WI7%k7_f{4@l#>rY+0 zyp-}CTELDDuLWL$j-sK2E*+u0ED*_9l^{Tvf6viN`!YbXfWPpIY>+p*8`JMM9_nle(fSKO~ThkpbqS& z&JcC!WHiW_zTSA_MmFMiABFQ``gl6Bi|}UTaUv1UdhJtsjw#zKPSdS+=J)L_mwevL zE6RyF+Mnp(d5Z)#=s00Od?r}ehn=_TxNOlKx@;F`Yd(j>b-(wzN=GbO#UK%Gbgg6@%5x3;V2Q&_1tE- z156Y}**Bv*Ui&ypG$n<8IfCjb*cTP)nmch_5ed04(Y!m!gkATvVJ{tmG=eSsL~A8! z=WXF4PsxhbK82GV38m?6*cT~kn&D?I-x%DB(Ll3AcR|F_nP>a$G~R@@{xj888&<~Jf}oF!E7abIzNd`CeM$R&WTPSqom=3}HkG259wb#Yel zKxhJzrdz+L0-jgmed|s^QZ=&$n7=>24^O1Lo z#L71onN_k+B(nAe03?|X4AEe-sxmf=U&S*-bDMz+1vM-E61LeP(l|$GfPbo80$~dl z%$)89ca^KDP}mI?{^movtxA)xgni;*e7W-w_4`a2!?PSkyxTsgSIhmnGxu-H;ZJK= zni0xZGLK2h_Br@2gE+4dz?b&;F{NKZ#OBXJ=fq$>L?eYFP44lAPtu7}Qh{M-;UDqd z%gG$a5m_RaLK;hTb|rI!WK_Y@14A1jxd(MnmQGGaV1DeQ`&c<^H_GA;#iFw4QVxZs z!4aQwB^kG}H`uf_bU(41s_5(h@V^Z*i=46-rH{ezc`PVOAmAdi16r+$Mn2j6?VI@_9Hjj+4Mgz}-M#QDhcCbRss(ZspL-sgH zF2y)oP(_!>O@T%deFGU^^pg3KyzU;@4hQAS0UcI}2qhOaWRN*7UXc4?=5@SYs zKHOiO0_Sisc%8PBXD?lPfVty3n7yKOet8jHhu0L()V;d*yiwo1IkK{T%VLIL=K~j} zY0kMW15bunvNB9Kxc-8WF^P;z&cR7#MZ*CkmHU|J(-@V19ixJ$F|zGSP9EA#Hbd_k z8sD)4$tP1!iiaEJC}Iw3mol+?s{X+two~kC>}I#tXk-1Z`ivWe+O!x9i3yAti<#v` zKB_Cv&`ms8z@qmVgh6>2xg^wugJopAlD&#pY;GFCB?RYfj72(54vvv*b2E}Pd!H$7 zI*%dzrY>|uWbPrleKaBRsDRrXPa(ZcZVvqnUW&c5MA2AhotbjSrc?{ippX$v_Ze@z zM|Vk_3)ax^GJv@%tp0pgK4&}!;(Z8MV};9547W#KzX|W~OnPD}Dc%>J{bFl>hr`C( z?sT+BmX}l#TMWsW*!`9z3!+8Pif@W-d@DsgQD&?rZS8~ncx2XZNThBOeaxpCo}R?U z4;%v~ih|yjA3fdYR{FsBqSl>7qsqpZ*Es{^<%$*whe~iM zvn1hkp$gZn+gtT;NsWvxs{=Hq(W6Bg8;KT2=z9T~j4s%kvX=vI9ga|h-G`Cs)_J-? zjERWM&S^ zD+yQlc+N>IJj)%;>A~=jWXY(&b{$cA125)dkxYt}a{+w$3W4+17d)aPd>?SG5O1&X z5R=Z`?cF|AdRk>fV@V-}n8d3(OZ2bl*$)&s57@AOhFA4-{|rC!et(Y30fO@qo_VBi z4M=Ezk&7Wm<_Is`L;MqAh{Z8puDcKW9$qp-p)<#aIWlcti515YK7>pWzJw=9de zMg|iZCPWRobltE~Sj*tC?t4473zlMu>nGz;6*L?^DK0d*`Zh0(t3$ppwm=uKkCLqd zla#y=r$ghMBJT{-tv{M$R+S#nPZ*HKV~0!$4|HHnlQ)xAMU4{>Fd=Ah6ps|_yKKz$ zBr9&Dk&$HOqKc5StxhVAVo(Pcp%;!7VH+qi6_#n zZ&aw+p6tb9hRz}1dfV;MWm?Po>+`Vgpyigd<(6mNI$n1!_FQ+jJ6ru}>+7rV-qkU% zw|rin&R6qcD&BW?SM5>k-M#Bp+K+DMu8oa>?GKkXM=i_q&YyT!;Gb!0dO2fGfJ}6@ zMQc9ytWuVDfrp3#W>@(n0XRE*V>J$)>b-L3dVYIyWgSFdwH{8vpA5v%EoQ!=Q84oy z*$sCv%KDi1ZnNC*VtBP7(&JU&$xCj?L*f?pI*e$uZmlFppEPwLLBy=vi)B{ zapU;9RQZb(H#UynqI-YF_J5f$dG;Rxzo4~?1_M0Gr4MTEbC;>Ph8il}THztx)f zxk>*^!{ph2K&!u=;>Ph8il%HF|G6ggzbS5J27f{I+1}9qvHEP@KR2G*Rz?4Z;Opv;E>-%H=rlU4FHY= z_EmEeK$Ux97PdZF5a_H9zA;tR7)&gVos%a|7vg-?=6>JkSLF>1;;Z&Xi}a+t0f7L6 zfq;G2=Dz+m5)mjeBZ?dtDzU&*lT}Q5`gSoVzgOXWnRfca6F`&FrS!z=Wth(^ z1jz#uw%%f3LqjX)pV#Cr9rf8R!VQ{jQ*lMdvK8uX+;(0o&N)U=@Aw|pZ?j_Ma(2mF z#I0&B0XD45@kwIAHT(kS z7=$d%mUeyCzMEZceD1dfCg=FmIXj6Gd078&7#2R*y(t`Z@iC7IYBH zp5TjNKbhbnI0K@o5MA_q#~@l|P_t9~K&yW3-rS#ZP^4 z$|p~1OC|t+XC9D|r!!i=8kTMLJT{j|d`4L|9yC1%0{8ACOofo$>KsNv^O?4~Y{Dn; zjvcCHE?g(S^!rMsXH&yCQY$Oaw_yZ(iWeoT%B#*Vr&vM`q5}%#K=Xh|Q4R1sZe}C4 z3?=LJn5hQo2F0rDNW2I zsYkCEr^xclPsv;&N`T-C5o8$eFc?UA1|Vin&G?FW;40J`bMCOEM=DuQOW|53bfq36 zxXDh%m!MH8qdx+cm#o*+@4HG4a$d%4?DoYqc!SL}HE@hUa*TH+Y%cM?M1pgnXue#I zpwLQjHpN^gi$vWE`6vNLNQn@AC)z@{$&wZ%SieNVNJMvydHnJ8#{LU+>%l=>$U7z5 zIt=4GFwxCjss&`xLwDw>RISYqQbWq`F0`MouW@i|wFq>8I3e%@_B9o<(h91p>JP4! zo)uV!?)R)}jNLTz<=EQr`KxoHSDSq>du;Ztgb_5?US z!|1^}<#Iag9GAK7by&u*up|*l$$v40QYaR?=P2;f0=LR1qM%uz@UkUHBqN^(AFjFw z3ud`qP=}hb6ZCB9`D?MhIx*Dnl)eZQ7ve_Tu)09CjX3GPAhvFEI>*&GKgBZMc<GeoE6hEq&kM%l ztd^EYK3@0nS3xDlixMhisFWMmZf}n38sJ$y?KT^535$hAKlDM=6cX&tegV4h69~;)SFwRpwd4 z_X*x>OXX-y24?pFXVS&rkem+#Q$m0rr)rsVU#+O(OG;FGgEd<3Gb{V>^vzl`T@O2q zRy(k}MT)bkFM;J$*+_jh^Vkoy69{vmzVUh1n*MoIg2?fCkdpH8L{yTp|MoWEC)zK^ z57m1AlXCQJD)6^*^y?`{9Dh<8{5Dw<^GgB1 zQcGbLgx+tcV@EZd#~sG)SkBy7R#^>CPbyuCKTcyELEhb>x7Ql2w%js%sKhtTk2jb+ z-Y8tzh`Q0Oc6>Ww<{-oR-0?H94~( zJqr#~-Bzv&#jPB0+1Q3F9bxS^(j(l*D$S&Gd1v%Ugs0FZzdCvgombg*h)USp#OE#o z*+MM*@ubQh^59Jfp})P$8fY5yxXSzcv(24$lL~8@W(?@H5K{7^AhT)2BvM%PSky;` z`dIzElf|0DWK?=F~{+1Sb&)$hYtZ`M{@hSSiu!a*nAicwel8~hmXy=zJ#bak0a$P zpJwj0H6N#B^lgkkcfKhhRAI| zo~64VrBB<$n|~dF_2qLD5R0YZ)=Z>@;9ks&uIjqc_noZMQRwH>4BChqX)A@1IM$Q? zDv7lY>4Et}3b<&y5uODRy=JDx+`V!Jpp&ttVbc?euAw=7klAFJ66s)xLs7+4SX@qN z+jgsB>+1t}=W0{ZTsVDI4n#k~zS^bLN=dUsTaSXKgc4K+%;5?dCd0uGrlmgt~(+W(rsWhZT*-j`WlaH2ifG4;VU3DP)-xhm=Dd zC+f2@GP;(n58@oYt>t<>W*YXS+WJzWAE<0VQ?$B+ryF;~TW6G2c2PNeSIYH3*U^kl zBvsJ19hA+nP6WC)LwO!I1x1N?rp`)1W_LU`0V|`rq?L~(FEz9H86dVQQg z9;3e#!BBgk91&w<_Z~}WZjmErlAIPRB2GENVnfD$OS*D?58iUmsxqs^4Y#?(a%0St z$u6jVNs9-5b(U?ts_S?Y4+$G=1#>P_aw(mDURXX%CKAYh#RE}M8_!#q~=<>T_a~R*~P|8 zeGqk&CykX1o6h=2iv@PNDZ05|?~WcnfjmWOIX$d`n2{cdRV2*;tvn!3O)F8_AFi0M zzqa5k2}UCNYMRB@G{n_dSi&qt^PNAWn&-D>(P9+U5%ssto_1_lTVT%?9tI^zFasCB zmq7d0%?iS5Gf`@kNMCXylA=nEV2jk4A;l4#TPMmzQj$6|Y=K%rAdA@8DW)cm>X8dv zn_IdS?X4w=w$|1y`|S)x)wi}nC&Tkju)}k7@u{+5&?u7Xw5}-)gGa~j3OPlg^O~oW zlNhd8MB>dTKOjM&mn1J*r+jk##nc6M$l^3hwh&%4tP22RP- z^IVZUnBjG1_VlfXr<8ApN8m0Qqw#nU9AjYb^gR%u=`PG{py4@KYl+N#Sv~{&oYs4M!vL_6S-4-yk!`+23<*SZ`xg*C81@i_yXNs>`I-@ zh)^WW%TDyHNE+H%#kZedJmh0m8zR<_(arYj4W1+qYgOE0-CBAmJX`MR$_&HACh{F} z{GrnWMg6`Np>AB9vsf1(MH^x_{ZiK$F=6qk_yx37TVvb9l2YWtVqk6_#<2o|%;4 zYdDJDt5OPQnq%e+{9Njx1o|R3Mu>rMNhM$?HJWrkOe>#3>Ixf}f-zCpgpE1&rm^{h zLyyX0zf(gF=QQg6tTS=;Q!vCHtP2+DRNuUSOHuPI{2{od$~n^r#sqAsgja>kOr+UL z5uJyjZWM|z>J=3XrG4x=dX+qAfw`NIXy6JgG#A6>4Hem@k&v4+;wgUWq)zz#NVi%3 zL2zhYj>Y)d_}f}LvM&~@?d?+8Kh(Zx4yfY|4RJiv+}q7a#Tg5?*4J6_fl8P~Cz|gG z9S1#rR$z}*F&2qckqmo?`fguV#7g0a;R7eT7_5oID{2l#ZABQ~M5C;oBrd}&RBD|! z0jUPzYNodQLA3ECW{ZbR5{b$PL(?2{Eio+P7KRl&c`9f z0gS^)9iBJVT`MoKr@E`<=LIl=iCJ7))s)@$@3}4O|+9u&Y3@j#q3Uw4sKm zUGEuA?x}xbF+xklf* z9v0Op%QqmrmcV15zv=;Ty?0J#_S>;;XkUL=y1z_29_?=N0`mubjkTr$B3CfOjoeHy zc=ah0-#d^D>;CKlF8bw*-N!A6PGr$5Wz3RZcvV`zOK%`>Kw|Odsy`G3zDZNxXWGA) zczy-pmGd`Y?JvoTV`KlHidp?4sgB>Isy{U8uOPf~eqAsARa*M@RM=lmc;)S|7m|2fcfw)qhBJ1bRw!6#bg&__6T$Z>f%D$lp^PqYDelru0#kmSOO3 zNZCsM-?sf+`bT}TMQWTs^s$^@h3J1gkpGLRj+_kt2XxmzN_7MW1qOK%Na+y)0PrV) z6cqFysg3|3;HOMSkSEm@92JdGK<-I(orEAJVT$QI{ie45Cb#}Gl@R~{eiB%pG9{l* zQh!%lL7@I|`kUH{3`)d^BB19}1%}EbXB+cXw*6hkQl)M_W4<^QIBp@Y zF2wly>xIov*JZ8r=g-H);tg}H8rD6-!b`i59OCSwAAWemB;$pfD$x+yJ(8Yiki7GfzFkdju4jtf{qSWap0nP|}%BW-Ta3RpX0SOO$@A5|x8k$OaBt^{eAVp6R{9 zM*F*VNKJS}E^t((`AWt{``Ud}gVak}f;A7QbG&-(kt3{2Ol zVoEPl;~fmWC*32d)T|zOIm^e^jr~N+oXZEAinj({+_bR>+;dCNf%t`Rsx5r+n9%^O zpd0I`Sy4s1RToLOy-+L&AnUTVB2m87`uH*dmZNx1Lm%ve)mZs^!?sb!{O~rKH_vP- zW#>O)@k!U$TOxu1EK1Z(GthOf_+GyTaDE&D0EmC~^%KR6^9MoYe>Dh%_5Xr1`hy^l zrzCL*kgqw}+`k2Z0E2@;!u;k!z6F7NO}r*zgg|+U*U&?Iav?tKg7S_}iPN3vBxG#% z4!+sd-IL#Z(^G86Q?B(7FOaX!><8Zj3V4bH`F{SNkstynPZ`}=V5qjlF`e&EfA5=e z^QevTSE-L|jN#g{FOnh=eY)4|HyE{SU^=wBcENpjv4Mp09GE9ZjNeF8x#iD|PQ2$y z%0%@t;{+uLP*!E(x{{a=9$z6Axlje$m27B;s3Z*_FaFjy4NldP7# zCXifOVSy>ElYC>+vRppWD{~cxHFkqC&T$3o`bCkWS-7R(NX7Y>ajWkQP4#x?>-n-Z zxiQ9-+mGB7ev0L+H_q%f&W`J>9`;?s^37a4*kW!tQ;V}~3B87|w+5AEeO(QAK{AxP zCW_t^c_LZ2btZCA#TqiM^LN!BZn&QDVaI{=>e00;PBjlW<8Exd*Dq38dMPzNbGGsd zQV`1!jQh3#(!%xngq!-avTtaioo3xDbIog{G?KS`J8j z-R?D?!p_Ti=8zK%3XWc`KVzhuw84vRYYEe6RR<~TZVI$9CLR60-?1%Nw7$k9iiU1H>S40EL zYb}aYmM{w3i#g_$luv*P(IUtqy460(2QbG0dGeF=lbkPWZWb&YPaP()nJoW*?Y(1= zWnsE3T((_Zwr$(CZQHi3E*o8TRhMm}%eIX!-kLLW?(Oq^Gjq?6`{PW+>{zj5?bukz z9q(Fi=9BrXpYAie8yh3;LfnAWAot^9tLiwzEm&+Jdk_e@x0a@sMn)A2S61YBJ00l| z6#!zYX6uqs3=GiQ-)0V7$5h)=Ovf@s-l(?M@sVqjoIq6T07B7{+#(eF5N5X?T}*eC z=UbU!=oV@HdQ@&72TjBzC~8P9Gls$0Y)SR$u&7+Y>Tl6|u08##0stbm8Q-2 z$Rr!Og+G0e;>;B-?LJ`DCxZ7zmx+bWVitk<$#`wW82wdDBYS15-Joiu}qq?0#=QizEvYXU zv@C}#z&F<>w5d8Ah;i-O(%qjSYRM6TyaC*_TvVDBOOD}=dYBzy1IChwVf$FV7Cl5gDz9Va zjHi(+X;8P0$0ffB;6EdAxc^oHNw~OvsYywAkWuQ08RHx z@(rijO{;>mB>-M(s9wAA)r}OxMYiZCnfbaz?@<2;d8~_2x$UpDirGc0`X);$3jzz9 zjn~nA4;aHV+9d#iW12PsW;t)W=vk+j<#IBdt-iuy3UTcW#pHZQNyT6i3Q2_IVsgR% z&&z*w@%keW@}G&t|1kmizsiUI7K{JKiNzd$sQmvF;6Fs=f9wtZH^Be%0RF=i@J|8$ zqw@UU01v{sfI=mvT1wn0)GR&s4mboTr;u4%loPH0&ja|6BJ=-lxd$`-A9UA0Mw^k9 zh5gTRk1RDSJM9+4cV9nHzEu(DG`m}%(11lr$$8drU^|37K}7bsRRx18Ym4mW&o1wY zc%jYqMC-2xSED-<_PAzneDGNgrXj|*iRZp-Z)1=BM+Oh?T2s8-Fcnc+Q&X3rx&5Eh za*>foQDf9E9thNtp<9IqLk#(gWu#=wix;(?cbE3d8&@lfz*?O<=R1~oD&b{>xNSJe zm>c^mkZZSK2tepAtGl&vY%d?_KAYax z>~XDauDZ0}Z^lcvn%h5dr)uor&WG8u(NFj^Q%7$_MaQ`_QYE7$DNL)rRXJIE@pSBJ zb4)#0Jl}A8dvw0L!OWSvbi~5TZunsk#@?{Kv%VL{e*3decrB6+`xO)j~Vt7O>Lzy5ci;F`@pTyn)OtNTycQa zsmey3Vf2QwvhY%*E`}7hb4;jk0$0zs|L!W=HJmCTOeroGnXq-PT6HE7 z;U+txZdR&9Xq-~fBiKSp)IK0QM&4oj&B7pBMq_>*yM}^1AvBv%GGk|M zB^HqsG-DN$SNd+TKZkDS6f2tyr9#DgVXql7$|JQfz6uTmtv9w1;}hB67OXGZgdE8# zp-J}DlBRQcHm|$Nc4n&p@<(9f+47tZ1S#4^6dCj{2mXcThh1S5dc;gtVRe|{kZJrx z%b7!|@cDH~!pq^S%r~|iP8c*dz#ypC$n zLPbBl0>^)Z)u4N+kHGX#3#y8|lw-}5fuFS!cSR3~TFL;3&npWqATwKnB2KRpjWb1-^=VpL^Oke&;rbE31*LRq;$SXK8*|diQP^^VbhhcR#B_6tY9d4OjUG91(X(6%oD)-5 zhv^aWECn-3s>HBq(I)<3WGVjL>bv@}Q+&EWtQhI%cN-+On96x14ZVOl_g$(0+HQ5b zUP+s)Sepo1PRorfrKltXtsWP)oOx0x8JugX;{e;*is3DYZ=A|YVC3^dDY4uPKC=KN zPbu0tay|VXlR>?tGmC8jqjmC!-`;f9)G6?DWKFwoen$v*OXUSfCoB5po)HqR>hXRhT8(3Rj zOm(-btY=f&>}rNmFC}7ATPCqa1S5|T(Um^zJ&zMkBV#^6l0Ns`Ne^X{Rztzuhqr^j zOsE1uR94OrsXY2KN*2RuHe*G;)ZURNmpS=&hu5V3z`#q;?1 zte*7CO~DpEz1FPMXQmwJ;sEE^91_;Z$D_grf?vByUdoi$&JKM`LiYe8iuGxFIK^bb zH=dmBd~WQK6bska&x%rANtzLJ6g^C?eFI%S@l0Z~?}C7i94pa}<%lOl!!U~++SbuU z++mQ|_F>>8!B5vlCFA9QjRr)ndm8ugt@zrZQ`6qBuJdU z4KMld%5vnYv;_8Mz|5c{9s?e!NFgacHcMLxpaVgS>$%m$W$5&41$*R$p*xdz#gNC_ zY0S*}Is+pnR1Qeyt-HN*Tw`$s_lG%%?=3<;`BBM3S4N*0)F`Yk}{w`#kW^R z&=EJQaDDXs)9Srx3RWLh93T?&p~1p=a@$i<_^$R@!(3hEd`XM9z|O#5;+BW|hNDz9 zX}KcRi6c3bh z6NBQh;1^|djDMK?Uh)uc6f6(GsHTnxCzYre*5P2W5Jj1cBq&KsN5m0yS<=r#sXClj z(yA=jmH&Y>)xtkAcQW>LCc||a{XK|HstMW71x%mz`o_J8U%t!(i2yOOly?1$%}>`<<9+nf&PN1#WB;=MTU&}xDI>4`E2%bCT4wsO%T_u@EN+B^1Z zl4JELwXHWbR%z3ogZH4!(uAHGRsAzgu;Wi7HW}fhO7*~zba;z!93LaWL&*sa6ltbf z1uDdh7k5SfSfEpmRz)8r)Q-4rq@--YSQG@a4KOlWc1<8qM~I^`YDu~}@kX{O7w6zvp>@<*@ zlzRY8`O9Od@g>phPGFcxIah%gLQ91h=Nfipa5$TksLW@p81up`C;PN zQFSe42g0-~jja8|0x{%rb|hfQ`U`~`F8p>k`m*~>wGkXdN~`dlc_uUvAY>KjYpINc zQ@k@UdM(l?MrK2|_f9}dK;|e{pjhmT6D~)D_fYYgSXFMtD-sC(=k48SdwxiLw>tn0 zB{5n!heWd~crJf4Z>nIksv}X~Q=pV)JeKjw3F4{)bJ5W_DS3- znr>`*dd2|Aj=upCjcjCTg6zbXWXZA%TYUMjzx&u&4CwT1T3x?@Z-3tj=zKnzx1Ij@ z`Fd~hbYnXGkxXQEMz_QkmR8ZC=gaqYH6L5`(dOmW*=|;0^YVDO5tjMh-aomK)9LHu z*=*2%M1V$S7RWJ5NS9GE3Nc!3D+I<1Q*pIL`M6`CuCq?*>dN-Uo%M+!i*s{?*UsmL zx3bl3#CKjZWalXOBG1Mf+`Bs5IVqfFTqUzrzG-U zApIApmtdy#-%Fw_6PjF0$_w9J2;?#(SV4%J7G&~c?Up&+nV{h##`>jOc}nwlU4 zG!VX>SV6QC=iC^gz(cCDl&~1U(ED>(6|4D1^nyS_HTgy1p)qpzWt{F|G^gi zW8&}MJpTVQnwOd3561RyG_Rbz3_io(&vm7S0V_A7+Wo=w(&|TRQSsUeOd#pt5p(M(9?V3JHv&Mp|S{~qWb`b6Vk_M2~;`)tDL za_;2#JDtF1ThcbkrIP-I@bUu}xx>?4ws5;#zc@D8$zZ}+VjuE6ax!AXSYzdWB{!hj zAwX&;U@D2(7)pI5j7R~aNXJ0P~=_?$AX?o;M{W`Slo6LgK8at^&C z^dn>jKOiRhG&EFmAzE#t<8(_Cmp({3Ou$dY9+98%g3+gV$Gx01BuxLCPi*?aBs z4*FEJ_Xb^m-_5^o6&9O8o%C{i?$jio-^C9LBaFW@nj`y|FXcijQ($xtNc&8xV;Dx- zTmZ2dK2GT8K;Q!j+Ey+=OjAJ3yctkJ%5M1)p-}|ZBuP>@>>2B- z=K2$3WGqE24Nqe+1gK-iH?b@KHU0C(tYehY5~v;J2LVWk|KXv3U02dO8!CE}_#JIf zUjnprpu7O~OZErvP8;&J^pPSy`n`H- zTIKN7kaR?X28%(y@1u0q4_G62bM%URPgo>H1K6PgoTX3>>l}#Yln$@A2>x89v^YTT z^Q4#vz!sd-^J*^XEZN9=nzNf5uDq`s2c>NwZydgie!QL%zHaplPD|2xiF#qG%x@%Z zCT(^tWP`ois>R#c!a@{iC5uy7y8oPeg5s4?m{gc#*u3uC$gN#o=yi?O)_xHQkS%COVAw-=JFvvqPhU=IUpAjbsuZ>f#TtpW1 z2ddN00Y*V0BG?+qKZ4j@hBr8IBmjjKl0O+i)b`5`48__%&Zd)la?Ey#=?vm^L)95S zU2Zek(d!z{Qz=3XP`)npZOfas-N|r_tx$cn9+8zCGi72M_GO66-*b6-u6Vj`*2}v= zS8&TzUh!gk`UdO^ZwEOzDQlDCm->2H~j10;@Oottx`U}|g{?8cD(+elT;ln!baxZ_Pc1D-nIN4P6C^3|(Lg)neP z&a`-*yMoAYZ|rT#7g4;MHiI z9KpPEwMz6xD$~(gFp)Ifcqx!ZP5WNw;uIaXuYFFSB11}LF;-?nVQox&G-fBYM2u~7 z)uBAA^`0Yzw^VkS4TG*e?jxe^ikt3#o3i09si3rt4DI%4Sl2%a!RkcMA( z>ytQ>82X9r@Zt5x#T6O12+0IGBb|dGieG0aA}7IdDAlB zmlvTgx_MEkPcbUEH@^8PPCybm;hQ`?6xba6ewtr-nWX`q{OFBBMzM5HE*^*M>%M`7z3olz5+R0YwJdpE5Cmx zq}*qckD9MEH`Y6g=Fb$D*q`nfJS6Zkp-*&+%yK64LD<3f6t20y(le_IZ%6+UcgmnW z)I(yt-R70vdj_(!1yuO3=;I{_b~+e=br`t{;d{=qG@UpVTEtpG zzE*z8dpg|v^%%HriH3tZhnI;r4I+Hcb9j6Kv{%a|nCFlW6Baw{rYU!*E`&CSmdnGu{;5O8fuc3Ir)12pJvjdpboz8Rr4(z z%Mc4s?&;Pmwc*-ChKuD%u}GD$x}OmZ3fDc5-Fi}sEIuApDPA7aYRwevGdg)ybvK+F z6x35{*YuL?jTDwaau|)M5SX<(CG}@9<8#7;&BYj}Y`=HwjYidwIEaOIV@Bo)#y-G5 z-*%%qvcPaz_Dt2Z2e;I@hPX_3@a^i$S4T= zD4NwK-zJ1B9;`;O!5-?U8ut9?m28~mABsNC*o-*jY>d+#QhY{o!rCob?zq5ijh$U54l{#B=mq(+`hV* zknEwP?rX{Xz6V3(0&s*TH$(GOCgnQp{3`SW63U(QEryk7m}{3#7pV3w3wh9oDP{o7b^ zu}-xr^iNd0B~5jDPXg#BxlHxUF{3?T*&MhINiPOnH;yxFV&XNH-Krus&XC_D;S-!$ zm=SK8sUjOW7B|80IvaKDb5T2LjAGi8iWIR)d#z&e1xzQaQd-xk)G~9UE|78Zk!Q@1 z?bz;s;t@BFg?IbE9i!9Ma*U=}Uj^H&AWov@oDAy=9S_`v4%6>eohAXFv5!3F8NkDx z9-|0fwa$Er6R@j$ZATELM*F=~ew^SLQ`n2A>RPy6y51SYea14@OhCKS+cMb~dyz=HJn05q%J!;H`f#N+>kU$L^2Fgn^ zN(dpS->sB9y`-~1ei<|r206A!2z!YTFzqAWA}!PQ?Jsg3j=RNA3~M2oYub4U)s?6L zyWRNlGpXs*U$Pi}Z-sFLzkOC97;DoP{E+Pxhvx8{Q%RE^o>~p)? zMab7*!t(vc2$}f)3V%AAvylYq9o3?&FzB{!6UeJ--f%7c4-M{;gZu0{)xItW>#$k3_x?x-QK#Aa4~ z4ART@-b}~LyDFHRka-}v0(sf5wcG@ds?r0UkgrFRp+#>p3v*qZ8HY2)P>``J^)SHG zX7>$h9P@(U#Bkd(883;V}r@?=S@#!wWR+D>ie5-{frOX}C9pCuTfuI?BNZUb(|`w_)_vKZ32B}2j*qt^o)MXpq54k1o z8#pP0z??=SuFd*(fLDgbb*PG;UE7-mi=HE{NWLyZWgQoTu0dy9?&cMC_KW9d&c+Tw zPT)Q|h(Kj?joYTN_ud1Wwyf2~HyZM$CQYORD~bp_7hlW4%E3ad9!p_Xdz{tYE!K*{}7tA>=P$kD zZ-!k9Pm?d(Au}V#-+KEgnwZk5X))k4;WO&|pXs~#=6NQxv&v%n@N}04SzbN}Wn7t& z$AU630tG=GOEfBll-5b0A|8!$Ni#iKn1ZmGbzQYatn$o3!(wV=+^S~XYO#tyRXz=a zvpXb|`d~SNG$?1j2rkgm{rY?NQkKjk&ry!klZ0(w?%U#?f z6=@|f9%n7}ETK~8RwBhwZunr;&_!xYa!Oz=?rYLOTuI|mW0l5PR#r1hRUhI|WvJ2( zb&j~V^*PVkF~bmV^Y1eOIO{Vinl`heofT;McRDz1BfpccxoyZ%i+D&xX?w`Hn)uFd z6Ysdtm5kqEG3bI-tPH)(m5dj+YkkWYPDc9fmTs7PwJd1)!Y?v$lsN? z8mge-(uN?l5>J(YtXQa-=={&ogl~+&-3q~a0oO|ivLdGrB;(8wcv6r_Jj9y}sZ#NG z3L-vW!BVI@(hzCneGxr(xGWB!_m^t-hy3oPgjvu#7Z-vnsGx0z!veRrN%hDvx#wuC znJ*)6V*V9r2Z+;ZmoNVU)`S_KoSli7qZ8+{N4D+%pa?Q64W;hYV?kD*@ zEF8XzoLLATW0b*bLL-V<;ygP=S>8s;zRkEijPMi&AVS_HNSKNeua%$oHottqJCho; zA`GqhXFPtOszxSIPD|^kzb4+TnCGdwhUzxNuR>>OQe$5F?8;0}4YyHDx)Br3P$ z!midhq3seTA5&-$2B7CwbvzIFnU`RCDX6Iid=HC%Axu4c!?GoSV%-`&kw(YDS1yej zQ2c5p0v_MG{TMvs%aP+chsY#pQhuxmK_(vZS~6y~^&2)g2;W+?wG;8uIoCeqJI`R1 z?-kAm>TUe4L48e_-`477?{7b<$Xgi4W7J{Zhi8(#SpJb^>vLJszdX2z0!H1my_9pnblgYAsnqmPec#Ww(O z=*4p^;wQ!`LLukLLxh;Qn`Pre1mcIs%co&eE`UP(=f3~#2%rwo$Lu11n;<~JK60Oa z9H(>BoO@Api5yy?xPDU4(=lqjeVs%BD+XnnO#kDgZSF#zb>(S$#E&vU+oi^q zN32hz$!sEp19=9|I=vVWE_{*8ziSVr^|#sPKFJA-pOBy8C}JI6ZGLPz>b35L3aGXD z!Ol8Xtc~Sa8N7sXkA7|87>%yr?B=qYfAjwiBAAQc)D+!!Z8qCYwn6G zak)<6PV3SrI%a^iV5VQv>E%hmBwKlF6XnuG$s^Vaxxwh?kir4_&d$#=Ju}M(m@WX@ z+(WI#hH~u?wbDiSs2ZcMXb`)o5FHH*qn#C)uV07jkm%6;hAF*(D0`jWJd+j=y$hyAmCBRCr{VxOo#3%#(#1hu!-WXu=BbSYpd{{RMeZhJ^AFp

    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/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2022-10-Checkpoints.pdf b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2022-10-ERC4626.pdf b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2023-05-v4.9.pdf b/typescript/packages/account-modules/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 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

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

    B zLPe1a78l*$Qhd-|(<{VBa6n zR7?ylY-4CQDk@KO03ukNBV7VQl{bOWdks zA)j6Edn!I3rxvnlg#ljZlWB{>D=(lmtUB#Dtaxq@YhiT14uERhPsgq=?b@64oA=2d z`10hY#z$pBR!v%>O`g=5ahSc8?zpMp=B9iA!r9QS|2uNh!A7pKa_%U+sJa?HW2T{|=wLQ< zsCIQ1eH`~7cB9sp{iW7lLf;A#r+)>?o(~iRQ(g;pM-;+X&^|iSoxn(Bl)n>UC~CKU zikgSN1R5l{r~SguUp6`Q5X24rzH^${`LU_;HxK8ua^fzTt#A5D+oGc~B;5T!fOUy z0^wjn67<5qK&_$gQ?vK4MKk>)IM8cgK)<4t-L8D$g7ZuWBq)B!z}z^#X~Jwcw^YKh zwi>wSNFYEEYYgmzs2}EJ@Q2wqqvnHi#ZAc}0JAct-G>mE5oKo)xKQHE7U!QB`0nQu zex^T+9uyob_@Smlya_??>fDKJ2fWL}ZHt=!ylryU$3IdJKiRQ}^bB;gz4%ZkZbbSt z%i6VNZ4#+~0n2+zlI2L6vp^;-oBl;0_$$F)`tonAS5}@Z(lNDIKKa64BuK1qDDvx% zgNq5Bk5vq!=aEsJgUC&P4qS4&!UwEV=Z+FKFDA@U5huIBpZW~p_Tg|T`%?#r_jJCq z-4YgLG~CazUi_)qKrjHjeu_UI^Loa zlS5)*GT~n9u+FFv#tY5+aYI~KcP!SEO~>+|T6M4sQlF!n}k()9Nwe4&dUyv$P^%(1#h7&RxR zc8*i(^TXg_L4C^n?;am?t(UUHSKx}hg`EnOoBs2?Ip?dkmG!H(b#Qf!PT7VZ{z4GS z842`jHptlYQuTTm+tTUyIGiZhz`5qrwN~lsk{u;0 zY*)&md0UsL@I5kkS?XbV|2W_)a@l&otCw()6esW48d$3GejU^CVL$)LQ3w+@MWEgX zZ+f-!gy#+R41cZBcjZNAp|Gll+eGu=c~F?l+3~~4%UI3TOTl$D(H+f*7Y%PlmClw+ zq+A}(-=>)_N$-#6xl5#1T`A*Ss*`%%Wlc)Ft7eGn882&on3zt-YyZ!9C}xJH~dlC^}n{R3!Y!YhL6R0@(!w*nnt`ZIu}>$-(iVOEr8D!Uhp{As>{Kx$rDyp@Lnz6j$R&yrf<4aiCpELB%}WzAeJW-(v^kku6|?bVK^3nwlJYPKhA z)bc;g1_oKo=;Vt?k0s-w(G?o`kZ5cg-cGgr~xAS<_0zbw_&4*`$9)r$7#K$OI)Jt5if-}i(NBB~1u@JfM(9GzL zUtz@*yI}S>36@Evz7~RY9#{Z-gt#W1UnC;Zdf5VUtGVEf9m4|<`mTgleMzGxI7$`pAZEP3G_vGu(W4Hf)pHcDY&?WlVHsa*>%P;J zdbjm4JPVfNwS35^><IY%4@Umb3K<`nbs z5nBB&a_!^&&d@&lv^;m?-N}M(Of;U1`H+0t#m32=w+^~v$z&*P) z4i=Y?;y02w*p7ql6$(~nIykwFJV8pT89{q@i{<^T9m+AuPF;IATL%OK_3;(xK_4b^ zPgt+q0tnFOZj0UeMdxvz#A$scp(o1>x}DM>HhpsB+hdnV)0w}e)d@bKs$L*Q2yup{v!xc`uTj6g zW&U(I;`i*f>E6JVVK*?%l>hai?39>UCVS#!7=ow#%JwMRI6K-wU2F!`TTTaOxDgk7 zAr9}&M0NVr-+0yo8+d#9Gb6>KRjHnz23DCuxOJ^oxj1Wx$rfQhKW2t)apKtFH|~9^ z1`jV3&K&pt^tMH-T)JMv;On<2BeA<@+f7lrEL!)^lEx_{CFIhn9ZiP62NFtS&ye8>B`t)n z@Sx6F^T5u%&?>i2&jwwdOQD*1Yzyy&6QtSm!VsMLvX|h9!wZz3@mue|tTIH-U3g z4f?Y!+?NK9*z_5F8z#(?O|ivZ>k={g+wvl#!$1_VC~Rs!V%FiFQ}hz987*0*QTjI0 zpF?tdpg0z;xf)^>uxnf7;MHua8@^h8v?6lTK(Qt(faL98r4xZ)HTdd<{@ET(6d#Fb>!=aj%qas>B zg$p|1WkxpBzO$MHuWwxVHtQx9`O6@wt<52j=(C{pvB*nYwj*CK_VY7sBv;THvFy9~9Z?{S`8x4n15hU;a<+2Dr!@Upue-$^15t*o(}im_=pXJNB3 zyy~q5dmA@QKF@@uI^eC)iiECnP)oOs*V@u~BIucJtEa+sbBmwrfTaTEt1zP3*O)ZS zewRw}>hDV!qv5)zrMBQn8GeQ6*j%a&*d}i*mvPNk1$BuxYFf%YpKhxz54eb}0sQEy zGXn3Cu}}lgvkZ=y+l;7nT=s5p0*5VdBCZeDee@Wr7Pv;%U@KZlm*_s)?^!&AIunNt zbhD9j%)^{cVY_^ecxc#_v&r?nXIus6Hb->h9#24@B zj^FADOxmOD>IrAy(`1hBp}Af|rdl%+1jFj{2Oa3CmHpvoj?@_4bpv|cYPjoCfx%+; zpk$e2r7|-IJh?VYc?b;rZo$@#;E^lSy&v%o>d^kr6%d7N{>nm>zDbH8UoowtEz*Hw z|EantSE&o)v6;DKH&)7{oHLD9Xs+fPo^aA+sI?HlYTH-OyecYIwPfDY*K(}P2g4Ny zbH~j)^r=5HYEM_$3i)@Jj=W{ROg0|er6VV~mc73ILf;HAQ>uGurWTms6XLCk2|fl~ z8IVV_u?|2#`**D!dHe>zVoLTBxB&9`y`3S4mt3KcfvVdci~}W4%AM!vO6#WCSHoI+ zt(edy=u4b5aSeI#yWylfjw(Q^4iNCdwSIErCh1KnL_L)6K8HUPhX9&N#}`2;)rk^r zOV<~pr08nSk3xD#s`pNcT;Iij&<<6`qK zHEcNn+-lUsGE*YkJ*LFJFen#O`XcO-#p$|GU5IU7vuE-xfs!lZ*kyi-&nmvfoq+o%{01-4(l0R_WzB=h^9{5LTSg&-`ho*~@jz zIm`J+u{Tj@3(}T8K~hx4t3W>RvHFk_e=szEpvJ>IkeFOJgLF#396TW}ov%=NJ60S! zM@km8zk$&zE2CAGpeKhB6VkIEyHVu0{l}N3n*yFp+v1p)W)=rDa*QxJ6D0QuFIfZZ z3V~}zLZ5=5MuoOZO)9fu6ZU8LM7B~uFm8{7Z@-)?w-S655bnU7m5uFaH zk`7?Ar(&~k#%$lhOdIQd^vwmC?XcoH6U zKjyYd7Kl-MMo)`a6ASC3L-G$aAjtoCOaQq<{^g%1a{C7zR=Gzu&NCdJf^}Rx$Anf$ z`Irdh>nJ@KQqhl?0?j_rutq<~VMv~ClI3`fDB=L)A_ zq)iS zv3||W8l@vEE){U{Ovjp^Ybw`)-b8$_13ko;t((KPlz3o8OGi@y;N z&y0&OVIMDyh$$*SN&o$GCSgBmIcK`^Urw%tVGI!cQzS@n?|6u8*jR*o5K%%NTB&+g z;7x)ls08IaRVp_}qLRWKt;7P<$T7(64^Nl4)dbfHQ#%BD0i9BR6e!3Volp>+Ky`i) zAcrx|*iYqkpt!FA`Qd*KS)KKg^?#&;I13yscZaJpy8Drp_M$`Uy#ZYqfYQeV=TDJ7 zLypX&rg7Kv7dK1>=8;PCX9!19%+u=u@dycmSht+aU_!|e7gD&O8|D${S@;Upt##kf zB!+m~6T3w2L$DpU5D(mhZc-4SKMc}wqe6|cXLmZPj=IxMeIOiow)oQwuc@LX)+qO* z1Xl?KVpt0tkd?_6qMP@0xO9a1d5InV@e4Hs=&h2~J;o~GHJqu1NkuB84I5rvmL=km z&&U8o1*1&XguNzMG=xnuJ6}m--CS^l?Xr}+W1)5E9aNl{VdlZJx*!zs;aay!eRs< z$&^s=wGZTOGFQ;c4;@IM3eQ_3Xo49kFfQ)Z@V*%^^2&ozh`;s!?qru$&UH*4Wh@fe zvDlfqp#|cpa(?qjD0UCUDy|~YJdXDJ31lq_HBDqLix_;4@E+>xs0_J>C~4mUwaz5i zJp|SVYRqn9e5EFVw=cY&3V6I)?Gn>u+v~F1Z>=-WBH{+!i`!{xsTW{ARM!qlI&=yi z;-<1r=RXWqwuTvI{OnoW(CS%qbs_V0K=2)Yo4L4?>Tz0U&*|(#Nw`(2onp(fcL*n@ z(e3I?Zud;hmdE-z%ltjfsqHm(!iOn$3+30 zqlbrwE&to0&)({g`2X&XG1C9zQvG{t=0ELR7G}Edb`_R?6)~~?+qgiogv}g3!cf*LbI~9BQd8zvw}35d>sEp$nVp`WlU@aUZijb#AYfK5{IVf+A6Je zpzLZcY1t&S3oLGOqZX1?mufUsh-S8zoNW~g{#c+1FNGPUCh6Cx)7C&xUC($J=&1o% zRRzE!skoCy3WU!1HTzr=z5kYKC<*(qd2ej)nm%e$Oxd0?(O<^lb!3;dknN-^Bo@rB5 z8{zUJ17A;1)?vMtzI%pJ@RME2mR%O@#ss}AsWX4$WdPr`(J}$k063~`$kK4xeX3wN z14YfitKosC=?y^eKV)Me9 zAHb^PSuN@nGNSnv(B<$5AxtUQb+@8}$8BCqX`AB=_30S)4K1sR(c5yt{d+0(4|u*L zNM8=>RPN9LTfEMvcP}(NjzkkE-8AZTTd&~Yd}mSNb3AB(kq*bfbhFxP`hK92YkmOK zbzn5OW@so6YGgydfEyqj`-IKMi?OJnq+qTvv`raiZBZT&L8>@G-)n#%&`X{}IP0_@ z!DWzEBXmF=8|QuW9Br~woJx^D*i=2_9VP{P+{C8{qA4B$kb%a^IyW zhSFSo2g0G&1s?*pMHs4y-jRq2NzKy2?y&^mf`54>bb43ST2R=S%X&~dUzuG}A{ro~ z5YJQmD>sv!ZT?rs-d&7hXd6#P2mj+SC+T>sYA>(*AzEG2F$+)Q{q?Df`|Vte?(~N4 z^YuC$AK$Txw{4)XK*4*SlV)(h@_jE_2jBbgj_>_3x$Es_CUAh~u(zd@{Y`3X|wkih0PB!ubNlB)Q;@>m$#EHJfF9Pz9&BU^m=%TWszq34y9!bTokd< zA93?->iKzFMlWg?9|_q{*|V=QEfS2&9-~((&-ykwPAA3p^{;aj7oYbpWC8;khRsuh zpqSdzD-v-oud~Civ&}hj=!VU7FA_L$J*aaljP_UPXZrMwDFas@Z+AMMFHg~{G=87q zeXLo0W)*4^{zRLlGj#WCaxaDYylihmOFGANS{@QUsL&-JXW1uJHc#9OT?eW2*GKA) zFY&bgJPTVGbf1UH(U}jR4-}lODr=AD3T2;#@97%v?@!WnY~EP#>tNOjEynITr*}bJ z#f!hTvdo;&aL#N|O%M~0?DujTIZ~${K4`nXDjJ$Jc<$Dpe^@R1crnn3aS0~h|9zH1 z)h|_64eU1}D)%DQt!B6wXg;E#w*1Xj8zr^l2wHtXr{lxx6BVSCC4qburhEU#Z#4=H z3pa@yrT$pIOl@F>@a;mtqm8{Pu82HA+rKu6wu=|TBFVCz4eUmxcVo9gf|tO$Tqn-v z2cK)ytpTCytE)S|=Fz}-E4g(E@a%zif$4ajl_0qfGEeBE8q8a*!)jAmz&ny z0HVBjzDkeXI-V*d{0fmU1^KmGUY@s|9Ut-OSg}}Gr?Hl&snidaST0imWA3zJ_!U!P zy?(^cr{|}sLe53V(Dl6sc>@)-&Wdh>7heBD2p`An>kpyA%aFq$O7;jLnGg5p zF@s9b$*4qCk2dh z3nbF@?)UR%Fm~JD-|6wzxUdP?r_emWVe@q8)8l!=>H;YY<^<)>GMVe zz5DN_KBfqm=2}Ft`yT~*q(4QOU``(rUb9sCHP}}&_tZp3n6qhxFrx+s7^6-zS}`4? zx)Fr|Zj^Way0sqRQD3#0GdkVEjnrA(g+p;DR1H(&iykycpxHSW+l5Y&;vzQj&KU{z z>CbVbp)G76?M_w?JhTG3go{n=$b?N!P3qmU&BU8d^^atdwH07=-26@#+8kqZltnq- zjy}tJwwx;K7deaFO_*|1D=`bHA_@Lj6;Y1f0!df@+A| z^o45=SI;EtSIcC-VSarbKOTWmSXX_0o$g7;tj2G+8(m`IURc~TGTCaT{+US--g-O= zX=s6u>B(vyQcfNl%1a$cBUY_;^T= zkXt?DLZXh#^MRE(tPLv<+W@J5?5%Q6tI)*&Uwtx`^w)1{ks_KB5zK zqUi13O}EQ4Z(xtQ6^4#|z4m_atqx>OQ3*HgSGW}>*iD-6s?i;KYEz_}mBe?2{@2?S zCklQa@5@Y5O*{^}6@Fj4>?rXtf6Gx@?0A_iT}9pQX0TlzpA#3;Iaeq;(8d5UJ4%i~w()Gj=yw}CLAG8jlFgDn*|U&R5C&0d_ds0=4g^a51Txr@%w zbqWvO<%CbCcd&qLvFy}7m)Ocnu=p#u8%Oy>0M&%NB52&fOXlNERcdnDp1TreV`C}nL zk2)Uh1A9Jgpt245=I14XV}tWEbGD$?j>n*5oVpv%+9iCB1?D2ho#q)zyq32|OC{Y* zB>#jo5B{76)S^bkyhoGz)kXcU^jXWfoR+aEE*`VgboV-gw(_N`yCPn?&Z(tS$r;hS zZLl2=c7>8B*?_7v>lemk%cZl!v!@_$i{m4xv)0vO!RX`R>inr>Gu+#?V%X0&T0YMn zE)uvXRq1E$l!bSIFmJMB=b4xc_{!_A+t){Fg2luT`&)bi-3b>nKCHVb*+CNV) zC}nh;HLqF6xDgP4c;?Ul23yC{FW}oxb8M369e+HLdI!|UQpGev&uej_O10Lt3lD_! z+xA-|l4enng?Y@YUWRk+LCxe}X|yTy*Zc;BdwQj-`|9C6HjR+Y>N6^yWI04|@_7d3 zp1iZ-kkZ&JeKR)7kaeiOOc`<_#3Dvjug|D$iAQPOZ04Sjxi_6Ul86l5d8k6bX5|YW|K`w4>AUBSG%tMj_(E=ss z0RVT=|lI&(&SUPM=iR{-JRQ3TgyK;EMGu4i<-KxA#STjq~nyRe#%Lh)-fPTM$=6N~x zb-%HSyu7cz{KjBRS7?@y2ieD8*~NaG4#mL8@NfpujC%x}ak&9xxN7?7Yg2ZFbjH=B z`x@prF+<)L*jmvXP%4)78^$7+95*ocb2q3%n_(gWSPn}FlU#dft#?TOG%QxbJ7xCN zmj&yfc$1>SfZ}AVTCyk6J`yHnzWyXHMJm ziz`D=855=E`vu2|xbB?Gz}JBlfL~8+kze{=KUEdl`D=^-!8t${BB04&q}))iO`k}> zh*p#CY8Lni7|-V1#mK;<$zDnh_)Ps}tKSd!*6vs831iLRwv?=xb2U;`+4wex2u0k) zc&gA6Tza35SLF&-h??hztkUji%=&w6Ewi&4P zU-bR&wyzx=+#bVm%J=B)V4yu57ZiL@CDHhcE;v7(q~$Hi@!e3}lO-sJ^-Nd?UHeBy z%;JcZE|_*RTCybt_u}R_pjIG$V}tJi?`Gv~o(B8nh4vW%`yiu^i1>!@6L;rM0fqrN zF`Wx&3Ot5%e?N+AJ2#F1S}1~(sJ%V6??==eA|-|&J{mh-pBEjC7Z_n9?=jhWx6$-u z*{0AYvV~9_u!&RadzY$P4JMK6opTedrWTOD9A`M}31MN2^E<898n9V`S=Sa8SDjFn z9-@DS2!xjzg+kiu*T*#3*Aoyq$seJxc4W4e2$oGjuo#gDiq(&OHL$yw4Ipfro%O(L zm<%LUEmy4^UhM>)36gMEkZcB7HnUB8BS;?S?%C?s>g9M__Wz*ntAgWb)+I%jWTC~( z%q)$Vnb~5rn3)?3a<`jKeMBQ>V)mD#OOQpvpd`!n4hDOa{;OXA8$8Dm<#6Xm0 zrAMbzLybKPZM)%c{0PDcgTL?wGDdhEux%~aWat!uNB~V%WG+=P+R+prXWTHb6N1qo z&}6t}oN8RMYMnu5y7V2fI-@OaM;xE$gZBEAAgU!5$9E{^$sNw!I)<-8lIE+B6kChs zSyUxVxi$%b4jnv(Kcmd~E+GB*E?|Ocw#rfkT;r8#h4BmIzFTm3zPGjH2U6FVk+Ph` z%DSZgNvA&oD%OzL#8}{j^SK^Mkl`zHD-puJiFg7~r>GO~yt^2xwN3J@-JrDUnh@kK$kQ0di6=|Wtk0?q-X>90GPqoqjhlZ4u`3q0A7|%9{R-X% zfcDu7R5fjK_K%#oV3GvH_rGrr3Ks=^g_{KM^{uP>yUg2Df~aI^$q*dS6*eM8O6bWP4=?8+%*t>m#zg(8T4Nw2};htmfB& z-Eo{xF2~m9(r@g(k9=+MpM~3kV*joDY`HMf-hoMWR2K2%;V|jBvqri3lAhH<+d(;2 z4?BBDrZrK$>9%vVO3v)zRSvA@=C;~HUmJUiDQ_&GwYt8kPB<^)~LEp6TI66T;~I zT$C|gBeB1INPE40WtOak*va;B_b4=Cg{W&3(UD1VAxouB5?~PEj@#;xh0n`)IWAT3 z4x{F+e$L`o2Pc}z*xqBiHTZ`w?LKRu1Z^{HqKsxONyd_^J^DF{%cY+bYBYYqFsG-v z#dCcoBob!*Fa!Xb4_H(sP>*PyOW&B0+hUW0W*$G^3*iJDNpCk=ABu!orTYZEv2z{4 zuI_EOGfNT?CfOm<1E^uQR}xi$qk=$dDDo`7W)eQ%;quEpveuk$0&|}X zNE_L(RAx)KG`-?2J?3Zyk++DVm7E>{k+*&!@SAbXK#xIWlb9UZ4Sf7V2%

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

    f ztMf@$>sXRv1G|x^kn36;ZgK|x<#=6!Q2!!?m*nPGs+^EUhAHC?+y9Tm%OiZej1f=Aondv zlo-{jT3v|Up~^v&0GBLI@N`PYk21K^(JW~GMgiv}fqR+>uSH#JRN_kwv zGr*ng-rHdxyxU?s&V)aqaghgeo)4;+4wL6hh_Gj@m;A4lsR?vo8Wc&%bb!+dnQa4^ za8ola;wdddzFK-W!e;64RYyLb#u-79fIykVeAGKm#_4L(aUYfq*ZVRmaF$VE2dec2 z*Q-8@SISr_(C+q=oCyx@Xoz52TbX?*cPWF%8Ycta8i!}67-iMeOdk?HM(LPd6wYX< zcjqqv)T0GFD7H0L*!7AL&eu4EM~1*p)hTI5>NM%t%-xBW1 z*d;(f5!yV%HRWy(KsXZFg25wIb_T^1A#V~JI>w%<-!|zX_;R8L&xI=J4@}`0O1;+7 zr7^zlomTGSe8Sm_S*Yu9W>2-g0oJ_|6!dB0AWi4pnxjQ;TDU=V-kadw!O)WTywt(3 zftAS&)T@9X3poAr?2eOx0M#*nxH=|)XW?&PwByxfa=7T}2eD<&$$vioppt((k;IdLbnQ{9In|HOJlx|J1!zm``PJuD`)6!S$k>R%0y$;%U`zBOAY*; zb+y(6c65`&oHGv$hZzHex{N@?6)Xr(e~Mbhe`Aw-ehn6UG{VRR7yKf!ieP}@8+w?9 z;R)k*_)ZU?O(9NkDK$k3*1X=JC;n-K0md8^5#Nu@n>f6a=^hj-Zmz!h*0c>s`#eov z@iXB1S?N7&6e+CR>5VnWBCgPKz@98K9-SFwsACc=BO9IZspCu_f3&J9a?$Y=sXpCZ zqp9YbNRv=Go-iZ+C%Igi8++iUae?0H)~E<(by+>(TD!)2pzW zcKl=g(HB7wd~XRRP@Xl%q<7S3j~|T}GeklBUjLWrky`HegZ(u2!mb4=*bt+`VTu8c zfJV}7tBpi-UiSm(EGYsaH~uTiaePB$@{ftgLMQ8n0%#YRgMPbVu{&?{{y6pT>6jW~ z)Ph3SYe97|XhcD^wBVnDf~0G28Kh#J&M5;TES4b80-nF*uf6&$k)Bx{UgMU+ZDmwj`@I zs#ea;-o{K{=9W!A=GLtSc}BAmMm3@&EN-Htdp zGBmmacis*0TUq%s-0a=TAmc+S%Rr%Hknt>sQ(kguXPY3SERs zb?|a+_rB|h9sw|oGDAt=mK(hBn{O(pZ!yBh&RtwbdY$SIk+ia`U6>%}*hi9DNz1|$ z$ttg^6X;H&5bfz8+@01(Rcl&dG!Y%1Q07KX4fdxcv!qp1DcL?8G#P8-&K?}*s@+MK z4&#roy&i+sW(9evamYKj6L7T|!$8T{dGqfjlNX~>UP_WU;9-_IDfH_fWZZ_?L+&5e z3EW%lMTxSjFUh55Mx}QhwTw%&X|AQnx5?|!&I76yCZ(o#Z?b67skObMKuG*uIHsF3 z9fk81Sv00qo)(*dJ+u)gWPSIRt9H@=8;|g*X~uj6P4NB zsuIS-6r{r&$5Nz2>iGHJ;Hmx9KceI7NU6qmfSy=90tK*AtaH(j9@{cTb})I5&pe$0 zHFJ-q7(*5J`}ToOuNe0eFM75qAKThK0ByvJUgO_7-x~xXf5z9EDb-8mol!F1g3)U=48z#n>D-K3g+C{hDgE-01mQyp!;lYm#b( z*+*aQ`9`k26GEHEvv_`9wC>SpNrt~Q+eldT$I>OPrUUlQgL=Ri{xSIwW!0Orp(@?f zGm9KCZ_KN*9C6ph_vePI_XQ;3z%pGp(j8H&oQ21d#KxRN))&xK^!EOg-fD-IVERgy z%fbncQ~1w!)I*^57OhK7vXL%@pE0`I&h05;fC;=LiiAqUfKupvEM4WO7YjH9QA^m= zP^(B5Ygj=D?ocy>=6B;xiZ+(AWKpVL!1MWT<;>*?^2LNlxYO|^dsjP8-td>t5Mz;> z-P)bAuTeU@v#M3}P$lNi4DR=hmK~{lD5O%QNe&q}o}@mg9mbbGE6Lv5Jm>CD%4i1f zdi5{0c4Ab8EOE_iAN>;fHr|L>*-&Z7jy#@UJO?HW!ekeHp;5~qhI$Ubk=zT5i4`aq{7Hh#)bUWdbi8=hd)N~` zDo4-+EDxcB$uZy$+w)_BIR~9`7s!4jk?OC1BfjrX&2TKby^>{1zDYtP%d4^p9O4sg z51E}~r=gf|}*3N^q@4L8Q`UFCIW7F_A`Oa0yJ5X(_v;EDWV6 z4M=I|RD}U-8<=t~dQXtA>2WDqtlTw3p*~Y%lo07v(GtuAET6qF{7(iV$Y3y{@C&Gm zxGR=-(6$&0P0Z?K{&yuw!0xjjT^}9yB7d({vBnKtEtyh=f)J9KwVFAW@-tKk(TRLH z$pZ0Om2HcKXjYe2zCxG_o#e6YHgc=*CU<8*1~S1^+`(^HUNyNt$JGr`iHfu!36ODd zCmCHuiUI{_O8s}7Vp2n4%VGusdxLmd6n-vpj-v(0jRUd;qQS)X+am$7pR$cAus^2N z$<%v)3!wH>8N#$^o8K6vgyH$u4f5Gq&~M+@_l<%hM;TD`5wFd3=*D&txzn#N2Tcep z8>*Gh$v6G1mUQjQmE*4cEO z@Fr7|u=b?#)dZ|m*e--{*MzLHRUxe{a@3GV(|uFc!j*}lrEdhKLp5pfUkHkL%#YxI zA}BKz<)hnWLdT@>4P{jz(xkrTXXeZ+Rjy*RKnrFUgSnOd$Byq%nYMTLZwo#fE z6tl=-M2%V?e5LX@6m&7(gISj0M5Dv{eOXRITA@UREA134VMHrDYy%O*IO&!mw!`+g z-+`CcR)qrovD!Go_qfcofIZ4vc;*ZvEqj$o@@psPdn1%TlC6p)ZbX0%o^$9}MOgDGP<+iNW_J8!0Hh2>c4cR^zfUv?Z%o_6}gE&NrzD0rpI;bDaU z?<9C?1?630$`yzW#yf6UO6@QWMRqX+Aup0sqzbC4r$&7b0urYrkXT|qxU5Jc7h6Hw zmOE!%cup$$ZrAy+R?gA~$x$uj!pHRUr*Ip0)Q`oSh`kf&K81e(C~0>GkX`&sDsOp= zO<^g03uMm+67K$Eoz)6dYR8dbo-@jz=aP)epi+ycKHI`l`9@YX6Pwi3ih0a!dFJk` za)dM%EbRUo2#s3yEY}dVBo;YEc7_&fF3WQ)81~DzjT+zlNo6CB^d6#!vmy<SVPvj8QhBz@K!RFKl14OOsk~D*v7y>H( zz&VHLZH;u9P<6$i+Zlt)EC;O$Y>q)~4TWuVl#3?as&F`OM|TE7mL*!aQVES6vW2@o zRcCTQ^zsk;KnFs-NB81R-13^d-4tJaoxSn;%}zw~UH#o#dboAPJv$V^dm6j*{A$}l zm{xCcu*?s{&$6WoCZpWkjPB~WIx&uY3ibxVg`Ft;@5&DUs2==h?fk#$NNoSJLnku} z;Jc0l_)i@=_Y-Ap7U&TMyTeFmZF?S9_PmuF75IMY!l4Pe1 z&%*G2*lpL{$Cw_fM{#v`bohY(j`IZ{L|H4Gf$`UXGKA|_zyMdkTRJYv(4`#iN$D3c z@2oq&SIU@eM8sdR85q1k8B|vd%1HV=QKp#pARJiE)w*Lx?E4z%NT6WXan4_ zM^CFz-RKJzzl{(lo~76b1Ur+2#sgy;~ta zK!8#HJdpqHLisPPTm@`wY@Hl6zp>O`8w1n78*4H%{cV5A^p{vM{UugRe~A^-Ut-1d zmsm0VC00y-4H8U$m6`vg{J&;c{}TMaiDCUS;Qx6Z{>?sQW@Y@Z4C_!^GnTZ)-X~Yr zJ_odHu`|(+pcfDZ5R7Og9)=w5mch|wNss}Xe@f`nry`=I=JlR)-n21;6$yHuwCB_W zHPU&%nDeM{&Q}-vwdc=df}_N2?o=+GkGonb%0WvZf!&9#wsaV0J2HyZZC}>sXG^Fp z-ei5w=i@f~*Zq9pDM*B_*A!W5BBM#T4=rJi&+Gm5WUTMUCcN**-RLvv?bqCCX)OHL z=S6#nIG^148Q~zyq4}2_a>G4OXO2|{|CI0$VF4d8g<-R>H^VVn+ zO`5GU^mI1+m3IF4RkitCd~OK%t8(7g-Si!%`&Zq=)rOnSvQ@67dJgr4YxXpJRTado zx&WE}nEmzM$#GjsA@|#+ZOwZ5pe{xm%H&e308YLeIvJN#R=H>@s_Pjs-vr z>5#{cW3pNX@OEadoC{pDMlWm-^L=+_y<>^1wO%;?0lh6!{^jf6Zzt#@{f3-@L@rzF zR~-f7F9Qc6K1=0|zqRqp;!@)}iw*G0<{)@BXD-&g>q;?lNqO z0bJZq|ELB&*M|OxG4TTv*DN;wInQlVdB*|bo`cnQ1uM|Lq_d2}{x)I*sSRv#Rfz@e z1?%qR*LR7vu_*`8u4$Rtt&2-xNf}{w;hhx}S_6K8*(0{yt^zho8=mqzx<|)VYruV9 z2d_^!@^M+xe-HM2trd+lt7J6LCWqJkt%KM;+O5)lPlEbla^(@?);wY!{MYaFbKoOf zVLQmBnN`NKX#^Nx1{mBwFxnu4Ew7{GGIDDVv}A3VX>ZJ%Ku;{Ijcgltu7uu|s1T=( zuIB(&2L2EjZ=PEuXq724$09l2V5%)HHTK@}25TUetN@-^Pk7Zk3gG)WefPaJUay!2 z;7z8JB@Mr$x7t~0RLb+t2LO3C*RI)!a3MPipQt%bkNm3I32)p4?t|hy=#fABFUmt^c$rND~TS?hoL(eR5 z{Sst(-0C`L=lR_ylg7#TVd&C8rdJJh}laqDTs zN6z8)#DJ>_>X9CjuZv0Jq@9W1=N&vXD@#7F387f+T{u@$G#^AAUCa8N&C(7|>cG$4 ztbCA0Mwu_+V;1L`JzuB0so=;1iX#-!KZ18sv$rKQq8pLX-S9YU%or^pz*DPZOpcg--$CSpj%RpYzt3U@FDvWZqQG)#UZlI z(k7iiahwoxr0s`*bHCjd?9AE|uo*YfpWY4V;(bazvOr-r^33*lOBK%au-)Ww%{K>@sdVah5x_HaBMw!0_dR-na8AM#T0z?10{TN{HvD7M4&^DLXB0IID z&3=Yv#qJ{CwtvkH#V@XTvcbrwvT64)9u~JIE0g}y#7P!5fZ1`dXp-8<%5~;DHWlxc z#M+*QCWfkt;2KXhSduS9i3+t8#-UNzAL>jnWG+5}uR;6>UNwv9aNZWQSgEokC}?|9 z6h?tTvS$_#mD>d#K~S#kj$bb!as-V<>av@r(7rC}KCgyiEFZVeHkSygtJfey3j7A0 z%X2i=vmV{@A)?Skv~Bn-p5A#0gPIh%Ny_L}bCfPJMRB@tH-y%~^-^{ih zS9EF3Qm$O6$`s3s^jNrMlQkcC74hNXdk57*=c&@v!rirr*x3%{I^JNw_O$R_e)84D zD?B@Rfwbt7$5=U}9guGn{T@0#WP<~R$WF)cMy)+W8gOUA&gHkq^O(I#{pRPbK5>%l z)#M8R`uXCMyZcL@7}m% zBZXBr&%eGZo)lR2VABfwTKsN00|{6JimaJ*tan>j*#e%UbcH=t}xxSH=`wjL?}?m#AqO%Y`*EZo;29?oIjB%g9|+(YIrEBHTB`NvAyb za;wVeGa100yGqx5B(j0gT*`@*{OtCqkv?$MDIOzY-_Q~h?I&G!cU4c!acLlu<0CPk=iV63H*9t5tEEZi}F4c zafGXs*}^FJRU&*^hoU&PrC-rXKtKLC=BV79e$wDOAH^N+kR5LYtZ!QWvT4|JV*uvI z!f3PAsIU(=DI`<#jQC!ZofSuO!pS(Ms_O`3+a(N>dE)KEG!?OK?NLdyuT#rP4VFE7 z9dnS?2glppbRY02(3lJF4{Qre7jwgvtQ`GKqFD?5R0yWiP!O}PEtiepfQmGLl-pzXi*l2*%V>y6`yN9&{K#@Uk+a(spfgC*PW#^|00Bj@&Ko z24}W?Ui@N9cWxkerKl{vXN)0b5+k;(r-rnTC@yj>N(-+C@6C>sf`N@r^4BgX5;w%O z+#6lNd_cKOnM3EgdKK%jnS|b^mNEo}M+Ln9< z^Uho}BixV%^S*Rbg}-$fhl)aS#<=PH-uqT4;GPqZb@-3REqv zx;v2MN2G>(T`GCX(8bL*R?7 zyh^b{g$;^x7bu~S56HY3KK)r{h2jy5Qd;zQ=xxgu0h>UCn9kZpA0I;&fxX)+8Izq@ z)_r36R&=_b#qFLZ?F~n*gjLMhWo(QNE@zh?%q5p1Tu}fUvO>CAtf9d3FU^-^G1)}JMa*enp#o-?)-~K*C|5_9w#FkHu?s1UiOhK zW{js#EX0(DHR-s8+;;kIfz1YU@=l4p#E;M>w%B{dGwken6^^tC{>7dS?ZTG=TxY}qm62|Vb)o)DH?Qbs;1vMg_$Ve!Oy{)R z1q`JScM1Gm=Kj|!vpv*qI+FC*qoKftNppP2cXpoaXY0lHf7xl~b&p3WD{(RYwn9Yv z{VPmz>=MU4*-QO-jm~{e*P`Dj~(m3cWWeZp!b)?Xe(kLrp?H z1eo`g#132~fWqzw^V6`oD2O6VLO3$g`^B!}_mUR6JK@vQiI{a*lPowA>#46y%vM5w zz*JRQtQl1tH;dmryQ5j5xTcH7B9+(Ao_sH6pxDJzp){XI6_!V=pPs7P$f(Qq(yeil zC>eVogStk!cC5cMqc}jRbug>Uv^v{_@9JZeReLF8CJxZ;<%kz!AY~&^;62I!KglXo zwaKehw8>$heD=Xkp-T%T|tWHPO#-e*@5-idtZ<+YO)rcNHBD}clG;BMbab3VxzqNkHpe}7^U-EVzf z9OBD+SG9ZZua?V3hFI9i4B%4Rr(c)6y5OpBA1aJz;@ zN+`>{-M70&Kwy1lzmLDwcsx%$YR)C1I(gVNG_92RC3lgo=6es4>ErvU94W0StIOGA z7r%aqBd4sh>;6?Acmcj(`=Tg^3(D(u@0w*WafeeL>X_}u;+hlDnL}$dE+u(ZkTe-@ z;T(WslcoTkVC!{JDm(UwT!{xKb!=IxZ4Vh2kQX~x%4uxq3G#W*533-XBIOdMBs%$G z-Hbwn2)|`7s;!V={3exTa$raX&`Qgk$-j|4)SQJ+!L?q6@sfF>{$RS-DX*6zO>evy z5%~uY>-+R`z3exW^S<2`+{}6waga9AUl~gIiJNpkno`f8bU#Li>8ab=-*c;dI~|=xuU^h+b)SQ3m}E>_Ho2X#$5kBMDbR-gBmHjUIIeRsfwORwpS>a>O6 zxY|u8y}8s7&3bB|Ses$Fbm2#V3nsR~JunRmwQm8IZ?xaI0Qir^=?0xMs|Tq`4S~G? z3>Fs!^=!ujyjPVYsOI|nT7XDcOMa@8h8m4h-S*W*Cbf$3lKy;cpZZv*ihzc0;mOlk znRZ_XrYhz1S`XA%Qf}e6u0mm1QD4ty=eC9j&rom~4#hE~0aKW^HtGvm0t7>2S7>DC z551J*nwN|tZ)E)gyoP0r<0Z&O65G0eS6ZAOm?PM?gdnD=#VVtCqR5T$T5V;2|u11A?t?b||FDfq$7^UpF;OC5J9iLgDe_F9o zD+($+aPcr3yOW|YiWQ1|qeAfX7O+U%LUm^>EmxctGdr>^n*5_IM1<2=oy^+0FJ|Fp0+OAx zlCXuWZt741uIT(%Z}^r`hr{kYD{UCQGg&{EZ{QL(Z()xM<0T)E*sIR8FGx(xX2g9C z4(?mf8xJSfqxYnzgVV(RrTx#gSCOOHB<-W*2FYVL1*%Z#aIklGgkIfdx4bYT>C8Ao zp?&mkQ=8CMzRqQfwS&eIPT>tXZ{=^sdB?nsV|l(w1Tk}{O5G;BeajpOa-WQV+H-g% zIJt6h7Gj;Jx^>@%kGj%N`L{Q@BFgk9igo;u07+bDN`q}qc5OM|yxcFZ>r&qomYqAk zN_R)kxD9 zia~a65{syun5q?xUCE@QK(ASS?C&_i_vt&9y*fjNXv1q>3ot^^J7h1}vlHvrW z7Mf|X?Ul%WUz6@KvlmGKpK5eZ@Zx^hJ0JwU4G19WehtZ=-|1zVxf(J$hx9f?Xbs7N zXP~<=HPVppW0JVn@7_|hbKGl68Y^~VJtrR{^~pq}gV)1Tl-f*ighSikHh&9s2F><1P8d!Hd;LuyW$m@n$vdWPJ?PIW^L+ zNR8-Q z+j>?1Y1bjkwKdWVwoDhx(uGidZYpM@@cOc?1eso7rk15;ieyqQXC0t=7c5FVQK&Iq zBFO>G=5{XLG9hGfpq+awa>On5aj642SpDRmhnZpOm@qh|b7%!{firvOHSY*M^M zFff2NSY{cmQ9A+S3*!Ry{(@Zd;BMZxOcWlftSYThfYcQQ8!=Oej%@PD*QCMh$DdDp z4h4=}uJ$X8afUnYNHzs@@`qJ5R+!c5jdbO%L16lD9hwxHOf~9JfT22z%7oxz*^mNZ ztQ?7&#ayO*(UTSlrIK46>_3Tu8lz#i+1PJQ)AW)+R+L@>ahOQvtSu2E$lF;C5dtvP z%AG%nWNMXH$<68GiSOF`b;0hGNLEQAkW414Zh!bN*jPsY6DcS&O0SUDUl#rm0ZKB3S?Nv^qqJ!D zOyVRKX-+nPe9a+Emf6$>$A-zPZJsfE?YJpa0HRi!-iRrh7=ceVV4H5iB=H`J0p5e( zF-n3t7y<6$ZNRodlDLzo;1d+5VVRO(?p07Ne!l}dq|o>d5t@J_`aWX*{7c#^MPs)Z zSrb@-_K|8q0%3i zOD!8A1+T2`DitG!2)TxlZlT}7j!#ry6a(tR#Ys)rptg#&^oeNqJKj`V+ymT}x6(l3rpN-bu% zQMwbmj!GF?i%&>Wp}yHhs5w+?%+J%UW?3#CWtZ_lZZ}X}Ex2_>ID{DzX|(;Iv>_>Z z$t1ay>O_+Z8%po^ow#EAr1>-19(|ZJHf7c|P6{V{S-(@WK|vOCHm(k@~eU7x!iQ&=?ps+X96mFmtdM6xy|+6c7jNazE$ zhj3|WErE$InIqV|N8*pc8nz;y^`b^GkuA$vVhz=fd}14&UO5}MFuem-m1V>DwaG<2 ziDUz1`D1Do$z1zV0&|6kGBv9zv2UD5y{JWoNwbO7HIH^7;S-Op&4nTFaSus_ne%tInT1QnbVQmI`UDs0FLNQ{Z|8cva-yRr1IkeN+pxsvgy53Z)TW5PnDek0>_PibL zn*~`sZR(_!J{zV-yW6UbJ*VVILvhcyBmFXbVGhtjm-~7j==r=BW6HQ7TkVq}bhODd zE6+BewR0bO*=yC{LjS<|bZ6%dI<$R1RJI!Co}Zo{BD%``L=UtDMfvZb)Bksr*uQ(? zG5#l>WM%pXPckz7k9<-^#&UxJ;e$FrXHAH7GKyD9OL^%(=4$t>)s*o~?SPO*`ARip-^Q*O>*Xp>c+YlD`~qWa~BMGgiJ%tB8DucV?&7! z)7j=bOp|1fqlM>ZoDWTwve!hc0(`q1e7(;1bKriF2!0kp#1P)J99%;FiXnMupJG-R zj_PKO)4B>bnz1mit2;ZPT`m|f4y`|0F=XE`fjIVQ$w9bS1b{&MECe{wv!XXpU|ne_ z4;MNZ%{XAnSMvLOqQ`xZv9UoEVJ(jqP3mw%Vqg*GW*vR#uwr%|&bn(l+(nFRC}ct* zf(M*f%;haGkmR0I@i4Zd;>#}L`-64_#}0mJCeh>buv-)_drGt{U9ZpEcUvb+2%#h& zq6=SukFQO>yf44YFJwIcBF=5T|L%hOFHIQ#lX5cuWtz-?nI`jJrpf%5X)^z1n#_Nh zCi7pW$^4gTGXG_oEPrV!%U@-dzsf9sm0A9!{J-U%|G{DZFXEp68u0%=_hexHe>8@h zrEkib7!#K{ zNn&j~aX%rxd^n3Z%&!vQfkiXP5)~IN6Qom<1@^qe`wRemGCAbkp{IC$Qt=OWH3fuE zo#!w6zB)-Z~D-9m$em;B`ue^97lu&BC*F;3KeTV@DgZaiKkgSXt6zaBSr3+3M z_EJ{=5j&&)6+tXVyGL$cAEoQ)xvFYC?%a>rHi`Y!T?jkNewPG>2OjHh#v6SRfV8nK zzjZ#rj;CXe}<>z@qOk;aYV}Uez6(JDNuENt%#R+If5O;Qa7i59e9* zKqY9sg!uZLw3JgkZ_&V6#iwya!&k%Wv2~EX2>fbRlk#;8pQVsgF1m<2j+o$dSL`*d0=(~$b~jiKh&4wqQ==t~x)Z|F7B z(U2S3sDaZH%Y+6zZvz0wQ6n1h9HaPYs;rKB>P4npGxzFqLR#7D^wSzhz{n)ZpwHxy zDK855f4@K8MZ0E57rq+DGyH``e0o0Pjv*Hs=s^vh0{A(O1gE0!ke**P47he8w1K-d z?1;DHeP2I3Ret`yWy)p5URADQGREnF%scHOjwdCd)r8yXMt+qXVQp8Vy)5yQl|Ewt z_m!?3a1nks?hc!zs1HByDljc(V0-SVy;_&c_8bOgfo!8M5$gnLCbtvHW`RGIAK#&# zQ?gZRXPiYS6GpOZfgdszi=#J_cLcBFQv9_DZ0trHwh@ja*B?Icw?-y8Hs+eMj$kmD zWb5~l=#OIe6jqDMK38+S`I*)Jbh6ip&hIR+IBuPCz=qp81yu|&Hn6ttoOL3`xIL+7 zSL;mh}$kFw{vVsD6AP5c_hto(l2va8Hc}RUBLFJSmB>NrD`rZMi z5m3-07d@RM+0U0wk!RFn#CrSif*3>$VMZeTGzSYHs624;%IO73I%AKy``1rIVgrWN`(|`5FI+?vfnAo@es&he?ZEj4X~!FI z!F}P`UJ+8UtQm7FCt*P-vQToTX_@7LdqXgwF?Yfj1x_$Dj_v@UVo~fW0)xBFgU=Su z;0kQ#`5SNtf_We;;kc(Xrb3JazH9}*vVG-?@wQ1wI<+G$ovZii~GCptffb0xc=iyavl)?M)2T>`dP zyRE4Wx}4bk@=5qE!r#!R_so7lkm?`|v+%49XU{)(|Kzs0AG40G>QV&{K&h6chn+`T zTB5{kj<11nAAt*tys&Be(aH2cLKkq0w&Xs$989rke|?FDa!_BQ@9&vI6qqJ^@}1PUpOCStYOvb=4AI54`*+uZQNtGEyuAC)KL353&WRg;t?K~m#rCXRS%7>y<0bN zQQm4ik-yBfjfACSrJc67(h^9w@)s)I>zZ|n3V0?Ei|Q`sI2-Sq=hK*ujkdk;)+ZF1 z75Yicq1l$qZ25z`D&9=5z>$%~>%;B+a^b;}`UH!h3#fMx-uor}@;$~*k*MH$NN@x> z=Ix=~LfoqV)J5VM{>VwZ7qK@ZA4VS1Cnjt0KT0@oYE3HL+6R!?v=VPc4=n=jjMjNv z;dIX4?vS3Fkr8`-@r-bQ!C1dqQ5t;cq%RQzX5~tqiS@DMWsKr^w<7nvt9{(IjsTOu zqTINBh&=FXR&+y^@L-xz(dJ}-|Fl-XaLWR5Y)kwTJCOKB)F2A#c7T>HqNa`wjZD8A z8#Y0*w{Bud8fr-w1=Zyz^W+PDj4pac3Xf% zzGc_vA14o{qkMDSv%{Rh#%Qa)s`yjz<6qYC`d51)KJ|}BAU_{|;bo${QpdI4K-~Qp zFhq`?Z&!~n0n+u6qRU6h<8MA-1JoX--O-2g+9UCZ+Sw!$`r(bs1;2lK&3p*G zs)u}W!Nx)A!}%Y(k}a?JKfBWRME&=!WU82cQbHUwL_tvLEYs z&rFFQ&py-03%3Nus0ScZ7BY{80*K}!9EAN4E!+7A0cGNnaE!19GC~TZ2j#C5HIhJ& zP$a5f;XzWCM7stD1!8?gm03BquRC@pHM@Q}`tbngJ8}(Fz%{Pws2c9|&SvENuP*-h z9$*4?SyEi$B7uB6*HS?sdS1O*KCM5!)U%wm%U%xSV{6PGEbQ;^Hm1oTrq7AydBSQi zF3p5LdogUM=ffIqy>O(lsktG1Hm9~I1F*4OgGVF(8C&n z-gZjLFf9m7I)XIf9@`n|b~t6a_igO*+~%@4wmqXH*)PlwAa`iQhmLEQqh_&x1riMe5So+vP!akaRnC+24^p;%Ql&H8LTrr`7mHZ@0uNjv%O zBMdBRKdlQz2n4xMK38kmucJ>N9 zZ3QG1ldd*BL+s??g6I+KRD1M31%k$+@Z4jO;@t5mASgN@!5HuYM)~cm-hna%pfnB6 zfw8rFIzl!-{FHPu(MmRzP!FAQAi#xz4)nXN3B=qX(?bIi()0!X83`Kg_f+@K&|Cl1 z-JMY7K2>oV(N~=wn+}H|!WeYeE@S;vpYAmDZr9EZ_M+kXB4Cf&DABZX%^6g+nNHOm z8jb#gwmZI%Is^))NiI9^L~!c>NH5!{GYpLq!mvjohl&o>U9!-I%OH$giSNPJ%RvsV z6xS4#3kX-KaZzQDRBeA_g_%K)OP80IQwLQa^ke(u?AvTc1=#jywwP-EpL?}KJFaK1 zkqbX@zhL`|O^Lj#IzND?{4CPeSWTxTb*JR%jwFr8Sq&ebUV2VT@{gXFrzd_PHh1LgC#&G94a&gw;GRR<{AI6r#AiEkbpbc4o3@C3WO{S7XO{Et7;@mipCY#b3T%ua+0(8OG1tDg|7hM`+8uB1W5g{{de1*u z?Ne9Y-P$hm89v>(7-}@2kE-k-fqqduwwT{p?DnKghW$jt2gN>B>g=?`8eEsT%`gS{I>OVD*Nz)>(@NdkHYliq&kfmMz0?uvB) z!F^&ojR;MkhCH#JXpVtqC~p#A=aszK0?HxqRmN!cDsBEk<{?Y2l!bT&aZ1@owCk0r z*e4Rt8U*Si9-IJO^GupqX#oe-iu%5Bc{}lpO;A#O>7v&cahlKc@!8?4UAb6A^)fo( zg9u-DWvk`8$A=k`*icVF`{ANb45YrH>9UA0Qp6nZ=2E96PXtkxYA0S;8}@SytH)Nj z@o=c=ZD+x(?BI}m-`nau1PpE4n_46%&dT@>mOUifi0!-H7k0GwDOdxtVAYD3^Kg)t z`R$kLg)W=hcXaahb_7Y)T8D0+ z(9^+RBS|a z{lVn7k>+k&OPzc51Jc9N8s~SHcRlY52YQLP4i|ydu}~*#{X|}^v;!1IvXqc4EFJO!0BID5M zP^J$zmTCy!*23yk)*3Iq`YV^BYc?NdZMvU27w3=6kBgB>pStpm=ZVYHMP}Qk&bbn^ z&+#*~D5w=a`L>E)Af&z6sK1J9QoXsl$1{6D-#ddm)zT~`@ms`&FZy)5`;)J#6?BHH z`b5i7{O)Q4(#%f(*mZej_up89>>A*zEbHEc88d_9ig{r#?KOA*vQI|3Hgwf#UT*8y zN}xBcp}*m|fC?J{O!+(na#f&gkQL!{nMhI?-X56t#o4&=T!VFc_dMLDRofmHF(vqE z9&x{$bj)<5vG)l{^VJqrikbx+;ck}5)4!g`+0J0Trqo;}bDiu_Q_&4{jxL7?DB6NND1Lf3-u%;(sD1j*db& zk#47HRx!lIUqN8-4gsTk1P4kftPv$Y$0$_kTCFgD*Eh%MMolIZtOhNNtA@iL_QJ>j zP>KkRdK~CzQ4jN!cOgdb-Pp2HTG(OIfc&}JFo(0SIT$E#bim~!<%$C|afar83ZsaO z_K1+6p7K-&7%{?nlqxJ*13fALS=0{vxX=l98l44wb^QC;I!#A{CJxrLLOYeGmw3NO zv+S*Qpzol`a!_oYt9F)~9@FIQBoQSV-xujGO$#6lWtB)cE1H55gx?5HEXG1T7R0DT z%;1?+cNt`HXk#{&h;cX(_h`)FmaYR07^K*4H2uY>-2J!(6q&Ru0_Tq;%B5iGnM4ej zRIbm&qba3g7+MtvogUO8VwN~()QCt*1_A(-F;0Dtv8erqE2VxzaUoY=s1q7Ph~?6< zsW7DFSt-QvuNG8D!}LmkGtP!ba>kRSLMi%p)0hcaFfITXR{9Nv(#2V_VC9jU;k|B~@URlR~=qV{j7idT0exJlVIUFoRbSI~=J) zT<@orBVqCHj08QOel^0Y`0HP_Xt3P@)g&)Re2P|V)PUJ-KkEfi3B?p67US)raU{kT zql?Tk83DQTf20MK1OE|=OWAmbKuXWV-^KEb;hotNQ|#TU#FucpA8ATDfqX%vYXGKT zy(KONTvZ)3`u>6!4Hc}luw@o5#Xv~O;y~>BL+b|`$?k^HeD;qNcdB~m&E{k%88Dh> z4@7J5N$6@@s4rj{)AZCVWo4*$FAQr;&P~N?W~E9N)|Dbz@sN}f8QI6We&}&?i#VL^ z60p;IYm3(3i3-E&WMrX8*Gb`hLDz~?qzDD(yG(Zt3uYSE&IY`CbQkTD{$a<&t9!B*=l6*PaO z!qY3nUnC6U)rcO0ne?6)xJ*DrfKb&WF^3BttHpqTG@Mj4SSMqCY{;boB+23>ea;yNztAer6@^U zoV1-~AVJ+uD~Fn@A{%_rnBQ$S{~^s9phx=U&8}|ICuB} zOtP>wW21HzddmjLK@<@E%#a|}4?4lXY}P^^G33w8s}g9xI%%4iNy0elZUF4F7=%Ns zKkS>yW4!HXbY~bfGebKY4co1X%QKtHpOmu8)iF(h%M*B+UZBMo&u>p*OpUJ9(WX6W zDDZKfVQ;h`=;N@Sg*;Ve>34(5ZJ%dgib*Ebqd=*wGXc=UnP-PDXk5vI&v1!JHAHn% z`>B1;0m6vZy+NK>aH`1j7;L;~UtW{$m4lD{F91$QkLmx0r2NYW_CLSa|2Mj0{?9lo zc4nr3&>hSFi0)K1Ef@I_KB)n9@B6wYrnZEknj#ctjxudJ}w zA$SVBukEf0^-WwF(yuaY*^$eWXoLxq1AqV;@}Y!NVQGHVuFeFrlVLjnU#}K$c#NRQ zG?mqh0B;?W%Fk%5DpNr7yP_68R87gv7?BdxgsM@HdfnVp@|9Q)ZRd9HnQn*l#-2BZ zdq3jml(I<6ap>C4y)+v*cOKY=%=p3#AhgR&6LW5x9^2!-v7|U>xGfGv=%y$^5%)w_ z@24_68ta08-i}2PXBs^1G@(A9oP_adD&XNm2^^W1&6A(vAd4D3uThi9WBLiYj~3OZ zJkO~xcSiUeRaz%I+}5yv48as$8FF!P!FWwEJE75hModr6dhgtI54KlHNkBf2tueVR zBqKSWYhq_r@vBssZwB~VuQ?&-&b3Z%jk=f7hqRu~C%LyK0>Ms*ryhE0O3&4pPNn_Q zuA+7Hq`u)R(1&>G5nWKyO>0IZ5@R?In`lFaR)u;mjNeO108xnsW)-r0gAP)Q54 z$KPR=>r3h~lT^yZZ2c*$A!t|#^(@hqf>lyjYBu5eQMx_$4zK1E!!zVQE|xv`ONOgK z3A|CZcb%32IG1Z|clu?GdUIL|g`^?^W~Ha5U}DDiPO`S3)cP z(1nwF>Nmo_ez4wU;zmYIL`;}hur^Y?8wF){v~9lIk!TP-S*ej>9&stQy~9MqGA6YbM|O!}RoT`uMNZ9A6L5*Y&4!i}Ci?&g$LZ&zzI(^Y-fSx%kiEPw6yY z%bwWn_fppN>HE~~{bdWh7~ikmo?PG8k9k|)g1HXX1FP~Gy4OZgkC7ql#I|QOi}OEw zpRm#R_=f|3$Z?W4vAFu4$H5ET?Zbskqa(lQr z#pvY$qXph4WKOfFUtVv?C!x`Px`wRFg_Ed4ccq(e*og0r!W{-ibICtrR|GrD6Dl z9<>ccWC09NeZH5FSOq7a=~1XqbJ+j9BAx{#?Q zRf-YbJ&HG|+=MU`5sNx6iZ?aCXo+$HhO7(p{>61FJ9^n&JCgUe)UddtmJ~4Km1XA)fDB*b{Jk>* z6W>TXDzAh+I2|NbA7BZEcT<}n8x(`4m=4X75C=ab#2q{&wdGej^lNe$U?{2d*#8#N zL-7Ie{rx~OU!@>vY-qMH95)*Um1|tg9hmNclUmCn7A08e?VZ;s3MKueyiS^|_*s8R zybc5OvxF5(@w7wsb)#rC&iY!S-z~+h8FkmmcjK3&sD`>$HLo({_#mfE42r;yJG+fv zBq|MiDdsqvAk<{0xF%<)dtie??8fBornUBI)2pcNizTu!Be3(zM57WBOR)2(ypg+B zAC)>05TwsAN5hilVl{e8Ck+d~V{Jo-pF0f?pfR>kVO|*a)@9K-pbs|6+`W&Uw&Q;A zd6~{V>Cuak%FR(`ZyA(AmeBh63&P3GXBMw+@z6JI!`73OyO&~vw4Q+h!rhdUCYryK zW~4OE!`2(2z00zXX!QI--z2acfatIF3aGF_*r~t{Y70Xk5)rOiaUCq?HI0_K@F%jf zNZo#N3EY{tU4yL`p2vxVD79wQ7To_}Q&C{M7mv4Fg{a*5!S?vsULbzfzIEo-B@Uw@ zBgLM8>g%1irJ)}tTEJHHslg!Sz}pt}tcsDSfQeuI$RKE?{DJ+PSS13Rs?P+c{X(?V z?6Vyx1ruue+=*N4Is0km#P#?d^8go;*@_0|Fd+Y2z1DT_TN)kuLBku~vz%W`h%PQU zf%_v9{fD6baGj2mF>IL93i>FWf>6#>X@9B<>sjJ(k^FMNpdrZ6|p;3Q+o+Y z5Tiso#T-uG_4Yrysqd@M$mg!iDhA}Ck)D7R}-|BhGyNh?DL75v;hKV8B6>R?Fz59tb zsNjymYx(b4U&I{|wNeEit565^bSlewlZ$t^bh17+b{BT_pfhB@GlLQ8d(Q~!K^c{I zKAt$b(Dg`(7W~7>8r30u#6V*;An|!|ilfN#=oG9Nb zAg7iKNNEXWTJ$Pfxs|ZozPV5kL4mrCeoryG;dk*ZKO#oc@P*;Nfw-~HSr|KE%A(gs zD+Ys_)F!HWO?O@`yc_>-1tPf7=PCkgFjr5H-i!`KLa(`qUdM*MIC?e>M75|W=1K)9 zK@+EZ4;H7f06_sn1Thi$=On2j3Z|$-A(7tKJhBxGG~2T9>@m_;V_IC)h_C=Mf|!gv zyYg?ho$ST!+e!u?$sMe+K;3gI-Jlpcq@O%@5pz|Kh_nbCn z;ryX4BcIG2pp#QF(%IQ(63T%o5&@UkG%Gwv+4ZZtfaC>dS~t%m+`tZ$T_M0NxU{$t zkS$N#n%kZB5cuch6QECbz;<9x_4Sz-Xb*UoCmkYFBgs*pXC|*56XNp#bL~~k>B|hb zPY92Rp>#sO6u>jRC(@_p#o38BAH!S~iFoRtCGjUu;O}Q4Y^`A$x{NiNnKgBfqhYVr zQeK+JQ->o94>BznJIk`mM3}|R+Xxp^=YcfW#6_fKaNO*D1zXmW=X!N!g=*URft7_{ zix#AE3Ng6NZ{vx_@c>sNK}0@e+;j_^bZkVI%Y(SDAql`^sb)JvJl->~cB+HugqP(~ zbD_(A1ua7J->Y=aPj3)%$7Zxgu0HHRcT}LZm=M{BFv%AR+ur{=wPJ@##6_7%kZnh9 zk76@Ld$}kmJ9#N)!Ee=0&MlUf+3NXJl^FykA6og6v(R~zb$3h*pgwn&~b_1nNK=?{9Ca5Ry$I!`l{ zT0S$BPLg3`9HHJ?kc{5%=7%x~z8vY_f+7UJh5zDldGQ({m5x)oHz61*3Hn68v)lQu zdYEd(QGIo9eW@?yavW3Xr%3h<*LT-p9&){F3eEV99@Tez0r=&)p+P8ao|n7=v$Mx}Myt%HeV8Q`W|@?qZt zR*vEemM`zALs2RGC`<7!@X_cm4V5Xa{?m~vCgVoS3IueH{W>mbIRA#z|Vi9o3PC#L|(nZN=3cUCl9r)nA0$1dJ&gz z3(VPig1`>X-nU%IiEs8^Pv#o5q`O-7k0cO?yorph{?h=3scIOuGV>I)D5*{UiS7?W z))1onIb!=}!fH>C;Zg{Dh8J~jZTF|11U0pBtDvwAvgUy_1DtE}$S^_vqCcW>@~)|J#T5cIBtu~QoCJev-KrY8Rl97IG^9^T&3@$P zB83+Gq|~kimH#$gH-2VFVk~f&K^?ezv#b!>QjGNQ5_fP!2?#+qaGAkJD?-TMYwoJr zbp^)Nipq5=hNHG_nGnmVQ7=L-jMGH#i*^z6Fd&(ihQ|C9bV3qaRCq=+E~GSwIS@MN zd(FLl9`Nwci30!jv_2{IPi+Y^7QjIr^ZVa>F}xH7hW&ECH!UMi%U8(F)3iI8s#fG< z;S-HWizq_GSxuoJM?RTVTEooAnoPR=NRC>4MeXDnKa91qQx+u1e*(X2BH&H8l zEwSI%P?%m(WH0XCE{~=7=sHJ;+;VzEu2o7vHVId5Fp?v>?`0J)@$<|#d}isD^eFni zx}IS|z9s@+C=o}cCoTQWl1b$TA4^7Ig%S`;xaXA-RbH`IgzKz6Bm!V4DON|SV<=h+H^mXwt2_zl1osL870b`Ip@-tIp<6GnqsDJmXNj3 z=dk&?7rr!BYOO0=d7;jBUo|IuFr~YJ7~i`9;{F3uQ%yo`UQqg?O!vJ{R}UL|T7}MF zOesV%+ysc^qzsGglc4L5_Tj4DMXS+%wWrpn)9mue;FE|CO|MJ{z^}bg{uT%qf zGSo(6@rrL^X4oiHNZ4sy!W6E|&NtNsN&qyNWKdgUY&5JQ%^R^n~<3fxJ?$);1|iS>g8i29D}cOVpR(A&^F8IfQVq0EC>AOdZv>u zE!?OpOQEe&n8`_*lKAvjEcE}jAnhYl5-{<8y;*BTi)eDx&8W5YG8&9-*df4r7vAA0 zM8yp88tLohOP+KWI%0_FtT5LQ(Kvsq2Mlf5nbdO3h)qEtph3x_{n{&D0JPLVI601* zWc2Oa`9G|vM^O=Qz`|R^!d36&TL)TP5Iw7L)IhTE4b}fC*T|u59{&w)Vfg_YD96ps zcF7fNkLrE0K{A6U!c|VyM|#gy91CJnz;=`Ya)es(iWVT}HYEr?*1uLCtbFb7(Tx=2 zfPh1pOe@7_dIMwm;y;GA5~N@hDDrE@A}{!dWgmz-&|Xx%9DX2Bs6(62s3%VJH5hej zMAO5lJ8gMoI>Eqz<(sFv!G+p`Y!D)*5bdxGcX$LZ&xePT?)bDDOwsp!=H%EfBT7wF zZQ?g&{}^mLv6wzb$MA3YrO=@TshqVeX5J+c%&9NO zDfsR$C|}~0NF8rNSo7G(<3JKM8%1ZrmMw{!=M<{J6)-;g^R05>7IQ_M}D`U2vrZWjttLYb+Htqp_4f?Bx?0uJAT54K0EX0Qq;Laf4iVZab{IiHEUGzI%%yxe<9=$(XlBoMVIhiJQQG&;Z2;O8+TW57u|LNbaM$O|E< z!h+GV^~ods&)e3`f)>coV@@gl&OMj#w^!a)E5AQ)o2jEf7Vm70_UH*WW7gTU@ri+* zqtnBc{0`e%5RdYze785t632X(xK{K@&NiXOS4`iw$dIA^pIg4v z-yx46pKQ_eLy?FoZPg9f#0}PvccQTef~?nxeNkDhcp#ljLMdA}AKVIeJOphcoL5SN zc;8ZU02K7@*s~d@F73#aM<36JbB@}WPDk6_$<(J}`8GV?{#qS5e%PjUvpWMU2M1g6 zvc1*r%Ul+-tz;k6K(&HT7ExI{w^j<4FK#L6v{_cYFT{Y>FSSqhrVtUsmp(r6Z2DwwEJJn;VYeRh#c>C#~6b;PG+dHSA0Bs@?jE+ zbU)kF{&B);+KVi9eN^d5R}+V!V4SIuSJAlZ_Apr4T!-4g)*zvi8&D3ZZxnC~&%)>0Dezig~#Sp#`$kp1|*lXjZ>(^JERY~-+ zczMO$?pNdNHDugXeb%c>72d( zr9q$=y|7bzM7oC{5%PsFlb{$>gt=o8VAY+J+sCPa`9D#uRZz803%W`d2)auDskdA_ z6khK8F`4z@B{`Vq?3rS=1%5v*k{!ZY~YFGzBdOkv{4!?HQTME?}DLK18GDlrUlzk?wjC;`DA6o5)s-z1!LunvFI zAP9-X5$ET!hZd|-Y6BV2;*`D?P_9+bu`kZR0JdjmV1dy=>*_j3ADkS*hV1mDUG0PD zU&I9z8v;d_+o~2-Vx8!mohnC^GhO}$y0lJwi2)p+ZhMM36SD{4#g0K3O+oyVgPF}h z?}>RjJDh`?!_G%S^0LRFyF#M`?1M!Z(S_M-T^i#p8_hk*!##)%#rz7|l0PGEqCAdx z^O&};!etfs3XXasTrC-|HB=f5Q#Vpgjx`J!>U|-QnB!nVET}NCa%^B>ua1UtAB44b zO7mCQh(@2HIT7UfpM#sapcw%p@0Xji+&nPJ3%&&e|4>U9J130|_`978lXDN7ZENRa zJ?r&4Ptw9IT&&(!h-F&sw&(j@>RJ8bYMndIC8h4)le{NmiJvCDeLdYayCz-3R^ze5 zO$`i+aJG*SRP_a+UwzXr>JRS6*-@unO$S~UXRtq9Ve2}LzoR=hfN5^9DuHC*t$TvDvSd7FGa#)wv+z_o zCubo$)C~j1L+=g=hYe9Vu?O5TVs7x+?pO_k?JDTEk*keVUDGH?zy}+rloG#|8q_7= zt@d2LhHo$;LA&THzEDoNAlnU(;tCv1(^no@2qw=rDHZzoBX2>5N;1GCIy|q#*Jl2M zUj*1}LMPB-h}!G2&@a;&Y>{R|d{z?^&gp9bRPY(!ojjQ83LCuU&%RezX{={#0X`oa z>tDTSz1-UL5AB14#_#NFYRjCK$TCI$=H_i_@icCfI~nSIwV{qP;IH&@V%Qm$4P3?} zdTtKDIY9IsLRuaOZuU}iYHv;hY~Wg%mXMtvTe>{N9-4}%Tiq((e_43v0Pqtc3MhRc zqmSS!M<%~v0w4syAvz=XZML?0$SUai1jJOzQje}EBMZ9)_wP?&KWvS~s&61v>$Mv| zZ)9plKkD$&+@qElR!Kb1F;-(}XX})L`Rav-i@)=K{c_O|YUCSkTGa?wDSHlzK&u^13Uw?=d$$wgEcT)i7BW>?e@d|J3 zBkik{%*{q+V)(%5FeRh{pBic!o=+$UU2)-&*PgT){#OXty3>qlE&SxEuMSJ(JbLxM?{ck6=67f_=;-6T_Smyit|jN#dtTSQ z{FX=AWai01FshVS(|xb}(Kwa3YuIcR?7*`ym*hSPCnrJgIfi|tNGK;~6oj#C*PWdV z2YT1cm)^AS^D)to_`Umz=WYRzdcL=2b^FVb2p}l~#l~40m?yqYYsB=@LO;V7lD0c}RMl$D^VR(B6oyvvoH=0n`GfVa zCDXm&8{dBJUUr!&M&{#)h~tO6I3G-+$g^~zQc^+O7_9{9b+`44B@HWe)H=b5M|_)~ z60ZaA4b?o0&j4Eu#LjVk$#dsu)8(|K&7iK*KImOw#Bb*+Hmy?04aLNOgWqVf-};Rw zDmya+Y+?ooFgD8P*vR!<8>)=d(+Ip&^y$9@xlx;DcV2)7^YA8{pvub={L$;8Vqlv;~FiztWFeniNTrdl+y=Pj(>k=UiJ zM_jnlk+W&|FsnSvc0E^3nGS+3C5r2prQw}WwWucFQGe3~QAe+)@RS+&h4FB%G#O)h z+9@l{4&v!kU@S;32pw;4@e!pLxu(oOlpHgj;o5SioPl;OO}1PZ|7RnoW3^FP1^4p@ z+k+XWQ^!w6 z6~F)u<}hi|K{?DhMI9yPCb@;MQ(jkLGd@l4ARP&Wd7ph&E7fBAk3UMdW3p>r~&OK676K>kMEfE()@Eu8xG?Ig?TB%`Z>IsS*0VX5u$j#g0)tE>bQ1imKIkj)1MOwNp)Y86{YkO z$JNly3Wr`cRi^&{uEE^B957UBYLSYf)jN+q!#vAQ>rUj$4@#9py2R>ZPKX=pC3!=++A)F+oH@K7nyki~625DpFXKzI7fFc<=KlsPVs;i4BEVG!cp?g%X4AUd#sFVy{#1BtN z*KKVloH09m#@Xc5Om2A+Hu}r#vn~2aDg=!Z$MIVsfZ^F~yh0=^*)mZu?qea3us#Y+ zRYxj0FI59X(tpY7!cO!Sj?&bm*r*>OWOc?CvG6n*0a)4z8z8eGc%o;C%GlkOD%F1R zMk)z=hFaj}S*LwzWi&}dDw>rh&$)*Lm2s)$VM~$l-hmdu418BNnm(7HT5?fXlh;u& zpTvI*nzMIvC$IY`c!4DKs=wK(V{z@Y7+9gKKkS69NjP7=S?crQ<4&)fscbDjnKVcp z&=vvBE4j2$&(~fsH^ryP+aamwP&6I7+@@6;w%_i|jZ~COlk6&D$N#kVD)HS9V`SUp zBaw9}73k@pIUlThSsP45HAaW{9Ag)Ar8RN)J0?gnuY1yM8+b)7lG%n7Vrw?zJj9hx zEPreI7Suq)Sd%{b$-}%}`=u=;x*%m8^uz+pC})!oi=E3hN^ID9){ZXNJNi}im2V=;xSYxs*- z+M29~y3%?AHm{Q4YDSnJ>q+De3Mb0<9zZ^5gx9+oz;gS9CmiAV^@&03)9_y?LX6V6 z{|a{b2NwD7;fenw#h4lY7b(Wc{!f-MGt+-dim6M*tg(NQV&5L;2quPYpJDtV;zfKh z#AgjQ8U_3bjMAEen#ct66P&!gf}7V@eB%ns5EmbR=nLO4Z2?#^iIPP7NtJNul!%P_ zn1pj6rY&tXzSHIs_sNSL$Rr=5MopqH9{g}&;hK&W!!ZJR31JWRi+l4<_G@q>+e=M` zY1mJLY{}tdOs9$|qF=pOt_{yyaKnIw>oY#6BtQ6>Jxwfh_Cx~LFEGaEL$5o-f^Ku^ zgVA%fN~xPz20VTL=%+4f_8}KOhxxq8+gc>6!C|r)({;2%?odxrK+|a}SEQY9jxf-r z3x4#z&6BKqCJ97{tCLLhKv3?FE_3eSI?L2?vkUc6dOMcrVMgBtlgI$fon;p6q%RuI7)u z?&AYRdz-4Czm}lFd&#Y=$IjzK_upXF|3 z<#DYA4MTY1zeSLAURM+tv6UQ7bBTu_dDGc!;+Tzg)1f;v?c?Y>eR)#*&;2Q zhj(c(GB$jPxme;Ju;3`l0@GngpvoSR%Fx*eyFA_B6OY=BpLxAX&}O-r(1H19HKg!e zEMYe`s;fsmh~zpq%VEGTZa7uA)=~QDn08)MkDvT+2VO2WoyZftPX ze>Fk;1CjloG#vZCs2cmfs2cmfs2cmfs2bp3R1NSiss{KMRRjEsssa8*)d2s2s(oc` z1O7cS;6IN1e+{qw$L{|x!E65v_`jcj|BW7CV`u*V!fTT{S{8J}N#0vM2K>0|)o&0J zpopZwy{R0WL0b^Ux{6~=t#=3GC(8+%`6(s5M7A#_7#Bh?k8seaS<6R0pL_QkS-J}^gnvC=Tc#;C zs7I{rzWh0+HP6U6lDs&4KJ8yGr@z> zpCrq~Uj+EOi=iFl4%|Er36z;*?lZoywL-Y@Y5tGpmpek)o;T?Qtpg=y;YN7+a)GeK ztfjC~vGORk2$K9neo6KODkIwm;bfN}9&(KlnFBzAYWm#h>jQ?q&+EbtZ?p9D8GZ6riBC7->sABlANs>H>JLi6_73>^KqG|8Ammrt)#};UP!CG z-N?tG%qFrnCe9Lp3l=UU?nowr8`IzOyI~1@B-W0)@nxlY`5mGpb!n@~(poz@>VDzH#KD>xUCwBjE8)OW{X98 zrUU_+s`E-s`q{U@72j4VBVS9A4qF+@QjFbFP1H>Yd<#5DzxzC(zK491W&TsbG!>Dx zlBRU2S&iLK!KN=^F8zAbz0%GWn6VY2Z1HtYlHSTt%;zWlj<6ZF@+}M3e))QNk`zTc z2_}EtKYsdg7V9bN&qAm9vwwC447piwu~pcq5Y*h(o)qc5I;YFy?u-c7{j;KZloq~RmMzovbk^)i|CP56 zOT0U zcKtYO8`uYD!f=Wp=EJ1sx<^u&fgMm_K!VBuVe|i3*?%IMOfAO_Kg5F`3n?EO*b^Gl zH$>-GOZt(h5WfEr`l8NhiQgyQsn}y)ms{wSH6}qe7yp8ygnoMK9+X~qnQC|gFlfXJ z-C)96Gic;&$0eaRZwR2GV#^oKMobrVtov+?+khBrw<%~b2=t^U`Hj(K-#y8Ip3=$$ zwjSlS*AsA1Weh$H8J};ZshlVqeI~RvDD*ZnI4@X)s5q$M3|h zkcJ`0Fq0Y$R{$eb%jX)nrGE%F&O4C!aGWazH9ClpY5QOg+3qIy?L8!a+3n3ciP|BZhAlr_pb0*O4t z5$RD1K2KMtk6g#f*aR?fG%j3*Dx9K6yKnVn3@Y6Juz%d&M=DvysGtFIaCQCMNbM5L zROX7T=a#J^LP*SYTQEy1zA+cUbpw&TYx9-++5+r<29?$abei*Frr+`Gb=}C5Fak5y zYO1_5Tn2^nad3^x`M+?6&_=!euHD9by7oG#4)j6+ONyJ|L2nu) zIFnrss541N8VG;CTQMzHx3*fpoQ^DCu5Q#wlR^@?89Kt@CoSe57B#=2 zqdE_j)Ff@Q!@N>@Y{-avJTk(j_V_}lv)(H?ZV3e*K?==wN*t}baP_Y3Q9kda-lYfR zY;4}HRulU!KmJ~7Dj_gA=KflSoV$hfsh__qt^T=)uc0Tus7LW=`6SohWI zIdxgq)%#+^f}Tvcpt8QwW7b{P{1V_XHm|_?49MJDI1a&`Zl3jx*BjIUqCmFx{iyG1W#b) z@VX)ls?0q026OjqCQxF%dy@w=d`@~6HiIkzW^c}UW&vsmg2lqWDfo%F6wOqomeenu zCX;nQQ!caG3^NoOLPh|O4fKX6O??l^pb(J_bS)sg*CCVDV3}O*b^k8kQ6%INGn&B7BL#ICmrwy9 z^DjXQh5A-by%7c}pmmu_YyKQu^eU}AcyBF!5zmvy_)dOx$Me8?H+12r8>9Z^`%Ai$ zjhM&Ay6q@Ir)#ti3ag(eYd8H{pZ9NDKIC`Jtw8q1ZqK<>k5?iJq#ZqMY|k<77y?2U zLf*D6G0iKC(n)VWK5t2n>C3%KQ9Y%3acg8 zH*{z?O>f7L1)HiV%QlqqyenQX4|LG3;6VT`V?B0jbk_nMK)Zd;UCXKB8?}d!%H`Gq z73R}uV3z4@Pfn5eJYh-C1* zeB?3GQJ=XzIy|fmhgN~-dM?DguPIEr*dJe|*bT_V0@2N0OzPE9+-+mvWUt%8X{hQM z>hD$c@N(Fd3ZdHhAqW>&)&n$&eBB!J}9aF zPPdY)L8Y3l9cBe#Fnz1?1Wq9?t_fUi|1Xa#fQ@Y$>3!^`6}{8N3Go$S^QaNNiB4l& zdC?96JST;5BdG&@tT66?Riuf)zAw;tNn|uxLDSt z-yN-4702>E!h%G|Vo{mb`r)~vj9MA*e4PiKYV-Ub*9BpyA&6y#EDU7_xa{df=()iO z+Us-u%Y?W>Cp@L0H8#tVfKF?%Jk&p%+pPIlbzatJ9;FgqmIqIO<#mGZd&S=6EL_C4 z#vYv{d2CC^DnGWfj5;$q<6ZLYAud({dA~f6#MW4LHc);=^#gx+nR(Rmnt5oCMX)a{ zD+O*VYKQJXT(HSft`H2&K1#dV{L|gpGnc=kXdh7!o<{xLqXM zV)pc^(JLVk{k8+HRbLEI%kJmU6lM*;iBYa|o*$TW50~vD9ds8##+<%Wt<8Qh3zKNa z6BL&$&Kv!4Q<{f&4VszB0Tsp>u5($t=**NZSRPDz2eV)_QqBriIeHgk50y#DPKPX7 zLwmX&5GRP8i)jhHjV7OvTAccoo@UY9(4F7)8~S3w?hiO&lw0=ArhO@LYUAXI;m&I* zBrIta9AEIgUBd%vi~{{rK!CF~`R`Ycta{}qr{-FjLFUKc1{O+g7KIj!T3dQI3)4;G zCc;t~bUuIQ9pxk7bHrdJ*do$FxDQkCY=@x%gjv_hMof;UKF zlNs05(DEc^@H2oDf=1Ih-Wtkv1=V4RfG!xcb(O|tj=Wrt(1J^uudBK6)z)(OM6?kA zlz-AT5*&Zs1G@_w4soo(e_VfzgFv-Wx#I5C@W9-%SBIt~73zaAG%168=kJ31oVxL{RELl6Ru^|S)$JkH?j*XD^y%c!8NCOPAsmuxfg34~NgQHnx2 zL@0tIL1=QerU1yH`HNC!~8xUIdOY-Qku~U_x zzZps3V|O||O_8dEB$}Kd$*$FUHc@6T8M+Uu1(%u4RdN`8TOrlFok-Zd<`rLU>-CU= zlpUm}S8j}$3iRLo5gi`zjAU487s@ji5*~0NIA|CCJyba>M^YhKxG}##R6xNFNo+9f zde*%ZnWJg+%FxjLpE2BUd)7h^-w&lRsoGx5g>NyYaVQ87X@`owv%w7ZZjsQZ2|u=~ za&g38FEp2R=5;mvcAUO&s}dCJzPj?_eNw*OIn>3+Sy`30hk6_OSTWinCu?a@10A>L zPnMuF3xI+#pd@vYJgP)40p-;zE#`gE7BqHo^)Btlbs`e1B)SZ4d$(x9sgr>r%^FvxMo8bF`(|p7-Z6v3*+J z&(^eI3EIPSn?K=V9J)q3=S#*-%%NIa&InG=K*MDK-N?57(I-0(zn@qM4?$Vi8mIo< z7;iYhS!Zwpu(6%&D2eJE4o2YCKv4ex5d zn`2-NH?m2xgrykKf>=VhH6*Zuq4=pyJ6e^sNpaQ_%TH6P=h!X^9w-Pd7Y>%8z`mVq z)bNd`KosY!ISnTlaR!zZ>KD%Ab&$@eG0qr>HH%G2wONhrPi{AD$KgEAX_ie~L^iMj z_BOBc-%^!DU-t$S^WAJIO2OqjX&coo;D%4eb+xdqw_si^=@8QG^pFuC{7PonY+(>~rNO7qkh?g=8XQd}O>%RsKZGqx;9s%JHdO=Ott9^RQ-|viqHE$?w{n@q zJn%+M!l)TvtZ%b0-RQIR9SanwQT$?+Jwb~;yK6~HQM8}AKy;g+f!HhV7s9j%DR~)E zc!UR>x{t3yXvaA1*B8-+!>II(H7#ck?RdKJ1T{u9v%d)Mz`QG<^yVzLQv5A$S~umz zTp)aZz;(_I(QMOcmW}hjLu%wM=?sN(K6h@R%G@#u_2T0^u>nThu!y0Hd24-AihF4c zli^b5di-5-S<_qM|CrM)_kkBhM)qv*{$OE>rRt)Wu;iWwDZe8;KI)OXe7{0b?)>ZV zAh*z&zra8NV}WrBk&-;3Z+XvV)v4iX`W-$Pn7)V2X+4Gwvq1GL%9{zTQ3+H#l5W&K zeo19LA#SflNM=cq1GUhV;fP$O3S+b_)0;ENesqJOth&4@vndXG!LKLYkw%l5$!_%4 z+cv55$2~=HL_E1->hM*Qkwvai>#y$27`~+$n*Ol2PnS3ZvdNKRUCzcksAgXa?j;`@(-;4= zSEdaM_Y~lg7FLpA)4<^H9KFV3%?j#`w;Wu^tdok(NVcrN65qAn@xpC}ZItRhGHcWu zZK9JgM5SxM$dp>&d-r3QU?5wRy-{t6bkX)O=%bP#S75J6#0yz*8ZHXaHjs!n^o&kd z{IrZ*Q23mH@R4I)wgsBTTl_{XdLglHL)tw@0YPE zq^-Kq(43aoWp2Y%vLi}puPko-zEu>jxBAXw=gUSW&ymM12ArbS=e%N;JlYo70S-x! zyLL&NV-|Ia2Tx3<^+Nh?5>JUDqw(9TjkVpekiJ8XQR)km_K)!5XFJh&TBVaN}|4;zLzt^Ipfn&#p3N9NR-6^f_vB~|3ZOj6u=lr_ z&eN$o>#sD&$4!mUN0Y80oM1+8!2S(zG(GvUW>JFaw)VG5v zTM=Mp%5PwbnFulZY69&)-Yku^Qq953mQAwC*{xS`NjBjFB(sioBmk!YAGyRImM zo?(mm(nyBZG&1=;lhz8VuR3rko#`HHehfhh?0y&dDTV;uTjM5OVF}=21%~1UrUGFG zXu(|TLmLM_rAE0ya>(VeYeByH>@J1tQW_JYbhrMg$h%~fW*q- zcIpMY^55h_=?ss@Hq(lbjAKuX-!Hen9eyRAJg$Ss7qC8+FrX(lCYRu$jynDswbXc19b~a^P(5hDrUTxbZo!m(m{Gi; z(mY_vHY|usrV_E*NVU`vXeAtLWv4}!4&IV(8K*Vw%m=EKDmQ${(k!}IgX_`o=U@*{ zqmeZfK`Pjbn;*KY6&qSnlC&`161&9!Lt92qQz70X8-^afo(lWSZPwpAZ331YEq?%0 z^L`S&E?ml`ER@M59vG%~$cCa3^+%heO+#v7-HYr?a);YRaTQR6qtk+yP)xwr@)?!q zsPJ_&Ah&2oZ#57akvzJFVaGfB^W+Ijar^8D{=#C|4F6RUgE1wVz zx>i5aB$$6Dw^Cq+k&+_T5-Sn&ICS8pt$q7Q^P}^%*xRzBl)hZM#2L#+{c!yuC$W4E z*kpdznN&9ZP=2XaFAK~r*PZ;bz*EFr?xF@bv8dg>KC)LEY7OdUd1cBj9$9?;jhdmY zF-YKLDNN0K#)3F)jA$8Jdae2F6Wj{E%7jfe!r!YOM zpE{dNee&TAa~n;o=NNgZ^plWHfTXBcd1??jkE!yDlZ=?cLDTgJ>tMsOFxttYV9=&4 z^hjdkSs#2$I#+DaDO5dFr(0Vn9CQxp(JIL-U!crpr5EB2SZ^~N$#SFHkKkee6d4Vd zUg=o+3|2?TY*23oJ?itPDwj>3X(at&k)c*8n^iM{S56=KMy}44iF<~;Yk7F2x&@@o zQjyy_aKzMlcsPZf{?lWWlinc3_=x2PM#crNjU_DW&H@H+$e5g19h-pec7(d;wR>#}JZj{BzhQwG^#*JFR}c3;>hJ$45(EB~gaQ8{3IAV9x&N`(|4UNtKLh^n z|Ka~r%4Or^1pMz(?picy%YXWifXb3xk^X@DWoQMet6p2l)LCDPxX8wffx!k_`K0gT zL*n1kUpaAJZZ9`&HUqphBF9EHS{FBI=9;>{0)&5JR;3$A_pR-{%uH;=?c zl9cS|`0f9)0-R~b*# z;rAFUo9`bdXJyGDYogR=b3Q-U2tPm7fCjhkdX&YE>~aH}Vy~PDlag17wNeM1Ggq!r zZKxlvuXVOtP~~@b(IO%}Wir%2}iGTqjwPa1F8ra*&E{=@oT%{+IR zH7c2FwMp4`cn>VvZ!>P?o<9(E4{{`FTB=|sO#~Zw_FylH6LW@5akon7mHM<(V(K#r zN{<*tOxe)KV_^*m1+k8pDOHXMtAjLaESiqR(>4>Flz?}}oNR&j#B)pYjBNJfJw9?% zdei$AO--_dO=%Q1Q3@x|C%IuYxmoOxH?TY2%;a3@Nxo-jx8 zcH=if7P!~K^@(qFVkPA0FsmnL$8Ostdkc?WIT*)1tc}bWqs5UwV?xEg6)SG}2tS>lZJ-BHr~->YXcxt4XKnB~&~V$$W8(1=5tl@P?)Jfdxj*kTR`!T< zy$5Yyc;eR4W2xR;7RWCB5qSg=wWlgEi^W(?as29E{lwiRZZ$i ziXc{IyqTq{!2KZbu&>azqo(A=iKS6&&v;*$~1kX_d*vZ+IN8SpEMi$v0l-}9aq{cP|}lkPpg$mbVdYk6gWQjiGA z5a)DfEWf^46{007ni|Ip%|}k1T$BVzncs3LU~iB2O^4f)O$vdvQY@0P#46Nl@8HN3 zc2J4PL4w$wdRV`JUR42Q9kav-0Cu);?$BZ*nN zbTvI<-i>lQuY(2ZtOEWF9XN zM#pIQ>));$!KAx;$REYKt>LP!R7xr_wMY}4IA7zO0{X2H=PEH8`)7mWeJq! z*lQ_@?%AE(1?i}7Ytx4sWPtMya*STJn`PwcD@w zI*a~JA8iIrQCU11tiR^0`2mgYB++u;Og#!x(E7VfJ7NRw%8s934chmQF^zB|s%s&( zaui&ej(yY;Y0z3{-oM9w{)d##;LG;(lItM{_$sod*wxgu?&?-{?mnDdQu#=XGo*a>9$_^zFg6E*L^Rjv ze_sy;An^NLvUP3L5$wwp3}>Nq=npf=zvDf+tOQDKXsS@bFF}H}`|K&S(9oq*HEMn#Ns=BrtJ0z1x#4H|EP*2AYEe zj#%Aik0aXac#7Udwz$8ki#nyIY{QD@}Fuh#<44* zGK5eOfV0S!nOHxrGt}T+FsSK?Q^=#C5mwW0B8@|Jl66JholT zDXu_av(`d+6tD~ZOvl*G3qIwQoiRMGb7~0S-ZW>S5<^rqd@Qk;YQ8w_C|qVAjFsxI zLvg3-Lf!kq{X$xY5r?sK$9^U^J4d_?4Wb%B9c2{|(G={J)8z~s$DV%Fb{QYavlNko zw}c|gt}(k&HRQ6FFuIpz;gw9LT-PtRX`xsk&(wF}=jfa{+igSL@pRZ<77jsRS?S9H ziL$W`qA?wY@XN#=!2?7KVnV)`5jxbh{ZZpbD3kuJUR@y2zHMKqO^!@JL^?e)!A+B z`U6nj&Xr*Rpke{rAI)SHUAgep0**c!KoAZp5XKtCblX?=d(l0Y>6!0YY%vxL4mq1% zfgKDRP-s21yOVRyG!qT%n5KmmfRuRg-x) zD`Pwquvs@uU*e>(g@%Z*aSyrWt>7HXG*!>gPRTuy6<6+~ui!k6Kb8&CO3-$-u5*nP z%*n{0CHew+R4e^h$aBtAHPeBN#U_z)S@{aK8?9kSIykGdlu&UwR#_-9tCS8!YL}ax zg3orKZYP^=g0+pw`Sr=gIo}z6Ik5{OLxFo)C>mU{p{^WxcWN0tF$Fm$VG`DFg@j6t z%~(KBY#N*&-*g@&looexCj2&Aozm>gP5{?y-FcXsKLy!l-7rQ+@$9yHvQYpqvz<|r z9uR7m?{%Z>kSai8{FK9W&)PpEzQxnLL`w6^SsNYKnXj3+sOw_SquDD&+e|Rv4Fp>% z>ht%Q`{}9$XbAzG!J%*5>LJ&KCf}nSGU%l-lvl3*ZNz>q{eabLxJd_**^sa+w(d{v z)L?ibdoUvYjTFYMGqvFB`r^=s*6SfvZ7JL2(QmQ?Y6yOdj}k2c7!!I`brplK*iulg zO$ImE%NrrLlG(Z@K)!)n9+-zB-=eCjty*e_>DS-(y;qw;L7=xLasPw5cM7wt+qMP6 z%CK!`*tTukw(W=v+jc|-Gi=+oZCe%j?|rJy!#=mF9`3_k4{LpcYpgNnnqTj|jow;l%0dg$iB*|ppC!5bMEj=Jne-!ob5R~3NyQ8w>ws>foDOceOQLr zr+3t{guZq<8~e?;c`I?vpN4OhX?NS3EKeAxe^MuG5nI37colx16yuY z2~XI!6#~53GKAY!xOm{bhQWPK>eVxE8e99Kp^&5hn7Sn4jSO=CQv>^@V!nC2P7TUD zL!}l3ChrKd8PsiSCK4+dPj>A`ld7oJVzQ;q#{M2yW?`9ED%Ew5qV}fk-gr-Qnl1v+ zyTf(%L-+L=v!CZ^w=J6k>QV34s1DKO-~$fmv4(H_1j{S`#sxf{RHD_9-}als@J<_-RbWoztxD8 zuN053jF@lCV1&19+V_h=p|)wt#rY9(9v^hHJ!vjo!|Di&7pFd17(0h*ci%LUux-y2 z2Vp6M@gb6Ov#?!+`B}7^Idcj7TC7a_F=(0yL3t4G+lIqfIk`UI6F1DPYdEJ%o!-O= zup30)o*Xsy!`hlwN1G|nv{eA8zrPT7I8BfzNWVA1^viFEW$C(&?>0=Q|NalPRvH7& zJq@pGXmyPjS{{1_e1tLKf^E6jxjkzP{9;Nyyf1ZN88BxV^Y4V0F;CQ#!8!GjASm!Y zg&{A+-YsI%Hs{9o7c z#`3tB_w}&TH1^uM{0Sp-icZx=p;q7fvz`lDc`M3o+icC@x1I6Z?d$VR>zrYmJX$|W zFebfuCC)BdulVPDxn$VSXb2~M>ko%+zur#7-NfdVO_pts^s!r}`{UI~wAmv)Ug%}} znqS~PrG4Ad9C|&oApuN8IN%$V?j|g zJ)YXR0KW0xIv1@2N>fes&R5lxic_6Tt~;;2yzC_4cV;x<&&K=ph7J>0o0kWHizLxZ zAh~qrZvq#jT@9>1o}e%no;YE>q;R`EPPS~@(Z#l#Jb}1^Yas%!Kvptd=DJZ zQ1fkq(|ps=r*Ln65UiaurA!Ewqc1w#SF)WSK4=muJ^2qQTbI4&j0%qdb2yW|6Gtsi?B1ux14QrmCdNGeGF{>BiK8u|3 zq`N$3w^pFmbzXe@Z3vVg6FZ>V1W#dCJA6#m{Xy&7<0pHSJ$V}Mw zN;iQ2_oK@i2E5HYrt_UYPh^Qt`iq}S^TKTg)6ys7XYVv!wTtJxuz|EJINVh#)4-oOnvA0GdqG=eW=SNWy zzhM1aZ+Ee^TO#z?fWPdIL>i!3Yv(z5Mgb@ zM$zS;|I0`SXSVLA8ajo$b4^ zo~DV!EVMV9D$)2^KW3V~5b^%l70_glT2XQ4aY^bPNXuu^!JTbtyth6zJ~i9bpAaX6 zTbh#dQpt2|kIW8?!K{&S-*^GjO3uQQs=&=n>D~^xLC2jV?WO?xwvYv{OoG|(-4`nI zTXXxf<#y(D31ymSpIZZ0otcZB$00_0S$l)#hP`mj@<%D1PhY>=RDM#s_TQGS|#Y`TFns$1!d=gYtVNi%SWUzBuT}Rl*b9 zjPRe#>tL&HTFLde5DJnUS}ZIJw9iMF-`CPwRZW%8cUCi=!u;r>WJbXISjK0_(XNdB zCZXf~tigs}k-O$R>gN=xM^n`M87N(!QZP(!ibFOZBezS~r_u*-T-TvH&xZX6w7h&I zF|EjPuAg+5UhhO7?@K+nU&JOC4_7~Zop+;EMnZ3IP|}s`p>FdNe;P}phNB^VAWNpD zJTLc%1;=dRoLq|IQM;!Ru^KwWd6n2ZSq^IF4j$X+h8Lk!xtVX`ytrt$3Oh`O>cX{X z8xLy{WXz@ zIUt; zDKwy9`1J=M%`&{i?(@DVP-8!hIEQ!tijBDTepYl`_){v-mhA?^7=chB4bNaQ7~WFI zv03D$FpH#h)b*v8V${#Lx3ETgtnW~$%rQ!1T1sj+Tv5u<=->d=ipD_!-C;(gg%P)w zAEC7=zgOz3MByjY_H&zoVQ|(jB_ZfB}yu3_>aPgfjLjg#sSao{!ZDC$a)h)4FKhqJ-z24Oju6mAsXvp7D zpG&yO=0C@vr%!|nnT{qg)rE%ZXpbed;USwFx>bpYhKq%9NWbrL)j#ma8e=NQMM%E&CL-j3dPCC?(r_Z5{m9FqJQ2u2cIKd0n?Y6s6 zj@xq7KNeb&0?qv}9s0)>O>c?HX)N&&X0rS*2xBpaTIM)Q2I4YMmUT0-kWirsb_*(z z@W>WRWd+J;uYQRnhgyXeQWc5pFy-4>H4H@Nxy0KC2}J2=_r>`d$xR#T1%q!{bNj6h z$|)mX?y-INJ|XV`i^66Eyw@cBL&*wM<#u#OMKi>YN|%UohD(Fy{l$4V@D?NfG>AsY zn^S#eom->YZyc`T@Hdmf`8N(%4p^|5`j(i5S5Ku~JM8V~^xj0@A8x|S@1ru-8DoJ$ zt;y43V0yzt*;ZOxOzaYBflQ`f9%xvLrTea#$nxUcqR>%qabpLZg+{Pmhv_DgW;66J zS@YI)eVU)Ypd=<*y@GS#t$$jJr(Ho|_a^>)@2GqYO4QVBN%o8*leo&NqS8wVY@yUE zLj@Lsb3o@_(c-_sZ|MJ9QbXnCdvL6hO?*j|-9!8~MDG{}#Ia)jAHkyYsmyM~PSH2n|`KjE)Qu{d0*l99VpvnG^$?+*QB=uYsJZP)E$GKDe+3>C4yPq>C7$ z2ABD|cY^5y!mF4sIA&*Um;V4|3>9lX#X9&XJBIfoBjGfCBLr6NK5w9 zePePG(H?XOQk@#=P-oI|L6wBfZf3L1FfIuObAg{8iWF{l;BM${IVl*ap+6K6M4IWC z`HO~az~30Cxo~WDZX9oGT-ghoZwF%Um~??N1#nR%wK@9w_V*%kNO?mb%DR`pRA~m@ zXIi)daS}ksrrGj{U8Nw@F{~>FbtnVZU9(P5JPpkn0=C*nLhVBwQ^3voC|*B1g*ZxX z{+MqUQ`_<&sqFT&dF?}$9VWpu&xFX&3lO1_NEaD3%nMcj;Jx@+A2IQJO*`x=!#I+H zb)su}DIL>fS}cH^TtdEp^3}rfYx)aS4*(H3_w_&R>EC?6fA6V)m9eprfUTS6-+g9g zXQp9bWoBll$7f@rr(t7bXJuj1rWLfcaWb}Xa>Qr&m&Et~L6FZs3;v&PpMT#qj4Uin z{~hw_z_N@WZn}AU5C60h)4T#t4Frkof!~W|biuyWw{e*gO@--yiS5eq5T|@_nwsPY z?Wj;yrcOH5CUMTuhJJtV>HU(Zv7}%wsnODr`Qk}q7WG&K4?4uFTTPX?jlgWi&e!(& zIJiGpsWN#v;4R_p;9Y6thp{9dNN!cLTtb$LGI#%Sc)hLW{kmz(@l~@@L;6ffdBT(R z{TfC8>iO1o^PwF~h4%gN4nza?45}1)`vlz;R?QVU_)Fg_#1a8kmLdDN^KIz%b8T+v zik~!P_cZG6JKwCbsu=m>*5P)bqS!;XPCysXddW)RQ6RkFDIqv- zT2;7o#+KaZOw9t&00dJnt`ATjXgVax9%^r>TtoCk%nItzPOdUnm&2>B&qLd-b&fjV z5*Trx2sZL}kLw;kSnC&Cwz0cqoI9IR^D5FIck+JnipgH-%sz54HTmI8b|W*~AnAMT zaPG`lLskLhQ1nV`0n>XXqY#|Eb)tI#F<7>%;v`Q&QSJrjM+9E1W}AhH z`N-=15bj8mvybP(^E0^pb9D~M5$~0bMjhetupsc2jWDD#zkaxJSSTdDw*4PA}RA`+NV_^?Dm#4^n z0q~{=EzR06nnc{Ia2DSe$Qn1L*^~W_3GOLj7(t;ceR}1qU9N=`Uv`3s- zds&Ze4$$Vm10`JL7uHbYJgk32%fUt+k%RN`XwnX>VnAumyTsW9*KVNHFj_zl`U#fx(A zQ@_UnhoO<;xTjUi8_v9nv2(1-729KV?m=*gdXCiFT;_PY>eFY5TF{T88J1Slpv^4q zk|dWb8MW88OD#>y^l*D~VDzW5HLptyk|faFcnN~CjK)Te45a}9L-l{SGT$9ZA zy=)5RtNC}BbK`i^ZU07BOX01YLr&YJL{Ltbc{N@e2WFpP$E+JckA{NT`KnI5Hk5_6 z`=V)!lFTfauC2;am0Fj@KE5KXDJnqBhl%60KqrTI_a{#N*Wry>o!WKO%cWNM4wE)VZ=W@qom89m-UO~Z@npwT+M8#4iEz5X_-@G4jCxb#f~;&ptF&}qCywAbMuN%FLm6b>>a0l6jV8;;M%jv z$IZsLVzf9!&7b=2+(MD2hK@=zB8)~1JYAE)Lv0l@v%jY8DI)j8Sp#??z?>I3x4bJ6 za_wwkmpq@0L>hFIv!dpUOt$E(stjo|bm+#5@;qmaT|!Liec+StG@foNf!&O2?v7d% z=c~nE8x}TEQaq#uJbCcu*gZCSQ#OV|0zlaD+Mjd`u{*$LSx;E60_Uwg+CDnvFWnut zn%vzVhe0b|p0~C4b?!@>ia3H#nwlLjHmd7hKci@?s~0_b2h;s?yqW`y(ZU3rS#hE2 zo=8xS(dK_r2Y1=rAW%j&ETh^&Jb?51_>-LH(Mmp=uf?k>Dg+dxNpLT8`vu$P^trR- z*BlF^y$cX8j^!Q!;PhI(q6?6&wX1-GczhUlWp3VPQd;Ew;(D1pf>F|ynO3V%YaUC#DNQYi)D9w=GSJqDh^#H> zPCx>LE0$qGmVa5Y-Lt+lC2sh!w&>spKW)>Xhp78pyB|U zDC1{^2SQk~j%+6>chDdVcneGzrt!29ubq&54s&=Gief1 z(A#FnNx1wvfDdC;T{<&vd8*6?hKHT$fWSg>aj*v6*gjZoED(j6P-$(EAfBuM;beQw z9}M83sK(@O9=p@*M$i@c#pt~;zNk6?^w3hkBp8GRv2f_uNhYQSiU|nA?y;QckHD*H zwLvES0RdC}d4j)idL8=CUs)PMROo}i!$8r5RCp8-3xsU3{8U|hD2~~x7{!Li_>*O(=n82xCA4(I`N013adkDGGl~P(_f6Nyz#OpuhMchymdX zoRBm64Fmy{078Y-3$guRS8~#bzrn_LQ<8FXK;#W}U<2=Fri z$KUHiEoF`;Rf)$9%{3;cmAURGO_dT!&b%T#uNz+y2S%r$P?9jJK=5xTND|Z!O`=ff zhJ=R@o2i=n=A=s@hzrILO9jwFHDgIA=m&HcoU$`m73j@7gnOA_uc!@`j;<11sZ-5w zHKx+viUpAf8BazLx{*YPO&}u)SYcSCfK7)6 zp9rZ`5dedmFAJ5b6;S{Wkpf(5L}X&CHWsS{yfIik^p=w#K=9B&&Lo9Rjf%&Ts{*W;WkCtu49mc34uUC z#BCHHghz>2(8K^FCC_aNoQZlS!QX98rI_9QPjTQvLx?#2Z5%@IFl7w4-2}bcKbp6Pp z=vb-VKA8Xl2Jwq17(|@$T=9yXD*1S1;=5&j2+DIWa>)_3KgfcKMP|b0>0|~5h?d<& z3Z4oS@jpDJE!()H4dwnIO&8p9^J(-wtj0RZ83c4lNGgaCAKVZtzUEg1Z>`8NJoO?C z*p6ue#BWg8&&;nHt9s}QzvMfhNlkLQ&q$2ubc>sxNQQ}h0$n;v>hZx8RcpN?8?Qns zXM5z;Evk&>Ymwzn5)LU@fY>>ejPubcc~hm7V*HtJ`&lCwcU{>%Lv|^Cs!5RE>2kfw zUuK7tqiVpVk51fAxP?H?2Ol|;9ml#~TU5oD3;zOHm1~Bi!8E9jp^5GuPd_jWh3TpR zeM3_(;DYB>8$iVBDBS}h0Td9tEHX6>uU=^sS0;~H2w@e0!#vAKJb}Sy9zgkI5ew&F zx!5gzcf42;k=J0UcRT&cj3L=aDt9*1y)WKi1+$+mjc>K8XQr`af@5lHv*t&z^~$1; ziN%W1I9chhEh|A?S~7IW_$aer%js#jIuH~7Q`kHoofN>5lSe#w44Ro@9THZ<`G}~K#qN0!W=oAPB3?J{I0DNArsJ97e9(+|4lL)e3HhGG=!tq@ zL;H{Loqb>MO=>Cewto;3wFwO7t|!I#CkP*>W#TQl^k_4}dMSajp`}M4CT`vNQRafr zwG7$b2y}dvY(_+TAXX}G{m>B(=8DElJ zN7Lzk4`==t7t!C+cPD1{e3*t#HXWGaxl04 ze+hIbx!W1j%6-qs!}Ir|{f!$iF#fOk*ZwQ+#Kz42|3nbPepRSS#$Y!gbUsxd-vP}T z+(>uB)6s$tOAiBZfcV2%N`};0@{RWR@;(^VnR-x*LI$ZT#|;>8cNyf^BxvF%t$e=5 zA6Dm-xca_@X7GM_dbqmqwy+ltOf|{Q0ivdyd3k0>Xj)7<0(RA-AFWNz!A-V|y{*|& zAp=3~%$9A#Ik6LKS6<`0aqZr0ueWe4$vDLdts~~+ATk@lj{_J*7vQks8K`Rr*U`-J z%F}3VmI#6GuC&Zwhn6F0q%eGj@nvjNecipvAFDZ2pRD}8l|KlmO6Z&`r_Ek+Y_%I<;l34}>zeur zA(5ibZH7IY+cb3f(PiU1bnZrlHX<`_PC;TAP|wlp{RvCz;P=M}vEW^PnS$6VI|TcF z)DEpGJDxxb)x)7Sqs*r85%&~mLDO5P5(brndr^E!7RR8oB#i1fbjnh%)tEDQ*%-|7 z>PK(Dq`0+(7#7rMWE-?;v>-@zAft_E3Cb@NrZaJcpyXpWZ?SV5nk*9ebUUSnGnLu1 zf@Tu}4+zni21~x$Mli#?Jq;2=BwLzJSyVhfg0~U^a?cf9+a}DqV_S&XPGnowUBhGfZRXZvA zF#5+T=jV50=urR-oOK#cP(;=JMorIA7x+4&Gi~N*XZ_(7=U0MNSA@&p6z0GXh6(54 z)t`&epCR=)T%ELrGQhu8)mt3L!RjN22>dn7Zq7g3sjJrZ*J4jCMVq9Xo&90z&#-`J zp!^*%9k72_q~N49MYR;HMYq%e zCMp|kVc9=2C{4fA-t4}-VHyS1X2;^v0ef4+LD-tcR4y4M=cFC18G;X_V-+w*`l^~=q-+Tl>KU#xRPKkaFN;IwR3Z1oV{QCi7Y z!~J^0w6`6O)}h$)Kk{%bIhadtwYl;rjbjmds^5FtWIXf~*#y zpn~6h=V)l|*H}tQnUDaA`I%w(=l;h0^MfDJLS2j6(b{TbNf);s4l&Op{`sEC`?+yP z8?LHVKpvt3z&}^tLw-uM9z0M%6V@NaS!7bc+GTwqQ~V?aLk;n8dp1DAP#em6diP8y zOA07-A1x*cM3RxC2l4Poyd@kb<}K>6$32KtbWDIpwv-e-1_ zT*C~EusK(Z{uQU3dnngqHYGgHAt&V%NYN0u#A#j`#7-c)G$1~(oOU91oRBngPa+3crvNI8PAh@Z&!g1tdqq$V)L^_q)IETyBW}dgM3w_R+2->_ZcB| z@Q;T|2`v1mENF3uK&@^d@^$u^+vd2t|CX;AnXUTI}F$<4EuZiLjXfBBKN7pg|D>t+{UD9m0W^Xrga&euQ-VqYz_8 zc@{L9n?e3>o*i8AV({oBC#;d})UwPndjl$|0sLU`JQWQrQFa^b_{nv`e11$a!eYoQ zt;5CQL3s_VAvW`*u;(OI8v1^Rvwouse%AU;wpw(Y-~HjMU_%*=P#duzjB*Hw$+G@1%=gGMKzGLop^bOk*C4q)U##)(2oYU_xVmg&~XOPa7FA=W$3LS1@r< zM$ce`tuaVLSY;r>HVxUQAYv!;0o}0ynp92(kuw<%TV@ml8_dSoVZzuDACa1zzKj3S zHm+5btFA9WG{R&mWXyic-X=4*5xMdQiJ!4I(fn8L%J4^R0IQ4SGxb0dJap1_D&>0^ z0=j~Rz8HH*9^&~9F(&aoC=!`dnRFZvdL^AvCV(s?R|Y2O0iAIbsA`) z-zu#IuLg|U&gJlESwJY@L>b9Z_u1S^u-CllC<}~)8@1W@71;VD+KCTYTEMaz-i%A| zoKLgt%Bm`0Q4?A-%mtuk)Uwt)lzEnWo~ff;Eop zC{R?&QXVjIS#ptcGHyDRmqjs=FV{GbZG-}!PTdnOdt0U zpp%bq_IJxs;??I)?G@hN?I(KZ8(R$~Ebko8u^7FgSCpb&#Gdto#RrRtO~;g64l6zd z#_%@FLkOO23ml~9!Mk5t$R>@NVWNBfV5Mg~M)y_s?|hzakg?Tzrt{`!l-T8jlTaQv zsx*@;9Q%>gw+E{aFHjijGr%G;(s}gfX!&{0`mcq!Lk8s|f5@=KljqpPdw222doj)3YW|z=OVKsMyp3@LXTO8#G)WSdRkE%GRF) zxtk}m2(%^(ax}!GdmQSXfNt@g+Yts?>s!qb1YQq-td-*UKRHK#sYd^e+3{OB89Uf~ z8}PJ3#xCZD#tNbWv?AtzD``cnzN>|d4Q-8#{|o(Pq-SLRhJP9VyCt5O1n#7`gfY~` zT3$F#&HBWV{BKz?^+i~lyEhHtmg%w1GP4K|r;vwKUz+WLFTSg}rtfER$@$#iwsYd!75APxL zwxwN*dxN^lYEj;UFRGz0n+|SRTWHABa~aFB$rcl(CcIX%M9#D*xBgib-bewG2Uqn3uw$C)ppM2l%uB*HddLcVRv1$WC+7Y*)9k`?DnmcO~$7dF*( zPpjbUyK`L+VipB5nbZ?uba+WM9fMt|MHFjSJ6v{?M`q=YZthB_bP64(NYcEynQ=WC zX6F@m=ZO$X)?UxJ97jYrS7U9yj68EXiZ`>!*r$tVf7>4k`T(Hh1{lBx0za^%0%+^; z@Gvk1WUmupP6wiJbb~O&>}JjEW7g(c;y`zAA*6M)uv8B-TLkzNelZlcRx_BnMm@Hf zIQ7BwcgVqVAFu4B8)HN)Lhup{ylXgdpMoXY!ktdud{uZZ9EBrNpx_SdM3Eo5Q^j6YWGwQwJR9Uvc29#9#lI(%B+NuB*vSLvm@t-hJh zzZlSnMcii$q$0eFb=^-xj^oECnv=&SQTHP>#aBKUSyM;3`Pr$f(euN$&u}P~(Jq9y zAQs{6RLX{n)o?tbZjp9zD9dt9twY(6sCrPfL(ZG1HKof!e4L<@7#6|v7g0Zr0Yrbl zjRB{9Z_Chm@yMhtQz_}abZt5( z$AtmOD^Y5{Mg#$cd?ux=G_c*L?s`tOXG7H&7%9i2R>p&>U;D;XHuu|Wi%KKbb_A8v zyDQg{0m|`G4-i{>-*(Mo8}qDtUT!rATvk0FL?C&X@R@k9)NrtXoFImhAa{MYCi$C8 z{Zu6#WN}X$9oAtF__e1Rm~RmCHH8;KWWOQ~n7x81yE5ZOVLW<=Vdvzx7LoM#~~0ADy=KiUD+y^L$?XPtL)A5^?S z-@z*+z8VMw1pZ+N&^*HOUn==oHHcU6j=xCyEesfIkvfhT`|0QfxJb(iW04aW>H{T5 zz-IYmh_?ui62^vQN38b&Z=v0Tu}OT3?8pfcK_p;>CC!VS zmPp|hC#DTmn7Yt!8PgcsnBW@e7;PHXs>M}UsZfuNzfxOLoH;J)FQP0OHu~XAsnl*6 zaW4N@_BFWD&oSNFvtvV)At*^QJfhmJI66PlI^^1gY7y6>UK-Bo!P&Rj%Rb!Pp?9O_ zBDtd81h9p?lH7#cgvjYhxmNb#{=)gh_XYpL{_2dGCL1VOEm<<{oC3=s;%Ne5@)ycQ zMF+itT!eW1Q3VO9pD0Jd1Yruf1O*3G{ifhu)TyyWv*q5I^Mdu~hO3x{9Ax_RCHBO?|;TFFS|V13PVfU!;#nKL@yXi*|u`XToB`W+6oT z%ft2%WQmI6VB#2wnuK)14MZsNR|`-@FCs9bU}LHxvr#+fUx&~|A_!T4R9q2 z<4H%};t58m&Ha>q;>6k{>O>y&qxQ>0YU8|VV>8PjEa5Z}UK(-X<{)fg@S^(?0?H0c z(UDb%u_cL#kIU2(SIKaZ8IC3X@mUdBNg|e45S|?`%q!#^nHi}ZiHL_I`J$YPeHvaG zr7eU|7*#MSK9_3Az|64_!;$)+iApFI&xmW}zQ{R&JSo1Ho%J1tH&HTa %|OBt__ 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

    >u|qF z&JT-u>?G2{ZOCkxbbq-T2qk?>3Z4s7*;<>nFMDNIs-W~JzOO)`sj0N z?^Z?$72pitwfM5NO*-{`t-{G$Ze*_#{~CVP9$FCVA}%)i)cxaQKP4O6+v+oGSnKK2 z#eF{-17$(wnpCn{L$I9w*5EWYzIZIB$nl5MZ>N$fCY2i&>NLY-KYe;DadU#@k6d*z z4VBjPpdglH8ua-!^wel#Ajy`=X_LE&Z+*=NKRyPrQ6e35y3)$9=RpkwwP%0z# z2jN(ys@&^LD|qwOcM5d|5Be%R4qM2~zDL+dX!Yt&JfHMxVl^Ddqj9y3s<*TEYmP|F z%zYz~3(vqaT1m`npA&S^?7P@&ZRe=O(d=l>y=zT_najNWHXnFvW`T~#3lFPWIj@jR z_P4wZzP9}9=jx7U_&nWinrq`A-9>}gr2{T~cu3=49xxYTwkC&80AGMT#*l8K!%0^- ze9!U7j-ebXP2dGSAKq_JpF1ZcH5w@T5&9MPUd>x6n#oNGoz#lc+Q&z8n|idI*?^D8 z-hcKVui$(!>!~(Ux-t^uA;n9mY^sjxKApJc95EwebcbiD_{O7kST(~Tcs0Q?0K81H zwz(wD0uTEMfa9zl^toJ=A$)N}igsgk{{l<-`fqz>4c-^egPq@Y4v&y)<;1@bRMx%F2mE6ReSr+mTBiy*FcBe$!f`OiD8aU83P$GvV%}4 z$4HRy(Q$5!HL7QxpDx3Xf$pj>B6oskJaQETGVRgkWmp*7^Ng`_1Ikjx{{?sgo-?u3 zaMZ-x1PPdNy%DfM&s1%D_2<0~)!Bzk@M|G}R?NvVrF}L&p)>JPKvh4>OeD#APb)_q!y7&;)5^7ANK6A)ISbw9D$O>3iNW-vy z4)7l&sW@|haY7S%Lrs}M5sRkAkU+SL!>mL7%3`W&5;Z_N5t?c~t&`iLz2RLT+2W)O zP`e-K1_G};ij0zMP_hATf~*K=8?lW{TAK0)37t?jE)cS|Ns>Z*_ zbW%5x%f!(+Z8$9xc7mq07{n=tl^x5%qmfu3TV24Q*iSo3W0P)aLX<@!1#U1IR`^i_ zJ31N<+iQt(iAW?n9GA;crKU{0Od)CWLp7Wdxs}JcE1*8OcT+&F05TzKt&C)UJgE1qVc~Qo$0>k4tK0Pv47_ zhnCv~Ini}4__ApOrFqZxiws%maWg?@OQMJB)VIIc6JZAJ=1*MMlL~_H@qcLt#1J3c zR-^NgWTFiwlk1+-u%gbVScNQWEMrW@GQdG|G6=}OFlrZ$&MMx~sSl0_vIB*izDZna z6=d?hzOpha9)R`iNjQL9B-mG4;w}IW1IGHs^bjbabpag+9<#FtGszqy!V)vFHaLRsL>oWFMgOfv#3eA)7ETtZO;URBoG+PaMdO z6X+hVu3IE{Y7Qs5aY2~EekkU^H^6@zRUx?hY<$ng{kAWy5;)Jd$0$scCN@Xy|{ zy9I;)c=d|2>~kkeemD-pzgl|kdb782)6cp^bD?!}3Ks<4cX+n%cQFdx0Zcl&@5b(& z`|qR$Tzg{u-A@bn%VGR4#GmhN8+LEE&CA-Feby=!J?P2JR_~`(f~+5THSc9MX+6C= z74OKij>qg;KQv-29)ZVg%`b2?+#>z4-Mp>w3}s;abF2Mqg$&=ZOtW zVN?EfuEdzBsW_`%S7}zJUxtkXM@QYfkTn1BbG~?;@8+g_YyfIWWtX4ld*p0t(#0SI zV_)}8bET>6nMBGc-%nfhjyx+cF51a#YjutX(z3&#Md7EZRj-TgUeLrts zr?rn-1uKcK#jG=y&2xxZL2{w|Q`#teVlYTU~c;zeaokDTl7 z-L5p_#y(Df@Z#t0UeDhncn-tV_x)OSBs~9oxxfB;xtC9rckKJF0MP4ZN!Q-Ef=R0# z-$gp&ndk1-jx~NA*t2IP68n;4Oqey+{P^r=u{w81ekCAx&#!ccchCX*uTJ8ihL6L8o!t9o>Ko3?G~lGs@CJzbbS0vGu%8SxwlY{fcGVeL*p2d z_(nvnlkyqAJ#T{XYV}apv5mHGNwCXfn{DtbcxomZL^s7Oa2q^=^L>1_!$qEcFE)Ge z4#xvpAfk~15D{HbYU}-J?82JQD0j>ub7E}IZ)JXYghHGYjozAqaD&TT8ZV#Kfp?1j zr8b?Yn;OWnOuj*X0vZA#O6uN#)>MM+R0yeXMS0ad$)h5*#E|`-fV( zsilt6GLZDlYja*e+O^syd|$*Y@lzQhfe9-BYds zoUq;dr(0w&n(u`s_}8jF%aDYD0ScV`6B1nsx=}7fpBQFw1I0^hcJjTpTH0g$xVzaw ze8KQZs_0KGyA%puwTcnh#rY>AlP+p%f$52cQ=1{hVm-_O6i12lI?8n=?>TFHHgGvx zCna~56d5PZS=zBJ?&{$LwGwDbvLk2dgtsn(k&bl=7Gd(}UZ>S2ytV$Y90Z&MuT7Pf zJm@Fc3@50^2DSc_t5EM0)+3NkkFZT~u@y;v%e1Z~lita5e;Mx9+Vu>R>Gvh0bziy} z$BUqY7E!u%CubPF4?v$azJ!!^l#;=`x^rKKX-A?}gb*vdgC#`GL2aS+rsdX>Y7TTR zvwyrRY?bI;r}4rj9vb~ndBzw3^s?9(p*9qFk7g8`tvpw90yn^p3^Z4=ys=8%GN!qpE%WVXbtxUhT{;q4P=UR!OZHJDXy zqPTGN{QR1$rNOsHJ#@pFkL~_qh%}?7eB=BPDebKQU7p)DO?C5c+Lo8+fH!Mjg4MUp z6{tyiE$;etuDovmLbo{FQ7Rs5_ zcKN3H!tl&#L`m&Xo99_2|JZ--h@QR$7D? zhk>F^mP3P$r7F=3@V{#wsBqmiKV7GMG8{t-E0c?aG}L*{LpZs|{=NN9+Yn_Zvyh>h#d-F=CQ*hRiSC~$98f&v^l)MqNnE+0SrBAO^2bKw_^ z%B}yL;gJ7e-;cckG;>xi*()axlD=^T<^UdY);<#VgKS^4XOkGVgH5S|6%`# zf9zkoj6dcx?->@WF{$X;3$!PeYmF(uywCx9%Y z%ce`o9UNok$IcB$4ANrxNnw!&agHT{e^FY7RESU55Q50{Db3xL;a9^0|KypOm2k@- zQIW{}Aw-ISmOKZD35@M zP}-o6&3q7*b0$RO5~p`VH2y??AonDFEtmL9uZ=K8an=ODTS(Imo?0f%RRuf1$*b-? zMMl1y$K~Dz{sm z4wCrMaL_tQf~jsJI)#2He(rcQB&aTYK}td}QjFphqSP6HoS<;&&cHY-t~ts?Z1Lz8 zo%j+)>J!krGB0|X>RpdZ3J%CL{n`?OU?C|TF{(cFd^CpOUY-cKq@D<^-h^$aHuFFD zX6!Bo!b7HYFl5U=b(@rCU|1}m^@v1nV47;7^$FnQx7%MZ$C^+xI-`V+yRL%@w8`_P z3Winw1VL#4gC%1sVvm0}AMre1g;=YQ6rgdic+x0sV~s_5*VzUpL$}V|N2AcEfrI51 zY+>>W;LMy%1F@Md%c&9ROz`?pldOp%&9hYNgX7~P5Q(Y7@EX$gb%o9H$(5I8OVVZZ!Z zEfg(Wrrlbh|3sw4YSLkjEXTi67^k)7z7_+Eb%Fdc?@Ws5=*+mac1rFGV_<;G+lq8V zm)2wIW*3r+;Pe)yG|V9bqsF>@5epsjLXjQ$fr70AbruVhx2ob`S2gIpzo8|eDF=j4 zFg)m2ca6`H$o2;1xq`~l_ zfR&Abins87*f30eOHVQ%p)j1`Qomxc` z#;cvmKK?Tzm6cCZ$j~?Jw#g$YreVBaiR)0S4 zSm!*>Iox{BRhb)(kqvaYAqYc^W3kfcEq;WP{K3cfBbzvsycCwX(~<*9KN`$Wd~P^M zv_lMC9#kK# z==cUw7(+J`_zP-KMU{S0*iMoOlfcZI!&$GajgMj_XG051PH@s%Ui#(w78~#<%1r*6 zRD?cInDp{0=ha+Rwq!mL;kDKJfvnQhBzjUUE^hhWlpn8;W@TD?Agyp))=wpUHqlEAJ_^Sg;A<8#ktRH+8~(B zH?j8_^orGau3)gGqc$+HMNXPUt}s2Zc;Wi;BWz7HPi z*9$uAmoiAMlUt#&LUn<57D}|!eo=Ulc@g5E{~*yuC#?@ONBSE6m^$ce*xV+(L5_z~`x*x2jym<81!WTR0qyD@@OMV% zibm4mKwXt9@eY?INoA+T>EM`qf;#chhiR6RO8LQMJh~l)-ZvuEw~el`VgnTq36t{! zd^U_nd??IIUDQW)wMpr?DxRH8%%ff0qy5^3bXHX45x@GJ8K5`Moy3umru?|Ou(bQP zKzSTyKB8hA1{YP;q&TKxoTc`kEQ_fznW^I&!`ob@yRlbQDv1RH6G>WCWZW;QzUX8{ zZSO07>olmUrJ%9%-;pv?Z5xMabWUHbeltUF%R-&PtifCjMvZyTLI#+Toq%w12~WX^ zb2yD~b|&EJj=gfpcGt*#!Hxgw(#wMwC~wVXKg!beDNXIElVvD?wnapZj~1* zd@VL&7H{ta($P2CxT(n8+6w#p|dirL}K=h zo{-^%ZPYR|JqK}g3gKkWVja=kg|E&M`*o_rscfl^77tREb5v6?L$&M;unnHr6{ z1p*R)c}N@TcL@ep1`k54;Hj+tj?p>f*CcCL<&U&gC+3GjKv965?w4@o;)1w?VHE0T z=7NJ5ws<0ICMFwYm(ovVnD6&42rX;i zH`;1xlt7SOw0`Uj;um<_*oxV&C@>c^$jcQ@@M#4+@C)g9CD<1g9=!Fe5=@}LT$Vssc`*r9FPESC58YpNj3?j>VET|Iqdy!4;!pwrLON_x!g}!zi4442 z5k*nEbkLT*{W}`tzhip&cW61JW?#wkD??6nG}*_QE@=Fm&HSq%U<^T43E0wx8VRi^ zcCCq|O)O}#P3mO&H|uF4qm5Rrcrtq<(jrkCf2&DJbVe*H&pbDZMK~w!P&Xk*1yH>} zk>z*I_|H7E8I;8lkU%>IyZ3(vwO&Jx1i3=#$wOX4>A`G6ZvP(EMXV00*%Zk%M+X_a zGR#{MmO(iVe~!E#f*6E=(!nS4(jlQk!zXjnq3#i+Fk5 z^N{N`;`rn^2@Ew0$e1Z2R2$trh(ZTPqek1~yCtECfsh>}?i2#;<{wl-sgf z>wWIw+9dXr=&QV-ylS(7yrCB8t)U+#lTQRsKUYb6E%B&Jck+sFrUJacE|NI`XeAK+O zzEio$GS$=bBQ$N|VuzuL=C6jpElK+IRBBJ%)w+Kfe)h~Lb9HCd^AQqH?6DC&UX0D(8q|oQrF|wfLv<<>j%3#% zyw15P3z~-4xK(6dK)VBD_VcbHFLR)C4&?|<4$j56Wj#8bAhljVUmI%mq{SVaR-=SD zNzJgC`5R``*CY#nfvleNal8ZecUnmNhVjMJvOAV7Q2$@f^B6>*TJP)F7SuX{u?H2G z!VaO&|C>Sg$bQnsq8`Z1V-s#RLH0l%;*&Ewc%yW04wV>Qp?7ay;I_&P*puuTr@aqK zMApF&_23#klZe_IQX$gPMiHc=syEWZw~6@r^*QtMs(zr=Gd<82|1K(S$M0FWCx5au zB`7II-4Ka_p|#^~(|XT(AnY?0l}JYcv1M0M!ga^Q+H%SD`C)4uG2x}8c+_J#*W<#kTKl=sW@9#`X^8|S zJ<9vCd)oClBEJw5jvdF$Hf93|ACVBbNoHQT1>?T79r@^NusWZ~68`=aoZLlt>e1zS z)#Mf%HP1nJi+OIkbDL_zM>sa1utOg9Y__mWkYUsD3=6%bg-OngYG~Ckc~4d2je(Fz z#XF8IY#W{eIoNY|Hz{8l%;L4>w|d^Fmmbd9T?r?@GpDl)M%Yo5VCQ>kymfgAcHdU^ z{1XF+z0Bb@?q*R%I>s&d;@49yI>JHIt%<}U(tci&X_itw|qg< zGaQa$rYM-a(i|E{Y6>1-Yv*L0RkMMEJ_vOGSR}Y`@o=47L%*a}I{fJ#)3#fquBT_b z@9!|0nENoGan2NrpROievY2RrJla&RJCDaJ^+!Lu)AxKT|&SGx@Nn>ew*)j*nU5Ybahor`t0&{(&?(d>C$2T@xkv{7zRIB z&ydGd$}38y^%T;go;)a2@nxXy@5fcB6L4c~X@8MpSt(Y>Z0xFi+P29v=BDl_HaRb_ z(ASES*iAv*vDQofKBnVMJ*&tR`Oz{tFmt=iQsW$0cME<-T#ozwQ(a81447`JMRH9w zrppe@U@9*w8}C-&>lH?sH`Gz6-q7f(%=aOT{Q#}|4RTesRpG3Upz8u^hsST!6g&x+%A{TTxE2Wezl#|zCU^n!PXbghb;&|Bd> zbfgB?&7&roim`Vky2&e}L^cB!sv_L^K-XBqvysb}@qa4H&cBoYX*Aq-7@o0U=n_i} zB|BJCf);%fGMVh8^t@`g+u`OkAGzbEGukQjbg3=GC2-tdKPt)^j=juXV(WbNksT(` z0>0Rfu_4FKM(dIIYX1EOSvP>iq$fX?qsvpK%>BdYM!_e3^z?P`d40)|ix2;{;rm%x z`R8m&HJQgk*cUTcR8e-r_;526Hm2@AUE^6;@4MknbG7BRxKdZk@Obmk&txRjXgkF- z;dvx5CAV(g&RuCS!`g*L6#I2rENoTzw7Tth(qWx!#^*aqood6*3Y4lP<@|B%^=RL- zvb9rW$yi_B+V&P;BC~r?WlyU0yngfJv6f1kgAvkOt9F(u%dl^ksl?-p?iM2*ejn@- z3-u;oun_7@%_s_N|M2>@s7bpUC@;0p_amAEAh)ZBWG(+8RWQ+Ax+OWwHM_;D^OP0r zkTQWm%PX2S`x`#R9lB-+L!0o{-+|;>HV-Sjs~LXyrj%s`@uy*37o6v-jGY?$s(t)i zQ?ti)_cHWp9gPxG399LQ4CEjcj2Pk(#Kgba{Ea{R-57;wrnn7m8!OTHdW5w)uX8Dj zY_KmPZ%)@afybZqIxDT6vC+?w`$YMqA*0-EU0Zd&!uDHD>B*w1Y&Mt_!KO#0p>LUZ z!=DIgjC;~3bpwkAxewm)OdPO%Q&=xDJDazwqR`hQ)X48#^5R4_kE1GC_$&QfVSkhDNl9 za;!q115;1ASs=vm8h%P{p8(Xd{`1k6gZn)Jl;^}WZ{yM7<&tpbJ((QMc&RA+Wzi-! z(LMacREWNOr3Dxs352WQBlm@1x!g!=A)edLtT@_QDv!VSE&XqN(t8yjxeBT_UxyZc zgkcx&y2zt*d$8K;_14Siw-D=?i(4>vO_%wiYuYq|eW7Wj@P-ZxW7kQdp$8T`BAxdy zJ1pC84=bH3u6JmY_qQ|N>$k#oh&SHIkRp@nO=^~Sr)hyMU;qDIWb?md&Lo+jUj^XB^ z2fg@n<_orM?N)b3>*z`kubM^%cC*ULVVk|&>%;6xigAcr&P&*Io71k2m(@BROLis}58~P_cks9NeVDZ}D@kVZX-up}ar_8^`;Zq-4>ysuSB=&*1^>*n zr9dscj@GJ&uT|yBi$-*b=WeFwVz@8trK(Lst%WSxDJQF~F6YIJv(!t_2f;az`3dy) zYNtY{J8i~RuSs<+zC4(j@HfD1VSlesu%J9u)E8N7fh!K`<-{=W!&F{BL1x6$CPC_! zstN{8UV%3mKp8eUD@_foye&FiE2$Oy6@BY%mo|OdB)MsRS+V;AG^s0OHM}NZh z3Kwd}RsuPCRS))hzW3g1U^4~Yn=jUP)#kHMZsyxP!HN7mAAGpb*!8I|b)eOUaJm(` zMsRS??!+SBM>FufPv^VR&9r4#_K)>8N)Nf@_ibwqGTH|xzd7HG1VjvO3Sy=j zE*e-f`KW%n?!-0HPM29MKl7d%a!#u3Q~=~!IY{n-*OaQbq&gwq3555@2dUarpq3C{ zDo6Me^es(93d@W!!OQvd`ePM#3#v+A3Y2$YFOAFnkUB-gS7*$@+FaMVktWyn5(#=t9)zM-MZWvd=_JhP0^-CK zM;PFRzt$$I(^efLyjw3^pi9`;LKHp(p+$+n)iE9;m~i0AW7K5#;V=5IISc`bmG)hf z?~##+!vqB_#2Yyd;;}fbl`Q&I^p@tKA*2g+N!VP$)wAc=PdUEhb3;lqHoB>h*TFjd z+b4dS1r%Ut;S?f;)HU%0#d-MP(nQdVYQOg42e+fr+t6WdKvQ-#JN=?pqSS|)1Kp6x z?ZJ<4Sf>i(`zaF&PJTBivY!chQ$#nMh+zq`$463?#gxqAvV`L0jhItb7cDl$x6Ht= ziQCS;J7rAGsXOI-(G_p|)0<+u?t{u53T90Xw1tf{1nOKIj`2jB-SP6o;_s5Xaek-k z?eyHBZH?L9{q>6A-|e}3-YC;ZdXge9j+~P{&3{nwptg`oNhn33+DBErrBIdXV$w;^ z-zWwu;;EofPb9OBgPT+~NOR(&rKnw~TP`#~ht6N$m%M88)dF&^?9?C@oJxfyPD#7{ z22NGF`~{CZ;zl`tVIJ`mrl%q;OhcX_uvx2lZr(zLhX-Z`H$>om(Uh)VSJk8)D4vI~ zFo%FPhk`aYYKh1o^CmjV_&NYx!6iW)ML3s9j$7h9Nln~z+=~}=QwQ{PcI{Ol?gCQo zWye0y#)=M*$Si`CY3)5ll)}QH%9%)vAEqb}#bE&drrN-ZrhbL_V8MT<6z0>WwsN#d zb79X{Fg0hR%Ns17oQ54*RY--`{O$u|-mju{W>jxMI^zE#5PIU6dR?LNd4JbZXxzL|%QSTo7&_4A^d zI<#y{x?#;nh(lc5pWjkm&09Mit?f@`i5V|rr`_X}C7s^duE%Ya7vZ;1IY7u zIJ3XOG6`s*>8YEd?C|SQ(?B>AZ#h8aW}s7AL@NEP^UO3ekgL^-R1N+LS)vvpS}V+C z)*+L)xcKXauyFk*smFeRWpGVWDpI7Vm32@7lYsxN~n6dODs7H+>#!QbJ$aeV| z8s;J#>pf-FhIC3{9HHVGr0+W56FJ^^osl1fki* z4VH^@Lc)OnrGtk^`SmJNiUF1v>xUqKkBo<649Zm~F)#uZ%%`p(@=zQw8#JF+3)bx4 z?f*dbw&WN7fNO_9(04tP(QQi&hxU7&+^_V5tQLg)VrNq)2soe*jUNt_3S~6N-~~(d>q~?H zCB67fU@0Kf{zC$=yGjBIH*f)({vLIt+8)(SI{wT7yaZ4>;548qKlZ^?v3NC+j%kSS z=;*C!{r*O$MInx?g^%Fc5q^=_5liiCind{-<~2H9)7_lYYU^)6N&@l^$|MM;&3~2|k^1eE1|X9F;h_SQ3-ZQ~VA~E-%93Fc$`A=m z1*XQx;$R>dD&l*WBt6bZX_f6^N_N#=o6_ihxP&ZR;9U&yb;f*h5P*3o#EF_kl+Za* z4nYprDXVux(Uod+2;B@PFJ#vg${E*xC&!Tf94P!WVHv*yXRJ;wA3)lcPqrOO#| zoiOX?^`hS%aeVQ~p>{Lnqu+se5%dYeN3&{-!#^BxL*l2SFk|E&lXj!zACkXk>f@ny zBjq2ce9`ogyP5u@J1`9c4VXB85!Ic>21T$wNOeQ*0cO6U_K9h^W7{69zp`!-a#)~W zA9{aqT_1ydfa4zsdui0oBl$$e-mQB@Z6o14;`L0Ayn^uck%K9FkCwg?e`(Y$Vtyq} z-B zs{w8%%fcO`fa`p%2R4r^yi!UJY}&0Qt8;@(=XzB4qnY;P792}80&k%|O+I~o$QdRn z)r79es((8|O&5_LYdq3)t_w%LWo@g6Mox&Ev-kQsmBo9)zMeK|x+b;P={pyCW(%f5 z#jCYH4k8YlBfFBDo0GeTSSPG=dP2o7Z8Vb1J}2K7$$e%mTA#8WC)8toQ5#)a=RLd? zcTX~{nR}qtMrYB+(AK(pjt$;U?u}dk(^DsZKQm5hK4B96 z`Cl*7&}zt?r!ZCLD&==G2AKa9N_qnMv#Lc!*t;zKTB_%_tOu$!QR#8&EZ&=SwH|cW zSYJI>t1AN%6b#nF*l&0%40YdnTEOA!*l?20eSOWa>nCQsEgyz2twk0b^I}clhq5)_y@pp{o&`ZgMxhO zx*ufYVY{$R!oGAzHIDY2)*<#4WSBCX!tKc8x0ii-)23b`<(G51UKh*3_m+`hBU}?o z!*wKV*c<(U8fM;$86%e2SM4GHv~a_ZBL14~l+v0WV!Z^0OMDx8gSr0+>HkZy`TvCU z|9Ml&_}@%l)#d7iviQu$cbd87x&EN*V#>Bkk&=Xo0!q0G2`L2mvw+ZFM#ofCM3Dha zM3e@Sg2<-8@Vd)j2%O3VR75}kATa)Qm2JlU_UYwwn2X|IoTkTE4M}yJ*TZ)${ArWP{uS}cP&`qG6lw8PBQ@Ic?K9XiM2rM-7FYCd1AbB zoL>jAo+^shBQVK&rTC^#(w6zYLsIIcG02=)UpozK%-*Y#UQ#W?zOdTQjuNm95{axu z_{D1a+wYA(CB=bUhS!`S_1%oMI=Qyx#U&tf5=d+Fe6{y)7N2-`?u-LLMZoK1<7+?& z=_R&cj#l~)K(fIX*S*2g!wS+!AW`5`0yogi$k!`ld>iH(d!P598VZ1!B+CcD_~yTp zn~~mvCZjf|clTj1FSa=4|E4LL+{cinRRjUqg4O5?LcCPI!$*!|rqMjYze|IHDripI z83KM=95zUg=uT+^HRK_FS230FosgPh?^hyY{C;7y=t=Gr=Ngb9EW}5|nPTV*K45qRKiv=Lti{pWsTmg! zYznVWdp;9^@(=Fh@f8;B8Q}!q%?Za%(T%{4Ceq8J^``9XK`PO-L(4IqyQ;v2(#z8a zO)GNwHA&l!N$%g}yqPOA!0tKjMsM#dd8t2=glH%4j-$M*p_^ytt5)+qrK1#Rzx5)JR=0!it#4&p|Ws=Qv<=C?#y*k%2Cg&p;>D<_#>m^fed%JPCsxxXp-9-Smo;_y7l^Q)}&NR6YdA`q~}fpK|w6Ge>e#zhr z%!v}IrinuY%;1i^j?9kSjtKVz_mKMrIi|XXTgH6)d`8^{KKd?9zD%L%gh$!}5&|j$ zh5}*&x&jsgvI082U_WVp7J`t0%D|@~F_7nx3qaXHY#`c6_h$dB1X%*Nf^{R>Y4=kH z*@AkZ*opMB1@VDj!L=jUG4JK~|LLF7yV85m3+(;qZRlO=ed~n*3GSWvMGh_pWrdK1 zy@Fi^u8Zwvr0=^k-uwP*8O#P22iA-2Cb_p2q!rW#ZUgT{d8elL(_j3TJQ$;(fgq#c zn4qR0soONZtTc|CpPTrT&9i6`Sz*x{+Xak{sAw!`A;RYdS zp>bg=!kD;7p}{yt!fHbG5FqR+bUJ=PFb%XOmV@P}4&ifX6~ZdYoysT-VQpw9`kmyc zI^p)e%CbB0(Z0BSLNlR2A!4C@;dvoP;Yi_1q1Tyv;Y=ZVI9zlO(G%7D?EKAqrIY@d zbK%tBEu;=AC)tybf2#pzLVEDt)DHtQ)55L6Ul?zmC*3nW!tx;=1407@0}1_119t=C z{eK3|2Iyds`{`gZG1y3}c&%(SY}2q@tXHB9J`Jb`u3)s#pEOny4W>i8(4K5oMhx^q zywRVeS90ol`eTB#TR;K*wDu_~(lN!ON*22`$C_CGgy3|oO`0W|rkXYN51QI3Ln)cG zty)+0Jm&6$d-Xil?qhc)haeMXDYi8H8ZLmZCY%;n&8gtfAn{=G5VN4;;M9=ipygma z#I4_aTwX#i2RE3zj{Tnf$#$+UaJ#KR+nC*4Ue+(eH{|`fFutrG**CHMJ&@mQAICSF zyAb`cA>YVIhz8+d(GuaKF%(f{Vfw^aM07D2n2c=wn2f9i#CvC9U`QT=&PeQ{8)){f zgCIx<;yifuoO?rI>_l6!FD!fKVYo;=q8HH|DE35qR>pS5#>PU%9!0DTBn@11c$`EH zoDM1nFQbz2^TcN2Q;|u;(W9jC6U6EwTiCA(2Ziy0@zY}6zh7MrQbw!e*NJ^2Hc;F7 z?<5Y&Dafd3sK}@|si-RmDtN}x4#PSqq@u8p52G^BoSjwll8~B7&Qi)$70(OVM0rsk z#TFnGb49(8AB7jD%J>W6#oe-^kg_~M0M1m;dG>RR2Rw9-Ac=fMSY`TZTMxR^AKH3 z7w6N{il-rdlsCx|^1IW8biM7c58}J#1$#aJ;8oNo^ON0$!bN*qTw7V&U|UpMXWLv` zMq5W4%pPD*Y(zFJ6NjDHMowEk>-TZYU&5=DHtv13k?QDmjAxOJNPFACF8pVUjb(f8 zJ)g*RY*&gak&V@totM#uB};+UOp} zZhjw=5AWOaJ^V;trmxqR<-P6bZ;r2tm+L*>@NML8^^f|Oc_@FVT_}5~awtwHQmAGq zI4D`DLSz7P2`NzSM0N(bM!t=7cPi)|8BY>J#*J?`ItT%|TjGV!z^wl($Oy^|Ss2*} zdH(nP?+N7gL8Ne@y_G@g-)1B(q)((+;p}8vDQ#5t)_Wy`rO0}cUhKE?gVy2vO?$=wYUe7IT%S>GHb~< zCJXVoYsvS77_w|hc*z(^IoTGnRMN(=WAav#SVfoTFSLD+39P^T>PriI!PTYk4p=Gm9FJ=ayuv=PZv^^ zwq-sE9vc^Im3$>O)8EX_b{Fy&94!bf6fMFnFfH6IiY-_zoGs9cnv0_4GUM1dt;N=| znsQi3C$n9I*Jv$VORD9xGFuog!<&xhbY(rsFAJOK=UR#{CEiJ`)z@+@Am(FAvSqk4 z@zU^8@RIRza}sjWZDi@C=;doAkLR)H=w)o>dPuxw-hv*e=SoXjOQ+>}$h>_z61o{a zJ07s-Q%kpVeAM609-2?F=W``|={^@9T<7?uzKK59A9CkiOYtT6Grr`-1VTuO*@#Jr zxeFNzi2^6hN831zjE7fX&4w4EVxlUU(Tq zg(=mTZdyCu-S$X0J=PT7lrQsD>S#S(i>cMrX8MEDQT^x(NSt2UkXBV!l~#37RaF&G zbw{I>LVR98!)Pg^X1SEC$=uk{aAano8QG9xx|!juzVxYi-pFRcoBSxWbgp@A;+^oQ zy7a8sWBM8I%y90ulzx$S5q9x%(R8tKv3F5n#rOVkQF0;OIAWp~@2%=$=Hl9t)Wz`r zc44yWYFs<6o7hF@N${S2k=nRD{>AWqe__4KZ~C3nMgM+%k+`~*HIsFcRg?wH`p9a? zTFZLNf^iJWns6XHk{Pp@PS2drEIiWAbTpFlof^-2cUU^)Nx3(ky63Dt?99BkpGxK2 zKKw{%BtNdrGU6oRbaaSxpmuEExOc#Iq#x_zX{B`qTvcsYI=nmRv`0GH zPId7<=WIYY;*UKZ@MXU%U1hf8ANZua%U&V0b31+md9%2aJg2Y>qZ`No%vJ77N|w>h zQy%`!LtJZIeO#+t16(6(Mygdd=Wt6}RjvSatz`f^Ah(Xs%zN=I=8^aueaW_(U&~bs zK_eFMJq9z{crbKSd|+~ndZc<#?+)jVejE+N&O8QYW-Q0MI&TH=@LqRxX5QIM{N=v( z?+m@in_ka)Hr&E?zdrWPcy`{3>D<11I>H_2j(26_=iq1JC*9TSIjeJx6av#m!>3 zt)CjYmg<7$f-VUf9ZgrSt?DMGUp3egnjHlmg-`j#VOJ{{AI(R%t@>u9e;ei*^-IUC zVMYrDfTEM6lBAiWr=q5!rK0C#5U=2*IXhTDDS9dD80itYP+%EpLvuzC&~(z9?I;+D z$f5D*K4~s+jpUd{NZ|`QWZU4t!&R)^pgi+l~*WT!sbSM?Q z6;+-(N7YN#Ua!8=&Hi?Bs1^65OG%_?| zIyopwB$*_|IO!lcDPXKHZM?hoL!kscrhtrib%6+~S_(D_UL^kAep) zO*>6vO(9K>^yaFfst%woTR~O3mCEW%gQUs)glXy|b>c)+1F6Zxgj&+3)|0|&p-G_0 zbV`@flgnyKL$%5Jgb&raYD>?B#A>-i2~QPI2~RsuWoKSz=Z4x9MNgSF4ZiXgz{lhj zcvo}xdI)$exGO$vP1#oU@qK-}lRcDA?os&ic=bHYP4ZR!@_wy7^i9I2;n(#kAu1y( zAnGQnCTcBcE2s#l<>)CW-6c;nKFcmZXZK!J~NT{|d>uhr{K3tJ9J6sr#8Ly;9 zS2;^wR^3u@*E-xxMo{6?esw!M8b_zzF7xWSn;);Gc2)UOYj3?%I1C?eRP9rZSA|kN zRb8q`s5qnYTnwu?s!&wjuOw5It$+=$i_PyKWQ3kr@R+)Rx(R@a&rOU#H zT4U>x!en?xV{>0~d^1$@Y4g%r!rB?Y^D=DhXic$s-;#V$t~OhTyH>4+^-t;oU9FCy zr|qS1bLEchDqb_(T26D9q33$bP|IS==2N0|s&&t0*d@wDoq-i> zCeXAV%!<>}2=_wt|D)|Kfa+Shv|$JYNpKR}-QC^Y3GVLhatIRK-QAtQ!5xCT2Pe4e zIS~Bk-goXdcjkR(=9{nTuUfVG*-v*@@2=Xrd$p~u8jdm2S*BfnTlVM8UHB<}s&cD- z%W&)G&fgvmhyVltvH`Kr-<~6$bDoo*gZPIDET$ZVb)hk*ik(_@nKcHk*6wxDJ*YWj z+5_7oPIlY4!*z!Brs#Lhx73|%S`gPD?hx)+?lA6%@3@?+HHg zH4(gfHklE`_&X0p084}RKM(#B zI6Dl(hq91FJ{78i>P3R)ML9)8pD2-fd#Yf~`I$}vv@N-vPvbF> zY|3D6kkUMQYM|Wl>vn~F@GZ-r5Z&_fkr0BR)Nu@pA){@3P7n`$q1sjp`Ch z&syxm2_c6;IL>}e)+qMBRNL}tLwK*XghS@cq&cwRy(fK-4W$0ZOKtz9cO4j8jS#i} zOesR-K=46&zPp6pg6~21r-b-t0y+nd57m?8Qfw={2OW~^ofLE&91*GziN6>`I0TwJ z5r$K)_?iXk-Lf`PU}&A_yzsmz7ZDB-4sixi2C+5~G~5>Pbwk(_9f@G%@D$0vL7P9m z0FHkZ6InM&Qq=%=Lf6OhuVCmPXnM-wWF_|5U)r7e^#$z%f}QwYQq z$sf;j@AxABgwagVTvKmRZ%IgPIgH_OjM`Ao#4asRpR}OAV)W+Py%Rx4$?%7eFzkh+ z!wPs$T4xB|^yZNU=1s}>*u2w6zZAlulL~roRY!z~QPdmAra2A$F~d+8oz61wy?k9B zJO*2DAjQ8X|13fL-wXTSLsZW#2n@WQKqyT|h>u8yy^wTV{_kPy3b;yZ_0CSyIMKtO zJJRv>0QjRF%j?-Z_e36UQw5v{jUFKIElP0LkA;;H`#xVQF6;tt4GV+Pd2+-h>%7&E z*H$&Ntfifb=}YT1)86=Juj~tNtxsC#K@SQZRv?t9qahp;LT>;u7ZWsW$ku;F-ooJh zU38XaxGO8$+p~d$t0-S3d&uz8zCk5A8loY|^#w?CF~P%9{Q8UhN$L0x(e0dHU1yh# zZ}ail2UTPP*3TFOd4@xvmK}+3kxcsoY`NkPL-nABpz!DW1H8GEkYSI13Gw5Vg+hTH z^9Yds2ePhot49bAD+~(C$&d&M;YUCK7ZVCB%=X_%9|WX-2=GTh3fD9mtoF8$ES_aJ z6ur|=6GubJ8YE95Y9z5A0byK@NU)Q?dbshpLZJ>Ew>~3v^chw51n6^3e}wh^CB%q# z80_*}AC}G?0q;#TLu`aNg*ov4y)Nt!kXijk4!v*Hux0-Hd;C$88dRY_-;kY$A$N(p z6rf;0>3)jW5(b6ov_*oX`y(Kd%MlfpVY^5CeQDAYlg+%cz!}>RZ z-vo-jR~#Cw%C?XU9tn4-)Fg3&OW5wehFOQKb}={xI;#Thm1F9%^|HCf z&G(-dYY_yupCi_5=kJrfySFcC5e14Tks&X(ZFHV;0T3J;4wL)M#y2|O@2l(j5y8!| zf5_XdXsbrg6UNUlTHV5n4skcQyH7CO-NKWbMw1TdH#+-IDcs#=|A5aaUfpIJ4(WF~ z`_Cz%kCTt|H-2Lsn=FESNiU;re-rSF`TXO|$@3xD59Hn5`!^8|-OTIXWDMP`?{`@K z)qHxX59VKpnHcqkz}hb(S^ylMGZ*@MOv084qf z1x=9E6ZGD*4k8u+hs?4i48u36)<+_ZM0d`L{=cnVi33{tL*9Oz&&QN6wmdLrHMC0k0M}Vo~Z4q z`O9cv4HgaZAN_hi7P85{KwOwPT-v@-MyQnwp%k>Xon+-%PXp8x5+Cp7>EFRH5)rTe zvA+`RHy)yS$oxO8IVcf)lw-p-q>_{A;eXh^e;Kr)jzVlgzoXcN*+hXta46<3?{P2dilFJJA!TKH z63}dW`bW{~>Y=OXAZcZLM&F(rAdyexdU(+5CZYd>jr)h~`%eUtC*CF3mQ&A;{}5#C zn-$FWPXvJ{-=*hPZ!0ucD#QWWmhQVOS$`LJM+V4A@}B<<$$PnF^3GSzKNjAtC#VwM zksY#zqGtiRB?CeOearftu6!930iS~Z5d0+W2d@cD( z$Q|BqTrGj8qjElhC%C5)R-ga!IN$&x2g(y^i`)Od0ZR}aFk9>pwUC~OJvI>fP?tFV z|4vCsLKl&~n?;2@3iEdr6XGEu!bgpZf%}WjpRqs({1f|MB>p>%V*LJ_CM2=?Kk}kD zzK7O@gwzn~`TQsB#dM7S_d@=j?{8)Q|3v>~X0zVC<3JrJ4{Q}1;>(wPmlZAE( zH)MDt7aywFMA-iN>?+0oa|&JZz)CU4WVjl%UNw>y8ED>cLrTDIOF{C7{Q`46#w^NCVBp{@=+Cl0Xfy%Lq7q)LvQ=PjTql zu&vLieQRL`NQNb#m&5)A`F~aE|5O!}2sjZ`VJZ?hap?RoqED#bNCK6_{#%kt3_3V0 z4+V9NIFMJ&G4yZ;3AMy2izI@Hz7Oa%_+v2xB=QY0FnEi|6OLC5UyT17Q~_iGY5{x! zcES5TSh9>h7(U#~KU%F`7-(D+TPAaK3!3%yY-h0U>nqMe$3#ImUB+-9L?ovcFj{<7 z6Br%LjbUdp!||s=ir${4LW09X;UaRhB>8j5F6Y8D(aQ!qhbMP)$bk$^0LO>o`Hx1N zpu`IlAW7&6aRsscc8opjk5QOA#PXlRF}?5qqFw*9r9bx9fbDo|iy&)})Q=5||6LKN z9~%`DoK;Ekp3F>o0~`JU1C-vzV?^^%`2=v_KSpAZ(6B2J-0?b3Dw+vjT_-XfV zswCuCcBn~rh0FZ``hZI~P2g%a-sA}C$vJy~aY^ef_^an;6H246TON1tJhuI<_3mC5 zIY7odVtD&*N9^bLMMHie0Uw4SB4xqI-JA)AAe_Y&x+6ySq4`y${US_meQ&AlB{gnr z({&e(B|hH(j6=^wZMe|qDyOHKjDd>^t+$}jD0;PS@QT(3qr2Yxe-0?#u0Mf!>dP2l ztkU|Y0B)<7)AkY(*S8;Lv+my@lwhm*6{!u$@B1@=vxd)IRn2mP4o|z8i+vdE#KlQ= zvFq?YrA~Fxc;*s=2l#fY0ly%>7Jv~xv98D8(C*!4s-Y3P#$8(5*$xo!(z(#h1A5$n zMoUi5lgL!l=a!ZkJZ{r@8UuH%QzUJN?g;3*?uY_|FZpdkn0Wm!#58?Bia;YPBmeSe z3hh02biHFZJxv$=DmS&59xi~o-@qfM#A@D--LM|DY(HqrY0{L*ygHF~WMTrzMPCY2HU)643mL@Asfb4gZ9$>eLbXpx* z-qETin9%BklqxM}^JPQ3i*)fMnCq*0hWZ@68{Tl1hT6_4Gkk7`ee%T(0h?4htyPPu z^W$@pNS{T=&Wg94H|^EOIZx* zzr)8?mgi=8BeBw#Hkg|$OB27?<}L^{w9nCiCsP`4yA)1r1L0mzkJC+(M^>w$ZQXq& zOHI$tkKd-khEJSp7Zxft+sSMcYt7Y3YRBJJzVsG1mKWd3H+OTNIz7#tTeh$}Qst>h zUt&o2Z|9T{&AJ1{Mg>g8|@2ay{)A79(^O)p=T zKJgp^+2=FJE$p%uWVLx`$Vako$WDq)Z6EjVZfCUmY~^}vPzw+%A_!Vm`q%!p>uHTbfP+os_?i8-k7~yq5yXR@;h>vV~<#+CsKkiiA z#c^I2tx+6q44!|E8jhXlCLc`uI=1iP3=prWE_!h%>87}5Cg~<$Lf(Cd>9`?{=N)cL z(e;Qw;dFkMJ3b@3HhQp_l=9JFY8=lN>zeq%)STc$8~*Zs<_K$D9%PUvwNGF0Dh7I% zW4VFMhNcL+k6T+6e2t zos$LaA)w#FSxFXNI8;*a-bj$N4;RPFlIL0(?6X1|Wx}Pr?G+?r$3(m5Lm$)?J?~Z! z@Q9ltjMM6jP5aJ_$?_w_OrVuF7QSwNw%Zq74nvm8t5+mN1{z(yP3;FA0s-Nb(kc3P z#-ZxiO_W#5r?<;O(Dy0I;5kdjWtQXPGoAsr+$V#5OA(97&1%p3ZZ)Gi6JJWzOVvs> zEWU6qO+c1krK6Bz0@z2H;?|} z(laVipJ)f9uT%n)sK}*9R3egSilvWKLXxP>q?c7sG|k6w{PzSHxSBXa11M`XTFHu27MRrxN6v9Og^PVN<&7q*lJd7*3~Lxo?#-1 zr$|esluajtbRxN}sIu6m$lfYPtS^tvK${3Goj@iVQ6!U5B+FoxZz^Sfq-_=Nnhn%! z)7K_hCt9bXPqt66Pf3v;E7mFUJ5oR5IC4KivI=%B1*){kw&}DkoeZ7Coz$J=o%EfgowS{los0k?0F_<5K!QMuK)gV*K%ziulZ=6s zfsBE)f$XN#YSGzj^Q_10-7L}(?2+UV<&nh^=8?t`r&TGa9Voj(e-{4|cPsN%=CSB` z7V?PkD9=@jhwhmkKR!lgsAy*v-b#vxIy>PdUP0EPs9~0SgqGFWACC%lq}MqNk0x{k zgIhNyj&zTTTRSG+WRHtmUm*^CkBnPOAzpQljazRrj&+ZYTW2!f1s->I5UZ=W8;rdOqJF(c1${aLM#gxDIESRvQO*(0v9aB~YkKEy-%8(1-*(^74v{WZedFhD?GVayx*6um%+FiTf>)i9+`*?*u1w9o$B|bGgMLtzNWp=2(=xvZ+q}&aE z9roE1+yh+u-TObK`YH*K5vIJR#12dDnOr;Ff8!&|O;Q|r9WLEtz1F(VI#t6W7lQv1 zm}E#U2CvrlDH5$lj4J+Z#k~3l)pwaJv|2K%aG8XJsv@d#nT&)QQ>yg0b9~jiRIL$e zBdXWQ?~0YERU(qnioZ~+jwXL7Rw-AhNX98v|4v=iN8Mqpah&8mkk3YSKz%?ak>iNJ&ry1JtVVW=hAwW zR@qjaR!ObmwaO~>bJcSV0wsbki&V(eHpy=q+s97urSBTmv zO{q?4NS0xiVOC(4V^&66C$3aAl?BpNkS@s1%PuG%TY_2saI@5@i(eX}L0N{rpuSMv zRIX8$I6rdy2`uAQ!6V-(lU*~Zw7QUP9m*qn_Qj&oWxmxq)w|I{j@Y)+PMqTDMa7mu{7A^={?n^3?^0g^T%%1^i>=TWXumdf`j{x!UWOyYj~csAGd;VQ`$c=Ccle0fAa<`OpITah$gbfALFU zj`~!Y#ez$Ph6xaYUg_g(U?U3smydIF+ASFQ;?~OAK#alxYbWiFlss~4Y3=%yf?{hc z?Y5MBGixpFrj)`xYjt|Xv84|{k!mU0MH!$wGqiKWwCr>ao^IVk>Skx45wNrvlMLE zx#DXVuvjXcQAM3mVUw+XlPw-L7$w;8u>w;{JBw<)(x zw=uUhw>h_6w*j~LP2!JIkD8BSk6#|;9(7kM0QrD&Krx^iP-r*TWV30#X|-v?3nT;* zHs%6z8x4SOr)GiKD;FyacFj$akD{xU&*f)xw>GfAZeY*~@mbw%v%45?1^!%&4JDBH ztjJyFQIfYhduG!5fUS1&5Yju3pa}Ma*t?9NL52X(l4+jtG&mW& z`G^v%`XKmr7%R$8U9i+gFN(J3^Wg{Q_w6FO`878{Gjqjhh~^&D zEgWlEX&F4^*vICVsAb;NGz4KM5aUMV<7DLHGMMBWVcG9!o5VY1fB)ICp=rEkxMoSm zZqH)Rk%B!ItrO+9qrStjA8QUh> zZP0tiXb06K=&J1djOX}IQ$BmoC`glO&pyvt&(WW@e0F>$d^UU*d=4Fk9hM!Y9kw0D z9o8M@9rhhY9abG?9d;ci9X1^n9S**RzLvJk0xSX?0?Y#J0;~d@O*jTv1~>-T2DqD8 zt5Iiz&4V6;cY{bfusf1FlsgtXm^&IfoF=7L?cc|K+MP1LFx}#O#d(Z+9)#Rs+{tqq z=CXaV!()!Y8H(B&gf|)HvdUt4VOGGkh-w(*?msbKgFF}Vh~xc0C%R94k z=JW68W9vI>JL~9c=xpZL>#A!SZKZ9ct+mdI9#f9Z?G|mkYYl7J=ga5Z z=dI@qcMIn>YwPD;=L8lr#8?Q0*`Lsrka7CVOl**@PNz3?|Olo8@O97K<%u!ou91 zsMGUF$f&5oSgB9KSaS{>Ibp=ZV>8lwumg_uYeDycD{uKPjkjMvmhOboA@~$q3vb26 zyF`j$f)9Vmp@NuMG(ePpM4zH(c^~X|*3ma6=3oQ%{t80yOh@o`XnwmPX^{Ss#cK~r z|AIJnXe^0^SpS0BBGb%LKCQMsc z$hC@*QM}}n)P>od*4jHp=EX&C{8F ziVb3c|A9iimSWVHEO3?P_U61oIpN%vbYJA?hHk3IE@f(?mF(1RC3g{%ZMHv`KZvSR zE@Fr^IttEi`*BiTRsuk$v5PY836e-Pq!JCt;Pcd7r^PsqSosYWhvlC?z zni^i*f34VR5xvB_>y)VA?V%jqfvtFgS2z)SecMAyswIQ#5p}6geH^&@;bc!5!k1&C%8#k3dUn;wZK(&^>+? zUV)d~+4+L&#tKuFUvv+&awL2tcD->zwt@-;kK`OYk;l&H47zbzI9ua_Y?!e39TtE< zL7iD`lUa?W8%Ps;M{s@4&WzBYYZ=oqW?NM3X6bRw{>eY;ieW{IC${LqlnQAYd^VR7 z4+}cF*b6ev>ALfi84YsPdq3O$bxtC5Izy8G)w=zhMAiSC=Sb$LaAohys&rPU_m(sd z2Qz|JWN8QCW^)okKr6)fqzZ1SG?a;g1akIQXL09l2X5w1mrU;wE)nS1WM_pbA`!Ch ze=K`bmLF*ur4*%@F}tkO)ZTq-KqQAO0xM+h$So0I|7!C4AisiU%b==Fy_QvFG+{hR zLO)&}kuS<$m2g+q_|vYsIepUqT74GYqS7jTB{rY*6ufZbJ;l9Bz$U9Q=EIo|aT9Lg zNZt55MJqvDG&0=>Gm&E2BX&+8(G{F!20{J!V%lv(cX;JT@>kQpTD-$;C3^YB)<>(^@~5 zg^XlVZQ4qydJub^Cdwn#2$_pvAwmD3pI~8_+%3nc0S}-Y$_mhRF;1WGC;I5$k#6ek zcmmVC|I~-42u%N>?|i{{5sjhhb{}}#Wmiqxu_4G8L?zuY0ioX&?rNDDTC>J)3hcBf zA3J4^FH0BXdn@lEeujnKi!ajBQp+lZF-|!@WteB_Fs+7^bV^L=jP^QVj%{8>bfVuh zqLX(x>eMulI%8QeqG^-6R}%j*TjK#J>bf|7=sC}Ak4V2N6lg@b2r4v9Hnp7c<)bPg0e^h(IL{Xq^zi@Qsj^mS6X zmI`DgFol)(QWy0AaK*@e$8vn>8Ue)!N5vcXgnEZ^huDoB9iD@|!sbA6kjKQXQGP|NtSR0j6m8$6 zn?+aF<~d7L7_Ex6SG)B^uyZDZ6m=vzP0_QzaU2uw>XRipSeKOA;@l<)WRr2au> zkS6E6Aq5EPTK4WKz3=!&!nNtFjBG^??G-1Tr!UgFWJ`2It9MZ;uZWFx`ziK_8j3B$ zR!b;#gW{N)jY<);0D74l>~9Y%MaakzDI2t5=UxV-Kz28CWv>|9ecu#4tj;b%FY)+t z8?+SefuNL21^)iS@4z_MeR$cM5F9R3uPZ0uG`lC-tC05Vo5H2wB-JswYnAGV411<* zh^?WgLQNflmLd|x>&n;t@P?4=-7wlv0$y&OdjgpkyRKbYTdrB1G@XL2f7Lfabjzr+u(J2*=>Y7q- z;}=&KC9sztW6a8Sn zXc5X6{HJU@X3Ni zS1GsY2{J^;c_}l^Ry)bCl6}sxf=-IlnwV@n9cyh?%vUH)3OTy7r1F{b1W#bNM9*E>M4O|P zAnQCc^7MW#C@XYj|ABmkb}8|_kV|->!rbk1iV+yfAc{{#z;YTUu9sJi1Y>5SFfwFN zt?JawwehSGfjqbA-W^RYK0VQ!FBAUbrv$v0q3Jy!eeFy>*~OE1ruX8wlN2!cmeWK_ zq8G;ZjQ<#qwQ5EzCg#JsTe=mL)sLR9jjEgR~2Ewp;><;3+7z_J#jh`K99G8?Sf#1=5YRL zq&tyebkHs=$`m5UX)eLsFsYO@4w@^T8#NWM#!@8^o}KSunTfqZ9dn1UFvw6$TVjV@ zJXda-ugQ;l#F0qx(Y#9L&i1xd`k}5rZ8Cm$wSnK7SO;YCvhFpGZEiVuG%|vgO(w$l zXz3DhSVoxl5g6x5x$ay{tZ6n@H-bDR2OAeUKVssV`SnKBuFbN_-VojI8BEj+vg zu|10;(0(x8iR^2^3bJXlcy5$)Q`eE1w$$Ri)nT&!g^QdzCN+N$*{1i#5z`n43#nov z+=>t^sBDRM82WdJJ*%BfLPJoOQNp%ZMZEgK3^Aqr6$?9=&6R-c9lAvtc~K?^$;*n( zPL`mWr){ml{ZV@s<$@dSY$#=}!^!3JrL` z2Mk3uZO;D0+^;$(q8(wKR=`zf$*!s^o#-Uci^#P4p4rvCd|$gL5givh)vHM8yd1d(|PI3?5qH22K!uDx)K4x%V^k;6(jSc#`tFZUsZ~KA(fi1~e z4@S}91>F);UiqnamcQ9pn?+42-%TLYNLoP%>^~35H)njeCp;k(3lfV?xnZBq^APOx z8En^Sq*JvL%qjwT!zd*T$>E$eqz?eoDc{r5H|bbbobo?YS*2PSlJX0sUt`hhP=g8c zhp0fN<5u>}wRxn!BN)9V^XvoSBm^ax0%F&0!lXxkDplq0iK$S`kz<*3iIAjS_>c2- z7HZeD${fv!)E@!Uo_1E<_8*R*V1xH-SWP^a(mN))PonP5c;qL{ID|VT+d`3?i8G{B z_~=mEu74XZ`;MF3E-(I|@(-1z~EA+fFU>D+tQflZ zdonL!nyWrp4ve7dkkUm*+qt&Gt3L+e@W_7CLz}q5e}L^dZjc~U_dR!dae5@FEs<8i zpotxXidL*T(IUK4lz#R8SIb;2c{(>UK&F1eXFS34!xbq-ia~_4&L$YxP-l9^|l)GW|l-o?1gXNW;cFt1M4fCJn*}2NF^P^$RQt z6=g|z<&S4Ua=&FZIhZoXae#cKuVSgwj)LsJiKrW>PNu(vj+h#!*y@USccy6p-HEjZ z!#DIk0zzdT9T!^$nwuj)u8$sCAaJ&;70Y<=emGOMV#Z4*@3x+~ifxWRiegcQ*fu1f z-htWVkZkNRQo4`0<}PpK>oBwiqRquUN1$nQ;q({JSn+(=ai|Ds`B4&*SQeuq9=#8e zjwEsogx&;)b0rT6rTu$Qk>iO`;veIaeURzQ?bYch(<7%`zhyXWd!3f11={V0)1*h( zW-(^2K*anWW>{`Df6f4RO$fi)+h)SC7|$!uuI%2vrFB+6r#d8}JQZiF@B6z<2l)2o zulPhy_$3?FzK}`--q{INX~jVrZ>O<+M4a`pa_;JvjNiBZP*_?IPc}!UjkaJfDG+7? z2+!nSuio5nlm7oaa6|*Q(gOu3C{Z~+I(j|s9>?v(u&D`7ioTLx9 zr*Xd}|0C+IG1GFl*;wP7Don`Y+k8N9i|y1%y(zTU_Mly}YRTm^Iyzd!#gV}rVSULa z=VZV>Cj4a6XLD)YxKn@Bg^6tMq!HJg#C~l;>ch6us4yC4kpFV&x(r}}PqAc(5T_5i3I1MMbTF)h6X zkzzbSq+M~}lQdfm$JernP#T*$)m(;nKKtW1E9+ zr^L01Fz8Tx;8P_U-%aFaixV2F#8DBg}#`CR2S zF0J8dr6fXsf2VVXDHUQ$5a127G?RA|rzK#r-`wzMmBG|RxY^;Qs61`Z%#Ar=z_yv{ z{nVPKtQ#@Lmw8S9BYS`UBl#YgE#%h{3tE>;^4SkJw%Y_>TSM(3##O)KR7;T&U@h`> zU7*d59^D(ISWMGVf1cU1VV6wBATz6bvYs@lyl2PRliZ zMgBH^80+AANF00*2=Lm%jBw%cros|Mek9?~d9=Le>Y5@RTbFh*$ALUN?+>hnS9t8Q zlw#wg9GRp}c>!}K#zv;&5|G`xx)yYZI7%5o zoR~31reGo#d3>2P9(z3(QGG3|5Lk(S{(0jr%X%1)^W=1Kv*wfNQ|h^YBI@C$2G-d0 z=yKV($x(gqvAep~FcIp6IbxUUk>h?Jj+K@@K_n}16!X=+kB&76`9X2$IkDk7sD8`T ze+VoO4v8Rv6_$w1&vwiSX0l9W88dlJS5biviwUW7GGQgNa%Pub=pjPuN z>*7SwI#f}-@8^E34eTx+DrBlQU@)ZAkT54eelFk_jJRiHoi{#sU)URIwlcyO&6Uv~ z61b$(30-aRX_LWwhY&5Bqh$F`oxoXo5uV!J~GKwJj>F=q4s^A zhvzei-7g51il9o=1(!6fy@>V#rWDmSp_RSu)74G-FLG)%q>o4Ez)x zQ1T6{?7+_lG8BpSI_mG((k|8IwjHyJf^JRw=IZvD4ZpA8JUXAFPtP-jPtc#5eL{vR zz^goL)OO%2Y9~7LKY_%TA0NOreBfO(`Ra0RFdO}Z6E$}-d$MhQ?ke)TU41JdLW-7a zhlE$CB zafvoIcoWy{^X?*(JgibK>cP4Ur&OsZaePq6fuw+-GXW*if>pVbe2$mzid0$JB&pG~ zQOd91L!HZoGwLz>cZ0up_t5Vr!V8G{*)qCa=zUkQ-?>eNF+J>|mzl-1SQBw4Aw{4| zk@W>JN5$R3GdIDWd{7s8j>7lB+Jh6k|19)M?F!+I5_+aki_0L%=zz}_c@M&&5lA~R z=(!e^+WyG4bY+FS^I~EaTpn}b=7JN>XzbSGqj%Za(x8k8@?^Pj0n^r+wESqB8xO_p zSSUHE-B0?F><-oke4_tNrXGK_{~7~s{T|2ku-x093nZtev&*9zC z9RdsWJFUoa*A<YwJlS-{kpkh=TT5dFEdux5hJb;LVETN%lkovc|y`HR*1=u)FT?dU7MMp)XOMM z_UxcC$)f_H#TsF1V#wA=cI*`xRdr9Q7G%f;d%b|DRL>K2AwB+%1S-^|vKDBt0xv~? zGZ!bcCjU)SFJ#bO#DtrK3S)Fsv-%gz*KD{E&ujXGK}*IEZOGLTYemw@Hgvh#hhT~7 zv_=H$$u#(BE&E_iQn-uARk!dja_vjfHCPUXm{qG2Rr#u?YKCgAwoNwV*fqtKTiVn9(6-9v0>>9s^mS{3vtEqylK&4fluwB|MRL@}j-HyW0lU3!l$sfY zOd`ZDGBV+Y)%#Wa0cXMWa3WTH2qU<2mQy7*totEbLmtv)8DU51M&(vMcqiu zpq!K2O14J2ZHOOr!oz8x1^uujVk{YKwTM8wX$dU;UXlHY6D%1QGD;q45pJ2qy(F~b ztGoY|G!QvTL9-;!n)j+TQ45}^f=(mDIqnmJ^gR4nG$_;1+~6%KA;KgIhrMa=s; zI1~yuOM5{{mo7taR_N4HMJhZnQOW+9i{!qFjS7@yX2%&wldb`tQS&a`S$Vw4)GE-? zs$|Ty1Z@&=wsXRVJaeSszabg&zH5Bf`X0o9=awxs+2g@u?lvi2&i~cVcn9ZQ_$|%= zdbsQv15^!2;5q6pob}iGnJdswboI(gEGy>MI=k8=a{nbe<;db%-sZ1$MYM9pjP(to z_aOW!pMa+^dF7Ai`QNAc_S$?A>DHrO+qr69C7B>@%U4y%lCm?I_a#LiuvBFAs)cM%Yp;_nGG&MF)k;tl1IcpK+XVLLu{y^XT%C7C_Dyx z2Ua#rFC?{i?#+4gKukz?I&+F^DDxmj(2AexJ~a%jd9u@|DoxEtGRk{sxwA*g{7xte z&F}RzExJwblxOcSu<6fB+l+sOkJpmGvrGY(S}H9)s-tWfUO2QeW!w-xV;x9Qh(JCR zF;yB2FGP9~rWUdTmT^*3D7$>hZ@uF0C<+Gstawn7uYGSAF?P++mbr9|ejOS-KJOeY zZ%&TK6k9y@Z>KL`lvwNp^|`$uKN$=?W7|)UZ}N`W@wqxYMV*u$hq}3S?+cx_B%?RkkWMXOwr7YZ+G8BrwU8*QiQVcYE z8c4(_phO>(Y^&456RBjD_~Aq(&|2J(oR!7970RMsoh7yluN|$h+?%I4mF@IZnvTSo z#S&MYJURN4vw&{WXq5%Kl54=1v?{TO8f;ibraV%5)OhS|DgQ=0KOJXY1`i0HXNBUr zM%SK&K*3qGU-?0Xzm{8uJ4GB<2}5}M@i|CZwLi7}e$&J$4h z?i3S*3PxO_j(?I_C^9j&TMJH8b>wsZ0ebi{cake96-ZOx@YBdOcVe#8em%`7HB~65f*{yenC7@&=fy0oALu6+$QQkb9A3cc zHx-Qk@l1g@D(F~TDxin9pR9#@rD+Kc#i|W`njyQV?ubn@vewL~ZEWNtg(u~u>XEor zqwyUGN(bG~hMXHIh+McoLZdgu>H@*YXUO;A)uj$@-HtHaNlx$aklr6TL3HND@ld`* zV-eMA_1upAto?~Ou)Fh142Rjuy5}8BNHeq`l^R`XBxwVLeS9JDD5GJq%1G1>Puh8B zho#-Q-JY>s7Xjx-U4%-^@RNGJ=O}_I5qPqnx+9-|Qm;q3Uz!`jBdM^Dx5Lw|+tpc! zbbKKNZ|n7z0;I0bCKb;1g_vC-PX>UUx$kzN7|{Dy)#25G5ZldDt;65$ahB@bmGecg zD;#2D0ZNK&;u6+<^tk8D@N&~b;ITjr#~&Rh3CJf`&%(QC+_UWb?4nUYxfo5dRPw$g}%)?OeKla#5^~$D2}`a1x`-Z z__6HTdk;rGe9JAH?!pOi;R0{?b0gv7y`)Rf-rm#Vy-&tslX`I^qa2lrPPpiMf&Grs z&G?H$Mo`rXRv6Cr2GJo~`R$6UVAU68PP!bw3WpLKCXVb)&P2kNqjLc3oJsKJ0VVR? z1RLVuL;C|vdtf$ybo&Nz_68wgIQ#^5Ocb{3A}k;N#$!*5ElvDEY-D*~8}`fcs`1KQ zOV3z4w!+yX8%%vCUy-@a4(6{id=7_mR$x?l<-`!qpqoR~+kjU!0$ySckceK|Z0)8XghRX^#4gCIhWLX zo{E)o?4Y*+M$)GSQ!;F4&PDxexAbNs`W^_GQpfe800LM#p$R`-x~dP+qpJM)1<6r6 z;olGtcZoH9l3Z9Nl!|EuI23K$>Lh0E`Z}?Sl8~4r;Scy=TFzCU^yyG=y0=KK z!ZGR5cp2kq77}05*0R2SW7lQSPhMl2`-m#gj{A!^Sw*IMQ`VqAl8cB2l9U;yrWIZ! z1R7anIId+CtLEt2-3KntX}ixi+{LM4cD#XpeJN#{)iU41yxi2b|3Av^DMoZC%met? zw(i(-$F^F8e0n1v z86L0T8YJ$XXXv)>_s|RvbZwP(JD+J|qQ+cNs`gB8AbgiIFkX*E)r) zo!=9^1^343NR56%`)t_mgY`nUq{DrC$nAkee!b_Z$DM-BJ~54OxK`0hp+8S!5RK(_ zFMjUQx_spt#k?6Vj7FWUz;~`VFM^x2_amnRv!ekQd*2nJ7+up7s8nD0S9hnhifqxhu37UQI7TF+SN(ifbi|M^S5iNUj zN4avc3yv=8V8-&NDfP5I#x`xQV>Z~HLp61)ngNN_Emx5euN%BAoxosWAv{*CjpcyVpiJ~p0 zSIm{61z0YS$lK8$wN5+91GtytqJmRxKNOo+o{s;*`j<9%JTr9PR4-j74t_p?yt`73 zdjaMRQq60S>GJyaPCsUB9)g+FKBPYmHy~&RD5o8-Q;Gd6Nl;z58Q}bn7jV+v9d-U< z*Dzy`V2pu)E6K~4m}^B7mBbHoDQ1+9Qj%g3(ZViJj51W0-V;b&8kmVQGfGRlsixJT z(m&L{xhrgK9H=CK;Tpk-yH_tfXnjPVM2!u(o>s) zS=1W8Z-$(2_}8{qHGF>rgXLvx3n6`x7&4*@UFA*d%yhwR+hiP`yDMkZq(Wx zNbxw|6bofD(QIWJLUa36WpE+k2FGZ;QO-ILivQXhv8K?2L;fi%RDs#CL<2m;Fr|uF zNzOm^Q$(Q*G9@-~tP1g>oLmFfa0ehAEC3~%-S$=An$Y3Td&mUq2<=H7P6|nv{vye@;E3x9~oaok#>WV zyih)328R4c&}ogUZb;)1@#w+@c4f;hS;9tUl3CNABv40#;L8QY1;>L3TAf>`6LOJ_ zL6Q2~>XwyMifU#Xrc(%-_dfxdqg8M;;M;#s_IU=)E*K|(=~^uao4cD7+5VN>pU5oB zDdsJSpm)pZ6Uj&dJb|baGUMbi3*b9BnT^aJUTsAptraDRO{XCS=BA3_TwTOkJiiKu z=awKBZ44xwym$p+Zb-NLkqehA5!1Q+0C7^;Aj=T(A@J?&XtZcP-oGHSY#&?e830z# zF<5>cLTD#*!HGdMh0kW`9Gc(7pzH7i(EnmTVwD&wU>1+a^EG(t^nZQBm$=O4IdeoU zr3C)^?bXKH+xu%g+e>5e9JpUDgIyE<#gw4<8sAPg@=ZQm%iSOQK(H*CcIG>9p~z1b zQb0LoYAy9b>YINT$I9ZQT6)aiD8Fv@T&0S9W8k1hI-svy#c|*{rF>wFEpHK!cS)jH z9@?}r9hRPq<49bXQ<5Z&cOPWl8HBlFTaI3~?XHxM>tL{4HqyB^3T_`O&Wm*<7Vso8 zPx26cQ%2-M8jRb$?dHhkw{crJ5~?Nz&=cG$7+dqv&xu>@;kPsC*C0RDf4)RY>FmWc^(%+az=~G=2_^*o~ z8W0mgWfeLloMYD)hER9x&@tMq1Mp%0V=%|dkZhMPPsV+m)gRmQJCLY1-X(6etwGqH zBpwr-fLfy%%(qVG!I*ZR(<#74&D%$RtkvEahnGixq7y0+N!EWF1ag+={sVb zm4|Gif5MmjDAq^Bv&gLY+49d!IWG-aCmFso%&()-OBlX6mDROD#3R~C8E80ehfmcX z1vI9|E#t#*1n*CkJya5xt|ShkfC91+mk*h4dl5Hi~&whbJfDq+lvb?Gv0(Zv;Uc{+dkh>V|r7=G@#|0pe!d z*m4@^z68zoiLr^puFqBzI0;D9sti%EcM~HqDPPsEXa&o>{L4@AUDFulvQTA}63w8M zgautX<|w+x@6J;VixK~*p9kv*`na2v++tCVo?w?@dam}?#h1AcHS3x4ob<!+OTp-LciU!JUs(P&DMFzFfSp9&fy}9 z)|5n)sQ7dZfHMHoNFN0*(tPW0km?&XH78|0K&vmUteA93 zEQZj^veMl{de0k9fk#Z|5Dm`1n14T z8*npdH;^(rh~o35@+O5uDx-^t50V%g)?K>MgbFMYm9AbHbgt+v2~7`Ss6=_hQKwmi zVS-IOQ9)4&Uv*RkE;EGASu%#qZ%RNi!Z>~tWJbr}EB1TcyWo*Jo7=`KPE`hV;g;t> z$idU&73Eu18Ay=lve6)_GSjWcBopfW2xajBnlr@-AQu%l(`&Z=D1o+5;l+}l$6AD< zy=6)O22IX7xy@#@Rm<`NO%oXinC8tZ#&)heDk7NjAPZxegz%r_RhuPs5pecH;o^cv z2a^}&iUzY7(3!`2BKjUDf)z@{-%Um{FQFfu0qGBe1U)eT)rD_vr`g!~7wCc>5DP5& z^&z22VIfvkO$dlNh3w3^awMDi5#)H%MJWcWQwwClY!qK=N5vCjk>r|W$*gKVQz_^R zjmbs}q?&hS(X84ejTyZF$!mcX7U4ChO9V~K*oBnQYdO~OQ<+qcLa_v|`7P>HwJ(;3 z7O<`*&09Lx_H9|9aV^zGwlqL29y7~qjGifSEAIQmoEx2#?o1-26&?73X9Y*1{Sx9s z@z}%*EXpe2VsRgTrHF{05mKoh*Yd5VD+cM}l{%m;a|f3_Ah})uOI-W@u^}d3BzX4DH(@t^$dVGDcL7%s%y3tMpd%{MFq1#ezqFQh}O`#o{*`g|Fm-j%kB1}2s;(_cN~ju?5?dUY_Y&PH5R7IA=}MNYv}u!@R=F0HyNmKT9) z3|r^7pBhBQrK?#yHtcTb^6|YbAw%>OEosEE!$*mDUYa>4V363@pk|CKBfQI6s5dMM zv|*ts@62P{abkJ|N`T+@Zwf{{2$&rieHC2rkZecR6n>fVqPS38<#5to+&KgM#xFo7t6bR?5r57hm zw!0;j_*@Hepq`w~RgFjrKOp%PrKc`=?*xS_vH_P0J;W7BW_!z?;cx|6s6PqZ$to0A zH!qU(2e{?-&O}HLm}lkQeG-Y;rn;~}Uekr~7Em>6Zb{Sd0v8T2CLE_Ct%TS0#2UZ( zjW$G*QY|^(b(KPdH%L$8pU)&8(e!i$8BoN~Jsa=e!bJLAk)H(2UtZq5OE|DfXKZz#-%7Cv;c_U zz<8m>i;2owb*h3TA9KRwV7BG-^>~@SuduuQ4QT> zKA5YNL;XUP2wx&IRXtk2y~b`1>xxV(gv0?(60oR$!kO7{g!lReYSP$|Y1C0HlPV9w zP=p6lC3mJNGi5QboJlpa{oQa`F~uT32S-6#)--8l)+nOn*pGp{xM|olhUWQaYU-Jr zg@^{SgIC()96yw|ff0Y~2=}dUxhYAHnrM5LnG&;Xk0`lrzzUK`Yt?zLQ?hJ7P|q8Li{+Za#{7j%-Bt;R5!EhOC4ENdx$rISiqAy3wwxCRB7Xa}a}+Ua1^j^_54DRe>)X^-3XO z8m{YNG}Hq!l^AV|E3Wt(yxXt-o>&7tM|8Rd3X0HT^{6rVaQlvu*GCIR0JM$*OHepl zO4sTGg>f$qOM=rvZ^NFIw+WJEgl2Gnk(m^ij3t_WT%==XGOod*bMp+2>=v6;5K`jZ zga+G9*6b@+;}YN8&w<-g^iQBSOo|Yux$fFUd^?HT$PHe$aeDo>br>De8m$t9ocfyl z?(7~byd_Q{4z61<#w4WzKsf-*ry`{+Df<+D+b8sj$Rbd~1jrWW{>>);^H8ai5->Um zhkL>r_XQeKS^e@1FHpL~izqw_dx#ZOqY5!@Fg@r~PDW*8$*KX$I3<4Wx)TK^L~V(3 zgLXL20C4I-Xf1-#>M#}2dXtwv@~8LivdRNvhCjH)l{U6H$+D9Bh$Z4<4za_A21_cY ziObJ-EnmRH=mXp_jehwZ#%7^^2PIMpr#21m7B(c%l!Kp9qi-iMvkbymD`?5<7(EN1 z&kKiG{*0RVgXi^UPgDhGbS26bP7D>>QsW@m6?2pnMb{<&w=@caD9PgRoeO zu(`NA=Z>Y#Wq&gWYh^av9#ykOI4L7lT@sB}T}po*8hQ*FaCd7V0X;hWl!KS<(#2dM zdY)?o_i>-dQ^+cbW*<{^Q1plyB@oV0W=(mvoWT}0XeiGXg zT%_=tSp&EnJZOa5zUU9m#o_8vpvFX&Eo8M&nVRLjtq`U10f=>mEYq(TNMnvL8MZ3><&!fo2|p;|gS{IR4m`VJy^xSVe6 zZIIfd-dhp>0Zg6JB`Qe~8@|zPamIyzEU29wz;19+R5oz^@<5w1KBx2O( zDlqhyCYj36y{nr6ZJC)StYUVd3Q@xbhQ&s)TogsWDP>qnbynuKY=-uCTmn-lv7MrQ z7=5K@ZKK854iV7~}@qwpBe`Aa>F91p=C{(T|{a3^niYr@eP*dV zL4dRNbX16Z^t%Fk3lRSkZ->ZV~O&vhi*V!R*wDR}JEeZ8g(r zY=#9%*Fj$=Ji(UJv`5}QP&b^@v$dYk-+9MbwyU1sy#*}axrC`(lg2xdLu{rN zc!ENFjP-&iyB9F)XhxhdK4)N{P3`XTqr=z}I1nL$wC!Mp6afcMIlj1I8(jYx}-XJ2k*3R3!Z4N?kl7*bkzVHr~To;IL_4SVVZ zHOR(9x;?D5@T>Z<^xwI zkQ2l9sxvRx_TzVO28puA5v+?x=1w0xF~BrIlUd1_F%{2}GOcfLauLc(-3WCRmi^QR z1vkP-X!PV?%M(rbX4YfWnBR&3JL^n9n~hZcTTuReVzetDIcqK4gHw%%Oj zRi|=EhSmraq!Jaa^eXu-2gLYhk|%6a;7t3VNQ8~e+OX1Dtwot3wk(9SD!#=pj2s^W z)Ezs&(a-2F_ZTO;)v@QDSM%qMVtSZ?KZ9edlL-$A^;`W9My42gP7ng4hf>-S{aR1c zC$_S%tlI>m2g-t@1|~=8REAI|;4rr(a=9t}>xGGavPk_GqkKdh=7sB2-9HCfA9FnA zAZLby-bhY=4X81+XL?fxc@Px@>ZK^ea2KV+vY@8+QTVdpIg}HU;*; zjR&gsJN&z&?P--jxyqwT@l7v><4RWxF=W%eFw2}_ZaBa~cR|j5AZ_=UX06k6 zD4rhUx$|?cNo@B%8Q8hOPY=FazD$kuqYHE?E&~%37+W(apuCr9#Dx0QN)t3NEg!9z z&8myF#AOlfvh_J{Oe*xg8o9pCxV>z#W}YnToPqqc3oIn2tE$NrneGH!;OCpOgkT5c zLrYt4`IbLbyVmrtiqdykNNA>`tg`H_hwSh(bEiyz)%A02U^GY6I%N=!jaCF@0^WY9 zReTCa6|jv{8~frGowYxEia!|_p94Z z%ZKxV$VP-2&Z!_12Mm@rZvt|?F91cod1bDQ;Zj#}E)M)I^TxvwDrfy_NBO#h$L7jH z6nfSl$;(Lb}tAUFPLaF%VCM$l6g zGa0t7;O;X@oRJB*Lq|fnn9ZUZJl6nayor4rnGKsQdWNxr*rB*@LPRf-23M)$2K<~#%T@1Ar(|sRu;YuNH6V7Yj@b%Ub8zLi`2o|k^MXgR zkoS!Y2a2@-{XPVk5{u`E=Ry&eVel|QeLz&-917Le0iO9uzdFzX-rN>_?Q26@6zeh$ zDLgg7`!;MTcj{P9C4?`vr$iJ#8hl`fjV6X>@`xfP+2F0Z?ic;8lQ|I{H$cc*k!K_e z5B)Lnz4rJy{dNaR(q^8rLo>n1#qmHHUXCn4v5rqW92yl;W<1iM_AkdKo{!Z{vC1jj zIW%j@D_??#3+qkHhe!XH(Enko^|lpa52^J$#d@bZ{xz| zjoobX7`;wV^Y;b@*GV;Zt3Y(MGMBE~_=~rOBcXbnI1&P4i8og8_3r)*@Ja z-^6(9gZ1J!#gFU=Z1+ab$iy_ep|;A>Ue-gC^B>(_^cH&b_BHzt+7H@j7p4!W$hFPXiynY_E7Kej5qj?Rst?l4}yCCl4hw5wh&nd~9Ssx;h|JG0C`v@E0TsH;{w$E{iO53Q{d4&WNB z=a!HdZ@3ZTg|}#JMGNzo`h# z6t`*fM6|kel+~${=CI0tb;bYgk^g6--Jp#n_>uYn)7bOC>#f(CZ;RdX)7$z(Pr6LYtQbB_m1xE`rG3R zaaQDUiX-Ay*+Bz?;j`yxt7FzT-Dq_MB~_zTLsdI{^5IQy%wgO2p@hU_!A|rB^uJ7e zo?fqaW_HJFR&gA3lb~1YWapNUvtIJSJTJU3US;c6Ws>fH8Q6QQ`_r{xLQc13zJOkE zJN?VfH^Qv&u`|K%JbP_JfzB<$u<>t-_!KacqRX2XSDsU}+d%)05w;ihtemK7?b+pc zS4@uv@L^6P4xUNydYU`$z|pboap<;06XCP_Z{Y)5WfW-0+YwiT@B+$k?;F4;gg?RG z+3^c77iNXD1eu*Z2p`yOpn|o8UaRUHvtlA)dTG5#hivtB>onW4=)~Y-qa$EO$r6^a z-AHB9v}UwNF}?K>Ybl7@;0bjOdsgm)E(cx&f1+_xB2G+zp9TpH*<@J3HHq1xF5&6H zLLKcpiYamW)tz3-?TAzJKSY9^wFHuMf(zUB<;Up&uul)R<{}a^q4P5JL+Mrm<6?D z#qEwU^Mx_9@Jpvz>Xh=RBxohWd+)XeAl0v;`U?BjDiR|4L5mhCRfflGR$?cms; zd>#WO9mgI6GsSB-3FxfE#AAaSW(-E3G63p``F3r5@X_RKR0P(>QxR`qa5it0E#xEW zpg$se_AjbcEa$Kw6>rP6Mmty#&52BltnnRh3%Rl|{y5rN$CXS&rs%Ur$JI%M{bx0eXen)W^}~87HMQ(_laF?5n7;@&x^fj zB`r#41$o=t&6Y-=z522$6dCuYDyRF+GTH{w{D6XPx~ z?2(pp-vo8$G|#g6*)nhBqBct@b*7&@1gt1-!@gHRDs5bEemhqcwm#TeeHD#5#t>aq z_|ck+$u`pgBA8KwO*X%3+PNq$*3S<~9zYBMXbBmU8> zfwEiV!b;8bD6by$&NS#=MH+_AH(dyj2>)s|kf${nLKkVIjmBsAjqVJ#>T1kht)wDH5#urm;pVwtBd{xG z^XIzLYL~%5FrO^A&SFw8S~}!wL_jGJ^$J=Mg;|v4m^|3U)(>Yf4BUbZ{Y0*(^Ido9 zY>vA3svP!eqU1i9!(h8* z8&_H;A%;7<>9I{9J+u8}TPHhwYtH5r_XPL&_*Udr<<@T7OS^1);8yEa?3VZqR}*I@SnT)0h~7Urw+I`n}Z2v6QC zxiwdP-r#IlMLydw*jwBk#x7eojn}a|`h5d8`(FiDeP4N>dB5gPcwcgmdtY=savP{(Y=ytZ8gYO!4R`enm{Ph|z)n zC}FIVP*wET8q_`dink_~O?bgn(uS-oEDF8z>uNx!MPNxM!rQ zf_z8$EpukaU5i(p`gr)H_{jM5@Cf}#^^`6zp)yU<(xllqPPh4@wLp(|x1WhJE` zB{7wkW@#`oq=nANGlJx38O3=LllEc2GQ@@b;4)=OKiXlx4YMucGI>eroVh%`etl!J z*~z_neQg8YksT8qbB&sbNHruA(LB6^+sWXfScUUpa)thj*ycoBhed`-Mo30uBc|f1 zqNw7!I&O8fZ64l)b<)}xZW-EF+t-eCqyIX!`)#?uPHk-1EqX4hE(R~NkIZMo>&Id1 z5bvKKg-_lC-UwcdAH&b{*U4XTmKzz27)EkTmRyWnCN0BGGJr^5exM?#8B!D3g`_L~ zZZ{|w$!q(tv($C=lBee*dfT#-_Ohqu19@Bb=G*6`w&N!SBV~<~o~oYCUc*57AYjN7 zxs{}a^qc!vnZ-k*eGa>f-!N2)Ex=v$T=V>URbMhn#I51kwS2gUE9&W%*g;ZE5-r|A zP|h%(-Na!oxzH$XOYEKWXuWWrgUFre33uymJzLIA<;n8YReHLT<1owW>9h49Hp|#e z=z-}0dux2b+@4y!8lYq8$vuDhr1Nw0)o9d<5!02v#Ut+}mhBpqLC`+n)v)%bpwu9_3d*0pj(y~+g_+9ie&Li)w z@Nx7)ajUp(s+{}Bd*|vwIhXgH^!d+xYuRm853D!0x9gL4=Pj#uH$^x_pdysQNa+jR%Qm*1`iH;PsWTZ4>QE>^Z zBz7_jOEsOfKnBV6O4FOUw0Y&iN~yJsC)2N23vKTEpN8#VQ%h5!x#=PeW?^)9^k9_w zZ;>i99Mdd=EaNJs6-;!DRLoTjJO&=~&&Yq&hrLnYQM_2P*tD=wm}VGjwtId4MBpc| zOz>HBb{l=z;4^q@Tz1QS;9xemZH{?dceKE}xUc7ZM8LAJP}ob3bAJ4TV9{7iE^`0! z!~=h)N~~uw{FY$WIFD<2=wM&obKm^dfiZ9#oM!|0B-*(I z@BNM7vv^$|cgTUdSf9^(E&Ze5xqrOe#irtP1V!K|uo%q8rU)EE+d}_hHh7Gs5ZuRc z3qHfS+m4|N#=x@kGMSU}Dq(TBmsyv2o?YZ?hTPy#!hcQ9v4;9^J&w)ohT0Dzg<^(6 z4w}GK;V)3}Secxe+?6PdpZ!v$?>}Q7D;(ov1!H4=X zer|=?5WUCliK4`&u^*%$Did9Z{Kc@p4YMY~#jCd*+Clsf^L=P@FRxohesIudim-LN|r6+cWw7M(?Z-xB{sq#C8geg7T5DaylrpB#T1 z%|&;AG&Y$op8gw2XJBM}U?`qyn4(B;WTaxWWI#8n8S7$w=%14Q#eI3Q-?UCD(?1w~ zlHbfv@~7|^eJ8ncQBzP;ml>%@EcMWGnOP(!D5o>BjHf#&Dj6zCE9ouGS1zi+8*#@I z8g-^Ts4oYrh}28p?0U#-j~LwWJ&x7Y{10E3vk&^pr6G zpsBKNw@gTQc6TnoqpEJ?tw=ygl2<9{r!Jn<6x1a#Tbt%8SZvDZm-pg!;!zrJ*Eh;i zESr?tY2{Hp0PV3=nBxW?el|}%2p&>qJ3F(WZbIVXl@)LR#N-+}Di3n@Uzb%kaFS>B zaop(TLM|l)4nS5V!ab+&**Xq9#k{S8Q)c4<*q$u~X2{UVsJPew>N3t4x2~>kTvXyD zBb(D$P-Lx9*jkgh5z3dO41~}5P6+yo* zetN)A8```)O>T_mTrbTExhbma>L~ZgnO;^>wX}5LYRLt-kEOV(pi4vH>hIgxh*4raEBilWH6DjZpAUSwBb=rpolKCowsaJNcVn7vT{ zi35bRd=LyShS4vTbtkF{umH*iL?~r6T_W$P8(L>7UEzrlk!iEqaRH?XrFB}Ot?T5w zN1KPjx1zDV1met~?Jn@bwe1B;olSL-_kgjz1=8%3Z7cXx+p!0&iOZc6J}2Cn2W?5C z?Je+vyzK%~ok(?+?|@mEL0!9&|7@DOUtjOKgwlfJt&Uu1@2Z5pGTZsh)p7NlLuv8Y zUKc!K^iV)>b|+q0!mKMeG(fMHnsM2iF$V|xq#Ht8byg@fSMJ{L8Slfyq$Cn6Cvx;3 zf4^t>kozrGK*h`&2kxE>g=w-L}r7g>tO7G*G z0(sUq+Q89Bid}Y5>v6KE5K$?B5#7m>p%F6G!71V_LBbHD@FUlF_;QhqxZk`0B@gVRp-?%kOQILuzs9SQU5jjpHotrd_4Q6AF7suZ*v z{)Ek6mw1KLj=}_yBeJ5p(X+yY!7q}KbA$>+T*tQwplA0Ih5#!=4ZxgE4br=Rg(Sd; zlgh7-1=L540(_!N^IONS!da}vkYbsr){{ci)xeITIFY;zpeNDW2Q%a&gAqykrx@^& z1nhMTHDdHo9NnLWvxB5Snc50QBq5<`n5-N(em_v_$n z+2O`rNtmam!fr~^k%rbnAtt%^Y2}yA=XWK6R~SN^9vwgQ15aQNvWDtGz0PHf-Z$r$ z3H0!wD1#&-F@U-cdr6zMAnnW#=SjYmP_47VSH;dP$K?*nf+x36s*lZ*ICoq&3HYce z(s7;)f`sOc9Nihix!y5Fj~}1v_+wAYs%c%@v4-U7bG!P3RePjRyP1KKcsW8qF`d~j zyI2Bah4e$Ne|FU%JJf+VdV-Q28HCp$nXOXRvj&8#p*HC7_v&~pHvz3})Fd#W4J|4s z*r|3(C?JZJR1*8^=v`LalE@W7bDdqVu0`}QRoa87f>d})uR^ld*}81AoxMI+l0@G$ zZSHW;1kv_GKtN1uo(7ko4WM}@TksR=QbVHPVbo32*K(vO^VQm3FaSP!TA~vJP4|>j zIl)<#X|uvo`aUfu+}nfqN??WWR~Dh_wbyjeqd_|-%Ry-Hg*Aau<<}$E^s8J}Rn^oh zyUYMT1K6>pMxCl$+57szOqXDS<$hCG} zOkuyf;-WWpidj3;Jmb8y|%~lGD?3yfE!0{O%c1Qy$baWS0 zHABc!EeAI`RaUrvyRR&Y+Rs)Mr`Vf}w4zDvro?~^(NZ;2Gt+iPOHoHZV^A~FZq)$0 zyrQIF&uDCllOYXUa9}PqM>j7tuXk>t5KTRvC%o*)23iWPT?wx*o7YMgt9fTXyJ>jK zC+sDo-%}LAA(@%?E6@<_&d&dotG~!IjG3H?NAi_c_9+vptdIbf_+(aoBRKPMp-^)r z8Lr|$n?0#qaue@+7?lVaT26#_SX<}p-w20zp4ow2!U=?hP%wuX5>=L5D=|h@FyQL2eHj30(%#?zL;7d{6UK%C$QlOPWzljWUXItBrAK5 z0)>TcZTAC=muVWlJ-}{>I~7a{nzWOOjboZuClxQ_rnY(>UV1fx*#dy`0?z37;ihDj z-%ERCy)Ahu0rY6RM{oo3G_7E2pWQAW1d?M??Scp2hRURx0R}65_hwLjD{)vE0+ujz ze2M@{v1iTinE{2UN%nxjs2g@@W_>URQNbuPc^ha7Y=Trha=<39<;Z#4Fx45sSagfI zEo1Q0OBHHGfQ_H#(>`V{dR38}+Q4&^I#qy;Uyr(1p%uW5hqtUY^wSt979`eKdP#Zh-6r%0-VbK70~?^6HLs9yo2e}^FLyIwz6x%o8DOmL8xC|>g1HY@$ak(oQV^Nf_l}T!u^*~s@ zr>A^orebOacd+v+Sw=M(+EZxsjrn;4G{!?>n&QCv>EVvYIJg39%W4zE{BF`W$Rz323i$B*w+7z-dN&>S6!Add7il@_tzeB%_w3zl7?eEvlGlg+3L#alf=5@s8ZgRVZ z>WPK6xl-rCneEWctwi?h|4fDzOUyE{ge z!;wU3-leDWY@Ar)_4TV7+O0**X2!x`->H`M%x(OhRLpIKK7qhh_RW}7IIuI! z)%l&=jv)+Z%H-Qe{(c@|lX3WM$xX1;*v!029S#ITziFTbvu3*)>RVUGL$M0bVqMeB zt+^5XtrH>2vFe+SKcos=$d( zZk`c2BaWK92C4x?JPJ4y0Kd=7#Hy#Y@UvmU;NPy3}b!NVqSZ6 z<3#9miP>hJyKpu!?4KeHt0CPoKM<*eDTEOQCCThC_&9lTvG+DREy`B|<~A z$SFir$2+OtQG;A+?sxS`oScWKgg{p<2r!DueTH3RAb6(}GLV0#d=Ylj^?xBbTh!g}MDN+$ z`{3xZ?f(EvdgJu^0lT$v!}EL5cKZQ*`-a>V-S@`W@g4jCJom3!F6UD?bmji{(Z| z@MBOz+ltzQ-Tv1G-D~$G;U8Ij{M#5DVjsf1oHER6bma2z#evhm4iIfu?Sh(68u3-d zRY}u1>N(Ym%14(ktuHR`=AHc9+S>Wmi_6C+kJ27~-_CFPufuw91Nf1g$lon?GK?zh zH%3KPLw|GL_GSMgla@fo{7+f1T0dC7SU-86W^g-XIm8p@1#1Q4hS3e?1shjvJ??(a zuixAk@6qIaa!>_cmsJaQhoQ^*6`m-O;jot8v^Vj~#^ydP6*?w{+ts?(a#Xu>tZDVJ z;+%O=SGqQHhpyZFJ@cG;aaa07>W8k|+GF&w<~+CLMd~(_hwf{#Y4_1~F|;IB3NQ29 z@O|j9{G4&oS2{OyLrOOdE)6cDhsoQR!-&J`ed96uTyqg|(Y54Onl~*b!-we)&$i1oA*I z1cAaFq`W{=9=bu0jX)Iw*$_0OfGdIg838dQcd$+XzZjYaw0BUCK*XHv87&NgLNHT5 zISdLI2n6PU7=hv#lG{F(eo`Fu5k&id8G-B=`UnK*fZD!BKQTlA zxmbXDn+!QhM36zg5IO2Zko|z0et=!KT_Bx&8nG1GL@>pGl70rAb{&LDzCaqm6p9IC zV=#7bW>99ZW{_s^CP*foXcKu7nFsZ(O zotzpm6Le%SXAoyF$$)}>dYzUUK^2M$q${K=bY-w-kY_OSfOmjso30z58Wk6L74ix+ zc2HafW1%>MMuSF!vj>m|5(g9q76*Rg%=)c&Rrt`<0+n}J zcU^Y@b)s(aZsMjcO`eM`_%il13de91DgY!1DylB!7o8C z!SF%8kRQRm(0EXIka*BPh&+fqs65EuR9-Yqkh&1yL4gCQ1F8cA`*nBCchPs%c0#W* zuR5>%Y?PnmILJOoG0?owWI>4ov;(yRwgVLVuKP`PB5YJy$lnMv&^r0rZTMO!UIL+Z z;%$G)3CTjj_YHzDC@zM`={1%j=?z%vRicm&he7H))5xC@5{GgOXy@@sBfE!r40P#* zugIR!!NbZ8GR#oGBLat+^WrxK;=M2i*>|z=cjP%pjOXG!CsFL?1{WOdn7mR3BIuNM{kLL?{<%XHm@{R|-igs>`-*8`EF@N&cD4WHMR%U>&Tpo$Q@; z=YFp1sz}xrZOb^hT}YRT0VR8Qcpra1cOS*6qFqjxp%zIas%offsB3s>pMSq+ALmYB zj&z$*fT$Lo5N##$Viwty)806Vq;ix7=Pbn|6pI?4*E{|j{45Z zDg8C3UB^c~Wf-GD%}2pU-$!_pw3n)v>|5MN%SU{ZwwI=t;#{P0gienfs$e&i3jAm+vp;}Gb+@SW@( z?OlSW=BM_j#HTtRi65mO<2Mljx<6Wcq+sOeaQ-mrzVsdDoyHyKUCL{hr#2sH9{NnA zf5eG+-714V5@VD=gJ?IIJ_dSZ@<53rwMbNot4azQ{aGniMfU$x87}I{qyVI(RTL}I zO%swzw^ax$>QYFalHX-POH`@lS!6&6%)mfy2$YhdC(`u9dTZ3qo!=|4_q{p~LB%eYdom}c{6~(5O zMIoO~m!wviU@pa4sx@zWCUHh_W`2h89|hq!#Z=-yZ{j$^RO+$xQj%yEmU*sx}3Ey1Eo?soK2W{MNkn8Nr#pRjh0N zVd8(xh08LCG8ZLJ^AKmmR>hC?&C=_1c8RSr8zqwe6obY8^n%Q1PXDBWA&(`GDUZ#~ zvH*#7dVbn*mFPv9|I!#Cw-IrM`d`Gs-LQ#{7v&;I>Rq{fb4r$v*LUBW9wtw zW9_5j8ULB@8R(h8yx-Z*eE7WN{OG)YiDHRj=}gIwOunq$Jmx=HVZmeRW9ol&g}(H@ zq`tKHiM`3a>3#`uGJ^lqh57&Fg){TeXC;r(|J+2`t}^d>JoLGV(=sO|f+Y`08rJCy zQkdlVi^O_K46;#~tl^o1Q^?0sP1AU0aU2&@%*Xb}nl3rq+c}2U_6lq-Oq7}4S>BoO z$EGe0E`%-yE>Ru%9erK_+)Fv;99fWAkeLfp!Be7>|AYaPgHxoF*vE;-axQ6^oCYQY zX44!e87@=BQ(nhD4_GdNUe#~fP2+SK;!UO;*>$X#S<#cj$0#lp9g}?1eA|3~e0ts> z9>gBV9!y<2yrR4+y|TPI*Nj`UXeU`GS*MyNo2EFk99VX2dxw3h-Z+}3_(pZDYFRd> zT&5l-m(0VxdOJpRZE9IpvU86i9zL};>R5KndN;b)ed6ErA8;Og&Ewzv9zc&ykZG< zfNokkCDCf@+_DCS=}*vV^EVrn_f$HdLKkS^XJ~X)C1{7twDw4tHo#YcF` zMWya+gc%LCPJw*km91x3A%%h`*W|%4qSQt|0^>lQnj*6dF8YLfs{lW;un8@j3pSvQISScq zl!5hc(Kd4Y+rfL?4GQrOHkQ()x!V@AoEqgkk0ZU88?`Tb>Ey+!dSC3UiI~50v<#Ub zkOrB~*Dki_syT;!shqM2(qd=;qQr*sO!q7q-|iBzP!Nk`J|;zc!D0*l{sXBnGTsUk z@dLst{RE;KI2%68dpUU{gmMZ-_W9eVShC)Xxj8WP8)k|6g!zmtjXS@S;Ub=!pj;E4Xtb~G~7!{rbA=UR5p*j|#{BHffel@#~tXOOtb=q(2g z0p%|LKw8mLFR6ZF<=b#w@Pzrmgl?JK4%pS)g$y6$V4z1_=fzSu2{gCYOKut4m`CnF z(DPwWD-Mx_4@A6mptQ9zN72HKp&Cvghdo2Uu3=H4HMB0Bu#Oc2rvtzf6==dp6F5UL z-i09it>`fRYt~kmaEOh?nR$=r(f`TMcs25e?8HO8Z$2)XgCP8_t5hb~P)Jqb&5Zj* z_}cb~E|3_dYR}L&;{q>^0!XibxJ667Mz_V8T-ghJ(Z0rzSQ&+gjO@;km(H7NXchg} zIvuW-g7$1KF%crBC~H7*#Gg%?#i(RjLAb4cPtJ3kV3fixsq9s_6d)&E=#ZY&m4GNN zWPYbvXfdq|_Ylht4StyM4CDURK(Y6b{-(OGdg2Xly-^v5c-UXBmfDxI-5%U4-6GFUW8nLKzYCPyI#E_cpwb zuN{Q*DJElLLW%lzi@Ats3|fAeh3X*%Q&Og>y<^Y1{tSPDHL}3?H_5#@muBAQVCLf%%RwYNDnv*BC$@~`@rcCbw|7* zT8#DI8w?yD#YP30*VhQF{@fmIqH-BlO%Nq6L)&r^TTMa{4i4{`FLfr0tTygfr`aJ% zD=`RXgs@^nz9k)<@T=CGFdJ&&xp|-nNNK>Y$84?FFvK@GR}l!K3?)d15Ag?&BkLkK z=52PSiGcrDk(bbQT^iwr6d5|I`oWKU|I!Jixl^RFfYPqdSmsJB)q?exz~B$Pzoevq zr$OqJ4vjN$tc-24ni0Ze~vuaJ{CH!b+IPWGT5sy8EMmH>53-`t-)kaPzEuU`~yJvXw=HGy}F|wA2Jzf`wK@jN|9;p0;r$nLdz6lC%lNm9}xppmXpvx`5SDh7F#3GW8~%2f9RRK8shdoJ5^ToTz*l8WC})RSrsSg}Mz{!y7IQ`*1GdeL?=TRxgb`6P z!b=;}7S`)Q*0B~Js}vbuBv<1fvDZcd5nkI;fkkgl9D#TX6Gd1ReQ6Tvu1ni!7r72X=lm-!^ZAH87LusFcfyZ7ly32=zCSP5oD{*zlRAZy* z;)2jm)8#7rQLJA(c-rF4tMKpMe{|*Bqw5+pHs8(Poex0FdBz9wA=^jYe%FApKh7kX5@7Td?+!DZQOyGzE^%hBcZ>%dN=>&g@0bg^TM44fKg9# zg-S3Wy8%V~F60qcA|x|J$=(&`We$;Mp*m68D6)fpa=7@#wdW1o_$Ulz&IM8yq0+$w zOo7%qn9EdZmqw{l}fi+z7Acox;Fqu^(&O5KGndH zcdz|OZjbZ}ta9K<)LPKe)T7aHm}N8cFct6|h%Udu1OdE(&_?Ptg)(c4qW#r$+v#D< zmSxPs!A39^YQ~drE-go$a}cid^k>l}i&`oPz2E}5Qe?tXgej>D{-x9j(U=R>wv2GS znu@P_fnUnVwt5QWSOV+JL^B#jOZt{keFbTi8{i;=21BLBA7Tbcb~fm$xNcDGR~~eX zq0Vv&Tj!aljOpM|^~9iBIaa?KG>b~)n!wt5!16tKPhqXfScqb41jB<{K(JxR%e#yh zK$ZGCTqfj?j2{u;3$z4Tu-%M*jC9f3ZNj1)wg^rLB1W=?Lth{wLBA#2xwM>zUV@XXk+8F4|f~cPMZuXdmiWm0jdPW3Ly)F4v^nQ$$UtsQzogPyaI& z4slT|f%MAO-vVbt`tM1!REh8_KFaNIf z5UGuC=sQAH-e}n-l(2E%-HKeo(+K=BP=+@|v9NcfKlaQU1N8gNVz2N)EA;0wB*+V3bqEl z@0eCWtuf6?O{|up92_W{V(5Az2R}2q8+0?rBNTyuin$T)e6Kz06i~>P6ugCm(q9M+ zd%bYp1~>W&c$+q6d~EVk$%XWJH35M69BZ^{>ZMNWEsg!McVsEoDq)zWWTJF1FSqMS zvl;UAUM|(`wip%4Qr=eOnTy<7-0x+3%&;^-R^(gd(mVaCIvh{T1v|=vKe+>Nn&3bo z>?u?n?iI)p6g1MLSI8M-jl!a>`@wIc(zC@Xz`H|pkg`ht*s3q(yNobOlH+?1N z9o+d4=8>{2GheIf67NhRoZ7YyFdFyhlO&@7nTt78WmU=EBgn5PlcY!Q zN#Yz^9_SM&H;bj?Pyg757B|cuG=mYk^?4fmDZ<7dxiiO(BkU#WrD$+^+w@bgQX*d= zQLDRz`TamAYA%H&&GgJ-*TkMKXl;xBUBr2s;{-j3$ zL>)D}QLf$gb3kO0&6m=}m$gg=`cf8^vxkzqZW-BPv6OVtW!fE0$zP={5?xbGJlan+ zHl(;NO!o9PRSb=>*jNm-S=~OmsLvDvXSrH(e77D9{pke4XWONZqV8b$x4ArXSDqq3 zRLP6A>QVte75+G@wK#X_E0L|FK3DK+^eUBC60gwPazXl>znL<2B)3z_11(=UtJY1~ zIpOSp3yn!KtW9p7K>Lxt%CJ3}JB;s6Jw@J&DAhxP{gx%o0Tr2tC6`^!Un9GMjjRD@ zb?9G?k78OW0W_w*p7;!^Qc*%;)ozUt%5IuWanXK4GaNw28<#d}ii%haIWZOxsa6E+ z_x=kcZR>x6ENAY&jfIGVNGi?H*B2Wr%U;Y?P77eZ!nzeN-9+AUH0^;yW62nC#77uWG)t(Z;I%Bad3!g5?xI-E4rM5e{>b?4Oj4^?)e{V zb?}Bb5lm?egG6mN0Qry?L!GxlpPk(?uZx?i|@d#7PO=~(WYL~x< zF%$sU@D!!cY9m~;`0z9k$@U!Svg5=wh&LnC_0-#S&DDUvqJ;6@6B;oa>JA4;U9P<^ z*&{u9&Y^`Q)!L|K++9<@#YlMr^#S--pp&2mbJ#rcz2`@UIz?5P18Hi!>d71md!`v$ zmq~#`fqwv~6`lnMh$gnA#Y4gs=ArP_h`hK|8pMVz_@{JnB(fH?VfHGo%}v56Ai4q~ z8_Ud3aZZ4s&)?zA(I5p(S3q{B!UCa3-qfSW>(K;+un)N+g4>~MD${4E6B`Edy^hh0 z6K%foY&B0cwz)1&*!L=Kvlbl!-+LP66x%oV5PjeZ;jA?t<>!Q#;x=EzzXOLl2M-?0 z!TMGqAV9T+(XJiH2rof49r{)nElK=ql0!m8Vb6q)f#m1P*u)LAE&B63%Hd-Kk8m$s zVQBm9KYFL`Gb)K5hkU~edfR2cL}&=F70VhVE68dRvd&gZ-S?SBJS8k8)xqz8Y=$xD z5t14YVod1l7A21Ur zeY%EK{s_e;C(0{V2wL>S-Z8M*Z3XIe2)F1nYF8m=h3Sp-WI<;d%$=ZBC|b@u_1fHC z%}z4_NW@9kt36o|Y#f3CtEi%37`(C$MljWc>k|rVLgMwt?iV5Or${!+q3(1JUkBAgBnV(|s@{h_d`3tsfwT3d9lvG7iMLc!`)#y`zowy6Q zt4QVc=UKZbacLzu;#jm3CnhU&%@m?Wy;xI-@$!rO1Osmgw}Ry0FCDK@cV}=R&#@Z- zcR_7}));2NoS$8(FKWrBM>8@|I7kWp$F~#@PK!}Xdj`$rz;|$FxE!+qETeH=-I>@K zQnOM8%#W!01;tZFH}3QgCl`mxm|wvGxk`s}0nXu8Y^5bh6MgJ-s}v3kfAQ z>QAf1qkyJ>p-QPCrA1{Mm_mXm1m=oW$&z$)mBQZ{W4lx5=nI<7&h-=7SkA1Vf_(ASb{B!}su!L+n4$DJEZl|C`{H@~R_%t}eWz5;v^q%~qmHDAatl&oFe z0XlC!nbH#*C3-%&vVNBZ>nHPxwk(Qqw0uvzPekl{gcXF9WK*syb&t$%Ptf2iPAQ&s z2MI%s4z?q>5YTlR0ui;_7D=Wd7h6ykKNf5rPm~P<`#C|Pgck~MHNL9#Ifu251s#$asgoe5;L5-7*=R<0uR5_aEw?3(;^RYq58cO$yI<;9k|w0>2{l6 zU*IyWCP*}){^xBH{a?bsK)2CgKG)J&`+n_<&~JG3tjgAns#t2LCcblJ?uyqE@C0B( zqBf%7YqJw?+w3A68vb@+0J>bs1n-L*seNqSd=SB~=c-?nEAi=>_Vk-arpj z>s#7VJEUCc?TFf`A&7f`nIH1NFI}!=yMiW-`V9ov`Z{56Rb~J(w%h~%87j-RML31> zwto?nY!YV;xtk@w{qDzd)kgbvU#!Q2!vRjS_|{0*0>?JKLoM(f+XgJ>?MZ~CVj(KR zr3Y5~1+v@gP})wiR%{PnfW$!hEGFagk+vKd{*#&;IO6Ownoy7G6%DZDt3Y-dN_c0L zpJW#Z4`X~IuH*$$Rs}&;{-UbF5!-s*sIZylfiD|PVX>v4OOm)(how@71vXD>kn0Xk zZo;nYTAi|$%A>!){qZZo<8Ln?w{6kwwQVbb;!(~~i2gAZXVboI!G z9~(9gO__vg0X?!=jq(|8sCt;hSxr0PwwO0)*K+8r`BR=k_huu(pdAv0Y4g6G$lE`I zwWqF`JRh!@j3~pZPr|wm)8^kr^CL^#NaK12AISoP8!>PF(#m{N*;nbTF3S8hxfgss zUVdAK%pck~21DkX42Zediia%45G#FU3?8$0&80@E&QP`4FjuUC`{HP2D_b*2KfE#< zL&?$Jwn9Nn$7AxvEI&!%#K^T?(Y?f=vUwV?b`Dz>g6z-qC6Vw~Nv8R@Kg^v(e>UT5 z&hZEH&Afmau&~<{l6v#2@Sb3kqEa@BCol`3KgY=J#BIR00FsCFo~RLe?W9W|D%nQ} zk3-Fk32Qk80axl@%*{QO339b5skDn%yL>!j-?s*qe3BbAZXn~3Up+suK`rG@e}5pC zi^|e2bty4y+*nMKuYv`eii(Zk>?xS@H#JQQo@NDfYln_y`h@8+ zZ0-(w-Z%I&bLbUz(!1Uxmju$W8DY}PYubq}{8TjL|6%B3D1NGs!7ibyODh-n7W~}y z3&{GE=)IhyOu2zHavR8@a#=#Ye zFMr7w?%s^vJ9uGH9*l_>^Qt=$SESX8@H5|F-8i*9W$qNZOCb=9^gL5Bnw)tWm5$t# znbin>L5(d*HQ@)fdV>#I^KoK-gVLBKG1<#?U9;NzWeG$k5b8lQ*B9mcilBj2p}f=Z z(Nv#FNKu1nb`8vtNO+o=U9a9lcn?Z&QwZFFmaZIK`JSV~uynTKgLAZXv0-~VgVaT% zFZ|ENvvheFi$C*;;@C@sKT{~Cq;QY}EXuZ!!{(8dxp9WjbosB6cowkF`SZ2EGkZ!2 zC9mz?>$=SIgv@WXR{rE(j!RuRy542bER%RS9S{HQ}Xh~&{DS5S(pYKt+c zNxLd9>ytG~1n|=Yb*xwXeIUFqUw5f*fxEi}x1KO#TS@ubC3(@a=lMO4QelmYc{Yz` zuY#GXM>9PtO(TYbYEk-8+wu*|Z}dKVIfBYN)Mc0%F+0_6yIJWHgmH&`L1u`wi96j7 zM&<8VL35HrZU^@pq_QXfYagiKMOA=*(6tIzRU3jU1!};l2BIsENr_7)n&GCNjTNP4 zU8wIOsKAl|j^d~h&S_tF*n4GQw-=JV=enri^xf`ddXr7srB9%)g=e~QFhzsT_c}Wq zPe{iaqS~y}%}D6s$nRT*PT8PFbyh>tBgIqGLw>LaWGi7rp!3&uY%ynhG|Jf%C^N)| zXvf6IVpL1q%8rQHSg0D+6+^bKYcP6a{_=1jc9Ldg^!Nt#PTYHb0+7eM@^>$=u0Iog z98JPKCHSR2V;PB89AX1dZxP#w6P3n?B=Lt?wEA>ebay~s+@6O^OE;^{MTsJ*qOC$qHpT>kumCX2sbUqJ!EI!jA4v!%2c zMeD+tWVcR9(@wli=i^uKC~gwL|*I&X!F`q&ZoJjRm$z$yhbx_Z}I3KlJETMl2Z?AoH|e; ziNjER=pd4w8CKz)mwLINDNtg&IxOS-@sxdx_8Hr^RrlMeNuOMi!E?V{cSMrWjBjPQ zva)~R(OUJ(wSbFh{R@sk%1zd3NX)bR_>~UuHm1Dwga{iE?V`ceTi%y`ORx{u2UyDj zI#L$d=NT4O5-pRDAGQ2DzN@CtUS8;8pTu(&gS(Ba@IQp8`(;r_ck--9xk%Sp3}hW? zIIwb4HS6QHVxdELG5^8sJ{8-$GDL1)1%u2#mpl^M_=p#G=!1$#=tr?xa2wBB9lW8* z+Fw6Apjim?B7=v=0o8@tlOt=lsDuNh_YO&!z^=l%RhKuf{vU45D5nZhk@R!0r6n zMvHGN^XP1AbLjL480Flc^_K0f^6}*p$Yop^^>Xp8AfQUtFK;I>_QjN4v=FxtQyV5tZ5^8Yz90FX>~70YOWE4m=lMrqwzE`HqjHZBYXn) zd%4qg{Kz~$RcdgzGrb85h8W{7oiVv%SB7ql;A6*Xyrz1OVRwb)5S?bJGt43SXs@Q? zDJ7d%ddn&D?U7P3i*5(?67lCc*#2=mreHIm<(R+QmRO<`&(>`G;p*a~Bfputs(Upy zvQJp=^^>|5%>U2&VHCK627d7v71^o&`N4MpypY*2{5<>iFdX6tDTF({<`)6FXzo6a z(7wMXfNDkf|7K^MlyF^5z2t~ zH_~NDhcrU|4E?hV;15CVs6bLUDF_|w9^)&|hRq*83L$sV6WDth@cZ_E4Y6?cxb0JgKdx8`&Bp!#|ivCwtE7^=!8m|)o}qV7?-NH@GQLEvnfPX_G8eN zKRyDp^LQ)cxrb}MZ(LC8YN@!Z;9@Rw18WdKdh86cPwdNdSk_#>K}0ZxJxJjMkcmDv zCh2s#Q=&lGg}RPLN`W^kzkQU#fXF>;)+>9w+9R%QP zk0~yn)tju?*ow&P_PQDUxa)m+;$G}=bI5f$U#$35roavlMH&K8%r->qPneJ13%=5q z8#@c*;>mlS>*eslHNyS7|AEU>L9=nw?fy3=cs$a8@GTw^0cKWxtAHt!NSxKJZm$3v zGjJww(UG<%L9+k{Hw*7$E1`(~AX4K)yf!8dv3&d&ZSxn{Fh7hwTo%72^jK5iiIcKZ zb{oO{ZFTs`0n|9d=ty|@GGV2gkmaXXNHx#CNE?Nwt*HL20Q%__XV^#$?$gj0lE~kp z-L2!0*P*E%&N=JT{P8wPTU#>Cg%6*~ul1EOL2;AS`htg4hg!3jR;SS3o?Ns$k4dy! z%Q&cc(A&)6xjCpi`JUXK+)sRA6~X$|$?bkO929JBKhO+^0dLK!F?m&}c!$%QO?EWt zYN47yW7z2&%8(V8>=)*D$zJ@x?!+G3l-02HU6LlQ&F4nQUTAS_>O%YW1GBGfY5nB} zoCzFH4H)vVTLusrUOq{Y@ql^oBcK$zLEh9oUyc-4stSl+pWx4e^u}2!Dwg0++u#^& zDv7tt4g{H;LO*z!fIyCMp={IBzG~ zoOLrsX~7i>87T|yTKTqq2pro%BJ1p=(6%Kx05kNt?9A@Nw;R8Fbmt9XqYn}n*aUo1 zB)OfhS)Hcei&8u|HH17!MY8E6cH+E*Z5ON>zmzo-`Mjm78iaxf+5J zBEEXa{dHY|;KfL1aZlwB$G`L3$~R0s-q0Y=G#l2?Jle)Zufh;oT99Q&c?>0ODL?A6 zBh7>J9po;J``~4!6mG;Y)5p~&CQ)5`Q`)i$S~lv3I60PAI3+5S0hHXlik0gXi@REW zbIiTH4Rf+7sSX|O_IatwZYc3kf5Jtt>DGYYndkgwcQ13;ye�R0pl!Gh|V83jf>^ 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

    Sve@6z;dti&qM@hjdwzFR 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 #Y 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 literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2025-04-v5.3.pdf b/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2025-04-v5.3.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8bf812ff58399b33262c251e00a3209a424becd6 GIT binary patch literal 154227 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

    `xU97POli2)8@K8~oE=v*$x$kp+UxvCFT}>lH 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⩔`B>BA9Z-U8vxzY|EBK5G$+e^28MB@HS{vO%&j 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 literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/README.md new file mode 100644 index 0000000..cba0f2f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/README.md @@ -0,0 +1,20 @@ +# Audits + +| Date | Version | Commit | Auditor | Scope | Links | +| ------------- | ------- | -------------------------------------------------------------------------------- | ------------ | -------------------- | ----------------------------------------------------------- | +| April 2025 | v5.3.0 | [`d4b2e98`](https://github.com/openzeppelin/openzeppelin-contracts/tree/d4b2e98) | OpenZeppelin | v5.3 Changes | [🔗](./2025-04-v5.3.pdf) | +| December 2024 | v5.2.0 | [`98d28f9`](https://github.com/openzeppelin/openzeppelin-contracts/tree/98d28f9) | OpenZeppelin | v5.2 Changes | [🔗](./2024-12-v5.2.pdf) | +| October 2024 | v5.1.0 | [`aba9ff6`](https://github.com/openzeppelin/openzeppelin-contracts/tree/aba9ff6) | OpenZeppelin | v5.1 Changes | [🔗](./2024-10-v5.1.pdf) | +| October 2023 | v5.0.0 | [`b5a3e69`](https://github.com/openzeppelin/openzeppelin-contracts/tree/b5a3e69) | OpenZeppelin | v5.0 Changes | [🔗](./2023-10-v5.0.pdf) | +| May 2023 | v4.9.0 | [`91df66c`](https://github.com/openzeppelin/openzeppelin-contracts/tree/91df66c) | OpenZeppelin | v4.9 Changes | [🔗](./2023-05-v4.9.pdf) | +| October 2022 | v4.8.0 | [`14f98db`](https://github.com/openzeppelin/openzeppelin-contracts/tree/14f98db) | OpenZeppelin | ERC4626, Checkpoints | [🔗](./2022-10-ERC4626.pdf) [🔗](./2022-10-Checkpoints.pdf) | +| October 2018 | v2.0.0 | [`dac5bcc`](https://github.com/openzeppelin/openzeppelin-contracts/tree/dac5bcc) | LevelK | Everything | [🔗](./2018-10.pdf) | +| March 2017 | v1.0.4 | [`9c5975a`](https://github.com/openzeppelin/openzeppelin-contracts/tree/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/.gitignore b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/.gitignore new file mode 100644 index 0000000..893adcd --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/.gitignore @@ -0,0 +1 @@ +patched diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/Makefile b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/Makefile new file mode 100644 index 0000000..d57d2ff --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/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 | $(DST) + @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 | $(DIFF) + @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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/README.md new file mode 100644 index 0000000..ff2ccdf --- /dev/null +++ b/typescript/packages/account-modules/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 is 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/diff/access_manager_AccessManager.sol.patch b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/diff/access_manager_AccessManager.sol.patch new file mode 100644 index 0000000..cfb6cdf --- /dev/null +++ b/typescript/packages/account-modules/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 adminRestricted, uint64 roleAdminId, uint32 executionDelay) { ++ ) internal view returns (bool adminRestricted, 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol new file mode 100644 index 0000000..e96883f --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessControlHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessControlHarness.sol new file mode 100644 index 0000000..e862d3e --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagedHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagedHarness.sol new file mode 100644 index 0000000..50be23a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagedHarness.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import "../patched/access/manager/IAccessManager.sol"; +import "../patched/access/manager/AccessManaged.sol"; + +contract AccessManagedHarness is AccessManaged { + bytes internal SOME_FUNCTION_CALLDATA = abi.encodeCall(this.someFunction, ()); + + constructor(address initialAuthority) AccessManaged(initialAuthority) {} + + function someFunction() public restricted() { + // Sanity for FV: the msg.data when calling this function should be the same as the data used when checking + // the schedule. This is a reformulation of `msg.data == SOME_FUNCTION_CALLDATA` that focuses on the operation + // hash for this call. + require( + IAccessManager(authority()).hashOperation(_msgSender(), address(this), msg.data) + == + IAccessManager(authority()).hashOperation(_msgSender(), address(this), SOME_FUNCTION_CALLDATA) + ); + } + + function authority_canCall_immediate(address caller) public view returns (bool result) { + (result,) = AuthorityUtils.canCallWithDelay(authority(), caller, address(this), this.someFunction.selector); + } + + function authority_canCall_delay(address caller) public view returns (uint32 result) { + (,result) = AuthorityUtils.canCallWithDelay(authority(), caller, address(this), this.someFunction.selector); + } + + function authority_getSchedule(address caller) public view returns (uint48) { + IAccessManager manager = IAccessManager(authority()); + return manager.getSchedule(manager.hashOperation(caller, address(this), SOME_FUNCTION_CALLDATA)); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagerHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagerHarness.sol new file mode 100644 index 0000000..69295d4 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagerHarness.sol @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import "../patched/access/manager/AccessManager.sol"; + +contract AccessManagerHarness is AccessManager { + // override with a storage slot that can basically take any value. + uint32 private _minSetback; + + constructor(address initialAdmin) AccessManager(initialAdmin) {} + + // FV + function minSetback() public view override returns (uint32) { + return _minSetback; + } + + function canCall_immediate(address caller, address target, bytes4 selector) external view returns (bool result) { + (result,) = canCall(caller, target, selector); + } + + function canCall_delay(address caller, address target, bytes4 selector) external view returns (uint32 result) { + (,result) = canCall(caller, target, selector); + } + + function canCallExtended(address caller, address target, bytes calldata data) external view returns (bool, uint32) { + return _canCallExtended(caller, target, data); + } + + function canCallExtended_immediate(address caller, address target, bytes calldata data) external view returns (bool result) { + (result,) = _canCallExtended(caller, target, data); + } + + function canCallExtended_delay(address caller, address target, bytes calldata data) external view returns (uint32 result) { + (,result) = _canCallExtended(caller, target, data); + } + + function getAdminRestrictions_restricted(bytes calldata data) external view returns (bool result) { + (result,,) = _getAdminRestrictions(data); + } + + function getAdminRestrictions_roleAdminId(bytes calldata data) external view returns (uint64 result) { + (,result,) = _getAdminRestrictions(data); + } + + function getAdminRestrictions_executionDelay(bytes calldata data) external view returns (uint32 result) { + (,,result) = _getAdminRestrictions(data); + } + + function hasRole_isMember(uint64 roleId, address account) external view returns (bool result) { + (result,) = hasRole(roleId, account); + } + + function hasRole_executionDelay(uint64 roleId, address account) external view returns (uint32 result) { + (,result) = hasRole(roleId, account); + } + + function getAccess_since(uint64 roleId, address account) external view returns (uint48 result) { + (result,,,) = getAccess(roleId, account); + } + + function getAccess_currentDelay(uint64 roleId, address account) external view returns (uint32 result) { + (,result,,) = getAccess(roleId, account); + } + + function getAccess_pendingDelay(uint64 roleId, address account) external view returns (uint32 result) { + (,,result,) = getAccess(roleId, account); + } + + function getAccess_effect(uint64 roleId, address account) external view returns (uint48 result) { + (,,,result) = getAccess(roleId, account); + } + + function getTargetAdminDelay_after(address target) public view virtual returns (uint32 result) { + (,result,) = _getTargetAdminDelayFull(target); + } + + function getTargetAdminDelay_effect(address target) public view virtual returns (uint48 result) { + (,,result) = _getTargetAdminDelayFull(target); + } + + function getRoleGrantDelay_after(uint64 roleId) public view virtual returns (uint32 result) { + (,result,) = _getRoleGrantDelayFull(roleId); + } + + function getRoleGrantDelay_effect(uint64 roleId) public view virtual returns (uint48 result) { + (,,result) = _getRoleGrantDelayFull(roleId); + } + + function hashExecutionId(address target, bytes4 selector) external pure returns (bytes32) { + return _hashExecutionId(target, selector); + } + + function executionId() external view returns (bytes32) { + return _executionId; + } + + // Pad with zeros (and don't revert) if data is too short. + function getSelector(bytes calldata data) external pure returns (bytes4) { + return bytes4(data); + } + + function getFirstArgumentAsAddress(bytes calldata data) external pure returns (address) { + return abi.decode(data[0x04:0x24], (address)); + } + + function getFirstArgumentAsUint64(bytes calldata data) external pure returns (uint64) { + return abi.decode(data[0x04:0x24], (uint64)); + } + + function _checkAuthorized() internal override { + // We need this hack otherwise certora will assume _checkSelector(_msgData()) can return anything :/ + require(msg.sig == _checkSelector(_msgData())); + super._checkAuthorized(); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/DoubleEndedQueueHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/DoubleEndedQueueHarness.sol new file mode 100644 index 0000000..d684c73 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20FlashMintHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20FlashMintHarness.sol new file mode 100644 index 0000000..2f989b2 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20PermitHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20PermitHarness.sol new file mode 100644 index 0000000..08113f4 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20WrapperHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20WrapperHarness.sol new file mode 100644 index 0000000..ca183ad --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC3156FlashBorrowerHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC3156FlashBorrowerHarness.sol new file mode 100644 index 0000000..1c76da2 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC721Harness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC721Harness.sol new file mode 100644 index 0000000..69c4c20 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC721ReceiverHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC721ReceiverHarness.sol new file mode 100644 index 0000000..3843ef4 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/EnumerableMapHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/EnumerableMapHarness.sol new file mode 100644 index 0000000..6155193 --- /dev/null +++ b/typescript/packages/account-modules/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 _positionOf(bytes32 key) public view returns (uint256) { + return _map._keys._inner._positions[key]; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/EnumerableSetHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/EnumerableSetHarness.sol new file mode 100644 index 0000000..09246de --- /dev/null +++ b/typescript/packages/account-modules/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 _positionOf(bytes32 value) public view returns (uint256) { + return _set._inner._positions[value]; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/InitializableHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/InitializableHarness.sol new file mode 100644 index 0000000..743d677 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/NoncesHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/NoncesHarness.sol new file mode 100644 index 0000000..beea5fd --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/NoncesHarness.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Nonces} from "../patched/utils/Nonces.sol"; + +contract NoncesHarness is Nonces { + function useNonce(address account) external returns (uint256) { + return _useNonce(account); + } + + function useCheckedNonce(address account, uint256 nonce) external { + _useCheckedNonce(account, nonce); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/Ownable2StepHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/Ownable2StepHarness.sol new file mode 100644 index 0000000..09a5faa --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/OwnableHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/OwnableHarness.sol new file mode 100644 index 0000000..79b4b1b --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/PausableHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/PausableHarness.sol new file mode 100644 index 0000000..5977b92 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/TimelockControllerHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/TimelockControllerHarness.sol new file mode 100644 index 0000000..95ae406 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2021-10.pdf b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2022-03.pdf b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2022-05.pdf b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/run.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/run.js new file mode 100755 index 0000000..91f4a6a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/run.js @@ -0,0 +1,168 @@ +#!/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 + +import { spawn } from 'child_process'; +import { PassThrough } from 'stream'; +import { once } from 'events'; +import path from 'path'; +import yargs from 'yargs'; +import { hideBin } from 'yargs/helpers'; +import pLimit from 'p-limit'; +import fs from 'fs/promises'; + +const argv = yargs(hideBin(process.argv)) + .env('') + .options({ + all: { + alias: 'a', + type: 'boolean', + }, + spec: { + alias: 's', + type: 'string', + default: path.resolve(import.meta.dirname, 'specs.json'), + }, + parallel: { + alias: 'p', + type: 'number', + default: 4, + }, + verbose: { + alias: 'v', + type: 'count', + default: 0, + }, + options: { + alias: 'o', + type: 'array', + default: [], + }, + }) + .parse(); + +function match(entry, request) { + const [reqSpec, reqContract] = request.split(':').reverse(); + return entry.spec == reqSpec && (!reqContract || entry.contract == reqContract); +} + +const specs = JSON.parse(fs.readFileSync(argv.spec, 'utf8')).filter(s => argv.all || argv._.some(r => match(s, r))); + +const limit = pLimit(argv.parallel); + +if (argv._.length == 0 && !argv.all) { + console.error(`Warning: No specs requested. Did you forget 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 = 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 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 ? ':heavy_check_mark:' : ':x:', + url ? `[link](${url?.replace('/output/', '/jobStatus/')})` : 'error', + url ? `[link](${url})` : 'error', + ), + ); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs.json new file mode 100644 index 0000000..a894190 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs.json @@ -0,0 +1,110 @@ +[ + { + "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": "AccessManager", + "contract": "AccessManagerHarness", + "files": ["certora/harnesses/AccessManagerHarness.sol"], + "options": ["--optimistic_hashing", "--optimistic_loop"] + }, + { + "spec": "AccessManaged", + "contract": "AccessManagedHarness", + "files": [ + "certora/harnesses/AccessManagedHarness.sol", + "certora/harnesses/AccessManagerHarness.sol" + ], + "options": [ + "--optimistic_hashing", + "--optimistic_loop", + "--link AccessManagedHarness:_authority=AccessManagerHarness" + ] + }, + { + "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"] + }, + { + "spec": "Nonces", + "contract": "NoncesHarness", + "files": ["certora/harnesses/NoncesHarness.sol"] + } +] diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessControl.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessControl.spec new file mode 100644 index 0000000..70b0672 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessControlDefaultAdminRules.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessControlDefaultAdminRules.spec new file mode 100644 index 0000000..5860fd5 --- /dev/null +++ b/typescript/packages/account-modules/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 renouncing │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +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 renouncing"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManaged.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManaged.spec new file mode 100644 index 0000000..adcb859 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManaged.spec @@ -0,0 +1,34 @@ +import "helpers/helpers.spec"; +import "methods/IAccessManaged.spec"; + +methods { + // FV + function someFunction() external; + function authority_canCall_immediate(address) external returns (bool); + function authority_canCall_delay(address) external returns (uint32); + function authority_getSchedule(address) external returns (uint48); +} + +invariant isConsumingScheduledOpClean() + isConsumingScheduledOp() == to_bytes4(0); + +rule callRestrictedFunction(env e) { + bool immediate = authority_canCall_immediate(e, e.msg.sender); + uint32 delay = authority_canCall_delay(e, e.msg.sender); + uint48 scheduleBefore = authority_getSchedule(e, e.msg.sender); + + someFunction@withrevert(e); + bool success = !lastReverted; + + uint48 scheduleAfter = authority_getSchedule(e, e.msg.sender); + + // can only call if immediate, or (with delay) by consuming a scheduled op + assert success => ( + immediate || + ( + delay > 0 && + isSetAndPast(e, scheduleBefore) && + scheduleAfter == 0 + ) + ); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManager.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManager.spec new file mode 100644 index 0000000..cc4b013 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManager.spec @@ -0,0 +1,826 @@ +import "helpers/helpers.spec"; +import "methods/IAccessManager.spec"; + +methods { + // FV + function canCall_immediate(address,address,bytes4) external returns (bool); + function canCall_delay(address,address,bytes4) external returns (uint32); + function canCallExtended(address,address,bytes) external returns (bool,uint32); + function canCallExtended_immediate(address,address,bytes) external returns (bool); + function canCallExtended_delay(address,address,bytes) external returns (uint32); + function getAdminRestrictions_restricted(bytes) external returns (bool); + function getAdminRestrictions_roleAdminId(bytes) external returns (uint64); + function getAdminRestrictions_executionDelay(bytes) external returns (uint32); + function hasRole_isMember(uint64,address) external returns (bool); + function hasRole_executionDelay(uint64,address) external returns (uint32); + function getAccess_since(uint64,address) external returns (uint48); + function getAccess_currentDelay(uint64,address) external returns (uint32); + function getAccess_pendingDelay(uint64,address) external returns (uint32); + function getAccess_effect(uint64,address) external returns (uint48); + function getTargetAdminDelay_after(address target) external returns (uint32); + function getTargetAdminDelay_effect(address target) external returns (uint48); + function getRoleGrantDelay_after(uint64 roleId) external returns (uint32); + function getRoleGrantDelay_effect(uint64 roleId) external returns (uint48); + function hashExecutionId(address,bytes4) external returns (bytes32) envfree; + function executionId() external returns (bytes32) envfree; + function getSelector(bytes) external returns (bytes4) envfree; + function getFirstArgumentAsAddress(bytes) external returns (address) envfree; + function getFirstArgumentAsUint64(bytes) external returns (uint64) envfree; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition isOnlyAuthorized(bytes4 selector) returns bool = + selector == to_bytes4(sig:labelRole(uint64,string).selector ) || + selector == to_bytes4(sig:setRoleAdmin(uint64,uint64).selector ) || + selector == to_bytes4(sig:setRoleGuardian(uint64,uint64).selector ) || + selector == to_bytes4(sig:setGrantDelay(uint64,uint32).selector ) || + selector == to_bytes4(sig:setTargetAdminDelay(address,uint32).selector ) || + selector == to_bytes4(sig:updateAuthority(address,address).selector ) || + selector == to_bytes4(sig:setTargetClosed(address,bool).selector ) || + selector == to_bytes4(sig:setTargetFunctionRole(address,bytes4[],uint64).selector) || + selector == to_bytes4(sig:grantRole(uint64,address,uint32).selector ) || + selector == to_bytes4(sig:revokeRole(uint64,address).selector ); + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: executionId must be clean when not in the middle of a call │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant cleanExecutionId() + executionId() == to_bytes32(0); + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: public role │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant publicRole(env e, address account) + hasRole_isMember(e, PUBLIC_ROLE(), account) && + hasRole_executionDelay(e, PUBLIC_ROLE(), account) == 0 && + getAccess_since(e, PUBLIC_ROLE(), account) == 0 && + getAccess_currentDelay(e, PUBLIC_ROLE(), account) == 0 && + getAccess_pendingDelay(e, PUBLIC_ROLE(), account) == 0 && + getAccess_effect(e, PUBLIC_ROLE(), account) == 0; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: hasRole is consistent with getAccess │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant hasRoleGetAccessConsistency(env e, uint64 roleId, address account) + hasRole_isMember(e, roleId, account) == (roleId == PUBLIC_ROLE() || isSetAndPast(e, getAccess_since(e, roleId, account))) && + hasRole_executionDelay(e, roleId, account) == getAccess_currentDelay(e, roleId, account); + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Functions: canCall, canCallExtended, getAccess, hasRole, isTargetClosed and getTargetFunctionRole do NOT revert │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule noRevert(env e) { + require nonpayable(e); + require sanity(e); + + address caller; + address target; + bytes data; + bytes4 selector; + uint64 roleId; + + canCall@withrevert(e, caller, target, selector); + assert !lastReverted; + + // require data.length <= max_uint64; + // + // canCallExtended@withrevert(e, caller, target, data); + // assert !lastReverted; + + getAccess@withrevert(e, roleId, caller); + assert !lastReverted; + + hasRole@withrevert(e, roleId, caller); + assert !lastReverted; + + isTargetClosed@withrevert(target); + assert !lastReverted; + + getTargetFunctionRole@withrevert(target, selector); + assert !lastReverted; + + // Not covered: + // - getAdminRestrictions (_1, _2 & _3) + // - getSelector +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Functions: admin restrictions are correct │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule getAdminRestrictions(env e, bytes data) { + bool restricted = getAdminRestrictions_restricted(e, data); + uint64 roleId = getAdminRestrictions_roleAdminId(e, data); + uint32 delay = getAdminRestrictions_executionDelay(e, data); + bytes4 selector = getSelector(data); + + if (data.length < 4) { + assert restricted == false; + assert roleId == 0; + assert delay == 0; + } else { + assert restricted == + isOnlyAuthorized(selector); + + assert roleId == ( + (restricted && selector == to_bytes4(sig:grantRole(uint64,address,uint32).selector)) || + (restricted && selector == to_bytes4(sig:revokeRole(uint64,address).selector )) + ? getRoleAdmin(getFirstArgumentAsUint64(data)) + : ADMIN_ROLE() + ); + + assert delay == ( + (restricted && selector == to_bytes4(sig:updateAuthority(address,address).selector )) || + (restricted && selector == to_bytes4(sig:setTargetClosed(address,bool).selector )) || + (restricted && selector == to_bytes4(sig:setTargetFunctionRole(address,bytes4[],uint64).selector)) + ? getTargetAdminDelay(e, getFirstArgumentAsAddress(data)) + : 0 + ); + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Functions: canCall │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule canCall(env e) { + address caller; + address target; + bytes4 selector; + + // Get relevant values + bool immediate = canCall_immediate(e, caller, target, selector); + uint32 delay = canCall_delay(e, caller, target, selector); + bool closed = isTargetClosed(target); + uint64 roleId = getTargetFunctionRole(target, selector); + bool isMember = hasRole_isMember(e, roleId, caller); + uint32 currentDelay = hasRole_executionDelay(e, roleId, caller); + + // Can only execute without delay in specific cases: + // - target not closed + // - if self-execution: `executionId` must match + // - if third party execution: must be member with no delay + assert immediate <=> ( + !closed && + ( + (caller == currentContract && executionId() == hashExecutionId(target, selector)) + || + (caller != currentContract && isMember && currentDelay == 0) + ) + ); + + // Can only execute with delay in specific cases: + // - target not closed + // - third party execution + // - caller is a member and has an execution delay + assert delay > 0 <=> ( + !closed && + caller != currentContract && + isMember && + currentDelay > 0 + ); + + // If there is a delay, then it must be the caller's execution delay + assert delay > 0 => delay == currentDelay; + + // Immediate execute means no delayed execution + assert immediate => delay == 0; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Functions: canCallExtended │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule canCallExtended(env e) { + address caller; + address target; + bytes data; + bytes4 selector = getSelector(data); + + bool immediate = canCallExtended_immediate(e, caller, target, data); + uint32 delay = canCallExtended_delay(e, caller, target, data); + bool enabled = getAdminRestrictions_restricted(e, data); + uint64 roleId = getAdminRestrictions_roleAdminId(e, data); + uint32 operationDelay = getAdminRestrictions_executionDelay(e, data); + bool inRole = hasRole_isMember(e, roleId, caller); + uint32 executionDelay = hasRole_executionDelay(e, roleId, caller); + + if (target == currentContract) { + // Can only execute without delay in the specific cases: + // - caller is the AccessManager and the executionId is set + // or + // - data matches an admin restricted function + // - caller has the necessary role + // - operation delay is not set + // - execution delay is not set + assert immediate <=> ( + ( + caller == currentContract && + data.length >= 4 && + executionId() == hashExecutionId(target, selector) + ) || ( + caller != currentContract && + enabled && + inRole && + operationDelay == 0 && + executionDelay == 0 + ) + ); + + // Immediate execute means no delayed execution + // This is equivalent to "delay > 0 => !immediate" + assert immediate => delay == 0; + + // Can only execute with delay in specific cases: + // - caller is a third party + // - data matches an admin restricted function + // - caller has the necessary role + // -operation delay or execution delay is set + assert delay > 0 <=> ( + caller != currentContract && + enabled && + inRole && + (operationDelay > 0 || executionDelay > 0) + ); + + // If there is a delay, then it must be the maximum of caller's execution delay and the operation delay + assert delay > 0 => to_mathint(delay) == max(operationDelay, executionDelay); + } else if (data.length < 4) { + assert immediate == false; + assert delay == 0; + } else { + // results are equivalent when targeting third party contracts + assert immediate == canCall_immediate(e, caller, target, selector); + assert delay == canCall_delay(e, caller, target, selector); + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ State transitions: getAccess │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule getAccessChangeTime(uint64 roleId, address account) { + env e1; + env e2; + + // values before + mathint getAccess1Before = getAccess_since(e1, roleId, account); + mathint getAccess2Before = getAccess_currentDelay(e1, roleId, account); + mathint getAccess3Before = getAccess_pendingDelay(e1, roleId, account); + mathint getAccess4Before = getAccess_effect(e1, roleId, account); + + // time pass: e1 → e2 + require clock(e1) <= clock(e2); + + // values after + mathint getAccess1After = getAccess_since(e2, roleId, account); + mathint getAccess2After = getAccess_currentDelay(e2, roleId, account); + mathint getAccess3After = getAccess_pendingDelay(e2, roleId, account); + mathint getAccess4After = getAccess_effect(e2, roleId, account); + + // member "since" cannot change as a consequence of time passing + assert getAccess1Before == getAccess1After; + + // any change of any other value should be a consequence of the effect timepoint being reached + assert ( + getAccess2Before != getAccess2After || + getAccess3Before != getAccess3After || + getAccess4Before != getAccess4After + ) => ( + getAccess4Before != 0 && + getAccess4Before > clock(e1) && + getAccess4Before <= clock(e2) && + getAccess2After == getAccess3Before && + getAccess3After == 0 && + getAccess4After == 0 + ); +} + +rule getAccessChangeCall(uint64 roleId, address account) { + env e; + + // sanity + require sanity(e); + + // values before + mathint getAccess1Before = getAccess_since(e, roleId, account); + mathint getAccess2Before = getAccess_currentDelay(e, roleId, account); + mathint getAccess3Before = getAccess_pendingDelay(e, roleId, account); + mathint getAccess4Before = getAccess_effect(e, roleId, account); + + // arbitrary function call + method f; calldataarg args; f(e, args); + + // values before + mathint getAccess1After = getAccess_since(e, roleId, account); + mathint getAccess2After = getAccess_currentDelay(e, roleId, account); + mathint getAccess3After = getAccess_pendingDelay(e, roleId, account); + mathint getAccess4After = getAccess_effect(e, roleId, account); + + // transitions + assert ( + getAccess1Before != getAccess1After || + getAccess2Before != getAccess2After || + getAccess3Before != getAccess3After || + getAccess4Before != getAccess4After + ) => ( + ( + f.selector == sig:grantRole(uint64,address,uint32).selector && + getAccess1After > 0 + ) || ( + ( + f.selector == sig:revokeRole(uint64,address).selector || + f.selector == sig:renounceRole(uint64,address).selector + ) && + getAccess1After == 0 && + getAccess2After == 0 && + getAccess3After == 0 && + getAccess4After == 0 + ) + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ State transitions: isTargetClosed │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule isTargetClosedChangeTime(address target) { + env e1; + env e2; + + // values before + bool isClosedBefore = isTargetClosed(e1, target); + + // time pass: e1 → e2 + require clock(e1) <= clock(e2); + + // values after + bool isClosedAfter = isTargetClosed(e2, target); + + // transitions + assert isClosedBefore == isClosedAfter; +} + +rule isTargetClosedChangeCall(address target) { + env e; + + // values before + bool isClosedBefore = isTargetClosed(e, target); + + // arbitrary function call + method f; calldataarg args; f(e, args); + + // values after + bool isClosedAfter = isTargetClosed(e, target); + + // transitions + assert isClosedBefore != isClosedAfter => ( + f.selector == sig:setTargetClosed(address,bool).selector + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ State transitions: getTargetFunctionRole │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule getTargetFunctionRoleChangeTime(address target, bytes4 selector) { + env e1; + env e2; + + // values before + mathint roleIdBefore = getTargetFunctionRole(e1, target, selector); + + // time pass: e1 → e2 + require clock(e1) <= clock(e2); + + // values after + mathint roleIdAfter = getTargetFunctionRole(e2, target, selector); + + // transitions + assert roleIdBefore == roleIdAfter; +} + +rule getTargetFunctionRoleChangeCall(address target, bytes4 selector) { + env e; + + // values before + mathint roleIdBefore = getTargetFunctionRole(e, target, selector); + + // arbitrary function call + method f; calldataarg args; f(e, args); + + // values after + mathint roleIdAfter = getTargetFunctionRole(e, target, selector); + + // transitions + assert roleIdBefore != roleIdAfter => ( + f.selector == sig:setTargetFunctionRole(address,bytes4[],uint64).selector + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ State transitions: getTargetAdminDelay │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule getTargetAdminDelayChangeTime(address target) { + env e1; + env e2; + + // values before + mathint delayBefore = getTargetAdminDelay(e1, target); + mathint delayPendingBefore = getTargetAdminDelay_after(e1, target); + mathint delayEffectBefore = getTargetAdminDelay_effect(e1, target); + + // time pass: e1 → e2 + require clock(e1) <= clock(e2); + + // values after + mathint delayAfter = getTargetAdminDelay(e2, target); + mathint delayPendingAfter = getTargetAdminDelay_after(e2, target); + mathint delayEffectAfter = getTargetAdminDelay_effect(e2, target); + + assert ( + delayBefore != delayAfter || + delayPendingBefore != delayPendingAfter || + delayEffectBefore != delayEffectAfter + ) => ( + delayEffectBefore > clock(e1) && + delayEffectBefore <= clock(e2) && + delayAfter == delayPendingBefore && + delayPendingAfter == 0 && + delayEffectAfter == 0 + ); +} + +rule getTargetAdminDelayChangeCall(address target) { + env e; + + // values before + mathint delayBefore = getTargetAdminDelay(e, target); + mathint delayPendingBefore = getTargetAdminDelay_after(e, target); + mathint delayEffectBefore = getTargetAdminDelay_effect(e, target); + + // arbitrary function call + method f; calldataarg args; f(e, args); + + // values after + mathint delayAfter = getTargetAdminDelay(e, target); + mathint delayPendingAfter = getTargetAdminDelay_after(e, target); + mathint delayEffectAfter = getTargetAdminDelay_effect(e, target); + + // if anything changed ... + assert ( + delayBefore != delayAfter || + delayPendingBefore != delayPendingAfter || + delayEffectBefore != delayEffectAfter + ) => ( + ( + // ... it was the consequence of a call to setTargetAdminDelay + f.selector == sig:setTargetAdminDelay(address,uint32).selector + ) && ( + // ... delay cannot decrease instantly + delayAfter >= delayBefore + ) && ( + // ... if setback is not 0, value cannot change instantly + minSetback() > 0 => ( + delayBefore == delayAfter + ) + ) && ( + // ... if the value did not change and there is a minSetback, there must be something scheduled in the future + delayAfter == delayBefore && minSetback() > 0 => ( + delayEffectAfter >= clock(e) + minSetback() + ) + // note: if there is no minSetback, and if the caller "confirms" the current value, + // then this as immediate effect and nothing is scheduled + ) && ( + // ... if the value changed, then no further change should be scheduled + delayAfter != delayBefore => ( + delayPendingAfter == 0 && + delayEffectAfter == 0 + ) + ) + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ State transitions: getRoleGrantDelay │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule getRoleGrantDelayChangeTime(uint64 roleId) { + env e1; + env e2; + + // values before + mathint delayBefore = getRoleGrantDelay(e1, roleId); + mathint delayPendingBefore = getRoleGrantDelay_after(e1, roleId); + mathint delayEffectBefore = getRoleGrantDelay_effect(e1, roleId); + + // time pass: e1 → e2 + require clock(e1) <= clock(e2); + + // values after + mathint delayAfter = getRoleGrantDelay(e2, roleId); + mathint delayPendingAfter = getRoleGrantDelay_after(e2, roleId); + mathint delayEffectAfter = getRoleGrantDelay_effect(e2, roleId); + + assert ( + delayBefore != delayAfter || + delayPendingBefore != delayPendingAfter || + delayEffectBefore != delayEffectAfter + ) => ( + delayEffectBefore > clock(e1) && + delayEffectBefore <= clock(e2) && + delayAfter == delayPendingBefore && + delayPendingAfter == 0 && + delayEffectAfter == 0 + ); +} + +rule getRoleGrantDelayChangeCall(uint64 roleId) { + env e; + + // values before + mathint delayBefore = getRoleGrantDelay(e, roleId); + mathint delayPendingBefore = getRoleGrantDelay_after(e, roleId); + mathint delayEffectBefore = getRoleGrantDelay_effect(e, roleId); + + // arbitrary function call + method f; calldataarg args; f(e, args); + + // values after + mathint delayAfter = getRoleGrantDelay(e, roleId); + mathint delayPendingAfter = getRoleGrantDelay_after(e, roleId); + mathint delayEffectAfter = getRoleGrantDelay_effect(e, roleId); + + // if anything changed ... + assert ( + delayBefore != delayAfter || + delayPendingBefore != delayPendingAfter || + delayEffectBefore != delayEffectAfter + ) => ( + ( + // ... it was the consequence of a call to setTargetAdminDelay + f.selector == sig:setGrantDelay(uint64,uint32).selector + ) && ( + // ... delay cannot decrease instantly + delayAfter >= delayBefore + ) && ( + // ... if setback is not 0, value cannot change instantly + minSetback() > 0 => ( + delayBefore == delayAfter + ) + ) && ( + // ... if the value did not change and there is a minSetback, there must be something scheduled in the future + delayAfter == delayBefore && minSetback() > 0 => ( + delayEffectAfter >= clock(e) + minSetback() + ) + // note: if there is no minSetback, and if the caller "confirms" the current value, + // then this as immediate effect and nothing is scheduled + ) && ( + // ... if the value changed, then no further change should be scheduled + delayAfter != delayBefore => ( + delayPendingAfter == 0 && + delayEffectAfter == 0 + ) + ) + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ State transitions: getRoleAdmin & getRoleGuardian │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule getRoleAdminChangeCall(uint64 roleId) { + // values before + mathint adminIdBefore = getRoleAdmin(roleId); + + // arbitrary function call + env e; method f; calldataarg args; f(e, args); + + // values after + mathint adminIdAfter = getRoleAdmin(roleId); + + // transitions + assert adminIdBefore != adminIdAfter => f.selector == sig:setRoleAdmin(uint64,uint64).selector; +} + +rule getRoleGuardianChangeCall(uint64 roleId) { + // values before + mathint guardianIdBefore = getRoleGuardian(roleId); + + // arbitrary function call + env e; method f; calldataarg args; f(e, args); + + // values after + mathint guardianIdAfter = getRoleGuardian(roleId); + + // transitions + assert guardianIdBefore != guardianIdAfter => ( + f.selector == sig:setRoleGuardian(uint64,uint64).selector + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ State transitions: getNonce │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule getNonceChangeCall(bytes32 operationId) { + // values before + mathint nonceBefore = getNonce(operationId); + + // reasonable assumption + require nonceBefore < max_uint32; + + // arbitrary function call + env e; method f; calldataarg args; f(e, args); + + // values after + mathint nonceAfter = getNonce(operationId); + + // transitions + assert nonceBefore != nonceAfter => ( + f.selector == sig:schedule(address,bytes,uint48).selector && + nonceAfter == nonceBefore + 1 + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ State transitions: getSchedule │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule getScheduleChangeTime(bytes32 operationId) { + env e1; + env e2; + + // values before + mathint scheduleBefore = getSchedule(e1, operationId); + + // time pass: e1 → e2 + require clock(e1) <= clock(e2); + + // values after + mathint scheduleAfter = getSchedule(e2, operationId); + + // transition + assert scheduleBefore != scheduleAfter => ( + scheduleBefore + expiration() > clock(e1) && + scheduleBefore + expiration() <= clock(e2) && + scheduleAfter == 0 + ); +} + +rule getScheduleChangeCall(bytes32 operationId) { + env e; + + // values before + mathint scheduleBefore = getSchedule(e, operationId); + + // arbitrary function call + method f; calldataarg args; f(e, args); + + // values after + mathint scheduleAfter = getSchedule(e, operationId); + + // transitions + assert scheduleBefore != scheduleAfter => ( + (f.selector == sig:schedule(address,bytes,uint48).selector && scheduleAfter >= clock(e)) || + (f.selector == sig:execute(address,bytes).selector && scheduleAfter == 0 ) || + (f.selector == sig:cancel(address,address,bytes).selector && scheduleAfter == 0 ) || + (f.selector == sig:consumeScheduledOp(address,bytes).selector && scheduleAfter == 0 ) || + (isOnlyAuthorized(to_bytes4(f.selector)) && scheduleAfter == 0 ) + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Functions: restricted functions can only be called by owner │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule restrictedFunctions(env e) { + require nonpayable(e); + require sanity(e); + + method f; + calldataarg args; + + f(e,args); + + assert ( + f.selector == sig:labelRole(uint64,string).selector || + f.selector == sig:setRoleAdmin(uint64,uint64).selector || + f.selector == sig:setRoleGuardian(uint64,uint64).selector || + f.selector == sig:setGrantDelay(uint64,uint32).selector || + f.selector == sig:setTargetAdminDelay(address,uint32).selector || + f.selector == sig:updateAuthority(address,address).selector || + f.selector == sig:setTargetClosed(address,bool).selector || + f.selector == sig:setTargetFunctionRole(address,bytes4[],uint64).selector + ) => ( + hasRole_isMember(e, ADMIN_ROLE(), e.msg.sender) || e.msg.sender == currentContract + ); +} + +rule restrictedFunctionsGrantRole(env e) { + require nonpayable(e); + require sanity(e); + + uint64 roleId; + address account; + uint32 executionDelay; + + // We want to check that the caller has the admin role before we possibly grant it. + bool hasAdminRoleBefore = hasRole_isMember(e, getRoleAdmin(roleId), e.msg.sender); + + grantRole(e, roleId, account, executionDelay); + + assert hasAdminRoleBefore || e.msg.sender == currentContract; +} + +rule restrictedFunctionsRevokeRole(env e) { + require nonpayable(e); + require sanity(e); + + uint64 roleId; + address account; + + // This is needed if roleId is self-administered, the `revokeRole` call could target + // e.msg.sender and remove the very role that is necessary for authorizing the call. + bool hasAdminRoleBefore = hasRole_isMember(e, getRoleAdmin(roleId), e.msg.sender); + + revokeRole(e, roleId, account); + + assert hasAdminRoleBefore || e.msg.sender == currentContract; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Functions: canCall delay is enforced for calls to execute (only for others target) │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +// getScheduleChangeCall proves that only {schedule} can set an operation schedule to a non 0 value +rule callDelayEnforce_scheduleInTheFuture(env e) { + address target; + bytes data; + uint48 when; + + // Condition: calling a third party with a delay + mathint delay = canCallExtended_delay(e, e.msg.sender, target, data); + require delay > 0; + + // Schedule + schedule(e, target, data, when); + + // Get operation schedule + mathint timepoint = getSchedule(e, hashOperation(e.msg.sender, target, data)); + + // Schedule is far enough in the future + assert timepoint == max(clock(e) + delay, when); +} + +rule callDelayEnforce_executeAfterDelay(env e) { + address target; + bytes data; + + // Condition: calling a third party with a delay + mathint delay = canCallExtended_delay(e, e.msg.sender, target, data); + + // Get operation schedule before + mathint scheduleBefore = getSchedule(e, hashOperation(e.msg.sender, target, data)); + + // Do call + execute@withrevert(e, target, data); + bool success = !lastReverted; + + // Get operation schedule after + mathint scheduleAfter = getSchedule(e, hashOperation(e.msg.sender, target, data)); + + // Can only execute if delay is set and has passed + assert success => ( + delay > 0 => ( + scheduleBefore != 0 && + scheduleBefore <= clock(e) + ) && + scheduleAfter == 0 + ); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/DoubleEndedQueue.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/DoubleEndedQueue.spec new file mode 100644 index 0000000..3b71bb4 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20.spec new file mode 100644 index 0000000..21a0335 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20FlashMint.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20FlashMint.spec new file mode 100644 index 0000000..6942495 --- /dev/null +++ b/typescript/packages/account-modules/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 ERC-3156 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)) trackedTransferredAmount; + +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 { + trackedTransferredAmount[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) => trackedTransferredAmount[receiver][recipient] == to_mathint(fees); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20Wrapper.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20Wrapper.spec new file mode 100644 index 0000000..04e6704 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC721.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC721.spec new file mode 100644 index 0000000..bad4c47 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/EnumerableMap.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/EnumerableMap.spec new file mode 100644 index 0000000..1801d99 --- /dev/null +++ b/typescript/packages/account-modules/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 _positionOf(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 _positionOf are inverse of one │ +│ another. This proves that we have a bijection between indices (the enumerability part) and keys (the entries that │ +│ are set and removed from the EnumerableMap). │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant consistencyIndex(uint256 index) + index < length() => to_mathint(_positionOf(key_at(index))) == index + 1 + { + preserved remove(bytes32 key) { + requireInvariant consistencyIndex(require_uint256(length() - 1)); + } + } + +invariant consistencyKey(bytes32 key) + contains(key) => ( + _positionOf(key) > 0 && + _positionOf(key) <= length() && + key_at(require_uint256(_positionOf(key) - 1)) == key + ) + { + preserved remove(bytes32 otherKey) { + requireInvariant consistencyKey(otherKey); + requireInvariant atUniqueness( + require_uint256(_positionOf(key) - 1), + require_uint256(_positionOf(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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/EnumerableSet.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/EnumerableSet.spec new file mode 100644 index 0000000..94d0a91 --- /dev/null +++ b/typescript/packages/account-modules/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 _positionOf(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 _positionOf 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() => _positionOf(at_(index)) == require_uint256(index + 1) + { + preserved remove(bytes32 key) { + requireInvariant consistencyIndex(require_uint256(length() - 1)); + } + } + +invariant consistencyKey(bytes32 key) + contains(key) => ( + _positionOf(key) > 0 && + _positionOf(key) <= length() && + at_(require_uint256(_positionOf(key) - 1)) == key + ) + { + preserved remove(bytes32 otherKey) { + requireInvariant consistencyKey(otherKey); + requireInvariant atUniqueness( + require_uint256(_positionOf(key) - 1), + require_uint256(_positionOf(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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Initializable.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Initializable.spec new file mode 100644 index 0000000..07c2930 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Nonces.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Nonces.spec new file mode 100644 index 0000000..4647c5c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Nonces.spec @@ -0,0 +1,92 @@ +import "helpers/helpers.spec"; + +methods { + function nonces(address) external returns (uint256) envfree; + function useNonce(address) external returns (uint256) envfree; + function useCheckedNonce(address,uint256) external envfree; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +function nonceSanity(address account) returns bool { + return nonces(account) < max_uint256; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: useNonce uses nonce │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule useNonce(address account) { + require nonceSanity(account); + + address other; + + mathint nonceBefore = nonces(account); + mathint otherNonceBefore = nonces(other); + + mathint nonceUsed = useNonce@withrevert(account); + bool success = !lastReverted; + + mathint nonceAfter = nonces(account); + mathint otherNonceAfter = nonces(other); + + // liveness + assert success, "doesn't revert"; + + // effect + assert nonceAfter == nonceBefore + 1 && nonceBefore == nonceUsed, "nonce is used"; + + // no side effect + assert otherNonceBefore != otherNonceAfter => other == account, "no other nonce is used"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: useCheckedNonce uses only the current nonce │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule useCheckedNonce(address account, uint256 currentNonce) { + require nonceSanity(account); + + address other; + + mathint nonceBefore = nonces(account); + mathint otherNonceBefore = nonces(other); + + useCheckedNonce@withrevert(account, currentNonce); + bool success = !lastReverted; + + mathint nonceAfter = nonces(account); + mathint otherNonceAfter = nonces(other); + + // liveness + assert success <=> to_mathint(currentNonce) == nonceBefore, "works iff current nonce is correct"; + + // effect + assert success => nonceAfter == nonceBefore + 1, "nonce is used"; + + // no side effect + assert otherNonceBefore != otherNonceAfter => other == account, "no other nonce is used"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: nonce only increments │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule nonceOnlyIncrements(address account) { + require nonceSanity(account); + + mathint nonceBefore = nonces(account); + + env e; method f; calldataarg args; + f(e, args); + + mathint nonceAfter = nonces(account); + + assert nonceAfter == nonceBefore || nonceAfter == nonceBefore + 1, "nonce only increments"; +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Ownable.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Ownable.spec new file mode 100644 index 0000000..0d50813 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Ownable2Step.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Ownable2Step.spec new file mode 100644 index 0000000..d13c6d3 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Pausable.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Pausable.spec new file mode 100644 index 0000000..a7aff9c --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/TimelockController.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/TimelockController.spec new file mode 100644 index 0000000..5123768 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/helpers/helpers.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/helpers/helpers.spec new file mode 100644 index 0000000..7125ce2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/helpers/helpers.spec @@ -0,0 +1,12 @@ +// environment +definition nonpayable(env e) returns bool = e.msg.value == 0; +definition nonzerosender(env e) returns bool = e.msg.sender != 0; +definition sanity(env e) returns bool = clock(e) > 0 && clock(e) <= max_uint48; + +// 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; + +// time +definition clock(env e) returns mathint = to_mathint(e.block.timestamp); +definition isSetAndPast(env e, uint48 timepoint) returns bool = timepoint != 0 && to_mathint(timepoint) <= clock(e); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessControl.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessControl.spec new file mode 100644 index 0000000..5c395b0 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessControlDefaultAdminRules.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessControlDefaultAdminRules.spec new file mode 100644 index 0000000..d02db18 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManaged.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManaged.spec new file mode 100644 index 0000000..886d917 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManaged.spec @@ -0,0 +1,5 @@ +methods { + function authority() external returns (address) envfree; + function isConsumingScheduledOp() external returns (bytes4) envfree; + function setAuthority(address) external; +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManager.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManager.spec new file mode 100644 index 0000000..5d305f7 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManager.spec @@ -0,0 +1,33 @@ +methods { + function ADMIN_ROLE() external returns (uint64) envfree; + function PUBLIC_ROLE() external returns (uint64) envfree; + function canCall(address,address,bytes4) external returns (bool,uint32); + function expiration() external returns (uint32) envfree; + function minSetback() external returns (uint32) envfree; + function isTargetClosed(address) external returns (bool) envfree; + function getTargetFunctionRole(address,bytes4) external returns (uint64) envfree; + function getTargetAdminDelay(address) external returns (uint32); + function getRoleAdmin(uint64) external returns (uint64) envfree; + function getRoleGuardian(uint64) external returns (uint64) envfree; + function getRoleGrantDelay(uint64) external returns (uint32); + function getAccess(uint64,address) external returns (uint48,uint32,uint32,uint48); + function hasRole(uint64,address) external returns (bool,uint32); + function labelRole(uint64,string) external; + function grantRole(uint64,address,uint32) external; + function revokeRole(uint64,address) external; + function renounceRole(uint64,address) external; + function setRoleAdmin(uint64,uint64) external; + function setRoleGuardian(uint64,uint64) external; + function setGrantDelay(uint64,uint32) external; + function setTargetFunctionRole(address,bytes4[],uint64) external; + function setTargetAdminDelay(address,uint32) external; + function setTargetClosed(address,bool) external; + function hashOperation(address,address,bytes) external returns (bytes32) envfree; + function getNonce(bytes32) external returns (uint32) envfree; + function getSchedule(bytes32) external returns (uint48); + function schedule(address,bytes,uint48) external returns (bytes32,uint32); + function execute(address,bytes) external returns (uint32); + function cancel(address,address,bytes) external returns (uint32); + function consumeScheduledOp(address,bytes) external; + function updateAuthority(address,address) external; +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC20.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC20.spec new file mode 100644 index 0000000..100901a --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC2612.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC2612.spec new file mode 100644 index 0000000..4ecc17b --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashBorrower.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashBorrower.spec new file mode 100644 index 0000000..733c168 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashLender.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashLender.spec new file mode 100644 index 0000000..66ed14c --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC5313.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC5313.spec new file mode 100644 index 0000000..f1d469f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC5313.spec @@ -0,0 +1,3 @@ +methods { + function owner() external returns (address) envfree; +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC721.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC721.spec new file mode 100644 index 0000000..34ff50b --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC721Receiver.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC721Receiver.spec new file mode 100644 index 0000000..e6bdf42 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IOwnable.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IOwnable.spec new file mode 100644 index 0000000..4d7c925 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IOwnable2Step.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IOwnable2Step.spec new file mode 100644 index 0000000..e6a9957 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/AccessControl.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/AccessControl.sol new file mode 100644 index 0000000..0c7ec60 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/AccessControl.sol @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (access/AccessControl.sol) + +pragma solidity ^0.8.20; + +import {IAccessControl} from "./IAccessControl.sol"; +import {Context} from "../utils/Context.sol"; +import {IERC165, 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); + _; + } + + /// @inheritdoc IERC165 + 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` from `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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol new file mode 100644 index 0000000..23f0770 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (access/IAccessControl.sol) + +pragma solidity >=0.8.4; + +/** + * @dev External interface of AccessControl declared to support ERC-165 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 to signal 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. This account bears the admin role (for the granted role). + * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}. + */ + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable.sol new file mode 100644 index 0000000..bd96f66 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol new file mode 100644 index 0000000..3a0747c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.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. + * + * This extension of the {Ownable} contract includes a two-step mechanism to transfer + * ownership, where the new owner must call {acceptOwnership} in order to replace the + * old one. This can help prevent common mistakes, such as transfers of ownership to + * incorrect accounts, or to contracts that are unable to interact with the + * permission system. + * + * 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. + * + * Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer. + */ + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/README.adoc new file mode 100644 index 0000000..b89865b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/README.adoc @@ -0,0 +1,45 @@ += 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. + +- {AccessManager} is a full-fledged access control solution for smart contract systems. Allows creating and assigning multiple hierarchical roles with execution delays for each account across various contracts. +- {AccessManaged} delegates its access control to an authority that dictates the permissions of the managed contract. It's compatible with an AccessManager as an authority. +- {AccessControl} provides a per-contract role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts within the same instance. +- {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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sol new file mode 100644 index 0000000..77a7e45 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sol @@ -0,0 +1,372 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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"; +import {IERC165} from "../../utils/introspection/ERC165.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}. + * * Role transfers must wait at least one block after scheduling before it can be accepted. + * * 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); + } + + /// @inheritdoc IERC165 + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId); + } + + /// @inheritdoc IERC5313 + 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); + } + + /// @inheritdoc AccessControl + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlEnumerable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlEnumerable.sol new file mode 100644 index 0000000..f2d79fd --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlEnumerable.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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"; +import {IERC165} from "../../utils/introspection/ERC165.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; + + /// @inheritdoc IERC165 + 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 Return all accounts that have `role` + * + * 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 getRoleMembers(bytes32 role) public view virtual returns (address[] memory) { + return _roleMembers[role].values(); + } + + /** + * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlDefaultAdminRules.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlDefaultAdminRules.sol new file mode 100644 index 0000000..616b4d8 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlDefaultAdminRules.sol @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (access/extensions/IAccessControlDefaultAdminRules.sol) + +pragma solidity >=0.8.4; + +import {IAccessControl} from "../IAccessControl.sol"; + +/** + * @dev External interface of AccessControlDefaultAdminRules declared to support ERC-165 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlEnumerable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlEnumerable.sol new file mode 100644 index 0000000..90371fa --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlEnumerable.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (access/extensions/IAccessControlEnumerable.sol) + +pragma solidity >=0.8.4; + +import {IAccessControl} from "../IAccessControl.sol"; + +/** + * @dev External interface of AccessControlEnumerable declared to support ERC-165 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManaged.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManaged.sol new file mode 100644 index 0000000..382a308 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManaged.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (access/manager/AccessManaged.sol) + +pragma solidity ^0.8.20; + +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 unambiguously 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManager.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManager.sol new file mode 100644 index 0000000..0510805 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManager.sol @@ -0,0 +1,740 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.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; + } + + /** + * @dev The identifier of the admin role. Required to perform most configuration operations including + * other roles' management and target restrictions. + */ + uint64 public constant ADMIN_ROLE = type(uint64).min; // 0 + + /** + * @dev The identifier of the public role. Automatically granted to all addresses with no delay. + */ + 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. + * See {AccessManager} description for a detailed breakdown of the authorization logic. + */ + 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 { + _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, revert + 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 call is not authorized, 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 and roles logic. + * + * WARNING: Carefully review the considerations of {AccessManaged-restricted} since they apply to this modifier. + */ + 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 adminRestricted, 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, getTargetFunctionRole(address(this), selector), 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 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 adminRestricted, uint64 roleId, uint32 operationDelay) = _getAdminRestrictions(data); + + // isTargetClosed apply to non-admin-restricted function + if (!adminRestricted && isTargetClosed(address(this))) { + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sol new file mode 100644 index 0000000..8b04709 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.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) { + bytes memory data = abi.encodeCall(IAuthority.canCall, (caller, target, selector)); + + assembly ("memory-safe") { + mstore(0x00, 0x00) + mstore(0x20, 0x00) + + if staticcall(gas(), authority, add(data, 0x20), mload(data), 0x00, 0x40) { + immediate := mload(0x00) + delay := mload(0x20) + + // If delay does not fit in a uint32, return 0 (no delay) + // equivalent to: if gt(delay, 0xFFFFFFFF) { delay := 0 } + delay := mul(delay, iszero(shr(32, delay))) + } + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol new file mode 100644 index 0000000..c93c711 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (access/manager/IAccessManaged.sol) + +pragma solidity >=0.8.4; + +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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sol new file mode 100644 index 0000000..925be90 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sol @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (access/manager/IAccessManager.sol) + +pragma solidity >=0.8.4; + +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 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 `allowed` 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 the admin functions in the manager itself. These are defined by the + * {AccessManager} documentation. + */ + 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. + * + * NOTE: When the manager itself is closed, admin functions are still accessible to avoid locking the contract. + */ + 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 since, uint32 currentDelay, uint32 pendingDelay, uint48 effect); + + /** + * @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 isMember, uint32 executionDelay); + + /** + * @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. + * + * Closing the manager itself won't disable access to admin methods to avoid locking the 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 operationId, uint32 nonce); + + /** + * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAuthority.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAuthority.sol new file mode 100644 index 0000000..6ad902c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAuthority.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (access/manager/IAuthority.sol) + +pragma solidity >=0.4.16; + +/** + * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/Account.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/Account.sol new file mode 100644 index 0000000..19c64d7 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/Account.sol @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (account/Account.sol) + +pragma solidity ^0.8.20; + +import {PackedUserOperation, IAccount, IEntryPoint} from "../interfaces/draft-IERC4337.sol"; +import {ERC4337Utils} from "./utils/draft-ERC4337Utils.sol"; +import {AbstractSigner} from "../utils/cryptography/signers/AbstractSigner.sol"; + +/** + * @dev A simple ERC4337 account implementation. This base implementation only includes the minimal logic to process + * user operations. + * + * Developers must implement the {AbstractSigner-_rawSignatureValidation} function to define the account's validation logic. + * + * NOTE: This core account doesn't include any mechanism for performing arbitrary external calls. This is an essential + * feature that all Account should have. We leave it up to the developers to implement the mechanism of their choice. + * Common choices include ERC-6900, ERC-7579 and ERC-7821 (among others). + * + * IMPORTANT: Implementing a mechanism to validate signatures is a security-sensitive operation as it may allow an + * attacker to bypass the account's security measures. Check out {SignerECDSA}, {SignerP256}, or {SignerRSA} for + * digital signature validation implementations. + * + * @custom:stateless + */ +abstract contract Account is AbstractSigner, IAccount { + /** + * @dev Unauthorized call to the account. + */ + error AccountUnauthorized(address sender); + + /** + * @dev Revert if the caller is not the entry point or the account itself. + */ + modifier onlyEntryPointOrSelf() { + _checkEntryPointOrSelf(); + _; + } + + /** + * @dev Revert if the caller is not the entry point. + */ + modifier onlyEntryPoint() { + _checkEntryPoint(); + _; + } + + /** + * @dev Canonical entry point for the account that forwards and validates user operations. + */ + function entryPoint() public view virtual returns (IEntryPoint) { + return ERC4337Utils.ENTRYPOINT_V08; + } + + /** + * @dev Return the account nonce for the canonical sequence. + */ + function getNonce() public view virtual returns (uint256) { + return getNonce(0); + } + + /** + * @dev Return the account nonce for a given sequence (key). + */ + function getNonce(uint192 key) public view virtual returns (uint256) { + return entryPoint().getNonce(address(this), key); + } + + /** + * @inheritdoc IAccount + */ + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash, + uint256 missingAccountFunds + ) public virtual onlyEntryPoint returns (uint256) { + uint256 validationData = _validateUserOp(userOp, userOpHash); + _payPrefund(missingAccountFunds); + return validationData; + } + + /** + * @dev Returns the validationData for a given user operation. By default, this checks the signature of the + * signable hash (produced by {_signableUserOpHash}) using the abstract signer ({AbstractSigner-_rawSignatureValidation}). + * + * NOTE: The userOpHash is assumed to be correct. Calling this function with a userOpHash that does not match the + * userOp will result in undefined behavior. + */ + function _validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) internal virtual returns (uint256) { + return + _rawSignatureValidation(_signableUserOpHash(userOp, userOpHash), userOp.signature) + ? ERC4337Utils.SIG_VALIDATION_SUCCESS + : ERC4337Utils.SIG_VALIDATION_FAILED; + } + + /** + * @dev Virtual function that returns the signable hash for a user operations. Since v0.8.0 of the entrypoint, + * `userOpHash` is an EIP-712 hash that can be signed directly. + */ + function _signableUserOpHash( + PackedUserOperation calldata /*userOp*/, + bytes32 userOpHash + ) internal view virtual returns (bytes32) { + return userOpHash; + } + + /** + * @dev Sends the missing funds for executing the user operation to the {entrypoint}. + * The `missingAccountFunds` must be defined by the entrypoint when calling {validateUserOp}. + */ + function _payPrefund(uint256 missingAccountFunds) internal virtual { + if (missingAccountFunds > 0) { + (bool success, ) = payable(msg.sender).call{value: missingAccountFunds}(""); + success; // Silence warning. The entrypoint should validate the result. + } + } + + /** + * @dev Ensures the caller is the {entrypoint}. + */ + function _checkEntryPoint() internal view virtual { + address sender = msg.sender; + if (sender != address(entryPoint())) { + revert AccountUnauthorized(sender); + } + } + + /** + * @dev Ensures the caller is the {entrypoint} or the account itself. + */ + function _checkEntryPointOrSelf() internal view virtual { + address sender = msg.sender; + if (sender != address(this) && sender != address(entryPoint())) { + revert AccountUnauthorized(sender); + } + } + + /** + * @dev Receive Ether. + */ + receive() external payable virtual {} +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/README.adoc new file mode 100644 index 0000000..dc3c9a0 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/README.adoc @@ -0,0 +1,30 @@ += Account +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/account + +This directory includes contracts to build accounts for ERC-4337. These include: + + * {Account}: An ERC-4337 smart account implementation that includes the core logic to process user operations. + * {AccountERC7579}: An extension of `Account` that implements support for ERC-7579 modules. + * {AccountERC7579Hooked}: An extension of `AccountERC7579` with support for a single hook module (type 4). + * {ERC7821}: Minimal batch executor implementation contracts. Useful to enable easy batch execution for smart contracts. + * {ERC4337Utils}: Utility functions for working with ERC-4337 user operations. + * {ERC7579Utils}: Utility functions for working with ERC-7579 modules and account modularity. + +== Core + +{{Account}} + +== Extensions + +{{AccountERC7579}} + +{{AccountERC7579Hooked}} + +{{ERC7821}} + +== Utilities + +{{ERC4337Utils}} + +{{ERC7579Utils}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579.sol new file mode 100644 index 0000000..40ea71e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579.sol @@ -0,0 +1,405 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (account/extensions/draft-AccountERC7579.sol) + +pragma solidity ^0.8.26; + +import {PackedUserOperation} from "../../interfaces/draft-IERC4337.sol"; +import {IERC1271} from "../../interfaces/IERC1271.sol"; +import {IERC7579Module, IERC7579Validator, IERC7579Execution, IERC7579AccountConfig, IERC7579ModuleConfig, MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR, MODULE_TYPE_FALLBACK} from "../../interfaces/draft-IERC7579.sol"; +import {ERC7579Utils, Mode, CallType, ExecType} from "../../account/utils/draft-ERC7579Utils.sol"; +import {EnumerableSet} from "../../utils/structs/EnumerableSet.sol"; +import {Bytes} from "../../utils/Bytes.sol"; +import {Packing} from "../../utils/Packing.sol"; +import {Address} from "../../utils/Address.sol"; +import {Calldata} from "../../utils/Calldata.sol"; +import {Account} from "../Account.sol"; + +/** + * @dev Extension of {Account} that implements support for ERC-7579 modules. + * + * To comply with the ERC-1271 support requirement, this contract defers signature validation to + * installed validator modules by calling {IERC7579Validator-isValidSignatureWithSender}. + * + * This contract does not implement validation logic for user operations since this functionality + * is often delegated to self-contained validation modules. Developers must install a validator module + * upon initialization (or any other mechanism to enable execution from the account): + * + * ```solidity + * contract MyAccountERC7579 is AccountERC7579, Initializable { + * function initializeAccount(address validator, bytes calldata validatorData) public initializer { + * _installModule(MODULE_TYPE_VALIDATOR, validator, validatorData); + * } + * } + * ``` + * + * [NOTE] + * ==== + * * Hook support is not included. See {AccountERC7579Hooked} for a version that hooks to execution. + * * Validator selection, when verifying either ERC-1271 signature or ERC-4337 UserOperation is implemented in + * internal virtual functions {_extractUserOpValidator} and {_extractSignatureValidator}. Both are implemented + * following common practices. However, this part is not standardized in ERC-7579 (or in any follow-up ERC). Some + * accounts may want to override these internal functions. + * * When combined with {ERC7739}, resolution ordering of {isValidSignature} may have an impact ({ERC7739} does not + * call super). Manual resolution might be necessary. + * * Static calls (using callType `0xfe`) are currently NOT supported. + * ==== + * + * WARNING: Removing all validator modules will render the account inoperable, as no user operations can be validated thereafter. + */ +abstract contract AccountERC7579 is Account, IERC1271, IERC7579Execution, IERC7579AccountConfig, IERC7579ModuleConfig { + using Bytes for *; + using ERC7579Utils for *; + using EnumerableSet for *; + using Packing for bytes32; + + EnumerableSet.AddressSet private _validators; + EnumerableSet.AddressSet private _executors; + mapping(bytes4 selector => address) private _fallbacks; + + /// @dev The account's {fallback} was called with a selector that doesn't have an installed handler. + error ERC7579MissingFallbackHandler(bytes4 selector); + + /// @dev Modifier that checks if the caller is an installed module of the given type. + modifier onlyModule(uint256 moduleTypeId, bytes calldata additionalContext) { + _checkModule(moduleTypeId, msg.sender, additionalContext); + _; + } + + /// @dev See {_fallback}. + fallback(bytes calldata) external payable virtual returns (bytes memory) { + return _fallback(); + } + + /// @inheritdoc IERC7579AccountConfig + function accountId() public view virtual returns (string memory) { + // vendorname.accountname.semver + return "@openzeppelin/community-contracts.AccountERC7579.v0.0.0"; + } + + /** + * @inheritdoc IERC7579AccountConfig + * + * @dev Supported call types: + * * Single (`0x00`): A single transaction execution. + * * Batch (`0x01`): A batch of transactions execution. + * * Delegate (`0xff`): A delegate call execution. + * + * Supported exec types: + * * Default (`0x00`): Default execution type (revert on failure). + * * Try (`0x01`): Try execution type (emits ERC7579TryExecuteFail on failure). + */ + function supportsExecutionMode(bytes32 encodedMode) public view virtual returns (bool) { + (CallType callType, ExecType execType, , ) = Mode.wrap(encodedMode).decodeMode(); + return + (callType == ERC7579Utils.CALLTYPE_SINGLE || + callType == ERC7579Utils.CALLTYPE_BATCH || + callType == ERC7579Utils.CALLTYPE_DELEGATECALL) && + (execType == ERC7579Utils.EXECTYPE_DEFAULT || execType == ERC7579Utils.EXECTYPE_TRY); + } + + /** + * @inheritdoc IERC7579AccountConfig + * + * @dev Supported module types: + * + * * Validator: A module used during the validation phase to determine if a transaction is valid and + * should be executed on the account. + * * Executor: A module that can execute transactions on behalf of the smart account via a callback. + * * Fallback Handler: A module that can extend the fallback functionality of a smart account. + */ + function supportsModule(uint256 moduleTypeId) public view virtual returns (bool) { + return + moduleTypeId == MODULE_TYPE_VALIDATOR || + moduleTypeId == MODULE_TYPE_EXECUTOR || + moduleTypeId == MODULE_TYPE_FALLBACK; + } + + /// @inheritdoc IERC7579ModuleConfig + function installModule( + uint256 moduleTypeId, + address module, + bytes calldata initData + ) public virtual onlyEntryPointOrSelf { + _installModule(moduleTypeId, module, initData); + } + + /// @inheritdoc IERC7579ModuleConfig + function uninstallModule( + uint256 moduleTypeId, + address module, + bytes calldata deInitData + ) public virtual onlyEntryPointOrSelf { + _uninstallModule(moduleTypeId, module, deInitData); + } + + /// @inheritdoc IERC7579ModuleConfig + function isModuleInstalled( + uint256 moduleTypeId, + address module, + bytes calldata additionalContext + ) public view virtual returns (bool) { + if (moduleTypeId == MODULE_TYPE_VALIDATOR) return _validators.contains(module); + if (moduleTypeId == MODULE_TYPE_EXECUTOR) return _executors.contains(module); + if (moduleTypeId == MODULE_TYPE_FALLBACK) return _fallbacks[bytes4(additionalContext[0:4])] == module; + return false; + } + + /// @inheritdoc IERC7579Execution + function execute(bytes32 mode, bytes calldata executionCalldata) public payable virtual onlyEntryPointOrSelf { + _execute(Mode.wrap(mode), executionCalldata); + } + + /// @inheritdoc IERC7579Execution + function executeFromExecutor( + bytes32 mode, + bytes calldata executionCalldata + ) + public + payable + virtual + onlyModule(MODULE_TYPE_EXECUTOR, Calldata.emptyBytes()) + returns (bytes[] memory returnData) + { + return _execute(Mode.wrap(mode), executionCalldata); + } + + /** + * @dev Implement ERC-1271 through IERC7579Validator modules. If module based validation fails, fallback to + * "native" validation by the abstract signer. + * + * NOTE: when combined with {ERC7739}, resolution ordering may have an impact ({ERC7739} does not call super). + * Manual resolution might be necessary. + */ + function isValidSignature(bytes32 hash, bytes calldata signature) public view virtual returns (bytes4) { + // check signature length is enough for extraction + if (signature.length >= 20) { + (address module, bytes calldata innerSignature) = _extractSignatureValidator(signature); + // if module is not installed, skip + if (isModuleInstalled(MODULE_TYPE_VALIDATOR, module, Calldata.emptyBytes())) { + // try validation, skip any revert + try IERC7579Validator(module).isValidSignatureWithSender(msg.sender, hash, innerSignature) returns ( + bytes4 magic + ) { + return magic; + } catch {} + } + } + return bytes4(0xffffffff); + } + + /** + * @dev Validates a user operation with {_signableUserOpHash} and returns the validation data + * if the module specified by the first 20 bytes of the nonce key is installed. Falls back to + * {Account-_validateUserOp} otherwise. + * + * See {_extractUserOpValidator} for the module extraction logic. + */ + function _validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) internal virtual override returns (uint256) { + address module = _extractUserOpValidator(userOp); + return + isModuleInstalled(MODULE_TYPE_VALIDATOR, module, Calldata.emptyBytes()) + ? IERC7579Validator(module).validateUserOp(userOp, _signableUserOpHash(userOp, userOpHash)) + : super._validateUserOp(userOp, userOpHash); + } + + /** + * @dev ERC-7579 execution logic. See {supportsExecutionMode} for supported modes. + * + * Reverts if the call type is not supported. + */ + function _execute( + Mode mode, + bytes calldata executionCalldata + ) internal virtual returns (bytes[] memory returnData) { + (CallType callType, ExecType execType, , ) = mode.decodeMode(); + if (callType == ERC7579Utils.CALLTYPE_SINGLE) return executionCalldata.execSingle(execType); + if (callType == ERC7579Utils.CALLTYPE_BATCH) return executionCalldata.execBatch(execType); + if (callType == ERC7579Utils.CALLTYPE_DELEGATECALL) return executionCalldata.execDelegateCall(execType); + revert ERC7579Utils.ERC7579UnsupportedCallType(callType); + } + + /** + * @dev Installs a module of the given type with the given initialization data. + * + * For the fallback module type, the `initData` is expected to be the (packed) concatenation of a 4-byte + * selector and the rest of the data to be sent to the handler when calling {IERC7579Module-onInstall}. + * + * Requirements: + * + * * Module type must be supported. See {supportsModule}. Reverts with {ERC7579Utils-ERC7579UnsupportedModuleType}. + * * Module must be of the given type. Reverts with {ERC7579Utils-ERC7579MismatchedModuleTypeId}. + * * Module must not be already installed. Reverts with {ERC7579Utils-ERC7579AlreadyInstalledModule}. + * + * Emits a {IERC7579ModuleConfig-ModuleInstalled} event. + */ + function _installModule(uint256 moduleTypeId, address module, bytes memory initData) internal virtual { + require(supportsModule(moduleTypeId), ERC7579Utils.ERC7579UnsupportedModuleType(moduleTypeId)); + require( + IERC7579Module(module).isModuleType(moduleTypeId), + ERC7579Utils.ERC7579MismatchedModuleTypeId(moduleTypeId, module) + ); + + if (moduleTypeId == MODULE_TYPE_VALIDATOR) { + require(_validators.add(module), ERC7579Utils.ERC7579AlreadyInstalledModule(moduleTypeId, module)); + } else if (moduleTypeId == MODULE_TYPE_EXECUTOR) { + require(_executors.add(module), ERC7579Utils.ERC7579AlreadyInstalledModule(moduleTypeId, module)); + } else if (moduleTypeId == MODULE_TYPE_FALLBACK) { + bytes4 selector; + (selector, initData) = _decodeFallbackData(initData); + require( + _fallbacks[selector] == address(0), + ERC7579Utils.ERC7579AlreadyInstalledModule(moduleTypeId, module) + ); + _fallbacks[selector] = module; + } + + IERC7579Module(module).onInstall(initData); + emit ModuleInstalled(moduleTypeId, module); + } + + /** + * @dev Uninstalls a module of the given type with the given de-initialization data. + * + * For the fallback module type, the `deInitData` is expected to be the (packed) concatenation of a 4-byte + * selector and the rest of the data to be sent to the handler when calling {IERC7579Module-onUninstall}. + * + * Requirements: + * + * * Module must be already installed. Reverts with {ERC7579Utils-ERC7579UninstalledModule} otherwise. + */ + function _uninstallModule(uint256 moduleTypeId, address module, bytes memory deInitData) internal virtual { + require(supportsModule(moduleTypeId), ERC7579Utils.ERC7579UnsupportedModuleType(moduleTypeId)); + + if (moduleTypeId == MODULE_TYPE_VALIDATOR) { + require(_validators.remove(module), ERC7579Utils.ERC7579UninstalledModule(moduleTypeId, module)); + } else if (moduleTypeId == MODULE_TYPE_EXECUTOR) { + require(_executors.remove(module), ERC7579Utils.ERC7579UninstalledModule(moduleTypeId, module)); + } else if (moduleTypeId == MODULE_TYPE_FALLBACK) { + bytes4 selector; + (selector, deInitData) = _decodeFallbackData(deInitData); + require( + _fallbackHandler(selector) == module && module != address(0), + ERC7579Utils.ERC7579UninstalledModule(moduleTypeId, module) + ); + delete _fallbacks[selector]; + } + + IERC7579Module(module).onUninstall(deInitData); + emit ModuleUninstalled(moduleTypeId, module); + } + + /** + * @dev Fallback function that delegates the call to the installed handler for the given selector. + * + * Reverts with {ERC7579MissingFallbackHandler} if the handler is not installed. + * + * Calls the handler with the original `msg.sender` appended at the end of the calldata following + * the ERC-2771 format. + */ + function _fallback() internal virtual returns (bytes memory) { + address handler = _fallbackHandler(msg.sig); + require(handler != address(0), ERC7579MissingFallbackHandler(msg.sig)); + + // From https://eips.ethereum.org/EIPS/eip-7579#fallback[ERC-7579 specifications]: + // - MUST utilize ERC-2771 to add the original msg.sender to the calldata sent to the fallback handler + // - MUST use call to invoke the fallback handler + (bool success, bytes memory returndata) = handler.call{value: msg.value}( + abi.encodePacked(msg.data, msg.sender) + ); + + if (success) return returndata; + + assembly ("memory-safe") { + revert(add(returndata, 0x20), mload(returndata)) + } + } + + /// @dev Returns the fallback handler for the given selector. Returns `address(0)` if not installed. + function _fallbackHandler(bytes4 selector) internal view virtual returns (address) { + return _fallbacks[selector]; + } + + /// @dev Checks if the module is installed. Reverts if the module is not installed. + function _checkModule( + uint256 moduleTypeId, + address module, + bytes calldata additionalContext + ) internal view virtual { + require( + isModuleInstalled(moduleTypeId, module, additionalContext), + ERC7579Utils.ERC7579UninstalledModule(moduleTypeId, module) + ); + } + + /** + * @dev Extracts the nonce validator from the user operation. + * + * To construct a nonce key, set nonce as follows: + * + * ``` + * | | + * ``` + * NOTE: The default behavior of this function replicates the behavior of + * https://github.com/rhinestonewtf/safe7579/blob/bb29e8b1a66658790c4169e72608e27d220f79be/src/Safe7579.sol#L266[Safe adapter], + * https://github.com/etherspot/etherspot-prime-contracts/blob/cfcdb48c4172cea0d66038324c0bae3288aa8caa/src/modular-etherspot-wallet/wallet/ModularEtherspotWallet.sol#L227[Etherspot's Prime Account], and + * https://github.com/erc7579/erc7579-implementation/blob/16138d1afd4e9711f6c1425133538837bd7787b5/src/MSAAdvanced.sol#L247[ERC7579 reference implementation]. + * + * This is not standardized in ERC-7579 (or in any follow-up ERC). Some accounts may want to override these internal functions. + * + * For example, https://github.com/bcnmy/nexus/blob/54f4e19baaff96081a8843672977caf712ef19f4/contracts/lib/NonceLib.sol#L17[Biconomy's Nexus] + * uses a similar yet incompatible approach (the validator address is also part of the nonce, but not at the same location) + */ + function _extractUserOpValidator(PackedUserOperation calldata userOp) internal pure virtual returns (address) { + return address(bytes32(userOp.nonce).extract_32_20(0)); + } + + /** + * @dev Extracts the signature validator from the signature. + * + * To construct a signature, set the first 20 bytes as the module address and the remaining bytes as the + * signature data: + * + * ``` + * | + * ``` + * + * NOTE: The default behavior of this function replicates the behavior of + * https://github.com/rhinestonewtf/safe7579/blob/bb29e8b1a66658790c4169e72608e27d220f79be/src/Safe7579.sol#L350[Safe adapter], + * https://github.com/bcnmy/nexus/blob/54f4e19baaff96081a8843672977caf712ef19f4/contracts/Nexus.sol#L239[Biconomy's Nexus], + * https://github.com/etherspot/etherspot-prime-contracts/blob/cfcdb48c4172cea0d66038324c0bae3288aa8caa/src/modular-etherspot-wallet/wallet/ModularEtherspotWallet.sol#L252[Etherspot's Prime Account], and + * https://github.com/erc7579/erc7579-implementation/blob/16138d1afd4e9711f6c1425133538837bd7787b5/src/MSAAdvanced.sol#L296[ERC7579 reference implementation]. + * + * This is not standardized in ERC-7579 (or in any follow-up ERC). Some accounts may want to override these internal functions. + */ + function _extractSignatureValidator( + bytes calldata signature + ) internal pure virtual returns (address module, bytes calldata innerSignature) { + return (address(bytes20(signature[0:20])), signature[20:]); + } + + /** + * @dev Extract the function selector from initData/deInitData for MODULE_TYPE_FALLBACK + * + * NOTE: If we had calldata here, we could use calldata slice which are cheaper to manipulate and don't require + * actual copy. However, this would require `_installModule` to get a calldata bytes object instead of a memory + * bytes object. This would prevent calling `_installModule` from a contract constructor and would force the use + * of external initializers. That may change in the future, as most accounts will probably be deployed as + * clones/proxy/ERC-7702 delegates and therefore rely on initializers anyway. + */ + function _decodeFallbackData( + bytes memory data + ) internal pure virtual returns (bytes4 selector, bytes memory remaining) { + return (bytes4(data), data.slice(4)); + } + + /// @dev By default, only use the modules for validation of userOp and signature. Disable raw signatures. + function _rawSignatureValidation( + bytes32 /*hash*/, + bytes calldata /*signature*/ + ) internal view virtual override returns (bool) { + return false; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579Hooked.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579Hooked.sol new file mode 100644 index 0000000..c83f38f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579Hooked.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (account/extensions/draft-AccountERC7579Hooked.sol) + +pragma solidity ^0.8.26; + +import {IERC7579Hook, MODULE_TYPE_HOOK} from "../../interfaces/draft-IERC7579.sol"; +import {ERC7579Utils, Mode} from "../../account/utils/draft-ERC7579Utils.sol"; +import {AccountERC7579} from "./draft-AccountERC7579.sol"; + +/** + * @dev Extension of {AccountERC7579} with support for a single hook module (type 4). + * + * If installed, this extension will call the hook module's {IERC7579Hook-preCheck} before executing any operation + * with {_execute} (including {execute} and {executeFromExecutor} by default) and {IERC7579Hook-postCheck} thereafter. + * + * NOTE: Hook modules break the check-effect-interaction pattern. In particular, the {IERC7579Hook-preCheck} hook can + * lead to potentially dangerous reentrancy. Using the `withHook()` modifier is safe if no effect is performed + * before the preHook or after the postHook. That is the case on all functions here, but it may not be the case if + * functions that have this modifier are overridden. Developers should be extremely careful when implementing hook + * modules or further overriding functions that involve hooks. + */ +abstract contract AccountERC7579Hooked is AccountERC7579 { + address private _hook; + + /// @dev A hook module is already present. This contract only supports one hook module. + error ERC7579HookModuleAlreadyPresent(address hook); + + /** + * @dev Calls {IERC7579Hook-preCheck} before executing the modified function and {IERC7579Hook-postCheck} + * thereafter. + */ + modifier withHook() { + address hook_ = hook(); + bytes memory hookData; + + // slither-disable-next-line reentrancy-no-eth + if (hook_ != address(0)) hookData = IERC7579Hook(hook_).preCheck(msg.sender, msg.value, msg.data); + _; + if (hook_ != address(0)) IERC7579Hook(hook_).postCheck(hookData); + } + + /// @inheritdoc AccountERC7579 + function accountId() public view virtual override returns (string memory) { + // vendorname.accountname.semver + return "@openzeppelin/community-contracts.AccountERC7579Hooked.v0.0.0"; + } + + /// @dev Returns the hook module address if installed, or `address(0)` otherwise. + function hook() public view virtual returns (address) { + return _hook; + } + + /// @dev Supports hook modules. See {AccountERC7579-supportsModule} + function supportsModule(uint256 moduleTypeId) public view virtual override returns (bool) { + return moduleTypeId == MODULE_TYPE_HOOK || super.supportsModule(moduleTypeId); + } + + /// @inheritdoc AccountERC7579 + function isModuleInstalled( + uint256 moduleTypeId, + address module, + bytes calldata data + ) public view virtual override returns (bool) { + return + (moduleTypeId == MODULE_TYPE_HOOK && module == hook()) || + super.isModuleInstalled(moduleTypeId, module, data); + } + + /// @dev Installs a module with support for hook modules. See {AccountERC7579-_installModule} + function _installModule( + uint256 moduleTypeId, + address module, + bytes memory initData + ) internal virtual override withHook { + if (moduleTypeId == MODULE_TYPE_HOOK) { + require(_hook == address(0), ERC7579HookModuleAlreadyPresent(_hook)); + _hook = module; + } + super._installModule(moduleTypeId, module, initData); + } + + /// @dev Uninstalls a module with support for hook modules. See {AccountERC7579-_uninstallModule} + function _uninstallModule( + uint256 moduleTypeId, + address module, + bytes memory deInitData + ) internal virtual override withHook { + if (moduleTypeId == MODULE_TYPE_HOOK) { + require(_hook == module, ERC7579Utils.ERC7579UninstalledModule(moduleTypeId, module)); + _hook = address(0); + } + super._uninstallModule(moduleTypeId, module, deInitData); + } + + /// @dev Hooked version of {AccountERC7579-_execute}. + function _execute( + Mode mode, + bytes calldata executionCalldata + ) internal virtual override withHook returns (bytes[] memory) { + return super._execute(mode, executionCalldata); + } + + /// @dev Hooked version of {AccountERC7579-_fallback}. + function _fallback() internal virtual override withHook returns (bytes memory) { + return super._fallback(); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-ERC7821.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-ERC7821.sol new file mode 100644 index 0000000..a8f2236 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-ERC7821.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (account/extensions/draft-ERC7821.sol) + +pragma solidity ^0.8.20; + +import {ERC7579Utils, Mode, CallType, ExecType, ModeSelector} from "../utils/draft-ERC7579Utils.sol"; +import {IERC7821} from "../../interfaces/draft-IERC7821.sol"; +import {Account} from "../Account.sol"; + +/** + * @dev Minimal batch executor following ERC-7821. + * + * Only supports supports single batch mode (`0x01000000000000000000`). Does not support optional "opData". + * + * @custom:stateless + */ +abstract contract ERC7821 is IERC7821 { + using ERC7579Utils for *; + + error UnsupportedExecutionMode(); + + /** + * @dev Executes the calls in `executionData` with no optional `opData` support. + * + * NOTE: Access to this function is controlled by {_erc7821AuthorizedExecutor}. Changing access permissions, for + * example to approve calls by the ERC-4337 entrypoint, should be implemented by overriding it. + * + * Reverts and bubbles up error if any call fails. + */ + function execute(bytes32 mode, bytes calldata executionData) public payable virtual { + if (!_erc7821AuthorizedExecutor(msg.sender, mode, executionData)) + revert Account.AccountUnauthorized(msg.sender); + if (!supportsExecutionMode(mode)) revert UnsupportedExecutionMode(); + executionData.execBatch(ERC7579Utils.EXECTYPE_DEFAULT); + } + + /// @inheritdoc IERC7821 + function supportsExecutionMode(bytes32 mode) public view virtual returns (bool result) { + (CallType callType, ExecType execType, ModeSelector modeSelector, ) = Mode.wrap(mode).decodeMode(); + return + callType == ERC7579Utils.CALLTYPE_BATCH && + execType == ERC7579Utils.EXECTYPE_DEFAULT && + modeSelector == ModeSelector.wrap(0x00000000); + } + + /** + * @dev Access control mechanism for the {execute} function. + * By default, only the contract itself is allowed to execute. + * + * Override this function to implement custom access control, for example to allow the + * ERC-4337 entrypoint to execute. + * + * ```solidity + * function _erc7821AuthorizedExecutor( + * address caller, + * bytes32 mode, + * bytes calldata executionData + * ) internal view virtual override returns (bool) { + * return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); + * } + * ``` + */ + function _erc7821AuthorizedExecutor( + address caller, + bytes32 /* mode */, + bytes calldata /* executionData */ + ) internal view virtual returns (bool) { + return caller == address(this); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/EIP7702Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/EIP7702Utils.sol new file mode 100644 index 0000000..804d6c2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/EIP7702Utils.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (account/utils/EIP7702Utils.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Library with common EIP-7702 utility functions. + * + * See https://eips.ethereum.org/EIPS/eip-7702[ERC-7702]. + */ +library EIP7702Utils { + bytes3 internal constant EIP7702_PREFIX = 0xef0100; + + /** + * @dev Returns the address of the delegate if `account` as an EIP-7702 delegation setup, or address(0) otherwise. + */ + function fetchDelegate(address account) internal view returns (address) { + bytes23 delegation = bytes23(account.code); + return bytes3(delegation) == EIP7702_PREFIX ? address(bytes20(delegation << 24)) : address(0); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC4337Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC4337Utils.sol new file mode 100644 index 0000000..6d2c8cc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC4337Utils.sol @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (account/utils/draft-ERC4337Utils.sol) + +pragma solidity ^0.8.20; + +import {IEntryPoint, PackedUserOperation} from "../../interfaces/draft-IERC4337.sol"; +import {Math} from "../../utils/math/Math.sol"; +import {Calldata} from "../../utils/Calldata.sol"; +import {Packing} from "../../utils/Packing.sol"; + +/// @dev This is available on all entrypoint since v0.4.0, but is not formally part of the ERC. +interface IEntryPointExtra { + function getUserOpHash(PackedUserOperation calldata userOp) external view returns (bytes32); +} + +/** + * @dev Library with common ERC-4337 utility functions. + * + * See https://eips.ethereum.org/EIPS/eip-4337[ERC-4337]. + */ +library ERC4337Utils { + using Packing for *; + + /// @dev Address of the entrypoint v0.7.0 + IEntryPoint internal constant ENTRYPOINT_V07 = IEntryPoint(0x0000000071727De22E5E9d8BAf0edAc6f37da032); + + /// @dev Address of the entrypoint v0.8.0 + IEntryPoint internal constant ENTRYPOINT_V08 = IEntryPoint(0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108); + + /// @dev For simulation purposes, validateUserOp (and validatePaymasterUserOp) return this value on success. + uint256 internal constant SIG_VALIDATION_SUCCESS = 0; + + /// @dev For simulation purposes, validateUserOp (and validatePaymasterUserOp) must return this value in case of signature failure, instead of revert. + uint256 internal constant SIG_VALIDATION_FAILED = 1; + + /// @dev Parses the validation data into its components. See {packValidationData}. + function parseValidationData( + uint256 validationData + ) internal pure returns (address aggregator, uint48 validAfter, uint48 validUntil) { + validAfter = uint48(bytes32(validationData).extract_32_6(0)); + validUntil = uint48(bytes32(validationData).extract_32_6(6)); + aggregator = address(bytes32(validationData).extract_32_20(12)); + if (validUntil == 0) validUntil = type(uint48).max; + } + + /// @dev Packs the validation data into a single uint256. See {parseValidationData}. + function packValidationData( + address aggregator, + uint48 validAfter, + uint48 validUntil + ) internal pure returns (uint256) { + return uint256(bytes6(validAfter).pack_6_6(bytes6(validUntil)).pack_12_20(bytes20(aggregator))); + } + + /// @dev Same as {packValidationData}, but with a boolean signature success flag. + function packValidationData(bool sigSuccess, uint48 validAfter, uint48 validUntil) internal pure returns (uint256) { + return + packValidationData( + address(uint160(Math.ternary(sigSuccess, SIG_VALIDATION_SUCCESS, SIG_VALIDATION_FAILED))), + validAfter, + validUntil + ); + } + + /** + * @dev Combines two validation data into a single one. + * + * The `aggregator` is set to {SIG_VALIDATION_SUCCESS} if both are successful, while + * the `validAfter` is the maximum and the `validUntil` is the minimum of both. + */ + function combineValidationData(uint256 validationData1, uint256 validationData2) internal pure returns (uint256) { + (address aggregator1, uint48 validAfter1, uint48 validUntil1) = parseValidationData(validationData1); + (address aggregator2, uint48 validAfter2, uint48 validUntil2) = parseValidationData(validationData2); + + bool success = aggregator1 == address(uint160(SIG_VALIDATION_SUCCESS)) && + aggregator2 == address(uint160(SIG_VALIDATION_SUCCESS)); + uint48 validAfter = uint48(Math.max(validAfter1, validAfter2)); + uint48 validUntil = uint48(Math.min(validUntil1, validUntil2)); + return packValidationData(success, validAfter, validUntil); + } + + /// @dev Returns the aggregator of the `validationData` and whether it is out of time range. + function getValidationData(uint256 validationData) internal view returns (address aggregator, bool outOfTimeRange) { + (address aggregator_, uint48 validAfter, uint48 validUntil) = parseValidationData(validationData); + return (aggregator_, block.timestamp < validAfter || validUntil < block.timestamp); + } + + /// @dev Get the hash of a user operation for a given entrypoint + function hash(PackedUserOperation calldata self, address entrypoint) internal view returns (bytes32) { + // NOTE: getUserOpHash is available since v0.4.0 + // + // Prior to v0.8.0, this was easy to replicate for any entrypoint and chainId. Since v0.8.0 of the + // entrypoint, this depends on the Entrypoint's domain separator, which cannot be hardcoded and is complex + // to recompute. Domain separator could be fetch using the `getDomainSeparatorV4` getter, or recomputed from + // the ERC-5267 getter, but both operation would require doing a view call to the entrypoint. Overall it feels + // simpler and less error prone to get that functionality from the entrypoint directly. + return IEntryPointExtra(entrypoint).getUserOpHash(self); + } + + /// @dev Returns `factory` from the {PackedUserOperation}, or address(0) if the initCode is empty or not properly formatted. + function factory(PackedUserOperation calldata self) internal pure returns (address) { + return self.initCode.length < 20 ? address(0) : address(bytes20(self.initCode[0:20])); + } + + /// @dev Returns `factoryData` from the {PackedUserOperation}, or empty bytes if the initCode is empty or not properly formatted. + function factoryData(PackedUserOperation calldata self) internal pure returns (bytes calldata) { + return self.initCode.length < 20 ? Calldata.emptyBytes() : self.initCode[20:]; + } + + /// @dev Returns `verificationGasLimit` from the {PackedUserOperation}. + function verificationGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) { + return uint128(self.accountGasLimits.extract_32_16(0)); + } + + /// @dev Returns `callGasLimit` from the {PackedUserOperation}. + function callGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) { + return uint128(self.accountGasLimits.extract_32_16(16)); + } + + /// @dev Returns the first section of `gasFees` from the {PackedUserOperation}. + function maxPriorityFeePerGas(PackedUserOperation calldata self) internal pure returns (uint256) { + return uint128(self.gasFees.extract_32_16(0)); + } + + /// @dev Returns the second section of `gasFees` from the {PackedUserOperation}. + function maxFeePerGas(PackedUserOperation calldata self) internal pure returns (uint256) { + return uint128(self.gasFees.extract_32_16(16)); + } + + /// @dev Returns the total gas price for the {PackedUserOperation} (ie. `maxFeePerGas` or `maxPriorityFeePerGas + basefee`). + function gasPrice(PackedUserOperation calldata self) internal view returns (uint256) { + unchecked { + // Following values are "per gas" + uint256 maxPriorityFee = maxPriorityFeePerGas(self); + uint256 maxFee = maxFeePerGas(self); + return Math.min(maxFee, maxPriorityFee + block.basefee); + } + } + + /// @dev Returns the first section of `paymasterAndData` from the {PackedUserOperation}. + function paymaster(PackedUserOperation calldata self) internal pure returns (address) { + return self.paymasterAndData.length < 52 ? address(0) : address(bytes20(self.paymasterAndData[0:20])); + } + + /// @dev Returns the second section of `paymasterAndData` from the {PackedUserOperation}. + function paymasterVerificationGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) { + return self.paymasterAndData.length < 52 ? 0 : uint128(bytes16(self.paymasterAndData[20:36])); + } + + /// @dev Returns the third section of `paymasterAndData` from the {PackedUserOperation}. + function paymasterPostOpGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) { + return self.paymasterAndData.length < 52 ? 0 : uint128(bytes16(self.paymasterAndData[36:52])); + } + + /// @dev Returns the fourth section of `paymasterAndData` from the {PackedUserOperation}. + function paymasterData(PackedUserOperation calldata self) internal pure returns (bytes calldata) { + return self.paymasterAndData.length < 52 ? Calldata.emptyBytes() : self.paymasterAndData[52:]; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC7579Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC7579Utils.sol new file mode 100644 index 0000000..3e6544e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC7579Utils.sol @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (account/utils/draft-ERC7579Utils.sol) + +pragma solidity ^0.8.20; + +import {Execution} from "../../interfaces/draft-IERC7579.sol"; +import {Packing} from "../../utils/Packing.sol"; +import {Address} from "../../utils/Address.sol"; + +type Mode is bytes32; +type CallType is bytes1; +type ExecType is bytes1; +type ModeSelector is bytes4; +type ModePayload is bytes22; + +/** + * @dev Library with common ERC-7579 utility functions. + * + * See https://eips.ethereum.org/EIPS/eip-7579[ERC-7579]. + */ +// slither-disable-next-line unused-state +library ERC7579Utils { + using Packing for *; + + /// @dev A single `call` execution. + CallType internal constant CALLTYPE_SINGLE = CallType.wrap(0x00); + + /// @dev A batch of `call` executions. + CallType internal constant CALLTYPE_BATCH = CallType.wrap(0x01); + + /// @dev A `delegatecall` execution. + CallType internal constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF); + + /// @dev Default execution type that reverts on failure. + ExecType internal constant EXECTYPE_DEFAULT = ExecType.wrap(0x00); + + /// @dev Execution type that does not revert on failure. + ExecType internal constant EXECTYPE_TRY = ExecType.wrap(0x01); + + /** + * @dev Emits when an {EXECTYPE_TRY} execution fails. + * @param batchExecutionIndex The index of the failed call in the execution batch. + * @param returndata The returned data from the failed call. + */ + event ERC7579TryExecuteFail(uint256 batchExecutionIndex, bytes returndata); + + /// @dev The provided {CallType} is not supported. + error ERC7579UnsupportedCallType(CallType callType); + + /// @dev The provided {ExecType} is not supported. + error ERC7579UnsupportedExecType(ExecType execType); + + /// @dev The provided module doesn't match the provided module type. + error ERC7579MismatchedModuleTypeId(uint256 moduleTypeId, address module); + + /// @dev The module is not installed. + error ERC7579UninstalledModule(uint256 moduleTypeId, address module); + + /// @dev The module is already installed. + error ERC7579AlreadyInstalledModule(uint256 moduleTypeId, address module); + + /// @dev The module type is not supported. + error ERC7579UnsupportedModuleType(uint256 moduleTypeId); + + /// @dev Input calldata not properly formatted and possibly malicious. + error ERC7579DecodingError(); + + /// @dev Executes a single call. + function execSingle( + bytes calldata executionCalldata, + ExecType execType + ) internal returns (bytes[] memory returnData) { + (address target, uint256 value, bytes calldata callData) = decodeSingle(executionCalldata); + returnData = new bytes[](1); + returnData[0] = _call(0, execType, target, value, callData); + } + + /// @dev Executes a batch of calls. + function execBatch( + bytes calldata executionCalldata, + ExecType execType + ) internal returns (bytes[] memory returnData) { + Execution[] calldata executionBatch = decodeBatch(executionCalldata); + returnData = new bytes[](executionBatch.length); + for (uint256 i = 0; i < executionBatch.length; ++i) { + returnData[i] = _call( + i, + execType, + executionBatch[i].target, + executionBatch[i].value, + executionBatch[i].callData + ); + } + } + + /// @dev Executes a delegate call. + function execDelegateCall( + bytes calldata executionCalldata, + ExecType execType + ) internal returns (bytes[] memory returnData) { + (address target, bytes calldata callData) = decodeDelegate(executionCalldata); + returnData = new bytes[](1); + returnData[0] = _delegatecall(0, execType, target, callData); + } + + /// @dev Encodes the mode with the provided parameters. See {decodeMode}. + function encodeMode( + CallType callType, + ExecType execType, + ModeSelector selector, + ModePayload payload + ) internal pure returns (Mode mode) { + return + Mode.wrap( + CallType + .unwrap(callType) + .pack_1_1(ExecType.unwrap(execType)) + .pack_2_4(bytes4(0)) + .pack_6_4(ModeSelector.unwrap(selector)) + .pack_10_22(ModePayload.unwrap(payload)) + ); + } + + /// @dev Decodes the mode into its parameters. See {encodeMode}. + function decodeMode( + Mode mode + ) internal pure returns (CallType callType, ExecType execType, ModeSelector selector, ModePayload payload) { + return ( + CallType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 0)), + ExecType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 1)), + ModeSelector.wrap(Packing.extract_32_4(Mode.unwrap(mode), 6)), + ModePayload.wrap(Packing.extract_32_22(Mode.unwrap(mode), 10)) + ); + } + + /// @dev Encodes a single call execution. See {decodeSingle}. + function encodeSingle( + address target, + uint256 value, + bytes calldata callData + ) internal pure returns (bytes memory executionCalldata) { + return abi.encodePacked(target, value, callData); + } + + /// @dev Decodes a single call execution. See {encodeSingle}. + function decodeSingle( + bytes calldata executionCalldata + ) internal pure returns (address target, uint256 value, bytes calldata callData) { + target = address(bytes20(executionCalldata[0:20])); + value = uint256(bytes32(executionCalldata[20:52])); + callData = executionCalldata[52:]; + } + + /// @dev Encodes a delegate call execution. See {decodeDelegate}. + function encodeDelegate( + address target, + bytes calldata callData + ) internal pure returns (bytes memory executionCalldata) { + return abi.encodePacked(target, callData); + } + + /// @dev Decodes a delegate call execution. See {encodeDelegate}. + function decodeDelegate( + bytes calldata executionCalldata + ) internal pure returns (address target, bytes calldata callData) { + target = address(bytes20(executionCalldata[0:20])); + callData = executionCalldata[20:]; + } + + /// @dev Encodes a batch of executions. See {decodeBatch}. + function encodeBatch(Execution[] memory executionBatch) internal pure returns (bytes memory executionCalldata) { + return abi.encode(executionBatch); + } + + /// @dev Decodes a batch of executions. See {encodeBatch}. + /// + /// NOTE: This function runs some checks and will throw a {ERC7579DecodingError} if the input is not properly formatted. + function decodeBatch(bytes calldata executionCalldata) internal pure returns (Execution[] calldata executionBatch) { + unchecked { + uint256 bufferLength = executionCalldata.length; + + // Check executionCalldata is not empty. + if (bufferLength < 32) revert ERC7579DecodingError(); + + // Get the offset of the array (pointer to the array length). + uint256 arrayLengthOffset = uint256(bytes32(executionCalldata[0:32])); + + // The array length (at arrayLengthOffset) should be 32 bytes long. We check that this is within the + // buffer bounds. Since we know bufferLength is at least 32, we can subtract with no overflow risk. + if (arrayLengthOffset > bufferLength - 32) revert ERC7579DecodingError(); + + // Get the array length. arrayLengthOffset + 32 is bounded by bufferLength so it does not overflow. + uint256 arrayLength = uint256(bytes32(executionCalldata[arrayLengthOffset:arrayLengthOffset + 32])); + + // Check that the buffer is long enough to store the array elements as "offset pointer": + // - each element of the array is an "offset pointer" to the data. + // - each "offset pointer" (to an array element) takes 32 bytes. + // - validity of the calldata at that location is checked when the array element is accessed, so we only + // need to check that the buffer is large enough to hold the pointers. + // + // Since we know bufferLength is at least arrayLengthOffset + 32, we can subtract with no overflow risk. + // Solidity limits length of such arrays to 2**64-1, this guarantees `arrayLength * 32` does not overflow. + if (arrayLength > type(uint64).max || bufferLength - arrayLengthOffset - 32 < arrayLength * 32) + revert ERC7579DecodingError(); + + assembly ("memory-safe") { + executionBatch.offset := add(add(executionCalldata.offset, arrayLengthOffset), 0x20) + executionBatch.length := arrayLength + } + } + } + + /// @dev Executes a `call` to the target with the provided {ExecType}. + function _call( + uint256 index, + ExecType execType, + address target, + uint256 value, + bytes calldata data + ) private returns (bytes memory) { + (bool success, bytes memory returndata) = (target == address(0) ? address(this) : target).call{value: value}( + data + ); + return _validateExecutionMode(index, execType, success, returndata); + } + + /// @dev Executes a `delegatecall` to the target with the provided {ExecType}. + function _delegatecall( + uint256 index, + ExecType execType, + address target, + bytes calldata data + ) private returns (bytes memory) { + (bool success, bytes memory returndata) = (target == address(0) ? address(this) : target).delegatecall(data); + return _validateExecutionMode(index, execType, success, returndata); + } + + /// @dev Validates the execution mode and returns the returndata. + function _validateExecutionMode( + uint256 index, + ExecType execType, + bool success, + bytes memory returndata + ) private returns (bytes memory) { + if (execType == ERC7579Utils.EXECTYPE_DEFAULT) { + Address.verifyCallResult(success, returndata); + } else if (execType == ERC7579Utils.EXECTYPE_TRY) { + if (!success) emit ERC7579TryExecuteFail(index, returndata); + } else { + revert ERC7579UnsupportedExecType(execType); + } + return returndata; + } +} + +// Operators +using {eqCallType as ==} for CallType global; +using {eqExecType as ==} for ExecType global; +using {eqModeSelector as ==} for ModeSelector global; +using {eqModePayload as ==} for ModePayload global; + +/// @dev Compares two `CallType` values for equality. +function eqCallType(CallType a, CallType b) pure returns (bool) { + return CallType.unwrap(a) == CallType.unwrap(b); +} + +/// @dev Compares two `ExecType` values for equality. +function eqExecType(ExecType a, ExecType b) pure returns (bool) { + return ExecType.unwrap(a) == ExecType.unwrap(b); +} + +/// @dev Compares two `ModeSelector` values for equality. +function eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) { + return ModeSelector.unwrap(a) == ModeSelector.unwrap(b); +} + +/// @dev Compares two `ModePayload` values for equality. +function eqModePayload(ModePayload a, ModePayload b) pure returns (bool) { + return ModePayload.unwrap(a) == ModePayload.unwrap(b); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/README.adoc new file mode 100644 index 0000000..c855cbb --- /dev/null +++ b/typescript/packages/account-modules/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 ERC-20 tokens for a given beneficiary. Custody of multiple tokens can + be given to this contract, which will release the token to the beneficiary following a given, customizable, vesting + schedule. + +== Contracts + +{{VestingWallet}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol new file mode 100644 index 0000000..03024fa --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.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 ERC-20 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 holds 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. + * + * NOTE: Chains with support for native ERC20s may allow the vesting wallet to withdraw the underlying asset as both an + * ERC20 and as native currency. For example, if chain C supports token A and the wallet gets deposited 100 A, then + * at 50% of the vesting period, the beneficiary can withdraw 50 A as ERC20 and 25 A as native currency (totaling 75 A). + * Consider disabling one of the withdrawal methods. + */ +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 beneficiary (owner), the start timestamp and the vesting duration (in seconds) 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWalletCliff.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWalletCliff.sol new file mode 100644 index 0000000..dd1da65 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWalletCliff.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (finance/VestingWalletCliff.sol) + +pragma solidity ^0.8.20; + +import {SafeCast} from "../utils/math/SafeCast.sol"; +import {VestingWallet} from "./VestingWallet.sol"; + +/** + * @dev Extension of {VestingWallet} that adds a cliff to the vesting schedule. + * + * _Available since v5.1._ + */ +abstract contract VestingWalletCliff is VestingWallet { + using SafeCast for *; + + uint64 private immutable _cliff; + + /// @dev The specified cliff duration is larger than the vesting duration. + error InvalidCliffDuration(uint64 cliffSeconds, uint64 durationSeconds); + + /** + * @dev Set the duration of the cliff, in seconds. The cliff starts vesting schedule (see {VestingWallet}'s + * constructor) and ends `cliffSeconds` later. + */ + constructor(uint64 cliffSeconds) { + if (cliffSeconds > duration()) { + revert InvalidCliffDuration(cliffSeconds, duration().toUint64()); + } + _cliff = start().toUint64() + cliffSeconds; + } + + /** + * @dev Getter for the cliff timestamp. + */ + function cliff() public view virtual returns (uint256) { + return _cliff; + } + + /** + * @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. Returns 0 if the {cliff} timestamp is not met. + * + * IMPORTANT: The cliff not only makes the schedule return 0, but it also ignores every possible side + * effect from calling the inherited implementation (i.e. `super._vestingSchedule`). Carefully consider + * this caveat if the overridden implementation of this function has any (e.g. writing to memory or reverting). + */ + function _vestingSchedule( + uint256 totalAllocation, + uint64 timestamp + ) internal view virtual override returns (uint256) { + return timestamp < cliff() ? 0 : super._vestingSchedule(totalAllocation, timestamp); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/Governor.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/Governor.sol new file mode 100644 index 0000000..05564b8 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/Governor.sol @@ -0,0 +1,818 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/Governor.sol) + +pragma solidity ^0.8.24; + +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 {Strings} from "../utils/Strings.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 {_quorumReached}, {_voteSucceeded} and {_countVote} + * - A voting module must implement {_getVotes} + * - Additionally, {votingPeriod}, {votingDelay}, and {quorum} 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(); + } + } + + /// @inheritdoc IERC165 + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return + interfaceId == type(IGovernor).interfaceId || + interfaceId == type(IGovernor).interfaceId ^ IGovernor.getProposalId.selector || + interfaceId == type(IERC1155Receiver).interfaceId || + super.supportsInterface(interfaceId); + } + + /// @inheritdoc IGovernor + function name() public view virtual returns (string memory) { + return _name; + } + + /// @inheritdoc IGovernor + 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))); + } + + /// @inheritdoc IGovernor + function getProposalId( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public view virtual returns (uint256) { + return hashProposal(targets, values, calldatas, descriptionHash); + } + + /// @inheritdoc IGovernor + 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; + } + } + + /// @inheritdoc IGovernor + function proposalThreshold() public view virtual returns (uint256) { + return 0; + } + + /// @inheritdoc IGovernor + function proposalSnapshot(uint256 proposalId) public view virtual returns (uint256) { + return _proposals[proposalId].voteStart; + } + + /// @inheritdoc IGovernor + function proposalDeadline(uint256 proposalId) public view virtual returns (uint256) { + return _proposals[proposalId].voteStart + _proposals[proposalId].voteDuration; + } + + /// @inheritdoc IGovernor + function proposalProposer(uint256 proposalId) public view virtual returns (address) { + return _proposals[proposalId].proposer; + } + + /// @inheritdoc IGovernor + function proposalEta(uint256 proposalId) public view virtual returns (uint256) { + return _proposals[proposalId].etaSeconds; + } + + /// @inheritdoc IGovernor + 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 totalWeight, + bytes memory params + ) internal virtual returns (uint256); + + /** + * @dev Hook that should be called every time the tally for a proposal is updated. + * + * Note: This function must run successfully. Reverts will result in the bricking of governance + */ + function _tallyUpdated(uint256 proposalId) 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 votesThreshold = proposalThreshold(); + if (votesThreshold > 0) { + uint256 proposerVotes = getVotes(proposer, clock() - 1); + 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 = getProposalId(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 + } + + /// @inheritdoc IGovernor + function queue( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public virtual returns (uint256) { + uint256 proposalId = getProposalId(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; + } + + /// @inheritdoc IGovernor + function execute( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public payable virtual returns (uint256) { + uint256 proposalId = getProposalId(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}. + */ + 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); + } + } + + /// @inheritdoc IGovernor + 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 `getProposalId` duplication has a cost that is limited, and that we accept. + uint256 proposalId = getProposalId(targets, values, calldatas, descriptionHash); + + address caller = _msgSender(); + if (!_validateCancel(proposalId, caller)) revert GovernorUnableToCancel(proposalId, caller); + + 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 = getProposalId(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; + } + + /// @inheritdoc IGovernor + function getVotes(address account, uint256 timepoint) public view virtual returns (uint256) { + return _getVotes(account, timepoint, _defaultParams()); + } + + /// @inheritdoc IGovernor + function getVotesWithParams( + address account, + uint256 timepoint, + bytes memory params + ) public view virtual returns (uint256) { + return _getVotes(account, timepoint, params); + } + + /// @inheritdoc IGovernor + function castVote(uint256 proposalId, uint8 support) public virtual returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, ""); + } + + /// @inheritdoc IGovernor + function castVoteWithReason( + uint256 proposalId, + uint8 support, + string calldata reason + ) public virtual returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, reason); + } + + /// @inheritdoc IGovernor + 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); + } + + /// @inheritdoc IGovernor + function castVoteBySig( + uint256 proposalId, + uint8 support, + address voter, + bytes memory signature + ) public virtual returns (uint256) { + if (!_validateVoteSig(proposalId, support, voter, signature)) { + revert GovernorInvalidSignature(voter); + } + return _castVote(proposalId, voter, support, ""); + } + + /// @inheritdoc IGovernor + function castVoteWithReasonAndParamsBySig( + uint256 proposalId, + uint8 support, + address voter, + string calldata reason, + bytes memory params, + bytes memory signature + ) public virtual returns (uint256) { + if (!_validateExtendedVoteSig(proposalId, support, voter, reason, params, signature)) { + revert GovernorInvalidSignature(voter); + } + return _castVote(proposalId, voter, support, reason, params); + } + + /// @dev Validate the `signature` used in {castVoteBySig} function. + function _validateVoteSig( + uint256 proposalId, + uint8 support, + address voter, + bytes memory signature + ) internal virtual returns (bool) { + return + SignatureChecker.isValidSignatureNow( + voter, + _hashTypedDataV4(keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support, voter, _useNonce(voter)))), + signature + ); + } + + /// @dev Validate the `signature` used in {castVoteWithReasonAndParamsBySig} function. + function _validateExtendedVoteSig( + uint256 proposalId, + uint8 support, + address voter, + string memory reason, + bytes memory params, + bytes memory signature + ) internal virtual returns (bool) { + return + SignatureChecker.isValidSignatureNow( + voter, + _hashTypedDataV4( + keccak256( + abi.encode( + EXTENDED_BALLOT_TYPEHASH, + proposalId, + support, + voter, + _useNonce(voter), + keccak256(bytes(reason)), + keccak256(params) + ) + ) + ), + signature + ); + } + + /** + * @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 totalWeight = _getVotes(account, proposalSnapshot(proposalId), params); + uint256 votedWeight = _countVote(proposalId, account, support, totalWeight, params); + + if (params.length == 0) { + emit VoteCast(account, proposalId, support, votedWeight, reason); + } else { + emit VoteCastWithParams(account, proposalId, support, votedWeight, reason, params); + } + + _tallyUpdated(proposalId); + + return votedWeight; + } + + /** + * @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) internal 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) { + unchecked { + uint256 length = bytes(description).length; + + // Length is too short to contain a valid proposer suffix + if (length < 52) { + return true; + } + + // Extract what would be the `#proposer=` marker beginning the suffix + bytes10 marker = bytes10(_unsafeReadBytesOffset(bytes(description), length - 52)); + + // If the marker is not found, there is no proposer suffix to check + if (marker != bytes10("#proposer=")) { + return true; + } + + // Check that the last 42 characters (after the marker) are a properly formatted address. + (bool success, address recovered) = Strings.tryParseAddress(description, length - 42, length); + return !success || recovered == proposer; + } + } + + /** + * @dev Check if the `caller` can cancel the proposal with the given `proposalId`. + * + * The default implementation allows the proposal proposer to cancel the proposal during the pending state. + */ + function _validateCancel(uint256 proposalId, address caller) internal view virtual returns (bool) { + return (state(proposalId) == ProposalState.Pending) && caller == proposalProposer(proposalId); + } + + /// @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); + + /** + * @dev Reads a bytes32 from a bytes array without bounds checking. + * + * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the + * assembly block as such would prevent some optimizations. + */ + function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) { + // This is not memory safe in the general case, but all calls to this private function are within bounds. + assembly ("memory-safe") { + value := mload(add(add(buffer, 0x20), offset)) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol new file mode 100644 index 0000000..b3f0feb --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/IGovernor.sol) + +pragma solidity >=0.8.4; + +import {IERC165} from "../interfaces/IERC165.sol"; +import {IERC6372} from "../interfaces/IERC6372.sol"; + +/** + * @dev Interface of the {Governor} core. + * + * NOTE: Event parameters lack the `indexed` keyword for compatibility with GovernorBravo events. + * Making event parameters `indexed` affects how events are decoded, potentially breaking existing indexers. + */ +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 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 The provided params buffer is not supported by the counting module. + */ + error GovernorInvalidVoteParams(); + + /** + * @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 The given `account` is unable to cancel the proposal with given `proposalId`. + */ + error GovernorUnableToCancel(uint256 proposalId, address account); + + /** + * @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 interpretation 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 EIP-712 domain separator). + */ + function name() external view returns (string memory); + + /** + * @notice module:core + * @dev Version of the governor instance (used in building the EIP-712 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. + * + * NOTE: For all off-chain and external calls, use {getProposalId}. + */ + function hashProposal( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) external pure returns (uint256); + + /** + * @notice module:core + * @dev Function used to get the proposal id from the proposal details. + */ + function getProposalId( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) external view 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 ERC-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 ERC-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. + * + * NOTE: The state of the Governor and `targets` may change between the proposal creation and its execution. + * This may be the result of third party actions on the targeted contracts, or other governor proposals. + * For example, the balance of this contract could be updated or its access control permissions may be modified, + * possibly compromising the proposal's ability to execute successfully (e.g. the governor doesn't have enough + * value to cover a proposal with multiple transfers). + */ + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/README.adoc new file mode 100644 index 0000000..3131a0b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/README.adoc @@ -0,0 +1,197 @@ += 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 {IVotes} contract. + +* {GovernorVotesQuorumFraction}: Combines with `GovernorVotes` to set the quorum as a fraction of the total token supply. + +* {GovernorVotesSuperQuorumFraction}: Combines `GovernorSuperQuorum` with `GovernorVotesQuorumFraction` to set the super 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. + +* {GovernorCountingFractional}: A more modular voting system that allows a user to vote with only part of its voting power, and to split that weight arbitrarily between the 3 different options (Against, For and Abstain). + +* {GovernorCountingOverridable}: An extended version of `GovernorCountingSimple` which allows delegatees to override their delegates while the vote is live. Must be used in conjunction with {VotesExtended}. + +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. + +* {GovernorTimelockAccess}: Connects with an instance of an {AccessManager}. This allows restrictions (and delays) enforced by the manager to be considered by the Governor and integrated into the AccessManager's "schedule + execute" workflow. + +* {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. + +* {GovernorProposalGuardian}: Adds a proposal guardian that can cancel proposals at any stage in their lifecycle--this permission is passed on to the proposers if the guardian is not set. + +* {GovernorSuperQuorum}: Extension of {Governor} with a super quorum. Proposals that meet the super quorum (and have a majority of for votes) advance to the `Succeeded` state before the proposal deadline. + +* {GovernorNoncesKeyed}: An extension of {Governor} with support for keyed nonces in addition to traditional nonces when voting by signature. + +In addition to modules and extensions, the core contract requires a few virtual functions to be implemented to your particular specifications: + +* <>: Delay (in ERC-6372 clock) since the proposal is submitted until voting power is fixed and voting starts. This can be used to enforce a delay after a proposal is published for users to buy tokens, or delegate their votes. +* <>: Delay (in ERC-6372 clock) since the proposal starts until voting ends. +* <>: Quorum required for a proposal to be successful. This function includes a `timepoint` argument (see ERC-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}} + +{{GovernorCountingFractional}} + +{{GovernorCountingOverridable}} + +{{GovernorVotes}} + +{{GovernorVotesQuorumFraction}} + +{{GovernorVotesSuperQuorumFraction}} + +=== Extensions + +{{GovernorTimelockAccess}} + +{{GovernorTimelockControl}} + +{{GovernorTimelockCompound}} + +{{GovernorSettings}} + +{{GovernorPreventLateQuorum}} + +{{GovernorStorage}} + +{{GovernorProposalGuardian}} + +{{GovernorSuperQuorum}} + +{{GovernorNoncesKeyed}} + +== Utils + +{{Votes}} + +{{VotesExtended}} + +== 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. 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 rescheduled. + +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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol new file mode 100644 index 0000000..17fef92 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol @@ -0,0 +1,471 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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"; +import {IERC165} from "../utils/introspection/ERC165.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 virtual {} + + /// @inheritdoc IERC165 + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingFractional.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingFractional.sol new file mode 100644 index 0000000..1460d2d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingFractional.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorCountingFractional.sol) + +pragma solidity ^0.8.24; + +import {IGovernor, Governor} from "../Governor.sol"; +import {GovernorCountingSimple} from "./GovernorCountingSimple.sol"; +import {Math} from "../../utils/math/Math.sol"; + +/** + * @dev Extension of {Governor} for fractional voting. + * + * Similar to {GovernorCountingSimple}, this contract is a votes counting module for {Governor} that supports 3 options: + * Against, For, Abstain. Additionally, it includes a fourth option: Fractional, which allows voters to split their voting + * power amongst the other 3 options. + * + * Votes cast with the Fractional support must be accompanied by a `params` argument that is three packed `uint128` values + * representing the weight the delegate assigns to Against, For, and Abstain respectively. For those votes cast for the other + * 3 options, the `params` argument must be empty. + * + * This is mostly useful when the delegate is a contract that implements its own rules for voting. These delegate-contracts + * can cast fractional votes according to the preferences of multiple entities delegating their voting power. + * + * Some example use cases include: + * + * * Voting from tokens that are held by a DeFi pool + * * Voting from an L2 with tokens held by a bridge + * * Voting privately from a shielded pool using zero knowledge proofs. + * + * Based on ScopeLift's https://github.com/ScopeLift/flexible-voting/blob/e5de2efd1368387b840931f19f3c184c85842761/src/GovernorCountingFractional.sol[`GovernorCountingFractional`] + * + * _Available since v5.1._ + */ +abstract contract GovernorCountingFractional is Governor { + using Math for *; + + uint8 internal constant VOTE_TYPE_FRACTIONAL = 255; + + struct ProposalVote { + uint256 againstVotes; + uint256 forVotes; + uint256 abstainVotes; + mapping(address voter => uint256) usedVotes; + } + + /** + * @dev Mapping from proposal ID to vote tallies for that proposal. + */ + mapping(uint256 proposalId => ProposalVote) private _proposalVotes; + + /** + * @dev A fractional vote params uses more votes than are available for that user. + */ + error GovernorExceedRemainingWeight(address voter, uint256 usedVotes, uint256 remainingWeight); + + /// @inheritdoc IGovernor + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public pure virtual override returns (string memory) { + return "support=bravo,fractional&quorum=for,abstain¶ms=fractional"; + } + + /// @inheritdoc IGovernor + function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) { + return usedVotes(proposalId, account) > 0; + } + + /** + * @dev Get the number of votes already cast by `account` for a proposal with `proposalId`. Useful for + * integrations that allow delegates to cast rolling, partial votes. + */ + function usedVotes(uint256 proposalId, address account) public view virtual returns (uint256) { + return _proposalVotes[proposalId].usedVotes[account]; + } + + /** + * @dev Get current distribution of votes for a given proposal. + */ + 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); + } + + /// @inheritdoc Governor + 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, forVotes must be > 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}. Function that records the delegate's votes. + * + * Executing this function consumes (part of) the delegate's weight on the proposal. This weight can be + * distributed amongst the 3 options (Against, For, Abstain) by specifying a fractional `support`. + * + * This counting module supports two vote casting modes: nominal and fractional. + * + * - Nominal: A nominal vote is cast by setting `support` to one of the 3 bravo options (Against, For, Abstain). + * - Fractional: A fractional vote is cast by setting `support` to `type(uint8).max` (255). + * + * Casting a nominal vote requires `params` to be empty and consumes the delegate's full remaining weight on the + * proposal for the specified `support` option. This is similar to the {GovernorCountingSimple} module and follows + * the `VoteType` enum from Governor Bravo. As a consequence, no vote weight remains unspent so no further voting + * is possible (for this `proposalId` and this `account`). + * + * Casting a fractional vote consumes a fraction of the delegate's remaining weight on the proposal according to the + * weights the delegate assigns to each support option (Against, For, Abstain respectively). The sum total of the + * three decoded vote weights _must_ be less than or equal to the delegate's remaining weight on the proposal (i.e. + * their checkpointed total weight minus votes already cast on the proposal). This format can be produced using: + * + * `abi.encodePacked(uint128(againstVotes), uint128(forVotes), uint128(abstainVotes))` + * + * NOTE: Consider that fractional voting restricts the number of casted votes (in each category) to 128 bits. + * Depending on how many decimals the underlying token has, a single voter may require to split their vote into + * multiple vote operations. For precision higher than ~30 decimals, large token holders may require a + * potentially large number of calls to cast all their votes. The voter has the possibility to cast all the + * remaining votes in a single operation using the traditional "bravo" vote. + */ + // slither-disable-next-line cyclomatic-complexity + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 totalWeight, + bytes memory params + ) internal virtual override returns (uint256) { + // Compute number of remaining votes. Returns 0 on overflow. + (, uint256 remainingWeight) = totalWeight.trySub(usedVotes(proposalId, account)); + if (remainingWeight == 0) { + revert GovernorAlreadyCastVote(account); + } + + uint256 againstVotes = 0; + uint256 forVotes = 0; + uint256 abstainVotes = 0; + uint256 usedWeight = 0; + + // For clarity of event indexing, fractional voting must be clearly advertised in the "support" field. + // + // Supported `support` value must be: + // - "Full" voting: `support = 0` (Against), `1` (For) or `2` (Abstain), with empty params. + // - "Fractional" voting: `support = 255`, with 48 bytes params. + if (support == uint8(GovernorCountingSimple.VoteType.Against)) { + if (params.length != 0) revert GovernorInvalidVoteParams(); + usedWeight = againstVotes = remainingWeight; + } else if (support == uint8(GovernorCountingSimple.VoteType.For)) { + if (params.length != 0) revert GovernorInvalidVoteParams(); + usedWeight = forVotes = remainingWeight; + } else if (support == uint8(GovernorCountingSimple.VoteType.Abstain)) { + if (params.length != 0) revert GovernorInvalidVoteParams(); + usedWeight = abstainVotes = remainingWeight; + } else if (support == VOTE_TYPE_FRACTIONAL) { + // The `params` argument is expected to be three packed `uint128`: + // `abi.encodePacked(uint128(againstVotes), uint128(forVotes), uint128(abstainVotes))` + if (params.length != 0x30) revert GovernorInvalidVoteParams(); + + assembly ("memory-safe") { + againstVotes := shr(128, mload(add(params, 0x20))) + forVotes := shr(128, mload(add(params, 0x30))) + abstainVotes := shr(128, mload(add(params, 0x40))) + usedWeight := add(add(againstVotes, forVotes), abstainVotes) // inputs are uint128: cannot overflow + } + + // check parsed arguments are valid + if (usedWeight > remainingWeight) { + revert GovernorExceedRemainingWeight(account, usedWeight, remainingWeight); + } + } else { + revert GovernorInvalidVoteType(); + } + + // update votes tracking + ProposalVote storage details = _proposalVotes[proposalId]; + if (againstVotes > 0) details.againstVotes += againstVotes; + if (forVotes > 0) details.forVotes += forVotes; + if (abstainVotes > 0) details.abstainVotes += abstainVotes; + details.usedVotes[account] += usedWeight; + + return usedWeight; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingOverridable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingOverridable.sol new file mode 100644 index 0000000..45a72ea --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingOverridable.sol @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorCountingOverridable.sol) + +pragma solidity ^0.8.24; + +import {SignatureChecker} from "../../utils/cryptography/SignatureChecker.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {VotesExtended} from "../utils/VotesExtended.sol"; +import {GovernorVotes} from "./GovernorVotes.sol"; +import {IGovernor, Governor} from "../Governor.sol"; + +/** + * @dev Extension of {Governor} which enables delegators to override the vote of their delegates. This module requires a + * token that inherits {VotesExtended}. + */ +abstract contract GovernorCountingOverridable is GovernorVotes { + bytes32 public constant OVERRIDE_BALLOT_TYPEHASH = + keccak256("OverrideBallot(uint256 proposalId,uint8 support,address voter,uint256 nonce,string reason)"); + + /** + * @dev Supported vote types. Matches Governor Bravo ordering. + */ + enum VoteType { + Against, + For, + Abstain + } + + struct VoteReceipt { + uint8 casted; // 0 if vote was not casted. Otherwise: support + 1 + bool hasOverridden; + uint208 overriddenWeight; + } + + struct ProposalVote { + uint256[3] votes; + mapping(address voter => VoteReceipt) voteReceipt; + } + + /// @dev The votes casted by `delegate` were reduced by `weight` after an override vote was casted by the original token holder + event VoteReduced(address indexed delegate, uint256 proposalId, uint8 support, uint256 weight); + + /// @dev A delegated vote on `proposalId` was overridden by `weight` + event OverrideVoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason); + + error GovernorAlreadyOverriddenVote(address account); + + mapping(uint256 proposalId => ProposalVote) private _proposalVotes; + + /// @inheritdoc IGovernor + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public pure virtual override returns (string memory) { + return "support=bravo,override&quorum=for,abstain&overridable=true"; + } + + /** + * @dev See {IGovernor-hasVoted}. + * + * NOTE: Calling {castVote} (or similar) casts a vote using the voting power that is delegated to the voter. + * Conversely, calling {castOverrideVote} (or similar) uses the voting power of the account itself, from its asset + * balances. Casting an "override vote" does not count as voting and won't be reflected by this getter. Consider + * using {hasVotedOverride} to check if an account has casted an "override vote" for a given proposal id. + */ + function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) { + return _proposalVotes[proposalId].voteReceipt[account].casted != 0; + } + + /** + * @dev Check if an `account` has overridden their delegate for a proposal. + */ + function hasVotedOverride(uint256 proposalId, address account) public view virtual returns (bool) { + return _proposalVotes[proposalId].voteReceipt[account].hasOverridden; + } + + /** + * @dev Accessor to the internal vote counts. + */ + function proposalVotes( + uint256 proposalId + ) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) { + uint256[3] storage votes = _proposalVotes[proposalId].votes; + return (votes[uint8(VoteType.Against)], votes[uint8(VoteType.For)], votes[uint8(VoteType.Abstain)]); + } + + /// @inheritdoc Governor + function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) { + uint256[3] storage votes = _proposalVotes[proposalId].votes; + return quorum(proposalSnapshot(proposalId)) <= votes[uint8(VoteType.For)] + votes[uint8(VoteType.Abstain)]; + } + + /** + * @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) { + uint256[3] storage votes = _proposalVotes[proposalId].votes; + return votes[uint8(VoteType.For)] > votes[uint8(VoteType.Against)]; + } + + /** + * @dev See {Governor-_countVote}. In this module, the support follows the `VoteType` enum (from Governor Bravo). + * + * NOTE: called by {Governor-_castVote} which emits the {IGovernor-VoteCast} (or {IGovernor-VoteCastWithParams}) + * event. + */ + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 totalWeight, + bytes memory /*params*/ + ) internal virtual override returns (uint256) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + if (support > uint8(VoteType.Abstain)) { + revert GovernorInvalidVoteType(); + } + + if (proposalVote.voteReceipt[account].casted != 0) { + revert GovernorAlreadyCastVote(account); + } + + totalWeight -= proposalVote.voteReceipt[account].overriddenWeight; + proposalVote.votes[support] += totalWeight; + proposalVote.voteReceipt[account].casted = support + 1; + + return totalWeight; + } + + /** + * @dev Variant of {Governor-_countVote} that deals with vote overrides. + * + * NOTE: See {hasVoted} for more details about the difference between {castVote} and {castOverrideVote}. + */ + function _countOverride(uint256 proposalId, address account, uint8 support) internal virtual returns (uint256) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + if (support > uint8(VoteType.Abstain)) { + revert GovernorInvalidVoteType(); + } + + if (proposalVote.voteReceipt[account].hasOverridden) { + revert GovernorAlreadyOverriddenVote(account); + } + + uint256 snapshot = proposalSnapshot(proposalId); + uint256 overriddenWeight = VotesExtended(address(token())).getPastBalanceOf(account, snapshot); + address delegate = VotesExtended(address(token())).getPastDelegate(account, snapshot); + uint8 delegateCasted = proposalVote.voteReceipt[delegate].casted; + + proposalVote.voteReceipt[account].hasOverridden = true; + proposalVote.votes[support] += overriddenWeight; + if (delegateCasted == 0) { + proposalVote.voteReceipt[delegate].overriddenWeight += SafeCast.toUint208(overriddenWeight); + } else { + uint8 delegateSupport = delegateCasted - 1; + proposalVote.votes[delegateSupport] -= overriddenWeight; + emit VoteReduced(delegate, proposalId, delegateSupport, overriddenWeight); + } + + return overriddenWeight; + } + + /// @dev Variant of {Governor-_castVote} that deals with vote overrides. Returns the overridden weight. + function _castOverride( + uint256 proposalId, + address account, + uint8 support, + string calldata reason + ) internal virtual returns (uint256) { + _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Active)); + + uint256 overriddenWeight = _countOverride(proposalId, account, support); + + emit OverrideVoteCast(account, proposalId, support, overriddenWeight, reason); + + _tallyUpdated(proposalId); + + return overriddenWeight; + } + + /// @dev Public function for casting an override vote. Returns the overridden weight. + function castOverrideVote( + uint256 proposalId, + uint8 support, + string calldata reason + ) public virtual returns (uint256) { + address voter = _msgSender(); + return _castOverride(proposalId, voter, support, reason); + } + + /// @dev Public function for casting an override vote using a voter's signature. Returns the overridden weight. + function castOverrideVoteBySig( + uint256 proposalId, + uint8 support, + address voter, + string calldata reason, + bytes calldata signature + ) public virtual returns (uint256) { + bool valid = SignatureChecker.isValidSignatureNow( + voter, + _hashTypedDataV4( + keccak256( + abi.encode( + OVERRIDE_BALLOT_TYPEHASH, + proposalId, + support, + voter, + _useNonce(voter), + keccak256(bytes(reason)) + ) + ) + ), + signature + ); + + if (!valid) { + revert GovernorInvalidSignature(voter); + } + + return _castOverride(proposalId, voter, support, reason); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol new file mode 100644 index 0000000..3f24a65 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorCountingSimple.sol) + +pragma solidity ^0.8.24; + +import {IGovernor, 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; + + /// @inheritdoc IGovernor + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public pure virtual override returns (string memory) { + return "support=bravo&quorum=for,abstain"; + } + + /// @inheritdoc IGovernor + 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); + } + + /// @inheritdoc Governor + 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 totalWeight, + bytes memory // params + ) internal virtual override returns (uint256) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + if (proposalVote.hasVoted[account]) { + revert GovernorAlreadyCastVote(account); + } + proposalVote.hasVoted[account] = true; + + if (support == uint8(VoteType.Against)) { + proposalVote.againstVotes += totalWeight; + } else if (support == uint8(VoteType.For)) { + proposalVote.forVotes += totalWeight; + } else if (support == uint8(VoteType.Abstain)) { + proposalVote.abstainVotes += totalWeight; + } else { + revert GovernorInvalidVoteType(); + } + + return totalWeight; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorNoncesKeyed.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorNoncesKeyed.sol new file mode 100644 index 0000000..c506b7e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorNoncesKeyed.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorNoncesKeyed.sol) + +pragma solidity ^0.8.24; + +import {Governor} from "../Governor.sol"; +import {Nonces} from "../../utils/Nonces.sol"; +import {NoncesKeyed} from "../../utils/NoncesKeyed.sol"; +import {SignatureChecker} from "../../utils/cryptography/SignatureChecker.sol"; + +/** + * @dev An extension of {Governor} that extends existing nonce management to use {NoncesKeyed}, where the key is the low-order 192 bits of the `proposalId`. + * This is useful for voting by signature while maintaining separate sequences of nonces for each proposal. + * + * NOTE: Traditional (un-keyed) nonces are still supported and can continue to be used as if this extension was not present. + */ +abstract contract GovernorNoncesKeyed is Governor, NoncesKeyed { + function _useCheckedNonce(address owner, uint256 nonce) internal virtual override(Nonces, NoncesKeyed) { + super._useCheckedNonce(owner, nonce); + } + + /** + * @dev Check the signature against keyed nonce and falls back to the traditional nonce. + * + * NOTE: This function won't call `super._validateVoteSig` if the keyed nonce is valid. + * Side effects may be skipped depending on the linearization of the function. + */ + function _validateVoteSig( + uint256 proposalId, + uint8 support, + address voter, + bytes memory signature + ) internal virtual override returns (bool) { + if ( + SignatureChecker.isValidSignatureNow( + voter, + _hashTypedDataV4( + keccak256( + abi.encode(BALLOT_TYPEHASH, proposalId, support, voter, nonces(voter, uint192(proposalId))) + ) + ), + signature + ) + ) { + _useNonce(voter, uint192(proposalId)); + return true; + } else { + return super._validateVoteSig(proposalId, support, voter, signature); + } + } + + /** + * @dev Check the signature against keyed nonce and falls back to the traditional nonce. + * + * NOTE: This function won't call `super._validateExtendedVoteSig` if the keyed nonce is valid. + * Side effects may be skipped depending on the linearization of the function. + */ + function _validateExtendedVoteSig( + uint256 proposalId, + uint8 support, + address voter, + string memory reason, + bytes memory params, + bytes memory signature + ) internal virtual override returns (bool) { + if ( + SignatureChecker.isValidSignatureNow( + voter, + _hashTypedDataV4( + keccak256( + abi.encode( + EXTENDED_BALLOT_TYPEHASH, + proposalId, + support, + voter, + nonces(voter, uint192(proposalId)), + keccak256(bytes(reason)), + keccak256(params) + ) + ) + ), + signature + ) + ) { + _useNonce(voter, uint192(proposalId)); + return true; + } else { + return super._validateExtendedVoteSig(proposalId, support, voter, reason, params, signature); + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol new file mode 100644 index 0000000..581f96e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorPreventLateQuorum.sol) + +pragma solidity ^0.8.24; + +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 Vote tally updated and detects if it caused quorum to be reached, potentially extending the voting period. + * + * May emit a {ProposalExtended} event. + */ + function _tallyUpdated(uint256 proposalId) internal virtual override { + super._tallyUpdated(proposalId); + if (_extendedDeadlines[proposalId] == 0 && _quorumReached(proposalId)) { + uint48 extendedDeadline = clock() + lateQuorumVoteExtension(); + + if (extendedDeadline > proposalDeadline(proposalId)) { + emit ProposalExtended(proposalId, extendedDeadline); + } + + _extendedDeadlines[proposalId] = extendedDeadline; + } + } + + /** + * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorProposalGuardian.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorProposalGuardian.sol new file mode 100644 index 0000000..5ff0c18 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorProposalGuardian.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorProposalGuardian.sol) +pragma solidity ^0.8.24; + +import {Governor} from "../Governor.sol"; + +/** + * @dev Extension of {Governor} which adds a proposal guardian that can cancel proposals at any stage in the proposal's lifecycle. + * + * NOTE: if the proposal guardian is not configured, then proposers take this role for their proposals. + */ +abstract contract GovernorProposalGuardian is Governor { + address private _proposalGuardian; + + event ProposalGuardianSet(address oldProposalGuardian, address newProposalGuardian); + + /** + * @dev Getter that returns the address of the proposal guardian. + */ + function proposalGuardian() public view virtual returns (address) { + return _proposalGuardian; + } + + /** + * @dev Update the proposal guardian's address. This operation can only be performed through a governance proposal. + * + * Emits a {ProposalGuardianSet} event. + */ + function setProposalGuardian(address newProposalGuardian) public virtual onlyGovernance { + _setProposalGuardian(newProposalGuardian); + } + + /** + * @dev Internal setter for the proposal guardian. + * + * Emits a {ProposalGuardianSet} event. + */ + function _setProposalGuardian(address newProposalGuardian) internal virtual { + emit ProposalGuardianSet(_proposalGuardian, newProposalGuardian); + _proposalGuardian = newProposalGuardian; + } + + /** + * @dev Override {Governor-_validateCancel} to implement the extended cancellation logic. + * + * * The {proposalGuardian} can cancel any proposal at any point. + * * If no proposal guardian is set, the {IGovernor-proposalProposer} can cancel their proposals at any point. + * * In any case, permissions defined in {Governor-_validateCancel} (or another override) remains valid. + */ + function _validateCancel(uint256 proposalId, address caller) internal view virtual override returns (bool) { + address guardian = proposalGuardian(); + + return + guardian == caller || + (guardian == address(0) && caller == proposalProposer(proposalId)) || + super._validateCancel(proposalId, caller); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSequentialProposalId.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSequentialProposalId.sol new file mode 100644 index 0000000..d6869bb --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSequentialProposalId.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorSequentialProposalId.sol) + +pragma solidity ^0.8.24; + +import {IGovernor, Governor} from "../Governor.sol"; + +/** + * @dev Extension of {Governor} that changes the numbering of proposal ids from the default hash-based approach to + * sequential ids. + */ +abstract contract GovernorSequentialProposalId is Governor { + uint256 private _latestProposalId; + mapping(uint256 proposalHash => uint256 proposalId) private _proposalIds; + + /** + * @dev The {latestProposalId} may only be initialized if it hasn't been set yet + * (through initialization or the creation of a proposal). + */ + error GovernorAlreadyInitializedLatestProposalId(); + + /// @inheritdoc IGovernor + function getProposalId( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public view virtual override returns (uint256) { + uint256 proposalHash = hashProposal(targets, values, calldatas, descriptionHash); + uint256 storedProposalId = _proposalIds[proposalHash]; + if (storedProposalId == 0) { + revert GovernorNonexistentProposal(0); + } + return storedProposalId; + } + + /** + * @dev Returns the latest proposal id. A return value of 0 means no proposals have been created yet. + */ + function latestProposalId() public view virtual returns (uint256) { + return _latestProposalId; + } + + /** + * @dev See {IGovernor-_propose}. + * Hook into the proposing mechanism to increment proposal count. + */ + function _propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description, + address proposer + ) internal virtual override returns (uint256) { + uint256 proposalHash = hashProposal(targets, values, calldatas, keccak256(bytes(description))); + uint256 storedProposalId = _proposalIds[proposalHash]; + if (storedProposalId == 0) { + _proposalIds[proposalHash] = ++_latestProposalId; + } + return super._propose(targets, values, calldatas, description, proposer); + } + + /** + * @dev Internal function to set the {latestProposalId}. This function is helpful when transitioning + * from another governance system. The next proposal id will be `newLatestProposalId` + 1. + * + * May only call this function if the current value of {latestProposalId} is 0. + */ + function _initializeLatestProposalId(uint256 newLatestProposalId) internal virtual { + if (_latestProposalId != 0) { + revert GovernorAlreadyInitializedLatestProposalId(); + } + _latestProposalId = newLatestProposalId; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol new file mode 100644 index 0000000..5f3cef7 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorSettings.sol) + +pragma solidity ^0.8.24; + +import {IGovernor, 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); + } + + /// @inheritdoc IGovernor + function votingDelay() public view virtual override returns (uint256) { + return _votingDelay; + } + + /// @inheritdoc IGovernor + function votingPeriod() public view virtual override returns (uint256) { + return _votingPeriod; + } + + /// @inheritdoc Governor + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorStorage.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorStorage.sol new file mode 100644 index 0000000..1c00678 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorStorage.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorStorage.sol) + +pragma solidity ^0.8.24; + +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 {IGovernor-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 targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash) + { + // 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 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) + { + proposalId = _proposalIds[index]; + (targets, values, calldatas, descriptionHash) = proposalDetails(proposalId); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSuperQuorum.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSuperQuorum.sol new file mode 100644 index 0000000..04602fd --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSuperQuorum.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorSuperQuorum.sol) +pragma solidity ^0.8.24; + +import {Governor} from "../Governor.sol"; + +/** + * @dev Extension of {Governor} with a super quorum. Proposals that meet the super quorum (and have a majority of for + * votes) advance to the `Succeeded` state before the proposal deadline. Counting modules that want to use this + * extension must implement {proposalVotes}. + */ +abstract contract GovernorSuperQuorum is Governor { + /** + * @dev Minimum number of cast votes required for a proposal to reach super quorum. Only FOR votes are counted + * towards the super quorum. Once the super quorum is reached, an active proposal can proceed to the next state + * without waiting for the proposal deadline. + * + * NOTE: The `timepoint` parameter corresponds to the snapshot used for counting the vote. This enables scaling of the + * quorum depending on values such as the `totalSupply` of a token at this timepoint (see {ERC20Votes}). + * + * NOTE: Make sure the value specified for the super quorum is greater than {quorum}, otherwise, it may be + * possible to pass a proposal with less votes than the default quorum. + */ + function superQuorum(uint256 timepoint) public view virtual returns (uint256); + + /** + * @dev Accessor to the internal vote counts. This must be implemented by the counting module. Counting modules + * that don't implement this function are incompatible with this module + */ + function proposalVotes( + uint256 proposalId + ) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes); + + /** + * @dev Overridden version of the {Governor-state} function that checks if the proposal has reached the super + * quorum. + * + * NOTE: If the proposal reaches super quorum but {_voteSucceeded} returns false, eg, assuming the super quorum + * has been set low enough that both FOR and AGAINST votes have exceeded it and AGAINST votes exceed FOR votes, + * the proposal continues to be active until {_voteSucceeded} returns true or the proposal deadline is reached. + * This means that with a low super quorum it is also possible that a vote can succeed prematurely before enough + * AGAINST voters have a chance to vote. Hence, it is recommended to set a high enough super quorum to avoid these + * types of scenarios. + */ + function state(uint256 proposalId) public view virtual override returns (ProposalState) { + ProposalState currentState = super.state(proposalId); + if (currentState != ProposalState.Active) return currentState; + + (, uint256 forVotes, ) = proposalVotes(proposalId); + if (forVotes < superQuorum(proposalSnapshot(proposalId)) || !_voteSucceeded(proposalId)) { + return ProposalState.Active; + } else if (proposalEta(proposalId) == 0) { + return ProposalState.Succeeded; + } else { + return ProposalState.Queued; + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockAccess.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockAccess.sol new file mode 100644 index 0000000..14823d9 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockAccess.sol @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorTimelockAccess.sol) + +pragma solidity ^0.8.24; + +import {IGovernor, 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. + * + * 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 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); + } + + /// @inheritdoc IGovernor + function proposalNeedsQueuing(uint256 proposalId) public view virtual override returns (bool) { + return _executionPlan[proposalId].delay > 0; + } + + /// @inheritdoc IGovernor + 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) { + // This function can reenter when calling `_manager.schedule` before performing state updates in `_setManagerData`. + // However, the `manager` is a trusted contract in the current context's security model (e.g. an `AccessManager`). + // slither-disable-next-line reentrancy-no-eth + (, 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); + } + } + } + + /// @inheritdoc Governor + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol new file mode 100644 index 0000000..dce13f1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorTimelockCompound.sol) + +pragma solidity ^0.8.24; + +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 proposals (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 from a proposal, unless executed via {Governor-relay}. + */ +abstract contract GovernorTimelockCompound is Governor { + ICompoundTimelock private _timelock; + + /** + * @dev Emitted when the timelock controller used for proposal execution is modified. + */ + 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); + } + + /// @inheritdoc IGovernor + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol new file mode 100644 index 0000000..b3f3b26 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorTimelockControl.sol) + +pragma solidity ^0.8.24; + +import {IGovernor, Governor} from "../Governor.sol"; +import {TimelockController} from "../TimelockController.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 and canceller) 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 cancelers 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. + */ +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); + } + + /// @inheritdoc IGovernor + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol new file mode 100644 index 0000000..4ad5870 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorVotes.sol) + +pragma solidity ^0.8.24; + +import {Governor} from "../Governor.sol"; +import {IVotes} from "../utils/IVotes.sol"; +import {IERC5805} from "../../interfaces/IERC5805.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 ERC-6372) is set to match the token's clock. Fallback to block numbers if the token + * does not implement ERC-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 ERC-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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol new file mode 100644 index 0000000..2f6034d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorVotesQuorumFraction.sol) + +pragma solidity ^0.8.24; + +import {GovernorVotes} from "./GovernorVotes.sol"; +import {Math} from "../../utils/math/Math.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) { + return _optimisticUpperLookupRecent(_quorumNumeratorHistory, 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 Math.mulDiv(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); + } + + /** + * @dev Returns the numerator at a specific timepoint. + */ + function _optimisticUpperLookupRecent( + Checkpoints.Trace208 storage ckpts, + uint256 timepoint + ) internal view returns (uint256) { + // If trace is empty, key and value are both equal to 0. + // In that case `key <= timepoint` is true, and it is ok to return 0. + (, uint48 key, uint208 value) = ckpts.latestCheckpoint(); + return key <= timepoint ? value : ckpts.upperLookupRecent(SafeCast.toUint48(timepoint)); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol new file mode 100644 index 0000000..1c47840 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorVotesSuperQuorumFraction.sol) +pragma solidity ^0.8.24; + +import {Governor} from "../Governor.sol"; +import {GovernorSuperQuorum} from "./GovernorSuperQuorum.sol"; +import {GovernorVotesQuorumFraction} from "./GovernorVotesQuorumFraction.sol"; +import {Math} from "../../utils/math/Math.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; + +/** + * @dev Extension of {GovernorVotesQuorumFraction} with a super quorum expressed as a + * fraction of the total supply. Proposals that meet the super quorum (and have a majority of for votes) advance to + * the `Succeeded` state before the proposal deadline. + */ +abstract contract GovernorVotesSuperQuorumFraction is GovernorVotesQuorumFraction, GovernorSuperQuorum { + using Checkpoints for Checkpoints.Trace208; + + Checkpoints.Trace208 private _superQuorumNumeratorHistory; + + event SuperQuorumNumeratorUpdated(uint256 oldSuperQuorumNumerator, uint256 newSuperQuorumNumerator); + + /** + * @dev The super quorum set is not valid as it exceeds the quorum denominator. + */ + error GovernorInvalidSuperQuorumFraction(uint256 superQuorumNumerator, uint256 denominator); + + /** + * @dev The super quorum set is not valid as it is smaller or equal to the quorum. + */ + error GovernorInvalidSuperQuorumTooSmall(uint256 superQuorumNumerator, uint256 quorumNumerator); + + /** + * @dev The quorum set is not valid as it exceeds the super quorum. + */ + error GovernorInvalidQuorumTooLarge(uint256 quorumNumerator, uint256 superQuorumNumerator); + + /** + * @dev Initialize super quorum as a fraction of the token's total supply. + * + * The super quorum is specified as a fraction of the token's total supply and has to + * be greater than the quorum. + */ + constructor(uint256 superQuorumNumeratorValue) { + _updateSuperQuorumNumerator(superQuorumNumeratorValue); + } + + /** + * @dev Returns the current super quorum numerator. + */ + function superQuorumNumerator() public view virtual returns (uint256) { + return _superQuorumNumeratorHistory.latest(); + } + + /** + * @dev Returns the super quorum numerator at a specific `timepoint`. + */ + function superQuorumNumerator(uint256 timepoint) public view virtual returns (uint256) { + return _optimisticUpperLookupRecent(_superQuorumNumeratorHistory, timepoint); + } + + /** + * @dev Returns the super quorum for a `timepoint`, in terms of number of votes: `supply * numerator / denominator`. + * See {GovernorSuperQuorum-superQuorum} for more details. + */ + function superQuorum(uint256 timepoint) public view virtual override returns (uint256) { + return Math.mulDiv(token().getPastTotalSupply(timepoint), superQuorumNumerator(timepoint), quorumDenominator()); + } + + /** + * @dev Changes the super quorum numerator. + * + * Emits a {SuperQuorumNumeratorUpdated} event. + * + * Requirements: + * + * - Must be called through a governance proposal. + * - New super quorum numerator must be smaller or equal to the denominator. + * - New super quorum numerator must be greater than or equal to the quorum numerator. + */ + function updateSuperQuorumNumerator(uint256 newSuperQuorumNumerator) public virtual onlyGovernance { + _updateSuperQuorumNumerator(newSuperQuorumNumerator); + } + + /** + * @dev Changes the super quorum numerator. + * + * Emits a {SuperQuorumNumeratorUpdated} event. + * + * Requirements: + * + * - New super quorum numerator must be smaller or equal to the denominator. + * - New super quorum numerator must be greater than or equal to the quorum numerator. + */ + function _updateSuperQuorumNumerator(uint256 newSuperQuorumNumerator) internal virtual { + uint256 denominator = quorumDenominator(); + if (newSuperQuorumNumerator > denominator) { + revert GovernorInvalidSuperQuorumFraction(newSuperQuorumNumerator, denominator); + } + + uint256 quorumNumerator = quorumNumerator(); + if (newSuperQuorumNumerator < quorumNumerator) { + revert GovernorInvalidSuperQuorumTooSmall(newSuperQuorumNumerator, quorumNumerator); + } + + uint256 oldSuperQuorumNumerator = _superQuorumNumeratorHistory.latest(); + _superQuorumNumeratorHistory.push(clock(), SafeCast.toUint208(newSuperQuorumNumerator)); + + emit SuperQuorumNumeratorUpdated(oldSuperQuorumNumerator, newSuperQuorumNumerator); + } + + /** + * @dev Overrides {GovernorVotesQuorumFraction-_updateQuorumNumerator} to ensure the super + * quorum numerator is greater than or equal to the quorum numerator. + */ + function _updateQuorumNumerator(uint256 newQuorumNumerator) internal virtual override { + // Ignoring check when the superQuorum was never set (construction sets quorum before superQuorum) + if (_superQuorumNumeratorHistory.length() > 0) { + uint256 superQuorumNumerator_ = superQuorumNumerator(); + if (newQuorumNumerator > superQuorumNumerator_) { + revert GovernorInvalidQuorumTooLarge(newQuorumNumerator, superQuorumNumerator_); + } + } + super._updateQuorumNumerator(newQuorumNumerator); + } + + /// @inheritdoc GovernorSuperQuorum + function state( + uint256 proposalId + ) public view virtual override(Governor, GovernorSuperQuorum) returns (ProposalState) { + return super.state(proposalId); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol new file mode 100644 index 0000000..a007f3a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (governance/utils/IVotes.sol) +pragma solidity >=0.8.4; + +/** + * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol new file mode 100644 index 0000000..f5994f2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.2.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 ERC-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 Validate that a timepoint is in the past, and return it as a uint48. + */ + function _validateTimepoint(uint256 timepoint) internal view returns (uint48) { + uint48 currentTimepoint = clock(); + if (timepoint >= currentTimepoint) revert ERC5805FutureLookup(timepoint, currentTimepoint); + return SafeCast.toUint48(timepoint); + } + + /** + * @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) { + return _delegateCheckpoints[account].upperLookupRecent(_validateTimepoint(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) { + return _totalCheckpoints.upperLookupRecent(_validateTimepoint(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) internal virtual { + 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 oldValue, uint208 newValue) { + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/VotesExtended.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/VotesExtended.sol new file mode 100644 index 0000000..5b67320 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/VotesExtended.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.2.0) (governance/utils/VotesExtended.sol) +pragma solidity ^0.8.20; + +import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; +import {Votes} from "./Votes.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; + +/** + * @dev Extension of {Votes} that adds checkpoints for delegations and balances. + * + * WARNING: While this contract extends {Votes}, valid uses of {Votes} may not be compatible with + * {VotesExtended} without additional considerations. This implementation of {_transferVotingUnits} must + * run AFTER the voting weight movement is registered, such that it is reflected on {_getVotingUnits}. + * + * Said differently, {VotesExtended} MUST be integrated in a way that calls {_transferVotingUnits} AFTER the + * asset transfer is registered and balances are updated: + * + * ```solidity + * contract VotingToken is Token, VotesExtended { + * function transfer(address from, address to, uint256 tokenId) public override { + * super.transfer(from, to, tokenId); // <- Perform the transfer first ... + * _transferVotingUnits(from, to, 1); // <- ... then call _transferVotingUnits. + * } + * + * function _getVotingUnits(address account) internal view override returns (uint256) { + * return balanceOf(account); + * } + * } + * ``` + * + * {ERC20Votes} and {ERC721Votes} follow this pattern and are thus safe to use with {VotesExtended}. + */ +abstract contract VotesExtended is Votes { + using Checkpoints for Checkpoints.Trace160; + using Checkpoints for Checkpoints.Trace208; + + mapping(address delegator => Checkpoints.Trace160) private _userDelegationCheckpoints; + mapping(address account => Checkpoints.Trace208) private _userVotingUnitsCheckpoints; + + /** + * @dev Returns the delegate of an `account` 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 getPastDelegate(address account, uint256 timepoint) public view virtual returns (address) { + return address(_userDelegationCheckpoints[account].upperLookupRecent(_validateTimepoint(timepoint))); + } + + /** + * @dev Returns the `balanceOf` of an `account` 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 getPastBalanceOf(address account, uint256 timepoint) public view virtual returns (uint256) { + return _userVotingUnitsCheckpoints[account].upperLookupRecent(_validateTimepoint(timepoint)); + } + + /// @inheritdoc Votes + function _delegate(address account, address delegatee) internal virtual override { + super._delegate(account, delegatee); + + _userDelegationCheckpoints[account].push(clock(), uint160(delegatee)); + } + + /// @inheritdoc Votes + function _transferVotingUnits(address from, address to, uint256 amount) internal virtual override { + super._transferVotingUnits(from, to, amount); + if (from != to) { + if (from != address(0)) { + _userVotingUnitsCheckpoints[from].push(clock(), SafeCast.toUint208(_getVotingUnits(from))); + } + if (to != address(0)) { + _userVotingUnitsCheckpoints[to].push(clock(), SafeCast.toUint208(_getVotingUnits(to))); + } + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol new file mode 100644 index 0000000..6c10b87 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1155.sol) + +pragma solidity >=0.6.2; + +import {IERC1155} from "../token/ERC1155/IERC1155.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol new file mode 100644 index 0000000..95f815f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1155MetadataURI.sol) + +pragma solidity >=0.6.2; + +import {IERC1155MetadataURI} from "../token/ERC1155/extensions/IERC1155MetadataURI.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol new file mode 100644 index 0000000..b56bdfe --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1155Receiver.sol) + +pragma solidity >=0.6.2; + +import {IERC1155Receiver} from "../token/ERC1155/IERC1155Receiver.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol new file mode 100644 index 0000000..4382286 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1271.sol) + +pragma solidity >=0.5.0; + +/** + * @dev Interface of the ERC-1271 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 `hash` + */ + function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4 magicValue); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol new file mode 100644 index 0000000..7bf3e1f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol) + +pragma solidity >=0.6.2; + +import {IERC20} from "./IERC20.sol"; +import {IERC165} from "./IERC165.sol"; + +/** + * @title IERC1363 + * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. + * + * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract + * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction. + */ +interface IERC1363 is IERC20, IERC165 { + /* + * 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 Moves a `value` amount of tokens from the caller's account to `to` + * and then calls {IERC1363Receiver-onTransferReceived} on `to`. + * @param to The address which you want to transfer to. + * @param value The amount of tokens to be transferred. + * @return A boolean value indicating whether the operation succeeded unless throwing. + */ + function transferAndCall(address to, uint256 value) external returns (bool); + + /** + * @dev Moves a `value` amount of tokens from the caller's account to `to` + * and then calls {IERC1363Receiver-onTransferReceived} on `to`. + * @param to The address which you want to transfer to. + * @param value The amount of tokens to be transferred. + * @param data Additional data with no specified format, sent in call to `to`. + * @return A boolean value indicating whether the operation succeeded unless throwing. + */ + function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); + + /** + * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism + * and then calls {IERC1363Receiver-onTransferReceived} on `to`. + * @param from The address which you want to send tokens from. + * @param to The address which you want to transfer to. + * @param value The amount of tokens to be transferred. + * @return A boolean value indicating whether the operation succeeded unless throwing. + */ + function transferFromAndCall(address from, address to, uint256 value) external returns (bool); + + /** + * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism + * and then calls {IERC1363Receiver-onTransferReceived} on `to`. + * @param from The address which you want to send tokens from. + * @param to The address which you want to transfer to. + * @param value The amount of tokens to be transferred. + * @param data Additional data with no specified format, sent in call to `to`. + * @return A boolean value indicating whether the operation succeeded unless throwing. + */ + function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool); + + /** + * @dev Sets a `value` amount of tokens as the allowance of `spender` over the + * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. + * @param spender The address which will spend the funds. + * @param value The amount of tokens to be spent. + * @return A boolean value indicating whether the operation succeeded unless throwing. + */ + function approveAndCall(address spender, uint256 value) external returns (bool); + + /** + * @dev Sets a `value` amount of tokens as the allowance of `spender` over the + * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. + * @param spender The address which will spend the funds. + * @param value The amount of tokens to be spent. + * @param data Additional data with no specified format, sent in call to `spender`. + * @return A boolean value indicating whether the operation succeeded unless throwing. + */ + function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol new file mode 100644 index 0000000..43efc9b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363Receiver.sol) + +pragma solidity >=0.5.0; + +/** + * @title IERC1363Receiver + * @dev Interface for any contract that wants to support `transferAndCall` or `transferFromAndCall` + * from ERC-1363 token contracts. + */ +interface IERC1363Receiver { + /** + * @dev Whenever ERC-1363 tokens are transferred to this contract via `transferAndCall` or `transferFromAndCall` + * by `operator` from `from`, this function is called. + * + * NOTE: To accept the transfer, this must return + * `bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))` + * (i.e. 0x88a7ca5c, or its own function selector). + * + * @param operator The address which called `transferAndCall` or `transferFromAndCall` function. + * @param from The address which the tokens are transferred from. + * @param value The amount of tokens transferred. + * @param data Additional data with no specified format. + * @return `bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))` if transfer is allowed unless throwing. + */ + function onTransferReceived( + address operator, + address from, + uint256 value, + bytes calldata data + ) external returns (bytes4); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol new file mode 100644 index 0000000..46efa88 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363Spender.sol) + +pragma solidity >=0.5.0; + +/** + * @title IERC1363Spender + * @dev Interface for any contract that wants to support `approveAndCall` + * from ERC-1363 token contracts. + */ +interface IERC1363Spender { + /** + * @dev Whenever an ERC-1363 token `owner` approves this contract via `approveAndCall` + * to spend their tokens, this function is called. + * + * NOTE: To accept the approval, this must return + * `bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))` + * (i.e. 0x7b04a2d0, or its own function selector). + * + * @param owner The address which called `approveAndCall` function and previously owned the tokens. + * @param value The amount of tokens to be spent. + * @param data Additional data with no specified format. + * @return `bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))` if approval is allowed unless throwing. + */ + function onApprovalReceived(address owner, uint256 value, bytes calldata data) external returns (bytes4); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol new file mode 100644 index 0000000..d2c99a5 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol) + +pragma solidity >=0.4.16; + +import {IERC165} from "../utils/introspection/IERC165.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol new file mode 100644 index 0000000..8c04719 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1820Implementer.sol) + +pragma solidity >=0.4.16; + +/** + * @dev Interface for an ERC-1820 implementer, as defined in the + * https://eips.ethereum.org/EIPS/eip-1820#interface-implementation-erc1820implementerinterface[ERC]. + * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol new file mode 100644 index 0000000..03efa03 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1820Registry.sol) + +pragma solidity >=0.5.0; + +/** + * @dev Interface of the global ERC-1820 Registry, as defined in the + * https://eips.ethereum.org/EIPS/eip-1820[ERC]. 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 ERC 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 ERC]. + */ + function interfaceHash(string calldata interfaceName) external pure returns (bytes32); + + /** + * @notice Updates the cache with whether the contract implements an ERC-165 interface or not. + * @param account Address of the contract for which to update the cache. + * @param interfaceId ERC-165 interface for which to update the cache. + */ + function updateERC165Cache(address account, bytes4 interfaceId) external; + + /** + * @notice Checks whether a contract implements an ERC-165 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 ERC-165 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 ERC-165 interface or not without using or updating the cache. + * @param account Address of the contract to check. + * @param interfaceId ERC-165 interface to check. + * @return True if `account` implements `interfaceId`, false otherwise. + */ + function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol new file mode 100644 index 0000000..95d222e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1967.sol) + +pragma solidity >=0.4.11; + +/** + * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol new file mode 100644 index 0000000..078e9ec --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol) + +pragma solidity >=0.4.16; + +import {IERC20} from "../token/ERC20/IERC20.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol new file mode 100644 index 0000000..adffeb5 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20Metadata.sol) + +pragma solidity >=0.6.2; + +import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol new file mode 100644 index 0000000..bc0fb64 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC2309.sol) + +pragma solidity >=0.4.11; + +/** + * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol new file mode 100644 index 0000000..330c064 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC2612.sol) + +pragma solidity >=0.6.2; + +import {IERC20Permit} from "../token/ERC20/extensions/IERC20Permit.sol"; + +interface IERC2612 is IERC20Permit {} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol new file mode 100644 index 0000000..858713b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC2981.sol) + +pragma solidity >=0.6.2; + +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. + * + * NOTE: ERC-2981 allows setting the royalty to 100% of the price. In that case all the price would be sent to the + * royalty receiver and 0 tokens to the seller. Contracts dealing with royalty should consider empty transfers. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol new file mode 100644 index 0000000..95b4b2d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC3156.sol) + +pragma solidity >=0.5.0; + +import {IERC3156FlashBorrower} from "./IERC3156FlashBorrower.sol"; +import {IERC3156FlashLender} from "./IERC3156FlashLender.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol new file mode 100644 index 0000000..5028df8 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC3156FlashBorrower.sol) + +pragma solidity >=0.5.0; + +/** + * @dev Interface of the ERC-3156 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol new file mode 100644 index 0000000..77ca98a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC3156FlashLender.sol) + +pragma solidity >=0.5.0; + +import {IERC3156FlashBorrower} from "./IERC3156FlashBorrower.sol"; + +/** + * @dev Interface of the ERC-3156 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol new file mode 100644 index 0000000..5f785c3 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC4626.sol) + +pragma solidity >=0.6.2; + +import {IERC20} from "../token/ERC20/IERC20.sol"; +import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; + +/** + * @dev Interface of the ERC-4626 "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 redemption 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol new file mode 100644 index 0000000..09f13b2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC4906.sol) + +pragma solidity >=0.6.2; + +import {IERC165} from "./IERC165.sol"; +import {IERC721} from "./IERC721.sol"; + +/// @title ERC-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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol new file mode 100644 index 0000000..96cd325 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC5267.sol) + +pragma solidity >=0.4.16; + +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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol new file mode 100644 index 0000000..9c94692 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC5313.sol) + +pragma solidity >=0.4.16; + +/** + * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol new file mode 100644 index 0000000..5d73abb --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC5805.sol) + +pragma solidity >=0.8.4; + +import {IVotes} from "../governance/utils/IVotes.sol"; +import {IERC6372} from "./IERC6372.sol"; + +interface IERC5805 is IERC6372, IVotes {} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol new file mode 100644 index 0000000..447a8ea --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC6372.sol) + +pragma solidity >=0.4.16; + +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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol new file mode 100644 index 0000000..6ec5136 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC721.sol) + +pragma solidity >=0.6.2; + +import {IERC721} from "../token/ERC721/IERC721.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol new file mode 100644 index 0000000..e713bc2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC721Enumerable.sol) + +pragma solidity >=0.6.2; + +import {IERC721Enumerable} from "../token/ERC721/extensions/IERC721Enumerable.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol new file mode 100644 index 0000000..932afaa --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC721Metadata.sol) + +pragma solidity >=0.6.2; + +import {IERC721Metadata} from "../token/ERC721/extensions/IERC721Metadata.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol new file mode 100644 index 0000000..7b5fd47 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC721Receiver.sol) + +pragma solidity >=0.5.0; + +import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol new file mode 100644 index 0000000..d65b9c7 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC777.sol) + +pragma solidity >=0.5.0; + +/** + * @dev Interface of the ERC-777 Token standard as defined in the ERC. + * + * This contract uses the + * https://eips.ethereum.org/EIPS/eip-1820[ERC-1820 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol new file mode 100644 index 0000000..4277333 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC777Recipient.sol) + +pragma solidity >=0.5.0; + +/** + * @dev Interface of the ERC-777 Tokens Recipient standard as defined in the ERC. + * + * 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[ERC-1820 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol new file mode 100644 index 0000000..46d1b4a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC777Sender.sol) + +pragma solidity >=0.5.0; + +/** + * @dev Interface of the ERC-777 Tokens Sender standard as defined in the ERC. + * + * {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[ERC-1820 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC7913.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC7913.sol new file mode 100644 index 0000000..4f887fb --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC7913.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC7913.sol) + +pragma solidity >=0.5.0; + +/** + * @dev Signature verifier interface. + */ +interface IERC7913SignatureVerifier { + /** + * @dev Verifies `signature` as a valid signature of `hash` by `key`. + * + * MUST return the bytes4 magic value IERC7913SignatureVerifier.verify.selector if the signature is valid. + * SHOULD return 0xffffffff or revert if the signature is not valid. + * SHOULD return 0xffffffff or revert if the key is empty + */ + function verify(bytes calldata key, bytes32 hash, bytes calldata signature) external view returns (bytes4); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/README.adoc new file mode 100644 index 0000000..9cb4d9a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/README.adoc @@ -0,0 +1,102 @@ += 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} +- {IERC6909} +- {IERC6909ContentURI} +- {IERC6909Metadata} +- {IERC6909TokenSupply} +- {IERC7674} +- {IERC7802} + +== Detailed ABI + +{{IERC20Errors}} + +{{IERC721Errors}} + +{{IERC1155Errors}} + +{{IERC1271}} + +{{IERC1363}} + +{{IERC1363Receiver}} + +{{IERC1363Spender}} + +{{IERC1820Implementer}} + +{{IERC1820Registry}} + +{{IERC1822Proxiable}} + +{{IERC2612}} + +{{IERC2981}} + +{{IERC3156FlashLender}} + +{{IERC3156FlashBorrower}} + +{{IERC4626}} + +{{IERC4906}} + +{{IERC5267}} + +{{IERC5313}} + +{{IERC5805}} + +{{IERC6372}} + +{{IERC6909}} + +{{IERC6909ContentURI}} + +{{IERC6909Metadata}} + +{{IERC6909TokenSupply}} + +{{IERC7674}} + +{{IERC7802}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol new file mode 100644 index 0000000..2edb85d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC1822.sol) + +pragma solidity >=0.4.16; + +/** + * @dev ERC-1822: 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC4337.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC4337.sol new file mode 100644 index 0000000..752e4e4 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC4337.sol @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC4337.sol) + +pragma solidity >=0.8.4; + +/** + * @dev A https://github.com/ethereum/ercs/blob/master/ERCS/erc-4337.md#useroperation[user operation] is composed of the following elements: + * - `sender` (`address`): The account making the operation + * - `nonce` (`uint256`): Anti-replay parameter (see “Semi-abstracted Nonce Support” ) + * - `factory` (`address`): account factory, only for new accounts + * - `factoryData` (`bytes`): data for account factory (only if account factory exists) + * - `callData` (`bytes`): The data to pass to the sender during the main execution call + * - `callGasLimit` (`uint256`): The amount of gas to allocate the main execution call + * - `verificationGasLimit` (`uint256`): The amount of gas to allocate for the verification step + * - `preVerificationGas` (`uint256`): Extra gas to pay the bundler + * - `maxFeePerGas` (`uint256`): Maximum fee per gas (similar to EIP-1559 max_fee_per_gas) + * - `maxPriorityFeePerGas` (`uint256`): Maximum priority fee per gas (similar to EIP-1559 max_priority_fee_per_gas) + * - `paymaster` (`address`): Address of paymaster contract, (or empty, if account pays for itself) + * - `paymasterVerificationGasLimit` (`uint256`): The amount of gas to allocate for the paymaster validation code + * - `paymasterPostOpGasLimit` (`uint256`): The amount of gas to allocate for the paymaster post-operation code + * - `paymasterData` (`bytes`): Data for paymaster (only if paymaster exists) + * - `signature` (`bytes`): Data passed into the account to verify authorization + * + * When passed to on-chain contracts, the following packed version is used. + * - `sender` (`address`) + * - `nonce` (`uint256`) + * - `initCode` (`bytes`): concatenation of factory address and factoryData (or empty) + * - `callData` (`bytes`) + * - `accountGasLimits` (`bytes32`): concatenation of verificationGas (16 bytes) and callGas (16 bytes) + * - `preVerificationGas` (`uint256`) + * - `gasFees` (`bytes32`): concatenation of maxPriorityFeePerGas (16 bytes) and maxFeePerGas (16 bytes) + * - `paymasterAndData` (`bytes`): concatenation of paymaster fields (or empty) + * - `signature` (`bytes`) + */ +struct PackedUserOperation { + address sender; + uint256 nonce; + bytes initCode; // `abi.encodePacked(factory, factoryData)` + bytes callData; + bytes32 accountGasLimits; // `abi.encodePacked(verificationGasLimit, callGasLimit)` 16 bytes each + uint256 preVerificationGas; + bytes32 gasFees; // `abi.encodePacked(maxPriorityFeePerGas, maxFeePerGas)` 16 bytes each + bytes paymasterAndData; // `abi.encodePacked(paymaster, paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymasterData)` (20 bytes, 16 bytes, 16 bytes, dynamic) + bytes signature; +} + +/** + * @dev Aggregates and validates multiple signatures for a batch of user operations. + * + * A contract could implement this interface with custom validation schemes that allow signature aggregation, + * enabling significant optimizations and gas savings for execution and transaction data cost. + * + * Bundlers and clients whitelist supported aggregators. + * + * See https://eips.ethereum.org/EIPS/eip-7766[ERC-7766] + */ +interface IAggregator { + /** + * @dev Validates the signature for a user operation. + * Returns an alternative signature that should be used during bundling. + */ + function validateUserOpSignature( + PackedUserOperation calldata userOp + ) external view returns (bytes memory sigForUserOp); + + /** + * @dev Returns an aggregated signature for a batch of user operation's signatures. + */ + function aggregateSignatures( + PackedUserOperation[] calldata userOps + ) external view returns (bytes memory aggregatesSignature); + + /** + * @dev Validates that the aggregated signature is valid for the user operations. + * + * Requirements: + * + * - The aggregated signature MUST match the given list of operations. + */ + function validateSignatures(PackedUserOperation[] calldata userOps, bytes calldata signature) external view; +} + +/** + * @dev Handle nonce management for accounts. + * + * Nonces are used in accounts as a replay protection mechanism and to ensure the order of user operations. + * To avoid limiting the number of operations an account can perform, the interface allows using parallel + * nonces by using a `key` parameter. + * + * See https://eips.ethereum.org/EIPS/eip-4337#semi-abstracted-nonce-support[ERC-4337 semi-abstracted nonce support]. + */ +interface IEntryPointNonces { + /** + * @dev Returns the nonce for a `sender` account and a `key`. + * + * Nonces for a certain `key` are always increasing. + */ + function getNonce(address sender, uint192 key) external view returns (uint256 nonce); +} + +/** + * @dev Handle stake management for entities (i.e. accounts, paymasters, factories). + * + * The EntryPoint must implement the following API to let entities like paymasters have a stake, + * and thus have more flexibility in their storage access + * (see https://eips.ethereum.org/EIPS/eip-4337#reputation-scoring-and-throttlingbanning-for-global-entities[reputation, throttling and banning.]) + */ +interface IEntryPointStake { + /** + * @dev Returns the balance of the account. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Deposits `msg.value` to the account. + */ + function depositTo(address account) external payable; + + /** + * @dev Withdraws `withdrawAmount` from the account to `withdrawAddress`. + */ + function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external; + + /** + * @dev Adds stake to the account with an unstake delay of `unstakeDelaySec`. + */ + function addStake(uint32 unstakeDelaySec) external payable; + + /** + * @dev Unlocks the stake of the account. + */ + function unlockStake() external; + + /** + * @dev Withdraws the stake of the account to `withdrawAddress`. + */ + function withdrawStake(address payable withdrawAddress) external; +} + +/** + * @dev Entry point for user operations. + * + * User operations are validated and executed by this contract. + */ +interface IEntryPoint is IEntryPointNonces, IEntryPointStake { + /** + * @dev A user operation at `opIndex` failed with `reason`. + */ + error FailedOp(uint256 opIndex, string reason); + + /** + * @dev A user operation at `opIndex` failed with `reason` and `inner` returned data. + */ + error FailedOpWithRevert(uint256 opIndex, string reason, bytes inner); + + /** + * @dev Batch of aggregated user operations per aggregator. + */ + struct UserOpsPerAggregator { + PackedUserOperation[] userOps; + IAggregator aggregator; + bytes signature; + } + + /** + * @dev Executes a batch of user operations. + * @param beneficiary Address to which gas is refunded upon completing the execution. + */ + function handleOps(PackedUserOperation[] calldata ops, address payable beneficiary) external; + + /** + * @dev Executes a batch of aggregated user operations per aggregator. + * @param beneficiary Address to which gas is refunded upon completing the execution. + */ + function handleAggregatedOps( + UserOpsPerAggregator[] calldata opsPerAggregator, + address payable beneficiary + ) external; +} + +/** + * @dev Base interface for an ERC-4337 account. + */ +interface IAccount { + /** + * @dev Validates a user operation. + * + * * MUST validate the caller is a trusted EntryPoint + * * MUST validate that the signature is a valid signature of the userOpHash, and SHOULD + * return SIG_VALIDATION_FAILED (and not revert) on signature mismatch. Any other error MUST revert. + * * MUST pay the entryPoint (caller) at least the “missingAccountFunds” (which might + * be zero, in case the current account’s deposit is high enough) + * + * Returns an encoded packed validation data that is composed of the following elements: + * + * - `authorizer` (`address`): 0 for success, 1 for failure, otherwise the address of an authorizer contract + * - `validUntil` (`uint48`): The UserOp is valid only up to this time. Zero for “infinite”. + * - `validAfter` (`uint48`): The UserOp is valid only after this time. + */ + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash, + uint256 missingAccountFunds + ) external returns (uint256 validationData); +} + +/** + * @dev Support for executing user operations by prepending the {executeUserOp} function selector + * to the UserOperation's `callData`. + */ +interface IAccountExecute { + /** + * @dev Executes a user operation. + */ + function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external; +} + +/** + * @dev Interface for a paymaster contract that agrees to pay for the gas costs of a user operation. + * + * NOTE: A paymaster must hold a stake to cover the required entrypoint stake and also the gas for the transaction. + */ +interface IPaymaster { + enum PostOpMode { + opSucceeded, + opReverted, + postOpReverted + } + + /** + * @dev Validates whether the paymaster is willing to pay for the user operation. See + * {IAccount-validateUserOp} for additional information on the return value. + * + * NOTE: Bundlers will reject this method if it modifies the state, unless it's whitelisted. + */ + function validatePaymasterUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash, + uint256 maxCost + ) external returns (bytes memory context, uint256 validationData); + + /** + * @dev Verifies the sender is the entrypoint. + * @param actualGasCost the actual amount paid (by account or paymaster) for this UserOperation + * @param actualUserOpFeePerGas total gas used by this UserOperation (including preVerification, creation, validation and execution) + */ + function postOp( + PostOpMode mode, + bytes calldata context, + uint256 actualGasCost, + uint256 actualUserOpFeePerGas + ) external; +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol new file mode 100644 index 0000000..aef2b0a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC6093.sol) +pragma solidity >=0.8.4; + +/** + * @dev Standard ERC-20 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 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 ERC-721 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens. + */ +interface IERC721Errors { + /** + * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-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 ERC-1155 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6909.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6909.sol new file mode 100644 index 0000000..df15761 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6909.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC6909.sol) + +pragma solidity >=0.6.2; + +import {IERC165} from "../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC-6909 compliant contract, as defined in the + * https://eips.ethereum.org/EIPS/eip-6909[ERC]. + */ +interface IERC6909 is IERC165 { + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set for a token of type `id`. + * The new allowance is `amount`. + */ + event Approval(address indexed owner, address indexed spender, uint256 indexed id, uint256 amount); + + /** + * @dev Emitted when `owner` grants or revokes operator status for a `spender`. + */ + event OperatorSet(address indexed owner, address indexed spender, bool approved); + + /** + * @dev Emitted when `amount` tokens of type `id` are moved from `sender` to `receiver` initiated by `caller`. + */ + event Transfer( + address caller, + address indexed sender, + address indexed receiver, + uint256 indexed id, + uint256 amount + ); + + /** + * @dev Returns the amount of tokens of type `id` owned by `owner`. + */ + function balanceOf(address owner, uint256 id) external view returns (uint256); + + /** + * @dev Returns the amount of tokens of type `id` that `spender` is allowed to spend on behalf of `owner`. + * + * NOTE: Does not include operator allowances. + */ + function allowance(address owner, address spender, uint256 id) external view returns (uint256); + + /** + * @dev Returns true if `spender` is set as an operator for `owner`. + */ + function isOperator(address owner, address spender) external view returns (bool); + + /** + * @dev Sets an approval to `spender` for `amount` of tokens of type `id` from the caller's tokens. An `amount` of + * `type(uint256).max` signifies an unlimited approval. + * + * Must return true. + */ + function approve(address spender, uint256 id, uint256 amount) external returns (bool); + + /** + * @dev Grants or revokes unlimited transfer permission of any token id to `spender` for the caller's tokens. + * + * Must return true. + */ + function setOperator(address spender, bool approved) external returns (bool); + + /** + * @dev Transfers `amount` of token type `id` from the caller's account to `receiver`. + * + * Must return true. + */ + function transfer(address receiver, uint256 id, uint256 amount) external returns (bool); + + /** + * @dev Transfers `amount` of token type `id` from `sender` to `receiver`. + * + * Must return true. + */ + function transferFrom(address sender, address receiver, uint256 id, uint256 amount) external returns (bool); +} + +/** + * @dev Optional extension of {IERC6909} that adds metadata functions. + */ +interface IERC6909Metadata is IERC6909 { + /** + * @dev Returns the name of the token of type `id`. + */ + function name(uint256 id) external view returns (string memory); + + /** + * @dev Returns the ticker symbol of the token of type `id`. + */ + function symbol(uint256 id) external view returns (string memory); + + /** + * @dev Returns the number of decimals for the token of type `id`. + */ + function decimals(uint256 id) external view returns (uint8); +} + +/** + * @dev Optional extension of {IERC6909} that adds content URI functions. + */ +interface IERC6909ContentURI is IERC6909 { + /** + * @dev Returns URI for the contract. + */ + function contractURI() external view returns (string memory); + + /** + * @dev Returns the URI for the token of type `id`. + */ + function tokenURI(uint256 id) external view returns (string memory); +} + +/** + * @dev Optional extension of {IERC6909} that adds a token supply function. + */ +interface IERC6909TokenSupply is IERC6909 { + /** + * @dev Returns the total supply of the token of type `id`. + */ + function totalSupply(uint256 id) external view returns (uint256); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7579.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7579.sol new file mode 100644 index 0000000..99a79c1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7579.sol @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC7579.sol) +pragma solidity >=0.8.4; + +import {PackedUserOperation} from "./draft-IERC4337.sol"; + +uint256 constant VALIDATION_SUCCESS = 0; +uint256 constant VALIDATION_FAILED = 1; +uint256 constant MODULE_TYPE_VALIDATOR = 1; +uint256 constant MODULE_TYPE_EXECUTOR = 2; +uint256 constant MODULE_TYPE_FALLBACK = 3; +uint256 constant MODULE_TYPE_HOOK = 4; + +/// @dev Minimal configuration interface for ERC-7579 modules +interface IERC7579Module { + /** + * @dev This function is called by the smart account during installation of the module + * @param data arbitrary data that may be passed to the module during `onInstall` initialization + * + * MUST revert on error (e.g. if module is already enabled) + */ + function onInstall(bytes calldata data) external; + + /** + * @dev This function is called by the smart account during uninstallation of the module + * @param data arbitrary data that may be passed to the module during `onUninstall` de-initialization + * + * MUST revert on error + */ + function onUninstall(bytes calldata data) external; + + /** + * @dev Returns boolean value if module is a certain type + * @param moduleTypeId the module type ID according the ERC-7579 spec + * + * MUST return true if the module is of the given type and false otherwise + */ + function isModuleType(uint256 moduleTypeId) external view returns (bool); +} + +/** + * @dev ERC-7579 Validation module (type 1). + * + * A module that implements logic to validate user operations and signatures. + */ +interface IERC7579Validator is IERC7579Module { + /** + * @dev Validates a UserOperation + * @param userOp the ERC-4337 PackedUserOperation + * @param userOpHash the hash of the ERC-4337 PackedUserOperation + * + * MUST validate that the signature is a valid signature of the userOpHash + * SHOULD return ERC-4337's SIG_VALIDATION_FAILED (and not revert) on signature mismatch + * See {IAccount-validateUserOp} for additional information on the return value + */ + function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external returns (uint256); + + /** + * @dev Validates a signature using ERC-1271 + * @param sender the address that sent the ERC-1271 request to the smart account + * @param hash the hash of the ERC-1271 request + * @param signature the signature of the ERC-1271 request + * + * MUST return the ERC-1271 `MAGIC_VALUE` if the signature is valid + * MUST NOT modify state + */ + function isValidSignatureWithSender( + address sender, + bytes32 hash, + bytes calldata signature + ) external view returns (bytes4); +} + +/** + * @dev ERC-7579 Hooks module (type 4). + * + * A module that implements logic to execute before and after the account executes a user operation, + * either individually or batched. + */ +interface IERC7579Hook is IERC7579Module { + /** + * @dev Called by the smart account before execution + * @param msgSender the address that called the smart account + * @param value the value that was sent to the smart account + * @param msgData the data that was sent to the smart account + * + * MAY return arbitrary data in the `hookData` return value + */ + function preCheck( + address msgSender, + uint256 value, + bytes calldata msgData + ) external returns (bytes memory hookData); + + /** + * @dev Called by the smart account after execution + * @param hookData the data that was returned by the `preCheck` function + * + * MAY validate the `hookData` to validate transaction context of the `preCheck` function + */ + function postCheck(bytes calldata hookData) external; +} + +struct Execution { + address target; + uint256 value; + bytes callData; +} + +/** + * @dev ERC-7579 Execution. + * + * Accounts should implement this interface so that the Entrypoint and ERC-7579 modules can execute operations. + */ +interface IERC7579Execution { + /** + * @dev Executes a transaction on behalf of the account. + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data + * + * MUST ensure adequate authorization control: e.g. onlyEntryPointOrSelf if used with ERC-4337 + * If a mode is requested that is not supported by the Account, it MUST revert + */ + function execute(bytes32 mode, bytes calldata executionCalldata) external payable; + + /** + * @dev Executes a transaction on behalf of the account. + * This function is intended to be called by Executor Modules + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data + * @return returnData An array with the returned data of each executed subcall + * + * MUST ensure adequate authorization control: i.e. onlyExecutorModule + * If a mode is requested that is not supported by the Account, it MUST revert + */ + function executeFromExecutor( + bytes32 mode, + bytes calldata executionCalldata + ) external payable returns (bytes[] memory returnData); +} + +/** + * @dev ERC-7579 Account Config. + * + * Accounts should implement this interface to expose information that identifies the account, supported modules and capabilities. + */ +interface IERC7579AccountConfig { + /** + * @dev Returns the account id of the smart account + * @return accountImplementationId the account id of the smart account + * + * MUST return a non-empty string + * The accountId SHOULD be structured like so: + * "vendorname.accountname.semver" + * The id SHOULD be unique across all smart accounts + */ + function accountId() external view returns (string memory accountImplementationId); + + /** + * @dev Function to check if the account supports a certain execution mode (see above) + * @param encodedMode the encoded mode + * + * MUST return true if the account supports the mode and false otherwise + */ + function supportsExecutionMode(bytes32 encodedMode) external view returns (bool); + + /** + * @dev Function to check if the account supports a certain module typeId + * @param moduleTypeId the module type ID according to the ERC-7579 spec + * + * MUST return true if the account supports the module type and false otherwise + */ + function supportsModule(uint256 moduleTypeId) external view returns (bool); +} + +/** + * @dev ERC-7579 Module Config. + * + * Accounts should implement this interface to allow installing and uninstalling modules. + */ +interface IERC7579ModuleConfig { + event ModuleInstalled(uint256 moduleTypeId, address module); + event ModuleUninstalled(uint256 moduleTypeId, address module); + + /** + * @dev Installs a Module of a certain type on the smart account + * @param moduleTypeId the module type ID according to the ERC-7579 spec + * @param module the module address + * @param initData arbitrary data that may be passed to the module during `onInstall` + * initialization. + * + * MUST implement authorization control + * MUST call `onInstall` on the module with the `initData` parameter if provided + * MUST emit ModuleInstalled event + * MUST revert if the module is already installed or the initialization on the module failed + */ + function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external; + + /** + * @dev Uninstalls a Module of a certain type on the smart account + * @param moduleTypeId the module type ID according the ERC-7579 spec + * @param module the module address + * @param deInitData arbitrary data that may be passed to the module during `onUninstall` + * deinitialization. + * + * MUST implement authorization control + * MUST call `onUninstall` on the module with the `deInitData` parameter if provided + * MUST emit ModuleUninstalled event + * MUST revert if the module is not installed or the deInitialization on the module failed + */ + function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external; + + /** + * @dev Returns whether a module is installed on the smart account + * @param moduleTypeId the module type ID according the ERC-7579 spec + * @param module the module address + * @param additionalContext arbitrary data that may be passed to determine if the module is installed + * + * MUST return true if the module is installed and false otherwise + */ + function isModuleInstalled( + uint256 moduleTypeId, + address module, + bytes calldata additionalContext + ) external view returns (bool); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7674.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7674.sol new file mode 100644 index 0000000..240c0e9 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7674.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC7674.sol) + +pragma solidity >=0.6.2; + +import {IERC20} from "./IERC20.sol"; + +/** + * @dev Temporary Approval Extension for ERC-20 (https://github.com/ethereum/ERCs/pull/358[ERC-7674]) + */ +interface IERC7674 is IERC20 { + /** + * @dev Set the temporary allowance, allowing `spender` to withdraw (within the same transaction) assets + * held by the caller. + */ + function temporaryApprove(address spender, uint256 value) external returns (bool success); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7802.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7802.sol new file mode 100644 index 0000000..940eddd --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7802.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC7802.sol) +pragma solidity >=0.6.2; + +import {IERC165} from "./IERC165.sol"; + +/// @title IERC7802 +/// @notice Defines the interface for crosschain ERC20 transfers. +interface IERC7802 is IERC165 { + /// @notice Emitted when a crosschain transfer mints tokens. + /// @param to Address of the account tokens are being minted for. + /// @param amount Amount of tokens minted. + /// @param sender Address of the caller (msg.sender) who invoked crosschainMint. + event CrosschainMint(address indexed to, uint256 amount, address indexed sender); + + /// @notice Emitted when a crosschain transfer burns tokens. + /// @param from Address of the account tokens are being burned from. + /// @param amount Amount of tokens burned. + /// @param sender Address of the caller (msg.sender) who invoked crosschainBurn. + event CrosschainBurn(address indexed from, uint256 amount, address indexed sender); + + /// @notice Mint tokens through a crosschain transfer. + /// @param _to Address to mint tokens to. + /// @param _amount Amount of tokens to mint. + function crosschainMint(address _to, uint256 _amount) external; + + /// @notice Burn tokens through a crosschain transfer. + /// @param _from Address to burn tokens from. + /// @param _amount Amount of tokens to burn. + function crosschainBurn(address _from, uint256 _amount) external; +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7821.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7821.sol new file mode 100644 index 0000000..8a11a6e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7821.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC7821.sol) + +pragma solidity >=0.5.0; + +/** + * @dev Interface for minimal batch executor. + */ +interface IERC7821 { + /** + * @dev Executes the calls in `executionData`. + * Reverts and bubbles up error if any call fails. + * + * `executionData` encoding: + * - If `opData` is empty, `executionData` is simply `abi.encode(calls)`. + * - Else, `executionData` is `abi.encode(calls, opData)`. + * See: https://eips.ethereum.org/EIPS/eip-7579 + * + * Supported modes: + * - `bytes32(0x01000000000000000000...)`: does not support optional `opData`. + * - `bytes32(0x01000000000078210001...)`: supports optional `opData`. + * + * Authorization checks: + * - If `opData` is empty, the implementation SHOULD require that + * `msg.sender == address(this)`. + * - If `opData` is not empty, the implementation SHOULD use the signature + * encoded in `opData` to determine if the caller can perform the execution. + * + * `opData` may be used to store additional data for authentication, + * paymaster data, gas limits, etc. + * + * For calldata compression efficiency, if a Call.to is `address(0)`, + * it will be replaced with `address(this)`. + */ + function execute(bytes32 mode, bytes calldata executionData) external payable; + + /** + * @dev This function is provided for frontends to detect support. + * Only returns true for: + * - `bytes32(0x01000000000000000000...)`: does not support optional `opData`. + * - `bytes32(0x01000000000078210001...)`: supports optional `opData`. + */ + function supportsExecutionMode(bytes32 mode) external view returns (bool); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol new file mode 100644 index 0000000..cdff6f7 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (metatx/ERC2771Context.sol) + +pragma solidity ^0.8.20; + +import {Context} from "../utils/Context.sol"; + +/** + * @dev Context variant with ERC-2771 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 ERC-2771 + * 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`. + * + * WARNING: The usage of `delegatecall` in this contract is dangerous and may result in context corruption. + * Any forwarded request to this contract triggering a `delegatecall` to itself will result in an invalid {_msgSender} + * recovery. + */ +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) { + uint256 calldataLength = msg.data.length; + uint256 contextSuffixLength = _contextSuffixLength(); + if (calldataLength >= contextSuffixLength && isTrustedForwarder(msg.sender)) { + unchecked { + return address(bytes20(msg.data[calldataLength - contextSuffixLength:])); + } + } 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) { + uint256 calldataLength = msg.data.length; + uint256 contextSuffixLength = _contextSuffixLength(); + if (calldataLength >= contextSuffixLength && isTrustedForwarder(msg.sender)) { + unchecked { + return msg.data[:calldataLength - contextSuffixLength]; + } + } else { + return super._msgData(); + } + } + + /** + * @dev ERC-2771 specifies the context as being a single address (20 bytes). + */ + function _contextSuffixLength() internal view virtual override returns (uint256) { + return 20; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Forwarder.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Forwarder.sol new file mode 100644 index 0000000..a463e70 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Forwarder.sol @@ -0,0 +1,372 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.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"; +import {Errors} from "../utils/Errors.sol"; + +/** + * @dev A forwarder compatible with ERC-2771 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 Errors.FailedCall(); + } + } + + /** + * @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 isValid, address signer) { + (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 ("memory-safe") { + 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. + * + * NOTE: Consider the execution of this forwarder is permissionless. Without this check, anyone may transfer assets + * that are owned by, or are approved to this forwarder. + */ + function _isTrustedByTarget(address target) internal view virtual returns (bool) { + bytes memory encodedParams = abi.encodeCall(ERC2771Context.isTrustedForwarder, (address(this))); + + bool success; + uint256 returnSize; + uint256 returnValue; + assembly ("memory-safe") { + // Perform the staticcall 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 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 + assembly ("memory-safe") { + invalid() + } + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/README.adoc new file mode 100644 index 0000000..c02fb10 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/README.adoc @@ -0,0 +1,17 @@ += Meta Transactions + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/metatx + +This directory includes contracts for adding meta-transaction capabilities (i.e. abstracting the execution context from the transaction origin) following the https://eips.ethereum.org/EIPS/eip-2771[ERC-2771 specification]. + +- {ERC2771Context}: Provides a mechanism to override the sender and calldata of the execution context (`msg.sender` and `msg.data`) with a custom value specified by a trusted forwarder. +- {ERC2771Forwarder}: A production-ready forwarder that relays operation requests signed off-chain by an EOA. + +== Core + +{{ERC2771Context}} + +== Utils + +{{ERC2771Forwarder}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagedTarget.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagedTarget.sol new file mode 100644 index 0000000..673feed --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagerMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagerMock.sol new file mode 100644 index 0000000..4b5be35 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagerMock.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {AccessManager} from "../access/manager/AccessManager.sol"; + +contract AccessManagerMock is AccessManager { + event CalledRestricted(address caller); + event CalledUnrestricted(address caller); + + constructor(address initialAdmin) AccessManager(initialAdmin) {} + + function fnRestricted() public onlyAuthorized { + emit CalledRestricted(msg.sender); + } + + function fnUnrestricted() public { + emit CalledUnrestricted(msg.sender); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol new file mode 100644 index 0000000..68f7d1d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol @@ -0,0 +1,171 @@ +// 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 value) external view returns (uint256) { + return _array.findUpperBound(value); + } + + function lowerBound(uint256 value) external view returns (uint256) { + return _array.lowerBound(value); + } + + function upperBound(uint256 value) external view returns (uint256) { + return _array.upperBound(value); + } + + function lowerBoundMemory(uint256[] memory array, uint256 value) external pure returns (uint256) { + return array.lowerBoundMemory(value); + } + + function upperBoundMemory(uint256[] memory array, uint256 value) external pure returns (uint256) { + return array.upperBoundMemory(value); + } + + function unsafeAccess(uint256 pos) external view returns (uint256) { + return _array.unsafeAccess(pos).value; + } + + function sort(uint256[] memory array) external pure returns (uint256[] memory) { + return array.sort(); + } + + function sortReverse(uint256[] memory array) external pure returns (uint256[] memory) { + return array.sort(_reverse); + } + + function _reverse(uint256 a, uint256 b) private pure returns (bool) { + return a > b; + } + + function unsafeSetLength(uint256 newLength) external { + _array.unsafeSetLength(newLength); + } + + function length() external view returns (uint256) { + return _array.length; + } +} + +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; + } + + function sort(address[] memory array) external pure returns (address[] memory) { + return array.sort(); + } + + function sortReverse(address[] memory array) external pure returns (address[] memory) { + return array.sort(_reverse); + } + + function _reverse(address a, address b) private pure returns (bool) { + return uint160(a) > uint160(b); + } + + function unsafeSetLength(uint256 newLength) external { + _array.unsafeSetLength(newLength); + } + + function length() external view returns (uint256) { + return _array.length; + } +} + +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; + } + + function sort(bytes32[] memory array) external pure returns (bytes32[] memory) { + return array.sort(); + } + + function sortReverse(bytes32[] memory array) external pure returns (bytes32[] memory) { + return array.sort(_reverse); + } + + function _reverse(bytes32 a, bytes32 b) private pure returns (bool) { + return uint256(a) > uint256(b); + } + + function unsafeSetLength(uint256 newLength) external { + _array.unsafeSetLength(newLength); + } + + function length() external view returns (uint256) { + return _array.length; + } +} + +contract BytesArraysMock { + using Arrays for bytes[]; + + bytes[] private _array; + + constructor(bytes[] memory array) { + _array = array; + } + + function unsafeAccess(uint256 pos) external view returns (bytes memory) { + return _array.unsafeAccess(pos).value; + } + + function unsafeSetLength(uint256 newLength) external { + _array.unsafeSetLength(newLength); + } + + function length() external view returns (uint256) { + return _array.length; + } +} + +contract StringArraysMock { + using Arrays for string[]; + + string[] private _array; + + constructor(string[] memory array) { + _array = array; + } + + function unsafeAccess(uint256 pos) external view returns (string memory) { + return _array.unsafeAccess(pos).value; + } + + function unsafeSetLength(uint256 newLength) external { + _array.unsafeSetLength(newLength); + } + + function length() external view returns (uint256) { + return _array.length; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AuthorityMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AuthorityMock.sol new file mode 100644 index 0000000..cd2356e --- /dev/null +++ b/typescript/packages/account-modules/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 private _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 private _immediate; + uint256 private _delay; + + function canCall( + address /* caller */, + address /* target */, + bytes4 /* selector */ + ) external view returns (bool immediate, uint256 delay) { + return (_immediate, _delay); + } + + function _setImmediate(bool immediate) external { + _immediate = immediate; + } + + function _setDelay(uint256 delay) external { + _delay = delay; + } +} + +contract AuthorityNoResponse { + function canCall(address /* caller */, address /* target */, bytes4 /* selector */) external view {} +} + +contract AuthorityObserveIsConsuming { + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Base64Dirty.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Base64Dirty.sol new file mode 100644 index 0000000..238bd26 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Base64Dirty.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Base64} from "../utils/Base64.sol"; + +contract Base64Dirty { + struct A { + uint256 value; + } + + function encode(bytes memory input) public pure returns (string memory) { + A memory unused = A({value: type(uint256).max}); + // To silence warning + unused; + + return Base64.encode(input); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/BatchCaller.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/BatchCaller.sol new file mode 100644 index 0000000..740691b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/BatchCaller.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Address} from "../utils/Address.sol"; + +contract BatchCaller { + struct Call { + address target; + uint256 value; + bytes data; + } + + function execute(Call[] calldata calls) external returns (bytes[] memory) { + bytes[] memory returndata = new bytes[](calls.length); + for (uint256 i = 0; i < calls.length; ++i) { + returndata[i] = Address.functionCallWithValue(calls[i].target, calls[i].data, calls[i].value); + } + return returndata; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol new file mode 100644 index 0000000..8b5ec7a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract CallReceiverMock { + event MockFunctionCalled(); + event MockFunctionCalledWithArgs(uint256 a, uint256 b); + event MockFunctionCalledExtra(address caller, uint256 value); + + 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"; + } + + function mockFunctionExtra() public payable { + emit MockFunctionCalledExtra(msg.sender, msg.value); + } +} + +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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ConstructorMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ConstructorMock.sol new file mode 100644 index 0000000..50e671b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ConstructorMock.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract ConstructorMock { + bool foo; + + enum RevertType { + None, + RevertWithoutMessage, + RevertWithMessage, + RevertWithCustomError, + Panic + } + + error CustomError(); + + constructor(RevertType error) { + // After transpilation to upgradeable contract, the constructor will become an initializer + // To silence the `... can be restricted to view` warning, we write to state + foo = true; + + if (error == RevertType.RevertWithoutMessage) { + revert(); + } else if (error == RevertType.RevertWithMessage) { + revert("ConstructorMock: reverting"); + } else if (error == RevertType.RevertWithCustomError) { + revert CustomError(); + } else if (error == RevertType.Panic) { + uint256 a = uint256(0) / uint256(0); + a; + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol new file mode 100644 index 0000000..199b2a9 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol new file mode 100644 index 0000000..0f11474 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.22; + +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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol new file mode 100644 index 0000000..fe32a21 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol new file mode 100644 index 0000000..cba7d47 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165InterfacesSupported.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165InterfacesSupported.sol new file mode 100644 index 0000000..dffd6a2 --- /dev/null +++ b/typescript/packages/account-modules/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 ERC-165 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol new file mode 100644 index 0000000..3542756 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol new file mode 100644 index 0000000..fec4339 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol new file mode 100644 index 0000000..78ef9c8 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol new file mode 100644 index 0000000..4bfacfd --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol new file mode 100644 index 0000000..33887cf --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ContextMock} from "./ContextMock.sol"; +import {Context} from "../utils/Context.sol"; +import {Multicall} from "../utils/Multicall.sol"; +import {ERC2771Context} from "../metatx/ERC2771Context.sol"; + +// By inheriting from ERC2771Context, Context's internal functions are overridden automatically +contract ERC2771ContextMock is ContextMock, ERC2771Context, Multicall { + /// @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(); + } + + function _contextSuffixLength() internal view override(Context, ERC2771Context) returns (uint256) { + return ERC2771Context._contextSuffixLength(); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol new file mode 100644 index 0000000..261fea1 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol new file mode 100644 index 0000000..1b1c936 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol new file mode 100644 index 0000000..7f76caa --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleProofCustomHashMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleProofCustomHashMock.sol new file mode 100644 index 0000000..1039af3 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleProofCustomHashMock.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {MerkleProof} from "../utils/cryptography/MerkleProof.sol"; + +// This could be a library, but then we would have to add it to the Stateless.sol mock for upgradeable tests +abstract contract MerkleProofCustomHashMock { + function customHash(bytes32 a, bytes32 b) internal pure returns (bytes32) { + return a < b ? sha256(abi.encode(a, b)) : sha256(abi.encode(b, a)); + } + + function verify(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal view returns (bool) { + return MerkleProof.verify(proof, root, leaf, customHash); + } + + function processProof(bytes32[] calldata proof, bytes32 leaf) internal view returns (bytes32) { + return MerkleProof.processProof(proof, leaf, customHash); + } + + function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal view returns (bool) { + return MerkleProof.verifyCalldata(proof, root, leaf, customHash); + } + + function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal view returns (bytes32) { + return MerkleProof.processProofCalldata(proof, leaf, customHash); + } + + function multiProofVerify( + bytes32[] calldata proof, + bool[] calldata proofFlags, + bytes32 root, + bytes32[] calldata leaves + ) internal view returns (bool) { + return MerkleProof.multiProofVerify(proof, proofFlags, root, leaves, customHash); + } + + function processMultiProof( + bytes32[] calldata proof, + bool[] calldata proofFlags, + bytes32[] calldata leaves + ) internal view returns (bytes32) { + return MerkleProof.processMultiProof(proof, proofFlags, leaves, customHash); + } + + function multiProofVerifyCalldata( + bytes32[] calldata proof, + bool[] calldata proofFlags, + bytes32 root, + bytes32[] calldata leaves + ) internal view returns (bool) { + return MerkleProof.multiProofVerifyCalldata(proof, proofFlags, root, leaves, customHash); + } + + function processMultiProofCalldata( + bytes32[] calldata proof, + bool[] calldata proofFlags, + bytes32[] calldata leaves + ) internal view returns (bytes32) { + return MerkleProof.processMultiProofCalldata(proof, proofFlags, leaves, customHash); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleTreeMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleTreeMock.sol new file mode 100644 index 0000000..48ee1a6 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleTreeMock.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {MerkleTree} from "../utils/structs/MerkleTree.sol"; + +contract MerkleTreeMock { + using MerkleTree for MerkleTree.Bytes32PushTree; + + MerkleTree.Bytes32PushTree private _tree; + + // This mock only stored the latest root. + // Production contract may want to store historical values. + bytes32 public root; + + event LeafInserted(bytes32 leaf, uint256 index, bytes32 root); + event LeafUpdated(bytes32 oldLeaf, bytes32 newLeaf, uint256 index, bytes32 root); + + function setup(uint8 _depth, bytes32 _zero) public { + root = _tree.setup(_depth, _zero); + } + + function push(bytes32 leaf) public { + (uint256 leafIndex, bytes32 currentRoot) = _tree.push(leaf); + emit LeafInserted(leaf, leafIndex, currentRoot); + root = currentRoot; + } + + function update(uint256 index, bytes32 oldValue, bytes32 newValue, bytes32[] memory proof) public { + (bytes32 oldRoot, bytes32 newRoot) = _tree.update(index, oldValue, newValue, proof); + if (oldRoot != root) revert MerkleTree.MerkleTreeUpdateInvalidProof(); + emit LeafUpdated(oldValue, newValue, index, newRoot); + root = newRoot; + } + + function depth() public view returns (uint256) { + return _tree.depth(); + } + + // internal state + function nextLeafIndex() public view returns (uint256) { + return _tree._nextLeafIndex; + } + + function sides(uint256 i) public view returns (bytes32) { + return _tree._sides[i]; + } + + function zeros(uint256 i) public view returns (bytes32) { + return _tree._zeros[i]; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MulticallHelper.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MulticallHelper.sol new file mode 100644 index 0000000..d70f3bf --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MulticallHelper.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20MulticallMock} from "./token/ERC20MulticallMock.sol"; + +contract MulticallHelper { + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol new file mode 100644 index 0000000..51030ac --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol new file mode 100644 index 0000000..fa701e2 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol new file mode 100644 index 0000000..3df2d1c --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol new file mode 100644 index 0000000..39e2d5e --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyTransientMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyTransientMock.sol new file mode 100644 index 0000000..f0e61ea --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyTransientMock.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {ReentrancyGuardTransient} from "../utils/ReentrancyGuardTransient.sol"; +import {ReentrancyAttack} from "./ReentrancyAttack.sol"; + +contract ReentrancyTransientMock is ReentrancyGuardTransient { + 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, "ReentrancyTransientMock: 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol new file mode 100644 index 0000000..19b9706 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol new file mode 100644 index 0000000..0bd3c61 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Stateless.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Stateless.sol new file mode 100644 index 0000000..8977f87 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Stateless.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +// 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 {Blockhash} from "../utils/Blockhash.sol"; +import {Bytes} from "../utils/Bytes.sol"; +import {CAIP2} from "../utils/CAIP2.sol"; +import {CAIP10} from "../utils/CAIP10.sol"; +import {Checkpoints} from "../utils/structs/Checkpoints.sol"; +import {CircularBuffer} from "../utils/structs/CircularBuffer.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 {EIP7702Utils} from "../account/utils/EIP7702Utils.sol"; +import {EnumerableMap} from "../utils/structs/EnumerableMap.sol"; +import {EnumerableSet} from "../utils/structs/EnumerableSet.sol"; +import {ERC165} from "../utils/introspection/ERC165.sol"; +import {ERC165Checker} from "../utils/introspection/ERC165Checker.sol"; +import {ERC721Holder} from "../token/ERC721/utils/ERC721Holder.sol"; +import {ERC1155Holder} from "../token/ERC1155/utils/ERC1155Holder.sol"; +import {ERC1967Utils} from "../proxy/ERC1967/ERC1967Utils.sol"; +import {ERC4337Utils} from "../account/utils/draft-ERC4337Utils.sol"; +import {ERC7579Utils} from "../account/utils/draft-ERC7579Utils.sol"; +import {ERC7913P256Verifier} from "../utils/cryptography/verifiers/ERC7913P256Verifier.sol"; +import {ERC7913RSAVerifier} from "../utils/cryptography/verifiers/ERC7913RSAVerifier.sol"; +import {Heap} from "../utils/structs/Heap.sol"; +import {Math} from "../utils/math/Math.sol"; +import {MerkleProof} from "../utils/cryptography/MerkleProof.sol"; +import {MessageHashUtils} from "../utils/cryptography/MessageHashUtils.sol"; +import {Nonces} from "../utils/Nonces.sol"; +import {NoncesKeyed} from "../utils/NoncesKeyed.sol"; +import {P256} from "../utils/cryptography/P256.sol"; +import {Packing} from "../utils/Packing.sol"; +import {Panic} from "../utils/Panic.sol"; +import {RSA} from "../utils/cryptography/RSA.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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol new file mode 100644 index 0000000..ec176e2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT +// This file was procedurally generated from scripts/generate/templates/StorageSlotMock.js. + +pragma solidity ^0.8.20; + +import {Multicall} from "../utils/Multicall.sol"; +import {StorageSlot} from "../utils/StorageSlot.sol"; + +contract StorageSlotMock is Multicall { + using StorageSlot for *; + + function setAddressSlot(bytes32 slot, address value) public { + slot.getAddressSlot().value = value; + } + + function setBooleanSlot(bytes32 slot, bool value) public { + slot.getBooleanSlot().value = value; + } + + function setBytes32Slot(bytes32 slot, bytes32 value) public { + slot.getBytes32Slot().value = value; + } + + function setUint256Slot(bytes32 slot, uint256 value) public { + slot.getUint256Slot().value = value; + } + + function setInt256Slot(bytes32 slot, int256 value) public { + slot.getInt256Slot().value = value; + } + + function getAddressSlot(bytes32 slot) public view returns (address) { + return slot.getAddressSlot().value; + } + + function getBooleanSlot(bytes32 slot) public view returns (bool) { + return slot.getBooleanSlot().value; + } + + function getBytes32Slot(bytes32 slot) public view returns (bytes32) { + return slot.getBytes32Slot().value; + } + + function getUint256Slot(bytes32 slot) public view returns (uint256) { + return slot.getUint256Slot().value; + } + + function getInt256Slot(bytes32 slot) public view returns (int256) { + return slot.getInt256Slot().value; + } + + mapping(uint256 key => string) public stringMap; + + function setStringSlot(bytes32 slot, string calldata value) public { + slot.getStringSlot().value = value; + } + + function setStringStorage(uint256 key, string calldata value) public { + stringMap[key].getStringSlot().value = value; + } + + function getStringSlot(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 setBytesSlot(bytes32 slot, bytes calldata value) public { + slot.getBytesSlot().value = value; + } + + function setBytesStorage(uint256 key, bytes calldata value) public { + bytesMap[key].getBytesSlot().value = value; + } + + function getBytesSlot(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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TimelockReentrant.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TimelockReentrant.sol new file mode 100644 index 0000000..aab676a --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TransientSlotMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TransientSlotMock.sol new file mode 100644 index 0000000..6b18fa5 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TransientSlotMock.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +// This file was procedurally generated from scripts/generate/templates/TransientSlotMock.js. + +pragma solidity ^0.8.24; + +import {Multicall} from "../utils/Multicall.sol"; +import {TransientSlot} from "../utils/TransientSlot.sol"; + +contract TransientSlotMock is Multicall { + using TransientSlot for *; + + event AddressValue(bytes32 slot, address value); + + function tloadAddress(bytes32 slot) public { + emit AddressValue(slot, slot.asAddress().tload()); + } + + function tstore(bytes32 slot, address value) public { + slot.asAddress().tstore(value); + } + + event BooleanValue(bytes32 slot, bool value); + + function tloadBoolean(bytes32 slot) public { + emit BooleanValue(slot, slot.asBoolean().tload()); + } + + function tstore(bytes32 slot, bool value) public { + slot.asBoolean().tstore(value); + } + + event Bytes32Value(bytes32 slot, bytes32 value); + + function tloadBytes32(bytes32 slot) public { + emit Bytes32Value(slot, slot.asBytes32().tload()); + } + + function tstore(bytes32 slot, bytes32 value) public { + slot.asBytes32().tstore(value); + } + + event Uint256Value(bytes32 slot, uint256 value); + + function tloadUint256(bytes32 slot) public { + emit Uint256Value(slot, slot.asUint256().tload()); + } + + function tstore(bytes32 slot, uint256 value) public { + slot.asUint256().tstore(value); + } + + event Int256Value(bytes32 slot, int256 value); + + function tloadInt256(bytes32 slot) public { + emit Int256Value(slot, slot.asInt256().tload()); + } + + function tstore(bytes32 slot, int256 value) public { + slot.asInt256().tstore(value); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/UpgradeableBeaconMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/UpgradeableBeaconMock.sol new file mode 100644 index 0000000..354ac02 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesExtendedMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesExtendedMock.sol new file mode 100644 index 0000000..9c45619 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesExtendedMock.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {VotesExtended} from "../governance/utils/VotesExtended.sol"; + +abstract contract VotesExtendedMock is VotesExtended { + 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 VotesExtendedTimestampMock is VotesExtendedMock { + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol new file mode 100644 index 0000000..e28d6b5 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/AccountMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/AccountMock.sol new file mode 100644 index 0000000..a870156 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/AccountMock.sol @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.27; + +import {Account} from "../../account/Account.sol"; +import {AccountERC7579} from "../../account/extensions/draft-AccountERC7579.sol"; +import {AccountERC7579Hooked} from "../../account/extensions/draft-AccountERC7579Hooked.sol"; +import {ERC721Holder} from "../../token/ERC721/utils/ERC721Holder.sol"; +import {ERC1155Holder} from "../../token/ERC1155/utils/ERC1155Holder.sol"; +import {ERC4337Utils} from "../../account/utils/draft-ERC4337Utils.sol"; +import {ERC7739} from "../../utils/cryptography/signers/draft-ERC7739.sol"; +import {ERC7821} from "../../account/extensions/draft-ERC7821.sol"; +import {MODULE_TYPE_VALIDATOR} from "../../interfaces/draft-IERC7579.sol"; +import {PackedUserOperation} from "../../interfaces/draft-IERC4337.sol"; +import {AbstractSigner} from "../../utils/cryptography/signers/AbstractSigner.sol"; +import {SignerECDSA} from "../../utils/cryptography/signers/SignerECDSA.sol"; +import {SignerP256} from "../../utils/cryptography/signers/SignerP256.sol"; +import {SignerRSA} from "../../utils/cryptography/signers/SignerRSA.sol"; +import {SignerERC7702} from "../../utils/cryptography/signers/SignerERC7702.sol"; +import {SignerERC7913} from "../../utils/cryptography/signers/SignerERC7913.sol"; +import {MultiSignerERC7913} from "../../utils/cryptography/signers/MultiSignerERC7913.sol"; +import {MultiSignerERC7913Weighted} from "../../utils/cryptography/signers/MultiSignerERC7913Weighted.sol"; + +abstract contract AccountMock is Account, ERC7739, ERC7821, ERC721Holder, ERC1155Holder { + /// Validates a user operation with a boolean signature. + function _rawSignatureValidation(bytes32 hash, bytes calldata signature) internal pure override returns (bool) { + return signature.length >= 32 && bytes32(signature) == hash; + } + + /// @inheritdoc ERC7821 + function _erc7821AuthorizedExecutor( + address caller, + bytes32 mode, + bytes calldata executionData + ) internal view virtual override returns (bool) { + return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); + } +} + +abstract contract AccountECDSAMock is Account, SignerECDSA, ERC7739, ERC7821, ERC721Holder, ERC1155Holder { + /// @inheritdoc ERC7821 + function _erc7821AuthorizedExecutor( + address caller, + bytes32 mode, + bytes calldata executionData + ) internal view virtual override returns (bool) { + return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); + } +} + +abstract contract AccountP256Mock is Account, SignerP256, ERC7739, ERC7821, ERC721Holder, ERC1155Holder { + /// @inheritdoc ERC7821 + function _erc7821AuthorizedExecutor( + address caller, + bytes32 mode, + bytes calldata executionData + ) internal view virtual override returns (bool) { + return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); + } +} + +abstract contract AccountRSAMock is Account, SignerRSA, ERC7739, ERC7821, ERC721Holder, ERC1155Holder { + /// @inheritdoc ERC7821 + function _erc7821AuthorizedExecutor( + address caller, + bytes32 mode, + bytes calldata executionData + ) internal view virtual override returns (bool) { + return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); + } +} + +abstract contract AccountERC7702Mock is Account, SignerERC7702, ERC7739, ERC7821, ERC721Holder, ERC1155Holder { + /// @inheritdoc ERC7821 + function _erc7821AuthorizedExecutor( + address caller, + bytes32 mode, + bytes calldata executionData + ) internal view virtual override returns (bool) { + return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); + } +} + +abstract contract AccountERC7702WithModulesMock is + Account, + AccountERC7579, + SignerERC7702, + ERC7739, + ERC721Holder, + ERC1155Holder +{ + function _validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) internal virtual override(Account, AccountERC7579) returns (uint256) { + return super._validateUserOp(userOp, userOpHash); + } + + /// @dev Resolve implementation of ERC-1271 by both ERC7739 and AccountERC7579 to support both schemes. + function isValidSignature( + bytes32 hash, + bytes calldata signature + ) public view virtual override(ERC7739, AccountERC7579) returns (bytes4) { + // ERC-7739 can return the fn selector (success), 0xffffffff (invalid) or 0x77390001 (detection). + // If the return is 0xffffffff, we fallback to validation using ERC-7579 modules. + bytes4 erc7739magic = ERC7739.isValidSignature(hash, signature); + return erc7739magic == bytes4(0xffffffff) ? AccountERC7579.isValidSignature(hash, signature) : erc7739magic; + } + + /// @dev Enable signature using the ERC-7702 signer. + function _rawSignatureValidation( + bytes32 hash, + bytes calldata signature + ) internal view virtual override(AbstractSigner, AccountERC7579, SignerERC7702) returns (bool) { + return SignerERC7702._rawSignatureValidation(hash, signature); + } +} + +abstract contract AccountERC7579Mock is AccountERC7579 { + constructor(address validator, bytes memory initData) { + _installModule(MODULE_TYPE_VALIDATOR, validator, initData); + } +} + +abstract contract AccountERC7579HookedMock is AccountERC7579Hooked { + constructor(address validator, bytes memory initData) { + _installModule(MODULE_TYPE_VALIDATOR, validator, initData); + } +} + +abstract contract AccountERC7913Mock is Account, SignerERC7913, ERC7739, ERC7821, ERC721Holder, ERC1155Holder { + /// @inheritdoc ERC7821 + function _erc7821AuthorizedExecutor( + address caller, + bytes32 mode, + bytes calldata executionData + ) internal view virtual override returns (bool) { + return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); + } +} + +abstract contract AccountMultiSignerMock is Account, MultiSignerERC7913, ERC7739, ERC7821, ERC721Holder, ERC1155Holder { + /// @inheritdoc ERC7821 + function _erc7821AuthorizedExecutor( + address caller, + bytes32 mode, + bytes calldata executionData + ) internal view virtual override returns (bool) { + return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); + } +} + +abstract contract AccountMultiSignerWeightedMock is + Account, + MultiSignerERC7913Weighted, + ERC7739, + ERC7821, + ERC721Holder, + ERC1155Holder +{ + /// @inheritdoc ERC7821 + function _erc7821AuthorizedExecutor( + address caller, + bytes32 mode, + bytes calldata executionData + ) internal view virtual override returns (bool) { + return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/modules/ERC7579Mock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/modules/ERC7579Mock.sol new file mode 100644 index 0000000..4cb559e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/modules/ERC7579Mock.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {MODULE_TYPE_HOOK, MODULE_TYPE_FALLBACK, MODULE_TYPE_VALIDATOR, IERC7579Hook, IERC7579Module, IERC7579Validator} from "../../../interfaces/draft-IERC7579.sol"; +import {SignatureChecker} from "../../../utils/cryptography/SignatureChecker.sol"; +import {PackedUserOperation} from "../../../interfaces/draft-IERC4337.sol"; +import {IERC1271} from "../../../interfaces/IERC1271.sol"; +import {ERC4337Utils} from "../../../account/utils/draft-ERC4337Utils.sol"; + +abstract contract ERC7579ModuleMock is IERC7579Module { + uint256 private _moduleTypeId; + + event ModuleInstalledReceived(address account, bytes data); + event ModuleUninstalledReceived(address account, bytes data); + + constructor(uint256 moduleTypeId) { + _moduleTypeId = moduleTypeId; + } + + function onInstall(bytes calldata data) public virtual { + emit ModuleInstalledReceived(msg.sender, data); + } + + function onUninstall(bytes calldata data) public virtual { + emit ModuleUninstalledReceived(msg.sender, data); + } + + function isModuleType(uint256 moduleTypeId) external view returns (bool) { + return moduleTypeId == _moduleTypeId; + } +} + +abstract contract ERC7579HookMock is ERC7579ModuleMock(MODULE_TYPE_HOOK), IERC7579Hook { + event PreCheck(address sender, uint256 value, bytes data); + event PostCheck(bytes hookData); + + function preCheck( + address msgSender, + uint256 value, + bytes calldata msgData + ) external returns (bytes memory hookData) { + emit PreCheck(msgSender, value, msgData); + return msgData; + } + + function postCheck(bytes calldata hookData) external { + emit PostCheck(hookData); + } +} + +abstract contract ERC7579FallbackHandlerMock is ERC7579ModuleMock(MODULE_TYPE_FALLBACK) { + event ERC7579FallbackHandlerMockCalled(address account, address sender, uint256 value, bytes data); + + error ERC7579FallbackHandlerMockRevert(); + + function _msgAccount() internal view returns (address) { + return msg.sender; + } + + function _msgSender() internal pure returns (address) { + return address(bytes20(msg.data[msg.data.length - 20:])); + } + + function _msgData() internal pure returns (bytes calldata) { + return msg.data[:msg.data.length - 20]; + } + + function callPayable() public payable { + emit ERC7579FallbackHandlerMockCalled(_msgAccount(), _msgSender(), msg.value, _msgData()); + } + + function callView() public view returns (address, address) { + return (_msgAccount(), _msgSender()); + } + + function callRevert() public pure { + revert ERC7579FallbackHandlerMockRevert(); + } +} + +abstract contract ERC7579ValidatorMock is ERC7579ModuleMock(MODULE_TYPE_VALIDATOR), IERC7579Validator { + mapping(address sender => address signer) private _associatedSigners; + + function onInstall(bytes calldata data) public virtual override(IERC7579Module, ERC7579ModuleMock) { + _associatedSigners[msg.sender] = address(bytes20(data[0:20])); + super.onInstall(data); + } + + function onUninstall(bytes calldata data) public virtual override(IERC7579Module, ERC7579ModuleMock) { + delete _associatedSigners[msg.sender]; + super.onUninstall(data); + } + + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) public view virtual returns (uint256) { + return + SignatureChecker.isValidSignatureNow(_associatedSigners[msg.sender], userOpHash, userOp.signature) + ? ERC4337Utils.SIG_VALIDATION_SUCCESS + : ERC4337Utils.SIG_VALIDATION_FAILED; + } + + function isValidSignatureWithSender( + address /*sender*/, + bytes32 hash, + bytes calldata signature + ) public view virtual returns (bytes4) { + return + SignatureChecker.isValidSignatureNow(_associatedSigners[msg.sender], hash, signature) + ? IERC1271.isValidSignature.selector + : bytes4(0xffffffff); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/utils/ERC7579UtilsMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/utils/ERC7579UtilsMock.sol new file mode 100644 index 0000000..e0a1e1a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/utils/ERC7579UtilsMock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {CallType, ExecType, ModeSelector, ModePayload} from "../../../account/utils/draft-ERC7579Utils.sol"; + +contract ERC7579UtilsGlobalMock { + function eqCallTypeGlobal(CallType callType1, CallType callType2) internal pure returns (bool) { + return callType1 == callType2; + } + + function eqExecTypeGlobal(ExecType execType1, ExecType execType2) internal pure returns (bool) { + return execType1 == execType2; + } + + function eqModeSelectorGlobal(ModeSelector modeSelector1, ModeSelector modeSelector2) internal pure returns (bool) { + return modeSelector1 == modeSelector2; + } + + function eqModePayloadGlobal(ModePayload modePayload1, ModePayload modePayload2) internal pure returns (bool) { + return modePayload1 == modePayload2; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol new file mode 100644 index 0000000..c72ed08 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC20WithAutoMinerReward.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC20WithAutoMinerReward.sol new file mode 100644 index 0000000..46be532 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC20WithAutoMinerReward.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; + +contract ERC20WithAutoMinerReward is ERC20 { + constructor() ERC20("Reward", "RWD") { + _mintMinerReward(); + } + + function _mintMinerReward() internal { + _mint(block.coinbase, 1000); + } + + function _update(address from, address to, uint256 value) internal virtual override { + if (!(from == address(0) && to == block.coinbase)) { + _mintMinerReward(); + } + super._update(from, to, value); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC4626Fees.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC4626Fees.sol new file mode 100644 index 0000000..dd49933 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC4626Fees.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IERC20} from "../../token/ERC20/IERC20.sol"; +import {ERC4626} from "../../token/ERC20/extensions/ERC4626.sol"; +import {SafeERC20} from "../../token/ERC20/utils/SafeERC20.sol"; +import {Math} from "../../utils/math/Math.sol"; + +/// @dev ERC-4626 vault with entry/exit fees expressed in https://en.wikipedia.org/wiki/Basis_point[basis point (bp)]. +/// +/// NOTE: The contract charges fees in terms of assets, not shares. This means that the fees are calculated based on the +/// amount of assets that are being deposited or withdrawn, and not based on the amount of shares that are being minted or +/// redeemed. This is an opinionated design decision that should be taken into account when integrating this contract. +/// +/// WARNING: This contract has not been audited and shouldn't be considered production ready. Consider using it with caution. +abstract contract ERC4626Fees is ERC4626 { + using Math for uint256; + + uint256 private constant _BASIS_POINT_SCALE = 1e4; + + // === Overrides === + + /// @dev Preview taking an entry fee on deposit. See {IERC4626-previewDeposit}. + function previewDeposit(uint256 assets) public view virtual override returns (uint256) { + uint256 fee = _feeOnTotal(assets, _entryFeeBasisPoints()); + return super.previewDeposit(assets - fee); + } + + /// @dev Preview adding an entry fee on mint. See {IERC4626-previewMint}. + function previewMint(uint256 shares) public view virtual override returns (uint256) { + uint256 assets = super.previewMint(shares); + return assets + _feeOnRaw(assets, _entryFeeBasisPoints()); + } + + /// @dev Preview adding an exit fee on withdraw. See {IERC4626-previewWithdraw}. + function previewWithdraw(uint256 assets) public view virtual override returns (uint256) { + uint256 fee = _feeOnRaw(assets, _exitFeeBasisPoints()); + return super.previewWithdraw(assets + fee); + } + + /// @dev Preview taking an exit fee on redeem. See {IERC4626-previewRedeem}. + function previewRedeem(uint256 shares) public view virtual override returns (uint256) { + uint256 assets = super.previewRedeem(shares); + return assets - _feeOnTotal(assets, _exitFeeBasisPoints()); + } + + /// @dev Send entry fee to {_entryFeeRecipient}. See {IERC4626-_deposit}. + function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual override { + uint256 fee = _feeOnTotal(assets, _entryFeeBasisPoints()); + address recipient = _entryFeeRecipient(); + + super._deposit(caller, receiver, assets, shares); + + if (fee > 0 && recipient != address(this)) { + SafeERC20.safeTransfer(IERC20(asset()), recipient, fee); + } + } + + /// @dev Send exit fee to {_exitFeeRecipient}. See {IERC4626-_deposit}. + function _withdraw( + address caller, + address receiver, + address owner, + uint256 assets, + uint256 shares + ) internal virtual override { + uint256 fee = _feeOnRaw(assets, _exitFeeBasisPoints()); + address recipient = _exitFeeRecipient(); + + super._withdraw(caller, receiver, owner, assets, shares); + + if (fee > 0 && recipient != address(this)) { + SafeERC20.safeTransfer(IERC20(asset()), recipient, fee); + } + } + + // === Fee configuration === + + function _entryFeeBasisPoints() internal view virtual returns (uint256) { + return 0; // replace with e.g. 100 for 1% + } + + function _exitFeeBasisPoints() internal view virtual returns (uint256) { + return 0; // replace with e.g. 100 for 1% + } + + function _entryFeeRecipient() internal view virtual returns (address) { + return address(0); // replace with e.g. a treasury address + } + + function _exitFeeRecipient() internal view virtual returns (address) { + return address(0); // replace with e.g. a treasury address + } + + // === Fee operations === + + /// @dev Calculates the fees that should be added to an amount `assets` that does not already include fees. + /// Used in {IERC4626-mint} and {IERC4626-withdraw} operations. + function _feeOnRaw(uint256 assets, uint256 feeBasisPoints) private pure returns (uint256) { + return assets.mulDiv(feeBasisPoints, _BASIS_POINT_SCALE, Math.Rounding.Ceil); + } + + /// @dev Calculates the fee part of an amount `assets` that already includes fees. + /// Used in {IERC4626-deposit} and {IERC4626-redeem} operations. + function _feeOnTotal(uint256 assets, uint256 feeBasisPoints) private pure returns (uint256) { + return assets.mulDiv(feeBasisPoints, feeBasisPoints + _BASIS_POINT_SCALE, Math.Rounding.Ceil); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/MyNFT.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/MyNFT.sol new file mode 100644 index 0000000..1a442fa --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/MyNFT.sol @@ -0,0 +1,9 @@ +// contracts/MyNFT.sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC721} from "../../token/ERC721/ERC721.sol"; + +contract MyNFT is ERC721 { + constructor() ERC721("MyNFT", "MNFT") {} +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintBase.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintBase.sol new file mode 100644 index 0000000..25139cb --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintBase.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {AccessControl} from "../../../access/AccessControl.sol"; +import {ERC20} from "../../../token/ERC20/ERC20.sol"; + +contract AccessControlERC20MintBase is ERC20, AccessControl { + // Create a new role identifier for the minter role + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + + error CallerNotMinter(address caller); + + constructor(address minter) ERC20("MyToken", "TKN") { + // Grant the minter role to a specified account + _grantRole(MINTER_ROLE, minter); + } + + function mint(address to, uint256 amount) public { + // Check that the calling account has the minter role + if (!hasRole(MINTER_ROLE, msg.sender)) { + revert CallerNotMinter(msg.sender); + } + _mint(to, amount); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintMissing.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintMissing.sol new file mode 100644 index 0000000..46002fd --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintMissing.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {AccessControl} from "../../../access/AccessControl.sol"; +import {ERC20} from "../../../token/ERC20/ERC20.sol"; + +contract AccessControlERC20MintMissing is ERC20, AccessControl { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); + + constructor() ERC20("MyToken", "TKN") { + // Grant the contract deployer the default admin role: it will be able + // to grant and revoke any roles + _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); + } + + function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { + _mint(to, amount); + } + + function burn(address from, uint256 amount) public onlyRole(BURNER_ROLE) { + _burn(from, amount); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintOnlyRole.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintOnlyRole.sol new file mode 100644 index 0000000..a71060a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintOnlyRole.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {AccessControl} from "../../../access/AccessControl.sol"; +import {ERC20} from "../../../token/ERC20/ERC20.sol"; + +contract AccessControlERC20Mint is ERC20, AccessControl { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); + + constructor(address minter, address burner) ERC20("MyToken", "TKN") { + _grantRole(MINTER_ROLE, minter); + _grantRole(BURNER_ROLE, burner); + } + + function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { + _mint(to, amount); + } + + function burn(address from, uint256 amount) public onlyRole(BURNER_ROLE) { + _burn(from, amount); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlModified.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlModified.sol new file mode 100644 index 0000000..479fa20 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlModified.sol @@ -0,0 +1,14 @@ +// contracts/AccessControlModified.sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {AccessControl} from "../../../access/AccessControl.sol"; + +contract AccessControlModified is AccessControl { + error AccessControlNonRevocable(); + + // Override the revokeRole function + function revokeRole(bytes32, address) public pure override { + revert AccessControlNonRevocable(); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessManagedERC20MintBase.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessManagedERC20MintBase.sol new file mode 100644 index 0000000..02ae00a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessManagedERC20MintBase.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {AccessManaged} from "../../../access/manager/AccessManaged.sol"; +import {ERC20} from "../../../token/ERC20/ERC20.sol"; + +contract AccessManagedERC20Mint is ERC20, AccessManaged { + constructor(address manager) ERC20("MyToken", "TKN") AccessManaged(manager) {} + + // Minting is restricted according to the manager rules for this function. + // The function is identified by its selector: 0x40c10f19. + // Calculated with bytes4(keccak256('mint(address,uint256)')) + function mint(address to, uint256 amount) public restricted { + _mint(to, amount); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/MyContractOwnable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/MyContractOwnable.sol new file mode 100644 index 0000000..0dfc804 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/MyContractOwnable.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Ownable} from "../../../access/Ownable.sol"; + +contract MyContract is Ownable { + constructor(address initialOwner) Ownable(initialOwner) {} + + function normalThing() public { + // anyone can call this normalThing() + } + + function specialThing() public onlyOwner { + // only the owner can call specialThing()! + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyAccountERC7702.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyAccountERC7702.sol new file mode 100644 index 0000000..a2f2ca4 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyAccountERC7702.sol @@ -0,0 +1,20 @@ +// contracts/MyAccountERC7702.sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Account} from "../../../account/Account.sol"; +import {ERC721Holder} from "../../../token/ERC721/utils/ERC721Holder.sol"; +import {ERC1155Holder} from "../../../token/ERC1155/utils/ERC1155Holder.sol"; +import {ERC7821} from "../../../account/extensions/draft-ERC7821.sol"; +import {SignerERC7702} from "../../../utils/cryptography/signers/SignerERC7702.sol"; + +contract MyAccountERC7702 is Account, SignerERC7702, ERC7821, ERC721Holder, ERC1155Holder { + /// @dev Allows the entry point as an authorized executor. + function _erc7821AuthorizedExecutor( + address caller, + bytes32 mode, + bytes calldata executionData + ) internal view virtual override returns (bool) { + return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyFactoryAccount.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyFactoryAccount.sol new file mode 100644 index 0000000..3db3a25 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyFactoryAccount.sol @@ -0,0 +1,37 @@ +// contracts/MyFactoryAccount.sol +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Clones} from "../../../proxy/Clones.sol"; +import {Address} from "../../../utils/Address.sol"; + +/** + * @dev A factory contract to create accounts on demand. + */ +contract MyFactoryAccount { + using Clones for address; + using Address for address; + + address private immutable _impl; + + constructor(address impl_) { + require(impl_.code.length > 0); + _impl = impl_; + } + + /// @dev Predict the address of the account + function predictAddress(bytes calldata callData) public view returns (address) { + return _impl.predictDeterministicAddress(keccak256(callData), address(this)); + } + + /// @dev Create clone accounts on demand + function cloneAndInitialize(bytes calldata callData) public returns (address) { + address predicted = predictAddress(callData); + if (predicted.code.length == 0) { + _impl.cloneDeterministic(keccak256(callData)); + predicted.functionCall(callData); + } + return predicted; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyGovernor.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyGovernor.sol new file mode 100644 index 0000000..4d38d0f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyGovernor.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {Governor} from "../../../governance/Governor.sol"; +import {GovernorCountingSimple} from "../../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotes} from "../../../governance/extensions/GovernorVotes.sol"; +import {GovernorVotesQuorumFraction} from "../../../governance/extensions/GovernorVotesQuorumFraction.sol"; +import {GovernorTimelockControl} from "../../../governance/extensions/GovernorTimelockControl.sol"; +import {TimelockController} from "../../../governance/TimelockController.sol"; +import {IVotes} from "../../../governance/utils/IVotes.sol"; + +contract MyGovernor is + Governor, + GovernorCountingSimple, + GovernorVotes, + GovernorVotesQuorumFraction, + GovernorTimelockControl +{ + constructor( + IVotes _token, + TimelockController _timelock + ) Governor("MyGovernor") GovernorVotes(_token) GovernorVotesQuorumFraction(4) GovernorTimelockControl(_timelock) {} + + function votingDelay() public pure override returns (uint256) { + return 7200; // 1 day + } + + function votingPeriod() public pure override returns (uint256) { + return 50400; // 1 week + } + + function proposalThreshold() public pure override returns (uint256) { + return 0; + } + + // The functions below are overrides required by Solidity. + + function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) { + return super.state(proposalId); + } + + 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(); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyToken.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyToken.sol new file mode 100644 index 0000000..cfb1675 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyToken.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC20} from "../../../token/ERC20/ERC20.sol"; +import {ERC20Permit} from "../../../token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20Votes} from "../../../token/ERC20/extensions/ERC20Votes.sol"; +import {Nonces} from "../../../utils/Nonces.sol"; + +contract MyToken is ERC20, ERC20Permit, ERC20Votes { + constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {} + + // The functions below are overrides required by Solidity. + + function _update(address from, address to, uint256 amount) internal override(ERC20, ERC20Votes) { + super._update(from, to, amount); + } + + function nonces(address owner) public view virtual override(ERC20Permit, Nonces) returns (uint256) { + return super.nonces(owner); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenTimestampBased.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenTimestampBased.sol new file mode 100644 index 0000000..7c0d329 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenTimestampBased.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC20} from "../../../token/ERC20/ERC20.sol"; +import {ERC20Permit} from "../../../token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20Votes} from "../../../token/ERC20/extensions/ERC20Votes.sol"; +import {Nonces} from "../../../utils/Nonces.sol"; + +contract MyTokenTimestampBased is ERC20, ERC20Permit, ERC20Votes { + constructor() ERC20("MyTokenTimestampBased", "MTK") ERC20Permit("MyTokenTimestampBased") {} + + // Overrides IERC6372 functions to make the token & governor timestamp-based + + function clock() public view override returns (uint48) { + return uint48(block.timestamp); + } + + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public pure override returns (string memory) { + return "mode=timestamp"; + } + + // The functions below are overrides required by Solidity. + + function _update(address from, address to, uint256 amount) internal override(ERC20, ERC20Votes) { + super._update(from, to, amount); + } + + function nonces(address owner) public view virtual override(ERC20Permit, Nonces) returns (uint256) { + return super.nonces(owner); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenWrapped.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenWrapped.sol new file mode 100644 index 0000000..c9d567d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenWrapped.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IERC20, ERC20} from "../../../token/ERC20/ERC20.sol"; +import {ERC20Permit} from "../../../token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20Votes} from "../../../token/ERC20/extensions/ERC20Votes.sol"; +import {ERC20Wrapper} from "../../../token/ERC20/extensions/ERC20Wrapper.sol"; +import {Nonces} from "../../../utils/Nonces.sol"; + +contract MyTokenWrapped is ERC20, ERC20Permit, ERC20Votes, ERC20Wrapper { + constructor( + IERC20 wrappedToken + ) ERC20("MyTokenWrapped", "MTK") ERC20Permit("MyTokenWrapped") ERC20Wrapper(wrappedToken) {} + + // The functions below are overrides required by Solidity. + + function decimals() public view override(ERC20, ERC20Wrapper) returns (uint8) { + return super.decimals(); + } + + function _update(address from, address to, uint256 amount) internal override(ERC20, ERC20Votes) { + super._update(from, to, amount); + } + + function nonces(address owner) public view virtual override(ERC20Permit, Nonces) returns (uint256) { + return super.nonces(owner); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/GameItems.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/GameItems.sol new file mode 100644 index 0000000..e84fc0b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/GameItems.sol @@ -0,0 +1,21 @@ +// contracts/GameItems.sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC1155} from "../../../../token/ERC1155/ERC1155.sol"; + +contract GameItems is ERC1155 { + uint256 public constant GOLD = 0; + uint256 public constant SILVER = 1; + uint256 public constant THORS_HAMMER = 2; + uint256 public constant SWORD = 3; + uint256 public constant SHIELD = 4; + + constructor() ERC1155("https://game.example/api/item/{id}.json") { + _mint(msg.sender, GOLD, 10 ** 18, ""); + _mint(msg.sender, SILVER, 10 ** 27, ""); + _mint(msg.sender, THORS_HAMMER, 1, ""); + _mint(msg.sender, SWORD, 10 ** 9, ""); + _mint(msg.sender, SHIELD, 10 ** 9, ""); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/MyERC115HolderContract.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/MyERC115HolderContract.sol new file mode 100644 index 0000000..742a53b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/MyERC115HolderContract.sol @@ -0,0 +1,7 @@ +// contracts/MyERC115HolderContract.sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC1155Holder} from "../../../../token/ERC1155/utils/ERC1155Holder.sol"; + +contract MyERC115HolderContract is ERC1155Holder {} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC20/GLDToken.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC20/GLDToken.sol new file mode 100644 index 0000000..b6c5454 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC20/GLDToken.sol @@ -0,0 +1,11 @@ +// contracts/GLDToken.sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC20} from "../../../../token/ERC20/ERC20.sol"; + +contract GLDToken is ERC20 { + constructor(uint256 initialSupply) ERC20("Gold", "GLD") { + _mint(msg.sender, initialSupply); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC6909/ERC6909GameItems.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC6909/ERC6909GameItems.sol new file mode 100644 index 0000000..611e1dd --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC6909/ERC6909GameItems.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC6909Metadata} from "../../../../token/ERC6909/extensions/draft-ERC6909Metadata.sol"; + +contract ERC6909GameItems is ERC6909Metadata { + uint256 public constant GOLD = 0; + uint256 public constant SILVER = 1; + uint256 public constant THORS_HAMMER = 2; + uint256 public constant SWORD = 3; + uint256 public constant SHIELD = 4; + + constructor() { + _setDecimals(GOLD, 18); + _setDecimals(SILVER, 18); + // Default decimals is 0 + _setDecimals(SWORD, 9); + _setDecimals(SHIELD, 9); + + _mint(msg.sender, GOLD, 10 ** 18); + _mint(msg.sender, SILVER, 10_000 ** 18); + _mint(msg.sender, THORS_HAMMER, 1); + _mint(msg.sender, SWORD, 10 ** 9); + _mint(msg.sender, SHIELD, 10 ** 9); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC721/GameItem.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC721/GameItem.sol new file mode 100644 index 0000000..b7f576f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC721/GameItem.sol @@ -0,0 +1,19 @@ +// contracts/GameItem.sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC721URIStorage, ERC721} from "../../../../token/ERC721/extensions/ERC721URIStorage.sol"; + +contract GameItem is ERC721URIStorage { + uint256 private _nextTokenId; + + constructor() ERC721("GameItem", "ITM") {} + + function awardItem(address player, string memory tokenURI) public returns (uint256) { + uint256 tokenId = _nextTokenId++; + _mint(player, tokenId); + _setTokenURI(tokenId, tokenURI); + + return tokenId; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Base64NFT.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Base64NFT.sol new file mode 100644 index 0000000..1fb6623 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Base64NFT.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC721} from "../../../token/ERC721/ERC721.sol"; +import {Strings} from "../../../utils/Strings.sol"; +import {Base64} from "../../../utils/Base64.sol"; + +contract Base64NFT is ERC721 { + using Strings for uint256; + + constructor() ERC721("Base64NFT", "MTK") {} + + // ... + + function tokenURI(uint256 tokenId) public pure override returns (string memory) { + // Equivalent to: + // { + // "name": "Base64NFT #1", + // // Replace with extra ERC-721 Metadata properties + // } + // prettier-ignore + string memory dataURI = string.concat("{\"name\": \"Base64NFT #", tokenId.toString(), "\"}"); + + return string.concat("data:application/json;base64,", Base64.encode(bytes(dataURI))); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Multicall.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Multicall.sol new file mode 100644 index 0000000..6faac6a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Multicall.sol @@ -0,0 +1,15 @@ +// contracts/Box.sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Multicall} from "../../../utils/Multicall.sol"; + +contract Box is Multicall { + function foo() public { + // ... + } + + function bar() public { + // ... + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCountingOverridableMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCountingOverridableMock.sol new file mode 100644 index 0000000..063cc36 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCountingOverridableMock.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {Governor} from "../../governance/Governor.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; +import {GovernorCountingOverridable} from "../../governance/extensions/GovernorCountingOverridable.sol"; + +abstract contract GovernorCountingOverridableMock is + GovernorSettings, + GovernorVotesQuorumFraction, + GovernorCountingOverridable +{ + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorFractionalMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorFractionalMock.sol new file mode 100644 index 0000000..ae8a2c1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorFractionalMock.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {Governor} from "../../governance/Governor.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingFractional} from "../../governance/extensions/GovernorCountingFractional.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorFractionalMock is GovernorSettings, GovernorVotesQuorumFraction, GovernorCountingFractional { + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol new file mode 100644 index 0000000..867eccf --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorNoncesKeyedMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorNoncesKeyedMock.sol new file mode 100644 index 0000000..91021cc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorNoncesKeyedMock.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {Governor, Nonces} 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"; +import {GovernorProposalGuardian} from "../../governance/extensions/GovernorProposalGuardian.sol"; +import {GovernorNoncesKeyed} from "../../governance/extensions/GovernorNoncesKeyed.sol"; + +abstract contract GovernorNoncesKeyedMock is + GovernorSettings, + GovernorVotesQuorumFraction, + GovernorCountingSimple, + GovernorNoncesKeyed +{ + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function _validateVoteSig( + uint256 proposalId, + uint8 support, + address voter, + bytes memory signature + ) internal virtual override(Governor, GovernorNoncesKeyed) returns (bool) { + return super._validateVoteSig(proposalId, support, voter, signature); + } + + function _validateExtendedVoteSig( + uint256 proposalId, + uint8 support, + address voter, + string memory reason, + bytes memory params, + bytes memory signature + ) internal virtual override(Governor, GovernorNoncesKeyed) returns (bool) { + return super._validateExtendedVoteSig(proposalId, support, voter, reason, params, signature); + } + + function _useCheckedNonce(address owner, uint256 nonce) internal virtual override(Nonces, GovernorNoncesKeyed) { + super._useCheckedNonce(owner, nonce); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol new file mode 100644 index 0000000..e403d17 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +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 _tallyUpdated(uint256 proposalId) internal override(Governor, GovernorPreventLateQuorum) { + super._tallyUpdated(proposalId); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorProposalGuardianMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorProposalGuardianMock.sol new file mode 100644 index 0000000..01e2f0a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorProposalGuardianMock.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +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"; +import {GovernorProposalGuardian} from "../../governance/extensions/GovernorProposalGuardian.sol"; + +abstract contract GovernorProposalGuardianMock is + GovernorSettings, + GovernorVotesQuorumFraction, + GovernorCountingSimple, + GovernorProposalGuardian +{ + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function _validateCancel( + uint256 proposalId, + address caller + ) internal view override(Governor, GovernorProposalGuardian) returns (bool) { + return super._validateCancel(proposalId, caller); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSequentialProposalIdMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSequentialProposalIdMock.sol new file mode 100644 index 0000000..0bd86dc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSequentialProposalIdMock.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +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"; +import {GovernorSequentialProposalId} from "../../governance/extensions/GovernorSequentialProposalId.sol"; + +abstract contract GovernorSequentialProposalIdMock is + GovernorSettings, + GovernorVotesQuorumFraction, + GovernorCountingSimple, + GovernorSequentialProposalId +{ + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function getProposalId( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public view virtual override(Governor, GovernorSequentialProposalId) returns (uint256) { + return super.getProposalId(targets, values, calldatas, descriptionHash); + } + + function _propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description, + address proposer + ) internal virtual override(Governor, GovernorSequentialProposalId) returns (uint256 proposalId) { + return super._propose(targets, values, calldatas, description, proposer); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorStorageMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorStorageMock.sol new file mode 100644 index 0000000..9b2178e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorStorageMock.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSuperQuorumMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSuperQuorumMock.sol new file mode 100644 index 0000000..72e8f16 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSuperQuorumMock.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {Governor} from "../../governance/Governor.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorVotes} from "../../governance/extensions/GovernorVotes.sol"; +import {GovernorSuperQuorum} from "../../governance/extensions/GovernorSuperQuorum.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorTimelockControl} from "../../governance/extensions/GovernorTimelockControl.sol"; + +abstract contract GovernorSuperQuorumMock is + GovernorSettings, + GovernorVotes, + GovernorTimelockControl, + GovernorSuperQuorum, + GovernorCountingSimple +{ + uint256 private _quorum; + uint256 private _superQuorum; + + constructor(uint256 quorum_, uint256 superQuorum_) { + _quorum = quorum_; + _superQuorum = superQuorum_; + } + + function quorum(uint256) public view override returns (uint256) { + return _quorum; + } + + function superQuorum(uint256) public view override returns (uint256) { + return _superQuorum; + } + + function state( + uint256 proposalId + ) public view override(Governor, GovernorSuperQuorum, GovernorTimelockControl) returns (ProposalState) { + return super.state(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function proposalVotes( + uint256 proposalId + ) + public + view + virtual + override(GovernorCountingSimple, GovernorSuperQuorum) + returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) + { + return super.proposalVotes(proposalId); + } + + 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 _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 _executor() internal view override(Governor, GovernorTimelockControl) returns (address) { + return super._executor(); + } + + 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 proposalNeedsQueuing( + uint256 proposalId + ) public view override(Governor, GovernorTimelockControl) returns (bool) { + return super.proposalNeedsQueuing(proposalId); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockAccessMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockAccessMock.sol new file mode 100644 index 0000000..64ad64b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockAccessMock.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol new file mode 100644 index 0000000..71508cd --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol new file mode 100644 index 0000000..0ff6fdf --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol new file mode 100644 index 0000000..ea699a3 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVotesSuperQuorumFractionMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVotesSuperQuorumFractionMock.sol new file mode 100644 index 0000000..1f4282e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVotesSuperQuorumFractionMock.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {Governor} from "../../governance/Governor.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorSuperQuorum} from "../../governance/extensions/GovernorSuperQuorum.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotesSuperQuorumFraction} from "../../governance/extensions/GovernorVotesSuperQuorumFraction.sol"; + +abstract contract GovernorVotesSuperQuorumFractionMock is + GovernorSettings, + GovernorVotesSuperQuorumFraction, + GovernorCountingSimple +{ + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function proposalVotes( + uint256 proposalId + ) + public + view + virtual + override(GovernorCountingSimple, GovernorSuperQuorum) + returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) + { + return super.proposalVotes(proposalId); + } + + function state( + uint256 proposalId + ) public view override(Governor, GovernorVotesSuperQuorumFraction) returns (ProposalState) { + return super.state(proposalId); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol new file mode 100644 index 0000000..6c31c99 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +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) returns (uint256) { + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol new file mode 100644 index 0000000..f3153a8 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol new file mode 100644 index 0000000..43d5a34 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol new file mode 100644 index 0000000..8c5641e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.22; + +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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol new file mode 100644 index 0000000..2a85d1d --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ForceApproveMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ForceApproveMock.sol new file mode 100644 index 0000000..6bd957e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ForceApproveMock.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC1363} from "../../token/ERC20/extensions/ERC1363.sol"; + +// contract that replicate USDT approval behavior in approveAndCall +abstract contract ERC1363ForceApproveMock is ERC1363 { + function approveAndCall(address spender, uint256 amount, bytes memory data) public virtual override returns (bool) { + require(amount == 0 || allowance(msg.sender, spender) == 0, "USDT approval failure"); + return super.approveAndCall(spender, amount, data); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363NoReturnMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363NoReturnMock.sol new file mode 100644 index 0000000..45136ed --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363NoReturnMock.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC1363} from "../../token/ERC20/extensions/ERC1363.sol"; + +abstract contract ERC1363NoReturnMock is ERC1363 { + function transferAndCall(address to, uint256 value, bytes memory data) public override returns (bool) { + super.transferAndCall(to, value, data); + assembly { + return(0, 0) + } + } + + function transferFromAndCall( + address from, + address to, + uint256 value, + bytes memory data + ) public override returns (bool) { + super.transferFromAndCall(from, to, value, data); + assembly { + return(0, 0) + } + } + + function approveAndCall(address spender, uint256 value, bytes memory data) public override returns (bool) { + super.approveAndCall(spender, value, data); + assembly { + return(0, 0) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReceiverMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReceiverMock.sol new file mode 100644 index 0000000..d33e05e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReceiverMock.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IERC1363Receiver} from "../../interfaces/IERC1363Receiver.sol"; + +contract ERC1363ReceiverMock is IERC1363Receiver { + enum RevertType { + None, + RevertWithoutMessage, + RevertWithMessage, + RevertWithCustomError, + Panic + } + + bytes4 private _retval; + RevertType private _error; + + event Received(address operator, address from, uint256 value, bytes data); + error CustomError(bytes4); + + constructor() { + _retval = IERC1363Receiver.onTransferReceived.selector; + _error = RevertType.None; + } + + function setUp(bytes4 retval, RevertType error) public { + _retval = retval; + _error = error; + } + + function onTransferReceived( + address operator, + address from, + uint256 value, + bytes calldata data + ) external override returns (bytes4) { + if (_error == RevertType.RevertWithoutMessage) { + revert(); + } else if (_error == RevertType.RevertWithMessage) { + revert("ERC1363ReceiverMock: 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, value, data); + return _retval; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReturnFalseMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReturnFalseMock.sol new file mode 100644 index 0000000..afdd01f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReturnFalseMock.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IERC20, ERC20} from "../../token/ERC20/ERC20.sol"; +import {ERC1363} from "../../token/ERC20/extensions/ERC1363.sol"; + +abstract contract ERC1363ReturnFalseOnERC20Mock is ERC1363 { + function transfer(address, uint256) public pure override(IERC20, ERC20) returns (bool) { + return false; + } + + function transferFrom(address, address, uint256) public pure override(IERC20, ERC20) returns (bool) { + return false; + } + + function approve(address, uint256) public pure override(IERC20, ERC20) returns (bool) { + return false; + } +} + +abstract contract ERC1363ReturnFalseMock is ERC1363 { + function transferAndCall(address, uint256, bytes memory) public pure override returns (bool) { + return false; + } + + function transferFromAndCall(address, address, uint256, bytes memory) public pure override returns (bool) { + return false; + } + + function approveAndCall(address, uint256, bytes memory) public pure override returns (bool) { + return false; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363SpenderMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363SpenderMock.sol new file mode 100644 index 0000000..b12c4c1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363SpenderMock.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IERC1363Spender} from "../../interfaces/IERC1363Spender.sol"; + +contract ERC1363SpenderMock is IERC1363Spender { + enum RevertType { + None, + RevertWithoutMessage, + RevertWithMessage, + RevertWithCustomError, + Panic + } + + bytes4 private _retval; + RevertType private _error; + + event Approved(address owner, uint256 value, bytes data); + error CustomError(bytes4); + + constructor() { + _retval = IERC1363Spender.onApprovalReceived.selector; + _error = RevertType.None; + } + + function setUp(bytes4 retval, RevertType error) public { + _retval = retval; + _error = error; + } + + function onApprovalReceived(address owner, uint256 value, bytes calldata data) external override returns (bytes4) { + if (_error == RevertType.RevertWithoutMessage) { + revert(); + } else if (_error == RevertType.RevertWithMessage) { + revert("ERC1363SpenderMock: reverting"); + } else if (_error == RevertType.RevertWithCustomError) { + revert CustomError(_retval); + } else if (_error == RevertType.Panic) { + uint256 a = uint256(0) / uint256(0); + a; + } + + emit Approved(owner, value, data); + return _retval; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ApprovalMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ApprovalMock.sol new file mode 100644 index 0000000..ff33a36 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20BridgeableMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20BridgeableMock.sol new file mode 100644 index 0000000..6249cb6 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20BridgeableMock.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20, ERC20Bridgeable} from "../../token/ERC20/extensions/draft-ERC20Bridgeable.sol"; + +abstract contract ERC20BridgeableMock is ERC20Bridgeable { + address private _bridge; + + error OnlyTokenBridge(); + event OnlyTokenBridgeFnCalled(address caller); + + constructor(address bridge) { + _bridge = bridge; + } + + function onlyTokenBridgeFn() external onlyTokenBridge { + emit OnlyTokenBridgeFnCalled(msg.sender); + } + + function _checkTokenBridge(address sender) internal view override { + if (sender != _bridge) { + revert OnlyTokenBridge(); + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol new file mode 100644 index 0000000..a26e1f5 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ExcessDecimalsMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ExcessDecimalsMock.sol new file mode 100644 index 0000000..4627efd --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol new file mode 100644 index 0000000..508573c --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ForceApproveMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ForceApproveMock.sol new file mode 100644 index 0000000..aecfb9e --- /dev/null +++ b/typescript/packages/account-modules/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 replicates 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20GetterHelper.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20GetterHelper.sol new file mode 100644 index 0000000..acdcced --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20GetterHelper.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IERC20} from "../../token/ERC20/IERC20.sol"; +import {IERC20Metadata} from "../../token/ERC20/extensions/IERC20Metadata.sol"; + +contract ERC20GetterHelper { + event ERC20TotalSupply(IERC20 token, uint256 totalSupply); + event ERC20BalanceOf(IERC20 token, address account, uint256 balanceOf); + event ERC20Allowance(IERC20 token, address owner, address spender, uint256 allowance); + event ERC20Name(IERC20Metadata token, string name); + event ERC20Symbol(IERC20Metadata token, string symbol); + event ERC20Decimals(IERC20Metadata token, uint8 decimals); + + function totalSupply(IERC20 token) external { + emit ERC20TotalSupply(token, token.totalSupply()); + } + + function balanceOf(IERC20 token, address account) external { + emit ERC20BalanceOf(token, account, token.balanceOf(account)); + } + + function allowance(IERC20 token, address owner, address spender) external { + emit ERC20Allowance(token, owner, spender, token.allowance(owner, spender)); + } + + function name(IERC20Metadata token) external { + emit ERC20Name(token, token.name()); + } + + function symbol(IERC20Metadata token) external { + emit ERC20Symbol(token, token.symbol()); + } + + function decimals(IERC20Metadata token) external { + emit ERC20Decimals(token, token.decimals()); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol new file mode 100644 index 0000000..39ab129 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol new file mode 100644 index 0000000..dce3e70 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol new file mode 100644 index 0000000..2129537 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Reentrant.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Reentrant.sol new file mode 100644 index 0000000..813913f --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol new file mode 100644 index 0000000..94bff32 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesAdditionalCheckpointsMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesAdditionalCheckpointsMock.sol new file mode 100644 index 0000000..39b3c65 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesAdditionalCheckpointsMock.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC20Votes} from "../../token/ERC20/extensions/ERC20Votes.sol"; +import {VotesExtended, Votes} from "../../governance/utils/VotesExtended.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; + +abstract contract ERC20VotesExtendedMock is ERC20Votes, VotesExtended { + function _delegate(address account, address delegatee) internal virtual override(Votes, VotesExtended) { + return super._delegate(account, delegatee); + } + + function _transferVotingUnits( + address from, + address to, + uint256 amount + ) internal virtual override(Votes, VotesExtended) { + return super._transferVotingUnits(from, to, amount); + } +} + +abstract contract ERC20VotesExtendedTimestampMock is ERC20VotesExtendedMock { + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sol new file mode 100644 index 0000000..3246fd4 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesTimestampMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesTimestampMock.sol new file mode 100644 index 0000000..78fdfae --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesTimestampMock.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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626LimitsMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626LimitsMock.sol new file mode 100644 index 0000000..a845365 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626Mock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626Mock.sol new file mode 100644 index 0000000..22ac5e8 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sol new file mode 100644 index 0000000..3dde095 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4646FeesMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4646FeesMock.sol new file mode 100644 index 0000000..368b078 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol new file mode 100644 index 0000000..7732ae4 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol new file mode 100644 index 0000000..1098647 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol new file mode 100644 index 0000000..14120f5 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol new file mode 100644 index 0000000..254435e --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/utils/cryptography/ERC7739Mock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/utils/cryptography/ERC7739Mock.sol new file mode 100644 index 0000000..c803a40 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/utils/cryptography/ERC7739Mock.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ECDSA} from "../../../utils/cryptography/ECDSA.sol"; +import {ERC7739} from "../../../utils/cryptography/signers/draft-ERC7739.sol"; +import {SignerECDSA} from "../../../utils/cryptography/signers/SignerECDSA.sol"; +import {SignerP256} from "../../../utils/cryptography/signers/SignerP256.sol"; +import {SignerRSA} from "../../../utils/cryptography/signers/SignerRSA.sol"; + +abstract contract ERC7739ECDSAMock is ERC7739, SignerECDSA {} +abstract contract ERC7739P256Mock is ERC7739, SignerP256 {} +abstract contract ERC7739RSAMock is ERC7739, SignerRSA {} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/package.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/package.json new file mode 100644 index 0000000..8ccb946 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/package.json @@ -0,0 +1,32 @@ +{ + "name": "@openzeppelin/contracts", + "description": "Secure Smart Contract library for Solidity", + "version": "5.4.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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Clones.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Clones.sol new file mode 100644 index 0000000..1eb71b7 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Clones.sol @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (proxy/Clones.sol) + +pragma solidity ^0.8.20; + +import {Create2} from "../utils/Create2.sol"; +import {Errors} from "../utils/Errors.sol"; + +/** + * @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-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 { + error CloneArgumentsTooLong(); + + /** + * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation`. + * + * This function uses the create opcode, which should never revert. + * + * WARNING: This function does not check if `implementation` has code. A clone that points to an address + * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they + * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. + */ + function clone(address implementation) internal returns (address instance) { + return clone(implementation, 0); + } + + /** + * @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency + * to the new contract. + * + * WARNING: This function does not check if `implementation` has code. A clone that points to an address + * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they + * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. + * + * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory) + * to always have enough balance for new deployments. Consider exposing this function under a payable method. + */ + function clone(address implementation, uint256 value) internal returns (address instance) { + if (address(this).balance < value) { + revert Errors.InsufficientBalance(address(this).balance, value); + } + assembly ("memory-safe") { + // 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(value, 0x09, 0x37) + } + if (instance == address(0)) { + revert Errors.FailedDeployment(); + } + } + + /** + * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation`. + * + * This function uses the create2 opcode and a `salt` to deterministically deploy + * the clone. Using the same `implementation` and `salt` multiple times will revert, since + * the clones cannot be deployed twice at the same address. + * + * WARNING: This function does not check if `implementation` has code. A clone that points to an address + * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they + * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. + */ + function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { + return cloneDeterministic(implementation, salt, 0); + } + + /** + * @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with + * a `value` parameter to send native currency to the new contract. + * + * WARNING: This function does not check if `implementation` has code. A clone that points to an address + * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they + * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. + * + * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory) + * to always have enough balance for new deployments. Consider exposing this function under a payable method. + */ + function cloneDeterministic( + address implementation, + bytes32 salt, + uint256 value + ) internal returns (address instance) { + if (address(this).balance < value) { + revert Errors.InsufficientBalance(address(this).balance, value); + } + assembly ("memory-safe") { + // 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(value, 0x09, 0x37, salt) + } + if (instance == address(0)) { + revert Errors.FailedDeployment(); + } + } + + /** + * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. + */ + function predictDeterministicAddress( + address implementation, + bytes32 salt, + address deployer + ) internal pure returns (address predicted) { + assembly ("memory-safe") { + 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 := and(keccak256(add(ptr, 0x43), 0x55), 0xffffffffffffffffffffffffffffffffffffffff) + } + } + + /** + * @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)); + } + + /** + * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom + * immutable arguments. These are provided through `args` and cannot be changed after deployment. To + * access the arguments within the implementation, use {fetchCloneArgs}. + * + * This function uses the create opcode, which should never revert. + * + * WARNING: This function does not check if `implementation` has code. A clone that points to an address + * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they + * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. + */ + function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance) { + return cloneWithImmutableArgs(implementation, args, 0); + } + + /** + * @dev Same as {xref-Clones-cloneWithImmutableArgs-address-bytes-}[cloneWithImmutableArgs], but with a `value` + * parameter to send native currency to the new contract. + * + * WARNING: This function does not check if `implementation` has code. A clone that points to an address + * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they + * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. + * + * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory) + * to always have enough balance for new deployments. Consider exposing this function under a payable method. + */ + function cloneWithImmutableArgs( + address implementation, + bytes memory args, + uint256 value + ) internal returns (address instance) { + if (address(this).balance < value) { + revert Errors.InsufficientBalance(address(this).balance, value); + } + bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args); + assembly ("memory-safe") { + instance := create(value, add(bytecode, 0x20), mload(bytecode)) + } + if (instance == address(0)) { + revert Errors.FailedDeployment(); + } + } + + /** + * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom + * immutable arguments. These are provided through `args` and cannot be changed after deployment. To + * access the arguments within the implementation, use {fetchCloneArgs}. + * + * This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same + * `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice + * at the same address. + * + * WARNING: This function does not check if `implementation` has code. A clone that points to an address + * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they + * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. + */ + function cloneDeterministicWithImmutableArgs( + address implementation, + bytes memory args, + bytes32 salt + ) internal returns (address instance) { + return cloneDeterministicWithImmutableArgs(implementation, args, salt, 0); + } + + /** + * @dev Same as {xref-Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-}[cloneDeterministicWithImmutableArgs], + * but with a `value` parameter to send native currency to the new contract. + * + * WARNING: This function does not check if `implementation` has code. A clone that points to an address + * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they + * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. + * + * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory) + * to always have enough balance for new deployments. Consider exposing this function under a payable method. + */ + function cloneDeterministicWithImmutableArgs( + address implementation, + bytes memory args, + bytes32 salt, + uint256 value + ) internal returns (address instance) { + bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args); + return Create2.deploy(value, salt, bytecode); + } + + /** + * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}. + */ + function predictDeterministicAddressWithImmutableArgs( + address implementation, + bytes memory args, + bytes32 salt, + address deployer + ) internal pure returns (address predicted) { + bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args); + return Create2.computeAddress(salt, keccak256(bytecode), deployer); + } + + /** + * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}. + */ + function predictDeterministicAddressWithImmutableArgs( + address implementation, + bytes memory args, + bytes32 salt + ) internal view returns (address predicted) { + return predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this)); + } + + /** + * @dev Get the immutable args attached to a clone. + * + * - If `instance` is a clone that was deployed using `clone` or `cloneDeterministic`, this + * function will return an empty array. + * - If `instance` is a clone that was deployed using `cloneWithImmutableArgs` or + * `cloneDeterministicWithImmutableArgs`, this function will return the args array used at + * creation. + * - If `instance` is NOT a clone deployed using this library, the behavior is undefined. This + * function should only be used to check addresses that are known to be clones. + */ + function fetchCloneArgs(address instance) internal view returns (bytes memory) { + bytes memory result = new bytes(instance.code.length - 45); // revert if length is too short + assembly ("memory-safe") { + extcodecopy(instance, add(result, 32), 45, mload(result)) + } + return result; + } + + /** + * @dev Helper that prepares the initcode of the proxy with immutable args. + * + * An assembly variant of this function requires copying the `args` array, which can be efficiently done using + * `mcopy`. Unfortunately, that opcode is not available before cancun. A pure solidity implementation using + * abi.encodePacked is more expensive but also more portable and easier to review. + * + * NOTE: https://eips.ethereum.org/EIPS/eip-170[EIP-170] limits the length of the contract code to 24576 bytes. + * With the proxy code taking 45 bytes, that limits the length of the immutable args to 24531 bytes. + */ + function _cloneCodeWithImmutableArgs( + address implementation, + bytes memory args + ) private pure returns (bytes memory) { + if (args.length > 24531) revert CloneArgumentsTooLong(); + return + abi.encodePacked( + hex"61", + uint16(args.length + 45), + hex"3d81600a3d39f3363d3d373d3d3d363d73", + implementation, + hex"5af43d82803e903d91602b57fd5bf3", + args + ); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol new file mode 100644 index 0000000..eb482f6 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Proxy.sol) + +pragma solidity ^0.8.22; + +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[ERC-1967], 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 ERC-1967) 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol new file mode 100644 index 0000000..ffa77cc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (proxy/ERC1967/ERC1967Utils.sol) + +pragma solidity ^0.8.21; + +import {IBeacon} from "../beacon/IBeacon.sol"; +import {IERC1967} from "../../interfaces/IERC1967.sol"; +import {Address} from "../../utils/Address.sol"; +import {StorageSlot} from "../../utils/StorageSlot.sol"; + +/** + * @dev This library provides getters and event emitting update functions for + * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots. + */ +library ERC1967Utils { + /** + * @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 ERC-1967 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 IERC1967.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 ERC-1967) 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 ERC-1967 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 IERC1967.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 ERC-1967 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 IERC1967.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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol new file mode 100644 index 0000000..0e73651 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/README.adoc new file mode 100644 index 0000000..1c4d010 --- /dev/null +++ b/typescript/packages/account-modules/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[ERC-1967] storage slots. + +- {ERC1967Utils}: Internal functions to get and set the storage slots defined in ERC-1967. +- {ERC1967Proxy}: A proxy using ERC-1967 storage slots. Not upgradeable by default. + +There are two alternative ways to add upgradeability to an ERC-1967 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 Hardhat and Foundry. + +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 ERC-1967 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[ERC-1822], 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[ERC-1822] 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 ERC-1822 interface. + +== Core + +{{Proxy}} + +== ERC-1967 + +{{IERC1967}} + +{{ERC1967Proxy}} + +{{ERC1967Utils}} + +== Transparent Proxy + +{{TransparentUpgradeableProxy}} + +{{ProxyAdmin}} + +== Beacon + +{{BeaconProxy}} + +{{IBeacon}} + +{{UpgradeableBeacon}} + +== Minimal Clones + +{{Clones}} + +== Utils + +{{Initializable}} + +{{UUPSUpgradeable}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol new file mode 100644 index 0000000..36558d6 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.2.0) (proxy/beacon/BeaconProxy.sol) + +pragma solidity ^0.8.22; + +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[ERC-1967] 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol new file mode 100644 index 0000000..f911b15 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (proxy/beacon/IBeacon.sol) + +pragma solidity >=0.4.16; + +/** + * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol new file mode 100644 index 0000000..8db9bd2 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol new file mode 100644 index 0000000..eefd49a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.2.0) (proxy/transparent/ProxyAdmin.sol) + +pragma solidity ^0.8.22; + +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,address)` + * and `upgradeAndCall(address,address,bytes)` are present, and `upgrade` must be used if no function should be called, + * while `upgradeAndCall` will invoke the `receive` function if the third argument is the empty byte string. + * If the getter returns `"5.0.0"`, only `upgradeAndCall(address,address,bytes)` is present, and the third 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol new file mode 100644 index 0000000..21af0e3 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.2.0) (proxy/transparent/TransparentUpgradeableProxy.sol) + +pragma solidity ^0.8.22; + +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 { + /// @dev See {UUPSUpgradeable-upgradeToAndCall} + function upgradeToAndCall(address newImplementation, bytes calldata data) 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. Relying on the value of the admin slot + * is generally fine if the implementation is trusted. + * + * 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 view 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol new file mode 100644 index 0000000..0d05fdb --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.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 reinitialization) 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 Pointer to storage slot. Allows integrators to override it with a custom storage location. + * + * NOTE: Consider following the ERC-7201 formula to derive storage locations. + */ + function _initializableStorageSlot() internal pure virtual returns (bytes32) { + return INITIALIZABLE_STORAGE; + } + + /** + * @dev Returns a pointer to the storage namespace. + */ + // solhint-disable-next-line var-name-mixedcase + function _getInitializableStorage() private pure returns (InitializableStorage storage $) { + bytes32 slot = _initializableStorageSlot(); + assembly { + $.slot := slot + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol new file mode 100644 index 0000000..d0f5842 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/UUPSUpgradeable.sol) + +pragma solidity ^0.8.22; + +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 ERC-1967) 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 ERC-1167 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 ERC-1822 {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 ERC-1967 compliant implementation pointing to self. + */ + 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 ERC-1967. + * + * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol new file mode 100644 index 0000000..8582e0c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol @@ -0,0 +1,389 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/ERC1155.sol) + +pragma solidity ^0.8.20; + +import {IERC1155} from "./IERC1155.sol"; +import {IERC1155MetadataURI} from "./extensions/IERC1155MetadataURI.sol"; +import {ERC1155Utils} from "./utils/ERC1155Utils.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_); + } + + /// @inheritdoc IERC165 + 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 ERC]. + * + * 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; + } + + /// @inheritdoc IERC1155 + 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; + } + + /// @inheritdoc IERC1155 + function setApprovalForAll(address operator, bool approved) public virtual { + _setApprovalForAll(_msgSender(), operator, approved); + } + + /// @inheritdoc IERC1155 + function isApprovedForAll(address account, address operator) public view virtual returns (bool) { + return _operatorApprovals[account][operator]; + } + + /// @inheritdoc IERC1155 + 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); + } + + /// @inheritdoc IERC1155 + 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); + ERC1155Utils.checkOnERC1155Received(operator, from, to, id, value, data); + } else { + ERC1155Utils.checkOnERC1155BatchReceived(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 ERC]. + * + * 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 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) { + assembly ("memory-safe") { + // 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol new file mode 100644 index 0000000..f017084 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/IERC1155.sol) + +pragma solidity >=0.6.2; + +import {IERC165} from "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC-1155 compliant contract, as defined in the + * https://eips.ethereum.org/EIPS/eip-1155[ERC]. + */ +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`. + */ + 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 zero address. + */ + 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 {IERC1155Receiver-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 {IERC1155Receiver-onERC1155BatchReceived} on the receiver. + * Ensure to follow the checks-effects-interactions pattern and consider employing + * reentrancy guards when interacting with untrusted contracts. + * + * Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments. + * + * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol new file mode 100644 index 0000000..f27b897 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/IERC1155Receiver.sol) + +pragma solidity >=0.6.2; + +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 ERC-1155 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 ERC-1155 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc new file mode 100644 index 0000000..f8bf958 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc @@ -0,0 +1,43 @@ += 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[ERC-1155 Multi Token Standard]. + +The ERC 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 ERC-1155 (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}} + +{{ERC1155Utils}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol new file mode 100644 index 0000000..fd6ad61 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol new file mode 100644 index 0000000..a0de999 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/extensions/ERC1155Pausable.sol) + +pragma solidity ^0.8.20; + +import {ERC1155} from "../ERC1155.sol"; +import {Pausable} from "../../../utils/Pausable.sol"; + +/** + * @dev ERC-1155 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol new file mode 100644 index 0000000..96d5e60 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/extensions/ERC1155Supply.sol) + +pragma solidity ^0.8.20; + +import {ERC1155} from "../ERC1155.sol"; +import {Arrays} from "../../../utils/Arrays.sol"; + +/** + * @dev Extension of ERC-1155 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 { + using Arrays for uint256[]; + + 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; + } + + /// @inheritdoc ERC1155 + 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.unsafeMemoryAccess(i); + // Overflow check required: The rest of the code assumes that totalSupply never overflows + _totalSupply[ids.unsafeMemoryAccess(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.unsafeMemoryAccess(i); + + unchecked { + // Overflow not possible: values[i] <= balanceOf(from, ids[i]) <= totalSupply(ids[i]) + _totalSupply[ids.unsafeMemoryAccess(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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol new file mode 100644 index 0000000..5abf319 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/extensions/ERC1155URIStorage.sol) + +pragma solidity ^0.8.20; + +import {Strings} from "../../../utils/Strings.sol"; +import {ERC1155} from "../ERC1155.sol"; + +/** + * @dev ERC-1155 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol new file mode 100644 index 0000000..501d855 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/extensions/IERC1155MetadataURI.sol) + +pragma solidity >=0.6.2; + +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[ERC]. + */ +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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol new file mode 100644 index 0000000..19d7963 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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 ERC-1155 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 { + /// @inheritdoc IERC165 + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Utils.sol new file mode 100644 index 0000000..03cb0f0 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Utils.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/utils/ERC1155Utils.sol) + +pragma solidity ^0.8.20; + +import {IERC1155Receiver} from "../IERC1155Receiver.sol"; +import {IERC1155Errors} from "../../../interfaces/draft-IERC6093.sol"; + +/** + * @dev Library that provide common ERC-1155 utility functions. + * + * See https://eips.ethereum.org/EIPS/eip-1155[ERC-1155]. + * + * _Available since v5.1._ + */ +library ERC1155Utils { + /** + * @dev Performs an acceptance check for the provided `operator` by calling {IERC1155Receiver-onERC1155Received} + * on the `to` address. The `operator` is generally the address that initiated the token transfer (i.e. `msg.sender`). + * + * The acceptance call is not executed and treated as a no-op if the target address doesn't contain code (i.e. an EOA). + * Otherwise, the recipient must implement {IERC1155Receiver-onERC1155Received} and return the acceptance magic value to accept + * the transfer. + */ + function checkOnERC1155Received( + address operator, + address from, + address to, + uint256 id, + uint256 value, + bytes memory data + ) internal { + 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 IERC1155Errors.ERC1155InvalidReceiver(to); + } + } catch (bytes memory reason) { + if (reason.length == 0) { + // non-IERC1155Receiver implementer + revert IERC1155Errors.ERC1155InvalidReceiver(to); + } else { + assembly ("memory-safe") { + revert(add(reason, 0x20), mload(reason)) + } + } + } + } + } + + /** + * @dev Performs a batch acceptance check for the provided `operator` by calling {IERC1155Receiver-onERC1155BatchReceived} + * on the `to` address. The `operator` is generally the address that initiated the token transfer (i.e. `msg.sender`). + * + * The acceptance call is not executed and treated as a no-op if the target address doesn't contain code (i.e. an EOA). + * Otherwise, the recipient must implement {IERC1155Receiver-onERC1155Received} and return the acceptance magic value to accept + * the transfer. + */ + function checkOnERC1155BatchReceived( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory values, + bytes memory data + ) internal { + 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 IERC1155Errors.ERC1155InvalidReceiver(to); + } + } catch (bytes memory reason) { + if (reason.length == 0) { + // non-IERC1155Receiver implementer + revert IERC1155Errors.ERC1155InvalidReceiver(to); + } else { + assembly ("memory-safe") { + revert(add(reason, 0x20), mload(reason)) + } + } + } + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol new file mode 100644 index 0000000..886febc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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 ERC-20 + * applications. + */ +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}. + * + * Both 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; + } + + /// @inheritdoc IERC20 + function totalSupply() public view virtual returns (uint256) { + return _totalSupply; + } + + /// @inheritdoc IERC20 + 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; + } + + /// @inheritdoc IERC20 + 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}. + * + * Skips emitting an {Approval} event indicating an allowance update. This is not + * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve]. + * + * 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: + * + * ```solidity + * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol new file mode 100644 index 0000000..b493743 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol) + +pragma solidity >=0.4.16; + +/** + * @dev Interface of the ERC-20 standard as defined in the ERC. + */ +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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc new file mode 100644 index 0000000..e7c981e --- /dev/null +++ b/typescript/packages/account-modules/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[ERC-20 Token Standard]. + +TIP: For an overview of ERC-20 tokens and a walk through on how to create a token contract read our xref:ROOT:erc20.adoc[ERC-20 guide]. + +There are a few core contracts that implement the behavior specified in the ERC-20 standard: + +* {IERC20}: the interface all ERC-20 implementations should conform to. +* {IERC20Metadata}: the extended ERC-20 interface including the <>, <> and <> functions. +* {ERC20}: the implementation of the ERC-20 interface, including the <>, <> and <> optional extensions to the standard interface. + +Additionally there are multiple custom extensions, including: + +* {ERC20Permit}: gasless approval of tokens (standardized as ERC-2612). +* {ERC20Bridgeable}: compatibility with crosschain bridges through ERC-7802. +* {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 ERC-3156). +* {ERC20Votes}: support for voting and vote delegation. +* {ERC20Wrapper}: wrapper to create an ERC-20 backed by another ERC-20, with deposit and withdraw methods. Useful in conjunction with {ERC20Votes}. +* {ERC20TemporaryApproval}: support for approvals lasting for only one transaction, as defined in ERC-7674. +* {ERC1363}: support for calling the target of a transfer or approval, enabling code execution on the receiver within a single transaction. +* {ERC4626}: tokenized vault that manages shares (represented as ERC-20) that are backed by assets (another ERC-20). + +Finally, there are some utilities to interact with ERC-20 contracts in various ways: + +* {SafeERC20}: a wrapper around the interface that eliminates the need to handle boolean return values. + +Other utilities that support ERC-20 assets can be found in the codebase: + +* ERC-20 tokens can be timelocked (held 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 ERC-20 (such as <>) and expose them as external functions in the way they prefer. + +== Core + +{{IERC20}} + +{{IERC20Metadata}} + +{{ERC20}} + +== Extensions + +{{IERC20Permit}} + +{{ERC20Permit}} + +{{ERC20Bridgeable}} + +{{ERC20Burnable}} + +{{ERC20Capped}} + +{{ERC20Pausable}} + +{{ERC20Votes}} + +{{ERC20Wrapper}} + +{{ERC20FlashMint}} + +{{ERC20TemporaryApproval}} + +{{ERC1363}} + +{{ERC4626}} + +== Utilities + +{{SafeERC20}} + +{{ERC1363Utils}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC1363.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC1363.sol new file mode 100644 index 0000000..3b3dbba --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC1363.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/ERC1363.sol) + +pragma solidity ^0.8.20; + +import {ERC20} from "../ERC20.sol"; +import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol"; +import {IERC1363} from "../../../interfaces/IERC1363.sol"; +import {ERC1363Utils} from "../utils/ERC1363Utils.sol"; + +/** + * @title ERC1363 + * @dev Extension of {ERC20} tokens that adds support for code execution after transfers and approvals + * on recipient contracts. Calls after transfers are enabled through the {ERC1363-transferAndCall} and + * {ERC1363-transferFromAndCall} methods while calls after approvals can be made with {ERC1363-approveAndCall} + * + * _Available since v5.1._ + */ +abstract contract ERC1363 is ERC20, ERC165, IERC1363 { + /** + * @dev Indicates a failure within the {transfer} part of a transferAndCall operation. + * @param receiver Address to which tokens are being transferred. + * @param value Amount of tokens to be transferred. + */ + error ERC1363TransferFailed(address receiver, uint256 value); + + /** + * @dev Indicates a failure within the {transferFrom} part of a transferFromAndCall operation. + * @param sender Address from which to send tokens. + * @param receiver Address to which tokens are being transferred. + * @param value Amount of tokens to be transferred. + */ + error ERC1363TransferFromFailed(address sender, address receiver, uint256 value); + + /** + * @dev Indicates a failure within the {approve} part of a approveAndCall operation. + * @param spender Address which will spend the funds. + * @param value Amount of tokens to be spent. + */ + error ERC1363ApproveFailed(address spender, uint256 value); + + /// @inheritdoc IERC165 + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IERC1363).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Moves a `value` amount of tokens from the caller's account to `to` + * and then calls {IERC1363Receiver-onTransferReceived} on `to`. Returns a flag that indicates + * if the call succeeded. + * + * Requirements: + * + * - The target has code (i.e. is a contract). + * - The target `to` must implement the {IERC1363Receiver} interface. + * - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer. + * - The internal {transfer} must succeed (returned `true`). + */ + function transferAndCall(address to, uint256 value) public returns (bool) { + return transferAndCall(to, value, ""); + } + + /** + * @dev Variant of {transferAndCall} that accepts an additional `data` parameter with + * no specified format. + */ + function transferAndCall(address to, uint256 value, bytes memory data) public virtual returns (bool) { + if (!transfer(to, value)) { + revert ERC1363TransferFailed(to, value); + } + ERC1363Utils.checkOnERC1363TransferReceived(_msgSender(), _msgSender(), to, value, data); + return true; + } + + /** + * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism + * and then calls {IERC1363Receiver-onTransferReceived} on `to`. Returns a flag that indicates + * if the call succeeded. + * + * Requirements: + * + * - The target has code (i.e. is a contract). + * - The target `to` must implement the {IERC1363Receiver} interface. + * - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer. + * - The internal {transferFrom} must succeed (returned `true`). + */ + function transferFromAndCall(address from, address to, uint256 value) public returns (bool) { + return transferFromAndCall(from, to, value, ""); + } + + /** + * @dev Variant of {transferFromAndCall} that accepts an additional `data` parameter with + * no specified format. + */ + function transferFromAndCall( + address from, + address to, + uint256 value, + bytes memory data + ) public virtual returns (bool) { + if (!transferFrom(from, to, value)) { + revert ERC1363TransferFromFailed(from, to, value); + } + ERC1363Utils.checkOnERC1363TransferReceived(_msgSender(), from, to, value, data); + return true; + } + + /** + * @dev Sets a `value` amount of tokens as the allowance of `spender` over the + * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. + * Returns a flag that indicates if the call succeeded. + * + * Requirements: + * + * - The target has code (i.e. is a contract). + * - The target `spender` must implement the {IERC1363Spender} interface. + * - The target must return the {IERC1363Spender-onApprovalReceived} selector to accept the approval. + * - The internal {approve} must succeed (returned `true`). + */ + function approveAndCall(address spender, uint256 value) public returns (bool) { + return approveAndCall(spender, value, ""); + } + + /** + * @dev Variant of {approveAndCall} that accepts an additional `data` parameter with + * no specified format. + */ + function approveAndCall(address spender, uint256 value, bytes memory data) public virtual returns (bool) { + if (!approve(spender, value)) { + revert ERC1363ApproveFailed(spender, value); + } + ERC1363Utils.checkOnERC1363ApprovalReceived(_msgSender(), spender, value, data); + return true; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol new file mode 100644 index 0000000..4d482d8 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol new file mode 100644 index 0000000..c6d0900 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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; + } + + /// @inheritdoc ERC20 + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol new file mode 100644 index 0000000..4d3a31f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.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 ERC-3156 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 {IERC3156FlashBorrower-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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol new file mode 100644 index 0000000..2f6d86c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/ERC20Pausable.sol) + +pragma solidity ^0.8.20; + +import {ERC20} from "../ERC20.sol"; +import {Pausable} from "../../../utils/Pausable.sol"; + +/** + * @dev ERC-20 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol new file mode 100644 index 0000000..7efa9ed --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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 ERC-20 Permit extension allowing approvals to be made via signatures, as defined in + * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612]. + * + * Adds the {permit} method, which can be used to change an account's ERC-20 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 ERC-20 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol new file mode 100644 index 0000000..c15e7f5 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.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 ERC-20 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 {Votes-delegate} function directly, or by providing a signature to be used with {Votes-delegateBySig}. Voting + * power can be queried through the public accessors {Votes-getVotes} and {Votes-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 + * {Votes-_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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol new file mode 100644 index 0000000..8916d1a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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 ERC-20 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" ERC-20 into a governance token. + * + * WARNING: Any mechanism in which the underlying token changes the {balanceOf} of an account without an explicit transfer + * may desynchronize this contract's supply and its underlying balance. Please exercise caution when wrapping tokens that + * may undercollateralize the wrapper (i.e. wrapper's total supply is higher than its underlying balance). See {_recover} + * for recovering value accrued to the wrapper. + */ +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; + } + + /// @inheritdoc IERC20Metadata + 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 or acquired from + * rebasing mechanisms. 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol new file mode 100644 index 0000000..fd8231a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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 ERC-4626 "Tokenized Vault Standard" as defined in + * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. + * + * This extension allows the minting and burning of "shares" (represented using the ERC-20 inheritance) in exchange for + * underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends + * the ERC-20 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 introduces configurable virtual assets and shares to help developers 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 even if an attacker is able to capture value from multiple user deposits, 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:ROOT: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 (ERC-20 or ERC-777). + */ + 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 ok, uint8 assetDecimals) { + (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(); + } + + /// @inheritdoc IERC4626 + function asset() public view virtual returns (address) { + return address(_asset); + } + + /// @inheritdoc IERC4626 + function totalAssets() public view virtual returns (uint256) { + return IERC20(asset()).balanceOf(address(this)); + } + + /// @inheritdoc IERC4626 + function convertToShares(uint256 assets) public view virtual returns (uint256) { + return _convertToShares(assets, Math.Rounding.Floor); + } + + /// @inheritdoc IERC4626 + function convertToAssets(uint256 shares) public view virtual returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Floor); + } + + /// @inheritdoc IERC4626 + function maxDeposit(address) public view virtual returns (uint256) { + return type(uint256).max; + } + + /// @inheritdoc IERC4626 + function maxMint(address) public view virtual returns (uint256) { + return type(uint256).max; + } + + /// @inheritdoc IERC4626 + function maxWithdraw(address owner) public view virtual returns (uint256) { + return _convertToAssets(balanceOf(owner), Math.Rounding.Floor); + } + + /// @inheritdoc IERC4626 + function maxRedeem(address owner) public view virtual returns (uint256) { + return balanceOf(owner); + } + + /// @inheritdoc IERC4626 + function previewDeposit(uint256 assets) public view virtual returns (uint256) { + return _convertToShares(assets, Math.Rounding.Floor); + } + + /// @inheritdoc IERC4626 + function previewMint(uint256 shares) public view virtual returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Ceil); + } + + /// @inheritdoc IERC4626 + function previewWithdraw(uint256 assets) public view virtual returns (uint256) { + return _convertToShares(assets, Math.Rounding.Ceil); + } + + /// @inheritdoc IERC4626 + function previewRedeem(uint256 shares) public view virtual returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Floor); + } + + /// @inheritdoc IERC4626 + 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; + } + + /// @inheritdoc IERC4626 + 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; + } + + /// @inheritdoc IERC4626 + 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; + } + + /// @inheritdoc IERC4626 + 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 ERC-777, `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(IERC20(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 ERC-777, `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(IERC20(asset()), receiver, assets); + + emit Withdraw(caller, receiver, owner, assets, shares); + } + + function _decimalsOffset() internal view virtual returns (uint8) { + return 0; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol new file mode 100644 index 0000000..87bbafa --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Metadata.sol) + +pragma solidity >=0.6.2; + +import {IERC20} from "../IERC20.sol"; + +/** + * @dev Interface for the optional metadata functions from the ERC-20 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol new file mode 100644 index 0000000..65488ba --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Permit.sol) + +pragma solidity >=0.4.16; + +/** + * @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in + * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612]. + * + * Adds the {permit} method, which can be used to change an account's ERC-20 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20Bridgeable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20Bridgeable.sol new file mode 100644 index 0000000..3473013 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20Bridgeable.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/draft-ERC20Bridgeable.sol) + +pragma solidity ^0.8.20; + +import {ERC20} from "../ERC20.sol"; +import {ERC165, IERC165} from "../../../utils/introspection/ERC165.sol"; +import {IERC7802} from "../../../interfaces/draft-IERC7802.sol"; + +/** + * @dev ERC20 extension that implements the standard token interface according to + * https://eips.ethereum.org/EIPS/eip-7802[ERC-7802]. + */ +abstract contract ERC20Bridgeable is ERC20, ERC165, IERC7802 { + /// @dev Modifier to restrict access to the token bridge. + modifier onlyTokenBridge() { + // Token bridge should never be impersonated using a relayer/forwarder. Using msg.sender is preferable to + // _msgSender() for security reasons. + _checkTokenBridge(msg.sender); + _; + } + + /// @inheritdoc ERC165 + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IERC7802).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC7802-crosschainMint}. Emits a {IERC7802-CrosschainMint} event. + */ + function crosschainMint(address to, uint256 value) public virtual override onlyTokenBridge { + _mint(to, value); + emit CrosschainMint(to, value, _msgSender()); + } + + /** + * @dev See {IERC7802-crosschainBurn}. Emits a {IERC7802-CrosschainBurn} event. + */ + function crosschainBurn(address from, uint256 value) public virtual override onlyTokenBridge { + _burn(from, value); + emit CrosschainBurn(from, value, _msgSender()); + } + + /** + * @dev Checks if the caller is a trusted token bridge. MUST revert otherwise. + * + * Developers should implement this function using an access control mechanism that allows + * customizing the list of allowed senders. Consider using {AccessControl} or {AccessManaged}. + */ + function _checkTokenBridge(address caller) internal virtual; +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20TemporaryApproval.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20TemporaryApproval.sol new file mode 100644 index 0000000..357daa9 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20TemporaryApproval.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/extensions/draft-ERC20TemporaryApproval.sol) + +pragma solidity ^0.8.24; + +import {IERC20, ERC20} from "../ERC20.sol"; +import {IERC7674} from "../../../interfaces/draft-IERC7674.sol"; +import {Math} from "../../../utils/math/Math.sol"; +import {SlotDerivation} from "../../../utils/SlotDerivation.sol"; +import {TransientSlot} from "../../../utils/TransientSlot.sol"; + +/** + * @dev Extension of {ERC20} that adds support for temporary allowances following ERC-7674. + * + * WARNING: This is a draft contract. The corresponding ERC is still subject to changes. + * + * _Available since v5.1._ + */ +abstract contract ERC20TemporaryApproval is ERC20, IERC7674 { + using SlotDerivation for bytes32; + using TransientSlot for bytes32; + using TransientSlot for TransientSlot.Uint256Slot; + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20_TEMPORARY_APPROVAL_STORAGE")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant ERC20_TEMPORARY_APPROVAL_STORAGE = + 0xea2d0e77a01400d0111492b1321103eed560d8fe44b9a7c2410407714583c400; + + /** + * @dev {allowance} override that includes the temporary allowance when looking up the current allowance. If + * adding up the persistent and the temporary allowances result in an overflow, type(uint256).max is returned. + */ + function allowance(address owner, address spender) public view virtual override(IERC20, ERC20) returns (uint256) { + (bool success, uint256 amount) = Math.tryAdd( + super.allowance(owner, spender), + _temporaryAllowance(owner, spender) + ); + return success ? amount : type(uint256).max; + } + + /** + * @dev Internal getter for the current temporary allowance that `spender` has over `owner` tokens. + */ + function _temporaryAllowance(address owner, address spender) internal view virtual returns (uint256) { + return _temporaryAllowanceSlot(owner, spender).tload(); + } + + /** + * @dev Alternative to {approve} that sets a `value` amount of tokens as the temporary allowance of `spender` over + * the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Requirements: + * - `spender` cannot be the zero address. + * + * Does NOT emit an {Approval} event. + */ + function temporaryApprove(address spender, uint256 value) public virtual returns (bool) { + _temporaryApprove(_msgSender(), spender, value); + return true; + } + + /** + * @dev Sets `value` as the temporary allowance of `spender` over the `owner`'s tokens. + * + * This internal function is equivalent to `temporaryApprove`, and can be used to e.g. set automatic allowances + * for certain subsystems, etc. + * + * Requirements: + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + * + * Does NOT emit an {Approval} event. + */ + function _temporaryApprove(address owner, address spender, uint256 value) internal virtual { + if (owner == address(0)) { + revert ERC20InvalidApprover(address(0)); + } + if (spender == address(0)) { + revert ERC20InvalidSpender(address(0)); + } + _temporaryAllowanceSlot(owner, spender).tstore(value); + } + + /** + * @dev {_spendAllowance} override that consumes the temporary allowance (if any) before eventually falling back + * to consuming the persistent allowance. + * NOTE: This function skips calling `super._spendAllowance` if the temporary allowance + * is enough to cover the spending. + */ + function _spendAllowance(address owner, address spender, uint256 value) internal virtual override { + // load transient allowance + uint256 currentTemporaryAllowance = _temporaryAllowance(owner, spender); + + // Check and update (if needed) the temporary allowance + set remaining value + if (currentTemporaryAllowance > 0) { + // All value is covered by the infinite allowance. nothing left to spend, we can return early + if (currentTemporaryAllowance == type(uint256).max) { + return; + } + // check how much of the value is covered by the transient allowance + uint256 spendTemporaryAllowance = Math.min(currentTemporaryAllowance, value); + unchecked { + // decrease transient allowance accordingly + _temporaryApprove(owner, spender, currentTemporaryAllowance - spendTemporaryAllowance); + // update value necessary + value -= spendTemporaryAllowance; + } + } + // reduce any remaining value from the persistent allowance + if (value > 0) { + super._spendAllowance(owner, spender, value); + } + } + + function _temporaryAllowanceSlot(address owner, address spender) private pure returns (TransientSlot.Uint256Slot) { + return ERC20_TEMPORARY_APPROVAL_STORAGE.deriveMapping(owner).deriveMapping(spender).asUint256(); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/ERC1363Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/ERC1363Utils.sol new file mode 100644 index 0000000..25577bc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/ERC1363Utils.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/utils/ERC1363Utils.sol) + +pragma solidity ^0.8.20; + +import {IERC1363Receiver} from "../../../interfaces/IERC1363Receiver.sol"; +import {IERC1363Spender} from "../../../interfaces/IERC1363Spender.sol"; + +/** + * @dev Library that provides common ERC-1363 utility functions. + * + * See https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. + */ +library ERC1363Utils { + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC1363InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the token `spender`. Used in approvals. + * @param spender Address that may be allowed to operate on tokens without being their owner. + */ + error ERC1363InvalidSpender(address spender); + + /** + * @dev Performs a call to {IERC1363Receiver-onTransferReceived} on a target address. + * + * Requirements: + * + * - The target has code (i.e. is a contract). + * - The target `to` must implement the {IERC1363Receiver} interface. + * - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer. + */ + function checkOnERC1363TransferReceived( + address operator, + address from, + address to, + uint256 value, + bytes memory data + ) internal { + if (to.code.length == 0) { + revert ERC1363InvalidReceiver(to); + } + + try IERC1363Receiver(to).onTransferReceived(operator, from, value, data) returns (bytes4 retval) { + if (retval != IERC1363Receiver.onTransferReceived.selector) { + revert ERC1363InvalidReceiver(to); + } + } catch (bytes memory reason) { + if (reason.length == 0) { + revert ERC1363InvalidReceiver(to); + } else { + assembly ("memory-safe") { + revert(add(reason, 0x20), mload(reason)) + } + } + } + } + + /** + * @dev Performs a call to {IERC1363Spender-onApprovalReceived} on a target address. + * + * Requirements: + * + * - The target has code (i.e. is a contract). + * - The target `spender` must implement the {IERC1363Spender} interface. + * - The target must return the {IERC1363Spender-onApprovalReceived} selector to accept the approval. + */ + function checkOnERC1363ApprovalReceived( + address operator, + address spender, + uint256 value, + bytes memory data + ) internal { + if (spender.code.length == 0) { + revert ERC1363InvalidSpender(spender); + } + + try IERC1363Spender(spender).onApprovalReceived(operator, value, data) returns (bytes4 retval) { + if (retval != IERC1363Spender.onApprovalReceived.selector) { + revert ERC1363InvalidSpender(spender); + } + } catch (bytes memory reason) { + if (reason.length == 0) { + revert ERC1363InvalidSpender(spender); + } else { + assembly ("memory-safe") { + revert(add(reason, 0x20), mload(reason)) + } + } + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol new file mode 100644 index 0000000..883e8d3 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "../IERC20.sol"; +import {IERC1363} from "../../../interfaces/IERC1363.sol"; + +/** + * @title SafeERC20 + * @dev Wrappers around ERC-20 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 { + /** + * @dev An operation with an ERC-20 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 Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful. + */ + function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) { + return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value))); + } + + /** + * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful. + */ + function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) { + return _callOptionalReturnBool(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. + * + * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" + * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using + * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract + * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. + */ + 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. + * + * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" + * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using + * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract + * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. + */ + 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. + * + * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function + * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being + * set here. + */ + 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 Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no + * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when + * targeting contracts. + * + * Reverts if the returned value is other than `true`. + */ + function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { + if (to.code.length == 0) { + safeTransfer(token, to, value); + } else if (!token.transferAndCall(to, value, data)) { + revert SafeERC20FailedOperation(address(token)); + } + } + + /** + * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target + * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when + * targeting contracts. + * + * Reverts if the returned value is other than `true`. + */ + function transferFromAndCallRelaxed( + IERC1363 token, + address from, + address to, + uint256 value, + bytes memory data + ) internal { + if (to.code.length == 0) { + safeTransferFrom(token, from, to, value); + } else if (!token.transferFromAndCall(from, to, value, data)) { + revert SafeERC20FailedOperation(address(token)); + } + } + + /** + * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no + * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when + * targeting contracts. + * + * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}. + * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall} + * once without retrying, and relies on the returned value to be true. + * + * Reverts if the returned value is other than `true`. + */ + function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { + if (to.code.length == 0) { + forceApprove(token, to, value); + } else if (!token.approveAndCall(to, value, data)) { + 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 {_callOptionalReturnBool} that reverts if call fails to meet the requirements. + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + uint256 returnSize; + uint256 returnValue; + assembly ("memory-safe") { + let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) + // bubble errors + if iszero(success) { + let ptr := mload(0x40) + returndatacopy(ptr, 0, returndatasize()) + revert(ptr, returndatasize()) + } + returnSize := returndatasize() + returnValue := mload(0) + } + + if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) { + 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 silently catches all reverts and returns a bool instead. + */ + function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { + bool success; + uint256 returnSize; + uint256 returnValue; + assembly ("memory-safe") { + success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) + returnSize := returndatasize() + returnValue := mload(0) + } + return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/README.adoc new file mode 100644 index 0000000..17d116c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/README.adoc @@ -0,0 +1,27 @@ += ERC-6909 + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc6909 + +This set of interfaces and contracts are all related to the https://eips.ethereum.org/EIPS/eip-6909[ERC-6909 Minimal Multi-Token Interface]. + +The ERC consists of four interfaces which fulfill different roles--the interfaces are as follows: + +. {IERC6909}: Base interface for a vanilla ERC6909 token. +. {IERC6909ContentURI}: Extends the base interface and adds content URI (contract and token level) functionality. +. {IERC6909Metadata}: Extends the base interface and adds metadata functionality, which exposes a name, symbol, and decimals for each token id. +. {IERC6909TokenSupply}: Extends the base interface and adds total supply functionality for each token id. + +Implementations are provided for each of the 4 interfaces defined in the ERC. + +== Core + +{{ERC6909}} + +== Extensions + +{{ERC6909ContentURI}} + +{{ERC6909Metadata}} + +{{ERC6909TokenSupply}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/draft-ERC6909.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/draft-ERC6909.sol new file mode 100644 index 0000000..6f5cdd6 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/draft-ERC6909.sol @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC6909/draft-ERC6909.sol) + +pragma solidity ^0.8.20; + +import {IERC6909} from "../../interfaces/draft-IERC6909.sol"; +import {Context} from "../../utils/Context.sol"; +import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of ERC-6909. + * See https://eips.ethereum.org/EIPS/eip-6909 + */ +contract ERC6909 is Context, ERC165, IERC6909 { + mapping(address owner => mapping(uint256 id => uint256)) private _balances; + + mapping(address owner => mapping(address operator => bool)) private _operatorApprovals; + + mapping(address owner => mapping(address spender => mapping(uint256 id => uint256))) private _allowances; + + error ERC6909InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 id); + error ERC6909InsufficientAllowance(address spender, uint256 allowance, uint256 needed, uint256 id); + error ERC6909InvalidApprover(address approver); + error ERC6909InvalidReceiver(address receiver); + error ERC6909InvalidSender(address sender); + error ERC6909InvalidSpender(address spender); + + /// @inheritdoc IERC165 + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IERC6909).interfaceId || super.supportsInterface(interfaceId); + } + + /// @inheritdoc IERC6909 + function balanceOf(address owner, uint256 id) public view virtual override returns (uint256) { + return _balances[owner][id]; + } + + /// @inheritdoc IERC6909 + function allowance(address owner, address spender, uint256 id) public view virtual override returns (uint256) { + return _allowances[owner][spender][id]; + } + + /// @inheritdoc IERC6909 + function isOperator(address owner, address spender) public view virtual override returns (bool) { + return _operatorApprovals[owner][spender]; + } + + /// @inheritdoc IERC6909 + function approve(address spender, uint256 id, uint256 amount) public virtual override returns (bool) { + _approve(_msgSender(), spender, id, amount); + return true; + } + + /// @inheritdoc IERC6909 + function setOperator(address spender, bool approved) public virtual override returns (bool) { + _setOperator(_msgSender(), spender, approved); + return true; + } + + /// @inheritdoc IERC6909 + function transfer(address receiver, uint256 id, uint256 amount) public virtual override returns (bool) { + _transfer(_msgSender(), receiver, id, amount); + return true; + } + + /// @inheritdoc IERC6909 + function transferFrom( + address sender, + address receiver, + uint256 id, + uint256 amount + ) public virtual override returns (bool) { + address caller = _msgSender(); + if (sender != caller && !isOperator(sender, caller)) { + _spendAllowance(sender, caller, id, amount); + } + _transfer(sender, receiver, id, amount); + return true; + } + + /** + * @dev Creates `amount` of token `id` 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 to, uint256 id, uint256 amount) internal { + if (to == address(0)) { + revert ERC6909InvalidReceiver(address(0)); + } + _update(address(0), to, id, amount); + } + + /** + * @dev Moves `amount` of token `id` from `from` to `to` without checking for approvals. This function verifies + * that neither the sender nor the receiver are address(0), which means it cannot mint or burn tokens. + * Relies on the `_update` mechanism. + * + * Emits a {Transfer} event. + * + * NOTE: This function is not virtual, {_update} should be overridden instead. + */ + function _transfer(address from, address to, uint256 id, uint256 amount) internal { + if (from == address(0)) { + revert ERC6909InvalidSender(address(0)); + } + if (to == address(0)) { + revert ERC6909InvalidReceiver(address(0)); + } + _update(from, to, id, amount); + } + + /** + * @dev Destroys a `amount` of token `id` from `account`. + * 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 from, uint256 id, uint256 amount) internal { + if (from == address(0)) { + revert ERC6909InvalidSender(address(0)); + } + _update(from, address(0), id, amount); + } + + /** + * @dev Transfers `amount` of token `id` 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 id, uint256 amount) internal virtual { + address caller = _msgSender(); + + if (from != address(0)) { + uint256 fromBalance = _balances[from][id]; + if (fromBalance < amount) { + revert ERC6909InsufficientBalance(from, fromBalance, amount, id); + } + unchecked { + // Overflow not possible: amount <= fromBalance. + _balances[from][id] = fromBalance - amount; + } + } + if (to != address(0)) { + _balances[to][id] += amount; + } + + emit Transfer(caller, from, to, id, amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner`'s `id` 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 id, uint256 amount) internal virtual { + if (owner == address(0)) { + revert ERC6909InvalidApprover(address(0)); + } + if (spender == address(0)) { + revert ERC6909InvalidSpender(address(0)); + } + _allowances[owner][spender][id] = amount; + emit Approval(owner, spender, id, amount); + } + + /** + * @dev Approve `spender` to operate on all of `owner`'s tokens + * + * This internal function is equivalent to `setOperator`, and can be used to e.g. set automatic allowances for + * certain subsystems, etc. + * + * Emits an {OperatorSet} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _setOperator(address owner, address spender, bool approved) internal virtual { + if (owner == address(0)) { + revert ERC6909InvalidApprover(address(0)); + } + if (spender == address(0)) { + revert ERC6909InvalidSpender(address(0)); + } + _operatorApprovals[owner][spender] = approved; + emit OperatorSet(owner, spender, approved); + } + + /** + * @dev Updates `owner`'s allowance for `spender` based on spent `amount`. + * + * 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 id, uint256 amount) internal virtual { + uint256 currentAllowance = allowance(owner, spender, id); + if (currentAllowance < type(uint256).max) { + if (currentAllowance < amount) { + revert ERC6909InsufficientAllowance(spender, currentAllowance, amount, id); + } + unchecked { + _allowances[owner][spender][id] = currentAllowance - amount; + } + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909ContentURI.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909ContentURI.sol new file mode 100644 index 0000000..9d082c0 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909ContentURI.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC6909/extensions/draft-ERC6909ContentURI.sol) + +pragma solidity ^0.8.20; + +import {ERC6909} from "../draft-ERC6909.sol"; +import {IERC6909ContentURI} from "../../../interfaces/draft-IERC6909.sol"; + +/** + * @dev Implementation of the Content URI extension defined in ERC6909. + */ +contract ERC6909ContentURI is ERC6909, IERC6909ContentURI { + string private _contractURI; + mapping(uint256 id => string) private _tokenURIs; + + /// @dev Event emitted when the contract URI is changed. See https://eips.ethereum.org/EIPS/eip-7572[ERC-7572] for details. + event ContractURIUpdated(); + + /// @dev See {IERC1155-URI} + event URI(string value, uint256 indexed id); + + /// @inheritdoc IERC6909ContentURI + function contractURI() public view virtual override returns (string memory) { + return _contractURI; + } + + /// @inheritdoc IERC6909ContentURI + function tokenURI(uint256 id) public view virtual override returns (string memory) { + return _tokenURIs[id]; + } + + /** + * @dev Sets the {contractURI} for the contract. + * + * Emits a {ContractURIUpdated} event. + */ + function _setContractURI(string memory newContractURI) internal virtual { + _contractURI = newContractURI; + + emit ContractURIUpdated(); + } + + /** + * @dev Sets the {tokenURI} for a given token of type `id`. + * + * Emits a {URI} event. + */ + function _setTokenURI(uint256 id, string memory newTokenURI) internal virtual { + _tokenURIs[id] = newTokenURI; + + emit URI(newTokenURI, id); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909Metadata.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909Metadata.sol new file mode 100644 index 0000000..31efebe --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909Metadata.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC6909/extensions/draft-ERC6909Metadata.sol) + +pragma solidity ^0.8.20; + +import {ERC6909} from "../draft-ERC6909.sol"; +import {IERC6909Metadata} from "../../../interfaces/draft-IERC6909.sol"; + +/** + * @dev Implementation of the Metadata extension defined in ERC6909. Exposes the name, symbol, and decimals of each token id. + */ +contract ERC6909Metadata is ERC6909, IERC6909Metadata { + struct TokenMetadata { + string name; + string symbol; + uint8 decimals; + } + + mapping(uint256 id => TokenMetadata) private _tokenMetadata; + + /// @dev The name of the token of type `id` was updated to `newName`. + event ERC6909NameUpdated(uint256 indexed id, string newName); + + /// @dev The symbol for the token of type `id` was updated to `newSymbol`. + event ERC6909SymbolUpdated(uint256 indexed id, string newSymbol); + + /// @dev The decimals value for token of type `id` was updated to `newDecimals`. + event ERC6909DecimalsUpdated(uint256 indexed id, uint8 newDecimals); + + /// @inheritdoc IERC6909Metadata + function name(uint256 id) public view virtual override returns (string memory) { + return _tokenMetadata[id].name; + } + + /// @inheritdoc IERC6909Metadata + function symbol(uint256 id) public view virtual override returns (string memory) { + return _tokenMetadata[id].symbol; + } + + /// @inheritdoc IERC6909Metadata + function decimals(uint256 id) public view virtual override returns (uint8) { + return _tokenMetadata[id].decimals; + } + + /** + * @dev Sets the `name` for a given token of type `id`. + * + * Emits an {ERC6909NameUpdated} event. + */ + function _setName(uint256 id, string memory newName) internal virtual { + _tokenMetadata[id].name = newName; + + emit ERC6909NameUpdated(id, newName); + } + + /** + * @dev Sets the `symbol` for a given token of type `id`. + * + * Emits an {ERC6909SymbolUpdated} event. + */ + function _setSymbol(uint256 id, string memory newSymbol) internal virtual { + _tokenMetadata[id].symbol = newSymbol; + + emit ERC6909SymbolUpdated(id, newSymbol); + } + + /** + * @dev Sets the `decimals` for a given token of type `id`. + * + * Emits an {ERC6909DecimalsUpdated} event. + */ + function _setDecimals(uint256 id, uint8 newDecimals) internal virtual { + _tokenMetadata[id].decimals = newDecimals; + + emit ERC6909DecimalsUpdated(id, newDecimals); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909TokenSupply.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909TokenSupply.sol new file mode 100644 index 0000000..0fd4c22 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909TokenSupply.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC6909/extensions/draft-ERC6909TokenSupply.sol) + +pragma solidity ^0.8.20; + +import {ERC6909} from "../draft-ERC6909.sol"; +import {IERC6909TokenSupply} from "../../../interfaces/draft-IERC6909.sol"; + +/** + * @dev Implementation of the Token Supply extension defined in ERC6909. + * Tracks the total supply of each token id individually. + */ +contract ERC6909TokenSupply is ERC6909, IERC6909TokenSupply { + mapping(uint256 id => uint256) private _totalSupplies; + + /// @inheritdoc IERC6909TokenSupply + function totalSupply(uint256 id) public view virtual override returns (uint256) { + return _totalSupplies[id]; + } + + /// @dev Override the `_update` function to update the total supply of each token id as necessary. + function _update(address from, address to, uint256 id, uint256 amount) internal virtual override { + super._update(from, to, id, amount); + + if (from == address(0)) { + _totalSupplies[id] += amount; + } + if (to == address(0)) { + unchecked { + // amount <= _balances[from][id] <= _totalSupplies[id] + _totalSupplies[id] -= amount; + } + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol new file mode 100644 index 0000000..2867cd1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/ERC721.sol) + +pragma solidity ^0.8.20; + +import {IERC721} from "./IERC721.sol"; +import {IERC721Metadata} from "./extensions/IERC721Metadata.sol"; +import {ERC721Utils} from "./utils/ERC721Utils.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[ERC-721] 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_; + } + + /// @inheritdoc IERC165 + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || + super.supportsInterface(interfaceId); + } + + /// @inheritdoc IERC721 + function balanceOf(address owner) public view virtual returns (uint256) { + if (owner == address(0)) { + revert ERC721InvalidOwner(address(0)); + } + return _balances[owner]; + } + + /// @inheritdoc IERC721 + function ownerOf(uint256 tokenId) public view virtual returns (address) { + return _requireOwned(tokenId); + } + + /// @inheritdoc IERC721Metadata + function name() public view virtual returns (string memory) { + return _name; + } + + /// @inheritdoc IERC721Metadata + function symbol() public view virtual returns (string memory) { + return _symbol; + } + + /// @inheritdoc IERC721Metadata + 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 ""; + } + + /// @inheritdoc IERC721 + function approve(address to, uint256 tokenId) public virtual { + _approve(to, tokenId, _msgSender()); + } + + /// @inheritdoc IERC721 + function getApproved(uint256 tokenId) public view virtual returns (address) { + _requireOwned(tokenId); + + return _getApproved(tokenId); + } + + /// @inheritdoc IERC721 + function setApprovalForAll(address operator, bool approved) public virtual { + _setApprovalForAll(_msgSender(), operator, approved); + } + + /// @inheritdoc IERC721 + function isApprovedForAll(address owner, address operator) public view virtual returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /// @inheritdoc IERC721 + 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); + } + } + + /// @inheritdoc IERC721 + function safeTransferFrom(address from, address to, uint256 tokenId) public { + safeTransferFrom(from, to, tokenId, ""); + } + + /// @inheritdoc IERC721 + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual { + transferFrom(from, to, tokenId); + ERC721Utils.checkOnERC721Received(_msgSender(), 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 ERC-721 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 `owner` for `tokenId`. + * - `spender` does not have approval to manage all of `owner`'s assets. + * + * 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); + ERC721Utils.checkOnERC721Received(_msgSender(), 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 ERC-721 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); + ERC721Utils.checkOnERC721Received(_msgSender(), 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; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol new file mode 100644 index 0000000..7498203 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/IERC721.sol) + +pragma solidity >=0.6.2; + +import {IERC165} from "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC-721 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 ERC-721 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 ERC-721 + * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol new file mode 100644 index 0000000..6110f0c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/IERC721Receiver.sol) + +pragma solidity >=0.5.0; + +/** + * @title ERC-721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC-721 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc new file mode 100644 index 0000000..22a3062 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc @@ -0,0 +1,69 @@ += 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 is all related to the https://eips.ethereum.org/EIPS/eip-721[ERC-721 Non-Fungible Token Standard]. + +TIP: For a walk through on how to create an ERC-721 token read our xref:ROOT:erc721.adoc[ERC-721 guide]. + +The ERC 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[ERC-2309] for minting batches of tokens during construction, in accordance with ERC-721. +* {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 ERC-2981. +* {ERC721Pausable}: A primitive to pause contract operation. +* {ERC721Burnable}: A way for token holders to burn their own tokens. +* {ERC721Wrapper}: Wrapper to create an ERC-721 backed by another ERC-721, 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 ERC-721 (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}} + +{{ERC721Utils}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol new file mode 100644 index 0000000..c6d2245 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/extensions/ERC721Burnable.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {Context} from "../../../utils/Context.sol"; + +/** + * @title ERC-721 Burnable Token + * @dev ERC-721 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol new file mode 100644 index 0000000..0f32673 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.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 ERC-2309 "Consecutive Transfer Extension" as defined in + * https://eips.ethereum.org/EIPS/eip-2309[ERC-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 ERC-721 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 ERC-721 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol new file mode 100644 index 0000000..1231ffc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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 ERC 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(); + + /// @inheritdoc IERC165 + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { + return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); + } + + /// @inheritdoc IERC721Enumerable + function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) { + if (index >= balanceOf(owner)) { + revert ERC721OutOfBoundsIndex(owner, index); + } + return _ownedTokens[owner][index]; + } + + /// @inheritdoc IERC721Enumerable + function totalSupply() public view virtual returns (uint256) { + return _allTokens.length; + } + + /// @inheritdoc IERC721Enumerable + function tokenByIndex(uint256 index) public view virtual returns (uint256) { + if (index >= totalSupply()) { + revert ERC721OutOfBoundsIndex(address(0), index); + } + return _allTokens[index]; + } + + /// @inheritdoc ERC721 + 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]; + + mapping(uint256 index => uint256) storage _ownedTokensByOwner = _ownedTokens[from]; + + // When the token to delete is the last token, the swap operation is unnecessary + if (tokenIndex != lastTokenIndex) { + uint256 lastTokenId = _ownedTokensByOwner[lastTokenIndex]; + + _ownedTokensByOwner[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 _ownedTokensByOwner[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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol new file mode 100644 index 0000000..9a75623 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/extensions/ERC721Pausable.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {Pausable} from "../../../utils/Pausable.sol"; + +/** + * @dev ERC-721 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol new file mode 100644 index 0000000..cb51fdb --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/extensions/ERC721Royalty.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {IERC165} from "../../../utils/introspection/ERC165.sol"; +import {ERC2981} from "../../common/ERC2981.sol"; + +/** + * @dev Extension of ERC-721 with the ERC-2981 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 ERC. 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 { + /// @inheritdoc IERC165 + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC2981) returns (bool) { + return super.supportsInterface(interfaceId); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol new file mode 100644 index 0000000..99630df --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/extensions/ERC721URIStorage.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {IERC721Metadata} from "./IERC721Metadata.sol"; +import {Strings} from "../../../utils/Strings.sol"; +import {IERC4906} from "../../../interfaces/IERC4906.sol"; +import {IERC165} from "../../../interfaces/IERC165.sol"; + +/** + * @dev ERC-721 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; + + /// @inheritdoc IERC165 + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, IERC165) returns (bool) { + return interfaceId == ERC4906_INTERFACE_ID || super.supportsInterface(interfaceId); + } + + /// @inheritdoc IERC721Metadata + 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 {IERC4906-MetadataUpdate}. + */ + function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { + _tokenURIs[tokenId] = _tokenURI; + emit MetadataUpdate(tokenId); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol new file mode 100644 index 0000000..f71195c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.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 ERC-721 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol new file mode 100644 index 0000000..111136b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.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 ERC-721 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" ERC-721 into a governance token. + */ +abstract contract ERC721Wrapper is ERC721, IERC721Receiver { + IERC721 private immutable _underlying; + + /** + * @dev The received ERC-721 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 ERC-721 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol new file mode 100644 index 0000000..1fe5885 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/extensions/IERC721Enumerable.sol) + +pragma solidity >=0.6.2; + +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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol new file mode 100644 index 0000000..b4da16d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/extensions/IERC721Metadata.sol) + +pragma solidity >=0.6.2; + +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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol new file mode 100644 index 0000000..6bb23ac --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Utils.sol new file mode 100644 index 0000000..575ee8b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Utils.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/utils/ERC721Utils.sol) + +pragma solidity ^0.8.20; + +import {IERC721Receiver} from "../IERC721Receiver.sol"; +import {IERC721Errors} from "../../../interfaces/draft-IERC6093.sol"; + +/** + * @dev Library that provide common ERC-721 utility functions. + * + * See https://eips.ethereum.org/EIPS/eip-721[ERC-721]. + * + * _Available since v5.1._ + */ +library ERC721Utils { + /** + * @dev Performs an acceptance check for the provided `operator` by calling {IERC721Receiver-onERC721Received} + * on the `to` address. The `operator` is generally the address that initiated the token transfer (i.e. `msg.sender`). + * + * The acceptance call is not executed and treated as a no-op if the target address doesn't contain code (i.e. an EOA). + * Otherwise, the recipient must implement {IERC721Receiver-onERC721Received} and return the acceptance magic value to accept + * the transfer. + */ + function checkOnERC721Received( + address operator, + address from, + address to, + uint256 tokenId, + bytes memory data + ) internal { + if (to.code.length > 0) { + try IERC721Receiver(to).onERC721Received(operator, from, tokenId, data) returns (bytes4 retval) { + if (retval != IERC721Receiver.onERC721Received.selector) { + // Token rejected + revert IERC721Errors.ERC721InvalidReceiver(to); + } + } catch (bytes memory reason) { + if (reason.length == 0) { + // non-IERC721Receiver implementer + revert IERC721Errors.ERC721InvalidReceiver(to); + } else { + assembly ("memory-safe") { + revert(add(reason, 0x20), mload(reason)) + } + } + } + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol new file mode 100644 index 0000000..5d75e3a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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 ERC. 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 a 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); + + /// @inheritdoc IERC165 + 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 receiver, uint256 amount) { + RoyaltyInfo storage _royaltyInfo = _tokenRoyaltyInfo[tokenId]; + address royaltyReceiver = _royaltyInfo.receiver; + uint96 royaltyFraction = _royaltyInfo.royaltyFraction; + + if (royaltyReceiver == address(0)) { + royaltyReceiver = _defaultRoyaltyInfo.receiver; + royaltyFraction = _defaultRoyaltyInfo.royaltyFraction; + } + + uint256 royaltyAmount = (salePrice * royaltyFraction) / _feeDenominator(); + + return (royaltyReceiver, 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/README.adoc new file mode 100644 index 0000000..a70d90d --- /dev/null +++ b/typescript/packages/account-modules/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 ERC-721 and ERC-1155. +** For ERC-721 consider {ERC721Royalty} which clears the royalty information from storage on burn. + +== Contracts + +{{ERC2981}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Address.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Address.sol new file mode 100644 index 0000000..cb90227 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Address.sol @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/Address.sol) + +pragma solidity ^0.8.20; + +import {Errors} from "./Errors.sol"; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev There's no code at `target` (it is not a contract). + */ + error AddressEmptyCode(address target); + + /** + * @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 Errors.InsufficientBalance(address(this).balance, amount); + } + + (bool success, bytes memory returndata) = recipient.call{value: amount}(""); + if (!success) { + _revert(returndata); + } + } + + /** + * @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 + * {Errors.FailedCall} 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 Errors.InsufficientBalance(address(this).balance, value); + } + (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 {Errors.FailedCall}) 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 {Errors.FailedCall} 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 {Errors.FailedCall}. + */ + 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 + assembly ("memory-safe") { + revert(add(returndata, 0x20), mload(returndata)) + } + } else { + revert Errors.FailedCall(); + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Arrays.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Arrays.sol new file mode 100644 index 0000000..511354a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Arrays.sol @@ -0,0 +1,552 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/Arrays.sol) +// This file was procedurally generated from scripts/generate/templates/Arrays.js. + +pragma solidity ^0.8.20; + +import {Comparators} from "./Comparators.sol"; +import {SlotDerivation} from "./SlotDerivation.sol"; +import {StorageSlot} from "./StorageSlot.sol"; +import {Math} from "./math/Math.sol"; + +/** + * @dev Collection of functions related to array types. + */ +library Arrays { + using SlotDerivation for bytes32; + using StorageSlot for bytes32; + + /** + * @dev Sort an array of uint256 (in memory) following the provided comparator function. + * + * This function does the sorting "in place", meaning that it overrides the input. The object is returned for + * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array. + * + * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the + * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful + * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may + * consume more gas than is available in a block, leading to potential DoS. + * + * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way. + */ + function sort( + uint256[] memory array, + function(uint256, uint256) pure returns (bool) comp + ) internal pure returns (uint256[] memory) { + _quickSort(_begin(array), _end(array), comp); + return array; + } + + /** + * @dev Variant of {sort} that sorts an array of uint256 in increasing order. + */ + function sort(uint256[] memory array) internal pure returns (uint256[] memory) { + sort(array, Comparators.lt); + return array; + } + + /** + * @dev Sort an array of address (in memory) following the provided comparator function. + * + * This function does the sorting "in place", meaning that it overrides the input. The object is returned for + * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array. + * + * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the + * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful + * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may + * consume more gas than is available in a block, leading to potential DoS. + * + * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way. + */ + function sort( + address[] memory array, + function(address, address) pure returns (bool) comp + ) internal pure returns (address[] memory) { + sort(_castToUint256Array(array), _castToUint256Comp(comp)); + return array; + } + + /** + * @dev Variant of {sort} that sorts an array of address in increasing order. + */ + function sort(address[] memory array) internal pure returns (address[] memory) { + sort(_castToUint256Array(array), Comparators.lt); + return array; + } + + /** + * @dev Sort an array of bytes32 (in memory) following the provided comparator function. + * + * This function does the sorting "in place", meaning that it overrides the input. The object is returned for + * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array. + * + * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the + * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful + * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may + * consume more gas than is available in a block, leading to potential DoS. + * + * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way. + */ + function sort( + bytes32[] memory array, + function(bytes32, bytes32) pure returns (bool) comp + ) internal pure returns (bytes32[] memory) { + sort(_castToUint256Array(array), _castToUint256Comp(comp)); + return array; + } + + /** + * @dev Variant of {sort} that sorts an array of bytes32 in increasing order. + */ + function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) { + sort(_castToUint256Array(array), Comparators.lt); + return array; + } + + /** + * @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops + * at end (exclusive). Sorting follows the `comp` comparator. + * + * Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls. + * + * IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should + * be used only if the limits are within a memory array. + */ + function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure { + unchecked { + if (end - begin < 0x40) return; + + // Use first element as pivot + uint256 pivot = _mload(begin); + // Position where the pivot should be at the end of the loop + uint256 pos = begin; + + for (uint256 it = begin + 0x20; it < end; it += 0x20) { + if (comp(_mload(it), pivot)) { + // If the value stored at the iterator's position comes before the pivot, we increment the + // position of the pivot and move the value there. + pos += 0x20; + _swap(pos, it); + } + } + + _swap(begin, pos); // Swap pivot into place + _quickSort(begin, pos, comp); // Sort the left side of the pivot + _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot + } + } + + /** + * @dev Pointer to the memory location of the first element of `array`. + */ + function _begin(uint256[] memory array) private pure returns (uint256 ptr) { + assembly ("memory-safe") { + ptr := add(array, 0x20) + } + } + + /** + * @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word + * that comes just after the last element of the array. + */ + function _end(uint256[] memory array) private pure returns (uint256 ptr) { + unchecked { + return _begin(array) + array.length * 0x20; + } + } + + /** + * @dev Load memory word (as a uint256) at location `ptr`. + */ + function _mload(uint256 ptr) private pure returns (uint256 value) { + assembly { + value := mload(ptr) + } + } + + /** + * @dev Swaps the elements memory location `ptr1` and `ptr2`. + */ + function _swap(uint256 ptr1, uint256 ptr2) private pure { + assembly { + let value1 := mload(ptr1) + let value2 := mload(ptr2) + mstore(ptr1, value2) + mstore(ptr2, value1) + } + } + + /// @dev Helper: low level cast address memory array to uint256 memory array + function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) { + assembly { + output := input + } + } + + /// @dev Helper: low level cast bytes32 memory array to uint256 memory array + function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) { + assembly { + output := input + } + } + + /// @dev Helper: low level cast address comp function to uint256 comp function + function _castToUint256Comp( + function(address, address) pure returns (bool) input + ) private pure returns (function(uint256, uint256) pure returns (bool) output) { + assembly { + output := input + } + } + + /// @dev Helper: low level cast bytes32 comp function to uint256 comp function + function _castToUint256Comp( + function(bytes32, bytes32) pure returns (bool) input + ) private pure returns (function(uint256, uint256) pure returns (bool) output) { + assembly { + output := input + } + } + + /** + * @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). + * + * NOTE: The `array` is expected to be sorted in ascending order, and to + * contain no repeated elements. + * + * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks + * support for repeated elements in the array. The {lowerBound} function should + * be used instead. + */ + 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 Searches an `array` sorted in ascending order and returns the first + * index that contains a value greater or equal than `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). + * + * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound]. + */ + function lowerBound(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) { + // this cannot overflow because mid < high + unchecked { + low = mid + 1; + } + } else { + high = mid; + } + } + + return low; + } + + /** + * @dev Searches an `array` sorted in ascending order and returns the first + * index that contains a value strictly greater than `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). + * + * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound]. + */ + function upperBound(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 { + // this cannot overflow because mid < high + unchecked { + low = mid + 1; + } + } + } + + return low; + } + + /** + * @dev Same as {lowerBound}, but with an array in memory. + */ + function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure 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 (unsafeMemoryAccess(array, mid) < element) { + // this cannot overflow because mid < high + unchecked { + low = mid + 1; + } + } else { + high = mid; + } + } + + return low; + } + + /** + * @dev Same as {upperBound}, but with an array in memory. + */ + function upperBoundMemory(uint256[] memory array, uint256 element) internal pure 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 (unsafeMemoryAccess(array, mid) > element) { + high = mid; + } else { + // this cannot overflow because mid < high + unchecked { + low = mid + 1; + } + } + } + + 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; + assembly ("memory-safe") { + slot := arr.slot + } + return slot.deriveArray().offset(pos).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; + assembly ("memory-safe") { + slot := arr.slot + } + return slot.deriveArray().offset(pos).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; + assembly ("memory-safe") { + slot := arr.slot + } + return slot.deriveArray().offset(pos).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 unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) { + bytes32 slot; + assembly ("memory-safe") { + slot := arr.slot + } + return slot.deriveArray().offset(pos).getBytesSlot(); + } + + /** + * @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(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) { + bytes32 slot; + assembly ("memory-safe") { + slot := arr.slot + } + return slot.deriveArray().offset(pos).getStringSlot(); + } + + /** + * @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))) + } + } + + /** + * @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(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 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(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(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory 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(string[] memory arr, uint256 pos) internal pure returns (string memory res) { + assembly { + res := mload(add(add(arr, 0x20), mul(pos, 0x20))) + } + } + + /** + * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. + * + * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. + */ + function unsafeSetLength(address[] storage array, uint256 len) internal { + assembly ("memory-safe") { + sstore(array.slot, len) + } + } + + /** + * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. + * + * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. + */ + function unsafeSetLength(bytes32[] storage array, uint256 len) internal { + assembly ("memory-safe") { + sstore(array.slot, len) + } + } + + /** + * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. + * + * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. + */ + function unsafeSetLength(uint256[] storage array, uint256 len) internal { + assembly ("memory-safe") { + sstore(array.slot, len) + } + } + + /** + * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. + * + * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. + */ + function unsafeSetLength(bytes[] storage array, uint256 len) internal { + assembly ("memory-safe") { + sstore(array.slot, len) + } + } + + /** + * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. + * + * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. + */ + function unsafeSetLength(string[] storage array, uint256 len) internal { + assembly ("memory-safe") { + sstore(array.slot, len) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Base64.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Base64.sol new file mode 100644 index 0000000..d9b09ec --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Base64.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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 + * See sections 4 and 5 of https://datatracker.ietf.org/doc/html/rfc4648 + */ + string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + string internal constant _TABLE_URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + + /** + * @dev Converts a `bytes` to its Bytes64 `string` representation. + */ + function encode(bytes memory data) internal pure returns (string memory) { + return _encode(data, _TABLE, true); + } + + /** + * @dev Converts a `bytes` to its Bytes64Url `string` representation. + * Output is not padded with `=` as specified in https://www.rfc-editor.org/rfc/rfc4648[rfc4648]. + */ + function encodeURL(bytes memory data) internal pure returns (string memory) { + return _encode(data, _TABLE_URL, false); + } + + /** + * @dev Internal table-agnostic conversion + */ + function _encode(bytes memory data, string memory table, bool withPadding) private 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 ""; + + // If padding is enabled, the final length should be `bytes` data length divided by 3 rounded up and then + // multiplied by 4 so that it leaves room for padding the last chunk + // - `data.length + 2` -> Prepare for division rounding up + // - `/ 3` -> Number of 3-bytes chunks (rounded up) + // - `4 *` -> 4 characters for each chunk + // This is equivalent to: 4 * Math.ceil(data.length / 3) + // + // If padding is disabled, the final length should be `bytes` data length multiplied by 4/3 rounded up as + // opposed to when padding is required to fill the last chunk. + // - `4 * data.length` -> 4 characters for each chunk + // - ` + 2` -> Prepare for division rounding up + // - `/ 3` -> Number of 3-bytes chunks (rounded up) + // This is equivalent to: Math.ceil((4 * data.length) / 3) + uint256 resultLength = withPadding ? 4 * ((data.length + 2) / 3) : (4 * data.length + 2) / 3; + + string memory result = new string(resultLength); + + assembly ("memory-safe") { + // Prepare the lookup table (skip the first "length" byte) + let tablePtr := add(table, 1) + + // Prepare result pointer, jump over length + let resultPtr := add(result, 0x20) + let dataPtr := data + let endPtr := add(data, mload(data)) + + // In some cases, the last iteration will read bytes after the end of the data. We cache the value, and + // set it to zero to make sure no dirty bytes are read in that section. + let afterPtr := add(endPtr, 0x20) + let afterCache := mload(afterPtr) + mstore(afterPtr, 0x00) + + // Run over the input, 3 bytes at a time + for {} lt(dataPtr, endPtr) {} { + // Advance 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // To write each character, shift the 3 byte (24 bits) chunk + // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) + // and apply logical AND with 0x3F to bitmask the least significant 6 bits. + // Use this as an index into the lookup table, mload an entire word + // so the desired character is in the least significant byte, and + // mstore8 this least significant byte into the result and continue. + + 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 + } + + // Reset the value that was cached + mstore(afterPtr, afterCache) + + if withPadding { + // 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Blockhash.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Blockhash.sol new file mode 100644 index 0000000..d420b8e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Blockhash.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/Blockhash.sol) +pragma solidity ^0.8.20; + +/** + * @dev Library for accessing historical block hashes beyond the standard 256 block limit. + * Uses EIP-2935's history storage contract which maintains a ring buffer of the last + * 8191 block hashes in state. + * + * For blocks within the last 256 blocks, it uses the native `BLOCKHASH` opcode. + * For blocks between 257 and 8191 blocks ago, it queries the EIP-2935 history storage. + * For blocks older than 8191 or future blocks, it returns zero, matching the `BLOCKHASH` behavior. + * + * NOTE: After EIP-2935 activation, it takes 8191 blocks to completely fill the history. + * Before that, only block hashes since the fork block will be available. + */ +library Blockhash { + /// @dev Address of the EIP-2935 history storage contract. + address internal constant HISTORY_STORAGE_ADDRESS = 0x0000F90827F1C53a10cb7A02335B175320002935; + + /** + * @dev Retrieves the block hash for any historical block within the supported range. + * + * NOTE: The function gracefully handles future blocks and blocks beyond the history window + * by returning zero, consistent with the EVM's native `BLOCKHASH` behavior. + */ + function blockHash(uint256 blockNumber) internal view returns (bytes32) { + uint256 current = block.number; + uint256 distance; + + unchecked { + // Can only wrap around to `current + 1` given `block.number - (2**256 - 1) = block.number + 1` + distance = current - blockNumber; + } + + return distance < 257 ? blockhash(blockNumber) : _historyStorageCall(blockNumber); + } + + /// @dev Internal function to query the EIP-2935 history storage contract. + function _historyStorageCall(uint256 blockNumber) private view returns (bytes32 hash) { + assembly ("memory-safe") { + // Store the blockNumber in scratch space + mstore(0x00, blockNumber) + mstore(0x20, 0) + + // call history storage address + pop(staticcall(gas(), HISTORY_STORAGE_ADDRESS, 0x00, 0x20, 0x20, 0x20)) + + // load result + hash := mload(0x20) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Bytes.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Bytes.sol new file mode 100644 index 0000000..15084ec --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Bytes.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/Bytes.sol) + +pragma solidity ^0.8.24; + +import {Math} from "./math/Math.sol"; + +/** + * @dev Bytes operations. + */ +library Bytes { + /** + * @dev Forward search for `s` in `buffer` + * * If `s` is present in the buffer, returns the index of the first instance + * * If `s` is not present in the buffer, returns type(uint256).max + * + * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf[Javascript's `Array.indexOf`] + */ + function indexOf(bytes memory buffer, bytes1 s) internal pure returns (uint256) { + return indexOf(buffer, s, 0); + } + + /** + * @dev Forward search for `s` in `buffer` starting at position `pos` + * * If `s` is present in the buffer (at or after `pos`), returns the index of the next instance + * * If `s` is not present in the buffer (at or after `pos`), returns type(uint256).max + * + * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf[Javascript's `Array.indexOf`] + */ + function indexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) { + uint256 length = buffer.length; + for (uint256 i = pos; i < length; ++i) { + if (bytes1(_unsafeReadBytesOffset(buffer, i)) == s) { + return i; + } + } + return type(uint256).max; + } + + /** + * @dev Backward search for `s` in `buffer` + * * If `s` is present in the buffer, returns the index of the last instance + * * If `s` is not present in the buffer, returns type(uint256).max + * + * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf[Javascript's `Array.lastIndexOf`] + */ + function lastIndexOf(bytes memory buffer, bytes1 s) internal pure returns (uint256) { + return lastIndexOf(buffer, s, type(uint256).max); + } + + /** + * @dev Backward search for `s` in `buffer` starting at position `pos` + * * If `s` is present in the buffer (at or before `pos`), returns the index of the previous instance + * * If `s` is not present in the buffer (at or before `pos`), returns type(uint256).max + * + * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf[Javascript's `Array.lastIndexOf`] + */ + function lastIndexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) { + unchecked { + uint256 length = buffer.length; + for (uint256 i = Math.min(Math.saturatingAdd(pos, 1), length); i > 0; --i) { + if (bytes1(_unsafeReadBytesOffset(buffer, i - 1)) == s) { + return i - 1; + } + } + return type(uint256).max; + } + } + + /** + * @dev Copies the content of `buffer`, from `start` (included) to the end of `buffer` into a new bytes object in + * memory. + * + * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`] + */ + function slice(bytes memory buffer, uint256 start) internal pure returns (bytes memory) { + return slice(buffer, start, buffer.length); + } + + /** + * @dev Copies the content of `buffer`, from `start` (included) to `end` (excluded) into a new bytes object in + * memory. + * + * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`] + */ + function slice(bytes memory buffer, uint256 start, uint256 end) internal pure returns (bytes memory) { + // sanitize + uint256 length = buffer.length; + end = Math.min(end, length); + start = Math.min(start, end); + + // allocate and copy + bytes memory result = new bytes(end - start); + assembly ("memory-safe") { + mcopy(add(result, 0x20), add(add(buffer, 0x20), start), sub(end, start)) + } + + return result; + } + + /** + * @dev Reads a bytes32 from a bytes array without bounds checking. + * + * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the + * assembly block as such would prevent some optimizations. + */ + function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) { + // This is not memory safe in the general case, but all calls to this private function are within bounds. + assembly ("memory-safe") { + value := mload(add(add(buffer, 0x20), offset)) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP10.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP10.sol new file mode 100644 index 0000000..84b35da --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP10.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.2.0) (utils/CAIP10.sol) + +pragma solidity ^0.8.24; + +import {Bytes} from "./Bytes.sol"; +import {Strings} from "./Strings.sol"; +import {CAIP2} from "./CAIP2.sol"; + +/** + * @dev Helper library to format and parse CAIP-10 identifiers + * + * https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md[CAIP-10] defines account identifiers as: + * account_id: chain_id + ":" + account_address + * chain_id: [-a-z0-9]{3,8}:[-_a-zA-Z0-9]{1,32} (See {CAIP2}) + * account_address: [-.%a-zA-Z0-9]{1,128} + * + * WARNING: According to [CAIP-10's canonicalization section](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md#canonicalization), + * the implementation remains at the developer's discretion. Please note that case variations may introduce ambiguity. + * For example, when building hashes to identify accounts or data associated to them, multiple representations of the + * same account would derive to different hashes. For EVM chains, we recommend using checksummed addresses for the + * "account_address" part. They can be generated onchain using {Strings-toChecksumHexString}. + */ +library CAIP10 { + using Strings for address; + using Bytes for bytes; + + /// @dev Return the CAIP-10 identifier for an account on the current (local) chain. + function local(address account) internal view returns (string memory) { + return format(CAIP2.local(), account.toChecksumHexString()); + } + + /** + * @dev Return the CAIP-10 identifier for a given caip2 chain and account. + * + * NOTE: This function does not verify that the inputs are properly formatted. + */ + function format(string memory caip2, string memory account) internal pure returns (string memory) { + return string.concat(caip2, ":", account); + } + + /** + * @dev Parse a CAIP-10 identifier into its components. + * + * NOTE: This function does not verify that the CAIP-10 input is properly formatted. The `caip2` return can be + * parsed using the {CAIP2} library. + */ + function parse(string memory caip10) internal pure returns (string memory caip2, string memory account) { + bytes memory buffer = bytes(caip10); + + uint256 pos = buffer.lastIndexOf(":"); + return (string(buffer.slice(0, pos)), string(buffer.slice(pos + 1))); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP2.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP2.sol new file mode 100644 index 0000000..d06dd6d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP2.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.2.0) (utils/CAIP2.sol) + +pragma solidity ^0.8.24; + +import {Bytes} from "./Bytes.sol"; +import {Strings} from "./Strings.sol"; + +/** + * @dev Helper library to format and parse CAIP-2 identifiers + * + * https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md[CAIP-2] defines chain identifiers as: + * chain_id: namespace + ":" + reference + * namespace: [-a-z0-9]{3,8} + * reference: [-_a-zA-Z0-9]{1,32} + * + * WARNING: In some cases, multiple CAIP-2 identifiers may all be valid representation of a single chain. + * For EVM chains, it is recommended to use `eip155:xxx` as the canonical representation (where `xxx` is + * the EIP-155 chain id). Consider the possible ambiguity when processing CAIP-2 identifiers or when using them + * in the context of hashes. + */ +library CAIP2 { + using Strings for uint256; + using Bytes for bytes; + + /// @dev Return the CAIP-2 identifier for the current (local) chain. + function local() internal view returns (string memory) { + return format("eip155", block.chainid.toString()); + } + + /** + * @dev Return the CAIP-2 identifier for a given namespace and reference. + * + * NOTE: This function does not verify that the inputs are properly formatted. + */ + function format(string memory namespace, string memory ref) internal pure returns (string memory) { + return string.concat(namespace, ":", ref); + } + + /** + * @dev Parse a CAIP-2 identifier into its components. + * + * NOTE: This function does not verify that the CAIP-2 input is properly formatted. + */ + function parse(string memory caip2) internal pure returns (string memory namespace, string memory ref) { + bytes memory buffer = bytes(caip2); + + uint256 pos = buffer.indexOf(":"); + return (string(buffer.slice(0, pos)), string(buffer.slice(pos + 1))); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Calldata.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Calldata.sol new file mode 100644 index 0000000..41860b2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Calldata.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (utils/Calldata.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Helper library for manipulating objects in calldata. + */ +library Calldata { + // slither-disable-next-line write-after-write + function emptyBytes() internal pure returns (bytes calldata result) { + assembly ("memory-safe") { + result.offset := 0 + result.length := 0 + } + } + + // slither-disable-next-line write-after-write + function emptyString() internal pure returns (string calldata result) { + assembly ("memory-safe") { + result.offset := 0 + result.length := 0 + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Comparators.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Comparators.sol new file mode 100644 index 0000000..a8c5e73 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Comparators.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Provides a set of functions to compare values. + * + * _Available since v5.1._ + */ +library Comparators { + function lt(uint256 a, uint256 b) internal pure returns (bool) { + return a < b; + } + + function gt(uint256 a, uint256 b) internal pure returns (bool) { + return a > b; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Context.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Context.sol new file mode 100644 index 0000000..4e535fe --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Context.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.1) (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; + } + + function _contextSuffixLength() internal view virtual returns (uint256) { + return 0; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Create2.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Create2.sol new file mode 100644 index 0000000..ffd39d9 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Create2.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (utils/Create2.sol) + +pragma solidity ^0.8.20; + +import {Errors} from "./Errors.sol"; + +/** + * @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 There's no code to deploy. + */ + error Create2EmptyBytecode(); + + /** + * @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 Errors.InsufficientBalance(address(this).balance, amount); + } + if (bytecode.length == 0) { + revert Create2EmptyBytecode(); + } + assembly ("memory-safe") { + addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt) + // if no address was created, and returndata is not empty, bubble revert + if and(iszero(addr), not(iszero(returndatasize()))) { + let p := mload(0x40) + returndatacopy(p, 0, returndatasize()) + revert(p, returndatasize()) + } + } + if (addr == address(0)) { + revert Errors.FailedDeployment(); + } + } + + /** + * @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) { + assembly ("memory-safe") { + 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 := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Errors.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Errors.sol new file mode 100644 index 0000000..442fc18 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Errors.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Collection of common custom errors used in multiple contracts + * + * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. + * It is recommended to avoid relying on the error API for critical functionality. + * + * _Available since v5.1._ + */ +library Errors { + /** + * @dev The ETH balance of the account is not enough to perform the operation. + */ + error InsufficientBalance(uint256 balance, uint256 needed); + + /** + * @dev A call to an address target failed. The target may have reverted. + */ + error FailedCall(); + + /** + * @dev The deployment failed. + */ + error FailedDeployment(); + + /** + * @dev A necessary precompile is missing. + */ + error MissingPrecompile(address); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Multicall.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Multicall.sol new file mode 100644 index 0000000..94222fe --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Multicall.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (utils/Multicall.sol) + +pragma solidity ^0.8.20; + +import {Address} from "./Address.sol"; +import {Context} from "./Context.sol"; + +/** + * @dev Provides a function to batch together multiple calls in a single external call. + * + * Consider any assumption about calldata validation performed by the sender may be violated if it's not especially + * careful about sending transactions invoking {multicall}. For example, a relay address that filters function + * selectors won't filter calls nested within a {multicall} operation. + * + * NOTE: Since 5.0.1 and 4.9.4, this contract identifies non-canonical contexts (i.e. `msg.sender` is not {Context-_msgSender}). + * If a non-canonical context is identified, the following self `delegatecall` appends the last bytes of `msg.data` + * to the subcall. This makes it safe to use with {ERC2771Context}. Contexts that don't affect the resolution of + * {Context-_msgSender} are not propagated to subcalls. + */ +abstract contract Multicall is Context { + /** + * @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) { + bytes memory context = msg.sender == _msgSender() + ? new bytes(0) + : msg.data[msg.data.length - _contextSuffixLength():]; + + results = new bytes[](data.length); + for (uint256 i = 0; i < data.length; i++) { + results[i] = Address.functionDelegateCall(address(this), bytes.concat(data[i], context)); + } + return results; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Nonces.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Nonces.sol new file mode 100644 index 0000000..37451ff --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/NoncesKeyed.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/NoncesKeyed.sol new file mode 100644 index 0000000..df9c570 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/NoncesKeyed.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.2.0) (utils/NoncesKeyed.sol) +pragma solidity ^0.8.20; + +import {Nonces} from "./Nonces.sol"; + +/** + * @dev Alternative to {Nonces}, that supports key-ed nonces. + * + * Follows the https://eips.ethereum.org/EIPS/eip-4337#semi-abstracted-nonce-support[ERC-4337's semi-abstracted nonce system]. + * + * NOTE: This contract inherits from {Nonces} and reuses its storage for the first nonce key (i.e. `0`). This + * makes upgrading from {Nonces} to {NoncesKeyed} safe when using their upgradeable versions (e.g. `NoncesKeyedUpgradeable`). + * Doing so will NOT reset the current state of nonces, avoiding replay attacks where a nonce is reused after the upgrade. + */ +abstract contract NoncesKeyed is Nonces { + mapping(address owner => mapping(uint192 key => uint64)) private _nonces; + + /// @dev Returns the next unused nonce for an address and key. Result contains the key prefix. + function nonces(address owner, uint192 key) public view virtual returns (uint256) { + return key == 0 ? nonces(owner) : _pack(key, _nonces[owner][key]); + } + + /** + * @dev Consumes the next unused nonce for an address and key. + * + * Returns the current value without the key prefix. Consumed nonce is increased, so calling this function twice + * with the same arguments will return different (sequential) results. + */ + function _useNonce(address owner, uint192 key) 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 key == 0 ? _useNonce(owner) : _pack(key, _nonces[owner][key]++); + } + } + + /** + * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`. + * + * This version takes the key and the nonce in a single uint256 parameter: + * - use the first 24 bytes for the key + * - use the last 8 bytes for the nonce + */ + function _useCheckedNonce(address owner, uint256 keyNonce) internal virtual override { + (uint192 key, ) = _unpack(keyNonce); + if (key == 0) { + super._useCheckedNonce(owner, keyNonce); + } else { + uint256 current = _useNonce(owner, key); + if (keyNonce != current) revert InvalidAccountNonce(owner, current); + } + } + + /** + * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`. + * + * This version takes the key and the nonce as two different parameters. + */ + function _useCheckedNonce(address owner, uint192 key, uint64 nonce) internal virtual { + _useCheckedNonce(owner, _pack(key, nonce)); + } + + /// @dev Pack key and nonce into a keyNonce + function _pack(uint192 key, uint64 nonce) private pure returns (uint256) { + return (uint256(key) << 64) | nonce; + } + + /// @dev Unpack a keyNonce into its key and nonce components + function _unpack(uint256 keyNonce) private pure returns (uint192 key, uint64 nonce) { + return (uint192(keyNonce >> 64), uint64(keyNonce)); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Packing.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Packing.sol new file mode 100644 index 0000000..f7c5d6f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Packing.sol @@ -0,0 +1,1656 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.2.0) (utils/Packing.sol) +// This file was procedurally generated from scripts/generate/templates/Packing.js. + +pragma solidity ^0.8.20; + +/** + * @dev Helper library packing and unpacking multiple values into bytesXX. + * + * Example usage: + * + * ```solidity + * library MyPacker { + * type MyType is bytes32; + * + * function _pack(address account, bytes4 selector, uint64 period) external pure returns (MyType) { + * bytes12 subpack = Packing.pack_4_8(selector, bytes8(period)); + * bytes32 pack = Packing.pack_20_12(bytes20(account), subpack); + * return MyType.wrap(pack); + * } + * + * function _unpack(MyType self) external pure returns (address, bytes4, uint64) { + * bytes32 pack = MyType.unwrap(self); + * return ( + * address(Packing.extract_32_20(pack, 0)), + * Packing.extract_32_4(pack, 20), + * uint64(Packing.extract_32_8(pack, 24)) + * ); + * } + * } + * ``` + * + * _Available since v5.1._ + */ +// solhint-disable func-name-mixedcase +library Packing { + error OutOfRangeAccess(); + + function pack_1_1(bytes1 left, bytes1 right) internal pure returns (bytes2 result) { + assembly ("memory-safe") { + left := and(left, shl(248, not(0))) + right := and(right, shl(248, not(0))) + result := or(left, shr(8, right)) + } + } + + function pack_2_2(bytes2 left, bytes2 right) internal pure returns (bytes4 result) { + assembly ("memory-safe") { + left := and(left, shl(240, not(0))) + right := and(right, shl(240, not(0))) + result := or(left, shr(16, right)) + } + } + + function pack_2_4(bytes2 left, bytes4 right) internal pure returns (bytes6 result) { + assembly ("memory-safe") { + left := and(left, shl(240, not(0))) + right := and(right, shl(224, not(0))) + result := or(left, shr(16, right)) + } + } + + function pack_2_6(bytes2 left, bytes6 right) internal pure returns (bytes8 result) { + assembly ("memory-safe") { + left := and(left, shl(240, not(0))) + right := and(right, shl(208, not(0))) + result := or(left, shr(16, right)) + } + } + + function pack_2_8(bytes2 left, bytes8 right) internal pure returns (bytes10 result) { + assembly ("memory-safe") { + left := and(left, shl(240, not(0))) + right := and(right, shl(192, not(0))) + result := or(left, shr(16, right)) + } + } + + function pack_2_10(bytes2 left, bytes10 right) internal pure returns (bytes12 result) { + assembly ("memory-safe") { + left := and(left, shl(240, not(0))) + right := and(right, shl(176, not(0))) + result := or(left, shr(16, right)) + } + } + + function pack_2_20(bytes2 left, bytes20 right) internal pure returns (bytes22 result) { + assembly ("memory-safe") { + left := and(left, shl(240, not(0))) + right := and(right, shl(96, not(0))) + result := or(left, shr(16, right)) + } + } + + function pack_2_22(bytes2 left, bytes22 right) internal pure returns (bytes24 result) { + assembly ("memory-safe") { + left := and(left, shl(240, not(0))) + right := and(right, shl(80, not(0))) + result := or(left, shr(16, right)) + } + } + + function pack_4_2(bytes4 left, bytes2 right) internal pure returns (bytes6 result) { + assembly ("memory-safe") { + left := and(left, shl(224, not(0))) + right := and(right, shl(240, not(0))) + result := or(left, shr(32, right)) + } + } + + function pack_4_4(bytes4 left, bytes4 right) internal pure returns (bytes8 result) { + assembly ("memory-safe") { + left := and(left, shl(224, not(0))) + right := and(right, shl(224, not(0))) + result := or(left, shr(32, right)) + } + } + + function pack_4_6(bytes4 left, bytes6 right) internal pure returns (bytes10 result) { + assembly ("memory-safe") { + left := and(left, shl(224, not(0))) + right := and(right, shl(208, not(0))) + result := or(left, shr(32, right)) + } + } + + function pack_4_8(bytes4 left, bytes8 right) internal pure returns (bytes12 result) { + assembly ("memory-safe") { + left := and(left, shl(224, not(0))) + right := and(right, shl(192, not(0))) + result := or(left, shr(32, right)) + } + } + + function pack_4_12(bytes4 left, bytes12 right) internal pure returns (bytes16 result) { + assembly ("memory-safe") { + left := and(left, shl(224, not(0))) + right := and(right, shl(160, not(0))) + result := or(left, shr(32, right)) + } + } + + function pack_4_16(bytes4 left, bytes16 right) internal pure returns (bytes20 result) { + assembly ("memory-safe") { + left := and(left, shl(224, not(0))) + right := and(right, shl(128, not(0))) + result := or(left, shr(32, right)) + } + } + + function pack_4_20(bytes4 left, bytes20 right) internal pure returns (bytes24 result) { + assembly ("memory-safe") { + left := and(left, shl(224, not(0))) + right := and(right, shl(96, not(0))) + result := or(left, shr(32, right)) + } + } + + function pack_4_24(bytes4 left, bytes24 right) internal pure returns (bytes28 result) { + assembly ("memory-safe") { + left := and(left, shl(224, not(0))) + right := and(right, shl(64, not(0))) + result := or(left, shr(32, right)) + } + } + + function pack_4_28(bytes4 left, bytes28 right) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + left := and(left, shl(224, not(0))) + right := and(right, shl(32, not(0))) + result := or(left, shr(32, right)) + } + } + + function pack_6_2(bytes6 left, bytes2 right) internal pure returns (bytes8 result) { + assembly ("memory-safe") { + left := and(left, shl(208, not(0))) + right := and(right, shl(240, not(0))) + result := or(left, shr(48, right)) + } + } + + function pack_6_4(bytes6 left, bytes4 right) internal pure returns (bytes10 result) { + assembly ("memory-safe") { + left := and(left, shl(208, not(0))) + right := and(right, shl(224, not(0))) + result := or(left, shr(48, right)) + } + } + + function pack_6_6(bytes6 left, bytes6 right) internal pure returns (bytes12 result) { + assembly ("memory-safe") { + left := and(left, shl(208, not(0))) + right := and(right, shl(208, not(0))) + result := or(left, shr(48, right)) + } + } + + function pack_6_10(bytes6 left, bytes10 right) internal pure returns (bytes16 result) { + assembly ("memory-safe") { + left := and(left, shl(208, not(0))) + right := and(right, shl(176, not(0))) + result := or(left, shr(48, right)) + } + } + + function pack_6_16(bytes6 left, bytes16 right) internal pure returns (bytes22 result) { + assembly ("memory-safe") { + left := and(left, shl(208, not(0))) + right := and(right, shl(128, not(0))) + result := or(left, shr(48, right)) + } + } + + function pack_6_22(bytes6 left, bytes22 right) internal pure returns (bytes28 result) { + assembly ("memory-safe") { + left := and(left, shl(208, not(0))) + right := and(right, shl(80, not(0))) + result := or(left, shr(48, right)) + } + } + + function pack_8_2(bytes8 left, bytes2 right) internal pure returns (bytes10 result) { + assembly ("memory-safe") { + left := and(left, shl(192, not(0))) + right := and(right, shl(240, not(0))) + result := or(left, shr(64, right)) + } + } + + function pack_8_4(bytes8 left, bytes4 right) internal pure returns (bytes12 result) { + assembly ("memory-safe") { + left := and(left, shl(192, not(0))) + right := and(right, shl(224, not(0))) + result := or(left, shr(64, right)) + } + } + + function pack_8_8(bytes8 left, bytes8 right) internal pure returns (bytes16 result) { + assembly ("memory-safe") { + left := and(left, shl(192, not(0))) + right := and(right, shl(192, not(0))) + result := or(left, shr(64, right)) + } + } + + function pack_8_12(bytes8 left, bytes12 right) internal pure returns (bytes20 result) { + assembly ("memory-safe") { + left := and(left, shl(192, not(0))) + right := and(right, shl(160, not(0))) + result := or(left, shr(64, right)) + } + } + + function pack_8_16(bytes8 left, bytes16 right) internal pure returns (bytes24 result) { + assembly ("memory-safe") { + left := and(left, shl(192, not(0))) + right := and(right, shl(128, not(0))) + result := or(left, shr(64, right)) + } + } + + function pack_8_20(bytes8 left, bytes20 right) internal pure returns (bytes28 result) { + assembly ("memory-safe") { + left := and(left, shl(192, not(0))) + right := and(right, shl(96, not(0))) + result := or(left, shr(64, right)) + } + } + + function pack_8_24(bytes8 left, bytes24 right) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + left := and(left, shl(192, not(0))) + right := and(right, shl(64, not(0))) + result := or(left, shr(64, right)) + } + } + + function pack_10_2(bytes10 left, bytes2 right) internal pure returns (bytes12 result) { + assembly ("memory-safe") { + left := and(left, shl(176, not(0))) + right := and(right, shl(240, not(0))) + result := or(left, shr(80, right)) + } + } + + function pack_10_6(bytes10 left, bytes6 right) internal pure returns (bytes16 result) { + assembly ("memory-safe") { + left := and(left, shl(176, not(0))) + right := and(right, shl(208, not(0))) + result := or(left, shr(80, right)) + } + } + + function pack_10_10(bytes10 left, bytes10 right) internal pure returns (bytes20 result) { + assembly ("memory-safe") { + left := and(left, shl(176, not(0))) + right := and(right, shl(176, not(0))) + result := or(left, shr(80, right)) + } + } + + function pack_10_12(bytes10 left, bytes12 right) internal pure returns (bytes22 result) { + assembly ("memory-safe") { + left := and(left, shl(176, not(0))) + right := and(right, shl(160, not(0))) + result := or(left, shr(80, right)) + } + } + + function pack_10_22(bytes10 left, bytes22 right) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + left := and(left, shl(176, not(0))) + right := and(right, shl(80, not(0))) + result := or(left, shr(80, right)) + } + } + + function pack_12_4(bytes12 left, bytes4 right) internal pure returns (bytes16 result) { + assembly ("memory-safe") { + left := and(left, shl(160, not(0))) + right := and(right, shl(224, not(0))) + result := or(left, shr(96, right)) + } + } + + function pack_12_8(bytes12 left, bytes8 right) internal pure returns (bytes20 result) { + assembly ("memory-safe") { + left := and(left, shl(160, not(0))) + right := and(right, shl(192, not(0))) + result := or(left, shr(96, right)) + } + } + + function pack_12_10(bytes12 left, bytes10 right) internal pure returns (bytes22 result) { + assembly ("memory-safe") { + left := and(left, shl(160, not(0))) + right := and(right, shl(176, not(0))) + result := or(left, shr(96, right)) + } + } + + function pack_12_12(bytes12 left, bytes12 right) internal pure returns (bytes24 result) { + assembly ("memory-safe") { + left := and(left, shl(160, not(0))) + right := and(right, shl(160, not(0))) + result := or(left, shr(96, right)) + } + } + + function pack_12_16(bytes12 left, bytes16 right) internal pure returns (bytes28 result) { + assembly ("memory-safe") { + left := and(left, shl(160, not(0))) + right := and(right, shl(128, not(0))) + result := or(left, shr(96, right)) + } + } + + function pack_12_20(bytes12 left, bytes20 right) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + left := and(left, shl(160, not(0))) + right := and(right, shl(96, not(0))) + result := or(left, shr(96, right)) + } + } + + function pack_16_4(bytes16 left, bytes4 right) internal pure returns (bytes20 result) { + assembly ("memory-safe") { + left := and(left, shl(128, not(0))) + right := and(right, shl(224, not(0))) + result := or(left, shr(128, right)) + } + } + + function pack_16_6(bytes16 left, bytes6 right) internal pure returns (bytes22 result) { + assembly ("memory-safe") { + left := and(left, shl(128, not(0))) + right := and(right, shl(208, not(0))) + result := or(left, shr(128, right)) + } + } + + function pack_16_8(bytes16 left, bytes8 right) internal pure returns (bytes24 result) { + assembly ("memory-safe") { + left := and(left, shl(128, not(0))) + right := and(right, shl(192, not(0))) + result := or(left, shr(128, right)) + } + } + + function pack_16_12(bytes16 left, bytes12 right) internal pure returns (bytes28 result) { + assembly ("memory-safe") { + left := and(left, shl(128, not(0))) + right := and(right, shl(160, not(0))) + result := or(left, shr(128, right)) + } + } + + function pack_16_16(bytes16 left, bytes16 right) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + left := and(left, shl(128, not(0))) + right := and(right, shl(128, not(0))) + result := or(left, shr(128, right)) + } + } + + function pack_20_2(bytes20 left, bytes2 right) internal pure returns (bytes22 result) { + assembly ("memory-safe") { + left := and(left, shl(96, not(0))) + right := and(right, shl(240, not(0))) + result := or(left, shr(160, right)) + } + } + + function pack_20_4(bytes20 left, bytes4 right) internal pure returns (bytes24 result) { + assembly ("memory-safe") { + left := and(left, shl(96, not(0))) + right := and(right, shl(224, not(0))) + result := or(left, shr(160, right)) + } + } + + function pack_20_8(bytes20 left, bytes8 right) internal pure returns (bytes28 result) { + assembly ("memory-safe") { + left := and(left, shl(96, not(0))) + right := and(right, shl(192, not(0))) + result := or(left, shr(160, right)) + } + } + + function pack_20_12(bytes20 left, bytes12 right) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + left := and(left, shl(96, not(0))) + right := and(right, shl(160, not(0))) + result := or(left, shr(160, right)) + } + } + + function pack_22_2(bytes22 left, bytes2 right) internal pure returns (bytes24 result) { + assembly ("memory-safe") { + left := and(left, shl(80, not(0))) + right := and(right, shl(240, not(0))) + result := or(left, shr(176, right)) + } + } + + function pack_22_6(bytes22 left, bytes6 right) internal pure returns (bytes28 result) { + assembly ("memory-safe") { + left := and(left, shl(80, not(0))) + right := and(right, shl(208, not(0))) + result := or(left, shr(176, right)) + } + } + + function pack_22_10(bytes22 left, bytes10 right) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + left := and(left, shl(80, not(0))) + right := and(right, shl(176, not(0))) + result := or(left, shr(176, right)) + } + } + + function pack_24_4(bytes24 left, bytes4 right) internal pure returns (bytes28 result) { + assembly ("memory-safe") { + left := and(left, shl(64, not(0))) + right := and(right, shl(224, not(0))) + result := or(left, shr(192, right)) + } + } + + function pack_24_8(bytes24 left, bytes8 right) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + left := and(left, shl(64, not(0))) + right := and(right, shl(192, not(0))) + result := or(left, shr(192, right)) + } + } + + function pack_28_4(bytes28 left, bytes4 right) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + left := and(left, shl(32, not(0))) + right := and(right, shl(224, not(0))) + result := or(left, shr(224, right)) + } + } + + function extract_2_1(bytes2 self, uint8 offset) internal pure returns (bytes1 result) { + if (offset > 1) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(248, not(0))) + } + } + + function replace_2_1(bytes2 self, bytes1 value, uint8 offset) internal pure returns (bytes2 result) { + bytes1 oldValue = extract_2_1(self, offset); + assembly ("memory-safe") { + value := and(value, shl(248, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_4_1(bytes4 self, uint8 offset) internal pure returns (bytes1 result) { + if (offset > 3) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(248, not(0))) + } + } + + function replace_4_1(bytes4 self, bytes1 value, uint8 offset) internal pure returns (bytes4 result) { + bytes1 oldValue = extract_4_1(self, offset); + assembly ("memory-safe") { + value := and(value, shl(248, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_4_2(bytes4 self, uint8 offset) internal pure returns (bytes2 result) { + if (offset > 2) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(240, not(0))) + } + } + + function replace_4_2(bytes4 self, bytes2 value, uint8 offset) internal pure returns (bytes4 result) { + bytes2 oldValue = extract_4_2(self, offset); + assembly ("memory-safe") { + value := and(value, shl(240, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_6_1(bytes6 self, uint8 offset) internal pure returns (bytes1 result) { + if (offset > 5) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(248, not(0))) + } + } + + function replace_6_1(bytes6 self, bytes1 value, uint8 offset) internal pure returns (bytes6 result) { + bytes1 oldValue = extract_6_1(self, offset); + assembly ("memory-safe") { + value := and(value, shl(248, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_6_2(bytes6 self, uint8 offset) internal pure returns (bytes2 result) { + if (offset > 4) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(240, not(0))) + } + } + + function replace_6_2(bytes6 self, bytes2 value, uint8 offset) internal pure returns (bytes6 result) { + bytes2 oldValue = extract_6_2(self, offset); + assembly ("memory-safe") { + value := and(value, shl(240, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_6_4(bytes6 self, uint8 offset) internal pure returns (bytes4 result) { + if (offset > 2) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(224, not(0))) + } + } + + function replace_6_4(bytes6 self, bytes4 value, uint8 offset) internal pure returns (bytes6 result) { + bytes4 oldValue = extract_6_4(self, offset); + assembly ("memory-safe") { + value := and(value, shl(224, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_8_1(bytes8 self, uint8 offset) internal pure returns (bytes1 result) { + if (offset > 7) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(248, not(0))) + } + } + + function replace_8_1(bytes8 self, bytes1 value, uint8 offset) internal pure returns (bytes8 result) { + bytes1 oldValue = extract_8_1(self, offset); + assembly ("memory-safe") { + value := and(value, shl(248, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_8_2(bytes8 self, uint8 offset) internal pure returns (bytes2 result) { + if (offset > 6) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(240, not(0))) + } + } + + function replace_8_2(bytes8 self, bytes2 value, uint8 offset) internal pure returns (bytes8 result) { + bytes2 oldValue = extract_8_2(self, offset); + assembly ("memory-safe") { + value := and(value, shl(240, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_8_4(bytes8 self, uint8 offset) internal pure returns (bytes4 result) { + if (offset > 4) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(224, not(0))) + } + } + + function replace_8_4(bytes8 self, bytes4 value, uint8 offset) internal pure returns (bytes8 result) { + bytes4 oldValue = extract_8_4(self, offset); + assembly ("memory-safe") { + value := and(value, shl(224, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_8_6(bytes8 self, uint8 offset) internal pure returns (bytes6 result) { + if (offset > 2) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(208, not(0))) + } + } + + function replace_8_6(bytes8 self, bytes6 value, uint8 offset) internal pure returns (bytes8 result) { + bytes6 oldValue = extract_8_6(self, offset); + assembly ("memory-safe") { + value := and(value, shl(208, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_10_1(bytes10 self, uint8 offset) internal pure returns (bytes1 result) { + if (offset > 9) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(248, not(0))) + } + } + + function replace_10_1(bytes10 self, bytes1 value, uint8 offset) internal pure returns (bytes10 result) { + bytes1 oldValue = extract_10_1(self, offset); + assembly ("memory-safe") { + value := and(value, shl(248, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_10_2(bytes10 self, uint8 offset) internal pure returns (bytes2 result) { + if (offset > 8) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(240, not(0))) + } + } + + function replace_10_2(bytes10 self, bytes2 value, uint8 offset) internal pure returns (bytes10 result) { + bytes2 oldValue = extract_10_2(self, offset); + assembly ("memory-safe") { + value := and(value, shl(240, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_10_4(bytes10 self, uint8 offset) internal pure returns (bytes4 result) { + if (offset > 6) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(224, not(0))) + } + } + + function replace_10_4(bytes10 self, bytes4 value, uint8 offset) internal pure returns (bytes10 result) { + bytes4 oldValue = extract_10_4(self, offset); + assembly ("memory-safe") { + value := and(value, shl(224, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_10_6(bytes10 self, uint8 offset) internal pure returns (bytes6 result) { + if (offset > 4) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(208, not(0))) + } + } + + function replace_10_6(bytes10 self, bytes6 value, uint8 offset) internal pure returns (bytes10 result) { + bytes6 oldValue = extract_10_6(self, offset); + assembly ("memory-safe") { + value := and(value, shl(208, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_10_8(bytes10 self, uint8 offset) internal pure returns (bytes8 result) { + if (offset > 2) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(192, not(0))) + } + } + + function replace_10_8(bytes10 self, bytes8 value, uint8 offset) internal pure returns (bytes10 result) { + bytes8 oldValue = extract_10_8(self, offset); + assembly ("memory-safe") { + value := and(value, shl(192, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_12_1(bytes12 self, uint8 offset) internal pure returns (bytes1 result) { + if (offset > 11) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(248, not(0))) + } + } + + function replace_12_1(bytes12 self, bytes1 value, uint8 offset) internal pure returns (bytes12 result) { + bytes1 oldValue = extract_12_1(self, offset); + assembly ("memory-safe") { + value := and(value, shl(248, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_12_2(bytes12 self, uint8 offset) internal pure returns (bytes2 result) { + if (offset > 10) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(240, not(0))) + } + } + + function replace_12_2(bytes12 self, bytes2 value, uint8 offset) internal pure returns (bytes12 result) { + bytes2 oldValue = extract_12_2(self, offset); + assembly ("memory-safe") { + value := and(value, shl(240, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_12_4(bytes12 self, uint8 offset) internal pure returns (bytes4 result) { + if (offset > 8) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(224, not(0))) + } + } + + function replace_12_4(bytes12 self, bytes4 value, uint8 offset) internal pure returns (bytes12 result) { + bytes4 oldValue = extract_12_4(self, offset); + assembly ("memory-safe") { + value := and(value, shl(224, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_12_6(bytes12 self, uint8 offset) internal pure returns (bytes6 result) { + if (offset > 6) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(208, not(0))) + } + } + + function replace_12_6(bytes12 self, bytes6 value, uint8 offset) internal pure returns (bytes12 result) { + bytes6 oldValue = extract_12_6(self, offset); + assembly ("memory-safe") { + value := and(value, shl(208, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_12_8(bytes12 self, uint8 offset) internal pure returns (bytes8 result) { + if (offset > 4) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(192, not(0))) + } + } + + function replace_12_8(bytes12 self, bytes8 value, uint8 offset) internal pure returns (bytes12 result) { + bytes8 oldValue = extract_12_8(self, offset); + assembly ("memory-safe") { + value := and(value, shl(192, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_12_10(bytes12 self, uint8 offset) internal pure returns (bytes10 result) { + if (offset > 2) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(176, not(0))) + } + } + + function replace_12_10(bytes12 self, bytes10 value, uint8 offset) internal pure returns (bytes12 result) { + bytes10 oldValue = extract_12_10(self, offset); + assembly ("memory-safe") { + value := and(value, shl(176, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_16_1(bytes16 self, uint8 offset) internal pure returns (bytes1 result) { + if (offset > 15) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(248, not(0))) + } + } + + function replace_16_1(bytes16 self, bytes1 value, uint8 offset) internal pure returns (bytes16 result) { + bytes1 oldValue = extract_16_1(self, offset); + assembly ("memory-safe") { + value := and(value, shl(248, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_16_2(bytes16 self, uint8 offset) internal pure returns (bytes2 result) { + if (offset > 14) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(240, not(0))) + } + } + + function replace_16_2(bytes16 self, bytes2 value, uint8 offset) internal pure returns (bytes16 result) { + bytes2 oldValue = extract_16_2(self, offset); + assembly ("memory-safe") { + value := and(value, shl(240, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_16_4(bytes16 self, uint8 offset) internal pure returns (bytes4 result) { + if (offset > 12) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(224, not(0))) + } + } + + function replace_16_4(bytes16 self, bytes4 value, uint8 offset) internal pure returns (bytes16 result) { + bytes4 oldValue = extract_16_4(self, offset); + assembly ("memory-safe") { + value := and(value, shl(224, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_16_6(bytes16 self, uint8 offset) internal pure returns (bytes6 result) { + if (offset > 10) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(208, not(0))) + } + } + + function replace_16_6(bytes16 self, bytes6 value, uint8 offset) internal pure returns (bytes16 result) { + bytes6 oldValue = extract_16_6(self, offset); + assembly ("memory-safe") { + value := and(value, shl(208, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_16_8(bytes16 self, uint8 offset) internal pure returns (bytes8 result) { + if (offset > 8) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(192, not(0))) + } + } + + function replace_16_8(bytes16 self, bytes8 value, uint8 offset) internal pure returns (bytes16 result) { + bytes8 oldValue = extract_16_8(self, offset); + assembly ("memory-safe") { + value := and(value, shl(192, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_16_10(bytes16 self, uint8 offset) internal pure returns (bytes10 result) { + if (offset > 6) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(176, not(0))) + } + } + + function replace_16_10(bytes16 self, bytes10 value, uint8 offset) internal pure returns (bytes16 result) { + bytes10 oldValue = extract_16_10(self, offset); + assembly ("memory-safe") { + value := and(value, shl(176, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_16_12(bytes16 self, uint8 offset) internal pure returns (bytes12 result) { + if (offset > 4) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(160, not(0))) + } + } + + function replace_16_12(bytes16 self, bytes12 value, uint8 offset) internal pure returns (bytes16 result) { + bytes12 oldValue = extract_16_12(self, offset); + assembly ("memory-safe") { + value := and(value, shl(160, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_20_1(bytes20 self, uint8 offset) internal pure returns (bytes1 result) { + if (offset > 19) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(248, not(0))) + } + } + + function replace_20_1(bytes20 self, bytes1 value, uint8 offset) internal pure returns (bytes20 result) { + bytes1 oldValue = extract_20_1(self, offset); + assembly ("memory-safe") { + value := and(value, shl(248, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_20_2(bytes20 self, uint8 offset) internal pure returns (bytes2 result) { + if (offset > 18) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(240, not(0))) + } + } + + function replace_20_2(bytes20 self, bytes2 value, uint8 offset) internal pure returns (bytes20 result) { + bytes2 oldValue = extract_20_2(self, offset); + assembly ("memory-safe") { + value := and(value, shl(240, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_20_4(bytes20 self, uint8 offset) internal pure returns (bytes4 result) { + if (offset > 16) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(224, not(0))) + } + } + + function replace_20_4(bytes20 self, bytes4 value, uint8 offset) internal pure returns (bytes20 result) { + bytes4 oldValue = extract_20_4(self, offset); + assembly ("memory-safe") { + value := and(value, shl(224, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_20_6(bytes20 self, uint8 offset) internal pure returns (bytes6 result) { + if (offset > 14) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(208, not(0))) + } + } + + function replace_20_6(bytes20 self, bytes6 value, uint8 offset) internal pure returns (bytes20 result) { + bytes6 oldValue = extract_20_6(self, offset); + assembly ("memory-safe") { + value := and(value, shl(208, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_20_8(bytes20 self, uint8 offset) internal pure returns (bytes8 result) { + if (offset > 12) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(192, not(0))) + } + } + + function replace_20_8(bytes20 self, bytes8 value, uint8 offset) internal pure returns (bytes20 result) { + bytes8 oldValue = extract_20_8(self, offset); + assembly ("memory-safe") { + value := and(value, shl(192, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_20_10(bytes20 self, uint8 offset) internal pure returns (bytes10 result) { + if (offset > 10) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(176, not(0))) + } + } + + function replace_20_10(bytes20 self, bytes10 value, uint8 offset) internal pure returns (bytes20 result) { + bytes10 oldValue = extract_20_10(self, offset); + assembly ("memory-safe") { + value := and(value, shl(176, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_20_12(bytes20 self, uint8 offset) internal pure returns (bytes12 result) { + if (offset > 8) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(160, not(0))) + } + } + + function replace_20_12(bytes20 self, bytes12 value, uint8 offset) internal pure returns (bytes20 result) { + bytes12 oldValue = extract_20_12(self, offset); + assembly ("memory-safe") { + value := and(value, shl(160, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_20_16(bytes20 self, uint8 offset) internal pure returns (bytes16 result) { + if (offset > 4) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(128, not(0))) + } + } + + function replace_20_16(bytes20 self, bytes16 value, uint8 offset) internal pure returns (bytes20 result) { + bytes16 oldValue = extract_20_16(self, offset); + assembly ("memory-safe") { + value := and(value, shl(128, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_22_1(bytes22 self, uint8 offset) internal pure returns (bytes1 result) { + if (offset > 21) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(248, not(0))) + } + } + + function replace_22_1(bytes22 self, bytes1 value, uint8 offset) internal pure returns (bytes22 result) { + bytes1 oldValue = extract_22_1(self, offset); + assembly ("memory-safe") { + value := and(value, shl(248, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_22_2(bytes22 self, uint8 offset) internal pure returns (bytes2 result) { + if (offset > 20) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(240, not(0))) + } + } + + function replace_22_2(bytes22 self, bytes2 value, uint8 offset) internal pure returns (bytes22 result) { + bytes2 oldValue = extract_22_2(self, offset); + assembly ("memory-safe") { + value := and(value, shl(240, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_22_4(bytes22 self, uint8 offset) internal pure returns (bytes4 result) { + if (offset > 18) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(224, not(0))) + } + } + + function replace_22_4(bytes22 self, bytes4 value, uint8 offset) internal pure returns (bytes22 result) { + bytes4 oldValue = extract_22_4(self, offset); + assembly ("memory-safe") { + value := and(value, shl(224, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_22_6(bytes22 self, uint8 offset) internal pure returns (bytes6 result) { + if (offset > 16) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(208, not(0))) + } + } + + function replace_22_6(bytes22 self, bytes6 value, uint8 offset) internal pure returns (bytes22 result) { + bytes6 oldValue = extract_22_6(self, offset); + assembly ("memory-safe") { + value := and(value, shl(208, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_22_8(bytes22 self, uint8 offset) internal pure returns (bytes8 result) { + if (offset > 14) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(192, not(0))) + } + } + + function replace_22_8(bytes22 self, bytes8 value, uint8 offset) internal pure returns (bytes22 result) { + bytes8 oldValue = extract_22_8(self, offset); + assembly ("memory-safe") { + value := and(value, shl(192, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_22_10(bytes22 self, uint8 offset) internal pure returns (bytes10 result) { + if (offset > 12) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(176, not(0))) + } + } + + function replace_22_10(bytes22 self, bytes10 value, uint8 offset) internal pure returns (bytes22 result) { + bytes10 oldValue = extract_22_10(self, offset); + assembly ("memory-safe") { + value := and(value, shl(176, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_22_12(bytes22 self, uint8 offset) internal pure returns (bytes12 result) { + if (offset > 10) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(160, not(0))) + } + } + + function replace_22_12(bytes22 self, bytes12 value, uint8 offset) internal pure returns (bytes22 result) { + bytes12 oldValue = extract_22_12(self, offset); + assembly ("memory-safe") { + value := and(value, shl(160, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_22_16(bytes22 self, uint8 offset) internal pure returns (bytes16 result) { + if (offset > 6) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(128, not(0))) + } + } + + function replace_22_16(bytes22 self, bytes16 value, uint8 offset) internal pure returns (bytes22 result) { + bytes16 oldValue = extract_22_16(self, offset); + assembly ("memory-safe") { + value := and(value, shl(128, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_22_20(bytes22 self, uint8 offset) internal pure returns (bytes20 result) { + if (offset > 2) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(96, not(0))) + } + } + + function replace_22_20(bytes22 self, bytes20 value, uint8 offset) internal pure returns (bytes22 result) { + bytes20 oldValue = extract_22_20(self, offset); + assembly ("memory-safe") { + value := and(value, shl(96, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_24_1(bytes24 self, uint8 offset) internal pure returns (bytes1 result) { + if (offset > 23) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(248, not(0))) + } + } + + function replace_24_1(bytes24 self, bytes1 value, uint8 offset) internal pure returns (bytes24 result) { + bytes1 oldValue = extract_24_1(self, offset); + assembly ("memory-safe") { + value := and(value, shl(248, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_24_2(bytes24 self, uint8 offset) internal pure returns (bytes2 result) { + if (offset > 22) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(240, not(0))) + } + } + + function replace_24_2(bytes24 self, bytes2 value, uint8 offset) internal pure returns (bytes24 result) { + bytes2 oldValue = extract_24_2(self, offset); + assembly ("memory-safe") { + value := and(value, shl(240, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_24_4(bytes24 self, uint8 offset) internal pure returns (bytes4 result) { + if (offset > 20) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(224, not(0))) + } + } + + function replace_24_4(bytes24 self, bytes4 value, uint8 offset) internal pure returns (bytes24 result) { + bytes4 oldValue = extract_24_4(self, offset); + assembly ("memory-safe") { + value := and(value, shl(224, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_24_6(bytes24 self, uint8 offset) internal pure returns (bytes6 result) { + if (offset > 18) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(208, not(0))) + } + } + + function replace_24_6(bytes24 self, bytes6 value, uint8 offset) internal pure returns (bytes24 result) { + bytes6 oldValue = extract_24_6(self, offset); + assembly ("memory-safe") { + value := and(value, shl(208, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_24_8(bytes24 self, uint8 offset) internal pure returns (bytes8 result) { + if (offset > 16) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(192, not(0))) + } + } + + function replace_24_8(bytes24 self, bytes8 value, uint8 offset) internal pure returns (bytes24 result) { + bytes8 oldValue = extract_24_8(self, offset); + assembly ("memory-safe") { + value := and(value, shl(192, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_24_10(bytes24 self, uint8 offset) internal pure returns (bytes10 result) { + if (offset > 14) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(176, not(0))) + } + } + + function replace_24_10(bytes24 self, bytes10 value, uint8 offset) internal pure returns (bytes24 result) { + bytes10 oldValue = extract_24_10(self, offset); + assembly ("memory-safe") { + value := and(value, shl(176, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_24_12(bytes24 self, uint8 offset) internal pure returns (bytes12 result) { + if (offset > 12) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(160, not(0))) + } + } + + function replace_24_12(bytes24 self, bytes12 value, uint8 offset) internal pure returns (bytes24 result) { + bytes12 oldValue = extract_24_12(self, offset); + assembly ("memory-safe") { + value := and(value, shl(160, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_24_16(bytes24 self, uint8 offset) internal pure returns (bytes16 result) { + if (offset > 8) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(128, not(0))) + } + } + + function replace_24_16(bytes24 self, bytes16 value, uint8 offset) internal pure returns (bytes24 result) { + bytes16 oldValue = extract_24_16(self, offset); + assembly ("memory-safe") { + value := and(value, shl(128, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_24_20(bytes24 self, uint8 offset) internal pure returns (bytes20 result) { + if (offset > 4) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(96, not(0))) + } + } + + function replace_24_20(bytes24 self, bytes20 value, uint8 offset) internal pure returns (bytes24 result) { + bytes20 oldValue = extract_24_20(self, offset); + assembly ("memory-safe") { + value := and(value, shl(96, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_24_22(bytes24 self, uint8 offset) internal pure returns (bytes22 result) { + if (offset > 2) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(80, not(0))) + } + } + + function replace_24_22(bytes24 self, bytes22 value, uint8 offset) internal pure returns (bytes24 result) { + bytes22 oldValue = extract_24_22(self, offset); + assembly ("memory-safe") { + value := and(value, shl(80, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_28_1(bytes28 self, uint8 offset) internal pure returns (bytes1 result) { + if (offset > 27) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(248, not(0))) + } + } + + function replace_28_1(bytes28 self, bytes1 value, uint8 offset) internal pure returns (bytes28 result) { + bytes1 oldValue = extract_28_1(self, offset); + assembly ("memory-safe") { + value := and(value, shl(248, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_28_2(bytes28 self, uint8 offset) internal pure returns (bytes2 result) { + if (offset > 26) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(240, not(0))) + } + } + + function replace_28_2(bytes28 self, bytes2 value, uint8 offset) internal pure returns (bytes28 result) { + bytes2 oldValue = extract_28_2(self, offset); + assembly ("memory-safe") { + value := and(value, shl(240, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_28_4(bytes28 self, uint8 offset) internal pure returns (bytes4 result) { + if (offset > 24) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(224, not(0))) + } + } + + function replace_28_4(bytes28 self, bytes4 value, uint8 offset) internal pure returns (bytes28 result) { + bytes4 oldValue = extract_28_4(self, offset); + assembly ("memory-safe") { + value := and(value, shl(224, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_28_6(bytes28 self, uint8 offset) internal pure returns (bytes6 result) { + if (offset > 22) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(208, not(0))) + } + } + + function replace_28_6(bytes28 self, bytes6 value, uint8 offset) internal pure returns (bytes28 result) { + bytes6 oldValue = extract_28_6(self, offset); + assembly ("memory-safe") { + value := and(value, shl(208, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_28_8(bytes28 self, uint8 offset) internal pure returns (bytes8 result) { + if (offset > 20) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(192, not(0))) + } + } + + function replace_28_8(bytes28 self, bytes8 value, uint8 offset) internal pure returns (bytes28 result) { + bytes8 oldValue = extract_28_8(self, offset); + assembly ("memory-safe") { + value := and(value, shl(192, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_28_10(bytes28 self, uint8 offset) internal pure returns (bytes10 result) { + if (offset > 18) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(176, not(0))) + } + } + + function replace_28_10(bytes28 self, bytes10 value, uint8 offset) internal pure returns (bytes28 result) { + bytes10 oldValue = extract_28_10(self, offset); + assembly ("memory-safe") { + value := and(value, shl(176, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_28_12(bytes28 self, uint8 offset) internal pure returns (bytes12 result) { + if (offset > 16) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(160, not(0))) + } + } + + function replace_28_12(bytes28 self, bytes12 value, uint8 offset) internal pure returns (bytes28 result) { + bytes12 oldValue = extract_28_12(self, offset); + assembly ("memory-safe") { + value := and(value, shl(160, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_28_16(bytes28 self, uint8 offset) internal pure returns (bytes16 result) { + if (offset > 12) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(128, not(0))) + } + } + + function replace_28_16(bytes28 self, bytes16 value, uint8 offset) internal pure returns (bytes28 result) { + bytes16 oldValue = extract_28_16(self, offset); + assembly ("memory-safe") { + value := and(value, shl(128, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_28_20(bytes28 self, uint8 offset) internal pure returns (bytes20 result) { + if (offset > 8) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(96, not(0))) + } + } + + function replace_28_20(bytes28 self, bytes20 value, uint8 offset) internal pure returns (bytes28 result) { + bytes20 oldValue = extract_28_20(self, offset); + assembly ("memory-safe") { + value := and(value, shl(96, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_28_22(bytes28 self, uint8 offset) internal pure returns (bytes22 result) { + if (offset > 6) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(80, not(0))) + } + } + + function replace_28_22(bytes28 self, bytes22 value, uint8 offset) internal pure returns (bytes28 result) { + bytes22 oldValue = extract_28_22(self, offset); + assembly ("memory-safe") { + value := and(value, shl(80, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_28_24(bytes28 self, uint8 offset) internal pure returns (bytes24 result) { + if (offset > 4) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(64, not(0))) + } + } + + function replace_28_24(bytes28 self, bytes24 value, uint8 offset) internal pure returns (bytes28 result) { + bytes24 oldValue = extract_28_24(self, offset); + assembly ("memory-safe") { + value := and(value, shl(64, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_32_1(bytes32 self, uint8 offset) internal pure returns (bytes1 result) { + if (offset > 31) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(248, not(0))) + } + } + + function replace_32_1(bytes32 self, bytes1 value, uint8 offset) internal pure returns (bytes32 result) { + bytes1 oldValue = extract_32_1(self, offset); + assembly ("memory-safe") { + value := and(value, shl(248, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_32_2(bytes32 self, uint8 offset) internal pure returns (bytes2 result) { + if (offset > 30) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(240, not(0))) + } + } + + function replace_32_2(bytes32 self, bytes2 value, uint8 offset) internal pure returns (bytes32 result) { + bytes2 oldValue = extract_32_2(self, offset); + assembly ("memory-safe") { + value := and(value, shl(240, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_32_4(bytes32 self, uint8 offset) internal pure returns (bytes4 result) { + if (offset > 28) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(224, not(0))) + } + } + + function replace_32_4(bytes32 self, bytes4 value, uint8 offset) internal pure returns (bytes32 result) { + bytes4 oldValue = extract_32_4(self, offset); + assembly ("memory-safe") { + value := and(value, shl(224, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_32_6(bytes32 self, uint8 offset) internal pure returns (bytes6 result) { + if (offset > 26) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(208, not(0))) + } + } + + function replace_32_6(bytes32 self, bytes6 value, uint8 offset) internal pure returns (bytes32 result) { + bytes6 oldValue = extract_32_6(self, offset); + assembly ("memory-safe") { + value := and(value, shl(208, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_32_8(bytes32 self, uint8 offset) internal pure returns (bytes8 result) { + if (offset > 24) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(192, not(0))) + } + } + + function replace_32_8(bytes32 self, bytes8 value, uint8 offset) internal pure returns (bytes32 result) { + bytes8 oldValue = extract_32_8(self, offset); + assembly ("memory-safe") { + value := and(value, shl(192, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_32_10(bytes32 self, uint8 offset) internal pure returns (bytes10 result) { + if (offset > 22) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(176, not(0))) + } + } + + function replace_32_10(bytes32 self, bytes10 value, uint8 offset) internal pure returns (bytes32 result) { + bytes10 oldValue = extract_32_10(self, offset); + assembly ("memory-safe") { + value := and(value, shl(176, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_32_12(bytes32 self, uint8 offset) internal pure returns (bytes12 result) { + if (offset > 20) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(160, not(0))) + } + } + + function replace_32_12(bytes32 self, bytes12 value, uint8 offset) internal pure returns (bytes32 result) { + bytes12 oldValue = extract_32_12(self, offset); + assembly ("memory-safe") { + value := and(value, shl(160, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_32_16(bytes32 self, uint8 offset) internal pure returns (bytes16 result) { + if (offset > 16) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(128, not(0))) + } + } + + function replace_32_16(bytes32 self, bytes16 value, uint8 offset) internal pure returns (bytes32 result) { + bytes16 oldValue = extract_32_16(self, offset); + assembly ("memory-safe") { + value := and(value, shl(128, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_32_20(bytes32 self, uint8 offset) internal pure returns (bytes20 result) { + if (offset > 12) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(96, not(0))) + } + } + + function replace_32_20(bytes32 self, bytes20 value, uint8 offset) internal pure returns (bytes32 result) { + bytes20 oldValue = extract_32_20(self, offset); + assembly ("memory-safe") { + value := and(value, shl(96, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_32_22(bytes32 self, uint8 offset) internal pure returns (bytes22 result) { + if (offset > 10) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(80, not(0))) + } + } + + function replace_32_22(bytes32 self, bytes22 value, uint8 offset) internal pure returns (bytes32 result) { + bytes22 oldValue = extract_32_22(self, offset); + assembly ("memory-safe") { + value := and(value, shl(80, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_32_24(bytes32 self, uint8 offset) internal pure returns (bytes24 result) { + if (offset > 8) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(64, not(0))) + } + } + + function replace_32_24(bytes32 self, bytes24 value, uint8 offset) internal pure returns (bytes32 result) { + bytes24 oldValue = extract_32_24(self, offset); + assembly ("memory-safe") { + value := and(value, shl(64, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } + + function extract_32_28(bytes32 self, uint8 offset) internal pure returns (bytes28 result) { + if (offset > 4) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := and(shl(mul(8, offset), self), shl(32, not(0))) + } + } + + function replace_32_28(bytes32 self, bytes28 value, uint8 offset) internal pure returns (bytes32 result) { + bytes28 oldValue = extract_32_28(self, offset); + assembly ("memory-safe") { + value := and(value, shl(32, not(0))) + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Panic.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Panic.sol new file mode 100644 index 0000000..e168824 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Panic.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Helper library for emitting standardized panic codes. + * + * ```solidity + * contract Example { + * using Panic for uint256; + * + * // Use any of the declared internal constants + * function foo() { Panic.GENERIC.panic(); } + * + * // Alternatively + * function foo() { Panic.panic(Panic.GENERIC); } + * } + * ``` + * + * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil]. + * + * _Available since v5.1._ + */ +// slither-disable-next-line unused-state +library Panic { + /// @dev generic / unspecified error + uint256 internal constant GENERIC = 0x00; + /// @dev used by the assert() builtin + uint256 internal constant ASSERT = 0x01; + /// @dev arithmetic underflow or overflow + uint256 internal constant UNDER_OVERFLOW = 0x11; + /// @dev division or modulo by zero + uint256 internal constant DIVISION_BY_ZERO = 0x12; + /// @dev enum conversion error + uint256 internal constant ENUM_CONVERSION_ERROR = 0x21; + /// @dev invalid encoding in storage + uint256 internal constant STORAGE_ENCODING_ERROR = 0x22; + /// @dev empty array pop + uint256 internal constant EMPTY_ARRAY_POP = 0x31; + /// @dev array out of bounds access + uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32; + /// @dev resource error (too large allocation or too large array) + uint256 internal constant RESOURCE_ERROR = 0x41; + /// @dev calling invalid internal function + uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51; + + /// @dev Reverts with a panic code. Recommended to use with + /// the internal constants with predefined codes. + function panic(uint256 code) internal pure { + assembly ("memory-safe") { + mstore(0x00, 0x4e487b71) + mstore(0x20, code) + revert(0x1c, 0x24) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Pausable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Pausable.sol new file mode 100644 index 0000000..68e7d26 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Pausable.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.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 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/README.adoc new file mode 100644 index 0000000..231bccd --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/README.adoc @@ -0,0 +1,139 @@ += 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. + + * {Math}, {SignedMath}: Implementation of various arithmetic functions. + * {SafeCast}: Checked downcasting functions to avoid silent truncation. + * {ReentrancyGuard}: A modifier that can prevent reentrancy during certain functions. + * {ReentrancyGuardTransient}: Variant of {ReentrancyGuard} that uses transient storage (https://eips.ethereum.org/EIPS/eip-1153[EIP-1153]). + * {Pausable}: A common emergency response mechanism that can pause functionality while a remediation is pending. + * {Nonces}: Utility for tracking and verifying address nonces that only increment. + * {NoncesKeyed}: Alternative to {Nonces}, that support keyed nonces following https://eips.ethereum.org/EIPS/eip-4337#semi-abstracted-nonce-support[ERC-4337 specifications]. + * {ERC165}, {ERC165Checker}: Utilities for inspecting interfaces supported by contracts. + * {BitMaps}: A simple library to manage boolean value mapped to a numerical index in an efficient way. + * {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. + * {DoubleEndedQueue}: An implementation of a https://en.wikipedia.org/wiki/Double-ended_queue[double ended queue] whose values can be added or removed from both sides. Useful for FIFO and LIFO structures. + * {CircularBuffer}: A data structure to store the last N values pushed to it. + * {Checkpoints}: A data structure to store values mapped to a strictly increasing key. Can be used for storing and accessing values over time. + * {Heap}: A library that implements a https://en.wikipedia.org/wiki/Binary_heap[binary heap] in storage. + * {MerkleTree}: A library with https://wikipedia.org/wiki/Merkle_Tree[Merkle Tree] data structures and helper functions. + * {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. + * {Address}: Collection of functions for overloading Solidity's https://docs.soliditylang.org/en/latest/types.html#address[`address`] type. + * {Arrays}: Collection of functions that operate on https://docs.soliditylang.org/en/latest/types.html#arrays[`arrays`]. + * {Base64}: On-chain base64 and base64URL encoding according to https://datatracker.ietf.org/doc/html/rfc4648[RFC-4648]. + * {Bytes}: Common operations on bytes objects. + * {Calldata}: Helpers for manipulating calldata. + * {Strings}: Common operations for strings formatting. + * {ShortStrings}: Library to encode (and decode) short strings into (or from) a single bytes32 slot for optimizing costs. Short strings are limited to 31 characters. + * {SlotDerivation}: Methods for deriving storage slot from ERC-7201 namespaces as well as from constructions such as mapping and arrays. + * {StorageSlot}: Methods for accessing specific storage slots formatted as common primitive types. + * {TransientSlot}: Primitives for reading from and writing to transient storage (only value types are currently supported). + * {Multicall}: Abstract contract with a utility to allow batching together multiple calls in a single transaction. Useful for allowing EOAs to perform multiple operations at once. + * {Context}: A utility for abstracting the sender and calldata in the current execution context. + * {Packing}: A library for packing and unpacking multiple values into bytes32 + * {Panic}: A library to revert with https://docs.soliditylang.org/en/v0.8.20/control-structures.html#panic-via-assert-and-error-via-require[Solidity panic codes]. + * {Comparators}: A library that contains comparator functions to use with the {Heap} library. + * {CAIP2}, {CAIP10}: Libraries for formatting and parsing CAIP-2 and CAIP-10 identifiers. + * {Blockhash}: A library for accessing historical block hashes beyond the standard 256 block limit utilizing EIP-2935's historical blockhash functionality. + * {Time}: A library that provides helpers for manipulating time-related objects, including a `Delay` type. + +[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}} + +== Security + +{{ReentrancyGuard}} + +{{ReentrancyGuardTransient}} + +{{Pausable}} + +{{Nonces}} + +{{NoncesKeyed}} + +== 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. ERC-20 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}} + +{{CircularBuffer}} + +{{Checkpoints}} + +{{Heap}} + +{{MerkleTree}} + +== Libraries + +{{Create2}} + +{{Address}} + +{{Arrays}} + +{{Base64}} + +{{Bytes}} + +{{Calldata}} + +{{Strings}} + +{{ShortStrings}} + +{{SlotDerivation}} + +{{StorageSlot}} + +{{TransientSlot}} + +{{Multicall}} + +{{Context}} + +{{Packing}} + +{{Panic}} + +{{Comparators}} + +{{CAIP2}} + +{{CAIP10}} + +{{Blockhash}} + +{{Time}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol new file mode 100644 index 0000000..a95fb51 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.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 EIP-1153 (transient storage) is available on the chain you're deploying at, + * consider using {ReentrancyGuardTransient} instead. + * + * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuardTransient.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuardTransient.sol new file mode 100644 index 0000000..a1318c8 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuardTransient.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (utils/ReentrancyGuardTransient.sol) + +pragma solidity ^0.8.24; + +import {TransientSlot} from "./TransientSlot.sol"; + +/** + * @dev Variant of {ReentrancyGuard} that uses transient storage. + * + * NOTE: This variant only works on networks where EIP-1153 is available. + * + * _Available since v5.1._ + */ +abstract contract ReentrancyGuardTransient { + using TransientSlot for *; + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant REENTRANCY_GUARD_STORAGE = + 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; + + /** + * @dev Unauthorized reentrant call. + */ + error ReentrancyGuardReentrantCall(); + + /** + * @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, REENTRANCY_GUARD_STORAGE.asBoolean().tload() will be false + if (_reentrancyGuardEntered()) { + revert ReentrancyGuardReentrantCall(); + } + + // Any calls to nonReentrant after this point will fail + REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true); + } + + function _nonReentrantAfter() private { + REENTRANCY_GUARD_STORAGE.asBoolean().tstore(false); + } + + /** + * @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 REENTRANCY_GUARD_STORAGE.asBoolean().tload(); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol new file mode 100644 index 0000000..81d713d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.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); + assembly ("memory-safe") { + 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 {toShortStringWithFallback}. + */ + 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 + * {toShortStringWithFallback}. + * + * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/SlotDerivation.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/SlotDerivation.sol new file mode 100644 index 0000000..df23efa --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/SlotDerivation.sol @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol) +// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js. + +pragma solidity ^0.8.20; + +/** + * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots + * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by + * the solidity language / compiler. + * + * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.]. + * + * Example usage: + * ```solidity + * contract Example { + * // Add the library methods + * using StorageSlot for bytes32; + * using SlotDerivation for bytes32; + * + * // Declare a namespace + * string private constant _NAMESPACE = ""; // eg. OpenZeppelin.Slot + * + * function setValueInNamespace(uint256 key, address newValue) internal { + * _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue; + * } + * + * function getValueInNamespace(uint256 key) internal view returns (address) { + * return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value; + * } + * } + * ``` + * + * TIP: Consider using this library along with {StorageSlot}. + * + * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking + * upgrade safety will ignore the slots accessed through this library. + * + * _Available since v5.1._ + */ +library SlotDerivation { + /** + * @dev Derive an ERC-7201 slot from a string (namespace). + */ + function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) { + assembly ("memory-safe") { + mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1)) + slot := and(keccak256(0x00, 0x20), not(0xff)) + } + } + + /** + * @dev Add an offset to a slot to get the n-th element of a structure or an array. + */ + function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) { + unchecked { + return bytes32(uint256(slot) + pos); + } + } + + /** + * @dev Derive the location of the first element in an array from the slot where the length is stored. + */ + function deriveArray(bytes32 slot) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + mstore(0x00, slot) + result := keccak256(0x00, 0x20) + } + } + + /** + * @dev Derive the location of a mapping element from the key. + */ + function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + mstore(0x00, and(key, shr(96, not(0)))) + mstore(0x20, slot) + result := keccak256(0x00, 0x40) + } + } + + /** + * @dev Derive the location of a mapping element from the key. + */ + function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + mstore(0x00, iszero(iszero(key))) + mstore(0x20, slot) + result := keccak256(0x00, 0x40) + } + } + + /** + * @dev Derive the location of a mapping element from the key. + */ + function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + mstore(0x00, key) + mstore(0x20, slot) + result := keccak256(0x00, 0x40) + } + } + + /** + * @dev Derive the location of a mapping element from the key. + */ + function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + mstore(0x00, key) + mstore(0x20, slot) + result := keccak256(0x00, 0x40) + } + } + + /** + * @dev Derive the location of a mapping element from the key. + */ + function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + mstore(0x00, key) + mstore(0x20, slot) + result := keccak256(0x00, 0x40) + } + } + + /** + * @dev Derive the location of a mapping element from the key. + */ + function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + let length := mload(key) + let begin := add(key, 0x20) + let end := add(begin, length) + let cache := mload(end) + mstore(end, slot) + result := keccak256(begin, add(length, 0x20)) + mstore(end, cache) + } + } + + /** + * @dev Derive the location of a mapping element from the key. + */ + function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + let length := mload(key) + let begin := add(key, 0x20) + let end := add(begin, length) + let cache := mload(end) + mstore(end, slot) + result := keccak256(begin, add(length, 0x20)) + mstore(end, cache) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol new file mode 100644 index 0000000..aebb105 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.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 ERC-1967 implementation slot: + * ```solidity + * contract ERC1967 { + * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. + * 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; + * } + * } + * ``` + * + * TIP: Consider using this library along with {SlotDerivation}. + */ +library StorageSlot { + struct AddressSlot { + address value; + } + + struct BooleanSlot { + bool value; + } + + struct Bytes32Slot { + bytes32 value; + } + + struct Uint256Slot { + uint256 value; + } + + struct Int256Slot { + int256 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) { + assembly ("memory-safe") { + r.slot := slot + } + } + + /** + * @dev Returns a `BooleanSlot` with member `value` located at `slot`. + */ + function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { + assembly ("memory-safe") { + r.slot := slot + } + } + + /** + * @dev Returns a `Bytes32Slot` with member `value` located at `slot`. + */ + function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { + assembly ("memory-safe") { + r.slot := slot + } + } + + /** + * @dev Returns a `Uint256Slot` with member `value` located at `slot`. + */ + function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { + assembly ("memory-safe") { + r.slot := slot + } + } + + /** + * @dev Returns a `Int256Slot` with member `value` located at `slot`. + */ + function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) { + assembly ("memory-safe") { + r.slot := slot + } + } + + /** + * @dev Returns a `StringSlot` with member `value` located at `slot`. + */ + function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { + assembly ("memory-safe") { + 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) { + assembly ("memory-safe") { + r.slot := store.slot + } + } + + /** + * @dev Returns a `BytesSlot` with member `value` located at `slot`. + */ + function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { + assembly ("memory-safe") { + 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) { + assembly ("memory-safe") { + r.slot := store.slot + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Strings.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Strings.sol new file mode 100644 index 0000000..a2d934d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Strings.sol @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/Strings.sol) + +pragma solidity ^0.8.20; + +import {Math} from "./math/Math.sol"; +import {SafeCast} from "./math/SafeCast.sol"; +import {SignedMath} from "./math/SignedMath.sol"; + +/** + * @dev String operations. + */ +library Strings { + using SafeCast for *; + + bytes16 private constant HEX_DIGITS = "0123456789abcdef"; + uint8 private constant ADDRESS_LENGTH = 20; + uint256 private constant SPECIAL_CHARS_LOOKUP = + (1 << 0x08) | // backspace + (1 << 0x09) | // tab + (1 << 0x0a) | // newline + (1 << 0x0c) | // form feed + (1 << 0x0d) | // carriage return + (1 << 0x22) | // double quote + (1 << 0x5c); // backslash + + /** + * @dev The `value` string doesn't fit in the specified `length`. + */ + error StringsInsufficientHexLength(uint256 value, uint256 length); + + /** + * @dev The string being parsed contains characters that are not in scope of the given base. + */ + error StringsInvalidChar(); + + /** + * @dev The string being parsed is not a properly formatted address. + */ + error StringsInvalidAddressFormat(); + + /** + * @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; + assembly ("memory-safe") { + ptr := add(add(buffer, 0x20), length) + } + while (true) { + ptr--; + assembly ("memory-safe") { + 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 Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal + * representation, according to EIP-55. + */ + function toChecksumHexString(address addr) internal pure returns (string memory) { + bytes memory buffer = bytes(toHexString(addr)); + + // hash the hex part of buffer (skip length + 2 bytes, length 40) + uint256 hashValue; + assembly ("memory-safe") { + hashValue := shr(96, keccak256(add(buffer, 0x22), 40)) + } + + for (uint256 i = 41; i > 1; --i) { + // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f) + if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) { + // case shift by xoring with 0x20 + buffer[i] ^= 0x20; + } + hashValue >>= 4; + } + return string(buffer); + } + + /** + * @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)); + } + + /** + * @dev Parse a decimal string and returns the value as a `uint256`. + * + * Requirements: + * - The string must be formatted as `[0-9]*` + * - The result must fit into an `uint256` type + */ + function parseUint(string memory input) internal pure returns (uint256) { + return parseUint(input, 0, bytes(input).length); + } + + /** + * @dev Variant of {parseUint-string} that parses a substring of `input` located between position `begin` (included) and + * `end` (excluded). + * + * Requirements: + * - The substring must be formatted as `[0-9]*` + * - The result must fit into an `uint256` type + */ + function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) { + (bool success, uint256 value) = tryParseUint(input, begin, end); + if (!success) revert StringsInvalidChar(); + return value; + } + + /** + * @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character. + * + * NOTE: This function will revert if the result does not fit in a `uint256`. + */ + function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) { + return _tryParseUintUncheckedBounds(input, 0, bytes(input).length); + } + + /** + * @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid + * character. + * + * NOTE: This function will revert if the result does not fit in a `uint256`. + */ + function tryParseUint( + string memory input, + uint256 begin, + uint256 end + ) internal pure returns (bool success, uint256 value) { + if (end > bytes(input).length || begin > end) return (false, 0); + return _tryParseUintUncheckedBounds(input, begin, end); + } + + /** + * @dev Implementation of {tryParseUint-string-uint256-uint256} that does not check bounds. Caller should make sure that + * `begin <= end <= input.length`. Other inputs would result in undefined behavior. + */ + function _tryParseUintUncheckedBounds( + string memory input, + uint256 begin, + uint256 end + ) private pure returns (bool success, uint256 value) { + bytes memory buffer = bytes(input); + + uint256 result = 0; + for (uint256 i = begin; i < end; ++i) { + uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i))); + if (chr > 9) return (false, 0); + result *= 10; + result += chr; + } + return (true, result); + } + + /** + * @dev Parse a decimal string and returns the value as a `int256`. + * + * Requirements: + * - The string must be formatted as `[-+]?[0-9]*` + * - The result must fit in an `int256` type. + */ + function parseInt(string memory input) internal pure returns (int256) { + return parseInt(input, 0, bytes(input).length); + } + + /** + * @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and + * `end` (excluded). + * + * Requirements: + * - The substring must be formatted as `[-+]?[0-9]*` + * - The result must fit in an `int256` type. + */ + function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) { + (bool success, int256 value) = tryParseInt(input, begin, end); + if (!success) revert StringsInvalidChar(); + return value; + } + + /** + * @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if + * the result does not fit in a `int256`. + * + * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`. + */ + function tryParseInt(string memory input) internal pure returns (bool success, int256 value) { + return _tryParseIntUncheckedBounds(input, 0, bytes(input).length); + } + + uint256 private constant ABS_MIN_INT256 = 2 ** 255; + + /** + * @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid + * character or if the result does not fit in a `int256`. + * + * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`. + */ + function tryParseInt( + string memory input, + uint256 begin, + uint256 end + ) internal pure returns (bool success, int256 value) { + if (end > bytes(input).length || begin > end) return (false, 0); + return _tryParseIntUncheckedBounds(input, begin, end); + } + + /** + * @dev Implementation of {tryParseInt-string-uint256-uint256} that does not check bounds. Caller should make sure that + * `begin <= end <= input.length`. Other inputs would result in undefined behavior. + */ + function _tryParseIntUncheckedBounds( + string memory input, + uint256 begin, + uint256 end + ) private pure returns (bool success, int256 value) { + bytes memory buffer = bytes(input); + + // Check presence of a negative sign. + bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty + bool positiveSign = sign == bytes1("+"); + bool negativeSign = sign == bytes1("-"); + uint256 offset = (positiveSign || negativeSign).toUint(); + + (bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end); + + if (absSuccess && absValue < ABS_MIN_INT256) { + return (true, negativeSign ? -int256(absValue) : int256(absValue)); + } else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) { + return (true, type(int256).min); + } else return (false, 0); + } + + /** + * @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as a `uint256`. + * + * Requirements: + * - The string must be formatted as `(0x)?[0-9a-fA-F]*` + * - The result must fit in an `uint256` type. + */ + function parseHexUint(string memory input) internal pure returns (uint256) { + return parseHexUint(input, 0, bytes(input).length); + } + + /** + * @dev Variant of {parseHexUint-string} that parses a substring of `input` located between position `begin` (included) and + * `end` (excluded). + * + * Requirements: + * - The substring must be formatted as `(0x)?[0-9a-fA-F]*` + * - The result must fit in an `uint256` type. + */ + function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) { + (bool success, uint256 value) = tryParseHexUint(input, begin, end); + if (!success) revert StringsInvalidChar(); + return value; + } + + /** + * @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character. + * + * NOTE: This function will revert if the result does not fit in a `uint256`. + */ + function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) { + return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length); + } + + /** + * @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an + * invalid character. + * + * NOTE: This function will revert if the result does not fit in a `uint256`. + */ + function tryParseHexUint( + string memory input, + uint256 begin, + uint256 end + ) internal pure returns (bool success, uint256 value) { + if (end > bytes(input).length || begin > end) return (false, 0); + return _tryParseHexUintUncheckedBounds(input, begin, end); + } + + /** + * @dev Implementation of {tryParseHexUint-string-uint256-uint256} that does not check bounds. Caller should make sure that + * `begin <= end <= input.length`. Other inputs would result in undefined behavior. + */ + function _tryParseHexUintUncheckedBounds( + string memory input, + uint256 begin, + uint256 end + ) private pure returns (bool success, uint256 value) { + bytes memory buffer = bytes(input); + + // skip 0x prefix if present + bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty + uint256 offset = hasPrefix.toUint() * 2; + + uint256 result = 0; + for (uint256 i = begin + offset; i < end; ++i) { + uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i))); + if (chr > 15) return (false, 0); + result *= 16; + unchecked { + // Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check). + // This guarantees that adding a value < 16 will not cause an overflow, hence the unchecked. + result += chr; + } + } + return (true, result); + } + + /** + * @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as an `address`. + * + * Requirements: + * - The string must be formatted as `(0x)?[0-9a-fA-F]{40}` + */ + function parseAddress(string memory input) internal pure returns (address) { + return parseAddress(input, 0, bytes(input).length); + } + + /** + * @dev Variant of {parseAddress-string} that parses a substring of `input` located between position `begin` (included) and + * `end` (excluded). + * + * Requirements: + * - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}` + */ + function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) { + (bool success, address value) = tryParseAddress(input, begin, end); + if (!success) revert StringsInvalidAddressFormat(); + return value; + } + + /** + * @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly + * formatted address. See {parseAddress-string} requirements. + */ + function tryParseAddress(string memory input) internal pure returns (bool success, address value) { + return tryParseAddress(input, 0, bytes(input).length); + } + + /** + * @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly + * formatted address. See {parseAddress-string-uint256-uint256} requirements. + */ + function tryParseAddress( + string memory input, + uint256 begin, + uint256 end + ) internal pure returns (bool success, address value) { + if (end > bytes(input).length || begin > end) return (false, address(0)); + + bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty + uint256 expectedLength = 40 + hasPrefix.toUint() * 2; + + // check that input is the correct length + if (end - begin == expectedLength) { + // length guarantees that this does not overflow, and value is at most type(uint160).max + (bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end); + return (s, address(uint160(v))); + } else { + return (false, address(0)); + } + } + + function _tryParseChr(bytes1 chr) private pure returns (uint8) { + uint8 value = uint8(chr); + + // Try to parse `chr`: + // - Case 1: [0-9] + // - Case 2: [a-f] + // - Case 3: [A-F] + // - otherwise not supported + unchecked { + if (value > 47 && value < 58) value -= 48; + else if (value > 96 && value < 103) value -= 87; + else if (value > 64 && value < 71) value -= 55; + else return type(uint8).max; + } + + return value; + } + + /** + * @dev Escape special characters in JSON strings. This can be useful to prevent JSON injection in NFT metadata. + * + * WARNING: This function should only be used in double quoted JSON strings. Single quotes are not escaped. + * + * NOTE: This function escapes all unicode characters, and not just the ones in ranges defined in section 2.5 of + * RFC-4627 (U+0000 to U+001F, U+0022 and U+005C). ECMAScript's `JSON.parse` does recover escaped unicode + * characters that are not in this range, but other tooling may provide different results. + */ + function escapeJSON(string memory input) internal pure returns (string memory) { + bytes memory buffer = bytes(input); + bytes memory output = new bytes(2 * buffer.length); // worst case scenario + uint256 outputLength = 0; + + for (uint256 i; i < buffer.length; ++i) { + bytes1 char = bytes1(_unsafeReadBytesOffset(buffer, i)); + if (((SPECIAL_CHARS_LOOKUP & (1 << uint8(char))) != 0)) { + output[outputLength++] = "\\"; + if (char == 0x08) output[outputLength++] = "b"; + else if (char == 0x09) output[outputLength++] = "t"; + else if (char == 0x0a) output[outputLength++] = "n"; + else if (char == 0x0c) output[outputLength++] = "f"; + else if (char == 0x0d) output[outputLength++] = "r"; + else if (char == 0x5c) output[outputLength++] = "\\"; + else if (char == 0x22) { + // solhint-disable-next-line quotes + output[outputLength++] = '"'; + } + } else { + output[outputLength++] = char; + } + } + // write the actual length and deallocate unused memory + assembly ("memory-safe") { + mstore(output, outputLength) + mstore(0x40, add(output, shl(5, shr(5, add(outputLength, 63))))) + } + + return string(output); + } + + /** + * @dev Reads a bytes32 from a bytes array without bounds checking. + * + * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the + * assembly block as such would prevent some optimizations. + */ + function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) { + // This is not memory safe in the general case, but all calls to this private function are within bounds. + assembly ("memory-safe") { + value := mload(add(add(buffer, 0x20), offset)) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/TransientSlot.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/TransientSlot.sol new file mode 100644 index 0000000..f0caea1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/TransientSlot.sol @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (utils/TransientSlot.sol) +// This file was procedurally generated from scripts/generate/templates/TransientSlot.js. + +pragma solidity ^0.8.24; + +/** + * @dev Library for reading and writing value-types to specific transient storage slots. + * + * Transient slots are often used to store temporary values that are removed after the current transaction. + * This library helps with reading and writing to such slots without the need for inline assembly. + * + * * Example reading and writing values using transient storage: + * ```solidity + * contract Lock { + * using TransientSlot for *; + * + * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. + * bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542; + * + * modifier locked() { + * require(!_LOCK_SLOT.asBoolean().tload()); + * + * _LOCK_SLOT.asBoolean().tstore(true); + * _; + * _LOCK_SLOT.asBoolean().tstore(false); + * } + * } + * ``` + * + * TIP: Consider using this library along with {SlotDerivation}. + */ +library TransientSlot { + /** + * @dev UDVT that represents a slot holding an address. + */ + type AddressSlot is bytes32; + + /** + * @dev Cast an arbitrary slot to a AddressSlot. + */ + function asAddress(bytes32 slot) internal pure returns (AddressSlot) { + return AddressSlot.wrap(slot); + } + + /** + * @dev UDVT that represents a slot holding a bool. + */ + type BooleanSlot is bytes32; + + /** + * @dev Cast an arbitrary slot to a BooleanSlot. + */ + function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) { + return BooleanSlot.wrap(slot); + } + + /** + * @dev UDVT that represents a slot holding a bytes32. + */ + type Bytes32Slot is bytes32; + + /** + * @dev Cast an arbitrary slot to a Bytes32Slot. + */ + function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) { + return Bytes32Slot.wrap(slot); + } + + /** + * @dev UDVT that represents a slot holding a uint256. + */ + type Uint256Slot is bytes32; + + /** + * @dev Cast an arbitrary slot to a Uint256Slot. + */ + function asUint256(bytes32 slot) internal pure returns (Uint256Slot) { + return Uint256Slot.wrap(slot); + } + + /** + * @dev UDVT that represents a slot holding a int256. + */ + type Int256Slot is bytes32; + + /** + * @dev Cast an arbitrary slot to a Int256Slot. + */ + function asInt256(bytes32 slot) internal pure returns (Int256Slot) { + return Int256Slot.wrap(slot); + } + + /** + * @dev Load the value held at location `slot` in transient storage. + */ + function tload(AddressSlot slot) internal view returns (address value) { + assembly ("memory-safe") { + value := tload(slot) + } + } + + /** + * @dev Store `value` at location `slot` in transient storage. + */ + function tstore(AddressSlot slot, address value) internal { + assembly ("memory-safe") { + tstore(slot, value) + } + } + + /** + * @dev Load the value held at location `slot` in transient storage. + */ + function tload(BooleanSlot slot) internal view returns (bool value) { + assembly ("memory-safe") { + value := tload(slot) + } + } + + /** + * @dev Store `value` at location `slot` in transient storage. + */ + function tstore(BooleanSlot slot, bool value) internal { + assembly ("memory-safe") { + tstore(slot, value) + } + } + + /** + * @dev Load the value held at location `slot` in transient storage. + */ + function tload(Bytes32Slot slot) internal view returns (bytes32 value) { + assembly ("memory-safe") { + value := tload(slot) + } + } + + /** + * @dev Store `value` at location `slot` in transient storage. + */ + function tstore(Bytes32Slot slot, bytes32 value) internal { + assembly ("memory-safe") { + tstore(slot, value) + } + } + + /** + * @dev Load the value held at location `slot` in transient storage. + */ + function tload(Uint256Slot slot) internal view returns (uint256 value) { + assembly ("memory-safe") { + value := tload(slot) + } + } + + /** + * @dev Store `value` at location `slot` in transient storage. + */ + function tstore(Uint256Slot slot, uint256 value) internal { + assembly ("memory-safe") { + tstore(slot, value) + } + } + + /** + * @dev Load the value held at location `slot` in transient storage. + */ + function tload(Int256Slot slot) internal view returns (int256 value) { + assembly ("memory-safe") { + value := tload(slot) + } + } + + /** + * @dev Store `value` at location `slot` in transient storage. + */ + function tstore(Int256Slot slot, int256 value) internal { + assembly ("memory-safe") { + tstore(slot, value) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol new file mode 100644 index 0000000..6493f56 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.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 recovered, RecoverError err, bytes32 errArg) { + 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. + assembly ("memory-safe") { + 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[ERC-2098 short signatures] + */ + function tryRecover( + bytes32 hash, + bytes32 r, + bytes32 vs + ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) { + 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 recovered, RecoverError err, bytes32 errArg) { + // 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol new file mode 100644 index 0000000..6400cbc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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; + // slither-disable-next-line constable-states + string private _nameFallback; + // slither-disable-next-line constable-states + 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); + } + + /// @inheritdoc IERC5267 + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/Hashes.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/Hashes.sol new file mode 100644 index 0000000..48c9bbe --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/Hashes.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/Hashes.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Library of standard hash functions. + * + * _Available since v5.1._ + */ +library Hashes { + /** + * @dev Commutative Keccak256 hash of a sorted pair of bytes32. Frequently used when working with merkle proofs. + * + * NOTE: Equivalent to the `standardNodeHash` in our https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. + */ + function commutativeKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32) { + return a < b ? efficientKeccak256(a, b) : efficientKeccak256(b, a); + } + + /** + * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory. + */ + function efficientKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32 value) { + assembly ("memory-safe") { + mstore(0x00, a) + mstore(0x20, b) + value := keccak256(0x00, 0x40) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol new file mode 100644 index 0000000..19b09e2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol @@ -0,0 +1,514 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/MerkleProof.sol) +// This file was procedurally generated from scripts/generate/templates/MerkleProof.js. + +pragma solidity ^0.8.20; + +import {Hashes} from "./Hashes.sol"; + +/** + * @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. + * + * IMPORTANT: Consider memory side-effects when using custom hashing functions + * that access memory in an unsafe way. + * + * NOTE: This library supports proof verification for merkle trees built using + * custom _commutative_ hashing functions (i.e. `H(a, b) == H(b, a)`). Proving + * leaf inclusion in trees built using non-commutative hashing functions requires + * additional logic that is not supported by this library. + */ +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. + * + * This version handles proofs in memory with the default hashing function. + */ + function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { + return processProof(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 leaves & pre-images are assumed to be sorted. + * + * This version handles proofs in memory with the default hashing function. + */ + function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]); + } + return computedHash; + } + + /** + * @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. + * + * This version handles proofs in memory with a custom hashing function. + */ + function verify( + bytes32[] memory proof, + bytes32 root, + bytes32 leaf, + function(bytes32, bytes32) view returns (bytes32) hasher + ) internal view returns (bool) { + return processProof(proof, leaf, hasher) == 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 leaves & pre-images are assumed to be sorted. + * + * This version handles proofs in memory with a custom hashing function. + */ + function processProof( + bytes32[] memory proof, + bytes32 leaf, + function(bytes32, bytes32) view returns (bytes32) hasher + ) internal view returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + computedHash = hasher(computedHash, proof[i]); + } + return computedHash; + } + + /** + * @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. + * + * This version handles proofs in calldata with the default hashing function. + */ + 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 leaves & pre-images are assumed to be sorted. + * + * This version handles proofs in calldata with the default hashing function. + */ + function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]); + } + return computedHash; + } + + /** + * @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. + * + * This version handles proofs in calldata with a custom hashing function. + */ + function verifyCalldata( + bytes32[] calldata proof, + bytes32 root, + bytes32 leaf, + function(bytes32, bytes32) view returns (bytes32) hasher + ) internal view returns (bool) { + return processProofCalldata(proof, leaf, hasher) == 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 leaves & pre-images are assumed to be sorted. + * + * This version handles proofs in calldata with a custom hashing function. + */ + function processProofCalldata( + bytes32[] calldata proof, + bytes32 leaf, + function(bytes32, bytes32) view returns (bytes32) hasher + ) internal view returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + computedHash = hasher(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}. + * + * This version handles multiproofs in memory with the default hashing function. + * + * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. + * + * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`. + * The `leaves` must be validated independently. See {processMultiProof}. + */ + function multiProofVerify( + bytes32[] memory proof, + bool[] memory proofFlags, + bytes32 root, + bytes32[] memory leaves + ) internal pure returns (bool) { + return processMultiProof(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. + * + * This version handles multiproofs in memory with the default hashing function. + * + * 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). + * + * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op, + * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not + * validating the leaves elsewhere. + */ + 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 proofFlagsLen = proofFlags.length; + + // Check proof validity. + if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen); + 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 < proofFlagsLen; i++) { + bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; + bytes32 b = proofFlags[i] + ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) + : proof[proofPos++]; + hashes[i] = Hashes.commutativeKeccak256(a, b); + } + + if (proofFlagsLen > 0) { + if (proofPos != proof.length) { + revert MerkleProofInvalidMultiproof(); + } + unchecked { + return hashes[proofFlagsLen - 1]; + } + } else if (leavesLen > 0) { + return leaves[0]; + } else { + return proof[0]; + } + } + + /** + * @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}. + * + * This version handles multiproofs in memory with a custom hashing function. + * + * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. + * + * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`. + * The `leaves` must be validated independently. See {processMultiProof}. + */ + function multiProofVerify( + bytes32[] memory proof, + bool[] memory proofFlags, + bytes32 root, + bytes32[] memory leaves, + function(bytes32, bytes32) view returns (bytes32) hasher + ) internal view returns (bool) { + return processMultiProof(proof, proofFlags, leaves, hasher) == 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. + * + * This version handles multiproofs in memory with a custom hashing function. + * + * 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). + * + * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op, + * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not + * validating the leaves elsewhere. + */ + function processMultiProof( + bytes32[] memory proof, + bool[] memory proofFlags, + bytes32[] memory leaves, + function(bytes32, bytes32) view returns (bytes32) hasher + ) internal view 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 proofFlagsLen = proofFlags.length; + + // Check proof validity. + if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen); + 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 < proofFlagsLen; i++) { + bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; + bytes32 b = proofFlags[i] + ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) + : proof[proofPos++]; + hashes[i] = hasher(a, b); + } + + if (proofFlagsLen > 0) { + if (proofPos != proof.length) { + revert MerkleProofInvalidMultiproof(); + } + unchecked { + return hashes[proofFlagsLen - 1]; + } + } else if (leavesLen > 0) { + return leaves[0]; + } else { + return proof[0]; + } + } + + /** + * @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}. + * + * This version handles multiproofs in calldata with the default hashing function. + * + * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. + * + * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`. + * The `leaves` must be validated independently. See {processMultiProofCalldata}. + */ + 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. + * + * This version handles multiproofs in calldata with the default hashing function. + * + * 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). + * + * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op, + * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not + * validating the leaves elsewhere. + */ + 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 proofFlagsLen = proofFlags.length; + + // Check proof validity. + if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen); + 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 < proofFlagsLen; i++) { + bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; + bytes32 b = proofFlags[i] + ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) + : proof[proofPos++]; + hashes[i] = Hashes.commutativeKeccak256(a, b); + } + + if (proofFlagsLen > 0) { + if (proofPos != proof.length) { + revert MerkleProofInvalidMultiproof(); + } + unchecked { + return hashes[proofFlagsLen - 1]; + } + } else if (leavesLen > 0) { + return leaves[0]; + } else { + return proof[0]; + } + } + + /** + * @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}. + * + * This version handles multiproofs in calldata with a custom hashing function. + * + * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. + * + * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`. + * The `leaves` must be validated independently. See {processMultiProofCalldata}. + */ + function multiProofVerifyCalldata( + bytes32[] calldata proof, + bool[] calldata proofFlags, + bytes32 root, + bytes32[] memory leaves, + function(bytes32, bytes32) view returns (bytes32) hasher + ) internal view returns (bool) { + return processMultiProofCalldata(proof, proofFlags, leaves, hasher) == 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. + * + * This version handles multiproofs in calldata with a custom hashing function. + * + * 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). + * + * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op, + * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not + * validating the leaves elsewhere. + */ + function processMultiProofCalldata( + bytes32[] calldata proof, + bool[] calldata proofFlags, + bytes32[] memory leaves, + function(bytes32, bytes32) view returns (bytes32) hasher + ) internal view 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 proofFlagsLen = proofFlags.length; + + // Check proof validity. + if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen); + 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 < proofFlagsLen; i++) { + bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; + bytes32 b = proofFlags[i] + ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) + : proof[proofPos++]; + hashes[i] = hasher(a, b); + } + + if (proofFlagsLen > 0) { + if (proofPos != proof.length) { + revert MerkleProofInvalidMultiproof(); + } + unchecked { + return hashes[proofFlagsLen - 1]; + } + } else if (leavesLen > 0) { + return leaves[0]; + } else { + return proof[0]; + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol new file mode 100644 index 0000000..37e9239 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.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[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] + * specifications. + */ +library MessageHashUtils { + /** + * @dev Returns the keccak256 digest of an ERC-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://ethereum.org/en/developers/docs/apis/json-rpc/#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) { + assembly ("memory-safe") { + 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 ERC-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://ethereum.org/en/developers/docs/apis/json-rpc/#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 ERC-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 Variant of {toDataWithIntendedValidatorHash-address-bytes} optimized for cases where `data` is a bytes32. + */ + function toDataWithIntendedValidatorHash( + address validator, + bytes32 messageHash + ) internal pure returns (bytes32 digest) { + assembly ("memory-safe") { + mstore(0x00, hex"19_00") + mstore(0x02, shl(96, validator)) + mstore(0x16, messageHash) + digest := keccak256(0x00, 0x36) + } + } + + /** + * @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-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) { + assembly ("memory-safe") { + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/P256.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/P256.sol new file mode 100644 index 0000000..81d79ad --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/P256.sol @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/P256.sol) +pragma solidity ^0.8.20; + +import {Math} from "../math/Math.sol"; +import {Errors} from "../Errors.sol"; + +/** + * @dev Implementation of secp256r1 verification and recovery functions. + * + * The secp256r1 curve (also known as P256) is a NIST standard curve with wide support in modern devices + * and cryptographic standards. Some notable examples include Apple's Secure Enclave and Android's Keystore + * as well as authentication protocols like FIDO2. + * + * Based on the original https://github.com/itsobvioustech/aa-passkeys-wallet/blob/d3d423f28a4d8dfcb203c7fa0c47f42592a7378e/src/Secp256r1.sol[implementation of itsobvioustech] (GNU General Public License v3.0). + * Heavily inspired in https://github.com/maxrobot/elliptic-solidity/blob/c4bb1b6e8ae89534d8db3a6b3a6b52219100520f/contracts/Secp256r1.sol[maxrobot] and + * https://github.com/tdrerup/elliptic-curve-solidity/blob/59a9c25957d4d190eff53b6610731d81a077a15e/contracts/curves/EllipticCurve.sol[tdrerup] implementations. + * + * _Available since v5.1._ + */ +library P256 { + struct JPoint { + uint256 x; + uint256 y; + uint256 z; + } + + /// @dev Generator (x component) + uint256 internal constant GX = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296; + /// @dev Generator (y component) + uint256 internal constant GY = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5; + /// @dev P (size of the field) + uint256 internal constant P = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF; + /// @dev N (order of G) + uint256 internal constant N = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551; + /// @dev A parameter of the weierstrass equation + uint256 internal constant A = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC; + /// @dev B parameter of the weierstrass equation + uint256 internal constant B = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B; + + /// @dev (P + 1) / 4. Useful to compute sqrt + uint256 private constant P1DIV4 = 0x3fffffffc0000000400000000000000000000000400000000000000000000000; + + /// @dev N/2 for excluding higher order `s` values + uint256 private constant HALF_N = 0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8; + + /** + * @dev Verifies a secp256r1 signature using the RIP-7212 precompile and falls back to the Solidity implementation + * if the precompile is not available. This version should work on all chains, but requires the deployment of more + * bytecode. + * + * @param h - hashed message + * @param r - signature half R + * @param s - signature half S + * @param qx - public key coordinate X + * @param qy - public key coordinate Y + * + * IMPORTANT: This function disallows signatures where the `s` value is above `N/2` to prevent malleability. + * To flip the `s` value, compute `s = N - s`. + */ + function verify(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) internal view returns (bool) { + (bool valid, bool supported) = _tryVerifyNative(h, r, s, qx, qy); + return supported ? valid : verifySolidity(h, r, s, qx, qy); + } + + /** + * @dev Same as {verify}, but it will revert if the required precompile is not available. + * + * Make sure any logic (code or precompile) deployed at that address is the expected one, + * otherwise the returned value may be misinterpreted as a positive boolean. + */ + function verifyNative(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) internal view returns (bool) { + (bool valid, bool supported) = _tryVerifyNative(h, r, s, qx, qy); + if (supported) { + return valid; + } else { + revert Errors.MissingPrecompile(address(0x100)); + } + } + + /** + * @dev Same as {verify}, but it will return false if the required precompile is not available. + */ + function _tryVerifyNative( + bytes32 h, + bytes32 r, + bytes32 s, + bytes32 qx, + bytes32 qy + ) private view returns (bool valid, bool supported) { + if (!_isProperSignature(r, s) || !isValidPublicKey(qx, qy)) { + return (false, true); // signature is invalid, and its not because the precompile is missing + } else if (_rip7212(h, r, s, qx, qy)) { + return (true, true); // precompile is present, signature is valid + } else if ( + // Given precompiles have no bytecode (i.e. `address(0x100).code.length == 0`), we use + // a valid signature with small `r` and `s` values to check if the precompile is present. Taken from + // https://github.com/C2SP/wycheproof/blob/4672ff74d68766e7785c2cac4c597effccef2c5c/testvectors/ecdsa_secp256r1_sha256_p1363_test.json#L1173-L1204 + _rip7212( + 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023, // sha256("123400") + 0x0000000000000000000000000000000000000000000000000000000000000005, + 0x0000000000000000000000000000000000000000000000000000000000000001, + 0xa71af64de5126a4a4e02b7922d66ce9415ce88a4c9d25514d91082c8725ac957, + 0x5d47723c8fbe580bb369fec9c2665d8e30a435b9932645482e7c9f11e872296b + ) + ) { + return (false, true); // precompile is present, signature is invalid + } else { + return (false, false); // precompile is absent + } + } + + /** + * @dev Low level helper for {_tryVerifyNative}. Calls the precompile and checks if there is a return value. + */ + function _rip7212(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) private view returns (bool isValid) { + assembly ("memory-safe") { + // Use the free memory pointer without updating it at the end of the function + let ptr := mload(0x40) + mstore(ptr, h) + mstore(add(ptr, 0x20), r) + mstore(add(ptr, 0x40), s) + mstore(add(ptr, 0x60), qx) + mstore(add(ptr, 0x80), qy) + // RIP-7212 precompiles return empty bytes when an invalid signature is passed, making it impossible + // to distinguish the presence of the precompile. Custom precompile implementations may decide to + // return `bytes32(0)` (i.e. false) without developers noticing, so we decide to evaluate the return value + // without expanding memory using scratch space. + mstore(0x00, 0) // zero out scratch space in case the precompile doesn't return anything + if iszero(staticcall(gas(), 0x100, ptr, 0xa0, 0x00, 0x20)) { + invalid() + } + isValid := mload(0x00) + } + } + + /** + * @dev Same as {verify}, but only the Solidity implementation is used. + */ + function verifySolidity(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) internal view returns (bool) { + if (!_isProperSignature(r, s) || !isValidPublicKey(qx, qy)) { + return false; + } + + JPoint[16] memory points = _preComputeJacobianPoints(uint256(qx), uint256(qy)); + uint256 w = Math.invModPrime(uint256(s), N); + uint256 u1 = mulmod(uint256(h), w, N); + uint256 u2 = mulmod(uint256(r), w, N); + (uint256 x, ) = _jMultShamir(points, u1, u2); + return ((x % N) == uint256(r)); + } + + /** + * @dev Public key recovery + * + * @param h - hashed message + * @param v - signature recovery param + * @param r - signature half R + * @param s - signature half S + * + * IMPORTANT: This function disallows signatures where the `s` value is above `N/2` to prevent malleability. + * To flip the `s` value, compute `s = N - s` and `v = 1 - v` if (`v = 0 | 1`). + */ + function recovery(bytes32 h, uint8 v, bytes32 r, bytes32 s) internal view returns (bytes32 x, bytes32 y) { + if (!_isProperSignature(r, s) || v > 1) { + return (0, 0); + } + + uint256 p = P; // cache P on the stack + uint256 rx = uint256(r); + uint256 ry2 = addmod(mulmod(addmod(mulmod(rx, rx, p), A, p), rx, p), B, p); // weierstrass equation y² = x³ + a.x + b + uint256 ry = Math.modExp(ry2, P1DIV4, p); // This formula for sqrt work because P ≡ 3 (mod 4) + if (mulmod(ry, ry, p) != ry2) return (0, 0); // Sanity check + if (ry % 2 != v) ry = p - ry; + + JPoint[16] memory points = _preComputeJacobianPoints(rx, ry); + uint256 w = Math.invModPrime(uint256(r), N); + uint256 u1 = mulmod(N - (uint256(h) % N), w, N); + uint256 u2 = mulmod(uint256(s), w, N); + (uint256 xU, uint256 yU) = _jMultShamir(points, u1, u2); + return (bytes32(xU), bytes32(yU)); + } + + /** + * @dev Checks if (x, y) are valid coordinates of a point on the curve. + * In particular this function checks that x < P and y < P. + */ + function isValidPublicKey(bytes32 x, bytes32 y) internal pure returns (bool result) { + assembly ("memory-safe") { + let p := P + let lhs := mulmod(y, y, p) // y^2 + let rhs := addmod(mulmod(addmod(mulmod(x, x, p), A, p), x, p), B, p) // ((x^2 + a) * x) + b = x^3 + ax + b + result := and(and(lt(x, p), lt(y, p)), eq(lhs, rhs)) // Should conform with the Weierstrass equation + } + } + + /** + * @dev Checks if (r, s) is a proper signature. + * In particular, this checks that `s` is in the "lower-range", making the signature non-malleable. + */ + function _isProperSignature(bytes32 r, bytes32 s) private pure returns (bool) { + return uint256(r) > 0 && uint256(r) < N && uint256(s) > 0 && uint256(s) <= HALF_N; + } + + /** + * @dev Reduce from jacobian to affine coordinates + * @param jx - jacobian coordinate x + * @param jy - jacobian coordinate y + * @param jz - jacobian coordinate z + * @return ax - affine coordinate x + * @return ay - affine coordinate y + */ + function _affineFromJacobian(uint256 jx, uint256 jy, uint256 jz) private view returns (uint256 ax, uint256 ay) { + if (jz == 0) return (0, 0); + uint256 p = P; // cache P on the stack + uint256 zinv = Math.invModPrime(jz, p); + assembly ("memory-safe") { + let zzinv := mulmod(zinv, zinv, p) + ax := mulmod(jx, zzinv, p) + ay := mulmod(jy, mulmod(zzinv, zinv, p), p) + } + } + + /** + * @dev Point addition on the jacobian coordinates + * Reference: https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-1998-cmo-2 + * + * Note that: + * + * - `addition-add-1998-cmo-2` doesn't support identical input points. This version is modified to use + * the `h` and `r` values computed by `addition-add-1998-cmo-2` to detect identical inputs, and fallback to + * `doubling-dbl-1998-cmo-2` if needed. + * - if one of the points is at infinity (i.e. `z=0`), the result is undefined. + */ + function _jAdd( + JPoint memory p1, + uint256 x2, + uint256 y2, + uint256 z2 + ) private pure returns (uint256 rx, uint256 ry, uint256 rz) { + assembly ("memory-safe") { + let p := P + let z1 := mload(add(p1, 0x40)) + let zz1 := mulmod(z1, z1, p) // zz1 = z1² + let s1 := mulmod(mload(add(p1, 0x20)), mulmod(mulmod(z2, z2, p), z2, p), p) // s1 = y1*z2³ + let r := addmod(mulmod(y2, mulmod(zz1, z1, p), p), sub(p, s1), p) // r = s2-s1 = y2*z1³-s1 = y2*z1³-y1*z2³ + let u1 := mulmod(mload(p1), mulmod(z2, z2, p), p) // u1 = x1*z2² + let h := addmod(mulmod(x2, zz1, p), sub(p, u1), p) // h = u2-u1 = x2*z1²-u1 = x2*z1²-x1*z2² + + // detect edge cases where inputs are identical + switch and(iszero(r), iszero(h)) + // case 0: points are different + case 0 { + let hh := mulmod(h, h, p) // h² + + // x' = r²-h³-2*u1*h² + rx := addmod( + addmod(mulmod(r, r, p), sub(p, mulmod(h, hh, p)), p), + sub(p, mulmod(2, mulmod(u1, hh, p), p)), + p + ) + // y' = r*(u1*h²-x')-s1*h³ + ry := addmod( + mulmod(r, addmod(mulmod(u1, hh, p), sub(p, rx), p), p), + sub(p, mulmod(s1, mulmod(h, hh, p), p)), + p + ) + // z' = h*z1*z2 + rz := mulmod(h, mulmod(z1, z2, p), p) + } + // case 1: points are equal + case 1 { + let x := x2 + let y := y2 + let z := z2 + let yy := mulmod(y, y, p) + let zz := mulmod(z, z, p) + let m := addmod(mulmod(3, mulmod(x, x, p), p), mulmod(A, mulmod(zz, zz, p), p), p) // m = 3*x²+a*z⁴ + let s := mulmod(4, mulmod(x, yy, p), p) // s = 4*x*y² + + // x' = t = m²-2*s + rx := addmod(mulmod(m, m, p), sub(p, mulmod(2, s, p)), p) + + // y' = m*(s-t)-8*y⁴ = m*(s-x')-8*y⁴ + // cut the computation to avoid stack too deep + let rytmp1 := sub(p, mulmod(8, mulmod(yy, yy, p), p)) // -8*y⁴ + let rytmp2 := addmod(s, sub(p, rx), p) // s-x' + ry := addmod(mulmod(m, rytmp2, p), rytmp1, p) // m*(s-x')-8*y⁴ + + // z' = 2*y*z + rz := mulmod(2, mulmod(y, z, p), p) + } + } + } + + /** + * @dev Point doubling on the jacobian coordinates + * Reference: https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2 + */ + function _jDouble(uint256 x, uint256 y, uint256 z) private pure returns (uint256 rx, uint256 ry, uint256 rz) { + assembly ("memory-safe") { + let p := P + let yy := mulmod(y, y, p) + let zz := mulmod(z, z, p) + let m := addmod(mulmod(3, mulmod(x, x, p), p), mulmod(A, mulmod(zz, zz, p), p), p) // m = 3*x²+a*z⁴ + let s := mulmod(4, mulmod(x, yy, p), p) // s = 4*x*y² + + // x' = t = m²-2*s + rx := addmod(mulmod(m, m, p), sub(p, mulmod(2, s, p)), p) + // y' = m*(s-t)-8*y⁴ = m*(s-x')-8*y⁴ + ry := addmod(mulmod(m, addmod(s, sub(p, rx), p), p), sub(p, mulmod(8, mulmod(yy, yy, p), p)), p) + // z' = 2*y*z + rz := mulmod(2, mulmod(y, z, p), p) + } + } + + /** + * @dev Compute G·u1 + P·u2 using the precomputed points for G and P (see {_preComputeJacobianPoints}). + * + * Uses Strauss Shamir trick for EC multiplication + * https://stackoverflow.com/questions/50993471/ec-scalar-multiplication-with-strauss-shamir-method + * + * We optimize this for 2 bits at a time rather than a single bit. The individual points for a single pass are + * precomputed. Overall this reduces the number of additions while keeping the same number of + * doublings + */ + function _jMultShamir( + JPoint[16] memory points, + uint256 u1, + uint256 u2 + ) private view returns (uint256 rx, uint256 ry) { + uint256 x = 0; + uint256 y = 0; + uint256 z = 0; + unchecked { + for (uint256 i = 0; i < 128; ++i) { + if (z > 0) { + (x, y, z) = _jDouble(x, y, z); + (x, y, z) = _jDouble(x, y, z); + } + // Read 2 bits of u1, and 2 bits of u2. Combining the two gives the lookup index in the table. + uint256 pos = ((u1 >> 252) & 0xc) | ((u2 >> 254) & 0x3); + // Points that have z = 0 are points at infinity. They are the additive 0 of the group + // - if the lookup point is a 0, we can skip it + // - otherwise: + // - if the current point (x, y, z) is 0, we use the lookup point as our new value (0+P=P) + // - if the current point (x, y, z) is not 0, both points are valid and we can use `_jAdd` + if (points[pos].z != 0) { + if (z == 0) { + (x, y, z) = (points[pos].x, points[pos].y, points[pos].z); + } else { + (x, y, z) = _jAdd(points[pos], x, y, z); + } + } + u1 <<= 2; + u2 <<= 2; + } + } + return _affineFromJacobian(x, y, z); + } + + /** + * @dev Precompute a matrice of useful jacobian points associated with a given P. This can be seen as a 4x4 matrix + * that contains combination of P and G (generator) up to 3 times each. See the table below: + * + * ┌────┬─────────────────────┐ + * │ i │ 0 1 2 3 │ + * ├────┼─────────────────────┤ + * │ 0 │ 0 p 2p 3p │ + * │ 4 │ g g+p g+2p g+3p │ + * │ 8 │ 2g 2g+p 2g+2p 2g+3p │ + * │ 12 │ 3g 3g+p 3g+2p 3g+3p │ + * └────┴─────────────────────┘ + * + * Note that `_jAdd` (and thus `_jAddPoint`) does not handle the case where one of the inputs is a point at + * infinity (z = 0). However, we know that since `N ≡ 1 mod 2` and `N ≡ 1 mod 3`, there is no point P such that + * 2P = 0 or 3P = 0. This guarantees that g, 2g, 3g, p, 2p, 3p are all non-zero, and that all `_jAddPoint` calls + * have valid inputs. + */ + function _preComputeJacobianPoints(uint256 px, uint256 py) private pure returns (JPoint[16] memory points) { + points[0x00] = JPoint(0, 0, 0); // 0,0 + points[0x01] = JPoint(px, py, 1); // 1,0 (p) + points[0x04] = JPoint(GX, GY, 1); // 0,1 (g) + points[0x02] = _jDoublePoint(points[0x01]); // 2,0 (2p) + points[0x08] = _jDoublePoint(points[0x04]); // 0,2 (2g) + points[0x03] = _jAddPoint(points[0x01], points[0x02]); // 3,0 (p+2p = 3p) + points[0x05] = _jAddPoint(points[0x01], points[0x04]); // 1,1 (p+g) + points[0x06] = _jAddPoint(points[0x02], points[0x04]); // 2,1 (2p+g) + points[0x07] = _jAddPoint(points[0x03], points[0x04]); // 3,1 (3p+g) + points[0x09] = _jAddPoint(points[0x01], points[0x08]); // 1,2 (p+2g) + points[0x0a] = _jAddPoint(points[0x02], points[0x08]); // 2,2 (2p+2g) + points[0x0b] = _jAddPoint(points[0x03], points[0x08]); // 3,2 (3p+2g) + points[0x0c] = _jAddPoint(points[0x04], points[0x08]); // 0,3 (g+2g = 3g) + points[0x0d] = _jAddPoint(points[0x01], points[0x0c]); // 1,3 (p+3g) + points[0x0e] = _jAddPoint(points[0x02], points[0x0c]); // 2,3 (2p+3g) + points[0x0f] = _jAddPoint(points[0x03], points[0x0c]); // 3,3 (3p+3g) + } + + function _jAddPoint(JPoint memory p1, JPoint memory p2) private pure returns (JPoint memory) { + (uint256 x, uint256 y, uint256 z) = _jAdd(p1, p2.x, p2.y, p2.z); + return JPoint(x, y, z); + } + + function _jDoublePoint(JPoint memory p) private pure returns (JPoint memory) { + (uint256 x, uint256 y, uint256 z) = _jDouble(p.x, p.y, p.z); + return JPoint(x, y, z); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/README.adoc new file mode 100644 index 0000000..37a9824 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/README.adoc @@ -0,0 +1,67 @@ += Cryptography + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/utils/cryptography + +A collection of contracts and libraries that implement various signature validation schemes and cryptographic primitives. These utilities enable secure authentication, multisignature operations, and advanced cryptographic operations in smart contracts. + + * {ECDSA}, {MessageHashUtils}: Libraries for interacting with ECDSA signatures. + * {P256}: Library for verifying and recovering public keys from secp256r1 signatures. + * {RSA}: Library with RSA PKCS#1 v1.5 signature verification utilities. + * {SignatureChecker}: A library helper to support regular ECDSA from EOAs as well as ERC-1271 signatures for smart contracts. + * {Hashes}: Commonly used hash functions. + * {MerkleProof}: Functions for verifying https://en.wikipedia.org/wiki/Merkle_tree[Merkle Tree] proofs. + * {EIP712}: Contract with functions to allow processing signed typed structure data according to https://eips.ethereum.org/EIPS/eip-712[EIP-712]. + * {ERC7739Utils}: Utilities library that implements a defensive rehashing mechanism to prevent replayability of smart contract signatures based on ERC-7739. + * {AbstractSigner}: Abstract contract for internal signature validation in smart contracts. + * {ERC7739}: An abstract contract to validate signatures following the rehashing scheme from {ERC7739Utils}. + * {SignerECDSA}, {SignerP256}, {SignerRSA}: Implementations of an {AbstractSigner} with specific signature validation algorithms. + * {SignerERC7702}: Implementation of {AbstractSigner} that validates signatures using the contract's own address as the signer, useful for delegated accounts following EIP-7702. + * {SignerERC7913}, {MultiSignerERC7913}, {MultiSignerERC7913Weighted}: Implementations of {AbstractSigner} that validate signatures based on ERC-7913. Including a simple and weighted multisignature scheme. + * {ERC7913P256Verifier}, {ERC7913RSAVerifier}: Ready to use ERC-7913 signature verifiers for P256 and RSA keys. + +== Utils + +{{ECDSA}} + +{{MessageHashUtils}} + +{{P256}} + +{{RSA}} + +{{SignatureChecker}} + +{{Hashes}} + +{{MerkleProof}} + +{{EIP712}} + +{{ERC7739Utils}} + +== Abstract Signers + +{{AbstractSigner}} + +{{ERC7739}} + +{{SignerECDSA}} + +{{SignerP256}} + +{{SignerRSA}} + +{{SignerERC7702}} + +{{SignerERC7913}} + +{{MultiSignerERC7913}} + +{{MultiSignerERC7913Weighted}} + +== Verifiers + +{{ERC7913P256Verifier}} + +{{ERC7913RSAVerifier}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/RSA.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/RSA.sol new file mode 100644 index 0000000..4e04ce5 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/RSA.sol @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/RSA.sol) +pragma solidity ^0.8.20; + +import {Math} from "../math/Math.sol"; + +/** + * @dev RSA PKCS#1 v1.5 signature verification implementation according to https://datatracker.ietf.org/doc/html/rfc8017[RFC8017]. + * + * This library supports PKCS#1 v1.5 padding to avoid malleability via chosen plaintext attacks in practical implementations. + * The padding follows the EMSA-PKCS1-v1_5-ENCODE encoding definition as per section 9.2 of the RFC. This padding makes + * RSA semantically secure for signing messages. + * + * Inspired by https://github.com/adria0/SolRsaVerify/blob/79c6182cabb9102ea69d4a2e996816091d5f1cd1[Adrià Massanet's work] (GNU General Public License v3.0). + * + * _Available since v5.1._ + */ +library RSA { + /** + * @dev Same as {pkcs1Sha256} but using SHA256 to calculate the digest of `data`. + */ + function pkcs1Sha256( + bytes memory data, + bytes memory s, + bytes memory e, + bytes memory n + ) internal view returns (bool) { + return pkcs1Sha256(sha256(data), s, e, n); + } + + /** + * @dev Verifies a PKCSv1.5 signature given a digest according to the verification + * method described in https://datatracker.ietf.org/doc/html/rfc8017#section-8.2.2[section 8.2.2 of RFC8017] with + * support for explicit or implicit NULL parameters in the DigestInfo (no other optional parameters are supported). + * + * IMPORTANT: For security reason, this function requires the signature and modulus to have a length of at least + * 2048 bits. If you use a smaller key, consider replacing it with a larger, more secure, one. + * + * WARNING: This verification algorithm doesn't prevent replayability. If called multiple times with the same + * digest, public key and (valid signature), it will return true every time. Consider including an onchain nonce + * or unique identifier in the message to prevent replay attacks. + * + * WARNING: This verification algorithm supports any exponent. NIST recommends using `65537` (or higher). + * That is the default value many libraries use, such as OpenSSL. Developers may choose to reject public keys + * using a low exponent out of security concerns. + * + * @param digest the digest to verify + * @param s is a buffer containing the signature + * @param e is the exponent of the public key + * @param n is the modulus of the public key + */ + function pkcs1Sha256(bytes32 digest, bytes memory s, bytes memory e, bytes memory n) internal view returns (bool) { + unchecked { + // cache and check length + uint256 length = n.length; + if ( + length < 0x100 || // Enforce 2048 bits minimum + length != s.length // signature must have the same length as the finite field + ) { + return false; + } + + // Verify that s < n to ensure there's only one valid signature for a given message + for (uint256 i = 0; i < length; i += 0x20) { + uint256 p = Math.min(i, length - 0x20); + bytes32 sp = _unsafeReadBytes32(s, p); + bytes32 np = _unsafeReadBytes32(n, p); + if (sp < np) { + // s < n in the upper bits (everything before is equal) → s < n globally: ok + break; + } else if (sp > np || p == length - 0x20) { + // s > n in the upper bits (everything before is equal) → s > n globally: fail + // or + // s = n and we are looking at the lower bits → s = n globally: fail + return false; + } + } + + // RSAVP1 https://datatracker.ietf.org/doc/html/rfc8017#section-5.2.2 + // The previous check guarantees that n > 0. Therefore modExp cannot revert. + bytes memory buffer = Math.modExp(s, e, n); + + // Check that buffer is well encoded: + // buffer ::= 0x00 | 0x01 | PS | 0x00 | DigestInfo + // + // With + // - PS is padding filled with 0xFF + // - DigestInfo ::= SEQUENCE { + // digestAlgorithm AlgorithmIdentifier, + // [optional algorithm parameters] -- not currently supported + // digest OCTET STRING + // } + + // Get AlgorithmIdentifier from the DigestInfo, and set the config accordingly + // - params: includes 00 + first part of DigestInfo + // - mask: filter to check the params + // - offset: length of the suffix (including digest) + bytes32 params; // 0x00 | DigestInfo + bytes32 mask; + uint256 offset; + + // Digest is expected at the end of the buffer. Therefore if NULL param is present, + // it should be at 32 (digest) + 2 bytes from the end. To those 34 bytes, we add the + // OID (9 bytes) and its length (2 bytes) to get the position of the DigestInfo sequence, + // which is expected to have a length of 0x31 when the NULL param is present or 0x2f if not. + if (bytes1(_unsafeReadBytes32(buffer, length - 0x32)) == 0x31) { + offset = 0x34; + // 00 (1 byte) | SEQUENCE length (0x31) = 3031 (2 bytes) | SEQUENCE length (0x0d) = 300d (2 bytes) | OBJECT_IDENTIFIER length (0x09) = 0609 (2 bytes) + // SHA256 OID = 608648016503040201 (9 bytes) | NULL = 0500 (2 bytes) (explicit) | OCTET_STRING length (0x20) = 0420 (2 bytes) + params = 0x003031300d060960864801650304020105000420000000000000000000000000; + mask = 0xffffffffffffffffffffffffffffffffffffffff000000000000000000000000; // (20 bytes) + } else if (bytes1(_unsafeReadBytes32(buffer, length - 0x30)) == 0x2F) { + offset = 0x32; + // 00 (1 byte) | SEQUENCE length (0x2f) = 302f (2 bytes) | SEQUENCE length (0x0b) = 300b (2 bytes) | OBJECT_IDENTIFIER length (0x09) = 0609 (2 bytes) + // SHA256 OID = 608648016503040201 (9 bytes) | NULL = | OCTET_STRING length (0x20) = 0420 (2 bytes) + params = 0x00302f300b060960864801650304020104200000000000000000000000000000; + mask = 0xffffffffffffffffffffffffffffffffffff0000000000000000000000000000; // (18 bytes) + } else { + // unknown + return false; + } + + // Length is at least 0x100 and offset is at most 0x34, so this is safe. There is always some padding. + uint256 paddingEnd = length - offset; + + // The padding has variable (arbitrary) length, so we check it byte per byte in a loop. + // This is required to ensure non-malleability. Not checking would allow an attacker to + // use the padding to manipulate the message in order to create a valid signature out of + // multiple valid signatures. + for (uint256 i = 2; i < paddingEnd; ++i) { + if (bytes1(_unsafeReadBytes32(buffer, i)) != 0xFF) { + return false; + } + } + + // All the other parameters are small enough to fit in a bytes32, so we can check them directly. + return + bytes2(0x0001) == bytes2(_unsafeReadBytes32(buffer, 0x00)) && // 00 | 01 + // PS was checked in the loop + params == _unsafeReadBytes32(buffer, paddingEnd) & mask && // DigestInfo + // Optional parameters are not checked + digest == _unsafeReadBytes32(buffer, length - 0x20); // Digest + } + } + + /// @dev Reads a bytes32 from a bytes array without bounds checking. + function _unsafeReadBytes32(bytes memory array, uint256 offset) private pure returns (bytes32 result) { + // Memory safeness is guaranteed as long as the provided `array` is a Solidity-allocated bytes array + // and `offset` is within bounds. This is the case for all calls to this private function from {pkcs1Sha256}. + assembly ("memory-safe") { + result := mload(add(add(array, 0x20), offset)) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol new file mode 100644 index 0000000..f85b24c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/SignatureChecker.sol) + +pragma solidity ^0.8.24; + +import {ECDSA} from "./ECDSA.sol"; +import {IERC1271} from "../../interfaces/IERC1271.sol"; +import {IERC7913SignatureVerifier} from "../../interfaces/IERC7913.sol"; +import {Bytes} from "../../utils/Bytes.sol"; + +/** + * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support: + * + * * ECDSA signatures from externally owned accounts (EOAs) + * * ERC-1271 signatures from smart contract wallets like Argent and Safe Wallet (previously Gnosis Safe) + * * ERC-7913 signatures from keys that do not have an Ethereum address of their own + * + * See https://eips.ethereum.org/EIPS/eip-1271[ERC-1271] and https://eips.ethereum.org/EIPS/eip-7913[ERC-7913]. + */ +library SignatureChecker { + using Bytes for bytes; + + /** + * @dev Checks if a signature is valid for a given signer and data hash. If the signer has code, the + * signature is validated against it using ERC-1271, 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). + * + * NOTE: For an extended version of this function that supports ERC-7913 signatures, see {isValidSignatureNow-bytes-bytes32-bytes-}. + */ + function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { + if (signer.code.length == 0) { + (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature); + return err == ECDSA.RecoverError.NoError && recovered == signer; + } else { + return 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 ERC-1271. + * + * 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)); + } + + /** + * @dev Verifies a signature for a given ERC-7913 signer and hash. + * + * The signer is a `bytes` object that is the concatenation of an address and optionally a key: + * `verifier || key`. A signer must be at least 20 bytes long. + * + * Verification is done as follows: + * + * * If `signer.length < 20`: verification fails + * * If `signer.length == 20`: verification is done using {isValidSignatureNow} + * * Otherwise: verification is done using {IERC7913SignatureVerifier} + * + * 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( + bytes memory signer, + bytes32 hash, + bytes memory signature + ) internal view returns (bool) { + if (signer.length < 20) { + return false; + } else if (signer.length == 20) { + return isValidSignatureNow(address(bytes20(signer)), hash, signature); + } else { + (bool success, bytes memory result) = address(bytes20(signer)).staticcall( + abi.encodeCall(IERC7913SignatureVerifier.verify, (signer.slice(20), hash, signature)) + ); + return (success && + result.length >= 32 && + abi.decode(result, (bytes32)) == bytes32(IERC7913SignatureVerifier.verify.selector)); + } + } + + /** + * @dev Verifies multiple ERC-7913 `signatures` for a given `hash` using a set of `signers`. + * Returns `false` if the number of signers and signatures is not the same. + * + * The signers should be ordered by their `keccak256` hash to ensure efficient duplication check. Unordered + * signers are supported, but the uniqueness check will be more expensive. + * + * 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 areValidSignaturesNow( + bytes32 hash, + bytes[] memory signers, + bytes[] memory signatures + ) internal view returns (bool) { + if (signers.length != signatures.length) return false; + + bytes32 lastId = bytes32(0); + + for (uint256 i = 0; i < signers.length; ++i) { + bytes memory signer = signers[i]; + + // If one of the signatures is invalid, reject the batch + if (!isValidSignatureNow(signer, hash, signatures[i])) return false; + + bytes32 id = keccak256(signer); + // If the current signer ID is greater than all previous IDs, then this is a new signer. + if (lastId < id) { + lastId = id; + } else { + // If this signer id is not greater than all the previous ones, verify that it is not a duplicate of a previous one + // This loop is never executed if the signers are ordered by id. + for (uint256 j = 0; j < i; ++j) { + if (id == keccak256(signers[j])) return false; + } + } + } + + return true; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/draft-ERC7739Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/draft-ERC7739Utils.sol new file mode 100644 index 0000000..e47f20b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/draft-ERC7739Utils.sol @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/draft-ERC7739Utils.sol) + +pragma solidity ^0.8.20; + +import {Calldata} from "../Calldata.sol"; + +/** + * @dev Utilities to process https://ercs.ethereum.org/ERCS/erc-7739[ERC-7739] typed data signatures + * that are specific to an EIP-712 domain. + * + * This library provides methods to wrap, unwrap and operate over typed data signatures with a defensive + * rehashing mechanism that includes the app's xref:api:utils/cryptography#EIP712-_domainSeparatorV4[EIP-712] + * and preserves readability of the signed content using an EIP-712 nested approach. + * + * A smart contract domain can validate a signature for a typed data structure in two ways: + * + * - As an application validating a typed data signature. See {typedDataSignStructHash}. + * - As a smart contract validating a raw message signature. See {personalSignStructHash}. + * + * NOTE: A provider for a smart contract wallet would need to return this signature as the + * result of a call to `personal_sign` or `eth_signTypedData`, and this may be unsupported by + * API clients that expect a return value of 129 bytes, or specifically the `r,s,v` parameters + * of an xref:api:utils/cryptography#ECDSA[ECDSA] signature, as is for example specified for + * xref:api:utils/cryptography#EIP712[EIP-712]. + */ +library ERC7739Utils { + /** + * @dev An EIP-712 type to represent "personal" signatures + * (i.e. mimic of `personal_sign` for smart contracts). + */ + bytes32 private constant PERSONAL_SIGN_TYPEHASH = keccak256("PersonalSign(bytes prefixed)"); + + /** + * @dev Nest a signature for a given EIP-712 type into a nested signature for the domain of the app. + * + * Counterpart of {decodeTypedDataSig} to extract the original signature and the nested components. + */ + function encodeTypedDataSig( + bytes memory signature, + bytes32 appSeparator, + bytes32 contentsHash, + string memory contentsDescr + ) internal pure returns (bytes memory) { + return + abi.encodePacked(signature, appSeparator, contentsHash, contentsDescr, uint16(bytes(contentsDescr).length)); + } + + /** + * @dev Parses a nested signature into its components. + * + * Constructed as follows: + * + * `signature ‖ APP_DOMAIN_SEPARATOR ‖ contentsHash ‖ contentsDescr ‖ uint16(contentsDescr.length)` + * + * - `signature` is the signature for the (ERC-7739) nested struct hash. This signature indirectly signs over the + * original "contents" hash (from the app) and the account's domain separator. + * - `APP_DOMAIN_SEPARATOR` is the EIP-712 {EIP712-_domainSeparatorV4} of the application smart contract that is + * requesting the signature verification (though ERC-1271). + * - `contentsHash` is the hash of the underlying data structure or message. + * - `contentsDescr` is a descriptor of the "contents" part of the the EIP-712 type of the nested signature. + * + * NOTE: This function returns empty if the input format is invalid instead of reverting. + * data instead. + */ + function decodeTypedDataSig( + bytes calldata encodedSignature + ) + internal + pure + returns (bytes calldata signature, bytes32 appSeparator, bytes32 contentsHash, string calldata contentsDescr) + { + unchecked { + uint256 sigLength = encodedSignature.length; + + // 66 bytes = contentsDescrLength (2 bytes) + contentsHash (32 bytes) + APP_DOMAIN_SEPARATOR (32 bytes). + if (sigLength < 66) return (Calldata.emptyBytes(), 0, 0, Calldata.emptyString()); + + uint256 contentsDescrEnd = sigLength - 2; // Last 2 bytes + uint256 contentsDescrLength = uint16(bytes2(encodedSignature[contentsDescrEnd:])); + + // Check for space for `contentsDescr` in addition to the 66 bytes documented above + if (sigLength < 66 + contentsDescrLength) return (Calldata.emptyBytes(), 0, 0, Calldata.emptyString()); + + uint256 contentsHashEnd = contentsDescrEnd - contentsDescrLength; + uint256 separatorEnd = contentsHashEnd - 32; + uint256 signatureEnd = separatorEnd - 32; + + signature = encodedSignature[:signatureEnd]; + appSeparator = bytes32(encodedSignature[signatureEnd:separatorEnd]); + contentsHash = bytes32(encodedSignature[separatorEnd:contentsHashEnd]); + contentsDescr = string(encodedSignature[contentsHashEnd:contentsDescrEnd]); + } + } + + /** + * @dev Nests an `ERC-191` digest into a `PersonalSign` EIP-712 struct, and returns the corresponding struct hash. + * This struct hash must be combined with a domain separator, using {MessageHashUtils-toTypedDataHash} before + * being verified/recovered. + * + * This is used to simulates the `personal_sign` RPC method in the context of smart contracts. + */ + function personalSignStructHash(bytes32 contents) internal pure returns (bytes32) { + return keccak256(abi.encode(PERSONAL_SIGN_TYPEHASH, contents)); + } + + /** + * @dev Nests an `EIP-712` hash (`contents`) into a `TypedDataSign` EIP-712 struct, and returns the corresponding + * struct hash. This struct hash must be combined with a domain separator, using {MessageHashUtils-toTypedDataHash} + * before being verified/recovered. + */ + function typedDataSignStructHash( + string calldata contentsName, + string calldata contentsType, + bytes32 contentsHash, + bytes memory domainBytes + ) internal pure returns (bytes32 result) { + return + bytes(contentsName).length == 0 + ? bytes32(0) + : keccak256( + abi.encodePacked(typedDataSignTypehash(contentsName, contentsType), contentsHash, domainBytes) + ); + } + + /** + * @dev Variant of {typedDataSignStructHash-string-string-bytes32-bytes} that takes a content descriptor + * and decodes the `contentsName` and `contentsType` out of it. + */ + function typedDataSignStructHash( + string calldata contentsDescr, + bytes32 contentsHash, + bytes memory domainBytes + ) internal pure returns (bytes32 result) { + (string calldata contentsName, string calldata contentsType) = decodeContentsDescr(contentsDescr); + + return typedDataSignStructHash(contentsName, contentsType, contentsHash, domainBytes); + } + + /** + * @dev Compute the EIP-712 typehash of the `TypedDataSign` structure for a given type (and typename). + */ + function typedDataSignTypehash( + string calldata contentsName, + string calldata contentsType + ) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked( + "TypedDataSign(", + contentsName, + " contents,string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)", + contentsType + ) + ); + } + + /** + * @dev Parse the type name out of the ERC-7739 contents type description. Supports both the implicit and explicit + * modes. + * + * Following ERC-7739 specifications, a `contentsName` is considered invalid if it's empty or it contains + * any of the following bytes , )\x00 + * + * If the `contentsType` is invalid, this returns an empty string. Otherwise, the return string has non-zero + * length. + */ + function decodeContentsDescr( + string calldata contentsDescr + ) internal pure returns (string calldata contentsName, string calldata contentsType) { + bytes calldata buffer = bytes(contentsDescr); + if (buffer.length == 0) { + // pass through (fail) + } else if (buffer[buffer.length - 1] == bytes1(")")) { + // Implicit mode: read contentsName from the beginning, and keep the complete descr + for (uint256 i = 0; i < buffer.length; ++i) { + bytes1 current = buffer[i]; + if (current == bytes1("(")) { + // if name is empty - passthrough (fail) + if (i == 0) break; + // we found the end of the contentsName + return (string(buffer[:i]), contentsDescr); + } else if (_isForbiddenChar(current)) { + // we found an invalid character (forbidden) - passthrough (fail) + break; + } + } + } else { + // Explicit mode: read contentsName from the end, and remove it from the descr + for (uint256 i = buffer.length; i > 0; --i) { + bytes1 current = buffer[i - 1]; + if (current == bytes1(")")) { + // we found the end of the contentsName + return (string(buffer[i:]), string(buffer[:i])); + } else if (_isForbiddenChar(current)) { + // we found an invalid character (forbidden) - passthrough (fail) + break; + } + } + } + return (Calldata.emptyString(), Calldata.emptyString()); + } + + function _isForbiddenChar(bytes1 char) private pure returns (bool) { + return char == 0x00 || char == bytes1(" ") || char == bytes1(",") || char == bytes1("(") || char == bytes1(")"); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/AbstractSigner.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/AbstractSigner.sol new file mode 100644 index 0000000..942ec2a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/AbstractSigner.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/AbstractSigner.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Abstract contract for signature validation. + * + * Developers must implement {_rawSignatureValidation} and use it as the lowest-level signature validation mechanism. + * + * @custom:stateless + */ +abstract contract AbstractSigner { + /** + * @dev Signature validation algorithm. + * + * WARNING: Implementing a signature validation algorithm is a security-sensitive operation as it involves + * cryptographic verification. It is important to review and test thoroughly before deployment. Consider + * using one of the signature verification libraries (xref:api:utils/cryptography#ECDSA[ECDSA], + * xref:api:utils/cryptography#P256[P256] or xref:api:utils/cryptography#RSA[RSA]). + */ + function _rawSignatureValidation(bytes32 hash, bytes calldata signature) internal view virtual returns (bool); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913.sol new file mode 100644 index 0000000..f485409 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913.sol @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/MultiSignerERC7913.sol) + +pragma solidity ^0.8.26; + +import {AbstractSigner} from "./AbstractSigner.sol"; +import {SignatureChecker} from "../SignatureChecker.sol"; +import {EnumerableSet} from "../../structs/EnumerableSet.sol"; + +/** + * @dev Implementation of {AbstractSigner} using multiple ERC-7913 signers with a threshold-based + * signature verification system. + * + * This contract allows managing a set of authorized signers and requires a minimum number of + * signatures (threshold) to approve operations. It uses ERC-7913 formatted signers, which + * makes it natively compatible with ECDSA and ERC-1271 signers. + * + * Example of usage: + * + * ```solidity + * contract MyMultiSignerAccount is Account, MultiSignerERC7913, Initializable { + * function initialize(bytes[] memory signers, uint64 threshold) public initializer { + * _addSigners(signers); + * _setThreshold(threshold); + * } + * + * function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf { + * _addSigners(signers); + * } + * + * function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf { + * _removeSigners(signers); + * } + * + * function setThreshold(uint64 threshold) public onlyEntryPointOrSelf { + * _setThreshold(threshold); + * } + * } + * ``` + * + * IMPORTANT: Failing to properly initialize the signers and threshold either during construction + * (if used standalone) or during initialization (if used as a clone) may leave the contract + * either front-runnable or unusable. + */ +abstract contract MultiSignerERC7913 is AbstractSigner { + using EnumerableSet for EnumerableSet.BytesSet; + using SignatureChecker for *; + + EnumerableSet.BytesSet private _signers; + uint64 private _threshold; + + /// @dev Emitted when a signer is added. + event ERC7913SignerAdded(bytes indexed signers); + + /// @dev Emitted when a signers is removed. + event ERC7913SignerRemoved(bytes indexed signers); + + /// @dev Emitted when the threshold is updated. + event ERC7913ThresholdSet(uint64 threshold); + + /// @dev The `signer` already exists. + error MultiSignerERC7913AlreadyExists(bytes signer); + + /// @dev The `signer` does not exist. + error MultiSignerERC7913NonexistentSigner(bytes signer); + + /// @dev The `signer` is less than 20 bytes long. + error MultiSignerERC7913InvalidSigner(bytes signer); + + /// @dev The `threshold` is zero. + error MultiSignerERC7913ZeroThreshold(); + + /// @dev The `threshold` is unreachable given the number of `signers`. + error MultiSignerERC7913UnreachableThreshold(uint64 signers, uint64 threshold); + + constructor(bytes[] memory signers_, uint64 threshold_) { + _addSigners(signers_); + _setThreshold(threshold_); + } + + /** + * @dev Returns a slice of the set of authorized signers. + * + * Using `start = 0` and `end = type(uint64).max` will return the entire set of signers. + * + * WARNING: Depending on the `start` and `end`, this operation can copy a large amount of data to memory, which + * can be expensive. This is designed for view accessors queried without gas fees. Using it in state-changing + * functions may become uncallable if the slice grows too large. + */ + function getSigners(uint64 start, uint64 end) public view virtual returns (bytes[] memory) { + return _signers.values(start, end); + } + + /// @dev Returns the number of authorized signers + function getSignerCount() public view virtual returns (uint256) { + return _signers.length(); + } + + /// @dev Returns whether the `signer` is an authorized signer. + function isSigner(bytes memory signer) public view virtual returns (bool) { + return _signers.contains(signer); + } + + /// @dev Returns the minimum number of signers required to approve a multisignature operation. + function threshold() public view virtual returns (uint64) { + return _threshold; + } + + /** + * @dev Adds the `newSigners` to those allowed to sign on behalf of this contract. + * Internal version without access control. + * + * Requirements: + * + * * Each of `newSigners` must be at least 20 bytes long. Reverts with {MultiSignerERC7913InvalidSigner} if not. + * * Each of `newSigners` must not be authorized. See {isSigner}. Reverts with {MultiSignerERC7913AlreadyExists} if so. + */ + function _addSigners(bytes[] memory newSigners) internal virtual { + for (uint256 i = 0; i < newSigners.length; ++i) { + bytes memory signer = newSigners[i]; + require(signer.length >= 20, MultiSignerERC7913InvalidSigner(signer)); + require(_signers.add(signer), MultiSignerERC7913AlreadyExists(signer)); + emit ERC7913SignerAdded(signer); + } + } + + /** + * @dev Removes the `oldSigners` from the authorized signers. Internal version without access control. + * + * Requirements: + * + * * Each of `oldSigners` must be authorized. See {isSigner}. Otherwise {MultiSignerERC7913NonexistentSigner} is thrown. + * * See {_validateReachableThreshold} for the threshold validation. + */ + function _removeSigners(bytes[] memory oldSigners) internal virtual { + for (uint256 i = 0; i < oldSigners.length; ++i) { + bytes memory signer = oldSigners[i]; + require(_signers.remove(signer), MultiSignerERC7913NonexistentSigner(signer)); + emit ERC7913SignerRemoved(signer); + } + _validateReachableThreshold(); + } + + /** + * @dev Sets the signatures `threshold` required to approve a multisignature operation. + * Internal version without access control. + * + * Requirements: + * + * * See {_validateReachableThreshold} for the threshold validation. + */ + function _setThreshold(uint64 newThreshold) internal virtual { + require(newThreshold > 0, MultiSignerERC7913ZeroThreshold()); + _threshold = newThreshold; + _validateReachableThreshold(); + emit ERC7913ThresholdSet(newThreshold); + } + + /** + * @dev Validates the current threshold is reachable. + * + * Requirements: + * + * * The {getSignerCount} must be greater or equal than to the {threshold}. Throws + * {MultiSignerERC7913UnreachableThreshold} if not. + */ + function _validateReachableThreshold() internal view virtual { + uint256 signersLength = _signers.length(); + uint64 currentThreshold = threshold(); + require( + signersLength >= currentThreshold, + MultiSignerERC7913UnreachableThreshold( + uint64(signersLength), // Safe cast. Economically impossible to overflow. + currentThreshold + ) + ); + } + + /** + * @dev Decodes, validates the signature and checks the signers are authorized. + * See {_validateSignatures} and {_validateThreshold} for more details. + * + * Example of signature encoding: + * + * ```solidity + * // Encode signers (verifier || key) + * bytes memory signer1 = abi.encodePacked(verifier1, key1); + * bytes memory signer2 = abi.encodePacked(verifier2, key2); + * + * // Order signers by their id + * if (keccak256(signer1) > keccak256(signer2)) { + * (signer1, signer2) = (signer2, signer1); + * (signature1, signature2) = (signature2, signature1); + * } + * + * // Assign ordered signers and signatures + * bytes[] memory signers = new bytes[](2); + * bytes[] memory signatures = new bytes[](2); + * signers[0] = signer1; + * signatures[0] = signature1; + * signers[1] = signer2; + * signatures[1] = signature2; + * + * // Encode the multi signature + * bytes memory signature = abi.encode(signers, signatures); + * ``` + * + * Requirements: + * + * * The `signature` must be encoded as `abi.encode(signers, signatures)`. + */ + function _rawSignatureValidation( + bytes32 hash, + bytes calldata signature + ) internal view virtual override returns (bool) { + if (signature.length == 0) return false; // For ERC-7739 compatibility + (bytes[] memory signers, bytes[] memory signatures) = abi.decode(signature, (bytes[], bytes[])); + return _validateThreshold(signers) && _validateSignatures(hash, signers, signatures); + } + + /** + * @dev Validates the signatures using the signers and their corresponding signatures. + * Returns whether the signers are authorized and the signatures are valid for the given hash. + * + * IMPORTANT: Sorting the signers by their `keccak256` hash will improve the gas efficiency of this function. + * See {SignatureChecker-areValidSignaturesNow-bytes32-bytes[]-bytes[]} for more details. + * + * Requirements: + * + * * The `signatures` and `signers` arrays must be equal in length. Returns false otherwise. + */ + function _validateSignatures( + bytes32 hash, + bytes[] memory signers, + bytes[] memory signatures + ) internal view virtual returns (bool valid) { + for (uint256 i = 0; i < signers.length; ++i) { + if (!isSigner(signers[i])) { + return false; + } + } + return hash.areValidSignaturesNow(signers, signatures); + } + + /** + * @dev Validates that the number of signers meets the {threshold} requirement. + * Assumes the signers were already validated. See {_validateSignatures} for more details. + */ + function _validateThreshold(bytes[] memory validatingSigners) internal view virtual returns (bool) { + return validatingSigners.length >= threshold(); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol new file mode 100644 index 0000000..653272f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/MultiSignerERC7913Weighted.sol) + +pragma solidity ^0.8.26; + +import {SafeCast} from "../../math/SafeCast.sol"; +import {MultiSignerERC7913} from "./MultiSignerERC7913.sol"; + +/** + * @dev Extension of {MultiSignerERC7913} that supports weighted signatures. + * + * This contract allows assigning different weights to each signer, enabling more + * flexible governance schemes. For example, some signers could have higher weight + * than others, allowing for weighted voting or prioritized authorization. + * + * Example of usage: + * + * ```solidity + * contract MyWeightedMultiSignerAccount is Account, MultiSignerERC7913Weighted, Initializable { + * function initialize(bytes[] memory signers, uint64[] memory weights, uint64 threshold) public initializer { + * _addSigners(signers); + * _setSignerWeights(signers, weights); + * _setThreshold(threshold); + * } + * + * function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf { + * _addSigners(signers); + * } + * + * function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf { + * _removeSigners(signers); + * } + * + * function setThreshold(uint64 threshold) public onlyEntryPointOrSelf { + * _setThreshold(threshold); + * } + * + * function setSignerWeights(bytes[] memory signers, uint64[] memory weights) public onlyEntryPointOrSelf { + * _setSignerWeights(signers, weights); + * } + * } + * ``` + * + * IMPORTANT: When setting a threshold value, ensure it matches the scale used for signer weights. + * For example, if signers have weights like 1, 2, or 3, then a threshold of 4 would require at + * least two signers (e.g., one with weight 1 and one with weight 3). See {signerWeight}. + */ +abstract contract MultiSignerERC7913Weighted is MultiSignerERC7913 { + using SafeCast for *; + + // Sum of all the extra weights of all signers. Storage packed with `MultiSignerERC7913._threshold` + uint64 private _totalExtraWeight; + + // Mapping from signer to extraWeight (in addition to all authorized signers having weight 1) + mapping(bytes signer => uint64) private _extraWeights; + + /** + * @dev Emitted when a signer's weight is changed. + * + * NOTE: Not emitted in {_addSigners} or {_removeSigners}. Indexers must rely on {ERC7913SignerAdded} + * and {ERC7913SignerRemoved} to index a default weight of 1. See {signerWeight}. + */ + event ERC7913SignerWeightChanged(bytes indexed signer, uint64 weight); + + /// @dev Thrown when a signer's weight is invalid. + error MultiSignerERC7913WeightedInvalidWeight(bytes signer, uint64 weight); + + /// @dev Thrown when the arrays lengths don't match. See {_setSignerWeights}. + error MultiSignerERC7913WeightedMismatchedLength(); + + constructor(bytes[] memory signers_, uint64[] memory weights_, uint64 threshold_) MultiSignerERC7913(signers_, 1) { + _setSignerWeights(signers_, weights_); + _setThreshold(threshold_); + } + + /// @dev Gets the weight of a signer. Returns 0 if the signer is not authorized. + function signerWeight(bytes memory signer) public view virtual returns (uint64) { + unchecked { + // Safe cast, _setSignerWeights guarantees 1+_extraWeights is a uint64 + return uint64(isSigner(signer).toUint() * (1 + _extraWeights[signer])); + } + } + + /// @dev Gets the total weight of all signers. + function totalWeight() public view virtual returns (uint64) { + return (getSignerCount() + _totalExtraWeight).toUint64(); + } + + /** + * @dev Sets weights for multiple signers at once. Internal version without access control. + * + * Requirements: + * + * * `signers` and `weights` arrays must have the same length. Reverts with {MultiSignerERC7913WeightedMismatchedLength} on mismatch. + * * Each signer must exist in the set of authorized signers. Otherwise reverts with {MultiSignerERC7913NonexistentSigner} + * * Each weight must be greater than 0. Otherwise reverts with {MultiSignerERC7913WeightedInvalidWeight} + * * See {_validateReachableThreshold} for the threshold validation. + * + * Emits {ERC7913SignerWeightChanged} for each signer. + */ + function _setSignerWeights(bytes[] memory signers, uint64[] memory weights) internal virtual { + require(signers.length == weights.length, MultiSignerERC7913WeightedMismatchedLength()); + + uint256 extraWeightAdded = 0; + uint256 extraWeightRemoved = 0; + for (uint256 i = 0; i < signers.length; ++i) { + bytes memory signer = signers[i]; + require(isSigner(signer), MultiSignerERC7913NonexistentSigner(signer)); + + uint64 weight = weights[i]; + require(weight > 0, MultiSignerERC7913WeightedInvalidWeight(signer, weight)); + + unchecked { + uint64 oldExtraWeight = _extraWeights[signer]; + uint64 newExtraWeight = weight - 1; + + if (oldExtraWeight != newExtraWeight) { + // Overflow impossible: weight values are bounded by uint64 and economic constraints + extraWeightRemoved += oldExtraWeight; + extraWeightAdded += _extraWeights[signer] = newExtraWeight; + emit ERC7913SignerWeightChanged(signer, weight); + } + } + } + unchecked { + // Safe from underflow: `extraWeightRemoved` is bounded by `_totalExtraWeight` by construction + // and weight values are bounded by uint64 and economic constraints + _totalExtraWeight = (uint256(_totalExtraWeight) + extraWeightAdded - extraWeightRemoved).toUint64(); + } + _validateReachableThreshold(); + } + + /** + * @dev See {MultiSignerERC7913-_addSigners}. + * + * In cases where {totalWeight} is almost `type(uint64).max` (due to a large `_totalExtraWeight`), adding new + * signers could cause the {totalWeight} computation to overflow. Adding a {totalWeight} calls after the new + * signers are added ensures no such overflow happens. + */ + function _addSigners(bytes[] memory newSigners) internal virtual override { + super._addSigners(newSigners); + + // This will revert if the new signers cause an overflow + _validateReachableThreshold(); + } + + /** + * @dev See {MultiSignerERC7913-_removeSigners}. + * + * Just like {_addSigners}, this function does not emit {ERC7913SignerWeightChanged} events. The + * {ERC7913SignerRemoved} event emitted by {MultiSignerERC7913-_removeSigners} is enough to track weights here. + */ + function _removeSigners(bytes[] memory signers) internal virtual override { + // Clean up weights for removed signers + // + // The `extraWeightRemoved` is bounded by `_totalExtraWeight`. The `super._removeSigners` function will revert + // if the signers array contains any duplicates, ensuring each signer's weight is only counted once. Since + // `_totalExtraWeight` is stored as a `uint64`, the final subtraction operation is also safe. + unchecked { + uint64 extraWeightRemoved = 0; + for (uint256 i = 0; i < signers.length; ++i) { + bytes memory signer = signers[i]; + + extraWeightRemoved += _extraWeights[signer]; + delete _extraWeights[signer]; + } + _totalExtraWeight -= extraWeightRemoved; + } + super._removeSigners(signers); + } + + /** + * @dev Sets the threshold for the multisignature operation. Internal version without access control. + * + * Requirements: + * + * * The {totalWeight} must be `>=` the {threshold}. Otherwise reverts with {MultiSignerERC7913UnreachableThreshold} + * + * NOTE: This function intentionally does not call `super._validateReachableThreshold` because the base implementation + * assumes each signer has a weight of 1, which is a subset of this weighted implementation. Consider that multiple + * implementations of this function may exist in the contract, so important side effects may be missed + * depending on the linearization order. + */ + function _validateReachableThreshold() internal view virtual override { + uint64 weight = totalWeight(); + uint64 currentThreshold = threshold(); + require(weight >= currentThreshold, MultiSignerERC7913UnreachableThreshold(weight, currentThreshold)); + } + + /** + * @dev Validates that the total weight of signers meets the threshold requirement. + * + * NOTE: This function intentionally does not call `super._validateThreshold` because the base implementation + * assumes each signer has a weight of 1, which is a subset of this weighted implementation. Consider that multiple + * implementations of this function may exist in the contract, so important side effects may be missed + * depending on the linearization order. + */ + function _validateThreshold(bytes[] memory signers) internal view virtual override returns (bool) { + unchecked { + uint64 weight = 0; + for (uint256 i = 0; i < signers.length; ++i) { + // Overflow impossible: weight values are bounded by uint64 and economic constraints + weight += signerWeight(signers[i]); + } + return weight >= threshold(); + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerECDSA.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerECDSA.sol new file mode 100644 index 0000000..517cd7e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerECDSA.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerECDSA.sol) + +pragma solidity ^0.8.20; + +import {AbstractSigner} from "./AbstractSigner.sol"; +import {ECDSA} from "../ECDSA.sol"; + +/** + * @dev Implementation of {AbstractSigner} using xref:api:utils/cryptography#ECDSA[ECDSA] signatures. + * + * For {Account} usage, a {_setSigner} function is provided to set the {signer} address. + * Doing so is easier for a factory, who is likely to use initializable clones of this contract. + * + * Example of usage: + * + * ```solidity + * contract MyAccountECDSA is Account, SignerECDSA, Initializable { + * function initialize(address signerAddr) public initializer { + * _setSigner(signerAddr); + * } + * } + * ``` + * + * IMPORTANT: Failing to call {_setSigner} either during construction (if used standalone) + * or during initialization (if used as a clone) may leave the signer either front-runnable or unusable. + */ +abstract contract SignerECDSA is AbstractSigner { + address private _signer; + + constructor(address signerAddr) { + _setSigner(signerAddr); + } + + /** + * @dev Sets the signer with the address of the native signer. This function should be called during construction + * or through an initializer. + */ + function _setSigner(address signerAddr) internal { + _signer = signerAddr; + } + + /// @dev Return the signer's address. + function signer() public view virtual returns (address) { + return _signer; + } + + /// @inheritdoc AbstractSigner + function _rawSignatureValidation( + bytes32 hash, + bytes calldata signature + ) internal view virtual override returns (bool) { + (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature); + return signer() == recovered && err == ECDSA.RecoverError.NoError; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7702.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7702.sol new file mode 100644 index 0000000..b02190e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7702.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerERC7702.sol) + +pragma solidity ^0.8.20; + +import {AbstractSigner} from "./AbstractSigner.sol"; +import {ECDSA} from "../ECDSA.sol"; + +/** + * @dev Implementation of {AbstractSigner} for implementation for an EOA. Useful for ERC-7702 accounts. + * + * @custom:stateless + */ +abstract contract SignerERC7702 is AbstractSigner { + /** + * @dev Validates the signature using the EOA's address (i.e. `address(this)`). + */ + function _rawSignatureValidation( + bytes32 hash, + bytes calldata signature + ) internal view virtual override returns (bool) { + (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature); + return address(this) == recovered && err == ECDSA.RecoverError.NoError; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7913.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7913.sol new file mode 100644 index 0000000..d0f567a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7913.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerERC7913.sol) + +pragma solidity ^0.8.24; + +import {AbstractSigner} from "./AbstractSigner.sol"; +import {SignatureChecker} from "../SignatureChecker.sol"; + +/** + * @dev Implementation of {AbstractSigner} using + * https://eips.ethereum.org/EIPS/eip-7913[ERC-7913] signature verification. + * + * For {Account} usage, a {_setSigner} function is provided to set the ERC-7913 formatted {signer}. + * Doing so is easier for a factory, who is likely to use initializable clones of this contract. + * + * The signer is a `bytes` object that concatenates a verifier address and a key: `verifier || key`. + * + * Example of usage: + * + * ```solidity + * contract MyAccountERC7913 is Account, SignerERC7913, Initializable { + * function initialize(bytes memory signer_) public initializer { + * _setSigner(signer_); + * } + * + * function setSigner(bytes memory signer_) public onlyEntryPointOrSelf { + * _setSigner(signer_); + * } + * } + * ``` + * + * IMPORTANT: Failing to call {_setSigner} either during construction (if used standalone) + * or during initialization (if used as a clone) may leave the signer either front-runnable or unusable. + */ + +abstract contract SignerERC7913 is AbstractSigner { + bytes private _signer; + + constructor(bytes memory signer_) { + _setSigner(signer_); + } + + /// @dev Return the ERC-7913 signer (i.e. `verifier || key`). + function signer() public view virtual returns (bytes memory) { + return _signer; + } + + /// @dev Sets the signer (i.e. `verifier || key`) with an ERC-7913 formatted signer. + function _setSigner(bytes memory signer_) internal { + _signer = signer_; + } + + /** + * @dev Verifies a signature using {SignatureChecker-isValidSignatureNow-bytes-bytes32-bytes-} + * with {signer}, `hash` and `signature`. + */ + function _rawSignatureValidation( + bytes32 hash, + bytes calldata signature + ) internal view virtual override returns (bool) { + return SignatureChecker.isValidSignatureNow(signer(), hash, signature); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerP256.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerP256.sol new file mode 100644 index 0000000..131b5c1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerP256.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerP256.sol) + +pragma solidity ^0.8.20; + +import {AbstractSigner} from "./AbstractSigner.sol"; +import {P256} from "../P256.sol"; + +/** + * @dev Implementation of {AbstractSigner} using xref:api:utils/cryptography#P256[P256] signatures. + * + * For {Account} usage, a {_setSigner} function is provided to set the {signer} public key. + * Doing so is easier for a factory, who is likely to use initializable clones of this contract. + * + * Example of usage: + * + * ```solidity + * contract MyAccountP256 is Account, SignerP256, Initializable { + * function initialize(bytes32 qx, bytes32 qy) public initializer { + * _setSigner(qx, qy); + * } + * } + * ``` + * + * IMPORTANT: Failing to call {_setSigner} either during construction (if used standalone) + * or during initialization (if used as a clone) may leave the signer either front-runnable or unusable. + */ +abstract contract SignerP256 is AbstractSigner { + bytes32 private _qx; + bytes32 private _qy; + + error SignerP256InvalidPublicKey(bytes32 qx, bytes32 qy); + + constructor(bytes32 qx, bytes32 qy) { + _setSigner(qx, qy); + } + + /** + * @dev Sets the signer with a P256 public key. This function should be called during construction + * or through an initializer. + */ + function _setSigner(bytes32 qx, bytes32 qy) internal { + if (!P256.isValidPublicKey(qx, qy)) revert SignerP256InvalidPublicKey(qx, qy); + _qx = qx; + _qy = qy; + } + + /// @dev Return the signer's P256 public key. + function signer() public view virtual returns (bytes32 qx, bytes32 qy) { + return (_qx, _qy); + } + + /// @inheritdoc AbstractSigner + function _rawSignatureValidation( + bytes32 hash, + bytes calldata signature + ) internal view virtual override returns (bool) { + if (signature.length < 0x40) return false; + bytes32 r = bytes32(signature[0x00:0x20]); + bytes32 s = bytes32(signature[0x20:0x40]); + (bytes32 qx, bytes32 qy) = signer(); + return P256.verify(hash, r, s, qx, qy); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerRSA.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerRSA.sol new file mode 100644 index 0000000..7ca18ea --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerRSA.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerRSA.sol) + +pragma solidity ^0.8.20; + +import {AbstractSigner} from "./AbstractSigner.sol"; +import {RSA} from "../RSA.sol"; + +/** + * @dev Implementation of {AbstractSigner} using xref:api:utils/cryptography#RSA[RSA] signatures. + * + * For {Account} usage, a {_setSigner} function is provided to set the {signer} public key. + * Doing so is easier for a factory, who is likely to use initializable clones of this contract. + * + * Example of usage: + * + * ```solidity + * contract MyAccountRSA is Account, SignerRSA, Initializable { + * function initialize(bytes memory e, bytes memory n) public initializer { + * _setSigner(e, n); + * } + * } + * ``` + * + * IMPORTANT: Failing to call {_setSigner} either during construction (if used standalone) + * or during initialization (if used as a clone) may leave the signer either front-runnable or unusable. + */ +abstract contract SignerRSA is AbstractSigner { + bytes private _e; + bytes private _n; + + constructor(bytes memory e, bytes memory n) { + _setSigner(e, n); + } + + /** + * @dev Sets the signer with a RSA public key. This function should be called during construction + * or through an initializer. + */ + function _setSigner(bytes memory e, bytes memory n) internal { + _e = e; + _n = n; + } + + /// @dev Return the signer's RSA public key. + function signer() public view virtual returns (bytes memory e, bytes memory n) { + return (_e, _n); + } + + /** + * @dev See {AbstractSigner-_rawSignatureValidation}. Verifies a PKCSv1.5 signature by calling + * xref:api:utils/cryptography.adoc#RSA-pkcs1Sha256-bytes-bytes-bytes-bytes-[RSA.pkcs1Sha256]. + * + * IMPORTANT: Following the RSASSA-PKCS1-V1_5-VERIFY procedure outlined in RFC8017 (section 8.2.2), the + * provided `hash` is used as the `M` (message) and rehashed using SHA256 according to EMSA-PKCS1-v1_5 + * encoding as per section 9.2 (step 1) of the RFC. + */ + function _rawSignatureValidation( + bytes32 hash, + bytes calldata signature + ) internal view virtual override returns (bool) { + (bytes memory e, bytes memory n) = signer(); + return RSA.pkcs1Sha256(abi.encodePacked(hash), signature, e, n); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/draft-ERC7739.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/draft-ERC7739.sol new file mode 100644 index 0000000..003b915 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/draft-ERC7739.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/draft-ERC7739.sol) + +pragma solidity ^0.8.20; + +import {AbstractSigner} from "./AbstractSigner.sol"; +import {EIP712} from "../EIP712.sol"; +import {ERC7739Utils} from "../draft-ERC7739Utils.sol"; +import {IERC1271} from "../../../interfaces/IERC1271.sol"; +import {MessageHashUtils} from "../MessageHashUtils.sol"; +import {ShortStrings} from "../../ShortStrings.sol"; + +/** + * @dev Validates signatures wrapping the message hash in a nested EIP712 type. See {ERC7739Utils}. + * + * Linking the signature to the EIP-712 domain separator is a security measure to prevent signature replay across different + * EIP-712 domains (e.g. a single offchain owner of multiple contracts). + * + * This contract requires implementing the {_rawSignatureValidation} function, which passes the wrapped message hash, + * which may be either an typed data or a personal sign nested type. + * + * NOTE: xref:api:utils/cryptography#EIP712[EIP-712] uses xref:api:utils/cryptography#ShortStrings[ShortStrings] to + * optimize gas costs for short strings (up to 31 characters). Consider that strings longer than that will use storage, + * which may limit the ability of the signer to be used within the ERC-4337 validation phase (due to + * https://eips.ethereum.org/EIPS/eip-7562#storage-rules[ERC-7562 storage access rules]). + */ +abstract contract ERC7739 is AbstractSigner, EIP712, IERC1271 { + using ERC7739Utils for *; + using MessageHashUtils for bytes32; + + /** + * @dev Attempts validating the signature in a nested EIP-712 type. + * + * A nested EIP-712 type might be presented in 2 different ways: + * + * - As a nested EIP-712 typed data + * - As a _personal_ signature (an EIP-712 mimic of the `eth_personalSign` for a smart contract) + */ + function isValidSignature(bytes32 hash, bytes calldata signature) public view virtual returns (bytes4 result) { + // For the hash `0x7739773977397739773977397739773977397739773977397739773977397739` and an empty signature, + // we return the magic value `0x77390001` as it's assumed impossible to find a preimage for it that can be used + // maliciously. Useful for simulation purposes and to validate whether the contract supports ERC-7739. + return + (_isValidNestedTypedDataSignature(hash, signature) || _isValidNestedPersonalSignSignature(hash, signature)) + ? IERC1271.isValidSignature.selector + : (hash == 0x7739773977397739773977397739773977397739773977397739773977397739 && signature.length == 0) + ? bytes4(0x77390001) + : bytes4(0xffffffff); + } + + /** + * @dev Nested personal signature verification. + */ + function _isValidNestedPersonalSignSignature(bytes32 hash, bytes calldata signature) private view returns (bool) { + return _rawSignatureValidation(_domainSeparatorV4().toTypedDataHash(hash.personalSignStructHash()), signature); + } + + /** + * @dev Nested EIP-712 typed data verification. + */ + function _isValidNestedTypedDataSignature( + bytes32 hash, + bytes calldata encodedSignature + ) private view returns (bool) { + // decode signature + ( + bytes calldata signature, + bytes32 appSeparator, + bytes32 contentsHash, + string calldata contentsDescr + ) = encodedSignature.decodeTypedDataSig(); + + ( + , + string memory name, + string memory version, + uint256 chainId, + address verifyingContract, + bytes32 salt, + + ) = eip712Domain(); + + // Check that contentHash and separator are correct + // Rebuild nested hash + return + hash == appSeparator.toTypedDataHash(contentsHash) && + bytes(contentsDescr).length != 0 && + _rawSignatureValidation( + appSeparator.toTypedDataHash( + ERC7739Utils.typedDataSignStructHash( + contentsDescr, + contentsHash, + abi.encode(keccak256(bytes(name)), keccak256(bytes(version)), chainId, verifyingContract, salt) + ) + ), + signature + ); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913P256Verifier.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913P256Verifier.sol new file mode 100644 index 0000000..60091c9 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913P256Verifier.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/verifiers/ERC7913P256Verifier.sol) + +pragma solidity ^0.8.20; + +import {P256} from "../../../utils/cryptography/P256.sol"; +import {IERC7913SignatureVerifier} from "../../../interfaces/IERC7913.sol"; + +/** + * @dev ERC-7913 signature verifier that support P256 (secp256r1) keys. + * + * @custom:stateless + */ +contract ERC7913P256Verifier is IERC7913SignatureVerifier { + /// @inheritdoc IERC7913SignatureVerifier + function verify(bytes calldata key, bytes32 hash, bytes calldata signature) public view virtual returns (bytes4) { + // Signature length may be 0x40 or 0x41. + if (key.length == 0x40 && signature.length >= 0x40) { + bytes32 qx = bytes32(key[0x00:0x20]); + bytes32 qy = bytes32(key[0x20:0x40]); + bytes32 r = bytes32(signature[0x00:0x20]); + bytes32 s = bytes32(signature[0x20:0x40]); + if (P256.verify(hash, r, s, qx, qy)) { + return IERC7913SignatureVerifier.verify.selector; + } + } + return 0xFFFFFFFF; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913RSAVerifier.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913RSAVerifier.sol new file mode 100644 index 0000000..07f58c8 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913RSAVerifier.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/verifiers/ERC7913RSAVerifier.sol) + +pragma solidity ^0.8.20; + +import {RSA} from "../../../utils/cryptography/RSA.sol"; +import {IERC7913SignatureVerifier} from "../../../interfaces/IERC7913.sol"; + +/** + * @dev ERC-7913 signature verifier that support RSA keys. + * + * @custom:stateless + */ +contract ERC7913RSAVerifier is IERC7913SignatureVerifier { + /// @inheritdoc IERC7913SignatureVerifier + function verify(bytes calldata key, bytes32 hash, bytes calldata signature) public view virtual returns (bytes4) { + (bytes memory e, bytes memory n) = abi.decode(key, (bytes, bytes)); + return + RSA.pkcs1Sha256(abi.encodePacked(hash), signature, e, n) + ? IERC7913SignatureVerifier.verify.selector + : bytes4(0xFFFFFFFF); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol new file mode 100644 index 0000000..be4cc5a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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 ERC-165 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 { + /// @inheritdoc IERC165 + function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol new file mode 100644 index 0000000..8650f55 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.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 ERC-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 ERC-165 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 ERC-165 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 ERC-165 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 ERC-165 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 ERC-165 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 ERC-165, 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 ("memory-safe") { + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol new file mode 100644 index 0000000..be1932f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol) + +pragma solidity >=0.4.16; + +/** + * @dev Interface of the ERC-165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[ERC]. + * + * 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[ERC 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/Math.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/Math.sol new file mode 100644 index 0000000..f0d608a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/Math.sol @@ -0,0 +1,749 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol) + +pragma solidity ^0.8.20; + +import {Panic} from "../Panic.sol"; +import {SafeCast} from "./SafeCast.sol"; + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + enum Rounding { + Floor, // Toward negative infinity + Ceil, // Toward positive infinity + Trunc, // Toward zero + Expand // Away from zero + } + + /** + * @dev Return the 512-bit addition of two uint256. + * + * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low. + */ + function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) { + assembly ("memory-safe") { + low := add(a, b) + high := lt(low, a) + } + } + + /** + * @dev Return the 512-bit multiplication of two uint256. + * + * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low. + */ + function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) { + // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use + // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 + // variables such that product = high * 2²⁵⁶ + low. + assembly ("memory-safe") { + let mm := mulmod(a, b, not(0)) + low := mul(a, b) + high := sub(sub(mm, low), lt(mm, low)) + } + } + + /** + * @dev Returns the addition of two unsigned integers, with a success flag (no overflow). + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + uint256 c = a + b; + success = c >= a; + result = c * SafeCast.toUint(success); + } + } + + /** + * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow). + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + uint256 c = a - b; + success = c <= a; + result = c * SafeCast.toUint(success); + } + } + + /** + * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow). + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + uint256 c = a * b; + assembly ("memory-safe") { + // Only true when the multiplication doesn't overflow + // (c / a == b) || (a == 0) + success := or(eq(div(c, a), b), iszero(a)) + } + // equivalent to: success ? c : 0 + result = c * SafeCast.toUint(success); + } + } + + /** + * @dev Returns the division of two unsigned integers, with a success flag (no division by zero). + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + success = b > 0; + assembly ("memory-safe") { + // The `DIV` opcode returns zero when the denominator is 0. + result := div(a, b) + } + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero). + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + success = b > 0; + assembly ("memory-safe") { + // The `MOD` opcode returns zero when the denominator is 0. + result := mod(a, b) + } + } + } + + /** + * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing. + */ + function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) { + (bool success, uint256 result) = tryAdd(a, b); + return ternary(success, result, type(uint256).max); + } + + /** + * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing. + */ + function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) { + (, uint256 result) = trySub(a, b); + return result; + } + + /** + * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing. + */ + function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) { + (bool success, uint256 result) = tryMul(a, b); + return ternary(success, result, type(uint256).max); + } + + /** + * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. + * + * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. + * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute + * one branch when needed, making this function more expensive. + */ + function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) { + unchecked { + // branchless ternary works because: + // b ^ (a ^ b) == a + // b ^ 0 == b + return b ^ ((a ^ b) * SafeCast.toUint(condition)); + } + } + + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return ternary(a > b, a, b); + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return ternary(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. + Panic.panic(Panic.DIVISION_BY_ZERO); + } + + // The following calculation ensures accurate ceiling division without overflow. + // Since a is non-zero, (a - 1) / b will not overflow. + // The largest possible result occurs when (a - 1) / b is type(uint256).max, + // but the largest value we can obtain is type(uint256).max - 1, which happens + // when a = type(uint256).max and b = 1. + unchecked { + return SafeCast.toUint(a > 0) * ((a - 1) / b + 1); + } + } + + /** + * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or + * denominator == 0. + * + * 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 { + (uint256 high, uint256 low) = mul512(x, y); + + // Handle non-overflow cases, 256 by 256 division. + if (high == 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 low / denominator; + } + + // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0. + if (denominator <= high) { + Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW)); + } + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [high low]. + uint256 remainder; + assembly ("memory-safe") { + // Compute remainder using mulmod. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512 bit number. + high := sub(high, gt(remainder, low)) + low := sub(low, 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 ("memory-safe") { + // Divide denominator by twos. + denominator := div(denominator, twos) + + // Divide [high low] by twos. + low := div(low, twos) + + // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one. + twos := add(div(sub(0, twos), twos), 1) + } + + // Shift in bits from high into low. + low |= high * twos; + + // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such + // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv ≡ 1 mod 2⁴. + 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⁸ + inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶ + inverse *= 2 - denominator * inverse; // inverse mod 2³² + inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴ + inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸ + inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶ + + // 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²⁵⁶. Since the preconditions guarantee that the outcome is + // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high + // is no longer required. + result = low * inverse; + return result; + } + } + + /** + * @dev 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) { + return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0); + } + + /** + * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256. + */ + function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) { + unchecked { + (uint256 high, uint256 low) = mul512(x, y); + if (high >= 1 << n) { + Panic.panic(Panic.UNDER_OVERFLOW); + } + return (high << (256 - n)) | (low >> n); + } + } + + /** + * @dev Calculates x * y >> n with full precision, following the selected rounding direction. + */ + function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) { + return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0); + } + + /** + * @dev Calculate the modular multiplicative inverse of a number in Z/nZ. + * + * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0. + * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible. + * + * If the input value is not inversible, 0 is returned. + * + * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the + * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}. + */ + function invMod(uint256 a, uint256 n) internal pure returns (uint256) { + unchecked { + if (n == 0) return 0; + + // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version) + // Used to compute integers x and y such that: ax + ny = gcd(a, n). + // When the gcd is 1, then the inverse of a modulo n exists and it's x. + // ax + ny = 1 + // ax = 1 + (-y)n + // ax ≡ 1 (mod n) # x is the inverse of a modulo n + + // If the remainder is 0 the gcd is n right away. + uint256 remainder = a % n; + uint256 gcd = n; + + // Therefore the initial coefficients are: + // ax + ny = gcd(a, n) = n + // 0a + 1n = n + int256 x = 0; + int256 y = 1; + + while (remainder != 0) { + uint256 quotient = gcd / remainder; + + (gcd, remainder) = ( + // The old remainder is the next gcd to try. + remainder, + // Compute the next remainder. + // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd + // where gcd is at most n (capped to type(uint256).max) + gcd - remainder * quotient + ); + + (x, y) = ( + // Increment the coefficient of a. + y, + // Decrement the coefficient of n. + // Can overflow, but the result is casted to uint256 so that the + // next value of y is "wrapped around" to a value between 0 and n - 1. + x - y * int256(quotient) + ); + } + + if (gcd != 1) return 0; // No inverse exists. + return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative. + } + } + + /** + * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`. + * + * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is + * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that + * `a**(p-2)` is the modular multiplicative inverse of a in Fp. + * + * NOTE: this function does NOT check that `p` is a prime greater than `2`. + */ + function invModPrime(uint256 a, uint256 p) internal view returns (uint256) { + unchecked { + return Math.modExp(a, p - 2, p); + } + } + + /** + * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m) + * + * Requirements: + * - modulus can't be zero + * - underlying staticcall to precompile must succeed + * + * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make + * sure the chain you're using it on supports the precompiled contract for modular exponentiation + * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, + * the underlying function will succeed given the lack of a revert, but the result may be incorrectly + * interpreted as 0. + */ + function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) { + (bool success, uint256 result) = tryModExp(b, e, m); + if (!success) { + Panic.panic(Panic.DIVISION_BY_ZERO); + } + return result; + } + + /** + * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m). + * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying + * to operate modulo 0 or if the underlying precompile reverted. + * + * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain + * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in + * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack + * of a revert, but the result may be incorrectly interpreted as 0. + */ + function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) { + if (m == 0) return (false, 0); + assembly ("memory-safe") { + let ptr := mload(0x40) + // | Offset | Content | Content (Hex) | + // |-----------|------------|--------------------------------------------------------------------| + // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 | + // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 | + // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 | + // | 0x60:0x7f | value of b | 0x<.............................................................b> | + // | 0x80:0x9f | value of e | 0x<.............................................................e> | + // | 0xa0:0xbf | value of m | 0x<.............................................................m> | + mstore(ptr, 0x20) + mstore(add(ptr, 0x20), 0x20) + mstore(add(ptr, 0x40), 0x20) + mstore(add(ptr, 0x60), b) + mstore(add(ptr, 0x80), e) + mstore(add(ptr, 0xa0), m) + + // Given the result < m, it's guaranteed to fit in 32 bytes, + // so we can use the memory scratch space located at offset 0. + success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20) + result := mload(0x00) + } + } + + /** + * @dev Variant of {modExp} that supports inputs of arbitrary length. + */ + function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) { + (bool success, bytes memory result) = tryModExp(b, e, m); + if (!success) { + Panic.panic(Panic.DIVISION_BY_ZERO); + } + return result; + } + + /** + * @dev Variant of {tryModExp} that supports inputs of arbitrary length. + */ + function tryModExp( + bytes memory b, + bytes memory e, + bytes memory m + ) internal view returns (bool success, bytes memory result) { + if (_zeroBytes(m)) return (false, new bytes(0)); + + uint256 mLen = m.length; + + // Encode call args in result and move the free memory pointer + result = abi.encodePacked(b.length, e.length, mLen, b, e, m); + + assembly ("memory-safe") { + let dataPtr := add(result, 0x20) + // Write result on top of args to avoid allocating extra memory. + success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen) + // Overwrite the length. + // result.length > returndatasize() is guaranteed because returndatasize() == m.length + mstore(result, mLen) + // Set the memory pointer after the returned data. + mstore(0x40, add(dataPtr, mLen)) + } + } + + /** + * @dev Returns whether the provided byte array is zero. + */ + function _zeroBytes(bytes memory byteArray) private pure returns (bool) { + for (uint256 i = 0; i < byteArray.length; ++i) { + if (byteArray[i] != 0) { + return false; + } + } + return true; + } + + /** + * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded + * towards zero. + * + * This method is based on Newton's method for computing square roots; the algorithm is restricted to only + * using integer operations. + */ + function sqrt(uint256 a) internal pure returns (uint256) { + unchecked { + // Take care of easy edge cases when a == 0 or a == 1 + if (a <= 1) { + return a; + } + + // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a + // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between + // the current value as `ε_n = | x_n - sqrt(a) |`. + // + // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root + // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is + // bigger than any uint256. + // + // By noticing that + // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)` + // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar + // to the msb function. + uint256 aa = a; + uint256 xn = 1; + + if (aa >= (1 << 128)) { + aa >>= 128; + xn <<= 64; + } + if (aa >= (1 << 64)) { + aa >>= 64; + xn <<= 32; + } + if (aa >= (1 << 32)) { + aa >>= 32; + xn <<= 16; + } + if (aa >= (1 << 16)) { + aa >>= 16; + xn <<= 8; + } + if (aa >= (1 << 8)) { + aa >>= 8; + xn <<= 4; + } + if (aa >= (1 << 4)) { + aa >>= 4; + xn <<= 2; + } + if (aa >= (1 << 2)) { + xn <<= 1; + } + + // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1). + // + // We can refine our estimation by noticing that the middle of that interval minimizes the error. + // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2). + // This is going to be our x_0 (and ε_0) + xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2) + + // From here, Newton's method give us: + // x_{n+1} = (x_n + a / x_n) / 2 + // + // One should note that: + // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a + // = ((x_n² + a) / (2 * x_n))² - a + // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a + // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²) + // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²) + // = (x_n² - a)² / (2 * x_n)² + // = ((x_n² - a) / (2 * x_n))² + // ≥ 0 + // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n + // + // This gives us the proof of quadratic convergence of the sequence: + // ε_{n+1} = | x_{n+1} - sqrt(a) | + // = | (x_n + a / x_n) / 2 - sqrt(a) | + // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) | + // = | (x_n - sqrt(a))² / (2 * x_n) | + // = | ε_n² / (2 * x_n) | + // = ε_n² / | (2 * x_n) | + // + // For the first iteration, we have a special case where x_0 is known: + // ε_1 = ε_0² / | (2 * x_0) | + // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2))) + // ≤ 2**(2*e-4) / (3 * 2**(e-1)) + // ≤ 2**(e-3) / 3 + // ≤ 2**(e-3-log2(3)) + // ≤ 2**(e-4.5) + // + // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n: + // ε_{n+1} = ε_n² / | (2 * x_n) | + // ≤ (2**(e-k))² / (2 * 2**(e-1)) + // ≤ 2**(2*e-2*k) / 2**e + // ≤ 2**(e-2*k) + xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above + xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5 + xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9 + xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18 + xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36 + xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72 + + // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision + // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either + // sqrt(a) or sqrt(a) + 1. + return xn - SafeCast.toUint(xn > a / xn); + } + } + + /** + * @dev 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a); + } + } + + /** + * @dev Return the log in base 2 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log2(uint256 x) internal pure returns (uint256 r) { + // If value has upper 128 bits set, log2 result is at least 128 + r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7; + // If upper 64 bits of 128-bit half set, add 64 to result + r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6; + // If upper 32 bits of 64-bit half set, add 32 to result + r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5; + // If upper 16 bits of 32-bit half set, add 16 to result + r |= SafeCast.toUint((x >> r) > 0xffff) << 4; + // If upper 8 bits of 16-bit half set, add 8 to result + r |= SafeCast.toUint((x >> r) > 0xff) << 3; + // If upper 4 bits of 8-bit half set, add 4 to result + r |= SafeCast.toUint((x >> r) > 0xf) << 2; + + // Shifts value right by the current result and use it as an index into this lookup table: + // + // | x (4 bits) | index | table[index] = MSB position | + // |------------|---------|-----------------------------| + // | 0000 | 0 | table[0] = 0 | + // | 0001 | 1 | table[1] = 0 | + // | 0010 | 2 | table[2] = 1 | + // | 0011 | 3 | table[3] = 1 | + // | 0100 | 4 | table[4] = 2 | + // | 0101 | 5 | table[5] = 2 | + // | 0110 | 6 | table[6] = 2 | + // | 0111 | 7 | table[7] = 2 | + // | 1000 | 8 | table[8] = 3 | + // | 1001 | 9 | table[9] = 3 | + // | 1010 | 10 | table[10] = 3 | + // | 1011 | 11 | table[11] = 3 | + // | 1100 | 12 | table[12] = 3 | + // | 1101 | 13 | table[13] = 3 | + // | 1110 | 14 | table[14] = 3 | + // | 1111 | 15 | table[15] = 3 | + // + // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes. + assembly ("memory-safe") { + r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000)) + } + } + + /** + * @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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value); + } + } + + /** + * @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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value); + } + } + + /** + * @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 x) internal pure returns (uint256 r) { + // If value has upper 128 bits set, log2 result is at least 128 + r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7; + // If upper 64 bits of 128-bit half set, add 64 to result + r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6; + // If upper 32 bits of 64-bit half set, add 32 to result + r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5; + // If upper 16 bits of 32-bit half set, add 16 to result + r |= SafeCast.toUint((x >> r) > 0xffff) << 4; + // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8 + return (r >> 3) | SafeCast.toUint((x >> r) > 0xff); + } + + /** + * @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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value); + } + } + + /** + * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol new file mode 100644 index 0000000..b345ede --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol @@ -0,0 +1,1162 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.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/bool 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); + } + + /** + * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. + */ + function toUint(bool b) internal pure returns (uint256 u) { + assembly ("memory-safe") { + u := iszero(iszero(b)) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol new file mode 100644 index 0000000..7c97aa4 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol) + +pragma solidity ^0.8.20; + +import {SafeCast} from "./SafeCast.sol"; + +/** + * @dev Standard signed math utilities missing in the Solidity language. + */ +library SignedMath { + /** + * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. + * + * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. + * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute + * one branch when needed, making this function more expensive. + */ + function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) { + unchecked { + // branchless ternary works because: + // b ^ (a ^ b) == a + // b ^ 0 == b + return b ^ ((a ^ b) * int256(SafeCast.toUint(condition))); + } + } + + /** + * @dev Returns the largest of two signed numbers. + */ + function max(int256 a, int256 b) internal pure returns (int256) { + return ternary(a > b, a, b); + } + + /** + * @dev Returns the smallest of two signed numbers. + */ + function min(int256 a, int256 b) internal pure returns (int256) { + return ternary(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 { + // Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson. + // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift, + // taking advantage of the most significant (or "sign" bit) in two's complement representation. + // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result, + // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative). + int256 mask = n >> 255; + + // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it. + return uint256((n + mask) ^ mask); + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol new file mode 100644 index 0000000..40cceb9 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol new file mode 100644 index 0000000..ce88f51 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol @@ -0,0 +1,630 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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 oldValue, uint224 newValue) { + 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 optimized 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 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoints. + */ + 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 oldValue, uint224 newValue) { + uint256 pos = self.length; + + if (pos > 0) { + Checkpoint224 storage last = _unsafeAccess(self, pos - 1); + uint32 lastKey = last._key; + uint224 lastValue = last._value; + + // Checkpoint keys must be non-decreasing. + if (lastKey > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (lastKey == key) { + last._value = value; + } else { + self.push(Checkpoint224({_key: key, _value: value})); + } + return (lastValue, value); + } else { + self.push(Checkpoint224({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the first (oldest) checkpoint with key strictly bigger 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 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 oldValue, uint208 newValue) { + 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 optimized 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 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoints. + */ + 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 oldValue, uint208 newValue) { + uint256 pos = self.length; + + if (pos > 0) { + Checkpoint208 storage last = _unsafeAccess(self, pos - 1); + uint48 lastKey = last._key; + uint208 lastValue = last._value; + + // Checkpoint keys must be non-decreasing. + if (lastKey > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (lastKey == key) { + last._value = value; + } else { + self.push(Checkpoint208({_key: key, _value: value})); + } + return (lastValue, value); + } else { + self.push(Checkpoint208({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the first (oldest) checkpoint with key strictly bigger 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 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 oldValue, uint160 newValue) { + 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 optimized 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 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoints. + */ + 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 oldValue, uint160 newValue) { + uint256 pos = self.length; + + if (pos > 0) { + Checkpoint160 storage last = _unsafeAccess(self, pos - 1); + uint96 lastKey = last._key; + uint160 lastValue = last._value; + + // Checkpoint keys must be non-decreasing. + if (lastKey > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (lastKey == key) { + last._value = value; + } else { + self.push(Checkpoint160({_key: key, _value: value})); + } + return (lastValue, value); + } else { + self.push(Checkpoint160({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the first (oldest) checkpoint with key strictly bigger 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 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/CircularBuffer.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/CircularBuffer.sol new file mode 100644 index 0000000..43ce89b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/CircularBuffer.sol @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/CircularBuffer.sol) +pragma solidity ^0.8.20; + +import {Math} from "../math/Math.sol"; +import {Arrays} from "../Arrays.sol"; +import {Panic} from "../Panic.sol"; + +/** + * @dev A fixed-size buffer for keeping `bytes32` items in storage. + * + * This data structure allows for pushing elements to it, and when its length exceeds the specified fixed size, + * new items take the place of the oldest element in the buffer, keeping at most `N` elements in the + * structure. + * + * Elements can't be removed but the data structure can be cleared. See {clear}. + * + * Complexity: + * - insertion ({push}): O(1) + * - lookup ({last}): O(1) + * - inclusion ({includes}): O(N) (worst case) + * - reset ({clear}): O(1) + * + * * The struct is called `Bytes32CircularBuffer`. Other types can be cast to and from `bytes32`. This data structure + * can only be used in storage, and not in memory. + * + * Example usage: + * + * ```solidity + * contract Example { + * // Add the library methods + * using CircularBuffer for CircularBuffer.Bytes32CircularBuffer; + * + * // Declare a buffer storage variable + * CircularBuffer.Bytes32CircularBuffer private myBuffer; + * } + * ``` + * + * _Available since v5.1._ + */ +library CircularBuffer { + /** + * @dev Error emitted when trying to setup a buffer with a size of 0. + */ + error InvalidBufferSize(); + + /** + * @dev Counts the number of items that have been pushed to the buffer. The residuo modulo _data.length indicates + * where the next value should be stored. + * + * 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. + * + * In a full buffer: + * - The most recently pushed item (last) is at data[(index - 1) % data.length] + * - The oldest item (first) is at data[index % data.length] + */ + struct Bytes32CircularBuffer { + uint256 _count; + bytes32[] _data; + } + + /** + * @dev Initialize a new CircularBuffer of a given size. + * + * If the CircularBuffer was already setup and used, calling that function again will reset it to a blank state. + * + * NOTE: The size of the buffer will affect the execution of {includes} function, as it has a complexity of O(N). + * Consider a large buffer size may render the function unusable. + */ + function setup(Bytes32CircularBuffer storage self, uint256 size) internal { + if (size == 0) revert InvalidBufferSize(); + clear(self); + Arrays.unsafeSetLength(self._data, size); + } + + /** + * @dev Clear all data in the buffer without resetting memory, keeping the existing size. + */ + function clear(Bytes32CircularBuffer storage self) internal { + self._count = 0; + } + + /** + * @dev Push a new value to the buffer. If the buffer is already full, the new value replaces the oldest value in + * the buffer. + */ + function push(Bytes32CircularBuffer storage self, bytes32 value) internal { + uint256 index = self._count++; + uint256 modulus = self._data.length; + Arrays.unsafeAccess(self._data, index % modulus).value = value; + } + + /** + * @dev Number of values currently in the buffer. This value is 0 for an empty buffer, and cannot exceed the size of + * the buffer. + */ + function count(Bytes32CircularBuffer storage self) internal view returns (uint256) { + return Math.min(self._count, self._data.length); + } + + /** + * @dev Length of the buffer. This is the maximum number of elements kept in the buffer. + */ + function length(Bytes32CircularBuffer storage self) internal view returns (uint256) { + return self._data.length; + } + + /** + * @dev Getter for the i-th value in the buffer, from the end. + * + * Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if trying to access an element that was not pushed, or that was + * dropped to make room for newer elements. + */ + function last(Bytes32CircularBuffer storage self, uint256 i) internal view returns (bytes32) { + uint256 index = self._count; + uint256 modulus = self._data.length; + uint256 total = Math.min(index, modulus); // count(self) + if (i >= total) { + Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS); + } + return Arrays.unsafeAccess(self._data, (index - i - 1) % modulus).value; + } + + /** + * @dev Check if a given value is in the buffer. + */ + function includes(Bytes32CircularBuffer storage self, bytes32 value) internal view returns (bool) { + uint256 index = self._count; + uint256 modulus = self._data.length; + uint256 total = Math.min(index, modulus); // count(self) + for (uint256 i = 0; i < total; ++i) { + if (Arrays.unsafeAccess(self._data, (index - i - 1) % modulus).value == value) { + return true; + } + } + return false; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol new file mode 100644 index 0000000..f243243 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/DoubleEndedQueue.sol) +pragma solidity ^0.8.20; + +import {Panic} from "../Panic.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; + * ``` + */ +library DoubleEndedQueue { + /** + * @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 {Panic-RESOURCE_ERROR} if the queue is full. + */ + function pushBack(Bytes32Deque storage deque, bytes32 value) internal { + unchecked { + uint128 backIndex = deque._end; + if (backIndex + 1 == deque._begin) Panic.panic(Panic.RESOURCE_ERROR); + deque._data[backIndex] = value; + deque._end = backIndex + 1; + } + } + + /** + * @dev Removes the item at the end of the queue and returns it. + * + * Reverts with {Panic-EMPTY_ARRAY_POP} if the queue is empty. + */ + function popBack(Bytes32Deque storage deque) internal returns (bytes32 value) { + unchecked { + uint128 backIndex = deque._end; + if (backIndex == deque._begin) Panic.panic(Panic.EMPTY_ARRAY_POP); + --backIndex; + value = deque._data[backIndex]; + delete deque._data[backIndex]; + deque._end = backIndex; + } + } + + /** + * @dev Inserts an item at the beginning of the queue. + * + * Reverts with {Panic-RESOURCE_ERROR} if the queue is full. + */ + function pushFront(Bytes32Deque storage deque, bytes32 value) internal { + unchecked { + uint128 frontIndex = deque._begin - 1; + if (frontIndex == deque._end) Panic.panic(Panic.RESOURCE_ERROR); + deque._data[frontIndex] = value; + deque._begin = frontIndex; + } + } + + /** + * @dev Removes the item at the beginning of the queue and returns it. + * + * Reverts with {Panic-EMPTY_ARRAY_POP} if the queue is empty. + */ + function popFront(Bytes32Deque storage deque) internal returns (bytes32 value) { + unchecked { + uint128 frontIndex = deque._begin; + if (frontIndex == deque._end) Panic.panic(Panic.EMPTY_ARRAY_POP); + value = deque._data[frontIndex]; + delete deque._data[frontIndex]; + deque._begin = frontIndex + 1; + } + } + + /** + * @dev Returns the item at the beginning of the queue. + * + * Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the queue is empty. + */ + function front(Bytes32Deque storage deque) internal view returns (bytes32 value) { + if (empty(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS); + return deque._data[deque._begin]; + } + + /** + * @dev Returns the item at the end of the queue. + * + * Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the queue is empty. + */ + function back(Bytes32Deque storage deque) internal view returns (bytes32 value) { + if (empty(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS); + 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 {Panic-ARRAY_OUT_OF_BOUNDS} if the index is out of bounds. + */ + function at(Bytes32Deque storage deque, uint256 index) internal view returns (bytes32 value) { + if (index >= length(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS); + // 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol new file mode 100644 index 0000000..68ce322 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol @@ -0,0 +1,1319 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.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. + * - Map can be cleared (all entries removed) in O(n). + * + * ```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 + * - `uint256 -> bytes32` (`UintToBytes32Map`) since v5.1.0 + * - `address -> address` (`AddressToAddressMap`) since v5.1.0 + * - `address -> bytes32` (`AddressToBytes32Map`) since v5.1.0 + * - `bytes32 -> address` (`Bytes32ToAddressMap`) since v5.1.0 + * - `bytes -> bytes` (`BytesToBytesMap`) since v5.4.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 *; + + // 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 Removes all the entries from a map. O(n). + * + * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the + * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block. + */ + function clear(Bytes32ToBytes32Map storage map) internal { + uint256 len = length(map); + for (uint256 i = 0; i < len; ++i) { + delete map._values[map._keys.at(i)]; + } + map._keys.clear(); + } + + /** + * @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 key, bytes32 value) { + bytes32 atKey = map._keys.at(index); + return (atKey, map._values[atKey]); + } + + /** + * @dev Tries to return the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool exists, bytes32 value) { + bytes32 val = map._values[key]; + if (val == bytes32(0)) { + return (contains(map, key), bytes32(0)); + } else { + return (true, val); + } + } + + /** + * @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 Returns an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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(); + } + + /** + * @dev Returns an array containing a slice of the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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, + uint256 start, + uint256 end + ) internal view returns (bytes32[] memory) { + return map._keys.values(start, end); + } + + // 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 Removes all the entries from a map. O(n). + * + * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that + * using it may render the function uncallable if the map grows to the point where clearing it consumes too much + * gas to fit in a block. + */ + function clear(UintToUintMap storage map) internal { + clear(map._inner); + } + + /** + * @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 key, uint256 value) { + (bytes32 atKey, bytes32 val) = at(map._inner, index); + return (uint256(atKey), uint256(val)); + } + + /** + * @dev Tries to return the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool exists, uint256 value) { + (bool success, bytes32 val) = tryGet(map._inner, bytes32(key)); + return (success, uint256(val)); + } + + /** + * @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 Returns an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + /** + * @dev Returns an array containing a slice of the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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, uint256 start, uint256 end) internal view returns (uint256[] memory) { + bytes32[] memory store = keys(map._inner, start, end); + uint256[] memory result; + + assembly ("memory-safe") { + 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 Removes all the entries from a map. O(n). + * + * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that + * using it may render the function uncallable if the map grows to the point where clearing it consumes too much + * gas to fit in a block. + */ + function clear(UintToAddressMap storage map) internal { + clear(map._inner); + } + + /** + * @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 key, address value) { + (bytes32 atKey, bytes32 val) = at(map._inner, index); + return (uint256(atKey), address(uint160(uint256(val)))); + } + + /** + * @dev Tries to return the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool exists, address value) { + (bool success, bytes32 val) = tryGet(map._inner, bytes32(key)); + return (success, address(uint160(uint256(val)))); + } + + /** + * @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 Returns an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + /** + * @dev Returns an array containing a slice of the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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, uint256 start, uint256 end) internal view returns (uint256[] memory) { + bytes32[] memory store = keys(map._inner, start, end); + uint256[] memory result; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + // UintToBytes32Map + + struct UintToBytes32Map { + 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(UintToBytes32Map storage map, uint256 key, bytes32 value) internal returns (bool) { + return set(map._inner, bytes32(key), 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(UintToBytes32Map storage map, uint256 key) internal returns (bool) { + return remove(map._inner, bytes32(key)); + } + + /** + * @dev Removes all the entries from a map. O(n). + * + * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that + * using it may render the function uncallable if the map grows to the point where clearing it consumes too much + * gas to fit in a block. + */ + function clear(UintToBytes32Map storage map) internal { + clear(map._inner); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(UintToBytes32Map 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(UintToBytes32Map 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(UintToBytes32Map storage map, uint256 index) internal view returns (uint256 key, bytes32 value) { + (bytes32 atKey, bytes32 val) = at(map._inner, index); + return (uint256(atKey), val); + } + + /** + * @dev Tries to return the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(UintToBytes32Map storage map, uint256 key) internal view returns (bool exists, bytes32 value) { + (bool success, bytes32 val) = tryGet(map._inner, bytes32(key)); + return (success, val); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(UintToBytes32Map storage map, uint256 key) internal view returns (bytes32) { + return get(map._inner, bytes32(key)); + } + + /** + * @dev Returns an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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(UintToBytes32Map storage map) internal view returns (uint256[] memory) { + bytes32[] memory store = keys(map._inner); + uint256[] memory result; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + /** + * @dev Returns an array containing a slice of the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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(UintToBytes32Map storage map, uint256 start, uint256 end) internal view returns (uint256[] memory) { + bytes32[] memory store = keys(map._inner, start, end); + uint256[] memory result; + + assembly ("memory-safe") { + 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 Removes all the entries from a map. O(n). + * + * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that + * using it may render the function uncallable if the map grows to the point where clearing it consumes too much + * gas to fit in a block. + */ + function clear(AddressToUintMap storage map) internal { + clear(map._inner); + } + + /** + * @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 key, uint256 value) { + (bytes32 atKey, bytes32 val) = at(map._inner, index); + return (address(uint160(uint256(atKey))), uint256(val)); + } + + /** + * @dev Tries to return the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(AddressToUintMap storage map, address key) internal view returns (bool exists, uint256 value) { + (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key)))); + return (success, uint256(val)); + } + + /** + * @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 Returns an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + /** + * @dev Returns an array containing a slice of the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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, uint256 start, uint256 end) internal view returns (address[] memory) { + bytes32[] memory store = keys(map._inner, start, end); + address[] memory result; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + // AddressToAddressMap + + struct AddressToAddressMap { + 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(AddressToAddressMap storage map, address key, address value) internal returns (bool) { + return set(map._inner, bytes32(uint256(uint160(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(AddressToAddressMap storage map, address key) internal returns (bool) { + return remove(map._inner, bytes32(uint256(uint160(key)))); + } + + /** + * @dev Removes all the entries from a map. O(n). + * + * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that + * using it may render the function uncallable if the map grows to the point where clearing it consumes too much + * gas to fit in a block. + */ + function clear(AddressToAddressMap storage map) internal { + clear(map._inner); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(AddressToAddressMap 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(AddressToAddressMap 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(AddressToAddressMap storage map, uint256 index) internal view returns (address key, address value) { + (bytes32 atKey, bytes32 val) = at(map._inner, index); + return (address(uint160(uint256(atKey))), address(uint160(uint256(val)))); + } + + /** + * @dev Tries to return the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(AddressToAddressMap storage map, address key) internal view returns (bool exists, address value) { + (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key)))); + return (success, address(uint160(uint256(val)))); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(AddressToAddressMap storage map, address key) internal view returns (address) { + return address(uint160(uint256(get(map._inner, bytes32(uint256(uint160(key))))))); + } + + /** + * @dev Returns an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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(AddressToAddressMap storage map) internal view returns (address[] memory) { + bytes32[] memory store = keys(map._inner); + address[] memory result; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + /** + * @dev Returns an array containing a slice of the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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( + AddressToAddressMap storage map, + uint256 start, + uint256 end + ) internal view returns (address[] memory) { + bytes32[] memory store = keys(map._inner, start, end); + address[] memory result; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + // AddressToBytes32Map + + struct AddressToBytes32Map { + 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(AddressToBytes32Map storage map, address key, bytes32 value) internal returns (bool) { + return set(map._inner, bytes32(uint256(uint160(key))), 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(AddressToBytes32Map storage map, address key) internal returns (bool) { + return remove(map._inner, bytes32(uint256(uint160(key)))); + } + + /** + * @dev Removes all the entries from a map. O(n). + * + * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that + * using it may render the function uncallable if the map grows to the point where clearing it consumes too much + * gas to fit in a block. + */ + function clear(AddressToBytes32Map storage map) internal { + clear(map._inner); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(AddressToBytes32Map 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(AddressToBytes32Map 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(AddressToBytes32Map storage map, uint256 index) internal view returns (address key, bytes32 value) { + (bytes32 atKey, bytes32 val) = at(map._inner, index); + return (address(uint160(uint256(atKey))), val); + } + + /** + * @dev Tries to return the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(AddressToBytes32Map storage map, address key) internal view returns (bool exists, bytes32 value) { + (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key)))); + return (success, val); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(AddressToBytes32Map storage map, address key) internal view returns (bytes32) { + return get(map._inner, bytes32(uint256(uint160(key)))); + } + + /** + * @dev Returns an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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(AddressToBytes32Map storage map) internal view returns (address[] memory) { + bytes32[] memory store = keys(map._inner); + address[] memory result; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + /** + * @dev Returns an array containing a slice of the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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( + AddressToBytes32Map storage map, + uint256 start, + uint256 end + ) internal view returns (address[] memory) { + bytes32[] memory store = keys(map._inner, start, end); + address[] memory result; + + assembly ("memory-safe") { + 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 Removes all the entries from a map. O(n). + * + * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that + * using it may render the function uncallable if the map grows to the point where clearing it consumes too much + * gas to fit in a block. + */ + function clear(Bytes32ToUintMap storage map) internal { + clear(map._inner); + } + + /** + * @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 key, uint256 value) { + (bytes32 atKey, bytes32 val) = at(map._inner, index); + return (atKey, uint256(val)); + } + + /** + * @dev Tries to return the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool exists, uint256 value) { + (bool success, bytes32 val) = tryGet(map._inner, key); + return (success, uint256(val)); + } + + /** + * @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 Returns an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + /** + * @dev Returns an array containing a slice of the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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, uint256 start, uint256 end) internal view returns (bytes32[] memory) { + bytes32[] memory store = keys(map._inner, start, end); + bytes32[] memory result; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + // Bytes32ToAddressMap + + struct Bytes32ToAddressMap { + 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(Bytes32ToAddressMap storage map, bytes32 key, address value) internal returns (bool) { + return set(map._inner, 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(Bytes32ToAddressMap storage map, bytes32 key) internal returns (bool) { + return remove(map._inner, key); + } + + /** + * @dev Removes all the entries from a map. O(n). + * + * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that + * using it may render the function uncallable if the map grows to the point where clearing it consumes too much + * gas to fit in a block. + */ + function clear(Bytes32ToAddressMap storage map) internal { + clear(map._inner); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(Bytes32ToAddressMap 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(Bytes32ToAddressMap 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(Bytes32ToAddressMap storage map, uint256 index) internal view returns (bytes32 key, address value) { + (bytes32 atKey, bytes32 val) = at(map._inner, index); + return (atKey, address(uint160(uint256(val)))); + } + + /** + * @dev Tries to return the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (bool exists, address value) { + (bool success, bytes32 val) = tryGet(map._inner, key); + return (success, address(uint160(uint256(val)))); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (address) { + return address(uint160(uint256(get(map._inner, key)))); + } + + /** + * @dev Returns an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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(Bytes32ToAddressMap storage map) internal view returns (bytes32[] memory) { + bytes32[] memory store = keys(map._inner); + bytes32[] memory result; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + /** + * @dev Returns an array containing a slice of the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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( + Bytes32ToAddressMap storage map, + uint256 start, + uint256 end + ) internal view returns (bytes32[] memory) { + bytes32[] memory store = keys(map._inner, start, end); + bytes32[] memory result; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + /** + * @dev Query for a nonexistent map key. + */ + error EnumerableMapNonexistentBytesKey(bytes key); + + struct BytesToBytesMap { + // Storage of keys + EnumerableSet.BytesSet _keys; + mapping(bytes key => bytes) _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(BytesToBytesMap storage map, bytes memory key, bytes memory 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(BytesToBytesMap storage map, bytes memory key) internal returns (bool) { + delete map._values[key]; + return map._keys.remove(key); + } + + /** + * @dev Removes all the entries from a map. O(n). + * + * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the + * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block. + */ + function clear(BytesToBytesMap storage map) internal { + uint256 len = length(map); + for (uint256 i = 0; i < len; ++i) { + delete map._values[map._keys.at(i)]; + } + map._keys.clear(); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(BytesToBytesMap storage map, bytes memory 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(BytesToBytesMap 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( + BytesToBytesMap storage map, + uint256 index + ) internal view returns (bytes memory key, bytes memory value) { + key = map._keys.at(index); + value = map._values[key]; + } + + /** + * @dev Tries to return the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet( + BytesToBytesMap storage map, + bytes memory key + ) internal view returns (bool exists, bytes memory value) { + value = map._values[key]; + exists = bytes(value).length != 0 || contains(map, key); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(BytesToBytesMap storage map, bytes memory key) internal view returns (bytes memory value) { + bool exists; + (exists, value) = tryGet(map, key); + if (!exists) { + revert EnumerableMapNonexistentBytesKey(key); + } + } + + /** + * @dev Returns an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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(BytesToBytesMap storage map) internal view returns (bytes[] memory) { + return map._keys.values(); + } + + /** + * @dev Returns an array containing a slice of the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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(BytesToBytesMap storage map, uint256 start, uint256 end) internal view returns (bytes[] memory) { + return map._keys.values(start, end); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol new file mode 100644 index 0000000..fbf742a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol @@ -0,0 +1,792 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/structs/EnumerableSet.sol) +// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. + +pragma solidity ^0.8.20; + +import {Arrays} from "../Arrays.sol"; +import {Math} from "../math/Math.sol"; + +/** + * @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. + * - Set can be cleared (all elements removed) in O(n). + * + * ```solidity + * contract Example { + * // Add the library methods + * using EnumerableSet for EnumerableSet.AddressSet; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * ``` + * + * The following types are supported: + * + * - `bytes32` (`Bytes32Set`) since v3.3.0 + * - `address` (`AddressSet`) since v3.3.0 + * - `uint256` (`UintSet`) since v3.3.0 + * - `string` (`StringSet`) since v5.4.0 + * - `bytes` (`BytesSet`) since v5.4.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 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 Removes all the values from a set. O(n). + * + * WARNING: This function has an unbounded cost that scales with set size. Developers should keep in mind that + * using it may render the function uncallable if the set grows to the point where clearing it consumes too much + * gas to fit in a block. + */ + function _clear(Set storage set) private { + uint256 len = _length(set); + for (uint256 i = 0; i < len; ++i) { + delete set._positions[set._values[i]]; + } + Arrays.unsafeSetLength(set._values, 0); + } + + /** + * @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; + } + + /** + * @dev Return a slice of the 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, uint256 start, uint256 end) private view returns (bytes32[] memory) { + unchecked { + end = Math.min(end, _length(set)); + start = Math.min(start, end); + + uint256 len = end - start; + bytes32[] memory result = new bytes32[](len); + for (uint256 i = 0; i < len; ++i) { + result[i] = Arrays.unsafeAccess(set._values, start + i).value; + } + return result; + } + } + + // 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 Removes all the values from a set. O(n). + * + * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the + * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. + */ + function clear(Bytes32Set storage set) internal { + _clear(set._inner); + } + + /** + * @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; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + /** + * @dev Return a slice of the 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, uint256 start, uint256 end) internal view returns (bytes32[] memory) { + bytes32[] memory store = _values(set._inner, start, end); + bytes32[] memory result; + + assembly ("memory-safe") { + 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 Removes all the values from a set. O(n). + * + * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the + * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. + */ + function clear(AddressSet storage set) internal { + _clear(set._inner); + } + + /** + * @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; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + /** + * @dev Return a slice of the 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, uint256 start, uint256 end) internal view returns (address[] memory) { + bytes32[] memory store = _values(set._inner, start, end); + address[] memory result; + + assembly ("memory-safe") { + 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 Removes all the values from a set. O(n). + * + * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the + * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. + */ + function clear(UintSet storage set) internal { + _clear(set._inner); + } + + /** + * @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; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + /** + * @dev Return a slice of the 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, uint256 start, uint256 end) internal view returns (uint256[] memory) { + bytes32[] memory store = _values(set._inner, start, end); + uint256[] memory result; + + assembly ("memory-safe") { + result := store + } + + return result; + } + + struct StringSet { + // Storage of set values + string[] _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(string 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(StringSet storage set, string memory value) internal returns (bool) { + if (!contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + 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(StringSet storage set, string memory value) internal returns (bool) { + // We cache the value's position to prevent multiple reads from the same storage slot + uint256 position = 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) { + string memory 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 Removes all the values from a set. O(n). + * + * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the + * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. + */ + function clear(StringSet storage set) internal { + uint256 len = length(set); + for (uint256 i = 0; i < len; ++i) { + delete set._positions[set._values[i]]; + } + Arrays.unsafeSetLength(set._values, 0); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(StringSet storage set, string memory value) internal view returns (bool) { + return set._positions[value] != 0; + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function length(StringSet storage set) internal 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(StringSet storage set, uint256 index) internal view returns (string memory) { + 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(StringSet storage set) internal view returns (string[] memory) { + return set._values; + } + + /** + * @dev Return a slice of the 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(StringSet storage set, uint256 start, uint256 end) internal view returns (string[] memory) { + unchecked { + end = Math.min(end, length(set)); + start = Math.min(start, end); + + uint256 len = end - start; + string[] memory result = new string[](len); + for (uint256 i = 0; i < len; ++i) { + result[i] = Arrays.unsafeAccess(set._values, start + i).value; + } + return result; + } + } + + struct BytesSet { + // Storage of set values + bytes[] _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(bytes 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(BytesSet storage set, bytes memory value) internal returns (bool) { + if (!contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + 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(BytesSet storage set, bytes memory value) internal returns (bool) { + // We cache the value's position to prevent multiple reads from the same storage slot + uint256 position = 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) { + bytes memory 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 Removes all the values from a set. O(n). + * + * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the + * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. + */ + function clear(BytesSet storage set) internal { + uint256 len = length(set); + for (uint256 i = 0; i < len; ++i) { + delete set._positions[set._values[i]]; + } + Arrays.unsafeSetLength(set._values, 0); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(BytesSet storage set, bytes memory value) internal view returns (bool) { + return set._positions[value] != 0; + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function length(BytesSet storage set) internal 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(BytesSet storage set, uint256 index) internal view returns (bytes memory) { + 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(BytesSet storage set) internal view returns (bytes[] memory) { + return set._values; + } + + /** + * @dev Return a slice of the 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(BytesSet storage set, uint256 start, uint256 end) internal view returns (bytes[] memory) { + unchecked { + end = Math.min(end, length(set)); + start = Math.min(start, end); + + uint256 len = end - start; + bytes[] memory result = new bytes[](len); + for (uint256 i = 0; i < len; ++i) { + result[i] = Arrays.unsafeAccess(set._values, start + i).value; + } + return result; + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Heap.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Heap.sol new file mode 100644 index 0000000..c97bb43 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Heap.sol @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/Heap.sol) + +pragma solidity ^0.8.20; + +import {Math} from "../math/Math.sol"; +import {SafeCast} from "../math/SafeCast.sol"; +import {Comparators} from "../Comparators.sol"; +import {Arrays} from "../Arrays.sol"; +import {Panic} from "../Panic.sol"; +import {StorageSlot} from "../StorageSlot.sol"; + +/** + * @dev Library for managing https://en.wikipedia.org/wiki/Binary_heap[binary heap] that can be used as + * https://en.wikipedia.org/wiki/Priority_queue[priority queue]. + * + * Heaps are represented as a tree of values where the first element (index 0) is the root, and where the node at + * index i is the child of the node at index (i-1)/2 and the parent of nodes at index 2*i+1 and 2*i+2. Each node + * stores an element of the heap. + * + * The structure is ordered so that each node is bigger than its parent. An immediate consequence is that the + * highest priority value is the one at the root. This value can be looked up in constant time (O(1)) at + * `heap.tree[0]` + * + * The structure is designed to perform the following operations with the corresponding complexities: + * + * * peek (get the highest priority value): O(1) + * * insert (insert a value): O(log(n)) + * * pop (remove the highest priority value): O(log(n)) + * * replace (replace the highest priority value with a new value): O(log(n)) + * * length (get the number of elements): O(1) + * * clear (remove all elements): O(1) + * + * IMPORTANT: This library allows for the use of custom comparator functions. Given that manipulating + * memory can lead to unexpected behavior. Consider verifying that the comparator does not manipulate + * the Heap's state directly and that it follows the Solidity memory safety rules. + * + * _Available since v5.1._ + */ +library Heap { + using Arrays for *; + using Math for *; + using SafeCast for *; + + /** + * @dev Binary heap that supports values of type uint256. + * + * Each element of that structure uses one storage slot. + */ + struct Uint256Heap { + uint256[] tree; + } + + /** + * @dev Lookup the root element of the heap. + */ + function peek(Uint256Heap storage self) internal view returns (uint256) { + // self.tree[0] will `ARRAY_ACCESS_OUT_OF_BOUNDS` panic if heap is empty. + return self.tree[0]; + } + + /** + * @dev Remove (and return) the root element for the heap using the default comparator. + * + * NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator + * during the lifecycle of a heap will result in undefined behavior. + */ + function pop(Uint256Heap storage self) internal returns (uint256) { + return pop(self, Comparators.lt); + } + + /** + * @dev Remove (and return) the root element for the heap using the provided comparator. + * + * NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator + * during the lifecycle of a heap will result in undefined behavior. + */ + function pop( + Uint256Heap storage self, + function(uint256, uint256) view returns (bool) comp + ) internal returns (uint256) { + unchecked { + uint256 size = length(self); + if (size == 0) Panic.panic(Panic.EMPTY_ARRAY_POP); + + // cache + uint256 rootValue = self.tree.unsafeAccess(0).value; + uint256 lastValue = self.tree.unsafeAccess(size - 1).value; + + // swap last leaf with root, shrink tree and re-heapify + self.tree.pop(); + self.tree.unsafeAccess(0).value = lastValue; + _siftDown(self, size - 1, 0, lastValue, comp); + + return rootValue; + } + } + + /** + * @dev Insert a new element in the heap using the default comparator. + * + * NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator + * during the lifecycle of a heap will result in undefined behavior. + */ + function insert(Uint256Heap storage self, uint256 value) internal { + insert(self, value, Comparators.lt); + } + + /** + * @dev Insert a new element in the heap using the provided comparator. + * + * NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator + * during the lifecycle of a heap will result in undefined behavior. + */ + function insert( + Uint256Heap storage self, + uint256 value, + function(uint256, uint256) view returns (bool) comp + ) internal { + uint256 size = length(self); + + // push new item and re-heapify + self.tree.push(value); + _siftUp(self, size, value, comp); + } + + /** + * @dev Return the root element for the heap, and replace it with a new value, using the default comparator. + * This is equivalent to using {pop} and {insert}, but requires only one rebalancing operation. + * + * NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator + * during the lifecycle of a heap will result in undefined behavior. + */ + function replace(Uint256Heap storage self, uint256 newValue) internal returns (uint256) { + return replace(self, newValue, Comparators.lt); + } + + /** + * @dev Return the root element for the heap, and replace it with a new value, using the provided comparator. + * This is equivalent to using {pop} and {insert}, but requires only one rebalancing operation. + * + * NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator + * during the lifecycle of a heap will result in undefined behavior. + */ + function replace( + Uint256Heap storage self, + uint256 newValue, + function(uint256, uint256) view returns (bool) comp + ) internal returns (uint256) { + uint256 size = length(self); + if (size == 0) Panic.panic(Panic.EMPTY_ARRAY_POP); + + // cache + uint256 oldValue = self.tree.unsafeAccess(0).value; + + // replace and re-heapify + self.tree.unsafeAccess(0).value = newValue; + _siftDown(self, size, 0, newValue, comp); + + return oldValue; + } + + /** + * @dev Returns the number of elements in the heap. + */ + function length(Uint256Heap storage self) internal view returns (uint256) { + return self.tree.length; + } + + /** + * @dev Removes all elements in the heap. + */ + function clear(Uint256Heap storage self) internal { + self.tree.unsafeSetLength(0); + } + + /** + * @dev Swap node `i` and `j` in the tree. + */ + function _swap(Uint256Heap storage self, uint256 i, uint256 j) private { + StorageSlot.Uint256Slot storage ni = self.tree.unsafeAccess(i); + StorageSlot.Uint256Slot storage nj = self.tree.unsafeAccess(j); + (ni.value, nj.value) = (nj.value, ni.value); + } + + /** + * @dev Perform heap maintenance on `self`, starting at `index` (with the `value`), using `comp` as a + * comparator, and moving toward the leaves of the underlying tree. + * + * NOTE: This is a private function that is called in a trusted context with already cached parameters. `size` + * and `value` could be extracted from `self` and `index`, but that would require redundant storage read. These + * parameters are not verified. It is the caller role to make sure the parameters are correct. + */ + function _siftDown( + Uint256Heap storage self, + uint256 size, + uint256 index, + uint256 value, + function(uint256, uint256) view returns (bool) comp + ) private { + unchecked { + // Check if there is a risk of overflow when computing the indices of the child nodes. If that is the case, + // there cannot be child nodes in the tree, so sifting is done. + if (index >= type(uint256).max / 2) return; + + // Compute the indices of the potential child nodes + uint256 lIndex = 2 * index + 1; + uint256 rIndex = 2 * index + 2; + + // Three cases: + // 1. Both children exist: sifting may continue on one of the branch (selection required) + // 2. Only left child exist: sifting may continue on the left branch (no selection required) + // 3. Neither child exist: sifting is done + if (rIndex < size) { + uint256 lValue = self.tree.unsafeAccess(lIndex).value; + uint256 rValue = self.tree.unsafeAccess(rIndex).value; + if (comp(lValue, value) || comp(rValue, value)) { + uint256 cIndex = comp(lValue, rValue).ternary(lIndex, rIndex); + _swap(self, index, cIndex); + _siftDown(self, size, cIndex, value, comp); + } + } else if (lIndex < size) { + uint256 lValue = self.tree.unsafeAccess(lIndex).value; + if (comp(lValue, value)) { + _swap(self, index, lIndex); + _siftDown(self, size, lIndex, value, comp); + } + } + } + } + + /** + * @dev Perform heap maintenance on `self`, starting at `index` (with the `value`), using `comp` as a + * comparator, and moving toward the root of the underlying tree. + * + * NOTE: This is a private function that is called in a trusted context with already cached parameters. `value` + * could be extracted from `self` and `index`, but that would require redundant storage read. These parameters are not + * verified. It is the caller role to make sure the parameters are correct. + */ + function _siftUp( + Uint256Heap storage self, + uint256 index, + uint256 value, + function(uint256, uint256) view returns (bool) comp + ) private { + unchecked { + while (index > 0) { + uint256 parentIndex = (index - 1) / 2; + uint256 parentValue = self.tree.unsafeAccess(parentIndex).value; + if (comp(parentValue, value)) break; + _swap(self, index, parentIndex); + index = parentIndex; + } + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/MerkleTree.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/MerkleTree.sol new file mode 100644 index 0000000..010ccfe --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/MerkleTree.sol @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/MerkleTree.sol) + +pragma solidity ^0.8.20; + +import {Hashes} from "../cryptography/Hashes.sol"; +import {Arrays} from "../Arrays.sol"; +import {Panic} from "../Panic.sol"; +import {StorageSlot} from "../StorageSlot.sol"; + +/** + * @dev Library for managing https://wikipedia.org/wiki/Merkle_Tree[Merkle Tree] data structures. + * + * Each tree is a complete binary tree with the ability to sequentially insert leaves, changing them from a zero to a + * non-zero value and updating its root. This structure allows inserting commitments (or other entries) that are not + * stored, but can be proven to be part of the tree at a later time if the root is kept. See {MerkleProof}. + * + * A tree is defined by the following parameters: + * + * * Depth: The number of levels in the tree, it also defines the maximum number of leaves as 2**depth. + * * Zero value: The value that represents an empty leaf. Used to avoid regular zero values to be part of the tree. + * * Hashing function: A cryptographic hash function used to produce internal nodes. Defaults to {Hashes-commutativeKeccak256}. + * + * NOTE: Building trees using non-commutative hashing functions (i.e. `H(a, b) != H(b, a)`) is supported. However, + * proving the inclusion of a leaf in such trees is not possible with the {MerkleProof} library since it only supports + * _commutative_ hashing functions. + * + * _Available since v5.1._ + */ +library MerkleTree { + /// @dev Error emitted when trying to update a leaf that was not previously pushed. + error MerkleTreeUpdateInvalidIndex(uint256 index, uint256 length); + + /// @dev Error emitted when the proof used during an update is invalid (could not reproduce the side). + error MerkleTreeUpdateInvalidProof(); + + /** + * @dev A complete `bytes32` Merkle tree. + * + * The `sides` and `zero` arrays are set to have a length equal to the depth of the tree during setup. + * + * 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. + * + * NOTE: The `root` and the updates history is not stored within the tree. Consider using a secondary structure to + * store a list of historical roots from the values returned from {setup} and {push} (e.g. a mapping, {BitMaps} or + * {Checkpoints}). + * + * WARNING: Updating any of the tree's parameters after the first insertion will result in a corrupted tree. + */ + struct Bytes32PushTree { + uint256 _nextLeafIndex; + bytes32[] _sides; + bytes32[] _zeros; + } + + /** + * @dev Initialize a {Bytes32PushTree} using {Hashes-commutativeKeccak256} to hash internal nodes. + * The capacity of the tree (i.e. number of leaves) is set to `2**treeDepth`. + * + * Calling this function on MerkleTree that was already setup and used will reset it to a blank state. + * + * Once a tree is setup, any push to it must use the same hashing function. This means that values + * should be pushed to it using the default {xref-MerkleTree-push-struct-MerkleTree-Bytes32PushTree-bytes32-}[push] function. + * + * IMPORTANT: The zero value should be carefully chosen since it will be stored in the tree representing + * empty leaves. It should be a value that is not expected to be part of the tree. + */ + function setup(Bytes32PushTree storage self, uint8 treeDepth, bytes32 zero) internal returns (bytes32 initialRoot) { + return setup(self, treeDepth, zero, Hashes.commutativeKeccak256); + } + + /** + * @dev Same as {xref-MerkleTree-setup-struct-MerkleTree-Bytes32PushTree-uint8-bytes32-}[setup], but allows to specify a custom hashing function. + * + * Once a tree is setup, any push to it must use the same hashing function. This means that values + * should be pushed to it using the custom push function, which should be the same one as used during the setup. + * + * IMPORTANT: Providing a custom hashing function is a security-sensitive operation since it may + * compromise the soundness of the tree. + * + * NOTE: Consider verifying that the hashing function does not manipulate the memory state directly and that it + * follows the Solidity memory safety rules. Otherwise, it may lead to unexpected behavior. + */ + function setup( + Bytes32PushTree storage self, + uint8 treeDepth, + bytes32 zero, + function(bytes32, bytes32) view returns (bytes32) fnHash + ) internal returns (bytes32 initialRoot) { + // Store depth in the dynamic array + Arrays.unsafeSetLength(self._sides, treeDepth); + Arrays.unsafeSetLength(self._zeros, treeDepth); + + // Build each root of zero-filled subtrees + bytes32 currentZero = zero; + for (uint256 i = 0; i < treeDepth; ++i) { + Arrays.unsafeAccess(self._zeros, i).value = currentZero; + currentZero = fnHash(currentZero, currentZero); + } + + // Set the first root + self._nextLeafIndex = 0; + + return currentZero; + } + + /** + * @dev Insert a new leaf in the tree, and compute the new root. Returns the position of the inserted leaf in the + * tree, and the resulting root. + * + * Hashing the leaf before calling this function is recommended as a protection against + * second pre-image attacks. + * + * This variant uses {Hashes-commutativeKeccak256} to hash internal nodes. It should only be used on merkle trees + * that were setup using the same (default) hashing function (i.e. by calling + * {xref-MerkleTree-setup-struct-MerkleTree-Bytes32PushTree-uint8-bytes32-}[the default setup] function). + */ + function push(Bytes32PushTree storage self, bytes32 leaf) internal returns (uint256 index, bytes32 newRoot) { + return push(self, leaf, Hashes.commutativeKeccak256); + } + + /** + * @dev Insert a new leaf in the tree, and compute the new root. Returns the position of the inserted leaf in the + * tree, and the resulting root. + * + * Hashing the leaf before calling this function is recommended as a protection against + * second pre-image attacks. + * + * This variant uses a custom hashing function to hash internal nodes. It should only be called with the same + * function as the one used during the initial setup of the merkle tree. + */ + function push( + Bytes32PushTree storage self, + bytes32 leaf, + function(bytes32, bytes32) view returns (bytes32) fnHash + ) internal returns (uint256 index, bytes32 newRoot) { + // Cache read + uint256 treeDepth = depth(self); + + // Get leaf index + index = self._nextLeafIndex++; + + // Check if tree is full. + if (index >= 1 << treeDepth) { + Panic.panic(Panic.RESOURCE_ERROR); + } + + // Rebuild branch from leaf to root + uint256 currentIndex = index; + bytes32 currentLevelHash = leaf; + for (uint256 i = 0; i < treeDepth; i++) { + // Reaching the parent node, is currentLevelHash the left child? + bool isLeft = currentIndex % 2 == 0; + + // If so, next time we will come from the right, so we need to save it + if (isLeft) { + Arrays.unsafeAccess(self._sides, i).value = currentLevelHash; + } + + // Compute the current node hash by using the hash function + // with either its sibling (side) or the zero value for that level. + currentLevelHash = fnHash( + isLeft ? currentLevelHash : Arrays.unsafeAccess(self._sides, i).value, + isLeft ? Arrays.unsafeAccess(self._zeros, i).value : currentLevelHash + ); + + // Update node index + currentIndex >>= 1; + } + + return (index, currentLevelHash); + } + + /** + * @dev Change the value of the leaf at position `index` from `oldValue` to `newValue`. Returns the recomputed "old" + * root (before the update) and "new" root (after the update). The caller must verify that the reconstructed old + * root is the last known one. + * + * The `proof` must be an up-to-date inclusion proof for the leaf being updated. This means that this function is + * vulnerable to front-running. Any {push} or {update} operation (that changes the root of the tree) would render + * all "in flight" updates invalid. + * + * This variant uses {Hashes-commutativeKeccak256} to hash internal nodes. It should only be used on merkle trees + * that were setup using the same (default) hashing function (i.e. by calling + * {xref-MerkleTree-setup-struct-MerkleTree-Bytes32PushTree-uint8-bytes32-}[the default setup] function). + */ + function update( + Bytes32PushTree storage self, + uint256 index, + bytes32 oldValue, + bytes32 newValue, + bytes32[] memory proof + ) internal returns (bytes32 oldRoot, bytes32 newRoot) { + return update(self, index, oldValue, newValue, proof, Hashes.commutativeKeccak256); + } + + /** + * @dev Change the value of the leaf at position `index` from `oldValue` to `newValue`. Returns the recomputed "old" + * root (before the update) and "new" root (after the update). The caller must verify that the reconstructed old + * root is the last known one. + * + * The `proof` must be an up-to-date inclusion proof for the leaf being update. This means that this function is + * vulnerable to front-running. Any {push} or {update} operation (that changes the root of the tree) would render + * all "in flight" updates invalid. + * + * This variant uses a custom hashing function to hash internal nodes. It should only be called with the same + * function as the one used during the initial setup of the merkle tree. + */ + function update( + Bytes32PushTree storage self, + uint256 index, + bytes32 oldValue, + bytes32 newValue, + bytes32[] memory proof, + function(bytes32, bytes32) view returns (bytes32) fnHash + ) internal returns (bytes32 oldRoot, bytes32 newRoot) { + unchecked { + // Check index range + uint256 length = self._nextLeafIndex; + if (index >= length) revert MerkleTreeUpdateInvalidIndex(index, length); + + // Cache read + uint256 treeDepth = depth(self); + + // Workaround stack too deep + bytes32[] storage sides = self._sides; + + // This cannot overflow because: 0 <= index < length + uint256 lastIndex = length - 1; + uint256 currentIndex = index; + bytes32 currentLevelHashOld = oldValue; + bytes32 currentLevelHashNew = newValue; + for (uint32 i = 0; i < treeDepth; i++) { + bool isLeft = currentIndex % 2 == 0; + + lastIndex >>= 1; + currentIndex >>= 1; + + if (isLeft && currentIndex == lastIndex) { + StorageSlot.Bytes32Slot storage side = Arrays.unsafeAccess(sides, i); + if (side.value != currentLevelHashOld) revert MerkleTreeUpdateInvalidProof(); + side.value = currentLevelHashNew; + } + + bytes32 sibling = proof[i]; + currentLevelHashOld = fnHash( + isLeft ? currentLevelHashOld : sibling, + isLeft ? sibling : currentLevelHashOld + ); + currentLevelHashNew = fnHash( + isLeft ? currentLevelHashNew : sibling, + isLeft ? sibling : currentLevelHashNew + ); + } + return (currentLevelHashOld, currentLevelHashNew); + } + } + + /** + * @dev Tree's depth (set at initialization) + */ + function depth(Bytes32PushTree storage self) internal view returns (uint256) { + return self._zeros.length; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/types/Time.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/types/Time.sol new file mode 100644 index 0000000..a495932 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/types/Time.sol @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.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 valueBefore, uint32 valueAfter, uint48 effect) { + (valueBefore, valueAfter, 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 valueBefore, uint32 valueAfter, uint48 effect) { + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol new file mode 100644 index 0000000..84cd62e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (vendor/compound/ICompoundTimelock.sol) + +pragma solidity >=0.6.9; + +/** + * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE new file mode 100644 index 0000000..7da2324 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/README.md new file mode 100644 index 0000000..ca39e51 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/README.md @@ -0,0 +1,16 @@ +Documentation is hosted at https://docs.openzeppelin.com/contracts. + +All of the content for the site is in this repository. The guides are in the +[docs](/docs) directory, and the API Reference is extracted from comments in +the source code. If you want to help improve the content, this is the +repository you should be contributing to. + +[`solidity-docgen`](https://github.com/OpenZeppelin/solidity-docgen) is the +program that extracts the API Reference from source code. + +The [`docs.openzeppelin.com`](https://github.com/OpenZeppelin/docs.openzeppelin.com) +repository hosts the configuration for the entire site, which includes +documentation for all of the OpenZeppelin projects. + +To run the docs locally you should run `npm run docs:watch` on this +repository. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/antora.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/antora.yml new file mode 100644 index 0000000..4bc06b3 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/antora.yml @@ -0,0 +1,7 @@ +name: contracts +title: Contracts +version: 5.x +prerelease: false +nav: + - modules/ROOT/nav.adoc + - modules/api/nav.adoc diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/config.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/config.js new file mode 100644 index 0000000..f0af663 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/config.js @@ -0,0 +1,21 @@ +const path = require('path'); +const fs = require('fs'); + +/** @type import('solidity-docgen/dist/config').UserConfig */ +module.exports = { + outputDir: 'docs/modules/api/pages', + templates: 'docs/templates', + exclude: ['mocks'], + pageExtension: '.adoc', + pages: (_, file, config) => { + // For each contract file, find the closest README.adoc and return its location as the output page path. + const sourcesDir = path.resolve(config.root, config.sourcesDir); + let dir = path.resolve(config.root, file.absolutePath); + while (dir.startsWith(sourcesDir)) { + dir = path.dirname(dir); + if (fs.existsSync(path.join(dir, 'README.adoc'))) { + return path.relative(sourcesDir, dir) + config.pageExtension; + } + } + }, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-control-multiple.svg b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-control-multiple.svg new file mode 100644 index 0000000..0314e09 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-control-multiple.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager-functions.svg b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager-functions.svg new file mode 100644 index 0000000..dbbf041 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager-functions.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager.svg b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager.svg new file mode 100644 index 0000000..12f91ba --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack-3a.png b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack-3a.png new file mode 100644 index 0000000000000000000000000000000000000000..4cb52237d635f634085d87337322ac5e0741ff01 GIT binary patch literal 60433 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¨> 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 W72fFO~av*&4wv-#`&9xxJ7DPz*Q3{XF6KYttW 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 ZvU7})GO|xKx>5WWyCiin@%)Vk{~s{kR%ZYJ literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack-6.png b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack-6.png new file mode 100644 index 0000000000000000000000000000000000000000..1587fb5c1360e59243297ebca9f097ed116dcdc4 GIT binary patch literal 56290 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 O?BA=lCt1P7>wf@z+Op{Y literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack.png b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack.png new file mode 100644 index 0000000000000000000000000000000000000000..dc059b228bf86b49a55f9afac01baf1188b51904 GIT binary patch literal 58886 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

    g*$r>t!O)t#tQ{bjOl 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 literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-mint.png b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-mint.png new file mode 100644 index 0000000000000000000000000000000000000000..f89ab90070952a0409570d00e2fb6e9ea0ed8c0f GIT binary patch literal 112787 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�O9c{+=>)TzHlOu>v`YGckW9-|?1gc7Nv~VY;rTZ`mYt zSyBzEn&M^m{)s}!P+L)ZfYHBGMJv}&A@d}4g&!Cd!81uVQTS7;Y7yYZf9FoS)Zx6k zwKWpg+2`0so^}q=!Yzs_Ljl^K>+7uEz7Lq^w?cuR2b!>ZqHOZ2N~+2|Ei+`x!6UB) z8v}R=x@cajfyxZ?Ms$EOlT4g$4ZKrSDeVas4nDdTlribQx6<>@d=*5D?0I>;*(5??mawz<4pTYMIdfLXK`}FW((94|f%#Cbi zkW(cAFGvWSumXj(%(A6I)?^_8+61(?`5oJx;yFHc?1O4(1cIOBIbM|k1NU>aZ`k6p z2)b2HFBnKlDC^cpgOI!(+{FBFfF*{;<9qYVYu>u@g=mvUMS|eW{(NiCM@tBE1653Z zV&-=?46~g(D|{4Xh!_h`zA4;2;Li-!YM!j(&2ZqBR3lxT*g7*hZ5QgxRXey7`O??y z;(3EzCSwAiVhhK;++5|?nQ^`sHO|V392>!)lGFVT?r4*s;eS!s#W6>R+?}P!S+S;m zz|R!Ovi$FeGsusG(tZzEyn%Le2GD2SXDjHT`%s2~;hFE&M{;>^xD$2PMbLpQ)KSLE z3tz*=jbZZi#2#?XG+u2ia@%-f4_}*8dy=Z)qosZpc5=~KwTPLrk}0@z00&CKt1|_h z2ZQ5)!F9_khU{O-p$U!%MXSMCOnyVv)H(sh{fSo+@ zjTvQa!vPaWffd*TAq2wkKscY1pSE6QD9*<~94RL1vtv5qwq_<95)p#M1p_KFS#<1; zn6dL+SU4<^^t8vFeDJnfJ2kadpLFzcU8kRX?m_|z#SX0H_xPQM+T)JZuHZ)^j@gGa zG^08cslXTMxTH*{#cIOdFL-ulVb~|@viAFaj$oGW4u)5O(JbFfzfDk zCb4JRPDPXE2sZjbZZYHvg)YULZWRY`wCCTrAklJy5)V7$IJ==IWkr?19 z1DKRmep)rccjgz1h$)E>caSE`;jV3;HJsN=W(VL$cH^V-|HEb?Hda{T`vI_zySsWq z_rk$w5VJs&gE$_h#$x>Qly0K%+r;!JjhR2?J2;0jnW?5K$fS;vK{$kn-T~IWuNi$y zCRO`C#eo#A`$puv(hc$`{2O8x2A%V_UlEg9qhYrZ)50;!tLj*8T=SS58yhwS0{v2z z#Z;{9LjLHiY|qjz@0Igfr>qf_1VthtVpRTcfF6Qgi>g1}c^48sWWy*doCIA!#74~H zl}}e7_p@1tbcJc(dr1-aqfeyc7R>)a8%m_{_|q`zhw6n^nq8E#eloGAl$KFqtZCC*d#9w?vs6CQn^I=?t(fqy|0ZeI+ldEodrQ#9;mmRE(--yHKh4t%Lrtp^V$`Nxkn=~Fi z1?R>8LlvHJ(?5}VE8u(M5K0vqnI)#B^#Pm;H_>7&0hESZ6b#_`Mu3+ogFQdwH{R%G z!rOzO_coT!ANZ1vPSK%1(M<43)1R4H4ws8hnuK4bJ7YDZQHcM?v4>w48S(L$KVHZvrLD zqt%QaahTC>!Fcj?bR5f|;(_0zRsweoEw##56x{`cT|OfnT30F{&5Ox2Z6=)RG;mW) z>_v*=?xr%|ySA`g_sUn;_jiA3nSLoIN~qHgCSVxJRRg<^yDQdO!?P^fM^4K=4~bIKyIABzR@MA zbX9+hIdTo$5tYC1ptm@yuW+v>!vC@o0Xf&@xJTN|8C>4k?}8#qlkZhTo(>I=p*}`% z^IU#XlR%SNzjW@X_c)c?x#dVICJ#$tyU?9V+FaxiyenkKVZ zrdxOg;O%OSr^H3YAuK>ag!bodvO*t?k}_3*2=n)$1oCBFovFt#f=Re3=0F z{UtmqWhbXOyl2?-B_$1yg@eTOtNucN80F~qe~@P5@vudrcw z#0_dA75VTaR|i|g`&Wg7VU;p>%{VzeFiy8c5HJTn)z%d^^3VelcHQLu`F29%n*_4a z@7IN%BOjbL(|w@TfRWf2jFqjjo9cpuTBkE6?Ib^SJGsgANEd{89qL}``>1?zOcSZ) zl$nFFWC9|$ooYOrx@L2p3oMCO>OO8Ab?e^#Z;^aO=>fUI|G-gtj|29NFyB75Akz0 z4fieGdA9gEKI1&fB6D&D(foCaDvGWw%%v(hayQYU@B)$SGB17x+;B}ON9Ic(A|W9W z;^1Xt%RyQM{WOuon)S0W`+agMUH!j&FG7TnU1j_a@u(A{NmITQTkV|Zo`OXa;D#L* zdyi5P5(hv%Q1g_njPBx(i8H)ttfo}GS7VH1k2&l0zg4fMW8q*gKR>T~MG%ux75TVf z)yD<>Ev^$9OyV?GK`j0dVU)i!#zJ(mBdX?(do>1z!NEO}j?v&+1oC^mhBA4k(?&u+ zuP2zStjjcEf1hdLYLeq~)tR<)8Iu#=TOxXEc((J#yTi>cj$znVpFe*cnub6x#TER= z#~06`ilDf+18R$g0Cb*OnMMKI2W`le^!4#*q?DmywYIj~*PAMHt_+PqkbH>`9=T5kV61!_V}RM8k+WZL!GLM zhK5FGl@a%SxM&r+zo&pg1%5LEdI_kmt z^{a?r`46`)bu!9bJ!3i~#`3kN_N_4DswIHqPLOo|`8ZXJ6@^mleFGc2k zm!JHUbJZsdT-#+sC88|cN90!0oj8lF8US^?D*v0L0(y`)<5p(`O>!(er{O>!9VEw3 zNTb5CP?5r1y(0)@YtiggQW6Q-7}?@)bc@Y_Vxv=5X^t`;oHd5~fBxJz(rBL-ccF-H zH|RuIdjB<)c_rX^)`O}9(m_3O1c_|bjv6nfQxp`_YRk*d2|CYd<>gC+B1n{Pl>$n; zEak!lLYZfg4*G#%BDy@mIWLbfw8j5o3}KRcYcF4QHV}+b_;YiTqQLKxyf(>O9+!>P z|35nK(+frMFty{~ukU;8Pz-n8zRk=fRdDBcW)pdhWaKqatvBXmb@bRiXns|x7d8Tg zvwy)Kb9dWPQ?Dk8)|*=MUQNTT|8jUWsX=|w=@FIv^wo}U`ma%Xc}ilFRwS$FMLtI) z;6c12%bi=Li&$&~;yB$TcrU!g5Sr_XlK67iU%bdrfi-8Wn9H^YC`c55W73D&HTtak z_0K_p7G@>)ua7!wL;Hkj--u}$LGpPw$Fx34w3{WXUOA`z!M@q{ND|@hCmA zyyq;#WKtRVn;8ltgUE?)MA7N8iL9BVp-1F}i$*HhFo;Qo$V0T^P{Oe$3K(C{3(616 z^DFiKz>y(nxF07>t5CwXMnmElG_fT`hZ}yLaJ%Nc$Nxoj|1Zo}BqZTgAB|c4pvYA9 zD!vRqX7Rw(9fZcSyAdAG(Tx39BmQ1Hb zKq#oCz8q7($<~tj!Hl?}u*O{mt3>l{M9GNQ0y3dy7p>0$bfe-Z4xx4rln0j*)5KTTN${e(QDCKE^A81B4=$6At=Rt`(hm z!6Tgas7Muf#*QL%bdNIdaZI*d2y_H3Q{{09E0nB?P_39 z3Hcyx6|L+&ySQmD#p&$;v$G8z;4oNAT+^>od?1N( z-e8>Oz;Tc0Ke^1t(wl)p&p+g_rXhGnDE_z_K6*yMkpcym3=|yn(A#0>Kiywk4i53P zlzMbns||KcH}(%5MS99BJX1Qx727zRxCbh zIK8t<|7EquMfxHa0b-j8jn*<;goWkc_)3})Mr4x~t#Wb)qBvJ3R2gQ@sn)y?NbM-F zks&y=o)M?bO_jzcznU~&av=mLxh^)Gc39d(Ob>~HwF?rm!^;AT{*QE@onYZMEV*os zm;I@ZN2H~&*(;|hl$Dg0g_|cDAT&9nnl$Xz!3Ok~+XgB7qY>OpMvTpspGYdubZ^}% z{_{u7%?9gS>*05$4b(8m_r`14=q={FgcfE6r}eZW7TSogdK|KX<&^V}xZQ`;GEKA_ zm*!WDU8;=Q9MIg0Kt>r>UGXQpH+0#ZPgvTSi9@VKK^(pNE8a(`>OB8Bz@xfo-SCoL zF8vttP>Wc3ep!)_h~u%+x9+ET6oIYB1nm5|Qlj~y%k2*&Kb*)hy?qrFtLa3~BNqL4 z`VmvEO>^y2-YpYMB`QjAguY)Tk5Y(_`u-?S@9s-yOzy6_B`P?8)bk>-MCh=pOkH@$ zKL6@iW1~O)_K6T}<={6Yi=pu9X9iH0XJ|MOx@WvZD(MI{bY*I=O&;YIjtt92Eq=?u zxBMpxr$Y^GzSrg(T`rgM=f3vbc40snx$K-FV1`wh73}M`f2AZ6Q1s!Nhs9q{$uT_> ziHsY~2HPC>;UJP5A}labB%~cz0TX`>rO51c#6ePFG(-&D<9?|9`|yt0I7g1d6}DVY zoMGyrf0PLvPnhCX)2&vua_DM0wy}pXukBgLavSkVv(EF+%JDs3IW@mIt=DXJ)7$xX z`|ps~hl2t-{ynY((w#L~4NLQL%@Qa$5+mN0G}7&lQxvht<(8pTEX^9nyTGK+z@G-xi;e!9>`p->B3 zHCT>s>66^=|H$4D@^yS6el!9lK9&WaCVVAO;5Ma|zQQ{Edy#7y(!lNUxZ}m3RsJWa z9r5tXkdjHY4_M`88D53Yq+yDGop_BAGx+}gLLZFTXK(mMOxwKUmnVAlRiJLI$(qM? zOTA{*8ROSY&O`6jAt@>meOp~0M3p((Wq?WD4Lkm}dLB_3>9f8s{Io?QNUSX!70?lT z+7^Ejcm1+28DsqQjAy^FeSbHv7ZkofSR&TN!mG7Pq5L8=urq#b{;l2RHst9Pu_tVe zm@S4q==!#dzZtWtdBP~rHS`nvok8vq-cBas;&2L@Aqt{?t?9_``BT<l+{90c zy!D}4_6%+8^V-po|Dhu!r`=JU@AFY#13hbeL^@e~XPTB?ECE%YO?-`Hk%gk+`)}pf zjAXf#=bCYnyC{|LlD{o}O;_0_?5sSBgNX{C!dfAsU>k;dd|QsxnF6>aj9_Dk2$veQWH6OD5M%w)t*4pmFL- z=rVBag0(xZ2P1jFK8u^j@%V(Y+Tb=3-nrt~IGxb?&wLD?$5gZY`0+j23LeenL(*?Q z4>*AxN9Pt76H`!3IA!quD|gdqnDcGPxJ+g5C$;LvjL+K}`DeJ~>xOa<(zF00pSA!8;=E(JY#2l!pAZ-K?UE80BO78udh)q^Y0D5%;`%+Q4GF^gqWV;E6uYZ z4OtH9Rg$FpU$bG3tZA_~TzX{NP&E9wcAdh({@Dqg+oeb%d0ok1Vb2}FC`)88B|n9X z_`Dcw)d~vq;Rx_QBc{wDdvh_qt@z1wmbqfJ%$51SbA1?Lz3lRDdL@i|fHmgJQ6s7T zV~3TCcnWUik;eyru6f`@m75;W7k3`#br|;!Col(J?oJ@QaWP5-R$QMm7xGc+@;qYG zPg@I|%NI%@X$}TZco}hc=5CO1E;O)?;@aN@Y%!LkVG~>)^XU`>~T|F_JkLE4W z;Wnp}n6$g5Nnw;(|xu$oe8$ zvhZZ{CX!>h{zP!-{qMK-uji7wB$0=YkV%sJ^z?>JRQS4;MINgiswOb5G!<6A4^T!G zD{|8pdk_=K?p=MJ&Y~pq-HPLV(ayVyE=UrPc@q*kVd!$nYb53?NDw5w$GWjkAM7pL z_nNrd8XPO8K)Sb&pm$*1V{e&~PEC0XNHX{%ecb90z@*df_Lv1sFn?M>UAM@~et z?He+6dCV=ILa;;Uyz*WYC)2RxI|@~sCCP?&Pq0AKL@15%yZc;^JPlT)Uqx$r`JA_NgkB>_I1a zq0XIG1VB+KG?>UecW1m)WaNht+fmT_=}Uk$M<+?k#d@~-+1w|CV4o|n6FSK=qZ|~U z4GLzbI%*OGe$OtM;+gn<%$|Dd!W7vV1Bn~{H15OsQK)EeRhsV%_*5me7;uMK`d8Q9 zyNAU@M1DI$Ayb>6jK_%^f5@}rKdwz2EVv#h$e%R4R|~oBE~-+lrRvKD@f7jzgd@_J zx_W#cu)1$w29j-y$5c~K>%zsm#aiaZjKD<0%n`!O*)V5mjf-)lL)r6znMX64Ue=z8fBFcEqCB zklN^+_BCk@YbF$SK8QQ6GvB%;?6tq*BWL(!`IvlHbfz3gnNTAlTrX^x9` zNe@X zfZ=@thj`SDkoz7XG^F>iUXxukhDGCR`P0ZrU!5I)p) zsV?DW>N*jLct|g6M-smN0Ccm{TVr_iDSW>(+L^aOMrQ3baMf5 zv@(S~%tyNlIiII4>%i}5dZKTE2GsV#s{Q&XT(g|=Bu+BeoUL~&MS1vQt9J&vlFU%R z%7ttv(1WPGeLwBmn;DOaV5K)ReKl)F7AWXvO@n8!cF?$`|2^`{V8$C_@II-5h^;HW zC(ciAe*L;AW*x&>|CWmG3Zy5g=A!b~_N2>`obSe(ooACE&X>1Ew{;>Ye}K#6rfN(Rv^ zvZbp+{%VGhYeRaIwzgCaLvvDCj4p=A96uZkX1Oks(loq5eI@#%8w3kD_eZ$lvW+vS zsh$y7h&s+ADGvBv5p?pm&A(p!0?g0Jst4(eoEyF-K3n$*PrlUEUZjN3yaHc)wqcv(;oH}dPt(ksf5k@_4f|MSWw|#V-FgvSVEpJ;CFJ9s zyS1VGbFY>267f9)kG98_o@8!S)RpWj1w6U#> zHS66Kv!Q^@zt#i7DX1`ZCY-vlG_3<8yQc`|8P|-K2r03MNXOt>PSiq;3{Ic$7MT$j z{<`zQ(pBj@o!z@3D~Y2!$$lRe77^kHunrv^^@ zOYZzdahW+ix#9xxzow6S7_hNyIh`f6J6+;@(Zp)&^c`+DdZ<6*n0~>v`i3h6c;mm~ zESYdE#O6};4Tdo9sVZ7nSf=^`}kAh zfS*M;%Mz}TVd~{VxX`1N%oV7C*(4iJ;*`W?=ykGhKvoT_*}%*nKuWn*emWb5q-#Sr z26c8%c-PF_?Tc&6zt*yuUlERNSGk{#P@zg6gqNkX0Z5VUl7G=M%8=%$k!?z{3#9q+ zQ?`qNqkJa!&N_*UKj(=%|%hVjyQ#0_?mm^=QI}kbZx6z5NHnCIv_p&}p}U z!dalVCUR?Uekec6)3x|k_LT0$d3UX=GKfy=<&2acyL9h?bl)6rCDUCaBKODA=cDGE z`&b=gN%v+9CCQ;6#rZHPa}Ajf+QhDyHr{v$zG|8Izitn>8V8wUo^8F%6J^kKtR23m zR}c8L9g6-R!rlU^s;+(aMv+jY1Vy@(knY|zNQs0(X*MC< zAl>XUx6kvQ_y2w8jBy;pF%V?Wxz?KNo^#&wx_=k4QYA*&0rKnTq3pj2=#Jc+lqidG zB!0=3S0}Gxvy@O7y6~(+1n&VX3`D~|E3ms|w(}zOp`ce?H?(KXbg-i4(`)PaG<@^_Co~j%Fl&Nw651{?;aD5g1U3gdvaf)ZFMYa>h;w?<;Ew!E#TiKLkEArwK;lXj zy+s1iYW$b!b4mxY&%X{#K&x4QTm4F!r1&S`y&8ZIx8tog9jYlgjux&K@yZ$a_VUI65Gh2 zyY+lE*ew|fvbr)D)6JI;4jRi7GpOtBr`qj65C!PSjt?m=XY2^WiiVR1aKXyh*0SCk zFhl9!&qS2fSUgQB%0CGK=lt>r5JNQ7OpEHuBR;$naiA#7qhKfZqR|^Q8ncm z9Pdd07*6B6-=%;8r9%;HDSGzjPQL;TTjb1bzwiK)_}TCNxit>#UK~ z{^s%thw7YBmh~s#LVhbN>b>WA@==xsVVePbW86e8c)^Sy(W=&ShyFx5{p31mTppbD zNi1W-cv60+ES4Bg=k3p3rX$*M1?>PBG*J46AD4*l^aLs{!LuX4A{Grujw0j)-W1g* zP^dftSG(#u=!0}}&&(d{6ld&?H{cL3V_V*;S<`Q)p$Vr zT|1Ymj!osoF^LzF-ftSyEF7CCLxe~Yjbsl`SFkNxPwauAqY3*Luar6`z9}6NG~X7g%+mS0a;Fn3cy9B5 zW9z3kyu9aRHMnwsQ60@zh{3bKhF_uG@;jQV&Zx0+n-0&teAJ6-DZa`Y@c6t^OxlqcErUfw*50-{0m84X8)ZpLLg& za-X-fC?ZC zP6}2VR|t>Jw38IM?yyMr`E{U7eaW z#Q$ZMt@yB#s+wx`<{W`a@fr*(TBj_WS-)uukINt6mcVh0kBX3NQT;ax6-BYZc8{|r zKIT|(@PY$lmVV|BeMAc1lE{_xOo)9`D1x9%)w7YsVmE^FxAqruZHllBC54<*j z!pDl&6Tl$@0n`%M7y|nRMsJ~L?K}$&uTW=Qo%X!L{5em!%fIVcsYQv@WIhp4^VwSc zo#f8L1(}-v^f%lsEEd+aO)-q1?mPa6x=$m52=*WR5(5yC@e?*DH@PxLT43}K+yIF0 zel*cQfW$8ne|Q%F|9S>Yd_vI!_K*WUI}l6;2*N0_VoEa2)yc0wvH&C3Eo%sx z1%OF3Tw^|YgQzeX^eqtT-gNZ73v5plKc}Z_Dh7ebLH~kY9Wa2=lgESD2 z0ayB&=#gqnYDKp3llkX&CN+V9=(4i1Na~F)Y`~Qai2}I7H_Vgu6w5GEa2E}p#z#Cf zoAXQ~0f2w!>tmPo1|e-He<1%?1m(3rl=cBY?pH-R-J;qMHL-ZPZt|Ap! zV3~s~qwldrDx|sa8&SSdjc2i~5U63LScs<7fNh~AwBG(|s&`YAMAx79O89kx` z{Dcnc$6mQyK(yZ#PAUg*K4~6jgolTRNEU!cnRc^Edv8A_D-%d}yTFr90_i1dV41+o zO+dDUXn!8T7*0tp=KI+ijOl=J0M=!1lD9KJ)x0$LKDv9;<#R;MNJm*V*o5<|0I_2T z+YLIvaz8!*NK(GFVZmd0Bsc21uhX?O0VvjmhPxePb56tRi1o%`^O)fIEu@$vzGH>s z3e=X6S}+T?+{vEL00VuqWn1qyf+?RK}5ENB|pZb&@pj>mK zlRi-6d#8ZCJZ&H`#PgLO=menM8KL!dx001y8`z{&xt(-r`Qk?sJ}s1*2zAf3zq zQkp59HH362fHfqG?g1DGGrnL)*`L$a4z+W@Gn97sYC=M)IgybNRej=aUj!B!pq|hR zENnf%K02uM000Vn5nuJ(l0_b4%FbrTyJ^#KMOQv*Uv%^UY{>5uINBn$5Lq${+izb6~OXSBa}S3JI1_R!|aBaTo&=){vAVI6Oc4u&f1 z4sw~u6hm z8k9hHPiPP$79nO&C0=(z4&IY3mloPy=%CFS~L#;Q$8iF(D{Y6S!YMfVvAd zIKF_z1hn|1IEg+_fN~Wecun~hsq9+Bw`@^lX9q-_W$b+PF1RRw@qylQN61Yl zzcji}&+W5tCaEpgm$H2)i2mHuzYr*8)~N@Ug-iB*fE_Lej1ZAWsAZ(HA}`|^K)w_d z!LcKT#1%B+vNlUj7jgC9-2ipibNTH#2swXW{b}dPga}H|LlMx#C6H-rgSw)uLAD#6 zX@uw#VKJJckOaV+2otsvuiFrWtsrpVWEh!`c0ige66{M`(Cqee1J&+fr@e9RZw}j{ zZndLFQ*;%*(;#Pixx z0Wdkj0u2E1g?#o?JAM~x*&-fD_(K(UTd-ZKSFgOrXJMKjt|FYjJRNUF#9u_e=$siq zzl;#I{dqj(^tirTxb)7HzkJ2#1H|XW16?U7*L{5U!$C!%OQ`f-G1%||B{jPs&;kqd zmXTynP0;m5gTldHl;8}^z=DE8t(tJ)g?$8An~A`=Q$Zw7RS^C5&b6yTVF zou_TX{2Xv}opXX&`s`0i_Rl_*zBq>MB(O52BzbXxg*GYUtYcJMtdYHku`^jBNXd{* zu9N=`nX{DNosD2nSq-Zs3x9vGWV*%;bm~BH4hI95F>fAoQlD-T7~e!4;@-Di#o(=b z^757_Wf>;ZDZ~c4?#MVFh`Bh`7tF7?*4Mow;!Z=qC*9&V z_Cx7ciTD+H|9d%p|0@^uZ=q0?}9S_Tl6M(M! z=<*F1()zEX<;-5fM!V2Ex29I=-}8%H?xPaR2<$lMEU9wkGJB z5JfC@A6Ogjxq_hL3LGOY0pGc&zdsY0gN=Gw_5$OY1R-~BP>w|x+y)H$hRhJIlvG9C!nuAnlA(vPAT5Xj5YaE|rB z7L?+_yaC2rl4}Z!2f^<^vXk-wiN}R|KvCbYT+^8)a`lJ* znR4c4bv3qLpX1X6Llbys;d$qa`zp{-u zTBJ9;s0(C0A;R%~%Al59GgZG^-d_v;CKdv-;HkR3YFI5G9^O+2^8tW_b0IuPTtPS> zssiSfFMtmL0@V-xqq|UA`_j)P8%~m`h|Ro$;DUl84}mb?0BlB7P;lkgp7r07MW?f} zf`Z+_SB97Guj4tXQ_|-7?^ANlinaY00NQ9)z3spR7lM9;6aPwaXWsgfW9C^fR(}rI zwIb`Y1!LE}zk=gqrXvz$d}rl3ycWFV4DKhG*S!<4m3kIM!X3X_+G^=$3B>1vdrm9H zMu@KY--Wrf_HjQO*B z10m_#4`p)(EP@FjG#T8I#_+n$J_yauY>j`D2Pm+&WJK3gVD8NKc z{T;{TBW3Hml!y8IB%AvVNDmH!vO64^bLm)8kCs7gY#uVjCRv=~#-?&Ofpd24E9MbW zc8J*5-RakjJFMN}-O5BUpfbYowLdmF5Y9Q6J{G>O95HCT0{Y6EG9krT(kz z-W^y01HF9rhsR?wvVNh6fu9Cuu$ccS*zW)y?=ZLF&0%k(xcm-To67qzc7z%og=(tY z!gW{hUB@c(?Q6zKgctI$ZVPjzHUkg&ieJ&!n9|36N1T6IwusZ{w7MKKqKPUPTR;q6 z;m5CYRkUlJ4Valpl=cc^Ht&jQRp})$NM)ufKj0s5{}r*@EwEEtB>j>_>an#*aBwig&Zw{x*2W52%9p=gdXaYtn_^0Y?z7;BmmkgMmI;TNFM+mK{Qud>z$V5WyM zwwr<@{>wftq}=H+zSZZHIh20tSDetAe-!ITRa&eJ-4qs_>m$vWW5xf-+o`AIX;854 z2p(1I$u%eb$zlr|GQmfv#TUX~7IptYUA?(R$&%-RS`6NIrV^ z>yGqa;_YR!D?{brel+&f#&&jxz|gk?my-t^-iEu1dBlO=*(Uhw85xttuk`C+tPU22C?8|!-q)_lFEzEA3mTzEjH zaq=69{<}j_nvPr!$_(f92E+d^&~~lSjubuSw{QIC@Jzld%DG;j{jXsC!O(!d&g;Z( z`wAfJA`fwiCh>G}RI7>I`?zWil2VD7M-{aczqL%Wf~}T<0%nSU`!klVt}b9iE0G5A zcrNI|3YPcQV^ami#p{2T+A+KN`1pWf5iS9Nw5;qSV313JaE$^kMuB7k7N z*Y#3i;Qj4zI9_AR+6$h?va5Ib$dB`ZHWFwttJTszg6lVSAnxc1T$MWZ49iMVvMU0k zklh~ZOI5%oAz$)qXP)*?K+oxpcn?%3tXlCMl5xgZKexH3a&#kD#Z*(Am?oV>pZUU{ zaATRm;J{M8 zkO?xd9VHHidAykna(-SOVl58Hqk`w2!Jn|lIP4zGw_nQ*LMi+J<_@?dw61@!lLZqw z(zVoQJ}mteimbR?`Cl)3eBIPD5`>k-`WlAArCo@(|)pzxg0BQ@Cwj=o@o^9m^%*siOt?}Ugi39#4NX7^eG~ab zPCzWsjJLX=);QPYxlE1snx-q?sOa@uZN9)#Th(a+#N<$AR{SmQiN}@K+j3&m0iTOj zNG=`-G1Sn2?S#)0lUmcd77o0p2(vzJ3w2P>S4}bT>qlU~7 zBvj|(hm=GE(r)9g+jMjUk`cXAD1Ml1fX2K>m$8ofAi+&9v$1{4>4Uw3sb3j#rz24t zi|E5Q$nM<;GVJ7f;)rTnxCiPtG$qu9&?wf6gs_xW?|cLEV^XrsWP)k*^4B<$q%fJCwD!y-4s|ZeWqH4t5=Wq>#64i z`NN2>I>G816hI#4&oc^C#q~!Au=3>#|Mj_y&A=72nXQUjo&~Vli0@kJ!ubi2qhsZ)kenK&A9TsuN61pjc%EQN{v1 zw)IBRLk#=hQHGZNs{;a79geD<>g1oXC`+=aFlNJ`YMF; zDo-}d%X#g%W-qta$N}4vkH6^Ong$S53Yqyj>Z7Q&QdRS zj0jlf_J9)hww_#THsWCfd7fO!6%bG&ZamW^gBhQ{E^-v`hXMQj9^kw}wpm{^U$!im$PfBfeD`uMHH_bTLOAJ1=Gg$sRP8CbfyWkZj?;F3 zd~NDqhyvnf2N-Y#Sc&?|l%60;5RvY`bRiF3<80%@S&B_lNCWEbM^xCv?KbovO>Alf zM#kstZS?9&@|EzYVJ3cZAU!T>|AYF1o<0cpmHx_AOcQa=o{tO}(eHgfbF;&e8W{n1 zjz0hL(}Y}i7h@ALo!sue6LC~AP&|+_*8)@{h^xl@-4NZNZtF%q#(!#P96>2OkhZT^ zpHhMVQZK)rc=iT{^_7e((dPYk-4L#@EbulL^;UtpR+3rnIjT6EvDX&w*gTosxPV&! zXTg?I;er}|_AA*XyXq@P7=L@b0`2-JxcYL0J7w~OQ> zj1fv|)zA^l@ja;N;+Obnm!Dqqa!y zpPE6w#+Ey}n((bwM@MtW33EEfcSLh9rhsFttx?}w_ClQ-%|KICgznrA2Xj4B@kG7e z|1_tuaSL%%{$j9ihPiyiVZmA?-Ji(9I%Ad{|5fo@fkDzX9lqQb5GX^}O8@r!I&XmM zz){Q|H};xsoJ5=u${;(3twIGV#){9SK?MO!E;r<%IMG*N#8*9f2;AEdD^WsT8w#-7 z2-}9hZ;p>=xMT#%F1*N&ZD%Hs<6YljUoK6y>hi4p$;Fhe^RQ5~BAXXyesJdVkFBZE zf~RpVmZ4Z&voZ%cIwkMgtOCIDrfrtJ_;Ma;pXLGThaWD4XszlaSZB#VqvM0~YP^sp z5Q+}!sG^K<3-Hcvp2|5gk0)RUWl`(DMphP9_?~KBTt_1!^zgBi20G&TKO6CYuX*0x z)>vwL4k8u9FTYBKS90(UGvd?!#vdwI ze{wpDAnB$eK-VCpDLbz1CLNYxu6`hOptYXpJopK4>SLi|@|nO4?LXRnt>TAIKTT3- z=jQ3ZSQ4ElMp%ctmf(Tz-l4p*%iB6sp)$DQ%nzD!@!fHPG>Z>2Tg&`Cp_%dqrW~9K z)PjN}-eB$aj7d`h*rEc<88vVBDQ@k7kdgPEUNMsJneNJdciXkoTZCaSILc=6r#Xxs zDE=pXRob|Tl+4alkrK0WEZ!zm#zr5-i=QNI*X z=JDozv7{dWcD;&d{|%$4k5l|d;Cyz2Wm(V&ptOjxf%YFYz~yJbWd#!nY^hZc#$Ui% z5pf0qYz4+qj6}BosVV?3;^}cRD|C*pm_T?NZ)_XI zK?+n=f?@$w&iIHQDghi6l@-kYGztjm-oD?6duzyZbO&6X6g4$6^PW2uhXV&3+rb*V z@lRyO`ct%O_W zE~~{)LhAgO^|$_Ft25Q+{j|U_8HLLEU-ITRo9fRDvdY+Z2Ku)Oiq}C|g=t z`4W)MrZVFK%iXQ5Ek@1CKs?$v2!AjRFt8BbnJkHpPY9kYGS2pQlUtaaVfxnYnE0n|ItjC zR&v`Xgggh!4={XQJ_{D2CKo-T^lir3*97uOV|TL0&B!mMAe`^)^!31TAi_LC_;yRt z^|udNJhvqga3)0&%%lWV3QU`WS+vYui6zD4R8qlajoLW4XRYrH&*SCUw2!GOpqhhu zl2njWVWpik_j0%xy8a<*XjnRn+byDK{vQl8pd^COqFkF+wANkAZTZ5GKX+$xKq~=Y z*OP{GyMV=bOg`-r`S2hGldz{{buWPx%oSyr-J` zGR_)oBNyjy_Fkb=XSa@KuB!CfBd<3zXCq8PBKtDs{a+%smPY{h?WJWBg6P}MB8CRG z3bZUN5d#AQ{#ExuLWl-9H+$al-z`iLv@@&sH}eg^A-%@yy9?S*3gmo8OURTDycTT} zBfyHKA9udi^B+@obV_yY+6c?F?m9+W3UR~LAq9}sw`r^LWj}pEFWMeh)uVgp0mzm= zwf)w69#pCPjWbC$)p{8*L{ckiPe87EC6gbxN-GXjNsgb~@O`Siu^_@k0Gc;(P*)9> z#DIsD!#V!%0yUur_HUZz znAYdcTj-pLi63FxYAjRG&u{CM$pue_q6z1;i(jqA^!-rdF)pIc+2NnXrEeXIYLt@dVq zTYdi9&cepE^gHQy6Ghur`Bu(p=R0ff?bF=Vk)kJ_vJt4 zCa*0|fvOC)y@hY6qG-!1dgI*-_ zEREBAwW|5y;1N-!>1%a3`nc14RC_{btT=1(m!4n7z6`pK*pFL&&ECq?Er_zYZ$*Q0 z70qKz7>gKz6tfq!IMu|fE(u$>G^XJodcL^ut!&w0ilJcB%8SKXOXjpjwHzD`{a2mG zv`&AlR+RSBs)E0*7#&tV&0*&ozk3sL@%$hu^5CmQgfeQzh1&8q70OVO&6XWf-pg00 zDJ8U>-HCn|IP7@XqVw34<8#!I2l|y%_a$nnZVqSMQm-e-_C3=5uOUk2d#qhbvWK@d z5r;p{6%To823Mk|-V8gxuI^S1_7W)bJx>fjWWy!b$cX99IIF3{=kHxUf=NI>ei7}N zmeuA``rSyF8;EVLN>cwJz(ww$C*UjYQ;fF`H*q+hWCA0W^DnVvaEj^JQRJRG-Tko; zYPmio+rO0%gZ8jz4!n?p5M7)Osod;Y9=nK0K^T=}4$D@Qk;#)Bg{H#dis*~p_O0q& z!#D#JEAno*yDlYGH8Wy-_GdyeW}}wHxqV9|I_Z{$0-b4q7zrx<(Os1h$x&D$q`JKv z)3mevxAybfKqOrMZ^D9F!!5V{AHb+!I)}WCKCl6|Etqxz(q#?Of7aG%-N;jc7o}~g z!7ZHohSuF05XiNgS}5M3{+E3DH=RyPJj{U?Jx{WqP?Ph{{^0{x@2kwV3B^S71UKfp z!M*VXa*?c*pSuBc^ijTqU&?&Yafl7#nriJ2Rbqp*#`G9wix`^aJsR`+-qy~)f~g6v@f9&BdJHWtme$iQ`CK)?T= zf!P2CriD93i>=QWqZ*~Pl-PHkzp5g>XvzgfFg-6Is-2I5 z1-^vt<$8xsUTY26fpGFHE=`kV;|tH&#%^G99#*|mxf~I@%pQ4^jnDF-Fn7T#+?{5; zG)vW!zEX@nT4gllVlYJBSywt=+_ST$OXPh2UK1(kS^U#Wte(3UxjKBCSs^=YoP6Z1 zkC@2POP9%x;EK%xvO!6{%*d6?s70NSIA9C z7o1tlqJD^|6dL%Ze3Moael)Pp0ri+rg?QY~RXUaHdfrz_5OjtL2qY;U{VaSpV5j40 zESUoV7oO1fTMq`Slo%?{+f_@BjB4DAv(8O6@@zU>?UBZSbPw`Y+L~R*Y04Q$W$e6T z7057U>QjoGsvz8rsi-Vrn0@H(g;a(#?nzo?Bi417J&9`KoNcZ!bdQiIN{HB?rm2?W zQV0%fYWxG^haBZ=S~b~!>bf(+KE7LCSu9B%PTZ1og|*Lx^U1B5yoxr7ur_&rECb=& zK#hI(CbvoG_7WrEZm&$)Jcpfk=RQ}#5MyY_&~y5?M%KQN>grciW;&kT4@xK{!}fuvVRTnJKXpU4DZa_M!s6Q zd=Wjqv3|0=a)%aom=VD==*(L!P2UM$fclv@r7a21m3c=@_PwE1i|<=a@OO6a=;nII zaYP!m$M&uDuA0XTGtE$@^HV`%c}nh6+0KVui!#9xS~lA&i2tHw{D5C~iv{8rn)e#* z(=Z-*k(U5=8{P0B;XPc`&f}JuevIL9TX=4q?eJ|A#?Y5>y6lVnb!x$ejmKUs#`n%A z3_VHY5gj6vS$2p`mPx_U(g4 zmbIk8Ea0Ob+A_RpdbLP7L(UPE?DQ1pF!H750JgLziZLTSL}K;PXLKA&^B848cv92N zo$k)%g-OYhFF7uVCCb5GZY!+AdruD|nf%!=rw|R=C4vTnW@Y(^JA*qae+*ViGM82^ zW4!_~Ml|{BA-Df00?qV0s)+s?a0<|aZjk<(44^TK>1SHRPwy?M}6#=An!TNCkd$fFDA$= zHGw4bV~{eN!-3V~2}z%0?&SJH-O`T7Djn4w=z)O|g>RR*rz>z32q~7uajq!uclb}Q zv8Fed-R$e0{mI=pJ3bu#(2lmR6*JKaQ9GA9rj*T5z8RjvK8D`%k?A&gV>2bhs0^{s zlNXD}?8b0-*P8taz;GnluJ7@+w>B{A9FOsMU36*?Z~I2d8HZI%UAZjLZg|ZxR$pm4kXOjX5xNaU31clVB~8qC`V{Y(KKXOmU{dyyxx|hh zG&dv;C{uhk2x@1huf%X+BZ0pEYzoPX0oems#-cGoHUd*1gd2M7J@_NAi~j;B^% zgci{hd}pP9s&KE0pLR(UVYbmOR?(p0Vqx~CVwSb*i#$9mi$ipo+*6Md(d8br`(bC| zF(9C@dQCg0wltaXpED*{?0_fzwW4`>Wz62nIM~XA)sXu(VqKGCAnPJf2Rw2jbk~5F zCJFlyCz>j+67k7(@cFI9r~2;g_!3rZc~wp(Zc{_(Gy-zsShW!k_r+A=qpBC30o1lb z0X2;#1>xg~BocHd(pXgZ%;NN&6)m%aX`VF^iqL&cwZ)fX#f7ZjmRnlfz6$RObbD#n z1PU0k|I@%X3ygt^V9j{F93dHL$%3DP+Q8X2lFB8~5% zybd$mlaGv0TU+SqA(NSW9}5znz8X*F{rJ}Tg;T>(-wBCmj~_Zt204f?w`*1(Zst89 zmtWTAPM1!`iv1qUFRw&g4;`mXGA;Xt(5wr*fEmWqwD4DdLAKnu*lkP#FPx8lSDv*8 zW(#<~z#@r9NoZNT8DDdh0b(F?s2_0}=p=>0l5qwlcX+Q1jad_TAzCT~R#2Ow^qnn` zrX*qEG<Y`MoAQaU^44xO4HuE~f&8-tW75lg255rb7^gYGs5?glVlzDEpoHAn{kgxW z-4fpbq8QaOwevCn0z5plrOi$~{M)HlVx`j1Ihti^j2K++Aq8*xWokLqblfUuYF-Sm zh_mWVpjiEk{*^6UIe767O2Be^hlK5EhO%=f+Y#{8KmVengyeU&FTus6j+}an$ojGt zE)S-s>j`OirS5P0V=E)k%Php?1V;Y5dIQUG)diV+E%2MSo!xu94wsU%kBl5%b_U2M z+b}P;KY3ak|NPSCY48P(pD5M+kB{|;XacY}?d~ivqI3K-O7n>3GiW=yg%4J8JNcn#L2;nzvEo7VcD$@JBF zUF5S}u6kf3d$m2{$JR!o34swlbVk3(%(9pk9!IiD7C$7Ag(0 z>7kAF#Xcx5d7Lf1L$Dz!EGRyxF~tf6lN2*-w%|0Te$DULr(>YPZ>2%WZ=?x_9f|X& zOvVltNn&7xYThP2`YzJbEF22-bkSBYlbgMbJNq6kgdOShsGgXM)Oem6OlAJw=wFov zu3>MEJA|8EHQcr2z8=6MYLG4l;@+2^As?4GnO3idWhw~X<<|GlvY>p|ek5_(!8IlU zeVpEW`dE?N^}5{2i_uT`nZe%bODc%64e05uWfF_|`*=EvPY+lccqW4qOdfXDjNf^^v2FKjZxQ8dGF|yp;;HwU z^%2fJ1L^zsY#Od>p5lv~_a;T6cdTsPdO+k+TCTRRNQ_AW%ueQ%y)y(@9cep1gbD2L z+V|*jJ}Og(H^<0!tl0SsqhU#Zf;BrOqJFS0v1FWtFNmal|K8E$Q0;NO53?3b4Qyu} z5zp{bI2U@oTH3JaA{bfY@WK*P<?YN5gu`l@oHl2oz9)B3UJa)86>QVjg zE!kWp*UdM8`k+|T9HYMM*38`7HpetL;=kmuOiz|!m0+9VMQkD;jQ z9QMoG-jrIgCfB##OHLUMq|%&SsT^o^_I*zr6ciV&od?Jizb`aAM8!K-UQ?K2sZofl z(8KBLbA#3Edev((yxO+@p?cN$^x4_nfeo(`!Pe{9S4O`^F0kALe?@bw+4>Y`NE(>t zEXSXby<5mPO-#M=Smaq~YdaYZ^r>1uerbmmbpDnz5n`P)#cXr4Tqax^gcMa*BPuss#+os?-ZwszH(uyZhA=Fo^p-*OV++NeQaytN5c@f7Gh??6S2Ql$Cv&0~H^I28@{&|Iv zr}kcnKndh}DR&~oet+K*?exb>?1Ev>3$xShP%c>?{xfUqle6nVYvcX%rgJw-_#rt5 ztoaTk1`j*%2ra{eZ!)INOoaRA4mgJC+F4c2&3~|aUc&~e6@?~<56I#1GiO1xF=mO| zw<=8A=DKiQp*=R8_wdWs?(s1A@yk=$y&_qks}`@*Qa8A&-1o)v1@KWkEi=U89v;T9 zmg|NOu$69(S^wq>Nu%ddZPjIL_AS^#<4GJX!WDbB=jUB|i3yg%f9@G2=J3yYir!vZ zwy5EjNYlSns*$^0ZGejkRbQq}EbTm_-QG?7vTb_(Wuf^;!LRcM1Id=>16yNbFlNp1 zMW@m4mDPv&D(?2iiGA8-R30tw-UYeIuMalvRi9L&pxhc>{6u5lU^1H`;x8c*jt`_% z+f_M$9}54dIk#3N<>GL&SQNaXo*?2+`{TNqF>t$n5xQA++tAW)3Trl!vtB57kvbXI z#2Q8)TPD;8%J@D`g{NVJ}qBIX6rshP_Zwwk)k1n3QuxT7uM}Aq4J6&#smUIJ&>KbF>wfv`{TlhfaO?xA$pouk2e|ZY`~gj4nf2 zAB$h2d2ZnN`-OT>dxsJ8l-sUIg+6XcbaHS=k7{YY{I1k!#?*RnZhr@b>t^HsVUZ*I zIJSEVbvhW5cBE9kY-fe)vJ|UFy^)>lOIz zgqPvqLXF#gO7nPEp#i3}32lNW^2303zi75iPvLAr3+hPp3`R>zB|IceX*46k-S4Ax ztyz}R(r5`opTi|HA4IVs5n8U4J=fXW(>|#=xoXh4xgm$g;`KlK^Ti9^5`TSnm+DRc z)5_z-Yw3x7^~Fge;^E`=^a{ntFLQ#Z!-~wFUtG@;Noi_r4ibu#>1UDNSCbtb%>}VN zoI$*0&%+|bpsdgWwmgV`uPo~Rw&$(0pRt+#2Epw>7~7 zoig^=(?s55l%+>r65@ue-GpxDFh*P2brcI&*9lS&=(|b9=gb)Hd} zxweK(w!`j$m?dfWSMnkGiQ`zuTQ_jCT~H1x#hORxuTSYk4L!ECQmsyJRD0_ zPHvQ4zIEG#M=$=JWTu05{kXez`tZe}X)nv0e2eSTz0>a`;T?|pl$xBu`phbU!!Qzrd4h&52ZO_0^Sp1%~%&>jN03Y*84KUbzt>hg=U6%$Ov`p!LCTsY)g>kB7Q zRZW>l4#u=v(k={u0Zdf<<$fBV1b$hcV7Fv*QZpD+VFgn?Z@A@T8Z9=9gXQ!m z6w}U@_Y!K~%__70_$c_2nfwl7>EEre7%|1}e6K>b>%2K!_139d`|Sw)^x3nVYPoMU zZDN6)h4!dHEJUNG>zZ=ENLAEak2P+q;~!7Fi-oe#HdoT6U6&txA#3txS9Cl;I~V!2 zW{_@~lk6%ObgomcX>NTmsPziwP_=%T?%Fi7R#@_O*t^)Vgh0-?;P=s@I~SDq)VAq6 zWa7G6V0|^tgQCi^zR|Jepu*KFr(&=A*afU07t?0OXMb+U5XFq%Tbl1>34CQV^dyJ@ z>Ajlr&_^TH^1Y$Ou#zdVoZ>_a+P4K@RQ~5;}UPNzh9y-v{ zAw$i&as-V`jVkcU@Ut#GAQKg|6C6}JAE31SqpQcU9+q__(2LE8!84Dd81Fgpte@wP^Bcrau&Uy4C)KW@cc~cXd z^0*J(+mdPzm~zEr_K-#Vw9ga`&XDe&e({ELKH%59(1!O(`qLL30T!(x+q^*q?oS@k zexHD%3~ovC%^`mHn_eyud*<_d9Mmwd;R{p_*1dBPD7jrjPlI2b&ea<`rA3c0xW5r2 za0?=)S-k0oELhZbc-{V1wo2njEtwb09hTW#V@y(JrY85;d`6zzpn37@^Tfa_!r{c; z5Iow9ni|%O!YGZGD@LoC*lZjF3+wL#xNhuOOv$WyEP>K$OW{{H!1r?9kDxb<)$J28a)k$MFZL4J9dI zkb!rzYO!ZV!ibaCTgGQGnh%-qBU|?G^}0KTEI>Si4sIrtt-$(c$!3#i>J5{LS{aQi zvB-Gf@%R!C-`GSO0m0l*VU)y>gMx{Z4A-}ufbu838oF1(5wm@#_;qePi6fjsWg~*C z*#p$BJ6)Dt3o;*uRRmn}ywWtE|Y;$zn(Xumi~*AhkK zk3Y*Dp{DbPXKs5wkW`6U&V$;E}W*Sq$jif)h=gGJ+zC-K21`r@9=4Gla=h%%NON3W?t%|J19>i^P^bYkHv4*AQmkyuFRdXHUM6$QGu*n=LrR?er2a2J6jT|{eh zKa0#aRzU-JJo0yAX*;ePE*y)OKZvYA8eaz7pbGIMJ_6IV5RCU673y}zlDdawg?6N0 zs345EhmisxPx|oWJ|e$082Usr^ zStct^KXSltQ;DonU+QKR1wLow?+3$t{!xVnW--D?QlAjY<77#o2Ij~w?pP+&i26ics!Bt2F-qajLkQXfZ6CO#<27~l@KgNOHCnY1q zjl-qxS%_7jg4q3hoAN*sx(b3oP7mX@*No8kw7K&R5+I=~#(S3U|#9 zU92mNKk7s7o5&y<_CKQS3`n{^WeJ9=NGA(W41uv4_GtzrpfN_DdA$LHdisGYZ8(lw zM>lb|>jg27?bsf;CU7by0P^5bAi*8n}1^nRYY3P`JiVg6)78(c`p=(FA)a2=Sg(pc1>tn9$!z@1U68th3~%AuEbkUu`y zZ`FA(RG;bImyCdH#-LvQknG&`zy6;A}xffqYco zidSRoXmG<2Pa)Eb2xH?@^(^!dv>nROS-yyz$j^7x0U2WBL|2h-(ET3;|AQw^DVy5Y z6@vLFky#H$NlB@?wiZ?0Co%B*NNZaJgH8G}-BNuBfprRZ>Pn;}n5gfsR@9Y4FUwyh zVv&?YGqzT4qf&-}KkCEgTexFWtdd(uZ%`4sBg>pZ-CJ1hADJ!*+1MW0cA$YNd}6g? zBI<$QD-%tl>gl>$Qdhr~?w-hQ_AEK~xC5C<)3^$3yn%qoP z%_I}o-(wP2lXb1#;OxNsk`kjo*Jtb;9A{M)R#qET8Gq;nLCypoJIE~Yc0I((((@En z=ZXLnkI^}>qW%=5FKo?T=AkjIHJU-AE|~RlW@V^a9LB?F1)mZ(9(qrhoG`F-a$jQg z)i$)CJAO|jo$f@Ob`XumT{4G+-4u-D>i4=Uh_;zXCgwYma(?cD?Y2racV6eMT*xIl zYznztjlew6mqR~hhu#-WOB*XeB%8qRfbSnUfvcC`C>=5gzl-8OfBsMO8-JjFN$4eZ z4=1o`W?5^)4G{%La`8`rt*npEtt+q7VcpS&&HT6ilw7^%J@PvEk~GrepvBo`2%Oub zoqrwVn2+RIEjuwk+mN_v;u4Y@)HN zQpnbMvl^eL0BMy_rXH5~Xh&V=k*?h@{P|>?Y5VwrU6OFQR`a2+e&tu3$B8k*TQbz+ zAwpgb@nJgJ<_z|z{Fjvd3SuG#a8f;H%;8Rde?i-PfAz*R$lDLUE?hA)AU1KD%%tIR zozO5XG23eWuc6V#yK`Akxnmr@`V0y@w7aWBcC*|<|05Pelz&2f?{ ze9O3*->P4Wj;5ipq9a%nv!YW=fsqceGTH_0}Cdd%$_Iy+NkGE&|WIQC{j{?^nR z7v+viN9Ub?_6C-_y6groy#}Vj6PvCPbh2S{D7}glb7x?oHH10x~A`K7qMNu|EpR%0^sNYjgRWeJhV} z)YI6wiPRC2*DcH6EZQ4foorm8>WPwrr%6spVR`Dev$Ny1|MTZhLLNs19|n!uBXB;F zyrSZGmDhSg+bsn+szzpJYb{D}7|4-l9riD7l6ahGGj3*`iW`cIRo7I&260Tt%*<@K zZP9Qo;XC6(%lrMAY9}3cq)^wrZqL*`)~oB!WC9-sYC7-2x^z!C2|>kFFo6)I*%{}< z)lBrOkSx`q_tph!dST%Gy3|b9~%bM(Zu-y>0 z8zVbc`mR=zB6KL5953G0n2hJfl9_kB(wXnQLngW{L;LxKBco%*cACtlGrCIpqH1XD z+ip4DRuZ|*YE;ENBubN;Tz=%rFL8JrfhoYGZItJz&N=43L0Mb@-FWL+b^hB^_w^sFSm zyJb0MyRp;x;o9DTxjQ3_ZdDp3M*T_5uA)AMZOvS4A3^`bm z1$u{7hf6Ex1BM9)+7P59JjQi@G|Ljn4u5sfGLWC7Dy%hNHn(oYWgq{`i<2AwvW^aa zQ)k$k%2f2Kzk?(E6l*NeBY*Y<7%EyN>d4)^Gjk`b_&hb(E~{h6*F*5NB8z*<7J=sE z&%H4RVLXO4{=t=;p@TjhryiCrf@~?yP4z5z>Rl-6cg-0Zo7%z}Mmht1qyU?&O8ag_H)uLZf@5sIH3Y)$J-(Lo`5Sk&L=p3YW%ADr@9_%hID$35y z72hmFO)T4?J~|rAEb)II4n5JZtNSJxB6M07GFDq$#O}Cx2f4YcvK?9#UZ-CBv9IPP z)VItCTNk#~X#}>0E<1(h9zL#aF~)}ON|G95i@hL8b8X}>2tKPZF?&^FdmhDnEY9a3 z7z#f$`Ox<~0*%#2bn}{LvL-A0l9<`S;jy>a)sT(-@v2xngGP@OQ;XwF2e5iV?0tH-MsjYSUlDWYRUeNhc2bmp{n6EbiFj6$ zlz3$TS$QpDlb7rUGxWwR*s}YVt)fN)YTW_3v_xxXB}bsS(8YlyJ(tV8uSc<=(C??P zi)1~nngMlS&u+*nEItA5`?nfd+|)|asRFx9f*G?fvoDAjIA7=L8c|}gU2Ycjnwmbe z=)meu7F0BcIYwv`s7m`3{roEb6>N{KJD3=o05y_a@+)rcXZG=78Pe_j3sg&r<*Bk)?MBpZ&MkqY zPsK8&uKhf%VSTH(0VyMTQAOCWM!(JWh>^w5}vzWu_yu|-9(Vlm94=wMk#(miSm|%EB zz6c_q!F2x1p8e=ra>I=N1&nAp#YfZBHg`QHi4@+e#g-}Nn%7Tuinl|9uJ+p*{3D+0 zXt~0dzBxDf5w6r>Oa-s8*j?bRs@#B@a6s|q<&xe^a{WyB!9svY(U)&-$fUfl)SmH+ zJ>qTWAVRVcpJYUQvQVzj)?-B6H9V(rYf1*5_?CfdZ9xSt=!|W6axOOr4=oIWnV-fN%^PcM>?wpB z&r)&>dVBY_pGzv3ha0+vrCBTqP0OhpF%lmJM4{8RPSDIZNGr#$ zFq3S9=(%t$!{~)c@X20VcB$(469;!)&EcMpj?RC-2L}z(C#lB&uwFh>)qcGd6>tek z0wGCu0vuO7#^EWktP;-9C=e;B(QWo?DM_*26)@&fd8fwN>N0$VFfjMCuqNv>^@}wk zLUju5KjOD{uVuqH_G6*3@ZO?Txq4aIc0}~5^ssK3FRpFj)S1Ja!ST142d=iCnM((F zqxRa*Eg_Kq6=6o^OzjN64YUHy5$5zKK{xzB&Iaf+@pf879YUejVIXE+P)!p9v4Yw?qFyBkFL?@Rtn=J{hT>>;fa z#JP5mK9%wBr`x>()qg7e{fKwq=I88>Q!2D_28bA>!i&EoBRx_rQI5O?>``KxD_v)i zyy?4aP@5w%rCS?K8L-oZXFK<=PzNUcr3K;D>sH2)3rZTp zvcI`uCU3?zj3|pnDt@!J9gz)2Q?s=W;b}mWy-Tt^v$_O)JG%c^!~;qGpXMPoKPpLZ zc4%biyZ-}T>T{iWn|3$a`-)bdQif;CQzo_9?3X(o9PeF`;A?z_WuX~@xn>g2D(6Kd zc1Bfja(@jM$H*64vRN7%mCDIgV{-6Pnfs4+fPyD-6rG1p4iZN6n!R8y| zo3@~SVO~Nv*$;9nu0&$eE~Q^9Ej4FTbIhyU7fVG;@Cu_pRlo%)N2s(Bx3yXH{oCs+ zOKY}S5L%HB8mO20z4Dy$c1^x+SgBf+w50twx3ay)PP`JTHnV__`}ZpZMaF9$nyFMh zMr>O|q|!uWuNEDAxh2l1Q&<$+zEEqG7cnxG=H1aJILAMSbrOEJ+shWz%SB<6Ujp<+ zv|pR_g5hJLWTADed|un^JEAuDBeVwgHnZ41zHsQkji6M07l%Z)1V7_c{I%RJRZV>J z6oUZY=@(sW^(Q0+HC?#;Bi*mQ{IaT6yZ9obVekul;wpV284SM=01ubarmZ|*x~yAB zwL&}Tk|@iZWk4P-c@yr@{N&pdPD#$7)@%2C{x+eR)L~U*r?G%P7@4lq# zU?6oUbpkg>t|^Swkef22#d`hOxw%uK_!6@yxT~S>7h|KBJ6RmD7izYQUnxy%9kMpG zJcgf{(;jx^G*Ot~bPXYIr?+s`gaB}|oYdYQ<~j`R1-~TC#IayU(iEbMxdOR1N3t`5rbAeMw(kQ5TRCabrvb<-U=*cverS9?gI$C|;7B6`xeL~&1DRZ4+ zuB~G^T5OwBxBAfcCtk?uy(N#NqKf}vaYk=3(oDnm&~wvII%#fbLAj^P6LGQi9?-TF zc8C+7Z0^Xsd+^GPhHf{{a2!u zxlV7KPHt)0Ss>GsUDkDY*sR~wJxv4cSB!B55Hc^?s}MF?HY*oOf1L3vTcG#^;x5l? zFmGj>#@NWtMNI%{S6oq4+(KL_#|#MZpx|l2IjgU`tV~OStEcUzZh_rN?DBATi^awx z1e}JW2ReOfqhA?)^JDCA?Fu5ky+p7^HSXVzNg*Du(3+TC;WyrXe6c~Vl(KLdZ!xUD zIpcphnz!sw?7O}w^UmVeelWm{U05zlhwA5)8qX`m7u^SzV$*Jz*Yx*9q3@hk*U;|KtT)Ge?dvR_OUn9`Mm{l-CL>vtR?8U zIkqFE5rC=;AKy_DdZM}v$R=JOR==GBO(BGC8H#|eH@%I}dnM;RDrE$8@#l+eKNREaf{S+~MrMJ0y z#t1}N;9GY3+ByO*5M=%^2Vff2(FvjdAb%L=Ob42`>W?vq-LDXcR=5Zb+v1br0urwJ zi8ue4Avqrvu^lQb|2~QfaFO3TQQsufy3svnu2USYJhO=6e7AIsFVGTBVN^86u~q(W zH;IrNs=I_~RaXI5p3tA+Y@SLThk zk7k&bI;f1($t*2<3x>XBGab6Mz9}&}Lf#LsC33ZBSBa_cE~r`W>s?uTy(X)AM5=yf zKhT;pXW^Q=Hzk~UFRd#Di#ly1sUcLW!;+~%M$~e}}vIM-&Zjv)Ln*V8S zPy>-ee191Ojew-qnktatG;Wsfc^6NqPjJ1Ro{p5t2$`xN+imSNFQLi#&>eJ$&%X4d z_=cpYCN~x_=ngK~Ih*17>FlM2!;X9L0Y67VS%B5R5L_T*YyT1M{!U;`yh7c>+pgjq8&Az?-E~( zkx56*6<+KyPAW1u8IYt*VW-p>$f~#vnUS-45IcHMHLvNLBR4>8K_02Y{e@-**IH-Y z%O#8%;+&^kmlmdrVYS;;rfUh1EC5}c^dy9FT~vy+BXG-k3_GOa_zseNIsk+^3bhrg zeI}Vjq?+gq?8drLme=cZpjx?ZQACMn_1Jav+|>V`aV4_XO{b6)a((50;b+60Y-867 z5~2M*er^7nAF9RBG9!whNQ*RF9^m+DT@<)LM*sUeWj}8BM`F)bS)GkSMm%ldpLh6)E)~6=dt~ zY>Bdf82M4P|A;*+kgROfWoK`_mrFW`m{bqLN7+vItFPvE{cU9SCui~lA!#)x89ZVo zY=((YmKFM+s5o^+V?xwh7~kn=k|KfSu#~Xfa8qE1Jwm;53lU#m@y)(-L=F6?Xjw# zrJsn0+@35rAh2CGii?*3Vc6Bj_4~Ys z#7l%)AyhI#s7d@6P|2Dn;->d$pUdnyb8vJfM@j!5YNTHtUm{3IKBPShN+_e(j4P=l&m|A03H%6+xu)$`3Q}SAdRvY(!J&D^y7b`H7yD=F6)Vhc+0?9*c0kIt#KGY zMth!ZD%BROTv2Y)9|B2@xSl^5uUoK?fqIYsfawlW)e49krd{vtk(6En8DP4@M`bUM zBPUuuF%PqL^DM1)D9e@HX)?Xkm?U|Kg%h_FO1YJ#{){COo#lLaa%;`559CLwb4V|V zMI(QQqP-yR56(Qle>zJr8t;KvqVLrz@(flFiwtDj1(SI?J^sw3bv=zCnQu$|o&#k~ z-G|}Suf{%375v6J-UtYR+Y&ZT?##Ohj+!$ZlE4uS@BGshbPJP^zD6CMuejh^cs7T#qa7rjN?ZrqkE$vHgkIcNL6BIb&QCid|)~?6b30)}l zzhe)Qt!mqsp>0uAd+$ZpNZID63dHp8cDu+&T=Af;2xykYfW9%%+I_2LbRW7TdJ(I0 zbj0ZrQV}1D=w$zlPU9JOR`G@uX&=8Z+_Y2y-*JhrwD_4A`s2H8Ecn^Qul>9cVA`l8 z(aQ6eitrs-A2DDH%7HpmH zZ$p4GfDa0HcVZFWV~ZvO#Z=B`HX-yj{sTUeEpL9{sN z@5|a+zw8VyGK$61-hS?qe?DX=G$UgQ7KAa)-jHMz@I+!sSmgv+ThPQE8kBh_!POxn zPX{GBZb@Mb!|gK3yQaMBkb~kuYM2q{Sg(6Vo?s-^GvjT*hKCRc5v#jL?0Kp+x+G9V z!~bj_Jej|K#uq7eh1z@ma?-=Hz1xkt8E%M;9D1$TXqh|d{;$bD&SYfP8;U;+sc>j7 zNSzb-haNEp3zwIiuhmQtRm))Q&lGEGpTX6k;}S`zR-=2tY?YbRnaX%I-RC;YJE`0A zJyc3u<)eTrkjzO_fs~7AoDz@kwF^=?ozOV6+MZ==s{~K@qw3)A_)JF?-eOl$(1B3F(_k6HUa>CosCOl9&>Ax2&fzRRC zp(QMt7S>qmlc4@x8rUh+26+iySsSkPL_7~{k0zJkayxkmP8jLDw$a=UKbn@30QAl9xPc0W-0r6SfI56%$1cb9V2?MIq#+;*ayT{Yn%nv-cTpjFfwFx;Y)!b&cBwBQND z#siNX^NTs2ItIphWtB`Q9&;S170GT4{AnyNDLz!keJdW($9V(T!2H;Rge_iw3@975 za&be$z>t%ZW2B0FqbU)LGIG$BN#Wd7IILGkmxDz_L^h^_9v)LmN~Pp!pv)e zfn#+lY@cdTO;=y9SJtKw-v@vKYAcrs&S|deztT6CNkVre&^O6EQjWEd9OfRNB$=6x zh*ejtAe|6I%*4sR!dE|zE!Od_ZRqQ^?wXh-)w$RGBQ8>cvT=si0|c&{j{Q-eMT9_7 z29(fibs|S<;b)HKW#?tn?wz*?3#B~#c6jF!S!Z(os&fx^4}v;vH}?J8LNbVE2Pd+S z1OyK`ebco3cHAH8dW_uouKe@dP0#syG9wwJsS^j9Kkxq9-hS@5WRN)t!a)*+Q*>ep z2IAh^^cS85H51fEzeA(4=0@ig-E+0xmgI_$9JW1i;Y$T6<&k6JV}X<8Z8BZl``X1E&VqN)%R095k)JCtTG|+kB#p<#f@>F>v?B3J+%-%c>uFhtd^HFA} zS$cu!OZuBsV?6xbFxVAOZ7jo+XbfMH&FuGwS|783kbE9>Y)e@afmkLq%59LYMaT=g z5-bNhpH~fl`jGw&0QUf>9$102K9G6veAZ6IUVLTL{V z%AGibp^b+XUN!?@s2-iGe-R+^- zn07W`wh1FE4PdCkAX$Xq`{$F5T6XxjRR{+O9LQBEt$zpjO zwW-uFe5CDH1A-W&O}08mP-#LI^;nk$Yfj)a9GJwiz$ML8#uy*G6l5RLR$$X?qn;fM z@{3^85C#+F7eNA){3yLV_->K_n*k0X5g;xQncxeZvSYCBO@)@~58b_D)UA()C=`Q> z<;Ngu-j$g~pb$I<+p(HOqeC!v_CcywxrO zMz-e3^igVXlqT1#U34C5%lG2X#~#+80e-J6+<36tGuj4c6CJWN*uHR(EPdEnhn82Q zB)UB&XN`qGHjV2#>Y&z7sjIFJprDw;{k4>6TZ3o-@ z3If8Clqxm5g5Ut!=~Pd|26bnk|DFQYbdW%~o`GdwG6{6rq{C0JLg@D5uzd(?qEfgz z-qyI-aMrE&V-_^H;65|Y!6_t18iRBxeI}cWK)j1Q?6{xTe%}f@3b@=wND|c%kMgSX zAe3d#Yr9kp+x*-;uAFacp+Aca6wagwRCFaOvgOT%@>yiaI&5KWMwZ)7!0j0mf1& z$PW!X!XV*xXtc-(jv|C^`t5NA7?L=@F-f{z0NEBue7y2n<9rGVf1hK6u*kUeIKt-W z_qZIIhBwNP79ViJ5CG670cv&H#xHW4s&dQE(oOxJ$J5RTFAfbqC`5pk-A;3M;-L}9 zg;K5ASW)d6zoX^oPG7`tPMp8%! z^iXt56o98ZuS*Bta9CdM!J3io&IZKN^P!61YYykTe`l#1V=;kI7($i>8tn`;*SAap zQ(*J@8^nI`@@x)%Dc@FPrJGKGB>)*{ay^mOw6hg(g3)Ta`+?q%uWwD0dytu$ZIgxo zr;)^B@I<>T0fISzyE5IgfibBxOIK&AwXl|l?s;C9ww55Vq^EFYD8Ro(3C5}|Pk9vZ zZDFYr1+=VW(tA0p4tbMf?y}yE#AK*86Uu7RLBq@o1#d{4LJQ*3Lx>zY5~s1i;Q+cB zvDVD9|8Hy_iUlEG@P#(~|q39|PLOjvXWUikzL3rJWV1pn|6B9fu zWM_s;?1{~&1@5Xp{0p3R=UR9c($p7jqd8Sz89-C9*}1ZoZ$nfMnY%!ZPu`?^wsO#P zxCwq_-S3;0{xG5m-ZBG6=B-DrC*P^uj=OQ)fNiuZI8edsNd+-}Y9wyYU8T7~lvV04yyFSONujFO*W4a4{W9ugmrFslQ)y z29%BQ#>%CMkyRQ z^w{F{xS3mOEpF*5xcor~-;1_S;@E5uz-COP5pgR0GgNI_>9wbp7Br(qXHjN#%hdDs zj(Z7J1VL%ZO=?PMtFQU&-vY)l5iXG*SUCCGp3L53S+0NqytU~7Jb!)d?@4gl*=gLF zDhL+ZkqtI4ye?n*tXrYK8GaJ9&hRRpN#}v!A$wi7ce%>UwKlb)VEdxjdF81eCPMnZW}v&qSN_hS0Y{}L5akx#VicxCM9rasa6oecoGjT4A2v&4R7;5O8f7q9TgKC~#p=X(K%GrEe^|wC8%e1?ojZr3 z_5r3Une@fYymNahhnPNFR@J2yuJ^pQKZU`<>RZhMD3a<32#D+_*G0brNno(+8*IMb zDN>vJz(>qSJYuw;6R=2kf8dXsOcgq-1?y%>Ei*fE%8k*Hk#b*WjI_o2@#Smc_avn)}RGU|()+tpK^ulLKkRVkI=y{P_H zM9n6R`|4eB!bcQ9pe})IGXDeul^0?E zWT61$^6lw}!(q$Cd3A|8aMYtyIqAZb`$spK5<`^DHH&ll~+c!TYF|A;j(ZP^KiLW?~v~ z0qZi}qhBH_D!9FoM7s?FcB`=N=X;r1S-#*9sN?PIsFP6z58mMDl8^ga`9PFvEM9^i-@S5s;5IjO8n zZ%A}JF|KxS5G&eVA=8*b@#v@j(dw?cV?%5ua{m=t(tc4(o9NOra`^#eM!M^mF;ap*MbpOg4LG^E!U)og%jg2 z^{V<>4ZsyO;b&x$Q`nH_O!|Y0<5#r9wtE3^BGW;`fi~$Kc&cOQ{5N=FS0BK{9uL`g z#X$7E{kN?>aqs;px)}e#BNum~la| zf+Es~-HxV{AyPcbCm`SiK~xJpL((8TC4HQk3J!42dBoUFkhrcs$h8H6Vs;p2aF((< z3;DpePmfQFN8fV+ydyo;St%Cm!lKAs(>vDMx{lsIOFT2Pb$tl+{X}zhQ6N*hEO#Vj zDXD>S-19d?0*gOAd`<8d4a~m36yUz6By1E3jAC0a`TEr#Q>%%Kfa}}Ksb`z-wb{r5 z=N*m-4%F#rXvi$BJLP3u&r%Q^KNuAX2LdGO?p$2*x64@UM_P3$i3EHW@a}B5EJ}7e z9)(8UBOw)LZqh9u^;bVn@{Nm2lWxa+nHNiUrE_IBE4p>fC=!s9*K}#@4h9L>Fk~}x9oW!Oic5Y3DHO5b9^y!k{$ycJvFd4su0LaYA9P+@pVOiG^KuW{(!g=TdzRl6p5zIp##V+lYi+Ef-tSKHcvYn%3QtmJiP#qLr(Jy zgS@1jKy60V$H#*VTHWg%4`xKvMqk{|ffwWumy_CnQ2^`X(FR16$Dvc1z``jXyKoJ5 z;tzT!FLAsV+z`!pDG0F*VgKKVnG=zT+p#|IpG+B&FxC!=?`b_;I?%EG&)ij@?d|6c zKh$Hl8Cz`luKhN=Vdw5)vUx>Vllwju03(D};QiQ{uH9_te_h`%oJ_{^8CH?+{~DG; zJsGA8`)@1ka6LK`^zHZ#o9mhSE{Lkg!|A?8ak2E=fk6q>-5_S~U!n{oGXP8dADFB$ zvg-DiKL3DZp1sSNKHgRNYntw>X@TSjOlfC^oPKV$r56$ZJas%I9-RYJt&dvtp^s%$ zuJ3oatx!gg{s8G8Izp{H8opzTr%R$RY=Ur5K>?(jp92B`q!xlBp6`Z@y0CK`&4=vM z)1~$IZY>0hOexNyG!qvgZ-XN`O}FRUua@<|(`PX&GlX$4I4HlFp7+gsw&me?wNRtLP2Q)d`JSq}nA>JQX&B}jEeQ7e%EARgEeqWip@&P-H z92vEo1HP_crG%KChhjgDFM!6T;T(AxiMARr=hQg7P>TjOmq(q{UMH-yzAKdQ0C|Ux zA#e_6Hgav~uFExAkSgJz#`tBo1OeQzhMlR>S9QL${-p!ACjA;?M+%(OHJ{Zp(@3yW zeqT$@09Ln+cNT?zo(E8Qp-`|rC<1LSq^CZqSG8t90m2*y_z225+XU?c(eSDXD%Kcc zG=6efv@lknfkt)dHE8ucG2mY3e^u+%z|Gl+fcjugaf*Ca2?- zBnKd`W*=Fa?y*Q0GZtCavX?9;V;4?aCsPlU$`mkClV!f++)leBtXm$XRotY1Ao04* zhqnEPWvGXQaEqwNkbnpH*U5KFidGW3OLCcxIPEkfIqzL^hTckgrvMmEVCo0pl#E&v zWQO0>08H=iTy62%@|&ube=AUddz;OVoK*fQCTNof<$EvyIh7@f>_Q7ljox$RZSa1@ zcnzMJ;CCrt7ArmA4c#5FzXX?16FS;GmOO>pWNn*Ib|qv9ohez!w&(Ge0ULK;=Gp)0 zcT!=absWSSS22fGS(ZE(BQ3=IL%yf)tsa;4cEIrXkQ2?-Kj-Ob{!DP(U1(U5D^?s(Di_-U z|EqbneRVfXjW4mQZ+ev(pF~xD*)yiZ8U!AXOSUfOQQLEfs*iLfd-fM*>L z0)E2yY4773(-shV1t2LL^G#fb0R5rK;Riq zjV%J`#P{uAFF%PqDUlbKSoL?%3|T03RD(M0BHB#`nKmE%RMrS2Y!d3ja5JApZ`u=$ z4$Jt7O3XVedm=e5WSv&-gC?sHKPdrlt5y^Hd`~*79z2{_%3Lj@*#HA(Ue^Z%C}(Nr zr6ltm&h{gZNYHR6pvwBtZuTX3MBf)m`5X(BVoev*%~XEf_IxNQ*z~kr-jc5fUjB-v zSjcT(S_Jvq&e`%!u`VS14^8C-73nGw7M_HkYn6i?bm2+TJd1U!bW)Jwluv)(+ezvbNJotU5eGXBYoh!@fQ3*8N=QgyI^0%k!MUva<;Fzuq$2pHau#=h9`9z3tcuM>+(jqtd%G2qnfqy3MVg+j7~Gi7CYb`CKp6BovJ_>TDG z4h)O>l}owkn9De~_y2^f7@I&00a-E5$znBJ0$iJpM!-6w{u4oHUf%pZt=5u(9Xy&M z@T~?J5V4Iq)?wbXbJLx)lpkjq1E|Cg)GT6(|0OW|%LMYvl32&T{@6e9#d#fDlhHw{ zB%T?+r3KSU313wbAmlv=ko3gt)sgwzRbQI2}Htcvsn zS9uB&y5jdR>|&6B91j3xFaRs$c6uvx=lJ23i?sTnmZHT8QRKb?c0F}4}$Nu!xNyV%l5 zV__ga<=1#Aurpeg`2j9-r|HP_L?aD6tnFVk5ki)<1?vP~2v9N@FRbU#cml^@ZE)f8 zeTLf}IGp$e@i-TC<*T<-0*U-UEmCE9+t?jM=8LBtdB8|K`IlCu_grNdJ)@OmqSV!t z2-)0GvrU%~1X$8UH<9h-E9MoR#2dRKm)u&w;KZg)s2?~#_>upBW}BJ7sVCvT9bVVg zvX?hpA-qxO_t}>Q@NW0*Y7W|6HZQtpOJA^W5Pwq81Y{QJe+->p0z>EPhCj`YwUIS33FVch zg%I;&KB<}%_l#n{4 zyOPJ)3@?%XF=VQ9{$`Aw-{2m4ni%zg1zB?|TW6KV$#ud{f6;-tFy6GKB9n{blNp{# z8MXe|?^32Va^82sx!&%@;M-~a9`D7IZTrYDxuAIcFW|%l@*vze~DKEb$RW5g{Fl_1wj!o zUjDD~0vI^?X8YQ78IxT#!JNPv#rQstH^`8?@xF|D=N9C93s?b=I>|-C0QMIcdEcCP zQA@ZUN|{ZuT!y1+z`l`nzaPoTiw=U{zNU8mW%pO$f#JDraQOltoegAiHlsx1}X+g zJg^(J%H_9@&cSw(f3ez$&mhg*io*Oik#C!ivpvrU)WH)Cbw_D8$kMGSR>Lh&8W+8k z)xPnwZpgb(nJrKUd90Wa0?Gres|FztgBg9{MgZcECf{HjeyoxNYflKz4JDy_dS5+( z?s*WfF8~G!n$}sZ?O;+|zxt_!U;i7~_ zNkLUg=E?=L5ywiX#*yl!WXZ+>IjH6d{+}MjS`Qw@#-|FkwVdD}vMWs;7CPwlE8?ZT z35`lRh{NLTdB{BnjJEJTisLgJO*jm;j8f!K>~rrbApIse8t8I(Hx}GvM%Rj5hED8_ z8I5SM{z*s(IHduK1*pfS5qOD2^J7+Eron8!`UCpb<2XaUhWzLF~)(Vfpe+FrlQ@WijF<*p3f zS@p!@NB?jWTE`Njnn1}I0G&6)caQwE!sBfk~1)we0 zJk@wE7hMJ$30C*nHIsomY&aHHT(@5*?JvHoKt)rWOyocEzyf;Q-F5BukpTN2b?dZx zusBT_aKleu>`cK$J<0qvWk1jbS2@}b(;2P+E`O)$0Llfa zMwBlEII}Yqmm9S}c_M$i0dSHpsT)B-1t&j-DO>gq&ZjH~bt&5&qv|9Q z(G)KeXoo0-{tjX^vSU}H@|=&)yF2H34d7nMBql&&rg`v?MdKU7q-=8&}i-gI0ysW zp#M{dcmdfO*~JD||ER&{NP@yG$bZ?P;US=9js=S>`zvT&;jjT2Zo#o}bXR1}aZuVL z6JX7Hub;BOR+c?<$2<$f1Hf_tz?`pP`<{yevu?S4Lr{h-4oOki(a<4Bx5=wLk(C4` zEPZN0;I#x9bL0$*=;GGr2|@MS*mtf>%`geInM19(Ry#lq1S+LMeJ~iL2I1Dn6*b4y zBxwzwcZ(hzW(@KZK?QEC5uw{9(@YygNnjoe+@?XAhAaIg?^*@w(y{MsZ_!*Ct^8&# zGG$sA9&%L(YLJs~X6$M}4DZaOW9*GdsUfIgORXBmu0^|qjEY%p@JP;s>g4zH=lxL! zb0L9pAVSISdyCL46aKay+2$F9Q6v34f=Ts^8C`FpNwl~4`=$NTS^6IRn#d z`|(H4bs3v?Npx!5Ue3z*;&l;mR{v3K$M2Nonsuhv)#K%qo+*(Ph9&p&(l{$=*8s_) z;4~r1tviLiaXzZ>@vC;nHHW3pK&sulUds|Ox!1bL{TzO}mMo0bU5$bC&%*$)>l?VW zGCv3Ce^KOw<$;O^8m0m*Xau5RR*4z^cd~>MxrdhX_0hokQUCc9iAchg_3tsUv9V7z z?j>oo&F4oBBH27_JD!)KKB1D*BArA$xgqfg>tn zqAd5s-`OwaAA#5 z>s|Y0c%V8#|1L>!28jCvu1Y!nEBD8c2d~KkCfTSV^=?9y?k_k0RpQ!hJ@DdsDzT_< z{E|kXF~3AzBD%`=T=(Y7HSvQc6-tnxnG8Q=qY$=wKP-^gSK|YzRT}CbUnJ5W^=ehvTctJQ4@0NaI*m1&KS3 z2M`-woR}4c6^SKo)up$t3Y;o~HrV=cW6ikVmj;4LF!jj4RTes7HPAvcJeYA_-2e$5 z*yn~4`h8PA8Vv9SM-#Clg9`>_d<>f#!|`}#)zR+}^b$l4PagyKYrNcdd@i^Ai*1fs zKwps*lB9Re*(Tiew7mFTmjvf?V}g&DDckB80mB-gV)`+ZFyI^K(V(BN(%-uJQb#wD zDKfEW3Muk19N@T-!4)xbS>4VrouOPO)u!f14ftsBHl2Vu-IU_`XDxt6gh}s|-+9c3=05BK6jnOXJ<#}&zbx}WMC3Tw zkmfF!h6(s_YD4rvhbg!@gggz8Ju`vsyv_N(%EDjJO!XU=WS7P<4oVeazS2PGS?b7) zqm%%SL#mk_L8SFWe8`!)0S`#fn#yQ3uGN^ySP#>{10B$T4LrOMdcesIR;~#xLwT1I z^8^JY0O|mSU?A941(RRb&?bNh02xj}>w)eI45SQ0SWzb0b%Y&=W>tWD>={+S!EQF#xC> zU@{~p;=n(fH3GPK&^@6&EjEO4bjee;@z+ND_u(6I9`8%?zJc}*)jn2`{dj5&UdNXX zc+yJ&S6shC^@oOgO>_xYy(gh@>sDQu^LH7kM*@qS-tXWjWdL73V-em13=*c@>9h9B zIWQ`alPRN+=-!(O`aAo&AYPV2njF?O@DD(s6aN5eKr#LjtvEV3fMjT_WTGx@W!%BW z7#zd_ZPv-eKY^|RK&aPcm-%l1@?+3}ggpzNskN+y)C!z?=;e(GYwov3KcE8-uu)pv z2Z0Z`BH0qXI09HMn0jj~!9p|nf3uRZs{*Gf&_W#+1T3IOcn3~)no6|>D+3uN1e+nK z;9WVhz<_^Y*t6m71!POd=TI7`UqDw&*6Dc6D z?fC^v9?k~=(GV)C6(QU(0ca7CdSWssu&s!gE2mJ510t{>m(Zf1Ab)q=y5e z_vh-WT#xlB<?oJc>M#+%?khGzLr%GBgY@LuAXW3XXu{>lPO ze;v&h1DO6n1h0!}*eXVH(0XGHeh#WH+HMvOPmVg#POnCQVLw%d$7gUp zeRN*>hfv6y>1_<<8No4^%K;&sN~!dm&dX;no`w9@y!qqxPvjNTNzSa(AYGD=-g6O8 zwb!dt8sqFNPs#JTD`&2aDy3YQl-xP3Jj=+9eHtfK{!!Izd{VbbP@B4Oat*&`VDu`s z*{G4z^rgNv`SeD18QL_kerzyZvpP4*d{U*TcXkDv4uz z>3P}CYh%O8>0tKdUxJBJI65mIr3Dz&QwY>9Zl#x=7g-skBr?c z+nFmAuje}y{Ztar^h~PHma?x5hdhm>I++wW(S+q4`+@C_x%pj>Co&ouL%9{DrBRSf zd1%;zb34^}hgK<9)Bjo2FVBM|$~y}$*SE$3R{<;EKwbwJku_30$W1CQclclJl<1R- zyPRBtmp7O6FP{$|tbX&LUZvFHXWqe8<_Ik0*#>;?+&v8fc08%!$7e&6Zx)-_RT&{z zrD7)Q%cU1<`gc>NRB2jN?-x9gdGyFQy1Xx^$M59a0eza4LW^>w8Ygj$9)?@Oi{8;3 zU^FhwEFgLf=mBPbYK2IR{fNo z|GMtnIfe!FTVRExs&*8SOKK21*t?jVehmMPWJedse>-Tn6w%Op9&lHJ~f z9`|a**eW9<18CeVY-}5b#?PPYe0DztOmzBW(uGLVp}mQI% z7~EW_O}elao%GD}cYD$pJ05&#Hh1?odhAy-rhZJHPPhLC^3}_#^0*{+l#FI4C&~i! zZ4OtW3W0K9WYFTpw|AS$gb1Kp!O-VLGcXFcW^?DJX}4VqnPk zjmd=I51&5K(7@h|4y*41rm>9?dU-j^vr>xh+`Snkzt}*e4jjlGh*oM`*<}Hez zF`!|Z{dn$zG)9Pc^7Bdll*fHIKxc^a>Z^O-phO-Oj5ww|`wlA@XLA4PIJ*#8e;)>s z6b+U5bEuhR6CWy8p@N^=0T9!*d_jw~)rrEm@$A~fHjL(X~|H97jeO{xcD&DY! z7|BYtwBVy}WHe^zZm~<+TdVQEf9q93k;)c&AFVF_ph;8+vCQcKkLuJeM^Z++bGSL8 zB~uLw$1=->%a}Hv*AmUT_viADydw&Q(XOK^0UNNm^V;2Yp%z7TYlE)U5PInJiLwcdci6t}wu$<6t%aIo>6)ZRqV54i;c#^ibwlxy zBtk|zGF)S!)n+k?I`I)>Fa*j5Ed)*%ulMt`;V|CYmpC>kM=;D#&VMb1A~7_V=%_U z^&K29Cnjp7@m#v{jsNk6puTW0wx}`*ydgSsDKUg+W3&~#6foS$Bk!%quBw@Gfosd4 z_k&GMz3>_1&D-o&4Fe{KD9>e{dG*{AZLS-rQ-RjUyv~i zh6d>B5v?OSM0T!uePV(-cv3Aj&)fXj3!0?8FYF|7v?Y~nCXEKmbO<-RP(Dxh3fzY{ z1Ya9^J(FLdcr)LjbqF``;4tIm>rA^>Bo>P?yTRAiIz&4_?$f&VW##JHzgy_kTg4xI zntfmTGAF*+-)kFn%ZTR1UVq$<*l%|bezdARS8~pt{`+7V8{$S*LBO#Gm5F%2EG&-6 zJV_gRsU%|*i8T^Q0D%6tD~$mU8fXYz{XqIuaYteEZ}F<3oth7q{+lgM*fERqo2*l| zS0|mY!s2H}qDX@@LA;*Wp|TFGse~mxmNtp|`x{pa!geZsEck{*SgsvK|6;X!VyQYH zfwpRanbplUM^|1M6TN$LTm1q0*54K)4OcC$>7Rt^wr^&>MF!6bAG4XnG%xH+RnS(oahy`158Hh4KSke#{2bpAqu zXEP!AYM2zN-sgScpWiMJ9thoYs<@Y9BXhj#{=${x;j-uK`jds6UR7{nm2Mm z|3=(HlZAAwPNY!ie8Oo=glQIoz@ksV2bf4SMTt6NZ>BR`LUS#03-e-pXDa>9;$I|e5f$OG3CFqx?%9<7;TfK8t2;r-VP@gMVi zBkR2*%1ma>m)XN~*P3(>#e&e@_mL`>ZsM^YF1;#rr35WJ1VL3F?*nZ?euNG8lG7nF z{ie(OtBR_iUDmCnEuaBEz%lHZz5!Mnns4u(@)Cz{db+x&y!oL7#Pfn>>f+VO zgv-kvd;C}4@n1ZbN310YEOS;w(GIDD6+c7;t3Om#N+6I7fTGtRr1-|s7AvXza^E%; z0m+HjVv8b&H-%INzpS!VM7B4@k73;eSz!o@OfH4h8E=)Dtn4(*6j6yaxBaK)$ z2*mZ}PTzJ?3whx4q)&?Cl69&vQJFssLnyd!75S2hdPmqZX?L318_M;cwmfl~3vr4H zu@YNO(3(1x=PH06NB9R02>(C^Z*J&h)DeS951;Aq^=kz*T*MPIn8iBA^yM#X<2U_a zQX|h*?-IcqBbx#(J=>i61k9;OM@(uvk0?`8r|kO@%34e9 zqw_RT-7#wpR-=DR8vfOBWgsU>&7rtaMYYo7mNTE#QeK`fsb}!0_Myx5a!pPirEZ=` z|9R_i%BAIuvHK`jyLvFyw!Kf6Dw#kFQ2hx{_d_6a+_$Wqi>n1;)fki(7L@~t3Lb06 z06<5LlxV&;bRT-N(2x0AjD(Vn;I3`z_QI?MKH%>w+u%*4@ip*dd7M#jF>WnJyOb& zF~#j8TxNrt{$eHL*9$5L{ zO=b`od>s)pVPYBV_6^Vi)j#}`J}@ah^HKieNQ$!-N$_XF&;ur?A5)! z@O-a7$-k?p(nI>TwpgEmMa#32+qPg&^TE@$mYuI_Fz{mRtFp%(d5e3fZ)SQwQ?QV;wA|Z3u__9E4k*7&oAAygtCu{0sbNU2@#d}=A%w}t$LebN#a=l9|jfw(~H=fG0 zx?(CLQwD^u!gBGK{=SGfaT@dy@g_ah<9v$Lr?-hl=BIi@O`yh?_WmT{6Gtx-zs zb|Ps}jFA7K4KSkCJtaeIrVy_Hs3Szxt|plWm8kQYn~XIiX)FgIOsJMXnc zdh|vV={8e;0)$*VRYcq}5W4c-8HcfU1Mrqd$Xt1>EAz4qQ9TW|8wKT3kxvi%-UN<< zhjq@hz97AD*Pv(@w|l*;Z#{B=)JI7In(zoDt9 z4n*62&pkN1@rRK@%zApvl%Zw}(7l)79g*y1U5!su=Q(Gk`|2u@R+k{&Us1Dkva85xG2}y+Y6{ch2m>{S-!jI%l$N=C%=FeCkZ2H$ zvX%<5@0nntdKtE)A|(QduIcu?{xkL14Jv)_RI%wNYJQ13aY z*goZ)AlmU4f#hMCtU&Ej`&WJr4-?x5McXw}nXlo=ET?0WeZ{XVCKA8%y~I@T4LKtv zcj*LKJgbNCRhP)OhdseW01hwxI52J%V5Qajlj<`(!$y%&%ICY@V*Pg-n;P%#=+5wB zy_*Tj3u~^3i_>47)YO`k<=$aE%9Z)t*-Ng{97OLn)bA&grlmrXBnam|*z9Fg9GY>) zuj_pLGn@~iPmh$XXd1e$U1};|dq@dPtnJ@BvS7E9o*p`F9^<=A@&9UlF>xjt-|;5s z(e1q=>z6ol>XO@N?w29Zx?yWG5U1Rc^z4u1K~=Ay&M&AHP=ftM&`+?xaPL7JF`~!` z?;++FT~S^Ak4gQJ#WOe{^8Tx}g$Do*&;8{LY>F(mkMt{PmtrNw> z%4W>dW$e?++yU(26t zM-ZYz1RO%L1kI5g+<~P2fa|rQKN<3=ADx4Q0BCp+rJTf3$Bmuj8;Dl0OZ|}cOUXh~ z1a$|Ak${8j00SPs{!MwhSpULtJj@BMyR6H}GcFGjYWou(tnX;+Sw}*L&4uio?rKf&%7AByP?7d(B=y}pyr%-O~zQq zigK`vazVd8Tciz^1K@Il@8V3HrjJBJc#>qSQ)TQwl|kKRUP)+5QiV}W%F~eAPnz<_ z<{|bNoUvoF6B_Yd4?^EO0I<`58C3^+?-`WcHC$MNYj11ITP&4o5ZSr?Or$M4F#CpB6Y{M~xK4xjy*qXcN# zd-n;uDuitpy+1=?Q6)LQBd}>QDqpud* zlu6prq}B1h{oGDAA&FLv)kkjWElpJ_ubn2 zLglNp3wsyX1TDJgb-we>%(vA-@c_8R%V9kFCZgD_@2h<4DqnR?sW75Ff0s|> zI)V@4|1aS43w$<{G;O@@%07imVUYbyT<3#Fv9OR)RgLQSb6j}I#)$MdqWS6S8iv@m z9dQVPFXr?`oAO8*nf>LZ5K^wu67$4@A5FvOHfl+iO*Qo!cNWi1hfsqhWhSSK3|r@- zCL4CJP_>9eHo?mJ=^kU2u6`LLTi{*K@u}ZS;eVcMTndu~mnd!WncmOtt|iSkOX9$^ zmw)q*1M<_(9><|Q6Hx*#S%y&U3kf z=I1`2L5^SVXR~$}LmqTScoO5*xg%&Tm=XhE!hfyWL;*7-Ga1&lM}+=@Yd!m5C79)y zM=IM1R@S`d5s!2qT|BEiwaj5$n=B1n>O#?rvF+P;hVRFi?*MTWbQKxTq z)osdpIuQ`(2u2^A!ctr#gaMcx6BwrRIeJwMbbD=>QuU6G+d& z*h{A2EhZB39w9d7i?*)9f<-`uNgH+;W)kK6u4^`O7z7{yuOcQr)H!7ICg0s5V}}}; z=GL@UWk4?R=By&H9KRT0LEJwW2>Ct8phq&J*{2SBviC1v4#vB1Cv_Zwhrtwp1~=y3 zSQjm39qhO9Zfi+kIToSN#{O{STw#zX<)BB6JJKWj!y&lyYUIvgeil&I09OKVut|jW z_Dr!y_Uf`z-}xyV32A=#uuY+CAK@ZfN(c?{lW9FpXqKhTC69Z7xlHGk!`JtG^lpzG z@H|RG$hTn>!rQMKfLW*A5t~wzW^SAmuuqsW=)tzDiM@^hE+X=8wW1i0fV7-KIudE0 zKm@ae#*XH@jlhR9bJ1zqZ8aeS9eU0WzlXzjyS_dSLVLfD8YkE%e^hsUu4}%ba_f;9 z!}M*`i|X`1P`1POssY#W)$fF*yV0@)w?B1pwL?nv;sXSuYk;6?qT0xuJ(jH>PYpWG z>XAIU30FV@cECj-R=*VEjbu4Vpir~;WQHtX#hDuWL4><>5_rikfDpw+nh|< zCC%o6oWnVI)d;dKRTaRwe=?v&=`VQ`FH$eJp4rtS1KKmg6$E&bqU%6;GNuE++( zSWyFDK69U<|0{1&OEI2f3bu1LkPuPTG|w0PkTNx0e!a`ltnRi}j9IUmM}WduF=%J=5MQ>g$;+b~9fR}`^0eKWB$KiA%!siCIF{ju2n<{1$NZSj{!4<9lx zG=y{o?Z(|U?p1scJJbEx=_%?hFuVYGXx5{uxRjKX%h9?`VefUm1~u(-Iq(0g2^JF11AR0E@XAH#W`s#{L^{fY&o*{i6l`#BS_cSM6$CcG`M^I@oSIvNRqny)x>1d!eLy;&U4ukHKUJ0wFN5B@W!^xu|>T ztWW`%q9AtDN?u)^;iJNFi6qSpmIT*RI+v$PqAhzsZ(e9Lkke4L9lPk@iA6Ji zd>B8XJpP0D=o32b$VD9J5l1g|bamAhn|>H+d3@$j(0?k|KP)_*?=P4eDhubM`V>Mh zkHl1!jCfp<>qqTxVaNhJ==u41iMOcO&Qxi6RaMU73qdZkIb{%GVWrOeNBNz-_*>u} z!(r|b6m+(U-CXxC&AK5XNn`#E#r$Cq|Fh`Mhph*@L4jdfoypAAGn!qtS+cpsYgC$_ zzXmuWIbnVLPRrjW1`l-Q<>a)Yv6vjC1ok`;fh7NImHxTT>C8Re7NP1M=be#pgPiaL zM4#;SU%GTDlIe*+Tq2n!+w)!%;k`dTN!68M)l3o2hKMK9K9Gkue=~ps|6@A_bloq9 zF-WwRL;N2k+E{wvze0C!;)JJ_&tiqn;5DT@uI$y}GtOvz{i&PaN*Gtr$LcG#O%z}I zhF_OY1dKnQ_DiRKsG*_p%XxmtUZQ(_tbX}|ji}7gn8Ub!l47!a6CWhXg*C-v!zQBS z*G`v3k;s}G3aSyXmFtA%F} z{+1 z2491y%{XIojOz@ZL8s{~w_RPZQ9Zv;QBe}u$}MQTkaV}LJ$iS#`R>{ziqo*PY=-zX zbOnD>=26Pcr+RuB@$q~?Ypq<1`qi$-N=-&wgMxzcEq=;@2f{@uTpS#nU-yO-j~s>n zcv(?=k^=e3jDH4x;Cx}?Lw=Cf;4I6+v?dpROM?Xn9c4*21#PHZ2~$(kneNQ+@6HE~ zWn)`M0~j|Im6Z**mPTd}-!9(xDLrrhrc1Hz>m4Ps?l+&m!K1#>6H$$f7-(afkE;4>J|Gh#jmdm;) zp5HCs`M~Lwhetm}OQz}blEv^xPO_4c{?HT_BcG2Ekg?q7{k7!AX*H*B&5{d`kqXp> z8&p($QmOLDO^?)gZtwQp&#m0afY+5A$763W^7)lj{jwc1Gc$ZD;_#6p^8uss5E+wl z@4JoQ&!0atva=OarDD5E*EQCiO_m~RMr0%;{90o;YV4~imQHyElA#=mU0q%00!F$C zDLCJ4ZP^Hmh}>XelF_aY=-!wgm=Bm(XD=MQaQSl1yLZ>c(~wPC8E< zue0WxH*a#@Ub}Y9a$%5zxWlOC{Z!=STy|EL1Z)&$AW#c0wNTmI!U}oWG&C8aftT&J zC&J-|_2?=bqmqi|=AJ|Uz9{~@YI3@{txXy{2;{}ZePBX0q${b2>L2(TOiMyanzlSv zZ#ewPrLm=jHRAi_mTk?vXPq>Xk#~|`5%1nQejm?-Gge$eq6@&{g{>{vMM0-Xwq2e4 z+3@BX^8cqhk}M(92EF)ev3$DfN9$W&;~CxF91gqkf%eF!QJF>1e3EZb8aI`)n1}|H zS~^rrO!98rxS^n^m<%+P^pun@3JwD-1x1jxCRAa+skHdLLh?(YqB*&t{pNzAib`bR zi=m9cL3KyS7)%)*NJ+04s&rHX--V8qi6+b8Plx7v-wSeC%`t7C^)t-bbcJP&#_r}K z+U+z-|7xM}hxWwlD#F6T1Pc!&B@5ylH&oDV(11!pLhhm9n%83v-#1`4{zf$FS_*pg zT|Jobs1VaiS@7(G6NQ=~I)^m~eTikFw=6m!yJ|JRhgUp+fhi{MRQr_bSH_PzRAhik4r#Mz-c+7Q?b!+NTWTF!4XgZuf-73_!uL; z?b>`B*x%dDmQ4~Vx!l&)ROa1IT#};)xwvF3XSa~V+d5h*kD*e_2fDhtjSUSZ zLsN^3xqg256znFSzUWjYGxNZzV+J}Pr}aV%IiV-&;Fr1oWuE?=hQhJlRS9joj|>m) z>NU5++hPS$Ls_Do{}&4-dHE!GGO?f>&58_&S^`Ikz96(3OG;6BIX8^O*|ndYs>LP= zdM#1OF)`$2R|j&KV>x1_(C;Tr*z*n1x9aNa2e2Oq2|1@xZX;W@w-G%vJFBRwnt^iM z=_Tp2S}6B4+vz?C%=E@Dv-lYVNo!r%YDLF4t!H~AVa({St?KCLq$MT_z<}qmTa$V6 zBms%HnhcmNAnVkg?a3~HJV}^R1=iQs?IuE%7iNrmpUu6uE}~R(Mn`;y;hG8r^BY&L zR9m(#MX?%oRXIC%npOyCb8?wa`XS+1=(?#kp3Omx0rUY2dbeii9dm4VSC>BcFa_=J zY!s+`)T5`SuCq}x{?@zM4jqhuf>R+(_gPn(EZMymF%-zP4xBVA>=Zo-DZWj%L`#aU z(c_?wB|5lweA!+?Ebd3LF z(Tn0RPw`K$IQ?HQcDLdC?U5bh{tEjd>YtQF&CL?%#d5IGQi2NFU1+3sla;l5XJthlh1VgB=Qy7q*ORBk5_Ju;t^cDBLu&M0oh$_I<^Lxe&Rtd zhDwuR9=*xUtq$c&*}@`!Wo6~M81#YtU)w%DK5}JN^XG_&5;)8!i{mz-2Q;>}D(UFF zgYuJ>pU)B+5^_HX>LZK!q=W`^6DKDp7{Q&twpXden!;}@=W14TRXW8OBh8dZR+a@oJ zK_w9eucDHYcn}mz%dMp+Es=Lc4STXWhO6Ba)zmV1>^FM9;lW*Psf6kFQ5?n@t^j(_ zJ1Ffla1GV>TCV~qd2^tgH@3CqRxdJYmOlh%o;X+$r?A0XVly|__tD4SzZ=?+gotRQ zl=s>-!SwWWs3eN~{4TH|JEl=$R=2(dMGk4BJ(y5&ad8bg(5G;i+~o6ca0rkB3JZ&3 zEp6@Yba~pk+S>a&hC~~Ar)7(ohLE%Ai=~5l_^xydCzjF*i;ZgKO<(N{9yT!@!^9U z@>XFoSc8;E{pt3Eoz*tp2^03N48@yJ6w}Mg2Q7E^cNf=t)QtBG!{XzqC^*c7X3@FI zHa5j(W@aG~5xv9mXK`K{kDOz`dD#TyNo08e^KWu$>Vu$-g`v!~H473Fl4ql}-ULnu zO}DGMBAB%;wpVmvF~MS!1$O}Z-N44i#&b}&i;Ihox9!4on%x;JjY^04e9sV-+L=B) z{Mcx)SQaeROgc3ga6X+^cPGSw__<_X0YSk6FeiHD={XB;E(+?@>~fv&1*HEUIgbCj zs;UYX53jqz-ul>y6PYlWpiF{@MxKxFCF<9bpyhNsKg3-kBd9A~p4D;3f>Aa9K76n} zw`xBFW+UqB*QX)aPYxDcFyFx23yp|Kd-)Ov+WrCW-deB+Aw>rCFa3c+qm0~KWp(u! zf5t;NQLac&xV68(k91>rwyxYqycJuczN&eTU1pb|6(^>qZgOy_(9_d%I_~7dW{}3& z*%@xpaH27^bg^Uf0 zBhGGy9@aO)8f8{6W-DFY+zND?&ij*d$T{w;b(AeuX0FeoZ=z7&!<=w%BHq)$ literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-rate-linear.png b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-rate-linear.png new file mode 100644 index 0000000000000000000000000000000000000000..09e8045e15abf6b96c089d171635693a60aed60b GIT binary patch literal 50813 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
    _8yl~6 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

    XRhnQ}H08>D;q7lu(1A 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 literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-rate-loglogext.png b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-rate-loglogext.png new file mode 100644 index 0000000000000000000000000000000000000000..127bc7f2fddc37bcfd0863238db2c7874f4e210f GIT binary patch literal 109923 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�S;#YCJ>3E4Gp0$=R%K*`_zT?& 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 NxuSVFSK-!^{{fq-$;AKw literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/tally-exec.png b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/tally-exec.png new file mode 100644 index 0000000000000000000000000000000000000000..e24a145d09abc70ab36c6f036bce726e8410534a GIT binary patch literal 231859 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


    >t>*+2Sz_Kd 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∈YQ8Q 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 VZVAzj{5LR4@tvC7A6e6o{|B=b*sA~l literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/tally-vote.png b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/tally-vote.png new file mode 100644 index 0000000000000000000000000000000000000000..7d270fce091298627d9c181c315415c7710de784 GIT binary patch literal 40507 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 dynamically, it is not always possible to determine which accounts hold a particular role. This is important as it allows proving certain properties about a system, such as that an administrative account is a multisig or a DAO, or that a certain role has been removed from all users, effectively disabling any associated functionality. + +Under the hood, `AccessControl` uses `EnumerableSet`, a more powerful variant of Solidity's `mapping` type, which allows for key enumeration. `getRoleMemberCount` can be used to retrieve the number of accounts that have a particular role, and `getRoleMember` can then be called to get the address of each of these accounts. + +```javascript +const minterCount = await myToken.getRoleMemberCount(MINTER_ROLE); + +const members = []; +for (let i = 0; i < minterCount; ++i) { + members.push(await myToken.getRoleMember(MINTER_ROLE, i)); +} +``` + +== Delayed operation + +Access control is essential to prevent unauthorized access to critical functions. These functions may be used to mint tokens, freeze transfers or perform an upgrade that completely changes the smart contract logic. While xref:api:access.adoc#Ownable[`Ownable`] and xref:api:access.adoc#AccessControl[`AccessControl`] can prevent unauthorized access, they do not address the issue of a misbehaving administrator attacking their own system to the prejudice of their users. + +This is the issue the xref:api:governance.adoc#TimelockController[`TimelockController`] is addressing. + +The xref:api:governance.adoc#TimelockController[`TimelockController`] is a proxy that is governed by proposers and executors. When set as the owner/admin/controller of a smart contract, it ensures that whichever maintenance operation is ordered by the proposers is subject to a delay. This delay protects the users of the smart contract by giving them time to review the maintenance operation and exit the system if they consider it is in their best interest to do so. + +=== Using `TimelockController` + +By default, the address that deployed the xref:api:governance.adoc#TimelockController[`TimelockController`] gets administration privileges over the timelock. This role grants the right to assign proposers, executors, and other administrators. + +The first step in configuring the xref:api:governance.adoc#TimelockController[`TimelockController`] is to assign at least one proposer and one executor. These can be assigned during construction or later by anyone with the administrator role. These roles are not exclusive, meaning an account can have both roles. + +Roles are managed using the xref:api:access.adoc#AccessControl[`AccessControl`] interface and the `bytes32` values for each role are accessible through the `ADMIN_ROLE`, `PROPOSER_ROLE` and `EXECUTOR_ROLE` constants. + +There is an additional feature built on top of `AccessControl`: giving the executor role to `address(0)` opens access to anyone to execute a proposal once the timelock has expired. This feature, while useful, should be used with caution. + +At this point, with both a proposer and an executor assigned, the timelock can perform operations. + +An optional next step is for the deployer to renounce its administrative privileges and leave the timelock self-administered. If the deployer decides to do so, all further maintenance, including assigning new proposers/schedulers or changing the timelock duration will have to follow the timelock workflow. This links the governance of the timelock to the governance of contracts attached to the timelock, and enforce a delay on timelock maintenance operations. + +WARNING: If the deployer renounces administrative rights in favour of timelock itself, assigning new proposers or executors will require a timelocked operation. This means that if the accounts in charge of any of these two roles become unavailable, then the entire contract (and any contract it controls) becomes locked indefinitely. + +With both the proposer and executor roles assigned and the timelock in charge of its own administration, you can now transfer the ownership/control of any contract to the timelock. + +TIP: A recommended configuration is to grant both roles to a secure governance contract such as a DAO or a multisig, and to additionally grant the executor role to a few EOAs held by people in charge of helping with the maintenance operations. These wallets cannot take over control of the timelock but they can help smoothen the workflow. + +=== Minimum delay + +Operations executed by the xref:api:governance.adoc#TimelockController[`TimelockController`] are not subject to a fixed delay but rather a minimum delay. Some major updates might call for a longer delay. For example, if a delay of just a few days might be sufficient for users to audit a minting operation, it makes sense to use a delay of a few weeks, or even a few months, when scheduling a smart contract upgrade. + +The minimum delay (accessible through the xref:api:governance.adoc#TimelockController-getMinDelay--[`getMinDelay`] method) can be updated by calling the xref:api:governance.adoc#TimelockController-updateDelay-uint256-[`updateDelay`] function. Bear in mind that access to this function is only accessible by the timelock itself, meaning this maintenance operation has to go through the timelock itself. + +[[access-management]] +== Access Management + +For a system of contracts, better integrated role management can be achieved with an xref:api:access.adoc#AccessManager[`AccessManager`] instance. Instead of managing each contract's permission separately, AccessManager stores all the permissions in a single contract, making your protocol easier to audit and maintain. + +Although xref:api:access.adoc#AccessControl[`AccessControl`] offers a more dynamic solution for adding permissions to your contracts than Ownable, decentralized protocols tend to become more complex after integrating new contract instances and requires you to keep track of permissions separately in each contract. This increases the complexity of permissions management and monitoring across the system. + +image::access-control-multiple.svg[Access Control multiple] + +Protocols managing permissions in production systems often require more integrated alternatives to fragmented permissions through multiple `AccessControl` instances. + +image::access-manager.svg[AccessManager] + +The AccessManager is designed around the concept of role and target functions: + +* Roles are granted to accounts (addresses) following a many-to-many approach for flexibility. This means that each user can have one or multiple roles and multiple users can have the same role. +* Access to a restricted target function is limited to one role. A target function is defined by one https://docs.soliditylang.org/en/v0.8.20/abi-spec.html#function-selector[function selector] on one contract (called target). + +For a call to be authorized, the caller must bear the role that is assigned to the current target function (contract address + function selector). + +image::access-manager-functions.svg[AccessManager functions] + +=== Using `AccessManager` + +OpenZeppelin Contracts provides xref:api:access.adoc#AccessManager[`AccessManager`] for managing roles across any number of contracts. The `AccessManager` itself is a contract that can be deployed and used out of the box. It sets an initial admin in the constructor who will be allowed to perform management operations. + +In order to restrict access to some functions of your contract, you should inherit from the xref:api:access.adoc#AccessManaged[`AccessManaged`] contract provided along with the manager. This provides the `restricted` modifier that can be used to protect any externally facing function. Note that you will have to specify the address of the AccessManager instance (xref:api:access.adoc#AccessManaged-constructor-address-[`initialAuthority`]) in the constructor so the `restricted` modifier knows which manager to use for checking permissions. + +Here's a simple example of an xref:tokens.adoc#ERC20[ERC-20 token] that defines a `mint` function that is restricted by an xref:api:access.adoc#AccessManager[`AccessManager`]: + +```solidity +include::api:example$access-control/AccessManagedERC20MintBase.sol[] +``` + +NOTE: Make sure you fully understand how xref:api:access.adoc#AccessManager[`AccessManager`] works before using it or copy-pasting the examples from this guide. + +Once the managed contract has been deployed, it is now under the manager's control. The initial admin can then assign the minter role to an address and also allow the role to call the `mint` function. For example, this is demonstrated in the following Javascript code using Ethers.js: + +```javascript +// const target = ...; +// const user = ...; +const MINTER = 42n; // Roles are uint64 (0 is reserved for the ADMIN_ROLE) + +// Grant the minter role with no execution delay +await manager.grantRole(MINTER, user, 0); + +// Allow the minter role to call the function selector +// corresponding to the mint function +await manager.setTargetFunctionRole( + target, + ['0x40c10f19'], // bytes4(keccak256('mint(address,uint256)')) + MINTER +); +``` + +Even though each role has its own list of function permissions, each role member (`address`) has an execution delay that will dictate how long the account should wait to execute a function that requires its role. Delayed operations must have the xref:api:access.adoc#AccessManager-schedule-address-bytes-uint48-[`schedule`] function called on them first in the AccessManager before they can be executed, either by calling to the target function or using the AccessManager's xref:api:access.adoc#AccessManager-execute-address-bytes-[`execute`] function. + +Additionally, roles can have a granting delay that prevents adding members immediately. The AccessManager admins can set this grant delay as follows: + +```javascript +const HOUR = 60 * 60; + +const GRANT_DELAY = 24 * HOUR; +const EXECUTION_DELAY = 5 * HOUR; +const ACCOUNT = "0x..."; + +await manager.connect(initialAdmin).setGrantDelay(MINTER, GRANT_DELAY); + +// The role will go into effect after the GRANT_DELAY passes +await manager.connect(initialAdmin).grantRole(MINTER, ACCOUNT, EXECUTION_DELAY); +``` + +Note that roles do not define a name. As opposed to the xref:api:access.adoc#AccessControl[`AccessControl`] case, roles are identified as numeric values instead of being hardcoded in the contract as `bytes32` values. It is still possible to allow for tooling discovery (e.g. for role exploration) using role labeling with the xref:api:access.adoc#AccessManager-labelRole-uint64-string-[`labelRole`] function. + +```javascript +await manager.labelRole(MINTER, "MINTER"); +``` + +Given the admins of the `AccessManaged` can modify all of its permissions, it's recommended to keep only a single admin address secured under a multisig or governance layer. To achieve this, it is possible for the initial admin to set up all the required permissions, targets, and functions, assign a new admin, and finally renounce its admin role. + +For improved incident response coordination, the manager includes a mode where administrators can completely close a target contract. When closed, all calls to restricted target functions in a target contract will revert. + +Closing and opening contracts don't alter any of their settings, neither permissions nor delays. Particularly, the roles required for calling specific target functions are not modified. + +This mode is useful for incident response operations that require temporarily shutting down a contract in order to evaluate emergencies and reconfigure permissions. + +```javascript +const target = await myToken.getAddress(); + +// Token's `restricted` functions closed +await manager.setTargetClosed(target, true); + +// Token's `restricted` functions open +await manager.setTargetClosed(target, false); +``` + +WARNING: Even if an `AccessManager` defines permissions for a target function, these won't be applied if the managed contract instance is not using the xref:api:access.adoc#AccessManaged-restricted--[`restricted`] modifier for that function, or if its manager is a different one. + +=== Role Admins and Guardians + +An important aspect of the AccessControl contract is that roles aren't granted nor revoked by role members. Instead, it relies on the concept of a role admin for granting and revoking. + +In the case of the `AccessManager`, the same rule applies and only the role's admins are able to call xref:api:access.adoc#AccessManager-grantRole-uint64-address-uint32-[grant] and xref:api:access.adoc#AccessManager-revokeRole-uint64-address-[revoke] functions. Note that calling these functions will be subject to the execution delay that the executing role admin has. + +Additionally, the `AccessManager` stores a _guardian_ as an extra protection for each role. This guardian has the ability to cancel operations that have been scheduled by any role member with an execution delay. Consider that a role will have its initial admin and guardian default to the `ADMIN_ROLE` (`0`). + +IMPORTANT: Be careful with the members of `ADMIN_ROLE`, since it acts as the default admin and guardian for every role. A misbehaved guardian can cancel operations at will, affecting the AccessManager's operation. + +=== Manager configuration + +The `AccessManager` provides a built-in interface for configuring permission settings that can be accessed by its `ADMIN_ROLE` members. + +This configuration interface includes the following functions: + +* Add a label to a role using the xref:api:access.adoc#AccessManager-labelRole-uint64-string-[`labelRole`] function. +* Assign the admin and guardian of a role with xref:api:access.adoc#AccessManager-setRoleAdmin-uint64-uint64-[`setRoleAdmin`] and xref:api:access.adoc#AccessManager-setRoleGuardian-uint64-uint64-[`setRoleGuardian`]. +* Set each role's grant delay via xref:api:access.adoc#AccessManager-setGrantDelay-uint64-uint32-[`setGrantDelay`]. + +As an admin, some actions will require a delay. Similar to each member's execution delay, some admin operations require waiting for execution and should follow the xref:api:access.adoc#AccessManager-schedule-address-bytes-uint48-[`schedule`] and xref:api:access.adoc#AccessManager-execute-address-bytes-[`execute`] workflow. + +More specifically, these delayed functions are those for configuring the settings of a specific target contract. The delay applied to these functions can be adjusted by the manager admins with xref:api:access.adoc#AccessManager-setTargetAdminDelay-address-uint32-[`setTargetAdminDelay`]. + +The delayed admin actions are: + +* Updating an `AccessManaged` contract xref:api:access.adoc#AccessManaged-authority--[authority] using xref:api:access.adoc#AccessManager-updateAuthority-address-address-[`updateAuthority`]. +* Closing or opening a target via xref:api:access.adoc#AccessManager-setTargetClosed-address-bool-[`setTargetClosed`]. +* Changing permissions of whether a role can call a target function with xref:api:access.adoc#AccessManager-setTargetFunctionRole-address-bytes4---uint64-[`setTargetFunctionRole`]. + +=== Using with Ownable + +Contracts already inheriting from xref:api:access.adoc#Ownable[`Ownable`] can migrate to AccessManager by transferring ownership to the manager. After that, all calls to functions with the `onlyOwner` modifier should be called through the manager's xref:api:access.adoc#AccessManager-execute-address-bytes-[`execute`] function, even if the caller doesn't require a delay. + +```javascript +await ownable.connect(owner).transferOwnership(accessManager); +``` + +=== Using with AccessControl + +For systems already using xref:api:access.adoc#AccessControl[`AccessControl`], the `DEFAULT_ADMIN_ROLE` can be granted to the `AccessManager` after revoking every other role. Subsequent calls should be made through the manager's xref:api:access.adoc#AccessManager-execute-address-bytes-[`execute`] method, similar to the Ownable case. + +```javascript +// Revoke old roles +await accessControl.connect(admin).revokeRole(MINTER_ROLE, account); + +// Grant the admin role to the access manager +await accessControl.connect(admin).grantRole(DEFAULT_ADMIN_ROLE, accessManager); + +await accessControl.connect(admin).renounceRole(DEFAULT_ADMIN_ROLE, admin); +``` diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/account-abstraction.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/account-abstraction.adoc new file mode 100644 index 0000000..82fc65e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/account-abstraction.adoc @@ -0,0 +1,100 @@ += Account Abstraction + +Unlike Externally Owned Accounts (EOAs), smart contracts may contain arbitrary verification logic based on authentication mechanisms different to Ethereum's native xref:api:utils.adoc#ECDSA[ECDSA] and have execution advantages such as batching or gas sponsorship. To leverage these properties of smart contracts, the community has widely adopted https://eips.ethereum.org/EIPS/eip-4337[ERC-4337], a standard to process user operations through an alternative mempool. + +The library provides multiple contracts for Account Abstraction following this standard as it enables more flexible and user-friendly interactions with applications. Account Abstraction use cases include wallets in novel contexts (e.g. embedded wallets), more granular configuration of accounts, and recovery mechanisms. + +== ERC-4337 Overview + +The ERC-4337 is a detailed specification of how to implement the necessary logic to handle operations without making changes to the protocol level (i.e. the rules of the blockchain itself). This specification defines the following components: + +=== UserOperation + +A `UserOperation` is a higher-layer pseudo-transaction object that represents the intent of the account. This shares some similarities with regular EVM transactions like the concept of `gasFees` or `callData` but includes fields that enable new capabilities. + +```solidity +struct PackedUserOperation { + address sender; + uint256 nonce; + bytes initCode; // concatenation of factory address and factoryData (or empty) + bytes callData; + bytes32 accountGasLimits; // concatenation of verificationGas (16 bytes) and callGas (16 bytes) + uint256 preVerificationGas; + bytes32 gasFees; // concatenation of maxPriorityFee (16 bytes) and maxFeePerGas (16 bytes) + bytes paymasterAndData; // concatenation of paymaster fields (or empty) + bytes signature; +} +``` + +This process of bundling user operations involves several costs that the bundler must cover, including base transaction fees, calldata serialization, entrypoint execution, and paymaster context costs. To compensate for these expenses, bundlers use the `preVerificationGas` and `gasFees` fields to charge users appropriately. + +NOTE: Estimating `preVerificationGas` is not standardized as it varies based on network conditions such as gas prices and the size of the operation bundle. + +TIP: Use xref:api:account.adoc#ERC4337Utils[`ERC4337Utils`] to manipulate the `UserOperation` struct and other ERC-4337 related values. + +=== Entrypoint + +Each `UserOperation` is executed through a contract known as the https://etherscan.io/address/0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108#code[`EntryPoint`]. This contract is a singleton deployed across multiple networks at the same address although other custom implementations may be used. + +The Entrypoint contracts is considered a trusted entity by the account. + +=== Bundlers + +The bundler is a piece of _offchain_ infrastructure that is in charge of processing an alternative mempool of user operations. Bundlers themselves call the Entrypoint contract's `handleOps` function with an array of UserOperations that are executed and included in a block. + +During the process, the bundler pays for the gas of executing the transaction and gets refunded during the execution phase of the Entrypoint contract. + +```solidity +/// @dev Process `userOps` and `beneficiary` receives all +/// the gas fees collected during the bundle execution. +function handleOps( + PackedUserOperation[] calldata ops, + address payable beneficiary +) external { ... } +``` + +=== Account Contract + +The Account Contract is a smart contract that implements the logic required to validate a `UserOperation` in the context of ERC-4337. Any smart contract account should conform with the `IAccount` interface to validate operations. + +```solidity +interface IAccount { + function validateUserOp(PackedUserOperation calldata, bytes32, uint256) external returns (uint256 validationData); +} +``` + +Similarly, an Account should have a way to execute these operations by either handling arbitrary calldata on its `fallback` or implementing the `IAccountExecute` interface: + +```solidity +interface IAccountExecute { + function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external; +} +``` + +NOTE: The `IAccountExecute` interface is optional. Developers might want to use xref:api:account.adoc#ERC7821[`ERC-7821`] for a minimal batched execution interface or rely on ERC-7579 or any other execution logic. + +To build your own account, see xref:accounts.adoc[accounts]. + +=== Factory Contract + +The smart contract accounts are created by a Factory contract defined by the Account developer. This factory receives arbitrary bytes as `initData` and returns an `address` where the logic of the account is deployed. + +To build your own factory, see xref:accounts.adoc#accounts_factory[account factories]. + +=== Paymaster Contract + +A Paymaster is an optional entity that can sponsor gas fees for Accounts, or allow them to pay for those fees in ERC-20 instead of native currency. This abstracts gas away of the user experience in the same way that computational costs of cloud servers are abstracted away from end-users. + +To build your own paymaster, see https://docs.openzeppelin.com/community-contracts/0.0.1/paymasters[paymasters]. + +== Further notes + +=== ERC-7562 Validation Rules + +To process a bundle of `UserOperations`, bundlers call xref:api:account.adoc#Account-validateUserOp-struct-PackedUserOperation-bytes32-uint256-[`validateUserOp`] on each operation sender to check whether the operation can be executed. However, the bundler has no guarantee that the state of the blockchain will remain the same after the validation phase. To overcome this problem, https://eips.ethereum.org/EIPS/eip-7562[ERC-7562] proposes a set of limitations to EVM code so that bundlers (or node operators) are protected from unexpected state changes. + +These rules outline the requirements for operations to be processed by the canonical mempool. + +Accounts can access its own storage during the validation phase, they might easily violate ERC-7562 storage access rules in undirect ways. For example, most accounts access their public keys from storage when validating a signature, limiting the ability of having accounts that validate operations for other accounts (e.g. via ERC-1271) + +TIP: Although any Account that breaks such rules may still be processed by a private bundler, developers should keep in mind the centralization tradeoffs of relying on private infrastructure instead of _permissionless_ execution. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/accounts.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/accounts.adoc new file mode 100644 index 0000000..c2f8996 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/accounts.adoc @@ -0,0 +1,354 @@ += Smart Accounts + +OpenZeppelin provides a simple xref:api:account.adoc#Account[`Account`] implementation including only the basic logic to handle user operations in compliance with ERC-4337. Developers who want to build their own account can leverage it to bootstrap custom implementations. + +User operations are validated using an xref:api:utils.adoc#AbstractSigner[`AbstractSigner`], which requires to implement the internal xref:api:utils.adoc#AbstractSigner-_rawSignatureValidation-bytes32-bytes-[`_rawSignatureValidation`] function, of which we offer a set of implementations to cover a wide customization range. This is the lowest-level signature validation layer and is used to wrap other validation methods like the Account's xref:api:account.adoc#Account-validateUserOp-struct-PackedUserOperation-bytes32-uint256-[`validateUserOp`]. + +== Setting up an account + +To setup an account, you can either start configuring it using our Wizard and selecting a predefined validation scheme, or bring your own logic and start by inheriting xref:api:account.adoc#Account[`Account`] from scratch. + +++++ + + + +++++ + +NOTE: Accounts don't support xref:erc721.adoc[ERC-721] and xref:erc1155.adoc[ERC-1155] tokens natively since these require the receiving address to implement an acceptance check. It is recommended to inherit xref:api:token/ERC721.adoc#ERC721Holder[ERC721Holder], xref:api:token/ERC1155.adoc#ERC1155Holder[ERC1155Holder] to include these checks in your account. + +=== Selecting a signer + +Since the minimum requirement of xref:api:account.adoc#Account[`Account`] is to provide an implementation of xref:api:utils/cryptography.adoc#AbstractSigner-_rawSignatureValidation-bytes32-bytes-[`_rawSignatureValidation`], the library includes specializations of the `AbstractSigner` contract that use custom digital signature verification algorithms. Some examples that you can select from include: + +* xref:api:utils/cryptography.adoc#SignerECDSA[`SignerECDSA`]: Verifies signatures produced by regular EVM Externally Owned Accounts (EOAs). +* xref:api:utils/cryptography.adoc#SignerP256[`SignerP256`]: Validates signatures using the secp256r1 curve, common for World Wide Web Consortium (W3C) standards such as FIDO keys, passkeys or secure enclaves. +* xref:api:utils/cryptography.adoc#SignerRSA[`SignerRSA`]: Verifies signatures of traditional PKI systems and X.509 certificates. +* xref:api:utils/cryptography.adoc#SignerERC7702[`SignerERC7702`]: Checks EOA signatures delegated to this signer using https://eips.ethereum.org/EIPS/eip-7702#set-code-transaction[EIP-7702 authorizations] +* xref:api:utils/cryptography.adoc#SignerERC7913[`SignerERC7913`]: Verifies generalized signatures following https://eips.ethereum.org/EIPS/eip-7913[ERC-7913]. +* https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#SignerZKEmail[`SignerZKEmail`]: Enables email-based authentication for smart contracts using zero knowledge proofs of email authority signatures. +* xref:api:utils/cryptography.adoc#MultiSignerERC7913[`MultiSignerERC7913`]: Allows using multiple ERC-7913 signers with a threshold-based signature verification system. +* xref:api:utils/cryptography.adoc#MultiSignerERC7913Weighted[`MultiSignerERC7913Weighted`]: Overrides the threshold mechanism of xref:api:utils/cryptography.adoc#MultiSignerERC7913[`MultiSignerERC7913`], offering different weights per signer. + +TIP: Given xref:api:utils/cryptography.adoc#SignerERC7913[`SignerERC7913`] provides a generalized standard for signature validation, you don't need to implement your own xref:api:utils/cryptography.adoc#AbstractSigner[`AbstractSigner`] for different signature schemes, consider bringing your own ERC-7913 verifier instead. + +==== Accounts factory + +The first time you send an user operation, your account will be created deterministically (i.e. its code and address can be predicted) using the the `initCode` field in the UserOperation. This field contains both the address of a smart contract (the factory) and the data required to call it and create your smart account. + +Suggestively, you can create your own account factory using the xref:api:proxy.adoc#Clones[Clones library], taking advantage of decreased deployment costs and account address predictability. + +[source,solidity] +---- +include::api:example$account/MyFactoryAccount.sol[] +---- + +Account factories should be carefully implemented to ensure the account address is deterministically tied to the initial owners. This prevents frontrunning attacks where a malicious actor could deploy the account with their own owners before the intended owner does. The factory should include the owner's address in the salt used for address calculation. + +==== Handling initialization + +Most smart accounts are deployed by a factory, the best practice is to create xref:api:proxy.adoc#minimal_clones[minimal clones] of initializable contracts. These signer implementations provide an initializable design by default so that the factory can interact with the account to set it up right after deployment in a single transaction. + +[source,solidity] +---- +import {Account} from "@openzeppelin/community-contracts/account/Account.sol"; +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import {SignerECDSA} from "@openzeppelin/community-contracts/utils/cryptography/SignerECDSA.sol"; + +contract MyAccount is Initializable, Account, SignerECDSA, ... { + // ... + + function initializeECDSA(address signer) public initializer { + _setSigner(signer); + } +} +---- + +Note that some account implementations may be deployed directly and therefore, won't require a factory. + +WARNING: Leaving an account uninitialized may leave it unusable since no public key was associated with it. + +=== Signature validation + +Regularly, accounts implement https://eips.ethereum.org/EIPS/eip-1271[ERC-1271] to enable smart contract signature verification given its wide adoption. To be compliant means that smart contract exposes an xref:api:interfaces.adoc#IERC1271-isValidSignature-bytes32-bytes-[`isValidSignature(bytes32 hash, bytes memory signature)`] method that returns `0x1626ba7e` to identify whether the signature is valid. + +The benefit of this standard is that it allows to receive any format of `signature` for a given `hash`. This generalized mechanism fits very well with the account abstraction principle of _bringing your own validation mechanism_. + +This is how you enable ERC-1271 using an xref:api:utils/cryptography.adoc#AbstractSigner[`AbstractSigner`]: + +[source,solidity] +---- +function isValidSignature(bytes32 hash, bytes calldata signature) public view override returns (bytes4) { + return _rawSignatureValidation(hash, signature) ? IERC1271.isValidSignature.selector : bytes4(0xffffffff); +} +---- + +IMPORTANT: We recommend using xref:api:utils/cryptography.adoc#ERC7739[ERC7739] to avoid replayability across accounts. This defensive rehashing mechanism that prevents signatures for this account to be replayed in another account controlled by the same signer. See xref:accounts.adoc#erc_7739_signatures[ERC-7739 signatures]. + +=== Batched execution + +Batched execution allows accounts to execute multiple calls in a single transaction, which is particularly useful for bundling operations that need to be atomic. This is especially valuable in the context of account abstraction where you want to minimize the number of user operations and associated gas costs. xref:api:account.adoc#ERC7821[`ERC-7821`] standard provides a minimal interface for batched execution. + +The library implementation supports a single batch mode (`0x01000000000000000000`) and allows accounts to execute multiple calls atomically. The standard includes access control through the xref:api:account.adoc#ERC7821-_erc7821AuthorizedExecutor-address-bytes32-bytes-[`_erc7821AuthorizedExecutor`] function, which by default only allows the contract itself to execute batches. + +Here's an example of how to use batched execution using EIP-7702: + +[source,solidity] +---- +import {Account} from "@openzeppelin/community-contracts/account/Account.sol"; +import {ERC7821} from "@openzeppelin/community-contracts/account/extensions/draft-ERC7821.sol"; +import {SignerERC7702} from "@openzeppelin/community-contracts/utils/cryptography/SignerERC7702.sol"; + +contract MyAccount is Account, SignerERC7702, ERC7821 { + // Override to allow the entrypoint to execute batches + function _erc7821AuthorizedExecutor( + address caller, + bytes32 mode, + bytes calldata executionData + ) internal view virtual override returns (bool) { + return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); + } +} +---- + +The batched execution data follows a specific format that includes the calls to be executed. This format follows the same format as https://eips.ethereum.org/EIPS/eip-7579#execution-behavior[ERC-7579 execution] but only supports `0x01` call type (i.e. batched `call`) and default execution type (i.e. reverts if at least one subcall does). + +To encode an ERC-7821 batch, you can use https://viem.sh/[viem]'s utilities: + +[source,typescript] +---- +// CALL_TYPE_BATCH, EXEC_TYPE_DEFAULT, ..., selector, payload +const mode = encodePacked( + ["bytes1", "bytes1", "bytes4", "bytes4", "bytes22"], + ["0x01", "0x00", "0x00000000", "0x00000000", "0x00000000000000000000000000000000000000000000"] +); + +const entries = [ + { + target: "0x000...0001", + value: 0n, + data: "0x000...000", + }, + { + target: "0x000...0002", + value: 0n, + data: "0x000...000", + } +]; + +const batch = encodeAbiParameters( + [parseAbiParameter("(address,uint256,bytes)[]")], + [ + entries.map<[Address, bigint, Hex]>((entry) => + [entry.target, entry.value ?? 0n, entry.data ?? "0x"] + ), + ] +); + +const userOpData = encodeFunctionData({ + abi: account.abi, + functionName: "execute", + args: [mode, batch] +}); +---- + +== Bundle a `UserOperation` + +xref:account-abstraction.adoc#useroperation[UserOperations] are a powerful abstraction layer that enable more sophisticated transaction capabilities compared to traditional Ethereum transactions. To get started, you'll need to an account, which you can get by xref:accounts.adoc#accounts_factory[deploying a factory] for your implementation. + +=== Preparing a UserOp + +A UserOperation is a struct that contains all the necessary information for the EntryPoint to execute your transaction. You'll need the `sender`, `nonce`, `accountGasLimits` and `callData` fields to construct a `PackedUserOperation` that can be signed later (to populate the `signature` field). + +TIP: Specify `paymasterAndData` with the address of a paymaster contract concatenated to `data` that will be passed to the paymaster's validatePaymasterUserOp function to support sponsorship as part of your user operation. + +Here's how to prepare one using https://viem.sh/[viem]: + +[source,typescript] +---- +import { getContract, createWalletClient, http, Hex } from 'viem'; + +const walletClient = createWalletClient({ + account, // See Viem's `privateKeyToAccount` + chain, // import { ... } from 'viem/chains'; + transport: http(), +}) + +const entrypoint = getContract({ + abi: [/* ENTRYPOINT ABI */], + address: '0x', + client: walletClient, +}); + +const userOp = { + sender: '0x', + nonce: await entrypoint.read.getNonce([sender, 0n]), + initCode: "0x" as Hex, + callData: '0x', + accountGasLimits: encodePacked( + ["uint128", "uint128"], + [ + 100_000n, // verificationGasLimit + 300_000n, // callGasLimit + ] + ), + preVerificationGas: 50_000n, + gasFees: encodePacked( + ["uint128", "uint128"], + [ + 0n, // maxPriorityFeePerGas + 0n, // maxFeePerGas + ] + ), + paymasterAndData: "0x" as Hex, + signature: "0x" as Hex, +}; +---- + +In case your account hasn't been deployed yet, make sure to provide the `initCode` field as `abi.encodePacked(factory, factoryData)` to deploy the account within the same UserOp: + +[source,typescript] +---- +const deployed = await publicClient.getCode({ address: predictedAddress }); + +if (!deployed) { + userOp.initCode = encodePacked( + ["address", "bytes"], + [ + '0x', + encodeFunctionData({ + abi: [/* ACCOUNT ABI */], + functionName: "", + args: [...], + }), + ] + ); +} +---- + +==== Estimating gas + +To calculate gas parameters of a `UserOperation`, developers should carefully consider the following fields: + +* `verificationGasLimit`: This covers the gas costs for signature verification, paymaster validation (if used), and account validation logic. While a typical value is around 100,000 gas units, this can vary significantly based on the complexity of your signature validation scheme in both the account and paymaster contracts. + +* `callGasLimit`: This parameter accounts for the actual execution of your account's logic. It's recommended to use `eth_estimateGas` for each subcall and add additional buffer for computational overhead. + +* `preVerificationGas`: This compensates for the EntryPoint's execution overhead. While 50,000 gas is a reasonable starting point, you may need to increase this value based on your UserOperation's size and specific bundler requirements. + +NOTE: The `maxFeePerGas` and `maxPriorityFeePerGas` values are typically provided by your bundler service, either through their SDK or a custom RPC method. + +IMPORTANT: A penalty of 10% (`UNUSED_GAS_PENALTY_PERCENT`) is applied on the amounts of `callGasLimit` and `paymasterPostOpGasLimit` gas that remains unused if the amount of remaining unused gas is greater than or equal to 40,000 (`PENALTY_GAS_THRESHOLD`). + +=== Signing the UserOp + +To sign a UserOperation, you'll need to first calculate its hash as an EIP-712 typed data structure using the EntryPoint's domain, then sign this hash using your account's signature scheme, and finally encode the resulting signature in the format that your account contract expects for verification. + +[source,typescript] +---- +import { signTypedData } from 'viem/actions'; + +// EntryPoint v0.8 EIP-712 domain +const domain = { + name: 'ERC4337', + version: '1', + chainId: 1, // Your target chain ID + verifyingContract: '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108', // v08 +}; + +// EIP-712 types for PackedUserOperation +const types = { + PackedUserOperation: [ + { name: 'sender', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + { name: 'initCode', type: 'bytes' }, + { name: 'callData', type: 'bytes' }, + { name: 'accountGasLimits', type: 'bytes32' }, + { name: 'preVerificationGas', type: 'uint256' }, + { name: 'gasFees', type: 'bytes32' }, + { name: 'paymasterAndData', type: 'bytes' }, + ], +} as const; + +// Sign the UserOperation using EIP-712 +userOp.signature = await eoa.signTypedData({ + domain, + types, + primaryType: 'PackedUserOperation', + message: { + sender: userOp.sender, + nonce: userOp.nonce, + initCode: userOp.initCode, + callData: userOp.callData, + accountGasLimits: userOp.accountGasLimits, + preVerificationGas: userOp.preVerificationGas, + gasFees: userOp.gasFees, + paymasterAndData: userOp.paymasterAndData, + }, +}); +---- + +Alternatively, developers can get the raw user operation hash by using the Entrypoint's `getUserOpHash` function: + +[source,typescript] +---- +const userOpHash = await entrypoint.read.getUserOpHash([userOp]); +userOp.signature = await eoa.sign({ hash: userOpHash }); +---- + +IMPORTANT: Using `getUserOpHash` directly may provide a poorer user experience as users see an opaque hash rather than structured transaction data. In many cases, offchain signers won't have an option to sign a raw hash. + +=== Sending the UserOp + +Finally, to send the user operation you can call `handleOps` on the Entrypoint contract and set yourself as the `beneficiary`. + +[source,typescript] +---- +// Send the UserOperation +const userOpReceipt = await walletClient + .writeContract({ + abi: [/* ENTRYPOINT ABI */], + address: '0x', + functionName: "handleOps", + args: [[userOp], eoa.address], + }) + .then((txHash) => + publicClient.waitForTransactionReceipt({ + hash: txHash, + }) + ); + +// Print receipt +console.log(userOpReceipt); +---- + +TIP: Since you're bundling your user operations yourself, you can safely specify `preVerificationGas` and `maxFeePerGas` in 0. + +=== Using a Bundler + +For better reliability, consider using a bundler service. Bundlers provide several key benefits: they automatically handle gas estimation, manage transaction ordering, support bundling multiple operations together, and generally offer higher transaction success rates compared to self-bundling. + +== Further notes + +=== ERC-7739 Signatures + +A common security practice to prevent user operation https://mirror.xyz/curiousapple.eth/pFqAdW2LiJ-6S4sg_u1z08k4vK6BCJ33LcyXpnNb8yU[replayability across smart contract accounts controlled by the same private key] (i.e. multiple accounts for the same signer) is to link the signature to the `address` and `chainId` of the account. This can be done by asking the user to sign a hash that includes these values. + +The problem with this approach is that the user might be prompted by the wallet provider to sign an https://x.com/howydev/status/1780353754333634738[obfuscated message], which is a phishing vector that may lead to a user losing its assets. + +To prevent this, developers may use xref:api:account#ERC7739Signer[`ERC7739Signer`], a utility that implements xref:api:interfaces#IERC1271[`IERC1271`] for smart contract signatures with a defensive rehashing mechanism based on a https://github.com/frangio/eip712-wrapper-for-eip1271[nested EIP-712 approach] to wrap the signature request in a context where there's clearer information for the end user. + +=== EIP-7702 Delegation + +https://eips.ethereum.org/EIPS/eip-7702[EIP-7702] lets EOAs delegate to smart contracts while keeping their original signing key. This creates a hybrid account that works like an EOA for signing but has smart contract features. Protocols don't need major changes to support EIP-7702 since they already handle both EOAs and smart contracts (see xref:api:utils/cryptography.adoc#SignatureChecker[SignatureChecker]). + +The signature verification stays compatible: delegated EOAs are treated as contracts using ERC-1271, making it easy to redelegate to a contract with ERC-1271 support with little overhead by reusing the validation mechanism of the account. + +TIP: Learn more about delegating to an ERC-7702 account in our xref:eoa-delegation.adoc[EOA Delegation] section. + +=== ERC-7579 Modules + +Smart accounts have evolved to embrace modularity as a design principle, with popular implementations like https://erc7579.com/#supporters[Safe, Pimlico, Rhinestone, Etherspot and many others] agreeing on ERC-7579 as the standard for module interoperability. This standardization enables accounts to extend their functionality through external contracts while maintaining compatibility across different implementations. + +OpenZeppelin Contracts provides both the building blocks for creating ERC-7579-compliant modules and an xref:api:account.adoc#AccountERC7579[`AccountERC7579`] implementation that supports installing and managing these modules. + +TIP: Learn more in our https://docs.openzeppelin.com/community-contracts/0.0.1/account-modules[account modules] section. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/backwards-compatibility.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/backwards-compatibility.adoc new file mode 100644 index 0000000..5d0e29b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/backwards-compatibility.adoc @@ -0,0 +1,50 @@ += Backwards Compatibility +:page-aliases: releases-stability.adoc + +OpenZeppelin Contracts uses semantic versioning to communicate backwards compatibility of its API and storage layout. Patch and minor updates will generally be backwards compatible, with rare exceptions as detailed below. Major updates should be assumed incompatible with previous releases. On this page, we provide details about these guarantees. + +== API + +In backwards compatible releases, all changes should be either additions or modifications to internal implementation details. Most code should continue to compile and behave as expected. The exceptions to this rule are listed below. + +=== Security + +Infrequently a patch or minor update will remove or change an API in a breaking way, but only if the previous API is considered insecure. These breaking changes will be noted in the changelog and release notes, and published along with a security advisory. + +=== Draft or Pre-Final ERCs + +ERCs that are not Final can change in incompatible ways. For this reason, we avoid shipping implementations of ERCs before they are Final. Some exceptions are made for ERCs that have been published for a long time and seem unlikely to change. Implementations for ERCs that may have breaking changes are published in files named `draft-*.sol` to make that condition explicit. There is no backwards compatibility guarantee for content in files prefixed with `draft`. + +Standards that have achieved widespread adoption with strong backwards compatibility expectations from the community may be treated as de-facto finalized and published without the `draft-` prefix, as extensive ecosystem reliance makes breaking changes highly unlikely. + +=== Virtual & Overrides + +Almost all functions in this library are virtual with some exceptions, but this does not mean that overrides are encouraged. There is a subset of functions that are designed to be overridden. By defining overrides outside of this subset you are potentially relying on internal implementation details. We make efforts to preserve backwards compatibility even in these cases but it is extremely difficult and easy to accidentally break. Caution is advised. + +Additionally, some minor updates may result in new compilation errors of the kind "two or more base classes define function with same name and parameter types" or "need to specify overridden contract", due to what Solidity considers ambiguity in inherited functions. This should be resolved by adding an override that invokes the function via `super`. + +See xref:extending-contracts.adoc[Extending Contracts] for more about virtual and overrides. + +=== Structs + +Struct members with an underscore prefix should be considered "private" and may break in minor versions. Struct data should only be accessed and modified through library functions. + +=== Errors + +The specific error format and data that is included with reverts should not be assumed stable unless otherwise specified. + +=== Major Releases + +Major releases should be assumed incompatible. Nevertheless, the external interfaces of contracts will remain compatible if they are standardized, or if the maintainers judge that changing them would cause significant strain on the ecosystem. + +An important aspect that major releases may break is "upgrade compatibility", in particular storage layout compatibility. It will never be safe for a live contract to upgrade from one major release to another. + +== Storage Layout + +Minor and patch updates always preserve storage layout compatibility. This means that a live contract can be upgraded from one minor to another without corrupting the storage layout. In some cases it may be necessary to initialize new state variables when upgrading, although we expect this to be infrequent. + +We recommend using xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins or CLI] to ensure storage layout safety of upgrades. + +== Solidity Version + +The minimum Solidity version required to compile the contracts will remain unchanged in minor and patch updates. New contracts introduced in minor releases may make use of newer Solidity features and require a more recent version of the compiler. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/eoa-delegation.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/eoa-delegation.adoc new file mode 100644 index 0000000..935852f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/eoa-delegation.adoc @@ -0,0 +1,143 @@ += EOA Delegation + +https://eips.ethereum.org/EIPS/eip-7702[EIP-7702] introduces a new transaction type (`0x4`) that grants https://ethereum.org/en/developers/docs/accounts/[Externally Owned Accounts (EOAs)] the ability to delegate execution to an smart contract. This is particularly useful to enable traditional EVM accounts to: + +* Batch multiple operations in a single transaction (e.g. xref:api:token/ERC20.adoc#IERC20-approve-address-uint256-[`approve`] + xref:api:token/ERC20.adoc#IERC20-transfer-address-uint256-[`transfer`], yey!) +* Sponsoring transactions for other users. +* Implementing privilege de-escalation (e.g., sub-keys with limited permissions) + +This section walks you through the process of delegating an EOA to a contract following https://eips.ethereum.org/EIPS/eip-7702[ERC-7702]. This allows you to use your EOA's private key to sign and execute operations with custom execution logic. Combined with https://eips.ethereum.org/EIPS/eip-4337[ERC-4337] infrastructure, users can achieve gas sponsoring through https://docs.openzeppelin.com/community-contracts/paymasters[paymasters]. + +== Delegating execution + +EIP-7702 enables EOAs to delegate their execution capabilities to smart contracts, effectively bridging the gap between traditional and xref:accounts.adoc[Smart Accounts]. The xref:api:utils/cryptography.adoc#[`SignerERC7702`] utility facilitates this delegation by verifying signatures against the EOA's address (`address(this)`), making it easier to implement EIP-7702 in smart contract accounts. + +[source,solidity] +---- +include::api:example$account/MyAccountERC7702.sol[] +---- + +TIP: Users can delegate to an instance of xref:api:account.adoc#ERC7821[`ERC-7821`] for a minimal batch executor that does not use ERC-4337 related code. + +=== Signing Authorization + +To authorize delegation, the EOA owner signs a message containing the chain ID, nonce, delegation address, and signature components (i.e. `[chain_id, address, nonce, y_parity, r, s]`). This signed authorization serves two purposes: it restricts execution to only the delegate contract and prevents replay attacks. + +The EOA maintains a delegation designator for each authorized address on each chain, which points to the contract whose code will be executed in the EOA's context to handle delegated operations. + +Here's how to construct an authorization with https://viem.sh/[viem]: + +[source, typescript] +---- +// Remember not to hardcode your private key! +const eoa = privateKeyToAccount(''); +const eoaClient = createWalletClient({ + account: eoa, + chain: publicClient.chain, + transport: http(), +}); + +const walletClient = createWalletClient({ + account, // See Viem's `privateKeyToAccount` + chain, // import { ... } from 'viem/chains'; + transport: http(), +}) + +const authorization = await eoaClient.signAuthorization({ + account: walletClient.account.address, + contractAddress: '0x', + // Use instead of `account` if your + // walletClient's account is the one sending the transaction + // executor: "self", +}); +---- + +NOTE: When implementing delegate contracts, ensure they require signatures that avoid replayability (e.g. a domain separator, nonce). +A poorly implemented delegate can allow a malicious actor to take near complete control over a signer's EOA. + +=== Send a Set Code Transaction + +After signing the authorization, you need to send a `SET_CODE_TX_TYPE` (0x04) transaction to write the delegation designator (i.e. `0xef0100 || address`) to your EOA's code, which tells the EVM to load and execute code from the specified address when operations are performed on your EOA. + +[source, typescript] +---- +// Send the `authorization` along with `data` +const receipt = await walletClient + .sendTransaction({ + authorizationList: [authorization], + data: '0x', + to: eoa.address, + }) + .then((txHash) => + publicClient.waitForTransactionReceipt({ + hash: txHash, + }) + ); + +// Print receipt +console.log(userOpReceipt); +---- + +To remove the delegation and restore your EOA to its original state, you can send a `SET_CODE_TX_TYPE` transaction with an authorization tuple that points to the zero address (`0x0000000000000000000000000000000000000000`). This will clear the account's code and reset its code hash to the empty hash, however, be aware that it will not automatically clean the EOA storage. + +When changing an account's delegation, ensure the newly delegated code is purposely designed and tested as an upgrade to the old one. To ensure safe migration between delegate contracts, namespaced storage that avoid accidental collisions following ERC-7201. + +WARNING: Updating the delegation designator may render your EOA unusable due to potential storage collisions. We recommend following similar practices to those of https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable[writing upgradeable smart contracts]. + +== Using with ERC-4337 + +The ability to set code to execute logic on an EOA allows users to leverage ERC-4337 infrastructure to process user operations. Developers only need to combine an xref:api:account.adoc#Account[`Account`] contract with an xref:api:utils/cryptography.adoc#SignerERC7702[`SignerERC7702`] to accomplish ERC-4337 compliance out of the box. + +=== Sending a UserOp + +Once your EOA is delegated to an ERC-4337 compatible account, you can send user operations through the entry point contract. The user operation includes all the necessary fields for execution, including gas limits, fees, and the actual call data to execute. The entry point will validate the operation and execute it in the context of your delegated account. + +Similar to how xref:accounts.adoc#bundle_a_useroperation[sending a UserOp] is achieved for factory accounts, here's how you can construct a UserOp for an EOA who's delegated to an xref:api:account.adoc#Account[`Account`] contract. + +[source, typescript] +---- +const userOp = { + sender: eoa.address, + nonce: await entrypoint.read.getNonce([eoa.address, 0n]), + initCode: "0x" as Hex, + callData: '0x', + accountGasLimits: encodePacked( + ["uint128", "uint128"], + [ + 100_000n, // verificationGas + 300_000n, // callGas + ] + ), + preVerificationGas: 50_000n, + gasFees: encodePacked( + ["uint128", "uint128"], + [ + 0n, // maxPriorityFeePerGas + 0n, // maxFeePerGas + ] + ), + paymasterAndData: "0x" as Hex, + signature: "0x" as Hex, +}; + +const userOpHash = await entrypoint.read.getUserOpHash([userOp]); +userOp.signature = await eoa.sign({ hash: userOpHash }); + +const userOpReceipt = await eoaClient + .writeContract({ + abi: EntrypointV08Abi, + address: entrypoint.address, + authorizationList: [authorization], + functionName: "handleOps", + args: [[userOp], eoa.address], + }) + .then((txHash) => + publicClient.waitForTransactionReceipt({ + hash: txHash, + }) + ); + +console.log(userOpReceipt); +---- + +NOTE: When using sponsored transaction relayers, be aware that the authorized account can cause relayers to spend gas without being reimbursed by either invalidating the authorization (increasing the account's nonce) or by sweeping the relevant assets out of the account. Relayers may implement safeguards like requiring a bond or using a reputation system. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc1155.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc1155.adoc new file mode 100644 index 0000000..2c31db8 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc1155.adoc @@ -0,0 +1,118 @@ += ERC-1155 + +ERC-1155 is a novel token standard that aims to take the best from previous standards to create a xref:tokens.adoc#different-kinds-of-tokens[*fungibility-agnostic*] and *gas-efficient* xref:tokens.adoc#but_first_coffee_a_primer_on_token_contracts[token contract]. + +TIP: ERC-1155 draws ideas from all of xref:erc20.adoc[ERC-20], xref:erc721.adoc[ERC-721], and https://eips.ethereum.org/EIPS/eip-777[ERC-777]. If you're unfamiliar with those standards, head to their guides before moving on. + +[[multi-token-standard]] +== Multi Token Standard + +The distinctive feature of ERC-1155 is that it uses a single smart contract to represent multiple tokens at once. This is why its xref:api:token/ERC1155.adoc#IERC1155-balanceOf-address-uint256-[`balanceOf`] function differs from ERC-20's and ERC-777's: it has an additional `id` argument for the identifier of the token that you want to query the balance of. + +This is similar to how ERC-721 does things, but in that standard a token `id` has no concept of balance: each token is non-fungible and exists or doesn't. The ERC-721 xref:api:token/ERC721.adoc#IERC721-balanceOf-address-[`balanceOf`] function refers to _how many different tokens_ an account has, not how many of each. On the other hand, in ERC-1155 accounts have a distinct balance for each token `id`, and non-fungible tokens are implemented by simply minting a single one of them. + +This approach leads to massive gas savings for projects that require multiple tokens. Instead of deploying a new contract for each token type, a single ERC-1155 token contract can hold the entire system state, reducing deployment costs and complexity. + +[[batch-operations]] +== Batch Operations + +Because all state is held in a single contract, it is possible to operate over multiple tokens in a single transaction very efficiently. The standard provides two functions, xref:api:token/ERC1155.adoc#IERC1155-balanceOfBatch-address---uint256---[`balanceOfBatch`] and xref:api:token/ERC1155.adoc#IERC1155-safeBatchTransferFrom-address-address-uint256---uint256---bytes-[`safeBatchTransferFrom`], that make querying multiple balances and transferring multiple tokens simpler and less gas-intensive. + +In the spirit of the standard, we've also included batch operations in the non-standard functions, such as xref:api:token/ERC1155.adoc#ERC1155-_mintBatch-address-uint256---uint256---bytes-[`_mintBatch`]. + +== Constructing an ERC-1155 Token Contract + +We'll use ERC-1155 to track multiple items in our game, which will each have their own unique attributes. We mint all items to the deployer of the contract, which we can later transfer to players. Players are free to keep their tokens or trade them with other people as they see fit, as they would any other asset on the blockchain! + +For simplicity, we will mint all items in the constructor, but you could add minting functionality to the contract to mint on demand to players. + +TIP: For an overview of minting mechanisms, check out xref:erc20-supply.adoc[Creating ERC-20 Supply]. + +Here's what a contract for tokenized items might look like: + +[source,solidity] +---- +include::api:example$token/ERC1155/GameItems.sol[] +---- + +Note that for our Game Items, Gold is a fungible token whilst Thor's Hammer is a non-fungible token as we minted only one. + +The xref:api:token/ERC1155.adoc#ERC1155[`ERC1155`] contract includes the optional extension xref:api:token/ERC1155.adoc#IERC1155MetadataURI[`IERC1155MetadataURI`]. That's where the xref:api:token/ERC1155.adoc#IERC1155MetadataURI-uri-uint256-[`uri`] function comes from: we use it to retrieve the metadata uri. + +Also note that, unlike ERC-20, ERC-1155 lacks a `decimals` field, since each token is distinct and cannot be partitioned. + +Once deployed, we will be able to query the deployer’s balance: +[source,javascript] +---- +> gameItems.balanceOf(deployerAddress,3) +1000000000 +---- + +We can transfer items to player accounts: +[source,javascript] +---- +> gameItems.safeTransferFrom(deployerAddress, playerAddress, 2, 1, "0x0") +> gameItems.balanceOf(playerAddress, 2) +1 +> gameItems.balanceOf(deployerAddress, 2) +0 +---- + +We can also batch transfer items to player accounts and get the balance of batches: +[source,javascript] +---- +> gameItems.safeBatchTransferFrom(deployerAddress, playerAddress, [0,1,3,4], [50,100,1,1], "0x0") +> gameItems.balanceOfBatch([playerAddress,playerAddress,playerAddress,playerAddress,playerAddress], [0,1,2,3,4]) +[50,100,1,1,1] +---- + +The metadata uri can be obtained: + +[source,javascript] +---- +> gameItems.uri(2) +"https://game.example/api/item/{id}.json" +---- + +The `uri` can include the string `++{id}++` which clients must replace with the actual token ID, in lowercase hexadecimal (with no 0x prefix) and leading zero padded to 64 hex characters. + +For token ID `2` and uri `++https://game.example/api/item/{id}.json++` clients would replace `++{id}++` with `0000000000000000000000000000000000000000000000000000000000000002` to retrieve JSON at `https://game.example/api/item/0000000000000000000000000000000000000000000000000000000000000002.json`. + +The JSON document for token ID 2 might look something like: + +[source,json] +---- +{ + "name": "Thor's hammer", + "description": "Mjölnir, the legendary hammer of the Norse god of thunder.", + "image": "https://game.example/item-id-8u5h2m.png", + "strength": 20 +} +---- + +For more information about the metadata JSON Schema, check out the https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md#erc-1155-metadata-uri-json-schema[ERC-1155 Metadata URI JSON Schema]. + +NOTE: You'll notice that the item's information is included in the metadata, but that information isn't on-chain! So a game developer could change the underlying metadata, changing the rules of the game! + +TIP: If you'd like to put all item information on-chain, you can extend ERC-721 to do so (though it will be rather costly) by providing a xref:utilities.adoc#base64[`Base64`] Data URI with the JSON schema encoded. You could also leverage IPFS to store the URI information, but these techniques are out of the scope of this overview guide + +[[sending-to-contracts]] +== Sending Tokens to Contracts + +A key difference when using xref:api:token/ERC1155.adoc#IERC1155-safeTransferFrom-address-address-uint256-uint256-bytes-[`safeTransferFrom`] is that token transfers to other contracts may revert with the following custom error: + +[source,text] +---- +ERC1155InvalidReceiver("

    ") +---- + +This is a good thing! It means that the recipient contract has not registered itself as aware of the ERC-1155 protocol, so transfers to it are disabled to *prevent tokens from being locked forever*. As an example, https://etherscan.io/token/0xa74476443119A942dE498590Fe1f2454d7D4aC0d?a=0xa74476443119A942dE498590Fe1f2454d7D4aC0d[the Golem contract currently holds over 350k `GNT` tokens], and lacks methods to get them out of there. This has happened to virtually every ERC20-backed project, usually due to user error. + +In order for our contract to receive ERC-1155 tokens we can inherit from the convenience contract xref:api:token/ERC1155.adoc#ERC1155Holder[`ERC1155Holder`] which handles the registering for us. However, we need to remember to implement functionality to allow tokens to be transferred out of our contract: + +[source,solidity] +---- +include::api:example$token/ERC1155/MyERC115HolderContract.sol[] +---- + +We can also implement more complex scenarios using the xref:api:token/ERC1155.adoc#IERC1155Receiver-onERC1155Received-address-address-uint256-uint256-bytes-[`onERC1155Received`] and xref:api:token/ERC1155.adoc#IERC1155Receiver-onERC1155BatchReceived-address-address-uint256---uint256---bytes-[`onERC1155BatchReceived`] functions. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20-supply.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20-supply.adoc new file mode 100644 index 0000000..273cb32 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20-supply.adoc @@ -0,0 +1,71 @@ += Creating ERC-20 Supply + +In this guide, you will learn how to create an ERC-20 token with a custom supply mechanism. We will showcase two idiomatic ways to use OpenZeppelin Contracts for this purpose that you will be able to apply to your smart contract development practice. + +The standard interface implemented by tokens built on Ethereum is called ERC-20, and Contracts includes a widely used implementation of it: the aptly named xref:api:token/ERC20.adoc[`ERC20`] contract. This contract, like the standard itself, is quite simple and bare-bones. In fact, if you try to deploy an instance of `ERC20` as-is it will be quite literally useless... it will have no supply! What use is a token with no supply? + +The way that supply is created is not defined in the ERC-20 document. Every token is free to experiment with its own mechanisms, ranging from the most decentralized to the most centralized, from the most naive to the most researched, and more. + +[[fixed-supply]] +== Fixed Supply + +Let's say we want a token with a fixed supply of 1000, initially allocated to the account that deploys the contract. If you've used Contracts v1, you may have written code like the following: + +[source,solidity] +---- +contract ERC20FixedSupply is ERC20 { + constructor() { + totalSupply += 1000; + balances[msg.sender] += 1000; + } +} +---- + +Starting with Contracts v2, this pattern is not only discouraged, but disallowed. The variables `totalSupply` and `balances` are now private implementation details of `ERC20`, and you can't directly write to them. Instead, there is an internal xref:api:token/ERC20.adoc#ERC20-_mint-address-uint256-[`_mint`] function that will do exactly this: + +[source,solidity] +---- +contract ERC20FixedSupply is ERC20 { + constructor() ERC20("Fixed", "FIX") { + _mint(msg.sender, 1000); + } +} +---- + +Encapsulating state like this makes it safer to extend contracts. For instance, in the first example we had to manually keep the `totalSupply` in sync with the modified balances, which is easy to forget. In fact, we omitted something else that is also easily forgotten: the `Transfer` event that is required by the standard, and which is relied on by some clients. The second example does not have this bug, because the internal `_mint` function takes care of it. + +[[rewarding-miners]] +== Rewarding Miners + +The internal xref:api:token/ERC20.adoc#ERC20-_mint-address-uint256-[`_mint`] function is the key building block that allows us to write ERC-20 extensions that implement a supply mechanism. + +The mechanism we will implement is a token reward for the miners that produce Ethereum blocks. In Solidity, we can access the address of the current block's miner in the global variable `block.coinbase`. We will mint a token reward to this address whenever someone calls the function `mintMinerReward()` on our token. The mechanism may sound silly, but you never know what kind of dynamic this might result in, and it's worth analyzing and experimenting with! + +[source,solidity] +---- +contract ERC20WithMinerReward is ERC20 { + constructor() ERC20("Reward", "RWD") {} + + function mintMinerReward() public { + _mint(block.coinbase, 1000); + } +} +---- + +As we can see, `_mint` makes it super easy to do this correctly. + +[[automating-the-reward]] +== Automating the Reward + +So far our supply mechanism was triggered manually, but `ERC20` also allows us to extend the core functionality of the token through the xref:api:token/ERC20.adoc#ERC20-_update-address-address-uint256-[`_update`] function. + +Adding to the supply mechanism from the previous section, we can use this function to mint a miner reward for every token transfer that is included in the blockchain. + +```solidity +include::api:example$ERC20WithAutoMinerReward.sol[] +``` + +[[wrapping-up]] +== Wrapping Up + +We've seen how to implement an ERC-20 supply mechanism: internally through `_mint`. Hopefully this has helped you understand how to use OpenZeppelin Contracts and some of the design principles behind it, and you can apply them to your own smart contracts. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20.adoc new file mode 100644 index 0000000..104b4ef --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20.adoc @@ -0,0 +1,67 @@ += ERC-20 + +An ERC-20 token contract keeps track of xref:tokens.adoc#different-kinds-of-tokens[_fungible_ tokens]: any one token is exactly equal to any other token; no tokens have special rights or behavior associated with them. This makes ERC-20 tokens useful for things like a *medium of exchange currency*, *voting rights*, *staking*, and more. + +OpenZeppelin Contracts provides many ERC20-related contracts. On the xref:api:token/ERC20.adoc[`API reference`] you'll find detailed information on their properties and usage. + +[[constructing-an-erc20-token-contract]] +== Constructing an ERC-20 Token Contract + +Using Contracts, we can easily create our own ERC-20 token contract, which will be used to track _Gold_ (GLD), an internal currency in a hypothetical game. + +Here's what our GLD token might look like. + +[source,solidity] +---- +include::api:example$token/ERC20/GLDToken.sol[] +---- + +Our contracts are often used via https://solidity.readthedocs.io/en/latest/contracts.html#inheritance[inheritance], and here we're reusing xref:api:token/ERC20.adoc#erc20[`ERC20`] for both the basic standard implementation and the xref:api:token/ERC20.adoc#ERC20-name--[`name`], xref:api:token/ERC20.adoc#ERC20-symbol--[`symbol`], and xref:api:token/ERC20.adoc#ERC20-decimals--[`decimals`] optional extensions. Additionally, we're creating an `initialSupply` of tokens, which will be assigned to the address that deploys the contract. + +TIP: For a more complete discussion of ERC-20 supply mechanisms, see xref:erc20-supply.adoc[Creating ERC-20 Supply]. + +That's it! Once deployed, we will be able to query the deployer's balance: + +[source,javascript] +---- +> GLDToken.balanceOf(deployerAddress) +1000000000000000000000 +---- + +We can also xref:api:token/ERC20.adoc#IERC20-transfer-address-uint256-[transfer] these tokens to other accounts: + +[source,javascript] +---- +> GLDToken.transfer(otherAddress, 300000000000000000000) +> GLDToken.balanceOf(otherAddress) +300000000000000000000 +> GLDToken.balanceOf(deployerAddress) +700000000000000000000 +---- + +[[a-note-on-decimals]] +== A Note on `decimals` + +Often, you'll want to be able to divide your tokens into arbitrary amounts: say, if you own `5 GLD`, you may want to send `1.5 GLD` to a friend, and keep `3.5 GLD` to yourself. Unfortunately, Solidity and the EVM do not support this behavior: only integer (whole) numbers can be used, which poses an issue. You may send `1` or `2` tokens, but not `1.5`. + +To work around this, xref:api:token/ERC20.adoc#ERC20[`ERC20`] provides a xref:api:token/ERC20.adoc#ERC20-decimals--[`decimals`] field, which is used to specify how many decimal places a token has. To be able to transfer `1.5 GLD`, `decimals` must be at least `1`, since that number has a single decimal place. + +How can this be achieved? It's actually very simple: a token contract can use larger integer values, so that a balance of `50` will represent `5 GLD`, a transfer of `15` will correspond to `1.5 GLD` being sent, and so on. + +It is important to understand that `decimals` is _only used for display purposes_. All arithmetic inside the contract is still performed on integers, and it is the different user interfaces (wallets, exchanges, etc.) that must adjust the displayed values according to `decimals`. The total token supply and balance of each account are not specified in `GLD`: you need to divide by `10 ** decimals` to get the actual `GLD` amount. + +You'll probably want to use a `decimals` value of `18`, just like Ether and most ERC-20 token contracts in use, unless you have a very special reason not to. When minting tokens or transferring them around, you will be actually sending the number `num GLD * (10 ** decimals)`. + +NOTE: By default, `ERC20` uses a value of `18` for `decimals`. To use a different value, you will need to override the `decimals()` function in your contract. + +```solidity +function decimals() public view virtual override returns (uint8) { + return 16; +} +``` + +So if you want to send `5` tokens using a token contract with 18 decimals, the method to call will actually be: + +```solidity +transfer(recipient, 5 * (10 ** 18)); +``` diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc4626.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc4626.adoc new file mode 100644 index 0000000..c219595 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc4626.adoc @@ -0,0 +1,214 @@ += ERC-4626 +:stem: latexmath + +https://eips.ethereum.org/EIPS/eip-4626[ERC-4626] is an extension of xref:erc20.adoc[ERC-20] that proposes a standard interface for token vaults. This standard interface can be used by widely different contracts (including lending markets, aggregators, and intrinsically interest bearing tokens), which brings a number of subtleties. Navigating these potential issues is essential to implementing a compliant and composable token vault. + +We provide a base implementation of ERC-4626 that includes a simple vault. This contract is designed in a way that allows developers to easily re-configure the vault's behavior, with minimal overrides, while staying compliant. In this guide, we will discuss some security considerations that affect ERC-4626. We will also discuss common customizations of the vault. + +[[inflation-attack]] +== Security concern: Inflation attack + +=== Visualizing the vault + +In exchange for the assets deposited into an ERC-4626 vault, a user receives shares. These shares can later be burned to redeem the corresponding underlying assets. The number of shares a user gets depends on the amount of assets they put in and on the exchange rate of the vault. This exchange rate is defined by the current liquidity held by the vault. + +- If a vault has 100 tokens to back 200 shares, then each share is worth 0.5 assets. +- If a vault has 200 tokens to back 100 shares, then each share is worth 2.0 assets. + +In other words, the exchange rate can be defined as the slope of the line that passes through the origin and the current number of assets and shares in the vault. Deposits and withdrawals move the vault in this line. + +image::erc4626-rate-linear.png[Exchange rates in linear scale] + +When plotted in log-log scale, the rate is defined similarly, but appears differently (because the point (0,0) is infinitely far away). Rates are represented by "diagonal" lines with different offsets. + +image::erc4626-rate-loglog.png[Exchange rates in logarithmic scale] + +In such a representation, widely different rates can be clearly visible in the same graph. This wouldn't be the case in linear scale. + +image::erc4626-rate-loglogext.png[More exchange rates in logarithmic scale] + +=== The attack + +When depositing tokens, the number of shares a user gets is rounded towards zero. This rounding takes away value from the user in favor of the vault (i.e. in favor of all the current shareholders). This rounding is often negligible because of the amount at stake. If you deposit 1e9 shares worth of tokens, the rounding will have you lose at most 0.0000001% of your deposit. However if you deposit 10 shares worth of tokens, you could lose 10% of your deposit. Even worse, if you deposit <1 share worth of tokens, then you get 0 shares, and you basically made a donation. + +For a given amount of assets, the more shares you receive the safer you are. If you want to limit your losses to at most 1%, you need to receive at least 100 shares. + +image::erc4626-deposit.png[Depositing assets] + +In the figure we can see that for a given deposit of 500 assets, the number of shares we get and the corresponding rounding losses depend on the exchange rate. If the exchange rate is that of the orange curve, we are getting less than a share, so we lose 100% of our deposit. However, if the exchange rate is that of the green curve, we get 5000 shares, which limits our rounding losses to at most 0.02%. + +image::erc4626-mint.png[Minting shares] + +Symmetrically, if we focus on limiting our losses to a maximum of 0.5%, we need to get at least 200 shares. With the green exchange rate that requires just 20 tokens, but with the orange rate that requires 200000 tokens. + +We can clearly see that the blue and green curves correspond to vaults that are safer than the yellow and orange curves. + +The idea of an inflation attack is that an attacker can donate assets to the vault to move the rate curve to the right, and make the vault unsafe. + +image::erc4626-attack.png[Inflation attack without protection] + +Figure 6 shows how an attacker can manipulate the rate of an empty vault. First the attacker must deposit a small amount of tokens (1 token) and follow up with a donation of 1e5 tokens directly to the vault to move the exchange rate "right". This puts the vault in a state where any deposit smaller than 1e5 would be completely lost to the vault. Given that the attacker is the only shareholder (from their donation), the attacker would steal all the tokens deposited. + +An attacker would typically wait for a user to do the first deposit into the vault, and would frontrun that operation with the attack described above. The risk is low, and the size of the "donation" required to manipulate the vault is equivalent to the size of the deposit that is being attacked. + +In math that gives: + +- stem:[a_0] the attacker deposit +- stem:[a_1] the attacker donation +- stem:[u] the user deposit + +[%header,cols=4*] +|=== +| +| Assets +| Shares +| Rate + +| initial +| stem:[0] +| stem:[0] +| - + +| after attacker's deposit +| stem:[a_0] +| stem:[a_0] +| stem:[1] + +| after attacker's donation +| stem:[a_0+a_1] +| stem:[a_0] +| stem:[\frac{a_0}{a_0+a_1}] +|=== + +This means a deposit of stem:[u] will give stem:[\frac{u \times a_0}{a_0 + a_1}] shares. + +For the attacker to dilute that deposit to 0 shares, causing the user to lose all its deposit, it must ensure that + +[stem] +++++ +\frac{u \times a_0}{a_0+a_1} < 1 \iff u < 1 + \frac{a_1}{a_0} +++++ + +Using stem:[a_0 = 1] and stem:[a_1 = u] is enough. So the attacker only needs stem:[u+1] assets to perform a successful attack. + +It is easy to generalize the above results to scenarios where the attacker is going after a smaller fraction of the user's deposit. In order to target stem:[\frac{u}{n}], the user needs to suffer rounding of a similar fraction, which means the user must receive at most stem:[n] shares. This results in: + +[stem] +++++ +\frac{u \times a_0}{a_0+a_1} < n \iff \frac{u}{n} < 1 + \frac{a_1}{a_0} +++++ + +In this scenario, the attack is stem:[n] times less powerful (in how much it is stealing) and costs stem:[n] times less to execute. In both cases, the amount of funds the attacker needs to commit is equivalent to its potential earnings. + +=== Defending with a virtual offset + +The defense we propose is based on the approach used in link:https://github.com/boringcrypto/YieldBox[YieldBox]. It consists of two parts: + +- Use an offset between the "precision" of the representation of shares and assets. Said otherwise, we use more decimal places to represent the shares than the underlying token does to represent the assets. +- Include virtual shares and virtual assets in the exchange rate computation. These virtual assets enforce the conversion rate when the vault is empty. + +These two parts work together in enforcing the security of the vault. First, the increased precision corresponds to a high rate, which we saw is safer as it reduces the rounding error when computing the amount of shares. Second, the virtual assets and shares (in addition to simplifying a lot of the computations) capture part of the donation, making it unprofitable for a developer to perform an attack. + +Following the previous math definitions, we have: + +- stem:[\delta] the vault offset +- stem:[a_0] the attacker deposit +- stem:[a_1] the attacker donation +- stem:[u] the user deposit + +[%header,cols=4*] +|=== +| +| Assets +| Shares +| Rate + +| initial +| stem:[1] +| stem:[10^\delta] +| stem:[10^\delta] + +| after attacker's deposit +| stem:[1+a_0] +| stem:[10^\delta \times (1+a_0)] +| stem:[10^\delta] + +| after attacker's donation +| stem:[1+a_0+a_1] +| stem:[10^\delta \times (1+a_0)] +| stem:[10^\delta \times \frac{1+a_0}{1+a_0+a_1}] +|=== + +One important thing to note is that the attacker only owns a fraction stem:[\frac{a_0}{1 + a_0}] of the shares, so when doing the donation, he will only be able to recover that fraction stem:[\frac{a_1 \times a_0}{1 + a_0}] of the donation. The remaining stem:[\frac{a_1}{1+a_0}] are captured by the vault. + +[stem] +++++ +\mathit{loss} = \frac{a_1}{1+a_0} +++++ + +When the user deposits stem:[u], he receives + +[stem] +++++ +10^\delta \times u \times \frac{1+a_0}{1+a_0+a_1} +++++ + +For the attacker to dilute that deposit to 0 shares, causing the user to lose all its deposit, it must ensure that + +[stem] +++++ +10^\delta \times u \times \frac{1+a_0}{1+a_0+a_1} < 1 +++++ + +[stem] +++++ +\iff 10^\delta \times u < \frac{1+a_0+a_1}{1+a_0} +++++ + +[stem] +++++ +\iff 10^\delta \times u < 1 + \frac{a_1}{1+a_0} +++++ + +[stem] +++++ +\iff 10^\delta \times u \le \mathit{loss} +++++ + +- If the offset is 0, the attacker loss is at least equal to the user's deposit. +- If the offset is greater than 0, the attacker will have to suffer losses that are orders of magnitude bigger than the amount of value that can hypothetically be stolen from the user. + +This shows that even with an offset of 0, the virtual shares and assets make this attack non profitable for the attacker. Bigger offsets increase the security even further by making any attack on the user extremely wasteful. + +The following figure shows how the offset impacts the initial rate and limits the ability of an attacker with limited funds to inflate it effectively. + +image::erc4626-attack-3a.png[Inflation attack without offset=3] +stem:[\delta = 3], stem:[a_0 = 1], stem:[a_1 = 10^5] + +image::erc4626-attack-3b.png[Inflation attack without offset=3 and an attacker deposit that limits its losses] +stem:[\delta = 3], stem:[a_0 = 100], stem:[a_1 = 10^5] + +image::erc4626-attack-6.png[Inflation attack without offset=6] +stem:[\delta = 6], stem:[a_0 = 1], stem:[a_1 = 10^5] + + +[[fees]] +== Custom behavior: Adding fees to the vault + +In an ERC-4626 vaults, fees can be captured during the deposit/mint and/or during the withdraw/redeem steps. In both cases it is essential to remain compliant with the ERC-4626 requirements with regard to the preview functions. + +For example, if calling `deposit(100, receiver)`, the caller should deposit exactly 100 underlying tokens, including fees, and the receiver should receive a number of shares that matches the value returned by `previewDeposit(100)`. Similarly, `previewMint` should account for the fees that the user will have to pay on top of share's cost. + +As for the `Deposit` event, while this is less clear in the EIP spec itself, there seems to be consensus that it should include the number of assets paid for by the user, including the fees. + +On the other hand, when withdrawing assets, the number given by the user should correspond to what he receives. Any fees should be added to the quote (in shares) performed by `previewWithdraw`. + +The `Withdraw` event should include the number of shares the user burns (including fees) and the number of assets the user actually receives (after fees are deducted). + +The consequence of this design is that both the `Deposit` and `Withdraw` events will describe two exchange rates. The spread between the "Buy-in" and the "Exit" prices correspond to the fees taken by the vault. + +The following example describes how fees proportional to the deposited/withdrawn amount can be implemented: + +```solidity +include::api:example$ERC4626Fees.sol[] +``` diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc6909.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc6909.adoc new file mode 100644 index 0000000..164ded8 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc6909.adoc @@ -0,0 +1,47 @@ += ERC-6909 + +ERC-6909 is a draft EIP that draws on ERC-1155 learnings since it was published in 2018. The main goals of ERC-6909 is to decrease gas costs and complexity--this is mainly accomplished by removing batching and callbacks. + +TIP: To understand the inspiration for a multi token standard, see the xref:erc1155.adoc#multi-token-standard[multi token standard] section within the EIP-1155 docs. + +== Changes from ERC-1155 + +There are three main changes from ERC-1155 which are as follows: + +. The removal of batch operations. +. The removal of transfer callbacks. +. Granularization in approvals--approvals can be set globally (as operators) or as amounts per token (inspired by ERC20). + +== Constructing an ERC-6909 Token Contract + +We'll use ERC-6909 to track multiple items in a game, each having their own unique attributes. All item types will by minted to the deployer of the contract, which we can later transfer to players. We'll also use the xref:api:token/ERC6909.adoc#ERC6909Metadata[`ERC6909Metadata`] extension to add decimals to our fungible items (the vanilla ERC-6909 implementation does not have decimals). + +For simplicity, we will mint all items in the constructor--however, minting functionality could be added to the contract to mint on demand to players. + +TIP: For an overview of minting mechanisms, check out xref:erc20-supply.adoc[Creating ERC-20 Supply]. + +Here's what a contract for tokenized items might look like: + +[source,solidity] +---- +include::api:example$token/ERC6909/ERC6909GameItems.sol[] +---- + +Note that there is no content URI functionality in the base implementation, but the xref:api:token/ERC6909.adoc#ERC6909ContentURI[`ERC6909ContentURI`] extension adds it. Additionally, the base implementation does not track total supplies, but the xref:api:token/ERC6909.adoc#ERC6909TokenSupply[`ERC6909TokenSupply`] extension tracks the total supply of each token id. + +Once the contract is deployed, we will be able to query the deployer’s balance: +[source,javascript] +---- +> gameItems.balanceOf(deployerAddress, 3) +1000000000 +---- + +We can transfer items to player accounts: +[source,javascript] +---- +> gameItems.transfer(playerAddress, 2, 1) +> gameItems.balanceOf(playerAddress, 2) +1 +> gameItems.balanceOf(deployerAddress, 2) +0 +---- diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc721.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc721.adoc new file mode 100644 index 0000000..4b784db --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc721.adoc @@ -0,0 +1,58 @@ += ERC-721 + +We've discussed how you can make a _fungible_ token using xref:erc20.adoc[ERC-20], but what if not all tokens are alike? This comes up in situations like *real estate*, *voting rights*, or *collectibles*, where some items are valued more than others, due to their usefulness, rarity, etc. ERC-721 is a standard for representing ownership of xref:tokens.adoc#different-kinds-of-tokens[_non-fungible_ tokens], that is, where each token is unique. + +ERC-721 is a more complex standard than ERC-20, with multiple optional extensions, and is split across a number of contracts. The OpenZeppelin Contracts provide flexibility regarding how these are combined, along with custom useful extensions. Check out the xref:api:token/ERC721.adoc[API Reference] to learn more about these. + +== Constructing an ERC-721 Token Contract + +We'll use ERC-721 to track items in our game, which will each have their own unique attributes. Whenever one is to be awarded to a player, it will be minted and sent to them. Players are free to keep their token or trade it with other people as they see fit, as they would any other asset on the blockchain! Please note any account can call `awardItem` to mint items. To restrict what accounts can mint items we can add xref:access-control.adoc[Access Control]. + +Here's what a contract for tokenized items might look like: + +[source,solidity] +---- +include::api:example$token/ERC721/GameItem.sol[] +---- + +The xref:api:token/ERC721.adoc#ERC721URIStorage[`ERC721URIStorage`] contract is an implementation of ERC-721 that includes the metadata standard extensions (xref:api:token/ERC721.adoc#IERC721Metadata[`IERC721Metadata`]) as well as a mechanism for per-token metadata. That's where the xref:api:token/ERC721.adoc#ERC721-_setTokenURI-uint256-string-[`_setTokenURI`] method comes from: we use it to store an item's metadata. + +Also note that, unlike ERC-20, ERC-721 lacks a `decimals` field, since each token is distinct and cannot be partitioned. + +New items can be created: + +[source,javascript] +---- +> gameItem.awardItem(playerAddress, "https://game.example/item-id-8u5h2m.json") +Transaction successful. Transaction hash: 0x... +Events emitted: + - Transfer(0x0000000000000000000000000000000000000000, playerAddress, 7) +---- + +And the owner and metadata of each item queried: + +[source,javascript] +---- +> gameItem.ownerOf(7) +playerAddress +> gameItem.tokenURI(7) +"https://game.example/item-id-8u5h2m.json" +---- + +This `tokenURI` should resolve to a JSON document that might look something like: + +[source,json] +---- +{ + "name": "Thor's hammer", + "description": "Mjölnir, the legendary hammer of the Norse god of thunder.", + "image": "https://game.example/item-id-8u5h2m.png", + "strength": 20 +} +---- + +For more information about the `tokenURI` metadata JSON Schema, check out the https://eips.ethereum.org/EIPS/eip-721[ERC-721 specification]. + +NOTE: You'll notice that the item's information is included in the metadata, but that information isn't on-chain! So a game developer could change the underlying metadata, changing the rules of the game! + +TIP: If you'd like to put all item information on-chain, you can extend ERC-721 to do so (though it will be rather costly) by providing a xref:utilities.adoc#base64[`Base64`] Data URI with the JSON schema encoded. You could also leverage IPFS to store the tokenURI information, but these techniques are out of the scope of this overview guide. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/extending-contracts.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/extending-contracts.adoc new file mode 100644 index 0000000..8ff4101 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/extending-contracts.adoc @@ -0,0 +1,51 @@ += Extending Contracts + +Most of the OpenZeppelin Contracts are expected to be used via https://solidity.readthedocs.io/en/latest/contracts.html#inheritance[inheritance]: you will _inherit_ from them when writing your own contracts. + +This is the commonly found `is` syntax, like in `contract MyToken is ERC20`. + +[NOTE] +==== +Unlike ``contract``s, Solidity ``library``s are not inherited from and instead rely on the https://solidity.readthedocs.io/en/latest/contracts.html#using-for[`using for`] syntax. + +OpenZeppelin Contracts has some ``library``s: most are in the xref:api:utils.adoc[Utils] directory. +==== + +== Overriding + +Inheritance is often used to add the parent contract's functionality to your own contract, but that's not all it can do. You can also _change_ how some parts of the parent behave using _overrides_. + +For example, imagine you want to change xref:api:access.adoc#AccessControl[`AccessControl`] so that xref:api:access.adoc#AccessControl-revokeRole-bytes32-address-[`revokeRole`] can no longer be called. This can be achieved using overrides: + +```solidity +include::api:example$access-control/AccessControlModified.sol[] +``` + +The old `revokeRole` is then replaced by our override, and any calls to it will immediately revert. We cannot _remove_ the function from the contract, but reverting on all calls is good enough. + +=== Calling `super` + +Sometimes you want to _extend_ a parent's behavior, instead of outright changing it to something else. This is where `super` comes in. + +The `super` keyword will let you call functions defined in a parent contract, even if they are overridden. This mechanism can be used to add additional checks to a function, emit events, or otherwise add functionality as you see fit. + +TIP: For more information on how overrides work, head over to the https://solidity.readthedocs.io/en/latest/contracts.html#index-17[official Solidity documentation]. + +Here is a modified version of xref:api:access.adoc#AccessControl[`AccessControl`] where xref:api:access.adoc#AccessControl-revokeRole-bytes32-address-[`revokeRole`] cannot be used to revoke the `DEFAULT_ADMIN_ROLE`: + + +```solidity +include::api:example$access-control/AccessControlNonRevokableAdmin.sol[] +``` + +The `super.revokeRole` statement at the end will invoke ``AccessControl``'s original version of `revokeRole`, the same code that would've run if there were no overrides in place. + +NOTE: The same rule is implemented and extended in xref:api:access.adoc#AccessControlDefaultAdminRules[`AccessControlDefaultAdminRules`], an extension that also adds enforced security measures for the `DEFAULT_ADMIN_ROLE`. + +== Security + +The maintainers of OpenZeppelin Contracts are mainly concerned with the correctness and security of the code as published in the library, and the combinations of base contracts with the official extensions from the library. + +Custom overrides, especially to hooks, can disrupt important assumptions and may introduce security risks in the code that was previously secure. While we try to ensure the contracts remain secure in the face of a wide range of potential customizations, this is done in a best-effort manner. While we try to document all important assumptions, this should not be relied upon. Custom overrides should be carefully reviewed and checked against the source code of the contract they are customizing to fully understand their impact and guarantee their security. + +The way functions interact internally should not be assumed to stay stable across releases of the library. For example, a function that is used in one context in a particular release may not be used in the same context in the next release. Contracts that override functions should revalidate their assumptions when updating the version of OpenZeppelin Contracts they are built on. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/faq.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/faq.adoc new file mode 100644 index 0000000..81c34bb --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/faq.adoc @@ -0,0 +1,13 @@ += Frequently Asked Questions + +== Can I restrict a function to EOAs only? + +When calling external addresses from your contract it is unsafe to assume that an address is an externally-owned account (EOA) and not a contract. Attempting to prevent 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. + +Although checking that the address has code, `address.code.length > 0`, may seem to differentiate contracts from EOAs, it can only say that an address is currently a contract, and its negation (that an address is not currently a contract) does not imply that the address is an EOA. Some counterexamples are: + + - address of a contract in construction + - address where a contract will be created + - address where a contract lived, but was destroyed + +Furthermore, an address will be considered a contract within the same transaction where it is scheduled for destruction by `SELFDESTRUCT`, which only has an effect at the end of the entire transaction. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/governance.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/governance.adoc new file mode 100644 index 0000000..c2b8218 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/governance.adoc @@ -0,0 +1,239 @@ += How to set up on-chain governance + +In this guide we will learn how OpenZeppelin’s Governor contract works, how to set it up, and how to use it to create proposals, vote for them, and execute them, using tools provided by Ethers.js and Tally. + +NOTE: Find detailed contract documentation at xref:api:governance.adoc[Governance API]. + +== Introduction + +Decentralized protocols are in constant evolution from the moment they are publicly released. Often, the initial team retains control of this evolution in the first stages, but eventually delegates it to a community of stakeholders. The process by which this community makes decisions is called on-chain governance, and it has become a central component of decentralized protocols, fueling varied decisions such as parameter tweaking, smart contract upgrades, integrations with other protocols, treasury management, grants, etc. + +This governance protocol is generally implemented in a special-purpose contract called “Governor”. The GovernorAlpha and GovernorBravo contracts designed by Compound have been very successful and popular so far, with the downside that projects with different requirements have had to fork the code to customize it for their needs, which can pose a high risk of introducing security issues. For OpenZeppelin Contracts, we set out to build a modular system of Governor contracts so that forking is not needed, and different requirements can be accommodated by writing small modules using Solidity inheritance. You will find the most common requirements out of the box in OpenZeppelin Contracts, but writing additional ones is simple, and we will be adding new features as requested by the community in future releases. Additionally, the design of OpenZeppelin Governor requires minimal use of storage and results in more gas efficient operation. + +== Compatibility + +OpenZeppelin’s Governor system was designed with a concern for compatibility with existing systems that were based on Compound’s GovernorAlpha and GovernorBravo. Because of this, you will find that many modules are presented in two variants, one of which is built for compatibility with those systems. + +=== ERC20Votes & ERC20VotesComp + +The ERC-20 extension to keep track of votes and vote delegation is one such case. The shorter one is the more generic version because it can support token supplies greater than 2^96, while the “Comp” variant is limited in that regard, but exactly fits the interface of the COMP token that is used by GovernorAlpha and Bravo. Both contract variants share the same events, so they are fully compatible when looking at events only. + +=== Governor & GovernorStorage + +An OpenZeppelin Governor contract is not interface-compatible with Compound's GovernorAlpha or Bravo. Even though events are fully compatible, proposal lifecycle functions (creation, execution, etc.) have different signatures that are meant to optimize storage use. Other functions from GovernorAlpha and Bravo are likewise not available. It’s possible to opt in some Bravo-like behavior by inheriting from the GovernorStorage module. This module provides proposal enumerability and alternate versions of the `queue`, `execute` and `cancel` function that only take the proposal id. This module reduces the calldata needed by some operations in exchange for an increased storage footprint. This might be a good trade-off for some L2 chains. It also provides primitives for indexer-free frontends. + +Note that even with the use of this module, one important difference with Compound's GovernorBravo is the way that `proposalId`s are calculated. Governor uses the hash of the proposal parameters with the purpose of keeping its data off-chain by event indexing, while the original Bravo implementation uses sequential `proposalId`s. + +=== GovernorTimelockControl & GovernorTimelockCompound + +When using a timelock with your Governor contract, you can use either OpenZeppelin’s TimelockController or Compound’s Timelock. Based on the choice of timelock, you should choose the corresponding Governor module: GovernorTimelockControl or GovernorTimelockCompound respectively. This allows you to migrate an existing GovernorAlpha instance to an OpenZeppelin-based Governor without changing the timelock in use. + +=== Tally + +https://www.tally.xyz[Tally] is a full-fledged application for user owned on-chain governance. It comprises a voting dashboard, proposal creation wizard, real time research and analysis, and educational content. + +For all of these options, the Governor will be compatible with Tally: users will be able to create proposals, see voting periods and delays following xref:api:interfaces.adoc#IERC6372[IERC6372], visualize voting power and advocates, navigate proposals, and cast votes. For proposal creation in particular, projects can also use https://docs.openzeppelin.com/defender/module/actions#transaction-proposals-reference[Defender Transaction Proposals] as an alternative interface. + +In the rest of this guide, we will focus on a fresh deploy of the vanilla OpenZeppelin Governor features without concern for compatibility with GovernorAlpha or Bravo. + +== Setup + +=== Token + +The voting power of each account in our governance setup will be determined by an ERC-20 token. The token has to implement the ERC20Votes extension. This extension will keep track of historical balances so that voting power is retrieved from past snapshots rather than current balance, which is an important protection that prevents double voting. + +```solidity +include::api:example$governance/MyToken.sol[] +``` + +If your project already has a live token that does not include ERC20Votes and is not upgradeable, you can wrap it in a governance token by using ERC20Wrapper. This will allow token holders to participate in governance by wrapping their tokens 1-to-1. + +```solidity +include::api:example$governance/MyTokenWrapped.sol[] +``` + +NOTE: The only other source of voting power available in OpenZeppelin Contracts currently is xref:api:token/ERC721.adoc#ERC721Votes[`ERC721Votes`]. ERC-721 tokens that don't provide this functionality can be wrapped into a voting tokens using a combination of xref:api:token/ERC721.adoc#ERC721Votes[`ERC721Votes`] and xref:api:token/ERC721.adoc#ERC721Wrapper[`ERC721Wrapper`]. + +NOTE: The internal clock used by the token to store voting balances will dictate the operating mode of the Governor contract attached to it. By default, block numbers are used. Since v4.9, developers can override the xref:api:interfaces.adoc#IERC6372[IERC6372] clock to use timestamps instead of block numbers. + +=== Governor + +Initially, we will build a Governor without a timelock. The core logic is given by the Governor contract, but we still need to choose: 1) how voting power is determined, 2) how many votes are needed for quorum, 3) what options people have when casting a vote and how those votes are counted, and 4) what type of token should be used to vote. Each of these aspects is customizable by writing your own module, or more easily choosing one from OpenZeppelin Contracts. + +For 1) we will use the GovernorVotes module, which hooks to an IVotes instance to determine the voting power of an account based on the token balance they hold when a proposal becomes active. This module requires as a constructor parameter the address of the token. This module also discovers the clock mode (ERC-6372) used by the token and applies it to the Governor. + +For 2) we will use GovernorVotesQuorumFraction which works together with ERC20Votes to define quorum as a percentage of the total supply at the block a proposal’s voting power is retrieved. This requires a constructor parameter to set the percentage. Most Governors nowadays use 4%, so we will initialize the module with parameter 4 (this indicates the percentage, resulting in 4%). + +For 3) we will use GovernorCountingSimple, a module that offers 3 options to voters: For, Against, and Abstain, and where only For and Abstain votes are counted towards quorum. + +Besides these modules, Governor itself has some parameters we must set. + +votingDelay: How long after a proposal is created should voting power be fixed. A large voting delay gives users time to unstake tokens if necessary. + +votingPeriod: How long does a proposal remain open to votes. + +These parameters are specified in the unit defined in the token's clock. Assuming the token uses block numbers, and assuming block time of around 12 seconds, we will have set votingDelay = 1 day = 7200 blocks, and votingPeriod = 1 week = 50400 blocks. + +We can optionally set a proposal threshold as well. This restricts proposal creation to accounts that have enough voting power. + +```solidity +include::api:example$governance/MyGovernor.sol[] +``` + +=== Timelock + +It is good practice to add a timelock to governance decisions. This allows users to exit the system if they disagree with a decision before it is executed. We will use OpenZeppelin’s TimelockController in combination with the GovernorTimelockControl module. + +IMPORTANT: When using a timelock, it is the timelock that will execute proposals and thus the timelock that should hold any funds, ownership, and access control roles. Before version 4.5 there was no way to recover funds in the Governor contract when using a timelock! Before version 4.3, when using the Compound Timelock, ETH in the timelock was not easily accessible. + +TimelockController uses an AccessControl setup that we need to understand in order to set up roles. + +- The Proposer role is in charge of queueing operations: this is the role the Governor instance should be granted, and it should likely be the only proposer in the system. +- The Executor role is in charge of executing already available operations: we can assign this role to the special zero address to allow anyone to execute (if operations can be particularly time sensitive, the Governor should be made Executor instead). +- Lastly, there is the Admin role, which can grant and revoke the two previous roles: this is a very sensitive role that will be granted automatically to the timelock itself, and optionally to a second account, which can be used for ease of setup but should promptly renounce the role. + +== Proposal Lifecycle + +Let’s walk through how to create and execute a proposal on our newly deployed Governor. + +A proposal is a sequence of actions that the Governor contract will perform if it passes. Each action consists of a target address, calldata encoding a function call, and an amount of ETH to include. Additionally, a proposal includes a human-readable description. + +=== Create a Proposal + +Let’s say we want to create a proposal to give a team a grant, in the form of ERC-20 tokens from the governance treasury. This proposal will consist of a single action where the target is the ERC-20 token, calldata is the encoded function call `transfer(, )`, and with 0 ETH attached. + +Generally a proposal will be created with the help of an interface such as Tally or https://docs.openzeppelin.com/defender/module/actions#transaction-proposals-reference[Defender Proposals]. Here we will show how to create the proposal using Ethers.js. + +First we get all the parameters necessary for the proposal action. + +```javascript +const tokenAddress = ...; +const token = await ethers.getContractAt(‘ERC20’, tokenAddress); + +const teamAddress = ...; +const grantAmount = ...; +const transferCalldata = token.interface.encodeFunctionData(‘transfer’, [teamAddress, grantAmount]); +``` + +Now we are ready to call the propose function of the Governor. Note that we don’t pass in one array of actions, but instead three arrays corresponding to the list of targets, the list of values, and the list of calldatas. In this case it’s a single action, so it’s simple: + +```javascript +await governor.propose( + [tokenAddress], + [0], + [transferCalldata], + “Proposal #1: Give grant to team”, +); +``` + +This will create a new proposal, with a proposal id that is obtained by hashing together the proposal data, and which will also be found in an event in the logs of the transaction. + +=== Cast a Vote + +Once a proposal is active, delegates can cast their vote. Note that it is delegates who carry voting power: if a token holder wants to participate, they can set a trusted representative as their delegate, or they can become a delegate themselves by self-delegating their voting power. + +Votes are cast by interacting with the Governor contract through the `castVote` family of functions. Voters would generally invoke this from a governance UI such as Tally. + +image::tally-vote.png[Voting in Tally] + +=== Execute the Proposal + +Once the voting period is over, if quorum was reached (enough voting power participated) and the majority voted in favor, the proposal is considered successful and can proceed to be executed. Once a proposal passes, it can be queued and executed from the same place you voted. + +image::tally-exec.png[Administration Panel in Tally] + +We will see now how to do this manually using Ethers.js. + +If a timelock was set up, the first step to execution is queueing. You will notice that both the queue and execute functions require passing in the entire proposal parameters, as opposed to just the proposal id. This is necessary because this data is not stored on chain, as a measure to save gas. Note that these parameters can always be found in the events emitted by the contract. The only parameter that is not sent in its entirety is the description, since this is only needed in its hashed form to compute the proposal id. + +To queue, we call the queue function: + +```javascript +const descriptionHash = ethers.utils.id(“Proposal #1: Give grant to team”); + +await governor.queue( + [tokenAddress], + [0], + [transferCalldata], + descriptionHash, +); +``` + +This will cause the Governor to interact with the timelock contract and queue the actions for execution after the required delay. + +After enough time has passed (according to the timelock parameters), the proposal can be executed. If there was no timelock to begin with, this step can be ran immediately after the proposal succeeds. + +```javascript +await governor.execute( + [tokenAddress], + [0], + [transferCalldata], + descriptionHash, +); +``` + +Executing the proposal will transfer the ERC-20 tokens to the chosen recipient. To wrap up: we set up a system where a treasury is controlled by the collective decision of the token holders of a project, and all actions are executed via proposals enforced by on-chain votes. + +== Timestamp based governance + +=== Motivation + +It is sometimes difficult to deal with durations expressed in number of blocks because of inconsistent or unpredictable time between blocks. This is particularly true of some L2 networks where blocks are produced based on blockchain usage. Using number of blocks can also lead to the governance rules being affected by network upgrades that modify the expected time between blocks. + +The difficulty of replacing block numbers with timestamps is that the Governor and the token must both use the same format when querying past votes. If a token is designed around block numbers, it is not possible for a Governor to reliably do timestamp based lookups. + +Therefore, designing a timestamp based voting system starts with the token. + +=== Token + +Since v4.9, all voting contracts (including xref:api:token/ERC20.adoc#ERC20Votes[`ERC20Votes`] and xref:api:token/ERC721.adoc#ERC721Votes[`ERC721Votes`]) rely on xref:api:interfaces.adoc#IERC6372[IERC6372] for clock management. In order to change from operating with block numbers to operating with timestamps, all that is required is to override the `clock()` and `CLOCK_MODE()` functions. + +```solidity +include::api:example$governance/MyTokenTimestampBased.sol[] +``` + +=== Governor + +The Governor will automatically detect the clock mode used by the token and adapt to it. There is no need to override anything in the Governor contract. However, the clock mode does affect how some values are interpreted. It is therefore necessary to set the `votingDelay()` and `votingPeriod()` accordingly. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Governor} from "@openzeppelin/contracts/governance/Governor.sol"; +import {GovernorCountingSimple} from "@openzeppelin/contracts/governance/compatibility/GovernorCountingSimple.sol"; +import {GovernorVotes} from "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol"; +import {GovernorVotesQuorumFraction} from "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol"; +import {GovernorTimelockControl} from "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol"; +import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol"; +import {IVotes} from "@openzeppelin/contracts/governance/utils/IVotes.sol"; + +contract MyGovernor is Governor, GovernorCountingSimple, GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl { + constructor(IVotes _token, TimelockController _timelock) + Governor("MyGovernor") + GovernorVotes(_token) + GovernorVotesQuorumFraction(4) + GovernorTimelockControl(_timelock) + {} + + function votingDelay() public pure virtual override returns (uint256) { + return 1 days; + } + + function votingPeriod() public pure virtual override returns (uint256) { + return 1 weeks; + } + + function proposalThreshold() public pure virtual override returns (uint256) { + return 0; + } + + // ... +} +``` + +=== Disclaimer + +Timestamp based voting is a recent feature that was formalized in ERC-6372 and ERC-5805, and introduced in v4.9. At the time this feature is released, some governance tooling may not support it yet. Users can expect invalid reporting of deadlines & durations if the tool is not able to interpret the ERC6372 clock. This invalid reporting by offchain tools does not affect the onchain security and functionality of the governance contract. + +Governors with timestamp support (v4.9 and above) are compatible with old tokens (before v4.9) and will operate in "block number" mode (which is the mode all old tokens operate on). On the other hand, old Governor instances (before v4.9) are not compatible with new tokens operating using timestamps. If you update your token code to use timestamps, make sure to also update your Governor code. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/index.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/index.adoc new file mode 100644 index 0000000..3c8e57e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/index.adoc @@ -0,0 +1,70 @@ += Contracts + +*A library for secure smart contract development.* Build on a solid foundation of community-vetted code. + + * Implementations of standards like xref:erc20.adoc[ERC20] and xref:erc721.adoc[ERC721]. + * Flexible xref:access-control.adoc[role-based permissioning] scheme. + * Reusable xref:utilities.adoc[Solidity components] to build custom contracts and complex decentralized systems. + +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 xref:backwards-compatibility.adoc[Backwards Compatibility]. + +== Overview + +[[install]] +=== Installation + +==== Hardhat (npm) + +```console +$ 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. + +```console +$ forge install OpenZeppelin/openzeppelin-contracts +``` + +Add `@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/` in `remappings.txt.` + +[[usage]] +=== Usage + +Once installed, you can use the contracts in the library by importing them: + +[source,solidity] +---- +include::api:example$MyNFT.sol[] +---- + +TIP: If you're new to smart contract development, head to xref:learn::developing-smart-contracts.adoc[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. + +[[security]] +== Security + +Please report any security issues you find via our https://www.immunefi.com/bounty/openzeppelin[bug bounty program on Immunefi] or directly to security@openzeppelin.org. + +The https://contracts.openzeppelin.com/security[Security Center] contains more details about the secure development process. + +[[next-steps]] +== Learn More + +The guides in the sidebar will teach about different concepts, and how to use the related contracts that OpenZeppelin Contracts provides: + +* xref:access-control.adoc[Access Control]: decide who can perform each of the actions on your system. +* xref:tokens.adoc[Tokens]: create tradable assets or collectibles, like the well known xref:erc20.adoc[ERC20] and xref:erc721.adoc[ERC721] standards. +* xref:utilities.adoc[Utilities]: generic useful tools, including non-overflowing math, signature verification, and trustless paying systems. + +The xref:api:token/ERC20.adoc[full API] 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' development in the https://forum.openzeppelin.com[community forum]. + +The following articles provide great background reading, though please note, some of the referenced tools have changed as the tooling in the ecosystem continues to rapidly evolve. + +* https://blog.openzeppelin.com/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05[The Hitchhiker’s Guide to Smart Contracts in Ethereum] will help you get an overview of the various tools available for smart contract development, and help you set up your environment. +* https://blog.openzeppelin.com/a-gentle-introduction-to-ethereum-programming-part-1-783cc7796094[A Gentle Introduction to Ethereum Programming, Part 1] 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 https://blog.openzeppelin.com/designing-the-architecture-for-your-ethereum-application-9cec086f8317[Designing the architecture for your Ethereum application], which discusses how to better structure your application and its relationship to the real world. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/multisig.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/multisig.adoc new file mode 100644 index 0000000..b44406b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/multisig.adoc @@ -0,0 +1,306 @@ += Multisig Account + +A multi-signature (multisig) account is a smart account that requires multiple authorized signers to approve operations before execution. Unlike traditional accounts controlled by a single private key, multisigs distribute control among multiple parties, eliminating single points of failure. For example, a 2-of-3 multisig requires signatures from at least 2 out of 3 possible signers. + +Popular implementations like https://safe.global/[Safe] (formerly Gnosis Safe) have become the standard for securing valuable assets. Multisigs provide enhanced security through collective authorization, customizable controls for ownership and thresholds, and the ability to rotate signers without changing the account address. + +== Beyond Standard Signature Verification + +As discussed in the xref:accounts.adoc#signature_validation[accounts section], the standard approach for smart contracts to verify signatures is https://eips.ethereum.org/EIPS/eip-1271[ERC-1271], which defines an `isValidSignature(hash, signature)`. However, it is limited in two important ways: + +1. It assumes the signer has an EVM address +2. It treats the signer as a single identity + +This becomes problematic when implementing multisig accounts where: + +* You may want to use signers that don't have EVM addresses (like keys from hardware devices) +* Each signer needs to be individually verified rather than treated as a collective identity +* You need a threshold system to determine when enough valid signatures are present + +The https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol[SignatureChecker] library is useful for verifying EOA and ERC-1271 signatures, but it's not designed for more complex arrangements like threshold-based multisigs. + +== ERC-7913 Signers + +https://eips.ethereum.org/EIPS/eip-7913[ERC-7913] extends the concept of signer representation to include keys that don't have EVM addresses, addressing this limitation. OpenZeppelin implements this standard through three contracts: + +=== SignerERC7913 + +The xref:api:utils.adoc#SignerERC7913[`SignerERC7913`] contract allows a single ERC-7913 formatted signer to control an account. The signer is represented as a `bytes` object that concatenates a verifier address and a key: `verifier || key`. + +[source,solidity] +---- +// contracts/MyAccountERC7913.sol +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {Account} from "@openzeppelin/community-contracts/account/Account.sol"; +import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; +import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; +import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; +import {ERC7739} from "@openzeppelin/community-contracts/utils/cryptography/signers/ERC7739.sol"; +import {ERC7821} from "@openzeppelin/community-contracts/account/extensions/ERC7821.sol"; +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import {SignerERC7913} from "@openzeppelin/community-contracts/utils/cryptography/signers/SignerERC7913.sol"; + +contract MyAccountERC7913 is Account, SignerERC7913, ERC7739, ERC7821, ERC721Holder, ERC1155Holder, Initializable { + constructor() EIP712("MyAccount7913", "1") {} + + function initialize(bytes memory signer) public initializer { + _setSigner(signer); + } + + function setSigner(bytes memory signer) public onlyEntryPointOrSelf { + _setSigner(signer); + } + + /// @dev Allows the entry point as an authorized executor. + function _erc7821AuthorizedExecutor( + address caller, + bytes32 mode, + bytes calldata executionData + ) internal view virtual override returns (bool) { + return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); + } +} +---- + +WARNING: Leaving an account uninitialized may leave it unusable since no public key was associated with it. + +=== MultiSignerERC7913 + +The xref:api:utils/cryptography.adoc#MultiSignerERC7913[`MultiSignerERC7913`] contract extends this concept to support multiple signers with a threshold-based signature verification system. + +[source,solidity] +---- +// contracts/MyAccountMultiSigner.sol +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.27; + +import {Account} from "@openzeppelin/community-contracts/account/Account.sol"; +import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; +import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; +import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; +import {ERC7739} from "@openzeppelin/community-contracts/utils/cryptography/signers/ERC7739.sol"; +import {ERC7821} from "@openzeppelin/community-contracts/account/extensions/ERC7821.sol"; +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import {MultiSignerERC7913} from "@openzeppelin/community-contracts/utils/cryptography/signers/MultiSignerERC7913.sol"; + +contract MyAccountMultiSigner is + Account, + MultiSignerERC7913, + ERC7739, + ERC7821, + ERC721Holder, + ERC1155Holder, + Initializable +{ + constructor() EIP712("MyAccountMultiSigner", "1") {} + + function initialize(bytes[] memory signers, uint256 threshold) public initializer { + _addSigners(signers); + _setThreshold(threshold); + } + + function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf { + _addSigners(signers); + } + + function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf { + _removeSigners(signers); + } + + function setThreshold(uint256 threshold) public onlyEntryPointOrSelf { + _setThreshold(threshold); + } + + /// @dev Allows the entry point as an authorized executor. + function _erc7821AuthorizedExecutor( + address caller, + bytes32 mode, + bytes calldata executionData + ) internal view virtual override returns (bool) { + return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); + } +} +---- + +This implementation is ideal for standard multisig setups where each signer has equal authority, and a fixed number of approvals is required. + +The `MultiSignerERC7913` contract provides several key features for managing multi-signature accounts. It maintains a set of authorized signers and implements a threshold-based system that requires a minimum number of signatures to approve operations. The contract includes an internal interface for managing signers, allowing for the addition and removal of authorized parties. + +NOTE: `MultiSignerERC7913` safeguards to ensure that the threshold remains achievable based on the current number of active signers, preventing situations where operations could become impossible to execute. + +The contract also provides public functions for querying signer information: xref:api:utils/cryptography.adoc#MultiSignerERC7913-isSigner-bytes-[`isSigner(bytes memory signer)`] to check if a given signer is authorized, xref:api:utils/cryptography.adoc#MultiSignerERC7913-getSigners-uint64-uint64-[`getSigners(uint64 start, uint64 end)`] to retrieve a paginated list of authorized signers, and xref:api:utils/cryptography.adoc#MultiSignerERC7913-getSignerCount[`getSignerCount()`] to get the total number of signers. These functions are useful when validating signatures, implementing customized access control logic, or building user interfaces that need to display signer information. + +=== MultiSignerERC7913Weighted + +For more sophisticated governance structures, the xref:api:utils/cryptography.adoc#MultiSignerERC7913Weighted[`MultiSignerERC7913Weighted`] contract extends `MultiSignerERC7913` by assigning different weights to each signer. + +[source,solidity] +---- +// contracts/MyAccountMultiSignerWeighted.sol +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.27; + +import {Account} from "@openzeppelin/community-contracts/account/Account.sol"; +import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; +import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; +import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; +import {ERC7739} from "@openzeppelin/community-contracts/utils/cryptography/signers/ERC7739.sol"; +import {ERC7821} from "@openzeppelin/community-contracts/account/extensions/ERC7821.sol"; +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import {MultiSignerERC7913Weighted} from "@openzeppelin/community-contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol"; + +contract MyAccountMultiSignerWeighted is + Account, + MultiSignerERC7913Weighted, + ERC7739, + ERC7821, + ERC721Holder, + ERC1155Holder, + Initializable +{ + constructor() EIP712("MyAccountMultiSignerWeighted", "1") {} + + function initialize(bytes[] memory signers, uint256[] memory weights, uint256 threshold) public initializer { + _addSigners(signers); + _setSignerWeights(signers, weights); + _setThreshold(threshold); + } + + function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf { + _addSigners(signers); + } + + function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf { + _removeSigners(signers); + } + + function setThreshold(uint256 threshold) public onlyEntryPointOrSelf { + _setThreshold(threshold); + } + + function setSignerWeights(bytes[] memory signers, uint256[] memory weights) public onlyEntryPointOrSelf { + _setSignerWeights(signers, weights); + } + + /// @dev Allows the entry point as an authorized executor. + function _erc7821AuthorizedExecutor( + address caller, + bytes32 mode, + bytes calldata executionData + ) internal view virtual override returns (bool) { + return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); + } +} +---- + +This implementation is perfect for scenarios where different signers should have varying levels of authority, such as: + +* Board members with different voting powers +* Organizational structures with hierarchical decision-making +* Hybrid governance systems combining core team and community members +* Execution setups like "social recovery" where you trust particular guardians more than others + +The `MultiSignerERC7913Weighted` contract extends `MultiSignerERC7913` with a weighting system. Each signer can have a custom weight, and operations require the total weight of signing participants to meet or exceed the threshold. Signers without explicit weights default to a weight of 1. + +NOTE: When setting up a weighted multisig, ensure the threshold value matches the scale used for signer weights. For example, if signers have weights like 1, 2, or 3, then a threshold of 4 would require at least two signers (e.g., one with weight 1 and one with weight 3). + +== Setting Up a Multisig Account + +To create a multisig account, you need to: + +1. Define your signers +2. Determine your threshold +3. Initialize your account with these parameters + +The example below demonstrates setting up a 2-of-3 multisig account with different types of signers: + +[source,solidity] +---- +// Example setup code +function setupMultisigAccount() external { + // Create signers using different types of keys + bytes memory ecdsaSigner = alice; // EOA address (20 bytes) + + // P256 signer with format: verifier || pubKey + bytes memory p256Signer = abi.encodePacked( + p256Verifier, + bobP256PublicKeyX, + bobP256PublicKeyY + ); + + // RSA signer with format: verifier || pubKey + bytes memory rsaSigner = abi.encodePacked( + rsaVerifier, + abi.encode(charlieRSAPublicKeyE, charlieRSAPublicKeyN) + ); + + // Create array of signers + bytes[] memory signers = new bytes[](3); + signers[0] = ecdsaSigner; + signers[1] = p256Signer; + signers[2] = rsaSigner; + + // Set threshold to 2 (2-of-3 multisig) + uint256 threshold = 2; + + // Initialize the account + myMultisigAccount.initialize(signers, threshold); +} +---- + +For a weighted multisig, you would also specify weights: + +[source,solidity] +---- +// Example setup for weighted multisig +function setupWeightedMultisigAccount() external { + // Create array of signers (same as above) + bytes[] memory signers = new bytes[](3); + signers[0] = ecdsaSigner; + signers[1] = p256Signer; + signers[2] = rsaSigner; + + // Assign weights to signers (Alice:1, Bob:2, Charlie:3) + uint256[] memory weights = new uint256[](3); + weights[0] = 1; + weights[1] = 2; + weights[2] = 3; + + // Set threshold to 4 (requires at least Bob+Charlie or all three) + uint256 threshold = 4; + + // Initialize the weighted account + myWeightedMultisigAccount.initialize(signers, weights, threshold); +} +---- + +IMPORTANT: The xref:api:utils/cryptography.adoc#MultiSignerERC7913-_validateReachableThreshold--[`_validateReachableThreshold`] function ensures that the sum of weights for all active signers meets or exceeds the threshold. Any customization built on top of the multisigner contracts must ensure the threshold is always reachable. + +For multisig accounts, the signature is a complex structure that contains both the signers and their individual signatures. The format follows ERC-7913's specification and must be properly encoded. + +=== Signature Format + +The multisig signature is encoded as: + +[source,solidity] +---- +abi.encode( + bytes[] signers, // Array of signers sorted by `keccak256` + bytes[] signatures // Array of signatures corresponding to each signer +) +---- + +Where: + +* `signers` is an array of the signers participating in this particular signature +* `signatures` is an array of the individual signatures corresponding to each signer + +[NOTE] +==== +To avoid duplicate signers, the contract uses `keccak256` to generate a unique id for each signer. When providing a multisignature, the `signers` array should be sorted in ascending order by `keccak256`, and the `signatures` array must match the order of their corresponding signers. +==== diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/tokens.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/tokens.adoc new file mode 100644 index 0000000..217c5e0 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/tokens.adoc @@ -0,0 +1,31 @@ += Tokens + +Ah, the "token": blockchain's most powerful and most misunderstood tool. + +A token is a _representation of something in the blockchain_. This something can be money, time, services, shares in a company, a virtual pet, anything. By representing things as tokens, we can allow smart contracts to interact with them, exchange them, create or destroy them. + +[[but_first_coffee_a_primer_on_token_contracts]] +== But First, [strikethrough]#Coffee# a Primer on Token Contracts + +Much of the confusion surrounding tokens comes from two concepts getting mixed up: _token contracts_ and the actual _tokens_. + +A _token contract_ is simply an Ethereum smart contract. "Sending tokens" actually means "calling a method on a smart contract that someone wrote and deployed". At the end of the day, a token contract is not much more than a mapping of addresses to balances, plus some methods to add and subtract from those balances. + +It is these balances that represent the _tokens_ themselves. Someone "has tokens" when their balance in the token contract is non-zero. That's it! These balances could be considered money, experience points in a game, deeds of ownership, or voting rights, and each of these tokens would be stored in different token contracts. + +[[different-kinds-of-tokens]] +== Different Kinds of Tokens + +Note that there's a big difference between having two voting rights and two deeds of ownership: each vote is equal to all others, but houses usually are not! This is called https://en.wikipedia.org/wiki/Fungibility[fungibility]. _Fungible goods_ are equivalent and interchangeable, like Ether, fiat currencies, and voting rights. _Non-fungible_ goods are unique and distinct, like deeds of ownership, or collectibles. + +In a nutshell, when dealing with non-fungibles (like your house) you care about _which ones_ you have, while in fungible assets (like your bank account statement) what matters is _how much_ you have. + +== Standards + +Even though the concept of a token is simple, they have a variety of complexities in the implementation. Because everything in Ethereum is just a smart contract, and there are no rules about what smart contracts have to do, the community has developed a variety of *standards* (called EIPs or ERCs) for documenting how a contract can interoperate with other contracts. + +You've probably heard of the ERC-20 or ERC-721 token standards, and that's why you're here. Head to our specialized guides to learn more about these: + + * xref:erc20.adoc[ERC-20]: the most widespread token standard for fungible assets, albeit somewhat limited by its simplicity. + * xref:erc721.adoc[ERC-721]: the de-facto solution for non-fungible tokens, often used for collectibles and games. + * xref:erc1155.adoc[ERC-1155]: a novel standard for multi-tokens, allowing for a single contract to represent multiple fungible and non-fungible tokens, along with batched operations for increased gas efficiency. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/upgradeable.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/upgradeable.adoc new file mode 100644 index 0000000..6d252d8 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/upgradeable.adoc @@ -0,0 +1,77 @@ += Using with Upgrades + +If your contract is going to be deployed with upgradeability, such as using the xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins], you will need to use the Upgradeable variant of OpenZeppelin Contracts. + +This variant is available as a separate package called `@openzeppelin/contracts-upgradeable`, which is hosted in the repository https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable[OpenZeppelin/openzeppelin-contracts-upgradeable]. It uses `@openzeppelin/contracts` as a peer dependency. + +It follows all of the rules for xref:upgrades-plugins::writing-upgradeable.adoc[Writing Upgradeable Contracts]: constructors are replaced by initializer functions, state variables are initialized in initializer functions, and we additionally check for storage incompatibilities across minor versions. + +TIP: OpenZeppelin provides a full suite of tools for deploying and securing upgradeable smart contracts. xref:openzeppelin::upgrades.adoc[Check out the full list of resources]. + +== Overview + +=== Installation + +```console +$ npm install @openzeppelin/contracts-upgradeable @openzeppelin/contracts +``` + +=== Usage + +The Upgradeable package replicates the structure of the main OpenZeppelin Contracts package, but every file and contract has the suffix `Upgradeable`. + +```diff +-import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; ++import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; + +-contract MyCollectible is ERC721 { ++contract MyCollectible is ERC721Upgradeable { +``` + +NOTE: Interfaces and libraries are not included in the Upgradeable package, but are instead imported from the main OpenZeppelin Contracts package. + +Constructors are replaced by internal initializer functions following the naming convention `+__{ContractName}_init+`. Since these are internal, you must always define your own public initializer function and call the parent initializer of the contract you extend. + +```diff +- constructor() ERC721("MyCollectible", "MCO") public { ++ function initialize() initializer public { ++ __ERC721_init("MyCollectible", "MCO"); + } +``` + +CAUTION: Use with multiple inheritance requires special attention. See the section below titled <>. + +Once this contract is set up and compiled, you can deploy it using the xref:upgrades-plugins::index.adoc[Upgrades Plugins]. The following snippet shows an example deployment script using Hardhat. + +```js +// scripts/deploy-my-collectible.js +const { ethers, upgrades } = require("hardhat"); + +async function main() { + const MyCollectible = await ethers.getContractFactory("MyCollectible"); + + const mc = await upgrades.deployProxy(MyCollectible); + + await mc.waitForDeployment(); + console.log("MyCollectible deployed to:", await mc.getAddress()); +} + +main(); +``` + +== Further Notes + +[[multiple-inheritance]] +=== Multiple Inheritance + +Initializer functions are not linearized by the compiler like constructors. Because of this, each `+__{ContractName}_init+` function embeds the linearized calls to all parent initializers. As a consequence, calling two of these `init` functions can potentially initialize the same contract twice. + +The function `+__{ContractName}_init_unchained+` found in every contract is the initializer function minus the calls to parent initializers, and can be used to avoid the double initialization problem, but doing this manually is not recommended. We hope to be able to implement safety checks for this in future versions of the Upgrades Plugins. + +=== Namespaced Storage + +You may notice that contracts use a struct with the `@custom:storage-location erc7201:` annotation to store the contract's state variables. This follows the https://eips.ethereum.org/EIPS/eip-7201[ERC-7201: Namespaced Storage Layout] pattern, where each contract has its own storage layout in a namespace that is separate from other contracts in the inheritance chain. + +Without namespaced storage, it isn't safe to simply add a state variable because it "shifts down" all of the state variables below in the inheritance chain. This makes the storage layouts incompatible, as explained in xref:upgrades-plugins::writing-upgradeable.adoc#modifying-your-contracts[Writing Upgradeable Contracts]. + +The namespaced storage pattern used in the Upgradeable package allows us to freely add new state variables in the future without compromising the storage compatibility with existing deployments. It also allows changing the inheritance order with no impact on the resulting storage layout, as long as all inherited contracts use namespaced storage. \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/utilities.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/utilities.adoc new file mode 100644 index 0000000..a248a0a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/utilities.adoc @@ -0,0 +1,559 @@ += Utilities + +The OpenZeppelin Contracts provide a ton of useful utilities that you can use in your project. For a complete list, check out the xref:api:utils.adoc[API Reference]. +Here are some of the more popular ones. + +[[cryptography]] +== Cryptography + +=== Checking Signatures On-Chain + +At a high level, signatures are a set of cryptographic algorithms that allow for a _signer_ to prove himself owner of a _private key_ used to authorize a piece of information (generally a transaction or `UserOperation`). Natively, the EVM supports the Elliptic Curve Digital Signature Algorithm (https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm[ECDSA]) using the secp256k1 curve, however other signature algorithms such as P256 and RSA are supported. + +==== Ethereum Signatures (secp256k1) + +xref:api:utils/cryptography.adoc#ECDSA[`ECDSA`] provides functions for recovering and managing Ethereum account ECDSA signatures. These are often generated via https://web3js.readthedocs.io/en/v1.7.3/web3-eth.html#sign[`web3.eth.sign`], and form a 65-byte array (of type `bytes` in Solidity) arranged the following way: `[[v (1)], [r (32)], [s (32)]]`. + +The data signer can be recovered with xref:api:utils/cryptography.adoc#ECDSA-recover-bytes32-bytes-[`ECDSA.recover`], and its address compared to verify the signature. Most wallets will hash the data to sign and add the prefix `\x19Ethereum Signed Message:\n`, so when attempting to recover the signer of an Ethereum signed message hash, you'll want to use xref:api:utils/cryptography.adoc#MessageHashUtils-toEthSignedMessageHash-bytes32-[`toEthSignedMessageHash`]. + +[source,solidity] +---- +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; +} +---- + +WARNING: Getting signature verification right is not trivial: make sure you fully read and understand xref:api:utils/cryptography.adoc#MessageHashUtils[`MessageHashUtils`]'s and xref:api:utils/cryptography.adoc#ECDSA[`ECDSA`]'s documentation. + +==== P256 Signatures (secp256r1) + +P256, also known as secp256r1, is one of the most used signature schemes. P256 signatures are standardized by the National Institute of Standards and Technology (NIST) and they are widely available in consumer hardware and software. + +These signatures are different from regular Ethereum Signatures (secp256k1) in that they use a different elliptic curve to perform operations but have similar security guarantees. + +[source,solidity] +---- +using P256 for bytes32; + +function _verify( + bytes32 data, + bytes32 r, + bytes32 s, + bytes32 qx, + bytes32 qy +) internal pure returns (bool) { + return data.verify(data, r, s, qx, qy); +} +---- + +By default, the `verify` function will try calling the https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md[RIP-7212] precompile at address `0x100` and will fallback to an implementation in Solidity if not available. We encourage you to use `verifyNative` if you know the precompile is available on the chain you're working on and on any other chain on which you intend to use the same bytecode in the future. In case of any doubts regarding the implementation roadmap of the native precompile `P256` of potential future target chains, please consider using `verifySolidity`. + +[source,solidity] +---- +using P256 for bytes32; + +function _verify( + bytes32 data, + bytes32 r, + bytes32 s, + bytes32 qx, + bytes32 qy +) internal pure returns (bool) { + // Will only call the precompile at address(0x100) + return data.verifyNative(data, r, s, qx, qy); +} +---- + +IMPORTANT: The P256 library only allows for `s` values in the lower order of the curve (i.e. `s <= N/2`) to prevent malleability. In case your tooling produces signatures in both sides of the curve, consider flipping the `s` value to keep compatibility. + +==== RSA + +RSA is a public-key cryptosystem that was popularized by corporate and governmental public key infrastructures (https://en.wikipedia.org/wiki/Public_key_infrastructure[PKIs]) and https://en.wikipedia.org/wiki/Domain_Name_System_Security_Extensions[DNSSEC]. + +This cryptosystem consists of using a private key that's the product of 2 large prime numbers. The message is signed by applying a modular exponentiation to its hash (commonly SHA256), where both the exponent and modulus compose the public key of the signer. + +RSA signatures are known for being less efficient than elliptic curve signatures given the size of the keys, which are big compared to ECDSA keys with the same security level. Using plain RSA is considered unsafe, this is why the implementation uses the `EMSA-PKCS1-v1_5` encoding method from https://datatracker.ietf.org/doc/html/rfc8017[RFC8017] to include padding to the signature. + +To verify a signature using RSA, you can leverage the xref:api:utils/cryptography.adoc#RSA[`RSA`] library that exposes a method for verifying RSA with the PKCS 1.5 standard: + +[source,solidity] +---- +using RSA for bytes32; + +function _verify( + bytes32 data, + bytes memory signature, + bytes memory e, + bytes memory n +) internal pure returns (bool) { + return data.pkcs1Sha256(signature, e, n); +} +---- + +IMPORTANT: Always use keys of at least 2048 bits. Additionally, be aware that PKCS#1 v1.5 allows for replayability due to the possibility of arbitrary optional parameters. To prevent replay attacks, consider including an onchain nonce or unique identifier in the message. + +=== Signature Verification + +The xref:api:utils/cryptography.adoc#SignatureChecker[`SignatureChecker`] library provides a unified interface for verifying signatures from different sources. It seamlessly supports: + +* ECDSA signatures from externally owned accounts (EOAs) +* ERC-1271 signatures from smart contract wallets like Argent and Safe Wallet +* ERC-7913 signatures from keys that don't have their own Ethereum address + +This allows developers to write signature verification code once and have it work across all these different signature types. + +==== Basic Signature Verification + +For standard signature verification that supports both EOAs and ERC-1271 contracts: + +[source,solidity] +---- +using SignatureChecker for address; + +function _verifySignature(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { + return SignatureChecker.isValidSignatureNow(signer, hash, signature); +} +---- + +The library automatically detects whether the signer is an EOA or a contract and uses the appropriate verification method. + +==== ERC-1271 Contract Signatures + +For smart contract wallets that implement ERC-1271, you can explicitly use: + +[source,solidity] +---- +function _verifyContractSignature(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { + return SignatureChecker.isValidERC1271SignatureNow(signer, hash, signature); +} +---- + +==== ERC-7913 Extended Signatures + +ERC-7913 extends signature verification to support keys that don't have their own Ethereum address. This is useful for integrating non-Ethereum cryptographic curves, hardware devices, or other identity systems. + +A signer is represented as a `bytes` object that concatenates a verifier address and a key: `verifier || key`. + +[source,solidity] +---- +function _verifyERC7913Signature(bytes memory signer, bytes32 hash, bytes memory signature) internal view returns (bool) { + return SignatureChecker.isValidSignatureNow(signer, hash, signature); +} +---- + +The verification process works as follows: + +* If `signer.length < 20`: verification fails +* If `signer.length == 20`: verification is done using standard signature checking +* Otherwise: verification is done using an ERC-7913 verifier + +==== Batch Verification + +For verifying multiple ERC-7913 signatures at once: + +[source,solidity] +---- +function _verifyMultipleSignatures( + bytes32 hash, + bytes[] memory signers, + bytes[] memory signatures +) internal view returns (bool) { + return SignatureChecker.areValidSignaturesNow(hash, signers, signatures); +} +---- + +This function will reject inputs that contain duplicated signers. Sorting the signers by their `keccak256` hash is recommended to minimize the gas cost. + +This unified approach allows smart contracts to accept signatures from any supported source without needing to implement different verification logic for each type. + +=== Verifying Merkle Proofs + +Developers can build a Merkle Tree off-chain, which allows for verifying that an element (leaf) is part of a set by using a Merkle Proof. This technique is widely used for creating whitelists (e.g., for airdrops) and other advanced use cases. + +TIP: OpenZeppelin Contracts provides a https://github.com/OpenZeppelin/merkle-tree[JavaScript library] for building trees off-chain and generating proofs. + +xref:api:utils/cryptography.adoc#MerkleProof[`MerkleProof`] provides: + +* xref:api:utils/cryptography.adoc#MerkleProof-verify-bytes32---bytes32-bytes32-[`verify`] - can prove that some value is part of a https://en.wikipedia.org/wiki/Merkle_tree[Merkle tree]. + +* xref:api:utils/cryptography.adoc#MerkleProof-multiProofVerify-bytes32-bytes32---bytes32---bool---[`multiProofVerify`] - can prove multiple values are part of a Merkle tree. + +For an on-chain Merkle Tree, see the xref:api:utils.adoc#MerkleTree[`MerkleTree`] library. + +[[introspection]] +== Introspection + +In Solidity, it's frequently helpful to know whether or not a contract supports an interface you'd like to use. ERC-165 is a standard that helps do runtime interface detection. Contracts provide helpers both for implementing ERC-165 in your contracts and querying other contracts: + +* xref:api:utils.adoc#IERC165[`IERC165`] — this is the ERC-165 interface that defines xref:api:utils.adoc#IERC165-supportsInterface-bytes4-[`supportsInterface`]. When implementing ERC-165, you'll conform to this interface. +* xref:api:utils.adoc#ERC165[`ERC165`] — inherit this contract if you'd like to support interface detection using a lookup table in contract storage. You can register interfaces using xref:api:utils.adoc#ERC165-_registerInterface-bytes4-[`_registerInterface(bytes4)`]: check out example usage as part of the ERC-721 implementation. +* xref:api:utils.adoc#ERC165Checker[`ERC165Checker`] — ERC165Checker simplifies the process of checking whether or not a contract supports an interface you care about. +* include with `using ERC165Checker for address;` +* xref:api:utils.adoc#ERC165Checker-_supportsInterface-address-bytes4-[`myAddress._supportsInterface(bytes4)`] +* xref:api:utils.adoc#ERC165Checker-_supportsAllInterfaces-address-bytes4---[`myAddress._supportsAllInterfaces(bytes4[\])`] + +[source,solidity] +---- +contract MyContract { + using ERC165Checker for address; + + bytes4 private InterfaceId_ERC721 = 0x80ac58cd; + + /** + * @dev transfer an ERC-721 token from this contract to someone else + */ + function transferERC721( + address token, + address to, + uint256 tokenId + ) + public + { + require(token.supportsInterface(InterfaceId_ERC721), "IS_NOT_721_TOKEN"); + IERC721(token).transferFrom(address(this), to, tokenId); + } +} +---- + +[[math]] +== Math + +Although Solidity already provides math operators (i.e. `+`, `-`, etc.), Contracts includes xref:api:utils.adoc#Math[`Math`]; a set of utilities for dealing with mathematical operators, with support for extra operations (e.g., xref:api:utils.adoc#Math-average-uint256-uint256-[`average`]) and xref:api:utils.adoc#SignedMath[`SignedMath`]; a library specialized in signed math operations. + +Include these contracts with `using Math for uint256` or `using SignedMath for int256` and then use their functions in your code: + +[source,solidity] +---- +contract MyContract { + using Math for uint256; + using SignedMath for int256; + + function tryOperations(uint256 a, uint256 b) internal pure { + (bool succeededAdd, uint256 resultAdd) = x.tryAdd(y); + (bool succeededSub, uint256 resultSub) = x.trySub(y); + (bool succeededMul, uint256 resultMul) = x.tryMul(y); + (bool succeededDiv, uint256 resultDiv) = x.tryDiv(y); + // ... + } + + function unsignedAverage(int256 a, int256 b) { + int256 avg = a.average(b); + // ... + } +} +---- + +Easy! + +TIP: While working with different data types that might require casting, you can use xref:api:utils.adoc#SafeCast[`SafeCast`] for type casting with added overflow checks. + +[[structures]] +== Structures + +Some use cases require more powerful data structures than arrays and mappings offered natively in Solidity. Contracts provides these libraries for enhanced data structure management: + +- xref:api:utils.adoc#BitMaps[`BitMaps`]: Store packed booleans in storage. +- xref:api:utils.adoc#Checkpoints[`Checkpoints`]: Checkpoint values with built-in lookups. +- xref:api:utils.adoc#DoubleEndedQueue[`DoubleEndedQueue`]: Store items in a queue with `pop()` and `queue()` constant time operations. +- xref:api:utils.adoc#EnumerableSet[`EnumerableSet`]: A https://en.wikipedia.org/wiki/Set_(abstract_data_type)[set] with enumeration capabilities. +- xref:api:utils.adoc#EnumerableMap[`EnumerableMap`]: A `mapping` variant with enumeration capabilities. +- xref:api:utils.adoc#MerkleTree[`MerkleTree`]: An on-chain https://wikipedia.org/wiki/Merkle_Tree[Merkle Tree] with helper functions. +- xref:api:utils.adoc#Heap.sol[`Heap`]: A + +The `Enumerable*` structures are similar to mappings in that they store and remove elements in constant time and don't allow for repeated entries, but they also support _enumeration_, which means you can easily query all stored entries both on and off-chain. + +=== Building a Merkle Tree + +Building an on-chain Merkle Tree allows developers to keep track of the history of roots in a decentralized manner. For these cases, the xref:api:utils.adoc#MerkleTree[`MerkleTree`] includes a predefined structure with functions to manipulate the tree (e.g. pushing values or resetting the tree). + +The Merkle Tree does not keep track of the roots intentionally, so that developers can choose their tracking mechanism. Setting up and using a Merkle Tree in Solidity is as simple as follows: + +NOTE: Functions are exposed without access control for demonstration purposes + +[source,solidity] +---- +using MerkleTree for MerkleTree.Bytes32PushTree; +MerkleTree.Bytes32PushTree private _tree; + +function setup(uint8 _depth, bytes32 _zero) public /* onlyOwner */ { + root = _tree.setup(_depth, _zero); +} + +function push(bytes32 leaf) public /* onlyOwner */ { + (uint256 leafIndex, bytes32 currentRoot) = _tree.push(leaf); + // Store the new root. +} +---- + +The library also supports custom hashing functions, which can be passed as an extra parameter to the xref:api:utils.adoc#MerkleTree-push-struct-MerkleTree-Bytes32PushTree-bytes32-[`push`] and xref:api:utils.adoc#MerkleTree-setup-struct-MerkleTree-Bytes32PushTree-uint8-bytes32-[`setup`] functions. + +Using custom hashing functions is a sensitive operation. After setup, it requires to keep using the same hashing function for every new value pushed to the tree to avoid corrupting the tree. For this reason, it's a good practice to keep your hashing function static in your implementation contract as follows: + +[source,solidity] +---- +using MerkleTree for MerkleTree.Bytes32PushTree; +MerkleTree.Bytes32PushTree private _tree; + +function setup(uint8 _depth, bytes32 _zero) public /* onlyOwner */ { + root = _tree.setup(_depth, _zero, _hashFn); +} + +function push(bytes32 leaf) public /* onlyOwner */ { + (uint256 leafIndex, bytes32 currentRoot) = _tree.push(leaf, _hashFn); + // Store the new root. +} + +function _hashFn(bytes32 a, bytes32 b) internal view returns(bytes32) { + // Custom hash function implementation + // Kept as an internal implementation detail to + // guarantee the same function is always used +} +---- + +=== Using a Heap + +A https://en.wikipedia.org/wiki/Binary_heap[binary heap] is a data structure that always stores the most important element at its peak and it can be used as a priority queue. + +To define what is most important in a heap, these frequently take comparator functions that tell the binary heap whether a value has more relevance than another. + +OpenZeppelin Contracts implements a Heap data structure with the properties of a binary heap. The heap uses the xref:api:utils.adoc#Comparators-lt-uint256-uint256-[`lt`] function by default but allows to customize its comparator. + +When using a custom comparator, it's recommended to wrap your function to avoid the possibility of mistakenly using a different comparator function: + +[source,solidity] +---- +function pop(Uint256Heap storage self) internal returns (uint256) { + return pop(self, Comparators.gt); +} + +function insert(Uint256Heap storage self, uint256 value) internal { + insert(self, value, Comparators.gt); +} + +function replace(Uint256Heap storage self, uint256 newValue) internal returns (uint256) { + return replace(self, newValue, Comparators.gt); +} +---- + + +[[misc]] +== Misc + +=== Packing + +The storage in the EVM is shaped in chunks of 32 bytes, each of this chunks is known as a _slot_, and can hold multiple values together as long as these values don't exceed its size. These properties of the storage allow for a technique known as _packing_, that consists of placing values together on a single storage slot to reduce the costs associated to reading and writing to multiple slots instead of just one. + +Commonly, developers pack values using structs that place values together so they fit better in storage. However, this approach requires to load such struct from either calldata or memory. Although sometimes necessary, it may be useful to pack values in a single slot and treat it as a packed value without involving calldata or memory. + +The xref:api:utils.adoc#Packing[`Packing`] library is a set of utilities for packing values that fit in 32 bytes. The library includes 3 main functionalities: + +* Packing 2 `bytesXX` values +* Extracting a packed `bytesXX` value from a `bytesYY` +* Replacing a packed `bytesXX` value from a `bytesYY` + +With these primitives, one can build custom functions to create custom packed types. For example, suppose you need to pack an `address` of 20 bytes with a `bytes4` selector and an `uint64` time period: + +[source,solidity] +---- +function _pack(address account, bytes4 selector, uint64 period) external pure returns (bytes32) { + bytes12 subpack = Packing.pack_4_8(selector, bytes8(period)); + return Packing.pack_20_12(bytes20(account), subpack); +} + +function _unpack(bytes32 pack) external pure returns (address, bytes4, uint64) { + return ( + address(Packing.extract_32_20(pack, 0)), + Packing.extract_32_4(pack, 20), + uint64(Packing.extract_32_8(pack, 24)) + ); +} +---- + +=== Storage Slots + +Solidity allocates a storage pointer for each variable declared in a contract. However, there are cases when it's required to access storage pointers that can't be derived by using regular Solidity. +For those cases, the xref:api:utils.adoc#StorageSlot[`StorageSlot`] library allows for manipulating storage slots directly. + +[source,solidity] +---- +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; +} +---- + +The xref:api:utils.adoc#TransientSlot[`TransientSlot`] library supports transient storage through user defined value types (https://docs.soliditylang.org/en/latest/types.html#user-defined-value-types[UDVTs]), which enables the same value types as in Solidity. + +[source,solidity] +---- +bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542; + +function _getTransientLock() internal view returns (bool) { + return _LOCK_SLOT.asBoolean().tload(); +} + +function _setTransientLock(bool lock) internal { + _LOCK_SLOT.asBoolean().tstore(lock); +} +---- + +WARNING: Manipulating storage slots directly is an advanced practice. Developers MUST make sure that the storage pointer is not colliding with other variables. + +One of the most common use cases for writing directly to storage slots is ERC-7201 for namespaced storage, which is guaranteed to not collide with other storage slots derived by Solidity. + +Users can leverage this standard using the xref:api:utils.adoc#SlotDerivation[`SlotDerivation`] library. + +[source,solidity] +---- +using SlotDerivation for bytes32; +string private constant _NAMESPACE = "" // eg. example.main + +function erc7201Pointer() internal view returns (bytes32) { + return _NAMESPACE.erc7201Slot(); +} +---- + +=== Base64 + +xref:api:utils.adoc#Base64[`Base64`] util allows you to transform `bytes32` data into its Base64 `string` representation. + +This is especially useful for building URL-safe tokenURIs for both xref:api:token/ERC721.adoc#IERC721Metadata-tokenURI-uint256-[`ERC-721`] or xref:api:token/ERC1155.adoc#IERC1155MetadataURI-uri-uint256-[`ERC-1155`]. This library provides a clever way to serve URL-safe https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs/[Data URI] compliant strings to serve on-chain data structures. + +Here is an example to send JSON Metadata through a Base64 Data URI using an ERC-721: + +[source,solidity] +---- +include::api:example$utilities/Base64NFT.sol[] +---- + +=== Multicall + +The `Multicall` abstract contract comes with a `multicall` function that bundles together multiple calls in a single external call. With it, external accounts may perform atomic operations comprising several function calls. This is not only useful for EOAs to make multiple calls in a single transaction, it's also a way to revert a previous call if a later one fails. + +Consider this dummy contract: + +[source,solidity] +---- +include::api:example$utilities/Multicall.sol[] +---- + +This is how to call the `multicall` function using Ethers.js, allowing `foo` and `bar` to be called in a single transaction: +[source,javascript] +---- +// scripts/foobar.js + +const instance = await ethers.deployContract("Box"); + +await instance.multicall([ + instance.interface.encodeFunctionData("foo"), + instance.interface.encodeFunctionData("bar") +]); +---- + +=== Historical Block Hashes + +xref:api:utils.adoc#Blockhash[`Blockhash`] provides L2 protocol developers with extended access to historical block hashes beyond Ethereum's native 256-block limit. By leveraging https://eips.ethereum.org/EIPS/eip-2935[EIP-2935]'s history storage contract, the library enables access to block hashes up to 8,191 blocks in the past, making it invaluable for L2 fraud proofs and state verification systems. + +The library seamlessly combines native `BLOCKHASH` opcode access for recent blocks (≤256) with EIP-2935 history storage queries for older blocks (257-8,191). It handles edge cases gracefully by returning zero for future blocks or those beyond the history window, matching the EVM's behavior. The implementation uses gas-efficient assembly for static calls to the history storage contract. + +[source,solidity] +---- +contract L1Inbox { + using Blockhash for uint256; + + function verifyBlockHash(uint256 blockNumber, bytes32 expectedHash) public view returns (bool) { + return blockNumber.blockHash() == expectedHash; + } +} +---- + +IMPORTANT: After EIP-2935 activation, it takes 8,191 blocks to completely fill the history storage. Before that, only block hashes since the fork block will be available. + +=== Time + +The xref:api:utils.adoc#Time[`Time`] library provides helpers for manipulating time-related objects in a type-safe manner. It uses `uint48` for timepoints and `uint32` for durations, helping to reduce gas costs while providing adequate precision. + +One of its key features is the `Delay` type, which represents a duration that can automatically change its value at a specified point in the future while maintaining delay guarantees. For example, when reducing a delay value (e.g., from 7 days to 1 day), the change only takes effect after the difference between the old and new delay (i.e. a 6 days) or a minimum setback period, preventing an attacker who gains admin access from immediately reducing security timeouts and executing sensitive operations. This is particularly useful for governance and security mechanisms where timelock periods need to be enforced. + +Consider this example for using and safely updating Delays: +[source,solidity] +---- +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Time} from "contracts/utils/types/Time.sol"; + +contract MyDelayedContract { + using Time for *; + + Time.Delay private _delay; + + constructor() { + _delay = Time.toDelay(3 days); + } + + function schedule(bytes32 operationId) external { + // Get the current `_delay` value, respecting any pending delay changes if they've taken effect + uint32 currentDelay = _delay.get(); + uint48 executionTime = Time.timestamp() + currentDelay; + + // ... schedule the operation at `executionTime` + } + + function execute(bytes32 operationId) external { + uint48 executionTime = getExecutionTime(operationId); + require(executionTime > 0, "Operation not scheduled"); + require(Time.timestamp() >= executionTime, "Delay not elapsed yet"); + + // ... execute the operation + } + + // Update the delay with `Time`'s safety mechanism + function updateDelay(uint32 newDelay) external { + (Time.Delay updatedDelay, uint48 effect) = _delay.withUpdate( + newDelay, // The new delay value + 5 days // Minimum setback if reducing the delay + ); + + _delay = updatedDelay; + + // ... emit events + } + + // Get complete delay details including pending changes + function getDelayDetails() external view returns ( + uint32 currentValue, // The current delay value + uint32 pendingValue, // The pending delay value + uint48 effectTime // The timepoint when the pending delay change takes effect + ) { + return _delay.getFull(); + } +} +---- + +This pattern is used extensively in OpenZeppelin's xref:api:access.adoc#AccessManager[AccessManager] for implementing secure time-based access control. For example, when changing an admin delay: + +[source,solidity] +---- +// From AccessManager.sol +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); +} +---- diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/wizard.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/wizard.adoc new file mode 100644 index 0000000..ed416e2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/wizard.adoc @@ -0,0 +1,15 @@ += Contracts Wizard +:page-notoc: + +Not sure where to start? Use the interactive generator below to bootstrap your +contract and learn about the components offered in OpenZeppelin Contracts. + +TIP: Place the resulting contract in your `contracts` or `src` directory in order to compile it with a tool like Hardhat or Foundry. Consider reading our guide on xref:learn::developing-smart-contracts.adoc[Developing Smart Contracts] for more guidance! + +++++ + + + +++++ + + diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/contract.hbs b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/contract.hbs new file mode 100644 index 0000000..458b511 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/contract.hbs @@ -0,0 +1,141 @@ +{{#each items}} +:{{name}}: pass:normal[xref:#{{anchor}}[`++{{name}}++`]] +{{/each}} + +{{#each functions}} +:{{fullname}}: pass:normal[xref:#{{anchor}}[`++{{name}}++`]] +{{/each}} + +[.contract] +[[{{anchor}}]] +=== `++{{name}}++` link:https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v{{oz-version}}/{{__item_context.file.absolutePath}}[{github-icon},role=heading-link] + +[.hljs-theme-light.nopadding] +```solidity +import "@openzeppelin/{{__item_context.file.absolutePath}}"; +``` + +{{{natspec.dev}}} + +{{#if modifiers}} +[.contract-index] +.Modifiers +-- +{{#each modifiers}} +* {xref-{{anchor~}} }[`++{{name}}({{names params}})++`] +{{/each}} +-- +{{/if}} + +{{#if has-functions}} +[.contract-index] +.Functions +-- +{{#each inherited-functions}} +{{#unless @first}} +[.contract-subindex-inherited] +.{{contract.name}} +{{/unless}} +{{#each functions}} +* {xref-{{anchor~}} }[`++{{name}}({{names params}})++`] +{{/each}} + +{{/each}} +-- +{{/if}} + +{{#if has-events}} +[.contract-index] +.Events +-- +{{#each inheritance}} +{{#unless @first}} +[.contract-subindex-inherited] +.{{name}} +{{/unless}} +{{#each events}} +* {xref-{{anchor~}} }[`++{{name}}({{names params}})++`] +{{/each}} + +{{/each}} +-- +{{/if}} + +{{#if has-errors}} +[.contract-index] +.Errors +-- +{{#each inheritance}} +{{#unless @first}} +[.contract-subindex-inherited] +.{{name}} +{{/unless}} +{{#each errors}} +* {xref-{{anchor~}} }[`++{{name}}({{names params}})++`] +{{/each}} + +{{/each}} +-- +{{/if}} + +{{#if has-internal-variables}} +[.contract-index] +.Internal Variables +-- +{{#each inheritance}} +{{#unless @first}} +[.contract-subindex-inherited] +.{{name}} +{{/unless}} +{{#each internal-variables}} +* {xref-{{anchor~}} }[`++{{typeDescriptions.typeString}} {{#if constant}}constant{{/if}} {{name}}++`] +{{/each}} + +{{/each}} +-- +{{/if}} + +{{#each modifiers}} +[.contract-item] +[[{{anchor}}]] +==== `[.contract-item-name]#++{{name}}++#++({{typed-params params}})++` [.item-kind]#modifier# + +{{{natspec.dev}}} + +{{/each}} + +{{#each functions}} +[.contract-item] +[[{{anchor}}]] +==== `[.contract-item-name]#++{{name}}++#++({{typed-params params}}){{#if returns2}} → {{typed-params returns2}}{{/if}}++` [.item-kind]#{{visibility}}# + +{{{natspec.dev}}} + +{{/each}} + +{{#each events}} +[.contract-item] +[[{{anchor}}]] +==== `[.contract-item-name]#++{{name}}++#++({{typed-params params}})++` [.item-kind]#event# + +{{{natspec.dev}}} + +{{/each}} + +{{#each errors}} +[.contract-item] +[[{{anchor}}]] +==== `[.contract-item-name]#++{{name}}++#++({{typed-params params}})++` [.item-kind]#error# + +{{{natspec.dev}}} + +{{/each}} + +{{#each internal-variables}} +[.contract-item] +[[{{anchor}}]] +==== `{{typeDescriptions.typeString}} [.contract-item-name]#++{{name}}++#` [.item-kind]#internal{{#if constant}} constant{{/if}}# + +{{{natspec.dev}}} + +{{/each}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/helpers.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/helpers.js new file mode 100644 index 0000000..1b63835 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/helpers.js @@ -0,0 +1,46 @@ +const { version } = require('../../package.json'); + +module.exports['oz-version'] = () => version; + +module.exports['readme-path'] = opts => { + return 'contracts/' + opts.data.root.id.replace(/\.adoc$/, '') + '/README.adoc'; +}; + +module.exports.names = params => params?.map(p => p.name).join(', '); + +module.exports['typed-params'] = params => { + return params?.map(p => `${p.type}${p.indexed ? ' indexed' : ''}${p.name ? ' ' + p.name : ''}`).join(', '); +}; + +const slug = (module.exports.slug = str => { + if (str === undefined) { + throw new Error('Missing argument'); + } + return str.replace(/\W/g, '-'); +}); + +const linksCache = new WeakMap(); + +function getAllLinks(items) { + if (linksCache.has(items)) { + return linksCache.get(items); + } + const res = {}; + linksCache.set(items, res); + for (const item of items) { + res[`xref-${item.anchor}`] = `xref:${item.__item_context.page}#${item.anchor}`; + res[slug(item.fullName)] = `pass:normal[xref:${item.__item_context.page}#${item.anchor}[\`${item.fullName}\`]]`; + } + return res; +} + +module.exports['with-prelude'] = opts => { + const links = getAllLinks(opts.data.site.items); + const contents = opts.fn(); + const neededLinks = contents + .match(/\{[-._a-z0-9]+\}/gi) + .map(m => m.replace(/^\{(.+)\}$/, '$1')) + .filter(k => k in links); + const prelude = neededLinks.map(k => `:${k}: ${links[k]}`).join('\n'); + return prelude + '\n' + contents; +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/page.hbs b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/page.hbs new file mode 100644 index 0000000..cab050a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/page.hbs @@ -0,0 +1,4 @@ +:github-icon: pass:[] +{{#with-prelude}} +{{readme (readme-path)}} +{{/with-prelude}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/properties.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/properties.js new file mode 100644 index 0000000..8d6b286 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/properties.js @@ -0,0 +1,88 @@ +const { isNodeType, findAll } = require('solidity-ast/utils'); +const { slug } = require('./helpers'); + +module.exports.anchor = function anchor({ item, contract }) { + let res = ''; + if (contract) { + res += contract.name + '-'; + } + res += item.name; + if ('parameters' in item) { + const signature = item.parameters.parameters.map(v => v.typeName.typeDescriptions.typeString).join(','); + res += slug('(' + signature + ')'); + } + if (isNodeType('VariableDeclaration', item)) { + res += '-' + slug(item.typeName.typeDescriptions.typeString); + } + return res; +}; + +module.exports.fullname = function fullname({ item }) { + let res = ''; + res += item.name; + if ('parameters' in item) { + const signature = item.parameters.parameters.map(v => v.typeName.typeDescriptions.typeString).join(','); + res += slug('(' + signature + ')'); + } + if (isNodeType('VariableDeclaration', item)) { + res += '-' + slug(item.typeName.typeDescriptions.typeString); + } + if (res.charAt(res.length - 1) === '-') { + return res.slice(0, -1); + } + return res; +}; + +module.exports.inheritance = function ({ item, build }) { + if (!isNodeType('ContractDefinition', item)) { + throw new Error('used inherited-items on non-contract'); + } + + return item.linearizedBaseContracts + .map(id => build.deref('ContractDefinition', id)) + .filter((c, i) => c.name !== 'Context' || i === 0); +}; + +module.exports['has-functions'] = function ({ item }) { + return item.inheritance.some(c => c.functions.length > 0); +}; + +module.exports['has-events'] = function ({ item }) { + return item.inheritance.some(c => c.events.length > 0); +}; + +module.exports['has-errors'] = function ({ item }) { + return item.inheritance.some(c => c.errors.length > 0); +}; + +module.exports['internal-variables'] = function ({ item }) { + return item.variables.filter(({ visibility }) => visibility === 'internal'); +}; + +module.exports['has-internal-variables'] = function ({ item }) { + return module.exports['internal-variables']({ item }).length > 0; +}; + +module.exports.functions = function ({ item }) { + return [ + ...[...findAll('FunctionDefinition', item)].filter(f => f.visibility !== 'private'), + ...[...findAll('VariableDeclaration', item)].filter(f => f.visibility === 'public'), + ]; +}; + +module.exports.returns2 = function ({ item }) { + if (isNodeType('VariableDeclaration', item)) { + return [{ type: item.typeDescriptions.typeString }]; + } else { + return item.returns; + } +}; + +module.exports['inherited-functions'] = function ({ item }) { + const { inheritance } = item; + const baseFunctions = new Set(inheritance.flatMap(c => c.functions.flatMap(f => f.baseFunctions ?? []))); + return inheritance.map((contract, i) => ({ + contract, + functions: contract.functions.filter(f => !baseFunctions.has(f.id) && (f.name !== 'constructor' || i === 0)), + })); +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/eslint.config.mjs b/typescript/packages/account-modules/lib/openzeppelin-contracts/eslint.config.mjs new file mode 100644 index 0000000..00fcc95 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/eslint.config.mjs @@ -0,0 +1,26 @@ +import js from '@eslint/js'; +import { includeIgnoreFile } from '@eslint/compat'; +import prettier from 'eslint-config-prettier'; +import globals from 'globals'; +import path from 'path'; + +export default [ + js.configs.recommended, + prettier, + { + languageOptions: { + ecmaVersion: 2022, + globals: { + ...globals.browser, + ...globals.mocha, + ...globals.node, + artifacts: 'readonly', + contract: 'readonly', + web3: 'readonly', + extendEnvironment: 'readonly', + expect: 'readonly', + }, + }, + }, + includeIgnoreFile(path.resolve(import.meta.dirname, '.gitignore')), +]; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/foundry.toml b/typescript/packages/account-modules/lib/openzeppelin-contracts/foundry.toml new file mode 100644 index 0000000..ea8b1fa --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/foundry.toml @@ -0,0 +1,15 @@ +[profile.default] +solc_version = '0.8.27' +evm_version = 'prague' +optimizer = true +optimizer-runs = 200 +src = 'contracts' +out = 'out' +libs = ['node_modules', 'lib'] +test = 'test' +cache_path = 'cache_forge' +fs_permissions = [{ access = "read", path = "./test/bin" }] + +[fuzz] +runs = 5000 +max_test_rejects = 150000 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/fv-requirements.txt b/typescript/packages/account-modules/lib/openzeppelin-contracts/fv-requirements.txt new file mode 100644 index 0000000..0c2ef0e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/fv-requirements.txt @@ -0,0 +1,4 @@ +certora-cli==4.13.1 +# File uses a custom name (fv-requirements.txt) so that it isn't picked by Netlify's build +# whose latest Python version is 0.3.8, incompatible with most recent versions of Halmos +halmos==0.2.6 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat.config.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat.config.js new file mode 100644 index 0000000..8f326b5 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat.config.js @@ -0,0 +1,124 @@ +/// ENVVAR +// - COMPILER: compiler version (default: 0.8.27) +// - SRC: contracts folder to compile (default: contracts) +// - RUNS: number of optimization runs (default: 200) +// - IR: enable IR compilation (default: false) +// - COVERAGE: enable coverage report (default: false) +// - GAS: enable gas report (default: false) +// - COINMARKETCAP: coinmarketcap api key for USD value in gas report +// - CI: output gas report to file instead of stdout + +const fs = require('fs'); +const path = require('path'); + +const { argv } = require('yargs/yargs')() + .env('') + .options({ + // Compilation settings + compiler: { + alias: 'compileVersion', + type: 'string', + default: '0.8.27', + }, + src: { + alias: 'source', + type: 'string', + default: 'contracts', + }, + runs: { + alias: 'optimizationRuns', + type: 'number', + default: 200, + }, + ir: { + alias: 'enableIR', + type: 'boolean', + default: false, + }, + evm: { + alias: 'evmVersion', + type: 'string', + default: 'prague', + }, + // Extra modules + coverage: { + type: 'boolean', + default: false, + }, + gas: { + alias: 'enableGasReport', + type: 'boolean', + default: false, + }, + coinmarketcap: { + alias: 'coinmarketcapApiKey', + type: 'string', + }, + }); + +require('@nomicfoundation/hardhat-chai-matchers'); +require('@nomicfoundation/hardhat-ethers'); +require('hardhat-exposed'); +require('hardhat-gas-reporter'); +require('hardhat-ignore-warnings'); +require('solidity-coverage'); +require('solidity-docgen'); + +for (const f of fs.readdirSync(path.join(__dirname, 'hardhat'))) { + require(path.join(__dirname, 'hardhat', f)); +} + +/** + * @type import('hardhat/config').HardhatUserConfig + */ +module.exports = { + solidity: { + version: argv.compiler, + settings: { + optimizer: { + enabled: true, + runs: argv.runs, + }, + evmVersion: argv.evm, + viaIR: argv.ir, + outputSelection: { '*': { '*': ['storageLayout'] } }, + }, + }, + warnings: { + 'contracts-exposed/**/*': { + 'code-size': 'off', + 'initcode-size': 'off', + }, + '*': { + 'unused-param': !argv.coverage, // coverage causes unused-param warnings + 'transient-storage': false, + default: 'error', + }, + }, + networks: { + hardhat: { + hardfork: argv.evm, + // Exposed contracts often exceed the maximum contract size. For normal contract, + // we rely on the `code-size` compiler warning, that will cause a compilation error. + allowUnlimitedContractSize: true, + initialBaseFeePerGas: argv.coverage ? 0 : undefined, + enableRip7212: true, + }, + }, + exposed: { + imports: true, + initializers: true, + exclude: ['vendor/**/*', '**/*WithInit.sol'], + }, + gasReporter: { + enabled: argv.gas, + showMethodSig: true, + includeBytecodeInJSON: true, + currency: 'USD', + coinmarketcap: argv.coinmarketcap, + }, + paths: { + sources: argv.src, + }, + docgen: require('./docs/config'), +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/async-test-sanity.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/async-test-sanity.js new file mode 100644 index 0000000..8e60f70 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/async-test-sanity.js @@ -0,0 +1,10 @@ +process.on('unhandledRejection', reason => { + // If the reason is already an Error object, throw it directly to preserve the stack trace. + if (reason instanceof Error) { + throw reason; + } else { + // If the reason is not an Error (e.g., a string, number, or other primitive), + // create a new Error object with the reason as its message. + throw new Error(`Unhandled rejection: ${reason}`); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/common-contracts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/common-contracts.js new file mode 100644 index 0000000..67e44be --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/common-contracts.js @@ -0,0 +1,69 @@ +const { task } = require('hardhat/config'); +const { TASK_TEST_SETUP_TEST_ENVIRONMENT } = require('hardhat/builtin-tasks/task-names'); +const { setCode } = require('@nomicfoundation/hardhat-network-helpers'); + +const fs = require('fs'); +const path = require('path'); + +const INSTANCES = { + // ERC-4337 Entrypoints + entrypoint: { + v07: { + address: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', + abi: JSON.parse(fs.readFileSync(path.resolve(__dirname, '../test/bin/EntryPoint070.abi'), 'utf-8')), + bytecode: fs.readFileSync(path.resolve(__dirname, '../test/bin/EntryPoint070.bytecode'), 'hex'), + }, + v08: { + address: '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108', + abi: JSON.parse(fs.readFileSync(path.resolve(__dirname, '../test/bin/EntryPoint080.abi'), 'utf-8')), + bytecode: fs.readFileSync(path.resolve(__dirname, '../test/bin/EntryPoint080.bytecode'), 'hex'), + }, + }, + senderCreator: { + v07: { + address: '0xEFC2c1444eBCC4Db75e7613d20C6a62fF67A167C', + abi: JSON.parse(fs.readFileSync(path.resolve(__dirname, '../test/bin/SenderCreator070.abi'), 'utf-8')), + bytecode: fs.readFileSync(path.resolve(__dirname, '../test/bin/SenderCreator070.bytecode'), 'hex'), + }, + v08: { + address: '0x449ED7C3e6Fee6a97311d4b55475DF59C44AdD33', + abi: JSON.parse(fs.readFileSync(path.resolve(__dirname, '../test/bin/SenderCreator080.abi'), 'utf-8')), + bytecode: fs.readFileSync(path.resolve(__dirname, '../test/bin/SenderCreator080.bytecode'), 'hex'), + }, + }, + deployer: { + // Arachnid's deterministic deployment proxy + // See: https://github.com/Arachnid/deterministic-deployment-proxy/tree/master + arachnid: { + address: '0x4e59b44847b379578588920cA78FbF26c0B4956C', + abi: [], + bytecode: + '0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3', + }, + // Micah's deployer + micah: { + address: '0x7A0D94F55792C434d74a40883C6ed8545E406D12', + abi: [], + bytecode: '0x60003681823780368234f58015156014578182fd5b80825250506014600cf3', + }, + }, + eip2935: { + address: '0x0000F90827F1C53a10cb7A02335B175320002935', + abi: [], + bytecode: + '0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500', + }, +}; + +const setup = (input, ethers) => + input.address && input.abi && input.bytecode + ? setCode(input.address, '0x' + input.bytecode.replace(/0x/, '')).then(() => + ethers.getContractAt(input.abi, input.address), + ) + : Promise.all( + Object.entries(input).map(([name, entry]) => setup(entry, ethers).then(result => [name, result])), + ).then(Object.fromEntries); + +task(TASK_TEST_SETUP_TEST_ENVIRONMENT).setAction((_, env, runSuper) => + runSuper().then(() => setup(INSTANCES, env.ethers).then(result => Object.assign(env, result))), +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/env-artifacts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/env-artifacts.js new file mode 100644 index 0000000..e97ae64 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/env-artifacts.js @@ -0,0 +1,29 @@ +const { HardhatError } = require('hardhat/internal/core/errors'); + +function isExpectedError(e, suffix) { + // HH700: Artifact not found - from https://hardhat.org/hardhat-runner/docs/errors#HH700 + return HardhatError.isHardhatError(e) && e.number === 700 && suffix !== ''; +} + +// Modifies the artifact require functions 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(hre => { + const suffixes = ['UpgradeableWithInit', 'Upgradeable', '']; + + // Ethers + const originalReadArtifact = hre.artifacts.readArtifact; + hre.artifacts.readArtifact = async function (name) { + for (const suffix of suffixes) { + try { + return await originalReadArtifact.call(this, name + suffix); + } catch (e) { + if (isExpectedError(e, suffix)) { + continue; + } else { + throw e; + } + } + } + throw new Error('Unreachable'); + }; +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js new file mode 100644 index 0000000..eeacf0a --- /dev/null +++ b/typescript/packages/account-modules/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 coming 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/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/remappings.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/remappings.js new file mode 100644 index 0000000..cd9984d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/remappings.js @@ -0,0 +1,18 @@ +const fs = require('fs'); +const { task } = require('hardhat/config'); +const { TASK_COMPILE_GET_REMAPPINGS } = require('hardhat/builtin-tasks/task-names'); + +task(TASK_COMPILE_GET_REMAPPINGS).setAction((taskArgs, env, runSuper) => + runSuper().then(remappings => + Object.assign( + remappings, + Object.fromEntries( + fs + .readFileSync('remappings.txt', 'utf-8') + .split('\n') + .filter(Boolean) + .map(line => line.trim().split('=')), + ), + ), + ), +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js new file mode 100644 index 0000000..965ba37 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/task-test-get-files.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/task-test-get-files.js new file mode 100644 index 0000000..108f40a --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol new file mode 100644 index 0000000..c34512b --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol new file mode 100644 index 0000000..a26ad0d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol @@ -0,0 +1,356 @@ +// 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 test_withdraw_zero_allowance(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); + (bool success,) = _vault_.call( + abi.encodeWithSelector(IERC4626.withdraw.selector, assets, receiver, owner) + ); + assertFalse(success); + } + + // + // 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 test_redeem_zero_allowance(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); + (bool success,) = _vault_.call( + abi.encodeWithSelector(IERC4626.redeem.selector, shares, receiver, owner) + ); + assertFalse(success); + } + + // + // 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/README.md new file mode 100644 index 0000000..651e443 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitattributes b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitattributes new file mode 100644 index 0000000..27042d4 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitattributes @@ -0,0 +1 @@ +src/Vm.sol linguist-generated diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml new file mode 100644 index 0000000..2d68e91 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml @@ -0,0 +1,128 @@ +name: CI + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Foundry + uses: foundry-rs/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@v4 + + - name: Install Foundry + uses: foundry-rs/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@v4 + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + - name: Check formatting + run: forge fmt --check diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/sync.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/sync.yml new file mode 100644 index 0000000..9b170f0 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/sync.yml @@ -0,0 +1,31 @@ +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@v4 + with: + fetch-depth: 0 + ref: v1 + + # The email is derived from the bots user id, + # found here: https://api.github.com/users/github-actions%5Bbot%5D + - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitignore b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitignore new file mode 100644 index 0000000..756106d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitignore @@ -0,0 +1,4 @@ +cache/ +out/ +.vscode +.idea diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/CONTRIBUTING.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/CONTRIBUTING.md new file mode 100644 index 0000000..89b75f3 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/CONTRIBUTING.md @@ -0,0 +1,193 @@ +## Contributing to Foundry + +Thanks for your interest in improving Foundry! + +There are multiple opportunities to contribute at any level. It doesn't matter if you are just getting started with Rust or are the most weathered expert, we can use your help. + +This document will help you get started. **Do not let the document intimidate you**. +It should be considered as a guide to help you navigate the process. + +The [dev Telegram][dev-tg] is available for any concerns you may have that are not covered in this guide. + +### Code of Conduct + +The Foundry project adheres to the [Rust Code of Conduct][rust-coc]. This code of conduct describes the _minimum_ behavior expected from all contributors. + +Instances of violations of the Code of Conduct can be reported by contacting the team at [me@gakonst.com](mailto:me@gakonst.com). + +### Ways to contribute + +There are fundamentally four ways an individual can contribute: + +1. **By opening an issue:** For example, if you believe that you have uncovered a bug + in Foundry, creating a new issue in the issue tracker is the way to report it. +2. **By adding context:** Providing additional context to existing issues, + such as screenshots and code snippets, which help resolve issues. +3. **By resolving issues:** Typically this is done in the form of either + demonstrating that the issue reported is not a problem after all, or more often, + by opening a pull request that fixes the underlying problem, in a concrete and + reviewable manner. + +**Anybody can participate in any stage of contribution**. We urge you to participate in the discussion +around bugs and participate in reviewing PRs. + +### Contributions Related to Spelling and Grammar + +At this time, we will not be accepting contributions that only fix spelling or grammatical errors in documentation, code or +elsewhere. + +### Asking for help + +If you have reviewed existing documentation and still have questions, or you are having problems, you can get help in the following ways: + +- **Asking in the support Telegram:** The [Foundry Support Telegram][support-tg] is a fast and easy way to ask questions. +- **Opening a discussion:** This repository comes with a discussions board where you can also ask for help. Click the "Discussions" tab at the top. + +As Foundry is still in heavy development, the documentation can be a bit scattered. +The [Foundry Book][foundry-book] is our current best-effort attempt at keeping up-to-date information. + +### Submitting a bug report + +When filing a new bug report in the issue tracker, you will be presented with a basic form to fill out. + +If you believe that you have uncovered a bug, please fill out the form to the best of your ability. Do not worry if you cannot answer every detail; just fill in what you can. Contributors will ask follow-up questions if something is unclear. + +The most important pieces of information we need in a bug report are: + +- The Foundry version you are on (and that it is up to date) +- The platform you are on (Windows, macOS, an M1 Mac or Linux) +- Code snippets if this is happening in relation to testing or building code +- Concrete steps to reproduce the bug + +In order to rule out the possibility of the bug being in your project, the code snippets should be as minimal +as possible. It is better if you can reproduce the bug with a small snippet as opposed to an entire project! + +See [this guide][mcve] on how to create a minimal, complete, and verifiable example. + +### Submitting a feature request + +When adding a feature request in the issue tracker, you will be presented with a basic form to fill out. + +Please include as detailed of an explanation as possible of the feature you would like, adding additional context if necessary. + +If you have examples of other tools that have the feature you are requesting, please include them as well. + +### Resolving an issue + +Pull requests are the way concrete changes are made to the code, documentation, and dependencies of Foundry. + +Even minor pull requests, such as those fixing wording, are greatly appreciated. Before making a large change, it is usually +a good idea to first open an issue describing the change to solicit feedback and guidance. This will increase +the likelihood of the PR getting merged. + +Please make sure that the following commands pass if you have changed the code: + +```sh +forge fmt --check +forge test -vvv +``` + +To make sure your changes are compatible with all compiler version targets, run the following commands: + +```sh +forge build --skip test --use solc:0.6.2 +forge build --skip test --use solc:0.6.12 +forge build --skip test --use solc:0.7.0 +forge build --skip test --use solc:0.7.6 +forge build --skip test --use solc:0.8.0 +``` + +The CI will also ensure that the code is formatted correctly and that the tests are passing across all compiler version targets. + +#### Adding cheatcodes + +Please follow the guide outlined in the [cheatcodes](https://github.com/foundry-rs/foundry/blob/master/docs/dev/cheatcodes.md#adding-a-new-cheatcode) documentation of Foundry. + +When making modifications to the native cheatcodes or adding new ones, please make sure to run [`./scripts/vm.py`](./scripts/vm.py) to update the cheatcodes in the [`src/Vm.sol`](./src/Vm.sol) file. + +By default the script will automatically generate the cheatcodes from the [`cheatcodes.json`](https://raw.githubusercontent.com/foundry-rs/foundry/master/crates/cheatcodes/assets/cheatcodes.json) file but alternatively you can provide a path to a JSON file containing the Vm interface, as generated by Foundry, with the `--from` flag. + +```sh +./scripts/vm.py --from path/to/cheatcodes.json +``` + +It is possible that the resulting [`src/Vm.sol`](./src/Vm.sol) file will have some changes that are not directly related to your changes, this is not a problem. + +#### Commits + +It is a recommended best practice to keep your changes as logically grouped as possible within individual commits. There is no limit to the number of commits any single pull request may have, and many contributors find it easier to review changes that are split across multiple commits. + +That said, if you have a number of commits that are "checkpoints" and don't represent a single logical change, please squash those together. + +#### Opening the pull request + +From within GitHub, opening a new pull request will present you with a template that should be filled out. Please try your best at filling out the details, but feel free to skip parts if you're not sure what to put. + +#### Discuss and update + +You will probably get feedback or requests for changes to your pull request. +This is a big part of the submission process, so don't be discouraged! Some contributors may sign off on the pull request right away, others may have more detailed comments or feedback. +This is a necessary part of the process in order to evaluate whether the changes are correct and necessary. + +**Any community member can review a PR, so you might get conflicting feedback**. +Keep an eye out for comments from code owners to provide guidance on conflicting feedback. + +#### Reviewing pull requests + +**Any Foundry community member is welcome to review any pull request**. + +All contributors who choose to review and provide feedback on pull requests have a responsibility to both the project and individual making the contribution. Reviews and feedback must be helpful, insightful, and geared towards improving the contribution as opposed to simply blocking it. If there are reasons why you feel the PR should not be merged, explain what those are. Do not expect to be able to block a PR from advancing simply because you say "no" without giving an explanation. Be open to having your mind changed. Be open to working _with_ the contributor to make the pull request better. + +Reviews that are dismissive or disrespectful of the contributor or any other reviewers are strictly counter to the Code of Conduct. + +When reviewing a pull request, the primary goals are for the codebase to improve and for the person submitting the request to succeed. **Even if a pull request is not merged, the submitter should come away from the experience feeling like their effort was not unappreciated**. Every PR from a new contributor is an opportunity to grow the community. + +##### Review a bit at a time + +Do not overwhelm new contributors. + +It is tempting to micro-optimize and make everything about relative performance, perfect grammar, or exact style matches. Do not succumb to that temptation.. + +Focus first on the most significant aspects of the change: + +1. Does this change make sense for Foundry? +2. Does this change make Foundry better, even if only incrementally? +3. Are there clear bugs or larger scale issues that need attending? +4. Are the commit messages readable and correct? If it contains a breaking change, is it clear enough? + +Note that only **incremental** improvement is needed to land a PR. This means that the PR does not need to be perfect, only better than the status quo. Follow-up PRs may be opened to continue iterating. + +When changes are necessary, _request_ them, do not _demand_ them, and **do not assume that the submitter already knows how to add a test or run a benchmark**. + +Specific performance optimization techniques, coding styles and conventions change over time. The first impression you give to a new contributor never does. + +Nits (requests for small changes that are not essential) are fine, but try to avoid stalling the pull request. Most nits can typically be fixed by the Foundry maintainers merging the pull request, but they can also be an opportunity for the contributor to learn a bit more about the project. + +It is always good to clearly indicate nits when you comment, e.g.: `Nit: change foo() to bar(). But this is not blocking`. + +If your comments were addressed but were not folded after new commits, or if they proved to be mistaken, please, [hide them][hiding-a-comment] with the appropriate reason to keep the conversation flow concise and relevant. + +##### Be aware of the person behind the code + +Be aware that _how_ you communicate requests and reviews in your feedback can have a significant impact on the success of the pull request. Yes, we may merge a particular change that makes Foundry better, but the individual might just not want to have anything to do with Foundry ever again. The goal is not just having good code. + +##### Abandoned or stale pull requests + +If a pull request appears to be abandoned or stalled, it is polite to first check with the contributor to see if they intend to continue the work before checking if they would mind if you took it over (especially if it just has nits left). When doing so, it is courteous to give the original contributor credit for the work they started, either by preserving their name and e-mail address in the commit log, or by using the `Author: ` or `Co-authored-by: ` metadata tag in the commits. + +_Adapted from the [ethers-rs contributing guide](https://github.com/gakonst/ethers-rs/blob/master/CONTRIBUTING.md)_. + +### Releasing + +Releases are automatically done by the release workflow when a tag is pushed, however, these steps still need to be taken: + +1. Ensure that the versions in the relevant `Cargo.toml` files are up-to-date. +2. Update documentation links +3. Perform a final audit for breaking changes. + +[rust-coc]: https://github.com/rust-lang/rust/blob/master/CODE_OF_CONDUCT.md +[dev-tg]: https://t.me/foundry_rs +[foundry-book]: https://github.com/foundry-rs/foundry-book +[support-tg]: https://t.me/foundry_support +[mcve]: https://stackoverflow.com/help/mcve +[hiding-a-comment]: https://help.github.com/articles/managing-disruptive-comments/#hiding-a-comment \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE new file mode 100644 index 0000000..cf01a49 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT new file mode 100644 index 0000000..28f9830 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/README.md new file mode 100644 index 0000000..2674dec --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/README.md @@ -0,0 +1,266 @@ +# 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 { + 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 addresses 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 + +Contains various assertions. + +### `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); +``` + +## Contributing + +See our [contributing guidelines](./CONTRIBUTING.md). + +## Getting Help + +First, see if the answer to your question can be found in [book](https://book.getfoundry.sh). + +If the answer is not there: + +- Join the [support Telegram](https://t.me/foundry_support) to get help, or +- Open a [discussion](https://github.com/foundry-rs/foundry/discussions/new/choose) with your question, or +- Open an issue with [the bug](https://github.com/foundry-rs/foundry/issues/new/choose) + +If you want to contribute, or follow along with contributor discussion, you can use our [main telegram](https://t.me/foundry_rs) to chat with us about the development of Foundry! + +## License + +Forge Standard Library is offered under either [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE) license. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/foundry.toml b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/foundry.toml new file mode 100644 index 0000000..f09a028 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/foundry.toml @@ -0,0 +1,23 @@ +[profile.default] +fs_permissions = [{ access = "read-write", path = "./"}] +optimizer = true +optimizer_runs = 200 + +[rpc_endpoints] +# The RPC URLs are modified versions of the default for testing initialization. +mainnet = "https://eth-mainnet.alchemyapi.io/v2/WV407BEiBmjNJfKo9Uo_55u0z0ITyCOX" # Different API key. +optimism_sepolia = "https://sepolia.optimism.io/" # Adds a trailing slash. +arbitrum_one_sepolia = "https://sepolia-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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/package.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/package.json new file mode 100644 index 0000000..6011817 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/package.json @@ -0,0 +1,16 @@ +{ + "name": "forge-std", + "version": "1.9.6", + "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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/scripts/vm.py b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/scripts/vm.py new file mode 100755 index 0000000..3cd047d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/scripts/vm.py @@ -0,0 +1,646 @@ +#!/usr/bin/env python3 + +import argparse +import copy +import json +import re +import subprocess +from enum import Enum as PyEnum +from pathlib import Path +from typing import Callable +from urllib import request + +VoidFn = Callable[[], None] + +CHEATCODES_JSON_URL = "https://raw.githubusercontent.com/foundry-rs/foundry/master/crates/cheatcodes/assets/cheatcodes.json" +OUT_PATH = "src/Vm.sol" + +VM_SAFE_DOC = """\ +/// 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. +""" + +VM_DOC = """\ +/// 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. +""" + + +def main(): + parser = argparse.ArgumentParser( + description="Generate Vm.sol based on the cheatcodes json created by Foundry") + parser.add_argument( + "--from", + metavar="PATH", + dest="path", + required=False, + help="path to a json file containing the Vm interface, as generated by Foundry") + args = parser.parse_args() + json_str = request.urlopen(CHEATCODES_JSON_URL).read().decode("utf-8") if args.path is None else Path(args.path).read_text() + contract = Cheatcodes.from_json(json_str) + + ccs = contract.cheatcodes + ccs = list(filter(lambda cc: cc.status not in ["experimental", "internal"], ccs)) + ccs.sort(key=lambda cc: cc.func.id) + + safe = list(filter(lambda cc: cc.safety == "safe", ccs)) + safe.sort(key=CmpCheatcode) + unsafe = list(filter(lambda cc: cc.safety == "unsafe", ccs)) + unsafe.sort(key=CmpCheatcode) + assert len(safe) + len(unsafe) == len(ccs) + + prefix_with_group_headers(safe) + prefix_with_group_headers(unsafe) + + out = "" + + out += "// Automatically @generated by scripts/vm.py. Do not modify manually.\n\n" + + pp = CheatcodesPrinter( + spdx_identifier="MIT OR Apache-2.0", + solidity_requirement=">=0.6.2 <0.9.0", + abicoder_pragma=True, + ) + pp.p_prelude() + pp.prelude = False + out += pp.finish() + + out += "\n\n" + out += VM_SAFE_DOC + vm_safe = Cheatcodes( + # TODO: Custom errors were introduced in 0.8.4 + errors=[], # contract.errors + events=contract.events, + enums=contract.enums, + structs=contract.structs, + cheatcodes=safe, + ) + pp.p_contract(vm_safe, "VmSafe") + out += pp.finish() + + out += "\n\n" + out += VM_DOC + vm_unsafe = Cheatcodes( + errors=[], + events=[], + enums=[], + structs=[], + cheatcodes=unsafe, + ) + pp.p_contract(vm_unsafe, "Vm", "VmSafe") + out += pp.finish() + + # Compatibility with <0.8.0 + def memory_to_calldata(m: re.Match) -> str: + return " calldata " + m.group(1) + + out = re.sub(r" memory (.*returns)", memory_to_calldata, out) + + with open(OUT_PATH, "w") as f: + f.write(out) + + forge_fmt = ["forge", "fmt", OUT_PATH] + res = subprocess.run(forge_fmt) + assert res.returncode == 0, f"command failed: {forge_fmt}" + + print(f"Wrote to {OUT_PATH}") + + +class CmpCheatcode: + cheatcode: "Cheatcode" + + def __init__(self, cheatcode: "Cheatcode"): + self.cheatcode = cheatcode + + def __lt__(self, other: "CmpCheatcode") -> bool: + return cmp_cheatcode(self.cheatcode, other.cheatcode) < 0 + + def __eq__(self, other: "CmpCheatcode") -> bool: + return cmp_cheatcode(self.cheatcode, other.cheatcode) == 0 + + def __gt__(self, other: "CmpCheatcode") -> bool: + return cmp_cheatcode(self.cheatcode, other.cheatcode) > 0 + + +def cmp_cheatcode(a: "Cheatcode", b: "Cheatcode") -> int: + if a.group != b.group: + return -1 if a.group < b.group else 1 + if a.status != b.status: + return -1 if a.status < b.status else 1 + if a.safety != b.safety: + return -1 if a.safety < b.safety else 1 + if a.func.id != b.func.id: + return -1 if a.func.id < b.func.id else 1 + return 0 + + +# HACK: A way to add group header comments without having to modify printer code +def prefix_with_group_headers(cheats: list["Cheatcode"]): + s = set() + for i, cheat in enumerate(cheats): + if cheat.group in s: + continue + + s.add(cheat.group) + + c = copy.deepcopy(cheat) + c.func.description = "" + c.func.declaration = f"// ======== {group(c.group)} ========" + cheats.insert(i, c) + return cheats + + +def group(s: str) -> str: + if s == "evm": + return "EVM" + if s == "json": + return "JSON" + return s[0].upper() + s[1:] + + +class Visibility(PyEnum): + EXTERNAL: str = "external" + PUBLIC: str = "public" + INTERNAL: str = "internal" + PRIVATE: str = "private" + + def __str__(self): + return self.value + + +class Mutability(PyEnum): + PURE: str = "pure" + VIEW: str = "view" + NONE: str = "" + + def __str__(self): + return self.value + + +class Function: + id: str + description: str + declaration: str + visibility: Visibility + mutability: Mutability + signature: str + selector: str + selector_bytes: bytes + + def __init__( + self, + id: str, + description: str, + declaration: str, + visibility: Visibility, + mutability: Mutability, + signature: str, + selector: str, + selector_bytes: bytes, + ): + self.id = id + self.description = description + self.declaration = declaration + self.visibility = visibility + self.mutability = mutability + self.signature = signature + self.selector = selector + self.selector_bytes = selector_bytes + + @staticmethod + def from_dict(d: dict) -> "Function": + return Function( + d["id"], + d["description"], + d["declaration"], + Visibility(d["visibility"]), + Mutability(d["mutability"]), + d["signature"], + d["selector"], + bytes(d["selectorBytes"]), + ) + + +class Cheatcode: + func: Function + group: str + status: str + safety: str + + def __init__(self, func: Function, group: str, status: str, safety: str): + self.func = func + self.group = group + self.status = status + self.safety = safety + + @staticmethod + def from_dict(d: dict) -> "Cheatcode": + return Cheatcode( + Function.from_dict(d["func"]), + str(d["group"]), + str(d["status"]), + str(d["safety"]), + ) + + +class Error: + name: str + description: str + declaration: str + + def __init__(self, name: str, description: str, declaration: str): + self.name = name + self.description = description + self.declaration = declaration + + @staticmethod + def from_dict(d: dict) -> "Error": + return Error(**d) + + +class Event: + name: str + description: str + declaration: str + + def __init__(self, name: str, description: str, declaration: str): + self.name = name + self.description = description + self.declaration = declaration + + @staticmethod + def from_dict(d: dict) -> "Event": + return Event(**d) + + +class EnumVariant: + name: str + description: str + + def __init__(self, name: str, description: str): + self.name = name + self.description = description + + +class Enum: + name: str + description: str + variants: list[EnumVariant] + + def __init__(self, name: str, description: str, variants: list[EnumVariant]): + self.name = name + self.description = description + self.variants = variants + + @staticmethod + def from_dict(d: dict) -> "Enum": + return Enum( + d["name"], + d["description"], + list(map(lambda v: EnumVariant(**v), d["variants"])), + ) + + +class StructField: + name: str + ty: str + description: str + + def __init__(self, name: str, ty: str, description: str): + self.name = name + self.ty = ty + self.description = description + + +class Struct: + name: str + description: str + fields: list[StructField] + + def __init__(self, name: str, description: str, fields: list[StructField]): + self.name = name + self.description = description + self.fields = fields + + @staticmethod + def from_dict(d: dict) -> "Struct": + return Struct( + d["name"], + d["description"], + list(map(lambda f: StructField(**f), d["fields"])), + ) + + +class Cheatcodes: + errors: list[Error] + events: list[Event] + enums: list[Enum] + structs: list[Struct] + cheatcodes: list[Cheatcode] + + def __init__( + self, + errors: list[Error], + events: list[Event], + enums: list[Enum], + structs: list[Struct], + cheatcodes: list[Cheatcode], + ): + self.errors = errors + self.events = events + self.enums = enums + self.structs = structs + self.cheatcodes = cheatcodes + + @staticmethod + def from_dict(d: dict) -> "Cheatcodes": + return Cheatcodes( + errors=[Error.from_dict(e) for e in d["errors"]], + events=[Event.from_dict(e) for e in d["events"]], + enums=[Enum.from_dict(e) for e in d["enums"]], + structs=[Struct.from_dict(e) for e in d["structs"]], + cheatcodes=[Cheatcode.from_dict(e) for e in d["cheatcodes"]], + ) + + @staticmethod + def from_json(s) -> "Cheatcodes": + return Cheatcodes.from_dict(json.loads(s)) + + @staticmethod + def from_json_file(file_path: str) -> "Cheatcodes": + with open(file_path, "r") as f: + return Cheatcodes.from_dict(json.load(f)) + + +class Item(PyEnum): + ERROR: str = "error" + EVENT: str = "event" + ENUM: str = "enum" + STRUCT: str = "struct" + FUNCTION: str = "function" + + +class ItemOrder: + _list: list[Item] + + def __init__(self, list: list[Item]) -> None: + assert len(list) <= len(Item), "list must not contain more items than Item" + assert len(list) == len(set(list)), "list must not contain duplicates" + self._list = list + pass + + def get_list(self) -> list[Item]: + return self._list + + @staticmethod + def default() -> "ItemOrder": + return ItemOrder( + [ + Item.ERROR, + Item.EVENT, + Item.ENUM, + Item.STRUCT, + Item.FUNCTION, + ] + ) + + +class CheatcodesPrinter: + buffer: str + + prelude: bool + spdx_identifier: str + solidity_requirement: str + abicoder_v2: bool + + block_doc_style: bool + + indent_level: int + _indent_str: str + + nl_str: str + + items_order: ItemOrder + + def __init__( + self, + buffer: str = "", + prelude: bool = True, + spdx_identifier: str = "UNLICENSED", + solidity_requirement: str = "", + abicoder_pragma: bool = False, + block_doc_style: bool = False, + indent_level: int = 0, + indent_with: int | str = 4, + nl_str: str = "\n", + items_order: ItemOrder = ItemOrder.default(), + ): + self.prelude = prelude + self.spdx_identifier = spdx_identifier + self.solidity_requirement = solidity_requirement + self.abicoder_v2 = abicoder_pragma + self.block_doc_style = block_doc_style + self.buffer = buffer + self.indent_level = indent_level + self.nl_str = nl_str + + if isinstance(indent_with, int): + assert indent_with >= 0 + self._indent_str = " " * indent_with + elif isinstance(indent_with, str): + self._indent_str = indent_with + else: + assert False, "indent_with must be int or str" + + self.items_order = items_order + + def finish(self) -> str: + ret = self.buffer.rstrip() + self.buffer = "" + return ret + + def p_contract(self, contract: Cheatcodes, name: str, inherits: str = ""): + if self.prelude: + self.p_prelude(contract) + + self._p_str("interface ") + name = name.strip() + if name != "": + self._p_str(name) + self._p_str(" ") + if inherits != "": + self._p_str("is ") + self._p_str(inherits) + self._p_str(" ") + self._p_str("{") + self._p_nl() + self._with_indent(lambda: self._p_items(contract)) + self._p_str("}") + self._p_nl() + + def _p_items(self, contract: Cheatcodes): + for item in self.items_order.get_list(): + if item == Item.ERROR: + self.p_errors(contract.errors) + elif item == Item.EVENT: + self.p_events(contract.events) + elif item == Item.ENUM: + self.p_enums(contract.enums) + elif item == Item.STRUCT: + self.p_structs(contract.structs) + elif item == Item.FUNCTION: + self.p_functions(contract.cheatcodes) + else: + assert False, f"unknown item {item}" + + def p_prelude(self, contract: Cheatcodes | None = None): + self._p_str(f"// SPDX-License-Identifier: {self.spdx_identifier}") + self._p_nl() + + if self.solidity_requirement != "": + req = self.solidity_requirement + elif contract and len(contract.errors) > 0: + req = ">=0.8.4 <0.9.0" + else: + req = ">=0.6.0 <0.9.0" + self._p_str(f"pragma solidity {req};") + self._p_nl() + + if self.abicoder_v2: + self._p_str("pragma experimental ABIEncoderV2;") + self._p_nl() + + self._p_nl() + + def p_errors(self, errors: list[Error]): + for error in errors: + self._p_line(lambda: self.p_error(error)) + + def p_error(self, error: Error): + self._p_comment(error.description, doc=True) + self._p_line(lambda: self._p_str(error.declaration)) + + def p_events(self, events: list[Event]): + for event in events: + self._p_line(lambda: self.p_event(event)) + + def p_event(self, event: Event): + self._p_comment(event.description, doc=True) + self._p_line(lambda: self._p_str(event.declaration)) + + def p_enums(self, enums: list[Enum]): + for enum in enums: + self._p_line(lambda: self.p_enum(enum)) + + def p_enum(self, enum: Enum): + self._p_comment(enum.description, doc=True) + self._p_line(lambda: self._p_str(f"enum {enum.name} {{")) + self._with_indent(lambda: self.p_enum_variants(enum.variants)) + self._p_line(lambda: self._p_str("}")) + + def p_enum_variants(self, variants: list[EnumVariant]): + for i, variant in enumerate(variants): + self._p_indent() + self._p_comment(variant.description) + + self._p_indent() + self._p_str(variant.name) + if i < len(variants) - 1: + self._p_str(",") + self._p_nl() + + def p_structs(self, structs: list[Struct]): + for struct in structs: + self._p_line(lambda: self.p_struct(struct)) + + def p_struct(self, struct: Struct): + self._p_comment(struct.description, doc=True) + self._p_line(lambda: self._p_str(f"struct {struct.name} {{")) + self._with_indent(lambda: self.p_struct_fields(struct.fields)) + self._p_line(lambda: self._p_str("}")) + + def p_struct_fields(self, fields: list[StructField]): + for field in fields: + self._p_line(lambda: self.p_struct_field(field)) + + def p_struct_field(self, field: StructField): + self._p_comment(field.description) + self._p_indented(lambda: self._p_str(f"{field.ty} {field.name};")) + + def p_functions(self, cheatcodes: list[Cheatcode]): + for cheatcode in cheatcodes: + self._p_line(lambda: self.p_function(cheatcode.func)) + + def p_function(self, func: Function): + self._p_comment(func.description, doc=True) + self._p_line(lambda: self._p_str(func.declaration)) + + def _p_comment(self, s: str, doc: bool = False): + s = s.strip() + if s == "": + return + + s = map(lambda line: line.lstrip(), s.split("\n")) + if self.block_doc_style: + self._p_str("/*") + if doc: + self._p_str("*") + self._p_nl() + for line in s: + self._p_indent() + self._p_str(" ") + if doc: + self._p_str("* ") + self._p_str(line) + self._p_nl() + self._p_indent() + self._p_str(" */") + self._p_nl() + else: + first_line = True + for line in s: + if not first_line: + self._p_indent() + first_line = False + + if doc: + self._p_str("/// ") + else: + self._p_str("// ") + self._p_str(line) + self._p_nl() + + def _with_indent(self, f: VoidFn): + self._inc_indent() + f() + self._dec_indent() + + def _p_line(self, f: VoidFn): + self._p_indent() + f() + self._p_nl() + + def _p_indented(self, f: VoidFn): + self._p_indent() + f() + + def _p_indent(self): + for _ in range(self.indent_level): + self._p_str(self._indent_str) + + def _p_nl(self): + self._p_str(self.nl_str) + + def _p_str(self, txt: str): + self.buffer += txt + + def _inc_indent(self): + self.indent_level += 1 + + def _dec_indent(self): + self.indent_level -= 1 + + +if __name__ == "__main__": + main() diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Base.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Base.sol new file mode 100644 index 0000000..851ac0c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Script.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Script.sol new file mode 100644 index 0000000..94e75f6 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol new file mode 100644 index 0000000..857ecd5 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol @@ -0,0 +1,669 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; +pragma experimental ABIEncoderV2; + +import {Vm} from "./Vm.sol"; + +abstract contract StdAssertions { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + event log(string); + event logs(bytes); + + event log_address(address); + event log_bytes32(bytes32); + event log_int(int256); + event log_uint(uint256); + 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, int256 val, uint256 decimals); + event log_named_decimal_uint(string key, uint256 val, uint256 decimals); + event log_named_int(string key, int256 val); + event log_named_uint(string key, uint256 val); + event log_named_bytes(string key, bytes val); + event log_named_string(string key, string val); + + 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); + + bool private _failed; + + function failed() public view returns (bool) { + if (_failed) { + return _failed; + } else { + return vm.load(address(vm), bytes32("failed")) != bytes32(0); + } + } + + function fail() internal virtual { + vm.store(address(vm), bytes32("failed"), bytes32(uint256(1))); + _failed = true; + } + + function assertTrue(bool data) internal pure virtual { + vm.assertTrue(data); + } + + function assertTrue(bool data, string memory err) internal pure virtual { + vm.assertTrue(data, err); + } + + function assertFalse(bool data) internal pure virtual { + vm.assertFalse(data); + } + + function assertFalse(bool data, string memory err) internal pure virtual { + vm.assertFalse(data, err); + } + + function assertEq(bool left, bool right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bool left, bool right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(uint256 left, uint256 right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(uint256 left, uint256 right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertEqDecimal(left, right, decimals); + } + + function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertEqDecimal(left, right, decimals, err); + } + + function assertEq(int256 left, int256 right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(int256 left, int256 right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEqDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertEqDecimal(left, right, decimals); + } + + function assertEqDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertEqDecimal(left, right, decimals, err); + } + + function assertEq(address left, address right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(address left, address right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(bytes32 left, bytes32 right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bytes32 left, bytes32 right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq32(bytes32 left, bytes32 right) internal pure virtual { + assertEq(left, right); + } + + function assertEq32(bytes32 left, bytes32 right, string memory err) internal pure virtual { + assertEq(left, right, err); + } + + function assertEq(string memory left, string memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(string memory left, string memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(bytes memory left, bytes memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bytes memory left, bytes memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(bool[] memory left, bool[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bool[] memory left, bool[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(uint256[] memory left, uint256[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(uint256[] memory left, uint256[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(int256[] memory left, int256[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(int256[] memory left, int256[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(address[] memory left, address[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(address[] memory left, address[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(bytes32[] memory left, bytes32[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bytes32[] memory left, bytes32[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(string[] memory left, string[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(string[] memory left, string[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(bytes[] memory left, bytes[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bytes[] memory left, bytes[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + // Legacy helper + function assertEqUint(uint256 left, uint256 right) internal pure virtual { + assertEq(left, right); + } + + function assertNotEq(bool left, bool right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bool left, bool right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(uint256 left, uint256 right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(uint256 left, uint256 right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertNotEqDecimal(left, right, decimals); + } + + function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) + internal + pure + virtual + { + vm.assertNotEqDecimal(left, right, decimals, err); + } + + function assertNotEq(int256 left, int256 right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(int256 left, int256 right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertNotEqDecimal(left, right, decimals); + } + + function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertNotEqDecimal(left, right, decimals, err); + } + + function assertNotEq(address left, address right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(address left, address right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(bytes32 left, bytes32 right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bytes32 left, bytes32 right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq32(bytes32 left, bytes32 right) internal pure virtual { + assertNotEq(left, right); + } + + function assertNotEq32(bytes32 left, bytes32 right, string memory err) internal pure virtual { + assertNotEq(left, right, err); + } + + function assertNotEq(string memory left, string memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(string memory left, string memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(bytes memory left, bytes memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bytes memory left, bytes memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(bool[] memory left, bool[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bool[] memory left, bool[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(uint256[] memory left, uint256[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(uint256[] memory left, uint256[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(int256[] memory left, int256[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(int256[] memory left, int256[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(address[] memory left, address[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(address[] memory left, address[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(bytes32[] memory left, bytes32[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bytes32[] memory left, bytes32[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(string[] memory left, string[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(string[] memory left, string[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(bytes[] memory left, bytes[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bytes[] memory left, bytes[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertLt(uint256 left, uint256 right) internal pure virtual { + vm.assertLt(left, right); + } + + function assertLt(uint256 left, uint256 right, string memory err) internal pure virtual { + vm.assertLt(left, right, err); + } + + function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertLtDecimal(left, right, decimals); + } + + function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertLtDecimal(left, right, decimals, err); + } + + function assertLt(int256 left, int256 right) internal pure virtual { + vm.assertLt(left, right); + } + + function assertLt(int256 left, int256 right, string memory err) internal pure virtual { + vm.assertLt(left, right, err); + } + + function assertLtDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertLtDecimal(left, right, decimals); + } + + function assertLtDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertLtDecimal(left, right, decimals, err); + } + + function assertGt(uint256 left, uint256 right) internal pure virtual { + vm.assertGt(left, right); + } + + function assertGt(uint256 left, uint256 right, string memory err) internal pure virtual { + vm.assertGt(left, right, err); + } + + function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertGtDecimal(left, right, decimals); + } + + function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertGtDecimal(left, right, decimals, err); + } + + function assertGt(int256 left, int256 right) internal pure virtual { + vm.assertGt(left, right); + } + + function assertGt(int256 left, int256 right, string memory err) internal pure virtual { + vm.assertGt(left, right, err); + } + + function assertGtDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertGtDecimal(left, right, decimals); + } + + function assertGtDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertGtDecimal(left, right, decimals, err); + } + + function assertLe(uint256 left, uint256 right) internal pure virtual { + vm.assertLe(left, right); + } + + function assertLe(uint256 left, uint256 right, string memory err) internal pure virtual { + vm.assertLe(left, right, err); + } + + function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertLeDecimal(left, right, decimals); + } + + function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertLeDecimal(left, right, decimals, err); + } + + function assertLe(int256 left, int256 right) internal pure virtual { + vm.assertLe(left, right); + } + + function assertLe(int256 left, int256 right, string memory err) internal pure virtual { + vm.assertLe(left, right, err); + } + + function assertLeDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertLeDecimal(left, right, decimals); + } + + function assertLeDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertLeDecimal(left, right, decimals, err); + } + + function assertGe(uint256 left, uint256 right) internal pure virtual { + vm.assertGe(left, right); + } + + function assertGe(uint256 left, uint256 right, string memory err) internal pure virtual { + vm.assertGe(left, right, err); + } + + function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertGeDecimal(left, right, decimals); + } + + function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertGeDecimal(left, right, decimals, err); + } + + function assertGe(int256 left, int256 right) internal pure virtual { + vm.assertGe(left, right); + } + + function assertGe(int256 left, int256 right, string memory err) internal pure virtual { + vm.assertGe(left, right, err); + } + + function assertGeDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertGeDecimal(left, right, decimals); + } + + function assertGeDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertGeDecimal(left, right, decimals, err); + } + + function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) internal pure virtual { + vm.assertApproxEqAbs(left, right, maxDelta); + } + + function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string memory err) + internal + pure + virtual + { + vm.assertApproxEqAbs(left, right, maxDelta, err); + } + + function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) + internal + pure + virtual + { + vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals); + } + + function assertApproxEqAbsDecimal( + uint256 left, + uint256 right, + uint256 maxDelta, + uint256 decimals, + string memory err + ) internal pure virtual { + vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals, err); + } + + function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) internal pure virtual { + vm.assertApproxEqAbs(left, right, maxDelta); + } + + function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string memory err) internal pure virtual { + vm.assertApproxEqAbs(left, right, maxDelta, err); + } + + function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) + internal + pure + virtual + { + vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals); + } + + function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals, string memory err) + internal + pure + virtual + { + vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals, err); + } + + function assertApproxEqRel( + uint256 left, + uint256 right, + uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% + ) internal pure virtual { + vm.assertApproxEqRel(left, right, maxPercentDelta); + } + + function assertApproxEqRel( + uint256 left, + uint256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + string memory err + ) internal pure virtual { + vm.assertApproxEqRel(left, right, maxPercentDelta, err); + } + + function assertApproxEqRelDecimal( + uint256 left, + uint256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals + ) internal pure virtual { + vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals); + } + + function assertApproxEqRelDecimal( + uint256 left, + uint256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals, + string memory err + ) internal pure virtual { + vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals, err); + } + + function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) internal pure virtual { + vm.assertApproxEqRel(left, right, maxPercentDelta); + } + + function assertApproxEqRel( + int256 left, + int256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + string memory err + ) internal pure virtual { + vm.assertApproxEqRel(left, right, maxPercentDelta, err); + } + + function assertApproxEqRelDecimal( + int256 left, + int256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals + ) internal pure virtual { + vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals); + } + + function assertApproxEqRelDecimal( + int256 left, + int256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals, + string memory err + ) internal pure virtual { + vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals, err); + } + + // Inherited from DSTest, not used but kept for backwards-compatibility + function checkEq0(bytes memory left, bytes memory right) internal pure returns (bool) { + return keccak256(left) == keccak256(right); + } + + function assertEq0(bytes memory left, bytes memory right) internal pure virtual { + assertEq(left, right); + } + + function assertEq0(bytes memory left, bytes memory right, string memory err) internal pure virtual { + assertEq(left, right, err); + } + + function assertNotEq0(bytes memory left, bytes memory right) internal pure virtual { + assertNotEq(left, right); + } + + function assertNotEq0(bytes memory left, bytes memory right, string memory err) internal pure virtual { + assertNotEq(left, right, err); + } + + 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); + revert("assertion failed"); + } + + 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); + revert("assertion failed"); + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol new file mode 100644 index 0000000..964cdbe --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol @@ -0,0 +1,287 @@ +// 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 + 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) { + 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' + // The upstream error thrown by forge for failing cheats changed so we check both the old and new versions + bytes memory oldNotFoundError = + abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias))); + bytes memory newNotFoundError = abi.encodeWithSignature( + "CheatcodeError(string)", string(abi.encodePacked("invalid rpc url: ", chainAlias)) + ); + bytes32 errHash = keccak256(err); + if ( + (errHash != keccak256(oldNotFoundError) && errHash != keccak256(newNotFoundError)) + || 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 `test_Rpcs` in `StdChains.t.sol` + setChainWithDefaultRpcUrl("anvil", ChainData("Anvil", 31337, "http://127.0.0.1:8545")); + setChainWithDefaultRpcUrl( + "mainnet", ChainData("Mainnet", 1, "https://eth-mainnet.alchemyapi.io/v2/pwc5rmJhrdoaSEfimoKEmsvOjKSmPDrP") + ); + setChainWithDefaultRpcUrl( + "sepolia", ChainData("Sepolia", 11155111, "https://sepolia.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001") + ); + setChainWithDefaultRpcUrl("holesky", ChainData("Holesky", 17000, "https://rpc.holesky.ethpandaops.io")); + setChainWithDefaultRpcUrl("optimism", ChainData("Optimism", 10, "https://mainnet.optimism.io")); + setChainWithDefaultRpcUrl( + "optimism_sepolia", ChainData("Optimism Sepolia", 11155420, "https://sepolia.optimism.io") + ); + setChainWithDefaultRpcUrl("arbitrum_one", ChainData("Arbitrum One", 42161, "https://arb1.arbitrum.io/rpc")); + setChainWithDefaultRpcUrl( + "arbitrum_one_sepolia", ChainData("Arbitrum One Sepolia", 421614, "https://sepolia-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_amoy", ChainData("Polygon Amoy", 80002, "https://rpc-amoy.polygon.technology") + ); + 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_sepolia", ChainData("Base Sepolia", 84532, "https://sepolia.base.org")); + setChainWithDefaultRpcUrl("base", ChainData("Base", 8453, "https://mainnet.base.org")); + setChainWithDefaultRpcUrl("blast_sepolia", ChainData("Blast Sepolia", 168587773, "https://sepolia.blast.io")); + setChainWithDefaultRpcUrl("blast", ChainData("Blast", 81457, "https://rpc.blast.io")); + setChainWithDefaultRpcUrl("fantom_opera", ChainData("Fantom Opera", 250, "https://rpc.ankr.com/fantom/")); + setChainWithDefaultRpcUrl( + "fantom_opera_testnet", ChainData("Fantom Opera Testnet", 4002, "https://rpc.ankr.com/fantom_testnet/") + ); + setChainWithDefaultRpcUrl("fraxtal", ChainData("Fraxtal", 252, "https://rpc.frax.com")); + setChainWithDefaultRpcUrl("fraxtal_testnet", ChainData("Fraxtal Testnet", 2522, "https://rpc.testnet.frax.com")); + setChainWithDefaultRpcUrl( + "berachain_bartio_testnet", ChainData("Berachain bArtio Testnet", 80084, "https://bartio.rpc.berachain.com") + ); + setChainWithDefaultRpcUrl("flare", ChainData("Flare", 14, "https://flare-api.flare.network/ext/C/rpc")); + setChainWithDefaultRpcUrl( + "flare_coston2", ChainData("Flare Coston2", 114, "https://coston2-api.flare.network/ext/C/rpc") + ); + + setChainWithDefaultRpcUrl("mode", ChainData("Mode", 34443, "https://mode.drpc.org")); + setChainWithDefaultRpcUrl("mode_sepolia", ChainData("Mode Sepolia", 919, "https://sepolia.mode.network")); + + setChainWithDefaultRpcUrl("zora", ChainData("Zora", 7777777, "https://zora.drpc.org")); + setChainWithDefaultRpcUrl( + "zora_sepolia", ChainData("Zora Sepolia", 999999999, "https://sepolia.rpc.zora.energy") + ); + + setChainWithDefaultRpcUrl("race", ChainData("Race", 6805, "https://racemainnet.io")); + setChainWithDefaultRpcUrl("race_sepolia", ChainData("Race Sepolia", 6806, "https://racemainnet.io")); + + setChainWithDefaultRpcUrl("metal", ChainData("Metal", 1750, "https://metall2.drpc.org")); + setChainWithDefaultRpcUrl("metal_sepolia", ChainData("Metal Sepolia", 1740, "https://testnet.rpc.metall2.com")); + + setChainWithDefaultRpcUrl("binary", ChainData("Binary", 624, "https://rpc.zero.thebinaryholdings.com")); + setChainWithDefaultRpcUrl( + "binary_sepolia", ChainData("Binary Sepolia", 625, "https://rpc.zero.thebinaryholdings.com") + ); + + setChainWithDefaultRpcUrl("orderly", ChainData("Orderly", 291, "https://rpc.orderly.network")); + setChainWithDefaultRpcUrl( + "orderly_sepolia", ChainData("Orderly Sepolia", 4460, "https://testnet-rpc.orderly.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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol new file mode 100644 index 0000000..9f360de --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol @@ -0,0 +1,829 @@ +// 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 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 are reserved by Ethereum and may be on all EVM-compatible chains. + vm.assume(addr < address(0x1) || addr > address(0xff)); + + // 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 assumeUnusedAddress(address addr) internal view virtual { + uint256 size; + assembly { + size := extcodesize(addr) + } + vm.assume(size == 0); + + assumeNotPrecompile(addr); + assumeNotZeroAddress(addr); + assumeNotForgeAddress(addr); + } + + 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(vm.getBlockTimestamp() + time); + } + + function rewind(uint256 time) internal virtual { + vm.warp(vm.getBlockTimestamp() - 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_StdCheats("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_StdCheats(string memory p0) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string)", p0)); + status; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol new file mode 100644 index 0000000..a302191 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdInvariant.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdInvariant.sol new file mode 100644 index 0000000..056db98 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdInvariant.sol @@ -0,0 +1,122 @@ +// 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 FuzzArtifactSelector { + string artifact; + 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; + + FuzzArtifactSelector[] private _targetedArtifactSelectors; + + FuzzSelector[] private _excludedSelectors; + 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 excludeSelector(FuzzSelector memory newExcludedSelector_) internal { + _excludedSelectors.push(newExcludedSelector_); + } + + 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(FuzzArtifactSelector 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 excludeSelectors() public view returns (FuzzSelector[] memory excludedSelectors_) { + excludedSelectors_ = _excludedSelectors; + } + + 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 (FuzzArtifactSelector[] 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol new file mode 100644 index 0000000..2a033c0 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol @@ -0,0 +1,283 @@ +// 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(""); +// json.readUint(""); +// ``` +// To write: +// ``` +// using stdJson for string; +// string memory json = "json"; +// json.serialize("a", uint256(123)); +// string memory semiFinal = json.serialize("b", string("test")); +// string memory finalJson = json.serialize("c", semiFinal); +// finalJson.write(""); +// ``` + +library stdJson { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function keyExists(string memory json, string memory key) internal view returns (bool) { + return vm.keyExistsJson(json, key); + } + + 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 readUintOr(string memory json, string memory key, uint256 defaultValue) internal view returns (uint256) { + return keyExists(json, key) ? readUint(json, key) : defaultValue; + } + + function readUintArrayOr(string memory json, string memory key, uint256[] memory defaultValue) + internal + view + returns (uint256[] memory) + { + return keyExists(json, key) ? readUintArray(json, key) : defaultValue; + } + + function readIntOr(string memory json, string memory key, int256 defaultValue) internal view returns (int256) { + return keyExists(json, key) ? readInt(json, key) : defaultValue; + } + + function readIntArrayOr(string memory json, string memory key, int256[] memory defaultValue) + internal + view + returns (int256[] memory) + { + return keyExists(json, key) ? readIntArray(json, key) : defaultValue; + } + + function readBytes32Or(string memory json, string memory key, bytes32 defaultValue) + internal + view + returns (bytes32) + { + return keyExists(json, key) ? readBytes32(json, key) : defaultValue; + } + + function readBytes32ArrayOr(string memory json, string memory key, bytes32[] memory defaultValue) + internal + view + returns (bytes32[] memory) + { + return keyExists(json, key) ? readBytes32Array(json, key) : defaultValue; + } + + function readStringOr(string memory json, string memory key, string memory defaultValue) + internal + view + returns (string memory) + { + return keyExists(json, key) ? readString(json, key) : defaultValue; + } + + function readStringArrayOr(string memory json, string memory key, string[] memory defaultValue) + internal + view + returns (string[] memory) + { + return keyExists(json, key) ? readStringArray(json, key) : defaultValue; + } + + function readAddressOr(string memory json, string memory key, address defaultValue) + internal + view + returns (address) + { + return keyExists(json, key) ? readAddress(json, key) : defaultValue; + } + + function readAddressArrayOr(string memory json, string memory key, address[] memory defaultValue) + internal + view + returns (address[] memory) + { + return keyExists(json, key) ? readAddressArray(json, key) : defaultValue; + } + + function readBoolOr(string memory json, string memory key, bool defaultValue) internal view returns (bool) { + return keyExists(json, key) ? readBool(json, key) : defaultValue; + } + + function readBoolArrayOr(string memory json, string memory key, bool[] memory defaultValue) + internal + view + returns (bool[] memory) + { + return keyExists(json, key) ? readBoolArray(json, key) : defaultValue; + } + + function readBytesOr(string memory json, string memory key, bytes memory defaultValue) + internal + view + returns (bytes memory) + { + return keyExists(json, key) ? readBytes(json, key) : defaultValue; + } + + function readBytesArrayOr(string memory json, string memory key, bytes[] memory defaultValue) + internal + view + returns (bytes[] memory) + { + return keyExists(json, key) ? readBytesArray(json, key) : defaultValue; + } + + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol new file mode 100644 index 0000000..459523b --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol new file mode 100644 index 0000000..bf3223d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {Vm} from "./Vm.sol"; + +struct FindData { + uint256 slot; + uint256 offsetLeft; + uint256 offsetRight; + bool found; +} + +struct StdStorage { + mapping(address => mapping(bytes4 => mapping(bytes32 => FindData))) finds; + bytes32[] _keys; + bytes4 _sig; + uint256 _depth; + address _target; + bytes32 _set; + bool _enable_packed_slots; + bytes _calldata; +} + +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"))))); + uint256 constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return bytes4(keccak256(bytes(sigStr))); + } + + function getCallParams(StdStorage storage self) internal view returns (bytes memory) { + if (self._calldata.length == 0) { + return flatten(self._keys); + } else { + return self._calldata; + } + } + + // Calls target contract with configured parameters + function callTarget(StdStorage storage self) internal view returns (bool, bytes32) { + bytes memory cald = abi.encodePacked(self._sig, getCallParams(self)); + (bool success, bytes memory rdat) = self._target.staticcall(cald); + bytes32 result = bytesToBytes32(rdat, 32 * self._depth); + + return (success, result); + } + + // Tries mutating slot value to determine if the targeted value is stored in it. + // If current value is 0, then we are setting slot value to type(uint256).max + // Otherwise, we set it to 0. That way, return value should always be affected. + function checkSlotMutatesCall(StdStorage storage self, bytes32 slot) internal returns (bool) { + bytes32 prevSlotValue = vm.load(self._target, slot); + (bool success, bytes32 prevReturnValue) = callTarget(self); + + bytes32 testVal = prevReturnValue == bytes32(0) ? bytes32(UINT256_MAX) : bytes32(0); + vm.store(self._target, slot, testVal); + + (, bytes32 newReturnValue) = callTarget(self); + + vm.store(self._target, slot, prevSlotValue); + + return (success && (prevReturnValue != newReturnValue)); + } + + // Tries setting one of the bits in slot to 1 until return value changes. + // Index of resulted bit is an offset packed slot has from left/right side + function findOffset(StdStorage storage self, bytes32 slot, bool left) internal returns (bool, uint256) { + for (uint256 offset = 0; offset < 256; offset++) { + uint256 valueToPut = left ? (1 << (255 - offset)) : (1 << offset); + vm.store(self._target, slot, bytes32(valueToPut)); + + (bool success, bytes32 data) = callTarget(self); + + if (success && (uint256(data) > 0)) { + return (true, offset); + } + } + return (false, 0); + } + + function findOffsets(StdStorage storage self, bytes32 slot) internal returns (bool, uint256, uint256) { + bytes32 prevSlotValue = vm.load(self._target, slot); + + (bool foundLeft, uint256 offsetLeft) = findOffset(self, slot, true); + (bool foundRight, uint256 offsetRight) = findOffset(self, slot, false); + + // `findOffset` may mutate slot value, so we are setting it to initial value + vm.store(self._target, slot, prevSlotValue); + return (foundLeft && foundRight, offsetLeft, offsetRight); + } + + function find(StdStorage storage self) internal returns (FindData storage) { + return find(self, true); + } + + /// @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, bool _clear) internal returns (FindData storage) { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes memory params = getCallParams(self); + + // calldata to test against + if (self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found) { + if (_clear) { + clear(self); + } + return self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))]; + } + vm.record(); + (, bytes32 callResult) = callTarget(self); + (bytes32[] memory reads,) = vm.accesses(address(who)); + + if (reads.length == 0) { + revert("stdStorage find(StdStorage): No storage use detected for target."); + } else { + for (uint256 i = reads.length; --i >= 0;) { + bytes32 prev = vm.load(who, reads[i]); + if (prev == bytes32(0)) { + emit WARNING_UninitedSlot(who, uint256(reads[i])); + } + + if (!checkSlotMutatesCall(self, reads[i])) { + continue; + } + + (uint256 offsetLeft, uint256 offsetRight) = (0, 0); + + if (self._enable_packed_slots) { + bool found; + (found, offsetLeft, offsetRight) = findOffsets(self, reads[i]); + if (!found) { + continue; + } + } + + // Check that value between found offsets is equal to the current call result + uint256 curVal = (uint256(prev) & getMaskByOffsets(offsetLeft, offsetRight)) >> offsetRight; + + if (uint256(callResult) != curVal) { + continue; + } + + emit SlotFound(who, fsig, keccak256(abi.encodePacked(params, field_depth)), uint256(reads[i])); + self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))] = + FindData(uint256(reads[i]), offsetLeft, offsetRight, true); + break; + } + } + + require( + self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found, + "stdStorage find(StdStorage): Slot(s) not found." + ); + + if (_clear) { + clear(self); + } + return self.finds[who][fsig][keccak256(abi.encodePacked(params, 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_calldata(StdStorage storage self, bytes memory _calldata) internal returns (StdStorage storage) { + self._calldata = _calldata; + 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 enable_packed_slots(StdStorage storage self) internal returns (StdStorage storage) { + self._enable_packed_slots = true; + 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) { + FindData storage data = find(self, false); + uint256 mask = getMaskByOffsets(data.offsetLeft, data.offsetRight); + uint256 value = (uint256(vm.load(self._target, bytes32(data.slot))) & mask) >> data.offsetRight; + clear(self); + return abi.encode(value); + } + + 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, true).slot - 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, true).slot - 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; + } + + function clear(StdStorage storage self) internal { + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + delete self._enable_packed_slots; + delete self._calldata; + } + + // Returns mask which contains non-zero bits for values between `offsetLeft` and `offsetRight` + // (slotValue & mask) >> offsetRight will be the value of the given packed variable + function getMaskByOffsets(uint256 offsetLeft, uint256 offsetRight) internal pure returns (uint256 mask) { + // mask = ((1 << (256 - (offsetRight + offsetLeft))) - 1) << offsetRight; + // using assembly because (1 << 256) causes overflow + assembly { + mask := shl(offsetRight, sub(shl(sub(256, add(offsetRight, offsetLeft)), 1), 1)) + } + } + + // Returns slot value with updated packed variable. + function getUpdatedSlotValue(bytes32 curValue, uint256 varValue, uint256 offsetLeft, uint256 offsetRight) + internal + pure + returns (bytes32 newValue) + { + return bytes32((uint256(curValue) & ~getMaskByOffsets(offsetLeft, offsetRight)) | (varValue << offsetRight)); + } +} + +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 find(self, true); + } + + function find(StdStorage storage self, bool _clear) internal returns (uint256) { + return stdStorageSafe.find(self, _clear).slot; + } + + 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 with_calldata(StdStorage storage self, bytes memory _calldata) internal returns (StdStorage storage) { + return stdStorageSafe.with_calldata(self, _calldata); + } + + function enable_packed_slots(StdStorage storage self) internal returns (StdStorage storage) { + return stdStorageSafe.enable_packed_slots(self); + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + return stdStorageSafe.depth(self, _depth); + } + + function clear(StdStorage storage self) internal { + stdStorageSafe.clear(self); + } + + 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; + bytes memory params = stdStorageSafe.getCallParams(self); + + if (!self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found) { + find(self, false); + } + FindData storage data = self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))]; + if ((data.offsetLeft + data.offsetRight) > 0) { + uint256 maxVal = 2 ** (256 - (data.offsetLeft + data.offsetRight)); + require( + uint256(set) < maxVal, + string( + abi.encodePacked( + "stdStorage find(StdStorage): Packed slot. We can't fit value greater than ", + vm.toString(maxVal) + ) + ) + ); + } + bytes32 curVal = vm.load(who, bytes32(data.slot)); + bytes32 valToSet = stdStorageSafe.getUpdatedSlotValue(curVal, uint256(set), data.offsetLeft, data.offsetRight); + + vm.store(who, bytes32(data.slot), valToSet); + + (bool success, bytes32 callResult) = stdStorageSafe.callTarget(self); + + if (!success || callResult != set) { + vm.store(who, bytes32(data.slot), curVal); + revert("stdStorage find(StdStorage): Failed to write value."); + } + clear(self); + } + + 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); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStyle.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStyle.sol new file mode 100644 index 0000000..d371e0c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdToml.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdToml.sol new file mode 100644 index 0000000..7ad3be2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdToml.sol @@ -0,0 +1,283 @@ +// 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 TOML files +// To parse: +// ``` +// using stdToml for string; +// string memory toml = vm.readFile(""); +// toml.readUint(""); +// ``` +// To write: +// ``` +// using stdToml for string; +// string memory json = "json"; +// json.serialize("a", uint256(123)); +// string memory semiFinal = json.serialize("b", string("test")); +// string memory finalJson = json.serialize("c", semiFinal); +// finalJson.write(""); +// ``` + +library stdToml { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function keyExists(string memory toml, string memory key) internal view returns (bool) { + return vm.keyExistsToml(toml, key); + } + + function parseRaw(string memory toml, string memory key) internal pure returns (bytes memory) { + return vm.parseToml(toml, key); + } + + function readUint(string memory toml, string memory key) internal pure returns (uint256) { + return vm.parseTomlUint(toml, key); + } + + function readUintArray(string memory toml, string memory key) internal pure returns (uint256[] memory) { + return vm.parseTomlUintArray(toml, key); + } + + function readInt(string memory toml, string memory key) internal pure returns (int256) { + return vm.parseTomlInt(toml, key); + } + + function readIntArray(string memory toml, string memory key) internal pure returns (int256[] memory) { + return vm.parseTomlIntArray(toml, key); + } + + function readBytes32(string memory toml, string memory key) internal pure returns (bytes32) { + return vm.parseTomlBytes32(toml, key); + } + + function readBytes32Array(string memory toml, string memory key) internal pure returns (bytes32[] memory) { + return vm.parseTomlBytes32Array(toml, key); + } + + function readString(string memory toml, string memory key) internal pure returns (string memory) { + return vm.parseTomlString(toml, key); + } + + function readStringArray(string memory toml, string memory key) internal pure returns (string[] memory) { + return vm.parseTomlStringArray(toml, key); + } + + function readAddress(string memory toml, string memory key) internal pure returns (address) { + return vm.parseTomlAddress(toml, key); + } + + function readAddressArray(string memory toml, string memory key) internal pure returns (address[] memory) { + return vm.parseTomlAddressArray(toml, key); + } + + function readBool(string memory toml, string memory key) internal pure returns (bool) { + return vm.parseTomlBool(toml, key); + } + + function readBoolArray(string memory toml, string memory key) internal pure returns (bool[] memory) { + return vm.parseTomlBoolArray(toml, key); + } + + function readBytes(string memory toml, string memory key) internal pure returns (bytes memory) { + return vm.parseTomlBytes(toml, key); + } + + function readBytesArray(string memory toml, string memory key) internal pure returns (bytes[] memory) { + return vm.parseTomlBytesArray(toml, key); + } + + function readUintOr(string memory toml, string memory key, uint256 defaultValue) internal view returns (uint256) { + return keyExists(toml, key) ? readUint(toml, key) : defaultValue; + } + + function readUintArrayOr(string memory toml, string memory key, uint256[] memory defaultValue) + internal + view + returns (uint256[] memory) + { + return keyExists(toml, key) ? readUintArray(toml, key) : defaultValue; + } + + function readIntOr(string memory toml, string memory key, int256 defaultValue) internal view returns (int256) { + return keyExists(toml, key) ? readInt(toml, key) : defaultValue; + } + + function readIntArrayOr(string memory toml, string memory key, int256[] memory defaultValue) + internal + view + returns (int256[] memory) + { + return keyExists(toml, key) ? readIntArray(toml, key) : defaultValue; + } + + function readBytes32Or(string memory toml, string memory key, bytes32 defaultValue) + internal + view + returns (bytes32) + { + return keyExists(toml, key) ? readBytes32(toml, key) : defaultValue; + } + + function readBytes32ArrayOr(string memory toml, string memory key, bytes32[] memory defaultValue) + internal + view + returns (bytes32[] memory) + { + return keyExists(toml, key) ? readBytes32Array(toml, key) : defaultValue; + } + + function readStringOr(string memory toml, string memory key, string memory defaultValue) + internal + view + returns (string memory) + { + return keyExists(toml, key) ? readString(toml, key) : defaultValue; + } + + function readStringArrayOr(string memory toml, string memory key, string[] memory defaultValue) + internal + view + returns (string[] memory) + { + return keyExists(toml, key) ? readStringArray(toml, key) : defaultValue; + } + + function readAddressOr(string memory toml, string memory key, address defaultValue) + internal + view + returns (address) + { + return keyExists(toml, key) ? readAddress(toml, key) : defaultValue; + } + + function readAddressArrayOr(string memory toml, string memory key, address[] memory defaultValue) + internal + view + returns (address[] memory) + { + return keyExists(toml, key) ? readAddressArray(toml, key) : defaultValue; + } + + function readBoolOr(string memory toml, string memory key, bool defaultValue) internal view returns (bool) { + return keyExists(toml, key) ? readBool(toml, key) : defaultValue; + } + + function readBoolArrayOr(string memory toml, string memory key, bool[] memory defaultValue) + internal + view + returns (bool[] memory) + { + return keyExists(toml, key) ? readBoolArray(toml, key) : defaultValue; + } + + function readBytesOr(string memory toml, string memory key, bytes memory defaultValue) + internal + view + returns (bytes memory) + { + return keyExists(toml, key) ? readBytes(toml, key) : defaultValue; + } + + function readBytesArrayOr(string memory toml, string memory key, bytes[] memory defaultValue) + internal + view + returns (bytes[] memory) + { + return keyExists(toml, key) ? readBytesArray(toml, key) : defaultValue; + } + + 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.writeToml(jsonKey, path); + } + + function write(string memory jsonKey, string memory path, string memory valueKey) internal { + vm.writeToml(jsonKey, path, valueKey); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol new file mode 100644 index 0000000..7106960 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol @@ -0,0 +1,209 @@ +// 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 pure virtual returns (uint256 result) { + result = _bound(x, min, max); + console2_log_StdUtils("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 pure virtual returns (int256 result) { + result = _bound(x, min, max); + console2_log_StdUtils("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) { + console2_log_StdUtils("computeCreateAddress is deprecated. Please use vm.computeCreateAddress instead."); + return vm.computeCreateAddress(deployer, nonce); + } + + function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) + internal + pure + virtual + returns (address) + { + console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead."); + return vm.computeCreate2Address(salt, initcodeHash, deployer); + } + + /// @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) { + console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead."); + return vm.computeCreate2Address(salt, initCodeHash); + } + + /// @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))); + } + + // This section is used to prevent the compilation of console, which shortens the compilation time when console is + // not used elsewhere. We also trick the compiler into letting us make the console log methods as `pure` to avoid + // any breaking changes to function signatures. + 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 = CONSOLE2_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function console2_log_StdUtils(string memory p0) private pure { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function console2_log_StdUtils(string memory p0, uint256 p1) private pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + } + + function console2_log_StdUtils(string memory p0, string memory p1) private pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Test.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Test.sol new file mode 100644 index 0000000..5ff60ea --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/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 {stdToml} from "./StdToml.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {Vm} from "./Vm.sol"; + +// 📦 BOILERPLATE +import {TestBase} from "./Base.sol"; + +// ⭐️ TEST +abstract contract Test is TestBase, StdAssertions, StdChains, StdCheats, StdInvariant, StdUtils { + // Note: IS_TEST() must return true. + bool public IS_TEST = true; +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol new file mode 100644 index 0000000..2f69997 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol @@ -0,0 +1,2263 @@ +// Automatically @generated by scripts/vm.py. Do not modify manually. + +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity >=0.6.2 <0.9.0; +pragma experimental ABIEncoderV2; + +/// 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 { + /// A modification applied to either `msg.sender` or `tx.origin`. Returned by `readCallers`. + enum CallerMode { + // No caller modification is currently active. + None, + // A one time broadcast triggered by a `vm.broadcast()` call is currently active. + Broadcast, + // A recurrent broadcast triggered by a `vm.startBroadcast()` call is currently active. + RecurrentBroadcast, + // A one time prank triggered by a `vm.prank()` call is currently active. + Prank, + // A recurrent prank triggered by a `vm.startPrank()` call is currently active. + RecurrentPrank + } + + /// The kind of account access that occurred. + enum AccountAccessKind { + // The account was called. + Call, + // The account was called via delegatecall. + DelegateCall, + // The account was called via callcode. + CallCode, + // The account was called via staticcall. + StaticCall, + // The account was created. + Create, + // The account was selfdestructed. + SelfDestruct, + // Synthetic access indicating the current context has resumed after a previous sub-context (AccountAccess). + Resume, + // The account's balance was read. + Balance, + // The account's codesize was read. + Extcodesize, + // The account's codehash was read. + Extcodehash, + // The account's code was copied. + Extcodecopy + } + + /// Forge execution contexts. + enum ForgeContext { + // Test group execution context (test, coverage or snapshot). + TestGroup, + // `forge test` execution context. + Test, + // `forge coverage` execution context. + Coverage, + // `forge snapshot` execution context. + Snapshot, + // Script group execution context (dry run, broadcast or resume). + ScriptGroup, + // `forge script` execution context. + ScriptDryRun, + // `forge script --broadcast` execution context. + ScriptBroadcast, + // `forge script --resume` execution context. + ScriptResume, + // Unknown `forge` execution context. + Unknown + } + + /// The transaction type (`txType`) of the broadcast. + enum BroadcastTxType { + // Represents a CALL broadcast tx. + Call, + // Represents a CREATE broadcast tx. + Create, + // Represents a CREATE2 broadcast tx. + Create2 + } + + /// An Ethereum log. Returned by `getRecordedLogs`. + struct Log { + // The topics of the log, including the signature, if any. + bytes32[] topics; + // The raw data of the log. + bytes data; + // The address of the log's emitter. + address emitter; + } + + /// An RPC URL and its alias. Returned by `rpcUrlStructs`. + struct Rpc { + // The alias of the RPC URL. + string key; + // The RPC URL. + string url; + } + + /// An RPC log object. Returned by `eth_getLogs`. + struct EthGetLogs { + // The address of the log's emitter. + address emitter; + // The topics of the log, including the signature, if any. + bytes32[] topics; + // The raw data of the log. + bytes data; + // The block hash. + bytes32 blockHash; + // The block number. + uint64 blockNumber; + // The transaction hash. + bytes32 transactionHash; + // The transaction index in the block. + uint64 transactionIndex; + // The log index. + uint256 logIndex; + // Whether the log was removed. + bool removed; + } + + /// A single entry in a directory listing. Returned by `readDir`. + struct DirEntry { + // The error message, if any. + string errorMessage; + // The path of the entry. + string path; + // The depth of the entry. + uint64 depth; + // Whether the entry is a directory. + bool isDir; + // Whether the entry is a symlink. + bool isSymlink; + } + + /// Metadata information about a file. + /// This structure is returned from the `fsMetadata` function and represents known + /// metadata about a file such as its permissions, size, modification + /// times, etc. + struct FsMetadata { + // True if this metadata is for a directory. + bool isDir; + // True if this metadata is for a symlink. + bool isSymlink; + // The size of the file, in bytes, this metadata is for. + uint256 length; + // True if this metadata is for a readonly (unwritable) file. + bool readOnly; + // The last modification time listed in this metadata. + uint256 modified; + // The last access time of this metadata. + uint256 accessed; + // The creation time listed in this metadata. + uint256 created; + } + + /// A wallet with a public and private key. + struct Wallet { + // The wallet's address. + address addr; + // The wallet's public key `X`. + uint256 publicKeyX; + // The wallet's public key `Y`. + uint256 publicKeyY; + // The wallet's private key. + uint256 privateKey; + } + + /// The result of a `tryFfi` call. + struct FfiResult { + // The exit code of the call. + int32 exitCode; + // The optionally hex-decoded `stdout` data. + bytes stdout; + // The `stderr` data. + bytes stderr; + } + + /// Information on the chain and fork. + struct ChainInfo { + // The fork identifier. Set to zero if no fork is active. + uint256 forkId; + // The chain ID of the current fork. + uint256 chainId; + } + + /// The result of a `stopAndReturnStateDiff` call. + struct AccountAccess { + // The chain and fork the access occurred. + ChainInfo chainInfo; + // The kind of account access that determines what the account is. + // If kind is Call, DelegateCall, StaticCall or CallCode, then the account is the callee. + // If kind is Create, then the account is the newly created account. + // If kind is SelfDestruct, then the account is the selfdestruct recipient. + // If kind is a Resume, then account represents a account context that has resumed. + AccountAccessKind kind; + // The account that was accessed. + // It's either the account created, callee or a selfdestruct recipient for CREATE, CALL or SELFDESTRUCT. + address account; + // What accessed the account. + address accessor; + // If the account was initialized or empty prior to the access. + // An account is considered initialized if it has code, a + // non-zero nonce, or a non-zero balance. + bool initialized; + // The previous balance of the accessed account. + uint256 oldBalance; + // The potential new balance of the accessed account. + // That is, all balance changes are recorded here, even if reverts occurred. + uint256 newBalance; + // Code of the account deployed by CREATE. + bytes deployedCode; + // Value passed along with the account access + uint256 value; + // Input data provided to the CREATE or CALL + bytes data; + // If this access reverted in either the current or parent context. + bool reverted; + // An ordered list of storage accesses made during an account access operation. + StorageAccess[] storageAccesses; + // Call depth traversed during the recording of state differences + uint64 depth; + } + + /// The storage accessed during an `AccountAccess`. + struct StorageAccess { + // The account whose storage was accessed. + address account; + // The slot that was accessed. + bytes32 slot; + // If the access was a write. + bool isWrite; + // The previous value of the slot. + bytes32 previousValue; + // The new value of the slot. + bytes32 newValue; + // If the access was reverted. + bool reverted; + } + + /// Gas used. Returned by `lastCallGas`. + struct Gas { + // The gas limit of the call. + uint64 gasLimit; + // The total gas used. + uint64 gasTotalUsed; + // DEPRECATED: The amount of gas used for memory expansion. Ref: + uint64 gasMemoryUsed; + // The amount of gas refunded. + int64 gasRefunded; + // The amount of gas remaining. + uint64 gasRemaining; + } + + /// The result of the `stopDebugTraceRecording` call + struct DebugStep { + // The stack before executing the step of the run. + // stack\[0\] represents the top of the stack. + // and only stack data relevant to the opcode execution is contained. + uint256[] stack; + // The memory input data before executing the step of the run. + // only input data relevant to the opcode execution is contained. + // e.g. for MLOAD, it will have memory\[offset:offset+32\] copied here. + // the offset value can be get by the stack data. + bytes memoryInput; + // The opcode that was accessed. + uint8 opcode; + // The call depth of the step. + uint64 depth; + // Whether the call end up with out of gas error. + bool isOutOfGas; + // The contract address where the opcode is running + address contractAddr; + } + + /// Represents a transaction's broadcast details. + struct BroadcastTxSummary { + // The hash of the transaction that was broadcasted + bytes32 txHash; + // Represent the type of transaction among CALL, CREATE, CREATE2 + BroadcastTxType txType; + // The address of the contract that was called or created. + // This is address of the contract that is created if the txType is CREATE or CREATE2. + address contractAddress; + // The block number the transaction landed in. + uint64 blockNumber; + // Status of the transaction, retrieved from the transaction receipt. + bool success; + } + + /// Holds a signed EIP-7702 authorization for an authority account to delegate to an implementation. + struct SignedDelegation { + // The y-parity of the recovered secp256k1 signature (0 or 1). + uint8 v; + // First 32 bytes of the signature. + bytes32 r; + // Second 32 bytes of the signature. + bytes32 s; + // The current nonce of the authority account at signing time. + // Used to ensure signature can't be replayed after account nonce changes. + uint64 nonce; + // Address of the contract implementation that will be delegated to. + // Gets encoded into delegation code: 0xef0100 || implementation. + address implementation; + } + + /// Represents a "potential" revert reason from a single subsequent call when using `vm.assumeNoReverts`. + /// Reverts that match will result in a FOUNDRY::ASSUME rejection, whereas unmatched reverts will be surfaced + /// as normal. + struct PotentialRevert { + // The allowed origin of the revert opcode; address(0) allows reverts from any address + address reverter; + // When true, only matches on the beginning of the revert data, otherwise, matches on entire revert data + bool partialMatch; + // The data to use to match encountered reverts + bytes revertData; + } + + // ======== Crypto ======== + + /// 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); + + /// 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); + + /// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language + /// at the derivation path `m/44'/60'/0'/0/{index}`. + function deriveKey(string calldata mnemonic, uint32 index, string calldata language) + external + pure + returns (uint256 privateKey); + + /// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language + /// at `{derivationPath}{index}`. + function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index, string calldata language) + external + pure + returns (uint256 privateKey); + + /// Derives secp256r1 public key from the provided `privateKey`. + function publicKeyP256(uint256 privateKey) external pure returns (uint256 publicKeyX, uint256 publicKeyY); + + /// Adds a private key to the local forge wallet and returns the address. + function rememberKey(uint256 privateKey) external returns (address keyAddr); + + /// Derive a set number of wallets from a mnemonic at the derivation path `m/44'/60'/0'/0/{0..count}`. + /// The respective private keys are saved to the local forge wallet for later use and their addresses are returned. + function rememberKeys(string calldata mnemonic, string calldata derivationPath, uint32 count) + external + returns (address[] memory keyAddrs); + + /// Derive a set number of wallets from a mnemonic in the specified language at the derivation path `m/44'/60'/0'/0/{0..count}`. + /// The respective private keys are saved to the local forge wallet for later use and their addresses are returned. + function rememberKeys( + string calldata mnemonic, + string calldata derivationPath, + string calldata language, + uint32 count + ) external returns (address[] memory keyAddrs); + + /// Signs data with a `Wallet`. + /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the + /// signature's `s` value, and the recovery id `v` in a single bytes32. + /// This format reduces the signature size from 65 to 64 bytes. + function signCompact(Wallet calldata wallet, bytes32 digest) external returns (bytes32 r, bytes32 vs); + + /// Signs `digest` with `privateKey` using the secp256k1 curve. + /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the + /// signature's `s` value, and the recovery id `v` in a single bytes32. + /// This format reduces the signature size from 65 to 64 bytes. + function signCompact(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 vs); + + /// Signs `digest` with signer provided to script using the secp256k1 curve. + /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the + /// signature's `s` value, and the recovery id `v` in a single bytes32. + /// This format reduces the signature size from 65 to 64 bytes. + /// If `--sender` is provided, the signer with provided address is used, otherwise, + /// if exactly one signer is provided to the script, that signer is used. + /// Raises error if signer passed through `--sender` does not match any unlocked signers or + /// if `--sender` is not provided and not exactly one signer is passed to the script. + function signCompact(bytes32 digest) external pure returns (bytes32 r, bytes32 vs); + + /// Signs `digest` with signer provided to script using the secp256k1 curve. + /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the + /// signature's `s` value, and the recovery id `v` in a single bytes32. + /// This format reduces the signature size from 65 to 64 bytes. + /// Raises error if none of the signers passed into the script have provided address. + function signCompact(address signer, bytes32 digest) external pure returns (bytes32 r, bytes32 vs); + + /// Signs `digest` with `privateKey` using the secp256r1 curve. + function signP256(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 s); + + /// Signs data with a `Wallet`. + function sign(Wallet calldata wallet, bytes32 digest) external returns (uint8 v, bytes32 r, bytes32 s); + + /// Signs `digest` with `privateKey` using the secp256k1 curve. + function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + + /// Signs `digest` with signer provided to script using the secp256k1 curve. + /// If `--sender` is provided, the signer with provided address is used, otherwise, + /// if exactly one signer is provided to the script, that signer is used. + /// Raises error if signer passed through `--sender` does not match any unlocked signers or + /// if `--sender` is not provided and not exactly one signer is passed to the script. + function sign(bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + + /// Signs `digest` with signer provided to script using the secp256k1 curve. + /// Raises error if none of the signers passed into the script have provided address. + function sign(address signer, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + + // ======== Environment ======== + + /// Gets the environment variable `name` and parses it as `address`. + /// Reverts if the variable was not found or could not be parsed. + function envAddress(string calldata name) external view returns (address value); + + /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value); + + /// Gets the environment variable `name` and parses it as `bool`. + /// Reverts if the variable was not found or could not be parsed. + function envBool(string calldata name) external view returns (bool value); + + /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value); + + /// Gets the environment variable `name` and parses it as `bytes32`. + /// Reverts if the variable was not found or could not be parsed. + function envBytes32(string calldata name) external view returns (bytes32 value); + + /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value); + + /// Gets the environment variable `name` and parses it as `bytes`. + /// Reverts if the variable was not found or could not be parsed. + function envBytes(string calldata name) external view returns (bytes memory value); + + /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value); + + /// Gets the environment variable `name` and returns true if it exists, else returns false. + function envExists(string calldata name) external view returns (bool result); + + /// Gets the environment variable `name` and parses it as `int256`. + /// Reverts if the variable was not found or could not be parsed. + function envInt(string calldata name) external view returns (int256 value); + + /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value); + + /// Gets the environment variable `name` and parses it as `bool`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, bool defaultValue) external view returns (bool value); + + /// Gets the environment variable `name` and parses it as `uint256`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, uint256 defaultValue) external view returns (uint256 value); + + /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, address[] calldata defaultValue) + external + view + returns (address[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue) + external + view + returns (bytes32[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, string[] calldata defaultValue) + external + view + returns (string[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue) + external + view + returns (bytes[] memory value); + + /// Gets the environment variable `name` and parses it as `int256`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, int256 defaultValue) external view returns (int256 value); + + /// Gets the environment variable `name` and parses it as `address`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, address defaultValue) external view returns (address value); + + /// Gets the environment variable `name` and parses it as `bytes32`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, bytes32 defaultValue) external view returns (bytes32 value); + + /// Gets the environment variable `name` and parses it as `string`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata defaultValue) external view returns (string memory value); + + /// Gets the environment variable `name` and parses it as `bytes`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, bytes calldata defaultValue) external view returns (bytes memory value); + + /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue) + external + view + returns (bool[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue) + external + view + returns (uint256[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue) + external + view + returns (int256[] memory value); + + /// Gets the environment variable `name` and parses it as `string`. + /// Reverts if the variable was not found or could not be parsed. + function envString(string calldata name) external view returns (string memory value); + + /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envString(string calldata name, string calldata delim) external view returns (string[] memory value); + + /// Gets the environment variable `name` and parses it as `uint256`. + /// Reverts if the variable was not found or could not be parsed. + function envUint(string calldata name) external view returns (uint256 value); + + /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value); + + /// Returns true if `forge` command was executed in given context. + function isContext(ForgeContext context) external view returns (bool result); + + /// Sets environment variables. + function setEnv(string calldata name, string calldata value) external; + + // ======== EVM ======== + + /// 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); + + /// Gets the address for a given private key. + function addr(uint256 privateKey) external pure returns (address keyAddr); + + /// Gets all the logs according to specified filter. + function eth_getLogs(uint256 fromBlock, uint256 toBlock, address target, bytes32[] calldata topics) + external + returns (EthGetLogs[] memory logs); + + /// Gets the current `block.blobbasefee`. + /// You should use this instead of `block.blobbasefee` if you use `vm.blobBaseFee`, as `block.blobbasefee` is assumed to be constant across a transaction, + /// and as a result will get optimized out by the compiler. + /// See https://github.com/foundry-rs/foundry/issues/6180 + function getBlobBaseFee() external view returns (uint256 blobBaseFee); + + /// Gets the current `block.number`. + /// You should use this instead of `block.number` if you use `vm.roll`, as `block.number` is assumed to be constant across a transaction, + /// and as a result will get optimized out by the compiler. + /// See https://github.com/foundry-rs/foundry/issues/6180 + function getBlockNumber() external view returns (uint256 height); + + /// Gets the current `block.timestamp`. + /// You should use this instead of `block.timestamp` if you use `vm.warp`, as `block.timestamp` is assumed to be constant across a transaction, + /// and as a result will get optimized out by the compiler. + /// See https://github.com/foundry-rs/foundry/issues/6180 + function getBlockTimestamp() external view returns (uint256 timestamp); + + /// 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); + + /// 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 nonce of an account. + function getNonce(address account) external view returns (uint64 nonce); + + /// Get the nonce of a `Wallet`. + function getNonce(Wallet calldata wallet) external returns (uint64 nonce); + + /// Gets all the recorded logs. + function getRecordedLogs() external returns (Log[] memory logs); + + /// Returns state diffs from current `vm.startStateDiffRecording` session. + function getStateDiff() external view returns (string memory diff); + + /// Returns state diffs from current `vm.startStateDiffRecording` session, in json format. + function getStateDiffJson() external view returns (string memory diff); + + /// Gets the gas used in the last call from the callee perspective. + function lastCallGas() external view returns (Gas memory gas); + + /// Loads a storage slot from an address. + function load(address target, bytes32 slot) external view returns (bytes32 data); + + /// Pauses gas metering (i.e. gas usage is not counted). Noop if already paused. + function pauseGasMetering() external; + + /// Records all storage reads and writes. + function record() external; + + /// Record all the transaction logs. + function recordLogs() external; + + /// Reset gas metering (i.e. gas usage is set to gas limit). + function resetGasMetering() external; + + /// Resumes gas metering (i.e. gas usage is counted again). Noop if already on. + function resumeGasMetering() external; + + /// Performs an Ethereum JSON-RPC request to the current fork URL. + function rpc(string calldata method, string calldata params) external returns (bytes memory data); + + /// Performs an Ethereum JSON-RPC request to the given endpoint. + function rpc(string calldata urlOrAlias, string calldata method, string calldata params) + external + returns (bytes memory data); + + /// Records the debug trace during the run. + function startDebugTraceRecording() external; + + /// Starts recording all map SSTOREs for later retrieval. + function startMappingRecording() external; + + /// Record all account accesses as part of CREATE, CALL or SELFDESTRUCT opcodes in order, + /// along with the context of the calls + function startStateDiffRecording() external; + + /// Stop debug trace recording and returns the recorded debug trace. + function stopAndReturnDebugTraceRecording() external returns (DebugStep[] memory step); + + /// Returns an ordered array of all account accesses from a `vm.startStateDiffRecording` session. + function stopAndReturnStateDiff() external returns (AccountAccess[] memory accountAccesses); + + /// Stops recording all map SSTOREs for later retrieval and clears the recorded data. + function stopMappingRecording() external; + + // ======== Filesystem ======== + + /// 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; + + /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the + /// artifact in the form of :: where and parts are optional. + function deployCode(string calldata artifactPath) external returns (address deployedAddress); + + /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the + /// artifact in the form of :: where and parts are optional. + /// Additionally accepts abi-encoded constructor arguments. + function deployCode(string calldata artifactPath, bytes calldata constructorArgs) + external + returns (address deployedAddress); + + /// Returns true if the given path points to an existing entity, else returns false. + function exists(string calldata path) external view returns (bool result); + + /// Performs a foreign function call via the terminal. + function ffi(string[] calldata commandInput) external returns (bytes memory 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); + + /// Gets the artifact path from code (aka. creation code). + function getArtifactPathByCode(bytes calldata code) external view returns (string memory path); + + /// Gets the artifact path from deployed code (aka. runtime code). + function getArtifactPathByDeployedCode(bytes calldata deployedCode) external view returns (string memory path); + + /// Returns the most recent broadcast for the given contract on `chainId` matching `txType`. + /// For example: + /// The most recent deployment can be fetched by passing `txType` as `CREATE` or `CREATE2`. + /// The most recent call can be fetched by passing `txType` as `CALL`. + function getBroadcast(string calldata contractName, uint64 chainId, BroadcastTxType txType) + external + view + returns (BroadcastTxSummary memory); + + /// Returns all broadcasts for the given contract on `chainId` with the specified `txType`. + /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. + function getBroadcasts(string calldata contractName, uint64 chainId, BroadcastTxType txType) + external + view + returns (BroadcastTxSummary[] memory); + + /// Returns all broadcasts for the given contract on `chainId`. + /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. + function getBroadcasts(string calldata contractName, uint64 chainId) + external + view + returns (BroadcastTxSummary[] memory); + + /// Gets the creation bytecode from an artifact file. Takes in the relative path to the json file or the path to the + /// artifact in the form of :: where and parts are optional. + 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 or the path to the + /// artifact in the form of :: where and parts are optional. + function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); + + /// Returns the most recent deployment for the current `chainId`. + function getDeployment(string calldata contractName) external view returns (address deployedAddress); + + /// Returns the most recent deployment for the given contract on `chainId` + function getDeployment(string calldata contractName, uint64 chainId) + external + view + returns (address deployedAddress); + + /// Returns all deployments for the given contract on `chainId` + /// Sorted in descending order of deployment time i.e descending order of BroadcastTxSummary.blockNumber. + /// The most recent deployment is the first element, and the oldest is the last. + function getDeployments(string calldata contractName, uint64 chainId) + external + view + returns (address[] memory deployedAddresses); + + /// Returns true if the path exists on disk and is pointing at a directory, else returns false. + function isDir(string calldata path) external view 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 view returns (bool result); + + /// Get the path of the current project root. + function projectRoot() external view returns (string memory path); + + /// Prompts the user for a string value in the terminal. + function prompt(string calldata promptText) external returns (string memory input); + + /// Prompts the user for an address in the terminal. + function promptAddress(string calldata promptText) external returns (address); + + /// Prompts the user for a hidden string value in the terminal. + function promptSecret(string calldata promptText) external returns (string memory input); + + /// Prompts the user for hidden uint256 in the terminal (usually pk). + function promptSecretUint(string calldata promptText) external returns (uint256); + + /// Prompts the user for uint256 in the terminal. + function promptUint(string calldata promptText) external returns (uint256); + + /// Reads the directory at the given path recursively, up to `maxDepth`. + /// `maxDepth` defaults to 1, meaning only the direct children of the given directory will be returned. + /// Follows symbolic links if `followLinks` is true. + function readDir(string calldata path) external view returns (DirEntry[] memory entries); + + /// See `readDir(string)`. + function readDir(string calldata path, uint64 maxDepth) external view returns (DirEntry[] memory entries); + + /// See `readDir(string)`. + 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; + + /// 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); + + /// Returns the time since unix epoch in milliseconds. + function unixTime() external view returns (uint256 milliseconds); + + /// 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; + + // ======== JSON ======== + + /// Checks if `key` exists in a JSON object. + function keyExistsJson(string calldata json, string calldata key) external view returns (bool); + + /// Parses a string of JSON data at `key` and coerces it to `address`. + function parseJsonAddress(string calldata json, string calldata key) external pure returns (address); + + /// Parses a string of JSON data at `key` and coerces it to `address[]`. + function parseJsonAddressArray(string calldata json, string calldata key) + external + pure + returns (address[] memory); + + /// Parses a string of JSON data at `key` and coerces it to `bool`. + function parseJsonBool(string calldata json, string calldata key) external pure returns (bool); + + /// Parses a string of JSON data at `key` and coerces it to `bool[]`. + function parseJsonBoolArray(string calldata json, string calldata key) external pure returns (bool[] memory); + + /// Parses a string of JSON data at `key` and coerces it to `bytes`. + function parseJsonBytes(string calldata json, string calldata key) external pure returns (bytes memory); + + /// Parses a string of JSON data at `key` and coerces it to `bytes32`. + function parseJsonBytes32(string calldata json, string calldata key) external pure returns (bytes32); + + /// Parses a string of JSON data at `key` and coerces it to `bytes32[]`. + function parseJsonBytes32Array(string calldata json, string calldata key) + external + pure + returns (bytes32[] memory); + + /// Parses a string of JSON data at `key` and coerces it to `bytes[]`. + function parseJsonBytesArray(string calldata json, string calldata key) external pure returns (bytes[] memory); + + /// Parses a string of JSON data at `key` and coerces it to `int256`. + function parseJsonInt(string calldata json, string calldata key) external pure returns (int256); + + /// Parses a string of JSON data at `key` and coerces it to `int256[]`. + function parseJsonIntArray(string calldata json, string calldata key) external pure returns (int256[] memory); + + /// Returns an array of all the keys in a JSON object. + function parseJsonKeys(string calldata json, string calldata key) external pure returns (string[] memory keys); + + /// Parses a string of JSON data at `key` and coerces it to `string`. + function parseJsonString(string calldata json, string calldata key) external pure returns (string memory); + + /// Parses a string of JSON data at `key` and coerces it to `string[]`. + function parseJsonStringArray(string calldata json, string calldata key) external pure returns (string[] memory); + + /// Parses a string of JSON data at `key` and coerces it to type array corresponding to `typeDescription`. + function parseJsonTypeArray(string calldata json, string calldata key, string calldata typeDescription) + external + pure + returns (bytes memory); + + /// Parses a string of JSON data and coerces it to type corresponding to `typeDescription`. + function parseJsonType(string calldata json, string calldata typeDescription) + external + pure + returns (bytes memory); + + /// Parses a string of JSON data at `key` and coerces it to type corresponding to `typeDescription`. + function parseJsonType(string calldata json, string calldata key, string calldata typeDescription) + external + pure + returns (bytes memory); + + /// Parses a string of JSON data at `key` and coerces it to `uint256`. + function parseJsonUint(string calldata json, string calldata key) external pure returns (uint256); + + /// Parses a string of JSON data at `key` and coerces it to `uint256[]`. + function parseJsonUintArray(string calldata json, string calldata key) external pure returns (uint256[] memory); + + /// ABI-encodes a JSON object. + function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData); + + /// ABI-encodes a JSON object at `key`. + function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData); + + /// See `serializeJson`. + function serializeAddress(string calldata objectKey, string calldata valueKey, address value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBool(string calldata objectKey, string calldata valueKey, bool value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeInt(string calldata objectKey, string calldata valueKey, int256 value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values) + external + returns (string memory json); + + /// Serializes a key and value to a JSON object stored in-memory that can be later written to a file. + /// 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); + + /// See `serializeJson`. + function serializeJsonType(string calldata typeDescription, bytes calldata value) + external + pure + returns (string memory json); + + /// See `serializeJson`. + function serializeJsonType( + string calldata objectKey, + string calldata valueKey, + string calldata typeDescription, + bytes calldata value + ) external returns (string memory json); + + /// See `serializeJson`. + function serializeString(string calldata objectKey, string calldata valueKey, string calldata value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeUintToHex(string calldata objectKey, string calldata valueKey, uint256 value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) + external + returns (string memory json); + + /// 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; + + /// Checks if `key` exists in a JSON object + /// `keyExists` is being deprecated in favor of `keyExistsJson`. It will be removed in future versions. + function keyExists(string calldata json, string calldata key) external view returns (bool); + + // ======== Scripting ======== + + /// Designate the next call as an EIP-7702 transaction + function attachDelegation(SignedDelegation calldata signedDelegation) external; + + /// Takes a signed transaction and broadcasts it to the network. + function broadcastRawTransaction(bytes calldata data) external; + + /// Has the next call (at this call depth only) create transactions that can later be signed and sent onchain. + /// Broadcasting address is determined by checking the following in order: + /// 1. If `--sender` argument was provided, that address is used. + /// 2. If exactly one signer (e.g. private key, hw wallet, keystore) is set when `forge broadcast` is invoked, that signer is used. + /// 3. Otherwise, default foundry sender (1804c8AB1F12E6bbf3894d4083f33e07309d1f38) is used. + 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; + + /// Returns addresses of available unlocked wallets in the script environment. + function getWallets() external returns (address[] memory wallets); + + /// Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction + function signAndAttachDelegation(address implementation, uint256 privateKey) + external + returns (SignedDelegation memory signedDelegation); + + /// Sign an EIP-7702 authorization for delegation + function signDelegation(address implementation, uint256 privateKey) + external + returns (SignedDelegation memory signedDelegation); + + /// Has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain. + /// Broadcasting address is determined by checking the following in order: + /// 1. If `--sender` argument was provided, that address is used. + /// 2. If exactly one signer (e.g. private key, hw wallet, keystore) is set when `forge broadcast` is invoked, that signer is used. + /// 3. Otherwise, default foundry sender (1804c8AB1F12E6bbf3894d4083f33e07309d1f38) is used. + 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; + + // ======== String ======== + + /// Returns true if `search` is found in `subject`, false otherwise. + function contains(string calldata subject, string calldata search) external returns (bool result); + + /// Returns the index of the first occurrence of a `key` in an `input` string. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `key` is not found. + /// Returns 0 in case of an empty `key`. + function indexOf(string calldata input, string calldata key) external pure returns (uint256); + + /// Parses the given `string` into an `address`. + function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue); + + /// Parses the given `string` into a `bool`. + function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue); + + /// Parses the given `string` into `bytes`. + function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue); + + /// Parses the given `string` into a `bytes32`. + function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue); + + /// Parses the given `string` into a `int256`. + function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue); + + /// Parses the given `string` into a `uint256`. + function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue); + + /// Replaces occurrences of `from` in the given `string` with `to`. + function replace(string calldata input, string calldata from, string calldata to) + external + pure + returns (string memory output); + + /// Splits the given `string` into an array of strings divided by the `delimiter`. + function split(string calldata input, string calldata delimiter) external pure returns (string[] memory outputs); + + /// Converts the given `string` value to Lowercase. + function toLowercase(string calldata input) external pure returns (string memory output); + + /// Converts the given value to a `string`. + function toString(address value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(bytes calldata value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(bytes32 value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(bool value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(uint256 value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(int256 value) external pure returns (string memory stringifiedValue); + + /// Converts the given `string` value to Uppercase. + function toUppercase(string calldata input) external pure returns (string memory output); + + /// Trims leading and trailing whitespace from the given `string` value. + function trim(string calldata input) external pure returns (string memory output); + + // ======== Testing ======== + + /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. + /// Formats values with decimals in failure message. + function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertApproxEqAbsDecimal( + uint256 left, + uint256 right, + uint256 maxDelta, + uint256 decimals, + string calldata error + ) external pure; + + /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. + /// Formats values with decimals in failure message. + function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertApproxEqAbsDecimal( + int256 left, + int256 right, + uint256 maxDelta, + uint256 decimals, + string calldata error + ) external pure; + + /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. + function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) external pure; + + /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. + /// Includes error message into revert string on failure. + function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string calldata error) external pure; + + /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. + function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) external pure; + + /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. + /// Includes error message into revert string on failure. + function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string calldata error) external pure; + + /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Formats values with decimals in failure message. + function assertApproxEqRelDecimal(uint256 left, uint256 right, uint256 maxPercentDelta, uint256 decimals) + external + pure; + + /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertApproxEqRelDecimal( + uint256 left, + uint256 right, + uint256 maxPercentDelta, + uint256 decimals, + string calldata error + ) external pure; + + /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Formats values with decimals in failure message. + function assertApproxEqRelDecimal(int256 left, int256 right, uint256 maxPercentDelta, uint256 decimals) + external + pure; + + /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertApproxEqRelDecimal( + int256 left, + int256 right, + uint256 maxPercentDelta, + uint256 decimals, + string calldata error + ) external pure; + + /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta) external pure; + + /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Includes error message into revert string on failure. + function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta, string calldata error) + external + pure; + + /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) external pure; + + /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Includes error message into revert string on failure. + function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta, string calldata error) + external + pure; + + /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message. + function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message. + /// Includes error message into revert string on failure. + function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Asserts that two `int256` values are equal, formatting them with decimals in failure message. + function assertEqDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Asserts that two `int256` values are equal, formatting them with decimals in failure message. + /// Includes error message into revert string on failure. + function assertEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Asserts that two `bool` values are equal. + function assertEq(bool left, bool right) external pure; + + /// Asserts that two `bool` values are equal and includes error message into revert string on failure. + function assertEq(bool left, bool right, string calldata error) external pure; + + /// Asserts that two `string` values are equal. + function assertEq(string calldata left, string calldata right) external pure; + + /// Asserts that two `string` values are equal and includes error message into revert string on failure. + function assertEq(string calldata left, string calldata right, string calldata error) external pure; + + /// Asserts that two `bytes` values are equal. + function assertEq(bytes calldata left, bytes calldata right) external pure; + + /// Asserts that two `bytes` values are equal and includes error message into revert string on failure. + function assertEq(bytes calldata left, bytes calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bool` values are equal. + function assertEq(bool[] calldata left, bool[] calldata right) external pure; + + /// Asserts that two arrays of `bool` values are equal and includes error message into revert string on failure. + function assertEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `uint256 values are equal. + function assertEq(uint256[] calldata left, uint256[] calldata right) external pure; + + /// Asserts that two arrays of `uint256` values are equal and includes error message into revert string on failure. + function assertEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `int256` values are equal. + function assertEq(int256[] calldata left, int256[] calldata right) external pure; + + /// Asserts that two arrays of `int256` values are equal and includes error message into revert string on failure. + function assertEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure; + + /// Asserts that two `uint256` values are equal. + function assertEq(uint256 left, uint256 right) external pure; + + /// Asserts that two arrays of `address` values are equal. + function assertEq(address[] calldata left, address[] calldata right) external pure; + + /// Asserts that two arrays of `address` values are equal and includes error message into revert string on failure. + function assertEq(address[] calldata left, address[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bytes32` values are equal. + function assertEq(bytes32[] calldata left, bytes32[] calldata right) external pure; + + /// Asserts that two arrays of `bytes32` values are equal and includes error message into revert string on failure. + function assertEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `string` values are equal. + function assertEq(string[] calldata left, string[] calldata right) external pure; + + /// Asserts that two arrays of `string` values are equal and includes error message into revert string on failure. + function assertEq(string[] calldata left, string[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bytes` values are equal. + function assertEq(bytes[] calldata left, bytes[] calldata right) external pure; + + /// Asserts that two arrays of `bytes` values are equal and includes error message into revert string on failure. + function assertEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure; + + /// Asserts that two `uint256` values are equal and includes error message into revert string on failure. + function assertEq(uint256 left, uint256 right, string calldata error) external pure; + + /// Asserts that two `int256` values are equal. + function assertEq(int256 left, int256 right) external pure; + + /// Asserts that two `int256` values are equal and includes error message into revert string on failure. + function assertEq(int256 left, int256 right, string calldata error) external pure; + + /// Asserts that two `address` values are equal. + function assertEq(address left, address right) external pure; + + /// Asserts that two `address` values are equal and includes error message into revert string on failure. + function assertEq(address left, address right, string calldata error) external pure; + + /// Asserts that two `bytes32` values are equal. + function assertEq(bytes32 left, bytes32 right) external pure; + + /// Asserts that two `bytes32` values are equal and includes error message into revert string on failure. + function assertEq(bytes32 left, bytes32 right, string calldata error) external pure; + + /// Asserts that the given condition is false. + function assertFalse(bool condition) external pure; + + /// Asserts that the given condition is false and includes error message into revert string on failure. + function assertFalse(bool condition, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than or equal to second. + /// Formats values with decimals in failure message. + function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than or equal to second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be greater than or equal to second. + /// Formats values with decimals in failure message. + function assertGeDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects first value to be greater than or equal to second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertGeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than or equal to second. + function assertGe(uint256 left, uint256 right) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than or equal to second. + /// Includes error message into revert string on failure. + function assertGe(uint256 left, uint256 right, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be greater than or equal to second. + function assertGe(int256 left, int256 right) external pure; + + /// Compares two `int256` values. Expects first value to be greater than or equal to second. + /// Includes error message into revert string on failure. + function assertGe(int256 left, int256 right, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than second. + /// Formats values with decimals in failure message. + function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be greater than second. + /// Formats values with decimals in failure message. + function assertGtDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects first value to be greater than second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertGtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than second. + function assertGt(uint256 left, uint256 right) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than second. + /// Includes error message into revert string on failure. + function assertGt(uint256 left, uint256 right, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be greater than second. + function assertGt(int256 left, int256 right) external pure; + + /// Compares two `int256` values. Expects first value to be greater than second. + /// Includes error message into revert string on failure. + function assertGt(int256 left, int256 right, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be less than or equal to second. + /// Formats values with decimals in failure message. + function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects first value to be less than or equal to second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be less than or equal to second. + /// Formats values with decimals in failure message. + function assertLeDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects first value to be less than or equal to second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertLeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be less than or equal to second. + function assertLe(uint256 left, uint256 right) external pure; + + /// Compares two `uint256` values. Expects first value to be less than or equal to second. + /// Includes error message into revert string on failure. + function assertLe(uint256 left, uint256 right, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be less than or equal to second. + function assertLe(int256 left, int256 right) external pure; + + /// Compares two `int256` values. Expects first value to be less than or equal to second. + /// Includes error message into revert string on failure. + function assertLe(int256 left, int256 right, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be less than second. + /// Formats values with decimals in failure message. + function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects first value to be less than second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be less than second. + /// Formats values with decimals in failure message. + function assertLtDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects first value to be less than second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertLtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be less than second. + function assertLt(uint256 left, uint256 right) external pure; + + /// Compares two `uint256` values. Expects first value to be less than second. + /// Includes error message into revert string on failure. + function assertLt(uint256 left, uint256 right, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be less than second. + function assertLt(int256 left, int256 right) external pure; + + /// Compares two `int256` values. Expects first value to be less than second. + /// Includes error message into revert string on failure. + function assertLt(int256 left, int256 right, string calldata error) external pure; + + /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message. + function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message. + /// Includes error message into revert string on failure. + function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message. + function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message. + /// Includes error message into revert string on failure. + function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Asserts that two `bool` values are not equal. + function assertNotEq(bool left, bool right) external pure; + + /// Asserts that two `bool` values are not equal and includes error message into revert string on failure. + function assertNotEq(bool left, bool right, string calldata error) external pure; + + /// Asserts that two `string` values are not equal. + function assertNotEq(string calldata left, string calldata right) external pure; + + /// Asserts that two `string` values are not equal and includes error message into revert string on failure. + function assertNotEq(string calldata left, string calldata right, string calldata error) external pure; + + /// Asserts that two `bytes` values are not equal. + function assertNotEq(bytes calldata left, bytes calldata right) external pure; + + /// Asserts that two `bytes` values are not equal and includes error message into revert string on failure. + function assertNotEq(bytes calldata left, bytes calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bool` values are not equal. + function assertNotEq(bool[] calldata left, bool[] calldata right) external pure; + + /// Asserts that two arrays of `bool` values are not equal and includes error message into revert string on failure. + function assertNotEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `uint256` values are not equal. + function assertNotEq(uint256[] calldata left, uint256[] calldata right) external pure; + + /// Asserts that two arrays of `uint256` values are not equal and includes error message into revert string on failure. + function assertNotEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `int256` values are not equal. + function assertNotEq(int256[] calldata left, int256[] calldata right) external pure; + + /// Asserts that two arrays of `int256` values are not equal and includes error message into revert string on failure. + function assertNotEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure; + + /// Asserts that two `uint256` values are not equal. + function assertNotEq(uint256 left, uint256 right) external pure; + + /// Asserts that two arrays of `address` values are not equal. + function assertNotEq(address[] calldata left, address[] calldata right) external pure; + + /// Asserts that two arrays of `address` values are not equal and includes error message into revert string on failure. + function assertNotEq(address[] calldata left, address[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bytes32` values are not equal. + function assertNotEq(bytes32[] calldata left, bytes32[] calldata right) external pure; + + /// Asserts that two arrays of `bytes32` values are not equal and includes error message into revert string on failure. + function assertNotEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `string` values are not equal. + function assertNotEq(string[] calldata left, string[] calldata right) external pure; + + /// Asserts that two arrays of `string` values are not equal and includes error message into revert string on failure. + function assertNotEq(string[] calldata left, string[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bytes` values are not equal. + function assertNotEq(bytes[] calldata left, bytes[] calldata right) external pure; + + /// Asserts that two arrays of `bytes` values are not equal and includes error message into revert string on failure. + function assertNotEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure; + + /// Asserts that two `uint256` values are not equal and includes error message into revert string on failure. + function assertNotEq(uint256 left, uint256 right, string calldata error) external pure; + + /// Asserts that two `int256` values are not equal. + function assertNotEq(int256 left, int256 right) external pure; + + /// Asserts that two `int256` values are not equal and includes error message into revert string on failure. + function assertNotEq(int256 left, int256 right, string calldata error) external pure; + + /// Asserts that two `address` values are not equal. + function assertNotEq(address left, address right) external pure; + + /// Asserts that two `address` values are not equal and includes error message into revert string on failure. + function assertNotEq(address left, address right, string calldata error) external pure; + + /// Asserts that two `bytes32` values are not equal. + function assertNotEq(bytes32 left, bytes32 right) external pure; + + /// Asserts that two `bytes32` values are not equal and includes error message into revert string on failure. + function assertNotEq(bytes32 left, bytes32 right, string calldata error) external pure; + + /// Asserts that the given condition is true. + function assertTrue(bool condition) external pure; + + /// Asserts that the given condition is true and includes error message into revert string on failure. + function assertTrue(bool condition, string calldata error) external pure; + + /// If the condition is false, discard this run's fuzz inputs and generate new ones. + function assume(bool condition) external pure; + + /// Discard this run's fuzz inputs and generate new ones if next call reverted. + function assumeNoRevert() external pure; + + /// Discard this run's fuzz inputs and generate new ones if next call reverts with the potential revert parameters. + function assumeNoRevert(PotentialRevert calldata potentialRevert) external pure; + + /// Discard this run's fuzz inputs and generate new ones if next call reverts with the any of the potential revert parameters. + function assumeNoRevert(PotentialRevert[] calldata potentialReverts) external pure; + + /// Writes a breakpoint to jump to in the debugger. + function breakpoint(string calldata char) external pure; + + /// Writes a conditional breakpoint to jump to in the debugger. + function breakpoint(string calldata char, bool value) external pure; + + /// Returns the Foundry version. + /// Format: -+.. + /// Sample output: 0.3.0-nightly+3cb96bde9b.1737036656.debug + /// Note: Build timestamps may vary slightly across platforms due to separate CI jobs. + /// For reliable version comparisons, use UNIX format (e.g., >= 1700000000) + /// to compare timestamps while ignoring minor time differences. + function getFoundryVersion() external view returns (string memory version); + + /// 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 as structs. + function rpcUrlStructs() external view returns (Rpc[] memory urls); + + /// Returns all rpc urls and their aliases `[alias, url][]`. + function rpcUrls() external view returns (string[2][] memory urls); + + /// Suspends execution of the main thread for `duration` milliseconds. + function sleep(uint256 duration) external; + + // ======== Toml ======== + + /// Checks if `key` exists in a TOML table. + function keyExistsToml(string calldata toml, string calldata key) external view returns (bool); + + /// Parses a string of TOML data at `key` and coerces it to `address`. + function parseTomlAddress(string calldata toml, string calldata key) external pure returns (address); + + /// Parses a string of TOML data at `key` and coerces it to `address[]`. + function parseTomlAddressArray(string calldata toml, string calldata key) + external + pure + returns (address[] memory); + + /// Parses a string of TOML data at `key` and coerces it to `bool`. + function parseTomlBool(string calldata toml, string calldata key) external pure returns (bool); + + /// Parses a string of TOML data at `key` and coerces it to `bool[]`. + function parseTomlBoolArray(string calldata toml, string calldata key) external pure returns (bool[] memory); + + /// Parses a string of TOML data at `key` and coerces it to `bytes`. + function parseTomlBytes(string calldata toml, string calldata key) external pure returns (bytes memory); + + /// Parses a string of TOML data at `key` and coerces it to `bytes32`. + function parseTomlBytes32(string calldata toml, string calldata key) external pure returns (bytes32); + + /// Parses a string of TOML data at `key` and coerces it to `bytes32[]`. + function parseTomlBytes32Array(string calldata toml, string calldata key) + external + pure + returns (bytes32[] memory); + + /// Parses a string of TOML data at `key` and coerces it to `bytes[]`. + function parseTomlBytesArray(string calldata toml, string calldata key) external pure returns (bytes[] memory); + + /// Parses a string of TOML data at `key` and coerces it to `int256`. + function parseTomlInt(string calldata toml, string calldata key) external pure returns (int256); + + /// Parses a string of TOML data at `key` and coerces it to `int256[]`. + function parseTomlIntArray(string calldata toml, string calldata key) external pure returns (int256[] memory); + + /// Returns an array of all the keys in a TOML table. + function parseTomlKeys(string calldata toml, string calldata key) external pure returns (string[] memory keys); + + /// Parses a string of TOML data at `key` and coerces it to `string`. + function parseTomlString(string calldata toml, string calldata key) external pure returns (string memory); + + /// Parses a string of TOML data at `key` and coerces it to `string[]`. + function parseTomlStringArray(string calldata toml, string calldata key) external pure returns (string[] memory); + + /// Parses a string of TOML data at `key` and coerces it to type array corresponding to `typeDescription`. + function parseTomlTypeArray(string calldata toml, string calldata key, string calldata typeDescription) + external + pure + returns (bytes memory); + + /// Parses a string of TOML data and coerces it to type corresponding to `typeDescription`. + function parseTomlType(string calldata toml, string calldata typeDescription) + external + pure + returns (bytes memory); + + /// Parses a string of TOML data at `key` and coerces it to type corresponding to `typeDescription`. + function parseTomlType(string calldata toml, string calldata key, string calldata typeDescription) + external + pure + returns (bytes memory); + + /// Parses a string of TOML data at `key` and coerces it to `uint256`. + function parseTomlUint(string calldata toml, string calldata key) external pure returns (uint256); + + /// Parses a string of TOML data at `key` and coerces it to `uint256[]`. + function parseTomlUintArray(string calldata toml, string calldata key) external pure returns (uint256[] memory); + + /// ABI-encodes a TOML table. + function parseToml(string calldata toml) external pure returns (bytes memory abiEncodedData); + + /// ABI-encodes a TOML table at `key`. + function parseToml(string calldata toml, string calldata key) external pure returns (bytes memory abiEncodedData); + + /// Takes serialized JSON, converts to TOML and write a serialized TOML to a file. + function writeToml(string calldata json, string calldata path) external; + + /// Takes serialized JSON, converts to TOML and write a serialized TOML table to an **existing** TOML file, replacing a value with key = + /// This is useful to replace a specific value of a TOML file, without having to parse the entire thing. + function writeToml(string calldata json, string calldata path, string calldata valueKey) external; + + // ======== Utilities ======== + + /// Compute the address of a contract created with CREATE2 using the given CREATE2 deployer. + function computeCreate2Address(bytes32 salt, bytes32 initCodeHash, address deployer) + external + pure + returns (address); + + /// Compute the address of a contract created with CREATE2 using the default CREATE2 deployer. + function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) external pure returns (address); + + /// Compute the address a contract will be deployed at for a given deployer address and nonce. + function computeCreateAddress(address deployer, uint256 nonce) external pure returns (address); + + /// Utility cheatcode to copy storage of `from` contract to another `to` contract. + function copyStorage(address from, address to) external; + + /// Returns ENS namehash for provided string. + function ensNamehash(string calldata name) external pure returns (bytes32); + + /// Gets the label for the specified address. + function getLabel(address account) external view returns (string memory currentLabel); + + /// Labels an address in call traces. + function label(address account, string calldata newLabel) external; + + /// Pauses collection of call traces. Useful in cases when you want to skip tracing of + /// complex calls which are not useful for debugging. + function pauseTracing() external view; + + /// Returns a random `address`. + function randomAddress() external returns (address); + + /// Returns a random `bool`. + function randomBool() external view returns (bool); + + /// Returns a random byte array value of the given length. + function randomBytes(uint256 len) external view returns (bytes memory); + + /// Returns a random fixed-size byte array of length 4. + function randomBytes4() external view returns (bytes4); + + /// Returns a random fixed-size byte array of length 8. + function randomBytes8() external view returns (bytes8); + + /// Returns a random `int256` value. + function randomInt() external view returns (int256); + + /// Returns a random `int256` value of given bits. + function randomInt(uint256 bits) external view returns (int256); + + /// Returns a random uint256 value. + function randomUint() external returns (uint256); + + /// Returns random uint256 value between the provided range (=min..=max). + function randomUint(uint256 min, uint256 max) external returns (uint256); + + /// Returns a random `uint256` value of given bits. + function randomUint(uint256 bits) external view returns (uint256); + + /// Unpauses collection of call traces. + function resumeTracing() external view; + + /// Utility cheatcode to set arbitrary storage for given target address. + function setArbitraryStorage(address target) external; + + /// Encodes a `bytes` value to a base64url string. + function toBase64URL(bytes calldata data) external pure returns (string memory); + + /// Encodes a `string` value to a base64url string. + function toBase64URL(string calldata data) external pure returns (string memory); + + /// Encodes a `bytes` value to a base64 string. + function toBase64(bytes calldata data) external pure returns (string memory); + + /// Encodes a `string` value to a base64 string. + function toBase64(string calldata data) external pure returns (string memory); +} + +/// 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 ======== + + /// Returns the identifier of the currently active fork. Reverts if no fork is currently active. + function activeFork() external view returns (uint256 forkId); + + /// In forking mode, explicitly grant the given address cheatcode access. + function allowCheatcodes(address account) external; + + /// Sets `block.blobbasefee` + function blobBaseFee(uint256 newBlobBaseFee) external; + + /// Sets the blobhashes in the transaction. + /// Not available on EVM versions before Cancun. + /// If used on unsupported EVM versions it will revert. + function blobhashes(bytes32[] calldata hashes) external; + + /// Sets `block.chainid`. + function chainId(uint256 newChainId) external; + + /// Clears all mocked calls. + function clearMockedCalls() external; + + /// Clones a source account code, state, balance and nonce to a target account and updates in-memory EVM state. + function cloneAccount(address source, address target) external; + + /// Sets `block.coinbase`. + function coinbase(address newCoinbase) external; + + /// 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 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 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 the latest block and returns the identifier of the fork. + function createSelectFork(string calldata urlOrAlias) 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); + + /// Sets an address' balance. + function deal(address account, uint256 newBalance) external; + + /// Removes the snapshot with the given ID created by `snapshot`. + /// Takes the snapshot ID to delete. + /// Returns `true` if the snapshot was successfully deleted. + /// Returns `false` if the snapshot does not exist. + function deleteStateSnapshot(uint256 snapshotId) external returns (bool success); + + /// Removes _all_ snapshots previously created by `snapshot`. + function deleteStateSnapshots() external; + + /// Sets `block.difficulty`. + /// Not available on EVM versions from Paris onwards. Use `prevrandao` instead. + /// Reverts if used on unsupported EVM versions. + function difficulty(uint256 newDifficulty) external; + + /// Dump a genesis JSON file's `allocs` to disk. + function dumpState(string calldata pathToStateJson) external; + + /// Sets an address' code. + function etch(address target, bytes calldata newRuntimeBytecode) external; + + /// Sets `block.basefee`. + function fee(uint256 newBasefee) external; + + /// Gets the blockhashes from the current transaction. + /// Not available on EVM versions before Cancun. + /// If used on unsupported EVM versions it will revert. + function getBlobhashes() external view returns (bytes32[] memory hashes); + + /// Returns true if the account is marked as persistent. + function isPersistent(address account) external view returns (bool persistent); + + /// Load a genesis JSON file's `allocs` into the in-memory EVM state. + function loadAllocs(string calldata pathToAllocsJson) 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; + + /// See `makePersistent(address)`. + function makePersistent(address account0, address account1) external; + + /// See `makePersistent(address)`. + function makePersistent(address account0, address account1, address account2) external; + + /// See `makePersistent(address)`. + function makePersistent(address[] calldata accounts) 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; + + /// Reverts a call to an address with specified revert data. + /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. + function mockCallRevert(address callee, bytes4 data, bytes calldata revertData) external; + + /// Reverts a call to an address with a specific `msg.value`, with specified revert data. + /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. + function mockCallRevert(address callee, uint256 msgValue, bytes4 data, bytes calldata revertData) 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; + + /// 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. + /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. + function mockCall(address callee, bytes4 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. + /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. + function mockCall(address callee, uint256 msgValue, bytes4 data, bytes calldata returnData) external; + + /// Mocks multiple calls to an address, returning specified data for each call. + function mockCalls(address callee, bytes calldata data, bytes[] calldata returnData) external; + + /// Mocks multiple calls to an address with a specific `msg.value`, returning specified data for each call. + function mockCalls(address callee, uint256 msgValue, bytes calldata data, bytes[] calldata returnData) external; + + /// Whenever a call is made to `callee` with calldata `data`, this cheatcode instead calls + /// `target` with the same calldata. This functionality is similar to a delegate call made to + /// `target` contract from `callee`. + /// Can be used to substitute a call to a function with another implementation that captures + /// the primary logic of the original function but is easier to reason about. + /// If calldata is not a strict match then partial match by selector is attempted. + function mockFunction(address callee, address target, bytes calldata data) external; + + /// Sets the *next* call's `msg.sender` to be the input address. + function prank(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 the *next* delegate call's `msg.sender` to be the input address. + function prank(address msgSender, bool delegateCall) external; + + /// Sets the *next* delegate call's `msg.sender` to be the input address, and the `tx.origin` to be the second input. + function prank(address msgSender, address txOrigin, bool delegateCall) 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.prevrandao`. + /// Not available on EVM versions before Paris. Use `difficulty` instead. + /// If used on unsupported EVM versions it will revert. + function prevrandao(uint256 newPrevrandao) 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); + + /// Resets the nonce of an account to 0 for EOAs and 1 for contract accounts. + function resetNonce(address account) external; + + /// Revert the state of the EVM to a previous snapshot + /// Takes the snapshot ID to revert to. + /// Returns `true` if the snapshot was successfully reverted. + /// Returns `false` if the snapshot does not exist. + /// **Note:** This does not automatically delete the snapshot. To delete the snapshot use `deleteStateSnapshot`. + function revertToState(uint256 snapshotId) external returns (bool success); + + /// Revert the state of the EVM to a previous snapshot and automatically deletes the snapshots + /// Takes the snapshot ID to revert to. + /// Returns `true` if the snapshot was successfully reverted and deleted. + /// Returns `false` if the snapshot does not exist. + function revertToStateAndDelete(uint256 snapshotId) external returns (bool success); + + /// Revokes persistent status from the address, previously added via `makePersistent`. + function revokePersistent(address account) external; + + /// See `revokePersistent(address)`. + function revokePersistent(address[] calldata accounts) external; + + /// Sets `block.height`. + function roll(uint256 newHeight) external; + + /// 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; + + /// Set blockhash for the current block. + /// It only sets the blockhash for blocks where `block.number - 256 <= number < block.number`. + function setBlockhash(uint256 blockNumber, bytes32 blockHash) 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; + + /// Snapshot capture the gas usage of the last call by name from the callee perspective. + function snapshotGasLastCall(string calldata name) external returns (uint256 gasUsed); + + /// Snapshot capture the gas usage of the last call by name in a group from the callee perspective. + function snapshotGasLastCall(string calldata group, string calldata name) external returns (uint256 gasUsed); + + /// Snapshot the current state of the evm. + /// Returns the ID of the snapshot that was created. + /// To revert a snapshot use `revertToState`. + function snapshotState() external returns (uint256 snapshotId); + + /// Snapshot capture an arbitrary numerical value by name. + /// The group name is derived from the contract name. + function snapshotValue(string calldata name, uint256 value) external; + + /// Snapshot capture an arbitrary numerical value by name in a group. + function snapshotValue(string calldata group, string calldata name, uint256 value) external; + + /// Sets all subsequent calls' `msg.sender` to be the input address until `stopPrank` is called. + function startPrank(address msgSender) 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; + + /// Sets all subsequent delegate calls' `msg.sender` to be the input address until `stopPrank` is called. + function startPrank(address msgSender, bool delegateCall) external; + + /// Sets all subsequent delegate 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, bool delegateCall) external; + + /// Start a snapshot capture of the current gas usage by name. + /// The group name is derived from the contract name. + function startSnapshotGas(string calldata name) external; + + /// Start a snapshot capture of the current gas usage by name in a group. + function startSnapshotGas(string calldata group, string calldata name) external; + + /// Resets subsequent calls' `msg.sender` to be `address(this)`. + function stopPrank() external; + + /// Stop the snapshot capture of the current gas by latest snapshot name, capturing the gas used since the start. + function stopSnapshotGas() external returns (uint256 gasUsed); + + /// Stop the snapshot capture of the current gas usage by name, capturing the gas used since the start. + /// The group name is derived from the contract name. + function stopSnapshotGas(string calldata name) external returns (uint256 gasUsed); + + /// Stop the snapshot capture of the current gas usage by name in a group, capturing the gas used since the start. + function stopSnapshotGas(string calldata group, string calldata name) external returns (uint256 gasUsed); + + /// Stores a value to an address' storage slot. + function store(address target, bytes32 slot, bytes32 value) 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; + + /// Sets `tx.gasprice`. + function txGasPrice(uint256 newGasPrice) external; + + /// Sets `block.timestamp`. + function warp(uint256 newTimestamp) external; + + /// `deleteSnapshot` is being deprecated in favor of `deleteStateSnapshot`. It will be removed in future versions. + function deleteSnapshot(uint256 snapshotId) external returns (bool success); + + /// `deleteSnapshots` is being deprecated in favor of `deleteStateSnapshots`. It will be removed in future versions. + function deleteSnapshots() external; + + /// `revertToAndDelete` is being deprecated in favor of `revertToStateAndDelete`. It will be removed in future versions. + function revertToAndDelete(uint256 snapshotId) external returns (bool success); + + /// `revertTo` is being deprecated in favor of `revertToState`. It will be removed in future versions. + function revertTo(uint256 snapshotId) external returns (bool success); + + /// `snapshot` is being deprecated in favor of `snapshotState`. It will be removed in future versions. + function snapshot() external returns (uint256 snapshotId); + + // ======== Testing ======== + + /// 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; + + /// 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; + + /// Prepare an expected anonymous log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData.). + /// Call this function, then emit an anonymous 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 expectEmitAnonymous(bool checkTopic0, bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) + external; + + /// Same as the previous method, but also checks supplied address against emitting contract. + function expectEmitAnonymous( + bool checkTopic0, + bool checkTopic1, + bool checkTopic2, + bool checkTopic3, + bool checkData, + address emitter + ) external; + + /// Prepare an expected anonymous log with all topic and data checks enabled. + /// Call this function, then emit an anonymous 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 expectEmitAnonymous() external; + + /// Same as the previous method, but also checks supplied address against emitting contract. + function expectEmitAnonymous(address emitter) 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; + + /// Expect a given number of logs with the provided topics. + function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, uint64 count) external; + + /// Expect a given number of logs from a specific emitter with the provided topics. + function expectEmit( + bool checkTopic1, + bool checkTopic2, + bool checkTopic3, + bool checkData, + address emitter, + uint64 count + ) external; + + /// Expect a given number of logs with all topic and data checks enabled. + function expectEmit(uint64 count) external; + + /// Expect a given number of logs from a specific emitter with all topic and data checks enabled. + function expectEmit(address emitter, uint64 count) external; + + /// Expects an error on next call that starts with the revert data. + function expectPartialRevert(bytes4 revertData) external; + + /// Expects an error on next call to reverter address, that starts with the revert data. + function expectPartialRevert(bytes4 revertData, address reverter) external; + + /// Expects an error on next call with any revert data. + function expectRevert() external; + + /// Expects an error on next call that exactly matches the revert data. + function expectRevert(bytes4 revertData) external; + + /// Expects a `count` number of reverts from the upcoming calls from the reverter address that match the revert data. + function expectRevert(bytes4 revertData, address reverter, uint64 count) external; + + /// Expects a `count` number of reverts from the upcoming calls from the reverter address that exactly match the revert data. + function expectRevert(bytes calldata revertData, address reverter, uint64 count) external; + + /// Expects an error on next call that exactly matches the revert data. + function expectRevert(bytes calldata revertData) external; + + /// Expects an error with any revert data on next call to reverter address. + function expectRevert(address reverter) external; + + /// Expects an error from reverter address on next call, with any revert data. + function expectRevert(bytes4 revertData, address reverter) external; + + /// Expects an error from reverter address on next call, that exactly matches the revert data. + function expectRevert(bytes calldata revertData, address reverter) external; + + /// Expects a `count` number of reverts from the upcoming calls with any revert data or reverter. + function expectRevert(uint64 count) external; + + /// Expects a `count` number of reverts from the upcoming calls that match the revert data. + function expectRevert(bytes4 revertData, uint64 count) external; + + /// Expects a `count` number of reverts from the upcoming calls that exactly match the revert data. + function expectRevert(bytes calldata revertData, uint64 count) external; + + /// Expects a `count` number of reverts from the upcoming calls from the reverter address. + function expectRevert(address reverter, uint64 count) 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 level of a test. + function skip(bool skipTest) external; + + /// Marks a test as skipped with a reason. Must be called at the top level of a test. + function skip(bool skipTest, string calldata reason) external; + + /// Stops all safe memory expectation in the current subcontext. + function stopExpectSafeMemory() external; +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console.sol new file mode 100644 index 0000000..4fdb667 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console.sol @@ -0,0 +1,1560 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +library console { + address constant CONSOLE_ADDRESS = + 0x000000000000000000636F6e736F6c652e6c6f67; + + function _sendLogPayloadImplementation(bytes memory payload) internal view { + address consoleAddress = CONSOLE_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + pop( + staticcall( + gas(), + consoleAddress, + add(payload, 32), + mload(payload), + 0, + 0 + ) + ) + } + } + + function _castToPure( + function(bytes memory) internal view fnIn + ) internal pure returns (function(bytes memory) pure fnOut) { + assembly { + fnOut := fnIn + } + } + + function _sendLogPayload(bytes memory payload) internal pure { + _castToPure(_sendLogPayloadImplementation)(payload); + } + + 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)); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol new file mode 100644 index 0000000..03531d9 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +import {console as console2} from "./console.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol new file mode 100644 index 0000000..f7dd2b4 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol new file mode 100644 index 0000000..9af4bf8 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol new file mode 100644 index 0000000..ba40806 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol new file mode 100644 index 0000000..391eeb4 --- /dev/null +++ b/typescript/packages/account-modules/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 withdrawal 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 withdrawal. + /// - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol new file mode 100644 index 0000000..0a16f45 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IMulticall3.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IMulticall3.sol new file mode 100644 index 0000000..0d031b7 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/safeconsole.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/safeconsole.sol new file mode 100644 index 0000000..87c475a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/safeconsole.sol @@ -0,0 +1,13937 @@ +// 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; + /// @solidity memory-safe-assembly + assembly { + pureSendLogPayload := fnIn + } + pureSendLogPayload(offset, size); + } + + function _sendLogPayloadView(uint256 offset, uint256 size) private view { + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + assembly { + pureMemcopy := fnIn + } + pureMemcopy(fromOffset, toOffset, length); + } + + function _memcopyView(uint256 fromOffset, uint256 toOffset, uint256 length) private view { + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + assembly { + m0 := mload(sub(offset, 0x60)) + m1 := mload(sub(offset, 0x40)) + m2 := mload(sub(offset, 0x20)) + // Selector of `log(bytes)`. + mstore(sub(offset, 0x60), 0x0be77f56) + mstore(sub(offset, 0x40), 0x20) + mstore(sub(offset, 0x20), length) + } + _sendLogPayload(offset - 0x44, length + 0x44); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + assembly { + m0 := mload(add(endOffset, 0x00)) + m1 := mload(add(endOffset, 0x20)) + m2 := mload(add(endOffset, 0x40)) + } + _memcopy(offset, offset + 0x60, length); + /// @solidity memory-safe-assembly + assembly { + // Selector of `log(bytes)`. + mstore(add(offset, 0x00), 0x0be77f56) + mstore(add(offset, 0x20), 0x20) + mstore(add(offset, 0x40), length) + } + _sendLogPayload(offset + 0x1c, length + 0x44); + _memcopy(offset + 0x60, offset, length); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + // Selector of `log(address)`. + mstore(0x00, 0x2c2ecbc2) + mstore(0x20, p0) + } + _sendLogPayload(0x1c, 0x24); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + } + } + + function log(bool p0) internal pure { + bytes32 m0; + bytes32 m1; + /// @solidity memory-safe-assembly + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + // Selector of `log(bool)`. + mstore(0x00, 0x32458eed) + mstore(0x20, p0) + } + _sendLogPayload(0x1c, 0x24); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + } + } + + function log(uint256 p0) internal pure { + bytes32 m0; + bytes32 m1; + /// @solidity memory-safe-assembly + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + // Selector of `log(uint256)`. + mstore(0x00, 0xf82c50f1) + mstore(0x20, p0) + } + _sendLogPayload(0x1c, 0x24); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + } + } + + function log(bytes32 p0) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(address p0, bool p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(address p0, uint256 p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(bool p0, bool p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(bool p0, uint256 p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(uint256 p0, bool p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(uint256 p0, uint256 p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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; + /// @solidity memory-safe-assembly + 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); + /// @solidity memory-safe-assembly + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol new file mode 100644 index 0000000..acc0c1e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {StdAssertions} from "../src/StdAssertions.sol"; +import {Vm} from "../src/Vm.sol"; + +interface VmInternal is Vm { + function _expectCheatcodeRevert(bytes memory message) external; +} + +contract StdAssertionsTest is StdAssertions { + string constant errorMessage = "User provided message"; + uint256 constant maxDecimals = 77; + + bool constant SHOULD_REVERT = true; + bool constant SHOULD_RETURN = false; + + bool constant STRICT_REVERT_DATA = true; + bool constant NON_STRICT_REVERT_DATA = false; + + VmInternal constant vm = VmInternal(address(uint160(uint256(keccak256("hevm cheat code"))))); + + 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)); + + assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); + } + + 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._expectCheatcodeRevert( + bytes( + string.concat( + "Call return data does not match: ", vm.toString(returnDataA), " != ", vm.toString(returnDataB) + ) + ) + ); + assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); + } + + 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)); + + assertEqCall(targetA, callDataA, targetB, callDataB, NON_STRICT_REVERT_DATA); + } + + 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._expectCheatcodeRevert( + bytes( + string.concat( + "Call revert data does not match: ", vm.toString(revertDataA), " != ", vm.toString(revertDataB) + ) + ) + ); + assertEqCall(targetA, callDataA, targetB, callDataB, STRICT_REVERT_DATA); + } + + 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.expectRevert(bytes("assertion failed")); + this.assertEqCallExternal(targetA, callDataA, targetB, callDataB, strictRevertData); + + vm.expectRevert(bytes("assertion failed")); + this.assertEqCallExternal(targetB, callDataB, targetA, callDataA, strictRevertData); + } + + // Helper function to test outcome of assertEqCall via `expect` cheatcodes + function assertEqCallExternal( + address targetA, + bytes memory callDataA, + address targetB, + bytes memory callDataB, + bool strictRevertData + ) public { + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol new file mode 100644 index 0000000..3ecaa2e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {Test} from "../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://eth-mainnet.alchemyapi.io/v2/WV407BEiBmjNJfKo9Uo_55u0z0ITyCOX"); + assertEq(getChain("optimism_sepolia").rpcUrl, "https://sepolia.optimism.io/"); + assertEq(getChain("arbitrum_one_sepolia").rpcUrl, "https://sepolia-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://eth-mainnet.alchemyapi.io/v2/WV407BEiBmjNJfKo9Uo_55u0z0ITyCOX"); + + // 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"); + } + + // Named with a leading underscore to clarify this is not intended to be run as a normal test, + // and is intended to be used in the below `test_Rpcs` test. + 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. + // Currently commented out since this is slow and public RPCs are flaky, often resulting in failing CI. + // function test_Rpcs() public { + // _testRpc("mainnet"); + // _testRpc("sepolia"); + // _testRpc("holesky"); + // _testRpc("optimism"); + // _testRpc("optimism_sepolia"); + // _testRpc("arbitrum_one"); + // _testRpc("arbitrum_one_sepolia"); + // _testRpc("arbitrum_nova"); + // _testRpc("polygon"); + // _testRpc("polygon_amoy"); + // _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_sepolia"); + // _testRpc("base"); + // _testRpc("blast_sepolia"); + // _testRpc("blast"); + // _testRpc("fantom_opera"); + // _testRpc("fantom_opera_testnet"); + // _testRpc("fraxtal"); + // _testRpc("fraxtal_testnet"); + // _testRpc("berachain_bartio_testnet"); + // _testRpc("flare"); + // _testRpc("flare_coston2"); + // } + + function test_RevertIf_ChainNotFound() 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_RevertIf_SetChain_ChainIdExist_FirstTest() 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_RevertIf_ChainBubbleUp() public { + // We deploy a mock to properly test the revert. + StdChainsMock stdChainsMock = new StdChainsMock(); + + stdChainsMock.exposed_setChain("needs_undefined_env_var", ChainData("", 123456789, "")); + // Forge environment variable error. + vm.expectRevert(); + stdChainsMock.exposed_getChain("needs_undefined_env_var"); + } + + function test_RevertIf_SetChain_ChainIdExists_SecondTest() 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_RevertIf_SetEmptyAlias() 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_RevertIf_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_RevertIf_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_RevertIf_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_RevertIf_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_RevertIf_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", 9999999999999999999, "https://modified.chain/")); + vm.expectRevert("StdChains getChain(uint256): Chain with ID 123456789 not found."); + stdChainsMock.exposed_getChain(123456789); + + Chain memory modifiedChain = getChain(9999999999999999999); + assertEq(modifiedChain.name, "Modified Chain"); + assertEq(modifiedChain.chainId, 9999999999999999999); + assertEq(modifiedChain.rpcUrl, "https://modified.chain/"); + } + + function test_RevertIf_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(); + stdChainsMock.exposed_getChain(31337); + vm.expectRevert(); + stdChainsMock.exposed_getChain("sepolia"); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol new file mode 100644 index 0000000..0a5a832 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol @@ -0,0 +1,618 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {StdCheats} from "../src/StdCheats.sol"; +import {Test} from "../src/Test.sol"; +import {stdJson} from "../src/StdJson.sol"; +import {stdToml} from "../src/StdToml.sol"; +import {IERC20} from "../src/interfaces/IERC20.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 test_DealToken() 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_RevertIf_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 pure { + 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 view { + 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 view { + 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(); + + 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_sepolia").chainId); + assertTrue( + addr < address(1) || (addr > address(9) && addr < address(0x4200000000000000000000000000000000000000)) + || addr > address(0x4200000000000000000000000000000000000800) + ); + } + + function testFuzz_AssumeNotForgeAddress(address addr) external pure { + assumeNotForgeAddress(addr); + assertTrue( + addr != address(vm) && addr != 0x000000000000000000636F6e736F6c652e6c6f67 + && addr != 0x4e59b44847b379578588920cA78FbF26c0B4956C + ); + } + + function test_RevertIf_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_RevertIf_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 view { + assumeNotBlacklisted(SHIB, addr); + assertTrue(true); + } + + function test_RevertIf_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 view { + assumeNotBlacklisted(USDC, addr); + assertFalse(USDCLike(USDC).isBlacklisted(addr)); + } + + function test_RevertIf_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 view { + assumeNotBlacklisted(USDT, addr); + assertFalse(USDTLike(USDT).isBlackListed(addr)); + } + + function test_dealUSDC() external { + // roll fork to the point when USDC contract updated to store balance in packed slots + vm.rollFork(19279215); + + uint256 balance = 100e6; + deal(USDC, address(this), balance); + assertEq(IERC20(USDC).balanceOf(address(this)), balance); + } +} + +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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol new file mode 100644 index 0000000..29803d5 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import {stdError} from "../src/StdError.sol"; +import {Test} from "../src/Test.sol"; + +contract StdErrorsTest is Test { + ErrorsTest test; + + function setUp() public { + test = new ErrorsTest(); + } + + function test_RevertIf_AssertionError() public { + vm.expectRevert(stdError.assertionError); + test.assertionError(); + } + + function test_RevertIf_ArithmeticError() public { + vm.expectRevert(stdError.arithmeticError); + test.arithmeticError(10); + } + + function test_RevertIf_DivisionError() public { + vm.expectRevert(stdError.divisionError); + test.divError(0); + } + + function test_RevertIf_ModError() public { + vm.expectRevert(stdError.divisionError); + test.modError(0); + } + + function test_RevertIf_EnumConversionError() public { + vm.expectRevert(stdError.enumConversionError); + test.enumConversion(1); + } + + function test_RevertIf_EncodeStgError() public { + vm.expectRevert(stdError.encodeStorageError); + test.encodeStgError(); + } + + function test_RevertIf_PopError() public { + vm.expectRevert(stdError.popError); + test.pop(); + } + + function test_RevertIf_IndexOOBError() public { + vm.expectRevert(stdError.indexOOBError); + test.indexOOBError(1); + } + + function test_RevertIf_MemOverflowError() public { + vm.expectRevert(stdError.memOverflowError); + test.mem(); + } + + function test_RevertIf_InternError() 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdJson.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdJson.t.sol new file mode 100644 index 0000000..6bedfcc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdJson.t.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {Test, stdJson} from "../src/Test.sol"; + +contract StdJsonTest is Test { + using stdJson for string; + + string root; + string path; + + function setUp() public { + root = vm.projectRoot(); + path = string.concat(root, "/test/fixtures/test.json"); + } + + struct SimpleJson { + uint256 a; + string b; + } + + struct NestedJson { + uint256 a; + string b; + SimpleJson c; + } + + function test_readJson() public view { + string memory json = vm.readFile(path); + assertEq(json.readUint(".a"), 123); + } + + function test_writeJson() public { + string memory json = "json"; + json.serialize("a", uint256(123)); + string memory semiFinal = json.serialize("b", string("test")); + string memory finalJson = json.serialize("c", semiFinal); + finalJson.write(path); + + string memory json_ = vm.readFile(path); + bytes memory data = json_.parseRaw("$"); + NestedJson memory decodedData = abi.decode(data, (NestedJson)); + + assertEq(decodedData.a, 123); + assertEq(decodedData.b, "test"); + assertEq(decodedData.c.a, 123); + assertEq(decodedData.c.b, "test"); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol new file mode 100644 index 0000000..d1269a0 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import {stdMath} from "../src/StdMath.sol"; +import {Test, stdError} from "../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 pure { + 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 pure { + uint256 manualAbs = getAbs(a); + + uint256 abs = stdMath.abs(a); + + assertEq(abs, manualAbs); + } + + function test_GetDelta_Uint() external pure { + 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 pure { + uint256 manualDelta = a > b ? a - b : b - a; + + uint256 delta = stdMath.delta(a, b); + + assertEq(delta, manualDelta); + } + + function test_GetDelta_Int() external pure { + 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 pure { + 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 pure { + vm.assume(b != 0); + uint256 manualDelta = a > b ? a - b : 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 pure { + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol new file mode 100644 index 0000000..46604f8 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol @@ -0,0 +1,488 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {stdStorage, StdStorage} from "../src/StdStorage.sol"; +import {Test} from "../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 testFuzz_StorageCheckedWriteMapPacked(address addr, uint128 value) public { + stdstore.enable_packed_slots().target(address(test)).sig(test.read_struct_lower.selector).with_key(addr) + .checked_write(value); + assertEq(test.read_struct_lower(addr), value); + + stdstore.enable_packed_slots().target(address(test)).sig(test.read_struct_upper.selector).with_key(addr) + .checked_write(value); + assertEq(test.read_struct_upper(addr), value); + } + + function test_StorageCheckedWriteMapPackedFullSuccess() 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 test_RevertStorageConst() public { + StorageTestTarget target = new StorageTestTarget(test); + + vm.expectRevert("stdStorage find(StdStorage): No storage use detected for target."); + target.expectRevertStorageConst(); + } + + function testFuzz_StorageNativePack(uint248 val1, uint248 val2, bool boolVal1, bool boolVal2) public { + stdstore.enable_packed_slots().target(address(test)).sig(test.tA.selector).checked_write(val1); + stdstore.enable_packed_slots().target(address(test)).sig(test.tB.selector).checked_write(boolVal1); + stdstore.enable_packed_slots().target(address(test)).sig(test.tC.selector).checked_write(boolVal2); + stdstore.enable_packed_slots().target(address(test)).sig(test.tD.selector).checked_write(val2); + + assertEq(test.tA(), val1); + assertEq(test.tB(), boolVal1); + assertEq(test.tC(), boolVal2); + assertEq(test.tD(), val2); + } + + 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_RevertIf_ReadingNonBoolValue() 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); + } + + function testFuzz_Packed(uint256 val, uint8 elemToGet) public { + // This function tries an assortment of packed slots, shifts meaning number of elements + // that are packed. Shiftsizes are the size of each element, i.e. 8 means a data type that is 8 bits, 16 == 16 bits, etc. + // Combined, these determine how a slot is packed. Making it random is too hard to avoid global rejection limit + // and make it performant. + + // change the number of shifts + for (uint256 i = 1; i < 5; i++) { + uint256 shifts = i; + + elemToGet = uint8(bound(elemToGet, 0, shifts - 1)); + + uint256[] memory shiftSizes = new uint256[](shifts); + for (uint256 j; j < shifts; j++) { + shiftSizes[j] = 8 * (j + 1); + } + + test.setRandomPacking(val); + + uint256 leftBits; + uint256 rightBits; + for (uint256 j; j < shiftSizes.length; j++) { + if (j < elemToGet) { + leftBits += shiftSizes[j]; + } else if (elemToGet != j) { + rightBits += shiftSizes[j]; + } + } + + // we may have some right bits unaccounted for + leftBits += 256 - (leftBits + shiftSizes[elemToGet] + rightBits); + // clear left bits, then clear right bits and realign + uint256 expectedValToRead = (val << leftBits) >> (leftBits + rightBits); + + uint256 readVal = stdstore.target(address(test)).enable_packed_slots().sig( + "getRandomPacked(uint8,uint8[],uint8)" + ).with_calldata(abi.encode(shifts, shiftSizes, elemToGet)).read_uint(); + + assertEq(readVal, expectedValToRead); + } + } + + function testFuzz_Packed2(uint256 nvars, uint256 seed) public { + // Number of random variables to generate. + nvars = bound(nvars, 1, 20); + + // This will decrease as we generate values in the below loop. + uint256 bitsRemaining = 256; + + // Generate a random value and size for each variable. + uint256[] memory vals = new uint256[](nvars); + uint256[] memory sizes = new uint256[](nvars); + uint256[] memory offsets = new uint256[](nvars); + + for (uint256 i = 0; i < nvars; i++) { + // Generate a random value and size. + offsets[i] = i == 0 ? 0 : offsets[i - 1] + sizes[i - 1]; + + uint256 nvarsRemaining = nvars - i; + uint256 maxVarSize = bitsRemaining - nvarsRemaining + 1; + sizes[i] = bound(uint256(keccak256(abi.encodePacked(seed, i + 256))), 1, maxVarSize); + bitsRemaining -= sizes[i]; + + uint256 maxVal; + uint256 varSize = sizes[i]; + assembly { + // mask = (1 << varSize) - 1 + maxVal := sub(shl(varSize, 1), 1) + } + vals[i] = bound(uint256(keccak256(abi.encodePacked(seed, i))), 0, maxVal); + } + + // Pack all values into the slot. + for (uint256 i = 0; i < nvars; i++) { + stdstore.enable_packed_slots().target(address(test)).sig("getRandomPacked(uint256,uint256)").with_key( + sizes[i] + ).with_key(offsets[i]).checked_write(vals[i]); + } + + // Verify the read data matches. + for (uint256 i = 0; i < nvars; i++) { + uint256 readVal = stdstore.enable_packed_slots().target(address(test)).sig( + "getRandomPacked(uint256,uint256)" + ).with_key(sizes[i]).with_key(offsets[i]).read_uint(); + + uint256 retVal = test.getRandomPacked(sizes[i], offsets[i]); + + assertEq(readVal, vals[i]); + assertEq(retVal, vals[i]); + } + } + + function testEdgeCaseArray() public { + stdstore.target(address(test)).sig("edgeCaseArray(uint256)").with_key(uint256(0)).checked_write(1); + assertEq(test.edgeCaseArray(0), 1); + } +} + +contract StorageTestTarget { + using stdStorage for StdStorage; + + StdStorage internal stdstore; + StorageTest internal test; + + constructor(StorageTest test_) { + test = test_; + } + + function expectRevertStorageConst() public { + stdstore.target(address(test)).sig("const()").find(); + } +} + +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"); + + uint256 randomPacking; + + // Array with length matching values of elements. + uint256[] public edgeCaseArray = [3, 3, 3]; + + 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; + } + + function setRandomPacking(uint256 val) public { + randomPacking = val; + } + + function _getMask(uint256 size) internal pure returns (uint256 mask) { + assembly { + // mask = (1 << size) - 1 + mask := sub(shl(size, 1), 1) + } + } + + function setRandomPacking(uint256 val, uint256 size, uint256 offset) public { + // Generate mask based on the size of the value + uint256 mask = _getMask(size); + // Zero out all bits for the word we're about to set + uint256 cleanedWord = randomPacking & ~(mask << offset); + // Place val in the correct spot of the cleaned word + randomPacking = cleanedWord | val << offset; + } + + function getRandomPacked(uint256 size, uint256 offset) public view returns (uint256) { + // Generate mask based on the size of the value + uint256 mask = _getMask(size); + // Shift to place the bits in the correct position, and use mask to zero out remaining bits + return (randomPacking >> offset) & mask; + } + + function getRandomPacked(uint8 shifts, uint8[] memory shiftSizes, uint8 elem) public view returns (uint256) { + require(elem < shifts, "!elem"); + uint256 leftBits; + uint256 rightBits; + + for (uint256 i; i < shiftSizes.length; i++) { + if (i < elem) { + leftBits += shiftSizes[i]; + } else if (elem != i) { + rightBits += shiftSizes[i]; + } + } + + // we may have some right bits unaccounted for + leftBits += 256 - (leftBits + shiftSizes[elem] + rightBits); + + // clear left bits, then clear right bits and realign + return (randomPacking << leftBits) >> (leftBits + rightBits); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStyle.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStyle.t.sol new file mode 100644 index 0000000..974e756 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStyle.t.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {Test, console2, StdStyle} from "../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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdToml.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdToml.t.sol new file mode 100644 index 0000000..5a45f4f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdToml.t.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {Test, stdToml} from "../src/Test.sol"; + +contract StdTomlTest is Test { + using stdToml for string; + + string root; + string path; + + function setUp() public { + root = vm.projectRoot(); + path = string.concat(root, "/test/fixtures/test.toml"); + } + + struct SimpleToml { + uint256 a; + string b; + } + + struct NestedToml { + uint256 a; + string b; + SimpleToml c; + } + + function test_readToml() public view { + string memory json = vm.readFile(path); + assertEq(json.readUint(".a"), 123); + } + + function test_writeToml() public { + string memory json = "json"; + json.serialize("a", uint256(123)); + string memory semiFinal = json.serialize("b", string("test")); + string memory finalJson = json.serialize("c", semiFinal); + finalJson.write(path); + + string memory toml = vm.readFile(path); + bytes memory data = toml.parseRaw("$"); + NestedToml memory decodedData = abi.decode(data, (NestedToml)); + + assertEq(decodedData.a, 123); + assertEq(decodedData.b, "test"); + assertEq(decodedData.c.a, 123); + assertEq(decodedData.c.b, "test"); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol new file mode 100644 index 0000000..aee801b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {Test, StdUtils} from "../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 pure returns (int256) { + return bound(num, min, max); + } + + function exposed_bound(uint256 num, uint256 min, uint256 max) external pure 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 pure { + 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 pure { + 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 pure { + 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 testFuzz_Bound_DistributionIsEven(uint256 min, uint256 size) public pure { + 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 testFuzz_Bound(uint256 num, uint256 min, uint256 max) public pure { + 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 pure { + 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_RevertIf_BoundMaxLessThanMin() 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 testFuzz_RevertIf_BoundMaxLessThanMin(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 pure { + 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 pure { + 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 pure { + 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 testFuzz_BoundInt_DistributionIsEven(int256 min, uint256 size) public pure { + 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 testFuzz_BoundInt(int256 num, int256 min, int256 max) public pure { + 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 pure { + 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 pure { + 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_RevertIf_BoundIntMaxLessThanMin() 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 testFuzz_RevertIf_BoundIntMaxLessThanMin(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 pure { + 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 pure { + 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_RevertIf_BytesLengthExceeds32() 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 pure { + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + uint256 nonce = 14; + address createAddress = computeCreateAddress(deployer, nonce); + assertEq(createAddress, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); + } + + /*////////////////////////////////////////////////////////////////////////// + COMPUTE CREATE2 ADDRESS + //////////////////////////////////////////////////////////////////////////*/ + + function test_ComputeCreate2Address() external pure { + 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 pure { + 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_RevertIf_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_RevertIf_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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/Vm.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/Vm.t.sol new file mode 100644 index 0000000..7c766b1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/Vm.t.sol @@ -0,0 +1,18 @@ +// 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"; + +// These tests ensure that functions are never accidentally removed from a Vm interface, or +// inadvertently moved between Vm and VmSafe. These tests must be updated each time a function is +// added to or removed from Vm or VmSafe. +contract VmTest is Test { + function test_VmInterfaceId() public pure { + assertEq(type(Vm).interfaceId, bytes4(0xdb28dd7b), "Vm"); + } + + function test_VmSafeInterfaceId() public pure { + assertEq(type(VmSafe).interfaceId, bytes4(0xb572f44f), "VmSafe"); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol new file mode 100644 index 0000000..e205cff --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol new file mode 100644 index 0000000..ce8e0e9 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol new file mode 100644 index 0000000..9beeafe --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol new file mode 100644 index 0000000..e993535 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/broadcast.log.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/broadcast.log.json new file mode 100644 index 0000000..0a0200b --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.json new file mode 100644 index 0000000..caebf6d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.json @@ -0,0 +1,8 @@ +{ + "a": 123, + "b": "test", + "c": { + "a": 123, + "b": "test" + } +} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.toml b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.toml new file mode 100644 index 0000000..60692bc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.toml @@ -0,0 +1,6 @@ +a = 123 +b = "test" + +[c] +a = 123 +b = "test" diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/LICENSE b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/LICENSE new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/README.md new file mode 100644 index 0000000..209c2cf --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/README.md @@ -0,0 +1,97 @@ +# Halmos Cheat Codes + +Halmos cheatcodes are abstract functions designed to facilitate writing symbolic tests, such as the creation of new symbolic values at runtime. While these cheatcodes are currently exclusive to [Halmos][halmos], they are not limited to it and could potentially be supported by other symbolic testing tools in the future. + +Please refer to [the list of currently available cheatcodes][list]. More cheatcodes will be added in the future. + +Join the [Halmos Telegram Group][chat] for any inquiries or further discussions. + +[halmos]: +[list]: +[chat]: + +## Installation + +To install using Foundry: +``` +forge install a16z/halmos-cheatcodes +``` +Alternatively, you can directly add it as a submodule: +``` +git submodule add https://github.com/a16z/halmos-cheatcodes +``` + +## Example usage + +Below is an example of a symbolic test that checks for potential unauthorized access to others' tokens. The approach involves setting up an initial symbolic state of the token contract, executing an arbitrary function call to the token contract, and checking if there is an execution path that increases the caller's balance and/or decreases the balance of others. This example illustrates how to utilize cheatcodes to set up initial symbolic states and execute arbitrary function calls. + +```solidity +// import Halmos cheatcodes +import {SymTest} from "halmos-cheatcodes/SymTest.sol"; + +import {Test} from "forge-std/Test.sol"; + +import {Token} from "/path/to/Token.sol"; + +contract TokenTest is SymTest, Test { + Token token; + + function setUp() public { + token = new Token(); + + // set the balances of three arbitrary accounts to arbitrary symbolic values + for (uint256 i = 0; i < 3; i++) { + address receiver = svm.createAddress('receiver'); // create a new symbolic address + uint256 amount = svm.createUint256('amount'); // create a new symbolic uint256 value + token.transfer(receiver, amount); + } + } + + function checkBalanceUpdate() public { + // consider two arbitrary distinct accounts + address caller = svm.createAddress('caller'); // create a symbolic address + address others = svm.createAddress('others'); // create another symbolic address + vm.assume(others != caller); // assume the two addresses are different + + // record their current balances + uint256 oldBalanceCaller = token.balanceOf(caller); + uint256 oldBalanceOthers = token.balanceOf(others); + + // execute an arbitrary function call to the token from the caller + vm.prank(caller); + uint256 dataSize = 100; // the max calldata size for the public functions in the token + bytes memory data = svm.createBytes(dataSize, 'data'); // create a symbolic calldata + address(token).call(data); + + // ensure that the caller cannot spend others' tokens + assert(token.balanceOf(caller) <= oldBalanceCaller); // cannot increase their own balance + assert(token.balanceOf(others) >= oldBalanceOthers); // cannot decrease others' balance + } +} +``` + +When running the above test against the following buggy token contract, Halmos will provide a counterexample that may be overlooked during manual reviews. + +```solidity +/// @notice This is a buggy token contract. DO NOT use it in production. +contract Token { + mapping(address => uint) public balanceOf; + + constructor() public { + balanceOf[msg.sender] = 1e27; + } + + function transfer(address to, uint amount) public { + _transfer(msg.sender, to, amount); + } + + function _transfer(address from, address to, uint amount) public { + balanceOf[from] -= amount; + balanceOf[to] += amount; + } +} +``` + +## Disclaimer + +_These smart contracts and code 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 and code. 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 AND CODE 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 and code 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 and code 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SVM.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SVM.sol new file mode 100644 index 0000000..b42c25c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SVM.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +/// @notice Symbolic Virtual Machine +interface SVM { + // Create a new symbolic uint value ranging over [0, 2**bitSize - 1] (inclusive) + function createUint(uint256 bitSize, string memory name) external pure returns (uint256 value); + + // Create a new symbolic uint256 value + function createUint256(string memory name) external pure returns (uint256 value); + + // Create a new symbolic signed int value + function createInt(uint256 bitSize, string memory name) external pure returns (int256 value); + + // Create a new symbolic int256 value + function createInt256(string memory name) external pure returns (int256 value); + + // Create a new symbolic byte array with the given byte size + function createBytes(uint256 byteSize, string memory name) external pure returns (bytes memory value); + + // Create a new symbolic string backed by a symbolic array with the given byte size + function createString(uint256 byteSize, string memory name) external pure returns (string memory value); + + // Create a new symbolic bytes32 value + function createBytes32(string memory name) external pure returns (bytes32 value); + + // Create a new symbolic bytes4 value + function createBytes4(string memory name) external pure returns (bytes4 value); + + // Create a new symbolic address value + function createAddress(string memory name) external pure returns (address value); + + // Create a new symbolic boolean value + function createBool(string memory name) external pure returns (bool value); + + // Create arbitrary symbolic calldata for the given contract or interface name. + // An exception is thrown if the contract name exists in multiple files. An optional filename (with .sol extension) can be provided to avoid ambiguity. + // By default, view and pure functions are excluded. An optional boolean flag can be set to include view and pure functions. + function createCalldata(string memory contractOrInterfaceName) external pure returns (bytes memory data); + function createCalldata(string memory contractOrInterfaceName, bool includeViewAndPureFunctions) external pure returns (bytes memory data); + function createCalldata(string memory filename, string memory contractOrInterfaceName) external pure returns (bytes memory data); + function createCalldata(string memory filename, string memory contractOrInterfaceName, bool includeViewAndPureFunctions) external pure returns (bytes memory data); + + // Assign symbolic values to uninitialized storage slots + function enableSymbolicStorage(address) external; + + // Snapshot the current storage of the given account and return a snapshot ID + function snapshotStorage(address) external returns (uint256 id); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SymTest.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SymTest.sol new file mode 100644 index 0000000..96684ed --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SymTest.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import {SVM} from "./SVM.sol"; + +abstract contract SymTest { + // SVM cheat code address: 0xf3993a62377bcd56ae39d773740a5390411e8bc9 + address internal constant SVM_ADDRESS = address(uint160(uint256(keccak256("svm cheat code")))); + + SVM internal constant svm = SVM(SVM_ADDRESS); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/logo.svg b/typescript/packages/account-modules/lib/openzeppelin-contracts/logo.svg new file mode 100644 index 0000000..f1e14c2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/logo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/netlify.toml b/typescript/packages/account-modules/lib/openzeppelin-contracts/netlify.toml new file mode 100644 index 0000000..0447f41 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/netlify.toml @@ -0,0 +1,3 @@ +[build] +command = "npm run docs" +publish = "build/site" diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/package-lock.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/package-lock.json new file mode 100644 index 0000000..acbc992 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/package-lock.json @@ -0,0 +1,10552 @@ +{ + "name": "openzeppelin-solidity", + "version": "5.3.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "openzeppelin-solidity", + "version": "5.3.0", + "license": "MIT", + "devDependencies": { + "@changesets/changelog-github": "^0.5.0", + "@changesets/cli": "^2.26.0", + "@changesets/pre": "^2.0.0", + "@changesets/read": "^0.6.0", + "@eslint/compat": "^1.2.1", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.6", + "@nomicfoundation/hardhat-ethers": "^3.0.4", + "@nomicfoundation/hardhat-network-helpers": "^1.0.3", + "@openzeppelin/docs-utils": "^0.1.5", + "@openzeppelin/merkle-tree": "^1.0.7", + "@openzeppelin/upgrade-safe-transpiler": "^0.3.32", + "@openzeppelin/upgrades-core": "^1.20.6", + "chai": "^4.2.0", + "eslint": "^9.0.0", + "eslint-config-prettier": "^10.0.0", + "ethers": "^6.14.0", + "glob": "^11.0.0", + "globals": "^16.0.0", + "graphlib": "^2.1.8", + "hardhat": "^2.24.0", + "hardhat-exposed": "^0.3.15", + "hardhat-gas-reporter": "^2.1.0", + "hardhat-ignore-warnings": "^0.2.11", + "husky": "^9.1.7", + "lint-staged": "^16.0.0", + "lodash.startcase": "^4.4.0", + "micromatch": "^4.0.2", + "p-limit": "^6.0.0", + "prettier": "^3.0.0", + "prettier-plugin-solidity": "^1.1.0", + "rimraf": "^6.0.0", + "semver": "^7.3.5", + "solhint": "^5.0.0", + "solhint-plugin-openzeppelin": "file:scripts/solhint-custom", + "solidity-ast": "^0.4.50", + "solidity-coverage": "^0.8.14", + "solidity-docgen": "^0.6.0-beta.29", + "undici": "^7.4.0", + "yargs": "^17.0.0" + } + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bytecodealliance/preview2-shim": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.0.tgz", + "integrity": "sha512-JorcEwe4ud0x5BS/Ar2aQWOQoFzjq/7jcnxYXCvSMh0oRm0dQXzOA+hqLDBnOMks1LLBA7dmiLLsEBl09Yd6iQ==", + "dev": true, + "license": "(Apache-2.0 WITH LLVM-exception)" + }, + "node_modules/@changesets/apply-release-plan": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-7.0.12.tgz", + "integrity": "sha512-EaET7As5CeuhTzvXTQCRZeBUcisoYPDDcXvgTE/2jmmypKp0RC7LxKj/yzqeh/1qFTZI7oDGFcL1PHRuQuketQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/config": "^3.1.1", + "@changesets/get-version-range-type": "^0.4.0", + "@changesets/git": "^3.0.4", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@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, + "license": "MIT", + "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": "6.0.6", + "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-6.0.6.tgz", + "integrity": "sha512-Frkj8hWJ1FRZiY3kzVCKzS0N5mMwWKwmv9vpam7vt8rZjLL1JMthdh6pSDVSPumHPshTTkKZ0VtNbE0cJHZZUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.3", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/changelog-git": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.1.tgz", + "integrity": "sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0" + } + }, + "node_modules/@changesets/changelog-github": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@changesets/changelog-github/-/changelog-github-0.5.1.tgz", + "integrity": "sha512-BVuHtF+hrhUScSoHnJwTELB4/INQxVFc+P/Qdt20BLiBFIHFJDDUaGsZw+8fQeJTRP5hJZrzpt3oZWh0G19rAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/get-github-info": "^0.6.0", + "@changesets/types": "^6.1.0", + "dotenv": "^8.1.0" + } + }, + "node_modules/@changesets/cli": { + "version": "2.29.2", + "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.29.2.tgz", + "integrity": "sha512-vwDemKjGYMOc0l6WUUTGqyAWH3AmueeyoJa1KmFRtCYiCoY5K3B68ErYpDB6H48T4lLI4czum4IEjh6ildxUeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/apply-release-plan": "^7.0.12", + "@changesets/assemble-release-plan": "^6.0.6", + "@changesets/changelog-git": "^0.2.1", + "@changesets/config": "^3.1.1", + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.3", + "@changesets/get-release-plan": "^4.0.10", + "@changesets/git": "^3.0.4", + "@changesets/logger": "^0.1.1", + "@changesets/pre": "^2.0.2", + "@changesets/read": "^0.6.5", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@changesets/write": "^0.4.0", + "@manypkg/get-packages": "^1.1.3", + "ansi-colors": "^4.1.3", + "ci-info": "^3.7.0", + "enquirer": "^2.4.1", + "external-editor": "^3.1.0", + "fs-extra": "^7.0.1", + "mri": "^1.2.0", + "p-limit": "^2.2.0", + "package-manager-detector": "^0.2.0", + "picocolors": "^1.1.0", + "resolve-from": "^5.0.0", + "semver": "^7.5.3", + "spawndamnit": "^3.0.1", + "term-size": "^2.1.0" + }, + "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, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@changesets/config": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@changesets/config/-/config-3.1.1.tgz", + "integrity": "sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.3", + "@changesets/logger": "^0.1.1", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1", + "micromatch": "^4.0.8" + } + }, + "node_modules/@changesets/errors": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.2.0.tgz", + "integrity": "sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==", + "dev": true, + "license": "MIT", + "dependencies": { + "extendable-error": "^0.1.5" + } + }, + "node_modules/@changesets/get-dependents-graph": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-2.1.3.tgz", + "integrity": "sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "picocolors": "^1.1.0", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/get-github-info": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@changesets/get-github-info/-/get-github-info-0.6.0.tgz", + "integrity": "sha512-v/TSnFVXI8vzX9/w3DU2Ol+UlTZcu3m0kXTjTT4KlAdwSvwutcByYwyYn9hwerPWfPkT2JfpoX0KgvCEi8Q/SA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dataloader": "^1.4.0", + "node-fetch": "^2.5.0" + } + }, + "node_modules/@changesets/get-release-plan": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-4.0.10.tgz", + "integrity": "sha512-CCJ/f3edYaA3MqoEnWvGGuZm0uMEMzNJ97z9hdUR34AOvajSwySwsIzC/bBu3+kuGDsB+cny4FljG8UBWAa7jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/assemble-release-plan": "^6.0.6", + "@changesets/config": "^3.1.1", + "@changesets/pre": "^2.0.2", + "@changesets/read": "^0.6.5", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3" + } + }, + "node_modules/@changesets/get-version-range-type": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.4.0.tgz", + "integrity": "sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@changesets/git": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@changesets/git/-/git-3.0.4.tgz", + "integrity": "sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@manypkg/get-packages": "^1.1.3", + "is-subdir": "^1.1.1", + "micromatch": "^4.0.8", + "spawndamnit": "^3.0.1" + } + }, + "node_modules/@changesets/logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.1.1.tgz", + "integrity": "sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.0" + } + }, + "node_modules/@changesets/parse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.4.1.tgz", + "integrity": "sha512-iwksMs5Bf/wUItfcg+OXrEpravm5rEd9Bf4oyIPL4kVTmJQ7PNDSd6MDYkpSJR1pn7tz/k8Zf2DhTCqX08Ou+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "js-yaml": "^3.13.1" + } + }, + "node_modules/@changesets/pre": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-2.0.2.tgz", + "integrity": "sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1" + } + }, + "node_modules/@changesets/read": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.6.5.tgz", + "integrity": "sha512-UPzNGhsSjHD3Veb0xO/MwvasGe8eMyNrR/sT9gR8Q3DhOQZirgKhhXv/8hVsI0QpPjR004Z9iFxoJU6in3uGMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/git": "^3.0.4", + "@changesets/logger": "^0.1.1", + "@changesets/parse": "^0.4.1", + "@changesets/types": "^6.1.0", + "fs-extra": "^7.0.1", + "p-filter": "^2.1.0", + "picocolors": "^1.1.0" + } + }, + "node_modules/@changesets/should-skip-package": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.2.tgz", + "integrity": "sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3" + } + }, + "node_modules/@changesets/types": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", + "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@changesets/write": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.4.0.tgz", + "integrity": "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "fs-extra": "^7.0.1", + "human-id": "^4.1.1", + "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, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/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, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/compat": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.9.tgz", + "integrity": "sha512-gCdSY54n7k+driCadyMNv8JSPzYLeDVM/ikZRtvtROBpRdFSkS8W9A82MqsaY7lZuwL0wiapgD0NT1xT0hyJsA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.10.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", + "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz", + "integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", + "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.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": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/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, + "license": "MIT", + "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/@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, + "license": "Python-2.0" + }, + "node_modules/@eslint/eslintrc/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/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, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.25.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz", + "integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", + "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.13.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@ethereumjs/common": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-3.2.0.tgz", + "integrity": "sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ethereumjs/util": "^8.1.0", + "crc-32": "^1.2.0" + } + }, + "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, + "license": "MPL-2.0", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/tx": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-4.2.0.tgz", + "integrity": "sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@ethereumjs/common": "^3.2.0", + "@ethereumjs/rlp": "^4.0.1", + "@ethereumjs/util": "^8.1.0", + "ethereum-cryptography": "^2.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/tx/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/tx/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/tx/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/tx/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/tx/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/tx/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "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, + "license": "MPL-2.0", + "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/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.8.0.tgz", + "integrity": "sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz", + "integrity": "sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/networks": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/web": "^5.8.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz", + "integrity": "sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.8.0.tgz", + "integrity": "sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/rlp": "^5.8.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.8.0.tgz", + "integrity": "sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz", + "integrity": "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", + "integrity": "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.8.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.8.0.tgz", + "integrity": "sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/base64": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz", + "integrity": "sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", + "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", + "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" + } + ], + "license": "MIT" + }, + "node_modules/@ethersproject/networks": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", + "integrity": "sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", + "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.8.0.tgz", + "integrity": "sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", + "integrity": "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "bn.js": "^5.2.1", + "elliptic": "6.6.1", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz", + "integrity": "sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz", + "integrity": "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/rlp": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.8.0.tgz", + "integrity": "sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.8.0.tgz", + "integrity": "sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/base64": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=12.x", + "pnpm": "7.5.1" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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, + "license": "ISC", + "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.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@metamask/abi-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@metamask/abi-utils/-/abi-utils-2.0.4.tgz", + "integrity": "sha512-StnIgUB75x7a7AgUhiaUZDpCsqGp7VkNnZh2XivXkJ6mPkE83U8ARGQj5MbRis7VJY8BC5V1AbB1fjdh0hupPQ==", + "dev": true, + "license": "(Apache-2.0 AND MIT)", + "dependencies": { + "@metamask/superstruct": "^3.1.0", + "@metamask/utils": "^9.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/superstruct": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@metamask/superstruct/-/superstruct-3.2.1.tgz", + "integrity": "sha512-fLgJnDOXFmuVlB38rUN5SmU7hAFQcCjrg3Vrxz67KTY7YHFnSNEKvX4avmEBdOI0yTCxZjwMCFEqsC8k2+Wd3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/utils": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-9.3.0.tgz", + "integrity": "sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==", + "dev": true, + "license": "ISC", + "dependencies": { + "@ethereumjs/tx": "^4.2.0", + "@metamask/superstruct": "^3.1.0", + "@noble/hashes": "^1.3.1", + "@scure/base": "^1.1.3", + "@types/debug": "^4.1.7", + "debug": "^4.3.4", + "pony-cause": "^2.1.10", + "semver": "^7.5.4", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.0.tgz", + "integrity": "sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@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/" + } + ], + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nomicfoundation/edr": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.11.0.tgz", + "integrity": "sha512-36WERf8ldvyHR6UAbcYsa+vpbW7tCrJGBwF4gXSsb8+STj1n66Hz85Y/O7B9+8AauX3PhglvV5dKl91tk43mWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/edr-darwin-arm64": "0.11.0", + "@nomicfoundation/edr-darwin-x64": "0.11.0", + "@nomicfoundation/edr-linux-arm64-gnu": "0.11.0", + "@nomicfoundation/edr-linux-arm64-musl": "0.11.0", + "@nomicfoundation/edr-linux-x64-gnu": "0.11.0", + "@nomicfoundation/edr-linux-x64-musl": "0.11.0", + "@nomicfoundation/edr-win32-x64-msvc": "0.11.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-darwin-arm64": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.11.0.tgz", + "integrity": "sha512-aYTVdcSs27XG7ayTzvZ4Yn9z/ABSaUwicrtrYK2NR8IH0ik4N4bWzo/qH8rax6rewVLbHUkGyGYnsy5ZN4iiMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-darwin-x64": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.11.0.tgz", + "integrity": "sha512-RxX7UYgvJrfcyT/uHUn44Nsy1XaoW+Q1khKMdHKxeW7BrgIi+Lz+siz3bX5vhSoAnKilDPhIVLrnC8zxQhjR2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.11.0.tgz", + "integrity": "sha512-J0j+rs0s11FuSipt/ymqrFmpJ7c0FSz1/+FohCIlUXDxFv//+1R/8lkGPjEYFmy8DPpk/iO8mcpqHTGckREbqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-musl": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.11.0.tgz", + "integrity": "sha512-4r32zkGMN7WT/CMEuW0VjbuEdIeCskHNDMW4SSgQSJOE/N9L1KSLJCSsAbPD3aYE+e4WRDTyOwmuLjeUTcLZKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-gnu": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.11.0.tgz", + "integrity": "sha512-SmdncQHLYtVNWLIMyGaY6LpAfamzTDe3fxjkirmJv3CWR5tcEyC6LMui/GsIVnJzXeNJBXAzwl8hTUAxHTM6kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-musl": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.11.0.tgz", + "integrity": "sha512-w6hUqpn/trwiH6SRuRGysj37LsQVCX5XDCA3Xi81sbOaLhbHrNvK9TXWyZmcuzbdTKQQW6VNywcSxDdOiChcJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-win32-x64-msvc": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.11.0.tgz", + "integrity": "sha512-BLmULjRKoH9BsX+c4Na2ypV7NGeJ+M6Zpqj/faPOwleVscDdSr/IhriyPaXCe8dyfwbge7lWsbekiADtPSnB2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/hardhat-chai-matchers": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.8.tgz", + "integrity": "sha512-Z5PiCXH4xhNLASROlSUOADfhfpfhYO6D7Hn9xp8PddmHey0jq704cr6kfU8TRrQ4PUZbpfsZadPj+pCfZdjPIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai-as-promised": "^7.1.3", + "chai-as-promised": "^7.1.1", + "deep-eql": "^4.0.1", + "ordinal": "^1.0.3" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-ethers": "^3.0.0", + "chai": "^4.2.0", + "ethers": "^6.1.0", + "hardhat": "^2.9.4" + } + }, + "node_modules/@nomicfoundation/hardhat-ethers": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.8.tgz", + "integrity": "sha512-zhOZ4hdRORls31DTOqg+GmEZM0ujly8GGIuRY7t7szEk2zW/arY1qDug/py8AEktT00v5K+b6RvbVog+va51IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "lodash.isequal": "^4.5.0" + }, + "peerDependencies": { + "ethers": "^6.1.0", + "hardhat": "^2.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-network-helpers": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.12.tgz", + "integrity": "sha512-xTNQNI/9xkHvjmCJnJOTyqDSl8uq1rKb2WOVmixQxFtRd7Oa3ecO8zM0cyC2YmOK+jHB9WPZ+F/ijkHg1CoORA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ethereumjs-util": "^7.1.4" + }, + "peerDependencies": { + "hardhat": "^2.9.5" + } + }, + "node_modules/@nomicfoundation/slang": { + "version": "0.18.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang/-/slang-0.18.3.tgz", + "integrity": "sha512-YqAWgckqbHM0/CZxi9Nlf4hjk9wUNLC9ngWCWBiqMxPIZmzsVKYuChdlrfeBPQyvQQBoOhbx+7C1005kLVQDZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bytecodealliance/preview2-shim": "0.17.0" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz", + "integrity": "sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.2", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.2", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.2" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz", + "integrity": "sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz", + "integrity": "sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz", + "integrity": "sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz", + "integrity": "sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz", + "integrity": "sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz", + "integrity": "sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz", + "integrity": "sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "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, + "license": "MIT", + "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/merkle-tree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@openzeppelin/merkle-tree/-/merkle-tree-1.0.8.tgz", + "integrity": "sha512-E2c9/Y3vjZXwVvPZKqCKUn7upnvam1P1ZhowJyZVQSkzZm5WhumtaRr+wkUXrZVfkIc7Gfrl7xzabElqDL09ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@metamask/abi-utils": "^2.0.4", + "ethereum-cryptography": "^3.0.0" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrade-safe-transpiler/-/upgrade-safe-transpiler-0.3.33.tgz", + "integrity": "sha512-yKdnfZtfDw0ivonZmDx1YgFJXLNHz/5+XPN7bx/9ObQYKUawmTiOcGC6BKezpphL+witvHQbMhmQbwGIyEoR8g==", + "dev": true, + "license": "MIT", + "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/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/@openzeppelin/upgrades-core": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.44.0.tgz", + "integrity": "sha512-AUnQW7cbh2ntFuQdHi5C0vKB+QfkTQtzXgCmzazXLJDX7slFTF676lw+x97ZKfzwQw5unO1+ALZMx+s+2yQUew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/slang": "^0.18.3", + "bignumber.js": "^9.1.2", + "cbor": "^10.0.0", + "chalk": "^4.1.0", + "compare-versions": "^6.0.0", + "debug": "^4.1.1", + "ethereumjs-util": "^7.0.3", + "minimatch": "^9.0.5", + "minimist": "^1.2.7", + "proper-lockfile": "^4.1.1", + "solidity-ast": "^0.4.60" + }, + "bin": { + "openzeppelin-upgrades-core": "dist/cli/cli.js" + } + }, + "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, + "license": "MIT", + "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/@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, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/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, + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@scure/base": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.5.tgz", + "integrity": "sha512-9rE6EOVeIQzt5TSu4v+K523F8u6DhBsoZWPGKlnCshhlDhy0kJzUX4V+tr2dWmzF1GdekvThABoEQBGBQI7xZw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "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, + "license": "BSD-3-Clause", + "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/core/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, + "license": "0BSD" + }, + "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, + "license": "BSD-3-Clause", + "dependencies": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/hub/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, + "license": "0BSD" + }, + "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, + "license": "BSD-3-Clause", + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/minimal/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, + "license": "0BSD" + }, + "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, + "license": "BSD-3-Clause", + "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/node/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, + "license": "0BSD" + }, + "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, + "license": "MIT", + "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/tracing/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, + "license": "0BSD" + }, + "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, + "license": "BSD-3-Clause", + "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, + "license": "BSD-3-Clause", + "dependencies": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils/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, + "license": "0BSD" + }, + "node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@solidity-parser/parser": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.19.0.tgz", + "integrity": "sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.6.tgz", + "integrity": "sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/chai": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.1.tgz", + "integrity": "sha512-iu1JLYmGmITRzUgNiLMZD3WCoFzpYtueuyAgHTXqgwSRAMIlFTnZqG6/xenkpUGRJEzSfklUTI4GNSzks/dc0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*" + } + }, + "node_modules/@types/chai-as-promised": { + "version": "7.1.8", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", + "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/secp256k1": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz", + "integrity": "sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "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, + "license": "ISC" + }, + "node_modules/abitype": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.8.tgz", + "integrity": "sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3 >=3.22.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.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, + "license": "MIT", + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.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, + "license": "BSD-3-Clause OR MIT", + "optional": true, + "engines": { + "node": ">=0.4.2" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/antlr4": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.2.tgz", + "integrity": "sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=16" + } + }, + "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, + "license": "ISC", + "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, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.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, + "license": "MIT" + }, + "node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "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, + "license": "MIT", + "dependencies": { + "is-windows": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/bignumber.js": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz", + "integrity": "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT" + }, + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/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, + "license": "MIT", + "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/boxen/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, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.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, + "license": "MIT" + }, + "node_modules/brotli-wasm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brotli-wasm/-/brotli-wasm-2.0.1.tgz", + "integrity": "sha512-+3USgYsC7bzb5yU0/p2HnnynZl0ak0E6uoIm4UW4Aby/8s8HFCq6NCfrrf1E9c3O8OCSzq3oYO1tUVqIi61Nww==", + "dev": true, + "license": "Apache-2.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, + "license": "ISC" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request/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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cbor": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-10.0.3.tgz", + "integrity": "sha512-72Jnj81xMsqepqdcSdf2+fflz/UDsThOHy5hj2MW5F5xzHL8Oa0KQ6I6V9CwVUPxg5pf+W9xp6W2KilaRXWWtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "nofilter": "^3.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-as-promised": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", + "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "check-error": "^1.0.2" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 6" + } + }, + "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, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "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" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cipher-base": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", + "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "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, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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, + "license": "MIT", + "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, + "license": "Python-2.0" + }, + "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, + "license": "MIT", + "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, + "license": "Apache-2.0", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "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, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/dataloader": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", + "integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "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.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true, + "license": "BSD-3-Clause", + "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, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "BSD-2-Clause", + "engines": { + "node": ">=10" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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, + "license": "MIT" + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "dev": true, + "license": "MIT", + "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.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint": { + "version": "9.25.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz", + "integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.13.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.25.1", + "@eslint/plugin-kit": "^0.2.8", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.2.tgz", + "integrity": "sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/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, + "license": "MIT", + "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/eslint/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.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, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ethereum-bloom-filters": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.2.0.tgz", + "integrity": "sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.4.0" + } + }, + "node_modules/ethereum-cryptography": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-3.2.0.tgz", + "integrity": "sha512-Urr5YVsalH+Jo0sYkTkv1MyI9bLYZwW8BENZCeE1QYaTHETEYx0Nv/SVsWkSqpYrzweg6d8KMY1wTjH/1m/BIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/ciphers": "1.3.0", + "@noble/curves": "1.9.0", + "@noble/hashes": "1.8.0", + "@scure/bip32": "1.7.0", + "@scure/bip39": "1.6.0" + }, + "engines": { + "node": "^14.21.3 || >=16", + "npm": ">=9" + } + }, + "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, + "license": "MPL-2.0", + "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/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, + "license": "MIT", + "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/ethers": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.14.0.tgz", + "integrity": "sha512-KgHwltNSMdbrGWEyKkM0Rt2s+u1nDH/5BVDQakLinzGEJi4bWindBzZSCC4gKsbZjwDTI6ex/8suR9Ihbmz4IQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "22.7.5", + "aes-js": "4.0.0-beta.5", + "tslib": "2.7.0", + "ws": "8.17.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ethers/node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethers/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethers/node_modules/@types/node": { + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "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.8" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.17" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "ISC" + }, + "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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "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, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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, + "license": "ISC", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/glob": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.2.tgz", + "integrity": "sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "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, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", + "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "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.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/got/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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "ISC" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hardhat": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.24.0.tgz", + "integrity": "sha512-wDkD5GPmttYv21MR7tGDkyQ22tO2V86OEV8pA7NcXWYUpibe8XZ2EanXCeRHO61vwEx0f7/M+NqrhJwasaNMJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ethereumjs/util": "^9.1.0", + "@ethersproject/abi": "^5.1.2", + "@nomicfoundation/edr": "^0.11.0", + "@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", + "boxen": "^5.1.2", + "chokidar": "^4.0.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "find-up": "^5.0.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "json-stream-stringify": "^3.1.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "micro-eth-signer": "^0.14.0", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "picocolors": "^1.1.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.8.26", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tinyglobby": "^0.2.6", + "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.19", + "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.19.tgz", + "integrity": "sha512-vVye5TurJu8dWeo4ma+EfLAOQaJyica4uncd0/BGPO2tmexuDwZUmE1vYx81PlP4Iak3wqkNTEPxWQaE2ZnKnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromatch": "^4.0.8", + "solidity-ast": "^0.4.59" + }, + "peerDependencies": { + "hardhat": "^2.3.0" + } + }, + "node_modules/hardhat-gas-reporter": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-2.2.3.tgz", + "integrity": "sha512-/52fDR0WOgPTjImmx4j179SAgxPv/499TD0o0qnMhaRr24i2cqlcmCW92FJi0QAKu7HcnxdBGZWQP/5aPjQqUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/units": "^5.7.0", + "@solidity-parser/parser": "^0.19.0", + "axios": "^1.6.7", + "brotli-wasm": "^2.0.1", + "chalk": "4.1.2", + "cli-table3": "^0.6.3", + "ethereum-cryptography": "^2.1.3", + "glob": "^10.3.10", + "jsonschema": "^1.4.1", + "lodash": "^4.17.21", + "markdown-table": "2.0.0", + "sha1": "^1.1.1", + "viem": "^2.27.0" + }, + "peerDependencies": { + "hardhat": "^2.16.0" + } + }, + "node_modules/hardhat-gas-reporter/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat-gas-reporter/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat-gas-reporter/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat-gas-reporter/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat-gas-reporter/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat-gas-reporter/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, + "license": "MIT", + "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/hardhat-gas-reporter/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/hardhat-gas-reporter/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/hardhat-gas-reporter/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/hardhat-gas-reporter/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/hardhat-gas-reporter/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/hardhat-ignore-warnings": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/hardhat-ignore-warnings/-/hardhat-ignore-warnings-0.2.12.tgz", + "integrity": "sha512-SaxCLKzYBMk3Rd1275TnanUmmxwgU+bu4Ekf2MKcqXxxt6xTGcPTtTaM+USrLgmejZHC4Itg/PaWITlOp4RL3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimatch": "^5.1.0", + "node-interval-tree": "^2.0.1", + "solidity-comments": "^0.0.2" + } + }, + "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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hardhat/node_modules/@ethereumjs/rlp": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-5.0.2.tgz", + "integrity": "sha512-DziebCdg4JpGlEqEdGgXmjqcFoJi+JGulUXwEjsZGAscAQ7MyD/7LE/GVCP29vEQxKc7AAwjT3A2ywHp2xfoCA==", + "dev": true, + "license": "MPL-2.0", + "bin": { + "rlp": "bin/rlp.cjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/hardhat/node_modules/@ethereumjs/util": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-9.1.0.tgz", + "integrity": "sha512-XBEKsYqLGXLah9PNJbgdkigthkG7TAGvlD/sH12beMXEyHDyigfcbdvHhmLyDWgDyOJn4QwiQUaF7yeuhnjdog==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@ethereumjs/rlp": "^5.0.2", + "ethereum-cryptography": "^2.2.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/hardhat/node_modules/@ethereumjs/util/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@ethereumjs/util/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@ethereumjs/util/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/hardhat/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "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/" + } + ], + "license": "MIT" + }, + "node_modules/hardhat/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "license": "MIT", + "funding": { + "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/" + } + ], + "license": "MIT", + "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/" + } + ], + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/hardhat/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hardhat/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, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hardhat/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, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hardhat/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, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hardhat/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "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, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/hardhat/node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/hardhat/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, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/hardhat/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "license": "MIT", + "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/hardhat/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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "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, + "license": "BSD-2-Clause" + }, + "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, + "license": "MIT", + "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/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-id": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.1.1.tgz", + "integrity": "sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg==", + "dev": true, + "license": "MIT", + "bin": { + "human-id": "dist/cli.js" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "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, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "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, + "license": "ISC" + }, + "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, + "license": "ISC" + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "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, + "license": "MIT", + "dependencies": { + "fp-ts": "^1.0.0" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "dependencies": { + "better-path-resolve": "1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isows": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.6.tgz", + "integrity": "sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jackspeak": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz", + "integrity": "sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/json-stream-stringify": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz", + "integrity": "sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=7.10.1" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonschema": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz", + "integrity": "sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "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, + "license": "MIT", + "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/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "package-json": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "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, + "license": "MIT" + }, + "node_modules/lint-staged": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.0.0.tgz", + "integrity": "sha512-sUCprePs6/rbx4vKC60Hez6X10HPkpDJaGcy3D1NdwR7g1RcNkWL8q9mJMreOqmHBTs+1sNFp+wOiX9fr+hoOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^13.1.0", + "debug": "^4.4.0", + "lilconfig": "^3.1.3", + "listr2": "^8.3.3", + "micromatch": "^4.0.8", + "nano-spawn": "^1.0.0", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.7.1" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=20.18" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/listr2": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", + "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/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, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/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, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", + "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "repeat-string": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "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, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "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/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micro-eth-signer": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.14.0.tgz", + "integrity": "sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.8.1", + "@noble/hashes": "~1.7.1", + "micro-packed": "~0.7.2" + } + }, + "node_modules/micro-eth-signer/node_modules/@noble/curves": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", + "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.2" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-eth-signer/node_modules/@noble/hashes": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", + "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "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, + "license": "MIT" + }, + "node_modules/micro-packed": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.7.3.tgz", + "integrity": "sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "ISC" + }, + "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, + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "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, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "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, + "license": "MIT", + "dependencies": { + "obliterator": "^2.0.0" + } + }, + "node_modules/mocha": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "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, + "license": "Python-2.0" + }, + "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, + "license": "ISC", + "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, + "license": "MIT", + "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": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "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/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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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/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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "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, + "license": "MIT" + }, + "node_modules/nano-spawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-1.0.1.tgz", + "integrity": "sha512-BfcvzBlUTxSDWfT+oH7vd6CbUV+rThLLHCIym/QO6GGLBsyVXleZs00fto2i2jzC/wPiBYk5jyOmpXWg4YopiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18" + }, + "funding": { + "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "ISC", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/obliterator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", + "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "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.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ordinal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ordinal/-/ordinal-1.0.3.tgz", + "integrity": "sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/ox": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", + "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.10.1", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0", + "@scure/bip32": "^1.5.0", + "@scure/bip39": "^1.4.0", + "abitype": "^1.0.6", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": 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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-limit": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", + "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "dev": true, + "license": "MIT", + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/package-manager-detector": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.11.tgz", + "integrity": "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "quansync": "^0.2.7" + } + }, + "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, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "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/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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pony-cause": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.11.tgz", + "integrity": "sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==", + "dev": true, + "license": "0BSD", + "engines": { + "node": ">=12.0.0" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-solidity": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.4.3.tgz", + "integrity": "sha512-Mrr/iiR9f9IaeGRMZY2ApumXcn/C5Gs3S7B7hWB3gigBFML06C0yEyW86oLp0eqiA0qg+46FaChgLPJCj/pIlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@solidity-parser/parser": "^0.20.1", + "semver": "^7.7.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "prettier": ">=2.3.0" + } + }, + "node_modules/prettier-plugin-solidity/node_modules/@solidity-parser/parser": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.20.1.tgz", + "integrity": "sha512-58I2sRpzaQUN+jJmWbHfbWf9AKfzqCI8JAdFB0vbyY+u8tBRcuTt9LxzasvR0LGQpcRv97eyV7l61FQ3Ib7zVw==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/proper-lockfile/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, + "license": "ISC" + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true, + "license": "ISC" + }, + "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, + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/quansync": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.10.tgz", + "integrity": "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "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" + } + ], + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "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, + "license": "MIT", + "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/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/recursive-readdir/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/recursive-readdir/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/registry-auth-token": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.0.tgz", + "integrity": "sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "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, + "license": "MIT", + "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, + "license": "MPL-2.0", + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "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" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "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" + } + ], + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "BSD-3-Clause", + "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/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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, + "license": "BSD-2-Clause", + "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==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sc-istanbul/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "ISC", + "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, + "license": "MIT" + }, + "node_modules/secp256k1": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.4.tgz", + "integrity": "sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "elliptic": "^6.5.7", + "node-addon-api": "^5.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/secp256k1/node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "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, + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "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, + "license": "(MIT AND BSD-3-Clause)", + "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, + "license": "BSD-3-Clause", + "dependencies": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "BSD-3-Clause", + "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/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "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/shelljs/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/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, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/solc": { + "version": "0.8.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.26.tgz", + "integrity": "sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "command-exists": "^1.2.8", + "commander": "^8.1.0", + "follow-redirects": "^1.12.1", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solc.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/solc/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "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, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/solhint": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.5.tgz", + "integrity": "sha512-WrnG6T+/UduuzSWsSOAbfq1ywLUDwNea3Gd5hg6PS+pLUm8lz2ECNr0beX609clBxmDeZ3676AiA9nPDljmbJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@solidity-parser/parser": "^0.19.0", + "ajv": "^6.12.6", + "antlr4": "^4.13.1-patch-1", + "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", + "latest-version": "^7.0.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/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "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/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, + "license": "Python-2.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, + "license": "MIT", + "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/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "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==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "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/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, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/solhint/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, + "license": "MIT" + }, + "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, + "license": "ISC", + "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, + "license": "MIT", + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/solidity-ast": { + "version": "0.4.60", + "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.60.tgz", + "integrity": "sha512-UwhasmQ37ji1ul8cIp0XlrQ/+SVQhy09gGqJH4jnwdo2TgI6YIByzi0PI5QvIGcIdFOs1pbSmJW1pnWB7AVh2w==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-coverage": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.15.tgz", + "integrity": "sha512-qH7290NKww4/t/qFvnSEePEzON0k025IGVlwc8wo8Q6p+h1Tt6fV2M0k3yfsps3TomZYTROsfPXjx7MSnwD5uA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@ethersproject/abi": "^5.0.9", + "@solidity-parser/parser": "^0.19.0", + "chalk": "^2.4.2", + "death": "^1.1.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.21", + "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/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, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/solidity-coverage/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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, + "license": "MIT", + "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/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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "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, + "license": "MIT", + "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==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "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, + "license": "MIT", + "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/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, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/solidity-coverage/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawndamnit": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-3.0.1.tgz", + "integrity": "sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==", + "dev": true, + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "cross-spawn": "^7.0.5", + "signal-exit": "^4.0.1" + } + }, + "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, + "license": "BSD-3-Clause" + }, + "node_modules/stacktrace-parser": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", + "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", + "dev": true, + "license": "MIT", + "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, + "license": "(MIT OR CC0-1.0)", + "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, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "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, + "license": "MIT", + "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": { + "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, + "license": "MIT", + "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/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "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/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/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, + "license": "MIT", + "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/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, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=0.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, + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "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, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.8.0.tgz", + "integrity": "sha512-vFv1GA99b7eKO1HG/4RPu2Is3FBTWBrmzqzO0mz+rLxN3yXkE4mqRcb8g8fHxzX4blEysrNZLqg5RbJLqX5buA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/viem": { + "version": "2.28.3", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.28.3.tgz", + "integrity": "sha512-kGYmSHNmzXqg7uZlaV6OEL1p68Z45BYTRPsUM0jYLmOn2zWy6DRA+YxntKnt6jBiCPjiWbVrbFm5QS6TWnfAXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.2", + "@noble/hashes": "1.7.2", + "@scure/bip32": "1.6.2", + "@scure/bip39": "1.5.4", + "abitype": "1.0.8", + "isows": "1.0.6", + "ox": "0.6.9", + "ws": "8.18.1" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/viem/node_modules/@noble/curves": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", + "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.2" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@noble/hashes": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", + "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@scure/bip32": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.2.tgz", + "integrity": "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.8.1", + "@noble/hashes": "~1.7.1", + "@scure/base": "~1.2.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@scure/bip39": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.4.tgz", + "integrity": "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.7.1", + "@scure/base": "~1.2.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/web3-utils": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.4.tgz", + "integrity": "sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==", + "dev": true, + "license": "LGPL-3.0", + "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/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "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, + "license": "BSD-2-Clause" + }, + "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, + "license": "MIT", + "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, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/workerpool": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true, + "license": "Apache-2.0" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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/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, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.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, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", + "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "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, + "license": "MIT", + "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.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "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, + "license": "MIT", + "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/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, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "scripts/solhint-custom": { + "name": "solhint-plugin-openzeppelin", + "version": "0.0.0", + "dev": true, + "dependencies": { + "minimatch": "^3.1.2" + } + }, + "scripts/solhint-custom/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "scripts/solhint-custom/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/package.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/package.json new file mode 100644 index 0000000..6cd1daa --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/package.json @@ -0,0 +1,104 @@ +{ + "name": "openzeppelin-solidity", + "description": "Secure Smart Contract library for Solidity", + "version": "5.4.0", + "private": true, + "files": [ + "/contracts/**/*.sol", + "!/contracts/mocks/**/*" + ], + "scripts": { + "compile": "hardhat compile", + "compile:harnesses": "env SRC=./certora/harnesses hardhat compile", + "coverage": "scripts/checks/coverage.sh", + "docs": "npm run prepare-docs && oz-docs", + "docs:watch": "oz-docs watch contracts docs/templates docs/config.js", + "prepare": "husky", + "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 .", + "lint:js:fix": "prettier --log-level warn --ignore-path .gitignore '**/*.{js,ts}' --write && eslint . --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", + "version": "scripts/release/version.sh", + "test": ". scripts/set-max-old-space-size.sh && hardhat test", + "test:generation": "scripts/checks/generation.sh", + "test:inheritance": "scripts/checks/inheritance-ordering.js artifacts/build-info/*", + "test:pragma": "scripts/checks/pragma-consistency.js artifacts/build-info/*", + "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.5.0", + "@changesets/cli": "^2.26.0", + "@changesets/pre": "^2.0.0", + "@changesets/read": "^0.6.0", + "@eslint/compat": "^1.2.1", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.6", + "@nomicfoundation/hardhat-ethers": "^3.0.4", + "@nomicfoundation/hardhat-network-helpers": "^1.0.3", + "@openzeppelin/docs-utils": "^0.1.5", + "@openzeppelin/merkle-tree": "^1.0.7", + "@openzeppelin/upgrade-safe-transpiler": "^0.3.32", + "@openzeppelin/upgrades-core": "^1.20.6", + "chai": "^4.2.0", + "eslint": "^9.0.0", + "eslint-config-prettier": "^10.0.0", + "ethers": "^6.14.0", + "glob": "^11.0.0", + "globals": "^16.0.0", + "graphlib": "^2.1.8", + "hardhat": "^2.24.0", + "hardhat-exposed": "^0.3.15", + "hardhat-gas-reporter": "^2.1.0", + "hardhat-ignore-warnings": "^0.2.11", + "husky": "^9.1.7", + "lint-staged": "^16.0.0", + "lodash.startcase": "^4.4.0", + "micromatch": "^4.0.2", + "p-limit": "^6.0.0", + "prettier": "^3.0.0", + "prettier-plugin-solidity": "^1.1.0", + "rimraf": "^6.0.0", + "semver": "^7.3.5", + "solhint": "^5.0.0", + "solhint-plugin-openzeppelin": "file:scripts/solhint-custom", + "solidity-ast": "^0.4.50", + "solidity-coverage": "^0.8.14", + "solidity-docgen": "^0.6.0-beta.29", + "undici": "^7.4.0", + "yargs": "^17.0.0" + }, + "lint-staged": { + "*.{js,ts}": [ + "prettier --log-level warn --ignore-path .gitignore --check", + "eslint" + ], + "*.sol": [ + "prettier --log-level warn --ignore-path .gitignore --check", + "solhint" + ] + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/remappings.txt b/typescript/packages/account-modules/lib/openzeppelin-contracts/remappings.txt new file mode 100644 index 0000000..304d138 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/remappings.txt @@ -0,0 +1 @@ +@openzeppelin/contracts/=contracts/ diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/renovate.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/renovate.json new file mode 100644 index 0000000..c0b97d8 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/renovate.json @@ -0,0 +1,4 @@ +{ + "extends": ["github>OpenZeppelin/configs"], + "labels": ["ignore-changeset"] +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compare-layout.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compare-layout.js new file mode 100644 index 0000000..64ff439 --- /dev/null +++ b/typescript/packages/account-modules/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 incompatibility found in ${name}:`); + console.log(report.explain()); + process.exitCode = 1; + } + } else { + console.log(`WARNING: ${name} is missing from the current branch`); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js new file mode 100755 index 0000000..2c7b4dc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js @@ -0,0 +1,247 @@ +#!/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.options?.solcInfo) !== JSON.stringify(ref.options?.solcInfo)) { + console.warn('WARNING: Reports produced with non matching metadata'); + } + + // gasReporter 1.0.0 uses ".info", but 2.0.0 uses ".data" + const updateInfo = update.info ?? update.data; + const refInfo = ref.info ?? ref.data; + + const deployments = updateInfo.deployments + .map(contract => + Object.assign(contract, { previousVersion: refInfo.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(updateInfo.methods) + .filter(key => refInfo.methods[key]) + .filter(key => updateInfo.methods[key].numberOfCalls > 0) + .filter( + key => !opts.strictTesting || updateInfo.methods[key].numberOfCalls === refInfo.methods[key].numberOfCalls, + ) + .map(key => ({ + contract: refInfo.methods[key].contract, + method: refInfo.methods[key].fnSig, + min: variation(...[updateInfo, refInfo].map(x => Math.min(...x.methods[key].gasData)), BASE_TX_COST), + max: variation(...[updateInfo, refInfo].map(x => Math.max(...x.methods[key].gasData)), BASE_TX_COST), + avg: variation(...[updateInfo, refInfo].map(x => Math.round(average(...x.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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/coverage.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/coverage.sh new file mode 100755 index 0000000..fd8b9e8 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/coverage.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -euo pipefail + +export COVERAGE=true +export FOUNDRY_FUZZ_RUNS=10 + +. scripts/set-max-old-space-size.sh + +# Hardhat coverage +hardhat coverage + +if [ "${CI:-"false"}" == "true" ]; then + # Foundry coverage + forge coverage --report lcov --ir-minimum + # Remove zero hits + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' '/,0/d' lcov.info + else + sed -i '/,0/d' lcov.info + fi +fi + +# Reports are then uploaded to Codecov automatically by workflow, and merged. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/extract-layout.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/extract-layout.js new file mode 100644 index 0000000..d0b9965 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/generation.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/generation.sh new file mode 100755 index 0000000..00d609f --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js new file mode 100755 index 0000000..fbeac9e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js @@ -0,0 +1,55 @@ +#!/usr/bin/env node + +const path = require('path'); +const graphlib = require('graphlib'); +const match = require('micromatch'); +const { findAll } = require('solidity-ast/utils'); +const { _: artifacts } = require('yargs').argv; + +// files to skip +const skipPatterns = ['contracts-exposed/**', 'contracts/mocks/**']; + +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 (match.any(source, skipPatterns)) 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 in 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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/pragma-consistency.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/pragma-consistency.js new file mode 100755 index 0000000..cf74cd2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/pragma-consistency.js @@ -0,0 +1,49 @@ +#!/usr/bin/env node + +const path = require('path'); +const semver = require('semver'); +const match = require('micromatch'); +const { findAll } = require('solidity-ast/utils'); +const { _: artifacts } = require('yargs').argv; + +// files to skip +const skipPatterns = ['contracts-exposed/**', 'contracts/mocks/WithInit.sol']; + +for (const artifact of artifacts) { + const { output: solcOutput } = require(path.resolve(__dirname, '../..', artifact)); + + const pragma = {}; + + // Extract pragma directive for all files + for (const source in solcOutput.contracts) { + if (match.any(source, skipPatterns)) continue; + for (const { literals } of findAll('PragmaDirective', solcOutput.sources[source].ast)) { + // There should only be one. + const [first, ...rest] = literals; + if (first === 'solidity') pragma[source] = rest.join(''); + } + } + + // Compare the pragma directive of the file, to that of the files it imports + for (const source in solcOutput.contracts) { + if (match.any(source, skipPatterns)) continue; + // minimum version of the compiler that matches source's pragma + const minVersion = semver.minVersion(pragma[source]); + // loop over all imports in source + for (const { absolutePath } of findAll('ImportDirective', solcOutput.sources[source].ast)) { + // So files that only import without declaring anything cause issues, because they don't shop in "pragma" + if (!pragma[absolutePath]) continue; + // Check that the minVersion for source satisfies the requirements of the imported files + if (!semver.satisfies(minVersion, pragma[absolutePath])) { + console.log( + `- ${source} uses ${pragma[source]} but depends on ${absolutePath} that requires ${pragma[absolutePath]}`, + ); + process.exitCode = 1; + } + } + } +} + +if (!process.exitCode) { + console.log('Pragma directives are consistent.'); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/fetch-common-contracts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/fetch-common-contracts.js new file mode 100755 index 0000000..af90424 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/fetch-common-contracts.js @@ -0,0 +1,50 @@ +#!/usr/bin/env node + +// This script snapshots the bytecode and ABI for the `hardhat/common-contracts.js` script. +// - Bytecode is fetched directly from the blockchain by querying the provided client endpoint. If no endpoint is +// provided, ethers default provider is used instead. +// - ABI is fetched from etherscan's API using the provided etherscan API key. If no API key is provided, ABI will not +// be fetched and saved. +// +// The produced artifacts are stored in the `output` folder ('test/bin' by default). For each contract, two files are +// produced: +// - `.bytecode` containing the contract bytecode (in binary encoding) +// - `.abi` containing the ABI (in utf-8 encoding) + +const fs = require('fs'); +const path = require('path'); +const { ethers } = require('ethers'); +const { request } = require('undici'); +const { hideBin } = require('yargs/helpers'); +const { argv } = require('yargs/yargs')(hideBin(process.argv)) + .env('') + .options({ + output: { type: 'string', default: 'test/bin/' }, + client: { type: 'string' }, + etherscan: { type: 'string' }, + }); + +// List of contract names and addresses to fetch +const config = { + EntryPoint070: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', + SenderCreator070: '0xEFC2c1444eBCC4Db75e7613d20C6a62fF67A167C', + EntryPoint080: '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108', + SenderCreator080: '0x449ED7C3e6Fee6a97311d4b55475DF59C44AdD33', +}; + +Promise.all( + Object.entries(config).flatMap(([name, addr]) => + Promise.all([ + argv.etherscan && + request(`https://api.etherscan.io/api?module=contract&action=getabi&address=${addr}&apikey=${argv.etherscan}`) + .then(({ body }) => body.json()) + .then(({ result: abi }) => fs.writeFile(path.join(argv.output, `${name}.abi`), abi, 'utf-8', () => {})), + ethers + .getDefaultProvider(argv.client) + .getCode(addr) + .then(bytecode => + fs.writeFile(path.join(argv.output, `${name}.bytecode`), ethers.getBytes(bytecode), 'binary', () => {}), + ), + ]), + ), +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/gen-nav.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/gen-nav.js new file mode 100644 index 0000000..06444f9 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/gen-nav.js @@ -0,0 +1,81 @@ +#!/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'; + default: + return startCase(directory); + } +} + +const menuItems = files.reduce( + (acc, file) => { + let current = acc; + const doc = file.replace(baseDir, ''); + + const keys = doc + .split('/') + .filter(Boolean) + .map(k => k.replace('.adoc', '')); + + for (let i = 0; i < keys.length; i++) { + current = current.items[keys[i]] ??= { + name: startCase(keys[i]), + dir: keys[i], + items: {}, + doc, + }; + } + + return acc; + }, + { + items: { + token: { + name: 'tokens', + dir: '', + items: {}, + }, + }, + }, +); + +const arrayifyItems = items => + Object.entries(items).map(([k, v]) => { + if (Object.keys(v.items ?? {}).length > 0) return [v, arrayifyItems(v.items)]; + return [k, v]; + }); + +const isString = v => typeof v === 'string'; + +const sortItems = items => + items.sort(([a], [b]) => + (isString(a) ? a : a.name).toLowerCase().localeCompare(isString(b) ? b : b.name, undefined, { numeric: true }), + ); + +const print = (items, level = 1) => { + items.forEach(([k, v]) => { + if (v.doc || k?.doc) + console.log(`${'*'.repeat(level)} xref:${v.doc || k.doc}[${getPageTitle(isString(k) ? k : k.name)}]`); + else console.log(`${'*'.repeat(level)} ${getPageTitle(isString(k) ? k : k.name)}`); + if (Array.isArray(v)) print(v, level + 1); + }); +}; + +print( + sortItems(arrayifyItems(menuItems.items)).map(([k, v]) => { + if (v?.length > 0) return [k, sortItems(v)]; + return [k, v]; + }), +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/format-lines.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/format-lines.js new file mode 100644 index 0000000..fa3d6b1 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/helpers/sanitize.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/helpers/sanitize.js new file mode 100644 index 0000000..e680ec1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/helpers/sanitize.js @@ -0,0 +1,5 @@ +module.exports = { + address: expr => `and(${expr}, shr(96, not(0)))`, + bool: expr => `iszero(iszero(${expr}))`, + bytes: (expr, size) => `and(${expr}, shl(${256 - 8 * size}, not(0)))`, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/run.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/run.js new file mode 100755 index 0000000..394bb39 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/run.js @@ -0,0 +1,61 @@ +#!/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 { + return null; + } +} + +function generateFromTemplate(file, template, outputPrefix = '', lint = false) { + 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).trimEnd(), + ); + + fs.writeFileSync(output, content); + lint && cp.execFileSync('prettier', ['--write', output]); +} + +// Some templates needs to go through the linter after generation +const needsLinter = ['utils/structs/EnumerableMap.sol']; + +// Contracts +for (const [file, template] of Object.entries({ + 'utils/cryptography/MerkleProof.sol': './templates/MerkleProof.js', + 'utils/math/SafeCast.sol': './templates/SafeCast.js', + 'utils/structs/Checkpoints.sol': './templates/Checkpoints.js', + 'utils/structs/EnumerableSet.sol': './templates/EnumerableSet.js', + 'utils/structs/EnumerableMap.sol': './templates/EnumerableMap.js', + 'utils/SlotDerivation.sol': './templates/SlotDerivation.js', + 'utils/StorageSlot.sol': './templates/StorageSlot.js', + 'utils/TransientSlot.sol': './templates/TransientSlot.js', + 'utils/Arrays.sol': './templates/Arrays.js', + 'utils/Packing.sol': './templates/Packing.js', + 'mocks/StorageSlotMock.sol': './templates/StorageSlotMock.js', + 'mocks/TransientSlotMock.sol': './templates/TransientSlotMock.js', +})) { + generateFromTemplate(file, template, './contracts/', needsLinter.includes(file)); +} + +// Tests +for (const [file, template] of Object.entries({ + 'utils/structs/Checkpoints.t.sol': './templates/Checkpoints.t.js', + 'utils/Packing.t.sol': './templates/Packing.t.js', + 'utils/SlotDerivation.t.sol': './templates/SlotDerivation.t.js', +})) { + generateFromTemplate(file, template, './test/', needsLinter.includes(file)); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.js new file mode 100644 index 0000000..6f9380a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.js @@ -0,0 +1,386 @@ +const format = require('../format-lines'); +const { capitalize } = require('../../helpers'); +const { TYPES } = require('./Arrays.opts'); + +const header = `\ +pragma solidity ^0.8.20; + +import {Comparators} from "./Comparators.sol"; +import {SlotDerivation} from "./SlotDerivation.sol"; +import {StorageSlot} from "./StorageSlot.sol"; +import {Math} from "./math/Math.sol"; + +/** + * @dev Collection of functions related to array types. + */ +`; + +const sort = type => `\ +/** + * @dev Sort an array of ${type.name} (in memory) following the provided comparator function. + * + * This function does the sorting "in place", meaning that it overrides the input. The object is returned for + * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array. + * + * NOTE: this function's cost is \`O(n · log(n))\` in average and \`O(n²)\` in the worst case, with n the length of the + * array. Using it in view functions that are executed through \`eth_call\` is safe, but one should be very careful + * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may + * consume more gas than is available in a block, leading to potential DoS. + * + * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way. + */ +function sort( + ${type.name}[] memory array, + function(${type.name}, ${type.name}) pure returns (bool) comp +) internal pure returns (${type.name}[] memory) { + ${ + type.name === 'uint256' + ? '_quickSort(_begin(array), _end(array), comp);' + : 'sort(_castToUint256Array(array), _castToUint256Comp(comp));' + } + return array; +} + +/** + * @dev Variant of {sort} that sorts an array of ${type.name} in increasing order. + */ +function sort(${type.name}[] memory array) internal pure returns (${type.name}[] memory) { + ${type.name === 'uint256' ? 'sort(array, Comparators.lt);' : 'sort(_castToUint256Array(array), Comparators.lt);'} + return array; +} +`; + +const quickSort = `\ +/** + * @dev Performs a quick sort of a segment of memory. The segment sorted starts at \`begin\` (inclusive), and stops + * at end (exclusive). Sorting follows the \`comp\` comparator. + * + * Invariant: \`begin <= end\`. This is the case when initially called by {sort} and is preserved in subcalls. + * + * IMPORTANT: Memory locations between \`begin\` and \`end\` are not validated/zeroed. This function should + * be used only if the limits are within a memory array. + */ +function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure { + unchecked { + if (end - begin < 0x40) return; + + // Use first element as pivot + uint256 pivot = _mload(begin); + // Position where the pivot should be at the end of the loop + uint256 pos = begin; + + for (uint256 it = begin + 0x20; it < end; it += 0x20) { + if (comp(_mload(it), pivot)) { + // If the value stored at the iterator's position comes before the pivot, we increment the + // position of the pivot and move the value there. + pos += 0x20; + _swap(pos, it); + } + } + + _swap(begin, pos); // Swap pivot into place + _quickSort(begin, pos, comp); // Sort the left side of the pivot + _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot + } +} + +/** + * @dev Pointer to the memory location of the first element of \`array\`. + */ +function _begin(uint256[] memory array) private pure returns (uint256 ptr) { + assembly ("memory-safe") { + ptr := add(array, 0x20) + } +} + +/** + * @dev Pointer to the memory location of the first memory word (32bytes) after \`array\`. This is the memory word + * that comes just after the last element of the array. + */ +function _end(uint256[] memory array) private pure returns (uint256 ptr) { + unchecked { + return _begin(array) + array.length * 0x20; + } +} + +/** + * @dev Load memory word (as a uint256) at location \`ptr\`. + */ +function _mload(uint256 ptr) private pure returns (uint256 value) { + assembly { + value := mload(ptr) + } +} + +/** + * @dev Swaps the elements memory location \`ptr1\` and \`ptr2\`. + */ +function _swap(uint256 ptr1, uint256 ptr2) private pure { + assembly { + let value1 := mload(ptr1) + let value2 := mload(ptr2) + mstore(ptr1, value2) + mstore(ptr2, value1) + } +} +`; + +const castArray = type => `\ +/// @dev Helper: low level cast ${type.name} memory array to uint256 memory array +function _castToUint256Array(${type.name}[] memory input) private pure returns (uint256[] memory output) { + assembly { + output := input + } +} +`; + +const castComparator = type => `\ +/// @dev Helper: low level cast ${type.name} comp function to uint256 comp function +function _castToUint256Comp( + function(${type.name}, ${type.name}) pure returns (bool) input +) private pure returns (function(uint256, uint256) pure returns (bool) output) { + assembly { + output := input + } +} +`; + +const search = `\ +/** + * @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). + * + * NOTE: The \`array\` is expected to be sorted in ascending order, and to + * contain no repeated elements. + * + * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks + * support for repeated elements in the array. The {lowerBound} function should + * be used instead. + */ +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 Searches an \`array\` sorted in ascending order and returns the first + * index that contains a value greater or equal than \`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). + * + * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound]. + */ +function lowerBound(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) { + // this cannot overflow because mid < high + unchecked { + low = mid + 1; + } + } else { + high = mid; + } + } + + return low; +} + +/** + * @dev Searches an \`array\` sorted in ascending order and returns the first + * index that contains a value strictly greater than \`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). + * + * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound]. + */ +function upperBound(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 { + // this cannot overflow because mid < high + unchecked { + low = mid + 1; + } + } + } + + return low; +} + +/** + * @dev Same as {lowerBound}, but with an array in memory. + */ +function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure 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 (unsafeMemoryAccess(array, mid) < element) { + // this cannot overflow because mid < high + unchecked { + low = mid + 1; + } + } else { + high = mid; + } + } + + return low; +} + +/** + * @dev Same as {upperBound}, but with an array in memory. + */ +function upperBoundMemory(uint256[] memory array, uint256 element) internal pure 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 (unsafeMemoryAccess(array, mid) > element) { + high = mid; + } else { + // this cannot overflow because mid < high + unchecked { + low = mid + 1; + } + } + } + + return low; +} +`; + +const unsafeAccessStorage = type => `\ +/** + * @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(${type.name}[] storage arr, uint256 pos) internal pure returns (StorageSlot.${capitalize( + type.name, +)}Slot storage) { + bytes32 slot; + assembly ("memory-safe") { + slot := arr.slot + } + return slot.deriveArray().offset(pos).get${capitalize(type.name)}Slot(); +} +`; + +const unsafeAccessMemory = type => `\ +/** + * @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(${type.name}[] memory arr, uint256 pos) internal pure returns (${type.name}${ + type.isValueType ? '' : ' memory' +} res) { + assembly { + res := mload(add(add(arr, 0x20), mul(pos, 0x20))) + } +} +`; + +const unsafeSetLength = type => `\ +/** + * @dev Helper to set the length of a dynamic array. Directly writing to \`.length\` is forbidden. + * + * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. + */ +function unsafeSetLength(${type.name}[] storage array, uint256 len) internal { + assembly ("memory-safe") { + sstore(array.slot, len) + } +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library Arrays {', + format( + [].concat( + 'using SlotDerivation for bytes32;', + 'using StorageSlot for bytes32;', + '', + // sorting, comparator, helpers and internal + sort({ name: 'uint256' }), + TYPES.filter(type => type.isValueType && type.name !== 'uint256').map(sort), + quickSort, + TYPES.filter(type => type.isValueType && type.name !== 'uint256').map(castArray), + TYPES.filter(type => type.isValueType && type.name !== 'uint256').map(castComparator), + // lookup + search, + // unsafe (direct) storage and memory access + TYPES.map(unsafeAccessStorage), + TYPES.map(unsafeAccessMemory), + TYPES.map(unsafeSetLength), + ), + ).trimEnd(), + '}', +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.opts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.opts.js new file mode 100644 index 0000000..80efc80 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.opts.js @@ -0,0 +1,9 @@ +const TYPES = [ + { name: 'address', isValueType: true }, + { name: 'bytes32', isValueType: true }, + { name: 'uint256', isValueType: true }, + { name: 'bytes', isValueType: false }, + { name: 'string', isValueType: false }, +]; + +module.exports = { TYPES }; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js new file mode 100644 index 0000000..0aaa181 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js @@ -0,0 +1,242 @@ +const format = require('../format-lines'); +const { OPTS } = require('./Checkpoints.opts'); + +// 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} oldValue, ${opts.valueTypeName} newValue) { + 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 optimized 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} storage ckpt = _unsafeAccess(self.${opts.checkpointFieldName}, pos - 1); + return (true, ckpt.${opts.keyFieldName}, ckpt.${opts.valueFieldName}); + } +} + +/** + * @dev Returns the number of checkpoints. + */ +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} oldValue, ${opts.valueTypeName} newValue) { + uint256 pos = self.length; + + if (pos > 0) { + ${opts.checkpointTypeName} storage last = _unsafeAccess(self, pos - 1); + ${opts.keyTypeName} lastKey = last.${opts.keyFieldName}; + ${opts.valueTypeName} lastValue = last.${opts.valueFieldName}; + + // Checkpoint keys must be non-decreasing. + if (lastKey > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (lastKey == key) { + last.${opts.valueFieldName} = value; + } else { + self.push(${opts.checkpointTypeName}({${opts.keyFieldName}: key, ${opts.valueFieldName}: value})); + } + return (lastValue, value); + } else { + self.push(${opts.checkpointTypeName}({${opts.keyFieldName}: key, ${opts.valueFieldName}: value})); + return (0, value); + } +} + +/** + * @dev Return the index of the first (oldest) checkpoint with key strictly bigger 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 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) + } +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library Checkpoints {', + format( + [].concat( + errors, + OPTS.map(opts => template(opts)), + ), + ).trimEnd(), + '}', +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.opts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.opts.js new file mode 100644 index 0000000..08b7b91 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.t.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.t.js new file mode 100644 index 0000000..77a9cd3 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.t.js @@ -0,0 +1,137 @@ +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 "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {Checkpoints} from "@openzeppelin/contracts/utils/structs/Checkpoints.sol"; +`; + +const template = opts => `\ +using Checkpoints for Checkpoints.${opts.historyTypeName}; + +// Maximum gap between keys used during the fuzzing tests: the \`_prepareKeys\` function will 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 pure 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 pure { + ${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 view { + (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).trimEnd()], + '}', + '', + ]), +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Enumerable.opts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Enumerable.opts.js new file mode 100644 index 0000000..50c7349 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Enumerable.opts.js @@ -0,0 +1,53 @@ +const { capitalize, mapValues } = require('../../helpers'); + +const typeDescr = ({ type, size = 0, memory = false }) => { + memory |= size > 0; + + const name = [type == 'uint256' ? 'Uint' : capitalize(type), size].filter(Boolean).join('x'); + const base = size ? type : undefined; + const typeFull = size ? `${type}[${size}]` : type; + const typeLoc = memory ? `${typeFull} memory` : typeFull; + return { name, type: typeFull, typeLoc, base, size, memory }; +}; + +const toSetTypeDescr = value => ({ + name: value.name + 'Set', + value, +}); + +const toMapTypeDescr = ({ key, value }) => ({ + name: `${key.name}To${value.name}Map`, + keySet: toSetTypeDescr(key), + key, + value, +}); + +const SET_TYPES = [ + { type: 'bytes32' }, + { type: 'address' }, + { type: 'uint256' }, + { type: 'string', memory: true }, + { type: 'bytes', memory: true }, +] + .map(typeDescr) + .map(toSetTypeDescr); + +const MAP_TYPES = [] + .concat( + // value type maps + ['uint256', 'address', 'bytes32'] + .flatMap((keyType, _, array) => array.map(valueType => ({ key: { type: keyType }, value: { type: valueType } }))) + .slice(0, -1), // remove bytes32 → bytes32 (last one) that is already defined + // non-value type maps + { key: { type: 'bytes', memory: true }, value: { type: 'bytes', memory: true } }, + ) + .map(entry => mapValues(entry, typeDescr)) + .map(toMapTypeDescr); + +module.exports = { + SET_TYPES, + MAP_TYPES, + typeDescr, + toSetTypeDescr, + toMapTypeDescr, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js new file mode 100644 index 0000000..f8deb88 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js @@ -0,0 +1,463 @@ +const format = require('../format-lines'); +const { fromBytes32, toBytes32 } = require('./conversion'); +const { MAP_TYPES } = require('./Enumerable.opts'); + +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. + * - Map can be cleared (all entries removed) in O(n). + * + * \`\`\`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 + * - \`uint256 -> bytes32\` (\`UintToBytes32Map\`) since v5.1.0 + * - \`address -> address\` (\`AddressToAddressMap\`) since v5.1.0 + * - \`address -> bytes32\` (\`AddressToBytes32Map\`) since v5.1.0 + * - \`bytes32 -> address\` (\`Bytes32ToAddressMap\`) since v5.1.0 + * - \`bytes -> bytes\` (\`BytesToBytesMap\`) since v5.4.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. + * ==== + */ +`; + +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 Removes all the entries from a map. O(n). + * + * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the + * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block. + */ +function clear(Bytes32ToBytes32Map storage map) internal { + uint256 len = length(map); + for (uint256 i = 0; i < len; ++i) { + delete map._values[map._keys.at(i)]; + } + map._keys.clear(); +} + +/** + * @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 key, bytes32 value) { + bytes32 atKey = map._keys.at(index); + return (atKey, map._values[atKey]); +} + +/** + * @dev Tries to return the value associated with \`key\`. O(1). + * Does not revert if \`key\` is not in the map. + */ +function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool exists, bytes32 value) { + bytes32 val = map._values[key]; + if (val == bytes32(0)) { + return (contains(map, key), bytes32(0)); + } else { + return (true, val); + } +} + +/** + * @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 Returns an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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(); +} + +/** + * @dev Returns an array containing a slice of the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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, uint256 start, uint256 end) internal view returns (bytes32[] memory) { + return map._keys.values(start, end); +} +`; + +const customMap = ({ name, key, value }) => `\ +// ${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, ${key.type} key, ${value.type} value) internal returns (bool) { + return set(map._inner, ${toBytes32(key.type, 'key')}, ${toBytes32(value.type, '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, ${key.type} key) internal returns (bool) { + return remove(map._inner, ${toBytes32(key.type, 'key')}); +} + +/** + * @dev Removes all the entries from a map. O(n). + * + * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that + * using it may render the function uncallable if the map grows to the point where clearing it consumes too much + * gas to fit in a block. + */ +function clear(${name} storage map) internal { + clear(map._inner); +} + +/** + * @dev Returns true if the key is in the map. O(1). + */ +function contains(${name} storage map, ${key.type} key) internal view returns (bool) { + return contains(map._inner, ${toBytes32(key.type, '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 (${key.type} key, ${value.type} value) { + (bytes32 atKey, bytes32 val) = at(map._inner, index); + return (${fromBytes32(key.type, 'atKey')}, ${fromBytes32(value.type, 'val')}); +} + +/** + * @dev Tries to return the value associated with \`key\`. O(1). + * Does not revert if \`key\` is not in the map. + */ +function tryGet(${name} storage map, ${key.type} key) internal view returns (bool exists, ${value.type} value) { + (bool success, bytes32 val) = tryGet(map._inner, ${toBytes32(key.type, 'key')}); + return (success, ${fromBytes32(value.type, 'val')}); +} + +/** + * @dev Returns the value associated with \`key\`. O(1). + * + * Requirements: + * + * - \`key\` must be in the map. + */ +function get(${name} storage map, ${key.type} key) internal view returns (${value.type}) { + return ${fromBytes32(value.type, `get(map._inner, ${toBytes32(key.type, 'key')})`)}; +} + +/** + * @dev Returns an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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 (${key.type}[] memory) { + bytes32[] memory store = keys(map._inner); + ${key.type}[] memory result; + + assembly ("memory-safe") { + result := store + } + + return result; +} + +/** + * @dev Returns an array containing a slice of the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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, uint256 start, uint256 end) internal view returns (${key.type}[] memory) { + bytes32[] memory store = keys(map._inner, start, end); + ${key.type}[] memory result; + + assembly ("memory-safe") { + result := store + } + + return result; +} +`; + +const memoryMap = ({ name, keySet, key, value }) => `\ +/** + * @dev Query for a nonexistent map key. + */ +error EnumerableMapNonexistent${key.name}Key(${key.type} key); + +struct ${name} { + // Storage of keys + EnumerableSet.${keySet.name} _keys; + mapping(${key.type} key => ${value.type}) _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(${name} storage map, ${key.typeLoc} key, ${value.typeLoc} 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(${name} storage map, ${key.typeLoc} key) internal returns (bool) { + delete map._values[key]; + return map._keys.remove(key); +} + +/** + * @dev Removes all the entries from a map. O(n). + * + * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the + * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block. + */ +function clear(${name} storage map) internal { + uint256 len = length(map); + for (uint256 i = 0; i < len; ++i) { + delete map._values[map._keys.at(i)]; + } + map._keys.clear(); +} + +/** + * @dev Returns true if the key is in the map. O(1). + */ +function contains(${name} storage map, ${key.typeLoc} 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(${name} 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( + ${name} storage map, + uint256 index +) internal view returns (${key.typeLoc} key, ${value.typeLoc} value) { + key = map._keys.at(index); + value = map._values[key]; +} + +/** + * @dev Tries to return the value associated with \`key\`. O(1). + * Does not revert if \`key\` is not in the map. + */ +function tryGet( + ${name} storage map, + ${key.typeLoc} key +) internal view returns (bool exists, ${value.typeLoc} value) { + value = map._values[key]; + exists = ${value.memory ? 'bytes(value).length != 0' : `value != ${value.type}(0)`} || contains(map, key); +} + +/** + * @dev Returns the value associated with \`key\`. O(1). + * + * Requirements: + * + * - \`key\` must be in the map. + */ +function get(${name} storage map, ${key.typeLoc} key) internal view returns (${value.typeLoc} value) { + bool exists; + (exists, value) = tryGet(map, key); + if (!exists) { + revert EnumerableMapNonexistent${key.name}Key(key); + } +} + +/** + * @dev Returns an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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 (${key.type}[] memory) { + return map._keys.values(); +} + +/** + * @dev Returns an array containing a slice of the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * 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, uint256 start, uint256 end) internal view returns (${key.type}[] memory) { + return map._keys.values(start, end); +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library EnumerableMap {', + format( + [].concat( + 'using EnumerableSet for *;', + '', + defaultMap, + MAP_TYPES.filter(({ key, value }) => !(key.memory || value.memory)).map(customMap), + MAP_TYPES.filter(({ key, value }) => key.memory || value.memory).map(memoryMap), + ), + ).trimEnd(), + '}', +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js new file mode 100644 index 0000000..eb6a0a2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js @@ -0,0 +1,469 @@ +const format = require('../format-lines'); +const { fromBytes32, toBytes32 } = require('./conversion'); +const { SET_TYPES } = require('./Enumerable.opts'); + +const header = `\ +pragma solidity ^0.8.20; + +import {Arrays} from "../Arrays.sol"; +import {Math} from "../math/Math.sol"; + +/** + * @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. + * - Set can be cleared (all elements removed) in O(n). + * + * \`\`\`solidity + * contract Example { + * // Add the library methods + * using EnumerableSet for EnumerableSet.AddressSet; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * \`\`\` + * + * The following types are supported: + * + * - \`bytes32\` (\`Bytes32Set\`) since v3.3.0 + * - \`address\` (\`AddressSet\`) since v3.3.0 + * - \`uint256\` (\`UintSet\`) since v3.3.0 + * - \`string\` (\`StringSet\`) since v5.4.0 + * - \`bytes\` (\`BytesSet\`) since v5.4.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 EnumerableSet, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableSet. + * ==== + */ +`; + +// NOTE: this should be deprecated in favor of a more native construction in v6.0 +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 Removes all the values from a set. O(n). + * + * WARNING: This function has an unbounded cost that scales with set size. Developers should keep in mind that + * using it may render the function uncallable if the set grows to the point where clearing it consumes too much + * gas to fit in a block. + */ +function _clear(Set storage set) private { + uint256 len = _length(set); + for (uint256 i = 0; i < len; ++i) { + delete set._positions[set._values[i]]; + } + Arrays.unsafeSetLength(set._values, 0); +} + +/** + * @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; +} + +/** + * @dev Return a slice of the 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, uint256 start, uint256 end) private view returns (bytes32[] memory) { + unchecked { + end = Math.min(end, _length(set)); + start = Math.min(start, end); + + uint256 len = end - start; + bytes32[] memory result = new bytes32[](len); + for (uint256 i = 0; i < len; ++i) { + result[i] = Arrays.unsafeAccess(set._values, start + i).value; + } + return result; + } +} +`; + +// NOTE: this should be deprecated in favor of a more native construction in v6.0 +const customSet = ({ name, value: { 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 Removes all the values from a set. O(n). + * + * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the + * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. + */ +function clear(${name} storage set) internal { + _clear(set._inner); +} + +/** + * @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; + + assembly ("memory-safe") { + result := store + } + + return result; +} + +/** + * @dev Return a slice of the 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, uint256 start, uint256 end) internal view returns (${type}[] memory) { + bytes32[] memory store = _values(set._inner, start, end); + ${type}[] memory result; + + assembly ("memory-safe") { + result := store + } + + return result; +} +`; + +const memorySet = ({ name, value }) => `\ +struct ${name} { + // Storage of set values + ${value.type}[] _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(${value.type} 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(${name} storage set, ${value.type} memory value) internal returns (bool) { + if (!contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + 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(${name} storage set, ${value.type} memory value) internal returns (bool) { + // We cache the value's position to prevent multiple reads from the same storage slot + uint256 position = 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) { + ${value.type} memory 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 Removes all the values from a set. O(n). + * + * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the + * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. + */ +function clear(${name} storage set) internal { + uint256 len = length(set); + for (uint256 i = 0; i < len; ++i) { + delete set._positions[set._values[i]]; + } + Arrays.unsafeSetLength(set._values, 0); +} + +/** + * @dev Returns true if the value is in the set. O(1). + */ +function contains(${name} storage set, ${value.type} memory value) internal view returns (bool) { + return set._positions[value] != 0; +} + +/** + * @dev Returns the number of values on the set. O(1). + */ +function length(${name} storage set) internal 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(${name} storage set, uint256 index) internal view returns (${value.type} memory) { + 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(${name} storage set) internal view returns (${value.type}[] memory) { + return set._values; +} + +/** + * @dev Return a slice of the 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, uint256 start, uint256 end) internal view returns (${value.type}[] memory) { + unchecked { + end = Math.min(end, length(set)); + start = Math.min(start, end); + + uint256 len = end - start; + ${value.type}[] memory result = new ${value.type}[](len); + for (uint256 i = 0; i < len; ++i) { + result[i] = Arrays.unsafeAccess(set._values, start + i).value; + } + return result; + } +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library EnumerableSet {', + format( + [].concat( + defaultSet, + SET_TYPES.filter(({ value }) => !value.memory).map(customSet), + SET_TYPES.filter(({ value }) => value.memory).map(memorySet), + ), + ).trimEnd(), + '}', +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.js new file mode 100644 index 0000000..890b2fe --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.js @@ -0,0 +1,187 @@ +const format = require('../format-lines'); +const { OPTS } = require('./MerkleProof.opts'); + +const DEFAULT_HASH = 'Hashes.commutativeKeccak256'; + +const formatArgsSingleLine = (...args) => args.filter(Boolean).join(', '); +const formatArgsMultiline = (...args) => '\n' + format(args.filter(Boolean).join(',\0').split('\0')); + +// TEMPLATE +const header = `\ +pragma solidity ^0.8.20; + +import {Hashes} from "./Hashes.sol"; + +/** + * @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. + * + * IMPORTANT: Consider memory side-effects when using custom hashing functions + * that access memory in an unsafe way. + * + * NOTE: This library supports proof verification for merkle trees built using + * custom _commutative_ hashing functions (i.e. \`H(a, b) == H(b, a)\`). Proving + * leaf inclusion in trees built using non-commutative hashing functions requires + * additional logic that is not supported by this library. + */ +`; + +const errors = `\ +/** + *@dev The multiproof provided is not valid. + */ +error MerkleProofInvalidMultiproof(); +`; + +const templateProof = ({ suffix, location, visibility, hash }) => `\ +/** + * @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. + * + * This version handles proofs in ${location} with ${hash ? 'a custom' : 'the default'} hashing function. + */ +function verify${suffix}(${(hash ? formatArgsMultiline : formatArgsSingleLine)( + `bytes32[] ${location} proof`, + 'bytes32 root', + 'bytes32 leaf', + hash && `function(bytes32, bytes32) view returns (bytes32) ${hash}`, +)}) internal ${visibility} returns (bool) { + return processProof${suffix}(proof, leaf${hash ? `, ${hash}` : ''}) == 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 leaves & pre-images are assumed to be sorted. + * + * This version handles proofs in ${location} with ${hash ? 'a custom' : 'the default'} hashing function. + */ +function processProof${suffix}(${(hash ? formatArgsMultiline : formatArgsSingleLine)( + `bytes32[] ${location} proof`, + 'bytes32 leaf', + hash && `function(bytes32, bytes32) view returns (bytes32) ${hash}`, +)}) internal ${visibility} returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + computedHash = ${hash ?? DEFAULT_HASH}(computedHash, proof[i]); + } + return computedHash; +} +`; + +const templateMultiProof = ({ suffix, location, visibility, hash }) => `\ +/** + * @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}. + * + * This version handles multiproofs in ${location} with ${hash ? 'a custom' : 'the default'} hashing function. + * + * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. + * + * NOTE: Consider the case where \`root == proof[0] && leaves.length == 0\` as it will return \`true\`. + * The \`leaves\` must be validated independently. See {processMultiProof${suffix}}. + */ +function multiProofVerify${suffix}(${formatArgsMultiline( + `bytes32[] ${location} proof`, + `bool[] ${location} proofFlags`, + 'bytes32 root', + `bytes32[] memory leaves`, + hash && `function(bytes32, bytes32) view returns (bytes32) ${hash}`, +)}) internal ${visibility} returns (bool) { + return processMultiProof${suffix}(proof, proofFlags, leaves${hash ? `, ${hash}` : ''}) == 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. + * + * This version handles multiproofs in ${location} with ${hash ? 'a custom' : 'the default'} hashing function. + * + * 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). + * + * NOTE: The _empty set_ (i.e. the case where \`proof.length == 1 && leaves.length == 0\`) is considered a no-op, + * and therefore a valid multiproof (i.e. it returns \`proof[0]\`). Consider disallowing this case if you're not + * validating the leaves elsewhere. + */ +function processMultiProof${suffix}(${formatArgsMultiline( + `bytes32[] ${location} proof`, + `bool[] ${location} proofFlags`, + `bytes32[] memory leaves`, + hash && `function(bytes32, bytes32) view returns (bytes32) ${hash}`, +)}) internal ${visibility} 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 proofFlagsLen = proofFlags.length; + + // Check proof validity. + if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen); + 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 < proofFlagsLen; i++) { + bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; + bytes32 b = proofFlags[i] + ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) + : proof[proofPos++]; + hashes[i] = ${hash ?? DEFAULT_HASH}(a, b); + } + + if (proofFlagsLen > 0) { + if (proofPos != proof.length) { + revert MerkleProofInvalidMultiproof(); + } + unchecked { + return hashes[proofFlagsLen - 1]; + } + } else if (leavesLen > 0) { + return leaves[0]; + } else { + return proof[0]; + } +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library MerkleProof {', + format( + [].concat( + errors, + OPTS.flatMap(opts => templateProof(opts)), + OPTS.flatMap(opts => templateMultiProof(opts)), + ), + ).trimEnd(), + '}', +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.opts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.opts.js new file mode 100644 index 0000000..911f239 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.opts.js @@ -0,0 +1,11 @@ +const { product } = require('../../helpers'); + +const OPTS = product( + [ + { suffix: '', location: 'memory' }, + { suffix: 'Calldata', location: 'calldata' }, + ], + [{ visibility: 'pure' }, { visibility: 'view', hash: 'hasher' }], +).map(objs => Object.assign({}, ...objs)); + +module.exports = { OPTS }; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.js new file mode 100644 index 0000000..9f3b771 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.js @@ -0,0 +1,92 @@ +const format = require('../format-lines'); +const sanitize = require('../helpers/sanitize'); +const { product } = require('../../helpers'); +const { SIZES } = require('./Packing.opts'); + +// TEMPLATE +const header = `\ +pragma solidity ^0.8.20; + +/** + * @dev Helper library packing and unpacking multiple values into bytesXX. + * + * Example usage: + * + * \`\`\`solidity + * library MyPacker { + * type MyType is bytes32; + * + * function _pack(address account, bytes4 selector, uint64 period) external pure returns (MyType) { + * bytes12 subpack = Packing.pack_4_8(selector, bytes8(period)); + * bytes32 pack = Packing.pack_20_12(bytes20(account), subpack); + * return MyType.wrap(pack); + * } + * + * function _unpack(MyType self) external pure returns (address, bytes4, uint64) { + * bytes32 pack = MyType.unwrap(self); + * return ( + * address(Packing.extract_32_20(pack, 0)), + * Packing.extract_32_4(pack, 20), + * uint64(Packing.extract_32_8(pack, 24)) + * ); + * } + * } + * \`\`\` + * + * _Available since v5.1._ + */ +// solhint-disable func-name-mixedcase +`; + +const errors = `\ +error OutOfRangeAccess(); +`; + +const pack = (left, right) => `\ +function pack_${left}_${right}(bytes${left} left, bytes${right} right) internal pure returns (bytes${ + left + right +} result) { + assembly ("memory-safe") { + left := ${sanitize.bytes('left', left)} + right := ${sanitize.bytes('right', right)} + result := or(left, shr(${8 * left}, right)) + } +} +`; + +const extract = (outer, inner) => `\ +function extract_${outer}_${inner}(bytes${outer} self, uint8 offset) internal pure returns (bytes${inner} result) { + if (offset > ${outer - inner}) revert OutOfRangeAccess(); + assembly ("memory-safe") { + result := ${sanitize.bytes('shl(mul(8, offset), self)', inner)} + } +} +`; + +const replace = (outer, inner) => `\ +function replace_${outer}_${inner}(bytes${outer} self, bytes${inner} value, uint8 offset) internal pure returns (bytes${outer} result) { + bytes${inner} oldValue = extract_${outer}_${inner}(self, offset); + assembly ("memory-safe") { + value := ${sanitize.bytes('value', inner)} + result := xor(self, shr(mul(8, offset), xor(oldValue, value))) + } +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library Packing {', + format( + [].concat( + errors, + product(SIZES, SIZES) + .filter(([left, right]) => SIZES.includes(left + right)) + .map(([left, right]) => pack(left, right)), + product(SIZES, SIZES) + .filter(([outer, inner]) => outer > inner) + .flatMap(([outer, inner]) => [extract(outer, inner), replace(outer, inner)]), + ), + ).trimEnd(), + '}', +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.opts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.opts.js new file mode 100644 index 0000000..893ad62 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.opts.js @@ -0,0 +1,3 @@ +module.exports = { + SIZES: [1, 2, 4, 6, 8, 10, 12, 16, 20, 22, 24, 28, 32], +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.t.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.t.js new file mode 100644 index 0000000..1feec28 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.t.js @@ -0,0 +1,48 @@ +const format = require('../format-lines'); +const { product } = require('../../helpers'); +const { SIZES } = require('./Packing.opts'); + +// TEMPLATE +const header = `\ +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {Packing} from "@openzeppelin/contracts/utils/Packing.sol"; +`; + +const testPack = (left, right) => `\ +function testPack(bytes${left} left, bytes${right} right) external pure { + assertEq(left, Packing.pack_${left}_${right}(left, right).extract_${left + right}_${left}(0)); + assertEq(right, Packing.pack_${left}_${right}(left, right).extract_${left + right}_${right}(${left})); +} +`; + +const testReplace = (outer, inner) => `\ +function testReplace(bytes${outer} container, bytes${inner} newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, ${outer - inner})); + + bytes${inner} oldValue = container.extract_${outer}_${inner}(offset); + + assertEq(newValue, container.replace_${outer}_${inner}(newValue, offset).extract_${outer}_${inner}(offset)); + assertEq(container, container.replace_${outer}_${inner}(newValue, offset).replace_${outer}_${inner}(oldValue, offset)); +} +`; + +// GENERATE +module.exports = format( + header, + 'contract PackingTest is Test {', + format( + [].concat( + 'using Packing for *;', + '', + product(SIZES, SIZES) + .filter(([left, right]) => SIZES.includes(left + right)) + .map(([left, right]) => testPack(left, right)), + product(SIZES, SIZES) + .filter(([outer, inner]) => outer > inner) + .map(([outer, inner]) => testReplace(outer, inner)), + ), + ).trimEnd(), + '}', +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js new file mode 100644 index 0000000..21000cf --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js @@ -0,0 +1,136 @@ +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/bool 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); +} +`; + +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); + } +} +`; + +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); +} +`; + +const boolToUint = `\ +/** + * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. + */ +function toUint(bool b) internal pure returns (uint256 u) { + assembly ("memory-safe") { + u := iszero(iszero(b)) + } +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library SafeCast {', + format( + [].concat(errors, LENGTHS.map(toUintDownCast), toUint(256), LENGTHS.map(toIntDownCast), toInt(256), boolToUint), + ).trimEnd(), + '}', +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Slot.opts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Slot.opts.js new file mode 100644 index 0000000..3eca2bc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Slot.opts.js @@ -0,0 +1,15 @@ +const { capitalize } = require('../../helpers'); + +const TYPES = [ + { type: 'address', isValueType: true }, + { type: 'bool', isValueType: true, name: 'Boolean' }, + { type: 'bytes32', isValueType: true, variants: ['bytes4'] }, + { type: 'uint256', isValueType: true, variants: ['uint32'] }, + { type: 'int256', isValueType: true, variants: ['int32'] }, + { type: 'string', isValueType: false }, + { type: 'bytes', isValueType: false }, +].map(type => Object.assign(type, { name: type.name ?? capitalize(type.type) })); + +Object.assign(TYPES, Object.fromEntries(TYPES.map(entry => [entry.type, entry]))); + +module.exports = { TYPES }; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.js new file mode 100644 index 0000000..a00e981 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.js @@ -0,0 +1,119 @@ +const format = require('../format-lines'); +const sanitize = require('../helpers/sanitize'); +const { TYPES } = require('./Slot.opts'); + +const header = `\ +pragma solidity ^0.8.20; + +/** + * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots + * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by + * the solidity language / compiler. + * + * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.]. + * + * Example usage: + * \`\`\`solidity + * contract Example { + * // Add the library methods + * using StorageSlot for bytes32; + * using SlotDerivation for bytes32; + * + * // Declare a namespace + * string private constant _NAMESPACE = ""; // eg. OpenZeppelin.Slot + * + * function setValueInNamespace(uint256 key, address newValue) internal { + * _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue; + * } + * + * function getValueInNamespace(uint256 key) internal view returns (address) { + * return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value; + * } + * } + * \`\`\` + * + * TIP: Consider using this library along with {StorageSlot}. + * + * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking + * upgrade safety will ignore the slots accessed through this library. + * + * _Available since v5.1._ + */ +`; + +const namespace = `\ +/** + * @dev Derive an ERC-7201 slot from a string (namespace). + */ +function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) { + assembly ("memory-safe") { + mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1)) + slot := and(keccak256(0x00, 0x20), not(0xff)) + } +} +`; + +const array = `\ +/** + * @dev Add an offset to a slot to get the n-th element of a structure or an array. + */ +function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) { + unchecked { + return bytes32(uint256(slot) + pos); + } +} + +/** + * @dev Derive the location of the first element in an array from the slot where the length is stored. + */ +function deriveArray(bytes32 slot) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + mstore(0x00, slot) + result := keccak256(0x00, 0x20) + } +} +`; + +const mapping = ({ type }) => `\ +/** + * @dev Derive the location of a mapping element from the key. + */ +function deriveMapping(bytes32 slot, ${type} key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + mstore(0x00, ${(sanitize[type] ?? (x => x))('key')}) + mstore(0x20, slot) + result := keccak256(0x00, 0x40) + } +} +`; + +const mapping2 = ({ type }) => `\ +/** + * @dev Derive the location of a mapping element from the key. + */ +function deriveMapping(bytes32 slot, ${type} memory key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + let length := mload(key) + let begin := add(key, 0x20) + let end := add(begin, length) + let cache := mload(end) + mstore(end, slot) + result := keccak256(begin, add(length, 0x20)) + mstore(end, cache) + } +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library SlotDerivation {', + format( + [].concat( + namespace, + array, + TYPES.map(type => (type.isValueType ? mapping(type) : mapping2(type))), + ), + ).trimEnd(), + '}', +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.t.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.t.js new file mode 100644 index 0000000..824af07 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.t.js @@ -0,0 +1,127 @@ +const format = require('../format-lines'); +const { capitalize } = require('../../helpers'); +const { TYPES } = require('./Slot.opts'); + +const header = `\ +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {SymTest} from "halmos-cheatcodes/SymTest.sol"; +import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; +`; + +const array = `\ +bytes[] private _array; + +function symbolicDeriveArray(uint256 length, uint256 offset) public { + vm.assume(length > 0); + vm.assume(offset < length); + _assertDeriveArray(length, offset); +} + +function testDeriveArray(uint256 length, uint256 offset) public { + length = bound(length, 1, type(uint256).max); + offset = bound(offset, 0, length - 1); + _assertDeriveArray(length, offset); +} + +function _assertDeriveArray(uint256 length, uint256 offset) public { + bytes32 baseSlot; + assembly { + baseSlot := _array.slot + sstore(baseSlot, length) // store length so solidity access does not revert + } + + bytes storage derived = _array[offset]; + bytes32 derivedSlot; + assembly { + derivedSlot := derived.slot + } + + assertEq(baseSlot.deriveArray().offset(offset), derivedSlot); +} +`; + +const mapping = ({ type, name }) => `\ +mapping(${type} => bytes) private _${type}Mapping; + +function testSymbolicDeriveMapping${name}(${type} key) public view { + bytes32 baseSlot; + assembly { + baseSlot := _${type}Mapping.slot + } + + bytes storage derived = _${type}Mapping[key]; + bytes32 derivedSlot; + assembly { + derivedSlot := derived.slot + } + + assertEq(baseSlot.deriveMapping(key), derivedSlot); +} +`; + +const mappingDirty = ({ type, name }) => `\ +function testSymbolicDeriveMapping${name}Dirty(bytes32 dirtyKey) public { + ${type} key; + assembly { + key := dirtyKey + } + + // run the "normal" test using a potentially dirty value + testSymbolicDeriveMapping${name}(key); +} +`; + +const boundedMapping = ({ type, name }) => `\ +mapping(${type} => bytes) private _${type}Mapping; + +function testDeriveMapping${name}(${type} memory key) public view { + _assertDeriveMapping${name}(key); +} + +function symbolicDeriveMapping${name}() public view { + _assertDeriveMapping${name}(svm.create${name}(256, "DeriveMapping${name}Input")); +} + +function _assertDeriveMapping${name}(${type} memory key) internal view { + bytes32 baseSlot; + assembly { + baseSlot := _${type}Mapping.slot + } + + bytes storage derived = _${type}Mapping[key]; + bytes32 derivedSlot; + assembly { + derivedSlot := derived.slot + } + + assertEq(baseSlot.deriveMapping(key), derivedSlot); +} +`; + +// GENERATE +module.exports = format( + header, + 'contract SlotDerivationTest is Test, SymTest {', + format( + [].concat( + 'using SlotDerivation for bytes32;', + '', + array, + TYPES.flatMap(type => + [].concat( + type, + (type.variants ?? []).map(variant => ({ + type: variant, + name: capitalize(variant), + isValueType: type.isValueType, + })), + ), + ).map(type => (type.isValueType ? mapping(type) : boundedMapping(type))), + mappingDirty(TYPES.bool), + mappingDirty(TYPES.address), + ), + ).trimEnd(), + '}', +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js new file mode 100644 index 0000000..53287b8 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js @@ -0,0 +1,77 @@ +const format = require('../format-lines'); +const { TYPES } = require('./Slot.opts'); + +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 ERC-1967 implementation slot: + * \`\`\`solidity + * contract ERC1967 { + * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. + * 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; + * } + * } + * \`\`\` + * + * TIP: Consider using this library along with {SlotDerivation}. + */ +`; + +const struct = ({ type, name }) => `\ +struct ${name}Slot { + ${type} value; +} +`; + +const get = ({ name }) => `\ +/** + * @dev Returns ${ + name.toLowerCase().startsWith('a') ? 'an' : 'a' + } \`${name}Slot\` with member \`value\` located at \`slot\`. + */ +function get${name}Slot(bytes32 slot) internal pure returns (${name}Slot storage r) { + assembly ("memory-safe") { + r.slot := slot + } +} +`; + +const getStorage = ({ type, name }) => `\ +/** + * @dev Returns an \`${name}Slot\` representation of the ${type} storage pointer \`store\`. + */ +function get${name}Slot(${type} storage store) internal pure returns (${name}Slot storage r) { + assembly ("memory-safe") { + r.slot := store.slot + } +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library StorageSlot {', + format( + [].concat( + TYPES.map(type => struct(type)), + TYPES.flatMap(type => [get(type), !type.isValueType && getStorage(type)].filter(Boolean)), + ), + ).trimEnd(), + '}', +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlotMock.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlotMock.js new file mode 100644 index 0000000..c6d326a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlotMock.js @@ -0,0 +1,57 @@ +const format = require('../format-lines'); +const { TYPES } = require('./Slot.opts'); + +const header = `\ +pragma solidity ^0.8.20; + +import {Multicall} from "../utils/Multicall.sol"; +import {StorageSlot} from "../utils/StorageSlot.sol"; +`; + +const storageSetValueType = ({ type, name }) => `\ +function set${name}Slot(bytes32 slot, ${type} value) public { + slot.get${name}Slot().value = value; +} +`; + +const storageGetValueType = ({ type, name }) => `\ +function get${name}Slot(bytes32 slot) public view returns (${type}) { + return slot.get${name}Slot().value; +} +`; + +const storageSetNonValueType = ({ type, name }) => `\ +mapping(uint256 key => ${type}) public ${type}Map; + +function set${name}Slot(bytes32 slot, ${type} calldata value) public { + slot.get${name}Slot().value = value; +} + +function set${name}Storage(uint256 key, ${type} calldata value) public { + ${type}Map[key].get${name}Slot().value = value; +} + +function get${name}Slot(bytes32 slot) public view returns (${type} memory) { + return slot.get${name}Slot().value; +} + +function get${name}Storage(uint256 key) public view returns (${type} memory) { + return ${type}Map[key].get${name}Slot().value; +} +`; + +// GENERATE +module.exports = format( + header, + 'contract StorageSlotMock is Multicall {', + format( + [].concat( + 'using StorageSlot for *;', + '', + TYPES.filter(type => type.isValueType).map(type => storageSetValueType(type)), + TYPES.filter(type => type.isValueType).map(type => storageGetValueType(type)), + TYPES.filter(type => !type.isValueType).map(type => storageSetNonValueType(type)), + ), + ).trimEnd(), + '}', +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlot.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlot.js new file mode 100644 index 0000000..9ede32f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlot.js @@ -0,0 +1,80 @@ +const format = require('../format-lines'); +const { TYPES } = require('./Slot.opts'); + +const header = `\ +pragma solidity ^0.8.24; + +/** + * @dev Library for reading and writing value-types to specific transient storage slots. + * + * Transient slots are often used to store temporary values that are removed after the current transaction. + * This library helps with reading and writing to such slots without the need for inline assembly. + * + * * Example reading and writing values using transient storage: + * \`\`\`solidity + * contract Lock { + * using TransientSlot for *; + * + * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. + * bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542; + * + * modifier locked() { + * require(!_LOCK_SLOT.asBoolean().tload()); + * + * _LOCK_SLOT.asBoolean().tstore(true); + * _; + * _LOCK_SLOT.asBoolean().tstore(false); + * } + * } + * \`\`\` + * + * TIP: Consider using this library along with {SlotDerivation}. + */ +`; + +const udvt = ({ type, name }) => `\ +/** + * @dev UDVT that represents a slot holding ${type == 'address' ? 'an' : 'a'} ${type}. + */ +type ${name}Slot is bytes32; + +/** + * @dev Cast an arbitrary slot to a ${name}Slot. + */ +function as${name}(bytes32 slot) internal pure returns (${name}Slot) { + return ${name}Slot.wrap(slot); +} +`; + +const transient = ({ type, name }) => `\ +/** + * @dev Load the value held at location \`slot\` in transient storage. + */ +function tload(${name}Slot slot) internal view returns (${type} value) { + assembly ("memory-safe") { + value := tload(slot) + } +} + +/** + * @dev Store \`value\` at location \`slot\` in transient storage. + */ +function tstore(${name}Slot slot, ${type} value) internal { + assembly ("memory-safe") { + tstore(slot, value) + } +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library TransientSlot {', + format( + [].concat( + TYPES.filter(type => type.isValueType).map(type => udvt(type)), + TYPES.filter(type => type.isValueType).map(type => transient(type)), + ), + ).trimEnd(), + '}', +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlotMock.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlotMock.js new file mode 100644 index 0000000..4807b0c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlotMock.js @@ -0,0 +1,35 @@ +const format = require('../format-lines'); +const { TYPES } = require('./Slot.opts'); + +const header = `\ +pragma solidity ^0.8.24; + +import {Multicall} from "../utils/Multicall.sol"; +import {TransientSlot} from "../utils/TransientSlot.sol"; +`; + +const transient = ({ type, name }) => `\ +event ${name}Value(bytes32 slot, ${type} value); + +function tload${name}(bytes32 slot) public { + emit ${name}Value(slot, slot.as${name}().tload()); +} + +function tstore(bytes32 slot, ${type} value) public { + slot.as${name}().tstore(value); +} +`; + +// GENERATE +module.exports = format( + header, + 'contract TransientSlotMock is Multicall {', + format( + [].concat( + 'using TransientSlot for *;', + '', + TYPES.filter(type => type.isValueType).map(type => transient(type)), + ), + ).trimEnd(), + '}', +); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/conversion.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/conversion.js new file mode 100644 index 0000000..9221f7c --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/git-user-config.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/git-user-config.sh new file mode 100644 index 0000000..e7b81c3 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/helpers.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/helpers.js new file mode 100644 index 0000000..d28c086 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/helpers.js @@ -0,0 +1,7 @@ +const iterate = require('../test/helpers/iterate'); +const strings = require('../test/helpers/strings'); + +module.exports = { + ...iterate, + ...strings, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/prepack.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/prepack.sh new file mode 100755 index 0000000..6af1032 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/prepare-docs.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/prepare-docs.sh new file mode 100755 index 0000000..0ff5b94 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/format-changelog.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/format-changelog.js new file mode 100755 index 0000000..c96dc92 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/synchronize-versions.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/synchronize-versions.js new file mode 100755 index 0000000..15aa259 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/update-comment.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/update-comment.js new file mode 100755 index 0000000..9d6df26 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/version.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/version.sh new file mode 100755 index 0000000..7b0ddea --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh new file mode 100644 index 0000000..bcf9b9a --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/github-release.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/github-release.js new file mode 100644 index 0000000..f213106 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/integrity-check.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/integrity-check.sh new file mode 100644 index 0000000..86e99f9 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/pack.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/pack.sh new file mode 100644 index 0000000..ce30712 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/publish.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/publish.sh new file mode 100644 index 0000000..e490e5d --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/rerun.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/rerun.js new file mode 100644 index 0000000..f48ce6e --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js new file mode 100644 index 0000000..59b03b2 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/start.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/start.sh new file mode 100644 index 0000000..7683ec5 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/state.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/state.js new file mode 100644 index 0000000..002f777 --- /dev/null +++ b/typescript/packages/account-modules/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(packageName, version) { + const res = await fetch(`https://registry.npmjs.com/${packageName}/${version}`); + return res.ok; +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js new file mode 100644 index 0000000..e156032 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/set-max-old-space-size.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/set-max-old-space-size.sh new file mode 100755 index 0000000..f56b11d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/set-max-old-space-size.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env sh + +# This script sets the node `--max-old-space-size` to 8192 if it is not set already. +# All existing `NODE_OPTIONS` are retained as is. + +export NODE_OPTIONS="${NODE_OPTIONS:-}" + +if [ "${NODE_OPTIONS##*--max-old-space-size*}" = "$NODE_OPTIONS" ]; then + export NODE_OPTIONS="${NODE_OPTIONS} --max-old-space-size=8192" +fi diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/index.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/index.js new file mode 100644 index 0000000..9625027 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/package.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/package.json new file mode 100644 index 0000000..ce9690d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/package.json @@ -0,0 +1,8 @@ +{ + "name": "solhint-plugin-openzeppelin", + "version": "0.0.0", + "private": true, + "dependencies": { + "minimatch": "^3.1.2" + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/update-docs-branch.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/update-docs-branch.js new file mode 100644 index 0000000..cf61daa --- /dev/null +++ b/typescript/packages/account-modules/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 { + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/README.md new file mode 100644 index 0000000..2309f9e --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/patch-apply.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/patch-apply.sh new file mode 100755 index 0000000..d9e1758 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/patch-save.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/patch-save.sh new file mode 100755 index 0000000..111e6f1 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile-onto.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile-onto.sh new file mode 100644 index 0000000..ae14da4 --- /dev/null +++ b/typescript/packages/account-modules/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" --no-verify + +# return to original branch +git checkout "$start_branch" diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile.sh new file mode 100644 index 0000000..f7c848c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile.sh @@ -0,0 +1,50 @@ +#!/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/access/manager/AccessManager.sol' \ + -p 'contracts/finance/VestingWallet.sol' \ + -p 'contracts/governance/TimelockController.sol' \ + -p 'contracts/metatx/ERC2771Forwarder.sol' \ + -n \ + -N 'contracts/mocks/**/*' \ + -q '@openzeppelin/' + +# delete compilation artifacts of vanilla code +npm run clean diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/upgradeable.patch b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/upgradeable.patch new file mode 100644 index 0000000..0fd5caa --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/upgradeable.patch @@ -0,0 +1,398 @@ +diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md +deleted file mode 100644 +index 35ad097ff..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 60d0a430a..0e4f91a6d 100644 +--- a/README.md ++++ b/README.md +@@ -19,6 +19,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 +@@ -26,7 +29,7 @@ + #### Hardhat (npm) + + ``` +-$ npm install @openzeppelin/contracts ++$ npm install @openzeppelin/contracts-upgradeable + ``` + + #### Foundry (git) +@@ -38,10 +41,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 + +@@ -50,10 +53,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 70ae73bc2..ef659873f 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": "5.3.0", + "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 c39954e35..fe681f87a 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"; + + /** +@@ -25,33 +24,20 @@ import {IERC5267} from "../../interfaces/IERC5267.sol"; + * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method + * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. + * +- * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain +- * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the +- * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. +- * +- * @custom:oz-upgrades-unsafe-allow state-variable-immutable ++ * NOTE: The upgradeable version of this contract does not use an immutable cache and recomputes the domain separator ++ * each time {_domainSeparatorV4} is called. That is cheaper than accessing a cached version in cold storage. + */ + 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; +- // slither-disable-next-line constable-states +- string private _nameFallback; +- // slither-disable-next-line constable-states +- string private _versionFallback; ++ string private _name; ++ string private _version; + + /** + * @dev Initializes the domain separator and parameter caches. +@@ -66,29 +52,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 +105,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 +123,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 eeeaf0bcd..65581c544 100644 +--- a/package.json ++++ b/package.json +@@ -34,7 +34,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/account/AccountERC7702.test.js b/test/account/AccountERC7702.test.js +index d08a52209..7a44bccfe 100644 +--- a/test/account/AccountERC7702.test.js ++++ b/test/account/AccountERC7702.test.js +@@ -26,8 +26,8 @@ async function fixture() { + + // domain cannot be fetched using getDomain(mock) before the mock is deployed + const domain = { +- name: 'AccountERC7702Mock', +- version: '1', ++ name: '', // Not initialized in the context of signer ++ version: '', // Not initialized in the context of signer + chainId: entrypointDomain.chainId, + verifyingContract: mock.address, + }; +diff --git a/test/account/examples/AccountERC7702WithModulesMock.test.js b/test/account/examples/AccountERC7702WithModulesMock.test.js +index 9ee5f9177..f6106bcc7 100644 +--- a/test/account/examples/AccountERC7702WithModulesMock.test.js ++++ b/test/account/examples/AccountERC7702WithModulesMock.test.js +@@ -36,8 +36,8 @@ async function fixture() { + + // domain cannot be fetched using getDomain(mock) before the mock is deployed + const domain = { +- name: 'AccountERC7702WithModulesMock', +- version: '1', ++ name: '', // Not initialized in the context of signer ++ version: '', // Not initialized in the context of signer + chainId: entrypointDomain.chainId, + verifyingContract: mock.address, + }; +diff --git a/test/utils/cryptography/EIP712.test.js b/test/utils/cryptography/EIP712.test.js +index 2b6e7fa97..268e0d29d 100644 +--- a/test/utils/cryptography/EIP712.test.js ++++ b/test/utils/cryptography/EIP712.test.js +@@ -47,27 +47,6 @@ describe('EIP712', function () { + const rebuildDomain = await getDomain(this.eip712); + expect(rebuildDomain).to.be.deep.equal(this.domain); + }); +- +- 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 ethers.deployContract('$Clones'); +- +- const clone = await factory +- .$clone(this.eip712) +- .then(tx => tx.wait()) +- .then(receipt => receipt.logs.find(ev => ev.fragment.name == 'return$clone_address').args.instance) +- .then(address => ethers.getContractAt('$EIP712Verifier', address)); +- +- const expectedDomain = { ...this.domain, verifyingContract: clone.target }; +- expect(await getDomain(clone)).to.be.deep.equal(expectedDomain); +- +- const expectedSeparator = await domainSeparator(expectedDomain); +- expect(await clone.$_domainSeparatorV4()).to.equal(expectedSeparator); +- }); +- } + }); + + it('hash digest', async function () { diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/slither.config.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/slither.config.json new file mode 100644 index 0000000..47892af --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/slither.config.json @@ -0,0 +1,4 @@ +{ + "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/vendor,contracts-exposed" +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/solhint.config.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/solhint.config.js new file mode 100644 index 0000000..07e7526 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/solhint.config.js @@ -0,0 +1,29 @@ +const customRules = require('solhint-plugin-openzeppelin'); + +const rules = [ + 'avoid-tx-origin', + 'const-name-snakecase', + 'contract-name-capwords', + 'event-name-capwords', + 'max-states-count', + 'explicit-types', + 'func-name-mixedcase', + 'func-param-name-mixedcase', + 'imports-on-top', + 'modifier-name-mixedcase', + 'no-console', + 'no-global-import', + 'no-unused-vars', + 'quotes', + 'use-forbidden-name', + 'var-name-mixedcase', + 'visibility-modifier-order', + 'interface-starts-with-i', + 'duplicated-imports', + ...customRules.map(r => `openzeppelin/${r.ruleId}`), +]; + +module.exports = { + plugins: ['openzeppelin'], + rules: Object.fromEntries(rules.map(r => [r, 'error'])), +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/TESTING.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/TESTING.md new file mode 100644 index 0000000..321c7e5 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/TESTING.md @@ -0,0 +1,3 @@ +## Testing + +Unit tests 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/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js new file mode 100644 index 0000000..c596e6a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js @@ -0,0 +1,874 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); + +const time = require('../helpers/time'); + +const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); + +const DEFAULT_ADMIN_ROLE = ethers.ZeroHash; +const ROLE = ethers.id('ROLE'); +const OTHER_ROLE = ethers.id('OTHER_ROLE'); + +function shouldBehaveLikeAccessControl() { + beforeEach(async function () { + [this.authorized, this.other, this.otherAdmin] = this.accounts; + }); + + shouldSupportInterfaces(['AccessControl']); + + describe('default admin', function () { + it('deployer has default admin role', async function () { + expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)).to.be.true; + }); + + it("other role's admin is the default admin role", async function () { + expect(await this.mock.getRoleAdmin(ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + + it("default admin role's admin is itself", async function () { + expect(await this.mock.getRoleAdmin(DEFAULT_ADMIN_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + }); + + describe('granting', function () { + beforeEach(async function () { + await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized); + }); + + it('non-admin cannot grant role to other accounts', async function () { + await expect(this.mock.connect(this.other).grantRole(ROLE, this.authorized)) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.other, DEFAULT_ADMIN_ROLE); + }); + + it('accounts can be granted a role multiple times', async function () { + await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized); + await expect(this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized)).to.not.emit( + this.mock, + 'RoleGranted', + ); + }); + }); + + describe('revoking', function () { + it('roles that are not had can be revoked', async function () { + expect(await this.mock.hasRole(ROLE, this.authorized)).to.be.false; + + await expect(this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.authorized)).to.not.emit( + this.mock, + 'RoleRevoked', + ); + }); + + describe('with granted role', function () { + beforeEach(async function () { + await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized); + }); + + it('admin can revoke role', async function () { + await expect(this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.authorized)) + .to.emit(this.mock, 'RoleRevoked') + .withArgs(ROLE, this.authorized, this.defaultAdmin); + + expect(await this.mock.hasRole(ROLE, this.authorized)).to.be.false; + }); + + it('non-admin cannot revoke role', async function () { + await expect(this.mock.connect(this.other).revokeRole(ROLE, this.authorized)) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.other, DEFAULT_ADMIN_ROLE); + }); + + it('a role can be revoked multiple times', async function () { + await this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.authorized); + + await expect(this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.authorized)).to.not.emit( + this.mock, + 'RoleRevoked', + ); + }); + }); + }); + + describe('renouncing', function () { + it('roles that are not had can be renounced', async function () { + await expect(this.mock.connect(this.authorized).renounceRole(ROLE, this.authorized)).to.not.emit( + this.mock, + 'RoleRevoked', + ); + }); + + describe('with granted role', function () { + beforeEach(async function () { + await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized); + }); + + it('bearer can renounce role', async function () { + await expect(this.mock.connect(this.authorized).renounceRole(ROLE, this.authorized)) + .to.emit(this.mock, 'RoleRevoked') + .withArgs(ROLE, this.authorized, this.authorized); + + expect(await this.mock.hasRole(ROLE, this.authorized)).to.be.false; + }); + + it('only the sender can renounce their roles', async function () { + await expect( + this.mock.connect(this.defaultAdmin).renounceRole(ROLE, this.authorized), + ).to.be.revertedWithCustomError(this.mock, 'AccessControlBadConfirmation'); + }); + + it('a role can be renounced multiple times', async function () { + await this.mock.connect(this.authorized).renounceRole(ROLE, this.authorized); + + await expect(this.mock.connect(this.authorized).renounceRole(ROLE, this.authorized)).not.to.emit( + this.mock, + 'RoleRevoked', + ); + }); + }); + }); + + describe('setting role admin', function () { + beforeEach(async function () { + await expect(this.mock.$_setRoleAdmin(ROLE, OTHER_ROLE)) + .to.emit(this.mock, 'RoleAdminChanged') + .withArgs(ROLE, DEFAULT_ADMIN_ROLE, OTHER_ROLE); + + await this.mock.connect(this.defaultAdmin).grantRole(OTHER_ROLE, this.otherAdmin); + }); + + it("a role's admin role can be changed", async function () { + expect(await this.mock.getRoleAdmin(ROLE)).to.equal(OTHER_ROLE); + }); + + it('the new admin can grant roles', async function () { + await expect(this.mock.connect(this.otherAdmin).grantRole(ROLE, this.authorized)) + .to.emit(this.mock, 'RoleGranted') + .withArgs(ROLE, this.authorized, this.otherAdmin); + }); + + it('the new admin can revoke roles', async function () { + await this.mock.connect(this.otherAdmin).grantRole(ROLE, this.authorized); + await expect(this.mock.connect(this.otherAdmin).revokeRole(ROLE, this.authorized)) + .to.emit(this.mock, 'RoleRevoked') + .withArgs(ROLE, this.authorized, this.otherAdmin); + }); + + it("a role's previous admins no longer grant roles", async function () { + await expect(this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized)) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.defaultAdmin, OTHER_ROLE); + }); + + it("a role's previous admins no longer revoke roles", async function () { + await expect(this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.authorized)) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.defaultAdmin, OTHER_ROLE); + }); + }); + + describe('onlyRole modifier', function () { + beforeEach(async function () { + await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized); + }); + + it('do not revert if sender has role', async function () { + await this.mock.connect(this.authorized).$_checkRole(ROLE); + }); + + it("revert if sender doesn't have role #1", async function () { + await expect(this.mock.connect(this.other).$_checkRole(ROLE)) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.other, ROLE); + }); + + it("revert if sender doesn't have role #2", async function () { + await expect(this.mock.connect(this.authorized).$_checkRole(OTHER_ROLE)) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.authorized, OTHER_ROLE); + }); + }); + + describe('internal functions', function () { + describe('_grantRole', function () { + it('return true if the account does not have the role', async function () { + await expect(this.mock.$_grantRole(ROLE, this.authorized)) + .to.emit(this.mock, 'return$_grantRole') + .withArgs(true); + }); + + it('return false if the account has the role', async function () { + await this.mock.$_grantRole(ROLE, this.authorized); + + await expect(this.mock.$_grantRole(ROLE, this.authorized)) + .to.emit(this.mock, 'return$_grantRole') + .withArgs(false); + }); + }); + + describe('_revokeRole', function () { + it('return true if the account has the role', async function () { + await this.mock.$_grantRole(ROLE, this.authorized); + + await expect(this.mock.$_revokeRole(ROLE, this.authorized)) + .to.emit(this.mock, 'return$_revokeRole') + .withArgs(true); + }); + + it('return false if the account does not have the role', async function () { + await expect(this.mock.$_revokeRole(ROLE, this.authorized)) + .to.emit(this.mock, 'return$_revokeRole') + .withArgs(false); + }); + }); + }); +} + +function shouldBehaveLikeAccessControlEnumerable() { + beforeEach(async function () { + [this.authorized, this.other, this.otherAdmin, this.otherAuthorized] = this.accounts; + }); + + shouldSupportInterfaces(['AccessControlEnumerable']); + + describe('enumerating', function () { + it('role bearers can be enumerated', async function () { + await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized); + await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.other); + await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.otherAuthorized); + await this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.other); + + const expectedMembers = [this.authorized.address, this.otherAuthorized.address]; + + const memberCount = await this.mock.getRoleMemberCount(ROLE); + const members = []; + for (let i = 0; i < memberCount; ++i) { + members.push(await this.mock.getRoleMember(ROLE, i)); + } + + expect(memberCount).to.equal(expectedMembers.length); + expect(members).to.deep.equal(expectedMembers); + expect(await this.mock.getRoleMembers(ROLE)).to.deep.equal(expectedMembers); + }); + + it('role enumeration should be in sync after renounceRole call', async function () { + expect(await this.mock.getRoleMemberCount(ROLE)).to.equal(0); + await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.defaultAdmin); + expect(await this.mock.getRoleMemberCount(ROLE)).to.equal(1); + await this.mock.connect(this.defaultAdmin).renounceRole(ROLE, this.defaultAdmin); + expect(await this.mock.getRoleMemberCount(ROLE)).to.equal(0); + }); + }); +} + +function shouldBehaveLikeAccessControlDefaultAdminRules() { + shouldSupportInterfaces(['AccessControlDefaultAdminRules']); + + beforeEach(async function () { + [this.newDefaultAdmin, this.other] = this.accounts; + }); + + 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.mock[getter](); + expect(value).to.equal(this.defaultAdmin); + expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, value)).to.be.true; + }); + + it('changes if the default admin changes', async function () { + // Starts an admin transfer + await this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin); + + // Wait for acceptance + await time.increaseBy.timestamp(this.delay + 1n, false); + await this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer(); + + const value = await this.mock[getter](); + expect(value).to.equal(this.newDefaultAdmin); + }); + }); + } + + describe('pendingDefaultAdmin()', function () { + it('returns 0 if no pending default admin transfer', async function () { + const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); + expect(newAdmin).to.equal(ethers.ZeroAddress); + expect(schedule).to.equal(0); + }); + + describe('when there is a scheduled default admin transfer', function () { + beforeEach('begins admin transfer', async function () { + await this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin); + }); + + for (const [fromSchedule, tag] of [ + [-1n, 'before'], + [0n, 'exactly when'], + [1n, 'after'], + ]) { + it(`returns pending admin and schedule ${tag} it passes if not accepted`, async function () { + // Wait until schedule + fromSchedule + const { schedule: firstSchedule } = await this.mock.pendingDefaultAdmin(); + await time.increaseTo.timestamp(firstSchedule + fromSchedule); + + const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); + expect(newAdmin).to.equal(this.newDefaultAdmin); + expect(schedule).to.equal(firstSchedule); + }); + } + + it('returns 0 after schedule passes and the transfer was accepted', async function () { + // Wait after schedule + const { schedule: firstSchedule } = await this.mock.pendingDefaultAdmin(); + await time.increaseTo.timestamp(firstSchedule + 1n, false); + + // Accepts + await this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer(); + + const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); + expect(newAdmin).to.equal(ethers.ZeroAddress); + expect(schedule).to.equal(0); + }); + }); + }); + + describe('defaultAdminDelay()', function () { + it('returns the current delay', async function () { + expect(await this.mock.defaultAdminDelay()).to.equal(this.delay); + }); + + describe('when there is a scheduled delay change', function () { + const newDelay = 0x1337n; // Any change + + beforeEach('begins delay change', async function () { + await this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(newDelay); + }); + + for (const [fromSchedule, tag, expectNew, delayTag] of [ + [-1n, 'before', false, 'old'], + [0n, 'exactly when', false, 'old'], + [1n, 'after', true, 'new'], + ]) { + it(`returns ${delayTag} delay ${tag} delay schedule passes`, async function () { + // Wait until schedule + fromSchedule + const { schedule } = await this.mock.pendingDefaultAdminDelay(); + await time.increaseTo.timestamp(schedule + fromSchedule); + + const currentDelay = await this.mock.defaultAdminDelay(); + expect(currentDelay).to.equal(expectNew ? newDelay : this.delay); + }); + } + }); + }); + + describe('pendingDefaultAdminDelay()', function () { + it('returns 0 if not set', async function () { + const { newDelay, schedule } = await this.mock.pendingDefaultAdminDelay(); + expect(newDelay).to.equal(0); + expect(schedule).to.equal(0); + }); + + describe('when there is a scheduled delay change', function () { + const newDelay = 0x1337n; // Any change + + beforeEach('begins admin transfer', async function () { + await this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(newDelay); + }); + + for (const [fromSchedule, tag, expectedDelay, delayTag, expectZeroSchedule] of [ + [-1n, 'before', newDelay, 'new'], + [0n, 'exactly when', newDelay, 'new'], + [1n, 'after', 0, 'zero', true], + ]) { + it(`returns ${delayTag} delay ${tag} delay schedule passes`, async function () { + // Wait until schedule + fromSchedule + const { schedule: firstSchedule } = await this.mock.pendingDefaultAdminDelay(); + await time.increaseTo.timestamp(firstSchedule + fromSchedule); + + const { newDelay, schedule } = await this.mock.pendingDefaultAdminDelay(); + expect(newDelay).to.equal(expectedDelay); + expect(schedule).to.equal(expectZeroSchedule ? 0 : firstSchedule); + }); + } + }); + }); + + describe('defaultAdminDelayIncreaseWait()', function () { + it('should return 5 days (default)', async function () { + expect(await this.mock.defaultAdminDelayIncreaseWait()).to.equal(time.duration.days(5)); + }); + }); + + it('should revert if granting default admin role', async function () { + await expect( + this.mock.connect(this.defaultAdmin).grantRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin), + ).to.be.revertedWithCustomError(this.mock, 'AccessControlEnforcedDefaultAdminRules'); + }); + + it('should revert if revoking default admin role', async function () { + await expect( + this.mock.connect(this.defaultAdmin).revokeRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin), + ).to.be.revertedWithCustomError(this.mock, 'AccessControlEnforcedDefaultAdminRules'); + }); + + it("should revert if defaultAdmin's admin is changed", async function () { + await expect(this.mock.$_setRoleAdmin(DEFAULT_ADMIN_ROLE, OTHER_ROLE)).to.be.revertedWithCustomError( + this.mock, + 'AccessControlEnforcedDefaultAdminRules', + ); + }); + + it('should not grant the default admin role twice', async function () { + await expect(this.mock.$_grantRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)).to.be.revertedWithCustomError( + this.mock, + 'AccessControlEnforcedDefaultAdminRules', + ); + }); + + describe('begins a default admin transfer', function () { + it('reverts if called by non default admin accounts', async function () { + await expect(this.mock.connect(this.other).beginDefaultAdminTransfer(this.newDefaultAdmin)) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.other, DEFAULT_ADMIN_ROLE); + }); + + describe('when there is no pending delay nor pending admin transfer', function () { + it('should set pending default admin and schedule', async function () { + const nextBlockTimestamp = (await time.clock.timestamp()) + 1n; + const acceptSchedule = nextBlockTimestamp + this.delay; + + await time.increaseTo.timestamp(nextBlockTimestamp, false); // set timestamp but don't mine the block yet + await expect(this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin)) + .to.emit(this.mock, 'DefaultAdminTransferScheduled') + .withArgs(this.newDefaultAdmin, acceptSchedule); + + const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); + expect(newAdmin).to.equal(this.newDefaultAdmin); + expect(schedule).to.equal(acceptSchedule); + }); + }); + + describe('when there is a pending admin transfer', function () { + beforeEach('sets a pending default admin transfer', async function () { + await this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin); + this.acceptSchedule = (await time.clock.timestamp()) + this.delay; + }); + + for (const [fromSchedule, tag] of [ + [-1n, 'before'], + [0n, 'exactly when'], + [1n, 'after'], + ]) { + it(`should be able to begin a transfer again ${tag} acceptSchedule passes`, async function () { + // Wait until schedule + fromSchedule + await time.increaseTo.timestamp(this.acceptSchedule + fromSchedule, false); + + // defaultAdmin changes its mind and begin again to another address + await expect(this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.other)).to.emit( + this.mock, + 'DefaultAdminTransferCanceled', // Cancellation is always emitted since it was never accepted + ); + const newSchedule = (await time.clock.timestamp()) + this.delay; + const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); + expect(newAdmin).to.equal(this.other); + expect(schedule).to.equal(newSchedule); + }); + } + + it('should not emit a cancellation event if the new default admin accepted', async function () { + // Wait until the acceptSchedule has passed + await time.increaseTo.timestamp(this.acceptSchedule + 1n, false); + + // Accept and restart + await this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer(); + await expect(this.mock.connect(this.newDefaultAdmin).beginDefaultAdminTransfer(this.other)).to.not.emit( + this.mock, + 'DefaultAdminTransferCanceled', + ); + }); + }); + + describe('when there is a pending delay', function () { + const newDelay = time.duration.hours(3); + + beforeEach('schedule a delay change', async function () { + await this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(newDelay); + ({ schedule: this.effectSchedule } = await this.mock.pendingDefaultAdminDelay()); + }); + + for (const [fromSchedule, schedulePassed, expectNewDelay] of [ + [-1n, 'before', false], + [0n, 'exactly when', false], + [1n, 'after', true], + ]) { + it(`should set the ${ + expectNewDelay ? 'new' : 'old' + } delay and apply it to next default admin transfer schedule ${schedulePassed} effectSchedule passed`, async function () { + // Wait until the expected fromSchedule time + const nextBlockTimestamp = this.effectSchedule + fromSchedule; + await time.increaseTo.timestamp(nextBlockTimestamp, false); + + // Start the new default admin transfer and get its schedule + const expectedDelay = expectNewDelay ? newDelay : this.delay; + const expectedAcceptSchedule = nextBlockTimestamp + expectedDelay; + await expect(this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin)) + .to.emit(this.mock, 'DefaultAdminTransferScheduled') + .withArgs(this.newDefaultAdmin, expectedAcceptSchedule); + + // Check that the schedule corresponds with the new delay + const { newAdmin, schedule: transferSchedule } = await this.mock.pendingDefaultAdmin(); + expect(newAdmin).to.equal(this.newDefaultAdmin); + expect(transferSchedule).to.equal(expectedAcceptSchedule); + }); + } + }); + }); + + describe('accepts transfer admin', function () { + beforeEach(async function () { + await this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin); + this.acceptSchedule = (await time.clock.timestamp()) + this.delay; + }); + + it('should revert if caller is not pending default admin', async function () { + await time.increaseTo.timestamp(this.acceptSchedule + 1n, false); + await expect(this.mock.connect(this.other).acceptDefaultAdminTransfer()) + .to.be.revertedWithCustomError(this.mock, 'AccessControlInvalidDefaultAdmin') + .withArgs(this.other); + }); + + describe('when caller is pending default admin and delay has passed', function () { + beforeEach(async function () { + await time.increaseTo.timestamp(this.acceptSchedule + 1n, false); + }); + + it('accepts a transfer and changes default admin', async function () { + // Emit events + await expect(this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer()) + .to.emit(this.mock, 'RoleRevoked') + .withArgs(DEFAULT_ADMIN_ROLE, this.defaultAdmin, this.newDefaultAdmin) + .to.emit(this.mock, 'RoleGranted') + .withArgs(DEFAULT_ADMIN_ROLE, this.newDefaultAdmin, this.newDefaultAdmin); + + // Storage changes + expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)).to.be.false; + expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, this.newDefaultAdmin)).to.be.true; + expect(await this.mock.owner()).to.equal(this.newDefaultAdmin); + + // Resets pending default admin and schedule + const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); + expect(newAdmin).to.equal(ethers.ZeroAddress); + expect(schedule).to.equal(0); + }); + }); + + describe('schedule not passed', function () { + for (const [fromSchedule, tag] of [ + [-1n, 'less'], + [0n, 'equal'], + ]) { + it(`should revert if block.timestamp is ${tag} to schedule`, async function () { + await time.increaseTo.timestamp(this.acceptSchedule + fromSchedule, false); + await expect(this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer()) + .to.be.revertedWithCustomError(this.mock, 'AccessControlEnforcedDefaultAdminDelay') + .withArgs(this.acceptSchedule); + }); + } + }); + }); + + describe('cancels a default admin transfer', function () { + it('reverts if called by non default admin accounts', async function () { + await expect(this.mock.connect(this.other).cancelDefaultAdminTransfer()) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.other, DEFAULT_ADMIN_ROLE); + }); + + describe('when there is a pending default admin transfer', function () { + beforeEach(async function () { + await this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin); + this.acceptSchedule = (await time.clock.timestamp()) + this.delay; + }); + + for (const [fromSchedule, tag] of [ + [-1n, 'before'], + [0n, 'exactly when'], + [1n, 'after'], + ]) { + it(`resets pending default admin and schedule ${tag} transfer schedule passes`, async function () { + // Advance until passed delay + await time.increaseTo.timestamp(this.acceptSchedule + fromSchedule, false); + + await expect(this.mock.connect(this.defaultAdmin).cancelDefaultAdminTransfer()).to.emit( + this.mock, + 'DefaultAdminTransferCanceled', + ); + + const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); + expect(newAdmin).to.equal(ethers.ZeroAddress); + expect(schedule).to.equal(0); + }); + } + + it('should revert if the previous default admin tries to accept', async function () { + await this.mock.connect(this.defaultAdmin).cancelDefaultAdminTransfer(); + + // Advance until passed delay + await time.increaseTo.timestamp(this.acceptSchedule + 1n, false); + + // Previous pending default admin should not be able to accept after cancellation. + await expect(this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer()) + .to.be.revertedWithCustomError(this.mock, 'AccessControlInvalidDefaultAdmin') + .withArgs(this.newDefaultAdmin); + }); + }); + + describe('when there is no pending default admin transfer', function () { + it('should succeed without changes', async function () { + await expect(this.mock.connect(this.defaultAdmin).cancelDefaultAdminTransfer()).to.not.emit( + this.mock, + 'DefaultAdminTransferCanceled', + ); + + const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); + expect(newAdmin).to.equal(ethers.ZeroAddress); + expect(schedule).to.equal(0); + }); + }); + }); + + describe('renounces admin', function () { + beforeEach(async function () { + await this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(ethers.ZeroAddress); + this.expectedSchedule = (await time.clock.timestamp()) + this.delay; + }); + + it('reverts if caller is not default admin', async function () { + await time.increaseBy.timestamp(this.delay + 1n, false); + await expect( + this.mock.connect(this.defaultAdmin).renounceRole(DEFAULT_ADMIN_ROLE, this.other), + ).to.be.revertedWithCustomError(this.mock, 'AccessControlBadConfirmation'); + }); + + it("renouncing the admin role when not an admin doesn't affect the schedule", async function () { + await time.increaseBy.timestamp(this.delay + 1n, false); + await this.mock.connect(this.other).renounceRole(DEFAULT_ADMIN_ROLE, this.other); + + const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); + expect(newAdmin).to.equal(ethers.ZeroAddress); + expect(schedule).to.equal(this.expectedSchedule); + }); + + it('keeps defaultAdmin consistent with hasRole if another non-defaultAdmin user renounces the DEFAULT_ADMIN_ROLE', async function () { + await time.increaseBy.timestamp(this.delay + 1n, false); + + // This passes because it's a noop + await this.mock.connect(this.other).renounceRole(DEFAULT_ADMIN_ROLE, this.other); + + expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)).to.be.true; + expect(await this.mock.defaultAdmin()).to.equal(this.defaultAdmin); + }); + + it('renounces role', async function () { + await time.increaseBy.timestamp(this.delay + 1n, false); + await expect(this.mock.connect(this.defaultAdmin).renounceRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)) + .to.emit(this.mock, 'RoleRevoked') + .withArgs(DEFAULT_ADMIN_ROLE, this.defaultAdmin, this.defaultAdmin); + + expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)).to.be.false; + expect(await this.mock.defaultAdmin()).to.equal(ethers.ZeroAddress); + expect(await this.mock.owner()).to.equal(ethers.ZeroAddress); + + const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); + expect(newAdmin).to.equal(ethers.ZeroAddress); + expect(schedule).to.equal(0); + }); + + it('allows to recover access using the internal _grantRole', async function () { + await time.increaseBy.timestamp(this.delay + 1n, false); + await this.mock.connect(this.defaultAdmin).renounceRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin); + + await expect(this.mock.connect(this.defaultAdmin).$_grantRole(DEFAULT_ADMIN_ROLE, this.other)) + .to.emit(this.mock, 'RoleGranted') + .withArgs(DEFAULT_ADMIN_ROLE, this.other, this.defaultAdmin); + }); + + describe('schedule not passed', function () { + for (const [fromSchedule, tag] of [ + [-1n, 'less'], + [0n, 'equal'], + ]) { + it(`reverts if block.timestamp is ${tag} to schedule`, async function () { + await time.increaseBy.timestamp(this.delay + fromSchedule, false); + await expect(this.mock.connect(this.defaultAdmin).renounceRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)) + .to.be.revertedWithCustomError(this.mock, 'AccessControlEnforcedDefaultAdminDelay') + .withArgs(this.expectedSchedule); + }); + } + }); + }); + + describe('changes delay', function () { + it('reverts if called by non default admin accounts', async function () { + await expect(this.mock.connect(this.other).changeDefaultAdminDelay(time.duration.hours(4))) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.other, DEFAULT_ADMIN_ROLE); + }); + + for (const [delayDifference, delayChangeType] of [ + [time.duration.hours(-1), 'decreased'], + [time.duration.hours(1), 'increased'], + [time.duration.days(5), 'increased to more than 5 days'], + ]) { + describe(`when the delay is ${delayChangeType}`, function () { + beforeEach(function () { + this.newDefaultAdminDelay = this.delay + delayDifference; + }); + + it('begins the delay change to the new delay', async function () { + // Calculate expected values + const capWait = await this.mock.defaultAdminDelayIncreaseWait(); + const minWait = capWait < this.newDefaultAdminDelay ? capWait : this.newDefaultAdminDelay; + const changeDelay = + this.newDefaultAdminDelay <= this.delay ? this.delay - this.newDefaultAdminDelay : minWait; + const nextBlockTimestamp = (await time.clock.timestamp()) + 1n; + const effectSchedule = nextBlockTimestamp + changeDelay; + + await time.increaseTo.timestamp(nextBlockTimestamp, false); + + // Begins the change + await expect(this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(this.newDefaultAdminDelay)) + .to.emit(this.mock, 'DefaultAdminDelayChangeScheduled') + .withArgs(this.newDefaultAdminDelay, effectSchedule); + + // Assert + const { newDelay, schedule } = await this.mock.pendingDefaultAdminDelay(); + expect(newDelay).to.equal(this.newDefaultAdminDelay); + expect(schedule).to.equal(effectSchedule); + }); + + describe('scheduling again', function () { + beforeEach('schedule once', async function () { + await this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(this.newDefaultAdminDelay); + }); + + for (const [fromSchedule, tag] of [ + [-1n, 'before'], + [0n, 'exactly when'], + [1n, 'after'], + ]) { + const passed = fromSchedule > 0; + + it(`succeeds ${tag} the delay schedule passes`, async function () { + // Wait until schedule + fromSchedule + const { schedule: firstSchedule } = await this.mock.pendingDefaultAdminDelay(); + const nextBlockTimestamp = firstSchedule + fromSchedule; + await time.increaseTo.timestamp(nextBlockTimestamp, false); + + // Calculate expected values + const anotherNewDefaultAdminDelay = this.newDefaultAdminDelay + time.duration.hours(2); + const capWait = await this.mock.defaultAdminDelayIncreaseWait(); + const minWait = capWait < anotherNewDefaultAdminDelay ? capWait : anotherNewDefaultAdminDelay; + const effectSchedule = nextBlockTimestamp + minWait; + + // Default admin changes its mind and begins another delay change + await expect(this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(anotherNewDefaultAdminDelay)) + .to.emit(this.mock, 'DefaultAdminDelayChangeScheduled') + .withArgs(anotherNewDefaultAdminDelay, effectSchedule); + + // Assert + const { newDelay, schedule } = await this.mock.pendingDefaultAdminDelay(); + expect(newDelay).to.equal(anotherNewDefaultAdminDelay); + expect(schedule).to.equal(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.mock.pendingDefaultAdminDelay(); + await time.increaseTo.timestamp(firstSchedule + fromSchedule, false); + + // Default admin changes its mind and begins another delay change + const anotherNewDefaultAdminDelay = this.newDefaultAdminDelay + time.duration.hours(2); + + const expected = expect( + this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(anotherNewDefaultAdminDelay), + ); + if (passed) { + await expected.to.not.emit(this.mock, 'DefaultAdminDelayChangeCanceled'); + } else { + await expected.to.emit(this.mock, 'DefaultAdminDelayChangeCanceled'); + } + }); + } + }); + }); + } + }); + + describe('rollbacks a delay change', function () { + it('reverts if called by non default admin accounts', async function () { + await expect(this.mock.connect(this.other).rollbackDefaultAdminDelay()) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.other, DEFAULT_ADMIN_ROLE); + }); + + describe('when there is a pending delay', function () { + beforeEach('set pending delay', async function () { + await this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(time.duration.hours(12)); + }); + + for (const [fromSchedule, tag] of [ + [-1n, 'before'], + [0n, 'exactly when'], + [1n, '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.mock.pendingDefaultAdminDelay(); + await time.increaseTo.timestamp(firstSchedule + fromSchedule, false); + + await this.mock.connect(this.defaultAdmin).rollbackDefaultAdminDelay(); + + const { newDelay, schedule } = await this.mock.pendingDefaultAdminDelay(); + expect(newDelay).to.equal(0); + expect(schedule).to.equal(0); + }); + + 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.mock.pendingDefaultAdminDelay(); + await time.increaseTo.timestamp(firstSchedule + fromSchedule, false); + + const expected = expect(this.mock.connect(this.defaultAdmin).rollbackDefaultAdminDelay()); + if (passed) { + await expected.to.not.emit(this.mock, 'DefaultAdminDelayChangeCanceled'); + } else { + await expected.to.emit(this.mock, 'DefaultAdminDelayChangeCanceled'); + } + }); + } + }); + + describe('when there is no pending delay', function () { + it('succeeds without changes', async function () { + await this.mock.connect(this.defaultAdmin).rollbackDefaultAdminDelay(); + + const { newDelay, schedule } = await this.mock.pendingDefaultAdminDelay(); + expect(newDelay).to.equal(0); + expect(schedule).to.equal(0); + }); + }); + }); +} + +module.exports = { + DEFAULT_ADMIN_ROLE, + shouldBehaveLikeAccessControl, + shouldBehaveLikeAccessControlEnumerable, + shouldBehaveLikeAccessControlDefaultAdminRules, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.test.js new file mode 100644 index 0000000..5c70cdc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.test.js @@ -0,0 +1,19 @@ +const { ethers } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl } = require('./AccessControl.behavior'); + +async function fixture() { + const [defaultAdmin, ...accounts] = await ethers.getSigners(); + const mock = await ethers.deployContract('$AccessControl'); + await mock.$_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + return { mock, defaultAdmin, accounts }; +} + +describe('AccessControl', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeAccessControl(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable.test.js new file mode 100644 index 0000000..2d9b561 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable.test.js @@ -0,0 +1,79 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +async function fixture() { + const [owner, other] = await ethers.getSigners(); + const ownable = await ethers.deployContract('$Ownable', [owner]); + return { owner, other, ownable }; +} + +describe('Ownable', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('emits ownership transfer events during construction', async function () { + await expect(this.ownable.deploymentTransaction()) + .to.emit(this.ownable, 'OwnershipTransferred') + .withArgs(ethers.ZeroAddress, this.owner); + }); + + it('rejects zero address for initialOwner', async function () { + await expect(ethers.deployContract('$Ownable', [ethers.ZeroAddress])) + .to.be.revertedWithCustomError({ interface: this.ownable.interface }, 'OwnableInvalidOwner') + .withArgs(ethers.ZeroAddress); + }); + + it('has an owner', async function () { + expect(await this.ownable.owner()).to.equal(this.owner); + }); + + describe('transfer ownership', function () { + it('changes owner after transfer', async function () { + await expect(this.ownable.connect(this.owner).transferOwnership(this.other)) + .to.emit(this.ownable, 'OwnershipTransferred') + .withArgs(this.owner, this.other); + + expect(await this.ownable.owner()).to.equal(this.other); + }); + + it('prevents non-owners from transferring', async function () { + await expect(this.ownable.connect(this.other).transferOwnership(this.other)) + .to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount') + .withArgs(this.other); + }); + + it('guards ownership against stuck state', async function () { + await expect(this.ownable.connect(this.owner).transferOwnership(ethers.ZeroAddress)) + .to.be.revertedWithCustomError(this.ownable, 'OwnableInvalidOwner') + .withArgs(ethers.ZeroAddress); + }); + }); + + describe('renounce ownership', function () { + it('loses ownership after renouncement', async function () { + await expect(this.ownable.connect(this.owner).renounceOwnership()) + .to.emit(this.ownable, 'OwnershipTransferred') + .withArgs(this.owner, ethers.ZeroAddress); + + expect(await this.ownable.owner()).to.equal(ethers.ZeroAddress); + }); + + it('prevents non-owners from renouncement', async function () { + await expect(this.ownable.connect(this.other).renounceOwnership()) + .to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount') + .withArgs(this.other); + }); + + it('allows to recover access using the internal _transferOwnership', async function () { + await this.ownable.connect(this.owner).renounceOwnership(); + + await expect(this.ownable.$_transferOwnership(this.other)) + .to.emit(this.ownable, 'OwnershipTransferred') + .withArgs(ethers.ZeroAddress, this.other); + + expect(await this.ownable.owner()).to.equal(this.other); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js new file mode 100644 index 0000000..5620a24 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js @@ -0,0 +1,102 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +async function fixture() { + const [owner, accountA, accountB] = await ethers.getSigners(); + const ownable2Step = await ethers.deployContract('$Ownable2Step', [owner]); + return { + ownable2Step, + owner, + accountA, + accountB, + }; +} + +describe('Ownable2Step', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('transfer ownership', function () { + it('starting a transfer does not change owner', async function () { + await expect(this.ownable2Step.connect(this.owner).transferOwnership(this.accountA)) + .to.emit(this.ownable2Step, 'OwnershipTransferStarted') + .withArgs(this.owner, this.accountA); + + expect(await this.ownable2Step.owner()).to.equal(this.owner); + expect(await this.ownable2Step.pendingOwner()).to.equal(this.accountA); + }); + + it('changes owner after transfer', async function () { + await this.ownable2Step.connect(this.owner).transferOwnership(this.accountA); + + await expect(this.ownable2Step.connect(this.accountA).acceptOwnership()) + .to.emit(this.ownable2Step, 'OwnershipTransferred') + .withArgs(this.owner, this.accountA); + + expect(await this.ownable2Step.owner()).to.equal(this.accountA); + expect(await this.ownable2Step.pendingOwner()).to.equal(ethers.ZeroAddress); + }); + + it('guards transfer against invalid user', async function () { + await this.ownable2Step.connect(this.owner).transferOwnership(this.accountA); + + await expect(this.ownable2Step.connect(this.accountB).acceptOwnership()) + .to.be.revertedWithCustomError(this.ownable2Step, 'OwnableUnauthorizedAccount') + .withArgs(this.accountB); + }); + }); + + describe('renouncing ownership', function () { + it('changes owner after renouncing ownership', async function () { + await expect(this.ownable2Step.connect(this.owner).renounceOwnership()) + .to.emit(this.ownable2Step, 'OwnershipTransferred') + .withArgs(this.owner, ethers.ZeroAddress); + + // 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(ethers.ZeroAddress); + }); + + it('pending owner resets after renouncing ownership', async function () { + await this.ownable2Step.connect(this.owner).transferOwnership(this.accountA); + expect(await this.ownable2Step.pendingOwner()).to.equal(this.accountA); + + await this.ownable2Step.connect(this.owner).renounceOwnership(); + expect(await this.ownable2Step.pendingOwner()).to.equal(ethers.ZeroAddress); + + await expect(this.ownable2Step.connect(this.accountA).acceptOwnership()) + .to.be.revertedWithCustomError(this.ownable2Step, 'OwnableUnauthorizedAccount') + .withArgs(this.accountA); + }); + + it('allows to recover access using the internal _transferOwnership', async function () { + await this.ownable2Step.connect(this.owner).renounceOwnership(); + + await expect(this.ownable2Step.$_transferOwnership(this.accountA)) + .to.emit(this.ownable2Step, 'OwnershipTransferred') + .withArgs(ethers.ZeroAddress, this.accountA); + + expect(await this.ownable2Step.owner()).to.equal(this.accountA); + }); + + it('allows the owner to cancel an initiated ownership transfer by setting newOwner to zero address', async function () { + // initiate ownership transfer to accountA + await this.ownable2Step.connect(this.owner).transferOwnership(this.accountA); + expect(await this.ownable2Step.pendingOwner()).to.equal(this.accountA); + + // cancel the ownership transfer by setting newOwner to zero address + await expect(this.ownable2Step.connect(this.owner).transferOwnership(ethers.ZeroAddress)) + .to.emit(this.ownable2Step, 'OwnershipTransferStarted') + .withArgs(this.owner, ethers.ZeroAddress); + expect(await this.ownable2Step.pendingOwner()).to.equal(ethers.ZeroAddress); + + // verify that accountA cannot accept ownership anymore + await expect(this.ownable2Step.connect(this.accountA).acceptOwnership()) + .to.be.revertedWithCustomError(this.ownable2Step, 'OwnableUnauthorizedAccount') + .withArgs(this.accountA); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlDefaultAdminRules.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlDefaultAdminRules.test.js new file mode 100644 index 0000000..48036fd --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlDefaultAdminRules.test.js @@ -0,0 +1,32 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const time = require('../../helpers/time'); + +const { + shouldBehaveLikeAccessControl, + shouldBehaveLikeAccessControlDefaultAdminRules, +} = require('../AccessControl.behavior'); + +async function fixture() { + const delay = time.duration.hours(10); + const [defaultAdmin, ...accounts] = await ethers.getSigners(); + const mock = await ethers.deployContract('$AccessControlDefaultAdminRules', [delay, defaultAdmin]); + return { mock, defaultAdmin, delay, accounts }; +} + +describe('AccessControlDefaultAdminRules', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('initial admin not zero', async function () { + await expect(ethers.deployContract('$AccessControlDefaultAdminRules', [this.delay, ethers.ZeroAddress])) + .to.be.revertedWithCustomError(this.mock, 'AccessControlInvalidDefaultAdmin') + .withArgs(ethers.ZeroAddress); + }); + + shouldBehaveLikeAccessControl(); + shouldBehaveLikeAccessControlDefaultAdminRules(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlEnumerable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlEnumerable.test.js new file mode 100644 index 0000000..ea1a8c4 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlEnumerable.test.js @@ -0,0 +1,24 @@ +const { ethers } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { + DEFAULT_ADMIN_ROLE, + shouldBehaveLikeAccessControl, + shouldBehaveLikeAccessControlEnumerable, +} = require('../AccessControl.behavior'); + +async function fixture() { + const [defaultAdmin, ...accounts] = await ethers.getSigners(); + const mock = await ethers.deployContract('$AccessControlEnumerable'); + await mock.$_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + return { mock, defaultAdmin, accounts }; +} + +describe('AccessControlEnumerable', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeAccessControl(); + shouldBehaveLikeAccessControlEnumerable(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManaged.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManaged.test.js new file mode 100644 index 0000000..d666b5e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManaged.test.js @@ -0,0 +1,146 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { impersonate } = require('../../helpers/account'); +const time = require('../../helpers/time'); + +async function fixture() { + const [admin, roleMember, other] = await ethers.getSigners(); + + const authority = await ethers.deployContract('$AccessManager', [admin]); + const managed = await ethers.deployContract('$AccessManagedTarget', [authority]); + + const anotherAuthority = await ethers.deployContract('$AccessManager', [admin]); + const authorityObserveIsConsuming = await ethers.deployContract('$AuthorityObserveIsConsuming'); + + await impersonate(authority.target); + const authorityAsSigner = await ethers.getSigner(authority.target); + + return { + roleMember, + other, + authorityAsSigner, + authority, + managed, + authorityObserveIsConsuming, + anotherAuthority, + }; +} + +describe('AccessManaged', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('sets authority and emits AuthorityUpdated event during construction', async function () { + await expect(this.managed.deploymentTransaction()) + .to.emit(this.managed, 'AuthorityUpdated') + .withArgs(this.authority); + }); + + describe('restricted modifier', function () { + beforeEach(async function () { + this.selector = this.managed.fnRestricted.getFragment().selector; + this.role = 42n; + await this.authority.$_setTargetFunctionRole(this.managed, this.selector, this.role); + await this.authority.$_grantRole(this.role, this.roleMember, 0, 0); + }); + + it('succeeds when role is granted without execution delay', async function () { + await this.managed.connect(this.roleMember)[this.selector](); + }); + + it('reverts when role is not granted', async function () { + await expect(this.managed.connect(this.other)[this.selector]()) + .to.be.revertedWithCustomError(this.managed, 'AccessManagedUnauthorized') + .withArgs(this.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 expect(this.managed.$_checkCanCall(this.roleMember, '0x1234')).to.be.reverted; + }); + + describe('when role is granted with execution delay', function () { + beforeEach(async function () { + const executionDelay = 911n; + await this.authority.$_grantRole(this.role, this.roleMember, 0, executionDelay); + }); + + it('reverts if the operation is not scheduled', async function () { + const fn = this.managed.interface.getFunction(this.selector); + const calldata = this.managed.interface.encodeFunctionData(fn, []); + const opId = await this.authority.hashOperation(this.roleMember, this.managed, calldata); + + await expect(this.managed.connect(this.roleMember)[this.selector]()) + .to.be.revertedWithCustomError(this.authority, 'AccessManagerNotScheduled') + .withArgs(opId); + }); + + it('succeeds if the operation is scheduled', async function () { + // Arguments + const delay = time.duration.hours(12); + const fn = this.managed.interface.getFunction(this.selector); + const calldata = this.managed.interface.encodeFunctionData(fn, []); + + // Schedule + const scheduledAt = (await time.clock.timestamp()) + 1n; + const when = scheduledAt + delay; + await time.increaseTo.timestamp(scheduledAt, false); + await this.authority.connect(this.roleMember).schedule(this.managed, calldata, when); + + // Set execution date + await time.increaseTo.timestamp(when, false); + + // Shouldn't revert + await this.managed.connect(this.roleMember)[this.selector](); + }); + }); + }); + + describe('setAuthority', function () { + it('reverts if the caller is not the authority', async function () { + await expect(this.managed.connect(this.other).setAuthority(this.other)) + .to.be.revertedWithCustomError(this.managed, 'AccessManagedUnauthorized') + .withArgs(this.other); + }); + + it('reverts if the new authority is not a valid authority', async function () { + await expect(this.managed.connect(this.authorityAsSigner).setAuthority(this.other)) + .to.be.revertedWithCustomError(this.managed, 'AccessManagedInvalidAuthority') + .withArgs(this.other); + }); + + it('sets authority and emits AuthorityUpdated event', async function () { + await expect(this.managed.connect(this.authorityAsSigner).setAuthority(this.anotherAuthority)) + .to.emit(this.managed, 'AuthorityUpdated') + .withArgs(this.anotherAuthority); + + expect(await this.managed.authority()).to.equal(this.anotherAuthority); + }); + }); + + describe('isConsumingScheduledOp', function () { + beforeEach(async function () { + await this.managed.connect(this.authorityAsSigner).setAuthority(this.authorityObserveIsConsuming); + }); + + it('returns bytes4(0) when not consuming operation', async function () { + expect(await this.managed.isConsumingScheduledOp()).to.equal('0x00000000'); + }); + + it('returns isConsumingScheduledOp selector when consuming operation', async function () { + const isConsumingScheduledOp = this.managed.interface.getFunction('isConsumingScheduledOp()'); + const fnRestricted = this.managed.fnRestricted.getFragment(); + await expect(this.managed.connect(this.other).fnRestricted()) + .to.emit(this.authorityObserveIsConsuming, 'ConsumeScheduledOpCalled') + .withArgs( + this.other, + this.managed.interface.encodeFunctionData(fnRestricted, []), + isConsumingScheduledOp.selector, + ); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.behavior.js new file mode 100644 index 0000000..385da57 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.behavior.js @@ -0,0 +1,257 @@ +const { expect } = require('chai'); + +const { + LIKE_COMMON_IS_EXECUTING, + LIKE_COMMON_GET_ACCESS, + LIKE_COMMON_SCHEDULABLE, + testAsSchedulableOperation, + testAsRestrictedOperation, + testAsDelayedOperation, + testAsCanCall, + testAsHasRole, +} = require('./AccessManager.predicate'); + +// ============ ADMIN OPERATION ============ + +/** + * @requires this.{manager,roles,calldata,role} + */ +function shouldBehaveLikeDelayedAdminOperation() { + const getAccessPath = LIKE_COMMON_GET_ACCESS; + testAsDelayedOperation.mineDelay = true; + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = + testAsDelayedOperation; + getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = function () { + beforeEach('set execution delay', async function () { + this.scheduleIn = this.executionDelay; // For testAsDelayedOperation + }); + testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); + }; + + beforeEach('set target as manager', function () { + this.target = this.manager; + }); + + testAsRestrictedOperation({ + callerIsTheManager: LIKE_COMMON_IS_EXECUTING, + callerIsNotTheManager() { + testAsHasRole({ + publicRoleIsRequired() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) + .to.be.revertedWithCustomError(this.target, 'AccessManagerUnauthorizedAccount') + .withArgs( + 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 = LIKE_COMMON_GET_ACCESS; + + function testScheduleOperation(mineDelay) { + return function self() { + self.mineDelay = mineDelay; + beforeEach('set execution delay', async function () { + this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation + }); + testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); + }; + } + + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = + testScheduleOperation(true); + getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = testScheduleOperation(false); + + beforeEach('set target as manager', function () { + this.target = this.manager; + }); + + testAsRestrictedOperation({ + callerIsTheManager: LIKE_COMMON_IS_EXECUTING, + callerIsNotTheManager() { + testAsHasRole({ + publicRoleIsRequired() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) + .to.be.revertedWithCustomError(this.target, 'AccessManagerUnauthorizedAccount') + .withArgs( + 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 = LIKE_COMMON_GET_ACCESS; + + function afterGrantDelay() { + afterGrantDelay.mineDelay = true; + beforeEach('set execution delay', async function () { + this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation + }); + testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); + } + + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = afterGrantDelay; + getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = afterGrantDelay; + + beforeEach('set target as manager', function () { + this.target = this.manager; + }); + + testAsRestrictedOperation({ + callerIsTheManager: LIKE_COMMON_IS_EXECUTING, + callerIsNotTheManager() { + testAsHasRole({ + publicRoleIsRequired() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) + .to.be.revertedWithCustomError(this.target, 'AccessManagerUnauthorizedAccount') + .withArgs(this.caller, roleAdmin); + }); + }, + specificRoleIsRequired: getAccessPath, + }); + }, + }); +} + +// ============ RESTRICTED OPERATION ============ + +/** + * @requires this.{manager,roles,calldata,role} + */ +function shouldBehaveLikeAManagedRestrictedOperation() { + function revertUnauthorized() { + it('reverts as AccessManagedUnauthorized', async function () { + await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) + .to.be.revertedWithCustomError(this.target, 'AccessManagedUnauthorized') + .withArgs(this.caller); + }); + } + + const getAccessPath = LIKE_COMMON_GET_ACCESS; + + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.beforeGrantDelay = + revertUnauthorized; + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasNoExecutionDelay.beforeGrantDelay = + revertUnauthorized; + getAccessPath.requiredRoleIsNotGranted = revertUnauthorized; + + function testScheduleOperation(mineDelay) { + return function self() { + self.mineDelay = mineDelay; + beforeEach('sets execution delay', async function () { + this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation + }); + testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); + }; + } + + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = + testScheduleOperation(true); + getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = testScheduleOperation(false); + + const isExecutingPath = LIKE_COMMON_IS_EXECUTING; + isExecutingPath.notExecuting = revertUnauthorized; + + testAsCanCall({ + closed: revertUnauthorized, + open: { + callerIsTheManager: isExecutingPath, + callerIsNotTheManager: { + publicRoleIsRequired() { + it('succeeds called directly', async function () { + await this.caller.sendTransaction({ to: this.target, data: this.calldata }); + }); + + it('succeeds via execute', async function () { + await this.manager.connect(this.caller).execute(this.target, this.calldata); + }); + }, + specificRoleIsRequired: getAccessPath, + }, + }, + }); +} + +/** + * @requires this.{target,manager,roles,calldata,role} + */ +function shouldBehaveLikeASelfRestrictedOperation() { + function revertUnauthorized() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedAccount') + .withArgs(this.caller, this.role?.id ?? 0n); + }); + } + + const getAccessPath = LIKE_COMMON_GET_ACCESS; + + function testScheduleOperation(mineDelay) { + return function self() { + self.mineDelay = mineDelay; + beforeEach('sets execution delay', async function () { + this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation + }); + testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); + }; + } + + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = + testScheduleOperation(true); + getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = testScheduleOperation(false); + + beforeEach('set target as manager', function () { + this.target = this.manager; + }); + + const isExecutingPath = LIKE_COMMON_IS_EXECUTING; + isExecutingPath.notExecuting = revertUnauthorized; + + testAsCanCall({ + closed: revertUnauthorized, + open: { + callerIsTheManager: isExecutingPath, + callerIsNotTheManager: { + publicRoleIsRequired() { + it('succeeds called directly', async function () { + await this.caller.sendTransaction({ to: this.target, data: this.calldata }); + }); + + it('succeeds via execute', async function () { + await this.manager.connect(this.caller).execute(this.target, this.calldata); + }); + }, + specificRoleIsRequired: getAccessPath, + }, + }, + }); +} + +module.exports = { + shouldBehaveLikeDelayedAdminOperation, + shouldBehaveLikeNotDelayedAdminOperation, + shouldBehaveLikeRoleAdminOperation, + shouldBehaveLikeAManagedRestrictedOperation, + shouldBehaveLikeASelfRestrictedOperation, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.predicate.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.predicate.js new file mode 100644 index 0000000..8b4c5f4 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.predicate.js @@ -0,0 +1,456 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { setStorageAt } = require('@nomicfoundation/hardhat-network-helpers'); + +const { EXECUTION_ID_STORAGE_SLOT, EXPIRATION, prepareOperation } = require('../../helpers/access-manager'); +const { impersonate } = require('../../helpers/account'); +const time = require('../../helpers/time'); + +// ============ COMMON PREDICATES ============ + +const LIKE_COMMON_IS_EXECUTING = { + executing() { + it('succeeds', async function () { + await this.caller.sendTransaction({ to: this.target, data: this.calldata }); + }); + }, + notExecuting() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedAccount') + .withArgs(this.caller, this.role.id); + }); + }, +}; + +const LIKE_COMMON_GET_ACCESS = { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedAccount') + .withArgs(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 expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedAccount') + .withArgs(this.caller, this.role.id); + }); + }, + afterGrantDelay() { + it('succeeds called directly', async function () { + await this.caller.sendTransaction({ to: this.target, data: this.calldata }); + }); + + it('succeeds via execute', async function () { + await this.manager.connect(this.caller).execute(this.target, this.calldata); + }); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay: undefined, // Diverges if there's an operation to schedule or not + callerHasNoExecutionDelay() { + it('succeeds called directly', async function () { + await this.caller.sendTransaction({ to: this.target, data: this.calldata }); + }); + + it('succeeds via execute', async function () { + await this.manager.connect(this.caller).execute(this.target, this.calldata); + }); + }, + }, + }, + requiredRoleIsNotGranted() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedAccount') + .withArgs(this.caller, this.role.id); + }); + }, +}; + +const LIKE_COMMON_SCHEDULABLE = { + scheduled: { + before() { + it('reverts as AccessManagerNotReady', async function () { + await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerNotReady') + .withArgs(this.operationId); + }); + }, + after() { + it('succeeds called directly', async function () { + await this.caller.sendTransaction({ to: this.target, data: this.calldata }); + }); + + it('succeeds via execute', async function () { + await this.manager.connect(this.caller).execute(this.target, this.calldata); + }); + }, + expired() { + it('reverts as AccessManagerExpired', async function () { + await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerExpired') + .withArgs(this.operationId); + }); + }, + }, + notScheduled() { + it('reverts as AccessManagerNotScheduled', async function () { + await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerNotScheduled') + .withArgs(this.operationId); + }); + }, +}; + +// ============ MODE ============ + +/** + * @requires this.{manager,target} + */ +function testAsClosable({ closed, open }) { + describe('when the manager is closed', function () { + beforeEach('close', async function () { + await this.manager.$_setTargetClosed(this.target, true); + }); + + closed(); + }); + + describe('when the manager is open', function () { + beforeEach('open', async function () { + await this.manager.$_setTargetClosed(this.target, false); + }); + + open(); + }); +} + +// ============ DELAY ============ + +/** + * @requires this.{delay} + */ +function testAsDelay(type, { before, after }) { + beforeEach('define timestamp when delay takes effect', async function () { + const timestamp = await time.clock.timestamp(); + this.delayEffect = timestamp + this.delay; + }); + + describe(`when ${type} delay has not taken effect yet`, function () { + beforeEach(`set next block timestamp before ${type} takes effect`, async function () { + await time.increaseTo.timestamp(this.delayEffect - 1n, !!before.mineDelay); + }); + + before(); + }); + + describe(`when ${type} delay has taken effect`, function () { + beforeEach(`set next block timestamp when ${type} takes effect`, async function () { + await time.increaseTo.timestamp(this.delayEffect, !!after.mineDelay); + }); + + after(); + }); +} + +// ============ OPERATION ============ + +/** + * @requires this.{manager,scheduleIn,caller,target,calldata} + */ +function testAsSchedulableOperation({ scheduled: { before, after, expired }, notScheduled }) { + describe('when operation is scheduled', function () { + beforeEach('schedule operation', async function () { + if (this.caller.target) { + await impersonate(this.caller.target); + this.caller = await ethers.getSigner(this.caller.target); + } + const { operationId, schedule } = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay: this.scheduleIn, + }); + await schedule(); + 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.clock.timestamp(); + const schedule = await this.manager.getSchedule(this.operationId); + await time.increaseTo.timestamp(schedule - 1n, !!before.mineDelay); + }); + + 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.clock.timestamp(); + const schedule = await this.manager.getSchedule(this.operationId); + await time.increaseTo.timestamp(schedule, !!after.mineDelay); + }); + + after(); + }); + + describe('when operation has expired', function () { + beforeEach('set next block time when operation expired', async function () { + this.scheduledAt = await time.clock.timestamp(); + const schedule = await this.manager.getSchedule(this.operationId); + await time.increaseTo.timestamp(schedule + EXPIRATION, !!expired.mineDelay); + }); + + expired(); + }); + }); + + describe('when operation is not scheduled', function () { + beforeEach('set expected operationId', async function () { + this.operationId = await this.manager.hashOperation(this.caller, this.target, this.calldata); + + // Assert operation is not scheduled + expect(await this.manager.getSchedule(this.operationId)).to.equal(0n); + }); + + notScheduled(); + }); +} + +/** + * @requires this.{manager,roles,target,calldata} + */ +function testAsRestrictedOperation({ callerIsTheManager: { executing, notExecuting }, callerIsNotTheManager }) { + describe('when the call comes from the manager (msg.sender == manager)', function () { + beforeEach('define caller as manager', async function () { + this.caller = this.manager; + if (this.caller.target) { + await impersonate(this.caller.target); + this.caller = await ethers.getSigner(this.caller.target); + } + }); + + describe('when _executionId is in storage for target and selector', function () { + beforeEach('set _executionId flag from calldata and target', async function () { + const executionId = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ['address', 'bytes4'], + [this.target.target, this.calldata.substring(0, 10)], + ), + ); + await setStorageAt(this.manager.target, EXECUTION_ID_STORAGE_SLOT, executionId); + }); + + executing(); + }); + + describe('when _executionId does not match target and selector', notExecuting); + }); + + 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,scheduleIn,caller,target,calldata,executionDelay} + */ +function testAsDelayedOperation() { + 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 + time.duration.hours(1); + await this.manager.$_setTargetAdminDelay(this.target, this.operationDelay); + this.scheduleIn = this.operationDelay; // For testAsSchedulableOperation + }); + + testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); + }); + + describe('when operation delay is shorter than execution delay', function () { + beforeEach('set operation delay', async function () { + this.operationDelay = this.executionDelay - time.duration.hours(1); + await this.manager.$_setTargetAdminDelay(this.target, this.operationDelay); + this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation + }); + + testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); + }); + }); + + describe('without operation delay', function () { + beforeEach('set operation delay', async function () { + this.operationDelay = 0n; + await this.manager.$_setTargetAdminDelay(this.target, this.operationDelay); + this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation + }); + + testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); + }); +} + +// ============ METHOD ============ + +/** + * @requires this.{manager,roles,role,target,calldata} + */ +function testAsCanCall({ + closed, + open: { + callerIsTheManager, + callerIsNotTheManager: { publicRoleIsRequired, specificRoleIsRequired }, + }, +}) { + testAsClosable({ + closed, + open() { + testAsRestrictedOperation({ + callerIsTheManager, + callerIsNotTheManager() { + testAsHasRole({ + publicRoleIsRequired, + specificRoleIsRequired, + }); + }, + }); + }, + }); +} + +/** + * @requires this.{target,calldata,roles,role} + */ +function testAsHasRole({ 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 + .connect(this.roles.ADMIN.members[0]) + .$_setTargetFunctionRole(this.target, this.calldata.substring(0, 10), this.role.id); + }); + + 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 + .connect(this.roles.ADMIN.members[0]) + .$_setTargetFunctionRole(this.target, this.calldata.substring(0, 10), this.role.id); + }); + + testAsGetAccess(specificRoleIsRequired); + }); +} + +/** + * @requires this.{manager,role,caller} + */ +function testAsGetAccess({ + 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 testAsDelay 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 testAsDelay + }); + + 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); + }); + + testAsDelay('grant', { before: case1, after: case2 }); + }); + + describe('when caller has no execution delay', function () { + beforeEach('set role and delay', async function () { + this.executionDelay = 0n; + await this.manager.$_grantRole(this.role.id, this.caller, this.grantDelay, this.executionDelay); + }); + + testAsDelay('grant', { before: case3, after: case4 }); + }); + }); + + describe('when role granting is not delayed', function () { + beforeEach('define delay', function () { + this.grantDelay = 0n; + }); + + 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 = 0n; + 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.equal(0n); + }); + + requiredRoleIsNotGranted(); + }); +} + +module.exports = { + LIKE_COMMON_IS_EXECUTING, + LIKE_COMMON_GET_ACCESS, + LIKE_COMMON_SCHEDULABLE, + testAsClosable, + testAsDelay, + testAsSchedulableOperation, + testAsRestrictedOperation, + testAsDelayedOperation, + testAsCanCall, + testAsHasRole, + testAsGetAccess, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.test.js new file mode 100644 index 0000000..7726831 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.test.js @@ -0,0 +1,2489 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { impersonate } = require('../../helpers/account'); +const { MAX_UINT48 } = require('../../helpers/constants'); +const { selector } = require('../../helpers/methods'); +const time = require('../../helpers/time'); + +const { + buildBaseRoles, + formatAccess, + EXPIRATION, + MINSETBACK, + EXECUTION_ID_STORAGE_SLOT, + CONSUMING_SCHEDULE_STORAGE_SLOT, + prepareOperation, + hashOperation, +} = require('../../helpers/access-manager'); + +const { + shouldBehaveLikeDelayedAdminOperation, + shouldBehaveLikeNotDelayedAdminOperation, + shouldBehaveLikeRoleAdminOperation, + shouldBehaveLikeAManagedRestrictedOperation, + shouldBehaveLikeASelfRestrictedOperation, +} = require('./AccessManager.behavior'); + +const { + LIKE_COMMON_SCHEDULABLE, + testAsClosable, + testAsDelay, + testAsSchedulableOperation, + testAsCanCall, + testAsHasRole, + testAsGetAccess, +} = require('./AccessManager.predicate'); + +async function fixture() { + const [admin, roleAdmin, roleGuardian, member, user, other] = await ethers.getSigners(); + + // Build roles + const roles = buildBaseRoles(); + + // Add members + roles.ADMIN.members = [admin]; + roles.SOME_ADMIN.members = [roleAdmin]; + roles.SOME_GUARDIAN.members = [roleGuardian]; + roles.SOME.members = [member]; + roles.PUBLIC.members = [admin, roleAdmin, roleGuardian, member, user, other]; + + const manager = await ethers.deployContract('$AccessManagerMock', [admin]); + const target = await ethers.deployContract('$AccessManagedTarget', [manager]); + + for (const { id: roleId, admin, guardian, members } of Object.values(roles)) { + if (roleId === roles.PUBLIC.id) continue; // Every address belong to public and is locked + if (roleId === roles.ADMIN.id) continue; // Admin set during construction and is locked + + // Set admin role avoiding default + if (admin.id !== roles.ADMIN.id) { + await manager.$_setRoleAdmin(roleId, admin.id); + } + + // Set guardian role avoiding default + if (guardian.id !== roles.ADMIN.id) { + await manager.$_setRoleGuardian(roleId, guardian.id); + } + + // Grant role to members + for (const member of members) { + await manager.$_grantRole(roleId, member, 0, 0); + } + } + + return { + admin, + roleAdmin, + user, + other, + roles, + manager, + target, + }; +} + +// This test suite is made using the following tools: +// +// * Predicates: Functions with common conditional setups without assertions. +// * Behaviors: Functions with common assertions. +// +// The behavioral tests are built by composing predicates and are used as templates +// for testing access to restricted functions. +// +// Similarly, unit tests in this suite will use predicates to test subsets of these +// behaviors and are helped by common assertions provided for some of the predicates. +// +// The predicates can be identified by the `testAs*` prefix while the behaviors +// are prefixed with `shouldBehave*`. The common assertions for predicates are +// defined as constants. +describe('AccessManager', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('during construction', function () { + it('grants admin role to initialAdmin', async function () { + const manager = await ethers.deployContract('$AccessManager', [this.other]); + expect(await manager.hasRole(this.roles.ADMIN.id, this.other).then(formatAccess)).to.be.deep.equal([true, '0']); + }); + + it('rejects zero address for initialAdmin', async function () { + await expect(ethers.deployContract('$AccessManager', [ethers.ZeroAddress])) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerInvalidInitialAdmin') + .withArgs(ethers.ZeroAddress); + }); + + 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.equal(admin.id); + expect(await this.manager.getRoleGuardian(roleId)).to.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: 379204n }; + }); + + testAsCanCall({ + closed() { + it('should return false and no delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.other, + this.target, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.false; + expect(delay).to.equal(0n); + }); + }, + open: { + callerIsTheManager: { + executing() { + it('should return true and no delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.true; + expect(delay).to.equal(0n); + }); + }, + notExecuting() { + it('should return false and no delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.false; + expect(delay).to.equal(0n); + }); + }, + }, + callerIsNotTheManager: { + publicRoleIsRequired() { + it('should return true and no delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.true; + expect(delay).to.equal(0n); + }); + }, + specificRoleIsRequired: { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay: function self() { + self.mineDelay = true; + + it('should return false and no execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.false; + expect(delay).to.equal(0n); + }); + }, + afterGrantDelay: function self() { + self.mineDelay = true; + + beforeEach('sets execution delay', function () { + this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation + }); + + testAsSchedulableOperation({ + scheduled: { + before: function self() { + self.mineDelay = true; + + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.false; + expect(delay).to.equal(this.executionDelay); + }); + }, + after: function self() { + self.mineDelay = true; + + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.false; + expect(delay).to.equal(this.executionDelay); + }); + }, + expired: function self() { + self.mineDelay = true; + + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.false; + expect(delay).to.equal(this.executionDelay); + }); + }, + }, + notScheduled() { + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.false; + expect(delay).to.equal(this.executionDelay); + }); + }, + }); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay: function self() { + self.mineDelay = true; + + it('should return false and no execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.false; + expect(delay).to.equal(0n); + }); + }, + afterGrantDelay: function self() { + self.mineDelay = true; + + it('should return true and no execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.true; + expect(delay).to.equal(0n); + }); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay() { + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.false; + expect(delay).to.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, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.true; + expect(delay).to.equal(0n); + }); + }, + }, + }, + requiredRoleIsNotGranted() { + it('should return false and no execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.false; + expect(delay).to.equal(0n); + }); + }, + }, + }, + }, + }); + }); + + describe('#expiration', function () { + it('has a 7 days default expiration', async function () { + expect(await this.manager.expiration()).to.equal(EXPIRATION); + }); + }); + + describe('#minSetback', function () { + it('has a 5 days default minimum setback', async function () { + expect(await this.manager.minSetback()).to.equal(MINSETBACK); + }); + }); + + describe('#isTargetClosed', function () { + testAsClosable({ + closed() { + it('returns true', async function () { + expect(await this.manager.isTargetClosed(this.target)).to.be.true; + }); + }, + open() { + it('returns false', async function () { + expect(await this.manager.isTargetClosed(this.target)).to.be.false; + }); + }, + }); + }); + + describe('#getTargetFunctionRole', function () { + const methodSelector = selector('something(address,bytes)'); + + it('returns the target function role', async function () { + const roleId = 21498n; + await this.manager.$_setTargetFunctionRole(this.target, methodSelector, roleId); + + expect(await this.manager.getTargetFunctionRole(this.target, methodSelector)).to.equal(roleId); + }); + + it('returns the ADMIN role if not set', async function () { + expect(await this.manager.getTargetFunctionRole(this.target, methodSelector)).to.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); + this.newDelay = time.duration.days(10); + + await this.manager.$_setTargetAdminDelay(this.target, this.newDelay); + this.delay = MINSETBACK; // For testAsDelay + }); + + testAsDelay('effect', { + before: function self() { + self.mineDelay = true; + + it('returns the old target admin delay', async function () { + expect(await this.manager.getTargetAdminDelay(this.target)).to.equal(this.oldDelay); + }); + }, + after: function self() { + self.mineDelay = true; + + it('returns the new target admin delay', async function () { + expect(await this.manager.getTargetAdminDelay(this.target)).to.equal(this.newDelay); + }); + }, + }); + }); + + it('returns the 0 if not set', async function () { + expect(await this.manager.getTargetAdminDelay(this.target)).to.equal(0n); + }); + }); + + describe('#getRoleAdmin', function () { + const roleId = 5234907n; + + it('returns the role admin', async function () { + const adminId = 789433n; + + await this.manager.$_setRoleAdmin(roleId, adminId); + + expect(await this.manager.getRoleAdmin(roleId)).to.equal(adminId); + }); + + it('returns the ADMIN role if not set', async function () { + expect(await this.manager.getRoleAdmin(roleId)).to.equal(this.roles.ADMIN.id); + }); + }); + + describe('#getRoleGuardian', function () { + const roleId = 5234907n; + + it('returns the role guardian', async function () { + const guardianId = 789433n; + + await this.manager.$_setRoleGuardian(roleId, guardianId); + + expect(await this.manager.getRoleGuardian(roleId)).to.equal(guardianId); + }); + + it('returns the ADMIN role if not set', async function () { + expect(await this.manager.getRoleGuardian(roleId)).to.equal(this.roles.ADMIN.id); + }); + }); + + describe('#getRoleGrantDelay', function () { + const roleId = 9248439n; + + 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 testAsDelay + }); + + testAsDelay('grant', { + before: function self() { + self.mineDelay = true; + + it('returns the old role grant delay', async function () { + expect(await this.manager.getRoleGrantDelay(roleId)).to.equal(this.oldDelay); + }); + }, + after: function self() { + self.mineDelay = true; + + it('returns the new role grant delay', async function () { + expect(await this.manager.getRoleGrantDelay(roleId)).to.equal(this.newDelay); + }); + }, + }); + }); + + it('returns 0 if delay is not set', async function () { + expect(await this.manager.getTargetAdminDelay(this.target)).to.equal(0n); + }); + }); + + describe('#getAccess', function () { + beforeEach('set role', function () { + this.role = { id: 9452n }; + this.caller = this.user; + }); + + testAsGetAccess({ + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay: function self() { + self.mineDelay = true; + + 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.equal(this.delayEffect); // inEffectSince + expect(access[1]).to.equal(this.executionDelay); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // pendingDelayEffect + + // Not in effect yet + expect(await time.clock.timestamp()).to.lt(access[0]); + }); + }, + afterGrantDelay: function self() { + self.mineDelay = true; + + 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.equal(this.delayEffect); // inEffectSince + expect(access[1]).to.equal(this.executionDelay); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // pendingDelayEffect + + // Already in effect + expect(await time.clock.timestamp()).to.equal(access[0]); + }); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay: function self() { + self.mineDelay = true; + + 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.equal(this.delayEffect); // inEffectSince + expect(access[1]).to.equal(0n); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // pendingDelayEffect + + // Not in effect yet + expect(await time.clock.timestamp()).to.lt(access[0]); + }); + }, + afterGrantDelay: function self() { + self.mineDelay = true; + + 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.equal(this.delayEffect); // inEffectSince + expect(access[1]).to.equal(0n); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // pendingDelayEffect + + // Already in effect + expect(await time.clock.timestamp()).to.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.equal(await time.clock.timestamp()); // inEffectSince + expect(access[1]).to.equal(this.executionDelay); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // pendingDelayEffect + + // Already in effect + expect(await time.clock.timestamp()).to.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.equal(await time.clock.timestamp()); // inEffectSince + expect(access[1]).to.equal(0n); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // pendingDelayEffect + + // Already in effect + expect(await time.clock.timestamp()).to.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.equal(0n); // inEffectSince + expect(access[1]).to.equal(0n); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // pendingDelayEffect + }); + }, + }); + }); + + describe('#hasRole', function () { + beforeEach('setup testAsHasRole', function () { + this.role = { id: 49832n }; + this.calldata = '0x12345678'; + this.caller = this.user; + }); + + testAsHasRole({ + 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.equal('0'); + }); + }, + specificRoleIsRequired: { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay: function self() { + self.mineDelay = true; + + 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.equal(this.executionDelay); + }); + }, + afterGrantDelay: function self() { + self.mineDelay = true; + + 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.equal(this.executionDelay); + }); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay: function self() { + self.mineDelay = true; + + 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.equal('0'); + }); + }, + afterGrantDelay: function self() { + self.mineDelay = true; + + 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.equal('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.equal(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.equal('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.equal('0'); + }); + }, + }, + }); + }); + + describe('#getSchedule', function () { + beforeEach('set role and calldata', async function () { + const fnRestricted = this.target.fnRestricted.getFragment().selector; + this.caller = this.user; + this.role = { id: 493590n }; + await this.manager.$_setTargetFunctionRole(this.target, fnRestricted, this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay + + this.calldata = this.target.interface.encodeFunctionData(fnRestricted, []); + this.scheduleIn = time.duration.days(10); // For testAsSchedulableOperation + }); + + testAsSchedulableOperation({ + scheduled: { + before: function self() { + self.mineDelay = true; + + it('returns schedule in the future', async function () { + const schedule = await this.manager.getSchedule(this.operationId); + expect(schedule).to.equal(this.scheduledAt + this.scheduleIn); + expect(schedule).to.gt(await time.clock.timestamp()); + }); + }, + after: function self() { + self.mineDelay = true; + + it('returns schedule', async function () { + const schedule = await this.manager.getSchedule(this.operationId); + expect(schedule).to.equal(this.scheduledAt + this.scheduleIn); + expect(schedule).to.equal(await time.clock.timestamp()); + }); + }, + expired: function self() { + self.mineDelay = true; + + it('returns 0', async function () { + expect(await this.manager.getSchedule(this.operationId)).to.equal(0n); + }); + }, + }, + notScheduled() { + it('defaults to 0', async function () { + expect(await this.manager.getSchedule(this.operationId)).to.equal(0n); + }); + }, + }); + }); + + describe('#getNonce', function () { + describe('when operation is scheduled', function () { + beforeEach('schedule operation', async function () { + const fnRestricted = this.target.fnRestricted.getFragment().selector; + this.caller = this.user; + this.role = { id: 4209043n }; + await this.manager.$_setTargetFunctionRole(this.target, fnRestricted, this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay + + this.calldata = this.target.interface.encodeFunctionData(fnRestricted, []); + this.delay = time.duration.days(10); + + const { operationId, schedule } = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay: this.delay, + }); + await schedule(); + this.operationId = operationId; + }); + + it('returns nonce', async function () { + expect(await this.manager.getNonce(this.operationId)).to.equal(1n); + }); + }); + + describe('when is not scheduled', function () { + it('returns default 0', async function () { + expect(await this.manager.getNonce(ethers.id('operation'))).to.equal(0n); + }); + }); + }); + + describe('#hashOperation', function () { + it('returns an operationId', async function () { + const args = [this.user, this.other, '0x123543']; + expect(await this.manager.hashOperation(...args)).to.equal(hashOperation(...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 args = [123443, 'TEST']; + const method = this.manager.interface.getFunction('labelRole(uint64,string)'); + this.calldata = this.manager.interface.encodeFunctionData(method, args); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + it('emits an event with the label', async function () { + await expect(this.manager.connect(this.admin).labelRole(this.roles.SOME.id, 'Some label')) + .to.emit(this.manager, 'RoleLabel') + .withArgs(this.roles.SOME.id, 'Some label'); + }); + + it('updates label on a second call', async function () { + await this.manager.connect(this.admin).labelRole(this.roles.SOME.id, 'Some label'); + + await expect(this.manager.connect(this.admin).labelRole(this.roles.SOME.id, 'Updated label')) + .to.emit(this.manager, 'RoleLabel') + .withArgs(this.roles.SOME.id, 'Updated label'); + }); + + it('reverts labeling PUBLIC_ROLE', async function () { + await expect(this.manager.connect(this.admin).labelRole(this.roles.PUBLIC.id, 'Some label')) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') + .withArgs(this.roles.PUBLIC.id); + }); + + it('reverts labeling ADMIN_ROLE', async function () { + await expect(this.manager.connect(this.admin).labelRole(this.roles.ADMIN.id, 'Some label')) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') + .withArgs(this.roles.ADMIN.id); + }); + }); + + describe('#setRoleAdmin', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const args = [93445, 84532]; + const method = this.manager.interface.getFunction('setRoleAdmin(uint64,uint64)'); + this.calldata = this.manager.interface.encodeFunctionData(method, args); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + it("sets any role's admin if called by an admin", async function () { + expect(await this.manager.getRoleAdmin(this.roles.SOME.id)).to.equal(this.roles.SOME_ADMIN.id); + + await expect(this.manager.connect(this.admin).setRoleAdmin(this.roles.SOME.id, this.roles.ADMIN.id)) + .to.emit(this.manager, 'RoleAdminChanged') + .withArgs(this.roles.SOME.id, this.roles.ADMIN.id); + + expect(await this.manager.getRoleAdmin(this.roles.SOME.id)).to.equal(this.roles.ADMIN.id); + }); + + it('reverts setting PUBLIC_ROLE admin', async function () { + await expect(this.manager.connect(this.admin).setRoleAdmin(this.roles.PUBLIC.id, this.roles.ADMIN.id)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') + .withArgs(this.roles.PUBLIC.id); + }); + + it('reverts setting ADMIN_ROLE admin', async function () { + await expect(this.manager.connect(this.admin).setRoleAdmin(this.roles.ADMIN.id, this.roles.ADMIN.id)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') + .withArgs(this.roles.ADMIN.id); + }); + }); + + describe('#setRoleGuardian', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const args = [93445, 84532]; + const method = this.manager.interface.getFunction('setRoleGuardian(uint64,uint64)'); + this.calldata = this.manager.interface.encodeFunctionData(method, args); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + it("sets any role's guardian if called by an admin", async function () { + expect(await this.manager.getRoleGuardian(this.roles.SOME.id)).to.equal(this.roles.SOME_GUARDIAN.id); + + await expect(this.manager.connect(this.admin).setRoleGuardian(this.roles.SOME.id, this.roles.ADMIN.id)) + .to.emit(this.manager, 'RoleGuardianChanged') + .withArgs(this.roles.SOME.id, this.roles.ADMIN.id); + + expect(await this.manager.getRoleGuardian(this.roles.SOME.id)).to.equal(this.roles.ADMIN.id); + }); + + it('reverts setting PUBLIC_ROLE admin', async function () { + await expect(this.manager.connect(this.admin).setRoleGuardian(this.roles.PUBLIC.id, this.roles.ADMIN.id)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') + .withArgs(this.roles.PUBLIC.id); + }); + + it('reverts setting ADMIN_ROLE admin', async function () { + await expect(this.manager.connect(this.admin).setRoleGuardian(this.roles.ADMIN.id, this.roles.ADMIN.id)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') + .withArgs(this.roles.ADMIN.id); + }); + }); + + describe('#setGrantDelay', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const args = [984910, time.duration.days(2)]; + const method = this.manager.interface.getFunction('setGrantDelay(uint64,uint32)'); + this.calldata = this.manager.interface.encodeFunctionData(method, args); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + it('reverts setting grant delay for the PUBLIC_ROLE', async function () { + await expect(this.manager.connect(this.admin).setGrantDelay(this.roles.PUBLIC.id, 69n)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') + .withArgs(this.roles.PUBLIC.id); + }); + + describe('when increasing the delay', function () { + const oldDelay = 10n; + const newDelay = 100n; + + beforeEach('sets old delay', async function () { + this.role = this.roles.SOME; + await this.manager.$_setGrantDelay(this.role.id, oldDelay); + await time.increaseBy.timestamp(MINSETBACK); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.equal(oldDelay); + }); + + it('increases the delay after minsetback', async function () { + const txResponse = await this.manager.connect(this.admin).setGrantDelay(this.role.id, newDelay); + const setGrantDelayAt = await time.clockFromReceipt.timestamp(txResponse); + await expect(txResponse) + .to.emit(this.manager, 'RoleGrantDelayChanged') + .withArgs(this.role.id, newDelay, setGrantDelayAt + MINSETBACK); + + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.equal(oldDelay); + await time.increaseBy.timestamp(MINSETBACK); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.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.increaseBy.timestamp(MINSETBACK); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.equal(oldDelay); + }); + + describe('when the delay difference is shorter than minimum setback', function () { + const newDelay = oldDelay - 1n; + + it('increases the delay after minsetback', async function () { + const txResponse = await this.manager.connect(this.admin).setGrantDelay(this.role.id, newDelay); + const setGrantDelayAt = await time.clockFromReceipt.timestamp(txResponse); + await expect(txResponse) + .to.emit(this.manager, 'RoleGrantDelayChanged') + .withArgs(this.role.id, newDelay, setGrantDelayAt + MINSETBACK); + + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.equal(oldDelay); + await time.increaseBy.timestamp(MINSETBACK); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.equal(newDelay); + }); + }); + + describe('when the delay difference is longer than minimum setback', function () { + const newDelay = 1n; + + beforeEach('assert delay difference is higher than minsetback', function () { + expect(oldDelay - newDelay).to.gt(MINSETBACK); + }); + + it('increases the delay after delay difference', async function () { + const setback = oldDelay - newDelay; + + const txResponse = await this.manager.connect(this.admin).setGrantDelay(this.role.id, newDelay); + const setGrantDelayAt = await time.clockFromReceipt.timestamp(txResponse); + + await expect(txResponse) + .to.emit(this.manager, 'RoleGrantDelayChanged') + .withArgs(this.role.id, newDelay, setGrantDelayAt + setback); + + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.equal(oldDelay); + await time.increaseBy.timestamp(setback); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.equal(newDelay); + }); + }); + }); + }); + + describe('#setTargetAdminDelay', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const args = [this.other.address, time.duration.days(3)]; + const method = this.manager.interface.getFunction('setTargetAdminDelay(address,uint32)'); + this.calldata = this.manager.interface.encodeFunctionData(method, args); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + describe('when increasing the delay', function () { + const oldDelay = time.duration.days(10); + const newDelay = time.duration.days(11); + + beforeEach('sets old delay', async function () { + await this.manager.$_setTargetAdminDelay(this.other, oldDelay); + await time.increaseBy.timestamp(MINSETBACK); + expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay); + }); + + it('increases the delay after minsetback', async function () { + const txResponse = await this.manager.connect(this.admin).setTargetAdminDelay(this.other, newDelay); + const setTargetAdminDelayAt = await time.clockFromReceipt.timestamp(txResponse); + await expect(txResponse) + .to.emit(this.manager, 'TargetAdminDelayUpdated') + .withArgs(this.other, newDelay, setTargetAdminDelayAt + MINSETBACK); + + expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay); + await time.increaseBy.timestamp(MINSETBACK); + expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(newDelay); + }); + }); + + describe('when reducing the delay', function () { + const oldDelay = time.duration.days(10); + + beforeEach('sets old delay', async function () { + await this.manager.$_setTargetAdminDelay(this.other, oldDelay); + await time.increaseBy.timestamp(MINSETBACK); + expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay); + }); + + describe('when the delay difference is shorter than minimum setback', function () { + const newDelay = oldDelay - 1n; + + it('increases the delay after minsetback', async function () { + const txResponse = await this.manager.connect(this.admin).setTargetAdminDelay(this.other, newDelay); + const setTargetAdminDelayAt = await time.clockFromReceipt.timestamp(txResponse); + await expect(txResponse) + .to.emit(this.manager, 'TargetAdminDelayUpdated') + .withArgs(this.other, newDelay, setTargetAdminDelayAt + MINSETBACK); + + expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay); + await time.increaseBy.timestamp(MINSETBACK); + expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(newDelay); + }); + }); + + describe('when the delay difference is longer than minimum setback', function () { + const newDelay = 1n; + + beforeEach('assert delay difference is higher than minsetback', function () { + expect(oldDelay - newDelay).to.gt(MINSETBACK); + }); + + it('increases the delay after delay difference', async function () { + const setback = oldDelay - newDelay; + + const txResponse = await this.manager.connect(this.admin).setTargetAdminDelay(this.other, newDelay); + const setTargetAdminDelayAt = await time.clockFromReceipt.timestamp(txResponse); + + await expect(txResponse) + .to.emit(this.manager, 'TargetAdminDelayUpdated') + .withArgs(this.other, newDelay, setTargetAdminDelayAt + setback); + + expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay); + await time.increaseBy.timestamp(setback); + expect(await this.manager.getTargetAdminDelay(this.other)).to.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 ethers.deployContract('$AccessManager', [this.admin]); + this.newManagedTarget = await ethers.deployContract('$AccessManagedTarget', [this.manager]); + }); + + describe('restrictions', function () { + beforeEach('set method and args', function () { + this.calldata = this.manager.interface.encodeFunctionData('updateAuthority(address,address)', [ + this.newManagedTarget.target, + this.newAuthority.target, + ]); + }); + + shouldBehaveLikeNotDelayedAdminOperation(); + }); + + it('changes the authority', async function () { + expect(await this.newManagedTarget.authority()).to.equal(this.manager); + + await expect(this.manager.connect(this.admin).updateAuthority(this.newManagedTarget, this.newAuthority)) + .to.emit(this.newManagedTarget, 'AuthorityUpdated') // Managed contract is responsible of notifying the change through an event + .withArgs(this.newAuthority); + + expect(await this.newManagedTarget.authority()).to.equal(this.newAuthority); + }); + }); + + describe('#setTargetClosed', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const args = [this.other.address, true]; + const method = this.manager.interface.getFunction('setTargetClosed(address,bool)'); + this.calldata = this.manager.interface.encodeFunctionData(method, args); + }); + + shouldBehaveLikeNotDelayedAdminOperation(); + }); + + it('closes and opens a target', async function () { + await expect(this.manager.connect(this.admin).setTargetClosed(this.target, true)) + .to.emit(this.manager, 'TargetClosed') + .withArgs(this.target, true); + expect(await this.manager.isTargetClosed(this.target)).to.be.true; + + await expect(this.manager.connect(this.admin).setTargetClosed(this.target, false)) + .to.emit(this.manager, 'TargetClosed') + .withArgs(this.target, false); + expect(await this.manager.isTargetClosed(this.target)).to.be.false; + }); + + describe('when the target is the manager', async function () { + it('closes and opens the manager', async function () { + await expect(this.manager.connect(this.admin).setTargetClosed(this.manager, true)) + .to.emit(this.manager, 'TargetClosed') + .withArgs(this.manager, true); + expect(await this.manager.isTargetClosed(this.manager)).to.be.true; + + await expect(this.manager.connect(this.admin).setTargetClosed(this.manager, false)) + .to.emit(this.manager, 'TargetClosed') + .withArgs(this.manager, false); + expect(await this.manager.isTargetClosed(this.manager)).to.be.false; + }); + }); + }); + + describe('#setTargetFunctionRole', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const args = [this.other.address, ['0x12345678'], 443342]; + const method = this.manager.interface.getFunction('setTargetFunctionRole(address,bytes4[],uint64)'); + this.calldata = this.manager.interface.encodeFunctionData(method, args); + }); + + 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, sig)).to.equal(this.roles.ADMIN.id); + } + + const allowRole = await this.manager + .connect(this.admin) + .setTargetFunctionRole(this.target, sigs, this.roles.SOME.id); + + for (const sig of sigs) { + await expect(allowRole) + .to.emit(this.manager, 'TargetFunctionRoleUpdated') + .withArgs(this.target, sig, this.roles.SOME.id); + expect(await this.manager.getTargetFunctionRole(this.target, sig)).to.equal(this.roles.SOME.id); + } + + await expect( + this.manager.connect(this.admin).setTargetFunctionRole(this.target, [sigs[1]], this.roles.SOME_ADMIN.id), + ) + .to.emit(this.manager, 'TargetFunctionRoleUpdated') + .withArgs(this.target, sigs[1], this.roles.SOME_ADMIN.id); + + for (const sig of sigs) { + expect(await this.manager.getTargetFunctionRole(this.target, sig)).to.equal( + sig == sigs[1] ? this.roles.SOME_ADMIN.id : this.roles.SOME.id, + ); + } + }); + }); + + describe('role admin operations', function () { + const ANOTHER_ADMIN = 0xdeadc0de1n; + const ANOTHER_ROLE = 0xdeadc0de2n; + + beforeEach('set required role', async function () { + // Make admin a member of ANOTHER_ADMIN + await this.manager.$_grantRole(ANOTHER_ADMIN, this.admin, 0, 0); + await this.manager.$_setRoleAdmin(ANOTHER_ROLE, ANOTHER_ADMIN); + + this.role = { id: ANOTHER_ADMIN }; + await this.manager.$_grantRole(this.role.id, this.user, 0, 0); + }); + + describe('#grantRole', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const args = [ANOTHER_ROLE, this.other.address, 0]; + const method = this.manager.interface.getFunction('grantRole(uint64,address,uint32)'); + this.calldata = this.manager.interface.encodeFunctionData(method, args); + }); + + shouldBehaveLikeRoleAdminOperation(ANOTHER_ADMIN); + }); + + it('reverts when granting PUBLIC_ROLE', async function () { + await expect(this.manager.connect(this.admin).grantRole(this.roles.PUBLIC.id, this.user, 0)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') + .withArgs(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.increaseBy.timestamp(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', + ]); + + this.txResponse = await this.manager + .connect(this.admin) + .grantRole(ANOTHER_ROLE, this.user, this.executionDelay); + this.delay = this.grantDelay; // For testAsDelay + }); + + testAsDelay('grant', { + before: function self() { + self.mineDelay = true; + + it('does not grant role to the user yet', async function () { + const timestamp = await time.clockFromReceipt.timestamp(this.txResponse); + await expect(this.txResponse) + .to.emit(this.manager, 'RoleGranted') + .withArgs(ANOTHER_ROLE, this.user, this.executionDelay, timestamp + this.grantDelay, true); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); + expect(access[0]).to.equal(timestamp + this.grantDelay); // inEffectSince + expect(access[1]).to.equal(this.executionDelay); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // pendingDelayEffect + + // Not in effect yet + const currentTimestamp = await time.clock.timestamp(); + expect(currentTimestamp).to.be.lt(access[0]); + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + false, + this.executionDelay.toString(), + ]); + }); + }, + after: function self() { + self.mineDelay = true; + + it('grants role to the user', async function () { + const timestamp = await time.clockFromReceipt.timestamp(this.txResponse); + await expect(this.txResponse) + .to.emit(this.manager, 'RoleGranted') + .withArgs(ANOTHER_ROLE, this.user, this.executionDelay, timestamp + this.grantDelay, true); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); + expect(access[0]).to.equal(timestamp + this.grantDelay); // inEffectSince + expect(access[1]).to.equal(this.executionDelay); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // pendingDelayEffect + + // Already in effect + const currentTimestamp = await time.clock.timestamp(); + expect(currentTimestamp).to.equal(access[0]); + expect(await this.manager.hasRole(ANOTHER_ROLE, this.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.increaseBy.timestamp(MINSETBACK); + }); + + it('immediately grants the role to the user', async function () { + const executionDelay = time.duration.days(6); + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + const txResponse = await this.manager + .connect(this.admin) + .grantRole(ANOTHER_ROLE, this.user, executionDelay); + const grantedAt = await time.clockFromReceipt.timestamp(txResponse); + await expect(txResponse) + .to.emit(this.manager, 'RoleGranted') + .withArgs(ANOTHER_ROLE, this.user, executionDelay, grantedAt, true); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); + expect(access[0]).to.equal(grantedAt); // inEffectSince + expect(access[1]).to.equal(executionDelay); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // pendingDelayEffect + + // Already in effect + const currentTimestamp = await time.clock.timestamp(); + expect(currentTimestamp).to.equal(access[0]); + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + 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, this.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.increaseBy.timestamp(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 + 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 txResponse = await this.manager + .connect(this.admin) + .grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay); + const timestamp = await time.clockFromReceipt.timestamp(txResponse); + + await expect(txResponse) + .to.emit(this.manager, 'RoleGranted') + .withArgs(ANOTHER_ROLE, this.user, this.newExecutionDelay, timestamp, false); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); + expect(access[0]).to.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.equal(this.newExecutionDelay); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // pendingDelayEffect + + // Already in effect + expect(await this.manager.hasRole(ANOTHER_ROLE, this.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 - time.duration.days(4); + this.txResponse = await this.manager + .connect(this.admin) + .grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay); + this.grantTimestamp = await time.clockFromReceipt.timestamp(this.txResponse); + + this.delay = this.previousExecutionDelay - this.newExecutionDelay; // For testAsDelay + }); + + it('emits event', async function () { + await expect(this.txResponse) + .to.emit(this.manager, 'RoleGranted') + .withArgs(ANOTHER_ROLE, this.user, this.newExecutionDelay, this.grantTimestamp + this.delay, false); + }); + + testAsDelay('execution delay effect', { + before: function self() { + self.mineDelay = true; + + it('does not change the execution delay yet', async function () { + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); + expect(access[0]).to.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.equal(this.previousExecutionDelay); // currentDelay + expect(access[2]).to.equal(this.newExecutionDelay); // pendingDelay + expect(access[3]).to.equal(this.grantTimestamp + this.delay); // pendingDelayEffect + + // Not in effect yet + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + }); + }, + after: function self() { + self.mineDelay = true; + + it('changes the execution delay', async function () { + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); + + expect(access[0]).to.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.equal(this.newExecutionDelay); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // pendingDelayEffect + + // Already in effect + expect(await this.manager.hasRole(ANOTHER_ROLE, this.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.increaseBy.timestamp(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 + 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 txResponse = await this.manager + .connect(this.admin) + .grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay); + const timestamp = await time.clockFromReceipt.timestamp(txResponse); + + await expect(txResponse) + .to.emit(this.manager, 'RoleGranted') + .withArgs(ANOTHER_ROLE, this.user, this.newExecutionDelay, timestamp, false); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); + expect(access[0]).to.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.equal(this.newExecutionDelay); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // pendingDelayEffect + + // Already in effect + expect(await this.manager.hasRole(ANOTHER_ROLE, this.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 - time.duration.days(4); + this.txResponse = await this.manager + .connect(this.admin) + .grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay); + this.grantTimestamp = await time.clockFromReceipt.timestamp(this.txResponse); + + this.delay = this.previousExecutionDelay - this.newExecutionDelay; // For testAsDelay + }); + + it('emits event', async function () { + await expect(this.txResponse) + .to.emit(this.manager, 'RoleGranted') + .withArgs(ANOTHER_ROLE, this.user, this.newExecutionDelay, this.grantTimestamp + this.delay, false); + }); + + testAsDelay('execution delay effect', { + before: function self() { + self.mineDelay = true; + + it('does not change the execution delay yet', async function () { + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); + expect(access[0]).to.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.equal(this.previousExecutionDelay); // currentDelay + expect(access[2]).to.equal(this.newExecutionDelay); // pendingDelay + expect(access[3]).to.equal(this.grantTimestamp + this.delay); // pendingDelayEffect + + // Not in effect yet + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + }); + }, + after: function self() { + self.mineDelay = true; + + it('changes the execution delay', async function () { + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); + + expect(access[0]).to.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.equal(this.newExecutionDelay); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // pendingDelayEffect + + // Already in effect + expect(await this.manager.hasRole(ANOTHER_ROLE, this.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 args = [ANOTHER_ROLE, this.other.address]; + const method = this.manager.interface.getFunction('revokeRole(uint64,address)'); + this.calldata = this.manager.interface.encodeFunctionData(method, args); + + // 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, this.user, this.grantDelay, 0); + + this.delay = this.grantDelay; // For testAsDelay + }); + + testAsDelay('grant', { + before: function self() { + self.mineDelay = true; + + it('revokes a granted role that will take effect in the future', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + + await expect(this.manager.connect(this.admin).revokeRole(ANOTHER_ROLE, this.user)) + .to.emit(this.manager, 'RoleRevoked') + .withArgs(ANOTHER_ROLE, this.user); + + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + + const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); + expect(access[0]).to.equal(0n); // inRoleSince + expect(access[1]).to.equal(0n); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // effect + }); + }, + after: function self() { + self.mineDelay = true; + + it('revokes a granted role that already took effect', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + '0', + ]); + + await expect(this.manager.connect(this.admin).revokeRole(ANOTHER_ROLE, this.user)) + .to.emit(this.manager, 'RoleRevoked') + .withArgs(ANOTHER_ROLE, this.user); + + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + + const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); + expect(access[0]).to.equal(0n); // inRoleSince + expect(access[1]).to.equal(0n); // currentDelay + expect(access[2]).to.equal(0n); // pendingDelay + expect(access[3]).to.equal(0n); // effect + }); + }, + }); + }); + + describe('when role has not been granted', function () { + it('has no effect', async function () { + expect(await this.manager.hasRole(this.roles.SOME.id, this.user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + await expect(this.manager.connect(this.roleAdmin).revokeRole(this.roles.SOME.id, this.user)).to.not.emit( + this.manager, + 'RoleRevoked', + ); + expect(await this.manager.hasRole(this.roles.SOME.id, this.user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + }); + }); + + it('reverts revoking PUBLIC_ROLE', async function () { + await expect(this.manager.connect(this.admin).revokeRole(this.roles.PUBLIC.id, this.user)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') + .withArgs(this.roles.PUBLIC.id); + }); + }); + }); + + describe('self role operations', function () { + describe('#renounceRole', function () { + beforeEach('grant role', async function () { + this.role = { id: 783164n }; + this.caller = this.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', + ]); + await expect(this.manager.connect(this.caller).renounceRole(this.role.id, this.caller)) + .to.emit(this.manager, 'RoleRevoked') + .withArgs(this.role.id, 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 expect(this.manager.connect(this.caller).renounceRole(this.roles.PUBLIC.id, this.caller)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') + .withArgs(this.roles.PUBLIC.id); + }); + + it('reverts if renouncing with bad caller confirmation', async function () { + await expect( + this.manager.connect(this.caller).renounceRole(this.role.id, this.other), + ).to.be.revertedWithCustomError(this.manager, 'AccessManagerBadConfirmation'); + }); + }); + }); + }); + }); + + describe('access managed self operations', function () { + describe('when calling a restricted target function', function () { + const method = 'fnRestricted()'; + + beforeEach('set required role', async function () { + this.role = { id: 785913n }; + await this.manager.$_setTargetFunctionRole( + this.manager, + this.manager[method].getFragment().selector, + this.role.id, + ); + }); + + describe('restrictions', function () { + beforeEach('set method and args', function () { + this.caller = this.user; + this.calldata = this.manager.interface.encodeFunctionData(method, []); + }); + + shouldBehaveLikeASelfRestrictedOperation(); + }); + + it('succeeds called by a role member', async function () { + await this.manager.$_grantRole(this.role.id, this.user, 0, 0); + + await expect(this.manager.connect(this.user)[method]()) + .to.emit(this.manager, 'CalledRestricted') + .withArgs(this.user); + }); + }); + + describe('when calling a non-restricted target function', function () { + const method = 'fnUnrestricted()'; + + beforeEach('set required role', async function () { + this.role = { id: 879435n }; + await this.manager.$_setTargetFunctionRole( + this.manager, + this.manager[method].getFragment().selector, + this.role.id, + ); + }); + + it('succeeds called by anyone', async function () { + await expect(this.manager.connect(this.user)[method]()) + .to.emit(this.manager, 'CalledUnrestricted') + .withArgs(this.user); + }); + }); + }); + + describe('access managed target operations', function () { + describe('when calling a restricted target function', function () { + const method = 'fnRestricted()'; + + beforeEach('set required role', async function () { + this.role = { id: 3597243n }; + await this.manager.$_setTargetFunctionRole( + this.target, + this.target[method].getFragment().selector, + this.role.id, + ); + }); + + describe('restrictions', function () { + beforeEach('set method and args', function () { + this.caller = this.user; + this.calldata = this.target.interface.encodeFunctionData(method, []); + }); + + shouldBehaveLikeAManagedRestrictedOperation(); + }); + + it('succeeds called by a role member', async function () { + await this.manager.$_grantRole(this.role.id, this.user, 0, 0); + + await expect(this.target.connect(this.user)[method]()) + .to.emit(this.target, 'CalledRestricted') + .withArgs(this.user); + }); + }); + + describe('when calling a non-restricted target function', function () { + const method = 'fnUnrestricted()'; + + beforeEach('set required role', async function () { + this.role = { id: 879435n }; + await this.manager.$_setTargetFunctionRole( + this.target, + this.target[method].getFragment().selector, + this.role.id, + ); + }); + + it('succeeds called by anyone', async function () { + await expect(this.target.connect(this.user)[method]()) + .to.emit(this.target, 'CalledUnrestricted') + .withArgs(this.user); + }); + }); + }); + + describe('#schedule', function () { + beforeEach('set target function role', async function () { + this.method = this.target.fnRestricted.getFragment(); + this.role = { id: 498305n }; + this.caller = this.user; + + await this.manager.$_setTargetFunctionRole(this.target, this.method.selector, this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay + + this.calldata = this.target.interface.encodeFunctionData(this.method, []); + this.delay = time.duration.weeks(2); + }); + + describe('restrictions', function () { + testAsCanCall({ + closed() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + const { schedule } = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay: this.delay, + }); + await expect(schedule()) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.target, 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 () { + const { schedule } = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay: this.delay, + }); + await expect(schedule()) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); + }); + }, + }, + callerIsNotTheManager: { + publicRoleIsRequired() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // prepareOperation is not used here because it alters the next block timestamp + await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); + }); + }, + specificRoleIsRequired: { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // prepareOperation is not used here because it alters the next block timestamp + await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); + }); + }, + afterGrantDelay() { + it('succeeds', async function () { + // prepareOperation is not used here because it alters the next block timestamp + await this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48); + }); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // prepareOperation is not used here because it alters the next block timestamp + await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); + }); + }, + afterGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // prepareOperation is not used here because it alters the next block timestamp + await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); + }); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay() { + it('succeeds', async function () { + const { schedule } = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay: this.delay, + }); + + await schedule(); + }); + }, + callerHasNoExecutionDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // prepareOperation is not used here because it alters the next block timestamp + await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); + }); + }, + }, + }, + requiredRoleIsNotGranted() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + const { schedule } = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay: this.delay, + }); + await expect(schedule()) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.target, 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, schedule } = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay: this.delay, + }); + + const txResponse = await schedule(); + + expect(await this.manager.getSchedule(operationId)).to.equal(scheduledAt + this.delay); + await expect(txResponse) + .to.emit(this.manager, 'OperationScheduled') + .withArgs(operationId, '1', scheduledAt + this.delay, this.caller, this.target, 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 txResponse = await this.manager.connect(this.caller).schedule(this.target, this.calldata, 0); + const scheduledAt = await time.clockFromReceipt.timestamp(txResponse); + + const operationId = await this.manager.hashOperation(this.caller, this.target, this.calldata); + + expect(await this.manager.getSchedule(operationId)).to.equal(scheduledAt + executionDelay); + await expect(txResponse) + .to.emit(this.manager, 'OperationScheduled') + .withArgs(operationId, '1', scheduledAt + executionDelay, this.caller, this.target, this.calldata); + }); + + it('increases the nonce of an operation scheduled more than once', async function () { + // Setup and check initial nonce + const expectedOperationId = hashOperation(this.caller, this.target, this.calldata); + expect(await this.manager.getNonce(expectedOperationId)).to.equal('0'); + + // Schedule + const op1 = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay: this.delay, + }); + await expect(op1.schedule()) + .to.emit(this.manager, 'OperationScheduled') + .withArgs(op1.operationId, 1n, op1.scheduledAt + this.delay, this.caller, this.target, this.calldata); + expect(expectedOperationId).to.equal(op1.operationId); + + // Consume + await time.increaseBy.timestamp(this.delay); + await this.manager.$_consumeScheduledOp(expectedOperationId); + + // Check nonce + expect(await this.manager.getNonce(expectedOperationId)).to.equal('1'); + + // Schedule again + const op2 = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay: this.delay, + }); + await expect(op2.schedule()) + .to.emit(this.manager, 'OperationScheduled') + .withArgs(op2.operationId, 2n, op2.scheduledAt + this.delay, this.caller, this.target, this.calldata); + expect(expectedOperationId).to.equal(op2.operationId); + + // Check final nonce + expect(await this.manager.getNonce(expectedOperationId)).to.equal('2'); + }); + + it('reverts if the specified execution date is before the current timestamp + caller execution delay', async function () { + const executionDelay = time.duration.weeks(1) + this.delay; + await this.manager.$_grantRole(this.role.id, this.caller, 0, executionDelay); + + const { schedule } = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay: this.delay, + }); + + await expect(schedule()) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); + }); + + it('reverts if an operation is already schedule', async function () { + const op1 = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay: this.delay, + }); + + await op1.schedule(); + + const op2 = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay: this.delay, + }); + + await expect(op2.schedule()) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerAlreadyScheduled') + .withArgs(op1.operationId); + }); + + it('panics scheduling calldata with less than 4 bytes', async function () { + const calldata = '0x1234'; // 2 bytes + + // Managed contract + const op1 = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: calldata, + delay: this.delay, + }); + await expect(op1.schedule()).to.be.revertedWithoutReason(); + + // Manager contract + const op2 = await prepareOperation(this.manager, { + caller: this.caller, + target: this.manager, + calldata: calldata, + delay: this.delay, + }); + await expect(op2.schedule()).to.be.revertedWithoutReason(); + }); + + it('reverts scheduling an unknown operation to the manager', async function () { + const calldata = '0x12345678'; + + const { schedule } = await prepareOperation(this.manager, { + caller: this.caller, + target: this.manager, + calldata, + delay: this.delay, + }); + + await expect(schedule()) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.manager, calldata); + }); + }); + + describe('#execute', function () { + beforeEach('set target function role', async function () { + this.method = this.target.fnRestricted.getFragment(); + this.role = { id: 9825430n }; + this.caller = this.user; + + await this.manager.$_setTargetFunctionRole(this.target, this.method.selector, this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 0); + + this.calldata = this.target.interface.encodeFunctionData(this.method, []); + }); + + describe('restrictions', function () { + testAsCanCall({ + closed() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); + }); + }, + open: { + callerIsTheManager: { + executing() { + it('succeeds', async function () { + await this.manager.connect(this.caller).execute(this.target, this.calldata); + }); + }, + notExecuting() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); + }); + }, + }, + callerIsNotTheManager: { + publicRoleIsRequired() { + it('succeeds', async function () { + await this.manager.connect(this.caller).execute(this.target, this.calldata); + }); + }, + specificRoleIsRequired: { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); + }); + }, + afterGrantDelay: function self() { + self.mineDelay = true; + + beforeEach('define schedule delay', function () { + this.scheduleIn = time.duration.days(21); // For testAsSchedulableOperation + }); + + testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); + }); + }, + afterGrantDelay: function self() { + self.mineDelay = true; + + it('succeeds', async function () { + await this.manager.connect(this.caller).execute(this.target, this.calldata); + }); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay() { + beforeEach('define schedule delay', function () { + this.scheduleIn = time.duration.days(15); // For testAsSchedulableOperation + }); + + testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); + }, + callerHasNoExecutionDelay() { + it('succeeds', async function () { + await this.manager.connect(this.caller).execute(this.target, this.calldata); + }); + }, + }, + }, + requiredRoleIsNotGranted() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.caller, this.target, 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, schedule } = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay, + }); + await schedule(); + await time.increaseBy.timestamp(delay); + await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) + .to.emit(this.manager, 'OperationExecuted') + .withArgs(operationId, 1n); + + expect(await this.manager.getSchedule(operationId)).to.equal(0n); + }); + + 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, schedule } = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay, + }); + await schedule(); + + // remove the execution delay + await this.manager.$_grantRole(this.role.id, this.caller, 0, 0); + + await time.increaseBy.timestamp(delay); + await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) + .to.emit(this.manager, 'OperationExecuted') + .withArgs(operationId, 1n); + + expect(await this.manager.getSchedule(operationId)).to.equal(0n); + }); + + it('keeps the original _executionId after finishing the call', async function () { + const executionIdBefore = await ethers.provider.getStorage(this.manager, EXECUTION_ID_STORAGE_SLOT); + await this.manager.connect(this.caller).execute(this.target, this.calldata); + const executionIdAfter = await ethers.provider.getStorage(this.manager, EXECUTION_ID_STORAGE_SLOT); + expect(executionIdBefore).to.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, schedule } = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay, + }); + await schedule(); + await time.increaseBy.timestamp(delay); + await this.manager.connect(this.caller).execute(this.target, this.calldata); + await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerNotScheduled') + .withArgs(operationId); + }); + }); + + describe('#consumeScheduledOp', function () { + beforeEach('define scheduling parameters', async function () { + const method = this.target.fnRestricted.getFragment(); + this.caller = await ethers.getSigner(this.target.target); + await impersonate(this.caller.address); + this.calldata = this.target.interface.encodeFunctionData(method, []); + this.role = { id: 9834983n }; + + await this.manager.$_setTargetFunctionRole(this.target, method.selector, this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay + + this.scheduleIn = time.duration.hours(10); // For testAsSchedulableOperation + }); + + describe('when caller is not consuming scheduled operation', function () { + beforeEach('set consuming false', async function () { + await this.target.setIsConsumingScheduledOp(false, ethers.toBeHex(CONSUMING_SCHEDULE_STORAGE_SLOT, 32)); + }); + + it('reverts as AccessManagerUnauthorizedConsume', async function () { + await expect(this.manager.connect(this.caller).consumeScheduledOp(this.caller, this.calldata)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedConsume') + .withArgs(this.caller); + }); + }); + + describe('when caller is consuming scheduled operation', function () { + beforeEach('set consuming true', async function () { + await this.target.setIsConsumingScheduledOp(true, ethers.toBeHex(CONSUMING_SCHEDULE_STORAGE_SLOT, 32)); + }); + + testAsSchedulableOperation({ + scheduled: { + before() { + it('reverts as AccessManagerNotReady', async function () { + await expect(this.manager.connect(this.caller).consumeScheduledOp(this.caller, this.calldata)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerNotReady') + .withArgs(this.operationId); + }); + }, + after() { + it('consumes the scheduled operation and resets timepoint', async function () { + expect(await this.manager.getSchedule(this.operationId)).to.equal(this.scheduledAt + this.scheduleIn); + + await expect(this.manager.connect(this.caller).consumeScheduledOp(this.caller, this.calldata)) + .to.emit(this.manager, 'OperationExecuted') + .withArgs(this.operationId, 1n); + expect(await this.manager.getSchedule(this.operationId)).to.equal(0n); + }); + }, + expired() { + it('reverts as AccessManagerExpired', async function () { + await expect(this.manager.connect(this.caller).consumeScheduledOp(this.caller, this.calldata)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerExpired') + .withArgs(this.operationId); + }); + }, + }, + notScheduled() { + it('reverts as AccessManagerNotScheduled', async function () { + await expect(this.manager.connect(this.caller).consumeScheduledOp(this.caller, this.calldata)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerNotScheduled') + .withArgs(this.operationId); + }); + }, + }); + }); + }); + + describe('#cancelScheduledOp', function () { + beforeEach('setup scheduling', async function () { + this.method = this.target.fnRestricted.getFragment(); + this.caller = this.roles.SOME.members[0]; + await this.manager.$_setTargetFunctionRole(this.target, this.method.selector, this.roles.SOME.id); + await this.manager.$_grantRole(this.roles.SOME.id, this.caller, 0, 1); // nonzero execution delay + + this.calldata = this.target.interface.encodeFunctionData(this.method, []); + this.scheduleIn = time.duration.days(10); // For testAsSchedulableOperation + }); + + testAsSchedulableOperation({ + scheduled: { + before() { + describe('when caller is the scheduler', function () { + it('succeeds', async function () { + await this.manager.connect(this.caller).cancel(this.caller, this.target, this.calldata); + }); + }); + + describe('when caller is an admin', function () { + it('succeeds', async function () { + await this.manager.connect(this.roles.ADMIN.members[0]).cancel(this.caller, this.target, this.calldata); + }); + }); + + describe('when caller is the role guardian', function () { + it('succeeds', async function () { + await this.manager + .connect(this.roles.SOME_GUARDIAN.members[0]) + .cancel(this.caller, this.target, this.calldata); + }); + }); + + describe('when caller is any other account', function () { + it('reverts as AccessManagerUnauthorizedCancel', async function () { + await expect(this.manager.connect(this.other).cancel(this.caller, this.target, this.calldata)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCancel') + .withArgs(this.other, this.caller, this.target, this.method.selector); + }); + }); + }, + after() { + it('succeeds', async function () { + await this.manager.connect(this.caller).cancel(this.caller, this.target, this.calldata); + }); + }, + expired() { + it('succeeds', async function () { + await this.manager.connect(this.caller).cancel(this.caller, this.target, this.calldata); + }); + }, + }, + notScheduled() { + it('reverts as AccessManagerNotScheduled', async function () { + await expect(this.manager.cancel(this.caller, this.target, this.calldata)) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerNotScheduled') + .withArgs(this.operationId); + }); + }, + }); + + it('cancels an operation and resets schedule', async function () { + const { operationId, schedule } = await prepareOperation(this.manager, { + caller: this.caller, + target: this.target, + calldata: this.calldata, + delay: this.scheduleIn, + }); + await schedule(); + await expect(this.manager.connect(this.caller).cancel(this.caller, this.target, this.calldata)) + .to.emit(this.manager, 'OperationCanceled') + .withArgs(operationId, 1n); + expect(await this.manager.getSchedule(operationId)).to.equal('0'); + }); + }); + + describe('with Ownable target contract', function () { + const roleId = 1n; + + beforeEach(async function () { + this.ownable = await ethers.deployContract('$Ownable', [this.manager]); + + // add user to role + await this.manager.$_grantRole(roleId, this.user, 0, 0); + }); + + it('initial state', async function () { + expect(await this.ownable.owner()).to.equal(this.manager); + }); + + describe('Contract is closed', function () { + beforeEach(async function () { + await this.manager.$_setTargetClosed(this.ownable, true); + }); + + it('directly call: reverts', async function () { + await expect(this.ownable.connect(this.user).$_checkOwner()) + .to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount') + .withArgs(this.user); + }); + + it('relayed call (with role): reverts', async function () { + await expect( + this.manager.connect(this.user).execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector), + ) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.user, this.ownable, this.ownable.$_checkOwner.getFragment().selector); + }); + + it('relayed call (without role): reverts', async function () { + await expect( + this.manager.connect(this.other).execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector), + ) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.other, this.ownable, this.ownable.$_checkOwner.getFragment().selector); + }); + }); + + describe('Contract is managed', function () { + describe('function is open to specific role', function () { + beforeEach(async function () { + await this.manager.$_setTargetFunctionRole( + this.ownable, + this.ownable.$_checkOwner.getFragment().selector, + roleId, + ); + }); + + it('directly call: reverts', async function () { + await expect(this.ownable.connect(this.user).$_checkOwner()) + .to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount') + .withArgs(this.user); + }); + + it('relayed call (with role): success', async function () { + await this.manager.connect(this.user).execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector); + }); + + it('relayed call (without role): reverts', async function () { + await expect( + this.manager.connect(this.other).execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector), + ) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') + .withArgs(this.other, this.ownable, this.ownable.$_checkOwner.getFragment().selector); + }); + }); + + describe('function is open to public role', function () { + beforeEach(async function () { + await this.manager.$_setTargetFunctionRole( + this.ownable, + this.ownable.$_checkOwner.getFragment().selector, + this.roles.PUBLIC.id, + ); + }); + + it('directly call: reverts', async function () { + await expect(this.ownable.connect(this.user).$_checkOwner()) + .to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount') + .withArgs(this.user); + }); + + it('relayed call (with role): success', async function () { + await this.manager.connect(this.user).execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector); + }); + + it('relayed call (without role): success', async function () { + await this.manager + .connect(this.other) + .execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector); + }); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AuthorityUtils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AuthorityUtils.test.js new file mode 100644 index 0000000..465f617 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AuthorityUtils.test.js @@ -0,0 +1,112 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { MAX_UINT32, MAX_UINT64 } = require('../../helpers/constants'); + +async function fixture() { + const [user, other] = await ethers.getSigners(); + + const mock = await ethers.deployContract('$AuthorityUtils'); + const notAuthorityMock = await ethers.deployContract('NotAuthorityMock'); + const authorityNoDelayMock = await ethers.deployContract('AuthorityNoDelayMock'); + const authorityDelayMock = await ethers.deployContract('AuthorityDelayMock'); + const authorityNoResponse = await ethers.deployContract('AuthorityNoResponse'); + + return { + user, + other, + mock, + notAuthorityMock, + authorityNoDelayMock, + authorityDelayMock, + authorityNoResponse, + }; +} + +describe('AuthorityUtils', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('canCallWithDelay', function () { + describe('when authority does not have a canCall function', function () { + beforeEach(async function () { + this.authority = this.notAuthorityMock; + }); + + it('returns (immediate = 0, delay = 0)', async function () { + const { immediate, delay } = await this.mock.$canCallWithDelay( + this.authority, + this.user, + this.other, + '0x12345678', + ); + expect(immediate).to.be.false; + expect(delay).to.equal(0n); + }); + }); + + describe('when authority has no delay', function () { + beforeEach(async function () { + this.authority = this.authorityNoDelayMock; + 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, + this.user, + this.other, + '0x12345678', + ); + expect(immediate).to.equal(this.immediate); + expect(delay).to.equal(0n); + }); + }); + + describe('when authority replies with a delay', function () { + beforeEach(async function () { + this.authority = this.authorityDelayMock; + }); + + for (const immediate of [true, false]) { + for (const delay of [0n, 42n, MAX_UINT32]) { + it(`returns (immediate=${immediate}, delay=${delay})`, async function () { + await this.authority._setImmediate(immediate); + await this.authority._setDelay(delay); + const result = await this.mock.$canCallWithDelay(this.authority, this.user, this.other, '0x12345678'); + expect(result.immediate).to.equal(immediate); + expect(result.delay).to.equal(delay); + }); + } + } + + it('out of bound delay', async function () { + await this.authority._setImmediate(false); + await this.authority._setDelay(MAX_UINT64); // bigger than the expected uint32 + const result = await this.mock.$canCallWithDelay(this.authority, this.user, this.other, '0x12345678'); + expect(result.immediate).to.equal(false); + expect(result.delay).to.equal(0n); + }); + }); + + describe('when authority replies with empty data', function () { + beforeEach(async function () { + this.authority = this.authorityNoResponse; + }); + + it('returns (immediate = 0, delay = 0)', async function () { + const { immediate, delay } = await this.mock.$canCallWithDelay( + this.authority, + this.user, + this.other, + '0x12345678', + ); + expect(immediate).to.be.false; + expect(delay).to.equal(0n); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.behavior.js new file mode 100644 index 0000000..eb10fbb --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.behavior.js @@ -0,0 +1,144 @@ +const { ethers, entrypoint } = require('hardhat'); +const { expect } = require('chai'); +const { impersonate } = require('../helpers/account'); +const { SIG_VALIDATION_SUCCESS, SIG_VALIDATION_FAILURE } = require('../helpers/erc4337'); +const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); + +function shouldBehaveLikeAccountCore() { + describe('entryPoint', function () { + it('should return the canonical entrypoint', async function () { + await this.mock.deploy(); + await expect(this.mock.entryPoint()).to.eventually.equal(entrypoint.v08); + }); + }); + + describe('validateUserOp', function () { + beforeEach(async function () { + await this.other.sendTransaction({ to: this.mock.target, value: ethers.parseEther('1') }); + await this.mock.deploy(); + this.userOp ??= {}; + }); + + it('should revert if the caller is not the canonical entrypoint', async function () { + // empty operation (does nothing) + const operation = await this.mock.createUserOp(this.userOp).then(op => this.signUserOp(op)); + + await expect(this.mock.connect(this.other).validateUserOp(operation.packed, operation.hash(), 0)) + .to.be.revertedWithCustomError(this.mock, 'AccountUnauthorized') + .withArgs(this.other); + }); + + describe('when the caller is the canonical entrypoint', function () { + beforeEach(async function () { + this.mockFromEntrypoint = this.mock.connect(await impersonate(entrypoint.v08.target)); + }); + + it('should return SIG_VALIDATION_SUCCESS if the signature is valid', async function () { + // empty operation (does nothing) + const operation = await this.mock.createUserOp(this.userOp).then(op => this.signUserOp(op)); + + expect(await this.mockFromEntrypoint.validateUserOp.staticCall(operation.packed, operation.hash(), 0)).to.eq( + SIG_VALIDATION_SUCCESS, + ); + }); + + it('should return SIG_VALIDATION_FAILURE if the signature is invalid', async function () { + // empty operation (does nothing) + const operation = await this.mock.createUserOp(this.userOp); + operation.signature = (await this.invalidSig?.()) ?? '0x00'; + + expect(await this.mockFromEntrypoint.validateUserOp.staticCall(operation.packed, operation.hash(), 0)).to.eq( + SIG_VALIDATION_FAILURE, + ); + }); + + it('should pay missing account funds for execution', async function () { + // empty operation (does nothing) + const operation = await this.mock.createUserOp(this.userOp).then(op => this.signUserOp(op)); + const value = 42n; + + await expect( + this.mockFromEntrypoint.validateUserOp(operation.packed, operation.hash(), value), + ).to.changeEtherBalances([this.mock, entrypoint.v08], [-value, value]); + }); + }); + }); + + describe('fallback', function () { + it('should receive ether', async function () { + await this.mock.deploy(); + const value = 42n; + + await expect(this.other.sendTransaction({ to: this.mock, value })).to.changeEtherBalances( + [this.other, this.mock], + [-value, value], + ); + }); + }); +} + +function shouldBehaveLikeAccountHolder() { + describe('onReceived', function () { + beforeEach(async function () { + await this.mock.deploy(); + }); + + shouldSupportInterfaces(['ERC1155Receiver']); + + describe('onERC1155Received', function () { + const ids = [1n, 2n, 3n]; + const values = [1000n, 2000n, 3000n]; + const data = '0x12345678'; + + beforeEach(async function () { + this.token = await ethers.deployContract('$ERC1155', ['https://somedomain.com/{id}.json']); + await this.token.$_mintBatch(this.other, ids, values, '0x'); + }); + + it('receives ERC1155 tokens from a single ID', async function () { + await this.token.connect(this.other).safeTransferFrom(this.other, this.mock, ids[0], values[0], data); + + await expect( + this.token.balanceOfBatch( + ids.map(() => this.mock), + ids, + ), + ).to.eventually.deep.equal(values.map((v, i) => (i == 0 ? v : 0n))); + }); + + it('receives ERC1155 tokens from a multiple IDs', async function () { + await expect( + this.token.balanceOfBatch( + ids.map(() => this.mock), + ids, + ), + ).to.eventually.deep.equal(ids.map(() => 0n)); + + await this.token.connect(this.other).safeBatchTransferFrom(this.other, this.mock, ids, values, data); + await expect( + this.token.balanceOfBatch( + ids.map(() => this.mock), + ids, + ), + ).to.eventually.deep.equal(values); + }); + }); + + describe('onERC721Received', function () { + const tokenId = 1n; + + beforeEach(async function () { + this.token = await ethers.deployContract('$ERC721', ['Some NFT', 'SNFT']); + await this.token.$_mint(this.other, tokenId); + }); + + it('receives an ERC721 token', async function () { + await this.token.connect(this.other).safeTransferFrom(this.other, this.mock, tokenId); + + await expect(this.token.ownerOf(tokenId)).to.eventually.equal(this.mock); + }); + }); + }); +} + +module.exports = { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder }; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.test.js new file mode 100644 index 0000000..2ccb81f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.test.js @@ -0,0 +1,48 @@ +const { ethers, entrypoint } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain } = require('../helpers/eip712'); +const { ERC4337Helper } = require('../helpers/erc4337'); +const { PackedUserOperation } = require('../helpers/eip712-types'); +const { NonNativeSigner } = require('../helpers/signers'); + +const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); +const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); +const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); + +async function fixture() { + // EOAs and environment + const [beneficiary, other] = await ethers.getSigners(); + const target = await ethers.deployContract('CallReceiverMock'); + + // ERC-4337 signer + const signer = new NonNativeSigner({ sign: hash => ({ serialized: hash }) }); + + // ERC-4337 account + const helper = new ERC4337Helper(); + const mock = await helper.newAccount('$AccountMock', ['Account', '1']); + + // ERC-4337 Entrypoint domain + const entrypointDomain = await getDomain(entrypoint.v08); + + // domain cannot be fetched using getDomain(mock) before the mock is deployed + const domain = { name: 'Account', version: '1', chainId: entrypointDomain.chainId, verifyingContract: mock.address }; + + const signUserOp = async userOp => + signer + .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) + .then(signature => Object.assign(userOp, { signature })); + + return { helper, mock, domain, signer, target, beneficiary, other, signUserOp }; +} + +describe('Account', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC1271({ erc7739: true }); + shouldBehaveLikeERC7821(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountECDSA.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountECDSA.test.js new file mode 100644 index 0000000..e6bf27a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountECDSA.test.js @@ -0,0 +1,52 @@ +const { ethers, entrypoint } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain } = require('../helpers/eip712'); +const { ERC4337Helper } = require('../helpers/erc4337'); +const { PackedUserOperation } = require('../helpers/eip712-types'); + +const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); +const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); +const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); + +async function fixture() { + // EOAs and environment + const [beneficiary, other] = await ethers.getSigners(); + const target = await ethers.deployContract('CallReceiverMock'); + + // ERC-4337 signer + const signer = ethers.Wallet.createRandom(); + + // ERC-4337 account + const helper = new ERC4337Helper(); + const mock = await helper.newAccount('$AccountECDSAMock', [signer, 'AccountECDSA', '1']); + + // ERC-4337 Entrypoint domain + const entrypointDomain = await getDomain(entrypoint.v08); + + // domain cannot be fetched using getDomain(mock) before the mock is deployed + const domain = { + name: 'AccountECDSA', + version: '1', + chainId: entrypointDomain.chainId, + verifyingContract: mock.address, + }; + + const signUserOp = userOp => + signer + .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) + .then(signature => Object.assign(userOp, { signature })); + + return { helper, mock, domain, signer, target, beneficiary, other, signUserOp }; +} + +describe('AccountECDSA', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC1271({ erc7739: true }); + shouldBehaveLikeERC7821(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.t.sol new file mode 100644 index 0000000..f08193f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.t.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {AccountERC7702Mock} from "@openzeppelin/contracts/mocks/account/AccountMock.sol"; +import {CallReceiverMock} from "@openzeppelin/contracts/mocks/CallReceiverMock.sol"; +import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; +import {ERC7579Utils, Execution, Mode, ModeSelector, ModePayload} from "@openzeppelin/contracts/account/utils/draft-ERC7579Utils.sol"; +import {ERC4337Utils, IEntryPointExtra} from "@openzeppelin/contracts/account/utils/draft-ERC4337Utils.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; +import {PackedUserOperation} from "@openzeppelin/contracts/interfaces/draft-IERC4337.sol"; +import {ERC7821} from "@openzeppelin/contracts/account/extensions/draft-ERC7821.sol"; + +contract AccountERC7702MockConstructor is AccountERC7702Mock { + constructor() EIP712("MyAccount", "1") {} +} + +contract AccountERC7702Test is Test { + using ERC7579Utils for *; + using ERC4337Utils for PackedUserOperation; + using Strings for *; + + uint256 private constant MAX_ETH = type(uint128).max; + + // Test accounts + CallReceiverMock private _target; + + // ERC-4337 signer + uint256 private _signerPrivateKey; + AccountERC7702MockConstructor private _signer; + + function setUp() public { + // Deploy target contract + _target = new CallReceiverMock(); + + // Setup signer + _signerPrivateKey = 0x1234; + _signer = AccountERC7702MockConstructor(payable(vm.addr(_signerPrivateKey))); + vm.deal(address(_signer), MAX_ETH); + + // Sign and attach delegation + vm.signAndAttachDelegation(address(new AccountERC7702MockConstructor()), _signerPrivateKey); + + // Setup entrypoint + vm.deal(address(ERC4337Utils.ENTRYPOINT_V08), MAX_ETH); + vm.etch(address(ERC4337Utils.ENTRYPOINT_V08), vm.readFileBinary("test/bin/EntryPoint070.bytecode")); + } + + function testExecuteBatch(uint256 argA, uint256 argB) public { + // Create the mode for batch execution + Mode mode = ERC7579Utils.CALLTYPE_BATCH.encodeMode( + ERC7579Utils.EXECTYPE_DEFAULT, + ModeSelector.wrap(0x00000000), + ModePayload.wrap(0x00000000) + ); + + Execution[] memory execution = new Execution[](2); + execution[0] = Execution({ + target: address(_target), + value: 1 ether, + callData: abi.encodeCall(CallReceiverMock.mockFunctionExtra, ()) + }); + execution[1] = Execution({ + target: address(_target), + value: 0, + callData: abi.encodeCall(CallReceiverMock.mockFunctionWithArgs, (argA, argB)) + }); + + // Pack the batch within a PackedUserOperation + PackedUserOperation[] memory ops = new PackedUserOperation[](1); + ops[0] = PackedUserOperation({ + sender: address(_signer), + nonce: 0, + initCode: bytes(""), + callData: abi.encodeCall(ERC7821.execute, (Mode.unwrap(mode), execution.encodeBatch())), + preVerificationGas: 100000, + accountGasLimits: bytes32(abi.encodePacked(uint128(100000), uint128(100000))), + gasFees: bytes32(abi.encodePacked(uint128(1000000), uint128(1000000))), + paymasterAndData: bytes(""), + signature: bytes("") + }); + (uint8 v, bytes32 r, bytes32 s) = vm.sign( + _signerPrivateKey, + IEntryPointExtra(address(ERC4337Utils.ENTRYPOINT_V08)).getUserOpHash(ops[0]) + ); + ops[0].signature = abi.encodePacked(r, s, v); + + // Expect the events to be emitted + vm.expectEmit(true, true, true, true); + emit CallReceiverMock.MockFunctionCalledExtra(address(_signer), 1 ether); + vm.expectEmit(true, true, true, true); + emit CallReceiverMock.MockFunctionCalledWithArgs(argA, argB); + + // Execute the batch + _signer.entryPoint().handleOps(ops, payable(makeAddr("beneficiary"))); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.test.js new file mode 100644 index 0000000..d08a522 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.test.js @@ -0,0 +1,52 @@ +const { ethers, entrypoint } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain } = require('../helpers/eip712'); +const { ERC4337Helper } = require('../helpers/erc4337'); +const { PackedUserOperation } = require('../helpers/eip712-types'); + +const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); +const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); +const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); + +async function fixture() { + // EOAs and environment + const [beneficiary, other] = await ethers.getSigners(); + const target = await ethers.deployContract('CallReceiverMock'); + + // ERC-4337 signer + const signer = ethers.Wallet.createRandom(ethers.provider); + + // ERC-4337 account + const helper = new ERC4337Helper(); + const mock = await helper.newAccount('$AccountERC7702Mock', ['AccountERC7702Mock', '1'], { erc7702signer: signer }); + + // ERC-4337 Entrypoint domain + const entrypointDomain = await getDomain(entrypoint.v08); + + // domain cannot be fetched using getDomain(mock) before the mock is deployed + const domain = { + name: 'AccountERC7702Mock', + version: '1', + chainId: entrypointDomain.chainId, + verifyingContract: mock.address, + }; + + const signUserOp = userOp => + signer + .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) + .then(signature => Object.assign(userOp, { signature })); + + return { helper, mock, domain, signer, target, beneficiary, other, signUserOp }; +} + +describe('AccountERC7702', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC1271({ erc7739: true }); + shouldBehaveLikeERC7821({ deployable: false }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7913.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7913.test.js new file mode 100644 index 0000000..297a5eb --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7913.test.js @@ -0,0 +1,116 @@ +const { ethers, entrypoint } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain } = require('../helpers/eip712'); +const { ERC4337Helper } = require('../helpers/erc4337'); +const { NonNativeSigner, P256SigningKey, RSASHA256SigningKey } = require('../helpers/signers'); +const { PackedUserOperation } = require('../helpers/eip712-types'); + +const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); +const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); +const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); + +// Prepare signer in advance (RSA are long to initialize) +const signerECDSA = ethers.Wallet.createRandom(); +const signerP256 = new NonNativeSigner(P256SigningKey.random()); +const signerRSA = new NonNativeSigner(RSASHA256SigningKey.random()); + +// Minimal fixture common to the different signer verifiers +async function fixture() { + // EOAs and environment + const [beneficiary, other] = await ethers.getSigners(); + const target = await ethers.deployContract('CallReceiverMock'); + + // ERC-7913 verifiers + const verifierP256 = await ethers.deployContract('ERC7913P256Verifier'); + const verifierRSA = await ethers.deployContract('ERC7913RSAVerifier'); + + // ERC-4337 env + const helper = new ERC4337Helper(); + await helper.wait(); + const entrypointDomain = await getDomain(entrypoint.v08); + const domain = { name: 'AccountERC7913', version: '1', chainId: entrypointDomain.chainId }; // Missing verifyingContract, + + const makeMock = signer => + helper.newAccount('$AccountERC7913Mock', [signer, 'AccountERC7913', '1']).then(mock => { + domain.verifyingContract = mock.address; + return mock; + }); + + const signUserOp = function (userOp) { + return this.signer + .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) + .then(signature => Object.assign(userOp, { signature })); + }; + + return { + helper, + verifierP256, + verifierRSA, + domain, + target, + beneficiary, + other, + makeMock, + signUserOp, + }; +} + +describe('AccountERC7913', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + // Using ECDSA key as verifier + describe('ECDSA key', function () { + beforeEach(async function () { + this.signer = signerECDSA; + this.mock = await this.makeMock(this.signer.address); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC1271({ erc7739: true }); + shouldBehaveLikeERC7821(); + }); + + // Using P256 key with an ERC-7913 verifier + describe('P256 key', function () { + beforeEach(async function () { + this.signer = signerP256; + this.mock = await this.makeMock( + ethers.concat([ + this.verifierP256.target, + this.signer.signingKey.publicKey.qx, + this.signer.signingKey.publicKey.qy, + ]), + ); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC1271({ erc7739: true }); + shouldBehaveLikeERC7821(); + }); + + // Using RSA key with an ERC-7913 verifier + describe('RSA key', function () { + beforeEach(async function () { + this.signer = signerRSA; + this.mock = await this.makeMock( + ethers.concat([ + this.verifierRSA.target, + ethers.AbiCoder.defaultAbiCoder().encode( + ['bytes', 'bytes'], + [this.signer.signingKey.publicKey.e, this.signer.signingKey.publicKey.n], + ), + ]), + ); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC1271({ erc7739: true }); + shouldBehaveLikeERC7821(); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSigner.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSigner.test.js new file mode 100644 index 0000000..78011a3 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSigner.test.js @@ -0,0 +1,326 @@ +const { ethers, entrypoint } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain } = require('../helpers/eip712'); +const { ERC4337Helper } = require('../helpers/erc4337'); +const { NonNativeSigner, P256SigningKey, RSASHA256SigningKey, MultiERC7913SigningKey } = require('../helpers/signers'); +const { MAX_UINT64 } = require('../helpers/constants'); + +const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); +const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); +const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); +const { PackedUserOperation } = require('../helpers/eip712-types'); + +// Prepare signers in advance (RSA are long to initialize) +const signerECDSA1 = ethers.Wallet.createRandom(); +const signerECDSA2 = ethers.Wallet.createRandom(); +const signerECDSA3 = ethers.Wallet.createRandom(); +const signerECDSA4 = ethers.Wallet.createRandom(); // Unauthorized signer +const signerP256 = new NonNativeSigner(P256SigningKey.random()); +const signerRSA = new NonNativeSigner(RSASHA256SigningKey.random()); + +// Minimal fixture common to the different signer verifiers +async function fixture() { + // EOAs and environment + const [beneficiary, other] = await ethers.getSigners(); + const target = await ethers.deployContract('CallReceiverMock'); + + // ERC-7913 verifiers + const verifierP256 = await ethers.deployContract('ERC7913P256Verifier'); + const verifierRSA = await ethers.deployContract('ERC7913RSAVerifier'); + + // ERC-4337 env + const helper = new ERC4337Helper(); + await helper.wait(); + const entrypointDomain = await getDomain(entrypoint.v08); + const domain = { name: 'AccountMultiSigner', version: '1', chainId: entrypointDomain.chainId }; // Missing verifyingContract + + const makeMock = (signers, threshold) => + helper.newAccount('$AccountMultiSignerMock', [signers, threshold, 'AccountMultiSigner', '1']).then(mock => { + domain.verifyingContract = mock.address; + return mock; + }); + + // Sign user operations using MultiERC7913SigningKey + const signUserOp = function (userOp) { + return this.signer + .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) + .then(signature => Object.assign(userOp, { signature })); + }; + + const invalidSig = function () { + return this.signer.signMessage('invalid'); + }; + + return { + helper, + verifierP256, + verifierRSA, + domain, + target, + beneficiary, + other, + makeMock, + signUserOp, + invalidSig, + }; +} + +describe('AccountMultiSigner', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('Multi ECDSA signers with threshold=1', function () { + beforeEach(async function () { + this.signer = new NonNativeSigner(new MultiERC7913SigningKey([signerECDSA1])); + this.mock = await this.makeMock([signerECDSA1.address], 1); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC1271({ erc7739: true }); + shouldBehaveLikeERC7821(); + }); + + describe('Multi ECDSA signers with threshold=2', function () { + beforeEach(async function () { + this.signer = new NonNativeSigner(new MultiERC7913SigningKey([signerECDSA1, signerECDSA2])); + this.mock = await this.makeMock([signerECDSA1.address, signerECDSA2.address], 2); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC1271({ erc7739: true }); + shouldBehaveLikeERC7821(); + }); + + describe('Mixed signers with threshold=2', function () { + beforeEach(async function () { + // Create signers array with all three types + signerP256.bytes = ethers.concat([ + this.verifierP256.target, + signerP256.signingKey.publicKey.qx, + signerP256.signingKey.publicKey.qy, + ]); + + signerRSA.bytes = ethers.concat([ + this.verifierRSA.target, + ethers.AbiCoder.defaultAbiCoder().encode( + ['bytes', 'bytes'], + [signerRSA.signingKey.publicKey.e, signerRSA.signingKey.publicKey.n], + ), + ]); + + this.signer = new NonNativeSigner(new MultiERC7913SigningKey([signerECDSA1, signerP256, signerRSA])); + this.mock = await this.makeMock([signerECDSA1.address, signerP256.bytes, signerRSA.bytes], 2); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC1271({ erc7739: true }); + shouldBehaveLikeERC7821(); + }); + + describe('Signer management', function () { + beforeEach(async function () { + this.signer = new NonNativeSigner(new MultiERC7913SigningKey([signerECDSA1, signerECDSA2])); + this.mock = await this.makeMock([signerECDSA1.address, signerECDSA2.address], 1); + await this.mock.deploy(); + }); + + it('can add signers', async function () { + const signers = [signerECDSA3.address]; + + // Successfully adds a signer + const signersArrayBefore = await this.mock.getSigners(0, MAX_UINT64).then(s => s.map(ethers.getAddress)); + await expect(this.mock.$_addSigners(signers)) + .to.emit(this.mock, 'ERC7913SignerAdded') + .withArgs(signerECDSA3.address); + const signersArrayAfter = await this.mock.getSigners(0, MAX_UINT64).then(s => s.map(ethers.getAddress)); + expect(signersArrayAfter.length).to.equal(signersArrayBefore.length + 1); + expect(signersArrayAfter).to.include(ethers.getAddress(signerECDSA3.address)); + + // Reverts if the signer was already added + await expect(this.mock.$_addSigners(signers)) + .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913AlreadyExists') + .withArgs(...signers.map(s => s.toLowerCase())); + }); + + it('can remove signers', async function () { + const signers = [signerECDSA2.address]; + + // Successfully removes an already added signer + const signersArrayBefore = await this.mock.getSigners(0, MAX_UINT64).then(s => s.map(ethers.getAddress)); + await expect(this.mock.$_removeSigners(signers)) + .to.emit(this.mock, 'ERC7913SignerRemoved') + .withArgs(signerECDSA2.address); + const signersArrayAfter = await this.mock.getSigners(0, MAX_UINT64).then(s => s.map(ethers.getAddress)); + expect(signersArrayAfter.length).to.equal(signersArrayBefore.length - 1); + expect(signersArrayAfter).to.not.include(ethers.getAddress(signerECDSA2.address)); + + // Reverts removing a signer if it doesn't exist + await expect(this.mock.$_removeSigners(signers)) + .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913NonexistentSigner') + .withArgs(...signers.map(s => s.toLowerCase())); + + // Reverts if removing a signer makes the threshold unreachable + await expect(this.mock.$_removeSigners([signerECDSA1.address])) + .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913UnreachableThreshold') + .withArgs(0, 1); + }); + + it('can change threshold', async function () { + // Reachable threshold is set + await expect(this.mock.$_setThreshold(2)).to.emit(this.mock, 'ERC7913ThresholdSet'); + + // Unreachable threshold reverts + await expect(this.mock.$_setThreshold(3)) + .to.revertedWithCustomError(this.mock, 'MultiSignerERC7913UnreachableThreshold') + .withArgs(2, 3); + + // Zero threshold reverts + await expect(this.mock.$_setThreshold(0)).to.revertedWithCustomError( + this.mock, + 'MultiSignerERC7913ZeroThreshold', + ); + }); + + it('rejects invalid signer format', async function () { + const invalidSigner = '0x123456'; // Too short + + await expect(this.mock.$_addSigners([invalidSigner])) + .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913InvalidSigner') + .withArgs(invalidSigner); + }); + + it('can read signers and threshold', async function () { + await expect( + this.mock.getSigners(0, MAX_UINT64).then(s => s.map(ethers.getAddress)), + ).to.eventually.have.deep.members([signerECDSA1.address, signerECDSA2.address]); + + await expect(this.mock.threshold()).to.eventually.equal(1); + }); + + it('checks if an address is a signer', async function () { + // Should return true for authorized signers + await expect(this.mock.isSigner(signerECDSA1.address)).to.eventually.be.true; + await expect(this.mock.isSigner(signerECDSA2.address)).to.eventually.be.true; + + // Should return false for unauthorized signers + await expect(this.mock.isSigner(signerECDSA3.address)).to.eventually.be.false; + await expect(this.mock.isSigner(signerECDSA4.address)).to.eventually.be.false; + }); + }); + + describe('Signature validation', function () { + const TEST_MESSAGE = ethers.keccak256(ethers.toUtf8Bytes('Test message')); + + beforeEach(async function () { + // Set up mock with authorized signers + this.mock = await this.makeMock([signerECDSA1.address, signerECDSA2.address], 1); + await this.mock.deploy(); + }); + + it('rejects signatures from unauthorized signers', async function () { + // Create signatures including an unauthorized signer + const authorizedSignature = await signerECDSA1.signMessage(ethers.getBytes(TEST_MESSAGE)); + const unauthorizedSignature = await signerECDSA4.signMessage(ethers.getBytes(TEST_MESSAGE)); + + // Prepare signers and signatures arrays + const signers = [ + signerECDSA1.address, + signerECDSA4.address, // Unauthorized signer + ].sort((a, b) => (ethers.toBigInt(ethers.keccak256(a)) < ethers.toBigInt(ethers.keccak256(b)) ? -1 : 1)); + + const signatures = signers.map(signer => { + if (signer === signerECDSA1.address) return authorizedSignature; + return unauthorizedSignature; + }); + + // Encode the multi-signature + const multiSignature = ethers.AbiCoder.defaultAbiCoder().encode(['bytes[]', 'bytes[]'], [signers, signatures]); + + // Should fail because one signer is not authorized + await expect(this.mock.$_rawSignatureValidation(TEST_MESSAGE, multiSignature)).to.eventually.be.false; + }); + + it('rejects invalid signatures from authorized signers', async function () { + // Create a valid signature and an invalid one from authorized signers + const validSignature = await signerECDSA1.signMessage(ethers.getBytes(TEST_MESSAGE)); + const invalidSignature = await signerECDSA2.signMessage(ethers.toUtf8Bytes('Different message')); // Wrong message + + // Prepare signers and signatures arrays + const signers = [signerECDSA1.address, signerECDSA2.address].sort((a, b) => + ethers.toBigInt(ethers.keccak256(a)) < ethers.toBigInt(ethers.keccak256(b)) ? -1 : 1, + ); + + const signatures = signers.map(signer => { + if (signer === signerECDSA1.address) return validSignature; + return invalidSignature; + }); + + // Encode the multi-signature + const multiSignature = ethers.AbiCoder.defaultAbiCoder().encode(['bytes[]', 'bytes[]'], [signers, signatures]); + + // Should fail because one signature is invalid + await expect(this.mock.$_rawSignatureValidation(TEST_MESSAGE, multiSignature)).to.eventually.be.false; + }); + + it('rejects signatures from unsorted signers', async function () { + // Create a valid signature and an invalid one from authorized signers + const validSignature1 = await signerECDSA1.signMessage(ethers.getBytes(TEST_MESSAGE)); + const validSignature2 = await signerECDSA2.signMessage(ethers.getBytes(TEST_MESSAGE)); + + // Prepare signers and signatures arrays + const signers = [signerECDSA1.address, signerECDSA2.address].sort((a, b) => + ethers.toBigInt(ethers.keccak256(a)) < ethers.toBigInt(ethers.keccak256(b)) ? -1 : 1, + ); + const unsortedSigners = signers.reverse(); + const signatures = unsortedSigners.map(signer => { + if (signer === signerECDSA1.address) return validSignature1; + return validSignature2; + }); + + // Encode the multi-signature + const multiSignature = ethers.AbiCoder.defaultAbiCoder().encode( + ['bytes[]', 'bytes[]'], + [unsortedSigners, signatures], + ); + + // Should fail because signers are not sorted + await expect(this.mock.$_rawSignatureValidation(TEST_MESSAGE, multiSignature)).to.eventually.be.false; + }); + + it('rejects signatures when signers.length != signatures.length', async function () { + // Create a valid signature and an invalid one from authorized signers + const validSignature1 = await signerECDSA1.signMessage(ethers.getBytes(TEST_MESSAGE)); + + // Prepare signers and signatures arrays + const signers = [signerECDSA1.address, signerECDSA2.address]; + const signatures = [validSignature1]; + + // Encode the multi-signature + const multiSignature = ethers.AbiCoder.defaultAbiCoder().encode(['bytes[]', 'bytes[]'], [signers, signatures]); + + // Should fail because signers and signatures arrays have different lengths + await expect(this.mock.$_rawSignatureValidation(TEST_MESSAGE, multiSignature)).to.eventually.be.false; + }); + + it('rejects duplicated signers', async function () { + // Create a valid signature + const validSignature = await signerECDSA1.signMessage(ethers.getBytes(TEST_MESSAGE)); + + // Prepare signers and signatures arrays + const signers = [signerECDSA1.address, signerECDSA1.address]; + const signatures = [validSignature, validSignature]; + + // Encode the multi-signature + const multiSignature = ethers.AbiCoder.defaultAbiCoder().encode(['bytes[]', 'bytes[]'], [signers, signatures]); + + // Should fail because of duplicated signers + await expect(this.mock.$_rawSignatureValidation(TEST_MESSAGE, multiSignature)).to.eventually.be.false; + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSignerWeighted.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSignerWeighted.test.js new file mode 100644 index 0000000..5519d8a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSignerWeighted.test.js @@ -0,0 +1,312 @@ +const { ethers, entrypoint } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain } = require('../helpers/eip712'); +const { ERC4337Helper } = require('../helpers/erc4337'); +const { NonNativeSigner, P256SigningKey, RSASHA256SigningKey, MultiERC7913SigningKey } = require('../helpers/signers'); +const { PackedUserOperation } = require('../helpers/eip712-types'); +const { MAX_UINT64 } = require('../helpers/constants'); + +const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); +const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); +const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); + +// Prepare signers in advance (RSA are long to initialize) +const signerECDSA1 = ethers.Wallet.createRandom(); +const signerECDSA2 = ethers.Wallet.createRandom(); +const signerECDSA3 = ethers.Wallet.createRandom(); +const signerECDSA4 = ethers.Wallet.createRandom(); +const signerP256 = new NonNativeSigner(P256SigningKey.random()); +const signerRSA = new NonNativeSigner(RSASHA256SigningKey.random()); + +// Minimal fixture common to the different signer verifiers +async function fixture() { + // EOAs and environment + const [beneficiary, other] = await ethers.getSigners(); + const target = await ethers.deployContract('CallReceiverMock'); + + // ERC-7913 verifiers + const verifierP256 = await ethers.deployContract('ERC7913P256Verifier'); + const verifierRSA = await ethers.deployContract('ERC7913RSAVerifier'); + + // ERC-4337 env + const helper = new ERC4337Helper(); + await helper.wait(); + const entrypointDomain = await getDomain(entrypoint.v08); + const domain = { name: 'AccountMultiSignerWeighted', version: '1', chainId: entrypointDomain.chainId }; // Missing verifyingContract + + const makeMock = (signers, weights, threshold) => + helper + .newAccount('$AccountMultiSignerWeightedMock', [signers, weights, threshold, 'AccountMultiSignerWeighted', '1']) + .then(mock => { + domain.verifyingContract = mock.address; + return mock; + }); + + // Sign user operations using NonNativeSigner with MultiERC7913SigningKey + const signUserOp = function (userOp) { + return this.signer + .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) + .then(signature => Object.assign(userOp, { signature })); + }; + + const invalidSig = function () { + return this.signer.signMessage('invalid'); + }; + + return { + helper, + verifierP256, + verifierRSA, + domain, + target, + beneficiary, + other, + makeMock, + signUserOp, + invalidSig, + }; +} + +describe('AccountMultiSignerWeighted', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('Weighted signers with equal weights (1, 1, 1) and threshold=2', function () { + beforeEach(async function () { + this.signer = new NonNativeSigner(new MultiERC7913SigningKey([signerECDSA1, signerECDSA3])); // 2 accounts, weight 1+1=2 + this.mock = await this.makeMock([signerECDSA1.address, signerECDSA2.address, signerECDSA3.address], [1, 1, 1], 2); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC1271({ erc7739: true }); + shouldBehaveLikeERC7821(); + }); + + describe('Weighted signers with varying weights (1, 2, 3) and threshold=3', function () { + beforeEach(async function () { + this.signer = new NonNativeSigner(new MultiERC7913SigningKey([signerECDSA1, signerECDSA2])); // 2 accounts, weight 1+2=3 + this.mock = await this.makeMock([signerECDSA1.address, signerECDSA2.address, signerECDSA3.address], [1, 2, 3], 3); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC1271({ erc7739: true }); + shouldBehaveLikeERC7821(); + }); + + describe('Mixed weighted signers with threshold=4', function () { + beforeEach(async function () { + // Create signers array with all three types + signerP256.bytes = ethers.concat([ + this.verifierP256.target, + signerP256.signingKey.publicKey.qx, + signerP256.signingKey.publicKey.qy, + ]); + + signerRSA.bytes = ethers.concat([ + this.verifierRSA.target, + ethers.AbiCoder.defaultAbiCoder().encode( + ['bytes', 'bytes'], + [signerRSA.signingKey.publicKey.e, signerRSA.signingKey.publicKey.n], + ), + ]); + + this.signer = new NonNativeSigner(new MultiERC7913SigningKey([signerP256, signerRSA])); // 2 accounts, weight 2+3=5 + this.mock = await this.makeMock( + [signerECDSA1.address, signerP256.bytes, signerRSA.bytes], + [1, 2, 3], + 4, // Requires at least signer2 + signer3, or all three signers + ); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC1271({ erc7739: true }); + shouldBehaveLikeERC7821(); + }); + + describe('Weight management', function () { + const signer1 = signerECDSA1.address; + const signer2 = signerECDSA2.address; + const signer3 = signerECDSA3.address; + const signer4 = signerECDSA4.address; + + beforeEach(async function () { + this.mock = await this.makeMock([signer1, signer2, signer3], [1, 2, 3], 4); + await this.mock.deploy(); + }); + + it('can get signer weights', async function () { + await expect(this.mock.signerWeight(signer1)).to.eventually.equal(1); + await expect(this.mock.signerWeight(signer2)).to.eventually.equal(2); + await expect(this.mock.signerWeight(signer3)).to.eventually.equal(3); + }); + + it('can update signer weights', async function () { + // Successfully updates weights and emits event + await expect(this.mock.$_setSignerWeights([signer1, signer2], [5, 6])) + .to.emit(this.mock, 'ERC7913SignerWeightChanged') + .withArgs(signer1, 5) + .to.emit(this.mock, 'ERC7913SignerWeightChanged') + .withArgs(signer2, 6); + + await expect(this.mock.signerWeight(signer1)).to.eventually.equal(5); + await expect(this.mock.signerWeight(signer2)).to.eventually.equal(6); + await expect(this.mock.signerWeight(signer3)).to.eventually.equal(3); // unchanged + }); + + it("no-op doesn't emit an event", async function () { + await expect(this.mock.$_setSignerWeights([signer1], [1])).to.not.emit(this.mock, 'ERC7913SignerWeightChanged'); + }); + + it('cannot set weight to non-existent signer', async function () { + // Reverts when setting weight for non-existent signer + await expect(this.mock.$_setSignerWeights([signer4], [1])) + .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913NonexistentSigner') + .withArgs(signer4.toLowerCase()); + }); + + it('cannot set weight to 0', async function () { + // Reverts when setting weight to 0 + await expect(this.mock.$_setSignerWeights([signer1], [0])) + .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913WeightedInvalidWeight') + .withArgs(signer1.toLowerCase(), 0); + }); + + it('requires signers and weights arrays to have same length', async function () { + // Reverts when arrays have different lengths + await expect(this.mock.$_setSignerWeights([signer1, signer2], [1])).to.be.revertedWithCustomError( + this.mock, + 'MultiSignerERC7913WeightedMismatchedLength', + ); + + await expect(this.mock.$_setSignerWeights([signer1], [1, 2])).to.be.revertedWithCustomError( + this.mock, + 'MultiSignerERC7913WeightedMismatchedLength', + ); + }); + + it('validates threshold is reachable when updating weights', async function () { + // First, lower the weights so the sum is exactly 9 (just enough for threshold=9) + await expect(this.mock.$_setSignerWeights([signer1, signer2, signer3], [2, 3, 4])) + .to.emit(this.mock, 'ERC7913SignerWeightChanged') + .withArgs(signer1, 2) + .to.emit(this.mock, 'ERC7913SignerWeightChanged') + .withArgs(signer2, 3) + .to.emit(this.mock, 'ERC7913SignerWeightChanged') + .withArgs(signer3, 4); + + // Increase threshold to 9 + await expect(this.mock.$_setThreshold(9)).to.emit(this.mock, 'ERC7913ThresholdSet').withArgs(9); + + // Now try to lower weights so their sum is less than the threshold + await expect(this.mock.$_setSignerWeights([signer1, signer2, signer3], [2, 2, 2])).to.be.revertedWithCustomError( + this.mock, + 'MultiSignerERC7913UnreachableThreshold', + ); + + // Try to increase threshold to be larger than the total weight + await expect(this.mock.$_setThreshold(10)) + .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913UnreachableThreshold') + .withArgs(9, 10); + }); + + it('reports default weight of 1 for signers without explicit weight', async function () { + // Add a new signer without setting weight + await this.mock.$_addSigners([signer4]); + + // Should have default weight of 1 + await expect(this.mock.signerWeight(signer4)).to.eventually.equal(1); + }); + + it('reports weight of 0 for invalid signers', async function () { + // not authorized + await expect(this.mock.signerWeight(signer4)).to.eventually.equal(0); + }); + + it('can get total weight of all signers', async function () { + await expect(this.mock.totalWeight()).to.eventually.equal(6); // 1+2+3=6 + }); + + it('totalWeight returns correct value when all signers have default weight of 1', async function () { + // Deploy a new mock with all signers having default weight (1) + const signers = [signerECDSA1.address, signerECDSA2.address, signerECDSA3.address]; + const defaultWeights = [1, 1, 1]; // All weights are 1 (default) + const newMock = await this.makeMock(signers, defaultWeights, 2); + await newMock.deploy(); + + // totalWeight should return max(3, 3) = 3 when all weights are default + await expect(newMock.totalWeight()).to.eventually.equal(3); + + // Clear custom weights to ensure we're using default weights + await newMock.$_setSignerWeights(signers, [1, 1, 1]); + + // totalWeight should still be max(3, 3) = 3 + await expect(newMock.totalWeight()).to.eventually.equal(3); + }); + + it('_setSignerWeights correctly handles default weights when updating', async function () { + await expect(this.mock.totalWeight()).to.eventually.equal(6); // 1+2+3=6 + + // Set weight for signer1 from 1 (default) to 5 + await this.mock.$_setSignerWeights([signer1], [5]); + await expect(this.mock.totalWeight()).to.eventually.equal(10); // 5+2+3=10 + + // Reset signer1 to default weight (1) + await this.mock.$_setSignerWeights([signer1], [1]); + await expect(this.mock.totalWeight()).to.eventually.equal(6); // 1+2+3=6 + }); + + it('updates total weight when adding and removing signers', async function () { + await expect(this.mock.totalWeight()).to.eventually.equal(6); // 1+2+3=6 + + // Add a new signer - should increase total weight by default weight (1) + await this.mock.$_addSigners([signer4]); + await expect(this.mock.totalWeight()).to.eventually.equal(7); // 1+2+3+1=7 + + // Set weight to 5 - should increase total weight by 4 + await this.mock.$_setSignerWeights([signer4], [5]); + await expect(this.mock.totalWeight()).to.eventually.equal(11); // 1+2+3+5=11 + + // Remove signer - should decrease total weight by current weight (5) + await this.mock.$_removeSigners([signer4]); + await expect(this.mock.totalWeight()).to.eventually.equal(6); // 1+2+3=6 + }); + + it('removing signers should not make threshold unreachable', async function () { + // current threshold = 4, totalWeight = 1+2+3 = 6 + + // After removing signer3, the threshold is unreachable because totalWeight = 1+2 = 3 but threshold = 4 + // [reverts] + await expect(this.mock.$_removeSigners([signer3])) + .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913UnreachableThreshold') + .withArgs(3, 4); + + // After removing signer1, the threshold is still reachable because totalWeight = 2+3 = 5 and threshold = 4 + // [does not revert] + await expect(this.mock.$_removeSigners([signer1])) + .to.emit(this.mock, 'ERC7913SignerRemoved') + .withArgs(signer1) + .to.not.emit(this.mock, 'ERC7913SignerWeightChanged'); + }); + + it('should revert if total weight to overflow (_setSignerWeights)', async function () { + await expect(this.mock.$_setSignerWeights([signer1, signer2, signer3], [1n, 1n, MAX_UINT64 - 1n])) + .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintDowncast') + .withArgs(64, MAX_UINT64 + 1n); + }); + + it('should revert if total weight to overflow (_addSigner)', async function () { + await this.mock.$_setSignerWeights([signer1, signer2, signer3], [1n, 1n, MAX_UINT64 - 2n]); + await expect(this.mock.totalWeight()).to.eventually.equal(MAX_UINT64); + + await expect(this.mock.$_addSigners([signer4])) + .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintDowncast') + .withArgs(64, MAX_UINT64 + 1n); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountP256.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountP256.test.js new file mode 100644 index 0000000..33aadbb --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountP256.test.js @@ -0,0 +1,58 @@ +const { ethers, entrypoint } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain } = require('../helpers/eip712'); +const { ERC4337Helper } = require('../helpers/erc4337'); +const { NonNativeSigner, P256SigningKey } = require('../helpers/signers'); +const { PackedUserOperation } = require('../helpers/eip712-types'); + +const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); +const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); +const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); + +async function fixture() { + // EOAs and environment + const [beneficiary, other] = await ethers.getSigners(); + const target = await ethers.deployContract('CallReceiverMock'); + + // ERC-4337 signer + const signer = new NonNativeSigner(P256SigningKey.random()); + + // ERC-4337 account + const helper = new ERC4337Helper(); + const mock = await helper.newAccount('$AccountP256Mock', [ + signer.signingKey.publicKey.qx, + signer.signingKey.publicKey.qy, + 'AccountP256', + '1', + ]); + + // ERC-4337 Entrypoint domain + const entrypointDomain = await getDomain(entrypoint.v08); + + // domain cannot be fetched using getDomain(mock) before the mock is deployed + const domain = { + name: 'AccountP256', + version: '1', + chainId: entrypointDomain.chainId, + verifyingContract: mock.address, + }; + + const signUserOp = userOp => + signer + .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) + .then(signature => Object.assign(userOp, { signature })); + + return { helper, mock, domain, signer, target, beneficiary, other, signUserOp }; +} + +describe('AccountP256', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC1271({ erc7739: true }); + shouldBehaveLikeERC7821(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountRSA.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountRSA.test.js new file mode 100644 index 0000000..707469f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountRSA.test.js @@ -0,0 +1,58 @@ +const { ethers, entrypoint } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain } = require('../helpers/eip712'); +const { ERC4337Helper } = require('../helpers/erc4337'); +const { NonNativeSigner, RSASHA256SigningKey } = require('../helpers/signers'); +const { PackedUserOperation } = require('../helpers/eip712-types'); + +const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); +const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); +const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); + +async function fixture() { + // EOAs and environment + const [beneficiary, other] = await ethers.getSigners(); + const target = await ethers.deployContract('CallReceiverMock'); + + // ERC-4337 signer + const signer = new NonNativeSigner(RSASHA256SigningKey.random()); + + // ERC-4337 account + const helper = new ERC4337Helper(); + const mock = await helper.newAccount('$AccountRSAMock', [ + signer.signingKey.publicKey.e, + signer.signingKey.publicKey.n, + 'AccountRSA', + '1', + ]); + + // ERC-4337 Entrypoint domain + const entrypointDomain = await getDomain(entrypoint.v08); + + // domain cannot be fetched using getDomain(mock) before the mock is deployed + const domain = { + name: 'AccountRSA', + version: '1', + chainId: entrypointDomain.chainId, + verifyingContract: mock.address, + }; + + const signUserOp = userOp => + signer + .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) + .then(signature => Object.assign(userOp, { signature })); + + return { helper, mock, domain, signer, target, beneficiary, other, signUserOp }; +} + +describe('AccountRSA', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC1271({ erc7739: true }); + shouldBehaveLikeERC7821(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/examples/AccountERC7702WithModulesMock.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/examples/AccountERC7702WithModulesMock.test.js new file mode 100644 index 0000000..9ee5f91 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/examples/AccountERC7702WithModulesMock.test.js @@ -0,0 +1,99 @@ +const { ethers, entrypoint } = require('hardhat'); +const { loadFixture, setBalance } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain } = require('../../helpers/eip712'); +const { ERC4337Helper } = require('../../helpers/erc4337'); +const { PackedUserOperation } = require('../../helpers/eip712-types'); + +const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('../Account.behavior'); +const { shouldBehaveLikeAccountERC7579 } = require('../extensions/AccountERC7579.behavior'); +const { shouldBehaveLikeERC1271 } = require('../../utils/cryptography/ERC1271.behavior'); +const { shouldBehaveLikeERC7821 } = require('../extensions/ERC7821.behavior'); + +const { MODULE_TYPE_VALIDATOR } = require('../../helpers/erc7579'); + +async function fixture() { + // EOAs and environment + const [beneficiary, other] = await ethers.getSigners(); + const target = await ethers.deployContract('CallReceiverMock'); + const anotherTarget = await ethers.deployContract('CallReceiverMock'); + + // Signer with EIP-7702 support + funding + const eoa = ethers.Wallet.createRandom(ethers.provider); + await setBalance(eoa.address, ethers.WeiPerEther); + + // ERC-7579 validator module + const validator = await ethers.deployContract('$ERC7579ValidatorMock'); + + // ERC-4337 account + const helper = new ERC4337Helper(); + const mock = await helper.newAccount('$AccountERC7702WithModulesMock', ['AccountERC7702WithModulesMock', '1'], { + erc7702signer: eoa, + }); + + // ERC-4337 Entrypoint domain + const entrypointDomain = await getDomain(entrypoint.v08); + + // domain cannot be fetched using getDomain(mock) before the mock is deployed + const domain = { + name: 'AccountERC7702WithModulesMock', + version: '1', + chainId: entrypointDomain.chainId, + verifyingContract: mock.address, + }; + + return { helper, validator, mock, domain, entrypointDomain, eoa, target, anotherTarget, beneficiary, other }; +} + +describe('AccountERC7702WithModules: ERC-7702 account with ERC-7579 modules supports', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('using ERC-7702 signer', function () { + beforeEach(async function () { + this.signer = this.eoa; + this.signUserOp = userOp => + this.signer + .signTypedData(this.entrypointDomain, { PackedUserOperation }, userOp.packed) + .then(signature => Object.assign(userOp, { signature })); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeERC7821({ deployable: false }); + shouldBehaveLikeERC1271({ erc7739: true }); + }); + + describe('using ERC-7579 validator', function () { + beforeEach(async function () { + // signer that adds a prefix to all signatures (except the userOp ones) + this.signer = ethers.Wallet.createRandom(); + this.signer.signMessage = message => + ethers.Wallet.prototype.signMessage + .bind(this.signer)(message) + .then(sign => ethers.concat([this.validator.target, sign])); + this.signer.signTypedData = (domain, types, values) => + ethers.Wallet.prototype.signTypedData + .bind(this.signer)(domain, types, values) + .then(sign => ethers.concat([this.validator.target, sign])); + + this.signUserOp = userOp => + ethers.Wallet.prototype.signTypedData + .bind(this.signer)(this.entrypointDomain, { PackedUserOperation }, userOp.packed) + .then(signature => Object.assign(userOp, { signature })); + + // Use the first 20 bytes from the nonce key (24 bytes) to identify the validator module + this.userOp = { nonce: ethers.zeroPadBytes(ethers.hexlify(this.validator.target), 32) }; + + // Deploy (using ERC-7702) and add the validator module using EOA + await this.mock.deploy(); + await this.mock.connect(this.eoa).installModule(MODULE_TYPE_VALIDATOR, this.validator, this.signer.address); + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountHolder(); + shouldBehaveLikeAccountERC7579(); + shouldBehaveLikeERC1271({ erc7739: false }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.behavior.js new file mode 100644 index 0000000..1b702fc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.behavior.js @@ -0,0 +1,563 @@ +const { ethers, entrypoint } = require('hardhat'); +const { expect } = require('chai'); +const { impersonate } = require('../../helpers/account'); +const { selector } = require('../../helpers/methods'); +const { zip } = require('../../helpers/iterate'); +const { + encodeMode, + encodeBatch, + encodeSingle, + encodeDelegate, + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK, + MODULE_TYPE_HOOK, + CALL_TYPE_CALL, + CALL_TYPE_BATCH, + CALL_TYPE_DELEGATE, + EXEC_TYPE_DEFAULT, + EXEC_TYPE_TRY, +} = require('../../helpers/erc7579'); + +const CALL_TYPE_INVALID = '0x42'; +const EXEC_TYPE_INVALID = '0x17'; +const MODULE_TYPE_INVALID = 999n; + +const coder = ethers.AbiCoder.defaultAbiCoder(); + +function shouldBehaveLikeAccountERC7579({ withHooks = false } = {}) { + describe('AccountERC7579', function () { + beforeEach(async function () { + await this.mock.deploy(); + await this.other.sendTransaction({ to: this.mock.target, value: ethers.parseEther('1') }); + + this.modules = {}; + this.modules[MODULE_TYPE_VALIDATOR] = await ethers.deployContract('$ERC7579ModuleMock', [MODULE_TYPE_VALIDATOR]); + this.modules[MODULE_TYPE_EXECUTOR] = await ethers.deployContract('$ERC7579ModuleMock', [MODULE_TYPE_EXECUTOR]); + this.modules[MODULE_TYPE_FALLBACK] = await ethers.deployContract('$ERC7579ModuleMock', [MODULE_TYPE_FALLBACK]); + this.modules[MODULE_TYPE_HOOK] = await ethers.deployContract('$ERC7579HookMock'); + + this.mockFromEntrypoint = this.mock.connect(await impersonate(entrypoint.v08.target)); + this.mockFromExecutor = this.mock.connect(await impersonate(this.modules[MODULE_TYPE_EXECUTOR].target)); + }); + + describe('accountId', function () { + it('should return the account ID', async function () { + await expect(this.mock.accountId()).to.eventually.equal( + withHooks + ? '@openzeppelin/community-contracts.AccountERC7579Hooked.v0.0.0' + : '@openzeppelin/community-contracts.AccountERC7579.v0.0.0', + ); + }); + }); + + describe('supportsExecutionMode', function () { + for (const [callType, execType] of zip( + [CALL_TYPE_CALL, CALL_TYPE_BATCH, CALL_TYPE_DELEGATE, CALL_TYPE_INVALID], + [EXEC_TYPE_DEFAULT, EXEC_TYPE_TRY, EXEC_TYPE_INVALID], + )) { + const result = callType != CALL_TYPE_INVALID && execType != EXEC_TYPE_INVALID; + + it(`${ + result ? 'does not support' : 'supports' + } CALL_TYPE=${callType} and EXEC_TYPE=${execType} execution mode`, async function () { + await expect(this.mock.supportsExecutionMode(encodeMode({ callType, execType }))).to.eventually.equal(result); + }); + } + }); + + describe('supportsModule', function () { + it('supports MODULE_TYPE_VALIDATOR module type', async function () { + await expect(this.mock.supportsModule(MODULE_TYPE_VALIDATOR)).to.eventually.equal(true); + }); + + it('supports MODULE_TYPE_EXECUTOR module type', async function () { + await expect(this.mock.supportsModule(MODULE_TYPE_EXECUTOR)).to.eventually.equal(true); + }); + + it('supports MODULE_TYPE_FALLBACK module type', async function () { + await expect(this.mock.supportsModule(MODULE_TYPE_FALLBACK)).to.eventually.equal(true); + }); + + it( + withHooks ? 'supports MODULE_TYPE_HOOK module type' : 'does not support MODULE_TYPE_HOOK module type', + async function () { + await expect(this.mock.supportsModule(MODULE_TYPE_HOOK)).to.eventually.equal(withHooks); + }, + ); + + it('does not support invalid module type', async function () { + await expect(this.mock.supportsModule(MODULE_TYPE_INVALID)).to.eventually.equal(false); + }); + }); + + describe('module installation', function () { + it('should revert if the caller is not the canonical entrypoint or the account itself', async function () { + await expect(this.mock.connect(this.other).installModule(MODULE_TYPE_VALIDATOR, this.mock, '0x')) + .to.be.revertedWithCustomError(this.mock, 'AccountUnauthorized') + .withArgs(this.other); + }); + + it('should revert if the module type is not supported', async function () { + await expect(this.mockFromEntrypoint.installModule(MODULE_TYPE_INVALID, this.mock, '0x')) + .to.be.revertedWithCustomError(this.mock, 'ERC7579UnsupportedModuleType') + .withArgs(MODULE_TYPE_INVALID); + }); + + it('should revert if the module is not the provided type', async function () { + const instance = this.modules[MODULE_TYPE_EXECUTOR]; + await expect(this.mockFromEntrypoint.installModule(MODULE_TYPE_VALIDATOR, instance, '0x')) + .to.be.revertedWithCustomError(this.mock, 'ERC7579MismatchedModuleTypeId') + .withArgs(MODULE_TYPE_VALIDATOR, instance); + }); + + for (const moduleTypeId of [ + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK, + withHooks && MODULE_TYPE_HOOK, + ].filter(Boolean)) { + const prefix = moduleTypeId == MODULE_TYPE_FALLBACK ? '0x12345678' : '0x'; + const initData = ethers.hexlify(ethers.randomBytes(256)); + const fullData = ethers.concat([prefix, initData]); + + it(`should install a module of type ${moduleTypeId}`, async function () { + const instance = this.modules[moduleTypeId]; + + await expect(this.mock.isModuleInstalled(moduleTypeId, instance, fullData)).to.eventually.equal(false); + + await expect(this.mockFromEntrypoint.installModule(moduleTypeId, instance, fullData)) + .to.emit(this.mock, 'ModuleInstalled') + .withArgs(moduleTypeId, instance) + .to.emit(instance, 'ModuleInstalledReceived') + .withArgs(this.mock, initData); // After decoding MODULE_TYPE_FALLBACK, it should remove the fnSig + + await expect(this.mock.isModuleInstalled(moduleTypeId, instance, fullData)).to.eventually.equal(true); + }); + + it(`does not allow to install a module of ${moduleTypeId} id twice`, async function () { + const instance = this.modules[moduleTypeId]; + + await this.mockFromEntrypoint.installModule(moduleTypeId, instance, fullData); + + await expect(this.mock.isModuleInstalled(moduleTypeId, instance, fullData)).to.eventually.equal(true); + + await expect(this.mockFromEntrypoint.installModule(moduleTypeId, instance, fullData)) + .to.be.revertedWithCustomError( + this.mock, + moduleTypeId == MODULE_TYPE_HOOK ? 'ERC7579HookModuleAlreadyPresent' : 'ERC7579AlreadyInstalledModule', + ) + .withArgs(...[moduleTypeId != MODULE_TYPE_HOOK && moduleTypeId, instance].filter(Boolean)); + }); + } + + withHooks && + describe('with hook', function () { + beforeEach(async function () { + await this.mockFromEntrypoint.$_installModule(MODULE_TYPE_HOOK, this.modules[MODULE_TYPE_HOOK], '0x'); + }); + + it('should call the hook of the installed module when performing an module install', async function () { + const instance = this.modules[MODULE_TYPE_EXECUTOR]; + const initData = ethers.hexlify(ethers.randomBytes(256)); + + const precheckData = this.mock.interface.encodeFunctionData('installModule', [ + MODULE_TYPE_EXECUTOR, + instance.target, + initData, + ]); + + await expect(this.mockFromEntrypoint.installModule(MODULE_TYPE_EXECUTOR, instance, initData)) + .to.emit(this.modules[MODULE_TYPE_HOOK], 'PreCheck') + .withArgs(entrypoint.v08, 0n, precheckData) + .to.emit(this.modules[MODULE_TYPE_HOOK], 'PostCheck') + .withArgs(precheckData); + }); + }); + }); + + describe('module uninstallation', function () { + it('should revert if the caller is not the canonical entrypoint or the account itself', async function () { + await expect(this.mock.connect(this.other).uninstallModule(MODULE_TYPE_VALIDATOR, this.mock, '0x')) + .to.be.revertedWithCustomError(this.mock, 'AccountUnauthorized') + .withArgs(this.other); + }); + + it('should revert if the module type is not supported', async function () { + await expect(this.mockFromEntrypoint.uninstallModule(MODULE_TYPE_INVALID, this.mock, '0x')) + .to.be.revertedWithCustomError(this.mock, 'ERC7579UnsupportedModuleType') + .withArgs(MODULE_TYPE_INVALID); + }); + + for (const moduleTypeId of [ + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK, + withHooks && MODULE_TYPE_HOOK, + ].filter(Boolean)) { + const prefix = moduleTypeId == MODULE_TYPE_FALLBACK ? '0x12345678' : '0x'; + const initData = ethers.hexlify(ethers.randomBytes(256)); + const fullData = ethers.concat([prefix, initData]); + + it(`should uninstall a module of type ${moduleTypeId}`, async function () { + const instance = this.modules[moduleTypeId]; + + await this.mock.$_installModule(moduleTypeId, instance, fullData); + + await expect(this.mock.isModuleInstalled(moduleTypeId, instance, fullData)).to.eventually.equal(true); + + await expect(this.mockFromEntrypoint.uninstallModule(moduleTypeId, instance, fullData)) + .to.emit(this.mock, 'ModuleUninstalled') + .withArgs(moduleTypeId, instance) + .to.emit(instance, 'ModuleUninstalledReceived') + .withArgs(this.mock, initData); // After decoding MODULE_TYPE_FALLBACK, it should remove the fnSig + + await expect(this.mock.isModuleInstalled(moduleTypeId, instance, fullData)).to.eventually.equal(false); + }); + + it(`should revert uninstalling a module of type ${moduleTypeId} if it was not installed`, async function () { + const instance = this.modules[moduleTypeId]; + + await expect(this.mockFromEntrypoint.uninstallModule(moduleTypeId, instance, fullData)) + .to.be.revertedWithCustomError(this.mock, 'ERC7579UninstalledModule') + .withArgs(moduleTypeId, instance); + }); + } + + it('should revert uninstalling a module of type MODULE_TYPE_FALLBACK if a different module was installed for the provided selector', async function () { + const instance = this.modules[MODULE_TYPE_FALLBACK]; + const anotherInstance = await ethers.deployContract('$ERC7579ModuleMock', [MODULE_TYPE_FALLBACK]); + const initData = '0x12345678abcdef'; + + await this.mockFromEntrypoint.$_installModule(MODULE_TYPE_FALLBACK, instance, initData); + await expect(this.mockFromEntrypoint.uninstallModule(MODULE_TYPE_FALLBACK, anotherInstance, initData)) + .to.be.revertedWithCustomError(this.mock, 'ERC7579UninstalledModule') + .withArgs(MODULE_TYPE_FALLBACK, anotherInstance); + }); + + withHooks && + describe('with hook', function () { + beforeEach(async function () { + await this.mockFromEntrypoint.$_installModule(MODULE_TYPE_HOOK, this.modules[MODULE_TYPE_HOOK], '0x'); + }); + + it('should call the hook of the installed module when performing a module uninstall', async function () { + const instance = this.modules[MODULE_TYPE_EXECUTOR]; + const initData = ethers.hexlify(ethers.randomBytes(256)); + + const precheckData = this.mock.interface.encodeFunctionData('uninstallModule', [ + MODULE_TYPE_EXECUTOR, + instance.target, + initData, + ]); + + await this.mock.$_installModule(MODULE_TYPE_EXECUTOR, instance, initData); + await expect(this.mockFromEntrypoint.uninstallModule(MODULE_TYPE_EXECUTOR, instance, initData)) + .to.emit(this.modules[MODULE_TYPE_HOOK], 'PreCheck') + .withArgs(entrypoint.v08, 0n, precheckData) + .to.emit(this.modules[MODULE_TYPE_HOOK], 'PostCheck') + .withArgs(precheckData); + }); + }); + }); + + describe('execution', function () { + beforeEach(async function () { + await this.mock.$_installModule(MODULE_TYPE_EXECUTOR, this.modules[MODULE_TYPE_EXECUTOR], '0x'); + }); + + for (const [execFn, mock] of [ + ['execute', 'mockFromEntrypoint'], + ['executeFromExecutor', 'mockFromExecutor'], + ]) { + describe(`executing with ${execFn}`, function () { + it('should revert if the call type is not supported', async function () { + await expect( + this[mock][execFn](encodeMode({ callType: CALL_TYPE_INVALID }), encodeSingle(this.other, 0, '0x')), + ) + .to.be.revertedWithCustomError(this.mock, 'ERC7579UnsupportedCallType') + .withArgs(ethers.solidityPacked(['bytes1'], [CALL_TYPE_INVALID])); + }); + + it('should revert if the caller is not authorized / installed', async function () { + const error = execFn == 'execute' ? 'AccountUnauthorized' : 'ERC7579UninstalledModule'; + const args = execFn == 'execute' ? [this.other] : [MODULE_TYPE_EXECUTOR, this.other]; + + await expect( + this[mock] + .connect(this.other) + [execFn](encodeMode({ callType: CALL_TYPE_CALL }), encodeSingle(this.other, 0, '0x')), + ) + .to.be.revertedWithCustomError(this.mock, error) + .withArgs(...args); + }); + + describe('single execution', function () { + it('calls the target with value and args', async function () { + const value = 0x432; + const data = encodeSingle( + this.target, + value, + this.target.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234']), + ); + + const tx = this[mock][execFn](encodeMode({ callType: CALL_TYPE_CALL }), data); + + await expect(tx).to.emit(this.target, 'MockFunctionCalledWithArgs').withArgs(42, '0x1234'); + await expect(tx).to.changeEtherBalances([this.mock, this.target], [-value, value]); + }); + + it('reverts when target reverts in default ExecType', async function () { + const value = 0x012; + const data = encodeSingle( + this.target, + value, + this.target.interface.encodeFunctionData('mockFunctionRevertsReason'), + ); + + await expect(this[mock][execFn](encodeMode({ callType: CALL_TYPE_CALL }), data)).to.be.revertedWith( + 'CallReceiverMock: reverting', + ); + }); + + it('emits ERC7579TryExecuteFail event when target reverts in try ExecType', async function () { + const value = 0x012; + const data = encodeSingle( + this.target, + value, + this.target.interface.encodeFunctionData('mockFunctionRevertsReason'), + ); + + await expect(this[mock][execFn](encodeMode({ callType: CALL_TYPE_CALL, execType: EXEC_TYPE_TRY }), data)) + .to.emit(this.mock, 'ERC7579TryExecuteFail') + .withArgs( + CALL_TYPE_CALL, + ethers.solidityPacked( + ['bytes4', 'bytes'], + [selector('Error(string)'), coder.encode(['string'], ['CallReceiverMock: reverting'])], + ), + ); + }); + }); + + describe('batch execution', function () { + it('calls the targets with value and args', async function () { + const value1 = 0x012; + const value2 = 0x234; + const data = encodeBatch( + [this.target, value1, this.target.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234'])], + [ + this.anotherTarget, + value2, + this.anotherTarget.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234']), + ], + ); + + const tx = this[mock][execFn](encodeMode({ callType: CALL_TYPE_BATCH }), data); + await expect(tx) + .to.emit(this.target, 'MockFunctionCalledWithArgs') + .to.emit(this.anotherTarget, 'MockFunctionCalledWithArgs'); + await expect(tx).to.changeEtherBalances( + [this.mock, this.target, this.anotherTarget], + [-value1 - value2, value1, value2], + ); + }); + + it('reverts when any target reverts in default ExecType', async function () { + const value1 = 0x012; + const value2 = 0x234; + const data = encodeBatch( + [this.target, value1, this.target.interface.encodeFunctionData('mockFunction')], + [ + this.anotherTarget, + value2, + this.anotherTarget.interface.encodeFunctionData('mockFunctionRevertsReason'), + ], + ); + + await expect(this[mock][execFn](encodeMode({ callType: CALL_TYPE_BATCH }), data)).to.be.revertedWith( + 'CallReceiverMock: reverting', + ); + }); + + it('emits ERC7579TryExecuteFail event when any target reverts in try ExecType', async function () { + const value1 = 0x012; + const value2 = 0x234; + const data = encodeBatch( + [this.target, value1, this.target.interface.encodeFunctionData('mockFunction')], + [ + this.anotherTarget, + value2, + this.anotherTarget.interface.encodeFunctionData('mockFunctionRevertsReason'), + ], + ); + + const tx = this[mock][execFn](encodeMode({ callType: CALL_TYPE_BATCH, execType: EXEC_TYPE_TRY }), data); + + await expect(tx) + .to.emit(this.mock, 'ERC7579TryExecuteFail') + .withArgs( + CALL_TYPE_BATCH, + ethers.solidityPacked( + ['bytes4', 'bytes'], + [selector('Error(string)'), coder.encode(['string'], ['CallReceiverMock: reverting'])], + ), + ); + + await expect(tx).to.changeEtherBalances( + [this.mock, this.target, this.anotherTarget], + [-value1, value1, 0], + ); + }); + }); + + describe('delegate call execution', function () { + it('delegate calls the target', async function () { + const slot = ethers.hexlify(ethers.randomBytes(32)); + const value = ethers.hexlify(ethers.randomBytes(32)); + const data = encodeDelegate( + this.target, + this.target.interface.encodeFunctionData('mockFunctionWritesStorage', [slot, value]), + ); + + await expect(ethers.provider.getStorage(this.mock.target, slot)).to.eventually.equal(ethers.ZeroHash); + await this[mock][execFn](encodeMode({ callType: CALL_TYPE_DELEGATE }), data); + await expect(ethers.provider.getStorage(this.mock.target, slot)).to.eventually.equal(value); + }); + + it('reverts when target reverts in default ExecType', async function () { + const data = encodeDelegate( + this.target, + this.target.interface.encodeFunctionData('mockFunctionRevertsReason'), + ); + await expect(this[mock][execFn](encodeMode({ callType: CALL_TYPE_DELEGATE }), data)).to.be.revertedWith( + 'CallReceiverMock: reverting', + ); + }); + + it('emits ERC7579TryExecuteFail event when target reverts in try ExecType', async function () { + const data = encodeDelegate( + this.target, + this.target.interface.encodeFunctionData('mockFunctionRevertsReason'), + ); + await expect( + this[mock][execFn](encodeMode({ callType: CALL_TYPE_DELEGATE, execType: EXEC_TYPE_TRY }), data), + ) + .to.emit(this.mock, 'ERC7579TryExecuteFail') + .withArgs( + CALL_TYPE_CALL, + ethers.solidityPacked( + ['bytes4', 'bytes'], + [selector('Error(string)'), coder.encode(['string'], ['CallReceiverMock: reverting'])], + ), + ); + }); + }); + + withHooks && + describe('with hook', function () { + beforeEach(async function () { + await this.mockFromEntrypoint.$_installModule(MODULE_TYPE_HOOK, this.modules[MODULE_TYPE_HOOK], '0x'); + }); + + it(`should call the hook of the installed module when executing ${execFn}`, async function () { + const caller = execFn === 'execute' ? entrypoint.v08 : this.modules[MODULE_TYPE_EXECUTOR]; + const value = 17; + const data = this.target.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234']); + + const mode = encodeMode({ callType: CALL_TYPE_CALL }); + const call = encodeSingle(this.target, value, data); + const precheckData = this[mock].interface.encodeFunctionData(execFn, [mode, call]); + + const tx = this[mock][execFn](mode, call, { value }); + + await expect(tx) + .to.emit(this.modules[MODULE_TYPE_HOOK], 'PreCheck') + .withArgs(caller, value, precheckData) + .to.emit(this.modules[MODULE_TYPE_HOOK], 'PostCheck') + .withArgs(precheckData); + await expect(tx).to.changeEtherBalances([caller, this.mock, this.target], [-value, 0n, value]); + }); + }); + }); + } + }); + + describe('fallback', function () { + beforeEach(async function () { + this.fallbackHandler = await ethers.deployContract('$ERC7579FallbackHandlerMock'); + }); + + it('reverts if there is no fallback module installed', async function () { + const { selector } = this.fallbackHandler.callPayable.getFragment(); + + await expect(this.fallbackHandler.attach(this.mock).callPayable()) + .to.be.revertedWithCustomError(this.mock, 'ERC7579MissingFallbackHandler') + .withArgs(selector); + }); + + describe('with a fallback module installed', function () { + beforeEach(async function () { + await Promise.all( + [ + this.fallbackHandler.callPayable.getFragment().selector, + this.fallbackHandler.callView.getFragment().selector, + this.fallbackHandler.callRevert.getFragment().selector, + ].map(selector => + this.mock.$_installModule( + MODULE_TYPE_FALLBACK, + this.fallbackHandler, + coder.encode(['bytes4', 'bytes'], [selector, '0x']), + ), + ), + ); + }); + + it('forwards the call to the fallback handler', async function () { + const calldata = this.fallbackHandler.interface.encodeFunctionData('callPayable'); + const value = 17n; + + await expect(this.fallbackHandler.attach(this.mock).connect(this.other).callPayable({ value })) + .to.emit(this.fallbackHandler, 'ERC7579FallbackHandlerMockCalled') + .withArgs(this.mock, this.other, value, calldata); + }); + + it('returns answer from the fallback handler', async function () { + await expect(this.fallbackHandler.attach(this.mock).connect(this.other).callView()).to.eventually.deep.equal([ + this.mock.target, + this.other.address, + ]); + }); + + it('bubble up reverts from the fallback handler', async function () { + await expect( + this.fallbackHandler.attach(this.mock).connect(this.other).callRevert(), + ).to.be.revertedWithCustomError(this.fallbackHandler, 'ERC7579FallbackHandlerMockRevert'); + }); + + withHooks && + describe('with hook', function () { + beforeEach(async function () { + await this.mockFromEntrypoint.$_installModule(MODULE_TYPE_HOOK, this.modules[MODULE_TYPE_HOOK], '0x'); + }); + + it('should call the hook of the installed module when performing a callback', async function () { + const precheckData = this.fallbackHandler.interface.encodeFunctionData('callPayable'); + const value = 17n; + + // call with interface: decode returned data + await expect(this.fallbackHandler.attach(this.mock).connect(this.other).callPayable({ value })) + .to.emit(this.modules[MODULE_TYPE_HOOK], 'PreCheck') + .withArgs(this.other, value, precheckData) + .to.emit(this.modules[MODULE_TYPE_HOOK], 'PostCheck') + .withArgs(precheckData); + }); + }); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeAccountERC7579, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.test.js new file mode 100644 index 0000000..7903c91 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.test.js @@ -0,0 +1,60 @@ +const { ethers, entrypoint } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain } = require('../../helpers/eip712'); +const { ERC4337Helper } = require('../../helpers/erc4337'); +const { PackedUserOperation } = require('../../helpers/eip712-types'); + +const { shouldBehaveLikeAccountCore } = require('../Account.behavior'); +const { shouldBehaveLikeAccountERC7579 } = require('./AccountERC7579.behavior'); +const { shouldBehaveLikeERC1271 } = require('../../utils/cryptography/ERC1271.behavior'); + +async function fixture() { + // EOAs and environment + const [other] = await ethers.getSigners(); + const target = await ethers.deployContract('CallReceiverMock'); + const anotherTarget = await ethers.deployContract('CallReceiverMock'); + + // ERC-7579 validator + const validator = await ethers.deployContract('$ERC7579ValidatorMock'); + + // ERC-4337 signer + const signer = ethers.Wallet.createRandom(); + + // ERC-4337 account + const helper = new ERC4337Helper(); + const mock = await helper.newAccount('$AccountERC7579Mock', [ + validator, + ethers.solidityPacked(['address'], [signer.address]), + ]); + + // ERC-4337 Entrypoint domain + const entrypointDomain = await getDomain(entrypoint.v08); + + return { helper, validator, mock, entrypointDomain, signer, target, anotherTarget, other }; +} + +describe('AccountERC7579', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + + this.signer.signMessage = message => + ethers.Wallet.prototype.signMessage + .bind(this.signer)(message) + .then(sign => ethers.concat([this.validator.target, sign])); + this.signer.signTypedData = (domain, types, values) => + ethers.Wallet.prototype.signTypedData + .bind(this.signer)(domain, types, values) + .then(sign => ethers.concat([this.validator.target, sign])); + this.signUserOp = userOp => + ethers.Wallet.prototype.signTypedData + .bind(this.signer)(this.entrypointDomain, { PackedUserOperation }, userOp.packed) + .then(signature => Object.assign(userOp, { signature })); + + this.userOp = { nonce: ethers.zeroPadBytes(ethers.hexlify(this.validator.target), 32) }; + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountERC7579(); + shouldBehaveLikeERC1271(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579Hooked.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579Hooked.test.js new file mode 100644 index 0000000..6db8fe9 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579Hooked.test.js @@ -0,0 +1,60 @@ +const { ethers, entrypoint } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain } = require('../../helpers/eip712'); +const { ERC4337Helper } = require('../../helpers/erc4337'); +const { PackedUserOperation } = require('../../helpers/eip712-types'); + +const { shouldBehaveLikeAccountCore } = require('../Account.behavior'); +const { shouldBehaveLikeAccountERC7579 } = require('./AccountERC7579.behavior'); +const { shouldBehaveLikeERC1271 } = require('../../utils/cryptography/ERC1271.behavior'); + +async function fixture() { + // EOAs and environment + const [other] = await ethers.getSigners(); + const target = await ethers.deployContract('CallReceiverMock'); + const anotherTarget = await ethers.deployContract('CallReceiverMock'); + + // ERC-7579 validator + const validator = await ethers.deployContract('$ERC7579ValidatorMock'); + + // ERC-4337 signer + const signer = ethers.Wallet.createRandom(); + + // ERC-4337 account + const helper = new ERC4337Helper(); + const mock = await helper.newAccount('$AccountERC7579HookedMock', [ + validator, + ethers.solidityPacked(['address'], [signer.address]), + ]); + + // ERC-4337 Entrypoint domain + const entrypointDomain = await getDomain(entrypoint.v08); + + return { helper, validator, mock, entrypointDomain, signer, target, anotherTarget, other }; +} + +describe('AccountERC7579Hooked', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + + this.signer.signMessage = message => + ethers.Wallet.prototype.signMessage + .bind(this.signer)(message) + .then(sign => ethers.concat([this.validator.target, sign])); + this.signer.signTypedData = (domain, types, values) => + ethers.Wallet.prototype.signTypedData + .bind(this.signer)(domain, types, values) + .then(sign => ethers.concat([this.validator.target, sign])); + this.signUserOp = userOp => + ethers.Wallet.prototype.signTypedData + .bind(this.signer)(this.entrypointDomain, { PackedUserOperation }, userOp.packed) + .then(signature => Object.assign(userOp, { signature })); + + this.userOp = { nonce: ethers.zeroPadBytes(ethers.hexlify(this.validator.target), 32) }; + }); + + shouldBehaveLikeAccountCore(); + shouldBehaveLikeAccountERC7579({ withHooks: true }); + shouldBehaveLikeERC1271(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/ERC7821.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/ERC7821.behavior.js new file mode 100644 index 0000000..d6bff8b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/ERC7821.behavior.js @@ -0,0 +1,145 @@ +const { ethers, entrypoint } = require('hardhat'); +const { expect } = require('chai'); + +const { CALL_TYPE_BATCH, encodeMode, encodeBatch } = require('../../helpers/erc7579'); + +function shouldBehaveLikeERC7821({ deployable = true } = {}) { + describe('supports ERC-7821', function () { + beforeEach(async function () { + // give eth to the account (before deployment) + await this.other.sendTransaction({ to: this.mock.target, value: ethers.parseEther('1') }); + + // account is not initially deployed + await expect(ethers.provider.getCode(this.mock)).to.eventually.equal('0x'); + + this.encodeUserOpCalldata = (...calls) => + this.mock.interface.encodeFunctionData('execute', [ + encodeMode({ callType: CALL_TYPE_BATCH }), + encodeBatch(...calls), + ]); + }); + + it('should revert if the caller is not the canonical entrypoint or the account itself', async function () { + await this.mock.deploy(); + + await expect( + this.mock.connect(this.other).execute( + encodeMode({ callType: CALL_TYPE_BATCH }), + encodeBatch({ + target: this.target, + data: this.target.interface.encodeFunctionData('mockFunctionExtra'), + }), + ), + ) + .to.be.revertedWithCustomError(this.mock, 'AccountUnauthorized') + .withArgs(this.other); + }); + + if (deployable) { + describe('when not deployed', function () { + it('should be created with handleOps and increase nonce', async function () { + const operation = await this.mock + .createUserOp({ + callData: this.encodeUserOpCalldata({ + target: this.target, + value: 17, + data: this.target.interface.encodeFunctionData('mockFunctionExtra'), + }), + }) + .then(op => op.addInitCode()) + .then(op => this.signUserOp(op)); + + // Can't call the account to get its nonce before it's deployed + await expect(entrypoint.v08.getNonce(this.mock.target, 0)).to.eventually.equal(0); + await expect(entrypoint.v08.handleOps([operation.packed], this.beneficiary)) + .to.emit(entrypoint.v08, 'AccountDeployed') + .withArgs(operation.hash(), this.mock, this.helper.factory, ethers.ZeroAddress) + .to.emit(this.target, 'MockFunctionCalledExtra') + .withArgs(this.mock, 17); + await expect(this.mock.getNonce()).to.eventually.equal(1); + }); + + it('should revert if the signature is invalid', async function () { + const operation = await this.mock + .createUserOp({ + callData: this.encodeUserOpCalldata({ + target: this.target, + value: 17, + data: this.target.interface.encodeFunctionData('mockFunctionExtra'), + }), + }) + .then(op => op.addInitCode()); + + operation.signature = '0x00'; + + await expect(entrypoint.v08.handleOps([operation.packed], this.beneficiary)).to.be.reverted; + }); + }); + } + + describe('when deployed', function () { + beforeEach(async function () { + await this.mock.deploy(); + }); + + it('should increase nonce and call target', async function () { + const operation = await this.mock + .createUserOp({ + callData: this.encodeUserOpCalldata({ + target: this.target, + value: 42, + data: this.target.interface.encodeFunctionData('mockFunctionExtra'), + }), + }) + .then(op => this.signUserOp(op)); + + await expect(this.mock.getNonce()).to.eventually.equal(0); + await expect(entrypoint.v08.handleOps([operation.packed], this.beneficiary)) + .to.emit(this.target, 'MockFunctionCalledExtra') + .withArgs(this.mock, 42); + await expect(this.mock.getNonce()).to.eventually.equal(1); + }); + + it('should support sending eth to an EOA', async function () { + const operation = await this.mock + .createUserOp({ callData: this.encodeUserOpCalldata({ target: this.other, value: 42 }) }) + .then(op => this.signUserOp(op)); + + await expect(this.mock.getNonce()).to.eventually.equal(0); + await expect(entrypoint.v08.handleOps([operation.packed], this.beneficiary)).to.changeEtherBalance( + this.other, + 42, + ); + await expect(this.mock.getNonce()).to.eventually.equal(1); + }); + + it('should support batch execution', async function () { + const value1 = 43374337n; + const value2 = 69420n; + + const operation = await this.mock + .createUserOp({ + callData: this.encodeUserOpCalldata( + { target: this.other, value: value1 }, + { + target: this.target, + value: value2, + data: this.target.interface.encodeFunctionData('mockFunctionExtra'), + }, + ), + }) + .then(op => this.signUserOp(op)); + + await expect(this.mock.getNonce()).to.eventually.equal(0); + const tx = entrypoint.v08.handleOps([operation.packed], this.beneficiary); + await expect(tx).to.changeEtherBalances([this.other, this.target], [value1, value2]); + await expect(tx).to.emit(this.target, 'MockFunctionCalledExtra').withArgs(this.mock, value2); + await expect(this.mock.getNonce()).to.eventually.equal(1); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC7821, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/EIP7702Utils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/EIP7702Utils.test.js new file mode 100644 index 0000000..fb045f7 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/EIP7702Utils.test.js @@ -0,0 +1,53 @@ +const { ethers, config } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +// [NOTE] +// +// ethers.getSigners() returns object than cannot currently send type-4 transaction, or sign authorization. Therefore, +// we have to instantiate the eoa AND the relayer manually using ethers 6.14.0 wallets. This can be improved when +// @nomicfoundation/hardhat-ethers starts instantiating signers with 7702 support. +const relayAuthorization = authorization => + ethers.Wallet.fromPhrase(config.networks.hardhat.accounts.mnemonic, ethers.provider).sendTransaction({ + to: ethers.ZeroAddress, + authorizationList: [authorization], + gasLimit: 46_000n, + }); + +const fixture = async () => { + const eoa = ethers.Wallet.createRandom(ethers.provider); + const mock = await ethers.deployContract('$EIP7702Utils'); + return { eoa, mock }; +}; + +describe('EIP7702Utils', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('fetchDelegate', function () { + it('EOA without delegation', async function () { + await expect(this.mock.$fetchDelegate(this.eoa)).to.eventually.equal(ethers.ZeroAddress); + }); + + it('EOA with delegation', async function () { + // set delegation + await this.eoa.authorize({ address: this.mock }).then(relayAuthorization); + + await expect(this.mock.$fetchDelegate(this.eoa)).to.eventually.equal(this.mock); + }); + + it('EOA with revoked delegation', async function () { + // set delegation + await this.eoa.authorize({ address: this.mock }).then(relayAuthorization); + // reset delegation + await this.eoa.authorize({ address: ethers.ZeroAddress }).then(relayAuthorization); + + await expect(this.mock.$fetchDelegate(this.eoa)).to.eventually.equal(ethers.ZeroAddress); + }); + + it('other smart contract', async function () { + await expect(this.mock.$fetchDelegate(this.mock)).to.eventually.equal(ethers.ZeroAddress); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC4337Utils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC4337Utils.test.js new file mode 100644 index 0000000..ab4f345 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC4337Utils.test.js @@ -0,0 +1,289 @@ +const { ethers, entrypoint } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { packValidationData, UserOperation } = require('../../helpers/erc4337'); +const { MAX_UINT48 } = require('../../helpers/constants'); +const ADDRESS_ONE = '0x0000000000000000000000000000000000000001'; + +const fixture = async () => { + const [authorizer, sender, factory, paymaster] = await ethers.getSigners(); + const utils = await ethers.deployContract('$ERC4337Utils'); + const SIG_VALIDATION_SUCCESS = await utils.$SIG_VALIDATION_SUCCESS(); + const SIG_VALIDATION_FAILED = await utils.$SIG_VALIDATION_FAILED(); + + return { utils, authorizer, sender, factory, paymaster, SIG_VALIDATION_SUCCESS, SIG_VALIDATION_FAILED }; +}; + +describe('ERC4337Utils', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('entrypoint', function () { + it('v0.7.0', async function () { + await expect(this.utils.$ENTRYPOINT_V07()).to.eventually.equal(entrypoint.v07); + }); + + it('v0.8.0', async function () { + await expect(this.utils.$ENTRYPOINT_V08()).to.eventually.equal(entrypoint.v08); + }); + }); + + describe('parseValidationData', function () { + it('parses the validation data', async function () { + const authorizer = this.authorizer; + const validUntil = 0x12345678n; + const validAfter = 0x9abcdef0n; + const validationData = packValidationData(validAfter, validUntil, authorizer); + + await expect(this.utils.$parseValidationData(validationData)).to.eventually.deep.equal([ + authorizer.address, + validAfter, + validUntil, + ]); + }); + + it('returns an type(uint48).max if until is 0', async function () { + const authorizer = this.authorizer; + const validAfter = 0x12345678n; + const validationData = packValidationData(validAfter, 0, authorizer); + + await expect(this.utils.$parseValidationData(validationData)).to.eventually.deep.equal([ + authorizer.address, + validAfter, + MAX_UINT48, + ]); + }); + + it('parse canonical values', async function () { + await expect(this.utils.$parseValidationData(this.SIG_VALIDATION_SUCCESS)).to.eventually.deep.equal([ + ethers.ZeroAddress, + 0n, + MAX_UINT48, + ]); + + await expect(this.utils.$parseValidationData(this.SIG_VALIDATION_FAILED)).to.eventually.deep.equal([ + ADDRESS_ONE, + 0n, + MAX_UINT48, + ]); + }); + }); + + describe('packValidationData', function () { + it('packs the validation data', async function () { + const authorizer = this.authorizer; + const validUntil = 0x12345678n; + const validAfter = 0x9abcdef0n; + const validationData = packValidationData(validAfter, validUntil, authorizer); + + await expect( + this.utils.$packValidationData(ethers.Typed.address(authorizer), validAfter, validUntil), + ).to.eventually.equal(validationData); + }); + + it('packs the validation data (bool)', async function () { + const success = false; + const validUntil = 0x12345678n; + const validAfter = 0x9abcdef0n; + const validationData = packValidationData(validAfter, validUntil, false); + + await expect( + this.utils.$packValidationData(ethers.Typed.bool(success), validAfter, validUntil), + ).to.eventually.equal(validationData); + }); + + it('packing reproduced canonical values', async function () { + await expect( + this.utils.$packValidationData(ethers.Typed.address(ethers.ZeroAddress), 0n, 0n), + ).to.eventually.equal(this.SIG_VALIDATION_SUCCESS); + await expect(this.utils.$packValidationData(ethers.Typed.bool(true), 0n, 0n)).to.eventually.equal( + this.SIG_VALIDATION_SUCCESS, + ); + await expect(this.utils.$packValidationData(ethers.Typed.address(ADDRESS_ONE), 0n, 0n)).to.eventually.equal( + this.SIG_VALIDATION_FAILED, + ); + await expect(this.utils.$packValidationData(ethers.Typed.bool(false), 0n, 0n)).to.eventually.equal( + this.SIG_VALIDATION_FAILED, + ); + }); + }); + + describe('combineValidationData', function () { + const validUntil1 = 0x12345678n; + const validAfter1 = 0x9abcdef0n; + const validUntil2 = 0x87654321n; + const validAfter2 = 0xabcdef90n; + + it('combines the validation data', async function () { + const validationData1 = packValidationData(validAfter1, validUntil1, ethers.ZeroAddress); + const validationData2 = packValidationData(validAfter2, validUntil2, ethers.ZeroAddress); + const expected = packValidationData(validAfter2, validUntil1, true); + + // check symmetry + await expect(this.utils.$combineValidationData(validationData1, validationData2)).to.eventually.equal(expected); + await expect(this.utils.$combineValidationData(validationData2, validationData1)).to.eventually.equal(expected); + }); + + for (const [authorizer1, authorizer2] of [ + [ethers.ZeroAddress, '0xbf023313b891fd6000544b79e353323aa94a4f29'], + ['0xbf023313b891fd6000544b79e353323aa94a4f29', ethers.ZeroAddress], + ]) { + it('returns SIG_VALIDATION_FAILURE if one of the authorizers is not address(0)', async function () { + const validationData1 = packValidationData(validAfter1, validUntil1, authorizer1); + const validationData2 = packValidationData(validAfter2, validUntil2, authorizer2); + const expected = packValidationData(validAfter2, validUntil1, false); + + // check symmetry + await expect(this.utils.$combineValidationData(validationData1, validationData2)).to.eventually.equal(expected); + await expect(this.utils.$combineValidationData(validationData2, validationData1)).to.eventually.equal(expected); + }); + } + }); + + describe('getValidationData', function () { + it('returns the validation data with valid validity range', async function () { + const aggregator = this.authorizer; + const validAfter = 0; + const validUntil = MAX_UINT48; + const validationData = packValidationData(validAfter, validUntil, aggregator); + + await expect(this.utils.$getValidationData(validationData)).to.eventually.deep.equal([aggregator.address, false]); + }); + + it('returns the validation data with invalid validity range (expired)', async function () { + const aggregator = this.authorizer; + const validAfter = 0; + const validUntil = 1; + const validationData = packValidationData(validAfter, validUntil, aggregator); + + await expect(this.utils.$getValidationData(validationData)).to.eventually.deep.equal([aggregator.address, true]); + }); + + it('returns the validation data with invalid validity range (not yet valid)', async function () { + const aggregator = this.authorizer; + const validAfter = MAX_UINT48; + const validUntil = MAX_UINT48; + const validationData = packValidationData(validAfter, validUntil, aggregator); + + await expect(this.utils.$getValidationData(validationData)).to.eventually.deep.equal([aggregator.address, true]); + }); + + it('returns address(0) and false for validationData = 0', async function () { + await expect(this.utils.$getValidationData(0n)).to.eventually.deep.equal([ethers.ZeroAddress, false]); + }); + }); + + describe('hash', function () { + for (const [version, instance] of Object.entries(entrypoint)) { + it(`returns the operation hash for entrypoint ${version}`, async function () { + const userOp = new UserOperation({ sender: this.sender, nonce: 1 }); + const expected = await userOp.hash(instance); + + await expect(this.utils.$hash(userOp.packed, instance)).to.eventually.equal(expected); + }); + } + }); + + describe('userOp values', function () { + describe('intiCode', function () { + beforeEach(async function () { + this.userOp = new UserOperation({ + sender: this.sender, + nonce: 1, + verificationGas: 0x12345678n, + factory: this.factory, + factoryData: '0x123456', + }); + + this.emptyUserOp = new UserOperation({ + sender: this.sender, + nonce: 1, + }); + }); + + it('returns factory', async function () { + await expect(this.utils.$factory(this.userOp.packed)).to.eventually.equal(this.factory); + await expect(this.utils.$factory(this.emptyUserOp.packed)).to.eventually.equal(ethers.ZeroAddress); + }); + + it('returns factoryData', async function () { + await expect(this.utils.$factoryData(this.userOp.packed)).to.eventually.equal('0x123456'); + await expect(this.utils.$factoryData(this.emptyUserOp.packed)).to.eventually.equal('0x'); + }); + }); + + it('returns verificationGasLimit', async function () { + const userOp = new UserOperation({ sender: this.sender, nonce: 1, verificationGas: 0x12345678n }); + await expect(this.utils.$verificationGasLimit(userOp.packed)).to.eventually.equal(userOp.verificationGas); + }); + + it('returns callGasLimit', async function () { + const userOp = new UserOperation({ sender: this.sender, nonce: 1, callGas: 0x12345678n }); + await expect(this.utils.$callGasLimit(userOp.packed)).to.eventually.equal(userOp.callGas); + }); + + it('returns maxPriorityFeePerGas', async function () { + const userOp = new UserOperation({ sender: this.sender, nonce: 1, maxPriorityFee: 0x12345678n }); + await expect(this.utils.$maxPriorityFeePerGas(userOp.packed)).to.eventually.equal(userOp.maxPriorityFee); + }); + + it('returns maxFeePerGas', async function () { + const userOp = new UserOperation({ sender: this.sender, nonce: 1, maxFeePerGas: 0x12345678n }); + await expect(this.utils.$maxFeePerGas(userOp.packed)).to.eventually.equal(userOp.maxFeePerGas); + }); + + it('returns gasPrice', async function () { + const userOp = new UserOperation({ + sender: this.sender, + nonce: 1, + maxPriorityFee: 0x12345678n, + maxFeePerGas: 0x87654321n, + }); + await expect(this.utils.$gasPrice(userOp.packed)).to.eventually.equal(userOp.maxPriorityFee); + }); + + describe('paymasterAndData', function () { + beforeEach(async function () { + this.userOp = new UserOperation({ + sender: this.sender, + nonce: 1, + paymaster: this.paymaster, + paymasterVerificationGasLimit: 0x12345678n, + paymasterPostOpGasLimit: 0x87654321n, + paymasterData: '0xbeefcafe', + }); + + this.emptyUserOp = new UserOperation({ + sender: this.sender, + nonce: 1, + }); + }); + + it('returns paymaster', async function () { + await expect(this.utils.$paymaster(this.userOp.packed)).to.eventually.equal(this.userOp.paymaster); + await expect(this.utils.$paymaster(this.emptyUserOp.packed)).to.eventually.equal(ethers.ZeroAddress); + }); + + it('returns verificationGasLimit', async function () { + await expect(this.utils.$paymasterVerificationGasLimit(this.userOp.packed)).to.eventually.equal( + this.userOp.paymasterVerificationGasLimit, + ); + await expect(this.utils.$paymasterVerificationGasLimit(this.emptyUserOp.packed)).to.eventually.equal(0n); + }); + + it('returns postOpGasLimit', async function () { + await expect(this.utils.$paymasterPostOpGasLimit(this.userOp.packed)).to.eventually.equal( + this.userOp.paymasterPostOpGasLimit, + ); + await expect(this.utils.$paymasterPostOpGasLimit(this.emptyUserOp.packed)).to.eventually.equal(0n); + }); + + it('returns data', async function () { + await expect(this.utils.$paymasterData(this.userOp.packed)).to.eventually.equal(this.userOp.paymasterData); + await expect(this.utils.$paymasterData(this.emptyUserOp.packed)).to.eventually.equal('0x'); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.t.sol new file mode 100644 index 0000000..bc69e4c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.t.sol @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +// Parts of this test file are adapted from Adam Egyed (@adamegyed) proof of concept available at: +// https://github.com/adamegyed/erc7579-execute-vulnerability/tree/4589a30ff139e143d6c57183ac62b5c029217a90 +// +// solhint-disable no-console + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; +import {PackedUserOperation, IAccount, IEntryPoint} from "@openzeppelin/contracts/interfaces/draft-IERC4337.sol"; +import {ERC4337Utils} from "@openzeppelin/contracts/account/utils/draft-ERC4337Utils.sol"; +import {ERC7579Utils, Mode, CallType, ExecType, ModeSelector, ModePayload, Execution} from "@openzeppelin/contracts/account/utils/draft-ERC7579Utils.sol"; +import {Test, Vm, console} from "forge-std/Test.sol"; + +contract SampleAccount is IAccount, Ownable { + using ECDSA for *; + using MessageHashUtils for *; + using ERC4337Utils for *; + using ERC7579Utils for *; + + event Log(bool duringValidation, Execution[] calls); + + error UnsupportedCallType(CallType callType); + + constructor(address initialOwner) Ownable(initialOwner) {} + + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash, + uint256 missingAccountFunds + ) external override returns (uint256 validationData) { + require(msg.sender == address(ERC4337Utils.ENTRYPOINT_V07), "only from EP"); + // Check signature + if (userOpHash.toEthSignedMessageHash().recover(userOp.signature) != owner()) { + revert OwnableUnauthorizedAccount(_msgSender()); + } + + // If this is an execute call with a batch operation, log the call details from the calldata + if (bytes4(userOp.callData[0x00:0x04]) == this.execute.selector) { + (CallType callType, , , ) = Mode.wrap(bytes32(userOp.callData[0x04:0x24])).decodeMode(); + + if (callType == ERC7579Utils.CALLTYPE_BATCH) { + // Remove the selector + bytes calldata params = userOp.callData[0x04:]; + + // Use the same vulnerable assignment technique here, but assert afterwards that the checks aren't + // broken here by comparing to the result of `abi.decode(...)`. + bytes calldata executionCalldata; + assembly ("memory-safe") { + let dataptr := add(params.offset, calldataload(add(params.offset, 0x20))) + executionCalldata.offset := add(dataptr, 32) + executionCalldata.length := calldataload(dataptr) + } + // Check that this decoding step is done correctly. + (, bytes memory executionCalldataMemory) = abi.decode(params, (bytes32, bytes)); + + require( + keccak256(executionCalldata) == keccak256(executionCalldataMemory), + "decoding during validation failed" + ); + // Now, we know that we have `bytes calldata executionCalldata` as would be decoded by the solidity + // builtin decoder for the `execute` function. + + // This is where the vulnerability from ExecutionLib results in a different result between validation + // and execution. + + emit Log(true, executionCalldata.decodeBatch()); + } + } + + if (missingAccountFunds > 0) { + (bool success, ) = payable(msg.sender).call{value: missingAccountFunds}(""); + success; // Silence warning. The entrypoint should validate the result. + } + + return ERC4337Utils.SIG_VALIDATION_SUCCESS; + } + + function execute(Mode mode, bytes calldata executionCalldata) external payable { + require(msg.sender == address(this) || msg.sender == address(ERC4337Utils.ENTRYPOINT_V07), "not auth"); + + (CallType callType, ExecType execType, , ) = mode.decodeMode(); + + // check if calltype is batch or single + if (callType == ERC7579Utils.CALLTYPE_SINGLE) { + executionCalldata.execSingle(execType); + } else if (callType == ERC7579Utils.CALLTYPE_BATCH) { + executionCalldata.execBatch(execType); + + emit Log(false, executionCalldata.decodeBatch()); + } else if (callType == ERC7579Utils.CALLTYPE_DELEGATECALL) { + executionCalldata.execDelegateCall(execType); + } else { + revert UnsupportedCallType(callType); + } + } +} + +contract ERC7579UtilsTest is Test { + using MessageHashUtils for *; + using ERC4337Utils for *; + using ERC7579Utils for *; + + address private _owner; + uint256 private _ownerKey; + address private _account; + address private _beneficiary; + address private _recipient1; + address private _recipient2; + + constructor() { + vm.etch(0x0000000071727De22E5E9d8BAf0edAc6f37da032, vm.readFileBinary("test/bin/EntryPoint070.bytecode")); + vm.etch(0xEFC2c1444eBCC4Db75e7613d20C6a62fF67A167C, vm.readFileBinary("test/bin/SenderCreator070.bytecode")); + + // signing key + (_owner, _ownerKey) = makeAddrAndKey("owner"); + + // ERC-4337 account + _account = address(new SampleAccount(_owner)); + vm.deal(_account, 1 ether); + + // other + _beneficiary = makeAddr("beneficiary"); + _recipient1 = makeAddr("recipient1"); + _recipient2 = makeAddr("recipient2"); + } + + function testExecuteBatchDecodeCorrectly() public { + Execution[] memory calls = new Execution[](2); + calls[0] = Execution({target: _recipient1, value: 1 wei, callData: ""}); + calls[1] = Execution({target: _recipient2, value: 1 wei, callData: ""}); + + PackedUserOperation[] memory userOps = new PackedUserOperation[](1); + userOps[0] = PackedUserOperation({ + sender: _account, + nonce: 0, + initCode: "", + callData: abi.encodeCall( + SampleAccount.execute, + ( + ERC7579Utils.encodeMode( + ERC7579Utils.CALLTYPE_BATCH, + ERC7579Utils.EXECTYPE_DEFAULT, + ModeSelector.wrap(0x00), + ModePayload.wrap(0x00) + ), + ERC7579Utils.encodeBatch(calls) + ) + ), + accountGasLimits: _packGas(500_000, 500_000), + preVerificationGas: 0, + gasFees: _packGas(1, 1), + paymasterAndData: "", + signature: "" + }); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign( + _ownerKey, + this.hashUserOperation(userOps[0]).toEthSignedMessageHash() + ); + userOps[0].signature = abi.encodePacked(r, s, v); + + vm.recordLogs(); + ERC4337Utils.ENTRYPOINT_V07.handleOps(userOps, payable(_beneficiary)); + + assertEq(_recipient1.balance, 1 wei); + assertEq(_recipient2.balance, 1 wei); + + _collectAndPrintLogs(false); + } + + function testExecuteBatchDecodeEmpty() public { + bytes memory fakeCalls = abi.encodePacked( + uint256(1), // Length of execution[] + uint256(0x20), // offset + uint256(uint160(_recipient1)), // target + uint256(1), // value: 1 wei + uint256(0x60), // offset of data + uint256(0) // length of + ); + + PackedUserOperation[] memory userOps = new PackedUserOperation[](1); + userOps[0] = PackedUserOperation({ + sender: _account, + nonce: 0, + initCode: "", + callData: abi.encodeCall( + SampleAccount.execute, + ( + ERC7579Utils.encodeMode( + ERC7579Utils.CALLTYPE_BATCH, + ERC7579Utils.EXECTYPE_DEFAULT, + ModeSelector.wrap(0x00), + ModePayload.wrap(0x00) + ), + abi.encodePacked( + uint256(0x70) // fake offset pointing to paymasterAndData + ) + ) + ), + accountGasLimits: _packGas(500_000, 500_000), + preVerificationGas: 0, + gasFees: _packGas(1, 1), + paymasterAndData: abi.encodePacked(address(0), fakeCalls), + signature: "" + }); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign( + _ownerKey, + this.hashUserOperation(userOps[0]).toEthSignedMessageHash() + ); + userOps[0].signature = abi.encodePacked(r, s, v); + + vm.expectRevert( + abi.encodeWithSelector( + IEntryPoint.FailedOpWithRevert.selector, + 0, + "AA23 reverted", + abi.encodeWithSelector(ERC7579Utils.ERC7579DecodingError.selector) + ) + ); + ERC4337Utils.ENTRYPOINT_V07.handleOps(userOps, payable(_beneficiary)); + + _collectAndPrintLogs(false); + } + + function testExecuteBatchDecodeDifferent() public { + bytes memory execCallData = abi.encodePacked( + uint256(0x20), // offset pointing to the next segment + uint256(5), // Length of execution[] + uint256(0), // offset of calls[0], and target (!!) + uint256(0x20), // offset of calls[1], and value (!!) + uint256(0), // offset of calls[2], and rel offset of data (!!) + uint256(0) // offset of calls[3]. + // There is one more to read by the array length, but it's not present here. This will be + // paymasterAndData.length during validation, pointing to an all-zero call. + // During execution, the offset will be 0, pointing to a call with value. + ); + + PackedUserOperation[] memory userOps = new PackedUserOperation[](1); + userOps[0] = PackedUserOperation({ + sender: _account, + nonce: 0, + initCode: "", + callData: abi.encodePacked( + SampleAccount.execute.selector, + ERC7579Utils.encodeMode( + ERC7579Utils.CALLTYPE_BATCH, + ERC7579Utils.EXECTYPE_DEFAULT, + ModeSelector.wrap(0x00), + ModePayload.wrap(0x00) + ), + uint256(0x5c), // offset pointing to the next segment + uint224(type(uint224).max), // Padding to align the `bytes` types + // type(uint256).max, // unknown padding + uint256(execCallData.length), // Length of the data + execCallData + ), + accountGasLimits: _packGas(500_000, 500_000), + preVerificationGas: 0, + gasFees: _packGas(1, 1), + paymasterAndData: abi.encodePacked(uint256(0), uint256(0)), // padding length to create an offset + signature: "" + }); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign( + _ownerKey, + this.hashUserOperation(userOps[0]).toEthSignedMessageHash() + ); + userOps[0].signature = abi.encodePacked(r, s, v); + + vm.expectRevert( + abi.encodeWithSelector( + IEntryPoint.FailedOpWithRevert.selector, + 0, + "AA23 reverted", + abi.encodeWithSelector(ERC7579Utils.ERC7579DecodingError.selector) + ) + ); + ERC4337Utils.ENTRYPOINT_V07.handleOps(userOps, payable(_beneficiary)); + + _collectAndPrintLogs(true); + } + + function testDecodeBatch() public { + // BAD: buffer empty + vm.expectRevert(ERC7579Utils.ERC7579DecodingError.selector); + this.callDecodeBatch(""); + + // BAD: buffer too short + vm.expectRevert(ERC7579Utils.ERC7579DecodingError.selector); + this.callDecodeBatch(abi.encodePacked(uint128(0))); + + // GOOD + this.callDecodeBatch(abi.encode(0)); + // Note: Solidity also supports this even though it's odd. Offset 0 means array is at the same location, which + // is interpreted as an array of length 0, which doesn't require any more data + // solhint-disable-next-line var-name-mixedcase + uint256[] memory _1 = abi.decode(abi.encode(0), (uint256[])); + _1; + + // BAD: offset is out of bounds + vm.expectRevert(ERC7579Utils.ERC7579DecodingError.selector); + this.callDecodeBatch(abi.encode(1)); + + // GOOD + this.callDecodeBatch(abi.encode(32, 0)); + + // BAD: reported array length extends beyond bounds + vm.expectRevert(ERC7579Utils.ERC7579DecodingError.selector); + this.callDecodeBatch(abi.encode(32, 1)); + + // GOOD + this.callDecodeBatch(abi.encode(32, 1, 0)); + + // GOOD + // + // 0000000000000000000000000000000000000000000000000000000000000020 (32) offset + // 0000000000000000000000000000000000000000000000000000000000000001 ( 1) array length + // 0000000000000000000000000000000000000000000000000000000000000020 (32) element 0 offset + // 000000000000000000000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (recipient) target for element #0 + // 000000000000000000000000000000000000000000000000000000000000002a (42) value for element #0 + // 0000000000000000000000000000000000000000000000000000000000000060 (96) offset to calldata for element #0 + // 000000000000000000000000000000000000000000000000000000000000000c (12) length of the calldata for element #0 + // 48656c6c6f20576f726c64210000000000000000000000000000000000000000 (..) buffer for the calldata for element #0 + assertEq( + bytes("Hello World!"), + this.callDecodeBatchAndGetFirstBytes( + abi.encode(32, 1, 32, _recipient1, 42, 96, 12, bytes12("Hello World!")) + ) + ); + + // This is invalid, the first element of the array points is out of bounds + // but we allow it past initial validation, because solidity will validate later when the bytes field is accessed + // + // 0000000000000000000000000000000000000000000000000000000000000020 (32) offset + // 0000000000000000000000000000000000000000000000000000000000000001 ( 1) array length + // 0000000000000000000000000000000000000000000000000000000000000020 (32) element 0 offset + // + bytes memory invalid = abi.encode(32, 1, 32); + this.callDecodeBatch(invalid); + vm.expectRevert(); + this.callDecodeBatchAndGetFirst(invalid); + + // this is invalid: the bytes field of the first element of the array is out of bounds + // but we allow it past initial validation, because solidity will validate later when the bytes field is accessed + // + // 0000000000000000000000000000000000000000000000000000000000000020 (32) offset + // 0000000000000000000000000000000000000000000000000000000000000001 ( 1) array length + // 0000000000000000000000000000000000000000000000000000000000000020 (32) element 0 offset + // 000000000000000000000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (recipient) target for element #0 + // 000000000000000000000000000000000000000000000000000000000000002a (42) value for element #0 + // 0000000000000000000000000000000000000000000000000000000000000060 (96) offset to calldata for element #0 + // + bytes memory invalidDeeply = abi.encode(32, 1, 32, _recipient1, 42, 96); + this.callDecodeBatch(invalidDeeply); + // Note that this is ok because we don't return the value. Returning it would introduce a check that would fails. + this.callDecodeBatchAndGetFirst(invalidDeeply); + vm.expectRevert(); + this.callDecodeBatchAndGetFirstBytes(invalidDeeply); + } + + function callDecodeBatch(bytes calldata executionCalldata) public pure { + ERC7579Utils.decodeBatch(executionCalldata); + } + + function callDecodeBatchAndGetFirst(bytes calldata executionCalldata) public pure { + ERC7579Utils.decodeBatch(executionCalldata)[0]; + } + + function callDecodeBatchAndGetFirstBytes(bytes calldata executionCalldata) public pure returns (bytes calldata) { + return ERC7579Utils.decodeBatch(executionCalldata)[0].callData; + } + + function hashUserOperation(PackedUserOperation calldata useroperation) public view returns (bytes32) { + return useroperation.hash(address(ERC4337Utils.ENTRYPOINT_V07)); + } + + function _collectAndPrintLogs(bool includeTotalValue) internal { + Vm.Log[] memory logs = vm.getRecordedLogs(); + for (uint256 i = 0; i < logs.length; i++) { + if (logs[i].emitter == _account) { + _printDecodedCalls(logs[i].data, includeTotalValue); + } + } + } + + function _printDecodedCalls(bytes memory logData, bool includeTotalValue) internal pure { + (bool duringValidation, Execution[] memory calls) = abi.decode(logData, (bool, Execution[])); + + console.log( + string.concat( + "Batch execute contents, as read during ", + duringValidation ? "validation" : "execution", + ": " + ) + ); + console.log(" Execution[] length: %s", calls.length); + + uint256 totalValue = 0; + for (uint256 i = 0; i < calls.length; ++i) { + console.log(string.concat(" calls[", vm.toString(i), "].target = ", vm.toString(calls[i].target))); + console.log(string.concat(" calls[", vm.toString(i), "].value = ", vm.toString(calls[i].value))); + console.log(string.concat(" calls[", vm.toString(i), "].data = ", vm.toString(calls[i].callData))); + totalValue += calls[i].value; + } + + if (includeTotalValue) { + console.log(" Total value: %s", totalValue); + } + } + + function _packGas(uint256 upper, uint256 lower) internal pure returns (bytes32) { + return bytes32(uint256((upper << 128) | uint128(lower))); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.test.js new file mode 100644 index 0000000..b0ca86c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.test.js @@ -0,0 +1,399 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { + CALL_TYPE_CALL, + CALL_TYPE_BATCH, + CALL_TYPE_DELEGATE, + EXEC_TYPE_DEFAULT, + EXEC_TYPE_TRY, + encodeSingle, + encodeBatch, + encodeDelegate, + encodeMode, +} = require('../../helpers/erc7579'); +const { selector } = require('../../helpers/methods'); + +const coder = ethers.AbiCoder.defaultAbiCoder(); + +const fixture = async () => { + const [sender] = await ethers.getSigners(); + const utils = await ethers.deployContract('$ERC7579Utils', { value: ethers.parseEther('1') }); + const utilsGlobal = await ethers.deployContract('$ERC7579UtilsGlobalMock'); + const target = await ethers.deployContract('CallReceiverMock'); + const anotherTarget = await ethers.deployContract('CallReceiverMock'); + return { utils, utilsGlobal, target, anotherTarget, sender }; +}; + +describe('ERC7579Utils', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('constants', async function () { + await expect(this.utils.$CALLTYPE_SINGLE()).to.eventually.equal(CALL_TYPE_CALL); + await expect(this.utils.$CALLTYPE_BATCH()).to.eventually.equal(CALL_TYPE_BATCH); + await expect(this.utils.$CALLTYPE_DELEGATECALL()).to.eventually.equal(CALL_TYPE_DELEGATE); + await expect(this.utils.$EXECTYPE_DEFAULT()).to.eventually.equal(EXEC_TYPE_DEFAULT); + await expect(this.utils.$EXECTYPE_TRY()).to.eventually.equal(EXEC_TYPE_TRY); + }); + + describe('execSingle', function () { + it('calls the target with value', async function () { + const value = 0x012; + const data = encodeSingle(this.target, value, this.target.interface.encodeFunctionData('mockFunction')); + + await expect(this.utils.$execSingle(data, EXEC_TYPE_DEFAULT)).to.emit(this.target, 'MockFunctionCalled'); + + await expect(ethers.provider.getBalance(this.target)).to.eventually.equal(value); + }); + + it('calls the target with value and args', async function () { + const value = 0x432; + const data = encodeSingle( + this.target, + value, + this.target.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234']), + ); + + await expect(this.utils.$execSingle(data, EXEC_TYPE_DEFAULT)) + .to.emit(this.target, 'MockFunctionCalledWithArgs') + .withArgs(42, '0x1234'); + + await expect(ethers.provider.getBalance(this.target)).to.eventually.equal(value); + }); + + it('default to calling self is target is address(0) (ERC-7821 calldata compression)', async function () { + const data = encodeSingle( + ethers.ZeroAddress, // address(0) + 0, + this.utils.interface.encodeFunctionData('$CALLTYPE_SINGLE', []), + ); + + await expect(this.utils.$execSingle(data, EXEC_TYPE_DEFAULT)) + .to.emit(this.utils, 'return$execSingle') + .withArgs([ethers.zeroPadBytes(CALL_TYPE_CALL, 32)]); + }); + + it('reverts when target reverts in default ExecType', async function () { + const value = 0x012; + const data = encodeSingle( + this.target, + value, + this.target.interface.encodeFunctionData('mockFunctionRevertsReason'), + ); + + await expect(this.utils.$execSingle(data, EXEC_TYPE_DEFAULT)).to.be.revertedWith('CallReceiverMock: reverting'); + }); + + it('emits ERC7579TryExecuteFail event when target reverts in try ExecType', async function () { + const value = 0x012; + const data = encodeSingle( + this.target, + value, + this.target.interface.encodeFunctionData('mockFunctionRevertsReason'), + ); + + await expect(this.utils.$execSingle(data, EXEC_TYPE_TRY)) + .to.emit(this.utils, 'ERC7579TryExecuteFail') + .withArgs( + CALL_TYPE_CALL, + ethers.solidityPacked( + ['bytes4', 'bytes'], + [selector('Error(string)'), coder.encode(['string'], ['CallReceiverMock: reverting'])], + ), + ); + }); + + it('reverts with an invalid exec type', async function () { + const value = 0x012; + const data = encodeSingle(this.target, value, this.target.interface.encodeFunctionData('mockFunction')); + + await expect(this.utils.$execSingle(data, '0x03')) + .to.be.revertedWithCustomError(this.utils, 'ERC7579UnsupportedExecType') + .withArgs('0x03'); + }); + }); + + describe('execBatch', function () { + it('calls the targets with value', async function () { + const value1 = 0x012; + const value2 = 0x234; + const data = encodeBatch( + [this.target, value1, this.target.interface.encodeFunctionData('mockFunction')], + [this.anotherTarget, value2, this.anotherTarget.interface.encodeFunctionData('mockFunction')], + ); + + await expect(this.utils.$execBatch(data, EXEC_TYPE_DEFAULT)) + .to.emit(this.target, 'MockFunctionCalled') + .to.emit(this.anotherTarget, 'MockFunctionCalled'); + + await expect(ethers.provider.getBalance(this.target)).to.eventually.equal(value1); + await expect(ethers.provider.getBalance(this.anotherTarget)).to.eventually.equal(value2); + }); + + it('calls the targets with value and args', async function () { + const value1 = 0x012; + const value2 = 0x234; + const data = encodeBatch( + [this.target, value1, this.target.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234'])], + [ + this.anotherTarget, + value2, + this.anotherTarget.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234']), + ], + ); + + await expect(this.utils.$execBatch(data, EXEC_TYPE_DEFAULT)) + .to.emit(this.target, 'MockFunctionCalledWithArgs') + .to.emit(this.anotherTarget, 'MockFunctionCalledWithArgs'); + + await expect(ethers.provider.getBalance(this.target)).to.eventually.equal(value1); + await expect(ethers.provider.getBalance(this.anotherTarget)).to.eventually.equal(value2); + }); + + it('default to calling self is target is address(0) (ERC-7821 calldata compression)', async function () { + const data = encodeBatch( + [ethers.ZeroAddress, 0, this.utils.interface.encodeFunctionData('$CALLTYPE_SINGLE', [])], + [ethers.ZeroAddress, 0, this.utils.interface.encodeFunctionData('$CALLTYPE_BATCH', [])], + ); + + await expect(this.utils.$execBatch(data, EXEC_TYPE_DEFAULT)) + .to.emit(this.utils, 'return$execBatch') + .withArgs([ethers.zeroPadBytes(CALL_TYPE_CALL, 32), ethers.zeroPadBytes(CALL_TYPE_BATCH, 32)]); + }); + + it('reverts when any target reverts in default ExecType', async function () { + const value1 = 0x012; + const value2 = 0x234; + const data = encodeBatch( + [this.target, value1, this.target.interface.encodeFunctionData('mockFunction')], + [this.anotherTarget, value2, this.anotherTarget.interface.encodeFunctionData('mockFunctionRevertsReason')], + ); + + await expect(this.utils.$execBatch(data, EXEC_TYPE_DEFAULT)).to.be.revertedWith('CallReceiverMock: reverting'); + }); + + it('emits ERC7579TryExecuteFail event when any target reverts in try ExecType', async function () { + const value1 = 0x012; + const value2 = 0x234; + const data = encodeBatch( + [this.target, value1, this.target.interface.encodeFunctionData('mockFunction')], + [this.anotherTarget, value2, this.anotherTarget.interface.encodeFunctionData('mockFunctionRevertsReason')], + ); + + await expect(this.utils.$execBatch(data, EXEC_TYPE_TRY)) + .to.emit(this.utils, 'ERC7579TryExecuteFail') + .withArgs( + CALL_TYPE_BATCH, + ethers.solidityPacked( + ['bytes4', 'bytes'], + [selector('Error(string)'), coder.encode(['string'], ['CallReceiverMock: reverting'])], + ), + ); + + // Check balances + await expect(ethers.provider.getBalance(this.target)).to.eventually.equal(value1); + await expect(ethers.provider.getBalance(this.anotherTarget)).to.eventually.equal(0); + }); + + it('reverts with an invalid exec type', async function () { + const value1 = 0x012; + const value2 = 0x234; + const data = encodeBatch( + [this.target, value1, this.target.interface.encodeFunctionData('mockFunction')], + [this.anotherTarget, value2, this.anotherTarget.interface.encodeFunctionData('mockFunction')], + ); + + await expect(this.utils.$execBatch(data, '0x03')) + .to.be.revertedWithCustomError(this.utils, 'ERC7579UnsupportedExecType') + .withArgs('0x03'); + }); + }); + + describe('execDelegateCall', function () { + it('delegate calls the target', async function () { + const slot = ethers.hexlify(ethers.randomBytes(32)); + const value = ethers.hexlify(ethers.randomBytes(32)); + const data = encodeDelegate( + this.target, + this.target.interface.encodeFunctionData('mockFunctionWritesStorage', [slot, value]), + ); + + await expect(ethers.provider.getStorage(this.utils.target, slot)).to.eventually.equal(ethers.ZeroHash); + await this.utils.$execDelegateCall(data, EXEC_TYPE_DEFAULT); + await expect(ethers.provider.getStorage(this.utils.target, slot)).to.eventually.equal(value); + }); + + it('default to calling self is target is address(0) (ERC-7821 calldata compression)', async function () { + const data = encodeDelegate( + ethers.ZeroAddress, + this.utils.interface.encodeFunctionData('$CALLTYPE_DELEGATECALL', []), + ); + + await expect(this.utils.$execDelegateCall(data, EXEC_TYPE_DEFAULT)) + .to.emit(this.utils, 'return$execDelegateCall') + .withArgs([ethers.zeroPadBytes(CALL_TYPE_DELEGATE, 32)]); + }); + + it('reverts when target reverts in default ExecType', async function () { + const data = encodeDelegate(this.target, this.target.interface.encodeFunctionData('mockFunctionRevertsReason')); + await expect(this.utils.$execDelegateCall(data, EXEC_TYPE_DEFAULT)).to.be.revertedWith( + 'CallReceiverMock: reverting', + ); + }); + + it('emits ERC7579TryExecuteFail event when target reverts in try ExecType', async function () { + const data = encodeDelegate(this.target, this.target.interface.encodeFunctionData('mockFunctionRevertsReason')); + await expect(this.utils.$execDelegateCall(data, EXEC_TYPE_TRY)) + .to.emit(this.utils, 'ERC7579TryExecuteFail') + .withArgs( + CALL_TYPE_CALL, + ethers.solidityPacked( + ['bytes4', 'bytes'], + [selector('Error(string)'), coder.encode(['string'], ['CallReceiverMock: reverting'])], + ), + ); + }); + + it('reverts with an invalid exec type', async function () { + const data = encodeDelegate(this.target, this.target.interface.encodeFunctionData('mockFunction')); + await expect(this.utils.$execDelegateCall(data, '0x03')) + .to.be.revertedWithCustomError(this.utils, 'ERC7579UnsupportedExecType') + .withArgs('0x03'); + }); + }); + + it('encodes Mode', async function () { + const callType = CALL_TYPE_BATCH; + const execType = EXEC_TYPE_TRY; + const selector = '0x12345678'; + const payload = ethers.toBeHex(0, 22); + + await expect(this.utils.$encodeMode(callType, execType, selector, payload)).to.eventually.equal( + encodeMode({ + callType, + execType, + selector, + payload, + }), + ); + }); + + it('decodes Mode', async function () { + const callType = CALL_TYPE_BATCH; + const execType = EXEC_TYPE_TRY; + const selector = '0x12345678'; + const payload = ethers.toBeHex(0, 22); + + await expect( + this.utils.$decodeMode( + encodeMode({ + callType, + execType, + selector, + payload, + }), + ), + ).to.eventually.deep.equal([callType, execType, selector, payload]); + }); + + it('encodes single', async function () { + const target = this.target; + const value = 0x123; + const data = '0x12345678'; + + await expect(this.utils.$encodeSingle(target, value, data)).to.eventually.equal(encodeSingle(target, value, data)); + }); + + it('decodes single', async function () { + const target = this.target; + const value = 0x123; + const data = '0x12345678'; + + await expect(this.utils.$decodeSingle(encodeSingle(target, value, data))).to.eventually.deep.equal([ + target.target, + value, + data, + ]); + }); + + it('encodes batch', async function () { + const entries = [ + [this.target, 0x123, '0x12345678'], + [this.anotherTarget, 0x456, '0x12345678'], + ]; + + await expect(this.utils.$encodeBatch(entries)).to.eventually.equal(encodeBatch(...entries)); + }); + + it('decodes batch', async function () { + const entries = [ + [this.target.target, 0x123, '0x12345678'], + [this.anotherTarget.target, 0x456, '0x12345678'], + ]; + + await expect(this.utils.$decodeBatch(encodeBatch(...entries))).to.eventually.deep.equal(entries); + }); + + it('encodes delegate', async function () { + const target = this.target; + const data = '0x12345678'; + + await expect(this.utils.$encodeDelegate(target, data)).to.eventually.equal(encodeDelegate(target, data)); + }); + + it('decodes delegate', async function () { + const target = this.target; + const data = '0x12345678'; + + await expect(this.utils.$decodeDelegate(encodeDelegate(target, data))).to.eventually.deep.equal([ + target.target, + data, + ]); + }); + + describe('global', function () { + describe('eqCallTypeGlobal', function () { + it('returns true if both call types are equal', async function () { + await expect(this.utilsGlobal.$eqCallTypeGlobal(CALL_TYPE_BATCH, CALL_TYPE_BATCH)).to.eventually.be.true; + }); + + it('returns false if both call types are different', async function () { + await expect(this.utilsGlobal.$eqCallTypeGlobal(CALL_TYPE_CALL, CALL_TYPE_BATCH)).to.eventually.be.false; + }); + }); + + describe('eqExecTypeGlobal', function () { + it('returns true if both exec types are equal', async function () { + await expect(this.utilsGlobal.$eqExecTypeGlobal(EXEC_TYPE_TRY, EXEC_TYPE_TRY)).to.eventually.be.true; + }); + + it('returns false if both exec types are different', async function () { + await expect(this.utilsGlobal.$eqExecTypeGlobal(EXEC_TYPE_DEFAULT, EXEC_TYPE_TRY)).to.eventually.be.false; + }); + }); + + describe('eqModeSelectorGlobal', function () { + it('returns true if both selectors are equal', async function () { + await expect(this.utilsGlobal.$eqModeSelectorGlobal('0x12345678', '0x12345678')).to.eventually.be.true; + }); + + it('returns false if both selectors are different', async function () { + await expect(this.utilsGlobal.$eqModeSelectorGlobal('0x12345678', '0x87654321')).to.eventually.be.false; + }); + }); + + describe('eqModePayloadGlobal', function () { + it('returns true if both payloads are equal', async function () { + await expect(this.utilsGlobal.$eqModePayloadGlobal(ethers.toBeHex(0, 22), ethers.toBeHex(0, 22))).to.eventually + .be.true; + }); + + it('returns false if both payloads are different', async function () { + await expect(this.utilsGlobal.$eqModePayloadGlobal(ethers.toBeHex(0, 22), ethers.toBeHex(1, 22))).to.eventually + .be.false; + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint070.abi b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint070.abi new file mode 100644 index 0000000..3f3b1d6 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint070.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"ret","type":"bytes"}],"name":"DelegateAndRevert","type":"error"},{"inputs":[{"internalType":"uint256","name":"opIndex","type":"uint256"},{"internalType":"string","name":"reason","type":"string"}],"name":"FailedOp","type":"error"},{"inputs":[{"internalType":"uint256","name":"opIndex","type":"uint256"},{"internalType":"string","name":"reason","type":"string"},{"internalType":"bytes","name":"inner","type":"bytes"}],"name":"FailedOpWithRevert","type":"error"},{"inputs":[{"internalType":"bytes","name":"returnData","type":"bytes"}],"name":"PostOpReverted","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"SenderAddressResult","type":"error"},{"inputs":[{"internalType":"address","name":"aggregator","type":"address"}],"name":"SignatureValidationFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"factory","type":"address"},{"indexed":false,"internalType":"address","name":"paymaster","type":"address"}],"name":"AccountDeployed","type":"event"},{"anonymous":false,"inputs":[],"name":"BeforeExecution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalDeposit","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"revertReason","type":"bytes"}],"name":"PostOpRevertReason","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"aggregator","type":"address"}],"name":"SignatureAggregatorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalStaked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unstakeDelaySec","type":"uint256"}],"name":"StakeLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawTime","type":"uint256"}],"name":"StakeUnlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"paymaster","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint256","name":"actualGasCost","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"actualGasUsed","type":"uint256"}],"name":"UserOperationEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"UserOperationPrefundTooLow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"revertReason","type":"bytes"}],"name":"UserOperationRevertReason","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"uint32","name":"unstakeDelaySec","type":"uint32"}],"name":"addStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"delegateAndRevert","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"depositTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deposits","outputs":[{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"bool","name":"staked","type":"bool"},{"internalType":"uint112","name":"stake","type":"uint112"},{"internalType":"uint32","name":"unstakeDelaySec","type":"uint32"},{"internalType":"uint48","name":"withdrawTime","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getDepositInfo","outputs":[{"components":[{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"bool","name":"staked","type":"bool"},{"internalType":"uint112","name":"stake","type":"uint112"},{"internalType":"uint32","name":"unstakeDelaySec","type":"uint32"},{"internalType":"uint48","name":"withdrawTime","type":"uint48"}],"internalType":"struct IStakeManager.DepositInfo","name":"info","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint192","name":"key","type":"uint192"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"initCode","type":"bytes"}],"name":"getSenderAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation","name":"userOp","type":"tuple"}],"name":"getUserOpHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation[]","name":"userOps","type":"tuple[]"},{"internalType":"contract IAggregator","name":"aggregator","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IEntryPoint.UserOpsPerAggregator[]","name":"opsPerAggregator","type":"tuple[]"},{"internalType":"address payable","name":"beneficiary","type":"address"}],"name":"handleAggregatedOps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation[]","name":"ops","type":"tuple[]"},{"internalType":"address payable","name":"beneficiary","type":"address"}],"name":"handleOps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint192","name":"key","type":"uint192"}],"name":"incrementNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"callData","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"verificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"callGasLimit","type":"uint256"},{"internalType":"uint256","name":"paymasterVerificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"paymasterPostOpGasLimit","type":"uint256"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"}],"internalType":"struct EntryPoint.MemoryUserOp","name":"mUserOp","type":"tuple"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"uint256","name":"prefund","type":"uint256"},{"internalType":"uint256","name":"contextOffset","type":"uint256"},{"internalType":"uint256","name":"preOpGas","type":"uint256"}],"internalType":"struct EntryPoint.UserOpInfo","name":"opInfo","type":"tuple"},{"internalType":"bytes","name":"context","type":"bytes"}],"name":"innerHandleOp","outputs":[{"internalType":"uint256","name":"actualGasCost","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint192","name":"","type":"uint192"}],"name":"nonceSequenceNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unlockStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawAddress","type":"address"}],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawAddress","type":"address"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"withdrawTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint070.bytecode b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint070.bytecode new file mode 100644 index 0000000000000000000000000000000000000000..fce261af5dc93a09c7ab25cd89463d1b23c5a223 GIT binary patch literal 16035 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 literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint080.abi b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint080.abi new file mode 100644 index 0000000..22fd32c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint080.abi @@ -0,0 +1 @@ +[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"ret","type":"bytes"}],"name":"DelegateAndRevert","type":"error"},{"inputs":[{"internalType":"uint256","name":"opIndex","type":"uint256"},{"internalType":"string","name":"reason","type":"string"}],"name":"FailedOp","type":"error"},{"inputs":[{"internalType":"uint256","name":"opIndex","type":"uint256"},{"internalType":"string","name":"reason","type":"string"},{"internalType":"bytes","name":"inner","type":"bytes"}],"name":"FailedOpWithRevert","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[{"internalType":"bytes","name":"returnData","type":"bytes"}],"name":"PostOpReverted","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"SenderAddressResult","type":"error"},{"inputs":[{"internalType":"address","name":"aggregator","type":"address"}],"name":"SignatureValidationFailed","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"factory","type":"address"},{"indexed":false,"internalType":"address","name":"paymaster","type":"address"}],"name":"AccountDeployed","type":"event"},{"anonymous":false,"inputs":[],"name":"BeforeExecution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalDeposit","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"revertReason","type":"bytes"}],"name":"PostOpRevertReason","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"aggregator","type":"address"}],"name":"SignatureAggregatorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalStaked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unstakeDelaySec","type":"uint256"}],"name":"StakeLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawTime","type":"uint256"}],"name":"StakeUnlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"paymaster","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint256","name":"actualGasCost","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"actualGasUsed","type":"uint256"}],"name":"UserOperationEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"UserOperationPrefundTooLow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"revertReason","type":"bytes"}],"name":"UserOperationRevertReason","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"uint32","name":"unstakeDelaySec","type":"uint32"}],"name":"addStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"delegateAndRevert","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"depositTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getDepositInfo","outputs":[{"components":[{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"bool","name":"staked","type":"bool"},{"internalType":"uint112","name":"stake","type":"uint112"},{"internalType":"uint32","name":"unstakeDelaySec","type":"uint32"},{"internalType":"uint48","name":"withdrawTime","type":"uint48"}],"internalType":"struct IStakeManager.DepositInfo","name":"info","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDomainSeparatorV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint192","name":"key","type":"uint192"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPackedUserOpTypeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"initCode","type":"bytes"}],"name":"getSenderAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation","name":"userOp","type":"tuple"}],"name":"getUserOpHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation[]","name":"userOps","type":"tuple[]"},{"internalType":"contract IAggregator","name":"aggregator","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IEntryPoint.UserOpsPerAggregator[]","name":"opsPerAggregator","type":"tuple[]"},{"internalType":"address payable","name":"beneficiary","type":"address"}],"name":"handleAggregatedOps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation[]","name":"ops","type":"tuple[]"},{"internalType":"address payable","name":"beneficiary","type":"address"}],"name":"handleOps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint192","name":"key","type":"uint192"}],"name":"incrementNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"callData","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"verificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"callGasLimit","type":"uint256"},{"internalType":"uint256","name":"paymasterVerificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"paymasterPostOpGasLimit","type":"uint256"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"}],"internalType":"struct EntryPoint.MemoryUserOp","name":"mUserOp","type":"tuple"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"uint256","name":"prefund","type":"uint256"},{"internalType":"uint256","name":"contextOffset","type":"uint256"},{"internalType":"uint256","name":"preOpGas","type":"uint256"}],"internalType":"struct EntryPoint.UserOpInfo","name":"opInfo","type":"tuple"},{"internalType":"bytes","name":"context","type":"bytes"}],"name":"innerHandleOp","outputs":[{"internalType":"uint256","name":"actualGasCost","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint192","name":"","type":"uint192"}],"name":"nonceSequenceNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"senderCreator","outputs":[{"internalType":"contract ISenderCreator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unlockStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawAddress","type":"address"}],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawAddress","type":"address"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"withdrawTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint080.bytecode b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint080.bytecode new file mode 100644 index 0000000000000000000000000000000000000000..f3f3bd1c1be220e99009e479c79697f0d66d18c8 GIT binary patch literal 21738 zcmd^n349b)ws$HW5K$q4q(dM`fhYu70$JDu!Wux9t~R7Jt@gbp0rLq7Cc%B|s_O0} zkcU=vCt*{F%Nv)`QNM9}>O657--!FXnddmq(dZkU(VwHDzVE4TknewPb$2>RhfdLn(Vq9`muXe)2Q>GN~x!;s~QaoNR zmAJh{tSeW$V#T``W%6_1QMF3xeIyzoqnOuGq&C_3fQbW^&<{7`aWpO5- z^emcVU#h4@Gk|8+riXDjE z?wo?=6YTr%GI`bqXg+=9<7YGZSeotmMVEe>$ul;qmH+ZV@osFKc8 z52?PVOFv&aZqb(3@pHaxzVNgo%YIeb+F17K8|VM6;;WMvU-w--Jxc%Xu*c9%cWfHz z1Az0WACM?~eU1%-@6fe}vRBMH>$@rENUif8ee3%*U02sHxib61wL4N4fA%YH%4IZ; z_O*wnuH@2j1E2)?ylv&4hLZ{YcAU68{8;Fvs>|hKlEkIM_`zyplF3td z^VFR!!Dc@9bikhKV;UAJD}3%X~(gc9S~`0P*0J&gJVh>J^fNolL? zHE|O=8jzH1#>A&4K0E0X^Vk=eE*bo+hg1xVAs90xLX!CG6rV@w6A$2$+7@IbO_)(h zhz-`I`xR%1r|sIkm#5XRl2)lz03R|f!ad*o81`CmcF+dx)3W$kH>;jzMNDia9?~fY zj23;cbvKjuN=k@`HSEhV=G>HWioc+nO$|tZ<+Cs^W91%)uNQ85f9=wxy>31%*WAlz z&a(N;{0GGh5UeJX+mBO2Ik<$$4t`dH>H*TT_?epO!e=UNOhS|xij&|~#4_BVJQ-U> zBgxnH1|a&~U?sUuFUZNgEqaTUcxB5d3-Mu31^8?Y)Ud_r;Ab3AD*}!Ten!5^x@han zgdjNih-qqK)^7{3&S02nVaE9I$@?WY=(oajNEV21b5^;>at0mzw0~ClXBQr7&wJ;L(R5Y z-ngs2TCT3Iud9!rTY&SUCd!UZG;dzt)poBlHj)2FuV~&tRI`4gNH!7B?=$$uFgk1%;Y`vwG{&~ z2&da`aqnhRgVKO`*zYz3|29F|C!|-_1$J~=k~na!R^r7_Pzll1I=+7it%3hrpcVi!x|G*DgzPN)`yu4X(=Ir{AEu+W4@~$~{_3 zQodk!hx>BIv?zrX6w7tjfGJ|^QC?kNv$dv@H`dhEmfD=b8#dJJsA=qt^4RwXXSDK> z&3xn-UWij0`w$L?~G=3vq0LTwe{q8mp@kJjVjm zxs$D;%iVtH2eWX9Im{Cta{$=v3_viYd->@L3DC?e%Z2t_v;)mUWrVY1_?+8~O1Y|f zXI(>0quf|mCvUI27BYk+4YBr*pJ-lWqj#>Iy%5gLZ31WdOA#nHssXUb*fewVIiKrgzNY>N`bvyZ0*%RM?Y zjyne?Gy(~P#<(bw78c6ec!Lb0*j3#io=cC?Kb(Wby#*kKIv8m9a z(PV|<4!%Nh)lBHIols|4rfEq-t%IFpVr-IvzLPAkty;w! zIp&H^GJ3HNgCrmfk`N!gCSrG3iPbJXx`xRu5wohDNzJe{C#p?+bQ39yQpmQH=3`r- z5RPsOK^T&rZ#6Fl{$5rsL78Om0z-0RSO$7At*^9 zahN4JrGEIpD2B@CX~n*$zd)vv%cb-5GAqe*C;t}I+8q*|&ak9Ply*M%aR_rU<(`V; zI7rj)rK2+akQ(qc-S=OvzQA|ip#k8Ez;QyY6P{4m*759F)OB+6N0=v zy$a|GcO(PzHnTa@*0Ika1>H?W0ey@>FAT?wGno_)`r9O4@XK<~eyLpwNiEQH!WK^- zRqkmTG|a+xz~p4`{H<6TLkr*;O?>8i<(>kucKRUW06R%dSu*u9YsbkRe||P1*BSC> z@v&_x+n-x)|LBAvHMUq?kw<#O9XYNi3*K5K9G??}?Yk zb$z(*y91w8AN%3)m#U^sShh0zHyvxTQvN*gt|Mpu@-FL60@X6ae+iW>XT@tk~ zA$)s%HLtoJn@tp2Q@brTh20q9c8|12Cj(eeez#85WBlmo0~bcl3Eb%v@<=#-BYZkY zk;c-BVm=Gq))i##yoNg;2^E_xP2#g8Qr%%=knW|98eiN4>Rw+0?qJNsu;LDvgp$S= z|M05AZ@=*I4n(%Q;NHU(i4kwmx`#nz%j~}jg zTM&sejz)O)RhEm%@C{|~?5kA|&#u({;Am!T=VQdnmy1QvUD>r-v9_SnK-0F8nwd?tKu6zZnzN4 zaoX^K<-^K)FE;*rz@3%F(nuGEr-m-8qBh*11q;u~CKS_N1G``^t zod4tA^39FE-M20AO{)cBiQ9S3e3Os+*dL533<0;dSf3BdYj0}zjqdw+k2}rq`3Fg{ z?P`u#sAkY`2%oL6SJyBGl_#HR5yb~SG|BDP9qcHsx)y+8p}VE9BxuTGKzGh*6l#^j z{MzGJpoX-&!nza==@L{NiRV<8+eE-~4n*P(Id_MwkR5Z#dC+f%7;>J}gF(JvKgfvo zFqAZ^5YXfvjE~(R9iLw(`6k;Vf zw}-H^ea{j^MSOjx>UraDWXjmub?&E3w&=_eagrX?HDK)ViFr|3YxdNHY$R!AS|Ed; zU8MT?#4?M|evmx#15~cxdhW+SjN~F-S{3#~xjcD(rlR@I?vV8n53L)!pM2 zR5tJpI{Vlui2Lk6_atrzoPMJ&5wf@J$P39O5O@!vL>!Wo{vx&=J+JukI-j}wp$q?G z#n}CSNXfhW;*Z~cZ^0|;reyBg@c7-kPWxlsEitYb+|WGtQ(pMWprtYxs^8V?PWYH$ zliEZs!c_hC?S(1eiOX)iEE1QZr9jahv_2p(mQY3|*X#(713#UB2itgYYF6B$32-`* zY|b{JD^ATrFw2nQOdWVg&Ur=Uled_?Eb~H(L_43o2BH+Pf^&ALy*l_a_&K9hA}BuP zZHrGf3~?&y?&!IK!@^>cAM@){uV)a7zNR?#cQmdj*zLwC1uf8!^F2&j)%xPtW!g%O~sUd(Sabv?h#kojrzs zi{gxeYj^840DbM>I`o%?*!~FwjJZWfhV2GpV+OSvhS`kaFu7tJPP#v*WtL4U;9YQbaca`AH~q30XZzu4D(zi-R#ISxJd z-}dUoeSh!1WB1IUlVQd@m8Yf%JQ3^k^CxUdbnT^U;Z89-$B^JErE$(%L}ukw9m-UZ zCGnZ}0+fCRjNX2?SmM%AeT;ZsDgg#9e%>{HA@jsd5`^b9Lytz187$d`=!5ZBaVP-* zNWWD@f}L4a5i22GJy1jf5ivx>A?W&I5$mMupO8?4E0@wvJtXDTpx4wQk=KIODzs$W z(}nvJmRnU3$zowU2a3pc##E$;GYt-QF1?7Kx%8(VCOF}08jCZ*+bhic0tY{Tql#!W zLv~F&TUL?EhUfBW=?u|KWw#_{@bk}Ay&XE-sC>p%6dJ&v$)`PFA!Hm>q>f^^y@Byi zML4JcT8ttfRn|(Hk?zgpGb&ZrJ`bPvZ9*KfE==QWQ((UWdIaY$L>`tD@**;jHws2+ zVmGj}%|mG*Qd=<9R6=@y=9&H!x-*B4WWnjpDob_n>6fTr9v$jPD9opq>3qWs*jX1& z2YI~r;QdNBUG{C!`2|eV<-|apa+Bj6E;^t7WvIQaBi!Lg9DRWr=M|^9SB4{9(yT2e z>}KW&*x(yH@AMFoda{6!`v7$Ar_kIxtY$;ud6UH^@adFvWg!kx5n_%OJT{{kt8Q`d zJe4}IPM)_Z1S}zwz{aZCqG>!2)-@$|DVByf4k)4(xc2kBUxfdmm7=N#_Uzxiuch60 z(-k+KQar#1kw!UU8k8eCh4J&=iH7mvllMJ% zec3a8ao>Fh6pnBk5%tulA4e>U=OLxh%V$ipBQ7EZbPvya88;DSOX@>K?vlM%UW)7Q z8#ZOy1L06RNneZ4c*G9e>I$E6OzaQk zyh&lxYT+|FKybO6AG~M&hLMN=5}5SDo*#_xtfSw4Y>xS4+L!#^r#{ZOQ!*8+pSgoz z5Af9a<1rDul72pWCZ#0YMY}oUp9C$x_h2{9`nD)l3o9M0_Kd^O0dw;s%7toZ5hJxnLfE36|@BBob2n&0-EL z-KGBlVz9$AOrTGaeDTsgLAwjNa}xNLd|@*mMP5%W2#L>p9y=8d2;ZL3rU%@*A5s*o zX6Q@~2fQ89d`SXYaHu7g4TjTjP=5@jvq^!-F=rH6F$n!)JS6VvaMO^C7QJy!nf+Qt z-Gd^TA=$$I=7*C4WA;6FamE^KQuOH6ib64%;Ao&HWX&&yf(Y+Mz_M^MpZcr=0?lLq zb+JhpxlI$nJb0v0rC_0?3M6Yx`AaJlu^$pkZ2l`7RunWF9Jpf zLW_2E1+Ty%Hsh+3&=Wg?kC4e?VFaxETSz z0zLmz=S9#q`0NwHdbaqS({z!$Yr)pbAEqK*_$Z$@nuc=vo|~i5s~M z*Ot=Oa5BLklbfY|NzMP=Zjmtu@j;2eOo)5Rp&)lM(~x6fPy>vQ?0d8%QdS`LZAAs2 zx|`2=4g72;yeTI694uds)K^5s-+|Ci#VBkFHc7W~ z+wN7-zTZ|6y}H{=d7NIM{&|J+=M}1-S15j7q4s%&T8HB*g}T~!!h`;V4;sKOkjnG@ zL|dfR%w4B~uPBE*$s&IEK!=;ru+?Lt&4Ez;yr=}$6eBVj{FB7T7{CNmSq>o+5^H2S zIcUKD=nL_{plN_W!g74H-A6->JM@JN<%E68=acT%>py5Go|bdEu?R(9a9k^TIj2P!uLK^MW1VYYE~6VF+BC zVen9D4==ocq?G-;+2n^wK^^EPiiN=x6Y`2$LWCWq7Ctb^F4ol~HHm@EARg?3uoDl4 zgh_+cCrk;mDn$=Mp|*co!bhY)>=Zsvx%QL|jB_6T8n38CZoS{q(?>ClruEKz2^y5YYrdG-2pj@+1i zX!Q5T?z`tQ_xTG;MjLKl@y0v%TpD`j*S=3~Y8m^}m!7<<`$*jRcu@vR}qT?N3s`$m9*CEQodj(RJ5f1P-^8{`q9rHi{FsmZ5S$P&dfYfv`E7d&qS5UPeJ!+VO-tOXy(mu8W?Bk`o+d=K|2 z&+qAdv`)%$hvkbe9`FE07|sl`J&TU$zEx1v^pzV znYG`00Lt)+y{cz7)H?W@`YX%Qi05vd_}vyg zXh!86q<)*;cHFDnCW^3Dz*7tKW%1<)sR(PiOh`_+^Z=sg*dfIPec@n*U(YM|Z^)gZ z{A%&Sxbmx#r`3ukM+Pq`Pn=T3x)_6J!O53&^b1*h0oLL>6BS_bC397N!K*4?d@SMG zV&zvCY(t-S$ynkGj^Lmgc=?q`xc+~m^eP^d|FN>G_({487XHp9SMig?Rx+S+EAzHP z2M?g;%2iz^N;I$+2kp#P5vHM#lB%uf;0%Gw zp zOraW=FTQGE1rSs<6_5M>v5Ki>tD>&f0ai@?ovNkG0U!~FmZ+3kx}7vuyHaW?vgKJ| zH+FnLHJR}^9Bh@;kDFwG6;gYKvXVhoM=j5bve)t=ycmHmdWq?x+~%|I%n_M$Rs z#qhyYM#b;fAgiKQj2c2!ln5LAJu0HSh=VSAzT9)brFX|{%1{P{nA3^}RhQRufG>g` z1^>qiyl_CfHF@PE6+y-0<3|)g!Nkzuo6EIppvd6Jgz0QjB^18&Q3%;oJxqphu9J1{ zCT$Z94Yn?nDyoTs5$pyTEd*PdA*+H+JMx~jH}RGGy8Vt`=75#7K122R$Uy0>B*%Yu z`u4tk^_=)Sz1t4H_AXMPy?oWr`RY6Qstfq4T138@M42r~|D;3gA-x&;0bQyBP;{wY z#-!X|w?jZkQ1kD9+BQ)#(!@imqBWZU09R~rO_@E<*Toz*jFplxYS8H zx1RW1)D_C5l<8##GWk?VjkRC6z^KJ=&yPlce(R(=ozyx?t)po5bKYU6oVMEnP6`Pz z*c9}otFS6$ajQfiN;DZYnP_TgA|6N~312^0ir#+LZ#YmrpN5cJvq&{I5Eqt={0b<& z9YWV#{Y%m%$snTGWSh$iRXCHcg@%ck>#5^ZV4yXK*aq+lhru5KqlHyS^>{^c-L6Kt zZmWz^!uVYi?MMwFqNb*mGzbiMojyHj{wF?ml1515rNL~niVJ=7alAk1dvEH zD8Kd=)z$9drF;9KCJM@j`v&DTzSaw7O-$F$upN{S`BNDvEgF|!I~Gr9y!2z$g=lbT zS6nRK4frIG7CiDkO)vLSRK4m+O8;lB4DS56Ka*i|Uifnl4>xfs~=J4G`XpvjM2ri}=br z`thbxo#FbQK@HNvdKh(m>sLopkJoR6M}4rqu1T@@_gp!WdQ6@vDqy>!y0#kcGN|G8 z*ALa#74f7&UggJ1d*g?VNUn&l%jCDg^Fx)_7fylG&SE1iM`{|mRfP`>@8|KYyW-Zj zO4Elww|3UO+VoFe-}v;1GxSRjIadAa;fh;opIZ)#irgSdsGo>n6S55Ykw9?FKpO1B z5g{ZGIkzb#1ENo4eY)?a!&XZQ0P-6kRl-VpLXp!9r%%80LltoD2ke+1{wu0K=na54 zPGKebwmtfN$BJ(z%g;I{18Va-P+lRA}5^R&a%J+DDt?A z7L=O7Hyl$F$3)_f6{qjo)cEgx+nKaa#8FWxvCm5932M3gLpZ-fes;3VJhHD2Wr zA$2W4$G>G3`{(=JZan7ug>wFxeTVJ76Y)xt%i7CQ%QPlI9h3|wW%_Pf3@4NvNcU&* zO`}wQ&>aX-GU3LzVCzbNrXIy$vsZ>(4%><4VyRwW0Q6L%Hh(|n-gCOXdZIG-#R-e= zHChWMAJa23zTfrQqPw21c-^C;XlLVNknJ$dX$S+3osC9>#zecLQoGVV`t8rWlO^{@%ifs-B+z{8Yi5HrMlPRv;v!TP3}Q)1mlouen} zHlJ}y)NOh|?TI-@1ar@;6{8McazV;>mwfy3oH74Cz2=356^nz zJIOm~vNvNA>8r z^m>+>#+3-a$aZNsGO!z~Wji_(eHX{TUs@G!?{-g8*lUvdYP`Fuw)Z6dp{!&=Y$f#a zjL1qN2RUBRwRv-?kf4#3aCacSLbkg=*2`U>bO5lV$u5T-B4T6ym4yqt!J#6fh8?K6 zj|uY_Vu!SQlVWSmkKj;_)_GUfq0qa2S0%mpC^AW#%Voh^M}f3`Qgs0nw?u4E}k+*zVq{&Qh)2KzjjK=oA2L~z45@~ iX$P--_5CHQ3SY2pz3QFkKB#J_+g`acWkhaD!T$wxV*1hm literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator070.abi b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator070.abi new file mode 100644 index 0000000..0a1f0e4 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator070.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"bytes","name":"initCode","type":"bytes"}],"name":"createSender","outputs":[{"internalType":"address","name":"sender","type":"address"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator070.bytecode b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator070.bytecode new file mode 100644 index 0000000000000000000000000000000000000000..8344c20281957f0aff5dd71a3650f5553f520704 GIT binary patch literal 451 zcmYdjNMJD&5KUy@4^Lod_!|u*OcNf+B!}}!nTaGas6s?d5*fR~6BO$I;|G7t7=^$p zSxhIU!<0^FY!OUkYzsF_P;O-u5(P1v6Id8cn;L<_O+aClrgla~FuNf^1WXgM=S?Hy zqy~_wq2Yv-K1i@{OyF*16k`-?W}ML6Bru^#P#mOjQcHqLOca_W~?3eV~_71&aW^K+7&892lli~-q#;|Bl$ literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator080.abi b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator080.abi new file mode 100644 index 0000000..e169340 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator080.abi @@ -0,0 +1 @@ +[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"opIndex","type":"uint256"},{"internalType":"string","name":"reason","type":"string"},{"internalType":"bytes","name":"inner","type":"bytes"}],"name":"FailedOpWithRevert","type":"error"},{"inputs":[{"internalType":"bytes","name":"initCode","type":"bytes"}],"name":"createSender","outputs":[{"internalType":"address","name":"sender","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"entryPoint","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"initCallData","type":"bytes"}],"name":"initEip7702Sender","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator080.bytecode b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator080.bytecode new file mode 100644 index 0000000000000000000000000000000000000000..0a8c61fb52987901cf2cbfbb119129d55d2a3c60 GIT binary patch literal 1217 zcmbVL&1(};5Z^I-*psv+ji7}-?CMRi)+BzQwzL%$TarCwOBdXEWK#{qq&D?X6n5Y4 zChaksRuK=Sh$lt#9}rsf;GupTRPZ3wiwE&w@FbYlx7!Z_t*!JO-VAT%&HQHOH)vtE zf?}+xl?u(OZq+qCic4))THU)p7N&cKR4e`bleZkE@Lf&MKY0H+Ooh{d;|U7iRO~ia zwm*Mj&=Pox(c)H~EW$#8U5;K`x3gydC59a~w6yxF?or`|Q;k(nW++0`0~&HuT7?QL zTLv|ShSM9D24)ZGKSyQyZtCva*)w`gigbmkcsQlmNSx#}c*8ZGr%4sGvs4oN^j}mB zUtxEW+id{eB%3Kn7*uuloVkwkA94xX`Olfsw3&HbA80_bNi8Wlie*p`QRc!%gWqOP zPiGhDzm$l_j~yq)Oy0Q2Ca#5};0?ivqmluK@M2C5K6Y#Xl8&>hYnQrQv{Z>$&b zdz8?VG^C}ps#k3+F7%tPRnprD!4jTl*zQ6EA`UpLsUgHZ8pKfS8Rja?S#6TdkW9P! zJ&1FPq%?Ez;_aK82-)zUE7*ggg0f!MTB&$MO=)OwV5anPVy?k&lj<)DiZ-VxL75BA z=TmV~yk5AKGf0}|a%5zzaD(*c$HyiTg=~Ht`?yzq`Js^=9VreSY#~O+#N_=Cl6;g6 kew^>DJ$tkGwE4oqLi>}c#jo|pS1udHLN47aNNqybUt=U#&;S4c literal 0 HcmV?d00001 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js new file mode 100644 index 0000000..b45ffee --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js @@ -0,0 +1,87 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const time = require('../helpers/time'); + +async function envSetup(mock, beneficiary, token) { + return { + eth: { + checkRelease: async (tx, amount) => { + await expect(tx).to.changeEtherBalances([mock, beneficiary], [-amount, amount]); + }, + setupFailure: async () => { + const beneficiaryMock = await ethers.deployContract('EtherReceiverMock'); + await beneficiaryMock.setAcceptEther(false); + await mock.connect(beneficiary).transferOwnership(beneficiaryMock); + return { args: [], error: [mock, 'FailedCall'] }; + }, + releasedEvent: 'EtherReleased', + args: [], + }, + token: { + checkRelease: async (tx, amount) => { + await expect(tx).to.emit(token, 'Transfer').withArgs(mock, beneficiary, amount); + await expect(tx).to.changeTokenBalances(token, [mock, beneficiary], [-amount, amount]); + }, + setupFailure: async () => { + const pausableToken = await ethers.deployContract('$ERC20Pausable', ['Name', 'Symbol']); + await pausableToken.$_pause(); + return { + args: [ethers.Typed.address(pausableToken)], + error: [pausableToken, 'EnforcedPause'], + }; + }, + releasedEvent: 'ERC20Released', + args: [ethers.Typed.address(token)], + }, + }; +} + +function shouldBehaveLikeVesting() { + it('check vesting schedule', async function () { + for (const timestamp of this.schedule) { + await time.increaseTo.timestamp(timestamp); + const vesting = this.vestingFn(timestamp); + + expect(await this.mock.vestedAmount(...this.args, timestamp)).to.equal(vesting); + expect(await this.mock.releasable(...this.args)).to.equal(vesting); + } + }); + + it('execute vesting schedule', async function () { + let released = 0n; + { + const tx = await this.mock.release(...this.args); + await expect(tx) + .to.emit(this.mock, this.releasedEvent) + .withArgs(...this.args, 0); + + await this.checkRelease(tx, 0n); + } + + for (const timestamp of this.schedule) { + await time.increaseTo.timestamp(timestamp, false); + const vested = this.vestingFn(timestamp); + + const tx = await this.mock.release(...this.args); + await expect(tx).to.emit(this.mock, this.releasedEvent); + + await this.checkRelease(tx, vested - released); + released = vested; + } + }); + + it('should revert on transaction failure', async function () { + const { args, error } = await this.setupFailure(); + + for (const timestamp of this.schedule) { + await time.increaseTo.timestamp(timestamp); + + await expect(this.mock.release(...args)).to.be.revertedWithCustomError(...error); + } + }); +} + +module.exports = { + envSetup, + shouldBehaveLikeVesting, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js new file mode 100644 index 0000000..b89258d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js @@ -0,0 +1,65 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { min } = require('../helpers/math'); +const time = require('../helpers/time'); + +const { envSetup, shouldBehaveLikeVesting } = require('./VestingWallet.behavior'); + +async function fixture() { + const amount = ethers.parseEther('100'); + const duration = time.duration.years(4); + const start = (await time.clock.timestamp()) + time.duration.hours(1); + + const [sender, beneficiary] = await ethers.getSigners(); + const mock = await ethers.deployContract('VestingWallet', [beneficiary, start, duration]); + + const token = await ethers.deployContract('$ERC20', ['Name', 'Symbol']); + await token.$_mint(mock, amount); + await sender.sendTransaction({ to: mock, value: amount }); + + const env = await envSetup(mock, beneficiary, token); + + const schedule = Array.from({ length: 64 }, (_, i) => (BigInt(i) * duration) / 60n + start); + const vestingFn = timestamp => min(amount, (amount * (timestamp - start)) / duration); + + return { mock, duration, start, beneficiary, schedule, vestingFn, env }; +} + +describe('VestingWallet', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('rejects zero address for beneficiary', async function () { + await expect(ethers.deployContract('VestingWallet', [ethers.ZeroAddress, this.start, this.duration])) + .revertedWithCustomError(this.mock, 'OwnableInvalidOwner') + .withArgs(ethers.ZeroAddress); + }); + + it('check vesting contract', async function () { + expect(await this.mock.owner()).to.equal(this.beneficiary); + expect(await this.mock.start()).to.equal(this.start); + expect(await this.mock.duration()).to.equal(this.duration); + expect(await this.mock.end()).to.equal(this.start + this.duration); + }); + + describe('vesting schedule', function () { + describe('Eth vesting', function () { + beforeEach(async function () { + Object.assign(this, this.env.eth); + }); + + shouldBehaveLikeVesting(); + }); + + describe('ERC20 vesting', function () { + beforeEach(async function () { + Object.assign(this, this.env.token); + }); + + shouldBehaveLikeVesting(); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWalletCliff.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWalletCliff.test.js new file mode 100644 index 0000000..799b24c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWalletCliff.test.js @@ -0,0 +1,70 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { min } = require('../helpers/math'); +const time = require('../helpers/time'); + +const { envSetup, shouldBehaveLikeVesting } = require('./VestingWallet.behavior'); + +async function fixture() { + const amount = ethers.parseEther('100'); + const duration = time.duration.years(4); + const start = (await time.clock.timestamp()) + time.duration.hours(1); + const cliffDuration = time.duration.years(1); + const cliff = start + cliffDuration; + + const [sender, beneficiary] = await ethers.getSigners(); + const mock = await ethers.deployContract('$VestingWalletCliff', [beneficiary, start, duration, cliffDuration]); + + const token = await ethers.deployContract('$ERC20', ['Name', 'Symbol']); + await token.$_mint(mock, amount); + await sender.sendTransaction({ to: mock, value: amount }); + + const env = await envSetup(mock, beneficiary, token); + + const schedule = Array.from({ length: 64 }, (_, i) => (BigInt(i) * duration) / 60n + start); + const vestingFn = timestamp => min(amount, timestamp < cliff ? 0n : (amount * (timestamp - start)) / duration); + + return { mock, duration, start, beneficiary, cliff, schedule, vestingFn, env }; +} + +describe('VestingWalletCliff', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('rejects a larger cliff than vesting duration', async function () { + await expect( + ethers.deployContract('$VestingWalletCliff', [this.beneficiary, this.start, this.duration, this.duration + 1n]), + ) + .revertedWithCustomError(this.mock, 'InvalidCliffDuration') + .withArgs(this.duration + 1n, this.duration); + }); + + it('check vesting contract', async function () { + expect(await this.mock.owner()).to.equal(this.beneficiary); + expect(await this.mock.start()).to.equal(this.start); + expect(await this.mock.duration()).to.equal(this.duration); + expect(await this.mock.end()).to.equal(this.start + this.duration); + expect(await this.mock.cliff()).to.equal(this.cliff); + }); + + describe('vesting schedule', function () { + describe('Eth vesting', function () { + beforeEach(async function () { + Object.assign(this, this.env.eth); + }); + + shouldBehaveLikeVesting(); + }); + + describe('ERC20 vesting', function () { + beforeEach(async function () { + Object.assign(this, this.env.token); + }); + + shouldBehaveLikeVesting(); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.t.sol new file mode 100644 index 0000000..66b684d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.t.sol @@ -0,0 +1,59 @@ +// 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 view { + if (includeProposer) { + description = string.concat(description, "#proposer=", Strings.toHexString(proposer)); + } + assertTrue(_isValidDescriptionForProposer(proposer, description)); + } + + function testInvalidDescriptionForProposer( + string memory description, + address commitProposer, + address actualProposer + ) public view { + vm.assume(commitProposer != actualProposer); + description = string.concat(description, "#proposer=", Strings.toHexString(commitProposer)); + assertFalse(_isValidDescriptionForProposer(actualProposer, description)); + } + + // We don't need to truly 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 returns (uint256) {} +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.test.js new file mode 100644 index 0000000..e66dd25 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.test.js @@ -0,0 +1,980 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { GovernorHelper } = require('../helpers/governance'); +const { getDomain, Ballot } = require('../helpers/eip712'); +const { ProposalState, VoteType } = require('../helpers/enums'); +const time = require('../helpers/time'); + +const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); +const { shouldBehaveLikeERC6372 } = require('./utils/ERC6372.behavior'); + +const TOKENS = [ + { Token: '$ERC20Votes', mode: 'blocknumber' }, + { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, + { Token: '$ERC20VotesLegacyMock', mode: 'blocknumber' }, +]; + +const name = 'OZ-Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const votingDelay = 4n; +const votingPeriod = 16n; +const value = ethers.parseEther('1'); + +const signBallot = account => (contract, message) => + getDomain(contract).then(domain => account.signTypedData(domain, { Ballot }, message)); + +async function deployToken(contractName) { + try { + return await ethers.deployContract(contractName, [tokenName, tokenSymbol, tokenName, version]); + } catch (error) { + if (error.message == 'incorrect number of arguments to constructor') { + // ERC20VotesLegacyMock has a different construction that uses version='1' by default. + return ethers.deployContract(contractName, [tokenName, tokenSymbol, tokenName]); + } + throw error; + } +} + +describe('Governor', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [owner, proposer, voter1, voter2, voter3, voter4, userEOA] = await ethers.getSigners(); + const receiver = await ethers.deployContract('CallReceiverMock'); + + const token = await deployToken(Token, [tokenName, tokenSymbol, version]); + const mock = await ethers.deployContract('$GovernorMock', [ + name, // name + votingDelay, // initialVotingDelay + votingPeriod, // initialVotingPeriod + 0n, // initialProposalThreshold + token, // tokenAddress + 10n, // quorumNumeratorValue + ]); + + await owner.sendTransaction({ to: mock, value }); + await token.$_mint(owner, tokenSupply); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(owner).delegate({ token: token, to: voter1, value: ethers.parseEther('10') }); + await helper.connect(owner).delegate({ token: token, to: voter2, value: ethers.parseEther('7') }); + await helper.connect(owner).delegate({ token: token, to: voter3, value: ethers.parseEther('5') }); + await helper.connect(owner).delegate({ token: token, to: voter4, value: ethers.parseEther('2') }); + + return { + owner, + proposer, + voter1, + voter2, + voter3, + voter4, + userEOA, + receiver, + token, + mock, + helper, + }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + // initiate fresh proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + value, + }, + ], + '', + ); + }); + + shouldSupportInterfaces(['ERC1155Receiver', 'Governor', 'Governor_5_3']); + shouldBehaveLikeERC6372(mode); + + it('deployment check', async function () { + expect(await this.mock.name()).to.equal(name); + expect(await this.mock.token()).to.equal(this.token); + expect(await this.mock.votingDelay()).to.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.equal(votingPeriod); + expect(await this.mock.quorum(0)).to.equal(0n); + expect(await this.mock.COUNTING_MODE()).to.equal('support=bravo&quorum=for,abstain'); + }); + + it('nominal workflow', async function () { + // Before + expect(await this.mock.proposalProposer(this.proposal.id)).to.equal(ethers.ZeroAddress); + expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; + expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.false; + expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.false; + expect(await ethers.provider.getBalance(this.mock)).to.equal(value); + expect(await ethers.provider.getBalance(this.receiver)).to.equal(0n); + + expect(await this.mock.proposalEta(this.proposal.id)).to.equal(0n); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.false; + + // Run proposal + const txPropose = await this.helper.connect(this.proposer).propose(); + const timepoint = await time.clockFromReceipt[mode](txPropose); + + await expect(txPropose) + .to.emit(this.mock, 'ProposalCreated') + .withArgs( + this.proposal.id, + this.proposer, + this.proposal.targets, + this.proposal.values, + this.proposal.signatures, + this.proposal.data, + timepoint + votingDelay, + timepoint + votingDelay + votingPeriod, + this.proposal.description, + ); + + await this.helper.waitForSnapshot(); + + await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For, reason: 'This is nice' })) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter1, this.proposal.id, VoteType.For, ethers.parseEther('10'), 'This is nice'); + + await expect(this.helper.connect(this.voter2).vote({ support: VoteType.For })) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter2, this.proposal.id, VoteType.For, ethers.parseEther('7'), ''); + + await expect(this.helper.connect(this.voter3).vote({ support: VoteType.Against })) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter3, this.proposal.id, VoteType.Against, ethers.parseEther('5'), ''); + + await expect(this.helper.connect(this.voter4).vote({ support: VoteType.Abstain })) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter4, this.proposal.id, VoteType.Abstain, ethers.parseEther('2'), ''); + + await this.helper.waitForDeadline(); + + const txExecute = await this.helper.execute(); + + await expect(txExecute).to.emit(this.mock, 'ProposalExecuted').withArgs(this.proposal.id); + + await expect(txExecute).to.emit(this.receiver, 'MockFunctionCalled'); + + // After + expect(await this.mock.proposalProposer(this.proposal.id)).to.equal(this.proposer); + expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; + expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.true; + expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.true; + expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); + expect(await ethers.provider.getBalance(this.receiver)).to.equal(value); + + expect(await this.mock.proposalEta(this.proposal.id)).to.equal(0n); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.false; + }); + + it('send ethers', async function () { + this.helper.setProposal( + [ + { + target: this.userEOA.address, + value, + }, + ], + '', + ); + + // Run proposal + await expect(async () => { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + return this.helper.execute(); + }).to.changeEtherBalances([this.mock, this.userEOA], [-value, value]); + }); + + describe('vote with signature', function () { + it('votes with an EOA signature on two proposals', async function () { + await this.token.connect(this.voter1).delegate(this.userEOA); + + for (let i = 0; i < 2; i++) { + const nonce = await this.mock.nonces(this.userEOA); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await expect( + this.helper.vote({ + support: VoteType.For, + voter: this.userEOA.address, + nonce, + signature: signBallot(this.userEOA), + }), + ) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.userEOA, this.proposal.id, VoteType.For, ethers.parseEther('10'), ''); + + // After + expect(await this.mock.hasVoted(this.proposal.id, this.userEOA)).to.be.true; + expect(await this.mock.nonces(this.userEOA)).to.equal(nonce + 1n); + + // Update proposal to allow for re-propose + this.helper.description += ' - updated'; + } + + await expect(this.mock.nonces(this.userEOA)).to.eventually.equal(2n); + }); + + it('votes with a valid EIP-1271 signature', async function () { + const wallet = await ethers.deployContract('ERC1271WalletMock', [this.userEOA]); + + await this.token.connect(this.voter1).delegate(wallet); + + const nonce = await this.mock.nonces(this.userEOA); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await expect( + this.helper.vote({ + support: VoteType.For, + voter: wallet.target, + nonce, + signature: signBallot(this.userEOA), + }), + ) + .to.emit(this.mock, 'VoteCast') + .withArgs(wallet, this.proposal.id, VoteType.For, ethers.parseEther('10'), ''); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + // After + expect(await this.mock.hasVoted(this.proposal.id, wallet)).to.be.true; + expect(await this.mock.nonces(wallet)).to.equal(nonce + 1n); + }); + + afterEach('no other votes are cast', async function () { + expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; + expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.false; + expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.false; + }); + }); + + describe('should revert', function () { + describe('on propose', function () { + it('if proposal already exists', async function () { + await this.helper.propose(); + await expect(this.helper.propose()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs(this.proposal.id, ProposalState.Pending, ethers.ZeroHash); + }); + + it('if proposer has below threshold votes', async function () { + const votes = ethers.parseEther('10'); + const threshold = ethers.parseEther('1000'); + await this.mock.$_setProposalThreshold(threshold); + await expect(this.helper.connect(this.voter1).propose()) + .to.be.revertedWithCustomError(this.mock, 'GovernorInsufficientProposerVotes') + .withArgs(this.voter1, votes, threshold); + }); + }); + + describe('on vote', function () { + it('if proposal does not exist', async function () { + await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For })) + .to.be.revertedWithCustomError(this.mock, 'GovernorNonexistentProposal') + .withArgs(this.proposal.id); + }); + + it('if voting has not started', async function () { + await this.helper.propose(); + await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For })) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Pending, + GovernorHelper.proposalStatesToBitMap([ProposalState.Active]), + ); + }); + + it('if support value is invalid', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await expect(this.helper.vote({ support: 255 })).to.be.revertedWithCustomError( + this.mock, + 'GovernorInvalidVoteType', + ); + }); + + it('if vote was already casted', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For })) + .to.be.revertedWithCustomError(this.mock, 'GovernorAlreadyCastVote') + .withArgs(this.voter1); + }); + + it('if voting is over', async function () { + await this.helper.propose(); + await this.helper.waitForDeadline(); + await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For })) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Defeated, + GovernorHelper.proposalStatesToBitMap([ProposalState.Active]), + ); + }); + }); + + describe('on vote by signature', function () { + beforeEach(async function () { + await this.token.connect(this.voter1).delegate(this.userEOA); + + // 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.userEOA); + + function tamper(str, index, mask) { + const arrayStr = ethers.getBytes(str); + arrayStr[index] ^= mask; + return ethers.hexlify(arrayStr); + } + + const voteParams = { + support: VoteType.For, + voter: this.userEOA.address, + nonce, + signature: (...args) => signBallot(this.userEOA)(...args).then(sig => tamper(sig, 42, 0xff)), + }; + + await expect(this.helper.vote(voteParams)) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') + .withArgs(voteParams.voter); + }); + + it('if vote nonce is incorrect', async function () { + const nonce = await this.mock.nonces(this.userEOA); + + const voteParams = { + support: VoteType.For, + voter: this.userEOA.address, + nonce: nonce + 1n, + signature: signBallot(this.userEOA), + }; + + await expect(this.helper.vote(voteParams)) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') + .withArgs(voteParams.voter); + }); + }); + + describe('on queue', function () { + it('always', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await expect(this.helper.queue()).to.be.revertedWithCustomError(this.mock, 'GovernorQueueNotImplemented'); + }); + }); + + describe('on execute', function () { + it('if proposal does not exist', async function () { + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorNonexistentProposal') + .withArgs(this.proposal.id); + }); + + it('if quorum is not reached', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter3).vote({ support: VoteType.For }); + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Active, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + + it('if score not reached', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.Against }); + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Active, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + + it('if voting is not over', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Active, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + + it('if receiver revert without reason', async function () { + this.helper.setProposal( + [ + { + target: this.receiver.target, + data: this.receiver.interface.encodeFunctionData('mockFunctionRevertsNoReason'), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await expect(this.helper.execute()).to.be.revertedWithCustomError(this.mock, 'FailedCall'); + }); + + it('if receiver revert with reason', async function () { + this.helper.setProposal( + [ + { + target: this.receiver.target, + data: this.receiver.interface.encodeFunctionData('mockFunctionRevertsReason'), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await expect(this.helper.execute()).to.be.revertedWith('CallReceiverMock: reverting'); + }); + + it('if proposal was already executed', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Executed, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + }); + }); + + describe('state', function () { + it('Unset', async function () { + await expect(this.mock.state(this.proposal.id)) + .to.be.revertedWithCustomError(this.mock, 'GovernorNonexistentProposal') + .withArgs(this.proposal.id); + }); + + it('Pending & Active', async function () { + await this.helper.propose(); + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Pending); + await this.helper.waitForSnapshot(); + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Pending); + await this.helper.waitForSnapshot(1n); + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active); + }); + + it('Defeated', async function () { + await this.helper.propose(); + await this.helper.waitForDeadline(); + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active); + await this.helper.waitForDeadline(1n); + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Defeated); + }); + + it('Succeeded', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active); + await this.helper.waitForDeadline(1n); + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Succeeded); + }); + + it('Executed', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Executed); + }); + }); + + describe('cancel', function () { + describe('internal', function () { + it('before proposal', async function () { + await expect(this.helper.cancel('internal')) + .to.be.revertedWithCustomError(this.mock, 'GovernorNonexistentProposal') + .withArgs(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.equal(ProposalState.Canceled); + + await this.helper.waitForSnapshot(); + await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For })) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Canceled, + GovernorHelper.proposalStatesToBitMap([ProposalState.Active]), + ); + }); + + it('after vote', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + + await this.helper.cancel('internal'); + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled); + + await this.helper.waitForDeadline(); + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Canceled, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + + it('after deadline', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await this.helper.cancel('internal'); + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Canceled, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + + it('after execution', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + await expect(this.helper.cancel('internal')) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Executed, + GovernorHelper.proposalStatesToBitMap( + [ProposalState.Canceled, ProposalState.Expired, ProposalState.Executed], + { inverted: true }, + ), + ); + }); + }); + + describe('public', function () { + it('before proposal', async function () { + await expect(this.helper.cancel('external')) + .to.be.revertedWithCustomError(this.mock, 'GovernorNonexistentProposal') + .withArgs(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.connect(this.proposer).propose(); + + await expect(this.helper.connect(this.owner).cancel('external')) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnableToCancel') + .withArgs(this.proposal.id, this.owner); + }); + + it('after vote started', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(1n); // snapshot + 1 block + + await expect(this.helper.cancel('external')) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnableToCancel') + .withArgs(this.proposal.id, this.owner); + }); + + it('after vote', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + + await expect(this.helper.cancel('external')) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnableToCancel') + .withArgs(this.proposal.id, this.voter1); + }); + + it('after deadline', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.cancel('external')) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnableToCancel') + .withArgs(this.proposal.id, this.voter1); + }); + + it('after execution', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + await expect(this.helper.cancel('external')) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnableToCancel') + .withArgs(this.proposal.id, this.voter1); + }); + }); + }); + + describe('proposal length', function () { + it('empty', async function () { + this.helper.setProposal([], ''); + + await expect(this.helper.propose()) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidProposalLength') + .withArgs(0, 0, 0); + }); + + it('mismatch #1', async function () { + this.helper.setProposal( + { + targets: [], + values: [0n], + data: [this.receiver.interface.encodeFunctionData('mockFunction')], + }, + '', + ); + await expect(this.helper.propose()) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidProposalLength') + .withArgs(0, 1, 1); + }); + + it('mismatch #2', async function () { + this.helper.setProposal( + { + targets: [this.receiver.target], + values: [], + data: [this.receiver.interface.encodeFunctionData('mockFunction')], + }, + '', + ); + await expect(this.helper.propose()) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidProposalLength') + .withArgs(1, 1, 0); + }); + + it('mismatch #3', async function () { + this.helper.setProposal( + { + targets: [this.receiver.target], + values: [0n], + data: [], + }, + '', + ); + await expect(this.helper.propose()) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidProposalLength') + .withArgs(1, 0, 1); + }); + }); + + describe('frontrun protection using description suffix', function () { + function shouldPropose() { + it('proposer can propose', async function () { + const txPropose = await this.helper.connect(this.proposer).propose(); + + await expect(txPropose) + .to.emit(this.mock, 'ProposalCreated') + .withArgs( + this.proposal.id, + this.proposer, + this.proposal.targets, + this.proposal.values, + this.proposal.signatures, + this.proposal.data, + (await time.clockFromReceipt[mode](txPropose)) + votingDelay, + (await time.clockFromReceipt[mode](txPropose)) + votingDelay + votingPeriod, + this.proposal.description, + ); + }); + + it('someone else can propose', async function () { + const txPropose = await this.helper.connect(this.voter1).propose(); + + await expect(txPropose) + .to.emit(this.mock, 'ProposalCreated') + .withArgs( + this.proposal.id, + this.voter1, + this.proposal.targets, + this.proposal.values, + this.proposal.signatures, + this.proposal.data, + (await time.clockFromReceipt[mode](txPropose)) + votingDelay, + (await time.clockFromReceipt[mode](txPropose)) + votingDelay + votingPeriod, + this.proposal.description, + ); + }); + } + + describe('without protection', function () { + describe('without suffix', function () { + shouldPropose(); + }); + + describe('with different suffix', function () { + beforeEach(function () { + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + value, + }, + ], + `#wrong-suffix=${this.proposer}`, + ); + }); + + shouldPropose(); + }); + + describe('with proposer suffix but bad address part', function () { + beforeEach(function () { + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + value, + }, + ], + `#proposer=0x3C44CdDdB6a900fa2b585dd299e03d12FA429XYZ`, // XYZ are not a valid hex char + ); + }); + + shouldPropose(); + }); + }); + + describe('with protection via proposer suffix', function () { + beforeEach(function () { + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + value, + }, + ], + `#proposer=${this.proposer}`, + ); + }); + + shouldPropose(); + }); + }); + + describe('onlyGovernance updates', function () { + it('setVotingDelay is protected', async function () { + await expect(this.mock.connect(this.owner).setVotingDelay(0n)) + .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') + .withArgs(this.owner); + }); + + it('setVotingPeriod is protected', async function () { + await expect(this.mock.connect(this.owner).setVotingPeriod(32n)) + .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') + .withArgs(this.owner); + }); + + it('setProposalThreshold is protected', async function () { + await expect(this.mock.connect(this.owner).setProposalThreshold(1_000_000_000_000_000_000n)) + .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') + .withArgs(this.owner); + }); + + it('can setVotingDelay through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('setVotingDelay', [0n]), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.execute()).to.emit(this.mock, 'VotingDelaySet').withArgs(4n, 0n); + + expect(await this.mock.votingDelay()).to.equal(0n); + }); + + it('can setVotingPeriod through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('setVotingPeriod', [32n]), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.execute()).to.emit(this.mock, 'VotingPeriodSet').withArgs(16n, 32n); + + expect(await this.mock.votingPeriod()).to.equal(32n); + }); + + it('cannot setVotingPeriod to 0 through governance', async function () { + const votingPeriod = 0n; + + this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('setVotingPeriod', [votingPeriod]), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidVotingPeriod') + .withArgs(votingPeriod); + }); + + it('can setProposalThreshold to 0 through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('setProposalThreshold', [1_000_000_000_000_000_000n]), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.execute()) + .to.emit(this.mock, 'ProposalThresholdSet') + .withArgs(0n, 1_000_000_000_000_000_000n); + + expect(await this.mock.proposalThreshold()).to.equal(1_000_000_000_000_000_000n); + }); + }); + + describe('safe receive', function () { + describe('ERC721', function () { + const tokenId = 1n; + + beforeEach(async function () { + this.token = await ethers.deployContract('$ERC721', ['Non Fungible Token', 'NFT']); + await this.token.$_mint(this.owner, tokenId); + }); + + it('can receive an ERC721 safeTransfer', async function () { + await this.token.connect(this.owner).safeTransferFrom(this.owner, this.mock, tokenId); + }); + }); + + describe('ERC1155', function () { + const tokenIds = { + 1: 1000n, + 2: 2000n, + 3: 3000n, + }; + + beforeEach(async function () { + this.token = await ethers.deployContract('$ERC1155', ['https://token-cdn-domain/{id}.json']); + await this.token.$_mintBatch(this.owner, Object.keys(tokenIds), Object.values(tokenIds), '0x'); + }); + + it('can receive ERC1155 safeTransfer', async function () { + await this.token.connect(this.owner).safeTransferFrom( + this.owner, + this.mock, + ...Object.entries(tokenIds)[0], // id + amount + '0x', + ); + }); + + it('can receive ERC1155 safeBatchTransfer', async function () { + await this.token + .connect(this.owner) + .safeBatchTransferFrom(this.owner, this.mock, Object.keys(tokenIds), Object.values(tokenIds), '0x'); + }); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/TimelockController.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/TimelockController.test.js new file mode 100644 index 0000000..08410d4 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/TimelockController.test.js @@ -0,0 +1,1279 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +const { GovernorHelper } = require('../helpers/governance'); +const { OperationState } = require('../helpers/enums'); +const time = require('../helpers/time'); + +const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); + +const salt = '0x025e7b0be353a74631ad648c667493c0e1cd31caa4cc2d3520fdc171ea0cc726'; // a random value + +const MINDELAY = time.duration.days(1); +const DEFAULT_ADMIN_ROLE = ethers.ZeroHash; +const PROPOSER_ROLE = ethers.id('PROPOSER_ROLE'); +const EXECUTOR_ROLE = ethers.id('EXECUTOR_ROLE'); +const CANCELLER_ROLE = ethers.id('CANCELLER_ROLE'); + +const getAddress = obj => obj.address ?? obj.target ?? obj; + +function genOperation(target, value, data, predecessor, salt) { + const id = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ['address', 'uint256', 'bytes', 'uint256', 'bytes32'], + [getAddress(target), value, data, predecessor, salt], + ), + ); + return { id, target, value, data, predecessor, salt }; +} + +function genOperationBatch(targets, values, payloads, predecessor, salt) { + const id = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ['address[]', 'uint256[]', 'bytes[]', 'uint256', 'bytes32'], + [targets.map(getAddress), values, payloads, predecessor, salt], + ), + ); + return { id, targets, values, payloads, predecessor, salt }; +} + +async function fixture() { + const [admin, proposer, canceller, executor, other] = await ethers.getSigners(); + + const mock = await ethers.deployContract('TimelockController', [MINDELAY, [proposer], [executor], admin]); + const callreceivermock = await ethers.deployContract('CallReceiverMock'); + const implementation2 = await ethers.deployContract('Implementation2'); + + expect(await mock.hasRole(CANCELLER_ROLE, proposer)).to.be.true; + await mock.connect(admin).revokeRole(CANCELLER_ROLE, proposer); + await mock.connect(admin).grantRole(CANCELLER_ROLE, canceller); + + return { + admin, + proposer, + canceller, + executor, + other, + mock, + callreceivermock, + implementation2, + }; +} + +describe('TimelockController', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldSupportInterfaces(['ERC1155Receiver']); + + it('initial state', async function () { + expect(await this.mock.getMinDelay()).to.equal(MINDELAY); + + expect(await this.mock.DEFAULT_ADMIN_ROLE()).to.equal(DEFAULT_ADMIN_ROLE); + expect(await this.mock.PROPOSER_ROLE()).to.equal(PROPOSER_ROLE); + expect(await this.mock.EXECUTOR_ROLE()).to.equal(EXECUTOR_ROLE); + expect(await this.mock.CANCELLER_ROLE()).to.equal(CANCELLER_ROLE); + + expect( + await Promise.all( + [PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, this.proposer)), + ), + ).to.deep.equal([true, false, false]); + + expect( + await Promise.all( + [PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, this.canceller)), + ), + ).to.deep.equal([false, true, false]); + + expect( + await Promise.all( + [PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, this.executor)), + ), + ).to.deep.equal([false, false, true]); + }); + + it('optional admin', async function () { + const mock = await ethers.deployContract('TimelockController', [ + MINDELAY, + [this.proposer], + [this.executor], + ethers.ZeroAddress, + ]); + expect(await mock.hasRole(DEFAULT_ADMIN_ROLE, this.admin)).to.be.false; + expect(await mock.hasRole(DEFAULT_ADMIN_ROLE, mock.target)).to.be.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.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.equal(this.operation.id); + }); + }); + describe('simple', function () { + describe('schedule', function () { + beforeEach(async function () { + this.operation = genOperation( + '0x31754f590B97fD975Eb86938f18Cc304E264D2F2', + 0n, + '0x3bf92ccc', + ethers.ZeroHash, + salt, + ); + }); + + it('proposer can schedule', async function () { + const tx = await this.mock + .connect(this.proposer) + .schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + ); + + await expect(tx) + .to.emit(this.mock, 'CallScheduled') + .withArgs( + this.operation.id, + 0n, + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + MINDELAY, + ) + .to.emit(this.mock, 'CallSalt') + .withArgs(this.operation.id, this.operation.salt); + + expect(await this.mock.getTimestamp(this.operation.id)).to.equal( + (await time.clockFromReceipt.timestamp(tx)) + MINDELAY, + ); + }); + + it('prevent overwriting active operation', async function () { + await this.mock + .connect(this.proposer) + .schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + ); + + await expect( + this.mock + .connect(this.proposer) + .schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') + .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Unset)); + }); + + it('prevent non-proposer from committing', async function () { + await expect( + this.mock + .connect(this.other) + .schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.other, PROPOSER_ROLE); + }); + + it('enforce minimum delay', async function () { + await expect( + this.mock + .connect(this.proposer) + .schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY - 1n, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockInsufficientDelay') + .withArgs(MINDELAY - 1n, MINDELAY); + }); + + it('schedule operation with salt zero', async function () { + await expect( + this.mock + .connect(this.proposer) + .schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + ethers.ZeroHash, + MINDELAY, + ), + ).to.not.emit(this.mock, 'CallSalt'); + }); + }); + + describe('execute', function () { + beforeEach(async function () { + this.operation = genOperation( + '0xAe22104DCD970750610E6FE15E623468A98b15f7', + 0n, + '0x13e414de', + ethers.ZeroHash, + '0xc1059ed2dc130227aa1d1d539ac94c641306905c020436c636e19e3fab56fc7f', + ); + }); + + it('revert if operation is not scheduled', async function () { + await expect( + this.mock + .connect(this.executor) + .execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') + .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); + }); + + describe('with scheduled operation', function () { + beforeEach(async function () { + await this.mock + .connect(this.proposer) + .schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + ); + }); + + it('revert if execution comes too early 1/2', async function () { + await expect( + this.mock + .connect(this.executor) + .execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') + .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); + }); + + it('revert if execution comes too early 2/2', async function () { + // -1 is too tight, test sometime fails + await this.mock.getTimestamp(this.operation.id).then(clock => time.increaseTo.timestamp(clock - 5n)); + + await expect( + this.mock + .connect(this.executor) + .execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') + .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); + }); + + describe('on time', function () { + beforeEach(async function () { + await this.mock.getTimestamp(this.operation.id).then(time.increaseTo.timestamp); + }); + + it('executor can reveal', async function () { + await expect( + this.mock + .connect(this.executor) + .execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + ), + ) + .to.emit(this.mock, 'CallExecuted') + .withArgs(this.operation.id, 0n, this.operation.target, this.operation.value, this.operation.data); + }); + + it('prevent non-executor from revealing', async function () { + await expect( + this.mock + .connect(this.other) + .execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.other, EXECUTOR_ROLE); + }); + + it('prevents reentrancy execution', async function () { + // Create operation + const reentrant = await ethers.deployContract('$TimelockReentrant'); + const reentrantOperation = genOperation( + reentrant, + 0n, + reentrant.interface.encodeFunctionData('reenter'), + ethers.ZeroHash, + salt, + ); + + // Schedule so it can be executed + await this.mock + .connect(this.proposer) + .schedule( + reentrantOperation.target, + reentrantOperation.value, + reentrantOperation.data, + reentrantOperation.predecessor, + reentrantOperation.salt, + MINDELAY, + ); + + // Advance on time to make the operation executable + await this.mock.getTimestamp(reentrantOperation.id).then(time.increaseTo.timestamp); + + // Grant executor role to the reentrant contract + await this.mock.connect(this.admin).grantRole(EXECUTOR_ROLE, reentrant); + + // Prepare reenter + const data = this.mock.interface.encodeFunctionData('execute', [ + getAddress(reentrantOperation.target), + reentrantOperation.value, + reentrantOperation.data, + reentrantOperation.predecessor, + reentrantOperation.salt, + ]); + await reentrant.enableRentrancy(this.mock, data); + + // Expect to fail + await expect( + this.mock + .connect(this.executor) + .execute( + reentrantOperation.target, + reentrantOperation.value, + reentrantOperation.data, + reentrantOperation.predecessor, + reentrantOperation.salt, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') + .withArgs(reentrantOperation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); + + // Disable reentrancy + await reentrant.disableReentrancy(); + const nonReentrantOperation = reentrantOperation; // Not anymore + + // Try again successfully + await expect( + this.mock + .connect(this.executor) + .execute( + nonReentrantOperation.target, + nonReentrantOperation.value, + nonReentrantOperation.data, + nonReentrantOperation.predecessor, + nonReentrantOperation.salt, + ), + ) + .to.emit(this.mock, 'CallExecuted') + .withArgs( + nonReentrantOperation.id, + 0n, + getAddress(nonReentrantOperation), + nonReentrantOperation.value, + nonReentrantOperation.data, + ); + }); + }); + }); + }); + }); + + describe('batch', function () { + describe('schedule', function () { + beforeEach(async function () { + this.operation = genOperationBatch( + Array(8).fill('0xEd912250835c812D4516BBD80BdaEA1bB63a293C'), + Array(8).fill(0n), + Array(8).fill('0x2fcb7a88'), + ethers.ZeroHash, + '0x6cf9d042ade5de78bed9ffd075eb4b2a4f6b1736932c2dc8af517d6e066f51f5', + ); + }); + + it('proposer can schedule', async function () { + const tx = this.mock + .connect(this.proposer) + .scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + ); + for (const i in this.operation.targets) { + await expect(tx) + .to.emit(this.mock, 'CallScheduled') + .withArgs( + this.operation.id, + i, + getAddress(this.operation.targets[i]), + this.operation.values[i], + this.operation.payloads[i], + this.operation.predecessor, + MINDELAY, + ) + .to.emit(this.mock, 'CallSalt') + .withArgs(this.operation.id, this.operation.salt); + } + + expect(await this.mock.getTimestamp(this.operation.id)).to.equal( + (await time.clockFromReceipt.timestamp(tx)) + MINDELAY, + ); + }); + + it('prevent overwriting active operation', async function () { + await this.mock + .connect(this.proposer) + .scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + ); + + await expect( + this.mock + .connect(this.proposer) + .scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') + .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Unset)); + }); + + it('length of batch parameter must match #1', async function () { + await expect( + this.mock + .connect(this.proposer) + .scheduleBatch( + this.operation.targets, + [], + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockInvalidOperationLength') + .withArgs(this.operation.targets.length, this.operation.payloads.length, 0n); + }); + + it('length of batch parameter must match #1', async function () { + await expect( + this.mock + .connect(this.proposer) + .scheduleBatch( + this.operation.targets, + this.operation.values, + [], + this.operation.predecessor, + this.operation.salt, + MINDELAY, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockInvalidOperationLength') + .withArgs(this.operation.targets.length, 0n, this.operation.payloads.length); + }); + + it('prevent non-proposer from committing', async function () { + await expect( + this.mock + .connect(this.other) + .scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.other, PROPOSER_ROLE); + }); + + it('enforce minimum delay', async function () { + await expect( + this.mock + .connect(this.proposer) + .scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY - 1n, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockInsufficientDelay') + .withArgs(MINDELAY - 1n, MINDELAY); + }); + }); + + describe('execute', function () { + beforeEach(async function () { + this.operation = genOperationBatch( + Array(8).fill('0x76E53CcEb05131Ef5248553bEBDb8F70536830b1'), + Array(8).fill(0n), + Array(8).fill('0x58a60f63'), + ethers.ZeroHash, + '0x9545eeabc7a7586689191f78a5532443698538e54211b5bd4d7dc0fc0102b5c7', + ); + }); + + it('revert if operation is not scheduled', async function () { + await expect( + this.mock + .connect(this.executor) + .executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') + .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); + }); + + describe('with scheduled operation', function () { + beforeEach(async function () { + await this.mock + .connect(this.proposer) + .scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + ); + }); + + it('revert if execution comes too early 1/2', async function () { + await expect( + this.mock + .connect(this.executor) + .executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') + .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); + }); + + it('revert if execution comes too early 2/2', async function () { + // -1 is to tight, test sometime fails + await this.mock.getTimestamp(this.operation.id).then(clock => time.increaseTo.timestamp(clock - 5n)); + + await expect( + this.mock + .connect(this.executor) + .executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') + .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); + }); + + describe('on time', function () { + beforeEach(async function () { + await this.mock.getTimestamp(this.operation.id).then(time.increaseTo.timestamp); + }); + + it('executor can reveal', async function () { + const tx = this.mock + .connect(this.executor) + .executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + ); + for (const i in this.operation.targets) { + await expect(tx) + .to.emit(this.mock, 'CallExecuted') + .withArgs( + this.operation.id, + i, + this.operation.targets[i], + this.operation.values[i], + this.operation.payloads[i], + ); + } + }); + + it('prevent non-executor from revealing', async function () { + await expect( + this.mock + .connect(this.other) + .executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.other, EXECUTOR_ROLE); + }); + + it('length mismatch #1', async function () { + await expect( + this.mock + .connect(this.executor) + .executeBatch( + [], + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockInvalidOperationLength') + .withArgs(0, this.operation.payloads.length, this.operation.values.length); + }); + + it('length mismatch #2', async function () { + await expect( + this.mock + .connect(this.executor) + .executeBatch( + this.operation.targets, + [], + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockInvalidOperationLength') + .withArgs(this.operation.targets.length, this.operation.payloads.length, 0n); + }); + + it('length mismatch #3', async function () { + await expect( + this.mock + .connect(this.executor) + .executeBatch( + this.operation.targets, + this.operation.values, + [], + this.operation.predecessor, + this.operation.salt, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockInvalidOperationLength') + .withArgs(this.operation.targets.length, 0n, this.operation.values.length); + }); + + it('prevents reentrancy execution', async function () { + // Create operation + const reentrant = await ethers.deployContract('$TimelockReentrant'); + const reentrantBatchOperation = genOperationBatch( + [reentrant], + [0n], + [reentrant.interface.encodeFunctionData('reenter')], + ethers.ZeroHash, + salt, + ); + + // Schedule so it can be executed + await this.mock + .connect(this.proposer) + .scheduleBatch( + reentrantBatchOperation.targets, + reentrantBatchOperation.values, + reentrantBatchOperation.payloads, + reentrantBatchOperation.predecessor, + reentrantBatchOperation.salt, + MINDELAY, + ); + + // Advance on time to make the operation executable + await this.mock.getTimestamp(reentrantBatchOperation.id).then(time.increaseTo.timestamp); + + // Grant executor role to the reentrant contract + await this.mock.connect(this.admin).grantRole(EXECUTOR_ROLE, reentrant); + + // Prepare reenter + const data = this.mock.interface.encodeFunctionData('executeBatch', [ + reentrantBatchOperation.targets.map(getAddress), + reentrantBatchOperation.values, + reentrantBatchOperation.payloads, + reentrantBatchOperation.predecessor, + reentrantBatchOperation.salt, + ]); + await reentrant.enableRentrancy(this.mock, data); + + // Expect to fail + await expect( + this.mock + .connect(this.executor) + .executeBatch( + reentrantBatchOperation.targets, + reentrantBatchOperation.values, + reentrantBatchOperation.payloads, + reentrantBatchOperation.predecessor, + reentrantBatchOperation.salt, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') + .withArgs(reentrantBatchOperation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); + + // Disable reentrancy + await reentrant.disableReentrancy(); + const nonReentrantBatchOperation = reentrantBatchOperation; // Not anymore + + // Try again successfully + const tx = this.mock + .connect(this.executor) + .executeBatch( + nonReentrantBatchOperation.targets, + nonReentrantBatchOperation.values, + nonReentrantBatchOperation.payloads, + nonReentrantBatchOperation.predecessor, + nonReentrantBatchOperation.salt, + ); + for (const i in nonReentrantBatchOperation.targets) { + await expect(tx) + .to.emit(this.mock, 'CallExecuted') + .withArgs( + nonReentrantBatchOperation.id, + i, + nonReentrantBatchOperation.targets[i], + nonReentrantBatchOperation.values[i], + nonReentrantBatchOperation.payloads[i], + ); + } + }); + }); + }); + + it('partial execution', async function () { + const operation = genOperationBatch( + [this.callreceivermock, this.callreceivermock, this.callreceivermock], + [0n, 0n, 0n], + [ + this.callreceivermock.interface.encodeFunctionData('mockFunction'), + this.callreceivermock.interface.encodeFunctionData('mockFunctionRevertsNoReason'), + this.callreceivermock.interface.encodeFunctionData('mockFunction'), + ], + ethers.ZeroHash, + '0x8ac04aa0d6d66b8812fb41d39638d37af0a9ab11da507afd65c509f8ed079d3e', + ); + + await this.mock + .connect(this.proposer) + .scheduleBatch( + operation.targets, + operation.values, + operation.payloads, + operation.predecessor, + operation.salt, + MINDELAY, + ); + + await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); + + await expect( + this.mock + .connect(this.executor) + .executeBatch( + operation.targets, + operation.values, + operation.payloads, + operation.predecessor, + operation.salt, + ), + ).to.be.revertedWithCustomError(this.mock, 'FailedCall'); + }); + }); + }); + + describe('cancel', function () { + beforeEach(async function () { + this.operation = genOperation( + '0xC6837c44AA376dbe1d2709F13879E040CAb653ca', + 0n, + '0x296e58dd', + ethers.ZeroHash, + '0xa2485763600634800df9fc9646fb2c112cf98649c55f63dd1d9c7d13a64399d9', + ); + await this.mock + .connect(this.proposer) + .schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + ); + }); + + it('canceller can cancel', async function () { + await expect(this.mock.connect(this.canceller).cancel(this.operation.id)) + .to.emit(this.mock, 'Cancelled') + .withArgs(this.operation.id); + }); + + it('cannot cancel invalid operation', async function () { + await expect(this.mock.connect(this.canceller).cancel(ethers.ZeroHash)) + .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') + .withArgs( + ethers.ZeroHash, + GovernorHelper.proposalStatesToBitMap([OperationState.Waiting, OperationState.Ready]), + ); + }); + + it('prevent non-canceller from canceling', async function () { + await expect(this.mock.connect(this.other).cancel(this.operation.id)) + .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') + .withArgs(this.other, CANCELLER_ROLE); + }); + }); + }); + + describe('maintenance', function () { + it('prevent unauthorized maintenance', async function () { + await expect(this.mock.connect(this.other).updateDelay(0n)) + .to.be.revertedWithCustomError(this.mock, 'TimelockUnauthorizedCaller') + .withArgs(this.other); + }); + + it('timelock scheduled maintenance', async function () { + const newDelay = time.duration.hours(6); + const operation = genOperation( + this.mock, + 0n, + this.mock.interface.encodeFunctionData('updateDelay', [newDelay]), + ethers.ZeroHash, + '0xf8e775b2c5f4d66fb5c7fa800f35ef518c262b6014b3c0aee6ea21bff157f108', + ); + + await this.mock + .connect(this.proposer) + .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); + + await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); + + await expect( + this.mock + .connect(this.executor) + .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt), + ) + .to.emit(this.mock, 'MinDelayChange') + .withArgs(MINDELAY, newDelay); + + expect(await this.mock.getMinDelay()).to.equal(newDelay); + }); + }); + + describe('dependency', function () { + beforeEach(async function () { + this.operation1 = genOperation( + '0xdE66bD4c97304200A95aE0AadA32d6d01A867E39', + 0n, + '0x01dc731a', + ethers.ZeroHash, + '0x64e932133c7677402ead2926f86205e2ca4686aebecf5a8077627092b9bb2feb', + ); + this.operation2 = genOperation( + '0x3c7944a3F1ee7fc8c5A5134ba7c79D11c3A1FCa3', + 0n, + '0x8f531849', + this.operation1.id, + '0x036e1311cac523f9548e6461e29fb1f8f9196b91910a41711ea22f5de48df07d', + ); + await this.mock + .connect(this.proposer) + .schedule( + this.operation1.target, + this.operation1.value, + this.operation1.data, + this.operation1.predecessor, + this.operation1.salt, + MINDELAY, + ); + await this.mock + .connect(this.proposer) + .schedule( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + MINDELAY, + ); + + await this.mock.getTimestamp(this.operation2.id).then(time.increaseTo.timestamp); + }); + + it('cannot execute before dependency', async function () { + await expect( + this.mock + .connect(this.executor) + .execute( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + ), + ) + .to.be.revertedWithCustomError(this.mock, 'TimelockUnexecutedPredecessor') + .withArgs(this.operation1.id); + }); + + it('can execute after dependency', async function () { + await this.mock + .connect(this.executor) + .execute( + this.operation1.target, + this.operation1.value, + this.operation1.data, + this.operation1.predecessor, + this.operation1.salt, + ); + await this.mock + .connect(this.executor) + .execute( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + ); + }); + }); + + describe('usage scenario', function () { + this.timeout(10000); + + it('call', async function () { + const operation = genOperation( + this.implementation2, + 0n, + this.implementation2.interface.encodeFunctionData('setValue', [42n]), + ethers.ZeroHash, + '0x8043596363daefc89977b25f9d9b4d06c3910959ef0c4d213557a903e1b555e2', + ); + + await this.mock + .connect(this.proposer) + .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); + + await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); + + await this.mock + .connect(this.executor) + .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt); + + expect(await this.implementation2.getValue()).to.equal(42n); + }); + + it('call reverting', async function () { + const operation = genOperation( + this.callreceivermock, + 0n, + this.callreceivermock.interface.encodeFunctionData('mockFunctionRevertsNoReason'), + ethers.ZeroHash, + '0xb1b1b276fdf1a28d1e00537ea73b04d56639128b08063c1a2f70a52e38cba693', + ); + + await this.mock + .connect(this.proposer) + .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); + + await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); + + await expect( + this.mock + .connect(this.executor) + .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt), + ).to.be.revertedWithCustomError(this.mock, 'FailedCall'); + }); + + it('call throw', async function () { + const operation = genOperation( + this.callreceivermock, + 0n, + this.callreceivermock.interface.encodeFunctionData('mockFunctionThrows'), + ethers.ZeroHash, + '0xe5ca79f295fc8327ee8a765fe19afb58f4a0cbc5053642bfdd7e73bc68e0fc67', + ); + + await this.mock + .connect(this.proposer) + .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); + + await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); + + // Targeted function reverts with a panic code (0x1) + the timelock bubble the panic code + await expect( + this.mock + .connect(this.executor) + .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt), + ).to.be.revertedWithPanic(PANIC_CODES.ASSERTION_ERROR); + }); + + it('call out of gas', async function () { + const operation = genOperation( + this.callreceivermock, + 0n, + this.callreceivermock.interface.encodeFunctionData('mockFunctionOutOfGas'), + ethers.ZeroHash, + '0xf3274ce7c394c5b629d5215723563a744b817e1730cca5587c567099a14578fd', + ); + + await this.mock + .connect(this.proposer) + .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); + + await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); + + await expect( + this.mock + .connect(this.executor) + .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + gasLimit: '100000', + }), + ).to.be.revertedWithCustomError(this.mock, 'FailedCall'); + }); + + it('call payable with eth', async function () { + const operation = genOperation( + this.callreceivermock, + 1, + this.callreceivermock.interface.encodeFunctionData('mockFunction'), + ethers.ZeroHash, + '0x5ab73cd33477dcd36c1e05e28362719d0ed59a7b9ff14939de63a43073dc1f44', + ); + + await this.mock + .connect(this.proposer) + .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); + + await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); + + expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); + expect(await ethers.provider.getBalance(this.callreceivermock)).to.equal(0n); + + await this.mock + .connect(this.executor) + .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + value: 1, + }); + + expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); + expect(await ethers.provider.getBalance(this.callreceivermock)).to.equal(1n); + }); + + it('call nonpayable with eth', async function () { + const operation = genOperation( + this.callreceivermock, + 1, + this.callreceivermock.interface.encodeFunctionData('mockFunctionNonPayable'), + ethers.ZeroHash, + '0xb78edbd920c7867f187e5aa6294ae5a656cfbf0dea1ccdca3751b740d0f2bdf8', + ); + + await this.mock + .connect(this.proposer) + .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); + + await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); + + expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); + expect(await ethers.provider.getBalance(this.callreceivermock)).to.equal(0n); + + await expect( + this.mock + .connect(this.executor) + .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt), + ).to.be.revertedWithCustomError(this.mock, 'FailedCall'); + + expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); + expect(await ethers.provider.getBalance(this.callreceivermock)).to.equal(0n); + }); + + it('call reverting with eth', async function () { + const operation = genOperation( + this.callreceivermock, + 1, + this.callreceivermock.interface.encodeFunctionData('mockFunctionRevertsNoReason'), + ethers.ZeroHash, + '0xdedb4563ef0095db01d81d3f2decf57cf83e4a72aa792af14c43a792b56f4de6', + ); + + await this.mock + .connect(this.proposer) + .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); + + await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); + + expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); + expect(await ethers.provider.getBalance(this.callreceivermock)).to.equal(0n); + + await expect( + this.mock + .connect(this.executor) + .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt), + ).to.be.revertedWithCustomError(this.mock, 'FailedCall'); + + expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); + expect(await ethers.provider.getBalance(this.callreceivermock)).to.equal(0n); + }); + }); + + describe('safe receive', function () { + describe('ERC721', function () { + const tokenId = 1n; + + beforeEach(async function () { + this.token = await ethers.deployContract('$ERC721', ['Non Fungible Token', 'NFT']); + await this.token.$_mint(this.other, tokenId); + }); + + it('can receive an ERC721 safeTransfer', async function () { + await this.token.connect(this.other).safeTransferFrom(this.other, this.mock, tokenId); + }); + }); + + describe('ERC1155', function () { + const tokenIds = { + 1: 1000n, + 2: 2000n, + 3: 3000n, + }; + + beforeEach(async function () { + this.token = await ethers.deployContract('$ERC1155', ['https://token-cdn-domain/{id}.json']); + await this.token.$_mintBatch(this.other, Object.keys(tokenIds), Object.values(tokenIds), '0x'); + }); + + it('can receive ERC1155 safeTransfer', async function () { + await this.token.connect(this.other).safeTransferFrom( + this.other, + this.mock, + ...Object.entries(tokenIds)[0n], // id + amount + '0x', + ); + }); + + it('can receive ERC1155 safeBatchTransfer', async function () { + await this.token + .connect(this.other) + .safeBatchTransferFrom(this.other, this.mock, Object.keys(tokenIds), Object.values(tokenIds), '0x'); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingFractional.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingFractional.test.js new file mode 100644 index 0000000..a46de21 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingFractional.test.js @@ -0,0 +1,248 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { GovernorHelper } = require('../../helpers/governance'); +const { VoteType } = require('../../helpers/enums'); +const { zip } = require('../../helpers/iterate'); +const { sum } = require('../../helpers/math'); + +const TOKENS = [ + { Token: '$ERC20Votes', mode: 'blocknumber' }, + { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, +]; + +const name = 'OZ-Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const votingDelay = 4n; +const votingPeriod = 16n; +const value = ethers.parseEther('1'); + +describe('GovernorCountingFractional', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [owner, proposer, voter1, voter2, voter3, voter4, other] = await ethers.getSigners(); + const receiver = await ethers.deployContract('CallReceiverMock'); + + const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); + const mock = await ethers.deployContract('$GovernorFractionalMock', [ + name, // name + votingDelay, // initialVotingDelay + votingPeriod, // initialVotingPeriod + 0n, // initialProposalThreshold + token, // tokenAddress + 10n, // quorumNumeratorValue + ]); + + await owner.sendTransaction({ to: mock, value }); + await token.$_mint(owner, tokenSupply); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); + await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); + await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); + await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); + + return { owner, proposer, voter1, voter2, voter3, voter4, other, receiver, token, mock, helper }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + value, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + }, + ], + '', + ); + }); + + it('deployment check', async function () { + expect(await this.mock.name()).to.equal(name); + expect(await this.mock.token()).to.equal(this.token); + expect(await this.mock.votingDelay()).to.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.equal(votingPeriod); + expect(await this.mock.COUNTING_MODE()).to.equal( + 'support=bravo,fractional&quorum=for,abstain¶ms=fractional', + ); + }); + + it('nominal is unaffected', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For, reason: 'This is nice' }); + await this.helper.connect(this.voter2).vote({ support: VoteType.For }); + await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); + await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; + expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.true; + expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.true; + expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); + expect(await ethers.provider.getBalance(this.receiver)).to.equal(value); + }); + + describe('voting with a fraction of the weight', function () { + it('twice', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + + expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([0n, 0n, 0n]); + expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.equal(false); + expect(await this.mock.usedVotes(this.proposal.id, this.voter2)).to.equal(0n); + + const steps = [ + ['0', '2', '1'], + ['1', '0', '1'], + ].map(votes => votes.map(vote => ethers.parseEther(vote))); + + for (const votes of steps) { + const params = ethers.solidityPacked(['uint128', 'uint128', 'uint128'], votes); + await expect( + this.helper.connect(this.voter2).vote({ + support: VoteType.Parameters, + reason: 'no particular reason', + params, + }), + ) + .to.emit(this.mock, 'VoteCastWithParams') + .withArgs( + this.voter2, + this.proposal.id, + VoteType.Parameters, + sum(...votes), + 'no particular reason', + params, + ); + } + + expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal(zip(...steps).map(v => sum(...v))); + expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.equal(true); + expect(await this.mock.usedVotes(this.proposal.id, this.voter2)).to.equal(sum(...[].concat(...steps))); + }); + + it('fractional then nominal', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + + expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([0n, 0n, 0n]); + expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.equal(false); + expect(await this.mock.usedVotes(this.proposal.id, this.voter2)).to.equal(0n); + + const weight = ethers.parseEther('7'); + const fractional = ['1', '2', '1'].map(ethers.parseEther); + + const params = ethers.solidityPacked(['uint128', 'uint128', 'uint128'], fractional); + await expect( + this.helper.connect(this.voter2).vote({ + support: VoteType.Parameters, + reason: 'no particular reason', + params, + }), + ) + .to.emit(this.mock, 'VoteCastWithParams') + .withArgs( + this.voter2, + this.proposal.id, + VoteType.Parameters, + sum(...fractional), + 'no particular reason', + params, + ); + + await expect(this.helper.connect(this.voter2).vote({ support: VoteType.Against })) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter2, this.proposal.id, VoteType.Against, weight - sum(...fractional), ''); + + expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([ + weight - sum(...fractional.slice(1)), + ...fractional.slice(1), + ]); + expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.equal(true); + expect(await this.mock.usedVotes(this.proposal.id, this.voter2)).to.equal(weight); + }); + + it('revert if params spend more than available', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + + const weight = ethers.parseEther('7'); + const fractional = ['0', '1000', '0'].map(ethers.parseEther); + + await expect( + this.helper.connect(this.voter2).vote({ + support: VoteType.Parameters, + reason: 'no particular reason', + params: ethers.solidityPacked(['uint128', 'uint128', 'uint128'], fractional), + }), + ) + .to.be.revertedWithCustomError(this.mock, 'GovernorExceedRemainingWeight') + .withArgs(this.voter2, sum(...fractional), weight); + }); + + it('revert if no weight remaining', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter2).vote({ support: VoteType.For }); + + await expect( + this.helper.connect(this.voter2).vote({ + support: VoteType.Parameters, + reason: 'no particular reason', + params: ethers.solidityPacked(['uint128', 'uint128', 'uint128'], [0n, 1n, 0n]), + }), + ) + .to.be.revertedWithCustomError(this.mock, 'GovernorAlreadyCastVote') + .withArgs(this.voter2); + }); + + it('revert if params are not properly formatted #1', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + + await expect( + this.helper.connect(this.voter2).vote({ + support: VoteType.Parameters, + reason: 'no particular reason', + params: ethers.solidityPacked(['uint128', 'uint128'], [0n, 1n]), + }), + ).to.be.revertedWithCustomError(this.mock, 'GovernorInvalidVoteParams'); + }); + + it('revert if params are not properly formatted #2', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + + await expect( + this.helper.connect(this.voter2).vote({ + support: VoteType.Against, + reason: 'no particular reason', + params: ethers.solidityPacked(['uint128', 'uint128', 'uint128'], [0n, 1n, 0n]), + }), + ).to.be.revertedWithCustomError(this.mock, 'GovernorInvalidVoteParams'); + }); + + it('revert if vote type is invalid', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + + await expect(this.helper.connect(this.voter2).vote({ support: 128n })).to.be.revertedWithCustomError( + this.mock, + 'GovernorInvalidVoteType', + ); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingOverridable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingOverridable.test.js new file mode 100644 index 0000000..fd1032b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingOverridable.test.js @@ -0,0 +1,346 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers'); + +const { GovernorHelper } = require('../../helpers/governance'); +const { getDomain, OverrideBallot } = require('../../helpers/eip712'); +const { VoteType } = require('../../helpers/enums'); + +const TOKENS = [ + { Token: '$ERC20VotesExtendedMock', mode: 'blocknumber' }, + { Token: '$ERC20VotesExtendedTimestampMock', mode: 'timestamp' }, +]; + +const name = 'Override Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const votingDelay = 4n; +const votingPeriod = 16n; +const value = ethers.parseEther('1'); + +const signBallot = account => (contract, message) => + getDomain(contract).then(domain => account.signTypedData(domain, { OverrideBallot }, message)); + +describe('GovernorCountingOverridable', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [owner, proposer, voter1, voter2, voter3, voter4, other] = await ethers.getSigners(); + const receiver = await ethers.deployContract('CallReceiverMock'); + + const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); + const mock = await ethers.deployContract('$GovernorCountingOverridableMock', [ + name, // name + votingDelay, // initialVotingDelay + votingPeriod, // initialVotingPeriod + 0n, // initialProposalThreshold + token, // tokenAddress + 10n, // quorumNumeratorValue + ]); + + await owner.sendTransaction({ to: mock, value }); + await token.$_mint(owner, tokenSupply); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); + await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); + await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); + await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); + + return { owner, proposer, voter1, voter2, voter3, voter4, other, receiver, token, mock, helper }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + value, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + }, + ], + '', + ); + }); + + it('deployment check', async function () { + expect(await this.mock.name()).to.equal(name); + expect(await this.mock.token()).to.equal(this.token); + expect(await this.mock.votingDelay()).to.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.equal(votingPeriod); + expect(await this.mock.COUNTING_MODE()).to.equal('support=bravo,override&quorum=for,abstain&overridable=true'); + }); + + it('nominal is unaffected', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For, reason: 'This is nice' }); + await this.helper.connect(this.voter2).vote({ support: VoteType.For }); + await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); + await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; + expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.true; + expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.true; + expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); + expect(await ethers.provider.getBalance(this.receiver)).to.equal(value); + }); + + describe('cast override vote', async function () { + beforeEach(async function () { + // user 1 -(delegate 10 tokens)-> user 2 + // user 2 -(delegate 7 tokens)-> user 2 + // user 3 -(delegate 5 tokens)-> user 1 + // user 4 -(delegate 2 tokens)-> user 2 + await this.token.connect(this.voter1).delegate(this.voter2); + await this.token.connect(this.voter3).delegate(this.voter1); + await this.token.connect(this.voter4).delegate(this.voter2); + await mine(); + + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + }); + + it('override after delegate vote', async function () { + expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.false; + expect(await this.mock.hasVoted(this.helper.id, this.voter2)).to.be.false; + expect(await this.mock.hasVoted(this.helper.id, this.voter3)).to.be.false; + expect(await this.mock.hasVoted(this.helper.id, this.voter4)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter2)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter3)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter4)).to.be.false; + + // user 2 votes + + await expect(this.helper.connect(this.voter2).vote({ support: VoteType.For })) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter2, this.helper.id, VoteType.For, ethers.parseEther('19'), ''); // 10 + 7 + 2 + + expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( + [0, 19, 0].map(x => ethers.parseEther(x.toString())), + ); + expect(await this.mock.hasVoted(this.helper.id, this.voter2)).to.be.true; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter2)).to.be.false; + + // user 1 overrides after user 2 votes + + const reason = "disagree with user 2's decision"; + await expect(this.mock.connect(this.voter1).castOverrideVote(this.helper.id, VoteType.Against, reason)) + .to.emit(this.mock, 'OverrideVoteCast') + .withArgs(this.voter1, this.helper.id, VoteType.Against, ethers.parseEther('10'), reason) + .to.emit(this.mock, 'VoteReduced') + .withArgs(this.voter2, this.helper.id, VoteType.For, ethers.parseEther('10')); + + expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( + [10, 9, 0].map(x => ethers.parseEther(x.toString())), + ); + expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.true; + }); + + it('override before delegate vote', async function () { + expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.false; + expect(await this.mock.hasVoted(this.helper.id, this.voter2)).to.be.false; + expect(await this.mock.hasVoted(this.helper.id, this.voter3)).to.be.false; + expect(await this.mock.hasVoted(this.helper.id, this.voter4)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter2)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter3)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter4)).to.be.false; + + // user 1 overrides before user 2 votes + + const reason = 'voter 2 is not voting'; + await expect(this.mock.connect(this.voter1).castOverrideVote(this.helper.id, VoteType.Against, reason)) + .to.emit(this.mock, 'OverrideVoteCast') + .withArgs(this.voter1, this.helper.id, VoteType.Against, ethers.parseEther('10'), reason) + .to.not.emit(this.mock, 'VoteReduced'); + + expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( + [10, 0, 0].map(x => ethers.parseEther(x.toString())), + ); + expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.true; + + // user 2 votes + + await expect(this.helper.connect(this.voter2).vote({ support: VoteType.For })) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter2, this.helper.id, VoteType.For, ethers.parseEther('9'), ''); // 7 + 2 + + expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( + [10, 9, 0].map(x => ethers.parseEther(x.toString())), + ); + expect(await this.mock.hasVoted(this.helper.id, this.voter2)).to.be.true; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter2)).to.be.false; + }); + + it('override before and after delegate vote', async function () { + expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.false; + expect(await this.mock.hasVoted(this.helper.id, this.voter2)).to.be.false; + expect(await this.mock.hasVoted(this.helper.id, this.voter3)).to.be.false; + expect(await this.mock.hasVoted(this.helper.id, this.voter4)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter2)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter3)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter4)).to.be.false; + + // user 1 overrides before user 2 votes + + const reason = 'voter 2 is not voting'; + await expect(this.mock.connect(this.voter1).castOverrideVote(this.helper.id, VoteType.Against, reason)) + .to.emit(this.mock, 'OverrideVoteCast') + .withArgs(this.voter1, this.helper.id, VoteType.Against, ethers.parseEther('10'), reason) + .to.not.emit(this.mock, 'VoteReduced'); + + expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( + [10, 0, 0].map(x => ethers.parseEther(x.toString())), + ); + expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.true; + + // user 2 votes + + await expect(this.helper.connect(this.voter2).vote({ support: VoteType.For })) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter2, this.helper.id, VoteType.For, ethers.parseEther('9'), ''); // 7 + 2 + + expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( + [10, 9, 0].map(x => ethers.parseEther(x.toString())), + ); + expect(await this.mock.hasVoted(this.helper.id, this.voter2)).to.be.true; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter2)).to.be.false; + + // User 4 overrides after user 2 votes + + const reason2 = "disagree with user 2's decision"; + await expect(this.mock.connect(this.voter4).castOverrideVote(this.helper.id, VoteType.Abstain, reason2)) + .to.emit(this.mock, 'OverrideVoteCast') + .withArgs(this.voter4, this.helper.id, VoteType.Abstain, ethers.parseEther('2'), reason2) + .to.emit(this.mock, 'VoteReduced') + .withArgs(this.voter2, this.helper.id, VoteType.For, ethers.parseEther('2')); + + expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( + [10, 7, 2].map(x => ethers.parseEther(x.toString())), + ); + expect(await this.mock.hasVoted(this.helper.id, this.voter4)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter4)).to.be.true; + }); + + it('vote (with delegated balance) and override (with self balance) are independent', async function () { + expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( + [0, 0, 0].map(x => ethers.parseEther(x.toString())), + ); + expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.false; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.false; + + // user 1 votes with delegated weight from user 3 + await expect(this.mock.connect(this.voter1).castVote(this.helper.id, VoteType.For)) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter1, this.helper.id, VoteType.For, ethers.parseEther('5'), ''); + + // user 1 cast an override vote with its own balance (delegated to user 2) + await expect(this.mock.connect(this.voter1).castOverrideVote(this.helper.id, VoteType.Against, '')) + .to.emit(this.mock, 'OverrideVoteCast') + .withArgs(this.voter1, this.helper.id, VoteType.Against, ethers.parseEther('10'), ''); + + expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( + [10, 5, 0].map(x => ethers.parseEther(x.toString())), + ); + expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.true; + expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.true; + }); + + it('can not override vote twice', async function () { + await expect(this.mock.connect(this.voter1).castOverrideVote(this.helper.id, VoteType.Against, '')) + .to.emit(this.mock, 'OverrideVoteCast') + .withArgs(this.voter1, this.helper.id, VoteType.Against, ethers.parseEther('10'), ''); + await expect(this.mock.connect(this.voter1).castOverrideVote(this.helper.id, VoteType.Abstain, '')) + .to.be.revertedWithCustomError(this.mock, 'GovernorAlreadyOverriddenVote') + .withArgs(this.voter1.address); + }); + + it('can not vote twice', async function () { + await expect(this.mock.connect(this.voter1).castVote(this.helper.id, VoteType.Against)) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter1, this.helper.id, VoteType.Against, ethers.parseEther('5'), ''); + await expect(this.mock.connect(this.voter1).castVote(this.helper.id, VoteType.Abstain)) + .to.be.revertedWithCustomError(this.mock, 'GovernorAlreadyCastVote') + .withArgs(this.voter1.address); + }); + + describe('invalid vote type', function () { + it('override vote', async function () { + await expect( + this.mock.connect(this.voter1).castOverrideVote(this.helper.id, 3, ''), + ).to.be.revertedWithCustomError(this.mock, 'GovernorInvalidVoteType'); + }); + + it('traditional vote', async function () { + await expect(this.mock.connect(this.voter1).castVote(this.helper.id, 3)).to.be.revertedWithCustomError( + this.mock, + 'GovernorInvalidVoteType', + ); + }); + }); + + describe('by signature', function () { + it('EOA signature', async function () { + const nonce = await this.mock.nonces(this.voter1); + + await expect( + this.helper.overrideVote({ + support: VoteType.For, + voter: this.voter1.address, + nonce, + signature: signBallot(this.voter1), + }), + ) + .to.emit(this.mock, 'OverrideVoteCast') + .withArgs(this.voter1, this.helper.id, VoteType.For, ethers.parseEther('10'), ''); + + expect(await this.mock.hasVotedOverride(this.proposal.id, this.voter1)).to.be.true; + }); + + it('revert if signature does not match signer', async function () { + const nonce = await this.mock.nonces(this.voter1); + + const voteParams = { + support: VoteType.For, + voter: this.voter2.address, + nonce, + signature: signBallot(this.voter1), + }; + + await expect(this.helper.overrideVote(voteParams)) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') + .withArgs(voteParams.voter); + }); + + it('revert if vote nonce is incorrect', async function () { + const nonce = await this.mock.nonces(this.voter1); + + const voteParams = { + support: VoteType.For, + voter: this.voter1.address, + nonce: nonce + 1n, + signature: signBallot(this.voter1), + }; + + await expect(this.helper.overrideVote(voteParams)) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') + .withArgs(voteParams.voter); + }); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js new file mode 100644 index 0000000..15910b8 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js @@ -0,0 +1,131 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { GovernorHelper } = require('../../helpers/governance'); +const { VoteType } = require('../../helpers/enums'); + +const TOKENS = [ + { Token: '$ERC721Votes', mode: 'blocknumber' }, + { Token: '$ERC721VotesTimestampMock', mode: 'timestamp' }, +]; + +const name = 'OZ-Governor'; +const version = '1'; +const tokenName = 'MockNFToken'; +const tokenSymbol = 'MTKN'; +const NFT0 = 0n; +const NFT1 = 1n; +const NFT2 = 2n; +const NFT3 = 3n; +const NFT4 = 4n; +const votingDelay = 4n; +const votingPeriod = 16n; +const value = ethers.parseEther('1'); + +describe('GovernorERC721', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [owner, voter1, voter2, voter3, voter4] = await ethers.getSigners(); + const receiver = await ethers.deployContract('CallReceiverMock'); + + const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); + const mock = await ethers.deployContract('$GovernorMock', [ + name, // name + votingDelay, // initialVotingDelay + votingPeriod, // initialVotingPeriod + 0n, // initialProposalThreshold + token, // tokenAddress + 10n, // quorumNumeratorValue + ]); + + await owner.sendTransaction({ to: mock, value }); + await Promise.all([NFT0, NFT1, NFT2, NFT3, NFT4].map(tokenId => token.$_mint(owner, tokenId))); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(owner).delegate({ token, to: voter1, tokenId: NFT0 }); + await helper.connect(owner).delegate({ token, to: voter2, tokenId: NFT1 }); + await helper.connect(owner).delegate({ token, to: voter2, tokenId: NFT2 }); + await helper.connect(owner).delegate({ token, to: voter3, tokenId: NFT3 }); + await helper.connect(owner).delegate({ token, to: voter4, tokenId: NFT4 }); + + return { + owner, + voter1, + voter2, + voter3, + voter4, + receiver, + token, + mock, + helper, + }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + // initiate fresh proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + value, + }, + ], + '', + ); + }); + + it('deployment check', async function () { + expect(await this.mock.name()).to.equal(name); + expect(await this.mock.token()).to.equal(this.token); + expect(await this.mock.votingDelay()).to.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.equal(votingPeriod); + expect(await this.mock.quorum(0n)).to.equal(0n); + + expect(await this.token.getVotes(this.voter1)).to.equal(1n); // NFT0 + expect(await this.token.getVotes(this.voter2)).to.equal(2n); // NFT1 & NFT2 + expect(await this.token.getVotes(this.voter3)).to.equal(1n); // NFT3 + expect(await this.token.getVotes(this.voter4)).to.equal(1n); // NFT4 + }); + + it('voting with ERC721 token', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + + await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For })) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter1, this.proposal.id, VoteType.For, 1n, ''); + + await expect(this.helper.connect(this.voter2).vote({ support: VoteType.For })) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter2, this.proposal.id, VoteType.For, 2n, ''); + + await expect(this.helper.connect(this.voter3).vote({ support: VoteType.Against })) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter3, this.proposal.id, VoteType.Against, 1n, ''); + + await expect(this.helper.connect(this.voter4).vote({ support: VoteType.Abstain })) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter4, this.proposal.id, VoteType.Abstain, 1n, ''); + + await this.helper.waitForDeadline(); + await this.helper.execute(); + + expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; + expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.true; + expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.true; + expect(await this.mock.hasVoted(this.proposal.id, this.voter3)).to.be.true; + expect(await this.mock.hasVoted(this.proposal.id, this.voter4)).to.be.true; + + expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([ + 1n, // againstVotes + 3n, // forVotes + 1n, // abstainVotes + ]); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorNoncesKeyed.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorNoncesKeyed.test.js new file mode 100644 index 0000000..e2cbd8f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorNoncesKeyed.test.js @@ -0,0 +1,244 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { GovernorHelper } = require('../../helpers/governance'); +const { getDomain, Ballot, ExtendedBallot } = require('../../helpers/eip712'); +const { VoteType } = require('../../helpers/enums'); +const { shouldBehaveLikeNoncesKeyed } = require('../../utils/Nonces.behavior'); + +const name = 'OZ-Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const votingDelay = 4n; +const votingPeriod = 16n; +const value = ethers.parseEther('1'); + +const signBallot = account => (contract, message) => + getDomain(contract).then(domain => account.signTypedData(domain, { Ballot }, message)); +const signExtendedBallot = account => (contract, message) => + getDomain(contract).then(domain => account.signTypedData(domain, { ExtendedBallot }, message)); + +describe('GovernorNoncesKeyed', function () { + const fixture = async () => { + const [owner, proposer, voter1, voter2, voter3, voter4, userEOA] = await ethers.getSigners(); + const receiver = await ethers.deployContract('CallReceiverMock'); + + const token = await ethers.deployContract('$ERC20Votes', [tokenName, tokenSymbol, tokenName, version]); + const mock = await ethers.deployContract('$GovernorNoncesKeyedMock', [ + name, // name + votingDelay, // initialVotingDelay + votingPeriod, // initialVotingPeriod + 0n, // initialProposalThreshold + token, // tokenAddress + 10n, // quorumNumeratorValue + ]); + + await owner.sendTransaction({ to: mock, value }); + await token.$_mint(owner, tokenSupply); + + const helper = new GovernorHelper(mock, 'blocknumber'); + await helper.connect(owner).delegate({ token: token, to: voter1, value: ethers.parseEther('10') }); + await helper.connect(owner).delegate({ token: token, to: voter2, value: ethers.parseEther('7') }); + await helper.connect(owner).delegate({ token: token, to: voter3, value: ethers.parseEther('5') }); + await helper.connect(owner).delegate({ token: token, to: voter4, value: ethers.parseEther('2') }); + + return { + owner, + proposer, + voter1, + voter2, + voter3, + voter4, + userEOA, + receiver, + token, + mock, + helper, + }; + }; + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + value, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + }, + ], + '', + ); + }); + + it('deployment check', async function () { + await expect(this.mock.name()).to.eventually.equal(name); + await expect(this.mock.token()).to.eventually.equal(this.token); + await expect(this.mock.votingDelay()).to.eventually.equal(votingDelay); + await expect(this.mock.votingPeriod()).to.eventually.equal(votingPeriod); + }); + + describe('vote with signature', function () { + for (const nonceType of ['default', 'keyed']) { + describe(`with ${nonceType} nonce`, function () { + beforeEach(async function () { + await this.helper.propose(); + + const maskedProposalId = BigInt(this.helper.id) & (2n ** 192n - 1n); + + this.getNonce = async address => { + return await (nonceType === 'default' + ? this.mock.nonces(address) + : this.mock['nonces(address,uint192)'](address, maskedProposalId)); + }; + }); + + it('votes with an EOA signature', async function () { + await this.token.connect(this.voter1).delegate(this.userEOA); + + const nonce = await this.getNonce(this.userEOA); + + await this.helper.waitForSnapshot(); + await expect( + this.helper.vote({ + support: VoteType.For, + voter: this.userEOA.address, + nonce, + signature: signBallot(this.userEOA), + }), + ) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.userEOA, this.proposal.id, VoteType.For, ethers.parseEther('10'), ''); + + await this.helper.waitForDeadline(); + await this.helper.execute(); + + // After + expect(await this.mock.hasVoted(this.proposal.id, this.userEOA)).to.be.true; + expect(await this.getNonce(this.userEOA)).to.equal(nonce + 1n); + }); + + it('votes with an EOA signature with reason', async function () { + await this.token.connect(this.voter1).delegate(this.userEOA); + + const nonce = await this.getNonce(this.userEOA); + + await this.helper.waitForSnapshot(); + await expect( + this.helper.vote({ + support: VoteType.For, + voter: this.userEOA.address, + nonce, + reason: 'This is an example reason', + signature: signExtendedBallot(this.userEOA), + }), + ) + .to.emit(this.mock, 'VoteCast') + .withArgs( + this.userEOA, + this.proposal.id, + VoteType.For, + ethers.parseEther('10'), + 'This is an example reason', + ); + + await this.helper.waitForDeadline(); + await this.helper.execute(); + + // After + expect(await this.mock.hasVoted(this.proposal.id, this.userEOA)).to.be.true; + expect(await this.getNonce(this.userEOA)).to.equal(nonce + 1n); + }); + + it('votes with a valid EIP-1271 signature', async function () { + const wallet = await ethers.deployContract('ERC1271WalletMock', [this.userEOA]); + + await this.token.connect(this.voter1).delegate(wallet); + + const nonce = await this.getNonce(wallet.target); + + await this.helper.waitForSnapshot(); + await expect( + this.helper.vote({ + support: VoteType.For, + voter: wallet.target, + nonce, + signature: signBallot(this.userEOA), + }), + ) + .to.emit(this.mock, 'VoteCast') + .withArgs(wallet, this.proposal.id, VoteType.For, ethers.parseEther('10'), ''); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + // After + expect(await this.mock.hasVoted(this.proposal.id, wallet)).to.be.true; + expect(await this.getNonce(wallet)).to.equal(nonce + 1n); + }); + + afterEach('no other votes are cast', async function () { + expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; + expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.false; + expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.false; + }); + }); + } + }); + + describe('on vote by signature', function () { + beforeEach(async function () { + await this.token.connect(this.voter1).delegate(this.userEOA); + + // 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.userEOA); + + function tamper(str, index, mask) { + const arrayStr = ethers.getBytes(str); + arrayStr[index] ^= mask; + return ethers.hexlify(arrayStr); + } + + const voteParams = { + support: VoteType.For, + voter: this.userEOA.address, + nonce, + signature: (...args) => signBallot(this.userEOA)(...args).then(sig => tamper(sig, 42, 0xff)), + }; + + await expect(this.helper.vote(voteParams)) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') + .withArgs(voteParams.voter); + }); + + for (const nonceType of ['default', 'keyed']) { + it(`if vote nonce is incorrect with ${nonceType} nonce`, async function () { + const nonce = await (nonceType === 'default' + ? this.mock.nonces(this.userEOA) + : this.mock['nonces(address,uint192)'](this.userEOA, BigInt(this.helper.id) & (2n ** 192n - 1n))); + + const voteParams = { + support: VoteType.For, + voter: this.userEOA.address, + nonce: nonce + 1n, + signature: signBallot(this.userEOA), + }; + + await expect(this.helper.vote(voteParams)) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') + .withArgs(voteParams.voter); + }); + } + }); + + shouldBehaveLikeNoncesKeyed(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js new file mode 100644 index 0000000..761087a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js @@ -0,0 +1,185 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { GovernorHelper } = require('../../helpers/governance'); +const { ProposalState, VoteType } = require('../../helpers/enums'); +const time = require('../../helpers/time'); + +const TOKENS = [ + { Token: '$ERC20Votes', mode: 'blocknumber' }, + { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, +]; + +const name = 'OZ-Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const votingDelay = 4n; +const votingPeriod = 16n; +const lateQuorumVoteExtension = 8n; +const quorum = ethers.parseEther('1'); +const value = ethers.parseEther('1'); + +describe('GovernorPreventLateQuorum', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [owner, proposer, voter1, voter2, voter3, voter4] = await ethers.getSigners(); + const receiver = await ethers.deployContract('CallReceiverMock'); + + const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); + const mock = await ethers.deployContract('$GovernorPreventLateQuorumMock', [ + name, // name + votingDelay, // initialVotingDelay + votingPeriod, // initialVotingPeriod + 0n, // initialProposalThreshold + token, // tokenAddress + lateQuorumVoteExtension, + quorum, + ]); + + await owner.sendTransaction({ to: mock, value }); + await token.$_mint(owner, tokenSupply); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); + await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); + await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); + await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); + + return { owner, proposer, voter1, voter2, voter3, voter4, receiver, token, mock, helper }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + // initiate fresh proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + value, + }, + ], + '', + ); + }); + + it('deployment check', async function () { + expect(await this.mock.name()).to.equal(name); + expect(await this.mock.token()).to.equal(this.token); + expect(await this.mock.votingDelay()).to.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.equal(votingPeriod); + expect(await this.mock.quorum(0)).to.equal(quorum); + expect(await this.mock.lateQuorumVoteExtension()).to.equal(lateQuorumVoteExtension); + }); + + it('nominal workflow unaffected', async function () { + const txPropose = await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.connect(this.voter2).vote({ support: VoteType.For }); + await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); + await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; + expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.true; + expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.true; + expect(await this.mock.hasVoted(this.proposal.id, this.voter3)).to.be.true; + expect(await this.mock.hasVoted(this.proposal.id, this.voter4)).to.be.true; + + expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([ + ethers.parseEther('5'), // againstVotes + ethers.parseEther('17'), // forVotes + ethers.parseEther('2'), // abstainVotes + ]); + + const voteStart = (await time.clockFromReceipt[mode](txPropose)) + votingDelay; + const voteEnd = (await time.clockFromReceipt[mode](txPropose)) + votingDelay + votingPeriod; + expect(await this.mock.proposalSnapshot(this.proposal.id)).to.equal(voteStart); + expect(await this.mock.proposalDeadline(this.proposal.id)).to.equal(voteEnd); + + await expect(txPropose) + .to.emit(this.mock, 'ProposalCreated') + .withArgs( + this.proposal.id, + this.proposer, + this.proposal.targets, + this.proposal.values, + this.proposal.signatures, + this.proposal.data, + voteStart, + voteEnd, + this.proposal.description, + ); + }); + + it('Delay is extended to prevent last minute take-over', async function () { + const txPropose = await this.helper.connect(this.proposer).propose(); + + // compute original schedule + const snapshotTimepoint = (await time.clockFromReceipt[mode](txPropose)) + votingDelay; + const deadlineTimepoint = (await time.clockFromReceipt[mode](txPropose)) + votingDelay + votingPeriod; + expect(await this.mock.proposalSnapshot(this.proposal.id)).to.equal(snapshotTimepoint); + expect(await this.mock.proposalDeadline(this.proposal.id)).to.equal(deadlineTimepoint); + // wait for the last minute to vote + await this.helper.waitForDeadline(-1n); + const txVote = await this.helper.connect(this.voter2).vote({ support: VoteType.For }); + + // cannot execute yet + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active); + + // compute new extended schedule + const extendedDeadline = (await time.clockFromReceipt[mode](txVote)) + lateQuorumVoteExtension; + expect(await this.mock.proposalSnapshot(this.proposal.id)).to.equal(snapshotTimepoint); + expect(await this.mock.proposalDeadline(this.proposal.id)).to.equal(extendedDeadline); + + // still possible to vote + await this.helper.connect(this.voter1).vote({ support: VoteType.Against }); + + await this.helper.waitForDeadline(); + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active); + await this.helper.waitForDeadline(1n); + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Defeated); + + // check extension event + await expect(txVote).to.emit(this.mock, 'ProposalExtended').withArgs(this.proposal.id, extendedDeadline); + }); + + describe('onlyGovernance updates', function () { + it('setLateQuorumVoteExtension is protected', async function () { + await expect(this.mock.connect(this.owner).setLateQuorumVoteExtension(0n)) + .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') + .withArgs(this.owner); + }); + + it('can setLateQuorumVoteExtension through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('setLateQuorumVoteExtension', [0n]), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.execute()) + .to.emit(this.mock, 'LateQuorumVoteExtensionSet') + .withArgs(lateQuorumVoteExtension, 0n); + + expect(await this.mock.lateQuorumVoteExtension()).to.equal(0n); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorProposalGuardian.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorProposalGuardian.test.js new file mode 100644 index 0000000..1741072 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorProposalGuardian.test.js @@ -0,0 +1,132 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { impersonate } = require('../../helpers/account'); +const { GovernorHelper } = require('../../helpers/governance'); +const { ProposalState } = require('../../helpers/enums'); + +const TOKENS = [ + { Token: '$ERC20Votes', mode: 'blocknumber' }, + { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, +]; +const name = 'Proposal Guardian Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const votingDelay = 4n; +const votingPeriod = 16n; +const value = ethers.parseEther('1'); + +describe('GovernorProposalGuardian', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [owner, proposer, guardian, voter1, voter2, voter3, voter4, other] = await ethers.getSigners(); + const receiver = await ethers.deployContract('CallReceiverMock'); + + const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); + const mock = await ethers.deployContract('$GovernorProposalGuardianMock', [ + name, // name + votingDelay, // initialVotingDelay + votingPeriod, // initialVotingPeriod + 0n, // initialProposalThreshold + token, // tokenAddress + 10n, // quorumNumeratorValue + ]); + + await impersonate(mock.target); + await owner.sendTransaction({ to: mock, value }); + await token.$_mint(owner, tokenSupply); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); + await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); + await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); + await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); + + return { owner, proposer, guardian, voter1, voter2, voter3, voter4, other, receiver, token, mock, helper }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + value, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + }, + ], + '', + ); + }); + + it('deployment check', async function () { + await expect(this.mock.name()).to.eventually.equal(name); + await expect(this.mock.token()).to.eventually.equal(this.token); + await expect(this.mock.votingDelay()).to.eventually.equal(votingDelay); + await expect(this.mock.votingPeriod()).to.eventually.equal(votingPeriod); + }); + + describe('set proposal guardian', function () { + it('from governance', async function () { + const governorSigner = await ethers.getSigner(this.mock.target); + await expect(this.mock.connect(governorSigner).setProposalGuardian(this.guardian)) + .to.emit(this.mock, 'ProposalGuardianSet') + .withArgs(ethers.ZeroAddress, this.guardian); + await expect(this.mock.proposalGuardian()).to.eventually.equal(this.guardian); + }); + + it('from non-governance', async function () { + await expect(this.mock.connect(this.other).setProposalGuardian(this.guardian)) + .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') + .withArgs(this.other); + }); + }); + + it('cancel proposal during pending state from proposer when proposal guardian is non-zero', async function () { + await this.mock.$_setProposalGuardian(this.guardian); + await this.helper.connect(this.proposer).propose(); + await expect(this.helper.connect(this.proposer).cancel()) + .to.emit(this.mock, 'ProposalCanceled') + .withArgs(this.proposal.id); + }); + + describe('cancel proposal during active state', function () { + beforeEach(async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(1n); + await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Active); + }); + + it('from proposal guardian', async function () { + await this.mock.$_setProposalGuardian(this.guardian); + + await expect(this.helper.connect(this.guardian).cancel()) + .to.emit(this.mock, 'ProposalCanceled') + .withArgs(this.proposal.id); + }); + + it('from proposer when proposal guardian is non-zero', async function () { + await this.mock.$_setProposalGuardian(this.guardian); + + await expect(this.helper.connect(this.proposer).cancel()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnableToCancel') + .withArgs(this.proposal.id, this.proposer); + }); + + it('from proposer when proposal guardian is zero', async function () { + await this.mock.$_setProposalGuardian(ethers.ZeroAddress); + + await expect(this.helper.connect(this.proposer).cancel()) + .to.emit(this.mock, 'ProposalCanceled') + .withArgs(this.proposal.id); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSequentialProposalId.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSequentialProposalId.test.js new file mode 100644 index 0000000..81bc6eb --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSequentialProposalId.test.js @@ -0,0 +1,202 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); + +const { GovernorHelper } = require('../../helpers/governance'); +const { VoteType } = require('../../helpers/enums'); +const iterate = require('../../helpers/iterate'); + +const TOKENS = [ + { Token: '$ERC20Votes', mode: 'blocknumber' }, + { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, +]; + +const name = 'OZ-Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const votingDelay = 4n; +const votingPeriod = 16n; +const value = ethers.parseEther('1'); + +async function deployToken(contractName) { + try { + return await ethers.deployContract(contractName, [tokenName, tokenSymbol, tokenName, version]); + } catch (error) { + if (error.message == 'incorrect number of arguments to constructor') { + // ERC20VotesLegacyMock has a different construction that uses version='1' by default. + return ethers.deployContract(contractName, [tokenName, tokenSymbol, tokenName]); + } + throw error; + } +} + +describe('GovernorSequentialProposalId', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [owner, proposer, voter1, voter2, voter3, voter4, userEOA] = await ethers.getSigners(); + const receiver = await ethers.deployContract('CallReceiverMock'); + + const token = await deployToken(Token, [tokenName, tokenSymbol, version]); + const mock = await ethers.deployContract('$GovernorSequentialProposalIdMock', [ + name, // name + votingDelay, // initialVotingDelay + votingPeriod, // initialVotingPeriod + 0n, // initialProposalThreshold + token, // tokenAddress + 10n, // quorumNumeratorValue + ]); + + await owner.sendTransaction({ to: mock, value }); + await token.$_mint(owner, tokenSupply); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(owner).delegate({ token: token, to: voter1, value: ethers.parseEther('10') }); + await helper.connect(owner).delegate({ token: token, to: voter2, value: ethers.parseEther('7') }); + await helper.connect(owner).delegate({ token: token, to: voter3, value: ethers.parseEther('5') }); + await helper.connect(owner).delegate({ token: token, to: voter4, value: ethers.parseEther('2') }); + + return { + owner, + proposer, + voter1, + voter2, + voter3, + voter4, + userEOA, + receiver, + token, + mock, + helper, + }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + value, + }, + ], + '', + ); + }); + + it('sequential proposal ids', async function () { + for (const i of iterate.range(1, 10)) { + this.proposal.description = ``; + + await expect(this.mock.hashProposal(...this.proposal.shortProposal)).to.eventually.equal(this.proposal.hash); + await expect(this.mock.getProposalId(...this.proposal.shortProposal)).revertedWithCustomError( + this.mock, + 'GovernorNonexistentProposal', + ); + await expect(this.mock.latestProposalId()).to.eventually.equal(i - 1); + + await expect(this.helper.connect(this.proposer).propose()) + .to.emit(this.mock, 'ProposalCreated') + .withArgs( + i, + this.proposer, + this.proposal.targets, + this.proposal.values, + this.proposal.signatures, + this.proposal.data, + anyValue, + anyValue, + this.proposal.description, + ); + + await expect(this.mock.hashProposal(...this.proposal.shortProposal)).to.eventually.equal(this.proposal.hash); + await expect(this.mock.getProposalId(...this.proposal.shortProposal)).to.eventually.equal(i); + await expect(this.mock.latestProposalId()).to.eventually.equal(i); + } + }); + + it('sequential proposal ids with offset start', async function () { + const offset = 69420; + await this.mock.$_initializeLatestProposalId(offset); + + for (const i of iterate.range(offset + 1, offset + 10)) { + this.proposal.description = ``; + + await expect(this.mock.hashProposal(...this.proposal.shortProposal)).to.eventually.equal(this.proposal.hash); + await expect(this.mock.getProposalId(...this.proposal.shortProposal)).revertedWithCustomError( + this.mock, + 'GovernorNonexistentProposal', + ); + await expect(this.mock.latestProposalId()).to.eventually.equal(i - 1); + + await expect(this.helper.connect(this.proposer).propose()) + .to.emit(this.mock, 'ProposalCreated') + .withArgs( + i, + this.proposer, + this.proposal.targets, + this.proposal.values, + this.proposal.signatures, + this.proposal.data, + anyValue, + anyValue, + this.proposal.description, + ); + + await expect(this.mock.hashProposal(...this.proposal.shortProposal)).to.eventually.equal(this.proposal.hash); + await expect(this.mock.getProposalId(...this.proposal.shortProposal)).to.eventually.equal(i); + await expect(this.mock.latestProposalId()).to.eventually.equal(i); + } + }); + + it('can only initialize latest proposal id from 0', async function () { + await this.helper.propose(); + await expect(this.mock.latestProposalId()).to.eventually.equal(1); + await expect(this.mock.$_initializeLatestProposalId(2)).to.be.revertedWithCustomError( + this.mock, + 'GovernorAlreadyInitializedLatestProposalId', + ); + }); + + it('cannot repropose same proposal', async function () { + await this.helper.connect(this.proposer).propose(); + await expect(this.helper.connect(this.proposer).propose()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs(await this.proposal.id, 0, ethers.ZeroHash); + }); + + it('nominal workflow', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + + await expect(this.mock.connect(this.voter1).castVote(1, VoteType.For)) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter1, 1, VoteType.For, ethers.parseEther('10'), ''); + + await expect(this.mock.connect(this.voter2).castVote(1, VoteType.For)) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter2, 1, VoteType.For, ethers.parseEther('7'), ''); + + await expect(this.mock.connect(this.voter3).castVote(1, VoteType.For)) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter3, 1, VoteType.For, ethers.parseEther('5'), ''); + + await expect(this.mock.connect(this.voter4).castVote(1, VoteType.Abstain)) + .to.emit(this.mock, 'VoteCast') + .withArgs(this.voter4, 1, VoteType.Abstain, ethers.parseEther('2'), ''); + + await this.helper.waitForDeadline(); + + await expect(this.helper.execute()) + .to.eventually.emit(this.mock, 'ProposalExecuted') + .withArgs(1) + .emit(this.receiver, 'MockFunctionCalled'); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorStorage.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorStorage.test.js new file mode 100644 index 0000000..f079405 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorStorage.test.js @@ -0,0 +1,155 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +const { GovernorHelper, timelockSalt } = require('../../helpers/governance'); +const { VoteType } = require('../../helpers/enums'); + +const TOKENS = [ + { Token: '$ERC20Votes', mode: 'blocknumber' }, + { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, +]; + +const DEFAULT_ADMIN_ROLE = ethers.ZeroHash; +const PROPOSER_ROLE = ethers.id('PROPOSER_ROLE'); +const EXECUTOR_ROLE = ethers.id('EXECUTOR_ROLE'); +const CANCELLER_ROLE = ethers.id('CANCELLER_ROLE'); + +const name = 'OZ-Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const votingDelay = 4n; +const votingPeriod = 16n; +const value = ethers.parseEther('1'); +const delay = 3600n; + +describe('GovernorStorage', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [deployer, owner, proposer, voter1, voter2, voter3, voter4] = await ethers.getSigners(); + const receiver = await ethers.deployContract('CallReceiverMock'); + + const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); + const timelock = await ethers.deployContract('TimelockController', [delay, [], [], deployer]); + const mock = await ethers.deployContract('$GovernorStorageMock', [ + name, + votingDelay, + votingPeriod, + 0n, + timelock, + token, + 0n, + ]); + + await owner.sendTransaction({ to: timelock, value }); + await token.$_mint(owner, tokenSupply); + await timelock.grantRole(PROPOSER_ROLE, mock); + await timelock.grantRole(PROPOSER_ROLE, owner); + await timelock.grantRole(CANCELLER_ROLE, mock); + await timelock.grantRole(CANCELLER_ROLE, owner); + await timelock.grantRole(EXECUTOR_ROLE, ethers.ZeroAddress); + await timelock.revokeRole(DEFAULT_ADMIN_ROLE, deployer); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); + await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); + await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); + await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); + + return { deployer, owner, proposer, voter1, voter2, voter3, voter4, receiver, token, timelock, mock, helper }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + // initiate fresh proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + value, + }, + ], + '', + ); + this.proposal.timelockid = await this.timelock.hashOperationBatch( + ...this.proposal.shortProposal.slice(0, 3), + ethers.ZeroHash, + timelockSalt(this.mock.target, this.proposal.shortProposal[3]), + ); + }); + + describe('proposal indexing', function () { + it('before propose', async function () { + expect(await this.mock.proposalCount()).to.equal(0n); + + await expect(this.mock.proposalDetailsAt(0n)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); + + await expect(this.mock.proposalDetails(this.proposal.id)) + .to.be.revertedWithCustomError(this.mock, 'GovernorNonexistentProposal') + .withArgs(this.proposal.id); + }); + + it('after propose', async function () { + await this.helper.propose(); + + expect(await this.mock.proposalCount()).to.equal(1n); + + expect(await this.mock.proposalDetailsAt(0n)).to.deep.equal([ + this.proposal.id, + this.proposal.targets, + this.proposal.values, + this.proposal.data, + this.proposal.descriptionHash, + ]); + + expect(await this.mock.proposalDetails(this.proposal.id)).to.deep.equal([ + this.proposal.targets, + this.proposal.values, + this.proposal.data, + this.proposal.descriptionHash, + ]); + }); + }); + + it('queue and execute by id', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.connect(this.voter2).vote({ support: VoteType.For }); + await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); + await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }); + await this.helper.waitForDeadline(); + + await expect(this.mock.queue(this.proposal.id)) + .to.emit(this.mock, 'ProposalQueued') + .withArgs(this.proposal.id, anyValue) + .to.emit(this.timelock, 'CallScheduled') + .withArgs(this.proposal.timelockid, ...Array(6).fill(anyValue)) + .to.emit(this.timelock, 'CallSalt') + .withArgs(this.proposal.timelockid, anyValue); + + await this.helper.waitForEta(); + + await expect(this.mock.execute(this.proposal.id)) + .to.emit(this.mock, 'ProposalExecuted') + .withArgs(this.proposal.id) + .to.emit(this.timelock, 'CallExecuted') + .withArgs(this.proposal.timelockid, ...Array(4).fill(anyValue)) + .to.emit(this.receiver, 'MockFunctionCalled'); + }); + + it('cancel by id', async function () { + await this.helper.connect(this.proposer).propose(); + await expect(this.mock.connect(this.proposer).cancel(this.proposal.id)) + .to.emit(this.mock, 'ProposalCanceled') + .withArgs(this.proposal.id); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorum.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorum.test.js new file mode 100644 index 0000000..9a8b845 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorum.test.js @@ -0,0 +1,168 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { GovernorHelper } = require('../../helpers/governance'); +const { ProposalState, VoteType } = require('../../helpers/enums'); +const time = require('../../helpers/time'); + +const TOKENS = [ + { Token: '$ERC20Votes', mode: 'blocknumber' }, + { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, +]; + +const DEFAULT_ADMIN_ROLE = ethers.ZeroHash; +const PROPOSER_ROLE = ethers.id('PROPOSER_ROLE'); +const EXECUTOR_ROLE = ethers.id('EXECUTOR_ROLE'); +const CANCELLER_ROLE = ethers.id('CANCELLER_ROLE'); + +const name = 'OZ-Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const votingDelay = 4n; +const votingPeriod = 16n; +const quorum = 10n; +const superQuorum = 40n; +const value = ethers.parseEther('1'); +const delay = time.duration.hours(1n); + +describe('GovernorSuperQuorum', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [proposer, voter1, voter2, voter3, voter4, voter5] = await ethers.getSigners(); + const receiver = await ethers.deployContract('CallReceiverMock'); + + const timelock = await ethers.deployContract('TimelockController', [delay, [], [], proposer]); + const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); + const mock = await ethers.deployContract('$GovernorSuperQuorumMock', [ + name, + votingDelay, // initialVotingDelay + votingPeriod, // initialVotingPeriod + 0n, // initialProposalThreshold + token, + timelock, + quorum, + superQuorum, + ]); + + await proposer.sendTransaction({ to: timelock, value }); + await token.$_mint(proposer, tokenSupply); + await timelock.grantRole(PROPOSER_ROLE, mock); + await timelock.grantRole(PROPOSER_ROLE, proposer); + await timelock.grantRole(CANCELLER_ROLE, mock); + await timelock.grantRole(CANCELLER_ROLE, proposer); + await timelock.grantRole(EXECUTOR_ROLE, ethers.ZeroAddress); + await timelock.revokeRole(DEFAULT_ADMIN_ROLE, proposer); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(proposer).delegate({ token, to: voter1, value: 40 }); + await helper.connect(proposer).delegate({ token, to: voter2, value: 30 }); + await helper.connect(proposer).delegate({ token, to: voter3, value: 20 }); + await helper.connect(proposer).delegate({ token, to: voter4, value: 15 }); + await helper.connect(proposer).delegate({ token, to: voter5, value: 5 }); + + return { proposer, voter1, voter2, voter3, voter4, voter5, receiver, token, mock, timelock, helper }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + value, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + }, + ], + '', + ); + }); + + it('deployment check', async function () { + await expect(this.mock.name()).to.eventually.equal(name); + await expect(this.mock.token()).to.eventually.equal(this.token); + await expect(this.mock.quorum(0)).to.eventually.equal(quorum); + await expect(this.mock.superQuorum(0)).to.eventually.equal(superQuorum); + }); + + it('proposal succeeds early when super quorum is reached', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + + // Vote with voter2 (30) - above quorum (10) but below super quorum (40) + await this.helper.connect(this.voter2).vote({ support: VoteType.For }); + await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Active); + + // Vote with voter3 (20) to reach super quorum (50 total > 40) + await this.helper.connect(this.voter3).vote({ support: VoteType.For }); + + await expect(this.mock.proposalEta(this.proposal.id)).to.eventually.equal(0); + + // Should be succeeded since we reached super quorum and no eta is set + await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Succeeded); + }); + + it('proposal remains active if super quorum is not reached', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + + // Vote with voter4 (15) - below super quorum (40) but above quorum (10) + await this.helper.connect(this.voter4).vote({ support: VoteType.For }); + await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Active); + + // Vote with voter5 (5) - still below super quorum (total 20 < 40) + await this.helper.connect(this.voter5).vote({ support: VoteType.For }); + await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Active); + + // Wait for deadline + await this.helper.waitForDeadline(1n); + + // Should succeed since deadline passed and we have enough support (20 > 10 quorum) + await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Succeeded); + }); + + it('proposal remains active if super quorum is reached but vote fails', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + + // Vote against with voter2 and voter3 (50) + await this.helper.connect(this.voter2).vote({ support: VoteType.Against }); + await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); + + // Vote for with voter1 (40) (reaching super quorum) + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + + // should be active since super quorum is reached but vote fails + await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Active); + + // wait for deadline + await this.helper.waitForDeadline(1n); + + // should be defeated since against votes are higher + await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Defeated); + }); + + it('proposal is queued if super quorum is reached and eta is set', async function () { + await this.helper.connect(this.proposer).propose(); + + await this.helper.waitForSnapshot(); + + // Vote with voter1 (40) - reaching super quorum + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + + await this.helper.queue(); + + // Queueing should set eta + await expect(this.mock.proposalEta(this.proposal.id)).to.eventually.not.equal(0); + + // Should be queued since we reached super quorum and eta is set + await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Queued); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorumGreaterThanQuorum.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorumGreaterThanQuorum.t.sol new file mode 100644 index 0000000..eb0409c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorumGreaterThanQuorum.t.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {GovernorVotesSuperQuorumFractionMock} from "../../../contracts/mocks/governance/GovernorVotesSuperQuorumFractionMock.sol"; +import {GovernorVotesQuorumFraction} from "../../../contracts/governance/extensions/GovernorVotesQuorumFraction.sol"; +import {GovernorVotesSuperQuorumFraction} from "../../../contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol"; +import {GovernorSettings} from "../../../contracts/governance/extensions/GovernorSettings.sol"; +import {GovernorVotes} from "../../../contracts/governance/extensions/GovernorVotes.sol"; +import {Governor} from "../../../contracts/governance/Governor.sol"; +import {IVotes} from "../../../contracts/governance/utils/IVotes.sol"; +import {ERC20VotesExtendedTimestampMock} from "../../../contracts/mocks/token/ERC20VotesAdditionalCheckpointsMock.sol"; +import {EIP712} from "../../../contracts/utils/cryptography/EIP712.sol"; +import {ERC20} from "../../../contracts/token/ERC20/ERC20.sol"; + +contract TokenMock is ERC20VotesExtendedTimestampMock { + constructor() ERC20("Mock Token", "MTK") EIP712("Mock Token", "1") {} +} + +/** + * Main responsibility: expose the functions that are relevant to the simulation + */ +contract GovernorHandler is GovernorVotesSuperQuorumFractionMock { + constructor( + string memory name_, + uint48 votingDelay_, + uint32 votingPeriod_, + uint256 proposalThreshold_, + IVotes token_, + uint256 quorumNumerator_, + uint256 superQuorumNumerator_ + ) + Governor(name_) + GovernorSettings(votingDelay_, votingPeriod_, proposalThreshold_) + GovernorVotes(token_) + GovernorVotesQuorumFraction(quorumNumerator_) + GovernorVotesSuperQuorumFraction(superQuorumNumerator_) + {} + + // solhint-disable-next-line func-name-mixedcase + function $_updateSuperQuorumNumerator(uint256 newSuperQuorumNumerator) public { + _updateSuperQuorumNumerator(newSuperQuorumNumerator); + } + + // solhint-disable-next-line func-name-mixedcase + function $_updateQuorumNumerator(uint256 newQuorumNumerator) public { + _updateQuorumNumerator(newQuorumNumerator); + } +} + +contract GovernorSuperQuorumGreaterThanQuorum is Test { + GovernorHandler private _governorHandler; + + function setUp() external { + _governorHandler = new GovernorHandler( + "GovernorName", + 0, // votingDelay + 1e4, // votingPeriod + 0, // proposalThreshold + new TokenMock(), // token + 10, // quorumNumerator + 50 // superQuorumNumerator + ); + + // limit the fuzzer scope + bytes4[] memory selectors = new bytes4[](2); + selectors[0] = GovernorHandler.$_updateSuperQuorumNumerator.selector; + selectors[1] = GovernorHandler.$_updateQuorumNumerator.selector; + + targetContract(address(_governorHandler)); + targetSelector(FuzzSelector(address(_governorHandler), selectors)); + } + + // solhint-disable-next-line func-name-mixedcase + function invariant_superQuorumGreaterThanQuorum() external view { + assertGe(_governorHandler.superQuorumNumerator(), _governorHandler.quorumNumerator()); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockAccess.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockAccess.test.js new file mode 100644 index 0000000..5eea647 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockAccess.test.js @@ -0,0 +1,864 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); + +const { GovernorHelper } = require('../../helpers/governance'); +const { hashOperation } = require('../../helpers/access-manager'); +const { max } = require('../../helpers/math'); +const { selector } = require('../../helpers/methods'); +const { ProposalState, VoteType } = require('../../helpers/enums'); +const time = require('../../helpers/time'); + +function prepareOperation({ sender, target, value = 0n, data = '0x' }) { + return { + id: hashOperation(sender, target, data), + operation: { target, value, data }, + selector: data.slice(0, 10).padEnd(10, '0'), + }; +} + +const TOKENS = [ + { Token: '$ERC20Votes', mode: 'blocknumber' }, + { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, +]; + +const name = 'OZ-Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const votingDelay = 4n; +const votingPeriod = 16n; +const value = ethers.parseEther('1'); + +describe('GovernorTimelockAccess', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [admin, voter1, voter2, voter3, voter4, other] = await ethers.getSigners(); + + const manager = await ethers.deployContract('$AccessManager', [admin]); + const receiver = await ethers.deployContract('$AccessManagedTarget', [manager]); + + const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); + const mock = await ethers.deployContract('$GovernorTimelockAccessMock', [ + name, + votingDelay, + votingPeriod, + 0n, + manager, + 0n, + token, + 0n, + ]); + + await admin.sendTransaction({ to: mock, value }); + await token.$_mint(admin, tokenSupply); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(admin).delegate({ token, to: voter1, value: ethers.parseEther('10') }); + await helper.connect(admin).delegate({ token, to: voter2, value: ethers.parseEther('7') }); + await helper.connect(admin).delegate({ token, to: voter3, value: ethers.parseEther('5') }); + await helper.connect(admin).delegate({ token, to: voter4, value: ethers.parseEther('2') }); + + return { admin, voter1, voter2, voter3, voter4, other, manager, receiver, token, mock, helper }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + + // restricted proposal + this.restricted = prepareOperation({ + sender: this.mock.target, + target: this.receiver.target, + data: this.receiver.interface.encodeFunctionData('fnRestricted'), + }); + + this.unrestricted = prepareOperation({ + sender: this.mock.target, + target: this.receiver.target, + data: this.receiver.interface.encodeFunctionData('fnUnrestricted'), + }); + + this.fallback = prepareOperation({ + sender: this.mock.target, + target: this.receiver.target, + data: '0x1234', + }); + }); + + it('accepts ether transfers', async function () { + await this.admin.sendTransaction({ to: this.mock, value: 1n }); + }); + + it('post deployment check', async function () { + expect(await this.mock.name()).to.equal(name); + expect(await this.mock.token()).to.equal(this.token); + expect(await this.mock.votingDelay()).to.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.equal(votingPeriod); + expect(await this.mock.quorum(0n)).to.equal(0n); + + expect(await this.mock.accessManager()).to.equal(this.manager); + }); + + it('sets base delay (seconds)', async function () { + const baseDelay = time.duration.hours(10n); + + // Only through governance + await expect(this.mock.connect(this.voter1).setBaseDelaySeconds(baseDelay)) + .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') + .withArgs(this.voter1); + + this.proposal = await this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('setBaseDelaySeconds', [baseDelay]), + }, + ], + 'descr', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.execute()).to.emit(this.mock, 'BaseDelaySet').withArgs(0n, baseDelay); + + expect(await this.mock.baseDelaySeconds()).to.equal(baseDelay); + }); + + it('sets access manager ignored', async function () { + const selectors = ['0x12345678', '0x87654321', '0xabcdef01']; + + // Only through governance + await expect(this.mock.connect(this.voter1).setAccessManagerIgnored(this.other, selectors, true)) + .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') + .withArgs(this.voter1); + + // Ignore + await this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('setAccessManagerIgnored', [ + this.other.address, + selectors, + true, + ]), + }, + ], + 'descr', + ); + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + const ignoreReceipt = this.helper.execute(); + for (const selector of selectors) { + await expect(ignoreReceipt) + .to.emit(this.mock, 'AccessManagerIgnoredSet') + .withArgs(this.other, selector, true); + expect(await this.mock.isAccessManagerIgnored(this.other, selector)).to.be.true; + } + + // Unignore + await this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('setAccessManagerIgnored', [ + this.other.address, + selectors, + false, + ]), + }, + ], + 'descr', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + const unignoreReceipt = this.helper.execute(); + for (const selector of selectors) { + await expect(unignoreReceipt) + .to.emit(this.mock, 'AccessManagerIgnoredSet') + .withArgs(this.other, selector, false); + expect(await this.mock.isAccessManagerIgnored(this.other, selector)).to.be.false; + } + }); + + it('sets access manager ignored when target is the governor', async function () { + const selectors = ['0x12345678', '0x87654321', '0xabcdef01']; + + await this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('setAccessManagerIgnored', [ + this.mock.target, + selectors, + true, + ]), + }, + ], + 'descr', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + const tx = this.helper.execute(); + for (const selector of selectors) { + await expect(tx).to.emit(this.mock, 'AccessManagerIgnoredSet').withArgs(this.mock, selector, true); + expect(await this.mock.isAccessManagerIgnored(this.mock, selector)).to.be.true; + } + }); + + it('does not need to queue proposals with no delay', async function () { + const roleId = 1n; + const executionDelay = 0n; + const baseDelay = 0n; + + // Set execution delay + await this.manager.connect(this.admin).setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); + await this.manager.connect(this.admin).grantRole(roleId, this.mock, executionDelay); + + // Set base delay + await this.mock.$_setBaseDelaySeconds(baseDelay); + + await this.helper.setProposal([this.restricted.operation], 'descr'); + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.helper.currentProposal.id)).to.be.false; + }); + + it('needs to queue proposals with any delay', async function () { + const roleId = 1n; + const delays = [ + [time.duration.hours(1n), time.duration.hours(2n)], + [time.duration.hours(2n), time.duration.hours(1n)], + ]; + + for (const [executionDelay, baseDelay] of delays) { + // Set execution delay + await this.manager + .connect(this.admin) + .setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); + await this.manager.connect(this.admin).grantRole(roleId, this.mock, executionDelay); + + // Set base delay + await this.mock.$_setBaseDelaySeconds(baseDelay); + + await this.helper.setProposal( + [this.restricted.operation], + `executionDelay=${executionDelay.toString()}}baseDelay=${baseDelay.toString()}}`, + ); + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.helper.currentProposal.id)).to.be.true; + } + }); + + describe('execution plan', function () { + it('returns plan for delayed operations', async function () { + const roleId = 1n; + const delays = [ + [time.duration.hours(1n), time.duration.hours(2n)], + [time.duration.hours(2n), time.duration.hours(1n)], + ]; + + for (const [executionDelay, baseDelay] of delays) { + // Set execution delay + await this.manager + .connect(this.admin) + .setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); + await this.manager.connect(this.admin).grantRole(roleId, this.mock, executionDelay); + + // Set base delay + await this.mock.$_setBaseDelaySeconds(baseDelay); + + this.proposal = await this.helper.setProposal( + [this.restricted.operation], + `executionDelay=${executionDelay.toString()}}baseDelay=${baseDelay.toString()}}`, + ); + await this.helper.propose(); + + expect(await this.mock.proposalExecutionPlan(this.proposal.id)).to.deep.equal([ + max(baseDelay, executionDelay), + [true], + [true], + ]); + } + }); + + it('returns plan for not delayed operations', async function () { + const roleId = 1n; + const executionDelay = 0n; + const baseDelay = 0n; + + // Set execution delay + await this.manager + .connect(this.admin) + .setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); + await this.manager.connect(this.admin).grantRole(roleId, this.mock, executionDelay); + + // Set base delay + await this.mock.$_setBaseDelaySeconds(baseDelay); + + this.proposal = await this.helper.setProposal([this.restricted.operation], `descr`); + await this.helper.propose(); + + expect(await this.mock.proposalExecutionPlan(this.proposal.id)).to.deep.equal([0n, [true], [false]]); + }); + + it('returns plan for an operation ignoring the manager', async function () { + await this.mock.$_setAccessManagerIgnored(this.receiver, this.restricted.selector, true); + + const roleId = 1n; + const delays = [ + [time.duration.hours(1n), time.duration.hours(2n)], + [time.duration.hours(2n), time.duration.hours(1n)], + ]; + + for (const [executionDelay, baseDelay] of delays) { + // Set execution delay + await this.manager + .connect(this.admin) + .setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); + await this.manager.connect(this.admin).grantRole(roleId, this.mock, executionDelay); + + // Set base delay + await this.mock.$_setBaseDelaySeconds(baseDelay); + + this.proposal = await this.helper.setProposal( + [this.restricted.operation], + `executionDelay=${executionDelay.toString()}}baseDelay=${baseDelay.toString()}}`, + ); + await this.helper.propose(); + + expect(await this.mock.proposalExecutionPlan(this.proposal.id)).to.deep.equal([ + baseDelay, + [false], + [false], + ]); + } + }); + }); + + 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(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + if (await this.mock.proposalNeedsQueuing(this.proposal.id)) { + expect(await this.helper.queue()) + .to.emit(this.mock, 'ProposalQueued') + .withArgs(this.proposal.id, anyValue); + } + if (delay > 0) { + await this.helper.waitForEta(); + } + await expect(this.helper.execute()) + .to.emit(this.mock, 'ProposalExecuted') + .withArgs(this.proposal.id) + .to.emit(this.receiver, 'CalledUnrestricted'); + }); + } + }); + + it('reverts when an operation is executed before eta', async function () { + const delay = time.duration.hours(2n); + await this.mock.$_setBaseDelaySeconds(delay); + + this.proposal = await this.helper.setProposal([this.unrestricted.operation], 'descr'); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnmetDelay') + .withArgs(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(2n); + const roleId = 1n; + + await this.manager.connect(this.admin).setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); + await this.manager.connect(this.admin).grantRole(roleId, this.mock, delay); + + // 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(); + await original.waitForSnapshot(); + await original.connect(this.voter1).vote({ support: VoteType.For }); + await original.waitForDeadline(); + await original.queue(); + await original.waitForEta(); + + // Suddenly cancel one of the proposed operations in the manager + await this.manager + .connect(this.admin) + .cancel(this.mock, this.restricted.operation.target, this.restricted.operation.data); + + // 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.connect(this.voter1).vote({ support: VoteType.For }); + await rescheduled.waitForDeadline(); + await rescheduled.queue(); // This will schedule it again in the manager + await rescheduled.waitForEta(); + + // Attempt to execute + await expect(original.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorMismatchedNonce') + .withArgs(original.currentProposal.id, 1, 2); + }); + + it('single operation with access manager delay', async function () { + const delay = 1000n; + const roleId = 1n; + + await this.manager.connect(this.admin).setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); + await this.manager.connect(this.admin).grantRole(roleId, this.mock, delay); + + this.proposal = await this.helper.setProposal([this.restricted.operation], 'descr'); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + const txQueue = await this.helper.queue(); + await this.helper.waitForEta(); + const txExecute = await this.helper.execute(); + + await expect(txQueue) + .to.emit(this.mock, 'ProposalQueued') + .withArgs(this.proposal.id, anyValue) + .to.emit(this.manager, 'OperationScheduled') + .withArgs( + this.restricted.id, + 1n, + (await time.clockFromReceipt.timestamp(txQueue)) + delay, + this.mock.target, + this.restricted.operation.target, + this.restricted.operation.data, + ); + + await expect(txExecute) + .to.emit(this.mock, 'ProposalExecuted') + .withArgs(this.proposal.id) + .to.emit(this.manager, 'OperationExecuted') + .withArgs(this.restricted.id, 1n) + .to.emit(this.receiver, 'CalledRestricted'); + }); + + it('bundle of varied operations', async function () { + const managerDelay = 1000n; + const roleId = 1n; + const baseDelay = managerDelay * 2n; + + await this.mock.$_setBaseDelaySeconds(baseDelay); + + await this.manager.connect(this.admin).setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); + await this.manager.connect(this.admin).grantRole(roleId, this.mock, managerDelay); + + this.proposal = await this.helper.setProposal( + [this.restricted.operation, this.unrestricted.operation, this.fallback.operation], + 'descr', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + const txQueue = await this.helper.queue(); + await this.helper.waitForEta(); + const txExecute = await this.helper.execute(); + + await expect(txQueue) + .to.emit(this.mock, 'ProposalQueued') + .withArgs(this.proposal.id, anyValue) + .to.emit(this.manager, 'OperationScheduled') + .withArgs( + this.restricted.id, + 1n, + (await time.clockFromReceipt.timestamp(txQueue)) + baseDelay, + this.mock.target, + this.restricted.operation.target, + this.restricted.operation.data, + ); + + await expect(txExecute) + .to.emit(this.mock, 'ProposalExecuted') + .withArgs(this.proposal.id) + .to.emit(this.manager, 'OperationExecuted') + .withArgs(this.restricted.id, 1n) + .to.emit(this.receiver, 'CalledRestricted') + .to.emit(this.receiver, 'CalledUnrestricted') + .to.emit(this.receiver, 'CalledFallback'); + }); + + describe('cancel', function () { + const delay = 1000n; + const roleId = 1n; + + beforeEach(async function () { + await this.manager + .connect(this.admin) + .setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); + await this.manager.connect(this.admin).grantRole(roleId, this.mock, delay); + }); + + it('cancels restricted with delay after queue (internal)', async function () { + this.proposal = await this.helper.setProposal([this.restricted.operation], 'descr'); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + await expect(this.helper.cancel('internal')) + .to.emit(this.mock, 'ProposalCanceled') + .withArgs(this.proposal.id) + .to.emit(this.manager, 'OperationCanceled') + .withArgs(this.restricted.id, 1n); + + await this.helper.waitForEta(); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Canceled, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, 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(); + await original.waitForSnapshot(); + await original.connect(this.voter1).vote({ support: VoteType.For }); + await original.waitForDeadline(); + await original.queue(); + + // Cancel the operation in the manager + await this.manager + .connect(this.admin) + .cancel(this.mock, this.restricted.operation.target, this.restricted.operation.data); + + // 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.connect(this.voter1).vote({ support: VoteType.For }); + await rescheduled.waitForDeadline(); + await rescheduled.queue(); // This will schedule it again in the manager + + // Cancel + const eta = await this.mock.proposalEta(rescheduled.currentProposal.id); + + await expect(original.cancel('internal')) + .to.emit(this.mock, 'ProposalCanceled') + .withArgs(original.currentProposal.id); + + await time.clock.timestamp().then(clock => time.increaseTo.timestamp(max(clock + 1n, eta))); + + await expect(original.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + original.currentProposal.id, + ProposalState.Canceled, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + + it('cancels unrestricted with queueing (internal)', async function () { + this.proposal = await this.helper.setProposal([this.unrestricted.operation], 'descr'); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + const eta = await this.mock.proposalEta(this.proposal.id); + + await expect(this.helper.cancel('internal')) + .to.emit(this.mock, 'ProposalCanceled') + .withArgs(this.proposal.id); + + await time.clock.timestamp().then(clock => time.increaseTo.timestamp(max(clock + 1n, eta))); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Canceled, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + + it('cancels unrestricted without queueing (internal)', async function () { + this.proposal = await this.helper.setProposal([this.unrestricted.operation], 'descr'); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.cancel('internal')) + .to.emit(this.mock, 'ProposalCanceled') + .withArgs(this.proposal.id); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Canceled, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + + it('cancels calls already canceled by guardian', async function () { + const operationA = { target: this.receiver.target, data: this.restricted.selector + '00' }; + const operationB = { target: this.receiver.target, data: this.restricted.selector + '01' }; + const operationC = { target: this.receiver.target, data: this.restricted.selector + '02' }; + const operationAId = hashOperation(this.mock.target, operationA.target, operationA.data); + const operationBId = hashOperation(this.mock.target, 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.connect(this.voter1).vote({ support: VoteType.For }); + await p.waitForDeadline(); + } + + // Can queue the first proposal + await proposal1.queue(); + + // Cannot queue the second proposal: operation A already scheduled with delay + await expect(proposal2.queue()) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerAlreadyScheduled') + .withArgs(operationAId); + + // Admin cancels operation B on the manager + await this.manager.connect(this.admin).cancel(this.mock, operationB.target, operationB.data); + + // Still cannot queue the second proposal: operation A already scheduled with delay + await expect(proposal2.queue()) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerAlreadyScheduled') + .withArgs(operationAId); + + await proposal1.waitForEta(); + + // Cannot execute first proposal: operation B has been canceled + await expect(proposal1.execute()) + .to.be.revertedWithCustomError(this.manager, 'AccessManagerNotScheduled') + .withArgs(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, this.restricted.selector)).to.be.false; + expect(await this.mock.isAccessManagerIgnored(this.mock, '0x12341234')).to.be.true; + }); + + it('internal setter', async function () { + await expect(this.mock.$_setAccessManagerIgnored(this.receiver, this.restricted.selector, true)) + .to.emit(this.mock, 'AccessManagerIgnoredSet') + .withArgs(this.receiver, this.restricted.selector, true); + + expect(await this.mock.isAccessManagerIgnored(this.receiver, this.restricted.selector)).to.be.true; + + await expect(this.mock.$_setAccessManagerIgnored(this.mock, '0x12341234', false)) + .to.emit(this.mock, 'AccessManagerIgnoredSet') + .withArgs(this.mock, '0x12341234', false); + + expect(await this.mock.isAccessManagerIgnored(this.mock, '0x12341234')).to.be.false; + }); + + it('external setter', async function () { + const setAccessManagerIgnored = (...args) => + this.mock.interface.encodeFunctionData('setAccessManagerIgnored', args); + + await this.helper.setProposal( + [ + { + target: this.mock.target, + data: setAccessManagerIgnored( + this.receiver.target, + [this.restricted.selector, this.unrestricted.selector], + true, + ), + }, + { + target: this.mock.target, + data: setAccessManagerIgnored(this.mock.target, ['0x12341234', '0x67896789'], false), + }, + ], + 'descr', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.execute()).to.emit(this.mock, 'AccessManagerIgnoredSet'); + + expect(await this.mock.isAccessManagerIgnored(this.receiver, this.restricted.selector)).to.be.true; + expect(await this.mock.isAccessManagerIgnored(this.receiver, this.unrestricted.selector)).to.be.true; + expect(await this.mock.isAccessManagerIgnored(this.mock, '0x12341234')).to.be.false; + expect(await this.mock.isAccessManagerIgnored(this.mock, '0x67896789')).to.be.false; + }); + + it('locked function', async function () { + const setAccessManagerIgnored = selector('setAccessManagerIgnored(address,bytes4[],bool)'); + + await expect( + this.mock.$_setAccessManagerIgnored(this.mock, setAccessManagerIgnored, true), + ).to.be.revertedWithCustomError(this.mock, 'GovernorLockedIgnore'); + + await this.mock.$_setAccessManagerIgnored(this.receiver, setAccessManagerIgnored, true); + }); + + it('ignores access manager', async function () { + const amount = 100n; + const target = this.token.target; + const data = this.token.interface.encodeFunctionData('transfer', [this.voter4.address, amount]); + const selector = data.slice(0, 10); + await this.token.$_mint(this.mock, amount); + + const roleId = 1n; + await this.manager.connect(this.admin).setTargetFunctionRole(target, [selector], roleId); + await this.manager.connect(this.admin).grantRole(roleId, this.mock, 0); + + await this.helper.setProposal([{ target, data }], 'descr #1'); + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') + .withArgs(this.manager, 0n, amount); + + await this.mock.$_setAccessManagerIgnored(target, selector, true); + + await this.helper.setProposal([{ target, data }], 'descr #2'); + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.execute()).to.emit(this.token, 'Transfer').withArgs(this.mock, this.voter4, amount); + }); + }); + + describe('operating on an Ownable contract', function () { + const method = selector('$_checkOwner()'); + + beforeEach(async function () { + this.ownable = await ethers.deployContract('$Ownable', [this.manager]); + this.operation = { + target: this.ownable.target, + data: this.ownable.interface.encodeFunctionData('$_checkOwner'), + }; + }); + + it('succeeds with delay', async function () { + const roleId = 1n; + const executionDelay = time.duration.hours(2n); + const baseDelay = time.duration.hours(1n); + + // Set execution delay + await this.manager.connect(this.admin).setTargetFunctionRole(this.ownable, [method], roleId); + await this.manager.connect(this.admin).grantRole(roleId, this.mock, executionDelay); + + // Set base delay + await this.mock.$_setBaseDelaySeconds(baseDelay); + + await this.helper.setProposal([this.operation], `descr`); + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + await this.helper.execute(); // Don't revert + }); + + it('succeeds without delay', async function () { + const roleId = 1n; + const executionDelay = 0n; + const baseDelay = 0n; + + // Set execution delay + await this.manager.connect(this.admin).setTargetFunctionRole(this.ownable, [method], roleId); + await this.manager.connect(this.admin).grantRole(roleId, this.mock, executionDelay); + + // Set base delay + await this.mock.$_setBaseDelaySeconds(baseDelay); + + await this.helper.setProposal([this.operation], `descr`); + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.execute(); // Don't revert + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js new file mode 100644 index 0000000..cd82481 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js @@ -0,0 +1,448 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); + +const { GovernorHelper } = require('../../helpers/governance'); +const { ProposalState, VoteType } = require('../../helpers/enums'); +const time = require('../../helpers/time'); + +const TOKENS = [ + { Token: '$ERC20Votes', mode: 'blocknumber' }, + { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, +]; + +const name = 'OZ-Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const votingDelay = 4n; +const votingPeriod = 16n; +const value = ethers.parseEther('1'); +const defaultDelay = time.duration.days(2n); + +describe('GovernorTimelockCompound', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [deployer, owner, voter1, voter2, voter3, voter4, other] = await ethers.getSigners(); + const receiver = await ethers.deployContract('CallReceiverMock'); + + const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); + const predictGovernor = await deployer + .getNonce() + .then(nonce => ethers.getCreateAddress({ from: deployer.address, nonce: nonce + 1 })); + const timelock = await ethers.deployContract('CompTimelock', [predictGovernor, defaultDelay]); + const mock = await ethers.deployContract('$GovernorTimelockCompoundMock', [ + name, + votingDelay, + votingPeriod, + 0n, + timelock, + token, + 0n, + ]); + + await owner.sendTransaction({ to: timelock, value }); + await token.$_mint(owner, tokenSupply); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); + await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); + await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); + await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); + + return { deployer, owner, voter1, voter2, voter3, voter4, other, receiver, token, mock, timelock, helper }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + value, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + }, + ], + '', + ); + }); + + it("doesn't accept ether transfers", async function () { + await expect(this.owner.sendTransaction({ to: this.mock, value: 1n })).to.be.revertedWithCustomError( + this.mock, + 'GovernorDisabledDeposit', + ); + }); + + it('post deployment check', async function () { + expect(await this.mock.name()).to.equal(name); + expect(await this.mock.token()).to.equal(this.token); + expect(await this.mock.votingDelay()).to.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.equal(votingPeriod); + expect(await this.mock.quorum(0n)).to.equal(0n); + + expect(await this.mock.timelock()).to.equal(this.timelock); + expect(await this.timelock.admin()).to.equal(this.mock); + }); + + it('nominal', async function () { + expect(await this.mock.proposalEta(this.proposal.id)).to.equal(0n); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.true; + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.connect(this.voter2).vote({ support: VoteType.For }); + await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); + await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }); + await this.helper.waitForDeadline(); + const txQueue = await this.helper.queue(); + + const eta = (await time.clockFromReceipt.timestamp(txQueue)) + defaultDelay; + expect(await this.mock.proposalEta(this.proposal.id)).to.equal(eta); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.true; + + await this.helper.waitForEta(); + const txExecute = await this.helper.execute(); + + await expect(txQueue) + .to.emit(this.mock, 'ProposalQueued') + .withArgs(this.proposal.id, eta) + .to.emit(this.timelock, 'QueueTransaction') + .withArgs(...Array(5).fill(anyValue), eta); + + await expect(txExecute) + .to.emit(this.mock, 'ProposalExecuted') + .withArgs(this.proposal.id) + .to.emit(this.timelock, 'ExecuteTransaction') + .withArgs(...Array(5).fill(anyValue), eta) + .to.emit(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.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await expect(this.helper.queue()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Queued, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded]), + ); + }); + + it('if proposal contains duplicate calls', async function () { + const action = { + target: this.token.target, + data: this.token.interface.encodeFunctionData('approve', [this.receiver.target, ethers.MaxUint256]), + }; + const { id } = this.helper.setProposal([action, action], ''); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await expect(this.helper.queue()) + .to.be.revertedWithCustomError(this.mock, 'GovernorAlreadyQueuedProposal') + .withArgs(id); + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorNotQueuedProposal') + .withArgs(id); + }); + }); + + describe('on execute', function () { + it('if not queued', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(1n); + + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Succeeded); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorNotQueuedProposal') + .withArgs(this.proposal.id); + }); + + it('if too early', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Queued); + + await expect(this.helper.execute()).to.be.rejectedWith( + "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.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(time.duration.days(30)); + + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Expired); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Expired, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + + it('if already executed', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + await this.helper.execute(); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Executed, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + }); + + describe('on safe receive', function () { + describe('ERC721', function () { + const tokenId = 1n; + + beforeEach(async function () { + this.token = await ethers.deployContract('$ERC721', ['Non Fungible Token', 'NFT']); + await this.token.$_mint(this.owner, tokenId); + }); + + it("can't receive an ERC721 safeTransfer", async function () { + await expect( + this.token.connect(this.owner).safeTransferFrom(this.owner, this.mock, tokenId), + ).to.be.revertedWithCustomError(this.mock, 'GovernorDisabledDeposit'); + }); + }); + + describe('ERC1155', function () { + const tokenIds = { + 1: 1000n, + 2: 2000n, + 3: 3000n, + }; + + beforeEach(async function () { + this.token = await ethers.deployContract('$ERC1155', ['https://token-cdn-domain/{id}.json']); + await this.token.$_mintBatch(this.owner, Object.keys(tokenIds), Object.values(tokenIds), '0x'); + }); + + it("can't receive ERC1155 safeTransfer", async function () { + await expect( + this.token.connect(this.owner).safeTransferFrom( + this.owner, + this.mock, + ...Object.entries(tokenIds)[0], // id + amount + '0x', + ), + ).to.be.revertedWithCustomError(this.mock, 'GovernorDisabledDeposit'); + }); + + it("can't receive ERC1155 safeBatchTransfer", async function () { + await expect( + this.token + .connect(this.owner) + .safeBatchTransferFrom(this.owner, this.mock, Object.keys(tokenIds), Object.values(tokenIds), '0x'), + ).to.be.revertedWithCustomError(this.mock, 'GovernorDisabledDeposit'); + }); + }); + }); + }); + + describe('cancel', function () { + it('cancel before queue prevents scheduling', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.cancel('internal')) + .to.emit(this.mock, 'ProposalCanceled') + .withArgs(this.proposal.id); + + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled); + + await expect(this.helper.queue()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Canceled, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded]), + ); + }); + + it('cancel after queue prevents executing', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + await expect(this.helper.cancel('internal')) + .to.emit(this.mock, 'ProposalCanceled') + .withArgs(this.proposal.id); + + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Canceled, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + }); + + describe('onlyGovernance', function () { + describe('relay', function () { + beforeEach(async function () { + await this.token.$_mint(this.mock, 1); + }); + + it('is protected', async function () { + await expect( + this.mock + .connect(this.owner) + .relay(this.token, 0, this.token.interface.encodeFunctionData('transfer', [this.other.address, 1n])), + ) + .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') + .withArgs(this.owner); + }); + + it('can be executed through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('relay', [ + this.token.target, + 0n, + this.token.interface.encodeFunctionData('transfer', [this.other.address, 1n]), + ]), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + + const txExecute = this.helper.execute(); + + await expect(txExecute).to.changeTokenBalances(this.token, [this.mock, this.other], [-1n, 1n]); + + await expect(txExecute).to.emit(this.token, 'Transfer').withArgs(this.mock, this.other, 1n); + }); + }); + + describe('updateTimelock', function () { + beforeEach(async function () { + this.newTimelock = await ethers.deployContract('CompTimelock', [this.mock, time.duration.days(7n)]); + }); + + it('is protected', async function () { + await expect(this.mock.connect(this.owner).updateTimelock(this.newTimelock)) + .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') + .withArgs(this.owner); + }); + + it('can be executed through governance to', async function () { + this.helper.setProposal( + [ + { + target: this.timelock.target, + data: this.timelock.interface.encodeFunctionData('setPendingAdmin', [this.owner.address]), + }, + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('updateTimelock', [this.newTimelock.target]), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + + await expect(this.helper.execute()) + .to.emit(this.mock, 'TimelockChange') + .withArgs(this.timelock, this.newTimelock); + + expect(await this.mock.timelock()).to.equal(this.newTimelock); + }); + }); + + it('can transfer timelock to new governor', async function () { + const newGovernor = await ethers.deployContract('$GovernorTimelockCompoundMock', [ + name, + 8n, + 32n, + 0n, + this.timelock, + this.token, + 0n, + ]); + + this.helper.setProposal( + [ + { + target: this.timelock.target, + data: this.timelock.interface.encodeFunctionData('setPendingAdmin', [newGovernor.target]), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + + await expect(this.helper.execute()).to.emit(this.timelock, 'NewPendingAdmin').withArgs(newGovernor); + + await newGovernor.__acceptAdmin(); + expect(await this.timelock.admin()).to.equal(newGovernor); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js new file mode 100644 index 0000000..507c7e2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js @@ -0,0 +1,504 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +const { GovernorHelper, timelockSalt } = require('../../helpers/governance'); +const { OperationState, ProposalState, VoteType } = require('../../helpers/enums'); +const time = require('../../helpers/time'); + +const TOKENS = [ + { Token: '$ERC20Votes', mode: 'blocknumber' }, + { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, +]; + +const DEFAULT_ADMIN_ROLE = ethers.ZeroHash; +const PROPOSER_ROLE = ethers.id('PROPOSER_ROLE'); +const EXECUTOR_ROLE = ethers.id('EXECUTOR_ROLE'); +const CANCELLER_ROLE = ethers.id('CANCELLER_ROLE'); + +const name = 'OZ-Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const votingDelay = 4n; +const votingPeriod = 16n; +const value = ethers.parseEther('1'); +const delay = time.duration.hours(1n); + +describe('GovernorTimelockControl', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [deployer, owner, voter1, voter2, voter3, voter4, other] = await ethers.getSigners(); + const receiver = await ethers.deployContract('CallReceiverMock'); + + const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); + const timelock = await ethers.deployContract('TimelockController', [delay, [], [], deployer]); + const mock = await ethers.deployContract('$GovernorTimelockControlMock', [ + name, + votingDelay, + votingPeriod, + 0n, + timelock, + token, + 0n, + ]); + + await owner.sendTransaction({ to: timelock, value }); + await token.$_mint(owner, tokenSupply); + await timelock.grantRole(PROPOSER_ROLE, mock); + await timelock.grantRole(PROPOSER_ROLE, owner); + await timelock.grantRole(CANCELLER_ROLE, mock); + await timelock.grantRole(CANCELLER_ROLE, owner); + await timelock.grantRole(EXECUTOR_ROLE, ethers.ZeroAddress); + await timelock.revokeRole(DEFAULT_ADMIN_ROLE, deployer); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); + await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); + await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); + await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); + + return { deployer, owner, voter1, voter2, voter3, voter4, other, receiver, token, mock, timelock, helper }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + value, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + }, + ], + '', + ); + + this.proposal.timelockid = await this.timelock.hashOperationBatch( + ...this.proposal.shortProposal.slice(0, 3), + ethers.ZeroHash, + timelockSalt(this.mock.target, this.proposal.shortProposal[3]), + ); + }); + + it("doesn't accept ether transfers", async function () { + await expect(this.owner.sendTransaction({ to: this.mock, value: 1n })).to.be.revertedWithCustomError( + this.mock, + 'GovernorDisabledDeposit', + ); + }); + + it('post deployment check', async function () { + expect(await this.mock.name()).to.equal(name); + expect(await this.mock.token()).to.equal(this.token); + expect(await this.mock.votingDelay()).to.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.equal(votingPeriod); + expect(await this.mock.quorum(0n)).to.equal(0n); + + expect(await this.mock.timelock()).to.equal(this.timelock); + }); + + it('nominal', async function () { + expect(await this.mock.proposalEta(this.proposal.id)).to.equal(0n); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.true; + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.connect(this.voter2).vote({ support: VoteType.For }); + await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); + await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }); + await this.helper.waitForDeadline(); + + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.true; + const txQueue = await this.helper.queue(); + + const eta = (await time.clockFromReceipt.timestamp(txQueue)) + delay; + expect(await this.mock.proposalEta(this.proposal.id)).to.equal(eta); + await this.helper.waitForEta(); + + const txExecute = this.helper.execute(); + + await expect(txQueue) + .to.emit(this.mock, 'ProposalQueued') + .withArgs(this.proposal.id, anyValue) + .to.emit(this.timelock, 'CallScheduled') + .withArgs(this.proposal.timelockid, ...Array(6).fill(anyValue)) + .to.emit(this.timelock, 'CallSalt') + .withArgs(this.proposal.timelockid, anyValue); + + await expect(txExecute) + .to.emit(this.mock, 'ProposalExecuted') + .withArgs(this.proposal.id) + .to.emit(this.timelock, 'CallExecuted') + .withArgs(this.proposal.timelockid, ...Array(4).fill(anyValue)) + .to.emit(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.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await expect(this.helper.queue()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Queued, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded]), + ); + }); + }); + + describe('on execute', function () { + it('if not queued', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(1n); + + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Succeeded); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.timelock, 'TimelockUnexpectedOperationState') + .withArgs(this.proposal.timelockid, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); + }); + + it('if too early', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Queued); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.timelock, 'TimelockUnexpectedOperationState') + .withArgs(this.proposal.timelockid, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); + }); + + it('if already executed', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + await this.helper.execute(); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Executed, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + + it('if already executed by another proposer', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + + await this.timelock.executeBatch( + ...this.proposal.shortProposal.slice(0, 3), + ethers.ZeroHash, + timelockSalt(this.mock.target, this.proposal.shortProposal[3]), + ); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Executed, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + }); + }); + + describe('cancel', function () { + it('cancel before queue prevents scheduling', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.cancel('internal')) + .to.emit(this.mock, 'ProposalCanceled') + .withArgs(this.proposal.id); + + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled); + + await expect(this.helper.queue()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Canceled, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded]), + ); + }); + + it('cancel after queue prevents executing', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + await expect(this.helper.cancel('internal')) + .to.emit(this.mock, 'ProposalCanceled') + .withArgs(this.proposal.id); + + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Canceled, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + + it('cancel on timelock is reflected on governor', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Queued); + + await expect(this.timelock.connect(this.owner).cancel(this.proposal.timelockid)) + .to.emit(this.timelock, 'Cancelled') + .withArgs(this.proposal.timelockid); + + expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled); + }); + }); + + describe('onlyGovernance', function () { + describe('relay', function () { + beforeEach(async function () { + await this.token.$_mint(this.mock, 1); + }); + + it('is protected', async function () { + await expect( + this.mock + .connect(this.owner) + .relay(this.token, 0n, this.token.interface.encodeFunctionData('transfer', [this.other.address, 1n])), + ) + .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') + .withArgs(this.owner); + }); + + it('can be executed through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('relay', [ + this.token.target, + 0n, + this.token.interface.encodeFunctionData('transfer', [this.other.address, 1n]), + ]), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + + const txExecute = await this.helper.execute(); + + await expect(txExecute).to.changeTokenBalances(this.token, [this.mock, this.other], [-1n, 1n]); + + await expect(txExecute).to.emit(this.token, 'Transfer').withArgs(this.mock, this.other, 1n); + }); + + it('is payable and can transfer eth to EOA', async function () { + const t2g = 128n; // timelock to governor + const g2o = 100n; // governor to eoa (other) + + this.helper.setProposal( + [ + { + target: this.mock.target, + value: t2g, + data: this.mock.interface.encodeFunctionData('relay', [this.other.address, g2o, '0x']), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + + await expect(this.helper.execute()).to.changeEtherBalances( + [this.timelock, this.mock, this.other], + [-t2g, t2g - g2o, g2o], + ); + }); + + it('protected against other proposers', async function () { + const call = [ + this.mock, + 0n, + this.mock.interface.encodeFunctionData('relay', [ethers.ZeroAddress, 0n, '0x']), + ethers.ZeroHash, + ethers.ZeroHash, + ]; + + await this.timelock.connect(this.owner).schedule(...call, delay); + + await time.increaseBy.timestamp(delay); + + // Error bubbled up from Governor + await expect(this.timelock.connect(this.owner).execute(...call)).to.be.revertedWithPanic( + PANIC_CODES.POP_ON_EMPTY_ARRAY, + ); + }); + }); + + describe('updateTimelock', function () { + beforeEach(async function () { + this.newTimelock = await ethers.deployContract('TimelockController', [ + delay, + [this.mock], + [this.mock], + ethers.ZeroAddress, + ]); + }); + + it('is protected', async function () { + await expect(this.mock.connect(this.owner).updateTimelock(this.newTimelock)) + .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') + .withArgs(this.owner); + }); + + it('can be executed through governance to', async function () { + this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('updateTimelock', [this.newTimelock.target]), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + + await expect(this.helper.execute()) + .to.emit(this.mock, 'TimelockChange') + .withArgs(this.timelock, this.newTimelock); + + expect(await this.mock.timelock()).to.equal(this.newTimelock); + }); + }); + + describe('on safe receive', function () { + describe('ERC721', function () { + const tokenId = 1n; + + beforeEach(async function () { + this.token = await ethers.deployContract('$ERC721', ['Non Fungible Token', 'NFT']); + await this.token.$_mint(this.owner, tokenId); + }); + + it("can't receive an ERC721 safeTransfer", async function () { + await expect( + this.token.connect(this.owner).safeTransferFrom(this.owner, this.mock, tokenId), + ).to.be.revertedWithCustomError(this.mock, 'GovernorDisabledDeposit'); + }); + }); + + describe('ERC1155', function () { + const tokenIds = { + 1: 1000n, + 2: 2000n, + 3: 3000n, + }; + + beforeEach(async function () { + this.token = await ethers.deployContract('$ERC1155', ['https://token-cdn-domain/{id}.json']); + await this.token.$_mintBatch(this.owner, Object.keys(tokenIds), Object.values(tokenIds), '0x'); + }); + + it("can't receive ERC1155 safeTransfer", async function () { + await expect( + this.token.connect(this.owner).safeTransferFrom( + this.owner, + this.mock, + ...Object.entries(tokenIds)[0], // id + amount + '0x', + ), + ).to.be.revertedWithCustomError(this.mock, 'GovernorDisabledDeposit'); + }); + + it("can't receive ERC1155 safeBatchTransfer", async function () { + await expect( + this.token + .connect(this.owner) + .safeBatchTransferFrom(this.owner, this.mock, Object.keys(tokenIds), Object.values(tokenIds), '0x'), + ).to.be.revertedWithCustomError(this.mock, 'GovernorDisabledDeposit'); + }); + }); + }); + }); + + it('clear queue of pending governor calls', async function () { + this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('nonGovernanceFunction'), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js new file mode 100644 index 0000000..99afd39 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js @@ -0,0 +1,165 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers'); + +const { GovernorHelper } = require('../../helpers/governance'); +const { ProposalState, VoteType } = require('../../helpers/enums'); +const time = require('../../helpers/time'); + +const TOKENS = [ + { Token: '$ERC20Votes', mode: 'blocknumber' }, + { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, +]; + +const name = 'OZ-Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const ratio = 8n; // percents +const newRatio = 6n; // percents +const votingDelay = 4n; +const votingPeriod = 16n; +const value = ethers.parseEther('1'); + +describe('GovernorVotesQuorumFraction', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [owner, voter1, voter2, voter3, voter4] = await ethers.getSigners(); + + const receiver = await ethers.deployContract('CallReceiverMock'); + + const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); + const mock = await ethers.deployContract('$GovernorMock', [name, votingDelay, votingPeriod, 0n, token, ratio]); + + await owner.sendTransaction({ to: mock, value }); + await token.$_mint(owner, tokenSupply); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); + await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); + await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); + await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); + + return { owner, voter1, voter2, voter3, voter4, receiver, token, mock, helper }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + value, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + }, + ], + '', + ); + }); + + it('deployment check', async function () { + expect(await this.mock.name()).to.equal(name); + expect(await this.mock.token()).to.equal(this.token); + expect(await this.mock.votingDelay()).to.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.equal(votingPeriod); + expect(await this.mock.quorum(0)).to.equal(0n); + expect(await this.mock.quorumNumerator()).to.equal(ratio); + expect(await this.mock.quorumDenominator()).to.equal(100n); + expect(await time.clock[mode]().then(clock => this.mock.quorum(clock - 1n))).to.equal( + (tokenSupply * ratio) / 100n, + ); + }); + + it('quorum reached', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + }); + + it('quorum not reached', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter2).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') + .withArgs( + this.proposal.id, + ProposalState.Defeated, + GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), + ); + }); + + describe('onlyGovernance updates', function () { + it('updateQuorumNumerator is protected', async function () { + await expect(this.mock.connect(this.owner).updateQuorumNumerator(newRatio)) + .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') + .withArgs(this.owner); + }); + + it('can updateQuorumNumerator through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('updateQuorumNumerator', [newRatio]), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.execute()).to.emit(this.mock, 'QuorumNumeratorUpdated').withArgs(ratio, newRatio); + + expect(await this.mock.quorumNumerator()).to.equal(newRatio); + expect(await this.mock.quorumDenominator()).to.equal(100n); + + // it takes one block for the new quorum to take effect + expect(await time.clock[mode]().then(blockNumber => this.mock.quorum(blockNumber - 1n))).to.equal( + (tokenSupply * ratio) / 100n, + ); + + await mine(); + + expect(await time.clock[mode]().then(blockNumber => this.mock.quorum(blockNumber - 1n))).to.equal( + (tokenSupply * newRatio) / 100n, + ); + }); + + it('cannot updateQuorumNumerator over the maximum', async function () { + const quorumNumerator = 101n; + this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('updateQuorumNumerator', [quorumNumerator]), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + const quorumDenominator = await this.mock.quorumDenominator(); + + await expect(this.helper.execute()) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidQuorumFraction') + .withArgs(quorumNumerator, quorumDenominator); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesSuperQuorumFraction.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesSuperQuorumFraction.test.js new file mode 100644 index 0000000..10a4448 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesSuperQuorumFraction.test.js @@ -0,0 +1,160 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { GovernorHelper } = require('../../helpers/governance'); +const { ProposalState, VoteType } = require('../../helpers/enums'); +const time = require('../../helpers/time'); + +const TOKENS = [ + { Token: '$ERC20Votes', mode: 'blocknumber' }, + { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, +]; + +const name = 'OZ-Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const quorumRatio = 8n; // percents +const superQuorumRatio = 50n; // percents +const newSuperQuorumRatio = 15n; // percents +const votingDelay = 4n; +const votingPeriod = 16n; +const value = ethers.parseEther('1'); + +describe('GovernorVotesSuperQuorumFraction', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [owner, voter1, voter2, voter3, voter4] = await ethers.getSigners(); + const receiver = await ethers.deployContract('CallReceiverMock'); + + const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); + const mock = await ethers.deployContract('$GovernorVotesSuperQuorumFractionMock', [ + name, + votingDelay, + votingPeriod, + 0n, + token, + quorumRatio, + superQuorumRatio, + ]); + + await owner.sendTransaction({ to: mock, value }); + await token.$_mint(owner, tokenSupply); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('30') }); + await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('20') }); + await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('15') }); + await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('5') }); + + return { owner, voter1, voter2, voter3, voter4, receiver, token, mock, helper }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + value, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + }, + ], + '', + ); + }); + + it('deployment check', async function () { + await expect(this.mock.name()).to.eventually.equal(name); + await expect(this.mock.token()).to.eventually.equal(this.token); + await expect(this.mock.votingDelay()).to.eventually.equal(votingDelay); + await expect(this.mock.votingPeriod()).to.eventually.equal(votingPeriod); + await expect(this.mock.quorumNumerator()).to.eventually.equal(quorumRatio); + await expect(this.mock.superQuorumNumerator()).to.eventually.equal(superQuorumRatio); + await expect(this.mock.quorumDenominator()).to.eventually.equal(100n); + await expect(time.clock[mode]().then(clock => this.mock.superQuorum(clock - 1n))).to.eventually.equal( + (tokenSupply * superQuorumRatio) / 100n, + ); + }); + + it('proposal remains active until super quorum is reached', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + + // Vote with voter1 (30%) - above quorum (8%) but below super quorum (50%) + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + + // Check proposal is still active + await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Active); + + // Vote with voter2 (20%) - now matches super quorum + await this.helper.connect(this.voter2).vote({ support: VoteType.For }); + + // Proposal should no longer be active + await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Succeeded); + }); + + describe('super quorum updates', function () { + it('updateSuperQuorumNumerator is protected', async function () { + await expect(this.mock.connect(this.owner).updateSuperQuorumNumerator(newSuperQuorumRatio)) + .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') + .withArgs(this.owner); + }); + + it('can update super quorum through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.target, + data: this.mock.interface.encodeFunctionData('updateSuperQuorumNumerator', [newSuperQuorumRatio]), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For }); + await this.helper.connect(this.voter2).vote({ support: VoteType.For }); + await this.helper.waitForDeadline(); + + await expect(this.helper.execute()) + .to.emit(this.mock, 'SuperQuorumNumeratorUpdated') + .withArgs(superQuorumRatio, newSuperQuorumRatio); + + await expect(this.mock.superQuorumNumerator()).to.eventually.equal(newSuperQuorumRatio); + }); + + it('cannot set super quorum below quorum', async function () { + const invalidSuperQuorum = quorumRatio - 1n; + + await expect(this.mock.$_updateSuperQuorumNumerator(invalidSuperQuorum)) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSuperQuorumTooSmall') + .withArgs(invalidSuperQuorum, quorumRatio); + }); + + it('cannot set super quorum above denominator', async function () { + const denominator = await this.mock.quorumDenominator(); + const invalidSuperQuorum = BigInt(denominator) + 1n; + + await expect(this.mock.$_updateSuperQuorumNumerator(invalidSuperQuorum)) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSuperQuorumFraction') + .withArgs(invalidSuperQuorum, denominator); + }); + + it('cannot set quorum above super quorum', async function () { + const invalidQuorum = superQuorumRatio + 1n; + + await expect(this.mock.$_updateQuorumNumerator(invalidQuorum)) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidQuorumTooLarge') + .withArgs(invalidQuorum, superQuorumRatio); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js new file mode 100644 index 0000000..db19bc6 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js @@ -0,0 +1,245 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { GovernorHelper } = require('../../helpers/governance'); +const { VoteType } = require('../../helpers/enums'); +const { getDomain, ExtendedBallot } = require('../../helpers/eip712'); + +const TOKENS = [ + { Token: '$ERC20Votes', mode: 'blocknumber' }, + { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, +]; + +const name = 'OZ-Governor'; +const version = '1'; +const tokenName = 'MockToken'; +const tokenSymbol = 'MTKN'; +const tokenSupply = ethers.parseEther('100'); +const votingDelay = 4n; +const votingPeriod = 16n; +const value = ethers.parseEther('1'); + +const params = { + decoded: [42n, 'These are my params'], + encoded: ethers.AbiCoder.defaultAbiCoder().encode(['uint256', 'string'], [42n, 'These are my params']), +}; + +describe('GovernorWithParams', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + const [owner, proposer, voter1, voter2, voter3, voter4, other] = await ethers.getSigners(); + const receiver = await ethers.deployContract('CallReceiverMock'); + + const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); + const mock = await ethers.deployContract('$GovernorWithParamsMock', [name, token]); + + await owner.sendTransaction({ to: mock, value }); + await token.$_mint(owner, tokenSupply); + + const helper = new GovernorHelper(mock, mode); + await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); + await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); + await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); + await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); + + return { owner, proposer, voter1, voter2, voter3, voter4, other, receiver, token, mock, helper }; + }; + + describe(`using ${Token}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.target, + value, + data: this.receiver.interface.encodeFunctionData('mockFunction'), + }, + ], + '', + ); + }); + + it('deployment check', async function () { + expect(await this.mock.name()).to.equal(name); + expect(await this.mock.token()).to.equal(this.token); + expect(await this.mock.votingDelay()).to.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.equal(votingPeriod); + }); + + it('nominal is unaffected', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + await this.helper.connect(this.voter1).vote({ support: VoteType.For, reason: 'This is nice' }); + await this.helper.connect(this.voter2).vote({ support: VoteType.For }); + await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); + await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; + expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.true; + expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.true; + expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); + expect(await ethers.provider.getBalance(this.receiver)).to.equal(value); + }); + + it('Voting with params is properly supported', async function () { + await this.helper.connect(this.proposer).propose(); + await this.helper.waitForSnapshot(); + + const weight = ethers.parseEther('7') - params.decoded[0]; + + await expect( + this.helper.connect(this.voter2).vote({ + support: VoteType.For, + reason: 'no particular reason', + params: params.encoded, + }), + ) + .to.emit(this.mock, 'CountParams') + .withArgs(...params.decoded) + .to.emit(this.mock, 'VoteCastWithParams') + .withArgs( + this.voter2.address, + this.proposal.id, + VoteType.For, + weight, + 'no particular reason', + params.encoded, + ); + + expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([0n, weight, 0n]); + }); + + describe('voting by signature', function () { + it('supports EOA signatures', async function () { + await this.token.connect(this.voter2).delegate(this.other); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + + // Prepare vote + const weight = ethers.parseEther('7') - params.decoded[0]; + const nonce = await this.mock.nonces(this.other); + const data = { + proposalId: this.proposal.id, + support: VoteType.For, + voter: this.other.address, + nonce, + reason: 'no particular reason', + params: params.encoded, + signature: (contract, message) => + getDomain(contract).then(domain => this.other.signTypedData(domain, { ExtendedBallot }, message)), + }; + + // Vote + await expect(this.helper.vote(data)) + .to.emit(this.mock, 'CountParams') + .withArgs(...params.decoded) + .to.emit(this.mock, 'VoteCastWithParams') + .withArgs(data.voter, data.proposalId, data.support, weight, data.reason, data.params); + + expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([0n, weight, 0n]); + expect(await this.mock.nonces(this.other)).to.equal(nonce + 1n); + }); + + it('supports EIP-1271 signature signatures', async function () { + const wallet = await ethers.deployContract('ERC1271WalletMock', [this.other]); + await this.token.connect(this.voter2).delegate(wallet); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + + // Prepare vote + const weight = ethers.parseEther('7') - params.decoded[0]; + const nonce = await this.mock.nonces(this.other); + const data = { + proposalId: this.proposal.id, + support: VoteType.For, + voter: wallet.target, + nonce, + reason: 'no particular reason', + params: params.encoded, + signature: (contract, message) => + getDomain(contract).then(domain => this.other.signTypedData(domain, { ExtendedBallot }, message)), + }; + + // Vote + await expect(this.helper.vote(data)) + .to.emit(this.mock, 'CountParams') + .withArgs(...params.decoded) + .to.emit(this.mock, 'VoteCastWithParams') + .withArgs(data.voter, data.proposalId, data.support, weight, data.reason, data.params); + + expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([0n, weight, 0n]); + expect(await this.mock.nonces(wallet)).to.equal(nonce + 1n); + }); + + it('reverts if signature does not match signer', async function () { + await this.token.connect(this.voter2).delegate(this.other); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + + // Prepare vote + const nonce = await this.mock.nonces(this.other); + const data = { + proposalId: this.proposal.id, + support: VoteType.For, + voter: this.other.address, + nonce, + reason: 'no particular reason', + params: params.encoded, + // tampered signature + signature: (contract, message) => + getDomain(contract) + .then(domain => this.other.signTypedData(domain, { ExtendedBallot }, message)) + .then(signature => { + const tamperedSig = ethers.toBeArray(signature); + tamperedSig[42] ^= 0xff; + return ethers.hexlify(tamperedSig); + }), + }; + + // Vote + await expect(this.helper.vote(data)) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') + .withArgs(data.voter); + }); + + it('reverts if vote nonce is incorrect', async function () { + await this.token.connect(this.voter2).delegate(this.other); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + + // Prepare vote + const nonce = await this.mock.nonces(this.other); + const data = { + proposalId: this.proposal.id, + support: VoteType.For, + voter: this.other.address, + nonce: nonce + 1n, + reason: 'no particular reason', + params: params.encoded, + signature: (contract, message) => + getDomain(contract).then(domain => this.other.signTypedData(domain, { ExtendedBallot }, message)), + }; + + // Vote + await expect(this.helper.vote(data)) + .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') + .withArgs(data.voter); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/ERC6372.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/ERC6372.behavior.js new file mode 100644 index 0000000..32f27b5 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/ERC6372.behavior.js @@ -0,0 +1,28 @@ +const { expect } = require('chai'); +const time = require('../../helpers/time'); + +function shouldBehaveLikeERC6372(mode = 'blocknumber') { + describe(`ERC-6372 behavior in ${mode} mode`, function () { + beforeEach(async function () { + this.mock = this.mock ?? this.token ?? this.votes; + }); + + it('should have a correct clock value', async function () { + const currentClock = await this.mock.clock(); + const expectedClock = await time.clock[mode](); + expect(currentClock).to.equal(expectedClock, `Clock mismatch in ${mode} mode`); + }); + + it('should have the correct CLOCK_MODE parameters', async function () { + const clockModeParams = new URLSearchParams(await this.mock.CLOCK_MODE()); + const expectedFromValue = mode === 'blocknumber' ? 'default' : null; + + expect(clockModeParams.get('mode')).to.equal(mode, `Expected mode to be ${mode}`); + expect(clockModeParams.get('from')).to.equal(expectedFromValue, `Expected 'from' to be ${expectedFromValue}`); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC6372, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js new file mode 100644 index 0000000..0997701 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js @@ -0,0 +1,325 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { mine } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain, Delegation } = require('../../helpers/eip712'); +const time = require('../../helpers/time'); + +const { shouldBehaveLikeERC6372 } = require('./ERC6372.behavior'); + +function shouldBehaveLikeVotes(tokens, { mode = 'blocknumber', fungible = true }) { + beforeEach(async function () { + [this.delegator, this.delegatee, this.alice, this.bob, this.other] = this.accounts; + this.domain = await getDomain(this.votes); + }); + + shouldBehaveLikeERC6372(mode); + + const getWeight = token => (fungible ? token : 1n); + + describe('run votes workflow', function () { + it('initial nonce is 0', async function () { + expect(await this.votes.nonces(this.alice)).to.equal(0n); + }); + + describe('delegation with signature', function () { + const token = tokens[0]; + + it('delegation without tokens', async function () { + expect(await this.votes.delegates(this.alice)).to.equal(ethers.ZeroAddress); + + await expect(this.votes.connect(this.alice).delegate(this.alice)) + .to.emit(this.votes, 'DelegateChanged') + .withArgs(this.alice, ethers.ZeroAddress, this.alice) + .to.not.emit(this.votes, 'DelegateVotesChanged'); + + expect(await this.votes.delegates(this.alice)).to.equal(this.alice); + }); + + it('delegation with tokens', async function () { + await this.votes.$_mint(this.alice, token); + const weight = getWeight(token); + + expect(await this.votes.delegates(this.alice)).to.equal(ethers.ZeroAddress); + + const tx = await this.votes.connect(this.alice).delegate(this.alice); + const timepoint = await time.clockFromReceipt[mode](tx); + + await expect(tx) + .to.emit(this.votes, 'DelegateChanged') + .withArgs(this.alice, ethers.ZeroAddress, this.alice) + .to.emit(this.votes, 'DelegateVotesChanged') + .withArgs(this.alice, 0n, weight); + + expect(await this.votes.delegates(this.alice)).to.equal(this.alice); + expect(await this.votes.getVotes(this.alice)).to.equal(weight); + expect(await this.votes.getPastVotes(this.alice, timepoint - 1n)).to.equal(0n); + await mine(); + expect(await this.votes.getPastVotes(this.alice, timepoint)).to.equal(weight); + }); + + it('delegation update', async function () { + await this.votes.connect(this.alice).delegate(this.alice); + await this.votes.$_mint(this.alice, token); + const weight = getWeight(token); + + expect(await this.votes.delegates(this.alice)).to.equal(this.alice); + expect(await this.votes.getVotes(this.alice)).to.equal(weight); + expect(await this.votes.getVotes(this.bob)).to.equal(0); + + const tx = await this.votes.connect(this.alice).delegate(this.bob); + const timepoint = await time.clockFromReceipt[mode](tx); + + await expect(tx) + .to.emit(this.votes, 'DelegateChanged') + .withArgs(this.alice, this.alice, this.bob) + .to.emit(this.votes, 'DelegateVotesChanged') + .withArgs(this.alice, weight, 0) + .to.emit(this.votes, 'DelegateVotesChanged') + .withArgs(this.bob, 0, weight); + + expect(await this.votes.delegates(this.alice)).to.equal(this.bob); + expect(await this.votes.getVotes(this.alice)).to.equal(0n); + expect(await this.votes.getVotes(this.bob)).to.equal(weight); + + expect(await this.votes.getPastVotes(this.alice, timepoint - 1n)).to.equal(weight); + expect(await this.votes.getPastVotes(this.bob, timepoint - 1n)).to.equal(0n); + await mine(); + expect(await this.votes.getPastVotes(this.alice, timepoint)).to.equal(0n); + expect(await this.votes.getPastVotes(this.bob, timepoint)).to.equal(weight); + }); + + describe('with signature', function () { + const nonce = 0n; + + it('accept signed delegation', async function () { + await this.votes.$_mint(this.delegator, token); + const weight = getWeight(token); + + const { r, s, v } = await this.delegator + .signTypedData( + this.domain, + { Delegation }, + { + delegatee: this.delegatee.address, + nonce, + expiry: ethers.MaxUint256, + }, + ) + .then(ethers.Signature.from); + + expect(await this.votes.delegates(this.delegator)).to.equal(ethers.ZeroAddress); + + const tx = await this.votes.delegateBySig(this.delegatee, nonce, ethers.MaxUint256, v, r, s); + const timepoint = await time.clockFromReceipt[mode](tx); + + await expect(tx) + .to.emit(this.votes, 'DelegateChanged') + .withArgs(this.delegator, ethers.ZeroAddress, this.delegatee) + .to.emit(this.votes, 'DelegateVotesChanged') + .withArgs(this.delegatee, 0, weight); + + expect(await this.votes.delegates(this.delegator.address)).to.equal(this.delegatee); + expect(await this.votes.getVotes(this.delegator.address)).to.equal(0n); + expect(await this.votes.getVotes(this.delegatee)).to.equal(weight); + expect(await this.votes.getPastVotes(this.delegatee, timepoint - 1n)).to.equal(0n); + await mine(); + expect(await this.votes.getPastVotes(this.delegatee, timepoint)).to.equal(weight); + }); + + it('rejects reused signature', async function () { + const { r, s, v } = await this.delegator + .signTypedData( + this.domain, + { Delegation }, + { + delegatee: this.delegatee.address, + nonce, + expiry: ethers.MaxUint256, + }, + ) + .then(ethers.Signature.from); + + await this.votes.delegateBySig(this.delegatee, nonce, ethers.MaxUint256, v, r, s); + + await expect(this.votes.delegateBySig(this.delegatee, nonce, ethers.MaxUint256, v, r, s)) + .to.be.revertedWithCustomError(this.votes, 'InvalidAccountNonce') + .withArgs(this.delegator, nonce + 1n); + }); + + it('rejects bad delegatee', async function () { + const { r, s, v } = await this.delegator + .signTypedData( + this.domain, + { Delegation }, + { + delegatee: this.delegatee.address, + nonce, + expiry: ethers.MaxUint256, + }, + ) + .then(ethers.Signature.from); + + const tx = await this.votes.delegateBySig(this.other, nonce, ethers.MaxUint256, v, r, s); + const receipt = await tx.wait(); + + const [delegateChanged] = receipt.logs.filter( + log => this.votes.interface.parseLog(log)?.name === 'DelegateChanged', + ); + const { args } = this.votes.interface.parseLog(delegateChanged); + expect(args.delegator).to.not.be.equal(this.delegator); + expect(args.fromDelegate).to.equal(ethers.ZeroAddress); + expect(args.toDelegate).to.equal(this.other); + }); + + it('rejects bad nonce', async function () { + const { r, s, v } = await this.delegator + .signTypedData( + this.domain, + { Delegation }, + { + delegatee: this.delegatee.address, + nonce: nonce + 1n, + expiry: ethers.MaxUint256, + }, + ) + .then(ethers.Signature.from); + + await expect(this.votes.delegateBySig(this.delegatee, nonce + 1n, ethers.MaxUint256, v, r, s)) + .to.be.revertedWithCustomError(this.votes, 'InvalidAccountNonce') + .withArgs(this.delegator, 0); + }); + + it('rejects expired permit', async function () { + const expiry = (await time.clock.timestamp()) - 1n; + const { r, s, v } = await this.delegator + .signTypedData( + this.domain, + { Delegation }, + { + delegatee: this.delegatee.address, + nonce, + expiry, + }, + ) + .then(ethers.Signature.from); + + await expect(this.votes.delegateBySig(this.delegatee, nonce, expiry, v, r, s)) + .to.be.revertedWithCustomError(this.votes, 'VotesExpiredSignature') + .withArgs(expiry); + }); + }); + }); + + describe('getPastTotalSupply', function () { + beforeEach(async function () { + await this.votes.connect(this.alice).delegate(this.alice); + }); + + it('reverts if block number >= current block', async function () { + const timepoint = 5e10; + const clock = await this.votes.clock(); + await expect(this.votes.getPastTotalSupply(timepoint)) + .to.be.revertedWithCustomError(this.votes, 'ERC5805FutureLookup') + .withArgs(timepoint, clock); + }); + + it('returns 0 if there are no checkpoints', async function () { + expect(await this.votes.getPastTotalSupply(0n)).to.equal(0n); + }); + + 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(this.alice, tokens[0]); + await mine(); + // t1 = mint #1 + const t1 = await this.votes.$_mint(this.alice, tokens[1]); + await mine(); + // t2 = burn #1 + const t2 = await this.votes.$_burn(...(fungible ? [this.alice] : []), tokens[1]); + await mine(); + // t3 = mint #2 + const t3 = await this.votes.$_mint(this.alice, tokens[2]); + await mine(); + // t4 = burn #0 + const t4 = await this.votes.$_burn(...(fungible ? [this.alice] : []), tokens[0]); + await mine(); + // t5 = burn #2 + const t5 = await this.votes.$_burn(...(fungible ? [this.alice] : []), tokens[2]); + await mine(); + + t0.timepoint = await time.clockFromReceipt[mode](t0); + t1.timepoint = await time.clockFromReceipt[mode](t1); + t2.timepoint = await time.clockFromReceipt[mode](t2); + t3.timepoint = await time.clockFromReceipt[mode](t3); + t4.timepoint = await time.clockFromReceipt[mode](t4); + t5.timepoint = await time.clockFromReceipt[mode](t5); + + expect(await this.votes.getPastTotalSupply(t0.timepoint - 1n)).to.equal(0); + expect(await this.votes.getPastTotalSupply(t0.timepoint)).to.equal(weight[0]); + expect(await this.votes.getPastTotalSupply(t0.timepoint + 1n)).to.equal(weight[0]); + expect(await this.votes.getPastTotalSupply(t1.timepoint)).to.equal(weight[0] + weight[1]); + expect(await this.votes.getPastTotalSupply(t1.timepoint + 1n)).to.equal(weight[0] + weight[1]); + expect(await this.votes.getPastTotalSupply(t2.timepoint)).to.equal(weight[0]); + expect(await this.votes.getPastTotalSupply(t2.timepoint + 1n)).to.equal(weight[0]); + expect(await this.votes.getPastTotalSupply(t3.timepoint)).to.equal(weight[0] + weight[2]); + expect(await this.votes.getPastTotalSupply(t3.timepoint + 1n)).to.equal(weight[0] + weight[2]); + expect(await this.votes.getPastTotalSupply(t4.timepoint)).to.equal(weight[2]); + expect(await this.votes.getPastTotalSupply(t4.timepoint + 1n)).to.equal(weight[2]); + expect(await this.votes.getPastTotalSupply(t5.timepoint)).to.equal(0); + await expect(this.votes.getPastTotalSupply(t5.timepoint + 1n)) + .to.be.revertedWithCustomError(this.votes, 'ERC5805FutureLookup') + .withArgs(t5.timepoint + 1n, t5.timepoint + 1n); + }); + }); + + // 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(this.alice, tokens[0]); + await this.votes.$_mint(this.alice, tokens[1]); + await this.votes.$_mint(this.alice, 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 expect(this.votes.getPastVotes(this.bob, timepoint)) + .to.be.revertedWithCustomError(this.votes, 'ERC5805FutureLookup') + .withArgs(timepoint, clock); + }); + + it('returns 0 if there are no checkpoints', async function () { + expect(await this.votes.getPastVotes(this.bob, 0n)).to.equal(0n); + }); + + it('returns the latest block if >= last checkpoint block', async function () { + const delegate = await this.votes.connect(this.alice).delegate(this.bob); + const timepoint = await time.clockFromReceipt[mode](delegate); + await mine(2); + + const latest = await this.votes.getVotes(this.bob); + expect(await this.votes.getPastVotes(this.bob, timepoint)).to.equal(latest); + expect(await this.votes.getPastVotes(this.bob, timepoint + 1n)).to.equal(latest); + }); + + it('returns zero if < first checkpoint block', async function () { + await mine(); + const delegate = await this.votes.connect(this.alice).delegate(this.bob); + const timepoint = await time.clockFromReceipt[mode](delegate); + await mine(2); + + expect(await this.votes.getPastVotes(this.bob, timepoint - 1n)).to.equal(0n); + }); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeVotes, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js new file mode 100644 index 0000000..7acacfc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js @@ -0,0 +1,102 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { sum } = require('../../helpers/math'); +const { zip } = require('../../helpers/iterate'); +const time = require('../../helpers/time'); + +const { shouldBehaveLikeVotes } = require('./Votes.behavior'); + +const MODES = { + blocknumber: '$VotesMock', + timestamp: '$VotesTimestampMock', +}; + +const AMOUNTS = [ethers.parseEther('10000000'), 10n, 20n]; + +describe('Votes', function () { + for (const [mode, artifact] of Object.entries(MODES)) { + const fixture = async () => { + const accounts = await ethers.getSigners(); + + const amounts = Object.fromEntries( + zip( + accounts.slice(0, AMOUNTS.length).map(({ address }) => address), + AMOUNTS, + ), + ); + + const name = 'My Vote'; + const version = '1'; + const votes = await ethers.deployContract(artifact, [name, version]); + + return { accounts, amounts, votes, name, version }; + }; + + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeVotes(AMOUNTS, { mode, fungible: true }); + + it('starts with zero votes', async function () { + expect(await this.votes.getTotalSupply()).to.equal(0n); + }); + + describe('performs voting operations', function () { + beforeEach(async function () { + this.txs = []; + for (const [account, amount] of Object.entries(this.amounts)) { + this.txs.push(await this.votes.$_mint(account, amount)); + } + }); + + it('reverts if block number >= current block', async function () { + const lastTxTimepoint = await time.clockFromReceipt[mode](this.txs.at(-1)); + const clock = await this.votes.clock(); + await expect(this.votes.getPastTotalSupply(lastTxTimepoint)) + .to.be.revertedWithCustomError(this.votes, 'ERC5805FutureLookup') + .withArgs(lastTxTimepoint, clock); + }); + + it('delegates', async function () { + expect(await this.votes.getVotes(this.accounts[0])).to.equal(0n); + expect(await this.votes.getVotes(this.accounts[1])).to.equal(0n); + expect(await this.votes.delegates(this.accounts[0])).to.equal(ethers.ZeroAddress); + expect(await this.votes.delegates(this.accounts[1])).to.equal(ethers.ZeroAddress); + + await this.votes.delegate(this.accounts[0], ethers.Typed.address(this.accounts[0])); + + expect(await this.votes.getVotes(this.accounts[0])).to.equal(this.amounts[this.accounts[0].address]); + expect(await this.votes.getVotes(this.accounts[1])).to.equal(0n); + expect(await this.votes.delegates(this.accounts[0])).to.equal(this.accounts[0]); + expect(await this.votes.delegates(this.accounts[1])).to.equal(ethers.ZeroAddress); + + await this.votes.delegate(this.accounts[1], ethers.Typed.address(this.accounts[0])); + + expect(await this.votes.getVotes(this.accounts[0])).to.equal( + this.amounts[this.accounts[0].address] + this.amounts[this.accounts[1].address], + ); + expect(await this.votes.getVotes(this.accounts[1])).to.equal(0n); + expect(await this.votes.delegates(this.accounts[0])).to.equal(this.accounts[0]); + expect(await this.votes.delegates(this.accounts[1])).to.equal(this.accounts[0]); + }); + + it('cross delegates', async function () { + await this.votes.delegate(this.accounts[0], ethers.Typed.address(this.accounts[1])); + await this.votes.delegate(this.accounts[1], ethers.Typed.address(this.accounts[0])); + + expect(await this.votes.getVotes(this.accounts[0])).to.equal(this.amounts[this.accounts[1].address]); + expect(await this.votes.getVotes(this.accounts[1])).to.equal(this.amounts[this.accounts[0].address]); + }); + + it('returns total amount of votes', async function () { + const totalSupply = sum(...Object.values(this.amounts)); + expect(await this.votes.getTotalSupply()).to.equal(totalSupply); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/VotesExtended.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/VotesExtended.test.js new file mode 100644 index 0000000..4a66ef2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/VotesExtended.test.js @@ -0,0 +1,152 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers'); + +const { sum } = require('../../helpers/math'); +const { zip } = require('../../helpers/iterate'); +const time = require('../../helpers/time'); + +const { shouldBehaveLikeVotes } = require('./Votes.behavior'); + +const MODES = { + blocknumber: '$VotesExtendedMock', + timestamp: '$VotesExtendedTimestampMock', +}; + +const AMOUNTS = [ethers.parseEther('10000000'), 10n, 20n]; + +describe('VotesExtended', function () { + for (const [mode, artifact] of Object.entries(MODES)) { + const fixture = async () => { + const accounts = await ethers.getSigners(); + + const amounts = Object.fromEntries( + zip( + accounts.slice(0, AMOUNTS.length).map(({ address }) => address), + AMOUNTS, + ), + ); + + const name = 'Override Votes'; + const version = '1'; + const votes = await ethers.deployContract(artifact, [name, version]); + + return { accounts, amounts, votes, name, version }; + }; + + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeVotes(AMOUNTS, { mode, fungible: true }); + + it('starts with zero votes', async function () { + expect(await this.votes.getTotalSupply()).to.equal(0n); + }); + + describe('performs voting operations', function () { + beforeEach(async function () { + this.txs = []; + for (const [account, amount] of Object.entries(this.amounts)) { + this.txs.push(await this.votes.$_mint(account, amount)); + } + }); + + it('reverts if block number >= current block', async function () { + const lastTxTimepoint = await time.clockFromReceipt[mode](this.txs.at(-1)); + const clock = await this.votes.clock(); + await expect(this.votes.getPastTotalSupply(lastTxTimepoint)) + .to.be.revertedWithCustomError(this.votes, 'ERC5805FutureLookup') + .withArgs(lastTxTimepoint, clock); + }); + + it('delegates', async function () { + expect(await this.votes.getVotes(this.accounts[0])).to.equal(0n); + expect(await this.votes.getVotes(this.accounts[1])).to.equal(0n); + expect(await this.votes.delegates(this.accounts[0])).to.equal(ethers.ZeroAddress); + expect(await this.votes.delegates(this.accounts[1])).to.equal(ethers.ZeroAddress); + + await this.votes.delegate(this.accounts[0], ethers.Typed.address(this.accounts[0])); + + expect(await this.votes.getVotes(this.accounts[0])).to.equal(this.amounts[this.accounts[0].address]); + expect(await this.votes.getVotes(this.accounts[1])).to.equal(0n); + expect(await this.votes.delegates(this.accounts[0])).to.equal(this.accounts[0]); + expect(await this.votes.delegates(this.accounts[1])).to.equal(ethers.ZeroAddress); + + await this.votes.delegate(this.accounts[1], ethers.Typed.address(this.accounts[0])); + + expect(await this.votes.getVotes(this.accounts[0])).to.equal( + this.amounts[this.accounts[0].address] + this.amounts[this.accounts[1].address], + ); + expect(await this.votes.getVotes(this.accounts[1])).to.equal(0n); + expect(await this.votes.delegates(this.accounts[0])).to.equal(this.accounts[0]); + expect(await this.votes.delegates(this.accounts[1])).to.equal(this.accounts[0]); + }); + + it('cross delegates', async function () { + await this.votes.delegate(this.accounts[0], ethers.Typed.address(this.accounts[1])); + await this.votes.delegate(this.accounts[1], ethers.Typed.address(this.accounts[0])); + + expect(await this.votes.getVotes(this.accounts[0])).to.equal(this.amounts[this.accounts[1].address]); + expect(await this.votes.getVotes(this.accounts[1])).to.equal(this.amounts[this.accounts[0].address]); + }); + + it('returns total amount of votes', async function () { + const totalSupply = sum(...Object.values(this.amounts)); + expect(await this.votes.getTotalSupply()).to.equal(totalSupply); + }); + }); + }); + + describe(`checkpoint delegates with ${mode}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('checkpoint delegates', async function () { + const tx = await this.votes.delegate(this.accounts[0], ethers.Typed.address(this.accounts[1])); + const timepoint = await time.clockFromReceipt[mode](tx); + await mine(2); + + expect(await this.votes.getPastDelegate(this.accounts[0], timepoint - 1n)).to.equal(ethers.ZeroAddress); + expect(await this.votes.getPastDelegate(this.accounts[0], timepoint)).to.equal(this.accounts[1].address); + expect(await this.votes.getPastDelegate(this.accounts[0], timepoint + 1n)).to.equal(this.accounts[1].address); + }); + + it('reverts if current timepoint <= timepoint', async function () { + const tx = await this.votes.delegate(this.accounts[0], ethers.Typed.address(this.accounts[1])); + const timepoint = await time.clockFromReceipt[mode](tx); + + await expect(this.votes.getPastDelegate(this.accounts[0], timepoint + 1n)) + .to.be.revertedWithCustomError(this.votes, 'ERC5805FutureLookup') + .withArgs(timepoint + 1n, timepoint); + }); + }); + + describe(`checkpoint balances with ${mode}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('checkpoint balances', async function () { + const tx = await this.votes.$_mint(this.accounts[0].address, 100n); + const timepoint = await time.clockFromReceipt[mode](tx); + await mine(2); + + expect(await this.votes.getPastBalanceOf(this.accounts[0].address, timepoint - 1n)).to.equal(0n); + expect(await this.votes.getPastBalanceOf(this.accounts[0].address, timepoint)).to.equal(100n); + expect(await this.votes.getPastBalanceOf(this.accounts[0].address, timepoint + 1n)).to.equal(100n); + }); + + it('reverts if current timepoint <= timepoint', async function () { + const tx = await this.votes.$_mint(this.accounts[0].address, 100n); + const timepoint = await time.clockFromReceipt[mode](tx); + + await expect(this.votes.getPastBalanceOf(this.accounts[0], timepoint + 1n)) + .to.be.revertedWithCustomError(this.votes, 'ERC5805FutureLookup') + .withArgs(timepoint + 1n, timepoint); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/access-manager.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/access-manager.js new file mode 100644 index 0000000..3b83430 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/access-manager.js @@ -0,0 +1,85 @@ +const { ethers } = require('hardhat'); + +const { MAX_UINT64 } = require('./constants'); +const time = require('./time'); +const { upgradeableSlot } = require('./storage'); + +function buildBaseRoles() { + const roles = { + ADMIN: { + id: 0n, + }, + SOME_ADMIN: { + id: 17n, + }, + SOME_GUARDIAN: { + id: 35n, + }, + SOME: { + id: 42n, + }, + 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); + +const EXECUTION_ID_STORAGE_SLOT = upgradeableSlot('AccessManager', 3n); +const CONSUMING_SCHEDULE_STORAGE_SLOT = upgradeableSlot('AccessManaged', 0n); + +/** + * @requires this.{manager, caller, target, calldata} + */ +async function prepareOperation(manager, { caller, target, calldata, delay }) { + const scheduledAt = (await time.clock.timestamp()) + 1n; + await time.increaseTo.timestamp(scheduledAt, false); // Fix next block timestamp for predictability + + return { + schedule: () => manager.connect(caller).schedule(target, calldata, scheduledAt + delay), + scheduledAt, + operationId: hashOperation(caller, target, calldata), + }; +} + +const lazyGetAddress = addressable => addressable.address ?? addressable.target ?? addressable; + +const hashOperation = (caller, target, data) => + ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ['address', 'address', 'bytes'], + [lazyGetAddress(caller), lazyGetAddress(target), data], + ), + ); + +module.exports = { + buildBaseRoles, + formatAccess, + MINSETBACK, + EXPIRATION, + EXECUTION_ID_STORAGE_SLOT, + CONSUMING_SCHEDULE_STORAGE_SLOT, + prepareOperation, + hashOperation, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/account.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/account.js new file mode 100644 index 0000000..96874b1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/account.js @@ -0,0 +1,14 @@ +const { ethers } = require('hardhat'); +const { impersonateAccount, setBalance } = require('@nomicfoundation/hardhat-network-helpers'); + +// Hardhat default balance +const DEFAULT_BALANCE = 10000n * ethers.WeiPerEther; + +const impersonate = (account, balance = DEFAULT_BALANCE) => + impersonateAccount(account) + .then(() => setBalance(account, balance)) + .then(() => ethers.getSigner(account)); + +module.exports = { + impersonate, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/chains.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/chains.js new file mode 100644 index 0000000..3711a81 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/chains.js @@ -0,0 +1,109 @@ +// NOTE: this file defines some examples of CAIP-2 and CAIP-10 identifiers. +// The following listing does not pretend to be exhaustive or even accurate. It SHOULD NOT be used in production. + +const { ethers } = require('hardhat'); +const { mapValues } = require('./iterate'); + +// EVM (https://axelarscan.io/resources/chains?type=evm) +const ethereum = { + Ethereum: '1', + optimism: '10', + binance: '56', + Polygon: '137', + Fantom: '250', + fraxtal: '252', + filecoin: '314', + Moonbeam: '1284', + centrifuge: '2031', + kava: '2222', + mantle: '5000', + base: '8453', + immutable: '13371', + arbitrum: '42161', + celo: '42220', + Avalanche: '43114', + linea: '59144', + blast: '81457', + scroll: '534352', + aurora: '1313161554', +}; + +// Cosmos (https://axelarscan.io/resources/chains?type=cosmos) +const cosmos = { + Axelarnet: 'axelar-dojo-1', + osmosis: 'osmosis-1', + cosmoshub: 'cosmoshub-4', + juno: 'juno-1', + 'e-money': 'emoney-3', + injective: 'injective-1', + crescent: 'crescent-1', + kujira: 'kaiyo-1', + 'secret-snip': 'secret-4', + secret: 'secret-4', + sei: 'pacific-1', + stargaze: 'stargaze-1', + assetmantle: 'mantle-1', + fetch: 'fetchhub-4', + ki: 'kichain-2', + evmos: 'evmos_9001-2', + aura: 'xstaxy-1', + comdex: 'comdex-1', + persistence: 'core-1', + regen: 'regen-1', + umee: 'umee-1', + agoric: 'agoric-3', + xpla: 'dimension_37-1', + acre: 'acre_9052-1', + stride: 'stride-1', + carbon: 'carbon-1', + sommelier: 'sommelier-3', + neutron: 'neutron-1', + rebus: 'reb_1111-1', + archway: 'archway-1', + provenance: 'pio-mainnet-1', + ixo: 'ixo-5', + migaloo: 'migaloo-1', + teritori: 'teritori-1', + haqq: 'haqq_11235-1', + celestia: 'celestia', + ojo: 'agamotto', + chihuahua: 'chihuahua-1', + saga: 'ssc-1', + dymension: 'dymension_1100-1', + fxcore: 'fxcore', + c4e: 'perun-1', + bitsong: 'bitsong-2b', + nolus: 'pirin-1', + lava: 'lava-mainnet-1', + 'terra-2': 'phoenix-1', + terra: 'columbus-5', +}; + +const makeCAIP = ({ namespace, reference, account }) => ({ + namespace, + reference, + account, + caip2: `${namespace}:${reference}`, + caip10: `${namespace}:${reference}:${account}`, + toCaip10: other => `${namespace}:${reference}:${ethers.getAddress(other.target ?? other.address ?? other)}`, +}); + +module.exports = { + CHAINS: mapValues( + Object.assign( + mapValues(ethereum, reference => ({ + namespace: 'eip155', + reference, + account: ethers.Wallet.createRandom().address, + })), + mapValues(cosmos, reference => ({ + namespace: 'cosmos', + reference, + account: ethers.encodeBase58(ethers.randomBytes(32)), + })), + ), + makeCAIP, + ), + getLocalCAIP: account => + ethers.provider.getNetwork().then(({ chainId }) => makeCAIP({ namespace: 'eip155', reference: chainId, account })), +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/constants.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/constants.js new file mode 100644 index 0000000..eb9b43e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/constants.js @@ -0,0 +1,5 @@ +module.exports = { + MAX_UINT32: 2n ** 32n - 1n, + MAX_UINT48: 2n ** 48n - 1n, + MAX_UINT64: 2n ** 64n - 1n, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/deploy.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/deploy.js new file mode 100644 index 0000000..0d4b956 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/deploy.js @@ -0,0 +1,14 @@ +const { artifacts, ethers } = require('hardhat'); +const { setCode } = require('@nomicfoundation/hardhat-network-helpers'); +const { generators } = require('./random'); + +const forceDeployCode = (name, address = generators.address(), runner = ethers.provider) => + artifacts + .readArtifact(name) + .then(({ abi, deployedBytecode }) => + setCode(address, deployedBytecode).then(() => new ethers.Contract(address, abi, runner)), + ); + +module.exports = { + forceDeployCode, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712-types.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712-types.js new file mode 100644 index 0000000..fb6fe3a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712-types.js @@ -0,0 +1,61 @@ +const { mapValues } = require('./iterate'); + +const formatType = schema => Object.entries(schema).map(([name, type]) => ({ name, type })); + +module.exports = mapValues( + { + EIP712Domain: { + name: 'string', + version: 'string', + chainId: 'uint256', + verifyingContract: 'address', + salt: 'bytes32', + }, + Permit: { owner: 'address', spender: 'address', value: 'uint256', nonce: 'uint256', deadline: 'uint256' }, + Ballot: { proposalId: 'uint256', support: 'uint8', voter: 'address', nonce: 'uint256' }, + ExtendedBallot: { + proposalId: 'uint256', + support: 'uint8', + voter: 'address', + nonce: 'uint256', + reason: 'string', + params: 'bytes', + }, + OverrideBallot: { proposalId: 'uint256', support: 'uint8', voter: 'address', nonce: 'uint256', reason: 'string' }, + Delegation: { delegatee: 'address', nonce: 'uint256', expiry: 'uint256' }, + ForwardRequest: { + from: 'address', + to: 'address', + value: 'uint256', + gas: 'uint256', + nonce: 'uint256', + deadline: 'uint48', + data: 'bytes', + }, + PackedUserOperation: { + sender: 'address', + nonce: 'uint256', + initCode: 'bytes', + callData: 'bytes', + accountGasLimits: 'bytes32', + preVerificationGas: 'uint256', + gasFees: 'bytes32', + paymasterAndData: 'bytes', + }, + UserOperationRequest: { + sender: 'address', + nonce: 'uint256', + initCode: 'bytes', + callData: 'bytes', + accountGasLimits: 'bytes32', + preVerificationGas: 'uint256', + gasFees: 'bytes32', + paymasterVerificationGasLimit: 'uint256', + paymasterPostOpGasLimit: 'uint256', + validAfter: 'uint48', + validUntil: 'uint48', + }, + }, + formatType, +); +module.exports.formatType = formatType; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712.js new file mode 100644 index 0000000..3843ac0 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712.js @@ -0,0 +1,45 @@ +const { ethers } = require('hardhat'); +const types = require('./eip712-types'); + +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 types.EIP712Domain.entries()) { + if (!(fields & (1 << i))) { + delete domain[name]; + } + } + + return domain; +} + +function domainType(domain) { + return types.EIP712Domain.filter(({ name }) => domain[name] !== undefined); +} + +function hashTypedData(domain, structHash) { + return ethers.solidityPackedKeccak256( + ['bytes', 'bytes32', 'bytes32'], + ['0x1901', ethers.TypedDataEncoder.hashDomain(domain), structHash], + ); +} + +module.exports = { + getDomain, + domainType, + domainSeparator: ethers.TypedDataEncoder.hashDomain, + hashTypedData, + ...types, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/enums.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/enums.js new file mode 100644 index 0000000..6adbf64 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/enums.js @@ -0,0 +1,14 @@ +const { ethers } = require('ethers'); + +const Enum = (...options) => Object.fromEntries(options.map((key, i) => [key, BigInt(i)])); +const EnumTyped = (...options) => Object.fromEntries(options.map((key, i) => [key, ethers.Typed.uint8(i)])); + +module.exports = { + Enum, + EnumTyped, + ProposalState: Enum('Pending', 'Active', 'Canceled', 'Defeated', 'Succeeded', 'Queued', 'Expired', 'Executed'), + VoteType: Object.assign(Enum('Against', 'For', 'Abstain'), { Parameters: 255n }), + Rounding: EnumTyped('Floor', 'Ceil', 'Trunc', 'Expand'), + OperationState: Enum('Unset', 'Waiting', 'Ready', 'Done'), + RevertType: EnumTyped('None', 'RevertWithoutMessage', 'RevertWithMessage', 'RevertWithCustomError', 'Panic'), +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc4337.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc4337.js new file mode 100644 index 0000000..0d5421b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc4337.js @@ -0,0 +1,217 @@ +const { ethers, config, entrypoint, senderCreator } = require('hardhat'); + +const SIG_VALIDATION_SUCCESS = '0x0000000000000000000000000000000000000000'; +const SIG_VALIDATION_FAILURE = '0x0000000000000000000000000000000000000001'; + +function getAddress(account) { + return account.target ?? account.address ?? account; +} + +function pack(left, right) { + return ethers.solidityPacked(['uint128', 'uint128'], [left, right]); +} + +function packValidationData(validAfter, validUntil, authorizer) { + return ethers.solidityPacked( + ['uint48', 'uint48', 'address'], + [ + validAfter, + validUntil, + typeof authorizer == 'boolean' + ? authorizer + ? SIG_VALIDATION_SUCCESS + : SIG_VALIDATION_FAILURE + : getAddress(authorizer), + ], + ); +} + +function packInitCode(factory, factoryData) { + return ethers.solidityPacked(['address', 'bytes'], [getAddress(factory), factoryData]); +} + +function packPaymasterAndData(paymaster, paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymasterData) { + return ethers.solidityPacked( + ['address', 'uint128', 'uint128', 'bytes'], + [getAddress(paymaster), paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymasterData], + ); +} + +/// Represent one user operation +class UserOperation { + constructor(params) { + this.sender = getAddress(params.sender); + this.nonce = params.nonce; + this.factory = params.factory ?? undefined; + this.factoryData = params.factoryData ?? '0x'; + this.callData = params.callData ?? '0x'; + this.verificationGas = params.verificationGas ?? 10_000_000n; + this.callGas = params.callGas ?? 100_000n; + this.preVerificationGas = params.preVerificationGas ?? 100_000n; + this.maxPriorityFee = params.maxPriorityFee ?? 100_000n; + this.maxFeePerGas = params.maxFeePerGas ?? 100_000n; + this.paymaster = params.paymaster ?? undefined; + this.paymasterVerificationGasLimit = params.paymasterVerificationGasLimit ?? 0n; + this.paymasterPostOpGasLimit = params.paymasterPostOpGasLimit ?? 0n; + this.paymasterData = params.paymasterData ?? '0x'; + this.signature = params.signature ?? '0x'; + } + + get packed() { + return { + sender: this.sender, + nonce: this.nonce, + initCode: this.factory ? packInitCode(this.factory, this.factoryData) : '0x', + callData: this.callData, + accountGasLimits: pack(this.verificationGas, this.callGas), + preVerificationGas: this.preVerificationGas, + gasFees: pack(this.maxPriorityFee, this.maxFeePerGas), + paymasterAndData: this.paymaster + ? packPaymasterAndData( + this.paymaster, + this.paymasterVerificationGasLimit, + this.paymasterPostOpGasLimit, + this.paymasterData, + ) + : '0x', + signature: this.signature, + }; + } + + hash(entrypoint) { + return entrypoint.getUserOpHash(this.packed); + } +} + +const parseInitCode = initCode => ({ + factory: '0x' + initCode.replace(/0x/, '').slice(0, 40), + factoryData: '0x' + initCode.replace(/0x/, '').slice(40), +}); + +/// Global ERC-4337 environment helper. +class ERC4337Helper { + constructor() { + this.factoryAsPromise = ethers.deployContract('$Create2'); + } + + async wait() { + this.factory = await this.factoryAsPromise; + return this; + } + + async newAccount(name, extraArgs = [], params = {}) { + const env = { + entrypoint: params.entrypoint ?? entrypoint.v08, + senderCreator: params.senderCreator ?? senderCreator.v08, + }; + + const { factory } = await this.wait(); + + const accountFactory = await ethers.getContractFactory(name); + + if (params.erc7702signer) { + const delegate = await accountFactory.deploy(...extraArgs); + const instance = await params.erc7702signer.getAddress().then(address => accountFactory.attach(address)); + const authorization = await params.erc7702signer.authorize({ address: delegate.target }); + return new ERC7702SmartAccount(instance, authorization, env); + } else { + const initCode = await accountFactory + .getDeployTransaction(...extraArgs) + .then(tx => + factory.interface.encodeFunctionData('$deploy', [0, params.salt ?? ethers.randomBytes(32), tx.data]), + ) + .then(deployCode => ethers.concat([factory.target, deployCode])); + + const instance = await ethers.provider + .call({ + from: env.entrypoint, + to: env.senderCreator, + data: env.senderCreator.interface.encodeFunctionData('createSender', [initCode]), + }) + .then(result => ethers.getAddress(ethers.hexlify(ethers.getBytes(result).slice(-20)))) + .then(address => accountFactory.attach(address)); + + return new SmartAccount(instance, initCode, env); + } + } +} + +/// Represent one ERC-4337 account contract. +class SmartAccount extends ethers.BaseContract { + constructor(instance, initCode, env) { + super(instance.target, instance.interface, instance.runner, instance.deployTx); + this.address = instance.target; + this.initCode = initCode; + this._env = env; + } + + async deploy(account = this.runner) { + const { factory: to, factoryData: data } = parseInitCode(this.initCode); + this.deployTx = await account.sendTransaction({ to, data }); + return this; + } + + async createUserOp(userOp = {}) { + userOp.sender ??= this; + userOp.nonce ??= await this._env.entrypoint.getNonce(userOp.sender, 0); + if (ethers.isAddressable(userOp.paymaster)) { + userOp.paymaster = await ethers.resolveAddress(userOp.paymaster); + userOp.paymasterVerificationGasLimit ??= 100_000n; + userOp.paymasterPostOpGasLimit ??= 100_000n; + } + return new UserOperationWithContext(userOp, this._env); + } +} + +class ERC7702SmartAccount extends SmartAccount { + constructor(instance, authorization, env) { + super(instance, undefined, env); + this.authorization = authorization; + } + + async deploy() { + // hardhat signers from @nomicfoundation/hardhat-ethers do not support type 4 txs. + // so we rebuild it using "native" ethers + await ethers.Wallet.fromPhrase(config.networks.hardhat.accounts.mnemonic, ethers.provider).sendTransaction({ + to: ethers.ZeroAddress, + authorizationList: [this.authorization], + gasLimit: 46_000n, // 21,000 base + PER_EMPTY_ACCOUNT_COST + }); + + return this; + } +} + +class UserOperationWithContext extends UserOperation { + constructor(userOp, env) { + super(userOp); + this._sender = userOp.sender; + this._env = env; + } + + addInitCode() { + if (this._sender?.initCode) { + return Object.assign(this, parseInitCode(this._sender.initCode)); + } else throw new Error('No init code available for the sender of this user operation'); + } + + getAuthorization() { + if (this._sender?.authorization) { + return this._sender.authorization; + } else throw new Error('No EIP-7702 authorization available for the sender of this user operation'); + } + + hash() { + return super.hash(this._env.entrypoint); + } +} + +module.exports = { + SIG_VALIDATION_SUCCESS, + SIG_VALIDATION_FAILURE, + packValidationData, + packInitCode, + packPaymasterAndData, + UserOperation, + ERC4337Helper, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7579.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7579.js new file mode 100644 index 0000000..6c3b475 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7579.js @@ -0,0 +1,58 @@ +const { ethers } = require('hardhat'); + +const MODULE_TYPE_VALIDATOR = 1; +const MODULE_TYPE_EXECUTOR = 2; +const MODULE_TYPE_FALLBACK = 3; +const MODULE_TYPE_HOOK = 4; + +const EXEC_TYPE_DEFAULT = '0x00'; +const EXEC_TYPE_TRY = '0x01'; + +const CALL_TYPE_CALL = '0x00'; +const CALL_TYPE_BATCH = '0x01'; +const CALL_TYPE_DELEGATE = '0xff'; + +const encodeMode = ({ + callType = '0x00', + execType = '0x00', + selector = '0x00000000', + payload = '0x00000000000000000000000000000000000000000000', +} = {}) => + ethers.solidityPacked( + ['bytes1', 'bytes1', 'bytes4', 'bytes4', 'bytes22'], + [callType, execType, '0x00000000', selector, payload], + ); + +const encodeSingle = (target, value = 0n, data = '0x') => + ethers.solidityPacked(['address', 'uint256', 'bytes'], [target.target ?? target.address ?? target, value, data]); + +const encodeBatch = (...entries) => + ethers.AbiCoder.defaultAbiCoder().encode( + ['(address,uint256,bytes)[]'], + [ + entries.map(entry => + Array.isArray(entry) + ? [entry[0].target ?? entry[0].address ?? entry[0], entry[1] ?? 0n, entry[2] ?? '0x'] + : [entry.target.target ?? entry.target.address ?? entry.target, entry.value ?? 0n, entry.data ?? '0x'], + ), + ], + ); + +const encodeDelegate = (target, data = '0x') => + ethers.solidityPacked(['address', 'bytes'], [target.target ?? target.address ?? target, data]); + +module.exports = { + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK, + MODULE_TYPE_HOOK, + EXEC_TYPE_DEFAULT, + EXEC_TYPE_TRY, + CALL_TYPE_CALL, + CALL_TYPE_BATCH, + CALL_TYPE_DELEGATE, + encodeMode, + encodeSingle, + encodeBatch, + encodeDelegate, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7739.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7739.js new file mode 100644 index 0000000..5a489de --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7739.js @@ -0,0 +1,118 @@ +const { ethers } = require('hardhat'); +const { formatType } = require('./eip712'); + +const PersonalSign = formatType({ prefixed: 'bytes' }); +const TypedDataSign = contentsTypeName => + formatType({ + contents: contentsTypeName, + name: 'string', + version: 'string', + chainId: 'uint256', + verifyingContract: 'address', + salt: 'bytes32', + }); + +class ERC7739Signer extends ethers.AbstractSigner { + #signer; + #domain; + + constructor(signer, domain) { + super(signer.provider); + this.#signer = signer; + this.#domain = domain; + } + + static from(signer, domain) { + return new this(signer, domain); + } + + get signingKey() { + return this.#signer.signingKey; + } + + get privateKey() { + return this.#signer.privateKey; + } + + async getAddress() { + return this.#signer.getAddress(); + } + + connect(provider) { + this.#signer.connect(provider); + } + + async signTransaction(tx) { + return this.#signer.signTransaction(tx); + } + + async signMessage(message) { + return this.#signer.signTypedData(this.#domain, { PersonalSign }, ERC4337Utils.preparePersonalSign(message)); + } + + async signTypedData(domain, types, value) { + const { allTypes, contentsTypeName, contentsDescr } = ERC4337Utils.getContentsDetail(types); + + return Promise.resolve( + this.#signer.signTypedData(domain, allTypes, ERC4337Utils.prepareSignTypedData(value, this.#domain)), + ).then(signature => + ethers.concat([ + signature, + ethers.TypedDataEncoder.hashDomain(domain), // appDomainSeparator + ethers.TypedDataEncoder.hashStruct(contentsTypeName, types, value), // contentsHash + ethers.toUtf8Bytes(contentsDescr), + ethers.toBeHex(contentsDescr.length, 2), + ]), + ); + } +} + +class ERC4337Utils { + static preparePersonalSign(message) { + return { + prefixed: ethers.concat([ + ethers.toUtf8Bytes(ethers.MessagePrefix), + ethers.toUtf8Bytes(String(message.length)), + typeof message === 'string' ? ethers.toUtf8Bytes(message) : message, + ]), + }; + } + + static prepareSignTypedData(contents, signerDomain) { + return { + name: signerDomain.name ?? '', + version: signerDomain.version ?? '', + chainId: signerDomain.chainId ?? 0, + verifyingContract: signerDomain.verifyingContract ?? ethers.ZeroAddress, + salt: signerDomain.salt ?? ethers.ZeroHash, + contents, + }; + } + + static getContentsDetail(contentsTypes, contentsTypeName = Object.keys(contentsTypes).at(0)) { + // Examples values + // + // contentsTypeName B + // typedDataSignType TypedDataSign(B contents,...)A(uint256 v)B(Z z)Z(A a) + // contentsType A(uint256 v)B(Z z)Z(A a) + // contentsDescr A(uint256 v)B(Z z)Z(A a)B + const allTypes = { TypedDataSign: TypedDataSign(contentsTypeName), ...contentsTypes }; + const typedDataSignType = ethers.TypedDataEncoder.from(allTypes).encodeType('TypedDataSign'); + const contentsType = typedDataSignType.slice(typedDataSignType.indexOf(')') + 1); // Remove TypedDataSign (first object) + const contentsDescr = contentsType + (contentsType.startsWith(contentsTypeName) ? '' : contentsTypeName); + + return { + allTypes, + contentsTypes, + contentsTypeName, + contentsDescr, + }; + } +} + +module.exports = { + ERC7739Signer, + ERC4337Utils, + PersonalSign, + TypedDataSign, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/governance.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/governance.js new file mode 100644 index 0000000..e068644 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/governance.js @@ -0,0 +1,217 @@ +const { ethers } = require('hardhat'); +const { ProposalState } = require('./enums'); +const { unique } = require('./iterate'); +const time = require('./time'); + +const timelockSalt = (address, descriptionHash) => + ethers.toBeHex((ethers.toBigInt(address) << 96n) ^ ethers.toBigInt(descriptionHash), 32); + +class GovernorHelper { + constructor(governor, mode = 'blocknumber') { + this.governor = governor; + this.mode = mode; + } + + connect(account) { + this.governor = this.governor.connect(account); + return this; + } + + /// Setter and getters + /** + * Specify a proposal either as + * 1) an array of objects [{ target, value, data }] + * 2) an object of arrays { targets: [], values: [], data: [] } + */ + setProposal(actions, description) { + if (Array.isArray(actions)) { + this.targets = actions.map(a => a.target); + this.values = actions.map(a => a.value || 0n); + this.data = actions.map(a => a.data || '0x'); + } else { + ({ targets: this.targets, values: this.values, data: this.data } = actions); + } + this.description = description; + return this; + } + + get hash() { + return ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode(['address[]', 'uint256[]', 'bytes[]', 'bytes32'], this.shortProposal), + ); + } + + get id() { + return this.governor.latestProposalId ? this.governor.getProposalId(...this.shortProposal) : this.hash; + } + + // used for checking events + get signatures() { + return this.data.map(() => ''); + } + + get descriptionHash() { + return ethers.id(this.description); + } + + // condensed version for queueing end executing + get shortProposal() { + return [this.targets, this.values, this.data, this.descriptionHash]; + } + + // full version for proposing + get fullProposal() { + return [this.targets, this.values, this.data, this.description]; + } + + get currentProposal() { + return this; + } + + /// Proposal lifecycle + delegate(delegation) { + return Promise.all([ + delegation.token.connect(delegation.to).delegate(delegation.to), + delegation.value === undefined || + delegation.token.connect(this.governor.runner).transfer(delegation.to, delegation.value), + delegation.tokenId === undefined || + delegation.token + .ownerOf(delegation.tokenId) + .then(owner => + delegation.token.connect(this.governor.runner).transferFrom(owner, delegation.to, delegation.tokenId), + ), + ]); + } + + propose() { + return this.governor.propose(...this.fullProposal); + } + + queue() { + return this.governor.queue(...this.shortProposal); + } + + execute() { + return this.governor.execute(...this.shortProposal); + } + + cancel(visibility = 'external') { + switch (visibility) { + case 'external': + return this.governor.cancel(...this.shortProposal); + + case 'internal': + return this.governor.$_cancel(...this.shortProposal); + + default: + throw new Error(`unsupported visibility "${visibility}"`); + } + } + + async vote(vote = {}) { + let method = 'castVote'; // default + let args = [await this.id, vote.support]; // base + + if (vote.signature) { + const sign = await this.forgeMessage(vote).then(msg => vote.signature(this.governor, msg)); + if (vote.params || vote.reason) { + method = 'castVoteWithReasonAndParamsBySig'; + args.push(vote.voter, vote.reason ?? '', vote.params ?? '0x', sign); + } else { + method = 'castVoteBySig'; + args.push(vote.voter, sign); + } + } else if (vote.params) { + method = 'castVoteWithReasonAndParams'; + args.push(vote.reason ?? '', vote.params); + } else if (vote.reason) { + method = 'castVoteWithReason'; + args.push(vote.reason); + } + + return await this.governor[method](...args); + } + + async overrideVote(vote = {}) { + let method = 'castOverrideVote'; + let args = [await this.id, vote.support]; + + vote.reason = vote.reason ?? ''; + + if (vote.signature) { + const sign = await this.forgeMessage(vote).then(msg => vote.signature(this.governor, { reason: '', ...msg })); + method = 'castOverrideVoteBySig'; + args.push(vote.voter, vote.reason ?? '', sign); + } + + return await this.governor[method](...args); + } + + /// Clock helpers + async waitForSnapshot(offset = 0n) { + const timepoint = await this.governor.proposalSnapshot(await this.id); + return time.increaseTo[this.mode](timepoint + offset); + } + + async waitForDeadline(offset = 0n) { + const timepoint = await this.governor.proposalDeadline(await this.id); + return time.increaseTo[this.mode](timepoint + offset); + } + + async waitForEta(offset = 0n) { + const timestamp = await this.governor.proposalEta(await this.id); + return time.increaseTo.timestamp(timestamp + offset); + } + + /// Other helpers + async forgeMessage(vote = {}) { + const message = { proposalId: await this.id, support: vote.support, voter: vote.voter, nonce: vote.nonce }; + + if (vote.params || vote.reason) { + message.reason = vote.reason ?? ''; + message.params = vote.params ?? '0x'; + } + + return message; + } + + /** + * 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 + */ + static proposalStatesToBitMap(proposalStates, options = {}) { + if (!Array.isArray(proposalStates)) { + proposalStates = [proposalStates]; + } + const statesCount = ethers.toBigInt(Object.keys(ProposalState).length); + let result = 0n; + + for (const state of unique(proposalStates)) { + if (state < 0n || state >= statesCount) { + expect.fail(`ProposalState ${state} out of possible states (0...${statesCount}-1)`); + } else { + result |= 1n << state; + } + } + + if (options.inverted) { + const mask = 2n ** statesCount - 1n; + result = result ^ mask; + } + + return ethers.toBeHex(result, 32); + } +} + +module.exports = { + GovernorHelper, + timelockSalt, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/iterate.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/iterate.js new file mode 100644 index 0000000..8c8e964 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/iterate.js @@ -0,0 +1,41 @@ +module.exports = { + // ================================================= Array helpers ================================================= + + // Cut an array into an array of sized-length arrays + // Example: chunk([1,2,3,4,5,6,7,8], 3) → [[1,2,3],[4,5,6],[7,8]] + chunk: (array, size = 1) => + Array.from({ length: Math.ceil(array.length / size) }, (_, i) => array.slice(i * size, i * size + size)), + + // Cartesian cross product of an array of arrays + // Example: product([1,2],[a,b,c],[true]) → [[1,a,true],[1,b,true],[1,c,true],[2,a,true],[2,b,true],[2,c,true]] + product: (...arrays) => arrays.reduce((a, b) => a.flatMap(ai => b.map(bi => [...ai, bi])), [[]]), + + // Range from start to end in increment + // Example: range(17,42,7) → [17,24,31,38] + range: (start, stop = undefined, step = 1) => { + if (stop == undefined) { + stop = start; + start = 0; + } + return start < stop ? Array.from({ length: (stop - start + step - 1) / step }, (_, i) => start + i * step) : []; + }, + + // Unique elements, with an optional getter function + // Example: unique([1,1,2,3,4,8,1,3,8,13,42]) → [1,2,3,4,8,13,42] + unique: (array, op = x => x) => array.filter((obj, i) => array.findIndex(entry => op(obj) === op(entry)) === i), + + // Zip arrays together. If some arrays are smaller, undefined is used as a filler. + // Example: zip([1,2],[a,b,c],[true]) → [[1,a,true],[2,b,undefined],[undefined,c,undefined]] + zip: (...args) => Array.from({ length: Math.max(...args.map(arg => arg.length)) }, (_, i) => args.map(arg => arg[i])), + + // ================================================ Object helpers ================================================= + + // Create a new object by mapping the values through a function, keeping the keys. Second function can be used to pre-filter entries + // Example: mapValues({a:1,b:2,c:3}, x => x**2) → {a:1,b:4,c:9} + mapValues: (obj, fn, fn2 = () => true) => + Object.fromEntries( + Object.entries(obj) + .filter(fn2) + .map(([k, v]) => [k, fn(v)]), + ), +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/math.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/math.js new file mode 100644 index 0000000..133254a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/math.js @@ -0,0 +1,33 @@ +// Array of number or bigint +const max = (...values) => values.slice(1).reduce((x, y) => (x > y ? x : y), values.at(0)); +const min = (...values) => values.slice(1).reduce((x, y) => (x < y ? x : y), values.at(0)); +const sum = (...values) => values.slice(1).reduce((x, y) => x + y, values.at(0)); + +// Computes modexp without BigInt overflow for large numbers +function modExp(b, e, m) { + let result = 1n; + + // If e is a power of two, modexp can be calculated as: + // for (let result = b, i = 0; i < log2(e); i++) result = modexp(result, 2, m) + // + // Given any natural number can be written in terms of powers of 2 (i.e. binary) + // then modexp can be calculated for any e, by multiplying b**i for all i where + // binary(e)[i] is 1 (i.e. a power of two). + for (let base = b % m; e > 0n; base = base ** 2n % m) { + // Least significant bit is 1 + if (e % 2n == 1n) { + result = (result * base) % m; + } + + e /= 2n; // Binary pop + } + + return result; +} + +module.exports = { + min, + max, + sum, + modExp, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/methods.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/methods.js new file mode 100644 index 0000000..a491897 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/methods.js @@ -0,0 +1,14 @@ +const { ethers } = require('hardhat'); + +const selector = signature => ethers.FunctionFragment.from(signature).selector; + +const interfaceId = signatures => + ethers.toBeHex( + signatures.reduce((acc, signature) => acc ^ ethers.toBigInt(selector(signature)), 0n), + 4, + ); + +module.exports = { + selector, + interfaceId, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/precompiles.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/precompiles.js new file mode 100644 index 0000000..fb6b713 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/precompiles.js @@ -0,0 +1,12 @@ +module.exports = { + ecRecover: '0x0000000000000000000000000000000000000001', + SHA2_256: '0x0000000000000000000000000000000000000002', + RIPEMD_160: '0x0000000000000000000000000000000000000003', + identity: '0x0000000000000000000000000000000000000004', + modexp: '0x0000000000000000000000000000000000000005', + ecAdd: '0x0000000000000000000000000000000000000006', + ecMul: '0x0000000000000000000000000000000000000007', + ecPairing: '0x0000000000000000000000000000000000000008', + blake2f: '0x0000000000000000000000000000000000000009', + pointEvaluation: '0x000000000000000000000000000000000000000a', +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/random.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/random.js new file mode 100644 index 0000000..6d78267 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/random.js @@ -0,0 +1,24 @@ +const { ethers } = require('hardhat'); + +const generators = { + address: () => ethers.Wallet.createRandom().address, + bytes32: () => ethers.hexlify(ethers.randomBytes(32)), + uint256: () => ethers.toBigInt(ethers.randomBytes(32)), + int256: () => ethers.toBigInt(ethers.randomBytes(32)) + ethers.MinInt256, + bytes: (length = 32) => ethers.hexlify(ethers.randomBytes(length)), + string: () => ethers.uuidV4(ethers.randomBytes(32)), +}; + +generators.address.zero = ethers.ZeroAddress; +generators.bytes32.zero = ethers.ZeroHash; +generators.uint256.zero = 0n; +generators.int256.zero = 0n; +generators.bytes.zero = '0x'; +generators.string.zero = ''; + +// alias hexBytes -> bytes +generators.hexBytes = generators.bytes; + +module.exports = { + generators, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/signers.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/signers.js new file mode 100644 index 0000000..baa8b06 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/signers.js @@ -0,0 +1,184 @@ +const { + AbiCoder, + AbstractSigner, + Signature, + TypedDataEncoder, + assert, + assertArgument, + concat, + dataLength, + decodeBase64, + getBytes, + getBytesCopy, + hashMessage, + hexlify, + sha256, + toBeHex, + keccak256, +} = require('ethers'); +const { secp256r1 } = require('@noble/curves/p256'); +const { generateKeyPairSync, privateEncrypt } = require('crypto'); + +// Lightweight version of BaseWallet +class NonNativeSigner extends AbstractSigner { + #signingKey; + + constructor(privateKey, provider) { + super(provider); + assertArgument( + privateKey && typeof privateKey.sign === 'function', + 'invalid private key', + 'privateKey', + '[ REDACTED ]', + ); + this.#signingKey = privateKey; + } + + get signingKey() { + return this.#signingKey; + } + get privateKey() { + return this.signingKey.privateKey; + } + + async getAddress() { + throw new Error("NonNativeSigner doesn't have an address"); + } + + connect(provider) { + return new NonNativeSigner(this.#signingKey, provider); + } + + async signTransaction(/*tx: TransactionRequest*/) { + throw new Error('NonNativeSigner cannot send transactions'); + } + + async signMessage(message /*: string | Uint8Array*/) /*: Promise*/ { + return this.signingKey.sign(hashMessage(message)).serialized; + } + + async signTypedData( + domain /*: TypedDataDomain*/, + types /*: Record>*/, + value /*: Record*/, + ) /*: Promise*/ { + // Populate any ENS names + const populated = await TypedDataEncoder.resolveNames(domain, types, value, async name => { + assert(this.provider != null, 'cannot resolve ENS names without a provider', 'UNSUPPORTED_OPERATION', { + operation: 'resolveName', + info: { name }, + }); + const address = await this.provider.resolveName(name); + assert(address != null, 'unconfigured ENS name', 'UNCONFIGURED_NAME', { value: name }); + return address; + }); + + return this.signingKey.sign(TypedDataEncoder.hash(populated.domain, types, populated.value)).serialized; + } +} + +class P256SigningKey { + #privateKey; + + constructor(privateKey) { + this.#privateKey = getBytes(privateKey); + } + + static random() { + return new this(secp256r1.utils.randomPrivateKey()); + } + + get privateKey() { + return hexlify(this.#privateKey); + } + + get publicKey() { + const publicKeyBytes = secp256r1.getPublicKey(this.#privateKey, false); + return { qx: hexlify(publicKeyBytes.slice(0x01, 0x21)), qy: hexlify(publicKeyBytes.slice(0x21, 0x41)) }; + } + + sign(digest /*: BytesLike*/) /*: Signature*/ { + assertArgument(dataLength(digest) === 32, 'invalid digest length', 'digest', digest); + + const sig = secp256r1.sign(getBytesCopy(digest), getBytesCopy(this.#privateKey), { lowS: true }); + + return Signature.from({ r: toBeHex(sig.r, 32), s: toBeHex(sig.s, 32), v: sig.recovery ? 0x1c : 0x1b }); + } +} + +class RSASigningKey { + #privateKey; + #publicKey; + + constructor(keyPair) { + const jwk = keyPair.publicKey.export({ format: 'jwk' }); + this.#privateKey = keyPair.privateKey; + this.#publicKey = { e: decodeBase64(jwk.e), n: decodeBase64(jwk.n) }; + } + + static random(modulusLength = 2048) { + return new this(generateKeyPairSync('rsa', { modulusLength })); + } + + get privateKey() { + return hexlify(this.#privateKey); + } + + get publicKey() { + return { e: hexlify(this.#publicKey.e), n: hexlify(this.#publicKey.n) }; + } + + sign(digest /*: BytesLike*/) /*: Signature*/ { + assertArgument(dataLength(digest) === 32, 'invalid digest length', 'digest', digest); + // SHA256 OID = 608648016503040201 (9 bytes) | NULL = 0500 (2 bytes) (explicit) | OCTET_STRING length (0x20) = 0420 (2 bytes) + return { + serialized: hexlify( + privateEncrypt(this.#privateKey, getBytes(concat(['0x3031300d060960864801650304020105000420', digest]))), + ), + }; + } +} + +class RSASHA256SigningKey extends RSASigningKey { + sign(digest /*: BytesLike*/) /*: Signature*/ { + assertArgument(dataLength(digest) === 32, 'invalid digest length', 'digest', digest); + return super.sign(sha256(getBytes(digest))); + } +} + +class MultiERC7913SigningKey { + // this is a sorted array of objects that contain {signer, weight} + #signers; + + constructor(signers) { + assertArgument( + Array.isArray(signers) && signers.length > 0, + 'signers must be a non-empty array', + 'signers', + signers.length, + ); + + // Sorting is done at construction so that it doesn't have to be done in sign() + this.#signers = signers.sort((s1, s2) => keccak256(s1.bytes ?? s1.address) - keccak256(s2.bytes ?? s2.address)); + } + + get signers() { + return this.#signers; + } + + sign(digest /*: BytesLike*/ /*: Signature*/) { + assertArgument(dataLength(digest) === 32, 'invalid digest length', 'digest', digest); + + return { + serialized: AbiCoder.defaultAbiCoder().encode( + ['bytes[]', 'bytes[]'], + [ + this.#signers.map(signer => signer.bytes ?? signer.address), + this.#signers.map(signer => signer.signingKey.sign(digest).serialized), + ], + ), + }; + } +} + +module.exports = { NonNativeSigner, P256SigningKey, RSASigningKey, RSASHA256SigningKey, MultiERC7913SigningKey }; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/storage.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/storage.js new file mode 100644 index 0000000..466cbb1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/storage.js @@ -0,0 +1,48 @@ +const { ethers } = require('hardhat'); +const { setStorageAt } = require('@nomicfoundation/hardhat-network-helpers'); + +const ImplementationLabel = 'eip1967.proxy.implementation'; +const AdminLabel = 'eip1967.proxy.admin'; +const BeaconLabel = 'eip1967.proxy.beacon'; + +const erc1967Slot = label => ethers.toBeHex(ethers.toBigInt(ethers.id(label)) - 1n); +const erc7201Slot = label => ethers.toBeHex(ethers.toBigInt(ethers.keccak256(erc1967Slot(label))) & ~0xffn); +const erc7201format = contractName => `openzeppelin.storage.${contractName}`; + +const getSlot = (address, slot) => + ethers.provider.getStorage(address, ethers.isBytesLike(slot) ? slot : erc1967Slot(slot)); + +const setSlot = (address, slot, value) => + Promise.all([ + ethers.isAddressable(address) ? address.getAddress() : Promise.resolve(address), + ethers.isAddressable(value) ? value.getAddress() : Promise.resolve(value), + ]).then(([address, value]) => setStorageAt(address, ethers.isBytesLike(slot) ? slot : erc1967Slot(slot), value)); + +const getAddressInSlot = (address, slot) => + getSlot(address, slot).then(slotValue => ethers.AbiCoder.defaultAbiCoder().decode(['address'], slotValue)[0]); + +const upgradeableSlot = (contractName, offset) => { + try { + // Try to get the artifact paths, will throw if it doesn't exist + artifacts._getArtifactPathSync(`${contractName}Upgradeable`); + return offset + ethers.toBigInt(erc7201Slot(erc7201format(contractName))); + } catch { + return offset; + } +}; + +module.exports = { + ImplementationLabel, + AdminLabel, + BeaconLabel, + ImplementationSlot: erc1967Slot(ImplementationLabel), + AdminSlot: erc1967Slot(AdminLabel), + BeaconSlot: erc1967Slot(BeaconLabel), + erc1967Slot, + erc7201Slot, + erc7201format, + setSlot, + getSlot, + getAddressInSlot, + upgradeableSlot, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/strings.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/strings.js new file mode 100644 index 0000000..4f34099 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/strings.js @@ -0,0 +1,5 @@ +module.exports = { + // Capitalize the first char of a string + // Example: capitalize('uint256') → 'Uint256' + capitalize: str => str.charAt(0).toUpperCase() + str.slice(1), +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/time.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/time.js new file mode 100644 index 0000000..574170c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/time.js @@ -0,0 +1,33 @@ +const { ethers } = require('hardhat'); +const { time, mine, mineUpTo } = require('@nomicfoundation/hardhat-network-helpers'); +const { mapValues } = require('./iterate'); + +const clock = { + blocknumber: () => time.latestBlock().then(ethers.toBigInt), + timestamp: () => time.latest().then(ethers.toBigInt), +}; +const clockFromReceipt = { + blocknumber: receipt => Promise.resolve(receipt).then(({ blockNumber }) => ethers.toBigInt(blockNumber)), + timestamp: receipt => + Promise.resolve(receipt) + .then(({ blockNumber }) => ethers.provider.getBlock(blockNumber)) + .then(({ timestamp }) => ethers.toBigInt(timestamp)), +}; +const increaseBy = { + blockNumber: mine, + timestamp: (delay, mine = true) => + time.latest().then(clock => increaseTo.timestamp(clock + ethers.toNumber(delay), mine)), +}; +const increaseTo = { + blocknumber: mineUpTo, + timestamp: (to, mine = true) => (mine ? time.increaseTo(to) : time.setNextBlockTimestamp(to)), +}; +const duration = mapValues(time.duration, fn => n => ethers.toBigInt(fn(ethers.toNumber(n)))); + +module.exports = { + clock, + clockFromReceipt, + increaseBy, + increaseTo, + duration, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/txpool.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/txpool.js new file mode 100644 index 0000000..f01327b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/txpool.js @@ -0,0 +1,29 @@ +const { network } = require('hardhat'); +const { expect } = require('chai'); +const { mine } = require('@nomicfoundation/hardhat-network-helpers'); + +const { unique } = require('./iterate'); + +async function batchInBlock(txs) { + try { + // disable auto-mining + await network.provider.send('evm_setAutomine', [false]); + // send all transactions + const responses = await Promise.all(txs.map(fn => fn())); + // mine one block + await mine(); + // fetch receipts + const receipts = await Promise.all(responses.map(response => response.wait())); + // Sanity check, all tx should be in the same block + expect(unique(receipts.map(receipt => receipt.blockNumber))).to.have.lengthOf(1); + // return responses + return receipts; + } finally { + // enable auto-mining + await network.provider.send('evm_setAutomine', [true]); + } +} + +module.exports = { + batchInBlock, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js new file mode 100644 index 0000000..ce13996 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js @@ -0,0 +1,133 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { impersonate } = require('../helpers/account'); +const { getDomain, ForwardRequest } = require('../helpers/eip712'); +const { MAX_UINT48 } = require('../helpers/constants'); + +const { shouldBehaveLikeRegularContext } = require('../utils/Context.behavior'); + +async function fixture() { + const [sender, other] = await ethers.getSigners(); + + const forwarder = await ethers.deployContract('ERC2771Forwarder', ['ERC2771Forwarder']); + const forwarderAsSigner = await impersonate(forwarder.target); + const context = await ethers.deployContract('ERC2771ContextMock', [forwarder]); + const domain = await getDomain(forwarder); + const types = { ForwardRequest }; + + return { sender, other, forwarder, forwarderAsSigner, context, domain, types }; +} + +describe('ERC2771Context', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('recognize trusted forwarder', async function () { + expect(await this.context.isTrustedForwarder(this.forwarder)).to.be.true; + }); + + it('returns the trusted forwarder', async function () { + expect(await this.context.trustedForwarder()).to.equal(this.forwarder); + }); + + describe('when called directly', function () { + shouldBehaveLikeRegularContext(); + }); + + describe('when receiving a relayed call', function () { + describe('msgSender', function () { + it('returns the relayed transaction original sender', async function () { + const nonce = await this.forwarder.nonces(this.sender); + const data = this.context.interface.encodeFunctionData('msgSender'); + + const req = { + from: await this.sender.getAddress(), + to: await this.context.getAddress(), + value: 0n, + data, + gas: 100000n, + nonce, + deadline: MAX_UINT48, + }; + + req.signature = await this.sender.signTypedData(this.domain, this.types, req); + + expect(await this.forwarder.verify(req)).to.be.true; + + await expect(this.forwarder.execute(req)).to.emit(this.context, 'Sender').withArgs(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 so `this.forwarderAsSigner` is used instead. + await expect(this.context.connect(this.forwarderAsSigner).msgSender()) + .to.emit(this.context, 'Sender') + .withArgs(this.forwarder); + }); + }); + + describe('msgData', function () { + it('returns the relayed transaction original data', async function () { + const args = [42n, 'OpenZeppelin']; + + const nonce = await this.forwarder.nonces(this.sender); + const data = this.context.interface.encodeFunctionData('msgData', args); + + const req = { + from: await this.sender.getAddress(), + to: await this.context.getAddress(), + value: 0n, + data, + gas: 100000n, + nonce, + deadline: MAX_UINT48, + }; + + req.signature = this.sender.signTypedData(this.domain, this.types, req); + + expect(await this.forwarder.verify(req)).to.be.true; + + await expect(this.forwarder.execute(req)) + .to.emit(this.context, 'Data') + .withArgs(data, ...args); + }); + }); + + it('returns the full original data when calldata length is less than 20 bytes (address length)', async function () { + const data = this.context.interface.encodeFunctionData('msgDataShort'); + + // The forwarder doesn't produce calls with calldata length less than 20 bytes so `this.forwarderAsSigner` is used instead. + await expect(await this.context.connect(this.forwarderAsSigner).msgDataShort()) + .to.emit(this.context, 'DataShort') + .withArgs(data); + }); + }); + + it('multicall poison attack', async function () { + const nonce = await this.forwarder.nonces(this.sender); + const data = this.context.interface.encodeFunctionData('multicall', [ + [ + // poisoned call to 'msgSender()' + ethers.concat([this.context.interface.encodeFunctionData('msgSender'), this.other.address]), + ], + ]); + + const req = { + from: await this.sender.getAddress(), + to: await this.context.getAddress(), + value: 0n, + data, + gas: 100000n, + nonce, + deadline: MAX_UINT48, + }; + + req.signature = await this.sender.signTypedData(this.domain, this.types, req); + + expect(await this.forwarder.verify(req)).to.be.true; + + await expect(this.forwarder.execute(req)).to.emit(this.context, 'Sender').withArgs(this.sender); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.t.sol new file mode 100644 index 0000000..605ae62 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.t.sol @@ -0,0 +1,279 @@ +// 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"; +import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; + +enum TamperType { + FROM, + TO, + VALUE, + DATA, + SIGNATURE +} + +contract ERC2771ForwarderMock is ERC2771Forwarder { + constructor(string memory name) ERC2771Forwarder(name) {} + + function forwardRequestStructHash( + ERC2771Forwarder.ForwardRequestData calldata request, + uint256 nonce + ) external view returns (bytes32) { + return + _hashTypedDataV4( + keccak256( + abi.encode( + _FORWARD_REQUEST_TYPEHASH, + request.from, + request.to, + request.value, + request.gas, + nonce, + request.deadline, + keccak256(request.data) + ) + ) + ); + } +} + +contract ERC2771ForwarderTest is Test { + using ECDSA for bytes32; + + ERC2771ForwarderMock internal _erc2771Forwarder; + CallReceiverMockTrustingForwarder internal _receiver; + + uint256 internal _signerPrivateKey = 0xA11CE; + address internal _signer = vm.addr(_signerPrivateKey); + + uint256 internal constant _MAX_ETHER = 10_000_000; // To avoid overflow + + function setUp() public { + _erc2771Forwarder = new ERC2771ForwarderMock("ERC2771Forwarder"); + _receiver = new CallReceiverMockTrustingForwarder(address(_erc2771Forwarder)); + } + + // Forge a new ForwardRequestData + function _forgeRequestData() private view returns (ERC2771Forwarder.ForwardRequestData memory) { + return + _forgeRequestData({ + value: 0, + deadline: uint48(block.timestamp + 1), + data: abi.encodeCall(CallReceiverMock.mockFunction, ()) + }); + } + + function _forgeRequestData( + uint256 value, + uint48 deadline, + bytes memory data + ) private view returns (ERC2771Forwarder.ForwardRequestData memory) { + return + ERC2771Forwarder.ForwardRequestData({ + from: _signer, + to: address(_receiver), + value: value, + gas: 30000, + deadline: deadline, + data: data, + signature: "" + }); + } + + // Sign a ForwardRequestData (in place) for a given nonce. Also returns it for convenience. + function _signRequestData( + ERC2771Forwarder.ForwardRequestData memory request, + uint256 nonce + ) private view returns (ERC2771Forwarder.ForwardRequestData memory) { + bytes32 digest = _erc2771Forwarder.forwardRequestStructHash(request, nonce); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_signerPrivateKey, digest); + request.signature = abi.encodePacked(r, s, v); + return request; + } + + // Tamper a ForwardRequestData (in place). Also returns it for convenience. + function _tamperRequestData( + ERC2771Forwarder.ForwardRequestData memory request, + TamperType tamper + ) private returns (ERC2771Forwarder.ForwardRequestData memory) { + if (tamper == TamperType.FROM) request.from = vm.randomAddress(); + else if (tamper == TamperType.TO) request.to = vm.randomAddress(); + else if (tamper == TamperType.VALUE) request.value = vm.randomUint(); + else if (tamper == TamperType.DATA) request.data = vm.randomBytes(4); + else if (tamper == TamperType.SIGNATURE) request.signature = vm.randomBytes(65); + + return request; + } + + // Predict the revert error for a tampered request, and expect it is emitted. + function _tamperedExpectRevert( + ERC2771Forwarder.ForwardRequestData memory request, + TamperType tamper, + uint256 nonce + ) private returns (ERC2771Forwarder.ForwardRequestData memory) { + if (tamper == TamperType.FROM) nonce = _erc2771Forwarder.nonces(request.from); + + // predict revert + if (tamper == TamperType.TO) { + vm.expectRevert( + abi.encodeWithSelector( + ERC2771Forwarder.ERC2771UntrustfulTarget.selector, + request.to, + address(_erc2771Forwarder) + ) + ); + } else { + (address recovered, , ) = _erc2771Forwarder.forwardRequestStructHash(request, nonce).tryRecover( + request.signature + ); + vm.expectRevert( + abi.encodeWithSelector(ERC2771Forwarder.ERC2771ForwarderInvalidSigner.selector, recovered, request.from) + ); + } + return request; + } + + function testExecuteAvoidsETHStuck(uint256 initialBalance, uint256 value, bool targetReverts) public { + initialBalance = bound(initialBalance, 0, _MAX_ETHER); + value = bound(value, 0, _MAX_ETHER); + + // create and sign request + ERC2771Forwarder.ForwardRequestData memory request = _forgeRequestData({ + value: value, + deadline: uint48(block.timestamp + 1), + data: targetReverts + ? abi.encodeCall(CallReceiverMock.mockFunctionRevertsNoReason, ()) + : abi.encodeCall(CallReceiverMock.mockFunction, ()) + }); + _signRequestData(request, _erc2771Forwarder.nonces(_signer)); + + vm.deal(address(_erc2771Forwarder), initialBalance); + vm.deal(address(this), request.value); + + if (targetReverts) vm.expectRevert(); + _erc2771Forwarder.execute{value: value}(request); + + assertEq(address(_erc2771Forwarder).balance, initialBalance); + } + + function testExecuteBatchAvoidsETHStuck(uint256 initialBalance, uint256 batchSize, uint256 value) public { + uint256 seed = uint256(keccak256(abi.encodePacked(initialBalance, batchSize, value))); + + batchSize = bound(batchSize, 1, 10); + initialBalance = bound(initialBalance, 0, _MAX_ETHER); + value = bound(value, 0, _MAX_ETHER); + + address refundReceiver = address(0xebe); + uint256 refundExpected = 0; + uint256 nonce = _erc2771Forwarder.nonces(_signer); + + // create an array of signed requests (that may fail) + ERC2771Forwarder.ForwardRequestData[] memory requests = new ERC2771Forwarder.ForwardRequestData[](batchSize); + for (uint256 i = 0; i < batchSize; ++i) { + bool failure = (seed >> i) & 0x1 == 0x1; + + requests[i] = _forgeRequestData({ + value: value, + deadline: uint48(block.timestamp + 1), + data: failure + ? abi.encodeCall(CallReceiverMock.mockFunctionRevertsNoReason, ()) + : abi.encodeCall(CallReceiverMock.mockFunction, ()) + }); + _signRequestData(requests[i], nonce + i); + + refundExpected += SafeCast.toUint(failure) * value; + } + + // distribute ether + vm.deal(address(_erc2771Forwarder), initialBalance); + vm.deal(address(this), value * batchSize); + + // execute batch + _erc2771Forwarder.executeBatch{value: value * batchSize}(requests, payable(refundReceiver)); + + // check balances + assertEq(address(_erc2771Forwarder).balance, initialBalance); + assertEq(refundReceiver.balance, refundExpected); + } + + function testVerifyTamperedValues(uint8 _tamper) public { + TamperType tamper = _asTamper(_tamper); + + // create request, sign, tamper + ERC2771Forwarder.ForwardRequestData memory request = _forgeRequestData(); + _signRequestData(request, 0); + _tamperRequestData(request, tamper); + + // should not pass verification + assertFalse(_erc2771Forwarder.verify(request)); + } + + function testExecuteTamperedValues(uint8 _tamper) public { + TamperType tamper = _asTamper(_tamper); + + // create request, sign, tamper, expect execution revert + ERC2771Forwarder.ForwardRequestData memory request = _forgeRequestData(); + _signRequestData(request, 0); + _tamperRequestData(request, tamper); + _tamperedExpectRevert(request, tamper, 0); + + vm.deal(address(this), request.value); + _erc2771Forwarder.execute{value: request.value}(request); + } + + function testExecuteBatchTamperedValuesZeroReceiver(uint8 _tamper) public { + TamperType tamper = _asTamper(_tamper); + uint256 nonce = _erc2771Forwarder.nonces(_signer); + + // create an array of signed requests + ERC2771Forwarder.ForwardRequestData[] memory requests = new ERC2771Forwarder.ForwardRequestData[](3); + for (uint256 i = 0; i < requests.length; ++i) { + requests[i] = _forgeRequestData({ + value: 0, + deadline: uint48(block.timestamp + 1), + data: abi.encodeCall(CallReceiverMock.mockFunction, ()) + }); + _signRequestData(requests[i], nonce + i); + } + + // tamper with request[1] and expect execution revert + _tamperRequestData(requests[1], tamper); + _tamperedExpectRevert(requests[1], tamper, nonce + 1); + + vm.deal(address(this), requests[1].value); + _erc2771Forwarder.executeBatch{value: requests[1].value}(requests, payable(address(0))); + } + + function testExecuteBatchTamperedValues(uint8 _tamper) public { + TamperType tamper = _asTamper(_tamper); + uint256 nonce = _erc2771Forwarder.nonces(_signer); + + // create an array of signed requests + ERC2771Forwarder.ForwardRequestData[] memory requests = new ERC2771Forwarder.ForwardRequestData[](3); + for (uint256 i = 0; i < requests.length; ++i) { + requests[i] = _forgeRequestData({ + value: 0, + deadline: uint48(block.timestamp + 1), + data: abi.encodeCall(CallReceiverMock.mockFunction, ()) + }); + _signRequestData(requests[i], nonce + i); + } + + // tamper with request[1] + _tamperRequestData(requests[1], tamper); + + // should not revert + vm.expectCall(address(_receiver), abi.encodeCall(CallReceiverMock.mockFunction, ()), 1); + + vm.deal(address(this), requests[1].value); + _erc2771Forwarder.executeBatch{value: requests[1].value}(requests, payable(address(0xebe))); + } + + function _asTamper(uint8 _tamper) private pure returns (TamperType) { + return TamperType(bound(_tamper, uint8(TamperType.FROM), uint8(TamperType.SIGNATURE))); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.test.js new file mode 100644 index 0000000..07682c1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.test.js @@ -0,0 +1,384 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain, ForwardRequest } = require('../helpers/eip712'); +const { sum } = require('../helpers/math'); +const time = require('../helpers/time'); + +async function fixture() { + const [sender, refundReceiver, another, ...accounts] = await ethers.getSigners(); + + const forwarder = await ethers.deployContract('ERC2771Forwarder', ['ERC2771Forwarder']); + const receiver = await ethers.deployContract('CallReceiverMockTrustingForwarder', [forwarder]); + const domain = await getDomain(forwarder); + const types = { ForwardRequest }; + + const forgeRequest = async (override = {}, signer = sender) => { + const req = { + from: await signer.getAddress(), + to: await receiver.getAddress(), + value: 0n, + data: receiver.interface.encodeFunctionData('mockFunction'), + gas: 100000n, + deadline: (await time.clock.timestamp()) + 60n, + nonce: await forwarder.nonces(sender), + ...override, + }; + req.signature = await signer.signTypedData(domain, types, req); + return req; + }; + + const estimateRequest = request => + ethers.provider.estimateGas({ + from: forwarder, + to: request.to, + data: ethers.solidityPacked(['bytes', 'address'], [request.data, request.from]), + value: request.value, + gasLimit: request.gas, + }); + + return { + sender, + refundReceiver, + another, + accounts, + forwarder, + receiver, + forgeRequest, + estimateRequest, + domain, + types, + }; +} + +describe('ERC2771Forwarder', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('verify', function () { + describe('with valid signature', function () { + it('returns true without altering the nonce', async function () { + const request = await this.forgeRequest(); + expect(await this.forwarder.nonces(request.from)).to.equal(request.nonce); + expect(await this.forwarder.verify(request)).to.be.true; + expect(await this.forwarder.nonces(request.from)).to.equal(request.nonce); + }); + }); + + describe('with tampered values', function () { + it('returns false with valid signature for non-current nonce', async function () { + const request = await this.forgeRequest({ nonce: 1337n }); + expect(await this.forwarder.verify(request)).to.be.false; + }); + + it('returns false with valid signature for expired deadline', async function () { + const request = await this.forgeRequest({ deadline: (await time.clock.timestamp()) - 1n }); + expect(await this.forwarder.verify(request)).to.be.false; + }); + }); + }); + + describe('execute', function () { + describe('with valid requests', function () { + it('emits an event and consumes nonce for a successful request', async function () { + const request = await this.forgeRequest(); + + expect(await this.forwarder.nonces(request.from)).to.equal(request.nonce); + + await expect(this.forwarder.execute(request)) + .to.emit(this.receiver, 'MockFunctionCalled') + .to.emit(this.forwarder, 'ExecutedForwardRequest') + .withArgs(request.from, request.nonce, true); + + expect(await this.forwarder.nonces(request.from)).to.equal(request.nonce + 1n); + }); + + it('reverts with an unsuccessful request', async function () { + const request = await this.forgeRequest({ + data: this.receiver.interface.encodeFunctionData('mockFunctionRevertsNoReason'), + }); + + await expect(this.forwarder.execute(request)).to.be.revertedWithCustomError(this.forwarder, 'FailedCall'); + }); + }); + + describe('with tampered request', function () { + it('reverts with valid signature for non-current nonce', async function () { + const request = await this.forgeRequest(); + + // consume nonce + await this.forwarder.execute(request); + + // nonce has changed + await expect(this.forwarder.execute(request)) + .to.be.revertedWithCustomError(this.forwarder, 'ERC2771ForwarderInvalidSigner') + .withArgs( + ethers.verifyTypedData( + this.domain, + this.types, + { ...request, nonce: request.nonce + 1n }, + request.signature, + ), + request.from, + ); + }); + + it('reverts with valid signature for expired deadline', async function () { + const request = await this.forgeRequest({ deadline: (await time.clock.timestamp()) - 1n }); + + await expect(this.forwarder.execute(request)) + .to.be.revertedWithCustomError(this.forwarder, 'ERC2771ForwarderExpiredRequest') + .withArgs(request.deadline); + }); + + it('reverts with valid signature but mismatched value', async function () { + const request = await this.forgeRequest({ value: 100n }); + + await expect(this.forwarder.execute(request)) + .to.be.revertedWithCustomError(this.forwarder, 'ERC2771ForwarderMismatchedValue') + .withArgs(request.value, 0n); + }); + }); + + it('bubbles out of gas', async function () { + const request = await this.forgeRequest({ + data: this.receiver.interface.encodeFunctionData('mockFunctionOutOfGas'), + gas: 1_000_000n, + }); + + const gasLimit = 100_000n; + await expect(this.forwarder.execute(request, { gasLimit })).to.be.revertedWithoutReason(); + + const { gasUsed } = await ethers.provider + .getBlock('latest') + .then(block => block.getTransaction(0)) + .then(tx => ethers.provider.getTransactionReceipt(tx.hash)); + + expect(gasUsed).to.equal(gasLimit); + }); + + it('bubbles out of gas forced by the relayer', async function () { + const request = await this.forgeRequest(); + + // 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(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 gasLimit = estimate + 10_000n; + + // The subcall out of gas should be caught by the contract and then bubbled up consuming + // the available gas with an `invalid` opcode. + await expect(this.forwarder.execute(request, { gasLimit })).to.be.revertedWithoutReason(); + + const { gasUsed } = await ethers.provider + .getBlock('latest') + .then(block => block.getTransaction(0)) + .then(tx => ethers.provider.getTransactionReceipt(tx.hash)); + + // We assert that indeed the gas was totally consumed. + expect(gasUsed).to.equal(gasLimit); + }); + }); + + describe('executeBatch', function () { + const requestsValue = requests => sum(...requests.map(request => request.value)); + const requestCount = 3; + const idx = 1; // index that will be tampered with + + beforeEach(async function () { + this.forgeRequests = override => + Promise.all(this.accounts.slice(0, requestCount).map(signer => this.forgeRequest(override, signer))); + this.requests = await this.forgeRequests({ value: 10n }); + this.value = requestsValue(this.requests); + }); + + describe('with valid requests', function () { + it('sanity', async function () { + for (const request of this.requests) { + expect(await this.forwarder.verify(request)).to.be.true; + } + }); + + it('emits events', async function () { + const receipt = this.forwarder.executeBatch(this.requests, this.another, { value: this.value }); + + for (const request of this.requests) { + await expect(receipt) + .to.emit(this.receiver, 'MockFunctionCalled') + .to.emit(this.forwarder, 'ExecutedForwardRequest') + .withArgs(request.from, request.nonce, true); + } + }); + + it('increase nonces', async function () { + await this.forwarder.executeBatch(this.requests, this.another, { value: this.value }); + + for (const request of this.requests) { + expect(await this.forwarder.nonces(request.from)).to.equal(request.nonce + 1n); + } + }); + }); + + describe('with tampered requests', function () { + it('reverts with mismatched value', async function () { + // tamper value of one of the request + resign + this.requests[idx] = await this.forgeRequest({ value: 100n }, this.accounts[1]); + + await expect(this.forwarder.executeBatch(this.requests, this.another, { value: this.value })) + .to.be.revertedWithCustomError(this.forwarder, 'ERC2771ForwarderMismatchedValue') + .withArgs(requestsValue(this.requests), this.value); + }); + + describe('when the refund receiver is the zero address', function () { + beforeEach(function () { + this.refundReceiver = ethers.ZeroAddress; + }); + + it('reverts with at least one valid signature for non-current nonce', async function () { + // Execute first a request + await this.forwarder.execute(this.requests[idx], { value: this.requests[idx].value }); + + // And then fail due to an already used nonce + await expect(this.forwarder.executeBatch(this.requests, this.refundReceiver, { value: this.value })) + .to.be.revertedWithCustomError(this.forwarder, 'ERC2771ForwarderInvalidSigner') + .withArgs( + ethers.verifyTypedData( + this.domain, + this.types, + { ...this.requests[idx], nonce: this.requests[idx].nonce + 1n }, + this.requests[idx].signature, + ), + this.requests[idx].from, + ); + }); + + it('reverts with at least one valid signature for expired deadline', async function () { + this.requests[idx] = await this.forgeRequest( + { ...this.requests[idx], deadline: (await time.clock.timestamp()) - 1n }, + this.accounts[1], + ); + + await expect(this.forwarder.executeBatch(this.requests, this.refundReceiver, { value: this.amount })) + .to.be.revertedWithCustomError(this.forwarder, 'ERC2771ForwarderExpiredRequest') + .withArgs(this.requests[idx].deadline); + }); + }); + + describe('when the refund receiver is a known address', function () { + beforeEach(async function () { + this.initialRefundReceiverBalance = await ethers.provider.getBalance(this.refundReceiver); + this.initialTamperedRequestNonce = await this.forwarder.nonces(this.requests[idx].from); + }); + + it('ignores a request with a valid signature for non-current nonce', async function () { + // Execute first a request + await this.forwarder.execute(this.requests[idx], { value: this.requests[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 events = await this.forwarder + .executeBatch(this.requests, this.refundReceiver, { value: this.value }) + .then(tx => tx.wait()) + .then(receipt => + receipt.logs.filter( + log => log?.fragment?.type == 'event' && log?.fragment?.name == 'ExecutedForwardRequest', + ), + ); + + expect(events).to.have.lengthOf(this.requests.length - 1); + }); + + it('ignores a request with a valid signature for expired deadline', async function () { + this.requests[idx] = await this.forgeRequest( + { ...this.requests[idx], deadline: (await time.clock.timestamp()) - 1n }, + this.accounts[1], + ); + + const events = await this.forwarder + .executeBatch(this.requests, this.refundReceiver, { value: this.value }) + .then(tx => tx.wait()) + .then(receipt => + receipt.logs.filter( + log => log?.fragment?.type == 'event' && log?.fragment?.name == 'ExecutedForwardRequest', + ), + ); + + expect(events).to.have.lengthOf(this.requests.length - 1); + }); + + afterEach(async function () { + // The invalid request value was refunded + expect(await ethers.provider.getBalance(this.refundReceiver)).to.equal( + this.initialRefundReceiverBalance + this.requests[idx].value, + ); + + // The invalid request from's nonce was not incremented + expect(await this.forwarder.nonces(this.requests[idx].from)).to.equal(this.initialTamperedRequestNonce); + }); + }); + + it('bubbles out of gas', async function () { + this.requests[idx] = await this.forgeRequest({ + data: this.receiver.interface.encodeFunctionData('mockFunctionOutOfGas'), + gas: 1_000_000n, + }); + + const gasLimit = 300_000n; + await expect( + this.forwarder.executeBatch(this.requests, ethers.ZeroAddress, { + gasLimit, + value: requestsValue(this.requests), + }), + ).to.be.revertedWithoutReason(); + + const { gasUsed } = await ethers.provider + .getBlock('latest') + .then(block => block.getTransaction(0)) + .then(tx => ethers.provider.getTransactionReceipt(tx.hash)); + + expect(gasUsed).to.equal(gasLimit); + }); + + 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 Promise.all(this.requests.slice(0, idx + 1).map(this.estimateRequest)).then(gas => + sum(...gas), + ); + + // 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 gasLimit = estimate + 10_000n; + + // The subcall out of gas should be caught by the contract and then bubbled up consuming + // the available gas with an `invalid` opcode. + await expect( + this.forwarder.executeBatch(this.requests, ethers.ZeroAddress, { + gasLimit, + value: requestsValue(this.requests), + }), + ).to.be.revertedWithoutReason(); + + const { gasUsed } = await ethers.provider + .getBlock('latest') + .then(block => block.getTransaction(0)) + .then(tx => ethers.provider.getTransactionReceipt(tx.hash)); + + // We assert that indeed the gas was totally consumed. + expect(gasUsed).to.equal(gasLimit); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js new file mode 100644 index 0000000..dcc6206 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js @@ -0,0 +1,160 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); + +module.exports = function shouldBehaveLikeClone() { + const assertProxyInitialization = function ({ value, balance }) { + it('initializes the proxy', async function () { + const dummy = await ethers.getContractAt('DummyImplementation', this.proxy); + expect(await dummy.value()).to.equal(value); + }); + + it('has expected balance', async function () { + expect(await ethers.provider.getBalance(this.proxy)).to.equal(balance); + }); + }; + + describe('construct with value', function () { + const value = 10n; + + it('factory has enough balance', async function () { + await this.deployer.sendTransaction({ to: this.factory, value }); + + const instance = await this.createClone({ deployValue: value }); + await expect(instance.deploymentTransaction()).to.changeEtherBalances([this.factory, instance], [-value, value]); + + expect(await ethers.provider.getBalance(instance)).to.equal(value); + }); + + it('factory does not have enough balance', async function () { + await expect(this.createClone({ deployValue: value })) + .to.be.revertedWithCustomError(this.factory, 'InsufficientBalance') + .withArgs(0n, value); + }); + }); + + describe('initialization without parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10n; + + beforeEach(async function () { + this.initializeData = await this.implementation.interface.encodeFunctionData('initializeNonPayable'); + }); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = await this.createClone({ initData: this.initializeData }); + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10n ** 6n; + + it('reverts', async function () { + await expect(this.createClone({ initData: this.initializeData, initValue: value })).to.be.reverted; + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 100n; + + beforeEach(async function () { + this.initializeData = await this.implementation.interface.encodeFunctionData('initializePayable'); + }); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = await this.createClone({ initData: this.initializeData }); + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10n ** 6n; + + beforeEach('creating proxy', async function () { + this.proxy = await this.createClone({ initData: this.initializeData, initValue: value }); + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); + + describe('initialization with parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10n; + + beforeEach(async function () { + this.initializeData = await this.implementation.interface.encodeFunctionData('initializeNonPayableWithValue', [ + expectedInitializedValue, + ]); + }); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = await this.createClone({ initData: this.initializeData }); + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10n ** 6n; + + it('reverts', async function () { + await expect(this.createClone({ initData: this.initializeData, initValue: value })).to.be.reverted; + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 42n; + + beforeEach(function () { + this.initializeData = this.implementation.interface.encodeFunctionData('initializePayableWithValue', [ + expectedInitializedValue, + ]); + }); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = await this.createClone({ initData: this.initializeData }); + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10n ** 6n; + + beforeEach('creating proxy', async function () { + this.proxy = await this.createClone({ initData: this.initializeData, initValue: value }); + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.t.sol new file mode 100644 index 0000000..5da6d56 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.t.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; + +contract ClonesTest is Test { + function getNumber() external pure returns (uint256) { + return 42; + } + + function testSymbolicPredictDeterministicAddressSpillage(address implementation, bytes32 salt) public view { + address predicted = Clones.predictDeterministicAddress(implementation, salt); + bytes32 spillage; + assembly ("memory-safe") { + spillage := and(predicted, 0xffffffffffffffffffffffff0000000000000000000000000000000000000000) + } + assertEq(spillage, bytes32(0)); + } + + function testSymbolicPredictDeterministicAddressWithImmutableArgsSpillage( + address implementation, + bytes32 salt, + bytes memory args + ) public view { + vm.assume(args.length < 0xbfd3); + + address predicted = Clones.predictDeterministicAddressWithImmutableArgs(implementation, args, salt); + bytes32 spillage; + /// @solidity memory-safe-assembly + assembly { + spillage := and(predicted, 0xffffffffffffffffffffffff0000000000000000000000000000000000000000) + } + assertEq(spillage, bytes32(0)); + } + + function testCloneDirty() external { + address cloneClean = Clones.clone(address(this)); + address cloneDirty = Clones.clone(_dirty(address(this))); + + // both clones have the same code + assertEq(cloneClean.code, cloneDirty.code); + + // both clones behave as expected + assertEq(ClonesTest(cloneClean).getNumber(), this.getNumber()); + assertEq(ClonesTest(cloneDirty).getNumber(), this.getNumber()); + } + + function testCloneDeterministicDirty(bytes32 salt) external { + address cloneClean = Clones.cloneDeterministic(address(this), salt); + address cloneDirty = Clones.cloneDeterministic(_dirty(address(this)), ~salt); + + // both clones have the same code + assertEq(cloneClean.code, cloneDirty.code); + + // both clones behave as expected + assertEq(ClonesTest(cloneClean).getNumber(), this.getNumber()); + assertEq(ClonesTest(cloneDirty).getNumber(), this.getNumber()); + } + + function testPredictDeterministicAddressDirty(bytes32 salt) external view { + address predictClean = Clones.predictDeterministicAddress(address(this), salt); + address predictDirty = Clones.predictDeterministicAddress(_dirty(address(this)), salt); + + //prediction should be similar + assertEq(predictClean, predictDirty); + } + + function testFetchCloneArgs(bytes memory args, bytes32 salt) external { + vm.assume(args.length < 0xbfd3); + + address instance1 = Clones.cloneWithImmutableArgs(address(this), args); + address instance2 = Clones.cloneDeterministicWithImmutableArgs(address(this), args, salt); + + // both clones have the same code + assertEq(instance1.code, instance2.code); + + // both clones behave as expected and args can be fetched + assertEq(ClonesTest(instance1).getNumber(), this.getNumber()); + assertEq(ClonesTest(instance2).getNumber(), this.getNumber()); + assertEq(Clones.fetchCloneArgs(instance1), args); + assertEq(Clones.fetchCloneArgs(instance2), args); + } + + function _dirty(address input) private pure returns (address output) { + assembly ("memory-safe") { + output := or(input, shl(160, not(0))) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.test.js new file mode 100644 index 0000000..93bcfba --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.test.js @@ -0,0 +1,177 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { generators } = require('../helpers/random'); + +const shouldBehaveLikeClone = require('./Clones.behaviour'); + +const cloneInitCode = (instance, args = undefined) => + args + ? ethers.concat([ + '0x61', + ethers.toBeHex(0x2d + ethers.getBytes(args).length, 2), + '0x3d81600a3d39f3363d3d373d3d3d363d73', + instance.target ?? instance.address ?? instance, + '0x5af43d82803e903d91602b57fd5bf3', + args, + ]) + : ethers.concat([ + '0x3d602d80600a3d3981f3363d3d373d3d3d363d73', + instance.target ?? instance.address ?? instance, + '0x5af43d82803e903d91602b57fd5bf3', + ]); + +async function fixture() { + const [deployer] = await ethers.getSigners(); + + const factory = await ethers.deployContract('$Clones'); + const implementation = await ethers.deployContract('DummyImplementation'); + + const newClone = + args => + async (opts = {}) => { + const clone = await ( + args + ? factory.$cloneWithImmutableArgs.staticCall(implementation, args) + : factory.$clone.staticCall(implementation) + ).then(address => implementation.attach(address)); + const tx = await (args + ? opts.deployValue + ? factory.$cloneWithImmutableArgs(implementation, args, ethers.Typed.uint256(opts.deployValue)) + : factory.$cloneWithImmutableArgs(implementation, args) + : opts.deployValue + ? factory.$clone(implementation, ethers.Typed.uint256(opts.deployValue)) + : factory.$clone(implementation)); + if (opts.initData || opts.initValue) { + await deployer.sendTransaction({ to: clone, value: opts.initValue ?? 0n, data: opts.initData ?? '0x' }); + } + return Object.assign(clone, { deploymentTransaction: () => tx }); + }; + + const newCloneDeterministic = + args => + async (opts = {}) => { + const salt = opts.salt ?? ethers.randomBytes(32); + const clone = await ( + args + ? factory.$cloneDeterministicWithImmutableArgs.staticCall(implementation, args, salt) + : factory.$cloneDeterministic.staticCall(implementation, salt) + ).then(address => implementation.attach(address)); + const tx = await (args + ? opts.deployValue + ? factory.$cloneDeterministicWithImmutableArgs( + implementation, + args, + salt, + ethers.Typed.uint256(opts.deployValue), + ) + : factory.$cloneDeterministicWithImmutableArgs(implementation, args, salt) + : opts.deployValue + ? factory.$cloneDeterministic(implementation, salt, ethers.Typed.uint256(opts.deployValue)) + : factory.$cloneDeterministic(implementation, salt)); + if (opts.initData || opts.initValue) { + await deployer.sendTransaction({ to: clone, value: opts.initValue ?? 0n, data: opts.initData ?? '0x' }); + } + return Object.assign(clone, { deploymentTransaction: () => tx }); + }; + + return { deployer, factory, implementation, newClone, newCloneDeterministic }; +} + +describe('Clones', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + for (const args of [undefined, '0x', '0x11223344']) { + describe(args ? `with immutable args: ${args}` : 'without immutable args', function () { + describe('clone', function () { + beforeEach(async function () { + this.createClone = this.newClone(args); + }); + + shouldBehaveLikeClone(); + + it('get immutable arguments', async function () { + const instance = await this.createClone(); + expect(await this.factory.$fetchCloneArgs(instance)).to.equal(args ?? '0x'); + }); + }); + + describe('cloneDeterministic', function () { + beforeEach(async function () { + this.createClone = this.newCloneDeterministic(args); + }); + + shouldBehaveLikeClone(); + + it('get immutable arguments', async function () { + const instance = await this.createClone(); + expect(await this.factory.$fetchCloneArgs(instance)).to.equal(args ?? '0x'); + }); + + it('revert if address already used', async function () { + const salt = ethers.randomBytes(32); + + const deployClone = () => + args + ? this.factory.$cloneDeterministicWithImmutableArgs(this.implementation, args, salt) + : this.factory.$cloneDeterministic(this.implementation, salt); + + // deploy once + await expect(deployClone()).to.not.be.reverted; + + // deploy twice + await expect(deployClone()).to.be.revertedWithCustomError(this.factory, 'FailedDeployment'); + }); + + it('address prediction', async function () { + const salt = ethers.randomBytes(32); + + const expected = ethers.getCreate2Address( + this.factory.target, + salt, + ethers.keccak256(cloneInitCode(this.implementation, args)), + ); + + if (args) { + const predicted = await this.factory.$predictDeterministicAddressWithImmutableArgs( + this.implementation, + args, + salt, + ); + expect(predicted).to.equal(expected); + + await expect(this.factory.$cloneDeterministicWithImmutableArgs(this.implementation, args, salt)) + .to.emit(this.factory, 'return$cloneDeterministicWithImmutableArgs_address_bytes_bytes32') + .withArgs(predicted); + } else { + const predicted = await this.factory.$predictDeterministicAddress(this.implementation, salt); + expect(predicted).to.equal(expected); + + await expect(this.factory.$cloneDeterministic(this.implementation, salt)) + .to.emit(this.factory, 'return$cloneDeterministic_address_bytes32') + .withArgs(predicted); + } + }); + }); + }); + } + + it('EIP-170 limit on immutable args', async function () { + // EIP-170 limits the contract code size to 0x6000 + // This limits the length of immutable args to 0x5fd3 + const args = generators.hexBytes(0x5fd4); + const salt = ethers.randomBytes(32); + + await expect( + this.factory.$predictDeterministicAddressWithImmutableArgs(this.implementation, args, salt), + ).to.be.revertedWithCustomError(this.factory, 'CloneArgumentsTooLong'); + + await expect(this.factory.$cloneWithImmutableArgs(this.implementation, args)).to.be.revertedWithCustomError( + this.factory, + 'CloneArgumentsTooLong', + ); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js new file mode 100644 index 0000000..b222800 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js @@ -0,0 +1,23 @@ +const { ethers } = require('hardhat'); + +const shouldBehaveLikeProxy = require('../Proxy.behaviour'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const fixture = async () => { + const [nonContractAddress] = await ethers.getSigners(); + + const implementation = await ethers.deployContract('DummyImplementation'); + + const createProxy = (implementation, initData, opts) => + ethers.deployContract('ERC1967Proxy', [implementation, initData], opts); + + return { nonContractAddress, implementation, createProxy }; +}; + +describe('ERC1967Proxy', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeProxy(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Utils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Utils.test.js new file mode 100644 index 0000000..0890324 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Utils.test.js @@ -0,0 +1,162 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getAddressInSlot, setSlot, ImplementationSlot, AdminSlot, BeaconSlot } = require('../../helpers/storage'); + +async function fixture() { + const [, admin, anotherAccount] = await ethers.getSigners(); + + const utils = await ethers.deployContract('$ERC1967Utils'); + const v1 = await ethers.deployContract('DummyImplementation'); + const v2 = await ethers.deployContract('CallReceiverMock'); + + return { admin, anotherAccount, utils, v1, v2 }; +} + +describe('ERC1967Utils', function () { + beforeEach('setup', async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('IMPLEMENTATION_SLOT', function () { + beforeEach('set v1 implementation', async function () { + await setSlot(this.utils, ImplementationSlot, this.v1); + }); + + describe('getImplementation', function () { + it('returns current implementation and matches implementation slot value', async function () { + expect(await this.utils.$getImplementation()).to.equal(this.v1); + expect(await getAddressInSlot(this.utils, ImplementationSlot)).to.equal(this.v1); + }); + }); + + describe('upgradeToAndCall', function () { + it('sets implementation in storage and emits event', async function () { + const newImplementation = this.v2; + const tx = await this.utils.$upgradeToAndCall(newImplementation, '0x'); + + expect(await getAddressInSlot(this.utils, ImplementationSlot)).to.equal(newImplementation); + await expect(tx).to.emit(this.utils, 'Upgraded').withArgs(newImplementation); + }); + + it('reverts when implementation does not contain code', async function () { + await expect(this.utils.$upgradeToAndCall(this.anotherAccount, '0x')) + .to.be.revertedWithCustomError(this.utils, 'ERC1967InvalidImplementation') + .withArgs(this.anotherAccount); + }); + + describe('when data is empty', function () { + it('reverts when value is sent', async function () { + await expect(this.utils.$upgradeToAndCall(this.v2, '0x', { value: 1 })).to.be.revertedWithCustomError( + this.utils, + 'ERC1967NonPayable', + ); + }); + }); + + describe('when data is not empty', function () { + it('delegates a call to the new implementation', async function () { + const initializeData = this.v2.interface.encodeFunctionData('mockFunction'); + const tx = await this.utils.$upgradeToAndCall(this.v2, initializeData); + await expect(tx).to.emit(await ethers.getContractAt('CallReceiverMock', this.utils), 'MockFunctionCalled'); + }); + }); + }); + }); + + describe('ADMIN_SLOT', function () { + beforeEach('set admin', async function () { + await setSlot(this.utils, AdminSlot, this.admin); + }); + + describe('getAdmin', function () { + it('returns current admin and matches admin slot value', async function () { + expect(await this.utils.$getAdmin()).to.equal(this.admin); + expect(await getAddressInSlot(this.utils, AdminSlot)).to.equal(this.admin); + }); + }); + + describe('changeAdmin', function () { + it('sets admin in storage and emits event', async function () { + const newAdmin = this.anotherAccount; + const tx = await this.utils.$changeAdmin(newAdmin); + + expect(await getAddressInSlot(this.utils, AdminSlot)).to.equal(newAdmin); + await expect(tx).to.emit(this.utils, 'AdminChanged').withArgs(this.admin, newAdmin); + }); + + it('reverts when setting the address zero as admin', async function () { + await expect(this.utils.$changeAdmin(ethers.ZeroAddress)) + .to.be.revertedWithCustomError(this.utils, 'ERC1967InvalidAdmin') + .withArgs(ethers.ZeroAddress); + }); + }); + }); + + describe('BEACON_SLOT', function () { + beforeEach('set beacon', async function () { + this.beacon = await ethers.deployContract('UpgradeableBeaconMock', [this.v1]); + await setSlot(this.utils, BeaconSlot, this.beacon); + }); + + describe('getBeacon', function () { + it('returns current beacon and matches beacon slot value', async function () { + expect(await this.utils.$getBeacon()).to.equal(this.beacon); + expect(await getAddressInSlot(this.utils, BeaconSlot)).to.equal(this.beacon); + }); + }); + + describe('upgradeBeaconToAndCall', function () { + it('sets beacon in storage and emits event', async function () { + const newBeacon = await ethers.deployContract('UpgradeableBeaconMock', [this.v2]); + const tx = await this.utils.$upgradeBeaconToAndCall(newBeacon, '0x'); + + expect(await getAddressInSlot(this.utils, BeaconSlot)).to.equal(newBeacon); + await expect(tx).to.emit(this.utils, 'BeaconUpgraded').withArgs(newBeacon); + }); + + it('reverts when beacon does not contain code', async function () { + await expect(this.utils.$upgradeBeaconToAndCall(this.anotherAccount, '0x')) + .to.be.revertedWithCustomError(this.utils, 'ERC1967InvalidBeacon') + .withArgs(this.anotherAccount); + }); + + it("reverts when beacon's implementation does not contain code", async function () { + const newBeacon = await ethers.deployContract('UpgradeableBeaconMock', [this.anotherAccount]); + + await expect(this.utils.$upgradeBeaconToAndCall(newBeacon, '0x')) + .to.be.revertedWithCustomError(this.utils, 'ERC1967InvalidImplementation') + .withArgs(this.anotherAccount); + }); + + describe('when data is empty', function () { + it('reverts when value is sent', async function () { + const newBeacon = await ethers.deployContract('UpgradeableBeaconMock', [this.v2]); + await expect(this.utils.$upgradeBeaconToAndCall(newBeacon, '0x', { value: 1 })).to.be.revertedWithCustomError( + this.utils, + 'ERC1967NonPayable', + ); + }); + }); + + describe('when data is not empty', function () { + it('delegates a call to the new implementation', async function () { + const initializeData = this.v2.interface.encodeFunctionData('mockFunction'); + const newBeacon = await ethers.deployContract('UpgradeableBeaconMock', [this.v2]); + const tx = await this.utils.$upgradeBeaconToAndCall(newBeacon, initializeData); + await expect(tx).to.emit(await ethers.getContractAt('CallReceiverMock', this.utils), 'MockFunctionCalled'); + }); + }); + + describe('reentrant beacon implementation() call', function () { + it('sees the new beacon implementation', async function () { + const newBeacon = await ethers.deployContract('UpgradeableBeaconReentrantMock'); + await expect(this.utils.$upgradeBeaconToAndCall(newBeacon, '0x')) + .to.be.revertedWithCustomError(newBeacon, 'BeaconProxyBeaconSlotAddress') + .withArgs(newBeacon); + }); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js new file mode 100644 index 0000000..f459c09 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js @@ -0,0 +1,185 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); + +const { getAddressInSlot, ImplementationSlot } = require('../helpers/storage'); + +module.exports = function shouldBehaveLikeProxy() { + it('cannot be initialized with a non-contract address', async function () { + const initializeData = '0x'; + const contractFactory = await ethers.getContractFactory('ERC1967Proxy'); + await expect(this.createProxy(this.nonContractAddress, initializeData)) + .to.be.revertedWithCustomError(contractFactory, 'ERC1967InvalidImplementation') + .withArgs(this.nonContractAddress); + }); + + const assertProxyInitialization = function ({ value, balance }) { + it('sets the implementation address', async function () { + expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.implementation); + }); + + it('initializes the proxy', async function () { + const dummy = this.implementation.attach(this.proxy); + expect(await dummy.value()).to.equal(value); + }); + + it('has expected balance', async function () { + expect(await ethers.provider.getBalance(this.proxy)).to.equal(balance); + }); + }; + + describe('without initialization', function () { + const initializeData = '0x'; + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = await this.createProxy(this.implementation, initializeData); + }); + + assertProxyInitialization({ value: 0n, balance: 0n }); + }); + + describe('when sending some balance', function () { + const value = 10n ** 5n; + + it('reverts', async function () { + await expect(this.createProxy(this.implementation, initializeData, { value })).to.be.reverted; + }); + }); + }); + + describe('initialization without parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10n; + + beforeEach(function () { + this.initializeData = this.implementation.interface.encodeFunctionData('initializeNonPayable'); + }); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = await this.createProxy(this.implementation, this.initializeData); + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0n, + }); + }); + + describe('when sending some balance', function () { + const value = 10n ** 5n; + + it('reverts', async function () { + await expect(this.createProxy(this.implementation, this.initializeData, { value })).to.be.reverted; + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 100n; + + beforeEach(function () { + this.initializeData = this.implementation.interface.encodeFunctionData('initializePayable'); + }); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = await this.createProxy(this.implementation, this.initializeData); + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0n, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = await this.createProxy(this.implementation, this.initializeData, { value }); + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); + + describe('initialization with parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10n; + + beforeEach(function () { + this.initializeData = this.implementation.interface.encodeFunctionData('initializeNonPayableWithValue', [ + expectedInitializedValue, + ]); + }); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = await this.createProxy(this.implementation, this.initializeData); + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expect(this.createProxy(this.implementation, this.initializeData, { value })).to.be.reverted; + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 42n; + + beforeEach(function () { + this.initializeData = this.implementation.interface.encodeFunctionData('initializePayableWithValue', [ + expectedInitializedValue, + ]); + }); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = await this.createProxy(this.implementation, this.initializeData); + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0n, + }); + }); + + describe('when sending some balance', function () { + const value = 10n ** 5n; + + beforeEach('creating proxy', async function () { + this.proxy = await this.createProxy(this.implementation, this.initializeData, { value }); + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + + describe('reverting initialization', function () { + beforeEach(function () { + this.initializeData = this.implementation.interface.encodeFunctionData('reverts'); + }); + + it('reverts', async function () { + await expect(this.createProxy(this.implementation, this.initializeData)).to.be.reverted; + }); + }); + }); +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js new file mode 100644 index 0000000..d64023b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js @@ -0,0 +1,141 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getAddressInSlot, BeaconSlot } = require('../../helpers/storage'); + +async function fixture() { + const [admin, other] = await ethers.getSigners(); + + const v1 = await ethers.deployContract('DummyImplementation'); + const v2 = await ethers.deployContract('DummyImplementationV2'); + const factory = await ethers.getContractFactory('BeaconProxy'); + const beacon = await ethers.deployContract('UpgradeableBeacon', [v1, admin]); + + const newBeaconProxy = (beacon, data, opts = {}) => factory.deploy(beacon, data, opts); + + return { admin, other, factory, beacon, v1, v2, newBeaconProxy }; +} + +describe('BeaconProxy', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('bad beacon is not accepted', function () { + it('non-contract beacon', async function () { + const notBeacon = this.other; + + await expect(this.newBeaconProxy(notBeacon, '0x')) + .to.be.revertedWithCustomError(this.factory, 'ERC1967InvalidBeacon') + .withArgs(notBeacon); + }); + + it('non-compliant beacon', async function () { + const badBeacon = await ethers.deployContract('BadBeaconNoImpl'); + + // BadBeaconNoImpl does not provide `implementation()` and has no fallback. + // This causes ERC1967Utils._setBeacon to revert. + await expect(this.newBeaconProxy(badBeacon, '0x')).to.be.revertedWithoutReason(); + }); + + it('non-contract implementation', async function () { + const badBeacon = await ethers.deployContract('BadBeaconNotContract'); + + await expect(this.newBeaconProxy(badBeacon, '0x')) + .to.be.revertedWithCustomError(this.factory, 'ERC1967InvalidImplementation') + .withArgs(await badBeacon.implementation()); + }); + }); + + describe('initialization', function () { + async function assertInitialized({ value, balance }) { + const beaconAddress = await getAddressInSlot(this.proxy, BeaconSlot); + expect(beaconAddress).to.equal(this.beacon); + + const dummy = this.v1.attach(this.proxy); + expect(await dummy.value()).to.equal(value); + + expect(await ethers.provider.getBalance(this.proxy)).to.equal(balance); + } + + it('no initialization', async function () { + this.proxy = await this.newBeaconProxy(this.beacon, '0x'); + await assertInitialized.bind(this)({ value: 0n, balance: 0n }); + }); + + it('non-payable initialization', async function () { + const value = 55n; + const data = this.v1.interface.encodeFunctionData('initializeNonPayableWithValue', [value]); + + this.proxy = await this.newBeaconProxy(this.beacon, data); + await assertInitialized.bind(this)({ value, balance: 0n }); + }); + + it('payable initialization', async function () { + const value = 55n; + const data = this.v1.interface.encodeFunctionData('initializePayableWithValue', [value]); + const balance = 100n; + + this.proxy = await this.newBeaconProxy(this.beacon, data, { value: balance }); + await assertInitialized.bind(this)({ value, balance }); + }); + + it('reverting initialization due to value', async function () { + await expect(this.newBeaconProxy(this.beacon, '0x', { value: 1n })).to.be.revertedWithCustomError( + this.factory, + 'ERC1967NonPayable', + ); + }); + + it('reverting initialization function', async function () { + const data = this.v1.interface.encodeFunctionData('reverts'); + await expect(this.newBeaconProxy(this.beacon, data)).to.be.revertedWith('DummyImplementation reverted'); + }); + }); + + describe('upgrade', function () { + it('upgrade a proxy by upgrading its beacon', async function () { + const value = 10n; + const data = this.v1.interface.encodeFunctionData('initializeNonPayableWithValue', [value]); + const proxy = await this.newBeaconProxy(this.beacon, data).then(instance => this.v1.attach(instance)); + + // test initial values + expect(await proxy.value()).to.equal(value); + + // test initial version + expect(await proxy.version()).to.equal('V1'); + + // upgrade beacon + await this.beacon.connect(this.admin).upgradeTo(this.v2); + + // test upgraded version + expect(await proxy.version()).to.equal('V2'); + }); + + it('upgrade 2 proxies by upgrading shared beacon', async function () { + const value1 = 10n; + const data1 = this.v1.interface.encodeFunctionData('initializeNonPayableWithValue', [value1]); + const proxy1 = await this.newBeaconProxy(this.beacon, data1).then(instance => this.v1.attach(instance)); + + const value2 = 42n; + const data2 = this.v1.interface.encodeFunctionData('initializeNonPayableWithValue', [value2]); + const proxy2 = await this.newBeaconProxy(this.beacon, data2).then(instance => this.v1.attach(instance)); + + // test initial values + expect(await proxy1.value()).to.equal(value1); + expect(await proxy2.value()).to.equal(value2); + + // test initial version + expect(await proxy1.version()).to.equal('V1'); + expect(await proxy2.version()).to.equal('V1'); + + // upgrade beacon + await this.beacon.connect(this.admin).upgradeTo(this.v2); + + // test upgraded version + expect(await proxy1.version()).to.equal('V2'); + expect(await proxy2.version()).to.equal('V2'); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js new file mode 100644 index 0000000..2da7d0a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js @@ -0,0 +1,55 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +async function fixture() { + const [admin, other] = await ethers.getSigners(); + + const v1 = await ethers.deployContract('Implementation1'); + const v2 = await ethers.deployContract('Implementation2'); + const beacon = await ethers.deployContract('UpgradeableBeacon', [v1, admin]); + + return { admin, other, beacon, v1, v2 }; +} + +describe('UpgradeableBeacon', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('cannot be created with non-contract implementation', async function () { + await expect(ethers.deployContract('UpgradeableBeacon', [this.other, this.admin])) + .to.be.revertedWithCustomError(this.beacon, 'BeaconInvalidImplementation') + .withArgs(this.other); + }); + + describe('once deployed', function () { + it('emits Upgraded event to the first implementation', async function () { + await expect(this.beacon.deploymentTransaction()).to.emit(this.beacon, 'Upgraded').withArgs(this.v1); + }); + + it('returns implementation', async function () { + expect(await this.beacon.implementation()).to.equal(this.v1); + }); + + it('can be upgraded by the admin', async function () { + await expect(this.beacon.connect(this.admin).upgradeTo(this.v2)) + .to.emit(this.beacon, 'Upgraded') + .withArgs(this.v2); + + expect(await this.beacon.implementation()).to.equal(this.v2); + }); + + it('cannot be upgraded to a non-contract', async function () { + await expect(this.beacon.connect(this.admin).upgradeTo(this.other)) + .to.be.revertedWithCustomError(this.beacon, 'BeaconInvalidImplementation') + .withArgs(this.other); + }); + + it('cannot be upgraded by other account', async function () { + await expect(this.beacon.connect(this.other).upgradeTo(this.v2)) + .to.be.revertedWithCustomError(this.beacon, 'OwnableUnauthorizedAccount') + .withArgs(this.other); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js new file mode 100644 index 0000000..df430d4 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js @@ -0,0 +1,82 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getAddressInSlot, ImplementationSlot } = require('../../helpers/storage'); + +async function fixture() { + const [admin, other] = await ethers.getSigners(); + + const v1 = await ethers.deployContract('DummyImplementation'); + const v2 = await ethers.deployContract('DummyImplementationV2'); + + const proxy = await ethers + .deployContract('TransparentUpgradeableProxy', [v1, admin, '0x']) + .then(instance => ethers.getContractAt('ITransparentUpgradeableProxy', instance)); + + const proxyAdmin = await ethers.getContractAt( + 'ProxyAdmin', + ethers.getCreateAddress({ from: proxy.target, nonce: 1n }), + ); + + return { admin, other, v1, v2, proxy, proxyAdmin }; +} + +describe('ProxyAdmin', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('has an owner', async function () { + expect(await this.proxyAdmin.owner()).to.equal(this.admin); + }); + + it('has an interface version', async function () { + expect(await this.proxyAdmin.UPGRADE_INTERFACE_VERSION()).to.equal('5.0.0'); + }); + + describe('without data', function () { + describe('with unauthorized account', function () { + it('fails to upgrade', async function () { + await expect(this.proxyAdmin.connect(this.other).upgradeAndCall(this.proxy, this.v2, '0x')) + .to.be.revertedWithCustomError(this.proxyAdmin, 'OwnableUnauthorizedAccount') + .withArgs(this.other); + }); + }); + + describe('with authorized account', function () { + it('upgrades implementation', async function () { + await this.proxyAdmin.connect(this.admin).upgradeAndCall(this.proxy, this.v2, '0x'); + expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.v2); + }); + }); + }); + + describe('with data', function () { + describe('with unauthorized account', function () { + it('fails to upgrade', async function () { + const data = this.v1.interface.encodeFunctionData('initializeNonPayableWithValue', [1337n]); + await expect(this.proxyAdmin.connect(this.other).upgradeAndCall(this.proxy, this.v2, data)) + .to.be.revertedWithCustomError(this.proxyAdmin, 'OwnableUnauthorizedAccount') + .withArgs(this.other); + }); + }); + + describe('with authorized account', function () { + describe('with invalid callData', function () { + it('fails to upgrade', async function () { + const data = '0x12345678'; + await expect(this.proxyAdmin.connect(this.admin).upgradeAndCall(this.proxy, this.v2, data)).to.be.reverted; + }); + }); + + describe('with valid callData', function () { + it('upgrades implementation', async function () { + const data = this.v2.interface.encodeFunctionData('initializeNonPayableWithValue', [1337n]); + await this.proxyAdmin.connect(this.admin).upgradeAndCall(this.proxy, this.v2, data); + expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.v2); + }); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js new file mode 100644 index 0000000..8e1d62e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js @@ -0,0 +1,357 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); + +const { impersonate } = require('../../helpers/account'); +const { getAddressInSlot, ImplementationSlot, AdminSlot } = require('../../helpers/storage'); + +// createProxy, initialOwner, accounts +module.exports = function shouldBehaveLikeTransparentUpgradeableProxy() { + before(async function () { + const implementationV0 = await ethers.deployContract('DummyImplementation'); + const implementationV1 = await ethers.deployContract('DummyImplementation'); + + const createProxyWithImpersonatedProxyAdmin = async (logic, initData, opts = undefined) => { + const [proxy, tx] = await this.createProxy(logic, initData, opts).then(instance => + Promise.all([ethers.getContractAt('ITransparentUpgradeableProxy', instance), instance.deploymentTransaction()]), + ); + + const proxyAdmin = await ethers.getContractAt( + 'ProxyAdmin', + ethers.getCreateAddress({ from: proxy.target, nonce: 1n }), + ); + const proxyAdminAsSigner = await proxyAdmin.getAddress().then(impersonate); + + return { + instance: logic.attach(proxy.target), // attaching proxy directly works well for everything except for event resolution + proxy, + proxyAdmin, + proxyAdminAsSigner, + tx, + }; + }; + + Object.assign(this, { + implementationV0, + implementationV1, + createProxyWithImpersonatedProxyAdmin, + }); + }); + + beforeEach(async function () { + Object.assign(this, await this.createProxyWithImpersonatedProxyAdmin(this.implementationV0, '0x')); + }); + + describe('implementation', function () { + it('returns the current implementation address', async function () { + expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.implementationV0); + }); + + it('delegates to the implementation', async function () { + expect(await this.instance.get()).to.be.true; + }); + }); + + describe('proxy admin', function () { + it('emits AdminChanged event during construction', async function () { + await expect(this.tx).to.emit(this.proxy, 'AdminChanged').withArgs(ethers.ZeroAddress, this.proxyAdmin); + }); + + it('sets the proxy admin in storage with the correct initial owner', async function () { + expect(await getAddressInSlot(this.proxy, AdminSlot)).to.equal(this.proxyAdmin); + + expect(await this.proxyAdmin.owner()).to.equal(this.owner); + }); + + it('can overwrite the admin by the implementation', async function () { + await this.instance.unsafeOverrideAdmin(this.other); + + const ERC1967AdminSlotValue = await getAddressInSlot(this.proxy, AdminSlot); + expect(ERC1967AdminSlotValue).to.equal(this.other); + expect(ERC1967AdminSlotValue).to.not.equal(this.proxyAdmin); + + // Still allows previous admin to execute admin operations + await expect(this.proxy.connect(this.proxyAdminAsSigner).upgradeToAndCall(this.implementationV1, '0x')) + .to.emit(this.proxy, 'Upgraded') + .withArgs(this.implementationV1); + }); + }); + + describe('upgradeToAndCall', function () { + describe('without migrations', function () { + beforeEach(async function () { + this.behavior = await ethers.deployContract('InitializableMock'); + }); + + describe('when the call does not fail', function () { + beforeEach(function () { + this.initializeData = this.behavior.interface.encodeFunctionData('initializeWithX', [42n]); + }); + + describe('when the sender is the admin', function () { + const value = 10n ** 5n; + + beforeEach(async function () { + this.tx = await this.proxy + .connect(this.proxyAdminAsSigner) + .upgradeToAndCall(this.behavior, this.initializeData, { + value, + }); + }); + + it('upgrades to the requested implementation', async function () { + expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behavior); + }); + + it('emits an event', async function () { + await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behavior); + }); + + it('calls the initializer function', async function () { + expect(await this.behavior.attach(this.proxy).x()).to.equal(42n); + }); + + it('sends given value to the proxy', async function () { + expect(await ethers.provider.getBalance(this.proxy)).to.equal(value); + }); + + it('uses the storage of the proxy', async function () { + // storage layout should look as follows: + // - 0: Initializable storage ++ initializerRan ++ onlyInitializingRan + // - 1: x + expect(await ethers.provider.getStorage(this.proxy, 1n)).to.equal(42n); + }); + }); + + describe('when the sender is not the admin', function () { + it('reverts', async function () { + await expect(this.proxy.connect(this.other).upgradeToAndCall(this.behavior, this.initializeData)).to.be + .reverted; + }); + }); + }); + + describe('when the call does fail', function () { + beforeEach(function () { + this.initializeData = this.behavior.interface.encodeFunctionData('fail'); + }); + + it('reverts', async function () { + await expect(this.proxy.connect(this.proxyAdminAsSigner).upgradeToAndCall(this.behavior, this.initializeData)) + .to.be.reverted; + }); + }); + }); + + describe('with migrations', function () { + describe('when the sender is the admin', function () { + const value = 10n ** 5n; + + describe('when upgrading to V1', function () { + beforeEach(async function () { + this.behaviorV1 = await ethers.deployContract('MigratableMockV1'); + const v1MigrationData = this.behaviorV1.interface.encodeFunctionData('initialize', [42n]); + + this.balancePreviousV1 = await ethers.provider.getBalance(this.proxy); + this.tx = await this.proxy + .connect(this.proxyAdminAsSigner) + .upgradeToAndCall(this.behaviorV1, v1MigrationData, { + value, + }); + }); + + it('upgrades to the requested version and emits an event', async function () { + expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behaviorV1); + + await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behaviorV1); + }); + + it("calls the 'initialize' function and sends given value to the proxy", async function () { + expect(await this.behaviorV1.attach(this.proxy).x()).to.equal(42n); + expect(await ethers.provider.getBalance(this.proxy)).to.equal(this.balancePreviousV1 + value); + }); + + describe('when upgrading to V2', function () { + beforeEach(async function () { + this.behaviorV2 = await ethers.deployContract('MigratableMockV2'); + const v2MigrationData = this.behaviorV2.interface.encodeFunctionData('migrate', [10n, 42n]); + + this.balancePreviousV2 = await ethers.provider.getBalance(this.proxy); + this.tx = await this.proxy + .connect(this.proxyAdminAsSigner) + .upgradeToAndCall(this.behaviorV2, v2MigrationData, { + value, + }); + }); + + it('upgrades to the requested version and emits an event', async function () { + expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behaviorV2); + + await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behaviorV2); + }); + + it("calls the 'migrate' function and sends given value to the proxy", async function () { + expect(await this.behaviorV2.attach(this.proxy).x()).to.equal(10n); + expect(await this.behaviorV2.attach(this.proxy).y()).to.equal(42n); + expect(await ethers.provider.getBalance(this.proxy)).to.equal(this.balancePreviousV2 + value); + }); + + describe('when upgrading to V3', function () { + beforeEach(async function () { + this.behaviorV3 = await ethers.deployContract('MigratableMockV3'); + const v3MigrationData = this.behaviorV3.interface.encodeFunctionData('migrate()'); + + this.balancePreviousV3 = await ethers.provider.getBalance(this.proxy); + this.tx = await this.proxy + .connect(this.proxyAdminAsSigner) + .upgradeToAndCall(this.behaviorV3, v3MigrationData, { + value, + }); + }); + + it('upgrades to the requested version and emits an event', async function () { + expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behaviorV3); + + await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behaviorV3); + }); + + it("calls the 'migrate' function and sends given value to the proxy", async function () { + expect(await this.behaviorV3.attach(this.proxy).x()).to.equal(42n); + expect(await this.behaviorV3.attach(this.proxy).y()).to.equal(10n); + expect(await ethers.provider.getBalance(this.proxy)).to.equal(this.balancePreviousV3 + value); + }); + }); + }); + }); + }); + + describe('when the sender is not the admin', function () { + it('reverts', async function () { + const behaviorV1 = await ethers.deployContract('MigratableMockV1'); + const v1MigrationData = behaviorV1.interface.encodeFunctionData('initialize', [42n]); + await expect(this.proxy.connect(this.other).upgradeToAndCall(behaviorV1, v1MigrationData)).to.be.reverted; + }); + }); + }); + }); + + describe('transparent proxy', function () { + beforeEach('creating proxy', async function () { + this.clashingImplV0 = await ethers.deployContract('ClashingImplementation'); + this.clashingImplV1 = await ethers.deployContract('ClashingImplementation'); + + Object.assign(this, await this.createProxyWithImpersonatedProxyAdmin(this.clashingImplV0, '0x')); + }); + + it('proxy admin cannot call delegated functions', async function () { + const factory = await ethers.getContractFactory('TransparentUpgradeableProxy'); + + await expect(this.instance.connect(this.proxyAdminAsSigner).delegatedFunction()).to.be.revertedWithCustomError( + factory, + 'ProxyDeniedAdminAccess', + ); + }); + + describe('when function names clash', function () { + it('executes the proxy function if the sender is the admin', async function () { + await expect(this.proxy.connect(this.proxyAdminAsSigner).upgradeToAndCall(this.clashingImplV1, '0x')) + .to.emit(this.proxy, 'Upgraded') + .withArgs(this.clashingImplV1); + }); + + it('delegates the call to implementation when sender is not the admin', async function () { + await expect(this.proxy.connect(this.other).upgradeToAndCall(this.clashingImplV1, '0x')) + .to.emit(this.instance, 'ClashingImplementationCall') + .to.not.emit(this.proxy, 'Upgraded'); + }); + }); + }); + + describe('regression', function () { + const initializeData = '0x'; + + it('should add new function', async function () { + const impl1 = await ethers.deployContract('Implementation1'); + const impl2 = await ethers.deployContract('Implementation2'); + const { instance, proxy, proxyAdminAsSigner } = await this.createProxyWithImpersonatedProxyAdmin( + impl1, + initializeData, + ); + + await instance.setValue(42n); + + // `getValue` is not available in impl1 + await expect(impl2.attach(instance).getValue()).to.be.reverted; + + // do upgrade + await proxy.connect(proxyAdminAsSigner).upgradeToAndCall(impl2, '0x'); + + // `getValue` is available in impl2 + expect(await impl2.attach(instance).getValue()).to.equal(42n); + }); + + it('should remove function', async function () { + const impl1 = await ethers.deployContract('Implementation1'); + const impl2 = await ethers.deployContract('Implementation2'); + const { instance, proxy, proxyAdminAsSigner } = await this.createProxyWithImpersonatedProxyAdmin( + impl2, + initializeData, + ); + + await instance.setValue(42n); + + // `getValue` is available in impl2 + expect(await impl2.attach(instance).getValue()).to.equal(42n); + + // do downgrade + await proxy.connect(proxyAdminAsSigner).upgradeToAndCall(impl1, '0x'); + + // `getValue` is not available in impl1 + await expect(impl2.attach(instance).getValue()).to.be.reverted; + }); + + it('should change function signature', async function () { + const impl1 = await ethers.deployContract('Implementation1'); + const impl3 = await ethers.deployContract('Implementation3'); + const { instance, proxy, proxyAdminAsSigner } = await this.createProxyWithImpersonatedProxyAdmin( + impl1, + initializeData, + ); + + await instance.setValue(42n); + + await proxy.connect(proxyAdminAsSigner).upgradeToAndCall(impl3, '0x'); + + expect(await impl3.attach(instance).getValue(8n)).to.equal(50n); + }); + + it('should add fallback function', async function () { + const impl1 = await ethers.deployContract('Implementation1'); + const impl4 = await ethers.deployContract('Implementation4'); + const { instance, proxy, proxyAdminAsSigner } = await this.createProxyWithImpersonatedProxyAdmin( + impl1, + initializeData, + ); + + await proxy.connect(proxyAdminAsSigner).upgradeToAndCall(impl4, '0x'); + + await this.other.sendTransaction({ to: proxy }); + + expect(await impl4.attach(instance).getValue()).to.equal(1n); + }); + + it('should remove fallback function', async function () { + const impl2 = await ethers.deployContract('Implementation2'); + const impl4 = await ethers.deployContract('Implementation4'); + const { instance, proxy, proxyAdminAsSigner } = await this.createProxyWithImpersonatedProxyAdmin( + impl4, + initializeData, + ); + + await proxy.connect(proxyAdminAsSigner).upgradeToAndCall(impl2, '0x'); + + await expect(this.other.sendTransaction({ to: proxy })).to.be.reverted; + + expect(await impl2.attach(instance).getValue()).to.equal(0n); + }); + }); +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js new file mode 100644 index 0000000..61e1801 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js @@ -0,0 +1,28 @@ +const { ethers } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const shouldBehaveLikeProxy = require('../Proxy.behaviour'); +const shouldBehaveLikeTransparentUpgradeableProxy = require('./TransparentUpgradeableProxy.behaviour'); + +async function fixture() { + const [owner, other, ...accounts] = await ethers.getSigners(); + + const implementation = await ethers.deployContract('DummyImplementation'); + + const createProxy = function (logic, initData, opts = undefined) { + return ethers.deployContract('TransparentUpgradeableProxy', [logic, owner, initData], opts); + }; + + return { nonContractAddress: owner, owner, other, accounts, implementation, createProxy }; +} + +describe('TransparentUpgradeableProxy', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeProxy(); + + // createProxy, owner, otherAccounts + shouldBehaveLikeTransparentUpgradeableProxy(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js new file mode 100644 index 0000000..6bf213f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js @@ -0,0 +1,216 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { MAX_UINT64 } = require('../../helpers/constants'); + +describe('Initializable', function () { + describe('basic testing without inheritance', function () { + beforeEach('deploying', async function () { + this.mock = await ethers.deployContract('InitializableMock'); + }); + + describe('before initialize', function () { + it('initializer has not run', async function () { + expect(await this.mock.initializerRan()).to.be.false; + }); + + it('_initializing returns false before initialization', async function () { + expect(await this.mock.isInitializing()).to.be.false; + }); + }); + + describe('after initialize', function () { + beforeEach('initializing', async function () { + await this.mock.initialize(); + }); + + it('initializer has run', async function () { + expect(await this.mock.initializerRan()).to.be.true; + }); + + it('_initializing returns false after initialization', async function () { + expect(await this.mock.isInitializing()).to.be.false; + }); + + it('initializer does not run again', async function () { + await expect(this.mock.initialize()).to.be.revertedWithCustomError(this.mock, 'InvalidInitialization'); + }); + }); + + describe('nested under an initializer', function () { + it('initializer modifier reverts', async function () { + await expect(this.mock.initializerNested()).to.be.revertedWithCustomError(this.mock, 'InvalidInitialization'); + }); + + it('onlyInitializing modifier succeeds', async function () { + await this.mock.onlyInitializingNested(); + expect(await this.mock.onlyInitializingRan()).to.be.true; + }); + }); + + it('cannot call onlyInitializable function outside the scope of an initializable function', async function () { + await expect(this.mock.initializeOnlyInitializing()).to.be.revertedWithCustomError(this.mock, 'NotInitializing'); + }); + }); + + it('nested initializer can run during construction', async function () { + const mock = await ethers.deployContract('ConstructorInitializableMock'); + expect(await mock.initializerRan()).to.be.true; + expect(await mock.onlyInitializingRan()).to.be.true; + }); + + it('multiple constructor levels can be initializers', async function () { + const mock = await ethers.deployContract('ChildConstructorInitializableMock'); + expect(await mock.initializerRan()).to.be.true; + expect(await mock.childInitializerRan()).to.be.true; + expect(await mock.onlyInitializingRan()).to.be.true; + }); + + describe('reinitialization', function () { + beforeEach('deploying', async function () { + this.mock = await ethers.deployContract('ReinitializerMock'); + }); + + it('can reinitialize', async function () { + expect(await this.mock.counter()).to.equal(0n); + await this.mock.initialize(); + expect(await this.mock.counter()).to.equal(1n); + await this.mock.reinitialize(2); + expect(await this.mock.counter()).to.equal(2n); + await this.mock.reinitialize(3); + expect(await this.mock.counter()).to.equal(3n); + }); + + it('can jump multiple steps', async function () { + expect(await this.mock.counter()).to.equal(0n); + await this.mock.initialize(); + expect(await this.mock.counter()).to.equal(1n); + await this.mock.reinitialize(128); + expect(await this.mock.counter()).to.equal(2n); + }); + + it('cannot nest reinitializers', async function () { + expect(await this.mock.counter()).to.equal(0n); + await expect(this.mock.nestedReinitialize(2, 2)).to.be.revertedWithCustomError( + this.mock, + 'InvalidInitialization', + ); + await expect(this.mock.nestedReinitialize(2, 3)).to.be.revertedWithCustomError( + this.mock, + 'InvalidInitialization', + ); + await expect(this.mock.nestedReinitialize(3, 2)).to.be.revertedWithCustomError( + this.mock, + 'InvalidInitialization', + ); + }); + + it('can chain reinitializers', async function () { + expect(await this.mock.counter()).to.equal(0n); + await this.mock.chainReinitialize(2, 3); + expect(await this.mock.counter()).to.equal(2n); + }); + + it('_getInitializedVersion returns right version', async function () { + await this.mock.initialize(); + expect(await this.mock.getInitializedVersion()).to.equal(1n); + await this.mock.reinitialize(12); + expect(await this.mock.getInitializedVersion()).to.equal(12n); + }); + + describe('contract locking', function () { + it('prevents initialization', async function () { + await this.mock.disableInitializers(); + await expect(this.mock.initialize()).to.be.revertedWithCustomError(this.mock, 'InvalidInitialization'); + }); + + it('prevents re-initialization', async function () { + await this.mock.disableInitializers(); + await expect(this.mock.reinitialize(255n)).to.be.revertedWithCustomError(this.mock, 'InvalidInitialization'); + }); + + it('can lock contract after initialization', async function () { + await this.mock.initialize(); + await this.mock.disableInitializers(); + await expect(this.mock.reinitialize(255n)).to.be.revertedWithCustomError(this.mock, 'InvalidInitialization'); + }); + }); + }); + + describe('events', function () { + it('constructor initialization emits event', async function () { + const mock = await ethers.deployContract('ConstructorInitializableMock'); + await expect(mock.deploymentTransaction()).to.emit(mock, 'Initialized').withArgs(1n); + }); + + it('initialization emits event', async function () { + const mock = await ethers.deployContract('ReinitializerMock'); + await expect(mock.initialize()).to.emit(mock, 'Initialized').withArgs(1n); + }); + + it('reinitialization emits event', async function () { + const mock = await ethers.deployContract('ReinitializerMock'); + await expect(mock.reinitialize(128)).to.emit(mock, 'Initialized').withArgs(128n); + }); + + it('chained reinitialization emits multiple events', async function () { + const mock = await ethers.deployContract('ReinitializerMock'); + + await expect(mock.chainReinitialize(2, 3)) + .to.emit(mock, 'Initialized') + .withArgs(2n) + .to.emit(mock, 'Initialized') + .withArgs(3n); + }); + }); + + describe('complex testing with inheritance', function () { + const mother = 12n; + const gramps = '56'; + const father = 34n; + const child = 78n; + + beforeEach('deploying', async function () { + this.mock = await ethers.deployContract('SampleChild'); + await this.mock.initialize(mother, gramps, father, child); + }); + + it('initializes human', async function () { + expect(await this.mock.isHuman()).to.be.true; + }); + + it('initializes mother', async function () { + expect(await this.mock.mother()).to.equal(mother); + }); + + it('initializes gramps', async function () { + expect(await this.mock.gramps()).to.equal(gramps); + }); + + it('initializes father', async function () { + expect(await this.mock.father()).to.equal(father); + }); + + it('initializes child', async function () { + expect(await this.mock.child()).to.equal(child); + }); + }); + + describe('disabling initialization', function () { + it('old and new patterns in bad sequence', async function () { + const DisableBad1 = await ethers.getContractFactory('DisableBad1'); + await expect(DisableBad1.deploy()).to.be.revertedWithCustomError(DisableBad1, 'InvalidInitialization'); + + const DisableBad2 = await ethers.getContractFactory('DisableBad2'); + await expect(DisableBad2.deploy()).to.be.revertedWithCustomError(DisableBad2, 'InvalidInitialization'); + }); + + it('old and new patterns in good sequence', async function () { + const ok = await ethers.deployContract('DisableOk'); + await expect(ok.deploymentTransaction()) + .to.emit(ok, 'Initialized') + .withArgs(1n) + .to.emit(ok, 'Initialized') + .withArgs(MAX_UINT64); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js new file mode 100644 index 0000000..17f8657 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js @@ -0,0 +1,120 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getAddressInSlot, ImplementationSlot } = require('../../helpers/storage'); + +async function fixture() { + const implInitial = await ethers.deployContract('UUPSUpgradeableMock'); + const implUpgradeOk = await ethers.deployContract('UUPSUpgradeableMock'); + const implUpgradeUnsafe = await ethers.deployContract('UUPSUpgradeableUnsafeMock'); + const implUpgradeNonUUPS = await ethers.deployContract('NonUpgradeableMock'); + const implUnsupportedUUID = await ethers.deployContract('UUPSUnsupportedProxiableUUID'); + // Used for testing non ERC1967 compliant proxies (clones are proxies that don't use the ERC1967 implementation slot) + const cloneFactory = await ethers.deployContract('$Clones'); + + const instance = await ethers + .deployContract('ERC1967Proxy', [implInitial, '0x']) + .then(proxy => implInitial.attach(proxy.target)); + + return { + implInitial, + implUpgradeOk, + implUpgradeUnsafe, + implUpgradeNonUUPS, + implUnsupportedUUID, + cloneFactory, + instance, + }; +} + +describe('UUPSUpgradeable', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + 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 () { + await expect(this.instance.upgradeToAndCall(this.implUpgradeOk, '0x')) + .to.emit(this.instance, 'Upgraded') + .withArgs(this.implUpgradeOk); + + expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.equal(this.implUpgradeOk); + }); + + it('upgrade to upgradeable implementation with call', async function () { + expect(await this.instance.current()).to.equal(0n); + + await expect( + this.instance.upgradeToAndCall(this.implUpgradeOk, this.implUpgradeOk.interface.encodeFunctionData('increment')), + ) + .to.emit(this.instance, 'Upgraded') + .withArgs(this.implUpgradeOk); + + expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.equal(this.implUpgradeOk); + + expect(await this.instance.current()).to.equal(1n); + }); + + it('calling upgradeTo on the implementation reverts', async function () { + await expect(this.implInitial.upgradeToAndCall(this.implUpgradeOk, '0x')).to.be.revertedWithCustomError( + this.implInitial, + 'UUPSUnauthorizedCallContext', + ); + }); + + it('calling upgradeToAndCall on the implementation reverts', async function () { + await expect( + this.implInitial.upgradeToAndCall( + this.implUpgradeOk, + this.implUpgradeOk.interface.encodeFunctionData('increment'), + ), + ).to.be.revertedWithCustomError(this.implUpgradeOk, 'UUPSUnauthorizedCallContext'); + }); + + it('calling upgradeToAndCall from a contract that is not an ERC1967 proxy (with the right implementation) reverts', async function () { + const instance = await this.cloneFactory.$clone + .staticCall(this.implUpgradeOk) + .then(address => this.implInitial.attach(address)); + await this.cloneFactory.$clone(this.implUpgradeOk); + + await expect(instance.upgradeToAndCall(this.implUpgradeUnsafe, '0x')).to.be.revertedWithCustomError( + instance, + 'UUPSUnauthorizedCallContext', + ); + }); + + it('rejects upgrading to an unsupported UUID', async function () { + await expect(this.instance.upgradeToAndCall(this.implUnsupportedUUID, '0x')) + .to.be.revertedWithCustomError(this.instance, 'UUPSUnsupportedProxiableUUID') + .withArgs(ethers.id('invalid UUID')); + }); + + it('upgrade to and unsafe upgradeable implementation', async function () { + await expect(this.instance.upgradeToAndCall(this.implUpgradeUnsafe, '0x')) + .to.emit(this.instance, 'Upgraded') + .withArgs(this.implUpgradeUnsafe); + + expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.equal(this.implUpgradeUnsafe); + }); + + // delegate to a non existing upgradeTo function causes a low level revert + it('reject upgrade to non uups implementation', async function () { + await expect(this.instance.upgradeToAndCall(this.implUpgradeNonUUPS, '0x')) + .to.be.revertedWithCustomError(this.instance, 'ERC1967InvalidImplementation') + .withArgs(this.implUpgradeNonUUPS); + }); + + it('reject proxy address as implementation', async function () { + const otherInstance = await ethers + .deployContract('ERC1967Proxy', [this.implInitial, '0x']) + .then(proxy => this.implInitial.attach(proxy.target)); + + await expect(this.instance.upgradeToAndCall(otherInstance, '0x')) + .to.be.revertedWithCustomError(this.instance, 'ERC1967InvalidImplementation') + .withArgs(otherInstance); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/sanity.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/sanity.test.js new file mode 100644 index 0000000..ea0175c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/sanity.test.js @@ -0,0 +1,27 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers'); + +async function fixture() { + return {}; +} + +describe('Environment sanity', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('snapshot', function () { + let blockNumberBefore; + + it('cache and mine', async function () { + blockNumberBefore = await ethers.provider.getBlockNumber(); + await mine(); + expect(await ethers.provider.getBlockNumber()).to.equal(blockNumberBefore + 1); + }); + + it('check snapshot', async function () { + expect(await ethers.provider.getBlockNumber()).to.equal(blockNumberBefore); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js new file mode 100644 index 0000000..d19b732 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js @@ -0,0 +1,763 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); + +const { RevertType } = require('../../helpers/enums'); +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); + +function shouldBehaveLikeERC1155() { + const firstTokenId = 1n; + const secondTokenId = 2n; + const unknownTokenId = 3n; + + const firstTokenValue = 1000n; + const secondTokenValue = 2000n; + + const RECEIVER_SINGLE_MAGIC_VALUE = '0xf23a6e61'; + const RECEIVER_BATCH_MAGIC_VALUE = '0xbc197c81'; + + beforeEach(async function () { + [this.recipient, this.proxy, this.alice, this.bruce] = this.otherAccounts; + }); + + 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(ethers.ZeroAddress, firstTokenId)).to.equal(0n); + }); + + describe("when accounts don't own tokens", function () { + it('returns zero for given addresses', async function () { + expect(await this.token.balanceOf(this.alice, firstTokenId)).to.equal(0n); + expect(await this.token.balanceOf(this.bruce, secondTokenId)).to.equal(0n); + expect(await this.token.balanceOf(this.alice, unknownTokenId)).to.equal(0n); + }); + }); + + describe('when accounts own some tokens', function () { + beforeEach(async function () { + await this.token.$_mint(this.alice, firstTokenId, firstTokenValue, '0x'); + await this.token.$_mint(this.bruce, secondTokenId, secondTokenValue, '0x'); + }); + + it('returns the amount of tokens owned by the given addresses', async function () { + expect(await this.token.balanceOf(this.alice, firstTokenId)).to.equal(firstTokenValue); + expect(await this.token.balanceOf(this.bruce, secondTokenId)).to.equal(secondTokenValue); + expect(await this.token.balanceOf(this.alice, unknownTokenId)).to.equal(0n); + }); + }); + }); + + describe('balanceOfBatch', function () { + it("reverts when input arrays don't match up", async function () { + const accounts1 = [this.alice, this.bruce, this.alice, this.bruce]; + const ids1 = [firstTokenId, secondTokenId, unknownTokenId]; + + await expect(this.token.balanceOfBatch(accounts1, ids1)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(ids1.length, accounts1.length); + + const accounts2 = [this.alice, this.bruce]; + const ids2 = [firstTokenId, secondTokenId, unknownTokenId]; + await expect(this.token.balanceOfBatch(accounts2, ids2)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(ids2.length, accounts2.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( + [this.alice, this.bruce, ethers.ZeroAddress], + [firstTokenId, secondTokenId, unknownTokenId], + ); + expect(result).to.deep.equal([0n, 0n, 0n]); + }); + + describe("when accounts don't own tokens", function () { + it('returns zeros for each account', async function () { + const result = await this.token.balanceOfBatch( + [this.alice, this.bruce, this.alice], + [firstTokenId, secondTokenId, unknownTokenId], + ); + expect(result).to.deep.equal([0n, 0n, 0n]); + }); + }); + + describe('when accounts own some tokens', function () { + beforeEach(async function () { + await this.token.$_mint(this.alice, firstTokenId, firstTokenValue, '0x'); + await this.token.$_mint(this.bruce, secondTokenId, secondTokenValue, '0x'); + }); + + it('returns amounts owned by each account in order passed', async function () { + const result = await this.token.balanceOfBatch( + [this.bruce, this.alice, this.alice], + [secondTokenId, firstTokenId, unknownTokenId], + ); + expect(result).to.deep.equal([secondTokenValue, firstTokenValue, 0n]); + }); + + it('returns multiple times the balance of the same address when asked', async function () { + const result = await this.token.balanceOfBatch( + [this.alice, this.bruce, this.alice], + [firstTokenId, secondTokenId, firstTokenId], + ); + expect(result).to.deep.equal([firstTokenValue, secondTokenValue, firstTokenValue]); + }); + }); + }); + + describe('setApprovalForAll', function () { + beforeEach(async function () { + this.tx = await this.token.connect(this.holder).setApprovalForAll(this.proxy, true); + }); + + it('sets approval status which can be queried via isApprovedForAll', async function () { + expect(await this.token.isApprovedForAll(this.holder, this.proxy)).to.be.true; + }); + + it('emits an ApprovalForAll log', async function () { + await expect(this.tx).to.emit(this.token, 'ApprovalForAll').withArgs(this.holder, this.proxy, true); + }); + + it('can unset approval for an operator', async function () { + await this.token.connect(this.holder).setApprovalForAll(this.proxy, false); + expect(await this.token.isApprovedForAll(this.holder, this.proxy)).to.be.false; + }); + + it('reverts if attempting to approve zero address as an operator', async function () { + await expect(this.token.connect(this.holder).setApprovalForAll(ethers.ZeroAddress, true)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidOperator') + .withArgs(ethers.ZeroAddress); + }); + }); + + describe('safeTransferFrom', function () { + beforeEach(async function () { + await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); + await this.token.$_mint(this.holder, secondTokenId, secondTokenValue, '0x'); + }); + + it('reverts when transferring more than balance', async function () { + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, this.recipient, firstTokenId, firstTokenValue + 1n, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') + .withArgs(this.holder, firstTokenValue, firstTokenValue + 1n, firstTokenId); + }); + + it('reverts when transferring to zero address', async function () { + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, ethers.ZeroAddress, firstTokenId, firstTokenValue, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(ethers.ZeroAddress); + }); + + function transferWasSuccessful() { + it('debits transferred balance from sender', async function () { + expect(await this.token.balanceOf(this.args.from, this.args.id)).to.equal(0n); + }); + + it('credits transferred balance to receiver', async function () { + expect(await this.token.balanceOf(this.args.to, this.args.id)).to.equal(this.args.value); + }); + + it('emits a TransferSingle log', async function () { + await expect(this.tx) + .to.emit(this.token, 'TransferSingle') + .withArgs(this.args.operator, this.args.from, this.args.to, this.args.id, this.args.value); + }); + } + + describe('when called by the holder', function () { + beforeEach(async function () { + this.args = { + operator: this.holder, + from: this.holder, + to: this.recipient, + id: firstTokenId, + value: firstTokenValue, + data: '0x', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeTransferFrom(this.args.from, this.args.to, this.args.id, this.args.value, this.args.data); + }); + + transferWasSuccessful(); + + it('preserves existing balances which are not transferred by holder', async function () { + expect(await this.token.balanceOf(this.holder, secondTokenId)).to.equal(secondTokenValue); + expect(await this.token.balanceOf(this.recipient, secondTokenId)).to.equal(0n); + }); + }); + + describe('when called by an operator on behalf of the holder', function () { + describe('when operator is not approved by holder', function () { + beforeEach(async function () { + await this.token.connect(this.holder).setApprovalForAll(this.proxy, false); + }); + + it('reverts', async function () { + await expect( + this.token + .connect(this.proxy) + .safeTransferFrom(this.holder, this.recipient, firstTokenId, firstTokenValue, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll') + .withArgs(this.proxy, this.holder); + }); + }); + + describe('when operator is approved by holder', function () { + beforeEach(async function () { + await this.token.connect(this.holder).setApprovalForAll(this.proxy, true); + + this.args = { + operator: this.proxy, + from: this.holder, + to: this.recipient, + id: firstTokenId, + value: firstTokenValue, + data: '0x', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeTransferFrom(this.args.from, this.args.to, this.args.id, this.args.value, this.args.data); + }); + + transferWasSuccessful(); + + it("preserves operator's balances not involved in the transfer", async function () { + expect(await this.token.balanceOf(this.proxy, firstTokenId)).to.equal(0n); + expect(await this.token.balanceOf(this.proxy, secondTokenId)).to.equal(0n); + }); + }); + }); + + describe('when sending to a valid receiver', function () { + beforeEach(async function () { + this.receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.None, + ]); + }); + + describe('without data', function () { + beforeEach(async function () { + this.args = { + operator: this.holder, + from: this.holder, + to: this.receiver, + id: firstTokenId, + value: firstTokenValue, + data: '0x', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeTransferFrom(this.args.from, this.args.to, this.args.id, this.args.value, this.args.data); + }); + + transferWasSuccessful(); + + it('calls onERC1155Received', async function () { + await expect(this.tx) + .to.emit(this.receiver, 'Received') + .withArgs(this.args.operator, this.args.from, this.args.id, this.args.value, this.args.data, anyValue); + }); + }); + + describe('with data', function () { + beforeEach(async function () { + this.args = { + operator: this.holder, + from: this.holder, + to: this.receiver, + id: firstTokenId, + value: firstTokenValue, + data: '0xf00dd00d', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeTransferFrom(this.args.from, this.args.to, this.args.id, this.args.value, this.args.data); + }); + + transferWasSuccessful(); + + it('calls onERC1155Received', async function () { + await expect(this.tx) + .to.emit(this.receiver, 'Received') + .withArgs(this.args.operator, this.args.from, this.args.id, this.args.value, this.args.data, anyValue); + }); + }); + }); + + describe('to a receiver contract returning unexpected value', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ + '0x00c0ffee', + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.None, + ]); + + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(receiver); + }); + }); + + describe('to a receiver contract that reverts', function () { + describe('with a revert string', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithMessage, + ]); + + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), + ).to.be.revertedWith('ERC1155ReceiverMock: reverting on receive'); + }); + }); + + describe('without a revert string', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithoutMessage, + ]); + + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(receiver); + }); + }); + + describe('with a custom error', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithCustomError, + ]); + + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), + ) + .to.be.revertedWithCustomError(receiver, 'CustomError') + .withArgs(RECEIVER_SINGLE_MAGIC_VALUE); + }); + }); + + describe('with a panic', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.Panic, + ]); + + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), + ).to.be.revertedWithPanic(); + }); + }); + }); + + describe('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const invalidReceiver = this.token; + + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, invalidReceiver, firstTokenId, firstTokenValue, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(invalidReceiver); + }); + }); + }); + + describe('safeBatchTransferFrom', function () { + beforeEach(async function () { + await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); + await this.token.$_mint(this.holder, secondTokenId, secondTokenValue, '0x'); + }); + + it('reverts when transferring value more than any of balances', async function () { + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + this.recipient, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue + 1n], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') + .withArgs(this.holder, secondTokenValue, secondTokenValue + 1n, secondTokenId); + }); + + it("reverts when ids array length doesn't match values array length", async function () { + const ids1 = [firstTokenId]; + const tokenValues1 = [firstTokenValue, secondTokenValue]; + + await expect( + this.token.connect(this.holder).safeBatchTransferFrom(this.holder, this.recipient, ids1, tokenValues1, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(ids1.length, tokenValues1.length); + + const ids2 = [firstTokenId, secondTokenId]; + const tokenValues2 = [firstTokenValue]; + + await expect( + this.token.connect(this.holder).safeBatchTransferFrom(this.holder, this.recipient, ids2, tokenValues2, '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(ids2.length, tokenValues2.length); + }); + + it('reverts when transferring to zero address', async function () { + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + ethers.ZeroAddress, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(ethers.ZeroAddress); + }); + + it('reverts when transferring from zero address', async function () { + await expect( + this.token.$_safeBatchTransferFrom(ethers.ZeroAddress, this.holder, [firstTokenId], [firstTokenValue], '0x'), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidSender') + .withArgs(ethers.ZeroAddress); + }); + + function batchTransferWasSuccessful() { + it('debits transferred balances from sender', async function () { + const newBalances = await this.token.balanceOfBatch( + this.args.ids.map(() => this.args.from), + this.args.ids, + ); + expect(newBalances).to.deep.equal(this.args.ids.map(() => 0n)); + }); + + it('credits transferred balances to receiver', async function () { + const newBalances = await this.token.balanceOfBatch( + this.args.ids.map(() => this.args.to), + this.args.ids, + ); + expect(newBalances).to.deep.equal(this.args.values); + }); + + it('emits a TransferBatch log', async function () { + await expect(this.tx) + .to.emit(this.token, 'TransferBatch') + .withArgs(this.args.operator, this.args.from, this.args.to, this.args.ids, this.args.values); + }); + } + + describe('when called by the holder', function () { + beforeEach(async function () { + this.args = { + operator: this.holder, + from: this.holder, + to: this.recipient, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + data: '0x', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeBatchTransferFrom(this.args.from, this.args.to, this.args.ids, this.args.values, this.args.data); + }); + + batchTransferWasSuccessful(); + }); + + describe('when called by an operator on behalf of the holder', function () { + describe('when operator is not approved by holder', function () { + beforeEach(async function () { + await this.token.connect(this.holder).setApprovalForAll(this.proxy, false); + }); + + it('reverts', async function () { + await expect( + this.token + .connect(this.proxy) + .safeBatchTransferFrom( + this.holder, + this.recipient, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll') + .withArgs(this.proxy, this.holder); + }); + }); + + describe('when operator is approved by holder', function () { + beforeEach(async function () { + await this.token.connect(this.holder).setApprovalForAll(this.proxy, true); + + this.args = { + operator: this.proxy, + from: this.holder, + to: this.recipient, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + data: '0x', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeBatchTransferFrom(this.args.from, this.args.to, this.args.ids, this.args.values, this.args.data); + }); + + batchTransferWasSuccessful(); + + it("preserves operator's balances not involved in the transfer", async function () { + expect(await this.token.balanceOf(this.proxy, firstTokenId)).to.equal(0n); + expect(await this.token.balanceOf(this.proxy, secondTokenId)).to.equal(0n); + }); + }); + }); + + describe('when sending to a valid receiver', function () { + beforeEach(async function () { + this.receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.None, + ]); + }); + + describe('without data', function () { + beforeEach(async function () { + this.args = { + operator: this.holder, + from: this.holder, + to: this.receiver, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + data: '0x', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeBatchTransferFrom(this.args.from, this.args.to, this.args.ids, this.args.values, this.args.data); + }); + + batchTransferWasSuccessful(); + + it('calls onERC1155BatchReceived', async function () { + await expect(this.tx) + .to.emit(this.receiver, 'BatchReceived') + .withArgs(this.holder, this.holder, this.args.ids, this.args.values, this.args.data, anyValue); + }); + }); + + describe('with data', function () { + beforeEach(async function () { + this.args = { + operator: this.holder, + from: this.holder, + to: this.receiver, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + data: '0xf00dd00d', + }; + this.tx = await this.token + .connect(this.args.operator) + .safeBatchTransferFrom(this.args.from, this.args.to, this.args.ids, this.args.values, this.args.data); + }); + + batchTransferWasSuccessful(); + + it('calls onERC1155Received', async function () { + await expect(this.tx) + .to.emit(this.receiver, 'BatchReceived') + .withArgs(this.holder, this.holder, this.args.ids, this.args.values, this.args.data, anyValue); + }); + }); + }); + + describe('to a receiver contract returning unexpected value', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_SINGLE_MAGIC_VALUE, + RevertType.None, + ]); + + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + receiver, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(receiver); + }); + }); + + describe('to a receiver contract that reverts', function () { + describe('with a revert string', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithMessage, + ]); + + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + receiver, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ).to.be.revertedWith('ERC1155ReceiverMock: reverting on batch receive'); + }); + }); + + describe('without a revert string', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithoutMessage, + ]); + + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + receiver, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(receiver); + }); + }); + + describe('with a custom error', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithCustomError, + ]); + + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + receiver, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(receiver, 'CustomError') + .withArgs(RECEIVER_SINGLE_MAGIC_VALUE); + }); + }); + + describe('with a panic', function () { + it('reverts', async function () { + const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.Panic, + ]); + + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + receiver, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ).to.be.revertedWithPanic(); + }); + }); + }); + + describe('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const invalidReceiver = this.token; + + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom( + this.holder, + invalidReceiver, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(invalidReceiver); + }); + }); + }); + + shouldSupportInterfaces(['ERC1155', 'ERC1155MetadataURI']); + }); +} + +module.exports = { + shouldBehaveLikeERC1155, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js new file mode 100644 index 0000000..8b0a672 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js @@ -0,0 +1,213 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { zip } = require('../../helpers/iterate'); +const { shouldBehaveLikeERC1155 } = require('./ERC1155.behavior'); + +const initialURI = 'https://token-cdn-domain/{id}.json'; + +async function fixture() { + const [operator, holder, ...otherAccounts] = await ethers.getSigners(); + const token = await ethers.deployContract('$ERC1155', [initialURI]); + return { token, operator, holder, otherAccounts }; +} + +describe('ERC1155', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeERC1155(); + + describe('internal functions', function () { + const tokenId = 1990n; + const mintValue = 9001n; + const burnValue = 3000n; + + const tokenBatchIds = [2000n, 2010n, 2020n]; + const mintValues = [5000n, 10000n, 42195n]; + const burnValues = [5000n, 9001n, 195n]; + + const data = '0x12345678'; + + describe('_mint', function () { + it('reverts with a zero destination address', async function () { + await expect(this.token.$_mint(ethers.ZeroAddress, tokenId, mintValue, data)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(ethers.ZeroAddress); + }); + + describe('with minted tokens', function () { + beforeEach(async function () { + this.tx = await this.token.connect(this.operator).$_mint(this.holder, tokenId, mintValue, data); + }); + + it('emits a TransferSingle event', async function () { + await expect(this.tx) + .to.emit(this.token, 'TransferSingle') + .withArgs(this.operator, ethers.ZeroAddress, this.holder, tokenId, mintValue); + }); + + it('credits the minted token value', async function () { + expect(await this.token.balanceOf(this.holder, tokenId)).to.equal(mintValue); + }); + }); + }); + + describe('_mintBatch', function () { + it('reverts with a zero destination address', async function () { + await expect(this.token.$_mintBatch(ethers.ZeroAddress, tokenBatchIds, mintValues, data)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') + .withArgs(ethers.ZeroAddress); + }); + + it('reverts if length of inputs do not match', async function () { + await expect(this.token.$_mintBatch(this.holder, tokenBatchIds, mintValues.slice(1), data)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(tokenBatchIds.length, mintValues.length - 1); + + await expect(this.token.$_mintBatch(this.holder, tokenBatchIds.slice(1), mintValues, data)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(tokenBatchIds.length - 1, mintValues.length); + }); + + describe('with minted batch of tokens', function () { + beforeEach(async function () { + this.tx = await this.token.connect(this.operator).$_mintBatch(this.holder, tokenBatchIds, mintValues, data); + }); + + it('emits a TransferBatch event', async function () { + await expect(this.tx) + .to.emit(this.token, 'TransferBatch') + .withArgs(this.operator, ethers.ZeroAddress, this.holder, tokenBatchIds, mintValues); + }); + + it('credits the minted batch of tokens', async function () { + const holderBatchBalances = await this.token.balanceOfBatch( + tokenBatchIds.map(() => this.holder), + tokenBatchIds, + ); + + expect(holderBatchBalances).to.deep.equal(mintValues); + }); + }); + }); + + describe('_burn', function () { + it("reverts when burning the zero account's tokens", async function () { + await expect(this.token.$_burn(ethers.ZeroAddress, tokenId, mintValue)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidSender') + .withArgs(ethers.ZeroAddress); + }); + + it('reverts when burning a non-existent token id', async function () { + await expect(this.token.$_burn(this.holder, tokenId, mintValue)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') + .withArgs(this.holder, 0, mintValue, tokenId); + }); + + it('reverts when burning more than available tokens', async function () { + await this.token.connect(this.operator).$_mint(this.holder, tokenId, mintValue, data); + + await expect(this.token.$_burn(this.holder, tokenId, mintValue + 1n)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') + .withArgs(this.holder, mintValue, mintValue + 1n, tokenId); + }); + + describe('with minted-then-burnt tokens', function () { + beforeEach(async function () { + await this.token.$_mint(this.holder, tokenId, mintValue, data); + this.tx = await this.token.connect(this.operator).$_burn(this.holder, tokenId, burnValue); + }); + + it('emits a TransferSingle event', async function () { + await expect(this.tx) + .to.emit(this.token, 'TransferSingle') + .withArgs(this.operator, this.holder, ethers.ZeroAddress, tokenId, burnValue); + }); + + it('accounts for both minting and burning', async function () { + expect(await this.token.balanceOf(this.holder, tokenId)).to.equal(mintValue - burnValue); + }); + }); + }); + + describe('_burnBatch', function () { + it("reverts when burning the zero account's tokens", async function () { + await expect(this.token.$_burnBatch(ethers.ZeroAddress, tokenBatchIds, burnValues)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidSender') + .withArgs(ethers.ZeroAddress); + }); + + it('reverts if length of inputs do not match', async function () { + await expect(this.token.$_burnBatch(this.holder, tokenBatchIds, burnValues.slice(1))) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(tokenBatchIds.length, burnValues.length - 1); + + await expect(this.token.$_burnBatch(this.holder, tokenBatchIds.slice(1), burnValues)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') + .withArgs(tokenBatchIds.length - 1, burnValues.length); + }); + + it('reverts when burning a non-existent token id', async function () { + await expect(this.token.$_burnBatch(this.holder, tokenBatchIds, burnValues)) + .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') + .withArgs(this.holder, 0, burnValues[0], tokenBatchIds[0]); + }); + + describe('with minted-then-burnt tokens', function () { + beforeEach(async function () { + await this.token.$_mintBatch(this.holder, tokenBatchIds, mintValues, data); + this.tx = await this.token.connect(this.operator).$_burnBatch(this.holder, tokenBatchIds, burnValues); + }); + + it('emits a TransferBatch event', async function () { + await expect(this.tx) + .to.emit(this.token, 'TransferBatch') + .withArgs(this.operator, this.holder, ethers.ZeroAddress, tokenBatchIds, burnValues); + }); + + it('accounts for both minting and burning', async function () { + const holderBatchBalances = await this.token.balanceOfBatch( + tokenBatchIds.map(() => this.holder), + tokenBatchIds, + ); + + expect(holderBatchBalances).to.deep.equal( + zip(mintValues, burnValues).map(([mintValue, burnValue]) => mintValue - burnValue), + ); + }); + }); + }); + }); + + describe('ERC1155MetadataURI', function () { + const firstTokenID = 42n; + const secondTokenID = 1337n; + + it('emits no URI event in constructor', async function () { + await expect(this.token.deploymentTransaction()).to.not.emit(this.token, 'URI'); + }); + + it('sets the initial URI for all token types', async function () { + expect(await this.token.uri(firstTokenID)).to.equal(initialURI); + expect(await this.token.uri(secondTokenID)).to.equal(initialURI); + }); + + describe('_setURI', function () { + const newURI = 'https://token-cdn-domain/{locale}/{id}.json'; + + it('emits no URI event', async function () { + await expect(this.token.$_setURI(newURI)).to.not.emit(this.token, 'URI'); + }); + + it('sets the new URI for all token types', async function () { + await this.token.$_setURI(newURI); + + expect(await this.token.uri(firstTokenID)).to.equal(newURI); + expect(await this.token.uri(secondTokenID)).to.equal(newURI); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js new file mode 100644 index 0000000..01e7ee2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js @@ -0,0 +1,66 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const ids = [42n, 1137n]; +const values = [3000n, 9902n]; + +async function fixture() { + const [holder, operator, other] = await ethers.getSigners(); + + const token = await ethers.deployContract('$ERC1155Burnable', ['https://token-cdn-domain/{id}.json']); + await token.$_mint(holder, ids[0], values[0], '0x'); + await token.$_mint(holder, ids[1], values[1], '0x'); + + return { token, holder, operator, other }; +} + +describe('ERC1155Burnable', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('burn', function () { + it('holder can burn their tokens', async function () { + await this.token.connect(this.holder).burn(this.holder, ids[0], values[0] - 1n); + + expect(await this.token.balanceOf(this.holder, ids[0])).to.equal(1n); + }); + + it("approved operators can burn the holder's tokens", async function () { + await this.token.connect(this.holder).setApprovalForAll(this.operator, true); + await this.token.connect(this.operator).burn(this.holder, ids[0], values[0] - 1n); + + expect(await this.token.balanceOf(this.holder, ids[0])).to.equal(1n); + }); + + it("unapproved accounts cannot burn the holder's tokens", async function () { + await expect(this.token.connect(this.other).burn(this.holder, ids[0], values[0] - 1n)) + .to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll') + .withArgs(this.other, this.holder); + }); + }); + + describe('burnBatch', function () { + it('holder can burn their tokens', async function () { + await this.token.connect(this.holder).burnBatch(this.holder, ids, [values[0] - 1n, values[1] - 2n]); + + expect(await this.token.balanceOf(this.holder, ids[0])).to.equal(1n); + expect(await this.token.balanceOf(this.holder, ids[1])).to.equal(2n); + }); + + it("approved operators can burn the holder's tokens", async function () { + await this.token.connect(this.holder).setApprovalForAll(this.operator, true); + await this.token.connect(this.operator).burnBatch(this.holder, ids, [values[0] - 1n, values[1] - 2n]); + + expect(await this.token.balanceOf(this.holder, ids[0])).to.equal(1n); + expect(await this.token.balanceOf(this.holder, ids[1])).to.equal(2n); + }); + + it("unapproved accounts cannot burn the holder's tokens", async function () { + await expect(this.token.connect(this.other).burnBatch(this.holder, ids, [values[0] - 1n, values[1] - 2n])) + .to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll') + .withArgs(this.other, this.holder); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js new file mode 100644 index 0000000..81c4f69 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js @@ -0,0 +1,105 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +async function fixture() { + const [holder, operator, receiver, other] = await ethers.getSigners(); + const token = await ethers.deployContract('$ERC1155Pausable', ['https://token-cdn-domain/{id}.json']); + return { token, holder, operator, receiver, other }; +} + +describe('ERC1155Pausable', function () { + const firstTokenId = 37n; + const firstTokenValue = 42n; + const secondTokenId = 19842n; + const secondTokenValue = 23n; + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('when token is paused', function () { + beforeEach(async function () { + await this.token.connect(this.holder).setApprovalForAll(this.operator, true); + await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); + await this.token.$_pause(); + }); + + it('reverts when trying to safeTransferFrom from holder', async function () { + await expect( + this.token + .connect(this.holder) + .safeTransferFrom(this.holder, this.receiver, firstTokenId, firstTokenValue, '0x'), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); + }); + + it('reverts when trying to safeTransferFrom from operator', async function () { + await expect( + this.token + .connect(this.operator) + .safeTransferFrom(this.holder, this.receiver, firstTokenId, firstTokenValue, '0x'), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); + }); + + it('reverts when trying to safeBatchTransferFrom from holder', async function () { + await expect( + this.token + .connect(this.holder) + .safeBatchTransferFrom(this.holder, this.receiver, [firstTokenId], [firstTokenValue], '0x'), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); + }); + + it('reverts when trying to safeBatchTransferFrom from operator', async function () { + await expect( + this.token + .connect(this.operator) + .safeBatchTransferFrom(this.holder, this.receiver, [firstTokenId], [firstTokenValue], '0x'), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); + }); + + it('reverts when trying to mint', async function () { + await expect(this.token.$_mint(this.holder, secondTokenId, secondTokenValue, '0x')).to.be.revertedWithCustomError( + this.token, + 'EnforcedPause', + ); + }); + + it('reverts when trying to mintBatch', async function () { + await expect( + this.token.$_mintBatch(this.holder, [secondTokenId], [secondTokenValue], '0x'), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); + }); + + it('reverts when trying to burn', async function () { + await expect(this.token.$_burn(this.holder, firstTokenId, firstTokenValue)).to.be.revertedWithCustomError( + this.token, + 'EnforcedPause', + ); + }); + + it('reverts when trying to burnBatch', async function () { + await expect( + this.token.$_burnBatch(this.holder, [firstTokenId], [firstTokenValue]), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); + }); + + describe('setApprovalForAll', function () { + it('approves an operator', async function () { + await this.token.connect(this.holder).setApprovalForAll(this.other, true); + expect(await this.token.isApprovedForAll(this.holder, this.other)).to.be.true; + }); + }); + + describe('balanceOf', function () { + it('returns the token value owned by the given address', async function () { + expect(await this.token.balanceOf(this.holder, firstTokenId)).to.equal(firstTokenValue); + }); + }); + + describe('isApprovedForAll', function () { + it('returns the approval of the operator', async function () { + expect(await this.token.isApprovedForAll(this.holder, this.operator)).to.be.true; + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js new file mode 100644 index 0000000..cca36a0 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js @@ -0,0 +1,119 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +async function fixture() { + const [holder] = await ethers.getSigners(); + const token = await ethers.deployContract('$ERC1155Supply', ['https://token-cdn-domain/{id}.json']); + return { token, holder }; +} + +describe('ERC1155Supply', function () { + const firstTokenId = 37n; + const firstTokenValue = 42n; + const secondTokenId = 19842n; + const secondTokenValue = 23n; + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('before mint', function () { + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.false; + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(0n); + expect(await this.token.totalSupply()).to.equal(0n); + }); + }); + + describe('after mint', function () { + describe('single', function () { + beforeEach(async function () { + await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.true; + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(firstTokenValue); + expect(await this.token.totalSupply()).to.equal(firstTokenValue); + }); + }); + + describe('batch', function () { + beforeEach(async function () { + await this.token.$_mintBatch( + this.holder, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.true; + expect(await this.token.exists(secondTokenId)).to.be.true; + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(firstTokenValue); + expect(await this.token.totalSupply(ethers.Typed.uint256(secondTokenId))).to.equal(secondTokenValue); + expect(await this.token.totalSupply()).to.equal(firstTokenValue + secondTokenValue); + }); + }); + }); + + describe('after burn', function () { + describe('single', function () { + beforeEach(async function () { + await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); + await this.token.$_burn(this.holder, firstTokenId, firstTokenValue); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.false; + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(0n); + expect(await this.token.totalSupply()).to.equal(0n); + }); + }); + + describe('batch', function () { + beforeEach(async function () { + await this.token.$_mintBatch( + this.holder, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ); + await this.token.$_burnBatch(this.holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue]); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.false; + expect(await this.token.exists(secondTokenId)).to.be.false; + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(0n); + expect(await this.token.totalSupply(ethers.Typed.uint256(secondTokenId))).to.equal(0n); + expect(await this.token.totalSupply()).to.equal(0n); + }); + }); + }); + + describe('other', function () { + it('supply unaffected by no-op', async function () { + await this.token.$_update(ethers.ZeroAddress, ethers.ZeroAddress, [firstTokenId], [firstTokenValue]); + expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(0n); + expect(await this.token.totalSupply()).to.equal(0n); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js new file mode 100644 index 0000000..a0d9b57 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js @@ -0,0 +1,70 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const erc1155Uri = 'https://token.com/nfts/'; +const baseUri = 'https://token.com/'; +const tokenId = 1n; +const value = 3000n; + +describe('ERC1155URIStorage', function () { + describe('with base uri set', function () { + async function fixture() { + const [holder] = await ethers.getSigners(); + + const token = await ethers.deployContract('$ERC1155URIStorage', [erc1155Uri]); + await token.$_setBaseURI(baseUri); + await token.$_mint(holder, tokenId, value, '0x'); + + return { token, holder }; + } + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('can request the token uri, returning the erc1155 uri if no token uri was set', async function () { + expect(await this.token.uri(tokenId)).to.equal(erc1155Uri); + }); + + it('can request the token uri, returning the concatenated uri if a token uri was set', async function () { + const tokenUri = '1234/'; + const expectedUri = `${baseUri}${tokenUri}`; + + await expect(this.token.$_setURI(ethers.Typed.uint256(tokenId), tokenUri)) + .to.emit(this.token, 'URI') + .withArgs(expectedUri, tokenId); + + expect(await this.token.uri(tokenId)).to.equal(expectedUri); + }); + }); + + describe('with base uri set to the empty string', function () { + async function fixture() { + const [holder] = await ethers.getSigners(); + + const token = await ethers.deployContract('$ERC1155URIStorage', ['']); + await token.$_mint(holder, tokenId, value, '0x'); + + return { token, holder }; + } + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('can request the token uri, returning an empty string if no token uri was set', async function () { + expect(await this.token.uri(tokenId)).to.equal(''); + }); + + it('can request the token uri, returning the token uri if a token uri was set', async function () { + const tokenUri = 'ipfs://1234/'; + + await expect(this.token.$_setURI(ethers.Typed.uint256(tokenId), tokenUri)) + .to.emit(this.token, 'URI') + .withArgs(tokenUri, tokenId); + + expect(await this.token.uri(tokenId)).to.equal(tokenUri); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js new file mode 100644 index 0000000..9bff487 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js @@ -0,0 +1,56 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); + +const ids = [1n, 2n, 3n]; +const values = [1000n, 2000n, 3000n]; +const data = '0x12345678'; + +async function fixture() { + const [owner] = await ethers.getSigners(); + + const token = await ethers.deployContract('$ERC1155', ['https://token-cdn-domain/{id}.json']); + const mock = await ethers.deployContract('$ERC1155Holder'); + + await token.$_mintBatch(owner, ids, values, '0x'); + + return { owner, token, mock }; +} + +describe('ERC1155Holder', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldSupportInterfaces(['ERC1155Receiver']); + + it('receives ERC1155 tokens from a single ID', async function () { + await this.token.connect(this.owner).safeTransferFrom(this.owner, this.mock, ids[0], values[0], data); + + expect(await this.token.balanceOf(this.mock, ids[0])).to.equal(values[0]); + + for (let i = 1; i < ids.length; i++) { + expect(await this.token.balanceOf(this.mock, ids[i])).to.equal(0n); + } + }); + + it('receives ERC1155 tokens from a multiple IDs', async function () { + expect( + await this.token.balanceOfBatch( + ids.map(() => this.mock), + ids, + ), + ).to.deep.equal(ids.map(() => 0n)); + + await this.token.connect(this.owner).safeBatchTransferFrom(this.owner, this.mock, ids, values, data); + + expect( + await this.token.balanceOfBatch( + ids.map(() => this.mock), + ids, + ), + ).to.deep.equal(values); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Utils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Utils.test.js new file mode 100644 index 0000000..5687568 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Utils.test.js @@ -0,0 +1,299 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { RevertType } = require('../../../helpers/enums'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +const firstTokenId = 1n; +const secondTokenId = 2n; +const firstTokenValue = 1000n; +const secondTokenValue = 1000n; + +const RECEIVER_SINGLE_MAGIC_VALUE = '0xf23a6e61'; +const RECEIVER_BATCH_MAGIC_VALUE = '0xbc197c81'; + +const deployReceiver = ( + revertType, + returnValueSingle = RECEIVER_SINGLE_MAGIC_VALUE, + returnValueBatched = RECEIVER_BATCH_MAGIC_VALUE, +) => ethers.deployContract('$ERC1155ReceiverMock', [returnValueSingle, returnValueBatched, revertType]); + +const fixture = async () => { + const [eoa, operator, owner] = await ethers.getSigners(); + const utils = await ethers.deployContract('$ERC1155Utils'); + + const receivers = { + correct: await deployReceiver(RevertType.None), + invalid: await deployReceiver(RevertType.None, '0xdeadbeef', '0xdeadbeef'), + message: await deployReceiver(RevertType.RevertWithMessage), + empty: await deployReceiver(RevertType.RevertWithoutMessage), + customError: await deployReceiver(RevertType.RevertWithCustomError), + panic: await deployReceiver(RevertType.Panic), + nonReceiver: await ethers.deployContract('CallReceiverMock'), + eoa, + }; + + return { operator, owner, utils, receivers }; +}; + +describe('ERC1155Utils', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('onERC1155Received', function () { + it('succeeds when called by an EOA', async function () { + await expect( + this.utils.$checkOnERC1155Received( + this.operator, + this.owner, + this.receivers.eoa, + firstTokenId, + firstTokenValue, + '0x', + ), + ).to.not.be.reverted; + }); + + it('succeeds when data is passed', async function () { + const data = '0x12345678'; + await expect( + this.utils.$checkOnERC1155Received( + this.operator, + this.owner, + this.receivers.correct, + firstTokenId, + firstTokenValue, + data, + ), + ).to.not.be.reverted; + }); + + it('succeeds when data is empty', async function () { + await expect( + this.utils.$checkOnERC1155Received( + this.operator, + this.owner, + this.receivers.correct, + firstTokenId, + firstTokenValue, + '0x', + ), + ).to.not.be.reverted; + }); + + it('reverts when receiver returns invalid value', async function () { + await expect( + this.utils.$checkOnERC1155Received( + this.operator, + this.owner, + this.receivers.invalid, + firstTokenId, + firstTokenValue, + '0x', + ), + ) + .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver') + .withArgs(this.receivers.invalid); + }); + + it('reverts when receiver reverts with message', async function () { + await expect( + this.utils.$checkOnERC1155Received( + this.operator, + this.owner, + this.receivers.message, + firstTokenId, + firstTokenValue, + '0x', + ), + ).to.be.revertedWith('ERC1155ReceiverMock: reverting on receive'); + }); + + it('reverts when receiver reverts without message', async function () { + await expect( + this.utils.$checkOnERC1155Received( + this.operator, + this.owner, + this.receivers.empty, + firstTokenId, + firstTokenValue, + '0x', + ), + ) + .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver') + .withArgs(this.receivers.empty); + }); + + it('reverts when receiver reverts with custom error', async function () { + await expect( + this.utils.$checkOnERC1155Received( + this.operator, + this.owner, + this.receivers.customError, + firstTokenId, + firstTokenValue, + '0x', + ), + ) + .to.be.revertedWithCustomError(this.receivers.customError, 'CustomError') + .withArgs(RECEIVER_SINGLE_MAGIC_VALUE); + }); + + it('reverts when receiver panics', async function () { + await expect( + this.utils.$checkOnERC1155Received( + this.operator, + this.owner, + this.receivers.panic, + firstTokenId, + firstTokenValue, + '0x', + ), + ).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO); + }); + + it('reverts when receiver does not implement onERC1155Received', async function () { + await expect( + this.utils.$checkOnERC1155Received( + this.operator, + this.owner, + this.receivers.nonReceiver, + firstTokenId, + firstTokenValue, + '0x', + ), + ) + .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver') + .withArgs(this.receivers.nonReceiver); + }); + }); + + describe('onERC1155BatchReceived', function () { + it('succeeds when called by an EOA', async function () { + await expect( + this.utils.$checkOnERC1155BatchReceived( + this.operator, + this.owner, + this.receivers.eoa, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ).to.not.be.reverted; + }); + + it('succeeds when data is passed', async function () { + const data = '0x12345678'; + await expect( + this.utils.$checkOnERC1155BatchReceived( + this.operator, + this.owner, + this.receivers.correct, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + data, + ), + ).to.not.be.reverted; + }); + + it('succeeds when data is empty', async function () { + await expect( + this.utils.$checkOnERC1155BatchReceived( + this.operator, + this.owner, + this.receivers.correct, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ).to.not.be.reverted; + }); + + it('reverts when receiver returns invalid value', async function () { + await expect( + this.utils.$checkOnERC1155BatchReceived( + this.operator, + this.owner, + this.receivers.invalid, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver') + .withArgs(this.receivers.invalid); + }); + + it('reverts when receiver reverts with message', async function () { + await expect( + this.utils.$checkOnERC1155BatchReceived( + this.operator, + this.owner, + this.receivers.message, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ).to.be.revertedWith('ERC1155ReceiverMock: reverting on batch receive'); + }); + + it('reverts when receiver reverts without message', async function () { + await expect( + this.utils.$checkOnERC1155BatchReceived( + this.operator, + this.owner, + this.receivers.empty, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver') + .withArgs(this.receivers.empty); + }); + + it('reverts when receiver reverts with custom error', async function () { + await expect( + this.utils.$checkOnERC1155BatchReceived( + this.operator, + this.owner, + this.receivers.customError, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.receivers.customError, 'CustomError') + .withArgs(RECEIVER_SINGLE_MAGIC_VALUE); + }); + + it('reverts when receiver panics', async function () { + await expect( + this.utils.$checkOnERC1155BatchReceived( + this.operator, + this.owner, + this.receivers.panic, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO); + }); + + it('reverts when receiver does not implement onERC1155BatchReceived', async function () { + await expect( + this.utils.$checkOnERC1155BatchReceived( + this.operator, + this.owner, + this.receivers.nonReceiver, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + ), + ) + .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver') + .withArgs(this.receivers.nonReceiver); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js new file mode 100644 index 0000000..748df4b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js @@ -0,0 +1,269 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); + +function shouldBehaveLikeERC20(initialSupply, opts = {}) { + const { forcedApproval } = opts; + + beforeEach(async function () { + [this.holder, this.recipient, this.other] = this.accounts; + }); + + it('total supply: returns the total token value', async function () { + expect(await this.token.totalSupply()).to.equal(initialSupply); + }); + + describe('balanceOf', function () { + it('returns zero when the requested account has no tokens', async function () { + expect(await this.token.balanceOf(this.other)).to.equal(0n); + }); + + it('returns the total token value when the requested account has some tokens', async function () { + expect(await this.token.balanceOf(this.holder)).to.equal(initialSupply); + }); + }); + + describe('transfer', function () { + beforeEach(function () { + this.transfer = (from, to, value) => this.token.connect(from).transfer(to, value); + }); + + shouldBehaveLikeERC20Transfer(initialSupply); + }); + + describe('transfer from', function () { + describe('when the token owner is not the zero address', function () { + describe('when the recipient is not the zero address', function () { + describe('when the spender has enough allowance', function () { + beforeEach(async function () { + await this.token.connect(this.holder).approve(this.recipient, initialSupply); + }); + + describe('when the token owner has enough balance', function () { + const value = initialSupply; + + beforeEach(async function () { + this.tx = await this.token.connect(this.recipient).transferFrom(this.holder, this.other, value); + }); + + it('transfers the requested value', async function () { + await expect(this.tx).to.changeTokenBalances(this.token, [this.holder, this.other], [-value, value]); + }); + + it('decreases the spender allowance', async function () { + expect(await this.token.allowance(this.holder, this.recipient)).to.equal(0n); + }); + + it('emits a transfer event', async function () { + await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.holder, this.other, value); + }); + + if (forcedApproval) { + it('emits an approval event', async function () { + await expect(this.tx) + .to.emit(this.token, 'Approval') + .withArgs( + this.holder.address, + this.recipient.address, + await this.token.allowance(this.holder, this.recipient), + ); + }); + } else { + it('does not emit an approval event', async function () { + await expect(this.tx).to.not.emit(this.token, 'Approval'); + }); + } + }); + + it('reverts when the token owner does not have enough balance', async function () { + const value = initialSupply; + await this.token.connect(this.holder).transfer(this.other, 1n); + await expect(this.token.connect(this.recipient).transferFrom(this.holder, this.other, value)) + .to.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') + .withArgs(this.holder, value - 1n, value); + }); + }); + + describe('when the spender does not have enough allowance', function () { + const allowance = initialSupply - 1n; + + beforeEach(async function () { + await this.token.connect(this.holder).approve(this.recipient, allowance); + }); + + it('reverts when the token owner has enough balance', async function () { + const value = initialSupply; + await expect(this.token.connect(this.recipient).transferFrom(this.holder, this.other, value)) + .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientAllowance') + .withArgs(this.recipient, allowance, value); + }); + + it('reverts when the token owner does not have enough balance', async function () { + const value = allowance; + await this.token.connect(this.holder).transfer(this.other, 2); + await expect(this.token.connect(this.recipient).transferFrom(this.holder, this.other, value)) + .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') + .withArgs(this.holder, value - 1n, value); + }); + }); + + describe('when the spender has unlimited allowance', function () { + beforeEach(async function () { + await this.token.connect(this.holder).approve(this.recipient, ethers.MaxUint256); + this.tx = await this.token.connect(this.recipient).transferFrom(this.holder, this.other, 1n); + }); + + it('does not decrease the spender allowance', async function () { + expect(await this.token.allowance(this.holder, this.recipient)).to.equal(ethers.MaxUint256); + }); + + it('does not emit an approval event', async function () { + await expect(this.tx).to.not.emit(this.token, 'Approval'); + }); + }); + }); + + it('reverts when the recipient is the zero address', async function () { + const value = initialSupply; + await this.token.connect(this.holder).approve(this.recipient, value); + await expect(this.token.connect(this.recipient).transferFrom(this.holder, ethers.ZeroAddress, value)) + .to.be.revertedWithCustomError(this.token, 'ERC20InvalidReceiver') + .withArgs(ethers.ZeroAddress); + }); + }); + + it('reverts when the token owner is the zero address', async function () { + // transferFrom does a spendAllowance before moving the assets + // - default behavior (ERC20) is to always update the approval using `_approve`. This will fail because the + // approver (owner) is address(0). This happens even if the amount transferred is zero, and the approval update + // is not actually necessary. + // - in ERC20TemporaryAllowance, transfer of 0 value will not update allowance (temporary or persistent) + // therefore the spendAllowance does not revert. However, the transfer of asset will revert because the sender + // is address(0) + const errorName = this.token.temporaryApprove ? 'ERC20InvalidSender' : 'ERC20InvalidApprover'; + + const value = 0n; + await expect(this.token.connect(this.recipient).transferFrom(ethers.ZeroAddress, this.recipient, value)) + .to.be.revertedWithCustomError(this.token, errorName) + .withArgs(ethers.ZeroAddress); + }); + }); + + describe('approve', function () { + beforeEach(function () { + this.approve = (owner, spender, value) => this.token.connect(owner).approve(spender, value); + }); + + shouldBehaveLikeERC20Approve(initialSupply); + }); +} + +function shouldBehaveLikeERC20Transfer(balance) { + describe('when the recipient is not the zero address', function () { + it('reverts when the sender does not have enough balance', async function () { + const value = balance + 1n; + await expect(this.transfer(this.holder, this.recipient, value)) + .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') + .withArgs(this.holder, balance, value); + }); + + describe('when the sender transfers all balance', function () { + const value = balance; + + beforeEach(async function () { + this.tx = await this.transfer(this.holder, this.recipient, value); + }); + + it('transfers the requested value', async function () { + await expect(this.tx).to.changeTokenBalances(this.token, [this.holder, this.recipient], [-value, value]); + }); + + it('emits a transfer event', async function () { + await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.holder, this.recipient, value); + }); + }); + + describe('when the sender transfers zero tokens', function () { + const value = 0n; + + beforeEach(async function () { + this.tx = await this.transfer(this.holder, this.recipient, value); + }); + + it('transfers the requested value', async function () { + await expect(this.tx).to.changeTokenBalances(this.token, [this.holder, this.recipient], [0n, 0n]); + }); + + it('emits a transfer event', async function () { + await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.holder, this.recipient, value); + }); + }); + }); + + it('reverts when the recipient is the zero address', async function () { + await expect(this.transfer(this.holder, ethers.ZeroAddress, balance)) + .to.be.revertedWithCustomError(this.token, 'ERC20InvalidReceiver') + .withArgs(ethers.ZeroAddress); + }); +} + +function shouldBehaveLikeERC20Approve(supply) { + 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 () { + await expect(this.approve(this.holder, this.recipient, value)) + .to.emit(this.token, 'Approval') + .withArgs(this.holder, this.recipient, value); + }); + + it('approves the requested value when there was no approved value before', async function () { + await this.approve(this.holder, this.recipient, value); + + expect(await this.token.allowance(this.holder, this.recipient)).to.equal(value); + }); + + it('approves the requested value and replaces the previous one when the spender had an approved value', async function () { + await this.approve(this.holder, this.recipient, 1n); + await this.approve(this.holder, this.recipient, value); + + expect(await this.token.allowance(this.holder, this.recipient)).to.equal(value); + }); + }); + + describe('when the sender does not have enough balance', function () { + const value = supply + 1n; + + it('emits an approval event', async function () { + await expect(this.approve(this.holder, this.recipient, value)) + .to.emit(this.token, 'Approval') + .withArgs(this.holder, this.recipient, value); + }); + + it('approves the requested value when there was no approved value before', async function () { + await this.approve(this.holder, this.recipient, value); + + expect(await this.token.allowance(this.holder, this.recipient)).to.equal(value); + }); + + it('approves the requested value and replaces the previous one when the spender had an approved value', async function () { + await this.approve(this.holder, this.recipient, 1n); + await this.approve(this.holder, this.recipient, value); + + expect(await this.token.allowance(this.holder, this.recipient)).to.equal(value); + }); + }); + }); + + it('reverts when the spender is the zero address', async function () { + await expect(this.approve(this.holder, ethers.ZeroAddress, supply)) + .to.be.revertedWithCustomError(this.token, `ERC20InvalidSpender`) + .withArgs(ethers.ZeroAddress); + }); +} + +module.exports = { + shouldBehaveLikeERC20, + shouldBehaveLikeERC20Transfer, + shouldBehaveLikeERC20Approve, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js new file mode 100644 index 0000000..2d9eefe --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js @@ -0,0 +1,199 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +const { + shouldBehaveLikeERC20, + shouldBehaveLikeERC20Transfer, + shouldBehaveLikeERC20Approve, +} = require('./ERC20.behavior'); + +const TOKENS = [{ Token: '$ERC20' }, { Token: '$ERC20ApprovalMock', forcedApproval: true }]; + +const name = 'My Token'; +const symbol = 'MTKN'; +const initialSupply = 100n; + +describe('ERC20', function () { + for (const { Token, forcedApproval } of TOKENS) { + describe(Token, function () { + const fixture = async () => { + // this.accounts is used by shouldBehaveLikeERC20 + const accounts = await ethers.getSigners(); + const [holder, recipient] = accounts; + + const token = await ethers.deployContract(Token, [name, symbol]); + await token.$_mint(holder, initialSupply); + + return { accounts, holder, recipient, token }; + }; + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeERC20(initialSupply, { 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.equal(18n); + }); + + describe('_mint', function () { + const value = 50n; + it('rejects a null account', async function () { + await expect(this.token.$_mint(ethers.ZeroAddress, value)) + .to.be.revertedWithCustomError(this.token, 'ERC20InvalidReceiver') + .withArgs(ethers.ZeroAddress); + }); + + it('rejects overflow', async function () { + await expect(this.token.$_mint(this.recipient, ethers.MaxUint256)).to.be.revertedWithPanic( + PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW, + ); + }); + + describe('for a non zero account', function () { + beforeEach('minting', async function () { + this.tx = await this.token.$_mint(this.recipient, value); + }); + + it('increments totalSupply', async function () { + await expect(await this.token.totalSupply()).to.equal(initialSupply + value); + }); + + it('increments recipient balance', async function () { + await expect(this.tx).to.changeTokenBalance(this.token, this.recipient, value); + }); + + it('emits Transfer event', async function () { + await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.recipient, value); + }); + }); + }); + + describe('_burn', function () { + it('rejects a null account', async function () { + await expect(this.token.$_burn(ethers.ZeroAddress, 1n)) + .to.be.revertedWithCustomError(this.token, 'ERC20InvalidSender') + .withArgs(ethers.ZeroAddress); + }); + + describe('for a non zero account', function () { + it('rejects burning more than balance', async function () { + await expect(this.token.$_burn(this.holder, initialSupply + 1n)) + .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') + .withArgs(this.holder, initialSupply, initialSupply + 1n); + }); + + const describeBurn = function (description, value) { + describe(description, function () { + beforeEach('burning', async function () { + this.tx = await this.token.$_burn(this.holder, value); + }); + + it('decrements totalSupply', async function () { + expect(await this.token.totalSupply()).to.equal(initialSupply - value); + }); + + it('decrements holder balance', async function () { + await expect(this.tx).to.changeTokenBalance(this.token, this.holder, -value); + }); + + it('emits Transfer event', async function () { + await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.holder, ethers.ZeroAddress, value); + }); + }); + }; + + describeBurn('for entire balance', initialSupply); + describeBurn('for less value than balance', initialSupply - 1n); + }); + }); + + describe('_update', function () { + const value = 1n; + + beforeEach(async function () { + this.totalSupply = await this.token.totalSupply(); + }); + + it('from is the zero address', async function () { + const tx = await this.token.$_update(ethers.ZeroAddress, this.holder, value); + await expect(tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.holder, value); + + expect(await this.token.totalSupply()).to.equal(this.totalSupply + value); + await expect(tx).to.changeTokenBalance(this.token, this.holder, value); + }); + + it('to is the zero address', async function () { + const tx = await this.token.$_update(this.holder, ethers.ZeroAddress, value); + await expect(tx).to.emit(this.token, 'Transfer').withArgs(this.holder, ethers.ZeroAddress, value); + + expect(await this.token.totalSupply()).to.equal(this.totalSupply - value); + await expect(tx).to.changeTokenBalance(this.token, this.holder, -value); + }); + + describe('from and to are the same address', function () { + it('zero address', async function () { + const tx = await this.token.$_update(ethers.ZeroAddress, ethers.ZeroAddress, value); + await expect(tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, ethers.ZeroAddress, value); + + expect(await this.token.totalSupply()).to.equal(this.totalSupply); + await expect(tx).to.changeTokenBalance(this.token, ethers.ZeroAddress, 0n); + }); + + describe('non zero address', function () { + it('reverts without balance', async function () { + await expect(this.token.$_update(this.recipient, this.recipient, value)) + .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') + .withArgs(this.recipient, 0n, value); + }); + + it('executes with balance', async function () { + const tx = await this.token.$_update(this.holder, this.holder, value); + await expect(tx).to.changeTokenBalance(this.token, this.holder, 0n); + await expect(tx).to.emit(this.token, 'Transfer').withArgs(this.holder, this.holder, value); + }); + }); + }); + }); + + describe('_transfer', function () { + beforeEach(function () { + this.transfer = this.token.$_transfer; + }); + + shouldBehaveLikeERC20Transfer(initialSupply); + + it('reverts when the sender is the zero address', async function () { + await expect(this.token.$_transfer(ethers.ZeroAddress, this.recipient, initialSupply)) + .to.be.revertedWithCustomError(this.token, 'ERC20InvalidSender') + .withArgs(ethers.ZeroAddress); + }); + }); + + describe('_approve', function () { + beforeEach(function () { + this.approve = this.token.$_approve; + }); + + shouldBehaveLikeERC20Approve(initialSupply); + + it('reverts when the owner is the zero address', async function () { + await expect(this.token.$_approve(ethers.ZeroAddress, this.recipient, initialSupply)) + .to.be.revertedWithCustomError(this.token, 'ERC20InvalidApprover') + .withArgs(ethers.ZeroAddress); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC1363.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC1363.test.js new file mode 100644 index 0000000..3d1f4e5 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC1363.test.js @@ -0,0 +1,370 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { + shouldBehaveLikeERC20, + shouldBehaveLikeERC20Transfer, + shouldBehaveLikeERC20Approve, +} = require('../ERC20.behavior.js'); +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); +const { RevertType } = require('../../../helpers/enums.js'); + +const name = 'My Token'; +const symbol = 'MTKN'; +const value = 1000n; +const data = '0x123456'; + +async function fixture() { + // this.accounts is used by shouldBehaveLikeERC20 + const accounts = await ethers.getSigners(); + const [holder, other] = accounts; + + const receiver = await ethers.deployContract('ERC1363ReceiverMock'); + const spender = await ethers.deployContract('ERC1363SpenderMock'); + const token = await ethers.deployContract('$ERC1363', [name, symbol]); + + await token.$_mint(holder, value); + + return { + accounts, + holder, + other, + token, + receiver, + spender, + selectors: { + onTransferReceived: receiver.interface.getFunction('onTransferReceived(address,address,uint256,bytes)').selector, + onApprovalReceived: spender.interface.getFunction('onApprovalReceived(address,uint256,bytes)').selector, + }, + }; +} + +describe('ERC1363', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldSupportInterfaces(['ERC165', 'ERC1363']); + shouldBehaveLikeERC20(value); + + describe('transferAndCall', function () { + describe('as a transfer', function () { + beforeEach(async function () { + this.recipient = this.receiver; + this.transfer = (holder, ...rest) => + this.token.connect(holder).getFunction('transferAndCall(address,uint256)')(...rest); + }); + + shouldBehaveLikeERC20Transfer(value); + }); + + it('reverts transferring to an EOA', async function () { + await expect(this.token.connect(this.holder).getFunction('transferAndCall(address,uint256)')(this.other, value)) + .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidReceiver') + .withArgs(this.other.address); + }); + + it('succeeds without data', async function () { + await expect( + this.token.connect(this.holder).getFunction('transferAndCall(address,uint256)')(this.receiver, value), + ) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder.address, this.receiver.target, value) + .to.emit(this.receiver, 'Received') + .withArgs(this.holder.address, this.holder.address, value, '0x'); + }); + + it('succeeds with data', async function () { + await expect( + this.token.connect(this.holder).getFunction('transferAndCall(address,uint256,bytes)')( + this.receiver, + value, + data, + ), + ) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder.address, this.receiver.target, value) + .to.emit(this.receiver, 'Received') + .withArgs(this.holder.address, this.holder.address, value, data); + }); + + it('reverts with reverting hook (without reason)', async function () { + await this.receiver.setUp(this.selectors.onTransferReceived, RevertType.RevertWithoutMessage); + + await expect( + this.token.connect(this.holder).getFunction('transferAndCall(address,uint256,bytes)')( + this.receiver, + value, + data, + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidReceiver') + .withArgs(this.receiver.target); + }); + + it('reverts with reverting hook (with reason)', async function () { + await this.receiver.setUp(this.selectors.onTransferReceived, RevertType.RevertWithMessage); + + await expect( + this.token.connect(this.holder).getFunction('transferAndCall(address,uint256,bytes)')( + this.receiver, + value, + data, + ), + ).to.be.revertedWith('ERC1363ReceiverMock: reverting'); + }); + + it('reverts with reverting hook (with custom error)', async function () { + const reason = '0x12345678'; + await this.receiver.setUp(reason, RevertType.RevertWithCustomError); + + await expect( + this.token.connect(this.holder).getFunction('transferAndCall(address,uint256,bytes)')( + this.receiver, + value, + data, + ), + ) + .to.be.revertedWithCustomError(this.receiver, 'CustomError') + .withArgs(reason); + }); + + it('panics with reverting hook (with panic)', async function () { + await this.receiver.setUp(this.selectors.onTransferReceived, RevertType.Panic); + + await expect( + this.token.connect(this.holder).getFunction('transferAndCall(address,uint256,bytes)')( + this.receiver, + value, + data, + ), + ).to.be.revertedWithPanic(); + }); + + it('reverts with bad return value', async function () { + await this.receiver.setUp('0x12345678', RevertType.None); + + await expect( + this.token.connect(this.holder).getFunction('transferAndCall(address,uint256,bytes)')( + this.receiver, + value, + data, + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidReceiver') + .withArgs(this.receiver.target); + }); + }); + + describe('transferFromAndCall', function () { + beforeEach(async function () { + await this.token.connect(this.holder).approve(this.other, ethers.MaxUint256); + }); + + describe('as a transfer', function () { + beforeEach(async function () { + this.recipient = this.receiver; + this.transfer = this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256)'); + }); + + shouldBehaveLikeERC20Transfer(value); + }); + + it('reverts transferring to an EOA', async function () { + await expect( + this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256)')( + this.holder, + this.other, + value, + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidReceiver') + .withArgs(this.other.address); + }); + + it('succeeds without data', async function () { + await expect( + this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256)')( + this.holder, + this.receiver, + value, + ), + ) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder.address, this.receiver.target, value) + .to.emit(this.receiver, 'Received') + .withArgs(this.other.address, this.holder.address, value, '0x'); + }); + + it('succeeds with data', async function () { + await expect( + this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256,bytes)')( + this.holder, + this.receiver, + value, + data, + ), + ) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder.address, this.receiver.target, value) + .to.emit(this.receiver, 'Received') + .withArgs(this.other.address, this.holder.address, value, data); + }); + + it('reverts with reverting hook (without reason)', async function () { + await this.receiver.setUp(this.selectors.onTransferReceived, RevertType.RevertWithoutMessage); + + await expect( + this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256,bytes)')( + this.holder, + this.receiver, + value, + data, + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidReceiver') + .withArgs(this.receiver.target); + }); + + it('reverts with reverting hook (with reason)', async function () { + await this.receiver.setUp(this.selectors.onTransferReceived, RevertType.RevertWithMessage); + + await expect( + this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256,bytes)')( + this.holder, + this.receiver, + value, + data, + ), + ).to.be.revertedWith('ERC1363ReceiverMock: reverting'); + }); + + it('reverts with reverting hook (with custom error)', async function () { + const reason = '0x12345678'; + await this.receiver.setUp(reason, RevertType.RevertWithCustomError); + + await expect( + this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256,bytes)')( + this.holder, + this.receiver, + value, + data, + ), + ) + .to.be.revertedWithCustomError(this.receiver, 'CustomError') + .withArgs(reason); + }); + + it('panics with reverting hook (with panic)', async function () { + await this.receiver.setUp(this.selectors.onTransferReceived, RevertType.Panic); + + await expect( + this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256,bytes)')( + this.holder, + this.receiver, + value, + data, + ), + ).to.be.revertedWithPanic(); + }); + + it('reverts with bad return value', async function () { + await this.receiver.setUp('0x12345678', RevertType.None); + + await expect( + this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256,bytes)')( + this.holder, + this.receiver, + value, + data, + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidReceiver') + .withArgs(this.receiver.target); + }); + }); + + describe('approveAndCall', function () { + describe('as an approval', function () { + beforeEach(async function () { + this.recipient = this.spender; + this.approve = (holder, ...rest) => + this.token.connect(holder).getFunction('approveAndCall(address,uint256)')(...rest); + }); + + shouldBehaveLikeERC20Approve(value); + }); + + it('reverts approving an EOA', async function () { + await expect(this.token.connect(this.holder).getFunction('approveAndCall(address,uint256)')(this.other, value)) + .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidSpender') + .withArgs(this.other.address); + }); + + it('succeeds without data', async function () { + await expect(this.token.connect(this.holder).getFunction('approveAndCall(address,uint256)')(this.spender, value)) + .to.emit(this.token, 'Approval') + .withArgs(this.holder.address, this.spender.target, value) + .to.emit(this.spender, 'Approved') + .withArgs(this.holder.address, value, '0x'); + }); + + it('succeeds with data', async function () { + await expect( + this.token.connect(this.holder).getFunction('approveAndCall(address,uint256,bytes)')(this.spender, value, data), + ) + .to.emit(this.token, 'Approval') + .withArgs(this.holder.address, this.spender.target, value) + .to.emit(this.spender, 'Approved') + .withArgs(this.holder.address, value, data); + }); + + it('with reverting hook (without reason)', async function () { + await this.spender.setUp(this.selectors.onApprovalReceived, RevertType.RevertWithoutMessage); + + await expect( + this.token.connect(this.holder).getFunction('approveAndCall(address,uint256,bytes)')(this.spender, value, data), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidSpender') + .withArgs(this.spender.target); + }); + + it('reverts with reverting hook (with reason)', async function () { + await this.spender.setUp(this.selectors.onApprovalReceived, RevertType.RevertWithMessage); + + await expect( + this.token.connect(this.holder).getFunction('approveAndCall(address,uint256,bytes)')(this.spender, value, data), + ).to.be.revertedWith('ERC1363SpenderMock: reverting'); + }); + + it('reverts with reverting hook (with custom error)', async function () { + const reason = '0x12345678'; + await this.spender.setUp(reason, RevertType.RevertWithCustomError); + + await expect( + this.token.connect(this.holder).getFunction('approveAndCall(address,uint256,bytes)')(this.spender, value, data), + ) + .to.be.revertedWithCustomError(this.spender, 'CustomError') + .withArgs(reason); + }); + + it('panics with reverting hook (with panic)', async function () { + await this.spender.setUp(this.selectors.onApprovalReceived, RevertType.Panic); + + await expect( + this.token.connect(this.holder).getFunction('approveAndCall(address,uint256,bytes)')(this.spender, value, data), + ).to.be.revertedWithPanic(); + }); + + it('reverts with bad return value', async function () { + await this.spender.setUp('0x12345678', RevertType.None); + + await expect( + this.token.connect(this.holder).getFunction('approveAndCall(address,uint256,bytes)')(this.spender, value, data), + ) + .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidSpender') + .withArgs(this.spender.target); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js new file mode 100644 index 0000000..dc40c79 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js @@ -0,0 +1,105 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const name = 'My Token'; +const symbol = 'MTKN'; +const initialBalance = 1000n; + +async function fixture() { + const [owner, burner] = await ethers.getSigners(); + + const token = await ethers.deployContract('$ERC20Burnable', [name, symbol], owner); + await token.$_mint(owner, initialBalance); + + return { owner, burner, token, initialBalance }; +} + +describe('ERC20Burnable', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('burn', function () { + it('reverts if not enough balance', async function () { + const value = this.initialBalance + 1n; + + await expect(this.token.connect(this.owner).burn(value)) + .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') + .withArgs(this.owner, this.initialBalance, value); + }); + + describe('on success', function () { + for (const { title, value } of [ + { title: 'for a zero value', value: 0n }, + { title: 'for a non-zero value', value: 100n }, + ]) { + describe(title, function () { + beforeEach(async function () { + this.tx = await this.token.connect(this.owner).burn(value); + }); + + it('burns the requested value', async function () { + await expect(this.tx).to.changeTokenBalance(this.token, this.owner, -value); + }); + + it('emits a transfer event', async function () { + await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.owner, ethers.ZeroAddress, value); + }); + }); + } + }); + }); + + describe('burnFrom', function () { + describe('reverts', function () { + it('if not enough balance', async function () { + const value = this.initialBalance + 1n; + + await this.token.connect(this.owner).approve(this.burner, value); + + await expect(this.token.connect(this.burner).burnFrom(this.owner, value)) + .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') + .withArgs(this.owner, this.initialBalance, value); + }); + + it('if not enough allowance', async function () { + const allowance = 100n; + + await this.token.connect(this.owner).approve(this.burner, allowance); + + await expect(this.token.connect(this.burner).burnFrom(this.owner, allowance + 1n)) + .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientAllowance') + .withArgs(this.burner, allowance, allowance + 1n); + }); + }); + + describe('on success', function () { + for (const { title, value } of [ + { title: 'for a zero value', value: 0n }, + { title: 'for a non-zero value', value: 100n }, + ]) { + describe(title, function () { + const originalAllowance = value * 3n; + + beforeEach(async function () { + await this.token.connect(this.owner).approve(this.burner, originalAllowance); + this.tx = await this.token.connect(this.burner).burnFrom(this.owner, value); + }); + + it('burns the requested value', async function () { + await expect(this.tx).to.changeTokenBalance(this.token, this.owner, -value); + }); + + it('decrements allowance', async function () { + expect(await this.token.allowance(this.owner, this.burner)).to.equal(originalAllowance - value); + }); + + it('emits a transfer event', async function () { + await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.owner, ethers.ZeroAddress, value); + }); + }); + } + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js new file mode 100644 index 0000000..a32ec43 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js @@ -0,0 +1,55 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const name = 'My Token'; +const symbol = 'MTKN'; +const cap = 1000n; + +async function fixture() { + const [user] = await ethers.getSigners(); + + const token = await ethers.deployContract('$ERC20Capped', [name, symbol, cap]); + + return { user, token, cap }; +} + +describe('ERC20Capped', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('requires a non-zero cap', async function () { + const ERC20Capped = await ethers.getContractFactory('$ERC20Capped'); + + await expect(ERC20Capped.deploy(name, symbol, 0)) + .to.be.revertedWithCustomError(ERC20Capped, 'ERC20InvalidCap') + .withArgs(0); + }); + + describe('capped token', function () { + it('starts with the correct cap', async function () { + expect(await this.token.cap()).to.equal(this.cap); + }); + + it('mints when value is less than cap', async function () { + const value = this.cap - 1n; + await this.token.$_mint(this.user, value); + expect(await this.token.totalSupply()).to.equal(value); + }); + + it('fails to mint if the value exceeds the cap', async function () { + await this.token.$_mint(this.user, this.cap - 1n); + await expect(this.token.$_mint(this.user, 2)) + .to.be.revertedWithCustomError(this.token, 'ERC20ExceededCap') + .withArgs(this.cap + 1n, this.cap); + }); + + it('fails to mint after cap is reached', async function () { + await this.token.$_mint(this.user, this.cap); + await expect(this.token.$_mint(this.user, 1)) + .to.be.revertedWithCustomError(this.token, 'ERC20ExceededCap') + .withArgs(this.cap + 1n, this.cap); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js new file mode 100644 index 0000000..1c751f7 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js @@ -0,0 +1,164 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const name = 'My Token'; +const symbol = 'MTKN'; +const initialSupply = 100n; +const loanValue = 10_000_000_000_000n; + +async function fixture() { + const [holder, other] = await ethers.getSigners(); + + const token = await ethers.deployContract('$ERC20FlashMintMock', [name, symbol]); + await token.$_mint(holder, initialSupply); + + return { holder, other, token }; +} + +describe('ERC20FlashMint', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('maxFlashLoan', function () { + it('token match', async function () { + expect(await this.token.maxFlashLoan(this.token)).to.equal(ethers.MaxUint256 - initialSupply); + }); + + it('token mismatch', async function () { + expect(await this.token.maxFlashLoan(ethers.ZeroAddress)).to.equal(0n); + }); + }); + + describe('flashFee', function () { + it('token match', async function () { + expect(await this.token.flashFee(this.token, loanValue)).to.equal(0n); + }); + + it('token mismatch', async function () { + await expect(this.token.flashFee(ethers.ZeroAddress, loanValue)) + .to.be.revertedWithCustomError(this.token, 'ERC3156UnsupportedToken') + .withArgs(ethers.ZeroAddress); + }); + }); + + describe('flashFeeReceiver', function () { + it('default receiver', async function () { + expect(await this.token.$_flashFeeReceiver()).to.equal(ethers.ZeroAddress); + }); + }); + + describe('flashLoan', function () { + it('success', async function () { + const receiver = await ethers.deployContract('ERC3156FlashBorrowerMock', [true, true]); + + const tx = await this.token.flashLoan(receiver, this.token, loanValue, '0x'); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, receiver, loanValue) + .to.emit(this.token, 'Transfer') + .withArgs(receiver, ethers.ZeroAddress, loanValue) + .to.emit(receiver, 'BalanceOf') + .withArgs(this.token, receiver, loanValue) + .to.emit(receiver, 'TotalSupply') + .withArgs(this.token, initialSupply + loanValue); + await expect(tx).to.changeTokenBalance(this.token, receiver, 0); + + expect(await this.token.totalSupply()).to.equal(initialSupply); + expect(await this.token.allowance(receiver, this.token)).to.equal(0n); + }); + + it('missing return value', async function () { + const receiver = await ethers.deployContract('ERC3156FlashBorrowerMock', [false, true]); + await expect(this.token.flashLoan(receiver, this.token, loanValue, '0x')) + .to.be.revertedWithCustomError(this.token, 'ERC3156InvalidReceiver') + .withArgs(receiver); + }); + + it('missing approval', async function () { + const receiver = await ethers.deployContract('ERC3156FlashBorrowerMock', [true, false]); + await expect(this.token.flashLoan(receiver, this.token, loanValue, '0x')) + .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientAllowance') + .withArgs(this.token, 0, loanValue); + }); + + it('unavailable funds', async function () { + const receiver = await ethers.deployContract('ERC3156FlashBorrowerMock', [true, true]); + const data = this.token.interface.encodeFunctionData('transfer', [this.other.address, 10]); + await expect(this.token.flashLoan(receiver, this.token, loanValue, data)) + .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') + .withArgs(receiver, loanValue - 10n, loanValue); + }); + + it('more than maxFlashLoan', async function () { + const receiver = await ethers.deployContract('ERC3156FlashBorrowerMock', [true, true]); + const data = this.token.interface.encodeFunctionData('transfer', [this.other.address, 10]); + await expect(this.token.flashLoan(receiver, this.token, ethers.MaxUint256, data)) + .to.be.revertedWithCustomError(this.token, 'ERC3156ExceededMaxLoan') + .withArgs(ethers.MaxUint256 - initialSupply); + }); + + describe('custom flash fee & custom fee receiver', function () { + const receiverInitialBalance = 200_000n; + const flashFee = 5_000n; + + beforeEach('init receiver balance & set flash fee', async function () { + this.receiver = await ethers.deployContract('ERC3156FlashBorrowerMock', [true, true]); + + const tx = await this.token.$_mint(this.receiver, receiverInitialBalance); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.receiver, receiverInitialBalance); + await expect(tx).to.changeTokenBalance(this.token, this.receiver, receiverInitialBalance); + + await this.token.setFlashFee(flashFee); + expect(await this.token.flashFee(this.token, loanValue)).to.equal(flashFee); + }); + + it('default flash fee receiver', async function () { + const tx = await this.token.flashLoan(this.receiver, this.token, loanValue, '0x'); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.receiver, loanValue) + .to.emit(this.token, 'Transfer') + .withArgs(this.receiver, ethers.ZeroAddress, loanValue + flashFee) + .to.emit(this.receiver, 'BalanceOf') + .withArgs(this.token, this.receiver, receiverInitialBalance + loanValue) + .to.emit(this.receiver, 'TotalSupply') + .withArgs(this.token, initialSupply + receiverInitialBalance + loanValue); + await expect(tx).to.changeTokenBalances(this.token, [this.receiver, ethers.ZeroAddress], [-flashFee, 0]); + + expect(await this.token.totalSupply()).to.equal(initialSupply + receiverInitialBalance - flashFee); + expect(await this.token.allowance(this.receiver, this.token)).to.equal(0n); + }); + + it('custom flash fee receiver', async function () { + const flashFeeReceiverAddress = this.other; + await this.token.setFlashFeeReceiver(flashFeeReceiverAddress); + expect(await this.token.$_flashFeeReceiver()).to.equal(flashFeeReceiverAddress); + + const tx = await this.token.flashLoan(this.receiver, this.token, loanValue, '0x'); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.receiver, loanValue) + .to.emit(this.token, 'Transfer') + .withArgs(this.receiver, ethers.ZeroAddress, loanValue) + .to.emit(this.token, 'Transfer') + .withArgs(this.receiver, flashFeeReceiverAddress, flashFee) + .to.emit(this.receiver, 'BalanceOf') + .withArgs(this.token, this.receiver, receiverInitialBalance + loanValue) + .to.emit(this.receiver, 'TotalSupply') + .withArgs(this.token, initialSupply + receiverInitialBalance + loanValue); + await expect(tx).to.changeTokenBalances( + this.token, + [this.receiver, flashFeeReceiverAddress], + [-flashFee, flashFee], + ); + + expect(await this.token.totalSupply()).to.equal(initialSupply + receiverInitialBalance); + expect(await this.token.allowance(this.receiver, flashFeeReceiverAddress)).to.equal(0n); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js new file mode 100644 index 0000000..1f1157c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js @@ -0,0 +1,129 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const name = 'My Token'; +const symbol = 'MTKN'; +const initialSupply = 100n; + +async function fixture() { + const [holder, recipient, approved] = await ethers.getSigners(); + + const token = await ethers.deployContract('$ERC20Pausable', [name, symbol]); + await token.$_mint(holder, initialSupply); + + return { holder, recipient, approved, token }; +} + +describe('ERC20Pausable', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('pausable token', function () { + describe('transfer', function () { + it('allows to transfer when unpaused', async function () { + await expect(this.token.connect(this.holder).transfer(this.recipient, initialSupply)).to.changeTokenBalances( + this.token, + [this.holder, this.recipient], + [-initialSupply, initialSupply], + ); + }); + + it('allows to transfer when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await expect(this.token.connect(this.holder).transfer(this.recipient, initialSupply)).to.changeTokenBalances( + this.token, + [this.holder, this.recipient], + [-initialSupply, initialSupply], + ); + }); + + it('reverts when trying to transfer when paused', async function () { + await this.token.$_pause(); + + await expect( + this.token.connect(this.holder).transfer(this.recipient, initialSupply), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); + }); + }); + + describe('transfer from', function () { + const allowance = 40n; + + beforeEach(async function () { + await this.token.connect(this.holder).approve(this.approved, allowance); + }); + + it('allows to transfer from when unpaused', async function () { + await expect( + this.token.connect(this.approved).transferFrom(this.holder, this.recipient, allowance), + ).to.changeTokenBalances(this.token, [this.holder, this.recipient], [-allowance, allowance]); + }); + + it('allows to transfer when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await expect( + this.token.connect(this.approved).transferFrom(this.holder, this.recipient, allowance), + ).to.changeTokenBalances(this.token, [this.holder, this.recipient], [-allowance, allowance]); + }); + + it('reverts when trying to transfer from when paused', async function () { + await this.token.$_pause(); + + await expect( + this.token.connect(this.approved).transferFrom(this.holder, this.recipient, allowance), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); + }); + }); + + describe('mint', function () { + const value = 42n; + + it('allows to mint when unpaused', async function () { + await expect(this.token.$_mint(this.recipient, value)).to.changeTokenBalance(this.token, this.recipient, value); + }); + + it('allows to mint when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await expect(this.token.$_mint(this.recipient, value)).to.changeTokenBalance(this.token, this.recipient, value); + }); + + it('reverts when trying to mint when paused', async function () { + await this.token.$_pause(); + + await expect(this.token.$_mint(this.recipient, value)).to.be.revertedWithCustomError( + this.token, + 'EnforcedPause', + ); + }); + }); + + describe('burn', function () { + const value = 42n; + + it('allows to burn when unpaused', async function () { + await expect(this.token.$_burn(this.holder, value)).to.changeTokenBalance(this.token, this.holder, -value); + }); + + it('allows to burn when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await expect(this.token.$_burn(this.holder, value)).to.changeTokenBalance(this.token, this.holder, -value); + }); + + it('reverts when trying to burn when paused', async function () { + await this.token.$_pause(); + + await expect(this.token.$_burn(this.holder, value)).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Permit.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Permit.test.js new file mode 100644 index 0000000..c3c80d7 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Permit.test.js @@ -0,0 +1,109 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain, domainSeparator, Permit } = require('../../../helpers/eip712'); +const time = require('../../../helpers/time'); + +const name = 'My Token'; +const symbol = 'MTKN'; +const initialSupply = 100n; + +async function fixture() { + const [holder, spender, owner, other] = await ethers.getSigners(); + + const token = await ethers.deployContract('$ERC20Permit', [name, symbol, name]); + await token.$_mint(holder, initialSupply); + + return { + holder, + spender, + owner, + other, + token, + }; +} + +describe('ERC20Permit', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('initial nonce is 0', async function () { + expect(await this.token.nonces(this.holder)).to.equal(0n); + }); + + it('domain separator', async function () { + expect(await this.token.DOMAIN_SEPARATOR()).to.equal(await getDomain(this.token).then(domainSeparator)); + }); + + describe('permit', function () { + const value = 42n; + const nonce = 0n; + const maxDeadline = ethers.MaxUint256; + + beforeEach(function () { + this.buildData = (contract, deadline = maxDeadline) => + getDomain(contract).then(domain => ({ + domain, + types: { Permit }, + message: { + owner: this.owner.address, + spender: this.spender.address, + value, + nonce, + deadline, + }, + })); + }); + + it('accepts owner signature', async function () { + const { v, r, s } = await this.buildData(this.token) + .then(({ domain, types, message }) => this.owner.signTypedData(domain, types, message)) + .then(ethers.Signature.from); + + await this.token.permit(this.owner, this.spender, value, maxDeadline, v, r, s); + + expect(await this.token.nonces(this.owner)).to.equal(1n); + expect(await this.token.allowance(this.owner, this.spender)).to.equal(value); + }); + + it('rejects reused signature', async function () { + const { v, r, s, serialized } = await this.buildData(this.token) + .then(({ domain, types, message }) => this.owner.signTypedData(domain, types, message)) + .then(ethers.Signature.from); + + await this.token.permit(this.owner, this.spender, value, maxDeadline, v, r, s); + + const recovered = await this.buildData(this.token).then(({ domain, types, message }) => + ethers.verifyTypedData(domain, types, { ...message, nonce: nonce + 1n, deadline: maxDeadline }, serialized), + ); + + await expect(this.token.permit(this.owner, this.spender, value, maxDeadline, v, r, s)) + .to.be.revertedWithCustomError(this.token, 'ERC2612InvalidSigner') + .withArgs(recovered, this.owner); + }); + + it('rejects other signature', async function () { + const { v, r, s } = await this.buildData(this.token) + .then(({ domain, types, message }) => this.other.signTypedData(domain, types, message)) + .then(ethers.Signature.from); + + await expect(this.token.permit(this.owner, this.spender, value, maxDeadline, v, r, s)) + .to.be.revertedWithCustomError(this.token, 'ERC2612InvalidSigner') + .withArgs(this.other, this.owner); + }); + + it('rejects expired permit', async function () { + const deadline = (await time.clock.timestamp()) - time.duration.weeks(1); + + const { v, r, s } = await this.buildData(this.token, deadline) + .then(({ domain, types, message }) => this.owner.signTypedData(domain, types, message)) + .then(ethers.Signature.from); + + await expect(this.token.permit(this.owner, this.spender, value, deadline, v, r, s)) + .to.be.revertedWithCustomError(this.token, 'ERC2612ExpiredSignature') + .withArgs(deadline); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js new file mode 100644 index 0000000..3c595c9 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js @@ -0,0 +1,546 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain, Delegation } = require('../../../helpers/eip712'); +const { batchInBlock } = require('../../../helpers/txpool'); +const time = require('../../../helpers/time'); + +const { shouldBehaveLikeVotes } = require('../../../governance/utils/Votes.behavior'); + +const TOKENS = [ + { Token: '$ERC20Votes', mode: 'blocknumber' }, + { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, +]; + +const name = 'My Token'; +const symbol = 'MTKN'; +const version = '1'; +const supply = ethers.parseEther('10000000'); + +describe('ERC20Votes', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + // accounts is required by shouldBehaveLikeVotes + const accounts = await ethers.getSigners(); + const [holder, recipient, delegatee, other1, other2] = accounts; + + const token = await ethers.deployContract(Token, [name, symbol, name, version]); + const domain = await getDomain(token); + + return { accounts, holder, recipient, delegatee, other1, other2, token, domain }; + }; + + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + this.votes = this.token; + }); + + // includes ERC6372 behavior check + shouldBehaveLikeVotes([1, 17, 42], { mode, fungible: true }); + + it('initial nonce is 0', async function () { + expect(await this.token.nonces(this.holder)).to.equal(0n); + }); + + it('minting restriction', async function () { + const value = 2n ** 208n; + await expect(this.token.$_mint(this.holder, value)) + .to.be.revertedWithCustomError(this.token, 'ERC20ExceededSafeSupply') + .withArgs(value, value - 1n); + }); + + it('recent checkpoints', async function () { + await this.token.connect(this.holder).delegate(this.holder); + for (let i = 0; i < 6; i++) { + await this.token.$_mint(this.holder, 1n); + } + const timepoint = await time.clock[mode](); + expect(await this.token.numCheckpoints(this.holder)).to.equal(6n); + // recent + expect(await this.token.getPastVotes(this.holder, timepoint - 1n)).to.equal(5n); + // non-recent + expect(await this.token.getPastVotes(this.holder, timepoint - 6n)).to.equal(0n); + }); + + describe('set delegation', function () { + describe('call', function () { + it('delegation with balance', async function () { + await this.token.$_mint(this.holder, supply); + expect(await this.token.delegates(this.holder)).to.equal(ethers.ZeroAddress); + + const tx = await this.token.connect(this.holder).delegate(this.holder); + const timepoint = await time.clockFromReceipt[mode](tx); + + await expect(tx) + .to.emit(this.token, 'DelegateChanged') + .withArgs(this.holder, ethers.ZeroAddress, this.holder) + .to.emit(this.token, 'DelegateVotesChanged') + .withArgs(this.holder, 0n, supply); + + expect(await this.token.delegates(this.holder)).to.equal(this.holder); + expect(await this.token.getVotes(this.holder)).to.equal(supply); + expect(await this.token.getPastVotes(this.holder, timepoint - 1n)).to.equal(0n); + await mine(); + expect(await this.token.getPastVotes(this.holder, timepoint)).to.equal(supply); + }); + + it('delegation without balance', async function () { + expect(await this.token.delegates(this.holder)).to.equal(ethers.ZeroAddress); + + await expect(this.token.connect(this.holder).delegate(this.holder)) + .to.emit(this.token, 'DelegateChanged') + .withArgs(this.holder, ethers.ZeroAddress, this.holder) + .to.not.emit(this.token, 'DelegateVotesChanged'); + + expect(await this.token.delegates(this.holder)).to.equal(this.holder); + }); + }); + + describe('with signature', function () { + const nonce = 0n; + + beforeEach(async function () { + await this.token.$_mint(this.holder, supply); + }); + + it('accept signed delegation', async function () { + const { r, s, v } = await this.holder + .signTypedData( + this.domain, + { Delegation }, + { + delegatee: this.holder.address, + nonce, + expiry: ethers.MaxUint256, + }, + ) + .then(ethers.Signature.from); + + expect(await this.token.delegates(this.holder)).to.equal(ethers.ZeroAddress); + + const tx = await this.token.delegateBySig(this.holder, nonce, ethers.MaxUint256, v, r, s); + const timepoint = await time.clockFromReceipt[mode](tx); + + await expect(tx) + .to.emit(this.token, 'DelegateChanged') + .withArgs(this.holder, ethers.ZeroAddress, this.holder) + .to.emit(this.token, 'DelegateVotesChanged') + .withArgs(this.holder, 0n, supply); + + expect(await this.token.delegates(this.holder)).to.equal(this.holder); + + expect(await this.token.getVotes(this.holder)).to.equal(supply); + expect(await this.token.getPastVotes(this.holder, timepoint - 1n)).to.equal(0n); + await mine(); + expect(await this.token.getPastVotes(this.holder, timepoint)).to.equal(supply); + }); + + it('rejects reused signature', async function () { + const { r, s, v } = await this.holder + .signTypedData( + this.domain, + { Delegation }, + { + delegatee: this.holder.address, + nonce, + expiry: ethers.MaxUint256, + }, + ) + .then(ethers.Signature.from); + + await this.token.delegateBySig(this.holder, nonce, ethers.MaxUint256, v, r, s); + + await expect(this.token.delegateBySig(this.holder, nonce, ethers.MaxUint256, v, r, s)) + .to.be.revertedWithCustomError(this.token, 'InvalidAccountNonce') + .withArgs(this.holder, nonce + 1n); + }); + + it('rejects bad delegatee', async function () { + const { r, s, v } = await this.holder + .signTypedData( + this.domain, + { Delegation }, + { + delegatee: this.holder.address, + nonce, + expiry: ethers.MaxUint256, + }, + ) + .then(ethers.Signature.from); + + const tx = await this.token.delegateBySig(this.delegatee, nonce, ethers.MaxUint256, v, r, s); + + const { args } = await tx + .wait() + .then(receipt => receipt.logs.find(event => event.fragment.name == 'DelegateChanged')); + expect(args[0]).to.not.equal(this.holder); + expect(args[1]).to.equal(ethers.ZeroAddress); + expect(args[2]).to.equal(this.delegatee); + }); + + it('rejects bad nonce', async function () { + const { r, s, v, serialized } = await this.holder + .signTypedData( + this.domain, + { Delegation }, + { + delegatee: this.holder.address, + nonce, + expiry: ethers.MaxUint256, + }, + ) + .then(ethers.Signature.from); + + const recovered = ethers.verifyTypedData( + this.domain, + { Delegation }, + { + delegatee: this.holder.address, + nonce: nonce + 1n, + expiry: ethers.MaxUint256, + }, + serialized, + ); + + await expect(this.token.delegateBySig(this.holder, nonce + 1n, ethers.MaxUint256, v, r, s)) + .to.be.revertedWithCustomError(this.token, 'InvalidAccountNonce') + .withArgs(recovered, nonce); + }); + + it('rejects expired permit', async function () { + const expiry = (await time.clock.timestamp()) - time.duration.weeks(1); + + const { r, s, v } = await this.holder + .signTypedData( + this.domain, + { Delegation }, + { + delegatee: this.holder.address, + nonce, + expiry, + }, + ) + .then(ethers.Signature.from); + + await expect(this.token.delegateBySig(this.holder, nonce, expiry, v, r, s)) + .to.be.revertedWithCustomError(this.token, 'VotesExpiredSignature') + .withArgs(expiry); + }); + }); + }); + + describe('change delegation', function () { + beforeEach(async function () { + await this.token.$_mint(this.holder, supply); + await this.token.connect(this.holder).delegate(this.holder); + }); + + it('call', async function () { + expect(await this.token.delegates(this.holder)).to.equal(this.holder); + + const tx = await this.token.connect(this.holder).delegate(this.delegatee); + const timepoint = await time.clockFromReceipt[mode](tx); + + await expect(tx) + .to.emit(this.token, 'DelegateChanged') + .withArgs(this.holder, this.holder, this.delegatee) + .to.emit(this.token, 'DelegateVotesChanged') + .withArgs(this.holder, supply, 0n) + .to.emit(this.token, 'DelegateVotesChanged') + .withArgs(this.delegatee, 0n, supply); + + expect(await this.token.delegates(this.holder)).to.equal(this.delegatee); + + expect(await this.token.getVotes(this.holder)).to.equal(0n); + expect(await this.token.getVotes(this.delegatee)).to.equal(supply); + expect(await this.token.getPastVotes(this.holder, timepoint - 1n)).to.equal(supply); + expect(await this.token.getPastVotes(this.delegatee, timepoint - 1n)).to.equal(0n); + await mine(); + expect(await this.token.getPastVotes(this.holder, timepoint)).to.equal(0n); + expect(await this.token.getPastVotes(this.delegatee, timepoint)).to.equal(supply); + }); + }); + + describe('transfers', function () { + beforeEach(async function () { + await this.token.$_mint(this.holder, supply); + }); + + it('no delegation', async function () { + await expect(this.token.connect(this.holder).transfer(this.recipient, 1n)) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.recipient, 1n) + .to.not.emit(this.token, 'DelegateVotesChanged'); + + this.holderVotes = 0n; + this.recipientVotes = 0n; + }); + + it('sender delegation', async function () { + await this.token.connect(this.holder).delegate(this.holder); + + const tx = await this.token.connect(this.holder).transfer(this.recipient, 1n); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.recipient, 1n) + .to.emit(this.token, 'DelegateVotesChanged') + .withArgs(this.holder, supply, supply - 1n); + + const { logs } = await tx.wait(); + const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged'); + for (const event of logs.filter(event => event.fragment.name == 'Transfer')) { + expect(event.index).to.lt(index); + } + + this.holderVotes = supply - 1n; + this.recipientVotes = 0n; + }); + + it('receiver delegation', async function () { + await this.token.connect(this.recipient).delegate(this.recipient); + + const tx = await this.token.connect(this.holder).transfer(this.recipient, 1n); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.recipient, 1n) + .to.emit(this.token, 'DelegateVotesChanged') + .withArgs(this.recipient, 0n, 1n); + + const { logs } = await tx.wait(); + const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged'); + for (const event of logs.filter(event => event.fragment.name == 'Transfer')) { + expect(event.index).to.lt(index); + } + + this.holderVotes = 0n; + this.recipientVotes = 1n; + }); + + it('full delegation', async function () { + await this.token.connect(this.holder).delegate(this.holder); + await this.token.connect(this.recipient).delegate(this.recipient); + + const tx = await this.token.connect(this.holder).transfer(this.recipient, 1n); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.recipient, 1n) + .to.emit(this.token, 'DelegateVotesChanged') + .withArgs(this.holder, supply, supply - 1n) + .to.emit(this.token, 'DelegateVotesChanged') + .withArgs(this.recipient, 0n, 1n); + + const { logs } = await tx.wait(); + const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged'); + for (const event of logs.filter(event => event.fragment.name == 'Transfer')) { + expect(event.index).to.lt(index); + } + + this.holderVotes = supply - 1n; + this.recipientVotes = 1n; + }); + + afterEach(async function () { + expect(await this.token.getVotes(this.holder)).to.equal(this.holderVotes); + expect(await this.token.getVotes(this.recipient)).to.equal(this.recipientVotes); + + // need to advance 2 blocks to see the effect of a transfer on "getPastVotes" + const timepoint = await time.clock[mode](); + await mine(); + expect(await this.token.getPastVotes(this.holder, timepoint)).to.equal(this.holderVotes); + expect(await this.token.getPastVotes(this.recipient, timepoint)).to.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(this.holder, supply); + }); + + describe('balanceOf', function () { + it('grants to initial account', async function () { + expect(await this.token.balanceOf(this.holder)).to.equal(supply); + }); + }); + + describe('numCheckpoints', function () { + it('returns the number of checkpoints for a delegate', async function () { + await this.token.connect(this.holder).transfer(this.recipient, 100n); //give an account a few tokens for readability + expect(await this.token.numCheckpoints(this.other1)).to.equal(0n); + + const t1 = await this.token.connect(this.recipient).delegate(this.other1); + t1.timepoint = await time.clockFromReceipt[mode](t1); + expect(await this.token.numCheckpoints(this.other1)).to.equal(1n); + + const t2 = await this.token.connect(this.recipient).transfer(this.other2, 10); + t2.timepoint = await time.clockFromReceipt[mode](t2); + expect(await this.token.numCheckpoints(this.other1)).to.equal(2n); + + const t3 = await this.token.connect(this.recipient).transfer(this.other2, 10); + t3.timepoint = await time.clockFromReceipt[mode](t3); + expect(await this.token.numCheckpoints(this.other1)).to.equal(3n); + + const t4 = await this.token.connect(this.holder).transfer(this.recipient, 20); + t4.timepoint = await time.clockFromReceipt[mode](t4); + expect(await this.token.numCheckpoints(this.other1)).to.equal(4n); + + expect(await this.token.checkpoints(this.other1, 0n)).to.deep.equal([t1.timepoint, 100n]); + expect(await this.token.checkpoints(this.other1, 1n)).to.deep.equal([t2.timepoint, 90n]); + expect(await this.token.checkpoints(this.other1, 2n)).to.deep.equal([t3.timepoint, 80n]); + expect(await this.token.checkpoints(this.other1, 3n)).to.deep.equal([t4.timepoint, 100n]); + await mine(); + expect(await this.token.getPastVotes(this.other1, t1.timepoint)).to.equal(100n); + expect(await this.token.getPastVotes(this.other1, t2.timepoint)).to.equal(90n); + expect(await this.token.getPastVotes(this.other1, t3.timepoint)).to.equal(80n); + expect(await this.token.getPastVotes(this.other1, t4.timepoint)).to.equal(100n); + }); + + it('does not add more than one checkpoint in a block', async function () { + await this.token.connect(this.holder).transfer(this.recipient, 100n); + expect(await this.token.numCheckpoints(this.other1)).to.equal(0n); + + const [t1, t2, t3] = await batchInBlock([ + () => this.token.connect(this.recipient).delegate(this.other1, { gasLimit: 200000 }), + () => this.token.connect(this.recipient).transfer(this.other2, 10n, { gasLimit: 200000 }), + () => this.token.connect(this.recipient).transfer(this.other2, 10n, { gasLimit: 200000 }), + ]); + t1.timepoint = await time.clockFromReceipt[mode](t1); + t2.timepoint = await time.clockFromReceipt[mode](t2); + t3.timepoint = await time.clockFromReceipt[mode](t3); + + expect(await this.token.numCheckpoints(this.other1)).to.equal(1); + expect(await this.token.checkpoints(this.other1, 0n)).to.be.deep.equal([t1.timepoint, 80n]); + + const t4 = await this.token.connect(this.holder).transfer(this.recipient, 20n); + t4.timepoint = await time.clockFromReceipt[mode](t4); + + expect(await this.token.numCheckpoints(this.other1)).to.equal(2n); + expect(await this.token.checkpoints(this.other1, 1n)).to.be.deep.equal([t4.timepoint, 100n]); + }); + }); + + describe('getPastVotes', function () { + it('reverts if block number >= current block', async function () { + const clock = await this.token.clock(); + await expect(this.token.getPastVotes(this.other1, 50_000_000_000n)) + .to.be.revertedWithCustomError(this.token, 'ERC5805FutureLookup') + .withArgs(50_000_000_000n, clock); + }); + + it('returns 0 if there are no checkpoints', async function () { + expect(await this.token.getPastVotes(this.other1, 0n)).to.equal(0n); + }); + + it('returns the latest block if >= last checkpoint block', async function () { + const tx = await this.token.connect(this.holder).delegate(this.other1); + const timepoint = await time.clockFromReceipt[mode](tx); + await mine(2); + + expect(await this.token.getPastVotes(this.other1, timepoint)).to.equal(supply); + expect(await this.token.getPastVotes(this.other1, timepoint + 1n)).to.equal(supply); + }); + + it('returns zero if < first checkpoint block', async function () { + await mine(); + const tx = await this.token.connect(this.holder).delegate(this.other1); + const timepoint = await time.clockFromReceipt[mode](tx); + await mine(2); + + expect(await this.token.getPastVotes(this.other1, timepoint - 1n)).to.equal(0n); + expect(await this.token.getPastVotes(this.other1, timepoint + 1n)).to.equal(supply); + }); + + it('generally returns the voting balance at the appropriate checkpoint', async function () { + const t1 = await this.token.connect(this.holder).delegate(this.other1); + await mine(2); + const t2 = await this.token.connect(this.holder).transfer(this.other2, 10); + await mine(2); + const t3 = await this.token.connect(this.holder).transfer(this.other2, 10); + await mine(2); + const t4 = await this.token.connect(this.other2).transfer(this.holder, 20); + await mine(2); + + t1.timepoint = await time.clockFromReceipt[mode](t1); + t2.timepoint = await time.clockFromReceipt[mode](t2); + t3.timepoint = await time.clockFromReceipt[mode](t3); + t4.timepoint = await time.clockFromReceipt[mode](t4); + + expect(await this.token.getPastVotes(this.other1, t1.timepoint - 1n)).to.equal(0n); + expect(await this.token.getPastVotes(this.other1, t1.timepoint)).to.equal(supply); + expect(await this.token.getPastVotes(this.other1, t1.timepoint + 1n)).to.equal(supply); + expect(await this.token.getPastVotes(this.other1, t2.timepoint)).to.equal(supply - 10n); + expect(await this.token.getPastVotes(this.other1, t2.timepoint + 1n)).to.equal(supply - 10n); + expect(await this.token.getPastVotes(this.other1, t3.timepoint)).to.equal(supply - 20n); + expect(await this.token.getPastVotes(this.other1, t3.timepoint + 1n)).to.equal(supply - 20n); + expect(await this.token.getPastVotes(this.other1, t4.timepoint)).to.equal(supply); + expect(await this.token.getPastVotes(this.other1, t4.timepoint + 1n)).to.equal(supply); + }); + }); + }); + + describe('getPastTotalSupply', function () { + beforeEach(async function () { + await this.token.connect(this.holder).delegate(this.holder); + }); + + it('reverts if block number >= current block', async function () { + const clock = await this.token.clock(); + await expect(this.token.getPastTotalSupply(50_000_000_000n)) + .to.be.revertedWithCustomError(this.token, 'ERC5805FutureLookup') + .withArgs(50_000_000_000n, clock); + }); + + it('returns 0 if there are no checkpoints', async function () { + expect(await this.token.getPastTotalSupply(0n)).to.equal(0n); + }); + + it('returns the latest block if >= last checkpoint block', async function () { + const tx = await this.token.$_mint(this.holder, supply); + const timepoint = await time.clockFromReceipt[mode](tx); + await mine(2); + + expect(await this.token.getPastTotalSupply(timepoint)).to.equal(supply); + expect(await this.token.getPastTotalSupply(timepoint + 1n)).to.equal(supply); + }); + + it('returns zero if < first checkpoint block', async function () { + await mine(); + const tx = await this.token.$_mint(this.holder, supply); + const timepoint = await time.clockFromReceipt[mode](tx); + await mine(2); + + expect(await this.token.getPastTotalSupply(timepoint - 1n)).to.equal(0n); + expect(await this.token.getPastTotalSupply(timepoint + 1n)).to.equal(supply); + }); + + it('generally returns the voting balance at the appropriate checkpoint', async function () { + const t1 = await this.token.$_mint(this.holder, supply); + await mine(2); + const t2 = await this.token.$_burn(this.holder, 10n); + await mine(2); + const t3 = await this.token.$_burn(this.holder, 10n); + await mine(2); + const t4 = await this.token.$_mint(this.holder, 20n); + await mine(2); + + t1.timepoint = await time.clockFromReceipt[mode](t1); + t2.timepoint = await time.clockFromReceipt[mode](t2); + t3.timepoint = await time.clockFromReceipt[mode](t3); + t4.timepoint = await time.clockFromReceipt[mode](t4); + + expect(await this.token.getPastTotalSupply(t1.timepoint - 1n)).to.equal(0n); + expect(await this.token.getPastTotalSupply(t1.timepoint)).to.equal(supply); + expect(await this.token.getPastTotalSupply(t1.timepoint + 1n)).to.equal(supply); + expect(await this.token.getPastTotalSupply(t2.timepoint)).to.equal(supply - 10n); + expect(await this.token.getPastTotalSupply(t2.timepoint + 1n)).to.equal(supply - 10n); + expect(await this.token.getPastTotalSupply(t3.timepoint)).to.equal(supply - 20n); + expect(await this.token.getPastTotalSupply(t3.timepoint + 1n)).to.equal(supply - 20n); + expect(await this.token.getPastTotalSupply(t4.timepoint)).to.equal(supply); + expect(await this.token.getPastTotalSupply(t4.timepoint + 1n)).to.equal(supply); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js new file mode 100644 index 0000000..2f630e6 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js @@ -0,0 +1,203 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { shouldBehaveLikeERC20 } = require('../ERC20.behavior'); + +const name = 'My Token'; +const symbol = 'MTKN'; +const decimals = 9n; +const initialSupply = 100n; + +async function fixture() { + // this.accounts is used by shouldBehaveLikeERC20 + const accounts = await ethers.getSigners(); + const [holder, recipient, other] = accounts; + + const underlying = await ethers.deployContract('$ERC20DecimalsMock', [name, symbol, decimals]); + await underlying.$_mint(holder, initialSupply); + + const token = await ethers.deployContract('$ERC20Wrapper', [`Wrapped ${name}`, `W${symbol}`, underlying]); + + return { accounts, holder, recipient, other, underlying, token }; +} + +describe('ERC20Wrapper', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + afterEach('Underlying balance', async function () { + expect(await this.underlying.balanceOf(this.token)).to.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.equal(decimals); + }); + + it('decimals default back to 18 if token has no metadata', async function () { + const noDecimals = await ethers.deployContract('CallReceiverMock'); + const token = await ethers.deployContract('$ERC20Wrapper', [`Wrapped ${name}`, `W${symbol}`, noDecimals]); + expect(await token.decimals()).to.equal(18n); + }); + + it('has underlying', async function () { + expect(await this.token.underlying()).to.equal(this.underlying); + }); + + describe('deposit', function () { + it('executes with approval', async function () { + await this.underlying.connect(this.holder).approve(this.token, initialSupply); + + const tx = await this.token.connect(this.holder).depositFor(this.holder, initialSupply); + await expect(tx) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.holder, this.token, initialSupply) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.holder, initialSupply); + await expect(tx).to.changeTokenBalances( + this.underlying, + [this.holder, this.token], + [-initialSupply, initialSupply], + ); + await expect(tx).to.changeTokenBalance(this.token, this.holder, initialSupply); + }); + + it('reverts when missing approval', async function () { + await expect(this.token.connect(this.holder).depositFor(this.holder, initialSupply)) + .to.be.revertedWithCustomError(this.underlying, 'ERC20InsufficientAllowance') + .withArgs(this.token, 0, initialSupply); + }); + + it('reverts when insufficient balance', async function () { + await this.underlying.connect(this.holder).approve(this.token, ethers.MaxUint256); + + await expect(this.token.connect(this.holder).depositFor(this.holder, ethers.MaxUint256)) + .to.be.revertedWithCustomError(this.underlying, 'ERC20InsufficientBalance') + .withArgs(this.holder, initialSupply, ethers.MaxUint256); + }); + + it('deposits to other account', async function () { + await this.underlying.connect(this.holder).approve(this.token, initialSupply); + + const tx = await this.token.connect(this.holder).depositFor(this.recipient, initialSupply); + await expect(tx) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.holder, this.token.target, initialSupply) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.recipient, initialSupply); + await expect(tx).to.changeTokenBalances( + this.underlying, + [this.holder, this.token], + [-initialSupply, initialSupply], + ); + await expect(tx).to.changeTokenBalances(this.token, [this.holder, this.recipient], [0, initialSupply]); + }); + + it('reverts minting to the wrapper contract', async function () { + await this.underlying.connect(this.holder).approve(this.token, ethers.MaxUint256); + + await expect(this.token.connect(this.holder).depositFor(this.token, ethers.MaxUint256)) + .to.be.revertedWithCustomError(this.token, 'ERC20InvalidReceiver') + .withArgs(this.token); + }); + }); + + describe('withdraw', function () { + beforeEach(async function () { + await this.underlying.connect(this.holder).approve(this.token, initialSupply); + await this.token.connect(this.holder).depositFor(this.holder, initialSupply); + }); + + it('reverts when insufficient balance', async function () { + await expect(this.token.connect(this.holder).withdrawTo(this.holder, ethers.MaxInt256)) + .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') + .withArgs(this.holder, initialSupply, ethers.MaxInt256); + }); + + it('executes when operation is valid', async function () { + const value = 42n; + + const tx = await this.token.connect(this.holder).withdrawTo(this.holder, value); + await expect(tx) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.token.target, this.holder, value) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, ethers.ZeroAddress, value); + await expect(tx).to.changeTokenBalances(this.underlying, [this.token, this.holder], [-value, value]); + await expect(tx).to.changeTokenBalance(this.token, this.holder, -value); + }); + + it('entire balance', async function () { + const tx = await this.token.connect(this.holder).withdrawTo(this.holder, initialSupply); + await expect(tx) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.token.target, this.holder, initialSupply) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, ethers.ZeroAddress, initialSupply); + await expect(tx).to.changeTokenBalances( + this.underlying, + [this.token, this.holder], + [-initialSupply, initialSupply], + ); + await expect(tx).to.changeTokenBalance(this.token, this.holder, -initialSupply); + }); + + it('to other account', async function () { + const tx = await this.token.connect(this.holder).withdrawTo(this.recipient, initialSupply); + await expect(tx) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.token, this.recipient, initialSupply) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, ethers.ZeroAddress, initialSupply); + await expect(tx).to.changeTokenBalances( + this.underlying, + [this.token, this.holder, this.recipient], + [-initialSupply, 0, initialSupply], + ); + await expect(tx).to.changeTokenBalance(this.token, this.holder, -initialSupply); + }); + + it('reverts withdrawing to the wrapper contract', async function () { + await expect(this.token.connect(this.holder).withdrawTo(this.token, initialSupply)) + .to.be.revertedWithCustomError(this.token, 'ERC20InvalidReceiver') + .withArgs(this.token); + }); + }); + + describe('recover', function () { + it('nothing to recover', async function () { + await this.underlying.connect(this.holder).approve(this.token, initialSupply); + await this.token.connect(this.holder).depositFor(this.holder, initialSupply); + + const tx = await this.token.$_recover(this.recipient); + await expect(tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.recipient, 0n); + await expect(tx).to.changeTokenBalance(this.token, this.recipient, 0); + }); + + it('something to recover', async function () { + await this.underlying.connect(this.holder).transfer(this.token, initialSupply); + + const tx = await this.token.$_recover(this.recipient); + await expect(tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.recipient, initialSupply); + await expect(tx).to.changeTokenBalance(this.token, this.recipient, initialSupply); + }); + }); + + describe('erc20 behaviour', function () { + beforeEach(async function () { + await this.underlying.connect(this.holder).approve(this.token, initialSupply); + await this.token.connect(this.holder).depositFor(this.holder, initialSupply); + }); + + shouldBehaveLikeERC20(initialSupply); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol new file mode 100644 index 0000000..72b0dac --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js new file mode 100644 index 0000000..ad8c926 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js @@ -0,0 +1,888 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +const { Enum } = require('../../../helpers/enums'); + +const name = 'My Token'; +const symbol = 'MTKN'; +const decimals = 18n; + +async function fixture() { + const [holder, recipient, spender, other, ...accounts] = await ethers.getSigners(); + return { holder, recipient, spender, other, accounts }; +} + +describe('ERC4626', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('inherit decimals if from asset', async function () { + for (const decimals of [0n, 9n, 12n, 18n, 36n]) { + const token = await ethers.deployContract('$ERC20DecimalsMock', ['', '', decimals]); + const vault = await ethers.deployContract('$ERC4626', ['', '', token]); + expect(await vault.decimals()).to.equal(decimals); + } + }); + + it('asset has not yet been created', async function () { + const vault = await ethers.deployContract('$ERC4626', ['', '', this.other.address]); + expect(await vault.decimals()).to.equal(decimals); + }); + + it('underlying excess decimals', async function () { + const token = await ethers.deployContract('$ERC20ExcessDecimalsMock'); + const vault = await ethers.deployContract('$ERC4626', ['', '', token]); + expect(await vault.decimals()).to.equal(decimals); + }); + + it('decimals overflow', async function () { + for (const offset of [243n, 250n, 255n]) { + const token = await ethers.deployContract('$ERC20DecimalsMock', ['', '', decimals]); + const vault = await ethers.deployContract('$ERC4626OffsetMock', ['', '', token, offset]); + await expect(vault.decimals()).to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW); + } + }); + + describe('reentrancy', function () { + const reenterType = Enum('No', 'Before', 'After'); + + const value = 1_000_000_000_000_000_000n; + const reenterValue = 1_000_000_000n; + + beforeEach(async function () { + // Use offset 1 so the rate is not 1:1 and we can't possibly confuse assets and shares + const token = await ethers.deployContract('$ERC20Reentrant'); + const vault = await ethers.deployContract('$ERC4626OffsetMock', ['', '', token, 1n]); + // Funds and approval for tests + await token.$_mint(this.holder, value); + await token.$_mint(this.other, value); + await token.$_approve(this.holder, vault, ethers.MaxUint256); + await token.$_approve(this.other, vault, ethers.MaxUint256); + await token.$_approve(token, vault, ethers.MaxUint256); + + Object.assign(this, { token, vault }); + }); + + // 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 this.token.$_mint(this.token, reenterValue); + + // Schedules a reentrancy from the token contract + await this.token.scheduleReenter( + reenterType.Before, + this.vault, + this.vault.interface.encodeFunctionData('deposit', [reenterValue, this.holder.address]), + ); + + // Initial share price + const sharesForDeposit = await this.vault.previewDeposit(value); + const sharesForReenter = await this.vault.previewDeposit(reenterValue); + + await expect(this.vault.connect(this.holder).deposit(value, this.holder)) + // Deposit normally, reentering before the internal `_update` + .to.emit(this.vault, 'Deposit') + .withArgs(this.holder, this.holder, value, sharesForDeposit) + // Reentrant deposit event → uses the same price + .to.emit(this.vault, 'Deposit') + .withArgs(this.token, this.holder, reenterValue, sharesForReenter); + + // Assert prices is kept + expect(await this.vault.previewDeposit(value)).to.equal(sharesForDeposit); + }); + + // 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 this.vault.connect(this.holder).deposit(value, this.holder); + await this.vault.connect(this.other).deposit(reenterValue, this.token); + + // Schedules a reentrancy from the token contract + await this.token.scheduleReenter( + reenterType.After, + this.vault, + this.vault.interface.encodeFunctionData('withdraw', [reenterValue, this.holder.address, this.token.target]), + ); + + // Initial share price + const sharesForWithdraw = await this.vault.previewWithdraw(value); + const sharesForReenter = await this.vault.previewWithdraw(reenterValue); + + // Do withdraw normally, triggering the _afterTokenTransfer hook + await expect(this.vault.connect(this.holder).withdraw(value, this.holder, this.holder)) + // Main withdraw event + .to.emit(this.vault, 'Withdraw') + .withArgs(this.holder, this.holder, this.holder, value, sharesForWithdraw) + // Reentrant withdraw event → uses the same price + .to.emit(this.vault, 'Withdraw') + .withArgs(this.token, this.holder, this.token, reenterValue, sharesForReenter); + + // Assert price is kept + expect(await this.vault.previewWithdraw(value)).to.equal(sharesForWithdraw); + }); + + // Donate newly minted tokens to the vault during the reentrancy causes the share price to increase. + // Still, the deposit that trigger the reentrancy 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 reentrancy does not affect deposit', async function () { + // Schedules a reentrancy from the token contract that mess up the share price + await this.token.scheduleReenter( + reenterType.Before, + this.token, + this.token.interface.encodeFunctionData('$_mint', [this.vault.target, reenterValue]), + ); + + // Price before + const sharesBefore = await this.vault.previewDeposit(value); + + // Deposit, reentering before the internal `_update` + await expect(this.vault.connect(this.holder).deposit(value, this.holder)) + // Price is as previewed + .to.emit(this.vault, 'Deposit') + .withArgs(this.holder, this.holder, value, sharesBefore); + + // Price was modified during reentrancy + expect(await this.vault.previewDeposit(value)).to.lt(sharesBefore); + }); + + // Burn some tokens from the vault during the reentrancy causes the share price to drop. + // Still, the withdraw that trigger the reentrancy 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 reentrancy does not affect withdraw', async function () { + await this.vault.connect(this.holder).deposit(value, this.holder); + await this.vault.connect(this.other).deposit(value, this.other); + + // Schedules a reentrancy from the token contract that mess up the share price + await this.token.scheduleReenter( + reenterType.After, + this.token, + this.token.interface.encodeFunctionData('$_burn', [this.vault.target, reenterValue]), + ); + + // Price before + const sharesBefore = await this.vault.previewWithdraw(value); + + // Withdraw, triggering the _afterTokenTransfer hook + await expect(this.vault.connect(this.holder).withdraw(value, this.holder, this.holder)) + // Price is as previewed + .to.emit(this.vault, 'Withdraw') + .withArgs(this.holder, this.holder, this.holder, value, sharesBefore); + + // Price was modified during reentrancy + expect(await this.vault.previewWithdraw(value)).to.gt(sharesBefore); + }); + }); + + describe('limits', function () { + beforeEach(async function () { + const token = await ethers.deployContract('$ERC20DecimalsMock', [name, symbol, decimals]); + const vault = await ethers.deployContract('$ERC4626LimitsMock', ['', '', token]); + + Object.assign(this, { token, vault }); + }); + + it('reverts on deposit() above max deposit', async function () { + const maxDeposit = await this.vault.maxDeposit(this.holder); + await expect(this.vault.connect(this.holder).deposit(maxDeposit + 1n, this.recipient)) + .to.be.revertedWithCustomError(this.vault, 'ERC4626ExceededMaxDeposit') + .withArgs(this.recipient, maxDeposit + 1n, maxDeposit); + }); + + it('reverts on mint() above max mint', async function () { + const maxMint = await this.vault.maxMint(this.holder); + + await expect(this.vault.connect(this.holder).mint(maxMint + 1n, this.recipient)) + .to.be.revertedWithCustomError(this.vault, 'ERC4626ExceededMaxMint') + .withArgs(this.recipient, maxMint + 1n, maxMint); + }); + + it('reverts on withdraw() above max withdraw', async function () { + const maxWithdraw = await this.vault.maxWithdraw(this.holder); + + await expect(this.vault.connect(this.holder).withdraw(maxWithdraw + 1n, this.recipient, this.holder)) + .to.be.revertedWithCustomError(this.vault, 'ERC4626ExceededMaxWithdraw') + .withArgs(this.holder, maxWithdraw + 1n, maxWithdraw); + }); + + it('reverts on redeem() above max redeem', async function () { + const maxRedeem = await this.vault.maxRedeem(this.holder); + + await expect(this.vault.connect(this.holder).redeem(maxRedeem + 1n, this.recipient, this.holder)) + .to.be.revertedWithCustomError(this.vault, 'ERC4626ExceededMaxRedeem') + .withArgs(this.holder, maxRedeem + 1n, maxRedeem); + }); + }); + + for (const offset of [0n, 6n, 18n]) { + const parseToken = token => token * 10n ** decimals; + const parseShare = share => share * 10n ** (decimals + offset); + + const virtualAssets = 1n; + const virtualShares = 10n ** offset; + + describe(`offset: ${offset}`, function () { + beforeEach(async function () { + const token = await ethers.deployContract('$ERC20DecimalsMock', [name, symbol, decimals]); + const vault = await ethers.deployContract('$ERC4626OffsetMock', [name + ' Vault', symbol + 'V', token, offset]); + + await token.$_mint(this.holder, ethers.MaxUint256 / 2n); // 50% of maximum + await token.$_approve(this.holder, vault, ethers.MaxUint256); + await vault.$_approve(this.holder, this.spender, ethers.MaxUint256); + + Object.assign(this, { token, vault }); + }); + + it('metadata', async function () { + expect(await this.vault.name()).to.equal(name + ' Vault'); + expect(await this.vault.symbol()).to.equal(symbol + 'V'); + expect(await this.vault.decimals()).to.equal(decimals + offset); + expect(await this.vault.asset()).to.equal(this.token); + }); + + describe('empty vault: no assets & no shares', function () { + it('status', async function () { + expect(await this.vault.totalAssets()).to.equal(0n); + }); + + it('deposit', async function () { + expect(await this.vault.maxDeposit(this.holder)).to.equal(ethers.MaxUint256); + expect(await this.vault.previewDeposit(parseToken(1n))).to.equal(parseShare(1n)); + + const tx = this.vault.connect(this.holder).deposit(parseToken(1n), this.recipient); + + await expect(tx).to.changeTokenBalances( + this.token, + [this.holder, this.vault], + [-parseToken(1n), parseToken(1n)], + ); + await expect(tx).to.changeTokenBalance(this.vault, this.recipient, parseShare(1n)); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.vault, parseToken(1n)) + .to.emit(this.vault, 'Transfer') + .withArgs(ethers.ZeroAddress, this.recipient, parseShare(1n)) + .to.emit(this.vault, 'Deposit') + .withArgs(this.holder, this.recipient, parseToken(1n), parseShare(1n)); + }); + + it('mint', async function () { + expect(await this.vault.maxMint(this.holder)).to.equal(ethers.MaxUint256); + expect(await this.vault.previewMint(parseShare(1n))).to.equal(parseToken(1n)); + + const tx = this.vault.connect(this.holder).mint(parseShare(1n), this.recipient); + + await expect(tx).to.changeTokenBalances( + this.token, + [this.holder, this.vault], + [-parseToken(1n), parseToken(1n)], + ); + await expect(tx).to.changeTokenBalance(this.vault, this.recipient, parseShare(1n)); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.vault, parseToken(1n)) + .to.emit(this.vault, 'Transfer') + .withArgs(ethers.ZeroAddress, this.recipient, parseShare(1n)) + .to.emit(this.vault, 'Deposit') + .withArgs(this.holder, this.recipient, parseToken(1n), parseShare(1n)); + }); + + it('withdraw', async function () { + expect(await this.vault.maxWithdraw(this.holder)).to.equal(0n); + expect(await this.vault.previewWithdraw(0n)).to.equal(0n); + + const tx = this.vault.connect(this.holder).withdraw(0n, this.recipient, this.holder); + + await expect(tx).to.changeTokenBalances(this.token, [this.vault, this.recipient], [0n, 0n]); + await expect(tx).to.changeTokenBalance(this.vault, this.holder, 0n); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.vault, this.recipient, 0n) + .to.emit(this.vault, 'Transfer') + .withArgs(this.holder, ethers.ZeroAddress, 0n) + .to.emit(this.vault, 'Withdraw') + .withArgs(this.holder, this.recipient, this.holder, 0n, 0n); + }); + + it('redeem', async function () { + expect(await this.vault.maxRedeem(this.holder)).to.equal(0n); + expect(await this.vault.previewRedeem(0n)).to.equal(0n); + + const tx = this.vault.connect(this.holder).redeem(0n, this.recipient, this.holder); + + await expect(tx).to.changeTokenBalances(this.token, [this.vault, this.recipient], [0n, 0n]); + await expect(tx).to.changeTokenBalance(this.vault, this.holder, 0n); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.vault, this.recipient, 0n) + .to.emit(this.vault, 'Transfer') + .withArgs(this.holder, ethers.ZeroAddress, 0n) + .to.emit(this.vault, 'Withdraw') + .withArgs(this.holder, this.recipient, this.holder, 0n, 0n); + }); + }); + + 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, parseToken(1n)); + }); + + it('status', async function () { + expect(await this.vault.totalSupply()).to.equal(0n); + expect(await this.vault.totalAssets()).to.equal(parseToken(1n)); + }); + + /** + * | 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()) + virtualAssets; + const effectiveShares = (await this.vault.totalSupply()) + virtualShares; + + const depositAssets = parseToken(1n); + const expectedShares = (depositAssets * effectiveShares) / effectiveAssets; + + expect(await this.vault.maxDeposit(this.holder)).to.equal(ethers.MaxUint256); + expect(await this.vault.previewDeposit(depositAssets)).to.equal(expectedShares); + + const tx = this.vault.connect(this.holder).deposit(depositAssets, this.recipient); + + await expect(tx).to.changeTokenBalances( + this.token, + [this.holder, this.vault], + [-depositAssets, depositAssets], + ); + await expect(tx).to.changeTokenBalance(this.vault, this.recipient, expectedShares); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.vault, depositAssets) + .to.emit(this.vault, 'Transfer') + .withArgs(ethers.ZeroAddress, this.recipient, expectedShares) + .to.emit(this.vault, 'Deposit') + .withArgs(this.holder, this.recipient, depositAssets, 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()) + virtualAssets; + const effectiveShares = (await this.vault.totalSupply()) + virtualShares; + + const mintShares = parseShare(1n); + const expectedAssets = (mintShares * effectiveAssets) / effectiveShares; + + expect(await this.vault.maxMint(this.holder)).to.equal(ethers.MaxUint256); + expect(await this.vault.previewMint(mintShares)).to.equal(expectedAssets); + + const tx = this.vault.connect(this.holder).mint(mintShares, this.recipient); + + await expect(tx).to.changeTokenBalances( + this.token, + [this.holder, this.vault], + [-expectedAssets, expectedAssets], + ); + await expect(tx).to.changeTokenBalance(this.vault, this.recipient, mintShares); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.vault, expectedAssets) + .to.emit(this.vault, 'Transfer') + .withArgs(ethers.ZeroAddress, this.recipient, mintShares) + .to.emit(this.vault, 'Deposit') + .withArgs(this.holder, this.recipient, expectedAssets, mintShares); + }); + + it('withdraw', async function () { + expect(await this.vault.maxWithdraw(this.holder)).to.equal(0n); + expect(await this.vault.previewWithdraw(0n)).to.equal(0n); + + const tx = this.vault.connect(this.holder).withdraw(0n, this.recipient, this.holder); + + await expect(tx).to.changeTokenBalances(this.token, [this.vault, this.recipient], [0n, 0n]); + await expect(tx).to.changeTokenBalance(this.vault, this.holder, 0n); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.vault, this.recipient, 0n) + .to.emit(this.vault, 'Transfer') + .withArgs(this.holder, ethers.ZeroAddress, 0n) + .to.emit(this.vault, 'Withdraw') + .withArgs(this.holder, this.recipient, this.holder, 0n, 0n); + }); + + it('redeem', async function () { + expect(await this.vault.maxRedeem(this.holder)).to.equal(0n); + expect(await this.vault.previewRedeem(0n)).to.equal(0n); + + const tx = this.vault.connect(this.holder).redeem(0n, this.recipient, this.holder); + + await expect(tx).to.changeTokenBalances(this.token, [this.vault, this.recipient], [0n, 0n]); + await expect(tx).to.changeTokenBalance(this.vault, this.holder, 0n); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.vault, this.recipient, 0n) + .to.emit(this.vault, 'Transfer') + .withArgs(this.holder, ethers.ZeroAddress, 0n) + .to.emit(this.vault, 'Withdraw') + .withArgs(this.holder, this.recipient, this.holder, 0n, 0n); + }); + }); + + 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, parseToken(1n)); + await this.vault.$_mint(this.holder, parseShare(100n)); + }); + + it('status', async function () { + expect(await this.vault.totalSupply()).to.equal(parseShare(100n)); + expect(await this.vault.totalAssets()).to.equal(parseToken(1n)); + }); + + /** + * | 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()) + virtualAssets; + const effectiveShares = (await this.vault.totalSupply()) + virtualShares; + + const depositAssets = parseToken(1n); + const expectedShares = (depositAssets * effectiveShares) / effectiveAssets; + + expect(await this.vault.maxDeposit(this.holder)).to.equal(ethers.MaxUint256); + expect(await this.vault.previewDeposit(depositAssets)).to.equal(expectedShares); + + const tx = this.vault.connect(this.holder).deposit(depositAssets, this.recipient); + + await expect(tx).to.changeTokenBalances( + this.token, + [this.holder, this.vault], + [-depositAssets, depositAssets], + ); + await expect(tx).to.changeTokenBalance(this.vault, this.recipient, expectedShares); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.vault, depositAssets) + .to.emit(this.vault, 'Transfer') + .withArgs(ethers.ZeroAddress, this.recipient, expectedShares) + .to.emit(this.vault, 'Deposit') + .withArgs(this.holder, this.recipient, depositAssets, 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()) + virtualAssets; + const effectiveShares = (await this.vault.totalSupply()) + virtualShares; + + const mintShares = parseShare(1n); + const expectedAssets = (mintShares * effectiveAssets) / effectiveShares + 1n; // add for the rounding + + expect(await this.vault.maxMint(this.holder)).to.equal(ethers.MaxUint256); + expect(await this.vault.previewMint(mintShares)).to.equal(expectedAssets); + + const tx = this.vault.connect(this.holder).mint(mintShares, this.recipient); + + await expect(tx).to.changeTokenBalances( + this.token, + [this.holder, this.vault], + [-expectedAssets, expectedAssets], + ); + await expect(tx).to.changeTokenBalance(this.vault, this.recipient, mintShares); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.vault, expectedAssets) + .to.emit(this.vault, 'Transfer') + .withArgs(ethers.ZeroAddress, this.recipient, mintShares) + .to.emit(this.vault, 'Deposit') + .withArgs(this.holder, this.recipient, expectedAssets, mintShares); + }); + + it('withdraw', async function () { + const effectiveAssets = (await this.vault.totalAssets()) + virtualAssets; + const effectiveShares = (await this.vault.totalSupply()) + virtualShares; + + const withdrawAssets = parseToken(1n); + const expectedShares = (withdrawAssets * effectiveShares) / effectiveAssets + 1n; // add for the rounding + + expect(await this.vault.maxWithdraw(this.holder)).to.equal(withdrawAssets); + expect(await this.vault.previewWithdraw(withdrawAssets)).to.equal(expectedShares); + + const tx = this.vault.connect(this.holder).withdraw(withdrawAssets, this.recipient, this.holder); + + await expect(tx).to.changeTokenBalances( + this.token, + [this.vault, this.recipient], + [-withdrawAssets, withdrawAssets], + ); + await expect(tx).to.changeTokenBalance(this.vault, this.holder, -expectedShares); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.vault, this.recipient, withdrawAssets) + .to.emit(this.vault, 'Transfer') + .withArgs(this.holder, ethers.ZeroAddress, expectedShares) + .to.emit(this.vault, 'Withdraw') + .withArgs(this.holder, this.recipient, this.holder, withdrawAssets, expectedShares); + }); + + it('withdraw with approval', async function () { + const assets = await this.vault.previewWithdraw(parseToken(1n)); + + await expect(this.vault.connect(this.other).withdraw(parseToken(1n), this.recipient, this.holder)) + .to.be.revertedWithCustomError(this.vault, 'ERC20InsufficientAllowance') + .withArgs(this.other, 0n, assets); + + await expect(this.vault.connect(this.spender).withdraw(parseToken(1n), this.recipient, this.holder)).to.not.be + .reverted; + }); + + it('redeem', async function () { + const effectiveAssets = (await this.vault.totalAssets()) + virtualAssets; + const effectiveShares = (await this.vault.totalSupply()) + virtualShares; + + const redeemShares = parseShare(100n); + const expectedAssets = (redeemShares * effectiveAssets) / effectiveShares; + + expect(await this.vault.maxRedeem(this.holder)).to.equal(redeemShares); + expect(await this.vault.previewRedeem(redeemShares)).to.equal(expectedAssets); + + const tx = this.vault.connect(this.holder).redeem(redeemShares, this.recipient, this.holder); + + await expect(tx).to.changeTokenBalances( + this.token, + [this.vault, this.recipient], + [-expectedAssets, expectedAssets], + ); + await expect(tx).to.changeTokenBalance(this.vault, this.holder, -redeemShares); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.vault, this.recipient, expectedAssets) + .to.emit(this.vault, 'Transfer') + .withArgs(this.holder, ethers.ZeroAddress, redeemShares) + .to.emit(this.vault, 'Withdraw') + .withArgs(this.holder, this.recipient, this.holder, expectedAssets, redeemShares); + }); + + it('redeem with approval', async function () { + await expect(this.vault.connect(this.other).redeem(parseShare(100n), this.recipient, this.holder)) + .to.be.revertedWithCustomError(this.vault, 'ERC20InsufficientAllowance') + .withArgs(this.other, 0n, parseShare(100n)); + + await expect(this.vault.connect(this.spender).redeem(parseShare(100n), this.recipient, this.holder)).to.not.be + .reverted; + }); + }); + }); + } + + describe('ERC4626Fees', function () { + const feeBasisPoints = 500n; // 5% + const valueWithoutFees = 10_000n; + const fees = (valueWithoutFees * feeBasisPoints) / 10_000n; + const valueWithFees = valueWithoutFees + fees; + + describe('input fees', function () { + beforeEach(async function () { + const token = await ethers.deployContract('$ERC20DecimalsMock', [name, symbol, 18n]); + const vault = await ethers.deployContract('$ERC4626FeesMock', [ + '', + '', + token, + feeBasisPoints, + this.other, + 0n, + ethers.ZeroAddress, + ]); + + await token.$_mint(this.holder, ethers.MaxUint256 / 2n); + await token.$_approve(this.holder, vault, ethers.MaxUint256 / 2n); + + Object.assign(this, { token, vault }); + }); + + it('deposit', async function () { + expect(await this.vault.previewDeposit(valueWithFees)).to.equal(valueWithoutFees); + this.tx = this.vault.connect(this.holder).deposit(valueWithFees, this.recipient); + }); + + it('mint', async function () { + expect(await this.vault.previewMint(valueWithoutFees)).to.equal(valueWithFees); + this.tx = this.vault.connect(this.holder).mint(valueWithoutFees, this.recipient); + }); + + afterEach(async function () { + await expect(this.tx).to.changeTokenBalances( + this.token, + [this.holder, this.vault, this.other], + [-valueWithFees, valueWithoutFees, fees], + ); + await expect(this.tx).to.changeTokenBalance(this.vault, this.recipient, valueWithoutFees); + await expect(this.tx) + // get total + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.vault, valueWithFees) + // redirect fees + .to.emit(this.token, 'Transfer') + .withArgs(this.vault, this.other, fees) + // mint shares + .to.emit(this.vault, 'Transfer') + .withArgs(ethers.ZeroAddress, this.recipient, valueWithoutFees) + // deposit event + .to.emit(this.vault, 'Deposit') + .withArgs(this.holder, this.recipient, valueWithFees, valueWithoutFees); + }); + }); + + describe('output fees', function () { + beforeEach(async function () { + const token = await ethers.deployContract('$ERC20DecimalsMock', [name, symbol, 18n]); + const vault = await ethers.deployContract('$ERC4626FeesMock', [ + '', + '', + token, + 0n, + ethers.ZeroAddress, + feeBasisPoints, + this.other, + ]); + + await token.$_mint(vault, ethers.MaxUint256 / 2n); + await vault.$_mint(this.holder, ethers.MaxUint256 / 2n); + + Object.assign(this, { token, vault }); + }); + + it('redeem', async function () { + expect(await this.vault.previewRedeem(valueWithFees)).to.equal(valueWithoutFees); + this.tx = this.vault.connect(this.holder).redeem(valueWithFees, this.recipient, this.holder); + }); + + it('withdraw', async function () { + expect(await this.vault.previewWithdraw(valueWithoutFees)).to.equal(valueWithFees); + this.tx = this.vault.connect(this.holder).withdraw(valueWithoutFees, this.recipient, this.holder); + }); + + afterEach(async function () { + await expect(this.tx).to.changeTokenBalances( + this.token, + [this.vault, this.recipient, this.other], + [-valueWithFees, valueWithoutFees, fees], + ); + await expect(this.tx).to.changeTokenBalance(this.vault, this.holder, -valueWithFees); + await expect(this.tx) + // withdraw principal + .to.emit(this.token, 'Transfer') + .withArgs(this.vault, this.recipient, valueWithoutFees) + // redirect fees + .to.emit(this.token, 'Transfer') + .withArgs(this.vault, this.other, fees) + // mint shares + .to.emit(this.vault, 'Transfer') + .withArgs(this.holder, ethers.ZeroAddress, valueWithFees) + // withdraw event + .to.emit(this.vault, 'Withdraw') + .withArgs(this.holder, this.recipient, this.holder, valueWithoutFees, 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 + const [alice, bruce] = this.accounts; + const token = await ethers.deployContract('$ERC20DecimalsMock', [name, symbol, 18n]); + const vault = await ethers.deployContract('$ERC4626', ['', '', token]); + + await token.$_mint(alice, 4000n); + await token.$_mint(bruce, 7001n); + await token.connect(alice).approve(vault, 4000n); + await token.connect(bruce).approve(vault, 7001n); + + // 1. Alice mints 2000 shares (costs 2000 tokens) + await expect(vault.connect(alice).mint(2000n, alice)) + .to.emit(token, 'Transfer') + .withArgs(alice, vault, 2000n) + .to.emit(vault, 'Transfer') + .withArgs(ethers.ZeroAddress, alice, 2000n); + + expect(await vault.previewDeposit(2000n)).to.equal(2000n); + expect(await vault.balanceOf(alice)).to.equal(2000n); + expect(await vault.balanceOf(bruce)).to.equal(0n); + expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(2000n); + expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(0n); + expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(2000n); + expect(await vault.totalSupply()).to.equal(2000n); + expect(await vault.totalAssets()).to.equal(2000n); + + // 2. Bruce deposits 4000 tokens (mints 4000 shares) + await expect(vault.connect(bruce).mint(4000n, bruce)) + .to.emit(token, 'Transfer') + .withArgs(bruce, vault, 4000n) + .to.emit(vault, 'Transfer') + .withArgs(ethers.ZeroAddress, bruce, 4000n); + + expect(await vault.previewDeposit(4000n)).to.equal(4000n); + expect(await vault.balanceOf(alice)).to.equal(2000n); + expect(await vault.balanceOf(bruce)).to.equal(4000n); + expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(2000n); + expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(4000n); + expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(6000n); + expect(await vault.totalSupply()).to.equal(6000n); + expect(await vault.totalAssets()).to.equal(6000n); + + // 3. Vault mutates by +3000 tokens (simulated yield returned from strategy) + await token.$_mint(vault, 3000n); + + expect(await vault.balanceOf(alice)).to.equal(2000n); + expect(await vault.balanceOf(bruce)).to.equal(4000n); + expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(2999n); // used to be 3000, but virtual assets/shares captures part of the yield + expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(5999n); // used to be 6000, but virtual assets/shares captures part of the yield + expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(6000n); + expect(await vault.totalSupply()).to.equal(6000n); + expect(await vault.totalAssets()).to.equal(9000n); + + // 4. Alice deposits 2000 tokens (mints 1333 shares) + await expect(vault.connect(alice).deposit(2000n, alice)) + .to.emit(token, 'Transfer') + .withArgs(alice, vault, 2000n) + .to.emit(vault, 'Transfer') + .withArgs(ethers.ZeroAddress, alice, 1333n); + + expect(await vault.balanceOf(alice)).to.equal(3333n); + expect(await vault.balanceOf(bruce)).to.equal(4000n); + expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(4999n); + expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(6000n); + expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(7333n); + expect(await vault.totalSupply()).to.equal(7333n); + expect(await vault.totalAssets()).to.equal(11000n); + + // 5. Bruce mints 2000 shares (costs 3001 assets) + // NOTE: Bruce's assets spent got rounded towards infinity + // NOTE: Alices's vault assets got rounded towards infinity + await expect(vault.connect(bruce).mint(2000n, bruce)) + .to.emit(token, 'Transfer') + .withArgs(bruce, vault, 3000n) + .to.emit(vault, 'Transfer') + .withArgs(ethers.ZeroAddress, bruce, 2000n); + + expect(await vault.balanceOf(alice)).to.equal(3333n); + expect(await vault.balanceOf(bruce)).to.equal(6000n); + expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(4999n); // used to be 5000 + expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(9000n); + expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(9333n); + expect(await vault.totalSupply()).to.equal(9333n); + expect(await vault.totalAssets()).to.equal(14000n); // used to be 14001 + + // 6. Vault mutates by +3000 tokens + // NOTE: Vault holds 17001 tokens, but sum of assetsOf() is 17000. + await token.$_mint(vault, 3000n); + + expect(await vault.balanceOf(alice)).to.equal(3333n); + expect(await vault.balanceOf(bruce)).to.equal(6000n); + expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(6070n); // used to be 6071 + expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(10928n); // used to be 10929 + expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(9333n); + expect(await vault.totalSupply()).to.equal(9333n); + expect(await vault.totalAssets()).to.equal(17000n); // used to be 17001 + + // 7. Alice redeem 1333 shares (2428 assets) + await expect(vault.connect(alice).redeem(1333n, alice, alice)) + .to.emit(vault, 'Transfer') + .withArgs(alice, ethers.ZeroAddress, 1333n) + .to.emit(token, 'Transfer') + .withArgs(vault, alice, 2427n); // used to be 2428 + + expect(await vault.balanceOf(alice)).to.equal(2000n); + expect(await vault.balanceOf(bruce)).to.equal(6000n); + expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(3643n); + expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(10929n); + expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(8000n); + expect(await vault.totalSupply()).to.equal(8000n); + expect(await vault.totalAssets()).to.equal(14573n); + + // 8. Bruce withdraws 2929 assets (1608 shares) + await expect(vault.connect(bruce).withdraw(2929n, bruce, bruce)) + .to.emit(vault, 'Transfer') + .withArgs(bruce, ethers.ZeroAddress, 1608n) + .to.emit(token, 'Transfer') + .withArgs(vault, bruce, 2929n); + + expect(await vault.balanceOf(alice)).to.equal(2000n); + expect(await vault.balanceOf(bruce)).to.equal(4392n); + expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(3643n); + expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(8000n); + expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(6392n); + expect(await vault.totalSupply()).to.equal(6392n); + expect(await vault.totalAssets()).to.equal(11644n); + + // 9. Alice withdraws 3643 assets (2000 shares) + // NOTE: Bruce's assets have been rounded back towards infinity + await expect(vault.connect(alice).withdraw(3643n, alice, alice)) + .to.emit(vault, 'Transfer') + .withArgs(alice, ethers.ZeroAddress, 2000n) + .to.emit(token, 'Transfer') + .withArgs(vault, alice, 3643n); + + expect(await vault.balanceOf(alice)).to.equal(0n); + expect(await vault.balanceOf(bruce)).to.equal(4392n); + expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(0n); + expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(8000n); // used to be 8001 + expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(4392n); + expect(await vault.totalSupply()).to.equal(4392n); + expect(await vault.totalAssets()).to.equal(8001n); + + // 10. Bruce redeem 4392 shares (8001 tokens) + await expect(vault.connect(bruce).redeem(4392n, bruce, bruce)) + .to.emit(vault, 'Transfer') + .withArgs(bruce, ethers.ZeroAddress, 4392n) + .to.emit(token, 'Transfer') + .withArgs(vault, bruce, 8000n); // used to be 8001 + + expect(await vault.balanceOf(alice)).to.equal(0n); + expect(await vault.balanceOf(bruce)).to.equal(0n); + expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(0n); + expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(0n); + expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(0n); + expect(await vault.totalSupply()).to.equal(0n); + expect(await vault.totalAssets()).to.equal(1n); // used to be 0 + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20Bridgeable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20Bridgeable.test.js new file mode 100644 index 0000000..06c3bb2 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20Bridgeable.test.js @@ -0,0 +1,89 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { shouldBehaveLikeERC20 } = require('../ERC20.behavior.js'); +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); + +const name = 'My Token'; +const symbol = 'MTKN'; +const initialSupply = 100n; + +async function fixture() { + const [other, bridge, ...accounts] = await ethers.getSigners(); + + const token = await ethers.deployContract('$ERC20BridgeableMock', [name, symbol, bridge]); + await token.$_mint(accounts[0], initialSupply); + + return { bridge, other, accounts, token }; +} + +describe('ERC20Bridgeable', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('onlyTokenBridgeFn', function () { + it('reverts when called by non-bridge', async function () { + await expect(this.token.onlyTokenBridgeFn()).to.be.revertedWithCustomError(this.token, 'OnlyTokenBridge'); + }); + + it('does not revert when called by bridge', async function () { + await expect(this.token.connect(this.bridge).onlyTokenBridgeFn()) + .to.emit(this.token, 'OnlyTokenBridgeFnCalled') + .withArgs(this.bridge); + }); + }); + + describe('crosschainMint', function () { + it('reverts when called by non-bridge', async function () { + await expect(this.token.crosschainMint(this.other, 100n)).to.be.revertedWithCustomError( + this.token, + 'OnlyTokenBridge', + ); + }); + + it('mints amount provided by the bridge when calling crosschainMint', async function () { + const amount = 100n; + await expect(this.token.connect(this.bridge).crosschainMint(this.other, amount)) + .to.emit(this.token, 'CrosschainMint') + .withArgs(this.other, amount, this.bridge) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.other, amount); + + await expect(this.token.balanceOf(this.other)).to.eventually.equal(amount); + }); + }); + + describe('crosschainBurn', function () { + it('reverts when called by non-bridge', async function () { + await expect(this.token.crosschainBurn(this.other, 100n)).to.be.revertedWithCustomError( + this.token, + 'OnlyTokenBridge', + ); + }); + + it('burns amount provided by the bridge when calling crosschainBurn', async function () { + const amount = 100n; + await this.token.$_mint(this.other, amount); + + await expect(this.token.connect(this.bridge).crosschainBurn(this.other, amount)) + .to.emit(this.token, 'CrosschainBurn') + .withArgs(this.other, amount, this.bridge) + .to.emit(this.token, 'Transfer') + .withArgs(this.other, ethers.ZeroAddress, amount); + + await expect(this.token.balanceOf(this.other)).to.eventually.equal(0); + }); + }); + + describe('ERC165', function () { + shouldSupportInterfaces({ + ERC7802: ['crosschainMint(address,uint256)', 'crosschainBurn(address,uint256)'], + }); + }); + + describe('ERC20 behavior', function () { + shouldBehaveLikeERC20(initialSupply); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20TemporaryApproval.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20TemporaryApproval.test.js new file mode 100644 index 0000000..a1f6362 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20TemporaryApproval.test.js @@ -0,0 +1,142 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { max, min } = require('../../../helpers/math.js'); + +const { shouldBehaveLikeERC20 } = require('../ERC20.behavior.js'); + +const name = 'My Token'; +const symbol = 'MTKN'; +const initialSupply = 100n; + +async function fixture() { + // this.accounts is used by shouldBehaveLikeERC20 + const accounts = await ethers.getSigners(); + const [holder, recipient, other] = accounts; + + const token = await ethers.deployContract('$ERC20TemporaryApproval', [name, symbol]); + await token.$_mint(holder, initialSupply); + + const spender = await ethers.deployContract('$Address'); + const batch = await ethers.deployContract('BatchCaller'); + const getter = await ethers.deployContract('ERC20GetterHelper'); + + return { accounts, holder, recipient, other, token, spender, batch, getter }; +} + +describe('ERC20TemporaryApproval', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeERC20(initialSupply); + + describe('setting and spending temporary allowance', function () { + beforeEach(async function () { + await this.token.connect(this.holder).transfer(this.batch, initialSupply); + }); + + for (let { + description, + persistentAllowance, + temporaryAllowance, + amount, + temporaryExpected, + persistentExpected, + } of [ + { description: 'can set temporary allowance', temporaryAllowance: 42n }, + { + description: 'can set temporary allowance on top of persistent allowance', + temporaryAllowance: 42n, + persistentAllowance: 17n, + }, + { description: 'support allowance overflow', temporaryAllowance: ethers.MaxUint256, persistentAllowance: 17n }, + { description: 'consuming temporary allowance alone', temporaryAllowance: 42n, amount: 2n }, + { + description: 'fallback to persistent allowance if temporary allowance is not sufficient', + temporaryAllowance: 42n, + persistentAllowance: 17n, + amount: 50n, + }, + { + description: 'do not reduce infinite temporary allowance #1', + temporaryAllowance: ethers.MaxUint256, + amount: 50n, + temporaryExpected: ethers.MaxUint256, + }, + { + description: 'do not reduce infinite temporary allowance #2', + temporaryAllowance: 17n, + persistentAllowance: ethers.MaxUint256, + amount: 50n, + temporaryExpected: ethers.MaxUint256, + persistentExpected: ethers.MaxUint256, + }, + ]) { + persistentAllowance ??= 0n; + temporaryAllowance ??= 0n; + amount ??= 0n; + temporaryExpected ??= min(persistentAllowance + temporaryAllowance - amount, ethers.MaxUint256); + persistentExpected ??= persistentAllowance - max(amount - temporaryAllowance, 0n); + + it(description, async function () { + await expect( + this.batch.execute( + [ + persistentAllowance && { + target: this.token, + value: 0n, + data: this.token.interface.encodeFunctionData('approve', [this.spender.target, persistentAllowance]), + }, + temporaryAllowance && { + target: this.token, + value: 0n, + data: this.token.interface.encodeFunctionData('temporaryApprove', [ + this.spender.target, + temporaryAllowance, + ]), + }, + amount && { + target: this.spender, + value: 0n, + data: this.spender.interface.encodeFunctionData('$functionCall', [ + this.token.target, + this.token.interface.encodeFunctionData('transferFrom', [ + this.batch.target, + this.recipient.address, + amount, + ]), + ]), + }, + { + target: this.getter, + value: 0n, + data: this.getter.interface.encodeFunctionData('allowance', [ + this.token.target, + this.batch.target, + this.spender.target, + ]), + }, + ].filter(Boolean), + ), + ) + .to.emit(this.getter, 'ERC20Allowance') + .withArgs(this.token, this.batch, this.spender, temporaryExpected); + + expect(await this.token.allowance(this.batch, this.spender)).to.equal(persistentExpected); + }); + } + + it('reverts when the recipient is the zero address', async function () { + await expect(this.token.connect(this.holder).temporaryApprove(ethers.ZeroAddress, 1n)) + .to.be.revertedWithCustomError(this.token, 'ERC20InvalidSpender') + .withArgs(ethers.ZeroAddress); + }); + + it('reverts when the token owner is the zero address', async function () { + await expect(this.token.$_temporaryApprove(ethers.ZeroAddress, this.recipient, 1n)) + .to.be.revertedWithCustomError(this.token, 'ERC20InvalidApprover') + .withArgs(ethers.ZeroAddress); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js new file mode 100644 index 0000000..0ae9463 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js @@ -0,0 +1,463 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const name = 'ERC20Mock'; +const symbol = 'ERC20Mock'; +const value = 100n; +const data = '0x12345678'; + +async function fixture() { + const [hasNoCode, owner, receiver, spender, other] = await ethers.getSigners(); + + const mock = await ethers.deployContract('$SafeERC20'); + const erc20ReturnFalseMock = await ethers.deployContract('$ERC20ReturnFalseMock', [name, symbol]); + const erc20ReturnTrueMock = await ethers.deployContract('$ERC20', [name, symbol]); // default implementation returns true + const erc20NoReturnMock = await ethers.deployContract('$ERC20NoReturnMock', [name, symbol]); + const erc20ForceApproveMock = await ethers.deployContract('$ERC20ForceApproveMock', [name, symbol]); + const erc1363Mock = await ethers.deployContract('$ERC1363', [name, symbol]); + const erc1363ReturnFalseOnErc20Mock = await ethers.deployContract('$ERC1363ReturnFalseOnERC20Mock', [name, symbol]); + const erc1363ReturnFalseMock = await ethers.deployContract('$ERC1363ReturnFalseMock', [name, symbol]); + const erc1363NoReturnMock = await ethers.deployContract('$ERC1363NoReturnMock', [name, symbol]); + const erc1363ForceApproveMock = await ethers.deployContract('$ERC1363ForceApproveMock', [name, symbol]); + const erc1363Receiver = await ethers.deployContract('$ERC1363ReceiverMock'); + const erc1363Spender = await ethers.deployContract('$ERC1363SpenderMock'); + + return { + hasNoCode, + owner, + receiver, + spender, + other, + mock, + erc20ReturnFalseMock, + erc20ReturnTrueMock, + erc20NoReturnMock, + erc20ForceApproveMock, + erc1363Mock, + erc1363ReturnFalseOnErc20Mock, + erc1363ReturnFalseMock, + erc1363NoReturnMock, + erc1363ForceApproveMock, + erc1363Receiver, + erc1363Spender, + }; +} + +describe('SafeERC20', function () { + before(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('with address that has no contract code', function () { + beforeEach(async function () { + this.token = this.hasNoCode; + }); + + it('reverts on transfer', async function () { + await expect(this.mock.$safeTransfer(this.token, this.receiver, 0n)) + .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') + .withArgs(this.token); + }); + + it('returns false on trySafeTransfer', async function () { + await expect(this.mock.$trySafeTransfer(this.token, this.receiver, 0n)) + .to.emit(this.mock, 'return$trySafeTransfer') + .withArgs(false); + }); + + it('reverts on transferFrom', async function () { + await expect(this.mock.$safeTransferFrom(this.token, this.mock, this.receiver, 0n)) + .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') + .withArgs(this.token); + }); + + it('returns false on trySafeTransferFrom', async function () { + await expect(this.mock.$trySafeTransferFrom(this.token, this.mock, this.receiver, 0n)) + .to.emit(this.mock, 'return$trySafeTransferFrom') + .withArgs(false); + }); + + it('reverts on increaseAllowance', async function () { + // Call to 'token.allowance' does not return any data, resulting in a decoding error (revert without reason) + await expect(this.mock.$safeIncreaseAllowance(this.token, this.spender, 0n)).to.be.revertedWithoutReason(); + }); + + it('reverts on decreaseAllowance', async function () { + // Call to 'token.allowance' does not return any data, resulting in a decoding error (revert without reason) + await expect(this.mock.$safeDecreaseAllowance(this.token, this.spender, 0n)).to.be.revertedWithoutReason(); + }); + + it('reverts on forceApprove', async function () { + await expect(this.mock.$forceApprove(this.token, this.spender, 0n)) + .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') + .withArgs(this.token); + }); + }); + + describe('with token that returns false on all calls', function () { + beforeEach(async function () { + this.token = this.erc20ReturnFalseMock; + }); + + it('reverts on transfer', async function () { + await expect(this.mock.$safeTransfer(this.token, this.receiver, 0n)) + .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') + .withArgs(this.token); + }); + + it('returns false on trySafeTransfer', async function () { + await expect(this.mock.$trySafeTransfer(this.token, this.receiver, 0n)) + .to.emit(this.mock, 'return$trySafeTransfer') + .withArgs(false); + }); + + it('reverts on transferFrom', async function () { + await expect(this.mock.$safeTransferFrom(this.token, this.mock, this.receiver, 0n)) + .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') + .withArgs(this.token); + }); + + it('returns false on trySafeTransferFrom', async function () { + await expect(this.mock.$trySafeTransferFrom(this.token, this.mock, this.receiver, 0n)) + .to.emit(this.mock, 'return$trySafeTransferFrom') + .withArgs(false); + }); + + it('reverts on increaseAllowance', async function () { + await expect(this.mock.$safeIncreaseAllowance(this.token, this.spender, 0n)) + .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') + .withArgs(this.token); + }); + + it('reverts on decreaseAllowance', async function () { + await expect(this.mock.$safeDecreaseAllowance(this.token, this.spender, 0n)) + .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') + .withArgs(this.token); + }); + + it('reverts on forceApprove', async function () { + await expect(this.mock.$forceApprove(this.token, this.spender, 0n)) + .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') + .withArgs(this.token); + }); + }); + + describe('with token that returns true on all calls', function () { + beforeEach(async function () { + this.token = this.erc20ReturnTrueMock; + }); + + shouldOnlyRevertOnErrors(); + }); + + describe('with token that returns no boolean values', function () { + beforeEach(async function () { + this.token = this.erc20NoReturnMock; + }); + + shouldOnlyRevertOnErrors(); + }); + + describe('with usdt approval behaviour', function () { + beforeEach(async function () { + this.token = this.erc20ForceApproveMock; + }); + + describe('with initial approval', function () { + beforeEach(async function () { + await this.token.$_approve(this.mock, this.spender, 100n); + }); + + it('safeIncreaseAllowance works', async function () { + await this.mock.$safeIncreaseAllowance(this.token, this.spender, 10n); + expect(await this.token.allowance(this.mock, this.spender)).to.equal(110n); + }); + + it('safeDecreaseAllowance works', async function () { + await this.mock.$safeDecreaseAllowance(this.token, this.spender, 10n); + expect(await this.token.allowance(this.mock, this.spender)).to.equal(90n); + }); + + it('forceApprove works', async function () { + await this.mock.$forceApprove(this.token, this.spender, 200n); + expect(await this.token.allowance(this.mock, this.spender)).to.equal(200n); + }); + }); + }); + + describe('with standard ERC1363', function () { + beforeEach(async function () { + this.token = this.erc1363Mock; + }); + + shouldOnlyRevertOnErrors(); + + describe('transferAndCall', function () { + it('cannot transferAndCall to an EOA directly', async function () { + await this.token.$_mint(this.owner, 100n); + + await expect(this.token.connect(this.owner).transferAndCall(this.receiver, value, ethers.Typed.bytes(data))) + .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidReceiver') + .withArgs(this.receiver); + }); + + it('can transferAndCall to an EOA using helper', async function () { + await this.token.$_mint(this.mock, value); + + await expect(this.mock.$transferAndCallRelaxed(this.token, this.receiver, value, data)) + .to.emit(this.token, 'Transfer') + .withArgs(this.mock, this.receiver, value); + }); + + it('can transferAndCall to an ERC1363Receiver using helper', async function () { + await this.token.$_mint(this.mock, value); + + await expect(this.mock.$transferAndCallRelaxed(this.token, this.erc1363Receiver, value, data)) + .to.emit(this.token, 'Transfer') + .withArgs(this.mock, this.erc1363Receiver, value) + .to.emit(this.erc1363Receiver, 'Received') + .withArgs(this.mock, this.mock, value, data); + }); + }); + + describe('transferFromAndCall', function () { + it('can transferFromAndCall to an EOA using helper', async function () { + await this.token.$_mint(this.owner, value); + await this.token.$_approve(this.owner, this.mock, ethers.MaxUint256); + + await expect(this.mock.$transferFromAndCallRelaxed(this.token, this.owner, this.receiver, value, data)) + .to.emit(this.token, 'Transfer') + .withArgs(this.owner, this.receiver, value); + }); + + it('can transferFromAndCall to an ERC1363Receiver using helper', async function () { + await this.token.$_mint(this.owner, value); + await this.token.$_approve(this.owner, this.mock, ethers.MaxUint256); + + await expect(this.mock.$transferFromAndCallRelaxed(this.token, this.owner, this.erc1363Receiver, value, data)) + .to.emit(this.token, 'Transfer') + .withArgs(this.owner, this.erc1363Receiver, value) + .to.emit(this.erc1363Receiver, 'Received') + .withArgs(this.mock, this.owner, value, data); + }); + }); + + describe('approveAndCall', function () { + it('can approveAndCall to an EOA using helper', async function () { + await expect(this.mock.$approveAndCallRelaxed(this.token, this.receiver, value, data)) + .to.emit(this.token, 'Approval') + .withArgs(this.mock, this.receiver, value); + }); + + it('can approveAndCall to an ERC1363Spender using helper', async function () { + await expect(this.mock.$approveAndCallRelaxed(this.token, this.erc1363Spender, value, data)) + .to.emit(this.token, 'Approval') + .withArgs(this.mock, this.erc1363Spender, value) + .to.emit(this.erc1363Spender, 'Approved') + .withArgs(this.mock, value, data); + }); + }); + }); + + describe('with ERC1363 that returns false on all ERC20 calls', function () { + beforeEach(async function () { + this.token = this.erc1363ReturnFalseOnErc20Mock; + }); + + it('reverts on transferAndCallRelaxed', async function () { + await expect(this.mock.$transferAndCallRelaxed(this.token, this.erc1363Receiver, 0n, data)) + .to.be.revertedWithCustomError(this.token, 'ERC1363TransferFailed') + .withArgs(this.erc1363Receiver, 0n); + }); + + it('reverts on transferFromAndCallRelaxed', async function () { + await expect(this.mock.$transferFromAndCallRelaxed(this.token, this.mock, this.erc1363Receiver, 0n, data)) + .to.be.revertedWithCustomError(this.token, 'ERC1363TransferFromFailed') + .withArgs(this.mock, this.erc1363Receiver, 0n); + }); + + it('reverts on approveAndCallRelaxed', async function () { + await expect(this.mock.$approveAndCallRelaxed(this.token, this.erc1363Spender, 0n, data)) + .to.be.revertedWithCustomError(this.token, 'ERC1363ApproveFailed') + .withArgs(this.erc1363Spender, 0n); + }); + }); + + describe('with ERC1363 that returns false on all ERC1363 calls', function () { + beforeEach(async function () { + this.token = this.erc1363ReturnFalseMock; + }); + + it('reverts on transferAndCallRelaxed', async function () { + await expect(this.mock.$transferAndCallRelaxed(this.token, this.erc1363Receiver, 0n, data)) + .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') + .withArgs(this.token); + }); + + it('reverts on transferFromAndCallRelaxed', async function () { + await expect(this.mock.$transferFromAndCallRelaxed(this.token, this.mock, this.erc1363Receiver, 0n, data)) + .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') + .withArgs(this.token); + }); + + it('reverts on approveAndCallRelaxed', async function () { + await expect(this.mock.$approveAndCallRelaxed(this.token, this.erc1363Spender, 0n, data)) + .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') + .withArgs(this.token); + }); + }); + + describe('with ERC1363 that returns no boolean values', function () { + beforeEach(async function () { + this.token = this.erc1363NoReturnMock; + }); + + it('reverts on transferAndCallRelaxed', async function () { + await expect( + this.mock.$transferAndCallRelaxed(this.token, this.erc1363Receiver, 0n, data), + ).to.be.revertedWithoutReason(); + }); + + it('reverts on transferFromAndCallRelaxed', async function () { + await expect( + this.mock.$transferFromAndCallRelaxed(this.token, this.mock, this.erc1363Receiver, 0n, data), + ).to.be.revertedWithoutReason(); + }); + + it('reverts on approveAndCallRelaxed', async function () { + await expect( + this.mock.$approveAndCallRelaxed(this.token, this.erc1363Spender, 0n, data), + ).to.be.revertedWithoutReason(); + }); + }); + + describe('with ERC1363 with usdt approval behaviour', function () { + beforeEach(async function () { + this.token = this.erc1363ForceApproveMock; + }); + + describe('without initial approval', function () { + it('approveAndCallRelaxed works when recipient is an EOA', async function () { + await this.mock.$approveAndCallRelaxed(this.token, this.spender, 10n, data); + expect(await this.token.allowance(this.mock, this.spender)).to.equal(10n); + }); + + it('approveAndCallRelaxed works when recipient is a contract', async function () { + await this.mock.$approveAndCallRelaxed(this.token, this.erc1363Spender, 10n, data); + expect(await this.token.allowance(this.mock, this.erc1363Spender)).to.equal(10n); + }); + }); + + describe('with initial approval', function () { + it('approveAndCallRelaxed works when recipient is an EOA', async function () { + await this.token.$_approve(this.mock, this.spender, 100n); + + await this.mock.$approveAndCallRelaxed(this.token, this.spender, 10n, data); + expect(await this.token.allowance(this.mock, this.spender)).to.equal(10n); + }); + + it('approveAndCallRelaxed reverts when recipient is a contract', async function () { + await this.token.$_approve(this.mock, this.erc1363Spender, 100n); + await expect(this.mock.$approveAndCallRelaxed(this.token, this.erc1363Spender, 10n, data)).to.be.revertedWith( + 'USDT approval failure', + ); + }); + }); + }); +}); + +function shouldOnlyRevertOnErrors() { + describe('transfers', function () { + beforeEach(async function () { + await this.token.$_mint(this.owner, 100n); + await this.token.$_mint(this.mock, 100n); + await this.token.$_approve(this.owner, this.mock, ethers.MaxUint256); + }); + + it("doesn't revert on transfer", async function () { + await expect(this.mock.$safeTransfer(this.token, this.receiver, 10n)) + .to.emit(this.token, 'Transfer') + .withArgs(this.mock, this.receiver, 10n); + }); + + it('returns true on trySafeTransfer', async function () { + await expect(this.mock.$trySafeTransfer(this.token, this.receiver, 10n)) + .to.emit(this.mock, 'return$trySafeTransfer') + .withArgs(true); + }); + + it("doesn't revert on transferFrom", async function () { + await expect(this.mock.$safeTransferFrom(this.token, this.owner, this.receiver, 10n)) + .to.emit(this.token, 'Transfer') + .withArgs(this.owner, this.receiver, 10n); + }); + + it('returns true on trySafeTransferFrom', async function () { + await expect(this.mock.$trySafeTransferFrom(this.token, this.owner, this.receiver, 10n)) + .to.emit(this.mock, 'return$trySafeTransferFrom') + .withArgs(true); + }); + }); + + describe('approvals', function () { + describe('with zero allowance', function () { + beforeEach(async function () { + await this.token.$_approve(this.mock, this.spender, 0n); + }); + + it("doesn't revert when force approving a non-zero allowance", async function () { + await this.mock.$forceApprove(this.token, this.spender, 100n); + expect(await this.token.allowance(this.mock, this.spender)).to.equal(100n); + }); + + it("doesn't revert when force approving a zero allowance", async function () { + await this.mock.$forceApprove(this.token, this.spender, 0n); + expect(await this.token.allowance(this.mock, this.spender)).to.equal(0n); + }); + + it("doesn't revert when increasing the allowance", async function () { + await this.mock.$safeIncreaseAllowance(this.token, this.spender, 10n); + expect(await this.token.allowance(this.mock, this.spender)).to.equal(10n); + }); + + it('reverts when decreasing the allowance', async function () { + await expect(this.mock.$safeDecreaseAllowance(this.token, this.spender, 10n)) + .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedDecreaseAllowance') + .withArgs(this.spender, 0n, 10n); + }); + }); + + describe('with non-zero allowance', function () { + beforeEach(async function () { + await this.token.$_approve(this.mock, this.spender, 100n); + }); + + it("doesn't revert when force approving a non-zero allowance", async function () { + await this.mock.$forceApprove(this.token, this.spender, 20n); + expect(await this.token.allowance(this.mock, this.spender)).to.equal(20n); + }); + + it("doesn't revert when force approving a zero allowance", async function () { + await this.mock.$forceApprove(this.token, this.spender, 0n); + expect(await this.token.allowance(this.mock, this.spender)).to.equal(0n); + }); + + it("doesn't revert when increasing the allowance", async function () { + await this.mock.$safeIncreaseAllowance(this.token, this.spender, 10n); + expect(await this.token.allowance(this.mock, this.spender)).to.equal(110n); + }); + + it("doesn't revert when decreasing the allowance to a positive value", async function () { + await this.mock.$safeDecreaseAllowance(this.token, this.spender, 50n); + expect(await this.token.allowance(this.mock, this.spender)).to.equal(50n); + }); + + it('reverts when decreasing the allowance to a negative value', async function () { + await expect(this.mock.$safeDecreaseAllowance(this.token, this.spender, 200n)) + .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedDecreaseAllowance') + .withArgs(this.spender, 100n, 200n); + }); + }); + }); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.behavior.js new file mode 100644 index 0000000..adfe15a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.behavior.js @@ -0,0 +1,216 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); + +function shouldBehaveLikeERC6909() { + const firstTokenId = 1n; + const secondTokenId = 2n; + const randomTokenId = 125523n; + + const firstTokenSupply = 2000n; + const secondTokenSupply = 3000n; + const amount = 100n; + + describe('like an ERC6909', function () { + describe('balanceOf', function () { + describe("when accounts don't own tokens", function () { + it('return zero', async function () { + await expect(this.token.balanceOf(this.holder, firstTokenId)).to.eventually.be.equal(0n); + await expect(this.token.balanceOf(this.holder, secondTokenId)).to.eventually.be.equal(0n); + await expect(this.token.balanceOf(this.other, randomTokenId)).to.eventually.be.equal(0n); + }); + }); + + describe('when accounts own some tokens', function () { + beforeEach(async function () { + await this.token.$_mint(this.holder, firstTokenId, firstTokenSupply); + await this.token.$_mint(this.holder, secondTokenId, secondTokenSupply); + }); + + it('returns amount owned by the given address', async function () { + await expect(this.token.balanceOf(this.holder, firstTokenId)).to.eventually.be.equal(firstTokenSupply); + await expect(this.token.balanceOf(this.holder, secondTokenId)).to.eventually.be.equal(secondTokenSupply); + await expect(this.token.balanceOf(this.other, firstTokenId)).to.eventually.be.equal(0n); + }); + }); + }); + + describe('setOperator', function () { + it('emits an OperatorSet event and updated the value', async function () { + await expect(this.token.connect(this.holder).setOperator(this.operator, true)) + .to.emit(this.token, 'OperatorSet') + .withArgs(this.holder, this.operator, true); + + // operator for holder + await expect(this.token.isOperator(this.holder, this.operator)).to.eventually.be.true; + + // not operator for other account + await expect(this.token.isOperator(this.other, this.operator)).to.eventually.be.false; + }); + + it('can unset the operator approval', async function () { + await this.token.connect(this.holder).setOperator(this.operator, true); + + // before + await expect(this.token.isOperator(this.holder, this.operator)).to.eventually.be.true; + + // unset + await expect(this.token.connect(this.holder).setOperator(this.operator, false)) + .to.emit(this.token, 'OperatorSet') + .withArgs(this.holder, this.operator, false); + + // after + await expect(this.token.isOperator(this.holder, this.operator)).to.eventually.be.false; + }); + + it('cannot set address(0) as an operator', async function () { + await expect(this.token.connect(this.holder).setOperator(ethers.ZeroAddress, true)) + .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidSpender') + .withArgs(ethers.ZeroAddress); + }); + }); + + describe('approve', function () { + it('emits an Approval event and updates allowance', async function () { + await expect(this.token.connect(this.holder).approve(this.operator, firstTokenId, firstTokenSupply)) + .to.emit(this.token, 'Approval') + .withArgs(this.holder, this.operator, firstTokenId, firstTokenSupply); + + // approved + await expect(this.token.allowance(this.holder, this.operator, firstTokenId)).to.eventually.be.equal( + firstTokenSupply, + ); + // other account is not approved + await expect(this.token.allowance(this.other, this.operator, firstTokenId)).to.eventually.be.equal(0n); + }); + + it('can unset the approval', async function () { + await expect(this.token.connect(this.holder).approve(this.operator, firstTokenId, 0n)) + .to.emit(this.token, 'Approval') + .withArgs(this.holder, this.operator, firstTokenId, 0n); + await expect(this.token.allowance(this.holder, this.operator, firstTokenId)).to.eventually.be.equal(0n); + }); + + it('cannot give allowance to address(0)', async function () { + await expect(this.token.connect(this.holder).approve(ethers.ZeroAddress, firstTokenId, firstTokenSupply)) + .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidSpender') + .withArgs(ethers.ZeroAddress); + }); + }); + + describe('transfer', function () { + beforeEach(async function () { + await this.token.$_mint(this.holder, firstTokenId, firstTokenSupply); + await this.token.$_mint(this.holder, secondTokenId, secondTokenSupply); + }); + + it('transfers to the zero address are blocked', async function () { + await expect(this.token.connect(this.holder).transfer(ethers.ZeroAddress, firstTokenId, firstTokenSupply)) + .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidReceiver') + .withArgs(ethers.ZeroAddress); + }); + + it('reverts when insufficient balance', async function () { + await expect(this.token.connect(this.holder).transfer(this.recipient, firstTokenId, firstTokenSupply + 1n)) + .to.be.revertedWithCustomError(this.token, 'ERC6909InsufficientBalance') + .withArgs(this.holder, firstTokenSupply, firstTokenSupply + 1n, firstTokenId); + }); + + it('emits event and transfers tokens', async function () { + await expect(this.token.connect(this.holder).transfer(this.recipient, firstTokenId, amount)) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.holder, this.recipient, firstTokenId, amount); + + await expect(this.token.balanceOf(this.holder, firstTokenId)).to.eventually.equal(firstTokenSupply - amount); + await expect(this.token.balanceOf(this.recipient, firstTokenId)).to.eventually.equal(amount); + }); + }); + + describe('transferFrom', function () { + beforeEach(async function () { + await this.token.$_mint(this.holder, firstTokenId, firstTokenSupply); + await this.token.$_mint(this.holder, secondTokenId, secondTokenSupply); + }); + + it('transfer from self', async function () { + await expect(this.token.connect(this.holder).transferFrom(this.holder, this.recipient, firstTokenId, amount)) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.holder, this.recipient, firstTokenId, amount); + + await expect(this.token.balanceOf(this.holder, firstTokenId)).to.eventually.equal(firstTokenSupply - amount); + await expect(this.token.balanceOf(this.recipient, firstTokenId)).to.eventually.equal(amount); + }); + + describe('with approval', async function () { + beforeEach(async function () { + await this.token.connect(this.holder).approve(this.operator, firstTokenId, amount); + }); + + it('reverts when insufficient allowance', async function () { + await expect( + this.token.connect(this.operator).transferFrom(this.holder, this.recipient, firstTokenId, amount + 1n), + ) + .to.be.revertedWithCustomError(this.token, 'ERC6909InsufficientAllowance') + .withArgs(this.operator, amount, amount + 1n, firstTokenId); + }); + + it('should emit transfer event and update approval (without an Approval event)', async function () { + await expect( + this.token.connect(this.operator).transferFrom(this.holder, this.recipient, firstTokenId, amount - 1n), + ) + .to.emit(this.token, 'Transfer') + .withArgs(this.operator, this.holder, this.recipient, firstTokenId, amount - 1n) + .to.not.emit(this.token, 'Approval'); + + await expect(this.token.allowance(this.holder, this.operator, firstTokenId)).to.eventually.equal(1n); + }); + + it("shouldn't reduce allowance when infinite", async function () { + await this.token.connect(this.holder).approve(this.operator, firstTokenId, ethers.MaxUint256); + + await this.token.connect(this.operator).transferFrom(this.holder, this.recipient, firstTokenId, amount); + + await expect(this.token.allowance(this.holder, this.operator, firstTokenId)).to.eventually.equal( + ethers.MaxUint256, + ); + }); + }); + }); + + describe('with operator approval', function () { + beforeEach(async function () { + await this.token.connect(this.holder).setOperator(this.operator, true); + await this.token.$_mint(this.holder, firstTokenId, firstTokenSupply); + }); + + it('operator can transfer', async function () { + await expect(this.token.connect(this.operator).transferFrom(this.holder, this.recipient, firstTokenId, amount)) + .to.emit(this.token, 'Transfer') + .withArgs(this.operator, this.holder, this.recipient, firstTokenId, amount); + + await expect(this.token.balanceOf(this.holder, firstTokenId)).to.eventually.equal(firstTokenSupply - amount); + await expect(this.token.balanceOf(this.recipient, firstTokenId)).to.eventually.equal(amount); + }); + + it('operator transfer does not reduce allowance', async function () { + // Also give allowance + await this.token.connect(this.holder).approve(this.operator, firstTokenId, firstTokenSupply); + + await expect(this.token.connect(this.operator).transferFrom(this.holder, this.recipient, firstTokenId, amount)) + .to.emit(this.token, 'Transfer') + .withArgs(this.operator, this.holder, this.recipient, firstTokenId, amount); + + await expect(this.token.allowance(this.holder, this.operator, firstTokenId)).to.eventually.equal( + firstTokenSupply, + ); + }); + }); + + shouldSupportInterfaces(['ERC6909']); + }); +} + +module.exports = { + shouldBehaveLikeERC6909, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.test.js new file mode 100644 index 0000000..fa41145 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.test.js @@ -0,0 +1,104 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { shouldBehaveLikeERC6909 } = require('./ERC6909.behavior'); + +async function fixture() { + const [holder, operator, recipient, other] = await ethers.getSigners(); + const token = await ethers.deployContract('$ERC6909'); + return { token, holder, operator, recipient, other }; +} + +describe('ERC6909', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeERC6909(); + + describe('internal functions', function () { + const tokenId = 1990n; + const mintValue = 9001n; + const burnValue = 3000n; + + describe('_mint', function () { + it('reverts with a zero destination address', async function () { + await expect(this.token.$_mint(ethers.ZeroAddress, tokenId, mintValue)) + .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidReceiver') + .withArgs(ethers.ZeroAddress); + }); + + describe('with minted tokens', function () { + beforeEach(async function () { + this.tx = await this.token.connect(this.operator).$_mint(this.holder, tokenId, mintValue); + }); + + it('emits a Transfer event from 0 address', async function () { + await expect(this.tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.operator, ethers.ZeroAddress, this.holder, tokenId, mintValue); + }); + + it('credits the minted token value', async function () { + await expect(this.token.balanceOf(this.holder, tokenId)).to.eventually.be.equal(mintValue); + }); + }); + }); + + describe('_transfer', function () { + it('reverts when transferring from the zero address', async function () { + await expect(this.token.$_transfer(ethers.ZeroAddress, this.holder, 1n, 1n)) + .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidSender') + .withArgs(ethers.ZeroAddress); + }); + + it('reverts when transferring to the zero address', async function () { + await expect(this.token.$_transfer(this.holder, ethers.ZeroAddress, 1n, 1n)) + .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidReceiver') + .withArgs(ethers.ZeroAddress); + }); + }); + + describe('_burn', function () { + it('reverts with a zero from address', async function () { + await expect(this.token.$_burn(ethers.ZeroAddress, tokenId, burnValue)) + .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidSender') + .withArgs(ethers.ZeroAddress); + }); + + describe('with burned tokens', function () { + beforeEach(async function () { + await this.token.connect(this.operator).$_mint(this.holder, tokenId, mintValue); + this.tx = await this.token.connect(this.operator).$_burn(this.holder, tokenId, burnValue); + }); + + it('emits a Transfer event to 0 address', async function () { + await expect(this.tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.operator, this.holder, ethers.ZeroAddress, tokenId, burnValue); + }); + + it('debits the burned token value', async function () { + await expect(this.token.balanceOf(this.holder, tokenId)).to.eventually.be.equal(mintValue - burnValue); + }); + }); + }); + + describe('_approve', function () { + it('reverts when the owner is the zero address', async function () { + await expect(this.token.$_approve(ethers.ZeroAddress, this.recipient, 1n, 1n)) + .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidApprover') + .withArgs(ethers.ZeroAddress); + }); + }); + + describe('_setOperator', function () { + it('reverts when the owner is the zero address', async function () { + await expect(this.token.$_setOperator(ethers.ZeroAddress, this.operator, true)) + .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidApprover') + .withArgs(ethers.ZeroAddress); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909ContentURI.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909ContentURI.test.js new file mode 100644 index 0000000..2a54e22 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909ContentURI.test.js @@ -0,0 +1,49 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +async function fixture() { + const token = await ethers.deployContract('$ERC6909ContentURI'); + return { token }; +} + +describe('ERC6909ContentURI', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('contractURI', function () { + it('is empty string by default', async function () { + await expect(this.token.contractURI()).to.eventually.equal(''); + }); + + it('is settable by internal setter', async function () { + await this.token.$_setContractURI('https://example.com'); + await expect(this.token.contractURI()).to.eventually.equal('https://example.com'); + }); + + it('emits an event when set', async function () { + await expect(this.token.$_setContractURI('https://example.com')).to.emit(this.token, 'ContractURIUpdated'); + }); + }); + + describe('tokenURI', function () { + it('is empty string by default', async function () { + await expect(this.token.tokenURI(1n)).to.eventually.equal(''); + }); + + it('can be set by dedicated setter', async function () { + await this.token.$_setTokenURI(1n, 'https://example.com/1'); + await expect(this.token.tokenURI(1n)).to.eventually.equal('https://example.com/1'); + + // Only set for the specified token ID + await expect(this.token.tokenURI(2n)).to.eventually.equal(''); + }); + + it('emits an event when set', async function () { + await expect(this.token.$_setTokenURI(1n, 'https://example.com/1')) + .to.emit(this.token, 'URI') + .withArgs('https://example.com/1', 1n); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909Metadata.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909Metadata.test.js new file mode 100644 index 0000000..e6d3dd9 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909Metadata.test.js @@ -0,0 +1,58 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +async function fixture() { + const token = await ethers.deployContract('$ERC6909Metadata'); + return { token }; +} + +describe('ERC6909Metadata', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('name', function () { + it('is empty string be default', async function () { + await expect(this.token.name(1n)).to.eventually.equal(''); + }); + + it('can be set by dedicated setter', async function () { + await expect(this.token.$_setName(1n, 'My Token')) + .to.emit(this.token, 'ERC6909NameUpdated') + .withArgs(1n, 'My Token'); + await expect(this.token.name(1n)).to.eventually.equal('My Token'); + + // Only set for the specified token ID + await expect(this.token.name(2n)).to.eventually.equal(''); + }); + }); + + describe('symbol', function () { + it('is empty string be default', async function () { + await expect(this.token.symbol(1n)).to.eventually.equal(''); + }); + + it('can be set by dedicated setter', async function () { + await expect(this.token.$_setSymbol(1n, 'MTK')).to.emit(this.token, 'ERC6909SymbolUpdated').withArgs(1n, 'MTK'); + await expect(this.token.symbol(1n)).to.eventually.equal('MTK'); + + // Only set for the specified token ID + await expect(this.token.symbol(2n)).to.eventually.equal(''); + }); + }); + + describe('decimals', function () { + it('is 0 by default', async function () { + await expect(this.token.decimals(1n)).to.eventually.equal(0); + }); + + it('can be set by dedicated setter', async function () { + await expect(this.token.$_setDecimals(1n, 18)).to.emit(this.token, 'ERC6909DecimalsUpdated').withArgs(1n, 18); + await expect(this.token.decimals(1n)).to.eventually.equal(18); + + // Only set for the specified token ID + await expect(this.token.decimals(2n)).to.eventually.equal(0); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909TokenSupply.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909TokenSupply.test.js new file mode 100644 index 0000000..0b8b053 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909TokenSupply.test.js @@ -0,0 +1,53 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { shouldBehaveLikeERC6909 } = require('../ERC6909.behavior'); + +async function fixture() { + const [holder, operator, recipient, other] = await ethers.getSigners(); + const token = await ethers.deployContract('$ERC6909TokenSupply'); + return { token, holder, operator, recipient, other }; +} + +describe('ERC6909TokenSupply', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeERC6909(); + + describe('totalSupply', function () { + it('is zero before any mint', async function () { + await expect(this.token.totalSupply(1n)).to.eventually.be.equal(0n); + }); + + it('minting tokens increases the total supply', async function () { + await this.token.$_mint(this.holder, 1n, 17n); + await expect(this.token.totalSupply(1n)).to.eventually.be.equal(17n); + }); + + describe('with tokens minted', function () { + const supply = 1000n; + + beforeEach(async function () { + await this.token.$_mint(this.holder, 1n, supply); + }); + + it('burning tokens decreases the total supply', async function () { + await this.token.$_burn(this.holder, 1n, 17n); + await expect(this.token.totalSupply(1n)).to.eventually.be.equal(supply - 17n); + }); + + it('supply unaffected by transfers', async function () { + await this.token.$_transfer(this.holder, this.recipient, 1n, 42n); + await expect(this.token.totalSupply(1n)).to.eventually.be.equal(supply); + }); + + it('supply unaffected by no-op', async function () { + await this.token.$_update(ethers.ZeroAddress, ethers.ZeroAddress, 1n, 42n); + await expect(this.token.totalSupply(1n)).to.eventually.be.equal(supply); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js new file mode 100644 index 0000000..433ffe0 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js @@ -0,0 +1,946 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); +const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); + +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); +const { RevertType } = require('../../helpers/enums'); + +const firstTokenId = 5042n; +const secondTokenId = 79217n; +const nonExistentTokenId = 13n; +const fourthTokenId = 4n; + +const RECEIVER_MAGIC_VALUE = '0x150b7a02'; + +function shouldBehaveLikeERC721() { + beforeEach(async function () { + const [owner, newOwner, approved, operator, other] = this.accounts; + Object.assign(this, { owner, newOwner, approved, operator, other }); + }); + + shouldSupportInterfaces(['ERC721']); + + describe('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(this.owner, firstTokenId); + await this.token.$_mint(this.owner, secondTokenId); + this.to = this.other; + }); + + describe('balanceOf', function () { + describe('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(this.owner)).to.equal(2n); + }); + }); + + describe('when the given address does not own any tokens', function () { + it('returns 0', async function () { + expect(await this.token.balanceOf(this.other)).to.equal(0n); + }); + }); + + describe('when querying the zero address', function () { + it('throws', async function () { + await expect(this.token.balanceOf(ethers.ZeroAddress)) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidOwner') + .withArgs(ethers.ZeroAddress); + }); + }); + }); + + describe('ownerOf', function () { + describe('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.equal(this.owner); + }); + }); + + describe('when the given token ID was not tracked by this token', function () { + const tokenId = nonExistentTokenId; + + it('reverts', async function () { + await expect(this.token.ownerOf(tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(tokenId); + }); + }); + }); + + describe('transfers', function () { + const tokenId = firstTokenId; + const data = '0x42'; + + beforeEach(async function () { + await this.token.connect(this.owner).approve(this.approved, tokenId); + await this.token.connect(this.owner).setApprovalForAll(this.operator, true); + }); + + const transferWasSuccessful = () => { + it('transfers the ownership of the given token ID to the given address', async function () { + await this.tx(); + expect(await this.token.ownerOf(tokenId)).to.equal(this.to); + }); + + it('emits a Transfer event', async function () { + await expect(this.tx()).to.emit(this.token, 'Transfer').withArgs(this.owner, this.to, tokenId); + }); + + it('clears the approval for the token ID with no event', async function () { + await expect(this.tx()).to.not.emit(this.token, 'Approval'); + + expect(await this.token.getApproved(tokenId)).to.equal(ethers.ZeroAddress); + }); + + it('adjusts owners balances', async function () { + const balanceBefore = await this.token.balanceOf(this.owner); + await this.tx(); + expect(await this.token.balanceOf(this.owner)).to.equal(balanceBefore - 1n); + }); + + it('adjusts owners tokens by index', async function () { + if (!this.token.tokenOfOwnerByIndex) return; + + await this.tx(); + expect(await this.token.tokenOfOwnerByIndex(this.to, 0n)).to.equal(tokenId); + expect(await this.token.tokenOfOwnerByIndex(this.owner, 0n)).to.not.equal(tokenId); + }); + }; + + const shouldTransferTokensByUsers = function (fragment, opts = {}) { + describe('when called by the owner', function () { + beforeEach(async function () { + this.tx = () => + this.token.connect(this.owner)[fragment](this.owner, this.to, tokenId, ...(opts.extra ?? [])); + }); + transferWasSuccessful(); + }); + + describe('when called by the approved individual', function () { + beforeEach(async function () { + this.tx = () => + this.token.connect(this.approved)[fragment](this.owner, this.to, tokenId, ...(opts.extra ?? [])); + }); + transferWasSuccessful(); + }); + + describe('when called by the operator', function () { + beforeEach(async function () { + this.tx = () => + this.token.connect(this.operator)[fragment](this.owner, this.to, tokenId, ...(opts.extra ?? [])); + }); + transferWasSuccessful(); + }); + + describe('when called by the owner without an approved user', function () { + beforeEach(async function () { + await this.token.connect(this.owner).approve(ethers.ZeroAddress, tokenId); + this.tx = () => + this.token.connect(this.operator)[fragment](this.owner, this.to, tokenId, ...(opts.extra ?? [])); + }); + transferWasSuccessful(); + }); + + describe('when sent to the owner', function () { + beforeEach(async function () { + this.tx = () => + this.token.connect(this.owner)[fragment](this.owner, this.owner, tokenId, ...(opts.extra ?? [])); + }); + + it('keeps ownership of the token', async function () { + await this.tx(); + expect(await this.token.ownerOf(tokenId)).to.equal(this.owner); + }); + + it('clears the approval for the token ID', async function () { + await this.tx(); + expect(await this.token.getApproved(tokenId)).to.equal(ethers.ZeroAddress); + }); + + it('emits only a transfer event', async function () { + await expect(this.tx()).to.emit(this.token, 'Transfer').withArgs(this.owner, this.owner, tokenId); + }); + + it('keeps the owner balance', async function () { + const balanceBefore = await this.token.balanceOf(this.owner); + await this.tx(); + expect(await this.token.balanceOf(this.owner)).to.equal(balanceBefore); + }); + + it('keeps same tokens by index', async function () { + if (!this.token.tokenOfOwnerByIndex) return; + + expect(await Promise.all([0n, 1n].map(i => this.token.tokenOfOwnerByIndex(this.owner, i)))).to.have.members( + [firstTokenId, secondTokenId], + ); + }); + }); + + describe('when the address of the previous owner is incorrect', function () { + it('reverts', async function () { + await expect( + this.token.connect(this.owner)[fragment](this.other, this.other, tokenId, ...(opts.extra ?? [])), + ) + .to.be.revertedWithCustomError(this.token, 'ERC721IncorrectOwner') + .withArgs(this.other, tokenId, this.owner); + }); + }); + + describe('when the sender is not authorized for the token id', function () { + if (opts.unrestricted) { + it('does not revert', async function () { + await this.token.connect(this.other)[fragment](this.owner, this.other, tokenId, ...(opts.extra ?? [])); + }); + } else { + it('reverts', async function () { + await expect( + this.token.connect(this.other)[fragment](this.owner, this.other, tokenId, ...(opts.extra ?? [])), + ) + .to.be.revertedWithCustomError(this.token, 'ERC721InsufficientApproval') + .withArgs(this.other, tokenId); + }); + } + }); + + describe('when the given token ID does not exist', function () { + it('reverts', async function () { + await expect( + this.token + .connect(this.owner) + [fragment](this.owner, this.other, nonExistentTokenId, ...(opts.extra ?? [])), + ) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(nonExistentTokenId); + }); + }); + + describe('when the address to transfer the token to is the zero address', function () { + it('reverts', async function () { + await expect( + this.token.connect(this.owner)[fragment](this.owner, ethers.ZeroAddress, tokenId, ...(opts.extra ?? [])), + ) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') + .withArgs(ethers.ZeroAddress); + }); + }); + }; + + const shouldTransferSafely = function (fragment, data, opts = {}) { + // sanity + it('function exists', async function () { + expect(this.token.interface.hasFunction(fragment)).to.be.true; + }); + + describe('to a user account', function () { + shouldTransferTokensByUsers(fragment, opts); + }); + + describe('to a valid receiver contract', function () { + beforeEach(async function () { + this.to = await ethers.deployContract('ERC721ReceiverMock', [RECEIVER_MAGIC_VALUE, RevertType.None]); + }); + + shouldTransferTokensByUsers(fragment, opts); + + it('calls onERC721Received', async function () { + await expect(this.token.connect(this.owner)[fragment](this.owner, this.to, tokenId, ...(opts.extra ?? []))) + .to.emit(this.to, 'Received') + .withArgs(this.owner, this.owner, tokenId, data, anyValue); + }); + + it('calls onERC721Received from approved', async function () { + await expect( + this.token.connect(this.approved)[fragment](this.owner, this.to, tokenId, ...(opts.extra ?? [])), + ) + .to.emit(this.to, 'Received') + .withArgs(this.approved, this.owner, tokenId, data, anyValue); + }); + + describe('with an invalid token id', function () { + it('reverts', async function () { + await expect( + this.token + .connect(this.approved) + [fragment](this.owner, this.to, nonExistentTokenId, ...(opts.extra ?? [])), + ) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(nonExistentTokenId); + }); + }); + }); + }; + + for (const { fnName, opts } of [ + { fnName: 'transferFrom', opts: {} }, + { fnName: '$_transfer', opts: { unrestricted: true } }, + ]) { + describe(`via ${fnName}`, function () { + shouldTransferTokensByUsers(fnName, opts); + }); + } + + for (const { fnName, opts } of [ + { fnName: 'safeTransferFrom', opts: {} }, + { fnName: '$_safeTransfer', opts: { unrestricted: true } }, + ]) { + describe(`via ${fnName}`, function () { + describe('with data', function () { + shouldTransferSafely(fnName, data, { ...opts, extra: [ethers.Typed.bytes(data)] }); + }); + + describe('without data', function () { + shouldTransferSafely(fnName, '0x', opts); + }); + + describe('to a receiver contract returning unexpected value', function () { + it('reverts', async function () { + const invalidReceiver = await ethers.deployContract('ERC721ReceiverMock', [ + '0xdeadbeef', + RevertType.None, + ]); + + await expect(this.token.connect(this.owner)[fnName](this.owner, invalidReceiver, tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') + .withArgs(invalidReceiver); + }); + }); + + describe('to a receiver contract that reverts with message', function () { + it('reverts', async function () { + const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithMessage, + ]); + + await expect( + this.token.connect(this.owner)[fnName](this.owner, revertingReceiver, tokenId), + ).to.be.revertedWith('ERC721ReceiverMock: reverting'); + }); + }); + + describe('to a receiver contract that reverts without message', function () { + it('reverts', async function () { + const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithoutMessage, + ]); + + await expect(this.token.connect(this.owner)[fnName](this.owner, revertingReceiver, tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') + .withArgs(revertingReceiver); + }); + }); + + describe('to a receiver contract that reverts with custom error', function () { + it('reverts', async function () { + const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithCustomError, + ]); + + await expect(this.token.connect(this.owner)[fnName](this.owner, revertingReceiver, tokenId)) + .to.be.revertedWithCustomError(revertingReceiver, 'CustomError') + .withArgs(RECEIVER_MAGIC_VALUE); + }); + }); + + describe('to a receiver contract that panics', function () { + it('reverts', async function () { + const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ + RECEIVER_MAGIC_VALUE, + RevertType.Panic, + ]); + + await expect( + this.token.connect(this.owner)[fnName](this.owner, revertingReceiver, tokenId), + ).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO); + }); + }); + + describe('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const nonReceiver = await ethers.deployContract('CallReceiverMock'); + + await expect(this.token.connect(this.owner)[fnName](this.owner, nonReceiver, tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') + .withArgs(nonReceiver); + }); + }); + }); + } + }); + + 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 () { + const receiver = await ethers.deployContract('ERC721ReceiverMock', [RECEIVER_MAGIC_VALUE, RevertType.None]); + + await expect(await this.token.$_safeMint(receiver, tokenId, ethers.Typed.bytes(data))) + .to.emit(receiver, 'Received') + .withArgs(anyValue, ethers.ZeroAddress, tokenId, data, anyValue); + }); + + it('calls onERC721Received — without data', async function () { + const receiver = await ethers.deployContract('ERC721ReceiverMock', [RECEIVER_MAGIC_VALUE, RevertType.None]); + + await expect(await this.token.$_safeMint(receiver, tokenId)) + .to.emit(receiver, 'Received') + .withArgs(anyValue, ethers.ZeroAddress, tokenId, '0x', anyValue); + }); + + describe('to a receiver contract returning unexpected value', function () { + it('reverts', async function () { + const invalidReceiver = await ethers.deployContract('ERC721ReceiverMock', ['0xdeadbeef', RevertType.None]); + + await expect(this.token.$_safeMint(invalidReceiver, tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') + .withArgs(invalidReceiver); + }); + }); + + describe('to a receiver contract that reverts with message', function () { + it('reverts', async function () { + const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithMessage, + ]); + + await expect(this.token.$_safeMint(revertingReceiver, tokenId)).to.be.revertedWith( + 'ERC721ReceiverMock: reverting', + ); + }); + }); + + describe('to a receiver contract that reverts without message', function () { + it('reverts', async function () { + const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithoutMessage, + ]); + + await expect(this.token.$_safeMint(revertingReceiver, tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') + .withArgs(revertingReceiver); + }); + }); + + describe('to a receiver contract that reverts with custom error', function () { + it('reverts', async function () { + const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithCustomError, + ]); + + await expect(this.token.$_safeMint(revertingReceiver, tokenId)) + .to.be.revertedWithCustomError(revertingReceiver, 'CustomError') + .withArgs(RECEIVER_MAGIC_VALUE); + }); + }); + + describe('to a receiver contract that panics', function () { + it('reverts', async function () { + const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ + RECEIVER_MAGIC_VALUE, + RevertType.Panic, + ]); + + await expect(this.token.$_safeMint(revertingReceiver, tokenId)).to.be.revertedWithPanic( + PANIC_CODES.DIVISION_BY_ZERO, + ); + }); + }); + + describe('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const nonReceiver = await ethers.deployContract('CallReceiverMock'); + + await expect(this.token.$_safeMint(nonReceiver, tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') + .withArgs(nonReceiver); + }); + }); + }); + }); + + describe('approve', function () { + const tokenId = firstTokenId; + + const itClearsApproval = function () { + it('clears approval for the token', async function () { + expect(await this.token.getApproved(tokenId)).to.equal(ethers.ZeroAddress); + }); + }; + + const itApproves = function () { + it('sets the approval for the target address', async function () { + expect(await this.token.getApproved(tokenId)).to.equal(this.approved ?? this.approved); + }); + }; + + const itEmitsApprovalEvent = function () { + it('emits an approval event', async function () { + await expect(this.tx) + .to.emit(this.token, 'Approval') + .withArgs(this.owner, this.approved ?? this.approved, tokenId); + }); + }; + + describe('when clearing approval', function () { + describe('when there was no prior approval', function () { + beforeEach(async function () { + this.approved = ethers.ZeroAddress; + this.tx = await this.token.connect(this.owner).approve(this.approved, tokenId); + }); + + itClearsApproval(); + itEmitsApprovalEvent(); + }); + + describe('when there was a prior approval', function () { + beforeEach(async function () { + await this.token.connect(this.owner).approve(this.other, tokenId); + this.approved = ethers.ZeroAddress; + this.tx = await this.token.connect(this.owner).approve(this.approved, tokenId); + }); + + itClearsApproval(); + itEmitsApprovalEvent(); + }); + }); + + describe('when approving a non-zero address', function () { + describe('when there was no prior approval', function () { + beforeEach(async function () { + this.tx = await this.token.connect(this.owner).approve(this.approved, tokenId); + }); + + itApproves(); + itEmitsApprovalEvent(); + }); + + describe('when there was a prior approval to the same address', function () { + beforeEach(async function () { + await this.token.connect(this.owner).approve(this.approved, tokenId); + this.tx = await this.token.connect(this.owner).approve(this.approved, tokenId); + }); + + itApproves(); + itEmitsApprovalEvent(); + }); + + describe('when there was a prior approval to a different address', function () { + beforeEach(async function () { + await this.token.connect(this.owner).approve(this.other, tokenId); + this.tx = await this.token.connect(this.owner).approve(this.approved, tokenId); + }); + + itApproves(); + itEmitsApprovalEvent(); + }); + }); + + describe('when the sender does not own the given token ID', function () { + it('reverts', async function () { + await expect(this.token.connect(this.other).approve(this.approved, tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidApprover') + .withArgs(this.other); + }); + }); + + describe('when the sender is approved for the given token ID', function () { + it('reverts', async function () { + await this.token.connect(this.owner).approve(this.approved, tokenId); + + await expect(this.token.connect(this.approved).approve(this.other, tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidApprover') + .withArgs(this.approved); + }); + }); + + describe('when the sender is an operator', function () { + beforeEach(async function () { + await this.token.connect(this.owner).setApprovalForAll(this.operator, true); + + this.tx = await this.token.connect(this.operator).approve(this.approved, tokenId); + }); + + itApproves(); + itEmitsApprovalEvent(); + }); + + describe('when the given token ID does not exist', function () { + it('reverts', async function () { + await expect(this.token.connect(this.operator).approve(this.approved, nonExistentTokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(nonExistentTokenId); + }); + }); + }); + + describe('setApprovalForAll', function () { + describe('when the operator willing to approve is not the owner', function () { + describe('when there is no operator approval set by the sender', function () { + it('approves the operator', async function () { + await this.token.connect(this.owner).setApprovalForAll(this.operator, true); + + expect(await this.token.isApprovedForAll(this.owner, this.operator)).to.be.true; + }); + + it('emits an approval event', async function () { + await expect(this.token.connect(this.owner).setApprovalForAll(this.operator, true)) + .to.emit(this.token, 'ApprovalForAll') + .withArgs(this.owner, this.operator, true); + }); + }); + + describe('when the operator was set as not approved', function () { + beforeEach(async function () { + await this.token.connect(this.owner).setApprovalForAll(this.operator, false); + }); + + it('approves the operator', async function () { + await this.token.connect(this.owner).setApprovalForAll(this.operator, true); + + expect(await this.token.isApprovedForAll(this.owner, this.operator)).to.be.true; + }); + + it('emits an approval event', async function () { + await expect(this.token.connect(this.owner).setApprovalForAll(this.operator, true)) + .to.emit(this.token, 'ApprovalForAll') + .withArgs(this.owner, this.operator, true); + }); + + it('can unset the operator approval', async function () { + await this.token.connect(this.owner).setApprovalForAll(this.operator, false); + + expect(await this.token.isApprovedForAll(this.owner, this.operator)).to.be.false; + }); + }); + + describe('when the operator was already approved', function () { + beforeEach(async function () { + await this.token.connect(this.owner).setApprovalForAll(this.operator, true); + }); + + it('keeps the approval to the given address', async function () { + await this.token.connect(this.owner).setApprovalForAll(this.operator, true); + + expect(await this.token.isApprovedForAll(this.owner, this.operator)).to.be.true; + }); + + it('emits an approval event', async function () { + await expect(this.token.connect(this.owner).setApprovalForAll(this.operator, true)) + .to.emit(this.token, 'ApprovalForAll') + .withArgs(this.owner, this.operator, true); + }); + }); + }); + + describe('when the operator is address zero', function () { + it('reverts', async function () { + await expect(this.token.connect(this.owner).setApprovalForAll(ethers.ZeroAddress, true)) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidOperator') + .withArgs(ethers.ZeroAddress); + }); + }); + }); + + describe('getApproved', function () { + describe('when token is not minted', function () { + it('reverts', async function () { + await expect(this.token.getApproved(nonExistentTokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(nonExistentTokenId); + }); + }); + + describe('when token has been minted ', function () { + it('should return the zero address', async function () { + expect(await this.token.getApproved(firstTokenId)).to.equal(ethers.ZeroAddress); + }); + + describe('when account has been approved', function () { + beforeEach(async function () { + await this.token.connect(this.owner).approve(this.approved, firstTokenId); + }); + + it('returns approved account', async function () { + expect(await this.token.getApproved(firstTokenId)).to.equal(this.approved); + }); + }); + }); + }); + }); + + describe('_mint(address, uint256)', function () { + it('reverts with a null destination address', async function () { + await expect(this.token.$_mint(ethers.ZeroAddress, firstTokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') + .withArgs(ethers.ZeroAddress); + }); + + describe('with minted token', function () { + beforeEach(async function () { + this.tx = await this.token.$_mint(this.owner, firstTokenId); + }); + + it('emits a Transfer event', async function () { + await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.owner, firstTokenId); + }); + + it('creates the token', async function () { + expect(await this.token.balanceOf(this.owner)).to.equal(1n); + expect(await this.token.ownerOf(firstTokenId)).to.equal(this.owner); + }); + + it('reverts when adding a token id that already exists', async function () { + await expect(this.token.$_mint(this.owner, firstTokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidSender') + .withArgs(ethers.ZeroAddress); + }); + }); + }); + + describe('_burn', function () { + it('reverts when burning a non-existent token id', async function () { + await expect(this.token.$_burn(nonExistentTokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(nonExistentTokenId); + }); + + describe('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(this.owner, firstTokenId); + await this.token.$_mint(this.owner, secondTokenId); + }); + + describe('with burnt token', function () { + beforeEach(async function () { + this.tx = await this.token.$_burn(firstTokenId); + }); + + it('emits a Transfer event', async function () { + await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.owner, ethers.ZeroAddress, firstTokenId); + }); + + it('deletes the token', async function () { + expect(await this.token.balanceOf(this.owner)).to.equal(1n); + await expect(this.token.ownerOf(firstTokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(firstTokenId); + }); + + it('reverts when burning a token id that has been deleted', async function () { + await expect(this.token.$_burn(firstTokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(firstTokenId); + }); + }); + }); + }); +} + +function shouldBehaveLikeERC721Enumerable() { + beforeEach(async function () { + const [owner, newOwner, approved, operator, other] = this.accounts; + Object.assign(this, { owner, newOwner, approved, operator, other }); + }); + + shouldSupportInterfaces(['ERC721Enumerable']); + + describe('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(this.owner, firstTokenId); + await this.token.$_mint(this.owner, secondTokenId); + this.to = this.other; + }); + + describe('totalSupply', function () { + it('returns total token supply', async function () { + expect(await this.token.totalSupply()).to.equal(2n); + }); + }); + + 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(this.owner, 0n)).to.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 expect(this.token.tokenOfOwnerByIndex(this.owner, 2n)) + .to.be.revertedWithCustomError(this.token, 'ERC721OutOfBoundsIndex') + .withArgs(this.owner, 2n); + }); + }); + + describe('when the given address does not own any token', function () { + it('reverts', async function () { + await expect(this.token.tokenOfOwnerByIndex(this.other, 0n)) + .to.be.revertedWithCustomError(this.token, 'ERC721OutOfBoundsIndex') + .withArgs(this.other, 0n); + }); + }); + + describe('after transferring all tokens to another user', function () { + beforeEach(async function () { + await this.token.connect(this.owner).transferFrom(this.owner, this.other, firstTokenId); + await this.token.connect(this.owner).transferFrom(this.owner, this.other, secondTokenId); + }); + + it('returns correct token IDs for target', async function () { + expect(await this.token.balanceOf(this.other)).to.equal(2n); + + expect(await Promise.all([0n, 1n].map(i => this.token.tokenOfOwnerByIndex(this.other, i)))).to.have.members([ + firstTokenId, + secondTokenId, + ]); + }); + + it('returns empty collection for original owner', async function () { + expect(await this.token.balanceOf(this.owner)).to.equal(0n); + await expect(this.token.tokenOfOwnerByIndex(this.owner, 0n)) + .to.be.revertedWithCustomError(this.token, 'ERC721OutOfBoundsIndex') + .withArgs(this.owner, 0n); + }); + }); + }); + + describe('tokenByIndex', function () { + it('returns all tokens', async function () { + expect(await Promise.all([0n, 1n].map(i => this.token.tokenByIndex(i)))).to.have.members([ + firstTokenId, + secondTokenId, + ]); + }); + + it('reverts if index is greater than supply', async function () { + await expect(this.token.tokenByIndex(2n)) + .to.be.revertedWithCustomError(this.token, 'ERC721OutOfBoundsIndex') + .withArgs(ethers.ZeroAddress, 2n); + }); + + for (const tokenId of [firstTokenId, secondTokenId]) { + it(`returns all tokens after burning token ${tokenId} and minting new tokens`, async function () { + const newTokenId = 300n; + const anotherNewTokenId = 400n; + + await this.token.$_burn(tokenId); + await this.token.$_mint(this.newOwner, newTokenId); + await this.token.$_mint(this.newOwner, anotherNewTokenId); + + expect(await this.token.totalSupply()).to.equal(3n); + + expect(await Promise.all([0n, 1n, 2n].map(i => this.token.tokenByIndex(i)))) + .to.have.members([firstTokenId, secondTokenId, newTokenId, anotherNewTokenId].filter(x => x !== tokenId)) + .to.not.include(tokenId); + }); + } + }); + }); + + describe('_mint(address, uint256)', function () { + it('reverts with a null destination address', async function () { + await expect(this.token.$_mint(ethers.ZeroAddress, firstTokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') + .withArgs(ethers.ZeroAddress); + }); + + describe('with minted token', function () { + beforeEach(async function () { + await this.token.$_mint(this.owner, firstTokenId); + }); + + it('adjusts owner tokens by index', async function () { + expect(await this.token.tokenOfOwnerByIndex(this.owner, 0n)).to.equal(firstTokenId); + }); + + it('adjusts all tokens list', async function () { + expect(await this.token.tokenByIndex(0n)).to.equal(firstTokenId); + }); + }); + }); + + describe('_burn', function () { + it('reverts when burning a non-existent token id', async function () { + await expect(this.token.$_burn(firstTokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(firstTokenId); + }); + + describe('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(this.owner, firstTokenId); + await this.token.$_mint(this.owner, secondTokenId); + }); + + describe('with burnt token', function () { + beforeEach(async function () { + await this.token.$_burn(firstTokenId); + }); + + it('removes that token from the token list of the owner', async function () { + expect(await this.token.tokenOfOwnerByIndex(this.owner, 0n)).to.equal(secondTokenId); + }); + + it('adjusts all tokens list', async function () { + expect(await this.token.tokenByIndex(0n)).to.equal(secondTokenId); + }); + + it('burns all tokens', async function () { + await this.token.$_burn(secondTokenId); + expect(await this.token.totalSupply()).to.equal(0n); + + await expect(this.token.tokenByIndex(0n)) + .to.be.revertedWithCustomError(this.token, 'ERC721OutOfBoundsIndex') + .withArgs(ethers.ZeroAddress, 0n); + }); + }); + }); + }); +} + +function shouldBehaveLikeERC721Metadata(name, symbol) { + shouldSupportInterfaces(['ERC721Metadata']); + + describe('metadata', function () { + 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); + }); + + describe('token URI', function () { + beforeEach(async function () { + await this.token.$_mint(this.owner, firstTokenId); + }); + + it('return empty string by default', async function () { + expect(await this.token.tokenURI(firstTokenId)).to.equal(''); + }); + + it('reverts when queried for non existent token id', async function () { + await expect(this.token.tokenURI(nonExistentTokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(nonExistentTokenId); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC721, + shouldBehaveLikeERC721Enumerable, + shouldBehaveLikeERC721Metadata, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js new file mode 100644 index 0000000..1454cb0 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js @@ -0,0 +1,23 @@ +const { ethers } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { shouldBehaveLikeERC721, shouldBehaveLikeERC721Metadata } = require('./ERC721.behavior'); + +const name = 'Non Fungible Token'; +const symbol = 'NFT'; + +async function fixture() { + return { + accounts: await ethers.getSigners(), + token: await ethers.deployContract('$ERC721', [name, symbol]), + }; +} + +describe('ERC721', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeERC721(); + shouldBehaveLikeERC721Metadata(name, symbol); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js new file mode 100644 index 0000000..a3bdea7 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js @@ -0,0 +1,28 @@ +const { ethers } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { + shouldBehaveLikeERC721, + shouldBehaveLikeERC721Metadata, + shouldBehaveLikeERC721Enumerable, +} = require('./ERC721.behavior'); + +const name = 'Non Fungible Token'; +const symbol = 'NFT'; + +async function fixture() { + return { + accounts: await ethers.getSigners(), + token: await ethers.deployContract('$ERC721Enumerable', [name, symbol]), + }; +} + +describe('ERC721', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeERC721(); + shouldBehaveLikeERC721Metadata(name, symbol); + shouldBehaveLikeERC721Enumerable(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js new file mode 100644 index 0000000..d6f0b80 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js @@ -0,0 +1,77 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const name = 'Non Fungible Token'; +const symbol = 'NFT'; +const tokenId = 1n; +const otherTokenId = 2n; +const unknownTokenId = 3n; + +async function fixture() { + const [owner, approved, another] = await ethers.getSigners(); + const token = await ethers.deployContract('$ERC721Burnable', [name, symbol]); + return { owner, approved, another, token }; +} + +describe('ERC721Burnable', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('like a burnable ERC721', function () { + beforeEach(async function () { + await this.token.$_mint(this.owner, tokenId); + await this.token.$_mint(this.owner, otherTokenId); + }); + + describe('burn', function () { + describe('when successful', function () { + it('emits a burn event, burns the given token ID and adjusts the balance of the owner', async function () { + const balanceBefore = await this.token.balanceOf(this.owner); + + await expect(this.token.connect(this.owner).burn(tokenId)) + .to.emit(this.token, 'Transfer') + .withArgs(this.owner, ethers.ZeroAddress, tokenId); + + await expect(this.token.ownerOf(tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(tokenId); + + expect(await this.token.balanceOf(this.owner)).to.equal(balanceBefore - 1n); + }); + }); + + describe('when there is a previous approval burned', function () { + beforeEach(async function () { + await this.token.connect(this.owner).approve(this.approved, tokenId); + await this.token.connect(this.owner).burn(tokenId); + }); + + describe('getApproved', function () { + it('reverts', async function () { + await expect(this.token.getApproved(tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(tokenId); + }); + }); + }); + + describe('when there is no previous approval burned', function () { + it('reverts', async function () { + await expect(this.token.connect(this.another).burn(tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721InsufficientApproval') + .withArgs(this.another, tokenId); + }); + }); + + describe('when the given token ID was not tracked by this contract', function () { + it('reverts', async function () { + await expect(this.token.connect(this.owner).burn(unknownTokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(unknownTokenId); + }); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.t.sol new file mode 100644 index 0000000..eca15e7 --- /dev/null +++ b/typescript/packages/account-modules/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/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js new file mode 100644 index 0000000..8d8a303 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js @@ -0,0 +1,228 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { sum } = require('../../../helpers/math'); + +const name = 'Non Fungible Token'; +const symbol = 'NFT'; + +describe('ERC721Consecutive', function () { + for (const offset of [0n, 1n, 42n]) { + describe(`with offset ${offset}`, function () { + async function fixture() { + const accounts = await ethers.getSigners(); + const [alice, bruce, chris, receiver] = accounts; + + const batches = [ + { receiver: alice, amount: 0n }, + { receiver: alice, amount: 1n }, + { receiver: alice, amount: 2n }, + { receiver: bruce, amount: 5n }, + { receiver: chris, amount: 0n }, + { receiver: alice, amount: 7n }, + ]; + const delegates = [alice, chris]; + + const token = await ethers.deployContract('$ERC721ConsecutiveMock', [ + name, + symbol, + offset, + delegates, + batches.map(({ receiver }) => receiver), + batches.map(({ amount }) => amount), + ]); + + return { accounts, alice, bruce, chris, receiver, batches, delegates, token }; + } + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('minting during construction', function () { + it('events are emitted at construction', async function () { + let first = offset; + for (const batch of this.batches) { + if (batch.amount > 0) { + await expect(this.token.deploymentTransaction()) + .to.emit(this.token, 'ConsecutiveTransfer') + .withArgs( + first /* fromTokenId */, + first + batch.amount - 1n /* toTokenId */, + ethers.ZeroAddress /* fromAddress */, + batch.receiver /* toAddress */, + ); + } else { + // ".to.not.emit" only looks at event name, and doesn't check the parameters + } + first += batch.amount; + } + }); + + it('ownership is set', async function () { + const owners = [ + ...Array(Number(offset)).fill(ethers.ZeroAddress), + ...this.batches.flatMap(({ receiver, amount }) => Array(Number(amount)).fill(receiver.address)), + ]; + + for (const tokenId in owners) { + if (owners[tokenId] != ethers.ZeroAddress) { + expect(await this.token.ownerOf(tokenId)).to.equal(owners[tokenId]); + } + } + }); + + it('balance & voting power are set', async function () { + for (const account of this.accounts) { + const balance = + sum(...this.batches.filter(({ receiver }) => receiver === account).map(({ amount }) => amount)) ?? 0n; + + expect(await this.token.balanceOf(account)).to.equal(balance); + + // If not delegated at construction, check before + do delegation + if (!this.delegates.includes(account)) { + expect(await this.token.getVotes(account)).to.equal(0n); + + await this.token.connect(account).delegate(account); + } + + // At this point all accounts should have delegated + expect(await this.token.getVotes(account)).to.equal(balance); + } + }); + + it('reverts on consecutive minting to the zero address', async function () { + await expect( + ethers.deployContract('$ERC721ConsecutiveMock', [ + name, + symbol, + offset, + this.delegates, + [ethers.ZeroAddress], + [10], + ]), + ) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') + .withArgs(ethers.ZeroAddress); + }); + }); + + describe('minting after construction', function () { + it('consecutive minting is not possible after construction', async function () { + await expect(this.token.$_mintConsecutive(this.alice, 10)).to.be.revertedWithCustomError( + this.token, + 'ERC721ForbiddenBatchMint', + ); + }); + + it('simple minting is possible after construction', async function () { + const tokenId = sum(...this.batches.map(b => b.amount)) + offset; + + await expect(this.token.ownerOf(tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(tokenId); + + await expect(this.token.$_mint(this.alice, tokenId)) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.alice, tokenId); + }); + + it('cannot mint a token that has been batched minted', async function () { + const tokenId = sum(...this.batches.map(b => b.amount)) + offset - 1n; + + expect(await this.token.ownerOf(tokenId)).to.not.equal(ethers.ZeroAddress); + + await expect(this.token.$_mint(this.alice, tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721InvalidSender') + .withArgs(ethers.ZeroAddress); + }); + }); + + describe('ERC721 behavior', function () { + const tokenId = offset + 1n; + + it('core takes over ownership on transfer', async function () { + await this.token.connect(this.alice).transferFrom(this.alice, this.receiver, tokenId); + + expect(await this.token.ownerOf(tokenId)).to.equal(this.receiver); + }); + + it('tokens can be burned and re-minted #1', async function () { + await expect(this.token.connect(this.alice).$_burn(tokenId)) + .to.emit(this.token, 'Transfer') + .withArgs(this.alice, ethers.ZeroAddress, tokenId); + + await expect(this.token.ownerOf(tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(tokenId); + + await expect(this.token.$_mint(this.bruce, tokenId)) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.bruce, tokenId); + + expect(await this.token.ownerOf(tokenId)).to.equal(this.bruce); + }); + + it('tokens can be burned and re-minted #2', async function () { + const tokenId = sum(...this.batches.map(({ amount }) => amount)) + offset; + + await expect(this.token.ownerOf(tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(tokenId); + + // mint + await expect(this.token.$_mint(this.alice, tokenId)) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.alice, tokenId); + + expect(await this.token.ownerOf(tokenId)).to.equal(this.alice); + + // burn + await expect(await this.token.$_burn(tokenId)) + .to.emit(this.token, 'Transfer') + .withArgs(this.alice, ethers.ZeroAddress, tokenId); + + await expect(this.token.ownerOf(tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(tokenId); + + // re-mint + await expect(this.token.$_mint(this.bruce, tokenId)) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.bruce, tokenId); + + expect(await this.token.ownerOf(tokenId)).to.equal(this.bruce); + }); + }); + }); + } + + describe('invalid use', function () { + const receiver = ethers.Wallet.createRandom(); + + it('cannot mint a batch larger than 5000', async function () { + const factory = await ethers.getContractFactory('$ERC721ConsecutiveMock'); + + await expect(ethers.deployContract('$ERC721ConsecutiveMock', [name, symbol, 0, [], [receiver], [5001n]])) + .to.be.revertedWithCustomError(factory, 'ERC721ExceededMaxBatchMint') + .withArgs(5001n, 5000n); + }); + + it('cannot use single minting during construction', async function () { + const factory = await ethers.getContractFactory('$ERC721ConsecutiveNoConstructorMintMock'); + + await expect( + ethers.deployContract('$ERC721ConsecutiveNoConstructorMintMock', [name, symbol]), + ).to.be.revertedWithCustomError(factory, 'ERC721ForbiddenMint'); + }); + + it('consecutive mint not compatible with enumerability', async function () { + const factory = await ethers.getContractFactory('$ERC721ConsecutiveEnumerableMock'); + + await expect( + ethers.deployContract('$ERC721ConsecutiveEnumerableMock', [name, symbol, [receiver], [100n]]), + ).to.be.revertedWithCustomError(factory, 'ERC721EnumerableForbiddenBatchMint'); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js new file mode 100644 index 0000000..acf731a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js @@ -0,0 +1,81 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const name = 'Non Fungible Token'; +const symbol = 'NFT'; +const tokenId = 1n; +const otherTokenId = 2n; +const data = ethers.Typed.bytes('0x42'); + +async function fixture() { + const [owner, receiver, operator] = await ethers.getSigners(); + const token = await ethers.deployContract('$ERC721Pausable', [name, symbol]); + return { owner, receiver, operator, token }; +} + +describe('ERC721Pausable', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('when token is paused', function () { + beforeEach(async function () { + await this.token.$_mint(this.owner, tokenId); + await this.token.$_pause(); + }); + + it('reverts when trying to transferFrom', async function () { + await expect( + this.token.connect(this.owner).transferFrom(this.owner, this.receiver, tokenId), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); + }); + + it('reverts when trying to safeTransferFrom', async function () { + await expect( + this.token.connect(this.owner).safeTransferFrom(this.owner, this.receiver, tokenId), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); + }); + + it('reverts when trying to safeTransferFrom with data', async function () { + await expect( + this.token.connect(this.owner).safeTransferFrom(this.owner, this.receiver, tokenId, data), + ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); + }); + + it('reverts when trying to mint', async function () { + await expect(this.token.$_mint(this.receiver, otherTokenId)).to.be.revertedWithCustomError( + this.token, + 'EnforcedPause', + ); + }); + + it('reverts when trying to burn', async function () { + await expect(this.token.$_burn(tokenId)).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); + }); + + describe('getApproved', function () { + it('returns approved address', async function () { + expect(await this.token.getApproved(tokenId)).to.equal(ethers.ZeroAddress); + }); + }); + + describe('balanceOf', function () { + it('returns the amount of tokens owned by the given address', async function () { + expect(await this.token.balanceOf(this.owner)).to.equal(1n); + }); + }); + + describe('ownerOf', function () { + it('returns the amount of tokens owned by the given address', async function () { + expect(await this.token.ownerOf(tokenId)).to.equal(this.owner); + }); + }); + + describe('isApprovedForAll', function () { + it('returns the approval of the operator', async function () { + expect(await this.token.isApprovedForAll(this.owner, this.operator)).to.be.false; + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js new file mode 100644 index 0000000..e11954a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js @@ -0,0 +1,57 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { shouldBehaveLikeERC2981 } = require('../../common/ERC2981.behavior'); + +const name = 'Non Fungible Token'; +const symbol = 'NFT'; + +const tokenId1 = 1n; +const tokenId2 = 2n; +const royalty = 200n; +const salePrice = 1000n; + +async function fixture() { + const [account1, account2, recipient] = await ethers.getSigners(); + + const token = await ethers.deployContract('$ERC721Royalty', [name, symbol]); + await token.$_mint(account1, tokenId1); + await token.$_mint(account1, tokenId2); + + return { account1, account2, recipient, token }; +} + +describe('ERC721Royalty', function () { + beforeEach(async function () { + Object.assign( + this, + await loadFixture(fixture), + { tokenId1, tokenId2, royalty, salePrice }, // set for behavior tests + ); + }); + + describe('token specific functions', function () { + beforeEach(async function () { + await this.token.$_setTokenRoyalty(tokenId1, this.recipient, royalty); + }); + + it('royalty information are kept during burn and re-mint', async function () { + await this.token.$_burn(tokenId1); + + expect(await this.token.royaltyInfo(tokenId1, salePrice)).to.deep.equal([ + this.recipient.address, + (salePrice * royalty) / 10000n, + ]); + + await this.token.$_mint(this.account2, tokenId1); + + expect(await this.token.royaltyInfo(tokenId1, salePrice)).to.deep.equal([ + this.recipient.address, + (salePrice * royalty) / 10000n, + ]); + }); + }); + + shouldBehaveLikeERC2981(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js new file mode 100644 index 0000000..830c13a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js @@ -0,0 +1,121 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); + +const name = 'Non Fungible Token'; +const symbol = 'NFT'; +const baseURI = 'https://api.example.com/v1/'; +const otherBaseURI = 'https://api.example.com/v2/'; +const sampleUri = 'mock://mytoken'; +const tokenId = 1n; +const nonExistentTokenId = 2n; + +async function fixture() { + const [owner] = await ethers.getSigners(); + const token = await ethers.deployContract('$ERC721URIStorageMock', [name, symbol]); + return { owner, token }; +} + +describe('ERC721URIStorage', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldSupportInterfaces(['0x49064906']); + + describe('token URI', function () { + beforeEach(async function () { + await this.token.$_mint(this.owner, tokenId); + }); + + it('it is empty by default', async function () { + expect(await this.token.tokenURI(tokenId)).to.equal(''); + }); + + it('reverts when queried for non existent token id', async function () { + await expect(this.token.tokenURI(nonExistentTokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(nonExistentTokenId); + }); + + it('can be set for a token id', async function () { + await this.token.$_setTokenURI(tokenId, sampleUri); + expect(await this.token.tokenURI(tokenId)).to.equal(sampleUri); + }); + + it('setting the uri emits an event', async function () { + await expect(this.token.$_setTokenURI(tokenId, sampleUri)) + .to.emit(this.token, 'MetadataUpdate') + .withArgs(tokenId); + }); + + it('setting the uri for non existent token id is allowed', async function () { + await expect(await this.token.$_setTokenURI(nonExistentTokenId, sampleUri)) + .to.emit(this.token, 'MetadataUpdate') + .withArgs(nonExistentTokenId); + + // value will be accessible after mint + await this.token.$_mint(this.owner, nonExistentTokenId); + expect(await this.token.tokenURI(nonExistentTokenId)).to.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(tokenId, sampleUri); + + expect(await this.token.tokenURI(tokenId)).to.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(tokenId, sampleUri); + + await this.token.setBaseURI(otherBaseURI); + expect(await this.token.tokenURI(tokenId)).to.equal(otherBaseURI + 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(tokenId)).to.equal(baseURI + tokenId); + }); + + it('tokens without URI can be burnt ', async function () { + await this.token.$_burn(tokenId); + + await expect(this.token.tokenURI(tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(tokenId); + }); + + it('tokens with URI can be burnt ', async function () { + await this.token.$_setTokenURI(tokenId, sampleUri); + + await this.token.$_burn(tokenId); + + await expect(this.token.tokenURI(tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(tokenId); + }); + + it('tokens URI is kept if token is burnt and reminted ', async function () { + await this.token.$_setTokenURI(tokenId, sampleUri); + + await this.token.$_burn(tokenId); + + await expect(this.token.tokenURI(tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') + .withArgs(tokenId); + + await this.token.$_mint(this.owner, tokenId); + expect(await this.token.tokenURI(tokenId)).to.equal(sampleUri); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js new file mode 100644 index 0000000..dcae1b8 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js @@ -0,0 +1,194 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers'); + +const time = require('../../../helpers/time'); + +const { shouldBehaveLikeVotes } = require('../../../governance/utils/Votes.behavior'); + +const TOKENS = [ + { Token: '$ERC721Votes', mode: 'blocknumber' }, + // no timestamp mode for ERC721Votes yet +]; + +const name = 'My Vote'; +const symbol = 'MTKN'; +const version = '1'; +const tokens = [ethers.parseEther('10000000'), 10n, 20n, 30n]; + +describe('ERC721Votes', function () { + for (const { Token, mode } of TOKENS) { + const fixture = async () => { + // accounts is required by shouldBehaveLikeVotes + const accounts = await ethers.getSigners(); + const [holder, recipient, other1, other2] = accounts; + + const token = await ethers.deployContract(Token, [name, symbol, name, version]); + + return { accounts, holder, recipient, other1, other2, token }; + }; + + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + this.votes = this.token; + }); + + // includes ERC6372 behavior check + shouldBehaveLikeVotes(tokens, { mode, fungible: false }); + + describe('balanceOf', function () { + beforeEach(async function () { + await this.votes.$_mint(this.holder, tokens[0]); + await this.votes.$_mint(this.holder, tokens[1]); + await this.votes.$_mint(this.holder, tokens[2]); + await this.votes.$_mint(this.holder, tokens[3]); + }); + + it('grants to initial account', async function () { + expect(await this.votes.balanceOf(this.holder)).to.equal(4n); + }); + }); + + describe('transfers', function () { + beforeEach(async function () { + await this.votes.$_mint(this.holder, tokens[0]); + }); + + it('no delegation', async function () { + await expect(this.votes.connect(this.holder).transferFrom(this.holder, this.recipient, tokens[0])) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.recipient, tokens[0]) + .to.not.emit(this.token, 'DelegateVotesChanged'); + + this.holderVotes = 0n; + this.recipientVotes = 0n; + }); + + it('sender delegation', async function () { + await this.votes.connect(this.holder).delegate(this.holder); + + const tx = await this.votes.connect(this.holder).transferFrom(this.holder, this.recipient, tokens[0]); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.recipient, tokens[0]) + .to.emit(this.token, 'DelegateVotesChanged') + .withArgs(this.holder, 1n, 0n); + + const { logs } = await tx.wait(); + const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged'); + for (const event of logs.filter(event => event.fragment.name == 'Transfer')) { + expect(event.index).to.lt(index); + } + + this.holderVotes = 0n; + this.recipientVotes = 0n; + }); + + it('receiver delegation', async function () { + await this.votes.connect(this.recipient).delegate(this.recipient); + + const tx = await this.votes.connect(this.holder).transferFrom(this.holder, this.recipient, tokens[0]); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.recipient, tokens[0]) + .to.emit(this.token, 'DelegateVotesChanged') + .withArgs(this.recipient, 0n, 1n); + + const { logs } = await tx.wait(); + const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged'); + for (const event of logs.filter(event => event.fragment.name == 'Transfer')) { + expect(event.index).to.lt(index); + } + + this.holderVotes = 0n; + this.recipientVotes = 1n; + }); + + it('full delegation', async function () { + await this.votes.connect(this.holder).delegate(this.holder); + await this.votes.connect(this.recipient).delegate(this.recipient); + + const tx = await this.votes.connect(this.holder).transferFrom(this.holder, this.recipient, tokens[0]); + await expect(tx) + .to.emit(this.token, 'Transfer') + .withArgs(this.holder, this.recipient, tokens[0]) + .to.emit(this.token, 'DelegateVotesChanged') + .withArgs(this.holder, 1n, 0n) + .to.emit(this.token, 'DelegateVotesChanged') + .withArgs(this.recipient, 0n, 1n); + + const { logs } = await tx.wait(); + const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged'); + for (const event of logs.filter(event => event.fragment.name == 'Transfer')) { + expect(event.index).to.lt(index); + } + + this.holderVotes = 0; + this.recipientVotes = 1n; + }); + + it('returns the same total supply on transfers', async function () { + await this.votes.connect(this.holder).delegate(this.holder); + + const tx = await this.votes.connect(this.holder).transferFrom(this.holder, this.recipient, tokens[0]); + const timepoint = await time.clockFromReceipt[mode](tx); + + await mine(2); + + expect(await this.votes.getPastTotalSupply(timepoint - 1n)).to.equal(1n); + expect(await this.votes.getPastTotalSupply(timepoint + 1n)).to.equal(1n); + + this.holderVotes = 0n; + this.recipientVotes = 0n; + }); + + it('generally returns the voting balance at the appropriate checkpoint', async function () { + await this.votes.$_mint(this.holder, tokens[1]); + await this.votes.$_mint(this.holder, tokens[2]); + await this.votes.$_mint(this.holder, tokens[3]); + + const total = await this.votes.balanceOf(this.holder); + + const t1 = await this.votes.connect(this.holder).delegate(this.other1); + await mine(2); + const t2 = await this.votes.connect(this.holder).transferFrom(this.holder, this.other2, tokens[0]); + await mine(2); + const t3 = await this.votes.connect(this.holder).transferFrom(this.holder, this.other2, tokens[2]); + await mine(2); + const t4 = await this.votes.connect(this.other2).transferFrom(this.other2, this.holder, tokens[2]); + await mine(2); + + t1.timepoint = await time.clockFromReceipt[mode](t1); + t2.timepoint = await time.clockFromReceipt[mode](t2); + t3.timepoint = await time.clockFromReceipt[mode](t3); + t4.timepoint = await time.clockFromReceipt[mode](t4); + + expect(await this.votes.getPastVotes(this.other1, t1.timepoint - 1n)).to.equal(0n); + expect(await this.votes.getPastVotes(this.other1, t1.timepoint)).to.equal(total); + expect(await this.votes.getPastVotes(this.other1, t1.timepoint + 1n)).to.equal(total); + expect(await this.votes.getPastVotes(this.other1, t2.timepoint)).to.equal(3n); + expect(await this.votes.getPastVotes(this.other1, t2.timepoint + 1n)).to.equal(3n); + expect(await this.votes.getPastVotes(this.other1, t3.timepoint)).to.equal(2n); + expect(await this.votes.getPastVotes(this.other1, t3.timepoint + 1n)).to.equal(2n); + expect(await this.votes.getPastVotes(this.other1, t4.timepoint)).to.equal('3'); + expect(await this.votes.getPastVotes(this.other1, t4.timepoint + 1n)).to.equal(3n); + + this.holderVotes = 0n; + this.recipientVotes = 0n; + }); + + afterEach(async function () { + expect(await this.votes.getVotes(this.holder)).to.equal(this.holderVotes); + expect(await this.votes.getVotes(this.recipient)).to.equal(this.recipientVotes); + + // need to advance 2 blocks to see the effect of a transfer on "getPastVotes" + const timepoint = await time.clock[mode](); + await mine(); + expect(await this.votes.getPastVotes(this.holder, timepoint)).to.equal(this.holderVotes); + expect(await this.votes.getPastVotes(this.recipient, timepoint)).to.equal(this.recipientVotes); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js new file mode 100644 index 0000000..eeead4c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js @@ -0,0 +1,201 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { shouldBehaveLikeERC721 } = require('../ERC721.behavior'); + +const name = 'Non Fungible Token'; +const symbol = 'NFT'; +const tokenId = 1n; +const otherTokenId = 2n; + +async function fixture() { + const accounts = await ethers.getSigners(); + const [owner, approved, other] = accounts; + + const underlying = await ethers.deployContract('$ERC721', [name, symbol]); + await underlying.$_safeMint(owner, tokenId); + await underlying.$_safeMint(owner, otherTokenId); + const token = await ethers.deployContract('$ERC721Wrapper', [`Wrapped ${name}`, `W${symbol}`, underlying]); + + return { accounts, owner, approved, other, underlying, token }; +} + +describe('ERC721Wrapper', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + 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.equal(this.underlying); + }); + + describe('depositFor', function () { + it('works with token approval', async function () { + await this.underlying.connect(this.owner).approve(this.token, tokenId); + + await expect(this.token.connect(this.owner).depositFor(this.owner, [tokenId])) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.owner, this.token, tokenId) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.owner, tokenId); + }); + + it('works with approval for all', async function () { + await this.underlying.connect(this.owner).setApprovalForAll(this.token, true); + + await expect(this.token.connect(this.owner).depositFor(this.owner, [tokenId])) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.owner, this.token, tokenId) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.owner, tokenId); + }); + + it('works sending to another account', async function () { + await this.underlying.connect(this.owner).approve(this.token, tokenId); + + await expect(this.token.connect(this.owner).depositFor(this.other, [tokenId])) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.owner, this.token, tokenId) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.other, tokenId); + }); + + it('works with multiple tokens', async function () { + await this.underlying.connect(this.owner).approve(this.token, tokenId); + await this.underlying.connect(this.owner).approve(this.token, otherTokenId); + + await expect(this.token.connect(this.owner).depositFor(this.owner, [tokenId, otherTokenId])) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.owner, this.token, tokenId) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.owner, tokenId) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.owner, this.token, otherTokenId) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.owner, otherTokenId); + }); + + it('reverts with missing approval', async function () { + await expect(this.token.connect(this.owner).depositFor(this.owner, [tokenId])) + .to.be.revertedWithCustomError(this.token, 'ERC721InsufficientApproval') + .withArgs(this.token, tokenId); + }); + }); + + describe('withdrawTo', function () { + beforeEach(async function () { + await this.underlying.connect(this.owner).approve(this.token, tokenId); + await this.token.connect(this.owner).depositFor(this.owner, [tokenId]); + }); + + it('works for an owner', async function () { + await expect(this.token.connect(this.owner).withdrawTo(this.owner, [tokenId])) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.token, this.owner, tokenId) + .to.emit(this.token, 'Transfer') + .withArgs(this.owner, ethers.ZeroAddress, tokenId); + }); + + it('works for an approved', async function () { + await this.token.connect(this.owner).approve(this.approved, tokenId); + + await expect(this.token.connect(this.approved).withdrawTo(this.owner, [tokenId])) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.token, this.owner, tokenId) + .to.emit(this.token, 'Transfer') + .withArgs(this.owner, ethers.ZeroAddress, tokenId); + }); + + it('works for an approved for all', async function () { + await this.token.connect(this.owner).setApprovalForAll(this.approved, true); + + await expect(this.token.connect(this.approved).withdrawTo(this.owner, [tokenId])) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.token, this.owner, tokenId) + .to.emit(this.token, 'Transfer') + .withArgs(this.owner, ethers.ZeroAddress, tokenId); + }); + + it("doesn't work for a non-owner nor approved", async function () { + await expect(this.token.connect(this.other).withdrawTo(this.owner, [tokenId])) + .to.be.revertedWithCustomError(this.token, 'ERC721InsufficientApproval') + .withArgs(this.other, tokenId); + }); + + it('works with multiple tokens', async function () { + await this.underlying.connect(this.owner).approve(this.token, otherTokenId); + await this.token.connect(this.owner).depositFor(this.owner, [otherTokenId]); + + await expect(this.token.connect(this.owner).withdrawTo(this.owner, [tokenId, otherTokenId])) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.token, this.owner, tokenId) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.token, this.owner, tokenId) + .to.emit(this.token, 'Transfer') + .withArgs(this.owner, ethers.ZeroAddress, tokenId) + .to.emit(this.token, 'Transfer') + .withArgs(this.owner, ethers.ZeroAddress, tokenId); + }); + + it('works to another account', async function () { + await expect(this.token.connect(this.owner).withdrawTo(this.other, [tokenId])) + .to.emit(this.underlying, 'Transfer') + .withArgs(this.token, this.other, tokenId) + .to.emit(this.token, 'Transfer') + .withArgs(this.owner, ethers.ZeroAddress, tokenId); + }); + }); + + describe('onERC721Received', function () { + it('only allows calls from underlying', async function () { + await expect( + this.token.connect(this.other).onERC721Received( + this.owner, + this.token, + tokenId, + this.other.address, // Correct data + ), + ) + .to.be.revertedWithCustomError(this.token, 'ERC721UnsupportedToken') + .withArgs(this.other); + }); + + it('mints a token to from', async function () { + await expect(this.underlying.connect(this.owner).safeTransferFrom(this.owner, this.token, tokenId)) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.owner, tokenId); + }); + }); + + describe('_recover', function () { + it('works if there is something to recover', async function () { + // Should use `transferFrom` to avoid `onERC721Received` minting + await this.underlying.connect(this.owner).transferFrom(this.owner, this.token, tokenId); + + await expect(this.token.$_recover(this.other, tokenId)) + .to.emit(this.token, 'Transfer') + .withArgs(ethers.ZeroAddress, this.other, tokenId); + }); + + it('reverts if there is nothing to recover', async function () { + const holder = await this.underlying.ownerOf(tokenId); + + await expect(this.token.$_recover(holder, tokenId)) + .to.be.revertedWithCustomError(this.token, 'ERC721IncorrectOwner') + .withArgs(this.token, tokenId, holder); + }); + }); + + describe('ERC712 behavior', function () { + shouldBehaveLikeERC721(); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js new file mode 100644 index 0000000..31dd2fd --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js @@ -0,0 +1,20 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); + +const name = 'Non Fungible Token'; +const symbol = 'NFT'; +const tokenId = 1n; + +describe('ERC721Holder', function () { + it('receives an ERC721 token', async function () { + const [owner] = await ethers.getSigners(); + + const token = await ethers.deployContract('$ERC721', [name, symbol]); + await token.$_mint(owner, tokenId); + + const receiver = await ethers.deployContract('$ERC721Holder'); + await token.connect(owner).safeTransferFrom(owner, receiver, tokenId); + + expect(await token.ownerOf(tokenId)).to.equal(receiver); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Utils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Utils.test.js new file mode 100644 index 0000000..2327d1a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Utils.test.js @@ -0,0 +1,94 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { RevertType } = require('../../../helpers/enums'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +const tokenId = 1n; + +const RECEIVER_MAGIC_VALUE = '0x150b7a02'; + +const deployReceiver = (revertType, returnValue = RECEIVER_MAGIC_VALUE) => + ethers.deployContract('$ERC721ReceiverMock', [returnValue, revertType]); + +const fixture = async () => { + const [eoa, operator, owner] = await ethers.getSigners(); + const utils = await ethers.deployContract('$ERC721Utils'); + + const receivers = { + correct: await deployReceiver(RevertType.None), + invalid: await deployReceiver(RevertType.None, '0xdeadbeef'), + message: await deployReceiver(RevertType.RevertWithMessage), + empty: await deployReceiver(RevertType.RevertWithoutMessage), + customError: await deployReceiver(RevertType.RevertWithCustomError), + panic: await deployReceiver(RevertType.Panic), + nonReceiver: await ethers.deployContract('CallReceiverMock'), + eoa, + }; + + return { operator, owner, utils, receivers }; +}; + +describe('ERC721Utils', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('onERC721Received', function () { + it('succeeds when called by an EOA', async function () { + await expect(this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.eoa, tokenId, '0x')).to + .not.be.reverted; + }); + + it('succeeds when data is passed', async function () { + const data = '0x12345678'; + await expect(this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.correct, tokenId, data)) + .to.not.be.reverted; + }); + + it('succeeds when data is empty', async function () { + await expect(this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.correct, tokenId, '0x')) + .to.not.be.reverted; + }); + + it('reverts when receiver returns invalid value', async function () { + await expect(this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.invalid, tokenId, '0x')) + .to.be.revertedWithCustomError(this.utils, 'ERC721InvalidReceiver') + .withArgs(this.receivers.invalid); + }); + + it('reverts when receiver reverts with message', async function () { + await expect( + this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.message, tokenId, '0x'), + ).to.be.revertedWith('ERC721ReceiverMock: reverting'); + }); + + it('reverts when receiver reverts without message', async function () { + await expect(this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.empty, tokenId, '0x')) + .to.be.revertedWithCustomError(this.utils, 'ERC721InvalidReceiver') + .withArgs(this.receivers.empty); + }); + + it('reverts when receiver reverts with custom error', async function () { + await expect( + this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.customError, tokenId, '0x'), + ) + .to.be.revertedWithCustomError(this.receivers.customError, 'CustomError') + .withArgs(RECEIVER_MAGIC_VALUE); + }); + + it('reverts when receiver panics', async function () { + await expect( + this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.panic, tokenId, '0x'), + ).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO); + }); + + it('reverts when receiver does not implement onERC721Received', async function () { + await expect( + this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.nonReceiver, tokenId, '0x'), + ) + .to.be.revertedWithCustomError(this.utils, 'ERC721InvalidReceiver') + .withArgs(this.receivers.nonReceiver); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js new file mode 100644 index 0000000..ae6abcc --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js @@ -0,0 +1,152 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); + +function shouldBehaveLikeERC2981() { + const royaltyFraction = 10n; + + shouldSupportInterfaces(['ERC2981']); + + describe('default royalty', function () { + beforeEach(async function () { + await this.token.$_setDefaultRoyalty(this.account1, royaltyFraction); + }); + + it('checks royalty is set', async function () { + expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.deep.equal([ + this.account1.address, + (this.salePrice * royaltyFraction) / 10_000n, + ]); + }); + + it('updates royalty amount', async function () { + const newFraction = 25n; + + await this.token.$_setDefaultRoyalty(this.account1, newFraction); + + expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.deep.equal([ + this.account1.address, + (this.salePrice * newFraction) / 10_000n, + ]); + }); + + it('holds same royalty value for different tokens', async function () { + const newFraction = 20n; + + await this.token.$_setDefaultRoyalty(this.account1, newFraction); + + expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.deep.equal( + await this.token.royaltyInfo(this.tokenId2, this.salePrice), + ); + }); + + it('Remove royalty information', async function () { + const newValue = 0n; + await this.token.$_deleteDefaultRoyalty(); + + expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.deep.equal([ethers.ZeroAddress, newValue]); + + expect(await this.token.royaltyInfo(this.tokenId2, this.salePrice)).to.deep.equal([ethers.ZeroAddress, newValue]); + }); + + it('reverts if invalid parameters', async function () { + const royaltyDenominator = await this.token.$_feeDenominator(); + + await expect(this.token.$_setDefaultRoyalty(ethers.ZeroAddress, royaltyFraction)) + .to.be.revertedWithCustomError(this.token, 'ERC2981InvalidDefaultRoyaltyReceiver') + .withArgs(ethers.ZeroAddress); + + const anotherRoyaltyFraction = 11000n; + + await expect(this.token.$_setDefaultRoyalty(this.account1, anotherRoyaltyFraction)) + .to.be.revertedWithCustomError(this.token, 'ERC2981InvalidDefaultRoyalty') + .withArgs(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 newFraction = 25n; + + expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.deep.equal([ + this.account1.address, + (this.salePrice * royaltyFraction) / 10_000n, + ]); + + await this.token.$_setTokenRoyalty(this.tokenId1, this.account1, newFraction); + + expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.deep.equal([ + this.account1.address, + (this.salePrice * newFraction) / 10_000n, + ]); + }); + + it('holds different values for different tokens', async function () { + const newFraction = 20n; + + await this.token.$_setTokenRoyalty(this.tokenId2, this.account1, newFraction); + + expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.not.deep.equal( + await this.token.royaltyInfo(this.tokenId2, this.salePrice), + ); + }); + + it('reverts if invalid parameters', async function () { + const royaltyDenominator = await this.token.$_feeDenominator(); + + await expect(this.token.$_setTokenRoyalty(this.tokenId1, ethers.ZeroAddress, royaltyFraction)) + .to.be.revertedWithCustomError(this.token, 'ERC2981InvalidTokenRoyaltyReceiver') + .withArgs(this.tokenId1, ethers.ZeroAddress); + + const anotherRoyaltyFraction = 11000n; + + await expect(this.token.$_setTokenRoyalty(this.tokenId1, this.account1, anotherRoyaltyFraction)) + .to.be.revertedWithCustomError(this.token, 'ERC2981InvalidTokenRoyalty') + .withArgs(this.tokenId1, anotherRoyaltyFraction, royaltyDenominator); + }); + + it('can reset token after setting royalty', async function () { + const newFraction = 30n; + + await this.token.$_setTokenRoyalty(this.tokenId1, this.account2, newFraction); + + // Tokens must have own information + expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.deep.equal([ + this.account2.address, + (this.salePrice * newFraction) / 10_000n, + ]); + + await this.token.$_setTokenRoyalty(this.tokenId2, this.account1, 0n); + + // Token must not share default information + expect(await this.token.royaltyInfo(this.tokenId2, this.salePrice)).to.deep.equal([this.account1.address, 0n]); + }); + + it('can hold default and token royalty information', async function () { + const newFraction = 30n; + + await this.token.$_setTokenRoyalty(this.tokenId2, this.account2, newFraction); + + // Tokens must not have same values + expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.not.deep.equal([ + this.account2.address, + (this.salePrice * newFraction) / 10_000n, + ]); + + // Updated token must have new values + expect(await this.token.royaltyInfo(this.tokenId2, this.salePrice)).to.deep.equal([ + this.account2.address, + (this.salePrice * newFraction) / 10_000n, + ]); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC2981, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Address.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Address.test.js new file mode 100644 index 0000000..8307a92 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Address.test.js @@ -0,0 +1,281 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +const coder = ethers.AbiCoder.defaultAbiCoder(); + +async function fixture() { + const [recipient, other] = await ethers.getSigners(); + + const mock = await ethers.deployContract('$Address'); + const target = await ethers.deployContract('CallReceiverMock'); + const targetEther = await ethers.deployContract('EtherReceiverMock'); + + return { recipient, other, mock, target, targetEther }; +} + +describe('Address', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('sendValue', function () { + describe('when sender contract has no funds', function () { + it('sends 0 wei', async function () { + await expect(this.mock.$sendValue(this.other, 0n)).to.changeEtherBalance(this.recipient, 0n); + }); + + it('reverts when sending non-zero amounts', async function () { + await expect(this.mock.$sendValue(this.other, 1n)) + .to.be.revertedWithCustomError(this.mock, 'InsufficientBalance') + .withArgs(0n, 1n); + }); + }); + + describe('when sender contract has funds', function () { + const funds = ethers.parseEther('1'); + + beforeEach(async function () { + await this.other.sendTransaction({ to: this.mock, value: funds }); + }); + + describe('with EOA recipient', function () { + it('sends 0 wei', async function () { + await expect(this.mock.$sendValue(this.recipient, 0n)).to.changeEtherBalance(this.recipient, 0n); + }); + + it('sends non-zero amounts', async function () { + await expect(this.mock.$sendValue(this.recipient, funds - 1n)).to.changeEtherBalance( + this.recipient, + funds - 1n, + ); + }); + + it('sends the whole balance', async function () { + await expect(this.mock.$sendValue(this.recipient, funds)).to.changeEtherBalance(this.recipient, funds); + expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); + }); + + it('reverts when sending more than the balance', async function () { + await expect(this.mock.$sendValue(this.recipient, funds + 1n)) + .to.be.revertedWithCustomError(this.mock, 'InsufficientBalance') + .withArgs(funds, funds + 1n); + }); + }); + + describe('with contract recipient', function () { + it('sends funds', async function () { + await this.targetEther.setAcceptEther(true); + await expect(this.mock.$sendValue(this.targetEther, funds)).to.changeEtherBalance(this.targetEther, funds); + }); + + it('reverts on recipient revert', async function () { + await this.targetEther.setAcceptEther(false); + await expect(this.mock.$sendValue(this.targetEther, funds)).to.be.revertedWithCustomError( + this.mock, + 'FailedCall', + ); + }); + }); + }); + }); + + describe('functionCall', function () { + describe('with valid contract receiver', function () { + it('calls the requested function', async function () { + const call = this.target.interface.encodeFunctionData('mockFunction'); + + await expect(this.mock.$functionCall(this.target, call)) + .to.emit(this.target, 'MockFunctionCalled') + .to.emit(this.mock, 'return$functionCall') + .withArgs(coder.encode(['string'], ['0x1234'])); + }); + + it('calls the requested empty return function', async function () { + const call = this.target.interface.encodeFunctionData('mockFunctionEmptyReturn'); + + await expect(this.mock.$functionCall(this.target, call)).to.emit(this.target, 'MockFunctionCalled'); + }); + + it('reverts when the called function reverts with no reason', async function () { + const call = this.target.interface.encodeFunctionData('mockFunctionRevertsNoReason'); + + await expect(this.mock.$functionCall(this.target, call)).to.be.revertedWithCustomError(this.mock, 'FailedCall'); + }); + + it('reverts when the called function reverts, bubbling up the revert reason', async function () { + const call = this.target.interface.encodeFunctionData('mockFunctionRevertsReason'); + + await expect(this.mock.$functionCall(this.target, call)).to.be.revertedWith('CallReceiverMock: reverting'); + }); + + it('reverts when the called function runs out of gas', async function () { + const call = this.target.interface.encodeFunctionData('mockFunctionOutOfGas'); + + await expect(this.mock.$functionCall(this.target, call, { gasLimit: 120_000n })).to.be.revertedWithCustomError( + this.mock, + 'FailedCall', + ); + }); + + it('reverts when the called function throws', async function () { + const call = this.target.interface.encodeFunctionData('mockFunctionThrows'); + + await expect(this.mock.$functionCall(this.target, call)).to.be.revertedWithPanic(PANIC_CODES.ASSERTION_ERROR); + }); + + it('reverts when function does not exist', async function () { + const call = new ethers.Interface(['function mockFunctionDoesNotExist()']).encodeFunctionData( + 'mockFunctionDoesNotExist', + ); + + await expect(this.mock.$functionCall(this.target, call)).to.be.revertedWithCustomError(this.mock, 'FailedCall'); + }); + }); + + describe('with non-contract receiver', function () { + it('reverts when address is not a contract', async function () { + const call = this.target.interface.encodeFunctionData('mockFunction'); + + await expect(this.mock.$functionCall(this.recipient, call)) + .to.be.revertedWithCustomError(this.mock, 'AddressEmptyCode') + .withArgs(this.recipient); + }); + }); + }); + + describe('functionCallWithValue', function () { + describe('with zero value', function () { + it('calls the requested function', async function () { + const call = this.target.interface.encodeFunctionData('mockFunction'); + + await expect(this.mock.$functionCallWithValue(this.target, call, 0n)) + .to.emit(this.target, 'MockFunctionCalled') + .to.emit(this.mock, 'return$functionCallWithValue') + .withArgs(coder.encode(['string'], ['0x1234'])); + }); + }); + + describe('with non-zero value', function () { + const value = ethers.parseEther('1.2'); + + it('reverts if insufficient sender balance', async function () { + const call = this.target.interface.encodeFunctionData('mockFunction'); + + await expect(this.mock.$functionCallWithValue(this.target, call, value)) + .to.be.revertedWithCustomError(this.mock, 'InsufficientBalance') + .withArgs(0n, value); + }); + + it('calls the requested function with existing value', async function () { + await this.other.sendTransaction({ to: this.mock, value }); + + const call = this.target.interface.encodeFunctionData('mockFunction'); + const tx = await this.mock.$functionCallWithValue(this.target, call, value); + + await expect(tx).to.changeEtherBalance(this.target, value); + + await expect(tx) + .to.emit(this.target, 'MockFunctionCalled') + .to.emit(this.mock, 'return$functionCallWithValue') + .withArgs(coder.encode(['string'], ['0x1234'])); + }); + + it('calls the requested function with transaction funds', async function () { + expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); + + const call = this.target.interface.encodeFunctionData('mockFunction'); + const tx = await this.mock.connect(this.other).$functionCallWithValue(this.target, call, value, { value }); + + await expect(tx).to.changeEtherBalance(this.target, value); + await expect(tx) + .to.emit(this.target, 'MockFunctionCalled') + .to.emit(this.mock, 'return$functionCallWithValue') + .withArgs(coder.encode(['string'], ['0x1234'])); + }); + + it('reverts when calling non-payable functions', async function () { + await this.other.sendTransaction({ to: this.mock, value }); + + const call = this.target.interface.encodeFunctionData('mockFunctionNonPayable'); + + await expect(this.mock.$functionCallWithValue(this.target, call, value)).to.be.revertedWithCustomError( + this.mock, + 'FailedCall', + ); + }); + }); + }); + + describe('functionStaticCall', function () { + it('calls the requested function', async function () { + const call = this.target.interface.encodeFunctionData('mockStaticFunction'); + + expect(await this.mock.$functionStaticCall(this.target, call)).to.equal(coder.encode(['string'], ['0x1234'])); + }); + + it('reverts on a non-static function', async function () { + const call = this.target.interface.encodeFunctionData('mockFunction'); + + await expect(this.mock.$functionStaticCall(this.target, call)).to.be.revertedWithCustomError( + this.mock, + 'FailedCall', + ); + }); + + it('bubbles up revert reason', async function () { + const call = this.target.interface.encodeFunctionData('mockFunctionRevertsReason'); + + await expect(this.mock.$functionStaticCall(this.target, call)).to.be.revertedWith('CallReceiverMock: reverting'); + }); + + it('reverts when address is not a contract', async function () { + const call = this.target.interface.encodeFunctionData('mockFunction'); + + await expect(this.mock.$functionStaticCall(this.recipient, call)) + .to.be.revertedWithCustomError(this.mock, 'AddressEmptyCode') + .withArgs(this.recipient); + }); + }); + + describe('functionDelegateCall', function () { + it('delegate calls the requested function', async function () { + const slot = ethers.hexlify(ethers.randomBytes(32)); + const value = ethers.hexlify(ethers.randomBytes(32)); + + const call = this.target.interface.encodeFunctionData('mockFunctionWritesStorage', [slot, value]); + + expect(await ethers.provider.getStorage(this.mock, slot)).to.equal(ethers.ZeroHash); + + await expect(await this.mock.$functionDelegateCall(this.target, call)) + .to.emit(this.mock, 'return$functionDelegateCall') + .withArgs(coder.encode(['string'], ['0x1234'])); + + expect(await ethers.provider.getStorage(this.mock, slot)).to.equal(value); + }); + + it('bubbles up revert reason', async function () { + const call = this.target.interface.encodeFunctionData('mockFunctionRevertsReason'); + + await expect(this.mock.$functionDelegateCall(this.target, call)).to.be.revertedWith( + 'CallReceiverMock: reverting', + ); + }); + + it('reverts when address is not a contract', async function () { + const call = this.target.interface.encodeFunctionData('mockFunction'); + + await expect(this.mock.$functionDelegateCall(this.recipient, call)) + .to.be.revertedWithCustomError(this.mock, 'AddressEmptyCode') + .withArgs(this.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/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.t.sol new file mode 100644 index 0000000..e45d29c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.t.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {SymTest} from "halmos-cheatcodes/SymTest.sol"; +import {Arrays} from "@openzeppelin/contracts/utils/Arrays.sol"; + +contract ArraysTest is Test, SymTest { + function testSort(uint256[] memory values) public pure { + Arrays.sort(values); + _assertSort(values); + } + + function symbolicSort() public pure { + uint256[] memory values = new uint256[](3); + for (uint256 i = 0; i < 3; i++) { + values[i] = svm.createUint256("arrayElement"); + } + Arrays.sort(values); + _assertSort(values); + } + + /// Asserts + + function _assertSort(uint256[] memory values) internal pure { + for (uint256 i = 1; i < values.length; ++i) { + assertLe(values[i - 1], values[i]); + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.test.js new file mode 100644 index 0000000..a4bc9d7 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.test.js @@ -0,0 +1,227 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { generators } = require('../helpers/random'); +const { capitalize } = require('../../scripts/helpers'); +const { TYPES } = require('../../scripts/generate/templates/Arrays.opts'); + +// See https://en.cppreference.com/w/cpp/algorithm/lower_bound +const lowerBound = (array, value) => { + const i = array.findIndex(element => value <= element); + return i == -1 ? array.length : i; +}; + +// See https://en.cppreference.com/w/cpp/algorithm/upper_bound +const upperBound = (array, value) => { + const i = array.findIndex(element => value < element); + return i == -1 ? array.length : i; +}; + +const bigintSign = x => (x > 0n ? 1 : x < 0n ? -1 : 0); +const comparator = (a, b) => bigintSign(ethers.toBigInt(a) - ethers.toBigInt(b)); +const hasDuplicates = array => array.some((v, i) => array.indexOf(v) != i); + +describe('Arrays', function () { + const fixture = async () => { + return { mock: await ethers.deployContract('$Arrays') }; + }; + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('search', function () { + for (const [title, { array, tests }] of Object.entries({ + 'Even number of elements': { + array: [11n, 12n, 13n, 14n, 15n, 16n, 17n, 18n, 19n, 20n], + tests: { + 'basic case': 16n, + 'first element': 11n, + 'last element': 20n, + 'searched value is over the upper boundary': 32n, + 'searched value is under the lower boundary': 2n, + }, + }, + 'Odd number of elements': { + array: [11n, 12n, 13n, 14n, 15n, 16n, 17n, 18n, 19n, 20n, 21n], + tests: { + 'basic case': 16n, + 'first element': 11n, + 'last element': 21n, + 'searched value is over the upper boundary': 32n, + 'searched value is under the lower boundary': 2n, + }, + }, + 'Array with gap': { + array: [11n, 12n, 13n, 14n, 15n, 20n, 21n, 22n, 23n, 24n], + tests: { + 'search value in gap': 17n, + }, + }, + 'Array with duplicated elements': { + array: [0n, 10n, 10n, 10n, 10n, 10n, 10n, 10n, 20n], + tests: { + 'search value is duplicated': 10n, + }, + }, + 'Array with duplicated first element': { + array: [10n, 10n, 10n, 10n, 10n, 10n, 10n, 20n], + tests: { + 'search value is duplicated first element': 10n, + }, + }, + 'Array with duplicated last element': { + array: [0n, 10n, 10n, 10n, 10n, 10n, 10n, 10n], + tests: { + 'search value is duplicated last element': 10n, + }, + }, + 'Empty array': { + array: [], + tests: { + 'always returns 0 for empty array': 10n, + }, + }, + })) { + describe(title, function () { + const fixture = async () => { + return { instance: await ethers.deployContract('Uint256ArraysMock', [array]) }; + }; + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + for (const [name, input] of Object.entries(tests)) { + describe(name, function () { + it('[deprecated] findUpperBound', async function () { + // findUpperBound does not support duplicated + if (hasDuplicates(array)) { + expect(await this.instance.findUpperBound(input)).to.equal(upperBound(array, input) - 1); + } else { + expect(await this.instance.findUpperBound(input)).to.equal(lowerBound(array, input)); + } + }); + + it('lowerBound', async function () { + expect(await this.instance.lowerBound(input)).to.equal(lowerBound(array, input)); + expect(await this.instance.lowerBoundMemory(array, input)).to.equal(lowerBound(array, input)); + }); + + it('upperBound', async function () { + expect(await this.instance.upperBound(input)).to.equal(upperBound(array, input)); + expect(await this.instance.upperBoundMemory(array, input)).to.equal(upperBound(array, input)); + }); + }); + } + }); + } + }); + + for (const { name, isValueType } of TYPES) { + const elements = Array.from({ length: 10 }, generators[name]); + + describe(name, function () { + const fixture = async () => { + return { instance: await ethers.deployContract(`${capitalize(name)}ArraysMock`, [elements]) }; + }; + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + if (isValueType) { + describe('sort', function () { + for (const length of [0, 1, 2, 8, 32, 128]) { + describe(`${name}[] of length ${length}`, function () { + beforeEach(async function () { + this.array = Array.from({ length }, generators[name]); + }); + + afterEach(async function () { + const expected = Array.from(this.array).sort(comparator); + const reversed = Array.from(expected).reverse(); + expect(await this.instance.sort(this.array)).to.deep.equal(expected); + expect(await this.instance.sortReverse(this.array)).to.deep.equal(reversed); + }); + + it('sort array', async function () { + // nothing to do here, beforeEach and afterEach already take care of everything. + }); + + if (length > 1) { + it('sort array for identical elements', async function () { + // duplicate the first value to all elements + this.array.fill(this.array.at(0)); + }); + + it('sort already sorted array', async function () { + // pre-sort the elements + this.array.sort(comparator); + }); + + it('sort reversed array', async function () { + // pre-sort in reverse order + this.array.sort(comparator).reverse(); + }); + + it('sort almost sorted array', async function () { + // pre-sort + rotate (move the last element to the front) for an almost sorted effect + this.array.sort(comparator); + this.array.unshift(this.array.pop()); + }); + } + }); + } + }); + } + + describe('unsafeAccess', function () { + describe('storage', function () { + for (const i in elements) { + it(`unsafeAccess within bounds #${i}`, async function () { + expect(await this.instance.unsafeAccess(i)).to.equal(elements[i]); + }); + } + + it('unsafeAccess outside bounds', async function () { + await expect(this.instance.unsafeAccess(elements.length)).to.not.be.rejected; + }); + + it('unsafeSetLength changes the length or the array', async function () { + const newLength = generators.uint256(); + + expect(await this.instance.length()).to.equal(elements.length); + await expect(this.instance.unsafeSetLength(newLength)).to.not.be.rejected; + expect(await this.instance.length()).to.equal(newLength); + }); + }); + + describe('memory', function () { + const fragment = `$unsafeMemoryAccess(${name}[] arr, uint256 pos)`; + + for (const i in elements) { + it(`unsafeMemoryAccess within bounds #${i}`, async function () { + expect(await this.mock[fragment](elements, i)).to.equal(elements[i]); + }); + } + + it('unsafeMemoryAccess outside bounds', async function () { + await expect(this.mock[fragment](elements, elements.length)).to.not.be.rejected; + }); + + it('unsafeMemoryAccess loop around', async function () { + for (let i = 251n; i < 256n; ++i) { + expect(await this.mock[fragment](elements, 2n ** i - 1n)).to.equal( + isValueType ? BigInt(elements.length) : generators[name].zero, + ); + expect(await this.mock[fragment](elements, 2n ** i + 0n)).to.equal(elements[0]); + expect(await this.mock[fragment](elements, 2n ** i + 1n)).to.equal(elements[1]); + } + }); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.t.sol new file mode 100644 index 0000000..b8aa7ac --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.t.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {Base64} from "@openzeppelin/contracts/utils/Base64.sol"; + +contract Base64Test is Test { + function testEncode(bytes memory input) external pure { + assertEq(Base64.encode(input), vm.toBase64(input)); + } + + function testEncodeURL(bytes memory input) external pure { + assertEq(Base64.encodeURL(input), _removePadding(vm.toBase64URL(input))); + } + + function _removePadding(string memory inputStr) internal pure returns (string memory) { + bytes memory input = bytes(inputStr); + bytes memory output; + + for (uint256 i = 0; i < input.length; ++i) { + if (input[input.length - i - 1] != 0x3d) { + output = new bytes(input.length - i); + break; + } + } + + for (uint256 i = 0; i < output.length; ++i) { + output[i] = input[i]; + } + + return string(output); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.test.js new file mode 100644 index 0000000..5c42746 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.test.js @@ -0,0 +1,59 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +// Replace "+/" with "-_" in the char table, and remove the padding +// see https://datatracker.ietf.org/doc/html/rfc4648#section-5 +const base64toBase64Url = str => str.replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', ''); + +async function fixture() { + const mock = await ethers.deployContract('$Base64'); + return { mock }; +} + +describe('Strings', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('base64', function () { + for (const { title, input, expected } of [ + { title: 'converts to base64 encoded string with double padding', input: 'test', expected: 'dGVzdA==' }, + { title: 'converts to base64 encoded string with single padding', input: 'test1', expected: 'dGVzdDE=' }, + { title: 'converts to base64 encoded string without padding', input: 'test12', expected: 'dGVzdDEy' }, + { title: 'converts to base64 encoded string (/ case)', input: 'où', expected: 'b/k=' }, + { title: 'converts to base64 encoded string (+ case)', input: 'zs~1t8', expected: 'enN+MXQ4' }, + { title: 'empty bytes', input: '', expected: '' }, + ]) + it(title, async function () { + const buffer = Buffer.from(input, 'ascii'); + expect(await this.mock.$encode(buffer)).to.equal(ethers.encodeBase64(buffer)); + expect(await this.mock.$encode(buffer)).to.equal(expected); + }); + }); + + describe('base64url', function () { + for (const { title, input, expected } of [ + { title: 'converts to base64url encoded string with double padding', input: 'test', expected: 'dGVzdA' }, + { title: 'converts to base64url encoded string with single padding', input: 'test1', expected: 'dGVzdDE' }, + { title: 'converts to base64url encoded string without padding', input: 'test12', expected: 'dGVzdDEy' }, + { title: 'converts to base64url encoded string (_ case)', input: 'où', expected: 'b_k' }, + { title: 'converts to base64url encoded string (- case)', input: 'zs~1t8', expected: 'enN-MXQ4' }, + { title: 'empty bytes', input: '', expected: '' }, + ]) + it(title, async function () { + const buffer = Buffer.from(input, 'ascii'); + expect(await this.mock.$encodeURL(buffer)).to.equal(base64toBase64Url(ethers.encodeBase64(buffer))); + expect(await this.mock.$encodeURL(buffer)).to.equal(expected); + }); + }); + + it('Encode reads beyond the input buffer into dirty memory', async function () { + const mock = await ethers.deployContract('Base64Dirty'); + const buffer32 = ethers.id('example'); + const buffer31 = buffer32.slice(0, -2); + + expect(await mock.encode(buffer31)).to.equal(ethers.encodeBase64(buffer31)); + expect(await mock.encode(buffer32)).to.equal(ethers.encodeBase64(buffer32)); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.t.sol new file mode 100644 index 0000000..eda4da6 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.t.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {Test} from "forge-std/Test.sol"; +import {Blockhash} from "../../contracts/utils/Blockhash.sol"; + +contract BlockhashTest is Test { + uint256 internal startingBlock; + + address internal constant SYSTEM_ADDRESS = 0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE; + + // See https://eips.ethereum.org/EIPS/eip-2935#bytecode + // Generated using https://www.evm.codes/playground + bytes private constant HISTORY_STORAGE_BYTECODE = + hex"3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500"; + + function setUp() public { + vm.roll(block.number + 100); + + startingBlock = block.number; + vm.etch(Blockhash.HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_BYTECODE); + } + + function testFuzzRecentBlocks(uint8 offset, uint64 currentBlock, bytes32 expectedHash) public { + // Recent blocks (1-256 blocks old) + uint256 boundedOffset = uint256(offset) + 1; + vm.assume(currentBlock > boundedOffset); + vm.roll(currentBlock); + + uint256 targetBlock = currentBlock - boundedOffset; + vm.setBlockhash(targetBlock, expectedHash); + + bytes32 result = Blockhash.blockHash(targetBlock); + assertEq(result, blockhash(targetBlock)); + assertEq(result, expectedHash); + } + + function testFuzzHistoryBlocks(uint16 offset, uint256 currentBlock, bytes32 expectedHash) public { + // History blocks (257-8191 blocks old) + offset = uint16(bound(offset, 257, 8191)); + vm.assume(currentBlock > offset); + vm.roll(currentBlock); + + uint256 targetBlock = currentBlock - offset; + _setHistoryBlockhash(targetBlock, expectedHash); + + bytes32 result = Blockhash.blockHash(targetBlock); + (bool success, bytes memory returndata) = Blockhash.HISTORY_STORAGE_ADDRESS.staticcall( + abi.encodePacked(bytes32(targetBlock)) + ); + assertTrue(success); + assertEq(result, abi.decode(returndata, (bytes32))); + assertEq(result, expectedHash); + } + + function testFuzzVeryOldBlocks(uint256 offset, uint256 currentBlock) public { + // Very old blocks (>8191 blocks old) + offset = bound(offset, 8192, type(uint256).max); + vm.assume(currentBlock > offset); + vm.roll(currentBlock); + + uint256 targetBlock = currentBlock - offset; + bytes32 result = Blockhash.blockHash(targetBlock); + assertEq(result, bytes32(0)); + } + + function testFuzzFutureBlocks(uint256 offset, uint256 currentBlock) public { + // Future blocks + offset = bound(offset, 1, type(uint256).max); + vm.roll(currentBlock); + + unchecked { + uint256 targetBlock = currentBlock + offset; + bytes32 result = Blockhash.blockHash(targetBlock); + assertEq(result, blockhash(targetBlock)); + } + } + + function testUnsupportedChainsReturnZeroWhenOutOfRange() public { + vm.etch(Blockhash.HISTORY_STORAGE_ADDRESS, hex""); + + vm.roll(block.number + 1000); + assertEq(Blockhash.blockHash(block.number - 1000), bytes32(0)); + } + + function _setHistoryBlockhash(bytes32 blockHash) internal { + _setHistoryBlockhash(block.number, blockHash); + } + + function _setHistoryBlockhash(uint256 blockNumber, bytes32 blockHash) internal { + // Subtracting 1 due to bug encountered during coverage + uint256 currentBlock = block.number - 1; + vm.assume(blockNumber < type(uint256).max); + vm.roll(blockNumber + 1); // roll to the next block so the storage contract sets the parent's blockhash + vm.prank(SYSTEM_ADDRESS); + (bool success, ) = Blockhash.HISTORY_STORAGE_ADDRESS.call(abi.encode(blockHash)); // set parent's blockhash + assertTrue(success); + vm.roll(currentBlock + 1); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.test.js new file mode 100644 index 0000000..a3de265 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.test.js @@ -0,0 +1,76 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture, mine, mineUpTo, setCode } = require('@nomicfoundation/hardhat-network-helpers'); +const { impersonate } = require('../helpers/account'); + +async function fixture() { + const mock = await ethers.deployContract('$Blockhash'); + return { mock }; +} + +const HISTORY_STORAGE_ADDRESS = '0x0000F90827F1C53a10cb7A02335B175320002935'; +const SYSTEM_ADDRESS = '0xfffffffffffffffffffffffffffffffffffffffe'; +const HISTORY_SERVE_WINDOW = 8191; +const BLOCKHASH_SERVE_WINDOW = 256; + +describe('Blockhash', function () { + before(async function () { + Object.assign(this, await loadFixture(fixture)); + + impersonate(SYSTEM_ADDRESS); + this.systemSigner = await ethers.getSigner(SYSTEM_ADDRESS); + }); + + it('recent block', async function () { + await mine(); + + const mostRecentBlock = (await ethers.provider.getBlock('latest')).number; + const blockToCheck = mostRecentBlock - 1; + const fetchedHash = (await ethers.provider.getBlock(blockToCheck)).hash; + await expect(this.mock.$blockHash(blockToCheck)).to.eventually.equal(fetchedHash); + }); + + it('old block', async function () { + await mine(); + + const mostRecentBlock = await ethers.provider.getBlock('latest'); + + // Call the history address with the most recent block hash + await this.systemSigner.sendTransaction({ + to: HISTORY_STORAGE_ADDRESS, + data: mostRecentBlock.hash, + }); + + await mineUpTo(mostRecentBlock.number + BLOCKHASH_SERVE_WINDOW + 10); + + // Verify blockhash after setting history + await expect(this.mock.$blockHash(mostRecentBlock.number)).to.eventually.equal(mostRecentBlock.hash); + }); + + it('very old block', async function () { + await mine(); + + const mostRecentBlock = await ethers.provider.getBlock('latest'); + await mineUpTo(mostRecentBlock.number + HISTORY_SERVE_WINDOW + 10); + + await expect(this.mock.$blockHash(mostRecentBlock.number)).to.eventually.equal(ethers.ZeroHash); + }); + + it('future block', async function () { + await mine(); + + const mostRecentBlock = await ethers.provider.getBlock('latest'); + const blockToCheck = mostRecentBlock.number + 10; + await expect(this.mock.$blockHash(blockToCheck)).to.eventually.equal(ethers.ZeroHash); + }); + + it('unsupported chain', async function () { + await setCode(HISTORY_STORAGE_ADDRESS, '0x00'); + + const mostRecentBlock = await ethers.provider.getBlock('latest'); + await mineUpTo(mostRecentBlock.number + BLOCKHASH_SERVE_WINDOW + 10); + + await expect(this.mock.$blockHash(mostRecentBlock.number)).to.eventually.equal(ethers.ZeroHash); + await expect(this.mock.$blockHash(mostRecentBlock.number + 20)).to.eventually.not.equal(ethers.ZeroHash); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.t.sol new file mode 100644 index 0000000..30f1421 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.t.sol @@ -0,0 +1,117 @@ +// 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"; +import {Bytes} from "@openzeppelin/contracts/utils/Bytes.sol"; + +contract BytesTest is Test { + using Bytes for bytes; + + // INDEX OF + function testIndexOf(bytes memory buffer, bytes1 s) public pure { + uint256 result = Bytes.indexOf(buffer, s); + + if (buffer.length == 0) { + // Case 0: buffer is empty + assertEq(result, type(uint256).max); + } else if (result == type(uint256).max) { + // Case 1: search value could not be found + for (uint256 i = 0; i < buffer.length; ++i) assertNotEq(buffer[i], s); + } else { + // Case 2: search value was found + assertEq(buffer[result], s); + // search value is not present anywhere before the found location + for (uint256 i = 0; i < result; ++i) assertNotEq(buffer[i], s); + } + } + + function testIndexOf(bytes memory buffer, bytes1 s, uint256 pos) public pure { + uint256 result = Bytes.indexOf(buffer, s, pos); + + if (buffer.length == 0) { + // Case 0: buffer is empty + assertEq(result, type(uint256).max); + } else if (result == type(uint256).max) { + // Case 1: search value could not be found + for (uint256 i = pos; i < buffer.length; ++i) assertNotEq(buffer[i], s); + } else { + // Case 2: search value was found + assertEq(buffer[result], s); + // search value is not present anywhere before the found location + for (uint256 i = pos; i < result; ++i) assertNotEq(buffer[i], s); + } + } + + function testLastIndexOf(bytes memory buffer, bytes1 s) public pure { + uint256 result = Bytes.lastIndexOf(buffer, s); + + if (buffer.length == 0) { + // Case 0: buffer is empty + assertEq(result, type(uint256).max); + } else if (result == type(uint256).max) { + // Case 1: search value could not be found + for (uint256 i = 0; i < buffer.length; ++i) assertNotEq(buffer[i], s); + } else { + // Case 2: search value was found + assertEq(buffer[result], s); + // search value is not present anywhere after the found location + for (uint256 i = result + 1; i < buffer.length; ++i) assertNotEq(buffer[i], s); + } + } + + function testLastIndexOf(bytes memory buffer, bytes1 s, uint256 pos) public pure { + uint256 result = Bytes.lastIndexOf(buffer, s, pos); + + if (buffer.length == 0) { + // Case 0: buffer is empty + assertEq(result, type(uint256).max); + } else if (result == type(uint256).max) { + // Case 1: search value could not be found + for (uint256 i = 0; i <= Math.min(pos, buffer.length - 1); ++i) assertNotEq(buffer[i], s); + } else { + // Case 2: search value was found + assertEq(buffer[result], s); + // search value is not present anywhere after the found location + for (uint256 i = result + 1; i <= Math.min(pos, buffer.length - 1); ++i) assertNotEq(buffer[i], s); + } + } + + // SLICES + function testSliceWithStartOnly(bytes memory buffer, uint256 start) public pure { + bytes memory originalBuffer = bytes.concat(buffer); + bytes memory result = buffer.slice(start); + + // Original buffer was not modified + assertEq(buffer, originalBuffer); + + // Should return bytes from start to end + assertEq(result.length, Math.saturatingSub(buffer.length, start)); + + // Verify content matches + for (uint256 i = 0; i < result.length; ++i) { + assertEq(result[i], buffer[start + i]); + } + } + + function testSlice(bytes memory buffer, uint256 start, uint256 end) public pure { + bytes memory originalBuffer = bytes.concat(buffer); + bytes memory result = buffer.slice(start, end); + + // Original buffer was not modified + assertEq(buffer, originalBuffer); + + // Calculate expected bounds after sanitization + uint256 sanitizedEnd = Math.min(end, buffer.length); + uint256 sanitizedStart = Math.min(start, sanitizedEnd); + uint256 expectedLength = sanitizedEnd - sanitizedStart; + + assertEq(result.length, expectedLength); + + // Verify content matches when there's content to verify + for (uint256 i = 0; i < result.length; ++i) { + assertEq(result[i], buffer[sanitizedStart + i]); + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.test.js new file mode 100644 index 0000000..f2a1b8f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.test.js @@ -0,0 +1,104 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +async function fixture() { + const mock = await ethers.deployContract('$Bytes'); + return { mock }; +} + +const lorem = ethers.toUtf8Bytes( + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', +); +const present = lorem.at(1); +const absent = 255; + +describe('Bytes', function () { + before(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('indexOf', function () { + it('first', async function () { + await expect(this.mock.$indexOf(lorem, ethers.toBeHex(present))).to.eventually.equal(lorem.indexOf(present)); + }); + + it('from index', async function () { + for (const start in Array(lorem.length + 10).fill()) { + const index = lorem.indexOf(present, start); + const result = index === -1 ? ethers.MaxUint256 : index; + await expect( + this.mock.$indexOf(lorem, ethers.toBeHex(present), ethers.Typed.uint256(start)), + ).to.eventually.equal(result); + } + }); + + it('absent', async function () { + await expect(this.mock.$indexOf(lorem, ethers.toBeHex(absent))).to.eventually.equal(ethers.MaxUint256); + }); + + it('empty buffer', async function () { + await expect(this.mock.$indexOf('0x', '0x00')).to.eventually.equal(ethers.MaxUint256); + await expect(this.mock.$indexOf('0x', '0x00', ethers.Typed.uint256(17))).to.eventually.equal(ethers.MaxUint256); + }); + }); + + describe('lastIndexOf', function () { + it('first', async function () { + await expect(this.mock.$lastIndexOf(lorem, ethers.toBeHex(present))).to.eventually.equal( + lorem.lastIndexOf(present), + ); + }); + + it('from index', async function () { + for (const start in Array(lorem.length + 10).fill()) { + const index = lorem.lastIndexOf(present, start); + const result = index === -1 ? ethers.MaxUint256 : index; + await expect( + this.mock.$lastIndexOf(lorem, ethers.toBeHex(present), ethers.Typed.uint256(start)), + ).to.eventually.equal(result); + } + }); + + it('absent', async function () { + await expect(this.mock.$lastIndexOf(lorem, ethers.toBeHex(absent))).to.eventually.equal(ethers.MaxUint256); + }); + + it('empty buffer', async function () { + await expect(this.mock.$lastIndexOf('0x', '0x00')).to.eventually.equal(ethers.MaxUint256); + await expect(this.mock.$lastIndexOf('0x', '0x00', ethers.Typed.uint256(17))).to.eventually.equal( + ethers.MaxUint256, + ); + }); + }); + + describe('slice', function () { + describe('slice(bytes, uint256)', function () { + for (const [descr, start] of Object.entries({ + 'start = 0': 0, + 'start within bound': 10, + 'start out of bound': 1000, + })) { + it(descr, async function () { + const result = ethers.hexlify(lorem.slice(start)); + await expect(this.mock.$slice(lorem, start)).to.eventually.equal(result); + }); + } + }); + + describe('slice(bytes, uint256, uint256)', function () { + for (const [descr, [start, end]] of Object.entries({ + 'start = 0': [0, 42], + 'start and end within bound': [17, 42], + 'end out of bound': [42, 1000], + 'start = end': [17, 17], + 'start > end': [42, 17], + })) { + it(descr, async function () { + const result = ethers.hexlify(lorem.slice(start, end)); + await expect(this.mock.$slice(lorem, start, ethers.Typed.uint256(end))).to.eventually.equal(result); + }); + } + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/CAIP.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/CAIP.test.js new file mode 100644 index 0000000..cd5995c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/CAIP.test.js @@ -0,0 +1,53 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { CHAINS, getLocalCAIP } = require('../helpers/chains'); + +async function fixture() { + const caip2 = await ethers.deployContract('$CAIP2'); + const caip10 = await ethers.deployContract('$CAIP10'); + return { caip2, caip10 }; +} + +describe('CAIP utilities', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('CAIP-2', function () { + it('local()', async function () { + const { caip2 } = await getLocalCAIP(); + expect(await this.caip2.$local()).to.equal(caip2); + }); + + for (const { namespace, reference, caip2 } of Object.values(CHAINS)) + it(`format(${namespace}, ${reference})`, async function () { + expect(await this.caip2.$format(namespace, reference)).to.equal(caip2); + }); + + for (const { namespace, reference, caip2 } of Object.values(CHAINS)) + it(`parse(${caip2})`, async function () { + expect(await this.caip2.$parse(caip2)).to.deep.equal([namespace, reference]); + }); + }); + + describe('CAIP-10', function () { + const { address: account } = ethers.Wallet.createRandom(); + + it(`local(${account})`, async function () { + const { caip10 } = await getLocalCAIP(account); + expect(await this.caip10.$local(ethers.Typed.address(account))).to.equal(caip10); + }); + + for (const { account, caip2, caip10 } of Object.values(CHAINS)) + it(`format(${caip2}, ${account})`, async function () { + expect(await this.caip10.$format(ethers.Typed.string(caip2), ethers.Typed.string(account))).to.equal(caip10); + }); + + for (const { account, caip2, caip10 } of Object.values(CHAINS)) + it(`parse(${caip10})`, async function () { + expect(await this.caip10.$parse(caip10)).to.deep.equal([caip2, account]); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Calldata.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Calldata.test.js new file mode 100644 index 0000000..7e9d3d4 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Calldata.test.js @@ -0,0 +1,22 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +async function fixture() { + const mock = await ethers.deployContract('$Calldata'); + return { mock }; +} + +describe('Calldata utilities', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('emptyBytes', async function () { + await expect(this.mock.$emptyBytes()).to.eventually.equal('0x'); + }); + + it('emptyString', async function () { + await expect(this.mock.$emptyString()).to.eventually.equal(''); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.behavior.js new file mode 100644 index 0000000..adb140f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.behavior.js @@ -0,0 +1,48 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +async function fixture() { + return { contextHelper: await ethers.deployContract('ContextMockCaller', []) }; +} +function shouldBehaveLikeRegularContext() { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('msgSender', function () { + it('returns the transaction sender when called from an EOA', async function () { + await expect(this.context.connect(this.sender).msgSender()).to.emit(this.context, 'Sender').withArgs(this.sender); + }); + + it('returns the transaction sender when called from another contract', async function () { + await expect(this.contextHelper.connect(this.sender).callSender(this.context)) + .to.emit(this.context, 'Sender') + .withArgs(this.contextHelper); + }); + }); + + describe('msgData', function () { + const args = [42n, 'OpenZeppelin']; + + it('returns the transaction data when called from an EOA', async function () { + const callData = this.context.interface.encodeFunctionData('msgData', args); + + await expect(this.context.msgData(...args)) + .to.emit(this.context, 'Data') + .withArgs(callData, ...args); + }); + + it('returns the transaction sender when from another contract', async function () { + const callData = this.context.interface.encodeFunctionData('msgData', args); + + await expect(this.contextHelper.callData(this.context, ...args)) + .to.emit(this.context, 'Data') + .withArgs(callData, ...args); + }); + }); +} + +module.exports = { + shouldBehaveLikeRegularContext, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.test.js new file mode 100644 index 0000000..b766729 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.test.js @@ -0,0 +1,18 @@ +const { ethers } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { shouldBehaveLikeRegularContext } = require('./Context.behavior'); + +async function fixture() { + const [sender] = await ethers.getSigners(); + const context = await ethers.deployContract('ContextMock', []); + return { sender, context }; +} + +describe('Context', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeRegularContext(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.t.sol new file mode 100644 index 0000000..b73db9f --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.t.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; + +contract Create2Test is Test { + function testSymbolicComputeAddressSpillage(bytes32 salt, bytes32 bytecodeHash, address deployer) public pure { + address predicted = Create2.computeAddress(salt, bytecodeHash, deployer); + bytes32 spillage; + assembly ("memory-safe") { + spillage := and(predicted, 0xffffffffffffffffffffffff0000000000000000000000000000000000000000) + } + assertEq(spillage, bytes32(0)); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.test.js new file mode 100644 index 0000000..99c47a0 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.test.js @@ -0,0 +1,190 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +const { RevertType } = require('../helpers/enums'); + +async function fixture() { + const [deployer, other] = await ethers.getSigners(); + + const factory = await ethers.deployContract('$Create2'); + + // Bytecode for deploying a contract that includes a constructor. + // We use a vesting wallet, with 3 constructor arguments. + const constructorByteCode = await ethers + .getContractFactory('VestingWallet') + .then(factory => ethers.concat([factory.bytecode, factory.interface.encodeDeploy([other.address, 0n, 0n])])); + + // Bytecode for deploying a contract that has no constructor log. + // Here we use the Create2 helper factory. + const constructorLessBytecode = await ethers + .getContractFactory('$Create2') + .then(factory => ethers.concat([factory.bytecode, factory.interface.encodeDeploy([])])); + + const mockFactory = await ethers.getContractFactory('ConstructorMock'); + + return { deployer, other, factory, constructorByteCode, constructorLessBytecode, mockFactory }; +} + +describe('Create2', function () { + const salt = 'salt message'; + const saltHex = ethers.id(salt); + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('computeAddress', function () { + it('computes the correct contract address', async function () { + const onChainComputed = await this.factory.$computeAddress(saltHex, ethers.keccak256(this.constructorByteCode)); + const offChainComputed = ethers.getCreate2Address( + this.factory.target, + saltHex, + ethers.keccak256(this.constructorByteCode), + ); + expect(onChainComputed).to.equal(offChainComputed); + }); + + it('computes the correct contract address with deployer', async function () { + const onChainComputed = await this.factory.$computeAddress( + saltHex, + ethers.keccak256(this.constructorByteCode), + ethers.Typed.address(this.deployer), + ); + const offChainComputed = ethers.getCreate2Address( + this.deployer.address, + saltHex, + ethers.keccak256(this.constructorByteCode), + ); + expect(onChainComputed).to.equal(offChainComputed); + }); + }); + + describe('deploy', function () { + it('deploys a contract without constructor', async function () { + const offChainComputed = ethers.getCreate2Address( + this.factory.target, + saltHex, + ethers.keccak256(this.constructorLessBytecode), + ); + + await expect(this.factory.$deploy(0n, saltHex, this.constructorLessBytecode)) + .to.emit(this.factory, 'return$deploy') + .withArgs(offChainComputed); + + expect(this.constructorLessBytecode).to.include((await ethers.provider.getCode(offChainComputed)).slice(2)); + }); + + it('deploys a contract with constructor arguments', async function () { + const offChainComputed = ethers.getCreate2Address( + this.factory.target, + saltHex, + ethers.keccak256(this.constructorByteCode), + ); + + await expect(this.factory.$deploy(0n, saltHex, this.constructorByteCode)) + .to.emit(this.factory, 'return$deploy') + .withArgs(offChainComputed); + + const instance = await ethers.getContractAt('VestingWallet', offChainComputed); + + expect(await instance.owner()).to.equal(this.other); + }); + + it('deploys a contract with funds deposited in the factory', async function () { + const value = 10n; + + await this.deployer.sendTransaction({ to: this.factory, value }); + + const offChainComputed = ethers.getCreate2Address( + this.factory.target, + saltHex, + ethers.keccak256(this.constructorByteCode), + ); + + expect(await ethers.provider.getBalance(this.factory)).to.equal(value); + expect(await ethers.provider.getBalance(offChainComputed)).to.equal(0n); + + await expect(this.factory.$deploy(value, saltHex, this.constructorByteCode)) + .to.emit(this.factory, 'return$deploy') + .withArgs(offChainComputed); + + expect(await ethers.provider.getBalance(this.factory)).to.equal(0n); + expect(await ethers.provider.getBalance(offChainComputed)).to.equal(value); + }); + + it('fails deploying a contract in an existent address', async function () { + await expect(this.factory.$deploy(0n, saltHex, this.constructorByteCode)).to.emit(this.factory, 'return$deploy'); + + await expect(this.factory.$deploy(0n, saltHex, this.constructorByteCode)).to.be.revertedWithCustomError( + this.factory, + 'FailedDeployment', + ); + }); + + it('fails deploying a contract if the bytecode length is zero', async function () { + await expect(this.factory.$deploy(0n, saltHex, '0x')).to.be.revertedWithCustomError( + this.factory, + 'Create2EmptyBytecode', + ); + }); + + it('fails deploying a contract if factory contract does not have sufficient balance', async function () { + await expect(this.factory.$deploy(1n, saltHex, this.constructorByteCode)) + .to.be.revertedWithCustomError(this.factory, 'InsufficientBalance') + .withArgs(0n, 1n); + }); + + describe('reverts error thrown during contract creation', function () { + it('bubbles up without message', async function () { + await expect( + this.factory.$deploy( + 0n, + saltHex, + ethers.concat([ + this.mockFactory.bytecode, + this.mockFactory.interface.encodeDeploy([RevertType.RevertWithoutMessage]), + ]), + ), + ).to.be.revertedWithCustomError(this.factory, 'FailedDeployment'); + }); + + it('bubbles up message', async function () { + await expect( + this.factory.$deploy( + 0n, + saltHex, + ethers.concat([ + this.mockFactory.bytecode, + this.mockFactory.interface.encodeDeploy([RevertType.RevertWithMessage]), + ]), + ), + ).to.be.revertedWith('ConstructorMock: reverting'); + }); + + it('bubbles up custom error', async function () { + await expect( + this.factory.$deploy( + 0n, + saltHex, + ethers.concat([ + this.mockFactory.bytecode, + this.mockFactory.interface.encodeDeploy([RevertType.RevertWithCustomError]), + ]), + ), + ).to.be.revertedWithCustomError({ interface: this.mockFactory.interface }, 'CustomError'); + }); + + it('bubbles up panic', async function () { + await expect( + this.factory.$deploy( + 0n, + saltHex, + ethers.concat([this.mockFactory.bytecode, this.mockFactory.interface.encodeDeploy([RevertType.Panic])]), + ), + ).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Multicall.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Multicall.test.js new file mode 100644 index 0000000..9c84e44 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Multicall.test.js @@ -0,0 +1,72 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +async function fixture() { + const [holder, alice, bruce] = await ethers.getSigners(); + + const amount = 12_000n; + const helper = await ethers.deployContract('MulticallHelper'); + const mock = await ethers.deployContract('$ERC20MulticallMock', ['name', 'symbol']); + await mock.$_mint(holder, amount); + + return { holder, alice, bruce, amount, mock, helper }; +} + +describe('Multicall', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('batches function calls', async function () { + expect(await this.mock.balanceOf(this.alice)).to.equal(0n); + expect(await this.mock.balanceOf(this.bruce)).to.equal(0n); + + await expect( + this.mock.multicall([ + this.mock.interface.encodeFunctionData('transfer', [this.alice.address, this.amount / 2n]), + this.mock.interface.encodeFunctionData('transfer', [this.bruce.address, this.amount / 3n]), + ]), + ) + .to.emit(this.mock, 'Transfer') + .withArgs(this.holder, this.alice, this.amount / 2n) + .to.emit(this.mock, 'Transfer') + .withArgs(this.holder, this.bruce, this.amount / 3n); + + expect(await this.mock.balanceOf(this.alice)).to.equal(this.amount / 2n); + expect(await this.mock.balanceOf(this.bruce)).to.equal(this.amount / 3n); + }); + + it('returns an array with the result of each call', async function () { + await this.mock.transfer(this.helper, this.amount); + expect(await this.mock.balanceOf(this.helper)).to.equal(this.amount); + + await this.helper.checkReturnValues(this.mock, [this.alice, this.bruce], [this.amount / 2n, this.amount / 3n]); + }); + + it('reverts previous calls', async function () { + expect(await this.mock.balanceOf(this.alice)).to.equal(0n); + + await expect( + this.mock.multicall([ + this.mock.interface.encodeFunctionData('transfer', [this.alice.address, this.amount]), + this.mock.interface.encodeFunctionData('transfer', [this.bruce.address, this.amount]), + ]), + ) + .to.be.revertedWithCustomError(this.mock, 'ERC20InsufficientBalance') + .withArgs(this.holder, 0, this.amount); + + expect(await this.mock.balanceOf(this.alice)).to.equal(0n); + }); + + it('bubbles up revert reasons', async function () { + await expect( + this.mock.multicall([ + this.mock.interface.encodeFunctionData('transfer', [this.alice.address, this.amount]), + this.mock.interface.encodeFunctionData('transfer', [this.bruce.address, this.amount]), + ]), + ) + .to.be.revertedWithCustomError(this.mock, 'ERC20InsufficientBalance') + .withArgs(this.holder, 0, this.amount); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.behavior.js new file mode 100644 index 0000000..c62864e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.behavior.js @@ -0,0 +1,189 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); + +function shouldBehaveLikeNonces() { + describe('should behave like Nonces', function () { + const sender = ethers.Wallet.createRandom(); + const other = ethers.Wallet.createRandom(); + + it('gets a nonce', async function () { + expect(this.mock.nonces(sender)).to.eventually.equal(0n); + }); + + describe('_useNonce', function () { + it('increments a nonce', async function () { + expect(this.mock.nonces(sender)).to.eventually.equal(0n); + + const eventName = ['return$_useNonce', 'return$_useNonce_address'].find(name => + this.mock.interface.getEvent(name), + ); + + await expect(this.mock.$_useNonce(sender)).to.emit(this.mock, eventName).withArgs(0n); + + await expect(this.mock.nonces(sender)).to.eventually.equal(1n); + }); + + it("increments only sender's nonce", async function () { + await expect(this.mock.nonces(sender)).to.eventually.equal(0n); + await expect(this.mock.nonces(other)).to.eventually.equal(0n); + + await this.mock.$_useNonce(sender); + + await expect(this.mock.nonces(sender)).to.eventually.equal(1n); + await expect(this.mock.nonces(other)).to.eventually.equal(0n); + }); + }); + + describe('_useCheckedNonce', function () { + it('increments a nonce', async function () { + // current nonce is 0n + await expect(this.mock.nonces(sender)).to.eventually.equal(0n); + + await this.mock.$_useCheckedNonce(sender, 0n); + + await expect(this.mock.nonces(sender)).to.eventually.equal(1n); + }); + + it("increments only sender's nonce", async function () { + // current nonce is 0n + await expect(this.mock.nonces(sender)).to.eventually.equal(0n); + await expect(this.mock.nonces(other)).to.eventually.equal(0n); + + await this.mock.$_useCheckedNonce(sender, 0n); + + await expect(this.mock.nonces(sender)).to.eventually.equal(1n); + await expect(this.mock.nonces(other)).to.eventually.equal(0n); + }); + + it('reverts when nonce is not the expected', async function () { + const currentNonce = await this.mock.nonces(sender); + + await expect(this.mock.$_useCheckedNonce(sender, currentNonce + 1n)) + .to.be.revertedWithCustomError(this.mock, 'InvalidAccountNonce') + .withArgs(sender, currentNonce); + }); + }); + }); +} + +function shouldBehaveLikeNoncesKeyed() { + describe('should support nonces with keys', function () { + const sender = ethers.Wallet.createRandom(); + + const keyOffset = key => key << 64n; + + it('gets a nonce', async function () { + await expect(this.mock.nonces(sender, ethers.Typed.uint192(0n))).to.eventually.equal(keyOffset(0n) + 0n); + await expect(this.mock.nonces(sender, ethers.Typed.uint192(17n))).to.eventually.equal(keyOffset(17n) + 0n); + }); + + describe('_useNonce', function () { + it('default variant uses key 0', async function () { + await expect(this.mock.nonces(sender, ethers.Typed.uint192(0n))).to.eventually.equal(keyOffset(0n) + 0n); + await expect(this.mock.nonces(sender, ethers.Typed.uint192(17n))).to.eventually.equal(keyOffset(17n) + 0n); + + await expect(this.mock.$_useNonce(sender)).to.emit(this.mock, 'return$_useNonce_address').withArgs(0n); + + await expect(this.mock.$_useNonce(sender, ethers.Typed.uint192(0n))) + .to.emit(this.mock, 'return$_useNonce_address_uint192') + .withArgs(keyOffset(0n) + 1n); + + await expect(this.mock.nonces(sender, ethers.Typed.uint192(0n))).to.eventually.equal(keyOffset(0n) + 2n); + await expect(this.mock.nonces(sender, ethers.Typed.uint192(17n))).to.eventually.equal(keyOffset(17n) + 0n); + }); + + it('use nonce at another key', async function () { + await expect(this.mock.nonces(sender, ethers.Typed.uint192(0n))).to.eventually.equal(keyOffset(0n) + 0n); + await expect(this.mock.nonces(sender, ethers.Typed.uint192(17n))).to.eventually.equal(keyOffset(17n) + 0n); + + await expect(this.mock.$_useNonce(sender, ethers.Typed.uint192(17n))) + .to.emit(this.mock, 'return$_useNonce_address_uint192') + .withArgs(keyOffset(17n) + 0n); + + await expect(this.mock.$_useNonce(sender, ethers.Typed.uint192(17n))) + .to.emit(this.mock, 'return$_useNonce_address_uint192') + .withArgs(keyOffset(17n) + 1n); + + await expect(this.mock.nonces(sender, ethers.Typed.uint192(0n))).to.eventually.equal(keyOffset(0n) + 0n); + await expect(this.mock.nonces(sender, ethers.Typed.uint192(17n))).to.eventually.equal(keyOffset(17n) + 2n); + }); + }); + + describe('_useCheckedNonce(address, uint256)', function () { + it('default variant uses key 0', async function () { + const currentNonce = await this.mock.nonces(sender, ethers.Typed.uint192(0n)); + + await this.mock.$_useCheckedNonce(sender, currentNonce); + + await expect(this.mock.nonces(sender, ethers.Typed.uint192(0n))).to.eventually.equal(currentNonce + 1n); + }); + + it('use nonce at another key', async function () { + const currentNonce = await this.mock.nonces(sender, ethers.Typed.uint192(17n)); + + await this.mock.$_useCheckedNonce(sender, currentNonce); + + await expect(this.mock.nonces(sender, ethers.Typed.uint192(17n))).to.eventually.equal(currentNonce + 1n); + }); + + it('reverts when nonce is not the expected', async function () { + const currentNonce = await this.mock.nonces(sender, ethers.Typed.uint192(42n)); + + // use and increment + await this.mock.$_useCheckedNonce(sender, currentNonce); + + // reuse same nonce + await expect(this.mock.$_useCheckedNonce(sender, currentNonce)) + .to.be.revertedWithCustomError(this.mock, 'InvalidAccountNonce') + .withArgs(sender, currentNonce + 1n); + + // use "future" nonce too early + await expect(this.mock.$_useCheckedNonce(sender, currentNonce + 10n)) + .to.be.revertedWithCustomError(this.mock, 'InvalidAccountNonce') + .withArgs(sender, currentNonce + 1n); + }); + }); + + describe('_useCheckedNonce(address, uint192, uint64)', function () { + const MASK = 0xffffffffffffffffn; + + it('default variant uses key 0', async function () { + const currentNonce = await this.mock.nonces(sender, ethers.Typed.uint192(0n)); + + await this.mock.$_useCheckedNonce(sender, ethers.Typed.uint192(0n), currentNonce); + + await expect(this.mock.nonces(sender, ethers.Typed.uint192(0n))).to.eventually.equal(currentNonce + 1n); + }); + + it('use nonce at another key', async function () { + const currentNonce = await this.mock.nonces(sender, ethers.Typed.uint192(17n)); + + await this.mock.$_useCheckedNonce(sender, ethers.Typed.uint192(17n), currentNonce & MASK); + + await expect(this.mock.nonces(sender, ethers.Typed.uint192(17n))).to.eventually.equal(currentNonce + 1n); + }); + + it('reverts when nonce is not the expected', async function () { + const currentNonce = await this.mock.nonces(sender, ethers.Typed.uint192(42n)); + + // use and increment + await this.mock.$_useCheckedNonce(sender, ethers.Typed.uint192(42n), currentNonce & MASK); + + // reuse same nonce + await expect(this.mock.$_useCheckedNonce(sender, ethers.Typed.uint192(42n), currentNonce & MASK)) + .to.be.revertedWithCustomError(this.mock, 'InvalidAccountNonce') + .withArgs(sender, currentNonce + 1n); + + // use "future" nonce too early + await expect(this.mock.$_useCheckedNonce(sender, ethers.Typed.uint192(42n), (currentNonce & MASK) + 10n)) + .to.be.revertedWithCustomError(this.mock, 'InvalidAccountNonce') + .withArgs(sender, currentNonce + 1n); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeNonces, + shouldBehaveLikeNoncesKeyed, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.test.js new file mode 100644 index 0000000..85aa735 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.test.js @@ -0,0 +1,16 @@ +const { ethers } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { shouldBehaveLikeNonces } = require('./Nonces.behavior'); + +async function fixture() { + const mock = await ethers.deployContract('$Nonces'); + return { mock }; +} + +describe('Nonces', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeNonces(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/NoncesKeyed.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/NoncesKeyed.test.js new file mode 100644 index 0000000..c46948e --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/NoncesKeyed.test.js @@ -0,0 +1,17 @@ +const { ethers } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { shouldBehaveLikeNonces, shouldBehaveLikeNoncesKeyed } = require('./Nonces.behavior'); + +async function fixture() { + const mock = await ethers.deployContract('$NoncesKeyed'); + return { mock }; +} + +describe('NoncesKeyed', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldBehaveLikeNonces(); + shouldBehaveLikeNoncesKeyed(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.t.sol new file mode 100644 index 0000000..40f052c --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.t.sol @@ -0,0 +1,993 @@ +// SPDX-License-Identifier: MIT +// This file was procedurally generated from scripts/generate/templates/Packing.t.js. + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {Packing} from "@openzeppelin/contracts/utils/Packing.sol"; + +contract PackingTest is Test { + using Packing for *; + + function testPack(bytes1 left, bytes1 right) external pure { + assertEq(left, Packing.pack_1_1(left, right).extract_2_1(0)); + assertEq(right, Packing.pack_1_1(left, right).extract_2_1(1)); + } + + function testPack(bytes2 left, bytes2 right) external pure { + assertEq(left, Packing.pack_2_2(left, right).extract_4_2(0)); + assertEq(right, Packing.pack_2_2(left, right).extract_4_2(2)); + } + + function testPack(bytes2 left, bytes4 right) external pure { + assertEq(left, Packing.pack_2_4(left, right).extract_6_2(0)); + assertEq(right, Packing.pack_2_4(left, right).extract_6_4(2)); + } + + function testPack(bytes2 left, bytes6 right) external pure { + assertEq(left, Packing.pack_2_6(left, right).extract_8_2(0)); + assertEq(right, Packing.pack_2_6(left, right).extract_8_6(2)); + } + + function testPack(bytes2 left, bytes8 right) external pure { + assertEq(left, Packing.pack_2_8(left, right).extract_10_2(0)); + assertEq(right, Packing.pack_2_8(left, right).extract_10_8(2)); + } + + function testPack(bytes2 left, bytes10 right) external pure { + assertEq(left, Packing.pack_2_10(left, right).extract_12_2(0)); + assertEq(right, Packing.pack_2_10(left, right).extract_12_10(2)); + } + + function testPack(bytes2 left, bytes20 right) external pure { + assertEq(left, Packing.pack_2_20(left, right).extract_22_2(0)); + assertEq(right, Packing.pack_2_20(left, right).extract_22_20(2)); + } + + function testPack(bytes2 left, bytes22 right) external pure { + assertEq(left, Packing.pack_2_22(left, right).extract_24_2(0)); + assertEq(right, Packing.pack_2_22(left, right).extract_24_22(2)); + } + + function testPack(bytes4 left, bytes2 right) external pure { + assertEq(left, Packing.pack_4_2(left, right).extract_6_4(0)); + assertEq(right, Packing.pack_4_2(left, right).extract_6_2(4)); + } + + function testPack(bytes4 left, bytes4 right) external pure { + assertEq(left, Packing.pack_4_4(left, right).extract_8_4(0)); + assertEq(right, Packing.pack_4_4(left, right).extract_8_4(4)); + } + + function testPack(bytes4 left, bytes6 right) external pure { + assertEq(left, Packing.pack_4_6(left, right).extract_10_4(0)); + assertEq(right, Packing.pack_4_6(left, right).extract_10_6(4)); + } + + function testPack(bytes4 left, bytes8 right) external pure { + assertEq(left, Packing.pack_4_8(left, right).extract_12_4(0)); + assertEq(right, Packing.pack_4_8(left, right).extract_12_8(4)); + } + + function testPack(bytes4 left, bytes12 right) external pure { + assertEq(left, Packing.pack_4_12(left, right).extract_16_4(0)); + assertEq(right, Packing.pack_4_12(left, right).extract_16_12(4)); + } + + function testPack(bytes4 left, bytes16 right) external pure { + assertEq(left, Packing.pack_4_16(left, right).extract_20_4(0)); + assertEq(right, Packing.pack_4_16(left, right).extract_20_16(4)); + } + + function testPack(bytes4 left, bytes20 right) external pure { + assertEq(left, Packing.pack_4_20(left, right).extract_24_4(0)); + assertEq(right, Packing.pack_4_20(left, right).extract_24_20(4)); + } + + function testPack(bytes4 left, bytes24 right) external pure { + assertEq(left, Packing.pack_4_24(left, right).extract_28_4(0)); + assertEq(right, Packing.pack_4_24(left, right).extract_28_24(4)); + } + + function testPack(bytes4 left, bytes28 right) external pure { + assertEq(left, Packing.pack_4_28(left, right).extract_32_4(0)); + assertEq(right, Packing.pack_4_28(left, right).extract_32_28(4)); + } + + function testPack(bytes6 left, bytes2 right) external pure { + assertEq(left, Packing.pack_6_2(left, right).extract_8_6(0)); + assertEq(right, Packing.pack_6_2(left, right).extract_8_2(6)); + } + + function testPack(bytes6 left, bytes4 right) external pure { + assertEq(left, Packing.pack_6_4(left, right).extract_10_6(0)); + assertEq(right, Packing.pack_6_4(left, right).extract_10_4(6)); + } + + function testPack(bytes6 left, bytes6 right) external pure { + assertEq(left, Packing.pack_6_6(left, right).extract_12_6(0)); + assertEq(right, Packing.pack_6_6(left, right).extract_12_6(6)); + } + + function testPack(bytes6 left, bytes10 right) external pure { + assertEq(left, Packing.pack_6_10(left, right).extract_16_6(0)); + assertEq(right, Packing.pack_6_10(left, right).extract_16_10(6)); + } + + function testPack(bytes6 left, bytes16 right) external pure { + assertEq(left, Packing.pack_6_16(left, right).extract_22_6(0)); + assertEq(right, Packing.pack_6_16(left, right).extract_22_16(6)); + } + + function testPack(bytes6 left, bytes22 right) external pure { + assertEq(left, Packing.pack_6_22(left, right).extract_28_6(0)); + assertEq(right, Packing.pack_6_22(left, right).extract_28_22(6)); + } + + function testPack(bytes8 left, bytes2 right) external pure { + assertEq(left, Packing.pack_8_2(left, right).extract_10_8(0)); + assertEq(right, Packing.pack_8_2(left, right).extract_10_2(8)); + } + + function testPack(bytes8 left, bytes4 right) external pure { + assertEq(left, Packing.pack_8_4(left, right).extract_12_8(0)); + assertEq(right, Packing.pack_8_4(left, right).extract_12_4(8)); + } + + function testPack(bytes8 left, bytes8 right) external pure { + assertEq(left, Packing.pack_8_8(left, right).extract_16_8(0)); + assertEq(right, Packing.pack_8_8(left, right).extract_16_8(8)); + } + + function testPack(bytes8 left, bytes12 right) external pure { + assertEq(left, Packing.pack_8_12(left, right).extract_20_8(0)); + assertEq(right, Packing.pack_8_12(left, right).extract_20_12(8)); + } + + function testPack(bytes8 left, bytes16 right) external pure { + assertEq(left, Packing.pack_8_16(left, right).extract_24_8(0)); + assertEq(right, Packing.pack_8_16(left, right).extract_24_16(8)); + } + + function testPack(bytes8 left, bytes20 right) external pure { + assertEq(left, Packing.pack_8_20(left, right).extract_28_8(0)); + assertEq(right, Packing.pack_8_20(left, right).extract_28_20(8)); + } + + function testPack(bytes8 left, bytes24 right) external pure { + assertEq(left, Packing.pack_8_24(left, right).extract_32_8(0)); + assertEq(right, Packing.pack_8_24(left, right).extract_32_24(8)); + } + + function testPack(bytes10 left, bytes2 right) external pure { + assertEq(left, Packing.pack_10_2(left, right).extract_12_10(0)); + assertEq(right, Packing.pack_10_2(left, right).extract_12_2(10)); + } + + function testPack(bytes10 left, bytes6 right) external pure { + assertEq(left, Packing.pack_10_6(left, right).extract_16_10(0)); + assertEq(right, Packing.pack_10_6(left, right).extract_16_6(10)); + } + + function testPack(bytes10 left, bytes10 right) external pure { + assertEq(left, Packing.pack_10_10(left, right).extract_20_10(0)); + assertEq(right, Packing.pack_10_10(left, right).extract_20_10(10)); + } + + function testPack(bytes10 left, bytes12 right) external pure { + assertEq(left, Packing.pack_10_12(left, right).extract_22_10(0)); + assertEq(right, Packing.pack_10_12(left, right).extract_22_12(10)); + } + + function testPack(bytes10 left, bytes22 right) external pure { + assertEq(left, Packing.pack_10_22(left, right).extract_32_10(0)); + assertEq(right, Packing.pack_10_22(left, right).extract_32_22(10)); + } + + function testPack(bytes12 left, bytes4 right) external pure { + assertEq(left, Packing.pack_12_4(left, right).extract_16_12(0)); + assertEq(right, Packing.pack_12_4(left, right).extract_16_4(12)); + } + + function testPack(bytes12 left, bytes8 right) external pure { + assertEq(left, Packing.pack_12_8(left, right).extract_20_12(0)); + assertEq(right, Packing.pack_12_8(left, right).extract_20_8(12)); + } + + function testPack(bytes12 left, bytes10 right) external pure { + assertEq(left, Packing.pack_12_10(left, right).extract_22_12(0)); + assertEq(right, Packing.pack_12_10(left, right).extract_22_10(12)); + } + + function testPack(bytes12 left, bytes12 right) external pure { + assertEq(left, Packing.pack_12_12(left, right).extract_24_12(0)); + assertEq(right, Packing.pack_12_12(left, right).extract_24_12(12)); + } + + function testPack(bytes12 left, bytes16 right) external pure { + assertEq(left, Packing.pack_12_16(left, right).extract_28_12(0)); + assertEq(right, Packing.pack_12_16(left, right).extract_28_16(12)); + } + + function testPack(bytes12 left, bytes20 right) external pure { + assertEq(left, Packing.pack_12_20(left, right).extract_32_12(0)); + assertEq(right, Packing.pack_12_20(left, right).extract_32_20(12)); + } + + function testPack(bytes16 left, bytes4 right) external pure { + assertEq(left, Packing.pack_16_4(left, right).extract_20_16(0)); + assertEq(right, Packing.pack_16_4(left, right).extract_20_4(16)); + } + + function testPack(bytes16 left, bytes6 right) external pure { + assertEq(left, Packing.pack_16_6(left, right).extract_22_16(0)); + assertEq(right, Packing.pack_16_6(left, right).extract_22_6(16)); + } + + function testPack(bytes16 left, bytes8 right) external pure { + assertEq(left, Packing.pack_16_8(left, right).extract_24_16(0)); + assertEq(right, Packing.pack_16_8(left, right).extract_24_8(16)); + } + + function testPack(bytes16 left, bytes12 right) external pure { + assertEq(left, Packing.pack_16_12(left, right).extract_28_16(0)); + assertEq(right, Packing.pack_16_12(left, right).extract_28_12(16)); + } + + function testPack(bytes16 left, bytes16 right) external pure { + assertEq(left, Packing.pack_16_16(left, right).extract_32_16(0)); + assertEq(right, Packing.pack_16_16(left, right).extract_32_16(16)); + } + + function testPack(bytes20 left, bytes2 right) external pure { + assertEq(left, Packing.pack_20_2(left, right).extract_22_20(0)); + assertEq(right, Packing.pack_20_2(left, right).extract_22_2(20)); + } + + function testPack(bytes20 left, bytes4 right) external pure { + assertEq(left, Packing.pack_20_4(left, right).extract_24_20(0)); + assertEq(right, Packing.pack_20_4(left, right).extract_24_4(20)); + } + + function testPack(bytes20 left, bytes8 right) external pure { + assertEq(left, Packing.pack_20_8(left, right).extract_28_20(0)); + assertEq(right, Packing.pack_20_8(left, right).extract_28_8(20)); + } + + function testPack(bytes20 left, bytes12 right) external pure { + assertEq(left, Packing.pack_20_12(left, right).extract_32_20(0)); + assertEq(right, Packing.pack_20_12(left, right).extract_32_12(20)); + } + + function testPack(bytes22 left, bytes2 right) external pure { + assertEq(left, Packing.pack_22_2(left, right).extract_24_22(0)); + assertEq(right, Packing.pack_22_2(left, right).extract_24_2(22)); + } + + function testPack(bytes22 left, bytes6 right) external pure { + assertEq(left, Packing.pack_22_6(left, right).extract_28_22(0)); + assertEq(right, Packing.pack_22_6(left, right).extract_28_6(22)); + } + + function testPack(bytes22 left, bytes10 right) external pure { + assertEq(left, Packing.pack_22_10(left, right).extract_32_22(0)); + assertEq(right, Packing.pack_22_10(left, right).extract_32_10(22)); + } + + function testPack(bytes24 left, bytes4 right) external pure { + assertEq(left, Packing.pack_24_4(left, right).extract_28_24(0)); + assertEq(right, Packing.pack_24_4(left, right).extract_28_4(24)); + } + + function testPack(bytes24 left, bytes8 right) external pure { + assertEq(left, Packing.pack_24_8(left, right).extract_32_24(0)); + assertEq(right, Packing.pack_24_8(left, right).extract_32_8(24)); + } + + function testPack(bytes28 left, bytes4 right) external pure { + assertEq(left, Packing.pack_28_4(left, right).extract_32_28(0)); + assertEq(right, Packing.pack_28_4(left, right).extract_32_4(28)); + } + + function testReplace(bytes2 container, bytes1 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 1)); + + bytes1 oldValue = container.extract_2_1(offset); + + assertEq(newValue, container.replace_2_1(newValue, offset).extract_2_1(offset)); + assertEq(container, container.replace_2_1(newValue, offset).replace_2_1(oldValue, offset)); + } + + function testReplace(bytes4 container, bytes1 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 3)); + + bytes1 oldValue = container.extract_4_1(offset); + + assertEq(newValue, container.replace_4_1(newValue, offset).extract_4_1(offset)); + assertEq(container, container.replace_4_1(newValue, offset).replace_4_1(oldValue, offset)); + } + + function testReplace(bytes4 container, bytes2 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 2)); + + bytes2 oldValue = container.extract_4_2(offset); + + assertEq(newValue, container.replace_4_2(newValue, offset).extract_4_2(offset)); + assertEq(container, container.replace_4_2(newValue, offset).replace_4_2(oldValue, offset)); + } + + function testReplace(bytes6 container, bytes1 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 5)); + + bytes1 oldValue = container.extract_6_1(offset); + + assertEq(newValue, container.replace_6_1(newValue, offset).extract_6_1(offset)); + assertEq(container, container.replace_6_1(newValue, offset).replace_6_1(oldValue, offset)); + } + + function testReplace(bytes6 container, bytes2 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 4)); + + bytes2 oldValue = container.extract_6_2(offset); + + assertEq(newValue, container.replace_6_2(newValue, offset).extract_6_2(offset)); + assertEq(container, container.replace_6_2(newValue, offset).replace_6_2(oldValue, offset)); + } + + function testReplace(bytes6 container, bytes4 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 2)); + + bytes4 oldValue = container.extract_6_4(offset); + + assertEq(newValue, container.replace_6_4(newValue, offset).extract_6_4(offset)); + assertEq(container, container.replace_6_4(newValue, offset).replace_6_4(oldValue, offset)); + } + + function testReplace(bytes8 container, bytes1 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 7)); + + bytes1 oldValue = container.extract_8_1(offset); + + assertEq(newValue, container.replace_8_1(newValue, offset).extract_8_1(offset)); + assertEq(container, container.replace_8_1(newValue, offset).replace_8_1(oldValue, offset)); + } + + function testReplace(bytes8 container, bytes2 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 6)); + + bytes2 oldValue = container.extract_8_2(offset); + + assertEq(newValue, container.replace_8_2(newValue, offset).extract_8_2(offset)); + assertEq(container, container.replace_8_2(newValue, offset).replace_8_2(oldValue, offset)); + } + + function testReplace(bytes8 container, bytes4 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 4)); + + bytes4 oldValue = container.extract_8_4(offset); + + assertEq(newValue, container.replace_8_4(newValue, offset).extract_8_4(offset)); + assertEq(container, container.replace_8_4(newValue, offset).replace_8_4(oldValue, offset)); + } + + function testReplace(bytes8 container, bytes6 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 2)); + + bytes6 oldValue = container.extract_8_6(offset); + + assertEq(newValue, container.replace_8_6(newValue, offset).extract_8_6(offset)); + assertEq(container, container.replace_8_6(newValue, offset).replace_8_6(oldValue, offset)); + } + + function testReplace(bytes10 container, bytes1 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 9)); + + bytes1 oldValue = container.extract_10_1(offset); + + assertEq(newValue, container.replace_10_1(newValue, offset).extract_10_1(offset)); + assertEq(container, container.replace_10_1(newValue, offset).replace_10_1(oldValue, offset)); + } + + function testReplace(bytes10 container, bytes2 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 8)); + + bytes2 oldValue = container.extract_10_2(offset); + + assertEq(newValue, container.replace_10_2(newValue, offset).extract_10_2(offset)); + assertEq(container, container.replace_10_2(newValue, offset).replace_10_2(oldValue, offset)); + } + + function testReplace(bytes10 container, bytes4 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 6)); + + bytes4 oldValue = container.extract_10_4(offset); + + assertEq(newValue, container.replace_10_4(newValue, offset).extract_10_4(offset)); + assertEq(container, container.replace_10_4(newValue, offset).replace_10_4(oldValue, offset)); + } + + function testReplace(bytes10 container, bytes6 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 4)); + + bytes6 oldValue = container.extract_10_6(offset); + + assertEq(newValue, container.replace_10_6(newValue, offset).extract_10_6(offset)); + assertEq(container, container.replace_10_6(newValue, offset).replace_10_6(oldValue, offset)); + } + + function testReplace(bytes10 container, bytes8 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 2)); + + bytes8 oldValue = container.extract_10_8(offset); + + assertEq(newValue, container.replace_10_8(newValue, offset).extract_10_8(offset)); + assertEq(container, container.replace_10_8(newValue, offset).replace_10_8(oldValue, offset)); + } + + function testReplace(bytes12 container, bytes1 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 11)); + + bytes1 oldValue = container.extract_12_1(offset); + + assertEq(newValue, container.replace_12_1(newValue, offset).extract_12_1(offset)); + assertEq(container, container.replace_12_1(newValue, offset).replace_12_1(oldValue, offset)); + } + + function testReplace(bytes12 container, bytes2 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 10)); + + bytes2 oldValue = container.extract_12_2(offset); + + assertEq(newValue, container.replace_12_2(newValue, offset).extract_12_2(offset)); + assertEq(container, container.replace_12_2(newValue, offset).replace_12_2(oldValue, offset)); + } + + function testReplace(bytes12 container, bytes4 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 8)); + + bytes4 oldValue = container.extract_12_4(offset); + + assertEq(newValue, container.replace_12_4(newValue, offset).extract_12_4(offset)); + assertEq(container, container.replace_12_4(newValue, offset).replace_12_4(oldValue, offset)); + } + + function testReplace(bytes12 container, bytes6 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 6)); + + bytes6 oldValue = container.extract_12_6(offset); + + assertEq(newValue, container.replace_12_6(newValue, offset).extract_12_6(offset)); + assertEq(container, container.replace_12_6(newValue, offset).replace_12_6(oldValue, offset)); + } + + function testReplace(bytes12 container, bytes8 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 4)); + + bytes8 oldValue = container.extract_12_8(offset); + + assertEq(newValue, container.replace_12_8(newValue, offset).extract_12_8(offset)); + assertEq(container, container.replace_12_8(newValue, offset).replace_12_8(oldValue, offset)); + } + + function testReplace(bytes12 container, bytes10 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 2)); + + bytes10 oldValue = container.extract_12_10(offset); + + assertEq(newValue, container.replace_12_10(newValue, offset).extract_12_10(offset)); + assertEq(container, container.replace_12_10(newValue, offset).replace_12_10(oldValue, offset)); + } + + function testReplace(bytes16 container, bytes1 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 15)); + + bytes1 oldValue = container.extract_16_1(offset); + + assertEq(newValue, container.replace_16_1(newValue, offset).extract_16_1(offset)); + assertEq(container, container.replace_16_1(newValue, offset).replace_16_1(oldValue, offset)); + } + + function testReplace(bytes16 container, bytes2 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 14)); + + bytes2 oldValue = container.extract_16_2(offset); + + assertEq(newValue, container.replace_16_2(newValue, offset).extract_16_2(offset)); + assertEq(container, container.replace_16_2(newValue, offset).replace_16_2(oldValue, offset)); + } + + function testReplace(bytes16 container, bytes4 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 12)); + + bytes4 oldValue = container.extract_16_4(offset); + + assertEq(newValue, container.replace_16_4(newValue, offset).extract_16_4(offset)); + assertEq(container, container.replace_16_4(newValue, offset).replace_16_4(oldValue, offset)); + } + + function testReplace(bytes16 container, bytes6 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 10)); + + bytes6 oldValue = container.extract_16_6(offset); + + assertEq(newValue, container.replace_16_6(newValue, offset).extract_16_6(offset)); + assertEq(container, container.replace_16_6(newValue, offset).replace_16_6(oldValue, offset)); + } + + function testReplace(bytes16 container, bytes8 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 8)); + + bytes8 oldValue = container.extract_16_8(offset); + + assertEq(newValue, container.replace_16_8(newValue, offset).extract_16_8(offset)); + assertEq(container, container.replace_16_8(newValue, offset).replace_16_8(oldValue, offset)); + } + + function testReplace(bytes16 container, bytes10 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 6)); + + bytes10 oldValue = container.extract_16_10(offset); + + assertEq(newValue, container.replace_16_10(newValue, offset).extract_16_10(offset)); + assertEq(container, container.replace_16_10(newValue, offset).replace_16_10(oldValue, offset)); + } + + function testReplace(bytes16 container, bytes12 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 4)); + + bytes12 oldValue = container.extract_16_12(offset); + + assertEq(newValue, container.replace_16_12(newValue, offset).extract_16_12(offset)); + assertEq(container, container.replace_16_12(newValue, offset).replace_16_12(oldValue, offset)); + } + + function testReplace(bytes20 container, bytes1 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 19)); + + bytes1 oldValue = container.extract_20_1(offset); + + assertEq(newValue, container.replace_20_1(newValue, offset).extract_20_1(offset)); + assertEq(container, container.replace_20_1(newValue, offset).replace_20_1(oldValue, offset)); + } + + function testReplace(bytes20 container, bytes2 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 18)); + + bytes2 oldValue = container.extract_20_2(offset); + + assertEq(newValue, container.replace_20_2(newValue, offset).extract_20_2(offset)); + assertEq(container, container.replace_20_2(newValue, offset).replace_20_2(oldValue, offset)); + } + + function testReplace(bytes20 container, bytes4 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 16)); + + bytes4 oldValue = container.extract_20_4(offset); + + assertEq(newValue, container.replace_20_4(newValue, offset).extract_20_4(offset)); + assertEq(container, container.replace_20_4(newValue, offset).replace_20_4(oldValue, offset)); + } + + function testReplace(bytes20 container, bytes6 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 14)); + + bytes6 oldValue = container.extract_20_6(offset); + + assertEq(newValue, container.replace_20_6(newValue, offset).extract_20_6(offset)); + assertEq(container, container.replace_20_6(newValue, offset).replace_20_6(oldValue, offset)); + } + + function testReplace(bytes20 container, bytes8 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 12)); + + bytes8 oldValue = container.extract_20_8(offset); + + assertEq(newValue, container.replace_20_8(newValue, offset).extract_20_8(offset)); + assertEq(container, container.replace_20_8(newValue, offset).replace_20_8(oldValue, offset)); + } + + function testReplace(bytes20 container, bytes10 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 10)); + + bytes10 oldValue = container.extract_20_10(offset); + + assertEq(newValue, container.replace_20_10(newValue, offset).extract_20_10(offset)); + assertEq(container, container.replace_20_10(newValue, offset).replace_20_10(oldValue, offset)); + } + + function testReplace(bytes20 container, bytes12 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 8)); + + bytes12 oldValue = container.extract_20_12(offset); + + assertEq(newValue, container.replace_20_12(newValue, offset).extract_20_12(offset)); + assertEq(container, container.replace_20_12(newValue, offset).replace_20_12(oldValue, offset)); + } + + function testReplace(bytes20 container, bytes16 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 4)); + + bytes16 oldValue = container.extract_20_16(offset); + + assertEq(newValue, container.replace_20_16(newValue, offset).extract_20_16(offset)); + assertEq(container, container.replace_20_16(newValue, offset).replace_20_16(oldValue, offset)); + } + + function testReplace(bytes22 container, bytes1 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 21)); + + bytes1 oldValue = container.extract_22_1(offset); + + assertEq(newValue, container.replace_22_1(newValue, offset).extract_22_1(offset)); + assertEq(container, container.replace_22_1(newValue, offset).replace_22_1(oldValue, offset)); + } + + function testReplace(bytes22 container, bytes2 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 20)); + + bytes2 oldValue = container.extract_22_2(offset); + + assertEq(newValue, container.replace_22_2(newValue, offset).extract_22_2(offset)); + assertEq(container, container.replace_22_2(newValue, offset).replace_22_2(oldValue, offset)); + } + + function testReplace(bytes22 container, bytes4 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 18)); + + bytes4 oldValue = container.extract_22_4(offset); + + assertEq(newValue, container.replace_22_4(newValue, offset).extract_22_4(offset)); + assertEq(container, container.replace_22_4(newValue, offset).replace_22_4(oldValue, offset)); + } + + function testReplace(bytes22 container, bytes6 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 16)); + + bytes6 oldValue = container.extract_22_6(offset); + + assertEq(newValue, container.replace_22_6(newValue, offset).extract_22_6(offset)); + assertEq(container, container.replace_22_6(newValue, offset).replace_22_6(oldValue, offset)); + } + + function testReplace(bytes22 container, bytes8 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 14)); + + bytes8 oldValue = container.extract_22_8(offset); + + assertEq(newValue, container.replace_22_8(newValue, offset).extract_22_8(offset)); + assertEq(container, container.replace_22_8(newValue, offset).replace_22_8(oldValue, offset)); + } + + function testReplace(bytes22 container, bytes10 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 12)); + + bytes10 oldValue = container.extract_22_10(offset); + + assertEq(newValue, container.replace_22_10(newValue, offset).extract_22_10(offset)); + assertEq(container, container.replace_22_10(newValue, offset).replace_22_10(oldValue, offset)); + } + + function testReplace(bytes22 container, bytes12 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 10)); + + bytes12 oldValue = container.extract_22_12(offset); + + assertEq(newValue, container.replace_22_12(newValue, offset).extract_22_12(offset)); + assertEq(container, container.replace_22_12(newValue, offset).replace_22_12(oldValue, offset)); + } + + function testReplace(bytes22 container, bytes16 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 6)); + + bytes16 oldValue = container.extract_22_16(offset); + + assertEq(newValue, container.replace_22_16(newValue, offset).extract_22_16(offset)); + assertEq(container, container.replace_22_16(newValue, offset).replace_22_16(oldValue, offset)); + } + + function testReplace(bytes22 container, bytes20 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 2)); + + bytes20 oldValue = container.extract_22_20(offset); + + assertEq(newValue, container.replace_22_20(newValue, offset).extract_22_20(offset)); + assertEq(container, container.replace_22_20(newValue, offset).replace_22_20(oldValue, offset)); + } + + function testReplace(bytes24 container, bytes1 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 23)); + + bytes1 oldValue = container.extract_24_1(offset); + + assertEq(newValue, container.replace_24_1(newValue, offset).extract_24_1(offset)); + assertEq(container, container.replace_24_1(newValue, offset).replace_24_1(oldValue, offset)); + } + + function testReplace(bytes24 container, bytes2 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 22)); + + bytes2 oldValue = container.extract_24_2(offset); + + assertEq(newValue, container.replace_24_2(newValue, offset).extract_24_2(offset)); + assertEq(container, container.replace_24_2(newValue, offset).replace_24_2(oldValue, offset)); + } + + function testReplace(bytes24 container, bytes4 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 20)); + + bytes4 oldValue = container.extract_24_4(offset); + + assertEq(newValue, container.replace_24_4(newValue, offset).extract_24_4(offset)); + assertEq(container, container.replace_24_4(newValue, offset).replace_24_4(oldValue, offset)); + } + + function testReplace(bytes24 container, bytes6 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 18)); + + bytes6 oldValue = container.extract_24_6(offset); + + assertEq(newValue, container.replace_24_6(newValue, offset).extract_24_6(offset)); + assertEq(container, container.replace_24_6(newValue, offset).replace_24_6(oldValue, offset)); + } + + function testReplace(bytes24 container, bytes8 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 16)); + + bytes8 oldValue = container.extract_24_8(offset); + + assertEq(newValue, container.replace_24_8(newValue, offset).extract_24_8(offset)); + assertEq(container, container.replace_24_8(newValue, offset).replace_24_8(oldValue, offset)); + } + + function testReplace(bytes24 container, bytes10 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 14)); + + bytes10 oldValue = container.extract_24_10(offset); + + assertEq(newValue, container.replace_24_10(newValue, offset).extract_24_10(offset)); + assertEq(container, container.replace_24_10(newValue, offset).replace_24_10(oldValue, offset)); + } + + function testReplace(bytes24 container, bytes12 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 12)); + + bytes12 oldValue = container.extract_24_12(offset); + + assertEq(newValue, container.replace_24_12(newValue, offset).extract_24_12(offset)); + assertEq(container, container.replace_24_12(newValue, offset).replace_24_12(oldValue, offset)); + } + + function testReplace(bytes24 container, bytes16 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 8)); + + bytes16 oldValue = container.extract_24_16(offset); + + assertEq(newValue, container.replace_24_16(newValue, offset).extract_24_16(offset)); + assertEq(container, container.replace_24_16(newValue, offset).replace_24_16(oldValue, offset)); + } + + function testReplace(bytes24 container, bytes20 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 4)); + + bytes20 oldValue = container.extract_24_20(offset); + + assertEq(newValue, container.replace_24_20(newValue, offset).extract_24_20(offset)); + assertEq(container, container.replace_24_20(newValue, offset).replace_24_20(oldValue, offset)); + } + + function testReplace(bytes24 container, bytes22 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 2)); + + bytes22 oldValue = container.extract_24_22(offset); + + assertEq(newValue, container.replace_24_22(newValue, offset).extract_24_22(offset)); + assertEq(container, container.replace_24_22(newValue, offset).replace_24_22(oldValue, offset)); + } + + function testReplace(bytes28 container, bytes1 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 27)); + + bytes1 oldValue = container.extract_28_1(offset); + + assertEq(newValue, container.replace_28_1(newValue, offset).extract_28_1(offset)); + assertEq(container, container.replace_28_1(newValue, offset).replace_28_1(oldValue, offset)); + } + + function testReplace(bytes28 container, bytes2 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 26)); + + bytes2 oldValue = container.extract_28_2(offset); + + assertEq(newValue, container.replace_28_2(newValue, offset).extract_28_2(offset)); + assertEq(container, container.replace_28_2(newValue, offset).replace_28_2(oldValue, offset)); + } + + function testReplace(bytes28 container, bytes4 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 24)); + + bytes4 oldValue = container.extract_28_4(offset); + + assertEq(newValue, container.replace_28_4(newValue, offset).extract_28_4(offset)); + assertEq(container, container.replace_28_4(newValue, offset).replace_28_4(oldValue, offset)); + } + + function testReplace(bytes28 container, bytes6 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 22)); + + bytes6 oldValue = container.extract_28_6(offset); + + assertEq(newValue, container.replace_28_6(newValue, offset).extract_28_6(offset)); + assertEq(container, container.replace_28_6(newValue, offset).replace_28_6(oldValue, offset)); + } + + function testReplace(bytes28 container, bytes8 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 20)); + + bytes8 oldValue = container.extract_28_8(offset); + + assertEq(newValue, container.replace_28_8(newValue, offset).extract_28_8(offset)); + assertEq(container, container.replace_28_8(newValue, offset).replace_28_8(oldValue, offset)); + } + + function testReplace(bytes28 container, bytes10 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 18)); + + bytes10 oldValue = container.extract_28_10(offset); + + assertEq(newValue, container.replace_28_10(newValue, offset).extract_28_10(offset)); + assertEq(container, container.replace_28_10(newValue, offset).replace_28_10(oldValue, offset)); + } + + function testReplace(bytes28 container, bytes12 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 16)); + + bytes12 oldValue = container.extract_28_12(offset); + + assertEq(newValue, container.replace_28_12(newValue, offset).extract_28_12(offset)); + assertEq(container, container.replace_28_12(newValue, offset).replace_28_12(oldValue, offset)); + } + + function testReplace(bytes28 container, bytes16 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 12)); + + bytes16 oldValue = container.extract_28_16(offset); + + assertEq(newValue, container.replace_28_16(newValue, offset).extract_28_16(offset)); + assertEq(container, container.replace_28_16(newValue, offset).replace_28_16(oldValue, offset)); + } + + function testReplace(bytes28 container, bytes20 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 8)); + + bytes20 oldValue = container.extract_28_20(offset); + + assertEq(newValue, container.replace_28_20(newValue, offset).extract_28_20(offset)); + assertEq(container, container.replace_28_20(newValue, offset).replace_28_20(oldValue, offset)); + } + + function testReplace(bytes28 container, bytes22 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 6)); + + bytes22 oldValue = container.extract_28_22(offset); + + assertEq(newValue, container.replace_28_22(newValue, offset).extract_28_22(offset)); + assertEq(container, container.replace_28_22(newValue, offset).replace_28_22(oldValue, offset)); + } + + function testReplace(bytes28 container, bytes24 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 4)); + + bytes24 oldValue = container.extract_28_24(offset); + + assertEq(newValue, container.replace_28_24(newValue, offset).extract_28_24(offset)); + assertEq(container, container.replace_28_24(newValue, offset).replace_28_24(oldValue, offset)); + } + + function testReplace(bytes32 container, bytes1 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 31)); + + bytes1 oldValue = container.extract_32_1(offset); + + assertEq(newValue, container.replace_32_1(newValue, offset).extract_32_1(offset)); + assertEq(container, container.replace_32_1(newValue, offset).replace_32_1(oldValue, offset)); + } + + function testReplace(bytes32 container, bytes2 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 30)); + + bytes2 oldValue = container.extract_32_2(offset); + + assertEq(newValue, container.replace_32_2(newValue, offset).extract_32_2(offset)); + assertEq(container, container.replace_32_2(newValue, offset).replace_32_2(oldValue, offset)); + } + + function testReplace(bytes32 container, bytes4 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 28)); + + bytes4 oldValue = container.extract_32_4(offset); + + assertEq(newValue, container.replace_32_4(newValue, offset).extract_32_4(offset)); + assertEq(container, container.replace_32_4(newValue, offset).replace_32_4(oldValue, offset)); + } + + function testReplace(bytes32 container, bytes6 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 26)); + + bytes6 oldValue = container.extract_32_6(offset); + + assertEq(newValue, container.replace_32_6(newValue, offset).extract_32_6(offset)); + assertEq(container, container.replace_32_6(newValue, offset).replace_32_6(oldValue, offset)); + } + + function testReplace(bytes32 container, bytes8 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 24)); + + bytes8 oldValue = container.extract_32_8(offset); + + assertEq(newValue, container.replace_32_8(newValue, offset).extract_32_8(offset)); + assertEq(container, container.replace_32_8(newValue, offset).replace_32_8(oldValue, offset)); + } + + function testReplace(bytes32 container, bytes10 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 22)); + + bytes10 oldValue = container.extract_32_10(offset); + + assertEq(newValue, container.replace_32_10(newValue, offset).extract_32_10(offset)); + assertEq(container, container.replace_32_10(newValue, offset).replace_32_10(oldValue, offset)); + } + + function testReplace(bytes32 container, bytes12 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 20)); + + bytes12 oldValue = container.extract_32_12(offset); + + assertEq(newValue, container.replace_32_12(newValue, offset).extract_32_12(offset)); + assertEq(container, container.replace_32_12(newValue, offset).replace_32_12(oldValue, offset)); + } + + function testReplace(bytes32 container, bytes16 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 16)); + + bytes16 oldValue = container.extract_32_16(offset); + + assertEq(newValue, container.replace_32_16(newValue, offset).extract_32_16(offset)); + assertEq(container, container.replace_32_16(newValue, offset).replace_32_16(oldValue, offset)); + } + + function testReplace(bytes32 container, bytes20 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 12)); + + bytes20 oldValue = container.extract_32_20(offset); + + assertEq(newValue, container.replace_32_20(newValue, offset).extract_32_20(offset)); + assertEq(container, container.replace_32_20(newValue, offset).replace_32_20(oldValue, offset)); + } + + function testReplace(bytes32 container, bytes22 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 10)); + + bytes22 oldValue = container.extract_32_22(offset); + + assertEq(newValue, container.replace_32_22(newValue, offset).extract_32_22(offset)); + assertEq(container, container.replace_32_22(newValue, offset).replace_32_22(oldValue, offset)); + } + + function testReplace(bytes32 container, bytes24 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 8)); + + bytes24 oldValue = container.extract_32_24(offset); + + assertEq(newValue, container.replace_32_24(newValue, offset).extract_32_24(offset)); + assertEq(container, container.replace_32_24(newValue, offset).replace_32_24(oldValue, offset)); + } + + function testReplace(bytes32 container, bytes28 newValue, uint8 offset) external pure { + offset = uint8(bound(offset, 0, 4)); + + bytes28 oldValue = container.extract_32_28(offset); + + assertEq(newValue, container.replace_32_28(newValue, offset).extract_32_28(offset)); + assertEq(container, container.replace_32_28(newValue, offset).replace_32_28(oldValue, offset)); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.test.js new file mode 100644 index 0000000..dd36f45 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.test.js @@ -0,0 +1,70 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { forceDeployCode } = require('../helpers/deploy'); +const { product } = require('../helpers/iterate'); +const { SIZES } = require('../../scripts/generate/templates/Packing.opts'); + +async function fixture() { + return { mock: await forceDeployCode('$Packing') }; +} + +describe('Packing', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('pack', function () { + for (const [size1, size2] of product(SIZES, SIZES).filter(([size1, size2]) => SIZES.includes(size1 + size2))) { + const value1 = ethers.hexlify(ethers.randomBytes(size1)); + const value2 = ethers.hexlify(ethers.randomBytes(size2)); + const packed = ethers.concat([value1, value2]); + + it(`pack bytes${size1} + bytes${size2} => bytes${size1 + size2}`, async function () { + expect(await this.mock[`$pack_${size1}_${size2}`](value1, value2)).to.equal(packed); + expect(await this.mock[`$extract_${size1 + size2}_${size1}`](packed, 0)).to.equal(value1); + expect(await this.mock[`$extract_${size1 + size2}_${size2}`](packed, size1)).to.equal(value2); + }); + } + }); + + describe('extract / replace', function () { + for (const [size1, size2] of product(SIZES, SIZES).filter(([size1, size2]) => size1 > size2)) { + const MAX_OFFSET = size1 - size2; + const offset = ethers.toNumber(ethers.randomBytes(1)) % (MAX_OFFSET + 1); + const outer = ethers.randomBytes(size1); + const value = ethers.randomBytes(size2); + + it(`extract bytes${size2} from bytes${size1}`, async function () { + expect(await this.mock[`$extract_${size1}_${size2}`](outer, offset)).to.equal( + ethers.hexlify(outer.slice(offset, offset + size2)), + ); + + await expect(this.mock[`$extract_${size1}_${size2}`](outer, MAX_OFFSET)).to.not.be.revertedWithCustomError( + this.mock, + 'OutOfRangeAccess', + ); + + await expect(this.mock[`$extract_${size1}_${size2}`](outer, MAX_OFFSET + 1)).to.be.revertedWithCustomError( + this.mock, + 'OutOfRangeAccess', + ); + }); + + it(`replace bytes${size2} from bytes${size1}`, async function () { + expect(await this.mock[`$replace_${size1}_${size2}`](outer, value, offset)).to.equal( + ethers.concat([outer.slice(0, offset), value, outer.slice(offset + size2)]), + ); + + await expect( + this.mock[`$replace_${size1}_${size2}`](outer, value, MAX_OFFSET), + ).to.not.be.revertedWithCustomError(this.mock, 'OutOfRangeAccess'); + + await expect( + this.mock[`$replace_${size1}_${size2}`](outer, value, MAX_OFFSET + 1), + ).to.be.revertedWithCustomError(this.mock, 'OutOfRangeAccess'); + }); + } + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Panic.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Panic.test.js new file mode 100644 index 0000000..49673c7 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Panic.test.js @@ -0,0 +1,37 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +async function fixture() { + return { mock: await ethers.deployContract('$Panic') }; +} + +describe('Panic', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + for (const [name, code] of Object.entries({ + GENERIC: 0x0, + ASSERT: PANIC_CODES.ASSERTION_ERROR, + UNDER_OVERFLOW: PANIC_CODES.ARITHMETIC_OVERFLOW, + DIVISION_BY_ZERO: PANIC_CODES.DIVISION_BY_ZERO, + ENUM_CONVERSION_ERROR: PANIC_CODES.ENUM_CONVERSION_OUT_OF_BOUNDS, + STORAGE_ENCODING_ERROR: PANIC_CODES.INCORRECTLY_ENCODED_STORAGE_BYTE_ARRAY, + EMPTY_ARRAY_POP: PANIC_CODES.POP_ON_EMPTY_ARRAY, + ARRAY_OUT_OF_BOUNDS: PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS, + RESOURCE_ERROR: PANIC_CODES.TOO_MUCH_MEMORY_ALLOCATED, + INVALID_INTERNAL_FUNCTION: PANIC_CODES.ZERO_INITIALIZED_VARIABLE, + })) { + describe(`${name} (${ethers.toBeHex(code)})`, function () { + it('exposes panic code as constant', async function () { + expect(await this.mock.getFunction(`$${name}`)()).to.equal(code); + }); + + it('reverts with panic when called', async function () { + await expect(this.mock.$panic(code)).to.be.revertedWithPanic(code); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Pausable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Pausable.test.js new file mode 100644 index 0000000..67d74a0 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Pausable.test.js @@ -0,0 +1,90 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +async function fixture() { + const [pauser] = await ethers.getSigners(); + + const mock = await ethers.deployContract('PausableMock'); + + return { pauser, mock }; +} + +describe('Pausable', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('when unpaused', function () { + beforeEach(async function () { + expect(await this.mock.paused()).to.be.false; + }); + + it('can perform normal process in non-pause', async function () { + expect(await this.mock.count()).to.equal(0n); + + await this.mock.normalProcess(); + expect(await this.mock.count()).to.equal(1n); + }); + + it('cannot take drastic measure in non-pause', async function () { + await expect(this.mock.drasticMeasure()).to.be.revertedWithCustomError(this.mock, 'ExpectedPause'); + + expect(await this.mock.drasticMeasureTaken()).to.be.false; + }); + + describe('when paused', function () { + beforeEach(async function () { + this.tx = await this.mock.pause(); + }); + + it('emits a Paused event', async function () { + await expect(this.tx).to.emit(this.mock, 'Paused').withArgs(this.pauser); + }); + + it('cannot perform normal process in pause', async function () { + await expect(this.mock.normalProcess()).to.be.revertedWithCustomError(this.mock, 'EnforcedPause'); + }); + + it('can take a drastic measure in a pause', async function () { + await this.mock.drasticMeasure(); + expect(await this.mock.drasticMeasureTaken()).to.be.true; + }); + + it('reverts when re-pausing', async function () { + await expect(this.mock.pause()).to.be.revertedWithCustomError(this.mock, 'EnforcedPause'); + }); + + describe('unpausing', function () { + it('is unpausable by the pauser', async function () { + await this.mock.unpause(); + expect(await this.mock.paused()).to.be.false; + }); + + describe('when unpaused', function () { + beforeEach(async function () { + this.tx = await this.mock.unpause(); + }); + + it('emits an Unpaused event', async function () { + await expect(this.tx).to.emit(this.mock, 'Unpaused').withArgs(this.pauser); + }); + + it('should resume allowing normal process', async function () { + expect(await this.mock.count()).to.equal(0n); + await this.mock.normalProcess(); + expect(await this.mock.count()).to.equal(1n); + }); + + it('should prevent drastic measure', async function () { + await expect(this.mock.drasticMeasure()).to.be.revertedWithCustomError(this.mock, 'ExpectedPause'); + }); + + it('reverts when re-unpausing', async function () { + await expect(this.mock.unpause()).to.be.revertedWithCustomError(this.mock, 'ExpectedPause'); + }); + }); + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ReentrancyGuard.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ReentrancyGuard.test.js new file mode 100644 index 0000000..c441856 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ReentrancyGuard.test.js @@ -0,0 +1,50 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +for (const variant of ['', 'Transient']) { + describe(`Reentrancy${variant}Guard`, function () { + async function fixture() { + const name = `Reentrancy${variant}Mock`; + const mock = await ethers.deployContract(name); + return { name, mock }; + } + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('nonReentrant function can be called', async function () { + expect(await this.mock.counter()).to.equal(0n); + await this.mock.callback(); + expect(await this.mock.counter()).to.equal(1n); + }); + + it('does not allow remote callback', async function () { + const attacker = await ethers.deployContract('ReentrancyAttack'); + await expect(this.mock.countAndCall(attacker)).to.be.revertedWith('ReentrancyAttack: failed call'); + }); + + it('_reentrancyGuardEntered should be true when guarded', async function () { + await this.mock.guardedCheckEntered(); + }); + + it('_reentrancyGuardEntered should be false when unguarded', async function () { + await this.mock.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 expect(this.mock.countLocalRecursive(10n)).to.be.revertedWithCustomError( + this.mock, + 'ReentrancyGuardReentrantCall', + ); + }); + + it('does not allow indirect local recursion', async function () { + await expect(this.mock.countThisRecursive(10n)).to.be.revertedWith(`${this.name}: failed call`); + }); + }); +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.t.sol new file mode 100644 index 0000000..80313bf --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.t.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {SymTest} from "halmos-cheatcodes/SymTest.sol"; + +import {ShortStrings, ShortString} from "@openzeppelin/contracts/utils/ShortStrings.sol"; + +contract ShortStringsTest is Test, SymTest { + string _fallback; + + function testRoundtripShort(string memory input) external pure { + vm.assume(_isShort(input)); + _assertRoundtripShort(input); + } + + function symbolicRoundtripShort() external pure { + string memory input = svm.createString(31, "RoundtripShortInput"); + _assertRoundtripShort(input); + } + + function testRoundtripWithFallback(string memory input, string memory fallbackInitial) external { + _assertRoundtripWithFallback(input, fallbackInitial); + } + + function symbolicRoundtripWithFallbackLong() external { + string memory input = svm.createString(256, "RoundtripWithFallbackInput"); + string memory fallbackInitial = svm.createString(256, "RoundtripWithFallbackFallbackInitial"); + _assertRoundtripWithFallback(input, fallbackInitial); + } + + function symbolicRoundtripWithFallbackShort() external { + string memory input = svm.createString(31, "RoundtripWithFallbackInput"); + string memory fallbackInitial = svm.createString(31, "RoundtripWithFallbackFallbackInitial"); + _assertRoundtripWithFallback(input, fallbackInitial); + } + + function testRevertLong(string memory input) external { + vm.assume(!_isShort(input)); + _assertRevertLong(input); + } + + function testLengthShort(string memory input) external pure { + vm.assume(_isShort(input)); + _assertLengthShort(input); + } + + function symbolicLengthShort() external pure { + string memory input = svm.createString(31, "LengthShortInput"); + _assertLengthShort(input); + } + + function testLengthWithFallback(string memory input, string memory fallbackInitial) external { + _fallback = fallbackInitial; + _assertLengthWithFallback(input); + } + + function symbolicLengthWithFallback() external { + uint256 length = 256; + string memory input = svm.createString(length, "LengthWithFallbackInput"); + string memory fallbackInitial = svm.createString(length, "LengthWithFallbackFallbackInitial"); + _fallback = fallbackInitial; + _assertLengthWithFallback(input); + } + + /// Assertions + + function _assertRoundtripShort(string memory input) internal pure { + ShortString short = ShortStrings.toShortString(input); + string memory output = ShortStrings.toString(short); + assertEq(input, output); + } + + function _assertRoundtripWithFallback(string memory input, string memory fallbackInitial) internal { + _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 _assertRevertLong(string memory input) internal { + vm.expectRevert(abi.encodeWithSelector(ShortStrings.StringTooLong.selector, input)); + this.toShortString(input); + } + + function _assertLengthShort(string memory input) internal pure { + ShortString short = ShortStrings.toShortString(input); + uint256 shortLength = ShortStrings.byteLength(short); + uint256 inputLength = bytes(input).length; + assertEq(inputLength, shortLength); + } + + function _assertLengthWithFallback(string memory input) internal { + uint256 inputLength = bytes(input).length; + ShortString short = ShortStrings.toShortStringWithFallback(input, _fallback); + uint256 shortLength = ShortStrings.byteLengthWithFallback(short, _fallback); + assertEq(inputLength, shortLength); + } + + /// Helpers + 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/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.test.js new file mode 100644 index 0000000..cb1a06a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.test.js @@ -0,0 +1,64 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const FALLBACK_SENTINEL = ethers.zeroPadValue('0xFF', 32); + +const length = sstr => parseInt(sstr.slice(64), 16); +const decode = sstr => ethers.toUtf8String(sstr).slice(0, length(sstr)); +const encode = str => + str.length < 32 + ? ethers.concat([ + ethers.encodeBytes32String(str).slice(0, -2), + ethers.zeroPadValue(ethers.toBeArray(str.length), 1), + ]) + : FALLBACK_SENTINEL; + +async function fixture() { + const mock = await ethers.deployContract('$ShortStrings'); + return { mock }; +} + +describe('ShortStrings', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + 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(encoded).to.equal(encode(str)); + expect(decode(encoded)).to.equal(str); + + expect(await this.mock.$byteLength(encoded)).to.equal(str.length); + expect(await this.mock.$toString(encoded)).to.equal(str); + } else { + await expect(this.mock.$toShortString(str)) + .to.be.revertedWithCustomError(this.mock, 'StringTooLong') + .withArgs(str); + } + }); + + it('set / get with fallback', async function () { + const short = await this.mock + .$toShortStringWithFallback(str, 0) + .then(tx => tx.wait()) + .then(receipt => receipt.logs.find(ev => ev.fragment.name == 'return$toShortStringWithFallback').args[0]); + + expect(short).to.equal(encode(str)); + + const promise = this.mock.$toString(short); + if (str.length < 32) { + expect(await promise).to.equal(str); + } else { + await expect(promise).to.be.revertedWithCustomError(this.mock, 'InvalidShortString'); + } + + expect(await this.mock.$byteLengthWithFallback(short, 0)).to.equal(str.length); + expect(await this.mock.$toStringWithFallback(short, 0)).to.equal(str); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.t.sol new file mode 100644 index 0000000..a0846e3 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.t.sol @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: MIT +// This file was procedurally generated from scripts/generate/templates/SlotDerivation.t.js. + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {SymTest} from "halmos-cheatcodes/SymTest.sol"; +import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; + +contract SlotDerivationTest is Test, SymTest { + using SlotDerivation for bytes32; + + bytes[] private _array; + + function symbolicDeriveArray(uint256 length, uint256 offset) public { + vm.assume(length > 0); + vm.assume(offset < length); + _assertDeriveArray(length, offset); + } + + function testDeriveArray(uint256 length, uint256 offset) public { + length = bound(length, 1, type(uint256).max); + offset = bound(offset, 0, length - 1); + _assertDeriveArray(length, offset); + } + + function _assertDeriveArray(uint256 length, uint256 offset) public { + bytes32 baseSlot; + assembly { + baseSlot := _array.slot + sstore(baseSlot, length) // store length so solidity access does not revert + } + + bytes storage derived = _array[offset]; + bytes32 derivedSlot; + assembly { + derivedSlot := derived.slot + } + + assertEq(baseSlot.deriveArray().offset(offset), derivedSlot); + } + + mapping(address => bytes) private _addressMapping; + + function testSymbolicDeriveMappingAddress(address key) public view { + bytes32 baseSlot; + assembly { + baseSlot := _addressMapping.slot + } + + bytes storage derived = _addressMapping[key]; + bytes32 derivedSlot; + assembly { + derivedSlot := derived.slot + } + + assertEq(baseSlot.deriveMapping(key), derivedSlot); + } + + mapping(bool => bytes) private _boolMapping; + + function testSymbolicDeriveMappingBoolean(bool key) public view { + bytes32 baseSlot; + assembly { + baseSlot := _boolMapping.slot + } + + bytes storage derived = _boolMapping[key]; + bytes32 derivedSlot; + assembly { + derivedSlot := derived.slot + } + + assertEq(baseSlot.deriveMapping(key), derivedSlot); + } + + mapping(bytes32 => bytes) private _bytes32Mapping; + + function testSymbolicDeriveMappingBytes32(bytes32 key) public view { + bytes32 baseSlot; + assembly { + baseSlot := _bytes32Mapping.slot + } + + bytes storage derived = _bytes32Mapping[key]; + bytes32 derivedSlot; + assembly { + derivedSlot := derived.slot + } + + assertEq(baseSlot.deriveMapping(key), derivedSlot); + } + + mapping(bytes4 => bytes) private _bytes4Mapping; + + function testSymbolicDeriveMappingBytes4(bytes4 key) public view { + bytes32 baseSlot; + assembly { + baseSlot := _bytes4Mapping.slot + } + + bytes storage derived = _bytes4Mapping[key]; + bytes32 derivedSlot; + assembly { + derivedSlot := derived.slot + } + + assertEq(baseSlot.deriveMapping(key), derivedSlot); + } + + mapping(uint256 => bytes) private _uint256Mapping; + + function testSymbolicDeriveMappingUint256(uint256 key) public view { + bytes32 baseSlot; + assembly { + baseSlot := _uint256Mapping.slot + } + + bytes storage derived = _uint256Mapping[key]; + bytes32 derivedSlot; + assembly { + derivedSlot := derived.slot + } + + assertEq(baseSlot.deriveMapping(key), derivedSlot); + } + + mapping(uint32 => bytes) private _uint32Mapping; + + function testSymbolicDeriveMappingUint32(uint32 key) public view { + bytes32 baseSlot; + assembly { + baseSlot := _uint32Mapping.slot + } + + bytes storage derived = _uint32Mapping[key]; + bytes32 derivedSlot; + assembly { + derivedSlot := derived.slot + } + + assertEq(baseSlot.deriveMapping(key), derivedSlot); + } + + mapping(int256 => bytes) private _int256Mapping; + + function testSymbolicDeriveMappingInt256(int256 key) public view { + bytes32 baseSlot; + assembly { + baseSlot := _int256Mapping.slot + } + + bytes storage derived = _int256Mapping[key]; + bytes32 derivedSlot; + assembly { + derivedSlot := derived.slot + } + + assertEq(baseSlot.deriveMapping(key), derivedSlot); + } + + mapping(int32 => bytes) private _int32Mapping; + + function testSymbolicDeriveMappingInt32(int32 key) public view { + bytes32 baseSlot; + assembly { + baseSlot := _int32Mapping.slot + } + + bytes storage derived = _int32Mapping[key]; + bytes32 derivedSlot; + assembly { + derivedSlot := derived.slot + } + + assertEq(baseSlot.deriveMapping(key), derivedSlot); + } + + mapping(string => bytes) private _stringMapping; + + function testDeriveMappingString(string memory key) public view { + _assertDeriveMappingString(key); + } + + function symbolicDeriveMappingString() public view { + _assertDeriveMappingString(svm.createString(256, "DeriveMappingStringInput")); + } + + function _assertDeriveMappingString(string memory key) internal view { + bytes32 baseSlot; + assembly { + baseSlot := _stringMapping.slot + } + + bytes storage derived = _stringMapping[key]; + bytes32 derivedSlot; + assembly { + derivedSlot := derived.slot + } + + assertEq(baseSlot.deriveMapping(key), derivedSlot); + } + + mapping(bytes => bytes) private _bytesMapping; + + function testDeriveMappingBytes(bytes memory key) public view { + _assertDeriveMappingBytes(key); + } + + function symbolicDeriveMappingBytes() public view { + _assertDeriveMappingBytes(svm.createBytes(256, "DeriveMappingBytesInput")); + } + + function _assertDeriveMappingBytes(bytes memory key) internal view { + bytes32 baseSlot; + assembly { + baseSlot := _bytesMapping.slot + } + + bytes storage derived = _bytesMapping[key]; + bytes32 derivedSlot; + assembly { + derivedSlot := derived.slot + } + + assertEq(baseSlot.deriveMapping(key), derivedSlot); + } + + function testSymbolicDeriveMappingBooleanDirty(bytes32 dirtyKey) public { + bool key; + assembly { + key := dirtyKey + } + + // run the "normal" test using a potentially dirty value + testSymbolicDeriveMappingBoolean(key); + } + + function testSymbolicDeriveMappingAddressDirty(bytes32 dirtyKey) public { + address key; + assembly { + key := dirtyKey + } + + // run the "normal" test using a potentially dirty value + testSymbolicDeriveMappingAddress(key); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.test.js new file mode 100644 index 0000000..22582b3 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.test.js @@ -0,0 +1,58 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { erc7201Slot } = require('../helpers/storage'); +const { generators } = require('../helpers/random'); + +async function fixture() { + const [account] = await ethers.getSigners(); + const mock = await ethers.deployContract('$SlotDerivation'); + return { mock, account }; +} + +describe('SlotDerivation', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('namespaces', function () { + const namespace = 'example.main'; + + it('erc-7201', async function () { + expect(await this.mock.$erc7201Slot(namespace)).to.equal(erc7201Slot(namespace)); + }); + }); + + describe('derivation', function () { + it('offset', async function () { + const base = generators.bytes32(); + const offset = generators.uint256(); + expect(await this.mock.$offset(base, offset)).to.equal((ethers.toBigInt(base) + offset) & ethers.MaxUint256); + }); + + it('array', async function () { + const base = generators.bytes32(); + expect(await this.mock.$deriveArray(base)).to.equal(ethers.keccak256(base)); + }); + + describe('mapping', function () { + for (const { type, key, isValueType } of [ + { type: 'bool', key: true, isValueType: true }, + { type: 'address', key: generators.address(), isValueType: true }, + { type: 'bytes32', key: generators.bytes32(), isValueType: true }, + { type: 'uint256', key: generators.uint256(), isValueType: true }, + { type: 'int256', key: generators.int256(), isValueType: true }, + { type: 'bytes', key: generators.hexBytes(128), isValueType: false }, + { type: 'string', key: 'lorem ipsum', isValueType: false }, + ]) { + it(type, async function () { + const base = generators.bytes32(); + const expected = isValueType + ? ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode([type, 'bytes32'], [key, base])) + : ethers.solidityPackedKeccak256([type, 'bytes32'], [key, base]); + expect(await this.mock[`$deriveMapping(bytes32,${type})`](base, key)).to.equal(expected); + }); + } + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js new file mode 100644 index 0000000..ddcf305 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js @@ -0,0 +1,73 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { generators } = require('../helpers/random'); + +const slot = ethers.id('some.storage.slot'); +const otherSlot = ethers.id('some.other.storage.slot'); + +const TYPES = [ + { name: 'Boolean', type: 'bool', value: true, isValueType: true, zero: false }, + { name: 'Address', type: 'address', value: generators.address(), isValueType: true, zero: generators.address.zero }, + { name: 'Bytes32', type: 'bytes32', value: generators.bytes32(), isValueType: true, zero: generators.bytes32.zero }, + { name: 'Uint256', type: 'uint256', value: generators.uint256(), isValueType: true, zero: generators.uint256.zero }, + { name: 'Int256', type: 'int256', value: generators.int256(), isValueType: true, zero: generators.int256.zero }, + { name: 'Bytes', type: 'bytes', value: generators.hexBytes(128), isValueType: false, zero: generators.hexBytes.zero }, + { name: 'String', type: 'string', value: 'lorem ipsum', isValueType: false, zero: '' }, +]; + +async function fixture() { + return { mock: await ethers.deployContract('StorageSlotMock') }; +} + +describe('StorageSlot', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + for (const { name, type, value, zero } of TYPES) { + describe(`${type} storage slot`, function () { + it('set', async function () { + await this.mock.getFunction(`set${name}Slot`)(slot, value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.mock.getFunction(`set${name}Slot`)(slot, value); + }); + + it('from right slot', async function () { + expect(await this.mock.getFunction(`get${name}Slot`)(slot)).to.equal(value); + }); + + it('from other slot', async function () { + expect(await this.mock.getFunction(`get${name}Slot`)(otherSlot)).to.equal(zero); + }); + }); + }); + } + + for (const { name, type, value, zero } of TYPES.filter(type => !type.isValueType)) { + describe(`${type} storage pointer`, function () { + it('set', async function () { + await this.mock.getFunction(`set${name}Storage`)(slot, value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.mock.getFunction(`set${name}Storage`)(slot, value); + }); + + it('from right slot', async function () { + expect(await this.mock.getFunction(`${type}Map`)(slot)).to.equal(value); + expect(await this.mock.getFunction(`get${name}Storage`)(slot)).to.equal(value); + }); + + it('from other slot', async function () { + expect(await this.mock.getFunction(`${type}Map`)(otherSlot)).to.equal(zero); + expect(await this.mock.getFunction(`get${name}Storage`)(otherSlot)).to.equal(zero); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.t.sol new file mode 100644 index 0000000..fe3c90b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.t.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; + +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; + +contract StringsTest is Test { + using Strings for *; + + function testParse(uint256 value) external pure { + assertEq(value, value.toString().parseUint()); + } + + function testParseSigned(int256 value) external pure { + assertEq(value, value.toStringSigned().parseInt()); + } + + function testParseHex(uint256 value) external pure { + assertEq(value, value.toHexString().parseHexUint()); + } + + function testParseChecksumHex(address value) external pure { + assertEq(value, value.toChecksumHexString().parseAddress()); + } + + function testTryParseHexUintExtendedEnd(string memory random) external pure { + uint256 length = bytes(random).length; + assembly ("memory-safe") { + mstore(add(add(random, 0x20), length), 0x3030303030303030303030303030303030303030303030303030303030303030) + } + + (bool success, ) = random.tryParseHexUint(1, length + 1); + assertFalse(success); + } + + function testTryParseAddressExtendedEnd(address random, uint256 begin) external pure { + begin = bound(begin, 3, 43); + string memory input = random.toHexString(); + uint256 length = bytes(input).length; + + assembly ("memory-safe") { + mstore(add(add(input, 0x20), length), 0x3030303030303030303030303030303030303030303030303030303030303030) + } + + (bool success, ) = input.tryParseAddress(begin, begin + 40); + assertFalse(success); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.test.js new file mode 100644 index 0000000..8d5e240 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.test.js @@ -0,0 +1,349 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +async function fixture() { + const mock = await ethers.deployContract('$Strings'); + return { mock }; +} + +describe('Strings', function () { + before(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('toString', function () { + const values = [ + 0n, + 7n, + 10n, + 99n, + 100n, + 101n, + 123n, + 4132n, + 12345n, + 1234567n, + 1234567890n, + 123456789012345n, + 12345678901234567890n, + 123456789012345678901234567890n, + 1234567890123456789012345678901234567890n, + 12345678901234567890123456789012345678901234567890n, + 123456789012345678901234567890123456789012345678901234567890n, + 1234567890123456789012345678901234567890123456789012345678901234567890n, + ]; + + describe('uint256', function () { + it('converts MAX_UINT256', async function () { + const value = ethers.MaxUint256; + expect(await this.mock.$toString(value)).to.equal(value.toString(10)); + expect(await this.mock.$parseUint(value.toString(10))).to.equal(value); + expect(await this.mock.$tryParseUint(value.toString(10))).to.deep.equal([true, value]); + }); + + for (const value of values) { + it(`converts ${value}`, async function () { + expect(await this.mock.$toString(value)).to.equal(value.toString(10)); + expect(await this.mock.$parseUint(value.toString(10))).to.equal(value); + expect(await this.mock.$tryParseUint(value.toString(10))).to.deep.equal([true, value]); + }); + } + }); + + describe('int256', function () { + it('converts MAX_INT256', async function () { + const value = ethers.MaxInt256; + expect(await this.mock.$toStringSigned(value)).to.equal(value.toString(10)); + expect(await this.mock.$parseInt(value.toString(10))).to.equal(value); + expect(await this.mock.$tryParseInt(value.toString(10))).to.deep.equal([true, value]); + }); + + it('converts MIN_INT256', async function () { + const value = ethers.MinInt256; + expect(await this.mock.$toStringSigned(value)).to.equal(value.toString(10)); + expect(await this.mock.$parseInt(value.toString(10))).to.equal(value); + expect(await this.mock.$tryParseInt(value.toString(10))).to.deep.equal([true, value]); + }); + + for (const value of values) { + it(`convert ${value}`, async function () { + expect(await this.mock.$toStringSigned(value)).to.equal(value.toString(10)); + expect(await this.mock.$parseInt(value.toString(10))).to.equal(value); + expect(await this.mock.$tryParseInt(value.toString(10))).to.deep.equal([true, value]); + }); + + it(`convert negative ${value}`, async function () { + const negated = -value; + expect(await this.mock.$toStringSigned(negated)).to.equal(negated.toString(10)); + expect(await this.mock.$parseInt(negated.toString(10))).to.equal(negated); + expect(await this.mock.$tryParseInt(negated.toString(10))).to.deep.equal([true, negated]); + }); + } + }); + }); + + describe('toHexString', function () { + it('converts 0', async function () { + const value = 0n; + const string = ethers.toBeHex(value); // 0x00 + + expect(await this.mock.getFunction('$toHexString(uint256)')(value)).to.equal(string); + expect(await this.mock.$parseHexUint(string)).to.equal(value); + expect(await this.mock.$parseHexUint(string.replace(/0x/, ''))).to.equal(value); + expect(await this.mock.$tryParseHexUint(string)).to.deep.equal([true, value]); + expect(await this.mock.$tryParseHexUint(string.replace(/0x/, ''))).to.deep.equal([true, value]); + }); + + it('converts a positive number', async function () { + const value = 0x4132n; + const string = ethers.toBeHex(value); + + expect(await this.mock.getFunction('$toHexString(uint256)')(value)).to.equal(string); + expect(await this.mock.$parseHexUint(string)).to.equal(value); + expect(await this.mock.$parseHexUint(string.replace(/0x/, ''))).to.equal(value); + expect(await this.mock.$tryParseHexUint(string)).to.deep.equal([true, value]); + expect(await this.mock.$tryParseHexUint(string.replace(/0x/, ''))).to.deep.equal([true, value]); + }); + + it('converts MAX_UINT256', async function () { + const value = ethers.MaxUint256; + const string = ethers.toBeHex(value); + + expect(await this.mock.getFunction('$toHexString(uint256)')(value)).to.equal(string); + expect(await this.mock.$parseHexUint(string)).to.equal(value); + expect(await this.mock.$parseHexUint(string.replace(/0x/, ''))).to.equal(value); + expect(await this.mock.$tryParseHexUint(string)).to.deep.equal([true, value]); + expect(await this.mock.$tryParseHexUint(string.replace(/0x/, ''))).to.deep.equal([true, value]); + }); + }); + + describe('toHexString fixed', function () { + it('converts a positive number (long)', async function () { + expect(await this.mock.getFunction('$toHexString(uint256,uint256)')(0x4132n, 32n)).to.equal( + '0x0000000000000000000000000000000000000000000000000000000000004132', + ); + }); + + it('converts a positive number (short)', async function () { + const length = 1n; + await expect(this.mock.getFunction('$toHexString(uint256,uint256)')(0x4132n, length)) + .to.be.revertedWithCustomError(this.mock, 'StringsInsufficientHexLength') + .withArgs(0x4132, length); + }); + + it('converts MAX_UINT256', async function () { + expect(await this.mock.getFunction('$toHexString(uint256,uint256)')(ethers.MaxUint256, 32n)).to.equal( + ethers.toBeHex(ethers.MaxUint256), + ); + }); + }); + + describe('addresses', function () { + const addresses = [ + '0xa9036907dccae6a1e0033479b12e837e5cf5a02f', // Random address + '0x0000e0ca771e21bd00057f54a68c30d400000000', // Leading and trailing zeros + // EIP-55 reference + '0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed', + '0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359', + '0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB', + '0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb', + '0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359', + '0x52908400098527886E0F7030069857D2E4169EE7', + '0x8617E340B3D01FA5F11F306F4090FD50E238070D', + '0xde709f2102306220921060314715629080e2fb77', + '0x27b1fdb04752bbc536007a920d24acb045561c26', + '0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed', + '0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359', + '0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB', + '0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb', + ]; + + describe('toHexString', function () { + for (const addr of addresses) { + it(`converts ${addr}`, async function () { + expect(await this.mock.getFunction('$toHexString(address)')(addr)).to.equal(addr.toLowerCase()); + }); + } + }); + + describe('toChecksumHexString', function () { + for (const addr of addresses) { + it(`converts ${addr}`, async function () { + expect(await this.mock.$toChecksumHexString(addr)).to.equal(ethers.getAddress(addr)); + }); + } + }); + + describe('parseAddress', function () { + for (const addr of addresses) { + it(`converts ${addr}`, async function () { + expect(await this.mock.$parseAddress(addr)).to.equal(ethers.getAddress(addr)); + expect(await this.mock.$tryParseAddress(addr)).to.deep.equal([true, ethers.getAddress(addr)]); + }); + } + }); + }); + + describe('equal', function () { + it('compares two empty strings', async function () { + expect(await this.mock.$equal('', '')).to.be.true; + }); + + it('compares two equal strings', async function () { + expect(await this.mock.$equal('a', 'a')).to.be.true; + }); + + it('compares two different strings', async function () { + expect(await this.mock.$equal('a', 'b')).to.be.false; + }); + + it('compares two different strings of different lengths', async function () { + expect(await this.mock.$equal('a', 'aa')).to.be.false; + expect(await this.mock.$equal('aa', 'a')).to.be.false; + }); + + it('compares two different large strings', async function () { + const str1 = 'a'.repeat(201); + const str2 = 'a'.repeat(200) + 'b'; + expect(await this.mock.$equal(str1, str2)).to.be.false; + }); + + it('compares two equal large strings', async function () { + const str1 = 'a'.repeat(201); + const str2 = 'a'.repeat(201); + expect(await this.mock.$equal(str1, str2)).to.be.true; + }); + }); + + describe('Edge cases: invalid parsing', function () { + it('parseUint overflow', async function () { + await expect(this.mock.$parseUint((ethers.MaxUint256 + 1n).toString(10))).to.be.revertedWithPanic( + PANIC_CODES.ARITHMETIC_OVERFLOW, + ); + await expect(this.mock.$tryParseUint((ethers.MaxUint256 + 1n).toString(10))).to.be.revertedWithPanic( + PANIC_CODES.ARITHMETIC_OVERFLOW, + ); + }); + + it('parseUint invalid character', async function () { + await expect(this.mock.$parseUint('0x1')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + await expect(this.mock.$parseUint('1f')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + await expect(this.mock.$parseUint('-10')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + await expect(this.mock.$parseUint('1.0')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + await expect(this.mock.$parseUint('1 000')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + expect(await this.mock.$tryParseUint('0x1')).to.deep.equal([false, 0n]); + expect(await this.mock.$tryParseUint('1f')).to.deep.equal([false, 0n]); + expect(await this.mock.$tryParseUint('-10')).to.deep.equal([false, 0n]); + expect(await this.mock.$tryParseUint('1.0')).deep.equal([false, 0n]); + expect(await this.mock.$tryParseUint('1 000')).deep.equal([false, 0n]); + }); + + it('parseUint invalid range', async function () { + expect(this.mock.$parseUint('12', 3, 2)).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + expect(await this.mock.$tryParseUint('12', 3, 2)).to.deep.equal([false, 0n]); + }); + + it('parseInt overflow', async function () { + await expect(this.mock.$parseInt((ethers.MaxUint256 + 1n).toString(10))).to.be.revertedWithPanic( + PANIC_CODES.ARITHMETIC_OVERFLOW, + ); + await expect(this.mock.$parseInt((-ethers.MaxUint256 - 1n).toString(10))).to.be.revertedWithPanic( + PANIC_CODES.ARITHMETIC_OVERFLOW, + ); + await expect(this.mock.$tryParseInt((ethers.MaxUint256 + 1n).toString(10))).to.be.revertedWithPanic( + PANIC_CODES.ARITHMETIC_OVERFLOW, + ); + await expect(this.mock.$tryParseInt((-ethers.MaxUint256 - 1n).toString(10))).to.be.revertedWithPanic( + PANIC_CODES.ARITHMETIC_OVERFLOW, + ); + await expect(this.mock.$parseInt((ethers.MaxInt256 + 1n).toString(10))).to.be.revertedWithCustomError( + this.mock, + 'StringsInvalidChar', + ); + await expect(this.mock.$parseInt((ethers.MinInt256 - 1n).toString(10))).to.be.revertedWithCustomError( + this.mock, + 'StringsInvalidChar', + ); + expect(await this.mock.$tryParseInt((ethers.MaxInt256 + 1n).toString(10))).to.deep.equal([false, 0n]); + expect(await this.mock.$tryParseInt((ethers.MinInt256 - 1n).toString(10))).to.deep.equal([false, 0n]); + }); + + it('parseInt invalid character', async function () { + await expect(this.mock.$parseInt('0x1')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + await expect(this.mock.$parseInt('1f')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + await expect(this.mock.$parseInt('1.0')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + await expect(this.mock.$parseInt('1 000')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + expect(await this.mock.$tryParseInt('0x1')).to.deep.equal([false, 0n]); + expect(await this.mock.$tryParseInt('1f')).to.deep.equal([false, 0n]); + expect(await this.mock.$tryParseInt('1.0')).to.deep.equal([false, 0n]); + expect(await this.mock.$tryParseInt('1 000')).to.deep.equal([false, 0n]); + }); + + it('parseInt invalid range', async function () { + expect(this.mock.$parseInt('-12', 3, 2)).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + expect(await this.mock.$tryParseInt('-12', 3, 2)).to.deep.equal([false, 0n]); + }); + + it('parseHexUint overflow', async function () { + await expect(this.mock.$parseHexUint((ethers.MaxUint256 + 1n).toString(16))).to.be.revertedWithPanic( + PANIC_CODES.ARITHMETIC_OVERFLOW, + ); + await expect(this.mock.$tryParseHexUint((ethers.MaxUint256 + 1n).toString(16))).to.be.revertedWithPanic( + PANIC_CODES.ARITHMETIC_OVERFLOW, + ); + }); + + it('parseHexUint invalid character', async function () { + await expect(this.mock.$parseHexUint('0123456789abcdefg')).to.be.revertedWithCustomError( + this.mock, + 'StringsInvalidChar', + ); + await expect(this.mock.$parseHexUint('-1')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + await expect(this.mock.$parseHexUint('-f')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + await expect(this.mock.$parseHexUint('-0xf')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + await expect(this.mock.$parseHexUint('1.0')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + await expect(this.mock.$parseHexUint('1 000')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + expect(await this.mock.$tryParseHexUint('0123456789abcdefg')).to.deep.equal([false, 0n]); + expect(await this.mock.$tryParseHexUint('-1')).to.deep.equal([false, 0n]); + expect(await this.mock.$tryParseHexUint('-f')).to.deep.equal([false, 0n]); + expect(await this.mock.$tryParseHexUint('-0xf')).to.deep.equal([false, 0n]); + expect(await this.mock.$tryParseHexUint('1.0')).to.deep.equal([false, 0n]); + expect(await this.mock.$tryParseHexUint('1 000')).to.deep.equal([false, 0n]); + }); + + it('parseHexUint invalid begin and end', async function () { + expect(this.mock.$parseHexUint('0x', 3, 2)).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); + expect(await this.mock.$tryParseHexUint('0x', 3, 2)).to.deep.equal([false, 0n]); + }); + + it('parseAddress invalid format', async function () { + for (const addr of [ + '0x736a507fB2881d6bB62dcA54673CF5295dC07833', // valid + '0x736a507fB2881d6-B62dcA54673CF5295dC07833', // invalid char + '0x0736a507fB2881d6bB62dcA54673CF5295dC07833', // tooLong + '0x36a507fB2881d6bB62dcA54673CF5295dC07833', // tooShort + '736a507fB2881d6bB62dcA54673CF5295dC07833', // missingPrefix - supported + ]) { + if (ethers.isAddress(addr)) { + expect(await this.mock.$parseAddress(addr)).to.equal(ethers.getAddress(addr)); + expect(await this.mock.$tryParseAddress(addr)).to.deep.equal([true, ethers.getAddress(addr)]); + } else { + await expect(this.mock.$parseAddress(addr)).to.be.revertedWithCustomError( + this.mock, + 'StringsInvalidAddressFormat', + ); + expect(await this.mock.$tryParseAddress(addr)).to.deep.equal([false, ethers.ZeroAddress]); + } + } + }); + }); + + describe('Escape JSON string', function () { + for (const input of ['', 'a', '{"a":"b/c"}', 'a\tb\nc\\d"e\rf/g\fh\bi']) + it(`escape ${JSON.stringify(input)}`, async function () { + await expect(this.mock.$escapeJSON(input)).to.eventually.equal(JSON.stringify(input).slice(1, -1)); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/TransientSlot.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/TransientSlot.test.js new file mode 100644 index 0000000..7b70be3 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/TransientSlot.test.js @@ -0,0 +1,59 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { generators } = require('../helpers/random'); + +const slot = ethers.id('some.storage.slot'); +const otherSlot = ethers.id('some.other.storage.slot'); + +// Non-value types are not supported by the `TransientSlot` library. +const TYPES = [ + { name: 'Boolean', type: 'bool', value: true, zero: false }, + { name: 'Address', type: 'address', value: generators.address(), zero: generators.address.zero }, + { name: 'Bytes32', type: 'bytes32', value: generators.bytes32(), zero: generators.bytes32.zero }, + { name: 'Uint256', type: 'uint256', value: generators.uint256(), zero: generators.uint256.zero }, + { name: 'Int256', type: 'int256', value: generators.int256(), zero: generators.int256.zero }, +]; + +async function fixture() { + return { mock: await ethers.deployContract('TransientSlotMock') }; +} + +describe('TransientSlot', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + for (const { name, type, value, zero } of TYPES) { + describe(`${type} transient slot`, function () { + const load = `tload${name}(bytes32)`; + const store = `tstore(bytes32,${type})`; + const event = `${name}Value`; + + it('load', async function () { + await expect(this.mock[load](slot)).to.emit(this.mock, event).withArgs(slot, zero); + }); + + it('store and load (2 txs)', async function () { + await this.mock[store](slot, value); + await expect(this.mock[load](slot)).to.emit(this.mock, event).withArgs(slot, zero); + }); + + it('store and load (batched)', async function () { + await expect( + this.mock.multicall([ + this.mock.interface.encodeFunctionData(store, [slot, value]), + this.mock.interface.encodeFunctionData(load, [slot]), + this.mock.interface.encodeFunctionData(load, [otherSlot]), + ]), + ) + .to.emit(this.mock, event) + .withArgs(slot, value) + .to.emit(this.mock, event) + .withArgs(otherSlot, zero); + + await expect(this.mock[load](slot)).to.emit(this.mock, event).withArgs(slot, zero); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js new file mode 100644 index 0000000..0f2879a --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js @@ -0,0 +1,211 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const TEST_MESSAGE = ethers.id('OpenZeppelin'); +const WRONG_MESSAGE = ethers.id('Nope'); +const NON_HASH_MESSAGE = '0xabcd'; + +async function fixture() { + const [signer] = await ethers.getSigners(); + const mock = await ethers.deployContract('$ECDSA'); + return { signer, mock }; +} + +describe('ECDSA', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('recover with invalid signature', function () { + it('with short signature', async function () { + await expect(this.mock.$recover(TEST_MESSAGE, '0x1234')) + .to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength') + .withArgs(2); + }); + + it('with long signature', async function () { + await expect( + this.mock.$recover( + TEST_MESSAGE, + '0x01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789', + ), + ) + .to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength') + .withArgs(85); + }); + }); + + describe('recover with valid signature', function () { + describe('using .sign', function () { + it('returns signer address with correct signature', async function () { + // Create the signature + const signature = await this.signer.signMessage(TEST_MESSAGE); + + // Recover the signer address from the generated message and signature. + expect(await this.mock.$recover(ethers.hashMessage(TEST_MESSAGE), signature)).to.equal(this.signer); + }); + + it('returns signer address with correct signature for arbitrary length message', async function () { + // Create the signature + const signature = await this.signer.signMessage(NON_HASH_MESSAGE); + + // Recover the signer address from the generated message and signature. + expect(await this.mock.$recover(ethers.hashMessage(NON_HASH_MESSAGE), signature)).to.equal(this.signer); + }); + + it('returns a different address', async function () { + const signature = await this.signer.signMessage(TEST_MESSAGE); + expect(await this.mock.$recover(WRONG_MESSAGE, signature)).to.not.be.equal(this.signer); + }); + + it('reverts with invalid signature', async function () { + const signature = + '0x332ce75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e01c'; + await expect(this.mock.$recover(TEST_MESSAGE, signature)).to.be.revertedWithCustomError( + this.mock, + 'ECDSAInvalidSignature', + ); + }); + }); + + describe('with v=27 signature', function () { + const signer = '0x2cc1166f6212628A0deEf2B33BEFB2187D35b86c'; + + const signatureWithoutV = + '0x5d99b6f7f6d1f73d1a26497f2b1c89b24c0993913f86e9a2d02cd69887d9c94f3c880358579d811b21dd1b7fd9bb01c1d81d10e69f0384e675c32b39643be892'; + + it('works with correct v value', async function () { + const v = '0x1b'; // 27 = 1b. + const signature = ethers.concat([signatureWithoutV, v]); + expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.equal(signer); + + const { r, s, yParityAndS: vs } = ethers.Signature.from(signature); + expect(await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s)).to.equal( + signer, + ); + + expect(await this.mock.getFunction('$recover(bytes32,bytes32,bytes32)')(TEST_MESSAGE, r, vs)).to.equal(signer); + }); + + it('rejects incorrect v value', async function () { + const v = '0x1c'; // 28 = 1c. + const signature = ethers.concat([signatureWithoutV, v]); + expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.not.equal(signer); + + const { r, s, yParityAndS: vs } = ethers.Signature.from(signature); + expect( + await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s), + ).to.not.equal(signer); + + expect(await this.mock.getFunction('$recover(bytes32,bytes32,bytes32)')(TEST_MESSAGE, r, vs)).to.not.equal( + signer, + ); + }); + + it('reverts wrong v values', async function () { + for (const v of ['0x00', '0x01']) { + const signature = ethers.concat([signatureWithoutV, v]); + await expect(this.mock.$recover(TEST_MESSAGE, signature)).to.be.revertedWithCustomError( + this.mock, + 'ECDSAInvalidSignature', + ); + + const { r, s } = ethers.Signature.from(signature); + await expect( + this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s), + ).to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignature'); + } + }); + + it('rejects short EIP2098 format', async function () { + const v = '0x1b'; // 27 = 1b. + const signature = ethers.concat([signatureWithoutV, v]); + + const { compactSerialized } = ethers.Signature.from(signature); + await expect(this.mock.$recover(TEST_MESSAGE, compactSerialized)) + .to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength') + .withArgs(64); + }); + }); + + describe('with v=28 signature', function () { + const signer = '0x1E318623aB09Fe6de3C9b8672098464Aeda9100E'; + + const signatureWithoutV = + '0x331fe75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e0'; + + it('works with correct v value', async function () { + const v = '0x1c'; // 28 = 1c. + const signature = ethers.concat([signatureWithoutV, v]); + expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.equal(signer); + + const { r, s, yParityAndS: vs } = ethers.Signature.from(signature); + expect(await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s)).to.equal( + signer, + ); + + expect(await this.mock.getFunction('$recover(bytes32,bytes32,bytes32)')(TEST_MESSAGE, r, vs)).to.equal(signer); + }); + + it('rejects incorrect v value', async function () { + const v = '0x1b'; // 27 = 1b. + const signature = ethers.concat([signatureWithoutV, v]); + expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.not.equal(signer); + + const { r, s, yParityAndS: vs } = ethers.Signature.from(signature); + expect( + await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s), + ).to.not.equal(signer); + + expect(await this.mock.getFunction('$recover(bytes32,bytes32,bytes32)')(TEST_MESSAGE, r, vs)).to.not.equal( + signer, + ); + }); + + it('reverts invalid v values', async function () { + for (const v of ['0x00', '0x01']) { + const signature = ethers.concat([signatureWithoutV, v]); + await expect(this.mock.$recover(TEST_MESSAGE, signature)).to.be.revertedWithCustomError( + this.mock, + 'ECDSAInvalidSignature', + ); + + const { r, s } = ethers.Signature.from(signature); + await expect( + this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s), + ).to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignature'); + } + }); + + it('rejects short EIP2098 format', async function () { + const v = '0x1b'; // 28 = 1b. + const signature = ethers.concat([signatureWithoutV, v]); + + const { compactSerialized } = ethers.Signature.from(signature); + await expect(this.mock.$recover(TEST_MESSAGE, compactSerialized)) + .to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength') + .withArgs(64); + }); + }); + + it('reverts with high-s value signature', async function () { + const message = '0xb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'; + + const highSSignature = + '0xe742ff452d41413616a5bf43fe15dd88294e983d3d36206c2712f39083d638bde0a0fc89be718fbc1033e1d30d78be1c68081562ed2e97af876f286f3453231d1b'; + + const r = ethers.dataSlice(highSSignature, 0, 32); + const s = ethers.dataSlice(highSSignature, 32, 64); + const v = ethers.dataSlice(highSSignature, 64, 65); + + await expect(this.mock.$recover(message, highSSignature)) + .to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureS') + .withArgs(s); + await expect(this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s)) + .to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureS') + .withArgs(s); + expect(() => ethers.Signature.from(highSSignature)).to.throw('non-canonical s'); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js new file mode 100644 index 0000000..2b6e7fa --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js @@ -0,0 +1,105 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { getDomain, domainSeparator, hashTypedData } = require('../../helpers/eip712'); +const { formatType } = require('../../helpers/eip712-types'); + +const LENGTHS = { + short: ['A Name', '1'], + long: ['A'.repeat(40), 'B'.repeat(40)], +}; + +const fixture = async () => { + const [from, to] = await ethers.getSigners(); + + const lengths = {}; + for (const [shortOrLong, [name, version]] of Object.entries(LENGTHS)) { + lengths[shortOrLong] = { name, version }; + lengths[shortOrLong].eip712 = await ethers.deployContract('$EIP712Verifier', [name, version]); + lengths[shortOrLong].domain = { + name, + version, + chainId: await ethers.provider.getNetwork().then(({ chainId }) => chainId), + verifyingContract: lengths[shortOrLong].eip712.target, + }; + } + + return { from, to, lengths }; +}; + +describe('EIP712', function () { + for (const [shortOrLong, [name, version]] of Object.entries(LENGTHS)) { + describe(`with ${shortOrLong} name and version`, function () { + beforeEach('deploying', async function () { + Object.assign(this, await loadFixture(fixture)); + Object.assign(this, this.lengths[shortOrLong]); + }); + + 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(rebuildDomain).to.be.deep.equal(this.domain); + }); + + 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 ethers.deployContract('$Clones'); + + const clone = await factory + .$clone(this.eip712) + .then(tx => tx.wait()) + .then(receipt => receipt.logs.find(ev => ev.fragment.name == 'return$clone_address').args.instance) + .then(address => ethers.getContractAt('$EIP712Verifier', address)); + + const expectedDomain = { ...this.domain, verifyingContract: clone.target }; + expect(await getDomain(clone)).to.be.deep.equal(expectedDomain); + + const expectedSeparator = await domainSeparator(expectedDomain); + expect(await clone.$_domainSeparatorV4()).to.equal(expectedSeparator); + }); + } + }); + + it('hash digest', async function () { + const structhash = ethers.hexlify(ethers.randomBytes(32)); + expect(await this.eip712.$_hashTypedDataV4(structhash)).to.equal(hashTypedData(this.domain, structhash)); + }); + + it('digest', async function () { + const types = { + Mail: formatType({ + to: 'address', + contents: 'string', + }), + }; + + const message = { + to: this.to.address, + contents: 'very interesting', + }; + + const signature = await this.from.signTypedData(this.domain, types, message); + + await expect(this.eip712.verify(signature, this.from.address, message.to, message.contents)).to.not.be.reverted; + }); + + it('name', async function () { + expect(await this.eip712.$_EIP712Name()).to.equal(name); + }); + + it('version', async function () { + expect(await this.eip712.$_EIP712Version()).to.equal(version); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC1271.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC1271.behavior.js new file mode 100644 index 0000000..ef3e668 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC1271.behavior.js @@ -0,0 +1,111 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { Permit, formatType, getDomain } = require('../../helpers/eip712'); +const { ERC7739Signer } = require('../../helpers/erc7739'); + +function shouldBehaveLikeERC1271({ erc7739 = false } = {}) { + const MAGIC_VALUE = '0x1626ba7e'; + + describe(`supports ERC-${erc7739 ? 7739 : 1271}`, function () { + beforeEach(async function () { + // if deploy function is present, check that code is already in place + if (this.mock.deploy) { + await ethers.provider.getCode(this.mock.address).then(code => code != '0x' || this.mock.deploy()); + } + this._signer = erc7739 + ? new ERC7739Signer(this.signer, this.domain ?? (await getDomain(this.mock))) + : this.signer; + }); + + describe('PersonalSign', function () { + it('returns true for a valid personal signature', async function () { + const text = 'Hello, world!'; + + const hash = ethers.hashMessage(text); + const signature = await this._signer.signMessage(text); + + await expect(this.mock.isValidSignature(hash, signature)).to.eventually.equal(MAGIC_VALUE); + }); + + it('returns false for an invalid personal signature', async function () { + const message = 'Message the app expects'; + const otherMessage = 'Message signed is different'; + + const hash = ethers.hashMessage(message); + const signature = await this._signer.signMessage(otherMessage); + + await expect(this.mock.isValidSignature(hash, signature)).to.eventually.not.equal(MAGIC_VALUE); + }); + }); + + describe('TypedDataSign', function () { + beforeEach(async function () { + // Dummy app domain, different from the ERC7739's domain + // Note the difference of format (signer domain doesn't include a salt, but app domain does) + this.appDomain = { + name: 'SomeApp', + version: '1', + chainId: await ethers.provider.getNetwork().then(({ chainId }) => chainId), + verifyingContract: '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', + salt: '0x02cb3d8cb5e8928c9c6de41e935e16a4e28b2d54e7e7ba47e99f16071efab785', + }; + }); + + it('returns true for a valid typed data signature', async function () { + const contents = { + owner: '0x1ab5E417d9AF00f1ca9d159007e12c401337a4bb', + spender: '0xD68E96620804446c4B1faB3103A08C98d4A8F55f', + value: 1_000_000n, + nonce: 0n, + deadline: ethers.MaxUint256, + }; + + const hash = ethers.TypedDataEncoder.hash(this.appDomain, { Permit }, contents); + const signature = await this._signer.signTypedData(this.appDomain, { Permit }, contents); + + await expect(this.mock.isValidSignature(hash, signature)).to.eventually.equal(MAGIC_VALUE); + }); + + it('returns true for valid typed data signature (nested types)', async function () { + const contentsTypes = { + B: formatType({ z: 'Z' }), + Z: formatType({ a: 'A' }), + A: formatType({ v: 'uint256' }), + }; + + const contents = { z: { a: { v: 1n } } }; + + const hash = ethers.TypedDataEncoder.hash(this.appDomain, contentsTypes, contents); + const signature = await this._signer.signTypedData(this.appDomain, contentsTypes, contents); + + await expect(this.mock.isValidSignature(hash, signature)).to.eventually.equal(MAGIC_VALUE); + }); + + it('returns false for an invalid typed data signature', async function () { + const contents = { + owner: '0x1ab5E417d9AF00f1ca9d159007e12c401337a4bb', + spender: '0xD68E96620804446c4B1faB3103A08C98d4A8F55f', + value: 1_000_000n, + nonce: 0n, + deadline: ethers.MaxUint256, + }; + + const hash = ethers.TypedDataEncoder.hash(this.appDomain, { Permit }, contents); + // message signed by the user is for a lower amount. + const signature = await this._signer.signTypedData(this.appDomain, { Permit }, { ...contents, value: 1_000n }); + + await expect(this.mock.isValidSignature(hash, signature)).to.eventually.not.equal(MAGIC_VALUE); + }); + }); + + erc7739 && + it('support ERC-7739 detection', async function () { + const hash = '0x7739773977397739773977397739773977397739773977397739773977397739'; + await expect(this.mock.isValidSignature(hash, '0x')).to.eventually.equal('0x77390001'); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC1271, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739.test.js new file mode 100644 index 0000000..8dc6a2b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739.test.js @@ -0,0 +1,42 @@ +const { ethers } = require('hardhat'); +const { shouldBehaveLikeERC1271 } = require('./ERC1271.behavior'); +const { NonNativeSigner, P256SigningKey, RSASHA256SigningKey } = require('../../helpers/signers'); + +describe('ERC7739', function () { + describe('for an ECDSA signer', function () { + before(async function () { + this.signer = ethers.Wallet.createRandom(); + this.mock = await ethers.deployContract('$ERC7739ECDSAMock', ['ERC7739ECDSA', '1', this.signer.address]); + }); + + shouldBehaveLikeERC1271({ erc7739: true }); + }); + + describe('for a P256 signer', function () { + before(async function () { + this.signer = new NonNativeSigner(P256SigningKey.random()); + this.mock = await ethers.deployContract('$ERC7739P256Mock', [ + 'ERC7739P256', + '1', + this.signer.signingKey.publicKey.qx, + this.signer.signingKey.publicKey.qy, + ]); + }); + + shouldBehaveLikeERC1271({ erc7739: true }); + }); + + describe('for an RSA signer', function () { + before(async function () { + this.signer = new NonNativeSigner(RSASHA256SigningKey.random()); + this.mock = await ethers.deployContract('$ERC7739RSAMock', [ + 'ERC7739RSA', + '1', + this.signer.signingKey.publicKey.e, + this.signer.signingKey.publicKey.n, + ]); + }); + + shouldBehaveLikeERC1271({ erc7739: true }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739Utils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739Utils.test.js new file mode 100644 index 0000000..93e382d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739Utils.test.js @@ -0,0 +1,203 @@ +const { expect } = require('chai'); +const { ethers } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { Permit } = require('../../helpers/eip712'); +const { ERC4337Utils, PersonalSign } = require('../../helpers/erc7739'); + +const details = ERC4337Utils.getContentsDetail({ Permit }); + +const fixture = async () => { + const mock = await ethers.deployContract('$ERC7739Utils'); + const domain = { + name: 'SomeDomain', + version: '1', + chainId: await ethers.provider.getNetwork().then(({ chainId }) => chainId), + verifyingContract: '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', + }; + const otherDomain = { + name: 'SomeOtherDomain', + version: '2', + chainId: await ethers.provider.getNetwork().then(({ chainId }) => chainId), + verifyingContract: '0x92C32cadBc39A15212505B5530aA765c441F306f', + }; + const permit = { + owner: '0x1ab5E417d9AF00f1ca9d159007e12c401337a4bb', + spender: '0xD68E96620804446c4B1faB3103A08C98d4A8F55f', + value: 1_000_000n, + nonce: 0n, + deadline: ethers.MaxUint256, + }; + return { mock, domain, otherDomain, permit }; +}; + +describe('ERC7739Utils', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('encodeTypedDataSig', function () { + it('wraps a typed data signature', async function () { + const signature = ethers.randomBytes(65); + const appSeparator = ethers.id('SomeApp'); + const contentsHash = ethers.id('SomeData'); + const contentsDescr = 'SomeType()'; + const encoded = ethers.concat([ + signature, + appSeparator, + contentsHash, + ethers.toUtf8Bytes(contentsDescr), + ethers.toBeHex(contentsDescr.length, 2), + ]); + + await expect( + this.mock.$encodeTypedDataSig(signature, appSeparator, contentsHash, contentsDescr), + ).to.eventually.equal(encoded); + }); + }); + + describe('decodeTypedDataSig', function () { + it('unwraps a typed data signature', async function () { + const signature = ethers.randomBytes(65); + const appSeparator = ethers.id('SomeApp'); + const contentsHash = ethers.id('SomeData'); + const contentsDescr = 'SomeType()'; + const encoded = ethers.concat([ + signature, + appSeparator, + contentsHash, + ethers.toUtf8Bytes(contentsDescr), + ethers.toBeHex(contentsDescr.length, 2), + ]); + + await expect(this.mock.$decodeTypedDataSig(encoded)).to.eventually.deep.equal([ + ethers.hexlify(signature), + appSeparator, + contentsHash, + contentsDescr, + ]); + }); + + it('returns default empty values if the signature is too short', async function () { + const encoded = ethers.randomBytes(65); // DOMAIN_SEPARATOR (32 bytes) + CONTENTS (32 bytes) + CONTENTS_TYPE_LENGTH (2 bytes) - 1 + await expect(this.mock.$decodeTypedDataSig(encoded)).to.eventually.deep.equal([ + '0x', + ethers.ZeroHash, + ethers.ZeroHash, + '', + ]); + }); + + it('returns default empty values if the length is invalid', async function () { + const encoded = ethers.concat([ethers.randomBytes(64), '0x3f']); // Can't be less than 64 bytes + await expect(this.mock.$decodeTypedDataSig(encoded)).to.eventually.deep.equal([ + '0x', + ethers.ZeroHash, + ethers.ZeroHash, + '', + ]); + }); + }); + + describe('personalSignStructhash', function () { + it('should produce a personal signature EIP-712 nested type', async function () { + const text = 'Hello, world!'; + + await expect(this.mock.$personalSignStructHash(ethers.hashMessage(text))).to.eventually.equal( + ethers.TypedDataEncoder.hashStruct('PersonalSign', { PersonalSign }, ERC4337Utils.preparePersonalSign(text)), + ); + }); + }); + + describe('typedDataSignStructHash', function () { + it('should match the typed data nested struct hash', async function () { + const message = ERC4337Utils.prepareSignTypedData(this.permit, this.domain); + + const contentsHash = ethers.TypedDataEncoder.hashStruct('Permit', { Permit }, this.permit); + const hash = ethers.TypedDataEncoder.hashStruct('TypedDataSign', details.allTypes, message); + + const domainBytes = ethers.AbiCoder.defaultAbiCoder().encode( + ['bytes32', 'bytes32', 'uint256', 'address', 'bytes32'], + [ + ethers.id(this.domain.name), + ethers.id(this.domain.version), + this.domain.chainId, + this.domain.verifyingContract, + ethers.ZeroHash, + ], + ); + + await expect( + this.mock.$typedDataSignStructHash( + details.contentsTypeName, + ethers.Typed.string(details.contentsDescr), + contentsHash, + domainBytes, + ), + ).to.eventually.equal(hash); + await expect( + this.mock.$typedDataSignStructHash(details.contentsDescr, contentsHash, domainBytes), + ).to.eventually.equal(hash); + }); + }); + + describe('typedDataSignTypehash', function () { + it('should match', async function () { + const typedDataSignType = ethers.TypedDataEncoder.from(details.allTypes).encodeType('TypedDataSign'); + + await expect( + this.mock.$typedDataSignTypehash( + details.contentsTypeName, + typedDataSignType.slice(typedDataSignType.indexOf(')') + 1), + ), + ).to.eventually.equal(ethers.keccak256(ethers.toUtf8Bytes(typedDataSignType))); + }); + }); + + describe('decodeContentsDescr', function () { + const forbiddenChars = ', )\x00'; + + for (const { descr, contentsDescr, contentTypeName, contentType } of [].concat( + { + descr: 'should parse a valid descriptor (implicit)', + contentsDescr: 'SomeType(address foo,uint256 bar)', + contentTypeName: 'SomeType', + }, + { + descr: 'should parse a valid descriptor (explicit)', + contentsDescr: 'A(C c)B(A a)C(uint256 v)B', + contentTypeName: 'B', + contentType: 'A(C c)B(A a)C(uint256 v)', + }, + { descr: 'should return nothing for an empty descriptor', contentsDescr: '', contentTypeName: null }, + { descr: 'should return nothing if no [(] is present', contentsDescr: 'SomeType', contentTypeName: null }, + { + descr: 'should return nothing if starts with [(] (implicit)', + contentsDescr: '(SomeType(address foo,uint256 bar)', + contentTypeName: null, + }, + { + descr: 'should return nothing if starts with [(] (explicit)', + contentsDescr: '(SomeType(address foo,uint256 bar)(SomeType', + contentTypeName: null, + }, + forbiddenChars.split('').map(char => ({ + descr: `should return nothing if contains [${char}] (implicit)`, + contentsDescr: `SomeType${char}(address foo,uint256 bar)`, + contentTypeName: null, + })), + forbiddenChars.split('').map(char => ({ + descr: `should return nothing if contains [${char}] (explicit)`, + contentsDescr: `SomeType${char}(address foo,uint256 bar)SomeType${char}`, + contentTypeName: null, + })), + )) { + it(descr, async function () { + await expect(this.mock.$decodeContentsDescr(contentsDescr)).to.eventually.deep.equal([ + contentTypeName ?? '', + contentTypeName ? (contentType ?? contentsDescr) : '', + ]); + }); + } + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js new file mode 100644 index 0000000..93ee964 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js @@ -0,0 +1,213 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); +const { SimpleMerkleTree } = require('@openzeppelin/merkle-tree'); + +// generate bytes32 leaves from a string +const toLeaves = (str, separator = '') => str.split(separator).map(e => ethers.keccak256(ethers.toUtf8Bytes(e))); +// internal node hashes +const concatSorted = (...elements) => Buffer.concat(elements.map(ethers.getBytes).sort(Buffer.compare)); +const defaultHash = (a, b) => ethers.keccak256(concatSorted(a, b)); +const customHash = (a, b) => ethers.sha256(concatSorted(a, b)); + +describe('MerkleProof', function () { + for (const { title, contractName, nodeHash } of [ + { title: 'default hash', contractName: '$MerkleProof', nodeHash: defaultHash }, + { title: 'custom hash', contractName: '$MerkleProofCustomHashMock', nodeHash: customHash }, + ]) { + describe(title, function () { + // stateless: no need for a fixture, just use before + before(async function () { + this.mock = await ethers.deployContract(contractName); + this.makeTree = str => SimpleMerkleTree.of(toLeaves(str), { nodeHash }); + }); + + describe('verify', function () { + it('returns true for a valid Merkle proof', async function () { + const merkleTree = this.makeTree('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='); + + const root = merkleTree.root; + const hash = merkleTree.at(0); + const proof = merkleTree.getProof(0); + + expect(await this.mock.$processProof(proof, hash)).to.equal(root); + expect(await this.mock.$processProofCalldata(proof, hash)).to.equal(root); + expect(await this.mock.$verify(proof, root, hash)).to.be.true; + expect(await this.mock.$verifyCalldata(proof, root, hash)).to.be.true; + + // For demonstration, it is also possible to create valid proofs for certain 64-byte values *not* in elements: + const noSuchLeaf = nodeHash(hash, proof.at(0)); + + expect(await this.mock.$processProof(proof.slice(1), noSuchLeaf)).to.equal(root); + expect(await this.mock.$processProofCalldata(proof.slice(1), noSuchLeaf)).to.equal(root); + expect(await this.mock.$verify(proof.slice(1), root, noSuchLeaf)).to.be.true; + expect(await this.mock.$verifyCalldata(proof.slice(1), root, noSuchLeaf)).to.be.true; + }); + + it('returns false for an invalid Merkle proof', async function () { + const correctMerkleTree = this.makeTree('abc'); + const otherMerkleTree = this.makeTree('def'); + + const root = correctMerkleTree.root; + const hash = correctMerkleTree.at(0); + const proof = otherMerkleTree.getProof(0); + + expect(await this.mock.$processProof(proof, hash)).to.not.equal(root); + expect(await this.mock.$processProofCalldata(proof, hash)).to.not.equal(root); + expect(await this.mock.$verify(proof, root, hash)).to.be.false; + expect(await this.mock.$verifyCalldata(proof, root, hash)).to.be.false; + }); + + it('returns false for a Merkle proof of invalid length', async function () { + const merkleTree = this.makeTree('abc'); + + const root = merkleTree.root; + const hash = merkleTree.at(0); + const proof = merkleTree.getProof(0); + const badProof = proof.slice(0, -1); + + expect(await this.mock.$processProof(badProof, hash)).to.not.equal(root); + expect(await this.mock.$processProofCalldata(badProof, hash)).to.not.equal(root); + expect(await this.mock.$verify(badProof, root, hash)).to.be.false; + expect(await this.mock.$verifyCalldata(badProof, root, hash)).to.be.false; + }); + }); + + describe('multiProofVerify', function () { + it('returns true for a valid Merkle multi proof', async function () { + const merkleTree = this.makeTree('abcdef'); + + const root = merkleTree.root; + const { proof, proofFlags, leaves } = merkleTree.getMultiProof(toLeaves('bdf')); + const hashes = leaves.map(e => merkleTree.leafHash(e)); + + expect(await this.mock.$processMultiProof(proof, proofFlags, hashes)).to.equal(root); + expect(await this.mock.$processMultiProofCalldata(proof, proofFlags, hashes)).to.equal(root); + expect(await this.mock.$multiProofVerify(proof, proofFlags, root, hashes)).to.be.true; + expect(await this.mock.$multiProofVerifyCalldata(proof, proofFlags, root, hashes)).to.be.true; + }); + + it('returns false for an invalid Merkle multi proof', async function () { + const merkleTree = this.makeTree('abcdef'); + const otherMerkleTree = this.makeTree('ghi'); + + const root = merkleTree.root; + const { proof, proofFlags, leaves } = otherMerkleTree.getMultiProof(toLeaves('ghi')); + const hashes = leaves.map(e => merkleTree.leafHash(e)); + + expect(await this.mock.$processMultiProof(proof, proofFlags, hashes)).to.not.equal(root); + expect(await this.mock.$processMultiProofCalldata(proof, proofFlags, hashes)).to.not.equal(root); + expect(await this.mock.$multiProofVerify(proof, proofFlags, root, hashes)).to.be.false; + expect(await this.mock.$multiProofVerifyCalldata(proof, proofFlags, root, hashes)).to.be.false; + }); + + it('revert with invalid multi proof #1', async function () { + const merkleTree = this.makeTree('abcd'); + + const root = merkleTree.root; + const hashA = merkleTree.at(0); + const hashB = merkleTree.at(1); + const hashCD = nodeHash(merkleTree.at(2), merkleTree.at(3)); + const hashE = ethers.randomBytes(32); // incorrect (not part of the tree) + const fill = ethers.randomBytes(32); + + await expect( + this.mock.$processMultiProof([hashB, fill, hashCD], [false, false, false], [hashA, hashE]), + ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); + + await expect( + this.mock.$processMultiProofCalldata([hashB, fill, hashCD], [false, false, false], [hashA, hashE]), + ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); + + await expect( + this.mock.$multiProofVerify([hashB, fill, hashCD], [false, false, false], root, [hashA, hashE]), + ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); + + await expect( + this.mock.$multiProofVerifyCalldata([hashB, fill, hashCD], [false, false, false], root, [hashA, hashE]), + ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); + }); + + it('revert with invalid multi proof #2', async function () { + const merkleTree = this.makeTree('abcd'); + + const root = merkleTree.root; + const hashA = merkleTree.at(0); + const hashB = merkleTree.at(1); + const hashCD = nodeHash(merkleTree.at(2), merkleTree.at(3)); + const hashE = ethers.randomBytes(32); // incorrect (not part of the tree) + const fill = ethers.randomBytes(32); + + await expect( + this.mock.$processMultiProof([hashB, fill, hashCD], [false, false, false, false], [hashE, hashA]), + ).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); + + await expect( + this.mock.$processMultiProofCalldata([hashB, fill, hashCD], [false, false, false, false], [hashE, hashA]), + ).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); + + await expect( + this.mock.$multiProofVerify([hashB, fill, hashCD], [false, false, false, false], root, [hashE, hashA]), + ).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); + + await expect( + this.mock.$multiProofVerifyCalldata([hashB, fill, hashCD], [false, false, false, false], root, [ + hashE, + hashA, + ]), + ).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); + }); + + it('limit case: works for tree containing a single leaf', async function () { + const merkleTree = this.makeTree('a'); + + const root = merkleTree.root; + const { proof, proofFlags, leaves } = merkleTree.getMultiProof(toLeaves('a')); + const hashes = leaves.map(e => merkleTree.leafHash(e)); + + expect(await this.mock.$processMultiProof(proof, proofFlags, hashes)).to.equal(root); + expect(await this.mock.$processMultiProofCalldata(proof, proofFlags, hashes)).to.equal(root); + expect(await this.mock.$multiProofVerify(proof, proofFlags, root, hashes)).to.be.true; + expect(await this.mock.$multiProofVerifyCalldata(proof, proofFlags, root, hashes)).to.be.true; + }); + + it('limit case: can prove empty leaves', async function () { + const merkleTree = this.makeTree('abcd'); + + const root = merkleTree.root; + expect(await this.mock.$processMultiProof([root], [], [])).to.equal(root); + expect(await this.mock.$processMultiProofCalldata([root], [], [])).to.equal(root); + expect(await this.mock.$multiProofVerify([root], [], root, [])).to.be.true; + expect(await this.mock.$multiProofVerifyCalldata([root], [], root, [])).to.be.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 leave = ethers.id('real leaf'); + const root = nodeHash(leave, ethers.ZeroHash); + + // Now we can pass any **malicious** fake leaves as valid! + const maliciousLeaves = ['malicious', 'leaves'].map(ethers.id).map(ethers.toBeArray).sort(Buffer.compare); + const maliciousProof = [leave, leave]; + const maliciousProofFlags = [true, true, false]; + + await expect( + this.mock.$processMultiProof(maliciousProof, maliciousProofFlags, maliciousLeaves), + ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); + + await expect( + this.mock.$processMultiProofCalldata(maliciousProof, maliciousProofFlags, maliciousLeaves), + ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); + + await expect( + this.mock.$multiProofVerify(maliciousProof, maliciousProofFlags, root, maliciousLeaves), + ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); + + await expect( + this.mock.$multiProofVerifyCalldata(maliciousProof, maliciousProofFlags, root, maliciousLeaves), + ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.t.sol new file mode 100644 index 0000000..4259c88 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.t.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; + +contract MessageHashUtilsTest is Test { + function testToDataWithIntendedValidatorHash(address validator, bytes memory data) external pure { + assertEq( + MessageHashUtils.toDataWithIntendedValidatorHash(validator, data), + MessageHashUtils.toDataWithIntendedValidatorHash(_dirty(validator), data) + ); + } + + function testToDataWithIntendedValidatorHash(address validator, bytes32 messageHash) external pure { + assertEq( + MessageHashUtils.toDataWithIntendedValidatorHash(validator, messageHash), + MessageHashUtils.toDataWithIntendedValidatorHash(_dirty(validator), messageHash) + ); + + assertEq( + MessageHashUtils.toDataWithIntendedValidatorHash(validator, messageHash), + MessageHashUtils.toDataWithIntendedValidatorHash(validator, abi.encodePacked(messageHash)) + ); + } + + function _dirty(address input) private pure returns (address output) { + assembly ("memory-safe") { + output := or(input, shl(160, not(0))) + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.test.js new file mode 100644 index 0000000..57e8286 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.test.js @@ -0,0 +1,97 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { domainSeparator, hashTypedData } = require('../../helpers/eip712'); + +async function fixture() { + const mock = await ethers.deployContract('$MessageHashUtils'); + return { mock }; +} + +describe('MessageHashUtils', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('toEthSignedMessageHash', function () { + it('prefixes bytes32 data correctly', async function () { + const message = ethers.randomBytes(32); + const expectedHash = ethers.hashMessage(message); + + await expect(this.mock.getFunction('$toEthSignedMessageHash(bytes32)')(message)).to.eventually.equal( + expectedHash, + ); + }); + + it('prefixes dynamic length data correctly', async function () { + const message = ethers.randomBytes(128); + const expectedHash = ethers.hashMessage(message); + + await expect(this.mock.getFunction('$toEthSignedMessageHash(bytes)')(message)).to.eventually.equal(expectedHash); + }); + + it('version match for bytes32', async function () { + const message = ethers.randomBytes(32); + const fixed = await this.mock.getFunction('$toEthSignedMessageHash(bytes32)')(message); + const dynamic = await this.mock.getFunction('$toEthSignedMessageHash(bytes)')(message); + + expect(fixed).to.equal(dynamic); + }); + }); + + describe('toDataWithIntendedValidatorHash', function () { + it('returns the digest of `bytes32 messageHash` correctly', async function () { + const verifier = ethers.Wallet.createRandom().address; + const message = ethers.randomBytes(32); + const expectedHash = ethers.solidityPackedKeccak256( + ['string', 'address', 'bytes32'], + ['\x19\x00', verifier, message], + ); + + await expect( + this.mock.getFunction('$toDataWithIntendedValidatorHash(address,bytes32)')(verifier, message), + ).to.eventually.equal(expectedHash); + }); + + it('returns the digest of `bytes memory message` correctly', async function () { + const verifier = ethers.Wallet.createRandom().address; + const message = ethers.randomBytes(128); + const expectedHash = ethers.solidityPackedKeccak256( + ['string', 'address', 'bytes'], + ['\x19\x00', verifier, message], + ); + + await expect( + this.mock.getFunction('$toDataWithIntendedValidatorHash(address,bytes)')(verifier, message), + ).to.eventually.equal(expectedHash); + }); + + it('version match for bytes32', async function () { + const verifier = ethers.Wallet.createRandom().address; + const message = ethers.randomBytes(32); + const fixed = await this.mock.getFunction('$toDataWithIntendedValidatorHash(address,bytes)')(verifier, message); + const dynamic = await this.mock.getFunction('$toDataWithIntendedValidatorHash(address,bytes32)')( + verifier, + message, + ); + + expect(fixed).to.equal(dynamic); + }); + }); + + describe('toTypedDataHash', function () { + it('returns the digest correctly', async function () { + const domain = { + name: 'Test', + version: '1', + chainId: 1n, + verifyingContract: ethers.Wallet.createRandom().address, + }; + const structhash = ethers.randomBytes(32); + const expectedHash = hashTypedData(domain, structhash); + + await expect(this.mock.$toTypedDataHash(domainSeparator(domain), structhash)).to.eventually.equal(expectedHash); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.t.sol new file mode 100644 index 0000000..ee11b43 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.t.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; + +import {P256} from "@openzeppelin/contracts/utils/cryptography/P256.sol"; +import {Errors} from "@openzeppelin/contracts/utils/Errors.sol"; + +contract P256Test is Test { + /// forge-config: default.fuzz.runs = 512 + function testVerify(bytes32 digest, uint256 seed) public view { + uint256 privateKey = _asPrivateKey(seed); + + (uint256 x, uint256 y) = vm.publicKeyP256(privateKey); + (bytes32 r, bytes32 s) = vm.signP256(privateKey, digest); + s = _ensureLowerS(s); + assertTrue(P256.verify(digest, r, s, bytes32(x), bytes32(y))); + assertTrue(P256.verifySolidity(digest, r, s, bytes32(x), bytes32(y))); + } + + /// forge-config: default.fuzz.runs = 512 + function testRecover(bytes32 digest, uint256 seed) public view { + uint256 privateKey = _asPrivateKey(seed); + + (uint256 x, uint256 y) = vm.publicKeyP256(privateKey); + (bytes32 r, bytes32 s) = vm.signP256(privateKey, digest); + s = _ensureLowerS(s); + (bytes32 qx0, bytes32 qy0) = P256.recovery(digest, 0, r, s); + (bytes32 qx1, bytes32 qy1) = P256.recovery(digest, 1, r, s); + assertTrue((qx0 == bytes32(x) && qy0 == bytes32(y)) || (qx1 == bytes32(x) && qy1 == bytes32(y))); + } + + function testVerifyNativeUnsupportedRIP7212(bytes32 digest, uint256 seed) public { + // By default, the precompile at address 0x100 is not supported. + + uint256 privateKey = _asPrivateKey(seed); + + (uint256 x, uint256 y) = vm.publicKeyP256(privateKey); + (bytes32 r, bytes32 s) = vm.signP256(privateKey, digest); + s = _ensureLowerS(s); + + (bool success, bytes memory returndata) = address(this).call( + abi.encodeCall(P256Test.verifyNative, (digest, r, s, bytes32(x), bytes32(y))) + ); + assertFalse(success); + assertEq(returndata, abi.encodeWithSelector(Errors.MissingPrecompile.selector, address(0x100))); + } + + function _asPrivateKey(uint256 seed) private pure returns (uint256) { + return bound(seed, 1, P256.N - 1); + } + + function _ensureLowerS(bytes32 s) private pure returns (bytes32) { + uint256 _s = uint256(s); + unchecked { + return _s > P256.N / 2 ? bytes32(P256.N - _s) : s; + } + } + + // See https://github.com/foundry-rs/foundry/issues/10237 + function verifyNative(bytes32 digest, bytes32 r, bytes32 s, bytes32 x, bytes32 y) external view { + P256.verifyNative(digest, r, s, x, y); + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.test.js new file mode 100644 index 0000000..a75d527 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.test.js @@ -0,0 +1,182 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { secp256r1 } = require('@noble/curves/p256'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const N = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551n; + +// As in ECDSA, signatures are malleable and the tooling produce both high and low S values. +// We need to ensure that the s value is in the lower half of the order of the curve. +const ensureLowerOrderS = ({ s, recovery, ...rest }) => { + if (s > N / 2n) { + s = N - s; + recovery = 1 - recovery; + } + return { s, recovery, ...rest }; +}; + +const prepareSignature = ( + privateKey = secp256r1.utils.randomPrivateKey(), + messageHash = ethers.hexlify(ethers.randomBytes(0x20)), +) => { + const publicKey = [ + secp256r1.getPublicKey(privateKey, false).slice(0x01, 0x21), + secp256r1.getPublicKey(privateKey, false).slice(0x21, 0x41), + ].map(ethers.hexlify); + const { r, s, recovery } = ensureLowerOrderS(secp256r1.sign(messageHash.replace(/0x/, ''), privateKey)); + const signature = [r, s].map(v => ethers.toBeHex(v, 0x20)); + + return { privateKey, publicKey, signature, recovery, messageHash }; +}; + +describe('P256', function () { + async function fixture() { + return { mock: await ethers.deployContract('$P256') }; + } + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('with signature', function () { + beforeEach(async function () { + Object.assign(this, prepareSignature()); + }); + + it('verify valid signature', async function () { + await expect(this.mock.$verify(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be.true; + await expect(this.mock.$verifySolidity(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be + .true; + await expect(this.mock.$verifyNative(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be + .true; + }); + + it('verify improper signature', async function () { + const signature = this.signature; + this.signature[0] = ethers.toBeHex(N, 0x20); // r = N + await expect(this.mock.$verify(this.messageHash, ...signature, ...this.publicKey)).to.eventually.be.false; + await expect(this.mock.$verifySolidity(this.messageHash, ...signature, ...this.publicKey)).to.eventually.be.false; + await expect(this.mock.$verifyNative(this.messageHash, ...signature, ...this.publicKey)).to.eventually.be.false; + }); + + it('recover public key', async function () { + await expect(this.mock.$recovery(this.messageHash, this.recovery, ...this.signature)).to.eventually.deep.equal( + this.publicKey, + ); + }); + + it('recovers (0,0) for invalid recovery bit', async function () { + await expect(this.mock.$recovery(this.messageHash, 2, ...this.signature)).to.eventually.deep.equal([ + ethers.ZeroHash, + ethers.ZeroHash, + ]); + }); + + it('recovers (0,0) for improper signature', async function () { + const signature = this.signature; + this.signature[0] = ethers.toBeHex(N, 0x20); // r = N + await expect(this.mock.$recovery(this.messageHash, this.recovery, ...signature)).to.eventually.deep.equal([ + ethers.ZeroHash, + ethers.ZeroHash, + ]); + }); + + it('reject signature with flipped public key coordinates ([x,y] >> [y,x])', async function () { + // flip public key + this.publicKey.reverse(); + + await expect(this.mock.$verify(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be.false; + await expect(this.mock.$verifySolidity(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be + .false; + await expect(this.mock.$verifyNative(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be + .false; + }); + + it('reject signature with flipped signature values ([r,s] >> [s,r])', async function () { + // Preselected signature where `r < N/2` and `s < N/2` + this.signature = [ + '0x45350225bad31e89db662fcc4fb2f79f349adbb952b3f652eed1f2aa72fb0356', + '0x513eb68424c42630012309eee4a3b43e0bdc019d179ef0e0c461800845e237ee', + ]; + + // Corresponding hash and public key + this.messageHash = '0x2ad1f900fe63745deeaedfdf396cb6f0f991c4338a9edf114d52f7d1812040a0'; + this.publicKey = [ + '0x9e30de165e521257996425d9bf12a7d366925614bf204eabbb78172b48e52e59', + '0x94bf0fe72f99654d7beae4780a520848e306d46a1275b965c4f4c2b8e9a2c08d', + ]; + + // Make sure it works + await expect(this.mock.$verify(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be.true; + + // Flip signature + this.signature.reverse(); + + await expect(this.mock.$verify(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be.false; + await expect(this.mock.$verifySolidity(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be + .false; + await expect(this.mock.$verifyNative(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be + .false; + await expect( + this.mock.$recovery(this.messageHash, this.recovery, ...this.signature), + ).to.eventually.not.deep.equal(this.publicKey); + }); + + it('reject signature with invalid message hash', async function () { + // random message hash + this.messageHash = ethers.hexlify(ethers.randomBytes(32)); + + await expect(this.mock.$verify(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be.false; + await expect(this.mock.$verifySolidity(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be + .false; + await expect(this.mock.$verifyNative(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be + .false; + await expect( + this.mock.$recovery(this.messageHash, this.recovery, ...this.signature), + ).to.eventually.not.deep.equal(this.publicKey); + }); + + it('fail to recover signature with invalid recovery bit', async function () { + // flip recovery bit + this.recovery = 1 - this.recovery; + + await expect( + this.mock.$recovery(this.messageHash, this.recovery, ...this.signature), + ).to.eventually.not.deep.equal(this.publicKey); + }); + }); + + // test cases for https://github.com/C2SP/wycheproof/blob/4672ff74d68766e7785c2cac4c597effccef2c5c/testvectors/ecdsa_secp256r1_sha256_p1363_test.json + describe('wycheproof tests', function () { + for (const { key, tests } of require('./ecdsa_secp256r1_sha256_p1363_test.json').testGroups) { + // parse public key + let [x, y] = [key.wx, key.wy].map(v => ethers.stripZerosLeft('0x' + v, 32)); + if (x.length > 66 || y.length > 66) continue; + x = ethers.zeroPadValue(x, 32); + y = ethers.zeroPadValue(y, 32); + + // run all tests for this key + for (const { tcId, comment, msg, sig, result } of tests) { + // only keep properly formatted signatures + if (sig.length != 128) continue; + + it(`${tcId}: ${comment}`, async function () { + // split signature, and reduce modulo N + let [r, s] = Array(2) + .fill() + .map((_, i) => ethers.toBigInt('0x' + sig.substring(64 * i, 64 * (i + 1)))); + // move s to lower part of the curve if needed + if (s <= N && s > N / 2n) s = N - s; + // prepare signature + r = ethers.toBeHex(r, 32); + s = ethers.toBeHex(s, 32); + // hash + const messageHash = ethers.sha256('0x' + msg); + + // check verify + await expect(this.mock.$verify(messageHash, r, s, x, y)).to.eventually.equal(result == 'valid'); + }); + } + } + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.helper.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.helper.js new file mode 100644 index 0000000..48c8ee4 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.helper.js @@ -0,0 +1,17 @@ +const path = require('path'); +const fs = require('fs'); + +module.exports = function* parse(file) { + const cache = {}; + const data = fs.readFileSync(path.resolve(__dirname, file), 'utf8'); + for (const line of data.split('\r\n')) { + const groups = line.match(/^(?\w+) = (?\w+)(?.*)$/)?.groups; + if (groups) { + const { key, value, extra } = groups; + cache[key] = value; + if (groups.key === 'Result') { + yield Object.assign({ extra: extra.trim() }, cache); + } + } + } +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.test.js new file mode 100644 index 0000000..bdf3391 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.test.js @@ -0,0 +1,102 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { bytes, bytes32 } = ethers.Typed; + +const parse = require('./RSA.helper'); + +async function fixture() { + return { mock: await ethers.deployContract('$RSA') }; +} + +describe('RSA', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + // Load test cases from file SigVer15_186-3.rsp from: + // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/dss/186-2rsatestvectors.zip + describe('SigVer15_186-3.rsp tests', function () { + for (const test of parse('SigVer15_186-3.rsp')) { + const { length } = Buffer.from(test.S, 'hex'); + + /// For now, RSA only supports digest that are 32bytes long. If we ever extend that, we can use these hashing functions for @noble: + // const { sha1 } = require('@noble/hashes/sha1'); + // const { sha224, sha256 } = require('@noble/hashes/sha256'); + // const { sha384, sha512 } = require('@noble/hashes/sha512'); + + if (test.SHAAlg === 'SHA256' && length >= 0x100) { + const result = test.Result === 'P'; + + it(`signature length ${length} ${test.extra} ${result ? 'works' : 'fails'}`, async function () { + const data = '0x' + test.Msg; + const sig = '0x' + test.S; + const exp = '0x' + test.e; + const mod = '0x' + test.n; + + expect(await this.mock.$pkcs1Sha256(bytes32(ethers.sha256(data)), sig, exp, mod)).to.equal(result); + expect(await this.mock.$pkcs1Sha256(bytes(data), sig, exp, mod)).to.equal(result); + }); + } + } + }); + + describe('others tests', function () { + // > openssl genrsa -out private.pem 2048 + // > openssl rsa -in private.pem -outform der -pubout -out public.pem + // > openssl asn1parse -in public.pem -inform DER -strparse 19 + // > echo -n 'hello world!' | openssl dgst -sha256 -sign private.pem | xxd -p | tr -d \\n + const openssl = { + descr: 'openssl', + data: ethers.toUtf8Bytes('hello world!'), + sig: '0x2ff4349940bf0db9bce422e316ac47e3d24b0a869acb05c9c46f74e17491177698b150f2a5996a6bf7d7c73e05af91ad78632115a7d95b823c462596486e56e8473b75a270ca4760cd83f244d5d3af81d2c7d188879abbc2992b22d51e22ffb725f0828c852ee44f81def383e0f92ebfa3c6d97ca5e52a4254f9a886680e3fb394c2a8a955849313dce2cb416f8a67974effd9a17d229146ce10a98684fb3d46a1e53ddaf831cdd2beed895532533c554ae087b2738a5c4cf0802e8062b2a599fd76d67b92eabffa8a92b24e08fbc866217502a4a3d9f6157e491bede3c1048fa8f2d804f66128e8a883018b0ec33a59e1086bf71ae5dc193d9815ca82892dbc', + exp: '0x010001', + mod: '0xDC1CE5F7B202464CD320B4F9E44FEE0A358BE7022AB155A5BDEE45B1AED3C5A19645D898E294CBA96EAD6929FD8FB4B23E9ADB4D3143A736232C32A8617A77B89F7D8399B9BE37F8349D111067F71D2F20237B9F1A7C1CF44819F9FA5AA030F563DCFB1CC59FFAA86BA2ABEE28D949FED0DF34071B7558950079E28CD9BBA4CAC2F0F86D7BBFB13363C792B5A70C9B279F0B43A264A7CB1A7C7C41FC6EC1D1C1125A6BECE3207AE582F74CE896B9AC18DB00C8985B70145217B831CC313FC06581E186BF70A2EEE2C3C065B5C91A89B2C099B4924CDBF5707D161BD83AC8D9FCA309AC75D63EACF21027C2C9C9F05994331CBDFDD24F9BC6C8B58D8F1824540B', + result: true, + }; + + // According to RFC4055, pg.5 and RFC8017, pg. 64, for SHA-1, and the SHA-2 family, + // the algorithm parameter has to be NULL and both explicit NULL parameter and implicit + // NULL parameter (ie, absent NULL parameter) are considered to be legal and equivalent. + const rfc4055 = { + descr: 'rfc8017 implicit null parameter', + data: ethers.toUtf8Bytes('hello world!'), + sig: '0xa0073057133ff3758e7e111b4d7441f1d8cbe4b2dd5ee4316a14264290dee5ed7f175716639bd9bb43a14e4f9fcb9e84dedd35e2205caac04828b2c053f68176d971ea88534dd2eeec903043c3469fc69c206b2a8694fd262488441ed8852280c3d4994e9d42bd1d575c7024095f1a20665925c2175e089c0d731471f6cc145404edf5559fd2276e45e448086f71c78d0cc6628fad394a34e51e8c10bc39bfe09ed2f5f742cc68bee899d0a41e4c75b7b80afd1c321d89ccd9fe8197c44624d91cc935dfa48de3c201099b5b417be748aef29248527e8bbb173cab76b48478d4177b338fe1f1244e64d7d23f07add560d5ad50b68d6649a49d7bc3db686daaa7', + exp: '0x03', + mod: '0xe932ac92252f585b3a80a4dd76a897c8b7652952fe788f6ec8dd640587a1ee5647670a8ad4c2be0f9fa6e49c605adf77b5174230af7bd50e5d6d6d6d28ccf0a886a514cc72e51d209cc772a52ef419f6a953f3135929588ebe9b351fca61ced78f346fe00dbb6306e5c2a4c6dfc3779af85ab417371cf34d8387b9b30ae46d7a5ff5a655b8d8455f1b94ae736989d60a6f2fd5cadbffbd504c5a756a2e6bb5cecc13bca7503f6df8b52ace5c410997e98809db4dc30d943de4e812a47553dce54844a78e36401d13f77dc650619fed88d8b3926e3d8e319c80c744779ac5d6abe252896950917476ece5e8fc27d5f053d6018d91b502c4787558a002b9283da7', + result: true, + }; + + const shortN = { + descr: 'returns false for a very short n', + data: ethers.toUtf8Bytes('hello world!'), + sig: '0x0102', + exp: '0x03', + mod: '0x0405', + result: false, + }; + + const differentLength = { + descr: 'returns false for a signature with different length to n', + data: ethers.toUtf8Bytes('hello world!'), + sig: '0x00112233', + exp: '0x03', + mod: '0xe932ac92252f585b3a80a4dd76a897c8b7652952fe788f6ec8dd640587a1ee5647670a8ad4c2be0f9fa6e49c605adf77b5174230af7bd50e5d6d6d6d28ccf0a886a514cc72e51d209cc772a52ef419f6a953f3135929588ebe9b351fca61ced78f346fe00dbb6306e5c2a4c6dfc3779af85ab417371cf34d8387b9b30ae46d7a5ff5a655b8d8455f1b94ae736989d60a6f2fd5cadbffbd504c5a756a2e6bb5cecc13bca7503f6df8b52ace5c410997e98809db4dc30d943de4e812a47553dce54844a78e36401d13f77dc650619fed88d8b3926e3d8e319c80c744779ac5d6abe252896950917476ece5e8fc27d5f053d6018d91b502c4787558a002b9283da7', + result: false, + }; + + // this is the openssl example where sig has been replaced by sig + mod + const sTooLarge = { + ...openssl, + descr: 'returns false if s >= n', + sig: ethers.toBeHex(ethers.toBigInt(openssl.sig) + ethers.toBigInt(openssl.mod)), + result: false, + }; + + for (const { descr, data, sig, exp, mod, result } of [openssl, rfc4055, shortN, differentLength, sTooLarge]) { + it(descr, async function () { + expect(await this.mock.$pkcs1Sha256(bytes(data), sig, exp, mod)).to.equal(result); + }); + } + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SigVer15_186-3.rsp b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SigVer15_186-3.rsp new file mode 100644 index 0000000..275be61 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SigVer15_186-3.rsp @@ -0,0 +1,3850 @@ +# CAVS 11.0 +# "SigVer PKCS#1 Ver 1.5" information +# Mod sizes selected: 1024 1536 2048 3072 4096 +# SHA Algorithm selected:SHA1 SHA224 SHA256 SHA384 SHA512 +# Generated on Wed Mar 02 00:13:02 2011 + +[mod = 1024] + +n = a8d68acd413c5e195d5ef04e1b4faaf242365cb450196755e92e1215ba59802aafbadbf2564dd550956abb54f8b1c917844e5f36195d1088c600e07cada5c080ede679f50b3de32cf4026e514542495c54b1903768791aae9e36f082cd38e941ada89baecada61ab0dd37ad536bcb0a0946271594836e92ab5517301d45176b5 + +p = c107a2fe924b76e206cb9bc4af2ab7008547c00846bf6d0680b3eac3ebcbd0c7fd7a54c2b9899b08f80cde1d3691eaaa2816b1eb11822d6be7beaf4e30977c49 +q = dfea984ce4307eafc0d140c2bb82861e5dbac4f8567cbc981d70440dd639492079031486315e305eb83e591c4a2e96064966f7c894c3ca351925b5ce82d8ef0d + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f +S = a3877b854832d6a6dec749a908e8bd3a73b24372e80321ed01c19ce066117d8efe78ef7168af8acd139e47dd262c0c92ed1701cf6c07e0c1140f82040167f55bb5180c18ad9e66a18dacf0742c1f05173129ed5ac523faeeb2119639cd30ae5a435884b55043d4fb7fa9af0dd92c365386044c2e8bcd196b3787bfede47fff37 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead +S = a5aa479d792448cc3e2ddfbe444017eea54efca7101651f4616f0260c7a48a364fe459abf98352e86b0b3d1478208687dffde1380d4462fce68cd61895401c3791186f17f159b91c02b5c0a30e894e142657b7537e84d2574837256da6940aa14cded7fbcba24b9e12ed2bb7e3f6db69b5a02807b57c9aa10ad9c0e1bde9443a +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = 9edf5246ae1d8fe800bc2ed422e6441cedde94c85a870277972a4b4a5a74f4fd76be8057ac92e6c5c36a4242dabacb79fe31052ef83c38da68cd2095185ae6398a284fc5d3c934fface4325ec734a2265fd3cbd513b957bef47f04f4dd699c6903a42757cccc5fdfe5b264f18f5bb16b394c4f855404486c63cb5f2d51aafed5 +S = 9a2e5b3ce63cb8df79f3cb25cce6964527e38592c58ba8b7b9312da25c62940985e93e62689f34b60cd019d3d472c0b72fcf2666bfcf8c13407e2150a138caaabaa409e6fd1ea55faf9180f7b41ed53d47c4dcdc3c669928d8a1c161f91918593dc3be3892c8df763d1a5ee6bcd5801866683005d89a2fd6ed3bef581833d922 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = d73829497cddbe41b705faac50e7899fdb5a38bf3a459e536357029e64f8796ba47f4fe96ba5a8b9a4396746e2164f55a25368ddd0b9a5188c7ac3da2d1f742286c3bdee697f9d546a25efcfe53191d743fcc6b47833d993d08804daeca78fb9076c3c017f53e33a90305af06220974d46bf19ed3c9b84edbae98b45a8771258 +S = 175015bda50abe0fa7d39a8353885ca01be3a7e7fcc55045744111362ee1914473a48dc537d956294b9e20a1ef661d58537acdc8de908fa050630fcc272e6d001045e6fdeed2d10531c8603334c2e8db39e73e6d9665ee1343f9e4198302d2201b44e8e8d06b3ef49cee6197582163a8490089ca654c0012fce1ba6511089750 +SaltVal = 00 +Result = P + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = a4397d9ab677aaa13a68a09de9ae0ed4045d479aa0ff3a7242dca477ab7884faf55cd06ddf19667f668b4589955bfd299dc7642c28a68bb2eba6f08c7ad9f5e96170913270c6463256a0537a72b32a04e5662416ecda74696d275a8bcfe999820ffc2ab210833201332f323828be7dac04c1f01f93a3dde1efe7483a51b1560d +S = 417aa0531b1da975066a1311a9bf2fa73f5daf90f0473a8937a27a9c6378c53012e0b4db3dcb5309b85a3e7f9db161848465f2e8102f75d171b4dc5371c3dca0bd70626dff5fad68549477fea84db9ac1b405440e178f5d9f74f3935e78a6aaf774b86d509fb25bd1a93aac9a2cdbce6a897842ea3ae07d3c8b4c43f97e0bf75 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a05000414dd1e335f65b2f5e31562a2c74ea6eab09892febcefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = e4690fb08396a8bf07377778a447dbd14c771024bd2353cbbd8446eda42795971c9eda0f2575be655c68614a7cd2fd252569c664dc291410548ec3a5eb06da2078a66c59441cbc9356e5a452f4c0386d6662a663fd6b61f254997ee6d63b5e3080e98d37e873ea737f17083713f7d5ce98ca79ca27d18199470c3d596caf66ed +S = 56b25cc46a9ef9607f4f0f553265996e22a4552fc6cb2752d0595e887afad29f7f9a390c17dc427c7d9f83f19f6986c60ec6d8f8017c3419cc2a838fe2425c7c80ceebfa1a0a3de507b5601609fe54b871efde685d23e546d69fbd14a30ebc2e67ac99446ae4978f1b3c120103294318b253aa9fcee638907b84ac72b25e18fa +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a050004148031ffbcbd668626dcc49e40128d8abdab1e8172 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f +S = 30db68c610b9086e9c6273da708ff8a89d73dfba6e2564aec908292af3a52b84ddd28bbb7c4a39df02f6e992be0d9aa8edb320a6e5a0a001ad097e7b8d09a87f50d55e1d68f47d2215a892221e7e33ddfe181b58fb12c8703e60cf0248c62af8a99111befd96b45ed4cf441a0623b013b94d3dd0976f6b5db7ae595069f21ea5 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead +S = 8ed880d91764fdadb04470e04509c6b800fe2bdb1cdb17071f855b8e38b3075c3b8a6991a34ab869127f47a753d7610c79e86a7a288b653326e31d90f4d043f52b7656b6831f6806119df6309a7846b05cb2630c28f7464a7b96e4e8ce76e9cd45502bd5e928f268763fea50271d29b7527097c51ebc2b2a3a83cf22e6b7e3fa +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = 9edf5246ae1d8fe800bc2ed422e6441cedde94c85a870277972a4b4a5a74f4fd76be8057ac92e6c5c36a4242dabacb79fe31052ef83c38da68cd2095185ae6398a284fc5d3c934fface4325ec734a2265fd3cbd513b957bef47f04f4dd699c6903a42757cccc5fdfe5b264f18f5bb16b394c4f855404486c63cb5f2d51aafed5 +S = 4a1716c989580f11bad633a8566b0f44ea689d8bc27c489bbf1a01d76bfa08ce87cace576ade53a5399addee803666fa1d99fa3739c556ae513baa10415e3db820e45f7518e15c7b1875f18f3835792e7ffaed1e7cf9c592afd660d2dda77e00f8f6cf298978929ca017cfce2675afaceca959810a4a33666be9a9a1b2f6523e +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = d73829497cddbe41b705faac50e7899fdb5a38bf3a459e536357029e64f8796ba47f4fe96ba5a8b9a4396746e2164f55a25368ddd0b9a5188c7ac3da2d1f742286c3bdee697f9d546a25efcfe53191d743fcc6b47833d993d08804daeca78fb9076c3c017f53e33a90305af06220974d46bf19ed3c9b84edbae98b45a8771258 +S = 57677b089e205486df4f56755972e3af88cabbc23efe29439b8d1e60ac226e990da487857392856d12cdcea387a269d1bbbc128549a1135ab062201cab8ac08886a313af8554506d7a93855b843086a1bf3dfbcb004ccde779c084ffa1724b41d17e10c8dd67dc0df26200376550eda14455d9b0b31f1d8c5e8bb1d3d963d0d5 +SaltVal = 00 +Result = P + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = a4397d9ab677aaa13a68a09de9ae0ed4045d479aa0ff3a7242dca477ab7884faf55cd06ddf19667f668b4589955bfd299dc7642c28a68bb2eba6f08c7ad9f5e96170913270c6463256a0537a72b32a04e5662416ecda74696d275a8bcfe999820ffc2ab210833201332f323828be7dac04c1f01f93a3dde1efe7483a51b1560d +S = 9b2222986b3f97dbdfd7aafd35fba51df5a7b76c88237e7454f2561b542289b424c76ba934e30b00e7726116ddadc359d6ad8b7ed7c16533c5661f2a61c45ec2e590e058663a740c0842e036d59f223d3c87a8127d40024ae205e46e3cd0fa323e01668da8bd723cc17e539a028a5ea69cb1fd9150db571a451ada2d81e05377 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c472fcfddd47f6ba3bb9eb166c248320d9b39fb4b2f70b65a85615244efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = e4690fb08396a8bf07377778a447dbd14c771024bd2353cbbd8446eda42795971c9eda0f2575be655c68614a7cd2fd252569c664dc291410548ec3a5eb06da2078a66c59441cbc9356e5a452f4c0386d6662a663fd6b61f254997ee6d63b5e3080e98d37e873ea737f17083713f7d5ce98ca79ca27d18199470c3d596caf66ed +S = 7016e23d4fc070a479f4a9c173de8f1dc3a54183ab44af9e3cfda7a229bed269712f5697fdd485f03ea21183f563ee0b5a91d3478c5cc94cf6fb56c0102a7098cbe06a8a5ae6a0eef7722ef9514c80e5944c8b1412b1411d56c7b674650eafca7433ac8b9266363a049f3be30885e30fee049e50ddd76816db309ed59f9b469b +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041ca73d80b7f5f188724498120a21df3683351f77de5eb916058f9769d8 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f +S = 10ecd0085694f8db6ea62dab2f239d8a93fcf449102f1368c67de329d79692b677500f55994c9722e2633063fc7d8c2c50ae8857d45c08bfaba9448dda0689c2a08605d47a7694beaacbdad1a954458a87fd78b6519393013b20996d636b755323b4b2b2b6d06a46c9221cd200462428ab5bef0f9743e144191f6928562627a7 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead +S = 488d328861653ab0a769a11a158ec7b479b62db5b253eda899beae580afb9a7c762030262b8a066f085185475e17870700504d3f78fcc4bcb95a3c1648796a323613a7b706cb64b048c68c06b396aac20b52f22f3fdce40992fb9a5ef68b5725134d83035a6f091d01aa5947175885822b2d4618c3f3fdbfd8819847fe40112b +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = 9edf5246ae1d8fe800bc2ed422e6441cedde94c85a870277972a4b4a5a74f4fd76be8057ac92e6c5c36a4242dabacb79fe31052ef83c38da68cd2095185ae6398a284fc5d3c934fface4325ec734a2265fd3cbd513b957bef47f04f4dd699c6903a42757cccc5fdfe5b264f18f5bb16b394c4f855404486c63cb5f2d51aafed5 +S = 7c547b350710337c783e7406935fb8ac7bcd1cdd4a7bcaeb63422067d1239f9f59fc29b51993a29d6ac8dcc7980871bbba1be8f0b6ce951a9e0cad64b37d7d0c3734e038efcd4e3499c8855f7c52ea3323ba4876ba9d78a98e7e5cf72b4b7444228dd0d81283e59055873450b8bc411d1cb970efda5cf5947a1d1f17e92a4639 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = d73829497cddbe41b705faac50e7899fdb5a38bf3a459e536357029e64f8796ba47f4fe96ba5a8b9a4396746e2164f55a25368ddd0b9a5188c7ac3da2d1f742286c3bdee697f9d546a25efcfe53191d743fcc6b47833d993d08804daeca78fb9076c3c017f53e33a90305af06220974d46bf19ed3c9b84edbae98b45a8771258 +S = 0b20e5093c2a926233108afbdd851b88eeb554f4beaa7b18e51519f7d0ec53b181a3b03e8484ba8de2aa7864a402e2208e84ec9914af9d776ed13c48bdeb6484254de169318a87c40f2265ff16714eae8aee2bc9c3cb4dee045e4f5d9d625210121bfcf2bed8d3ffa602ce27fff4e61cf9bb650e71a6921ae6ffa296cb11bdbb +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = a4397d9ab677aaa13a68a09de9ae0ed4045d479aa0ff3a7242dca477ab7884faf55cd06ddf19667f668b4589955bfd299dc7642c28a68bb2eba6f08c7ad9f5e96170913270c6463256a0537a72b32a04e5662416ecda74696d275a8bcfe999820ffc2ab210833201332f323828be7dac04c1f01f93a3dde1efe7483a51b1560d +S = 9313380722659eeccf8be943fbf514e90fb19657dfb410a50bdfc0cfb058a58e56bbae71ea1a30ecee08ca5d31a2d0bcd3f5a967a3794259c03635ee24cf2a15303ddb5962ae9747d72e83f630580600ba64d24bc4014c5d44640b2369b45fb09c2ba20721e0ae27d1a32546afa1bd023aa61079cea65389f55c31cfedb460b3 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420fa98b3853b928263002bcb39b454ea21f3f62bcaf6bc2b616490b7a7160120d7efefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = e4690fb08396a8bf07377778a447dbd14c771024bd2353cbbd8446eda42795971c9eda0f2575be655c68614a7cd2fd252569c664dc291410548ec3a5eb06da2078a66c59441cbc9356e5a452f4c0386d6662a663fd6b61f254997ee6d63b5e3080e98d37e873ea737f17083713f7d5ce98ca79ca27d18199470c3d596caf66ed +S = 477a7d6ff281bee7d56ac9cdc7f041b7497483f07a3cea5667ff178233219f75da7b88d9fc854a22ef541af3a5be8fb30b4e50bcb6d130e11f6c18eadec5d10f9895d654c0947aad152ba395c1039d7a8ff41b829179984a513f1abeb5a748bf248af1ea0152093d9fafb5d18e4cf91bd3b57ddd18b6984d976e6bef58cb30ec +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d06096086480165030402010500042034c9d0b0b487446c903244e640affe835096c7ada2e4295090bd9386884df006 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f +S = 5ad712eea6e12cf093b8aaa41bd972bd92ea43442dfae0671b27b80d821fdf8a83b032b870e2aa618430ab207ccb1c86bc5e74ea44a0f1ba2cfa2fca003e8547eedc4fd748e7718a9dc39c032b9bb997b4c01f49e441ddcb134d9b2c28a3dcbf126de439f07cb58aece617573797d939957083e51fe5eec00deaae17c41f59ed +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead +S = 1f00ccb2e22d0355b20b79b3d3c2416c03d281673fa3314aeec0cb41373e9a8ad5441e93545b6ceb9d3b8d660709cc2b8cff61924768fcf5b0d0ac771a395c02797123f503866d2aee5bb03c651091388486f63793bd714485ead5e03b92c9d80668c2088866b14361d2eb5eb838f903994d84471d5a352366eff2c5cbdf1ab6 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = 9edf5246ae1d8fe800bc2ed422e6441cedde94c85a870277972a4b4a5a74f4fd76be8057ac92e6c5c36a4242dabacb79fe31052ef83c38da68cd2095185ae6398a284fc5d3c934fface4325ec734a2265fd3cbd513b957bef47f04f4dd699c6903a42757cccc5fdfe5b264f18f5bb16b394c4f855404486c63cb5f2d51aafed5 +S = 52edcc1c2bd6eecfda613f0ed8cc8ed5d0f0b881b5a05eca36d9fbb3d04a9f36f0fa916008d13ae8b17b8f6d97ac4450d892b2731f14a477032cd353b8c054d53a3b2932124fd8d1bac88b44e4fd6f37b8ec3575b290fad24a262011b45f7e9b96b09324901f1d153921e13f7246ffdce405018c20975dcd28a7fe55689bdd9f +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = d73829497cddbe41b705faac50e7899fdb5a38bf3a459e536357029e64f8796ba47f4fe96ba5a8b9a4396746e2164f55a25368ddd0b9a5188c7ac3da2d1f742286c3bdee697f9d546a25efcfe53191d743fcc6b47833d993d08804daeca78fb9076c3c017f53e33a90305af06220974d46bf19ed3c9b84edbae98b45a8771258 +S = 7e3ccb6ab03b419a3e54f81337a3c3f72e8c65bbd19ddd50246a36f51f58741ec245d2d0f07677a4f88aa3b1caeecdffe5fd6edcf8b8bcfb569637ad02eb154d17b87a8f00d0e618a7f4a70ce407f20359153e5f4a4d9744f3f3ff44120c08a460500f030fd3398e97fcaef9d0a7e2acef19a81f706805be5fc003d78e5b29c0 +SaltVal = 00 +Result = P + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = a4397d9ab677aaa13a68a09de9ae0ed4045d479aa0ff3a7242dca477ab7884faf55cd06ddf19667f668b4589955bfd299dc7642c28a68bb2eba6f08c7ad9f5e96170913270c6463256a0537a72b32a04e5662416ecda74696d275a8bcfe999820ffc2ab210833201332f323828be7dac04c1f01f93a3dde1efe7483a51b1560d +S = 1077cf5852f21c7986f30bc2bb382138e93c0670315a83799047e122b7804cb8cdc892f23c8297b8315c16c351f0c6138cecb630a51b8a0980eeb59d575b3d86c52ae9270c6f444143d22ad6a1eea05a886281c9d7c93f0d3ab2528bb72e99b2afbf74f04038c3e17743e286a409304e4c19d441a68142b0d7b3c0a6da5532bd +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d0609608648016503040202050004301cdb4de69f4d84845bef51cd666020a895fbea98f2f61c9554ebdcffa525877093cbc9a4b1b8efeb77980d73ca54de17efef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = e4690fb08396a8bf07377778a447dbd14c771024bd2353cbbd8446eda42795971c9eda0f2575be655c68614a7cd2fd252569c664dc291410548ec3a5eb06da2078a66c59441cbc9356e5a452f4c0386d6662a663fd6b61f254997ee6d63b5e3080e98d37e873ea737f17083713f7d5ce98ca79ca27d18199470c3d596caf66ed +S = 63c488bdf2f7de4cd048c535b481a4cc2898e3810eda0038b2283bfe9b3f2beba2a74268639ecfc05170d1af534ced5d3b4941d1aad317875e05d6a19f734625721ed1f262faf995feb1acb44ba76beaec957aa8023429865717d0abfc553cb67474034344ceb8c5d4bddff7fa230ac620e5e665006dffb1c4cc7995c73841f9 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430cf563bb8f42149df04c9bf20652986e8888907d2ff11f086bb1b6152abd4e945ad82dda241cfbf511a88b36a5a450dcc +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f +S = 48db9934d51e8c2e234d70ff665bf2de4fef620e23f27550254a0b4b18338e299c024c4ffc5a502945e9f2e091a86ff6e7f44059f1ca58b4a18bc15931ae1176a9775247039e57d4e322f3d77fed6c6e9bec26b066fe565384c42d2ac79dd8312c8e09d3a2bf85fba0648a02f0e958d4711396e42362c5558eb7227b12aa94d7 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead +S = 125b4dddf5e18c8de2f7b72faa76f1d03dd88aac3c76ebc037b4b1aa1435eda6bef2c948e2ba51e763b8572f4ecef228ca38c10299add6f3f67c171a8fd56e33a1c287c49f844e4e98b20f0fe727b58515e5e7d3846c029afe08d25a9edf0dda6677b1cb2ca6be67763171f114932c43f53af126d0aab6dcb52d5b320b385c6d +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = 9edf5246ae1d8fe800bc2ed422e6441cedde94c85a870277972a4b4a5a74f4fd76be8057ac92e6c5c36a4242dabacb79fe31052ef83c38da68cd2095185ae6398a284fc5d3c934fface4325ec734a2265fd3cbd513b957bef47f04f4dd699c6903a42757cccc5fdfe5b264f18f5bb16b394c4f855404486c63cb5f2d51aafed5 +S = 70a4fc2afc2524ec159aaaac0cf5242e276057c3ebaee9c3c430aa862ac5758aa3a55f6f6ebbb25bc5229e51c976949314244efb35d89d4516845e41f9cb9c4db78d381eb35f257d3b9981eac9e27cd9d18a56a6dceceebb77523255684ad6ff58622889e08a616acafca687e2742074d0f7431ff5ca4324c4d25b44af9fd2aa +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = d73829497cddbe41b705faac50e7899fdb5a38bf3a459e536357029e64f8796ba47f4fe96ba5a8b9a4396746e2164f55a25368ddd0b9a5188c7ac3da2d1f742286c3bdee697f9d546a25efcfe53191d743fcc6b47833d993d08804daeca78fb9076c3c017f53e33a90305af06220974d46bf19ed3c9b84edbae98b45a8771258 +S = 8b57a6f91606ba4813b83536581eb15d72875dcbb0a514b4c03b6df8f202fa8556e4002122bedaf26eaa107ece4860752379ec8baa64f40098be92a4214b69e98b24ae1cc4d2f457cff4f405a82ef94c5f8dfaadd3078d7a9224887db86c3218bf53c9779ed09895b2cfb84f1fad2e5b1f8e4b209c5785b9ce332cd41356c171 +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = a4397d9ab677aaa13a68a09de9ae0ed4045d479aa0ff3a7242dca477ab7884faf55cd06ddf19667f668b4589955bfd299dc7642c28a68bb2eba6f08c7ad9f5e96170913270c6463256a0537a72b32a04e5662416ecda74696d275a8bcfe999820ffc2ab210833201332f323828be7dac04c1f01f93a3dde1efe7483a51b1560d +S = 8e0fecaaf7911ccadb8ca5b6ae3bb89580cbda49d3181d5aab4f03431c62aedb4affc58b87c4b3c4ee09f7908f34f52e2901891382b57cd78d3a824fe446eef4ef46b2afb0d34e6cd9a263c21db8c9c2cdcd5e60eaac571d67410c7136180ddd6195ff2a0691746e457da69bd1667a56b1980a22d5f0b3595af0e8c3bf97c2d6 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d0609608648016503040203050004406bb51b0f43cc58788c9d60f71e06fc473949ae313b3354033526cdfac71690c584f916b1a8eeb47f17f339b6cccc3fb3a53786d418295c1e454db8cb17cb7de6efefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b +Msg = e4690fb08396a8bf07377778a447dbd14c771024bd2353cbbd8446eda42795971c9eda0f2575be655c68614a7cd2fd252569c664dc291410548ec3a5eb06da2078a66c59441cbc9356e5a452f4c0386d6662a663fd6b61f254997ee6d63b5e3080e98d37e873ea737f17083713f7d5ce98ca79ca27d18199470c3d596caf66ed +S = 9572ebe453e2f17dd72921b38a27c28c68f4605aedf6b4a7d54079e3ceb2811ccaa6dbc0d71d47d93cd1f18cfb028744fe3d8971b0e9712f29ccab4152e2635dff3b9a1e9cb8f462b138b00c4c0a1163739286b50ac232da5075a9ba3c02a3f604d4629a7df516b39c8d01cb5019f9630436c70415c6b16d79bb29f3a46b72d6 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d060960864801650304020305000440605b7b97abce7dee5f9b9ebf2ebe35d7e474e62b3a6e86b108cbfe3c3a8300bd11deb0210048f502b7af1c9dcb1805f1d61e8df038359729a4bb33774b9d13aa +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +n = a8d68acd413c5e195d5ef04e1b4faaf242365cb450196755e92e1215ba59802aafbadbf2564dd550956abb54f8b1c917844e5f36195d1088c600e07cada5c080ede679f50b3de32cf4026e514542495c54b1903768791aae9e36f082cd38e941ada89baecada61ab0dd37ad536bcb0a0946271594836e92ab5517301d45176b5 + +p = c107a2fe924b76e206cb9bc4af2ab7008547c00846bf6d0680b3eac3ebcbd0c7fd7a54c2b9899b08f80cde1d3691eaaa2816b1eb11822d6be7beaf4e30977c49 + +q = dfea984ce4307eafc0d140c2bb82861e5dbac4f8567cbc981d70440dd639492079031486315e305eb83e591c4a2e96064966f7c894c3ca351925b5ce82d8ef0d + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f +S = 3c9db203bbb31c7a3498b3b35ec2ea818614f3a17cad8308f834c6945305e3b94f9886c00098640cb56cefbf06a9ebb7a8c28af610c49896dae53303fb716bc3d2ebf95205944f845658732e8a7ee032472942292f82ba24a66094c7c3b417f5e678a19c04e3b54ba5f0f03610c56d31b9726ee0e39cb1708d89fa61ba9a039b +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead +S = 6592c64db5ce133e1c7d499bf7ea4d0203897186b4319fc5e29522d97b9af212fd5a10a8c15246a46d0382cc61c9bfe2b211871d7dfa4eff9a6fa15426309844fa72b1de7aba231c66076185014b9f9e9fadbc2a739ee95c48da75fbfc7d05c22e7896db47407e8d78f0d28519c7fcb6c868b05016bcf73075477a92e97625bc +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 9edf5246ae1d8fe800bc2ed422e6441cedde94c85a870277972a4b4a5a74f4fd76be8057ac92e6c5c36a4242dabacb79fe31052ef83c38da68cd2095185ae6398a284fc5d3c934fface4325ec734a2265fd3cbd513b957bef47f04f4dd699c6903a42757cccc5fdfe5b264f18f5bb16b394c4f855404486c63cb5f2d51aafed5 +S = 6c80cc0f17783b39712a994f16a461830c26ba3f3afd1a277cda564c8a8b41c4ab444bb6f79df1d109f781de3e6e81d2a0aa2b6ff566e065b3125a6bebd36039aaab46e38a3fb36f66e665372f0cbe15a696d00cd79922bce7e6771ac59fa0c4576f28eeffca9177bdfb0804d2f883b929f58d4ea948df8bb3c283fa337d5665 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 4ff6c9e7f9f03abd3e114a788fd51318feda52b6509c1b685483cb6574213f6a8ab4435cf5f34d2eeb076c0510d77b9a48889ae0ca44dfe8773b480169e8f423ce96938ef7221caeac02be42c38618bdf15eacecdf5d91da807d69f1a3229361c4a3a2c628060d05290b2776ce6d52499e647022b66e9b071a4f167c495683ec +S = 6466b9759635fbb2a3e8cb7d2a6192ea7da6033b76dd578b76ca468fcb9215f8138966f9aaa3e82246d15bb271a269eda087e63812406407ca12cb085ae82ceebcf28eb44f6608549fbf6383882c864688665a1b5a2d748496b36f8b935f676339fc61e9bc0c3a5a58141226f300cf29c4371047d530a4776809f572b88ecdfe +SaltVal = 00 +Result = P + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 85624c37ee13b3d8cb80a5961a39c5953caf10f1b4e9c00a2c78701fb8ac821f5f08bebbd8f43bc091b283a4f693f25eef6b5f7baa42ff6f9c4c8529c21c8eea2d143d56bd2022cc2da461f34fb210959981e0b1e11a00cb65553e870e047076f66e123027ff30a3a63d87aab0fee7e243d8dbb9e0da8cc79079e36225cdee6c +S = 705a07d366f2326ced17374d5f599d483ccf184d5fbbc288face464b64c058e6583b8ba664f979f3a6c1b0755b1e2cfe8154c39176d432f59af5714bcf9b0af8da122af77f0393385613393d43db7902eb1b81fc9dc6604692e0f85d30ec59fdc521cd35e5aeef006a6b919bdf47bc9a468daf3e86b3e4956ff736bbc25c9ed1 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a050004143dee53379c3e2d8c26a41c9f63be60b1993097d7efefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 263da806fe0a7a242843f295893fd891cd13c0ecc1648c90fc79322bc594bf2531839cd58c7210f4fa0307525ea112c77b11ae6d5a49c90ceb8682d6ee9931551481a7a1623fb7d6d7e6f5c54ef2bdeaa6da779f1fe91a8e0749ef6c976198e5186150d2491a74b20514435821dae2e19499a2e9dae986ff9aeb00558694fcbc +S = 727d32d7faa37ab2dac96e9f822be4dfe60459ab7aa18a26cecf6c84bfa7fac7261c86f89ca84356ee20fa9e8a8a9a2b5f5e624cc4269aa8583fb148777091ecab8929e3f8a628c8f6e1b3a48ff1f60ce1b40f279439bf8eadc6c1b977b51e8ec3c65cb8db9fdb956b514d28381260b9f6b02b2d065ef57770952d968bed65b8 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414eaf16b6fc483cd5d255ffe76f761420c4df301e6 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f +S = 64c3e9ef2af3501ed929ec204d43848d42f3393e437b4267c70d87fc5296ebd752739088529c16e2f6f0aa87e1bc6843779dac3af54f90d3334d4b65b6b0adaf91b6fa8a75826a30f50177f887e705fb64a9258f131dc958bff8134bd68206b9d3a6fa70b2c7de5308269a6c33716916c37810aa69ce3e81db88674a07fe55e1 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead +S = 6c9e4455899b0ede371ddb6fe074217d330fe0e27537b0f06ea2e24c75ed6017594ead552296da15f11e6e6923639d95fb73e98d5160e80754ec12f4a06660c6e27eb4de4fbcfbeb37176ef5281a190249e34276a2d736e622c8151f3d5b838e450383edc986cee6b00a1d4cd5a7de8fc8629b6557a3becad84cff5c6c51f2a8 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 9edf5246ae1d8fe800bc2ed422e6441cedde94c85a870277972a4b4a5a74f4fd76be8057ac92e6c5c36a4242dabacb79fe31052ef83c38da68cd2095185ae6398a284fc5d3c934fface4325ec734a2265fd3cbd513b957bef47f04f4dd699c6903a42757cccc5fdfe5b264f18f5bb16b394c4f855404486c63cb5f2d51aafed5 +S = 9b689f488edb16d4aa3192af3760977401dd066d319d4c5dacff4dbe8aab9aa5790f39bc2378d0c8f52f286fc1cabb743bf6aabffacf5ffe4186054d0b121a2e6559806886759398e7d30781380aead8af992485e2bd582208dcf69ae8e7124b1571cdfb7db87cd565f293cb8d26a8d005508a3332d4ec27d44a1423402e6d8c +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 4ff6c9e7f9f03abd3e114a788fd51318feda52b6509c1b685483cb6574213f6a8ab4435cf5f34d2eeb076c0510d77b9a48889ae0ca44dfe8773b480169e8f423ce96938ef7221caeac02be42c38618bdf15eacecdf5d91da807d69f1a3229361c4a3a2c628060d05290b2776ce6d52499e647022b66e9b071a4f167c495683ec +S = 86ff99daaee2a3c866a71f7f6fb391b9b31a3cbcf525321087a6b253e42a7b5fa386ba3907751933cd153431507b78486d5d43dd35779962fbc9babc487afc696b0140ade1456fc5b23ce5c7c97019247e827cc7032c7e101b68eb4bfb003ba107f042b92ff697789fe43018d28794c7aa8a70a5386e891e3456a5e52990853b +SaltVal = 00 +Result = P + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 85624c37ee13b3d8cb80a5961a39c5953caf10f1b4e9c00a2c78701fb8ac821f5f08bebbd8f43bc091b283a4f693f25eef6b5f7baa42ff6f9c4c8529c21c8eea2d143d56bd2022cc2da461f34fb210959981e0b1e11a00cb65553e870e047076f66e123027ff30a3a63d87aab0fee7e243d8dbb9e0da8cc79079e36225cdee6c +S = 1f4e56f13d4167951a716dc8340c006715a4b9340a1bbcfcbb7befd70e15723d81ee5152c42967ac479b3a4ceaf1527b9379daeb245c423a21bf35826dc0f6b90a4caa579d962023e12e2eda516484ddc9483b91c7853d03a1854536d1e6fdfb9217223d2d9132a56d411183fc30de2463c4d5bea4429e7599dc9c4dd2b96b89 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041cc53cbccde35eed66e504f5ae6ecf78ba8f83abd4b67822b40e121f99efefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 263da806fe0a7a242843f295893fd891cd13c0ecc1648c90fc79322bc594bf2531839cd58c7210f4fa0307525ea112c77b11ae6d5a49c90ceb8682d6ee9931551481a7a1623fb7d6d7e6f5c54ef2bdeaa6da779f1fe91a8e0749ef6c976198e5186150d2491a74b20514435821dae2e19499a2e9dae986ff9aeb00558694fcbc +S = 002e26f1d72dcaaf2935f4177601e7b55da3ba0769372a2326d4e621449deecf84c2b3b2998da662907d167a6e7dd0b63116acd7c98d3e086da986ce126568aa31ffa136efaab815ccb9e8059a1e2bf1393dfe8567b73c8191d5acb8560a69514495a33362e05b94c3e260e181603a5d5d9a589c21c5b18effbbf016cd493276 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041cd8eee327931d42ecd0654f1da8d551ebc5ca117b9a9bee9d28049ac5 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f +S = 8b5a3675f397841c53a9021dad71a1efab91451c71ad7060ce85d75b306d6403ba23d3370b0695be87485cf6680204c68424bc7e442ef90ac01c4df420ef574294823250a000d56a5d00947800dcb2f4947f5b4eb18fa1dbdc6ab16be4b7131102d4dff98ddeac38554473964d29cdc521ee690cde5a8cd16889aa090c32c53e +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead +S = 750e59f29d2dfeedab2a3a09034904715957149126c63e6a2dc7a633a32c4c0561d54eeb1479cb65274bac37cac4751f4dffdfb7530171599b61d94862845f6cd12a5e0bd6adabc36f06d216a00b1942349710540555106aeb87f5cf3f78df918f36cf63291ef2a7064e31b84075d1c8b551225a25f59c721a3d77046078557f +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 9be28a4763c6665880c1c2a8a74494622be46de3c20e5b118cf70fee51d33b6d0b473e84a4200382004526a33eea59e13b07070e580937207ec7b2cc5fb76856fe6210a771150fa0e5da9baee4a6209ed3d4e2b3bfd2e5f6591b0ace3e657ad07c1b47d8520d5159386767f11fdfaf41fa3348fb7dd32d3c25da5d1d78433985 +S = 0ac6e41252383ee5d07f4fb08a22204f56440a8f3c8568d6e6bae46cfc9d39b65b2eae827164d716e9e465301d08fca7356ef447e0699feabbfac16ed19dc9233b457fe64d6fab38aca4464e5cd3eae3f43bab17856cdcc942e2cc848b7bf390fc53b3ed2e6f63c5d961bc83475ac200708f6e1d5be30cbe24fe4d3dad754269 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = f56379c42e3ba856585ca28f7fb768f65d273a5fc546156142857b0afb7c72d2d97ecfceec71b4260bdc58c9bb42065f53af69805d9006233ec70a591aff463bf23d78200fb8cc14a4eba286afe8924120efad9e3d3f06f7452c725e53728b8f86c9fb245fbaf7086ab0092e215213830d1091212efc1ec59ddc3a83707d4ab8 +S = 5f49d8dc4519d9520d6542eca08cafb2d99cdb97c5a8685df2476b40505a2f9e8d63d76516b83481e2d961a7e8dc5f9f46887e394776711b0f85e4303065c06d362456bc219fc6eb343ede6733f779f75853533bc9ab876188da8ad98f9ea2f335d2ceec34ef9cb2782bb0f79cad309608ddc222e00ebcff9d14f6e6ed39638b +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 399b54f756514628f32ce8f1cf391d77047af55f3d43804923e5e09a188aa27f28604f2f3cfa3d7091f3ab5c69d40d650137a597c22d531dbbdeae074f6f534a2b297e087cd7d7125e6f8eac97f5a990859d9d3555301c5076b02f9c4d3f84d62b3d090c7cb1ba1841eab668c066990079f206c15d1383eb3ba58ae17bc2dc2c +S = a62e4b688bb3c4c2e11a3a0b1ef81ff4bbaa110c9b830d02bda2d364dadb2345a8c5dca58c611515f0c09732ee6a6642d5c5c339460a9d15022f48c36e9bc2fb8b2b0ff99005273287b8c3bed87993baf52f0e9d079281bc25a8694ed9692446127c26c34f21e610a84f3617247ecfb3b5337fe59d1239dfb7fdac8694dbef0b +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420be1f73a059cec568dcdfddf1daff4201e79273653f88ef8f16be7e9ee660335aefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = b8518b80a55b365eb1850e18f88da2941c99543c2f865df3d37d114d9fc764ffc5e2ae94f2d4ab6276bfc6bda5b6976a7dcfaa56897982880410dd5542af3ad34c469990cbec828327764842ef488f767c6b0c8cd1e08caec63438f2665517d195a4d4daf64bc2a70bd11d119eec93a060960245d162844c5f11a98cd26003e1 +S = 06317d3df0fa7ae350729ae2096b050dcec8909d36681ccca09a7a527b90767f8c2318c49e09483b48df77ddb632d6ca721155165389f7795d3ede70465678649399242aed6d984ca74fc6c2eb4dd4bb2cd7bf2125ec853f2bf757d665b29487bc5b63df0d0b03b18608d3d9a7576ea0954aef3d3303f7d8fd7e7f9725c114e2 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420a51c139e5ff91509eb0bd542bebfb9a4baa9399a5535d9168942298ce69c4f5b +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = d3787e2cd5eddc154a3b29c8a5161cb0ef6fa97d6b90c9d579677d46ba22108075fd9dc13958d290c40df3ae2400224a1cf8dd74c9adc8d48522ad9c0c34c1bbde732954e432bc6e55da0beddb849ec1f2c6815d91cc006a0dabaebd3af3ac87d38327cc1ca22317c54b776b12c7197c39829c1f0c17f700d7ad88938c86594d +S = 678507d9ebb2c5254ff371d3e41b435deb1118bf0b0121c1bb8a46575df101d12d771471b956f8c229b8021a9f08faa61e0577c6a715108874bf655576954a85fb63817b58298fe3d3643a748dcc635210d2b202e3b2e663c4a212ecbc7fdf5e34e8d499a20034d98732c09be015ea728d1cc831c61965f3e32a8aae958d43d7 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 31f8dd3024b0487ae1e3a7af9032ef7c76d5420d617771814747c09b2a4ce9ba3ef8630b4e01e3fd5c6c24f588ebe44433682f5663e2df2b6978640bc2c3c1763c69d75b59efe68af8cf516a32cba1ef8380cdc72a3eb9d4d217fcdf7136e68b7173c2870e245808ff35b677587b3066af45a6c97d340563c84d107eff4d61df +S = 8d26faa1cc87606514e47b7ab3d82768868a61d237cf18e75f935e20fc5925e2c667b05cbd09da878fd623430f71ecd1f632fff4d1d049ae704004c89012008e8856f61a03001b423f4f06eadb4a72eb946a7a4dc4469e995609801498bb7471a533ee0f422adc5d41b744301efd836e5cfcc496cfc6ee646ae2218e924f76f9 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = be9b41883cfadec3960d866fe8514f9821c6c7e65af6e5c167343fb8ac227e2432760f08fbfd1c3c92e0bbcbe5266599577aa949122e215d9a81a69fa81dc0c035e46040d5ecd28d46c8ed6f490a8da3b00543c7b9d84a769aa8bdb35d2c088bee6f9df673d1e8ffdb4f8424ba05af0054f1fb27f7fa47528f31eebc74563ecb +S = 735c47985ee75db358eb0d05624be43778a37d40ad1df88cfc5b4669906e290704265fb3a133df781dfdfaa082d21d0c431b54c0c6c239fb0c0b47e675c0def6d94a726ff8267c449f1300b21a7c7f171c76e869851f9be39546e274f60924ddeedd4f69b70d97293a10ebbb3df8f9c1fec31f7d3562150a357150fbc8ae5237 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = f8a2f38109c9b6d868c5b3481cd3478c8e0845fc3e36479cb50f4158bb8d5c8ec99101cdc1ca33ddddd823ffe5b1fe75a6440a459f5df13bfdc95d2dcabac482616d86f52509359772cb3313d46083367792d9afdf27f313d9062c24b29c4f52a67ea9829b50620f10e50d0e50a77dd7eb3adac1665cf52c3210d9c5dbfba305 +S = 9ebce94bb79d82fcd236874df4c2c3d1b56481ba15fc17a345f6d45297b6adb9e07c1b582e22ce0b1830763758827a77ca675c708163cbe7a5db72d2a95939b3cef60c632a19849e6d95bf6a867604eea7f69b506bcee7d04678d4252c715edf0a928ef4c1181177bff20c3a95215782cd6b70564cf1ec2ea25e6318ef1f96b5 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430940085d291d91da907231dd6d6e10d71011dc3e0944671e632bb0d87c0b8fa1bc2f1019caa64a8f6844a8db073b0743b +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 7e3c652fb2786a379614fc8f9f01555cf029cf61cf0af6c455a4e2156996c48cef84be923cbbf883cd18f0b3392611af658688c5f79453c60d479a0a2e5943b581a8c1393cdd2c1c604b97fca41a9ed0aea43e70891fea58547ddaa83790a7709c72152b9b242f89b5759a72c6252347354b9a6b6ef4e302920d4af86c831745 +S = 995e2522f280d28f9719663178429d6ffb26cfcfbcc15812e83821db1a5e2a31a8160574e4fe4f1f09ce67690c67fe89c11015ffbf5dd5ec669561f0a2b13c416992de570a532b805b00b8003f6c70d56925ff2bb5555daf3edef1da6bcb1c94d29bbb243119da64ef352d36ddd6ac472a99a1a22da809aa235b51afc8379619 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d060960864801650304020205000430cfd23d0f765da0ba39f284a77f62552300460944a69e6fddf7aaa731f62c6d822f5eb581075a23fd540aa7a920f7c3bbefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 2bd0f6349c6f8198a10ce8e761feb6d4d72bc71addcefc628a773367be537758fbad737e77b52d1e6f80f1a1bd518af2ad17b9280d36df65838afdfd24a9dedb4169932184a3200f3c367526f64ea08d4de640b3038b3d365063b604796f3bc0a50d3d67edc1c233b2345dbf337d5e6d5ea04605e7547e9e980a48c2e82af5cd +S = 38103ad73f8bb3a9c3e01e95b8cc45e982a64f17a318026e185d523dec851ef9fbd1b9c2694a4688925580bb50709ea624417a685b39b36e988d9b7b41282cb969379c3e739c0a98151db9181dfa58c5e6ffbaaa6971dd5171d9ebcf18ce346364f7601856aa68584ee3303e8a69d0dad778e4a4ba3ed4f8a009d561652d134e +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = d3787e2cd5eddc154a3b29c8a5161cb0ef6fa97d6b90c9d579677d46ba22108075fd9dc13958d290c40df3ae2400224a1cf8dd74c9adc8d48522ad9c0c34c1bbde732954e432bc6e55da0beddb849ec1f2c6815d91cc006a0dabaebd3af3ac87d38327cc1ca22317c54b776b12c7197c39829c1f0c17f700d7ad88938c86594d +S = 22754363656ce107c1beea8999cb4a95d267d6c6d3a06b42c939f51254f822cf49bd6d51e27af51afa0d260fb4bf6fcb8b4926270851d64f2fae6f4c6562c532e3fd72db5188c51eb57b01a871004b38d6a1bb4856fdd93573735a480b4c3e444262d198d54de6db409db7432dd45beabc34991cb6868e1e1dc62f8ef509f36e +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 31f8dd3024b0487ae1e3a7af9032ef7c76d5420d617771814747c09b2a4ce9ba3ef8630b4e01e3fd5c6c24f588ebe44433682f5663e2df2b6978640bc2c3c1763c69d75b59efe68af8cf516a32cba1ef8380cdc72a3eb9d4d217fcdf7136e68b7173c2870e245808ff35b677587b3066af45a6c97d340563c84d107eff4d61df +S = 92cd8a854b4b9842c12c7f9ec2dcfad57d1f403ce8276d355f436c1d9aaa720867dc5a96b91debceedf55eea2a33d99e586a0a59d68e9289ce6f001be3d9ae9887d9f169ecd77600ef60b97851bc8ad6c5566c830a25690a13a92bd082fdc0b356a6443fcae3d29c5e9818b06c69748149a3f34793a6c7b04da345caa01d6f20 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = be9b41883cfadec3960d866fe8514f9821c6c7e65af6e5c167343fb8ac227e2432760f08fbfd1c3c92e0bbcbe5266599577aa949122e215d9a81a69fa81dc0c035e46040d5ecd28d46c8ed6f490a8da3b00543c7b9d84a769aa8bdb35d2c088bee6f9df673d1e8ffdb4f8424ba05af0054f1fb27f7fa47528f31eebc74563ecb +S = 5d8ce84e9473178a2ab5373d3154e7d649b40a144040d4a612e9ae43666d681458b5d985f5bb1bd5709455f5421dcff12307e074714b6592f0095c0a67f66f950ac8e2cc7b8ffa5d8f89d407292ac659a4e479ee2cba19d6f31673edbecb3535b85b11edfcea4df17799418fdfda145711f5f9c0540f811ac92e05bea4460c87 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = f8a2f38109c9b6d868c5b3481cd3478c8e0845fc3e36479cb50f4158bb8d5c8ec99101cdc1ca33ddddd823ffe5b1fe75a6440a459f5df13bfdc95d2dcabac482616d86f52509359772cb3313d46083367792d9afdf27f313d9062c24b29c4f52a67ea9829b50620f10e50d0e50a77dd7eb3adac1665cf52c3210d9c5dbfba305 +S = 3c42cf56c04c1ddd18a5ec523df036428d09bb44a7b12be5bf6fdb3866a122a5cd0edb2cc81930c126a9244afcf6a27c8820369f474a06f8b7022ac8b95e35791a49d71a40ecd145e8d2e334b15f6ed698b7a646248ee73f567739469960c0da5112916a12f212d198a6f6c518b4745a578d265ab1c04438d7a38263a5a8c254 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d060960864801650304020305000440174762fdf1f011f716417beb00598a33aae32c141c664908178740f19833d9109154e89f80a1ff369930cb2dbeeba511433122236e0cf6df2d7b7202de550c6a +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 7e3c652fb2786a379614fc8f9f01555cf029cf61cf0af6c455a4e2156996c48cef84be923cbbf883cd18f0b3392611af658688c5f79453c60d479a0a2e5943b581a8c1393cdd2c1c604b97fca41a9ed0aea43e70891fea58547ddaa83790a7709c72152b9b242f89b5759a72c6252347354b9a6b6ef4e302920d4af86c831745 +S = a6825908039d9165b1f1d7e85de390819b3e13fb914521bde6370db313e0c37444bc1bca1d798a73e9602b3c61a67b6c3531c25a0528f4945ac7f27ed5848b782668cad8533000a42a0435de4436e4ee7fe0f9a347750543d921a313c6872cbcf5466ae41a69f32d03acff357cf3e4f1a3e7ed4575dc61bf4fb77a04b9d3cb32 +SaltVal = 00 +EM with hash moved = 0001ffffffffffff003051300d06096086480165030402030500044062eeafda47b660f230159a79e8b20ffc84752ef5ddc420ac6478511cc199f983ea3cb8cbeb9955c175ba5afce719ae601c6303a1f6cd5e0c241b5cfb8577deb6efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 +Msg = 2bd0f6349c6f8198a10ce8e761feb6d4d72bc71addcefc628a773367be537758fbad737e77b52d1e6f80f1a1bd518af2ad17b9280d36df65838afdfd24a9dedb4169932184a3200f3c367526f64ea08d4de640b3038b3d365063b604796f3bc0a50d3d67edc1c233b2345dbf337d5e6d5ea04605e7547e9e980a48c2e82af5cd +S = a5c713d065e204f5a3d87e4752b235fa79a703931065aaf7ae4a29d641763d7ea4350d8d9a29b29b4fc770169ba7adf1cf7ba872769265cab2d41ee7e227e7682c749fbc5836debc02485eaca9637391c3793b3f05701f80a90cfcc04c091fa37628e4eebbefe5ceec0b4dee1b41241fb883252fe18ca65ab01e4a4e3f31ba36 +SaltVal = 00 +Result = P + +n = a8d68acd413c5e195d5ef04e1b4faaf242365cb450196755e92e1215ba59802aafbadbf2564dd550956abb54f8b1c917844e5f36195d1088c600e07cada5c080ede679f50b3de32cf4026e514542495c54b1903768791aae9e36f082cd38e941ada89baecada61ab0dd37ad536bcb0a0946271594836e92ab5517301d45176b5 + +p = c107a2fe924b76e206cb9bc4af2ab7008547c00846bf6d0680b3eac3ebcbd0c7fd7a54c2b9899b08f80cde1d3691eaaa2816b1eb11822d6be7beaf4e30977c49 + +q = dfea984ce4307eafc0d140c2bb82861e5dbac4f8567cbc981d70440dd639492079031486315e305eb83e591c4a2e96064966f7c894c3ca351925b5ce82d8ef0d + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = d3787e2cd5eddc154a3b29c8a5161cb0ef6fa97d6b90c9d579677d46ba22108075fd9dc13958d290c40df3ae2400224a1cf8dd74c9adc8d48522ad9c0c34c1bbde732954e432bc6e55da0beddb849ec1f2c6815d91cc006a0dabaebd3af3ac87d38327cc1ca22317c54b776b12c7197c39829c1f0c17f700d7ad88938c86594d +S = 4bae63c2b4ed42b92d95293ba755c0f3dbae5a13369b298147e3d7d9cf8629b7df9df22f13370239ef86c91a6b15efc5611057b375e948d554a95a7119f5663b0ba6c373121f2d4f6f9a8703a78153be3472f296254db218a22925546340dd0495ec68f354ed17ed4f9d85d4b9eb1b9d1816cc1422c852410841f166e69cc212 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = 31f8dd3024b0487ae1e3a7af9032ef7c76d5420d617771814747c09b2a4ce9ba3ef8630b4e01e3fd5c6c24f588ebe44433682f5663e2df2b6978640bc2c3c1763c69d75b59efe68af8cf516a32cba1ef8380cdc72a3eb9d4d217fcdf7136e68b7173c2870e245808ff35b677587b3066af45a6c97d340563c84d107eff4d61df +S = 8a8b25a74adf17dbc6ee3dba1982f94c17ecae57a75835cc4cd476a1afb23d01c964e8532a6d0afe71ebd8d26a2e5514906caae8b18ddd860ae16303723cbd0a155cca1a4a7be32c2396b1d09544057e7f7fdf6bf1bb2861ecc0f90223269add410dd66ea54a507a31b75528bb277ee9d3d3096d2e2f0f33b0509f27bd990b9c +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = eb2a75ef219b2bec0987c2623a76a8d3c292754519c47f8d541aa8cd9b6c7b3cdd3f7825c2e9ab33e2f684eb34cbe27ac98971b1ba34364e5f15687dc15c829e520a9649dc0ee48fb8aeab8340293ffa869b5c8e4720bae91a3ce140ed7b3f1db25478625653fd8bf378e03346dae7d9638fdfe5a7d032e6ef59bc1e070fdb40 +S = 0fd7069ca1e24f81f3c67b0bcba5fa72764655739d549a59288e6eaebf4d2f52c52eaa17e495ec2b2fcb52a4673aac2e48e2078688b8e5d8a91d7c8c4bae725070425a183e95b352999ab2b49adce63b6c9d48dc29e0649d91b73fb04c45786239b0022231e5e173e2f0d94fee7905706f39ec88fce30d107e4151d010be719b +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = f1cf2ba2463023a1d329957cf3fdc044ffecf8ce0a11f9b6ce8b7ba5e5db07d03d8d08c1c61b255a6d0ece174e661593253cc04e06a69cad4fdb1442da97014e77c1c484994c93104f5b10d876a820022e26fab68ae57e258c36c9ca501106ef87b38674278b14cc61578248d48b889800f2cf8ffd9748266ce6c2c4af0fbcbc +S = 2e305057388fc454647e2c20b71c3cc3383af683126b1b802b6e74096b46655df2715e18bbd1f9f7f4484dc63ea58bd7461c58d6e7ed63e885a2524b01eeea2b9d0cbe25e6f0f780fed9fc9610ea5b7de468b0cc409da4607a367b2815d346facdb6375a7723d013f2d8726e7b40a680b82c112324ab161aab860a943d4fc84d +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a050004141bd3d18838d09a61c2b0ba9865a146b958c0ec0b +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = 8b61c39efa507e17cf4d575bd600286d56a40e84f35d6c06d3cc33b400e161220df1c86bfd0911226081008cbfd4fa0c3aafc4de70478d089ff02f8e0cecb2e6a68011abe64d4196f9de70a9217e8bad594c02df3891cfe71750b509761fc59f9c3627c77ec61759e28c2e1cc4a5e339f9a451ef12e23b8983154d8d0524a437 +S = 72c3377e5a389a176383ffb832de6eaf3b7ee9dfb38f504031af6f3d059cd9c1027e22233d1ed0908bc08ae5edb9aa491aa189610b353b31ec92eb8186c0d2bbe8fb1364c3df8393b5917f69243ccc7cf95edd413cc175793c964efc3eed10b6c2c4de4d7b75f419a68e6cf8eb1a09b0ff29c40b713ed63c4fcc08fb59ddfcf4 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a050004141c6c02fb4af79739cab2f59451c9ec6ff577051befefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = a6cc1c55dd9b8da73acc6716344503690a9db27bb439518719b41da28284c9894fdbce9de9cc032cf7af6df2d5c658e04121a61c58be6848c2f5ab07291394bdef46b09720b985cca5ff6d22bbb5a4b3a4639ff19ca49fe80f8787c30934ea92eed3694a6ba93c0dac840eacd05a0e6b9a2d430469311fee6a3158de0c2ff38f +S = 7fc3737dfc4bf283bb8f8aa2918af4fb7156703b4870f679bb76e079e561d0adb7a21bfae94e21b83edf20bd28d6c06505109bcdd000c7533a8ff9118be14cd8beeda9cdae6f0735d75fb80953bf28587fae51e024d5b415664b3ab9c26abbbb7f2461d9bf7f2520ba08a09421939fd661d5e3dd83f3e4c41f760291e1c081e8 +SaltVal = 00 +Result = P + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = d3787e2cd5eddc154a3b29c8a5161cb0ef6fa97d6b90c9d579677d46ba22108075fd9dc13958d290c40df3ae2400224a1cf8dd74c9adc8d48522ad9c0c34c1bbde732954e432bc6e55da0beddb849ec1f2c6815d91cc006a0dabaebd3af3ac87d38327cc1ca22317c54b776b12c7197c39829c1f0c17f700d7ad88938c86594d +S = 7948b018e9d0772d84bdda094957387e91179fd7ed4483091f764a2077d37b87a54f4d10069584e50314e1d866c01f1c22de215c0cd1ffff3e23b321378c1b53d0d517aa29ac262ce86dee0ba752958fab5ab69a3a0fb6824ffa8554d4b212f532611b10a28faca706391ac2bbe04a9603e4f15021ddbb1d47505bee6ba83c28 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = 31f8dd3024b0487ae1e3a7af9032ef7c76d5420d617771814747c09b2a4ce9ba3ef8630b4e01e3fd5c6c24f588ebe44433682f5663e2df2b6978640bc2c3c1763c69d75b59efe68af8cf516a32cba1ef8380cdc72a3eb9d4d217fcdf7136e68b7173c2870e245808ff35b677587b3066af45a6c97d340563c84d107eff4d61df +S = 2146e1bf9d75336d7bd76091527567c9326df14a810cf39d22eb91589584caaecd89ddc1b3ef0782e79e535b0bdce8eba2d7f40aa05720278e6c3ed8fe58974fc1ba6cde3fdb79284b64eeb5d08fb312eab503fbdcd85c240414b8a9fb726f38e2780d2506381d90eccbad3c075c7fee67e8a1da037f14fc4a6d8f06c301742b +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = eb2a75ef219b2bec0987c2623a76a8d3c292754519c47f8d541aa8cd9b6c7b3cdd3f7825c2e9ab33e2f684eb34cbe27ac98971b1ba34364e5f15687dc15c829e520a9649dc0ee48fb8aeab8340293ffa869b5c8e4720bae91a3ce140ed7b3f1db25478625653fd8bf378e03346dae7d9638fdfe5a7d032e6ef59bc1e070fdb40 +S = 885c184cf7e40453f8dcd49e1336c91adfc070ae886b23b561cf444092017a86594dbc09c484d6307201633b4476c480994c4bf0a38195d9e9065dee62f5510cb0d9b16a5a9e0ad86eee516a090809e599b4b7022333bdc1c2f9b0cd181a897108c8db6e2abec0c9c6acc426e55ceb9cb4dd565af9d0eadc24ad33bc6a0f2f9d +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = f1cf2ba2463023a1d329957cf3fdc044ffecf8ce0a11f9b6ce8b7ba5e5db07d03d8d08c1c61b255a6d0ece174e661593253cc04e06a69cad4fdb1442da97014e77c1c484994c93104f5b10d876a820022e26fab68ae57e258c36c9ca501106ef87b38674278b14cc61578248d48b889800f2cf8ffd9748266ce6c2c4af0fbcbc +S = 56c800772a63baea87e02adecbe6e7a1cbf352ec6c40d68d02035a8ef54e3c5d4e4c8d23a686d186ab783dc0115ff56138f05cd0a88a28df8304a7fe8c1f944acff2c51ba447d333e97a053aaf222bb6371c35d37a3c7345f7ba81ce99baaf2f165c3a5f0d9a1200da7017de8ab65c35cd7d082800fd13fb87c37ceff83e3dd0 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c084f86c411436b0111c733c5642186a98d5a8dd8cceb2746ccb8342c +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = 8b61c39efa507e17cf4d575bd600286d56a40e84f35d6c06d3cc33b400e161220df1c86bfd0911226081008cbfd4fa0c3aafc4de70478d089ff02f8e0cecb2e6a68011abe64d4196f9de70a9217e8bad594c02df3891cfe71750b509761fc59f9c3627c77ec61759e28c2e1cc4a5e339f9a451ef12e23b8983154d8d0524a437 +S = 1daeb428f8dcb93c16b0b96a23708a4a0b2e70ab7fcc2fb16075f901f94fc9bde149b26c83738e58dc598bf4e1c53b34adb69d93f30726a174ac87c1a1b67bf70fd83fb9b89f476fcb13cfed84c2f6d6a92294e0eae0bfdf91119cb692b096c9bc3d242a31f8a979f965fb983031b8f33f18b1713cab83c1391005a94b79ab31 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c6c72c171d3d71a0bc8488c39813a0b20e2e937a13d9484f6c5de23d1efefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = a6cc1c55dd9b8da73acc6716344503690a9db27bb439518719b41da28284c9894fdbce9de9cc032cf7af6df2d5c658e04121a61c58be6848c2f5ab07291394bdef46b09720b985cca5ff6d22bbb5a4b3a4639ff19ca49fe80f8787c30934ea92eed3694a6ba93c0dac840eacd05a0e6b9a2d430469311fee6a3158de0c2ff38f +S = 7d914ae58407a2b981e58ca575a81796a5d3d7073f6cc3b2641338fff4b963c35125e99360b8bebbd12add1919ae46f84c67b642b43d48360785d7d990bd6b23a24feb54925575a46c2e49d5ce16204ef0c921a25c31fe0b5ed623b2a35be5069b7a7fa57322a9fdcee5b391451d49e624fad211494ac3230efbad44cc5f739a +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = d3787e2cd5eddc154a3b29c8a5161cb0ef6fa97d6b90c9d579677d46ba22108075fd9dc13958d290c40df3ae2400224a1cf8dd74c9adc8d48522ad9c0c34c1bbde732954e432bc6e55da0beddb849ec1f2c6815d91cc006a0dabaebd3af3ac87d38327cc1ca22317c54b776b12c7197c39829c1f0c17f700d7ad88938c86594d +S = 73b08114f6256d434c5cdc278a9ca697ea2447895884ce05170dd41d5073ae0b6e346ae64fe886287151e0c6aab0aca3638e5b82d63aaaafc50f8070b592cd052ce7bec9306ddc4760a6f6f2166e40800715103f938698a68a10c73ddf524c6c6e55f76f7a0ab7058cace263af7061fe70fd93ca62884d232195a91acc38af2e +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = 31f8dd3024b0487ae1e3a7af9032ef7c76d5420d617771814747c09b2a4ce9ba3ef8630b4e01e3fd5c6c24f588ebe44433682f5663e2df2b6978640bc2c3c1763c69d75b59efe68af8cf516a32cba1ef8380cdc72a3eb9d4d217fcdf7136e68b7173c2870e245808ff35b677587b3066af45a6c97d340563c84d107eff4d61df +S = 6707ff06f4e6fe6cab612b8deb099ac9995511ff0f43fd42f9f1822105e6c78cf6e7bdb117f5a8d554000aeb22c69cd0beb7cf1eddaff92161117f08befcb01605e3300826c87f2fb10f6e34bde865db2c5b7124d3273a997b115f3d0022d0cded54daed0b4ddabfb9b39abec2f9b1e052a89c4d64f38a7649729ccb14f72650 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = eb2a75ef219b2bec0987c2623a76a8d3c292754519c47f8d541aa8cd9b6c7b3cdd3f7825c2e9ab33e2f684eb34cbe27ac98971b1ba34364e5f15687dc15c829e520a9649dc0ee48fb8aeab8340293ffa869b5c8e4720bae91a3ce140ed7b3f1db25478625653fd8bf378e03346dae7d9638fdfe5a7d032e6ef59bc1e070fdb40 +S = 43a9b4ac08716a3fa5e6ea8fc5957492d093b3a4293df69efae3501e938dc25f551bffc491abbc1059543280c8f48e5c97ae0fe602c911eb894804ee585f2d3b9de882856ba2bb4c86c6a14b8126cb02be2ec6303c228dfb892d3786ebd2a9eb3247581ff7f01a2d0f6d4c75a96dcb4e98fddd204eb8d191f0896506fb72d2ea +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = f1cf2ba2463023a1d329957cf3fdc044ffecf8ce0a11f9b6ce8b7ba5e5db07d03d8d08c1c61b255a6d0ece174e661593253cc04e06a69cad4fdb1442da97014e77c1c484994c93104f5b10d876a820022e26fab68ae57e258c36c9ca501106ef87b38674278b14cc61578248d48b889800f2cf8ffd9748266ce6c2c4af0fbcbc +S = 6db3e5bbdfe86efac37bc19abbd07d9209f67876d0ed8f8859b1826d98eb22fa093e161274e4a38675cb76224a70346730314f08475db6ce6fd77d840b9de3063c88e987fb244ac823e962b31ec648ca8942e378a2f7ccf7400b036aea7c5a11e694d85c3c929e43613178eaade378d3c2f6805a14d94029f4a5ce89a87651d7 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420659241b16b3fb30e5012378eac6d83b927e7fc9d0eb5a5ea9d1b75d48441a6a9 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = 8b61c39efa507e17cf4d575bd600286d56a40e84f35d6c06d3cc33b400e161220df1c86bfd0911226081008cbfd4fa0c3aafc4de70478d089ff02f8e0cecb2e6a68011abe64d4196f9de70a9217e8bad594c02df3891cfe71750b509761fc59f9c3627c77ec61759e28c2e1cc4a5e339f9a451ef12e23b8983154d8d0524a437 +S = 87ee0da9c96d9a17f63d3e9e142181c0979c381ceb769a370545b535abc6eb8981d3fd4029f529909f620d2a00f209b6ad7c8f709fca13118e00a2f21086fb3a4eb4e416a0b2a121e4f7be5b172a8ed12185948cdb75575fe53d883a354f17baae73fe464d85ca0519b980a4b6f565bc0e76060f86b4cb3e90b6c4b9902f5bc0 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004200d04ea209c27fd97098f416a6410afea38ead35d43b7a1f93d7ae04f7d62d502efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = a6cc1c55dd9b8da73acc6716344503690a9db27bb439518719b41da28284c9894fdbce9de9cc032cf7af6df2d5c658e04121a61c58be6848c2f5ab07291394bdef46b09720b985cca5ff6d22bbb5a4b3a4639ff19ca49fe80f8787c30934ea92eed3694a6ba93c0dac840eacd05a0e6b9a2d430469311fee6a3158de0c2ff38f +S = 8be4adcf1f21261f16ed5b4ce29284399e2a6b7f6339ebb94fcd8c412827911eb5e626d6c83315a59db85bea8010ccded74991f98488fc48989b1854619acccb63fff3d1e4e9a350440744e8bd16631f39ef2a1426b8ffc33418dc7a2a0bdd3330b0bbebba1f0b9fcad2347a875dd89feb43506c0d8e1476e36c9fc6a2798ec9 +SaltVal = 00 +Result = P + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = d3787e2cd5eddc154a3b29c8a5161cb0ef6fa97d6b90c9d579677d46ba22108075fd9dc13958d290c40df3ae2400224a1cf8dd74c9adc8d48522ad9c0c34c1bbde732954e432bc6e55da0beddb849ec1f2c6815d91cc006a0dabaebd3af3ac87d38327cc1ca22317c54b776b12c7197c39829c1f0c17f700d7ad88938c86594d +S = 70fa48adbbe7f5cfcc61dd844ec0948d8c20ca5bca62cafb0d7014413350c5fbbbaeff1d445a7367420b1237dd316db6c8298d5ba13a3b26cbc48a84081bb12848cd8acbd198a7250d0411ed8d0e56d0163c39853b3893655037f6b4774be21d62c604522904202d6aa0f11aa1f7f56612e85139ac0d577593586d6229422289 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = 31f8dd3024b0487ae1e3a7af9032ef7c76d5420d617771814747c09b2a4ce9ba3ef8630b4e01e3fd5c6c24f588ebe44433682f5663e2df2b6978640bc2c3c1763c69d75b59efe68af8cf516a32cba1ef8380cdc72a3eb9d4d217fcdf7136e68b7173c2870e245808ff35b677587b3066af45a6c97d340563c84d107eff4d61df +S = 1a7aa3bb07684cb72a23a570dd06eec11f1ac1e5cc02108b6bcd7145c413c743da8706a44db575b7053573e975ea2bc111821612f14aa001dea6551863e34af0e68d6f9281cccf590d1b2528085cb8e878a427d320c73806a3af8b498b7d3789b66dda4ba9d6c26d15500c71a6b663d9612076792513776921503435d6578b6b +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = eb2a75ef219b2bec0987c2623a76a8d3c292754519c47f8d541aa8cd9b6c7b3cdd3f7825c2e9ab33e2f684eb34cbe27ac98971b1ba34364e5f15687dc15c829e520a9649dc0ee48fb8aeab8340293ffa869b5c8e4720bae91a3ce140ed7b3f1db25478625653fd8bf378e03346dae7d9638fdfe5a7d032e6ef59bc1e070fdb40 +S = 706c8a70281ab07dca9ce73757279e70621358f1a5bad91bb8d0f34a4519c625ad000df75709b7fc805ee64e1a0e8b2f5c637a833b682c707eb21ad79f99d9f82aa91ca1f3ceb6da9c117c96391f547297cc8f507cc4363f9f2ff84fd9c8f430e84740f3d3d9f385e73d90c8769da2615e46552566f456f6a675d613b8a97678 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = f1cf2ba2463023a1d329957cf3fdc044ffecf8ce0a11f9b6ce8b7ba5e5db07d03d8d08c1c61b255a6d0ece174e661593253cc04e06a69cad4fdb1442da97014e77c1c484994c93104f5b10d876a820022e26fab68ae57e258c36c9ca501106ef87b38674278b14cc61578248d48b889800f2cf8ffd9748266ce6c2c4af0fbcbc +S = 5b3567d2742f596b42cd2e3951f75b8058a98d822961f5deed17ce86355fef06ce8f1b1e83da9f27ac4203d2b6a406ae2657993624344fc760a0ade6106028e2dd68646f1c6a735547aa7e4d4e6ae1d3f14610d5eebc88dfeeccf979d93f1721554c67bdbae99dcc2efcf3a98eeb6bf713dd3c5fbfa44e3b9467838744d226bd +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430582a092df1f38834b32c013209c529a91289d7e595d648c1a633680988e5c8f8153c37c9caf89c37578d4a5cccedf712 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = 8b61c39efa507e17cf4d575bd600286d56a40e84f35d6c06d3cc33b400e161220df1c86bfd0911226081008cbfd4fa0c3aafc4de70478d089ff02f8e0cecb2e6a68011abe64d4196f9de70a9217e8bad594c02df3891cfe71750b509761fc59f9c3627c77ec61759e28c2e1cc4a5e339f9a451ef12e23b8983154d8d0524a437 +S = 0a23fdb9060b70ffeb690d0e4be5201499f3623663c4a3c5b8ccd937c20523fcdf526db4279d7d7f1067e241b0d7f00de2841934691747976f3c63e68048702b69db8981d8efba63f0fabab14abf2f517b0d5caab537f187af9f46414f070fa5c1fb9d2eb6858476a5af8bc82b7c38aed298f169f1b962aa452e5f6cfbfe766d +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffff003041300d06096086480165030402020500043061ec010a79fc79f61a9051dae86a56fd57b311f7d5043f4519aae525d02bbe46a433dcc6aad89016c6298dd09ea7ffecefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = a6cc1c55dd9b8da73acc6716344503690a9db27bb439518719b41da28284c9894fdbce9de9cc032cf7af6df2d5c658e04121a61c58be6848c2f5ab07291394bdef46b09720b985cca5ff6d22bbb5a4b3a4639ff19ca49fe80f8787c30934ea92eed3694a6ba93c0dac840eacd05a0e6b9a2d430469311fee6a3158de0c2ff38f +S = 9bda2d9a6a3570737eef2c75f5fd4891d9e8acc102654decc8321b2e114ae8c2f615a1173d855e5d4261a99dc7f825fccef11199e57ba30d98502c237761217261dc31cd14de68201278ccfb46459323d192fdce1577a1a9098e5c7117bc0e52ece3403e0b35fc64969342a72ad74e0330a10a50b67536b088372514a8436de3 +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = d3787e2cd5eddc154a3b29c8a5161cb0ef6fa97d6b90c9d579677d46ba22108075fd9dc13958d290c40df3ae2400224a1cf8dd74c9adc8d48522ad9c0c34c1bbde732954e432bc6e55da0beddb849ec1f2c6815d91cc006a0dabaebd3af3ac87d38327cc1ca22317c54b776b12c7197c39829c1f0c17f700d7ad88938c86594d +S = 3892627dc93f65857a6e773202ee6d8bfed806ec2580f1f63fc7bb547d6ca2d2459efa5aa6cdc9513153ef2dc2f9acc0a3f878c4b3a149b674f246842610ec9d4f8d2038bf1126632b588b7c8376066d1b18d85e51ec221efcb5f58e6f3f4fab1fb6b232d443cb16484670b1adec3a450f9f926ceee02c6ffedebc4664a9c5bf +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = 31f8dd3024b0487ae1e3a7af9032ef7c76d5420d617771814747c09b2a4ce9ba3ef8630b4e01e3fd5c6c24f588ebe44433682f5663e2df2b6978640bc2c3c1763c69d75b59efe68af8cf516a32cba1ef8380cdc72a3eb9d4d217fcdf7136e68b7173c2870e245808ff35b677587b3066af45a6c97d340563c84d107eff4d61df +S = 6015144a01c388c92bd4913907fe075a42afea023989156b840a493f074d55164405e50a4105d5ba9810a9c761f4626e6e05bf7ec4b47b07ad459ff404db6931f4a994a1911fc65448163d369eaa61674ce2112f79a7a9f541f26a111a605b9a3aeda1db6627c59bf723d34153769d18d9ca724570484583b37ffbb11bf7d4be +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = eb2a75ef219b2bec0987c2623a76a8d3c292754519c47f8d541aa8cd9b6c7b3cdd3f7825c2e9ab33e2f684eb34cbe27ac98971b1ba34364e5f15687dc15c829e520a9649dc0ee48fb8aeab8340293ffa869b5c8e4720bae91a3ce140ed7b3f1db25478625653fd8bf378e03346dae7d9638fdfe5a7d032e6ef59bc1e070fdb40 +S = 45d7f419feda3099092973f1d61994225fec873a0467b1348776a3a6578a10b24be941000311519cf426aa8bdf45a300d7eb31766e0516988cefb14f076c0502a9f7421ff4965875bae992930322d34555cd32ec47d8e6b1ddf95cf1eb193ef3accea5db5343a80d0d36d4325361c7180de57dcd80929bcb9fa166ecf930113c +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = f1cf2ba2463023a1d329957cf3fdc044ffecf8ce0a11f9b6ce8b7ba5e5db07d03d8d08c1c61b255a6d0ece174e661593253cc04e06a69cad4fdb1442da97014e77c1c484994c93104f5b10d876a820022e26fab68ae57e258c36c9ca501106ef87b38674278b14cc61578248d48b889800f2cf8ffd9748266ce6c2c4af0fbcbc +S = 22a5c4a08adf1a8d1dc26d0a3f02af5f12062b82e10743fbc2ae74b0bb533de279bb57bb6f0a44f9b79c2621c426e9e6b5f50a5a8a2df9d46ce9fdbdd0bf6e74cbe2e55682046145a7e40622bc81ec945e8b87a8a9b9ad711e7626109772b64be7a7ad7d5f3b3aad20c03eb164716b62e0851f1041930d4e5ef4b50bff82f425 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d0609608648016503040203050004406aa75a3539ad3822952b91897813389ae2946b072578bea95a64f583bb5eb9a27a8e44c2405a9681d9a290e2cd55fbd59c381039de0e21ff120d2a3ed8889277 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = 8b61c39efa507e17cf4d575bd600286d56a40e84f35d6c06d3cc33b400e161220df1c86bfd0911226081008cbfd4fa0c3aafc4de70478d089ff02f8e0cecb2e6a68011abe64d4196f9de70a9217e8bad594c02df3891cfe71750b509761fc59f9c3627c77ec61759e28c2e1cc4a5e339f9a451ef12e23b8983154d8d0524a437 +S = 088942923512cc272b5cd0b40d4aac42ea3165c74c90970ebdc46b5fa8c0b0e153f85c446b0a2d3886c7fd468a47efeba91550c7f01167ce009a4d6a3069bb280b6755eb9716c03f64cd2788555b9f8a0e85d74879dfa9c48ba3ff2002a8b0de02cc8479ca2a59966994d36c6622f4297e2a26cfaa824e447a6badb92331829c +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffff003051300d0609608648016503040203050004409bf5087cc76d346579861f84faef10011e190ef00bfd9b708719d5b672952c0a5f5a8fea8c12b2d738e0b420d785e6a02d7352b6a0e3d20ea2c2140094278b52efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 +Msg = a6cc1c55dd9b8da73acc6716344503690a9db27bb439518719b41da28284c9894fdbce9de9cc032cf7af6df2d5c658e04121a61c58be6848c2f5ab07291394bdef46b09720b985cca5ff6d22bbb5a4b3a4639ff19ca49fe80f8787c30934ea92eed3694a6ba93c0dac840eacd05a0e6b9a2d430469311fee6a3158de0c2ff38f +S = 82f547779204eefa0d857ae077b2e02e61dc76ee75e709388ce33b3f227dc96c5a98148a816a4c954516a7e44b00b080cd8b05cfa4ae9ff82d64b811f62e6752904b88c2e4a9d54088a49d2d480c267b96974c46f75a4fd9cf09acca14290d6515defc75e0807334cba3f492d42a17dec01396e39d7d8335bb4d11a1c19db3d2 +SaltVal = 00 +Result = P + +[mod = 1536] + +n = d2b6c8fd44e7eb621fa6685fb62371872b5e8408af51bd1b44c6473823402418a26963b98e6fb191cf74175e64132ae6cd101133fc002a89c10bf7739eb930b9c067b52570842395657f927434aa3acbf3369dcdc3990f77cbf22939ddd5877f09c8aab818b80aa20544b6928fe62c78795a4160aecde6ab454db0dcdf1d6c13522526c5ccf82d429791059306f02cdc18c4e580ec6c2da19b3c6de63933ebeac79010c73df95748d987e96a0f8ad523b5014b33423f55922aec2ec23b9aa22f + +p = f260d143cff1e8e0931765da8cb335c0206bf7fd19aaf8ff41e762992f2bb0a660cd65f08a80fe502c9125166a6927aa1859a874159796fada835b48522f5795ed1f8d23f05016358ff908b0dd638bb7ed12c8b80b46aa858d52c77bb7fc0ed1 +q = de8e674fac0b7ea32d518a22030fd10d4298a77974db8febe195a4240dc5373e8161baf8ce47dc4fd076f64e307ea6262c35b9819bac4f142b613973eeb6a62a15a2ff09fba9ce4db7186969af925ee3acb7d3be7a1f9c85358216640fc1e0ff + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 95e319c0df793cf1c1b424a8949b9529d6c1a0cece5f6db573a538b68b529a9810830a84d7c8a3b9747d2882585845653c3e179ec35befcc5a7153e96370467f9448ca1999fba2f801f65c0857a18f138f356233a5ce4d8d80c1243c1c2f518ce8da60696d38c21731c6ca23db9ffc99974d8777bcdf1062ad3bb198fdb64226 +S = 1b5d13124f4a0ba3b4e8f102a7044d8a633ea025729f55ac75e4a8544612f229d4f43c45574983b51efc83ab611a60b009949dd032c97358bb7ae5d3b2ce417fe11a9f6435b84bf7113b23403b010fd749838823450ec954f6e3f54c13db12606ead2eadbf209d5d31efaaa0924f256d3f64692db8a2b7fd8197df13c33b160b2f8fef0d4f2ccdd1e1a5b269b25e4efb462c000573b8584d45c2cafd248348f19cf1f7422abaa402ba54274b7611c4c9db3a7dac61ce51c396cc3c59ecbe5594 +SaltVal = 00 +Result = P + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 7271bcb91b18288e874f4c04c10a21bd35150b1813ef61a7f4dc29e4c036231fcf040abb4ece169ae5afc5d696abdbb2e943a7d0464789a4a2ecb1285e1e29d16b1716c2b3313b41b4f8be676e842f1b8006c6418ea0ec2ee57afd5f62124d6b90d3693710ea9f693e55c01f113c24e04385efd3b2a3932e07ae96f295b996d6 +S = 6b9212d017ad9f4bb7ebfa3975b514bdd22240d753fef5631e1c216bc750336349255d53b857bc944d3eee3bc82805620d770e41dcba45869f47d36343ef067cae99a941ab94948bf0c02d2a3ee403c7eab0f9d6f9423c166e62c2dd61198046944b5082db4a17843229489c46baab712416e3d0a685d2353abe010c94ddf7b47f5edf1fdfc9a5e0de27d65ab5dfc9f2e660d20d169cde3e2642393edd79fe7316ec4ebe61fb88223f6711e138d09ec3d76781e73d93e7dba9830c53cdb5b0fb +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a050004147c3d3d4d94e5e297419551f26b517d0046a98d9c +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 1484f58f6b8cff56ab4b81d17967dee7ef1eabeae57c11706fd2735ea6655145ac636df2ea1b2c409c6c3e31907e813d2ab123eaacd3089db4966bb00741c7c48ca5f8599c539d9c790cc27f1b79bc0f331c53036a872790e9cc4c851f343893be34dfec079c1c11481253e4a3bf55051048835ba50037f1165c5f0478a76b5a +S = 57b3646aae17304bcfab8b6477bbcf791ccfb4b20001b2c3cd4e6dafe129934f2c401b07eada6a4b2db9393ffed36a8ae8af85b1d433a398399fc0c2956959e99c12053ac3346710ea5d9119fa4757032fd1739b426e879214afe364a9d274d383e4d1fa64b0b07c6f6014dcbeed59ee0dbcbec90cb5f3133daeb829855d61b88777d806b5717227a8016a965f1bd2080b44ef80bdbd0bf0c494ea7baf09295aacf161c433320fa81cfca5ba44a71264a1d1db1d2f5baeb58eb9d623710ed1ba +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 957018ebbf4bc279aff3a28f87510c01666122399490a4c300680910ed6ece73e84b0e70fd2b53362a63ac6a1456ff26f999a142e65524d22aed70ef0ae115bbb6f3e09f7c88add73c507b311c29c6117c4111b92d7bc2c7dd1532ffd687054be9aeb700a4297863cc043a6c079308cad8a19926d0cb25ac032677c8ba28442d +S = 7d9edeb96e2eb21b32fc3707c42fc26cc2ddaf5283ed2853206e51594027fddbc82260dfb3e2da03dbec1069f0bdc63a7583f0ffc194ba158860fb0bd13dbe22ed34f7f77821b58ff1b6d9a6721f91914d3529d5e605b813f7de832afbc57d7ba570a4af8f9ad2b7ea8d2c1656c669e1df7d3c112bdbe212d37d61ff62d03d8b19426437a48977ea5aaf5eccdb7d90d1e8a1c652cb2333984cfac0c1432e42fb16168a3760328039d1a836a52baa9be92050e96dc86d37c8e0b0684d445be018 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = af0272c90402a9c27f9cf6c9de652cb7a3a402b4695a0c58777fea11958fc0c51f45e6b857a6e0afff42905628b7aadf457669ec83ca80af5d16544f6a5e688e7a0818aae2e48b80146be3f77344b69c650dc28aa957dc8debf22a87956c9212e9d472664dc3927ee59e5776671539382bef7657820a083b499dd57fbec12797 +S = 3cb0d524151a8e3210123ac13086c6299074f5b5a4276059cc2e741944eda31a80aada9427d0a7e49823632075093e4f779f9b84ec4f159227e650c267cf7126047f7d257dc6e41ec6113570bc231681667735d41085ea92a2b9197fac8e4ec9bfff1d2b16f65ceeed22741a872a05afd641b1444a928a948d15248b119f28b3d35e28a337096cb7bb97e7e3d73bf1cf8abdad9cbfb84481a3e124b8c345a2d1065b1713de71e0ef6b8beddb6d88e82379960bdc1cda7ebc4c4c4ea9bd1d81dd +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 3797ad7bd2b5c611a7b1a15b8337058a1e2c15cc42418d7b2fc949943fc8076cc64c6d9e3c004e489efe297711e5f2dfc92b15d029b5b9652ba541ff037419f1ff40af7db267bf005154d4695d990cef823e1b04c0599284c8df6233a9ba9b66ab1c7a007b12a3a0895cab19af7cd923130d2e504e56a241ce1fb11978c31632 +S = 0a34ff5dd8d7ef76bfd56bd4218ad50c22cee0af0532674427c7e13f8b99b86e7128316bf2084c6477180283a7b3f4f4aefe5e0dd4aa136a2920ea70eb23b0e8b8b2c2a2c530f4efa1b6bc59d2a83547cd5c4043ce497639f609f05f3d4d2099b07d9bdc0a15690b7bf2da73def963eeebe118e59ead6dd89f0fa271645fca4d9bf220080a850649f48709bcbcc1cea3fce9618bf167e2fdb13a1ed50eea093d1070c5bfb162b054317f2e41bb3099c39d8e2c7b0b771da05cb7b7bd1abfbfa8 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a0500041486d9512b229032778b2d54e07bd553ebe7f36713efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 95e319c0df793cf1c1b424a8949b9529d6c1a0cece5f6db573a538b68b529a9810830a84d7c8a3b9747d2882585845653c3e179ec35befcc5a7153e96370467f9448ca1999fba2f801f65c0857a18f138f356233a5ce4d8d80c1243c1c2f518ce8da60696d38c21731c6ca23db9ffc99974d8777bcdf1062ad3bb198fdb64226 +S = 19ca086cb98c4770fbd6b70206c3896f966c968c1e5600a2348f3457fa823f053b45b75f0da759994d5d047922efa5184fd0499f57be607a9ac63a1926f8317e6845934a37cd58c07831a970d9599dcc15fb50c629caff451c96e2e2d7f9e3842e8dcdb8011adc8f5cb1c01392218d62285442d9b651b2a0369af3f99343dc8e24fe4f93fdd490636e78ca1b7ae73af5ee2bc0ab6a0fb42ef612c3260f62a1577c3b41bcc25e8feaed1f53e0d85c8155c9c38cf72385ae28e96831f891e03ad3 +SaltVal = 00 +Result = P + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 7271bcb91b18288e874f4c04c10a21bd35150b1813ef61a7f4dc29e4c036231fcf040abb4ece169ae5afc5d696abdbb2e943a7d0464789a4a2ecb1285e1e29d16b1716c2b3313b41b4f8be676e842f1b8006c6418ea0ec2ee57afd5f62124d6b90d3693710ea9f693e55c01f113c24e04385efd3b2a3932e07ae96f295b996d6 +S = 843e9f1f0a472be4a3bdf456281eda82aaaa08a0fab173f2086bc03f8b88c0517f457bc276ad144c1b53084d736f2077b0c05f451ed6544a36bd26e902592b384c6d33587a79f2023226fc7c52b1384bc6dc83360769014fb5110245b2395baeec2b3087f6b6eb5de706d08fa7eb069c749a56b91d43d1ccc8f1631a597beaa6486a618b85a2982eb32fb5039584c65f7f07e7c31663a06f48941878f1ef4cbb657f18cc85db6e9d1c87ff81fa7b1e63c74abda333de6242a21a43789749bdbc +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041cd6266f6d4d47969031bf6bd3800efb1332f5c75ba7d91394de470bb6 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 1484f58f6b8cff56ab4b81d17967dee7ef1eabeae57c11706fd2735ea6655145ac636df2ea1b2c409c6c3e31907e813d2ab123eaacd3089db4966bb00741c7c48ca5f8599c539d9c790cc27f1b79bc0f331c53036a872790e9cc4c851f343893be34dfec079c1c11481253e4a3bf55051048835ba50037f1165c5f0478a76b5a +S = d140b01f9d0d67a4b869fa67c115919268657f97d846886f07174fe6a30be909a74f1dfc4590ea356e349bce40547539e76bc9011ea133356c6f01b7739126c8af29e307966bfe39999625ef989faf817d0ad6378fe5dfcd5974089349d977c7fec62289b760b4c7679d41e463be7e3f996cf1f66e48cc004f5823b1f7a94524abd06ff35fc4f51fe6bd16dc4b43eb360ca18b4c4e5a33440d748dc7fb1ec3a8344f4e175f52479f4d93275e03890664fb3a2941187bd023a3a277fa840986c3 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 957018ebbf4bc279aff3a28f87510c01666122399490a4c300680910ed6ece73e84b0e70fd2b53362a63ac6a1456ff26f999a142e65524d22aed70ef0ae115bbb6f3e09f7c88add73c507b311c29c6117c4111b92d7bc2c7dd1532ffd687054be9aeb700a4297863cc043a6c079308cad8a19926d0cb25ac032677c8ba28442d +S = 10699cef91c348ab96ec062c0a98bacec04aed2bc2a806d8553258ebdc999abd59651e8aa7236e50eaf0a183e278a956de7ad6c3eacf7e5a2dc1e46a5fc1ff58d09db56580d924de5c3ea9863c006cd9f1556555b024a670c316d2de697976a3ce5d3994a758220cc83cffce43f7ce42942c3caad5a477c494d9581185c4e5a69f056778c77784a7fcb246f3edb1cf93bd416057d0c2ebeb36647ba8796b50ea569930132d189cb43be8405ea210b8e2266807620487791839d0e6ee4dcf9d63 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = af0272c90402a9c27f9cf6c9de652cb7a3a402b4695a0c58777fea11958fc0c51f45e6b857a6e0afff42905628b7aadf457669ec83ca80af5d16544f6a5e688e7a0818aae2e48b80146be3f77344b69c650dc28aa957dc8debf22a87956c9212e9d472664dc3927ee59e5776671539382bef7657820a083b499dd57fbec12797 +S = 90277451b160d24cd2df6e5e84e2f90a8fb6208f3395a305e299d5005656a153d27801084f7cb76fd0e4b8d118f84214416bc65446cf41fdbb6532c07b718ed82e34a8b5b52575e39de48e65eddeced22e5556d89103960a228df0efb047ae0e1569e579b477b38198045bc3f4cfe021dc9bccc33f10d3ea30a01c7c567ab22bd2d0bbec9c57dc990bf0ef19fb5942f116ed33510ff76405ea1cd99c0b47ac687d8c66f9540685d831302c272de04b4459951ff480f99dccbe3b0c01f3330560 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 2da2547df2b14d5f28bd5cd71250f55cd840a11e7bd799470e30938124e4dcb985e7a72325aca57f5690d59a3c759e1781ad1b6f4b1bb6376b94f8a2d88b9f465beef1238b4b51e1fc371059b4f08557de41609ec3a63b2df5b172c1cdac359b1880db830ed6790d847bb41b6209d3a356c419b3cac251b2144faae8ed8fc541 +S = 8866a8d6767eb3a88cbbf6075ce1ff085e541e3dd305915cfa2ebc94ce8d6ae9b7a76d5770bd4e96b913fc41824b59f3066471b054f744efe0fda0f12fd1413b755f0c1d93fa3bfd00dbac16cd6c83a947d71645aa3828b7452aef6b68a92f83dbb48a041ccf1905e10665e186d5aa85e502b36dacfec5b1d17ce9500caef5e8eb8b51cff080368b75baaee54886e602e722d2b9d04dbf05026624ec6fa772830090c570c5b8ac7594abe3ab312d46fa3294dd96ed9c2642672154240e66b197 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c9d529ed5fc99f3b9f2d3c3abce14aa723e6ee9397db13c35a355fb87efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = df8494995c51a92e651ecc6229ec4c5ffc54b2975876ea582233a3a02f9cf73207a94fe9e92f814d0f0c3c6432a4a6cb51924304af9719121bd612437344a14e6b5aa89d8b0d9aec77ffdd1373f77220268fd7a99e2c2c61953396e8f37ae1e894fd695d4ad33a3426607618f3cbf78904b2362e301d6b6c1ab1f637b627fe28 +S = 8474bb2649667bea417d1a51fcf6cf891c29d838c7002d7189b945b53436cc0b67175e910e2cdbd3e1855326f7c0c823a8b76d06b2ae1e0bc6a835a524401b5a280d07f09acd94ee745e1a789919128c617a683d1b145b3adcc494aa701c2fc5895d14ba6a7798c3fa51a04497e78413200b284a4b50bd82f0b7a1a4b3b5b3cae15e345844b0b7f155e48bc52fddc2a83648b2714daeafbd0c8c36de1165cdaa75bc8442b681b9ecc1cae114e629b13956734aef0ad11c421ebcc27202df5899 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420351b72799b9cfe54802309d2be3fd5ffc3377302cb171d35af0d486d4e664516 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 73a012bce858e0ae42fa2893a0fb1439a73a9c101841b28ca8c8bdcb0c7b497853fefdef782dcda238a871bb218f1503ec8a52020c0d5d6887da7eab05c7c4f226c1f8321911cf966bde63251cf3e49ff8c38ba724aad027f876ddf10c2642a296f2eaccf38b4e5483a3e818bab0ebd574ed314989a27594a2a6c2e44b222b51 +S = bd0512605f506b906f012de9f50ca56881c61edc331d8b36996b4eefe75b4751b6ff980194b52e19b82dc85fb3428c86905aea1e59e9db90018ad5471e29ec170f18b9668725a562caf850ef41c7ab871448a6f428db6b2ddf85fddf029dfbbff5677bd92aceaa9372f9a579a2f7fbfa8872f8de3f7b15c5095598d39b3808f99cc672d89171302a7e7c3430a1ae675cf3d1b3341f432b4c57a372f9be3a06970f2c4ee3f557b98a8e767db450ff29a491163330bb3438432c5dad3dd8dffbd1 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = af51ab7e521b64502702bd561e40dbb41e2f80afa95bd562bcdc67b3f6e36f86fd9256311e11782f33de2918ca64f5d083d02cffba209fc2667ca4a141ca60c02a7d4559c7add9696e6db9aa4659dec2a96e20bacd1ff8b1a4a48ad20096e383fbb97fdf96190e67a05877f4da461ef158b263c62a806b973cfc222f7b6e8037 +S = 6ed6b46b522f09d6c1007dc32e593a2dec403c5f318e9ce0edbbb2ca6b9b05803ba43c1828ce2fc0e2fe8feb4f80db80e1673e111f204a6a009c115f0a797006bdfc5b5258404e259aa0f9d72957d01f92b756daa9981952dddb0bd1b1aff6caf46ccaaab62a15f52c79fd663ff64b94ab8428c04780efe11ce1a210acd89e63a26f4a48b9e4acf7c327521a9654ffcdfe03c6baec5cc8bc32731d6a9254302a69f56bf43ae8b82738e8073f073dfc8c386d9adb0f1acf16e59710e4e519cb42 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = ae4dbe3079ef09f963a3da04099f596a6eed3c979d798eff8f69af0d4eac9d5c5bd6712a4d2b2d0abcf9b4d85d2c1af26e1c1ea555a9f5e6848a4a439fe28219e1144406bcd939a1bf901069bdd5c6fc2c54248acbdf898888bfe9a9a048160a08b13eac0c22b528360df59e71c2e4ef6e3e552c4744d04e62b096279907e098 +S = c7ad03de788a43496f2ebed7df3179788360095e880785bc5f9135be256cbd7693ff1c47d7dc74e1e3f318a533ad50850336d64cecaf1b6b6a317332810d433362eff2b03b6730df4a04ac3c69e18e752577cf8ba9bb0981a2c6cfc2178fcaa3bee1957cf10a74e87541a3311e40206457a11efcf76893f59dc78cde650b0571072a9af5500dc76cfad2bce35057768b97046adb84a67efce9d9f569839e3f36541cf0b24862f8311796edb735476eed85d8290619b56237a89028c92b3eab48 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004208aeae1f557c4b574127603b7da392e75ad6df1b94d840cff18ca38033d5cd0f4efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 9245f9e8a7b4e2c8744d5bd42ebe68ca32426a5cf7c5ab78414938cc9888ef8af9dad868cb5ab9ec1444e4e6eda2543e3428f8ef805c4f545afa35a3aa96fdb76f83bf12b3f4f322bf613fc38b2c8e0678856230418b6b062fb358488d6eed7c5c0656ec48c9bbf2da6a1473eea43faa68204f27239928172a3e49c52b58e861 +S = c9e9152887b5111f721aced7cdb0e7368b0eecafaa1506ccdf35c378b633937d08544493a1e8aa84b5b7f892d89976f2ebfd55ae85189f61fb280ebfff5a01fc2c90fa4896ebdc3725ec472631e69d35fc9d5a03447941e7befe21a36ce5cad72088177d7e54cffb60dadfaf3800ca38e9751df2d4fab7738f31d82a944e0f3bf652197121c4e74ce5f170fed950f7a03906e75b7fe12469fa4d44fe8348d5459bc5f5f13aa694c12ac64912a20d694230ed95b75f3de4eb0c3c60169695e94c +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = bf15e4f37e28f61a35be4539f17d70c75d3591c19368b84c320a999cb1858114f3008faf1be1209ea1908b33a67e0ffd84670935aad46a58a7e36916844a756b579a6e0c15c11404a8d3c09f410a5287f00b6a2d726adb6a4a715c67131d81ba146aead115d0bb94710e4b466d2621acc8a91c729334f1ca433bdb5605058d48 +S = 897dd26e35a3833b069c14e173d8f90443d51f3c8867457980f0c20420568290a2e239642fd21e93778dfea2bdf3ccf72c3ee8f4334394238d52fe577d1d050dd69838626922ed9af276f888356349fd1ca8e9c17d615b9d3cdf86e86d01eebbe52dbd26c034e8a93fffe7cbca27edb1d03b13643ed4ad122400d4f980ff7b8a9864d39e9fbd5781ea4d21a06136b70a90fe2bea2ce142334403bb078095f1257df2162e9998a7268d1f05f4c483f726b9b0cfc132023c643b1b0b04b6d88745 +SaltVal = 00 +Result = P + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = df8494995c51a92e651ecc6229ec4c5ffc54b2975876ea582233a3a02f9cf73207a94fe9e92f814d0f0c3c6432a4a6cb51924304af9719121bd612437344a14e6b5aa89d8b0d9aec77ffdd1373f77220268fd7a99e2c2c61953396e8f37ae1e894fd695d4ad33a3426607618f3cbf78904b2362e301d6b6c1ab1f637b627fe28 +S = c7fab5c4083fd43b67dcc56c10b5f9a4793ae49411b828512e4930765f496e313995b506e6b2ed4ceb29eb2b9a649e18a1c9f22fa5c89f7349bd7d8e967c3169fdd120517834c0aa355b5bb85b13b0c1fbc2e915c9ac8d7801c37cfdcc45376d8915ab57a67cb39fbe3c976e49e3a47e2312dce0b27ebb2baab9214a7af25482ca1f7d9baaca22ab73deca082b271044048505257c968b131f5dea33c1d02bd4ced74b6c0cf71cba31d989c685e9291789d2a5e906c52268a270ec8206e3bddb +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430ee9e3e985b715474d343f9823ce7f3fd430e13cd9dc4d9117c1a7f1c87f40e16a1012f103c90db1b979cc17934b20756 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 73a012bce858e0ae42fa2893a0fb1439a73a9c101841b28ca8c8bdcb0c7b497853fefdef782dcda238a871bb218f1503ec8a52020c0d5d6887da7eab05c7c4f226c1f8321911cf966bde63251cf3e49ff8c38ba724aad027f876ddf10c2642a296f2eaccf38b4e5483a3e818bab0ebd574ed314989a27594a2a6c2e44b222b51 +S = 28e465b1d7e5e227ca3af797f7f4606a4d78fa8037190e52819b184bb42237b64854c317e08bf3e6ac2e544eb58e0e318682224623f8912682c9afe0e81e7d9f027105c0da1c2b5f27fb24089af422f559ba97839749bcf9e968dca0e58213a0ba53547934804a1e10db9da4464ce7800e5613c89586277beaf69edc62a3e8ca2a8935ac4d0b4d65e7ebff4358be37102a70f327245475bd6673c7d092505f321cb600f6df917c6873625e5d3539d95b94be06d39f90eccb424a9e5acb27f0d3 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = af51ab7e521b64502702bd561e40dbb41e2f80afa95bd562bcdc67b3f6e36f86fd9256311e11782f33de2918ca64f5d083d02cffba209fc2667ca4a141ca60c02a7d4559c7add9696e6db9aa4659dec2a96e20bacd1ff8b1a4a48ad20096e383fbb97fdf96190e67a05877f4da461ef158b263c62a806b973cfc222f7b6e8037 +S = 198f72795be3be9f70828fcfa6fd2eb286f4d996153953730f8195669840b685b1854ebd54f8d1ae8db487802f8c6978197822157eb45c8085ae91f11390e0d8910f2bb51d1efbd743e2e7d7e16c4757a67a666c1e6bbb90fae924550847b68e41bb9d8b58b376c70c075cbedb2875bd7789971d2281ac3a591c7361030dd46afa79ef20a32f68764d40f4f5d689f3686967e57f1b718522a61ebf35e194219f9b044aadccdf0fab455be9f86a651bd9eebab4e8c798c9156880b06f12ca6b7f +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = ae4dbe3079ef09f963a3da04099f596a6eed3c979d798eff8f69af0d4eac9d5c5bd6712a4d2b2d0abcf9b4d85d2c1af26e1c1ea555a9f5e6848a4a439fe28219e1144406bcd939a1bf901069bdd5c6fc2c54248acbdf898888bfe9a9a048160a08b13eac0c22b528360df59e71c2e4ef6e3e552c4744d04e62b096279907e098 +S = 14f03b08b6e55a8aac770701ae964a627e2c35a6e5b0a086cad74eb7cfd5f30c2b481b9a23a03e61f9a73ea131ee9e0d44ae896fd815595adc40a7f719e37d453c6c2ac99f5e76665894fbba102102e31a4fbcc172d523a0feddf5f0098949041cf5c6dd729882db4a3104062f37fd0b51f990d180fd58c2894d9c306e001878aceab5ff4376b98c65864e2216702b6afe97686498732b6259a85e60e56e184515d8326d7ea98508566fb6ff79e771a08904918f19562d28d6ae334b9f15104a +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d060960864801650304020205000430d641c0a68fa8724ce04f866e4c8d232b9643ff63669e3ba6b030d0ab734710b9d6ae8c7703bf964d4b827d2098fcb79cefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 9245f9e8a7b4e2c8744d5bd42ebe68ca32426a5cf7c5ab78414938cc9888ef8af9dad868cb5ab9ec1444e4e6eda2543e3428f8ef805c4f545afa35a3aa96fdb76f83bf12b3f4f322bf613fc38b2c8e0678856230418b6b062fb358488d6eed7c5c0656ec48c9bbf2da6a1473eea43faa68204f27239928172a3e49c52b58e861 +S = 7ea67611c9dec51c441cd3b5980e566f13e1191ab9acc5885d12e04c231b8ab7ab1bd388cdfbcbcd6a8c175d50296483edd4415ff4220b6af620e3ab5d2561c0db009e2ed7b094c8ead105d9067ce25c555cd306f52f183efe0bf3a618c5d52b9517ea948cc1a3dc43cbab21dfa74a44db4a34f8ef6aeb9e7fade424122a96f587a5ea94dc9b7399485d2bcf255826389209a89d5695891bae7bcfb22e430a3f5324fbfe79adc7f7fc5b143b86518022a96902fbba5a39275650d8028d3bf144 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = bf15e4f37e28f61a35be4539f17d70c75d3591c19368b84c320a999cb1858114f3008faf1be1209ea1908b33a67e0ffd84670935aad46a58a7e36916844a756b579a6e0c15c11404a8d3c09f410a5287f00b6a2d726adb6a4a715c67131d81ba146aead115d0bb94710e4b466d2621acc8a91c729334f1ca433bdb5605058d48 +S = a7395ce62131a5eac115ea950fe60953fc334cc244b13b159720a502b7194c9e65eb665e6475e1e19e462b735496d65fa8a5c16162d97b11656a85b43fdd4a819ae918d79e50e51ea1e9f5fa92f467410c61d50ce2e3b61f59be2c88cfadea890b71edb70fa87e38df81c38d315b33fe4ca4fdbd5779052c16eed21468a03b15fa7a235e8f6831ff55fe2eaf79eaf466a2280eccb8139dc16c8f296f0e79a1bc4784f37e6550264d7e26a8507b97b1e279f644a29c166be2c761e1ddd7cb6611 +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = df8494995c51a92e651ecc6229ec4c5ffc54b2975876ea582233a3a02f9cf73207a94fe9e92f814d0f0c3c6432a4a6cb51924304af9719121bd612437344a14e6b5aa89d8b0d9aec77ffdd1373f77220268fd7a99e2c2c61953396e8f37ae1e894fd695d4ad33a3426607618f3cbf78904b2362e301d6b6c1ab1f637b627fe28 +S = d1d6a615340ccb1504625ab056d09a95f42836bbee98bbc1ebeeef5296adc55eb8159a5dccf5fbd9bab8854bdae4f9c73379881adfaeab1bed26a544f4b56067d1c29f473ad84486a4e48c51354e4b1a9c9ba1aa019d1c75c277a2dc5df6ec4e112312c93e5652dbe107270f02805250dc77e833637c65f2248e2834b7cb62135b43730a54e0782822fbceb33073912728dbe0da834342ff7d519404c1171b347b96a4df6bf794634247e4b15b93d7929a0e1852dd20b6c88b4f30e0a18be8da +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d06096086480165030402030500044027c454d298019b1b6718f4ebbb3e2d115f3ea8a214cc95367bbe80783dbc781438847c4b1508b6010de44f47ab6e213f32e7348b8e6d6b4f85fbfbd3b4c6e05f +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 73a012bce858e0ae42fa2893a0fb1439a73a9c101841b28ca8c8bdcb0c7b497853fefdef782dcda238a871bb218f1503ec8a52020c0d5d6887da7eab05c7c4f226c1f8321911cf966bde63251cf3e49ff8c38ba724aad027f876ddf10c2642a296f2eaccf38b4e5483a3e818bab0ebd574ed314989a27594a2a6c2e44b222b51 +S = 3a24d99406cb5a02ba7a403dc0b5b2bb87984a3feec115dfd4e5531993c391294aa226761a02affab891886acc356160bc9543f2b722412392dd5dfef65688d8084268278eb04482eee60f72a34b30376a8395f5f3fd27dd56e7a8431f2093a8ae93c02674409c492b52a1b0c53923672db546c85ce5e2e160c94e78a5d66dba5c398b97585a20f3b32ac35a4216e4b93fd85c3fc5693fff06eab4b9e0495c5ab0d93bbce6b3e16bcd9bb458b2d7b4e30f9f4a52f48311a26e3c0e9ae30e4872 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = af51ab7e521b64502702bd561e40dbb41e2f80afa95bd562bcdc67b3f6e36f86fd9256311e11782f33de2918ca64f5d083d02cffba209fc2667ca4a141ca60c02a7d4559c7add9696e6db9aa4659dec2a96e20bacd1ff8b1a4a48ad20096e383fbb97fdf96190e67a05877f4da461ef158b263c62a806b973cfc222f7b6e8037 +S = ac7598c1f1f9245d59b443cf44e1eaa00f9a213ba24fffe3b6051dd0d9f430669edeab9157371eeda529bace4e66f31f272b210b5b9308d0dda403385238d758de9d2099c516e39cba18a1552059d9eba6deca27db71e766ad67b9db321011b727619bb303df82bdbf029649300b03e0ebc3208b2ea8e290b670b2796b4ea12de9f07e6185fe508548d2516ee1f8997394079cabdb6bbda455983169fee7cca71eb4c5841c27c37762b985824134fea46bd2c95d7d82abb66894c6671ddc45d4 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = ab50f6312f99e068e4a76ed88efda9b0acf416b30500e798843673b1450be4ccf05f2f5746ba4ac7f9d5993ac15ca95aacf22085b676f42c9984dc79e63f0435554e05e859251442f88679b9da474474a0553b6877f916c1ec5aef830244f47181275f2e9263a8a289c2f89f0246e2c42f264ea27013b51e24bf9416c0a01a48 +S = 6c0b09fd6b371212279378f8e3d91a4861c63c7353e5480643774821ac72cb3519cfd77e46c6edcce92b796fdd5a511199e9b870087fd9d815e7d8c8deccfc7c229b93a038e202e60df022d0a966e6616c67a447cee59b0b3ca206e9e503e928dcb33160b9b21897e24d860c7327e83f15ca41449f7aea16a3e7d83faa458dd0f27117e68bc279367925a42ec8cef69cc1bae1df16408ca60b8f1b9fe9f837a1227153b59ab2b3707c1e5cffd79d7c11a31a81f41317f012b497e34d4b3bb962 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d060960864801650304020305000440c4765be0d27a4bdb86ec440bb5259aff46c9bd89a6870bf5b87c3755ce45d780c63282898f959c929d9f144143a038c36d4d0448ef8c4663cedf5cab3d59bf0aefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = d3d03ff14b9e72bef1c6e7d29a5bb8f0ce554cf3cc867a63cdd0f1468d94d738086db0be811f82d8c9ca36d5be64426b126585074ec4726216237155ae4782eebdca24c35114758624879ada1efa61651a692527edeaf30aa4e3eaba0e7be8b67b4e63a8c26594f28965db89c0065f066fc7f5fab2e143820179251cb5194fb9 +S = 81664625093bdfe332db62e3c1f5ba000062576d95f1a82dbc5043eaa267d7602c25cb45759ae8ceb360c017f9a0c4847763e25206699792af187294514bb214a453730350673bbf2feb73033a567d4d11a6a4a13d2d1d79850bd71e4ee9b8b404d2114f505ca695a760be6b1a784be63a208edeadbd1a22c86d8ba614210d9b01b89f70243749f5be9b43385ba94ba0797219323bb1817e5e3bfbae02e2e360383e333b27c32b6685e6b9545a3a6c7742a7e0612f20bfff18907c58f3fe671e +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 +Msg = 4ff4d6aee37bbccf415b68228612f69eddea178398c0c13d7f0a258b6719e2e0079b780a0863ff115b6d1962cf1c252ce3c7b50bd87442e40be31f1082cfacbcc570cc8fef44998e040f563d8521a40742d7f9e070644f29fbd119d41e437bc8307dba87c1a5f20ee54b07fdd0a7ddf7a322cc4c86194ed5f7ddfb2061feb8cd +S = 303e5f73eb2125488fed92692fe597994b86e4189ef71152bbe277501866f64df9de78f3d11d74c6aa48a916ce2759012ea86a862966a3cb78d8ac12d0d99d059e8cd56e83c0f5198ef7248059510687e3943fd41defcd58ad501976ec17fd1c252c13a177cb99d2ed831279d6cba8ca63ad0929eef4fcc85c985bc449030a76aff7a2b389d23b89471e21907043eb6c973ed375d85871bcc9203d6c615fa78a066e7fc5ac9f8f7099ac22d5a8b26d0608df22ae0cdbabeb81bc6f750a61f5ee +SaltVal = 00 +Result = P + +n = d2b6c8fd44e7eb621fa6685fb62371872b5e8408af51bd1b44c6473823402418a26963b98e6fb191cf74175e64132ae6cd101133fc002a89c10bf7739eb930b9c067b52570842395657f927434aa3acbf3369dcdc3990f77cbf22939ddd5877f09c8aab818b80aa20544b6928fe62c78795a4160aecde6ab454db0dcdf1d6c13522526c5ccf82d429791059306f02cdc18c4e580ec6c2da19b3c6de63933ebeac79010c73df95748d987e96a0f8ad523b5014b33423f55922aec2ec23b9aa22f + +p = f260d143cff1e8e0931765da8cb335c0206bf7fd19aaf8ff41e762992f2bb0a660cd65f08a80fe502c9125166a6927aa1859a874159796fada835b48522f5795ed1f8d23f05016358ff908b0dd638bb7ed12c8b80b46aa858d52c77bb7fc0ed1 + +q = de8e674fac0b7ea32d518a22030fd10d4298a77974db8febe195a4240dc5373e8161baf8ce47dc4fd076f64e307ea6262c35b9819bac4f142b613973eeb6a62a15a2ff09fba9ce4db7186969af925ee3acb7d3be7a1f9c85358216640fc1e0ff + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 5d7f76ed239a1a5d00c3a4f4da964ae0bc409c43ce9b147b859aeea617e8396532cc2fe1ed50c20cffa2772a2eba778f0b3de4aadda26942db9315009e96692ed5ecafbe3bb98e8ec666dcea2144b3535d72c77ee400f6a0ae5421e9b7cd3b4eb0a79f8cf41fa76abfd77a3e9a7b25b21aa5eec8cafee41c66a7bb6a4ad7d74f +S = 810510f7e41b63d4d1db17ccd919547d021c0148047ae92fa3278a1fc7d2bcea796f6ad6b927df033302d5df46b3d33af70560c01bceb46502552a8b6b67e0c754ab1bf58f5ca9f96397aebd5d852c66865c399032bac358e7a990ed6dab9aec27e664a08c505fce3dca4bae2cefd8e1b35f6d4b4216cd6572f139e4b520188e8199c9e3809938ad642123c466e0d59b172217ad290dbf74e2ada78c0b7dfe639ee88caf44535a734794406fe909922442b1bcee8fa3a8e31bfd665dd219c46d +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414fe4eed9d60746feb5599bdcf486716a6a04a0e69 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 044138280eb07cf03ec9747c7e9b89e0a37850b2fc40ba6b2ae38b1132210d13d194057510f1e62c178b45cc46188d6082b8f499cd33ad2c1a825f755f92d760eb44fa89fab8fda287cbd81661def7eb81da33ed9b700209f3a6eaf7728f3c1cf959feaef58e2919349315a1f775314948e4f7f48d801fcb5e5413de94a0a40e +S = 6af0c3b45ee0b0f5182b692d5703921e779bcc5ec5e5f71fef5c480a491acd10e61166ac2b40e4246fcb28aeb5b8feb870be4a4efa13695ec211e5f603d86d33b228a41069003d18841f48aee2f4802f1dfe95caa9a3d89e5425ce06fa4d17ac2e5fe4af0e5a2f86e5ccfa21c5d1520290b2d4d4ca5096486b6012e302b2eb3cd9f906d36719f3a19e3c124969eaad2a43c2e30bea835dcad93ed550dc3137e59fd891694274cfd6a2522600c661dc496f4e4de5a58aa51afc15834de5c97e96 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 8f662067a26e81165e23ed70b145725faf2c591491ba4d9ffe8fbfbc8a7b88f07d39d0d5d55a2fb28e7f134f20cb62084a98601f0e69d257fd2064beb47248caa79720a71d461ed07ce069ddc7ecc39b65c36a62248c3ba37d6b1dc11af69d2295e9d685831a9496b1afb9bfad8edf4288153e85db0cd0ac08d7b46dc2f0d120 +S = af16b7a53f57ef673aeaf9a17727836d00e883352e7e2109911dd839ab23d46400f140af84d4cb4a5864165c682aa85eeaf4300e74b94b4f8fdbadbec540e07056b55fffc96a627939928ce5fb61e119c94f14719a93fd5f3a3dd4a8754a8bcaba64afd5e63bea1a793d420a2b6975603f2d4597b26799da0240fdb7d8b0e6e2896f63bbb46526a2f651ed17deda3ab3b43622e749bb608c6d30d41d7346f9338bbd768209e531a17e2a92b815efd222049451785565117f39812de4c6ecc65e +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = f93d6cdebcf190ea6ab2358636af5cfe4b3a9bdc1bce160bf350aa3cd3956b897e255158cd3e2e83481ce3b6f778d418764f992d48e4f7fb6d080e6b3799d3f35949c17241a0cc5ba84597166779e6a38ce45681ad944cce7c432baf9cd8caf2b33125f2c12052bbb0b3b76f2cb97be9b4813a9ff1e5fdcd478769d0ab5b36cf +S = 1e076b3feeb281e5ded58a886f653c59a31789050df263bf06401eabf4eb79b4b516350fa63b06c4ea8339190ee9ec30c3972f0009a892bc5938e17c0ad3502f5b6ebfc6e90281cdd94ee5758a2747e05d2523ba337301d392bfc6fe57890234bb1e485ecb0c2eff55c6861100b2911fe594e6db29ed773da026bea1875f334a2de2214e656f6bb25b6f84ef5cfd4158d27642f84579c1f5e185bfbe2948c2ef26e6610355e190b4c06143f487a68ff15da2f7acc9e28bbae89e9ef0c362d63a +SaltVal = 00 +Result = P + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 6f856225ba8dd27718b7c684764f2a18c19df4dc4bb9accd71a12bec7b89a337c372dfd91afecc9e678339a9915edb699f8a94c91e71f4a7c30101885203338abea8c39a926526e68f01d49597ed4db6cad35e77ee71a09814a8431f78d0094caa4f95cfeb6ae639da5b1fb150a389e888a1da4f8364b887aabe7918b6992d67 +S = 2491418adaa343b655e7a3e762737b02ee904d6d79fb6ddb9cf2043b671de59e5165f2898bace269f0e65f3e754aee71a5fa596a5a89574afa49818c7a962c38e1577f2302b75ddf53fff93ef035be0dfe14a086a27ab5a2e64808c9abc9007cfc748fac383c9c89fad72d89044c49cca11cf761d7d8e506920aeba7e7e8f187aa287c6c8878a90fbded8489789e2742a8386d8cb21f9d0b51123a5f78de74656107e562ebf50ace92da2437ed325629e66e14b573668ed6462a8ea21e54a543 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a05000414753938c49eb8f7bc120354dd8ff2177dbe9bb916efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 9fc80458af5f2489a910779f7b9d078b249a68a276219af01ac830d0d4d0b2ba089f415b7e7079eb624a9cbb8f2eec0d0d955829d71a5bade27322255ca5eddb3178b7f1d42919ac3c606c132d612eb9b886a6d705edcb9d506e63ca32d0687b223caf403bf1cc75403a30d0dd9d94362f569bd38704b2696ba13be8deb7ec40 +S = b23c38a05b861aabb41227c23af9d3b6e1767605cdcaf1627875a7ce09f99cc4b7397a4f010a3bb2d8a9c9765b9877f936369d761a13dc3c22c0db84a3364661b5c7fd39e6965e43a728069daf89612dd8dec3dc9142d6987b8345579d9be7891d315247955f70ba789d3650947de9e92948e049696a00d0e0f6d256cfa24128be180ead9af648436c1cd21d0b396d70c27c94ad8c8625b6b3dffbb3ff78c475732203c8d08a3f99e7dcc86f1c233131571210e8135a29565761dc94e77bf484 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 5d7f76ed239a1a5d00c3a4f4da964ae0bc409c43ce9b147b859aeea617e8396532cc2fe1ed50c20cffa2772a2eba778f0b3de4aadda26942db9315009e96692ed5ecafbe3bb98e8ec666dcea2144b3535d72c77ee400f6a0ae5421e9b7cd3b4eb0a79f8cf41fa76abfd77a3e9a7b25b21aa5eec8cafee41c66a7bb6a4ad7d74f +S = d1b5a7c9880f3b076d635ce4f881de6c715d0e2ac85fd08ad5d4ca93f2b04870f7264bad5c7dc9f38046b7ce0bbb4fb4e6279571533f61cde6d540c6e6bf69e4869ab76a563f30cc6718cdef849f76c75aea4c9a3068bc579b1104474d9a4849d9c3db49fee17afa5281fa7ffb848e9b33835e942e89c04e291d123f5d2bc5869f076b550dd8c04d2c2f29ad290ae294ab3d34ef54f5148b256f50c54f14dbe4f02e2aef97e39a90431b774142b3dbaae385615323badf58f309e70a1084ee59 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c7c8aa165fbd14e4361a3bdf3f9b6bbfcbc8e14153c901f8e2104975b +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 044138280eb07cf03ec9747c7e9b89e0a37850b2fc40ba6b2ae38b1132210d13d194057510f1e62c178b45cc46188d6082b8f499cd33ad2c1a825f755f92d760eb44fa89fab8fda287cbd81661def7eb81da33ed9b700209f3a6eaf7728f3c1cf959feaef58e2919349315a1f775314948e4f7f48d801fcb5e5413de94a0a40e +S = 6883e11e659c46bbbe5a9b3470adfcfeb546bf008d1f2f272e2b3b957ffb52f6d25e0a1aa4facdde72c103566cb6b898a9f059f17b895ccca14aff8a658591998e8f106dc8624a48158e932034f9f3fd4f2692e37ab8a31d02831641d0518d4557f2588f394eac4a54510b4d4397cca2f55e7b8e08f7fbcee8a9f1c60e4f6a8fbe30b3b29bd7492aea116701187d6bcc9c91979de68b52e7c6d57e4fb9d5fd6526497be575ee861bb83e05f5b51b9cd60276d93e6fe987f4240c610d94aedb49 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 8f662067a26e81165e23ed70b145725faf2c591491ba4d9ffe8fbfbc8a7b88f07d39d0d5d55a2fb28e7f134f20cb62084a98601f0e69d257fd2064beb47248caa79720a71d461ed07ce069ddc7ecc39b65c36a62248c3ba37d6b1dc11af69d2295e9d685831a9496b1afb9bfad8edf4288153e85db0cd0ac08d7b46dc2f0d120 +S = 0e53008d7626ce138c6aff6c40eb86dece247e192bd5013880e759f96142d22d18abb6f1701b88aa28d53b0c5c13b91a316e79373a37ecfcd61df7d3c34b59ea36eebe0c6864ef63514e504a8c796780be8c2586f1a2eca3a45d45b15c4c38f94420ef563efd9fe2d8c194d01c7c34cdbd7f89923bb39bec9e8ddbb1a282e1ee18bc9cc93ab42c2dbe58ff0927036d2a66e364d88354571b75fd11f131076d6fc9c75b810b522d2c18faa4a6332cf82122dfdd17f5efa030fbb50177f97c9bf9 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = f93d6cdebcf190ea6ab2358636af5cfe4b3a9bdc1bce160bf350aa3cd3956b897e255158cd3e2e83481ce3b6f778d418764f992d48e4f7fb6d080e6b3799d3f35949c17241a0cc5ba84597166779e6a38ce45681ad944cce7c432baf9cd8caf2b33125f2c12052bbb0b3b76f2cb97be9b4813a9ff1e5fdcd478769d0ab5b36cf +S = ca58ea0da7afc7dd4a1d32ff168a03b478f296dc0f6edb2a0e859d85476f1af70d21b42f0af6fed26cf82604f8a2c5d87b50e5a5babed6d585a6a84861ae56dd2654c4884af6672ef57c63d8b03e5d7cb8ea49e6e8b53051cc64b366dab0b93fe29dfbcd7b9a0b8885711bd103844532f08ddc2edea7076e36e7ee25eb592bda6a4f862af008344117f5c51073407a8d230f2ab5aad9c981ad10842706b502f4c984f2f969dfb5090678b602b4748004984fec3a39779c2f5ee1b02c6eb77dcc +SaltVal = 00 +Result = P + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 6f856225ba8dd27718b7c684764f2a18c19df4dc4bb9accd71a12bec7b89a337c372dfd91afecc9e678339a9915edb699f8a94c91e71f4a7c30101885203338abea8c39a926526e68f01d49597ed4db6cad35e77ee71a09814a8431f78d0094caa4f95cfeb6ae639da5b1fb150a389e888a1da4f8364b887aabe7918b6992d67 +S = 1a524bd769380e63ba31ebc0adf908a5c2b657b03a534da42eae48f044ecd2bb643f2ab320b34df4ad0938e17044d9e8a40c0b50d696024e0f717f19102f82854c626642da58c430ac865d3a25299f5d8864b418a172b331734db2efec8e44d082556d7d37731e4d4a317a22a076caf9f9e9854c1eafbdd57fae1822ab268076126f55c3ca52873885f9be15c0308210465b78e34335d6fcc569c8e4ae0f65034c0d8ffc1f078983e15e4b2bd7f46a0bf41c8ad7fbae341037c2bc87c2248060 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c3634827aefd0d0bef3df495c39e6d596907496b91679e2bd96be6542efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 95d3ac5ad05aabd72a1c331b0bb6f75ddeaef4f4b0b6a6bdf92f7bbdb9ed8807c73a7ae0661dd0221adc48debabf9745c5175dc9f97f587f2262d8c831bd73308d26f996ae0eab8ee743a70383b8a7211489eb71083a74467d40735957c201b08fa010c4cdb5a2e23a5939d28f2a8eb7730d8536036f61dab2d134b753839a4e +S = 15893719e5cd0ceaac13914028cbc46bcfa00171d18041371ee945c546f10a0f212231090f4ab7f490ac852bec6ba820997d71467b797ff9a09af565794a85c15e3c10aac19b91f6a540afcfeca49f1660a788c2ae040a907146b4f6179d808f96da06f15daa18cb3be6b2ca0913fa91e966652a29360dc41e50c6c43ea5d633532d264b0ca09987ff3b0cd1542b4a6a48332d434ee3f02f9e0ee353d2acf260a3ac278de0ba65677b44911ec76071f74a5ebfeb33107a01fdfecbbc4645baf6 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 0b9c18c93a8b1b8fbbd036c2d5a6869c2c326e80e613df300d3ad74034fc28cb5e657b641bd0944ff4b4d8f209c10c86f92c5f120247ab9a6a54f8931d9b429b97ba7c67043dd4fda66e3923786e1a1711857180cab701a52398dbdd636127467f4221ba3dfa62ff99a6613e68d639b73be6adb2868c69b902ad8a044f756135 +S = 29dff9f009373438341a72589399904fab9b900a2bc65c371c989dd60e9c825dc222d982d773cea97be3a3c378956a91240b23eb59a4cd5b78d44fb948bc402db68a8efc3d9d7c48b55a826bab47ef4b605c0ff33a7019d8f1e71a17b43a6a72a57889157c15d10d65152a7581b8ccc0c09b1dd284d9da78786853bb8b88f4458bf178e05247713ed13a6bb7080827a1f4cc85de9a8b094f9c6edb71e8e3166d4907b786fc64d97359907661b6e63e6c1e415e9d31aff0e43a47e5830fcbd26e +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 5c27ae4e00a9253b8e43c744e235654a6ff72a1cd37acfe0aeb10fb5b5505b9602d4ce81aec363d9a235660aaa93286bcc9ff768d7b44de03e4f48cc27cf5a22c07942f9d2bf3bed98c273c5d115be5314c48c9c64951939048de3fd8cb661d83d20f2fb9226143d17f2d6be7e4490caf06ed100a1a499b3a772c8900c8ed781 +S = 36b438a2420cd0683b040001f926e499992d21be6d6315302123efc80d63d9182f014fc8e8cbbaa70c5875f2e7e7127e5925eb267948101ecca130bf0846f2c4aec394faedba13ec6cc19e476cb31c2cb025bb188127fe70d240fed47d674f2d5b2c3b4660b08242ebb5c005bd1e836c908121f0e73dd80a18668b79d05783c521d9913768296b057cdad7f408394d080e46b74e72c6d337b54c6ff976af2eacd7ce51f3d2432f3ccf7b55b074cc2817272816525b91264c96325f3145324cea +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420cb6adea7aa43ed6220f5f0c4dce57facddc4f77cd4e9072b0468da9bf104c1bbefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 8bbcc23dd3ea4ba9c1d1c8e052be5d49e1f358c657050a3b9e83d64a59d88761d273e6f733258d12facaf60da72bd798b723b200d601a7b1512e8ef9ca10420e2f2d3f53ed9470d76079421e8e1ffd2516fb54a063163b8625b3f8cf02327d7d8834f5d967009dffdd25d59c716177f7e4c2672e650b6bc204593d566906dfb4 +S = 3e116c20ca4dba97fd0804d5ac89cf75bf53a71c77af12c2301a1c093aa269a9074f467c57727a5c0b17f18968842f98bb11d8b4afa9a9ba193c0e8f2d2853a19293c310ad2a5e792ceafdf307959a50fc48aba8dd911b367614b26b1a19ef13e37a4e3eedd4229174d7e6184f6bdc4c5d24397545709170a72fe202bfac3695373da28abf90aa1dec9ce1ecf4afa22016c2b6b65e65a5ffe38925ebebe49e4def0133916b4c22d2225122e1d77703a716da7cacdb85d9863d53c039da1a1c44 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 676a410de221dc39a833bd94dffc5b06dc4ae2613b1ce1452ea9434115a4813a4fbf1611506e3280f4edb24513845083560a176549a81b04b1df668b1fcc3599c5ab65e6899b282a58a0fc3abdeede74b265ba5eb658278a1f9251bdb29b364f713716d5b43024fe7b5582bb03c36ca39763b495a9b46e9f21cbec1ef598ed27 +S = 34f5337351298d299f64828163e2c8edca0bbb1e80d8da4141c3aadd5827d815f32ec5ec6696679580f92d1e97ea7cb85485566f061a4eca830c22f01f9d952d33c2aea8cf7d1b49d426cfe029f2c52a2789e9031e015ad74c7105d43b9fa603869e850c6be898830ce1a921430cede5f1312de7bdd4edcde835f32102ec28628ca49b5009fdb5ac03c6ad077c77f66fae2779eace6908c4fb5051d82255e7e50920afd1692f1c08d61d233f47e8a7a1e342d39fbc8ac527d96a622a2812f177 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = ad82f5bc35d0995edf617b3b05f4ebabb0444cdb678980734541a1754f30f26804a615b735007e54167127a09603858fecd8bc0772b60f8ab7c39a15cf8c4348ee4ceec6366cf0dfcc46c66d312e08fbd0b3982dd3221f5c3b4cba803089f05395fde8b3e01ad8482966c168807f5a37845c491332d5992ffa66697d1830e1d2 +S = 8dfd4ce88f22ca5c7faee59e9c0c319ce22581108d1f333a4f53c239a840db6cbd9a18d1be3d211bb2a7dc69d1750aed173a50cce78d4b8ae804525f5e3dee05c98d9e1debef27ac43dbd8faf87607affdd97589995cf062c7f3b5c1ce7dad7c200c3124fdfce5f05e0044ea952e54ab642c47e0bff3f80cf96f0dcd08baabd11152b8741d8e700c27d805ee6edff11f95b441a24d65bccdc6949b91baebfaf249762f61593974813bec018929b51cdaa89df092b38422e2a82aa7cc8a22f971 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 75025b7ff7978e537b49fdbc59a54ce3e8313c96885ecce3e6b8a5e67b60b4df56bc19871c6d40a54d814ddcc8eabec7922f4b48d362111c2152f0b30101323fab596d0c0e1aaa0f1417c6c127a2192ef44556486fb3b28217fd499a7b09bdb6fd4120b3d68814ba5a7230147db4a63f97d923416437f73c4f227643f05f9e6c +S = 1f435cd0b2835f4a895c2a53c4a9cf8561197c90548881f3150b7f2247ce7c1f0fba20dc1b3a265566b2cacd6ac66f087ccbe11776168f382ca2cf79cf97420ea665c5cc547e250a3582febaebf9b4ec97a1cf7c8f1f75e75e67454bb2179d6fe1a66a1ca01091134871f8886eda7e72536eb05b3ab352f8e775f94a0c1c3060d3932200cc10aa07a282a2c540ead4be9c3b664da3adbc4a513e5363b41e8e867d2c348eaf50c37cab0a1ad9f7e32dc48f1ed90d2c4fd88c7588f3250e9b582a +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d0609608648016503040201050004201652a7df9a92d3bca639e5b379b1bad5728d06fe2ef755fa734a1f09be6e782c +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 0b9c18c93a8b1b8fbbd036c2d5a6869c2c326e80e613df300d3ad74034fc28cb5e657b641bd0944ff4b4d8f209c10c86f92c5f120247ab9a6a54f8931d9b429b97ba7c67043dd4fda66e3923786e1a1711857180cab701a52398dbdd636127467f4221ba3dfa62ff99a6613e68d639b73be6adb2868c69b902ad8a044f756135 +S = 49eac9a68c0786ced77b437b01a3a562a5d6e6fbc9728dd513814cbe611f3d1d4aeb4540a61853595964d370406f3a18fc6973387c99821c8e966c47bb6e636543ba7940b1c0f23a8fcf46ee4e3173dd39980088b0fb2479ee4a08b41b2dff7b3ec1d2989bae39f7abd1bffc8d33155518ea6968b6b471c90e6773c76c6fe8cbb1fcc138dbd48e9eda1090ab245dc2b98fd7c553a7bf11321ef7c77fb14f36e5b7c969abd5e8c049d2ee4fc3f08caa6d996ee0580af6cbe27c2fb1e0bf3d79fd +SaltVal = 00 +Result = P + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 5c27ae4e00a9253b8e43c744e235654a6ff72a1cd37acfe0aeb10fb5b5505b9602d4ce81aec363d9a235660aaa93286bcc9ff768d7b44de03e4f48cc27cf5a22c07942f9d2bf3bed98c273c5d115be5314c48c9c64951939048de3fd8cb661d83d20f2fb9226143d17f2d6be7e4490caf06ed100a1a499b3a772c8900c8ed781 +S = 2a7d47940bef4582f4edaaaab4b0181c76c091179465ec3c007edef88775986ac07f85b4fbbd68450ba9dc346f590cee4ec1e828978d82c5e0bbb87df6f8c548ebbe64fb4f101bb8cce618d88dfb96f3d8d5efb0d6f7dd67c8f75eb068005f47db66d87c33b833dabf7dbd02b3b327988164f436a0e313efa3cd124f87730b463962b21b5a4e3a9530db7ea0ad8d3ebaa23414aecd343ceb58e324a1deb1653e792ec5a9eae709d77b2e55b6e8b5f653a8044882d020f5fa8520afa588416d67 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d060960864801650304020205000430e1d3f55e005049c7d99593b81a02de751db47deb6bbd6cebef963164123fce991214c8be6828cd6caa14964f293e1245efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 8bbcc23dd3ea4ba9c1d1c8e052be5d49e1f358c657050a3b9e83d64a59d88761d273e6f733258d12facaf60da72bd798b723b200d601a7b1512e8ef9ca10420e2f2d3f53ed9470d76079421e8e1ffd2516fb54a063163b8625b3f8cf02327d7d8834f5d967009dffdd25d59c716177f7e4c2672e650b6bc204593d566906dfb4 +S = cc5bb97aff280fed4499d2fb96d5acdee24406fd1d80217a0b6a27f7324f4728db0a4a6f996addb55ee8fd2fff1aa109d7293f5a7954a08857e53941d1ba0a86e1c38ec61cf9d54c2ed40c281475fd68dfa1aaf0c246a05959465c89bef974df66fb1f3228e07fe03eb7b9546c6f09dabecc6f2b8f2f6be058186578d87a097aa6a0a15f98061d4d1a1ccb67a9a6ae6b35e264e591a8115b459dd392d3c1f6a6785ed3c97d319d19b562da148e7361ee261c2991ca09ea924d69d5dc59f7beae +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 676a410de221dc39a833bd94dffc5b06dc4ae2613b1ce1452ea9434115a4813a4fbf1611506e3280f4edb24513845083560a176549a81b04b1df668b1fcc3599c5ab65e6899b282a58a0fc3abdeede74b265ba5eb658278a1f9251bdb29b364f713716d5b43024fe7b5582bb03c36ca39763b495a9b46e9f21cbec1ef598ed27 +S = 4f43d98e1a988f7b64d37fb9db79b1759e1b971f90fccd542d636f04c4f8e35c3f07d941c906f8fb788cfdef25b4438a5c9322ca2230e62b17e618dcd7a4669a187506dbd2087cd25da81f351cb87430163208dd06bc3e5b7a36559969ebbde2200f8933c45cb327f5e56e1c36bd15d11ebc7bd0034cc2fec3a9382dacd61a715c1f2f5babbd549faf752d4515e4375df0aae487327b765b45e82a868dc7985e03bbf1e6c80d022562c7e4455db4463f42fca3f2bfbe9f6cabeb3bb61fe0c073 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = ad82f5bc35d0995edf617b3b05f4ebabb0444cdb678980734541a1754f30f26804a615b735007e54167127a09603858fecd8bc0772b60f8ab7c39a15cf8c4348ee4ceec6366cf0dfcc46c66d312e08fbd0b3982dd3221f5c3b4cba803089f05395fde8b3e01ad8482966c168807f5a37845c491332d5992ffa66697d1830e1d2 +S = 5028c5c1d6558214048ab00458a5b0308053d91b312c671a15a47ebc32dc85b9760202b7f1d81549fe4c76d48318655b376e7d2398be7693f530bc28611cd48a7825759641c24fef6af1376d0d7bbbf23b9753dccb810a95e4d988be0c3c694f445f47e46e2aed98223c0583fac02cd9330e5652a697b07338193efe9afe1a514786c31edea49654d90d87d7caf26978accd08aa2272e12dcb058296c032fae8c63c736bcf4837c1d0bd2deb0a9539eea5f376aa5d1593afd8a0bb48d44bd5a3 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 75025b7ff7978e537b49fdbc59a54ce3e8313c96885ecce3e6b8a5e67b60b4df56bc19871c6d40a54d814ddcc8eabec7922f4b48d362111c2152f0b30101323fab596d0c0e1aaa0f1417c6c127a2192ef44556486fb3b28217fd499a7b09bdb6fd4120b3d68814ba5a7230147db4a63f97d923416437f73c4f227643f05f9e6c +S = 068559fc0164a646aa07337ac8d98cba1da106d4fa951f408315284f4b2138037687b87c33b38d0e180ccd62bfe1baf2c42f72b9750d133502092c42a3faec6e42f3059ccb5cf1b3db1ec2c714e12aa0c5ab612a4d0c913ada82c98015ec761e7237087e2da676cc92e3340b2f31b13b157bb128b2a6afbd183dd67d5e1bf8bd041e580ac6a3fb8b4ab280d182ef906fb247c0d174076da4770eb10b13163c2e53f0a5b8a0b2352de761677a424fd5d71a4efb54b49ba6e2a96b9aa740453157 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430d7d7bfdf4dd5cfd15b04f924d4be54564e72e6a2ec5cd83b24866b42a01970acc7686ba35e3f9fc29f0fd53fc5254104 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 0b9c18c93a8b1b8fbbd036c2d5a6869c2c326e80e613df300d3ad74034fc28cb5e657b641bd0944ff4b4d8f209c10c86f92c5f120247ab9a6a54f8931d9b429b97ba7c67043dd4fda66e3923786e1a1711857180cab701a52398dbdd636127467f4221ba3dfa62ff99a6613e68d639b73be6adb2868c69b902ad8a044f756135 +S = 3583422f69bf11bb8c8c9e18c40cf2fe3d6930b174a4d8efcca214550b525f7d460077d280e714b8297378a9d228226c719f790961999f0532d7068ac8d51dacfae64819e8b7eaf618ddbc33557cd8f9a3a1e65efe8a4d02654bc725b1aa779ba54b1b9445488a084b9614d8e2c9a0d559a217c6427cb62a6cd8a255512bbdb006427db49b1a3698b643a21d65cfea8e624aefd38f0a3700687bd035028bc161f5eb005cb66aed2fe59110108140b15d6b97567b72b1c712d6fd030872d50ae4 +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 5c27ae4e00a9253b8e43c744e235654a6ff72a1cd37acfe0aeb10fb5b5505b9602d4ce81aec363d9a235660aaa93286bcc9ff768d7b44de03e4f48cc27cf5a22c07942f9d2bf3bed98c273c5d115be5314c48c9c64951939048de3fd8cb661d83d20f2fb9226143d17f2d6be7e4490caf06ed100a1a499b3a772c8900c8ed781 +S = ac97f3f6ebcaeb77a23ca3b9226f7167c7315e5687391b700f21e45a00b23d7ad5834ef313eb3163b2390ccc63f9d76274120c1f0380747b33c1c77edb3e06923482e39b5c964f8499c20e28ed3fb064990190cffd033ce3ae384c275298367baafafc5e66bb0cdbad6e2cf9b16a393610f0088c129b75b88da6207bfb8570425e38b9f2a30d24f4753184e36ce0dde7e9026fcee5cb88f70c1bfd3b9a3f0a0c6bb80a04266c2edb3ca9c06a37cbbf77c1b50c01443c9282d023309a1668fccc +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d06096086480165030402030500044068ac2dc5d380018cb50e8316dea0bd72d31a9c354b9185b1d227c6540be123d48d79581880a02e2cbb7166289ab6798fd3215b272fd171bf16f74af65de4a360efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 8bbcc23dd3ea4ba9c1d1c8e052be5d49e1f358c657050a3b9e83d64a59d88761d273e6f733258d12facaf60da72bd798b723b200d601a7b1512e8ef9ca10420e2f2d3f53ed9470d76079421e8e1ffd2516fb54a063163b8625b3f8cf02327d7d8834f5d967009dffdd25d59c716177f7e4c2672e650b6bc204593d566906dfb4 +S = 5b591910bacd2f0bb6b2052f81445397d2056d114924a306a2b24c4fac2b7698d9ad725cec3010d57b11795f7654969a86f528709655d07a336a68fd4cbbe6ffc95fbf1a6e6c17c2d627c6011e4209f406ae7f2c670ecf4081053c2283845e2c855938da5530a146a1ce4bc203d0179a19398177534c7bb37cd9837911e8b1e7988b800e8046864fbf95e8c584a3c4209f3ea5fd535ba58859ff128fed9d0fc5be8e8c2890a71e38f3acf2a1fb537cdc87f53e3376276c8cd501d21069e453c6 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 676a410de221dc39a833bd94dffc5b06dc4ae2613b1ce1452ea9434115a4813a4fbf1611506e3280f4edb24513845083560a176549a81b04b1df668b1fcc3599c5ab65e6899b282a58a0fc3abdeede74b265ba5eb658278a1f9251bdb29b364f713716d5b43024fe7b5582bb03c36ca39763b495a9b46e9f21cbec1ef598ed27 +S = 5f6b11ef4b5b0a1bcd9cdb2086c60db19544dd33aac813ff6ec628d9de0ab882bab6496b79477cd445f71686f666b9e041e2ac40959ad94d3df00b1ef8c7ac3ab68b1d2e07294b3aa54bbcc1039b90dda11bce3aaf66646d19a7224028dbe7b48dbb67dece2812a5bf82e89db0908cb26043b78ca5ba455ab680d3d6aa4bd1682b39b5ff744a65dd5cfa909d1b71218a48d88e4e112a8b959b1886d956610d915ef41b30031eb3f2acf7d42387db245d84ada17b5995711ab2e12b8ffca81905 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = b17ebdbb8027c2ef5e5de76780979c65723d73c0ff0227d95074ded158d1abf96f1d578a3c716197d996433f32d3f727ae02ba2812e91044a2c808df892fc12b7a122de5981f153f934f5d1d14bc8a835cb2814e28089123d7b1b4a6ce8e12ec1c86c7325ad9e6cfd5b1be67f0fb5c62c374519c0807b55e38566b8ef197a722 +S = 1e80b47f34629c79b612fa8d25483056d1475f5f51c50ac60e8f5eade21469dce676d13b32140760d828dece21cd9aa2381b40f42e8e20a77392713f5372d1e87fc131eb7367b98d92a76e5276bfd073d6e44f8e9cf81e175d531e6ad50dbf84bcbb636b378c3342ddf6b2d85c3d27b2afe449c40f2915515c4c417a633b4de6c30e86f49f8f5dc44427642aa0c98e499e321aebda279a7321836a3cb24ee90c08c9e88f7745c19deb0e1de72b4da5734bb137414f1d4b1c78a9c2e58f148105 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b +Msg = 212bd005a8e8e13b0bf4620ce2d3d6bbf18b3d195b05e90412b78d2e92809720cfd3bf7e6b18e08c2d4f07f1aff7cabb562edca48719de931886776605d0a6ef6503573c9c41351cd165c0dea3e59f5c17fd3739d50a7c66953407ebd44f6ae4cb03c0c9a12b88f3e07cb35c2667fba71d407760ac9f6c846f07674465c58806 +S = 6db765c50f9ac9da75eafad6652ddb99e62234397fb2c96769af84da59cd408c12b7562104d9ce9e7455e06abd53af83da43406c64bf15d37ead519d6b3a12cd5e02803c92eeeff2312cc681d53b22caafe9ed5541db754772fcfff3ae53cf67d07b8eda85202a36db8cc01fad12dc3b455bbe123f9ed7c3873c0ebf25bcd55dac7002c7ad1d00eee91c58c357276cce875ba1719b2356ad821d278e9a62ae1a6e22b145ce2c072a1faaaaa8ad2ca4ca807eba3d420af2f3d915993d1327c940 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d0609608648016503040203050004404be226f7beb9c592f2429b00af0b7dd3de42b17313c58ab7ff24fb441e6e47280fa6f5ebf3bc14dc60f8754db42c984e4bc5077fa7b559d727938c3043453166 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +n = d2b6c8fd44e7eb621fa6685fb62371872b5e8408af51bd1b44c6473823402418a26963b98e6fb191cf74175e64132ae6cd101133fc002a89c10bf7739eb930b9c067b52570842395657f927434aa3acbf3369dcdc3990f77cbf22939ddd5877f09c8aab818b80aa20544b6928fe62c78795a4160aecde6ab454db0dcdf1d6c13522526c5ccf82d429791059306f02cdc18c4e580ec6c2da19b3c6de63933ebeac79010c73df95748d987e96a0f8ad523b5014b33423f55922aec2ec23b9aa22f + +p = f260d143cff1e8e0931765da8cb335c0206bf7fd19aaf8ff41e762992f2bb0a660cd65f08a80fe502c9125166a6927aa1859a874159796fada835b48522f5795ed1f8d23f05016358ff908b0dd638bb7ed12c8b80b46aa858d52c77bb7fc0ed1 + +q = de8e674fac0b7ea32d518a22030fd10d4298a77974db8febe195a4240dc5373e8161baf8ce47dc4fd076f64e307ea6262c35b9819bac4f142b613973eeb6a62a15a2ff09fba9ce4db7186969af925ee3acb7d3be7a1f9c85358216640fc1e0ff + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 34d9afccc659c8f438830b2fbe8b6600dfabc007cb22e826ee7dcbe2c515eb0cf1d90ca08a4d30edb5d3c6f6792a1f19ce3421eef7fc3f7212f7a965ee8abff01ccdcc8b498ff11ecb9a5f667937c99bc0f51a50f3a7639ae3ac1774b0737a62de3d5755ab25f1cfa05e3d4767bd4ecfdc7711f4662b3ae688237ed9b3d703aa +S = 38fae4b9233682065387c11829b0a9747217bd7d49acbb5957b8e7d231235f4f7ec316b5a3e5f4f8f45c8b9a161f9b8d3bed9aec0a7b0d4484474150c8bdf392172592c1d0b8ee2724d08aa73a32afad3dad1a0cac3a9f21811f53c69809239c26e36c7b6f4b3a90dceab045413dc3e89fa1927cc7a622e55044a3417b44ff93b2faa3c864c6fe519fa1a8189121a4881e178979096f17519203f0d2c9313a70b2a5b670b675319ad0971a0728f0db729fb5d50280a33fa201271715b256515f +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 95e2657996a4fa69f824ca49ab5a7e6ebaf498a0dc9eaa7f4981c51fcc0935f619ec6bf862683b0025cc48724839bc1e67aa3c686d321ba66185cdca83ba9f41984fa61b826ef56b136e13f1239dadf6e03d877866ccb887908917ef0d33f117b614fd291e3e91736b15150e650db9bdcdb56317f0f5ebe97c938bd691fc9140 +S = 3ae81b95c93a702dada5637e1c4113e5c37a8a24021bb2371c788a90ce8fab1c063c7e17f7f570a25baa9adfc78035d8ecc87219df1bd30c6b8b593682f354db71902ce23faa18f4af6fb9cf925ef7916c168f7298d56c49b6c68da954b56e2164ca37bb7c06498d6ee96aa502011356fc48733b937f299616ecba6699fb8d3d64e332c0fe3f9c58c18f033f92f237940afe9101702af51d3cc220547028eeca8e2d4f46ccb400f0620339b4da7d415ea288bbd7552eef2e68e4ca7c4ea6d011 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 24b78a630dd8cde2fa183956b3edff7e0ea5bdcdc0f1f51172a3bf5218b7bafd7e9048422385fbba4b9c4a4d50958953392b18f98d96dae66a54e81fd12987284465586d9365cfe0f35ce6e250541367e46f77550973582e4b85d1efc235c8389fbb21ac0480319b19e176df5c2f850338fa43abda8f582f40bfe18a92e26573 +S = af9d6db0d610643147996ceb4e3cd539603b068b02eb31a70dd83d40d45f88ba25edda65873271099965fe67758104c2e40b93a8aa3eaf1277fe0d0db1c08de0b96b82c9b48f9a2cac852124de8ff81a7d9742365c8e7f68e94b5d3fbd3aca0e42528b0693f4c61aad95cd912a53545a785e08464b2f675a4b1a5a3c53a8acfebcb25875f7afd802f6f5d6342b1bef4c848504b40a475e56ce9b967175dd9288761599946838617dcc57ee43e1b99eb47be11773cd326029cebed368f821fd4d +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414a651b5b5a63ddcb4142c5f673fff0619b853c194 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 165c3a41385c453b38d0ce2eef3a1fd2863535b993080c84847b1d5641ea24890d9726a0ad44b37dcd0269d59f44b9e0c537ee5571566a95cb39332693adaf64070aac7307c1a37877353e09e5cc17e26b45c3d9d74c0f140a4b89799e844366cc5dd3a28cfa9e94fd1157b308fac23e4006be2d0d1282670a5c2735ab9567f7 +S = 56965ebb90a59710f86a5868573132bc39e3be28d7b5c1e588bc2c80799a0c89c17dff65d281b7aad6c0c4dedc4c134d022512b3821e057f51e27105858b2ae063f3cd0b4204b326ef8ba52310a3187a2effb3295a848de5d06d73504f71c6a91c2edfa5b6bffc5b140b031957b7bb26055f1cb2a79b89df8b1c31d9a54d96d546fa1f77e3678efcd9aa875627419d1dd38c1fe743785739c8bd0655b996f5bba23604983385ccb75640fb0c6b128c2e117e9a5fbb7b25ab1d9e7a2db644113b +SaltVal = 00 +Result = P + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = e2c50870d442d577b5fcd43778e9ac0e13f62ae7d506325ffa38fc267d697da72dfb22eb03d4c4bab3a9d904817ce78056633f93138ce773257ed88c5aa16923f2010c39fa4f38b2d529a6b61c9ac058a8e55775ec7e94df885a31bb1c68e8285a602c2260bb18a54402a515f04c1fdd3003da5709e621ec4d546f7c6cc7e2ff +S = 11875488140cf57011ffff2c42926d00a8f2cae3367360ab338c96aebdcf9cd95c091840c416039f58c8a5fc0cee32432a673714f67baa42d4ba6150054dc88644d5c133903fcf02ed83e196078041bc96f2ce785e0759f0a7ca80f41c2c2a97196d0e4763330b74355d8de3a102538e1b4174de2ae8ac71ac14f8e0a9d9d9a71a34b953c0977758c43fe96a3cbd9ba00b52a72fe464b485d306979685db3bfcdfbec66425dbd20fd59e0985458dd4afbed8dc4a0756f38c54624d86ea71e9b1 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a05000414cb9ea455374c24f698ff1b23b65a9a0e1980c32fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 2a5853c37f9428e1879034feb2d07a5c454e9970f4c1ff43b21f5918c8614d4f24866c89f4da620d7478706b040e1d5f7ee028f7c610c0f8a31cf77fcda875e4477e69e3eed3c6fe53ccab1dc6402278b3c00eb632d45f56d988884fd42733f3384733199505ba7bcb92cc5d1eeff3708cf435f55d974325fd6bf3d10767f046 +S = 616e467f569c1af563d7775df9c11116856febba4a4b7f801945b702621bad8cd599fe43ba381e02a67714244c0961c9cc65b6f842c2391a439ffab1d262ab0896e200493526f9047e3bd77e1b88ec854f8075bb54d7ebaa1143b4adf05fcd1f7873e036f464e73b4761505f7e96d6e80553260a95449dabc1e45f6e5079ea6fbfb8281c693005d3214e175ed18a9f5e70d7a59e87381611aff9cc82964bc6e68735bc11277f5c2e00be2d089511b12a32bebcb96ed91f4e158989b3869eab4c +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 34d9afccc659c8f438830b2fbe8b6600dfabc007cb22e826ee7dcbe2c515eb0cf1d90ca08a4d30edb5d3c6f6792a1f19ce3421eef7fc3f7212f7a965ee8abff01ccdcc8b498ff11ecb9a5f667937c99bc0f51a50f3a7639ae3ac1774b0737a62de3d5755ab25f1cfa05e3d4767bd4ecfdc7711f4662b3ae688237ed9b3d703aa +S = 238a420dff7b0b18fcb6684933c38a9401fb2a6f8fdbb42b786cf5acb08948a46e42197fa690a613c8c0ba530d57d4f3fcdb410edaadcf995377a4512d09e5dea6de8e8f553d7694705929b012e7de002c95cd670f47890fb2077ee5a4c819ba2438d0757d8dfd1d0a83e4203672c269ac7a0c1e9769cb86eb3c9f5d7cd81058bcce66f1e3e7f47e1e15f000a02a7c98794f383c9b8650cf512b3040d1b6ccd638f5c8aa891228ea870177add8a9e754fe1a5c97f01f945dacf851eb6eaa0219 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 95e2657996a4fa69f824ca49ab5a7e6ebaf498a0dc9eaa7f4981c51fcc0935f619ec6bf862683b0025cc48724839bc1e67aa3c686d321ba66185cdca83ba9f41984fa61b826ef56b136e13f1239dadf6e03d877866ccb887908917ef0d33f117b614fd291e3e91736b15150e650db9bdcdb56317f0f5ebe97c938bd691fc9140 +S = 5ae8f7c7b9f7002e048f47d7471f83265860a70e7da64a9ec5053f07e9d92f2af5d738c79bbc9924eae62eb723edca05a965f48946573323132b482c04810d521277676145e505b515cb4fbf2f783e3f71124300bcc96963536ce8ca83086a004e4963b8fa52c4101073d252bbc242fd6e0648b61edb394d84b01f1d7bb28f24b65e89f5acc881b6d30612105f143c0bb871193f70d4217a1e283285518cba57ee85a3bc77fc9f481ddcbd5a78144685de81a6828b0a253f17929ce14c4cdf12 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 24b78a630dd8cde2fa183956b3edff7e0ea5bdcdc0f1f51172a3bf5218b7bafd7e9048422385fbba4b9c4a4d50958953392b18f98d96dae66a54e81fd12987284465586d9365cfe0f35ce6e250541367e46f77550973582e4b85d1efc235c8389fbb21ac0480319b19e176df5c2f850338fa43abda8f582f40bfe18a92e26573 +S = 6fafddafe9df19c45011ae4914adda6bbdbb20b43106d6d81faf1121c6300f9f9f2f87991b27a79d7ab8df8466539d4974d5cd379413ff1f2ab1f826ef5a6b128966fba4000593ce924132c26e3cc2734c38536178d34d90bb141576b80fe2ef1c4be81fde648d1aa3a4f537bcf815edab3cd3b44f7db09e7d5f73a17a9af84500c87d33b9d1ec7854852400c389473c8a13f70bc37bac6f75ce407996a3fdb9489fbcfb860a8b4c7280d3795841cc325fa0c9ce025ecb3f0c2d6c18a44c8ed8 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041cdc59d2d30fcd76a4ee2fee88ea165458725b7796e06af5a9bd13f257 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 165c3a41385c453b38d0ce2eef3a1fd2863535b993080c84847b1d5641ea24890d9726a0ad44b37dcd0269d59f44b9e0c537ee5571566a95cb39332693adaf64070aac7307c1a37877353e09e5cc17e26b45c3d9d74c0f140a4b89799e844366cc5dd3a28cfa9e94fd1157b308fac23e4006be2d0d1282670a5c2735ab9567f7 +S = 00f76baa258f67d94294939b305b41eba86c36b5ec68a155281a692b0be33d01d0b4c2aee3bb503a4f26ec4688b459bdd550dfdd029bae58f744c14b2768d184f6cdb9bf1e6da750cf10883f14d49ee5d836ba34b84eee98e7feafab7ed239b4154666eb0ebf0f3be6f44926656a0b9c5f649fbe5638d563fccdeaca8665a6a7868061a7a544b69b92abae588c8461e01e47f2d83f00978a99caaa2b4478a72c83806d24ba5e41447ed7fb6f22b1750223a9b18c8a2a08f00eb58ee20559dec8 +SaltVal = 00 +Result = P + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = e2c50870d442d577b5fcd43778e9ac0e13f62ae7d506325ffa38fc267d697da72dfb22eb03d4c4bab3a9d904817ce78056633f93138ce773257ed88c5aa16923f2010c39fa4f38b2d529a6b61c9ac058a8e55775ec7e94df885a31bb1c68e8285a602c2260bb18a54402a515f04c1fdd3003da5709e621ec4d546f7c6cc7e2ff +S = 6dfff6e5d6e75fa6b9f012a13c4e62a469d915c7382f20c8b961084ab41cfbc04dbb150d5f50c7c1cc75e6e891b0950a95df3171decab5cd48dd02a62b51f50358248b1c47f1cf7949d78bf236bcf1f6803e27e37725b60a37ede16f951587290f4eb5b4af07b7a6c06bd520adfd29e56ae61efc3ca7d436a8af7c2da47bf201ba602896bcebb44adcbb54083a26b91ef32657ee52b7c69a98f985dcb37328fd703c26303c4863ee3efda288bd9565258b93298dbce897003c760168cc17a734 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041caf4c1d01bf7efc97ce8b761e6fb40139563ffeb393b5ebec6f015885efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 2a5853c37f9428e1879034feb2d07a5c454e9970f4c1ff43b21f5918c8614d4f24866c89f4da620d7478706b040e1d5f7ee028f7c610c0f8a31cf77fcda875e4477e69e3eed3c6fe53ccab1dc6402278b3c00eb632d45f56d988884fd42733f3384733199505ba7bcb92cc5d1eeff3708cf435f55d974325fd6bf3d10767f046 +S = bd10583413878f8c71938b58927ef67e7e46a56f56756ccd099e3df80dc44126566525c666f009b0bcd35ab1ed54d55a34b5e7e0c1efc1b8a54199a5d4605fd464111a40ce3c93523f6ab771d8c8b03939daf3593a020284815357958c7b69e8500d360138ab64a94237faf280a33fb257f4191b5ef385a7b9ed40e6fe77b6e85e471c3c7fa922a2044600285e2c71f5b76edfb8ac76c5b9ee0fa1856c632c9c3531763cefd999fd2f497efc4520029c6c08a8b8b2ae0cee0bc81b222dcffff4 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = e1ba864ce9f41cf4ee2ddcbeb7a05afb1f48fb88610b5da39233f3fc6f1df00f593567b29e22b0eafa3d0d035e488de0ef5d318f52244e20274932b8d32d0ae183dc04246e40b0da5a94ac3f611a80c8f511c7b722e290ec139a03fed89c488a6698a4cbdfb7e56b141801994980fa5c384d042758aceaad5e0caef604d370b3 +S = 5596571f16dbd20f8c64ee7c1fe8750910bf640837c9de5c8cf02bf1b36a4ed8e41e95e10be3038334c7ed93b80ef660b1061d3595c647a603d203d2bd9a357236679944325572748f54fb84f382a7d369899a82fdc5da17cb5a24e2811ca881fc748a6ffc4a6610a6f3ca5db07241f7bdae1d6ecfd7eea37b276d8667a536cd45c8841c5197471ea8959c253eff1588cd99355beab1bfbbcdad5c19aa507be24e826479058197313a94902d36df02770cc67a1c3f7adc1d467640ade84237c0 +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 3730776bea4bbd16ab03e8dfb6ec4b962cf4312ec6432cc1c466aad327adc9db20d16d00c8da8f201140d816fd516e3d0ed20e30fde95bd4af3b75996451cefc32403951b28944bff93ec88cc966be9a09a35432731241018d735560da8a54d951c404e60e1e85fb4843e1c783f4e4b806ad2ebd9086864f475771b2f11f0378 +S = a9a3fac88d8fa6478302de5589304fcd201792e51e7f5e2f10305311fe804dc70728623b20dcccbc996bbc7dfc2ef283521480910df1bbdf72a51151353a791319181e586868f37f17499dc31684ea8632595ecccb553f9bbd499ad291dbbac1813de8fa06a53021bb674b198c79f5c8f2f28c84c09863951501a52bc7d8076e02adb656cafb940587beb815397a9bedd3129c2beb5cef8e3771e985b4a81be0cf6d50b53af7723a0ac0973fc053004831cc3954b2356e4aaff9aafd13ead212 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = a9ba6a22549b61aca519cfec89c316889f0404eb354b5f8d7268c174d43aa6fbde87c4d20a2b9b4605754cc21bceae96f09b9ff8726598480b3785991b48d36ca5dacabe49621d4672e9bff8d0b2f9cd091dbac6abcb2e2f660391217855464a687d23f0f78a1034543fd0948fb91eb45052fc5ec9c648c7e9949014d2a7271c +S = c71119e288acfcaeca10f632f20ca3d9aab35d62f4d8ea66acb955d83c0bf0b9eeac6bb3f776efcb4bae51e47c3cd29ec5d9c8f25bb6f52956ba4ceca9e189a5dd24f1a5f314cc65c2d77b9c1450931765bca3ba701434cc9ce3c4dca806f1f1b7e11da83ce253a1c68bd306770f3d3e8be5ad242b480fab2ba73c20d3922ecfd5d3e4c66ab7a220ce1e175d19740caafc76005056a67326be67f413233810c8fabeefd00b3a3ec19178f48178c8df23a0d08e38179447e3c1f7ead1ac186298 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420669cf26386b9f299c4b53a9cc5bc93fde922383716b1bad573ef605208ad4741 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = c68bfecaa74019105206ace85d710f160907bdffbce96268b2b63680efac8a217810a053c2d0c0126b6888512802843effe1ffc8b6ff185e8bf518fa251c025fcbf26c9fd4bf8edf5e78995e43e34ab449fcbe58999888657348019e1f80dfaf27f809b6c353aa0195ff8419965c88005120a3b84ffada04d2759973c6204899 +S = b7873d5e394de2c8d17f988135da4563f12d449858e5b26e630596c325046e30f0a66ff38b97e8bd3c7b8cfeed4021ed08b025d7c8919c9c7eb29c980290faa100d4b56c1837bea27dfb862cfb216a0965a1c6a923a65e654569164ac93a3b39bc7f533a4b64e4e8a3b88d0fad6eda12e11b181c9abca3b776fc409a8f069ad40478c3f2f02b0634d5d095316813415ceaaf8ff069d85649b8f4b6ce82ba55a2a3b0e53274f10a8cc0c7863032a38ac5bbefdc735523a683bf92196be7120845 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 17c6696009d0ea40825e93872261234db051c06cb17230e339574b7802a4b0a2bb18b8a5a2caa8ff55b22b03e56cffc42d39ee346247008deb32eff072cadb4c3b173f82b49a24c74ed694498c0f52155952c8389fb5412415e0585659ccb0363ecbe63f67c9c45f15d1b8a13dd38409dea436bf91465b71626a70f2de339927 +S = 181e3c1d3f6f6ceb7465b6d232f0fbe3270bdd3e6fe05a8dbc3ca9611280b141c11b903c8c34e7a09b1124874d2ac93af9b3d8ff495d7eaf763edf281235066ac6c7c1dcc257049c732ab2288b918f1b7c43bc36f40f5fd070d362322109b51b85574b30987bbd2d460a53ddd694a972fea606ba2b3a4192dcb30490370454e147013d6c7ec15ddc72d81dd7d0601c49a00e61b57ce3cce8ce89b8048359a450a42ed1d7a424e725d75ed0ba5818b377ef809b3c32564562315f21c8d031ec0b +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004201b3650ae9361fac5158b27993f4f51b62133f7172673d0cdedc1820e3d127314efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 063c070dbba386b97c50ea8c475cb9817fb00be490184906d19a3535ae052aeb06cca546d21505b8080e8f00bf80b55993a698f14b3fcb9cb9e25acae2920bb75f92e3e1037aecbfbe8b36b0c1401c32e325c85444ecfa6e30be040f46cf1a37d935c8c696fac4356770e68498c4757339d6a4f5c3485ce2fed63cec21e5dfd4 +S = 97c48f987ae22938db183cd761956e3dde0cad8a865b70f2392b77f876c63520a12d3bd80850fa6cc20e9bf94d058f2d0a7ebc83186d0defb0ae256237a9fae92b2653284086d49b04ed9ffc3e10f6bb3f9de76396cb4fad3fcbda87bbb1df8c26e2d70f3d5dd0ae4c159ef3aca0fea506887666cd923435b0d40ae434a816b71d72b91a92b107721761adbc7b678d89ae5c8ecb0ab9078f8805dfa033e00a25b30c3c1c4ca8bb3bbdc36b7846267c2a8e5c6ccd97a454fe813c93f50eecabf8 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = e1ba864ce9f41cf4ee2ddcbeb7a05afb1f48fb88610b5da39233f3fc6f1df00f593567b29e22b0eafa3d0d035e488de0ef5d318f52244e20274932b8d32d0ae183dc04246e40b0da5a94ac3f611a80c8f511c7b722e290ec139a03fed89c488a6698a4cbdfb7e56b141801994980fa5c384d042758aceaad5e0caef604d370b3 +S = 1f01900a2786e048f388a061f173adf5247b68076effd95b5c174661b6fc3589981bbc03cbe75534af40ffe0e60c741745cd143f23c2d073e70856ea88442e56f6ebc26e8609b72a955f9377eae375913c032819afcf60cae66d893525ce0bb83e0184ff7dd85893443e10d7be59466c6b7276452501e105bd3e0a8f7553c58ed8700d8e43aad9efd827fafc1948288c12e380b82a9ba22340919a52a9453f2b14e6b7795215720cb6c2a89fa8bbeb46a416267f3126456cb6fdc9fad183059b +SaltVal = 00 +Result = P + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 3730776bea4bbd16ab03e8dfb6ec4b962cf4312ec6432cc1c466aad327adc9db20d16d00c8da8f201140d816fd516e3d0ed20e30fde95bd4af3b75996451cefc32403951b28944bff93ec88cc966be9a09a35432731241018d735560da8a54d951c404e60e1e85fb4843e1c783f4e4b806ad2ebd9086864f475771b2f11f0378 +S = c5670f7a66b167b3369df23e847a68022be3f2acf2c54b1f9c8b4559466587e80f73b6b668921af9902b72a2cbcec0f92771cfdef7bcb12d3db6032b434b8aa2e2bb2a29f16756916887a79e78552254b702cf2a14c9b9c6c7dcb84745fe27c90f0eb7760aa4f98ed241bbe65a8597aa6d26fad59874b38fb48c2a69e4a77d7414b66552dc7a9b15646acbaac71aeb4c4fe69be40137e79a05ba512d40f86af2d7ad5a1893fb589ec9aa25854083f8535da0acccd0c497dd8ae3a16d3a8b3973 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = a9ba6a22549b61aca519cfec89c316889f0404eb354b5f8d7268c174d43aa6fbde87c4d20a2b9b4605754cc21bceae96f09b9ff8726598480b3785991b48d36ca5dacabe49621d4672e9bff8d0b2f9cd091dbac6abcb2e2f660391217855464a687d23f0f78a1034543fd0948fb91eb45052fc5ec9c648c7e9949014d2a7271c +S = 29bef7b04835e0020a2cba2b9f6db73583493c3702678cc624ee60dca13ef99f58bd2466b3cc3515e3ac52cc01e53aa0b1ca13871ae90317ed90d5dc810a49b0f569cdf78cd4ac2b554f272f3aa541875478901c26d82835bf482451812460da6392f801293ce370b1dc1ca420cde9af65f191dbbb57e0868971451be9030f414c24cada0d759767b93526e39cee99933f4eccee7eabf0353fef6061ee271558144cbc8c4aaf2d2b6e9bc9dcf2fe3f1902f1ef1cbd4617b04281ffae8925fa09 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430ec65d014978f49b770a449d588ef99f8c92263e18690c237b1c0edaa8da55716adc29d56621402e375c606e7399c9a83 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = c68bfecaa74019105206ace85d710f160907bdffbce96268b2b63680efac8a217810a053c2d0c0126b6888512802843effe1ffc8b6ff185e8bf518fa251c025fcbf26c9fd4bf8edf5e78995e43e34ab449fcbe58999888657348019e1f80dfaf27f809b6c353aa0195ff8419965c88005120a3b84ffada04d2759973c6204899 +S = 80fe5722ecf6c505989f017b63fa71b2723acd378ef8c4b4de5aa611d99196584eed2b46160f4739906533fe54034db7264a19366f7719ef576d3765907f49792fdccde4b94db4b42c95a9c54b2fa67f513039329f3b3fccba4d44f69ed2c9cf3b0469556ef88d90391af612a273ada316756c36d447b4c1b36edf516e8fd0569cdc4fe2254d3165a9250a9163c9b0c629bc64fc7cf9bf96c3b51d78e378678f2309658bbb363ff462f51d145b82fcef1a0282278453b48cd8715d32dd8a2214 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 17c6696009d0ea40825e93872261234db051c06cb17230e339574b7802a4b0a2bb18b8a5a2caa8ff55b22b03e56cffc42d39ee346247008deb32eff072cadb4c3b173f82b49a24c74ed694498c0f52155952c8389fb5412415e0585659ccb0363ecbe63f67c9c45f15d1b8a13dd38409dea436bf91465b71626a70f2de339927 +S = 82af137868d165dd09c47c95c960e636513305030879d7c4e1f0b58c65fcbc10842f7794e0b80b019b4b384b3473fb452b9e04380f84232e986dddb79957845c0f69f880a51a73cd4bdd041d98576be7220992982ffbe30fe53adfd524dc5da9d8d21a2140056faef2e059a1b282914db1b83494026696601026ac038bed35ac5bc7fa317cf2302f4f211dd8bfcfa3866d8fadb498709bba9aa823c617f8c339d17d0094f31b945c1c8138c944e6ac6a601a705e47b25e9e290faa0550549989 +SaltVal = 00 +EM with hash moved = 0001ff003041300d0609608648016503040202050004305b2dc15a4a45f199a414077ae9da96fc71a00f9ecdb0c40e214da9b370763b672571e471a8d0328d5ac83d2ea45ad2a7efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 063c070dbba386b97c50ea8c475cb9817fb00be490184906d19a3535ae052aeb06cca546d21505b8080e8f00bf80b55993a698f14b3fcb9cb9e25acae2920bb75f92e3e1037aecbfbe8b36b0c1401c32e325c85444ecfa6e30be040f46cf1a37d935c8c696fac4356770e68498c4757339d6a4f5c3485ce2fed63cec21e5dfd4 +S = d216d9776d8ce35cbfa62808888f67d9a154c87184be9000322148237b8bb64bb75aa5a1773ca9d5b375ae4f643846d07dbc3cfc8246d8ff2f774ff42b184df3495cbadb81a8fad00c00f61fb59602c087d570db0ee1312a2747be0fcd9d563aa1cf14522ace1e202c76ce7849b818b04e4bf489fd723c977f1a2594d65d8595917ad0b575cea228d95d6e3a9ba6f6ca604b8650d5d4e7c182a487a20af05c15139bd46b2f2e48e5db0f184bfad5119a9c256ab601820b7671b6cc48394de6f6 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = e1ba864ce9f41cf4ee2ddcbeb7a05afb1f48fb88610b5da39233f3fc6f1df00f593567b29e22b0eafa3d0d035e488de0ef5d318f52244e20274932b8d32d0ae183dc04246e40b0da5a94ac3f611a80c8f511c7b722e290ec139a03fed89c488a6698a4cbdfb7e56b141801994980fa5c384d042758aceaad5e0caef604d370b3 +S = b4be3c1b7b85f8eff79c890661621f6f3e997ec0b957d540e12b51461fd711b1f7ef026e7f4ecd1298b2f179fd90a55cdaa8c67eeb592dc077d8157b8a04611c904808a6e8a88e83d0965b6f8673253ffaedb437e01e771fa652cbccc976bac41d5be23c5a11bc4027f38d7442e999dc4ecd4af036c201332f7bb1177ca523becf8bc98575d2c4cc4f69bfd9383e540a8eb70dae384f3f07e190f72b856139d5232c3b9037b7e05dbe596af51751da4fa33a03c1d3e847e5339f2fdbf4601272 +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 3730776bea4bbd16ab03e8dfb6ec4b962cf4312ec6432cc1c466aad327adc9db20d16d00c8da8f201140d816fd516e3d0ed20e30fde95bd4af3b75996451cefc32403951b28944bff93ec88cc966be9a09a35432731241018d735560da8a54d951c404e60e1e85fb4843e1c783f4e4b806ad2ebd9086864f475771b2f11f0378 +S = 204d6b33a90f2ce261f413b54563f97b04021d081789d8b20bae89ce2ea0de539a264a7aa47e4e4cfb9864fa271f097fe1ef632363e3ad3996e7d7d4412138419d5e17c245ded83329bf6805880397b5d9c724e4185b86fe55c88b4e8f01056747ce712b10eeed8081b928c805c4b89b6955219d9441289fd800588012b4a19a415f96096144d88c9a9de4ecaa817e36e6aa1123bcceeeaa6c779fb7fb67a61773fd1c8e9dda482be5882b4f81217bf9019753919c0c98f3d56bd60ab4e8ad9d +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = a9ba6a22549b61aca519cfec89c316889f0404eb354b5f8d7268c174d43aa6fbde87c4d20a2b9b4605754cc21bceae96f09b9ff8726598480b3785991b48d36ca5dacabe49621d4672e9bff8d0b2f9cd091dbac6abcb2e2f660391217855464a687d23f0f78a1034543fd0948fb91eb45052fc5ec9c648c7e9949014d2a7271c +S = 380e96b29f08c307d6894255bf104751d5c12892caec1f449311dea1eba85d63829c4f6f8e4c48bae11e6ce246635ffabe1f921de533867a738de08974c2685e7cb981c94ba95d50f2c663a90c281cf676655d542c5fb91818fa83b273cb7f55d88555068e9827de54abeeb597a7f66b20bcf542d9423826363716ad63fe29ef6a093f723d3a0f8926b678402fed69645b0fdebd943546fb0e0316e925eda23c755a321e23df6910e7b6c908b35dcd0b2e0e4c9dbaf51d050ad6d9d16f67891c +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d06096086480165030402030500044068a22ec35ac1e035665d558ea68f2d2867cae3935aede53c6940477d181f9630c3c8d24a06be07e006049c545aaa830a3ab849ff91d935df4edcf4e46868abc4 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = c68bfecaa74019105206ace85d710f160907bdffbce96268b2b63680efac8a217810a053c2d0c0126b6888512802843effe1ffc8b6ff185e8bf518fa251c025fcbf26c9fd4bf8edf5e78995e43e34ab449fcbe58999888657348019e1f80dfaf27f809b6c353aa0195ff8419965c88005120a3b84ffada04d2759973c6204899 +S = 7264f99a15645f551eb08662418097e48da66f7c3d5a953d7296330bfa24d02f87f554e19c20f98a848daa9de39a22b848f514826acfaebdd93db456394713547ca172439f18473f36243eb0ce85cb7357d04f011e34c139d72fc540afe0e7a5927c8466bf28a76e572c851493f23569ccb73132a650ba5af14ff2cdb20a3dca7fcc465e6ac6998fdb2df6f3d88044b4354cec5f7f6ce7f02d3dad61e764058f9a69a6c4e63d4e0ac89567fe23cd1eaa5726d567d7a647fc2ff4ab299a05a896 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 17c6696009d0ea40825e93872261234db051c06cb17230e339574b7802a4b0a2bb18b8a5a2caa8ff55b22b03e56cffc42d39ee346247008deb32eff072cadb4c3b173f82b49a24c74ed694498c0f52155952c8389fb5412415e0585659ccb0363ecbe63f67c9c45f15d1b8a13dd38409dea436bf91465b71626a70f2de339927 +S = 5d90ac2736979a5a789b927b6b142bf08cdf50a5018e9e75cb03363f255d4bf10e0873e39c7cfe7f0faaa2594b856ebaea0b3a83c6c1fbbd1201e533b2ce14e726ba43aff51445e976f9158d6b369fd121e17e34e529a9f7935f3583943fb82eb0e551e7a183254cd1d442ec87d3b853613ced92c28ad87c7884b8e57729fa36b25767be0b77108d2f1da7122c3c44f71ef1fae6399400190863764d2d28076953e579bd5380058cbc06671b76d6cc2bed1bfb1eb0a22e72308c5c294bc4d339 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffff003051300d0609608648016503040203050004409e1ae481b6e7360c34c33703717c48bf5c84b980c112931713bb8563dbbc3542dbc309570342b078e7955ded523fc9b8e992724b26452984214d8f3d04a7f0efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 +Msg = 03403f0e704c5e28fc547e60cdba09c7bdb7e4fff89fa2a0c667f8d9a564715b9b556372caa4227545e9736122b044c1d17c9ad1ac0ccae2cedcec0029ef8dd3d3cca4c3a1c7c75ff7819f00deb29aa95726df32f00687a694590ae9a7caf79e53ace9471c3bb6aebb25e98529497349fabe9d6cec1741b2c0e53adc487e1984 +S = 5959dba95cc8fe826428883acbc57294a10e8e8ffda441b07f8fb2ad17f52589774c27c2f1cb54e96614bf7b7a89c4227168ccbea47a941540d2d71157844ae0210c6fb7abdb58db349ce1515b63303f85a6bdb38bd6ea0f9a340fe70d3aba17f4b5f2a36dcb37f354eb86533e4424c7ccd8377775a28f9beb6921c8b4d9e89811ff748bc1b026e9214c9c16227a36f803cabbd738025bd9f7cfa1c33ed4c00b5d8035389c8d6a02051576d33c8e83f2f72fdc1b35a0dde73fea1e2a93dae015 +SaltVal = 00 +Result = F (3 - Signature changed ) + +[mod = 2048] + +n = a911245a2cfb33d8ee375df9439f74e669c03a8d9acad25bd27acf3cd8bea7eb9dbe470155c7c72782c94861f7b573cd325639fb070e9ba6e621991aefa45106182e4d264be7068035595d7549052989b3e7fd04cabc94012c1278a0ef8672b1a51dd1a9e276816ba497dea24b4febe3dd8e977707bcd230ca6fb6f8a8bff9e6ba24fbadcd93f00126b19b396a38e6ef86d18fef945b9154c1963fb488c7025953511f86d05638bfe056493730bc6778446e59cd3c5c3acf07a0a3a64943793652f10e3292aa7a6d25a03181cc6f6ba0658d909e59ce2a02bacc9766fd8c4fbd4ed9c23a866844b8a794d49e505f9f944870a71aadbe5338039825c2dff81af3 + +p = bf96de108963b5113399b664765efe046e2dafdb70d6e5e29dc6ec89b789b059348d74d89129c7ade9ddb404c6dc3a3437c7fc9f23bc38dadc8ffd0ff757999f5c2d510b993056147ccdf421e03d0be2c74ec333a9677c430cc604f5550d0d86defdde71488e3db889c699a5cacb44dcdae2f3cca38695e783e6f6250827efb1 +q = e1e7e33618d1b64d6862c132e4b1cd5fabad20ce62bd97bce2a3f5ad2da67bb0a7f0b9e48335a33b7b95e77ec4c47e91416881f9f7c23f9bc1918cc644335c74260e90cd7b2e0fed802f19e78c5ed80a431b38630d82f982c74a0381b8ecf943c60810fae90574e216357b2535002316d9529cb56420f3cc82dea37cb624e1e3 + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 04d5d202ade6be1df96d263021141bd6e4e68a14c5b413df73b817df8979137377ee2df5c0e60d3f67a8ee6ea3d6f5e6da97c196cdf4437d1183d06cbe43740e6bc88a2759988919eed421ac651b870ec5ab0d190fc9f5d5bc64873e66f56147c6a90f1edec2dbb2773ae673ceaa78588b6b9527f2fbd1f15da265dbea558125 +S = 6b2703ff1a8d96808bf97eb6d297a8b8d11f479e22b8471e03d2713d124f7c8bf46225e8de2b9db432c39209c242420bc9a17196a38c1b2daa096a73e33912b353a6adf9d198d15eadb6f287c5d2379fe8c07d9e5735bc4c474c2ff9bc7ee6d3684335f7f825664d6272426b2fa20bae585f7bb306b352d916679c68c77ce0d2032cee4909fd02f4f4711ff4e771251c3a9e284f37fb1bd417d8842d030500d84bf7a774b5bbf089e2829c7e7dc27f4d88408e5b549522339e6eb98d51718a219c0fdc20e26bb32d85ef877a5fae812ece7bb04a1ac5a0dd71ae4e8d4c25aaccf8c1f5b9c0de7e0491cd754a675ab6eb8c630b8afc49e0597ea6cacc6c37fe9f +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a050004143d68a61abc2403258d48c94be567caa29e315c8befefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 3efa6c9938d6bc37f0373d0baba3697acc3bed498f9dfea7fa0af06e11c405a64aba834b4067094fabf822e390ad1bf3b58112ef580d50d120aad95c54d640a14bd9c0c824a8890db7095809caf84a338949f2a63090a9250b3e255ca00c4e682b9d4c9a4a5ee578fab20605c24c9f432edbb4f57fedb2a9a10dfff65d2fd403 +S = 343014b8db6ba664af3dc07530e444976bac0a7fd3505218500b0342c0c861d508f55383c18ee70cf47516acabd50dbc2ec18a8cc2054ab87496b9cf22e4f576d5f208d0cd3be114f65f69e0ae744e46edbe0a378942e24eb51fbe25a0caeb654b20ce9a8feda1bd02981a24ed35fd139d107611cbdecc7b1a960ec57a19eef79bac1ed277b746772b405c7c29cf8e32c1c7a49557928ec792944bbc87183fe828a3469214fd35c8ca16df57a985d610ef80db9728f3d31529a7c39da03d39a6735117dc99225921d26fcee7779d7ae191934452207bddaa60c0aadef72c1ea09d5a1d7cac615a8a5b08c5e429d801f868683a72263d80db270a413a8fd9c4d8 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 0017191f1c6b5bdf895837a17e05ca6119ea3606aedb978c5f423962ecac0811cc87471f7c2985331715cd79277a1e48bafd1a03b9b8023d7683e2208472090fcb9fbc8adb292c52817ca5ce98d307ae22fc7ace985b5e5d7e32813e392095ae25e7e128e3723685f01625687c186fd9796fbd30f2cc91359ed87d85b5bc9338 +S = 1d2db922b68b7e89cdef4a238e033500962d61cd39bcad53494663921ae6b0f7710728d9dfb8d52d7725d4f11ca058b1195b1c3c4614c32dce6a2b1b9ad1db261bfde9cc8258787fa7ac9884ffb5e69775ee76ae8af3a15254898e8497b77d7cdb161415a1615eec8ae7ba4ffb352ba459a1d84e43a04b616a13cac644b38c528047841e249ff2795ef2fd066615828545d04c82e92a027bc110c5de6a52355e02bd7888c97dfd48a925528e48890323c6a4f44e5d04ea05cf3009e838a6bf438fad103ea8ffe8d0f7d770c0034de693c7bbad16e8c6a923cc8976bda5bc08b15897075162068b39b362699149e0cd4eda9ff1bade4fb540dc27c17e4119708a +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 1577757d0f460af152dc68b6ab25deadfebba5f68351bb6e2e51ee766fc437f71c734aa3ac4b6b7da506839b5708732acb87a8b4f7eff09e33858cf5f14a866aa822459a11355e939696ad940823a51590ace407e8570a5dca42cccba96b44cea0cd8beca8cc8a3d0dd30d2a233c19753570807abe4fb2b4dbd2d68201ee1a2b +S = 5322e332949c0f15fe63f09927e2ef90a0f1eb2262fc8a7dc602facf8b5cf74dd0eaa2638a6d4393c0167be176e8e68d3b1a6dd4c7f043dc81e702b3b2620df5a4032e6319ff88e19c9cf57fc03f3ec5ca75db70b6b22a38f40a3dc214b477da2e1400eba49c35323c8d83e5159eb4ca6701b4fdb99f18505f266ccdcedbeae59b36fec2616b04da979376403a435d3aae0113d4605b9ffda0afe72923ed2644069a408c148b4e781387fe49f3103841eff840f0b39b298ab4893ba2c292af33b57f6f6f69cf5464be470f678ec07f0ae97c9ff292d896a7daec48cf9e48ecd006acbc2c8567368be62f2178d469ae958ac0b5bd66917944c4b53d1f42ea2f20 +SaltVal = 00 +Result = P + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = b72914feec0e16233c24031390fe31942537dfc03d58810915fb597b163147414f22e26b23f3c7ee3fed32ecd0dbcb36f2b3c2106b791d3499615119a93410740af4630021c3f87a3f01bdf0d0b5ae3cd52eeacc94ea0da48db6baa5b117770fcfe9be454f4650d022a9cda7f95382adb5ee827c1f71f861da43bba796a32319 +S = 2c2a5042129ef97c6235195df1da7b3d80e08176900daa562ea660258269e1a55c73bf226fb54d21f28b8cc02aab8f453405f2c0ee6682ec8ff2d1d8540aec1ed953f53847bc43f0c89608164532da10188400e9e7850114ece817aa854024e696fed5ff74a3747de548fe431d4a95c789bb377a8add64a8583dc7fb203fd66ec9e476232c25b9d454aa9ea7332672cde4ef7540b12ee28524b6c399be32805ac0f7f0db08eb07b93cd24a23baabccdbf5c8437fe2c3330586757a897242c8f2673ab8295ee88e5ec2222fd6519fc49cb1eea3d21d63f07d32bf0874dfdd5e74f511b2e06750ceafaef4238824f92c5da128042dbf64557cd6e4d7ee35d479b3 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 25d08c937abe386aa08b54cb9d7537829c478e53e67df73b0da9cbf76a153acbcaaa9e7c6510099e10172016b3562dd7fc126fef5561b5c7148e2ba6f2c07378bfd7f7ce54977e25c808fe6be71cb1bfdf936b793d1c2b6a18bdf0658c74cefd6b1f40912e99c086322695d42111edc4ad932bf885f782ab81fcc33a207b73e3 +S = 93a032b6e997c0f9ed6261cc4617d98afb80cbd6450a3d9ea2f63999dd68194c9451538975d7626d77a34734d99b5992f98ed18c7f9dc0026fe34cf6583a6a36eb6baadb8316e3aa48d9da4244544da430cb8a19953d84ad4575733d887ed3bbcb4f25389cd36b1c565bf661b1c918a14e5e00e0f0857900ed4c98beab9fe6d1f66a0df588b61afae9fa31e94464d85bc743193303259e9806231cf5cdd4d4c9da5691c08156aa72f4da7607d598d450a5c852a8b3f577194afece74e59fd4ba8c5bfa583c2fa9a6f6aca7c51f772d02fe8e0bcaf5e4c2c7cdd6a38f7264d717aa2b30daa6968a4e7e7e2dcc1de9e34604f0b80c8b793f882d35497d81ade352 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a0500041461ba8219a8f4252ba5e715540544ffde89da3072 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 04b9dc9e05391605d1101e84d4cbe1a08bc3e12a97e7e21e10bbe6cb1ba15c34bf5895b7f4c277ecfdea75d0f845bf23b438b50ec2dba209cffda7fc3168f5a4bf653f39e683704ef99599f8c9fa2d3276217080844b2dd33193a7ad062cd385adebc46d020567f26c1970446e7194977985f9c805c0eb44e087d026c5785e9f +S = 39b142d1b8340384b8eea14f948125101c3c54bb339fc06a5dfb652ff28df204b05561e7ff8e1e6630d7ee9dc7a6147f6f24ddd703bc753cd3226e35812a821e68b7a77cae8429202a74dd1361e8e568f99ee2799a92500a21c73f98024d091c5e29e9531bfde05a7959a3d8f390eb17a6292d11d361a0caa7a5cd2900df5fd2f09679c9a1e58e525721fd068061e5bf5c95d1f491da063532ef620d537a45dc74cbf249c97493bc8985cd0fafdba295fcb65b5ce134cb30d504c93a999909e0cee5aba1d6a6e1f3a3d25403d09bff303d6b89f6a81d8c570c735ffac0d0d415c7b6cb7a10f68d94cca2f1de7975a5073411529b48b2a148a9353c536369df48 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c330514ff465a496206061832aa09d4d549aec683133b10ea884bf3f9 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = ad12e61576bc1b15d5bff13ab66a496bb5f643dc8461bc858d7a15d3d938369d314fd3598305ee9087429e8fa1e70e600a61c8f82b7e34b2497f5bfc676ef15068b2936775e04da99ed45fe7c401414cb605e4919a803b718f27fa5d90149e709b60ada513f43f48649cbdaae55ee91902091e0f9a10d9aaa699795c1cd243e4 +S = 3009202b1060f77de9e25bc5bf80062a16fd8c8a7e27c4f8fa2d069c6b706bb981f0e2561d8dafd42c647c844ff30b0a226704bb85a3a58dbd5baaa8e19ebfb7635d4f502677b6575b31ca37ba4a51e747fd97ed2a1fc330f2ddfd10669aa9ea4f13c990b4cfa7e15e983459df317ff83506803db89d9f15f3b93ca0acb22d800d9a2c36770718b62a78998fd13471107afb36b700aedde93fb9019ae9aaa9ae4f33d7a18cbbd8474ffcd38a6b4dd95de015786e50811bf3de5dc7de6c3eeb721e8197a8cc537e1d076a887634cb7af055305218680b605055d7e999b90a348745d277bc36dfb38c431c9edb329d3c5c750afcca77ccf159276ff70b6e8f949a +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 3ede763590291420c8da355f5e5930447317445e61d0cee6970dbf59a4ec4e679123ea0c744373fd423aa945e51ce5308e2307684df4af5edf23b0ebc7fac138a07676dbb1936f42c2c9d0552ed7f0573abf560da512e123806d46cb4044c0a712de02e96ea171b9ef9090d76212bb811df5199792b2ccfd23f36a413852b17d +S = a3dfa3b5ce640d92f95260d559bb5c40710a2d3cb38b816fd3b790c78ede96bdc213e7e6e76f35d5e24cf1a6dc54d856be83e352f55b3caf98b6dffcc952023978a5a6900cc9b0201b99c90795c38ecf0a3dd5cfd9579378c57c0083b2584a3bf859c69a553ce7cf8c1ecb98376b4ce90e1a0271c4043654f175e90477440f7108b960d1e3e2d00743e0a2db96d179999709722b046070c4ecb6f3f3650365119004b016e62272fe9e7c06999c8b1f8e0ac56f46c668103cd23f1457f37e376b8aa5c4235db08ceb577945f3276b931f5933bda713f0c8643aac2b0ad92f7c8021da0072444ebffe55d0cf183f002ffe1e8c221508e7f65b73c05f9362214440 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c6622f8e46c8c838679d4e8af043ccdd2f9bf3a6820a5dc64a446fe67efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 250f95cfabab5de46ab2bda3cdeb3228cf7330aa1b5764ad75623c795634a9cad69424c9cf08ef3b40a29df9ef1cd4a053285289b0012efc844660a0220884369d22db87e7c8939b3a63482cb79cca5a4eb721a1dd23ce079c4f549ab8bff7193e5ec4f23b16d16c229ec6266d939cc087cba5d8eae6cd3884251f4d60808bdc +S = 580511902d07b267c4daa41b6660db0d20795afe0320a961a36b384fe3537f7a88e31e09c5e3f660d2ec4e176c2ebf7e45be1b579831c0c75509380684e5936b79097d6c3b7262583e4c2f81ba09e78e542e823e855ee97260e8fc9d53fac6d452d601d07526583d078e293c0f183d716a0f7b37de31b000ca7bb095303d4eca67393886e43ac271c119244d4c45d98212924402b37660c0f7dfcd34e4672011d1aa721337b1025bdfbce502f017a573a18850cbbe108bc9fa978078906a4c1d4023f8158cb5224b46f43f70c8029793981011d77c816749f6ca9a71c2749e0e151fc69c7f4b39fad8e96cf4dc6ae451bfb506d9faef8b377b7c5b47e19a3a59 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 8db3a4d5a7b2fa1c3cf85a9e07df0aa00eeacfe1defc527218c7c8c82c86d21065efa2c2266360797369cc02b25a24b2b35e48fdef961c450d9b2ef0ab2899bd5a132958ea82bf2ce95bf77866fc09a5fa2dedd70a52c3c246e671bf75248e1e75077fbe7d75dfdca6b72529aa2d801feb400694b7970e90ca8eda5c14e47adb +S = 9724b7c6909ae1499a06410557882d9fe49a804c68c172cd5945e40132d750d47a454f155c075c0e57003f20cef4a1edc84d427b6bd9f61617ab502ba6dc5c6b1d032a380898bacb80d5484d39783dbfac37c4f001fd8d4e1bb2310d459637be04cd5fb2cf6b32dbfd214b8f7cc0dada942cc41c9f476bf6ffa502bf7928dc8610ac0097dab03f79171046af23887c2d530463714bf7fe59933cad26266a117cd355d0402a4490472b0006f6e915c56e204eb480ab48fe9ef0dcde5660cb9ad235890713f77b5333c1314dcc741c2c8d0fed546d23696275a8d578a0d39d4f1dece330d73ff1c20c72ea82e4b714db309a0063edd35b22f12ea68f5c5723c8a2 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = d6fd570826eb30d7f3173089ffcdc2f791c60cb4bc5760e6e3e9d3557da92bc21681ff7a9646192bc6331ff5109673c487c957de276455b85db1de0eca603132447c7ea51d9e4be4a8611884fa153e81eeb81dd46c227643ea7f167d3202b56666d81db0425b8faba289625e44b4edd6ce7aa7be13f88d30923bc4cb3ff78006 +S = 4c142307690bf57792293509295ebe275716356260e0fee39e72b64fd6210f547bbc8eb84ee2fffe5bca0121735f934d1832079031d9813902269cb6a814a71a09012f08f6f8ae10907ca0755fae622328feedd8da1ca666d2b713ca0d5b6de85b9b1cbbd6874dd980f304a313ca07e6c70a44e9dda1bed3d9a2cce521473661f33b7fa96c496b8f7a9c77e9bd0ae0dd47bec92c2a4dc9f75af9280402a04014523957efa5f52985eff48e4f1bd54858a956743dd2badf858d00c83213908baf95c527afcf0e32f7c97d4dde5dbb936ffb09500a2bc0bf71839d55489a21d642ee455dfa8b525a4d4890b2283eb043b3bf77d2ed7e2885c32b004fbc89693380 +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 8457c53956849cdb39bc8e7657d62a2cda9e13e1a5c3574142f1fd041c3add70efbab5207c7b78058196e9aae89b69bc3f330dc96804f44892d5d8da68f3e2cf87d3c3ec36f8006b51178d44877a9eabc6a2badaf2301110dd060fda74a9319136e91824ebc5dc179289a2cc9b3971025632419bac0f55a20dcacb8ca92372be +S = a2a2c0264dbb8b8810aae0b9ec7408553803dd02be6247358ce39f98f0c0f0339915347ff3c4dfee0e0a49b675ba69e376f3dbba56aae846cf7f986a0a5f37fc9971a58e3217cca26dffee8655f3025bd61776683feecdde546fa88fb881d619a8ec2daf092079a850340f6af41b2dd11d9935bb06c2253bdbd32a6fb8bd5317d3c9c3be5b683e7fd6366e1816895664d8ee312eca47ecf862be009d9df699a7d2f515c69e3093fd50a3babe9ebaeab6267086a3185a908ea29af8eecf81e2be7c9c2ae33cb2380c73af264d24961b5c7711b0289e1a095f2966656ead1fed95b6c33d7082c3868f1f7b706f9442ddb76e3582f73e4839a0a110dbb78e9cfcc5 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 6918d6328ca0a8b64bbe81d91cdea519911b59fc2dbd53af76006fec4b18a320787135ce883b2b2edb26041bf86aa52c230b9620335b6e7f9ec08c7ed6b70823d819e9ab019e9929249f966fdb2069311a0ddc680ac468f514d4ed873b04a6beb0985b91a0cfd8ed51b09f9e6d06da739eaa939d5a00275901c4f8cf25076339 +S = 794d0a45bc9fc6febb586e319dfa6924c888594802b9deb9668963fdb309bf02817960a7457106fc474f91601436e8954cbb6815350b2c51b53c968d2c48cc1799550d5d03b41f6e5a8c3c264d2e2fe0b5b8ff53fdcb9dd111c985cb488d7086e6548b4077ec00721c9cb500fe07a031c2030e8ad1dd0112c34ffd9091d77a187aac8661b298eee39eb615f9715c4c48a6762ede55a466ec7f3cdb6a937cfc80188a85d8f8d3a2a80b199ce5e6375af8f02f06d706a34d9cf38318903965db54aaa7d3fa7a7ee58034cd58c8435739c8906366e2ddba293f2fb2c15f07fa4951014471e7f677d3bdacffc4c68a906e08d68b39f9010746cbacd22980cee73e8d +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 4ce993829f7b8112277cedbf8b4ec59244cd7ef79a7bad09cfdbd1109a1a7348d7f472e57cd69853cf4070c2d66e5ce20f37e2eb623547e154265f167d92a3f03caf84eca981ffe3cb45728d0c10ae43e9b44d09eee346cbe297bee73fb021ece5df72a10ec4df4a85539926137ce23c3a0b685826cdd150e1f4978bc6bc16c4 +S = 29865f133c69122e1b309b299270b5d693db89c5192eca5c829c795db460cb1dad3d1f27d200790fab035c90c00b238384bb30ee30752425f2b7f424d71bea79993046100760f3fa3c6e019d025338c13940a97778ea67e6d6138d8e8ff601d2309f02762add479d85d25fa31bd1c89af97927dac2ddf818cfe2179548db4da69c163d8cbf5f9c98ea33957022a52d6f33b19bbd3d05f40f2dfd49d999184cf5f9bc69fc1b21359c3c85ddebb6936c4f49015026539e8c4aad2dd3a3b4ba309021fb317348d12b560ec608b74f812e3b74e4c8407765f30d6d03a5c20db821adc4c844018d57fb5364d0e7c3d55816782200ddf92b13dc2e0d4665b4cf3e1059 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = c801a9270165955fa4d85fd502c0e6be0c91e1c453ef734f331300034a6f3e8a2f958f9361558e1a7e25e7eab6c76d617e256674898029f2f4c9ec0dc14fd716869b5d886698cb4841f8212b28d222b91490a731d70838cd52e9dd46e959329b34dcba0ff77875705517b59f402c2d4d34994b0325d1c865b6397db7abd578a0 +S = 290d0d444ee458777b5fdc3207d37054407c0dfa6806296869d3ec402a18209a3d06eb63d995293697e8c0a0e72489bfc9132857d6c7a17f4852e4e573a48d2a2a127fdd270092f5029d976b060a570c90d685bd2325d80c9867a3b245455545bfae8cf87cff314f4d0a968229446dbf24adcd2a52ef9abd30b4746c2e04c0fdf52655427eb03bf63fdb208c6a776a3852052ac225eb33d7246f7ba624723f9c22abaf6d2f9219181ca62e44bb53a9ce8b45e7c6d742586a234e5de66df4ffbf7bc9e7f815a7d5aadb2f727f3151afa6ff48f6090d9fe08c8b0f1505598ca4a4ccbde6ab0f87b43059065097c737e53dc17f200c3a54b00d709a5b8bdce80f2e +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420af8893e585e7d2dbf3b8d3dec0802db4ee1ae86e8bbe369d8e1eb3aa634eb2cfefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 2466a246feda6fa5cee22c2f33ed9d643c1f6824d9f327719225bc7678cfe4c85cd210ed4077701b0b5650418177a74c71b8eda3306e2ef3474f5d326990eadea84a9686e822878c932997298e01f2b16c42e019e21bdfb67b3df5478df444366c97df1bdd23dc82ce23abee44d3a61e9484e88ed642634197b52dbece451b59 +S = 79c3b93019bdb8a6d6a79e813e4d96928f730afc010657b1eb870f2891219de5fbd464fce97b2bda12a9d84a3d5c120c660ed0f70457e223809b26a996afab7c23143b411a1aae566d7e9d19d278044567b5064bc918bb101cadc7a521c31c5e1962a7437d8f799ee6a76fc2f0a6733cfcb63246b1a864bb14ae70daf848824da565892d750af7c5da6e02e4889143a746e7e58b562d19cd3cf3d97795e50e1dcfa26d43f00357c92f01b327718d6cd292498dd29d0d830408b568b2c91541a76b21b5d4efea46bc128d9c4aea4e9f60a4a601c876736bf9312a00a2bd81b4ca5d8e37ab2c79dacbe7d8e6abcc4691db64649cdff212f467a9d805b2c38cd031 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = ecb6731a006eb273f6c5404a2e2d1faa5232f7afdff5b69be1dc7927fe88af17b5077b11e84b5baf98db08d3f1c99d3b86e4fa55dd2e6b542e91858368cd51d975b5adcebf9bee6ef309caac05b276f874a70b14cfce2e237891f003a8d3f3dcb328cff98d45b3d78db5507c72cef20aa4e4f094bcbc47304543824ec480dd48 +S = 8831265bcd54bf33d8c46cbd48052e9357c31afee92276b1b744e2521da9b83968e9ca90446064d8f174b248f64e792f91f4fae15252688e0f8ad38b28a532ddc7dc59e77d81b7a51dda2df2f2cbd5195c87b66db297b74296d4058fd00a060377dc1ec286c21e4f84c17ef315d443e89912e6b5d5f7d4ade31cc2b1aaaebcf09aaca20041b5f9b799b5b532391f85fd236ff3fa794baf4b25a2a188b0746728f1cfe0816b37d8dd648c53d76b81ee42ce27bf07baa27016b82c9ef3e1f5523ded7d35622d4986a6699b261f483e9b68b9c99e17e4aeb1c7baa84be1177264894ed5aab8592dfaaa652898b37aec28c19d154df27956f604bb6a30d0964d4e97 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420e45bf84dc5abc5c28a27625b0c96d7399fa1bba8fdaf1d5b5354970b2ff9dec3 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = daf4399ffab3de496e3ec347b4ee6f4ebdbd83cf434ea81e5d2dc6d351577771a9fdbb458985ed913fd2f5ea1cc5c0df8203eddb3ff9c94d191e7e05aa7887e16f6267aa1b8c9b393143cdded1f34a02d2eab60a125eff7f0ab28f6ca6f5c60853aca79559d1d1886b1bb1ea7c80f7fed5f94624658530fd587061d0ebd51a2d +S = 38aba878044ffa4572749376a12fa96b3b8cf778e68baa7ae05b4cf0457242f3a1eb8451678e79ad73741e169efbabdb0469a53dafb627ca3d14fbe392fe311e792b8f274e0d8439de0d9a82c14082abcc4253a5a7292f846ab816419b34c57587f2fda5c6be4f4a3c4130acef535dab4f0e05f5c8b18993f57b167298ba24b0d238964e0fa87114079fec872c673cb7d961ccf7ceff7fd5ada8a6f309de2d96a40224b12b921ad987b20e0ccafad43d0220e24b82aef90151befdbaaddfcb5b35e505912438668b4f61745734879c54c1105983c83a569560f35265be0d3ebcacedbce139c489f4be3c3befba6dbd6c5c92e0441a4a789ea383516be0f4540c +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 6cd8ccf65bb3833c81961801ec68a9735fefb8a5f7e3e63c0e47fd6b60f934216c87af801e444692aa9b8737bba4fe62cdf5b485d7bbf54a2e095684a66ff765facf06f16e6c84b2b2444cae0aa05196ace9274069bdc5579042895210ba7ca2dc58d8309452c70661386e4c21842a77c47219bdf512ddccfd9b9cbbe5024b41 +S = 12eede9247a5fd5579fd51f172ce798d20f8d932326f21ab0dc698711899c68357158ba1eebe07bfc1a78a08aad655da3a26556896267afdcd5e55d2ec91fdbf79960321ad13788e33eddd06b2f25347af73db9cdf628e8ac7a57b2a03555aacfd4af01afbd049dec0be8e279ad369a3c606fb1663e4b0f95be5416c5ecfeccf73c5d829ab5041e21ad0d1792b4536033f518b411c3c82ea162cef14dd704d23a278c0d71ddc9adc4014379c920e54ef8487ab3f5f6e991e50450c609fa769b60e057e6afb511df74ba7cc6458fe493a7a23e8267a742d20600f3c9261efd554b4c0b366ec0562c94c4180f34ba40780a24e8c36e110c40b6bb28b22394177a4 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 5fa43f0df5b0d9486b1e5f80a604230cb1159cddc9681462b47ca1aa547856c97bb7ba7c0183791014215a7fd00f71dd0f8996f28351162902b0a8a920b8a2c103cd6c89736435c63109e60f8aa7542e2b04bac9378b6642974eb2db924b361e9dee3c7c74d8743469dfea76fc5634c8ad8ef0aa0e9c6e751c5da989cfb87ca7 +S = 268bf5a0977722b24a174d83dc7dbec6ca1c392ad4a48d68af1b1ce30034e471dc8ccff5e5da865f677eb85c1e3022cadc89ec82624bc8ce5c632d1863a4946f364718f3566d38dda330ed68deb56130d10126fc9dc4f501f36e6e94507d5a556c8de76efd8149276eac52d16af495679cdd4361f66b7d963b9faa5ca0f8920227071c519f3f1ddcc7c03870a9639e78ce5f1e61b5291c190a4f9ef237116ebca742a513efe5fe39b1dd8914e71b60128b0e180685008ae206a64cc51c218f45db765c1af655457af34f94789ae5527dfa840a1cc9dbaef8003d81d3f59b7a3c440a9497da1be98182cbe368f0c984710f9ec986428f5c7a38313d43bcf680df +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 40bf49cb5825523aa5aea4c0e6b08b7f857f5e8a1ae01af731c14a364d272aa12d670b534d99f93eb04a9c78dd715cd628a4c8bc328c3933b397b23c77ec0b65a7a44f994a37623c0b34e7783d3660d11c13970056563efecaf0d25f8f2ac5e138dedb4556e7d55d3fd64d670ee6e199eb3393fd8d26707ffc3470459cc89e3e +S = 825731d01b0c197e2b27c4314b256ea5bc09ce9f012ca120695ba38c0ebdfa8c8802ca5137ef675f76a17038780f94f753b1234d0531be8fbe82e557d9357b18bea2a5c1cb83dd129e31e9c2aba44640145d2ed36470ee57a9486fe04ae13d1be2ea4047ef405a53a2d4f5bbcd21c9598de98046191bb605ce7004e3250b128a0d7d075ea7bab16a30f165fda23318547481b8b6c9bea0843876934bf7c89e013c9f19a8e661ec2e78013b89aa6beed57d88cb27ac34cc18f231c6e6dfcb8cc1580fd5ea8185b927147b564d31f724466d64692a17dda68e0b8fbc1a7cfec4bfa9c9f96f73bde2d0ab8948d09e1e739d5277a4d3d4e70236e9a3dec388986684 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d060960864801650304020205000430e57e40b2774ca1517efc987400aad5a59ffe873f0532d8a092db7b4f7be006eb591eba4082d41eda449a261187bf3804efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 752fbf49ae63c7853b3ef6f52ed324e53867925bd5d4c49dc42b93f3ba9d7eae579c4169593da98f10e1a61e1214a2aa2fb511a4a75849dc9be89445c29184f85ddc877c6d1cbb45230a047a98ac5bfcbe7b69a397c454cba44fd90fa13f9b546f39ba0a52c8a8ae5c0038932962f8e3cd00c1e00be28c70c8a787d9be6f69c9 +S = 80d7286710e5f165eeb63d2936e8e313ac5999bd297d35590c2b6ffaa4b7b7ed30003f0b83c1d1996c8593a37bc5d7b501a3d126ac6124779a23718497002d9dd2ce891b83d185e333af05460c6deb65a509640f775a0d3c70e55112c2e4af19f4ccec7af9ebb34226164f1b47d50b8ecc1dc3e0fc09aa15abfce5aa3998b5c2b1fde261c35eb43220f0d64529f723801d7faff841faba8709f6ea7751f30428dfc58045c84995107ee013ca4a84f65b99adde1abdefb5428f834ac8da04dafb9beaf1813f73a4bff2ec94120e3a702aed1184c387ebda2abf1959970724299b9a05f4ad313d91beb5344fe1fe13b3fc3386c279f031c77d74bdc9bc97e22455 +SaltVal = 00 +Result = P + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 18e158ea033c33dddfc57c8d6c8f132d9b129aa64416cd971bd3119ae1564fcad726028278288f6767c0d6a8a73906840a67b50dec8a302c20760fe62bf10dddb05d171a2c97a309e41e43c51b787a9687d1ceb906e61e5f8e2136f76205a1b08ccdbe3a875017cd3c28ed6d3013186cfb990e30fcf041374b1cae57ef5ab24b +S = 3491d346ada87f5585e13c5e3ed29c35f7f8536d16b99a57e3519c6c0fff826e6e314ffab85c3d5918473cf49dfb066cf107db8398840c53a1582a2bfc792c7cc1b72d3ea0a0ee0bd9c5aba576a9c1a41836caeb61da3b019fd553ec455b5b2c66da6682595e1d2731135ea8681e3d0b262316763f0840f030e6e26c67f11c1bf93dbe71b82d593bbe869ebf8bebf831e62ef31d2851469145a1f618734baf114716c0949a28a27a83521b5c68bc5b11081f6877562ed33ad603b436b7a9f98dc0f2968350810e24477d87df566a77f6197796a835b1945418667596171868a6b14d0617a2d76fb85130d8f5fc397326ea5f43587ce1812eb86e1aa584bb936b +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430cc8f60696cd0d4217858fd042c6caa3350dca7c9e36ad539e96052393204ff21a692e6349566d013a30f59c2d6bab449 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = daf4399ffab3de496e3ec347b4ee6f4ebdbd83cf434ea81e5d2dc6d351577771a9fdbb458985ed913fd2f5ea1cc5c0df8203eddb3ff9c94d191e7e05aa7887e16f6267aa1b8c9b393143cdded1f34a02d2eab60a125eff7f0ab28f6ca6f5c60853aca79559d1d1886b1bb1ea7c80f7fed5f94624658530fd587061d0ebd51a2d +S = 091d2c61d369410e236653b2b1b068cab3fa6632220f72737520838b7febc00bfbec8e993c3c969d7d4825ebf03a5ef7f087926ef7316f97e57e515f9aaa76b3a7bb10e64d983e6c443906882028dfb7e5fd4558a3f24b2c3b863174b011e8587995eb425d52e95bb27f98413cf2a1f5999990df7f5d3835aa19b93fae1b1734ddfd2be99b9a5a071d062b707543b47aa650faf640afa43a51c4013e27d278557d4429584bdebfe5fbef4c9bce178a496c0124aadc24d9ee8af3e0e83ea72ea93751eb687875902c7348a212819097860041a9773d810dae6d3c9eb6049ffe38e2a09d976cfcd3dededb7f374577458b25124669a85de7465b8ece756633c1ad +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 6cd8ccf65bb3833c81961801ec68a9735fefb8a5f7e3e63c0e47fd6b60f934216c87af801e444692aa9b8737bba4fe62cdf5b485d7bbf54a2e095684a66ff765facf06f16e6c84b2b2444cae0aa05196ace9274069bdc5579042895210ba7ca2dc58d8309452c70661386e4c21842a77c47219bdf512ddccfd9b9cbbe5024b41 +S = 0f8e07afaddf2b88cd2ccc2f720228e612ac00459aef46f9605cc609539097e60b10c6507ffd3fc27a15d348398c573bc8d385edb18fe0246af4c0ab32165f05a0b641d2e016f562397d3080d602d9c734b4d00b27f8a016f58aff098be7d09498b8e1775f0d7a3f69c383dc1abb2f177fa53ae8c5425a82a1a9ef0b428b70e48b7bd99df60ee016c4bd02f428a19225d3cba5e640d297cd28bf96a45cfa8e4e222e245b55a5528301d71e12b70246338ae0f4754b74a45fb670477aa1b1794ca1067aa1289819290ac7fa23bcea04442fd2c5ec835bb4a2d007fc2f9530995409f1e707220ed5b845feef66537889c85a89592d2df941cb61254b7d69ade808 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 5ba7760eab59b0b7eb22f2542c627352ef1c75f931f06dfca949644e4bd79d38104078a9f91296cd52fd3ee0343f00454d5f98d2e31e156f17ab3adf671624dd77072d6b11b011676a004f5fa719d2a69f05d1a7e3a4f47afce9b8b5f346148517655dfdfa1967adbd94ed778dda329e6e76e920376b5246de6da779f651b657 +S = 8385a5fe194a10ad210c8dc069899df18ba80008a47f0f8479aa690eae5588c04401b96afa0d8bd6512b98a46d137b32b48cde633f04604f8f08f63daf4f35b836374750d08cd20d4553752d3eb5d27da8b8d12e86cb81c592d39b66ac38c04f0d5140039f165ed670b3757282816f6b607e2708e66fc699dff5e81cf2861b64a98b572a5c417056fee1335e909f3f7b9d6930f399c29a92750b486263081e6ecc2a2da06dc1883f687a9fd480f4366c3099c7fe0d56c5c7a70b5a710ba021c075b9ad46e741189bbccc4f4ac936e71121a3c62c577f8157b1919df586569e6bb52158fd0f8d08ac1114981f904b5f8b267a12e1098b2f77918ee9189dbf29b6 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = e703433ae230a79291405dfaf58386e63fb5028088dbcda5c26e8f30efbb6e7c918a272461fe5d0d43bc31a77a4f126f18ccd6b9b9b10aac7113878e03f946425403760e1f4fcba2e99c185638b020b400f8aa365e6fd35088c0a8b105aff4c719b5578184ea98586c293c90976e58bbdd82a380dddbcf9af0bd1a235ba62013 +S = 25181c5f1450e2179d3b6ee166178c674fc572507cdbb0aafca5da9b54f10a3f223670db1122140887e68b9fe8365f316981b3d611157e2d579873a2292daab5e8ec6844ec58021cd814040cefda9f7cc3bed4eb0edd3098e3d9e5546060f19df911f1f89b92e82dd7aa118623e1c707ce43a2877ad085527ccfb5d5aa2775e089e606192f785f3edcc02c59e28dc9a9eae82647e1644aaacf05c91628b1f9cc55c683ca5e349946799f456bf8f2e943a0d93966521e2c35e294ca610dd93f4d871cc80b15bf4990a0999ab392659cd81af705ef0a3d84968f85393dd6a53579c3e463ff2c08b9f68efd4a0cce43c8118fcb61fa2fc47aa9ccb6ec0453b7ba51 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d060960864801650304020305000440df5bda9e56bdbe752f0af28644291a8d0fd9925f8794a485f27fdd5b3c603ebd68742e334ece1969a14dfd84e782e5ee8c8836b93aad629c63c826c84cba848defefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 5cb7a0a74095a6f284a13d4392aac30a73a9211df0520bf2f7e9831240579fca2f7d8d24fdc8d4161306dcf8b678b13be92804598f7c7308d10c0ab3bfb1092a3adee799113498b76a500c3f64e8f8a4fa16d8012bf3354e576823daed410ff54383b7edc5007a3d5228d200e3221fac6e1ca6fc0adfd92e53a6d96f10303994 +S = 25b408187418c512e7d36eac17edc64999e94011b4d5088ab926d29e433a69e24ebac43146a1371635fc78c3d215a66ea46d0a734b1607fdb9c3848a1404545ff60582abd579d978902ed399eb5dcdfacde0ca02145480246e1a22af5ddca7080aec216895d3528a8756e0c1a2059d392f87576fe896e411ddf02bd6be81ae2a654e0a15542a6b533b776703e2057b01ad02f5430d97c691f80219e46319de527541f0bfcf0b4e1b510059fa20779eb44b1ef293b7a8318447ed25793037ddfd1877cd98514c81575613f36d946670f632779eaf629a593fe99110e781cb38101a3cbd54d7871983dbf868a00cfcb17bd330309d43b8df8d4f05eb4c43649cdf +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 +Msg = 1d9589c9227a3ebe444b5fdda538adf0ae8f8fd69b30b58e3a41fb91ef229065fca3576fff758d09bcdfadd41db2904f777fd9a90f0790d4ddf30ddb90c61875d20f4edacce3c7d5ed8af51be779cfdbfb802f96774579317df17e490529a0c6254036b391ab324d5eb501590b74b2bbc1fb5b45dad1b8cda1a2168258356f80 +S = 6eaf91209e0a5f7d985231c7226732f64e2592e6be2886081f830119018ee427b3293ca3ab4156a41684824f26227401f1b10f7d993b000f3bd5d82d831bcdf772137a2982af4f1fa2b57b49833b97f448aba20458f3bd8417872f7d6b6156300d87aa87f2aee301ff53b6c367dd6907b61b6336d1ac97c4aae90e7919d94b1cb0d919a33003f05f941339f5c7de72ca94d9b65d42176deb086ec259df9e29675c087ca0d42f51be4324f8e1bff094a517083e51794dbb68aa229f7c1560945142c4e66264cf8d8fbd43dad4de21b96522f4ad7d1d121fb320204b008ccef86a22427b59b8e58d7e44fad62921b44301249fe1139ff656fedd466ffd46c27703 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d060960864801650304020305000440b1601c43923bb80b35c45d083bd748d75a3fcaff22044525ab82d705d5465863cb373e069fa40c9b8e5aa4d5ff7ad45700c7a8da342bf0b16686db87fba0abaf +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +n = a911245a2cfb33d8ee375df9439f74e669c03a8d9acad25bd27acf3cd8bea7eb9dbe470155c7c72782c94861f7b573cd325639fb070e9ba6e621991aefa45106182e4d264be7068035595d7549052989b3e7fd04cabc94012c1278a0ef8672b1a51dd1a9e276816ba497dea24b4febe3dd8e977707bcd230ca6fb6f8a8bff9e6ba24fbadcd93f00126b19b396a38e6ef86d18fef945b9154c1963fb488c7025953511f86d05638bfe056493730bc6778446e59cd3c5c3acf07a0a3a64943793652f10e3292aa7a6d25a03181cc6f6ba0658d909e59ce2a02bacc9766fd8c4fbd4ed9c23a866844b8a794d49e505f9f944870a71aadbe5338039825c2dff81af3 + +p = bf96de108963b5113399b664765efe046e2dafdb70d6e5e29dc6ec89b789b059348d74d89129c7ade9ddb404c6dc3a3437c7fc9f23bc38dadc8ffd0ff757999f5c2d510b993056147ccdf421e03d0be2c74ec333a9677c430cc604f5550d0d86defdde71488e3db889c699a5cacb44dcdae2f3cca38695e783e6f6250827efb1 + +q = e1e7e33618d1b64d6862c132e4b1cd5fabad20ce62bd97bce2a3f5ad2da67bb0a7f0b9e48335a33b7b95e77ec4c47e91416881f9f7c23f9bc1918cc644335c74260e90cd7b2e0fed802f19e78c5ed80a431b38630d82f982c74a0381b8ecf943c60810fae90574e216357b2535002316d9529cb56420f3cc82dea37cb624e1e3 + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = b756bc9af8682c9473fe98082ecb72f33f6199099baece582cc6672924e3472790a90dc330af8cd6863c7c882d4e6e726ce106ff0b6d641865b1e300bfaf067cd8f8af38c1299266efb6eaa88fe66a30191f772528649449891c1eda921539b6b5c80ac255df278bd7f44b2efd9c4f766fa455459b9a4735bf8f807e441cc81b +S = 20aad3d29d4bdf75f18d3617771723419920e688928a0c742af8b11bd2e05767afa0256c868c3538111359b7bb91dbf1b8bfc383a1573cec0bf0c62837b13fb5df21e7e07bb5d758ba8d58171d22b46147d6f7bd3b8751e97ecf13a5bc8c9b5ef7f00702c3ca400b6adacc6de96779a48881fd7c3f544f95f99ac1037f6b9f49c308aed1f6634afcbd46dd6fcecc015fccc24716cc590687fb2492c96812c9ac037f743e3b47d60420ee271331031d290fa6179178444256acb5697fbcbfbbb4fd3c6227566de99b246a8914721d5dbe58c2411df01348b63bce4e3659ae7ad09579be43acadad01ba02eb4c118b23ef64b318c7424920c5da7176ab2cdadb84 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 196c5dfa45aa9b9d8c8f0459ae650aeb45f1b05e06a6ecda44194fbdb5b5e7ec79b0656c583d7b2c4c0488253fcf77a51586e4e8ed5d81e9a44cb9779bc0938bbb90d8d9b63278a58f2f2ad85cd453534b2a2983e32918368c2965ad529911f2e6f3006ce5ef5ab05df8329a8edc659dedc7c5576f72776803989a8560aa29c8 +S = 4bfeb7f6d376548f1ada66742eb2320689db85eaca0f75845aff7cbc91faeb1efe96ddaeabf8f9bf2b3031aff3711ebf9e4bbfd46861a8bb5107aea784a78205e067779e98be0a74458c0c850903f58dd3541636c2160a8854914798310324f852c3806f0a0e59ac6b5d3ccfd2580443d09752640e27f41b1e692b3ffec67c39868f4605230b341a2b56ac68bd2fa3450df2ebf4867ac0156be6513e03bab686f435c931532632adc177e95971bfad056424230943e5757d0c5384671592b7b0bd4a454d4d73bf312f4f46f2f310e897bb657be3165d040ff0d8bf72315ae313fda1052c37307a31c2f8d4edce4644b5bfeb5ac37fdf0e2a393692dfb72bb4ea +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a0500041476e8a26a34cb08f8f58253d073c53dd76a749c5fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = c0b251836d180dbcb995b4ae6e18856be5e8bf067841b753394226efe507c7801312223eb1efa2b3b117eebe001676deb8e94cad96aa36abae6f013d5d6f18f680665514e33b164efde094cdda7b707858c38f7496ac28ebaa461b0d92e285556d78910eec45911503b84de0e48f9abf2d3e2f626090b59c95901d666baa3627 +S = 0cc0b5e4251083e72898e6d239dae55489a42675123fceb8abf34886846e5af39d109fb65d55fb019c43c3fe91b891262d8ec0aa721acd97848f455f049d6af58b5e579b92208fa48f7afcb403dd99870bb25a15b33a67b5a1ad10ccf3df04fbf5fc42a2a0dea7b6c689d18da14757b2b5ebeafc39f62b5fdbe58f44f03e148d4e5ae6ce1bdce9f316daf7722ba6622ea6eb964fc3d0d9ab54ac226a3371ef96300d9d737767cbd04963015781d14d9f0f640b1981219d391ae1d94eab184d68f1764e7dc2aa2890b08c16ac277aab85e2912975702ca0834ff7026be694f805fb2692a605635a020018342dd89b8a53f8b5fc7b5fa8b13fbd9f8b5deebbc199 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414f40c85085852eab21192fc3cd95f0ae92a42c3cd +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 9df2b3e0f8035d92193f0c980e8ce31aaf7218078171f907da982db246533dff2a8553ffa7d641cbc14fc4bbc1240ad8d7d07394046795b9372882a0b7524da3c03acad4719996f0e62a578ea175459c2ee5ea0c062125cbb59975f3385f7441a939a2c91ef464e8cefb4d7b75289b4efad905d84f47b4259a138f139222bbc1 +S = a82261947dd0f5b3f34197bb91401278dca36b759a7402ae65d8db6b6a12fb2bcf67e564d16030fd1b7e4e4df9bf0577c5dd5d6a5d8766009277003d0e7929675ccdfa04285e74ecfa1a937db117a130fe4662da0a869d7d34832165f86ad8c345cd6aa027036d818af45fcc8fb7bf55975c948af26ca363ff796c752afafc8e5afc5ce5208bacdaa98601046e69e648975a87ea34b011237bfe5f734d9470bfe71cd5053e2831d321fdb13e2a4221f992670782b7c584634761b7b96a28e33b69eba97ceb45aa1adffb29fd4705e4532e0fe1890d1575b5e43d4aa294c27936999b413a3086b000050330178b0f71248a0a92af444d8fcdaa0237b7952602a5 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 3f3544b53b09a91b7f1a27d5fed879788432e604a8b6d121fcf98ba886396b657441211c0b8d47c9e1af392c4cf127851a3c689d823811055bb5c7a28c4ad16ac43b71686ba07506d8c4098bc4cccfe3fe99329f61eff73c04d614a8b040c60297eddea1428c5b59cc233ef94eb09a189a11eb122c21a84d5d241cc1da6571b7 +S = 8caf5231442d5352259da89fbf54888cd32774b7851232b21defd3ae6d780a5387ec021f0260cd299ced9fd814208d1102620cee37b2d48b5c9ad90c061f0c2a527bbd1eabd7aa76a5f4e083483eff1a9b5d62dfe57c751d9bc49991485569142c65656a67213c37907db465dc7225c7fcdd7b9a37e3d6b887b07c3dd07dfcbdde86baccbdf6fd13676e062f9f875f912058536fbd31d4dafd9c051bb79236e6e0f90db221acfae0690b6fcba1cd7716145afabd39866e393dad2ae99b24f9d97682e6c1163f5f442c4e49c7422923625b63e82fb1a3186fcf0bb81ba38d6761156b1f723c0de7fdbb0c678effc49c128e655f36ea465d41e704ad1b449294ef +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 2726543e530ab04b06a11cbae1da53aa966dc51642d390fcfe95acbfb0ca65cb28db0f77688af52f423392d2295104594143bdbab8517c0b59ea7beb5e2fea1e86b69d77688702fb076b5543a6671722de83bc88edcfa4a651a84c539638c6af6c3c6606fc0abff77cd2cdd50124744d95b229498a58f0150e5986c0ffecdfc6 +S = 51d57b3e66fd6e271241215438be99969c40d0ea4a5b7c4918143f68f58e5cd9d52d90159e7bdc9b73ac3d3d908cdda5e402f0fd352931f9bca9dd886fed30c791efd2466dfc7c6483aa32c2865cef82a40dcf5c5bc3aad547b8e1dc9d973c8b90f529ef272a24645a6b76887925b6e19970d9f2d7d68a513f2e1638b184aa8cd20967618d06662bfe1450f03b72d19790fd1a591694043b310d982077285deafc28f95b3c6218edf59649b38e9170fb3f18483fb3788a14b161648beb4ce471c0ba4c041b87e6b38067fb934f50908b755bd126d2904b75ad7ce75a8a5d0c3540e1d9c7ad52242f2e5a5511d46ad8099f9386299f369e69e53107c6f51fb985 +SaltVal = 00 +Result = P + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = b756bc9af8682c9473fe98082ecb72f33f6199099baece582cc6672924e3472790a90dc330af8cd6863c7c882d4e6e726ce106ff0b6d641865b1e300bfaf067cd8f8af38c1299266efb6eaa88fe66a30191f772528649449891c1eda921539b6b5c80ac255df278bd7f44b2efd9c4f766fa455459b9a4735bf8f807e441cc81b +S = 3840e121a02c4d4dead5197cabbfffd00005c9474df11252853dde2cb83ef772e2a533d7e51cf524af80d1a541994018abe93fb5835989e870ec3400f171ac786678fadd6e478ddd2d6f95719c559d737dcf2e5fa0b875827ad8558c70f6b8ab725d7344ac5197270e494ceb03b89680b8bf99ee9260cf91f0611060d7ada8d2c7eb672a2957fe4eb1d3b027c4062f2d2d840304e4a7faa243b816b10bc893b2ad48e7ada998eabd1e9fca72c0820b9b4feedc3733d20087da09c26e352fd7a4962c707a7ba9e1f66b18ea89d96d0059ebd13d177bccbf2d80a502a7362e198d7bbe1199d5587c06e1192ff539ff5276ee5ee8ffe25df0a1998e5c8ab05d3097 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 196c5dfa45aa9b9d8c8f0459ae650aeb45f1b05e06a6ecda44194fbdb5b5e7ec79b0656c583d7b2c4c0488253fcf77a51586e4e8ed5d81e9a44cb9779bc0938bbb90d8d9b63278a58f2f2ad85cd453534b2a2983e32918368c2965ad529911f2e6f3006ce5ef5ab05df8329a8edc659dedc7c5576f72776803989a8560aa29c8 +S = 411e75af44716f884c084569a3500b74017141ec3f1c2768e0720d3df6cf221a155812756068bfdc74d998743647757d80e15752b0df1ed038ac316aa202a5eec1d0363e773a372d9f60c4d5c585f1111ed44b02c241280d2b6980b2cbb09128ce9b6ed38d50dd0ce10b73961b82996bc82a48f0d5a574910a691e55048136ce8f3668cec4cebe5c791d6b66b6c54617bc70d0d578080f22d9ed09030887bbeb5408155187a03657b55680c614e57c2e28e2c837eb7bdbec6985af6b596fcba378084d5f1a4fb80ec426966d9a9f914431811a06133c4e6df7a48577e16a8b6cc5af6873b70dbb5ef191ac9214866e73f0c99f33da2d21d313a6bb62cf03ea01 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041cc28faf02c47ebeac647f99f7cffeaad70df6513830d41a12b1d05b62efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = d699ca7f777828b13679a9e2ca89568233b8cf479d90462186a5ce71236ed6760053f007e807d8880418b11746c59106090f408ef1133dc1199602c16de2893054d10fe7932718eb6e24b39c0f5aff302cbdee60e5f94961eb08f516e70374841a38ae86407ef2c2bbc538dbedf1a9e9e6e961263fea73e945222dd95b7a9e5a +S = 01818ab2f8883d5b580b7d7fdd6bd15cc59f59842dd14649b27aa0aac3666562e4ee8a716d8f9a6fe19bcb5f505956457fbf200b8f0121a070788a546b86f8149f0aa98f2c6439412ed4a00114259b348d1f9e583eaa54fbc384c52c518159e460582051afee2d4163350bdba58112bf0fd9ada18346891ac14888765a68d3475f8f8f92ac9e5f4b02480859f239405d8fd14a05ef95fe9b726affaef8c8d54e6cc3a01a1399b2c2b2eba18b7e3dd7ee337c0f108dd53c460112a58f7e6b09db540ebb72fe8e3d1afa5224705f0159aed4d94d4ec0711e58873682199c90e9aa0046f81c3faa3fb21a0a05991f0752ec7e1c04d9009fcdf69d68098f9eaaea6d +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041cd8a970b5e7e41f37017b8160a04e42a8bcf502522a1ffaa739d6cee0 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = b1d87e6e67cf95799888c51383d6e6cb4fd8eecb4d2959ac7e58ce8f5598ff69bdb8d19e5e55bdd21c4e75fbe178cbbb9d93cfee8b7d387fb5a6067fbac46578cfc8d3fe04108588c9de077eb009249374f205553bba9d0218b2449ed413a142eef0ceb7e068b744a420c3c377f1b7faddddd729e5484ee0ae64cf132aee7d70 +S = 3dfbf8cf23053223500b1cc0a4e43e7754f3490f33648064bb9a806d17b8412075997148a76a152e7becbcc26783fb0519df481711648b35ead7fccb9937baf37e4b86133c15ec2ba0311ed6cbfb742daccd68bbe8f1b49766366da644302a04ec1952db9fb8e50641e3b0cf9c04066f5d49cff593581beedda78e50615c5f42f31444462f59e1e3a8331c1494867361073e5ebb8d6ecbc5b356454a4d24d87ff4dae556442384aeb0cbfadb3437074a76969b8f213a4e8a0a0538114888c95436582ecdae288c4f142612e5ca9e273da165cade52674f7668dd170cde6d7f8e6c02cd1cb013c87ab4a5c71f9f04c20a0fee617968f4862a101726368a96f3ef +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 51a9457af4abc1b75f3bdd4a383b7ad79f1bdcea045b15953b4bc15ad216f44aa2fe716fa4e91d68061db3537e48b8f0dfc3b202ea1795f966c17ecf7332a3301b1a8add2ae67a523f8730a72476d2b45bf52978f9970abcb80215f347f4a365e484f98c2dabc2be3302bc0dd1cdb16c3c39a913dae25e245898f08ef763da31 +S = 9c7b10642d88022ee6cd2816c95178a5b163ab887a3b663c0236228b72a6a92eb18d3a0fae84526f1e17442a2dbb199402693f166d31d30105b7929046db4b1812cea8d7a1c5d5d53f785130cae9816b8254de0aaaeecac2992a1df4796dd423641d685e65478850a59436aff0f0ce36f1d3111719255dd376d8315905f4b3db7439ff2b0fda6226ba64df947dec832db48905a3f2d0d9a2b46f92d91794ab98734e0a7acfa0b60216f728a0a4f6c3e188978cf745e620cb3a0fa836c1a548e1b1bd2c03926473ef6b145d6fd99eb5d512632334a2588fd7b2640e0d893e6fff31350a467543ec4a18f51853bd4566674bbc2867a18de04953b1cca246a558d7 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = ad32c2e66fa67fa97cbbc8736e36a04dfa8aff5f734c75098fe711306e9181d6d87e7aeec7535b6e25dd0da5d6032dcff9f96de76bb737bc8daa944748a94d3c4e2a50dfa2b654195a9ac0cba4e0c962077ddbacebcc3bea5c3bea260b45ccc695a0096208b7b4d3a45aab8cdeb4be2eab7e1356fa73c8b98204db74bf4c479d +S = 1c0ee89d483230cfe29503591c7d002e1930128999e06dab41d60e55ed7fb191b068b2b7c606e0b684dfbcd7b43045f10cffd72e96fdb10af7062d1e3af334b2db7d79f3ca478ba4d21f4e2d9aad635c47c15d26eb86643ff15d5366074d009bb4e213902f8c4ed53f5f3c2e1ae0771f0441f68257aa9705a4044d6846103c75f83c96f3d23a450681394e0f6f816fdc5545d96321e90a4c0a90899eac77751933f502c4b6fe72177ac1e9d3f3a67b9db66b96b78361ea7c47317b742d6f6a941a55c496cf7fcdd73ffa79274898081490049612f580a8d1e7edc95c10902dfc0826be1066e489912bbdfa2c8d6142ce9e1d3dbd8c9a9b9400f39579589f003f +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 585e2aa15bbe0f218e5119f95a252b57ce65d9474d35c1c284de1ee79f2b9a88bd1364e8a19783c3aaee6a8f05e0cc022170b1d463bdcac61c2a01e3b8bd550638c5e59ce2c04aab367b2a14257b0a157e9c6411a9f8fa94970a6992f91401efb0bdd44485ff0de11b40840e21bf8f97cc321a8785aefa33dfc67e7acbf7474c +S = 2e02460ece0246277d4517b9c00d40ee669251ce1be2d8c13bcb67b7e90635d6a68f8cf7373bb5962ff1d182f3fe706ae3e216446527cafe5e763432141f92995002f6c6c208e85ca3203de5d6602db70c2302c804abcb7b3a22edbc120a3b59b1febfc485bd787ff0053cba05d27800ab41bb431d9b7d7ccf0f1a5f52eda8432fc70d1bbc5fc766b08280124df71d7432542d5caee7d88db6654510ee81c3cd23b1501679a2fc2b050acfaf9218d7c6d4b260f9e8b986e9dd9c158820379609f11626d6b35eda024aa545286e884b6e135ac3e18d52c9be687004f0a81fabcef972cd2e82d954a43ace6f1971d7311ba9f267b262303cb51121fde66e073e10 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d0609608648016503040201050004206510c46f56c48ac0b28992c5bd0fe4047d3baf1fc7e528f67b15f3b9188af1a1 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 790ba59678e1eca8ce7e7723488b181ff1fccb3e339df4df3eede794ae30add767c006f8c4a4aa5af263d4df961a01a1b6cdf5e3d6fb004761757f414b70a5cbf5d87c5a51e7261146f7693556946be27ed6b9fc5ded8e6799fe537b7f2e62b2e9fc0fa465d3e93693df3d0ecf21dc4a10be1e71109d27a9ae30692b90926af5 +S = 91a2efacfa4e8642b683ff7c17b08743f8bd03950a35ba44372ef1814fbdec087c033d6eceeee431efdc6a3fac97f85b8248a92b601dc4ea9e02a23fb921655f084a4035b42c0e491ddee05c4d3d4024b6446caf77e917d28453640c0af50d937b5d74b535acbb3ef9b2dc87bd3cfc80f24d2aa9b1feeae7b549c197cca6888fdb617c8a5a1c91a23c6299cdd1b7d292b0227634bdfd415cb6f12723fca2edcfd1176a485b2a2cea075765785077c84de1c50da27daf89407becac9fd9664f2547c5a9f66c9ae3c14ce318317c58d4c3d3b07f07d2f8a58fc10b854b583a628054cdcb9f7729e5707d151a4ba82b1d99f339d4f8a0674f260a8a6b8665169fa0 +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 4cec86b6da42bda1aa66d9f6ee0ec6c30f4f575ca2bcdca198d2f67fb494aaba4372b5e9076f1fc2748313971f3eee2173af967da5840d74eb7246ffe9d8370a6c9f2f795b646a69ebd9e3b8116869c73d1af57e45b83b919f307f02d439aae8313a9d6ec068c51e772fef60aed45e3dd7581b69699f8d811dd249915d012bd9 +S = 89a014c41636b64663cf381dcc399355e2974e1db624e36d5fda7d3967417a3810910948813ea58caab8f7cf2dec7309d26d5cf7db0dd60a0ff42982b91f64f17cae9195f2955395e9ddc7335c441de9b65a0e252f98db17a805ffd0d0b9a68dd6be098107f1a6f7cd1292b2d6a9c23cd631c62709b72eecfb9fcaca2a3ff036984bafa785722c3fdc8398479ab77a3e1678c7af85f75f7a2f4f54a13ecddbbd4aeec7a96445c885d12aaf236a9c4058e3e669335f5fde34d6905bed45cd741d9a08f8501706d03c7f98b2c7214eecbf4759d661a32eb9c302a9c0057ab734b46dc3575ab42951298b59d3d8429339fb58bf035173a84dea90cc6354dbf68d31 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 13f936517eac73d6776695c1ff3051850e32fab734cc46c280e355dca079ef3949810e7edaf19c783c187d0e0c32d074fc3a72a276ffc405837aaf74ec5fe5659ff26961531c51b56fbecb6b28455e78ea7f7237faad131659d9f290eb69ac5bd8f54fe233561bf5daff85bf9d9182f9a2a9015e07fcb95fcaa72617e6c0ce81 +S = 2eed7fbbf583693f63e22bf78eb4d389064c21c37b66667c1b1994934bf9ace14c30279253e9195d176535e28aced6719292b064f2cf99124d55b347a14c960af52e912afb53356168d1f19727d19b65c5090c4db0e4fa9ea0ee3d3f28ce0a956f7011765bb5e58a14b8854e58e04723bc73de96278c78efbed70ebc8052d3359ba967dc91b1f982932baf770d2d2f252f37d274b9131e8c5d4607b67115bb18200a2ead70c6882ff721284d0d0876ee85e68dbefd4e3a9d5d898aa9ee6d2195c822fa02d74ec85d7a93d9688fdc5fc0c93d9c7df6c1519ce1384174e2aa5fcca3bf92e260274f2e0430ba4f008928d6ece05f0ac5a26683ce956fb7ed43f7b5 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = c81e98ab21239d9d887553bca6ecbc55a1e4593036f8e670080d44ba3793b79935075121d5bcaed3a5dce2c17ea9b0f35909fd08644283205602cafaffa2545a23ab18ae889a33f04ee0d9ce7f2d9109e7eea21b2615c81c03182ce6033c93783b13d698624392bd2a8a202bd0ffc860f29b31afa2f71c2bb85752c66ce8dbba +S = 36403d0116aa5bad635f855b1aba7ccbe7787bac4d2d0678fad33163c6a19e88fa53acd13646466ba5e11668752f52ffa3333c59d9e00bdb9cbbb9e549a47c700b1d8be5e1a778056bbb0f4d0a3266cf5b78b2c8a224f460a20b31963105236decdb49f4bd3adad75b6ef5331cf0d54c91fc0337a5ea3d1dc94e6182b11d7eb6690096242d84c174a0c01869c81b193156a730ed08acb516da3a2b1646da3fc8742191e3620d813fab2f4288768388b5c2892ebe6a42b7047401437b625b7d87368991020aa1f4831088343c51af5217334f852c49b474fdee6676cbf8d78018061bf3c398a75a73503e868468136afc187ec1deec0e2a852b454befc60d9873 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 796a46d728d7d9d6418710970f311d92f5362862f71df0d47b3fb63e51c35712f2cdb8b205f3668628f17e4dec9dcbb0211d2f1d555744d297a9423881da2473755106372685d2dd5ab51bb6efd9499f1cd8f7d5fafb990b43a262ba593665b98a5efa0d92766302613daf7b1fcddf866ed14833eff238a70792dc6ce3bd610b +S = 94c00c47cfb2eabed6ce3b04f88e797b1b2eaea162dac2e51fcfc8b9f9242c0f48f664f0b65ad4305867758811fd1cebc244f026684835b451e97e6806ad2427700f2d9c12f681b2d601fb6ead7953209a0c47db678ce0075f34705e4b1cc414f74574b4028bce76a69e160ae8180710b31d42950b66f70c6c28b15dbe38915e8c36d7df03ff5494a1265041a801c5916ff73e08bceb792c536608262d60ec34f4d3ffedd74127e9d5b237af1d300ec58bd4475f05c568978860804818fecea2781c96752821cf22164b1b917f3032c58cd47996e3ff5284004723d0c27a3d6439da0cfb725b991601a801c89a77f2ba174e3980d7d3f1b342c4b6cd16121656 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420e6689fb887124d3316d9609e412b959be86b7b02a1be76f300ebcfc82701a77cefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = ac481c957d422abb5ce8a73366bba51b4b718d83ed3c59d22a4f0464f59f3f78ace6664aa5eeb27c0b0cb0bae8eaf29e828a04d1eb88a174d4a027bea26f49e6c47e0443437cd4b29acb2738c93f12e8a5224307727b376fb38fad3141a95a7e9b17dec87d75f724b42ef4f3303f6dc15b3e326da99b818a70277c06fbd2d909 +S = 3da89b974fb03b26a5617a391b68413d62d03b7cf27daa0024e7b0085c1f542bd82adc66102c16c57c7765b1bee5ceae98ed54fd5fbddc1dc37a3a75f5695c49dc6f026213f79cbab37093a9549465370b7663f363a232c81ecb71074166bdaed7a558c5bdab0a20aa7f5c1eff0258eea42374ac3d4b386586fda7913305a602c33b6ef6dca0718fc330530e65f44d8824b4d1e137bcd3aaa9fbf0e4079cbb02a541971ce5a25d8aa91918576bdfb774ba70848db5b78331c71c26c0682b812d03197970e481689c39c56bf1bfb2d7f4c0d5c8bbbf5b3b6537f48572d5f79788362a0a7172f20308cbdc64f0dd9d0416bf09c608e915c070f4bb444e3b7ea492 +SaltVal = 00 +Result = P + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 8603abf63e1dc6a957770c225394c0223874b3ccf069c315ee26a2761519d9e3d5fb0c0197a57f945b25d9369f11284f831b26412ce6bbe36618c2318db11042ad9bb27ae881770018e5af72b66d31d8fb7ea3d7440cf528bbb12f4834fc6d70550b27c7fa5cb6d7d7e0143d6051e4a5e5c6b2f602857bca36187021d2a3f756 +S = 27d202a060e759b168e451c6bda8a290ce96aa70eaad61e65a37962a766b851ad506cd68755341f4ce2858c24c27953fc8f85788fe77f90d17e7427f6e487ee4e41bf64773c79fc1472e89ef66f6cd532a1f485adb2cc3952a15e5b93eac7cb2585f03206733a142b8ba9465653e02843eb5c70ce8d7b59fb3b8cc2ae8d0405a714fd55638aca05b0bb3b5dca25dc7230eecac2c8fac049a0891e1b986308814486dc9d076b780b30f1c2a9b8292d2e3c56ab2980c3b3cf87292a300924c30bf2633f272deb8ada1149d3e347f930cb5a4c7db035352915b031f524ff07889e1abd54ab5ce572c63d0ed3ecbb522e7a4d087763cbb712eb44ff81ced4a9ccc3e +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 44935b571d8e202a7c257defda42c57a4cf3deeefa104f7fd31e9b7c7f73ce8c959b55380ffb12a9fbb4b0b373ca3413ce86d5f518180ebac081f1f791b0bec1e3ebb42813712701305ed3e9f7ce7086024587103c4f831098630b68030d8f94974d212f113a87b985ea8e975096a15b4ffa99464efbd70bc38c90d6bdd2698d +S = 64cfae08fc369c5dac6c08609300ad79ecc260f52cd9ab810d536f776aeb9158e8745474c76ee9119ad1d3780f0175bb48e239998e0580272417f9129fc778f5679d277102551387e23ea1b0602b6617bd323deffb2c894e24d6ff5de645efc49e9165a8cb3752dc59f81e0e205eda79da7dd64baa300743919969a1a3313c2e5b211d9bb3627cf6cca4f406481b95bceca64c733ba51a04bba15c7977bfab4a776009b82d152279bca00699c91d9bff0e1f78e3a81e52e2367c982a421cdddd7dacf0b888c36d7b9ffb3254f8140fb6aca60138f196b1c65690b40476a371ac2f62899d253e730d60bf62559fd4aa3196098a0ad53c98eed2a0476a4b51f264 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d060960864801650304020205000430bbbab81643e08d7a9d84d488c6845a98389c05737c2c54103cbb497d3291a181a2ab6b4e5c376b90bae7af4405e178ddefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 69ec7262fa272d2512fe9281a0aeb2ceeb77a0692fad31618b0cff731a4cb43961f5859ee975fc952c6ffb0bb657fe19843ca07fb0e4614e501ea6e49b54011d4d60b3c84da06f588d4d61dc32086f32f6b6bf77ca8e79c1bf70ce1126793983f6d404c86fd30fd6fd3ecdde5feb8f7f088e0539c6d30124a1aa7fe206e2e3d2 +S = 3ea196268020d94c900f39ee2eca7e735e0cb478de58836b575628ef46c5e78898c2d76c7627fe36baf3eedf4d89c2572aa3afa8cb8c5ee3433e4c2ab7abe8369047d21cdcb00e1467ccd60cd2bbddbbccff5a7e0f1ed9d2d5fc4fb587d41ac538e66d9b559793e0fa8e44ea72e9c603d236f1c82c4ccf665a5337fb797b001ac0f4acfd90e54d147cb196f4169dfa0f72744bad275a748f4b402bb2cb2ca9adefb057a6400855483bb12c8e51909a7241f413ce7d84f42f8e4032acbb4a97848a0f2a3c473af3f6e218100b4d446616d55d55571c0fa9e178f502370008317456318115f8276aa1e569cf364efd5c7de9734eaa575802b0db421de6309c175f +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = ab5e706303ef34f4f855722eb521454bd886ea281c677ff935b40b3cfcf7bfebcc2a7cf62ccc95f0ae34d5081724c43cbfa126c93b02c5e63a4870b1adad446a2b802adf932fa127f3a6be93a8d770e2c79a09b4bcb8fa423142de4b3228bb528e0684068041e2028e5333b6b263d4a5b8199bd2e7b0a874e34d5ef1d28fac0a +S = 94c98efaf358dc0ac76b26f7f52b6a9c35bd8b63f9517a5b679af3cf3c48fc4ec99e5c75e7b1ef27a4dcd5443f6f4286d798cd96f746c63c290e501938196421d691faf84a5009e410545c407d920b14174e66da700b457b8a8e2e59c094e33ab1f0b3a5a954cf814da7587c95681d990ef86c4f67ef97f2ebfefa600c190a49ac88cf1c6bcc8423781117fc1686da1ed0032baa42d00fa62c38f5d3d27c355eca2f4b79b57b54b7f97c43df57b546f2391f5328ad295a16b1fb6d5eab36dcded973a7f34a0c600bf8008b96b70a3e8ce0d706d16dc2c1f298978c95d4823e406f433a48c6c98e41341704abb7860120db033591eab0674e1b2f998e58926111 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d0609608648016503040202050004306234baf47b7e2a2b38f44db0a1103dcea4fe9e2f3c6b951228d1b7bad3672f8bf772a915bc9bfc52d1e5c51165c50adc +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = d2c5b7edd8611a62e537db9331f5023e16d6ec150cc6e706d7c7fcbfff930c7281831fd5c4aff86ece57ed0db882f59a5fe403105d0592ca38a081fed84922873f538ee774f13b8cc09bd0521db4374aec69f4bae6dcb66455822c0b84c91a3474ffac2ad06f0a4423cd2c6a49d4f0d6242d6a1890937b5d9835a5f0ea5b1d01 +S = a524f38bc8b2104d55275efdcd8f1bf9d529d9565a757df8b3f8bfa067d5278721006eba463365945b81ab4a504122021f8234051847938ab3eca24f95e4aded34f9e57a7b377aa16fd9379d0b703accee4aa78a015d0986e20c4fdc950a579494c56eaef8b812e2bb0182b74da9f1c0e1e3b56142481d18e64fa797293fdbf7d8d54c44524fe6b957a06ccd292edf0e0353b96e047813662a7326c42c8bcd1d231c6a486699b756fd1c301b1891da6d51a3e5722cfa46592798e91d8df31cd98a3dd0b725391a4f9c6fa1ba312471f8d1d85519f8df7ba66244c5dc679a1348d2d415b8aa22b02a9322fd2469f9da475a8d832862e6a0cf24eee957eafc488d +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 302093a4a99ea31b8a693aac1743663b725aea8e19c1e35fb01dabb001a1fe5f413c5bfa9410add4d4272b598e617d9e4eb1203d1d890b5f4793931a62a28cfe8be8b1eaf36946249baffba95bc014c2294dc7d8982ce5899f09bdfc9c583e71988d5b1ccd90b433656b7246854672cf8a96a70a9391b9063fe5f2fcb8a95be1 +S = 2efe346135008623c56353482a684924e55455e5e75746707de371b9b14ffbaaf5b5f2ed85bd7e28ce4e1700af5014bbd315c32b872d567ea214af56e8c3276cebdb0f597a6bf2b0758ae2e5d1e2e9334a53f838c668bc9a1503010bc5cb97f6215847802827ce9f88cee4233cc80a1afca84cfcf7368e4518e157f05447586cfdb3ad9b2d79bba5a6c4f7494375472fb9075d61ff42c7816e23550f1643b758fa26f4377dff2034f5e68c5889665341d482bd4175a286022f8346ca925e925f574cc961146c4e2c3e8ba12e083a0ad31394357d099c973a9ccdd4a7a6649085fc1d4a377911be767bc9f96df50f991a9a589c5d5d19c3b3e8fcf7127b7e32ad +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 634de10919c2ebf47f5520cccd2aa37f484201b015fdab5c4ddeaabd548f8e6e6625a7d172a478ae2cc6691c5ef8bca57ea6c2a586b84ff3005d6bc360074acb97b77fa5e57a6c75ef33fdcb119c96cbf588498b656b4dbc5d1bab8d65d83bcc1d8bcf4e1a4bae92f02544a1901d1738d570fd29591c8dff8da2d3e1090b48b9 +S = 8e11eaac64a60172d6bde00aff7d654c61661c4e3213bd64b6141294b3d2491bfba0040ba09eb060a14a9c754b1b3dc74dd5e6de8185eb1cb71eae7464b1511d0b302864b34c08b041528807301c01b33a4630c74b1e6fe829518962c380de8b9094f4f90178313a7d2229a0fec1a798056b871a25778813cd70b35e713cc83816549f11717e3dd4a1412251c1082df1c03c0def3ddfdf3d7cf1b7654e5af94866392ad32330f45b7e9491a4d1cc2ad64a3b7ebaac075cb26d5115bf9a846dbc29faa8302a5f6337fa2ba07f9987ce1bc729e67fe2e8172bd44cc79ea15ced0cb49039ebc4749713343f136b7c32f5760d403568a4a6bee7fd697b82d9d44983 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = e532de1004ff3af1c5cfd5459c14e3c07acef7fd9f0d731fb0b143b90975cbeb542c1dce5a4a70121aa5cee6187d0c18f8baff7e4b76ed94a9bb4266008e84b12b2c8945c793e8ad4244ad123448515df371e99c62e29da709d15c036b8cce0693ba8a3cf1e48a0a6434db91987c99d592791b1f895a6ba0f87cf956f1789034 +S = 522fbeb9dda25bc573f9112a9f91c17edc93e2768e3500b4e2a4686c9548624900f28c878fa71336798cbe95dad6c3905ac04e4709defb972c13b6a532b0f827b86a8c809699ebcce39f38d71612ecfbd030d320d709edf5a0b7ac3f3ea49ccf8429066a679d4a9f42cf2e21bfb2616918fd80fbb7507bd301a6c650efa802cd4b139f02f65408090dde62bd825e04afc720ff8850461d5f1444bc49ef8f6f4f06e7aae64bc0f9ef3beba8298603aad62547ab8e94374cc45f7165e08c612408fe29ec242b2db649475dc2b76debb660433a2d2af7c4f82fac4b858f0b715e1048933d54bf2830f6373e6aa1ec2f460889c33b3ff78a2344f33929dac1c728b0 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d060960864801650304020305000440ed1dda6011a1309b31409ff9a5f57605f8a6d33d91249b0c1e37bdeb6a580d334c89f5332a598379bb1f37127bc39366b275962c3bb9b888d6d576fe89f6ed37efefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = fcd993a231000dacf06ffd5d90ad238d5f67c86a9f61ea10ceb2995a2b31a1f7752b69c0f6571b48c00b05b537af40cfcf738f57173d899af7e5fb4635a5887b3ecb922524b15e8ae3ef721fe8cf42a0d4020c5f7d9101dd3516a597502b7822e023d67ac3f81c98e0850c42adf57327f57c082bd845980013ab60f681abbb14 +S = a05058b41fa7d48c6be9420c6372d559d466a85e174c272f7394cf3896e1b945ab8941462cde4042d1da2a8b4ef11b5de2c720595855190bd113d566d420b31d51cc87365a2b8d7be99e2ca792b94ecc5364cf63be7a16aaed3a723754d7491480829c0cc9fdc1791998f30ef80291aa756fcab57ff5f3e7fa2d6ab001c52e76efc8dc18f5d5fa2cc762ff863e9d6d1fd921376a8f20d4dfa61f0a4c389e42db2adb07d168d438d1ecaf8e4d62006a29d944b1b5e5172d99579bf03addced9aad16038997d2721f365629cc5b065f656bd306cd76a01cba35c806a476f47c7f9b50d211b90d882201bebac5204fcff51a28d7b95c12eafde637bc50a10a0312a +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 55268a860d34f9ac8071c4048c4d6b9e5475b9a89da448e178bc475122157b3828158444ce016206b21237a7adcc4ed7fa8b5d079a5f07d8f619a5d3c7a6465a339cf4de38133a534eb6e3e1481a03dd7c4e3cf723b33ab5030d80204bdb67bdbee463be1313897a9c844e1b27df929622e5dde10248e860e5c05fa0755be547 +S = 7150a5c72d046e51f58b5d2bc60886be8b5d95edd49ee011986915138b53dc6f1c20913513418fb9a5edfcf4a3a9e4c6302c5bff2227c81d447334c3faeafda5ab5ccf2f25da8217cb3acfc8778c22bcd1559180260a8d9a3df3b2e1c7f1696bde815b4ada1e44b50b500a0aa4b880ba68176aeefcf96db028383b124f5bc7b587c6c6a726e2af4cad35b85d25fc158fc44d34a5bba69fded3b37af8cab2c53233a6e363e153966e10d6c7606a23a51b9358bb964f49ea3f19af1c038c5a1dba87b68b5802fc75f8c68a5486479391e54e743ffb64c185286140db15fdaf51aa2c6173fcb3d60f736a460623dc351f035d546f75fa07aa496f65bd8e4a66913e +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 +Msg = 587e0c53dc96138e7a0d05f8bb10e6d7d8cac64a87e538e7154e06a2b53923f01866e12d3da2643b8b90576d1da9dda35d82cbb6d44d141640a385b1e781b2172c9030dc60a9043eda985c084a207db74a40fdda36b532bf3ec0ea4bb9295c2abc845f29ecb3dadf90ac7c93eb7dad5ac88dc48056247a29362d9e38d33b0b70 +S = 40f0315cfa6e8180e68c9f409917bf35f6feee875faaca6f63d41caf57ba81f1994e4781bea5476f58feae8681229546e0b0ad4f6965e08b8c4b5915a7ae72430c18e556c9ccabf9b2adc9f4a188bed3b70982ff3561290e90cee779fe0c0a98da503f700815b9720126b1c6764103df4e05aeb81adcd11792e38ff4f072b5f403e458459e2e40e453bafe96773c489a3b55ce8f3a2dac7b5fcfbcbae53d6b27fa9acce6c3d9da72c355e11e8f56290f75fb53bd41bd0fb822662d218c6e6b8148c5a058bc2a8855e00d7d432db7ec3207be1f106cd1497a55c46607989fc295426b2f06bd7bc4da7ed40604efff01f037450abc3a1e0a657793e782f8a2389d +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d060960864801650304020305000440f7868e28e7d36a3691e196c831ce747400ae162cc2850af22ee47105eda53fe7b8826b1599e66035a13e247406b04b27b4336859fa666279991b18ae997466c0 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +n = 93397894e668653afab24bf55c15071960a81157e680444891c42ac0cebf9ff99e3739e12d0223d62ea048e77ee284582a707050fd11258f27fb6a4e2b583ab37ed0799708e3379e41b191092b2f4631c974dfe81993c740f21bbd0d828ad398893aa33101f445e5ff02ca498b8a851100e8d50aa2fe4c88ee38be966222657f943f9bed73f018a4fd371d208c362cb2aa4d1cec9c68f8416ef00ded34f4a1ee4d59a8ff4c5b3deb33c504542dfbd772ac649c8313644a32205a602cb5581819e4f4a2b8150e63e20669690429a4b5cc77577295183ff6b760a1b5fb989f158107860751c7808c54c1c511d3057b5e9537e009576b723dc9073c0b03f28955e7 + +p = cd819c9501262da3cf149709f0f56e59c2783263e399819dff248ac9e674c5d1e281e2f6471aff294b6e1db918d1d52f20bd4777b1175440c9b40da42b1c6a0cb28e404ee6446d19cdf7559304a693400d94e826eb90772fec7835cec7009be5e6b09ee7052d0b8ed413eec628d4ba9ea2dba3e53fb6fb7491eb3ce3bb16e88d + +q = b765ec141594c3a8503df7bd3e31264a88bf76ada5d529ef0969724a991787e8630cf8ee8c223fb9894c98679235139a5424e778e72309f7ff60fd5766d3edf0aa21f82d13c1ccd9d75d7799917b7abaf05c1f2dac240dd0bf3c1af0d1f5600bf46e93da91bb36a7031436e305b427af5a090b484a2c0a397d89f92c5d9c9d43 + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 16ae604b3a4e9c7f1d616e2deab96b6207705b9a8f87468503cdd20a3c02cc8da43d046da68b5ed163d926a5a714a4df1b8ef007bca408f68b9e20de86d6398ad81df5e74d5aaac40874b5d6787211ff88e128cf1676e84ca7f51aee5951efee1915dcc11502a8df74fac4c8451dda49b631a8fb87470f0ebe9b67449bbd1640 +S = 3a0751f873595e6c75cfe668304ce23e37da8f2412bef538256db7333562cd7b7457506912e176b8af543d5e01eb9742c8a42d356453a9d2ea9b78d6774144e3237e8fb3c0822c16a5550cc8dfb52af497df73d30643b4a8abe07c8e04cb165909e030faffa2429089ab6ca3d88584a0669e4955334ad5c7d41bc5efcb901f7cafe0e31552da57833d595fcf955247545cd057781d58f27c9c1a835f19f40deed90628de42de3b3efa4ad1a7311e67ee3354f6234e7aace3d39751a84611ff53d3ba70a552a78c74094c84cd401eab240aa33bf9c1492d1e173750f7505966ce83fcaae886102cd139f827386ff3898e7a1fcdde095cd96165a11b47ad5a43ca +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a050004140010617ed97007b337d2736ef686b8bc4f438f2c +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = b3d09ef22d893ef3cc09eaa9b2777e982a84341ceaa00d45956f73e484761ce6c61b31e165ccb0edeb7e0fb5255922ce27b13e4790399f8110730740276ba8032fa544919c5493d583cce5eb593a087bfe936c46f9ca85fe0646715bce93db6bf5581f2a5989ae5299ddb574d583f948b5110542adbd88657fcff95c01567cc7 +S = 859c4b66e9843f82baf341875b80215e16acedea013b10511a993b8407d72bd5dd00589d4016dde5b082f8cb0fee5f339d3e4167ba2399269e215afca6ec2c1ec3d572e214f9513086d281a4ccb5890d75bab00eb4bccc44074de6fef0e8c21237f7630557374da6779889016709aec7fe8c2999d14cfdd9a617bf858c941674737cf0723f146759e4aa691f4bad8af3296027f92fbb81476587f76759592cdc389a34d06d2bdab0bc87742e0013a11b571b58cc4990828d374268995b34d7eb8c09928efe0204cc349c83f575ff70ff3d4ffc9026561ce0601f17c8cdc945a59b44d8323a8c3dcded6158e880c7e1a214c2d3554e814a0b9c64f35724261452 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a0500041486b684bc197e2f935d2cbe5ddcc6f94830a4ce21efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = f41491a2448f0abab25b9f4958b6eb93343282e62dae1d2e5485f7c369057685a1230e2ba66c63d8e03fadeff33a612989f20ee551e784bf48b73c633791f4a47ced9ac80e7a6b26bc585cf4b588b95a4da10ccafec44094add106b52fdb78f00cdafc2183a06ccdce0f74fda7883b4d0aa645403d2d98d60e3d1d615ccc4a94 +S = 81007a0eaaab1b6205fb5579a55d50a7d7b4bb077eb0cdad18756b4bddc447cc6f1a427cfa32100cf5c0c00db6d28c371059e6341d947d843722ae8fcd0c81a4650fb96857ca5d09a270cbec62a2fcbf997b67fbae0763a5cc28f526c452b416f25fdca7bbaa82c966e7be2a5b0866da58b05e024439f15428b0815117efb9c08310e193e7e7a5f2371f7c2c2edd17616a7fb991c2e173b7fd80ae4537d38ed647c32dd16129e56600d32418575c608f360368b750faac157a3a43ff665a5ed5c545e07f413e9475e7d79d542356358f0c554cc206c3880406447308d1e0d1871d90a84ee4a43152488acbbeb7bf55fadaf3e8b32e01a363ca8e3935efda1e43 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 7cf8f94a517da2e5f856e8ddec29ab25a1a3b1faaf0eeb193326f92e7228ef8fc02d5a2aa1b67ebd2d88e245b9ba0fb8b30c94f6ce7a4dfd5f11e55d07029aed93f540bb209f8949839783f6e86562bab8dc8016c1aba24b912e7dcb228a79edbdf8b4e418614af2c22cd4d9c0542e9379bd7e42cfc8716a8f25c85e0be814f8 +S = 636d180a954780e947e916eabfcd4cfce80dc0cba1cae58342e142207fee42f3f6655ffb6c78f89fe1d2f31ed54e991d14b814583e8c84723263a22734acadfb5bf00dcd6df8bda4ebb3927a36b13bca2991094f1f92610dcaf953b33a4d1cf571085e297e3cca697e4aec953ab2134e23e62d176ade623e3e2efa562e7e0a87fb7ddc3a169325cd01fee10b2f6ed2012b9c9db99089521d2d15a15da86fcb165501eaf454bb36c8798e0476f59bf2a7d5eb395228744e266198032de0afe58cb10f81dadf57dfad47f764721e54f1248c00f98d7fd2fbbc5aa0998b8a480a73df7c2eff9940bbf644cc821ffa9bf570f2b24c43570b81c103cb4d0c39deb507 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 7ff7ba5d5e8aa7de3ffc560672a9c1b0f2eee1c39a8d7fb89553475617f81ec04a46b5b28c7d5e08d7f71f80800805c02528bb9be1545b90c1b184937c73ad115efdb92e8649cb51518b5be216118a52146eb25ca8d7428bc4cdc9fd9cfd5066a264ed57b5b695c1950132b59b8df56da708ee9059dfdab284ef3c1adf5dafc9 +S = 55fd6153dfbdd9850218c3b48a4f5e74e9aea999b7e0bf0514481f29b9491d62a4a4dbae2fbaea27cd4dea5ddfc17052d3598bc329eb3ec437d1001387510d7d0288cfe298cc5fd9f7b91c887d41d81d6685853285d67e874467c036d52be31ee49bfcaaee129a3cda168b59ffe523ef64f7e972cbda2afedf1a0fe7c6d457d79d9a73b7424fe6ec4290988dd81daa58e1fed69ddec52f8482a27da34b70114cd07f04591c5d2a38eefba0abd33d4c1f500a4073eafc5199548d7b96c772cac71cc02e18fa998f143132bcfa5e44f2dd62692c90e9a96b243ee20310fa9fff790b04a2d8811b46c5c97e66dbd5e36b03aa290cb9ae27ba94018e61430eac223f +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA1 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 3b9ffc79b59b069fb97124a6c13d51ad413638c1e8e09dab2383f90be4db64aba111b80d9feaf446703fde0fbbaded1a3b8d65a20a26c44620225d17163f43f0304768069b4206bff3ea3ec8095f0062e21c2afc032af407eb938b06e21afce4f129548b320b05b24a5b8cf633bd512d3fcccff75953f4958ebfcbffcdd45830 +S = 7f2efdaf79621804a71b9fda74328b00a65d949b26f739e1b9755ac860c5ad7bf63453a572fc54d6ec790230ac91a150ec428c252f2f8e222625b3e3e65e5abe5155b55da30fc2a89e22101f15a841058ccadfcaddb5405738d86fbbc85d82062dc988a945fb2afb9a9c4d52494f0cfad39f120577931632c31a63f06a370d1150aa4a45441bb31ccab8f7f742f5419a14a302ee0c558de496c66002a02266154ddf2b5808e33b920493e5db1719c9e6f7f43a069455024364988ad622d8d61a5b798a5f9849cf29a0d59eff8459ca65dfd0ea1a9381e8f595ff72d59bd86eb04afe1c4b61c239a746eb102effa940c011321dec7675d99ec4d03261ac254602 +SaltVal = 00 +Result = P + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 16ae604b3a4e9c7f1d616e2deab96b6207705b9a8f87468503cdd20a3c02cc8da43d046da68b5ed163d926a5a714a4df1b8ef007bca408f68b9e20de86d6398ad81df5e74d5aaac40874b5d6787211ff88e128cf1676e84ca7f51aee5951efee1915dcc11502a8df74fac4c8451dda49b631a8fb87470f0ebe9b67449bbd1640 +S = 13c5d85a48e10871542ca7b6c7f7fcc0f86da6e9cca9fb9b8f36f30fdf2f320b61b73ca1ef0b9c07af8e675f32b7a648ca109885c006971e821f09a489d1f8b79dd2d03a20b5d9c02f0117bba86ce8b419c67b90093d89f2631dbd38387a847b9490ebbfd7b6818f70e09c3ac25223ce2199030df51bb5da8242d1dd2396c72062a60f481c73a830c109e74b9fad92d7a9a414643ccb2e392afd13a8deab2b4433b0ff5eb3c01892c71a00a3e2d1173506b6340f57ad27e54a4bc5e16d50de2ed519f300f2afff9bc2a39e42c70a0fb02123db01500bb79dceda3a33b915ba095fc1269542832386a19b3ef65f56d8bf64ee4c83d5411bd0b6f097a749556917 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c35674247cb0e952ef2d28bf3e3c63c34d0ea8b3f194941d3678440aa +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = a9db46f44d85c4414d15a62541906e6ae498c06e2336191174d6bdd16993f13485b56b674e780724a310bbd850e9cd06e03343e6b39e9c535062bde4fb832e588b538637763824b62eaf20dbb09181e35996b1e1fc172ea7331881e9f28574a062bc80adec4c85bf93fcbe768810f3c9f8c7f0a5292837d6c5fef22b76222bd5 +S = 0ac7106eefb290dc2681c447fae564aad0e73028927907b323a7e1c340efa53638349d3ff6f9bd393431f085c84bd5a447a82ac98cbe6100eca7becaefb20fcbdf3c13cf883538e39a7c47c92e0a0da716bf520835156c02ad30d357115e467f9fa1b869ed1e6e1736402c2df62276cc766a0916ccebd7854f0b6f14e88de01164491ca82ed831e6e2f45b636b4ac73a3a0e0522cb47ba1758dce66ffe9e6afcd09ee6820bea67ff7351a157aade87d7243e68d3a14824b07c0a831260fd4b21020ad943ab0aceabf2fd259a038d30f786ce3a60c6fa68a5d7b1901380b19912a7eb61da8a224b9f0d2109bd161de1d3892d1001cdda4fec492bfd1fb0050039 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c062e999e48e75ccabd60ec5e67bdede1b8beb5c89c5b8455d638b0f5efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 659bd5f2edf90ba229a140bceb69036750477ef4f4ba4a646565882ad8fd2d321b669d21cb197cdfc7c9c053e4460b6de3a1396aa09134538b1510c75c5b54fb03e195ffdeda4a432fd3db59cd96fbfc1a4f385234edd06e70cbc719049036d20354e6138f041dd64a07b8580d217a1ddd98a4341a96c6bcfacfd4a736637cbe +S = 8742d7f61cd01a1cda403f08a9f367dd2f62895531634920eba3de112e3e5dc30752533851ffdba2bb48905d3532e2a55572ddeeade4dea7f80664b243f951282ca678194d6b91a9fdbaee763b01823ca4037d77cb3aef976a90bcaf195431b3856c3b598bd2c0e9000970e49d0938b3492b6c710ee898fc719b40d0b5cd98a54de06cea29584361317f4d8adcb23b982479513289c4729ad5b39fedb2ba6a6cb83fff0c2dc35d8997b9bc0d8bbe45857ffe3da67655cffac7c89e33257bb08ce3d10610b53cde7d8b31d721ea34fde8f798cf91a866bc0a52a9aa03e24454e0ab27f7cc00219072b3cebd9883ed1fe5dd02d4b59536488931d5c6059794da49 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 25c6f8cff7a49f5c0b7c1f02e3d4b8935c26cd768f33e79dfa9bfdb6dbabf3a6dd766033f62794009095dabfe718faa2b29c021205f346a47670a6497fb10fc523bc4562d44edfe5956f93c15c4ab38bba3cf8aebd2b7f60161911d477f8a7b13fc02dc459c087f16131d2700911ec36bc2f36b0818298b721bec6c18c29c254 +S = 44e33dc3011088c96cf066e4a3b93487d86779cc770c43e7a7b5d6b722cd582ce8988a28605a4961645d9bfcf60b68a83d8a5f2a85dd07f358715fdcabcea43c2816ac12771e76e54c14fe3073e1eb43312cd0e2fa0c93f07b0c215220c59379121aba72fc7e13702d9152386f6554b12b0323cb42d09ac5ad5f065fe6b045e37812a55cc6132a6a9dce1a7928a974e3e35213719b3175f96ef87dfb1cb84a67bcdd5f5b15fe2508bb6815809404e0e6b1d88da4d7202feffbfbd76010279fcd4f6fc233b27a934601c4e3701fd00eab581fde1d2aee3e27ae9b7b627e208d013fd0590c3718731c19f105258acdfd10fc8c542982e6d86b7c275372b8112fc4 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = cdb5d9071fa3a040095d41253a6a8081200ed6f4aa095b455181eaf9593c7f255412e380e9a28cbcd345be172c40f72dec3e8a10adfd8a9ab147e9022524e1aea74e934807e5ef144a64d381f5d477fe883f080e4868939f41b925988c7d31b1ce4f318701d290f077a3c88b1b8cc89cfbfb981703b23ffb0bbfe5e115af35d5 +S = 1dd48357b45763f1bea1c5a7b0f346ca8aa1ab19b163e05c78128e5f9625a22a7b3b1d8c18763349089725fe41f7431bcd42b965ae6f7dd00ae046f7fd2161d344b471dee5ff1d9fd4d5c520a6facc3bfbd8650598b34ea6c94d684b0187a2437c529e4d6408852662fe70c807c1270427b02db59f04b8df01a087f3ea9e3c80894763de195fe7f92dea8c70a3bb85864e410a4e8313a836e47fcf5050090742fbb1eb64703d5d599fab43930bf4b8a916c134f4984993e2723c4a5814265c500da5caf709143899c5a5d8eb199479aa0cf68366b7e80ff21d1352bd2bac2bb2c63a8235a379b3fb3baaa416243eed20c2c861e4924b71de1a74bfc96a85ad74 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 14690026e93115e009238306861b8968408c9f320614b61afe54c1de47fe74eedc2f4c65bc00cf3e485815c5ec04874b0109e71ef23891b99e040037fe91930e080d91f9d3436c36fb6d42f2474aa9028971acd3c6e511a497e9def2cf161b345eaad8c97623722fec0d1375e01878f3a06df738ca42c044b1ac63f802b592ca +S = 0356405c184af63e2f550081e8dd7dc7138bdcbc44d22e6225bb4babec42983f0556989ebb8bd6df4fda3b1a3d4abf2659a584ec0790379c74c7bf156d14531939aaf920fb9959d5e7cd0d2fa4f86c8029e6271522faf29499d50bfdf1b20e68de2fe4a52a84db86a39491e0e599935c3b726f6b7b876e8bbc633d05ccbb3aecbb9d1e419bd2bde528f6a7ca6ab4c9f8638a67d9aeef1491af6c5fb1c29f76a68e981bccad09d3eccdbb2fe5d44a9bb23a10f9a0fd594173b126fcf145ac2a3420e78b6b195ca4630aa2a48fd62192f21c34e8885187489eef8c79a67aa079fd8d2811a5d41b73a1cf78133424943b3414dd183d8ad242158e3c3c956185a153 +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 266a05f02ee6137da278d709b7504bf55978e432c215c5aa4cea34db831d4ac57f3eee07718504457b5be1ccc51c0279cd1cfed7fee8ba8785cedce5609f82e8b7b3334a702e16e9fe82616e7935152cf4e5e94b0b898325bbf9eef077b1499e77d1bc015469b133d2f44035fc22ead677db8bd610808a4c97745345f0db07ae +S = 598ea4dc537da91b6e9593fcb39d89f28fbda380f1b42858666b6569d40688929ced67f6df07eb58bd984fcf51a72b863649603b6e3be9f99cae28015959ba7d64fa4c0f188f849774760074d46131a5b78b712d50266feb110ab034b62bd67b38bff88eb5f04cc174c8c9e2d8f8daf6c33038a1a10088698fa09b6c397db2da169468fbe2eed851ae1265cfc05f19642d8d6ada114f4ff065e6b7b132d3cc498ed23ed4317a3d0f5c5462c9afd7dd196faede84f5f8e40b3bc8913797f1e23ebb3aebcfb23749207c95685ecf0e3f164291c1fc9087a49c88fca0b4736c7c86fe1a159b6b34dfd30cc626ef4c458f712f4a879a730e8fd6b2e075cd02b96011 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 58718b3ba6a4ddcaa7d3f7bd46cbca5591f95d87741fb852c74b004f8c0ae38a71d937909ddcddc9a8d3ec08eb490b61fb0e1f3b70e827a5eb8663ee57b5bc6f6ed760ac7f90ad9c6fc25044ffbcae8b4cae83499c60c8a15724db91540adac756524fb6d72713ea048a6c98088c797a8dc0d0d980f065ec150fae600c6f0438 +S = 29c5a0ab72d0219034ce32ed330a4b388573eb804713d98029fbc1da87a474eca1f1814dd61e26c7bed630f3a4f980734321d56fb3309c751953a4dd9110c293730829bfdc83cabf619b220818e30151c38e6bb9d304eb7204029f8af86209275b1b5fb84bdb12aeaf3013db78d6dc1bcbc23fbe3dd7eb3c3bec332c8453de3ddd2e39cadf7e062f00a682bf18ab68ed3c6bddaa9dada51c99117eceaf6f8179eb9a59e6143a56d5f26d4138a5c31e49104c5982cb1b202253a292786cdb94a2b383c9d96afaf83d52160eccbc42cf2568744999a662097b315ded7fb417a823e3e9b6c5f7a822bd58a4e5542fbdfba63f60266c0b86a363153ae0444e0ee1a5 +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 35524c5781983f729374b6342099239157485a64b9cffd112b50386849c3afcdfe3eb5965174bfb5827d189756d5d64cafa60ce75f4a41283e0b21587b2e73752f314b8f38508172444e61852c71a4f284cfa00770c8bbddb8d425371f7fc7acf1b17609dc336df1006ffac6497777cdfd497c8c91525377c130accce0bc92bc +S = 77fa540194591f2d49a7740936cc5c909e73e970fc833bd8031dbcfcf78599095bc8d185cdf681c4855c4e4527a75c5552ab3611fa7788c424c3b051d1236fb1bc3e7b65421cbb1982ae623fbd65210035c78032476df3d64c8e8136c74c47b694a881479608568368fae8d7374d32173240e55e074e4a064f6309df823269f2a2477a5bd06c819b67d9c5f0a8720af431c3edcc85a1b2cac7d2288d90b446b62cb070d1cbb87234ec41c55b89318bd852aeb60779246ffd84532d08ea27e27347c7997e7007da4680f4b7872ab89499a1b0381c4837893fd0ca055bf1f0fc4b1682044190d40e7cd4b6c077faa077d27cf5a9966e95d6acd89f1dd1a61a8a4a +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420b7cc7185c6cff2f0237380831075de8079252edb588ab3a492e600abe24dbb7eefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 31dce7cc7c03a063b9879e0343e9b6461db1992333a941bfe34a8f86bc74327b8662cacc82dc4daaf3aeaa57dc5aad810c0a23ce58c83eb828f13b9b35e7410c90078d6de7dbccbe0490c8b696aa471334f6302e9fc0f0d247471c4e116e58c958b477d63266e449f4144048f8414ca59d5e0a6b90fa1fb64a337cc8da703d5a +S = 8be14c18fba2b95cd0d0fed4b171462b07db0b5e5edf5803b595182e97ac814eb929be28d18a8f45f837ce537475fab819244788681676ef73930ac28062082b6a593072b2218862a80439a1b9e2c637ef9806463c7c3120a01473ffd9df2152d871b83d782baf6512af6979ba3a9b8d68828716539c771161b81bdd056f7535e2cc654489c90ee5c1366609c775c760cac8d084ee6d618d25a70ef64fa631c0c4caea75296d97237da8c977e711374620f232e71163d2a2515d71e30985f84a3d4839f4367a2d273f0477bc677dc830302ac423364f4628d7cba5b92d5c9f37de4268f8d957905072f2cbb7249dad4f55909e41e4edce618535c7cf62001f52 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d0609608648016503040201050004207f3ac72d5591ed16096abd35813dc29dfaa0b834e2b57e45315b3731b4d7292f +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 2656ef08c07fc1ec469aa9c73b677af225a9f5f6f8d0e150d1d65e71e6677609bd44f5859de97ad6436ecf75d5ab76a41c9f84f6ed13b311e87ab2b3661cbff3ac7378ca65d5eed14f54fc4c34e3d7681cbae5c1c1fbd3274395e2a21d6881b358ab21ddfe8b4564d215d8553e56c4c68dc1c05f5ad1691a48ef9546f495e4d2 +S = 849d23a7f9dfd0956315dc9a60c04dac1d7db660c67d2ea57db40098a84d258b111457686821134dcde66990015e769311aa53e1920bacbf59d214beb3fb79cd6482601f5ac3848f90ebe864428d0854a245c1a51f40b10899cc08fc4dcaa6b322fbedaa7b56db804009a0829fea827065ff655c1f82497c5d59998c8a577bd5e170b4734b7a24f574db4ac56fd7cf96039c594e9a109c10185e69102e27105533d826d50b5c39bd964d88ccd2e0a467a668ce15a84014c958723ce6c09230bcfdded9839ef40bb5f80ec2073081e5e6565454270937b8cff537c0b065a923d173ad04a31592fe699e2424d8bf6bb0b947ff161a33b9b03fd69892a0d9a8c711 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 1c58bd7408d1d2ecbab294bd48408178d4a95be7ca3c89e963d8bb7c6ea5cd1c4f03ee4c48c00172f78e43e720b42e4fad039e26f30c339c3790f6a371383f464f86d63c7d0c58bd24dcdc94b13fd776d7aa3d92d7ede969ffae3fe07016109325cabd6d311da0764884a7eb814a42945a848052fd4875f8c21ade5bf4a708ad +S = 60dfbc77059709311bfa31a69dc9db4703d0fc44d715598afc39331e2620d73423f2cb8026c3dd9a133a7c0a62174448128934c776616f1f9bf12c3936f52340d4f034725a759cda95a743602805f0fd7bb03a8d6fba9947d1692f6e7615ae3b89f4251542f5c902f41661f443101da8a666654c86d3cd8aa93733d677d6c4e83b527def0db12bdad93feb76e9bf986a1624834de5febd2b0a970db189c878bd99d3ae86decfd0842735361bfb1fb0cf548a9bd43411b4be4b8db8db1a585555d9fc5066bbdc081ade816777cbd29723062ca7709429331bb52a2e5967948d1d6aafe979a9e12cbd20a30937bd6965d1a04e3060f72a46fd3af1127dac637a24 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 47611125ef346ddab85ba9493e92eb1566bad85e9d17f99664bb63900b4297dabcc0a74dbcf89ae2eecf12c899002cb36a10a876bd854ad418537f93f89744d3d187449e50a940c0e344b4d97b15b8b0914224ca6794f73c90e0fabdb2c6a0ff8b9e314032b0271c9fa3d9a56e3956b5e039948323acca75d34b1a35c0397307 +S = 2fa1aed1f8b9656c8216c2ea8ba98c67a6d52cc143816c7f83b5f72e572d6953c28249593bb01332ede6b991ada2ea1004e594966f1aeb2fff14db6ae311bdcf439c8c949de248d7870b0f9f3edfa11705de95b552d3a0bd86fb52476981df2cde1df65de3ad7b957fd82b7f98d8c6bbd4b7e2b65e143c627f5e4d2cb871326ced2f904947ec2250c5ff9d330a74a480afd38277909d4d040781947302ebfa6ecd229d93b5261eeb237dc99b9060749bfeb189f99e0164ce36cb0b64935e52870fdc8cef93a0e198465f48d7ffd87c9bd1b40a127f0fca14d559ceecade77d30486cab930ba50a3358269f641ca11ccb30d3fd21becdb50efb778eb10d424b76 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = af84a31d1c08faade967cbb5a016837fb2d1c0bc5eea5b75d4e2a6449b36f2c3307b5545f0adaac437c5d81bca89587572a8f106ea06c6f9fb5593a9e6e5341302bd678ca6ead2af4917489ae85e485aa95ec6a3bd8e2ec48ad0a7db0a4a95456e71615908667c566786a199c43d5b149d1ac8fb9f299cc0c97d6842cf0c1d42 +S = 014773de1e3486a2d54c7a0a0a1a70caf61ce94868902314462c2bfd9c640de7b499578230a41734a1822cd0fde610c487c1dad10e35d70136cb162d79c403c7408cba33b72fcafbee2dffad251ecb6bd4b082aa5350b194c587b8bb1ededc902df1e2e6eb03a5744c87ee49e087759237ea133c8484d62cf142344b56cf3c5e1f72998c531129f66e0458bfd4e8b1de1866e76e3912f680bbf8a96ee4f2971e6fcf029788e0dd586db744a7f9a0010a2a27d98b3b04884cf269f19f1937e8612cfc5b144b7aaf9b2fb0464a26f4013de9fd12851c3f8c9bf1fe6926fe512e0543114cbf9bd86336d7d2aa6c2a696a3fd071467784c2cd8f64e8bcb00fcbc792 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d0609608648016503040202050004300c4887ee786dff1356756432824889c71e522ca5d478d9cba311b11a51dae49696d1f1f454ce4017e74d9f45cb17b797 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 5c95cabba94825969c306fef29fdeb104955f9e7fdc63aa29000f57d1d41b9d85210448d732ea480a2ca9c785df4492d485405a22d1c8cb4413b5ef3a9d464b23ceed55a8b6d5b041e41724601dd114c80ea8d2b2e3dba732c075303a74c9c22a39745cbf7eb924799fcb9021c9f8c977780572d08130c06d9cd9d552193aa50 +S = 019962ad704a78fce2306273ff3a649fe973dcf2dcd6d0e692a592f357c9ac459a15b0bb0ff986f104f99301c87579a321b0d4ab9e947a9de47b56c0094e4ffa6a8949594348e342f8eda30e68f5005bbf72cef70c522a124eeab1d7441cd65dff7e1ad36bca0534c09c284e8e931766406b43b62db89472c2514c3d1a6911a92e19a0dc923919daeaeec53746f487e06afedfcb679b531ede784d9d6072dad50348e1d8f01094f29cf5cc96f6c1f40ab455be6c98788e9d7615ddb6a66b893913ad0cc63a72b9dd357ce086b2df7c8a106c0c363e3e2317e37815df69b22a9d52d6e5e47d8be17ba61b2b2019a0f85fae30e1d4f2622be50086848cb405d578 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 7f88a5d6178889bcf09ab7407a01bad132cfa7456ca0fc294f88ce56214a24c5c5cb9ea581c65aaa05c017a7a93f9b5ff737539969c53a72731ffbf7c4cc5af3ca10d00674ab75f73bc3244b631ed9177e945d1233c426ee3d0778e9b6a2d19f96408422779fa44c9b8923542f063ba0d1d00dda51078946b4268d537f365170 +S = 91584aee68fc0d4e7d24afcf4eade5fea0ffedc4d49d1d75e673029bb998ad170ee5d1d28a2779c846e617b8c9783119f4af4602461434a24c1351f737ae315868a78f615019234606a12e3fdc3cbb05d2f0cfc877b344fbecec5f71f0202b507df23e4a3917cdfbd1691fc69c509598e2bd7c71ac39a71a295ae0ed1531b97dbc6666ecdb830917f04cae848f8b18b8abf191091b07632e1632ff611432b7a50c0a7654d59506ac3b4c058eb16bb66174a39f933a4c389cc86c9c124a3246402928a3e3fcc8d35a817027c2c2448b792f2009548516642d75839b61c6e2d5b63c4ee4c0cd72e559be3cf0e466a4a566681b66b71089f67c1044157d78215e0f +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 97e7bb62b6d35c8e423a4c98de8264c14eacb2b12f36cc76e54064cad6ef1d94d60f9db2e1fce4f610c2dc6ec68331e92a1962b6dbfd19afdf67b877dcb734ff8a14264f68531f83ae1a3c138345fb5871884d4c1656ed921c02efb66b259cb59c3f7dc0b1a1b63d048a960f7e906b1709419bfa480bf0258559340febfffebe +S = 6010444309201677f71890ce09e31f671208b2804c309a85a401b275eeb5d234ffe5fc6dad17fd9781cb00ccccd1d1260c2d7090652add1b635633170ef5e9eec6ab240c382a3850fe0947892870d0424bfbedd434db4084ba29cbe7c8a27b4aa858b648fb0c7096db4dfbaed09fbd7483a2e9d8c409f87c9a2a26984137000cbe451140da9bc56c4382a091bcb171c3da5f9833fd224a429353439469a39033f2e1ea20283c643eec651952ac9853ac15a8a8751ce72a443b41e17e41fb86e69ec0620660f65361035441700652619c9248b2ebe5cd83c00bd2b232c13b544b470334d7314704dde6c81150e54e9ce132a5aaa3ac03a931113160e93814e968 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d0609608648016503040202050004307c1b2374e40835303155d969bca1d02f901e2569823d83b1b8ef0221cf4af285fb3535d60dcafc85b0b856d7bb9229a5efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = f167b1c5e4e480c6d96035630415b83c9b2d137a2ecd6efa37523eaff2dbb9416e078dfae400d1e349b83c2a1f7295c790856a5fbd5c056954c29c8f605cc85766773802ad05a7b5dde10bd6cc5b10b994f0c47ce959942fa9c87738b56e69f600401ba5e5fbe982be650c2fb2d61158cef8899757cb03955fec377397168468 +S = 6e2cef82eca498f7f1bb521fca7f11b31f1e80f5d1face48609d78b2ba79b8e82c6800e92d419c4c48b7bdbc6c41cc2b9fcbd05627c1f4c567629929022baa4ea1b431f361b08afedec6eff545b682b8d9a6b18bf62f34a1596048f5455f51d5496c89eec6e7f8431ee271ae84658347df2d1a52a5acc37b0b5eb1438342da02f2dfe44e50877221a8623b1d1602339223748df48cea785f94c5ee719e95ebb2ab7d795dbf53d4055be0591e203c6ef69d6b08aff07be7e546f501e42c3192115b5f2c259c4ab2dc585cf37dd3ff54e89f0607c5e3a2f198e2875a7550bdffd0eaecb44adad438b3d0ea810668eabb123baa66843d1a136b0369332bf74d91ba +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = e946af251dd8b043a9c866cb4f5e4b65e5a983b4587203e4f16ef982d7b76891d67d13da5ef99d83cfa3eee3f3a5d995cc8ffbcb914ce6e5f3557f43a424a4571aec12fe918786104fb023352b7214fb50e072263f07684813219591090cb1e73ffa7439bc69b311b156cd69fead45c0f805b06d6a8ad232da3a04140d55d86a +S = 839d586ce12b7c22bc2e0d921d11756a9a65e8275f61307b1bf1d6e350ac126a50c52363f561e2d2f8edf3f92b9fd88af138178ee34fdc3f4d288bb142dae2e5378c50754da25eb541dd80e83f63a356c760e8efa03f07efc420109bae6c701fad5b8dc8fb266e2ce1cfa7b71f04f63c692e4b0aece6b970baa77914791e8a25e5100a2205811da238a451f5a100355b28abd39964d43dc0e2b51a8e2ddba0e94d02ef11a5cb2058acf3f98dfeb34cf939b5bb0525eebb17bb25e517fe3eb3e04e04afa892f318618cb66de38503bcf994c9d2ec20effa04d68a0df7c76dddf30e88e1fdf5afdcb2dca0e124946e7f39248633b03166027611deb276bcf2c0ed +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = c41b35fc1669b8663a14b3c37c87f27c2d1b7a539b3b1da341c74be93ab52b84fcfeeab942b854fa4a7fa168411a9196fc5cbb90e847211c4478093f8dbf08033a0d6078aa938cf95b2818b05cebb65d052a8f52e583d7c2fc49a43c2a2a0073e80e3c40364188ead4d5c1a4b5428a57b1509ea27a376520d104c5e9fa3e3a5b +S = 2ce448ee7ebf21be380247cc3f8472e440f3911128025fef0adaac37d4dc977bc5f81224dde9df193907c17fbd624ddb51c2b54c214af57520d3f69d12885e3b47cb2c005c18eac82b86d5d514cefc99794badd609cd5cb8775cf685ec1ddf6acc0272a4a58311c348381bc24c4b85626993a601ae292b13c3e8a9c0262fb8deac28320810e776c196454be73d5ad08f780ef45dfaf7704435f2b3141ef32c2d7ecb1f26398a0dd8c01c39367987f22600b07979627b391276d1c444ec87e430769fe22ec3e1d5cd4df358314282d10e2a4098b6658ffa44c4135142c2661f2a80d4d380b5ad3d2727d0ce12f1e6d67af797c3480100ea50a0fdb0bd1cb2a78e +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = c069fe30bbe18aed9d39d26f4ebcbd89a9f18f07982822e5795372bfc7176089f623af809ec15360dcaaebd8f61f8c3b3d35c0783871ce4cfe943cb6e4b893ac589c620c0d3d85d559a6a797db080628600d7699076aa968a4b4adf76374b63dae7d1ebc507daab3dad30f9445a0b5b8da21ba524f3c3aa23358ce6b8c7252a6 +S = 5e67fa94c7e19b66548220ef4e07769ff75d4e76917004492334f0fa15ffb8b14271301c170e3d325811bdfc1dc53f1b4369a2c0a99d261d9de59a73efd4ecedade05da9faccaf35d462057bb8bbbe29e3f5d4c383908c0b25006f779399064889441a84e0ce569eb474ddfb83cda6be253743693bbd551f6ac0b8cfad225d5635972d4e508ae5f7846ee3adb61958ef53146af42d0c6ce32559f661a3c3a14068b8b488f85d7e5641e250bfd9975653ad86f93ba5e5f57f5799ec135d9af7c529e6447ac43b114475060150e98ce86df3f69cabfd5a59158f0f8c4043935e0fee317901baf27aab76a2cc1561d969bb3d69de65885bfec00a522c5010fd2ae1 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = d99885b2fd968ed1385f0245a8ec086dbf33cd903c4a1c205ad0303b4789c677d74876df7a1242396c80708b2b6595dd2eb1f33fd495040e9be8577492ca9b2e1187fa92a7bea8d054c2bb78f8403d3c0c227ff890b4b1ef4405b0571b911f19ed1cb9d26ce1e51d59ec8b14f8c52714c14e1cc158ee4a4abfefe2efcb2579c0 +S = 0efe5b7647f3b6bdc7e9d161afe8591fd21c818276311c4a04a3922e7da47c9ca87bdb8d2d8b8eb267a335ada64db1f19cc35c6b9bdb06589233a834f106db34b75284f943e7426edf57b63d3c23032fcef1cc871530ed003b3a62d994caf8c4c10a90528af67824f5e5267b2eb284c4310706aefe248d3a2d98e922c859be49b71c0278f537fea1586ad9658da5c59ba11b6abaf2433500be32c862796de6aa58fe7955fa51845fb4e304adec80941f70e27ec24f1c6bafe0f2746fa102040f2483ba7e3043469c6138adaf8fe50b4274d9548b30ad0bb048af103454afad3e536c2d95ae24fb2feb08ac0f469551edcb3fa36ca078a469c001d5637cbb1bd4 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d06096086480165030402030500044065183a0ec842001ad183a8b55e9118f29757c477ffd30f57dce02a218238e0a400d6a509c69a74dd64b400c809026e9e3ad8930f550b594be664491b5732f3afefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = ae898f661a8614a533fbbae90eb5e9810ca4a205b9327845f4d3dc7f51de9ed5bb9bb1fd5e9d2f3bc4529c8c3dd86f248512ce1ba1fc9a640a3babfe0df95d6e72ef4b6c5cc35add7095fa0139d5a8eecb57b73da7a95103dfa4b9037b41d2211aaee51adda19f7380ed59afca539dc5289ae5d195e1a50abc358cf4615f07d7 +S = 0ffd86aabb2861142ad2833b1b74cbffd660755d58081f816f28639bd6cd70b6d312d6722f14e4d608b154891eee96ffab837e472286c528086fb323ade633cf1b778427b504701bca01c1a8cb18547cdc3af6afd180a65042c072c741525346be008dd2dddb53d63dc7b33458bc59fd50b35bdc291a2760ac545c4fd21a37b710050fcff970271ab9ef51fc5953fad7bbd28e9d4f84d27c36711afb3ef2e21d55a3f5cb028667c10b23a334ed7e7275b6830588f4938f2c3b9ff795029c5c9eb3965bcd784ed3bb5a119d165db4ed808d388423059ffb091fcdbb1e6e5c65291b1e5fea5bd17e2c5f16be05c3d13bc8249b7f98720b300479b0a25d680cf3f0 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d0609608648016503040203050004406c4c610edabaa9eebb437d9c62286c4f159bb471247b77f443153bea722f2a86de52a83f4c9561ae581f8b3568bf9977ad8696ca8f310ccecd598238b3edf845 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af +Msg = 0c84d0c19e69926823ae89727d7dc8f27e2dd6a8fe0c60dd2b5c2a8f219b4bcebb089a66a86264bec1f3600099cde47a56545845c0fcec24985486ae2b44feb027928ecdacab8467a6a13ac35b7048674085f8c71181fb21203a5aa6ee02afdaf82d943dd3cd5c2b7bc00101e9ed5e81e3ca9e781822f59d6c158ebd9160c415 +S = 5af917efcb50475ef7d9b555885d07cb1f38149cd8f0102760298131cb6737f5d085f2762682f98c5e5e9918d9ab5ee4eb6e94989bff59af8ea042d0225d71690bbb770ffebc0610afccadb9726c9fba0ad7c716a0712fc4ac4e14ae7c21adca56d7349e68440b3244ac4afae225e7d70b68b4bc80fa9ca6a0b5665ffd831acd05403d8050c35d95caee2d6ad1eb53523a531e87efcae11cd225a102578f8ba6fb4b907f22b9515eba4449e145b9301619d5445723537c16b8543f524f37301989026d0b4829dbc5386fff11b74e54be9f8203f2a2cb16a2181f1a8767f1f161f650f7559da91578b999a34a2eab985aa96231b7200ccc6f38c2a621ab6b190d +SaltVal = 00 +Result = F (3 - Signature changed ) + +[mod = 3072] + +n = f33d3234f13272c3b2b6821ce4805663ff2e8b0d2a47de363d97fc9cc879cc6b40f9e53aea695dc538a0d2b558498829aac327eacbcd889e172b34f90745c5d528b7e82605f1a58fd228ec7fd4b6f476f393864f48dc47097c8a780a2ecc02f748138dbd7df99c52d822a2e5154c6047fb0eeb4f49da38edcae3c32d3fde435f291f96cad1e09e1030ad7efb4944b69e074d0d7964becb3cb86238d8d293bef3030d141d14868bc21fa133e9de1115f749991cf86ef506e663ac162b2c8567ff131a6b467a6f564d6c588860becbd88970354198ecdd4f1f4baee8f8bdaf7255835385f5673625f113550b123628a0be3994d91c3a19a82e5d73448dabf684ee6794fba7a2b1afbee0287e5a11180c29ce0896795d52ac7f408fe28e8e9116fe0b61a1083f95c5227d62d5537b5040b79e21b3a8e83c225bf3efebb2f808541e97d28a2468359fc60f588e74faad611262064628a25d8d61f9d03d8b21cca515595aaf2343a759b74a6a8afeffca139a389aa281995cd18e16a9cf7b7ff0dddb + +p = f3fcc6aae575312778d9e896acfd7c1aa4c5524f20453e8bab255363164afa7124b2425587a077fa0bfaf61b12ef3f0540dc4c9e777122a60610a53d1d75b0a5859c654a8ddfc2ff4860758bf5a6f264bf8bc2baa7551eb7be23bc06978be992fc81d890e07a3abf95d20eee3f6bbbc089985cac96395b473b2741c66bd2ccbef228432f66b906c15b19694dd786c29f06cbc17b2e6400dde4e3db85819382b3d05a4c3009f092d40d05ed5b2e0428a214e15a7aca09b47120b9ea6cb4084fcd +q = ff36fcdc519fe10c69aa0dde2cf3bc72cf2ce9a54ac063d809b523f4e5d7ddaa5413d500dc21f409ce661bf33018b748fba3966d874bf96f4313eafea9decfba71d540ae0508161a3658c4762d94ebb3a4e228c45661315db30c20fbd9e20e24c044e4f0b49e6ec80949b16e0ab07f3d32b248b39f48332cc3686df05d29c170a7276acdd129259aaf018ae3afb49b6e0ddb9e404a492863daee7be71dfb11279047794e45f399a9665796d32d5e65956a13a6fbe992b36bf4c842f5f519ac47 + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 9d1f17aab0ce96c4d83405d1e3baba1dffa86ecccee7f1c1b80b1bbf859106ce2b647ae1e4a6a9b584ae1dfc0a4deebb755638f1d95dcc79b1be263177e2a05c72bde545d09ba726f41d9547117e876af81bfc672e33c71442eb05675d9552df1b313d1f9934f9ddd08955fa21d6edf23000a277f6f149591299a0a96032861e +S = cbb358cb77cb2f130b7ad636fe7ab00d1964ebd5da22bef0139a6265a15c6638b17ef3d84a588710adc06d0242085f155bf5349064dac7481ed79d62b3ed60121f010729b61bee45554bfd5d494afc55405fcc1ab8eedc9c6251d2d0512ccf2e4f370dfc523215a09553ed2b7a46e8bb0e63d1ef0b09664b42c35e303e2fc3e2142e53a0a11569f8dcd56d47542618e3f3aae3790e1f531240b52b0a89f2a24f018116e513e876c8079f3ea61210da71e481ab89934385319de3275c0d9fc9ab33ed8bed5f704ad40ceb364f21855a5f5cb1e1d2b580ee4724fdf61f308d7136160127247d4db3486170cd2183047f15c8cb54368085f595f6bcff02675d6945a1d9741768820bed442fb03d5087e793b62d3d0d37567020475268c8786a5e5385970728cebd6c027aac15240ace0f0beb6c29f656f6b3f3d458d20005e41aef294de9823722893021d9cb621b29c2730cda7b6703e3a66edac57019b8404eaf8483edf91478f294f88907e277bcff47fdce9ab7f772ec256122530ed8bc3b48 +SaltVal = 00 +Result = P + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = b33acd11fefde3f71597af02e49e821354a0bed0080b31a44a4aa1064531a8ff749bc3e65a51a56f742ed1e46c8167b18fb33e26812a34792f6cc20a0688d4eb63b2d7a04a2d13235a6e3b2c007e42aeeca071a5c134b70f11db403888dc483b67c632c63457d41db09d16620a5bbb1352ae7ed430f0616fd6dd421933f4aff7 +S = b1f3ee7bf9b57da11da3a557d311e0d00e474578d3d798ade0626105191f6db1d8d66da0a35259e40ff746d9c512478d8972cde6bf271f679ba2f8e49444002ba7f94b65ba9250bb5710587c9ea0ebf31802abb7508a785405f8ba7e0753ae1b95675d4a89227a93a96f3f273fdc3aa7fe48b94e48dec9ab2fefbbbec394a84305b0237232394c21cf31ae14e5b938e825be9ef35605d0200b9c085cab040833623e72fac9f59a2297e17cca08d3a0e11cecb5b35b3b86238a48be38c6c03f7e45d7c5495d55aab57bdf8edd871aa9caef624466b09721ac7d27a74f5ccb3645bf0690d0396fb56e424b716df6bd9e10becf9b7b10210266d0ebac4cded6510b02528ba2d3b5318b7e8f43462dda97b523b6f7355896cfd8989f8d9dac98e1f98f125d60a5d382513426565f3b1d1f305c59b2b7f659c41fb796aa6936e4e845c4ebfb14bb62b2883edb1580e68d52d62e0143410f5a5d2e8f7a2d82107b2ffcaa64dbdd32bff2d3228ae115cd86a27a3292ff43d165b174e7d77f6dd73402c6 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 7020d49c0b19cb515b193fdd410abfa3638fb66e2cf29208145e2608214e4debad45d1666bc08bfba568cbcbc78dfaab21d07d79e91fddb17fe7253bf5848c87cffd54dc07eef2ed55c56faead310e6508d82f04674973b6153121b82dd1c96a5daf27a6e98c4950f397f42ef9e045fa9f0f94b6af569d405ea4e226d11c4bbb +S = e4ce05162810343296c8c774a21000f647973dd43615237b9f753c522d32aa6ce6742fa8c9b702b0a074ef8adbd17008226e7718c4c94255b01d7870cd5cfa3aadcb309612a7b0661ce1af202f7df92885a0f70886b8edec606b1923534c75f3cda19b156a2c90f6c412d33e2e0045b6a78aaa2fa991bf61417ce8f2c74a50aff9cdbcbeabab3e404799a8091e5ae1637933272b082d8abe7305173b0ebb619e4dc1dfc77015861c073e24de4dfc28e0fd95edf45cf540d7ecca1bd30cef47fb5e398c16e7f7e41ab35c932235464a91b3eafaecb1de97708a35c39730e58a39a2af7ac71959ece442e00d42e7c1f2885c49e5b799bec3d9735e1cdc85a4c3ea58b50524a51552f230525c834c705c1f1252f85433e42043d10bd5ceb42f8213d8e9db29924cdcd127f97778e75c1626b9fb68d6f0baac56d4cc30d0c03d80ac2f92b8ce2e15a7500b0710ffadc94c54a67a9b27c5531880a60491bfec5c78a7febed2c9b3e5c45474e156ad09e966e18f9f74ad2d60710c63e6ef36ffd478b8 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414a695cf2db3cc4089154364865e1f75073a39e420 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 856d1fe7642047ed19e96d364e5a2efa2c85a1041fb33b09dd59f038a4479b12c223a07c5b16d01367c58dbffa832e8bc8c4a5b4e8d55effd8cb6b50c2badf79fd277750d7bf80049249f4b1acd9e7316446213679df0d95355ad2e5aa0dbf493c61ec8a5f831e69a25cec33edc4209506f260b25a370e73fbed6c1ee5aa042b +S = 24b57099a2e8840bdcdb4461260aecd17534f76d074c765b9944bcddf9b31572c1494b586d0da7f93e7d25fcae44804562dd13ad676b61e70d19fec98cf6dd2eb917faff448e29b951a77b1017a8650d0061bd77742e04a44c79bec6ce141bd264824b6e553a3f761bf583e231f2152cac58f71dc7198e675e364103012aae9b45a3d1a7d61cc25cadcf7d061bf36a10599a812ec279a996a486d46984ff3c10bdd6a465b93eb1796639e499d865f38b4de2b14301d01a359f36017ace359ad1e3c8c223ed74b00c6a113288e64a9c610f5f06d537edb11f520bb4eeefd055cb3560fd8b4d56311c5546b07ba1f3fd0d3e105f3da24f3bae8ed44fbeb6512fb66cf155e3e61475436b95f196f452e612aa9890cdb48938b29b624094e36f651bd305700b39176273b54ec9abb996e644be39496d8b88aa26dc5d4bafc343b9850c0201e44fac6c1ac69c4e408ad5769bf58fae1b8a88c160c0d193a2c807375a4550c4cf56c947a9afd9498fc220a469affedecda22bf44a8f6f9bafcd913948 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 590c04975accb7dda8c07afb60a7dec74d2ab36751b787c1068c6933a412f384266d871ba851d86f1417acbffd10e103cb19ae22196f2c655bc5152cc494cbe067b39c289c274460a53cb34791d511f76100001b6acd215cfa61d91c3e4655676305cb26fcf70396a45817f9e49d778c57072fb80b796d8c2b873d6bdbcf9802 +S = 8913d37eb20039be9bf34df63a3824f13f20324a3c2c2e7adc705f418c77d9be7f127e406d765501663b551e4482a177f58273483b51b3bb4614054ccca4a157eb6f4224b6c0b6e4e2b92d11b87fffb26237544c959125d2047165fc8dcc2d5766b6dd7d79abc37b79ea7bef2169e80e74237f5574494eff54b15f4ec7a5eed2e982a3b8d76b64801a37d888b079ac680b0833b51c2bb8a168c63cfb0a96a8817d8512fa4812eb457c1ed8ce0d563ea021a34e644e70689595a078ef469dea58a334207c6930a5ccd82307311ec25cc56807f2a9160b5d738acb42925acfbd4206bd92a24946e2a3fd8e04a1226e472be33eaaa5eed4c13eabca68ecef4d9c005b2f132eb827872235217622284833e339303162d866133a007e27e88af86b23c451a846eb393e05af713a59a929edd2943e6cff60aa906459c667595154747156c52c39bd369751a7a7f926bfb7e42bda447faa314a7593dfa4a06bc334ad9e52339917fc65598f06ff61ee6d7854325d40284e12505af8c57b857887f15d29 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = bbadf4bac5fa0abe2abf1e9993d33b798c5f7476dae4d6bb0e809be75a6da0b3a4ca1ad4d99e8423841adcfb9f1e0ee2a8ffb16cf888f15d513ecc0eb6e882127f4f4618ac433a137ade9a99340d37894c4b28f1aab0bc2f442bb356ef0cadd374c5e250e7f114d83495c23cfba69fb69ecc42cd98661f7810ceb686adde0a3d +S = 257d8b3a2fb7ca6d0a78adf2b6e11dc4865c63888422d0795773249865d18519033508be2811d797d564687827eed35cc4c24bddc548e7be68a14cea7e8e0a3a6ef801df2d41519dbc056fdf5cb23dc60a9b8e94581a8beda4f4e660f699ba5a649bd5724a1d48f88552c3129bd08e2ac8b0ef60ecb938d4039a2fdc648b6afadd04683b40f144e474b8a99b3a81fdc623391eaba2111dc5aa812e3fc6b9c8f8711e9986c0c2f012cc1a0120c79004eae424dc4c90f24c8f52d536dbb50a101ff04498887eab4d2bc76902c2587a3b32ef3a8a58c3cbd11a9dd14055da56e7ba011bae74875fa631a0dfa524fe396b6a5ba1b92730adf17b2e9bed78cde226ffbbbfe29d3add1c61262c0ac9624f1feec48aa73de41627514bebaf76997b0350ea4d590c6cb59252c9d693020e7887bebd7a25f1769433d39fcd3dd46625208be410d50ae16b4d8fa6554be3d94a848ffc3211a915453b45a3328b001a5b605d686129a4cf4862b5e3453ebc42c2a11fe180adf5c12d50d361128abb1555aba5 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a050004149a135a3d21fc0556fdd6fa7ab0a3b1e4ff330f9fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = cb4029c463e243b9f901855447fa2af302441ee117a3622a359fb3ae8b356675d3cc97428f6b826b922831e7c3e458a91e357d2cfba45b5093198964c0935784041cf925cdfde7eef72e83ca9310fc3be75e73f1b5615d9bc16429fd8d68224267199694a50038eb30f9c3223fe8e05065a84a55ce4430b3c66adba07a1c9059 +S = 3f5e4b911aa319cfc15e4d6f7ee82b12a7bf827dfd244a5e57a52bfeb04bdb9e29a1cebdc4ebb2139906c42a5ea92a6737495d35d43ddeea1786420e57d994d880625f0c4f56594f80a732b549c65132355d56c8e7acc857344fc736a7b3168e8e892921c12c0cf8ae7a5d66a9d95d4180b1684ce3866024eeed217fe3d386380aab1530513aba18703fed501984820d8bb050229daf0467fdf13020094be24d8fa8cafb8a6774861b4a2a0e32373989fba555141d7113804b635c0ce480818ab755c87be02aecbd69754f68c3fea89dc854996a05fbd3d5f10cc7083f893297c63dc384a6376fcffc8cfb170ac7e0363489832e0c3e9b0400d928e05411408b7b12b653a1e4aaee79ee46fe892cc64fa21afa202c763b161b7d4f1c32e7bfc75442f1a3c31aede44374939b64c264f9b1833fe04172ccf818108f74634384bcf0208492fd81a77282a27987a9001754fc74690a021880b7f2324e65a084d88c3f4486fd974d50edf6c206ed616ed9376f1855a13b51c914c48b3bb0cce759de +SaltVal = 00 +Result = P + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 58a1db581148b3b2a3f3c967d69d3feae7df5a327e122103dfb4276e640ca59b2b11cbc60c895888ce6e69589a958e51af92233658d6deb31b1aa4e53401a11d42f897e13f617634b5f22e182f57c150ee1f9c6aded527fdc96d9b30c9e3147b031ee7b2921a353fc246c0ae7f2bfe700d4f6cd8f959256a4f75b3550dfa253e +S = 3b93e9611a492f19acd725d92cddbe696e97f29c5612d7a1c57b7cfeb7c70bae57cb9c75b6c611bb1ba39e48dc99ba9ebc091d7ecb5124bee1596541ee337746c86c6280a2db0f434e13735148d39db23e594ceaacb36bc29fe005ba204bca2d90cdb083e9972b227aecc588f601427c8977ace25580481db532f580cfcd54f56169fc2f31cd00f22834cd4ee3c6d9c5f708a9d26e10e341771ce65ee4233184506a17f891cbb633fc4571d7dfcacb949523f692fd44f08cadfce02b6fc54bc156a684c9a706742d5b2d33f45b01001e777ff13f3b485c5da6778526e1f80bae0a812d80cb2bbe2fcab984754b3ae9532e24e9c930ecedf50cb554ad345655e25ad118f40e9c729efc53c67f8c9e533ed434d57c92ee71fa809aadc3c6c82aa4bfde5df4b1a32d43981b9019c04ab9b32129158d302f780c22cb47249a1f767861730c4702b8f599b594aafa691d423bab81e8de32ce7a6e988839a55a94c198c8b10e432ba10567e8a01d264a9f2964016ba1f070592abf8f1eaf25f5c06f39 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = ad65063815129120fbc5875461c916131cf2d47084800e5270475cbe620d7959fe345228c1995d9befbb2ccacd2042fe11f4257397f4b55c558abb289139c504513c32a1146a8937bf5d0fcadad398acfc549d4384168f0c8a1d6be016a68f768fc6cc2a764fbcfc54f355dcf0acbf25c65b6367b5af4569f848936e571c7eb8 +S = 2f264e0f5c24603eda9315230f23de193fe6ccece8de2d6b0ec8ead9803798b7c66b9ef0ba801b029c86bbb35a743031f5ceaf19881948cf8e2dfb52a4c7353de5844863a8a6ce407a0c88dde7f76f76b8a548930f902c974462299a9065a2a9c90b639bf017f77cb699b2c255bd18999757ab616b39cca6cdbdcf176a0057620c88bf0727133b3c5607ea13a454b45ed8d29178ea182f54329921677f7ad9b01ec3b0dac78dd82319f5b04d9e64da052fa5b193c32806a3dc6182d2bd2cfbd7741130b5d6d32ccebf48183d8b552186bbc8f6f6ddbcfeb3ac86579794bbdd51d9b231d4520b7aca40379570861f09338185e120850e989b9f708fecdae37c95507a46eef059bf7cec22a8728d03cdc7a758e85ed2c7d78b61caca723a4daa85bc6acb5e72c59fe1ab459e9d181aa2c3b0a8019f510156d76b0712678019980f2377d1ad7f126fb81762090a394a172513de39d388bc52903725f20d476724774ab0debb48e33fd03c7b48765cf91270245b42416b504c97c335400e36367c06 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c1600b15747d006f8765132be06c17817a701f2b805bf6476a1dd5582efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 0484eae59ee761e0cd361909a014b9bc1260356bdeb74440933a1503e9913d3f5630f5a0ddd882a02761f462d4b813de1324973f70cd9789ee7e447f56aad7c4ceadc840ad5541c58ea1d2f3a4c866594d7d76dce9727c5dec1bab9632b4dd459385cd8db86586992c7d1b82b64e9973e7f63a0befaedb02b598b01026b8370a +S = 74e96c2236f61bffc5830647a50f32a09b5170c586d38b83506c91f6337bed6aee942710a9288e17f8e9fa3e48ca99c23c8dec0f963f8a28c0a55db3d05fac86a67039a6c0be46d28207be9ec12e389bcea525386d4a0500d64a3d2b846cac4c5f9db7fe8a226e54e28e6524145680e8aec1b5d5f531e7cc5595e3f9973bf1b682574ba48bd42d55b240d2c9b6929b4a8fe8eb6493a2a7aea700c81dd8126c4f5cf2676adebfaf8641257d4281945ec771cdb4e45601ca20a19083e0844b8ecaba048ecfd2d76c24324f368f7c20563524271cbf5aa4239ac6259a3eef2c80e5f78ad3c7bddf786a090d7ac2f0b7e0fb5851c5017f9bb84001261038f79cad754d183662cef7676caa122fd0fb763944dd89de28f06fd40ad4721a02618b1a0e20056e265c8a2629fb57df29646df0ba56e94682bf3eba253a08fac1925d39561090d8f36c3b5068b26484e134cefaa7613898fb12c4a93122b7224771745ff115d4f70eef1e47c0a656ccec2d0afc46ed9d0fd5b29d151d23f59723d3818f1b +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 469ce940f2675abe473f931292c7fb141eb1d11ab62fcb1065aafdcb80b7fd9ae647451e871dd85c2386291154443845cfcbfe23e7b00b08535e6eda300bd59b4aeaf53e97a22cb90400655b74e83d60069264c397f345538978e909c2fa1899f7efc2472add9efc71151199fa9d518b4c6ecaa0cfdfc1188f6237003d6e10bb +S = bb0257ed939f61ba105b2381a70acae35915a625a5728e29287bf0b1928e7c8a82d6b7ca4c1d35c6dc22b2c44895202f147390da4a1d3e64f416c03ced1f2523d586cf3b36046fb221efe1375fcc2d2ec9f1c0ed979e901573b2184385098a0fe27d9263ed6054410a3230f02b6258af4f183e82a4fe13597b5c805ad22536552b222c065627d4bdb929718bbfbc21cbd8e7d688a350ca2d36ed325c737af93df4993a9cc3be1d718cb092f48efcfdf21eb419de0666e3bad14abb09ec86890dd925c54b228b8efd5f491a5d52bbf508f15bd83e912569aeebdf9b570485df348e2cbc42395674aa69f3aeaf0c9573a27098253fb36f913b332f90466b18e2e78d8c504cf0eb835b5373e2113969f935b710013ba340292be2be396256d6c6559621fe96c1fab4b92e0908f71396b8dd2096ff1f2edf1ac6a31cb3b405e0ffd7c41b8edd1de01910cce15461176e4d2706665fab3cc1c9fa4e810e15b59d64e9a46588e0629d8cb16d60bebefdcfe58cd87c37c0e8497004bc42e29f024db067 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 207fe949bf4eb76dec39e361e5153fc593b59d2d10607c306681e8bc9aa19bace993689d51eedafd53c11864f8810b281246c32cc43717f844438c0fe013797c3f3c68afeab8be870a979fb074f20c2fe2214e3b832d984fb788e87d13fc2e05ace2b0269294ad349a2540eb614f88038dac06045629465c46b9c2af3c46036e +S = 7fb366be277c3653fec8f65d741808e0e1676da31ea5388d2a87ff65d7e9dc032086be8b0f64642b937a8e0e563ab44b91e79003bd92713768b6caba087c973b351a340f3cafef865c6631da91e2eb55d9ebebd5d71c094ee8be88c43caa7c1f6a698070594d76d5b036ecdfbf0f7a9f680b56e6012230b1b91171d9fad3b8dc3c4ab88949acf036968169b9efd622cb52f485a2ed1bb6f65ed848761a67da1f67278a04891f663ce4bbab7f691b0ad1b8b4873e9bb4875d5627d581c262882f16d2c5f56e8614346934311408954b77f407272badffd3c2fadcb8a8a43441d612f6ba1d4ffbc00fdbf7fcc5ca0c9002c43f47f145ff0ffabb8c5760d4abdb6eaa01487555ff1ae4ffc632473a25831815f8e37b60cde1c85a537de9a75b5189fd5cdca65284165ee8d03082924feeea8cbeb72a1d5480fd2be13c4732f2f98ab7ffbb085c8f6c796993dc10b4c1187f32ecf2bb8bf592c3ae117be68a30e8c92d094e674a514fe9665643befd8e2c545a14e1b9f565eab37c3d913e18da9652 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c49c8f2542bf9c2bfd41d90d2ec3c717718ba9a1636f5ad048011cea9 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = dbbd09ff7b1c707c2bd52014adbb773ceb146aa72637c8724f5ac39fb5a5acc4e18bfe04be599e3ffe0f6186b870cfd2565527f5ae46a3d06f4bfcc7bf00317222e885959e03c6531da3d59e127b63f25ff9f94377d63b34bfeb6d893b4636df667da49a61427120503885450205bb05d0a9e879c70e1a0409df1dce709e4473 +S = 2e4d98c10e126e544d2b74bbcf0a4f03f081d4725a6661c0683d3612b01ddb2dd6f0391ef3679f39dc0785b37ac275f0d6841ed3a44ff7f6a407a085129a164faf63ff2aaed18ec6a5f7d27b48d017a50b24c8c4859ad2bb680ace5f3af57f2eac2d7337c0dd7403ffb2e8bac69dfdc98e62a07354b2fc93d03e499ee2d126647edaba094196b693e98cb98ad2817ba3f7f522c8f786b6ef82632ef5a00d5d4f42db6d26709909ca751aa8174037c924628852ce78e2829493d6c741d3558adcf713734697754e55e7b3bea0d8717da8aba2b2874527a0b3a8d2e1433344dd6bbaee1ebc7fa352539d94c6b45f915c6979b8e18be8934d28d770806c6ff893660dffd0e948a8cce11ac870507f88c1f86caa875ad721326dcb4f0d5ecc2d2538c4fabcc6c756ce4a59bcdafc44568787cf2bd9650486da8c85fd0b87794547e179e498cb6a5b26f71f9987d703f2d53418411c1f9a3a2e6705637b7bbda9660641c0eb037eb432b2d7515d1ffa99175cfdb8a2a4eed013b947faa4bf1c3cbd59 +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 4255d5da3223d2f6e33c43abecea1ea7926f7052eb96a203438efb73bef867723f3f77d88928a8bfa4aae8ef83ff569ae3fb4a4a769d951741e40a1d42e33d2d57188ac35bfa593892d1a13947caab78b34b19a12184269050472fc11919730851891782f1c06dcb745a75718174a4a9ca06e5413474ded6385f744789c19169 +S = 6fb009ed4d66f18ae694d6e383196b02f4d82a1c7a755ec4989af1e2f7381355a5cb0bd7b51e48de878c74c9a2b359deecc55ffe4e67c8de5666f7a23144a7a67cdfb0a62d0135d4f58c07fe467f044c1ed33afee03eec57f8a0f83b451f145f1eb598d3997b67d98b5d05a6b28d74eca249af0129ee680b9055704d803f32ce93d77fdd0455f5002fab33b30bdc0c8bccfc6834c9a260168b366ffa6f0421324b673d7e697cb266a09e03afb0ac6fe89495852a6e90d6e132b54eb0b899bfd3d9b4b84bd4ef4b4566beaf2884acd26a27c0241f820d6612fc8fe9c5f4810c6a6a32c924a7b532b63bea39c535aea33d50eb388d5efb7bdaab3864830c225c642353228cdf3e0edafe39bb7d9d9bf8143285b18ad2c941ffaa67bf4d91f94ee1abdc9e5ec6f141ea0df5a27490c51d0b75e5ba470c9e02f071063f89f7bc221170f8b67203ee6997029d53848868b8ed144651071b14eb96da6e2cdb9b9f6183f548d500270a20bb1cb2e12c4a43c5bdb3fb97b36ec02617248242e5a59dd7e7 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 3a463bbff446f2b5057c50da18fcebff0f2c5be7e91e4144e91d88e2f486ea233cdab6ab1b10d15c4130fb85121d54564ab21f98e311c59b38381d6f6ad6ea56035ca67ad9567edc36fc9d8d3504ad206fbb9b5fd7549b3de3806d0ced3fdef0d8f59194f6c0ff1b2909bd5a4959fe44c66e58a58f8fcb14321cff224469cdd8 +S = 26502431034a0f2baeaf1cb7d8fa138b32d53f808d6183270dbcb24267c71564377a6d470ec42a02a7e88711c8c1e46a8b3868d15ac81146ad6c9ce9c40a1b09c8bada5020cc52d3ac2452a1b81c4ed0052a79c6e5cc275a032a816698e5f39004a340c13e52e9d672abaf2f5e230dd9f5a40eb250e8743a46414961d347a8828d5c1eb290fbad7eff81c7204bf377b9d9f4f8a2067cba6a6b7a088491cf42eaa8b201b5d8b37033d6db81454faea89417d52dc4b50ed920ad1e863f083e1f6dba595661adfea362d0e7c8b10a55fc58a1202fd222b4354c320dfa1e466e49625bc0c80dd620ba3cc2027ada7177ce44483f5dc8caadb3ff7d812524835f402e0d691e0be9bbac2bdd0dc6881e85b0ef46962b8441c89f7eb2a2d14bde8d2ff933dcc0db390f225f2322544bb95b34c2c2e59e6823f56c048508be7a3011a3130983185b47305477b19f3c701ff3009342c19dc22bea62b4bd2ed221ae9c2213b3026a576f8e25d72f9c72468e61b6cfd9530ccc1c183e101df9aa3228e8ce3a +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420d65f865a519cd429cc9d221cdce15d51363697e694b2cd6c09987f0310b5e8d8efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 631b9db77357d87e004b61ebda972db826db2b9f03c913136d7f5e2f601395ec406fcf96785f768162e849f867dca77667ab0a195a7cd253387c44e31776d20393a59ce373c638578a70aeccdaa8c78100b188f4cc21f99a2f3a2bd25a76781c24640d86acb3a668408c99517e261641b994ad199fe1104f185e1be6713b119e +S = b3fc32b58ff28bdb60d7080dbd90e369d5b6ac8567f9953a3155e42ad86f671134b77d5f00cf1b686708da2dbcafd637b0e1c9dca59ee74b1bbdc339aac119661a2a1f3f837271a67c5788bf309f77752c4d62ddddbec71bf7b066acfd08b96d840cf4aec4c52eff42bb85038d78d668466458dc7d69621206ee831726f28e49a8a389789d39733abd67fa334c4ea1a39081bd1c086dea0a091e8eecb06d413799f88711084310c30cc824fc8f48d0a3ebdf481123a30a5535ef0c8649ff42746441bcdf3a7ffc23cc13c5aa75b2fd8a413b0cfe1388cf724cc105c182615902f91caacdc7617e349a553738d5a329445c710787cb08b87332a91ef8fa1ecc4f86a7c56d6ddbeb3397d2f92d2f325d29fefce33954a6620e3bee73411f11a152418c5cb6f37e0305530bf510589f2918204584a9126a3372fd7f915070bdba48e54c596d8693a9d18f848bd5a53982e8c8c33fcb3959ccf4a56d3b942917673aaa9246a5baff5f5aeca056287cebd950968308d535b1a62a5aed92d95d9d6c2c +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 50af2bdc908dfa76ea44c19958ba61f2deaf29e663434a30bfb98acc157a3c14635d6f2a57256695654c482f16ff193ea369e9e1c2344baec04d0999d0e81617a3c5c48438b137c2f64f1a24f818908aa8a16ecd8f1ca75d6b22082882b025be376f93b3db385745c5d79f3fa50fb01e15df207171044586e9bfed42d4d84f51 +S = 6b3f7aa014e45d369cf4cbfa86fd284af19ceaa355a00f55bf242f02094135e899529b0c64538ec409b60b6c9666f8dcc61fd6060c990954f8200cf6a477e8a114633fd8c9a62c0e8d1d171ccb5e09d360d42d868edc0bc0750338da5ab69f53ebd8f9ee99c55d9e1cf6bc9e9a8d10db7cc267adf5e525af09568c7d6ce2f59ce8c5be5562f2ba88d561f1d46dc3aa765b3a3a2f5f156177d5de5e959f2beaeacc2b265fe5f7f3638db14a97d673489faf35be8579071a09e46f48967d46e251a7bbf460fde2528e36709b5b4e13a51ee53423bd4059f38a1e3dd2720dd9c037fb6ee048ecded10e5d7c199fc3b2ea4404110e5a283b4feab8048487984c6972ced45ea31b1d262f0b071ddc146f4db71cf43b56ff887679ce39e9a6a3e449b04f3d6bab80ac393abb472dbab9ad52eea3b936ff414b9eda99d710e7c836c86a60755b65cbc0135b71f87fa96897c708cdb69d6c6d6d4ca5fa850fb6ad9b2c0eb5483b3641f211b2bee68ef6e1b32188099e7752d6776168adf7f0667f7b2017 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420e4a129a7ddccb2047e91b87062a92c5672bd3bf6238b5d2ba1175f37f458790d +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 5c78db3e64375eb7325e70272bd431c10a71e34acb58f215c987313123ac67e1633a0a4c62bd4a76666b526f8efbcacb70baa05100db08f8b40ec10fe5559abb791336a6bf660cf69ab7b17ce2905a2e07ad9dd8f755770e42eb93657cc0c9e3e42be6b342dcab1d166d18b6ee3aead418736245796f4841bd43309cb194fc40 +S = d3bf9e41c55375a032394a403ebe35dc800541f87ef67f9de42b9a386b7ed0f78403eadca167e2f49c5332cef85c2bd821511c721ff4b3bc3fcece51bb10921838384da4af0c40c1031617067656cba8eb2d2b7f1744ecdfab6874038163a97cd08439aad0b8f959364a0cb0154a9606289909a1a6a486030abd1dcbbfc113ac34bace0b84f1b7f9cccba5dbecdd1932f7993966f5ced9187692d03b8dfd99f87c2903d72bd7c0acbb942c6f1f321d43a357a21f6fb6b78f91b92346ec2e577cb8aaf9e7affd12ee3d27ec9dafe50b5cc874c374d2e2c1bdcb22f1b6105035c393e4f8f23660e2d54795757a0d1729ac12e053aeb239b7368eb991278f3a0c2f72c551cb90b96cd86905389582641d6c029c6622b2f7db133191966901d83dabdc5e634f6c8ae59aa54e6c0c2db7a1f573b825102777fc8961be82a624e5ce01244ae8279794fa5ab2fd62590ad8a00c5d0b0ad11a0154d9bbc2cf129514bf193c715e49cc75bcf8343ea017906dcab061658083ae11fe7247ec95ba18cca761 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 275a91aa97dae189c61fd1b7854d49899d9406d958a8401143718a853103f90683d088b3a71cbb13dfb2836144d662270a7acf0f05b5dcf56c701640de63ad73a240d5ff332d6b5cfc78dc57608643aefd0dd1da3283722cded7ad1b6b5eccdd0c103e3442f4398ba5d9a441e1473345ffb5d4e3e6fc4add210c17bee2dea06b +S = 270c4cf3272ae89db2b9b2be30ef1167d1b8b67307e40f97c81c3c9ced0924ac971d669e6c0b35ece58b5d4d4fcb4fda5776f81e99db9f8ea4ec5d65ec960f2feb0a4166019e5bf856246952a9a68567703e505dcee51df9827c51dfe6b13eb6038eba7cc3f3443f0ef6f28ed06fcf272255ccfb31f3a956a36744b878af8eee1eaf0e3ff1277ae602f6b3c1940697d41a5acfbe1bed9abdf73f7882c36647f2f8566d3d5eb24ff8758ca4ee72405c4f9645a2b176ee0dceeed37e8decfe2a3894d6d2118cdb7295593837e2ef96335066dc899a44dccc93ae1aa1a6d2548d074be21170e3cd6c73555bfc3a95897ac9a4766573008ea7559a08c3ad3c21bcdc32e4dbc7c5982f279b036bf790ad0beb6b129d22d834bbd74a204d5d60bf39a3fb4ae819b772dba0ada94a45a5fd7ecc79cafa31dba6762b5b51ee95c0651b63309004923b77c010d4b6b3df457aa0b0e5507c3d804fae26b0c384c1a34d1bdc998005226e81f2b9fae100776f5e3e410f53da6898e20cebdbcdbde9efa1acbb +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d0609608648016503040202050004307f87c39e3367aae5759a4d5de9ef2ce5f95692c59fe337dc4087aa11be86c01655406490b00224111fab085cb688bac2efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 88af470625e6b5be3358cf6a8698a5655ef321838f044746df83bc55b05e8529df0b120aeb1c7b3a5a1409705879f887a22a7b78a2f30186db5fb7b888cd4e8c80c6feea5d8ecb57ddf9076b8980188594947bbd0533091a19b87906e2f727fe3589138ec3652d7d86b0d0455fd78cc5fdda283a00ebe76c5e370b25060498e7 +S = 879c4df9b66227ce30e6403b620a488c72329b400ec67667a600bcfe3d0ea893f3051c8076eee81e0fece30c4153552ae2b2c774888657adb5300bedaf4940d6d6ce9310a476093b3590fca889e8ead464809be4da3370c21784e4740453df999bb9f7c290ea16e4b0e4ca666ddf23c757474fa9b0dbef769b1876e1eb553ee3a1c14c201c101164d5d1e5f628a7ebaf65c0f0f27f239ff67a4fe659d347cf50921b5859d79d86f8bfd2a25eabfcf76eb606b4151516c482c74ca3e54ede03e99086e61c0708e8ad9c94c1fe3640bf811f4e2c0e62d17d593f2e86adfd0798f04616adf9367b0f77f40de77135301debb490bfc76ba710878ddf91651a5fa025c348b6066a49853d6ece7bc79cdcd8ae709a77b96701c1ba9c4a91663e3790bad5c5c48017fcfd005a1b03d47d07dd3c511aefeb4c766dd19e377d2d82329a222b18ee0899e166cfb37c0b1b3226123f80a33c096fa4ba784719c4d9e52e60ccddb6da8575e705a36dbee7d97093f830283c71abbbb85c06daa913f96dede4ce +SaltVal = 00 +Result = P + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 78c938a5628ba2973c2b793348ae3857f599e83bb26c930c026cfcd7d3a58da90c3091f565b2a3357b2566d424db774cffbfa08c50df4f9c0b2746832f6f936955b9c3f989b353095884677d2ac4be68d3cce6756431ac86478bd79a8b7b16f47cec367a7798985bfccee3f40573f6f5964821bf966a9411dd1f17e48ecffc93 +S = 4009022b370d46f9b15af306f177d7aacf5949bb58b68c05680eed83ef5b35b29c53f781ec1910006c4a7756d1c0e67ae52e7599f691352ad5c052dd6fa7f33121841869f1df1884489b18f4fcaf4b790f6818549b26f2c764acdea5113427c0aa6f0d0c3c688f10e572adb610240ca1397a96964861a562625f1a55c2d369017585136aa6f473c368d64f8ee85eb21aea3de696e3a258890c458b1434936f48c5725b6c81de0d2f9019a4ab27724526f64f6ed1e1dc09f1d828c1d6a1cb4c593d4e554e714bf55ef5fa2915eed46497215957abfe3c92fc06dfd73add5c2046a97b50c4d2366a4ff6c03ec4ea2e916f58240744456cf57df158a7a4c3c0bfa9cee2fe72ebc2d792a99aedfcb7070841a691abaed83bd55df0408a8555e8c58c0023d2000dd7589f9e3b5e5fc9f6448f47e870ca13755408fae7eaa16e2dfd4d41b4de4099b5e224222a520b87784b2679dcd66cfa94077b9c5756190bd25d13fb40015f1bdbb73526ab6467d0eb1aaa458f38adfd539a109eed0fc253af8e8c +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = b82dc25af8993613cd5f5e6e851dad20d155f1d2831f3278971addde70a82283655b9aab7caa2db075e933990b78d9ed763ac6ca3448ff3109e708a445b84df3452fc0533c46c2b0347347444fd7356953b80eab6531cf22152818ff9b818c6460917b79c1d6bfbc0fe5e398daa38b3a6fb80fa09f416af2c2c55316fc6ba97f +S = 03ebbcc4ce14c87345290d77a652ddb0a27143e11278b4083cc33a70e4395dab1dcc8468f483e6b8fc461e31e1d5331fda53e5ea595950888d05203b06316f7e5bbec3a2a3ba3d8917e56a657d04c0a8a8aa123119facdd323114f9a1ae78ff5d9295b4bb244443a4e3ada7c00985e74de8b295dc898ecd6c891331cd458a040edf8e8d2d9aafbfbad55f111265723bf9b04636f211d853be40c9119850c2905bf665cae93968363e82794faabcb02a2f1ea1414ff05c63c3f32832e7d786809603b41776554c973560e69c3d37eb295be53c5b9a9769dad97f4a99d15e11c5268e10387b1ba13b198165f78423b61e2c203de534f9e331c004bdf85d1413896d4deb83a8bcf8a09c26f43725ae9a1f0f6ebbba092803e498a9fa5e3d15042964596817ba275fcfc89cace5b0b566afa19fc3897223b2eedb48d1d5259aa576f3248ef1647e6c3bcd5d3f88f5894be8006147a4595d416404f2de4724080bfbdc5dd58262ca15f1987b09a80a2a38c8594e1d2307fb99c1336f85e7c0cbc8ce0 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 18201d59ba48bd77abd33ec87a68c1bf5ab93b471aab100857b7e4e6f08fadcbba050da77529e0b5ffb211ffc8a0b124861f4a592aad70ae127f9a938021309a4b5ee57ed45f47653c179462d4ded03ed55b147852a8298a6ab1566ec2dd756133f14ce7bf311b0fcac872f886694594b03742ac7ae26224c813bf819e0ba5a8 +S = a07673ffcd2d28c4dc9ee2f91ab9b1f7f59aba09779102f5832409a3ce9d9193ebb54fc122018602ecf9d52a0e29c137e7a4430253faf49ce6a5f25b7eb7245e2dc01aa870f0061cd7857a6f58e765fccd06ca7f35cd796aa016bc0198583f86ab714a044e68c4827f5ecde03f9c9843f3fd5c8448bd039b5ac70a6bec0048155a11e55f60edd315a560c5410210be96baab0056f0ef9404333d068af9a814b5e8be1ebcbb1cc746080fa7b3a09e200426188b14488cfcb564a8327eea01c0c1a1681552fc23cf516f600e596ff6bf44489f07db4167c02028eb6295c769fcab30df726aec31af2cef6a26deb01a918e6dcbe6bc16fbd21092a28418598e958b99d7db0157674ac564e03ec10bd6a59d5a87435259b5d74ecafa3c0209a6c20edb7e874f6db5fb83019dfa7820584aebbf93740849b5e63985b707e891ffcebf0c45f827933808d2a7374cee25694ce9a714f433017540c996c0b169a284a5b1b2d31c954ababb6f75d7dd060408e74bb09cb9be1288a9b52127fabdc2de942f +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 6c49d5bc93d861ac46788e3c93d6e815966b90248f46ec89370c9db0553db1bd8cb81a2e77825fbbf8c39281cc11826063f131a2ef9b89ddbcfe4a1abf0447367117d289dee475c6f85fe32232072db94a6b392d66ed719063c6b8846a4aa2a0c46de416ef870993f1546767ec3f52e6f3e08f0e1cc30b6ad66bcd357d962ac3 +S = c35cc19c52d8727b0e9945942208234a2c4ba3f4d4accaf9b54fe161b5b92537838d74a94c0aed70e58e99cdafbab8d6b968f57d3af6b7a49d8592a4b381635f7ceeb25c4efa0cf8d6cd6c2e8b751143f11ec50956db690802fa0ee40640badc70ded68345255b54a97dae73b340e10af6f546dfd395d3434b775c6dfe29058d6c3b9531e968091f8e80f9f4a82439890f7435622b3fda11eda964dbc5c94f2eb7b66ac1e17b6e4bbb5a77870e8f03af62920e64ec059e6fd037574f31636800f53e506570f5352c99f04985337819cf47e8cc54ac38667e3406597f66025d05e2269a77b347f02129b510f38f898a7a79a71dc6126d3db62dc3dfe5faf7e917cff2fd6aaccec49eaa0e8a35b4bee78ca043ab2f860155ac2ecf3cb7564d8fcfc913653f6392fc03a675884062217f23543d1030704a733d077969d9181ec555c0f3808ec7d6bb7873787c296782a8c3d374039ed636037e2aea56cd230baccb692fe46cb84efcebeec031801ec10ea4fece8940ca6e4228bf5aa40206efddb8 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d0609608648016503040202050004300ba6737418933139584032033536d357a432e5e4b816eea001f2b4d47dc04550e24f47ea3060631bca744f42b3cf9675 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 08845a6647884ae71378c1ea0ebb9cac11159eb121cc08089e0a6ad0be83b8fb3a57a052473a1bb9c8d243b5c260642b10a3556b58fa096c3dc86159d61c444d5f92f25c2f7495d2ea251abff8c03eb336fcecc6eb53c6dbfd630226659477ece0fbf78ae77ee0b9e239ee10992153cbebe70acac22068dd46a2f43e5131785f +S = 06771fb5a09539491074d33f227cda5a26e630075870b00e84c0fbf47c98e60a986d5441ec0ed557c7b02db2394951b61d3ac76a94fc87b21ae77c082bfc0271c321a77ea020900fbcb7ce8ed40016279b7462df2da6e32ce0975c3a5d05cb03dd0e97b533f3bbaa352d579a2bf2d47fb72568f2a0e06a514bd1b3475db260f0fd040626fd8681914a28d49e6566855f02ee2eaa5e1e3e277e00e677c60c87083fa88785d48f7970fbf5e835e0b2bdecc61df27ea9fc7cf3f510cb234d25405c4f9078139bc85b92bd0e8905be80380188d61d699a7c7db0e087932c2cadcc6991a34dc2a6f9c2e9b659dd1527c51d6c41fdf23b5a14f5d8f0c3ed2f28c08223ce4450ca5e896a2ffd0f490cf2495956eb0257246afeece291b8ba7c373caff9eb52ab90462069d20e3b09f1e874dadeb2cbb599d2be0eea434f70f2d26ada7812f58b7edf20ca299ec53762943c628ee31891c26f69eab3242cf0d90ef1607ed56c19ff5af4d4be35334cc013b47aa087935a855dc1ff62ac5be945978d8913 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d0609608648016503040203050004404cfedf114d5b9205c1c8fa9a8d73b55d82c17feaeadcf7da87eb11bc021a4b55a0c0e4e232dbafcccc1423db05e8a917b5d86dd9854d2f9081c5cf7744d882e2efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = b2f46df8613ade16f5efaf19cd04d7ab3a99c804e0cdf66160d493b1344a9d91dac61b7a34b3a4392f5b20a0a345d37c7ac197c715c1681eebea267573eb9709450eac967c0c05ca5e26b6fa3f714c15a2720bd6a2ea7a3d90f3223fde4c92bd3bf2a6b300f009b2cb77f99069314a5efad3ae9a4ff233a697170d793b159695 +S = a411a40f0b95e8a447e09914a31ab52842583a1a90479435bea0bd20104c6423ec3ca53a42e8803d172996237e35e59952d32ad3484fcec66fb8ace07034928ed162d287125963099eec4b1f59dc835a1ca02a658771a64e20a5d4e2c83770a11438b1956bca7c586595f8cdd28f90a033b22a27f10dfd6a3de68ae283b0af9b9fb3fae6963b9177ab6bd03b7ccef9e482c3c6cfb50434212c341afadcbb8c62ec4b63758c2ff5c4ea4e6625f8ebe1b51dadfc902c572d7786ff0acc39b82a3b3dd14ecaece9db85dde3d4f13cf7cfcfecbc5de471316585541a19270c3ac94aed43087b5c03e8da4f5ce3ab7cb10567d57fc2564e2df03143cad78a797bbdbe86e9d5d64f9cc9f9e46a288bafcca13edfabd4c1914884d6984447873d033a8164346b34405c8c0c84e1ee88d480d3bfda3aa075007d7647ee8581bfdf91912df7572bb8ebc9ae22f8dfb308e983788fdf835e415e883a401cf23a426da1b21de4d904b5d52bafa91b969f36811e829d8bafe39ed4d78e2f30c2e60038d96a95 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d0609608648016503040203050004409f24b226f1c31a5ced2822ae473ff80616c976eeaf6ca63f2ffdcf92238baaf570822977f1c37aa3b53a03a0ae95c82b8de631b9bbbd0a6bb6623d9b8ef18d0e +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 68f05fb0d353897bd65d75d3b54f34199bb8e5803b8f78c5b87fb71ac282866303b169a4b95b48baa4546f4a228fd9f899efaed9155b0a2a321100423d3cdfc596c8b31b58750f203c2a0a1dbb8d88f873d0bba7cccde9eadb566f3a87c606fceadc45fbfaca671568884f35c86ec981f30213d4a90f9c6e7bf70beae8498371 +S = e7c726b4bc65c98e0468e9e20bd38fde581f0975031c56bc8a1b149724bc313442436f6b0742aa96fef392f24f4c6e78c6afcb17a9a70a686c3091a0a746f6e427023877c5080ec23d50c2c8ed063b5d435ba3cadfb0786cc0fbec7d4b834e45ba3d4ba19101beb4cd0851cd66dac7dbe6028a5a27873b81580ef817c0cec52dcc99e5d0a48400109525813c9c087b403fff944c08febb645d36d0635c817d543d319cb0625fdc8e098cbd64b67c1981da87a4550d6bbc49d074fadff82f56332679baf1861b9f09ceeb8d18351dc7565af1e4729dbfb265056baf28ddd980dbdf512e9d86faa6acaeea1744f6437e30a9ea6faafffd6a813e255215bc1ef3e3a6d2879c763dacba1af4e657a7aa19e11143da902ee567fcf6ed9bad15f952e7087d1befe7bcef6a9f14fb7d7cbe9e06ff583ea888b27a0781c1e1c46dbabd14d5688f25cab383b05c79dd4f500bd2be7c647cab0b12c123a0257cda1f0dab31d42f70b53adc07765e583a146ecde0f37fde7c0f93e72cdc56e734577be3cd1a +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 98ccc6f8347973189f124ecceb360f429f1aa6f850ce712175c2b24a7688403d06db7d26b3e187f4bbadb302220837f7017126eb2162a2cbc8d54dfed3070048057cc0ef9f43ed1d317bbd86af16e94ac7dda61d72b4d7a5ca2081231b067f563cb6779d20270c5ba884559fbbe88e0599670ed76c4d797821aa3703750e252f +S = 039f309c9e084736e33c0be61eda376c5ab9759a0ef9e47f9fe17ae52cc6bf878cc2bc6bc3dbd9986f9f1b971a5eea3377a919922aeca340d63fc414376aea9670aba138a831f75b4bc63ff3b1964a6d732988e6d801f4bffde8b36fe629e57ff3f6d6ca425a8b7d23f6f66d647aad60e60819cf00afea8003bc56ae59de98a4f0e87ce92f4a12e3641a7b4c9dc53027659f0257c3ec7e013e8396b5a006ea8b1fea2eb25132618f75f5903640bcafba9f511338fc234e1f000cfccee896194d0182347e979afa5b03402690f959329ec567bad325172c913b4575c1c46722828a99e9a304f016eb615664a43ad1bdb26e99e429c2cda4926c9005af24de69861850b6a0908347b2e72474df05c775b7cfb2360df99dfafbed216844931117462497b51e40b6b634863eb5043f001b6d3b15e61f00de1d9f012fb774933f502089a213ad2eb89cd150b46895405f087c5c93d7a9fb55bce4a2d93505d81f2966ecc6e0386c1957451d014892087d978422c612d226c9dbdad48a3aafe50bec47 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 112b7aa9fec5c7ac703a49c298c4e29586083296f79b099e6ec422d586840ed486d36e06362d6554f14d4d01fc39a9d2167e5b7350bd18161f66185db0c4127a7b3a67951bcc9e6d5de010439746e4f43b773e65ab1ab4234fcd024be621fea819e6ce1c56aa5841db7cfa4f11f67b411c7a4233b0bbc60f267f4668cfa4baa6 +S = aa3ee99d39ad0332ca48deeb68b5966962018906f1e2e97d0d711df66e600fc875faf8da141212ea9bc49b2934f19bcb26f819b3633381b23f74f0c1d486c8fed6f6c17cacaac222e55c8c534ca2cb3921ca6f0cc19d045fa5456b4ffbc496d0d3079f19d93bba5600048b783a905abc3f30fe4b33b057a203b5f9d01254bdeb02896cc11b713fdca55e3ecc67e243fddf19130e2f3c79bd984558feef0fe877e071b0a13323e700de83244e2bcc09a602eaa06bb39d832d58e30450dcd96b30052778c07d4b209d5929bb6cc80800c95963a24bea449189301b50b5f26a899739dd0a4af6eba05e7e625c96cabda3beb2e4b0d11ccf72252b2d524d76a104a6dcef635517d78f248c78837422ac900557e1671958116500c673e2fc9a08e40d4eff8d44146f43fcc5f4086d276ba026e9953425a11b7be0036ddba0648f12424c3359cd8db8a0490b1bab3b35d3550840b4937ad1986aadedab74fcab27fec7561ae2bbcbb16d28d173efdf049fa8a1daae66db51f4c03fc91d1cda85d2cddc +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd +Msg = 7f1b83830b4da729242205b0e519b5243d32442d45f5a933d1b57bc54616613cabcdc99b02a7ddbad8cdb2a41b46c33d2cbd9f283585dee7bdda5944796a9bf06514926b14ef8a23448e5de0b682e35f3d21b03d1486ff1874d9e9f066d1dbd3d77646b9ea2c98ad92ed6c2d5fd6fdd498e5e1368b01f40c213a9291b553092b +S = c8e55b1b1ace23e606465dc81f6a349ad61d2b8a1afed31215ee6a0c8214c5366a2ce18cb649c4bcccde5ef2bf4af51f093049d1ecfa5f5b639f7ec62d5a4cbc505d0f11bae2c16d8d6a61a4f1f9613be25d66fcba03a7c405204cc816414a296787e5a1462d12fab51a829bf13dec500da689520ddddc305152021337a86b676545f8202c5f936d9cadeda41a111b65d9174488419dd19da5d3960b6f59281bb2e90b4c12891a1d5800d0b0a932bbc95639b130dc7d03402322f7cc7e06020d5124023b049c61cc6e88b345d0a395c80f1f04b7760f0c526537f4d4c515696253361a0eb03c3c5bf567cee736f63572c85db1c7e5d016ff19c0e1d38caf0f7569dc00e3c4301be9baed19d45aaa90ab7204c2c70191926ebac319caa27f55e5e68b57ba4a70dc153d750e318099c85359f1ebe70686f4bbaf9b9f6de3459cd8c4a7bcf8e559eb7c68790a67b0951554d9fed9b5c396f44860ec61cf0446cfa8061b19c72a34b62be8f34736fbf14fe556ad57aea605c60adbdee4d3fafc5af8 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +n = f33d3234f13272c3b2b6821ce4805663ff2e8b0d2a47de363d97fc9cc879cc6b40f9e53aea695dc538a0d2b558498829aac327eacbcd889e172b34f90745c5d528b7e82605f1a58fd228ec7fd4b6f476f393864f48dc47097c8a780a2ecc02f748138dbd7df99c52d822a2e5154c6047fb0eeb4f49da38edcae3c32d3fde435f291f96cad1e09e1030ad7efb4944b69e074d0d7964becb3cb86238d8d293bef3030d141d14868bc21fa133e9de1115f749991cf86ef506e663ac162b2c8567ff131a6b467a6f564d6c588860becbd88970354198ecdd4f1f4baee8f8bdaf7255835385f5673625f113550b123628a0be3994d91c3a19a82e5d73448dabf684ee6794fba7a2b1afbee0287e5a11180c29ce0896795d52ac7f408fe28e8e9116fe0b61a1083f95c5227d62d5537b5040b79e21b3a8e83c225bf3efebb2f808541e97d28a2468359fc60f588e74faad611262064628a25d8d61f9d03d8b21cca515595aaf2343a759b74a6a8afeffca139a389aa281995cd18e16a9cf7b7ff0dddb + +p = f3fcc6aae575312778d9e896acfd7c1aa4c5524f20453e8bab255363164afa7124b2425587a077fa0bfaf61b12ef3f0540dc4c9e777122a60610a53d1d75b0a5859c654a8ddfc2ff4860758bf5a6f264bf8bc2baa7551eb7be23bc06978be992fc81d890e07a3abf95d20eee3f6bbbc089985cac96395b473b2741c66bd2ccbef228432f66b906c15b19694dd786c29f06cbc17b2e6400dde4e3db85819382b3d05a4c3009f092d40d05ed5b2e0428a214e15a7aca09b47120b9ea6cb4084fcd + +q = ff36fcdc519fe10c69aa0dde2cf3bc72cf2ce9a54ac063d809b523f4e5d7ddaa5413d500dc21f409ce661bf33018b748fba3966d874bf96f4313eafea9decfba71d540ae0508161a3658c4762d94ebb3a4e228c45661315db30c20fbd9e20e24c044e4f0b49e6ec80949b16e0ab07f3d32b248b39f48332cc3686df05d29c170a7276acdd129259aaf018ae3afb49b6e0ddb9e404a492863daee7be71dfb11279047794e45f399a9665796d32d5e65956a13a6fbe992b36bf4c842f5f519ac47 + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = 3330bc3d3eda995522e8849c7e8bb5f3f6e895b3d7238156febdca74f62100f26079707698c6eb1d9530c971119a2e95ea7a8cc3c9e869f901f563eeba3d714b4ec06b18f3edcd749b00b88a188e39c0845ece31e07b265efb872920955238e2c5acb60c9877c7c2fb0057cfdb8f5fdc8a3c63e6650540efb41e24f3d188de1d +S = 5949a5007545d28832b13c6c0a453447eff95e2dcff9e403db83bba0379abed6d503394befaedefe578be085622fa73ab8f63af52eb91dded8a0456df41651cabccfd34250b813b57dcc4535edbe0901196724c0842b951ebf3ab469faaa51fb22e5574696dbb57614892d21a889224f6bb0da4b81b8fce60499b8802b36f1576780e298d87b71dd5496128b0c8fbd3f1994385c8029b720cde1317db984e02c0ee77cafca705d4be54fbca18c4f5ddf85eaeab784002c8d1fdf5e3794d94c5c6c781e9c05eee22e4c1556d9f8f6215b23d5c687ddb79af29a280a4cd6be95542709f423d918d9147c2c501d3f6121e942fbeedbe70dafaf76819842d651df018959e586e8ac4325a5e616c3e6474e1640d259c55474366761156aabd0d144a6437e7584bf33089ead0610f9ce10dbe39fa93ecc7665082d64aac474432689758cdb092757a53ee5b9b4eb3f6ec3589074248ee547c6fd203fe5bbf217974f1e2e398dd4d1909e85146d7e1dcf74ed9478ebd414268bef406228ef21c80ed1e4 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = cb67ebf8f8adde0c2b0640db1f4668ef866c27606577504abb7b777e63f3f8783b593c9286f437778ff235d990b6d767d17358f914fa150e31d04d79fe842557713fef44099dabcf69bbce2b479243278483b05f9c32fab441980bfb4354d3f2b3428c78484f43fd018c94370c81b516e7c3b6fbc5c9062533fb3a6bfb0c0a31 +S = 5e8e0eda2fd7477143e33826c1f37f1091e766874f8d9717ada2754610aee94c5bdbcf939e710a2d5bdce1329aaab8eee0a33ea8d93ac243e80a61f09fe31dad8eb291525dfda5110148a9041551c4673db5edb4d3e457e2ac8834bfe600ad9e210a9dbd238f8811552a5a6de7ac23e7ead2746cce7358e7b0fe27af32e204bf292e7be24536a1df8e10712bce78d0d94331de7095e9f56760d7e9e3534b0a8bb30357e2948e2e649c489e916abb399541067f778a21505e0ce4e43e3a64c30fcb8a22c575b2f63868b151e7c0865a52884008477d78aedec9b950bca5ffa93dee9c7b8234a054b61d2898a4fdafb1cd2008635ff56744d0419cee15477f544caf2b264dff93c2ef060fbc7e062ea29d80bec0e74287d9e2c0adba92b5592c4339776bef5cda132c83f296810833cc99119aaa31849ddcf62bf16c45f7654f04ac4eac75102e9c5b79738e7d405caa63dd917f3f199d132169192397198c67551ea78339ae376502e7e4ab23e5626c766fba9916ecd20d15fd63c75e4a927ec8 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = fc57235b4d597f5a5380a07aaf7ac6074b17d75ee4b504ffc6fcaae4d7cb7611d771cd6de6216bd047a04a5d6341c5121113fd9d14597c71e53a181ab4ba1acda9e9a0446f5a40c9f3d7ee9069532049912030f6386301fa01c4e573656abecaf9266489efee476ce08e56bac99a1fd553a7371057badcc2a101d999f4c1aa30 +S = 5b53b1a1fbbb8a28bc715cd607a699caa795fcff045e660e102b6c51e0daf25a9cc0d0639c1bbcbb9805904cf16ea3bc26c18f58a3702f39a3c1cbc5e6dac954d65d102e0c44345704844af1b8e3f15b7dad532192e35e27a335bb67dd3367c828b7eac524e1fa3a1db556c0c3180487ce197cef59ef05025d0e0c7dfb87fd9da457d15688434f5165f16205a8400849118de58b6380b807a6600c698b2553979c7e0b83ca200433c5b5a6155eb6b37ccd8d584f695a93e2b1a3f933e3a0997c18ec63c6e90c54f87bc48b8057be5eea9131d8acd848843fb3aea56882c414258478548a7806de7db039d97c5c440d8a99923cfd7c3718046fb16bfe53dfd157be94edc1ce944fd5770c38247d78927947c06d113759f4134c841323b3679b0e1b4537335d4a16aa2ddb01fb1735b8f8d0b0107ae714fbf727ac74572d355da37b997b9a424735f535232ddacd026814799d86b91b7701753fe1952651e991a1b8357f43ea06c043ca1cd57fdec28ddbe011554bc04dbbf3cecd03710d454bfd +SaltVal = 00 +Result = P + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = 6449afe8eb08b35e4411a1bdf1eab7d7cf0d5813f83b1063e714d376dde5852e84c1c054d2d3d18b31f20382dd76216e8d4a36b8554397f2cbb023106933cad532cf4c8b984143f79e94648c3af002dffdb3d35bf5c2f736d32236a349c28a4ab69bddf505fb138cd21e4b43cfff6212676db966a1613916468f9498463bcd75 +S = aa36dfbe785a437cd2c92b11941827bb4884157fdcae8331de98ab8d3294ce8425e719b3b0e54eb27d7a46e9729ce18044880a18261d28d6c10641818d7dd47c421d748c984597cfcfca821f8c3294da53d16c1af99135f750294709b92755a3f5051e033ce3f6df055a77c628ca952511a33b2a1e6ebdae047d9c7589c8689e9ab16747dd4788d023315e6c98f2f060f3bcb655d487afccef512d929da03e0e4d7ecc2b7715ca61cbad3f8fd8f4383391014f14fb414cf49347ac60c01b713b6dad9e09e60b927b261aa5877a1d5b0e76906d40bc77cfb41405b93a3c93fc2ac12aa08e44b577980e2ffdbce606aee14533c8161c85ce8e4493a8c1aa03f708c6a4f84d44f9d147082c1d6d0c8498e109d4e26406ddaeaafb9409cb2cf249a6308d3d8d7bedbb8133d542513d9c4424a3609e81066dece42a7a115279af0155e3596058a4e22f6876cd931f1e4e5ae5800ca96eca88a3c04b789ca1c843fa9730b4c050e269f9f101a48c5c1df7e5770f5a823e1e29dcb47367153a17bff1ec +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a05000414c2f234adf6d0986f254e79e3e89264f7681cdb65efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = 6d16916bed6c4e35c76fcf5ba043724e7404bb147d12534057ac512261c1b93b660242f37d3c5d8f2de5725dd5f56d314bf77915c45f0b3df41e23397674cf6e6d05f0c76c3040a8939c9424fb135f6f55947896cda31d6d35e437c95fe8dff0ca47224e81ef016a41bbbc18da4851efd7043ffd61878fba6127153be5c6f4a8 +S = b08db35d788332d2bdeb8e89c371858710b0664e464f9b726c92ffa837387e7ff14a885cc776b1ec4763da1c7120c5da133c3dc01de44c93fae6a9e13c3542f5ac6ea44f3ac9892a5b775a535b4723777a43240af123ef78bb1c1d6788098fd148a764290a559ff2637af485d280bed6e1b289e518aee6cbe842b3feedd158c409d13a5f117c8db853bab5b564e43a06a83f4d2748cd718bdb8fe41f5fcdf9f0104dd8125fddb401e8b5ddcad388007c3c86c0e4502c94e67b0d194002f5464d22ca2ec65af465abbd44bf90e3b578a9884b86728fe22705a9ab24549d4c168eb7b3f1c6f6b07a55c3a8347b392e0eb50ae985a7e3eef4cbfe060692b45c6671597c59947d056b9452b2030529705a6793547d75d67298182087193f608163f3599464ab3ffe82539e202679b84df75ad7effd5985b9e08a88d3977dc978b748a9bece9e08b42b88ec6a766989aa03c1ff73445706035cb50fbf01f89c9855784912dc7b911cadacb0fac987e7f5bab76d9658ff84755c70225a4e42bdc84feb +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = 724265b54dd8716ecca57175e3182d40c4ef7a1f0d9e0fc240f095fc75f0fdc64b0a1687246e5f9392b51af10cc7a161e6fcfd9d8081b5e0bdfee4a5b6758eb1b06e34534c51a6ebfe1319a9c0147997084801daf7960835d37d1eceb7fd573589b5e7a22d49ef7ef806972568c95deb121cad5ddba3b1c96bb76a00df50005a +S = b2f503ef1d4b84ee0abdcf78640f1f82de00b2f5fefd803e1322a3e09e617750884b4d6d7e8aa741c93e9b36dae70647c3fae398161729f2f8962f9985157ff7fd7de42d8ae7579602fec0f91d0350a8bb38fb54234d806f3251eb6ee2a3806e3fa846a7add80f0d2dd2fe9977265f5ada5012f739bd3f06925d7b8ce869851bbd5897b819c71effe7a611b1105e68a3edc5b70cede299548e9116841ff1ee624ce0d8d477a18c723ac05c756084f4e7cbfe851db1e044ea175c8603f90a4ea87421e79565b8ad247c9885a41af0a2d1032f2807b731f574d54b6c82af900b0a1815b4e30513c7033e67a1c78329dff1a4542bf28aa5ea78de037bcbd7a9e0740693f71586d2dde6df39a979dc55335854d656a8a4f123b4414504b1a3f3f0f5e7d12ab700d24b9f34df58eccf2371d9e8429f5f206122b3663f99ba02929e8f46aaf061845f793ba8bc7e4de8621bf2d1df9a1ae2fc130a478437c10d2bbd51207dc07af35c88c5807c92b739d3b5a689250ecf86bf1bcc8e3b5238d2884073 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a050004143ea74de96d5511a9072c9cb0dab7868fc0c87e3d +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = a6185cf668fe6bcd1a872da768424d95f6d52792a0342c580617887948aa03aa0e862562cce09ea44400e5184cf51e61d18841ab1c6e798354c2caec44b2f7af5f78a3f2018cb60cf817029843ab27c81932b3fd2e258e9431ff960299f08623a1d51ccf91687baf40b4ce4ed7cd2e73d7bdc6af5ec13432a6b633e2cece77af +S = a31dc7740083a5c5b17c2b4549d4ff97405b2de7a5d878ba927fe7cba62de764685a23f65cdfbe9d0ae2060434443f8b18d8032e7d7b952428dab81cd158ea3946d17c28d1bb160e6e8da0be12489206cc1c57670da9277e53ffd10a3a4883796d9389e2a361e335efe34e91d6d12e78f606a7e79fa3afc7640396d72cf34cf39150e7784110ba4c703d34747ce050c0d679ef7b1e72cc9e049e4ec583b9aae258d08560e74ba41d4917d8f41c1d4a3b8f04bb76c99b36f738619e6c3b977f716f1229da7d54287c0209403ceb35e98e77cc37499b7c2127254ddec1826d8ed6fb83ffa13e4727ad2329d6c85df002025b0639399a050bc2ee13ef43d4b5cf25a36cc0c9fa27c2e2523093dc48a2b1f66aab351965866459f6c4bb59827cdef8058311a81713c011f8f77f819c906be90fc9e09b6c5cd8ded0da32a30e756ac1fc26282af539dba2398ab21a254067fa338479714fa3b37fd7d7e6032e6b9e5cd31f23972b1aedc53778ceb8a39d3b2b3337e694be843e35dcfc310b09f560f0 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = f5df0f6986dd3e9cf4c243af92a6a69fba85406eb7944318e2d47ac80ce7d24c1c231ac6f9e507a5ab277bd4bd550631e55dae41e706eb22b682f6c1dc46434d1d194ceb576b91abade9ddbae44ecada0d7c871065cbd99c79a1602e8e431c573fea303e681ae594432ff1cad139fa817c095642fa8c156f74584179e8856454 +S = aa1f614775143e046d4ab4d317f2a69a319e82f91dd4e9e3cde226c5ff87bca2093afefa76890fd8a2cefe38c96aa94dfe9efe7e3975425f77bc6b4b13f2c84e8ee80aa7ebd95683a95ae0255f0923faecce58b02c6dc9ac9336801fd0a768d6df0a0b705d8e1402fb8f769ed32f8cb890be42b86a1035d73f01ff6757bd02a7e99449a5849f0f2d0003ef53773a0b13cc07e53a81a7914892238ef798faad7660f9caea94abc282870714d1e9bf7d29840f0beea5cf4addb6bda8b441db30dd43e207249577db9af55c674cc58ba2cefaf1a4fb03ee766f45dc46aacd12c7cc5508371db63f2b971e6842819a33b3535a1592787bdb0544317f88cfd63e43dcc987472cfbafdaa5923b3737165f979ebfb647d86f6d2a8dd5137484225164b19f063fca9cc72f516b2402983f7e5a643f8cb299870166b04177daeb90ea978e957d5f7a918063253d7144f589019c7691c6198f830b86d9c8a97af6d530d0c1126b377d5f450ee9eebe33a9b135774624f575caa08871c549f2d074552ca2b6 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = e3fc380f53d94344f864766b7f1ca420e59f430ff31d120a080bff5a181c4753f56ddf2ccdff130df46b6d68e4d1d88d83120579a43f0eefcf5159cb451ac0923f7bee4d77d80c98e9c99ef6db12a7671bd6143d8807572bd321539f87187851478e2f1c574a780e5fe6d1bb6bc75bd635533802a75d37e59ce4b37ee7feb8b9 +S = 6556cf98dad966f1c91e0fc492d74f52a7896d1901409047bc630f4b4e97044cb9f142e6560467aab4d65a302d856f72c15332873e0a8b646b3c70bfa8d522c50906c240289741e5e9d11f77a640b7d96707c959d130355fb2a2fd65af4bef7f05ef9496f630f79139d90556a970e1110d12ef10a1b7e74e6dcf7a39ae299ef8649c06d745104ca65b82b52eaa0f00f936525065221a690a65afd7699d93c70405403cc13a72d944dcc0efcd431604aa638515033cfb499207de58a798a22c047d18dc825abead4848c7f521eb1ddb2a10af5fd7bbdf9eca83fea139f6a015b614d7126652a302786850f400c05c2945de31cdbf0ae83c3e39c80a1860d233f17e5925a211b1a35e1e7bd72cc1785f9674f858b43759542809a3d9e241d29a62519424c8215815e0e85bd1374ef99ec64f08b3e84e3a6c04918462098329c97d8522aae23e3d5511d6489a1155774916946e7e0e10979905c5cb603561fb6004dcfc30ad2b6817272be904e928c4951eded095e75a5f7726f255b01a85211bf4 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = 167c1cf3b93548a9248cba2d5024da528f9a23bbcdb883a915ec051157f8adf268eaa3e54a4f95f6aea456b2b70dcb81014a0736e2e6b5e5efb1b6f4c2710c75fbd5f7b385aa5d0b1b516ffe0a718a8438e95ba26509473eb1010a335e999ea1d8235e86f2ae6b93737d4f38d1b8e0023c606726de88025e62c347f3b3d92a1b +S = 674ee4315853c10823b2d0da2e4b13b6125b9ab7ec5458fa09139ae74dd16b83f88a75bbff1b7d70a3d099d12c6a84661dc4097ddf5b569a5f3d1ff4de4b595dfc0a6726d1e6d1962af78a94ed73fd2104fcedafb61097f8753b5e8420e17e284179e7fbd16d3ca50ed0a66c5c2ea1e412f3f758ec18f6fc07e69164f71a8a1d779365a5042f5ab514005937da2b92b5120b62590134888134176f5cafbbb4a98f08c4e2d581e0ad9deb2caa666f36d4ee13e3be6a31861e4609479dcd4796b9064e7164aa7569230baba4fdcda388bff7d2c52645e9d4331c76cd2726eaa7039078fc0f74a47882bc0a47ffbb43e284d6dc4532e94f4bafa5e17d8dd2f108cb2f3b206e06eacd8a901a6e1f7c82ea45959c3de898560678aaa052ea9d9217e97b2a30de1cf6649fccac679f15317423078edf88af05080b679a581be29a76d8cc20ea7d33ec576ae8aef7d58c1b3126f6efa0941434b6dea5c0ffe8f404f1d37cacc3c5e853ad269a18bbc19720cd214eccc813d95ec62a0f083d2d0e66224e +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c20f660487ee230a6692b24f4eab6705e71f3b31197c1b445b5986def +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = 2524a5d692240e9c82d0d620a0b7a08c3f71ee679bd78a676174268672363f57e469479b4ae6021036883189fce06e43b82a5777927fee2c404c404fcd024505990f0840a20e0791013add3db8291e92aab7837beb4047533a12d0f7cc21921f4cfd31ee1f02e5c7ecce23635cf97a201e00bb9c2f815c8358ae1ea5f8fcee4c +S = b7ef6a53edc10ca9d6a16678c2cc38ee3859dfec0ed0012c788c5981fe2a1d04103acb6179c176d9f9003eb86db354fd504107c7921608e131cb3d4642ea87c0be3e91e7e85943e7ba650db959eeee710b0cec5817990de252244e95aafae943b9828f11da0e490d11b5990ca2d3254095f3ffc0defc38e5d9d87e3088a84d002844b8fb7231cc7d69539bcefa4eb345168529a12cbf866a76bc1f46c112b25099f91290222b839ba7167e8bb99a001d139e18a231c6fd5c7ddde5a0799b2885f8d32b77b620fa555d43bcfa1cdb897e53d8786f7fa2a734cf881994fd8b71148a3b96791c18d28fb6e39e9acea7e61a03b3367a1eed28c15ffed710389c6b047ac5cecc30cf4a9b0ac2648204c72ba48a7957e7190e4d34bd8a55e3e488e61cc64f1130d81f5a182d480fe032aa7f7302ab386eac8666c2213b103872564c11ac0e63f1b9a2946f3e185a0815e4ee2aab57a592344afb8568d70979e62077d5256fed2aa02d800ebadd4d9b26d7ec7ef0b3edf89d2fadbeed40f35b54897f49 +SaltVal = 00 +Result = P + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = 93af2807782787ccbdda1f2d60e56c455c5ef40f152fcfd7f62466ee59427ba2a75b6a6dc0dfae6d9df5a61434ca99219b29f9cf714de44c7af3f06c89b3289fa38f522161cd7470960296033270c8396691679009f49d173b48272648b75b4ccf7569892398e1bdf12a7561237c017505bec8b9a6cd0020824c92825df61b91 +S = c0aff8cf59e543109654e1bd05a2fac0a13782cf26cff6978a07e72b6aa64ab84dba40836ec1504a83a51374e32f09dee79845cda7aa9fb6c75a9bde61616addd9bef949f55d5a638615e3947c64fe8d8a85bb54ef6e71090b7c84812da8d4af8929c1964f27820435a587318c148f9221fdb4b63ce7f43c22a0e840bdfc56ec1205fbc5735158a1a6624869e4ca791d95b2fa01b1e1434709014549f4c0998a0574c6711d1a4295b653317db362f151b371a851535601de3d66d03c24fcce8116c1242e523a074754231f3c70e9e2985a5228021fd6389823a48b5aa2a70febcd61aec23fe98f6a9f305d588289c6e3f2522b6c28a94bdb27bc81b44a39a0b826572ea40a9772b9e3aff50106bd77b2a5ccaa1b901eee1d8ea6e037f7815110fefaf2cba69c55f7035d2771b095ce38d13553798c400e2f7d407fd0b3dcdb38d8592c4edfc5e5cece6aff1be8de3769a3269fc2a99d1ecc98c0ffae39313c1827b81d361074f9d1919829e23e20d0f2e361417b35da1eee8849899ed2f199fe +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c9cf324cc0a040165d93508d7218c029560c75dc71785fa64343930ecefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = 38f06d35930bdafb5aa674262c796b395036f3a54103e9e26a2ebabd2e1c81f42b836f00c0d97032cc0d0b01b9748aa3ba065cda50cab711138f82a7afdd718b2d2b7209745248e30f4275a430f45e31f5a0aaa1eb2feb4ed1f3802c9e96ba5ac5503df7b75da937a9af7ab698e02d0c8b6aa5a1191accc32ac27df5022fa28a +S = 0ea93bb8e9b4639bc999e044c328e9991b5986dec71937465695d5ede0a28d5f152cd19cee3794ce1391a2cef186a92a789e46f70d7ab5e38d0d02ada5a9bcb558ab77fc06ab08db51d159cd9648a49cdd7239748ca02eea81e3e08758cc4054e279e1a98d77a2cb9ff77649c84e843f02d61b98ab73788da32b8fbd9e7d0338089ff2697341e4fee7cc72b73093e098b361a76eb0d56072b9bd04aeb05eae4c918027dc6f3c12607c504031d54e456af36be5c711b544bcba137fe415e96c25d5931a4524bff801bcd5f771370d42157ab1304c201ab6654dfa4f5f933aef840b74feedf08a3c8d74ca4de6fe562950bb7e5c3d901a3eebe1bfb2c6b6ec24b44535bd0f89b6ba7ff65378a65781ccc5243a9578f74f90f894447c49d240d6e118e92ebfcd8079326174b55291ecf57bf39813df3651f690eb1c5d8056b8bd50cbac145e909138c37a6844a5b624da4be9d13a988a5c43e2b49d11f035a92a098a59071b26231b024c1f6fad1920c2059cb53838215c6be939b2db31ba595ad3 +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = 49da6ae32f9149781533adb07e035a916ad270052b7ee57f74b931e1b30b4b9ea01ad51b162a935c23e022dc5b4be7bc71254520085513d7c6b94d3aaa230956a0a1ad4d530260f94395bed31734d01334813b198e70b70cbe06c3c1566098de71f65b3f8e2196989edbe95c5bc6fddedc71bab766d6ba678627fd3f5ccade7e +S = 1273aec2765d853e0dbc6819df05d3c008cf12a14078d0398ad1c833340e8aa656e463f170324879d99e14a10f67e29b5b09b9dbe71e93b298c61db9c47426064dc5a95d250cb06fdd9d3258a6112180a390df3a82aefabbe5c3083e0978725da87104c50d9e831d24ad9545f3c11eade633638589e04685f671e68a6ece18c856521d91d4d74fda95879ee39a45ac139416472c3a5ba6fa17d744745da2a7a5ca1b2d38e813d2058f7fa54a2787e464a9764b11f7421f6fcabbf982f4046b4d4ef7f0e86caf038265c0f1711b2ce4ddcc5a70b8f77337fa219c1068f15f8533d99e9773313159f04f746d629129f03e517280d3c41f304e531cb8ab3e6c5a097700e9f890026274cf9deb9e80836636b3dfb2133d24cbd7c5174e89ac5e28dc2523b13b4e1031913e172eca410c3ac3cac74734b45f8448a531aca430f0d00d3bfbaede84d9c4220ea88017edea356d19e30678ea5f82ea7537192f10489ff50e40eed9f4f78075a37613df24d5da59fd075f1a45cc9d7a61a2ef8274c0e7ff +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = a455b7d1b3b32ef7daa94505fe97b16726745409dfadbfc9df30f52ce7c3714fee9b6b217b2a58d05338b0815435f344a1ceee47ffbe3b4a7fe707525ea117a229520de7243fe8b3eda1cb2c5dfcff06afac3aaee4c022c8650c0ddceb7a0b4c9ca1268a7799e887f10d1e6fe091dc939936c1a7555c7c2ddac88f3157f75337 +S = b92a17bc07f74204ac547672fd12d01df6888ed332d1453aa423e504c11c4828e500edb7ccf8071f1f98c4b68a7fdbe665a3b82fec5acbde24a0be40bace89bcb59d4f9b83323e6f3cd0656cf9334974b02d437155d6d37a02de832a8356a88f83cce253b4bce850d9c5e00e89a6bfe1ef7215d64b68a259b8f25fab901f5e6f9f0a8b508c554f2b1162ba358fa5270c6ded1e36af3f47c3558523eb1c3c7d6373e4679324481300e8af1737ee62b840001659678987017d2212c4387dd16105dd81f77b40357f607a7d5bd6ce07f7ee5d7ac4cd6d0df5136751d438000b26e4d36585ccb743102fadb674251a870396a3c0c91f6df33af415c196f7de0746d2060b28b456bad9b0c81d22a58f2e9ce06371b5d40a8eb1d0fb98a1610fb734e9fdd48fc553b08dc13dab29328cc3ba552557e2bc4c245c247cc7549a03bd2b616c01e98b04ea835d0f02c6d13939f62264d28aeadce370df07e722057254aa312f0abcfd306431d880330fed7d76337f58eca8a24bf3860a8c758a6df39d95e9 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = d262295e4f40d1ddaecf5fcd56af7b80625a4cd83c64a3ad6d02766fb3ca910d54b98815b37af01c21e5ce60f5c750acdfe1bb7c7933a5621f7a64a801f7c637767203b7947feff8fd007491fbeb40c7d04dbbb0478f3c988ff87ca349744bb4e094818e19d53839eb2538a890a3b398dca733bbce02d0166587a6a7b4ca864c +S = b27d86aba157581c706913aefc77e7ac3c9d4946c646a6f7ff78d4c1c19d0488637c010dff274cedf37014fe1c89d29018daab58b5aada55fbc35cc973290d3f4a7e7c61f78fb3216793d087adbcda38d963fea102b4240a09cdd433086248173f201171ae10014b0c785b5c374c0fc2a38e021f98d78954aefe53244d01cff67b7991ba28dbb1127f21ebba54440d31f5ab3bfa6be1b7d6696445e47f071232be25b08da70ac8ec00603910f9706d6f3692de55d1e646cc7c34a4887cd692e69db28e00a5de8c8d2a618e351f7714c59ebc419231e36d6debba2d3a054ecfb9bf6268e6507aa96823acd635f6d31b6d716ae10425c9661a0a8b7b8797d2d90d27336faa572a13b33dffb81918b42c70c28f0ae88ffc923120cc50ee8f5d9025f71936b606bf44b8d1f26dce76b1b13f2b6c3c5903407e846fce2dc7e3d7fbfd00693e4c25dd96ede4e29473d8edb7532b729010df0aa73d81386c470af3326fb3bdbae500965c0bcc7697e92f8cffc14ea29e5021b56d4f78a668c72a57bf86 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = c9e861253ff04d978781a7a45099445db4fbacba1c821e905eb6d4bd299d87a5a3d436e350dd243836bb20c73fbc0885de9790ebf5b640eef7d5bc304acc4878efa98b606402934dc98a1aa443e1083b9eb1390e36f67f34179deb11635148ccf492e9034307a5be88151fa223b04b683b712d8da5e9e44a0736e8c63dd3908b +S = af1a58738c5900de8d3be297fcd89458a2c11b90532dbf31acb6a4bb1ef2141e866637bd59e7af286f396bffa1fb46e13c2ddf0591df51a8ec29691c03d734ba37727421806cca1650cf172cbca3c60876992af88037e6e43902eca5c2c91ba7cf8a408adcb5545bb4151f05a31db4bfb17978aaba5b5bc626c07880f52c47f2f53d60b5197f4374695ded18f18dea635940740a3c5aee8caa9f01ce9fb02ee9bb66743fab75e63e2233089302044085c5e0ddb723aa142e0ba9f30abeb47782655d980dd7869caf0ca65b25958395dbff5fbac082141bc6cec4f032c60e973e0a6b1421f5126b5ecaf92f4873077dcca2d90b492ecfecb1fd76512ad2726f9c036206bc34deab19dd39182b8616eda9f97745f2e09432ae55ddd6ec683bd366e45668dffad941e7458e01afda6e3a232fb715799975cd9d81130d73f834300f2657112d57d661ea7705e912854676e50c43ace1093ba5bf579627e97e2539d6b0fe53741541487f89c2fac52fc97dd4dfe0b58c9637cbbd84011a80adeb3789 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420bd0a68c45ca3504eff3fd99a411e4930d50450c1dfaf869af04bbec14d10a9c0 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = b44a3b7de7c8b57126fa95ae13853b28a221ce78d84d2330d242e06b0825e1a8d380dad82df33eb5b82760560304d90008242940f987a1363c888034b40f5c884209c3958b152329fc80e70a0c74e3d2c16cf2fd76ebdd41db6e7f1e3d9f27b508cb3edd8a962a74f9ee71f3b83d2245d6e371dad8e3a1f7b8dc27502d3c0cd8 +S = 7f0b8969669053c26cb0051e0c182fa688375ed6afdd39f7982d88bdf8d422e9c9ce4ab5d1f63a18db785031d17a3286d7cc1349d1ebfd764522cab0962fcb1e071394d00b4595231e8fb7db6d10e659ce8158ebe78e7ea60818d0276a2645cf2dea02d12e9447652259dd12a93936cf2cc0259d03fac70ccf47c99dd8e0b5cc9f90916a961e9b16f9e80b51dfdb38a6efefdb5e2dbd7359a292b89d8aed8868b7e9fc444a262a04a331894a57ef0eb2be8ecf79c6481fa8bee709bbfe6cdcebf04325e98ea156e82a4cb87afd1d69eca37f4dca02c319c3f83f65cb12aad441f8cb92e48ae789626b3662158148a61d8bad4b265df2fdb03730b947f5e542d9ef319e271fa27e598d39c9e6b645b610f96836ddc5523263a98f901f9b47e3046fe324702732a62206fcaf7373df7d987d236574b8b66bff55518ee403ed9e9763e366c26bf3ae47c8f1be461bcc6dedf549b3ea7d5649b5d7bbcbcbbbbeeda04218b861044f3115b684cd82a71be509345ffef5d5326071c4c63d119e86ff38 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420e3b41f283a3ef951ad52a3dd58c46db1518442328f512485699894018fa1ab54efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = 0d0547eee5ac01f37f29f03aadcfa560adbd5b02b5182d23cf9787cde745dbfb228295b7724b508068bc4aee49d3159963779036a1b916035e59f566778c22d0a4fc2be808116ce6066f863c57c00d7c59b38176aa4480a0f63f39bc0dff24b4397cf1c9ce85beec02498c6cff1cf4d23778160af842d3c3404f3c17d227496f +S = 8b3380702deaf0e22ef08ca6c3c9e68616de1359a1cfd5f03968148a837f11f15474046c6434aa2a69005855ca945556c04ec3b57daccb2605683474eeae4fffeb19c221ee5c61b54b0914dc0ae7253d72e6d73b669f52651ff2d25e513e565d3648e6d5eeee63891ace75b924a2143dda487d8076174784165b105663719273ea6b42209ec456bf1f433b117e02e6a5bb35e285618cabebf49a8fbdf046b05bbd37020dece2afd1f6c9bd2fc804ba09bdb0d8aa7af0de45b7ff616d051106f6727415a460a62983817e373474666dcc8260a3ebfd59341f01990e6d8b7d15092c3d7dedc2d4190d75374d138bb414610834d48c9bc23c43d1ea96c7e9294a2d803c26a427e4a2b5f86f19bc7d10da9aaee219291c94d7a3052211f6c5b739168e544747b8090705a63671df1ba7a82d8cc5e76b5475acae66455fe377cf52156549d7431191573f60ffdd24d6640610f4515e3801a526d49fefc2d1b59456e3337485cab9955afada0ad5e33deba6944d98b24c24731acc54b78ea1cd2808fa +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = 9802b7acc01de6de29215e2878ea1ddec20fefe95963e56ce5c203a7b60a391b586795ee68d4b692a7de84a24dab1e0ca03c1475c4efd7d9d5486d7233f069dc1dfe1b768276040b130f8cb29d3af8f2965f962af66a3a304886ee390028e6f90f50b20bb50cb792963de021119d91d8cd01ddd094dcf8ba6505efc2c4ba96ba +S = 99e39af2014f011fbb413ec25a428af8ee4bf6f2adb3fd20964d551ad8355c46cdfe35c955cff611d299f533852288ad20b901d80e048ca80eb3cacd83e638e15953413e3018076e91b1064b2c0d615c8bd6b9098f7e3b6da919470636135b926c97124e943e987355c6d71d683136c8fa9698f15c0ed3abf9ab7f03f5e565f1f1b1b056d7d1ecbbd1d7afc5a45bce19984c8ff9a92437d832f89f0cfc5700d18482c4d63376fdbb851ba2a1f272df06718faaba2e9e1c8ee1bd3a3aca58a02aad3437f89fbfbea5f12b8ebc336b8dc942058c80e099c60ed6ca6ce128faec8343aede16c44ea97e1ac1073e24f5499772b8abdad9c8c33922bcdac1068715c74f4822b4e9109a8020270997db56299052f14132a1d7b19820e380ea74a68236de72be5d33f4e89c5fed4ca643f6ed7a3f505aad27a22b6ff694597c883896fffba2ef4fe81cf44cfe342ed6fa127cf31c58a16a5a35919cf2cc3adb47c6c84f660bd9e2dcc4b8b29beaef329affd4b5cff2c59cebaf3648624485c4cf94e9ec +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d060960864801650304020205000430825058944465183ce7f88365fe96cbadd70cebade9f1469771f0a1bb5ef6e86c4e3e35d2a34393aad10183ead0436783efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = b438d4fd3a46058f4eecae06d9bf1d43c54eb5ebb504446bf350903aa902335e55f9a93277fba8668ce4af474003e241e0c115a20e8327a0b8d2919e4bba3eab236f9e4c4737f67b5383faefb55f9d9e1c0d28812eed89977aa1ee2cad6d935b08e4d8d211c197d58913b4869f9df663637c15107d0a14571f03d06d38e6da76 +S = efe705f492c2f05595143b7d2fede01de8d4ed8aa6730d5db7540d9353bdce15cad57eef7e66e98a0fc3d34e223be094c5f60dedb8c89f5c3e4f6b10f5d41415e098741bcd4324558655b215217582daebfd44d2154748a707d2219f68a1e9d97a75900329dfc0d7a28b1929775bd37fb66524945b6b86635dba4f2e7a95da17301a1522effe0728edf148e7007810ad509d8d541e6520b83247052e9e79a84746f11f469eb4db1446f5dce3519f09d8b4f154b0f3c403d23a37e89aa68683027b76fcbdf373496216aeda698b2fb8785e364bf2bd2449277c0d8420ceb2c157f8663a35c02f1c4a4aa86c7753ed755e60c022a4bb3106da295f3a2a72f2c861c619b8726f1749b9bae639589b72e9e34eb9176608f2a38daee1329de2f28291216b8c77a7409eb5c1d7e351e906f1f25a26c6df4abf3038658f7cdcfa3e1fd611efb4cc6c5167c4f76e2100d02612e12d2e696c80ce977e7a150e477ae0b67af577a62a6b57e6bfb9ce19f56979008076c73f018e5479de5c69bf1ebf5aca53 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = fc06f66ce9cb46deaf65f79666dcfa90b09d1e2fecd7e2caac268767696f6ac6760b91a233278433836a5ef780d923b26df854b4eb32c15a707b9fd7f634da34f04fad9682b36fc0f1e2b0d859d9846e9e381fbaa4a2a225c367350c756056c0521b70d13f38b08ce21314c259a4c5cb2ba3a6cb7eef2d348b30728c50bb8571 +S = 6106401f71a67b9b68fedb23595f45492fc7eec4557a00a5638aae54d3854dbd87d2f66eb94cea8c02f466a85983a37fd202ccad8892eee14e3301fc132c530b36b31383739ed7a51433e90cb7ccf1c17a0a512d249e70a3d51b7dda16680946872856e5901c726d3bf2af49fc264c3c6a373d9135e802a8ca37ba891c9e13c21dea83ddd6c55c25867872e18c0a726d5fe6dd3d6ddddfa0cff7246a63dd38cbd738945afbb3be72c55cc2ef38f56d596619970312d93a9322098601193d1dd537e1041b46e8ab5d67b40a069b4153d365742a32ff81defb4fd00782695b81b124959d33c29e88a1d911c4da17dc32d41c1b5f1836ae1654d56feb9a55a488a2a97a92ddfd9c754713309f661739cb2baef671bf41a3e74452690e0131bd3a3675316d296d696b0f07a50516897043a5b2f090bbb618d822245f5fa5aa7125551aa988ffb289e8804bd5149cc8ff372496a5071ae7f8583a8755effea0c6599116ae5b8a3f94ef2f4e6d440c9304d6a091ebf14fcd8700ad5367a21e6e8105ed +SaltVal = 00 +Result = P + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = c2fd970b5b17cd1a58dc8423f1354f7feb5fc86a609c7b59c229ff8e1d6f66e99c7dd8014fb67a732bc7947a53ddf4c096148d743832649df595adae436a305ad820f2a96c1c124cc0aff12edf45954ba3df50c57cc39c346d714a3e57dadc697acd2f2c39b25d4c1d7ae1661dd6fcc71da75884b4b6ecc832a61f68e22730bd +S = 861383c21c18f931fc4fb352d846e725e39cc117c4324952344cd007b6a00ccf08fc79048545fab5c30fb356460d5af25a63f83871dea84d464ce4179cbe5e6fd09a384c45ad046101a9460238eb3f445e8911970cb9c43d096f70b78f3434cca05cbf8ee861f6bb6cee9e123a24cbf6ebc5021d3a9a55c7ff08c6bb274a7736f34fa7c04029c246f2c70751e51a4607484ec87e816a3a5c92c06a10f512709fc4365a7c80941109b1cba4dd7ee79d4c3f851a32763807425e5b7583d49e97f337f270e6387f99dd21d62c9db52406d3376a5e549782625813634a8fd237e7ac477355f4be7e05e2a9c3cde9ede554026ffe1ac3e8f545a4d49ad39c2aee4b52c45440983f25c276ed58ea5fac719c5332655113dd768d93311cb6dbff54357f40c23b4bb9c20c7bf0525150e71e17e486eaec90d2263c9758447bc02739a14cb7c3e60cf376b9326a861951d6d38ee291e59219757a9de264cfdbd4b4601b8413161b927daff25504e0361f6669af8cea75f35969c910c3c5e1890597931164 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = cf28960fc5ef7fd91e051ca12516ba961ce953d48492fb3598e97a6a1b3a3b4b533e656c564a47f184c7f9a355e240435584b31e6c851ce1631d21afa49b24714159676d38ef741bf6a7bc3319317e0b7a98ea206b7587f23d63d21606b22886a060e53bf544cefe7a8dac7bfa6b3a97950c410308ca02112fa3d4c7c8e90e33 +S = defe54ece1df4a9e2f9b2ec712b2047be979113674458c3e1409777a8c568bf43b4455fd4197ab42fc514e3595cec0d46f3302cf556889820e1c9cfd38c642ea09adefa815727b6c06b2a194e095f2696e35f3611c19129a86bf60b11799b6587bef89082a631cbea67fc4d77c7dc998afb8caae59e7a63a5792cbaddfad6e3bf8a0d0fee650b7a9cd502211dac3743642075a2a563ee20c05393992c776869a6eb4a206de21e72ec27be193537a32dfa65831bd13c66f6aeb2bcb6239ef31b2d7e8deb309be4f639c7ef9d3e6147e15a8a9dbace13315a3267bc4ad07ce02575a8b279b37646b871b33ddce57a8170c422474c2aa5bfd5323288753628562f0afc715576c027f7f125793dbbfce3fbaf79fc032bcd9214983fddf1d3a083819399c107e2913de535dfbfb267cd0e0602d6836a902c6589bd1f35dc07146c166d26592d8d52fca9a82340c0da7303602531f8144aa1f704e66380e07fe3c54e13b1361a427531a399616b4ce74ee9633347dd29112e180c5ed263c0153f3500a +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d0609608648016503040202050004307d7ca11cef0aa9200c55b78df8c91c41266ce955d1fb2622cd36ec797f3ddf70eff54c77a2904cfcb282cce545a31094 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = 835eab9bf266d49ac4c672c5765511461a3261dd04ab8bddc75ec577609e253ab019b2db30b7c132e0c57f868052ca0a03d945a74121abfcec6263a4c5a955b70f7dfd9344c3bddc08df78c15b1c5c81124eff2e88b6aeb29125020faf64b3eb89d4b14b9852719f245d85ff6f7b70b430d8b8fa42313d049ef0c8418799e7de +S = 7f96dcefcdd212f01c585dc3bdb38f3168eed84c77eba3d9c5e052cf84fb059974ea282c5d5a4773e13f4d23206c3ef731dbada06ccb827a75c4002a267554f2d2290e2cc23791f8db52aaffc7e2af981f9ea55d8eeb9abcaf379cc47dfa54d28b59686e737e2e4c3a4c9039ddfe637dff0f1ae77ad9fbab078ab9a81259785880890fbb32c70301877b6f53591862f45463bc7c25da257b8fc798f7d3d115d6a7b2228543b81e768516d8f29f645165c1378623c3e32dc6ca08c452665038db2ef5ee432857e60eec20c6ba75981833cb78c8cbd18bc3243d4959ed8ea4e5cc3102e1180530fde85e837188e029717a6c9444265d5bf297b44bcce7367e3579f09928e97257f48f935a869b72c53be1d3eab08dd10cbff54bb099d2e9a2d3ea9acaadd2c2e7c0ab89f58d265941eae9b1bd31d544c4baa8132859869284154b7f9b99fc98cecf104473437cd6960a768f044a655034403896cafa00fd89b9968097d2cfc90215fb1b6e068c0cd6224aa5f73013e1cddedfa80d3dbdc0bde0b7 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d06096086480165030402030500044092c353394e0845afea273cc4747df99a1d7a0474ab8902f073a0c432a27adbc8398de33e7d5b73c3cb4df25e6067981f237b11f009d9c1e547af65322d32905d +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = 62440e53c9081680b721630cf3071ed102fe0ccef99906c98f7ca93876654e62ec6e3cc28d8c1dac6b5caf33601fbc49a3024c289aa419f1efd24393e69545efee6e283a76e0f7a2012f72347d6806fdd0a1fd6fb582f307c604892dd9795d5c90cd39822c0b8aaaa22214d8f1eae534b262876bf13c7a533b9be1cef81b7cf0 +S = 646d7a66aea8b4a22f75881e6647ba0f207bd5cd15e019468138fd126e1c7f660a97aa55634646cd8e5e584b6bc29a4cd213cf222657ff6526b7e0ecfaf56c0a90ec4f17a297b0f8523bdf39cc612757867272409c65e8b2eb463cb134560d021f60a81ff4eb08aa97cbd6c07cc3b32422442724029be186995c2694ee4def6009a7a1a8b3c9eea48d634ab3b84c0c9566ede4eddcc5e59338ba5aa304502c637f9ecd0b707e841d0b7befddef4fe0875809fe386122882ab02e9d06af3b9953d8416cee296decddc3b2e36329434f567d57330c418624c5a70cf7611552fc2fb420af0ab0ea2c6ca4b19a0854e6db10662a7fdaea3c015e53524617cc29afb9cfa9065e1065d95d288f395402667caf80d7b4a3a91f5b681ff10518e5c01ddf0f20c359ebcce526091164d5718cb49b9a42bbb57361865384e8e2e162abd7629b1fd242892d5164c012dc07650c70cee79a2ccd13f424b574eb1f6cef662cde18302038bad6e100a4e7b949b9f1a87de5a2d6352ab830be1138d9b83c4f8992 +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = 7c38bdb32ddcea204a99b5f953ff3d6e0adbefcdd40804f661884a0f8fd328798c6fdc023bc1085cda236dcee137f6292d7af8fe5d1cb80e7d0f2e02e25e085c54c0f2ae736d15095330ddb96abd002fac46bc3ff449608ca6ac0d40920bbe001c51861f9a851911fee78e23b53c636acf66c2f95f370257258771316a84514b +S = 0d07f7c0cbe4a84df3fc088750c9c503ecdba6c37a72ffb15a2da05b5c99740c894427cbcd6cb2c8ee70f35175e70f226c466761356e07009ca88752ae2cff5d7b2e7f2da77a36b68de59db7f5182abe88cb95b52d766d721b5fec504f6aa7b9ceaa9dca1241a5819d4d48ede38c045d625442b27b8384dab964616885cbfca944a747f024032da7b3a3fce0b02254e08c8b9e48646407e69aa317df5706888fc13f091602e1affc23f17cd50ef4275e321a102c2b066975ee8a0dd3111cb0e88037ba98ba477ec67737024ae92edcd7d944bfe2863336a59026052bbf2280d542db1cc70f06a9509805db6651f795b0b4d74f94fbb06d2d4149321f9334f5fdba395cd852e46ff2ffecd063a96ce5d2d5b15cc075c243b30be7a260fcd6891ee3063fe3898037c79309fa043fe210974a1ed96c14bd0f0db1055f710367e55d702ef3a9bdb9215368407312dd415f420bf0a90f67c53c9474219f36adee08220b0798d14c455e57ee8ee47f2b8c7eaf8d5f8474a9d2f51d49a785ed4626407c +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffff003051300d060960864801650304020305000440a780cdcf06d5af7e658c9a0afab551db2fe1c5d86b54dfab86d5c10acffe37c4c8ef7b65dc13a26c2330ad19d34f1065d99ce4376e6b9886cf30792e9430de25efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = df8787cd9718e6bde708b9998cad4e91c7d58afc60b719efeb2ac80f4a152ea3732792ee74c809bbb44fdf397b753809b409f796f2e6dfa5b223f82de08935689c4a532a3def047296934d3e794f2da47af57f1ff501212753cc5604880369e3e058942afc771f09173ccc518f23738aa000ea4072f0279d568fa93d4c6b143d +S = 8407b86a4d3715092fcb38c7d55a528182cd6cd94186a86cc654bec9be3d472ba908d5288c1393619f1a4ea1322ae01d47f321a414d0cb1e00fa37c71364319b2e3f6935f00f0b5518806e8c21504b2784f14c739d186df08091139a911d7c8612b4ec15f17ea9f069898f4f820c9b8aeb5ea34aad293637c532c47b9a258d633614afb0cacc5ca475fd4d3e24fd25809df22f14c20289a7808806cacce46eba40d33f3392e72ce6316ce02866955ffe0558510b26c303c37c773f387d93739b77e053d896f078d0487cc4085712e2e5b42a6031e3d01808e94b8219304a6756233dbab0a2f133d088e67a2cd4392f4d688bf4f4ac4ee9a3a099f7389c5d8ac5f09f55cd831cee52306727581792455ff2fba50592a7b2b686fe4e7444866a2ff69cdd68895f84a1f9864b7f36c6ae89853adc517fe8b9a8fdfdc78ba03f91dc582dea4fd387858ff90dbcf9cf3878632b5b8448e19a797485ad4bb9d2c28b1e7ac717ffd4639617d4d4ebd44a556561fbef00e66b99c5ada41bfccab314aa06 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = a24b2fc765c9953c545043a7ee2edf6c1887925c6f5301d9dba67f3a67348071501451ea5bc407b76c6eb6eb5569e343ec033b0c607e8540cd58d5f30dd002edd2a55b99f121961e015609cb25a81db8268bffaac58e98384f99c02c7172ae2c4e86b39acfe729b83a91a61007f17513efa84600458c240789efa8af3b256c75 +S = 960d6a156414272675d2c09a340d9e053e96e8ba3737ebb8a11d4829ec9287e6997594549cfe6e7f60018074a90d1e89272672f4a464d969ddf7b634a34c36d15b16c542911ddc2805bde86b5716b8c8e9e2dd81133ae4d70469803dda409e8e8f6c0ae0785652528c02f49732c4d2dd6a33bdf93c17ce851e8d3d7ded4636d63f34f4fb2e43531bc61d2dce3f60cf2e521cd5cd7a5f19c35fb0bad328975676fd7958bdc7a957d0c1ea3a30f9141a39b67e101c9e9832cfa63b4b09568d5d13f50ad24af42d4fa9b6a0c3fd95be4a4d7efbe2a89fb7d675054fd5630c120e48af7b7caee23fe5ba2dfeeadb31aca63fcc729e4cb352315cd06f8e62e9b727b9a8b8ee179c69afd09b4d5cf5a8ddb281607374a526d462d40ed43e9197d871485fe84f8b07ae7ff7bb411d128b9a63cde123945201873f5f257ebee48b0bd68c3486352530819f0b01330217e4acf76e43f676e33bc803cd11cca82d7d0cc0e7c14b58c65300a877b443bef4e75d3ae079e13b4719d2993dcd3f90d234956b99 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 +Msg = d8b0d39a21a7b7d11541c35ba83329b6320896e86f165a13cab1c94adb9ee1a32eca2d8d463ce864e14966437e07b01a1d046f0046370bca4c3613dcd3aae03f900075f45062aa883ce68ae95b05f978584e9a5f865bef252105c280d7d4c46a86b9757648004365ad80f6f447154bf96c50dfae376c4f4dd0849edded04d74b +S = 2b5652f5be8741b03959eb713e46299a62ed69bc11c1e774c3683af9494e7bb8e51bc4e4d8de1e65fabcf1b4995ff065612fb5cd1812ac7a2c1a0aca8d76c66a3dbea40f426d55a6d60572ae28d3444f059ac714b79e9cb1b9bf443315b85e872a4e20fc69ea1b89c01398b1dd528de6410b48c141b1f7e70ac888393b81b20a8fd6add6ce8a423f4f8e57c6860cdac522349b9215e0c1b25c78a7d94852cdadd5e3f0a4baf2975b60a17cb0e3b9c79060b4ea0eaa153e1500cc05c283ac300e3da7b91aecbb10a50e86a1ed74120a0770d0608893fe6eadee193a20d920291c71df799e620aae96b263f4567962fcfaab4caaa4f06d9d0052a5e2ed8c2f62328a973e2f39568507f6445c7e883e81858df862804c419e3ee5c6bab1832521e841da32bac64a4d89400a2f7d447796f441d3784df53187305fab96ea4faef0cb1229cabdb8cf07c9177b8ebd977c4ed6f260a9b9e97d5d4918cb0370e71ca008db73913f2d519b99b376575a808761dd144d74fd8a7b68f38d5021f8b0533e41 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +n = cf92efc93d89c560e4cff3e81fb72672bf010ae82335c342ed80c0eace8fd0333470dfe2d327f9ebe0ede4f39b0260144d1ec783dffda1f883c0a41cd21e9244d1ab2e4869d765c7e1506e5c1be03db067be54e887daaa13e0d5122e872373891a0480c56d8ced157d316a8ec314bb9f15fa49c0ffc0d78f913ec2dcf354bcfdae2bc031febc69c4fe9c51c05dcec9c1d3004dc8a9c62234d91e4dbd5f9455d94814bd6feef8697efdd9c93af4a9b1ca2e9023109905242eb82977bb4866a81220f8232558af67296b34a19b818e5c07ba53b6e4b270ccf67cc7149c79bf875fff248f4f6f86fa4e9a10dfc162b4c4accbd5f76e4afc89c5339a35f960c7e5d156058bde8c9a49aceb5fea67a09325348a8d573e304e9d133f77913c785e5725d615432d6a258dd4038011a7e19369de19878e945e9d4191148550bdbe5bc22aab57703dc880c3bc08c2df1327ebbf5bb9c2e75082e998dc48685511958c4e7b895dd6be533ffe84d5aee6511480e6547b89144136b8aa41c6942c00f5ed42b7 + +p = ea7777733c9695e5bfc71a4de384aa8d9556b620f13d50a4b3523d95efab4c5c037fe788c98ae85b11b3ae884eed6f3b8f5bcf5ab1b7b20ad3f44f760b2287cc57937487d73c44f4395d48ef746548eeb9101a42a6d27299be78fcc6160da8c550fa46f9cd7252b91f0d110bbdb3ddaffbbcbc60395538565a266b0f78325a4fd5fe846615f5bab1ab0b306392a1d5853da8e03cd00aab4b9045c5d898594373cfe55654169f1c7eb22dc87c7497db4a729b27ab95cccbc4f44bb8a51c0bbba7 + +q = e2a332843df5531bcd8a06e30e3cd414e9a201b2e27b610f944f6d915a5396b5508eda547a3a9425426d988428f87f71b58f40dcb02b012095ad2ccd43c4c4aaf510fafa7388fbff8a190dbdb98fda002db90ba0f0c819045df960e5d7747654ba73baff92a630b08bd78c1629ca8cc839678b87081a54c3d27b34617d2a53bc87fd43ea3e5eda402fee3d18e06f3ed1c2e0e81861e95766de7aceca9fb003e945f8bd43de9f1edc154241f926e5c761109fa4e9cb359ac778f0c6f748fae271 + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = b04cbe36549d4a58dd6ecf23afa174b2c45b9f664d14b8939cea3178403bc3757272fa78b021f3b9a75165a75616de2171664fea032acb5758968c4b1ab63765ba4a607811d4513c48ef0743f5e27e2e86752f20e304d6734fd178aa8f9ea5a74f7cfb1fc1deeb4a87f1c0dfd330dc3fcd3345f035c7614e4944fe7de91b95a2 +S = a4d1579f4732ce97ffaf6852183ec36900945fd9283be8bc50a1dcf81e8c4f277d5aacec934a5fb6951f97efb5636986e06ba302e964d118cedb83fb6a308772dff6d77080ad390ea8e8f401f5e2ab4feffa25559e699e49ce08004b15c49a7915f28099aeebfcbb3d22426a51caa71097fc5fbccf0cef1610c17cfe76587cea2f6a04cb7893394a736fe2d9b4b72093c5109b086b6f2301b7dc7bbab0cde72828407175946cc275d17da0fc63da6159492d70a341613971926be6623b262df63f1b9c9e9917622f365ecae401123baf3e33c2dc04555804e2b6b3dc14ca263121a510ee44c9a4602c005956f1d41e0b6c68ad78200fef0ccaf8ed668239e196c55e11fa57ce96bf8457baa139db776a43b98951b500850170bb57ec17cf796bfa73799d48b24da7fc85f828a6c1287459735b34148ccf84de1379bd2c13b8cff140ce6f8140b8cb8326374def23122b1fe8f015d6b62be5d99a04e62c88e3f611414ccca66193fa31a51cbe9c88d85c9b3bf6802ae24f4f4263a7b92251a82c +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = feb972fee487cdd8d18f8a681042624f51dfa8639f96dcf693ee7e5cc76420a78e54bfb5e21d536d9e81a545ee4a610703336cd60b05776c6001d5a5ff7e89413dd3a4e5b577ce648567223dbac83f6508ce9b46bfdc1b07faede10e193266c372fcc89744dd6546ec0aa8585c0423eec878debba263ef51c9794b9efec8dcb6 +S = 879feb8b92579291f651e8b476d5414e46ebfba0c85b4907a7479d5327c6f582356ac2fd6dd59414b9df5a465a24cefdc39f19c6e814545745710c9098d15385c7823996cb6509c20e359dba1fa6bfd5e22b41aae1a8de26aff1c26427033f6b3d7f4f8c28a3e398c52c8e5221785f4926b9230eefa264b1684d598310a6e09919409e34a693f3c508aae0d861867fa680f0712a1b7019c850b00216ad194e80357a06a995c9da2bbd9f2189f939b228e5487ac83318def7dbe3752c656653517e475764b375f54a26f848e697aece0acba9cc3b722d37fbcfecb40b5a2b7adde54f02f9fa0cf3b2769ed2d4f81879822e01a289cb9b632e15a9ea45e09e962ee27964992f3a406ac9c72d3d0f97563e8296df97d7ca6383e6643d0b499896768846023f901ee0397b229ccdb706701ad048a7d7f17c52b46fd9288c4a6f5d47c0fd6fb55ff74299ef8b3e1b4c2d72af4c24876b6f68bf7ec74359ffff8461f9a9893c9157e0f022e0453dbb87515d71d64178044048c6e161e6730e23e79973 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414da0d47de632ee4adb50d8031bed0027c846d752b +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 08511714a11c3770946e03091a2826e5efaec9a10f9870c0bdab1e42ca07c07814a1c8184df4198dfef42390cb444ffcf8a89dde2cbd8bcc75e83a798d8ccc865c80109abdc061b48562cbc0c2cc706940252a2f520972b9ce81816c5a32b43ce6d435c27ae6d88f32a043c1872a52d4cf0bbaba07e4ec2dd15e3c44b9614244 +S = 136b4e04197fdc938eff67044168e7dc31ff57b7885d9b41df0d3efd5251a5f91e641b73cfc7732ed326519773c6cc77648f2db4ccd056d52f7314e3f3009eed7f2120155a3566a307cf268adb6c004d435957370dfe06570d626c75db422915e34aa53707ab99998c6d8c0978c0dff28585f628a5077873465b6372bc24a9374fc6edbfbb8cf8833e51cd0cd9df4d3edf0a59a531811599666a2617cea298476300de1fe3e12e45a861f28e66982ef0dd41674276779a92ff9307eeae1159e2526641cd18eab80b43a83deacb075e60864804d9da39eb1cedab591906d4b428af9ae9451c06e6a3b90fb3999808a93c883ac59f80b4d1e3a32a824d1affbfe6332c7527745bf8272ca22bdd508822a655e0e4346343233e1068bdbb866eb512bc47abdd8ac777a2b93e12809e8576b898f97a341621a1fed89db77449b590344e8147d0e81beaad44f74abfef11181c6ec161e96045ee3d0f7dc96c53c6baf7dbc385dbce0d6a054970987b392db1f237778dfb667ae9a4f7133c3d49e78e30 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 5f474c3407a08ec87ce50ba52183d2b605d61768ace41d03134c593aee79d401341bd19eddd8b003eb3e125ba7fd3ee32d53c3fb2ac75f7de51a204d7c7bc93170fa77e3643f8465227cac95dfa06e01c0ceb5fc9d0db8f204411ff8815a67a71ccb872b243dd4972b85227b52d42cb9c72e36948b1ef00a79a79e64847d760b +S = 65e8cec81b96a92cabcd2acf178afd01ea7ac429634804dab05faca839e1dead2387a4a4c702863bd0522c3a6847960f604bceaa5b56cc78f1ccc535e9c387c70f929bdfb564da2c4f8653b74065affa5c754ad6ffb1be0e02918b1e066f14e5abf499b75d176106ac67b6d2ea954eee902afc8816e5c9b143a6820c4ee4c8ab76fc20442bde40a0dcca8f64de6955df646e3790074ae0d11501242d6499022eb9597eb39ae68f52152f71e5b1500ccdf46dc8909dbae8ac5869d21ef30029b0bb3881df988161b7dd3f80d9f0a9631ec6e95a33e02f2e3e736c086ba17d7f803ce670ea9186be3da26e552d656aa915b5f0aa0fd80e32f318670ee05d0a52a8ddf56bdfdcf1f413b66f4d3173b8f6dfbf8e2434c467f6c340b93e597c1cb2f114e103d7c03973c6d10fb357b5ec91e47f03cb6a794f8b4c3eaa6b2be6ea9a3fd34417373aadddcd9dccdb95fc71a639ea99e0641d5aeb63d59477b8b8629a4012e35a3e167ef445b085403018f7a2c731b88dbb843c3cfca5c367d29dae8346 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a050004140221cce979dddc3f07b69ad9575641e343384e9defefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 23adfc8012add4adaac91852a169e42d92552d70b56ca413ed98dd6e0901b1074381e1a90d59fbb60e2282bd6706494f3a2f200f6d80b209ab83ae45aca3259bb79c34c8652fe2c2a71a4b490a47ffbf3a44a539c5f3e4d622838350f29eced085e43c07a099507a7e9abd1d1496cd249a7a0316462d00235b7ea3b7625b744f +S = c789f344e0f4e0c291bee6336b3d7d2314b0fa847970df318ea8ebba2de399914ccdd085ca5c48913ebe9851a29e40545db646d958b9370e0c59b249119b67efb26cd864e226b289c62edda506560ae976f764d575515483bd13093b28ee85d4ea62fde932d0a77dbd81c971e7f4386fb79c7f4fde362df166255e05bac5289d8f74562be2daf26513472f472b68828b402c4570a5cb8fb027518a29c3c78a35a9fae810aa6aa2bf0333850d6f71eef951c4c7f315f00be29682121e471cb8fd05b556e995d96e51d4d56f0369abacf234d19e43e737467c14e82e05732d521276b81d8a75eae5a096692ded6f5b56fdd22b719a3541ff98dca661778c25f6188c756543bca8b8ef5a29bd801826fa613b349cc24e69ff4017805e181fcfbd8e947a3d38400fea81a18cb8c151a304e6e39c0e86b57ee0d0b1acd7c052ed94818cad2a6e75de2bc7c46fa9ffd9d37b9ce05ca53cdce91ae58bddafd5fc626ae71073b1efa0015cc9df589ae73cda5563f60774fd559e565250af8b9f2834d2d2 +SaltVal = 00 +Result = P + +SHAAlg = SHA1 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 94f581408cfaecd499c20c50ce61b30fb294b95bf1a84c79529788e7e97547e18e0a3b298ec13a08a0c1d8901a593b2564a12b3cad5e6961de27427fccc6635cb2e1ef63dedacfa6aaf34a23aeb6d54634942cb0eccca137e28eb42eac60e5e6e8c2c674e60d54b5a1a18790f43f287b0ab4e34117b89d024515087bf20c7487 +S = 2e43df8eca870c60a75965eccf79952b6251f216e8ab745226963ba9200b8ba9a99f9093a5b3df5f64e496b73b8ce077b76f4badae288c3e979796f88049ff2ff7cc0401b0f31c48487d01b4ce4854c4f5afb9cdf7b10ca196b665efefe4be742b2db236a379660170c3f684ab76b69de13a3053c403e8e14394379a0e1a6b6ea6ec501e95c17d6c7c728e08315777d29cbafa972d483d7e7ff5d9b97a8c7606300a03e57b92cf727cbcb6f14ae3c22ff2d417481ffc180a378e4fb1a72efeca8231b5fcba6b1561659d8ad96dde28a2f4360ddfce2c598428012abb2ea530b3dcfebab4e3b550cea5894deff740ace9ef4bfd42337cb2d186d2cd05a27e35d37e04093ffc0751f80ca4ac2c3b197c9cc60756029ee0febdbff2c9cd69cd0423a37fe4560a1f8805ce591455dbe56bef0cf8616901f682bfcc1b58049fc8e3ba40f28611822413b1a04d5ead7bf3cf0ecd94ef6bfd4716f1b1c4d82f70ba8e71de91f84b804512dc037bc17a3de87a74e8c37ee921e2c1a03e7cc9768e3059dc +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 2456ef08c07fc1ec469aa9c73b677af225a9f5f6f8d0e150d1d65e71e6677609bd44f5859de97ad6436ecf75d5ab76a41c9f84f6ed13b311e87ab2b3661cbff3ac7378ca65d5eed14f54fc4c34e3d7681cbae5c1c1fbd3274395e2a21d6881b358ab21ddfe8b4564d215d8553e56c4c68dc1c05f5ad1691a48ef9546f495e4d2 +S = 0631ccf756acdd39dcf45947556f56418b598b25512f9851ecc826e8e15ef8312b12896c5046736df8c36c1e80d43abf9dadfdecdaf48b6a79a09200008695e2c7469c837edce5bcc6c86506908be7942dc6e498f9806a921180cd0b997211afa495d1de016a1b98ba5aad0ef0b0b1f1ac7c8dd5feaa44ae69f8edd6fbe7a4b196ff96077090d2bcc05a675bccec3ab7d3b6b63adbd97626494e57d03ccec82a4ebeb2641b07228de82ce892e24df312f2df624235b00495b444232c205a5001c0db68c06ef7112c8427ae0d563b53b16f9fb1bef64e59cac4694884204f3cf3022ee2471c158e70ffd552ccd582f92eaacbcda5a43d4e4d4b2e72b2193e34b03b9ffbd47da3c0482593440910dfc334d74fc1d0dc11e74210fd31fcdccb7ca2d01931ea6c75faf1f7a32c8115b0661ee1e3457090b97cd35ae36d34b06da17c047e785a5da9d23c048dea4c766849792ae07ec95ffea56686fffd71fba54d44fe8e3d2dbe742a97acdbd7d54fe3a78d08bee547664a0f1dd1544b509b5d12fb +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 29fd9ed0a8ca9609d8e67edcffcbf733f15581633c2449b1a2414115cc04763e3c359fd58471f106b5cf3b3d1bc42e2d2744fc17ad2a264950da8ee53a25d4e3106ddf592409bafaedeaa2ddb57f5d8192d7cd0d9706c4dc4bc91a385a6dfd668bec89e4f25a98ee677fdc4637c62b35195619cd637ecc727d560c9996a39ace +S = 71265c24f74301a5c2cb797274c15af942ff4b98aad737596c4195fb698a69396cfb5e967359faa0f091931fd0ead53859ae16c1fb18b071b20dc0e8936b58a6dc8eadc773ab583525b1b9c01112c75acec69221d5a214eb2295a26ecd476ec37d8f2ff62f7dbb7452f306d3c4851b67a57fe3e6d7ff98489e47ec0768e3d701f13719f0d8f11281ca4fd6bc1dabed86c9d51fe187ba5a1d3187465e2181e4fc76cbc0ac42f287e9e4013dab1926e19d02bc5d7b84605111f5d2fd63229cc27d8a0e3378646d90a44726aa6f0a528e86a9b9ae709aec1a924400b67da5fc4d2cf307b810e66bca0120b659659882699994764d3eb992ea3521f40e8fde04af2f84e73e33ae5172f969b05e11f55872db50c1d0287bd331850025e3a62c25c26deec2605a4012c0c7ae8454e3c27ba299858930f3b384188c41b5302c83f9032e45bc9995f3ec5b3e5de246eb0bb791afa31523277c26a590fa67bbec78b7934d876f8a8ade9e12190411829625a845f0cfa48bfbcc0af544a8952d52eaedeafd +SaltVal = 00 +Result = P + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 092a5bc0943f3cf6a6295b47ebfa4c872f57f1a10c8a4040c6d246cf73fd6ca45f39fa78ae28d91b43329d65e11fc37090e5360443be1853b77ec0e79e24ffd8fdafa842d3334ff6fb2b50705311140a1e2c8f6fa7aa0d5128ee2f5fe92b3071ac326d06498825f196bc7d4f89f7c7bca1d503c78173a6a3dfca9b1f9c3b88d7 +S = 31e1288d0923e5de3feb553eff8781fcc91fd118f13e2c931e2ec8d3a102344e9f2069bcd3e9b863911013ce2e6e58948123435fdbaefa122e8393cd84abc653559b2958d643ed93431639123aac801ec52578b8e8250d21d32a7edcba7d639f890c3675f664db36fa859ee340d9c90d560b6e1b07a82811a0ac875e0061ac86ac352d33c1760c3ecaa86977efa971f415e3c4d878e5c4d6cedf865b048d78359c1b063713bc20f89a77962998f253920855f80cdfa21f54cbdafac23e259f6de785f8b298aa9e0363a4f098ac1136b036f40c8ccb87de2751ebe4bd4791be851537352b5e813fd1f82d3042853c44fdf645d47dccf149288ebd41b4a583a8887fb01ed1dc7cea237a53649f62a94e3e1724cd409eda8194d39c047b58c43b3210050ebfa39551a4d1128ae519ba23b20456f0d5ed259342f71e1a40d3b84a27afa1d26a1e4d3e365975e9e92c52802dbde13a239748b1644b528cd824c503e6dd4cb1d146cbf1d5a96e20c388bac4bea7b484c337c7b733ab6715bd92dcbc12 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c87593553a6906097c51fe2ef6f4de291844e6c083f4abcf7f2d581fb +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 729c6a3b890e20387db4ebdeaef7e1036a7e59af6da5952ba72ba55a402a874cda4d9311163d17cb595c3e07d0b6364eb13591f6c414ec3e2395cf9b3ef7d54c21a20d34faa69fe9d563b309ab898ecd9b44fee077b0f97182938187784bca94cf059f4e3d3002ba7a321389475933a8af1468138d6303ea4e8c81c6f810b04d +S = 31a04b5bb1588d4410472beaf2d6ff86d514c30456ef16df2e0b92dd9f26b7782aa0d363d1e3035546d7c91c6cfd05a21190f597103f3900ca12b51922eabbba0f9df47010efcd5394263987c7b79bf8df94ae0318aba4a14caaf791f4a0807bead368a129e201d466e9e70868471e2cad83324e1f70650a2e1d11d9aa539c98e29f1991226357e3585eaac9c856027aa3ac418fa72f00ab71738dd6baa3e8e8af0f30fb58c02f50c50bbd64b6dc1d693fd5d548ce2e0e0dad0ac2936cd3bd1c16ea2ffcd1d2fdc683aa5a0461158aa5e621ceebe36a705d4a2813e5a1b8adeb44718d1af3124849bbb3859db3f8114374c6680cc80222b214ee737744eaf1b7bd400345782fb4df6fdd9e4116714028886e250847e7455ec466465bddd55bc4f67e5ca6048e95653592c9d0bd689dc1ec88aa642f253568d3cc00d3bd719b90e8227c3a1a924f58a8ba5fa68e0b932bf3be5441e601a8466111c8ea6eca21039d8605244aa07952e6918291a2a58ed90f111ea075954cedb1967d4d80bd208f +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 1399504353d5ebc7064355b017edfefe97729cdd100720cb16bce8fd200136ff9668e19c2bac4afd6df392159a500a3cb68ceb19da2648c6cf98402fdcdc78bbdb2fc92f921535cf419d20c678e6bcc72be2c6f5085a700008329e9145ef54e90b766fc531169484aac9678b57b7fde91ffc933742ab80c2ea1368ed0441b3d0 +S = 19e0165b14491e2f84f6eb55f7d0e3bfa5ce45d20067a7809def939408a90b0cb60b3733081960a0917981a89c8907ba50622411958982b37554b40235c28bd478a06d0cfc3aa628c6685fb739a4f72cbd3fa6b6fca3b2e927a7a79fe2d6513ad8e04317ded8873e446eacc8e600380d450cfaddf32523ed7bd339f3f61638bdbbf80ea2cbaffc51b2e14aef079a491eaf55c7da79189327070e0c66daa906646095b2c0062850d9269a456bb13e632e5954208fa9d9a576bf14c958741f7e30372709c20a209d0fdfb0e18608a65f049565b25a77afb4a3d79a49e9fced249f6045d95c83f0ea4b8595288eb022620a1a6e6768239fc95867c575338514bb8d16f4595b6463a0bc576f1edb72c2cc4344b1000f43447207f2ca9049c86c6ec92f1f74b6811b65534808ef659af5e3f283a39b9921ab906a51a9043bc34dd023c54f2a682f0867bf543ac02b55a13920f8c5295b0aae650af71083f7562c84bad2bb0685b0d6101978ab5d789b88c3785d82a01f154795084b6e363235b10fec +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = c783252ef5e96363cb48e544342f0b82a98334cfa425d5a158cfc8339f3fe6cd3498d746220529c77c9fa0d14f91cd82d579e214eb12c5a6c511633fe14c471039216bf9bd164e4f00bd46dd32db18284ec8c6f89419a8133a7dbe4c5fe545bc40e88850ae65f984c06a806dc55413fd7c3887838882a6711edc81620152085b +S = 516e3483482b42a740c475678c4954ddeddca4f5d3cbb9474aa7fe7ade371f4ec09d497ad8f4bcc33f60dfefdbe3bb66268f5bf25eff3a6f4d58b2295c82dd977933e237fbb140f9c095bb31b091e0d8ce862a588a827a3ed7a0a6b407c534c37fe6e89b047042de8119db826edb202cbbd6188820371d7aaea860f08e23cf927fafcea8f398c3e189cdacbe458f3804131b6cb8f32bdea4c8e88dbab79b5493928a794aa125a102c2af675e8a1654489651214793bd7b8e86bb237f5fd19ba5c902986687e18390604a5fbe531cef3d1cda48c7dfefe053bb3142ba153256b1aacabee463dc63e7d74179e83101aed8e9c140f51ea45c94c9114f22d9ba63aef338b87c975f3453fccb06ded002477a073f40a4e3a42df7bb588a5aa830fbefa8c7f2bf363bfe43e236d25f8c0d0adab69e3b3b1ccc756a5e8edf180cc5ef3d18eaea6ae4d09e407a1783ee6a4a5505a90df31d310dd150e6aedb20bb97b2551e6e96223aac0b3484a6179498d1b4c2412090ad5a4d3dbc0fec1d11d8d0a813 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041caca1cfaac92548bc1743c2fbf38354db0247dc19de0004601b8c68cbefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 5c0231e10a12e268e08dbd3b86845a1907e6bf853552e12e482a68afc7e9b378acb61c0cc3397d6e53adf3d50036e1a7f07538a52d5af6634a3aedfc4a22c603bd6a45bd2c8dcf8db73829affda082293c19b4ffb9e5c7a76349b6bcb3e676f7d647355a0eb7e0ae5655e730456a448834f9bafaa3985ae0d97f4c58cbdfcc3a +S = 1d7b0e1ea89523699cb8ca51a9086043c1d3c4e2d0d0dc5e1a6f3688d318f7db0d2a5272f71915ee2439db175714b2c38e8c0b27264c8ee01bd1b292b66197e023f6b49dea082b469cd30289aa5b2079e6342789b1cbace05ce265e5fb1716947989e5ccbdf4779a37bd4b748ffc91c2944259ae2de9582334b6df1c839160e4e704cc8a771d371507a68c61f3a06c46a41e3aef02162e9f20c85ef51b3f15562d2b9a512ef0e81ad60f9934be2a2cf7e5f54813244d360148334c40fc8a2e65335bacac5b9a607d70d4296f56803de8c0840653ae2837a7e826dd4569896555395bc0d4262d9fc025f400859421bfa8cd5841a3375e22efc9c1538e78795e28b6eea359da14ca3c44ee30d16e7359b7d83d47b6744099c345ec60bf2fde687d0f81db3718d3a79e4ae86a0c3bb47ef0618342f103d6e6f7ba89d4a4a520b1a61b2d8d3c5f178a46166631b58921b7e0aeed15c175e85f76575b746359ea831f87c261695896125032d7ad4ad26014abfd7742d5396dc1516f46dd273cee88bc +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 70125f4abfb1179f8c2b4f4cc30386a6fbce13786050b848f0e27adbeb16b0fb849e5b77dd6ab56c32110dc35572d1fb5a9bed2893ea533cbf71db867e9f4e78081dbdad1ff7182b42fcfce52467cb845cbf02665efbc7e7aaeac2e043d22e6e635830f56d9f676423b4c4ba192a9cc96901fb39a9cd3cd11a13d6f222f77964 +S = a06c4d12aba140f9db9ae4dad7a507c241cfc073fe16cccb8e99c0793a0a605097a0538bb4849089473050ae1873fd369c2295dc98b5561f975a66d32caa6ebbf887428b163a9a0515a0f614f636e8e8a87993c11fb334195de25c3cc9103a9e01f5bf2b6b6bba1786b0ef02e17c9256aa8fc714fe5bd7c905e240c2dd120662ff4ed31c229df92e0c819ca384735235e5f817c9a844b733c4c125498ad5493d1651ef8833886d98b409b41709fd0d0c20b0c91c666cdd4443dc0aec4e3d9a844d28b40b36be972a99ceebe68b955fa699229bb393bb65f32f139cbc42b20be0481aca045f965ed2caca3d4f7802bac775fd0032967570d826361620b32a2f230600aabddaf976b1998c9a5ec545fec80522f16876c4fc77e0867867bfab4b167fbee839b83b7f5d647a902e3118a167b0a7c7fbbc31f23c8b9606429c66c46a3cd7498e14a94fb315360a1668025ee35bb49fa614250fefd9236b8d3be9bdb271f865b460910149449e7d22df7dee27db29aa123bc31915cded3def0249d2a3 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 29d9cfca7319f6e6ae00ba6de43e9f20e140ec7b45f76095d7dc21491c31f5932989b43cb58afeba72f229529ed87d7fd435a49729a25cac74636fb0eda5e5ddfa047854455048051291d0ced04819e7edf82d7defe5cf9dc11c69544ab346154452015a4cf33e8e35e5972ba217da20d4937175c0492131650ef87c5ce48001 +S = ac2b892951ec306c6fc6c0550d633819a2d4f073001665cbaa7eceb96972e7b0358fd49f1fddfefbe16cfdb78fa15e4174b5d3e398268da9eb23e6b7cd8bcb679079106f583390462850e44b23aaf0a59dc9780d0f3b15bb93368da8fdefb979b2220241af3e60e5c1e2bcf23e2e8657438cabc2ba22e4081889d94f2abcafca0dee1e81ef1c29d3164d86fb50d28ebcf89e362f9eda07cd85206b9351c6092d37f0cbd1765aa81c4e0e18bb01d204a3073e1b60fe67c6233862f1739f223cf79160154c138f01d4428e76980e0dd9c21e1a701d05a6e67acf7f257275b383e506bcdcd54a80fafe266e87eb36b3c076589d1696916ccc88e4af50d8f3766e6dde0e530cf747d814a591e5da6bc977eb25b43df723e28e3ff226253d07043abf1b8f5a013b2651de9dfa34b7ffd94baf8fb1459b9fe305bd58064138a0ede6af36298f3444086f1a7d0c723ecfcd6404fd267bb20ad48f6655a9a0886868a83a214957b40af02064692661c1b191aa828339495b3de0c789856f80e5b2d569fd +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d06096086480165030402010500042038dfa46ebe6244537c96b22aaa7542f8cf5a10069d87d81b37f93a2ff7323cb2 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = adb245d4c5c72ee661b657c6efc444f8b1bce6b8c0e1bf905028472935a48d62a742219f42b6326350b5f4224b6544509e128fbeac22f026134b9805320373a8e938098a9f42a2dd8a16ad672abc628f1703a7b8fd7330cde583eb1db60c9b6afbfec23ce652c57b953f4b3d95b1e6dda5f7f54dbcbbc9ad4d38061cc9a74cce +S = 7f25b51b4d94f2220ff257205e640272376993e698cce9fc5a9b429ecf8a3d6d4150341df129b74030afd5d092858153cdd01a38a586c05871632525ad7b9d433dd9f8b1436d3d62efe46501665e075e918c39f775ad6e1e3e4883a529024193891d9463b0d1424a42890d5c05058d8925fb4c446510f12afd6457b50cb611eb0ca641b8f2f2c0afa4f03e98d154447497a4640405676e003f8a2cae21458d56c59785e34f54000b6105e85e25e4c380db43c71b990d3653ac344e2bc72bff987d6c5249205f2770998725e88125309a7c49dc28f9e6fc8a1340f9dab47fc6507d3d99fa876c330ee8183827db1cfa6c05179bd49d5e4bd6b467d559731417c9b19d0d265bd7cce858178e15cda9eda4b1ace1f6a492251c4e591945d2749d7ce65e8c03d57277e6bcb0f097c13504f006405e879616d95b5b75005118830beaab13538943044da67867877da87f29183fc05ca754df6c5bff810b6e5dc64b9e50ad29da9fc74a2fd20ccac5a300928ced1c3eb719e44e3b21071746fc559b1f +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = bbaa076712216e08ed954528d8309ee685afcd901d6865c4d48b63d5c0a8a870eb71ad80a7c2724e21deb7ed39fc6fd5910272cee49072109a4030a8992cef1d5db129544b7382b142a1fa7f747b66927411212a8f4dff1b6033822b9f6851bc3af1e5aba73e8677786776a630b56c645564436ec6a7f42e4fedc2277b63b494 +S = 477b191f2d027ad6621e38d56aad700749444fd895238f9dae3633176505d798d670ab5e85df8fc42906949ba36090a14577e9b179e6704be20f1d3ec2ff00b9f038a71956ee353f358f608d1728164fdd3b90213152049f2b3588237a8c1530f5333f0b89f07443fadaf09e80122ecf2af6c2dbadd5e189f35f9c2cd680118a2793190d0d63f83e13edbabfbd01031b6875d9c7fcd38bff3587021ef04f1ea0777ac67e76aa1b0773109b869075ae2c4c1f0121782ad767a7d0e78f3170c3e3243309ad36378a698f39fc6591463dbe9c84292bc4a44b4874320f9c5cc3cdca879f2a015362dcacc5c74cccc2bfe05f0773f3a836e1ec511c72d9fc7317deb4b2af5976bdfd1fabbe15b3f99b498647d92f818f658f8398c031cf2f364ffc106e75ece8f1cb87af2592fc4661f80c45e76fec99545c54dda470a019ba9a26068f05517defdba0d423029580ffce95b3ae1e5c8a882806f40ffc3b78640d6b311c2de8b0d51bf82a1ccf304975bc413d5f7e2222d91e5d650ba601594283aa49 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 7e5a48ece8abf0637665d2cc4df0476da66a82006aefc2100018cca662c1992577104c739db3675984683d2d43c3abaea52c032fc42749f8dad8a2e953c6096027df445d66bc16e41527b7a338da81d5308aec664724bc588a577965d75220e636cf18f36c5067cccea8267754be32abee8e25ed1b7085f9b79d3b6314ef467e +S = 8b08c4fadf5a33065be2fe7b2487190aaa863d150c819bedd2de321ec34b9f397e5ceba241c998d1138080867a2931660f6d720099698a473b10fab8c6c1ac99bba21ec964db0e9de0424d12565bf20978a6041b8c72019f910c286781c7979a98047abe06850d282644f6b7f375c6bd6af8509727b0d64d851902baade451f6af0c21967e4d545a535ada7f59f23d90992ab1268dab4797907527b9929cef18ea468e4803ddd69f44627577e9cec0ed8219a659db94d46f560cc1c32fc36537f9fbd568e26d22d070c82805cd17cdf80ef8ff1129f5254984ea7e13f3b1d40f7d9c304f49b504b634807f77dfe73cab854d3b98878dac4d33d13289d1fbe9e1b2f3c75f6ef5e4deb2bbd8e56ee6353f2a5d9c28d4640b01777b3bf743e4acd53e2e413dee01bba20d1811c62c3ffb27fa6a6a522dca12cba25c0b5c2f02d3f6b4593789741aa8d2e111b81e34fbed7ea544405dc0edf263283fd28249665001488c67f9ca067569f82c52587ec438b54516d1d84acff50719049e64edd562ad +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420c46cd19378dbc903c60d48ba8ef26b1ff32f64f6612a2fc01dd770c878eceb8befefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 2bc088c8b2a4af1e90a9023b3216fdbf89aab7710e8b0bd6037ff503fb5e3eaf9cc85c8ca41394d82a87612e27ce19a334a6ce0e95d972a7776f3fd47622563f6212a72c43ba100a9a23c947ea57ff697719bf5b4ed3160485d0771ec4ab5c460508304f97816ddc69e4022e859bf73adb6b53ff40623e16b60a638beee398eb +S = c42b0d458924349b4510e4805a6f199b29defe24c7220c54d1ddc44117bc05c5b25858939708333c8fcae96efc75e1df6c6b429b2f0e3f9ac21a59e15c1a976fa91294c11e255139725d5b9ceffce0bffc93166057d191be06435d68a64e0d790731f00fdd868dd2881546f467b52d3fd240cea6b6e3883db18facbb67ff858918de576f275d6a0fef13fa135665928a043390607b964a8d395117f886c661d9a9f8d3a2d863292bb2d82c987487180dc2fe859fc20fc5ba849399fbc2a5bbc414fb244003b1887d945580d2bae524d24de03fc14e5595e7471f14cb212cff64d561de03d5a85304a51883a10c259ab729e750f8a424f769eb8ce2f12c2ce2b3835b0ac9b219a22b5725149d65681c525eaa55ddea7f674ebc833f74464302597cf603d95fba141b8ddbaf3a540df6ef9bda7146f4d104a9287a4a55bcc5f7cb4dafde9c437d2172cebab2278ce97441cd1e091e3d18429fae503e1cc23319ca6abcdef6f8562a11fe7fa1b283f4c81a3025668bfe995dac330bd0a3ac869985 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d06096086480165030402020500043034a99a927444c010c6a1e59848fda5efa3d6f47f1dc62aa4a8c085308632d72f89e37e9f74f5947755a2dec1ddcdcdf2efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 52e616af9542cd632f93bc2f3d510bef3dd341572014ffdaa0b6eecbd447f6c302c4b142b45b1f990e759b075ef40d22f5b96278366a3977ec72df8ae1497e85acf59143cad19b8df08d193ea076b5a5fbf7bc2bd660d2360fe7e54d21ed5f7cf782a0fafe2aab097ee11f1e2a5e6a42f69539b8287f32e0b21de65bbfbb0170 +S = cb647fd846c24b61bf5bd7893de079147a8fb4d447bdf26aa871d7ef83de578a383d932b152bc28ba4baa5ccb15e499e338b2a5e3606533c62915a26ebd8351212c226265bf097af9e30f113566921dda511c72fe0fb114eba47bfcdd052032abed1f69e144ee7c347f62f730b96aa42b75e23773d2a65f0d5f63e01c395ffe6c9a87c2364c05983e4c676af4b57a2190a2bb7f5f1b96574663a13540f51da353be8876879a1ac90b10a5acd42a69b6ab45ca194fed641acdb89fcc2d93325028f01a3149795a2d95887e29e161902da1708410d37cab1987d4f3265b9ade7c1bff7b385ec9ea1221fe00a285a77b5ad37f1e8519326d7baab48fcd70aa52dc2e6f8e7270e2c9c99f21b30d217a62969bfb584ddcac60959f71d0ae16cce6a41126c9c597970a79da11e7302ec710df8890afd0b133306b8f8a2e1c67a6f0103cef6b13fe4c1b19415759291267b3fb0dfd552d83ac856f85859589c69d911c9e498160906833664437456739116626d03f6f2028d869218b418b6b9360d536e +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 11a710487cbb1b9392d6f6c305b105f68df8d5d6384e0cc10292a028a5604835b2db30b1e1aaf124a541c03e0462e575a6e370f02cb127a4c315c2bdf8365b3fcee020ed0d834b6ade7f549e959e645bcee20e40bb823adebc2f611a309b00d28c3c46c4aa4e10ab631718aa5f6e69ee2c7e17908ec82cb81667e508f6981f38 +S = 378ea4183be0744a9b81e57577e197b4b20f3e9cb7fc455def83eecac3f470e758557b741796439947eb6b97b46b3e67c12f30452c04ccc3801496db5e3df3b5f6442b7086eaaf36ee1a43746926e78cb43317259970b71dcc9127fb41668845f0bc7a938addcbefc7ff19025f4c35da5efdb74884a98872119983bd0c1db06489b7530caefcc81822e74fa635ed4aa441a48b8b7d6d64f1a489d50fea892b2296c6b1c24829e7f7a23c186dee29d88bed157386e4090caee36fe5984aa09cc222db2f5985dff56fa97da47202fe49efac993ecedba74132e144e3ca1a5702127dda6ad91e133aa6e53d3d5cb8c81b1397b8c8ea2b55714f6559f198d8ffa7aecbb12b2d4bd99eb697a3d26ca55694f2f1e99e543d6be90e4a21214ce3082d0848f3c141c98becd7f986d5684e67a8cc5b783d90aaa7e0e2f30616f59f38ee150ca41101c4f20ade865add34fed3727b745db406e91dbdeffc40875dfdf2ff0dc62a8d392b4272630d3b17ccdfe39313e7f8f265b2770942f500396d2e2d97f9 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430eb5d1d6ac4370fbf37da65a4a43e31015aaba587ed2b1720edc90282ab022f9581f3fd35e174a5be58edd5f9a9aaddf3 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 979982a68d0d60a1200990ebf8a49a7b7db3d1e83f9ad9d9946267bc830c48bbe025a5ebb99b85c7f1cf93de2beb22c8e9766e5ef526242b01f5251d8a768780026add2d2d8fb9ffccb86f8779221b01d206e586d96b83839b3e006910a4bca6438fb5d5b2900431f8ecab50a9f18d0e7e8abec7b212fdc9ab667f08dd3eef14 +S = ac48451dfee18a468ebfebb7300d03efd9231ee21d9a3e3bdb5db9f5ce8d3e1ccb9af7284d5a98a00c39cf62d9c4a46c0374808b0dc01bc57ac8a61682a7784279d090d5d57c5b4f36cb468fc9200e3c28818f5e8cb14bbec20dc460f2721cddb09233f64b0fcf7fa00c165395a681ebe52fc8673d7b18003c4387ca6c9487f02912cc15e525531e1d40aa79881e2c6b2038c5938476d4649f20957cb0405c6f1dfb14c1986235b7f8f18ebe3c47600ab80f841c100ebba3e042d865d0fb8de4708da33493fadc509683bfdd16c00c5cec1fdd7d3017f4a0718a615dc7122202a54ea7429966e6f818a4096db8f0ef3e530780f09eab5d96bff59869fb8c85ed059a3ad8dc3d5613f3300a8ed17754228ab4e38dc24dd8127ac8d4cb7a68af8aefc87e94344c46868c1562942e188c9618be86bfa09d12a16aa0b52a7ab493fec12eb8f4898bd000ace4c2520d6713772b524dfaa86655fc5dd140d1d7ed49db225c93845b41ecd10b8dfea26adf2761733cf0d330feb9cd024bc4b906fa14ff +SaltVal = 00 +Result = P + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 7fa4945a374691fad437ab261e2c9068c7221fb14ea96f4a2483130d0e6d9cd5ca3d6033f52d7a632c77127e7222dff0d11be92d448794a0d558dae4031ed83766208c2c96acdda048abdbeeba78496752f359fc82d1b63eee36c789d185337b9c77a0abe16ac19870fc8fe0c0d9d6b390d1f486cd2edd0cb74463624049b58a +S = 9e8ed5b7a3863ca22b2c2fdcd28ad09e69346c8d14262c7800e85ddf71b845bf31d2101fcb91fbce1f227ee1c72210f29d995404ea2e4b31b41a71173884570c2fa0753facadaae01038e6b897940e386b601e972d84095cd7e51345348d45a653c1ce707210b017c1b32ff4904eadcd34097af48a430a0147499a9d9ee8a765258b94fa56b0185bb0789cd222941eeaa8356964d2b1b12c81c0ad0440725ee6360c9e2f2885047c5b6f2069590c0f85352f5936e183d78e5a152f6337e1643bb37de221291191fa4226973f9fde3c688fd214c49ba3ca6df5a09bbf4523ead8682835944b1f7175ae038f84955dab509e0d68b5d9da75eba60e11e4e9ebb4d0f2dee448694f952eb3ad39e740516f129d12874e29ceb895dc87dfbb2ce4f208d1e646c347f9682dce4b71ac53ebca2a499ce64112279ac439f5942c8d04f2bf5e699000efde4909e6b6b62cfb52ee384e31beb22b1799731c543c4a95303f8fd32a14d7c0fcc4b449c9782af392800d2f7bc37369293f49c1cb94b2921dd407 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 831c38ca5421eab1edb3600fce5acce059ff4c5b38b56d69fcdaee5c045fc6dea164672777084574277f92b42b654c8401517a5d8baeb30cb6c6df635a20422f610cb66a2c7c37b13215a5f8ea86c67cec198bf95387941d6511f53d76cc3b48093daaf93925c950579e2142d56741b0627d059657eb188552e2b853200cb911 +S = 5c95df8ef637f77033e66934588956aabf334f0f5ca5efa1bb0e5b1c58fd313cdacb4d9f3163305e048d2f33a9d101fd6c0670f96d67b466d11f03d3aba60bdc04869e3a17aae7c80080e146c114413bb6f6016653baf26d3516fc05fef13149dd552bf5149cddaa46b783e625d5a3a0b859563e9f467d9a2723e5efd041a92a9837d4b652219d4a9799b35cb3df6c80b8467338b0e7c325e0dc1ee22387af8877e66c6f6a9b0d12a83db08dd4a843dc0e7d0aef5f0ca9cff1db415f2dfdeeb3a0525b2cd32c07dbf39eb9a3a132b9f764b66ec0ac6cbe0e770e1afb063cd1cbcfd8e8b39e10c290ab4a8500b0729a1240c772ef5adb065965ba3a4536e2ee0058cb11ea58834a5ff267fb11e90160c7a433bc1af9a044e208265e4c62b5940fde0e168a8863bb398305acc367cdb1c3b70f39ef051ce9614a125c3241bdaf42d8416d4efbc003f698878829dc2cdb1dc1f7c0ffb1af30b8d807b459403336a2eae1a6a497e95a0667a2f547b5d40bd97f9d76259c3ce91f1209a00e8da48fec +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 939cc087cba5d8eae6cd3884251f4d60808bdc82f2e6f013183217befa20cd5929d339c80ae7171e71b2f60671c9a36273c6e53186496ab6f63d02d7205d0bc384f62cd71cee47c3ed05a8e8db5b8305c1339d13c1f6496dd97b9634b785c7f2cf8d037daac24e1f814fb8f30adcd49292576cef4cf47380e9723b9f68a1e92f +S = c80363c21f7f20d91361e148b0a76c33ab2109b8c8e34609f567b49ec9675f1c04452715371913685f9a2f88effc90f3ac16665a2dbc81ccbdb4cdf677b66752fe07577c9a2986e48bc03e12126bb5212d7e821adb66c4eb96c267eb898db16f0fdc52f8f98797281d8411aaa4949d41815133a79a7f6f8cb3893fa1e28a37ee6c550e17772d5be34cf4b2cb16f119fbf9d5f41c411e1d2561d33aecfd9fcc425e287a650b127d11ddb2fe49a82ad3e7cfa84a4da75615ae23d0cbc45d58b7cd4123105ce3444a52412bbf09c08036f10d03d79ee735741858017181262fb5e2f817e0c53d3def1fe84c53807933bfdbb2ac2eec4fd96d638255364033e38ae5f9cdab1241938c1f6dcb14067bd236cb69809d95349d9c1723b39b71192cfe0c8a204c142a2a72d67f124ad6b8804d3b5ea149c7a1e884025fe56bc7ebf925d34ca62c285d3b290eb38fb24e59ad7c47914b98d55cf8d1685f1d08d1e919f314994a348499a68d3c669872a113bc119fdede411f4318dfffc8082e442784b68b +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 118a21ca36aa54b42804f7fb07874ba74e14bf3906dfc4343a19dddcaaccf53ec306f670cf39971a6ae2763535696613ce480aa0ff70a3e735e826d834b892480a058039417dfb5c59f693d47651ad3d55a51ded849af779d312a17b060f2d93ccd1e6acf53e2981df87775f3109c72ccc7121a8ff2468f3fade785086987128 +S = 5d1fbfceec266986ee94603ef2f57ff87959bcb7f1677fc871f97b5e73bbafb6885957eb04616a3a9bd010fa46c8a5c40831944a7f506d165ef3cfa4d3a7bf0768360e8dc0444c2b7a2e05106cdbd6e3ab029c11ebd701fcee53bc46acd269582ecd7635178b850ebf2522d16bb4e6671ee7dd1d417cf0d23baa26237e03fc0650462c1d113dd450e4465ff18d3a9871fe5fbcaf554d14c0bad78752b4c048356ffed2f80ec319ba816c60d06e270c656c8687be145df46baafb686a9b74df7347c8712dfe671b33aad8b3b7eeaf6322a8e770891c8e03526e1c6ea4fb9dd03413d646b3ac78a3f6b28ff87612616dcf87efbe12ebcb6933bfeb714961e8e153f96ffdbf7777f6109be52a936a13986e4e8229535f51a679f7d7aad4acf1824bf0616517785b864f5f19d275406ec53089a04a4f1b820d167b5ad3ba36910a9730722dfc58fad54f1e0d7f761f5d4ed3bff3037f79361fcefe723647c65811f4ac66dd6dc4e3f5b4bb1cd0f3d2aaf000251b69b9464a35bb7f7540b1249dd39d +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d06096086480165030402030500044022b0603ccde4538899af30bbe52e2e4d6e62ca5f5e69a0e7cfe914a193af2e5788f6bf85199a7098078438b5d2a3b694b926526033922915953e113bc4b56d3eefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = 465c2bbd78a5f3bcb387d0db7910e9b2d0b827948d949a67d2cc19b2d64f29f8e4c52145a7c68b06a449cc1d085f0835a421405336e6bdaeeabab2c1200c1d9e70a7ee85ebe46bb5a41dd382706441a8e975d4dfb9ea0db015ae788687b48f08f1e9dba6cf675c72bceb2b3238895eb3a89e2c609e0752125b90b42a92af48de +S = 902cd4cb495e446e0b4d4cc1944fd9cddb126dcb60543dc32c4ed0eb4e72182b1a13459746e4ae37805e23808cec5974083911f1c3f155e09a3223b03aa145128c9a2ead1c7010dbf43231b6ba5fce2ca77734e543139118475f5f3eb9db6c0dd00b01b7a48a1b4c65cabf9260d22776bd4168a7f7b8b81099ffb60d6ee00356cc16cfee9026fd318ef4f0e71288daf10e06b6789fe0c590ccb7c448b7426dca0329453633d98fd3917562a2df5c2a1ffb07f82354b8e3b1a508908314245767542b856938e019ff4ee00c46ced5b8b836b57b9d0999742b2e23dcb15e66c49401495dfa7267360eb0493722abe6c89cb92d47aeac5218a4a949b4d7c4ea23c7448995294424995ef6b873959fa8f670e764a59cae39e998459f9eb03f3f640a6c4a6c39a9532c48db61b5d6031e7098bbd836f5ef887c20f00e6f8d3e82a7cf3f3fd027cc315b85e93205b78e29b9307d25f6c38498bbfeb08a0aca6975f241df0bb9e27e99dca0b555ed294a23071664a7fc9039838a892bd4cf9696763637 +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = cc848fc93ced6a3252fe844053b56f8b8df90ac8ebdbb035c81baf3801eefc424efe25fad2b38698f0b1c08e61a2676e8335fb08f4661ad26001f38e9761fe26e37eebdb9827d89eec8bc6be09fe4ec461fa909c42646df5aa11f6e95c8923e1330bc9b3b7d1c60eee947e1875538c55ce51b1cbfc5d10644d559e9378edd43a +S = a2771501c8d96b8f29f456930f1551f648abc58e214854d44c1bc32de90c2a8d269ebb1c30456e710fe411483b4c931d40a7c300e731ab0897f976e5c5aced427bb462acb998ddc23031c84efe0d187930254e0e0e1f20c9155ba23f7d2a02f1b390db18c71d37f175d13f44e421279ed5d803ef7946ceb364dfb42114b2943b446ae2eab8932f19a87eb449adcae98223f333a47eb028dcdbb9a8fea2018b3e9bae3420d99d288daf1c13f9eb9932814d530d1f8cd0f496ab21aa984f5f2df5fc5f56a6e7431542864f2ee78108eb4ffdf98d50b8bbfff626da4f166881d8126442331ab8d4d30492473a6af9c1fbb08fbbfb6bdc828d2c2419a302800d21e91aaeb39a453858f6f2a3675afe000de678e5095b9b885d1b02c153dfc48b33470fe8521afa1d36a18e2ebb81d58e1cfed3c0125bc8c5635cb88ac78e03aa6d661dfac9bd2844aaf98b6ac7c753543865c70a34c9f49b33fa63bc7b4f0b4a38279fc413482f2757b287c31f83c786d5a55438c00d1f3bff8479ed3992cce425a0 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d0609608648016503040203050004403c1940aad46377052b5ca5f32e427fc60524134f6b125784071ecd029233a6b878b85b7f3c9a7ccd4838fb9352a468d02f64a6e19ffcf2e2158aef7f09033d5d +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = b493cdbc8bf23247fcb00bc4ad61ee808ccdcfaecde823ff2f04467382451a6e6655f20e555aaebce425270145accd9b11bb8ed144e6fa038ac2a585b955cdae9eca3d2bfc697199d2c7fb54dd3a26895e90d8931d01bd84ae61a101f39b1e54e25a78bc8809c5074efe51637cf24072fbb5759c5f1fb3a9254a028f38fe5588 +S = 301c7cfbd1d8fe0d725cc8854a9ba1c7b16a3e4c0e357373a57cf22386bc562615cea5e5359d90eac51e558a15580622585f4144905b4dcdecca2e42f68010aaf8be6a17cf2fd4a5ec77871c2229912dd6318f365214939e785d2e9d23c75eaf8cb3c9ec8a21d15cf7186aa3e92e1c1209f054c335fbd61ac9c48244ecb4d607e3bed905a930f9605855e9b220129ecff5239eab8260fe7cca7d07af495a134dcd63dbd71c72205d11613ba89925f7bbe36c2909e9dfd40596f2b6956e749c3710587d4f1c304acbadf83c29caacd3a1b3f0dd332560fb8802be3af45e6e09aaae57d8b8c75441f310ddd927a3279243817943719451b94cd6d3cd62c8e1c15070c2fda9baa2534018279d36ccc15fac086cae7d430c44276517d1e32082a6de8d0cd7d88900f9cf4a5e7012074834b9783734dd1524e191a63e0c6eeaa5632f6ff2c92f3d05589791d8e717f4833cb5640d2444074e881419cd521fb7f5f847fc1852c8e17ee7c7eb3d808c9870b1f81ea69a54b361b65c535e0dff70278c61 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b +Msg = a97ba5b9773d187153d602d121ec843f36ccc618105046af44067093b78e6e11114441fa6f2011a759dac139f351c725772d3bf1e2c32d38ee3a3cf441ec64fde40f18ccf6959185a25065354e5a5b5715b47e9e782d70ee508601ab07d30037082452b6746540151783154a9ad1e9ddfaa9b8a73956b7da5331e741730beac9 +S = 2f2c9aea6942c5a24b4e5e04875eb5c6f44e83d89ccf1f13455890e2d61f2b7ab464355c5cd0e7e9aecf004a0b85d0cee852a9681f4792899731f984e2c06e47b8dfc4424e4cef5b9f15def45d528a3a275fb4fe7a194ee7b10a6f9694e8e1659d95a6f915fd79e3406e05136b244213ccf67c5e2055adbffa85896591d7abff96f6e68494dcfc48440bf66cae21d1752544933bd22154756ad15a3c664188cca88b5f23a6acdc151e62f7d0bfa9cd60429031736d7df76bf2c12f37c338a1174eb42cb740c5d38c1cf1b682aab8d49443016cbe397cc0c44374f29502d997bde22a45efd0e7c801ffdcf1b3e42e93b955ecc0eac9f5b71c349504e8b2973d894f0d33edfcd07f9fb6b3cbee593448bef9590391d13b661e2dd18f70b43b59f2e79d65905f9ffd8ce0117e06e610f34fcc8dfc72d6f0440e2e6f882747c5416bb8c3ef6ec702164b51309d3df33a3846237a2f0ea8dd39ffbe0a8d549cdddd063d7d5a65fa27acb62f46ea9f467dc0defd426cecda8afcccadd1fa3e483d5fd2 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +[mod = 4096] + +n = b10935650754c1a27e54f9ee525c77045d1a056baedc8c1ba05a3d66322c8e2e41689ca02b8e6ec55d3331cd714e161b35c774311540c6410cc3b130e65cec325377ccf18a5d77054afaa737e65b68662327627f5d1092df98c08b60a3ba67599b1406986f441528d2f1f5d6fe5ec6b8aa797dbdb3162876b08298237af81c7004863576af572ddd66c487cf32a82d0f9fe260f8f2681613208aec55723622f50d3cb3bd33b1226d5b5b9ea2c97a2c59054e31536849ec2f0f2597c077e621ddea0a22ddfb1df925c9f1941cd431afce0398d28e736cfeab3dd7f062a65a2a4c1ddca1f32afa03b4ddfd8b7ca40cc0ce2ed42229d753f03cc6d8bcdca76ab7c2703c5ddad08aa9bf9a27740a8b23168c6b55917bd3d5c1c057c34d1efb1411da51ab745519bd92b9432fea8fadcb9a70e5dc3adcd3081d3333507b7b998886e988296628dd7265e64eab557712556cc492377f15a078dcb620a6e7f051a1fb8754efdca3de253dd0aad4205b032659e4a4fb307f074fbde340702b5911acb34737d7834600cf2ac77f62f83ccc9ba78ff911021b9f8ad1bf421430ae0d64916944b504542c0f6263c48e5e233ef1869df1efc2ccf6f4a95e4db2de7b4cb1a992bef6573511bab4bf2cd58e72a0c235f56dfc182df4dfffb69433a5677415f35d84f5125f5200eb57868cce6b74c5833417990e318372c9239a36dca1a0b28809 + +p = bd4e8bb7fd7ef1e39d71de06b0001bdadcc81b0edf2226e0d056b7eea70b2249000279cc1c04b1ac2919014fc3fb8b62baca3e261601fb0a58a9f67f03cd60085b2d43906d36ad014f321012a9bde9617478a0c10201afd53f2207de3648afd1d737afadf7fd2c0b9824d4f66b2c7dfe93390888ac088c680c27b1b2486659ccfa8986c8c23f78f18b5815a410328e629e7440221bffd8ec4722bba3420da5234f898f8cd7e6d7dcb1349bc4a0b665b41d930e3957cfdc88797aee5b2b27dafb5ba0949e3dd892f490212dfd249f4b1d99fd3b72695ee0652997127f0b9b417fa8365ba9fd103b978309d9baa9d401902cc107cb8d2af7ce04660900e3707ab3 +q = ef67f69838735c055145d21fccb42298642177fe3fadc39070a95e4fc04ff058aeaf9070b4eb2de1cca72d8533bc55206d2ce9f2895b148da67c89e5b6496ba682f76bcaef69306a7fa4fbd41a838bdf0fab3e7b56c27a8c18dc4bf970364dff7427cdcc6f532b49712282370a718b7d5287bfc02c4abc35ccb2eab3777f5e0d8a27ff9ebe13e725aa0a0cd48aee1fa33ea6b4ea965ba42fcce7af3c528a6675cedf4969640f2ca73345dfd322620df9dcf16520195df8232061e2bc89c12de24838f255e7b1c17713ba435d5a351e263350198b3fb881b8ce0acb5aa58b7afaff184489d167c9af21e40e2ba9fa69b44a3854329385c97df0de24dc283a4053 + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 200ee1828829d9fd27576e253ea700245c38c5ae78fc76e33dbc4877a55d1e10c961fdeff8b1c0d306990d1ae614872a7b4a450fac578465b74e9879c77d29abc8f39b177a40ce74c47c083b4c8b2f0c449e3c4f87fdec17e405b84bb96c0807c4cda44037606ba70a0847d0959460945e3e90b4307818be6de99135a4b225ec +S = 33d2c45a355afbb8eb5f64fbdc4bd3719afbcba36d5d4bbc697887ecb7e7ecaf99bb31798977e3385544fd4c44efe1b05f2a34119bafcd6377c24f57c030498f6d96148677079ffa05a253e9499d6b13d3c02d5347dd3263045919f1a7169f4297cb4ead2340e6706269a8607b1575044e75adcb94cc7db8ed80a776ff1e56d1ac13ed7d82439750d51904337c63bea9a059a056f30bbb8c1c721a0d666cb843b1a8223b197a9f48e3941a9f6d8cf022dc4edca612d057b2548986698f2a53266f49e7995640eebe929fceda0d33eb24437113edaea93e8d7892ab14b25e851b88808b470a90bdcff021e798ffbed003b3b9c8d53e4a1cf77aa7b5016a2ca41d4da22ebe498c73bb3d0239cf41ef7f404fd609d390c8c1a0d2f0a6817cd3ef966196d64c89524032b6ddfdc6f9d6876d6b9e1c55010969238af5f2ab616bbc9234445d07f2462aa907b31a08677fcb9236206187e00888b53e925c334f4993d3f18ad6db81ced54b666fc6513da7a4e8a8f1c0eaeb6819cce7cbd27de9f9c9718d900297247e41a704b7613221fa114cf145a1cdabf4217eee25678a24420c4a75f8d444069c976ef95d61e5abed512c01cff4b864038ec8e4aa877ac501664d48be5aba39a35df9b3b1ef01a25ebede122b1797494442420e0f0d0d4b7c49d85f9ffdb102a7a1e0ce6e4a99d9690a80958ed548e5beadec583c192316fc7311 +SaltVal = 00 +Result = P + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = e0dd55521da6bd181813a02ed22eb20e2f5d9070573846be5d9814c91ff072ba6de1514b6d08a4373d1b1feedb343e8e426c8a0fd6ac18bd02c052ec20adf9e799456b294df822d035ed7e4e4652c46299f06647ca02852b9e47b4e2e856ffdcad322c54861e40cb46b245b5dd2f4b727c10ad7ffae195ee7754c2133f928981 +S = 2c89c5c5b481ae5b632c628ac42501f9df48347c2ffdc7d06526d2884bd5dfa01591a0a197bc87c0c3e2b9fbd6934a29fe5039fcf5b5fc89c1731fda7e274e706826740dc352d95c470ec799bf4123e7d673060de89d217acc23ae544ef70e4bcff3af691123216582b4fb6bc277a1c364acd0bc7a689de95e2a90d762ef4ce7284ae0a9d42f0ff37a2f6a40da956cb08ef0520df1e5c9462ebb5694d93ab5ea7ab7cb3f1812eb06ffda74f651d15439797ee0597fd00c5c08ff08ceff35a44875afd485126a9044c0635c4ec60992dbeb9cb9be19541b019a270c85e2c7a31a687f96f13b75a11e1cccc0257a7a9baf665553ffd34802aa23f0db466ec35d8d5a0d6a560c75b0ed1f434ce06e23ea582e53851c59824e476686d027810f7b46f31e88969b8274bb3116277ec1a3982f26d6918d4919b2fbbd161af81786842b57c9dd7f388323dc377aa64dac6782abbac9ab3558cfa8c989b8df8ac5be897c848cfe00407ffc9de8f3dc94a263182523c31efac84120c3262158d9190908479fcf24343192b86991a15a2fbea0ed8ba12d7644af798be3205538ce4e45a437e116a1faaf527614e57a4fe2299c383fa2383a57b7e950eee956dfaad4dec984a239fa4e09586113659126658581b62de9eedda4a921589b02d2f24c57f2827b4044b8709bd688a8a114fc9c875973ef145ca1211698bde58ad273c67b6a5c44 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 22b5d51cc4048a5a3188dff7caabe8c2f2d8b59fcd3032da477f4cbb596e555b88faaab5ae249300fcea6a3d4077000c64973cc3376d05c171686200f173e0ea486c356e7bd8225205d59ecb1c4f304b35779d9aca71c3285b4dc5a2b33968c36cf5bd6db58701f8532fc1cae69d41276e621f4b0da534b60f17bbc82729b58d +S = 297bb0df8a838904aab3f7a517cc87b6f5f4e53e314a2f6d0270fc34ec94da9341cf86aa8f7de3220485f0598a5907ac559e89bbbb1e6ce4fa2f1a17cb5c8696bbce34480ca4f7b2bfa2d446e028359fdeb265af0e3e1bf3232712cd06ae681d7c5e8107fd9b088931ec27893a0f2ec6b1b9a1e53e0da9a3e19a2bc840366acb9452099fe221f28a6a8913f2d866d3d0d4127ec3a96c71099e5ec63be473390c4aeb9cfec8a651e812807bf8b3dcf75fad8372382f86556924ab57dcfd59a02b9f3b2da272c1c738fa6f1fc3a78cdeaa91120cce66b9b3287037c1858645e418fa74a5ad75196e0d10d38052cd4ab8e5aba58805b4bd58daae20a801491d042180019cd41b70559fd9dbd1cb505c7f7feac497405697866753a8d3e2a92f854a988a50f3554ea0aab86e79d5516db5f729cfd4e2d1c7bc754d00d75de863dbc5c254748e805da04492ff230aaa89ecee80b5501128bc37646fee92c3714e26fda4a120f684dfc043bc26cba3347a3defceedf425e729ebc0f7199a348f29e500a0cf50bbc71375b0c7324f41db18f7e3091c9435f3238ca879e61684ec7c5e05ceb3835d4a3efa4d07ab918a4c0b10f01fc8207e15aeab15d21fdf032960fe5235447bd5c6eddda747e8d9e11c3d05612ca1491cc5d1314946e45e3aa1c6b1756dc906168684685133375a7d7cb69ab04eab56cbba728e70ae8d4deccf4139a7 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 709fa24119653806778374d1d9574c92fef4959886c61958a97ae96a2918f5d48572d98b70c2fa37818fd2372cd088e5f154c41bd361c1f60c9ca4d9ff280cb56e12ea88eded932497b91332ff0ac4766a6620553beed494ae401562c99d379990477c41792d2a561fcae0ca3a4b29cecff0524ea4b479baf730e70c6fbda007 +S = 0b7c22e20bb685bcd1d871bd2466cbf02994e50238895ac17cb51bc630b646f3ccf7d1c572478d762648e958e8fe1cc1d6a3b5eb6ce85bef9a01945cfe9755cf2d55875ed9cc0b1980e54d9d11a64a4855fccfaa3c3f4973bea94717b18bc4960734bce689a6581061a85e6a6e316540d209e6044c5bee56fbde7319716094ebf240133b1c2dab38565846f0603efc68ba43c36f439f49f8ad9110833156a72435948c3581c2d5bc1dd40441a5d63200252cc9e8af7bad81f5513313ac3c3665a03cf2d89c98b736d3ae566a175a979885d4d1bc87913eb1c755de17d2c80bf91baa108027af75e55ef8c5f13d26b4ff88ba3fc4b9aabfb36f90927678a2838e374eb764a3773d769ecfe9fbee806b30d3b1828fa1aa8a082563ce38279f26c09b898ee863e5eaa868d9a52a35612cbc5e87e5202d5f1fe6608e0d20ffa9641588a8e60cd0f06b8455f72378ec5e75015b4e3933c3a8d8c72e204db29e3327f8d3c30f8b9150760673b572c0a1af15b0344ffc3e5d405a208fb96b2f8f03c63806351ae34108dd8f9018a6220c67d962c76fb09579bea1c43121d467e05684f267d7633caa14cec7c81fce053aa121922c190f042bbcb08e37dffc6b7f7e022fe9c937882c27fd8b4e8002a53efd9e7c32cdbee30b373bd40d547c07696b3e854e4fa66b4fd7b9ef41b8f6ca5e6e7acea19e6e624d61e24494bd93ae7226d686 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 6b9b00a0420a1869f6fe4de18f707dfa850983b626efba9737dfbd56de7c71d8c0e6465d668fb9fbe54a1e4bbea59c6203797902bbbf971288a53f4c87e21e3678468d531f95169ae9953327d36658318812343cc965358f12ff4ae97ba7ec70dce25fea34c4352f4c0715de975aba505dfb3eca188899f71f1365958174e46e +S = 7b08a6191987f3def583b16c365017b9a9f4baa76826ef12593e448fd5d7cc49d441fe7ac0edee5dbd1685a7295a724bc0b1137e8860930f12bdda8527b60c3ab08546d887f77e74315d4a6be9d4531413914645d51c05008a7e145257af7e7a1e41d949f284be7a7f1ac71885275da46ad75b45d6f19785f0a7a4f18124eb8b2d3692ca9d7c3b2cd05fe1df60ebebeff90cdb7b18b20a704acf64407de123a553cbf21c2468a25595fe2e2f6c0516221efb0f5057d92d0e64e0d95c1e5500467fe7c1742561fd0ed03fdbe4795a9a7457c3eba1033e11af6ae64e59bb9c84412fe89551d52435bb0b717cfb8b029413ea796f6b69212649c97e5a7f2e2ac50eff7b1485a251154c6da8609765e3e3b5cc155f0316c0f8a3f6630177a881e3546ba1dfa404430a0910f71531b892c6964abe8cfddadf60a301427d9d43bd8bfffcc68ddbb1df8b718f07ef794d95f47650b0608c5e5beef2edd339021152c5cd33d6737ff3c5f5aff14ef447274a7cd727e4f9530e40470989e60e0849eb3eec1a124feac7b452dcb5ff002225bbacb420a60afeb10781e7784140aad0f76b01b00343835caff44983b0e681154478b951845cd26b852f279ea45f4f6887ba29976c48fc618a7eee9b7b110fc00f495f015264ac6e0e88ae0129748da755264ee4b1289882a1cbff971d6e87545cd670875c0ebf2464f1133ba5ef764d49cb98 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a0500041427b561ce228f7d5f0f8a9b1a35af930ab5a9cfa6efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = dbee53378324652b696ae9daee6d6ceb27bbd30533cb49efcc3e7cf51b64098ed102343d7352ddb5f54cb0408b249b61bc1485b8b85b3d27eb86b033d2ee60ad0e821191b7c6c52ef21ceb87c643d4fa2b1d661f64b514f38f800e367be3b411b9f651fcf68806df8863047746d0fefc9d5edf01e0e0b89be0b5fcc5bd4cef03 +S = 24d07b55df196ab4f27c5c1008b49b54d726af278fad7408c8006262756037498841b35db44ea4ef7514a1edb148da8ef08fef64ee14c3059e6983526acfa9e6e64af6e056e0e6a602c9656253829adf8bdd43950885e3a6a8f202d90a728e0377242fa09cd3de5108b8b06b44d968f10e3652cd8840daac895b08923b981ad4ae2bf4ecbd230afb18c1fbd645eb993b40ba4e0aecee894d76bb414e33c1ed752abc8c8d950b4a16868337b40dbcd9707b3c28b5d59dfbfbce57dbcb54238f86fc7ce2c6a5386388a73da4e65c5b2a48d620819760a6f64b34cea861fa0703bbcb80524c63ff64c673250e1cd922cc3fdce9849e9c57fdbf3312c2f5517abd501ee26bb06e7ee25e58b3051944e0e47e6074a9af1f6e6ab3879057eb82519521856dc94e70e4b8663d8e2af2064b75847cf02d814a77a64bd395cc1f3357ae466f4d9ffb5f0b808d770b854ea44295984a938337729d301f28bbc5e332e27dc023c96db9bef26664d4a3d10993fd6942372254ec5639ed69905eee6b6afb2bda04685d34e3d1e7e1b8fabf9fc1a0418623c014e27b9acf277097108cbccec1be5527e7baa2ab100d8ad16ad1046f84e728ad3daa98a681c7cbd520d1ef131dd5d588325b390ff12e7b565c04de481c03dbb16f24f96a9241437ad31aefeb336ff3a1669aecf15302b26528f90b0ccb1853881d89318edbf3929ec5bc45ad5cc8 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a050004149f14ee6f6cd3ed793d7fa5a7dceafe71ee86f6c6 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 1d9f5b7a9786d2d493b4277ed95816559e6521ea07fa308deb217baadbbda9595fbe39308397225b92f2b6ef22a2cc7c50d91ee24d9bf0651a72f3038f646804a22288d4e682240e522f89d9449fa677c546711b0f0a86fb4df611a7a132ef996b33100dc92f20135ad466e24839ec6f8515e03e542f3a780c159f3f1811853e +S = 287a3784de71ed88e4621273a477d5570a0db6dd00d528ae7378858a01e7412a6ed335f30e0b4672d61a6f248ddfcf40ac8d827f847355fb0751e4ba40ecfcb9373a0439200778ce27391480c21938515d174db382e27d57148fd235b7663b9d4bd4b1f8bf1134900bccc5a0dd53bbac5336363d8976e01804b9cd089700fbe7ac7bf61f511e8fc3d0cd28f6e6207ef9d5757b762ee96facb746d7c514526b5c6afc71879e359130bbbde3110b9fd1d35c2c4be5a0246a53b164b3c6b5ebc96f10657d2faa629bbff44cdab4fb9aef359251f3b7e33d96bc96caa65a4ce7ca31ce65be880560469712de61585c59c3513bbe87dca0076670b142fb8e6e65b18f21ed0d931a1712a4c6d62cdb6411626d70593e97716b22d10d3bfb6420f8471e6c75509f6495bc1505a8bf8172512cc20dc76875d3adec3a29dd7fe79e258344e8cd8094520d1e4e07e20092e5a4dfdecc30625e9547b23c6a27abc6dc058a2e51f769f6a232fbd09577da3a137401cd1c6e4c7ae959a52fdcf1f7aa4856db6e58fff070e20becbb735dcc3c7a2208ad7cef837891d20281e2045d47a37ab9e7eef5234de2d0e9e5c33b48bf8d9475f96fa368a87cd3bb82b0ef167f5533ed365e73b8e64657dc9c616794d4508042bf5b727d60cfdbc4999e8429d02ef91156cc74942fc08e85a9e08630887dfa4d820bc90c96eaea99af4b6c90beca889fe2 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = a96a3d33f00d283002fe250940244a11048a4bbd3c6d3d5858939ff767de9ab07c2088075731b4a9413f605d38660d374c80f60e493fde3196790b565dc293d3ec40d6115cbb4c3d70f48140bf385df21634a98a180bcf5a27a6e1b9884cdd40c172303946d4785455c48e9c1fc2c4aa284e6b18f0fa9939d3c329072ea1025d +S = 553b659961b3c76e6ae1f2cc56928e90488c5a6c8c8f6be7885824cd69730b356a57a42f7da21ee061bbdf8354a6ffb3b4c96948a7547c77e6786afd77bd6507aa159919d0eb56384610a18a971c396f994cb6f2b426fcb0b96a12836ae99f6f1e91de39a90c6df4e88af34dd59ece75f1d841466eb72634ae73fb66b952e4a7f071f09777033faf0bfae8fe80d7b45c3e46b063c06adaa71ea66e8bace380d35fc8dc3d61cc4687655b89f2a74a41f29f8ea4b77a806a0239bff08c596392e5a78472af3cbba23bcf8145ab3cabc66d04bab15a8330cbd6f626673fd16c8a30a6c4eb110690e2d5bcddb327619887a12475e0d598866123b2604e3d14750e5593276e3830f11cbaa30f7ee61479ee05788f1f7616053b98599bb5246261de3e90df969d0f84dc41066305ca493e5c814cd199590e6ee20317ad9acea9ec22b57185d334c17855485edcc3d2d7e939800c12d02b4bf818c72bc03d9d06c228aebbe9dc7d018349fc9ed8ad34249e05a99cecf3dfff0e2061af2e6357518758b1ce23db5bb2d69fe5fbe64b3e08b193c30c647233a60372e64cb550f90a923321cec4ec692b3d2caadab37b6fb3826d591449ae2ca3a6a754df669f3a5beda1b191a8a2107c649d69234d83ceab0a1c0f65bbb9d7f518a0106c655b86b3a280dfc8c75548612b01bad47e7b1c232a0af34e7de7291eb9e747292e78b61fa0c174 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = cb9fd0e59bc6d0c1b1ca328db6bd9205ca50ab8526e81dc000f46eb5af7d4edf10fe1fac2877b4310bbd591cfc1414ead5ff2b5aaa57e621a99b96df4487d65293e811c9f3ae45dcf443065b721bc584018d52798fe1a0f144aac92dad56512e1a03af254494092b330440325ffb2c3b169f29ca1dadd2979ac80c87311147da +S = 7a0a3a76ee0fd8be7ab380c909d18702fb0ee2730c61bdb7fe5623fe62137145bd555dd1945ace3c46888afa725359bfa21028dbcec113d14948a95a3ef8fde2a454d56627de249a7548306ca4c042037ec8ded524926237d69bd4099383e0fe68cbfa1d13542955aeca3fb27e1c21dbec1f6b763c0e5df2efb9e3b0a5a5ee439c91832361f27237f7570e0fbe93ccaba416a2495daa38a7adc15c5f39ceaeeb9240ef19e6e58a07567fa3d8fe5cc375ba28d15395a8afe98b71162609a06ae34035f6e92e7e58c6e814aa9714880fc8403bef091396ea465bdede70706e514431ece1a30b6b0e640456a3c353a790b5e9fcd1a75177aaa092af6cb07221df11b9dfd9f9e7be02b2433841cb7e3db33a5e4010b0c411e7c823af510c80c5930279b7f655c52d7abe24050561c5ea2f290a8e59d17ed8f7873446ac329095814b47d2710648090aa52b4e969298968e313f7f7e49599bb01fe361e1d16ff10d25eab366ea47aed18c98fb87c1ff915bf040db4a46458e12173823e541a47f7fa92377db3070cca6ffb9b78e36fb90fd662f47605b8872b8556c886b84a774dce72f92f8f673f55f8bf24153c9f18753ebae13d999ddb8caa25fc75ec58f29adff866dd5ea68aaee641d9e34c3783187c3383f57a88ef1b72e90ff9f512a6061ba922954f63cbc0726b2935adee477a14e6b38e7115be26b314e456c65d56b3a07 +SaltVal = 00 +Result = P + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 0bdae31979864502cc9e0cc38b9d97ccb0aa40a0076de142d72197e9c4eac5fbf4695c39718e5a37ceae91100ed6aa57c15e695170c133613baccdc3c154667d400dd893fd192b7be7bd5ad0779a5a4bda3b59ee52eb4482dac98b44091e28dc38edde8ee7ccbeb45df3f06c8f93b08e436997e175921c8efaa15ad463ef14fe +S = 34a41f46718ae045c386405e56268514a7baa1fe63c6a4e1c963b1a43010720caee088df14f3ae4681a5a63f89966ba2ec3243fdb80514a977004680770bc8e7069acc7aab3130532064a74f14e86356708f32829ca06e0749af4c6fd8210e2137bfacd11087630828afc4a15d01f8bc1c1a59eee3b6815e4168017dd572136af46860d0ec0d8b24d342d8502c09528fe02ca39c78daa7eb6c6ab0d9f063d92338f68aa7b165b05d044e7f9cb9ba1f059058c15b088a3087d6797658523b3f3950ff37c7fe135886b0b309b5e3d259993e1373e7c86626497c573264d928ec0c3d653cbee9403f12de12c7790c54e0bed9cbbe70aa78094972bd921cd0dfed81ea6e91df914e83e75dbc714eb89e7dcf3dd4d71450424898133a9bc67bd4e103422cbea4adac473efb16c6b10ebe089ee60034e0c599f66f836574f7207180cd6de83e3708128d867439a90748676fee209dec01acd90d5003fcf7dd1e919bbb3ace60cad0964081a8eaed261c5eddc7384297731cf9cf892730b938e8aeeedd60b06617fe7639c2f3493bf96cff12df30b19ae86c8edb0867f5476b6c381301ba9cd3ccd39b12ba11222068878550cda07e217185eea14f75bc44512490d1aefa18ed11729867e4e16eab49770747cdca5d4c39b451d50ac9432c42bf3122da7472fd58d95ce0937d33818449ece98b64ab39d1d0e0ed5e6ac11f5b119dec8f +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c0b8e0726c9d9bb66179c5fbffb9b336ce88a54e819789583af5fface +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 0f46bac55d9e2d3bcf07f70ffccc050fc35fd35232a87629a69de0533413607048d368b88cf193ed0c59e68e97ab574e68498bc506aee4646801bbae5de9eaa52ba48e8376530bab649850dfff635cb3db090042f897e71fe965d58f36ee2cf500deb48de36d9b5d21ecbb69fc9d1c2763c8ba32d10b884273f2b45c89c82d46 +S = 5ac96146da56064477b2994f953f31906fb9f546553551c4c76b4811074194dd0a4622e3a53e6c9d13404dae87e4f13b7142bea20336ee033295f2ed94405d7ec0351d880c78d753ca18dcb6b39735c588e656aceae827c273068097b39d1567f921a4f2305f7543fe2efeb0ec47a0dba7849ba4e919c388cf05de325c2399cf84f1a167a0895a783e167732020826d5735e8b0b7cba4ee338ff586cde712eaf638e7163ba45ef94818f73e7b7160243ac366dce1730b9ac0937532607f9d5f24f9fdb1e227150d0df91a8ebd951e7aacb371c0ed053c204b22735ed7688d587cba4a23f7857d05fdf97cce9f363389832c35ad291757c0ff8ff1e5a5075aa97856cff7838d3ecda3450a7c9d27f0617ec80c94a2e2a09028fca6e613f902399ef4f783e768f8f62e097a2dc52dbe096bab99cc4d01ca7020d72d0566cd6b8b0df6c1a1123247097b8ecd978925a540e05c2acd9d65d3e64a6b05702824380c1a24bd67d66f2b623f962e89087f08c5695b3f9655fdf24856a9f6561f4191ac338d67e90bc0c747ef7cd5a115d47aaa9d048ebc84c098383260fee49bdb446d1a153e51b0041a5e34bf71ef2d9b579067138a492e6ac8a693da58d5ff37743de28411d56090ee31f9e08cfb8566c7067635a30ed65cc24d40e1084d6c4164740d0770a88a287897b34fc4490a7f565827d8139577c0052f4760ef17c5f5978a3 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041ce07ae5bb44ac73b9490d62cb7f02d236e95b023c7aba070143c6243cefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = ec287cdb5ee54e8441dcc0662f98420233406c61c6bd9255fd1f9701003d069bbe9c5e71df93ae2afaac624f094c5d0a1a97482d478e2975e77a3711068eed5e13c85df5d918c7e7b1c46a47f50b9ae9b709136ab3da8d7083029033120c8a3d53721f6e33bdc042cced7f57db1b2129745d7520f4eae5ce387f4b710c0106c0 +S = 30a67f084b071c9e0d5c5f3f797cd89441932da1e5cf9b7788855d03f6f2a52d6519ae67ea7616d76f2a73016dec5663f6e337c9c26ab3a4e0bb6d3f8ea18d0ebb1693ca5419b9cd19fe747f486f8bdc40164da9d7024d7fc675b7f87b702615ba523b59a747550a26bdb8a80a57dd14698a17b6ed4c4f04fbcb3ad98a2190f02f508b681a517663a3c0a4516f92f87cd9077b674e716099e36dc50ad24f98bb74a6afd0f85318a67abdab02fa2853d206acf49f941706cdb0e632244f2be99ca1aa9cf36f2383c1092371031a99b7342714fffffbbac48ebe8fc7a1f31c40834090d7dd9d905047ec08aa0c73d1b2a3cdf6c10d3930db3f8675a97ec1cb175142725bdce1d73dc97f656ac1441c967475e46b7a94ed38d067def9a54bfaeca15a49780f5caf2e42ad3b5df0787c1c06844b28b68dfb0d675e235a4114920e327e870e2346572c3b04aa29ec476933470a0e56fdf3ec0f5e1baa35265637cad3b24de388eb4b68403b4b6652ac1c258cc56bc4cd9d3d804632da9eb23445154fbf26d2eefa30ec2916a54b052ce58baddf426680477aabbee34fc6d98e57af4342b2942c77dd8695103487203a77d4f8e4ee066bf003f45cdcabe7b57b46b34084bf22eb5c905ac76df823a0e9343fbe4a868a6e0adb58bb5725b8da3c03933d95b4012498557bb78d096b810be5f403b9063243bbec780de51ce927d7294ff4 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = c9228bd9823d98cc91944bd362aba13e16f6cfc78d9fea74c383e8be607ec7f28ae80cd8fe5f6f935fc7d5c8cd907e02ba378055f910744218426fdbf01334277a66a7c8e58185dbe51453204d77945be0343ffa64c570f7f99f5e00a96f8dd640a345f35e2c426fca82ad2409e94b1130f4f5fcf647485b0da09d75b3193bc5 +S = 7ddff91ff1168c9bf0843a1da3c141e1856e312c0d83c4052b9c134d3b0fa82a53e4e1923b051be39fb6245d6acda63026161feed4e2d56d83677ebb347b1849d479b3da628b02a3a411f86c443e7807f6b5239950bf2b060da1c6905dc75ec2e4236b8cdd77419361abd4720267ce447c104f437afab32af9e1b4c0104989ebefbaa7ec0c18a065a0c38a79ccd9e40eac3554d78f3dafdce7acf06e19e7e2792cd7c70bf1f0eb15e32c7d6c41331ad8c8a1bd70d4bf74e64548175d913999aa673c995bbe8ae3e68c362e3427c116290a9680d6d7b4be07de3cdeac0a0723699be8ad032f794610510ec4f61eaf355e56e15d053007b1d228a91b1f576597c1c78636c2202ff55c070eb3242b48eada77b90777001067fe61907ebccce40bb6b6361add71717c3a429267147b341bfa8bf0400512c538948a9171f2d0aa278aef5b950b5b7722b372ed5c2ba1e18562f0fd7b7da7566f61f5adf1f8ed1023605f360872cd963286bb5685cfda4968f412922df0b9b7cd0ffd8dbd16a2382b6893b4d075bd0965f4f7e4e2c09b0bd00217fa6bcf9e0ac71309e071c4ca0077bcca9c60ee5226ef058ff8b7a076d68cf161b13dc90d51f65babe1f4727396f070af6b3dce92586e0d31028e6adcfcbc32c71551c7d688cf9c32fbb26d03c5fabd455fc716d9a9cb82a740a6a46627d80c75035b0bf02dac08ed6f45539f035885 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 91e945fbaa97924f3e6d9ad222bb01e935b7b41df0c2207a3eeca2348eb93e9127269302bce70e9341f35f86fd42293bdfd5fe5415f88a16dbc40e1191e7110311a852fa3f2500b9e2df2d5db2798140b1bd2b1ebfe01d76690779330309468cf67768295adacf87c83bee9d69e96fc0537625c41603426491bdcae30ba847f4 +S = 34dd79f3254da1471173aff6aaf54ec5a8633b468af99d925ec258438f3bade74fd1f23c631f94e6db57b3fec9b05ffb18013cc090bcb1f871e011241b352549e9dc72349681c10bdeb1ef00f99d4a70c48488d812bb621d0e3b926876b91da56541176dcea55152d31915f9e633620886f6264c70c2875019afd51eea4ac8cafc17842e2e035233d4679cb22d329a671b061a2da194d00dfe6a3d6ea3c3b10369e0558b68456b241e7c368e2492bd0d5cbbdab42a8526acc04cf2ed43944708e99980b31bdac37e754850c0370da4ac8b71b5147ddc91dcb7509df44b3fad89c2cb4e147255b064ffa9ff758a55c045f27bdb4b12107e1820530431a28baa16da02925ffc8e84cbc7ecf70c2dab46e246ac51888a198d85dbbdf4be40e674e562533667240e043a6e8a7d1a026af2ecf6a1cd24934f6469e28b14bea0f46cd333b1043d837b5b21022c9f7dd7713f8576152431746b54c9cb9a7ed3bb5c7d027281cbdf9377187fd584b8761f5f6972ef357cf8c54c9009d9e650aeb4c9d718919706d48ac76c404875e95d60b5cfc06588e1bef0ae95c31d13a27edb86dfb643d9d2f08373d7af39783804123202f796b1a01da28932a103a817c368f9e8bc8764cb949e351e0cfeac9087eca02e097662020927940b84dce30f22eb053c02f6345f6de59c2428a0c462020650db4e93c515304bd6fdfbf882d29034fe218c +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420a20a34a9c3d9d0e915b9f010007a3c625bf71d96211c68cee82075ad2dfd21e7efefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = c63bd2db43b2e094aeeb020514d2439f6d8d04d0c40b403398e0140481507ed617a965880fd7d975a7329deb459ae2df5ac656de8dd95d4716369eb86796c2c6125878f1e718bdd65c825aa73368aed95613ad1c06d7299034ea51362f7777a580ed16fe129d13219784432126652ef6291c1272762e2b77bca43266211a24da +S = 18fe9f7495370f1b1a8318e33ef759e72fd463d358de45d4aa412b1c149607681d12d7da6b7640ff21b53745387e6a5c9effca633c0c6d1e7c150ac6b622981167fad90fdef6b0bc71bf87cf7aaff12afeb60c823d95b32e29f84fe500248207d792d27965f915cd9527a666985223b4b2e7d72b1819cea49c825c304eec56632188b0907b54e2fd9d805a53e58acd08b291532d9500c64ff406d54c0f43e16c5a6f40499d20383e6537bda582b5081d0db95bead3b436c7d12d5c9ac695d4b660c79feafaee8b79f4fd9147cb5a14f5c8700c868d24bf0bd086397deee79284b3a79e9b68560ed6e863da75da37d324edf13243556f66982745b2ae931e3f2348fd8c3f206b183cd8768183c92ce6a0daccaface91f3ad6dda20d5c604b5c474918fb124c494f76d68ca7192ef25bca03648eae43008f9c3482bdb7b086ea92d41ba3a243bba037f7f08dfc6912218dca0fb97a11acd0ec3432d1fa4fd73f4d810843606374c780b8fef34ec13fa6e26ca05124d8029cf7ee6f9cc90ddc1196e29c4a6ec9feaca4c2050053a212838ab901bb9df01e31b6519a9d4f019ae5bebe1bcafc92f79ec70bb1e1f1db62cd964b8a15171edc72081daf239b0f9306921444032295b4c7428873e142fd20ed2f2e598fa346f2a76579045c727de99294e2245db6d62061d1a2cae226f0aade7da4bc32fc6e750483cc20fb2f017178be +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = d34ec8c4045b0433954c81096a09dc82a0c6c799157bac1d2a949407c7ea480ba0f3b56db735951622014ce70f5d104d05424d166d084883501e029e62fe5fcd406087a8f6ae8d08c4b94f6022aa9d51013b9d7854276d8bcfde0ba4ee7e72dc3aff061cc8ad323002dc501da9d7c9b51b197d68d2c0655d2e3e76c27452c960 +S = 4082a6bb4453970119c7f4cd61253f441fba30c004ddda4ef25f6b9f30edfd3d2db0f207e8b7c34f2d9ee23d692c850a29e70906a98fabdfebb5fac91722dbab0f19ea0b3952041cc448fa9e3eb8b54965e068a2a0df68b44f2839b9d10ed07f9d92039772bf6fe6a6d4db2531a03d7eebc15a125b87ec9899cf7b14911dcc4f0880b2196e165c1e45edc0de4abf859f30d87e3bfc3cbd69ed066aeef26869ec70012f0c1d1e13ba1bed0a6260d0c412c8e4aa6fd0f8b716ce33fc5bbf3562e98c307b1b8e617b26aa3f55e3dc063f7ffe4d03844b0da97411f3996fd94416648724148bffc5900f1f9b908f2c6ff5ad20c90d3f5ebd76e3aadab7b9e9e55ef50ecf4d923249a83cc59167e65bf6593aeeccd750ef0c3f1029dae3fe1ee23678ea70406a4e4f9f1165a48c16659d367e2f1748e104ed1f898db701336c680400818cebb47529fcd1f9da787a025c316a2baf2c1d32eba2eab393830eee7a2465d0e43c19362e64266883be22d85a0efa83f3f837d206bfc96993d16199712f6947b39cf0875b3744d96705ea19c8a173aeba23c6a049aa668a66f2c6559cba601c4a8737fe512509e90eb5751abe5c45f22e9fe31dc936b7e80544daa4e26cb9d088a623ad6a7e70902196a0973b8bae0866513360a05265ba92e96fd8e7a09e35a239a0d2499713ca0e7b5dabb06d162fac90a75e9b6483b3513787b66b9f85 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d0609608648016503040201050004206befb2ccaf4b531cf9ffc53f938035025cfdb7eeae29da84ebec94e716c003f8 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 8f937d50d24a1a6ed858d2e3de56e5c23b917d5a936c87b84effc06d48041391caf42207ba6d23030ed7edca864752b99ba3b089b308c3d19668bdcc2578995d4ac9ac502b347de3a37cd685f22f1bddb3cddb0e0f2ca53a311b1d45f9464edbf55a42b48d69d0167d8fb69c89d6e8376b57277211a2d4fa0560075d2d37dc12 +S = 2df1e58e7491739bb027c6315a70eebbcf37b8e5958df07578a589a47cbaf1edb23ff2e676f2f273a1cc0babd22e0bff874529cfd6479ae5c7250f06579eb212dd3f4058c476abae8e94c89afe05746c3aea93155cf03195ce5f4eced399d2b61aab7f4060b69844cbff6303d264c4755be78af001d125af461fececad8f46a9c4b07420ca63c4212f80a751fcca6a4737684543fcf07b39089baa9995394766f69239479e7c9778c644e022dd4ec7e07a769aa75db2571e58a5e0ba1e4377e9677092bc9dee9d9dbb448441da8f4385b4d4f8ccff4b3dc3c3c3ac8ba11a6ce8caafa930108ba3603c5b0ef65a02a7afebebf605aa88511513a69b3086fdfc25c588c4d61a06219d0d5643410d3ae4d78b2f695efe4e0b82161c53bb9d4b8a83692bb16de8da18b4a6c2abbd0f6b0e24229077fd6c3bca918bc9d9f4518598238df0c925f8587fff0852c44e8107ccbc1ce6a9be3b0941c3b28bb03c87eeb959d719dba9a64a338c7b9931cdf6bb169686de1f8de0e1fa74d03419d164f2c8bd2030562705d1470415e48144181dfd31cdd4219b5d22f9a4c659923cf5c4edbde18e8277dae11264c11423c5481402e80af223f0c4faea0c2c7aefacbf513962c2f16af353ffae1414b408f726eeb946d7c4c8577e72d8f1d49ae2301cf70abee46d286a6fac1b888c334538abb3b830fae595bbb19ea9dce46a343da031117c +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = ef737d90f65532a2693ef41fe916a2b970c411409d3801c54caf50ff6a326eee086011bdad6e2aedf16c17b047ca1a931b1a0a601d174843dce7f52b969d62734e02c8c220953a30d2d0d7aaabad449788695abb2c881b5cd819eba41b3bfd47ece00b66f6d14ab233f39dd4bcc8080de03868197392625a68ce9a32a31525b1 +S = 6d2d3c16eed39f5b46ffc45a8476c0778bda78d2dfd246ebcfbc74f88c5ab742cab942de2da36e1ec2cf65a43b4ff04927021211b35d6b6b2136ef1d69671aa8b95f6b55be4751a54b8df1bd87518e4a736bff9ef849cf7bc212734b77a7fcfd3ba99327884685a146294ba0a45233b03e97a27af2f615952261cbfdb1b5bac0f5fadbb8decbc4b16ac96606242a9489f20fa74f726d3c45e0e0c515382288a8ac19ccd3eec7ac94d30019dcbfbf77f9dd592531eb1ef4eacf9c38ccc0414317a3d7eecbac02a130b8bfda18f4e0fa6a5bcab44d35e020afdfda351afa1f9feab93579861d2ac39e6c8499b8b5777a6be5ac77b3ecdb12fe8189b0bfc00a4a3e4e6041e2d52a5112e8af45e5d0a45f0b88ef66ca29076738ed07129be4493916bd885e128359e860ad8f0c0d8fb649710cc76a0d3ea701a2ba1d7e77ff9b037c51f93e9b9e162f71da900c07b42ce0f02fa633e8e987cd063b8659f25d190f3d35105f70edb65201dd67d9565cf4e718f4db2f57569c8c88f20ec11aae3ba3bc1bc78c29b2364acf2f964fd2165fe82d8721f1b16b668804468f0697643d1bd0efc5d45f8c27b7804b4931e210a1eb789c8422d7795a9b156fd9762a56fa27b7d5adb2357797ba50dea7ffd217025876ade111d504799ef8fec084e061ca0b884899701a9265969a9a027c5337cb0e1e86d3d5d1b8a0a80eda33c8936b436c83 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 5e59add32c339dd10f33de88b32b8cfc1dd8fe7684693e27633bbc0dcce7431bff7e2b943b13d1b8d47a44a286504171093b62a6e57392cd8882c4609648e5e880410e65580bfff0e422c99ff1efcaa9e901decaa89ad4e98c6d1ff9cba6ce1d0a2bbf0f2b210fc266b3d4469b0e0fede6b0dcac75e3ecc3968435a01409e801 +S = 5d7f2def0ab2f104974b66e6a7ed79a4cbe4d9c6ab4bed75f442703fdaecf0e76eef5fa5c13163b4fa661137c877e4416a3fbb4a15a2dd534267ab860ae73bb97abb5e48bd5ac60108baf4aa28eaa5b3aed8f84adf06063e575b39c932a565ac9689a6ea93359f5e5c384bd41af7627df06169ad4728e9b17f5cc7855b5e2a88d4417142bce9b45ffd82e785c6cc8774e3c78fa637ac69c90a2198909fb1b611ba28ec978b1813bfcedc2a4ab6f8a2f457a146be5a6ef6ef90a91caa3553f96a743ef0f3c2a057ffee3ea2b4a3a2c7e9b26ee2e531f8b17216080096527df06b83bc11ecb977053e5d81f6c3e30e0fc5d4353bcb7bd97906ae7eb4bb1670fe28a8bd674c836e395953d3c3e64503818e3c563284c7d21545e7038d3dffa0182b5e6a7ca50e07d7dbd3614c4b2006a4f1a14b77c3dabf98459cd33ec5b325118f9e65b851a155b3f73267950c92078c70fc5dff3e9f07a9c5ef42fc210b5d2b24a9dec7db05c12e492decaf4b448c9545ee492dc0c2a4a5bff2ed32a8a0ca0a41b7f7455e622763319054e1212c0297bb604452f82393a3a96f54b1a141da0edeef052d2f0382375e501d67b1a83d0b02bdd9c99fd68063b908da1738e88b2da99979abbf73e60a4a295d24fda59db64486bfd7eb5b8dab06dd22202d58422bd450f1f698d7ba51f71ef556c5bad3d1461481677e501dde5b613fb2ccf85fb40f +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 655d108236ed81085d937f81dd9056d691a1dd531f2507f32a81b5dec9c4ce30388792fcce182b912fd785fbc3df60cd67e9a41e626ef4d29a0c851b082b313e69e0c79b3612a6e8d7db8abd1430a555ccc5f293e92bc643933ba8a3a4b862215c30586757231995bb6834cdb6cb4df528fb6fb89ca4a4ce7dd8c37e87b38a61 +S = 3363dc1b2f8be1f660baf2b61348786a7305f4bc3e7f030318a743893e41feb40636f768a286c0e82f0638eece2d7f53f8b5c8c5052e6a942e9a99fef85e8d5f2d83e6768515ca14c8e8dce14717af8fd5a2ef209c9b8bd314e5297eb48aabdb7875d1c33efbe9d18ef9021ec41cb54926bd3542243db8c576d8bcfc61b5dc6bc8f37b91e3d631bfed66d97e9a39aa815a8c138932d4b6087b5413c888e97caa07b54541f22cda57a9d06b92047276bd21bc5ed946650ce7f9b07cc2e150bf14233e8571a8f09259dc1620e6f55609b2f2a257dfe250649de5e7dc42fd7503809d0ca8344cc92571a91ca99abe1d22bb6f56e84ab0ccbbca0d8267fadf08017fe98ec57088234e81546386ea48725e0edffff0738ccc99aeff1f3977be58761373749175e7adb270ca322f15f866a668b3473f5587ca80fb61200acb3c09bbc087419a5d4a3408131571d06f09607f8d0b07a285b79d041842e5cbb682e11db41b0c36784c4c4895d007f076d3e3ed2a13d9f0601cd4e95ed492dd57505f76f119eb3fe56c899c20aa745335fa2df73552e95ae596b1ceb67e3a533b2df1ea1ed661fe5b46e1e31b753211eb44fe683e26fa1faee65adede0c86c788a067cd1c885ccbfc0066fa94070a310cdcd19003b6b7fc836c79f19e7e402a549850719c3cc3fb4cea67de4332680c3b891e0aa42693bf113fb7210e6b0d470d30335a69 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = ab8fbba0e6a56a02b0b42f139cd656416b9bb654da952b09bf1a46fd544542cdd33e3a7c43bb9a1591c7d491e2c354fa28aab5d1f39935ae8b8e66263b6f27f1ef4fd34c02eeb89d517ecb5694ad991beedf8127c2bb21ecc9ea0ef9611bc821284beddaca43ace317627d2a599c0fece4c3821eee05d70ca1b7a5406f510da5 +S = 87615e72a27b387de06e4e8bc3f2e70d24d061abb00a8a006456ff0b8bee03924307420517eccb0eee44c1f8a7458e13c0694c1bf7855d5ab1202807339bc82cb5cb3974b83d4000751fdced787295387acb814c2ffb4f636704de4595bf281d544f72d676bf59768389d92bbb08ad9662481129af3ea0ff2a0faadad65c93ab0029ee0ddff3ecd02e0bae13c4597de92cbddd6fcd9ba4d83688db7c278ca55e5c15b061993a1a53984efffc0ed72f55f79f3d11581ade9b651a6ddb5ad4863e3b9798d2bdd7c346174b114778f49ebde94c53c406ecc6812fec601995236ee09a8df5d0663ec4cb49fc47599b2b884cde458d6cba31abac1d3900fba8d9a053f02ceec3dc9f372b285634a3b21d4c7182c891523fc75bb8e49494d5f5eb4dd001c40fc549f9f586e60fd2f9b3b3dff4c8d33978193599de8471d2db11a4586f2be00c2f03d818ccee82f183f784c88a5d04e14ec99ef808e3e68333fefdaa414be5d7e817de3472ab212c40de7f172b3e62d203d7da871573f4f1fcd0f01f49258413e726cd91a79f465dc0ab69962436dcf52162c09fdbc151853327fe69a51ea91a339138742d555b40be06df4ddd594cc51baeac5738c96d0218363461bae49da0418fc3330adfd9ec008e89e2342a9084800893b2eb86e40e27da0500a171e234098079b91e08780d5d4e3308e5158bf7b4de557662311c533c9daf553a +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 450171e919ecc10bbf1d05f41eee02eab8eede088a31263433eb1652593d14b7494f7de1dd9fa465a39918283b6726d2010a9f80edaadcbab72afea43e007a782a44d633d006ad8f57e5f93219dd92254c61f187e2aa3a83ad4e7a7fc7142c9631070349bac9e371232a307880f94cc9e11b5b8532d94a78607e0f4bbe2232fb +S = 0471456bd38ff2a5adeb19b73c35de60f07d7907479f9e6d5735dca75ebd3ef499194917287ae0c3334a5b97f2be41598917a5d880b3d021c61a7acfe9083441661f56fb984ec6717986c558a10d108fac9e00bbd5adbd817a7684edd424e612c8a7f60ff1c8056067f0eee1c6ce3a4ceb6c27c735f0fdc93cfb521b529e1002659e6fe9cddcc79c218a84ee59b7355a43b47b5c4ece8535e0874cca866e3981dec3d1996d4dd05afab27bb5dae9d6ac9dc39e957329eb273254c4e7784a29db26696bd0ff872eede9fff869c35487643755d9cd5bae01c7858b123e4f9688b1d2607f349d52c828dd6d76ff41514565564d39038814841a0441c232411c8afcb15073739f5d5c537138b9bbda60bfd2cfea2847678ffbab73eb02fcaba9e4cabd7768bc0c3a6009dd78f02a8d791f5e1e30d7358b5a642cf0a1a838b954b76a15386109926595b2862de80ddfea98e6218efb925cf5d6434b93045cad5bfd1af36e63a98c14b8f5c6974f04e5e52243bf7cffdc8cb9c0a35fc3250943d07037b319cafef02a2fd21c39aaa3da9f171f1e9c9613ff97d3a6770e7639ecbfa7e47804d8833e8212064d091e02801869bcb2bbbfc2be5d21b2da790ddd7973b6f5b9d6c763cfa503c6243851461490dfab31cccc6621fd91fc1ae28b4b1d393cb1e41d397852acd98fa35b93b6b4dd92e2d5fac7665d8c0b3f7d03ad3048b6854b +SaltVal = 00 +Result = P + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 105048a958c92670205618120e4f1f5f40af63b03d2dc8272ba8c13743c8696683e3d051a21d92f149d4af1e803b9651674483ae26c40b4226d2f689826f4c33b86db227a589f7c9b0dbeb784570705b8535d35e3b165c771268232e0684265c19b5993347557d7ebb32742a4337d4060248fac7656de14f5833f32fb94f1e6a +S = 82bd70e07ba8994dae47a4f8d639168e5e9aa2cf70cc3c011482d170efcaa8aae5d2c8e46d63a583c20d9b7ee21e39b86429aa4550c9f2df8a955a43e2ebd3ff99e1ff3625285de3d506a95e183c664374eaccf0ecfe6d1fdbdbd33f61696064815a21e43600fe7bd45830208970bd63eaff3d2d796740fe1917196bcdffa4107f6b143a7283dff052c1b732fbb545d2772fc725cb0f1f69689b57ea25a8e54c6d68bd10026b911134f034c9f9499f001c71e67a1668dcf11e3974c6ca2658a4dae79a103b1bc3e01195b8ca7da0a09923eabb8f7d035598383404fd7145946931cf2f577c3d2356aff6e2b37f4b084c00943de3c90b9f944f42af472a7eab05cb33d144ad0b36c2d3343f67af4c78bd1fa86b5dd66c9edbba788278dc063c2a6754c114ecbf5e12ce76ea97b9b83431f215f2670a5f23e27b1614330671d3f4b5701ac57bb8fc8a4eb33d2203d3a4faaa1513471d94446a6bf170a78389738567da8206f8e2a6d906a428253e7a2bd95b26ede968d6781b5247bdaa067988f671f9049da2fd3e81a9a0e419cf077d54d524fa561a395af3d443ef4e56f217fa5e981dd693999caa88da4a58bb7cf5bd0136ba939f507fca7ba93fb95c8e33837576230a28f2e66ae1c566f480b16f7f3c770128ffac3b2fa8dc33f1455f8178b1c4dde3d2df25c49d9d2458fcbc1c1c5c33dccda3987f50455f898609622063 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d0609608648016503040202050004303bcaa2105477a151f58e5854c43aea16ba8a3f7aec859c767b4c972f6516065230af636d2de691db4bf4eca0591d5df8 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = c74267ab7b27fc613890220c1b77f9205b8a8b4a7c8aa4f8c5f1e41bf5d7122b3216b36c42addb71fd6244de02ac9d72aacf24443a49774c5d6da726d14e8f1360de644112578d4ca1dab4042d561d7131ac3614b6117070c6b34ec9249fbb2c3ae2a1af53eeb7fa0a409b0602402025d869e94356a9376bea0bff8d5693407e +S = 5daace94b6042b542d3ad0dbfd6987222d598febc1e612c89c008c8ae828767cb3248235febf65a100367753aa8c75445b08aca203a83d471b090c4b40eccf1a375e15e6db3cb49eab5db7bd30dd0ad2750ec9eeb09f1ca646f2cd7941cc53c1a5bd982032dad6c022f4958785fa37caed46c67fdb8fd0b8571494a255a0d8e093b79811b013e8bdd0636345c59fb31d1daef1ff7c8d777721cca8b5997cea173c2044ca0b0c552136ef57d5dbdc9383f034daaa20a61d6db7ba504d0ca67d9d3cc8df5c52603a870010d7024d7fc67ff2b719551ce5b1dcb3228c7c17b0772e3160ff940789935c563b72ad97302fbd276a7d17c8d6ac70866d945be4a19b3ed1256339c005a03c1bb0be9549d25a94daa4459ae2f6d3b2b4ebfddc545f76c3fd761016d3a4a79301c6d94d4f84ee9da965f1c9ef2239c6a7cdd28f4badb57580177b395fee7c684b70c43d92b5f5718e3353dda2ca34e10f0a1595474b3f0cfd90ffcd10c3ce987ed72da95aff0d967b582f9c7ba4067b77f728986bfa3fec94cca5104d361c185caaaa1daf8ae9a54553190d54e16c86604172cd53ff7b37060152d1fbc61e54817580aaa6a99ac1e577161c718c6810a735abf2cad04c51c901b26540e0546fe218be87b12929f2aacd48d9768c51d690820876b1a73bf3d8c86fbf3d37a0f2f8aa9f39dc8b86e3990001cb3ce8fe75d41ad863fa54acfb +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d06096086480165030402020500043041bc09c6fe8e745e4fbb2fa6312743e27bb5e82870600e0f80b1147e6ea9f392710548d938b910d106960f7d1989f8d0efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = c0af5d4f3251d02d37abc8770b5884391a66e7a1700087bc714a0280ca8d910fa794df3a27561b440cd54be9b845e49f5571981c535b701817221a54f12984db4f76aa883158acc8dd4d23a1d422b5f4045ce7ff3fd73325ecad5bf2fd59fc5a211d66413aa1ab4111dcf6a748371ebe91f07b511ebdf96b59b36a61d4652112 +S = 326963d3bb01390b62b4dc1326248ba0c0bc44b240e7b01fd5b05bb138777b31cec22ac0b0d53279ddeb14d86ef2acec7b0c3ba1c8e587513279ecfd6b912717d316ec7bb6aecd56004f9a110e3dafaf3f3f9997549e8b65751d1c4574dcf16a0df08ab705289a9b53930f2bf90c0a6a8f461c69d659929cc2b8514f6c08e07c0c542ec8bb2ab42512f48d8c866f4db4a309af0114e6b9ba1c382f48580a9befad7dbc1d9611de97fede893243fadd94dd78e99f43199d76ea3707d6c8a2e1339b534238bf1bcdf5c2b7144b616872c7a08d4d6399228d508d01c81e7dc345527ef087ccd983f94fccc1f5f8db9a34eee662484881f38eca79426ad87f4ad7ec35dc46c835ae5b38b8bdad63515d710eea32b8024558dc1929e704225debd4e9a770706c78057678199e4d006d185556f27bdfcf5330bbe9cde8271316f460efa53840dfaa30cc1f230395c4f12d7e0a0ae57d71297dcce3834a27b4f29a2c8381eeec3ef4e71a2b54ff1ee09147385f5e41fedb3c3df398cb53e1d19c97fc0f5f85f2fdd0b42cf2065fb68b7a2850e065016e9c3b88e4a0d17370cc63f771de00536c57739625372ec08d8241672ce3aac63dc843d17a227a7f6c68b85eb39e4074bd7ed49682242b213ceedada0db1f2ad978620c43aa88325284588a5244f82083c4420572e30486bd40902b71319c9b246ae9bd7d994f9396ff2bbe844ef +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 42c5ea617a25f019329ee172e4932485518dabd01983249189597473b4a6616cc5ba8ee693e0ad1d76e0f0c85ac8c0fb11ecb24cee2cb7358f7593b9fa8b904aec0573eb6d99af92a899d9d0fabe5cb349256eec9797422dd60d7fd5fe73f2cf5ead7fb72fd85e3f6fd284d2edfc5e77a03ec5f73c4c2f420728220fe9e9efc3 +S = 6836dff1bea541916b9ccce2695e921ff27a737ac54f4a5c3b2facee80a8dd3bbfe86c93a1af8da5c6b3a92c445dfac7e215fa9f3d67c9589dba858a223f326afeb8f5d0f92f28ac4e3671c22b5b4e0b4266f776aca928bb0309929f2c452b62d462675cef09388e5720cf0cb99351d44059790720db82ce014d7e795826833284bd4205c64e1330e30e09ff6220f62c013c117ace4f4286cd46e52694c4925aba12a5278e47de910dcdd820396febe5179bbc6ccecdac1883bd408530bde92e93c49db2c6fbb42e9705f29703763b21a8172489d2831889bb060505040940e60f7c5cb9f58327c3d3f7cf7e18ad60e877edb65222a699d4acdcb358fbc87e1e461468cfdc82a8cd7fb1f82e05378737f4aa741a63ddf6039b23e1aa19d94e7087915899685add8a8da8f64a93707be0b6354c8e9a8aefc7484bb45cd0beca493a4a0aef0b6aaae801866b905683c582bf39f9cc0768d880c6e4b331da86506b298c180cf95fa45e532483c55544371468088b4e378f37976c397e09f89081f0f0b6f4ba3be6929957f55f14a88f6beb456b70e6fbc6227e98c1e8a4a6f734c9080c13ed58bcfb3456cbbc217653835000f54956d839d4073571d8a42fa2294df1a747e88af53a16df1834203009cccd6d61304739872ab92be79a4462125ebc8bba909ca2b4d91b9e520d6c681c2f92070f156e31a6875122993e1d94fc3568 +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 3ad62d183432746cfbdac6d9c87148bf13df52e906f67c573156fc407f8d2f576983754e69164298b20172741e02dd27683c2c889bdaebc2caf5df5602b7995f7dc14b1a18cbdba5078a3607c8d7e771550de8c49eb3b752365bade94dc98c0ede585786299a661b643fb99cae388d26441c2da2f7ca0b8fde500f02480b2fea +S = 817ef0cbd8bbe2c93d49bbc09c5d5fdb0c36ad983f0e1f45b41026d3efabad67c69aeb07a0bcffd57c4c6ce95857ab1dd6e786f83d2bc7460366cf051019168bfc56edee99aca9b3862a77c8a9c22787b35004624a7baf963b6e1be2530b0ee43fe44bf21f52e23b2ea0dd7a9cbd77c960d9269bc9efe867f10bab0d27eee85fe95fa90ada2171e9c0acd17ccc6132983276d0c6f1260b8e20ab84ab4eaabb5db220ae7becb26f05e32df93d2a759a9d2d94fa6cfb2a54ef20ea8f486cf587eb2977fdf17e4b65bfd66497aab225254d53cba4b18c9b4c8e30e6f5010eae0d19d53b17c9ba8ba0afb5109dc45f7e39e604f57d1bdfe3a2354346f462036599815578c497a9829be3fd73b4d7fca27385cbe44faabefbc25fd599c3e817a606dc53544e6e10cf3182fdb806441d470f16168237685e2a384391c3b15663cfe9a00f938fb7f9362752e4377217c06c7419a2426bfbf76b503be486a2b90146e9c75718b208c8fc492f47d17e4e8f3ec9b1dd5a067cf1e4ced4617243217518653ee3f30ab3a2c3f95ad15e6939f88e169c643ed2056d594fba35c8e8fcda9f7a5fbf17ffc42ccefac0aeb95cada9b48fc4a9456626ec017b8dd995cab7720cdb7c093ffbd3b2c149cacd7a2328b6ec825376d19ff693a8c8beddb9cf2c67cc22bec90f1d4e0a310d7d7f81582b56fd2127fd7a9c1d3b8d1050ebbbf06be49da1f1 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d0609608648016503040203050004404f6c763ce96f5274b8ea00e1e795e0afcc8a1d1fec8879a033437d0c153b2ef5ed766002b39b50a10f9cc919f57cd0679b82940ad47bc8b5961061fe1575eaac +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 96c824575d1e537b1f8d27dda15040ab262f9416f0f61260032786362becbd41404fe9f8a9ad46b81f68fe16b3dd4b741396dbd209c078e744dfe8705bc012c90faf63bad1eb70938457dd7b83727d05e689ba04012c38a12edeb5aacd10342d88515a46dcbf1835d4c18ab318f81f872772fb54e12199b5488cb58b87c56996 +S = 336a1580b52f2b15e7fe7eefe6d4503fe0985bfcca17e5379d17d210be01e44394adce8d1c482db58ff71b6ba418b069fe15153ffac74b3f7190df14791f8532adf655721a5d113df77d164226b941cabc035853b795db3dbfe64a0a89fa8728071cec0bc1264cd9c7d43b429cbf868cd7e2ce9f5f71c6b1c9705ff2d99f99fffc6bd964e4aa85ae127e074a95e396551418acc46fd22d61711cc4dfd51428130b0036c54120723bccc8268d9f1739488e4874c7fd77a207a28b97f463fa0667adfddb34adeb6f11bbc1ea2e057120ccbae92c3504d14fa4d87768e435b1479237b61178e48232c6884c94f0f287cbd135ddb9629678d7097f8c966d1b74f288a8d307764cc34e3690be4e790c57627ff1e6ee2572afaef68dccaf441575dd5112341f91c0f20efc8a75047672c190403e8d5aeb1005e2040502d7cce97cc8977315aaef7fcc9c5b0029246839134dc72f72dc2e80e1d3d5e48881dd71f6b2accf21635252d82adedcf86f58dbfda3ea1c0624fcfbef191a89a43d5fbd62cf6142cb26c4cdf9cfc0d8c993b3e80d551ec56b29734ba77dcdb03cc20912ad85efc48d314c42b15120ecfcc03d85a43f2ae733fd2decde46e535aa84415bcc7de4203869ff945176b9e7047c5953bf241e3b537a93e62b412cd81591d658e7f55c4bce859bfc56683abea7e6e1f87f807ae05c52ab504f0341d301ad06429fd964 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = d44ccfb041a426cbcea27f0d5e2a77b21074beb5c175bfe5d39a833b2cbcd26b81519cb9d4df980e3bb72b4be4df8bdd56502492f9613baad984d132a730ca8d011e4e54f2b87060bdcf0d24d68cf74032a95354c0e0401238a4ba981310bdfcda1dad28a417f5e8db52ef413e1904052ce714a41fda1745776405157944f4df +S = 5272ca5de6f01c255f59460bf1789ad5fef5cd25345d701c045c3623933f6d44389c5cb6eb3746b0aa75ad49cd5900223ff998d5752ca0c164dffa90cd4a3857de3f4c66e9d3c19bdebc842babc4b0fa60bdf53b76efd35de73230e283a590f4f4a9b7658ab1e1e0e5631534710ae18c7b866e79be08cbf3c30bbe6c0daec86237c439a7f63e57640263a75ed980f5180dea5874e2af8348bb15b833055936abdd01f8e5d913499382496691b6c60b5b2aae76b8c51794dbf9d9e852e62c410e9981b5663c59a0e5ba5c1545643de0fc9397150518d7e6122334246e277570ae2bdc4e84e916096000a44ec2e68943589d62b24f45594f35a2b7197ec665d45c3d9d403e7510f536a0e214cc6e3391c0494c5d52508e777b851157ff091995f4e0d2131f9e40fa4e81091e46cc40c0459a4f2d5c198222f0c7b39a5e2fe86a6f964a966d1e66ea550627d4b21c90cf3beeb8c4901a2ca47ed8b3581f37852f582382922ddf0fe0e322ef9409ae860b251699220efbd41f09968d2787d4b7a79ec4828b9ba1702b5da7751546ef626f2c7507ca4201e1845f39af9d813a45eff6ec0c234ff31eb9c8c2f78a0d70952ddf010ed03279390e13d6ea464171831ef86855816f9eb25c44e94ea5a40a6f134a55197415c7b621c7ae5cb29ed27e9bab16c1b6e7747e1462e64b99f5b8d07aed6c92ebdda2802269cfa3827d3e65c8ee +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d060960864801650304020305000440b6f769c5eb51469bed21e0e25d8eb3b9f5909a58eaee7435ba9dfcc3bddd272f82d00c6c7992f5caacb7814315f1f58aece9fda52a15a6a80a179c02bc194614efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 +Msg = 1fa4b8433fa5d5d2228abd92b49e6147f7ed6c79a557102517e406b26557d026cf06429a5be840ecc0f0c9b38399357860c3ba23ebbd35b377a3273237eafee8a33997d01d7a0048d532820cea0ddf65d2bed89efb05f2b8b2117a5f4509c71c64e6bfcbcd839d5029f7f1863022e7781486cdd41d58d09c90d7061fd6ddb228 +S = a65d94748b11294edf430b91e649a7fcbce5d47ab1084c0dac64033e582360f7cc18c1b7e71f8cfa3c0677505fba6769af39bbadeddf6b3ea1031b103f3fd72f3c4d56ff6a75fc2e16c4eeee8a1d4be05e001fe210d07c1df1e62d17b9d9def6d981df183c97b4bfba226cf88dab793eef75fc99b028100ed522e98de4dd5c26fd954a928619ad6024ae454f11f1b56c0c7f04442bbdf4ca282bc76f7f054d5195a5ca398d06e8f149b0044d310b74eac7a14c2dd9999ea248f9a332b62ef97867a4e4e312305860a8797c5f9bb66ca4fe13c054e55948b1e54dfbad12015854fd4ee347bb19bc2b59930056a712f090fccd9b31c96b3426ddbb16c4cfe130b0f8327fd61e1df46e093f6232cddc3f9b43d8b5a7b8edab6937d869353cc3fbf8d050879b8fd8793912f06a603a1936476247ea140212530397e3ca5a593899198e9d3ca1eff1ba302a0713183c7e2d60a5492fcd8b1df4e787dee2d305153ea690d81b194205a54425c1e1df4364a20082868f09b5d11b5e5ebb77e41b5eb91d4ac73a75d29f7bfba2e056dc8d19a483c4256f68a3f4e80e2f8a801cc1401286dbe15636c653a80dcbc73f249fcbaf4b446e21e9cabca231615d44578e2f8466f22e9b2b03d21e2f4e19623d15361336763a28dd989bd5a912fba53bc4d5ea1c790ba81f5fa21ac1a0fb43fe5a550108a27041c7e854e7aef824a29ce7ffeb62 +SaltVal = 00 +Result = F (3 - Signature changed ) + +n = b10935650754c1a27e54f9ee525c77045d1a056baedc8c1ba05a3d66322c8e2e41689ca02b8e6ec55d3331cd714e161b35c774311540c6410cc3b130e65cec325377ccf18a5d77054afaa737e65b68662327627f5d1092df98c08b60a3ba67599b1406986f441528d2f1f5d6fe5ec6b8aa797dbdb3162876b08298237af81c7004863576af572ddd66c487cf32a82d0f9fe260f8f2681613208aec55723622f50d3cb3bd33b1226d5b5b9ea2c97a2c59054e31536849ec2f0f2597c077e621ddea0a22ddfb1df925c9f1941cd431afce0398d28e736cfeab3dd7f062a65a2a4c1ddca1f32afa03b4ddfd8b7ca40cc0ce2ed42229d753f03cc6d8bcdca76ab7c2703c5ddad08aa9bf9a27740a8b23168c6b55917bd3d5c1c057c34d1efb1411da51ab745519bd92b9432fea8fadcb9a70e5dc3adcd3081d3333507b7b998886e988296628dd7265e64eab557712556cc492377f15a078dcb620a6e7f051a1fb8754efdca3de253dd0aad4205b032659e4a4fb307f074fbde340702b5911acb34737d7834600cf2ac77f62f83ccc9ba78ff911021b9f8ad1bf421430ae0d64916944b504542c0f6263c48e5e233ef1869df1efc2ccf6f4a95e4db2de7b4cb1a992bef6573511bab4bf2cd58e72a0c235f56dfc182df4dfffb69433a5677415f35d84f5125f5200eb57868cce6b74c5833417990e318372c9239a36dca1a0b28809 + +p = bd4e8bb7fd7ef1e39d71de06b0001bdadcc81b0edf2226e0d056b7eea70b2249000279cc1c04b1ac2919014fc3fb8b62baca3e261601fb0a58a9f67f03cd60085b2d43906d36ad014f321012a9bde9617478a0c10201afd53f2207de3648afd1d737afadf7fd2c0b9824d4f66b2c7dfe93390888ac088c680c27b1b2486659ccfa8986c8c23f78f18b5815a410328e629e7440221bffd8ec4722bba3420da5234f898f8cd7e6d7dcb1349bc4a0b665b41d930e3957cfdc88797aee5b2b27dafb5ba0949e3dd892f490212dfd249f4b1d99fd3b72695ee0652997127f0b9b417fa8365ba9fd103b978309d9baa9d401902cc107cb8d2af7ce04660900e3707ab3 + +q = ef67f69838735c055145d21fccb42298642177fe3fadc39070a95e4fc04ff058aeaf9070b4eb2de1cca72d8533bc55206d2ce9f2895b148da67c89e5b6496ba682f76bcaef69306a7fa4fbd41a838bdf0fab3e7b56c27a8c18dc4bf970364dff7427cdcc6f532b49712282370a718b7d5287bfc02c4abc35ccb2eab3777f5e0d8a27ff9ebe13e725aa0a0cd48aee1fa33ea6b4ea965ba42fcce7af3c528a6675cedf4969640f2ca73345dfd322620df9dcf16520195df8232061e2bc89c12de24838f255e7b1c17713ba435d5a351e263350198b3fb881b8ce0acb5aa58b7afaff184489d167c9af21e40e2ba9fa69b44a3854329385c97df0de24dc283a4053 + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = d65a050fc06c9f176a6be7a7bcb0a9f074112ea5c7fb03b04bc2fb25143477741d74e5e2ea06873a6c2676bf255ee6668d57ab42b3f0fd40278d781418b16673bad04183ea5e7490152c620056f4a989de33a8a199363f360f78d5a0882ba0d4731520da089ded812d26b351969b7bc1314b2caac1f851fcc82a1cb0abc9abfd +S = 77e7756da33c3918b94a1faae80f2081606e9646ccf2be6aa16f2b4fbfdb8ba57fdcf61e892cf9b77d60df62c07e56fa34177df466710c7f3b4c5084647bc9c9a52d66d080b3a1d6fac9d439cb6f207a72f70337ca9c357e16278f6f846f7028345dc0ea8139359ad62a103c43a922293afd300436d76daa5a92f940df6f21f1c442ee3d4aa8488defebf29127e11413cddf4471fc5324ac14ffc97403505867105ccaee26c742082472f6dee0d985f05777d6faacb166f34da96057be40530df9b1076b645272d154614fad693d4d5270670a20b71103c0e740114f3585c2ae02a4865e0277a76eb173bc2ad65db5e0a9aabc5d47f903643a1cff148703991ddc4e05ba766712a93d3243bcd714d067c8fb54eea3c3b5e69cef976c8794471b5afbcf7e327f14258410394d388ce095e5a623a406d33238d2c37a29eb1d099a2730185da1b2e295a55f74b555a6d6beec7fa7b9b76d916e9f487547d06356ed9e3ba818e31825e97b465174a7fb8404b7da84020f555247c2f03a407ce5afe07d3d9df9c94147697d0591ed2ff6776ee778cd74c07e071bd8b2260cab2e0eabb4c97af8d5ebdbac9323b0a73a9d93d27a635d8d5af1651de596afd4c9012f9f8840d05e80a2afe47399cefebb70450fc4b501fd69f67867123e95a6ba653f69cfe3cb5a38e3ffd92d2a37fda91c06e59eef42c836b50050f8b9fa808a4a114b +SaltVal = 00 +Result = P + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 7228696b438ee71ee4be5fe548af7423508c3de7e370f6cd416ff61f94d5e140c9b21f4b9d968df7fb9972be859eb43e71d94cdf968ff7b6c61d2ea95f3c59d41d83402c322ec262991dc90ba7207dfde371b8fc1782ba96a7f91f4b22f90ef117a4b2572adeee2966534c13d5bb37294e5d6b878fd1a9348c0baf4d0695675f +S = 34d3fb114d6871eeb6a9cc9960d655df44d2a5c8f1d8bbf1b3b03896f5ba8178c2e92f8c420d537bf9f8e23866c11d0e02e67431a1506b35f97a85ef220635a28eaa76659fc8fe07d0d4f06fc43c2c4ff96f8e27965078c67abcab78faa4299d345ed81a442698ca99d1c0e4f0baed8095dce5d30add437c1f06f79c215cab5ff88eb280de1b75c3f19f8a9c8810143be9e127b04fc0316d65e7cb4af7786886663062d88ffcd0e64c5e359874db6bb63f91e92c14a4f3893d6beb209d4e009d646d14d01dd3a84f445ad2f54877e0b529356d561665e7be8332c33dbce60d0b2075cd88af0bdc6a0d8edc2efdfdacdc5bdb4bd3537f28ee523c1a355cbf94c04329fef5c75726c047caa8119ccc4e9d60f203b0fa48400e07e9270758b99b0fafa65c0cbaf40cd3408716e257c539cb6aee3e171830e70db3a5110ef5a2561f87bf9b56ca69a61f7abb1b0be64d2627d7d78055f4ecec34c9f9768cf2c21f5ce656d069799476ba6c2b223a17dfaa6e958b046658e545ec4a28e2b6565bc320296ea2a8360b6f980d8e81567a7c40a32c82e2576ebe9e2ca68c46239e2638737075c3a0c0dc68795331700cdf2ed1c81b44b69afbbc7776e08ba794be48f16dbbd8d21505d8749deaa470aca86c27314675553afe88a96b80a67e4257c95a57bb3e9262977588717b54814250cce8bcf8e260ec58c6866903bb3f635148bfa9 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414e3a0e0ee761eba5ffabbc08ba0f2fd689e143a3a +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 92e658a7f7bef5990043c260671864572e070d373345af8304f76923f4f4464e6fcd26ae8a0bfcbfdeb73a7997208a2ec8d8bfb502000bc824c572ab742b7e0eef0a3535de554856aaa28d43f1e7af48d9822557a57d6062860f4909b366ea75bba36b841a2741260b0da2079ef73c6e0a0e26654444171ad1ddd685d82df14b +S = 4496155562e965348a09e9a67ab0009c2b74275a209729eba350db82e066527d9294cea63a56ba53718250b86c64d29b327cae24be1d1b6e3eb996e539e213af4739a5fb52970e89d6ffb0e4f7074603ae6bc2afe88379fe8685fed5c2e30183199702b2028ce39192b35ce3a7111573b148ccc6b7bb15c6aacc4a72819b860f3704a0660241a5339ce3ac7eabb8eba25370d690a0c478b3be35f3613e6be74fd9904d32bc51762d9c921276159e4bb5930aee4ac654b51c5c77b84af7f71c4b88714b1c1bf23ba28d3ddf32906a1497bcd86fe2d8a6f369d145439119028c82d0cc2eab42a4775193d7c3db38c1b86c4a4c697d726e924120852dd747da3bbc77a906f367cc5f9303b6a4cd076bfd4237975ec9cef8ed1d637f25ac0ee20d1bfd918db031102913f8258de26d3319268d97983d29899b8a394db559a95f0fa46ec4fdd77ca0d901aebf952c321bf38c2e6e7943af071a7492b5220e4ee1a376c9c254cd958a743d47b458a93d993b3f011d81afcb5421ffd4305bf6385084ab3fd2159aaa76510a0bc20abf5bcb36beabf9e1dce3472961998e6aad1a68935283e62d49334fd1a3e56cac2681a9a172686022e1ccb5a215333da9dff877ee2b38484e4824f28eaab90d2f10973cb67f0b0ff7b32733464d1553f18306eda6cb50155a4047e0e39dff11524f97819f73bc3482df0e7d65bcbcbd4dd23f845dd0 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = d51a8b58c08bd2f5d5cdcb0dc596e5a2999e86d6ffa6fc09e5b9b64246b2b4d044fe3c3178a3cf3286815b58f4d8b27f3c0b3bc11fa4e7993d976748e3cb9d7824d650202b0923a7cfacc84c688a71c5e1b187260f739f0541b0aadc19586bae9a2b2fee81c3b89cd9d57ab1cab40abdb216d3cf771b0b951b8be5c4905f08ba +S = 068f422fa9bb79c8f18de3cc684be48ed59521ad0ea3a36326f0e4f96db1f2380b4e6a8d67f15a13b68ab0aee7a7b4d0166d94ccc1ac522de51052ee303c56ffad6d72912443ac8433c4e10229d9b9b605977bcf9ef69e33006c50e6077f6f0ac5d56cb9ef36c3de96653748a9d720841c9e4993fdde385ef8d5197b8da2c9c9b029e58d5d28c8a4d017556f31d45ec3dafd5f92a99c5342f31207b7ca9574ed043279f0cf6b5ecb4927425e149609009b5fd0295faa4a189d093f9635de49c8caf34200ccaace04c42c2f57136618932556a20ed057d60dfd87c8343d3a1a3b8d7b760453877ec67a535676c97ea65fc5623b9b7eeb5419840a27d872b199686381093aef3e968af7c4faee2e88fe7904212e6733c6571102cddb6d222e51aa19eaa59afb7799b0590fa6114c0d0ad5a4b09b104c3b0d1f31c8e90d8abf26516b72c7d0b1533bc66ce4d0e25d08454fa766522a4278080a42eb51d064101c1d845361d4ba69809d1340ab354f907986f759ca18d62861370fc4a5fe147aa6504387f1a5285629e3fc92b53abaf66d9bc135818748f59902752359f074f831a87fe7fee433a8b564e61b07500bc0610f8f17a172f92117edaa9b9e6f5858326590328cc9f12ef630f14b1459f3e6db8f665cc9be64285ad681f5728bf1b1507a72769f1db7ac1231d123b6cbe57f647adf4956b5237e7f754ff910278de89a7c +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = ce5ccd9b81d0103e99c4bdd8216b4cd75f4063174ea2eda94fc16cd31bbe9057fc0e08f83d20983bde3f6c6b8db9acdfd24150808a92368596557181d445e5a04e91112db2812b58035d72378d8bc00a1ef75ec373b81dc6f1f0a2ed96f302cf2eac8f42ca3df11e6ee678440a28b0dfab2a36eaf35bcbf3c759a71e47120f6c +S = adb58e2ca61b110bcc5697d845e3f035fa8ee93203f12475ae3a81ca0a9820d799724b3323aeee7d3d6e978f324c84738d6b56c37dbd15b71bdac3a4102576886978db6d78a0c0291886e3eea01f1e95565789d3998a2613557202cb598d560c1e158e3c30d89a4add63fbebd361a17f332c5c69857b648813cd90c2ba48b720601e9b0533c6baa740223dbd8682fe0ddce8a6d9bac06931ce4d0516ca1cfd9cb06cad6fdfc1faededca19480c247a39c5e4815e79dfcabe5f4fbb0ed9ba17b4f7e25f1c55ed71c31a5e559c60158bd66ba199bba3e091e20393377b3a4561b9f07aaed7c0dd77d41984cf47bf34359b3a513618c4595be045750d47788b22cdf102d7d10726605706b772d2e773215f52b9c073855018022848ad75d7483aea8a34af5a900025f71f0b46c587a550dcbfa011902bdc870d6cea895640e4c775c954e11a3423fc9e0d6ea4421408816ca066586a37210c7ac8aedf032413bdadb41c0e6ff5c57d4a77f71067274d43ad9960b895734aae6a1176ded2883303e24100398a4cca23dae13d018391a8756adaaba709354b799f22f27d4a5517967acbf694e066056c49da87df46829c1e4062c535c17b72989d7eb045903665576e6144478e8938b0b2fb4a916f9f2f65990b683c49adeb6e6d6ab7a7c29c530217626d1429025b7cf627f72c4c588ae86ac1a1aec4120bd4108943675e53bb837e +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffff003021300906052b0e03021a05000414970d2e4e51ca9f81fe2e46fe8ee73b728122b0eaefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = d8807c9c2e144010d462ddeb70445182165168be1a5f33c22346b6cd81e7e162c16dc2a77ed3f80c7aa76b2ced0d3af81c06f5122ef20d773b548861a7d6f96cae8db0f73f7d2ecd0e60dc05e5a3fc263ab2df8f07755816d61a72f01b165ed1c766af531a1bca9cb915973b000f7d5499dc8efd4eeffee71b21da4188aff6d9 +S = 9e7c462e899885020d173f427cd4e15994749339dce4f39a1916635010d984b6d627da831d4264ae8f929eb66b8b14938ae12ea74e4a51877facfd402d0b6945a299ac6b63ac800dee3c2d5e64c4feea4ded7b3523f4fbd950e8647c32fe9b2eab6c64d74fc90d8318d52e482e811f74c1990b80d07622a35d7ee430c5beca1997f942117e48146413a3d07cb42ab16657176edfea16f5ac4cef9870689ac51edda514099ed6665b289e0ad9071b35c9ebcf06b0517260e47a516ff852f278fdd7b3f54db18bc5491a44dc87dcdb92a3e9282f7de19db80424703af856a361a9c9f685c3b16efb5474cbe23c8f04e3d5c5fdd0ae9dc5d73f9f04e267bb4aff348c55e2139fe554dabdf99e90b0ad20a01c1e02af92fee0d8a22136f8953bf999500a6d1a5478c9c6ecfe123b068085928354efadd5a9e41e66a15d73dd5966eead4d39491ee2d74bb6ee5608089ece479e53d599f9c19392ca064761688317d0d178a627b7a9059093107f727f754fd538e223cc6f01ad991c4c35164394f4a60da9de6b1b2dcedd892eafe4e3b04b99ea2f6459a2dda8eb7ac7020bb12656207470362c0a10ea79cf3d5512353aa87cefadd601f25ae15068049d2dc158c04a3a8e00ee4b8af3a430890b572c414b28abf2aa14c5403a1fd918baacc4f6b4f80446dec87ef2c808697f0fdb8f142876d8b7d8d90536e3119bba38fb4e1672ec +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = aefe857b2bd74d6bbc3d1376cac4aa6df362be9d5d77c5f54a0c336bed58ed9b7d8901b187c1948a885e1c16bb7ecf0130c25a921e53d7d37a23f9f2c8768ae732a01857d710ebb8658d3ab7eac09ed6e7f3c65aa7186d64ce0d895e351ec598f5cc3233c2cc393f7b53d520fe91ff36417b69bd9fce6ef16f514976db5a86f8 +S = 30de099e81b7207862eaee842f7bbca8db96c4348cfc148da9ab9bd6479ca79f09d9cfbeab93c20f58351d18f7b88cba4c1ddafb46ae5331b75d216cbf6fac92cca17f2cf7142cd42007be50a24a1c53ddd69890673ebcf6d476854fd0a5f76e7c53b40890855ac801ff2088e0d427ad02d8e43d499a06670ab6e8b43f661c16295f7c6b04ac5494ccf27bc49b5c65233af02d6c15cbcccf40aca45929fc413c566bd07616748b9e5cc8562879c2782c1345973f7777f56ad0dc290458b6f3b5a88f160a8eaf8ad0fc394b283c1acdf9bcf2eccf88164f1b868d07a05b7239e4858c2f3d076a299a1ce032ee4967f7da07198d3ca26912e9ad2db79ea8f49f21544e82f6e231651805e934524899ef854255998c1cc59de1ae49e482ac801e3c678626b3b79bb6be296af03c863f89c73a87bed864636eed84c0a5ff05cdec57a3ec76071137fdb3cdde2c4f03c3bbcffeef28f298dd13fe669396e8fcc3a478f4f3793693e8183d96425ebb92f41ae373aeed30182f8a6bbe6b3440ab2a22ad0199bc59fd631e221223abd2358ee6b8e879b2aac64fb41257fc5983ac3e2de5386819042832a8bf53313c0d77767d53a148bddc46638acfd626b908b056c71292c0f9d1b1ced4f2d2ae70e70de9b3dfe6b150314225f21c03b8b53baac3432a72767c09f360393feb18854ea884e8326b94c225d871cbb003bb94d91a74b358 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 4793168aa3ac854a7e0bd652b8a57666d96ddc389aca257da748fc46a38ebd8e6c90da0fa1057d5b621c6f27576a38eaf42788a7fb9bd50642d346aab698d0bfa0a29fd22708b7e616fbdbc4e0b4ad92e2ab18a7e70aeb9ef161c6a9379b3a286a312c7b3c9d7a142312e2d05a6a1f872a6054e267ffae6c3d5a45ec2d7e44f3 +S = 9d2457bf29a45871f04f476eb7a43238d3ddfc7c61fc2ad160335cd1c42ae0da5eeb2ee10f2528ba1e645d27b306f9e833b86ab62b1c4785d9249be1ea9e83e80a5b3a774f2af61d6b536d7670833bca21406cf5dbdcbd2a9e17b2679dd33b026351943e841a7ba4fa3f18e2e278a9db180757021fad06befdbe75f6c77a36518a2c3b88b6329849fbb1007c7ddb7e278b64e319f93b4713717282e5845a168b7825b47f23223793a7a93adf68d5b83c6ed2b6cfd850a8c81589032047fdac6fe091e0369a07919329845612a797dc7f9adfab30255e672d8fa8639a597e556b215e83115fe2268f1c9870b1ba0caee15a26c45acac368baff4018eea4414eddd86678e30d2a46ed879ed6795641af64cdae0f94686c134e1f05dd4f59936e1450a26f2927de6c44247bdfceba2b14cbafcded775da0fb0b81baeeb35e52fbd44d7a4668fb4c832ac0a9c622dce6889a1df6d15ab6c956dc4249127eb7f1b45379e56ca7caaf89617491f5ff38daaa5f0d58bf8eb0138919e3e9bbfce08861b92df0124647bc175bb000d8d0661c71d27294dbdf1112d1461081a931c036d5b2e204e94bb3a31502d055cd74869fe7ef5ef78657a194b9b4900f8882c25668d5e1abf37b038a716a2735bbfbed06b2b55b514f24dbae2e570b9b6164707fd4307b7730a48d3395f372be552402c7c1afb94516294c7823e4e295cff2f2e866ed +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041cd79527d7b3e43885192c0577d81561869ffcca8d1a7ebf268ef448d2efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 8a64b6cc5b6a7947d76c4f7392be0e56cab7831b4a04710a8e42d7b828cd727b63d2832125acd2e21a6df3920ebac81c9bdd472b05157d2a6230d36ffe5c91b3fd3ba0c6423594809012eafbefc88dff52919fbe764177c20dd7e6231c52bffda2c696217aaec70b8284bb15fd8f66ea36fd143c673166bad85e973c4b550441 +S = 9d579f90d7339f303ac17951057363d529d1b448daa7d7025d93b111aeaa5a1087a7063515b01f30d245a6d27dc2074a51f33273405f6db2ffc466d96b822b1224f07aa8075b9abf044ad120eeb39b2e48d5f4c9f7aa1657ccc639873eae8b9218f3e800eb560d5a04e2797fb8ff3f7c320f7122eaf227febf6ae3a8e2042074b7d22222be95ede069af032315fc264ea1a85af5de920f1ee1ee3696850b581f2eb4c342d5df7aff1ad5b8164f9ec08f77e60c0afc256de6ef1a18e1e113a60e7b5ba8a0c665c0cbedb4a56a146a1662c8ec88d5796e9352c36f73a5f5845659a0711c818b0b4f7a20abc52a31474f8a51678aea7a13cd3d361ebdc758fbf90af9764bd757c7505b834105f0ba803f444f4e17310fbd76d4ae2205ab134a6134819ab329e1a58a7382624ddc2bb3f54ef41b6549cfd1158a3c363e4c0a5b3474dc75baeb43baf99df031210be3a9ec4c4e910768715b4763b4f3ccf60af91984e17495f4064cdeb4d7b280c8c5565a6c774960bf2c71a917b955f258eaca5b0bb9f48de529b258828c138d606b4531b7f621b9b9c1753db014e8202e94e8ad10c18925ae170ec08d0a38fd493f022a618bbadffabe015ee21414d893cdf20226330b94970d2d9ce45bf63a664febba1cbc3d6fc20ef8f2283265d1fad429bc4c0c010022113fc81bafe06afbd7b6af26f369fe526936d233f5616dc5ddc7eaa1 +SaltVal = 00 +Result = P + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 9186fc389b58e4aa051fc5a96912c940f4c0159780a5062300fcba1a1fd5d32a2467776a19a79b912c1a826655e780773930040e4fa2d661414b9c0995aca3b58c10dc204a1c254038a6cac1a7cb4cb1b63b617d75d83b1c4a800d8a9426cc788f28334278dc0921f16ca6a2a6e5b456318a33cb3b6ebfbce4421685656bd5d9 +S = 2e7a8b6a247395fc2c4aa4f0fbb4073fc25923bd456da34955a1fbdc66049fa20d093818d0f65611dee0ce14d15cabf313096d629866bc3b12ac8805b9c0487c92cd5500bb5f1258c8769bcb0bb0ac0024d611f317896c472cb9fbe100a40ee6910331e77120bdb6d31603774a49ec63fa0d5a66bcc1d21caacc647e4942efaf53f28bf4c8685b536615ce951ef1f9b790fb1e5e423aa581b54d3ea30b8cebd8bd939f17d0bcf551bf36d3d0080d808291cd60240aa8a6ce963c5688da23fbb992d45a4075feb1263310cea1148ff2ef382b2fc2f96eef811b338be205a0791adb7c07895dec70d75ea4f6a3d94b7a9b072be6b5d72f964e74decce749f3d7ec84e929a1db42e7451e50d50a79631a44ae1dc38eb4e541640b421ac93d33917680888288e063011d80fbce554bec874b0a4d4670210a9fb9f73858e1c0ac7c98d01b1065f2e8dfae52ece1a4d3fdd46d48b1dd0d77bff7fbdf899672c9306cffb4c070f83551002dc564307730448b34258e7ab7a0db18250950752636e34484b7e9063479b2266e639a4a6d3bcb3c9471f1e466c5339e10007751e7392b8591194ab85e00760debf22dcaf83774d1ebf59af46859c264bba1387b6cee391b131b9f633bded7f1dddf7a370742f40a3ed1ef7f5a312e5e26077109ea298c8932d4abd003bc407cab7612db67a94840a381ea7cd084e4d1825eca83ab84ea7043 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 9c8697689a09da7917bd79af7bc026c32837849ff5f03a1ede464513fa45928cad0fcc581e7e73c6eb0b2eb01cef62b8568803d251fdaa038c25e86840a5db799259fe8f0cf645a44eed6a5a0192813f0d7dd3500c30e9bcfefbe7ea3e1d1cbcb52cd6164db77b9aa829d5b613f0aee1b5df9d210cd11fd19b90e9a1dcf57dde +S = 5cccfe2cb4098226ce3988f1fdde318bd67a4488d48c8dd57b678d4808f0627010ccda741f0420ff14324c67489fe4b55356b5fa14219a6484331cb32df6c649e449d077d35276e2508dff31a421357befdcd05049fe9f3a19fc2b65f7b336e89e953414c708533bdd4c256f6541c87be7c32c2d6a34da805c63ba836dc3ae5ff01f4669185cdb2a57054f2d5645b4010075567374fa60d06dcee10595d35c961e350604d7423e5beb754ae5f34d3c144526ae2cb9583eca938da7c7b26765d5d2816a30bc390be5f1325f2eb9a934cbf9311911127b91aae4aa4c418192954bd89ebef8c54d575248e3827a38ef50486d0fc2ce1080c0d8d750c1bb3dacda49cbb95706fd4af5a915418131f429f50b55de551ec23516200bd5cfc31410d74e1ca7bbf79180f3de84ffa56de13e7f6651928065abd8d3bac5d18ae6e3e3801f102ebc7d08c20f9e9f591351e03c9ca3f6d12ef6bbe356916467154c30306e0519b853b4d073f10f0808a7e2dc22e55d4894c100ee5ca7209e4eeab9a346defe83d0ac34699c4776e1c63ad4807746cd1c05f4fd0f32c2183145eee8ad6df8c16aa00c33ccb871cbe373ff04bfb064bfdf30b8b096123e2e137952194765dbde4d12fb846e9baad76f1eb00ac0ec2c44945095eba3aa812a3d33b96d1a966829cf4ba7a98e8c794abeb2152237e8a261f014a19c2b110d1c6444f8fd8d69d733 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 4eab894093e01b38e38a8fc8b4d6ada3bc337ad1b30615035a9fdf24bc6cde30b46d6449afe8eb08b35e4411a1bdf1eab7d7cf0d5813f83b1063e714d376dde5852e84c1c054d2d3d18b31f20382dd76216e8d4a36b8554397f2cbb023106933cad532cf4c8b984143f79e94648c3af002dffdb3d35bf5c2f736d32236a349c2 +S = 96d24cb0170440b5a493d313a500c9d095952899b669494cc182f0616d0da2918f4644961a6480e127459f63551bfff6e72f3ba3cc5bd8f529c8bf9e2bb90c9c12e2e70448e4ee1923ae1e3561fb6b5bbefccdd9634903bea982d9be5521914e8d70a51606cfc1ab9806f68487998ddf94e00af91f64b7dc739a62d98dfca35ddf4ef4f2c318b3b5dbb58d0b892fe0932d48d4d8ce0f88eeffc9dc5b8f4ddd9f493a3b03c62679bf261ba8a3e9c98e478e9cc74296714a0e8d16f0246a1e77c48c6ecc43b4c0aaff9a04e6594ce508d4185ac5e189d2c0a124cde1d65e832981dc49a699f9c6f978f0949078be9fcc545d33568b632bee58999fe83a2670d24c03b8f306385674fe3120be26e12325abb051514c95a60b3369d04ad92b85423d7da9a06bfde71265fcf8c9fed0b320909a1f4c66f4b5b6259a4938983c8f547fdfb630a64779a5c835d82c5435f60ef8887ca47fca7767a27c267c9d1efc09018e86340f4ba3961ddcefdd2bab540fd9c038d16ec723b31da7b54f0138cb54aa979d726c96ed2de5b4cd238cbc54ea0440217c87667eeced158009580a66e7432062c5cc108648cd6e52e2aef481891cf7963efffd5f2c5d9d468ea32748b9295bd6d64ecd8744b4a5d44baa2346b2e23a88639b3e6de22d58b201b896bc58c916d748563d0f68d90819cd749f9218f715a012d0e7388dae82363815e389033e +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c25980db8b2660bb031224d824ac443d7f673a16ff6f4ca64774cd52c +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = b49b676c4b56eeedca153f915c23079f3e9b87a7d02b4565ec1702e77681edf234e716a3e0ed25527c5d4cbbe66c7a60ac3fd22921ad5b4eb147f97671959c21faa3b74378bcf431fe7626c11def7eadb455033909ac3c1619cb2f852da890c0aed632953a4cc154f768b3eb28347c50fee7011fb0af5085cead8e5cd2413097 +S = 410a01190f07def9bbe6b2834634d4f84c4f626e9e286d504c9393dcc751b76327443ab10e9e9da673e668831c231050b8c37c6fd0a92b814924ee73f0b6a2838c7c6bb39f02918ce05a701f92e38680e8c43c75a57ec2fc818316e0e32b85a5126b2ffaf9340338121379a57ea00b1529ca11cd5b6f444654ebf079bc44e3bb487943580f768b2a2ef9a31b0cca4c0c811124e1492b32f4c2a393bd67335a310ec1cb4cf908613c552a9dc68a99f2e633475e5f24c9140a813ca1539f63c7e241b700f202edbeb1133a043d61e93baef9f3a4c0f8e6cd14f9c2a8aaede1486e0f8da8c19b5a2147357f6059da419078e631e48f6a9cf888d22aaaa22073a896bff816ac5dc940b2383397f76255ae9559ec0812444d47f5b3205595c9db1a74b7dd40c704fdfdbe786713a3b79dc52b0c882bbb8a62aa01d8569966ebc00ea4fe5df212ee4a875afc85f48464cacd874b7a63f705cba529b43a14c483032d616f7b965f9784ec1fda02b05a5d310b11b4df17ec35c828b129218d4158dcc58753f5e208ad8a97e32451da1fd591101ad2f93fcd1e6f5d6fb7b468da1937fab4ccc8e9f3e95a4160b2055e8634bbd0798bf0fdeb658a435a21028fa7cd4be555767573e09d5053941aa0814ab314c45bb94a36997e576a026d017ec7a519237d82297f15c1906fc5866c1a3f6096ddb33576fc68e39c6bcd8f087355a12fd94d +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004203a75e4efbd95ceba73b7671c870d5cd4613bae5fdfabf22e8b5b18fab56f620fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = b31156951f5d041c1a01991b23102d5bb4acad22c777804d994a6a9fae2ab15915777f0bed6788a928b3ece18f905fac06e1872412aba59598c978d6e8e15fdaf996bd82f6ffa1b5fa58a7b319f819a69f835a7b9c6185efa06f51edc3f43817e8d6d8a3430e996819599038c730a37106fbeecf6d82668438a4bc8b474b8539 +S = 9bd1789015404f8537c89ccb750e04b5fdf82b0daa5d56f40ae64459aa23931ee5d8812cfd01102e3749024a881d3e7a13269b8ce17cbe725cab71c53e218d4b97d4f1274247b112a4376fef4686ff0ddede255e8b085d763eedb7f17eddfded5bbfb0121a3f4b6d47f1bcef7aa871817fcffde3f7ebd75c00c5ab1f6d5b2a6f5a4ecf92a9aecf902711572123eac011bf9a406bf4da6ee6411fef5b82aea8038396052e3801381061e5ac04b8f1d0ddfb678f28920fb5ac471a7046383204d5add6bbe78b9a7c9ab1b3f9b4b5984bfc8a03794075cb101bba0aa2fc170cf6da9401850ddd86357b962582f9bf0e174ed42ce101692008e2ecb51fc1185be19017a43e6bb08e2df7082cc9221895f159eefefaff9d8f3290c9f76934d34882c97989d4afd6a42f3815f7d474a7d020c797c13a9b4786d68ca8a700fe3e0abd1df9563344f0a7bba30d043fc5fc1d3d585f54efaa45cddba963383a0a1f979d48e8ae4fd633ec6698ea4f1e14c6fa2a7f6024524e6db1b0b66160398919c4faccd105d82c54fc98335b531baa9a7c96582ae05be7d93b0fa3e92fcb7a2f30950e3f31fa21270882d7a0e75cafc87fbb387bff937d45be79e95d973684a9f2b486f6649436ceb8deda18aac63c0103c705361ac5b318647aa632d98edf09c3ebba86afcc00f3ebd27505b926a59f67dc8b436d75c5a449e13808aef13e805c35dc +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = bafd723d8ef5602cd03f8cc4f54c398a7a6ff4277a2cc9c77fb2b6bf98a66072ab2205750dfeb2f1504eb6495c2b56fdc1b7c2cf4c5b4824d953c8ac676d6845720d881d7d75f917ee4369711e3b22a3b147f58a23bc70c5a4df586026a853afb4c6e47d05e29c6751288f8263040644f02973a127d8aa74895f4d21fbe08878 +S = 4b5029ded3d15dcb29534fc7f46330bf5fb64ebbb4602874e26364aa52614fd05218973224b1936af01aae5990bccbd92c2a6d20d170acdf782020b2a4ee8ccf5fb9402838cf0017af1bb0e2b5cd69c08b2f4ef222f1340972d21e3218fdde4ba3af10c3baf88883698897c52c7b34d84659468400d4d403355d59f1e21812d8304510dd8bb2963c47d91099dc36d7f0e19f69cba4a83b40f49e332d543c7489c62fb3513dba94e9e98fbcdb2e8d71ff544b774b9303b5e8ab1102e4bb34cd6a4839fc007a5031d87b778e858f20127bb09ce92b96c149915a87a2829532c3608d77425ce38f2697df9fa992baa90900e85bf6eb7100ccb6667e093b376b45230c6ab901de3541fc5dafd0cfd9abaabf7d88908261d36f1146757189f51d167a7294abe9be9a16028718ca3dbbab7e5d43ecb428c2956cf1d44c3e8a875e0b9e3c978fb489988b72f04a9cbd06488162d27498b52298b7efa3aee0937cb0a03740d82d43e9b108b0fd5e80ea34336fc5f711c8d62f74011b893d41742449ba91fce88522cc76208bf901fbcaf84e9662ab9ef109b63d03a45b7e1d4075b2ba5323417f675f61c915dfaed6810f663bffcae467bc6bd7772103a0a1e445f2dab341025ba4c2bfc93ece19c64dde97ab7be7c00f9064bdf2a1fe7c4af045a2362d371dc30e26b8e25bfb258c4b479e5109baa194dfa4382669b0734f1b6ab63c7e +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 65d1c1c5f2aede8f6ef03b53d0ffac64ae6b9666b18a000e4763ec2997cae7e0bacddf3a284f35e270f3132b2d3c005135f2b10213c7221cb83ae6b96dbcbc690c1162be70faae0e2a11da7475f420186da586b07b31fc471490a43da3cd7190c367f359b2f6719a0211393692703441bd4ebd7ad111b316c32dcdc021462edd +S = 7dcd0def685ce0d0dc10cf783ff7e71f69c18d7edf9e32dd583d46201d961cdc1f8381b5dea980ef331ccf27b2db4f7bca619b29c92e04284b14c6c2ed9bb62c323ad22130641834a4fd703dfb714d8d17939b34b9bda15a018b24bb596de618208c65feb7c262b8dbd4f6b10fac674855b5bd1fc15fd1faee28e39bc495867df3847af4c2b8b40bf3e5694c84ec4fca9deec321ae730ef0b10329318e34331e21ae5bc21bffb025821881d54d9a3f7adbb96fab78f1aa6392fa4fd8db78bd3e2bfdef787054c9c85cc2e07fdff85c48341d587b7ff55f9c96e32ef06aef9df62d5f9ab837f3538d822f862120d2e4cf6abb43c620a7cf08a8a72d3d9dc0f7d02d4c6fe620d3d43891696d7ee9731fe448a12070f573043378f3a2acb470fa7eaf01873af3deaa0906f28fbba9fd4b5b05dd806711427a36fbf9d82f627f1620f9d48fc10c2d1f32c88826faa6f49ea6918daab391079c37a76ff76a6a8696567b319c3adbdd0ee5c2dff7ea8411c52f719ece66297797d3ccc99de851f14cd061dfee6288766149dbf4df8ef4554848f22e3d461f3b9eda7d7cfbd2e5b60b434d86507ad1e7718064b030d470307c22ff18439b2ed3e1f757eede270f4ef8b6e75ce824d0e65f02631ec87782e7b4b39bcbb152230c93087676707206fd4966a4d7953931ce284eb7ff9d5b9bb7a86ad7dd561d334b0052a6a23b25ae9a05dd +SaltVal = 00 +Result = P + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 01fdd22335a45577e5cc758f73df444818c364cb28096c6197678e88bd687746566277bdcda9e200ba02b625a95a7d9b1db875bed471efa94d9bf54b88c32fbe0de308d32f8e0cf2926e9421ebf0a662073e17420f6ef2af0af81e0aa36e3a7d2c67cc8fe4bd9bf575f859abc1098544de3c907f5f683f1ad66850eb97cf602c +S = 2369b3beff47a12b51b8ca1d8fca20136ba94bfc7c16ebe84d322bd65d569af515521c1ab131ea2afeb2620c823b1753a28d0207c7b9e97eacb303a62da587a7a0417b75b8979f492dd16d5f8cf9cf181777f25954b91acb34c7e688d60fc78054d496ad8d6082678aeb7ddd87b02c07c3fbc627ff44bd89d7a151a4ef01e0a9066e19a2fb6271f0a47d7409fc08ad9990e5fc9fb297ee72c50a39bb1302273cf7a042a85e44d48548d859790cd126fa64bb72cf40beda6b651c7e957b8cbeaa7248de8fed106ccc3106ecc1fd0f91584dac294e0747032c854e60dcfb6ff82b6f7df1ef478a69978a558df0b1021fab6d84cf9f76ce0b574768ce12f5d3d44cd54f21339f7189532f7e960f3544a53c70a7027b782089904ef763bfd8d538654076c822fc0df2b1f7cfe297c9f260371023011ef3bb191c0772cc0edf5aae1897e2314988b1a10ba503907fc1b49cd675d766c65a12bd60bb7da104d7fdf9f2987dfcefcd9a27caeb56d2a564b64d1e86d95fca84e6413d1fdf716595ce476fb8e3c3e71c3e574c5222e706177da384a3c21c4f1a418a799513ab32a0c315916ddec5fb80139a7fe05624538be2130cc26101604504714ea0258672049f0f432bda7c4fcde9337423203e1d6323c090e11668470bfd4a2f910ac5c2c15739f3433e6d38fa8685d4ecb2f837a9282ad8c110ee083daf05b0ed7ec04f4711cb1d +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = e880d3f9d8365b9f6e1bf535b95344a882d374417ec91227c73821268de36aae096d131fb3be7343b5a9251c9fcb5be15cb67543654fd3f43474e76afce28ee19756a09fc0f3c57b82e48ba0f042b68f1738d863316521591c81778f0a44c90c7983a101669df94ebd1550481580fdba9aa2c22a4ad4a45d65a8fa1d1ed0c539 +S = 486292eec1aff1481ee618d78c8f28d59aba6cccd74d1d0e82502d1b27df2871f55348713ac01f9ea9dd6dbb8150a3df926326dc136957f91dad72104f2327b19d3890155cd5f018464c7c2c4c3509b2f47426b119fb124046180b2ec409c4a59da8098baa59a97a100c7539785d893932b9efaf2fe5197220d1706b96ce89911883cf50d96e1f8290bd320f47ed916f9254b9cd4be55f85dccbcd0c5731b2432810182ddbd37ecbda7229e9e3bf46c7af5878c8ff4c96f55bc0c46b57a88f8d5e756a682bb279b1672d43edb783b8a4eb4c25b42702dae46db934af12b7fd3852a5a2dbd307e4730aa1c993f5054152547a8a76ec07d47e296fd55b6d405481b9283d4fa2d262a38772b10da63286f009208d6a98f4174c2ee64f790dbd47c2508224d0a96d3eace8938d719ea730f026b6e7deb0eddc967a68d78b34eb8fb3138bff69d484203c5b7c00bfa230a01957911f5589226228d16080003fc1f7b6d544e7b2a46f97b70d111ee1d846535a84dfd43c2b42a90bfe373d9319846bc069cfe2ce7a23f41e0934c97b3964c2b892dc2f66231f8b6185ef6570d4ca31841cf9b562daa5914d185aba76ba58d66592f3237954424b103dfa20268f049c9749330084d007f7c2cd5405b1b1da06a75662f4f7c280430dfcb9bc37bdba64200273d13c319ad247ad7e20ae26920767ba43b2b1a02ab22b188fa5a12108d170 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d0609608648016503040201050004205ea6db376f12859c355a917d06abfb3f5f97736f5bbb23f71ec1de277ba047f2 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 1179b364278cc399916b066e7ea2adda5701135fe737fd3cbfa320e3d966e3ad7bbd67cd5e8ec4831040969297d0b9f3572150cb36940c9bfdd9abb60105bef904e4b0b6569004f13f42decfa269c54bdaf9a72be8061d32d091f19840a2deb77397960755bb0a4ce81ae50ee694594aa8311f6746b4b96b0073fb6fdc65c951 +S = 96c8373de5bb82b7da57e144e219250dbba46fccb74e1c325e3bf19c16fd38e2a71e642fcbb6f0fc8ef77739ce1b8aff04a967573b1bc71c894dd5bb29f3de66736608f4f4383c0d5329a2a7fb127a243544acf40d245e2068bb21a8dce0b4d7e81e165086afa43929b44e45f3a5d77d57505a86651da1dd4fbe0fb6f83b37423e670e06c810db19cdfb2d1d36c441903affe00f12078b229cb368ee5e63c451ce391f1eb1161076fcfb9dc2f499de5a6b948dd2b3dad0e6cc1ded8b27129197fa0998d6fcd117c37cd4745d844d6443d0e32a7d6cb34510d1270f31b25f7f2b4f5deb8bb94b7638f058a59eedd80837beac603775c67edf03957a6ffcf7c18c8a376a02bbb9eacc175904c0b5c09d29ecceca5ddb3d8143a6afbd89a1a3b372e2c7eebff1223b1bb4f1a26c4fcb6605f1326c6e4a25c9ca7eea8441b0495f53b7c6015fda720e62e1023fb039f1e3cf1ae9490f46ff75e0b5bfcd354f91e0aca5a4ce22e64876002e304bb7eb1212171225de212e0ac5304907bc803b61066cf68083832033f4902cda8e6ef109c638346f0598fb27f38f2ef130c81f78d5721b89b949d364f0336e3b4b982b7213aa7afc9aa35f5fbad2286f4a4639cd981c7908012b4787ab506d3bb745c9a8232253d59c24bcd60f95ae74debd5967491ad8b5ae564a09a79de6438090bea658b232d0dd620e548e020e9971ed4bcae5aa +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 7a143960d5a8c615dd58a10ba92eb257888befe939812d105f7d36412f291b146c90cc8f9584e5a75d3ccb045b42f805038d9304d5e944dbd4a046a63a53becb6a294b38262cdeec02efccb918742148fe4e385df503885c63b4c10d8400189c5c25dee4f06858ecb5b8cbb2498ed6286117047d0395a29df503cefb75f7d18e +S = 5d5f734d2700f3dcdf27489b57adb3b488de71bad11e6146dada53b80e4b5bcba10695996a7b52f89aab2f3ff43c17355deea644c2ac94fd760dc45aacb4471137a93ae4d9c4fccef44742682f0f985f26da2bc70bbacb95550f99b9003851b7a998bb1535218f7e47d41c52b79736f3005ebe8f46c5d4fcda4c7ae36bf68ac8c527d8589bb841abcb6d0cf12a797622c4275548abfd2c46d35132e5cd631da7f16c05129fbd1647a470f73c7417ac85ff85e71c433c849f5123353e49ce5d6bfbada544e4aee9887262a8c51b5cf6ddcfa15aff2315ad910d74e92245945309f71815dfc23d4b830536f68ad444637a808077650590407e25923247aaf53df43fa90d465ee06d9a9a5a7ae86d8a2180d70430e4916e7005ffb4858712edab095f8a691e2260c3fd56a4311dc25b4ed8c4ea0e43e4bb44ca26ca8ef674019218af0559de44bc0cc5f9463575ec28f3fc9d7a4d0e9b00972044b01187ca06d0dc7f0c5ea336c0e2290e1367d12101f293dab4139124c217cde848e7e4a0f15b3d3805767f88aeec07bda40dd23826afcdca5caebdf54c32021113d711b6bf07300a2ec7dde75d550c93562a30e93810c9ab3ed830a719e02df7dbcd62c4316692b69ae722a01c462e5cbd31ebef67602fdcc9580e6e326d77a4f2a0ad079acf2c2592748f9dd7c7ca7560e4cb3e7b60e9906b8bf02fde02c9c5e0645caed699d1 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430fd72258dc3162b6f2eb1784384443649d457af90d1c6bd30c443b7e3ce562e7d7e660afd677d87d01695dba2597a886f +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 8b48c7483bab7109f4d05b8cee9338be36640bb068fbffeab94892013ba9f96c5d60c093b144b229f3b6f8bc46d7858ac0f9b197295323fc00f8f582bf0a136f612ae4a020342dd883293258986d1eb07e33a4d42735e7725ca89783026f5d219b8f7a9810e3abbfad114f896dbccbd778fb2e90ea0a11f4d640c22d8b41a127 +S = 5ec4ad5490edb3c268798a03c1fd36d43cd64e6665ede2dc2cd77d833f15edb7b836fb7c31a9a6135b4ea1c84f8ea7513883d8d38037d7f086d50d69fd730fe300b5c0090f4c7cba382fe27f7ecd56a0df98f6b9e656f11169c717fe8636fb2cc6ecbd4a44ea73f91b9189b640bcf51870ff97b23a4dcaac6e4852a8862c73f80f89e25daeeab317dcc570fd7503421989334ed729d453e2b372a58ef37fc773b25d6911aa52a11d516d1011b052c0f9f33306965525c4605884980a2ba24deece8271d65c1623cee181dba8f953a577d989e1d7f6d5393920cfdb9361ec22c10bc85926cd37f3289b1efa6ceeb78e7a1d1b54be2865aeeaa9dddd4aaa2c72353338c247411463af28004fe154b3e41fc88f137c6ab9c240e98f0441237111f9fea9709f41b45cb601d91ee24725a62e0f04a72aaada19b8a25da14b86fa2a5c7f4a359fde437d7a2b9b6553b6dda023e03d3996dffeb8511eb67959c2c647e28f8e9c0c17e412308105a10c0bc4d2820c7d6acd718c1ff38fd1e27db4dc07d2f12f45f2eb8f414861bbace017c6bc4ac46f815269f68212e1c0a3fca93622fda40102194efc58c816146048d49af8717faa6e58251db269f1fd075816da19ff5a5fb0a9ecebacb276b3bca5f6050b33cf50e065320fd703ec4779b3488f1cacdc6a8d469e9f0b5a97f7632efc417bc9efd2ea18d768b27b8863e753588dc3a5 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 9e1d1d96ec18b95c118a04d5d8dc554d705565e87ae1048961110af3ea62912e0cc2612d0150acad9d64fc60dfcf694bc6640f6c65b7bfa13a24f5c5bc130a1c337babf1cca58a7ded33530bc660e25a2989b3439bed9a9babb1b45b82279dfebc4fe32b769ebb94a8fff31eb618284241ce39b3430bfb415bbe2ffd6524b19e +S = 728ea547f16aac9bc1449a5614fc3612292831c3596d2897ee8426c04c353f4fc19590bfd790660833fce2152b026327eebe9c934aa8db566bf63938486bf8699bbb6f2cc7882ed6e9e9cb2d3b0647a5355616604576b12d26123bd60732b2e240e9015a7c4044a0ace6f18d522ba55bc9bed1cf88f94680150d05d6a8bc58e74862f7588993892859f88c92e6516f02d57fb4475a4c4872a211ee03d5152b2111ac0f46e9d826f1dfca27a1ded9888b8a573e6702f116475a93cb2d7e6301ac8742f3dc2c48403e4205082b7e4f8fb21b814c6f94634a50e83e4a3c0900906b162621360d506eea63954581771c72b2abf6bd5bf0505e3a8329ca8e1af6b497ddd7695237fe454b8a06498e4308c0b7f79102ef07977932a57927e2c4dbb3b1199ffeb33e244f536a19375fb5ee25279b425eda4693cef0a4904f8ace80e7a1916740563e4fcc18ec4356dfd8f351fb3969b704233e6c877ce339e7e38e98e0dcfebcb0668dab057171e643b6669dc187f9ea8dda2eaa295b8f88a8ba8f4cfb579d5d33681f0a306f2f20821b67613e18545059b2f6e8049770fe4b280ba849ba38dc6e70949cf6ca160910653a7e3a2c36af5fa1eac778216ee33a60e67dac7ceb7a35cf6bd926e1a16160e303e46afdfa28b018a872f205309035da90752c179f8d4de48f671c08a6a43f7bebd4c49391514783e6989897fabbfdcd87f196 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 45036afedca29e7386c707f029cd67ba4740e7eddd38146d8be5271ef46c895868f19695c1f5a26d8ae339c567e5ab43b0fcc8056050e9922ec53010f9ce10b869860f88d4fdca375ecf3a6e65fc37351cf33aac75f067fb4588cb8ba383e27790e95c3dde5f20ba4ab49255ecb8117ad14dc44ae6c09790175980f7b930077b +S = 634e95db19d75fdb681e468e2e9f991ea38bebcd5e44717148be6c79625136182c8c3b136f09529d3f95e42d4da796a4b9010fdf3d3a483e5c78ccea3ae200a382f1c690a01e2f450dc1128c014f533bae31237d48890a5bcfb3996aecf790d18e6601d9b12022d7f134b1243965727a8ebc1479dfab096298a116440818aaf961ed9aa730e3df72f7d115f57e1294ff53549161b66d6f15f3219323fb067bcc492e9320c7b706613cca0ef030aeae3fe14d04dbc2416ea6d0ef89ac48e0ba83c90e33df7dbe215da1c7c70bfba0cf1ba2ceef1900c76c9216d9c5db17c9d3e2401814609defd932c47b864a65e9c30f75e63f2609ec2416405ef072240092dd23f835fd415d190eefe2afb80f5c02ab433946062d3bcb5c18f009677e43f5e02fcd4a330eaebac40dc788e4fc6890c1c75e22cc2e801153018b316d0bdb0adaf9b2fd98e4ba7b3507ce1f1627c006a49ed81177cbbb5a37cb952ca93655ef2fc4dc34532f9f5ce35906682a295230a0824934dc9ade9ae445d4f5342395badae4371c23635bfc03effc650595381a352cbb8c9c8a353bf795799b3d41520a966f48b7fbb28389f6eeb02c62ae21f7776e8a65b7b0fe6b10f0a498ba9d2ab503cd7e8b79fed5c1a9239766f577266a868db7b74e274b82107cb2b6e8dd04149d556258bfb92b5fa0ae4f05f407191bc28774159066857383d64d5b567e44e706 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d060960864801650304020205000430cb91c002dfd7118dbc156c9b6c6faaebf14d2d79a0d28a084b2fef838a9fbab5fd2e5f9d6ee8b032d4f6588e5219fb02efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 4d72aa3953630bbc1c51a7fb6c7e0375938e8afbeef430c1b0ab56b6e226ed11a989df2cc819aa9665f14e6410f86ac7010fa2e4a18f43df4df22a3956d0e25d4c0e0c757c520482b7b9c1ac55cdfdd67ab19676989f35a435952d71ef4aa679bd67fabc77f45fa99910c77c44e604ca85dc305ada0d4c37f2fa2703b57c818e +S = 13e21486fe238e70f645edfb21dc32ea0f415e5e260483799870d947151362a7249f700818014c1707016d71a83c389ee6f17354e20b55402f4c6036dff827d237fc7b24cfb2b5398fb34beb35d2d61b5c4d089ef832c219162484d453587869f1139d7fd3497ff4189517ecbb2d314c049d4e86dafc418c716c3e4c2803ea03c66b90b93c620aafac05e4252212200dd1448e34914da304148d1466e5e32edaf6743fa43c307f24ec1a0d46b4bb941945a2ed7c02da826476522cf7fe329268774052310d4b817a4058d9ae6084b4f1428ea1fa5a5dc0e666ff9466480b9f1d6142890010fc2ca3ee46db1ab084a524bea1c27b89adc87ceaea0a1d9e8d83358cfc20997b8c94204c80871c0e9da89b224ba42181743b285157d3eae18f19f8a38a102e53d2378aa241b5300a20592bc487651264dcf9084c3b1f0095e848f1af5a940a25ce3d0ae660ebe9ea09858bb366451fe8f4d1dfcf018938db14bc4efb1c4a2a7f5b08facbf81256ffc0453e4ba14744d1611e85cba35baa9302bbe959dfc2c0b96c932063fe40991c2ee47bc1ed97999f8e5f747f8138691db117784a5800ad4d210caebdbc3ba84e8fceee3bf59ff163c7ec9c0eaa468813a1fa8215464f390fc62d45993db71a7e56c4a022fd4ee377a725e87a2415877a6365b086c76bd2702abb265ec3b37b198eb84e9ce6e1037848c10bc132aa2f8e1af165 +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 709abcd4c8297d89f8e4a5446dd32ee612838200c5a990950b091e21029661d997dbcb35f89924ac4db2dcbea345a038281b2bb49e425f5f0af794ffacca303434fc77fd332ca57fd0323a02bc4c963d6878c5d375209c1d6cfc052aaf359704afc66a356028298aea2e6817a22e387b3861f966318c705898e01aabf11fbfd3 +S = 95fbadad59d07287451d54b9645279f6fc62ea2c6dcdea2d49548a992844d46b559be0328662c2be146e3812aa9bfb073ef21f2c73dafdce8297d70a04ab3bae8e0237f6da726621da82066ec76afca2340e3ec256ab5f3e0bb53833c78770ba95e39a7f844e9e483a6cb7f98d496e4eea095f08d809b422dada7dc779303939e5dcc644bbd0b22a339bbee4a9203005aa34a276ca5c1135418c705b8d70284ef279f49421304b28d1ef8606ccb2c9591ef36b418ff3f52933ce1b059d9a3d04e483c2baafb719131f29f1fbfabb85c7bf0b979ae3377a35fb877eab9dcc630759d18b3974a999bfab9704953d661ca6449cacbace130869c2b0751d205c5c6ffbeaf3017e9bce964b2d4b6af2ee8bc9897b6df0d53b061e89918eabc9ed4f46da59748576e816c5bdd0c847a411948d43509e994ba816d6391b041f23c9d70d004e9d3c09fa717c4531af5b8dca8393d28dbfe3b07d6a88da2383181050bb033b8f21546432f62caf52cfb364e87ae5fea1c6e2948e39aeeaba89797163fb2b3bd35d8bb8832218a5d931d351e9cee457504ae70c09b51004c826c913cbf61f570504951e02b1e47e9ab3dc47b44559e77d79b734790a1faedef901d267129139c66c992f039ab42d15635ca1ced47ab12ba87e12fec8bb574c9dcd94e7c6ef54a75fd568755042e8d928f344c65497b3183eda9534db97a90b24927d77e2e3 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 2be1649aab8e12b337a5d974ebe354a0ce3e74f4fc76c45a05edf16090b889e844f60321e86000b6c822d0455bea3812243e72fdd61276b1bb9a781f565db22b488b63a47090187a56e92a2bca36887fc891b6759f1f167d52e467e73fdc8b9cfe478d0c8c44e267a9a1ef107ef2cc4f83e04846a0c42d269375c5a2915d9ca4 +S = 11a6268f9ab602dca7444e9e821e9e9dbf2ff6f875f255d8dc202f953d91d6bd13c74697c70412131091a062f7511b06264d083ed49b24ad429d35e9fb02326fbb2b206dada13f5aab60b5b3db5df6b83e80eb946e199206dc2fc7246ffc6f663217fb5ff2ca14eed28a58ba010b5ce47993b4b66ff00bcd20720a4a6df35a81aba6d277b2ac3fe65dd7089b6fb918831c54165aa833fd84fddc5350bedd1517bbb180dc63016a10668add62ce782292af053a1419970cce6c6740d9654b62d836b7446db56267e08aa204fbc3d3352c196c6b757cb08f137b0653bf362249dc7a7162eb3d82764b51b8f7676401e89c3437ea3fef7b727a096143033d2dff653107e6bf20f9586b2ab75a164d5ab84cd0bc6e04749ad4599c80e4edff189c472b02c91b31955284c42aa5390d83defd8c4c24f14e2aa9668fcfb0b683fd7702da5330e73cba32b77a1c197c4385b5ba5e0ce2e5a3732838fe136020b870c238ddf5900b662dbed59e9664754b63cc4b8fa3766797b2120924d712935f4a591e61d292782bd6029b3eb434e33c06dc53d1152471c000dd8e9eec094ba6b3dd5d5e71e23039480df29c2b00fffb5358bb5628adf89260445ce4ea3cc4a701af52d382ed2e9c1db9837c29e211332f9b6c176630f307c5b0d0e28a1a09fd285ce2c12d1f18269cb1a04e5c1c1740fbe8af04edd32abffd09ca5641806520eab220 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d060960864801650304020305000440a6e9bd72eb12cb01af08cd796b9a5d7f70e34e1c142af67f862971169f7110687017d74eac1c5d45f013743c20ae189d7c9c61802770a915b37a0ffba5ee490d +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = 1dce67cb88490ddb92b9528b478d3cd681c51ddeb0a76f3cd7b40394d7da5b6cf0eb543e854e07cb1ff5f2b3b58e53432bfed58e180b6ebfcc5888ad92975fb032faaab4baea7d8b7efc6e885e21f749471d1bd4fd3a4ce6173d8d874b99d4e2ebe3b254b08635c3b7b80e31c9acef90df0937d8e59cd158bf4959498a4881a9 +S = a73f90dd956d119b2364f15b1772eb3398cc0dfa717bef2d0180ffb42c5a6a9f6240e56297fffc3ec10b8527678e37c126a033cce08451a5052575ad1e471801df563e447e57626a09a5b218aa5d1b3ae3dafa8a43e0f5b187f9d11333cd07a52a9b0844bf61f37f9107fb9770ecc17f1858767475e9e63945bebf12c54a25f9759cfa4b11c605d41cc2b7aadb786a03fc41146ab249d984f6b78c89af37a6d788c67f0575faba520cda93288479f02c83e78122ae5b88ceb6ecdc429f5e8cffc9e1fc78d8c4e638c74fc905a2ecf6fb2e797a1d8b86d458d0d594836f66b801445e743d33a5f936138a1c18dcd08f6a826fdbe71bac84dea0884e5310316d9a28b50d5f40d441d5385db88f4934b4fb85538e9838ae64f9055da047f8d49d432feee879301bed3cb7c2774179fd4f76813284a492d1c89df758ad141eab289c504bddf9934753d94588c2c9fafd69b6b261ce320c103bbba0842e9e2e14fd88d17319f9a7596a55701c22226e255d06f5dbcd432a930758725ae73adce8be417d7a94a712d5c5b3809441557b348720a35da7de59923e59c92df63de405fd913fd7fbf3407c72455d3be934e3d7a878bdaf88498842fe533a03387ac4a6271f0c3621c33424f610eaaaf6878fc99660b2f8833935b6eba90636eeb9b9f52fc0f3244183e59caf31d890b22cca748c80abf9837808b4a1fbb9cd5c9a9b84a2dd +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = f0b048e510fd9d75f3d7bf3f460ece324aaa452f6e2c2d6a23179114ecaf3137b4017ae16523b684b6bd819d45c87c94e59645e33913a67b824a0c63b52b3ba3d18b41606f6ca8489a7ff031e2e73dfcac404cc0cce0ab25565c2a0db04e8d7aec5683ac555fdc894824f64246f2783446af430c501ba62f4756d15907a38d83 +S = 05eb7a32c9cefdabc9208a080b7542bdd0e1e2e4a8529c29a7529527207a0b5105464d0cc445e7e64fe2a9be5cfe6635d4fc1ae7bb7ee36b86fb2ac72ac7d53af6b1dc6df2c85d9aa3513ecbce8ecfb1926332f3119a4bfae1b01b2565376be9872cbc7bbfed88a4d2e67a78587ca53e09863bf21ac1350bb38e009c3c458d2df736b1212e7980d0a3735925cabf39ad4da1b98e9e7a6e4f73aa048d8d686297fc6885e5a939e3195908e17d32f7e78d22e9eaf3e9373ed923f0b2d6b45497351cdbc9fb8ba0aa912223121a24b2b44b291743bc3ece0d3911c4d54ce82f883493805273b0fbcc964ae9529b83e6f22d0aedc8b6f8b2a410abbce970cfa44e30c9b97ffb312d5a53d904d5e99a86745a70c6c9f8f3303c31b39dd587211cc49c973837d89117583ce5be56ce263976d9c19303b7d8971bd1bc0a7bfed7af8ac90329a628a85cee99a3c5e9bddaf857467a8fd3b015345e983946a1a22c4bd2c18e3af937555a08dcdaa055a8fed0e06ebf19f5890ed0dcae6e031e9150810d654925a9347add44fafab80d3bc8342e9f41e60ab742d17d368e02e82d56418c22ef10021431c00af4e21b7436aaca8b67dd7c5b1519ecf0c414491c1bd8a1ab3fcb1bee7d202673c0a080f56ae2966605132998c79ea59bc6aeab631bc0064187f11ef3273d5c6459ba6ebef569b99ac751ec0edc37492c7c563991a0dbeb2710 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = aaf54244327c90f0aec7add583fb42cfae696074fefd5c9a80d9dd1a3b3d33d31eaaeaf137479f6f268313dad0fc7e5858a026ea4b112fee1a4eb5e8ce911881f77397d0e55621d91b046753019436afd98e0455f44fc93126ae106e77df4d811b98716aa573bc367794d2c97d8b12da1b7b233f637ccf6b8c3f15359ff179db +S = 0524037b884cfc8ed0047ca0cce7f7cfda9893c065ea6a1ebf673398e23a56aa4b0a179f1b776a3bb716ea83f0f9f863661aaefe7f50da0d714d9cdea2408a09708d50aa4c6bc6ab31240341098a1d8951c82e4708a5cba44d0d0b98b09dc8f8781ea59d9d6dc168bf80d50e67fb53763aebc6dc12b19ee6ef47b838d58f1bee5f6f3a263a430b22f633195ed0d32a92c08b2a4e75807f1b56edac08a6a87720c611ed497dc184974ad7d3fc17dac4c409a44c3fd29a35259fac0ac2395f81be0fcfedacc8044397f4fbc858640af552b2cab5f85a042d41050470f7fa485ed38a0fee6f9e935611e33b50264ca04f8fc1c6e15d20d10b023ae7768b0b87f99fd298e7663fdaf5dda0f61c019ce0516daa8db07f46dede1ad63f8839e58e3c33e69df238c3481b7ebcbeaf448b986ccfb09b3cb62249ecea2315be42cc6876b7ad17a79a10d8bb4cb83b7e33fd28218b58690daf5de8da3824bae1bc9d84a8c9c09b5f4d67497d2d5b215bd530d41decf24d32d1c73beae4e6edd3d2859f11c7d8ae60673c94f1a233e285aa2bf8be8de7c5791bb6bc624ed74bc1de32796bf656c744dfa9ebc3958b71f2f26a9d28de16927aa2923e6b897c3c3c1f719b3239d1e59a136890b21efe97081cdcdc69a39668791fc4089fccb694a77a88101358ffb961792ca3c41b15bb81e1edd7fe403ebce86ff17c5534d441d946b7763806 +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 +Msg = aaf63b5ed0e0aeb7ef3da4f134dbc2e8942acc27029e7366e5556f51c9face8b54e98cf37c936326f824e445f464c7f809db80b26c39133766f5285c0433620e0febed963e48561bab4ea06984c094f103415810a0b9439485faf07c42a491ffc24586d07dc52fa1f002fee64ab7d0db69a27dc804e6ad832aaeee37eb130465 +S = 28cf265ebfccf2400d6129058b7168cdd9fd44f44a74630d8df79d306b41a82d9ff0e7e08ba01d31514ddc3ef87dff19321346aab5c67959c551695cfdf04bfbb0ab74affb9edc69b9aa6eebef1d4fb7b1ecf7fa30ad5834136de2510fa774a24799b6f5e6410f4f14354c010f7f9e4976d7772ccfdeab7eeff704e9531ec3db509c1f0913144a444dff8e36f9f50e6c2c7a693c5ed440d95b721664aff953a18f033df5ce2fbc2902d9fe4644f10d50f69abbc7d2f58a80e6b6b4c94d75fa53bdec788315e87c103e81dff4c5cf7c5f1fb14a3019cc89a871328969ba9d12fb14326458ef1df1dce42b02ad17db4bbc75161e66aecbdba7ebbf1709fb208642e3e1a3c12738440502cd235d6a43a08d24f6a397b0a5b86d0a8456e939d4422934917905b3772e2c5736ffc0b3cc8b8bbc1c9629ac37d54def02ec83a106a6537adcb6559ea3cb2024a1007384e604fc64ee9fde2aedd129348c7fc34b240dc841fc45b2fd2c9ec16264b067f139bba8f3c31bcb4291b71e590bc953fd63d1ee44a901d47fcba0d12150ebde6f50209646831e10cf3fa7e129e5504fbcdf4832f5589f191925dd85ea7d11031cfcefa5ed4f9bde552c4270930204d37c37faa8dedcbc2838a36fd425d2bbad87660fbf8df20610e666a9c382b81b27b0cb172a188c46bed70dfca37563129376b2d6e78d4be92b81978031a84eee45f9731a2a +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d0609608648016503040203050004400ab1a89aa9fb0c29b4163f44d7662e24023b152d820dc90168548295c7e1b5836d3de20a9fae39be49bcc40d0c54e271a4f6fbf4050c315553dcb6a3db8b5eabefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +n = a74f2eeb83f4f87768ad1068802b453e7b9808db9d1758ce52ccc70c3cbc4cef2afccf66b1116896fa27acc8cd779b4df59757e24bcc0e69f409b638cba8adbad885f95680dc4a7423d576c448cc38b00ec0292ea3323bd1eabe2bcb6d9e9c94665eda88dae5bcfdac2a3ca71b6d3bfd31cddda0f41f14dc5ddef946a9f779398b05e46678d2e490ac28c8807e9991bdc00ecc28d1b7cf63b6f3f47961080fc45e43729013366c654e1189888cfdb7458fbd56ba3b29756087ad1a0f86bc5e1637f7c6f881343033bec98c22e5c22d91ec2576c66214aa895d08c29707e0c181c666727767f5cb99835eb35a75d44033e5fbf947f7ca249861d5fa5b5d1cd4845d4d241048bfe2b06ffec934665ce371c826a2bb4c2de1dbd115a1e220465c6eb9d26297e2f9187726926e33f6ac7154ed73148aab86813b11b7fc043a969c8b9477aeb6305a73e10cd9db0cd5dd323a9c7ddc08accc214b4a555da9cde05f3a351948e56848d543ea504071f6251e035af576e04e55725516e215ce5b40c13f4029caeee38e4183c834127c857e1a0ce52e2db2faca43542eed0fc2331980be2e70ed938e007d1ef56f103f800dac041bae43d2117fc7030da4f4a87b1161c7cdd46de4098d10167e028fae2eea05da82c687ad82817efa65e973845b5a103424d17234fa78da06984549569443fb9c8755c4627a5b04992e15c0823b45a855 + +p = d86293ff70f21a0aaf50f3e91a38fbd29c3e84a034b5a9d5ead0dfdf0707cd9a85bc5e17c51f149c804f9feb00c2aec790e605b53108cf008e7636ff32e0329af9049e0bc48b91e2712deb4c0b1c2e943da090ea0dfe4e64c79f4242366eb8761a827e64d7fd3ae66b340093a21024418db44dc8305fcb097b942b2f7c790835d27e24a9653eb7af54aa06482f6438d4676965d602f3f1f8939e184f6ac9c9df083fb862d617af4516d824f419e11157b208009cec826538f80331286925a47da40e6317914dcab19706831ec84f58d158d945a354d3d2d1900ba044e25741168d334c5100ad408591212f26481759d46a735fa5f14b650bc5ee0e4f059538cf + +q = c5f08c5456b320360fa4338f92b57a8c6715fb6ddcb07c2d0ff93b6549e7df6e8d3dafc5710f02b42d82f62ff2d365fd7d9b1518eb512f55cf10f347829aa961ba9edb5c5e36c1d899b4fd462e9e89050bf7edcb20c0b54771bf22056a7f2091739878dfc53047ea7cc2af9ced1fccee39b2e9502307f44b1e8f3065aa9d2a45e1b5ee174d067a32fd3573f8d85c17fe3153736e9b2ed6a9fe068530eafdb0c42c7ca5cc9fbf44f84594b324965f537f1862f2ec303b42a838ae892dd1a59b577b7506c663638c837b67d6e6d03066b71967ce938b381f91f50fa526089fd146f62977cc41111597481d9c3af2c099279be8e6cc9fe7c64d394f9298b44a4d9b + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = e5f707f500cc4d0d36ebec7b49ded4c1c1d8fd4186f5a1a5aec2a97e9400652b2aa57ffd90243299e5eeb79d5d3900869300a9d1214b2c606fb05420c81af4e9b3c9d8a5809afcb52189fc903b74ccad7d22a9a431834f9010396db75b58566d276af935f9b7132a92c3a39d0c179f002644e502dd2674fc3c66dc8c7442f37f +S = 84108250f5183b7a1957f5ce9c10b762fa7cf3444f76485c0b5033e1f922d45ca86feb96407efcefabd35bafa24b1f3e5d86ffdced1c3757e23017bc2a816e940391eaec9c2b1e01c1f29119b4064c60a2f5ed91162b308e21f70374815e916f134f7e8907a8fc120dea9cc15c53741ae1d1146942a06d0e1d297ec0fcd1e7024bacf58b0b64ab63f95ee3e3f3893a6a892c8c949ce1ad5664196bc7370411d6c18ac7b3998e5d9d35e6c649f9205f0453ebdbc9eb6da6b4aa549b2af507deb7ac776a89b43b87e01be516e4ba36cecea8fa598321beeb7eff47e7561b52be6ca99fe8114b9be68b0f77c5d8769c35fa04d5c4894d331e7a1d65f25b44ca95e8074931bda83dbb36ee622582112fd918a732afe4040280395fa87dd566e69b3668b295a53aeb3ade6835b32dc8bde3e59f6b6ee36322b39d50c14cc98f7af082468be675b73548f5194dd4c907d99db54f785097cb9ed28c812bee694ec4ee85a8d41501d0a70d82cd8316c2b63d06e2e502be79b5a1f7c06735eb5b850cb0562a117972f171e04870caa751064db6fc4b2d64a2ddbdcf1d17f6952b630b86d6124bf6a7449cc57ed4cafa192756571fcaea3e0a52a92baf4d18f7b61ac404876b1f7e6a53498bb9eccbfe94992a1f326017cdf91039266d9a3deed3dcb124ae6aa96402f80372881a207dd833b4ae38d9d9f5ea2f30a4fa45e566e33e1e1388 +SaltVal = 00 +Result = P + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 5eaae0a318af7626f80e9c31a4e7bc127d24e823c80b1efc0c13cbe7baf78d95130a3d0f47ca2deedab7aecf4c66d602f9d180823ef1932add8f8825a35726a7482e90da96c5821ccd6ed867472f5010581590b578cb6b71a46b60510194630cc3bde1ee4dc9fe1699db21e1db6bb2a6619a22a4bec22c3827525b541dd9cd2c +S = 0d5434fa33a83f13477d6ebecc596e1847218ed9dc99e9d75a175a85d3bebf47ac7fa9b537d48f49cafc12ad3b239a7407f56a27b9dc4ce222ac838a6bdffe594fab2c6d0bc15365a3e90f6765e837ad864105decfa723101affc6c87dbfa0cc0234b9f1fe033d34bd9a5c4fca3a5e228b3ee3c75bbf000a6ab654c2448a43a6b4d2439ee84bd125fb44688a942e847dba0ccf781840a0341516080bf7dc1ed725b566c07e846840d02ab8fca219127ba0f7fec701c79a1a8c7e1a3db32985eac37a2d15b8e22ba159a78bfaab05f00934c95c1aa8d9b350af9ee17de47a69ec25a05572fa57ae33d9ef1d7f1f6d149870c96b2c3f266df32e1e9ff28c718bd03d1b1a7ae7b63fe22a82c2b7879c117c7d16a805efda0925c02aa5759653dc6cae6f1d5ab02d718c78403e40ca30a9f5473777927980d142845178535dcef705d3ffc0f650ce17e8e984da4bf98a78c0436dcb00f96c8aa5f893ce4c2f5088d87d6ce2c90b09a107e3431c0cf855f641d964866b56f409e9bc7bc6147ea3838c1d78c833c973f2f3040872cae6d226aa77e95ac907dd514bfc3534f76621c4b663a0886fcf34e5f741a2dcad200943da40b38da72d6d60eb3ea0489ba6ebc1d0a5b19c966cfa87d72ff8ced17ac770f4ac20c88ccb2e3feae775bcd9747a5c87ac38c7294c7a99c04e1a421b14fbea33dac05f7efa2c0fdf6988cd8f15ac6751 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = f11684d68056464935458c80bb76ecc5ffb35a4c35ef4cc51d7c1c32847fadf60da0512f3106ea46858250c53b0af368ec6ac27695364b51df03234ca3d688beaddd4555c05dd6acdbeccd1fbbe074dea107b4405599355a6b6ac7d1c56401ec593527ed344551a2bfebca3742e0b74ea6f4f9517fff54074a1bd066f2105fa9 +S = 61caa531f63359df1779d5765223207864a01b218fca9a8ca97c125987b1aeca6e0f667276421e708f4f6943df074c48b58384cec8e773e60b4d2c2ecd9db62afd9ddaaba4398d98618ee89c6ea170ff53ad6bc0c08fbb3ec07954fdcf980df778b36c823f42844be7793e78d70248139fd8f6b8cef38d2f5a93e8c5c0b5f5f879f3f929da5b7d9d9727c808ece9290570051238b75dc13decda4e619800acff51f99538f97db8dbeeadf8f54bcc58c06433a3e018dc9bf8ffa876534cd4d2f3b5e88021e8141f0356d01f5198704ac9ebf3d4433f92e12afd6dd6ce5a734800fc874a0f1a4281f7120380db8f27d2cc54fc51291d68c2b031a046426243d2e1c34cae5302685e1eea7aee04d01a1cd4326297fc605af8a6ca1943dc43d9cacf9e713b9cf427628b54ef0da3bb13eb64b9dfdb9e173176c693453ebbcfeeb9b637bc9bfa401fd63f1edcd6fdba3504f73c7f2305683c8a58ab77250813cfe94fda23da973d3db920e3134e94efa3ecb5f43211b3d12c2ac67d7d43fc7237cb629bc8b2bcfe8593945feb32d3a9d2828a2e16efa56111c3d1e6406e8a738313b615a9ee30edb4d03028b7ea0545efaaddcb2a941129530f67e1d9d870a529c6c649ba7db4bf2878e268f7794943a19a0b9d230250491a870cdcecf971bd7e66bbab6a6e9ffaf5f8b727f00532a609975c78820b48b0af715ecaf6867bebfbd708 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414f3c22813bf0da5f5ce5244a03ccc74c41a51caea +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 6b7c63bb3b14afdc085c08805123108fef29976a4c856c74d34473d1a553f86d8e9f4340377a6dd19d4172f9c13b86eaa2c5ad6f68ac8676e2db67cb3236af26c7c558688c15cc225fdbfa57c5dba883dc080bdb91ed95d7124b0eee8704e6a0fd37cabaa2ad75d63874c921c4c91e61863cda362e0e419f4dde8fc10a8444e4 +S = 2980e019c0c7e460c720ca8e45e8742a14a5c712db17cf51e8a5fc7ccd6b2878c4c609b1ccc6258493a965a444bcddb6a21dc129119f4425d1a707555a6b50bdbbe0cdbdf0abcdfaf8cff67c2056e2e9df573f425dd0f56fb1ce3e8171e12ef6e9b0062d5b393fd61b723801a9f57bd8dcdf01d0965641607e3c952715a729e71622a3695e16e92b7f8028c3ac25edaf3ebc34bde80113fa8d4d4f7a56b6aa0100cfea550a220a22ed7b24d35f2e89ab0709ab7e3478fc1a61f94b6726d5c3120e2de4cd8ea7f5c5651f425d4435c1de0696babe95094397324711e4e7892e287fe8131f976f263c0ef209bd78a248b1c72813c963ebfd52162ea9a6065aa32b0a97bb33eb39e3bcca888e6f92afb8f3891317bba4fbaaa27f638bd7900801683ab6a4f66d0101246c1aede70ddd6367d255f21e86ee48734df39549501ecd4367f6b59e386a9a42874cf0db6af11c998d29a62392d1bcc40f2feaaff847aee8bce8a93af3f1c0280966f9836af3098c10260dc6db8372939d020e863919e228f0df85ac23f67a5cd84e7a564bfae74a307140e636f10681514383d0b270d03cdd969b5e2eb5fec36af874b1d7f387b7ba69daba036527474fcc803f823cb17734e8faa073cf470ce65e480bb137332422a55d3bbc72a148758ee0a222f8febe8f8d99c1051df894132dea5b0387b5753719253ff3dcf94b006f2c83e06b4fa3 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 3be0bbfc2f5d6da14c29e7dddaf4630f902fe246117bce54b661dd248e43384da392dde67f42419def7b3a0307921d2a66372372bcf012a089c61930273dfbed0a8a70be4701c8c353cdd1a00de3fb19ff39bae0e1322caa5f5dfc881d608675f72f3b2b8d82473cff85725df5d14405e39b6d378b2b649bc3904dd47893200e +S = 632af5e0d55d9eb7d4230c6818d1a178df225d91919423df4168a3e1fe2142f1f26f00c5666dfe6817b2a27f3c2fe6546ca747d74467f85ac0b73b8e34639e8448e0a560b1bc3ec827819db0df2d22874106205f93dd0d903926ec0478a5361e7a9878c6974a8c095d1b5779d783823d4355ebe24762045229ea839d05a177ffabd39738488ff449111238397da1266eb97ce6e3c63c7cb9ab2950140ac4a94dd148520dd67527c48d086e20bb6e18a26fba04a81008e35e0cf04388eb4ae9a1193d4806bd2b771117dd2ee2f349b01805dc056e5f0f3ca4df9c15562d6e1c9fb611059136fa581125c383f6cdf2ca7f7bdfa6cc8d7a2aeb1e2ef7799941f2c6c8a34021be8c771ce3e37aaf31157f91c37ea9ee02e6ecd3001ec30bcd6a45258ec7761d967798402ad5976f22542e5604d58627fafba14bc5bf3145861eed0165484286a2bfa0e17a37710b3a17bf9090f3493c81ccac46078084dd2eb43456cbeac804224083b5a9bbac414a57332086b8e8b0881707d41d4089066e36469b0085da76c6fc16d2486b3f7fe31964f928d3d902c3d5598df2f72d1a2d5436779985bc9e7264d07448f792a7f394aa36c9534be9ca7f431e90729481d0397ad8e4db9f4a429f238f7e1cea5c03795d82beea3ccdec38ee4b727272a9eb520e943ef2a1ffb10cb9e8147e1ea0b1d3208810b891b37f9ed8722a93328468b9fbcd +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a05000414a42c6b6337793e971d69173bb994a17471dc3642efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA1 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 25627026d11f380f939eac2156adb1bdc2e9c087bb318c782b5ae52f0224dc887b6d2870a0a5c8f81082eaa800f50c15805c61b5fff976f312a3157f71bb6ae84262646c9be95e0f4289ffeab7555ec6746c6ae973738a30f143805e72de93b405a8edc2c9d4427cb01cb29083b5f1f72682a5ca1e880f5850a2ee750b75a015 +S = 3c76bc9dfff017dbc6ce8cddfb1066ab8e669761c9a3ba229229eda74f05d7790c0993883aab90d16c2fc358a7117f8118c9147c69810f2fe1d7cd4220c5df5bc67ce3d2abbff139083bb6d6c48f6122f71b30f20e37e39f760f9c3b317bb26d6a14fd864d97d13c9a1dd7480c03727a6b6fb2b1b74340678a68c0efbcd36a39d42bc8dff44eb78d1ab4131b80eb4cbcbb6687f0cda506320882dcd70c1839c653a026179a0615175660fe557f45867fe6d883cb808db01ab41efcc0cd2137355fd2ebed412516c8003213a523068e47ed03e58f529af079a5f86bada203793808d0454e8170c666b2638c248df1e6b9a0cad05a94f9710d7912d833e3a474a58b450e10a22188444b18dce363b1bb3cfba548206fe448e84a608694f060e71bc17e50c1c777b6fe8f0d2f480f154b90ac5c6ec274a62d23d72a263cf0fe797c5a1b226d612c2007b502b42c9cebe5fe27b5e2b731852ab7db8eaa8fdc005072c96ed55284cc59985aad5528100062ee96c482e9539cc0b5a5e30954ab4a386beef0dae13c681ad8729a4b3dad39739892f2789f18c5b517ec2ccdb2b9d539ee51546783e633efe4d22363858090a0f501ce4acb8231e2515bb06f02ff6b42ffc62b30056f71ef4ab1952b614c32711bf8211f99a97bd3d3c5780142f3730e7763a476584efe9d8bb8839d27c405f52306f3d4db3168a094316c699e9190479e +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = d40724deeeb76472778ad98431d2e2061239d0178df747d81349e77cda1e2c9fdd1393d924a1ff9245955a182bc17fee16f25868e32243748eeebbbbf54a34e9de7346483c250e94ae0fd20b4984e3c39773c840df999846a7f5a8ec787c66f2e10f8554beaa5b1fbbde87841381d62b9ea468ca0ac50ef56846f738eb1e8c63 +S = 258f159cb8bb860c3c3db9d6b59a44600190f0076d1f2ac163b52081e01fe2e7423861ed9bb5df8b40d4d1354dd74219c71247bbdec4be0e90910f827da0565b6d13c5f60db49e0932220c1861dfb3f0b13a5fa74477aa329ab24913ca918ba7cd4e72fa532e044910f6a72cb525853f926b752adc76d39bbb9a265206c9820c3e331670103fb82a9a0071dcc48ccc1a650ea1c95341a48476af0a9b0e4286d96f0a976d3884ba97e5aa78909748947996f233ba02d6586a375dbaa81f3f00f880352f7e1842dad59733a40bd0c9393276c47b8baa99e8404b1f539d09cd6958007b297ac8c82f66fe2768fcf572766522a104d2de11435a19d2d1ad77221ed22d045a227f437752f3029f6cc55a99511f1febecbd45d529e216803b335cc206810d19804874760f66872c8575022f7eabfe437924b931d18e8156f33e6eac5d5f1540476359c130781a436b17f3bc23eac0f9fdc06e9123109bfba7d9a7eccbafe6ffa87f6c872d952e7fb3f6f2f73455d0f4f7fc63a744e7713219425e746d7d2f9564c4cd1a6301cdd78b0945debc122d85adb52b3cce920b22e77f0c835a87da3a2c9ec3c0938551f76f229b7c734242c6b78eb7ede1424368834e94d9f7df0070dd4d5c7503b5b023508483c4977b0a69e4183e83b88fcd924df78387b916ba475d9cc922deabef2dd07a3920870ef1a8105d6a6aaafb3210a7b1848b81 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c560c52ba7c3dc1e996063b94d4238054241198d156f307d890406f06 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 662e6fd267dd8f2e5f0fe89034e4b0a6e8241a256dc8cd6bbbbd966421e459aad85d4ef0de0569a0013d1ac33aee37223dca37aa4ed4a0155622c2c736e1a6f65b9b420e93b5ee541f3c1cc909e14351b8411c14c16a1125009bf362e84ceb9b176eb3f62df40591df92546a47c5bb7c7e13332b6d9408e2e0b18efbdc2c10df +S = 76070d1cc628d84353c5535dfd3dc19573a91911217d3f9382de19b3d51f3f5607c7f88d82bdca4871b5361f39b8316b45a9bdb3775a69714bdaaded31dedd9716a8ae202c0237732b935c469ba22adb7dd67f67f5717787a6bc33e303af0f341cf202f8696c72f54772bd619c7929afb2785912701e91d96f9005942e6d11fbd757239a5cafbc93ca098c5632424f7b930e69457cc8810cc9ac3b5a1d1e17009ee45887a632cab31c9d9dab6e843481a09e5a7ca77be9d3d5b0d668689bdb82e4e2e43310fbddd5774d482b43cfc1499196ca521fc58bed44971eb15d216ee55b125ea8f65439425dfe1007d0be5418113484e1ee9b1fe3ab25625ac624eecbd03ff9e1b7dc66503afb625ff659917635098442af02696feb0b2d9559c19505cfde72470d34dd1719655874c8d4c23a94d5f91da9aedfc38e96e271ecbeaf924d7a9313cdcf6f485cfb1f3107c3ce8e0fa06a326ed75732738d52a094e9babf6e14f3f67ed48a09797020c9ad48a31aebcf4fe0e0b4d1c128a0f90f2bfdd520c566559747802367e95d45cc8202a479fead34c90c4663f313f3db337cc244a85eb595a904ac9c8c213fa6e762a251a4b84e733b7990aaa92a358ef369732f2224b5d37692f48f8cf6589034755347eff0c34725236d3d55ec27ae919e6d255025e4d2636b6c07807c66751942d9362143de6133a90f3d3503d9b50f91d549a7 +SaltVal = 00 +EM with hash moved = 0001ffffffffff00302d300d06096086480165030402040500041c58df3479e243f7dbe552ec444cc92a91f478808b02c5c6b5c28d44d0efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = c65baead3c9c432956e7da3ecd9f9b81b220c054b3f6f9b79a4e0f6116a9c810bed80c1d5324455345cd0c0179b6014e4a5efacdce1261515a61d70348d11db1f7d0356914edc4471848bb8b124736eea78ba5375723290902ff41ffaaa7a5fb7a2d72ba075f88acd742300320bc030ad19107b9d6911a86980f947dc4942893 +S = 6676debdc5c1d257b6bf532f1f61981e769e3bf0676b5050a8dbc65ed78ed3b88c687d0213ab1c0ad73b8606e2e2e9ffe7ee8f9b20a532a3fd59945b9f371d13807e36da1aed420d4390c26980cf70465e3dedc22368b09117e4606257677132a7c92e73c0633718290535915c512d629bd3db35306f264c5681e4b48e3f5e63f46289e41d74ab29a099c637132d2b8a04bf7649e4fbb0a6b3f37873d2c001d7833c9bb1f4de8043858223dd005ef43c6ea6e0806d2958ead96fa89af9119b2ac16b6302e9f23c5a2d79a2d6c4bf5b576ab07de117857ad4766606e52de3b1cfd368746425c74154cd814e63ee05d419c9f05038683970019b24961de26f0312203358cf5a69fc3a8c34376774d93a07e8ee8cb4e49d3c8061cd988ea9a96973b07dc8a8b96db165a0f287df5a538304a9b05e2ee294c155e17bef1df251297213904b56fbd3770d6587e0f610b291d0be288bd744315aebacdd71d00316f9d169d542108747a10aa65c36398eee21d7c580d088871e9c7be4b590f78b8f315f92e6970ba9fb9f929af324d02a281972cf2841155de6a76b54c1316c818f9c21c52eb8ad063b53aab1b22e72054ecfcd833efbd3d0da69c3730e81d48f54cd9c22da891fc589b3b61b5a226bf54d401e576f2ce86c9b651cba2d93d63e2e3181a97baa20a15f6e584dc30e1dfcf1a3d2b69803eb84d3ed4f1e153b76f14def51 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 953446b04306756e65d0cd8bdc3960a0713b59fdc73c90ea8d7b5b33f8aea6e371ea464f8bc28a5637b313e83bc0e6c5e059c087eb81aae3cf30cc2c21f686184ce2bdc786a2730103eb9bc0681c2bee821e726f388eac62be1ed4a40c38b9968fe554211eee59f72f410c1b4b9556a3bf5118bd95aabff0c20c19a4a1bc67e5 +S = 179296ecacedd93047d4442e8dd5a0de7e2799f45ceaf381cde74f3dfb96d5afaac92bae3df1a572c24757eb2cf91b970cd038278623d6cda864d2db12a763b94198dcb47e6041100ad6308403ad35859d19ff3608dd6dda433c4a30f53dae2d615e612cdb0c0fd4543243b02e873a3ad6a7315b0144a9c1ecd18c446781d7a8cfea621f646a219d6d108b5679520158c3d51287425cc920e65c94eeb01f9b92bb16d167e60906e30e9d2dc8a3fb8d509bfc406994e3d0a39e27d13b3ed5015c61c624e1f3425793c6b0a96a4982997715163ea2ffbcf38680edc6f03a9981d0283053bb3b84061e5c5ec886ff6cbed8041980a49af1ab383f349ea01be6bb0fac45be52a853770e9b0e8f1ddf69a18edbd858eed11c0c8739379de177074aab7c9e20d1783ee7dc46c186eb3966abd35ab08df3574db45b674858b3baddac03fa27d818eac14d3edf5f53852a6e42b052aca9b1ec392d70d53ed10af5b8b5e0df1a6318c558ca47740dee0e5293319a398f01e92743a425a8d4940b65bd16ad266c0db2eb5d53dc3532c98edbad8faf955d65811003a2d887374218bc4504b82b710dc828d838638ff3e8a25cc898c8d210626388132b9e023900d4867350c72ae8c3bd6f0c4d2732294403c1b6b2ef03670e44b2e33e05c5a00299e070a237186b85271a196908609a996cb386d20e285ed3446bd0f03a184aa47998625cc5 +SaltVal = 00 +Result = P + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 4a51133aae088367ed396b7e7c5115f017ee32fc10e9cbd2e8947af91c40d9ee41033b0e53b89ab54b46d1a8ef260bb0ee1f7c882c544ff95b81df44cb8229c0831582c490e085c79db650c6c416f0e7a4f4195bb4bc1a88d695116830e35b2c370f4f260c8a2ce50c0f4fa2a329aadb60f6713d4f2a16c78356782df26b587a +S = 0eb8a7a48915663d4feb5c00c37b1862c248e9305c2644f40b32654b1899e0469554dee6495c6142588d25c7b04d9e498422902307bb8a861ffe02bd3e15eb521241f69afc928325c85508e698dfb5f2ecbdb555829a6c0a1ed7f97a711ade294107101bcae30d469734e7344ab29b03d7bcfb364d219d3d984c1f5915bee9fb6e2255cdcb0e8500bf69d9c8751dacad6e966438eddbe6325141fbdddb4d9c45554e467df872a0dcf5fe9e12b7bf610117bd0662cf2d97c33988c2244283dbd3cf8657c69a94bc48ccb22fff87308eebf175874dca3d5baad98adcfcad551b8f397f76a96f02f398f7e1a5c5d49ad6490d2476b03eca81e806089b5f88c368cc63421f20f54e6b3eff6c020fb3f7a6df34c2592dfa3f45327541ebfdc7f6f37e6ae0609fdd6aae6add86b9a793023bcb0bdcdb051e17ff51ccfde476a87c04a5b2f5ce11e014360dd9547996dffa7c075f7eb4d2d779443ba313af95670a33ecf0db05c7fea3760e53d08707441d7ce6f068d45c746d047ce7fca96106b100d704363bcf82e0b384f789284b8e472581a52004a7632fb6c8d4bce4e325a321d0ed7873aa62b9098c73ba4cd185a5ad2e99850c57167dc75561d630fa9e9b2094c2f327f6f3d097121be3d1444d941002861feddc38ddde941a223d9f525bf5acfe4e5ca39bf39e5f37b5db29bae077d451198f1e0d99fc93185c2810f602cd1d +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA224 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = d9b8ac36d3fe6d7e9c008affd1752d4b928c1f1787dae8da249738972b0b85f67243f69ae60880afd0124fc2577867d6466b8bb410245d82121bc897177a9b8e21d17699670bea189aa1dc6b6c0d2a04538292c08adacf775ad004d2976f5e5c6dcaf5dc5deef4e38215faa1191cc0fc4037fbe4fee484e0841db6edb2d21789 +S = 14ba242af3387b7b0489a0012f787986254b084dfb24cd31d7aa143756886345462f6d98ee33e8477cf0606c60c99b585b52dd301975f7400e73d5cbdf7d91ddc5b7262b615d39f2d0ae48bd5695a61630b082ec78cde6d91dc4b3fd518c413bea61a966b1d5b316cd3878a91d80a64d52f5ef24da2378c43e528b4b912d823bce8987a9b908ac884fba7a03a2129996a60859761d8498e5b9e0c9afd9aaa901c8abfcd80a940ddd9731351deb918cc6177ce0c12cbb27695487e9de6fa23203dad7137e9eadc5259a3c850530c2283e1178c0b2395eedf183c3cf78ea4f3c20b3e80017f669ffc97649f439bd6476ab484b04e0de8e96b596b1994b6a99d732e54886daf9ec82d22e2bccab9ca64db92e1299302eeb031c667aebb0509f6a39e22f2bae56e7cbc06c9a1ab76c16ce0fe5ad92155b330f31830a1df7af51f1178e8aece7bf595152b2530199193eae8c4586af91eb1f713c45b08a87b75d825dee919881ccd9a6448dd2bd0767fadb16415c305825d7db8e01d89ca97821f0293acfb1e85b08d83349f37e99131d3766636d6c7f61afc77c059035cc090e95e987687f3d764264d2c82c1ae4c4766365977365f30b26ba23755dcb6b1545433284a4129dc39625156057f23c44103ba0f02706b16f630ccea0fe204d43d9ef162f0bf17fbf83a10816b66365cfd5b9c4aaa08ec8e1260540e9fdc19fcfd2dd91 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 9b1f5c7d045d72035019a18dac59247ac99cd251dfc74557f2623b6054043ce56b0c7e57b49205b3089e0e571e97ae1452feb784a45cdb9d04781487cdce43ab8f3d170d110030db96df844660a6029073d776669b9cad71b0ffd928195d36e88f18ee46238d3ba48346cb0279706817b48fd8a0cb7002f97f5f53ea419b60c3 +S = 3a9992cd8247ecf8ee650608b4520bbab5fa1774b8381c702930216b0dc6b9040b0dcae567c552ff5870a438d478c805edb56f396e9dfa422464b9559091aa231cc83ba676029936c204e58e473d93a8bb598135463614df6a54dc050f8db86bcfbc942979c3f011b8db0cea0b6bb0695ea1fb8c2f5872e4d89d9ae066b62b062156bba2ccf2be26ee1dce469219f387ec865f16d5b6babde6d0eca2efe1c9a51ec9f1f44a3cefe4eb054d33b80cf945c8bf530b9f8f924952d02fa75c410f3a57dbc2307f03a2cb9455f8a02e1b36b75f0f64087dcae1e639cd360da5d6a7394dcb7c1baeb4b323783cd3fbd207d8faaa5cc3b93867be4d47d934260129f0e51fd1dfb78b3c7c59f02b71be439722ed22654db5c1dc24b83785490ced8d0b97e11f85ee42f95582802446a38d812d59efbc6012a5dadf162aa0979a5de4fb7e4a19b4531c1b11231cb509f3dc05c74d90a1e2a8d9e6168da9fd226d5e53e0cd5ef93fc7ed638287207932f2b1451bab5c4bcabedf244585fa27e1a526cd9c7535768078c2b447cb30b6687d373295d6983ffa31083fd5230eb3574c4b65cb4bce0059d8e77e240d6be41f63fe98e94e76ea9969d8874f92c971a98d184ad6f78c33d5a1051a33b99c2d481ca3c06372f639d78e9601c20f93368ce8a1830d0c5b67aced9f2af6d3e8770321b209e271645e6909e251d31be1156d99f1204ab3 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 82f869cafa1e8bec3d9891bf59cf8f15a0581b41f223afe13ff64efb471a6a4ca45506dc0b1818d6cff83197a6625f05b08b5322b5a7bfe1af5b02388874077624d96ad7a2bedd55df1bcbc23c5d3b14a25bf600c38beccaa276d45b55691394096edfe2487aa41277e8a667a326e9ea7daf4e02a239fe44202f0b8c3661554d +S = 94d64e8a8f8ff9fb1fc76207b8be1a45f76f09bd0287baec04cc53e08639542dbaeeeaff537b0de30d63ffd961080d3b94708d60b364990c6db0c8ad673e6670f2c476ad7d7a957bf3c46e09fcca93812daf509ed7b88b182ce6f8315ec4787da0b4a0a09f6f48f2cd4a2cb3257abbb1b5c921a0db8c9de8bc64b98f4c347e27d5d063e232e4cfbaae6cb78effedf18ee5f7af1765cb95a3a8db21cf94166de19a0180f7c152f6b25ea2a68703d5d4443c27523baaa08cbedd2e489b0235f2203165f13169e7df9d930fbd7556fd594571a38f4eeb5b428694ac5b9858d233cc2bfe0d21e2fd6f599479024369b7f102b1624ba4160c48028017aae2fa815f7fa439b1545dec9b9e372f7cd8323c8bbf7e182b064deef2b65731d18d2241899f4f573fd9421a4b9a809e9876188db404cb262485761fd9bb315fd69db37601da5805e8e3fa7a64f654a11259c0764b28e53bffcf03d71683ece0fb9571aac451c085c1190353ed1c7a07bc03bd4abd0ce68c6a848a17720dcbb03231e1f505f1a6275d422dd89de55c0d70ada23f5240626c42e64bf33b668c69b6aad7b16534bb10d1aef16ee155df6b0ed2d3768e48171c62838a84c982713aaa5e982370fe10625687a5a960bfb205f85531dc093ba443abf4d22abf519b7db2afc36bae0c10283a551e5aa41c942c9a28fe199522da96b4bc2d640453c6bb495c258578fe +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420b2b9f428aca658a676034a1382b07d422f560f637c9fd49e258e742e065a852c +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = ee7d5046460f07173172b1dfc3382667b6080522b99da7580a115183475caefa82187ccc938785efb2d6d19a45a31aeff6be80dd092c7e45ec721d5b10106750f84b1f2e902faf03bfd562413fe2d365ad50a6d7dc7175116f300d04a79bdbb7799ea132e4116d9a81f6cc9d5cfb3b110247ded7db727506bad58b45b305f079 +S = 0642e1315d86676ff3f00490d4a2b8285333c7f7a14a152543d85a9f15fb2d54d60519d1896697b1ca9469c382469725455a7124191bc438b3566ed434bf318097e396c049aba9fc85a293ed4187d16bffeef55229cb52b950b504621cf13d683ccd6a0fb53e00d358551a8989c7afc09e34ec90f8286e7413de3decad04496b5a749a081c0e82ff71f6838780808270d72265e9abcf87f0e1f4439f0f7b3ab95729d4041a502573f94aa8fb1989dde4c2287335818f0fd03a72b4e6811249f665b0d05acff32069d80f570782f568bc851c434d82cc94fa168b6f2619a57a97284789bc41d9bbb29749bbbc3470c774079af80eba8287a2d53f4e14df1e619cc8b5e7709d5c54cd4b0cdcc8693c3d04b460c382531e749638736226a9ac2605f82eca3e3df3dae4f2e7cc70e0d39fd2772f193a4df10a25b58bfbc5497a0ee98e8f60cccedb1152741e52e53bbf3ec1a23bfa44b73753c60d69c1615c58739f2f093fbfd6c9ab25799cdd9e8b65bcac94af0ebab3f66780c3fdb486cb20427db12a97fd0257f1b7c956733304c4d30e3faa78c27bba260d697be1ef36eaae6c87d49f36112d7964ed7683fa47597fe58b212f19f4cc1d88805cad324fdf4ee05687421e827266d452a851401cc02c4af7a61fb1bd40f772bc1cca4e5955710f2e9ea23bec04ed7e3054fe8f1170c70935ee22384a43e82e1e855be59d428f8f +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 27331a2203df81efd7f4d19278bcbd4050c32f8fb6df3a93786e5147b6dfb62ff774343c764511f0bd893fc27511d2c47d15b7833933a22f2db548fcca13cfc787b882fd3409cab98ba4592c09e5a942fcafa582dc69a637de46a0cdc7ca9e7dfe8a6b2de63392916acd8997da412a02f519625447882df2b5aac283560c0a99 +S = 4bd55acc43b26d2e69cdee990682e40580642fcaa9c0057c2f3c6e3cff14234f8e7304ef16cd79ef50c6e52ea8b02a46915ec21371556d217da4f3820eff0dfbc1a3dfe8bb43756e2e829d4bb240742e604e1d6b1e3dcaf69f346839e0351cad7b10c165f34603864c47e6a01420e677a421352f4a20a18814b1fc0db029825ba182732ae1480cb1e18fd1ecfc6d0fb6b6bb32944580aad72dc7e9f0f9dd41c114f8a5e77a1a07da0b51ea830a5877ba964460d45ac122829976d459dd7e49b74130c201d413ac78525f75463f69bd2c9da63c848be84a240368b7dc004e4c26273e5ee4a0bbe2903bb59cc2200fafd222fa59a5cbce12ce1a375ad512284043aa4d44abf3846d9d21b3a27c28b03d5cac655f91fd17a9d0a15f450db44a09aee6deb337ff3837bd85045c2f716ea147f098ec2560655492427291a1619404c77985c860643e85e01a767a8367ea387f930686becd9cf51e6da3a5183ac306d30b42d7b41646355f77192939af92a248d9243144d6ed0c440c60e656d535d5e656d8d22df272daeb01336ed4f57f5dee8f8514d7a100e996ce32d06c1bdcfa8d490a53d0f4329052491e5f3173f0430f07f18869f866f8403a389b2be6b68efb44dcad6537a2e305500acda845b5f50e91433ad84a094c12c0a38682bdc3a54fd3f6b322cc72fbd2ec805748f7e82ee3e5fc4603140e3b0813cf81e1861fb2e4 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = c8ef4787dbd28656118a8cf26f182c77f48ffab67b6b522be3239c306c02cf6f6432349d041a6d6695eab5a3d67369d3a23dc8c9ced3f7a2516247faa782bb607754c50673cd51bd7f5104211684c611ea5d7e63cb7c1cd5cabddd469e0dca26477c832bf1943a451ae902d5f7f24a1a1417a4eb3c0bccac985ce57b1a4905aa +S = 578c8c3166a0199da16eb3f93eebe5d2bfc3ee668432bcd26d8c87ab349137f5392f60b66578eaaf47c3fc7ed0101ee650b51fd522f8d06474345eaa73e253f8b1c133a9a874c6234381ba4b8dc0494d1ff5d65167b0c46adb12538cfbc75ce1042e4d69cfaa4ef5083c08f91f03b295e0433597e0aea94dc596fd015b4770db71592b9f41e3b587313148a4a2784f1bde2755034bd99b15ae982e0e4ad4c9dc8f8d8ab06d692251520c813b540f5b514f88827ab94b879cf61bfbadff5277239079b90d023826f2a8f330c37bb3279d0ebf0659196cedbd91a347e8e0235a009d7f39fdad4faaffca75f6343fea2ec8c588776b64ec1371c90046ba5b6bb148a75c7748e11649442a77ed80e76a23b1c761b9e3636e3147ac6fe408fede1f4c7c7b8ca651abbbbd20d131218e2e43bcd2252b1b180678d9196c6067a0473c8c73f0610973807746b44c2bde619a5e4f4cb3371e260c47eaf31e935c025b523c39b659098369fff0215e17edda2985247c90b3d84676110e1344d538aa34dced5f97c71921406adca7bc1ec54ca66c43b7321497a71310f70184aa3691451f5207f455ad947e33c9f22f7a96fdc970c325a286848413fb092271a295bc0de317c0b76a2617fb0fdf2c792bcce16b9c3f5c4f03dddd7ca4b1adaa6f4dee058b1b3a2326086e5140ad8618c0c7517b148f1054b897548f881961d54bcea391f7a8 +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d06096086480165030402010500042077cab6a7538318a9ab5fb2c9399130c8fdd3064629374b4a49b2b88bee0e6463efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA256 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 5d5e9a1c2ab1b7c859c7cdbb21caf3fe77ace0bfdfb05af6832df249828fef2c8a9e884ca903562e60070813fa9f59201ba63fbb9c6965389668dcb5bd5b0e42f074f3460ee4871e0aa07b0642652a3d0cf9d06492b5f627e14031203c9d0cf8b66843d0005c32df7f198c5ca124509e7230f9826a9cf60d893c5952a75cd396 +S = 5b460ece8562655899aa4ffa98650e7043766b0b2735662ceaf6958df776efbb60c92330790a57cc26093db03f6dd9a02f0046de5f71397d496ffe41d70f4a0b2e98c0c080dbb546726cc4808e70cdb31d84c23c021c45b617c7778d102bad94ba0f98980211eff7ccdd43ea61c17d08f9e319bf6b36b56ca3dcd8b12a240d81cee2b7a7eb234dc822f610e2bc712eb1d9562d826f8fa902107487949fba4538ddbf5d41d161c55fb3fedd6d2c6f90ec177d672e136f1352f4d07d5c21f0173928292e310fbf40ea6d9e974ee5db68501069310b6255e0a541bcb335934e15f6e504807884cd46c91efa9e224f8402fcaef986da5f159a35a40ea221afcb9e00aaf968cacb7d720c2aa1c5025cbd2ae9e3857e857e9bb82981e43f3f197c1286ca0819a7caff78e3621807f2682fa10a49e7091419d99ff0f42ccd22c5b455ca8214117aaad92e46cfd8598dbb533b38d8a4d5f8cafe6caab99468a7bf540f5a7f15414c76b5b404a6cb855af8ad7d62c60959e489a40ded9898a3ee04fdd3de2f8ef95a207b226daa9e4ddcc688e7636fbaeddafc0282f5924f7ffca4f9cdd8115bb17c36ac2b8804c3afaccc1ed4057b97b59d01705cbeea65cac20c6623cdd66cccede7f1db9d98d567e5c48116159b8113f8247a879e0990c2a3ac8c817bf6c98902f8b497621a53ddbccb07d01b7f8694a45ee68d2d04a33cb3535db2e6 +SaltVal = 00 +Result = P + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 0a5d9e0c5ffd0d0eab672509388aa606fb5063e26d23aef59ab011f274eb3f0e6e5349654677159922b90dbcdf521470a696be4cc079c082ab53a5bf6de0c353288b6e92efec6b7ad88fa79652f72921b9e2466f28cf14898fbe2118053764845f8d735c0164f7f9f4715d5e3981cf635dbd63134e2c92526d79ebc3e4f708e8 +S = 31af3922e01de9d2ad34e11b89c1ec21ad76c2913375137206c779459c2db5fa9f180c1a061393f1106c7bd7c0c19e316f37f47f462e1fd870d05332ebaa582579f15e48729e5f8380c947f563244d08aa2104570334c60fa0a01a9f0bf9aae07e2e7c3e5de6acc71f8b3aabb9fe6036674d8eefee4fe7c0e5d3d9323e3fa92931c1a19689e53f4fa53381c4b73f8d91577ca7ce8128b88e8340b63f2e89a4618138c68ee53fb05ca95c94ecfc2526eebc9a38930c12c6f4416db316c507dbee0fe64a3bc66041aaf95f67d9a0294d97b4a4579e0f946fbf7309f042307fd3611f5ff2aab4a738410b62327d2b57cbfd05c5af3e6d61c794732fdf160e61b8bc6a4d3511668d2340bf6d2d1d46bd960e9be045d83bb71a93f1d9f72c67d8e318dc9c78da55758b660e2b1feb7ced2e8ff0a4a29e5febcb40078c92b8019db63551ab866959732aeba71a94df7c35d753e5a831da820d45f09a530176ed964387dda6e7e047302428583c16ace2f4a90f86539c756c0b7baf80a1475851920107fb9f742db3086067fa0c8a6a326f14ba69f8dee961e5cd7407dd5e6d74e81730492d03f825cceb96f2261f2d6b3bb48df1ccc07b9830df23aa26aac452d99d61bab38735b9daae68caa8a36ac7b57e01d181e6ad3321851bf42cfe627c0e2526af37abe7a8f454d754adbd24fccae6778547651d281354e2b167a21cb2e58a86 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = c265cc1668d494b6dbbf477f187eed2a862a49392b00b180200a1de342fc7d612b5c505261e572eccc2e350c6e87b4344e2364cfb57decbd9df4370b67b8c702ccea4c6416ff75f2906606313b6a2b6ec2590b00b0e6a1cde1ccc71036b494598d59e8d5f1ea45cf0db0e177e7f0f9e2cb136753840477b9d3daf77819b78d6c +S = 7b6e5c6672b76a49b637135878e9738da6b1ad1710a1f8c557c5de7c3a5364d4927f3497d6b7daedb931a65e3433dbfde8791af39c97e90437155a3eb3fc96c37d2b0a51126faee5706b0b73c63413f9082d6f0a3d2ad7fcc69e935c016a4abbb2295135bcef8c078e11e262c0c1038f4311926823cb1b148dd8e63942a927e806a84260e51341ff99eb02fa053dc9258b4113da1d76d0734f81234a51a196139171a90c60c9a6f6baadd3e3b99769bd1890984b3e434f94e9f27c7086d86ee86d45ddbd7130bde845b6c47b6dca29edcd6f7898a42e499555700683732feb4c2e200c0fb1e11c0f314682ead943aca08e276eacc1d67e02018690d159a7d50561bec7087c5e21b32bcf2b27c0245f410df9c137696f014befa4a0c13fe7302b44393bfe6e3747cd88ec2dff0c639bbca4e7ecb77f7989a35c2acdb6a9dbb70092a9b7f4f4c8c8d9f7286d9666b24393c95e2cc256c03645944fc7b194a73be5a6acca491c0a98e551aadf5b002a1c42d57149f6788697eda81d1735a85442b6b313ba798c92ec0464a4f02ec3cd5059694428e0961c93e75155d1e5f965e5956a82d7f9ebc51fae9ed151710768ff1c172ae2b68c81da2190575a35cbb5f9eb52f56ba5f838d05d40c35b9fe901a75d5d96e09b85841d68d055bca786514fc6249b136a22870379dbd54576a91b646406ed12445521b67c694e94626ed15f09 +SaltVal = 00 +EM with hash moved = 0001ffffffffff003041300d060960864801650304020205000430c0d206b5a6126ec9a86519315cb38f2484d00f36f2065d3a0dfe6f34657ad926ff281b90d8187ae2c2eb45c68643c352efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = f1fb8e6cfdfc5dd3931e8fb5c92b974650224e935787f170acfe69b22418d09f3e6d30a303eb8e45306d2758978ff976c3c185aadb9bd46dc871b8d49a2654072845def5f74da4465e4d4d91e7b162d0f75c0d11b2f7206e1988583e7546e48df9ac21caa3cca8c063e68ac87f39da3c36196c2ea442dd5ae56cd35a7d1f8619 +S = 2c0ce9b108db78aebb905e421bd0a993b38d9e6b66bba9cf5a9ad72fea11f0ea2a8eec30e7947fbd552c63535f2097e4d6ccf07024e833967a119abb869327d880ca2c21c3f32dd559eb8fb6090107832aa884eea6c9284231a6869013cb0654b3cf17cc87b39a9b7612e2c91f77ccbc1736d1c7e5816694632fed14bb764c4c4f5f80193b6fb9247026a3e754805f00cb8a73b62f01b6ca9206890aa3008e63a2ca87a0eb54affe1e94f2a676060921620ef8bfc8563abfc9006b8ed0f7c71cb8a987daa6d96c0b819e4d1cf279417998e8d9f7f4334186923a10d3ea888e0b8d8699494c9e5a0468345f1a93a79b436b864a4f84c74f77d95ac7095156d96d4b83000177cc33c8ff9f555bf5afd2968708eee4b10a397ab76c3ff22766caf8d3836b5d5fa7a580bceb6245063bfa74fa9d79cf2c61b8ab92a92ffd93eabeae820ddd5f4c94301bd7210b18142126267a1b2ef3f8725110ad570a7d46ef5a18fd32b031ebf23d0c4f56e134f76b667217d486845f93e965bca006934ef68d5e11f8edb1adcffaaa51b5b0f42959473c53348709ffea3963436dd7794aadee13aa24e1872152b9bbd031e71700a8924556b703c7be70d33e523d9ddddacf0641756468872c7ad17b71208c78fa993561d54aa6255b6abc5d1b9ea7c58f28554a76acc9f662e186a1aff26e6f7ce8c9ac20fb64cadfec72a08ece04b51bda01a7 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 879645d6b8014a368de5b3f59c0f6d61d05150fd6978461c447db0af5d00055c92f1bcd0aa916d55959933a7f5b85403de432482da2926a5312575316737623d05545f899d5d1c11084eefe2f2b8792d9971879ad18936de4c815b9018b821386926f4aa994c9e926d6bb04f9af52405874140ed5582bef01dfa2975786b8a77 +S = 2287114cfb12bbdf370c453bb39e68bea8c24afa1db85239b54f7ced68798dce71ccc3a283859cb67717b7d0299f28238cf05c9016e867203afc345498a98cc933165d1d2103263f0556ad6b89a408227b3d68909f1c31460f818da5a389033004e5d89909661995a6c98fa3a59a56869cefe67d06a7e5580e288a1d69eeffb1aed49e77adfa674123690d42f83411d807ee7fd5a2b21c055ebf9d393733c1fe96d9a9678814fbed5cf5478a54edb8e432524d0c05022a5b477c4fe901ae8b4a8e8d00b1519075fe5e160eb5b1c090a7b1deb970c7f900dd47c47bebcb3fb5334be683dadaf023660d0d82ac0de747f0982cc31428ebcabb03ab4eb46750331fa88db48c15b40dd18a83dce93e7e769db6dd32cb99a78243233d509528b03825ddd5eaf2f29b68396e23293607e8bd5455c23843f63304d5d3865943434b61f471e2b3464f37fadd3d29dd104b36c9f6f859f4d84446364fb56af34e9eb15882519b072b890d682b254d6461f997e056b42452a2346ac6f0653845d456b20c3a273a7d421295ff91871fb525c7274471ecdfa93c9358067dd4911a3010b629d0c2b3a2db23af2a4510d6230522b170b61e804ebf561c7ecf45c5b741c37141ee407809901d557e2c8f88e7a719f2d3b5952928722e96311b9a1ba5106cd5ae9d8d101d583d321fd42c68cf4c28d944ab9433153831e3884556d485c927970f25 +SaltVal = 00 +Result = P + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 92b5088f66c761117eefe5d57d490b0a2d8f735adaed7065f910c46f0e81aa55cc311ac67d5548afa4736ef7e1bdcb6d169febffc8942a2cc83d74bc12b44eaef51e1a72747f9658edd3a749f85a55b5923316cc7b2c4ff1dcd9186b2de3405e56a390fa14ef54f39f3418318ac5b0c8ea737b2aba5ee89c7e0b38e627b6864f +S = 50758bef01ca5623082d4fb6888e9c27598bdefd63abd5168c8a122d4bc26e45d50736136f9f28848b082f18ae69cc2c3cba98f3458cbe71167a6629ea604a606b7a10fba68edd1576367ef0551b1c0dac9ab830ba41d7c9825ddab0a4cf01c62669d3c7f434e18c6bba0c6b931f6317f66f0aa6694441bbb9cfb74220920d9d861a857cd984c0e35666eded9d6d67fead62231f2cef40fe4252d02aaa3b12418d26cb646128fa69e13c57f90a85a7606859f84da62feace94bfb607cbb8fce4c23006b1a3f0aa6724072ade5c1cc2c664556edb9d40ff63d0de44b35a68e81aea98e98d52883c4fe41cca6f1f09398251f28d30165f34b74b008af8742b93c8fb7586cef90efa60e0542f3f5f85dbee12b3008c834a13c587dbda2e570dd12149390fb7e8788b46502046e0e158c3aede9c789895af2508663d7d1b9ede251321800db59575bd7971bb9a93a2c0ad2ec377f0268e7b6eb404c0cc02055d0e69726176f39b8826b1bcf8f4df7a7ede44a5ebe2d862825d6b1c11e9a30ab838789bee11344aa1d88e8495792c68344fa889ee8c2dfa418b5fcd18ba7cce65018fb6ea8d00dee814084eac349f5a233f34b2921cc0f09b5f6b6aa4cdaf90196f14ea66dcc9ab1ccc4acc1ca2d097bff923252db6d19db50e877f6848e3a14dc8d799fd8a8722aa6e98b5b4e53225af9d2c40811c6967e525db1993ed1539fcecde +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430d6b9bb354aa8acf8326afd721b8bbb21603ef5d2f897c52cc0f27f9169f5bb894168a77ee4a65079fd68e9b38a7a4ea9 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA384 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 9a5592fd0be381aad74258865cab802a5f161df848a2e3a38e382af2706b45c0e6a31048d77bc99f8c672182659a9252ca27f25d6566495f8e99e04907cf9a40ea0987e9df9cb7e492d64c9665e4d32c62f3d5dc7396a86ed5688bfccaf2f3f68ecf1f688d0df280d3d7024bc451edbf0dc4ecfedafbaad94aed56931f9cf6e8 +S = 6b95909cfb0edba3177083097f74edac27b652bfd73575efac3db0971290bd7718b5a5491724c095a25c1a75b67a24a9e7caea4e2319637abe40efc0c5ce640a879978aac6ec898a4cce02b87cffb59f0c27c1c01759d7f698adf77003e033e70895e64a1f50f8cc471f61cb8e4c37a6a32e0875551b558314442fd7880c1fc74046b960f6fb4938ca6a7b1fc709cb046cb51c5fcf32c5d8e63324c88cd3ba6ff43406688771d1fd5ace55ccd8c90a96f403461f65c1cafd3068c4be660ccd740f34edcc1b4c57ee0e5ea5a3c2b9d76e583a9d1c70f480f508d589e72dfb0e5a6355bd70a2f90bddc1847d582d426f37b1060e475bfc62ca3133f4431407b948cbbf8ef4ec6488d773c5a840ffe2bf2cdd8a9aa753d0e66733daa5837f26eee99be7ac230fe0437898b6f9cf8e92419f0ee112d0475dfed75f8a8dfa4fe2f1e7d54da8fed8bd883f7326890f74a61beb22ad9822536bd3780f8a18573d16376f4f393e8e2305decfea889933b92d673569b4038d49547cde3c11e4f1331ded794c6fdb266c02048ce0be47b829e9be709ceaea89c3acfb12741332d147d8fe981b146955a29186f1b44f69ea276e78448d5752117eae565cfa54e6dda92387f330542dd30bb9426e1965a76a5a438f55ce22d252fd8e62df04c4e8c7a719385d4d56f37194f7e03368d17fe8165ed176d636b3b55fb99c483d707d160543561a +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = e0e52ff4aaaab424199c5cf2a172d1ebe64f7b6e2096fe19c400048161ec3c26c7f6a3a66fca0230173bb73cad8fb9796e1dd7074f1b40e79cb148b0df516983034b8840b99c7afa1b07c7a98f68ae1fef44693ee7a4b2679e2485359847286cdb0d692c50c8276b6d2b13a211a4b8c5afecb979afdc5a821182427a547480c9 +S = 8c61782fa17abd9424bd4df6333f775a1a36cb913fc3324d4a860c4619ab778ec699e88cbf7d55d8b9e7c9a4bf760ff1238c1b65f3d3afb50702c844706e855187ca2fbc92c18f5ac9558b8b719f7e985d791caf719721c66673026c393fd6fe4aaad8829188e5978ed401256ab8ece9d6713b55a0b8cce1c33b9dc333ed48d83bbbab4290471866d1d4d3e239daa5f315e18a19f78d7679ea1ba028032dfbca40ab0ac436f948a129c7d182911d0452548755a90dffa2294a4089c2a46352b1e76e06c203e230a0229989ddab4171deeef125af7ad0be3f28dd2d3cdaf25ef500d8d7134546bc79806ad7bc8dbdfd882f6924148b2480cffdd9d4ef0235385c76687fe669822ae14238736c4e8fa48d494ea578a6a940f07be7284274dbe9aabba9b6077d253eeaecd483f60763f8baee3d5e27a7c820c103160df87f875b10ffad7d810283fe118fd040b0e64b8b007aaa049a5ea739f85ad8245e0223f3bb3c66904bb89bb58eed61324ceb4b49b951de42d1ffff7ed9905050d05c73f34946562d5d39acf768f7be5292f20448bc5b61795fe077631587abc5465e67fff8118dbefda942bdbbe673eab46142f047d0359f112f64ba92eb54ee45b349bcb3befb89e31080d48303c90acafa4aa09466348b50f2923d29c1f9bf34dad7b3246653c7fd20f480b33ef3d9e116ddda73b7791f2fc5fc4c31bcac2bde5b79691f +SaltVal = 00 +Result = P + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 2fd1aa7be544c3206a9d43464b3fcd90f3f8cf48d08ec099b59ba6fe7d9bdcfaf244120aed1695d8be32d1b1cd6f143982ab945d635fb48a7c76831c0460851a3d62b7209c30cd9c2abdbe3d2a5282a9fcde1a6f418dd23c409bc351896b9b34d7d3a1a63bbaf3d677e612d4a80fa14829386a64b33fa217c9b26e8453e4a6b2 +S = 560a204f8a24adc61ac4d3c8de48304d9c59f6faf1bf1059bf1edb7e786ad81d95d6e17acfc30d84a151ff5496507da3094b7464839443d5530e22d6316076fadb5ffa013319230b14115e0905a997f4019dad2abde8d415a2b040bc6413c172a620a878d3695f70ffceb14fbeeb4538bf3c9b905e5907cba8ed8fc4a6ef9eeb863c99251abfaa9c483198618f2858a0c2d04a3f7e1e51128c9309303e01182cbfa20ea398c02354247fb30d32e977e6ea2dcc97be8921149257d13e31dde63b4992b167dd87f53116114a6344a3913ee313b4361d9258a2b10e9cefb19d0455466574bd58c0f284f99362737d0ad83d3ed0d587084f4e677a6748d68c1e3fee364600905873bb10de67b02e0aca45273ddb2f667aa22e885231b2bede0b541b79d2adf5e251be56e43b2577bba5244838471ed6899871016372771f88ebde49a776bb11697f15e50d490be4e52f95868f01bbd8ca549a60c50f1e99ddfe399f76fea48567e6abc0a845ddac6e963964624e38e1fb56565f99f3cdd7ddb7aebc3c53c7d82c6e3eeb058d128b4bacaca5f5fc8b037818d34c732fd15aeb70b0d688a233b5f91b65ff1f68cfa6f3a55b144840a9979996dfcfdf84cd9b02d385a842b27121cbe645155521e2c53ba3f1747af5609950b0cc808f33402dbb94fd1128fe9b309850b9ef11e82ec0498d595ff6436aab76a4df49047d76e5342c14b1 +SaltVal = 00 +Result = F (1 - Message changed) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 6ed981437f350723c4f1677f7bacdb78d12a22a19b3ed30646edf16d11d0bfdb79bad65af59b74fae4a41716c4ac4bd8a4d3c0ffdc659fe0fb011eab01fa53f0cffd4562dbf449da282b8c9f76b1ece4b6020c92c0e2a748488c24a00e0c6bb556eaf8e298082dcc78cdeda2f88366a3edfe2ee1b07f924515d82bd4a1d0b230 +S = 4684f8bc41880feaebaf54fc8cbb1d85c378db4bb916a7e162fa6683667b2f6df1e41e722f57e027486dd2c89ec035e2fe88ec082bbc105422b9116362bb00fac7f687297a858a08bea678d8489ce7cc27133c4f0acba0c7aee1daa55938ba2fc8957e6dca7493c0f054cc8a61d96b1d2689b1af69b491f58aeb6b3011827ad0d60bf1385402d4c7e7dac0f6f1259e7069a788816cce8db301639007ed1224bbdcbef9447df741cdb6a1f03796398372eb86ed8c995d281326a834688010becd7c737096de2573eb210035f14b937cf614cab6d1717711685e029b7b23d922bf2d6d63e354af5cf1b8609d021196e04a4e1baab203b1adce2b9c4bdf5a9a989157d2832867abc5173e5944ff070c9f7b06a14373fac3bfd76a73129e4cd0420c4696da9ef6f672f4cc9973434bcd2f0e351fe4509138d20a55bf73e42365da8d7ba3dd74b86055a785d346546de0f9837ecbcf52d6658e16e657b20428a8003a9b31d9f69e8206da1068fea98ea282a8731d96fe5e5be7d0b68c9eaf16090eea1f424e4cc5a509f8d6efb97f846d8ff1bd739288deeeecee6d0122eff6efbba9541ee1b2387f2092022df8584521d556bdc7ff9c8914d35a7b44075382fa3f03a3d4ec1ad11539cdf3b92eb37da08949c7ddbc2108e228c4548f41224b4da41098ae67a048be0fd22254a49186360bd0cea7877621130af6b8abfb490a108ab0 +SaltVal = 00 +Result = F (2 - Public Key e changed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 3a33da20cfb3e3ac722e7df7865330b8f62a73d9119a1f21992e240f16197b0970775cb6bdd5b0a858f4c93e33ca51c86eca80ed2865924a95d1795c5009cfa0f3150ef8e68b03517456808324b6527846887291ccc880455b546c0ca2f2777beb955ab0efdcc4f0efdc0a8f001f1a10a7ecb28ea5c9cf5b143f67e6b3dd5ae2 +S = 2fd9e8beeb55cf3640f615951e25b1731e1c51b4a1a2f251ff2761c3de6393c00f1ee2876e103a38c3149eafb804efa687b953eaf86b270d6cef192869aacc206f2018067df43db0ad8de6687ecd0535ed299180521066553ae2e6ed21604193eac012986767e48aea294fa3769482bcd2c167723707284dbcc7849d8320220319f7087baae33e7d05cab1e1430d3b2ba0e9ec5c5620f097c13b5a5a7c286ec9061f1963d27aafd79e2a217da1cb99389a5335ceb7690db3ce5cac022a542c14be25cb3e090400653a46863f443bd40807c546916b8090098fc5416744aa8d167bbcd48d718f5fee47339ec5446bbcb53ff6270f761e57589c399b558a24da5a5b3121a4a296e1ee1e01395f20b967c6cfaf2dd92e6e9fbc7c866b910570808e8dc87b66a8d9518dd9829f71f6a5e7e544e86551d907fcf2da2f4707e19586c19598a063ec1bfb252d91449f22ca90f2f88bbc6266ede3c19912a2481f70795a0a6ab6c1644a9458f9dce7a6459587135f5e3f20944a00d0874ff3b748a12a81e54a33da1a65df5dd932dbd979c79116e7d1138d35abf18b2a82c364490975c118c194c102a7c0eae6c629ec8043f9c55b63e55eacb3b352250ef5fa489ace55ec6b0771711aefd26f35483dacabe89fd15e248f669b5b2c343ba9de80b523432b9a0e4b05486c0132c4e1608f49efd481aed7b6da2ddd78fd5bafefcef2f074 +SaltVal = 00 +EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d060960864801650304020305000440ece68078ae14353fad83f9da0bc52f954e4f83bdc06abda384df386e15c66759f7a78859e7627c41d5c146cb5f8a46a147f1bb3ce2fbccd6d7efaa3d098c0a64 +Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 244581a2b06130d1af01b83ab281dc252d97481cd92819575660a0781501637975fb65e22c3ea83fe9ccefd13812c884a578ca2124371cc5b06a37923369eca4a652a84679e8f76635a1474760faef76a10e6fff2467f9e0401431be57fb32d7fe71d1385e082530daa84704f3e256e46880be1ea161ba924d8418664b623dfb +S = 45b532bc216a9e6c0b58ef1e500e0cfc11cb85614faa4301e5c373acbb46f1fa655975b8fe4d50098f5b1ffff7e45db3e339b27b2d6d3349fa952922b876dd333c862bacf6cf4d3b1b98fca4adc2a4674b0397326ebad63a553f97cbf763d5549e982b999eaa77dfa074311d236936056a2f097385136ea5d82f76190e4a896bd5c2ef3580eb98340b136dae2215c3ec324ad44fa1920213fc6985faa58fab2a5ab4f1c268dc1489c4f257e54c573247a6e32640780f7345dcd7c371de12696a2fff5d94ab9677914d3d21fd0b436405b8122f410a3374ed67c8b414120a1c50c18b6a8acaff5bb68b2ced8036d30045378402e4cd193cfab277e9808045b30c65f947f39c4b3b25af8130a46d03fef6ab01c8d3a5807ff6a96628523fcd8447f24d11cbad36b5553f5d4c8051739a700d6113d48e3c28bee871fc00c46b013e887ba957ab45911f056d4b98c00b4e6b5b02b1d674918b90b40ca688e096ad0705d6f72e4999b0cbe9ed94cb297df6872e02fbd3ed2a8be758d4e6af7fa416b14d6785852b2a06d001e1b10e9829e3c6ad27bb2f1ce05104115decac07ff9c4e3cbb0bc0d264e9f27e9dcb48a9d8ce44b5e6cb37defc81e282071eb0ea06285c5afed12fa5b509a54449dbcd19431ad4522348ab0aed336c351709d3aa717d1e453362bc65d041af2fa7c1328231420741b433373e78d98f23940d6e59c132e7 +SaltVal = 00 +Result = F (3 - Signature changed ) + +SHAAlg = SHA512 +e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 +d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d +Msg = 24c8f1e99508bd234cf1161e94b439ac41e6392994d4ff685e178fee68688e5e13b501353c7458b76237ab2a0b80434163d75cdb271b29eec11619bdb55359523b349a282d3f142824b9cbd6df7611cde4ef4c696995f9c37465f1e242bdeb2fe66e432a3212fa5cdaa0fd8cd73daa360a55903922eb76d0bf2d9fc3d74c4ddf +S = 3941bb2afeacc1962b51ffecb000ed9406ba6e0935006203eac5aab1e35b980e6b3bbacf6d79f249e2c0fcd4259298d659870fbfa7e5c78d0e72aec15768e9e9d7353369ef2c91240645dfe40d85f68026bc4aff204798ad20cdf05a66640f6885ab633597636cd5af965ef1d2bdcc5dd0922f23e150ba67cdf148421d6ed43349b2ab426af2c9609eda45b980c842c2817513f8d0ec7c1b404fe07a7269088e359948fa05a6d63d3002f88ccd3167dc30242a42a07b17940a4f5763013800fefced30d42daef920e15d167e6bef092d440be42624e6f855ab7842a8871140dc17458f479933e082f1794a4c56cb338d31ca4f5bc6983dc2ec124e6785b16a0530b4c7e33488da83a184aff5448277a61c32cf6a8a4995a939552e0cad8d37da113b7806510577af56f9abfc7a37c566405be6d0b3271d8dd9071a0e83c51467f2fd3d22c805bc9ea025d1b1033a99235acb145729df2b6dcd761196c74b02f8aec2b53d19c20be6b3f7e46c21690737c675d46d240d6774278c0dc7db0a817b570cd493530d2acc0685bb1d51a81992ba45a3acbb690467fcd2524deef1b2efd643cac753d86a760c9428427a7b5cfe2624efdcca0f4c2c02ae67c3e3df01c4a19c3172377b425834c1c376366eab600693f63ece2d6ff94412f768a9dba4d202d70a9324f76b2f58295015164213c71d3bae7b90edd800ada1d972353f320c +SaltVal = 00 +EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d060960864801650304020305000440f8b77aee7f4480f3de4575717e774c7735f9d46cfbc3706fcc2cbfed078b75fa59223ba0cda570d5bdf5ba1bd9d087f37e36b22b65552b85cfcc01a7b30c7f78efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef +Result = F (4 - Format of the EM is incorrect - hash moved to left ) diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js new file mode 100644 index 0000000..1436196 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js @@ -0,0 +1,416 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const precompile = require('../../helpers/precompiles'); +const { P256SigningKey, NonNativeSigner } = require('../../helpers/signers'); + +const TEST_MESSAGE = ethers.id('OpenZeppelin'); +const TEST_MESSAGE_HASH = ethers.hashMessage(TEST_MESSAGE); + +const WRONG_MESSAGE = ethers.id('Nope'); +const WRONG_MESSAGE_HASH = ethers.hashMessage(WRONG_MESSAGE); + +const aliceP256 = new NonNativeSigner(P256SigningKey.random()); +const bobP256 = new NonNativeSigner(P256SigningKey.random()); + +async function fixture() { + const [signer, extraSigner, other] = await ethers.getSigners(); + const mock = await ethers.deployContract('$SignatureChecker'); + const wallet = await ethers.deployContract('ERC1271WalletMock', [signer]); + const wallet2 = await ethers.deployContract('ERC1271WalletMock', [extraSigner]); + const malicious = await ethers.deployContract('ERC1271MaliciousMock'); + const signature = await signer.signMessage(TEST_MESSAGE); + const verifier = await ethers.deployContract('ERC7913P256Verifier'); + + return { signer, other, extraSigner, mock, wallet, wallet2, malicious, signature, verifier }; +} + +describe('SignatureChecker (ERC1271)', function () { + before('deploying', async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('EOA account', function () { + it('with matching signer and signature', async function () { + await expect( + this.mock.$isValidSignatureNow(ethers.Typed.address(this.signer.address), TEST_MESSAGE_HASH, this.signature), + ).to.eventually.be.true; + }); + + it('with invalid signer', async function () { + await expect( + this.mock.$isValidSignatureNow(ethers.Typed.address(this.other.address), TEST_MESSAGE_HASH, this.signature), + ).to.eventually.be.false; + }); + + it('with invalid signature', async function () { + await expect( + this.mock.$isValidSignatureNow(ethers.Typed.address(this.signer.address), WRONG_MESSAGE_HASH, this.signature), + ).to.eventually.be.false; + }); + }); + + describe('ERC1271 wallet', function () { + for (const fn of ['isValidERC1271SignatureNow', 'isValidSignatureNow']) { + describe(fn, function () { + it('with matching signer and signature', async function () { + await expect( + this.mock.getFunction(`$${fn}`)( + ethers.Typed.address(this.wallet.target), + TEST_MESSAGE_HASH, + this.signature, + ), + ).to.eventually.be.true; + }); + + it('with invalid signer', async function () { + await expect( + this.mock.getFunction(`$${fn}`)(ethers.Typed.address(this.mock.target), TEST_MESSAGE_HASH, this.signature), + ).to.eventually.be.false; + }); + + it('with identity precompile', async function () { + await expect( + this.mock.getFunction(`$${fn}`)( + ethers.Typed.address(precompile.identity), + TEST_MESSAGE_HASH, + this.signature, + ), + ).to.eventually.be.false; + }); + + it('with invalid signature', async function () { + await expect( + this.mock.getFunction(`$${fn}`)( + ethers.Typed.address(this.wallet.target), + WRONG_MESSAGE_HASH, + this.signature, + ), + ).to.eventually.be.false; + }); + + it('with malicious wallet', async function () { + await expect( + this.mock.getFunction(`$${fn}`)( + ethers.Typed.address(this.malicious.target), + TEST_MESSAGE_HASH, + this.signature, + ), + ).to.eventually.be.false; + }); + }); + } + }); + + describe('ERC7913', function () { + describe('isValidSignatureNow', function () { + describe('with EOA signer', function () { + it('with matching signer and signature', async function () { + const eoaSigner = ethers.zeroPadValue(this.signer.address, 20); + const signature = await this.signer.signMessage(TEST_MESSAGE); + await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(eoaSigner), TEST_MESSAGE_HASH, signature)).to + .eventually.be.true; + }); + + it('with invalid signer', async function () { + const eoaSigner = ethers.zeroPadValue(this.other.address, 20); + const signature = await this.signer.signMessage(TEST_MESSAGE); + await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(eoaSigner), TEST_MESSAGE_HASH, signature)).to + .eventually.be.false; + }); + + it('with invalid signature', async function () { + const eoaSigner = ethers.zeroPadValue(this.signer.address, 20); + const signature = await this.signer.signMessage(TEST_MESSAGE); + await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(eoaSigner), WRONG_MESSAGE_HASH, signature)).to + .eventually.be.false; + }); + }); + + describe('with ERC-1271 wallet', function () { + it('with matching signer and signature', async function () { + const walletSigner = ethers.zeroPadValue(this.wallet.target, 20); + const signature = await this.signer.signMessage(TEST_MESSAGE); + await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(walletSigner), TEST_MESSAGE_HASH, signature)) + .to.eventually.be.true; + }); + + it('with invalid signer', async function () { + const walletSigner = ethers.zeroPadValue(this.mock.target, 20); + const signature = await this.signer.signMessage(TEST_MESSAGE); + await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(walletSigner), TEST_MESSAGE_HASH, signature)) + .to.eventually.be.false; + }); + + it('with invalid signature', async function () { + const walletSigner = ethers.zeroPadValue(this.wallet.target, 20); + const signature = await this.signer.signMessage(TEST_MESSAGE); + await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(walletSigner), WRONG_MESSAGE_HASH, signature)) + .to.eventually.be.false; + }); + }); + + describe('with ERC-7913 verifier', function () { + it('with matching signer and signature', async function () { + const signer = ethers.concat([ + this.verifier.target, + aliceP256.signingKey.publicKey.qx, + aliceP256.signingKey.publicKey.qy, + ]); + const signature = await aliceP256.signMessage(TEST_MESSAGE); + + await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(signer), TEST_MESSAGE_HASH, signature)).to + .eventually.be.true; + }); + + it('with invalid verifier', async function () { + const signer = ethers.concat([ + this.mock.target, // invalid verifier + aliceP256.signingKey.publicKey.qx, + aliceP256.signingKey.publicKey.qy, + ]); + const signature = await aliceP256.signMessage(TEST_MESSAGE); + + await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(signer), TEST_MESSAGE_HASH, signature)).to + .eventually.be.false; + }); + + it('with invalid key', async function () { + const signer = ethers.concat([this.verifier.target, ethers.randomBytes(32)]); + const signature = await aliceP256.signMessage(TEST_MESSAGE); + + await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(signer), TEST_MESSAGE_HASH, signature)).to + .eventually.be.false; + }); + + it('with invalid signature', async function () { + const signer = ethers.concat([ + this.verifier.target, + aliceP256.signingKey.publicKey.qx, + aliceP256.signingKey.publicKey.qy, + ]); + const signature = ethers.randomBytes(65); // invalid (random) signature + + await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(signer), TEST_MESSAGE_HASH, signature)).to + .eventually.be.false; + }); + + it('with signer too short', async function () { + const signer = ethers.randomBytes(19); // too short + const signature = await aliceP256.signMessage(TEST_MESSAGE); + await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(signer), TEST_MESSAGE_HASH, signature)).to + .eventually.be.false; + }); + }); + }); + + describe('areValidSignaturesNow', function () { + const sortSigners = (...signers) => + signers.sort(({ signer: a }, { signer: b }) => ethers.keccak256(b) - ethers.keccak256(a)); + + it('should validate a single signature', async function () { + const signer = ethers.zeroPadValue(this.signer.address, 20); + const signature = await this.signer.signMessage(TEST_MESSAGE); + + await expect(this.mock.$areValidSignaturesNow(TEST_MESSAGE_HASH, [signer], [signature])).to.eventually.be.true; + }); + + it('should validate multiple signatures with different signer types', async function () { + const signers = sortSigners( + { + signer: ethers.zeroPadValue(this.signer.address, 20), + signature: await this.signer.signMessage(TEST_MESSAGE), + }, + { + signer: ethers.zeroPadValue(this.wallet.target, 20), + signature: await this.signer.signMessage(TEST_MESSAGE), + }, + { + signer: ethers.concat([ + this.verifier.target, + aliceP256.signingKey.publicKey.qx, + aliceP256.signingKey.publicKey.qy, + ]), + signature: await aliceP256.signMessage(TEST_MESSAGE), + }, + ); + + await expect( + this.mock.$areValidSignaturesNow( + TEST_MESSAGE_HASH, + signers.map(({ signer }) => signer), + signers.map(({ signature }) => signature), + ), + ).to.eventually.be.true; + }); + + it('should validate multiple EOA signatures', async function () { + const signers = sortSigners( + { + signer: ethers.zeroPadValue(this.signer.address, 20), + signature: await this.signer.signMessage(TEST_MESSAGE), + }, + { + signer: ethers.zeroPadValue(this.extraSigner.address, 20), + signature: await this.extraSigner.signMessage(TEST_MESSAGE), + }, + ); + + await expect( + this.mock.$areValidSignaturesNow( + TEST_MESSAGE_HASH, + signers.map(({ signer }) => signer), + signers.map(({ signature }) => signature), + ), + ).to.eventually.be.true; + }); + + it('should validate multiple ERC-1271 wallet signatures', async function () { + const signers = sortSigners( + { + signer: ethers.zeroPadValue(this.wallet.target, 20), + signature: await this.signer.signMessage(TEST_MESSAGE), + }, + { + signer: ethers.zeroPadValue(this.wallet2.target, 20), + signature: await this.extraSigner.signMessage(TEST_MESSAGE), + }, + ); + + await expect( + this.mock.$areValidSignaturesNow( + TEST_MESSAGE_HASH, + signers.map(({ signer }) => signer), + signers.map(({ signature }) => signature), + ), + ).to.eventually.be.true; + }); + + it('should validate multiple ERC-7913 signatures (ordered by ID)', async function () { + const signers = sortSigners( + { + signer: ethers.concat([ + this.verifier.target, + aliceP256.signingKey.publicKey.qx, + aliceP256.signingKey.publicKey.qy, + ]), + signature: await aliceP256.signMessage(TEST_MESSAGE), + }, + { + signer: ethers.concat([ + this.verifier.target, + bobP256.signingKey.publicKey.qx, + bobP256.signingKey.publicKey.qy, + ]), + signature: await bobP256.signMessage(TEST_MESSAGE), + }, + ); + + await expect( + this.mock.$areValidSignaturesNow( + TEST_MESSAGE_HASH, + signers.map(({ signer }) => signer), + signers.map(({ signature }) => signature), + ), + ).to.eventually.be.true; + }); + + it('should validate multiple ERC-7913 signatures (unordered)', async function () { + const signers = sortSigners( + { + signer: ethers.concat([ + this.verifier.target, + aliceP256.signingKey.publicKey.qx, + aliceP256.signingKey.publicKey.qy, + ]), + signature: await aliceP256.signMessage(TEST_MESSAGE), + }, + { + signer: ethers.concat([ + this.verifier.target, + bobP256.signingKey.publicKey.qx, + bobP256.signingKey.publicKey.qy, + ]), + signature: await bobP256.signMessage(TEST_MESSAGE), + }, + ).reverse(); // reverse + + await expect( + this.mock.$areValidSignaturesNow( + TEST_MESSAGE_HASH, + signers.map(({ signer }) => signer), + signers.map(({ signature }) => signature), + ), + ).to.eventually.be.true; + }); + + it('should return false if any signature is invalid', async function () { + const signers = sortSigners( + { + signer: ethers.zeroPadValue(this.signer.address, 20), + signature: await this.signer.signMessage(TEST_MESSAGE), + }, + { + signer: ethers.zeroPadValue(this.extraSigner.address, 20), + signature: await this.extraSigner.signMessage(WRONG_MESSAGE), + }, + ); + + await expect( + this.mock.$areValidSignaturesNow( + TEST_MESSAGE_HASH, + signers.map(({ signer }) => signer), + signers.map(({ signature }) => signature), + ), + ).to.eventually.be.false; + }); + + it('should return false if there are duplicate signers', async function () { + const signers = sortSigners( + { + signer: ethers.zeroPadValue(this.signer.address, 20), + signature: await this.signer.signMessage(TEST_MESSAGE), + }, + { + signer: ethers.zeroPadValue(this.signer.address, 20), + signature: await this.signer.signMessage(TEST_MESSAGE), + }, + ); + + await expect( + this.mock.$areValidSignaturesNow( + TEST_MESSAGE_HASH, + signers.map(({ signer }) => signer), + signers.map(({ signature }) => signature), + ), + ).to.eventually.be.false; + }); + + it('should return false if signatures array length does not match signers array length', async function () { + const signers = sortSigners( + { + signer: ethers.zeroPadValue(this.signer.address, 20), + signature: await this.signer.signMessage(TEST_MESSAGE), + }, + { + signer: ethers.zeroPadValue(this.extraSigner.address, 20), + signature: await this.extraSigner.signMessage(TEST_MESSAGE), + }, + ); + + await expect( + this.mock.$areValidSignaturesNow( + TEST_MESSAGE_HASH, + signers.map(({ signer }) => signer), + signers.map(({ signature }) => signature).slice(1), + ), + ).to.eventually.be.false; + }); + + it('should pass with empty arrays', async function () { + await expect(this.mock.$areValidSignaturesNow(TEST_MESSAGE_HASH, [], [])).to.eventually.be.true; + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ecdsa_secp256r1_sha256_p1363_test.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ecdsa_secp256r1_sha256_p1363_test.json new file mode 100644 index 0000000..9cd94cf --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ecdsa_secp256r1_sha256_p1363_test.json @@ -0,0 +1,3719 @@ +{ + "algorithm" : "ECDSA", + "generatorVersion" : "0.8r12", + "numberOfTests" : 219, + "header" : [ + "Test vectors of type EcdsaVerify are meant for the verification", + "of IEEE P1363 encoded ECDSA signatures." + ], + "notes" : { + "EdgeCase" : "Edge case values such as r=1 and s=0 can lead to forgeries if the ECDSA implementation does not check boundaries and computes s^(-1)==0.", + "PointDuplication" : "Some implementations of ECDSA do not handle duplication and points at infinity correctly. This is a test vector that has been specially crafted to check for such an omission.", + "SigSize" : "The size of the signature should always be twice the number of bytes of the size of the order. But some libraries accept signatures with less bytes." + }, + "schema" : "ecdsa_p1363_verify_schema.json", + "testGroups" : [ + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "KSexBRK64-3c_kZ4KBKLrSkDJpkZ9whgacjE32xzKDg", + "y" : "x3h5ZOqsAOWSH7FJimD0YGdms9loUAFVjRqXTnNBUT4" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "042927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e", + "wx" : "2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838", + "wy" : "00c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200042927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKSexBRK64+3c/kZ4KBKLrSkDJpkZ\n9whgacjE32xzKDjHeHlk6qwA5ZIfsUmKYPRgZ2az2WhQAVWNGpdOc0FRPg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 1, + "comment" : "signature malleability", + "msg" : "313233343030", + "sig" : "2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e184cd60b855d442f5b3c7b11eb6c4e0ae7525fe710fab9aa7c77a67f79e6fadd76", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 2, + "comment" : "Modified r or s, e.g. by adding or subtracting the order of the group", + "msg" : "313233343030", + "sig" : "012ba3a8bd6b94d5ed80a6d9d1190a436ebccc0833490686deac8635bcb9bf536900b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db", + "result" : "invalid", + "flags" : [] + }, + { + "tcId" : 3, + "comment" : "Modified r or s, e.g. by adding or subtracting the order of the group", + "msg" : "313233343030", + "sig" : "d45c5740946b2a147f59262ee6f5bc90bd01ed280528b62b3aed5fc93f06f739b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db", + "result" : "invalid", + "flags" : [] + }, + { + "tcId" : 4, + "comment" : "Modified r or s, e.g. by adding or subtracting the order of the group", + "msg" : "313233343030", + "sig" : "012ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e1800b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db", + "result" : "invalid", + "flags" : [] + }, + { + "tcId" : 5, + "comment" : "Modified r or s, e.g. by adding or subtracting the order of the group", + "msg" : "313233343030", + "sig" : "d45c5741946b2a137f59262ee6f5bc91001af27a5e1117a64733950642a3d1e8b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db", + "result" : "invalid", + "flags" : [] + }, + { + "tcId" : 6, + "comment" : "Modified r or s, e.g. by adding or subtracting the order of the group", + "msg" : "313233343030", + "sig" : "002ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e1801b329f478a2bbd0a6c384ee1493b1f518276e0e4a5375928d6fcd160c11cb6d2c", + "result" : "invalid", + "flags" : [] + }, + { + "tcId" : 7, + "comment" : "Modified r or s, e.g. by adding or subtracting the order of the group", + "msg" : "313233343030", + "sig" : "002ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e1801b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db", + "result" : "invalid", + "flags" : [] + }, + { + "tcId" : 8, + "comment" : "Modified r or s, e.g. by adding or subtracting the order of the group", + "msg" : "313233343030", + "sig" : "2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e184cd60b865d442f5a3c7b11eb6c4e0ae79578ec6353a20bf783ecb4b6ea97b825", + "result" : "invalid", + "flags" : [] + }, + { + "tcId" : 9, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 10, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 11, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "0000000000000000000000000000000000000000000000000000000000000000ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 12, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "0000000000000000000000000000000000000000000000000000000000000000ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 13, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "0000000000000000000000000000000000000000000000000000000000000000ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 14, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "0000000000000000000000000000000000000000000000000000000000000000ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 15, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "0000000000000000000000000000000000000000000000000000000000000000ffffffff00000001000000000000000000000001000000000000000000000000", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 16, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 17, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 18, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "0000000000000000000000000000000000000000000000000000000000000001ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 19, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "0000000000000000000000000000000000000000000000000000000000000001ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 20, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "0000000000000000000000000000000000000000000000000000000000000001ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 21, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "0000000000000000000000000000000000000000000000000000000000000001ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 22, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "0000000000000000000000000000000000000000000000000000000000000001ffffffff00000001000000000000000000000001000000000000000000000000", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 23, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325510000000000000000000000000000000000000000000000000000000000000000", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 24, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325510000000000000000000000000000000000000000000000000000000000000001", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 25, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 26, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 27, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 28, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 29, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551ffffffff00000001000000000000000000000001000000000000000000000000", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 30, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325500000000000000000000000000000000000000000000000000000000000000000", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 31, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325500000000000000000000000000000000000000000000000000000000000000001", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 32, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 33, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 34, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 35, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 36, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550ffffffff00000001000000000000000000000001000000000000000000000000", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 37, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325520000000000000000000000000000000000000000000000000000000000000000", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 38, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325520000000000000000000000000000000000000000000000000000000000000001", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 39, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 40, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 41, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 42, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 43, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552ffffffff00000001000000000000000000000001000000000000000000000000", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 44, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 45, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 46, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000001000000000000000000000000ffffffffffffffffffffffffffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 47, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000001000000000000000000000000ffffffffffffffffffffffffffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 48, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000001000000000000000000000000ffffffffffffffffffffffffffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 49, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000001000000000000000000000000ffffffffffffffffffffffffffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 50, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000001000000000000000000000000ffffffffffffffffffffffffffffffff00000001000000000000000000000001000000000000000000000000", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 51, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 52, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 53, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000001000000000000000000000001000000000000000000000000ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 54, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000001000000000000000000000001000000000000000000000000ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 55, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000001000000000000000000000001000000000000000000000000ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 56, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000001000000000000000000000001000000000000000000000000ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 57, + "comment" : "Signature with special case values for r and s", + "msg" : "313233343030", + "sig" : "ffffffff00000001000000000000000000000001000000000000000000000000ffffffff00000001000000000000000000000001000000000000000000000000", + "result" : "invalid", + "flags" : [ + "EdgeCase" + ] + }, + { + "tcId" : 58, + "comment" : "Edge case for Shamir multiplication", + "msg" : "3639383139", + "sig" : "64a1aab5000d0e804f3e2fc02bdee9be8ff312334e2ba16d11547c97711c898e6af015971cc30be6d1a206d4e013e0997772a2f91d73286ffd683b9bb2cf4f1b", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 59, + "comment" : "special case hash", + "msg" : "343236343739373234", + "sig" : "16aea964a2f6506d6f78c81c91fc7e8bded7d397738448de1e19a0ec580bf266252cd762130c6667cfe8b7bc47d27d78391e8e80c578d1cd38c3ff033be928e9", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 60, + "comment" : "special case hash", + "msg" : "37313338363834383931", + "sig" : "9cc98be2347d469bf476dfc26b9b733df2d26d6ef524af917c665baccb23c882093496459effe2d8d70727b82462f61d0ec1b7847929d10ea631dacb16b56c32", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 61, + "comment" : "special case hash", + "msg" : "3130333539333331363638", + "sig" : "73b3c90ecd390028058164524dde892703dce3dea0d53fa8093999f07ab8aa432f67b0b8e20636695bb7d8bf0a651c802ed25a395387b5f4188c0c4075c88634", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 62, + "comment" : "special case hash", + "msg" : "33393439343031323135", + "sig" : "bfab3098252847b328fadf2f89b95c851a7f0eb390763378f37e90119d5ba3ddbdd64e234e832b1067c2d058ccb44d978195ccebb65c2aaf1e2da9b8b4987e3b", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 63, + "comment" : "special case hash", + "msg" : "31333434323933303739", + "sig" : "204a9784074b246d8bf8bf04a4ceb1c1f1c9aaab168b1596d17093c5cd21d2cd51cce41670636783dc06a759c8847868a406c2506fe17975582fe648d1d88b52", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 64, + "comment" : "special case hash", + "msg" : "33373036323131373132", + "sig" : "ed66dc34f551ac82f63d4aa4f81fe2cb0031a91d1314f835027bca0f1ceeaa0399ca123aa09b13cd194a422e18d5fda167623c3f6e5d4d6abb8953d67c0c48c7", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 65, + "comment" : "special case hash", + "msg" : "333433363838373132", + "sig" : "060b700bef665c68899d44f2356a578d126b062023ccc3c056bf0f60a237012b8d186c027832965f4fcc78a3366ca95dedbb410cbef3f26d6be5d581c11d3610", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 66, + "comment" : "special case hash", + "msg" : "31333531353330333730", + "sig" : "9f6adfe8d5eb5b2c24d7aa7934b6cf29c93ea76cd313c9132bb0c8e38c96831db26a9c9e40e55ee0890c944cf271756c906a33e66b5bd15e051593883b5e9902", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 67, + "comment" : "special case hash", + "msg" : "36353533323033313236", + "sig" : "a1af03ca91677b673ad2f33615e56174a1abf6da168cebfa8868f4ba273f16b720aa73ffe48afa6435cd258b173d0c2377d69022e7d098d75caf24c8c5e06b1c", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 68, + "comment" : "special case hash", + "msg" : "31353634333436363033", + "sig" : "fdc70602766f8eed11a6c99a71c973d5659355507b843da6e327a28c11893db93df5349688a085b137b1eacf456a9e9e0f6d15ec0078ca60a7f83f2b10d21350", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 69, + "comment" : "special case hash", + "msg" : "34343239353339313137", + "sig" : "b516a314f2fce530d6537f6a6c49966c23456f63c643cf8e0dc738f7b876e675d39ffd033c92b6d717dd536fbc5efdf1967c4bd80954479ba66b0120cd16fff2", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 70, + "comment" : "special case hash", + "msg" : "3130393533323631333531", + "sig" : "3b2cbf046eac45842ecb7984d475831582717bebb6492fd0a485c101e29ff0a84c9b7b47a98b0f82de512bc9313aaf51701099cac5f76e68c8595fc1c1d99258", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 71, + "comment" : "special case hash", + "msg" : "35393837333530303431", + "sig" : "30c87d35e636f540841f14af54e2f9edd79d0312cfa1ab656c3fb15bfde48dcf47c15a5a82d24b75c85a692bd6ecafeb71409ede23efd08e0db9abf6340677ed", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 72, + "comment" : "special case hash", + "msg" : "33343633303036383738", + "sig" : "38686ff0fda2cef6bc43b58cfe6647b9e2e8176d168dec3c68ff262113760f52067ec3b651f422669601662167fa8717e976e2db5e6a4cf7c2ddabb3fde9d67d", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 73, + "comment" : "special case hash", + "msg" : "39383137333230323837", + "sig" : "44a3e23bf314f2b344fc25c7f2de8b6af3e17d27f5ee844b225985ab6e2775cf2d48e223205e98041ddc87be532abed584f0411f5729500493c9cc3f4dd15e86", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 74, + "comment" : "special case hash", + "msg" : "33323232303431303436", + "sig" : "2ded5b7ec8e90e7bf11f967a3d95110c41b99db3b5aa8d330eb9d638781688e97d5792c53628155e1bfc46fb1a67e3088de049c328ae1f44ec69238a009808f9", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 75, + "comment" : "special case hash", + "msg" : "36363636333037313034", + "sig" : "bdae7bcb580bf335efd3bc3d31870f923eaccafcd40ec2f605976f15137d8b8ff6dfa12f19e525270b0106eecfe257499f373a4fb318994f24838122ce7ec3c7", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 76, + "comment" : "special case hash", + "msg" : "31303335393531383938", + "sig" : "50f9c4f0cd6940e162720957ffff513799209b78596956d21ece251c2401f1c6d7033a0a787d338e889defaaabb106b95a4355e411a59c32aa5167dfab244726", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 77, + "comment" : "special case hash", + "msg" : "31383436353937313935", + "sig" : "f612820687604fa01906066a378d67540982e29575d019aabe90924ead5c860d3f9367702dd7dd4f75ea98afd20e328a1a99f4857b316525328230ce294b0fef", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 78, + "comment" : "special case hash", + "msg" : "33313336303436313839", + "sig" : "9505e407657d6e8bc93db5da7aa6f5081f61980c1949f56b0f2f507da5782a7ac60d31904e3669738ffbeccab6c3656c08e0ed5cb92b3cfa5e7f71784f9c5021", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 79, + "comment" : "special case hash", + "msg" : "32363633373834323534", + "sig" : "bbd16fbbb656b6d0d83e6a7787cd691b08735aed371732723e1c68a40404517d9d8e35dba96028b7787d91315be675877d2d097be5e8ee34560e3e7fd25c0f00", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 80, + "comment" : "special case hash", + "msg" : "31363532313030353234", + "sig" : "2ec9760122db98fd06ea76848d35a6da442d2ceef7559a30cf57c61e92df327e7ab271da90859479701fccf86e462ee3393fb6814c27b760c4963625c0a19878", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 81, + "comment" : "special case hash", + "msg" : "35373438303831363936", + "sig" : "54e76b7683b6650baa6a7fc49b1c51eed9ba9dd463221f7a4f1005a89fe00c592ea076886c773eb937ec1cc8374b7915cfd11b1c1ae1166152f2f7806a31c8fd", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 82, + "comment" : "special case hash", + "msg" : "36333433393133343638", + "sig" : "5291deaf24659ffbbce6e3c26f6021097a74abdbb69be4fb10419c0c496c946665d6fcf336d27cc7cdb982bb4e4ecef5827f84742f29f10abf83469270a03dc3", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 83, + "comment" : "special case hash", + "msg" : "31353431313033353938", + "sig" : "207a3241812d75d947419dc58efb05e8003b33fc17eb50f9d15166a88479f107cdee749f2e492b213ce80b32d0574f62f1c5d70793cf55e382d5caadf7592767", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 84, + "comment" : "special case hash", + "msg" : "3130343738353830313238", + "sig" : "6554e49f82a855204328ac94913bf01bbe84437a355a0a37c0dee3cf81aa7728aea00de2507ddaf5c94e1e126980d3df16250a2eaebc8be486effe7f22b4f929", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 85, + "comment" : "special case hash", + "msg" : "3130353336323835353638", + "sig" : "a54c5062648339d2bff06f71c88216c26c6e19b4d80a8c602990ac82707efdfce99bbe7fcfafae3e69fd016777517aa01056317f467ad09aff09be73c9731b0d", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 86, + "comment" : "special case hash", + "msg" : "393533393034313035", + "sig" : "975bd7157a8d363b309f1f444012b1a1d23096593133e71b4ca8b059cff37eaf7faa7a28b1c822baa241793f2abc930bd4c69840fe090f2aacc46786bf919622", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 87, + "comment" : "special case hash", + "msg" : "393738383438303339", + "sig" : "5694a6f84b8f875c276afd2ebcfe4d61de9ec90305afb1357b95b3e0da43885e0dffad9ffd0b757d8051dec02ebdf70d8ee2dc5c7870c0823b6ccc7c679cbaa4", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 88, + "comment" : "special case hash", + "msg" : "33363130363732343432", + "sig" : "a0c30e8026fdb2b4b4968a27d16a6d08f7098f1a98d21620d7454ba9790f1ba65e470453a8a399f15baf463f9deceb53acc5ca64459149688bd2760c65424339", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 89, + "comment" : "special case hash", + "msg" : "31303534323430373035", + "sig" : "614ea84acf736527dd73602cd4bb4eea1dfebebd5ad8aca52aa0228cf7b99a88737cc85f5f2d2f60d1b8183f3ed490e4de14368e96a9482c2a4dd193195c902f", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 90, + "comment" : "special case hash", + "msg" : "35313734343438313937", + "sig" : "bead6734ebe44b810d3fb2ea00b1732945377338febfd439a8d74dfbd0f942fa6bb18eae36616a7d3cad35919fd21a8af4bbe7a10f73b3e036a46b103ef56e2a", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 91, + "comment" : "special case hash", + "msg" : "31393637353631323531", + "sig" : "499625479e161dacd4db9d9ce64854c98d922cbf212703e9654fae182df9bad242c177cf37b8193a0131108d97819edd9439936028864ac195b64fca76d9d693", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 92, + "comment" : "special case hash", + "msg" : "33343437323533333433", + "sig" : "08f16b8093a8fb4d66a2c8065b541b3d31e3bfe694f6b89c50fb1aaa6ff6c9b29d6455e2d5d1779748573b611cb95d4a21f967410399b39b535ba3e5af81ca2e", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 93, + "comment" : "special case hash", + "msg" : "333638323634333138", + "sig" : "be26231b6191658a19dd72ddb99ed8f8c579b6938d19bce8eed8dc2b338cb5f8e1d9a32ee56cffed37f0f22b2dcb57d5c943c14f79694a03b9c5e96952575c89", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 94, + "comment" : "special case hash", + "msg" : "33323631313938363038", + "sig" : "15e76880898316b16204ac920a02d58045f36a229d4aa4f812638c455abe0443e74d357d3fcb5c8c5337bd6aba4178b455ca10e226e13f9638196506a1939123", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 95, + "comment" : "special case hash", + "msg" : "39363738373831303934", + "sig" : "352ecb53f8df2c503a45f9846fc28d1d31e6307d3ddbffc1132315cc07f16dad1348dfa9c482c558e1d05c5242ca1c39436726ecd28258b1899792887dd0a3c6", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 96, + "comment" : "special case hash", + "msg" : "34393538383233383233", + "sig" : "4a40801a7e606ba78a0da9882ab23c7677b8642349ed3d652c5bfa5f2a9558fb3a49b64848d682ef7f605f2832f7384bdc24ed2925825bf8ea77dc5981725782", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 97, + "comment" : "special case hash", + "msg" : "383234363337383337", + "sig" : "eacc5e1a8304a74d2be412b078924b3bb3511bac855c05c9e5e9e44df3d61e967451cd8e18d6ed1885dd827714847f96ec4bb0ed4c36ce9808db8f714204f6d1", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 98, + "comment" : "special case hash", + "msg" : "3131303230383333373736", + "sig" : "2f7a5e9e5771d424f30f67fdab61e8ce4f8cd1214882adb65f7de94c31577052ac4e69808345809b44acb0b2bd889175fb75dd050c5a449ab9528f8f78daa10c", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 99, + "comment" : "special case hash", + "msg" : "313333383731363438", + "sig" : "ffcda40f792ce4d93e7e0f0e95e1a2147dddd7f6487621c30a03d710b330021979938b55f8a17f7ed7ba9ade8f2065a1fa77618f0b67add8d58c422c2453a49a", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 100, + "comment" : "special case hash", + "msg" : "333232313434313632", + "sig" : "81f2359c4faba6b53d3e8c8c3fcc16a948350f7ab3a588b28c17603a431e39a8cd6f6a5cc3b55ead0ff695d06c6860b509e46d99fccefb9f7f9e101857f74300", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 101, + "comment" : "special case hash", + "msg" : "3130363836363535353436", + "sig" : "dfc8bf520445cbb8ee1596fb073ea283ea130251a6fdffa5c3f5f2aaf75ca808048e33efce147c9dd92823640e338e68bfd7d0dc7a4905b3a7ac711e577e90e7", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 102, + "comment" : "special case hash", + "msg" : "3632313535323436", + "sig" : "ad019f74c6941d20efda70b46c53db166503a0e393e932f688227688ba6a576293320eb7ca0710255346bdbb3102cdcf7964ef2e0988e712bc05efe16c199345", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 103, + "comment" : "special case hash", + "msg" : "37303330383138373734", + "sig" : "ac8096842e8add68c34e78ce11dd71e4b54316bd3ebf7fffdeb7bd5a3ebc1883f5ca2f4f23d674502d4caf85d187215d36e3ce9f0ce219709f21a3aac003b7a8", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 104, + "comment" : "special case hash", + "msg" : "35393234353233373434", + "sig" : "677b2d3a59b18a5ff939b70ea002250889ddcd7b7b9d776854b4943693fb92f76b4ba856ade7677bf30307b21f3ccda35d2f63aee81efd0bab6972cc0795db55", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 105, + "comment" : "special case hash", + "msg" : "31343935353836363231", + "sig" : "479e1ded14bcaed0379ba8e1b73d3115d84d31d4b7c30e1f05e1fc0d5957cfb0918f79e35b3d89487cf634a4f05b2e0c30857ca879f97c771e877027355b2443", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 106, + "comment" : "special case hash", + "msg" : "34303035333134343036", + "sig" : "43dfccd0edb9e280d9a58f01164d55c3d711e14b12ac5cf3b64840ead512a0a31dbe33fa8ba84533cd5c4934365b3442ca1174899b78ef9a3199f49584389772", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 107, + "comment" : "special case hash", + "msg" : "33303936343537353132", + "sig" : "5b09ab637bd4caf0f4c7c7e4bca592fea20e9087c259d26a38bb4085f0bbff1145b7eb467b6748af618e9d80d6fdcd6aa24964e5a13f885bca8101de08eb0d75", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 108, + "comment" : "special case hash", + "msg" : "32373834303235363230", + "sig" : "5e9b1c5a028070df5728c5c8af9b74e0667afa570a6cfa0114a5039ed15ee06fb1360907e2d9785ead362bb8d7bd661b6c29eeffd3c5037744edaeb9ad990c20", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 109, + "comment" : "special case hash", + "msg" : "32363138373837343138", + "sig" : "0671a0a85c2b72d54a2fb0990e34538b4890050f5a5712f6d1a7a5fb8578f32edb1846bab6b7361479ab9c3285ca41291808f27fd5bd4fdac720e5854713694c", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 110, + "comment" : "special case hash", + "msg" : "31363432363235323632", + "sig" : "7673f8526748446477dbbb0590a45492c5d7d69859d301abbaedb35b2095103a3dc70ddf9c6b524d886bed9e6af02e0e4dec0d417a414fed3807ef4422913d7c", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 111, + "comment" : "special case hash", + "msg" : "36383234313839343336", + "sig" : "7f085441070ecd2bb21285089ebb1aa6450d1a06c36d3ff39dfd657a796d12b5249712012029870a2459d18d47da9aa492a5e6cb4b2d8dafa9e4c5c54a2b9a8b", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 112, + "comment" : "special case hash", + "msg" : "343834323435343235", + "sig" : "914c67fb61dd1e27c867398ea7322d5ab76df04bc5aa6683a8e0f30a5d287348fa07474031481dda4953e3ac1959ee8cea7e66ec412b38d6c96d28f6d37304ea", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "CtmVACiNRmlAAx1yqfVEWk1DeEZAhVvwpph00t5f4QM", + "y" : "xQEebvLELc1Q1dPSn5mubrosgMkkT0xUIvCXn_DDul4" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "040ad99500288d466940031d72a9f5445a4d43784640855bf0a69874d2de5fe103c5011e6ef2c42dcd50d5d3d29f99ae6eba2c80c9244f4c5422f0979ff0c3ba5e", + "wx" : "0ad99500288d466940031d72a9f5445a4d43784640855bf0a69874d2de5fe103", + "wy" : "00c5011e6ef2c42dcd50d5d3d29f99ae6eba2c80c9244f4c5422f0979ff0c3ba5e" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200040ad99500288d466940031d72a9f5445a4d43784640855bf0a69874d2de5fe103c5011e6ef2c42dcd50d5d3d29f99ae6eba2c80c9244f4c5422f0979ff0c3ba5e", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECtmVACiNRmlAAx1yqfVEWk1DeEZA\nhVvwpph00t5f4QPFAR5u8sQtzVDV09Kfma5uuiyAySRPTFQi8Jef8MO6Xg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 113, + "comment" : "k*G has a large x-coordinate", + "msg" : "313233343030", + "sig" : "000000000000000000000000000000004319055358e8617b0c46353d039cdaabffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 114, + "comment" : "r too large", + "msg" : "313233343030", + "sig" : "ffffffff00000001000000000000000000000000fffffffffffffffffffffffcffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e", + "result" : "invalid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "qwX9nQ3ia5zm9IGWUtn8aRk9CqOY8PuoAT4JxYIgRVQ", + "y" : "GSNScSKMeGdZCV0St1rwaS3UED8Z9qjDL0lDWh6bjUU" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04ab05fd9d0de26b9ce6f4819652d9fc69193d0aa398f0fba8013e09c58220455419235271228c786759095d12b75af0692dd4103f19f6a8c32f49435a1e9b8d45", + "wx" : "00ab05fd9d0de26b9ce6f4819652d9fc69193d0aa398f0fba8013e09c582204554", + "wy" : "19235271228c786759095d12b75af0692dd4103f19f6a8c32f49435a1e9b8d45" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004ab05fd9d0de26b9ce6f4819652d9fc69193d0aa398f0fba8013e09c58220455419235271228c786759095d12b75af0692dd4103f19f6a8c32f49435a1e9b8d45", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEqwX9nQ3ia5zm9IGWUtn8aRk9CqOY\n8PuoAT4JxYIgRVQZI1JxIox4Z1kJXRK3WvBpLdQQPxn2qMMvSUNaHpuNRQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 115, + "comment" : "r,s are large", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "gJhPOaH_OKhqaKpCAba-Xfv-z4diGXELB7rfb91MbFY", + "y" : "Ef65c5DZgm56Bt-0GHHJQNdEFe08rCCJ8URQGbtV7ZU" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "0480984f39a1ff38a86a68aa4201b6be5dfbfecf876219710b07badf6fdd4c6c5611feb97390d9826e7a06dfb41871c940d74415ed3cac2089f1445019bb55ed95", + "wx" : "0080984f39a1ff38a86a68aa4201b6be5dfbfecf876219710b07badf6fdd4c6c56", + "wy" : "11feb97390d9826e7a06dfb41871c940d74415ed3cac2089f1445019bb55ed95" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000480984f39a1ff38a86a68aa4201b6be5dfbfecf876219710b07badf6fdd4c6c5611feb97390d9826e7a06dfb41871c940d74415ed3cac2089f1445019bb55ed95", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgJhPOaH/OKhqaKpCAba+Xfv+z4di\nGXELB7rfb91MbFYR/rlzkNmCbnoG37QYcclA10QV7TysIInxRFAZu1XtlQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 116, + "comment" : "r and s^-1 have a large Hamming weight", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd909135bdb6799286170f5ead2de4f6511453fe50914f3df2de54a36383df8dd4", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "QgG0JylEIBwylPW6qaMjK23Wh0lfzBmnCpW8YCtPfAU", + "y" : "lcN-up7oFxwbtaxv6vdTvDb0Y-Ou8WYpVywMCo-wgA4" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "044201b4272944201c3294f5baa9a3232b6dd687495fcc19a70a95bc602b4f7c0595c37eba9ee8171c1bb5ac6feaf753bc36f463e3aef16629572c0c0a8fb0800e", + "wx" : "4201b4272944201c3294f5baa9a3232b6dd687495fcc19a70a95bc602b4f7c05", + "wy" : "0095c37eba9ee8171c1bb5ac6feaf753bc36f463e3aef16629572c0c0a8fb0800e" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200044201b4272944201c3294f5baa9a3232b6dd687495fcc19a70a95bc602b4f7c0595c37eba9ee8171c1bb5ac6feaf753bc36f463e3aef16629572c0c0a8fb0800e", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQgG0JylEIBwylPW6qaMjK23Wh0lf\nzBmnCpW8YCtPfAWVw366nugXHBu1rG/q91O8NvRj467xZilXLAwKj7CADg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 117, + "comment" : "r and s^-1 have a large Hamming weight", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd27b4577ca009376f71303fd5dd227dcef5deb773ad5f5a84360644669ca249a5", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "pxr2TeUSakpOAreSLWbOlBXOiKTJ0lUU2RCCyHJayVc", + "y" : "XUdyPI--WAuzaf7JwmZdjjCkNbmTJkVILnyfEehyKWs" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04a71af64de5126a4a4e02b7922d66ce9415ce88a4c9d25514d91082c8725ac9575d47723c8fbe580bb369fec9c2665d8e30a435b9932645482e7c9f11e872296b", + "wx" : "00a71af64de5126a4a4e02b7922d66ce9415ce88a4c9d25514d91082c8725ac957", + "wy" : "5d47723c8fbe580bb369fec9c2665d8e30a435b9932645482e7c9f11e872296b" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004a71af64de5126a4a4e02b7922d66ce9415ce88a4c9d25514d91082c8725ac9575d47723c8fbe580bb369fec9c2665d8e30a435b9932645482e7c9f11e872296b", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpxr2TeUSakpOAreSLWbOlBXOiKTJ\n0lUU2RCCyHJayVddR3I8j75YC7Np/snCZl2OMKQ1uZMmRUgufJ8R6HIpaw==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 118, + "comment" : "small r and s", + "msg" : "313233343030", + "sig" : "00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000001", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 119, + "comment" : "incorrect size of signature", + "msg" : "313233343030", + "sig" : "0501", + "result" : "acceptable", + "flags" : [ + "SigSize" + ] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "ZifOxPBzHqI_wpMfkOvlt1cvWX0g3wj8KzHujvFrFXI", + "y" : "YXDtd9jQoU_FycPEyb5_DT7hj3CbsnXq8gc-JY_mlKU" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "046627cec4f0731ea23fc2931f90ebe5b7572f597d20df08fc2b31ee8ef16b15726170ed77d8d0a14fc5c9c3c4c9be7f0d3ee18f709bb275eaf2073e258fe694a5", + "wx" : "6627cec4f0731ea23fc2931f90ebe5b7572f597d20df08fc2b31ee8ef16b1572", + "wy" : "6170ed77d8d0a14fc5c9c3c4c9be7f0d3ee18f709bb275eaf2073e258fe694a5" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200046627cec4f0731ea23fc2931f90ebe5b7572f597d20df08fc2b31ee8ef16b15726170ed77d8d0a14fc5c9c3c4c9be7f0d3ee18f709bb275eaf2073e258fe694a5", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZifOxPBzHqI/wpMfkOvlt1cvWX0g\n3wj8KzHujvFrFXJhcO132NChT8XJw8TJvn8NPuGPcJuyderyBz4lj+aUpQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 120, + "comment" : "small r and s", + "msg" : "313233343030", + "sig" : "00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000003", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 121, + "comment" : "incorrect size of signature", + "msg" : "313233343030", + "sig" : "0503", + "result" : "acceptable", + "flags" : [ + "SigSize" + ] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "WnyIJehWkczh9edUTFTnPxSvwBDLcxNDJiyn7Fp39b8", + "y" : "727fYqRJfBvXsUf7bD0irzw5v86V8w4ToW09eygS-BM" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "045a7c8825e85691cce1f5e7544c54e73f14afc010cb731343262ca7ec5a77f5bfef6edf62a4497c1bd7b147fb6c3d22af3c39bfce95f30e13a16d3d7b2812f813", + "wx" : "5a7c8825e85691cce1f5e7544c54e73f14afc010cb731343262ca7ec5a77f5bf", + "wy" : "00ef6edf62a4497c1bd7b147fb6c3d22af3c39bfce95f30e13a16d3d7b2812f813" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200045a7c8825e85691cce1f5e7544c54e73f14afc010cb731343262ca7ec5a77f5bfef6edf62a4497c1bd7b147fb6c3d22af3c39bfce95f30e13a16d3d7b2812f813", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWnyIJehWkczh9edUTFTnPxSvwBDL\ncxNDJiyn7Fp39b/vbt9ipEl8G9exR/tsPSKvPDm/zpXzDhOhbT17KBL4Ew==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 122, + "comment" : "small r and s", + "msg" : "313233343030", + "sig" : "00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000005", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 123, + "comment" : "incorrect size of signature", + "msg" : "313233343030", + "sig" : "0505", + "result" : "acceptable", + "flags" : [ + "SigSize" + ] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "y-DCkTLNc4Nk_t1gMVKZDASOXi__mW2IP6bKynl4xzc", + "y" : "cK9qjORMtBIksmA2BvTATRiOgL_3zDGtUYnUqw1w6ME" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04cbe0c29132cd738364fedd603152990c048e5e2fff996d883fa6caca7978c73770af6a8ce44cb41224b2603606f4c04d188e80bff7cc31ad5189d4ab0d70e8c1", + "wx" : "00cbe0c29132cd738364fedd603152990c048e5e2fff996d883fa6caca7978c737", + "wy" : "70af6a8ce44cb41224b2603606f4c04d188e80bff7cc31ad5189d4ab0d70e8c1" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004cbe0c29132cd738364fedd603152990c048e5e2fff996d883fa6caca7978c73770af6a8ce44cb41224b2603606f4c04d188e80bff7cc31ad5189d4ab0d70e8c1", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEy+DCkTLNc4Nk/t1gMVKZDASOXi//\nmW2IP6bKynl4xzdwr2qM5Ey0EiSyYDYG9MBNGI6Av/fMMa1RidSrDXDowQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 124, + "comment" : "small r and s", + "msg" : "313233343030", + "sig" : "00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 125, + "comment" : "incorrect size of signature", + "msg" : "313233343030", + "sig" : "0506", + "result" : "acceptable", + "flags" : [ + "SigSize" + ] + }, + { + "tcId" : 126, + "comment" : "r is larger than n", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325560000000000000000000000000000000000000000000000000000000000000006", + "result" : "invalid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "S-QXgJcALw3qto8NmhMODtM6Z5XQKiB5bbg0RLA34Tk", + "y" : "IPEwUeDuzc_OTazqD1DR8kfKpmnxk8G0B1tRriltLVY" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "044be4178097002f0deab68f0d9a130e0ed33a6795d02a20796db83444b037e13920f13051e0eecdcfce4dacea0f50d1f247caa669f193c1b4075b51ae296d2d56", + "wx" : "4be4178097002f0deab68f0d9a130e0ed33a6795d02a20796db83444b037e139", + "wy" : "20f13051e0eecdcfce4dacea0f50d1f247caa669f193c1b4075b51ae296d2d56" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200044be4178097002f0deab68f0d9a130e0ed33a6795d02a20796db83444b037e13920f13051e0eecdcfce4dacea0f50d1f247caa669f193c1b4075b51ae296d2d56", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAES+QXgJcALw3qto8NmhMODtM6Z5XQ\nKiB5bbg0RLA34Tkg8TBR4O7Nz85NrOoPUNHyR8qmafGTwbQHW1GuKW0tVg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 127, + "comment" : "s is larger than n", + "msg" : "313233343030", + "sig" : "0000000000000000000000000000000000000000000000000000000000000005ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc75fbd8", + "result" : "invalid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "0Pc3kiA3Fq_UvkMp-qSNJp8VMT67ujedd4PJe_PokNk", + "y" : "lx9KMgZgW-wheCv14nXHFEF-j1ZlSea8aGkNI2PInME" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04d0f73792203716afd4be4329faa48d269f15313ebbba379d7783c97bf3e890d9971f4a3206605bec21782bf5e275c714417e8f566549e6bc68690d2363c89cc1", + "wx" : "00d0f73792203716afd4be4329faa48d269f15313ebbba379d7783c97bf3e890d9", + "wy" : "00971f4a3206605bec21782bf5e275c714417e8f566549e6bc68690d2363c89cc1" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004d0f73792203716afd4be4329faa48d269f15313ebbba379d7783c97bf3e890d9971f4a3206605bec21782bf5e275c714417e8f566549e6bc68690d2363c89cc1", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0Pc3kiA3Fq/UvkMp+qSNJp8VMT67\nujedd4PJe/PokNmXH0oyBmBb7CF4K/XidccUQX6PVmVJ5rxoaQ0jY8icwQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 128, + "comment" : "small r and s^-1", + "msg" : "313233343030", + "sig" : "00000000000000000000000000000000000000000000000000000000000001008f1e3c7862c58b16bb76eddbb76eddbb516af4f63f2d74d76e0d28c9bb75ea88", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "SDiyvjWmJ2qA754igUD52bls6Dt6JU9xzN67uAVM4F8", + "y" : "-py8EjyRmxngAjgZjQQGkEO9ZgqCiBQFH8uKrHOKbGs" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "044838b2be35a6276a80ef9e228140f9d9b96ce83b7a254f71ccdebbb8054ce05ffa9cbc123c919b19e00238198d04069043bd660a828814051fcb8aac738a6c6b", + "wx" : "4838b2be35a6276a80ef9e228140f9d9b96ce83b7a254f71ccdebbb8054ce05f", + "wy" : "00fa9cbc123c919b19e00238198d04069043bd660a828814051fcb8aac738a6c6b" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200044838b2be35a6276a80ef9e228140f9d9b96ce83b7a254f71ccdebbb8054ce05ffa9cbc123c919b19e00238198d04069043bd660a828814051fcb8aac738a6c6b", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESDiyvjWmJ2qA754igUD52bls6Dt6\nJU9xzN67uAVM4F/6nLwSPJGbGeACOBmNBAaQQ71mCoKIFAUfy4qsc4psaw==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 129, + "comment" : "smallish r and s^-1", + "msg" : "313233343030", + "sig" : "000000000000000000000000000000000000000000000000002d9b4d347952d6ef3043e7329581dbb3974497710ab11505ee1c87ff907beebadd195a0ffe6d7a", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "c5OYPKMKUgu8R4PcmWB0aqtETvUgwKjncRGapOdLD2Q", + "y" : "6de-GrAaC_Ym5wmGPmpIbbrzJ5OvzPd04sbNJ7GFdSY" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "047393983ca30a520bbc4783dc9960746aab444ef520c0a8e771119aa4e74b0f64e9d7be1ab01a0bf626e709863e6a486dbaf32793afccf774e2c6cd27b1857526", + "wx" : "7393983ca30a520bbc4783dc9960746aab444ef520c0a8e771119aa4e74b0f64", + "wy" : "00e9d7be1ab01a0bf626e709863e6a486dbaf32793afccf774e2c6cd27b1857526" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200047393983ca30a520bbc4783dc9960746aab444ef520c0a8e771119aa4e74b0f64e9d7be1ab01a0bf626e709863e6a486dbaf32793afccf774e2c6cd27b1857526", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc5OYPKMKUgu8R4PcmWB0aqtETvUg\nwKjncRGapOdLD2Tp174asBoL9ibnCYY+akhtuvMnk6/M93Tixs0nsYV1Jg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 130, + "comment" : "100-bit r and small s^-1", + "msg" : "313233343030", + "sig" : "000000000000000000000000000000000000001033e67e37b32b445580bf4eff8b748b74000000008b748b748b748b7466e769ad4a16d3dcd87129b8e91d1b4d", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "WsMxoRA_6WZpc3nzVqk381BYigVHfjCIUbilAtXfzcU", + "y" : "_pmT30tXk5srjaCVv215QmUgTP4DvplaAuZdQIyHHAs" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "045ac331a1103fe966697379f356a937f350588a05477e308851b8a502d5dfcdc5fe9993df4b57939b2b8da095bf6d794265204cfe03be995a02e65d408c871c0b", + "wx" : "5ac331a1103fe966697379f356a937f350588a05477e308851b8a502d5dfcdc5", + "wy" : "00fe9993df4b57939b2b8da095bf6d794265204cfe03be995a02e65d408c871c0b" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200045ac331a1103fe966697379f356a937f350588a05477e308851b8a502d5dfcdc5fe9993df4b57939b2b8da095bf6d794265204cfe03be995a02e65d408c871c0b", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWsMxoRA/6WZpc3nzVqk381BYigVH\nfjCIUbilAtXfzcX+mZPfS1eTmyuNoJW/bXlCZSBM/gO+mVoC5l1AjIccCw==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 131, + "comment" : "small r and 100 bit s^-1", + "msg" : "313233343030", + "sig" : "0000000000000000000000000000000000000000000000000000000000000100ef9f6ba4d97c09d03178fa20b4aaad83be3cf9cb824a879fec3270fc4b81ef5b", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "HSCb6N4t6HcJWjmdOQTHTMRY2Sbie7jljl6uV2fEFQk", + "y" : "3VngTCFPexjc41H8KlSYk6aGDoAWPzjMYKTyydBA2Mk" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "041d209be8de2de877095a399d3904c74cc458d926e27bb8e58e5eae5767c41509dd59e04c214f7b18dce351fc2a549893a6860e80163f38cc60a4f2c9d040d8c9", + "wx" : "1d209be8de2de877095a399d3904c74cc458d926e27bb8e58e5eae5767c41509", + "wy" : "00dd59e04c214f7b18dce351fc2a549893a6860e80163f38cc60a4f2c9d040d8c9" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200041d209be8de2de877095a399d3904c74cc458d926e27bb8e58e5eae5767c41509dd59e04c214f7b18dce351fc2a549893a6860e80163f38cc60a4f2c9d040d8c9", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHSCb6N4t6HcJWjmdOQTHTMRY2Sbi\ne7jljl6uV2fEFQndWeBMIU97GNzjUfwqVJiTpoYOgBY/OMxgpPLJ0EDYyQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 132, + "comment" : "100-bit r and s^-1", + "msg" : "313233343030", + "sig" : "00000000000000000000000000000000000000062522bbd3ecbe7c39e93e7c25ef9f6ba4d97c09d03178fa20b4aaad83be3cf9cb824a879fec3270fc4b81ef5b", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "CDU5--5EYl46yq-i_LQTSTks7wYzobj6vs7gwTOxDpk", + "y" : "kVwevnvwDfhTUZZ3ClgEeuKkAvJjJrt9QdTXYWM3kR4" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04083539fbee44625e3acaafa2fcb41349392cef0633a1b8fabecee0c133b10e99915c1ebe7bf00df8535196770a58047ae2a402f26326bb7d41d4d7616337911e", + "wx" : "083539fbee44625e3acaafa2fcb41349392cef0633a1b8fabecee0c133b10e99", + "wy" : "00915c1ebe7bf00df8535196770a58047ae2a402f26326bb7d41d4d7616337911e" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004083539fbee44625e3acaafa2fcb41349392cef0633a1b8fabecee0c133b10e99915c1ebe7bf00df8535196770a58047ae2a402f26326bb7d41d4d7616337911e", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECDU5++5EYl46yq+i/LQTSTks7wYz\nobj6vs7gwTOxDpmRXB6+e/AN+FNRlncKWAR64qQC8mMmu31B1NdhYzeRHg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 133, + "comment" : "r and s^-1 are close to n", + "msg" : "313233343030", + "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6324d5555555550000000055555555555555553ef7a8e48d07df81a693439654210c70", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "ius2inAnpNZKveo3OQwMHWom85ni2XNN4es9Dhk3OHQ", + "y" : "Bb0Tg0cV4duum4dc8HvVXhtmkcf3U2rvOxm_ekrfV20" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "048aeb368a7027a4d64abdea37390c0c1d6a26f399e2d9734de1eb3d0e1937387405bd13834715e1dbae9b875cf07bd55e1b6691c7f7536aef3b19bf7a4adf576d", + "wx" : "008aeb368a7027a4d64abdea37390c0c1d6a26f399e2d9734de1eb3d0e19373874", + "wy" : "05bd13834715e1dbae9b875cf07bd55e1b6691c7f7536aef3b19bf7a4adf576d" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200048aeb368a7027a4d64abdea37390c0c1d6a26f399e2d9734de1eb3d0e1937387405bd13834715e1dbae9b875cf07bd55e1b6691c7f7536aef3b19bf7a4adf576d", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEius2inAnpNZKveo3OQwMHWom85ni\n2XNN4es9Dhk3OHQFvRODRxXh266bh1zwe9VeG2aRx/dTau87Gb96St9XbQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 134, + "comment" : "s == 1", + "msg" : "313233343030", + "sig" : "555555550000000055555555555555553ef7a8e48d07df81a693439654210c700000000000000000000000000000000000000000000000000000000000000001", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 135, + "comment" : "s == 0", + "msg" : "313233343030", + "sig" : "555555550000000055555555555555553ef7a8e48d07df81a693439654210c700000000000000000000000000000000000000000000000000000000000000000", + "result" : "invalid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "tTPUaV3VuMXgd1flXm5Rb34siPoCOeI_YOjsB91w8oc", + "y" : "GxNO5YzFgyeEVoY_M8OoXYgffUo5hQFD4p1OrwCa_kc" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04b533d4695dd5b8c5e07757e55e6e516f7e2c88fa0239e23f60e8ec07dd70f2871b134ee58cc583278456863f33c3a85d881f7d4a39850143e29d4eaf009afe47", + "wx" : "00b533d4695dd5b8c5e07757e55e6e516f7e2c88fa0239e23f60e8ec07dd70f287", + "wy" : "1b134ee58cc583278456863f33c3a85d881f7d4a39850143e29d4eaf009afe47" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004b533d4695dd5b8c5e07757e55e6e516f7e2c88fa0239e23f60e8ec07dd70f2871b134ee58cc583278456863f33c3a85d881f7d4a39850143e29d4eaf009afe47", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEtTPUaV3VuMXgd1flXm5Rb34siPoC\nOeI/YOjsB91w8ocbE07ljMWDJ4RWhj8zw6hdiB99SjmFAUPinU6vAJr+Rw==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 136, + "comment" : "point at infinity during verify", + "msg" : "313233343030", + "sig" : "7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8555555550000000055555555555555553ef7a8e48d07df81a693439654210c70", + "result" : "invalid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "9Q03G5G_sdfRThMjUjvDqoy_LFf54oTeYoyLRTZ4e4Y", + "y" : "-UrYh6yU1SckfNLn0MixKRxVPJcwQFOAsUy7IJ9fot0" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04f50d371b91bfb1d7d14e1323523bc3aa8cbf2c57f9e284de628c8b4536787b86f94ad887ac94d527247cd2e7d0c8b1291c553c9730405380b14cbb209f5fa2dd", + "wx" : "00f50d371b91bfb1d7d14e1323523bc3aa8cbf2c57f9e284de628c8b4536787b86", + "wy" : "00f94ad887ac94d527247cd2e7d0c8b1291c553c9730405380b14cbb209f5fa2dd" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004f50d371b91bfb1d7d14e1323523bc3aa8cbf2c57f9e284de628c8b4536787b86f94ad887ac94d527247cd2e7d0c8b1291c553c9730405380b14cbb209f5fa2dd", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9Q03G5G/sdfRThMjUjvDqoy/LFf5\n4oTeYoyLRTZ4e4b5StiHrJTVJyR80ufQyLEpHFU8lzBAU4CxTLsgn1+i3Q==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 137, + "comment" : "edge case for signature malleability", + "msg" : "313233343030", + "sig" : "7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a97fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "aOxuKY6v4WU5FWzlehSwSnBHwiG6_DpYLq6w2FfE2UY", + "y" : "l77RrxeFARf9s5sjJPIgpWmO0WxCaiczW7OFrIym-zA" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "0468ec6e298eafe16539156ce57a14b04a7047c221bafc3a582eaeb0d857c4d94697bed1af17850117fdb39b2324f220a5698ed16c426a27335bb385ac8ca6fb30", + "wx" : "68ec6e298eafe16539156ce57a14b04a7047c221bafc3a582eaeb0d857c4d946", + "wy" : "0097bed1af17850117fdb39b2324f220a5698ed16c426a27335bb385ac8ca6fb30" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000468ec6e298eafe16539156ce57a14b04a7047c221bafc3a582eaeb0d857c4d94697bed1af17850117fdb39b2324f220a5698ed16c426a27335bb385ac8ca6fb30", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaOxuKY6v4WU5FWzlehSwSnBHwiG6\n/DpYLq6w2FfE2UaXvtGvF4UBF/2zmyMk8iClaY7RbEJqJzNbs4WsjKb7MA==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 138, + "comment" : "edge case for signature malleability", + "msg" : "313233343030", + "sig" : "7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a97fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "adoDZHNNLlMP7OlAGSZf77eBoPGwj2yIl732VXknyLg", + "y" : "ZtLTx9zVGLI9cmlg8Gmtcakz2G74q7zOiyD3HiqEcAI" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "0469da0364734d2e530fece94019265fefb781a0f1b08f6c8897bdf6557927c8b866d2d3c7dcd518b23d726960f069ad71a933d86ef8abbcce8b20f71e2a847002", + "wx" : "69da0364734d2e530fece94019265fefb781a0f1b08f6c8897bdf6557927c8b8", + "wy" : "66d2d3c7dcd518b23d726960f069ad71a933d86ef8abbcce8b20f71e2a847002" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000469da0364734d2e530fece94019265fefb781a0f1b08f6c8897bdf6557927c8b866d2d3c7dcd518b23d726960f069ad71a933d86ef8abbcce8b20f71e2a847002", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEadoDZHNNLlMP7OlAGSZf77eBoPGw\nj2yIl732VXknyLhm0tPH3NUYsj1yaWDwaa1xqTPYbvirvM6LIPceKoRwAg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 139, + "comment" : "u1 == 1", + "msg" : "313233343030", + "sig" : "555555550000000055555555555555553ef7a8e48d07df81a693439654210c70bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "2K3AACOo7cAlduK2Pj4wYhpHHisjIGIBh78GehrB_zI", + "y" : "M-K1DsCYB6zLNhMf_5XtEqCahrTqlpCqMoYVdrojYuE" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04d8adc00023a8edc02576e2b63e3e30621a471e2b2320620187bf067a1ac1ff3233e2b50ec09807accb36131fff95ed12a09a86b4ea9690aa32861576ba2362e1", + "wx" : "00d8adc00023a8edc02576e2b63e3e30621a471e2b2320620187bf067a1ac1ff32", + "wy" : "33e2b50ec09807accb36131fff95ed12a09a86b4ea9690aa32861576ba2362e1" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004d8adc00023a8edc02576e2b63e3e30621a471e2b2320620187bf067a1ac1ff3233e2b50ec09807accb36131fff95ed12a09a86b4ea9690aa32861576ba2362e1", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2K3AACOo7cAlduK2Pj4wYhpHHisj\nIGIBh78GehrB/zIz4rUOwJgHrMs2Ex//le0SoJqGtOqWkKoyhhV2uiNi4Q==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 140, + "comment" : "u1 == n - 1", + "msg" : "313233343030", + "sig" : "555555550000000055555555555555553ef7a8e48d07df81a693439654210c7044a5ad0ad0636d9f12bc9e0a6bdd5e1cbcb012ea7bf091fcec15b0c43202d52e", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "NiOslzztClb6bYgvA6fVx-3KAs_HskAfqzaQ2-dat4U", + "y" : "jbBpCOZLKGE9pyV-c385eT2o5xO6BkO5LpuzJSvn-P4" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "043623ac973ced0a56fa6d882f03a7d5c7edca02cfc7b2401fab3690dbe75ab7858db06908e64b28613da7257e737f39793da8e713ba0643b92e9bb3252be7f8fe", + "wx" : "3623ac973ced0a56fa6d882f03a7d5c7edca02cfc7b2401fab3690dbe75ab785", + "wy" : "008db06908e64b28613da7257e737f39793da8e713ba0643b92e9bb3252be7f8fe" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200043623ac973ced0a56fa6d882f03a7d5c7edca02cfc7b2401fab3690dbe75ab7858db06908e64b28613da7257e737f39793da8e713ba0643b92e9bb3252be7f8fe", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENiOslzztClb6bYgvA6fVx+3KAs/H\nskAfqzaQ2+dat4WNsGkI5ksoYT2nJX5zfzl5PajnE7oGQ7kum7MlK+f4/g==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 141, + "comment" : "u2 == 1", + "msg" : "313233343030", + "sig" : "555555550000000055555555555555553ef7a8e48d07df81a693439654210c70555555550000000055555555555555553ef7a8e48d07df81a693439654210c70", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "zwTqd-liJSPYlLk_9S3DAnsxlZUDtvo4kOXgQmP5IvE", + "y" : "6FKPt8AGs5g8i4QA5XtO1xdAwvOXVDiCEZm-3q7Ksuk" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04cf04ea77e9622523d894b93ff52dc3027b31959503b6fa3890e5e04263f922f1e8528fb7c006b3983c8b8400e57b4ed71740c2f3975438821199bedeaecab2e9", + "wx" : "00cf04ea77e9622523d894b93ff52dc3027b31959503b6fa3890e5e04263f922f1", + "wy" : "00e8528fb7c006b3983c8b8400e57b4ed71740c2f3975438821199bedeaecab2e9" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004cf04ea77e9622523d894b93ff52dc3027b31959503b6fa3890e5e04263f922f1e8528fb7c006b3983c8b8400e57b4ed71740c2f3975438821199bedeaecab2e9", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzwTqd+liJSPYlLk/9S3DAnsxlZUD\ntvo4kOXgQmP5IvHoUo+3wAazmDyLhADle07XF0DC85dUOIIRmb7ersqy6Q==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 142, + "comment" : "u2 == n - 1", + "msg" : "313233343030", + "sig" : "555555550000000055555555555555553ef7a8e48d07df81a693439654210c70aaaaaaaa00000000aaaaaaaaaaaaaaaa7def51c91a0fbf034d26872ca84218e1", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "23osihq1c-WSncJAd7UI1-aD1JInmWvaPp942-_3c1A", + "y" : "T0F_O8mogHXC4KrdWhMxFzDPfMdqgvEaNurwimyZogY" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04db7a2c8a1ab573e5929dc24077b508d7e683d49227996bda3e9f78dbeff773504f417f3bc9a88075c2e0aadd5a13311730cf7cc76a82f11a36eaf08a6c99a206", + "wx" : "00db7a2c8a1ab573e5929dc24077b508d7e683d49227996bda3e9f78dbeff77350", + "wy" : "4f417f3bc9a88075c2e0aadd5a13311730cf7cc76a82f11a36eaf08a6c99a206" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004db7a2c8a1ab573e5929dc24077b508d7e683d49227996bda3e9f78dbeff773504f417f3bc9a88075c2e0aadd5a13311730cf7cc76a82f11a36eaf08a6c99a206", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE23osihq1c+WSncJAd7UI1+aD1JIn\nmWvaPp942+/3c1BPQX87yaiAdcLgqt1aEzEXMM98x2qC8Ro26vCKbJmiBg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 143, + "comment" : "edge case for u1", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffde91e1ba60fdedb76a46bcb51dc0b8b4b7e019f0a28721885fa5d3a8196623397", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "3q0Rx6WzloYvIZdNxHUvre_5lO_pu9BatBN2XqgLbh8", + "y" : "HePwZA6Kxu3Pic_1PEDiZbuUB4o0NzbfB6oDGPx_4f8" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04dead11c7a5b396862f21974dc4752fadeff994efe9bbd05ab413765ea80b6e1f1de3f0640e8ac6edcf89cff53c40e265bb94078a343736df07aa0318fc7fe1ff", + "wx" : "00dead11c7a5b396862f21974dc4752fadeff994efe9bbd05ab413765ea80b6e1f", + "wy" : "1de3f0640e8ac6edcf89cff53c40e265bb94078a343736df07aa0318fc7fe1ff" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004dead11c7a5b396862f21974dc4752fadeff994efe9bbd05ab413765ea80b6e1f1de3f0640e8ac6edcf89cff53c40e265bb94078a343736df07aa0318fc7fe1ff", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3q0Rx6WzloYvIZdNxHUvre/5lO/p\nu9BatBN2XqgLbh8d4/BkDorG7c+Jz/U8QOJlu5QHijQ3Nt8HqgMY/H/h/w==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 144, + "comment" : "edge case for u1", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdea5843ffeb73af94313ba4831b53fe24f799e525b1e8e8c87b59b95b430ad9", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "0LxHLg18geuu06bvlsGGE7sf6m-ZQyb76A4A395nx-k", + "y" : "mGxyPqSEPUg4m5RvZK1WyDrXD_F7qFM1Zn0bufphnv0" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04d0bc472e0d7c81ebaed3a6ef96c18613bb1fea6f994326fbe80e00dfde67c7e9986c723ea4843d48389b946f64ad56c83ad70ff17ba85335667d1bb9fa619efd", + "wx" : "00d0bc472e0d7c81ebaed3a6ef96c18613bb1fea6f994326fbe80e00dfde67c7e9", + "wy" : "00986c723ea4843d48389b946f64ad56c83ad70ff17ba85335667d1bb9fa619efd" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004d0bc472e0d7c81ebaed3a6ef96c18613bb1fea6f994326fbe80e00dfde67c7e9986c723ea4843d48389b946f64ad56c83ad70ff17ba85335667d1bb9fa619efd", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0LxHLg18geuu06bvlsGGE7sf6m+Z\nQyb76A4A395nx+mYbHI+pIQ9SDiblG9krVbIOtcP8XuoUzVmfRu5+mGe/Q==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 145, + "comment" : "edge case for u1", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd03ffcabf2f1b4d2a65190db1680d62bb994e41c5251cd73b3c3dfc5e5bafc035", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "oKRMqUfWairLc2AIucCNGrKtA3duAmQPeEldRY3VHDI", + "y" : "Yzf-XPjEYEsfHECdwthy1ClKR2JCDfQ6MKI5LkBCat0" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04a0a44ca947d66a2acb736008b9c08d1ab2ad03776e02640f78495d458dd51c326337fe5cf8c4604b1f1c409dc2d872d4294a4762420df43a30a2392e40426add", + "wx" : "00a0a44ca947d66a2acb736008b9c08d1ab2ad03776e02640f78495d458dd51c32", + "wy" : "6337fe5cf8c4604b1f1c409dc2d872d4294a4762420df43a30a2392e40426add" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004a0a44ca947d66a2acb736008b9c08d1ab2ad03776e02640f78495d458dd51c326337fe5cf8c4604b1f1c409dc2d872d4294a4762420df43a30a2392e40426add", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoKRMqUfWairLc2AIucCNGrKtA3du\nAmQPeEldRY3VHDJjN/5c+MRgSx8cQJ3C2HLUKUpHYkIN9DowojkuQEJq3Q==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 146, + "comment" : "edge case for u1", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd4dfbc401f971cd304b33dfdb17d0fed0fe4c1a88ae648e0d2847f74977534989", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "ycIRUpDQCLRftl-tD2AjiSmMJUILd1AZ1Ctiw86Klrc", + "y" : "OHfSWoCA3ALZh8pzDwQFwsnb76xG-eYBzD8G6XE5c_0" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04c9c2115290d008b45fb65fad0f602389298c25420b775019d42b62c3ce8a96b73877d25a8080dc02d987ca730f0405c2c9dbefac46f9e601cc3f06e9713973fd", + "wx" : "00c9c2115290d008b45fb65fad0f602389298c25420b775019d42b62c3ce8a96b7", + "wy" : "3877d25a8080dc02d987ca730f0405c2c9dbefac46f9e601cc3f06e9713973fd" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004c9c2115290d008b45fb65fad0f602389298c25420b775019d42b62c3ce8a96b73877d25a8080dc02d987ca730f0405c2c9dbefac46f9e601cc3f06e9713973fd", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEycIRUpDQCLRftl+tD2AjiSmMJUIL\nd1AZ1Ctiw86Klrc4d9JagIDcAtmHynMPBAXCydvvrEb55gHMPwbpcTlz/Q==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 147, + "comment" : "edge case for u1", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbc4024761cd2ffd43dfdb17d0fed112b988977055cd3a8e54971eba9cda5ca71", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "Xsoe9MKH3dxmuLzPG4jookwAGJYvPF5--oO8Gl_2Az4", + "y" : "XnnEyywkW4xFq9zoqOTadY2SpgfDLNQH7K7yLxyTSnE" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "045eca1ef4c287dddc66b8bccf1b88e8a24c0018962f3c5e7efa83bc1a5ff6033e5e79c4cb2c245b8c45abdce8a8e4da758d92a607c32cd407ecaef22f1c934a71", + "wx" : "5eca1ef4c287dddc66b8bccf1b88e8a24c0018962f3c5e7efa83bc1a5ff6033e", + "wy" : "5e79c4cb2c245b8c45abdce8a8e4da758d92a607c32cd407ecaef22f1c934a71" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200045eca1ef4c287dddc66b8bccf1b88e8a24c0018962f3c5e7efa83bc1a5ff6033e5e79c4cb2c245b8c45abdce8a8e4da758d92a607c32cd407ecaef22f1c934a71", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXsoe9MKH3dxmuLzPG4jookwAGJYv\nPF5++oO8Gl/2Az5eecTLLCRbjEWr3Oio5Np1jZKmB8Ms1AfsrvIvHJNKcQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 148, + "comment" : "edge case for u1", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd788048ed39a5ffa77bfb62fa1fda2257742bf35d128fb3459f2a0c909ee86f91", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "XKqgMOf98OSTa8erWpY1PgoB5BMMP4vyLUc-MXAppHo", + "y" : "3ratxGL3BY8qINNx6XAiVOmyAWQgBbPO2pJrQrF4vvk" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "045caaa030e7fdf0e4936bc7ab5a96353e0a01e4130c3f8bf22d473e317029a47adeb6adc462f7058f2a20d371e9702254e9b201642005b3ceda926b42b178bef9", + "wx" : "5caaa030e7fdf0e4936bc7ab5a96353e0a01e4130c3f8bf22d473e317029a47a", + "wy" : "00deb6adc462f7058f2a20d371e9702254e9b201642005b3ceda926b42b178bef9" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200045caaa030e7fdf0e4936bc7ab5a96353e0a01e4130c3f8bf22d473e317029a47adeb6adc462f7058f2a20d371e9702254e9b201642005b3ceda926b42b178bef9", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXKqgMOf98OSTa8erWpY1PgoB5BMM\nP4vyLUc+MXAppHretq3EYvcFjyog03HpcCJU6bIBZCAFs87akmtCsXi++Q==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 149, + "comment" : "edge case for u1", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd476d9131fd381bd917d0fed112bc9e0a5924b5ed5b11167edd8b23582b3cb15e", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "wv0gusBuVVu4rAzmnrHqIPg6H8NQHIpmRpsaMfYZsJg", + "y" : "YjcFB3n1K2Fb17jXaiX8lcou0yUlx18n_8h6w5fmy68" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04c2fd20bac06e555bb8ac0ce69eb1ea20f83a1fc3501c8a66469b1a31f619b0986237050779f52b615bd7b8d76a25fc95ca2ed32525c75f27ffc87ac397e6cbaf", + "wx" : "00c2fd20bac06e555bb8ac0ce69eb1ea20f83a1fc3501c8a66469b1a31f619b098", + "wy" : "6237050779f52b615bd7b8d76a25fc95ca2ed32525c75f27ffc87ac397e6cbaf" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004c2fd20bac06e555bb8ac0ce69eb1ea20f83a1fc3501c8a66469b1a31f619b0986237050779f52b615bd7b8d76a25fc95ca2ed32525c75f27ffc87ac397e6cbaf", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwv0gusBuVVu4rAzmnrHqIPg6H8NQ\nHIpmRpsaMfYZsJhiNwUHefUrYVvXuNdqJfyVyi7TJSXHXyf/yHrDl+bLrw==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 150, + "comment" : "edge case for u1", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8374253e3e21bd154448d0a8f640fe46fafa8b19ce78d538f6cc0a19662d3601", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "P9ahyn93-zsLvnJsNyAQBoQm4R6mrnjOF77a5LuobO0", + "y" : "A85VFkBr-M-quHRerBzWkBitb1C1Rhhy3fxW4Ns8j_Q" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "043fd6a1ca7f77fb3b0bbe726c372010068426e11ea6ae78ce17bedae4bba86ced03ce5516406bf8cfaab8745eac1cd69018ad6f50b5461872ddfc56e0db3c8ff4", + "wx" : "3fd6a1ca7f77fb3b0bbe726c372010068426e11ea6ae78ce17bedae4bba86ced", + "wy" : "03ce5516406bf8cfaab8745eac1cd69018ad6f50b5461872ddfc56e0db3c8ff4" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200043fd6a1ca7f77fb3b0bbe726c372010068426e11ea6ae78ce17bedae4bba86ced03ce5516406bf8cfaab8745eac1cd69018ad6f50b5461872ddfc56e0db3c8ff4", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEP9ahyn93+zsLvnJsNyAQBoQm4R6m\nrnjOF77a5LuobO0DzlUWQGv4z6q4dF6sHNaQGK1vULVGGHLd/Fbg2zyP9A==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 151, + "comment" : "edge case for u1", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd357cfd3be4d01d413c5b9ede36cba5452c11ee7fe14879e749ae6a2d897a52d6", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "nLjlHielrjtiSmDW3DJzTkmJ2yDpvKPt4e33sIaRERQ", + "y" : "tMEEqzxnfks21lVuitX1I0EKGfLid6qJX8VzIrRCdUQ" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "049cb8e51e27a5ae3b624a60d6dc32734e4989db20e9bca3ede1edf7b086911114b4c104ab3c677e4b36d6556e8ad5f523410a19f2e277aa895fc57322b4427544", + "wx" : "009cb8e51e27a5ae3b624a60d6dc32734e4989db20e9bca3ede1edf7b086911114", + "wy" : "00b4c104ab3c677e4b36d6556e8ad5f523410a19f2e277aa895fc57322b4427544" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200049cb8e51e27a5ae3b624a60d6dc32734e4989db20e9bca3ede1edf7b086911114b4c104ab3c677e4b36d6556e8ad5f523410a19f2e277aa895fc57322b4427544", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnLjlHielrjtiSmDW3DJzTkmJ2yDp\nvKPt4e33sIaRERS0wQSrPGd+SzbWVW6K1fUjQQoZ8uJ3qolfxXMitEJ1RA==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 152, + "comment" : "edge case for u1", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd29798c5c0ee287d4a5e8e6b799fd86b8df5225298e6ffc807cd2f2bc27a0a6d8", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "o-UsFW3K8QUCYgt5VbwrQLx47z1WnhIjwmJRLY9JYCo", + "y" : "SiA58xwQlwJK08yG5XMh3gMjVUY0hhZM8ZKUSXffFH8" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04a3e52c156dcaf10502620b7955bc2b40bc78ef3d569e1223c262512d8f49602a4a2039f31c1097024ad3cc86e57321de032355463486164cf192944977df147f", + "wx" : "00a3e52c156dcaf10502620b7955bc2b40bc78ef3d569e1223c262512d8f49602a", + "wy" : "4a2039f31c1097024ad3cc86e57321de032355463486164cf192944977df147f" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004a3e52c156dcaf10502620b7955bc2b40bc78ef3d569e1223c262512d8f49602a4a2039f31c1097024ad3cc86e57321de032355463486164cf192944977df147f", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEo+UsFW3K8QUCYgt5VbwrQLx47z1W\nnhIjwmJRLY9JYCpKIDnzHBCXAkrTzIblcyHeAyNVRjSGFkzxkpRJd98Ufw==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 153, + "comment" : "edge case for u1", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd0b70f22c781092452dca1a5711fa3a5a1f72add1bf52c2ff7cae4820b30078dd", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "8Zt4kocg1b7o5nD7kAEPsVw3v5G1ilFXw_PAWbJlXog", + "y" : "z3AeyWL7ShHc8nP13DV-WEaFYMfP65QtB0q9QykmBQk" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04f19b78928720d5bee8e670fb90010fb15c37bf91b58a5157c3f3c059b2655e88cf701ec962fb4a11dcf273f5dc357e58468560c7cfeb942d074abd4329260509", + "wx" : "00f19b78928720d5bee8e670fb90010fb15c37bf91b58a5157c3f3c059b2655e88", + "wy" : "00cf701ec962fb4a11dcf273f5dc357e58468560c7cfeb942d074abd4329260509" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004f19b78928720d5bee8e670fb90010fb15c37bf91b58a5157c3f3c059b2655e88cf701ec962fb4a11dcf273f5dc357e58468560c7cfeb942d074abd4329260509", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8Zt4kocg1b7o5nD7kAEPsVw3v5G1\nilFXw/PAWbJlXojPcB7JYvtKEdzyc/XcNX5YRoVgx8/rlC0HSr1DKSYFCQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 154, + "comment" : "edge case for u1", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd16e1e458f021248a5b9434ae23f474b43ee55ba37ea585fef95c90416600f1ba", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "g6dERZ7N-wGlz1KyegW7czdILSQvI117TLiTRVRckKg", + "y" : "wF1JM3uWSYEyh96f_pA1X9kF3188MpRYKBIfN8xQ3m4" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "0483a744459ecdfb01a5cf52b27a05bb7337482d242f235d7b4cb89345545c90a8c05d49337b9649813287de9ffe90355fd905df5f3c32945828121f37cc50de6e", + "wx" : "0083a744459ecdfb01a5cf52b27a05bb7337482d242f235d7b4cb89345545c90a8", + "wy" : "00c05d49337b9649813287de9ffe90355fd905df5f3c32945828121f37cc50de6e" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000483a744459ecdfb01a5cf52b27a05bb7337482d242f235d7b4cb89345545c90a8c05d49337b9649813287de9ffe90355fd905df5f3c32945828121f37cc50de6e", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEg6dERZ7N+wGlz1KyegW7czdILSQv\nI117TLiTRVRckKjAXUkze5ZJgTKH3p/+kDVf2QXfXzwylFgoEh83zFDebg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 155, + "comment" : "edge case for u1", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd2252d6856831b6cf895e4f0535eeaf0e5e5809753df848fe760ad86219016a97", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "3RPGs0xWmC3a4STwOd_SP0sZu-iM7o5SiuUeXW86Idc", + "y" : "v61MLm8mP-XrWcqXTQOfwOTDNFaS-1Mgva5L07QqRf8" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04dd13c6b34c56982ddae124f039dfd23f4b19bbe88cee8e528ae51e5d6f3a21d7bfad4c2e6f263fe5eb59ca974d039fc0e4c3345692fb5320bdae4bd3b42a45ff", + "wx" : "00dd13c6b34c56982ddae124f039dfd23f4b19bbe88cee8e528ae51e5d6f3a21d7", + "wy" : "00bfad4c2e6f263fe5eb59ca974d039fc0e4c3345692fb5320bdae4bd3b42a45ff" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004dd13c6b34c56982ddae124f039dfd23f4b19bbe88cee8e528ae51e5d6f3a21d7bfad4c2e6f263fe5eb59ca974d039fc0e4c3345692fb5320bdae4bd3b42a45ff", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3RPGs0xWmC3a4STwOd/SP0sZu+iM\n7o5SiuUeXW86Ide/rUwubyY/5etZypdNA5/A5MM0VpL7UyC9rkvTtCpF/w==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 156, + "comment" : "edge case for u1", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd81ffe55f178da695b28c86d8b406b15dab1a9e39661a3ae017fbe390ac0972c3", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "Z-b2Wc3ehpovZfCU6U5bTfrWNrv5UZL-7tAbDz3rdGA", + "y" : "o34KUfJYt661Hf5ZL1z9VoW75YcSyNkjPGKIZDfDi6A" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "0467e6f659cdde869a2f65f094e94e5b4dfad636bbf95192feeed01b0f3deb7460a37e0a51f258b7aeb51dfe592f5cfd5685bbe58712c8d9233c62886437c38ba0", + "wx" : "67e6f659cdde869a2f65f094e94e5b4dfad636bbf95192feeed01b0f3deb7460", + "wy" : "00a37e0a51f258b7aeb51dfe592f5cfd5685bbe58712c8d9233c62886437c38ba0" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000467e6f659cdde869a2f65f094e94e5b4dfad636bbf95192feeed01b0f3deb7460a37e0a51f258b7aeb51dfe592f5cfd5685bbe58712c8d9233c62886437c38ba0", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZ+b2Wc3ehpovZfCU6U5bTfrWNrv5\nUZL+7tAbDz3rdGCjfgpR8li3rrUd/lkvXP1WhbvlhxLI2SM8YohkN8OLoA==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 157, + "comment" : "edge case for u2", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd7fffffffaaaaaaaaffffffffffffffffe9a2538f37b28a2c513dee40fecbb71a", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "LrZBJQWuwFxlRfApkyCH5JDQVRHo7B9Zlhe7Nn-eyq8", + "y" : "gF9R78xIA0A_mxrgEkiQ8GpD_tzdsxgw9maa8pKJXLA" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "042eb6412505aec05c6545f029932087e490d05511e8ec1f599617bb367f9ecaaf805f51efcc4803403f9b1ae0124890f06a43fedcddb31830f6669af292895cb0", + "wx" : "2eb6412505aec05c6545f029932087e490d05511e8ec1f599617bb367f9ecaaf", + "wy" : "00805f51efcc4803403f9b1ae0124890f06a43fedcddb31830f6669af292895cb0" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200042eb6412505aec05c6545f029932087e490d05511e8ec1f599617bb367f9ecaaf805f51efcc4803403f9b1ae0124890f06a43fedcddb31830f6669af292895cb0", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELrZBJQWuwFxlRfApkyCH5JDQVRHo\n7B9Zlhe7Nn+eyq+AX1HvzEgDQD+bGuASSJDwakP+3N2zGDD2ZprykolcsA==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 158, + "comment" : "edge case for u2", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdb62f26b5f2a2b26f6de86d42ad8a13da3ab3cccd0459b201de009e526adf21f2", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "hNtkWGjqs146n9gOBW4uhVQ146a2jXWlCoVGJf4NfzU", + "y" : "bSWJrGVe3JoR7z4HXt3amr-S5yFxVw73v0Oi7jkzjP4" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "0484db645868eab35e3a9fd80e056e2e855435e3a6b68d75a50a854625fe0d7f356d2589ac655edc9a11ef3e075eddda9abf92e72171570ef7bf43a2ee39338cfe", + "wx" : "0084db645868eab35e3a9fd80e056e2e855435e3a6b68d75a50a854625fe0d7f35", + "wy" : "6d2589ac655edc9a11ef3e075eddda9abf92e72171570ef7bf43a2ee39338cfe" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000484db645868eab35e3a9fd80e056e2e855435e3a6b68d75a50a854625fe0d7f356d2589ac655edc9a11ef3e075eddda9abf92e72171570ef7bf43a2ee39338cfe", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhNtkWGjqs146n9gOBW4uhVQ146a2\njXWlCoVGJf4NfzVtJYmsZV7cmhHvPgde3dqav5LnIXFXDve/Q6LuOTOM/g==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 159, + "comment" : "edge case for u2", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbb1d9ac949dd748cd02bbbe749bd351cd57b38bb61403d700686aa7b4c90851e", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "kbnkfFYnhmLXXAmDsiyo6mqlBZt6L_djfrKXXjhq1mM", + "y" : "SaqP8oPQ93wY1tEdwGIWX9E8PAMQZ5wUCDAqFoVOz70" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "0491b9e47c56278662d75c0983b22ca8ea6aa5059b7a2ff7637eb2975e386ad66349aa8ff283d0f77c18d6d11dc062165fd13c3c0310679c1408302a16854ecfbd", + "wx" : "0091b9e47c56278662d75c0983b22ca8ea6aa5059b7a2ff7637eb2975e386ad663", + "wy" : "49aa8ff283d0f77c18d6d11dc062165fd13c3c0310679c1408302a16854ecfbd" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000491b9e47c56278662d75c0983b22ca8ea6aa5059b7a2ff7637eb2975e386ad66349aa8ff283d0f77c18d6d11dc062165fd13c3c0310679c1408302a16854ecfbd", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkbnkfFYnhmLXXAmDsiyo6mqlBZt6\nL/djfrKXXjhq1mNJqo/yg9D3fBjW0R3AYhZf0Tw8AxBnnBQIMCoWhU7PvQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 160, + "comment" : "edge case for u2", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd66755a00638cdaec1c732513ca0234ece52545dac11f816e818f725b4f60aaf2", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "8-wvE8rwTQGStH-0xTEfttTcawqegC5TJ_fsXujkg00", + "y" : "-X4-Rot9Dbhn1uz-geKw-VMd-H79tHwTOKwyH-_lpDI" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04f3ec2f13caf04d0192b47fb4c5311fb6d4dc6b0a9e802e5327f7ec5ee8e4834df97e3e468b7d0db867d6ecfe81e2b0f9531df87efdb47c1338ac321fefe5a432", + "wx" : "00f3ec2f13caf04d0192b47fb4c5311fb6d4dc6b0a9e802e5327f7ec5ee8e4834d", + "wy" : "00f97e3e468b7d0db867d6ecfe81e2b0f9531df87efdb47c1338ac321fefe5a432" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004f3ec2f13caf04d0192b47fb4c5311fb6d4dc6b0a9e802e5327f7ec5ee8e4834df97e3e468b7d0db867d6ecfe81e2b0f9531df87efdb47c1338ac321fefe5a432", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8+wvE8rwTQGStH+0xTEfttTcawqe\ngC5TJ/fsXujkg035fj5Gi30NuGfW7P6B4rD5Ux34fv20fBM4rDIf7+WkMg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 161, + "comment" : "edge case for u2", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd55a00c9fcdaebb6032513ca0234ecfffe98ebe492fdf02e48ca48e982beb3669", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "2SsgCu_Ktqx9r9msry-hCzGAI1uPRrRQPkaTxnD8zIg", + "y" : "XvLzrr9bMXR1M2JWdo98Ge-3NS0n5MzK3IW2uKuSLHI" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04d92b200aefcab6ac7dafd9acaf2fa10b3180235b8f46b4503e4693c670fccc885ef2f3aebf5b317475336256768f7c19efb7352d27e4cccadc85b6b8ab922c72", + "wx" : "00d92b200aefcab6ac7dafd9acaf2fa10b3180235b8f46b4503e4693c670fccc88", + "wy" : "5ef2f3aebf5b317475336256768f7c19efb7352d27e4cccadc85b6b8ab922c72" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004d92b200aefcab6ac7dafd9acaf2fa10b3180235b8f46b4503e4693c670fccc885ef2f3aebf5b317475336256768f7c19efb7352d27e4cccadc85b6b8ab922c72", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2SsgCu/Ktqx9r9msry+hCzGAI1uP\nRrRQPkaTxnD8zIhe8vOuv1sxdHUzYlZ2j3wZ77c1LSfkzMrchba4q5Iscg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 162, + "comment" : "edge case for u2", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdab40193f9b5d76c064a27940469d9fffd31d7c925fbe05c919491d3057d66cd2", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "Cog2HrkuzKJiWzjl-Yu6u5a_F5s9dvxIFAo7zYgVI80", + "y" : "5r31YDP4SlBUA1WXN12QhmqiyWuGpBzPbt6_RymK1Ik" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "040a88361eb92ecca2625b38e5f98bbabb96bf179b3d76fc48140a3bcd881523cde6bdf56033f84a5054035597375d90866aa2c96b86a41ccf6edebf47298ad489", + "wx" : "0a88361eb92ecca2625b38e5f98bbabb96bf179b3d76fc48140a3bcd881523cd", + "wy" : "00e6bdf56033f84a5054035597375d90866aa2c96b86a41ccf6edebf47298ad489" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200040a88361eb92ecca2625b38e5f98bbabb96bf179b3d76fc48140a3bcd881523cde6bdf56033f84a5054035597375d90866aa2c96b86a41ccf6edebf47298ad489", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECog2HrkuzKJiWzjl+Yu6u5a/F5s9\ndvxIFAo7zYgVI83mvfVgM/hKUFQDVZc3XZCGaqLJa4akHM9u3r9HKYrUiQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 163, + "comment" : "edge case for u2", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdca0234ebb5fdcb13ca0234ecffffffffcb0dadbbc7f549f8a26b4408d0dc8600", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "0PsXzNj6_oJ-DBr8XY2ANm4rIOfxSlY6K6UEadhDdeg", + "y" : "aGEladOeK7n1VDVVZGRt6ZrGAsxjSc-MHiNqfedjfZM" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04d0fb17ccd8fafe827e0c1afc5d8d80366e2b20e7f14a563a2ba50469d84375e868612569d39e2bb9f554355564646de99ac602cc6349cf8c1e236a7de7637d93", + "wx" : "00d0fb17ccd8fafe827e0c1afc5d8d80366e2b20e7f14a563a2ba50469d84375e8", + "wy" : "68612569d39e2bb9f554355564646de99ac602cc6349cf8c1e236a7de7637d93" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004d0fb17ccd8fafe827e0c1afc5d8d80366e2b20e7f14a563a2ba50469d84375e868612569d39e2bb9f554355564646de99ac602cc6349cf8c1e236a7de7637d93", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0PsXzNj6/oJ+DBr8XY2ANm4rIOfx\nSlY6K6UEadhDdehoYSVp054rufVUNVVkZG3pmsYCzGNJz4weI2p952N9kw==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 164, + "comment" : "edge case for u2", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbfffffff3ea3677e082b9310572620ae19933a9e65b285598711c77298815ad3", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "g28zu8HcDT06u87w2R8R4qxBgQdsmvCiKx5DCdPtsnY", + "y" : "mrRD_2-QHjDHc4Z1gpl8K-wrDLgSDXYCNvOpW76IH3U" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04836f33bbc1dc0d3d3abbcef0d91f11e2ac4181076c9af0a22b1e4309d3edb2769ab443ff6f901e30c773867582997c2bec2b0cb8120d760236f3a95bbe881f75", + "wx" : "00836f33bbc1dc0d3d3abbcef0d91f11e2ac4181076c9af0a22b1e4309d3edb276", + "wy" : "009ab443ff6f901e30c773867582997c2bec2b0cb8120d760236f3a95bbe881f75" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004836f33bbc1dc0d3d3abbcef0d91f11e2ac4181076c9af0a22b1e4309d3edb2769ab443ff6f901e30c773867582997c2bec2b0cb8120d760236f3a95bbe881f75", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEg28zu8HcDT06u87w2R8R4qxBgQds\nmvCiKx5DCdPtsnaatEP/b5AeMMdzhnWCmXwr7CsMuBINdgI286lbvogfdQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 165, + "comment" : "edge case for u2", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd266666663bbbbbbbe6666666666666665b37902e023fab7c8f055d86e5cc41f4", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "kvmfvpc-1KKZcZuu5LQydBI3A03sjXK6UQPLM-Vf7rg", + "y" : "Az3Q6RE0xzQXSInz688behrAV2cokoDuenlM69bmlpc" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "0492f99fbe973ed4a299719baee4b432741237034dec8d72ba5103cb33e55feeb8033dd0e91134c734174889f3ebcf1b7a1ac05767289280ee7a794cebd6e69697", + "wx" : "0092f99fbe973ed4a299719baee4b432741237034dec8d72ba5103cb33e55feeb8", + "wy" : "033dd0e91134c734174889f3ebcf1b7a1ac05767289280ee7a794cebd6e69697" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000492f99fbe973ed4a299719baee4b432741237034dec8d72ba5103cb33e55feeb8033dd0e91134c734174889f3ebcf1b7a1ac05767289280ee7a794cebd6e69697", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkvmfvpc+1KKZcZuu5LQydBI3A03s\njXK6UQPLM+Vf7rgDPdDpETTHNBdIifPrzxt6GsBXZyiSgO56eUzr1uaWlw==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 166, + "comment" : "edge case for u2", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbfffffff36db6db7a492492492492492146c573f4c6dfc8d08a443e258970b09", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "01uljaMBl9N45hjsD6fi4tEs_9c-u7IEnRMLukNK8J4", + "y" : "_4OYbmh15B6kMrdYWkmzpsd8uzxHkZ-OgodMeUY1wdI" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04d35ba58da30197d378e618ec0fa7e2e2d12cffd73ebbb2049d130bba434af09eff83986e6875e41ea432b7585a49b3a6c77cbb3c47919f8e82874c794635c1d2", + "wx" : "00d35ba58da30197d378e618ec0fa7e2e2d12cffd73ebbb2049d130bba434af09e", + "wy" : "00ff83986e6875e41ea432b7585a49b3a6c77cbb3c47919f8e82874c794635c1d2" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004d35ba58da30197d378e618ec0fa7e2e2d12cffd73ebbb2049d130bba434af09eff83986e6875e41ea432b7585a49b3a6c77cbb3c47919f8e82874c794635c1d2", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE01uljaMBl9N45hjsD6fi4tEs/9c+\nu7IEnRMLukNK8J7/g5huaHXkHqQyt1haSbOmx3y7PEeRn46Ch0x5RjXB0g==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 167, + "comment" : "edge case for u2", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbfffffff2aaaaaab7fffffffffffffffc815d0e60b3e596ecb1ad3a27cfd49c4", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "hlHOSQ8bRtc_P_R1FJvikTZpczSlGdfdqwclyNB5MiQ", + "y" : "4RxlvYypLci8mugpEfC1J1HOId2QA65gkAvYJfWQzCg" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "048651ce490f1b46d73f3ff475149be29136697334a519d7ddab0725c8d0793224e11c65bd8ca92dc8bc9ae82911f0b52751ce21dd9003ae60900bd825f590cc28", + "wx" : "008651ce490f1b46d73f3ff475149be29136697334a519d7ddab0725c8d0793224", + "wy" : "00e11c65bd8ca92dc8bc9ae82911f0b52751ce21dd9003ae60900bd825f590cc28" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200048651ce490f1b46d73f3ff475149be29136697334a519d7ddab0725c8d0793224e11c65bd8ca92dc8bc9ae82911f0b52751ce21dd9003ae60900bd825f590cc28", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhlHOSQ8bRtc/P/R1FJvikTZpczSl\nGdfdqwclyNB5MiThHGW9jKktyLya6CkR8LUnUc4h3ZADrmCQC9gl9ZDMKA==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 168, + "comment" : "edge case for u2", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd7fffffff55555555ffffffffffffffffd344a71e6f651458a27bdc81fd976e37", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "bY4bEsgxoNqHlWUP-V8QHtkh2eL3KxWxzaypgmuc_G0", + "y" : "721j4rxcCJVwOUpLyfiS1ebHpqY3sgRppYwQatSGvzc" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "046d8e1b12c831a0da8795650ff95f101ed921d9e2f72b15b1cdaca9826b9cfc6def6d63e2bc5c089570394a4bc9f892d5e6c7a6a637b20469a58c106ad486bf37", + "wx" : "6d8e1b12c831a0da8795650ff95f101ed921d9e2f72b15b1cdaca9826b9cfc6d", + "wy" : "00ef6d63e2bc5c089570394a4bc9f892d5e6c7a6a637b20469a58c106ad486bf37" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200046d8e1b12c831a0da8795650ff95f101ed921d9e2f72b15b1cdaca9826b9cfc6def6d63e2bc5c089570394a4bc9f892d5e6c7a6a637b20469a58c106ad486bf37", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbY4bEsgxoNqHlWUP+V8QHtkh2eL3\nKxWxzaypgmuc/G3vbWPivFwIlXA5SkvJ+JLV5sempjeyBGmljBBq1Ia/Nw==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 169, + "comment" : "edge case for u2", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd3fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192aa", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "CuWAuukztO8pl8vbsJIjKMqaQQ9ieg99_yTLTZIOFUI", + "y" : "iRHn-Mw2WoqI64FCGjYczCuZ4wnY3Nmpi6g8OUnYk-M" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "040ae580bae933b4ef2997cbdbb0922328ca9a410f627a0f7dff24cb4d920e15428911e7f8cc365a8a88eb81421a361ccc2b99e309d8dcd9a98ba83c3949d893e3", + "wx" : "0ae580bae933b4ef2997cbdbb0922328ca9a410f627a0f7dff24cb4d920e1542", + "wy" : "008911e7f8cc365a8a88eb81421a361ccc2b99e309d8dcd9a98ba83c3949d893e3" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200040ae580bae933b4ef2997cbdbb0922328ca9a410f627a0f7dff24cb4d920e15428911e7f8cc365a8a88eb81421a361ccc2b99e309d8dcd9a98ba83c3949d893e3", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECuWAuukztO8pl8vbsJIjKMqaQQ9i\neg99/yTLTZIOFUKJEef4zDZaiojrgUIaNhzMK5njCdjc2amLqDw5SdiT4w==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 170, + "comment" : "edge case for u2", + "msg" : "313233343030", + "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd5d8ecd64a4eeba466815ddf3a4de9a8e6abd9c5db0a01eb80343553da648428f", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "W4Ev1SGq-mmDWoSczm-962mDtELSRE_nDhNMAn_EaWM", + "y" : "g4pA8qNgkukATpLY2UDPVjhVDOZyzouNThXrpUmSSek" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "045b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc46963838a40f2a36092e9004e92d8d940cf5638550ce672ce8b8d4e15eba5499249e9", + "wx" : "5b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc46963", + "wy" : "00838a40f2a36092e9004e92d8d940cf5638550ce672ce8b8d4e15eba5499249e9" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200045b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc46963838a40f2a36092e9004e92d8d940cf5638550ce672ce8b8d4e15eba5499249e9", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW4Ev1SGq+mmDWoSczm+962mDtELS\nRE/nDhNMAn/EaWODikDyo2CS6QBOktjZQM9WOFUM5nLOi41OFeulSZJJ6Q==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 171, + "comment" : "point duplication during verification", + "msg" : "313233343030", + "sig" : "6f2347cab7dd76858fe0555ac3bc99048c4aacafdfb6bcbe05ea6c42c4934569bb726660235793aa9957a61e76e00c2c435109cf9a15dd624d53f4301047856b", + "result" : "valid", + "flags" : [ + "PointDuplication" + ] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "W4Ev1SGq-mmDWoSczm-962mDtELSRE_nDhNMAn_EaWM", + "y" : "fHW_DFyfbRf_sW0nJr8wqceq8xqNMXRyseoUWrZtthY" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "045b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc469637c75bf0c5c9f6d17ffb16d2726bf30a9c7aaf31a8d317472b1ea145ab66db616", + "wx" : "5b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc46963", + "wy" : "7c75bf0c5c9f6d17ffb16d2726bf30a9c7aaf31a8d317472b1ea145ab66db616" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200045b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc469637c75bf0c5c9f6d17ffb16d2726bf30a9c7aaf31a8d317472b1ea145ab66db616", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW4Ev1SGq+mmDWoSczm+962mDtELS\nRE/nDhNMAn/EaWN8db8MXJ9tF/+xbScmvzCpx6rzGo0xdHKx6hRatm22Fg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 172, + "comment" : "duplication bug", + "msg" : "313233343030", + "sig" : "6f2347cab7dd76858fe0555ac3bc99048c4aacafdfb6bcbe05ea6c42c4934569bb726660235793aa9957a61e76e00c2c435109cf9a15dd624d53f4301047856b", + "result" : "invalid", + "flags" : [ + "PointDuplication" + ] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "at2oK5AmGw8xn6oNh4ZlprbaSX8JyQMXYiLDSs_vcqY", + "y" : "R-b1DcxArV2bWfdgK7Ii-tcaQb9eH530lZo2TGLkiNk" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "046adda82b90261b0f319faa0d878665a6b6da497f09c903176222c34acfef72a647e6f50dcc40ad5d9b59f7602bb222fad71a41bf5e1f9df4959a364c62e488d9", + "wx" : "6adda82b90261b0f319faa0d878665a6b6da497f09c903176222c34acfef72a6", + "wy" : "47e6f50dcc40ad5d9b59f7602bb222fad71a41bf5e1f9df4959a364c62e488d9" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200046adda82b90261b0f319faa0d878665a6b6da497f09c903176222c34acfef72a647e6f50dcc40ad5d9b59f7602bb222fad71a41bf5e1f9df4959a364c62e488d9", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEat2oK5AmGw8xn6oNh4ZlprbaSX8J\nyQMXYiLDSs/vcqZH5vUNzECtXZtZ92ArsiL61xpBv14fnfSVmjZMYuSI2Q==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 173, + "comment" : "point with x-coordinate 0", + "msg" : "313233343030", + "sig" : "0000000000000000000000000000000000000000000000000000000000000001555555550000000055555555555555553ef7a8e48d07df81a693439654210c70", + "result" : "invalid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "L8oNCkeRTed-1W5-zMMnamARIMbfAGnIJcj2oByfOCA", + "y" : "ZfNFCh0XxrJJiaOb6xx97PyoOE-9wpRBjl2Aezxu194" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "042fca0d0a47914de77ed56e7eccc3276a601120c6df0069c825c8f6a01c9f382065f3450a1d17c6b24989a39beb1c7decfca8384fbdc294418e5d807b3c6ed7de", + "wx" : "2fca0d0a47914de77ed56e7eccc3276a601120c6df0069c825c8f6a01c9f3820", + "wy" : "65f3450a1d17c6b24989a39beb1c7decfca8384fbdc294418e5d807b3c6ed7de" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200042fca0d0a47914de77ed56e7eccc3276a601120c6df0069c825c8f6a01c9f382065f3450a1d17c6b24989a39beb1c7decfca8384fbdc294418e5d807b3c6ed7de", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEL8oNCkeRTed+1W5+zMMnamARIMbf\nAGnIJcj2oByfOCBl80UKHRfGskmJo5vrHH3s/Kg4T73ClEGOXYB7PG7X3g==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 174, + "comment" : "point with x-coordinate 0", + "msg" : "313233343030", + "sig" : "010000000000000000000000000000000000000000000000000000000000000000003333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aa9", + "result" : "invalid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "3YbTtfShPoURCDt4ACCBxT_0Z_EevZilGmM9t2Zl0lA", + "y" : "RdXIIAyJ8voQ2Ek0kibSHY367W_41cs-G34XR068GPc" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04dd86d3b5f4a13e8511083b78002081c53ff467f11ebd98a51a633db76665d25045d5c8200c89f2fa10d849349226d21d8dfaed6ff8d5cb3e1b7e17474ebc18f7", + "wx" : "00dd86d3b5f4a13e8511083b78002081c53ff467f11ebd98a51a633db76665d250", + "wy" : "45d5c8200c89f2fa10d849349226d21d8dfaed6ff8d5cb3e1b7e17474ebc18f7" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004dd86d3b5f4a13e8511083b78002081c53ff467f11ebd98a51a633db76665d25045d5c8200c89f2fa10d849349226d21d8dfaed6ff8d5cb3e1b7e17474ebc18f7", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3YbTtfShPoURCDt4ACCBxT/0Z/Ee\nvZilGmM9t2Zl0lBF1cggDIny+hDYSTSSJtIdjfrtb/jVyz4bfhdHTrwY9w==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 175, + "comment" : "comparison with point at infinity ", + "msg" : "313233343030", + "sig" : "555555550000000055555555555555553ef7a8e48d07df81a693439654210c703333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aa9", + "result" : "invalid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "T-pVsyyzKsoMEsTNCr-05ksPWlFuV4wBZZGpP1oPvMU", + "y" : "19P9ELK-ZoxUeyEva7FMiPD-zTiopLLHhe075izksoA" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "044fea55b32cb32aca0c12c4cd0abfb4e64b0f5a516e578c016591a93f5a0fbcc5d7d3fd10b2be668c547b212f6bb14c88f0fecd38a8a4b2c785ed3be62ce4b280", + "wx" : "4fea55b32cb32aca0c12c4cd0abfb4e64b0f5a516e578c016591a93f5a0fbcc5", + "wy" : "00d7d3fd10b2be668c547b212f6bb14c88f0fecd38a8a4b2c785ed3be62ce4b280" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200044fea55b32cb32aca0c12c4cd0abfb4e64b0f5a516e578c016591a93f5a0fbcc5d7d3fd10b2be668c547b212f6bb14c88f0fecd38a8a4b2c785ed3be62ce4b280", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAET+pVsyyzKsoMEsTNCr+05ksPWlFu\nV4wBZZGpP1oPvMXX0/0Qsr5mjFR7IS9rsUyI8P7NOKiksseF7TvmLOSygA==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 176, + "comment" : "extreme value for k and edgecase s", + "msg" : "313233343030", + "sig" : "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978555555550000000055555555555555553ef7a8e48d07df81a693439654210c70", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "xqdxUnAkIneSFwpvju5zW_Mrf5ivZp6tKZgC4y18MQc", + "y" : "vDtLXmWriHu9NDVys-VhkmH-Ogc-L_14QS9yaGfbWJ4" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04c6a771527024227792170a6f8eee735bf32b7f98af669ead299802e32d7c3107bc3b4b5e65ab887bbd343572b3e5619261fe3a073e2ffd78412f726867db589e", + "wx" : "00c6a771527024227792170a6f8eee735bf32b7f98af669ead299802e32d7c3107", + "wy" : "00bc3b4b5e65ab887bbd343572b3e5619261fe3a073e2ffd78412f726867db589e" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004c6a771527024227792170a6f8eee735bf32b7f98af669ead299802e32d7c3107bc3b4b5e65ab887bbd343572b3e5619261fe3a073e2ffd78412f726867db589e", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExqdxUnAkIneSFwpvju5zW/Mrf5iv\nZp6tKZgC4y18MQe8O0teZauIe700NXKz5WGSYf46Bz4v/XhBL3JoZ9tYng==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 177, + "comment" : "extreme value for k and s^-1", + "msg" : "313233343030", + "sig" : "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978b6db6db6249249254924924924924924625bd7a09bec4ca81bcdd9f8fd6b63cc", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "hRwrutCOVOx6mvmfSfA2RNbsbVmyB_7JjehafRW5Vu8", + "y" : "zumWAoMEUHVoS0EL6ND3SUuRqiN59gcnMZ8Q3esP6dY" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04851c2bbad08e54ec7a9af99f49f03644d6ec6d59b207fec98de85a7d15b956efcee9960283045075684b410be8d0f7494b91aa2379f60727319f10ddeb0fe9d6", + "wx" : "00851c2bbad08e54ec7a9af99f49f03644d6ec6d59b207fec98de85a7d15b956ef", + "wy" : "00cee9960283045075684b410be8d0f7494b91aa2379f60727319f10ddeb0fe9d6" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004851c2bbad08e54ec7a9af99f49f03644d6ec6d59b207fec98de85a7d15b956efcee9960283045075684b410be8d0f7494b91aa2379f60727319f10ddeb0fe9d6", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhRwrutCOVOx6mvmfSfA2RNbsbVmy\nB/7JjehafRW5Vu/O6ZYCgwRQdWhLQQvo0PdJS5GqI3n2BycxnxDd6w/p1g==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 178, + "comment" : "extreme value for k and s^-1", + "msg" : "313233343030", + "sig" : "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978cccccccc00000000cccccccccccccccc971f2ef152794b9d8fc7d568c9e8eaa7", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "9kF8imcFhOOIZ2lJ5T2n_FWRH_aDGNG_MGEgWssZxI8", + "y" : "jyt0PfNK0PcmdKy3UFkpeEd5zZrJFsNmnq1DAmq21D8" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04f6417c8a670584e388676949e53da7fc55911ff68318d1bf3061205acb19c48f8f2b743df34ad0f72674acb7505929784779cd9ac916c3669ead43026ab6d43f", + "wx" : "00f6417c8a670584e388676949e53da7fc55911ff68318d1bf3061205acb19c48f", + "wy" : "008f2b743df34ad0f72674acb7505929784779cd9ac916c3669ead43026ab6d43f" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004f6417c8a670584e388676949e53da7fc55911ff68318d1bf3061205acb19c48f8f2b743df34ad0f72674acb7505929784779cd9ac916c3669ead43026ab6d43f", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9kF8imcFhOOIZ2lJ5T2n/FWRH/aD\nGNG/MGEgWssZxI+PK3Q980rQ9yZ0rLdQWSl4R3nNmskWw2aerUMCarbUPw==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 179, + "comment" : "extreme value for k and s^-1", + "msg" : "313233343030", + "sig" : "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc476699783333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aaa", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "UBQhJ3vkWl7v7GxjmTDWNgMlZa9CDPM3P1V_qn-KBkM", + "y" : "hnPWy2B24c_Nx9_nOEyOXKwI10UB8q5uicrRldCqE3E" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04501421277be45a5eefec6c639930d636032565af420cf3373f557faa7f8a06438673d6cb6076e1cfcdc7dfe7384c8e5cac08d74501f2ae6e89cad195d0aa1371", + "wx" : "501421277be45a5eefec6c639930d636032565af420cf3373f557faa7f8a0643", + "wy" : "008673d6cb6076e1cfcdc7dfe7384c8e5cac08d74501f2ae6e89cad195d0aa1371" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004501421277be45a5eefec6c639930d636032565af420cf3373f557faa7f8a06438673d6cb6076e1cfcdc7dfe7384c8e5cac08d74501f2ae6e89cad195d0aa1371", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUBQhJ3vkWl7v7GxjmTDWNgMlZa9C\nDPM3P1V/qn+KBkOGc9bLYHbhz83H3+c4TI5crAjXRQHyrm6JytGV0KoTcQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 180, + "comment" : "extreme value for k and s^-1", + "msg" : "313233343030", + "sig" : "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc4766997849249248db6db6dbb6db6db6db6db6db5a8b230d0b2b51dcd7ebf0c9fef7c185", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "DZNb-f_BFaUnc19ynKikyiPuAaSJSt8ONBWshOgIuzQ", + "y" : "MZWjdi_qKe04kSvZ6mxP3nDDBQiTpDdYUM5h2C66M8U" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "040d935bf9ffc115a527735f729ca8a4ca23ee01a4894adf0e3415ac84e808bb343195a3762fea29ed38912bd9ea6c4fde70c3050893a4375850ce61d82eba33c5", + "wx" : "0d935bf9ffc115a527735f729ca8a4ca23ee01a4894adf0e3415ac84e808bb34", + "wy" : "3195a3762fea29ed38912bd9ea6c4fde70c3050893a4375850ce61d82eba33c5" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200040d935bf9ffc115a527735f729ca8a4ca23ee01a4894adf0e3415ac84e808bb343195a3762fea29ed38912bd9ea6c4fde70c3050893a4375850ce61d82eba33c5", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDZNb+f/BFaUnc19ynKikyiPuAaSJ\nSt8ONBWshOgIuzQxlaN2L+op7TiRK9nqbE/ecMMFCJOkN1hQzmHYLrozxQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 181, + "comment" : "extreme value for k", + "msg" : "313233343030", + "sig" : "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc4766997816a4502e2781e11ac82cbc9d1edd8c981584d13e18411e2f6e0478c34416e3bb", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "Xln1Bwhka-iliTVQFDCOYLZo-2cBliBsQedI5k5NyiE", + "y" : "XeN_7lyXvK9xRNW0WZgvUu7q-98Dqsuv7zjiE2JKAd4" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "045e59f50708646be8a589355014308e60b668fb670196206c41e748e64e4dca215de37fee5c97bcaf7144d5b459982f52eeeafbdf03aacbafef38e213624a01de", + "wx" : "5e59f50708646be8a589355014308e60b668fb670196206c41e748e64e4dca21", + "wy" : "5de37fee5c97bcaf7144d5b459982f52eeeafbdf03aacbafef38e213624a01de" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200045e59f50708646be8a589355014308e60b668fb670196206c41e748e64e4dca215de37fee5c97bcaf7144d5b459982f52eeeafbdf03aacbafef38e213624a01de", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXln1Bwhka+iliTVQFDCOYLZo+2cB\nliBsQedI5k5NyiFd43/uXJe8r3FE1bRZmC9S7ur73wOqy6/vOOITYkoB3g==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 182, + "comment" : "extreme value for k and edgecase s", + "msg" : "313233343030", + "sig" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296555555550000000055555555555555553ef7a8e48d07df81a693439654210c70", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "Fp-3lzJYQ_r_L3pbVEXani_WIm9--Q7wv-kkEEsC244", + "y" : "e7uN5mLHubHPmyL3ouWCvUbVgdaIeO-yuGGxMdih1mc" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04169fb797325843faff2f7a5b5445da9e2fd6226f7ef90ef0bfe924104b02db8e7bbb8de662c7b9b1cf9b22f7a2e582bd46d581d68878efb2b861b131d8a1d667", + "wx" : "169fb797325843faff2f7a5b5445da9e2fd6226f7ef90ef0bfe924104b02db8e", + "wy" : "7bbb8de662c7b9b1cf9b22f7a2e582bd46d581d68878efb2b861b131d8a1d667" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004169fb797325843faff2f7a5b5445da9e2fd6226f7ef90ef0bfe924104b02db8e7bbb8de662c7b9b1cf9b22f7a2e582bd46d581d68878efb2b861b131d8a1d667", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFp+3lzJYQ/r/L3pbVEXani/WIm9+\n+Q7wv+kkEEsC2457u43mYse5sc+bIvei5YK9RtWB1oh477K4YbEx2KHWZw==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 183, + "comment" : "extreme value for k and s^-1", + "msg" : "313233343030", + "sig" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296b6db6db6249249254924924924924924625bd7a09bec4ca81bcdd9f8fd6b63cc", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "JxzYnAABQwlrYtTp5MqIWu8vcCPRiv_a-Le1SJgUh1Q", + "y" : "ChxulU4yEIQ1tV-jhbD3ZIGmCbkUnMtLArLKR_6OTaU" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04271cd89c000143096b62d4e9e4ca885aef2f7023d18affdaf8b7b548981487540a1c6e954e32108435b55fa385b0f76481a609b9149ccb4b02b2ca47fe8e4da5", + "wx" : "271cd89c000143096b62d4e9e4ca885aef2f7023d18affdaf8b7b54898148754", + "wy" : "0a1c6e954e32108435b55fa385b0f76481a609b9149ccb4b02b2ca47fe8e4da5" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004271cd89c000143096b62d4e9e4ca885aef2f7023d18affdaf8b7b548981487540a1c6e954e32108435b55fa385b0f76481a609b9149ccb4b02b2ca47fe8e4da5", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJxzYnAABQwlrYtTp5MqIWu8vcCPR\niv/a+Le1SJgUh1QKHG6VTjIQhDW1X6OFsPdkgaYJuRScy0sCsspH/o5NpQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 184, + "comment" : "extreme value for k and s^-1", + "msg" : "313233343030", + "sig" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296cccccccc00000000cccccccccccccccc971f2ef152794b9d8fc7d568c9e8eaa7", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "PQvH7Y8J0st920brwe15mrFWOpq4S_UkWHoiCv5JnBI", + "y" : "4i3Ds8EDgkpPN42WrbCkCKvxnOfWiqYkT3jLIW-j-N8" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "043d0bc7ed8f09d2cb7ddb46ebc1ed799ab1563a9ab84bf524587a220afe499c12e22dc3b3c103824a4f378d96adb0a408abf19ce7d68aa6244f78cb216fa3f8df", + "wx" : "3d0bc7ed8f09d2cb7ddb46ebc1ed799ab1563a9ab84bf524587a220afe499c12", + "wy" : "00e22dc3b3c103824a4f378d96adb0a408abf19ce7d68aa6244f78cb216fa3f8df" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200043d0bc7ed8f09d2cb7ddb46ebc1ed799ab1563a9ab84bf524587a220afe499c12e22dc3b3c103824a4f378d96adb0a408abf19ce7d68aa6244f78cb216fa3f8df", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPQvH7Y8J0st920brwe15mrFWOpq4\nS/UkWHoiCv5JnBLiLcOzwQOCSk83jZatsKQIq/Gc59aKpiRPeMshb6P43w==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 185, + "comment" : "extreme value for k and s^-1", + "msg" : "313233343030", + "sig" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2963333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aaa", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "psiFreGkxWb5uwENBml0q7KBeX-nASiMchvL0jZjqbc", + "y" : "LkJLaQlXFo0ZOmCW_HeisASpx9Rn4Afh8gWEWPmK8xY" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04a6c885ade1a4c566f9bb010d066974abb281797fa701288c721bcbd23663a9b72e424b690957168d193a6096fc77a2b004a9c7d467e007e1f2058458f98af316", + "wx" : "00a6c885ade1a4c566f9bb010d066974abb281797fa701288c721bcbd23663a9b7", + "wy" : "2e424b690957168d193a6096fc77a2b004a9c7d467e007e1f2058458f98af316" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004a6c885ade1a4c566f9bb010d066974abb281797fa701288c721bcbd23663a9b72e424b690957168d193a6096fc77a2b004a9c7d467e007e1f2058458f98af316", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpsiFreGkxWb5uwENBml0q7KBeX+n\nASiMchvL0jZjqbcuQktpCVcWjRk6YJb8d6KwBKnH1GfgB+HyBYRY+YrzFg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 186, + "comment" : "extreme value for k and s^-1", + "msg" : "313233343030", + "sig" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29649249248db6db6dbb6db6db6db6db6db5a8b230d0b2b51dcd7ebf0c9fef7c185", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "jTwsLDt2W6gonmrDgSVyolv3XfYth6tzMMO9utnr-lw", + "y" : "TGhFRC1mk1sjhXjUOuxU98qhYh0a8kHUYy4LeAxCP10" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "048d3c2c2c3b765ba8289e6ac3812572a25bf75df62d87ab7330c3bdbad9ebfa5c4c6845442d66935b238578d43aec54f7caa1621d1af241d4632e0b780c423f5d", + "wx" : "008d3c2c2c3b765ba8289e6ac3812572a25bf75df62d87ab7330c3bdbad9ebfa5c", + "wy" : "4c6845442d66935b238578d43aec54f7caa1621d1af241d4632e0b780c423f5d" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200048d3c2c2c3b765ba8289e6ac3812572a25bf75df62d87ab7330c3bdbad9ebfa5c4c6845442d66935b238578d43aec54f7caa1621d1af241d4632e0b780c423f5d", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjTwsLDt2W6gonmrDgSVyolv3XfYt\nh6tzMMO9utnr+lxMaEVELWaTWyOFeNQ67FT3yqFiHRryQdRjLgt4DEI/XQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 187, + "comment" : "extreme value for k", + "msg" : "313233343030", + "sig" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29616a4502e2781e11ac82cbc9d1edd8c981584d13e18411e2f6e0478c34416e3bb", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpY", + "y" : "T-NC4v4af5uO5-tKfA-eFivOM1drMV7Oy7ZAaDe_UfU" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", + "wx" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", + "wy" : "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaxfR8uEsQkf4vOblY6RA8ncDfYEt\n6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9Q==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 188, + "comment" : "testing point duplication", + "msg" : "313233343030", + "sig" : "bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2", + "result" : "invalid", + "flags" : [] + }, + { + "tcId" : 189, + "comment" : "testing point duplication", + "msg" : "313233343030", + "sig" : "44a5ad0ad0636d9f12bc9e0a6bdd5e1cbcb012ea7bf091fcec15b0c43202d52e249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2", + "result" : "invalid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpY", + "y" : "sBy9HAHlgGVxGBS1g_Bh6dQxzKmUzqExNEm_l8hArgo" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296b01cbd1c01e58065711814b583f061e9d431cca994cea1313449bf97c840ae0a", + "wx" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", + "wy" : "00b01cbd1c01e58065711814b583f061e9d431cca994cea1313449bf97c840ae0a" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296b01cbd1c01e58065711814b583f061e9d431cca994cea1313449bf97c840ae0a", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaxfR8uEsQkf4vOblY6RA8ncDfYEt\n6zOg9KE5RdiYwpawHL0cAeWAZXEYFLWD8GHp1DHMqZTOoTE0Sb+XyECuCg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 190, + "comment" : "testing point duplication", + "msg" : "313233343030", + "sig" : "bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2", + "result" : "invalid", + "flags" : [] + }, + { + "tcId" : 191, + "comment" : "testing point duplication", + "msg" : "313233343030", + "sig" : "44a5ad0ad0636d9f12bc9e0a6bdd5e1cbcb012ea7bf091fcec15b0c43202d52e249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2", + "result" : "invalid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "BKrsc2NXJvIT-4qeZNo7hjLkFJWpRNAEW1IuunJA-tU", + "y" : "h9kxV5iqo6W6AXdXh87QXqr3tOCfyB1tGqVG6DZdUl0" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "0404aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad587d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d", + "wx" : "04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5", + "wy" : "0087d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000404aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad587d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBKrsc2NXJvIT+4qeZNo7hjLkFJWp\nRNAEW1IuunJA+tWH2TFXmKqjpboBd1eHztBeqve04J/IHW0apUboNl1SXQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 192, + "comment" : "pseudorandom signature", + "msg" : "", + "sig" : "b292a619339f6e567a305c951c0dcbcc42d16e47f219f9e98e76e09d8770b34a0177e60492c5a8242f76f07bfe3661bde59ec2a17ce5bd2dab2abebdf89a62e2", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 193, + "comment" : "pseudorandom signature", + "msg" : "4d7367", + "sig" : "530bd6b0c9af2d69ba897f6b5fb59695cfbf33afe66dbadcf5b8d2a2a6538e23d85e489cb7a161fd55ededcedbf4cc0c0987e3e3f0f242cae934c72caa3f43e9", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 194, + "comment" : "pseudorandom signature", + "msg" : "313233343030", + "sig" : "a8ea150cb80125d7381c4c1f1da8e9de2711f9917060406a73d7904519e51388f3ab9fa68bd47973a73b2d40480c2ba50c22c9d76ec217257288293285449b86", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 195, + "comment" : "pseudorandom signature", + "msg" : "0000000000000000000000000000000000000000", + "sig" : "986e65933ef2ed4ee5aada139f52b70539aaf63f00a91f29c69178490d57fb713dafedfb8da6189d372308cbf1489bbbdabf0c0217d1c0ff0f701aaa7a694b9c", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "TzN8z9Z3JqgF5PFgCuKEnfOAfsoRc4Ajn72BaQAAAAA", + "y" : "7Z3qEkzIw5ZBZBHpiMMPQn61BK9DoxRs1d9-pgZm1oU" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "044f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685", + "wx" : "4f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000", + "wy" : "00ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200044f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETzN8z9Z3JqgF5PFgCuKEnfOAfsoR\nc4Ajn72BaQAAAADtneoSTMjDlkFkEemIww9CfrUEr0OjFGzV336mBmbWhQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 196, + "comment" : "x-coordinate of the public key has many trailing 0's", + "msg" : "4d657373616765", + "sig" : "d434e262a49eab7781e353a3565e482550dd0fd5defa013c7f29745eff3569f19b0c0a93f267fb6052fd8077be769c2b98953195d7bc10de844218305c6ba17a", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 197, + "comment" : "x-coordinate of the public key has many trailing 0's", + "msg" : "4d657373616765", + "sig" : "0fe774355c04d060f76d79fd7a772e421463489221bf0a33add0be9b1979110b500dcba1c69a8fbd43fa4f57f743ce124ca8b91a1f325f3fac6181175df55737", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 198, + "comment" : "x-coordinate of the public key has many trailing 0's", + "msg" : "4d657373616765", + "sig" : "bb40bf217bed3fb3950c7d39f03d36dc8e3b2cd79693f125bfd06595ee1135e3541bf3532351ebb032710bdb6a1bf1bfc89a1e291ac692b3fa4780745bb55677", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "PPA9YU2JOc_UmaB4c_rCgWGPBrj_h-gBXD9JcmUASTU", + "y" : "hPoXTXkccr8s44gKiWDdKnx6EzioL4Wp5Zzb3oAAAAA" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "043cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f49726500493584fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000", + "wx" : "3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935", + "wy" : "0084fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200043cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f49726500493584fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPPA9YU2JOc/UmaB4c/rCgWGPBrj/\nh+gBXD9JcmUASTWE+hdNeRxyvyzjiAqJYN0qfHoTOKgvhanlnNvegAAAAA==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 199, + "comment" : "y-coordinate of the public key has many trailing 0's", + "msg" : "4d657373616765", + "sig" : "664eb7ee6db84a34df3c86ea31389a5405badd5ca99231ff556d3e75a233e73a59f3c752e52eca46137642490a51560ce0badc678754b8f72e51a2901426a1bd", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 200, + "comment" : "y-coordinate of the public key has many trailing 0's", + "msg" : "4d657373616765", + "sig" : "4cd0429bbabd2827009d6fcd843d4ce39c3e42e2d1631fd001985a79d1fd8b439638bf12dd682f60be7ef1d0e0d98f08b7bca77a1a2b869ae466189d2acdabe3", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 201, + "comment" : "y-coordinate of the public key has many trailing 0's", + "msg" : "4d657373616765", + "sig" : "e56c6ea2d1b017091c44d8b6cb62b9f460e3ce9aed5e5fd41e8added97c56c04a308ec31f281e955be20b457e463440b4fcf2b80258078207fc1378180f89b55", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "PPA9YU2JOc_UmaB4c_rCgWGPBrj_h-gBXD9JcmUASTU", + "y" : "ewXosYbjjUHTHHf1dp8i1YOF7MhX0HpWGmMkIX____8" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "043cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f4972650049357b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff", + "wx" : "3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935", + "wy" : "7b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200043cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f4972650049357b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPPA9YU2JOc/UmaB4c/rCgWGPBrj/\nh+gBXD9JcmUASTV7BeixhuONQdMcd/V2nyLVg4XsyFfQelYaYyQhf////w==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 202, + "comment" : "y-coordinate of the public key has many trailing 1's", + "msg" : "4d657373616765", + "sig" : "1158a08d291500b4cabed3346d891eee57c176356a2624fb011f8fbbf3466830228a8c486a736006e082325b85290c5bc91f378b75d487dda46798c18f285519", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 203, + "comment" : "y-coordinate of the public key has many trailing 1's", + "msg" : "4d657373616765", + "sig" : "b1db9289649f59410ea36b0c0fc8d6aa2687b29176939dd23e0dde56d309fa9d3e1535e4280559015b0dbd987366dcf43a6d1af5c23c7d584e1c3f48a1251336", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 204, + "comment" : "y-coordinate of the public key has many trailing 1's", + "msg" : "4d657373616765", + "sig" : "b7b16e762286cb96446aa8d4e6e7578b0a341a79f2dd1a220ac6f0ca4e24ed86ddc60a700a139b04661c547d07bbb0721780146df799ccf55e55234ecb8f12bc", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "KCnDH6ouQA40TtlLyj_NBUWVbrz-itD236X_jv____8", + "y" : "oBqvrwAOUlhYVa-nZ2reKEETCZBS31fn6zvTfr65Ii4" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "042829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffffa01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e", + "wx" : "2829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffff", + "wy" : "00a01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200042829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffffa01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKCnDH6ouQA40TtlLyj/NBUWVbrz+\nitD236X/jv////+gGq+vAA5SWFhVr6dnat4oQRMJkFLfV+frO9N+vrkiLg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 205, + "comment" : "x-coordinate of the public key has many trailing 1's", + "msg" : "4d657373616765", + "sig" : "d82a7c2717261187c8e00d8df963ff35d796edad36bc6e6bd1c91c670d9105b43dcabddaf8fcaa61f4603e7cbac0f3c0351ecd5988efb23f680d07debd139929", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 206, + "comment" : "x-coordinate of the public key has many trailing 1's", + "msg" : "4d657373616765", + "sig" : "5eb9c8845de68eb13d5befe719f462d77787802baff30ce96a5cba063254af782c026ae9be2e2a5e7ca0ff9bbd92fb6e44972186228ee9a62b87ddbe2ef66fb5", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 207, + "comment" : "x-coordinate of the public key has many trailing 1's", + "msg" : "4d657373616765", + "sig" : "96843dd03c22abd2f3b782b170239f90f277921becc117d0404a8e4e36230c28f2be378f526f74a543f67165976de9ed9a31214eb4d7e6db19e1ede123dd991d", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "____-UgIHmoEWN2PnnOPJmX_kFmtaqwHCDGMTKmnpPU", + "y" : "Woq8ui3ahHQxHuVBSblzyuDA-4lVetC_eOZSmhZjvXM" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f55a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73", + "wx" : "00fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f5", + "wy" : "5a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f55a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE////+UgIHmoEWN2PnnOPJmX/kFmt\naqwHCDGMTKmnpPVairy6LdqEdDEe5UFJuXPK4MD7iVV60L945lKaFmO9cw==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 208, + "comment" : "x-coordinate of the public key is large", + "msg" : "4d657373616765", + "sig" : "766456dce1857c906f9996af729339464d27e9d98edc2d0e3b760297067421f6402385ecadae0d8081dccaf5d19037ec4e55376eced699e93646bfbbf19d0b41", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 209, + "comment" : "x-coordinate of the public key is large", + "msg" : "4d657373616765", + "sig" : "c605c4b2edeab20419e6518a11b2dbc2b97ed8b07cced0b19c34f777de7b9fd9edf0f612c5f46e03c719647bc8af1b29b2cde2eda700fb1cff5e159d47326dba", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 210, + "comment" : "x-coordinate of the public key is large", + "msg" : "4d657373616765", + "sig" : "d48b68e6cabfe03cf6141c9ac54141f210e64485d9929ad7b732bfe3b7eb8a84feedae50c61bd00e19dc26f9b7e2265e4508c389109ad2f208f0772315b6c941", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "AAAAA_oV-WOUnV8DpvXH-G-eABXusjrrv_EXOTe6dI4", + "y" : "EJmHIHDo6HxVX6E2Wcyl1_rc_LACPqiJVIykivK6fnE" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "0400000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71", + "wx" : "03fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e", + "wy" : "1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000400000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAAAAA/oV+WOUnV8DpvXH+G+eABXu\nsjrrv/EXOTe6dI4QmYcgcOjofFVfoTZZzKXX+tz8sAI+qIlUjKSK8rp+cQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 211, + "comment" : "x-coordinate of the public key is small", + "msg" : "4d657373616765", + "sig" : "b7c81457d4aeb6aa65957098569f0479710ad7f6595d5874c35a93d12a5dd4c7b7961a0b652878c2d568069a432ca18a1a9199f2ca574dad4b9e3a05c0a1cdb3", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 212, + "comment" : "x-coordinate of the public key is small", + "msg" : "4d657373616765", + "sig" : "6b01332ddb6edfa9a30a1321d5858e1ee3cf97e263e669f8de5e9652e76ff3f75939545fced457309a6a04ace2bd0f70139c8f7d86b02cb1cc58f9e69e96cd5a", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 213, + "comment" : "x-coordinate of the public key is small", + "msg" : "4d657373616765", + "sig" : "efdb884720eaeadc349f9fc356b6c0344101cd2fd8436b7d0e6a4fb93f106361f24bee6ad5dc05f7613975473aadf3aacba9e77de7d69b6ce48cb60d8113385d", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "vLspFMefBF6qbsu8YSgWs75dLWeWcH2BJen4UcGK8BU", + "y" : "AAAAABNSu0oPoupMzrmrY91oSt5aESe88wCmmKcZO8I" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2", + "wx" : "00bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015", + "wy" : "1352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvLspFMefBF6qbsu8YSgWs75dLWeW\ncH2BJen4UcGK8BUAAAAAE1K7Sg+i6kzOuatj3WhK3loRJ7zzAKaYpxk7wg==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 214, + "comment" : "y-coordinate of the public key is small", + "msg" : "4d657373616765", + "sig" : "31230428405560dcb88fb5a646836aea9b23a23dd973dcbe8014c87b8b20eb070f9344d6e812ce166646747694a41b0aaf97374e19f3c5fb8bd7ae3d9bd0beff", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 215, + "comment" : "y-coordinate of the public key is small", + "msg" : "4d657373616765", + "sig" : "caa797da65b320ab0d5c470cda0b36b294359c7db9841d679174db34c4855743cf543a62f23e212745391aaf7505f345123d2685ee3b941d3de6d9b36242e5a0", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 216, + "comment" : "y-coordinate of the public key is small", + "msg" : "4d657373616765", + "sig" : "7e5f0ab5d900d3d3d7867657e5d6d36519bc54084536e7d21c336ed8001859459450c07f201faec94b82dfb322e5ac676688294aad35aa72e727ff0b19b646aa", + "result" : "valid", + "flags" : [] + } + ] + }, + { + "jwk" : { + "crv" : "P-256", + "kid" : "none", + "kty" : "EC", + "x" : "vLspFMefBF6qbsu8YSgWs75dLWeWcH2BJen4UcGK8BU", + "y" : "_____uytRLbwXRWzMUZUnCKXtSKl7thDDP9ZZ1jmxD0" + }, + "key" : { + "curve" : "secp256r1", + "keySize" : 256, + "type" : "EcPublicKey", + "uncompressed" : "04bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d", + "wx" : "00bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015", + "wy" : "00fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d" + }, + "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d", + "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvLspFMefBF6qbsu8YSgWs75dLWeW\ncH2BJen4UcGK8BX////+7K1EtvBdFbMxRlScIpe1IqXu2EMM/1lnWObEPQ==\n-----END PUBLIC KEY-----", + "sha" : "SHA-256", + "type" : "EcdsaP1363Verify", + "tests" : [ + { + "tcId" : 217, + "comment" : "y-coordinate of the public key is large", + "msg" : "4d657373616765", + "sig" : "d7d70c581ae9e3f66dc6a480bf037ae23f8a1e4a2136fe4b03aa69f0ca25b35689c460f8a5a5c2bbba962c8a3ee833a413e85658e62a59e2af41d9127cc47224", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 218, + "comment" : "y-coordinate of the public key is large", + "msg" : "4d657373616765", + "sig" : "341c1b9ff3c83dd5e0dfa0bf68bcdf4bb7aa20c625975e5eeee34bb396266b3472b69f061b750fd5121b22b11366fad549c634e77765a017902a67099e0a4469", + "result" : "valid", + "flags" : [] + }, + { + "tcId" : 219, + "comment" : "y-coordinate of the public key is large", + "msg" : "4d657373616765", + "sig" : "70bebe684cdcb5ca72a42f0d873879359bd1781a591809947628d313a3814f67aec03aca8f5587a4d535fa31027bbe9cc0e464b1c3577f4c2dcde6b2094798a9", + "result" : "valid", + "flags" : [] + } + ] + } + ] +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js new file mode 100644 index 0000000..8117c69 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js @@ -0,0 +1,18 @@ +const { ethers } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { shouldSupportInterfaces } = require('./SupportsInterface.behavior'); + +async function fixture() { + return { + mock: await ethers.deployContract('$ERC165'), + }; +} + +describe('ERC165', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + shouldSupportInterfaces(); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js new file mode 100644 index 0000000..1bbe8a5 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js @@ -0,0 +1,245 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +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'; + +async function fixture() { + return { mock: await ethers.deployContract('$ERC165Checker') }; +} + +describe('ERC165Checker', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('ERC165 missing return data', function () { + before(async function () { + this.target = await ethers.deployContract('ERC165MissingData'); + }); + + it('does not support ERC165', async function () { + expect(await this.mock.$supportsERC165(this.target)).to.be.false; + }); + + it('does not support mock interface via supportsInterface', async function () { + expect(await this.mock.$supportsInterface(this.target, DUMMY_ID)).to.be.false; + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + expect(await this.mock.$supportsAllInterfaces(this.target, [DUMMY_ID])).to.be.false; + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + expect(await this.mock.$getSupportedInterfaces(this.target, [DUMMY_ID])).to.deep.equal([false]); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + expect(await this.mock.$supportsERC165InterfaceUnchecked(this.target, DUMMY_ID)).to.be.false; + }); + }); + + describe('ERC165 malicious return data', function () { + beforeEach(async function () { + this.target = await ethers.deployContract('ERC165MaliciousData'); + }); + + it('does not support ERC165', async function () { + expect(await this.mock.$supportsERC165(this.target)).to.be.false; + }); + + it('does not support mock interface via supportsInterface', async function () { + expect(await this.mock.$supportsInterface(this.target, DUMMY_ID)).to.be.false; + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + expect(await this.mock.$supportsAllInterfaces(this.target, [DUMMY_ID])).to.be.false; + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + expect(await this.mock.$getSupportedInterfaces(this.target, [DUMMY_ID])).to.deep.equal([false]); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + expect(await this.mock.$supportsERC165InterfaceUnchecked(this.target, DUMMY_ID)).to.be.true; + }); + }); + + describe('ERC165 not supported', function () { + beforeEach(async function () { + this.target = await ethers.deployContract('ERC165NotSupported'); + }); + + it('does not support ERC165', async function () { + expect(await this.mock.$supportsERC165(this.target)).to.be.false; + }); + + it('does not support mock interface via supportsInterface', async function () { + expect(await this.mock.$supportsInterface(this.target, DUMMY_ID)).to.be.false; + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + expect(await this.mock.$supportsAllInterfaces(this.target, [DUMMY_ID])).to.be.false; + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + expect(await this.mock.$getSupportedInterfaces(this.target, [DUMMY_ID])).to.deep.equal([false]); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + expect(await this.mock.$supportsERC165InterfaceUnchecked(this.target, DUMMY_ID)).to.be.false; + }); + }); + + describe('ERC165 supported', function () { + beforeEach(async function () { + this.target = await ethers.deployContract('ERC165InterfacesSupported', [[]]); + }); + + it('supports ERC165', async function () { + expect(await this.mock.$supportsERC165(this.target)).to.be.true; + }); + + it('does not support mock interface via supportsInterface', async function () { + expect(await this.mock.$supportsInterface(this.target, DUMMY_ID)).to.be.false; + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + expect(await this.mock.$supportsAllInterfaces(this.target, [DUMMY_ID])).to.be.false; + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + expect(await this.mock.$getSupportedInterfaces(this.target, [DUMMY_ID])).to.deep.equal([false]); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + expect(await this.mock.$supportsERC165InterfaceUnchecked(this.target, DUMMY_ID)).to.be.false; + }); + }); + + describe('ERC165 and single interface supported', function () { + beforeEach(async function () { + this.target = await ethers.deployContract('ERC165InterfacesSupported', [[DUMMY_ID]]); + }); + + it('supports ERC165', async function () { + expect(await this.mock.$supportsERC165(this.target)).to.be.true; + }); + + it('supports mock interface via supportsInterface', async function () { + expect(await this.mock.$supportsInterface(this.target, DUMMY_ID)).to.be.true; + }); + + it('supports mock interface via supportsAllInterfaces', async function () { + expect(await this.mock.$supportsAllInterfaces(this.target, [DUMMY_ID])).to.be.true; + }); + + it('supports mock interface via getSupportedInterfaces', async function () { + expect(await this.mock.$getSupportedInterfaces(this.target, [DUMMY_ID])).to.deep.equal([true]); + }); + + it('supports mock interface via supportsERC165InterfaceUnchecked', async function () { + expect(await this.mock.$supportsERC165InterfaceUnchecked(this.target, DUMMY_ID)).to.be.true; + }); + }); + + describe('ERC165 and many interfaces supported', function () { + const supportedInterfaces = [DUMMY_ID, DUMMY_ID_2, DUMMY_ID_3]; + beforeEach(async function () { + this.target = await ethers.deployContract('ERC165InterfacesSupported', [supportedInterfaces]); + }); + + it('supports ERC165', async function () { + expect(await this.mock.$supportsERC165(this.target)).to.be.true; + }); + + it('supports each interfaceId via supportsInterface', async function () { + for (const interfaceId of supportedInterfaces) { + expect(await this.mock.$supportsInterface(this.target, interfaceId)).to.be.true; + } + }); + + it('supports all interfaceIds via supportsAllInterfaces', async function () { + expect(await this.mock.$supportsAllInterfaces(this.target, supportedInterfaces)).to.be.true; + }); + + it('supports none of the interfaces queried via supportsAllInterfaces', async function () { + const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2]; + + expect(await this.mock.$supportsAllInterfaces(this.target, interfaceIdsToTest)).to.be.false; + }); + + it('supports not all of the interfaces queried via supportsAllInterfaces', async function () { + const interfaceIdsToTest = [...supportedInterfaces, DUMMY_UNSUPPORTED_ID]; + expect(await this.mock.$supportsAllInterfaces(this.target, interfaceIdsToTest)).to.be.false; + }); + + it('supports all interfaceIds via getSupportedInterfaces', async function () { + expect(await this.mock.$getSupportedInterfaces(this.target, supportedInterfaces)).to.deep.equal( + supportedInterfaces.map(i => supportedInterfaces.includes(i)), + ); + }); + + it('supports none of the interfaces queried via getSupportedInterfaces', async function () { + const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2]; + + expect(await this.mock.$getSupportedInterfaces(this.target, interfaceIdsToTest)).to.deep.equal( + interfaceIdsToTest.map(i => supportedInterfaces.includes(i)), + ); + }); + + it('supports not all of the interfaces queried via getSupportedInterfaces', async function () { + const interfaceIdsToTest = [...supportedInterfaces, DUMMY_UNSUPPORTED_ID]; + + expect(await this.mock.$getSupportedInterfaces(this.target, interfaceIdsToTest)).to.deep.equal( + interfaceIdsToTest.map(i => supportedInterfaces.includes(i)), + ); + }); + + it('supports each interfaceId via supportsERC165InterfaceUnchecked', async function () { + for (const interfaceId of supportedInterfaces) { + expect(await this.mock.$supportsERC165InterfaceUnchecked(this.target, interfaceId)).to.be.true; + } + }); + }); + + describe('account address does not support ERC165', function () { + it('does not support ERC165', async function () { + expect(await this.mock.$supportsERC165(DUMMY_ACCOUNT)).to.be.false; + }); + + it('does not support mock interface via supportsInterface', async function () { + expect(await this.mock.$supportsInterface(DUMMY_ACCOUNT, DUMMY_ID)).to.be.false; + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + expect(await this.mock.$supportsAllInterfaces(DUMMY_ACCOUNT, [DUMMY_ID])).to.be.false; + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + expect(await this.mock.$getSupportedInterfaces(DUMMY_ACCOUNT, [DUMMY_ID])).to.deep.equal([false]); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + expect(await this.mock.$supportsERC165InterfaceUnchecked(DUMMY_ACCOUNT, DUMMY_ID)).to.be.false; + }); + }); + + it('Return bomb resistance', async function () { + this.target = await ethers.deployContract('ERC165ReturnBombMock'); + + const { gasUsed: gasUsed1 } = await this.mock.$supportsInterface.send(this.target, DUMMY_ID).then(tx => tx.wait()); + expect(gasUsed1).to.be.lessThan(120_000n); // 3*30k + 21k + some margin + + const { gasUsed: gasUsed2 } = await this.mock.$getSupportedInterfaces + .send(this.target, [DUMMY_ID, DUMMY_ID_2, DUMMY_ID_3, DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2]) + .then(tx => tx.wait()); + + expect(gasUsed2).to.be.lessThan(250_000n); // (2+5)*30k + 21k + some margin + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js new file mode 100644 index 0000000..6e716d1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js @@ -0,0 +1,166 @@ +const { expect } = require('chai'); +const { interfaceId } = require('../../helpers/methods'); +const { mapValues } = require('../../helpers/iterate'); + +const INVALID_ID = '0xffffffff'; +const GOVERNOR_INTERFACE = [ + '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)', +]; +const SIGNATURES = { + 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)', + ], + ERC1155MetadataURI: ['uri(uint256)'], + ERC1155Receiver: [ + 'onERC1155Received(address,address,uint256,uint256,bytes)', + 'onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)', + ], + ERC1363: [ + 'transferAndCall(address,uint256)', + 'transferAndCall(address,uint256,bytes)', + 'transferFromAndCall(address,address,uint256)', + 'transferFromAndCall(address,address,uint256,bytes)', + 'approveAndCall(address,uint256)', + 'approveAndCall(address,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: GOVERNOR_INTERFACE, + Governor_5_3: GOVERNOR_INTERFACE.concat('getProposalId(address[],uint256[],bytes[],bytes32)'), + ERC2981: ['royaltyInfo(uint256,uint256)'], + ERC6909: [ + 'balanceOf(address,uint256)', + 'allowance(address,address,uint256)', + 'isOperator(address,address)', + 'transfer(address,uint256,uint256)', + 'transferFrom(address,address,uint256,uint256)', + 'approve(address,uint256,uint256)', + 'setOperator(address,bool)', + ], +}; + +const INTERFACE_IDS = mapValues(SIGNATURES, interfaceId); + +function shouldSupportInterfaces(interfaces = [], signatures = SIGNATURES) { + // case where only signatures are provided + if (!Array.isArray(interfaces)) { + signatures = interfaces; + interfaces = Object.keys(interfaces); + } + + interfaces.unshift('ERC165'); + signatures.ERC165 = SIGNATURES.ERC165; + const interfaceIds = mapValues(signatures, interfaceId, ([name]) => interfaces.includes(name)); + + describe('ERC165', function () { + beforeEach(function () { + this.contractUnderTest = this.mock || this.token; + }); + + describe('when the interfaceId is supported', function () { + it('uses less than 30k gas', async function () { + for (const k of interfaces) { + const interfaceId = interfaceIds[k] ?? k; + expect(await this.contractUnderTest.supportsInterface.estimateGas(interfaceId)).to.lte(30_000n); + } + }); + + it('returns true', async function () { + for (const k of interfaces) { + const interfaceId = interfaceIds[k] ?? k; + expect(await this.contractUnderTest.supportsInterface(interfaceId), `does not support ${k}`).to.be.true; + } + }); + }); + + describe('when the interfaceId is not supported', function () { + it('uses less than 30k', async function () { + expect(await this.contractUnderTest.supportsInterface.estimateGas(INVALID_ID)).to.lte(30_000n); + }); + + it('returns false', async function () { + expect(await this.contractUnderTest.supportsInterface(INVALID_ID), `supports ${INVALID_ID}`).to.be.false; + }); + }); + + 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 (signatures[k] === undefined) continue; + + // Check the presence of each function in the contract's interface + for (const fnSig of signatures[k]) { + expect(this.contractUnderTest.interface.hasFunction(fnSig), `did not find ${fnSig}`).to.be.true; + } + } + }); + }); +} + +module.exports = { + SIGNATURES, + INTERFACE_IDS, + shouldSupportInterfaces, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.t.sol new file mode 100644 index 0000000..3c83feb --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.t.sol @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test, stdError} from "forge-std/Test.sol"; + +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; + +contract MathTest is Test { + function testSymbolicTernary(bool f, uint256 a, uint256 b) public pure { + assertEq(Math.ternary(f, a, b), f ? a : b); + } + + // ADD512 & MUL512 + function testAdd512(uint256 a, uint256 b) public pure { + (uint256 high, uint256 low) = Math.add512(a, b); + + // test against tryAdd + (bool success, uint256 result) = Math.tryAdd(a, b); + if (success) { + assertEq(high, 0); + assertEq(low, result); + } else { + assertEq(high, 1); + } + + // test against unchecked + unchecked { + assertEq(low, a + b); // unchecked allow overflow + } + } + + function testMul512(uint256 a, uint256 b) public pure { + (uint256 high, uint256 low) = Math.mul512(a, b); + + // test against tryMul + (bool success, uint256 result) = Math.tryMul(a, b); + if (success) { + assertEq(high, 0); + assertEq(low, result); + } else { + assertGt(high, 0); + } + + // test against unchecked + unchecked { + assertEq(low, a * b); // unchecked allow overflow + } + + // test against alternative method + (uint256 _high, uint256 _low) = _mulKaratsuba(a, b); + assertEq(high, _high); + assertEq(low, _low); + } + + // MIN & MAX + function testSymbolicMinMax(uint256 a, uint256 b) public pure { + assertEq(Math.min(a, b), a < b ? a : b); + assertEq(Math.max(a, b), a > b ? a : b); + } + + // CEILDIV + function testCeilDiv(uint256 a, uint256 b) public pure { + vm.assume(b > 0); + + uint256 result = Math.ceilDiv(a, b); + + if (result == 0) { + assertEq(a, 0); + } else { + uint256 expect = a / b; + if (expect * b < a) { + expect += 1; + } + assertEq(result, expect); + } + } + + // SQRT + function testSqrt(uint256 input, uint8 r) public pure { + 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; + } + + // INV + function testInvMod(uint256 value, uint256 p) public pure { + _testInvMod(value, p, true); + } + + function testInvMod2(uint256 seed) public pure { + uint256 p = 2; // prime + _testInvMod(bound(seed, 1, p - 1), p, false); + } + + function testInvMod17(uint256 seed) public pure { + uint256 p = 17; // prime + _testInvMod(bound(seed, 1, p - 1), p, false); + } + + function testInvMod65537(uint256 seed) public pure { + uint256 p = 65537; // prime + _testInvMod(bound(seed, 1, p - 1), p, false); + } + + function testInvModP256(uint256 seed) public pure { + uint256 p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff; // prime + _testInvMod(bound(seed, 1, p - 1), p, false); + } + + function _testInvMod(uint256 value, uint256 p, bool allowZero) private pure { + uint256 inverse = Math.invMod(value, p); + if (inverse != 0) { + assertEq(mulmod(value, inverse, p), 1); + assertLt(inverse, p); + } else { + assertTrue(allowZero); + } + } + + // LOG2 + function testLog2(uint256 input, uint8 r) public pure { + 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 pure { + 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 pure { + 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 pure { + // Full precision for x * y + (uint256 xyHi, uint256 xyLo) = Math.mul512(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) = Math.mul512(q, d); + // Add remainder of x * y / d (computed as rem = (x * y % d)) + (uint256 c, uint256 qdRemLo) = Math.add512(qdLo, mulmod(x, y, d)); + uint256 qdRemHi = qdHi + c; + + // Full precision check that x * y = q * d + rem + assertEq(xyHi, qdRemHi); + assertEq(xyLo, qdRemLo); + } + + /// forge-config: default.allow_internal_expect_revert = true + function testMulDivDomain(uint256 x, uint256 y, uint256 d) public { + (uint256 xyHi, ) = Math.mul512(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 + vm.expectRevert(d == 0 ? stdError.divisionError : stdError.arithmeticError); + Math.mulDiv(x, y, d); + } + + // MOD EXP + /// forge-config: default.allow_internal_expect_revert = true + function testModExp(uint256 b, uint256 e, uint256 m) public { + if (m == 0) { + vm.expectRevert(stdError.divisionError); + } + uint256 result = Math.modExp(b, e, m); + assertLt(result, m); + assertEq(result, _nativeModExp(b, e, m)); + } + + function testTryModExp(uint256 b, uint256 e, uint256 m) public view { + (bool success, uint256 result) = Math.tryModExp(b, e, m); + assertEq(success, m != 0); + if (success) { + assertLt(result, m); + assertEq(result, _nativeModExp(b, e, m)); + } else { + assertEq(result, 0); + } + } + + /// forge-config: default.allow_internal_expect_revert = true + function testModExpMemory(uint256 b, uint256 e, uint256 m) public { + if (m == 0) { + vm.expectRevert(stdError.divisionError); + } + bytes memory result = Math.modExp(abi.encodePacked(b), abi.encodePacked(e), abi.encodePacked(m)); + assertEq(result.length, 0x20); + uint256 res = abi.decode(result, (uint256)); + assertLt(res, m); + assertEq(res, _nativeModExp(b, e, m)); + } + + function testTryModExpMemory(uint256 b, uint256 e, uint256 m) public view { + (bool success, bytes memory result) = Math.tryModExp( + abi.encodePacked(b), + abi.encodePacked(e), + abi.encodePacked(m) + ); + if (success) { + assertEq(result.length, 0x20); // m is a uint256, so abi.encodePacked(m).length is 0x20 + uint256 res = abi.decode(result, (uint256)); + assertLt(res, m); + assertEq(res, _nativeModExp(b, e, m)); + } else { + assertEq(result.length, 0); + } + } + + // Helpers + function _asRounding(uint8 r) private pure returns (Math.Rounding) { + vm.assume(r < uint8(type(Math.Rounding).max)); + return Math.Rounding(r); + } + + function _mulKaratsuba(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 _nativeModExp(uint256 b, uint256 e, uint256 m) private pure returns (uint256) { + if (m == 1) return 0; + uint256 r = 1; + while (e > 0) { + if (e % 2 > 0) { + r = mulmod(r, b, m); + } + b = mulmod(b, b, m); + e >>= 1; + } + return r; + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.test.js new file mode 100644 index 0000000..6a09938 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.test.js @@ -0,0 +1,713 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +const { Rounding } = require('../../helpers/enums'); +const { min, max, modExp } = require('../../helpers/math'); +const { generators } = require('../../helpers/random'); +const { product, range } = require('../../helpers/iterate'); + +const RoundingDown = [Rounding.Floor, Rounding.Trunc]; +const RoundingUp = [Rounding.Ceil, Rounding.Expand]; + +const bytes = (value, width = undefined) => ethers.Typed.bytes(ethers.toBeHex(value, width)); +const uint256 = value => ethers.Typed.uint256(value); +bytes.zero = '0x'; +uint256.zero = 0n; + +const testCommutative = (fn, lhs, rhs, expected, ...extra) => + Promise.all([ + expect(fn(lhs, rhs, ...extra)).to.eventually.deep.equal(expected), + expect(fn(rhs, lhs, ...extra)).to.eventually.deep.equal(expected), + ]); + +const splitHighLow = n => [n / (1n << 256n), n % (1n << 256n)]; + +async function fixture() { + const mock = await ethers.deployContract('$Math'); + + // disambiguation, we use the version with explicit rounding + mock.$mulDiv = mock['$mulDiv(uint256,uint256,uint256,uint8)']; + mock.$sqrt = mock['$sqrt(uint256,uint8)']; + mock.$log2 = mock['$log2(uint256,uint8)']; + mock.$log10 = mock['$log10(uint256,uint8)']; + mock.$log256 = mock['$log256(uint256,uint8)']; + + return { mock }; +} + +describe('Math', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('add512', function () { + it('adds correctly without reverting', async function () { + const values = [0n, 1n, 17n, 42n, ethers.MaxUint256 - 1n, ethers.MaxUint256]; + for (const [a, b] of product(values, values)) { + await expect(this.mock.$add512(a, b)).to.eventually.deep.equal(splitHighLow(a + b)); + } + }); + }); + + describe('mul512', function () { + it('multiplies correctly without reverting', async function () { + const values = [0n, 1n, 17n, 42n, ethers.MaxUint256 - 1n, ethers.MaxUint256]; + for (const [a, b] of product(values, values)) { + await expect(this.mock.$mul512(a, b)).to.eventually.deep.equal(splitHighLow(a * b)); + } + }); + }); + + describe('tryAdd', function () { + it('adds correctly', async function () { + const a = 5678n; + const b = 1234n; + await testCommutative(this.mock.$tryAdd, a, b, [true, a + b]); + }); + + it('reverts on addition overflow', async function () { + const a = ethers.MaxUint256; + const b = 1n; + await testCommutative(this.mock.$tryAdd, a, b, [false, 0n]); + }); + }); + + describe('trySub', function () { + it('subtracts correctly', async function () { + const a = 5678n; + const b = 1234n; + await expect(this.mock.$trySub(a, b)).to.eventually.deep.equal([true, a - b]); + }); + + it('reverts if subtraction result would be negative', async function () { + const a = 1234n; + const b = 5678n; + await expect(this.mock.$trySub(a, b)).to.eventually.deep.equal([false, 0n]); + }); + }); + + describe('tryMul', function () { + it('multiplies correctly', async function () { + const a = 1234n; + const b = 5678n; + await testCommutative(this.mock.$tryMul, a, b, [true, a * b]); + }); + + it('multiplies by zero correctly', async function () { + const a = 0n; + const b = 5678n; + await testCommutative(this.mock.$tryMul, a, b, [true, a * b]); + }); + + it('reverts on multiplication overflow', async function () { + const a = ethers.MaxUint256; + const b = 2n; + await testCommutative(this.mock.$tryMul, a, b, [false, 0n]); + }); + }); + + describe('tryDiv', function () { + it('divides correctly', async function () { + const a = 5678n; + const b = 5678n; + await expect(this.mock.$tryDiv(a, b)).to.eventually.deep.equal([true, a / b]); + }); + + it('divides zero correctly', async function () { + const a = 0n; + const b = 5678n; + await expect(this.mock.$tryDiv(a, b)).to.eventually.deep.equal([true, a / b]); + }); + + it('returns complete number result on non-even division', async function () { + const a = 7000n; + const b = 5678n; + await expect(this.mock.$tryDiv(a, b)).to.eventually.deep.equal([true, a / b]); + }); + + it('reverts on division by zero', async function () { + const a = 5678n; + const b = 0n; + await expect(this.mock.$tryDiv(a, b)).to.eventually.deep.equal([false, 0n]); + }); + }); + + describe('tryMod', function () { + describe('modulos correctly', function () { + it('when the dividend is smaller than the divisor', async function () { + const a = 284n; + const b = 5678n; + await expect(this.mock.$tryMod(a, b)).to.eventually.deep.equal([true, a % b]); + }); + + it('when the dividend is equal to the divisor', async function () { + const a = 5678n; + const b = 5678n; + await expect(this.mock.$tryMod(a, b)).to.eventually.deep.equal([true, a % b]); + }); + + it('when the dividend is larger than the divisor', async function () { + const a = 7000n; + const b = 5678n; + await expect(this.mock.$tryMod(a, b)).to.eventually.deep.equal([true, a % b]); + }); + + it('when the dividend is a multiple of the divisor', async function () { + const a = 17034n; // 17034 == 5678 * 3 + const b = 5678n; + await expect(this.mock.$tryMod(a, b)).to.eventually.deep.equal([true, a % b]); + }); + }); + + it('reverts with a 0 divisor', async function () { + const a = 5678n; + const b = 0n; + await expect(this.mock.$tryMod(a, b)).to.eventually.deep.equal([false, 0n]); + }); + }); + + describe('saturatingAdd', function () { + it('adds correctly', async function () { + const a = 5678n; + const b = 1234n; + await testCommutative(this.mock.$saturatingAdd, a, b, a + b); + await testCommutative(this.mock.$saturatingAdd, a, 0n, a); + await testCommutative(this.mock.$saturatingAdd, ethers.MaxUint256, 0n, ethers.MaxUint256); + }); + + it('bounds on addition overflow', async function () { + await testCommutative(this.mock.$saturatingAdd, ethers.MaxUint256, 1n, ethers.MaxUint256); + await expect(this.mock.$saturatingAdd(ethers.MaxUint256, ethers.MaxUint256)).to.eventually.equal( + ethers.MaxUint256, + ); + }); + }); + + describe('saturatingSub', function () { + it('subtracts correctly', async function () { + const a = 5678n; + const b = 1234n; + await expect(this.mock.$saturatingSub(a, b)).to.eventually.equal(a - b); + await expect(this.mock.$saturatingSub(a, a)).to.eventually.equal(0n); + await expect(this.mock.$saturatingSub(a, 0n)).to.eventually.equal(a); + await expect(this.mock.$saturatingSub(0n, a)).to.eventually.equal(0n); + await expect(this.mock.$saturatingSub(ethers.MaxUint256, 1n)).to.eventually.equal(ethers.MaxUint256 - 1n); + }); + + it('bounds on subtraction overflow', async function () { + await expect(this.mock.$saturatingSub(0n, 1n)).to.eventually.equal(0n); + await expect(this.mock.$saturatingSub(1n, 2n)).to.eventually.equal(0n); + await expect(this.mock.$saturatingSub(1n, ethers.MaxUint256)).to.eventually.equal(0n); + await expect(this.mock.$saturatingSub(ethers.MaxUint256 - 1n, ethers.MaxUint256)).to.eventually.equal(0n); + }); + }); + + describe('saturatingMul', function () { + it('multiplies correctly', async function () { + const a = 1234n; + const b = 5678n; + await testCommutative(this.mock.$saturatingMul, a, b, a * b); + }); + + it('multiplies by zero correctly', async function () { + const a = 0n; + const b = 5678n; + await testCommutative(this.mock.$saturatingMul, a, b, 0n); + }); + + it('bounds on multiplication overflow', async function () { + const a = ethers.MaxUint256; + const b = 2n; + await testCommutative(this.mock.$saturatingMul, a, b, ethers.MaxUint256); + }); + }); + + describe('max', function () { + it('is correctly detected in both position', async function () { + await testCommutative(this.mock.$max, 1234n, 5678n, max(1234n, 5678n)); + }); + }); + + describe('min', function () { + it('is correctly detected in both position', async function () { + await testCommutative(this.mock.$min, 1234n, 5678n, min(1234n, 5678n)); + }); + }); + + describe('average', function () { + it('is correctly calculated with two odd numbers', async function () { + const a = 57417n; + const b = 95431n; + await expect(this.mock.$average(a, b)).to.eventually.equal((a + b) / 2n); + }); + + it('is correctly calculated with two even numbers', async function () { + const a = 42304n; + const b = 84346n; + await expect(this.mock.$average(a, b)).to.eventually.equal((a + b) / 2n); + }); + + it('is correctly calculated with one even and one odd number', async function () { + const a = 57417n; + const b = 84346n; + await expect(this.mock.$average(a, b)).to.eventually.equal((a + b) / 2n); + }); + + it('is correctly calculated with two max uint256 numbers', async function () { + const a = ethers.MaxUint256; + await expect(this.mock.$average(a, a)).to.eventually.equal(a); + }); + }); + + describe('ceilDiv', function () { + it('reverts on zero division', async function () { + const a = 2n; + const b = 0n; + // It's unspecified because it's a low level 0 division error + await expect(this.mock.$ceilDiv(a, b)).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO); + }); + + it('does not round up a zero result', async function () { + const a = 0n; + const b = 2n; + const r = 0n; + await expect(this.mock.$ceilDiv(a, b)).to.eventually.equal(r); + }); + + it('does not round up on exact division', async function () { + const a = 10n; + const b = 5n; + const r = 2n; + await expect(this.mock.$ceilDiv(a, b)).to.eventually.equal(r); + }); + + it('rounds up on division with remainders', async function () { + const a = 42n; + const b = 13n; + const r = 4n; + await expect(this.mock.$ceilDiv(a, b)).to.eventually.equal(r); + }); + + it('does not overflow', async function () { + const a = ethers.MaxUint256; + const b = 2n; + const r = 1n << 255n; + await expect(this.mock.$ceilDiv(a, b)).to.eventually.equal(r); + }); + + it('correctly computes max uint256 divided by 1', async function () { + const a = ethers.MaxUint256; + const b = 1n; + const r = ethers.MaxUint256; + await expect(this.mock.$ceilDiv(a, b)).to.eventually.equal(r); + }); + }); + + describe('mulDiv', function () { + it('divide by 0', async function () { + const a = 1n; + const b = 1n; + const c = 0n; + await expect(this.mock.$mulDiv(a, b, c, Rounding.Floor)).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO); + }); + + it('reverts with result higher than 2 ^ 256', async function () { + const a = 5n; + const b = ethers.MaxUint256; + const c = 2n; + await expect(this.mock.$mulDiv(a, b, c, Rounding.Floor)).to.be.revertedWithPanic( + PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW, + ); + }); + + describe('does round down', function () { + it('small values', async function () { + for (const rounding of RoundingDown) { + await expect(this.mock.$mulDiv(3n, 4n, 5n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$mulDiv(3n, 5n, 5n, rounding)).to.eventually.equal(3n); + } + }); + + it('large values', async function () { + for (const rounding of RoundingDown) { + await expect(this.mock.$mulDiv(42n, ethers.MaxUint256 - 1n, ethers.MaxUint256, rounding)).to.eventually.equal( + 41n, + ); + + await expect(this.mock.$mulDiv(17n, ethers.MaxUint256, ethers.MaxUint256, rounding)).to.eventually.equal(17n); + + await expect( + this.mock.$mulDiv(ethers.MaxUint256 - 1n, ethers.MaxUint256 - 1n, ethers.MaxUint256, rounding), + ).to.eventually.equal(ethers.MaxUint256 - 2n); + + await expect( + this.mock.$mulDiv(ethers.MaxUint256, ethers.MaxUint256 - 1n, ethers.MaxUint256, rounding), + ).to.eventually.equal(ethers.MaxUint256 - 1n); + + await expect( + this.mock.$mulDiv(ethers.MaxUint256, ethers.MaxUint256, ethers.MaxUint256, rounding), + ).to.eventually.equal(ethers.MaxUint256); + } + }); + }); + + describe('does round up', function () { + it('small values', async function () { + for (const rounding of RoundingUp) { + await expect(this.mock.$mulDiv(3n, 4n, 5n, rounding)).to.eventually.equal(3n); + await expect(this.mock.$mulDiv(3n, 5n, 5n, rounding)).to.eventually.equal(3n); + } + }); + + it('large values', async function () { + for (const rounding of RoundingUp) { + await expect(this.mock.$mulDiv(42n, ethers.MaxUint256 - 1n, ethers.MaxUint256, rounding)).to.eventually.equal( + 42n, + ); + + await expect(this.mock.$mulDiv(17n, ethers.MaxUint256, ethers.MaxUint256, rounding)).to.eventually.equal(17n); + + await expect( + this.mock.$mulDiv(ethers.MaxUint256 - 1n, ethers.MaxUint256 - 1n, ethers.MaxUint256, rounding), + ).to.eventually.equal(ethers.MaxUint256 - 1n); + + await expect( + this.mock.$mulDiv(ethers.MaxUint256, ethers.MaxUint256 - 1n, ethers.MaxUint256, rounding), + ).to.eventually.equal(ethers.MaxUint256 - 1n); + + await expect( + this.mock.$mulDiv(ethers.MaxUint256, ethers.MaxUint256, ethers.MaxUint256, rounding), + ).to.eventually.equal(ethers.MaxUint256); + } + }); + }); + }); + + describe('mulShr', function () { + it('reverts with result higher than 2 ^ 256', async function () { + const a = 5n; + const b = ethers.MaxUint256; + const c = 1n; + await expect(this.mock.$mulShr(a, b, c, Rounding.Floor)).to.be.revertedWithPanic( + PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW, + ); + }); + + describe('does round down', function () { + it('small values', async function () { + for (const rounding of RoundingDown) { + await expect(this.mock.$mulShr(3n, 5n, 1n, rounding)).to.eventually.equal(7n); + await expect(this.mock.$mulShr(3n, 5n, 2n, rounding)).to.eventually.equal(3n); + } + }); + + it('large values', async function () { + for (const rounding of RoundingDown) { + await expect(this.mock.$mulShr(42n, ethers.MaxUint256, 255n, rounding)).to.eventually.equal(83n); + + await expect(this.mock.$mulShr(17n, ethers.MaxUint256, 255n, rounding)).to.eventually.equal(33n); + + await expect(this.mock.$mulShr(ethers.MaxUint256, ethers.MaxInt256 + 1n, 255n, rounding)).to.eventually.equal( + ethers.MaxUint256, + ); + + await expect(this.mock.$mulShr(ethers.MaxUint256, ethers.MaxInt256, 255n, rounding)).to.eventually.equal( + ethers.MaxUint256 - 2n, + ); + } + }); + }); + + describe('does round up', function () { + it('small values', async function () { + for (const rounding of RoundingUp) { + await expect(this.mock.$mulShr(3n, 5n, 1n, rounding)).to.eventually.equal(8n); + await expect(this.mock.$mulShr(3n, 5n, 2n, rounding)).to.eventually.equal(4n); + } + }); + + it('large values', async function () { + for (const rounding of RoundingUp) { + await expect(this.mock.$mulShr(42n, ethers.MaxUint256, 255n, rounding)).to.eventually.equal(84n); + + await expect(this.mock.$mulShr(17n, ethers.MaxUint256, 255n, rounding)).to.eventually.equal(34n); + + await expect(this.mock.$mulShr(ethers.MaxUint256, ethers.MaxInt256 + 1n, 255n, rounding)).to.eventually.equal( + ethers.MaxUint256, + ); + + await expect(this.mock.$mulShr(ethers.MaxUint256, ethers.MaxInt256, 255n, rounding)).to.eventually.equal( + ethers.MaxUint256 - 1n, + ); + } + }); + }); + }); + + describe('invMod', function () { + for (const factors of [ + [0n], + [1n], + [2n], + [17n], + [65537n], + [0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffn], + [3n, 5n], + [3n, 7n], + [47n, 53n], + ]) { + const p = factors.reduce((acc, f) => acc * f, 1n); + + describe(`using p=${p} which is ${p > 1 && factors.length > 1 ? 'not ' : ''}a prime`, function () { + it('trying to inverse 0 returns 0', async function () { + await expect(this.mock.$invMod(0, p)).to.eventually.equal(0n); + await expect(this.mock.$invMod(p, p)).to.eventually.equal(0n); // p is 0 mod p + }); + + if (p != 0) { + for (const value of Array.from({ length: 16 }, generators.uint256)) { + const isInversible = factors.every(f => value % f); + it(`trying to inverse ${value}`, async function () { + const result = await this.mock.$invMod(value, p); + if (isInversible) { + expect((value * result) % p).to.equal(1n); + } else { + expect(result).to.equal(0n); + } + }); + } + } + }); + } + }); + + describe('modExp', function () { + for (const [name, type] of Object.entries({ uint256, bytes })) { + describe(`with ${name} inputs`, function () { + it('is correctly calculating modulus', async function () { + const b = 3n; + const e = 200n; + const m = 50n; + + await expect(this.mock.$modExp(type(b), type(e), type(m))).to.eventually.equal(type(b ** e % m).value); + }); + + it('is correctly reverting when modulus is zero', async function () { + const b = 3n; + const e = 200n; + const m = 0n; + + await expect(this.mock.$modExp(type(b), type(e), type(m))).to.be.revertedWithPanic( + PANIC_CODES.DIVISION_BY_ZERO, + ); + }); + }); + } + + describe('with large bytes inputs', function () { + for (const [[b, log2b], [e, log2e], [m, log2m]] of product( + range(320, 512, 64).map(e => [2n ** BigInt(e) + 1n, e]), + range(320, 512, 64).map(e => [2n ** BigInt(e) + 1n, e]), + range(320, 512, 64).map(e => [2n ** BigInt(e) + 1n, e]), + )) { + it(`calculates b ** e % m (b=2**${log2b}+1) (e=2**${log2e}+1) (m=2**${log2m}+1)`, async function () { + const mLength = ethers.dataLength(ethers.toBeHex(m)); + + await expect(this.mock.$modExp(bytes(b), bytes(e), bytes(m))).to.eventually.equal( + bytes(modExp(b, e, m), mLength).value, + ); + }); + } + }); + }); + + describe('tryModExp', function () { + for (const [name, type] of Object.entries({ uint256, bytes })) { + describe(`with ${name} inputs`, function () { + it('is correctly calculating modulus', async function () { + const b = 3n; + const e = 200n; + const m = 50n; + + await expect(this.mock.$tryModExp(type(b), type(e), type(m))).to.eventually.deep.equal([ + true, + type(b ** e % m).value, + ]); + }); + + it('is correctly reverting when modulus is zero', async function () { + const b = 3n; + const e = 200n; + const m = 0n; + + await expect(this.mock.$tryModExp(type(b), type(e), type(m))).to.eventually.deep.equal([false, type.zero]); + }); + }); + } + + describe('with large bytes inputs', function () { + for (const [[b, log2b], [e, log2e], [m, log2m]] of product( + range(320, 513, 64).map(e => [2n ** BigInt(e) + 1n, e]), + range(320, 513, 64).map(e => [2n ** BigInt(e) + 1n, e]), + range(320, 513, 64).map(e => [2n ** BigInt(e) + 1n, e]), + )) { + it(`calculates b ** e % m (b=2**${log2b}+1) (e=2**${log2e}+1) (m=2**${log2m}+1)`, async function () { + const mLength = ethers.dataLength(ethers.toBeHex(m)); + + await expect(this.mock.$tryModExp(bytes(b), bytes(e), bytes(m))).to.eventually.deep.equal([ + true, + bytes(modExp(b, e, m), mLength).value, + ]); + }); + } + }); + }); + + describe('sqrt', function () { + it('rounds down', async function () { + for (const rounding of RoundingDown) { + await expect(this.mock.$sqrt(0n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$sqrt(1n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$sqrt(2n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$sqrt(3n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$sqrt(4n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$sqrt(144n, rounding)).to.eventually.equal(12n); + await expect(this.mock.$sqrt(999999n, rounding)).to.eventually.equal(999n); + await expect(this.mock.$sqrt(1000000n, rounding)).to.eventually.equal(1000n); + await expect(this.mock.$sqrt(1000001n, rounding)).to.eventually.equal(1000n); + await expect(this.mock.$sqrt(1002000n, rounding)).to.eventually.equal(1000n); + await expect(this.mock.$sqrt(1002001n, rounding)).to.eventually.equal(1001n); + await expect(this.mock.$sqrt(ethers.MaxUint256, rounding)).to.eventually.equal( + 340282366920938463463374607431768211455n, + ); + } + }); + + it('rounds up', async function () { + for (const rounding of RoundingUp) { + await expect(this.mock.$sqrt(0n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$sqrt(1n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$sqrt(2n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$sqrt(3n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$sqrt(4n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$sqrt(144n, rounding)).to.eventually.equal(12n); + await expect(this.mock.$sqrt(999999n, rounding)).to.eventually.equal(1000n); + await expect(this.mock.$sqrt(1000000n, rounding)).to.eventually.equal(1000n); + await expect(this.mock.$sqrt(1000001n, rounding)).to.eventually.equal(1001n); + await expect(this.mock.$sqrt(1002000n, rounding)).to.eventually.equal(1001n); + await expect(this.mock.$sqrt(1002001n, rounding)).to.eventually.equal(1001n); + await expect(this.mock.$sqrt(ethers.MaxUint256, rounding)).to.eventually.equal( + 340282366920938463463374607431768211456n, + ); + } + }); + }); + + describe('log', function () { + describe('log2', function () { + it('rounds down', async function () { + for (const rounding of RoundingDown) { + await expect(this.mock.$log2(0n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log2(1n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log2(2n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log2(3n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log2(4n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log2(5n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log2(6n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log2(7n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log2(8n, rounding)).to.eventually.equal(3n); + await expect(this.mock.$log2(9n, rounding)).to.eventually.equal(3n); + await expect(this.mock.$log2(ethers.MaxUint256, rounding)).to.eventually.equal(255n); + } + }); + + it('rounds up', async function () { + for (const rounding of RoundingUp) { + await expect(this.mock.$log2(0n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log2(1n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log2(2n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log2(3n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log2(4n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log2(5n, rounding)).to.eventually.equal(3n); + await expect(this.mock.$log2(6n, rounding)).to.eventually.equal(3n); + await expect(this.mock.$log2(7n, rounding)).to.eventually.equal(3n); + await expect(this.mock.$log2(8n, rounding)).to.eventually.equal(3n); + await expect(this.mock.$log2(9n, rounding)).to.eventually.equal(4n); + await expect(this.mock.$log2(ethers.MaxUint256, rounding)).to.eventually.equal(256n); + } + }); + }); + + describe('log10', function () { + it('rounds down', async function () { + for (const rounding of RoundingDown) { + await expect(this.mock.$log10(0n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log10(1n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log10(2n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log10(9n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log10(10n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log10(11n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log10(99n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log10(100n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log10(101n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log10(999n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log10(1000n, rounding)).to.eventually.equal(3n); + await expect(this.mock.$log10(1001n, rounding)).to.eventually.equal(3n); + await expect(this.mock.$log10(ethers.MaxUint256, rounding)).to.eventually.equal(77n); + } + }); + + it('rounds up', async function () { + for (const rounding of RoundingUp) { + await expect(this.mock.$log10(0n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log10(1n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log10(2n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log10(9n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log10(10n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log10(11n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log10(99n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log10(100n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log10(101n, rounding)).to.eventually.equal(3n); + await expect(this.mock.$log10(999n, rounding)).to.eventually.equal(3n); + await expect(this.mock.$log10(1000n, rounding)).to.eventually.equal(3n); + await expect(this.mock.$log10(1001n, rounding)).to.eventually.equal(4n); + await expect(this.mock.$log10(ethers.MaxUint256, rounding)).to.eventually.equal(78n); + } + }); + }); + + describe('log256', function () { + it('rounds down', async function () { + for (const rounding of RoundingDown) { + await expect(this.mock.$log256(0n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log256(1n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log256(2n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log256(255n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log256(256n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log256(257n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log256(65535n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log256(65536n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log256(65537n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log256(ethers.MaxUint256, rounding)).to.eventually.equal(31n); + } + }); + + it('rounds up', async function () { + for (const rounding of RoundingUp) { + await expect(this.mock.$log256(0n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log256(1n, rounding)).to.eventually.equal(0n); + await expect(this.mock.$log256(2n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log256(255n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log256(256n, rounding)).to.eventually.equal(1n); + await expect(this.mock.$log256(257n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log256(65535n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log256(65536n, rounding)).to.eventually.equal(2n); + await expect(this.mock.$log256(65537n, rounding)).to.eventually.equal(3n); + await expect(this.mock.$log256(ethers.MaxUint256, rounding)).to.eventually.equal(32n); + } + }); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js new file mode 100644 index 0000000..ab62406 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js @@ -0,0 +1,159 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { range } = require('../../helpers/iterate'); + +async function fixture() { + const mock = await ethers.deployContract('$SafeCast'); + return { mock }; +} + +describe('SafeCast', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + for (const bits of range(8, 256, 8).map(ethers.toBigInt)) { + const maxValue = 2n ** bits - 1n; + + describe(`toUint${bits}`, () => { + it('downcasts 0', async function () { + expect(await this.mock[`$toUint${bits}`](0n)).is.equal(0n); + }); + + it('downcasts 1', async function () { + expect(await this.mock[`$toUint${bits}`](1n)).is.equal(1n); + }); + + it(`downcasts 2^${bits} - 1 (${maxValue})`, async function () { + expect(await this.mock[`$toUint${bits}`](maxValue)).is.equal(maxValue); + }); + + it(`reverts when downcasting 2^${bits} (${maxValue + 1n})`, async function () { + await expect(this.mock[`$toUint${bits}`](maxValue + 1n)) + .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintDowncast') + .withArgs(bits, maxValue + 1n); + }); + + it(`reverts when downcasting 2^${bits} + 1 (${maxValue + 2n})`, async function () { + await expect(this.mock[`$toUint${bits}`](maxValue + 2n)) + .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintDowncast') + .withArgs(bits, maxValue + 2n); + }); + }); + } + + describe('toUint256', () => { + it('casts 0', async function () { + expect(await this.mock.$toUint256(0n)).is.equal(0n); + }); + + it('casts 1', async function () { + expect(await this.mock.$toUint256(1n)).is.equal(1n); + }); + + it(`casts INT256_MAX (${ethers.MaxInt256})`, async function () { + expect(await this.mock.$toUint256(ethers.MaxInt256)).is.equal(ethers.MaxInt256); + }); + + it('reverts when casting -1', async function () { + await expect(this.mock.$toUint256(-1n)) + .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntToUint') + .withArgs(-1n); + }); + + it(`reverts when casting INT256_MIN (${ethers.MinInt256})`, async function () { + await expect(this.mock.$toUint256(ethers.MinInt256)) + .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntToUint') + .withArgs(ethers.MinInt256); + }); + }); + + for (const bits of range(8, 256, 8).map(ethers.toBigInt)) { + const minValue = -(2n ** (bits - 1n)); + const maxValue = 2n ** (bits - 1n) - 1n; + + describe(`toInt${bits}`, () => { + it('downcasts 0', async function () { + expect(await this.mock[`$toInt${bits}`](0n)).is.equal(0n); + }); + + it('downcasts 1', async function () { + expect(await this.mock[`$toInt${bits}`](1n)).is.equal(1n); + }); + + it('downcasts -1', async function () { + expect(await this.mock[`$toInt${bits}`](-1n)).is.equal(-1n); + }); + + it(`downcasts -2^${bits - 1n} (${minValue})`, async function () { + expect(await this.mock[`$toInt${bits}`](minValue)).is.equal(minValue); + }); + + it(`downcasts 2^${bits - 1n} - 1 (${maxValue})`, async function () { + expect(await this.mock[`$toInt${bits}`](maxValue)).is.equal(maxValue); + }); + + it(`reverts when downcasting -2^${bits - 1n} - 1 (${minValue - 1n})`, async function () { + await expect(this.mock[`$toInt${bits}`](minValue - 1n)) + .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast') + .withArgs(bits, minValue - 1n); + }); + + it(`reverts when downcasting -2^${bits - 1n} - 2 (${minValue - 2n})`, async function () { + await expect(this.mock[`$toInt${bits}`](minValue - 2n)) + .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast') + .withArgs(bits, minValue - 2n); + }); + + it(`reverts when downcasting 2^${bits - 1n} (${maxValue + 1n})`, async function () { + await expect(this.mock[`$toInt${bits}`](maxValue + 1n)) + .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast') + .withArgs(bits, maxValue + 1n); + }); + + it(`reverts when downcasting 2^${bits - 1n} + 1 (${maxValue + 2n})`, async function () { + await expect(this.mock[`$toInt${bits}`](maxValue + 2n)) + .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast') + .withArgs(bits, maxValue + 2n); + }); + }); + } + + describe('toInt256', () => { + it('casts 0', async function () { + expect(await this.mock.$toInt256(0)).is.equal(0n); + }); + + it('casts 1', async function () { + expect(await this.mock.$toInt256(1)).is.equal(1n); + }); + + it(`casts INT256_MAX (${ethers.MaxInt256})`, async function () { + expect(await this.mock.$toInt256(ethers.MaxInt256)).is.equal(ethers.MaxInt256); + }); + + it(`reverts when casting INT256_MAX + 1 (${ethers.MaxInt256 + 1n})`, async function () { + await expect(this.mock.$toInt256(ethers.MaxInt256 + 1n)) + .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintToInt') + .withArgs(ethers.MaxInt256 + 1n); + }); + + it(`reverts when casting UINT256_MAX (${ethers.MaxUint256})`, async function () { + await expect(this.mock.$toInt256(ethers.MaxUint256)) + .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintToInt') + .withArgs(ethers.MaxUint256); + }); + }); + + describe('toUint (bool)', function () { + it('toUint(false) should be 0', async function () { + expect(await this.mock.$toUint(false)).to.equal(0n); + }); + + it('toUint(true) should be 1', async function () { + expect(await this.mock.$toUint(true)).to.equal(1n); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.t.sol new file mode 100644 index 0000000..98a40a1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.t.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; + +import {Math} from "../../../contracts/utils/math/Math.sol"; +import {SignedMath} from "../../../contracts/utils/math/SignedMath.sol"; + +contract SignedMathTest is Test { + function testSymbolicTernary(bool f, int256 a, int256 b) public pure { + assertEq(SignedMath.ternary(f, a, b), f ? a : b); + } + + // MIN & MAX + function testSymbolicMinMax(int256 a, int256 b) public pure { + assertEq(SignedMath.min(a, b), a < b ? a : b); + assertEq(SignedMath.max(a, b), a > b ? a : b); + } + + // MIN + function testSymbolicMin(int256 a, int256 b) public pure { + int256 result = SignedMath.min(a, b); + + assertLe(result, a); + assertLe(result, b); + assertTrue(result == a || result == b); + } + + // MAX + function testSymbolicMax(int256 a, int256 b) public pure { + int256 result = SignedMath.max(a, b); + + assertGe(result, a); + assertGe(result, b); + assertTrue(result == a || result == b); + } + + // AVERAGE + // 1. simple test, not full int256 range + function testAverage1(int256 a, int256 b) public pure { + a = bound(a, type(int256).min / 2, type(int256).max / 2); + b = bound(b, type(int256).min / 2, type(int256).max / 2); + + int256 result = SignedMath.average(a, b); + + assertEq(result, (a + b) / 2); + } + + // 2. more complex test, full int256 range + function testAverage2(int256 a, int256 b) public pure { + (int256 result, int256 min, int256 max) = ( + SignedMath.average(a, b), + SignedMath.min(a, b), + SignedMath.max(a, b) + ); + + // average must be between `a` and `b` + assertGe(result, min); + assertLe(result, max); + + unchecked { + // must be unchecked in order to support `a = type(int256).min, b = type(int256).max` + uint256 deltaLower = uint256(result - min); + uint256 deltaUpper = uint256(max - result); + uint256 remainder = uint256((a & 1) ^ (b & 1)); + assertEq(remainder, Math.max(deltaLower, deltaUpper) - Math.min(deltaLower, deltaUpper)); + } + } + + // ABS + function testSymbolicAbs(int256 a) public pure { + uint256 result = SignedMath.abs(a); + + unchecked { + // must be unchecked in order to support `n = type(int256).min` + assertEq(result, a < 0 ? uint256(-a) : uint256(a)); + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js new file mode 100644 index 0000000..877f3b4 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js @@ -0,0 +1,53 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { min, max } = require('../../helpers/math'); + +async function testCommutative(fn, lhs, rhs, expected, ...extra) { + expect(await fn(lhs, rhs, ...extra)).to.deep.equal(expected); + expect(await fn(rhs, lhs, ...extra)).to.deep.equal(expected); +} + +async function fixture() { + const mock = await ethers.deployContract('$SignedMath'); + return { mock }; +} + +describe('SignedMath', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('max', function () { + it('is correctly detected in both position', async function () { + await testCommutative(this.mock.$max, -1234n, 5678n, max(-1234n, 5678n)); + }); + }); + + describe('min', function () { + it('is correctly detected in both position', async function () { + await testCommutative(this.mock.$min, -1234n, 5678n, min(-1234n, 5678n)); + }); + }); + + describe('average', function () { + it('is correctly calculated with various input', async function () { + for (const x of [ethers.MinInt256, -57417n, -42304n, -4n, -3n, 0n, 3n, 4n, 42304n, 57417n, ethers.MaxInt256]) { + for (const y of [ethers.MinInt256, -57417n, -42304n, -5n, -2n, 0n, 2n, 5n, 42304n, 57417n, ethers.MaxInt256]) { + expect(await this.mock.$average(x, y)).to.equal((x + y) / 2n); + } + } + }); + }); + + describe('abs', function () { + const abs = x => (x < 0n ? -x : x); + + for (const n of [ethers.MinInt256, ethers.MinInt256 + 1n, -1n, 0n, 1n, ethers.MaxInt256 - 1n, ethers.MaxInt256]) { + it(`correctly computes the absolute value of ${n}`, async function () { + expect(await this.mock.$abs(n)).to.equal(abs(n)); + }); + } + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js new file mode 100644 index 0000000..5662ab1 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js @@ -0,0 +1,149 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +async function fixture() { + const bitmap = await ethers.deployContract('$BitMaps'); + return { bitmap }; +} + +describe('BitMap', function () { + const keyA = 7891n; + const keyB = 451n; + const keyC = 9592328n; + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('starts empty', async function () { + expect(await this.bitmap.$get(0, keyA)).to.be.false; + expect(await this.bitmap.$get(0, keyB)).to.be.false; + expect(await this.bitmap.$get(0, keyC)).to.be.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.be.true; + expect(await this.bitmap.$get(0, keyB)).to.be.false; + expect(await this.bitmap.$get(0, keyC)).to.be.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.be.false; + expect(await this.bitmap.$get(0, keyB)).to.be.false; + expect(await this.bitmap.$get(0, keyC)).to.be.false; + }); + + it('set several consecutive keys', async function () { + await this.bitmap.$setTo(0, keyA + 0n, true); + await this.bitmap.$setTo(0, keyA + 1n, true); + await this.bitmap.$setTo(0, keyA + 2n, true); + await this.bitmap.$setTo(0, keyA + 3n, true); + await this.bitmap.$setTo(0, keyA + 4n, true); + await this.bitmap.$setTo(0, keyA + 2n, false); + await this.bitmap.$setTo(0, keyA + 4n, false); + expect(await this.bitmap.$get(0, keyA + 0n)).to.be.true; + expect(await this.bitmap.$get(0, keyA + 1n)).to.be.true; + expect(await this.bitmap.$get(0, keyA + 2n)).to.be.false; + expect(await this.bitmap.$get(0, keyA + 3n)).to.be.true; + expect(await this.bitmap.$get(0, keyA + 4n)).to.be.false; + }); + }); + + describe('set', function () { + it('adds a key', async function () { + await this.bitmap.$set(0, keyA); + expect(await this.bitmap.$get(0, keyA)).to.be.true; + expect(await this.bitmap.$get(0, keyB)).to.be.false; + expect(await this.bitmap.$get(0, keyC)).to.be.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.be.true; + expect(await this.bitmap.$get(0, keyB)).to.be.true; + expect(await this.bitmap.$get(0, keyC)).to.be.false; + }); + + it('adds several consecutive keys', async function () { + await this.bitmap.$set(0, keyA + 0n); + await this.bitmap.$set(0, keyA + 1n); + await this.bitmap.$set(0, keyA + 3n); + expect(await this.bitmap.$get(0, keyA + 0n)).to.be.true; + expect(await this.bitmap.$get(0, keyA + 1n)).to.be.true; + expect(await this.bitmap.$get(0, keyA + 2n)).to.be.false; + expect(await this.bitmap.$get(0, keyA + 3n)).to.be.true; + expect(await this.bitmap.$get(0, keyA + 4n)).to.be.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.be.false; + expect(await this.bitmap.$get(0, keyB)).to.be.true; + expect(await this.bitmap.$get(0, keyC)).to.be.false; + }); + + it('removes consecutive added keys', async function () { + await this.bitmap.$set(0, keyA + 0n); + await this.bitmap.$set(0, keyA + 1n); + await this.bitmap.$set(0, keyA + 3n); + await this.bitmap.$unset(0, keyA + 1n); + expect(await this.bitmap.$get(0, keyA + 0n)).to.be.true; + expect(await this.bitmap.$get(0, keyA + 1n)).to.be.false; + expect(await this.bitmap.$get(0, keyA + 2n)).to.be.false; + expect(await this.bitmap.$get(0, keyA + 3n)).to.be.true; + expect(await this.bitmap.$get(0, keyA + 4n)).to.be.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.be.true; + expect(await this.bitmap.$get(0, keyB)).to.be.false; + expect(await this.bitmap.$get(0, keyC)).to.be.true; + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.t.sol new file mode 100644 index 0000000..74d8fb8 --- /dev/null +++ b/typescript/packages/account-modules/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 "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {Checkpoints} from "@openzeppelin/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 will 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 pure returns (uint32) { + return SafeCast.toUint32(bound(uint256(x), uint256(min), uint256(max))); + } + + function _prepareKeys(uint32[] memory keys, uint32 maxSpread) internal pure { + 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 view { + (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 will 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 pure returns (uint48) { + return SafeCast.toUint48(bound(uint256(x), uint256(min), uint256(max))); + } + + function _prepareKeys(uint48[] memory keys, uint48 maxSpread) internal pure { + 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 view { + (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 will 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 pure returns (uint96) { + return SafeCast.toUint96(bound(uint256(x), uint256(min), uint256(max))); + } + + function _prepareKeys(uint96[] memory keys, uint96 maxSpread) internal pure { + 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 view { + (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/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.test.js new file mode 100644 index 0000000..fd22544 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.test.js @@ -0,0 +1,146 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { VALUE_SIZES } = require('../../../scripts/generate/templates/Checkpoints.opts'); + +describe('Checkpoints', function () { + for (const length of VALUE_SIZES) { + describe(`Trace${length}`, function () { + const fixture = async () => { + const mock = await ethers.deployContract('$Checkpoints'); + const methods = { + at: (...args) => mock.getFunction(`$at_Checkpoints_Trace${length}`)(0, ...args), + latest: (...args) => mock.getFunction(`$latest_Checkpoints_Trace${length}`)(0, ...args), + latestCheckpoint: (...args) => mock.getFunction(`$latestCheckpoint_Checkpoints_Trace${length}`)(0, ...args), + length: (...args) => mock.getFunction(`$length_Checkpoints_Trace${length}`)(0, ...args), + push: (...args) => mock.getFunction(`$push(uint256,uint${256 - length},uint${length})`)(0, ...args), + lowerLookup: (...args) => mock.getFunction(`$lowerLookup(uint256,uint${256 - length})`)(0, ...args), + upperLookup: (...args) => mock.getFunction(`$upperLookup(uint256,uint${256 - length})`)(0, ...args), + upperLookupRecent: (...args) => + mock.getFunction(`$upperLookupRecent(uint256,uint${256 - length})`)(0, ...args), + }; + + return { mock, methods }; + }; + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('without checkpoints', function () { + it('at zero reverts', async function () { + // Reverts with array out of bound access, which is unspecified + await expect(this.methods.at(0)).to.be.reverted; + }); + + it('returns zero as latest value', async function () { + expect(await this.methods.latest()).to.equal(0n); + + const ckpt = await this.methods.latestCheckpoint(); + expect(ckpt[0]).to.be.false; + expect(ckpt[1]).to.equal(0n); + expect(ckpt[2]).to.equal(0n); + }); + + it('lookup returns 0', async function () { + expect(await this.methods.lowerLookup(0)).to.equal(0n); + expect(await this.methods.upperLookup(0)).to.equal(0n); + expect(await this.methods.upperLookupRecent(0)).to.equal(0n); + }); + }); + + describe('with checkpoints', function () { + beforeEach('pushing checkpoints', async function () { + this.checkpoints = [ + { key: 2n, value: 17n }, + { key: 3n, value: 42n }, + { key: 5n, value: 101n }, + { key: 7n, value: 23n }, + { key: 11n, value: 99n }, + ]; + 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.equal(value); + expect(at._key).to.equal(key); + } + }); + + it('length', async function () { + expect(await this.methods.length()).to.equal(this.checkpoints.length); + }); + + it('returns latest value', async function () { + const latest = this.checkpoints.at(-1); + expect(await this.methods.latest()).to.equal(latest.value); + expect(await this.methods.latestCheckpoint()).to.deep.equal([true, latest.key, latest.value]); + }); + + it('cannot push values in the past', async function () { + await expect(this.methods.push(this.checkpoints.at(-1).key - 1n, 0n)).to.be.revertedWithCustomError( + this.mock, + 'CheckpointUnorderedInsertion', + ); + }); + + it('can update last value', async function () { + const newValue = 42n; + + // check length before the update + expect(await this.methods.length()).to.equal(this.checkpoints.length); + + // update last key + await this.methods.push(this.checkpoints.at(-1).key, newValue); + expect(await this.methods.latest()).to.equal(newValue); + + // check that length did not change + expect(await this.methods.length()).to.equal(this.checkpoints.length); + }); + + it('lower lookup', async function () { + for (let i = 0; i < 14; ++i) { + const value = this.checkpoints.find(x => i <= x.key)?.value || 0n; + + expect(await this.methods.lowerLookup(i)).to.equal(value); + } + }); + + it('upper lookup & upperLookupRecent', async function () { + for (let i = 0; i < 14; ++i) { + const value = this.checkpoints.findLast(x => i >= x.key)?.value || 0n; + + expect(await this.methods.upperLookup(i)).to.equal(value); + expect(await this.methods.upperLookupRecent(i)).to.equal(value); + } + }); + + it('upperLookupRecent with more than 5 checkpoints', async function () { + const moreCheckpoints = [ + { key: 12n, value: 22n }, + { key: 13n, value: 131n }, + { key: 17n, value: 45n }, + { key: 19n, value: 31452n }, + { key: 21n, value: 0n }, + ]; + 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 = allCheckpoints.findLast(x => i >= x.key)?.value || 0n; + expect(await this.methods.upperLookup(i)).to.equal(value); + expect(await this.methods.upperLookupRecent(i)).to.equal(value); + } + }); + }); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/CircularBuffer.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/CircularBuffer.test.js new file mode 100644 index 0000000..e79ba69 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/CircularBuffer.test.js @@ -0,0 +1,83 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +const { generators } = require('../../helpers/random'); + +const LENGTH = 4; + +async function fixture() { + const mock = await ethers.deployContract('$CircularBuffer'); + await mock.$setup(0, LENGTH); + return { mock }; +} + +describe('CircularBuffer', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('reverts on invalid setup', async function () { + await expect(this.mock.$setup(0, 0)).to.be.revertedWithCustomError(this.mock, 'InvalidBufferSize'); + }); + + it('starts empty', async function () { + expect(await this.mock.$count(0)).to.equal(0n); + expect(await this.mock.$length(0)).to.equal(LENGTH); + expect(await this.mock.$includes(0, ethers.ZeroHash)).to.be.false; + await expect(this.mock.$last(0, 0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); + }); + + it('push', async function () { + const values = Array.from({ length: LENGTH + 3 }, generators.bytes32); + + for (const [i, value] of values.map((v, i) => [i, v])) { + // push value + await this.mock.$push(0, value); + + // view of the values + const pushed = values.slice(0, i + 1); + const stored = pushed.slice(-LENGTH); + const dropped = pushed.slice(0, -LENGTH); + + // check count + expect(await this.mock.$length(0)).to.equal(LENGTH); + expect(await this.mock.$count(0)).to.equal(stored.length); + + // check last + for (const j in stored) { + expect(await this.mock.$last(0, j)).to.equal(stored.at(-j - 1)); + } + await expect(this.mock.$last(0, stored.length + 1)).to.be.revertedWithPanic( + PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS, + ); + + // check included and non-included values + for (const v of stored) { + expect(await this.mock.$includes(0, v)).to.be.true; + } + for (const v of dropped) { + expect(await this.mock.$includes(0, v)).to.be.false; + } + expect(await this.mock.$includes(0, ethers.ZeroHash)).to.be.false; + } + }); + + it('clear', async function () { + const value = generators.bytes32(); + await this.mock.$push(0, value); + + expect(await this.mock.$count(0)).to.equal(1n); + expect(await this.mock.$length(0)).to.equal(LENGTH); + expect(await this.mock.$includes(0, value)).to.be.true; + await this.mock.$last(0, 0); // not revert + + await this.mock.$clear(0); + + expect(await this.mock.$count(0)).to.equal(0n); + expect(await this.mock.$length(0)).to.equal(LENGTH); + expect(await this.mock.$includes(0, value)).to.be.false; + await expect(this.mock.$last(0, 0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js new file mode 100644 index 0000000..3615dfb --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js @@ -0,0 +1,102 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +async function fixture() { + const mock = await ethers.deployContract('$DoubleEndedQueue'); + + /** Rebuild the content of the deque as a JS array. */ + const getContent = () => + mock.$length(0).then(length => Promise.all(Array.from({ length: Number(length) }, (_, i) => mock.$at(0, i)))); + + return { mock, getContent }; +} + +describe('DoubleEndedQueue', function () { + const coder = ethers.AbiCoder.defaultAbiCoder(); + const bytesA = coder.encode(['uint256'], [0xdeadbeef]); + const bytesB = coder.encode(['uint256'], [0x0123456789]); + const bytesC = coder.encode(['uint256'], [0x42424242]); + const bytesD = coder.encode(['uint256'], [0x171717]); + + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('when empty', function () { + it('getters', async function () { + expect(await this.mock.$empty(0)).to.be.true; + expect(await this.getContent()).to.have.ordered.members([]); + }); + + it('reverts on accesses', async function () { + await expect(this.mock.$popBack(0)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY); + await expect(this.mock.$popFront(0)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY); + await expect(this.mock.$back(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); + await expect(this.mock.$front(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); + }); + }); + + describe('when not empty', function () { + beforeEach(async function () { + await this.mock.$pushBack(0, bytesB); + await this.mock.$pushFront(0, bytesA); + await this.mock.$pushBack(0, bytesC); + this.content = [bytesA, bytesB, bytesC]; + }); + + it('getters', async function () { + expect(await this.mock.$empty(0)).to.be.false; + expect(await this.mock.$length(0)).to.equal(this.content.length); + expect(await this.mock.$front(0)).to.equal(this.content[0]); + expect(await this.mock.$back(0)).to.equal(this.content[this.content.length - 1]); + expect(await this.getContent()).to.have.ordered.members(this.content); + }); + + it('out of bounds access', async function () { + await expect(this.mock.$at(0, this.content.length)).to.be.revertedWithPanic( + PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS, + ); + }); + + describe('push', function () { + it('front', async function () { + await this.mock.$pushFront(0, bytesD); + this.content.unshift(bytesD); // add element at the beginning + + expect(await this.getContent()).to.have.ordered.members(this.content); + }); + + it('back', async function () { + await this.mock.$pushBack(0, bytesD); + this.content.push(bytesD); // add element at the end + + expect(await this.getContent()).to.have.ordered.members(this.content); + }); + }); + + describe('pop', function () { + it('front', async function () { + const value = this.content.shift(); // remove first element + await expect(this.mock.$popFront(0)).to.emit(this.mock, 'return$popFront').withArgs(value); + + expect(await this.getContent()).to.have.ordered.members(this.content); + }); + + it('back', async function () { + const value = this.content.pop(); // remove last element + await expect(this.mock.$popBack(0)).to.emit(this.mock, 'return$popBack').withArgs(value); + + expect(await this.getContent()).to.have.ordered.members(this.content); + }); + }); + + it('clear', async function () { + await this.mock.$clear(0); + + expect(await this.mock.$empty(0)).to.be.true; + expect(await this.getContent()).to.have.ordered.members([]); + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js new file mode 100644 index 0000000..4074b07 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js @@ -0,0 +1,214 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); + +const zip = (array1, array2) => array1.map((item, index) => [item, array2[index]]); + +function shouldBehaveLikeMap() { + async function expectMembersMatch(methods, keys, values) { + expect(keys.length).to.equal(values.length); + expect(await methods.length()).to.equal(keys.length); + expect([...(await methods.keys())]).to.have.members(keys); + + for (const [key, value] of zip(keys, values)) { + expect(await methods.contains(key)).to.be.true; + expect(await methods.get(key)).to.equal(value); + } + + expect(await Promise.all(keys.map((_, index) => methods.at(index)))).to.have.deep.members(zip(keys, values)); + } + + it('starts empty', async function () { + expect(await this.methods.contains(this.keyA)).to.be.false; + + await expectMembersMatch(this.methods, [], []); + }); + + describe('set', function () { + it('adds a key', async function () { + await expect(this.methods.set(this.keyA, this.valueA)).to.emit(this.mock, this.events.setReturn).withArgs(true); + + await expectMembersMatch(this.methods, [this.keyA], [this.valueA]); + }); + + it('adds several keys', async function () { + await this.methods.set(this.keyA, this.valueA); + await this.methods.set(this.keyB, this.valueB); + + await expectMembersMatch(this.methods, [this.keyA, this.keyB], [this.valueA, this.valueB]); + expect(await this.methods.contains(this.keyC)).to.be.false; + }); + + it('returns false when adding keys already in the set', async function () { + await this.methods.set(this.keyA, this.valueA); + + await expect(this.methods.set(this.keyA, this.valueA)).to.emit(this.mock, this.events.setReturn).withArgs(false); + + await expectMembersMatch(this.methods, [this.keyA], [this.valueA]); + }); + + it('updates values for keys already in the set', async function () { + await this.methods.set(this.keyA, this.valueA); + await this.methods.set(this.keyA, this.valueB); + + await expectMembersMatch(this.methods, [this.keyA], [this.valueB]); + }); + }); + + describe('remove', function () { + it('removes added keys', async function () { + await this.methods.set(this.keyA, this.valueA); + + await expect(this.methods.remove(this.keyA)).to.emit(this.mock, this.events.removeReturn).withArgs(true); + + expect(await this.methods.contains(this.keyA)).to.be.false; + await expectMembersMatch(this.methods, [], []); + }); + + it('returns false when removing keys not in the set', async function () { + await expect(await this.methods.remove(this.keyA)) + .to.emit(this.mock, this.events.removeReturn) + .withArgs(false); + + expect(await this.methods.contains(this.keyA)).to.be.false; + }); + + it('adds and removes multiple keys', async function () { + // [] + + await this.methods.set(this.keyA, this.valueA); + await this.methods.set(this.keyC, this.valueC); + + // [A, C] + + await this.methods.remove(this.keyA); + await this.methods.remove(this.keyB); + + // [C] + + await this.methods.set(this.keyB, this.valueB); + + // [C, B] + + await this.methods.set(this.keyA, this.valueA); + await this.methods.remove(this.keyC); + + // [A, B] + + await this.methods.set(this.keyA, this.valueA); + await this.methods.set(this.keyB, this.valueB); + + // [A, B] + + await this.methods.set(this.keyC, this.valueC); + await this.methods.remove(this.keyA); + + // [B, C] + + await this.methods.set(this.keyA, this.valueA); + await this.methods.remove(this.keyB); + + // [A, C] + + await expectMembersMatch(this.methods, [this.keyA, this.keyC], [this.valueA, this.valueC]); + + expect(await this.methods.contains(this.keyA)).to.be.true; + expect(await this.methods.contains(this.keyB)).to.be.false; + expect(await this.methods.contains(this.keyC)).to.be.true; + }); + }); + + describe('clear', function () { + it('clears a single entry', async function () { + await this.methods.set(this.keyA, this.valueA); + + await this.methods.clear(); + + expect(await this.methods.contains(this.keyA)).to.be.false; + await expectMembersMatch(this.methods, [], []); + }); + + it('clears multiple entries', async function () { + await this.methods.set(this.keyA, this.valueA); + await this.methods.set(this.keyB, this.valueB); + await this.methods.set(this.keyC, this.valueC); + + await this.methods.clear(); + + expect(await this.methods.contains(this.keyA)).to.be.false; + expect(await this.methods.contains(this.keyB)).to.be.false; + expect(await this.methods.contains(this.keyC)).to.be.false; + await expectMembersMatch(this.methods, [], []); + }); + + it('does not revert on empty map', async function () { + await this.methods.clear(); + }); + + it('clear then add entry', async function () { + await this.methods.set(this.keyA, this.valueA); + await this.methods.set(this.keyB, this.valueB); + await this.methods.set(this.keyC, this.valueC); + + await this.methods.clear(); + + await this.methods.set(this.keyA, this.valueA); + + expect(await this.methods.contains(this.keyA)).to.be.true; + expect(await this.methods.contains(this.keyB)).to.be.false; + expect(await this.methods.contains(this.keyC)).to.be.false; + await expectMembersMatch(this.methods, [this.keyA], [this.valueA]); + }); + }); + + describe('read', function () { + beforeEach(async function () { + await this.methods.set(this.keyA, this.valueA); + }); + + describe('get', function () { + it('existing value', async function () { + expect(await this.methods.get(this.keyA)).to.equal(this.valueA); + }); + + it('missing value', async function () { + await expect(this.methods.get(this.keyB)) + .to.be.revertedWithCustomError(this.mock, this.error ?? 'EnumerableMapNonexistentKey') + .withArgs( + this.key?.memory || this.value?.memory + ? this.keyB + : ethers.AbiCoder.defaultAbiCoder().encode([this.key.type], [this.keyB]), + ); + }); + }); + + describe('tryGet', function () { + it('existing value', async function () { + expect(await this.methods.tryGet(this.keyA)).to.have.ordered.members([true, this.valueA]); + }); + + it('missing value', async function () { + expect(await this.methods.tryGet(this.keyB)).to.have.ordered.members([false, this.zeroValue]); + }); + }); + }); + + it('keys (full & paginated)', async function () { + const keys = [this.keyA, this.keyB, this.keyC]; + await this.methods.set(this.keyA, this.valueA); + await this.methods.set(this.keyB, this.valueB); + await this.methods.set(this.keyC, this.valueC); + + // get all values + expect([...(await this.methods.keys())]).to.deep.equal(keys); + + // try pagination + for (const begin of [0, 1, 2, 3, 4]) + for (const end of [0, 1, 2, 3, 4]) { + expect([...(await this.methods.keysPage(begin, end))]).to.deep.equal(keys.slice(begin, end)); + } + }); +} + +module.exports = { + shouldBehaveLikeMap, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js new file mode 100644 index 0000000..567c82d --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js @@ -0,0 +1,83 @@ +const { ethers } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { mapValues } = require('../../helpers/iterate'); +const { generators } = require('../../helpers/random'); +const { MAP_TYPES, typeDescr, toMapTypeDescr } = require('../../../scripts/generate/templates/Enumerable.opts'); + +const { shouldBehaveLikeMap } = require('./EnumerableMap.behavior'); + +// Add Bytes32ToBytes32Map that must be tested but is not part of the generated types. +MAP_TYPES.unshift(toMapTypeDescr({ key: typeDescr({ type: 'bytes32' }), value: typeDescr({ type: 'bytes32' }) })); + +async function fixture() { + const mock = await ethers.deployContract('$EnumerableMap'); + + const env = Object.fromEntries( + MAP_TYPES.map(({ name, key, value }) => [ + name, + { + key, + value, + keys: Array.from({ length: 3 }, generators[key.type]), + values: Array.from({ length: 3 }, generators[value.type]), + zeroValue: generators[value.type].zero, + methods: mapValues( + MAP_TYPES.filter(map => map.key.name == key.name).length == 1 + ? { + set: `$set(uint256,${key.type},${value.type})`, + get: `$get(uint256,${key.type})`, + tryGet: `$tryGet(uint256,${key.type})`, + remove: `$remove(uint256,${key.type})`, + contains: `$contains(uint256,${key.type})`, + clear: `$clear_EnumerableMap_${name}(uint256)`, + length: `$length_EnumerableMap_${name}(uint256)`, + at: `$at_EnumerableMap_${name}(uint256,uint256)`, + keys: `$keys_EnumerableMap_${name}(uint256)`, + keysPage: `$keys_EnumerableMap_${name}(uint256,uint256,uint256)`, + } + : { + set: `$set(uint256,${key.type},${value.type})`, + get: `$get_EnumerableMap_${name}(uint256,${key.type})`, + tryGet: `$tryGet_EnumerableMap_${name}(uint256,${key.type})`, + remove: `$remove_EnumerableMap_${name}(uint256,${key.type})`, + contains: `$contains_EnumerableMap_${name}(uint256,${key.type})`, + clear: `$clear_EnumerableMap_${name}(uint256)`, + length: `$length_EnumerableMap_${name}(uint256)`, + at: `$at_EnumerableMap_${name}(uint256,uint256)`, + keys: `$keys_EnumerableMap_${name}(uint256)`, + keysPage: `$keys_EnumerableMap_${name}(uint256,uint256,uint256)`, + }, + fnSig => + (...args) => + mock.getFunction(fnSig)(0, ...args), + ), + events: { + setReturn: `return$set_EnumerableMap_${name}_${key.type}_${value.type}`, + removeReturn: `return$remove_EnumerableMap_${name}_${key.type}`, + }, + error: key.memory || value.memory ? `EnumerableMapNonexistent${key.name}Key` : `EnumerableMapNonexistentKey`, + }, + ]), + ); + + return { mock, env }; +} + +describe('EnumerableMap', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + for (const { name, key, value } of MAP_TYPES) { + describe(`${name} (enumerable map from ${key.type} to ${value.type})`, function () { + beforeEach(async function () { + Object.assign(this, this.env[name]); + [this.keyA, this.keyB, this.keyC] = this.keys; + [this.valueA, this.valueB, this.valueC] = this.values; + }); + + shouldBehaveLikeMap(); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js new file mode 100644 index 0000000..286563b --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js @@ -0,0 +1,175 @@ +const { expect } = require('chai'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +function shouldBehaveLikeSet() { + async function expectMembersMatch(methods, values) { + expect(await methods.length()).to.equal(values.length); + for (const value of values) expect(await methods.contains(value)).to.be.true; + + expect(await Promise.all(values.map((_, index) => methods.at(index)))).to.have.deep.members(values); + expect([...(await methods.values())]).to.have.deep.members(values); + } + + it('starts empty', async function () { + expect(await this.methods.contains(this.valueA)).to.be.false; + + await expectMembersMatch(this.methods, []); + }); + + describe('add', function () { + it('adds a value', async function () { + await expect(this.methods.add(this.valueA)).to.emit(this.mock, this.events.addReturn).withArgs(true); + + await expectMembersMatch(this.methods, [this.valueA]); + }); + + it('adds several values', async function () { + await this.methods.add(this.valueA); + await this.methods.add(this.valueB); + + await expectMembersMatch(this.methods, [this.valueA, this.valueB]); + expect(await this.methods.contains(this.valueC)).to.be.false; + }); + + it('returns false when adding values already in the set', async function () { + await this.methods.add(this.valueA); + + await expect(this.methods.add(this.valueA)).to.emit(this.mock, this.events.addReturn).withArgs(false); + + await expectMembersMatch(this.methods, [this.valueA]); + }); + }); + + describe('at', function () { + it('reverts when retrieving non-existent elements', async function () { + await expect(this.methods.at(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); + }); + + it('retrieves existing element', async function () { + await this.methods.add(this.valueA); + expect(await this.methods.at(0)).to.deep.equal(this.valueA); + }); + }); + + describe('remove', function () { + it('removes added values', async function () { + await this.methods.add(this.valueA); + + await expect(this.methods.remove(this.valueA)).to.emit(this.mock, this.events.removeReturn).withArgs(true); + + expect(await this.methods.contains(this.valueA)).to.be.false; + await expectMembersMatch(this.methods, []); + }); + + it('returns false when removing values not in the set', async function () { + await expect(this.methods.remove(this.valueA)).to.emit(this.mock, this.events.removeReturn).withArgs(false); + + expect(await this.methods.contains(this.valueA)).to.be.false; + }); + + it('adds and removes multiple values', async function () { + // [] + + await this.methods.add(this.valueA); + await this.methods.add(this.valueC); + + // [A, C] + + await this.methods.remove(this.valueA); + await this.methods.remove(this.valueB); + + // [C] + + await this.methods.add(this.valueB); + + // [C, B] + + await this.methods.add(this.valueA); + await this.methods.remove(this.valueC); + + // [A, B] + + await this.methods.add(this.valueA); + await this.methods.add(this.valueB); + + // [A, B] + + await this.methods.add(this.valueC); + await this.methods.remove(this.valueA); + + // [B, C] + + await this.methods.add(this.valueA); + await this.methods.remove(this.valueB); + + // [A, C] + + await expectMembersMatch(this.methods, [this.valueA, this.valueC]); + + expect(await this.methods.contains(this.valueB)).to.be.false; + }); + }); + + describe('clear', function () { + it('clears a single value', async function () { + await this.methods.add(this.valueA); + + await this.methods.clear(); + + expect(await this.methods.contains(this.valueA)).to.be.false; + await expectMembersMatch(this.methods, []); + }); + + it('clears multiple values', async function () { + await this.methods.add(this.valueA); + await this.methods.add(this.valueB); + await this.methods.add(this.valueC); + + await this.methods.clear(); + + expect(await this.methods.contains(this.valueA)).to.be.false; + expect(await this.methods.contains(this.valueB)).to.be.false; + expect(await this.methods.contains(this.valueC)).to.be.false; + await expectMembersMatch(this.methods, []); + }); + + it('does not revert on empty set', async function () { + await this.methods.clear(); + }); + + it('clear then add value', async function () { + await this.methods.add(this.valueA); + await this.methods.add(this.valueB); + await this.methods.add(this.valueC); + + await this.methods.clear(); + + await this.methods.add(this.valueA); + + expect(await this.methods.contains(this.valueA)).to.be.true; + expect(await this.methods.contains(this.valueB)).to.be.false; + expect(await this.methods.contains(this.valueC)).to.be.false; + await expectMembersMatch(this.methods, [this.valueA]); + }); + }); + + it('values (full & paginated)', async function () { + const values = [this.valueA, this.valueB, this.valueC]; + await this.methods.add(this.valueA); + await this.methods.add(this.valueB); + await this.methods.add(this.valueC); + + // get all values + expect([...(await this.methods.values())]).to.deep.equal(values); + + // try pagination + for (const begin of [0, 1, 2, 3, 4]) + for (const end of [0, 1, 2, 3, 4]) { + expect([...(await this.methods.valuesPage(begin, end))]).to.deep.equal(values.slice(begin, end)); + } + }); +} + +module.exports = { + shouldBehaveLikeSet, +}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js new file mode 100644 index 0000000..135bdf5 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js @@ -0,0 +1,66 @@ +const { ethers } = require('hardhat'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { mapValues } = require('../../helpers/iterate'); +const { generators } = require('../../helpers/random'); +const { SET_TYPES } = require('../../../scripts/generate/templates/Enumerable.opts'); + +const { shouldBehaveLikeSet } = require('./EnumerableSet.behavior'); + +const getMethods = (mock, fnSigs) => + mapValues( + fnSigs, + fnSig => + (...args) => + mock.getFunction(fnSig)(0, ...args), + ); + +async function fixture() { + const mock = await ethers.deployContract('$EnumerableSet'); + + const env = Object.fromEntries( + SET_TYPES.map(({ name, value }) => [ + name, + { + value, + values: Array.from( + { length: 3 }, + value.size ? () => Array.from({ length: value.size }, generators[value.base]) : generators[value.type], + ), + methods: getMethods(mock, { + add: `$add(uint256,${value.type})`, + remove: `$remove(uint256,${value.type})`, + contains: `$contains(uint256,${value.type})`, + clear: `$clear_EnumerableSet_${name}(uint256)`, + length: `$length_EnumerableSet_${name}(uint256)`, + at: `$at_EnumerableSet_${name}(uint256,uint256)`, + values: `$values_EnumerableSet_${name}(uint256)`, + valuesPage: `$values_EnumerableSet_${name}(uint256,uint256,uint256)`, + }), + events: { + addReturn: `return$add_EnumerableSet_${name}_${value.type.replace(/[[\]]/g, '_')}`, + removeReturn: `return$remove_EnumerableSet_${name}_${value.type.replace(/[[\]]/g, '_')}`, + }, + }, + ]), + ); + + return { mock, env }; +} + +describe('EnumerableSet', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + for (const { name, value } of SET_TYPES) { + describe(`${name} (enumerable set of ${value.type})`, function () { + beforeEach(function () { + Object.assign(this, this.env[name]); + [this.valueA, this.valueB, this.valueC] = this.values; + }); + + shouldBehaveLikeSet(); + }); + } +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.t.sol new file mode 100644 index 0000000..ba7d770 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.t.sol @@ -0,0 +1,74 @@ +// 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"; +import {Heap} from "@openzeppelin/contracts/utils/structs/Heap.sol"; +import {Comparators} from "@openzeppelin/contracts/utils/Comparators.sol"; + +contract Uint256HeapTest is Test { + using Heap for Heap.Uint256Heap; + + Heap.Uint256Heap internal heap; + + function _validateHeap(function(uint256, uint256) view returns (bool) comp) internal view { + for (uint32 i = 1; i < heap.length(); ++i) { + assertFalse(comp(heap.tree[i], heap.tree[(i - 1) / 2])); + } + } + + function testFuzz(uint256[] calldata input) public { + vm.assume(input.length < 0x20); + assertEq(heap.length(), 0); + + uint256 min = type(uint256).max; + for (uint256 i = 0; i < input.length; ++i) { + heap.insert(input[i]); + assertEq(heap.length(), i + 1); + _validateHeap(Comparators.lt); + + min = Math.min(min, input[i]); + assertEq(heap.peek(), min); + } + + uint256 max = 0; + for (uint256 i = 0; i < input.length; ++i) { + uint256 top = heap.peek(); + uint256 pop = heap.pop(); + assertEq(heap.length(), input.length - i - 1); + _validateHeap(Comparators.lt); + + assertEq(pop, top); + assertGe(pop, max); + max = pop; + } + } + + function testFuzzGt(uint256[] calldata input) public { + vm.assume(input.length < 0x20); + assertEq(heap.length(), 0); + + uint256 max = 0; + for (uint256 i = 0; i < input.length; ++i) { + heap.insert(input[i], Comparators.gt); + assertEq(heap.length(), i + 1); + _validateHeap(Comparators.gt); + + max = Math.max(max, input[i]); + assertEq(heap.peek(), max); + } + + uint256 min = type(uint256).max; + for (uint256 i = 0; i < input.length; ++i) { + uint256 top = heap.peek(); + uint256 pop = heap.pop(Comparators.gt); + assertEq(heap.length(), input.length - i - 1); + _validateHeap(Comparators.gt); + + assertEq(pop, top); + assertLe(pop, min); + min = pop; + } + } +} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.test.js new file mode 100644 index 0000000..6d75120 --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.test.js @@ -0,0 +1,113 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); + +async function fixture() { + const mock = await ethers.deployContract('$Heap'); + return { mock }; +} + +describe('Heap', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('Uint256Heap', function () { + it('starts empty', async function () { + expect(await this.mock.$length(0)).to.equal(0n); + }); + + it('peek, pop and replace from empty', async function () { + await expect(this.mock.$peek(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); + await expect(this.mock.$pop(0)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY); + await expect(this.mock.$replace(0, 0n)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY); + }); + + it('clear', async function () { + await this.mock.$insert(0, 42n); + + expect(await this.mock.$length(0)).to.equal(1n); + expect(await this.mock.$peek(0)).to.equal(42n); + + await this.mock.$clear(0); + + expect(await this.mock.$length(0)).to.equal(0n); + await expect(this.mock.$peek(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); + }); + + it('support duplicated items', async function () { + expect(await this.mock.$length(0)).to.equal(0n); + + // insert 5 times + await this.mock.$insert(0, 42n); + await this.mock.$insert(0, 42n); + await this.mock.$insert(0, 42n); + await this.mock.$insert(0, 42n); + await this.mock.$insert(0, 42n); + + // pop 5 times + await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n); + await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n); + await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n); + await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n); + await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n); + + // popping a 6th time panics + await expect(this.mock.$pop(0)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY); + }); + + it('insert, pop and replace', async function () { + const heap = []; + for (const { op, value } of [ + { op: 'insert', value: 712 }, // [712] + { op: 'insert', value: 20 }, // [20, 712] + { op: 'insert', value: 4337 }, // [20, 712, 4437] + { op: 'pop' }, // 20, [712, 4437] + { op: 'insert', value: 1559 }, // [712, 1559, 4437] + { op: 'insert', value: 165 }, // [165, 712, 1559, 4437] + { op: 'insert', value: 155 }, // [155, 165, 712, 1559, 4437] + { op: 'insert', value: 7702 }, // [155, 165, 712, 1559, 4437, 7702] + { op: 'pop' }, // 155, [165, 712, 1559, 4437, 7702] + { op: 'replace', value: 721 }, // 165, [712, 721, 1559, 4437, 7702] + { op: 'pop' }, // 712, [721, 1559, 4437, 7702] + { op: 'pop' }, // 721, [1559, 4437, 7702] + { op: 'pop' }, // 1559, [4437, 7702] + { op: 'pop' }, // 4437, [7702] + { op: 'pop' }, // 7702, [] + { op: 'pop' }, // panic + { op: 'replace', value: '1363' }, // panic + ]) { + switch (op) { + case 'insert': + await this.mock.$insert(0, value); + heap.push(value); + heap.sort((a, b) => a - b); + break; + case 'pop': + if (heap.length == 0) { + await expect(this.mock.$pop(0)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY); + } else { + await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(heap.shift()); + } + break; + case 'replace': + if (heap.length == 0) { + await expect(this.mock.$replace(0, value)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY); + } else { + await expect(this.mock.$replace(0, value)).to.emit(this.mock, 'return$replace').withArgs(heap.shift()); + heap.push(value); + heap.sort((a, b) => a - b); + } + break; + } + expect(await this.mock.$length(0)).to.equal(heap.length); + if (heap.length == 0) { + await expect(this.mock.$peek(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); + } else { + expect(await this.mock.$peek(0)).to.equal(heap[0]); + } + } + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/MerkleTree.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/MerkleTree.test.js new file mode 100644 index 0000000..f0380ed --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/MerkleTree.test.js @@ -0,0 +1,180 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); +const { StandardMerkleTree } = require('@openzeppelin/merkle-tree'); + +const { generators } = require('../../helpers/random'); +const { range } = require('../../helpers/iterate'); + +const DEPTH = 4; // 16 slots + +const makeTree = (leaves = [], length = 2 ** DEPTH, zero = ethers.ZeroHash) => + StandardMerkleTree.of( + [] + .concat( + leaves, + Array.from({ length: length - leaves.length }, () => zero), + ) + .map(leaf => [leaf]), + ['bytes32'], + { sortLeaves: false }, + ); + +const ZERO = makeTree().leafHash([ethers.ZeroHash]); + +async function fixture() { + const mock = await ethers.deployContract('MerkleTreeMock'); + await mock.setup(DEPTH, ZERO); + return { mock }; +} + +describe('MerkleTree', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + it('sets initial values at setup', async function () { + const merkleTree = makeTree(); + + await expect(this.mock.root()).to.eventually.equal(merkleTree.root); + await expect(this.mock.depth()).to.eventually.equal(DEPTH); + await expect(this.mock.nextLeafIndex()).to.eventually.equal(0n); + }); + + describe('push', function () { + it('pushing correctly updates the tree', async function () { + const leaves = []; + + // for each leaf slot + for (const i in range(2 ** DEPTH)) { + // generate random leaf + leaves.push(generators.bytes32()); + + // rebuild tree. + const tree = makeTree(leaves); + const hash = tree.leafHash(tree.at(i)); + + // push value to tree + await expect(this.mock.push(hash)).to.emit(this.mock, 'LeafInserted').withArgs(hash, i, tree.root); + + // check tree + await expect(this.mock.root()).to.eventually.equal(tree.root); + await expect(this.mock.nextLeafIndex()).to.eventually.equal(BigInt(i) + 1n); + } + }); + + it('pushing to a full tree reverts', async function () { + await Promise.all(Array.from({ length: 2 ** Number(DEPTH) }).map(() => this.mock.push(ethers.ZeroHash))); + + await expect(this.mock.push(ethers.ZeroHash)).to.be.revertedWithPanic(PANIC_CODES.TOO_MUCH_MEMORY_ALLOCATED); + }); + }); + + describe('update', function () { + for (const { leafCount, leafIndex } of range(2 ** DEPTH + 1).flatMap(leafCount => + range(leafCount).map(leafIndex => ({ leafCount, leafIndex })), + )) + it(`updating a leaf correctly updates the tree (leaf #${leafIndex + 1}/${leafCount})`, async function () { + // initial tree + const leaves = Array.from({ length: leafCount }, generators.bytes32); + const oldTree = makeTree(leaves); + + // fill tree and verify root + for (const i in leaves) { + await this.mock.push(oldTree.leafHash(oldTree.at(i))); + } + await expect(this.mock.root()).to.eventually.equal(oldTree.root); + + // create updated tree + leaves[leafIndex] = generators.bytes32(); + const newTree = makeTree(leaves); + + const oldLeafHash = oldTree.leafHash(oldTree.at(leafIndex)); + const newLeafHash = newTree.leafHash(newTree.at(leafIndex)); + + // perform update + await expect(this.mock.update(leafIndex, oldLeafHash, newLeafHash, oldTree.getProof(leafIndex))) + .to.emit(this.mock, 'LeafUpdated') + .withArgs(oldLeafHash, newLeafHash, leafIndex, newTree.root); + + // verify updated root + await expect(this.mock.root()).to.eventually.equal(newTree.root); + + // if there is still room in the tree, fill it + for (const i of range(leafCount, 2 ** DEPTH)) { + // push new value and rebuild tree + leaves.push(generators.bytes32()); + const nextTree = makeTree(leaves); + + // push and verify root + await this.mock.push(nextTree.leafHash(nextTree.at(i))); + await expect(this.mock.root()).to.eventually.equal(nextTree.root); + } + }); + + it('replacing a leaf that was not previously pushed reverts', async function () { + // changing leaf 0 on an empty tree + await expect(this.mock.update(1, ZERO, ZERO, [])) + .to.be.revertedWithCustomError(this.mock, 'MerkleTreeUpdateInvalidIndex') + .withArgs(1, 0); + }); + + it('replacing a leaf using an invalid proof reverts', async function () { + const leafCount = 4; + const leafIndex = 2; + + const leaves = Array.from({ length: leafCount }, generators.bytes32); + const tree = makeTree(leaves); + + // fill tree and verify root + for (const i in leaves) { + await this.mock.push(tree.leafHash(tree.at(i))); + } + await expect(this.mock.root()).to.eventually.equal(tree.root); + + const oldLeafHash = tree.leafHash(tree.at(leafIndex)); + const newLeafHash = generators.bytes32(); + const proof = tree.getProof(leafIndex); + // invalid proof (tamper) + proof[1] = generators.bytes32(); + + await expect(this.mock.update(leafIndex, oldLeafHash, newLeafHash, proof)).to.be.revertedWithCustomError( + this.mock, + 'MerkleTreeUpdateInvalidProof', + ); + }); + }); + + it('reset', async function () { + // empty tree + const emptyTree = makeTree(); + + // tree with one element + const leaves = [generators.bytes32()]; + const tree = makeTree(leaves); + const hash = tree.leafHash(tree.at(0)); + + // root should be that of a zero tree + expect(await this.mock.root()).to.equal(emptyTree.root); + expect(await this.mock.nextLeafIndex()).to.equal(0n); + + // push leaf and check root + await expect(this.mock.push(hash)).to.emit(this.mock, 'LeafInserted').withArgs(hash, 0, tree.root); + + expect(await this.mock.root()).to.equal(tree.root); + expect(await this.mock.nextLeafIndex()).to.equal(1n); + + // reset tree + await this.mock.setup(DEPTH, ZERO); + + expect(await this.mock.root()).to.equal(emptyTree.root); + expect(await this.mock.nextLeafIndex()).to.equal(0n); + + // re-push leaf and check root + await expect(this.mock.push(hash)).to.emit(this.mock, 'LeafInserted').withArgs(hash, 0, tree.root); + + expect(await this.mock.root()).to.equal(tree.root); + expect(await this.mock.nextLeafIndex()).to.equal(1n); + }); +}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/types/Time.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/types/Time.test.js new file mode 100644 index 0000000..3ab6fef --- /dev/null +++ b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/types/Time.test.js @@ -0,0 +1,135 @@ +const { ethers } = require('hardhat'); +const { expect } = require('chai'); +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); + +const { product } = require('../../helpers/iterate'); +const { max } = require('../../helpers/math'); +const time = require('../../helpers/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) => { + value = ethers.toBigInt(value); + size = ethers.toBigInt(size); + expect(value).to.be.greaterThanOrEqual(0n, `value is not a valid uint${size}`); + expect(value).to.be.lessThan(1n << size, `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, +]; + +async function fixture() { + const mock = await ethers.deployContract('$Time'); + return { mock }; +} + +describe('Time', function () { + beforeEach(async function () { + Object.assign(this, await loadFixture(fixture)); + }); + + describe('clocks', function () { + it('timestamp', async function () { + expect(await this.mock.$timestamp()).to.equal(await time.clock.timestamp()); + }); + + it('block number', async function () { + expect(await this.mock.$blockNumber()).to.equal(await time.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 () { + expect(await this.mock.$pack(valueBefore, valueAfter, effect)).to.equal(delay); + expect(packDelay({ valueBefore, valueAfter, effect })).to.equal(delay); + }); + + it('unpack', async function () { + expect(await this.mock.$unpack(delay)).to.deep.equal([valueBefore, valueAfter, effect]); + + expect(unpackDelay(delay)).to.deep.equal({ + valueBefore, + valueAfter, + effect, + }); + }); + }); + + it('toDelay', async function () { + for (const value of [...SOME_VALUES, MAX_UINT32]) { + expect(await this.mock.$toDelay(value).then(unpackDelay)).to.deep.equal({ + valueBefore: 0n, + valueAfter: value, + effect: 0n, + }); + } + }); + + it('get & getFull', async function () { + const timepoint = await time.clock.timestamp(); + 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.equal(isPast ? valueAfter : valueBefore); + expect(await this.mock.$getFull(delay)).to.deep.equal([ + isPast ? valueAfter : valueBefore, + isPast ? 0n : valueAfter, + isPast ? 0n : effect, + ]); + } + }); + + it('withUpdate', async function () { + const timepoint = await time.clock.timestamp(); + 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); + + expect( + await this.mock.$withUpdate(packDelay({ valueBefore, valueAfter, effect }), newvalueAfter, minSetback), + ).to.deep.equal([ + packDelay({ + valueBefore: expectedvalueBefore, + valueAfter: newvalueAfter, + effect: timepoint + expectedSetback, + }), + timepoint + expectedSetback, + ]); + } + }); + }); +}); diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gas-snapshot b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gas-snapshot new file mode 100644 index 0000000..a37218e --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gas-snapshot @@ -0,0 +1,3 @@ +SafeSingletonDeployerTest:test_deploy_createsAtExpectedAddress() (gas: 110747) +SafeSingletonDeployerTest:test_deploy_createsContractCorrectly() (gas: 100784) +SafeSingletonDeployerTest:test_deploy_reverts() (gas: 41137) \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.github/workflows/test.yml b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.github/workflows/test.yml new file mode 100644 index 0000000..fb3a71c --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.github/workflows/test.yml @@ -0,0 +1,86 @@ +name: Forge CI + +on: + pull_request: + branches: + - main + +env: + FOUNDRY_PROFILE: ci + +jobs: + forge-test: + name: Run Forge Tests and Checks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Run Forge build + run: | + forge --version + forge build --sizes + id: build + + - name: Run Forge tests + run: | + forge test -vvv + id: test + + - name: Check formatting + run: | + forge fmt --check + id: fmt + + forge-coverage: + name: Run Coverage Reporting + 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: Install forge dependencies + run: forge install + + - name: Install lcov + run: | + sudo apt-get install lcov + id: lcov + + - name: Run coverage + run: | + forge coverage --report summary --report lcov + + - name: Prune coverage + run: | + lcov --remove ./lcov.info -o ./lcov-filtered.info 'test/*' 'script/*' 'src/utils/*' + + - name: Submit coverage to Coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + path-to-lcov: ./lcov-filtered.info + flag-name: foundry + parallel: true + + finish: + needs: forge-coverage + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Coveralls Finished + uses: coverallsapp/github-action@v2 + with: + parallel-finished: true diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitignore b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitignore new file mode 100644 index 0000000..85198aa --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitignore @@ -0,0 +1,14 @@ +# Compiler files +cache/ +out/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Docs +docs/ + +# Dotenv file +.env diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitmodules b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitmodules new file mode 100644 index 0000000..888d42d --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/forge-std"] + path = lib/forge-std + url = https://github.com/foundry-rs/forge-std diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/README.md b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/README.md new file mode 100644 index 0000000..853c64d --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/README.md @@ -0,0 +1,9 @@ + +# Solidity Safe Singleton Factory Deployer +This is a Solidity library for using [Safe Singleton Factory](https://github.com/safe-global/safe-singleton-factory). At the code level, this factory matches [Arachnid's Determinstic Deployment Proxy](https://github.com/Arachnid/deterministic-deployment-proxy). It is different from other deterministic deployment factories in that Safe holds the private key and has NOT shared any presigned transactions. This can help avoid accidental or malicious nonce increments via presigned transactions with invalid gas values for a certain network. + +Safe has currently deployed this factory to 252 chains and it has the same address on 248. + +I made this library so that this factory would be easiser to use with Forge deployment scripts, as there seem to only be existing tools for Hardhat. + +Example usage in [`ExampleDeploy.s.sol`](https://github.com/wilsoncusack/safe-singleton-deployer-sol/blob/main/scripts/ExampleDeploy.s.sol) diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/foundry.toml b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/foundry.toml new file mode 100644 index 0000000..25b918f --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/foundry.toml @@ -0,0 +1,6 @@ +[profile.default] +src = "src" +out = "out" +libs = ["lib"] + +# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitattributes b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitattributes new file mode 100644 index 0000000..27042d4 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitattributes @@ -0,0 +1 @@ +src/Vm.sol linguist-generated diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.github/workflows/ci.yml b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.github/workflows/ci.yml new file mode 100644 index 0000000..cb241ae --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.github/workflows/sync.yml b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.github/workflows/sync.yml new file mode 100644 index 0000000..5a9e9d5 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitignore b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitignore new file mode 100644 index 0000000..756106d --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitignore @@ -0,0 +1,4 @@ +cache/ +out/ +.vscode +.idea diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/LICENSE-APACHE b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/LICENSE-APACHE new file mode 100644 index 0000000..cf01a49 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/LICENSE-MIT b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/LICENSE-MIT new file mode 100644 index 0000000..28f9830 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/README.md b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/README.md new file mode 100644 index 0000000..0cb8660 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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 + +Contains various assertions. + +### `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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/foundry.toml b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/foundry.toml new file mode 100644 index 0000000..c873eaa --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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://eth-mainnet.alchemyapi.io/v2/WV407BEiBmjNJfKo9Uo_55u0z0ITyCOX" # 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/package.json b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/package.json new file mode 100644 index 0000000..acc004b --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/package.json @@ -0,0 +1,16 @@ +{ + "name": "forge-std", + "version": "1.7.6", + "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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/scripts/vm.py b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/scripts/vm.py new file mode 100755 index 0000000..f0537db --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/scripts/vm.py @@ -0,0 +1,635 @@ +#!/usr/bin/env python3 + +import copy +import json +import re +import subprocess +from enum import Enum as PyEnum +from typing import Callable +from urllib import request + +VoidFn = Callable[[], None] + +CHEATCODES_JSON_URL = "https://raw.githubusercontent.com/foundry-rs/foundry/master/crates/cheatcodes/assets/cheatcodes.json" +OUT_PATH = "src/Vm.sol" + +VM_SAFE_DOC = """\ +/// 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. +""" + +VM_DOC = """\ +/// 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. +""" + + +def main(): + json_str = request.urlopen(CHEATCODES_JSON_URL).read().decode("utf-8") + contract = Cheatcodes.from_json(json_str) + + ccs = contract.cheatcodes + ccs = list(filter(lambda cc: cc.status not in ["experimental", "internal"], ccs)) + ccs.sort(key=lambda cc: cc.func.id) + + safe = list(filter(lambda cc: cc.safety == "safe", ccs)) + safe.sort(key=CmpCheatcode) + unsafe = list(filter(lambda cc: cc.safety == "unsafe", ccs)) + unsafe.sort(key=CmpCheatcode) + assert len(safe) + len(unsafe) == len(ccs) + + prefix_with_group_headers(safe) + prefix_with_group_headers(unsafe) + + out = "" + + out += "// Automatically @generated by scripts/vm.py. Do not modify manually.\n\n" + + pp = CheatcodesPrinter( + spdx_identifier="MIT OR Apache-2.0", + solidity_requirement=">=0.6.2 <0.9.0", + abicoder_pragma=True, + ) + pp.p_prelude() + pp.prelude = False + out += pp.finish() + + out += "\n\n" + out += VM_SAFE_DOC + vm_safe = Cheatcodes( + # TODO: Custom errors were introduced in 0.8.4 + errors=[], # contract.errors + events=contract.events, + enums=contract.enums, + structs=contract.structs, + cheatcodes=safe, + ) + pp.p_contract(vm_safe, "VmSafe") + out += pp.finish() + + out += "\n\n" + out += VM_DOC + vm_unsafe = Cheatcodes( + errors=[], + events=[], + enums=[], + structs=[], + cheatcodes=unsafe, + ) + pp.p_contract(vm_unsafe, "Vm", "VmSafe") + out += pp.finish() + + # Compatibility with <0.8.0 + def memory_to_calldata(m: re.Match) -> str: + return " calldata " + m.group(1) + + out = re.sub(r" memory (.*returns)", memory_to_calldata, out) + + with open(OUT_PATH, "w") as f: + f.write(out) + + forge_fmt = ["forge", "fmt", OUT_PATH] + res = subprocess.run(forge_fmt) + assert res.returncode == 0, f"command failed: {forge_fmt}" + + print(f"Wrote to {OUT_PATH}") + + +class CmpCheatcode: + cheatcode: "Cheatcode" + + def __init__(self, cheatcode: "Cheatcode"): + self.cheatcode = cheatcode + + def __lt__(self, other: "CmpCheatcode") -> bool: + return cmp_cheatcode(self.cheatcode, other.cheatcode) < 0 + + def __eq__(self, other: "CmpCheatcode") -> bool: + return cmp_cheatcode(self.cheatcode, other.cheatcode) == 0 + + def __gt__(self, other: "CmpCheatcode") -> bool: + return cmp_cheatcode(self.cheatcode, other.cheatcode) > 0 + + +def cmp_cheatcode(a: "Cheatcode", b: "Cheatcode") -> int: + if a.group != b.group: + return -1 if a.group < b.group else 1 + if a.status != b.status: + return -1 if a.status < b.status else 1 + if a.safety != b.safety: + return -1 if a.safety < b.safety else 1 + if a.func.id != b.func.id: + return -1 if a.func.id < b.func.id else 1 + return 0 + + +# HACK: A way to add group header comments without having to modify printer code +def prefix_with_group_headers(cheats: list["Cheatcode"]): + s = set() + for i, cheat in enumerate(cheats): + if cheat.group in s: + continue + + s.add(cheat.group) + + c = copy.deepcopy(cheat) + c.func.description = "" + c.func.declaration = f"// ======== {group(c.group)} ========" + cheats.insert(i, c) + return cheats + + +def group(s: str) -> str: + if s == "evm": + return "EVM" + if s == "json": + return "JSON" + return s[0].upper() + s[1:] + + +class Visibility(PyEnum): + EXTERNAL: str = "external" + PUBLIC: str = "public" + INTERNAL: str = "internal" + PRIVATE: str = "private" + + def __str__(self): + return self.value + + +class Mutability(PyEnum): + PURE: str = "pure" + VIEW: str = "view" + NONE: str = "" + + def __str__(self): + return self.value + + +class Function: + id: str + description: str + declaration: str + visibility: Visibility + mutability: Mutability + signature: str + selector: str + selector_bytes: bytes + + def __init__( + self, + id: str, + description: str, + declaration: str, + visibility: Visibility, + mutability: Mutability, + signature: str, + selector: str, + selector_bytes: bytes, + ): + self.id = id + self.description = description + self.declaration = declaration + self.visibility = visibility + self.mutability = mutability + self.signature = signature + self.selector = selector + self.selector_bytes = selector_bytes + + @staticmethod + def from_dict(d: dict) -> "Function": + return Function( + d["id"], + d["description"], + d["declaration"], + Visibility(d["visibility"]), + Mutability(d["mutability"]), + d["signature"], + d["selector"], + bytes(d["selectorBytes"]), + ) + + +class Cheatcode: + func: Function + group: str + status: str + safety: str + + def __init__(self, func: Function, group: str, status: str, safety: str): + self.func = func + self.group = group + self.status = status + self.safety = safety + + @staticmethod + def from_dict(d: dict) -> "Cheatcode": + return Cheatcode( + Function.from_dict(d["func"]), + str(d["group"]), + str(d["status"]), + str(d["safety"]), + ) + + +class Error: + name: str + description: str + declaration: str + + def __init__(self, name: str, description: str, declaration: str): + self.name = name + self.description = description + self.declaration = declaration + + @staticmethod + def from_dict(d: dict) -> "Error": + return Error(**d) + + +class Event: + name: str + description: str + declaration: str + + def __init__(self, name: str, description: str, declaration: str): + self.name = name + self.description = description + self.declaration = declaration + + @staticmethod + def from_dict(d: dict) -> "Event": + return Event(**d) + + +class EnumVariant: + name: str + description: str + + def __init__(self, name: str, description: str): + self.name = name + self.description = description + + +class Enum: + name: str + description: str + variants: list[EnumVariant] + + def __init__(self, name: str, description: str, variants: list[EnumVariant]): + self.name = name + self.description = description + self.variants = variants + + @staticmethod + def from_dict(d: dict) -> "Enum": + return Enum( + d["name"], + d["description"], + list(map(lambda v: EnumVariant(**v), d["variants"])), + ) + + +class StructField: + name: str + ty: str + description: str + + def __init__(self, name: str, ty: str, description: str): + self.name = name + self.ty = ty + self.description = description + + +class Struct: + name: str + description: str + fields: list[StructField] + + def __init__(self, name: str, description: str, fields: list[StructField]): + self.name = name + self.description = description + self.fields = fields + + @staticmethod + def from_dict(d: dict) -> "Struct": + return Struct( + d["name"], + d["description"], + list(map(lambda f: StructField(**f), d["fields"])), + ) + + +class Cheatcodes: + errors: list[Error] + events: list[Event] + enums: list[Enum] + structs: list[Struct] + cheatcodes: list[Cheatcode] + + def __init__( + self, + errors: list[Error], + events: list[Event], + enums: list[Enum], + structs: list[Struct], + cheatcodes: list[Cheatcode], + ): + self.errors = errors + self.events = events + self.enums = enums + self.structs = structs + self.cheatcodes = cheatcodes + + @staticmethod + def from_dict(d: dict) -> "Cheatcodes": + return Cheatcodes( + errors=[Error.from_dict(e) for e in d["errors"]], + events=[Event.from_dict(e) for e in d["events"]], + enums=[Enum.from_dict(e) for e in d["enums"]], + structs=[Struct.from_dict(e) for e in d["structs"]], + cheatcodes=[Cheatcode.from_dict(e) for e in d["cheatcodes"]], + ) + + @staticmethod + def from_json(s) -> "Cheatcodes": + return Cheatcodes.from_dict(json.loads(s)) + + @staticmethod + def from_json_file(file_path: str) -> "Cheatcodes": + with open(file_path, "r") as f: + return Cheatcodes.from_dict(json.load(f)) + + +class Item(PyEnum): + ERROR: str = "error" + EVENT: str = "event" + ENUM: str = "enum" + STRUCT: str = "struct" + FUNCTION: str = "function" + + +class ItemOrder: + _list: list[Item] + + def __init__(self, list: list[Item]) -> None: + assert len(list) <= len(Item), "list must not contain more items than Item" + assert len(list) == len(set(list)), "list must not contain duplicates" + self._list = list + pass + + def get_list(self) -> list[Item]: + return self._list + + @staticmethod + def default() -> "ItemOrder": + return ItemOrder( + [ + Item.ERROR, + Item.EVENT, + Item.ENUM, + Item.STRUCT, + Item.FUNCTION, + ] + ) + + +class CheatcodesPrinter: + buffer: str + + prelude: bool + spdx_identifier: str + solidity_requirement: str + abicoder_v2: bool + + block_doc_style: bool + + indent_level: int + _indent_str: str + + nl_str: str + + items_order: ItemOrder + + def __init__( + self, + buffer: str = "", + prelude: bool = True, + spdx_identifier: str = "UNLICENSED", + solidity_requirement: str = "", + abicoder_pragma: bool = False, + block_doc_style: bool = False, + indent_level: int = 0, + indent_with: int | str = 4, + nl_str: str = "\n", + items_order: ItemOrder = ItemOrder.default(), + ): + self.prelude = prelude + self.spdx_identifier = spdx_identifier + self.solidity_requirement = solidity_requirement + self.abicoder_v2 = abicoder_pragma + self.block_doc_style = block_doc_style + self.buffer = buffer + self.indent_level = indent_level + self.nl_str = nl_str + + if isinstance(indent_with, int): + assert indent_with >= 0 + self._indent_str = " " * indent_with + elif isinstance(indent_with, str): + self._indent_str = indent_with + else: + assert False, "indent_with must be int or str" + + self.items_order = items_order + + def finish(self) -> str: + ret = self.buffer.rstrip() + self.buffer = "" + return ret + + def p_contract(self, contract: Cheatcodes, name: str, inherits: str = ""): + if self.prelude: + self.p_prelude(contract) + + self._p_str("interface ") + name = name.strip() + if name != "": + self._p_str(name) + self._p_str(" ") + if inherits != "": + self._p_str("is ") + self._p_str(inherits) + self._p_str(" ") + self._p_str("{") + self._p_nl() + self._with_indent(lambda: self._p_items(contract)) + self._p_str("}") + self._p_nl() + + def _p_items(self, contract: Cheatcodes): + for item in self.items_order.get_list(): + if item == Item.ERROR: + self.p_errors(contract.errors) + elif item == Item.EVENT: + self.p_events(contract.events) + elif item == Item.ENUM: + self.p_enums(contract.enums) + elif item == Item.STRUCT: + self.p_structs(contract.structs) + elif item == Item.FUNCTION: + self.p_functions(contract.cheatcodes) + else: + assert False, f"unknown item {item}" + + def p_prelude(self, contract: Cheatcodes | None = None): + self._p_str(f"// SPDX-License-Identifier: {self.spdx_identifier}") + self._p_nl() + + if self.solidity_requirement != "": + req = self.solidity_requirement + elif contract and len(contract.errors) > 0: + req = ">=0.8.4 <0.9.0" + else: + req = ">=0.6.0 <0.9.0" + self._p_str(f"pragma solidity {req};") + self._p_nl() + + if self.abicoder_v2: + self._p_str("pragma experimental ABIEncoderV2;") + self._p_nl() + + self._p_nl() + + def p_errors(self, errors: list[Error]): + for error in errors: + self._p_line(lambda: self.p_error(error)) + + def p_error(self, error: Error): + self._p_comment(error.description, doc=True) + self._p_line(lambda: self._p_str(error.declaration)) + + def p_events(self, events: list[Event]): + for event in events: + self._p_line(lambda: self.p_event(event)) + + def p_event(self, event: Event): + self._p_comment(event.description, doc=True) + self._p_line(lambda: self._p_str(event.declaration)) + + def p_enums(self, enums: list[Enum]): + for enum in enums: + self._p_line(lambda: self.p_enum(enum)) + + def p_enum(self, enum: Enum): + self._p_comment(enum.description, doc=True) + self._p_line(lambda: self._p_str(f"enum {enum.name} {{")) + self._with_indent(lambda: self.p_enum_variants(enum.variants)) + self._p_line(lambda: self._p_str("}")) + + def p_enum_variants(self, variants: list[EnumVariant]): + for i, variant in enumerate(variants): + self._p_indent() + self._p_comment(variant.description) + + self._p_indent() + self._p_str(variant.name) + if i < len(variants) - 1: + self._p_str(",") + self._p_nl() + + def p_structs(self, structs: list[Struct]): + for struct in structs: + self._p_line(lambda: self.p_struct(struct)) + + def p_struct(self, struct: Struct): + self._p_comment(struct.description, doc=True) + self._p_line(lambda: self._p_str(f"struct {struct.name} {{")) + self._with_indent(lambda: self.p_struct_fields(struct.fields)) + self._p_line(lambda: self._p_str("}")) + + def p_struct_fields(self, fields: list[StructField]): + for field in fields: + self._p_line(lambda: self.p_struct_field(field)) + + def p_struct_field(self, field: StructField): + self._p_comment(field.description) + self._p_indented(lambda: self._p_str(f"{field.ty} {field.name};")) + + def p_functions(self, cheatcodes: list[Cheatcode]): + for cheatcode in cheatcodes: + self._p_line(lambda: self.p_function(cheatcode.func)) + + def p_function(self, func: Function): + self._p_comment(func.description, doc=True) + self._p_line(lambda: self._p_str(func.declaration)) + + def _p_comment(self, s: str, doc: bool = False): + s = s.strip() + if s == "": + return + + s = map(lambda line: line.lstrip(), s.split("\n")) + if self.block_doc_style: + self._p_str("/*") + if doc: + self._p_str("*") + self._p_nl() + for line in s: + self._p_indent() + self._p_str(" ") + if doc: + self._p_str("* ") + self._p_str(line) + self._p_nl() + self._p_indent() + self._p_str(" */") + self._p_nl() + else: + first_line = True + for line in s: + if not first_line: + self._p_indent() + first_line = False + + if doc: + self._p_str("/// ") + else: + self._p_str("// ") + self._p_str(line) + self._p_nl() + + def _with_indent(self, f: VoidFn): + self._inc_indent() + f() + self._dec_indent() + + def _p_line(self, f: VoidFn): + self._p_indent() + f() + self._p_nl() + + def _p_indented(self, f: VoidFn): + self._p_indent() + f() + + def _p_indent(self): + for _ in range(self.indent_level): + self._p_str(self._indent_str) + + def _p_nl(self): + self._p_str(self.nl_str) + + def _p_str(self, txt: str): + self.buffer += txt + + def _inc_indent(self): + self.indent_level += 1 + + def _dec_indent(self): + self.indent_level -= 1 + + +if __name__ == "__main__": + main() diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Base.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Base.sol new file mode 100644 index 0000000..851ac0c --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Script.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Script.sol new file mode 100644 index 0000000..94e75f6 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdAssertions.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdAssertions.sol new file mode 100644 index 0000000..a6d0f13 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdAssertions.sol @@ -0,0 +1,669 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; +pragma experimental ABIEncoderV2; + +import {Vm} from "./Vm.sol"; + +abstract contract StdAssertions { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + event log(string); + event logs(bytes); + + event log_address(address); + event log_bytes32(bytes32); + event log_int(int256); + event log_uint(uint256); + 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, int256 val, uint256 decimals); + event log_named_decimal_uint(string key, uint256 val, uint256 decimals); + event log_named_int(string key, int256 val); + event log_named_uint(string key, uint256 val); + event log_named_bytes(string key, bytes val); + event log_named_string(string key, string val); + + 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); + + bool private _failed; + + function failed() public view returns (bool) { + if (_failed) { + return _failed; + } else { + return vm.load(address(vm), bytes32("failed")) != bytes32(0); + } + } + + function fail() internal virtual { + vm.store(address(vm), bytes32("failed"), bytes32(uint256(1))); + _failed = true; + } + + function assertTrue(bool data) internal pure virtual { + vm.assertTrue(data); + } + + function assertTrue(bool data, string memory err) internal pure virtual { + vm.assertTrue(data, err); + } + + function assertFalse(bool data) internal pure virtual { + vm.assertFalse(data); + } + + function assertFalse(bool data, string memory err) internal pure virtual { + vm.assertFalse(data, err); + } + + function assertEq(bool left, bool right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bool left, bool right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(uint256 left, uint256 right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(uint256 left, uint256 right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertEqDecimal(left, right, decimals); + } + + function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertEqDecimal(left, right, decimals, err); + } + + function assertEq(int256 left, int256 right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(int256 left, int256 right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEqDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertEqDecimal(left, right, decimals); + } + + function assertEqDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertEqDecimal(left, right, decimals, err); + } + + function assertEq(address left, address right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(address left, address right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(bytes32 left, bytes32 right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bytes32 left, bytes32 right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq32(bytes32 left, bytes32 right) internal pure virtual { + assertEq(left, right); + } + + function assertEq32(bytes32 left, bytes32 right, string memory err) internal pure virtual { + assertEq(left, right, err); + } + + function assertEq(string memory left, string memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(string memory left, string memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(bytes memory left, bytes memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bytes memory left, bytes memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(bool[] memory left, bool[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bool[] memory left, bool[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(uint256[] memory left, uint256[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(uint256[] memory left, uint256[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(int256[] memory left, int256[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(int256[] memory left, int256[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(address[] memory left, address[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(address[] memory left, address[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(bytes32[] memory left, bytes32[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bytes32[] memory left, bytes32[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(string[] memory left, string[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(string[] memory left, string[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + function assertEq(bytes[] memory left, bytes[] memory right) internal pure virtual { + vm.assertEq(left, right); + } + + function assertEq(bytes[] memory left, bytes[] memory right, string memory err) internal pure virtual { + vm.assertEq(left, right, err); + } + + // Legacy helper + function assertEqUint(uint256 left, uint256 right) internal pure virtual { + assertEq(left, right); + } + + function assertNotEq(bool left, bool right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bool left, bool right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(uint256 left, uint256 right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(uint256 left, uint256 right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertNotEqDecimal(left, right, decimals); + } + + function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) + internal + pure + virtual + { + vm.assertNotEqDecimal(left, right, decimals, err); + } + + function assertNotEq(int256 left, int256 right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(int256 left, int256 right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertNotEqDecimal(left, right, decimals); + } + + function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertNotEqDecimal(left, right, decimals, err); + } + + function assertNotEq(address left, address right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(address left, address right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(bytes32 left, bytes32 right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bytes32 left, bytes32 right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq32(bytes32 left, bytes32 right) internal pure virtual { + assertNotEq(left, right); + } + + function assertNotEq32(bytes32 left, bytes32 right, string memory err) internal pure virtual { + assertNotEq(left, right, err); + } + + function assertNotEq(string memory left, string memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(string memory left, string memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(bytes memory left, bytes memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bytes memory left, bytes memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(bool[] memory left, bool[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bool[] memory left, bool[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(uint256[] memory left, uint256[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(uint256[] memory left, uint256[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(int256[] memory left, int256[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(int256[] memory left, int256[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(address[] memory left, address[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(address[] memory left, address[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(bytes32[] memory left, bytes32[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bytes32[] memory left, bytes32[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(string[] memory left, string[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(string[] memory left, string[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertNotEq(bytes[] memory left, bytes[] memory right) internal pure virtual { + vm.assertNotEq(left, right); + } + + function assertNotEq(bytes[] memory left, bytes[] memory right, string memory err) internal pure virtual { + vm.assertNotEq(left, right, err); + } + + function assertLt(uint256 left, uint256 right) internal pure virtual { + vm.assertLt(left, right); + } + + function assertLt(uint256 left, uint256 right, string memory err) internal pure virtual { + vm.assertLt(left, right, err); + } + + function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertLtDecimal(left, right, decimals); + } + + function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertLtDecimal(left, right, decimals, err); + } + + function assertLt(int256 left, int256 right) internal pure virtual { + vm.assertLt(left, right); + } + + function assertLt(int256 left, int256 right, string memory err) internal pure virtual { + vm.assertLt(left, right, err); + } + + function assertLtDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertLtDecimal(left, right, decimals); + } + + function assertLtDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertLtDecimal(left, right, decimals, err); + } + + function assertGt(uint256 left, uint256 right) internal pure virtual { + vm.assertGt(left, right); + } + + function assertGt(uint256 left, uint256 right, string memory err) internal pure virtual { + vm.assertGt(left, right, err); + } + + function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertGtDecimal(left, right, decimals); + } + + function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertGtDecimal(left, right, decimals, err); + } + + function assertGt(int256 left, int256 right) internal pure virtual { + vm.assertGt(left, right); + } + + function assertGt(int256 left, int256 right, string memory err) internal pure virtual { + vm.assertGt(left, right, err); + } + + function assertGtDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertGtDecimal(left, right, decimals); + } + + function assertGtDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertGtDecimal(left, right, decimals, err); + } + + function assertLe(uint256 left, uint256 right) internal pure virtual { + vm.assertLe(left, right); + } + + function assertLe(uint256 left, uint256 right, string memory err) internal pure virtual { + vm.assertLe(left, right, err); + } + + function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertLeDecimal(left, right, decimals); + } + + function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertLeDecimal(left, right, decimals, err); + } + + function assertLe(int256 left, int256 right) internal pure virtual { + vm.assertLe(left, right); + } + + function assertLe(int256 left, int256 right, string memory err) internal pure virtual { + vm.assertLe(left, right, err); + } + + function assertLeDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertLeDecimal(left, right, decimals); + } + + function assertLeDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertLeDecimal(left, right, decimals, err); + } + + function assertGe(uint256 left, uint256 right) internal pure virtual { + vm.assertGe(left, right); + } + + function assertGe(uint256 left, uint256 right, string memory err) internal pure virtual { + vm.assertGe(left, right, err); + } + + function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { + vm.assertGeDecimal(left, right, decimals); + } + + function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertGeDecimal(left, right, decimals, err); + } + + function assertGe(int256 left, int256 right) internal pure virtual { + vm.assertGe(left, right); + } + + function assertGe(int256 left, int256 right, string memory err) internal pure virtual { + vm.assertGe(left, right, err); + } + + function assertGeDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { + vm.assertGeDecimal(left, right, decimals); + } + + function assertGeDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { + vm.assertGeDecimal(left, right, decimals, err); + } + + function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) internal pure virtual { + vm.assertApproxEqAbs(left, right, maxDelta); + } + + function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string memory err) + internal + pure + virtual + { + vm.assertApproxEqAbs(left, right, maxDelta, err); + } + + function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) + internal + pure + virtual + { + vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals); + } + + function assertApproxEqAbsDecimal( + uint256 left, + uint256 right, + uint256 maxDelta, + uint256 decimals, + string memory err + ) internal pure virtual { + vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals, err); + } + + function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) internal pure virtual { + vm.assertApproxEqAbs(left, right, maxDelta); + } + + function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string memory err) internal pure virtual { + vm.assertApproxEqAbs(left, right, maxDelta, err); + } + + function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) + internal + pure + virtual + { + vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals); + } + + function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals, string memory err) + internal + pure + virtual + { + vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals, err); + } + + function assertApproxEqRel( + uint256 left, + uint256 right, + uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% + ) internal pure virtual { + vm.assertApproxEqRel(left, right, maxPercentDelta); + } + + function assertApproxEqRel( + uint256 left, + uint256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + string memory err + ) internal pure virtual { + vm.assertApproxEqRel(left, right, maxPercentDelta, err); + } + + function assertApproxEqRelDecimal( + uint256 left, + uint256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals + ) internal pure virtual { + vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals); + } + + function assertApproxEqRelDecimal( + uint256 left, + uint256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals, + string memory err + ) internal pure virtual { + vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals, err); + } + + function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) internal pure virtual { + vm.assertApproxEqRel(left, right, maxPercentDelta); + } + + function assertApproxEqRel( + int256 left, + int256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + string memory err + ) internal pure virtual { + vm.assertApproxEqRel(left, right, maxPercentDelta, err); + } + + function assertApproxEqRelDecimal( + int256 left, + int256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals + ) internal pure virtual { + vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals); + } + + function assertApproxEqRelDecimal( + int256 left, + int256 right, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals, + string memory err + ) internal pure virtual { + vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals, err); + } + + // Inhertied from DSTest, not used but kept for backwards-compatibility + function checkEq0(bytes memory left, bytes memory right) internal pure returns (bool) { + return keccak256(left) == keccak256(right); + } + + function assertEq0(bytes memory left, bytes memory right) internal pure virtual { + assertEq(left, right); + } + + function assertEq0(bytes memory left, bytes memory right, string memory err) internal pure virtual { + assertEq(left, right, err); + } + + function assertNotEq0(bytes memory left, bytes memory right) internal pure virtual { + assertNotEq(left, right); + } + + function assertNotEq0(bytes memory left, bytes memory right, string memory err) internal pure virtual { + assertNotEq(left, right, err); + } + + 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); + revert("assertion failed"); + } + + 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); + revert("assertion failed"); + } + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdChains.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdChains.sol new file mode 100644 index 0000000..27e1bf2 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdChains.sol @@ -0,0 +1,250 @@ +// 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 + 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) { + 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' + // The upstream error thrown by forge for failing cheats changed so we check both the old and new versions + bytes memory oldNotFoundError = + abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias))); + bytes memory newNotFoundError = abi.encodeWithSignature( + "CheatcodeError(string)", string(abi.encodePacked("invalid rpc url: ", chainAlias)) + ); + bytes32 errHash = keccak256(err); + if ( + (errHash != keccak256(oldNotFoundError) && errHash != keccak256(newNotFoundError)) + || 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://eth-mainnet.alchemyapi.io/v2/pwc5rmJhrdoaSEfimoKEmsvOjKSmPDrP") + ); + 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")); + setChainWithDefaultRpcUrl("fraxtal", ChainData("Fraxtal", 252, "https://rpc.frax.com")); + setChainWithDefaultRpcUrl("fraxtal_testnet", ChainData("Fraxtal Testnet", 2522, "https://rpc.testnet.frax.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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdCheats.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdCheats.sol new file mode 100644 index 0000000..f293313 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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_StdCheats("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_StdCheats(string memory p0) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string)", p0)); + status; + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdError.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdError.sol new file mode 100644 index 0000000..a302191 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdInvariant.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdInvariant.sol new file mode 100644 index 0000000..bcd9ac0 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdJson.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdJson.sol new file mode 100644 index 0000000..6dbde83 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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(""); +// json.readUint(""); +// ``` +// To write: +// ``` +// using stdJson for string; +// string memory json = "json"; +// json.serialize("a", uint256(123)); +// string memory semiFinal = json.serialize("b", string("test")); +// string memory finalJson = json.serialize("c", semiFinal); +// finalJson.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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdMath.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdMath.sol new file mode 100644 index 0000000..459523b --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStorage.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStorage.sol new file mode 100644 index 0000000..ffd668c --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStorage.sol @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {Vm} from "./Vm.sol"; + +struct FindData { + uint256 slot; + uint256 offsetLeft; + uint256 offsetRight; + bool found; +} + +struct StdStorage { + mapping(address => mapping(bytes4 => mapping(bytes32 => FindData))) finds; + bytes32[] _keys; + bytes4 _sig; + uint256 _depth; + address _target; + bytes32 _set; + bool _enable_packed_slots; + bytes _calldata; +} + +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"))))); + uint256 constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return bytes4(keccak256(bytes(sigStr))); + } + + function getCallParams(StdStorage storage self) internal view returns (bytes memory) { + if (self._calldata.length == 0) { + return flatten(self._keys); + } else { + return self._calldata; + } + } + + // Calls target contract with configured parameters + function callTarget(StdStorage storage self) internal view returns (bool, bytes32) { + bytes memory cald = abi.encodePacked(self._sig, getCallParams(self)); + (bool success, bytes memory rdat) = self._target.staticcall(cald); + bytes32 result = bytesToBytes32(rdat, 32 * self._depth); + + return (success, result); + } + + // Tries mutating slot value to determine if the targeted value is stored in it. + // If current value is 0, then we are setting slot value to type(uint256).max + // Otherwise, we set it to 0. That way, return value should always be affected. + function checkSlotMutatesCall(StdStorage storage self, bytes32 slot) internal returns (bool) { + bytes32 prevSlotValue = vm.load(self._target, slot); + (bool success, bytes32 prevReturnValue) = callTarget(self); + + bytes32 testVal = prevReturnValue == bytes32(0) ? bytes32(UINT256_MAX) : bytes32(0); + vm.store(self._target, slot, testVal); + + (, bytes32 newReturnValue) = callTarget(self); + + vm.store(self._target, slot, prevSlotValue); + + return (success && (prevReturnValue != newReturnValue)); + } + + // Tries setting one of the bits in slot to 1 until return value changes. + // Index of resulted bit is an offset packed slot has from left/right side + function findOffset(StdStorage storage self, bytes32 slot, bool left) internal returns (bool, uint256) { + for (uint256 offset = 0; offset < 256; offset++) { + uint256 valueToPut = left ? (1 << (255 - offset)) : (1 << offset); + vm.store(self._target, slot, bytes32(valueToPut)); + + (bool success, bytes32 data) = callTarget(self); + + if (success && (uint256(data) > 0)) { + return (true, offset); + } + } + return (false, 0); + } + + function findOffsets(StdStorage storage self, bytes32 slot) internal returns (bool, uint256, uint256) { + bytes32 prevSlotValue = vm.load(self._target, slot); + + (bool foundLeft, uint256 offsetLeft) = findOffset(self, slot, true); + (bool foundRight, uint256 offsetRight) = findOffset(self, slot, false); + + // `findOffset` may mutate slot value, so we are setting it to initial value + vm.store(self._target, slot, prevSlotValue); + return (foundLeft && foundRight, offsetLeft, offsetRight); + } + + function find(StdStorage storage self) internal returns (FindData storage) { + return find(self, true); + } + + /// @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, bool _clear) internal returns (FindData storage) { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes memory params = getCallParams(self); + + // calldata to test against + if (self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found) { + if (_clear) { + clear(self); + } + return self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))]; + } + vm.record(); + (, bytes32 callResult) = callTarget(self); + (bytes32[] memory reads,) = vm.accesses(address(who)); + + if (reads.length == 0) { + revert("stdStorage find(StdStorage): No storage use detected for target."); + } else { + 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 (!checkSlotMutatesCall(self, reads[i])) { + continue; + } + + (uint256 offsetLeft, uint256 offsetRight) = (0, 0); + + if (self._enable_packed_slots) { + bool found; + (found, offsetLeft, offsetRight) = findOffsets(self, reads[i]); + if (!found) { + continue; + } + } + + // Check that value between found offsets is equal to the current call result + uint256 curVal = (uint256(prev) & getMaskByOffsets(offsetLeft, offsetRight)) >> offsetRight; + + if (uint256(callResult) != curVal) { + continue; + } + + emit SlotFound(who, fsig, keccak256(abi.encodePacked(params, field_depth)), uint256(reads[i])); + self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))] = + FindData(uint256(reads[i]), offsetLeft, offsetRight, true); + break; + } + } + + require( + self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found, + "stdStorage find(StdStorage): Slot(s) not found." + ); + + if (_clear) { + clear(self); + } + return self.finds[who][fsig][keccak256(abi.encodePacked(params, 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_calldata(StdStorage storage self, bytes memory _calldata) internal returns (StdStorage storage) { + self._calldata = _calldata; + 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 enable_packed_slots(StdStorage storage self) internal returns (StdStorage storage) { + self._enable_packed_slots = true; + 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) { + FindData storage data = find(self, false); + uint256 mask = getMaskByOffsets(data.offsetLeft, data.offsetRight); + uint256 value = (uint256(vm.load(self._target, bytes32(data.slot))) & mask) >> data.offsetRight; + clear(self); + return abi.encode(value); + } + + 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, true).slot - 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, true).slot - 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; + } + + function clear(StdStorage storage self) internal { + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + delete self._enable_packed_slots; + delete self._calldata; + } + + // Returns mask which contains non-zero bits for values between `offsetLeft` and `offsetRight` + // (slotValue & mask) >> offsetRight will be the value of the given packed variable + function getMaskByOffsets(uint256 offsetLeft, uint256 offsetRight) internal pure returns (uint256 mask) { + // mask = ((1 << (256 - (offsetRight + offsetLeft))) - 1) << offsetRight; + // using assembly because (1 << 256) causes overflow + assembly { + mask := shl(offsetRight, sub(shl(sub(256, add(offsetRight, offsetLeft)), 1), 1)) + } + } + + // Returns slot value with updated packed variable. + function getUpdatedSlotValue(bytes32 curValue, uint256 varValue, uint256 offsetLeft, uint256 offsetRight) + internal + pure + returns (bytes32 newValue) + { + return bytes32((uint256(curValue) & ~getMaskByOffsets(offsetLeft, offsetRight)) | (varValue << offsetRight)); + } +} + +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 find(self, true); + } + + function find(StdStorage storage self, bool _clear) internal returns (uint256) { + return stdStorageSafe.find(self, _clear).slot; + } + + 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 with_calldata(StdStorage storage self, bytes memory _calldata) internal returns (StdStorage storage) { + return stdStorageSafe.with_calldata(self, _calldata); + } + + function enable_packed_slots(StdStorage storage self) internal returns (StdStorage storage) { + return stdStorageSafe.enable_packed_slots(self); + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + return stdStorageSafe.depth(self, _depth); + } + + function clear(StdStorage storage self) internal { + stdStorageSafe.clear(self); + } + + 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; + bytes memory params = stdStorageSafe.getCallParams(self); + + if (!self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found) { + find(self, false); + } + FindData storage data = self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))]; + if ((data.offsetLeft + data.offsetRight) > 0) { + uint256 maxVal = 2 ** (256 - (data.offsetLeft + data.offsetRight)); + require( + uint256(set) < maxVal, + string( + abi.encodePacked( + "stdStorage find(StdStorage): Packed slot. We can't fit value greater than ", + vm.toString(maxVal) + ) + ) + ); + } + bytes32 curVal = vm.load(who, bytes32(data.slot)); + bytes32 valToSet = stdStorageSafe.getUpdatedSlotValue(curVal, uint256(set), data.offsetLeft, data.offsetRight); + + vm.store(who, bytes32(data.slot), valToSet); + + (bool success, bytes32 callResult) = stdStorageSafe.callTarget(self); + + if (!success || callResult != set) { + vm.store(who, bytes32(data.slot), curVal); + revert("stdStorage find(StdStorage): Failed to write value."); + } + clear(self); + } + + 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); + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStyle.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStyle.sol new file mode 100644 index 0000000..d371e0c --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdToml.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdToml.sol new file mode 100644 index 0000000..ef88db6 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdToml.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 TOML files +// To parse: +// ``` +// using stdToml for string; +// string memory toml = vm.readFile(""); +// toml.readUint(""); +// ``` +// To write: +// ``` +// using stdToml for string; +// string memory json = "json"; +// json.serialize("a", uint256(123)); +// string memory semiFinal = json.serialize("b", string("test")); +// string memory finalJson = json.serialize("c", semiFinal); +// finalJson.write(""); +// ``` + +library stdToml { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function parseRaw(string memory toml, string memory key) internal pure returns (bytes memory) { + return vm.parseToml(toml, key); + } + + function readUint(string memory toml, string memory key) internal pure returns (uint256) { + return vm.parseTomlUint(toml, key); + } + + function readUintArray(string memory toml, string memory key) internal pure returns (uint256[] memory) { + return vm.parseTomlUintArray(toml, key); + } + + function readInt(string memory toml, string memory key) internal pure returns (int256) { + return vm.parseTomlInt(toml, key); + } + + function readIntArray(string memory toml, string memory key) internal pure returns (int256[] memory) { + return vm.parseTomlIntArray(toml, key); + } + + function readBytes32(string memory toml, string memory key) internal pure returns (bytes32) { + return vm.parseTomlBytes32(toml, key); + } + + function readBytes32Array(string memory toml, string memory key) internal pure returns (bytes32[] memory) { + return vm.parseTomlBytes32Array(toml, key); + } + + function readString(string memory toml, string memory key) internal pure returns (string memory) { + return vm.parseTomlString(toml, key); + } + + function readStringArray(string memory toml, string memory key) internal pure returns (string[] memory) { + return vm.parseTomlStringArray(toml, key); + } + + function readAddress(string memory toml, string memory key) internal pure returns (address) { + return vm.parseTomlAddress(toml, key); + } + + function readAddressArray(string memory toml, string memory key) internal pure returns (address[] memory) { + return vm.parseTomlAddressArray(toml, key); + } + + function readBool(string memory toml, string memory key) internal pure returns (bool) { + return vm.parseTomlBool(toml, key); + } + + function readBoolArray(string memory toml, string memory key) internal pure returns (bool[] memory) { + return vm.parseTomlBoolArray(toml, key); + } + + function readBytes(string memory toml, string memory key) internal pure returns (bytes memory) { + return vm.parseTomlBytes(toml, key); + } + + function readBytesArray(string memory toml, string memory key) internal pure returns (bytes[] memory) { + return vm.parseTomlBytesArray(toml, 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.writeToml(jsonKey, path); + } + + function write(string memory jsonKey, string memory path, string memory valueKey) internal { + vm.writeToml(jsonKey, path, valueKey); + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdUtils.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdUtils.sol new file mode 100644 index 0000000..0f61305 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdUtils.sol @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {IMulticall3} from "./interfaces/IMulticall3.sol"; +import {MockERC20} from "./mocks/MockERC20.sol"; +import {MockERC721} from "./mocks/MockERC721.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 pure virtual returns (uint256 result) { + result = _bound(x, min, max); + console2_log_StdUtils("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 pure virtual returns (int256 result) { + result = _bound(x, min, max); + console2_log_StdUtils("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) { + console2_log_StdUtils("computeCreateAddress is deprecated. Please use vm.computeCreateAddress instead."); + return vm.computeCreateAddress(deployer, nonce); + } + + function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) + internal + pure + virtual + returns (address) + { + console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead."); + return vm.computeCreate2Address(salt, initcodeHash, deployer); + } + + /// @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) { + console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead."); + return vm.computeCreate2Address(salt, initCodeHash); + } + + /// @dev returns an initialized mock ERC20 contract + function deployMockERC20(string memory name, string memory symbol, uint8 decimals) + internal + returns (MockERC20 mock) + { + mock = new MockERC20(); + mock.initialize(name, symbol, decimals); + } + + /// @dev returns an initialized mock ERC721 contract + function deployMockERC721(string memory name, string memory symbol) internal returns (MockERC721 mock) { + mock = new MockERC721(); + mock.initialize(name, symbol); + } + + /// @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))); + } + + // This section is used to prevent the compilation of console, which shortens the compilation time when console is + // not used elsewhere. We also trick the compiler into letting us make the console log methods as `pure` to avoid + // any breaking changes to function signatures. + 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 = CONSOLE2_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function console2_log_StdUtils(string memory p0) private pure { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function console2_log_StdUtils(string memory p0, uint256 p1) private pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + } + + function console2_log_StdUtils(string memory p0, string memory p1) private pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Test.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Test.sol new file mode 100644 index 0000000..5ff60ea --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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 {stdToml} from "./StdToml.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {Vm} from "./Vm.sol"; + +// 📦 BOILERPLATE +import {TestBase} from "./Base.sol"; + +// ⭐️ TEST +abstract contract Test is TestBase, StdAssertions, StdChains, StdCheats, StdInvariant, StdUtils { + // Note: IS_TEST() must return true. + bool public IS_TEST = true; +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Vm.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Vm.sol new file mode 100644 index 0000000..313d020 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Vm.sol @@ -0,0 +1,1638 @@ +// Automatically @generated by scripts/vm.py. Do not modify manually. + +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity >=0.6.2 <0.9.0; +pragma experimental ABIEncoderV2; + +/// 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 { + /// A modification applied to either `msg.sender` or `tx.origin`. Returned by `readCallers`. + enum CallerMode { + // No caller modification is currently active. + None, + // A one time broadcast triggered by a `vm.broadcast()` call is currently active. + Broadcast, + // A recurrent broadcast triggered by a `vm.startBroadcast()` call is currently active. + RecurrentBroadcast, + // A one time prank triggered by a `vm.prank()` call is currently active. + Prank, + // A recurrent prank triggered by a `vm.startPrank()` call is currently active. + RecurrentPrank + } + + /// The kind of account access that occurred. + enum AccountAccessKind { + // The account was called. + Call, + // The account was called via delegatecall. + DelegateCall, + // The account was called via callcode. + CallCode, + // The account was called via staticcall. + StaticCall, + // The account was created. + Create, + // The account was selfdestructed. + SelfDestruct, + // Synthetic access indicating the current context has resumed after a previous sub-context (AccountAccess). + Resume, + // The account's balance was read. + Balance, + // The account's codesize was read. + Extcodesize, + // The account's codehash was read. + Extcodehash, + // The account's code was copied. + Extcodecopy + } + + /// An Ethereum log. Returned by `getRecordedLogs`. + struct Log { + // The topics of the log, including the signature, if any. + bytes32[] topics; + // The raw data of the log. + bytes data; + // The address of the log's emitter. + address emitter; + } + + /// An RPC URL and its alias. Returned by `rpcUrlStructs`. + struct Rpc { + // The alias of the RPC URL. + string key; + // The RPC URL. + string url; + } + + /// An RPC log object. Returned by `eth_getLogs`. + struct EthGetLogs { + // The address of the log's emitter. + address emitter; + // The topics of the log, including the signature, if any. + bytes32[] topics; + // The raw data of the log. + bytes data; + // The block hash. + bytes32 blockHash; + // The block number. + uint64 blockNumber; + // The transaction hash. + bytes32 transactionHash; + // The transaction index in the block. + uint64 transactionIndex; + // The log index. + uint256 logIndex; + // Whether the log was removed. + bool removed; + } + + /// A single entry in a directory listing. Returned by `readDir`. + struct DirEntry { + // The error message, if any. + string errorMessage; + // The path of the entry. + string path; + // The depth of the entry. + uint64 depth; + // Whether the entry is a directory. + bool isDir; + // Whether the entry is a symlink. + bool isSymlink; + } + + /// Metadata information about a file. + /// This structure is returned from the `fsMetadata` function and represents known + /// metadata about a file such as its permissions, size, modification + /// times, etc. + struct FsMetadata { + // True if this metadata is for a directory. + bool isDir; + // True if this metadata is for a symlink. + bool isSymlink; + // The size of the file, in bytes, this metadata is for. + uint256 length; + // True if this metadata is for a readonly (unwritable) file. + bool readOnly; + // The last modification time listed in this metadata. + uint256 modified; + // The last access time of this metadata. + uint256 accessed; + // The creation time listed in this metadata. + uint256 created; + } + + /// A wallet with a public and private key. + struct Wallet { + // The wallet's address. + address addr; + // The wallet's public key `X`. + uint256 publicKeyX; + // The wallet's public key `Y`. + uint256 publicKeyY; + // The wallet's private key. + uint256 privateKey; + } + + /// The result of a `tryFfi` call. + struct FfiResult { + // The exit code of the call. + int32 exitCode; + // The optionally hex-decoded `stdout` data. + bytes stdout; + // The `stderr` data. + bytes stderr; + } + + /// Information on the chain and fork. + struct ChainInfo { + // The fork identifier. Set to zero if no fork is active. + uint256 forkId; + // The chain ID of the current fork. + uint256 chainId; + } + + /// The result of a `stopAndReturnStateDiff` call. + struct AccountAccess { + // The chain and fork the access occurred. + ChainInfo chainInfo; + // The kind of account access that determines what the account is. + // If kind is Call, DelegateCall, StaticCall or CallCode, then the account is the callee. + // If kind is Create, then the account is the newly created account. + // If kind is SelfDestruct, then the account is the selfdestruct recipient. + // If kind is a Resume, then account represents a account context that has resumed. + AccountAccessKind kind; + // The account that was accessed. + // It's either the account created, callee or a selfdestruct recipient for CREATE, CALL or SELFDESTRUCT. + address account; + // What accessed the account. + address accessor; + // If the account was initialized or empty prior to the access. + // An account is considered initialized if it has code, a + // non-zero nonce, or a non-zero balance. + bool initialized; + // The previous balance of the accessed account. + uint256 oldBalance; + // The potential new balance of the accessed account. + // That is, all balance changes are recorded here, even if reverts occurred. + uint256 newBalance; + // Code of the account deployed by CREATE. + bytes deployedCode; + // Value passed along with the account access + uint256 value; + // Input data provided to the CREATE or CALL + bytes data; + // If this access reverted in either the current or parent context. + bool reverted; + // An ordered list of storage accesses made during an account access operation. + StorageAccess[] storageAccesses; + // Call depth traversed during the recording of state differences + uint64 depth; + } + + /// The storage accessed during an `AccountAccess`. + struct StorageAccess { + // The account whose storage was accessed. + address account; + // The slot that was accessed. + bytes32 slot; + // If the access was a write. + bool isWrite; + // The previous value of the slot. + bytes32 previousValue; + // The new value of the slot. + bytes32 newValue; + // If the access was reverted. + bool reverted; + } + + // ======== Environment ======== + + /// Gets the environment variable `name` and parses it as `address`. + /// Reverts if the variable was not found or could not be parsed. + function envAddress(string calldata name) external view returns (address value); + + /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value); + + /// Gets the environment variable `name` and parses it as `bool`. + /// Reverts if the variable was not found or could not be parsed. + function envBool(string calldata name) external view returns (bool value); + + /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value); + + /// Gets the environment variable `name` and parses it as `bytes32`. + /// Reverts if the variable was not found or could not be parsed. + function envBytes32(string calldata name) external view returns (bytes32 value); + + /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value); + + /// Gets the environment variable `name` and parses it as `bytes`. + /// Reverts if the variable was not found or could not be parsed. + function envBytes(string calldata name) external view returns (bytes memory value); + + /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value); + + /// Gets the environment variable `name` and parses it as `int256`. + /// Reverts if the variable was not found or could not be parsed. + function envInt(string calldata name) external view returns (int256 value); + + /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value); + + /// Gets the environment variable `name` and parses it as `bool`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, bool defaultValue) external view returns (bool value); + + /// Gets the environment variable `name` and parses it as `uint256`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, uint256 defaultValue) external view returns (uint256 value); + + /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, address[] calldata defaultValue) + external + view + returns (address[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue) + external + view + returns (bytes32[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, string[] calldata defaultValue) + external + view + returns (string[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue) + external + view + returns (bytes[] memory value); + + /// Gets the environment variable `name` and parses it as `int256`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, int256 defaultValue) external view returns (int256 value); + + /// Gets the environment variable `name` and parses it as `address`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, address defaultValue) external view returns (address value); + + /// Gets the environment variable `name` and parses it as `bytes32`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, bytes32 defaultValue) external view returns (bytes32 value); + + /// Gets the environment variable `name` and parses it as `string`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata defaultValue) external view returns (string memory value); + + /// Gets the environment variable `name` and parses it as `bytes`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, bytes calldata defaultValue) external view returns (bytes memory value); + + /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue) + external + view + returns (bool[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue) + external + view + returns (uint256[] memory value); + + /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`. + /// Reverts if the variable could not be parsed. + /// Returns `defaultValue` if the variable was not found. + function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue) + external + view + returns (int256[] memory value); + + /// Gets the environment variable `name` and parses it as `string`. + /// Reverts if the variable was not found or could not be parsed. + function envString(string calldata name) external view returns (string memory value); + + /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envString(string calldata name, string calldata delim) external view returns (string[] memory value); + + /// Gets the environment variable `name` and parses it as `uint256`. + /// Reverts if the variable was not found or could not be parsed. + function envUint(string calldata name) external view returns (uint256 value); + + /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`. + /// Reverts if the variable was not found or could not be parsed. + function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value); + + /// Sets environment variables. + function setEnv(string calldata name, string calldata value) external; + + // ======== EVM ======== + + /// 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); + + /// Gets the address for a given private key. + function addr(uint256 privateKey) external pure returns (address keyAddr); + + /// Gets all the logs according to specified filter. + function eth_getLogs(uint256 fromBlock, uint256 toBlock, address target, bytes32[] calldata topics) + external + returns (EthGetLogs[] memory logs); + + /// Gets the current `block.number`. + /// You should use this instead of `block.number` if you use `vm.roll`, as `block.number` is assumed to be constant across a transaction, + /// and as a result will get optimized out by the compiler. + /// See https://github.com/foundry-rs/foundry/issues/6180 + function getBlockNumber() external view returns (uint256 height); + + /// Gets the current `block.timestamp`. + /// You should use this instead of `block.timestamp` if you use `vm.warp`, as `block.timestamp` is assumed to be constant across a transaction, + /// and as a result will get optimized out by the compiler. + /// See https://github.com/foundry-rs/foundry/issues/6180 + function getBlockTimestamp() external view returns (uint256 timestamp); + + /// 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); + + /// 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 nonce of an account. + function getNonce(address account) external view returns (uint64 nonce); + + /// Gets all the recorded logs. + function getRecordedLogs() external returns (Log[] memory logs); + + /// Loads a storage slot from an address. + function load(address target, bytes32 slot) external view returns (bytes32 data); + + /// Pauses gas metering (i.e. gas usage is not counted). Noop if already paused. + function pauseGasMetering() external; + + /// Records all storage reads and writes. + function record() external; + + /// Record all the transaction logs. + function recordLogs() external; + + /// Resumes gas metering (i.e. gas usage is counted again). Noop if already on. + function resumeGasMetering() external; + + /// Performs an Ethereum JSON-RPC request to the current fork URL. + function rpc(string calldata method, string calldata params) external returns (bytes memory data); + + /// Signs `digest` with `privateKey` using the secp256r1 curve. + function signP256(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 s); + + /// Signs `digest` with `privateKey` using the secp256k1 curve. + function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + + /// Starts recording all map SSTOREs for later retrieval. + function startMappingRecording() external; + + /// Record all account accesses as part of CREATE, CALL or SELFDESTRUCT opcodes in order, + /// along with the context of the calls + function startStateDiffRecording() external; + + /// Returns an ordered array of all account accesses from a `vm.startStateDiffRecording` session. + function stopAndReturnStateDiff() external returns (AccountAccess[] memory accountAccesses); + + /// Stops recording all map SSTOREs for later retrieval and clears the recorded data. + function stopMappingRecording() external; + + // ======== Filesystem ======== + + /// 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; + + /// Returns true if the given path points to an existing entity, else returns false. + function exists(string calldata path) external returns (bool result); + + /// Performs a foreign function call via the terminal. + function ffi(string[] calldata commandInput) external returns (bytes memory 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); + + /// 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); + + /// 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); + + /// Reads the directory at the given path recursively, up to `maxDepth`. + /// `maxDepth` defaults to 1, meaning only the direct children of the given directory will be returned. + /// Follows symbolic links if `followLinks` is true. + function readDir(string calldata path) external view returns (DirEntry[] memory entries); + + /// See `readDir(string)`. + function readDir(string calldata path, uint64 maxDepth) external view returns (DirEntry[] memory entries); + + /// See `readDir(string)`. + 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; + + /// 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); + + /// Returns the time since unix epoch in milliseconds. + function unixTime() external returns (uint256 milliseconds); + + /// 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; + + // ======== JSON ======== + + /// Checks if `key` exists in a JSON object + /// `keyExists` is being deprecated in favor of `keyExistsJson`. It will be removed in future versions. + function keyExists(string calldata json, string calldata key) external view returns (bool); + + /// Checks if `key` exists in a JSON object. + function keyExistsJson(string calldata json, string calldata key) external view returns (bool); + + /// Parses a string of JSON data at `key` and coerces it to `address`. + function parseJsonAddress(string calldata json, string calldata key) external pure returns (address); + + /// Parses a string of JSON data at `key` and coerces it to `address[]`. + function parseJsonAddressArray(string calldata json, string calldata key) + external + pure + returns (address[] memory); + + /// Parses a string of JSON data at `key` and coerces it to `bool`. + function parseJsonBool(string calldata json, string calldata key) external pure returns (bool); + + /// Parses a string of JSON data at `key` and coerces it to `bool[]`. + function parseJsonBoolArray(string calldata json, string calldata key) external pure returns (bool[] memory); + + /// Parses a string of JSON data at `key` and coerces it to `bytes`. + function parseJsonBytes(string calldata json, string calldata key) external pure returns (bytes memory); + + /// Parses a string of JSON data at `key` and coerces it to `bytes32`. + function parseJsonBytes32(string calldata json, string calldata key) external pure returns (bytes32); + + /// Parses a string of JSON data at `key` and coerces it to `bytes32[]`. + function parseJsonBytes32Array(string calldata json, string calldata key) + external + pure + returns (bytes32[] memory); + + /// Parses a string of JSON data at `key` and coerces it to `bytes[]`. + function parseJsonBytesArray(string calldata json, string calldata key) external pure returns (bytes[] memory); + + /// Parses a string of JSON data at `key` and coerces it to `int256`. + function parseJsonInt(string calldata json, string calldata key) external pure returns (int256); + + /// Parses a string of JSON data at `key` and coerces it to `int256[]`. + function parseJsonIntArray(string calldata json, string calldata key) external pure returns (int256[] memory); + + /// Returns an array of all the keys in a JSON object. + function parseJsonKeys(string calldata json, string calldata key) external pure returns (string[] memory keys); + + /// Parses a string of JSON data at `key` and coerces it to `string`. + function parseJsonString(string calldata json, string calldata key) external pure returns (string memory); + + /// Parses a string of JSON data at `key` and coerces it to `string[]`. + function parseJsonStringArray(string calldata json, string calldata key) external pure returns (string[] memory); + + /// Parses a string of JSON data at `key` and coerces it to `uint256`. + function parseJsonUint(string calldata json, string calldata key) external pure returns (uint256); + + /// Parses a string of JSON data at `key` and coerces it to `uint256[]`. + function parseJsonUintArray(string calldata json, string calldata key) external pure returns (uint256[] memory); + + /// ABI-encodes a JSON object. + function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData); + + /// ABI-encodes a JSON object at `key`. + function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData); + + /// See `serializeJson`. + function serializeAddress(string calldata objectKey, string calldata valueKey, address value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBool(string calldata objectKey, string calldata valueKey, bool value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeInt(string calldata objectKey, string calldata valueKey, int256 value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values) + external + returns (string memory json); + + /// Serializes a key and value to a JSON object stored in-memory that can be later written to a file. + /// 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); + + /// See `serializeJson`. + function serializeString(string calldata objectKey, string calldata valueKey, string calldata value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) + external + returns (string memory json); + + /// See `serializeJson`. + function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) + external + returns (string memory json); + + /// 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; + + // ======== Scripting ======== + + /// 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; + + // ======== String ======== + + /// Parses the given `string` into an `address`. + function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue); + + /// Parses the given `string` into a `bool`. + function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue); + + /// Parses the given `string` into `bytes`. + function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue); + + /// Parses the given `string` into a `bytes32`. + function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue); + + /// Parses the given `string` into a `int256`. + function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue); + + /// Parses the given `string` into a `uint256`. + function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue); + + /// Replaces occurrences of `from` in the given `string` with `to`. + function replace(string calldata input, string calldata from, string calldata to) + external + pure + returns (string memory output); + + /// Splits the given `string` into an array of strings divided by the `delimiter`. + function split(string calldata input, string calldata delimiter) external pure returns (string[] memory outputs); + + /// Converts the given `string` value to Lowercase. + function toLowercase(string calldata input) external pure returns (string memory output); + + /// Converts the given value to a `string`. + function toString(address value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(bytes calldata value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(bytes32 value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(bool value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(uint256 value) external pure returns (string memory stringifiedValue); + + /// Converts the given value to a `string`. + function toString(int256 value) external pure returns (string memory stringifiedValue); + + /// Converts the given `string` value to Uppercase. + function toUppercase(string calldata input) external pure returns (string memory output); + + /// Trims leading and trailing whitespace from the given `string` value. + function trim(string calldata input) external pure returns (string memory output); + + // ======== Testing ======== + + /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. + /// Formats values with decimals in failure message. + function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertApproxEqAbsDecimal( + uint256 left, + uint256 right, + uint256 maxDelta, + uint256 decimals, + string calldata error + ) external pure; + + /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. + /// Formats values with decimals in failure message. + function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertApproxEqAbsDecimal( + int256 left, + int256 right, + uint256 maxDelta, + uint256 decimals, + string calldata error + ) external pure; + + /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. + function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) external pure; + + /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. + /// Includes error message into revert string on failure. + function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string calldata error) external pure; + + /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. + function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) external pure; + + /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. + /// Includes error message into revert string on failure. + function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string calldata error) external pure; + + /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Formats values with decimals in failure message. + function assertApproxEqRelDecimal(uint256 left, uint256 right, uint256 maxPercentDelta, uint256 decimals) + external + pure; + + /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertApproxEqRelDecimal( + uint256 left, + uint256 right, + uint256 maxPercentDelta, + uint256 decimals, + string calldata error + ) external pure; + + /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Formats values with decimals in failure message. + function assertApproxEqRelDecimal(int256 left, int256 right, uint256 maxPercentDelta, uint256 decimals) + external + pure; + + /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertApproxEqRelDecimal( + int256 left, + int256 right, + uint256 maxPercentDelta, + uint256 decimals, + string calldata error + ) external pure; + + /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta) external pure; + + /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Includes error message into revert string on failure. + function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta, string calldata error) + external + pure; + + /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) external pure; + + /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. + /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% + /// Includes error message into revert string on failure. + function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta, string calldata error) + external + pure; + + /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message. + function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message. + /// Includes error message into revert string on failure. + function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Asserts that two `int256` values are equal, formatting them with decimals in failure message. + function assertEqDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Asserts that two `int256` values are equal, formatting them with decimals in failure message. + /// Includes error message into revert string on failure. + function assertEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Asserts that two `bool` values are equal. + function assertEq(bool left, bool right) external pure; + + /// Asserts that two `bool` values are equal and includes error message into revert string on failure. + function assertEq(bool left, bool right, string calldata error) external pure; + + /// Asserts that two `string` values are equal. + function assertEq(string calldata left, string calldata right) external pure; + + /// Asserts that two `string` values are equal and includes error message into revert string on failure. + function assertEq(string calldata left, string calldata right, string calldata error) external pure; + + /// Asserts that two `bytes` values are equal. + function assertEq(bytes calldata left, bytes calldata right) external pure; + + /// Asserts that two `bytes` values are equal and includes error message into revert string on failure. + function assertEq(bytes calldata left, bytes calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bool` values are equal. + function assertEq(bool[] calldata left, bool[] calldata right) external pure; + + /// Asserts that two arrays of `bool` values are equal and includes error message into revert string on failure. + function assertEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `uint256 values are equal. + function assertEq(uint256[] calldata left, uint256[] calldata right) external pure; + + /// Asserts that two arrays of `uint256` values are equal and includes error message into revert string on failure. + function assertEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `int256` values are equal. + function assertEq(int256[] calldata left, int256[] calldata right) external pure; + + /// Asserts that two arrays of `int256` values are equal and includes error message into revert string on failure. + function assertEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure; + + /// Asserts that two `uint256` values are equal. + function assertEq(uint256 left, uint256 right) external pure; + + /// Asserts that two arrays of `address` values are equal. + function assertEq(address[] calldata left, address[] calldata right) external pure; + + /// Asserts that two arrays of `address` values are equal and includes error message into revert string on failure. + function assertEq(address[] calldata left, address[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bytes32` values are equal. + function assertEq(bytes32[] calldata left, bytes32[] calldata right) external pure; + + /// Asserts that two arrays of `bytes32` values are equal and includes error message into revert string on failure. + function assertEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `string` values are equal. + function assertEq(string[] calldata left, string[] calldata right) external pure; + + /// Asserts that two arrays of `string` values are equal and includes error message into revert string on failure. + function assertEq(string[] calldata left, string[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bytes` values are equal. + function assertEq(bytes[] calldata left, bytes[] calldata right) external pure; + + /// Asserts that two arrays of `bytes` values are equal and includes error message into revert string on failure. + function assertEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure; + + /// Asserts that two `uint256` values are equal and includes error message into revert string on failure. + function assertEq(uint256 left, uint256 right, string calldata error) external pure; + + /// Asserts that two `int256` values are equal. + function assertEq(int256 left, int256 right) external pure; + + /// Asserts that two `int256` values are equal and includes error message into revert string on failure. + function assertEq(int256 left, int256 right, string calldata error) external pure; + + /// Asserts that two `address` values are equal. + function assertEq(address left, address right) external pure; + + /// Asserts that two `address` values are equal and includes error message into revert string on failure. + function assertEq(address left, address right, string calldata error) external pure; + + /// Asserts that two `bytes32` values are equal. + function assertEq(bytes32 left, bytes32 right) external pure; + + /// Asserts that two `bytes32` values are equal and includes error message into revert string on failure. + function assertEq(bytes32 left, bytes32 right, string calldata error) external pure; + + /// Asserts that the given condition is false. + function assertFalse(bool condition) external pure; + + /// Asserts that the given condition is false and includes error message into revert string on failure. + function assertFalse(bool condition, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than or equal to second. + /// Formats values with decimals in failure message. + function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than or equal to second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be greater than or equal to second. + /// Formats values with decimals in failure message. + function assertGeDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects first value to be greater than or equal to second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertGeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than or equal to second. + function assertGe(uint256 left, uint256 right) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than or equal to second. + /// Includes error message into revert string on failure. + function assertGe(uint256 left, uint256 right, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be greater than or equal to second. + function assertGe(int256 left, int256 right) external pure; + + /// Compares two `int256` values. Expects first value to be greater than or equal to second. + /// Includes error message into revert string on failure. + function assertGe(int256 left, int256 right, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than second. + /// Formats values with decimals in failure message. + function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be greater than second. + /// Formats values with decimals in failure message. + function assertGtDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects first value to be greater than second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertGtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than second. + function assertGt(uint256 left, uint256 right) external pure; + + /// Compares two `uint256` values. Expects first value to be greater than second. + /// Includes error message into revert string on failure. + function assertGt(uint256 left, uint256 right, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be greater than second. + function assertGt(int256 left, int256 right) external pure; + + /// Compares two `int256` values. Expects first value to be greater than second. + /// Includes error message into revert string on failure. + function assertGt(int256 left, int256 right, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be less than or equal to second. + /// Formats values with decimals in failure message. + function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects first value to be less than or equal to second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be less than or equal to second. + /// Formats values with decimals in failure message. + function assertLeDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects first value to be less than or equal to second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertLeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be less than or equal to second. + function assertLe(uint256 left, uint256 right) external pure; + + /// Compares two `uint256` values. Expects first value to be less than or equal to second. + /// Includes error message into revert string on failure. + function assertLe(uint256 left, uint256 right, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be less than or equal to second. + function assertLe(int256 left, int256 right) external pure; + + /// Compares two `int256` values. Expects first value to be less than or equal to second. + /// Includes error message into revert string on failure. + function assertLe(int256 left, int256 right, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be less than second. + /// Formats values with decimals in failure message. + function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Compares two `uint256` values. Expects first value to be less than second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be less than second. + /// Formats values with decimals in failure message. + function assertLtDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Compares two `int256` values. Expects first value to be less than second. + /// Formats values with decimals in failure message. Includes error message into revert string on failure. + function assertLtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Compares two `uint256` values. Expects first value to be less than second. + function assertLt(uint256 left, uint256 right) external pure; + + /// Compares two `uint256` values. Expects first value to be less than second. + /// Includes error message into revert string on failure. + function assertLt(uint256 left, uint256 right, string calldata error) external pure; + + /// Compares two `int256` values. Expects first value to be less than second. + function assertLt(int256 left, int256 right) external pure; + + /// Compares two `int256` values. Expects first value to be less than second. + /// Includes error message into revert string on failure. + function assertLt(int256 left, int256 right, string calldata error) external pure; + + /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message. + function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure; + + /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message. + /// Includes error message into revert string on failure. + function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; + + /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message. + function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) external pure; + + /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message. + /// Includes error message into revert string on failure. + function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; + + /// Asserts that two `bool` values are not equal. + function assertNotEq(bool left, bool right) external pure; + + /// Asserts that two `bool` values are not equal and includes error message into revert string on failure. + function assertNotEq(bool left, bool right, string calldata error) external pure; + + /// Asserts that two `string` values are not equal. + function assertNotEq(string calldata left, string calldata right) external pure; + + /// Asserts that two `string` values are not equal and includes error message into revert string on failure. + function assertNotEq(string calldata left, string calldata right, string calldata error) external pure; + + /// Asserts that two `bytes` values are not equal. + function assertNotEq(bytes calldata left, bytes calldata right) external pure; + + /// Asserts that two `bytes` values are not equal and includes error message into revert string on failure. + function assertNotEq(bytes calldata left, bytes calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bool` values are not equal. + function assertNotEq(bool[] calldata left, bool[] calldata right) external pure; + + /// Asserts that two arrays of `bool` values are not equal and includes error message into revert string on failure. + function assertNotEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `uint256` values are not equal. + function assertNotEq(uint256[] calldata left, uint256[] calldata right) external pure; + + /// Asserts that two arrays of `uint256` values are not equal and includes error message into revert string on failure. + function assertNotEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `int256` values are not equal. + function assertNotEq(int256[] calldata left, int256[] calldata right) external pure; + + /// Asserts that two arrays of `int256` values are not equal and includes error message into revert string on failure. + function assertNotEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure; + + /// Asserts that two `uint256` values are not equal. + function assertNotEq(uint256 left, uint256 right) external pure; + + /// Asserts that two arrays of `address` values are not equal. + function assertNotEq(address[] calldata left, address[] calldata right) external pure; + + /// Asserts that two arrays of `address` values are not equal and includes error message into revert string on failure. + function assertNotEq(address[] calldata left, address[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bytes32` values are not equal. + function assertNotEq(bytes32[] calldata left, bytes32[] calldata right) external pure; + + /// Asserts that two arrays of `bytes32` values are not equal and includes error message into revert string on failure. + function assertNotEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `string` values are not equal. + function assertNotEq(string[] calldata left, string[] calldata right) external pure; + + /// Asserts that two arrays of `string` values are not equal and includes error message into revert string on failure. + function assertNotEq(string[] calldata left, string[] calldata right, string calldata error) external pure; + + /// Asserts that two arrays of `bytes` values are not equal. + function assertNotEq(bytes[] calldata left, bytes[] calldata right) external pure; + + /// Asserts that two arrays of `bytes` values are not equal and includes error message into revert string on failure. + function assertNotEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure; + + /// Asserts that two `uint256` values are not equal and includes error message into revert string on failure. + function assertNotEq(uint256 left, uint256 right, string calldata error) external pure; + + /// Asserts that two `int256` values are not equal. + function assertNotEq(int256 left, int256 right) external pure; + + /// Asserts that two `int256` values are not equal and includes error message into revert string on failure. + function assertNotEq(int256 left, int256 right, string calldata error) external pure; + + /// Asserts that two `address` values are not equal. + function assertNotEq(address left, address right) external pure; + + /// Asserts that two `address` values are not equal and includes error message into revert string on failure. + function assertNotEq(address left, address right, string calldata error) external pure; + + /// Asserts that two `bytes32` values are not equal. + function assertNotEq(bytes32 left, bytes32 right) external pure; + + /// Asserts that two `bytes32` values are not equal and includes error message into revert string on failure. + function assertNotEq(bytes32 left, bytes32 right, string calldata error) external pure; + + /// Asserts that the given condition is true. + function assertTrue(bool condition) external pure; + + /// Asserts that the given condition is true and includes error message into revert string on failure. + function assertTrue(bool condition, string calldata error) external pure; + + /// 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 as structs. + function rpcUrlStructs() external view returns (Rpc[] memory urls); + + /// Returns all rpc urls and their aliases `[alias, url][]`. + function rpcUrls() external view returns (string[2][] memory urls); + + /// Suspends execution of the main thread for `duration` milliseconds. + function sleep(uint256 duration) external; + + // ======== Toml ======== + + /// Checks if `key` exists in a TOML table. + function keyExistsToml(string calldata toml, string calldata key) external view returns (bool); + + /// Parses a string of TOML data at `key` and coerces it to `address`. + function parseTomlAddress(string calldata toml, string calldata key) external pure returns (address); + + /// Parses a string of TOML data at `key` and coerces it to `address[]`. + function parseTomlAddressArray(string calldata toml, string calldata key) + external + pure + returns (address[] memory); + + /// Parses a string of TOML data at `key` and coerces it to `bool`. + function parseTomlBool(string calldata toml, string calldata key) external pure returns (bool); + + /// Parses a string of TOML data at `key` and coerces it to `bool[]`. + function parseTomlBoolArray(string calldata toml, string calldata key) external pure returns (bool[] memory); + + /// Parses a string of TOML data at `key` and coerces it to `bytes`. + function parseTomlBytes(string calldata toml, string calldata key) external pure returns (bytes memory); + + /// Parses a string of TOML data at `key` and coerces it to `bytes32`. + function parseTomlBytes32(string calldata toml, string calldata key) external pure returns (bytes32); + + /// Parses a string of TOML data at `key` and coerces it to `bytes32[]`. + function parseTomlBytes32Array(string calldata toml, string calldata key) + external + pure + returns (bytes32[] memory); + + /// Parses a string of TOML data at `key` and coerces it to `bytes[]`. + function parseTomlBytesArray(string calldata toml, string calldata key) external pure returns (bytes[] memory); + + /// Parses a string of TOML data at `key` and coerces it to `int256`. + function parseTomlInt(string calldata toml, string calldata key) external pure returns (int256); + + /// Parses a string of TOML data at `key` and coerces it to `int256[]`. + function parseTomlIntArray(string calldata toml, string calldata key) external pure returns (int256[] memory); + + /// Returns an array of all the keys in a TOML table. + function parseTomlKeys(string calldata toml, string calldata key) external pure returns (string[] memory keys); + + /// Parses a string of TOML data at `key` and coerces it to `string`. + function parseTomlString(string calldata toml, string calldata key) external pure returns (string memory); + + /// Parses a string of TOML data at `key` and coerces it to `string[]`. + function parseTomlStringArray(string calldata toml, string calldata key) external pure returns (string[] memory); + + /// Parses a string of TOML data at `key` and coerces it to `uint256`. + function parseTomlUint(string calldata toml, string calldata key) external pure returns (uint256); + + /// Parses a string of TOML data at `key` and coerces it to `uint256[]`. + function parseTomlUintArray(string calldata toml, string calldata key) external pure returns (uint256[] memory); + + /// ABI-encodes a TOML table. + function parseToml(string calldata toml) external pure returns (bytes memory abiEncodedData); + + /// ABI-encodes a TOML table at `key`. + function parseToml(string calldata toml, string calldata key) external pure returns (bytes memory abiEncodedData); + + /// Takes serialized JSON, converts to TOML and write a serialized TOML to a file. + function writeToml(string calldata json, string calldata path) external; + + /// Takes serialized JSON, converts to TOML and write a serialized TOML table to an **existing** TOML file, replacing a value with key = + /// This is useful to replace a specific value of a TOML file, without having to parse the entire thing. + function writeToml(string calldata json, string calldata path, string calldata valueKey) external; + + // ======== Utilities ======== + + /// Compute the address of a contract created with CREATE2 using the given CREATE2 deployer. + function computeCreate2Address(bytes32 salt, bytes32 initCodeHash, address deployer) + external + pure + returns (address); + + /// Compute the address of a contract created with CREATE2 using the default CREATE2 deployer. + function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) external pure returns (address); + + /// Compute the address a contract will be deployed at for a given deployer address and nonce. + function computeCreateAddress(address deployer, uint256 nonce) external pure returns (address); + + /// 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); + + /// 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); + + /// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language + /// at the derivation path `m/44'/60'/0'/0/{index}`. + function deriveKey(string calldata mnemonic, uint32 index, string calldata language) + external + pure + returns (uint256 privateKey); + + /// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language + /// at `{derivationPath}{index}`. + function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index, string calldata language) + external + pure + returns (uint256 privateKey); + + /// Gets the label for the specified address. + function getLabel(address account) external view returns (string memory currentLabel); + + /// Get a `Wallet`'s nonce. + function getNonce(Wallet calldata wallet) external returns (uint64 nonce); + + /// Labels an address in call traces. + function label(address account, string calldata newLabel) external; + + /// Adds a private key to the local forge wallet and returns the address. + function rememberKey(uint256 privateKey) external returns (address keyAddr); + + /// Signs data with a `Wallet`. + function sign(Wallet calldata wallet, bytes32 digest) external returns (uint8 v, bytes32 r, bytes32 s); + + /// Encodes a `bytes` value to a base64url string. + function toBase64URL(bytes calldata data) external pure returns (string memory); + + /// Encodes a `string` value to a base64url string. + function toBase64URL(string calldata data) external pure returns (string memory); + + /// Encodes a `bytes` value to a base64 string. + function toBase64(bytes calldata data) external pure returns (string memory); + + /// Encodes a `string` value to a base64 string. + function toBase64(string calldata data) external pure returns (string memory); +} + +/// 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 ======== + + /// Returns the identifier of the currently active fork. Reverts if no fork is currently active. + function activeFork() external view returns (uint256 forkId); + + /// In forking mode, explicitly grant the given address cheatcode access. + function allowCheatcodes(address account) external; + + /// Sets `block.chainid`. + function chainId(uint256 newChainId) external; + + /// Clears all mocked calls. + function clearMockedCalls() external; + + /// Sets `block.coinbase`. + function coinbase(address newCoinbase) external; + + /// 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 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 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 the latest block and returns the identifier of the fork. + function createSelectFork(string calldata urlOrAlias) 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); + + /// Sets an address' balance. + function deal(address account, uint256 newBalance) external; + + /// Removes the snapshot with the given ID created by `snapshot`. + /// Takes the snapshot ID to delete. + /// Returns `true` if the snapshot was successfully deleted. + /// Returns `false` if the snapshot does not exist. + function deleteSnapshot(uint256 snapshotId) external returns (bool success); + + /// Removes _all_ snapshots previously created by `snapshot`. + function deleteSnapshots() external; + + /// Sets `block.difficulty`. + /// Not available on EVM versions from Paris onwards. Use `prevrandao` instead. + /// Reverts if used on unsupported EVM versions. + function difficulty(uint256 newDifficulty) external; + + /// Dump a genesis JSON file's `allocs` to disk. + function dumpState(string calldata pathToStateJson) external; + + /// Sets an address' code. + function etch(address target, bytes calldata newRuntimeBytecode) external; + + /// Sets `block.basefee`. + function fee(uint256 newBasefee) external; + + /// Returns true if the account is marked as persistent. + function isPersistent(address account) external view returns (bool persistent); + + /// Load a genesis JSON file's `allocs` into the in-memory revm state. + function loadAllocs(string calldata pathToAllocsJson) 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; + + /// See `makePersistent(address)`. + function makePersistent(address account0, address account1) external; + + /// See `makePersistent(address)`. + function makePersistent(address account0, address account1, address account2) external; + + /// See `makePersistent(address)`. + function makePersistent(address[] calldata accounts) 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; + + /// 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; + + /// Sets the *next* call's `msg.sender` to be the input address. + function prank(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 `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; + + /// 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); + + /// Resets the nonce of an account to 0 for EOAs and 1 for contract accounts. + function resetNonce(address account) external; + + /// Revert the state of the EVM to a previous snapshot + /// Takes the snapshot ID to revert to. + /// Returns `true` if the snapshot was successfully reverted. + /// Returns `false` if the snapshot does not exist. + /// **Note:** This does not automatically delete the snapshot. To delete the snapshot use `deleteSnapshot`. + function revertTo(uint256 snapshotId) external returns (bool success); + + /// Revert the state of the EVM to a previous snapshot and automatically deletes the snapshots + /// Takes the snapshot ID to revert to. + /// Returns `true` if the snapshot was successfully reverted and deleted. + /// Returns `false` if the snapshot does not exist. + function revertToAndDelete(uint256 snapshotId) external returns (bool success); + + /// Revokes persistent status from the address, previously added via `makePersistent`. + function revokePersistent(address account) external; + + /// See `revokePersistent(address)`. + function revokePersistent(address[] calldata accounts) external; + + /// Sets `block.height`. + function roll(uint256 newHeight) external; + + /// 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; + + /// 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; + + /// 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); + + /// Sets all subsequent calls' `msg.sender` to be the input address until `stopPrank` is called. + function startPrank(address msgSender) 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; + + /// Stores a value to an address' storage slot. + function store(address target, bytes32 slot, bytes32 value) 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; + + /// Sets `tx.gasprice`. + function txGasPrice(uint256 newGasPrice) external; + + /// Sets `block.timestamp`. + function warp(uint256 newTimestamp) external; + + // ======== Testing ======== + + /// 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; + + /// 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; + + /// 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 with any revert data. + function expectRevert() external; + + /// Expects an error on next call that starts with the revert data. + function expectRevert(bytes4 revertData) external; + + /// Expects an error on next call that exactly matches the revert data. + function expectRevert(bytes calldata revertData) 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; + + /// Stops all safe memory expectation in the current subcontext. + function stopExpectSafeMemory() external; +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/console.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/console.sol new file mode 100644 index 0000000..ad57e53 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/console2.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/console2.sol new file mode 100644 index 0000000..c1e2cd7 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC1155.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC1155.sol new file mode 100644 index 0000000..f7dd2b4 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC165.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC165.sol new file mode 100644 index 0000000..9af4bf8 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC20.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC20.sol new file mode 100644 index 0000000..ba40806 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC4626.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC4626.sol new file mode 100644 index 0000000..bfe3a11 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC721.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC721.sol new file mode 100644 index 0000000..0a16f45 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IMulticall3.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IMulticall3.sol new file mode 100644 index 0000000..0d031b7 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC20.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC20.sol new file mode 100644 index 0000000..2a022fa --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC20.sol @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {IERC20} from "../interfaces/IERC20.sol"; + +/// @notice This is a mock contract of the ERC20 standard for testing purposes only, it SHOULD NOT be used in production. +/// @dev Forked from: https://github.com/transmissions11/solmate/blob/0384dbaaa4fcb5715738a9254a7c0a4cb62cf458/src/tokens/ERC20.sol +contract MockERC20 is IERC20 { + /*////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string internal _name; + + string internal _symbol; + + uint8 internal _decimals; + + function name() external view override returns (string memory) { + return _name; + } + + function symbol() external view override returns (string memory) { + return _symbol; + } + + function decimals() external view override returns (uint8) { + return _decimals; + } + + /*////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 internal _totalSupply; + + mapping(address => uint256) internal _balanceOf; + + mapping(address => mapping(address => uint256)) internal _allowance; + + function totalSupply() external view override returns (uint256) { + return _totalSupply; + } + + function balanceOf(address owner) external view override returns (uint256) { + return _balanceOf[owner]; + } + + function allowance(address owner, address spender) external view override returns (uint256) { + return _allowance[owner][spender]; + } + + /*////////////////////////////////////////////////////////////// + EIP-2612 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 internal INITIAL_CHAIN_ID; + + bytes32 internal INITIAL_DOMAIN_SEPARATOR; + + mapping(address => uint256) public nonces; + + /*////////////////////////////////////////////////////////////// + INITIALIZE + //////////////////////////////////////////////////////////////*/ + + /// @dev A bool to track whether the contract has been initialized. + bool private initialized; + + /// @dev To hide constructor warnings across solc versions due to different constructor visibility requirements and + /// syntaxes, we add an initialization function that can be called only once. + function initialize(string memory name_, string memory symbol_, uint8 decimals_) public { + require(!initialized, "ALREADY_INITIALIZED"); + + _name = name_; + _symbol = symbol_; + _decimals = decimals_; + + INITIAL_CHAIN_ID = _pureChainId(); + INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); + + initialized = true; + } + + /*////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 amount) public virtual override returns (bool) { + _allowance[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + + return true; + } + + function transfer(address to, uint256 amount) public virtual override returns (bool) { + _balanceOf[msg.sender] = _sub(_balanceOf[msg.sender], amount); + _balanceOf[to] = _add(_balanceOf[to], amount); + + emit Transfer(msg.sender, to, amount); + + return true; + } + + function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { + uint256 allowed = _allowance[from][msg.sender]; // Saves gas for limited approvals. + + if (allowed != ~uint256(0)) _allowance[from][msg.sender] = _sub(allowed, amount); + + _balanceOf[from] = _sub(_balanceOf[from], amount); + _balanceOf[to] = _add(_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"); + + 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 _pureChainId() == 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"), + _pureChainId(), + address(this) + ) + ); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL MINT/BURN LOGIC + //////////////////////////////////////////////////////////////*/ + + function _mint(address to, uint256 amount) internal virtual { + _totalSupply = _add(_totalSupply, amount); + _balanceOf[to] = _add(_balanceOf[to], amount); + + emit Transfer(address(0), to, amount); + } + + function _burn(address from, uint256 amount) internal virtual { + _balanceOf[from] = _sub(_balanceOf[from], amount); + _totalSupply = _sub(_totalSupply, amount); + + emit Transfer(from, address(0), amount); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL SAFE MATH LOGIC + //////////////////////////////////////////////////////////////*/ + + function _add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "ERC20: addition overflow"); + return c; + } + + function _sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(a >= b, "ERC20: subtraction underflow"); + return a - b; + } + + /*////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////*/ + + // 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(); + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC721.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC721.sol new file mode 100644 index 0000000..f21151b --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC721.sol @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {IERC721Metadata} from "../interfaces/IERC721.sol"; + +/// @notice This is a mock contract of the ERC721 standard for testing purposes only, it SHOULD NOT be used in production. +/// @dev Forked from: https://github.com/transmissions11/solmate/blob/0384dbaaa4fcb5715738a9254a7c0a4cb62cf458/src/tokens/ERC721.sol +contract MockERC721 is IERC721Metadata { + /*////////////////////////////////////////////////////////////// + METADATA STORAGE/LOGIC + //////////////////////////////////////////////////////////////*/ + + string internal _name; + + string internal _symbol; + + function name() external view override returns (string memory) { + return _name; + } + + function symbol() external view override returns (string memory) { + return _symbol; + } + + function tokenURI(uint256 id) public view virtual override returns (string memory) {} + + /*////////////////////////////////////////////////////////////// + ERC721 BALANCE/OWNER STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(uint256 => address) internal _ownerOf; + + mapping(address => uint256) internal _balanceOf; + + function ownerOf(uint256 id) public view virtual override returns (address owner) { + require((owner = _ownerOf[id]) != address(0), "NOT_MINTED"); + } + + function balanceOf(address owner) public view virtual override returns (uint256) { + require(owner != address(0), "ZERO_ADDRESS"); + + return _balanceOf[owner]; + } + + /*////////////////////////////////////////////////////////////// + ERC721 APPROVAL STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(uint256 => address) internal _getApproved; + + mapping(address => mapping(address => bool)) internal _isApprovedForAll; + + function getApproved(uint256 id) public view virtual override returns (address) { + return _getApproved[id]; + } + + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _isApprovedForAll[owner][operator]; + } + + /*////////////////////////////////////////////////////////////// + INITIALIZE + //////////////////////////////////////////////////////////////*/ + + /// @dev A bool to track whether the contract has been initialized. + bool private initialized; + + /// @dev To hide constructor warnings across solc versions due to different constructor visibility requirements and + /// syntaxes, we add an initialization function that can be called only once. + function initialize(string memory name_, string memory symbol_) public { + require(!initialized, "ALREADY_INITIALIZED"); + + _name = name_; + _symbol = symbol_; + + initialized = true; + } + + /*////////////////////////////////////////////////////////////// + ERC721 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 id) public payable virtual override { + 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 override { + _isApprovedForAll[msg.sender][operator] = approved; + + emit ApprovalForAll(msg.sender, operator, approved); + } + + function transferFrom(address from, address to, uint256 id) public payable virtual override { + 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. + _balanceOf[from]--; + + _balanceOf[to]++; + + _ownerOf[id] = to; + + delete _getApproved[id]; + + emit Transfer(from, to, id); + } + + function safeTransferFrom(address from, address to, uint256 id) public payable virtual override { + transferFrom(from, to, id); + + require( + !_isContract(to) + || IERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") + == IERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function safeTransferFrom(address from, address to, uint256 id, bytes memory data) + public + payable + virtual + override + { + transferFrom(from, to, id); + + require( + !_isContract(to) + || IERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) + == IERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + /*////////////////////////////////////////////////////////////// + ERC165 LOGIC + //////////////////////////////////////////////////////////////*/ + + function supportsInterface(bytes4 interfaceId) public view virtual override 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. + + _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"); + + _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( + !_isContract(to) + || IERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") + == IERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function _safeMint(address to, uint256 id, bytes memory data) internal virtual { + _mint(to, id); + + require( + !_isContract(to) + || IERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) + == IERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + /*////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////*/ + + function _isContract(address _addr) private view returns (bool) { + uint256 codeLength; + + // Assembly required for versions < 0.8.0 to check extcodesize. + assembly { + codeLength := extcodesize(_addr) + } + + return codeLength > 0; + } +} + +interface IERC721TokenReceiver { + function onERC721Received(address, address, uint256, bytes calldata) external returns (bytes4); +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/safeconsole.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/safeconsole.sol new file mode 100644 index 0000000..5714d09 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdAssertions.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdAssertions.t.sol new file mode 100644 index 0000000..ea79468 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdAssertions.t.sol @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/StdAssertions.sol"; +import {Vm} from "../src/Vm.sol"; + +interface VmInternal is Vm { + function _expectCheatcodeRevert(bytes memory message) external; +} + +contract StdAssertionsTest is StdAssertions { + string constant errorMessage = "User provided message"; + uint256 constant maxDecimals = 77; + + bool constant SHOULD_REVERT = true; + bool constant SHOULD_RETURN = false; + + bool constant STRICT_REVERT_DATA = true; + bool constant NON_STRICT_REVERT_DATA = false; + + VmInternal constant vm = VmInternal(address(uint160(uint256(keccak256("hevm cheat code"))))); + + 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)); + + assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); + } + + 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._expectCheatcodeRevert( + bytes( + string.concat( + "Call return data does not match: ", vm.toString(returnDataA), " != ", vm.toString(returnDataB) + ) + ) + ); + assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); + } + + 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)); + + assertEqCall(targetA, callDataA, targetB, callDataB, NON_STRICT_REVERT_DATA); + } + + 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._expectCheatcodeRevert( + bytes( + string.concat( + "Call revert data does not match: ", vm.toString(revertDataA), " != ", vm.toString(revertDataB) + ) + ) + ); + assertEqCall(targetA, callDataA, targetB, callDataB, STRICT_REVERT_DATA); + } + + 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.expectRevert(bytes("assertion failed")); + this.assertEqCallExternal(targetA, callDataA, targetB, callDataB, strictRevertData); + + vm.expectRevert(bytes("assertion failed")); + this.assertEqCallExternal(targetB, callDataB, targetA, callDataA, strictRevertData); + } + + // Helper function to test outcome of assertEqCall via `expect` cheatcodes + function assertEqCallExternal( + address targetA, + bytes memory callDataA, + address targetB, + bytes memory callDataB, + bool strictRevertData + ) public { + assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); + } + + function testFailFail() public { + fail(); + } +} + +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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdChains.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdChains.t.sol new file mode 100644 index 0000000..4c3283a --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdChains.t.sol @@ -0,0 +1,221 @@ +// 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://eth-mainnet.alchemyapi.io/v2/WV407BEiBmjNJfKo9Uo_55u0z0ITyCOX"); + 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://eth-mainnet.alchemyapi.io/v2/WV407BEiBmjNJfKo9Uo_55u0z0ITyCOX"); + + // 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"); + } + + // Named with a leading underscore to clarify this is not intended to be run as a normal test, + // and is intended to be used in the below `test_Rpcs` test. + 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. + // Currently commented out since this is slow and public RPCs are flaky, often resulting in failing CI. + // function test_Rpcs() 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"); + // _testRpc("fraxtal"); + // _testRpc("fraxtal_testnet"); + // } + + 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(); + stdChainsMock.exposed_getChain(31337); + vm.expectRevert(); + stdChainsMock.exposed_getChain("sepolia"); + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdCheats.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdCheats.t.sol new file mode 100644 index 0000000..e96cb52 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdCheats.t.sol @@ -0,0 +1,618 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/StdCheats.sol"; +import "../src/Test.sol"; +import "../src/StdJson.sol"; +import "../src/StdToml.sol"; +import "../src/interfaces/IERC20.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 test_DealToken() 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 pure { + 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 view { + 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 view { + 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(); + + 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 pure { + 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 view { + 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 view { + 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 view { + assumeNotBlacklisted(USDT, addr); + assertFalse(USDTLike(USDT).isBlackListed(addr)); + } + + function test_dealUSDC() external { + // roll fork to the point when USDC contract updated to store balance in packed slots + vm.rollFork(19279215); + + uint256 balance = 100e6; + deal(USDC, address(this), balance); + assertEq(IERC20(USDC).balanceOf(address(this)), balance); + } +} + +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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdError.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdError.t.sol new file mode 100644 index 0000000..a306eaa --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdError.t.sol @@ -0,0 +1,120 @@ +// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdJson.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdJson.t.sol new file mode 100644 index 0000000..e32b92e --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdJson.t.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdJsonTest is Test { + using stdJson for string; + + string root; + string path; + + function setUp() public { + root = vm.projectRoot(); + path = string.concat(root, "/test/fixtures/test.json"); + } + + struct SimpleJson { + uint256 a; + string b; + } + + struct NestedJson { + uint256 a; + string b; + SimpleJson c; + } + + function test_readJson() public view { + string memory json = vm.readFile(path); + assertEq(json.readUint(".a"), 123); + } + + function test_writeJson() public { + string memory json = "json"; + json.serialize("a", uint256(123)); + string memory semiFinal = json.serialize("b", string("test")); + string memory finalJson = json.serialize("c", semiFinal); + finalJson.write(path); + + string memory json_ = vm.readFile(path); + bytes memory data = json_.parseRaw("$"); + NestedJson memory decodedData = abi.decode(data, (NestedJson)); + + assertEq(decodedData.a, 123); + assertEq(decodedData.b, "test"); + assertEq(decodedData.c.a, 123); + assertEq(decodedData.c.b, "test"); + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdMath.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdMath.t.sol new file mode 100644 index 0000000..ed0f9ba --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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 pure { + 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 pure { + uint256 manualAbs = getAbs(a); + + uint256 abs = stdMath.abs(a); + + assertEq(abs, manualAbs); + } + + function test_GetDelta_Uint() external pure { + 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 pure { + 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 pure { + 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 pure { + 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 pure { + 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 pure { + 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStorage.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStorage.t.sol new file mode 100644 index 0000000..e1e6aa0 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStorage.t.sol @@ -0,0 +1,463 @@ +// 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 testFuzz_StorageCheckedWriteMapPacked(address addr, uint128 value) public { + stdstore.enable_packed_slots().target(address(test)).sig(test.read_struct_lower.selector).with_key(addr) + .checked_write(value); + assertEq(test.read_struct_lower(addr), value); + + stdstore.enable_packed_slots().target(address(test)).sig(test.read_struct_upper.selector).with_key(addr) + .checked_write(value); + assertEq(test.read_struct_upper(addr), value); + } + + function test_StorageCheckedWriteMapPackedFullSuccess() 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 testFuzz_StorageNativePack(uint248 val1, uint248 val2, bool boolVal1, bool boolVal2) public { + stdstore.enable_packed_slots().target(address(test)).sig(test.tA.selector).checked_write(val1); + stdstore.enable_packed_slots().target(address(test)).sig(test.tB.selector).checked_write(boolVal1); + stdstore.enable_packed_slots().target(address(test)).sig(test.tC.selector).checked_write(boolVal2); + stdstore.enable_packed_slots().target(address(test)).sig(test.tD.selector).checked_write(val2); + + assertEq(test.tA(), val1); + assertEq(test.tB(), boolVal1); + assertEq(test.tC(), boolVal2); + assertEq(test.tD(), val2); + } + + 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); + } + + function testFuzzPacked(uint256 val, uint8 elemToGet) public { + // This function tries an assortment of packed slots, shifts meaning number of elements + // that are packed. Shiftsizes are the size of each element, i.e. 8 means a data type that is 8 bits, 16 == 16 bits, etc. + // Combined, these determine how a slot is packed. Making it random is too hard to avoid global rejection limit + // and make it performant. + + // change the number of shifts + for (uint256 i = 1; i < 5; i++) { + uint256 shifts = i; + + elemToGet = uint8(bound(elemToGet, 0, shifts - 1)); + + uint256[] memory shiftSizes = new uint256[](shifts); + for (uint256 j; j < shifts; j++) { + shiftSizes[j] = 8 * (j + 1); + } + + test.setRandomPacking(val); + + uint256 leftBits; + uint256 rightBits; + for (uint256 j; j < shiftSizes.length; j++) { + if (j < elemToGet) { + leftBits += shiftSizes[j]; + } else if (elemToGet != j) { + rightBits += shiftSizes[j]; + } + } + + // we may have some right bits unaccounted for + leftBits += 256 - (leftBits + shiftSizes[elemToGet] + rightBits); + // clear left bits, then clear right bits and realign + uint256 expectedValToRead = (val << leftBits) >> (leftBits + rightBits); + + uint256 readVal = stdstore.target(address(test)).enable_packed_slots().sig( + "getRandomPacked(uint8,uint8[],uint8)" + ).with_calldata(abi.encode(shifts, shiftSizes, elemToGet)).read_uint(); + + assertEq(readVal, expectedValToRead); + } + } + + function testFuzzPacked2(uint256 nvars, uint256 seed) public { + // Number of random variables to generate. + nvars = bound(nvars, 1, 20); + + // This will decrease as we generate values in the below loop. + uint256 bitsRemaining = 256; + + // Generate a random value and size for each variable. + uint256[] memory vals = new uint256[](nvars); + uint256[] memory sizes = new uint256[](nvars); + uint256[] memory offsets = new uint256[](nvars); + + for (uint256 i = 0; i < nvars; i++) { + // Generate a random value and size. + offsets[i] = i == 0 ? 0 : offsets[i - 1] + sizes[i - 1]; + + uint256 nvarsRemaining = nvars - i; + uint256 maxVarSize = bitsRemaining - nvarsRemaining + 1; + sizes[i] = bound(uint256(keccak256(abi.encodePacked(seed, i + 256))), 1, maxVarSize); + bitsRemaining -= sizes[i]; + + uint256 maxVal; + uint256 varSize = sizes[i]; + assembly { + // mask = (1 << varSize) - 1 + maxVal := sub(shl(varSize, 1), 1) + } + vals[i] = bound(uint256(keccak256(abi.encodePacked(seed, i))), 0, maxVal); + } + + // Pack all values into the slot. + for (uint256 i = 0; i < nvars; i++) { + stdstore.enable_packed_slots().target(address(test)).sig("getRandomPacked(uint256,uint256)").with_key( + sizes[i] + ).with_key(offsets[i]).checked_write(vals[i]); + } + + // Verify the read data matches. + for (uint256 i = 0; i < nvars; i++) { + uint256 readVal = stdstore.enable_packed_slots().target(address(test)).sig( + "getRandomPacked(uint256,uint256)" + ).with_key(sizes[i]).with_key(offsets[i]).read_uint(); + + uint256 retVal = test.getRandomPacked(sizes[i], offsets[i]); + + assertEq(readVal, vals[i]); + assertEq(retVal, vals[i]); + } + } +} + +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"); + + uint256 randomPacking; + + 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; + } + + function setRandomPacking(uint256 val) public { + randomPacking = val; + } + + function _getMask(uint256 size) internal pure returns (uint256 mask) { + assembly { + // mask = (1 << size) - 1 + mask := sub(shl(size, 1), 1) + } + } + + function setRandomPacking(uint256 val, uint256 size, uint256 offset) public { + // Generate mask based on the size of the value + uint256 mask = _getMask(size); + // Zero out all bits for the word we're about to set + uint256 cleanedWord = randomPacking & ~(mask << offset); + // Place val in the correct spot of the cleaned word + randomPacking = cleanedWord | val << offset; + } + + function getRandomPacked(uint256 size, uint256 offset) public view returns (uint256) { + // Generate mask based on the size of the value + uint256 mask = _getMask(size); + // Shift to place the bits in the correct position, and use mask to zero out remaining bits + return (randomPacking >> offset) & mask; + } + + function getRandomPacked(uint8 shifts, uint8[] memory shiftSizes, uint8 elem) public view returns (uint256) { + require(elem < shifts, "!elem"); + uint256 leftBits; + uint256 rightBits; + + for (uint256 i; i < shiftSizes.length; i++) { + if (i < elem) { + leftBits += shiftSizes[i]; + } else if (elem != i) { + rightBits += shiftSizes[i]; + } + } + + // we may have some right bits unaccounted for + leftBits += 256 - (leftBits + shiftSizes[elem] + rightBits); + + // clear left bits, then clear right bits and realign + return (randomPacking << leftBits) >> (leftBits + rightBits); + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStyle.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStyle.t.sol new file mode 100644 index 0000000..e12c005 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdToml.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdToml.t.sol new file mode 100644 index 0000000..631b1b5 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdToml.t.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdTomlTest is Test { + using stdToml for string; + + string root; + string path; + + function setUp() public { + root = vm.projectRoot(); + path = string.concat(root, "/test/fixtures/test.toml"); + } + + struct SimpleToml { + uint256 a; + string b; + } + + struct NestedToml { + uint256 a; + string b; + SimpleToml c; + } + + function test_readToml() public view { + string memory json = vm.readFile(path); + assertEq(json.readUint(".a"), 123); + } + + function test_writeToml() public { + string memory json = "json"; + json.serialize("a", uint256(123)); + string memory semiFinal = json.serialize("b", string("test")); + string memory finalJson = json.serialize("c", semiFinal); + finalJson.write(path); + + string memory toml = vm.readFile(path); + bytes memory data = toml.parseRaw("$"); + NestedToml memory decodedData = abi.decode(data, (NestedToml)); + + assertEq(decodedData.a, 123); + assertEq(decodedData.b, "test"); + assertEq(decodedData.c.a, 123); + assertEq(decodedData.c.b, "test"); + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdUtils.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdUtils.t.sol new file mode 100644 index 0000000..4994c6c --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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 pure returns (int256) { + return bound(num, min, max); + } + + function exposed_bound(uint256 num, uint256 min, uint256 max) external pure 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 pure { + 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 pure { + 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 pure { + 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 pure { + 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 pure { + 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 pure { + 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 pure { + 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 pure { + 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 pure { + 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 pure { + 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 pure { + 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 pure { + 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 pure { + 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 pure { + 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 pure { + 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 pure { + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + uint256 nonce = 14; + address createAddress = computeCreateAddress(deployer, nonce); + assertEq(createAddress, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); + } + + /*////////////////////////////////////////////////////////////////////////// + COMPUTE CREATE2 ADDRESS + //////////////////////////////////////////////////////////////////////////*/ + + function test_ComputeCreate2Address() external pure { + 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 pure { + 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/Vm.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/Vm.t.sol new file mode 100644 index 0000000..4ff3d7e --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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 pure { + assertEq(type(VmSafe).interfaceId, bytes4(0xce9c7617), "VmSafe"); + assertEq(type(Vm).interfaceId, bytes4(0xaf68a970), "Vm"); + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationScript.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationScript.sol new file mode 100644 index 0000000..e205cff --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationScriptBase.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationScriptBase.sol new file mode 100644 index 0000000..ce8e0e9 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationTest.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationTest.sol new file mode 100644 index 0000000..9beeafe --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationTestBase.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationTestBase.sol new file mode 100644 index 0000000..e993535 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/broadcast.log.json b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/broadcast.log.json new file mode 100644 index 0000000..0a0200b --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.json b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.json new file mode 100644 index 0000000..caebf6d --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.json @@ -0,0 +1,8 @@ +{ + "a": 123, + "b": "test", + "c": { + "a": 123, + "b": "test" + } +} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.toml b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.toml new file mode 100644 index 0000000..60692bc --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.toml @@ -0,0 +1,6 @@ +a = 123 +b = "test" + +[c] +a = 123 +b = "test" diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC20.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC20.t.sol new file mode 100644 index 0000000..e246810 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC20.t.sol @@ -0,0 +1,441 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {MockERC20} from "../../src/mocks/MockERC20.sol"; +import {StdCheats} from "../../src/StdCheats.sol"; +import {Test} from "../../src/Test.sol"; + +contract Token_ERC20 is MockERC20 { + constructor(string memory name, string memory symbol, uint8 decimals) { + initialize(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); + } +} + +contract MockERC20Test is StdCheats, Test { + Token_ERC20 token; + + bytes32 constant PERMIT_TYPEHASH = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + function setUp() public { + token = new Token_ERC20("Token", "TKN", 18); + } + + function invariantMetadata() public view { + 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); + + vm.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); + + vm.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 = vm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = vm.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); + + vm.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); + + vm.prank(from); + token.approve(address(this), 1e18); + + token.transferFrom(from, address(0xBEEF), 1e18); + } + + function testFailPermitBadNonce() public { + uint256 privateKey = 0xBEEF; + address owner = vm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = vm.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 = vm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = vm.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 = vm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(0xCAFE), 1e18, 0, oldTimestamp)) + ) + ) + ); + + vm.warp(block.timestamp + 1); + token.permit(owner, address(0xCAFE), 1e18, oldTimestamp, v, r, s); + } + + function testFailPermitReplay() public { + uint256 privateKey = 0xBEEF; + address owner = vm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = vm.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 { + Token_ERC20 tkn = new Token_ERC20(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); + + vm.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 = vm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = vm.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); + + vm.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); + + vm.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 = vm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = vm.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 = vm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = vm.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 = vm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = vm.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 = vm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = vm.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); + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC721.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC721.t.sol new file mode 100644 index 0000000..f986d79 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC721.t.sol @@ -0,0 +1,721 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import {MockERC721, IERC721TokenReceiver} from "../../src/mocks/MockERC721.sol"; +import {StdCheats} from "../../src/StdCheats.sol"; +import {Test} from "../../src/Test.sol"; + +contract ERC721Recipient is IERC721TokenReceiver { + 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 IERC721TokenReceiver.onERC721Received.selector; + } +} + +contract RevertingERC721Recipient is IERC721TokenReceiver { + function onERC721Received(address, address, uint256, bytes calldata) public virtual override returns (bytes4) { + revert(string(abi.encodePacked(IERC721TokenReceiver.onERC721Received.selector))); + } +} + +contract WrongReturnDataERC721Recipient is IERC721TokenReceiver { + function onERC721Received(address, address, uint256, bytes calldata) public virtual override returns (bytes4) { + return 0xCAFEBEEF; + } +} + +contract NonERC721Recipient {} + +contract Token_ERC721 is MockERC721 { + constructor(string memory _name, string memory _symbol) { + initialize(_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); + } +} + +contract MockERC721Test is StdCheats, Test { + Token_ERC721 token; + + function setUp() public { + token = new Token_ERC721("Token", "TKN"); + } + + function invariantMetadata() public view { + 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); + + vm.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)); + + vm.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); + + vm.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); + + vm.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); + + vm.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); + + vm.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); + assertEq(recipient.data(), ""); + } + + function testSafeTransferFromToERC721RecipientWithData() public { + address from = address(0xABCD); + ERC721Recipient recipient = new ERC721Recipient(); + + token.mint(from, 1337); + + vm.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); + assertEq(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); + assertEq(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); + assertEq(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 Token_ERC721(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); + + vm.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)); + + vm.expectRevert("NOT_MINTED"); + token.ownerOf(id); + } + + function testApproveAll(address to, bool approved) public { + token.setApprovalForAll(to, approved); + + assertEq(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); + + vm.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); + + vm.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); + + vm.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); + + vm.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); + assertEq(recipient.data(), ""); + } + + function testSafeTransferFromToERC721RecipientWithData(uint256 id, bytes calldata data) public { + address from = address(0xABCD); + ERC721Recipient recipient = new ERC721Recipient(); + + token.mint(from, id); + + vm.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); + assertEq(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); + assertEq(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); + assertEq(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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/scripts/ExampleDeploy.s.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/scripts/ExampleDeploy.s.sol new file mode 100644 index 0000000..8a01f52 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/scripts/ExampleDeploy.s.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {Script, console2} from "forge-std/Script.sol"; + +import {SafeSingletonDeployer} from "../src/SafeSingletonDeployer.sol"; +import {Mock} from "../test/Mock.sol"; + +contract ExampleDeployScript is Script { + function run() public { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + SafeSingletonDeployer.broadcastDeploy({ + deployerPrivateKey: deployerPrivateKey, + creationCode: type(Mock).creationCode, + args: abi.encode(1), + salt: bytes32("0x1234") + }); + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/src/SafeSingletonDeployer.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/src/SafeSingletonDeployer.sol new file mode 100644 index 0000000..d53d49f --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/src/SafeSingletonDeployer.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {VmSafe} from "forge-std/Vm.sol"; + +/// @notice Library for deploying contracts using Safe's Singleton Factory +/// https://github.com/safe-global/safe-singleton-factory +library SafeSingletonDeployer { + error DeployFailed(); + + address constant SAFE_SINGLETON_FACTORY = 0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7; + VmSafe private constant VM = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function computeAddress(bytes memory creationCode, bytes32 salt) public pure returns (address) { + return computeAddress(creationCode, "", salt); + } + + function computeAddress(bytes memory creationCode, bytes memory args, bytes32 salt) public pure returns (address) { + return VM.computeCreate2Address({ + salt: salt, + initCodeHash: _hashInitCode(creationCode, args), + deployer: SAFE_SINGLETON_FACTORY + }); + } + + function broadcastDeploy(bytes memory creationCode, bytes memory args, bytes32 salt) internal returns (address) { + VM.broadcast(); + return _deploy(creationCode, args, salt); + } + + function broadcastDeploy(bytes memory creationCode, bytes32 salt) internal returns (address) { + VM.broadcast(); + return _deploy(creationCode, "", salt); + } + + function broadcastDeploy(address deployer, bytes memory creationCode, bytes memory args, bytes32 salt) + internal + returns (address) + { + VM.broadcast(deployer); + return _deploy(creationCode, args, salt); + } + + function broadcastDeploy(address deployer, bytes memory creationCode, bytes32 salt) internal returns (address) { + VM.broadcast(deployer); + return _deploy(creationCode, "", salt); + } + + function broadcastDeploy(uint256 deployerPrivateKey, bytes memory creationCode, bytes memory args, bytes32 salt) + internal + returns (address) + { + VM.broadcast(deployerPrivateKey); + return _deploy(creationCode, args, salt); + } + + function broadcastDeploy(uint256 deployerPrivateKey, bytes memory creationCode, bytes32 salt) + internal + returns (address) + { + VM.broadcast(deployerPrivateKey); + return _deploy(creationCode, "", salt); + } + + /// @dev Allows calling without Forge broadcast + function deploy(bytes memory creationCode, bytes memory args, bytes32 salt) internal returns (address) { + return _deploy(creationCode, args, salt); + } + + /// @dev Allows calling without Forge broadcast + function deploy(bytes memory creationCode, bytes32 salt) internal returns (address) { + return _deploy(creationCode, "", salt); + } + + function _deploy(bytes memory creationCode, bytes memory args, bytes32 salt) private returns (address) { + bytes memory callData = abi.encodePacked(salt, creationCode, args); + + (bool success, bytes memory result) = SAFE_SINGLETON_FACTORY.call(callData); + + if (!success) { + // contract does not pass on revert reason + // https://github.com/Arachnid/deterministic-deployment-proxy/blob/master/source/deterministic-deployment-proxy.yul#L13 + revert DeployFailed(); + } + + return address(bytes20(result)); + } + + function _hashInitCode(bytes memory creationCode, bytes memory args) private pure returns (bytes32) { + return keccak256(abi.encodePacked(creationCode, args)); + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/Mock.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/Mock.sol new file mode 100644 index 0000000..3c33499 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/Mock.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract Mock { + uint256 public value; + + constructor(uint256 startValue) { + value = startValue; + } + + function setValue(uint256 value_) public returns (uint256) { + return value = value_; + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/MockReverting.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/MockReverting.sol new file mode 100644 index 0000000..7fa3794 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/MockReverting.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract MockReverting { + error MyError(); + + constructor() { + revert MyError(); + } +} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/SafeSingletonDeployer.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/SafeSingletonDeployer.t.sol new file mode 100644 index 0000000..859be79 --- /dev/null +++ b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/SafeSingletonDeployer.t.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Test} from "forge-std/Test.sol"; + +import {SafeSingletonDeployer} from "../src/SafeSingletonDeployer.sol"; + +import {Mock} from "./Mock.sol"; +import {MockReverting} from "./MockReverting.sol"; + +contract SafeSingletonDeployerTest is Test { + // cast code 0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7 --rpc-url https://mainnet.base.org + bytes factoryCode = + hex"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3"; + + function setUp() public { + vm.etch(SafeSingletonDeployer.SAFE_SINGLETON_FACTORY, factoryCode); + } + + function test_deploy_createsAtExpectedAddress() public { + address expectedAddress = + SafeSingletonDeployer.computeAddress(type(Mock).creationCode, abi.encode(1), bytes32("0x1234")); + assertEq(expectedAddress.code, ""); + address returnAddress = SafeSingletonDeployer.deploy({ + creationCode: type(Mock).creationCode, + args: abi.encode(1), + salt: bytes32("0x1234") + }); + assertEq(returnAddress, expectedAddress); + assertNotEq(expectedAddress.code, ""); + } + + function test_deploy_createsContractCorrectly() public { + uint256 startValue = 1; + address mock = SafeSingletonDeployer.deploy({ + creationCode: type(Mock).creationCode, + args: abi.encode(1), + salt: bytes32("0x1234") + }); + assertEq(startValue, Mock(mock).value()); + uint256 newValue = 2; + Mock(mock).setValue(newValue); + assertEq(newValue, Mock(mock).value()); + } + + function test_deploy_reverts() public { + vm.expectRevert(); + SafeSingletonDeployer.deploy({ + creationCode: type(MockReverting).creationCode, + args: abi.encode(1), + salt: bytes32("0x1234") + }); + } +} diff --git a/typescript/packages/account-modules/script/CalculateStorageSlot.s.sol b/typescript/packages/account-modules/script/CalculateStorageSlot.s.sol new file mode 100644 index 0000000..7fbacdd --- /dev/null +++ b/typescript/packages/account-modules/script/CalculateStorageSlot.s.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Script, console} from "forge-std/Script.sol"; +import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; + +contract CalculateStorageSlot is Script { + using SlotDerivation for string; + + function run() public { + // AutoTopUpExecutor storage slot + string memory topUpNamespace = "autotopup.storage.AutoTopUpExecutor"; + bytes32 topUpSlot = topUpNamespace.erc7201Slot(); + console.log("AutoTopUpExecutor Namespace:", topUpNamespace); + console.log("AutoTopUpExecutor Storage slot:"); + console.logBytes32(topUpSlot); + + console.log(""); + + // AutoCollectExecutor storage slot + string memory collectNamespace = "autocollect.storage.AutoCollectExecutor"; + bytes32 collectSlot = collectNamespace.erc7201Slot(); + console.log("AutoCollectExecutor Namespace:", collectNamespace); + console.log("AutoCollectExecutor Storage slot:"); + console.logBytes32(collectSlot); + } +} diff --git a/typescript/packages/account-modules/script/Deploy.s.sol b/typescript/packages/account-modules/script/Deploy.s.sol new file mode 100644 index 0000000..931afa5 --- /dev/null +++ b/typescript/packages/account-modules/script/Deploy.s.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Script, console} from "forge-std/Script.sol"; +import {SafeSingletonDeployer} from "safe-singleton-deployer/SafeSingletonDeployer.sol"; +import {AutoTopUpExecutor} from "../src/AutoTopUpExecutor.sol"; +import {AutoCollectExecutor} from "../src/AutoCollectExecutor.sol"; + +contract Deploy is Script { + // Use meaningful salts for deterministic addresses across chains + bytes32 constant AUTO_TOPUP_SALT = keccak256("AutoTopUpExecutor.v1"); + bytes32 constant AUTO_COLLECT_SALT = keccak256("AutoCollectExecutor.v1"); + + function run() external returns (address autoTopUp, address autoCollect) { + // Get deployer from environment + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + console.log("=== Deploying Account Modules ==="); + console.log("Deployer:", vm.addr(deployerPrivateKey)); + console.log(""); + + vm.startBroadcast(deployerPrivateKey); + + // Deploy AutoTopUpExecutor using Safe Singleton Factory + console.log("Deploying AutoTopUpExecutor..."); + autoTopUp = _deploySingleton( + type(AutoTopUpExecutor).creationCode, + "", // No constructor args + AUTO_TOPUP_SALT, + "AutoTopUpExecutor" + ); + + // Deploy AutoCollectExecutor using Safe Singleton Factory + console.log("Deploying AutoCollectExecutor..."); + autoCollect = _deploySingleton( + type(AutoCollectExecutor).creationCode, + "", // No constructor args + AUTO_COLLECT_SALT, + "AutoCollectExecutor" + ); + + vm.stopBroadcast(); + + // Log deployment summary + console.log(""); + console.log("=== Deployment Summary ==="); + console.log("AutoTopUpExecutor:", autoTopUp); + console.log("AutoCollectExecutor:", autoCollect); + console.log(""); + console.log("These addresses will be consistent across all chains!"); + console.log("========================="); + } + + function _deploySingleton( + bytes memory creationCode, + bytes memory constructorArgs, + bytes32 salt, + string memory contractName + ) internal returns (address deployed) { + // Use SafeSingletonDeployer.deploy (not broadcastDeploy) since we're already broadcasting + deployed = SafeSingletonDeployer.deploy(creationCode, constructorArgs, salt); + + console.log(string.concat(contractName, " deployed at:"), deployed); + + // Verify deployment + require(deployed.code.length > 0, string.concat(contractName, " deployment failed")); + } + + // Helper function to predict addresses without deploying + function predict() external view { + console.log("=== Predicted Addresses ==="); + + // Predict AutoTopUpExecutor address + address predictedAutoTopUp = + SafeSingletonDeployer.computeAddress(type(AutoTopUpExecutor).creationCode, AUTO_TOPUP_SALT); + console.log("AutoTopUpExecutor:", predictedAutoTopUp); + + // Predict AutoCollectExecutor address + address predictedAutoCollect = + SafeSingletonDeployer.computeAddress(type(AutoCollectExecutor).creationCode, AUTO_COLLECT_SALT); + console.log("AutoCollectExecutor:", predictedAutoCollect); + + console.log("==========================="); + } +} diff --git a/typescript/packages/account-modules/script/README.md b/typescript/packages/account-modules/script/README.md new file mode 100644 index 0000000..d02fbf6 --- /dev/null +++ b/typescript/packages/account-modules/script/README.md @@ -0,0 +1,42 @@ +# Account Modules Deployment Scripts + +## Deploy.s.sol + +Deploys the AutoTopUpExecutor and AutoCollectExecutor modules using Safe's Singleton Factory for deterministic addresses across all chains. + +### Usage + +#### Predict Addresses (without deploying) +```bash +forge script script/Deploy.s.sol:Deploy --sig "predict()" +``` + +#### Deploy to a Network +```bash +# Set required environment variables +export PRIVATE_KEY= + +# Deploy to Base Sepolia +forge script script/Deploy.s.sol:Deploy \ + --rpc-url \ + --broadcast \ + --verify + +# Deploy to Base Mainnet +forge script script/Deploy.s.sol:Deploy \ + --rpc-url \ + --broadcast \ + --verify +``` + +### Deployed Addresses + +The modules will be deployed to the same addresses on all chains: +- **AutoTopUpExecutor**: `0x92Be8FA04bF1d9Ee311F4B2754Ca22252ccA18D4` +- **AutoCollectExecutor**: `0x6647fA97ff1f04614A0A960dcF499545c4DcC431` + +### Notes + +- The contracts are deployed as immutable singletons (no upgradeability, no owner) +- Addresses are deterministic using Safe Singleton Factory +- The factory is deployed on 250+ chains at: `0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7` \ No newline at end of file diff --git a/typescript/packages/account-modules/script/verify.sh b/typescript/packages/account-modules/script/verify.sh new file mode 100755 index 0000000..d33727c --- /dev/null +++ b/typescript/packages/account-modules/script/verify.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# Script to verify deployed contracts on Basescan/Etherscan +# Usage: ./verify.sh [network] +# Example: ./verify.sh base-sepolia + +NETWORK=${1:-base-sepolia} + +# Contract addresses (same on all chains) +AUTO_TOPUP_ADDRESS="0x92Be8FA04bF1d9Ee311F4B2754Ca22252ccA18D4" +AUTO_COLLECT_ADDRESS="0x6647fA97ff1f04614A0A960dcF499545c4DcC431" + +echo "Verifying contracts on $NETWORK..." +echo "" + +# Verify AutoTopUpExecutor +echo "Verifying AutoTopUpExecutor at $AUTO_TOPUP_ADDRESS..." +forge verify-contract \ + --chain $NETWORK \ + --num-of-optimizations 200 \ + --compiler-version v0.8.30 \ + $AUTO_TOPUP_ADDRESS \ + src/AutoTopUpExecutor.sol:AutoTopUpExecutor + +echo "" + +# Verify AutoCollectExecutor +echo "Verifying AutoCollectExecutor at $AUTO_COLLECT_ADDRESS..." +forge verify-contract \ + --chain $NETWORK \ + --num-of-optimizations 200 \ + --compiler-version v0.8.30 \ + $AUTO_COLLECT_ADDRESS \ + src/AutoCollectExecutor.sol:AutoCollectExecutor + +echo "" +echo "Verification complete!" +echo "" +echo "View verified contracts:" +echo "- AutoTopUpExecutor: https://sepolia.basescan.org/address/$AUTO_TOPUP_ADDRESS#code" +echo "- AutoCollectExecutor: https://sepolia.basescan.org/address/$AUTO_COLLECT_ADDRESS#code" diff --git a/typescript/packages/account-modules/src/AutoCollectExecutor.sol b/typescript/packages/account-modules/src/AutoCollectExecutor.sol new file mode 100644 index 0000000..cef3065 --- /dev/null +++ b/typescript/packages/account-modules/src/AutoCollectExecutor.sol @@ -0,0 +1,558 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {IAutoCollectExecutor} from "./IAutoCollectExecutor.sol"; +import {ERC7579ExecutorBase} from "modulekit/src/module-bases/ERC7579ExecutorBase.sol"; +import {IModule} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; +import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; + +/** + * @title AutoCollectExecutor + * @notice ERC-7579 executor module for automatic ERC-20 token collection from service accounts + * @dev Enables permissionless triggering of pre-configured collections from service accounts to main accounts + */ +contract AutoCollectExecutor is IAutoCollectExecutor, ERC7579ExecutorBase, ReentrancyGuard { + using EnumerableSet for EnumerableSet.Bytes32Set; + + // ============ Storage ============ + + /// @dev ERC-7201 namespace for storage + /// @custom:storage-location erc7201:autocollect.storage.AutoCollectExecutor + // keccak256(abi.encode(uint256(keccak256("autocollect.storage.AutoCollectExecutor")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant STORAGE_NAMESPACE = 0x6ede4012bbf78b7156310dfe77e035f310125e160497f34e20b746b314ff2200; + + /// @custom:storage-namespace AutoCollectStorage + struct AutoCollectStorage { + // Config ID => user configuration + mapping(bytes32 => CollectConfig) configs; + // Config ID => internal state + mapping(bytes32 => CollectState) states; + // Account => set of config IDs + mapping(address => EnumerableSet.Bytes32Set) accountConfigs; + // Account => initialized status + mapping(address => bool) initializedAccounts; + } + + // ============ Constructor ============ + + constructor() {} + + // ============ Storage Access ============ + + function _getStorage() private pure returns (AutoCollectStorage storage $) { + assembly { + $.slot := STORAGE_NAMESPACE + } + } + + // ============ Module Management (ERC-7579) ============ + + /** + * @notice Called when module is installed for an account + * @param data Encoded initial configurations (optional) + * @dev Format: abi.encode(address[], CollectConfig[]) + * @dev Parallel arrays: assets and configs at same indices + */ + function onInstall(bytes calldata data) external override(IAutoCollectExecutor, IModule) { + AutoCollectStorage storage $ = _getStorage(); + address account = msg.sender; + + // Prevent double initialization + require(!$.initializedAccounts[account], "Already initialized"); + + // Mark account as initialized + $.initializedAccounts[account] = true; + + uint256 configCount = 0; + + // Optional: decode and set initial configurations + if (data.length > 0) { + // Decode as parallel arrays: assets and configs + (address[] memory assets, CollectConfig[] memory configs) = abi.decode(data, (address[], CollectConfig[])); + + // Validate array lengths match + require(assets.length == configs.length, InvalidConfigurationArrays()); + + configCount = assets.length; + + // Process each configuration using the public function + // This handles all validation, state initialization, and event emission + for (uint256 i = 0; i < assets.length; i++) { + configureCollection(assets[i], configs[i]); + } + } + + emit ModuleInstalled(account, configCount); + } + + /** + * @notice Called when module is uninstalled for an account + * @dev Additional data parameter is unused + */ + function onUninstall(bytes calldata) external override(IAutoCollectExecutor, IModule) { + AutoCollectStorage storage $ = _getStorage(); + + // Clean up all configs for this account + address account = msg.sender; + bytes32[] memory configIds = $.accountConfigs[account].values(); + + // Iterate in reverse to efficiently remove from set while deleting configs + for (uint256 i = configIds.length; i > 0; i--) { + bytes32 configId = configIds[i - 1]; + delete $.configs[configId]; + delete $.states[configId]; + $.accountConfigs[account].remove(configId); + } + + // Mark account as uninitialized + delete $.initializedAccounts[account]; + + emit ModuleUninstalled(account, configIds.length); + } + + /** + * @notice Returns whether this module is of a certain type + * @param _typeId The type ID to check + * @return True if this module is an executor (type 0x01) + */ + function isModuleType(uint256 _typeId) external pure override(IAutoCollectExecutor, IModule) returns (bool) { + return _typeId == TYPE_EXECUTOR; + } + + // ============ Configuration Management ============ + + /** + * @notice Configure a new collection or update an existing one + * @param asset The ERC-20 token address + * @param config The collection configuration + * @return configId The generated config ID + */ + function configureCollection(address asset, CollectConfig memory config) public returns (bytes32 configId) { + require(asset != address(0), InvalidAsset()); + require(config.target != address(0), InvalidTarget()); + + AutoCollectStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + configId = generateConfigId(msg.sender, asset); + + // Check if this is a new config + if ($.states[configId].asset == address(0)) { + // Initialize state for new config + $.states[configId] = CollectState({asset: asset, lastCollectDate: 0}); + + // Add to account's config set + $.accountConfigs[msg.sender].add(configId); + } + + // Update the configuration + _configureCollection(configId, config); + } + + /** + * @notice Update an existing collection configuration by ID + * @param configId The config ID to update + * @param config The new configuration + */ + function configureCollectionById(bytes32 configId, CollectConfig memory config) external { + AutoCollectStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + // Verify config exists and caller owns it + require($.states[configId].asset != address(0), ConfigNotFound()); + require($.accountConfigs[msg.sender].contains(configId), Unauthorized(configId, msg.sender)); + + // Update the configuration + _configureCollection(configId, config); + } + + /** + * @dev Internal function to configure a collection + * @dev IMPORTANT: This function does NOT validate that the config exists or belongs to the caller. + * @dev Caller must perform these checks before calling this function. + * @param configId The config ID to configure + * @param config The configuration to apply + */ + function _configureCollection(bytes32 configId, CollectConfig memory config) internal { + require(config.target != address(0), InvalidTarget()); + + AutoCollectStorage storage $ = _getStorage(); + CollectState memory state = $.states[configId]; + + bool wasEnabled = $.configs[configId].enabled; + $.configs[configId] = config; + + emit CollectionConfigured(msg.sender, state.asset, config.target, configId, config); + + // Emit enable/disable events if status changed + if (config.enabled && !wasEnabled) { + emit CollectionEnabled(msg.sender, state.asset, configId); + } else if (!config.enabled && wasEnabled) { + emit CollectionDisabled(msg.sender, state.asset, configId); + } + } + + /** + * @notice Enable a collection configuration by asset address + * @param asset The asset address + */ + function enableCollection(address asset) external { + bytes32 configId = generateConfigId(msg.sender, asset); + enableCollection(configId); + } + + /** + * @notice Enable a collection configuration by config ID + * @param configId The config ID to enable + */ + function enableCollection(bytes32 configId) public { + AutoCollectStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + CollectState memory state = $.states[configId]; + require(state.asset != address(0), ConfigNotFound()); + + // Verify caller owns this config + address account = msg.sender; + require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); + + if (!$.configs[configId].enabled) { + $.configs[configId].enabled = true; + emit CollectionEnabled(account, state.asset, configId); + } + } + + /** + * @notice Disable a collection configuration by asset address + * @param asset The asset address + */ + function disableCollection(address asset) external { + bytes32 configId = generateConfigId(msg.sender, asset); + disableCollection(configId); + } + + /** + * @notice Disable a collection configuration by config ID + * @param configId The config ID to disable + */ + function disableCollection(bytes32 configId) public { + AutoCollectStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + CollectState memory state = $.states[configId]; + require(state.asset != address(0), ConfigNotFound()); + + // Verify caller owns this config + address account = msg.sender; + require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); + + if ($.configs[configId].enabled) { + $.configs[configId].enabled = false; + emit CollectionDisabled(account, state.asset, configId); + } + } + + // ============ Execution ============ + + /** + * @notice Trigger all collections for a specific account + * @param account The service account to trigger collections for + * @dev Emits CollectionExecuted for each successful collection + */ + function triggerAllCollections(address account) external nonReentrant { + AutoCollectStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[account], ModuleNotInitialized(account)); + + bytes32[] memory configIds = $.accountConfigs[account].values(); + + // Calculate date once for all configs + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + + for (uint256 i = 0; i < configIds.length; i++) { + _tryExecuteCollection(configIds[i], account, year, month, day); + } + } + + /** + * @notice Trigger a specific collection by asset + * @param account The service account to collect from + * @param asset The asset to collect + * @dev Emits CollectionExecuted if successful, CollectionSkipped if conditions not met + */ + function triggerCollection(address account, address asset) external nonReentrant { + AutoCollectStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[account], ModuleNotInitialized(account)); + + bytes32 configId = generateConfigId(account, asset); + + // Verify config exists and belongs to the account + require($.states[configId].asset != address(0), ConfigNotFound()); + require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); + + // Calculate current date + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + + _tryExecuteCollection(configId, account, year, month, day); + } + + /** + * @notice Execute a collection transfer (external for try-catch) + * @param account The service account to transfer from + * @param asset The token address + * @param target The target address to transfer to + * @param amount The amount to transfer + * @dev Must be external/public for try-catch. Only callable by this contract. + */ + function _executeCollectionTransfer(address account, address asset, address target, uint256 amount) external { + require(msg.sender == address(this), "Only self"); + + bytes memory result = + _execute(account, asset, 0, abi.encodeWithSelector(IERC20.transfer.selector, target, amount)); + + // Check return value (handle non-standard tokens like USDT that don't return bool) + if (result.length > 0) { + require(result.length == 32, InvalidTransferReturn(result)); + require(abi.decode(result, (bool)), TransferReturnedFalse(result)); + } + } + + /** + * @dev Internal function to attempt a collection execution + * @param configId The config ID to execute + * @param account The service account that owns the configuration + * @param year Current year + * @param month Current month (1-12) + * @param day Current day (1-31) + * @dev Emits CollectionExecuted on success, CollectionSkipped for conditions not met + * @dev Uses graceful failure handling - does not revert on collection failures + */ + function _tryExecuteCollection(bytes32 configId, address account, uint256 year, uint256 month, uint256 day) + private + { + AutoCollectStorage storage $ = _getStorage(); + + CollectConfig memory config = $.configs[configId]; + CollectState storage state = $.states[configId]; + + // Validate and calculate collection + (bool canExecute, uint256 currentBalance, uint256 collectAmount, uint256 currentDate,) = + _validateAndCalculateCollection(config, state, account, year, month, day); + + if (!canExecute) { + // Always emit skip event for complete visibility + emit CollectionSkipped( + account, state.asset, configId, currentBalance, config.threshold, config.minimumRemaining, collectAmount + ); + return; + } + + // Try to execute transfer - wrapped in try-catch to prevent batch operation failure + // If this fails, other collections in the batch can still succeed + try this._executeCollectionTransfer(account, state.asset, config.target, collectAmount) { + // Update state AFTER successful transfer + state.lastCollectDate = currentDate; + emit CollectionExecuted(account, state.asset, config.target, configId, collectAmount); + } catch Error(string memory reason) { + emit CollectionFailed(account, state.asset, configId, reason); + } catch (bytes memory) { + emit CollectionFailed(account, state.asset, configId, "Transfer failed"); + } + } + + /** + * @dev Validates if a collection can be executed and calculates the amount + * @param config The collection configuration + * @param state The collection state (storage pointer for reading) + * @param account The service account + * @param year Current year + * @param month Current month (1-12) + * @param day Current day (1-31) + * @return canExecute Whether the collection can be executed + * @return currentBalance The current balance of the asset in the account + * @return collectAmount The amount that would be collected (balance - minimumRemaining) + * @return currentDate The encoded current date (YYYYMMDD) + * @return reason Error message if cannot execute + */ + function _validateAndCalculateCollection( + CollectConfig memory config, + CollectState memory state, + address account, + uint256 year, + uint256 month, + uint256 day + ) + private + view + returns ( + bool canExecute, + uint256 currentBalance, + uint256 collectAmount, + uint256 currentDate, + string memory reason + ) + { + // Check if enabled + if (!config.enabled) { + return (false, 0, 0, 0, "Collection not enabled"); + } + + // Check once per day limit using calendar days + currentDate = year * 10000 + month * 100 + day; + if (currentDate <= state.lastCollectDate) { + return (false, 0, 0, currentDate, "Already collected today"); + } + + // Get current balance + currentBalance = IERC20(state.asset).balanceOf(account); + + // Calculate collect amount (balance minus what we want to keep) + collectAmount = currentBalance >= config.minimumRemaining ? currentBalance - config.minimumRemaining : 0; + + // Check for zero balance (skip collection) + if (currentBalance == 0) { + return (false, currentBalance, collectAmount, currentDate, "Balance is zero"); + } + + // Check threshold requirement + if (currentBalance < config.threshold) { + return (false, currentBalance, collectAmount, currentDate, "Balance below threshold"); + } + + // Skip if nothing to collect + if (collectAmount == 0) { + return (false, currentBalance, collectAmount, currentDate, "Collect amount would be zero"); + } + + return (true, currentBalance, collectAmount, currentDate, ""); + } + + // ============ View Functions ============ + + /// @inheritdoc IAutoCollectExecutor + function isInitialized(address smartAccount) external view override(IAutoCollectExecutor, IModule) returns (bool) { + AutoCollectStorage storage $ = _getStorage(); + return $.initializedAccounts[smartAccount]; + } + + /** + * @notice Generate a config ID for given parameters + * @param account The service account + * @param asset The token address + * @return The generated config ID + */ + function generateConfigId(address account, address asset) public pure returns (bytes32) { + return keccak256(abi.encode("CollectConfig", account, asset)); + } + + /** + * @notice Get all collection configurations for an account + * @param account The account to query + * @return configs Array of configurations + * @return states Array of states + */ + function getCollectionConfigs(address account) + external + view + returns (CollectConfig[] memory configs, CollectState[] memory states) + { + AutoCollectStorage storage $ = _getStorage(); + + bytes32[] memory configIds = $.accountConfigs[account].values(); + configs = new CollectConfig[](configIds.length); + states = new CollectState[](configIds.length); + + for (uint256 i = 0; i < configIds.length; i++) { + configs[i] = $.configs[configIds[i]]; + states[i] = $.states[configIds[i]]; + } + } + + /** + * @notice Check if a collection can be executed + * @param account The account that owns the config + * @param asset The asset to check + * @return canExecute Whether the collection can be executed + * @return reason Reason if cannot execute + */ + function canExecuteCollection(address account, address asset) + external + view + returns (bool canExecute, string memory reason) + { + AutoCollectStorage storage $ = _getStorage(); + + bytes32 configId = generateConfigId(account, asset); + CollectConfig memory config = $.configs[configId]; + CollectState memory state = $.states[configId]; + + if (state.asset == address(0)) { + return (false, "Config not found"); + } + + if (!$.accountConfigs[account].contains(configId)) { + return (false, "Account doesn't own config"); + } + + if (!config.enabled) { + return (false, "Collection disabled"); + } + + // Get current date + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + + // Use shared validation logic + (bool canExec,,,, string memory errorReason) = + _validateAndCalculateCollection(config, state, account, year, month, day); + + return (canExec, errorReason); + } + + /** + * @notice Get collection config by asset + * @param account The service account + * @param asset The token address + * @return config The configuration + * @return state The state + */ + function getCollectionConfig(address account, address asset) + external + view + returns (CollectConfig memory config, CollectState memory state) + { + bytes32 configId = generateConfigId(account, asset); + AutoCollectStorage storage $ = _getStorage(); + config = $.configs[configId]; + state = $.states[configId]; + } + + /** + * @notice Get collection config by config ID + * @param configId The config ID + * @return config The configuration + * @return state The state + */ + function getCollectionConfigById(bytes32 configId) + external + view + returns (CollectConfig memory config, CollectState memory state) + { + AutoCollectStorage storage $ = _getStorage(); + config = $.configs[configId]; + state = $.states[configId]; + } +} diff --git a/typescript/packages/account-modules/src/AutoTopUpExecutor.sol b/typescript/packages/account-modules/src/AutoTopUpExecutor.sol new file mode 100644 index 0000000..effb355 --- /dev/null +++ b/typescript/packages/account-modules/src/AutoTopUpExecutor.sol @@ -0,0 +1,551 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {IAutoTopUpExecutor} from "./IAutoTopUpExecutor.sol"; +import {ERC7579ExecutorBase} from "modulekit/src/module-bases/ERC7579ExecutorBase.sol"; +import {IModule} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; +import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; + +/** + * @title AutoTopUpExecutor + * @notice ERC-7579 executor module for automatic ERC-20 token balance management + * @dev Enables permissionless triggering of pre-configured top-ups from Safe accounts to agent accounts + */ +contract AutoTopUpExecutor is IAutoTopUpExecutor, ERC7579ExecutorBase, ReentrancyGuard { + using EnumerableSet for EnumerableSet.Bytes32Set; + using SafeERC20 for IERC20; + + // ============ Storage ============ + + /// @dev ERC-7201 namespace for storage + /// @custom:storage-location erc7201:autotopup.storage.AutoTopUpExecutor + // keccak256(abi.encode(uint256(keccak256("autotopup.storage.AutoTopUpExecutor")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant STORAGE_NAMESPACE = 0xf1fdef444005737c1eaec423fc423d55d53d0a09b4618f0f50ba7fb8df2b0400; + + /// @custom:storage-namespace AutoTopUpStorage + struct AutoTopUpStorage { + // Config ID => user configuration + mapping(bytes32 => TopUpConfig) configs; + // Config ID => internal state + mapping(bytes32 => TopUpState) states; + // Account => set of config IDs + mapping(address => EnumerableSet.Bytes32Set) accountConfigs; + // Account => initialized status + mapping(address => bool) initializedAccounts; + } + + // ============ Constructor ============ + + constructor() {} + + // ============ Storage Access ============ + + function _getStorage() private pure returns (AutoTopUpStorage storage $) { + assembly { + $.slot := STORAGE_NAMESPACE + } + } + + // ============ Module Management (ERC-7579) ============ + + /** + * @notice Called when module is installed for an account + * @param data Encoded initial configurations (optional) + * @dev Format: abi.encode(address[], address[], TopUpConfig[]) + * @dev Parallel arrays: agents, assets, and configs at same indices + */ + function onInstall(bytes calldata data) external override(IAutoTopUpExecutor, IModule) { + AutoTopUpStorage storage $ = _getStorage(); + address account = msg.sender; + + // Prevent double initialization + require(!$.initializedAccounts[account], "Already initialized"); + + // Mark account as initialized + $.initializedAccounts[account] = true; + + uint256 configCount = 0; + + // Optional: decode and set initial configurations + if (data.length > 0) { + // Decode as parallel arrays: agents, assets, and configs + (address[] memory agents, address[] memory assets, TopUpConfig[] memory configs) = + abi.decode(data, (address[], address[], TopUpConfig[])); + + // Validate array lengths match + require(agents.length == assets.length && agents.length == configs.length, InvalidConfigurationArrays()); + + configCount = agents.length; + + // Process each configuration using the public function + // This handles all validation, state initialization, and event emission + for (uint256 i = 0; i < agents.length; i++) { + configureTopUp(agents[i], assets[i], configs[i]); + } + } + + emit ModuleInstalled(account, configCount); + } + + /** + * @notice Called when module is uninstalled for an account + * @dev Additional data parameter is unused + */ + function onUninstall(bytes calldata) external override(IAutoTopUpExecutor, IModule) { + AutoTopUpStorage storage $ = _getStorage(); + + // Clean up all configs for this account + address account = msg.sender; + bytes32[] memory configIds = $.accountConfigs[account].values(); + + // Iterate in reverse to efficiently remove from set while deleting configs + for (uint256 i = configIds.length; i > 0; i--) { + bytes32 configId = configIds[i - 1]; + delete $.configs[configId]; + delete $.states[configId]; + $.accountConfigs[account].remove(configId); + } + + // Mark account as uninitialized + delete $.initializedAccounts[account]; + + emit ModuleUninstalled(account, configIds.length); + } + + /** + * @notice Returns whether this module is of a certain type + * @param _typeId The type ID to check + * @return True if this module is an executor (type 0x01) + */ + function isModuleType(uint256 _typeId) external pure override(IAutoTopUpExecutor, IModule) returns (bool) { + return _typeId == TYPE_EXECUTOR; + } + + // ============ Configuration Management ============ + + /** + * @notice Configure a new top-up or update an existing one + * @param agent The agent account to top up + * @param asset The ERC-20 token address + * @param config The top-up configuration + * @return configId The generated config ID + */ + function configureTopUp(address agent, address asset, TopUpConfig memory config) public returns (bytes32 configId) { + require(agent != address(0) && agent != msg.sender, InvalidAgent()); + require(asset != address(0), InvalidAsset()); + + AutoTopUpStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + configId = generateConfigId(msg.sender, agent, asset); + + // Check if this is a new config + if ($.states[configId].agent == address(0)) { + // Initialize state for new config + $.states[configId] = + TopUpState({agent: agent, asset: asset, lastTopUpDay: 0, monthlySpent: 0, lastResetMonth: 0}); + + // Add to account's config set + $.accountConfigs[msg.sender].add(configId); + } + + // Update the configuration + _configureTopUp(configId, config); + } + + /** + * @notice Update an existing top-up configuration by ID + * @param configId The config ID to update + * @param config The new configuration + */ + function configureTopUpById(bytes32 configId, TopUpConfig memory config) external { + AutoTopUpStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + // Verify config exists and caller owns it + require($.states[configId].agent != address(0), ConfigNotFound()); + require($.accountConfigs[msg.sender].contains(configId), Unauthorized(configId, msg.sender)); + + // Update the configuration + _configureTopUp(configId, config); + } + + /** + * @dev Internal function to configure a top-up + * @dev IMPORTANT: This function does NOT validate that the config exists or belongs to the caller. + * @dev Caller must perform these checks before calling this function. + * @param configId The config ID to configure + * @param config The configuration to apply + */ + function _configureTopUp(bytes32 configId, TopUpConfig memory config) internal { + // Note: dailyLimit can be greater than monthlyLimit for use cases where users want + // monthly budget constraints but no daily restrictions + require(config.dailyLimit > 0 && config.monthlyLimit > 0, InvalidConfiguration()); + + AutoTopUpStorage storage $ = _getStorage(); + TopUpState memory state = $.states[configId]; + + bool wasEnabled = $.configs[configId].enabled; + $.configs[configId] = config; + + emit TopUpConfigured(msg.sender, state.agent, state.asset, configId, config); + + // Emit enable/disable events if status changed + if (config.enabled && !wasEnabled) { + emit TopUpEnabled(msg.sender, state.agent, state.asset, configId); + } else if (!config.enabled && wasEnabled) { + emit TopUpDisabled(msg.sender, state.agent, state.asset, configId); + } + } + + /** + * @notice Enable a top-up configuration + * @param configId The config ID to enable + */ + function enableTopUp(bytes32 configId) external { + AutoTopUpStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + TopUpState memory state = $.states[configId]; + require(state.agent != address(0), ConfigNotFound()); + + // Verify caller owns this config + address account = msg.sender; + require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); + + if (!$.configs[configId].enabled) { + $.configs[configId].enabled = true; + emit TopUpEnabled(account, state.agent, state.asset, configId); + } + } + + /** + * @notice Disable a top-up configuration + * @param configId The config ID to disable + */ + function disableTopUp(bytes32 configId) external { + AutoTopUpStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); + + TopUpState memory state = $.states[configId]; + require(state.agent != address(0), ConfigNotFound()); + + // Verify caller owns this config + address account = msg.sender; + require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); + + if ($.configs[configId].enabled) { + $.configs[configId].enabled = false; + emit TopUpDisabled(account, state.agent, state.asset, configId); + } + } + + // ============ Execution ============ + + /** + * @notice Trigger all top-ups for a specific account + * @param account The account to trigger top-ups for + * @dev Emits TopUpExecuted for each successful top-up + */ + function triggerTopUps(address account) external nonReentrant { + AutoTopUpStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[account], ModuleNotInitialized(account)); + + bytes32[] memory configIds = $.accountConfigs[account].values(); + + // Calculate date once for all configs + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + + for (uint256 i = 0; i < configIds.length; i++) { + _tryExecuteTopUp(configIds[i], account, year, month, day); + } + } + + /** + * @notice Trigger a specific top-up by config ID + * @param account The account that owns the config + * @param configId The config ID to trigger + * @dev Emits TopUpExecuted if successful, reverts on transfer failure + */ + function triggerTopUp(address account, bytes32 configId) external nonReentrant { + AutoTopUpStorage storage $ = _getStorage(); + + // Check if module is initialized for this account + require($.initializedAccounts[account], ModuleNotInitialized(account)); + + // Verify config exists and belongs to the account + require($.states[configId].agent != address(0), ConfigNotFound()); + require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); + + // Calculate current date + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + + _tryExecuteTopUp(configId, account, year, month, day); + } + + /** + * @notice Execute a top-up transfer (external for try-catch) + * @param account The main account to transfer from + * @param asset The token address + * @param agent The agent account to transfer to + * @param amount The amount to transfer + * @dev Must be external/public for try-catch. Only callable by this contract. + */ + function _executeTopUpTransfer(address account, address asset, address agent, uint256 amount) external { + require(msg.sender == address(this), "Only self"); + + bytes memory result = + _execute(account, asset, 0, abi.encodeWithSelector(IERC20.transfer.selector, agent, amount)); + + // Check return value (handle non-standard tokens like USDT that don't return bool) + if (result.length > 0) { + require(result.length == 32, InvalidTransferReturn(result)); + require(abi.decode(result, (bool)), TransferReturnedFalse(result)); + } + } + + /** + * @dev Internal function to attempt a top-up execution + * @param configId The config ID to execute + * @param account The Safe account that owns the configuration + * @param year Current year + * @param month Current month (1-12) + * @param day Current day (1-31) + * @dev Emits TopUpExecuted on success, TopUpFailed for insufficient balance + * @dev Reverts on transfer failure (indicates configuration error) + */ + /** + * @dev Validates if a top-up can be executed and calculates the amount + * @param config The top-up configuration + * @param state The top-up state (storage pointer for reading) + * @param account The Safe account + * @param year Current year + * @param month Current month (1-12) + * @param day Current day (1-31) + * @return canExecute Whether the top-up can be executed + * @return topUpAmount The amount to top up (0 if cannot execute) + * @return currentDay The encoded current day (YYYYMMDD) + * @return currentMonth The encoded current month (year * 12 + month) + * @return reason Error message if cannot execute + */ + function _validateAndCalculateTopUp( + TopUpConfig memory config, + TopUpState memory state, + address account, + uint256 year, + uint256 month, + uint256 day + ) + private + view + returns (bool canExecute, uint256 topUpAmount, uint256 currentDay, uint256 currentMonth, string memory reason) + { + // Check if enabled + if (!config.enabled) { + return (false, 0, 0, 0, "Top-up not enabled"); + } + + // Check once per day limit using calendar days + currentDay = year * 10000 + month * 100 + day; + if (currentDay <= state.lastTopUpDay) { + return (false, 0, currentDay, 0, "Already topped up today"); + } + + // Check monthly limit using calendar months + currentMonth = year * 12 + month; + uint256 monthlySpent = state.monthlySpent; + if (currentMonth > state.lastResetMonth) { + monthlySpent = 0; // Will be reset in actual execution + } + + // Check if agent needs top-up + uint256 agentBalance = IERC20(state.asset).balanceOf(state.agent); + if (agentBalance >= config.dailyLimit) { + return (false, 0, currentDay, currentMonth, "Agent balance sufficient"); + } + + // Calculate top-up amount + topUpAmount = config.dailyLimit - agentBalance; + + // Apply monthly limit + if (monthlySpent + topUpAmount > config.monthlyLimit) { + topUpAmount = config.monthlyLimit - monthlySpent; + if (topUpAmount == 0) { + return (false, 0, currentDay, currentMonth, "Monthly limit reached"); + } + } + + // Check account has sufficient balance + if (IERC20(state.asset).balanceOf(account) < topUpAmount) { + return (false, 0, currentDay, currentMonth, "Insufficient account balance"); + } + + return (true, topUpAmount, currentDay, currentMonth, ""); + } + + function _tryExecuteTopUp(bytes32 configId, address account, uint256 year, uint256 month, uint256 day) private { + AutoTopUpStorage storage $ = _getStorage(); + + TopUpConfig memory config = $.configs[configId]; + TopUpState storage state = $.states[configId]; + + // Validate and calculate top-up + (bool canExecute, uint256 topUpAmount, uint256 currentDay, uint256 currentMonth, string memory reason) = + _validateAndCalculateTopUp(config, state, account, year, month, day); + + if (!canExecute) { + // Only emit failure for insufficient balance (not for normal conditions like already topped up) + if (keccak256(bytes(reason)) == keccak256(bytes("Insufficient account balance"))) { + emit TopUpFailed(account, state.agent, state.asset, configId, reason); + } + return; + } + + // Try to execute transfer - wrapped in try-catch to prevent batch operation failure + // If this fails, other top-ups in the batch can still succeed + try this._executeTopUpTransfer(account, state.asset, state.agent, topUpAmount) { + // Update state AFTER successful transfer + + // Reset monthly counter if needed + if (currentMonth > state.lastResetMonth) { + state.monthlySpent = 0; + state.lastResetMonth = currentMonth; + } + + state.lastTopUpDay = currentDay; + state.monthlySpent += topUpAmount; + + emit TopUpExecuted(account, state.agent, state.asset, configId, topUpAmount); + } catch Error(string memory errorReason) { + emit TopUpFailed(account, state.agent, state.asset, configId, errorReason); + } catch (bytes memory) { + emit TopUpFailed(account, state.agent, state.asset, configId, "Transfer failed"); + } + } + + // ============ View Functions ============ + + /// @inheritdoc IAutoTopUpExecutor + function isInitialized(address smartAccount) external view override(IAutoTopUpExecutor, IModule) returns (bool) { + AutoTopUpStorage storage $ = _getStorage(); + return $.initializedAccounts[smartAccount]; + } + + /** + * @notice Generate a config ID for given parameters + * @param account The Safe account + * @param agent The agent account + * @param asset The token address + * @return The generated config ID + */ + function generateConfigId(address account, address agent, address asset) public pure returns (bytes32) { + return keccak256(abi.encode("TopUpConfig", account, agent, asset)); + } + + /** + * @notice Get all top-up configurations for an account + * @param account The account to query + * @return configs Array of configurations + * @return states Array of states + */ + function getTopUpConfigs(address account) + external + view + returns (TopUpConfig[] memory configs, TopUpState[] memory states) + { + AutoTopUpStorage storage $ = _getStorage(); + + bytes32[] memory configIds = $.accountConfigs[account].values(); + configs = new TopUpConfig[](configIds.length); + states = new TopUpState[](configIds.length); + + for (uint256 i = 0; i < configIds.length; i++) { + configs[i] = $.configs[configIds[i]]; + states[i] = $.states[configIds[i]]; + } + } + + /** + * @notice Check if a top-up can be executed + * @param account The account that owns the config + * @param configId The config ID to check + * @return canExecute Whether the top-up can be executed + * @return reason Reason if cannot execute + */ + function canExecuteTopUp(address account, bytes32 configId) + external + view + returns (bool canExecute, string memory reason) + { + AutoTopUpStorage storage $ = _getStorage(); + + TopUpConfig memory config = $.configs[configId]; + TopUpState memory state = $.states[configId]; + + if (state.agent == address(0)) { + return (false, "Config not found"); + } + + if (!$.accountConfigs[account].contains(configId)) { + return (false, "Account doesn't own config"); + } + + if (!config.enabled) { + return (false, "Top-up disabled"); + } + + // Get current date + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + + // Use shared validation logic + (bool canExec,,,, string memory errorReason) = + _validateAndCalculateTopUp(config, state, account, year, month, day); + + return (canExec, errorReason); + } + + /** + * @notice Get top-up by config ID + * @param configId The config ID + * @return config The configuration + * @return state The state + */ + function getTopUpById(bytes32 configId) external view returns (TopUpConfig memory config, TopUpState memory state) { + AutoTopUpStorage storage $ = _getStorage(); + config = $.configs[configId]; + state = $.states[configId]; + } + + /** + * @notice Get top-up by account, agent, and asset + * @param account The Safe account + * @param agent The agent account + * @param asset The token address + * @return config The configuration + * @return state The state + */ + function getTopUp(address account, address agent, address asset) + external + view + returns (TopUpConfig memory config, TopUpState memory state) + { + bytes32 configId = generateConfigId(account, agent, asset); + AutoTopUpStorage storage $ = _getStorage(); + config = $.configs[configId]; + state = $.states[configId]; + } +} diff --git a/typescript/packages/account-modules/src/IAutoCollectExecutor.sol b/typescript/packages/account-modules/src/IAutoCollectExecutor.sol new file mode 100644 index 0000000..caeb7b9 --- /dev/null +++ b/typescript/packages/account-modules/src/IAutoCollectExecutor.sol @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +/** + * @title IAutoCollectExecutor + * @notice Interface for the ERC-7579 executor module that manages automatic ERC-20 token collection + * @dev Enables permissionless triggering of pre-configured collections from service accounts to main accounts + */ +interface IAutoCollectExecutor { + // ============ Structs ============ + + /// @notice User-configurable parameters + struct CollectConfig { + address target; // Main account to collect funds to + uint256 threshold; // Minimum balance to trigger collection (0 = no threshold) + uint256 minimumRemaining; // Minimum amount to leave in account after collection (0 = collect all) + bool enabled; // Configuration active status + } + + /// @notice Immutable identity and internal state (not user-editable) + struct CollectState { + address asset; // ERC-20 token address (immutable, part of config ID) + uint256 lastCollectDate; // Last collection date (YYYYMMDD format) + } + + // ============ Events ============ + + event ModuleInstalled(address indexed account, uint256 initialConfigs); + + event ModuleUninstalled(address indexed account, uint256 removedConfigs); + + event CollectionConfigured( + address indexed account, address indexed asset, address target, bytes32 indexed configId, CollectConfig config + ); + + event CollectionExecuted( + address indexed account, address indexed asset, address target, bytes32 indexed configId, uint256 amount + ); + + event CollectionSkipped( + address indexed account, + address indexed asset, + bytes32 indexed configId, + uint256 balance, + uint256 threshold, + uint256 minimumRemaining, + uint256 collectAmount + ); + + event CollectionFailed(address indexed account, address indexed asset, bytes32 indexed configId, string reason); + + event CollectionEnabled(address indexed account, address indexed asset, bytes32 indexed configId); + + event CollectionDisabled(address indexed account, address indexed asset, bytes32 indexed configId); + + // ============ Errors ============ + + error ModuleNotInitialized(address account); + error InvalidConfiguration(); + error ConfigNotFound(); + error Unauthorized(bytes32 configId, address caller); + error InvalidAsset(); + error InvalidTarget(); + error AlreadyCollectedToday(); + error BalanceBelowThreshold(); + error InvalidConfigurationArrays(); + error TransferFailed(); + error InvalidTransferReturn(bytes result); + error TransferReturnedFalse(bytes result); + + // ============ Module Management (ERC-7579) ============ + + /** + * @notice Called when module is installed for an account + * @param data Encoded initial configurations (optional) + * @dev Format: abi.encode(address[], CollectConfig[]) + * @dev Parallel arrays: assets and configs at same indices + */ + function onInstall(bytes calldata data) external; + + /** + * @notice Called when module is uninstalled for an account + * @dev Additional data parameter is unused + */ + function onUninstall(bytes calldata) external; + + /** + * @notice Returns whether this module is of a certain type + * @param _typeId The type ID to check + * @return True if this module is an executor (type 0x01) + */ + function isModuleType(uint256 _typeId) external pure returns (bool); + + /** + * @notice Check if module is initialized for an account + * @param smartAccount The account to check + * @return Whether the module is initialized + */ + function isInitialized(address smartAccount) external view returns (bool); + + // ============ Configuration Management ============ + + /** + * @notice Configure a new collection or update an existing one + * @param asset The ERC-20 token address + * @param config The collection configuration + * @return configId The generated config ID + */ + function configureCollection(address asset, CollectConfig memory config) external returns (bytes32 configId); + + /** + * @notice Update an existing collection configuration by ID + * @param configId The config ID to update + * @param config The new configuration + */ + function configureCollectionById(bytes32 configId, CollectConfig memory config) external; + + /** + * @notice Enable a collection configuration by asset address + * @param asset The asset address + */ + function enableCollection(address asset) external; + + /** + * @notice Enable a collection configuration by config ID + * @param configId The config ID to enable + */ + function enableCollection(bytes32 configId) external; + + /** + * @notice Disable a collection configuration by asset address + * @param asset The asset address + */ + function disableCollection(address asset) external; + + /** + * @notice Disable a collection configuration by config ID + * @param configId The config ID to disable + */ + function disableCollection(bytes32 configId) external; + + // ============ Execution ============ + + /** + * @notice Trigger all collections for a specific account + * @param account The service account to trigger collections for + * @dev Emits CollectionExecuted for each successful collection + */ + function triggerAllCollections(address account) external; + + /** + * @notice Trigger a specific collection by asset + * @param account The service account to collect from + * @param asset The asset to collect + * @dev Emits CollectionExecuted if successful, CollectionSkipped if conditions not met + */ + function triggerCollection(address account, address asset) external; + + // ============ View Functions ============ + + /** + * @notice Generate a config ID for given parameters + * @param account The service account + * @param asset The token address + * @return The generated config ID + */ + function generateConfigId(address account, address asset) external pure returns (bytes32); + + /** + * @notice Get all collection configurations for an account + * @param account The account to query + * @return configs Array of configurations + * @return states Array of states + */ + function getCollectionConfigs(address account) + external + view + returns (CollectConfig[] memory configs, CollectState[] memory states); + + /** + * @notice Check if a collection can be executed + * @param account The account that owns the config + * @param asset The asset to check + * @return canExecute Whether the collection can be executed + * @return reason Reason if cannot execute + */ + function canExecuteCollection(address account, address asset) + external + view + returns (bool canExecute, string memory reason); + + /** + * @notice Get collection config by asset + * @param account The service account + * @param asset The token address + * @return config The configuration + * @return state The state + */ + function getCollectionConfig(address account, address asset) + external + view + returns (CollectConfig memory config, CollectState memory state); + + /** + * @notice Get collection config by config ID + * @param configId The config ID + * @return config The configuration + * @return state The state + */ + function getCollectionConfigById(bytes32 configId) + external + view + returns (CollectConfig memory config, CollectState memory state); +} diff --git a/typescript/packages/account-modules/src/IAutoTopUpExecutor.sol b/typescript/packages/account-modules/src/IAutoTopUpExecutor.sol new file mode 100644 index 0000000..1f27799 --- /dev/null +++ b/typescript/packages/account-modules/src/IAutoTopUpExecutor.sol @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +/** + * @title IAutoTopUpExecutor + * @notice Interface for the ERC-7579 executor module that manages automatic ERC-20 token balance top-ups + * @dev Enables permissionless triggering of pre-configured top-ups from Safe accounts to agent accounts + */ +interface IAutoTopUpExecutor { + // ============ Structs ============ + + /// @notice User-configurable parameters + struct TopUpConfig { + uint256 dailyLimit; // Target balance to maintain (max top-up per day) + uint256 monthlyLimit; // Maximum total top-ups per month + bool enabled; // Configuration active status + } + + /// @notice Immutable identity and internal state (not user-editable) + struct TopUpState { + address agent; // Target agent account (immutable, part of config ID) + address asset; // ERC-20 token address (immutable, part of config ID) + uint256 lastTopUpDay; // Last top-up day (year * 10000 + month * 100 + day) + uint256 monthlySpent; // Amount topped up this month + uint256 lastResetMonth; // Last reset month (year * 12 + month) + } + + // ============ Events ============ + + event ModuleInstalled(address indexed account, uint256 initialConfigs); + + event ModuleUninstalled(address indexed account, uint256 removedConfigs); + + event TopUpConfigured( + address indexed account, address indexed agent, address asset, bytes32 indexed configId, TopUpConfig config + ); + + event TopUpExecuted( + address indexed account, address indexed agent, address asset, bytes32 indexed configId, uint256 amount + ); + + event TopUpFailed( + address indexed account, address indexed agent, address asset, bytes32 indexed configId, string reason + ); + + event TopUpEnabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId); + + event TopUpDisabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId); + + // ============ Errors ============ + + error ModuleNotInitialized(address account); + error InvalidConfiguration(); + error ConfigNotFound(); + error Unauthorized(bytes32 configId, address caller); + error InvalidAgent(); + error InvalidAsset(); + error AlreadyToppedUpToday(); + error MonthlyLimitExceeded(); + error InsufficientBalance(); + error TopUpNotEnabled(); + error TransferFailed(); + error InvalidTransferReturn(bytes result); + error TransferReturnedFalse(bytes result); + error InvalidConfigurationArrays(); + + // ============ Module Management (ERC-7579) ============ + + /** + * @notice Called when module is installed for an account + * @param data Encoded initial configurations (optional) + * @dev Format: abi.encode(address[], address[], TopUpConfig[]) + * @dev Parallel arrays: agents, assets, and configs at same indices + */ + function onInstall(bytes calldata data) external; + + /** + * @notice Called when module is uninstalled for an account + * @dev Additional data parameter is unused + */ + function onUninstall(bytes calldata) external; + + /** + * @notice Returns whether this module is of a certain type + * @param _typeId The type ID to check + * @return True if this module is an executor (type 0x01) + */ + function isModuleType(uint256 _typeId) external pure returns (bool); + + /** + * @notice Check if module is initialized for an account + * @param smartAccount The account to check + * @return Whether the module is initialized + */ + function isInitialized(address smartAccount) external view returns (bool); + + // ============ Configuration Management ============ + + /** + * @notice Configure a new top-up or update an existing one + * @param agent The agent account to top up + * @param asset The ERC-20 token address + * @param config The top-up configuration + * @return configId The generated config ID + */ + function configureTopUp(address agent, address asset, TopUpConfig memory config) external returns (bytes32 configId); + + /** + * @notice Update an existing top-up configuration by ID + * @param configId The config ID to update + * @param config The new configuration + */ + function configureTopUpById(bytes32 configId, TopUpConfig memory config) external; + + /** + * @notice Enable a top-up configuration + * @param configId The config ID to enable + */ + function enableTopUp(bytes32 configId) external; + + /** + * @notice Disable a top-up configuration + * @param configId The config ID to disable + */ + function disableTopUp(bytes32 configId) external; + + // ============ Execution ============ + + /** + * @notice Trigger all top-ups for a specific account + * @param account The account to trigger top-ups for + * @dev Emits TopUpExecuted for each successful top-up + */ + function triggerTopUps(address account) external; + + /** + * @notice Trigger a specific top-up by config ID + * @param account The account that owns the config + * @param configId The config ID to trigger + * @dev Emits TopUpExecuted if successful, reverts on transfer failure + */ + function triggerTopUp(address account, bytes32 configId) external; + + // ============ View Functions ============ + + /** + * @notice Generate a config ID for given parameters + * @param account The Safe account + * @param agent The agent account + * @param asset The token address + * @return The generated config ID + */ + function generateConfigId(address account, address agent, address asset) external pure returns (bytes32); + + /** + * @notice Get all top-up configurations for an account + * @param account The account to query + * @return configs Array of configurations + * @return states Array of states + */ + function getTopUpConfigs(address account) + external + view + returns (TopUpConfig[] memory configs, TopUpState[] memory states); + + /** + * @notice Check if a top-up can be executed + * @param account The account that owns the config + * @param configId The config ID to check + * @return canExecute Whether the top-up can be executed + * @return reason Reason if cannot execute + */ + function canExecuteTopUp(address account, bytes32 configId) + external + view + returns (bool canExecute, string memory reason); + + /** + * @notice Get top-up by config ID + * @param configId The config ID + * @return config The configuration + * @return state The state + */ + function getTopUpById(bytes32 configId) external view returns (TopUpConfig memory config, TopUpState memory state); + + /** + * @notice Get top-up by account, agent, and asset + * @param account The Safe account + * @param agent The agent account + * @param asset The token address + * @return config The configuration + * @return state The state + */ + function getTopUp(address account, address agent, address asset) + external + view + returns (TopUpConfig memory config, TopUpState memory state); +} diff --git a/typescript/packages/account-modules/test/AutoCollectExecutor.integration.t.sol b/typescript/packages/account-modules/test/AutoCollectExecutor.integration.t.sol new file mode 100644 index 0000000..d03be8b --- /dev/null +++ b/typescript/packages/account-modules/test/AutoCollectExecutor.integration.t.sol @@ -0,0 +1,675 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Test, Vm, console2} from "forge-std/Test.sol"; +import { + RhinestoneModuleKit, + AccountType, + AccountInstance, + UserOpData +} from "modulekit/src/test/RhinestoneModuleKit.sol"; +import {ModuleKitHelpers} from "modulekit/src/test/ModuleKitHelpers.sol"; +import {AutoCollectExecutor} from "../src/AutoCollectExecutor.sol"; +import {IAutoCollectExecutor} from "../src/IAutoCollectExecutor.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { + IModule, + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK, + MODULE_TYPE_HOOK +} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; +import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; + +// Import mocks +import {MockERC20} from "./mocks/MockERC20.sol"; +import {MockUSDT} from "./mocks/MockUSDT.sol"; +import {MaliciousCollectToken} from "./mocks/MaliciousCollectToken.sol"; + +// Integration tests using RhinestoneModuleKit for proper Safe interaction +contract AutoCollectExecutorIntegrationTest is Test, RhinestoneModuleKit { + using SafeERC20 for IERC20; + using ModuleKitHelpers for AccountInstance; + + // Main contracts + AutoCollectExecutor public executor; + MockERC20 public token; + MockUSDT public usdt; + + // Test accounts + AccountInstance public serviceAccount; + address public mainAccount; + address public stranger; + + // Test constants + uint256 constant THRESHOLD = 10 ether; + uint256 constant INITIAL_SERVICE_BALANCE = 100 ether; + uint256 constant INITIAL_MAIN_BALANCE = 1000 ether; + + // Events from the module + event ModuleInstalled(address indexed account, uint256 initialConfigs); + event ModuleUninstalled(address indexed account, uint256 removedConfigs); + event CollectionConfigured( + address indexed account, + address indexed asset, + address target, + bytes32 indexed configId, + IAutoCollectExecutor.CollectConfig config + ); + event CollectionExecuted( + address indexed account, address indexed asset, address target, bytes32 indexed configId, uint256 amount + ); + event CollectionSkipped( + address indexed account, + address indexed asset, + bytes32 indexed configId, + uint256 balance, + uint256 threshold, + uint256 minimumRemaining, + uint256 collectAmount + ); + event CollectionFailed(address indexed account, address indexed asset, bytes32 indexed configId, string reason); + + function setUp() public { + // Initialize ModuleKit with Safe account type + super.init(); + + // Create test addresses + mainAccount = makeAddr("mainAccount"); + stranger = makeAddr("stranger"); + + // Deploy tokens + token = new MockERC20("Test Token", "TEST"); + usdt = new MockUSDT(); + + // Deploy AutoCollectExecutor module as singleton + executor = new AutoCollectExecutor(); + + // Create a Safe service account instance + serviceAccount = makeAccountInstance("service-account"); + + // Fund service account with tokens + token.mint(serviceAccount.account, INITIAL_SERVICE_BALANCE); + usdt.mint(serviceAccount.account, INITIAL_SERVICE_BALANCE); + + // Give main account some initial balance + token.mint(mainAccount, INITIAL_MAIN_BALANCE); + usdt.mint(mainAccount, INITIAL_MAIN_BALANCE); + } + + // ============ Module Installation with Safe ============ + + function test_Integration_InstallModule() public { + // Install the module on the service account using ModuleKit + // Note: Event emissions during UserOp execution cannot be tested with expectEmit + // due to ModuleKit's internal use of recordLogs(). Events are tested in unit tests. + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Verify module is properly installed and initialized + assertTrue(executor.isInitialized(serviceAccount.account)); + assertTrue(serviceAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); + } + + function test_Integration_InstallWithInitialConfigs() public { + // Prepare installation data with initial configurations + address[] memory assets = new address[](2); + IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](2); + + assets[0] = address(token); + assets[1] = address(usdt); + configs[0] = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + configs[1] = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD * 2, minimumRemaining: 0, enabled: true + }); + + bytes memory installData = abi.encode(assets, configs); + + // Install with initial configs using ModuleKit + // Events during UserOp execution are tested in unit tests + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), installData); + + // Verify configs were created + (IAutoCollectExecutor.CollectConfig[] memory retrievedConfigs,) = + executor.getCollectionConfigs(serviceAccount.account); + assertEq(retrievedConfigs.length, 2); + assertTrue(serviceAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); + } + + // ============ Execution Tests with Safe ============ + + function test_Integration_TriggerCollection_Success() public { + // Install module using ModuleKit + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + // Check balances before + uint256 serviceBalanceBefore = token.balanceOf(serviceAccount.account); + uint256 mainBalanceBefore = token.balanceOf(mainAccount); + assertEq(serviceBalanceBefore, INITIAL_SERVICE_BALANCE); + + // Expect the CollectionExecuted event + vm.expectEmit(true, true, true, true); + emit CollectionExecuted(serviceAccount.account, address(token), mainAccount, configId, serviceBalanceBefore); + + // Anyone can trigger the collection (permissionless) + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Check balances after + assertEq(token.balanceOf(serviceAccount.account), 0); // All collected + assertEq(token.balanceOf(mainAccount), mainBalanceBefore + serviceBalanceBefore); + } + + function test_Integration_TriggerCollection_NonStandardToken() public { + // Test with USDT-style token that has non-standard transfer + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(usdt), config); + + // Check initial state + uint256 serviceBalanceBefore = usdt.balanceOf(serviceAccount.account); + uint256 mainBalanceBefore = usdt.balanceOf(mainAccount); + + // Trigger collection with non-standard token + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(usdt)); + + // Verify transfer succeeded despite non-standard return + assertEq(usdt.balanceOf(serviceAccount.account), 0); + assertEq(usdt.balanceOf(mainAccount), mainBalanceBefore + serviceBalanceBefore); + } + + function test_Integration_TriggerAllCollections_BatchExecution() public { + // Setup multiple configs for the same account + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Configure collections for different tokens + vm.startPrank(serviceAccount.account); + IAutoCollectExecutor.CollectConfig memory tokenConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + IAutoCollectExecutor.CollectConfig memory usdtConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + executor.configureCollection(address(token), tokenConfig); + executor.configureCollection(address(usdt), usdtConfig); + vm.stopPrank(); + + // Record balances before + uint256 serviceTokenBefore = token.balanceOf(serviceAccount.account); + uint256 serviceUsdtBefore = usdt.balanceOf(serviceAccount.account); + uint256 mainTokenBefore = token.balanceOf(mainAccount); + uint256 mainUsdtBefore = usdt.balanceOf(mainAccount); + + // Trigger all collections for the service account + vm.prank(stranger); + executor.triggerAllCollections(serviceAccount.account); + + // Should have executed 2 collections (verify by checking balances) + assertEq(token.balanceOf(serviceAccount.account), 0); + assertEq(usdt.balanceOf(serviceAccount.account), 0); + assertEq(token.balanceOf(mainAccount), mainTokenBefore + serviceTokenBefore); + assertEq(usdt.balanceOf(mainAccount), mainUsdtBefore + serviceUsdtBefore); + } + + // ============ Daily Limit Tests ============ + + function test_Integration_DailyLimitReset() public { + // Setup config + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + // First collection (service has 100 ether, above threshold) + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + assertEq(token.balanceOf(serviceAccount.account), 0); + + // Add some tokens back + token.mint(serviceAccount.account, 50 ether); + + // Try to collect again same day - should fail (already collected today) + (bool canExecute, string memory reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); + assertFalse(canExecute); + assertEq(reason, "Already collected today"); + + // Move to next day + vm.warp(block.timestamp + 1 days); + + // Now can execute again (new day, service has 50 ether above threshold) + (canExecute, reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + + // Execute the collection + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + assertEq(token.balanceOf(serviceAccount.account), 0); + } + + function test_Integration_ThresholdEnforcement() public { + // Setup config with high threshold + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + uint256 highThreshold = INITIAL_SERVICE_BALANCE + 50 ether; + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: highThreshold, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + uint256 currentBalance = token.balanceOf(serviceAccount.account); + + // Should not collect - balance below threshold + vm.expectEmit(true, true, true, true); + emit CollectionSkipped( + serviceAccount.account, + address(token), + configId, + currentBalance, + highThreshold, + 0, // minimumRemaining + currentBalance // would collect (balance - 0) + ); + + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Balance should not change + assertEq(token.balanceOf(serviceAccount.account), INITIAL_SERVICE_BALANCE); + + // Add more tokens to exceed threshold + token.mint(serviceAccount.account, 60 ether); + + // Now should be able to collect + (bool canExecute, string memory reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + } + + // ============ Module Uninstall Tests ============ + + function test_Integration_UninstallModule_CleansState() + public + withModuleStorageClearValidation(serviceAccount, address(executor)) + { + // Install and configure using ModuleKit + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + vm.startPrank(serviceAccount.account); + IAutoCollectExecutor.CollectConfig memory tokenConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + IAutoCollectExecutor.CollectConfig memory usdtConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD * 2, minimumRemaining: 0, enabled: true + }); + executor.configureCollection(address(token), tokenConfig); + executor.configureCollection(address(usdt), usdtConfig); + vm.stopPrank(); + + // Verify configs exist + (IAutoCollectExecutor.CollectConfig[] memory configs,) = executor.getCollectionConfigs(serviceAccount.account); + assertEq(configs.length, 2); + + // Uninstall module using ModuleKit + // Events during UserOp execution are tested in unit tests + serviceAccount.uninstallModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Verify state is cleaned + assertFalse(executor.isInitialized(serviceAccount.account)); + assertFalse(serviceAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); + (configs,) = executor.getCollectionConfigs(serviceAccount.account); + assertEq(configs.length, 0); + } + + // ============ Reentrancy Protection Tests ============ + + function test_Integration_ReentrancyProtection() public { + // Deploy malicious token + MaliciousCollectToken malToken = new MaliciousCollectToken(); + + // Setup module with malicious token using ModuleKit + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + executor.configureCollection(address(malToken), config); + + // Set reentrancy target - malicious token will try to call back + malToken.setTarget(executor, serviceAccount.account, address(malToken)); + + // Fund service account with malicious tokens + malToken.mint(serviceAccount.account, INITIAL_SERVICE_BALANCE); + + // Try to trigger - reentrancy guard should prevent issues + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(malToken)); + + // Should have completed successfully despite reentrancy attempt + // Full balance should be collected + assertEq(malToken.balanceOf(serviceAccount.account), 0); + assertEq(malToken.balanceOf(mainAccount), INITIAL_SERVICE_BALANCE); + } + + // ============ Access Control Tests ============ + + function test_Integration_ModuleNotInitialized() public { + // Don't install module - test that uninitialized accounts can't configure + // Stranger cannot configure without module being installed for their account + vm.prank(stranger); + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); + executor.configureCollection(address(token), config); + } + + function test_Integration_CrossAccountConfigurationBlocked() public { + // Install module for serviceAccount only + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Service account can configure for itself + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + // Stranger cannot modify service account's configs (module not initialized for stranger) + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); + executor.disableCollection(configId); + } + + // ============ Edge Case Tests ============ + + function test_Integration_ZeroBalanceSkipped() public { + // Setup module using ModuleKit + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, + threshold: 0, // Zero threshold + minimumRemaining: 0, + enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + // Drain service account balance + vm.prank(serviceAccount.account); + token.transfer(mainAccount, INITIAL_SERVICE_BALANCE); + + uint256 currentBalance = token.balanceOf(serviceAccount.account); + assertEq(currentBalance, 0); + + // Try to trigger - should skip due to zero balance + vm.expectEmit(true, true, true, true); + emit CollectionSkipped( + serviceAccount.account, + address(token), + configId, + 0, // balance + 0, // threshold + 0, // minimumRemaining + 0 // would collect + ); + + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Balance should remain zero + assertEq(token.balanceOf(serviceAccount.account), 0); + } + + function test_Integration_DisabledConfigSkipped() public { + // Setup module using ModuleKit + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + // Disable the configuration + vm.prank(serviceAccount.account); + executor.disableCollection(configId); + + uint256 serviceBalanceBefore = token.balanceOf(serviceAccount.account); + uint256 mainBalanceBefore = token.balanceOf(mainAccount); + + // Try to trigger - should not execute (disabled) + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Balances should not change + assertEq(token.balanceOf(serviceAccount.account), serviceBalanceBefore); + assertEq(token.balanceOf(mainAccount), mainBalanceBefore); + } + + function test_Integration_PartialCollectionAfterThresholdChange() public { + // Setup with low threshold initially + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + // First collection should work (100 ether > 10 ether threshold) + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + assertEq(token.balanceOf(serviceAccount.account), 0); + + // Add some tokens back + token.mint(serviceAccount.account, 5 ether); + + // Update threshold to be higher than current balance + vm.prank(serviceAccount.account); + IAutoCollectExecutor.CollectConfig memory newConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: 20 ether, minimumRemaining: 0, enabled: true + }); + executor.configureCollectionById(configId, newConfig); + + // Move to next day + vm.warp(block.timestamp + 1 days); + + // Should not collect due to threshold (5 ether < 20 ether) + (bool canExecute, string memory reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); + assertFalse(canExecute); + assertEq(reason, "Balance below threshold"); + } + + // ============ Multi-Day Collection Tests ============ + + function test_Integration_CollectionAcrossDays() public { + // Setup config with zero threshold (collect any amount) + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + vm.prank(serviceAccount.account); + IAutoCollectExecutor.CollectConfig memory config = + IAutoCollectExecutor.CollectConfig({target: mainAccount, threshold: 0, minimumRemaining: 0, enabled: true}); + executor.configureCollection(address(token), config); + + // Day 1: Collect all balance + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + assertEq(token.balanceOf(serviceAccount.account), 0); + + // Add some tokens back same day + token.mint(serviceAccount.account, 30 ether); + + // Should not collect again same day + (bool canExecute, string memory reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); + assertFalse(canExecute); + assertEq(reason, "Already collected today"); + + // Move to next day + vm.warp(block.timestamp + 1 days); + + // Day 2: Should be able to collect again + uint256 mainBalanceBeforeDay2 = token.balanceOf(mainAccount); + + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Should have collected the 30 ether + assertEq(token.balanceOf(serviceAccount.account), 0); + assertEq(token.balanceOf(mainAccount), mainBalanceBeforeDay2 + 30 ether); + } + + // ============ Module Type Tests ============ + + function test_Integration_ModuleType() public { + // Verify module type - should only be true for EXECUTOR type + assertTrue(executor.isModuleType(MODULE_TYPE_EXECUTOR)); + assertFalse(executor.isModuleType(MODULE_TYPE_VALIDATOR)); + assertFalse(executor.isModuleType(MODULE_TYPE_FALLBACK)); + assertFalse(executor.isModuleType(MODULE_TYPE_HOOK)); + } + + // ============ Complex Scenarios ============ + + function test_Integration_MultipleServiceAccounts() public { + // Create second service account + AccountInstance memory serviceAccount2 = makeAccountInstance("service-account-2"); + + // Fund second service account + token.mint(serviceAccount2.account, INITIAL_SERVICE_BALANCE); + + // Install module on both accounts + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + serviceAccount2.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Configure collections on both accounts to same main account + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + executor.configureCollection(address(token), config); + + vm.prank(serviceAccount2.account); + executor.configureCollection(address(token), config); + + uint256 mainBalanceBefore = token.balanceOf(mainAccount); + + // Trigger collections from both accounts + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + vm.prank(stranger); + executor.triggerCollection(serviceAccount2.account, address(token)); + + // Both service accounts should be drained, main should receive both balances + assertEq(token.balanceOf(serviceAccount.account), 0); + assertEq(token.balanceOf(serviceAccount2.account), 0); + assertEq(token.balanceOf(mainAccount), mainBalanceBefore + (INITIAL_SERVICE_BALANCE * 2)); + } + + function test_Integration_ConfigurationUpdatesAfterExecution() public { + // Setup and execute first collection + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection(address(token), config); + + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Add tokens back + token.mint(serviceAccount.account, 40 ether); + + // Update configuration to new target + address newMainAccount = makeAddr("newMainAccount"); + vm.prank(serviceAccount.account); + IAutoCollectExecutor.CollectConfig memory newConfig = IAutoCollectExecutor.CollectConfig({ + target: newMainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + executor.configureCollectionById(configId, newConfig); + + // Move to next day and collect again + vm.warp(block.timestamp + 1 days); + + uint256 newMainBalanceBefore = token.balanceOf(newMainAccount); + + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Should collect to new target + assertEq(token.balanceOf(serviceAccount.account), 0); + assertEq(token.balanceOf(newMainAccount), newMainBalanceBefore + 40 ether); + } + + // ============ Integration Tests for MinimumRemaining ============ + + function test_Integration_PartialCollectionWithMinimumRemaining() public { + // Setup: Service account with 100 tokens, collect with 30 minimumRemaining + // Expected: Collect 70, leave 30 + uint256 minimumRemaining = 30 ether; + uint256 threshold = 50 ether; + + // Install module + serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Configure collection with minimumRemaining + vm.prank(serviceAccount.account); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + // Verify initial balances + assertEq(token.balanceOf(serviceAccount.account), INITIAL_SERVICE_BALANCE); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE); + + // Trigger collection + vm.prank(stranger); + executor.triggerCollection(serviceAccount.account, address(token)); + + // Verify partial collection - should leave minimumRemaining + uint256 expectedCollected = INITIAL_SERVICE_BALANCE - minimumRemaining; + assertEq(token.balanceOf(serviceAccount.account), minimumRemaining); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollected); + + // Verify config state persists + (IAutoCollectExecutor.CollectConfig memory config,) = executor.getCollectionConfigById(configId); + assertEq(config.minimumRemaining, minimumRemaining); + } +} diff --git a/typescript/packages/account-modules/test/AutoCollectExecutor.t.sol b/typescript/packages/account-modules/test/AutoCollectExecutor.t.sol new file mode 100644 index 0000000..6080146 --- /dev/null +++ b/typescript/packages/account-modules/test/AutoCollectExecutor.t.sol @@ -0,0 +1,1192 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Test, console2} from "forge-std/Test.sol"; +import {AutoCollectExecutor} from "../src/AutoCollectExecutor.sol"; +import {IAutoCollectExecutor} from "../src/IAutoCollectExecutor.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; +import { + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK, + MODULE_TYPE_HOOK +} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; + +// Import mocks +import {MockERC20} from "./mocks/MockERC20.sol"; +import {MockUSDT} from "./mocks/MockUSDT.sol"; +import {MockSafe} from "./mocks/MockSafe.sol"; +import {MockTokenReturnsFalse} from "./mocks/MockTokenReturnsFalse.sol"; + +// Test contract with proper inheritance for module testing +contract AutoCollectExecutorTest is Test { + // Main contracts + AutoCollectExecutor public executor; + MockERC20 public token; + MockUSDT public usdt; + MockSafe public serviceAccount; + + // Test addresses + address public owner; + address public mainAccount; + address public stranger; + + // Test constants + uint256 constant THRESHOLD = 10 ether; + uint256 constant INITIAL_SERVICE_BALANCE = 100 ether; + uint256 constant INITIAL_MAIN_BALANCE = 1000 ether; + + // Events to test + event ModuleInstalled(address indexed account, uint256 initialConfigs); + event ModuleUninstalled(address indexed account, uint256 removedConfigs); + event CollectionConfigured( + address indexed account, + address indexed asset, + address target, + bytes32 indexed configId, + IAutoCollectExecutor.CollectConfig config + ); + event CollectionExecuted( + address indexed account, address indexed asset, address target, bytes32 indexed configId, uint256 amount + ); + event CollectionSkipped( + address indexed account, + address indexed asset, + bytes32 indexed configId, + uint256 balance, + uint256 threshold, + uint256 minimumRemaining, + uint256 collectAmount + ); + event CollectionFailed(address indexed account, address indexed asset, bytes32 indexed configId, string reason); + event CollectionEnabled(address indexed account, address indexed asset, bytes32 indexed configId); + event CollectionDisabled(address indexed account, address indexed asset, bytes32 indexed configId); + + function setUp() public { + // Set up test accounts + owner = makeAddr("owner"); + mainAccount = makeAddr("mainAccount"); + stranger = makeAddr("stranger"); + + // Deploy test tokens + token = new MockERC20("Test Token", "TEST"); + usdt = new MockUSDT(); + + // Deploy mock service account (Safe) + serviceAccount = new MockSafe(owner); + + // Deploy AutoCollectExecutor as singleton + executor = new AutoCollectExecutor(); + + // Enable executor as module on service account + vm.prank(owner); + serviceAccount.enableModule(address(executor)); + + // Fund service account with tokens + token.mint(address(serviceAccount), INITIAL_SERVICE_BALANCE); + usdt.mint(address(serviceAccount), INITIAL_SERVICE_BALANCE); + + // Give main account some initial balance + token.mint(mainAccount, INITIAL_MAIN_BALANCE); + usdt.mint(mainAccount, INITIAL_MAIN_BALANCE); + } + + // ============ Module Installation Tests ============ + + function test_OnInstall_EmptyData() public { + // Install module without initial configs + vm.expectEmit(true, false, false, true); + emit ModuleInstalled(address(serviceAccount), 0); + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + assertTrue(executor.isInitialized(address(serviceAccount))); + } + + function test_OnInstall_WithSingleConfig() public { + // Prepare installation data + address[] memory assets = new address[](1); + IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](1); + + assets[0] = address(token); + configs[0] = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + bytes memory installData = abi.encode(assets, configs); + + // Calculate expected config ID + bytes32 configId = executor.generateConfigId(address(serviceAccount), address(token)); + + // Expect events + vm.expectEmit(true, true, true, true); + emit CollectionConfigured(address(serviceAccount), address(token), mainAccount, configId, configs[0]); + + vm.expectEmit(true, true, true, true); + emit CollectionEnabled(address(serviceAccount), address(token), configId); + + vm.expectEmit(true, false, false, true); + emit ModuleInstalled(address(serviceAccount), 1); + + vm.prank(address(serviceAccount)); + executor.onInstall(installData); + + assertTrue(executor.isInitialized(address(serviceAccount))); + + // Verify config was created + (IAutoCollectExecutor.CollectConfig memory config,) = executor.getCollectionConfigById(configId); + assertEq(config.target, mainAccount); + assertEq(config.threshold, THRESHOLD); + assertEq(config.minimumRemaining, 0); + assertTrue(config.enabled); + } + + function test_OnInstall_RevertInvalidAsset() public { + // Try to install with zero address asset + address[] memory assets = new address[](1); + IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](1); + + assets[0] = address(0); // Invalid + configs[0] = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + bytes memory installData = abi.encode(assets, configs); + + vm.prank(address(serviceAccount)); + vm.expectRevert(IAutoCollectExecutor.InvalidAsset.selector); + executor.onInstall(installData); + } + + function test_OnInstall_RevertInvalidTarget() public { + // Try to install with zero address target + address[] memory assets = new address[](1); + IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](1); + + assets[0] = address(token); + configs[0] = IAutoCollectExecutor.CollectConfig({ + target: address(0), threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); // Invalid target + + bytes memory installData = abi.encode(assets, configs); + + vm.prank(address(serviceAccount)); + vm.expectRevert(IAutoCollectExecutor.InvalidTarget.selector); + executor.onInstall(installData); + } + + // ============ Module Uninstallation Tests ============ + + function test_OnUninstall_CleansUpAllState() public { + // First install with configs + address[] memory assets = new address[](2); + IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](2); + + assets[0] = address(token); + assets[1] = address(usdt); + configs[0] = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + configs[1] = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + executor.onInstall(abi.encode(assets, configs)); + + // Verify installation + assertTrue(executor.isInitialized(address(serviceAccount))); + (IAutoCollectExecutor.CollectConfig[] memory retrievedConfigs,) = + executor.getCollectionConfigs(address(serviceAccount)); + assertEq(retrievedConfigs.length, 2); + + // Now uninstall + vm.expectEmit(true, false, false, true); + emit ModuleUninstalled(address(serviceAccount), 2); + + vm.prank(address(serviceAccount)); + executor.onUninstall(""); + + // Verify all state is cleaned + assertFalse(executor.isInitialized(address(serviceAccount))); + (retrievedConfigs,) = executor.getCollectionConfigs(address(serviceAccount)); + assertEq(retrievedConfigs.length, 0); + } + + // ============ Configuration Management Tests ============ + + function test_ConfigureCollection_NewConfig() public { + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + bytes32 expectedConfigId = executor.generateConfigId(address(serviceAccount), address(token)); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + assertEq(configId, expectedConfigId); + + // Verify config was created + (IAutoCollectExecutor.CollectConfig memory retrievedConfig, IAutoCollectExecutor.CollectState memory state) = + executor.getCollectionConfigById(configId); + assertEq(retrievedConfig.target, mainAccount); + assertEq(retrievedConfig.threshold, THRESHOLD); + assertTrue(retrievedConfig.enabled); + assertEq(state.asset, address(token)); + assertEq(state.lastCollectDate, 0); + } + + function test_ConfigureCollection_RevertInvalidAsset() public { + // Setup: Install module + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + // Try to configure with zero address asset + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.InvalidAsset.selector)); + executor.configureCollection(address(0), config); + } + + function test_ConfigureCollection_RevertInvalidTarget() public { + // Setup: Install module + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + // Try to configure with zero address target + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: address(0), threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.InvalidTarget.selector)); + executor.configureCollection(address(token), config); + } + + function test_ConfigureCollection_ZeroThreshold() public { + // Setup: Install module + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + // Test with zero threshold (should be valid - collect any balance) + IAutoCollectExecutor.CollectConfig memory config = + IAutoCollectExecutor.CollectConfig({target: mainAccount, threshold: 0, minimumRemaining: 0, enabled: true}); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Verify config was created successfully + (IAutoCollectExecutor.CollectConfig memory retrievedConfig,) = executor.getCollectionConfigById(configId); + assertEq(retrievedConfig.target, mainAccount); + assertEq(retrievedConfig.threshold, 0); + assertTrue(retrievedConfig.enabled); + } + + function test_ConfigureCollection_RevertNotInitialized() public { + // Don't install module - try to configure + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + vm.expectRevert( + abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, address(serviceAccount)) + ); + executor.configureCollection(address(token), config); + } + + // ============ Enable/Disable Tests ============ + + function test_EnableDisableCollection() public { + // Setup config (enabled by default) + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Disable it + vm.expectEmit(true, true, true, true); + emit CollectionDisabled(address(serviceAccount), address(token), configId); + + vm.prank(address(serviceAccount)); + executor.disableCollection(configId); + + // Verify it's disabled + (IAutoCollectExecutor.CollectConfig memory retrievedConfig,) = executor.getCollectionConfigById(configId); + assertFalse(retrievedConfig.enabled); + + // Enable it again + vm.expectEmit(true, true, true, true); + emit CollectionEnabled(address(serviceAccount), address(token), configId); + + vm.prank(address(serviceAccount)); + executor.enableCollection(configId); + + // Verify it's enabled + (retrievedConfig,) = executor.getCollectionConfigById(configId); + assertTrue(retrievedConfig.enabled); + } + + function test_EnableDisable_RevertUnauthorized() public { + // Setup config as service account + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Try to disable as stranger (should fail - module not initialized) + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); + executor.disableCollection(configId); + + // Try to enable as stranger (should fail - module not initialized) + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); + executor.enableCollection(configId); + } + + // ============ Configuration By ID Tests ============ + + function test_ConfigureCollectionById_Success() public { + // Setup: Install module and create initial config + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Update config by ID + address newTarget = makeAddr("newTarget"); + uint256 newThreshold = THRESHOLD * 2; + IAutoCollectExecutor.CollectConfig memory newConfig = IAutoCollectExecutor.CollectConfig({ + target: newTarget, threshold: newThreshold, minimumRemaining: 0, enabled: true + }); + + vm.expectEmit(true, true, true, true); + emit CollectionConfigured(address(serviceAccount), address(token), newTarget, configId, newConfig); + + vm.prank(address(serviceAccount)); + executor.configureCollectionById(configId, newConfig); + + // Verify config was updated + (IAutoCollectExecutor.CollectConfig memory retrievedConfig,) = executor.getCollectionConfigById(configId); + assertEq(retrievedConfig.target, newTarget); + assertEq(retrievedConfig.threshold, newThreshold); + assertTrue(retrievedConfig.enabled); + } + + function test_ConfigureCollectionById_RevertConfigNotFound() public { + // Install module but use non-existent configId + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + bytes32 nonExistentConfigId = keccak256("nonexistent"); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ConfigNotFound.selector)); + executor.configureCollectionById(nonExistentConfigId, config); + } + + function test_ConfigureCollectionById_RevertUnauthorized() public { + // Setup: Service account creates a config + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Stranger tries to update service account's config + IAutoCollectExecutor.CollectConfig memory newConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD * 2, minimumRemaining: 0, enabled: true + }); + + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); + executor.configureCollectionById(configId, newConfig); + } + + // ============ Execution Tests ============ + + function test_TriggerCollection_Success() public { + // Setup: Install module and configure collection + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Service account has balance above threshold + uint256 serviceBalanceBefore = token.balanceOf(address(serviceAccount)); + uint256 mainBalanceBefore = token.balanceOf(mainAccount); + assertEq(serviceBalanceBefore, INITIAL_SERVICE_BALANCE); + + // Expect the CollectionExecuted event + vm.expectEmit(true, true, true, true); + emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, serviceBalanceBefore); + + // Trigger the collection + executor.triggerCollection(address(serviceAccount), address(token)); + + // Verify the collection was executed (full balance transferred) + assertEq(token.balanceOf(address(serviceAccount)), 0); + assertEq(token.balanceOf(mainAccount), mainBalanceBefore + serviceBalanceBefore); + } + + function test_TriggerCollection_SkippedBelowThreshold() public { + // Setup with high threshold + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + uint256 highThreshold = INITIAL_SERVICE_BALANCE + 1 ether; + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: highThreshold, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + uint256 currentBalance = token.balanceOf(address(serviceAccount)); + + // Expect CollectionSkipped event + vm.expectEmit(true, true, true, true); + emit CollectionSkipped( + address(serviceAccount), + address(token), + configId, + currentBalance, + highThreshold, + 0, // minimumRemaining + currentBalance // would collect + ); + + // Trigger collection - should be skipped + executor.triggerCollection(address(serviceAccount), address(token)); + + // Balance should not change + assertEq(token.balanceOf(address(serviceAccount)), INITIAL_SERVICE_BALANCE); + } + + function test_TriggerAllCollections_MultipleAssets() public { + // Setup multiple configs for the same account + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + // Configure collections for both tokens + IAutoCollectExecutor.CollectConfig memory tokenConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + IAutoCollectExecutor.CollectConfig memory usdtConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.startPrank(address(serviceAccount)); + executor.configureCollection(address(token), tokenConfig); + executor.configureCollection(address(usdt), usdtConfig); + vm.stopPrank(); + + // Record balances before + uint256 serviceTokenBefore = token.balanceOf(address(serviceAccount)); + uint256 serviceUsdtBefore = usdt.balanceOf(address(serviceAccount)); + uint256 mainTokenBefore = token.balanceOf(mainAccount); + uint256 mainUsdtBefore = usdt.balanceOf(mainAccount); + + // Trigger all collections + vm.prank(stranger); + executor.triggerAllCollections(address(serviceAccount)); + + // Should have executed 2 collections + assertEq(token.balanceOf(address(serviceAccount)), 0); + assertEq(usdt.balanceOf(address(serviceAccount)), 0); + assertEq(token.balanceOf(mainAccount), mainTokenBefore + serviceTokenBefore); + assertEq(usdt.balanceOf(mainAccount), mainUsdtBefore + serviceUsdtBefore); + } + + // ============ Daily Limit Tests ============ + + function test_DailyLimitReset() public { + // Setup config + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // First collection should work + (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + + // Actually execute the collection + executor.triggerCollection(address(serviceAccount), address(token)); + + // Add some tokens back to service account + token.mint(address(serviceAccount), 50 ether); + + // Should not be able to collect again same day + (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertFalse(canExecute); + assertEq(reason, "Already collected today"); + + // Move to next day + vm.warp(block.timestamp + 1 days); + + // Now should be able to collect again + (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + } + + // ============ View Function Tests ============ + + function test_CanExecuteCollection_Conditions() public { + // Setup + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + executor.configureCollection(address(token), config); + + // Should be able to execute (service balance is above threshold) + (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + + // Test with disabled config + bytes32 configId = executor.generateConfigId(address(serviceAccount), address(token)); + vm.prank(address(serviceAccount)); + executor.disableCollection(configId); + + (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertFalse(canExecute); + assertEq(reason, "Collection disabled"); + } + + function test_GetCollectionConfig_Success() public { + // Setup: Install module and create config + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Test getCollectionConfig function + ( + IAutoCollectExecutor.CollectConfig memory retrievedConfig, + IAutoCollectExecutor.CollectState memory retrievedState + ) = executor.getCollectionConfig(address(serviceAccount), address(token)); + + assertEq(retrievedConfig.target, mainAccount); + assertEq(retrievedConfig.threshold, THRESHOLD); + assertTrue(retrievedConfig.enabled); + assertEq(retrievedState.asset, address(token)); + assertEq(retrievedState.lastCollectDate, 0); + } + + function test_GetCollectionConfig_NonExistentConfig() public { + // Test getCollectionConfig with non-existent config + (IAutoCollectExecutor.CollectConfig memory config, IAutoCollectExecutor.CollectState memory state) = + executor.getCollectionConfig(address(serviceAccount), address(token)); + + // Should return zero values for non-existent config + assertEq(config.target, address(0)); + assertEq(config.threshold, 0); + assertEq(config.minimumRemaining, 0); + assertFalse(config.enabled); + assertEq(state.asset, address(0)); + assertEq(state.lastCollectDate, 0); + } + + function test_CanExecuteCollection_ConfigNotFound() public { + bytes32 configId = executor.generateConfigId(address(serviceAccount), address(token)); + + (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + + assertFalse(canExecute); + assertEq(reason, "Config not found"); + } + + function test_GetCollectionConfigs() public { + // Install module and create multiple configs + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory tokenConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + IAutoCollectExecutor.CollectConfig memory usdtConfig = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD * 2, minimumRemaining: 0, enabled: true + }); + + vm.startPrank(address(serviceAccount)); + executor.configureCollection(address(token), tokenConfig); + executor.configureCollection(address(usdt), usdtConfig); + vm.stopPrank(); + + // Get all configs + (IAutoCollectExecutor.CollectConfig[] memory configs, IAutoCollectExecutor.CollectState[] memory states) = + executor.getCollectionConfigs(address(serviceAccount)); + + assertEq(configs.length, 2); + assertEq(states.length, 2); + + // Verify configs (order might vary due to EnumerableSet) + bool foundToken = false; + bool foundUsdt = false; + + for (uint256 i = 0; i < configs.length; i++) { + if (states[i].asset == address(token)) { + foundToken = true; + assertEq(configs[i].target, mainAccount); + assertEq(configs[i].threshold, THRESHOLD); + assertTrue(configs[i].enabled); + } else if (states[i].asset == address(usdt)) { + foundUsdt = true; + assertEq(configs[i].target, mainAccount); + assertEq(configs[i].threshold, THRESHOLD * 2); + assertTrue(configs[i].enabled); + } + } + + assertTrue(foundToken); + assertTrue(foundUsdt); + } + + // ============ Date Boundary Tests ============ + + function test_YearTransition() public { + // Setup config + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + executor.configureCollection(address(token), config); + + // Set time to Dec 31, 2023 + vm.warp(1704067199); // Dec 31, 2023 23:59:59 UTC + + // Execute collection on last day of year + executor.triggerCollection(address(serviceAccount), address(token)); + + // Add tokens back + token.mint(address(serviceAccount), 50 ether); + + // Should not execute again same day + (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertFalse(canExecute); + assertEq(reason, "Already collected today"); + + // Move to Jan 1, 2024 (next year) + vm.warp(1704067200); // Jan 1, 2024 00:00:00 UTC + + // Should be able to execute (new day and new year) + (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + } + + function test_LeapYearFebruary() public { + // Setup config + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + executor.configureCollection(address(token), config); + + // Set time to Feb 28, 2024 (leap year) + vm.warp(1709078400); // Feb 28, 2024 00:00:00 UTC + + // Execute collection on Feb 28 + executor.triggerCollection(address(serviceAccount), address(token)); + + // Add tokens back + token.mint(address(serviceAccount), 50 ether); + + // Move to Feb 29 (leap day) + vm.warp(1709164800); // Feb 29, 2024 00:00:00 UTC + + // Should be able to execute on leap day + (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + + executor.triggerCollection(address(serviceAccount), address(token)); + + // Add tokens back again + token.mint(address(serviceAccount), 50 ether); + + // Move to March 1 + vm.warp(1709251200); // March 1, 2024 00:00:00 UTC + + // Should be able to execute on March 1 + (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + } + + // ============ Fuzz Tests ============ + + function testFuzz_DailyExecutionLimit(uint32 startTimestamp, uint32 timeDelta) public { + // Test that daily execution limit is enforced across various start times and deltas + // Bound start timestamp to reasonable range (year 2020-2030) + uint256 startTime = bound(uint256(startTimestamp), 1577836800, 1893456000); // 2020-2030 + vm.warp(startTime); + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + executor.configureCollection(address(token), config); + + // Execute first collection + executor.triggerCollection(address(serviceAccount), address(token)); + + // Add tokens back + token.mint(address(serviceAccount), 50 ether); + + // Calculate seconds remaining in current calendar day + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + uint256 endOfDay = BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day) + 86400 - 1; + uint256 secondsLeftInDay = endOfDay - block.timestamp; + + // Bound time delta to stay within current calendar day + uint256 deltaSeconds = bound(uint256(timeDelta), 0, secondsLeftInDay); + vm.warp(block.timestamp + deltaSeconds); + + // Should not be able to execute again same calendar day + (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertFalse(canExecute); + assertEq(reason, "Already collected today"); + + // Move to next calendar day + vm.warp(block.timestamp + (secondsLeftInDay - deltaSeconds) + 1); + + // Now should be able to execute + (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); + assertTrue(canExecute); + assertEq(reason, ""); + } + + function testFuzz_ConfigurationThresholds(uint256 threshold) public { + // Bound to reasonable values + threshold = bound(threshold, 0, type(uint128).max); + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + // Should succeed with any threshold + IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: 0, enabled: true + }); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection(address(token), config); + + // Verify config was stored correctly + (IAutoCollectExecutor.CollectConfig memory retrieved,) = executor.getCollectionConfigById(configId); + assertEq(retrieved.target, mainAccount); + assertEq(retrieved.threshold, threshold); + assertTrue(retrieved.enabled); + } + + // ============ Module Type Tests ============ + + function test_IsModuleType() public { + assertTrue(executor.isModuleType(MODULE_TYPE_EXECUTOR)); + assertFalse(executor.isModuleType(MODULE_TYPE_VALIDATOR)); + assertFalse(executor.isModuleType(MODULE_TYPE_FALLBACK)); + assertFalse(executor.isModuleType(MODULE_TYPE_HOOK)); + } + + // ============ Error Cases Tests ============ + + function test_TriggerCollection_RevertModuleNotInitialized() public { + // Don't install module - try to trigger + vm.expectRevert( + abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, address(serviceAccount)) + ); + executor.triggerCollection(address(serviceAccount), address(token)); + } + + function test_TriggerCollection_RevertConfigNotFound() public { + // Install module but don't create config + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ConfigNotFound.selector)); + executor.triggerCollection(address(serviceAccount), address(token)); + } + + // ============ MinimumRemaining Tests ============ + + function test_CollectWithMinimumRemaining() public { + // Setup: 100 USDC balance, threshold 50, minimumRemaining 20 + // Expected: Collect 80, leave 20 + uint256 minimumRemaining = 20 ether; + uint256 threshold = 50 ether; + + // Install and configure + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + // Verify initial balance + assertEq(token.balanceOf(address(serviceAccount)), INITIAL_SERVICE_BALANCE); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE); + + // Trigger collection + uint256 expectedCollectAmount = INITIAL_SERVICE_BALANCE - minimumRemaining; + + vm.expectEmit(true, true, true, true); + emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, expectedCollectAmount); + + executor.triggerCollection(address(serviceAccount), address(token)); + + // Verify balances + assertEq(token.balanceOf(address(serviceAccount)), minimumRemaining); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollectAmount); + } + + function test_CollectWithZeroThresholdAndMinimumRemaining() public { + // Setup: 100 USDC balance, threshold 0, minimumRemaining 30 + // Expected: Collect 70, leave 30 + uint256 minimumRemaining = 30 ether; + uint256 threshold = 0; + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + // Trigger collection + uint256 expectedCollectAmount = INITIAL_SERVICE_BALANCE - minimumRemaining; + + vm.expectEmit(true, true, true, true); + emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, expectedCollectAmount); + + executor.triggerCollection(address(serviceAccount), address(token)); + + // Verify balances + assertEq(token.balanceOf(address(serviceAccount)), minimumRemaining); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollectAmount); + } + + function test_SkipCollectionWhenMinimumRemainingEqualsBalance() public { + // Setup: 50 USDC balance, threshold 20, minimumRemaining 50 + // Expected: Skip (collect amount = 0) + uint256 balance = 50 ether; + uint256 minimumRemaining = 50 ether; + uint256 threshold = 20 ether; + + // Set service account balance to exactly minimumRemaining + token.burn(address(serviceAccount), INITIAL_SERVICE_BALANCE - balance); + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + // Expect CollectionSkipped event + vm.expectEmit(true, true, true, true); + emit CollectionSkipped( + address(serviceAccount), + address(token), + configId, + balance, // current balance + threshold, + minimumRemaining, + 0 // would collect amount + ); + + executor.triggerCollection(address(serviceAccount), address(token)); + + // Verify balances unchanged + assertEq(token.balanceOf(address(serviceAccount)), balance); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE); + } + + function test_SkipCollectionWhenMinimumRemainingExceedsBalance() public { + // Setup: 40 USDC balance, threshold 20, minimumRemaining 50 + // Expected: Skip (can't leave 50 when we only have 40) + uint256 balance = 40 ether; + uint256 minimumRemaining = 50 ether; + uint256 threshold = 20 ether; + + // Set service account balance + token.burn(address(serviceAccount), INITIAL_SERVICE_BALANCE - balance); + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + // Expect CollectionSkipped event + vm.expectEmit(true, true, true, true); + emit CollectionSkipped( + address(serviceAccount), + address(token), + configId, + balance, // current balance + threshold, + minimumRemaining, + 0 // would collect amount (balance < minimumRemaining, so 0) + ); + + executor.triggerCollection(address(serviceAccount), address(token)); + + // Verify balances unchanged + assertEq(token.balanceOf(address(serviceAccount)), balance); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE); + } + + function test_MinimumRemainingGreaterThanThreshold() public { + // Setup: 100 USDC balance, threshold 10, minimumRemaining 80 + // Expected: Collect 20, leave 80 (triggers at 10 but keeps 80) + uint256 minimumRemaining = 80 ether; + uint256 threshold = 10 ether; + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + // Trigger collection + uint256 expectedCollectAmount = INITIAL_SERVICE_BALANCE - minimumRemaining; + + vm.expectEmit(true, true, true, true); + emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, expectedCollectAmount); + + executor.triggerCollection(address(serviceAccount), address(token)); + + // Verify balances + assertEq(token.balanceOf(address(serviceAccount)), minimumRemaining); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollectAmount); + } + + function test_MinimumRemainingEqualsThreshold() public { + // Setup: 100 USDC balance, threshold 50, minimumRemaining 50 + // Expected: Collect 50, leave 50 + uint256 minimumRemaining = 50 ether; + uint256 threshold = 50 ether; + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + // Trigger collection + uint256 expectedCollectAmount = INITIAL_SERVICE_BALANCE - minimumRemaining; + + vm.expectEmit(true, true, true, true); + emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, expectedCollectAmount); + + executor.triggerCollection(address(serviceAccount), address(token)); + + // Verify balances + assertEq(token.balanceOf(address(serviceAccount)), minimumRemaining); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollectAmount); + } + + function test_CollectionSkippedEventIncludesMinimumRemaining() public { + // Verify new event parameters are emitted correctly when skipping + uint256 threshold = 200 ether; // Higher than balance + uint256 minimumRemaining = 10 ether; + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true + }) + ); + + uint256 currentBalance = INITIAL_SERVICE_BALANCE; + uint256 wouldCollect = currentBalance - minimumRemaining; + + // Expect CollectionSkipped with all parameters + vm.expectEmit(true, true, true, true); + emit CollectionSkipped( + address(serviceAccount), address(token), configId, currentBalance, threshold, minimumRemaining, wouldCollect + ); + + executor.triggerCollection(address(serviceAccount), address(token)); + } + + // ============ Batch Failure Tests ============ + + function test_TriggerAllCollections_PartialFailure() public { + // Test that if one collection fails, others still succeed + // This demonstrates resilience of batch operations with try-catch + + // Import the bad token mock + MockTokenReturnsFalse badToken = new MockTokenReturnsFalse(); + badToken.mint(address(serviceAccount), INITIAL_SERVICE_BALANCE); + + // Install module + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + // Configure 3 collections: good token, bad token, good USDT + vm.prank(address(serviceAccount)); + bytes32 goodConfigId1 = executor.configureCollection( + address(token), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }) + ); + + vm.prank(address(serviceAccount)); + bytes32 badConfigId = executor.configureCollection( + address(badToken), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }) + ); + + vm.prank(address(serviceAccount)); + bytes32 goodConfigId2 = executor.configureCollection( + address(usdt), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }) + ); + + // Trigger all collections - should not revert despite badToken failure + executor.triggerAllCollections(address(serviceAccount)); + + // Verify: good tokens collected, bad token remained + assertEq(token.balanceOf(address(serviceAccount)), 0); + assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + INITIAL_SERVICE_BALANCE); + + assertEq(badToken.balanceOf(address(serviceAccount)), INITIAL_SERVICE_BALANCE); // Failed - balance unchanged + assertEq(badToken.balanceOf(mainAccount), 0); + + assertEq(usdt.balanceOf(address(serviceAccount)), 0); + assertEq(usdt.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + INITIAL_SERVICE_BALANCE); + } + + function test_CollectionFailed_EmitsCorrectReason() public { + // Test that CollectionFailed event contains meaningful error message + MockTokenReturnsFalse badToken = new MockTokenReturnsFalse(); + badToken.mint(address(serviceAccount), INITIAL_SERVICE_BALANCE); + + vm.prank(address(serviceAccount)); + executor.onInstall(""); + + vm.prank(address(serviceAccount)); + bytes32 configId = executor.configureCollection( + address(badToken), + IAutoCollectExecutor.CollectConfig({ + target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true + }) + ); + + // Should emit CollectionFailed with generic reason (custom errors fall to catch(bytes)) + vm.expectEmit(true, true, true, true); + emit CollectionFailed(address(serviceAccount), address(badToken), configId, "Transfer failed"); + + executor.triggerCollection(address(serviceAccount), address(badToken)); + + // Verify state was NOT updated (no collection happened) + (, IAutoCollectExecutor.CollectState memory state) = executor.getCollectionConfigById(configId); + assertEq(state.lastCollectDate, 0); // Should remain 0 since transfer failed + } +} diff --git a/typescript/packages/account-modules/test/AutoTopUpExecutor.integration.t.sol b/typescript/packages/account-modules/test/AutoTopUpExecutor.integration.t.sol new file mode 100644 index 0000000..77e78a5 --- /dev/null +++ b/typescript/packages/account-modules/test/AutoTopUpExecutor.integration.t.sol @@ -0,0 +1,441 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Test, Vm, console2} from "forge-std/Test.sol"; +import { + RhinestoneModuleKit, + AccountType, + AccountInstance, + UserOpData +} from "modulekit/src/test/RhinestoneModuleKit.sol"; +import {ModuleKitHelpers} from "modulekit/src/test/ModuleKitHelpers.sol"; +import {AutoTopUpExecutor} from "../src/AutoTopUpExecutor.sol"; +import {IAutoTopUpExecutor} from "../src/IAutoTopUpExecutor.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { + IModule, + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK, + MODULE_TYPE_HOOK +} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; +import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; + +// Import mocks +import {MockERC20} from "./mocks/MockERC20.sol"; +import {MockUSDT} from "./mocks/MockUSDT.sol"; +import {MaliciousToken} from "./mocks/MaliciousToken.sol"; + +// Integration tests using RhinestoneModuleKit for proper Safe interaction +contract AutoTopUpExecutorIntegrationTest is Test, RhinestoneModuleKit { + using SafeERC20 for IERC20; + using ModuleKitHelpers for AccountInstance; + + // Main contracts + AutoTopUpExecutor public executor; + MockERC20 public token; + MockUSDT public usdt; + + // Test accounts + AccountInstance public safeAccount; + address public agent1; + address public agent2; + address public stranger; + + // Test constants + uint256 constant DAILY_LIMIT = 100 ether; + uint256 constant MONTHLY_LIMIT = 1000 ether; + uint256 constant INITIAL_SAFE_BALANCE = 10000 ether; + uint256 constant INITIAL_AGENT_BALANCE = 50 ether; + + // Events from the module + event ModuleInstalled(address indexed account, uint256 initialConfigs); + event ModuleUninstalled(address indexed account, uint256 removedConfigs); + event TopUpConfigured( + address indexed account, + address indexed agent, + address asset, + bytes32 indexed configId, + IAutoTopUpExecutor.TopUpConfig config + ); + event TopUpExecuted( + address indexed account, address indexed agent, address asset, bytes32 indexed configId, uint256 amount + ); + event TopUpFailed( + address indexed account, address indexed agent, address asset, bytes32 indexed configId, string reason + ); + + function setUp() public { + // Initialize ModuleKit with Safe account type + super.init(); + + // Create test addresses + agent1 = makeAddr("agent1"); + agent2 = makeAddr("agent2"); + stranger = makeAddr("stranger"); + + // Deploy tokens + token = new MockERC20("Test Token", "TEST"); + usdt = new MockUSDT(); + + // Deploy AutoTopUpExecutor module as singleton + executor = new AutoTopUpExecutor(); + + // Create a Safe account instance + safeAccount = makeAccountInstance("safe-account"); + + // Fund Safe account with tokens + token.mint(safeAccount.account, INITIAL_SAFE_BALANCE); + usdt.mint(safeAccount.account, INITIAL_SAFE_BALANCE); + + // Give agents some initial balance (below daily limit) + token.mint(agent1, INITIAL_AGENT_BALANCE); + token.mint(agent2, INITIAL_AGENT_BALANCE); + usdt.mint(agent1, INITIAL_AGENT_BALANCE); + usdt.mint(agent2, INITIAL_AGENT_BALANCE); + } + + // ============ Module Installation with Safe ============ + + function test_Integration_InstallModule() public { + // Install the module on the Safe account using ModuleKit + // Note: Event emissions during UserOp execution cannot be tested with expectEmit + // due to ModuleKit's internal use of recordLogs(). Events are tested in unit tests. + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Verify module is properly installed and initialized + assertTrue(executor.isInitialized(safeAccount.account)); + assertTrue(safeAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); + } + + function test_Integration_InstallWithInitialConfigs() public { + // Prepare installation data with initial configurations + address[] memory agents = new address[](2); + address[] memory assets = new address[](2); + IAutoTopUpExecutor.TopUpConfig[] memory configs = new IAutoTopUpExecutor.TopUpConfig[](2); + + agents[0] = agent1; + agents[1] = agent2; + assets[0] = address(token); + assets[1] = address(token); + + configs[0] = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + configs[1] = IAutoTopUpExecutor.TopUpConfig({ + dailyLimit: DAILY_LIMIT / 2, monthlyLimit: MONTHLY_LIMIT / 2, enabled: false + }); + + bytes memory installData = abi.encode(agents, assets, configs); + + // Install with initial configs using ModuleKit + // Events during UserOp execution are tested in unit tests + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), installData); + + // Verify configs were created + (IAutoTopUpExecutor.TopUpConfig[] memory retrievedConfigs,) = executor.getTopUpConfigs(safeAccount.account); + assertEq(retrievedConfigs.length, 2); + assertTrue(safeAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); + } + + // ============ Execution Tests with Safe ============ + + function test_Integration_TriggerTopUp_Success() public { + // Install module using ModuleKit + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(safeAccount.account); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Check agent balance before + uint256 agentBalanceBefore = token.balanceOf(agent1); + assertEq(agentBalanceBefore, INITIAL_AGENT_BALANCE); + + // Calculate expected top-up amount + uint256 expectedTopUp = DAILY_LIMIT - agentBalanceBefore; + + // Expect the TopUpExecuted event + vm.expectEmit(true, true, true, true); + emit TopUpExecuted(safeAccount.account, agent1, address(token), configId, expectedTopUp); + + // Anyone can trigger the top-up (permissionless) + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + + // Check agent balance after + uint256 agentBalanceAfter = token.balanceOf(agent1); + assertEq(agentBalanceAfter, DAILY_LIMIT); + + // Check Safe balance decreased + assertEq(token.balanceOf(safeAccount.account), INITIAL_SAFE_BALANCE - expectedTopUp); + } + + function test_Integration_TriggerTopUp_NonStandardToken() public { + // Test with USDT-style token that has non-standard transfer + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(safeAccount.account); + bytes32 configId = executor.configureTopUp(agent1, address(usdt), config); + + // Check initial state + uint256 agentBalanceBefore = usdt.balanceOf(agent1); + uint256 expectedTopUp = DAILY_LIMIT - agentBalanceBefore; + + // Trigger top-up with non-standard token + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + + // Verify transfer succeeded despite non-standard return + assertEq(usdt.balanceOf(agent1), DAILY_LIMIT); + assertEq(usdt.balanceOf(safeAccount.account), INITIAL_SAFE_BALANCE - expectedTopUp); + } + + function test_Integration_TriggerTopUps_BatchExecution() public { + // Setup multiple configs for the same account + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + // Configure multiple agents with different tokens + vm.startPrank(safeAccount.account); + executor.configureTopUp(agent1, address(token), config); + executor.configureTopUp(agent2, address(token), config); + executor.configureTopUp(agent1, address(usdt), config); + vm.stopPrank(); + + // Record balances before + uint256 agent1TokenBefore = token.balanceOf(agent1); + uint256 agent2TokenBefore = token.balanceOf(agent2); + uint256 agent1UsdtBefore = usdt.balanceOf(agent1); + + // Trigger all top-ups for the Safe account + vm.prank(stranger); + executor.triggerTopUps(safeAccount.account); + + // Should have executed 3 top-ups (verify by checking balances) + + // Verify all balances were topped up + assertEq(token.balanceOf(agent1), DAILY_LIMIT); + assertEq(token.balanceOf(agent2), DAILY_LIMIT); + assertEq(usdt.balanceOf(agent1), DAILY_LIMIT); + } + + // ============ Daily/Monthly Limit Tests ============ + + function test_Integration_DailyLimitReset() public { + // Setup config with low daily limit + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: 60 ether, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(safeAccount.account); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // First top-up (agent1 has 50 ether, needs 10 ether to reach 60) + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + assertEq(token.balanceOf(agent1), 60 ether); + + // Spend some tokens + vm.prank(agent1); + token.transfer(agent2, 20 ether); + assertEq(token.balanceOf(agent1), 40 ether); + + // Try to top-up again same day - should fail (already topped up today) + (bool canExecute, string memory reason) = executor.canExecuteTopUp(safeAccount.account, configId); + assertFalse(canExecute); + assertEq(reason, "Already topped up today"); + + // Move to next day + vm.warp(block.timestamp + 1 days); + + // Now can execute again (new day, agent balance is 40, needs 20 to reach 60) + (canExecute, reason) = executor.canExecuteTopUp(safeAccount.account, configId); + assertTrue(canExecute); + assertEq(reason, ""); + + // Execute the top-up + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + assertEq(token.balanceOf(agent1), 60 ether); + } + + function test_Integration_MonthlyLimitEnforcement() public { + // Setup config with low monthly limit + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = IAutoTopUpExecutor.TopUpConfig({ + dailyLimit: 100 ether, + monthlyLimit: 120 ether, // Just above one top-up (50 ether needed initially) + enabled: true + }); + + vm.prank(safeAccount.account); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // First top-up should work (agent has 50 ether, needs 50 ether to reach 100) + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + assertEq(token.balanceOf(agent1), 100 ether); + + // Spend most tokens + vm.prank(agent1); + token.transfer(agent2, 90 ether); + assertEq(token.balanceOf(agent1), 10 ether); + + // Move to next day to allow another top-up + vm.warp(block.timestamp + 1 days); + + // Second top-up should be partial (would need 90 ether, but only 70 left in monthly limit) + // Monthly spent: 50 ether, limit: 120 ether, remaining: 70 ether + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + + // Balance should be: 10 (current) + 70 (remaining monthly limit) = 80 ether + assertEq(token.balanceOf(agent1), 80 ether); + + // Move to next day and try again - should fail (monthly limit reached) + vm.warp(block.timestamp + 1 days); + vm.prank(agent1); + token.transfer(agent2, 10 ether); // Spend some to be below daily limit + + (bool canExecute, string memory reason) = executor.canExecuteTopUp(safeAccount.account, configId); + assertFalse(canExecute); + assertEq(reason, "Monthly limit reached"); + } + + // ============ Module Uninstall Tests ============ + + function test_Integration_UninstallModule_CleansState() + public + withModuleStorageClearValidation(safeAccount, address(executor)) + { + // Install and configure using ModuleKit + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.startPrank(safeAccount.account); + executor.configureTopUp(agent1, address(token), config); + executor.configureTopUp(agent2, address(usdt), config); + vm.stopPrank(); + + // Verify configs exist + (IAutoTopUpExecutor.TopUpConfig[] memory configs,) = executor.getTopUpConfigs(safeAccount.account); + assertEq(configs.length, 2); + + // Uninstall module using ModuleKit + // Events during UserOp execution are tested in unit tests + safeAccount.uninstallModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + // Verify state is cleaned + assertFalse(executor.isInitialized(safeAccount.account)); + assertFalse(safeAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); + (configs,) = executor.getTopUpConfigs(safeAccount.account); + assertEq(configs.length, 0); + } + + // ============ Reentrancy Protection Tests ============ + + function test_Integration_ReentrancyProtection() public { + // Deploy malicious token + MaliciousToken malToken = new MaliciousToken(); + + // Setup module with malicious token using ModuleKit + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(safeAccount.account); + bytes32 configId = executor.configureTopUp(agent1, address(malToken), config); + + // Set reentrancy target + malToken.setTarget(executor, configId); + + // Fund Safe with malicious tokens + malToken.mint(safeAccount.account, INITIAL_SAFE_BALANCE); + + // Try to trigger - reentrancy guard should prevent issues + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + + // Should have completed successfully despite reentrancy attempt + assertEq(malToken.balanceOf(agent1), DAILY_LIMIT); + } + + // ============ Access Control Tests ============ + + function test_Integration_ModuleNotInitialized() public { + // Don't install module - test that uninitialised accounts can't configure + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + // Stranger cannot configure without module being installed for their account + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); + executor.configureTopUp(agent1, address(token), config); + } + + function test_Integration_CrossAccountConfigurationBlocked() public { + // Install module for safeAccount only + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + // Safe account can configure for itself + vm.prank(safeAccount.account); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Stranger cannot modify safe account's configs (module not initialized for stranger) + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); + executor.disableTopUp(configId); + } + + // ============ Edge Case Tests ============ + + function test_Integration_InsufficientSafeBalance() public { + // Setup module using ModuleKit + safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(safeAccount.account); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Drain Safe balance + vm.prank(safeAccount.account); + token.transfer(agent2, INITIAL_SAFE_BALANCE); + + // Try to trigger - should fail due to insufficient balance + vm.expectEmit(true, true, true, true); + emit TopUpFailed(safeAccount.account, agent1, address(token), configId, "Insufficient account balance"); + + vm.prank(stranger); + executor.triggerTopUp(safeAccount.account, configId); + + // Agent balance should not change + assertEq(token.balanceOf(agent1), INITIAL_AGENT_BALANCE); + } + + function test_Integration_ModuleType() public { + // Verify module type - should only be true for EXECUTOR type + assertTrue(executor.isModuleType(MODULE_TYPE_EXECUTOR)); + assertFalse(executor.isModuleType(MODULE_TYPE_VALIDATOR)); + assertFalse(executor.isModuleType(MODULE_TYPE_FALLBACK)); + assertFalse(executor.isModuleType(MODULE_TYPE_HOOK)); + } +} diff --git a/typescript/packages/account-modules/test/AutoTopUpExecutor.t.sol b/typescript/packages/account-modules/test/AutoTopUpExecutor.t.sol new file mode 100644 index 0000000..4a865b9 --- /dev/null +++ b/typescript/packages/account-modules/test/AutoTopUpExecutor.t.sol @@ -0,0 +1,941 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Test, console2} from "forge-std/Test.sol"; +import {AutoTopUpExecutor} from "../src/AutoTopUpExecutor.sol"; +import {IAutoTopUpExecutor} from "../src/IAutoTopUpExecutor.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; + +// Import mocks +import {MockERC20} from "./mocks/MockERC20.sol"; +import {MockUSDT} from "./mocks/MockUSDT.sol"; +import {MockSafe} from "./mocks/MockSafe.sol"; +import {MockTokenBadReturn} from "./mocks/MockTokenBadReturn.sol"; +import {MockTokenReturnsFalse} from "./mocks/MockTokenReturnsFalse.sol"; + +// Test contract with proper inheritance for module testing +contract AutoTopUpExecutorTest is Test { + // Main contracts + AutoTopUpExecutor public executor; + MockERC20 public token; + MockUSDT public usdt; + MockSafe public safe; + + // Test addresses + address public owner; + address public agent1; + address public agent2; + address public stranger; + + // Test constants + uint256 constant DAILY_LIMIT = 100 ether; + uint256 constant MONTHLY_LIMIT = 1000 ether; + uint256 constant INITIAL_SAFE_BALANCE = 10000 ether; + uint256 constant INITIAL_AGENT_BALANCE = 50 ether; // Below daily limit + + // Events to test + event ModuleInstalled(address indexed account, uint256 initialConfigs); + event ModuleUninstalled(address indexed account, uint256 removedConfigs); + event TopUpConfigured( + address indexed account, + address indexed agent, + address asset, + bytes32 indexed configId, + IAutoTopUpExecutor.TopUpConfig config + ); + event TopUpExecuted( + address indexed account, address indexed agent, address asset, bytes32 indexed configId, uint256 amount + ); + event TopUpFailed( + address indexed account, address indexed agent, address asset, bytes32 indexed configId, string reason + ); + event TopUpEnabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId); + event TopUpDisabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId); + + function setUp() public { + // Set up test accounts + owner = makeAddr("owner"); + stranger = makeAddr("stranger"); + agent1 = makeAddr("agent1"); + agent2 = makeAddr("agent2"); + + // Deploy test tokens + token = new MockERC20("Test Token", "TEST"); + usdt = new MockUSDT(); + + // Deploy mock Safe + safe = new MockSafe(owner); + + // Deploy AutoTopUpExecutor as singleton + executor = new AutoTopUpExecutor(); + + // Enable executor as module on Safe + vm.prank(owner); + safe.enableModule(address(executor)); + + // Fund Safe with tokens + token.mint(address(safe), INITIAL_SAFE_BALANCE); + usdt.mint(address(safe), INITIAL_SAFE_BALANCE); + + // Give agents some initial balance (below daily limit) + token.mint(agent1, INITIAL_AGENT_BALANCE); + token.mint(agent2, INITIAL_AGENT_BALANCE); + usdt.mint(agent1, INITIAL_AGENT_BALANCE); + usdt.mint(agent2, INITIAL_AGENT_BALANCE); + } + + // ============ Module Installation Tests ============ + + function test_OnInstall_EmptyData() public { + // Install module without initial configs + vm.expectEmit(true, false, false, true); + emit ModuleInstalled(address(safe), 0); + + vm.prank(address(safe)); + executor.onInstall(""); + + assertTrue(executor.isInitialized(address(safe))); + } + + function test_OnInstall_WithSingleConfig() public { + // Prepare installation data + address[] memory agents = new address[](1); + address[] memory assets = new address[](1); + IAutoTopUpExecutor.TopUpConfig[] memory configs = new IAutoTopUpExecutor.TopUpConfig[](1); + + agents[0] = agent1; + assets[0] = address(token); + configs[0] = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + bytes memory installData = abi.encode(agents, assets, configs); + + // Calculate expected config ID + bytes32 configId = executor.generateConfigId(address(safe), agent1, address(token)); + + // Expect events + vm.expectEmit(true, true, true, true); + emit TopUpConfigured(address(safe), agent1, address(token), configId, configs[0]); + + vm.expectEmit(true, true, true, true); + emit TopUpEnabled(address(safe), agent1, address(token), configId); + + vm.expectEmit(true, false, false, true); + emit ModuleInstalled(address(safe), 1); + + vm.prank(address(safe)); + executor.onInstall(installData); + + assertTrue(executor.isInitialized(address(safe))); + + // Verify config was created + (IAutoTopUpExecutor.TopUpConfig memory config,) = executor.getTopUpById(configId); + assertEq(config.dailyLimit, DAILY_LIMIT); + assertEq(config.monthlyLimit, MONTHLY_LIMIT); + assertTrue(config.enabled); + } + + function test_OnInstall_RevertInvalidAgent() public { + // Try to install with zero address agent + address[] memory agents = new address[](1); + address[] memory assets = new address[](1); + IAutoTopUpExecutor.TopUpConfig[] memory configs = new IAutoTopUpExecutor.TopUpConfig[](1); + + agents[0] = address(0); // Invalid + assets[0] = address(token); + configs[0] = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + bytes memory installData = abi.encode(agents, assets, configs); + + vm.prank(address(safe)); + vm.expectRevert(IAutoTopUpExecutor.InvalidAgent.selector); + executor.onInstall(installData); + } + + // ============ Module Uninstallation Tests ============ + + function test_OnUninstall_CleansUpAllState() public { + // First install with configs + address[] memory agents = new address[](2); + address[] memory assets = new address[](2); + IAutoTopUpExecutor.TopUpConfig[] memory configs = new IAutoTopUpExecutor.TopUpConfig[](2); + + agents[0] = agent1; + agents[1] = agent2; + assets[0] = address(token); + assets[1] = address(token); + + for (uint256 i = 0; i < 2; i++) { + configs[i] = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + } + + vm.prank(address(safe)); + executor.onInstall(abi.encode(agents, assets, configs)); + + // Verify installation + assertTrue(executor.isInitialized(address(safe))); + (IAutoTopUpExecutor.TopUpConfig[] memory retrievedConfigs,) = executor.getTopUpConfigs(address(safe)); + assertEq(retrievedConfigs.length, 2); + + // Now uninstall + vm.expectEmit(true, false, false, true); + emit ModuleUninstalled(address(safe), 2); + + vm.prank(address(safe)); + executor.onUninstall(""); + + // Verify all state is cleaned + assertFalse(executor.isInitialized(address(safe))); + (retrievedConfigs,) = executor.getTopUpConfigs(address(safe)); + assertEq(retrievedConfigs.length, 0); + } + + // ============ Configuration Management Tests ============ + + function test_ConfigureTopUp_NewConfig() public { + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + bytes32 expectedConfigId = executor.generateConfigId(address(safe), agent1, address(token)); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + assertEq(configId, expectedConfigId); + + // Verify config was created + (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig, IAutoTopUpExecutor.TopUpState memory state) = + executor.getTopUpById(configId); + assertEq(retrievedConfig.dailyLimit, DAILY_LIMIT); + assertEq(retrievedConfig.monthlyLimit, MONTHLY_LIMIT); + assertTrue(retrievedConfig.enabled); + assertEq(state.agent, agent1); + assertEq(state.asset, address(token)); + } + + function test_ConfigureTopUp_RevertInvalidAgent_ZeroAddress() public { + // Setup: Install module + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + // Try to configure with zero address agent + vm.prank(address(safe)); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.InvalidAgent.selector)); + executor.configureTopUp(address(0), address(token), config); + } + + function test_ConfigureTopUp_RevertInvalidAgent_SameAsAccount() public { + // Setup: Install module + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + // Try to configure with agent same as account (msg.sender) + vm.prank(address(safe)); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.InvalidAgent.selector)); + executor.configureTopUp(address(safe), address(token), config); + } + + function test_ConfigureTopUp_RevertInvalidAsset() public { + // Setup: Install module + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + // Try to configure with zero address asset + vm.prank(address(safe)); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.InvalidAsset.selector)); + executor.configureTopUp(agent1, address(0), config); + } + + function test_ConfigureTopUp_MaxValues() public { + // Setup: Install module + vm.prank(address(safe)); + executor.onInstall(""); + + // Test with maximum uint256 values + IAutoTopUpExecutor.TopUpConfig memory config = IAutoTopUpExecutor.TopUpConfig({ + dailyLimit: type(uint256).max, monthlyLimit: type(uint256).max, enabled: true + }); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Verify config was created successfully + (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig,) = executor.getTopUpById(configId); + assertEq(retrievedConfig.dailyLimit, type(uint256).max); + assertEq(retrievedConfig.monthlyLimit, type(uint256).max); + assertTrue(retrievedConfig.enabled); + } + + function test_ConfigureTopUp_RevertInvalidConfiguration() public { + vm.prank(address(safe)); + executor.onInstall(""); + + // Zero daily limit + IAutoTopUpExecutor.TopUpConfig memory config1 = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: 0, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + vm.expectRevert(IAutoTopUpExecutor.InvalidConfiguration.selector); + executor.configureTopUp(agent1, address(token), config1); + + // Zero monthly limit + IAutoTopUpExecutor.TopUpConfig memory config2 = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: 0, enabled: true}); + + vm.prank(address(safe)); + vm.expectRevert(IAutoTopUpExecutor.InvalidConfiguration.selector); + executor.configureTopUp(agent1, address(token), config2); + } + + // ============ Enable/Disable Tests ============ + + function test_EnableDisableTopUp() public { + // Setup disabled config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: false}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Enable it + vm.expectEmit(true, true, true, true); + emit TopUpEnabled(address(safe), agent1, address(token), configId); + + vm.prank(address(safe)); + executor.enableTopUp(configId); + + // Verify it's enabled + (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig,) = executor.getTopUpById(configId); + assertTrue(retrievedConfig.enabled); + + // Disable it + vm.expectEmit(true, true, true, true); + emit TopUpDisabled(address(safe), agent1, address(token), configId); + + vm.prank(address(safe)); + executor.disableTopUp(configId); + + // Verify it's disabled + (retrievedConfig,) = executor.getTopUpById(configId); + assertFalse(retrievedConfig.enabled); + } + + function test_EnableDisable_RevertUnauthorized() public { + // Setup config as safe account + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: false}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Try to enable as stranger (should fail - module not initialized) + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); + executor.enableTopUp(configId); + + // Try to disable as stranger (should fail - module not initialized) + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); + executor.disableTopUp(configId); + + // Now test with an initialized but unauthorized account + address otherAccount = makeAddr("otherAccount"); + vm.prank(otherAccount); + executor.onInstall(""); + + // Try to enable config owned by safe account (should fail - unauthorized) + vm.prank(otherAccount); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.Unauthorized.selector, configId, otherAccount)); + executor.enableTopUp(configId); + } + + // ============ View Function Tests ============ + + function test_ConfigureTopUpById_Success() public { + // Setup: Install module and create initial config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory initialConfig = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: false}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), initialConfig); + + // Update config by ID + IAutoTopUpExecutor.TopUpConfig memory newConfig = IAutoTopUpExecutor.TopUpConfig({ + dailyLimit: DAILY_LIMIT * 2, monthlyLimit: MONTHLY_LIMIT * 3, enabled: true + }); + + vm.expectEmit(true, true, true, true); + emit TopUpConfigured(address(safe), agent1, address(token), configId, newConfig); + vm.expectEmit(true, true, true, true); + emit TopUpEnabled(address(safe), agent1, address(token), configId); + + vm.prank(address(safe)); + executor.configureTopUpById(configId, newConfig); + + // Verify config was updated + (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig,) = executor.getTopUpById(configId); + assertEq(retrievedConfig.dailyLimit, DAILY_LIMIT * 2); + assertEq(retrievedConfig.monthlyLimit, MONTHLY_LIMIT * 3); + assertTrue(retrievedConfig.enabled); + } + + function test_ConfigureTopUpById_RevertModuleNotInitialized() public { + // Don't install module for safe + bytes32 configId = keccak256("dummy"); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, address(safe))); + executor.configureTopUpById(configId, config); + } + + function test_ConfigureTopUpById_RevertConfigNotFound() public { + // Install module but use non-existent configId + vm.prank(address(safe)); + executor.onInstall(""); + + bytes32 nonExistentConfigId = keccak256("nonexistent"); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ConfigNotFound.selector)); + executor.configureTopUpById(nonExistentConfigId, config); + } + + function test_ConfigureTopUpById_RevertUnauthorized() public { + // Setup: Safe creates a config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Stranger tries to update safe's config + IAutoTopUpExecutor.TopUpConfig memory newConfig = IAutoTopUpExecutor.TopUpConfig({ + dailyLimit: DAILY_LIMIT * 2, monthlyLimit: MONTHLY_LIMIT * 2, enabled: false + }); + + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); + executor.configureTopUpById(configId, newConfig); + } + + function test_ConfigureTopUpById_RevertInvalidConfiguration() public { + // Setup: Install module and create initial config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory initialConfig = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), initialConfig); + + // Try to update with invalid config (zero daily limit) + IAutoTopUpExecutor.TopUpConfig memory invalidConfig = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: 0, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.InvalidConfiguration.selector)); + executor.configureTopUpById(configId, invalidConfig); + } + + function test_TriggerTopUp_EmitsEvent() public { + // Setup: Install module and configure top-up + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Agent has low balance, needs top-up + uint256 agentBalanceBefore = token.balanceOf(agent1); + uint256 expectedTopUp = DAILY_LIMIT - agentBalanceBefore; + + // Expect the TopUpExecuted event + vm.expectEmit(true, true, true, true); + emit TopUpExecuted(address(safe), agent1, address(token), configId, expectedTopUp); + + // Trigger the top-up + executor.triggerTopUp(address(safe), configId); + + // Verify the top-up was executed + assertEq(token.balanceOf(agent1), DAILY_LIMIT); + } + + function test_CanExecuteTopUp_Conditions() public { + // Setup + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Should be able to execute (agent balance is below daily limit) + (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + + // Fund agent to be above daily limit + token.mint(agent1, DAILY_LIMIT); + + // Should not be able to execute now + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertFalse(canExecute); + assertEq(reason, "Agent balance sufficient"); + + // Test with disabled config + vm.prank(address(safe)); + executor.disableTopUp(configId); + + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertFalse(canExecute); + assertEq(reason, "Top-up disabled"); + } + + function test_TransferValidation_InvalidReturn() public { + // Setup: Install module and configure top-up + vm.prank(address(safe)); + executor.onInstall(""); + + // Create a token that returns malformed data + MockTokenBadReturn badToken = new MockTokenBadReturn(); + badToken.mint(address(safe), INITIAL_SAFE_BALANCE); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(badToken), config); + + // Should emit TopUpFailed when transfer returns malformed data (now caught by try-catch) + vm.prank(stranger); + vm.expectEmit(true, true, true, true); + emit TopUpFailed(address(safe), agent1, address(badToken), configId, "Transfer failed"); + executor.triggerTopUp(address(safe), configId); + + // Verify state was NOT updated (no top-up happened) + (, IAutoTopUpExecutor.TopUpState memory state) = executor.getTopUpById(configId); + assertEq(state.lastTopUpDay, 0); // Should remain 0 since transfer failed + assertEq(state.monthlySpent, 0); // Should remain 0 since transfer failed + } + + function test_TransferValidation_ReturnsFalse() public { + // Setup: Install module and configure top-up + vm.prank(address(safe)); + executor.onInstall(""); + + // Create a token that returns false on transfer + MockTokenReturnsFalse falseToken = new MockTokenReturnsFalse(); + falseToken.mint(address(safe), INITIAL_SAFE_BALANCE); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(falseToken), config); + + // Should emit TopUpFailed when transfer returns false (now caught by try-catch) + vm.prank(stranger); + vm.expectEmit(true, true, true, true); + emit TopUpFailed(address(safe), agent1, address(falseToken), configId, "Transfer failed"); + executor.triggerTopUp(address(safe), configId); + + // Verify state was NOT updated (no top-up happened) + (, IAutoTopUpExecutor.TopUpState memory state) = executor.getTopUpById(configId); + assertEq(state.lastTopUpDay, 0); // Should remain 0 since transfer failed + assertEq(state.monthlySpent, 0); // Should remain 0 since transfer failed + } + + function test_GetTopUp_Success() public { + // Setup: Install module and create config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Test getTopUp function + (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig, IAutoTopUpExecutor.TopUpState memory retrievedState) = + executor.getTopUp(address(safe), agent1, address(token)); + + assertEq(retrievedConfig.dailyLimit, DAILY_LIMIT); + assertEq(retrievedConfig.monthlyLimit, MONTHLY_LIMIT); + assertTrue(retrievedConfig.enabled); + assertEq(retrievedState.agent, agent1); + assertEq(retrievedState.asset, address(token)); + } + + function test_GetTopUp_NonExistentConfig() public { + // Test getTopUp with non-existent config + (IAutoTopUpExecutor.TopUpConfig memory config, IAutoTopUpExecutor.TopUpState memory state) = + executor.getTopUp(address(safe), agent1, address(token)); + + // Should return zero values for non-existent config + assertEq(config.dailyLimit, 0); + assertEq(config.monthlyLimit, 0); + assertFalse(config.enabled); + assertEq(state.agent, address(0)); + assertEq(state.asset, address(0)); + } + + function test_CanExecuteTopUp_ConfigNotFound() public { + bytes32 nonExistentConfigId = keccak256("nonexistent"); + + (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), nonExistentConfigId); + + assertFalse(canExecute); + assertEq(reason, "Config not found"); + } + + function test_CanExecuteTopUp_AccountDoesntOwnConfig() public { + // Setup: Safe creates a config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Try to check canExecute with different account (stranger) + (bool canExecute, string memory reason) = executor.canExecuteTopUp(stranger, configId); + + assertFalse(canExecute); + assertEq(reason, "Account doesn't own config"); + } + + function test_GetTopUpConfigs() public { + // Install module and create multiple configs + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config1 = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + IAutoTopUpExecutor.TopUpConfig memory config2 = IAutoTopUpExecutor.TopUpConfig({ + dailyLimit: DAILY_LIMIT / 2, monthlyLimit: MONTHLY_LIMIT / 2, enabled: false + }); + + vm.startPrank(address(safe)); + executor.configureTopUp(agent1, address(token), config1); + executor.configureTopUp(agent2, address(usdt), config2); + vm.stopPrank(); + + // Get all configs + (IAutoTopUpExecutor.TopUpConfig[] memory configs, IAutoTopUpExecutor.TopUpState[] memory states) = + executor.getTopUpConfigs(address(safe)); + + assertEq(configs.length, 2); + assertEq(states.length, 2); + + // Verify first config + assertEq(configs[0].dailyLimit, DAILY_LIMIT); + assertEq(configs[0].monthlyLimit, MONTHLY_LIMIT); + assertTrue(configs[0].enabled); + + // Verify second config + assertEq(configs[1].dailyLimit, DAILY_LIMIT / 2); + assertEq(configs[1].monthlyLimit, MONTHLY_LIMIT / 2); + assertFalse(configs[1].enabled); + } + + // ============ Date Boundary Tests ============ + + function test_DailyLimitReset() public { + // Setup config with daily limit + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // First execution should work + (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + + // Actually execute the top-up + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + + // Should not be able to execute again same day (daily limit enforced) + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertFalse(canExecute); + assertEq(reason, "Already topped up today"); + + // Move to next day + vm.warp(block.timestamp + 1 days); + + // Now check - should not execute because agent balance is sufficient + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertFalse(canExecute); + assertEq(reason, "Agent balance sufficient"); + + // Reduce agent balance to need another top-up + vm.prank(agent1); + token.transfer(agent2, 60 ether); + + // Now should be able to execute + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + } + + function test_MonthlyLimitReset() public { + // Setup config with low monthly limit (just enough for 2 top-ups) + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = IAutoTopUpExecutor.TopUpConfig({ + dailyLimit: DAILY_LIMIT, + monthlyLimit: 110 ether, // Allows ~2 top-ups of 50 ether each + enabled: true + }); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // First top-up should work + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + assertEq(token.balanceOf(agent1), DAILY_LIMIT); + + // Spend tokens and move to next day + vm.prank(agent1); + token.transfer(agent2, 90 ether); + vm.warp(block.timestamp + 1 days); + + // Second top-up should work (still within monthly limit) + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + + // After second top-up, agent should have less than daily limit due to monthly limit + // Monthly limit is 110 ether, already spent 50 ether, so can only top up 60 ether more + // Agent had 10 ether, topped up by 60 ether to reach 70 ether + assertEq(token.balanceOf(agent1), 70 ether); + + // Spend tokens and move to next day (transfer less than balance) + vm.prank(agent1); + token.transfer(agent2, 60 ether); + vm.warp(block.timestamp + 1 days); + + // Third top-up should fail (monthly limit reached) + (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); + assertFalse(canExecute); + assertEq(reason, "Monthly limit reached"); + + // Move to next month (30 days forward to ensure month change) + vm.warp(block.timestamp + 30 days); + + // Should be able to execute again (new month) + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + + // Execute to verify it actually works + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + assertEq(token.balanceOf(agent1), DAILY_LIMIT); + } + + function test_YearTransition() public { + // Setup config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Set time to Dec 31, 2023 + vm.warp(1704067199); // Dec 31, 2023 23:59:59 UTC + + // Execute top-up on last day of year + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + + // Reduce balance to need another top-up + vm.prank(agent1); + token.transfer(agent2, 60 ether); + + // Should not execute again same day + (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); + assertFalse(canExecute); + assertEq(reason, "Already topped up today"); + + // Move to Jan 1, 2024 (next year) + vm.warp(1704067200); // Jan 1, 2024 00:00:00 UTC + + // Should be able to execute (new day and new year) + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + + // Verify execution works + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + assertEq(token.balanceOf(agent1), DAILY_LIMIT); + } + + function test_LeapYearFebruary() public { + // Setup config + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Set time to Feb 28, 2024 (leap year) + vm.warp(1709078400); // Feb 28, 2024 00:00:00 UTC + + // Execute top-up on Feb 28 + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + + // Reduce balance + vm.prank(agent1); + token.transfer(agent2, 60 ether); + + // Move to Feb 29 (leap day) + vm.warp(1709164800); // Feb 29, 2024 00:00:00 UTC + + // Should be able to execute on leap day + (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + + // Reduce balance again + vm.prank(agent1); + token.transfer(agent2, 60 ether); + + // Move to March 1 + vm.warp(1709251200); // March 1, 2024 00:00:00 UTC + + // Should be able to execute on March 1 + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + } + + // ============ Fuzz Tests ============ + + function testFuzz_DailyExecutionLimit(uint32 startTimestamp, uint32 timeDelta) public { + // Test that daily execution limit is enforced across various start times and deltas + // Bound start timestamp to reasonable range (year 2020-2030) + uint256 startTime = bound(uint256(startTimestamp), 1577836800, 1893456000); // 2020-2030 + vm.warp(startTime); + + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); + + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Execute first top-up + vm.prank(address(safe)); + executor.triggerTopUp(address(safe), configId); + + // Reduce balance to need another top-up + vm.prank(agent1); + token.transfer(agent2, 60 ether); + + // Calculate seconds remaining in current calendar day + (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); + uint256 endOfDay = BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day) + 86400 - 1; + uint256 secondsLeftInDay = endOfDay - block.timestamp; + + // Bound time delta to stay within current calendar day + uint256 deltaSeconds = bound(uint256(timeDelta), 0, secondsLeftInDay); + vm.warp(block.timestamp + deltaSeconds); + + // Should not be able to execute again same calendar day + (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); + assertFalse(canExecute); + assertEq(reason, "Already topped up today"); + + // Move to next calendar day + vm.warp(block.timestamp + (secondsLeftInDay - deltaSeconds) + 1); + + // Now should be able to execute + (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); + assertTrue(canExecute); + assertEq(reason, ""); + } + + function testFuzz_ConfigurationLimits(uint256 dailyLimit, uint256 monthlyLimit) public { + // Bound to reasonable values + dailyLimit = bound(dailyLimit, 1, type(uint128).max); + monthlyLimit = bound(monthlyLimit, 1, type(uint128).max); + + vm.prank(address(safe)); + executor.onInstall(""); + + IAutoTopUpExecutor.TopUpConfig memory config = + IAutoTopUpExecutor.TopUpConfig({dailyLimit: dailyLimit, monthlyLimit: monthlyLimit, enabled: true}); + + // Should succeed with valid limits + vm.prank(address(safe)); + bytes32 configId = executor.configureTopUp(agent1, address(token), config); + + // Verify config was stored correctly + (IAutoTopUpExecutor.TopUpConfig memory retrieved,) = executor.getTopUpById(configId); + assertEq(retrieved.dailyLimit, dailyLimit); + assertEq(retrieved.monthlyLimit, monthlyLimit); + } +} diff --git a/typescript/packages/account-modules/test/mocks/MaliciousCollectToken.sol b/typescript/packages/account-modules/test/mocks/MaliciousCollectToken.sol new file mode 100644 index 0000000..fffb1df --- /dev/null +++ b/typescript/packages/account-modules/test/mocks/MaliciousCollectToken.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {AutoCollectExecutor} from "../../src/AutoCollectExecutor.sol"; + +// Malicious token that tries to re-enter during transfer for collection tests +contract MaliciousCollectToken is ERC20 { + AutoCollectExecutor public target; + address public targetAccount; + address public targetAsset; + + constructor() ERC20("MaliciousCollect", "MALCOL") {} + + function setTarget(AutoCollectExecutor _target, address _account, address _asset) external { + target = _target; + targetAccount = _account; + targetAsset = _asset; + } + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } + + function transfer(address to, uint256 amount) public override returns (bool) { + // Try to re-enter during transfer + if (address(target) != address(0)) { + try target.triggerCollection(targetAccount, targetAsset) {} catch {} + } + return super.transfer(to, amount); + } +} diff --git a/typescript/packages/account-modules/test/mocks/MaliciousToken.sol b/typescript/packages/account-modules/test/mocks/MaliciousToken.sol new file mode 100644 index 0000000..e88e6b3 --- /dev/null +++ b/typescript/packages/account-modules/test/mocks/MaliciousToken.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {AutoTopUpExecutor} from "../../src/AutoTopUpExecutor.sol"; + +// Malicious token that tries to re-enter during transfer +contract MaliciousToken is ERC20 { + AutoTopUpExecutor public target; + bytes32 public targetConfigId; + + constructor() ERC20("Malicious", "MAL") {} + + function setTarget(AutoTopUpExecutor _target, bytes32 _configId) external { + target = _target; + targetConfigId = _configId; + } + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } + + function transfer(address to, uint256 amount) public override returns (bool) { + // Try to re-enter during transfer + if (address(target) != address(0)) { + try target.triggerTopUp(address(this), targetConfigId) {} catch {} + } + return super.transfer(to, amount); + } +} diff --git a/typescript/packages/account-modules/test/mocks/MockERC20.sol b/typescript/packages/account-modules/test/mocks/MockERC20.sol new file mode 100644 index 0000000..96c6a65 --- /dev/null +++ b/typescript/packages/account-modules/test/mocks/MockERC20.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract MockERC20 is ERC20 { + constructor(string memory name, string memory symbol) ERC20(name, symbol) {} + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } + + function burn(address from, uint256 amount) external { + _burn(from, amount); + } +} diff --git a/typescript/packages/account-modules/test/mocks/MockSafe.sol b/typescript/packages/account-modules/test/mocks/MockSafe.sol new file mode 100644 index 0000000..18d90ab --- /dev/null +++ b/typescript/packages/account-modules/test/mocks/MockSafe.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {ModeCode} from "modulekit/src/accounts/common/lib/ModeLib.sol"; +import {ExecutionLib} from "modulekit/src/accounts/erc7579/lib/ExecutionLib.sol"; + +// Mock Safe contract for testing ERC-7579 module execution +contract MockSafe { + mapping(address => bool) public isModuleEnabled; + + // Storage for execution results + bool public lastExecutionSuccess; + bytes public lastExecutionResult; + + // Mock owner for testing + address public owner; + + constructor(address _owner) { + owner = _owner; + } + + function enableModule(address module) external { + require(msg.sender == owner, "Only owner"); + isModuleEnabled[module] = true; + } + + // ERC-7579 compatible execution function + // This is called by the module's _execute function via ERC7579ExecutorBase + function executeFromExecutor( + ModeCode, // mode - we ignore this in the mock + bytes calldata executionCalldata + ) + external + payable + returns (bytes[] memory returnData) + { + require(isModuleEnabled[msg.sender], "Module not enabled"); + + // Decode the execution calldata + // For single execution mode, it's encoded as (target, value, callData) + (address target, uint256 value, bytes memory data) = ExecutionLib.decodeSingle(executionCalldata); + + // Execute the call + bool success; + bytes memory result; + (success, result) = target.call{value: value}(data); + lastExecutionSuccess = success; + lastExecutionResult = result; + + if (!success) { + // Bubble up the revert reason + assembly { + revert(add(result, 32), mload(result)) + } + } + + // Return as array (ERC-7579 expects array of results) + returnData = new bytes[](1); + returnData[0] = result; + + return returnData; + } +} diff --git a/typescript/packages/account-modules/test/mocks/MockTokenBadReturn.sol b/typescript/packages/account-modules/test/mocks/MockTokenBadReturn.sol new file mode 100644 index 0000000..28a2b79 --- /dev/null +++ b/typescript/packages/account-modules/test/mocks/MockTokenBadReturn.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +// Mock ERC20 token that returns malformed data (not 32 bytes) on transfer +contract MockTokenBadReturn { + mapping(address => uint256) private _balances; + mapping(address => mapping(address => uint256)) private _allowances; + uint256 private _totalSupply; + + string public name = "Bad Return Token"; + string public symbol = "BAD"; + uint8 public decimals = 18; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function allowance(address owner, address spender) public view returns (uint256) { + return _allowances[owner][spender]; + } + + function approve(address spender, uint256 amount) external returns (bool) { + _allowances[msg.sender][spender] = amount; + return true; + } + + function transfer(address to, uint256 amount) external returns (bool) { + require(_balances[msg.sender] >= amount, "Insufficient balance"); + _balances[msg.sender] -= amount; + _balances[to] += amount; + + // Return malformed data (64 bytes instead of 32) + assembly { + let ptr := mload(0x40) + mstore(ptr, 0x0000000000000000000000000000000000000000000000000000000000000001) + mstore(add(ptr, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000001) + return(ptr, 0x40) + } + } + + function transferFrom(address from, address to, uint256 amount) external returns (bool) { + require(_balances[from] >= amount, "Insufficient balance"); + require(_allowances[from][msg.sender] >= amount, "Insufficient allowance"); + + _balances[from] -= amount; + _balances[to] += amount; + _allowances[from][msg.sender] -= amount; + + return true; + } + + function mint(address to, uint256 amount) external { + _balances[to] += amount; + _totalSupply += amount; + } +} diff --git a/typescript/packages/account-modules/test/mocks/MockTokenReturnsFalse.sol b/typescript/packages/account-modules/test/mocks/MockTokenReturnsFalse.sol new file mode 100644 index 0000000..1310406 --- /dev/null +++ b/typescript/packages/account-modules/test/mocks/MockTokenReturnsFalse.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +// Mock ERC20 token that returns false on transfer +contract MockTokenReturnsFalse { + mapping(address => uint256) private _balances; + mapping(address => mapping(address => uint256)) private _allowances; + uint256 private _totalSupply; + + string public name = "False Return Token"; + string public symbol = "FALSE"; + uint8 public decimals = 18; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function allowance(address owner, address spender) public view returns (uint256) { + return _allowances[owner][spender]; + } + + function approve(address spender, uint256 amount) external returns (bool) { + _allowances[msg.sender][spender] = amount; + return true; + } + + function transfer(address to, uint256 amount) external returns (bool) { + require(_balances[msg.sender] >= amount, "Insufficient balance"); + _balances[msg.sender] -= amount; + _balances[to] += amount; + + // Always return false even on successful transfer + return false; + } + + function transferFrom(address from, address to, uint256 amount) external returns (bool) { + require(_balances[from] >= amount, "Insufficient balance"); + require(_allowances[from][msg.sender] >= amount, "Insufficient allowance"); + + _balances[from] -= amount; + _balances[to] += amount; + _allowances[from][msg.sender] -= amount; + + return true; + } + + function mint(address to, uint256 amount) external { + _balances[to] += amount; + _totalSupply += amount; + } +} diff --git a/typescript/packages/account-modules/test/mocks/MockUSDT.sol b/typescript/packages/account-modules/test/mocks/MockUSDT.sol new file mode 100644 index 0000000..39ccb57 --- /dev/null +++ b/typescript/packages/account-modules/test/mocks/MockUSDT.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +// Mock ERC20 token that returns nothing on transfer (like USDT) +contract MockUSDT { + mapping(address => uint256) private _balances; + mapping(address => mapping(address => uint256)) private _allowances; + uint256 private _totalSupply; + + string public name = "Mock USDT"; + string public symbol = "mUSDT"; + uint8 public decimals = 6; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function allowance(address owner, address spender) public view returns (uint256) { + return _allowances[owner][spender]; + } + + // USDT-style transfer that returns nothing + function transfer(address to, uint256 amount) external { + require(_balances[msg.sender] >= amount, "Insufficient balance"); + _balances[msg.sender] -= amount; + _balances[to] += amount; + // No return value - mimics USDT behavior + } + + function approve(address spender, uint256 amount) external returns (bool) { + _allowances[msg.sender][spender] = amount; + return true; + } + + function transferFrom(address from, address to, uint256 amount) external returns (bool) { + require(_balances[from] >= amount, "Insufficient balance"); + require(_allowances[from][msg.sender] >= amount, "Insufficient allowance"); + + _balances[from] -= amount; + _balances[to] += amount; + _allowances[from][msg.sender] -= amount; + + return true; + } + + function mint(address to, uint256 amount) external { + _balances[to] += amount; + _totalSupply += amount; + } +} From c9444e134ca34b4a5f9f56704be3749364c82378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Wed, 7 Jan 2026 10:33:18 -0300 Subject: [PATCH 2/3] chore: clean up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../.github/workflows/test.yml | 40 - .../packages/account-modules/.gitignore | 11 - typescript/packages/account-modules/README.md | 69 - .../docs/auto-collect/architecture.md | 252 - .../docs/auto-top-up/architecture.md | 272 - .../packages/account-modules/foundry.lock | 68 - .../packages/account-modules/foundry.toml | 28 - .../.gitattributes | 1 - .../BokkyPooBahsDateTimeLibrary/.gitignore | 8 - .../lib/BokkyPooBahsDateTimeLibrary/LICENSE | 21 - .../lib/BokkyPooBahsDateTimeLibrary/README.md | 915 - .../BokkyPooBahsDateTimeContract.sol | 177 - .../contracts/BokkyPooBahsDateTimeLibrary.sol | 301 - .../contracts/TestDateTime.sol | 142 - ...ooBahsDateTimeContract_flattened_v1.00.sol | 491 - .../deployment/deployment-v1.00-prerelease.md | 32 - ...enJulianDatesAndGregorianCalendarDates.pdf | Bin 90427 -> 0 bytes .../docs/timestampFromDateTime.png | Bin 188342 -> 0 bytes .../docs/timestampToDateTime.png | Bin 168968 -> 0 bytes .../flattened/TestDateTime_flattened.sol | 439 - .../images/clocks.png | Bin 1843439 -> 0 bytes .../scripts/solidityFlattener.pl | 138 - .../test/00_runGeth.sh | 8 - .../test/01_test1.sh | 605 - .../test/02_attachGeth.sh | 9 - .../test/BokkyPooBahsDateTimeLibrary.js | 11 - .../test/BokkyPooBahsDateTimeLibrary.sol | 300 - .../test/README.md | 56 - .../test/TestDateTime.js | 16 - .../test/TestDateTime.sol | 141 - .../test/deploymentData.js | 11 - .../test/functions.js | 571 - .../test/genesis.json | 112 - .../BokkyPooBahsDateTimeLibrary/test/settings | 21 - .../test/test1output.txt | 3070 ---- .../test/test1results.txt | 2422 --- ...--a00af22d07c87d96eeeb0ed583f8f6ac7812827e | 1 - ...--a11aae29840fbb5c86e6fd4cf809eba183aef433 | 1 - ...--a22ab8a9d641ce77e06d98b7d7065d324d3d6976 | 1 - ...--a33a6c312d9ad0e0f2e95541beed0cc081621fd0 | 1 - ...--a44a08d3f6933c69212114bb66e2df1813651844 | 1 - ...--a55a151eb00fded1634d27d1127b4be4627079ea | 1 - ...--a66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 | 1 - ...--a77a2b9d4b1c010a22a7c565dc418cef683dbcec | 1 - ...--a88a05d2b88283ce84c8325760b72a64591279a2 | 1 - ...--a99a0ae3354c06b1459fd441a32a3f71005d7da0 | 1 - ...--aaaa9de1e6c564446ebca0fd102d8bd92093c756 | 1 - ...--abba43e7594e3b76afb157989e93c6621497fd4b | 1 - ...--acca534c9f62ab495bd986e002ddf0f054caae4f | 1 - ...--adda9b762a00ff12711113bfdc36958b73d7f915 | 1 - ...--aeea63b5479b50f79583ec49dacdcf86ddeff392 | 1 - ...--affa4d3a80add8ce4018540e056dacb649589394 | 1 - ...--b00bfde102270687324f9205b693859df64f8923 | 1 - ...--b11be1d4ef8e94d01cb2695092a79d139a8dad98 | 1 - ...--b22be2d9eef0d7e260cf96a64feea0b95ed3e74f | 1 - ...--b33b7ecf5e47be3981c74d989d3af8b665b4b649 | 1 - ...--b44b43d59b738b088b690ae276c1e979aba8268d | 1 - ...--b55b57d113b45481e31aaf03d6f4e5ad4ef325f8 | 1 - ...--b66bcb4e473de80e2c8a47ced10c22c705a5e602 | 1 - ...--b77bbbaa7c1649547ae61de4b80b91568c28351a | 1 - ...--b88b728490b417e29b0784db30535db343830dba | 1 - ...--b99b3d1f72edb05a0321db58eddcf83fd73c4ade | 1 - ...--baab56da883edbe5314b8005be410022c510ccae | 1 - ...--bbbb9809de0456ce0e0cd660e6e4ceabef3f521c | 1 - ...--bccb68dd0ac87ef290aef49870d155f076c87868 | 1 - ...--bddb726ee06906e104db210e6d0506f2b062e477 | 1 - ...--beeb24ff18203658d0a1d4682ee3f36ad663ec87 | 1 - ...--bffbd8f029ef0bd81cf754b53e8b3a5684f8b3ff | 1 - .../lib/forge-std/.gitattributes | 1 - .../lib/forge-std/.github/CODEOWNERS | 1 - .../lib/forge-std/.github/workflows/ci.yml | 82 - .../lib/forge-std/.github/workflows/sync.yml | 31 - .../account-modules/lib/forge-std/.gitignore | 4 - .../lib/forge-std/CONTRIBUTING.md | 193 - .../lib/forge-std/LICENSE-APACHE | 203 - .../account-modules/lib/forge-std/LICENSE-MIT | 25 - .../account-modules/lib/forge-std/README.md | 266 - .../lib/forge-std/foundry.toml | 23 - .../lib/forge-std/package.json | 16 - .../lib/forge-std/scripts/vm.py | 646 - .../lib/forge-std/src/Base.sol | 42 - .../lib/forge-std/src/Script.sol | 28 - .../lib/forge-std/src/StdAssertions.sol | 764 - .../lib/forge-std/src/StdChains.sol | 286 - .../lib/forge-std/src/StdCheats.sol | 829 - .../lib/forge-std/src/StdConstants.sol | 30 - .../lib/forge-std/src/StdError.sol | 15 - .../lib/forge-std/src/StdInvariant.sol | 122 - .../lib/forge-std/src/StdJson.sol | 283 - .../lib/forge-std/src/StdMath.sol | 43 - .../lib/forge-std/src/StdStorage.sol | 473 - .../lib/forge-std/src/StdStyle.sol | 333 - .../lib/forge-std/src/StdToml.sol | 283 - .../lib/forge-std/src/StdUtils.sol | 208 - .../lib/forge-std/src/Test.sol | 34 - .../account-modules/lib/forge-std/src/Vm.sol | 2468 --- .../lib/forge-std/src/console.sol | 1560 -- .../lib/forge-std/src/console2.sol | 4 - .../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/IERC6909.sol | 72 - .../lib/forge-std/src/interfaces/IERC721.sol | 164 - .../lib/forge-std/src/interfaces/IERC7540.sol | 150 - .../lib/forge-std/src/interfaces/IERC7575.sol | 241 - .../forge-std/src/interfaces/IMulticall3.sol | 73 - .../lib/forge-std/src/safeconsole.sol | 13937 ---------------- .../lib/forge-std/test/CommonBase.t.sol | 44 - .../lib/forge-std/test/StdAssertions.t.sol | 141 - .../lib/forge-std/test/StdChains.t.sol | 227 - .../lib/forge-std/test/StdCheats.t.sol | 639 - .../lib/forge-std/test/StdConstants.t.sol | 38 - .../lib/forge-std/test/StdError.t.sol | 120 - .../lib/forge-std/test/StdJson.t.sol | 49 - .../lib/forge-std/test/StdMath.t.sol | 202 - .../lib/forge-std/test/StdStorage.t.sol | 488 - .../lib/forge-std/test/StdStyle.t.sol | 110 - .../lib/forge-std/test/StdToml.t.sol | 49 - .../lib/forge-std/test/StdUtils.t.sol | 342 - .../lib/forge-std/test/Vm.t.sol | 18 - .../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/forge-std/test/fixtures/test.json | 8 - .../lib/forge-std/test/fixtures/test.toml | 6 - .../lib/modulekit/.changeset/README.md | 8 - .../lib/modulekit/.changeset/config.json | 11 - .../lib/modulekit/.env-example | 2 - .../lib/modulekit/.github/workflows/ci.yaml | 55 - .../.github/workflows/dependency.yml | 88 - .../account-modules/lib/modulekit/.gitignore | 19 - .../account-modules/lib/modulekit/.npmrc | 1 - .../lib/modulekit/.solhint.json | 19 - .../lib/modulekit/.solhintignore | 5 - .../lib/modulekit/CHANGELOG.md | 186 - .../account-modules/lib/modulekit/README.md | 137 - .../lib/modulekit/docs/Accounts.md | 45 - .../lib/modulekit/foundry.toml | 27 - .../lib/modulekit/gas_calculations/.gitkeep | 0 .../lib/modulekit/octanerc.json | 3 - .../lib/modulekit/package.json | 66 - .../lib/modulekit/pnpm-lock.yaml | 4803 ------ .../lib/modulekit/remappings.txt | 12 - .../lib/modulekit/src/Accounts.sol | 28 - .../lib/modulekit/src/Helpers.sol | 40 - .../lib/modulekit/src/Integrations.sol | 18 - .../lib/modulekit/src/Interfaces.sol | 30 - .../lib/modulekit/src/Mocks.sol | 31 - .../lib/modulekit/src/ModuleKit.sol | 22 - .../lib/modulekit/src/Modules.sol | 55 - .../common/interfaces/IERC4337Account.sol | 75 - .../common/interfaces/IERC7579Account.sol | 131 - .../common/interfaces/IERC7579Module.sol | 162 - .../src/accounts/common/lib/ModeLib.sol | 160 - .../src/accounts/erc7579/ERC7579Factory.sol | 151 - .../erc7579/helpers/ExecutionHelper.sol | 139 - .../erc7579/interfaces/IERC7579Bootstrap.sol | 38 - .../src/accounts/erc7579/interfaces/IMSA.sol | 28 - .../src/accounts/erc7579/lib/ExecutionLib.sol | 86 - .../factory/interface/IAccountFactory.sol | 36 - .../factory/template/FactoryTemplate.sol | 39 - .../src/accounts/kernel/KernelFactory.sol | 181 - .../accounts/kernel/interfaces/IAccount.sol | 58 - .../kernel/interfaces/IAccountExecute.sol | 26 - .../kernel/interfaces/IERC7579Account.sol | 133 - .../kernel/interfaces/IERC7579Module.sol | 133 - .../accounts/kernel/interfaces/IKernel.sol | 151 - .../kernel/interfaces/IKernelFactory.sol | 7 - .../kernel/interfaces/IValidationManager.sol | 32 - .../src/accounts/kernel/lib/ExecLib.sol | 325 - .../accounts/kernel/lib/ValidationTypeLib.sol | 244 - .../src/accounts/kernel/mock/MockFallback.sol | 78 - .../src/accounts/kernel/types/Constants.sol | 83 - .../src/accounts/kernel/types/Structs.sol | 8 - .../src/accounts/kernel/types/Types.sol | 115 - .../src/accounts/nexus/NexusFactory.sol | 177 - .../src/accounts/nexus/interfaces/INexus.sol | 44 - .../nexus/interfaces/INexusAccountFactory.sol | 30 - .../nexus/interfaces/INexusBootstrap.sol | 104 - .../src/accounts/safe/SafeFactory.sol | 190 - .../src/accounts/safe/interfaces/IERC7484.sol | 48 - .../safe/interfaces/IERC7579Account.sol | 137 - .../accounts/safe/interfaces/ISafe7579.sol | 268 - .../safe/interfaces/ISafe7579Launchpad.sol | 130 - .../src/accounts/safe/interfaces/ISafeOp.sol | 82 - .../safe/interfaces/ISafeProxyFactory.sol | 33 - .../src/accounts/safe/types/DataTypes.sol | 29 - .../precompiles/BytecodeDeployer.sol | 32 - .../precompiles/ERC7579Precompiles.sol | 67 - .../precompiles/KernelPrecompiles.sol | 65 - .../precompiles/NexusPrecompiles.sol | 88 - .../precompiles/Safe7579Precompiles.sol | 63 - .../precompiles/SmartSessionsPrecompiles.sol | 23 - .../src/deployment/predeploy/EntryPoint.sol | 47 - .../src/deployment/predeploy/MockFactory.sol | 22 - .../src/deployment/predeploy/Registry.sol | 20 - .../deployment/registry/RegistryDeployer.sol | 216 - .../registry/interfaces/IERC7484.sol | 52 - .../registry/interfaces/IExternalResolver.sol | 68 - .../interfaces/IExternalSchemaValidator.sol | 23 - .../registry/interfaces/IRegistry.sol | 419 - .../deployment/registry/types/DataTypes.sol | 128 - .../lib/modulekit/src/external/ERC4337.sol | 41 - .../lib/modulekit/src/integrations/ERC20.sol | 129 - .../modulekit/src/integrations/ERC4626.sol | 76 - .../lib/modulekit/src/integrations/ERC721.sol | 43 - .../src/integrations/ERC7579Exec.sol | 108 - .../integrations/interfaces/IBotRegistry.sol | 7 - .../integrations/interfaces/IDFSRegistry.sol | 23 - .../src/integrations/interfaces/IDSProxy.sol | 24 - .../src/integrations/interfaces/IERC20.sol | 34 - .../src/integrations/interfaces/IERC4626.sol | 30 - .../src/integrations/interfaces/IERC721.sol | 21 - .../interfaces/IERC721Enumerable.sol | 11 - .../interfaces/IFLParamGetter.sol | 11 - .../src/integrations/interfaces/IGasToken.sol | 15 - .../integrations/interfaces/ILendingPool.sol | 187 - .../interfaces/IMCDPriceVerifier.sol | 16 - .../integrations/interfaces/IProxyERC20.sol | 8 - .../interfaces/IProxyRegistry.sol | 8 - .../integrations/interfaces/ISmartSession.sol | 364 - .../interfaces/ISubscriptions.sol | 10 - .../src/integrations/interfaces/ITrigger.sol | 9 - .../src/integrations/interfaces/IWETH.sol | 21 - .../integrations/interfaces/LSTs/ICBETH.sol | 7 - .../integrations/interfaces/LSTs/IRETH.sol | 8 - .../integrations/interfaces/LSTs/IWstETH.sol | 8 - .../integrations/interfaces/aave/IAToken.sol | 9 - .../interfaces/aave/ILendToAaveMigrator.sol | 7 - .../interfaces/aave/ILendingPool.sol | 179 - .../aave/ILendingPoolAddressesProvider.sol | 55 - .../integrations/interfaces/aave/IStkAave.sol | 11 - .../aaveV2/IAaveIncentivesController.sol | 108 - .../aaveV2/IAaveProtocolDataProviderV2.sol | 77 - .../ILendingPoolAddressesProviderV2.sol | 48 - .../interfaces/aaveV2/ILendingPoolV2.sol | 517 - .../aaveV2/IPriceOracleGetterAave.sol | 14 - .../interfaces/aaveV2/IStakedToken.sol | 6 - .../interfaces/aaveV3/DataTypes.sol | 271 - .../aaveV3/IAaveProtocolDataProvider.sol | 39 - .../interfaces/aaveV3/IAaveV3Oracle.sol | 66 - .../interfaces/aaveV3/IL2PoolV3.sol | 140 - .../aaveV3/IPoolAddressesProvider.sol | 229 - .../interfaces/aaveV3/IPoolV3.sol | 867 - .../interfaces/aaveV3/IPriceOracleGetter.sol | 28 - .../aaveV3/IPriceOracleSentinel.sol | 54 - .../interfaces/aaveV3/IRewardsController.sol | 189 - .../interfaces/aaveV3/IRewardsDistributor.sol | 201 - .../balancer/IFlashLoanRecipient.sol | 24 - .../interfaces/balancer/IFlashLoans.sol | 12 - .../interfaces/balancer/IMerkleRedeem.sol | 14 - .../interfaces/balancer/IPool.sol | 6 - .../interfaces/balancer/IVault.sol | 44 - .../interfaces/bprotocol/IBAMM.sol | 7 - .../interfaces/chainlink/IAggregatorV3.sol | 43 - .../interfaces/chainlink/IFeedRegistry.sol | 183 - .../interfaces/chainlink/IPhaseAggregator.sol | 15 - .../interfaces/compound/ICToken.sol | 71 - .../interfaces/compound/ICompoundOracle.sol | 7 - .../interfaces/compound/IComptroller.sol | 54 - .../interfaces/compoundV3/IComet.sol | 142 - .../interfaces/compoundV3/ICometExt.sol | 16 - .../interfaces/compoundV3/ICometRewards.sol | 36 - .../interfaces/convex/IBaseRewardPool.sol | 16 - .../interfaces/convex/IBooster.sol | 17 - .../interfaces/convex/IConvexToken.sol | 10 - .../interfaces/convex/IRewardPool.sol | 7 - .../interfaces/curve/IAddressProvider.sol | 9 - .../interfaces/curve/ICurve3PoolZap.sol | 9 - .../interfaces/curve/ICurveFactory.sol | 24 - .../interfaces/curve/IDepositZap.sol | 8 - .../interfaces/curve/IFeeDistributor.sol | 7 - .../interfaces/curve/ILiquidityGauge.sol | 20 - .../integrations/interfaces/curve/IMinter.sol | 8 - .../interfaces/curve/IRegistry.sol | 19 - .../integrations/interfaces/curve/ISwaps.sol | 174 - .../interfaces/curve/IVotingEscrow.sol | 10 - .../curve/stethPool/ICurveStethPool.sol | 8 - .../interfaces/curveusd/ICurveUsd.sol | 157 - .../interfaces/dydx/ISoloMargin.sol | 463 - .../integrations/interfaces/euler/IDToken.sol | 6 - .../interfaces/euler/IEulerMarkets.sol | 6 - .../interfaces/exchange/IExchangeV3.sol | 41 - .../interfaces/exchange/IExchangeWrapper.sol | 45 - .../exchange/IKyberNetworkProxy.sol | 92 - .../interfaces/exchange/IOasis.sol | 45 - .../exchange/IOffchainWrapper.sol.bak | 16 - .../interfaces/exchange/IPair.sol | 18 - .../interfaces/exchange/IQuoter.sol | 70 - .../interfaces/exchange/ISwapRouter.sol | 105 - .../interfaces/exchange/IUniswapRouter.sol | 117 - .../flashloan/IERC3156FlashBorrower.sol | 23 - .../flashloan/IERC3156FlashLender.sol | 37 - .../interfaces/flashloan/IFlashLoanBase.sol | 14 - .../interfaces/guni/IGUniPool.sol | 7 - .../interfaces/guni/IGUniRouter02.sol | 41 - .../interfaces/insta/IInstaAccountV2.sol | 7 - .../interfaces/insta/IInstaIndex.sol | 12 - .../insta/IInstaMakerDAOMerkleDistributor.sol | 24 - .../interfaces/kyber/IAggregationExecutor.sol | 17 - .../interfaces/kyber/IExecutorHelper.sol | 382 - .../kyber/IMetaAggregationRouterV2.sol | 44 - .../integrations/interfaces/lido/IWStEth.sol | 11 - .../interfaces/liquity/IBondNFT.sol | 29 - .../interfaces/liquity/IBondNFTArtwork.sol | 15 - .../liquity/IBorrowerOperations.sol | 75 - .../liquity/IChickenBondManager.sol | 82 - .../interfaces/liquity/ICollSurplusPool.sol | 30 - .../interfaces/liquity/IHintHelpers.sol | 38 - .../interfaces/liquity/ILQTYStaking.sol | 46 - .../interfaces/liquity/IPriceFeed.sol | 8 - .../interfaces/liquity/ISortedTroves.sol | 64 - .../interfaces/liquity/IStabilityPool.sol | 168 - .../interfaces/liquity/ITroveManager.sol | 148 - .../src/integrations/interfaces/mcd/ICat.sol | 13 - .../interfaces/mcd/ICdpRegistry.sol | 14 - .../integrations/interfaces/mcd/ICropJoin.sol | 9 - .../integrations/interfaces/mcd/ICropper.sol | 13 - .../integrations/interfaces/mcd/IDSPause.sol | 7 - .../integrations/interfaces/mcd/IDaiJoin.sol | 12 - .../integrations/interfaces/mcd/IDssSpell.sol | 9 - .../src/integrations/interfaces/mcd/IGem.sol | 17 - .../integrations/interfaces/mcd/IGetCdps.sol | 22 - .../src/integrations/interfaces/mcd/IJoin.sol | 14 - .../src/integrations/interfaces/mcd/IJug.sol | 14 - .../integrations/interfaces/mcd/IManager.sol | 23 - .../src/integrations/interfaces/mcd/IOsm.sol | 8 - .../interfaces/mcd/IPipInterface.sol | 8 - .../src/integrations/interfaces/mcd/IPot.sol | 12 - .../integrations/interfaces/mcd/ISpotter.sol | 16 - .../src/integrations/interfaces/mcd/IVat.sol | 30 - .../interfaces/morpho/IMorpho.sol | 135 - .../interfaces/morpho/IMorphoAaveV2Lens.sol | 257 - .../interfaces/morpho/IMorphoAaveV3.sol | 236 - .../interfaces/morpho/IRewardsDistributor.sol | 8 - .../interfaces/morpho/MorphoTypes.sol | 126 - .../interfaces/morpho/MorphoTypesAaveV3.sol | 991 -- .../mstable/IBoostedVaultWithLockup.sol | 75 - .../interfaces/mstable/ISavingsContractV2.sol | 35 - .../interfaces/mstable/ImAsset.sol | 151 - .../interfaces/qidao/IQiDaoRegistry.sol | 2 - .../interfaces/qidao/IStablecoin.sol | 48 - .../interfaces/rari/IFundController.sol | 7 - .../interfaces/rari/IFundManager.sol | 11 - .../interfaces/rari/IFundProxy.sol | 15 - .../interfaces/rari/IFuseAsset.sol | 7 - .../reflexer/IBasicTokenAdapters.sol | 12 - .../interfaces/reflexer/ICoinJoin.sol | 10 - .../interfaces/reflexer/IFSMWrapper.sol | 6 - .../interfaces/reflexer/IGetSafes.sol | 22 - .../interfaces/reflexer/IMedianOracle.sol | 7 - .../interfaces/reflexer/IOracleRelayer.sol | 16 - .../interfaces/reflexer/ISAFEEngine.sol | 53 - .../interfaces/reflexer/ISAFEManager.sol | 25 - .../interfaces/reflexer/ISAFESaviour.sol | 11 - .../interfaces/reflexer/ITaxCollector.sol | 14 - .../integrations/interfaces/spark/IsDAI.sol | 11 - .../interfaces/strategy/ISubStorage.sol | 13 - .../interfaces/uniswap/IUniswapV2Factory.sol | 11 - .../interfaces/uniswap/IUniswapV2Pair.sol | 11 - .../interfaces/uniswap/v3/IQuoter.sol | 71 - .../interfaces/uniswap/v3/ISwapRouter.sol | 85 - .../uniswap/v3/IUniswapV3Factory.sol | 15 - .../uniswap/v3/IUniswapV3FlashCallback.sol | 6 - .../IUniswapV3NonfungiblePositionManager.sol | 115 - .../interfaces/uniswap/v3/IUniswapV3Pool.sol | 39 - .../uniswap/v3/IUniswapV3SwapCallback.sol | 25 - .../integrations/interfaces/yearn/IYVault.sol | 18 - .../interfaces/yearn/IYearnRegistry.sol | 9 - .../integrations/registry/ExampleFactory.sol | 147 - .../src/integrations/registry/FactoryBase.sol | 22 - .../src/integrations/uniswap/MockUniswap.sol | 52 - .../uniswap/helpers/MainnetAddresses.sol | 7 - .../src/integrations/uniswap/v3/Uniswap.sol | 197 - .../lib/modulekit/src/mocks/MockERC20.sol | 257 - .../lib/modulekit/src/mocks/MockERC721.sol | 258 - .../src/module-bases/ERC1271Policy.sol | 19 - .../module-bases/ERC7484RegistryAdapter.sol | 20 - .../src/module-bases/ERC7579ActionPolicy.sol | 18 - .../src/module-bases/ERC7579ExecutorBase.sol | 109 - .../src/module-bases/ERC7579FallbackBase.sol | 27 - .../src/module-bases/ERC7579HookBase.sol | 68 - .../src/module-bases/ERC7579HookDestruct.sol | 275 - .../ERC7579HookDestructSingleHook.sol | 275 - .../ERC7579HybridValidatorBase.sol | 17 - .../src/module-bases/ERC7579ModuleBase.sol | 23 - .../src/module-bases/ERC7579PolicyBase.sol | 15 - .../ERC7579StatelessValidatorBase.sol | 17 - .../src/module-bases/ERC7579UserOpPolicy.sol | 16 - .../src/module-bases/ERC7579ValidatorBase.sol | 65 - .../module-bases/ERC7579ValidatorMaster.sol | 68 - .../src/module-bases/SchedulingBase.sol | 145 - .../src/module-bases/interfaces/Flashloan.sol | 75 - .../src/module-bases/interfaces/IERC1271.sol | 25 - .../src/module-bases/interfaces/IERC712.sol | 6 - .../src/module-bases/interfaces/IERC7484.sol | 49 - .../src/module-bases/interfaces/IPolicy.sol | 111 - .../interfaces/IStatelessValidator.sol | 13 - .../src/module-bases/mocks/MockExecutor.sol | 38 - .../src/module-bases/mocks/MockFallback.sol | 28 - .../src/module-bases/mocks/MockHook.sol | 36 - .../mocks/MockHookMultiPlexer.sol | 116 - .../mocks/MockHybridValidator.sol | 65 - .../src/module-bases/mocks/MockPolicy.sol | 72 - .../src/module-bases/mocks/MockRegistry.sol | 44 - .../mocks/MockStatelessValidator.sol | 31 - .../src/module-bases/mocks/MockTarget.sol | 21 - .../src/module-bases/mocks/MockValidator.sol | 53 - .../module-bases/utils/ERC7579Constants.sol | 12 - .../utils/ERC7579ValidatorLib.sol | 190 - .../module-bases/utils/TrustedForwarder.sol | 56 - .../lib/modulekit/src/test/Auxiliary.sol | 60 - .../modulekit/src/test/ModuleKitHelpers.sol | 1322 -- .../src/test/RhinestoneModuleKit.sol | 471 - .../src/test/helpers/ERC7579Helpers.sol | 164 - .../modulekit/src/test/helpers/HelperBase.sol | 661 - .../src/test/helpers/KernelHelpers.sol | 584 - .../src/test/helpers/NexusHelpers.sol | 292 - .../src/test/helpers/SafeHelpers.sol | 535 - .../src/test/helpers/SmartSessionHelpers.sol | 393 - .../interfaces/IAccountModulesPaginated.sol | 20 - .../lib/modulekit/src/test/utils/ECDSA.sol | 10 - .../src/test/utils/ERC4337Helpers.sol | 272 - .../lib/modulekit/src/test/utils/Log.sol | 19 - .../lib/modulekit/src/test/utils/Storage.sol | 413 - .../lib/modulekit/src/test/utils/Vm.sol | 206 - .../src/test/utils/gas/GasCalculations.sol | 140 - .../src/test/utils/gas/GasParser.sol | 113 - .../src/test/utils/gas/UserOpGasLog.sol | 68 - .../lib/modulekit/test/BaseTest.t.sol | 28 - .../lib/modulekit/test/Diff.t.sol | 910 - .../modulekit/test/GasCalculationsTest.sol | 26 - .../lib/modulekit/test/RegistryDeployer.t.sol | 203 - .../test/integrations/ExampleFactory.t.sol | 75 - .../test/integrations/SmartSession.t.sol | 405 - .../test/integrations/SwapTest.t.sol | 103 - .../modulekit/test/mocks/MockK1Validator.sol | 70 - .../MockK1ValidatorUncompliantUninstall.sol | 69 - .../test/mocks/MockValidatorFalse.sol | 66 - .../.changeset/config.json | 12 - .../lib/openzeppelin-contracts/.codecov.yml | 16 - .../lib/openzeppelin-contracts/.editorconfig | 21 - .../.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 | 51 - .../.github/actions/setup/action.yml | 22 - .../.github/actions/storage-layout/action.yml | 57 - .../.github/workflows/actionlint.yml | 18 - .../.github/workflows/changeset.yml | 28 - .../.github/workflows/checks.yml | 132 - .../.github/workflows/docs.yml | 19 - .../.github/workflows/formal-verification.yml | 86 - .../.github/workflows/release-cycle.yml | 214 - .../.github/workflows/upgradeable.yml | 34 - .../lib/openzeppelin-contracts/.gitignore | 67 - .../lib/openzeppelin-contracts/.gitmodules | 10 - .../openzeppelin-contracts/.husky/pre-commit | 2 - .../lib/openzeppelin-contracts/.mocharc.js | 4 - .../lib/openzeppelin-contracts/.prettierrc | 15 - .../lib/openzeppelin-contracts/.solcover.js | 21 - .../lib/openzeppelin-contracts/CHANGELOG.md | 1278 -- .../openzeppelin-contracts/CODE_OF_CONDUCT.md | 73 - .../openzeppelin-contracts/CONTRIBUTING.md | 36 - .../lib/openzeppelin-contracts/FUNDING.json | 10 - .../lib/openzeppelin-contracts/GUIDELINES.md | 155 - .../lib/openzeppelin-contracts/LICENSE | 22 - .../lib/openzeppelin-contracts/README.md | 108 - .../lib/openzeppelin-contracts/RELEASING.md | 45 - .../lib/openzeppelin-contracts/SECURITY.md | 43 - .../openzeppelin-contracts/audits/2017-03.md | 292 - .../openzeppelin-contracts/audits/2018-10.pdf | Bin 1000527 -> 0 bytes .../audits/2022-10-Checkpoints.pdf | Bin 155606 -> 0 bytes .../audits/2022-10-ERC4626.pdf | Bin 204184 -> 0 bytes .../audits/2023-05-v4.9.pdf | Bin 485395 -> 0 bytes .../audits/2023-10-v5.0.pdf | Bin 910284 -> 0 bytes .../audits/2024-10-v5.1.pdf | Bin 395831 -> 0 bytes .../audits/2024-12-v5.2.pdf | Bin 242253 -> 0 bytes .../audits/2025-04-v5.3.pdf | Bin 154227 -> 0 bytes .../openzeppelin-contracts/audits/README.md | 20 - .../openzeppelin-contracts/certora/.gitignore | 1 - .../openzeppelin-contracts/certora/Makefile | 54 - .../openzeppelin-contracts/certora/README.md | 60 - .../access_manager_AccessManager.sol.patch | 97 - .../AccessControlDefaultAdminRulesHarness.sol | 46 - .../harnesses/AccessControlHarness.sol | 6 - .../harnesses/AccessManagedHarness.sol | 36 - .../harnesses/AccessManagerHarness.sol | 116 - .../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/NoncesHarness.sol | 14 - .../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 92882 -> 0 bytes .../certora/reports/2022-03.pdf | Bin 199401 -> 0 bytes .../certora/reports/2022-05.pdf | Bin 132223 -> 0 bytes .../lib/openzeppelin-contracts/certora/run.js | 168 - .../openzeppelin-contracts/certora/specs.json | 110 - .../certora/specs/AccessControl.spec | 119 - .../specs/AccessControlDefaultAdminRules.spec | 464 - .../certora/specs/AccessManaged.spec | 34 - .../certora/specs/AccessManager.spec | 826 - .../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/Nonces.spec | 92 - .../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 | 12 - .../certora/specs/methods/IAccessControl.spec | 8 - .../IAccessControlDefaultAdminRules.spec | 36 - .../certora/specs/methods/IAccessManaged.spec | 5 - .../certora/specs/methods/IAccessManager.spec | 33 - .../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 | 207 - .../contracts/access/IAccessControl.sol | 98 - .../contracts/access/Ownable.sol | 100 - .../contracts/access/Ownable2Step.sol | 67 - .../contracts/access/README.adoc | 45 - .../AccessControlDefaultAdminRules.sol | 372 - .../extensions/AccessControlEnumerable.sol | 81 - .../IAccessControlDefaultAdminRules.sol | 192 - .../extensions/IAccessControlEnumerable.sol | 31 - .../access/manager/AccessManaged.sol | 112 - .../access/manager/AccessManager.sol | 740 - .../access/manager/AuthorityUtils.sol | 36 - .../access/manager/IAccessManaged.sol | 32 - .../access/manager/IAccessManager.sol | 399 - .../contracts/access/manager/IAuthority.sol | 14 - .../contracts/account/Account.sol | 145 - .../contracts/account/README.adoc | 30 - .../extensions/draft-AccountERC7579.sol | 405 - .../extensions/draft-AccountERC7579Hooked.sol | 107 - .../account/extensions/draft-ERC7821.sol | 70 - .../contracts/account/utils/EIP7702Utils.sol | 21 - .../account/utils/draft-ERC4337Utils.sol | 159 - .../account/utils/draft-ERC7579Utils.sol | 280 - .../contracts/finance/README.adoc | 14 - .../contracts/finance/VestingWallet.sol | 159 - .../contracts/finance/VestingWalletCliff.sol | 54 - .../contracts/governance/Governor.sol | 818 - .../contracts/governance/IGovernor.sol | 454 - .../contracts/governance/README.adoc | 197 - .../governance/TimelockController.sol | 471 - .../extensions/GovernorCountingFractional.sol | 190 - .../GovernorCountingOverridable.sol | 222 - .../extensions/GovernorCountingSimple.sol | 96 - .../extensions/GovernorNoncesKeyed.sol | 91 - .../extensions/GovernorPreventLateQuorum.sol | 92 - .../extensions/GovernorProposalGuardian.sol | 58 - .../GovernorSequentialProposalId.sol | 75 - .../extensions/GovernorSettings.sol | 106 - .../governance/extensions/GovernorStorage.sol | 125 - .../extensions/GovernorSuperQuorum.sol | 58 - .../extensions/GovernorTimelockAccess.sol | 346 - .../extensions/GovernorTimelockCompound.sol | 165 - .../extensions/GovernorTimelockControl.sol | 167 - .../governance/extensions/GovernorVotes.sol | 63 - .../GovernorVotesQuorumFraction.sol | 113 - .../GovernorVotesSuperQuorumFraction.sol | 134 - .../contracts/governance/utils/IVotes.sol | 59 - .../contracts/governance/utils/Votes.sol | 252 - .../governance/utils/VotesExtended.sol | 84 - .../contracts/interfaces/IERC1155.sol | 6 - .../interfaces/IERC1155MetadataURI.sol | 6 - .../contracts/interfaces/IERC1155Receiver.sol | 6 - .../contracts/interfaces/IERC1271.sol | 17 - .../contracts/interfaces/IERC1363.sol | 86 - .../contracts/interfaces/IERC1363Receiver.sol | 32 - .../contracts/interfaces/IERC1363Spender.sol | 26 - .../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 | 26 - .../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/IERC7913.sol | 18 - .../contracts/interfaces/README.adoc | 102 - .../contracts/interfaces/draft-IERC1822.sol | 20 - .../contracts/interfaces/draft-IERC4337.sol | 253 - .../contracts/interfaces/draft-IERC6093.sol | 161 - .../contracts/interfaces/draft-IERC6909.sol | 125 - .../contracts/interfaces/draft-IERC7579.sol | 226 - .../contracts/interfaces/draft-IERC7674.sol | 17 - .../contracts/interfaces/draft-IERC7802.sol | 31 - .../contracts/interfaces/draft-IERC7821.sol | 44 - .../contracts/metatx/ERC2771Context.sol | 90 - .../contracts/metatx/ERC2771Forwarder.sol | 372 - .../contracts/metatx/README.adoc | 17 - .../contracts/mocks/AccessManagedTarget.sol | 34 - .../contracts/mocks/AccessManagerMock.sol | 20 - .../contracts/mocks/ArraysMock.sol | 171 - .../contracts/mocks/AuthorityMock.sol | 69 - .../contracts/mocks/Base64Dirty.sol | 19 - .../contracts/mocks/BatchCaller.sol | 20 - .../contracts/mocks/CallReceiverMock.sol | 78 - .../contracts/mocks/ConstructorMock.sol | 34 - .../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 | 28 - .../mocks/ERC3156FlashBorrowerMock.sol | 53 - .../contracts/mocks/EtherReceiverMock.sol | 17 - .../contracts/mocks/InitializableMock.sol | 130 - .../mocks/MerkleProofCustomHashMock.sol | 62 - .../contracts/mocks/MerkleTreeMock.sol | 52 - .../contracts/mocks/MulticallHelper.sol | 23 - .../MultipleInheritanceInitializableMocks.sol | 131 - .../contracts/mocks/PausableMock.sol | 31 - .../contracts/mocks/ReentrancyAttack.sol | 12 - .../contracts/mocks/ReentrancyMock.sol | 50 - .../mocks/ReentrancyTransientMock.sol | 50 - .../mocks/RegressionImplementation.sol | 61 - .../SingleInheritanceInitializableMocks.sol | 49 - .../contracts/mocks/Stateless.sol | 53 - .../contracts/mocks/StorageSlotMock.sol | 87 - .../contracts/mocks/TimelockReentrant.sol | 26 - .../contracts/mocks/TransientSlotMock.sol | 61 - .../contracts/mocks/UpgradeableBeaconMock.sol | 27 - .../contracts/mocks/VotesExtendedMock.sol | 42 - .../contracts/mocks/VotesMock.sol | 42 - .../contracts/mocks/account/AccountMock.sol | 169 - .../mocks/account/modules/ERC7579Mock.sol | 115 - .../mocks/account/utils/ERC7579UtilsMock.sol | 23 - .../contracts/mocks/compound/CompTimelock.sol | 174 - .../mocks/docs/ERC20WithAutoMinerReward.sol | 22 - .../contracts/mocks/docs/ERC4626Fees.sol | 109 - .../contracts/mocks/docs/MyNFT.sol | 9 - .../AccessControlERC20MintBase.sol | 25 - .../AccessControlERC20MintMissing.sol | 24 - .../AccessControlERC20MintOnlyRole.sol | 23 - .../access-control/AccessControlModified.sol | 14 - .../AccessManagedERC20MintBase.sol | 16 - .../docs/access-control/MyContractOwnable.sol | 17 - .../mocks/docs/account/MyAccountERC7702.sol | 20 - .../mocks/docs/account/MyFactoryAccount.sol | 37 - .../mocks/docs/governance/MyGovernor.sol | 80 - .../mocks/docs/governance/MyToken.sol | 21 - .../docs/governance/MyTokenTimestampBased.sol | 32 - .../mocks/docs/governance/MyTokenWrapped.sol | 28 - .../mocks/docs/token/ERC1155/GameItems.sol | 21 - .../token/ERC1155/MyERC115HolderContract.sol | 7 - .../mocks/docs/token/ERC20/GLDToken.sol | 11 - .../docs/token/ERC6909/ERC6909GameItems.sol | 26 - .../mocks/docs/token/ERC721/GameItem.sol | 19 - .../mocks/docs/utilities/Base64NFT.sol | 27 - .../mocks/docs/utilities/Multicall.sol | 15 - .../GovernorCountingOverridableMock.sol | 18 - .../governance/GovernorFractionalMock.sol | 14 - .../mocks/governance/GovernorMock.sol | 14 - .../governance/GovernorNoncesKeyedMock.sol | 45 - .../GovernorPreventLateQuorumMock.sol | 40 - .../GovernorProposalGuardianMock.sol | 27 - .../GovernorSequentialProposalIdMock.sol | 39 - .../mocks/governance/GovernorStorageMock.sol | 79 - .../governance/GovernorSuperQuorumMock.sol | 95 - .../governance/GovernorTimelockAccessMock.sol | 70 - .../GovernorTimelockCompoundMock.sol | 69 - .../GovernorTimelockControlMock.sol | 69 - .../mocks/governance/GovernorVoteMock.sol | 20 - .../GovernorVotesSuperQuorumFractionMock.sol | 37 - .../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/ERC1363ForceApproveMock.sol | 13 - .../mocks/token/ERC1363NoReturnMock.sol | 33 - .../mocks/token/ERC1363ReceiverMock.sol | 52 - .../mocks/token/ERC1363ReturnFalseMock.sol | 34 - .../mocks/token/ERC1363SpenderMock.sol | 47 - .../mocks/token/ERC20ApprovalMock.sol | 10 - .../mocks/token/ERC20BridgeableMock.sol | 26 - .../mocks/token/ERC20DecimalsMock.sol | 17 - .../mocks/token/ERC20ExcessDecimalsMock.sol | 9 - .../mocks/token/ERC20FlashMintMock.sol | 26 - .../mocks/token/ERC20ForceApproveMock.sol | 13 - .../mocks/token/ERC20GetterHelper.sol | 38 - .../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 - .../ERC20VotesAdditionalCheckpointsMock.sol | 31 - .../mocks/token/ERC20VotesLegacyMock.sol | 253 - .../mocks/token/ERC20VotesTimestampMock.sol | 29 - .../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 - .../mocks/utils/cryptography/ERC7739Mock.sol | 13 - .../contracts/package.json | 32 - .../contracts/proxy/Clones.sol | 294 - .../contracts/proxy/ERC1967/ERC1967Proxy.sol | 40 - .../contracts/proxy/ERC1967/ERC1967Utils.sol | 177 - .../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 | 118 - .../contracts/proxy/utils/Initializable.sol | 238 - .../contracts/proxy/utils/UUPSUpgradeable.sol | 146 - .../contracts/token/ERC1155/ERC1155.sol | 389 - .../contracts/token/ERC1155/IERC1155.sol | 123 - .../token/ERC1155/IERC1155Receiver.sol | 59 - .../contracts/token/ERC1155/README.adoc | 43 - .../ERC1155/extensions/ERC1155Burnable.sol | 28 - .../ERC1155/extensions/ERC1155Pausable.sol | 38 - .../ERC1155/extensions/ERC1155Supply.sol | 88 - .../ERC1155/extensions/ERC1155URIStorage.sol | 61 - .../extensions/IERC1155MetadataURI.sol | 20 - .../token/ERC1155/utils/ERC1155Holder.sol | 40 - .../token/ERC1155/utils/ERC1155Utils.sol | 88 - .../contracts/token/ERC20/ERC20.sol | 305 - .../contracts/token/ERC20/IERC20.sol | 79 - .../contracts/token/ERC20/README.adoc | 78 - .../token/ERC20/extensions/ERC1363.sol | 135 - .../token/ERC20/extensions/ERC20Burnable.sol | 39 - .../token/ERC20/extensions/ERC20Capped.sol | 54 - .../token/ERC20/extensions/ERC20FlashMint.sol | 134 - .../token/ERC20/extensions/ERC20Pausable.sol | 33 - .../token/ERC20/extensions/ERC20Permit.sol | 77 - .../token/ERC20/extensions/ERC20Votes.sol | 83 - .../token/ERC20/extensions/ERC20Wrapper.sol | 89 - .../token/ERC20/extensions/ERC4626.sol | 282 - .../token/ERC20/extensions/IERC20Metadata.sol | 26 - .../token/ERC20/extensions/IERC20Permit.sol | 90 - .../extensions/draft-ERC20Bridgeable.sol | 51 - .../draft-ERC20TemporaryApproval.sol | 119 - .../token/ERC20/utils/ERC1363Utils.sol | 95 - .../contracts/token/ERC20/utils/SafeERC20.sol | 212 - .../contracts/token/ERC6909/README.adoc | 27 - .../contracts/token/ERC6909/draft-ERC6909.sol | 224 - .../extensions/draft-ERC6909ContentURI.sol | 53 - .../extensions/draft-ERC6909Metadata.sol | 77 - .../extensions/draft-ERC6909TokenSupply.sol | 35 - .../contracts/token/ERC721/ERC721.sol | 430 - .../contracts/token/ERC721/IERC721.sol | 135 - .../token/ERC721/IERC721Receiver.sol | 28 - .../contracts/token/ERC721/README.adoc | 69 - .../ERC721/extensions/ERC721Burnable.sol | 26 - .../ERC721/extensions/ERC721Consecutive.sol | 176 - .../ERC721/extensions/ERC721Enumerable.sol | 164 - .../ERC721/extensions/ERC721Pausable.sol | 37 - .../token/ERC721/extensions/ERC721Royalty.sol | 26 - .../ERC721/extensions/ERC721URIStorage.sol | 58 - .../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 - .../token/ERC721/utils/ERC721Utils.sol | 50 - .../contracts/token/common/ERC2981.sol | 139 - .../contracts/token/common/README.adoc | 10 - .../contracts/utils/Address.sol | 149 - .../contracts/utils/Arrays.sol | 552 - .../contracts/utils/Base64.sol | 119 - .../contracts/utils/Blockhash.sol | 53 - .../contracts/utils/Bytes.sol | 113 - .../contracts/utils/CAIP10.sol | 54 - .../contracts/utils/CAIP2.sol | 51 - .../contracts/utils/Calldata.sol | 25 - .../contracts/utils/Comparators.sol | 19 - .../contracts/utils/Context.sol | 28 - .../contracts/utils/Create2.sol | 92 - .../contracts/utils/Errors.sol | 34 - .../contracts/utils/Multicall.sol | 37 - .../contracts/utils/Nonces.sol | 46 - .../contracts/utils/NoncesKeyed.sol | 74 - .../contracts/utils/Packing.sol | 1656 -- .../contracts/utils/Panic.sol | 57 - .../contracts/utils/Pausable.sol | 112 - .../contracts/utils/README.adoc | 139 - .../contracts/utils/ReentrancyGuard.sol | 87 - .../utils/ReentrancyGuardTransient.sol | 61 - .../contracts/utils/ShortStrings.sol | 122 - .../contracts/utils/SlotDerivation.sol | 155 - .../contracts/utils/StorageSlot.sol | 143 - .../contracts/utils/Strings.sol | 490 - .../contracts/utils/TransientSlot.sol | 183 - .../contracts/utils/cryptography/ECDSA.sol | 180 - .../contracts/utils/cryptography/EIP712.sol | 160 - .../contracts/utils/cryptography/Hashes.sol | 31 - .../utils/cryptography/MerkleProof.sol | 514 - .../utils/cryptography/MessageHashUtils.sol | 99 - .../contracts/utils/cryptography/P256.sol | 408 - .../contracts/utils/cryptography/README.adoc | 67 - .../contracts/utils/cryptography/RSA.sol | 154 - .../utils/cryptography/SignatureChecker.sol | 135 - .../utils/cryptography/draft-ERC7739Utils.sol | 207 - .../cryptography/signers/AbstractSigner.sol | 23 - .../signers/MultiSignerERC7913.sol | 252 - .../signers/MultiSignerERC7913Weighted.sol | 208 - .../cryptography/signers/SignerECDSA.sol | 56 - .../cryptography/signers/SignerERC7702.sol | 25 - .../cryptography/signers/SignerERC7913.sol | 63 - .../utils/cryptography/signers/SignerP256.sol | 64 - .../utils/cryptography/signers/SignerRSA.sol | 65 - .../cryptography/signers/draft-ERC7739.sol | 99 - .../verifiers/ERC7913P256Verifier.sol | 29 - .../verifiers/ERC7913RSAVerifier.sol | 23 - .../contracts/utils/introspection/ERC165.sol | 25 - .../utils/introspection/ERC165Checker.sol | 124 - .../contracts/utils/introspection/IERC165.sol | 25 - .../contracts/utils/math/Math.sol | 749 - .../contracts/utils/math/SafeCast.sol | 1162 -- .../contracts/utils/math/SignedMath.sol | 68 - .../contracts/utils/structs/BitMaps.sol | 60 - .../contracts/utils/structs/Checkpoints.sol | 630 - .../utils/structs/CircularBuffer.sol | 140 - .../utils/structs/DoubleEndedQueue.sol | 156 - .../contracts/utils/structs/EnumerableMap.sol | 1319 -- .../contracts/utils/structs/EnumerableSet.sol | 792 - .../contracts/utils/structs/Heap.sol | 256 - .../contracts/utils/structs/MerkleTree.sol | 267 - .../contracts/utils/types/Time.sol | 133 - .../vendor/compound/ICompoundTimelock.sol | 86 - .../contracts/vendor/compound/LICENSE | 11 - .../lib/openzeppelin-contracts/docs/README.md | 16 - .../openzeppelin-contracts/docs/antora.yml | 7 - .../lib/openzeppelin-contracts/docs/config.js | 21 - .../ROOT/images/access-control-multiple.svg | 97 - .../ROOT/images/access-manager-functions.svg | 47 - .../modules/ROOT/images/access-manager.svg | 99 - .../modules/ROOT/images/erc4626-attack-3a.png | Bin 60433 -> 0 bytes .../modules/ROOT/images/erc4626-attack-3b.png | Bin 66184 -> 0 bytes .../modules/ROOT/images/erc4626-attack-6.png | Bin 56290 -> 0 bytes .../modules/ROOT/images/erc4626-attack.png | Bin 58886 -> 0 bytes .../modules/ROOT/images/erc4626-deposit.png | Bin 115497 -> 0 bytes .../docs/modules/ROOT/images/erc4626-mint.png | Bin 112787 -> 0 bytes .../ROOT/images/erc4626-rate-linear.png | Bin 50813 -> 0 bytes .../ROOT/images/erc4626-rate-loglog.png | Bin 72818 -> 0 bytes .../ROOT/images/erc4626-rate-loglogext.png | Bin 109923 -> 0 bytes .../docs/modules/ROOT/images/tally-exec.png | Bin 231859 -> 0 bytes .../docs/modules/ROOT/images/tally-vote.png | Bin 40507 -> 0 bytes .../docs/modules/ROOT/nav.adoc | 29 - .../modules/ROOT/pages/access-control.adoc | 288 - .../ROOT/pages/account-abstraction.adoc | 100 - .../docs/modules/ROOT/pages/accounts.adoc | 354 - .../ROOT/pages/backwards-compatibility.adoc | 50 - .../modules/ROOT/pages/eoa-delegation.adoc | 143 - .../docs/modules/ROOT/pages/erc1155.adoc | 118 - .../docs/modules/ROOT/pages/erc20-supply.adoc | 71 - .../docs/modules/ROOT/pages/erc20.adoc | 67 - .../docs/modules/ROOT/pages/erc4626.adoc | 214 - .../docs/modules/ROOT/pages/erc6909.adoc | 47 - .../docs/modules/ROOT/pages/erc721.adoc | 58 - .../ROOT/pages/extending-contracts.adoc | 51 - .../docs/modules/ROOT/pages/faq.adoc | 13 - .../docs/modules/ROOT/pages/governance.adoc | 239 - .../docs/modules/ROOT/pages/index.adoc | 70 - .../docs/modules/ROOT/pages/multisig.adoc | 306 - .../docs/modules/ROOT/pages/tokens.adoc | 31 - .../docs/modules/ROOT/pages/upgradeable.adoc | 77 - .../docs/modules/ROOT/pages/utilities.adoc | 559 - .../docs/modules/ROOT/pages/wizard.adoc | 15 - .../docs/templates/contract.hbs | 141 - .../docs/templates/helpers.js | 46 - .../docs/templates/page.hbs | 4 - .../docs/templates/properties.js | 88 - .../openzeppelin-contracts/eslint.config.mjs | 26 - .../lib/openzeppelin-contracts/foundry.toml | 15 - .../fv-requirements.txt | 4 - .../openzeppelin-contracts/hardhat.config.js | 124 - .../hardhat/async-test-sanity.js | 10 - .../hardhat/common-contracts.js | 69 - .../hardhat/env-artifacts.js | 29 - .../hardhat/ignore-unreachable-warnings.js | 45 - .../hardhat/remappings.js | 18 - .../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 | 356 - .../lib/erc4626-tests/LICENSE | 661 - .../lib/erc4626-tests/README.md | 116 - .../lib/forge-std/.gitattributes | 1 - .../lib/forge-std/.github/workflows/ci.yml | 128 - .../lib/forge-std/.github/workflows/sync.yml | 31 - .../lib/forge-std/.gitignore | 4 - .../lib/forge-std/CONTRIBUTING.md | 193 - .../lib/forge-std/LICENSE-APACHE | 203 - .../lib/forge-std/LICENSE-MIT | 25 - .../lib/forge-std/README.md | 266 - .../lib/forge-std/foundry.toml | 23 - .../lib/forge-std/package.json | 16 - .../lib/forge-std/scripts/vm.py | 646 - .../lib/forge-std/src/Base.sol | 35 - .../lib/forge-std/src/Script.sol | 27 - .../lib/forge-std/src/StdAssertions.sol | 669 - .../lib/forge-std/src/StdChains.sol | 287 - .../lib/forge-std/src/StdCheats.sol | 829 - .../lib/forge-std/src/StdError.sol | 15 - .../lib/forge-std/src/StdInvariant.sol | 122 - .../lib/forge-std/src/StdJson.sol | 283 - .../lib/forge-std/src/StdMath.sol | 43 - .../lib/forge-std/src/StdStorage.sol | 473 - .../lib/forge-std/src/StdStyle.sol | 333 - .../lib/forge-std/src/StdToml.sol | 283 - .../lib/forge-std/src/StdUtils.sol | 209 - .../lib/forge-std/src/Test.sol | 33 - .../lib/forge-std/src/Vm.sol | 2263 --- .../lib/forge-std/src/console.sol | 1560 -- .../lib/forge-std/src/console2.sol | 4 - .../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/src/safeconsole.sol | 13937 ---------------- .../lib/forge-std/test/StdAssertions.t.sol | 141 - .../lib/forge-std/test/StdChains.t.sol | 227 - .../lib/forge-std/test/StdCheats.t.sol | 618 - .../lib/forge-std/test/StdError.t.sol | 120 - .../lib/forge-std/test/StdJson.t.sol | 49 - .../lib/forge-std/test/StdMath.t.sol | 202 - .../lib/forge-std/test/StdStorage.t.sol | 488 - .../lib/forge-std/test/StdStyle.t.sol | 110 - .../lib/forge-std/test/StdToml.t.sol | 49 - .../lib/forge-std/test/StdUtils.t.sol | 342 - .../lib/forge-std/test/Vm.t.sol | 18 - .../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/forge-std/test/fixtures/test.json | 8 - .../lib/forge-std/test/fixtures/test.toml | 6 - .../lib/halmos-cheatcodes/LICENSE | 661 - .../lib/halmos-cheatcodes/README.md | 97 - .../lib/halmos-cheatcodes/src/SVM.sol | 49 - .../lib/halmos-cheatcodes/src/SymTest.sol | 11 - .../lib/openzeppelin-contracts/logo.svg | 15 - .../lib/openzeppelin-contracts/netlify.toml | 3 - .../openzeppelin-contracts/package-lock.json | 10552 ------------ .../lib/openzeppelin-contracts/package.json | 104 - .../lib/openzeppelin-contracts/remappings.txt | 1 - .../lib/openzeppelin-contracts/renovate.json | 4 - .../scripts/checks/compare-layout.js | 20 - .../scripts/checks/compareGasReports.js | 247 - .../scripts/checks/coverage.sh | 24 - .../scripts/checks/extract-layout.js | 38 - .../scripts/checks/generation.sh | 6 - .../scripts/checks/inheritance-ordering.js | 55 - .../scripts/checks/pragma-consistency.js | 49 - .../scripts/fetch-common-contracts.js | 50 - .../openzeppelin-contracts/scripts/gen-nav.js | 81 - .../scripts/generate/format-lines.js | 16 - .../scripts/generate/helpers/sanitize.js | 5 - .../scripts/generate/run.js | 61 - .../scripts/generate/templates/Arrays.js | 386 - .../scripts/generate/templates/Arrays.opts.js | 9 - .../scripts/generate/templates/Checkpoints.js | 242 - .../generate/templates/Checkpoints.opts.js | 17 - .../generate/templates/Checkpoints.t.js | 137 - .../generate/templates/Enumerable.opts.js | 53 - .../generate/templates/EnumerableMap.js | 463 - .../generate/templates/EnumerableSet.js | 469 - .../scripts/generate/templates/MerkleProof.js | 187 - .../generate/templates/MerkleProof.opts.js | 11 - .../scripts/generate/templates/Packing.js | 92 - .../generate/templates/Packing.opts.js | 3 - .../scripts/generate/templates/Packing.t.js | 48 - .../scripts/generate/templates/SafeCast.js | 136 - .../scripts/generate/templates/Slot.opts.js | 15 - .../generate/templates/SlotDerivation.js | 119 - .../generate/templates/SlotDerivation.t.js | 127 - .../scripts/generate/templates/StorageSlot.js | 77 - .../generate/templates/StorageSlotMock.js | 57 - .../generate/templates/TransientSlot.js | 80 - .../generate/templates/TransientSlotMock.js | 35 - .../scripts/generate/templates/conversion.js | 30 - .../scripts/git-user-config.sh | 6 - .../openzeppelin-contracts/scripts/helpers.js | 7 - .../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/set-max-old-space-size.sh | 10 - .../scripts/solhint-custom/index.js | 84 - .../scripts/solhint-custom/package.json | 8 - .../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 | 50 - .../scripts/upgradeable/upgradeable.patch | 398 - .../slither.config.json | 4 - .../openzeppelin-contracts/solhint.config.js | 29 - .../openzeppelin-contracts/test/TESTING.md | 3 - .../test/access/AccessControl.behavior.js | 874 - .../test/access/AccessControl.test.js | 19 - .../test/access/Ownable.test.js | 79 - .../test/access/Ownable2Step.test.js | 102 - .../AccessControlDefaultAdminRules.test.js | 32 - .../AccessControlEnumerable.test.js | 24 - .../test/access/manager/AccessManaged.test.js | 146 - .../access/manager/AccessManager.behavior.js | 257 - .../access/manager/AccessManager.predicate.js | 456 - .../test/access/manager/AccessManager.test.js | 2489 --- .../access/manager/AuthorityUtils.test.js | 112 - .../test/account/Account.behavior.js | 144 - .../test/account/Account.test.js | 48 - .../test/account/AccountECDSA.test.js | 52 - .../test/account/AccountERC7702.t.sol | 97 - .../test/account/AccountERC7702.test.js | 52 - .../test/account/AccountERC7913.test.js | 116 - .../test/account/AccountMultiSigner.test.js | 326 - .../AccountMultiSignerWeighted.test.js | 312 - .../test/account/AccountP256.test.js | 58 - .../test/account/AccountRSA.test.js | 58 - .../AccountERC7702WithModulesMock.test.js | 99 - .../extensions/AccountERC7579.behavior.js | 563 - .../account/extensions/AccountERC7579.test.js | 60 - .../extensions/AccountERC7579Hooked.test.js | 60 - .../account/extensions/ERC7821.behavior.js | 145 - .../test/account/utils/EIP7702Utils.test.js | 53 - .../account/utils/draft-ERC4337Utils.test.js | 289 - .../account/utils/draft-ERC7579Utils.t.sol | 418 - .../account/utils/draft-ERC7579Utils.test.js | 399 - .../test/bin/EntryPoint070.abi | 1 - .../test/bin/EntryPoint070.bytecode | Bin 16035 -> 0 bytes .../test/bin/EntryPoint080.abi | 1 - .../test/bin/EntryPoint080.bytecode | Bin 21738 -> 0 bytes .../test/bin/SenderCreator070.abi | 1 - .../test/bin/SenderCreator070.bytecode | Bin 451 -> 0 bytes .../test/bin/SenderCreator080.abi | 1 - .../test/bin/SenderCreator080.bytecode | Bin 1217 -> 0 bytes .../test/finance/VestingWallet.behavior.js | 87 - .../test/finance/VestingWallet.test.js | 65 - .../test/finance/VestingWalletCliff.test.js | 70 - .../test/governance/Governor.t.sol | 59 - .../test/governance/Governor.test.js | 980 -- .../governance/TimelockController.test.js | 1279 -- .../GovernorCountingFractional.test.js | 248 - .../GovernorCountingOverridable.test.js | 346 - .../extensions/GovernorERC721.test.js | 131 - .../extensions/GovernorNoncesKeyed.test.js | 244 - .../GovernorPreventLateQuorum.test.js | 185 - .../GovernorProposalGuardian.test.js | 132 - .../GovernorSequentialProposalId.test.js | 202 - .../extensions/GovernorStorage.test.js | 155 - .../extensions/GovernorSuperQuorum.test.js | 168 - ...GovernorSuperQuorumGreaterThanQuorum.t.sol | 79 - .../extensions/GovernorTimelockAccess.test.js | 864 - .../GovernorTimelockCompound.test.js | 448 - .../GovernorTimelockControl.test.js | 504 - .../GovernorVotesQuorumFraction.test.js | 165 - .../GovernorVotesSuperQuorumFraction.test.js | 160 - .../extensions/GovernorWithParams.test.js | 245 - .../test/governance/utils/ERC6372.behavior.js | 28 - .../test/governance/utils/Votes.behavior.js | 325 - .../test/governance/utils/Votes.test.js | 102 - .../governance/utils/VotesExtended.test.js | 152 - .../test/helpers/access-manager.js | 85 - .../test/helpers/account.js | 14 - .../test/helpers/chains.js | 109 - .../test/helpers/constants.js | 5 - .../test/helpers/deploy.js | 14 - .../test/helpers/eip712-types.js | 61 - .../test/helpers/eip712.js | 45 - .../test/helpers/enums.js | 14 - .../test/helpers/erc4337.js | 217 - .../test/helpers/erc7579.js | 58 - .../test/helpers/erc7739.js | 118 - .../test/helpers/governance.js | 217 - .../test/helpers/iterate.js | 41 - .../test/helpers/math.js | 33 - .../test/helpers/methods.js | 14 - .../test/helpers/precompiles.js | 12 - .../test/helpers/random.js | 24 - .../test/helpers/signers.js | 184 - .../test/helpers/storage.js | 48 - .../test/helpers/strings.js | 5 - .../test/helpers/time.js | 33 - .../test/helpers/txpool.js | 29 - .../test/metatx/ERC2771Context.test.js | 133 - .../test/metatx/ERC2771Forwarder.t.sol | 279 - .../test/metatx/ERC2771Forwarder.test.js | 384 - .../test/proxy/Clones.behaviour.js | 160 - .../test/proxy/Clones.t.sol | 91 - .../test/proxy/Clones.test.js | 177 - .../test/proxy/ERC1967/ERC1967Proxy.test.js | 23 - .../test/proxy/ERC1967/ERC1967Utils.test.js | 162 - .../test/proxy/Proxy.behaviour.js | 185 - .../test/proxy/beacon/BeaconProxy.test.js | 141 - .../proxy/beacon/UpgradeableBeacon.test.js | 55 - .../test/proxy/transparent/ProxyAdmin.test.js | 82 - .../TransparentUpgradeableProxy.behaviour.js | 357 - .../TransparentUpgradeableProxy.test.js | 28 - .../test/proxy/utils/Initializable.test.js | 216 - .../test/proxy/utils/UUPSUpgradeable.test.js | 120 - .../test/sanity.test.js | 27 - .../test/token/ERC1155/ERC1155.behavior.js | 763 - .../test/token/ERC1155/ERC1155.test.js | 213 - .../extensions/ERC1155Burnable.test.js | 66 - .../extensions/ERC1155Pausable.test.js | 105 - .../ERC1155/extensions/ERC1155Supply.test.js | 119 - .../extensions/ERC1155URIStorage.test.js | 70 - .../token/ERC1155/utils/ERC1155Holder.test.js | 56 - .../token/ERC1155/utils/ERC1155Utils.test.js | 299 - .../test/token/ERC20/ERC20.behavior.js | 269 - .../test/token/ERC20/ERC20.test.js | 199 - .../token/ERC20/extensions/ERC1363.test.js | 370 - .../ERC20/extensions/ERC20Burnable.test.js | 105 - .../ERC20/extensions/ERC20Capped.test.js | 55 - .../ERC20/extensions/ERC20FlashMint.test.js | 164 - .../ERC20/extensions/ERC20Pausable.test.js | 129 - .../ERC20/extensions/ERC20Permit.test.js | 109 - .../token/ERC20/extensions/ERC20Votes.test.js | 546 - .../ERC20/extensions/ERC20Wrapper.test.js | 203 - .../test/token/ERC20/extensions/ERC4626.t.sol | 41 - .../token/ERC20/extensions/ERC4626.test.js | 888 - .../extensions/draft-ERC20Bridgeable.test.js | 89 - .../draft-ERC20TemporaryApproval.test.js | 142 - .../test/token/ERC20/utils/SafeERC20.test.js | 463 - .../test/token/ERC6909/ERC6909.behavior.js | 216 - .../test/token/ERC6909/ERC6909.test.js | 104 - .../extensions/ERC6909ContentURI.test.js | 49 - .../extensions/ERC6909Metadata.test.js | 58 - .../extensions/ERC6909TokenSupply.test.js | 53 - .../test/token/ERC721/ERC721.behavior.js | 946 -- .../test/token/ERC721/ERC721.test.js | 23 - .../token/ERC721/ERC721Enumerable.test.js | 28 - .../ERC721/extensions/ERC721Burnable.test.js | 77 - .../ERC721/extensions/ERC721Consecutive.t.sol | 181 - .../extensions/ERC721Consecutive.test.js | 228 - .../ERC721/extensions/ERC721Pausable.test.js | 81 - .../ERC721/extensions/ERC721Royalty.test.js | 57 - .../extensions/ERC721URIStorage.test.js | 121 - .../ERC721/extensions/ERC721Votes.test.js | 194 - .../ERC721/extensions/ERC721Wrapper.test.js | 201 - .../token/ERC721/utils/ERC721Holder.test.js | 20 - .../token/ERC721/utils/ERC721Utils.test.js | 94 - .../test/token/common/ERC2981.behavior.js | 152 - .../test/utils/Address.test.js | 281 - .../test/utils/Arrays.t.sol | 31 - .../test/utils/Arrays.test.js | 227 - .../test/utils/Base64.t.sol | 34 - .../test/utils/Base64.test.js | 59 - .../test/utils/Blockhash.t.sol | 100 - .../test/utils/Blockhash.test.js | 76 - .../test/utils/Bytes.t.sol | 117 - .../test/utils/Bytes.test.js | 104 - .../test/utils/CAIP.test.js | 53 - .../test/utils/Calldata.test.js | 22 - .../test/utils/Context.behavior.js | 48 - .../test/utils/Context.test.js | 18 - .../test/utils/Create2.t.sol | 17 - .../test/utils/Create2.test.js | 190 - .../test/utils/Multicall.test.js | 72 - .../test/utils/Nonces.behavior.js | 189 - .../test/utils/Nonces.test.js | 16 - .../test/utils/NoncesKeyed.test.js | 17 - .../test/utils/Packing.t.sol | 993 -- .../test/utils/Packing.test.js | 70 - .../test/utils/Panic.test.js | 37 - .../test/utils/Pausable.test.js | 90 - .../test/utils/ReentrancyGuard.test.js | 50 - .../test/utils/ShortStrings.t.sol | 109 - .../test/utils/ShortStrings.test.js | 64 - .../test/utils/SlotDerivation.t.sol | 248 - .../test/utils/SlotDerivation.test.js | 58 - .../test/utils/StorageSlot.test.js | 73 - .../test/utils/Strings.t.sol | 50 - .../test/utils/Strings.test.js | 349 - .../test/utils/TransientSlot.test.js | 59 - .../test/utils/cryptography/ECDSA.test.js | 211 - .../test/utils/cryptography/EIP712.test.js | 105 - .../utils/cryptography/ERC1271.behavior.js | 111 - .../test/utils/cryptography/ERC7739.test.js | 42 - .../utils/cryptography/ERC7739Utils.test.js | 203 - .../utils/cryptography/MerkleProof.test.js | 213 - .../utils/cryptography/MessageHashUtils.t.sol | 33 - .../cryptography/MessageHashUtils.test.js | 97 - .../test/utils/cryptography/P256.t.sol | 65 - .../test/utils/cryptography/P256.test.js | 182 - .../test/utils/cryptography/RSA.helper.js | 17 - .../test/utils/cryptography/RSA.test.js | 102 - .../utils/cryptography/SigVer15_186-3.rsp | 3850 ----- .../cryptography/SignatureChecker.test.js | 416 - .../ecdsa_secp256r1_sha256_p1363_test.json | 3719 ----- .../test/utils/introspection/ERC165.test.js | 18 - .../utils/introspection/ERC165Checker.test.js | 245 - .../SupportsInterface.behavior.js | 166 - .../test/utils/math/Math.t.sol | 349 - .../test/utils/math/Math.test.js | 713 - .../test/utils/math/SafeCast.test.js | 159 - .../test/utils/math/SignedMath.t.sol | 80 - .../test/utils/math/SignedMath.test.js | 53 - .../test/utils/structs/BitMap.test.js | 149 - .../test/utils/structs/Checkpoints.t.sol | 332 - .../test/utils/structs/Checkpoints.test.js | 146 - .../test/utils/structs/CircularBuffer.test.js | 83 - .../utils/structs/DoubleEndedQueue.test.js | 102 - .../utils/structs/EnumerableMap.behavior.js | 214 - .../test/utils/structs/EnumerableMap.test.js | 83 - .../utils/structs/EnumerableSet.behavior.js | 175 - .../test/utils/structs/EnumerableSet.test.js | 66 - .../test/utils/structs/Heap.t.sol | 74 - .../test/utils/structs/Heap.test.js | 113 - .../test/utils/structs/MerkleTree.test.js | 180 - .../test/utils/types/Time.test.js | 135 - .../safe-singleton-deployer-sol/.gas-snapshot | 3 - .../.github/workflows/test.yml | 86 - .../safe-singleton-deployer-sol/.gitignore | 14 - .../safe-singleton-deployer-sol/.gitmodules | 3 - .../lib/safe-singleton-deployer-sol/README.md | 9 - .../safe-singleton-deployer-sol/foundry.toml | 6 - .../lib/forge-std/.gitattributes | 1 - .../lib/forge-std/.github/workflows/ci.yml | 134 - .../lib/forge-std/.github/workflows/sync.yml | 29 - .../lib/forge-std/.gitignore | 4 - .../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/package.json | 16 - .../lib/forge-std/scripts/vm.py | 635 - .../lib/forge-std/src/Base.sol | 35 - .../lib/forge-std/src/Script.sol | 27 - .../lib/forge-std/src/StdAssertions.sol | 669 - .../lib/forge-std/src/StdChains.sol | 250 - .../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 | 179 - .../lib/forge-std/src/StdMath.sol | 43 - .../lib/forge-std/src/StdStorage.sol | 473 - .../lib/forge-std/src/StdStyle.sol | 333 - .../lib/forge-std/src/StdToml.sol | 179 - .../lib/forge-std/src/StdUtils.sol | 226 - .../lib/forge-std/src/Test.sol | 33 - .../lib/forge-std/src/Vm.sol | 1638 -- .../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 - .../forge-std/src/interfaces/IMulticall3.sol | 73 - .../lib/forge-std/src/mocks/MockERC20.sol | 234 - .../lib/forge-std/src/mocks/MockERC721.sol | 235 - .../lib/forge-std/src/safeconsole.sol | 13248 --------------- .../lib/forge-std/test/StdAssertions.t.sol | 145 - .../lib/forge-std/test/StdChains.t.sol | 221 - .../lib/forge-std/test/StdCheats.t.sol | 618 - .../lib/forge-std/test/StdError.t.sol | 120 - .../lib/forge-std/test/StdJson.t.sol | 49 - .../lib/forge-std/test/StdMath.t.sol | 212 - .../lib/forge-std/test/StdStorage.t.sol | 463 - .../lib/forge-std/test/StdStyle.t.sol | 110 - .../lib/forge-std/test/StdToml.t.sol | 49 - .../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 - .../lib/forge-std/test/fixtures/test.json | 8 - .../lib/forge-std/test/fixtures/test.toml | 6 - .../lib/forge-std/test/mocks/MockERC20.t.sol | 441 - .../lib/forge-std/test/mocks/MockERC721.t.sol | 721 - .../scripts/ExampleDeploy.s.sol | 20 - .../src/SafeSingletonDeployer.sol | 92 - .../safe-singleton-deployer-sol/test/Mock.sol | 14 - .../test/MockReverting.sol | 10 - .../test/SafeSingletonDeployer.t.sol | 54 - .../script/CalculateStorageSlot.s.sol | 27 - .../account-modules/script/Deploy.s.sol | 85 - .../packages/account-modules/script/README.md | 42 - .../packages/account-modules/script/verify.sh | 41 - .../src/AutoCollectExecutor.sol | 558 - .../account-modules/src/AutoTopUpExecutor.sol | 551 - .../src/IAutoCollectExecutor.sol | 214 - .../src/IAutoTopUpExecutor.sol | 198 - .../AutoCollectExecutor.integration.t.sol | 675 - .../test/AutoCollectExecutor.t.sol | 1192 -- .../test/AutoTopUpExecutor.integration.t.sol | 441 - .../test/AutoTopUpExecutor.t.sol | 941 -- .../test/mocks/MaliciousCollectToken.sol | 32 - .../test/mocks/MaliciousToken.sol | 30 - .../account-modules/test/mocks/MockERC20.sol | 16 - .../account-modules/test/mocks/MockSafe.sol | 63 - .../test/mocks/MockTokenBadReturn.sol | 60 - .../test/mocks/MockTokenReturnsFalse.sol | 55 - .../account-modules/test/mocks/MockUSDT.sol | 54 - 1362 files changed, 239941 deletions(-) delete mode 100644 typescript/packages/account-modules/.github/workflows/test.yml delete mode 100644 typescript/packages/account-modules/.gitignore delete mode 100644 typescript/packages/account-modules/README.md delete mode 100644 typescript/packages/account-modules/docs/auto-collect/architecture.md delete mode 100644 typescript/packages/account-modules/docs/auto-top-up/architecture.md delete mode 100644 typescript/packages/account-modules/foundry.lock delete mode 100644 typescript/packages/account-modules/foundry.toml delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitattributes delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitignore delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/LICENSE delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/README.md delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeContract.sol delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/TestDateTime.sol delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/BokkyPooBahsDateTimeContract_flattened_v1.00.sol delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/deployment-v1.00-prerelease.md delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/docs/ConvertingBetweenJulianDatesAndGregorianCalendarDates.pdf delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/docs/timestampFromDateTime.png delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/docs/timestampToDateTime.png delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/flattened/TestDateTime_flattened.sol delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/images/clocks.png delete mode 100755 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/scripts/solidityFlattener.pl delete mode 100755 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/00_runGeth.sh delete mode 100755 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/01_test1.sh delete mode 100755 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/02_attachGeth.sh delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.js delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.sol delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/README.md delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.js delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.sol delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/deploymentData.js delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/functions.js delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/genesis.json delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/settings delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1output.txt delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1results.txt delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-30.360937280Z--a00af22d07c87d96eeeb0ed583f8f6ac7812827e delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-58.104082316Z--a11aae29840fbb5c86e6fd4cf809eba183aef433 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-21.169063367Z--a22ab8a9d641ce77e06d98b7d7065d324d3d6976 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-41.707647638Z--a33a6c312d9ad0e0f2e95541beed0cc081621fd0 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-39-04.584040707Z--a44a08d3f6933c69212114bb66e2df1813651844 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-01.013666678Z--a55a151eb00fded1634d27d1127b4be4627079ea delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-37.426191216Z--a66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-58.899396047Z--a77a2b9d4b1c010a22a7c565dc418cef683dbcec delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-09.150580614Z--a88a05d2b88283ce84c8325760b72a64591279a2 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-34.770098207Z--a99a0ae3354c06b1459fd441a32a3f71005d7da0 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-17.400859858Z--aaaa9de1e6c564446ebca0fd102d8bd92093c756 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-35.122799190Z--abba43e7594e3b76afb157989e93c6621497fd4b delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-51.178332229Z--acca534c9f62ab495bd986e002ddf0f054caae4f delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-14.034178720Z--adda9b762a00ff12711113bfdc36958b73d7f915 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-33.471449656Z--aeea63b5479b50f79583ec49dacdcf86ddeff392 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-51.697690594Z--affa4d3a80add8ce4018540e056dacb649589394 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-46-38.500831000Z--b00bfde102270687324f9205b693859df64f8923 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-13.633282000Z--b11be1d4ef8e94d01cb2695092a79d139a8dad98 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-34.792913000Z--b22be2d9eef0d7e260cf96a64feea0b95ed3e74f delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-50-14.030093000Z--b33b7ecf5e47be3981c74d989d3af8b665b4b649 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-51-02.743266000Z--b44b43d59b738b088b690ae276c1e979aba8268d delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-16.250696000Z--b55b57d113b45481e31aaf03d6f4e5ad4ef325f8 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-56.678333000Z--b66bcb4e473de80e2c8a47ced10c22c705a5e602 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-55-56.546405000Z--b77bbbaa7c1649547ae61de4b80b91568c28351a delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-58-22.605806000Z--b88b728490b417e29b0784db30535db343830dba delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-59-11.614985000Z--b99b3d1f72edb05a0321db58eddcf83fd73c4ade delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-06.765694000Z--baab56da883edbe5314b8005be410022c510ccae delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-29.951106000Z--bbbb9809de0456ce0e0cd660e6e4ceabef3f521c delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-29.293263000Z--bccb68dd0ac87ef290aef49870d155f076c87868 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-54.216243000Z--bddb726ee06906e104db210e6d0506f2b062e477 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-08-54.756436000Z--beeb24ff18203658d0a1d4682ee3f36ad663ec87 delete mode 100644 typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-09-53.679255000Z--bffbd8f029ef0bd81cf754b53e8b3a5684f8b3ff delete mode 100644 typescript/packages/account-modules/lib/forge-std/.gitattributes delete mode 100644 typescript/packages/account-modules/lib/forge-std/.github/CODEOWNERS delete mode 100644 typescript/packages/account-modules/lib/forge-std/.github/workflows/ci.yml delete mode 100644 typescript/packages/account-modules/lib/forge-std/.github/workflows/sync.yml delete mode 100644 typescript/packages/account-modules/lib/forge-std/.gitignore delete mode 100644 typescript/packages/account-modules/lib/forge-std/CONTRIBUTING.md delete mode 100644 typescript/packages/account-modules/lib/forge-std/LICENSE-APACHE delete mode 100644 typescript/packages/account-modules/lib/forge-std/LICENSE-MIT delete mode 100644 typescript/packages/account-modules/lib/forge-std/README.md delete mode 100644 typescript/packages/account-modules/lib/forge-std/foundry.toml delete mode 100644 typescript/packages/account-modules/lib/forge-std/package.json delete mode 100755 typescript/packages/account-modules/lib/forge-std/scripts/vm.py delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/Base.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/Script.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdAssertions.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdChains.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdCheats.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdConstants.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdError.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdInvariant.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdJson.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdMath.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdStorage.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdStyle.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdToml.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/StdUtils.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/Test.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/Vm.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/console.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/console2.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC1155.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC165.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC20.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC4626.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC6909.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC721.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7540.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7575.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/interfaces/IMulticall3.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/src/safeconsole.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/CommonBase.t.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdAssertions.t.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdChains.t.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdCheats.t.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdConstants.t.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdError.t.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdJson.t.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdMath.t.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdStorage.t.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdStyle.t.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdToml.t.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/StdUtils.t.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/Vm.t.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationScript.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationScriptBase.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationTest.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationTestBase.sol delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/fixtures/broadcast.log.json delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/fixtures/test.json delete mode 100644 typescript/packages/account-modules/lib/forge-std/test/fixtures/test.toml delete mode 100644 typescript/packages/account-modules/lib/modulekit/.changeset/README.md delete mode 100644 typescript/packages/account-modules/lib/modulekit/.changeset/config.json delete mode 100644 typescript/packages/account-modules/lib/modulekit/.env-example delete mode 100644 typescript/packages/account-modules/lib/modulekit/.github/workflows/ci.yaml delete mode 100644 typescript/packages/account-modules/lib/modulekit/.github/workflows/dependency.yml delete mode 100644 typescript/packages/account-modules/lib/modulekit/.gitignore delete mode 100644 typescript/packages/account-modules/lib/modulekit/.npmrc delete mode 100644 typescript/packages/account-modules/lib/modulekit/.solhint.json delete mode 100644 typescript/packages/account-modules/lib/modulekit/.solhintignore delete mode 100644 typescript/packages/account-modules/lib/modulekit/CHANGELOG.md delete mode 100644 typescript/packages/account-modules/lib/modulekit/README.md delete mode 100644 typescript/packages/account-modules/lib/modulekit/docs/Accounts.md delete mode 100644 typescript/packages/account-modules/lib/modulekit/foundry.toml delete mode 100644 typescript/packages/account-modules/lib/modulekit/gas_calculations/.gitkeep delete mode 100644 typescript/packages/account-modules/lib/modulekit/octanerc.json delete mode 100644 typescript/packages/account-modules/lib/modulekit/package.json delete mode 100644 typescript/packages/account-modules/lib/modulekit/pnpm-lock.yaml delete mode 100644 typescript/packages/account-modules/lib/modulekit/remappings.txt delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/Accounts.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/Helpers.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/Integrations.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/Interfaces.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/Mocks.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/ModuleKit.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/Modules.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC4337Account.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Account.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Module.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/common/lib/ModeLib.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/ERC7579Factory.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/helpers/ExecutionHelper.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IERC7579Bootstrap.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IMSA.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/lib/ExecutionLib.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/factory/interface/IAccountFactory.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/factory/template/FactoryTemplate.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/KernelFactory.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccount.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccountExecute.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Account.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Module.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernel.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernelFactory.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IValidationManager.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ExecLib.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ValidationTypeLib.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/mock/MockFallback.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Constants.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Structs.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Types.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/NexusFactory.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexus.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusAccountFactory.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusBootstrap.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/SafeFactory.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7484.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7579Account.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579Launchpad.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeOp.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeProxyFactory.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/accounts/safe/types/DataTypes.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/BytecodeDeployer.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/ERC7579Precompiles.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/KernelPrecompiles.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/NexusPrecompiles.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/Safe7579Precompiles.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/SmartSessionsPrecompiles.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/EntryPoint.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/MockFactory.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/Registry.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/registry/RegistryDeployer.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IERC7484.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalResolver.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalSchemaValidator.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IRegistry.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/deployment/registry/types/DataTypes.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/external/ERC4337.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/ERC20.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/ERC4626.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/ERC721.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/ERC7579Exec.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IBotRegistry.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDFSRegistry.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDSProxy.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC20.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC4626.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721Enumerable.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IFLParamGetter.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IGasToken.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ILendingPool.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IMCDPriceVerifier.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyERC20.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyRegistry.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISmartSession.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISubscriptions.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ITrigger.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IWETH.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/ICBETH.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IRETH.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IWstETH.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IAToken.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendToAaveMigrator.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPool.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPoolAddressesProvider.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IStkAave.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveIncentivesController.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveProtocolDataProviderV2.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolAddressesProviderV2.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolV2.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IPriceOracleGetterAave.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IStakedToken.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/DataTypes.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveProtocolDataProvider.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveV3Oracle.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IL2PoolV3.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolAddressesProvider.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolV3.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleGetter.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleSentinel.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsController.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsDistributor.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoanRecipient.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoans.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IMerkleRedeem.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IPool.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IVault.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/bprotocol/IBAMM.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IAggregatorV3.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IFeedRegistry.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IPhaseAggregator.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICToken.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICompoundOracle.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/IComptroller.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/IComet.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometExt.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometRewards.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBaseRewardPool.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBooster.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IConvexToken.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IRewardPool.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IAddressProvider.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurve3PoolZap.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurveFactory.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IDepositZap.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IFeeDistributor.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ILiquidityGauge.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IMinter.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IRegistry.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ISwaps.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IVotingEscrow.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/stethPool/ICurveStethPool.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curveusd/ICurveUsd.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/dydx/ISoloMargin.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IDToken.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IEulerMarkets.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeV3.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeWrapper.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IKyberNetworkProxy.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOasis.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOffchainWrapper.sol.bak delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IPair.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IQuoter.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/ISwapRouter.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IUniswapRouter.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashBorrower.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashLender.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IFlashLoanBase.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniPool.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniRouter02.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaAccountV2.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaIndex.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaMakerDAOMerkleDistributor.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IAggregationExecutor.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IExecutorHelper.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IMetaAggregationRouterV2.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/lido/IWStEth.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFT.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFTArtwork.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBorrowerOperations.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IChickenBondManager.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ICollSurplusPool.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IHintHelpers.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ILQTYStaking.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IPriceFeed.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ISortedTroves.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IStabilityPool.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ITroveManager.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICat.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICdpRegistry.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropJoin.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropper.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDSPause.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDaiJoin.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDssSpell.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGem.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGetCdps.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJoin.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJug.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IManager.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IOsm.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPipInterface.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPot.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ISpotter.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IVat.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorpho.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV2Lens.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV3.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IRewardsDistributor.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypes.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypesAaveV3.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/IBoostedVaultWithLockup.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ISavingsContractV2.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ImAsset.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IQiDaoRegistry.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IStablecoin.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundController.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundManager.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundProxy.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFuseAsset.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IBasicTokenAdapters.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ICoinJoin.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IFSMWrapper.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IGetSafes.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IMedianOracle.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IOracleRelayer.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEEngine.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEManager.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFESaviour.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ITaxCollector.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/spark/IsDAI.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/strategy/ISubStorage.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Factory.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Pair.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IQuoter.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/ISwapRouter.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Factory.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3FlashCallback.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3NonfungiblePositionManager.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Pool.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3SwapCallback.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYVault.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYearnRegistry.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/registry/ExampleFactory.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/registry/FactoryBase.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/MockUniswap.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/helpers/MainnetAddresses.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/v3/Uniswap.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC20.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC721.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC1271Policy.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7484RegistryAdapter.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ActionPolicy.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ExecutorBase.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579FallbackBase.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookBase.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestruct.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestructSingleHook.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HybridValidatorBase.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ModuleBase.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579PolicyBase.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579StatelessValidatorBase.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579UserOpPolicy.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorBase.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorMaster.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/SchedulingBase.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/Flashloan.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC1271.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC712.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC7484.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IPolicy.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IStatelessValidator.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockExecutor.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockFallback.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHook.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHookMultiPlexer.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHybridValidator.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockPolicy.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockRegistry.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockStatelessValidator.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockTarget.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockValidator.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579Constants.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579ValidatorLib.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/TrustedForwarder.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/Auxiliary.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/ModuleKitHelpers.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/RhinestoneModuleKit.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/helpers/ERC7579Helpers.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/helpers/HelperBase.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/helpers/KernelHelpers.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/helpers/NexusHelpers.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/helpers/SafeHelpers.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/helpers/SmartSessionHelpers.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/helpers/interfaces/IAccountModulesPaginated.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/ECDSA.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/ERC4337Helpers.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/Log.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/Storage.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/Vm.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasCalculations.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasParser.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/UserOpGasLog.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/test/BaseTest.t.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/test/Diff.t.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/test/GasCalculationsTest.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/test/RegistryDeployer.t.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/test/integrations/ExampleFactory.t.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/test/integrations/SmartSession.t.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/test/integrations/SwapTest.t.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1Validator.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1ValidatorUncompliantUninstall.sol delete mode 100644 typescript/packages/account-modules/lib/modulekit/test/mocks/MockValidatorFalse.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.changeset/config.json delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.codecov.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.editorconfig delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/bug_report.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/feature_request.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/setup/action.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/storage-layout/action.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/actionlint.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/changeset.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/checks.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/docs.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/formal-verification.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/release-cycle.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/upgradeable.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.gitignore delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.gitmodules delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/.husky/pre-commit delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.mocharc.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.prettierrc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/.solcover.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/CHANGELOG.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/CODE_OF_CONDUCT.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/CONTRIBUTING.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/FUNDING.json delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/GUIDELINES.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/LICENSE delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/README.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/RELEASING.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/SECURITY.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2017-03.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2018-10.pdf delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2022-10-Checkpoints.pdf delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2022-10-ERC4626.pdf delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2023-05-v4.9.pdf delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2023-10-v5.0.pdf delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2024-10-v5.1.pdf delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2024-12-v5.2.pdf delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2025-04-v5.3.pdf delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/audits/README.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/.gitignore delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/Makefile delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/README.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/diff/access_manager_AccessManager.sol.patch delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessControlHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagedHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagerHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/DoubleEndedQueueHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20FlashMintHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20PermitHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20WrapperHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC3156FlashBorrowerHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC721Harness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC721ReceiverHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/EnumerableMapHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/EnumerableSetHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/InitializableHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/NoncesHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/Ownable2StepHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/OwnableHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/PausableHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/TimelockControllerHarness.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2021-10.pdf delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2022-03.pdf delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2022-05.pdf delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/run.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs.json delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessControl.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessControlDefaultAdminRules.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManaged.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManager.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/DoubleEndedQueue.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20FlashMint.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20Wrapper.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC721.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/EnumerableMap.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/EnumerableSet.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Initializable.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Nonces.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Ownable.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Ownable2Step.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Pausable.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/TimelockController.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/helpers/helpers.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessControl.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessControlDefaultAdminRules.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManaged.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManager.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC20.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC2612.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashBorrower.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashLender.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC5313.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC721.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC721Receiver.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IOwnable.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IOwnable2Step.spec delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/AccessControl.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/README.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlEnumerable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlDefaultAdminRules.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlEnumerable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManaged.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManager.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAuthority.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/Account.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/README.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579Hooked.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-ERC7821.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/EIP7702Utils.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC4337Utils.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC7579Utils.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/README.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWalletCliff.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/Governor.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/README.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingFractional.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingOverridable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorNoncesKeyed.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorProposalGuardian.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSequentialProposalId.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorStorage.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSuperQuorum.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockAccess.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/VotesExtended.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC7913.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/README.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC4337.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6909.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7579.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7674.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7802.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7821.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Forwarder.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/README.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagedTarget.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagerMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AuthorityMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Base64Dirty.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/BatchCaller.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ConstructorMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165InterfacesSupported.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleProofCustomHashMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleTreeMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MulticallHelper.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyTransientMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Stateless.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TimelockReentrant.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TransientSlotMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/UpgradeableBeaconMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesExtendedMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/AccountMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/modules/ERC7579Mock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/utils/ERC7579UtilsMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC20WithAutoMinerReward.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC4626Fees.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/MyNFT.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintBase.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintMissing.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintOnlyRole.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlModified.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessManagedERC20MintBase.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/MyContractOwnable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyAccountERC7702.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyFactoryAccount.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyGovernor.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyToken.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenTimestampBased.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenWrapped.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/GameItems.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/MyERC115HolderContract.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC20/GLDToken.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC6909/ERC6909GameItems.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC721/GameItem.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Base64NFT.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Multicall.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCountingOverridableMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorFractionalMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorNoncesKeyedMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorProposalGuardianMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSequentialProposalIdMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorStorageMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSuperQuorumMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockAccessMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVotesSuperQuorumFractionMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ForceApproveMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363NoReturnMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReceiverMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReturnFalseMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363SpenderMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ApprovalMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20BridgeableMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ExcessDecimalsMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ForceApproveMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20GetterHelper.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Reentrant.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesAdditionalCheckpointsMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesTimestampMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626LimitsMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626Mock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4646FeesMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/utils/cryptography/ERC7739Mock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/package.json delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Clones.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/README.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Utils.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC1363.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20Bridgeable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20TemporaryApproval.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/ERC1363Utils.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/README.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/draft-ERC6909.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909ContentURI.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909Metadata.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909TokenSupply.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Utils.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/README.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Address.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Arrays.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Base64.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Blockhash.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Bytes.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP10.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP2.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Calldata.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Comparators.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Context.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Create2.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Errors.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Multicall.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Nonces.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/NoncesKeyed.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Packing.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Panic.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Pausable.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/README.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuardTransient.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/SlotDerivation.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Strings.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/TransientSlot.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/Hashes.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/P256.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/README.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/RSA.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/draft-ERC7739Utils.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/AbstractSigner.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerECDSA.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7702.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7913.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerP256.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerRSA.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/draft-ERC7739.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913P256Verifier.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913RSAVerifier.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/Math.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/CircularBuffer.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Heap.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/MerkleTree.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/types/Time.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/README.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/antora.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/config.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-control-multiple.svg delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager-functions.svg delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager.svg delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack-3a.png delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack-3b.png delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack-6.png delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack.png delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-deposit.png delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-mint.png delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-rate-linear.png delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-rate-loglog.png delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-rate-loglogext.png delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/tally-exec.png delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/tally-vote.png delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/nav.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/access-control.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/account-abstraction.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/accounts.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/backwards-compatibility.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/eoa-delegation.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc1155.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20-supply.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc4626.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc6909.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc721.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/extending-contracts.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/faq.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/governance.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/index.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/multisig.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/tokens.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/upgradeable.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/utilities.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/wizard.adoc delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/contract.hbs delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/helpers.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/page.hbs delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/properties.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/eslint.config.mjs delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/foundry.toml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/fv-requirements.txt delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat.config.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/async-test-sanity.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/common-contracts.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/env-artifacts.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/remappings.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/task-test-get-files.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/README.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitattributes delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/sync.yml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitignore delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/CONTRIBUTING.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/README.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/foundry.toml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/package.json delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/scripts/vm.py delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Base.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Script.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdInvariant.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStyle.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdToml.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Test.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IMulticall3.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/safeconsole.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdJson.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStyle.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdToml.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/Vm.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/broadcast.log.json delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.json delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.toml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/LICENSE delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/README.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SVM.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SymTest.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/logo.svg delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/netlify.toml delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/package-lock.json delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/package.json delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/remappings.txt delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/renovate.json delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compare-layout.js delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/coverage.sh delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/extract-layout.js delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/generation.sh delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/pragma-consistency.js delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/fetch-common-contracts.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/gen-nav.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/format-lines.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/helpers/sanitize.js delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/run.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.opts.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.opts.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.t.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Enumerable.opts.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.opts.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.opts.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.t.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Slot.opts.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.t.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlotMock.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlot.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlotMock.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/conversion.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/git-user-config.sh delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/helpers.js delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/prepack.sh delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/prepare-docs.sh delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/format-changelog.js delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/synchronize-versions.js delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/update-comment.js delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/version.sh delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/github-release.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/integrity-check.sh delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/pack.sh delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/publish.sh delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/rerun.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/start.sh delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/state.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/set-max-old-space-size.sh delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/index.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/package.json delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/update-docs-branch.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/README.md delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/patch-apply.sh delete mode 100755 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/patch-save.sh delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile-onto.sh delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile.sh delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/upgradeable.patch delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/slither.config.json delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/solhint.config.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/TESTING.md delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlDefaultAdminRules.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlEnumerable.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManaged.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.predicate.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AuthorityUtils.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountECDSA.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7913.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSigner.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSignerWeighted.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountP256.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountRSA.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/examples/AccountERC7702WithModulesMock.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579Hooked.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/ERC7821.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/EIP7702Utils.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC4337Utils.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint070.abi delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint070.bytecode delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint080.abi delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint080.bytecode delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator070.abi delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator070.bytecode delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator080.abi delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator080.bytecode delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWalletCliff.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/TimelockController.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingFractional.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingOverridable.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorNoncesKeyed.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorProposalGuardian.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSequentialProposalId.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorStorage.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorum.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorumGreaterThanQuorum.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockAccess.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesSuperQuorumFraction.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/ERC6372.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/VotesExtended.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/access-manager.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/account.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/chains.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/constants.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/deploy.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712-types.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/enums.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc4337.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7579.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7739.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/governance.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/iterate.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/math.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/methods.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/precompiles.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/random.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/signers.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/storage.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/strings.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/time.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/txpool.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Utils.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/sanity.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Utils.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC1363.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Permit.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20Bridgeable.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20TemporaryApproval.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909ContentURI.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909Metadata.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909TokenSupply.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Utils.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Address.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/CAIP.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Calldata.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Multicall.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/NoncesKeyed.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Panic.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Pausable.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ReentrancyGuard.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/TransientSlot.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC1271.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739Utils.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.helper.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SigVer15_186-3.rsp delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ecdsa_secp256r1_sha256_p1363_test.json delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/CircularBuffer.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.t.sol delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/MerkleTree.test.js delete mode 100644 typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/types/Time.test.js delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gas-snapshot delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.github/workflows/test.yml delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitignore delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitmodules delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/README.md delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/foundry.toml delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitattributes delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.github/workflows/ci.yml delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.github/workflows/sync.yml delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitignore delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/LICENSE-APACHE delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/LICENSE-MIT delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/README.md delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/foundry.toml delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/package.json delete mode 100755 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/scripts/vm.py delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Base.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Script.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdAssertions.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdChains.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdCheats.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdError.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdInvariant.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdJson.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdMath.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStorage.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStyle.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdToml.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdUtils.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Test.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Vm.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/console.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/console2.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC1155.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC165.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC20.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC4626.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC721.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IMulticall3.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC20.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC721.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/safeconsole.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdAssertions.t.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdChains.t.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdCheats.t.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdError.t.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdJson.t.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdMath.t.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStorage.t.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStyle.t.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdToml.t.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdUtils.t.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/Vm.t.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationScript.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationScriptBase.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationTest.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationTestBase.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/broadcast.log.json delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.json delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.toml delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC20.t.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC721.t.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/scripts/ExampleDeploy.s.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/src/SafeSingletonDeployer.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/Mock.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/MockReverting.sol delete mode 100644 typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/SafeSingletonDeployer.t.sol delete mode 100644 typescript/packages/account-modules/script/CalculateStorageSlot.s.sol delete mode 100644 typescript/packages/account-modules/script/Deploy.s.sol delete mode 100644 typescript/packages/account-modules/script/README.md delete mode 100755 typescript/packages/account-modules/script/verify.sh delete mode 100644 typescript/packages/account-modules/src/AutoCollectExecutor.sol delete mode 100644 typescript/packages/account-modules/src/AutoTopUpExecutor.sol delete mode 100644 typescript/packages/account-modules/src/IAutoCollectExecutor.sol delete mode 100644 typescript/packages/account-modules/src/IAutoTopUpExecutor.sol delete mode 100644 typescript/packages/account-modules/test/AutoCollectExecutor.integration.t.sol delete mode 100644 typescript/packages/account-modules/test/AutoCollectExecutor.t.sol delete mode 100644 typescript/packages/account-modules/test/AutoTopUpExecutor.integration.t.sol delete mode 100644 typescript/packages/account-modules/test/AutoTopUpExecutor.t.sol delete mode 100644 typescript/packages/account-modules/test/mocks/MaliciousCollectToken.sol delete mode 100644 typescript/packages/account-modules/test/mocks/MaliciousToken.sol delete mode 100644 typescript/packages/account-modules/test/mocks/MockERC20.sol delete mode 100644 typescript/packages/account-modules/test/mocks/MockSafe.sol delete mode 100644 typescript/packages/account-modules/test/mocks/MockTokenBadReturn.sol delete mode 100644 typescript/packages/account-modules/test/mocks/MockTokenReturnsFalse.sol delete mode 100644 typescript/packages/account-modules/test/mocks/MockUSDT.sol diff --git a/typescript/packages/account-modules/.github/workflows/test.yml b/typescript/packages/account-modules/.github/workflows/test.yml deleted file mode 100644 index 4481ec6..0000000 --- a/typescript/packages/account-modules/.github/workflows/test.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: CI - -on: - push: - pull_request: - workflow_dispatch: - -env: - FOUNDRY_PROFILE: ci - -jobs: - check: - name: Foundry project - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - - - name: Show Forge version - run: | - forge --version - - - name: Run Forge fmt - run: | - forge fmt --check - id: fmt - - - name: Run Forge build - run: | - forge build --sizes - id: build - - - name: Run Forge tests - run: | - forge test -vvv - id: test diff --git a/typescript/packages/account-modules/.gitignore b/typescript/packages/account-modules/.gitignore deleted file mode 100644 index 3269660..0000000 --- a/typescript/packages/account-modules/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# Compiler files -cache/ -out/ - -# Ignores development broadcast logs -!/broadcast -/broadcast/*/31337/ -/broadcast/**/dry-run/ - -# Dotenv file -.env diff --git a/typescript/packages/account-modules/README.md b/typescript/packages/account-modules/README.md deleted file mode 100644 index 1e67976..0000000 --- a/typescript/packages/account-modules/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# Account Modules - -ERC-7579 compliant executor modules for smart account automation in the x402 payments system. - -## Modules - -### AutoTopUpModule -- Automatically tops up agent accounts when balance falls below threshold -- Configurable per-agent limits (daily, monthly) -- Permissionless triggering with proper checks -- Used by: Main accounts to fund agent accounts - -### AutoCollectModule -- Automatically collects payments from service accounts -- Configurable collection thresholds (amount and time) -- Batch collection optimization -- Used by: Service accounts to collect to main accounts - -## Architecture - -All modules implement the ERC-7579 executor module interface: -- `onInstall(bytes calldata data)` - Module installation -- `onUninstall(bytes calldata data)` - Module removal -- `isModuleType(uint256 typeID)` - Returns true for executor type (0x01) -- `isInitialized(address account)` - Check if module is initialized for account - -## Deployment - -The modules are deployed as immutable singletons using Safe's Singleton Factory, ensuring the same addresses across all chains: - -- **AutoTopUpExecutor**: `0x16f13052FbFFfcE34E5752b7F4CFF881a030F40B` -- **AutoCollectExecutor**: `0x29864bd91370886c38dE9Fe95F5589E7EbE15130` - -These addresses are deterministic and will remain consistent on all supported chains (Base, Base Sepolia, etc.). - -## Development - -### Prerequisites - -- [Foundry](https://book.getfoundry.sh/getting-started/installation) -- [pnpm](https://pnpm.io/installation) (for ModuleKit dependencies) - -### Setup - -```bash -# Install Forge dependencies -forge install - -# Install ModuleKit node dependencies (required for compilation) -cd lib/modulekit && npm install && cd ../.. - -# Build contracts -forge build - -# Run tests -forge test - -# Deploy -forge script script/Deploy.s.sol --rpc-url $RPC_URL --broadcast -``` - -**Important**: ModuleKit requires its node modules to be installed for proper compilation. This step (`pnpm install` in the modulekit directory) must be performed after cloning the repository and before building. - -## Security - -- Non-custodial design - modules only execute based on user-defined rules -- Access control via ERC-7579 standards -- Immutable singleton contracts - no upgradeability, no owner -- Comprehensive event logging \ No newline at end of file diff --git a/typescript/packages/account-modules/docs/auto-collect/architecture.md b/typescript/packages/account-modules/docs/auto-collect/architecture.md deleted file mode 100644 index 5da5185..0000000 --- a/typescript/packages/account-modules/docs/auto-collect/architecture.md +++ /dev/null @@ -1,252 +0,0 @@ -# AutoCollectExecutor Architecture - -## Overview - -AutoCollectExecutor is an ERC-7579 executor module that automatically collects funds from service accounts to a main seller account. It mirrors the AutoTopUpExecutor pattern but reverses the transfer direction - collecting funds FROM the account where the module is installed TO a configured target account. - -## Key Design Principles - -1. **Installation Location**: Module is installed ON each service account (not on main account) -2. **Transfer Direction**: FROM service account (where module is installed) TO main account -3. **Permissionless Execution**: Anyone can trigger collections (gas incentives for automation) -4. **Calendar-Based Limits**: Collections limited to once per calendar day (UTC) -5. **Per-Asset Configuration**: Each token has its own collection configuration - -## Architecture Components - -### Storage Structure - -```solidity -// Configuration per asset -struct CollectConfig { - address target; // Main account to collect funds to - address asset; // ERC-20 token address - uint256 threshold; // Minimum balance to trigger collection (0 = no threshold) - uint256 minimumRemaining; // Minimum amount to leave in account (0 = collect all) - bool enabled; // Whether collection is enabled -} - -// State tracking per configuration -struct CollectState { - uint256 lastCollectDate; // Last collection date (YYYYMMDD format) -} - -// Storage mappings -mapping(uint256 => CollectConfig) configs; // configId => config -mapping(uint256 => CollectState) states; // configId => state -mapping(address => EnumerableSet.Bytes32Set) accountConfigs; // service account => configIds (using EnumerableSet) - -// Config ID generation (deterministic) -configId = keccak256(abi.encode("CollectConfig", serviceAccount, asset)) -``` - -### Core Functions - -#### Module Lifecycle -- `onInstall(bytes calldata data)` - Install with optional initial configurations -- `onUninstall(bytes calldata)` - Clean up all configurations and state -- `isModuleType(uint256 typeID)` - Returns MODULE_TYPE_EXECUTOR constant -- `isInitialized(address account)` - Check if module is initialized for account - -#### Configuration Management -- `configureCollection(address asset, CollectConfig config)` - Create/update config for msg.sender -- `enableCollection(bytes32 configId)` - Enable collection for a config -- `disableCollection(bytes32 configId)` - Disable collection for a config - -#### Collection Execution -- `triggerCollection(address account, address asset)` - Trigger collection for specific asset on account -- `triggerAllCollections(address account)` - Trigger all enabled collections for specific account -- `canExecuteCollection(address account, address asset)` - Check if collection can execute - -#### View Functions -- `getCollectionConfig(address account, address asset)` - Get specific config -- `getCollectionConfigs(address account)` - Get all configs for an account -- `getCollectionState(address account, address asset)` - Get collection state - -## Execution Flow - -### Collection Trigger Flow -``` -1. External caller → triggerCollection(account, asset) -2. Module validates: - - Configuration exists and is enabled for account - - Calendar day has changed since last collection - - Balance meets threshold (if threshold > 0) - - Balance >= minimumRemaining (can leave the required amount) - - collectAmount = balance - minimumRemaining > 0 -3. Module executes: - - Get current balance of asset in account - - Calculate collect amount: balance - minimumRemaining - - Transfer collect amount to configured target - - Leave minimumRemaining in account - - If transfer fails, emit CollectionSkipped event and continue - - Update lastCollectDate only on successful transfer -4. Emit CollectionExecuted or CollectionSkipped event -``` - -### Calendar Day Tracking -- Uses BokkyPooBah's DateTime Library (same as AutoTopUpExecutor) -- Dates encoded as YYYYMMDD (e.g., 20240829) -- All timestamps are UTC-based -- Prevents multiple collections per calendar day - -## Security Considerations - -1. **Access Control** - - Only service account (msg.sender) can configure its own collections - - Anyone can trigger collections (permissionless) - - Module can only transfer FROM the account it's installed on - -2. **Reentrancy Protection** - - CEI (Checks-Effects-Interactions) pattern - - State updates before external calls - - ReentrancyGuard on execution functions - -3. **Token Safety** - - Execute transfers via Safe's _execute() (like AutoTopUpExecutor) - - Handle non-standard token returns by checking returndata length - - Decode and validate return value if present - - Zero-value transfer protection - -## Events - -```solidity -event CollectionConfigured( - address indexed account, - address indexed asset, - address indexed target, - uint256 threshold -); - -event CollectionExecuted( - address indexed account, - address indexed asset, - address indexed target, - uint256 amount -); - -event CollectionSkipped( - address indexed account, - address indexed asset, - bytes32 indexed configId, - uint256 balance, - uint256 threshold, - uint256 minimumRemaining, - uint256 collectAmount -); - -event CollectionEnabled(address indexed account, address indexed asset); -event CollectionDisabled(address indexed account, address indexed asset); -``` - -## Edge Cases & Validation - -1. **Collection Validation** - - If balance < threshold: Skip collection, emit CollectionSkipped event - - If balance = 0: Skip collection, emit CollectionSkipped event - - If balance < minimumRemaining: Skip collection, emit CollectionSkipped event - - If balance - minimumRemaining = 0: Skip collection, emit CollectionSkipped event - - Threshold = 0 means trigger collection on any balance - - minimumRemaining = 0 means collect full balance (default behavior) - -2. **Valid Configurations** - - minimumRemaining > threshold: Valid (effective threshold is minimumRemaining) - - minimumRemaining = threshold: Valid (collect when balance exactly at or above threshold) - - minimumRemaining = 0, threshold = 0: Valid (collect any non-zero balance) - - minimumRemaining > 0, threshold = 0: Valid (collect when balance > minimumRemaining) - -3. **Invalid Configuration** - - Target cannot be zero address - - Asset must be valid ERC-20 contract - - Threshold and minimumRemaining can both be 0 - -3. **Date Boundaries** - - Month transitions handled correctly - - Year transitions handled correctly - - Leap years considered - -4. **Token Edge Cases** - - Non-standard return values (USDT) - - Tokens with transfer fees - - Balance changes between check and transfer (handled gracefully by skipping collection) - -## Gas Optimization - -1. **Storage Patterns** - - Separate config and state structs for efficient updates - - Pack struct fields for optimal storage slots - - Use mappings instead of arrays where possible - -2. **Execution Optimization** - - Calculate date once per execution - - Batch operations where possible - - Skip zero-balance collections early - -## Differences from AutoTopUpExecutor - -| Aspect | AutoTopUpExecutor | AutoCollectExecutor | -|--------|-------------------|---------------------| -| Installation | On main account | On service accounts | -| Transfer Direction | Main → Agent accounts | Service account → Main | -| Config Storage | Per (agent, asset) | Per (asset) on each account | -| Limits | Daily/Monthly amounts | Once per calendar day | -| Threshold | Top-up when below | Collect when above | -| Target | Multiple agents | Single main account | - -## Integration with Safe Accounts - -Service accounts will have AutoCollectExecutor installed as an ERC-7579 module: -```solidity -Safe Service Account -├── Owner: User's Privy Wallet -├── Modules: -│ └── AutoCollectExecutor -│ ├── Collection configs per asset -│ ├── Target: Main account (also owned by Privy wallet) -│ └── Thresholds and state -└── Holdings: USDC, other tokens (to be collected) -``` - -## Testing Strategy - -1. **Unit Tests** - - All configuration functions - - Collection execution logic - - Calendar day calculations - - Edge cases and error conditions - -2. **Integration Tests (ModuleKit)** - - Module installation/uninstallation - - Cross-account interactions - - Real Safe account testing - - Gas usage validation - -3. **Fuzz Testing** - - Date arithmetic edge cases - - Random threshold values - - Multiple asset scenarios - -## Implementation Notes - -### Upgradeability -- Use UUPS proxy pattern (same as AutoTopUpExecutor) -- OwnableUpgradeable for upgrade admin control -- ERC-7201 namespaced storage for upgrade safety - -### Dependencies -- BokkyPooBah's DateTime Library (already in lib/) -- OpenZeppelin contracts upgradeable (including EnumerableSet) -- ModuleKit for ERC-7579 compliance -- ERC7579ExecutorBase for _execute() functionality - -## Implementation Checklist - -- [ ] Core contract implementation (UUPS upgradeable) -- [ ] Interface extraction (IAutoCollectExecutor) -- [ ] Token transfer via _execute() with returndata validation -- [ ] Calendar-based date tracking with DateTime library -- [ ] Event and error definitions -- [ ] Unit tests following AutoTopUpExecutor.t.sol patterns -- [ ] Integration tests with ModuleKit -- [ ] Gas optimization and forge fmt -- [ ] Security review \ No newline at end of file diff --git a/typescript/packages/account-modules/docs/auto-top-up/architecture.md b/typescript/packages/account-modules/docs/auto-top-up/architecture.md deleted file mode 100644 index 6fc7821..0000000 --- a/typescript/packages/account-modules/docs/auto-top-up/architecture.md +++ /dev/null @@ -1,272 +0,0 @@ -# AutoTopUpExecutor Module Architecture - -## Overview - -The AutoTopUpExecutor is an ERC-7579 executor module that enables automatic balance management for Safe smart accounts. It allows anyone to trigger pre-configured ERC-20 token transfers from a main Safe account to designated agent accounts when their balances fall below specified thresholds. - -## Core Design Principles - -### 1. Non-Custodial Architecture -- Module operates as part of the Safe's execution context -- Never holds funds directly -- User maintains full control over configuration and can disable at any time -- Executions happen through Safe's module system - -### 2. Permissionless Triggering -- Anyone can call the trigger function to execute configured top-ups -- Security enforced through on-chain configuration and limits -- Primary automation through our keeper infrastructure (with option for users to self-host) - -### 3. Multi-Agent Support -- Single module instance manages multiple agent configurations -- Each agent has independent thresholds, amounts, and limits -- Efficient batch operations for checking and executing multiple top-ups - -## Technical Architecture - -### Module Type -- **Type**: Executor Module (0x01) -- **Standard**: ERC-7579 compliant -- **Base**: Rhinestone ModuleKit's `ERC7579ExecutorBase` -- **Upgradeable**: Yes, using UUPS pattern with OpenZeppelin - -### Storage Pattern -- **ERC-7201**: Namespaced storage for upgrade safety -- **Storage Layout**: - ```solidity - // User-configurable parameters - struct TopUpConfig { - uint256 dailyLimit; // Target balance to maintain (max top-up per day) - uint256 monthlyLimit; // Maximum total top-ups per month - bool enabled; // Configuration active status - } - - // Immutable identity and internal state (not user-editable) - struct TopUpState { - address agent; // Target agent account (immutable, part of config ID) - address asset; // ERC-20 token address (immutable, part of config ID) - uint256 lastTopUpTime; // Last top-up timestamp (enforces once-per-day) - uint256 monthlySpent; // Amount topped up this month - uint256 lastResetMonth; // Last monthly reset timestamp - } - - struct AutoTopUpStorage { - // Config ID => user configuration - mapping(bytes32 => TopUpConfig) configs; - - // Config ID => internal state - mapping(bytes32 => TopUpState) states; - - // Account => set of config IDs - mapping(address => EnumerableSet.Bytes32Set) accountConfigs; - } - ``` - -- **Config ID Generation**: `keccak256(abi.encode("TopUpConfig", account, agent, asset))` returns bytes32 for unique configs -- **Namespaced IDs**: "TopUpConfig" prefix prevents collision with other system hashes -- **Per-Account Execution**: Each account's configs are triggered separately to avoid gas limits -- **Gas Optimization**: EnumerableSet allows O(1) add/remove and efficient iteration within an account - -### Key Functions - -#### Module Interface (ERC-7579 via ModuleKit) -```solidity -// Inherited from ERC7579ExecutorBase -function onInstall(bytes calldata data) external -function onUninstall(bytes calldata data) external -function isModuleType(uint256 typeID) external view returns (bool) -function isInitialized(address smartAccount) external view returns (bool) - -// Internal execution helpers from base (used within our functions) -// _execute(address account, address to, uint256 value, bytes memory data) - single tx -// _execute(address account, Execution[] memory execs) - batch tx -// (Plus msg.sender variants and delegatecall versions we won't use) -``` - -#### Configuration Management -```solidity -function configureTopUp( - address agent, - address asset, - TopUpConfig calldata config -) external returns (bytes32 configId) - -function configureTopUpById( - bytes32 configId, - TopUpConfig calldata config -) external - -function disableTopUp(bytes32 configId) external -function enableTopUp(bytes32 configId) external -``` - -#### Execution -```solidity -function triggerTopUps(address account) external returns (bytes32[] memory executed) -function triggerTopUp(bytes32 configId) external returns (bool executed) -``` - -#### View Functions -```solidity -function generateConfigId(address account, address agent, address asset) external pure returns (bytes32) -function getTopUpConfigs(address account) external view returns (TopUpConfig[] memory, TopUpState[] memory) -function canExecuteTopUp(bytes32 configId) external view returns (bool, string memory reason) -function getTopUpById(bytes32 configId) external view returns (TopUpConfig memory config, TopUpState memory state) -function getTopUp(address account, address agent, address asset) external view returns (TopUpConfig memory config, TopUpState memory state) -``` - -## Execution Flow - -### 1. Installation -1. Safe owner calls module management to install AutoTopUpExecutor -2. Module's `onInstall` is called with initial configurations (optional) -3. Module registers the Safe account as initialized - -### 2. Configuration -1. Safe owner sends transaction to module to configure top-ups -2. Config ID generated: `keccak256(abi.encode("TopUpConfig", account, agent, asset))` -3. `configureTopUp()` creates new or updates existing config for agent/asset pair -4. `configureTopUpById()` updates existing config by its ID -5. Agent and asset are immutable once set (part of the config ID) -6. Only dailyLimit, monthlyLimit, and enabled status can be updated -7. Multiple configurations can exist for different agents and different tokens -8. Frontend/keeper can precompute config IDs using `generateConfigId()` - -### 3. Triggering -1. Keeper calls `triggerTopUps(account)` for each account (separate transactions) -2. Module iterates through all enabled configurations for that specific account -3. For each configuration: - - Check if already topped up today (via `lastTopUpTime`) - - Calculate top-up amount: `min(dailyLimit - agentBalance, monthlyLimit - monthlySpent)` - - Skip if amount ≤ 0 (agent already funded or monthly limit reached) - - Execute transfer via internal `_execute()` helper (triggers Safe's module execution) - - Update `lastTopUpTime` and `monthlySpent` - -### 4. Limit Management -- **Daily**: Enforced by once-per-day check using `lastTopUpTime` -- **Monthly**: Reset on the 1st of each month (tracked via `lastResetMonth`) -- **Top-up calculation**: Always maintains balance up to `dailyLimit`, respecting `monthlyLimit` -- **No partial days**: If a top-up happens, it's for the full daily amount (up to monthly remaining) - -## Security Considerations - -### Access Control -- Only Safe account can configure its own top-ups -- Configuration updates require Safe transaction -- No admin keys or external control - -### Limit Enforcement -- Once-per-day enforcement prevents abuse -- Monthly budget caps provide spending control -- Simple calculation: top up to daily limit, not exceeding monthly budget - -### Reentrancy Protection -- OpenZeppelin's ReentrancyGuard on all state-changing functions -- Checks-effects-interactions pattern -- State updates before external calls - -### Validation -- Balance checks before transfers -- Sufficient Safe balance validation -- Asset address validation (ensure valid ERC-20 contract) -- Agent address validation (prevent self-transfers) - -## Gas Optimization - -### Batch Operations -- Per-account batch execution (all configs for one account in one tx) -- Bounded gas usage per transaction -- Keeper maintains off-chain list of accounts to service - -### Storage Efficiency -- EnumerableSet for per-account config tracking -- O(1) config lookups via mapping -- Config IDs prevent duplicate account/agent/asset combinations -- No global account list needed (keeper tracks off-chain) - -## Integration Points - -### ERC-7579 Module System -- Registered as executor module (type 0x01) -- Uses ModuleKit's `_execute()` helpers for execution -- Works across all ERC-7579 compliant accounts (Safe, Kernel, Biconomy) - -### Token Contracts -- ERC20 interface for balance checks -- OpenZeppelin's SafeERC20 for safe token transfers -- Transfers executed via Safe module system (using _execute) -- No direct token approvals needed - -### Monitoring & Events -```solidity -event TopUpConfigured(address indexed account, address indexed agent, address asset, bytes32 indexed configId, TopUpConfig config) -event TopUpExecuted(address indexed account, address indexed agent, address asset, bytes32 indexed configId, uint256 amount) -event TopUpFailed(address indexed account, address indexed agent, address asset, bytes32 indexed configId, string reason) -event TopUpEnabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId) -event TopUpDisabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId) -``` - -- **TopUpConfigured**: Emitted on both initial configuration and updates -- **TopUpEnabled/Disabled**: Emitted whenever enabled status changes (via any function) - -## Future Enhancements - -### Post-MVP Improvements -1. **Native Token Support**: ETH/MATIC/etc. alongside ERC-20s -2. **Off-chain Signatures**: Gasless configuration updates via EIP-712 signed messages - -## Testing Strategy - -### Unit Tests -- Configuration CRUD operations -- Daily limit enforcement (once per day) -- Monthly limit tracking and resets -- Balance calculation logic (top up to daily limit) - -### Integration Tests -- Safe module installation/uninstallation using ModuleKit test utilities -- Token transfer execution through Safe -- Multi-account scenarios using ModuleKit's `makeAccountInstance` -- Cross-implementation tests (Safe, Kernel, Biconomy) - lower priority - -### Security Tests -- Reentrancy attempts -- Limit bypass attempts (trying to trigger multiple times per day) -- Unauthorized configuration changes -- Edge cases around month transitions - -## Implementation Stack - -### Dependencies -- **ModuleKit** (v0.5.9+): Rhinestone's development kit for ERC-7579 modules - - Provides `ERC7579ExecutorBase` for executor functionality - - Built-in test utilities for multi-account testing (Safe, Kernel, Biconomy) - - Helper functions for module deployment - - Integration with Module Registry - - Main import: `import "modulekit/Modules.sol"` - - **Important**: Requires `npm install` in lib/modulekit directory for ERC4337 dependencies -- **OpenZeppelin Contracts Upgradeable**: For UUPS proxy pattern and utilities -- **OpenZeppelin Contracts**: For ERC20 interface and security utilities - -### Inheritance Chain -``` -AutoTopUpExecutor - ├── ERC7579ExecutorBase (from ModuleKit) - │ └── IERC7579Module - ├── UUPSUpgradeable (from OpenZeppelin) - ├── OwnableUpgradeable (from OpenZeppelin) - └── ReentrancyGuardUpgradeable (from OpenZeppelin) -``` - -## Deployment Considerations - -### Deployment Steps -1. Deploy implementation contract -2. Deploy proxy with initializer -3. Register in Rhinestone module registry -4. Integrate with Safe deployment flow -5. Utilize ModuleKit's deployment helpers - -### Monitoring -- Subgraph for indexing all contract events -- Track and alert on failed top-ups (especially during initial rollout) \ No newline at end of file diff --git a/typescript/packages/account-modules/foundry.lock b/typescript/packages/account-modules/foundry.lock deleted file mode 100644 index 1d1d4a5..0000000 --- a/typescript/packages/account-modules/foundry.lock +++ /dev/null @@ -1,68 +0,0 @@ -{ - "../../external/x402-private": { - "rev": "0fd862e2dc734ca0303210c919e246990b5c1cc7" - }, - "../escrow/lib/forge-std": { - "rev": "addeae62cd620c53f2fdc91bfc82396f5df79d1d" - }, - "../escrow/lib/openzeppelin-contracts": { - "rev": "4a67c6f3ab2be41487889a020c99e11dedbd6eb4" - }, - "../escrow/lib/openzeppelin-contracts-upgradeable": { - "rev": "62164b46517484f5b734d2c0e7e647de058685bf" - }, - "external/x402-private": { - "branch": { - "name": "main", - "rev": "3211e365dc998d8853d1a5cf16d6673feef57340" - } - }, - "lib/BokkyPooBahsDateTimeLibrary": { - "rev": "1dc26f977c57a6ba3ed6d7c53cafdb191e7e59ae" - }, - "lib/forge-std": { - "tag": { - "name": "v1.10.0", - "rev": "8bbcf6e3f8f62f419e5429a0bd89331c85c37824" - } - }, - "lib/modulekit": { - "tag": { - "name": "v0.5.9", - "rev": "b696ccbe1b16a55d8b1a1de192309500af0fae5e" - } - }, - "lib/openzeppelin-contracts": { - "tag": { - "name": "v5.4.0", - "rev": "c64a1edb67b6e3f4a15cca8909c9482ad33a02b0" - } - }, - "lib/openzeppelin-contracts-upgradeable": { - "tag": { - "name": "v5.4.0", - "rev": "e725abddf1e01cf05ace496e950fc8e243cc7cab" - } - }, - "packages/account-modules/lib/BokkyPooBahsDateTimeLibrary": { - "rev": "1dc26f977c57a6ba3ed6d7c53cafdb191e7e59ae" - }, - "packages/account-modules/lib/forge-std": { - "rev": "8bbcf6e3f8f62f419e5429a0bd89331c85c37824" - }, - "packages/account-modules/lib/modulekit": { - "rev": "676bb65032c17b13ecd15ee89f435f0afeffca9b" - }, - "packages/account-modules/lib/openzeppelin-contracts": { - "rev": "c64a1edb67b6e3f4a15cca8909c9482ad33a02b0" - }, - "packages/escrow/lib/forge-std": { - "rev": "addeae62cd620c53f2fdc91bfc82396f5df79d1d" - }, - "packages/escrow/lib/openzeppelin-contracts": { - "rev": "4a67c6f3ab2be41487889a020c99e11dedbd6eb4" - }, - "packages/escrow/lib/openzeppelin-contracts-upgradeable": { - "rev": "62164b46517484f5b734d2c0e7e647de058685bf" - } -} \ No newline at end of file diff --git a/typescript/packages/account-modules/foundry.toml b/typescript/packages/account-modules/foundry.toml deleted file mode 100644 index 41e39e9..0000000 --- a/typescript/packages/account-modules/foundry.toml +++ /dev/null @@ -1,28 +0,0 @@ -[profile.default] -src = "src" -out = "out" -libs = ["lib"] -remappings = [ - "modulekit/=lib/modulekit/", - "@openzeppelin/=lib/openzeppelin-contracts/", - "forge-std/=lib/forge-std/src/", - "BokkyPooBahsDateTimeLibrary/=lib/BokkyPooBahsDateTimeLibrary/", - "safe-singleton-deployer/=lib/safe-singleton-deployer-sol/src/", - # ModuleKit dependencies - "erc4337-validation/=lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/", - "@ERC4337/=lib/modulekit/node_modules/@ERC4337/", - "account-abstraction/=lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/", - "account-abstraction-v0.6/=lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/", - "@rhinestone/=lib/modulekit/node_modules/@rhinestone/", - "ds-test/=lib/modulekit/node_modules/ds-test/src/", - "solady/=lib/modulekit/node_modules/solady/src/", - "solarray/=lib/modulekit/node_modules/solarray/src/", - "@prb/math/=lib/modulekit/node_modules/@prb/math/src/", - "ExcessivelySafeCall/=lib/modulekit/node_modules/excessively-safe-call/src/" -] -solc = "0.8.30" -optimizer = true -optimizer_runs = 200 - -[lint] -exclude_lints = ["asm-keccak256"] diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitattributes b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitattributes deleted file mode 100644 index 52031de..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.sol linguist-language=Solidity diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitignore b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitignore deleted file mode 100644 index a26200d..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -.DS_Store -.project -.settings -test/testchain/geth -test/testchain/geth.ipc -test/testchain/history -test/contracts -private diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/LICENSE b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/LICENSE deleted file mode 100644 index 0040033..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018 The Officious BokkyPooBah / Bok Consulting Pty Ltd - -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/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/README.md b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/README.md deleted file mode 100644 index a078dc6..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/README.md +++ /dev/null @@ -1,915 +0,0 @@ - - -
    - -
    - -# BokkyPooBah's DateTime Library - -A gas-efficient Solidity date and time library. - -Instead of using loops and lookup tables, this date conversions library uses formulae to convert year/month/day hour:minute:second to a Unix timestamp and back. - -See [BokkyPooBah’s Gas-Efficient Solidity DateTime Library](https://medium.com/@BokkyPooBah/bokkypoobahs-gas-efficient-solidity-datetime-library-92bf96d9b2da) for more explanations. - -Thank you to [Alex Kampa](https://github.com/alex-kampa), [James Zaki](https://github.com/jzaki) and [Adrian Guerrera](https://github.com/apguerrera) for helping to validate this library. Thanks also to [Oleksii Matiiasevych](https://github.com/lastperson) for asking about leap seconds. - -
    - -
    - -## Table Of Contents - -* [History](#history) -* [Bug Bounty Scope And Donations](#bug-bounty-scope-and-donations) -* [Deployment](#deployment) -* [Questions And Answers](#questions-and-answers) -* [Conventions](#conventions) -* [Functions](#functions) - * [_daysFromDate](#_daysfromdate) - * [_daysToDate](#_daystodate) - * [timestampFromDate](#timestampfromdate) - * [timestampFromDateTime](#timestampfromdatetime) - * [timestampToDate](#timestamptodate) - * [timestampToDateTime](#timestamptodatetime) - * [isValidDate](#isvaliddate) - * [isValidDateTime](#isvaliddatetime) - * [isLeapYear](#isleapyear) - * [_isLeapYear](#_isleapyear) - * [isWeekDay](#isweekday) - * [isWeekEnd](#isweekend) - * [getDaysInMonth](#getdaysinmonth) - * [_getDaysInMonth](#_getdaysinmonth) - * [getDayOfWeek](#getdayofweek) - * [getYear](#getyear) - * [getMonth](#getmonth) - * [getDay](#getday) - * [getHour](#gethour) - * [getMinute](#getminute) - * [getSecond](#getsecond) - * [addYears](#addyears) - * [addMonths](#addmonths) - * [addDays](#adddays) - * [addHours](#addhours) - * [addMinutes](#addminutes) - * [addSeconds](#addseconds) - * [subYears](#subyears) - * [subMonths](#submonths) - * [subDays](#subdays) - * [subHours](#subhours) - * [subMinutes](#subminutes) - * [subSeconds](#subseconds) - * [diffYears](#diffyears) - * [diffMonths](#diffmonths) - * [diffDays](#diffdays) - * [diffHours](#diffhours) - * [diffMinutes](#diffminutes) - * [diffSeconds](#diffseconds) -* [Gas Cost](#gas-cost) -* [Algorithm](#algorithm) -* [Testing](#testing) -* [References](#references) - -
    - -
    - -## History - -Version | Date | Notes -:------------------ |:------------ |:--------------------------------------- -v1.00-pre-release | May 25 2018 | "Rarefaction" pre-release. I'm currently trying to get this library audited, so don't use in production mode yet. -v1.00-pre-release-a | Jun 2 2018 | "Rarefaction" pre-release a. Added the [contracts/BokkyPooBahsDateTimeContract.sol](contracts/BokkyPooBahsDateTimeContract.sol) wrapper for convenience.
    [Alex Kampa](https://github.com/alex-kampa) conducted a range of [tests](https://github.com/alex-kampa/test_BokkyPooBahsDateTimeLibrary) on the library. -v1.00-pre-release-b | Jun 4 2018 | "Rarefaction" pre-release b. Replaced public function with internal for easier EtherScan verification - [a83e13b](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary/commit/a83e13bef31e8ef399007dd237e42bd5cdf479e6).
    Deployed [contracts/BokkyPooBahsDateTimeContract.sol](contracts/BokkyPooBahsDateTimeContract.sol) with the inlined [contracts/BokkyPooBahsDateTimeLibrary.sol](contracts/BokkyPooBahsDateTimeLibrary.sol) to the [Ropsten network](deployment/deployment-v1.00-prerelease.md) at address [0x07239bb079094481bfaac91ca842426860021aaa](https://ropsten.etherscan.io/address/0x07239bb079094481bfaac91ca842426860021aaa#code) -v1.00-pre-release-c | June 8 2018 | "Rarefaction" pre-release c. Added `require(year >= 1970)` to `_daysFromDate(...)` in [4002b27](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary/commit/4002b278d1779fcd4f3f4527a60a5887ee6c20ba) as highlighted in [James Zaki](https://github.com/jzaki)'s audit -v1.00-pre-release-d | Sep 1 2018 | "Rarefaction" pre-release d. Added [isValidDate(...)](#isvaliddate) and [isValidDateTime(...)](#isvaliddatetime) in [380061b](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary/commit/380061b9d20c83450ee303f709fe58e973c5f4a9) as highlighted in [Adrian Guerrera](https://github.com/apguerrera)'s audit -v1.00 | Sep 2 2018 | "Rarefaction" release -v1.01 | Feb 14 2019 | "Notoryctes" release. Upgraded contracts to Solidity 0.5.x.
    Updated to MIT Licence -v1.01 | Feb 17 2019 | Bug bounty added - -
    - -
    - -## Bug Bounty Scope And Donations - -Details of the bug bounty program for this project can be found at [BokkyPooBah's Hall Of Fame And Bug Bounties](https://github.com/bokkypoobah/BokkyPooBahsHallOfFameAndBugBounties). Please consider [donating](https://github.com/bokkypoobah/BokkyPooBahsHallOfFameAndBugBounties#donations) to support the bug bounty, and the development and maintenance of decentralised applications. - -The scope of the bug bounty for this project follows: - -* [contracts/BokkyPooBahsDateTimeLibrary.sol](contracts/BokkyPooBahsDateTimeLibrary.sol) - -
    - -
    - -## Deployment - -[v1.00 of the source code](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary/tree/1ea8ef42b3d8db17b910b46e4f8c124b59d77c03/contracts) for [BokkyPooBahsDateTimeContract.sol](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary/blob/1ea8ef42b3d8db17b910b46e4f8c124b59d77c03/contracts/BokkyPooBahsDateTimeContract.sol) and [TestDateTime.sol](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary/blob/1ea8ef42b3d8db17b910b46e4f8c124b59d77c03/contracts/TestDateTime.sol) has been deployed to: - -* The Ropsten network: - * BokkyPooBahsDateTimeContract.sol at [0x947cc35992e6723de50bf704828a01fd2d5d6641](https://ropsten.etherscan.io/address/0x947cc35992e6723de50bf704828a01fd2d5d6641#code) - * TestDateTime.sol at [0xa068fe3e029a972ecdda2686318806d2b19875d1](https://ropsten.etherscan.io/address/0xa068fe3e029a972ecdda2686318806d2b19875d1#code) - -* Mainnet: - * BokkyPooBahsDateTimeContract.sol at [0x23d23d8f243e57d0b924bff3a3191078af325101](https://etherscan.io/address/0x23d23d8f243e57d0b924bff3a3191078af325101#code) - * TestDateTime.sol at [0x78f96b2d5f717fa9ad416957b79d825cc4cce69d](https://etherscan.io/address/0x78f96b2d5f717fa9ad416957b79d825cc4cce69d#code) - -For each of the deployed contracts above, you can click on the *Read Contract* tab to test out the date/time/timestamp functions. - -
    - -
    - -## Questions And Answers - -### Questions by `_dredge` - -User [/u/_dredge](https://www.reddit.com/user/_dredge) asked the [following questions](https://www.reddit.com/r/ethereum/comments/8m3p4j/bokkypoobahs_datetime_library_a_solidity/dzkss7n/): - -> Some Muslim countries have a Friday/Saturday weekend. Workday(1-7) may be more useful. -> -> I presume leap seconds and such details are taken care of in the Unix timecode. -> -> Some additional ideas for functions below. -> -> Quarter calculations -> -> weekNumber(1-53) -> -> Complete years / months / weeks / days -> -> Nearest years / months / weeks / days - -Regarding regions and systems where Friday/Saturday are weekends, please use the function `getDayOfWeek(timestamp)` that returns 1 (= Monday, ..., 7 (= Sunday) to determine whether you should treat a day as a weekday or weekend. - -See the next question regarding the leap seconds. - -Regarding the additional ideas, thanks! - -
    - -### What about the leap second? - -Asked by [Oleksii Matiiasevych](https://github.com/lastperson) and */u/_dredge* above. - -For example, a [leap second](https://en.wikipedia.org/wiki/Unix_time#Leap_seconds) was inserted on Jan 01 1999. - -From the first answer to [Unix time and leap seconds](https://stackoverflow.com/a/16539483): - -> The number of seconds per day are fixed with Unix timestamps. -> -> > The Unix time number is zero at the Unix epoch, and increases by exactly 86400 per day since the epoch. -> -> So it cannot represent leap seconds. The OS will slow down the clock to accommodate for this. The leap seconds is simply not existent as far a Unix timestamps are concerned. - -And from the second answer to [Unix time and leap seconds](https://stackoverflow.com/a/16539734): - -> Unix time is easy to work with, but some timestamps are not real times, and some timestamps are not unique times. -> -> That is, there are some duplicate timestamps representing two different seconds in time, because in unix time the sixtieth second might have to repeat itself (as there can't be a sixty-first second). Theoretically, they could also be gaps in the future because the sixtieth second doesn't have to exist, although no skipping leap seconds have been issued so far. -> -> Rationale for unix time: it's defined so that it's easy to work with. Adding support for leap seconds to the standard libraries is very tricky. -> ... - -This library aims to replicate the [Unix time](https://en.wikipedia.org/wiki/Unix_time) functionality and assumes that leap seconds are handled by the underlying operating system. - -
    - -### What is the maximum year 2345? - -Asked by [Adrian Guerrera](https://github.com/apguerrera). - -**2345** is just an arbitrary number chosen for the year limit to test to. The algorithms should still work beyond this date. - -
    - -### Why are there no input validations to some of the functions? - -Asked by [Adrian Guerrera](https://github.com/apguerrera). Specifically, the functions [_daysFromDate](#_daysfromdate), [timestampFromDate](#timestampfromdate) and [timestampFromDateTime](#timestampfromdatetime). - -The date and time inputs should be validated before the values are passed to these functions. The validation functions [isValidDate(...)](#isvaliddate) and [isValidDateTime(...)](#isvaliddatetime) have now been added for this purpose. - -
    - -### Why are all variables 256-bit integers? - -This library provides a cheap conversion between the timestamp and year/month/day hour:minute:second formats. There is no requirement for this library to store a packed structure to represent a DateTime as this data can be stored as a `uint256` and converted on the fly to year/month/day hour:minute:second. - -
    - -### Why do you call this a gas-efficient library? - -The formulae for converting between a timestamp and year/month/day hour:minute:second format uses a mathematically simple algorithm without any loops. The gas cost is relatively constant (as there are no loops) and the mathematical computations are relative cheap (compared to using loops and looking up data from storage). - -
    - -### Can this library be written more efficiently? - -Most likely. The aim of this first version is for the conversions to be computed correctly. - -
    - -### How gas-efficient is this library? - -From [Gas Cost](#gas-cost), `timestampToDateTime(…)` has an execution gas cost of 3,101 gas, and `timestampFromDateTime(…)` has an execution gas cost of 2,566 gas. - -
    - -
    - -## Conventions - -All dates, times and Unix timestamps are [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time). - -Unit | Range | Notes -:------------- |:-------------------------:|:--------------------------------------------------------------- -timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC -year | 1970 ... 2345 | -month | 1 ... 12 | -day | 1 ... 31 | -hour | 0 ... 23 | -minute | 0 ... 59 | -second | 0 ... 59 | -dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday -year/month/day | 1970/01/01 ... 2345/12/31 | - -`_days`, `_months` and `_years` variable names are `_`-prefixed as the non-prefixed versions are reserved words in Solidity. - -All functions operate on the `uint` timestamp data type, except for functions prefixed with `_`. - -
    - -
    - -## Functions - -### _daysFromDate - -Calculate the number of days `_days` from 1970/01/01 to `year`/`month`/`day`. - -```javascript -function _daysFromDate(uint year, uint month, uint day) public pure returns (uint _days) -``` - -**NOTE** This function does not validate the `year`/`month`/`day` input. Use [`isValidDate(...)`](#isvaliddate) to validate the input if necessary. - -
    - -### _daysToDate - -Calculate `year`/`month`/`day` from the number of days `_days` since 1970/01/01 . - -```javascript -function _daysToDate(uint _days) public pure returns (uint year, uint month, uint day) -``` - -
    - -### timestampFromDate - -Calculate the `timestamp` to `year`/`month`/`day`. - -```javascript -function timestampFromDate(uint year, uint month, uint day) public pure returns (uint timestamp) -``` - -**NOTE** This function does not validate the `year`/`month`/`day` input. Use [`isValidDate(...)`](#isvaliddate) to validate the input if necessary. - -
    - -### timestampFromDateTime - -Calculate the `timestamp` to `year`/`month`/`day` `hour`:`minute`:`second` UTC. - -```javascript -function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (uint timestamp) -``` - -**NOTE** This function does not validate the `year`/`month`/`day` `hour`:`minute`:`second` input. Use [`isValidDateTime(...)`](#isvaliddatetime) to validate the input if necessary. - -
    - -### timestampToDate - -Calculate `year`/`month`/`day` from `timestamp`. - -```javascript -function timestampToDate(uint timestamp) public pure returns (uint year, uint month, uint day) -``` - -
    - -### timestampToDateTime - -Calculate `year`/`month`/`day` `hour`:`minute`:`second` from `timestamp`. - -```javascript -function timestampToDateTime(uint timestamp) public pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) -``` - -
    - -### isValidDate - -Is the date specified by `year`/`month`/`day` a valid date? - -```javascript_ -function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) -``` - -
    - -
    - -### isValidDateTime - -Is the date/time specified by `year`/`month`/`day` `hour`:`minute`:`second` a valid date/time? - -```javascript_ -function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) -``` - -
    - -### isLeapYear - -Is the year specified by `timestamp` a leap year? - -```javascript_ -function isLeapYear(uint timestamp) public pure returns (bool leapYear) -``` - -
    - -### _isLeapYear - -Is the specified `year` (e.g. 2018) a leap year? - -```javascript_ -function _isLeapYear(uint year) public pure returns (bool leapYear) -``` - -
    - -### isWeekDay - -Is the day specified by `timestamp` a weekday (Monday, ..., Friday)? - -```javascript -function isWeekDay(uint timestamp) public pure returns (bool weekDay) -``` - -
    - -### isWeekEnd - -Is the day specified by `timestamp` a weekend (Saturday, Sunday)? - -```javascript -function isWeekEnd(uint timestamp) public pure returns (bool weekEnd) -``` - -
    - -### getDaysInMonth - -Return the day in the month `daysInMonth` for the month specified by `timestamp`. - -```javascript -function getDaysInMonth(uint timestamp) public pure returns (uint daysInMonth) -``` - -
    - -### _getDaysInMonth - -Return the day in the month `daysInMonth` (1, ..., 31) for the month specified by the `year`/`month`. - -```javascript -function _getDaysInMonth(uint year, uint month) public pure returns (uint daysInMonth) -``` - -
    - -### getDayOfWeek - -Return the day of the week `dayOfWeek` (1 = Monday, ..., 7 = Sunday) for the date specified by `timestamp`. - -```javascript -function getDayOfWeek(uint timestamp) public pure returns (uint dayOfWeek) -``` - -
    - -### getYear - -Get the `year` of the date specified by `timestamp`. - -```javascript -function getYear(uint timestamp) public pure returns (uint year) -``` - -
    - -### getMonth - -Get the `month` of the date specified by `timestamp`. - -```javascript -function getMonth(uint timestamp) public pure returns (uint month) -``` - -
    - -### getDay - -Get the day of the month `day` (1, ..., 31) of the date specified `timestamp`. - -```javascript -function getDay(uint timestamp) public pure returns (uint day) -``` - -
    - -### getHour - -Get the `hour` of the date and time specified by `timestamp`. - -```javascript -function getHour(uint timestamp) public pure returns (uint hour) -``` - -
    - -### getMinute - -Get the `minute` of the date and time specified by `timestamp`. - -```javascript -function getMinute(uint timestamp) public pure returns (uint minute) -``` - -
    - -### getSecond - -Get the `second` of the date and time specified by `timestamp`. - -```javascript -function getSecond(uint timestamp) public pure returns (uint second) -``` - -
    - -### addYears - -Add `_years` years to the date and time specified by `timestamp`. - -Note that the resulting day of the month will be adjusted if it exceeds the valid number of days in the month. For example, if the original date is 2020/02/29 and an additional year is added to this date, the resulting date will be an invalid date of 2021/02/29. The resulting date is then adjusted to 2021/02/28. - -```javascript -function addYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) -``` - -
    - -### addMonths - -Add `_months` months to the date and time specified by `timestamp`. - -Note that the resulting day of the month will be adjusted if it exceeds the valid number of days in the month. For example, if the original date is 2019/01/31 and an additional month is added to this date, the resulting date will be an invalid date of 2019/02/31. The resulting date is then adjusted to 2019/02/28. - -```javascript -function addMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) -``` - -
    - -### addDays - -Add `_days` days to the date and time specified by `timestamp`. - -```javascript -function addDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) -``` - -
    - -### addHours - -Add `_hours` hours to the date and time specified by `timestamp`. - -```javascript -function addHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) -``` - -
    - -### addMinutes - -Add `_minutes` minutes to the date and time specified by `timestamp`. - -```javascript -function addMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) -``` - -
    - -### addSeconds - -Add `_seconds` seconds to the date and time specified by `timestamp`. - -```javascript -function addSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) -``` - -
    - -### subYears - -Subtract `_years` years from the date and time specified by `timestamp`. - -Note that the resulting day of the month will be adjusted if it exceeds the valid number of days in the month. For example, if the original date is 2020/02/29 and a year is subtracted from this date, the resulting date will be an invalid date of 2019/02/29. The resulting date is then adjusted to 2019/02/28. - -```javascript -function subYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) -``` - -
    - -### subMonths - -Subtract `_months` months from the date and time specified by `timestamp`. - -Note that the resulting day of the month will be adjusted if it exceeds the valid number of days in the month. For example, if the original date is 2019/03/31 and a month is subtracted from this date, the resulting date will be an invalid date of 2019/02/31. The resulting date is then adjusted to 2019/02/28. - -```javascript -function subMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) -``` - -
    - -### subDays - -Subtract `_days` days from the date and time specified by `timestamp`. - -```javascript -function subDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) -``` - -
    - -### subHours - -Subtract `_hours` hours from the date and time specified by `timestamp`. - -```javascript -function subHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) -``` - -
    - -### subMinutes - -Subtract `_minutes` minutes from the date and time specified by `timestamp`. - -```javascript -function subMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) -``` - -
    - -### subSeconds - -Subtract `_seconds` seconds from the date and time specified by `timestamp`. - -```javascript -function subSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) -``` - -
    - -### diffYears - -Calculate the number of years between the dates specified by `fromTimeStamp` and `toTimestamp`. - -Note that this calculation is computed as `getYear(toTimestamp) - getYear(fromTimestamp)`, rather that subtracting the years (since 1970/01/01) represented by both `{to|from}Timestamp`. - -```javascript -function diffYears(uint fromTimestamp, uint toTimestamp) public pure returns (uint _years) -``` - -
    - -### diffMonths - -Calculate the number of months between the dates specified by `fromTimeStamp` and `toTimestamp`. - -Note that this calculation is computed as `getYear(toTimestamp) * 12 + getMonth(toTimestamp) - getYear(fromTimestamp) * 12 - getMonth(fromTimestamp)`, rather that subtracting the months (since 1970/01/01) represented by both `{to|from}Timestamp`. - -```javascript -function diffMonths(uint fromTimestamp, uint toTimestamp) public pure returns (uint _months) -``` - -
    - -### diffDays - -Calculate the number of days between the dates specified by `fromTimeStamp` and `toTimestamp`. - -Note that this calculation is computed as `(toTimestamp - fromTimestamp) / SECONDS_PER_DAY`, rather that subtracting the days (since 1970/01/01) represented by both `{to|from}Timestamp`. - -```javascript -function diffDays(uint fromTimestamp, uint toTimestamp) public pure returns (uint _days) -``` - -
    - -### diffHours - -Calculate the number of hours between the dates specified by `fromTimeStamp` and `toTimestamp`. - -Note that this calculation is computed as `(toTimestamp - fromTimestamp) / SECONDS_PER_HOUR`, rather that subtracting the hours (since 1970/01/01) represented by both `{to|from}Timestamp`. - -```javascript -function diffHours(uint fromTimestamp, uint toTimestamp) public pure returns (uint _hours) -``` - -
    - -### diffMinutes - -Calculate the number of minutes between the dates specified by `fromTimeStamp` and `toTimestamp`. - -Note that this calculation is computed as `(toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE`, rather that subtracting the minutes (since 1970/01/01) represented by both `{to|from}Timestamp`. - -```javascript -function diffMinutes(uint fromTimestamp, uint toTimestamp) public pure returns (uint _minutes) -``` - -
    - -### diffSeconds - -Calculate the number of seconds between the dates specified by `fromTimeStamp` and `toTimestamp`. - -Note that this calculation is computed as `toTimestamp - fromTimestamp`. - -```javascript -function diffSeconds(uint fromTimestamp, uint toTimestamp) public pure returns (uint _seconds) -``` - -
    - -
    - -## Gas Cost - -### `timestampToDateTime(...)` Gas Cost - -From executing the following function, the transaction gas cost is 24,693 - -```javascript -> testDateTime.timestampToDateTime(1527120000) -[2018, 5, 24, 0, 0, 0] -> testDateTime.timestampToDateTime.estimateGas(1527120000) -24693 -``` - -From Remix, the execution gas cost is 3,101 . - -From my latest testing with Remix using Solidity 0.4.24: - - - -
    - -### `timestampFromDateTime(...)` Gas Cost - -From executing the following function, the transaction gas cost is 25,054 - -```javascript -> testDateTime.timestampFromDateTime(2018, 05, 24, 1, 2, 3) -1527123723 -> testDateTime.timestampFromDateTime.estimateGas(2018, 05, 24, 1, 2, 3) -25054 -``` - -From Remix, the execution gas cost is 2,566 . - -From my latest testing with Remix using Solidity 0.4.24: - - - -
    - -### Remix Gas Estimates - -Remix gas estimates using Solidity 0.4.24: - -```json -{ - "Creation": { - "codeDepositCost": "908400", - "executionCost": "942", - "totalCost": "909342" - }, - "External": { - "DOW_FRI()": "1130", - "DOW_MON()": "1262", - "DOW_SAT()": "1064", - "DOW_SUN()": "360", - "DOW_THU()": "1108", - "DOW_TUE()": "250", - "DOW_WED()": "778", - "OFFSET19700101()": "932", - "SECONDS_PER_DAY()": "690", - "SECONDS_PER_HOUR()": "580", - "SECONDS_PER_MINUTE()": "1196", - "_daysFromDate(uint256,uint256,uint256)": "638", - "_daysToDate(uint256)": "1280", - "_getDaysInMonth(uint256,uint256)": "885", - "_isLeapYear(uint256)": "1115", - "_now()": "997", - "_nowDateTime()": "1562", - "addDays(uint256,uint256)": "772", - "addHours(uint256,uint256)": "662", - "addMinutes(uint256,uint256)": "838", - "addMonths(uint256,uint256)": "1851", - "addSeconds(uint256,uint256)": "896", - "addYears(uint256,uint256)": "1846", - "diffDays(uint256,uint256)": "1207", - "diffHours(uint256,uint256)": "503", - "diffMinutes(uint256,uint256)": "316", - "diffMonths(uint256,uint256)": "infinite", - "diffSeconds(uint256,uint256)": "712", - "diffYears(uint256,uint256)": "infinite", - "getDay(uint256)": "1114", - "getDayOfWeek(uint256)": "415", - "getDaysInMonth(uint256)": "1120", - "getHour(uint256)": "491", - "getMinute(uint256)": "1373", - "getMonth(uint256)": "1378", - "getSecond(uint256)": "810", - "getYear(uint256)": "1337", - "isLeapYear(uint256)": "1633", - "isValidDate(uint256,uint256,uint256)": "942", - "isValidDateTime(uint256,uint256,uint256,uint256,uint256,uint256)": "1269", - "isWeekDay(uint256)": "1284", - "isWeekEnd(uint256)": "624", - "subDays(uint256,uint256)": "1146", - "subHours(uint256,uint256)": "288", - "subMinutes(uint256,uint256)": "992", - "subMonths(uint256,uint256)": "2363", - "subSeconds(uint256,uint256)": "1336", - "subYears(uint256,uint256)": "1871", - "timestampFromDate(uint256,uint256,uint256)": "718", - "timestampFromDateTime(uint256,uint256,uint256,uint256,uint256,uint256)": "1077", - "timestampToDate(uint256)": "infinite", - "timestampToDateTime(uint256)": "1945" - } -} -``` -
    - -
    - -## Algorithm - -The formulae to convert year/month/day hour:minute:second to a Unix timestamp and back use the algorithms from [Converting Between Julian Dates and Gregorian Calendar Dates](http://aa.usno.navy.mil/faq/docs/JD_Formula.php). These algorithms were originally designed by [Fliegel and van Flandern (1968)](http://www.worldcat.org/title/machine-algorithm-for-processing-calendar-dates/oclc/754110896). - -Note that these algorithms depend on negative numbers, so Solidity unsigned integers `uint` are converted to signed integers `int` to compute the date conversions and the results are converted back to `uint` for general use. - -
    - -### Converting YYYYMMDD to Unix Timestamp - -The Fortran algorithm follows: - -``` - INTEGER FUNCTION JD (YEAR,MONTH,DAY) -C -C---COMPUTES THE JULIAN DATE (JD) GIVEN A GREGORIAN CALENDAR -C DATE (YEAR,MONTH,DAY). -C - INTEGER YEAR,MONTH,DAY,I,J,K -C - I= YEAR - J= MONTH - K= DAY -C - JD= K-32075+1461*(I+4800+(J-14)/12)/4+367*(J-2-(J-14)/12*12) - 2 /12-3*((I+4900+(J-14)/12)/100)/4 -C - RETURN - END -``` - -Translating this formula, and subtracting an offset (2,440,588) so 1970/01/01 is day 0: - -``` -days = day - - 32075 - + 1461 * (year + 4800 + (month - 14) / 12) / 4 - + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 - - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 - - offset -``` - -
    - -### Converting Unix Timestamp To YYYYMMDD - -The Fortran algorithm follows: - -``` - SUBROUTINE GDATE (JD, YEAR,MONTH,DAY) -C -C---COMPUTES THE GREGORIAN CALENDAR DATE (YEAR,MONTH,DAY) -C GIVEN THE JULIAN DATE (JD). -C - INTEGER JD,YEAR,MONTH,DAY,I,J,K -C - L= JD+68569 - N= 4*L/146097 - L= L-(146097*N+3)/4 - I= 4000*(L+1)/1461001 - L= L-1461*I/4+31 - J= 80*L/2447 - K= L-2447*J/80 - L= J/11 - J= J+2-12*L - I= 100*(N-49)+I+L -C - YEAR= I - MONTH= J - DAY= K -C - RETURN - END - ``` - -Translating this formula and adding an offset (2,440,588) so 1970/01/01 is day 0: - -``` -int L = days + 68569 + offset -int N = 4 * L / 146097 -L = L - (146097 * N + 3) / 4 -year = 4000 * (L + 1) / 1461001 -L = L - 1461 * year / 4 + 31 -month = 80 * L / 2447 -dd = L - 2447 * month / 80 -L = month / 11 -month = month + 2 - 12 * L -year = 100 * (N - 49) + year + L -``` - -
    - -
    - -## Testing - -Details of the testing environment can be found in [test](test). - -The DateTime library calculations have been tested for the date range 1970/01/01 to 2345/12/01 for periodically sampled dates. - -The following functions were tested using the script [test/01_test1.sh](test/01_test1.sh) with the summary results saved -in [test/test1results.txt](test/test1results.txt) and the detailed output saved in [test/test1output.txt](test/test1output.txt): - -* [x] Deploy [contracts/BokkyPooBahsDateTimeLibrary.sol](contracts/BokkyPooBahsDateTimeLibrary.sol) library -* [x] Deploy [contracts/TestDateTime.sol](contracts/TestDateTime.sol) contract -* [x] Test `isValidDate(...)` -* [x] Test `isValidDateTime(...)` -* [x] Test `isLeapYear(...)` -* [x] Test `_isLeapYear(...)` -* [x] Test `isWeekDay(...)` -* [x] Test `isWeekEnd(...)` -* [x] Test `getDaysInMonth(...)` -* [x] Test `_getDaysInMonth(...)` -* [x] Test `getDayOfWeek(...)` -* [x] Test `get{Year|Month|Day|Hour|Minute|Second}(...)` -* [x] Test `add{Years|Months|Days|Hours|Minutes|Seconds}(...)` -* [x] Test `sub{Years|Months|Days|Hours|Minutes|Seconds}(...)` -* [x] Test `diff{Years|Months|Days|Hours|Minutes|Seconds}(...)` -* [x] For a range of Unix timestamps from 1970/01/01 to 2345/12/21 - * [x] Generate the year/month/day hour/minute/second from the Unix timestamp using `timestampToDateTime(...)` - * [x] Generate the Unix timestamp from the calculated year/month/day hour/minute/second using `timestampFromDateTime(...)` - * [x] Compare the year/month/day hour/minute/second to the JavaScript *Date* calculation - -
    - -
    - -## References - -A copy of the webpage with the algorithm [Converting Between Julian Dates and Gregorian Calendar Dates](http://aa.usno.navy.mil/faq/docs/JD_Formula.php) has been saved to [docs/ConvertingBetweenJulianDatesAndGregorianCalendarDates.pdf](docs/ConvertingBetweenJulianDatesAndGregorianCalendarDates.pdf) as some people have had difficulty accessing this page. - -
    - -
    - -Enjoy! - -(c) BokkyPooBah / Bok Consulting Pty Ltd - Feb 17 2019. The MIT Licence. diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeContract.sol b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeContract.sol deleted file mode 100644 index 2a58cb1..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeContract.sol +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.0 <0.9.0; - -// ---------------------------------------------------------------------------- -// BokkyPooBah's DateTime Library v1.00 - Contract Instance -// -// A gas-efficient Solidity date and time library -// -// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary -// -// Tested date range 1970/01/01 to 2345/12/31 -// -// Conventions: -// Unit | Range | Notes -// :-------- |:-------------:|:----- -// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC -// year | 1970 ... 2345 | -// month | 1 ... 12 | -// day | 1 ... 31 | -// hour | 0 ... 23 | -// minute | 0 ... 59 | -// second | 0 ... 59 | -// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday -// -// -// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018. -// -// GNU Lesser General Public License 3.0 -// https://www.gnu.org/licenses/lgpl-3.0.en.html -// ---------------------------------------------------------------------------- - -import "BokkyPooBahsDateTimeLibrary.sol"; - -contract BokkyPooBahsDateTimeContract { - uint public constant SECONDS_PER_DAY = 24 * 60 * 60; - uint public constant SECONDS_PER_HOUR = 60 * 60; - uint public constant SECONDS_PER_MINUTE = 60; - int public constant OFFSET19700101 = 2440588; - - uint public constant DOW_MON = 1; - uint public constant DOW_TUE = 2; - uint public constant DOW_WED = 3; - uint public constant DOW_THU = 4; - uint public constant DOW_FRI = 5; - uint public constant DOW_SAT = 6; - uint public constant DOW_SUN = 7; - - function _now() public view returns (uint timestamp) { - timestamp = now; - } - function _nowDateTime() public view returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { - (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(now); - } - function _daysFromDate(uint year, uint month, uint day) public pure returns (uint _days) { - return BokkyPooBahsDateTimeLibrary._daysFromDate(year, month, day); - } - function _daysToDate(uint _days) public pure returns (uint year, uint month, uint day) { - return BokkyPooBahsDateTimeLibrary._daysToDate(_days); - } - function timestampFromDate(uint year, uint month, uint day) public pure returns (uint timestamp) { - return BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day); - } - function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (uint timestamp) { - return BokkyPooBahsDateTimeLibrary.timestampFromDateTime(year, month, day, hour, minute, second); - } - function timestampToDate(uint timestamp) public pure returns (uint year, uint month, uint day) { - (year, month, day) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); - } - function timestampToDateTime(uint timestamp) public pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { - (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(timestamp); - } - - function isValidDate(uint year, uint month, uint day) public pure returns (bool valid) { - valid = BokkyPooBahsDateTimeLibrary.isValidDate(year, month, day); - } - function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (bool valid) { - valid = BokkyPooBahsDateTimeLibrary.isValidDateTime(year, month, day, hour, minute, second); - } - function isLeapYear(uint timestamp) public pure returns (bool leapYear) { - leapYear = BokkyPooBahsDateTimeLibrary.isLeapYear(timestamp); - } - function _isLeapYear(uint year) public pure returns (bool leapYear) { - leapYear = BokkyPooBahsDateTimeLibrary._isLeapYear(year); - } - function isWeekDay(uint timestamp) public pure returns (bool weekDay) { - weekDay = BokkyPooBahsDateTimeLibrary.isWeekDay(timestamp); - } - function isWeekEnd(uint timestamp) public pure returns (bool weekEnd) { - weekEnd = BokkyPooBahsDateTimeLibrary.isWeekEnd(timestamp); - } - - function getDaysInMonth(uint timestamp) public pure returns (uint daysInMonth) { - daysInMonth = BokkyPooBahsDateTimeLibrary.getDaysInMonth(timestamp); - } - function _getDaysInMonth(uint year, uint month) public pure returns (uint daysInMonth) { - daysInMonth = BokkyPooBahsDateTimeLibrary._getDaysInMonth(year, month); - } - function getDayOfWeek(uint timestamp) public pure returns (uint dayOfWeek) { - dayOfWeek = BokkyPooBahsDateTimeLibrary.getDayOfWeek(timestamp); - } - - function getYear(uint timestamp) public pure returns (uint year) { - year = BokkyPooBahsDateTimeLibrary.getYear(timestamp); - } - function getMonth(uint timestamp) public pure returns (uint month) { - month = BokkyPooBahsDateTimeLibrary.getMonth(timestamp); - } - function getDay(uint timestamp) public pure returns (uint day) { - day = BokkyPooBahsDateTimeLibrary.getDay(timestamp); - } - function getHour(uint timestamp) public pure returns (uint hour) { - hour = BokkyPooBahsDateTimeLibrary.getHour(timestamp); - } - function getMinute(uint timestamp) public pure returns (uint minute) { - minute = BokkyPooBahsDateTimeLibrary.getMinute(timestamp); - } - function getSecond(uint timestamp) public pure returns (uint second) { - second = BokkyPooBahsDateTimeLibrary.getSecond(timestamp); - } - - function addYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addYears(timestamp, _years); - } - function addMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addMonths(timestamp, _months); - } - function addDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addDays(timestamp, _days); - } - function addHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addHours(timestamp, _hours); - } - function addMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addMinutes(timestamp, _minutes); - } - function addSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addSeconds(timestamp, _seconds); - } - - function subYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subYears(timestamp, _years); - } - function subMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subMonths(timestamp, _months); - } - function subDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subDays(timestamp, _days); - } - function subHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subHours(timestamp, _hours); - } - function subMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subMinutes(timestamp, _minutes); - } - function subSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subSeconds(timestamp, _seconds); - } - - function diffYears(uint fromTimestamp, uint toTimestamp) public pure returns (uint _years) { - _years = BokkyPooBahsDateTimeLibrary.diffYears(fromTimestamp, toTimestamp); - } - function diffMonths(uint fromTimestamp, uint toTimestamp) public pure returns (uint _months) { - _months = BokkyPooBahsDateTimeLibrary.diffMonths(fromTimestamp, toTimestamp); - } - function diffDays(uint fromTimestamp, uint toTimestamp) public pure returns (uint _days) { - _days = BokkyPooBahsDateTimeLibrary.diffDays(fromTimestamp, toTimestamp); - } - function diffHours(uint fromTimestamp, uint toTimestamp) public pure returns (uint _hours) { - _hours = BokkyPooBahsDateTimeLibrary.diffHours(fromTimestamp, toTimestamp); - } - function diffMinutes(uint fromTimestamp, uint toTimestamp) public pure returns (uint _minutes) { - _minutes = BokkyPooBahsDateTimeLibrary.diffMinutes(fromTimestamp, toTimestamp); - } - function diffSeconds(uint fromTimestamp, uint toTimestamp) public pure returns (uint _seconds) { - _seconds = BokkyPooBahsDateTimeLibrary.diffSeconds(fromTimestamp, toTimestamp); - } -} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol deleted file mode 100644 index 79a6e10..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol +++ /dev/null @@ -1,301 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.0 <0.9.0; - -// ---------------------------------------------------------------------------- -// BokkyPooBah's DateTime Library v1.01 -// -// A gas-efficient Solidity date and time library -// -// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary -// -// Tested date range 1970/01/01 to 2345/12/31 -// -// Conventions: -// Unit | Range | Notes -// :-------- |:-------------:|:----- -// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC -// year | 1970 ... 2345 | -// month | 1 ... 12 | -// day | 1 ... 31 | -// hour | 0 ... 23 | -// minute | 0 ... 59 | -// second | 0 ... 59 | -// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday -// -// -// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. -// ---------------------------------------------------------------------------- - -library BokkyPooBahsDateTimeLibrary { - - uint constant SECONDS_PER_DAY = 24 * 60 * 60; - uint constant SECONDS_PER_HOUR = 60 * 60; - uint constant SECONDS_PER_MINUTE = 60; - int constant OFFSET19700101 = 2440588; - - uint constant DOW_MON = 1; - uint constant DOW_TUE = 2; - uint constant DOW_WED = 3; - uint constant DOW_THU = 4; - uint constant DOW_FRI = 5; - uint constant DOW_SAT = 6; - uint constant DOW_SUN = 7; - - // ------------------------------------------------------------------------ - // Calculate the number of days from 1970/01/01 to year/month/day using - // the date conversion algorithm from - // https://aa.usno.navy.mil/faq/JD_formula.html - // and subtracting the offset 2440588 so that 1970/01/01 is day 0 - // - // days = day - // - 32075 - // + 1461 * (year + 4800 + (month - 14) / 12) / 4 - // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 - // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 - // - offset - // ------------------------------------------------------------------------ - function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) { - require(year >= 1970); - int _year = int(year); - int _month = int(month); - int _day = int(day); - - int __days = _day - - 32075 - + 1461 * (_year + 4800 + (_month - 14) / 12) / 4 - + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12 - - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4 - - OFFSET19700101; - - _days = uint(__days); - } - - // ------------------------------------------------------------------------ - // Calculate year/month/day from the number of days since 1970/01/01 using - // the date conversion algorithm from - // http://aa.usno.navy.mil/faq/docs/JD_Formula.php - // and adding the offset 2440588 so that 1970/01/01 is day 0 - // - // int L = days + 68569 + offset - // int N = 4 * L / 146097 - // L = L - (146097 * N + 3) / 4 - // year = 4000 * (L + 1) / 1461001 - // L = L - 1461 * year / 4 + 31 - // month = 80 * L / 2447 - // dd = L - 2447 * month / 80 - // L = month / 11 - // month = month + 2 - 12 * L - // year = 100 * (N - 49) + year + L - // ------------------------------------------------------------------------ - function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) { - int __days = int(_days); - - int L = __days + 68569 + OFFSET19700101; - int N = 4 * L / 146097; - L = L - (146097 * N + 3) / 4; - int _year = 4000 * (L + 1) / 1461001; - L = L - 1461 * _year / 4 + 31; - int _month = 80 * L / 2447; - int _day = L - 2447 * _month / 80; - L = _month / 11; - _month = _month + 2 - 12 * L; - _year = 100 * (N - 49) + _year + L; - - year = uint(_year); - month = uint(_month); - day = uint(_day); - } - - function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) { - timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; - } - function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) { - timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second; - } - function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) { - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function timestampToDateTime(uint timestamp) internal pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - uint secs = timestamp % SECONDS_PER_DAY; - hour = secs / SECONDS_PER_HOUR; - secs = secs % SECONDS_PER_HOUR; - minute = secs / SECONDS_PER_MINUTE; - second = secs % SECONDS_PER_MINUTE; - } - - function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) { - if (year >= 1970 && month > 0 && month <= 12) { - uint daysInMonth = _getDaysInMonth(year, month); - if (day > 0 && day <= daysInMonth) { - valid = true; - } - } - } - function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) { - if (isValidDate(year, month, day)) { - if (hour < 24 && minute < 60 && second < 60) { - valid = true; - } - } - } - function isLeapYear(uint timestamp) internal pure returns (bool leapYear) { - (uint year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); - leapYear = _isLeapYear(year); - } - function _isLeapYear(uint year) internal pure returns (bool leapYear) { - leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); - } - function isWeekDay(uint timestamp) internal pure returns (bool weekDay) { - weekDay = getDayOfWeek(timestamp) <= DOW_FRI; - } - function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) { - weekEnd = getDayOfWeek(timestamp) >= DOW_SAT; - } - function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) { - (uint year, uint month,) = _daysToDate(timestamp / SECONDS_PER_DAY); - daysInMonth = _getDaysInMonth(year, month); - } - function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) { - if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { - daysInMonth = 31; - } else if (month != 2) { - daysInMonth = 30; - } else { - daysInMonth = _isLeapYear(year) ? 29 : 28; - } - } - // 1 = Monday, 7 = Sunday - function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) { - uint _days = timestamp / SECONDS_PER_DAY; - dayOfWeek = (_days + 3) % 7 + 1; - } - - function getYear(uint timestamp) internal pure returns (uint year) { - (year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function getMonth(uint timestamp) internal pure returns (uint month) { - (,month,) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function getDay(uint timestamp) internal pure returns (uint day) { - (,,day) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function getHour(uint timestamp) internal pure returns (uint hour) { - uint secs = timestamp % SECONDS_PER_DAY; - hour = secs / SECONDS_PER_HOUR; - } - function getMinute(uint timestamp) internal pure returns (uint minute) { - uint secs = timestamp % SECONDS_PER_HOUR; - minute = secs / SECONDS_PER_MINUTE; - } - function getSecond(uint timestamp) internal pure returns (uint second) { - second = timestamp % SECONDS_PER_MINUTE; - } - - function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { - (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); - year += _years; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp >= timestamp); - } - function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { - (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); - month += _months; - year += (month - 1) / 12; - month = (month - 1) % 12 + 1; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp >= timestamp); - } - function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _days * SECONDS_PER_DAY; - require(newTimestamp >= timestamp); - } - function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _hours * SECONDS_PER_HOUR; - require(newTimestamp >= timestamp); - } - function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE; - require(newTimestamp >= timestamp); - } - function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _seconds; - require(newTimestamp >= timestamp); - } - - function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { - (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); - year -= _years; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp <= timestamp); - } - function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { - (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); - uint yearMonth = year * 12 + (month - 1) - _months; - year = yearMonth / 12; - month = yearMonth % 12 + 1; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp <= timestamp); - } - function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _days * SECONDS_PER_DAY; - require(newTimestamp <= timestamp); - } - function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _hours * SECONDS_PER_HOUR; - require(newTimestamp <= timestamp); - } - function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE; - require(newTimestamp <= timestamp); - } - function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _seconds; - require(newTimestamp <= timestamp); - } - - function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) { - require(fromTimestamp <= toTimestamp); - (uint fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); - (uint toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); - _years = toYear - fromYear; - } - function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) { - require(fromTimestamp <= toTimestamp); - (uint fromYear, uint fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); - (uint toYear, uint toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); - _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth; - } - function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) { - require(fromTimestamp <= toTimestamp); - _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY; - } - function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) { - require(fromTimestamp <= toTimestamp); - _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR; - } - function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) { - require(fromTimestamp <= toTimestamp); - _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE; - } - function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) { - require(fromTimestamp <= toTimestamp); - _seconds = toTimestamp - fromTimestamp; - } -} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/TestDateTime.sol b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/TestDateTime.sol deleted file mode 100644 index 4213d67..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/contracts/TestDateTime.sol +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.0 <0.9.0; - -import "BokkyPooBahsDateTimeLibrary.sol"; - -// ---------------------------------------------------------------------------- -// Testing BokkyPooBah's DateTime Library -// -// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary -// -// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. -// ---------------------------------------------------------------------------- - -contract TestDateTime { - using BokkyPooBahsDateTimeLibrary for uint; - - uint public nextYear; - - function test() public { - uint today = now; - nextYear = today.addYears(1); - } - - function timestampFromDate(uint year, uint month, uint day) public pure returns (uint timestamp) { - return BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day); - } - function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (uint timestamp) { - return BokkyPooBahsDateTimeLibrary.timestampFromDateTime(year, month, day, hour, minute, second); - } - function timestampToDate(uint timestamp) public pure returns (uint year, uint month, uint day) { - (year, month, day) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); - } - function timestampToDateTime(uint timestamp) public pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { - (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(timestamp); - } - - function isLeapYear(uint timestamp) public pure returns (bool leapYear) { - leapYear = BokkyPooBahsDateTimeLibrary.isLeapYear(timestamp); - } - function _isLeapYear(uint year) public pure returns (bool leapYear) { - leapYear = BokkyPooBahsDateTimeLibrary._isLeapYear(year); - } - function isWeekDay(uint timestamp) public pure returns (bool weekDay) { - weekDay = BokkyPooBahsDateTimeLibrary.isWeekDay(timestamp); - } - function isWeekEnd(uint timestamp) public pure returns (bool weekEnd) { - weekEnd = BokkyPooBahsDateTimeLibrary.isWeekEnd(timestamp); - } - - function getDaysInMonth(uint timestamp) public pure returns (uint daysInMonth) { - daysInMonth = BokkyPooBahsDateTimeLibrary.getDaysInMonth(timestamp); - } - function _getDaysInMonth(uint year, uint month) public pure returns (uint daysInMonth) { - daysInMonth = BokkyPooBahsDateTimeLibrary._getDaysInMonth(year, month); - } - function getDayOfWeek(uint timestamp) public pure returns (uint dayOfWeek) { - dayOfWeek = BokkyPooBahsDateTimeLibrary.getDayOfWeek(timestamp); - } - - function isValidDate(uint year, uint month, uint day) public pure returns (bool valid) { - valid = BokkyPooBahsDateTimeLibrary.isValidDate(year, month, day); - } - function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (bool valid) { - valid = BokkyPooBahsDateTimeLibrary.isValidDateTime(year, month, day, hour, minute, second); - } - - function getYear(uint timestamp) public pure returns (uint year) { - year = BokkyPooBahsDateTimeLibrary.getYear(timestamp); - } - function getMonth(uint timestamp) public pure returns (uint month) { - month = BokkyPooBahsDateTimeLibrary.getMonth(timestamp); - } - function getDay(uint timestamp) public pure returns (uint day) { - day = BokkyPooBahsDateTimeLibrary.getDay(timestamp); - } - function getHour(uint timestamp) public pure returns (uint hour) { - hour = BokkyPooBahsDateTimeLibrary.getHour(timestamp); - } - function getMinute(uint timestamp) public pure returns (uint minute) { - minute = BokkyPooBahsDateTimeLibrary.getMinute(timestamp); - } - function getSecond(uint timestamp) public pure returns (uint second) { - second = BokkyPooBahsDateTimeLibrary.getSecond(timestamp); - } - - function addYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addYears(timestamp, _years); - } - function addMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addMonths(timestamp, _months); - } - function addDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addDays(timestamp, _days); - } - function addHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addHours(timestamp, _hours); - } - function addMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addMinutes(timestamp, _minutes); - } - function addSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addSeconds(timestamp, _seconds); - } - - function subYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subYears(timestamp, _years); - } - function subMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subMonths(timestamp, _months); - } - function subDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subDays(timestamp, _days); - } - function subHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subHours(timestamp, _hours); - } - function subMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subMinutes(timestamp, _minutes); - } - function subSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subSeconds(timestamp, _seconds); - } - - function diffYears(uint fromTimestamp, uint toTimestamp) public pure returns (uint _years) { - _years = BokkyPooBahsDateTimeLibrary.diffYears(fromTimestamp, toTimestamp); - } - function diffMonths(uint fromTimestamp, uint toTimestamp) public pure returns (uint _months) { - _months = BokkyPooBahsDateTimeLibrary.diffMonths(fromTimestamp, toTimestamp); - } - function diffDays(uint fromTimestamp, uint toTimestamp) public pure returns (uint _days) { - _days = BokkyPooBahsDateTimeLibrary.diffDays(fromTimestamp, toTimestamp); - } - function diffHours(uint fromTimestamp, uint toTimestamp) public pure returns (uint _hours) { - _hours = BokkyPooBahsDateTimeLibrary.diffHours(fromTimestamp, toTimestamp); - } - function diffMinutes(uint fromTimestamp, uint toTimestamp) public pure returns (uint _minutes) { - _minutes = BokkyPooBahsDateTimeLibrary.diffMinutes(fromTimestamp, toTimestamp); - } - function diffSeconds(uint fromTimestamp, uint toTimestamp) public pure returns (uint _seconds) { - _seconds = BokkyPooBahsDateTimeLibrary.diffSeconds(fromTimestamp, toTimestamp); - } -} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/BokkyPooBahsDateTimeContract_flattened_v1.00.sol b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/BokkyPooBahsDateTimeContract_flattened_v1.00.sol deleted file mode 100644 index 389ba39..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/BokkyPooBahsDateTimeContract_flattened_v1.00.sol +++ /dev/null @@ -1,491 +0,0 @@ -pragma solidity ^0.4.23; - -// ---------------------------------------------------------------------------- -// BokkyPooBah's DateTime Library v1.00 -// -// A gas-efficient Solidity date and time library -// -// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary -// -// Tested date range 1970/01/01 to 2345/12/31 -// -// Conventions: -// Unit | Range | Notes -// :-------- |:-------------:|:----- -// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC -// year | 1970 ... 2345 | -// month | 1 ... 12 | -// day | 1 ... 31 | -// hour | 0 ... 23 | -// minute | 0 ... 59 | -// second | 0 ... 59 | -// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday -// -// -// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018. -// -// GNU Lesser General Public License 3.0 -// https://www.gnu.org/licenses/lgpl-3.0.en.html -// ---------------------------------------------------------------------------- - -library BokkyPooBahsDateTimeLibrary { - - uint constant SECONDS_PER_DAY = 24 * 60 * 60; - uint constant SECONDS_PER_HOUR = 60 * 60; - uint constant SECONDS_PER_MINUTE = 60; - int constant OFFSET19700101 = 2440588; - - uint constant DOW_MON = 1; - uint constant DOW_TUE = 2; - uint constant DOW_WED = 3; - uint constant DOW_THU = 4; - uint constant DOW_FRI = 5; - uint constant DOW_SAT = 6; - uint constant DOW_SUN = 7; - - // ------------------------------------------------------------------------ - // Calculate the number of days from 1970/01/01 to year/month/day using - // the date conversion algorithm from - // http://aa.usno.navy.mil/faq/docs/JD_Formula.php - // and subtracting the offset 2440588 so that 1970/01/01 is day 0 - // - // days = day - // - 32075 - // + 1461 * (year + 4800 + (month - 14) / 12) / 4 - // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 - // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 - // - offset - // ------------------------------------------------------------------------ - function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) { - int _year = int(year); - int _month = int(month); - int _day = int(day); - - int __days = _day - - 32075 - + 1461 * (_year + 4800 + (_month - 14) / 12) / 4 - + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12 - - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4 - - OFFSET19700101; - - _days = uint(__days); - } - - // ------------------------------------------------------------------------ - // Calculate year/month/day from the number of days since 1970/01/01 using - // the date conversion algorithm from - // http://aa.usno.navy.mil/faq/docs/JD_Formula.php - // and adding the offset 2440588 so that 1970/01/01 is day 0 - // - // int L = days + 68569 + offset - // int N = 4 * L / 146097 - // L = L - (146097 * N + 3) / 4 - // year = 4000 * (L + 1) / 1461001 - // L = L - 1461 * year / 4 + 31 - // month = 80 * L / 2447 - // dd = L - 2447 * month / 80 - // L = month / 11 - // month = month + 2 - 12 * L - // year = 100 * (N - 49) + year + L - // ------------------------------------------------------------------------ - function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) { - int __days = int(_days); - - int L = __days + 68569 + OFFSET19700101; - int N = 4 * L / 146097; - L = L - (146097 * N + 3) / 4; - int _year = 4000 * (L + 1) / 1461001; - L = L - 1461 * _year / 4 + 31; - int _month = 80 * L / 2447; - int _day = L - 2447 * _month / 80; - L = _month / 11; - _month = _month + 2 - 12 * L; - _year = 100 * (N - 49) + _year + L; - - year = uint(_year); - month = uint(_month); - day = uint(_day); - } - - function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) { - timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; - } - function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) { - timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second; - } - function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) { - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function timestampToDateTime(uint timestamp) internal pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - uint secs = timestamp % SECONDS_PER_DAY; - hour = secs / SECONDS_PER_HOUR; - secs = secs % SECONDS_PER_HOUR; - minute = secs / SECONDS_PER_MINUTE; - second = secs % SECONDS_PER_MINUTE; - } - - function isLeapYear(uint timestamp) internal pure returns (bool leapYear) { - uint year; - uint month; - uint day; - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - leapYear = _isLeapYear(year); - } - function _isLeapYear(uint year) internal pure returns (bool leapYear) { - leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); - } - function isWeekDay(uint timestamp) internal pure returns (bool weekDay) { - weekDay = getDayOfWeek(timestamp) <= DOW_FRI; - } - function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) { - weekEnd = getDayOfWeek(timestamp) >= DOW_SAT; - } - function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) { - uint year; - uint month; - uint day; - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - daysInMonth = _getDaysInMonth(year, month); - } - function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) { - if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { - daysInMonth = 31; - } else if (month != 2) { - daysInMonth = 30; - } else { - daysInMonth = _isLeapYear(year) ? 29 : 28; - } - } - // 1 = Monday, 7 = Sunday - function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) { - uint _days = timestamp / SECONDS_PER_DAY; - dayOfWeek = (_days + 3) % 7 + 1; - } - - function getYear(uint timestamp) internal pure returns (uint year) { - uint month; - uint day; - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function getMonth(uint timestamp) internal pure returns (uint month) { - uint year; - uint day; - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function getDay(uint timestamp) internal pure returns (uint day) { - uint year; - uint month; - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function getHour(uint timestamp) internal pure returns (uint hour) { - uint secs = timestamp % SECONDS_PER_DAY; - hour = secs / SECONDS_PER_HOUR; - } - function getMinute(uint timestamp) internal pure returns (uint minute) { - uint secs = timestamp % SECONDS_PER_HOUR; - minute = secs / SECONDS_PER_MINUTE; - } - function getSecond(uint timestamp) internal pure returns (uint second) { - second = timestamp % SECONDS_PER_MINUTE; - } - - function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { - uint year; - uint month; - uint day; - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - year += _years; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp >= timestamp); - } - function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { - uint year; - uint month; - uint day; - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - month += _months; - year += (month - 1) / 12; - month = (month - 1) % 12 + 1; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp >= timestamp); - } - function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _days * SECONDS_PER_DAY; - require(newTimestamp >= timestamp); - } - function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _hours * SECONDS_PER_HOUR; - require(newTimestamp >= timestamp); - } - function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE; - require(newTimestamp >= timestamp); - } - function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _seconds; - require(newTimestamp >= timestamp); - } - - function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { - uint year; - uint month; - uint day; - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - year -= _years; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp <= timestamp); - } - function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { - uint year; - uint month; - uint day; - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - uint yearMonth = year * 12 + (month - 1) - _months; - year = yearMonth / 12; - month = yearMonth % 12 + 1; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp <= timestamp); - } - function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _days * SECONDS_PER_DAY; - require(newTimestamp <= timestamp); - } - function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _hours * SECONDS_PER_HOUR; - require(newTimestamp <= timestamp); - } - function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE; - require(newTimestamp <= timestamp); - } - function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _seconds; - require(newTimestamp <= timestamp); - } - - function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) { - require(fromTimestamp <= toTimestamp); - uint fromYear; - uint fromMonth; - uint fromDay; - uint toYear; - uint toMonth; - uint toDay; - (fromYear, fromMonth, fromDay) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); - (toYear, toMonth, toDay) = _daysToDate(toTimestamp / SECONDS_PER_DAY); - _years = toYear - fromYear; - } - function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) { - require(fromTimestamp <= toTimestamp); - uint fromYear; - uint fromMonth; - uint fromDay; - uint toYear; - uint toMonth; - uint toDay; - (fromYear, fromMonth, fromDay) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); - (toYear, toMonth, toDay) = _daysToDate(toTimestamp / SECONDS_PER_DAY); - _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth; - } - function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) { - require(fromTimestamp <= toTimestamp); - _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY; - } - function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) { - require(fromTimestamp <= toTimestamp); - _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR; - } - function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) { - require(fromTimestamp <= toTimestamp); - _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE; - } - function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) { - require(fromTimestamp <= toTimestamp); - _seconds = toTimestamp - fromTimestamp; - } -} - - -// ---------------------------------------------------------------------------- -// BokkyPooBah's DateTime Library v1.00 - Contract Instance -// -// A gas-efficient Solidity date and time library -// -// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary -// -// Tested date range 1970/01/01 to 2345/12/31 -// -// Conventions: -// Unit | Range | Notes -// :-------- |:-------------:|:----- -// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC -// year | 1970 ... 2345 | -// month | 1 ... 12 | -// day | 1 ... 31 | -// hour | 0 ... 23 | -// minute | 0 ... 59 | -// second | 0 ... 59 | -// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday -// -// -// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018. -// -// GNU Lesser General Public License 3.0 -// https://www.gnu.org/licenses/lgpl-3.0.en.html -// ---------------------------------------------------------------------------- - -contract BokkyPooBahsDateTimeContract { - uint public constant SECONDS_PER_DAY = 24 * 60 * 60; - uint public constant SECONDS_PER_HOUR = 60 * 60; - uint public constant SECONDS_PER_MINUTE = 60; - int public constant OFFSET19700101 = 2440588; - - uint public constant DOW_MON = 1; - uint public constant DOW_TUE = 2; - uint public constant DOW_WED = 3; - uint public constant DOW_THU = 4; - uint public constant DOW_FRI = 5; - uint public constant DOW_SAT = 6; - uint public constant DOW_SUN = 7; - - function _now() public view returns (uint timestamp) { - timestamp = now; - } - function _nowDateTime() public view returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { - (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(now); - } - function _daysFromDate(uint year, uint month, uint day) public pure returns (uint _days) { - return BokkyPooBahsDateTimeLibrary._daysFromDate(year, month, day); - } - function _daysToDate(uint _days) public pure returns (uint year, uint month, uint day) { - return BokkyPooBahsDateTimeLibrary._daysToDate(_days); - } - function timestampFromDate(uint year, uint month, uint day) public pure returns (uint timestamp) { - return BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day); - } - function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (uint timestamp) { - return BokkyPooBahsDateTimeLibrary.timestampFromDateTime(year, month, day, hour, minute, second); - } - function timestampToDate(uint timestamp) public pure returns (uint year, uint month, uint day) { - (year, month, day) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); - } - function timestampToDateTime(uint timestamp) public pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { - (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(timestamp); - } - - function isLeapYear(uint timestamp) public pure returns (bool leapYear) { - leapYear = BokkyPooBahsDateTimeLibrary.isLeapYear(timestamp); - } - function _isLeapYear(uint year) public pure returns (bool leapYear) { - leapYear = BokkyPooBahsDateTimeLibrary._isLeapYear(year); - } - function isWeekDay(uint timestamp) public pure returns (bool weekDay) { - weekDay = BokkyPooBahsDateTimeLibrary.isWeekDay(timestamp); - } - function isWeekEnd(uint timestamp) public pure returns (bool weekEnd) { - weekEnd = BokkyPooBahsDateTimeLibrary.isWeekEnd(timestamp); - } - - function getDaysInMonth(uint timestamp) public pure returns (uint daysInMonth) { - daysInMonth = BokkyPooBahsDateTimeLibrary.getDaysInMonth(timestamp); - } - function _getDaysInMonth(uint year, uint month) public pure returns (uint daysInMonth) { - daysInMonth = BokkyPooBahsDateTimeLibrary._getDaysInMonth(year, month); - } - function getDayOfWeek(uint timestamp) public pure returns (uint dayOfWeek) { - dayOfWeek = BokkyPooBahsDateTimeLibrary.getDayOfWeek(timestamp); - } - - function getYear(uint timestamp) public pure returns (uint year) { - year = BokkyPooBahsDateTimeLibrary.getYear(timestamp); - } - function getMonth(uint timestamp) public pure returns (uint month) { - month = BokkyPooBahsDateTimeLibrary.getMonth(timestamp); - } - function getDay(uint timestamp) public pure returns (uint day) { - day = BokkyPooBahsDateTimeLibrary.getDay(timestamp); - } - function getHour(uint timestamp) public pure returns (uint hour) { - hour = BokkyPooBahsDateTimeLibrary.getHour(timestamp); - } - function getMinute(uint timestamp) public pure returns (uint minute) { - minute = BokkyPooBahsDateTimeLibrary.getMinute(timestamp); - } - function getSecond(uint timestamp) public pure returns (uint second) { - second = BokkyPooBahsDateTimeLibrary.getSecond(timestamp); - } - - function addYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addYears(timestamp, _years); - } - function addMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addMonths(timestamp, _months); - } - function addDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addDays(timestamp, _days); - } - function addHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addHours(timestamp, _hours); - } - function addMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addMinutes(timestamp, _minutes); - } - function addSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addSeconds(timestamp, _seconds); - } - - function subYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subYears(timestamp, _years); - } - function subMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subMonths(timestamp, _months); - } - function subDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subDays(timestamp, _days); - } - function subHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subHours(timestamp, _hours); - } - function subMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subMinutes(timestamp, _minutes); - } - function subSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subSeconds(timestamp, _seconds); - } - - function diffYears(uint fromTimestamp, uint toTimestamp) public pure returns (uint _years) { - _years = BokkyPooBahsDateTimeLibrary.diffYears(fromTimestamp, toTimestamp); - } - function diffMonths(uint fromTimestamp, uint toTimestamp) public pure returns (uint _months) { - _months = BokkyPooBahsDateTimeLibrary.diffMonths(fromTimestamp, toTimestamp); - } - function diffDays(uint fromTimestamp, uint toTimestamp) public pure returns (uint _days) { - _days = BokkyPooBahsDateTimeLibrary.diffDays(fromTimestamp, toTimestamp); - } - function diffHours(uint fromTimestamp, uint toTimestamp) public pure returns (uint _hours) { - _hours = BokkyPooBahsDateTimeLibrary.diffHours(fromTimestamp, toTimestamp); - } - function diffMinutes(uint fromTimestamp, uint toTimestamp) public pure returns (uint _minutes) { - _minutes = BokkyPooBahsDateTimeLibrary.diffMinutes(fromTimestamp, toTimestamp); - } - function diffSeconds(uint fromTimestamp, uint toTimestamp) public pure returns (uint _seconds) { - _seconds = BokkyPooBahsDateTimeLibrary.diffSeconds(fromTimestamp, toTimestamp); - } -} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/deployment-v1.00-prerelease.md b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/deployment-v1.00-prerelease.md deleted file mode 100644 index e93cb8a..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/deployment/deployment-v1.00-prerelease.md +++ /dev/null @@ -1,32 +0,0 @@ -# Deployment - -Compiled with Remix with Solidity 0.4.24+commit.e67f0147.Emscripten.clang and optimisation switched on - -
    - -
    - -## Deploy From Remix To Ropsten Via Geth - -```javascript -var bokkypoobahsdatetimecontractContract = web3.eth.contract([{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_hours","type":"uint256"}],"name":"subHours","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"fromTimestamp","type":"uint256"},{"name":"toTimestamp","type":"uint256"}],"name":"diffMinutes","outputs":[{"name":"_minutes","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getDaysInMonth","outputs":[{"name":"daysInMonth","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOW_TUE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"},{"name":"day","type":"uint256"}],"name":"_daysFromDate","outputs":[{"name":"_days","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"},{"name":"day","type":"uint256"}],"name":"timestampFromDate","outputs":[{"name":"timestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getDayOfWeek","outputs":[{"name":"dayOfWeek","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOW_SUN","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"fromTimestamp","type":"uint256"},{"name":"toTimestamp","type":"uint256"}],"name":"diffHours","outputs":[{"name":"_hours","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getHour","outputs":[{"name":"hour","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"}],"name":"_getDaysInMonth","outputs":[{"name":"daysInMonth","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_months","type":"uint256"}],"name":"addMonths","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"isWeekEnd","outputs":[{"name":"weekEnd","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_years","type":"uint256"}],"name":"addYears","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_years","type":"uint256"}],"name":"subYears","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_hours","type":"uint256"}],"name":"addHours","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"SECONDS_PER_HOUR","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"},{"name":"day","type":"uint256"},{"name":"hour","type":"uint256"},{"name":"minute","type":"uint256"},{"name":"second","type":"uint256"}],"name":"timestampFromDateTime","outputs":[{"name":"timestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"fromTimestamp","type":"uint256"},{"name":"toTimestamp","type":"uint256"}],"name":"diffSeconds","outputs":[{"name":"_seconds","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getDay","outputs":[{"name":"day","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_days","type":"uint256"}],"name":"addDays","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"SECONDS_PER_DAY","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"fromTimestamp","type":"uint256"},{"name":"toTimestamp","type":"uint256"}],"name":"diffMonths","outputs":[{"name":"_months","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_minutes","type":"uint256"}],"name":"addMinutes","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getSecond","outputs":[{"name":"second","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOW_WED","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_seconds","type":"uint256"}],"name":"addSeconds","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"_days","type":"uint256"}],"name":"_daysToDate","outputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"},{"name":"day","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"_nowDateTime","outputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"},{"name":"day","type":"uint256"},{"name":"hour","type":"uint256"},{"name":"minute","type":"uint256"},{"name":"second","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getYear","outputs":[{"name":"year","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_minutes","type":"uint256"}],"name":"subMinutes","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getMonth","outputs":[{"name":"month","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"OFFSET19700101","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_months","type":"uint256"}],"name":"subMonths","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"year","type":"uint256"}],"name":"_isLeapYear","outputs":[{"name":"leapYear","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"_now","outputs":[{"name":"timestamp","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"isLeapYear","outputs":[{"name":"leapYear","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_days","type":"uint256"}],"name":"subDays","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOW_SAT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"fromTimestamp","type":"uint256"},{"name":"toTimestamp","type":"uint256"}],"name":"diffDays","outputs":[{"name":"_days","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOW_THU","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOW_FRI","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"isWeekDay","outputs":[{"name":"weekDay","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"timestampToDate","outputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"},{"name":"day","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"SECONDS_PER_MINUTE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"timestampToDateTime","outputs":[{"name":"year","type":"uint256"},{"name":"month","type":"uint256"},{"name":"day","type":"uint256"},{"name":"hour","type":"uint256"},{"name":"minute","type":"uint256"},{"name":"second","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"},{"name":"_seconds","type":"uint256"}],"name":"subSeconds","outputs":[{"name":"newTimestamp","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOW_MON","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"getMinute","outputs":[{"name":"minute","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"fromTimestamp","type":"uint256"},{"name":"toTimestamp","type":"uint256"}],"name":"diffYears","outputs":[{"name":"_years","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"}]); -var bokkypoobahsdatetimecontract = bokkypoobahsdatetimecontractContract.new( - { - from: web3.eth.accounts[1], - data: '0x608060405234801561001057600080fd5b50611091806100206000396000f30060806040526004361061025a5763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041662501553811461025f57806302e98e0d1461028c57806310848ddf146102a7578063126702a0146102bf5780631e0582e9146102d45780631f4f77b2146102f257806322f8a2b81461031057806329441674146103285780632af123b81461033d5780633e239e1a146103585780633f9e0eb7146103705780634355644d1461038b5780634371c465146103a6578063442b8c79146103d2578063444fda82146103ed5780634b321502146104085780634df86126146104235780635e05bd6d1461043857806362fb96971461045f57806365c728401461047a5780637217523c1461049257806374f0314f146104ad5780637be34109146104c257806389a3a00d146104dd5780638aa001fc146104f85780638bbf51b7146105105780638d4a2d391461052557806390059aed146105405780639220d4261461057657806392d66313146105be5780639e524caa146105d6578063a324ad24146105f1578063a3f144ae14610609578063ad203bd41461061e578063b05eb08d14610639578063b3bb8cd414610651578063b8d16dbc14610666578063c7b6fd6a1461067e578063c7edf88c14610699578063c9d34622146106ae578063cfbb9f37146106c9578063d2b50743146106de578063d6582d0d146106f3578063de5101af1461070b578063e955643014610723578063ea1c169014610738578063f615ed5414610750578063f9fd52501461076b578063fa93f88314610780578063ff2258cb14610798575b600080fd5b34801561026b57600080fd5b5061027a6004356024356107b3565b60408051918252519081900360200190f35b34801561029857600080fd5b5061027a6004356024356107c6565b3480156102b357600080fd5b5061027a6004356107d2565b3480156102cb57600080fd5b5061027a6107e3565b3480156102e057600080fd5b5061027a6004356024356044356107e8565b3480156102fe57600080fd5b5061027a6004356024356044356107fd565b34801561031c57600080fd5b5061027a60043561080a565b34801561033457600080fd5b5061027a610815565b34801561034957600080fd5b5061027a60043560243561081a565b34801561036457600080fd5b5061027a600435610826565b34801561037c57600080fd5b5061027a600435602435610831565b34801561039757600080fd5b5061027a60043560243561083d565b3480156103b257600080fd5b506103be600435610849565b604080519115158252519081900360200190f35b3480156103de57600080fd5b5061027a600435602435610854565b3480156103f957600080fd5b5061027a600435602435610860565b34801561041457600080fd5b5061027a60043560243561086c565b34801561042f57600080fd5b5061027a610878565b34801561044457600080fd5b5061027a60043560243560443560643560843560a43561087e565b34801561046b57600080fd5b5061027a600435602435610899565b34801561048657600080fd5b5061027a6004356108a5565b34801561049e57600080fd5b5061027a6004356024356108b0565b3480156104b957600080fd5b5061027a6108bc565b3480156104ce57600080fd5b5061027a6004356024356108c3565b3480156104e957600080fd5b5061027a6004356024356108cf565b34801561050457600080fd5b5061027a6004356108db565b34801561051c57600080fd5b5061027a6108e6565b34801561053157600080fd5b5061027a6004356024356108eb565b34801561054c57600080fd5b506105586004356108f7565b60408051938452602084019290925282820152519081900360600190f35b34801561058257600080fd5b5061058b610912565b604080519687526020870195909552858501939093526060850191909152608084015260a0830152519081900360c00190f35b3480156105ca57600080fd5b5061027a600435610937565b3480156105e257600080fd5b5061027a600435602435610942565b3480156105fd57600080fd5b5061027a60043561094e565b34801561061557600080fd5b5061027a610959565b34801561062a57600080fd5b5061027a600435602435610960565b34801561064557600080fd5b506103be60043561096c565b34801561065d57600080fd5b5061027a610977565b34801561067257600080fd5b506103be60043561097b565b34801561068a57600080fd5b5061027a600435602435610986565b3480156106a557600080fd5b5061027a610992565b3480156106ba57600080fd5b5061027a600435602435610997565b3480156106d557600080fd5b5061027a6109a3565b3480156106ea57600080fd5b5061027a6109a8565b3480156106ff57600080fd5b506103be6004356109ad565b34801561071757600080fd5b506105586004356109b8565b34801561072f57600080fd5b5061027a6109d3565b34801561074457600080fd5b5061058b6004356109d8565b34801561075c57600080fd5b5061027a6004356024356109fe565b34801561077757600080fd5b5061027a610a0a565b34801561078c57600080fd5b5061027a600435610a0f565b3480156107a457600080fd5b5061027a600435602435610a1a565b60006107bf8383610a26565b9392505050565b60006107bf8383610a3a565b60006107dd82610a57565b92915050565b600281565b60006107f5848484610a85565b949350505050565b60006107f5848484610ad9565b60006107dd82610af3565b600781565b60006107bf8383610b06565b60006107dd82610b20565b60006107bf8383610b2e565b60006107bf8383610bb4565b60006107dd82610c2a565b60006107bf8383610c3f565b60006107bf8383610c65565b60006107bf8383610cc0565b610e1081565b600061088e878787878787610cd4565b979650505050505050565b60006107bf8383610cfe565b60006107dd82610d12565b60006107bf8383610d2d565b6201518081565b60006107bf8383610d42565b60006107bf8383610d96565b60006107dd82610da9565b600381565b60006107bf8383610db0565b600080600061090584610dc0565b9250925092509193909250565b60008060008060008061092442610e55565b949b939a50919850965094509092509050565b60006107dd82610e96565b60006107bf8383610eb2565b60006107dd82610ec5565b62253d8c81565b60006107bf8383610ee0565b60006107dd82610f61565b4290565b60006107dd82610f86565b60006107bf8383610fa8565b600681565b60006107bf8383610fbd565b600481565b600581565b60006107dd82610fd8565b60008060006109c684610fed565b9196909550909350915050565b603c81565b6000806000806000806109ea87610e55565b949c939b5091995097509550909350915050565b60006107bf8383610ffe565b600181565b60006107dd8261100e565b60006107bf838361101d565b610e1081028203828111156107dd57600080fd5b600081831115610a4957600080fd5b603c8383035b049392505050565b6000808080610a6b62015180865b04610dc0565b91945092509050610a7c8383610b2e565b95945050505050565b6225bad61960046064600c600d1986018190059687016113248101929092056003028390056112c09092016105b502929092059093016001199582029094039490940161016f029390930591909101030190565b600062015180610aea858585610a85565b02949350505050565b6007620151809091046003010660010190565b600081831115610b1557600080fd5b610e10838303610a4f565b610e10620151809091060490565b60008160011480610b3f5750816003145b80610b4a5750816005145b80610b555750816007145b80610b605750816008145b80610b6b575081600a145b80610b76575081600c145b15610b835750601f6107dd565b60028214610b935750601e6107dd565b610b9c83610f61565b610ba757601c610baa565b601d5b60ff169392505050565b600080808080610bc76201518088610a65565b600c91890160001901828104939093019650910660010193509150610bec8484610b2e565b905080821115610bfa578091505b62015180870662015180610c0f868686610a85565b0201945086851015610c2057600080fd5b5050505092915050565b60006006610c3783610af3565b101592915050565b600080808080610c526201518088610a65565b918801955093509150610bec8484610b2e565b600080808080610c786201518088610a65565b91889003955093509150610c8c8484610b2e565b905080821115610c9a578091505b62015180870662015180610caf868686610a85565b0201945086851115610c2057600080fd5b610e1081028201828110156107dd57600080fd5b600081603c8402610e10860262015180610cef8b8b8b610a85565b02010101979650505050505050565b600081831115610d0d57600080fd5b500390565b60008080610d236201518085610a65565b9695505050505050565b6201518081028201828110156107dd57600080fd5b600080808080808087891115610d5757600080fd5b610d64620151808a610a65565b91975095509350610d786201518089610a65565b50600c97880297909102019590950393909303979650505050505050565b603c81028201828110156107dd57600080fd5b603c900690565b818101828110156107dd57600080fd5b60008080836226496581018280808062023ab1600486020593506004600362023ab1860201059094039362164b09610fa0600187010205925060046105b58402058503601f01945061098f85605002811515610e1857fe5b059150605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b6000808080808080610e6a6201518089610a65565b919a9099919850610e10620151809092068281049850603c929006828104975091909106945092505050565b60008080610ea76201518085610a65565b509095945050505050565b603c81028203828111156107dd57600080fd5b60008080610ed66201518085610a65565b5095945050505050565b60008080808080610ef46201518089610a65565b91965094509250600c808602850188900360001901925082049450600c82066001019350610f228585610b2e565b905080831115610f30578092505b62015180880662015180610f45878787610a85565b0201955087861115610f5657600080fd5b505050505092915050565b600060048206158015610f7657506064820615155b806107dd57505061019090061590565b6000808080610f986201518086610a65565b91945092509050610a7c83610f61565b6201518081028203828111156107dd57600080fd5b600081831115610fcc57600080fd5b62015180838303610a4f565b60006005610fe583610af3565b111592915050565b600080806109c66201518085610a65565b808203828111156107dd57600080fd5b6000610e108206603c81610a4f565b60008080808080808789111561103257600080fd5b61103f620151808a610a65565b919750955093506110536201518089610a65565b505095909503989750505050505050505600a165627a7a72305820d4f1389ffe027f893a43a30bb50d36944b44ec9d5e69c6327987a6ef9e41a1d60029', - gas: '4700000' - }, function (e, contract){ - console.log(e, contract); - if (typeof contract.address !== 'undefined') { - console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash); - } - }) -``` - -``` -INFO [06-04|17:10:54] Submitted contract creation fullhash=0xf1cfcf58e4f9428da80d8c79e299668fb93959177ca400ed8ae18ed46c9fbae2 contract=0x07239Bb079094481bfAAc91cA842426860021Aaa -``` - -Deployment transaction https://ropsten.etherscan.io/tx/0xf1cfcf58e4f9428da80d8c79e299668fb93959177ca400ed8ae18ed46c9fbae2 with 1,181,383 gas used. - -Deployed contract to https://ropsten.etherscan.io/address/0x07239bb079094481bfaac91ca842426860021aaa#code \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/docs/ConvertingBetweenJulianDatesAndGregorianCalendarDates.pdf b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/docs/ConvertingBetweenJulianDatesAndGregorianCalendarDates.pdf deleted file mode 100644 index f079e3155f19e17c33b0dccb8ac3b9de6e881978..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90427 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
    d>-QFfMdh%2YivSU}PL({% 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∨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 Td%FyQojC$yF)>LhNn!mT>MxLN diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/docs/timestampFromDateTime.png b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/docs/timestampFromDateTime.png deleted file mode 100644 index d991890e5b0d98bb40c93c644b87d13d9e5e9ec9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188342 zcmcG#byOT%l<fE4V^Z{0-N$EgDcL_v3gjJ`)wLl2u zHG;+0r{cC&96WDuui@d|_Q})Bbdio^OoZpi&g3eCBSF^)2u&34*aw~kjw4@K^0@Tk z5zr}q;Rr&Z<4aw~dU2Vs&if)xbGE0yhF1BRMA+c!YiXuhMGd9aN1J@B_btXBK%6&lXtvtNXw7Hs@BWX9_ly$J8 za)TX9IGLSh5F@*Gc5R!3?iBq71mlEEO;3}zM-R`4=#=o%)XK)YH%?HM~+uzjx_GBp~avHi^!Uj-jesemNRPR@bk0Gnebq&f0S@+18ZX+}`X|&3e`wB*4#PIDq|gbR)E%MR28o z_IZ^Ao-q=cosBX1cNExVb`kY;5hXezB`qRZAnrceD`}ojgbei8G04wWxFWA5ghaSh zL4#=Cs!tX=rGE1vZoSsorgFqyNX|Hs2y@2Dc4q-|xS_qTsukRS_z> zO^72^!lDnymyYCX5<86cT~9pT!Oh?~4D!V}xwTaBlKM?6!uX!S?YYBSBH}jz#-k|f z63iQ<+z^BLtGU&b@lrPG$UBLrasJWHiy%=kR5^^!2V=W;Umvnd?F7~x>nYD=Js9&h z@Xf(B7x7rrc0b-nw0~#2@aITwn+z}QC8xdt;m&wotapj6$t&7{8fb)Lsk%o^%XJ8h zP35aB_mMna$3^_?GwYov{YYH8lJx8W0RGrd7QN22Li&AkdwWovc!u{x zDGDf^FoYG@`YLCD*qKTWltq=b!ufLf?z8@oez>WMJn44F4u%HeF^HO!)cT<)I@DLK z`!xbfWyen04#K!HqEk@oYPTFIGG?a{|ffKBoKf$K}*dT z!df+o)TI2v7!`s|9B8VFkrMLb3x*wvekV>9#Xj=eFGQ5c#huLtp)x`_o5rT6&rAVL4*@!qC13%7 z9h!8!utVR*@H`4Dk7$A_z;~cWX^q{K%vsbK_k^W7xaS5DBEw5=bHML^2GPR^M)iq^ahP@#LAay}EnlF4+&X zZ!{%(n))xJg`!^Oa~3)jQx`7fbreomr|^RHFgQ{hlC>3um0MNrzR10ERW&O;ncgbV zDt-0MK-;%OS-VjcS2ZWk@QYz?htWfxPdut_w|Yon*94?gt=w64JzOq_$zV!>M~_Fo zR>`$^OLxRdkC8*M+?XRr_uQSt5a6;a%gW5&KCqX7ksPMe?t zYtudt6AT*?ASVF{(grM(Jdy%5*rrgXq^3lRu7+7GsV#RbONZx&eMVwO`qRevDtVyx zk`2dIcsga(0`@0MlY`s?E{PUNn>=g=YzC~z~_GcNd2 z?bP(&=?B@@AIJ(%kB%r?H!f9}5t<}#vrK$VSL5F=xkSA5zI4CDr6k2k#0kTBi^CRZG<=|Apa;%R#udZvywNhB%zxep! zBkIKd@6Qugre&r@{r8}30WnLzi)-d;usPB$Wk7ZgbV;6J9W;Jk@rw*-Etahy2oN1r5+=$(~JWjdg zoS&Xsk%^J9@w7Y(2*!|%Pk2%Gykit=Xc2NF#wKLzJ0sztewj`AIdeKQgq}k!<#!Kn zzRk^)P>;u&sq?m5EllwzRhWA&CNJ;10_U zmM56fLYktb7zcp$+MZY}TDa7{VPOAREzK}Gq}H30o8R7HL8R7O_N-+qVsyDWu!h#Q zD<>>2Y%>hZrKC5jZmz=%{XM~z3!Nq^B~tw8$bM>A=M3u5X=?J18v0bP*pYJlX7saA zigt1U=Xy%k-H)B0gGOj6MO^kqTMc&IE^96mr+aMo+WRa&*|}K2buNp8eOkj>FG?Q` zMcpsvK7xoSeyYxVpK;Tc)8?yuWz_0-u>Dfg z`>$)8B&Vs7k=zUlTXx%*4S0> zsdCk&(qk^&TY6>lv+$Q>YsTKe9{-WaKI<>c%fU;rC((kuNzq&Bkr7vh~_{r z#d%+CVY)%MpP3TsV|pKTnS{?gmWd(ge(%<~!(in%T9|Jn0X3JoQ&!gUSecT@UPsb&QTmBi-(N?Yg zT%+OgXzMSq)uRFI*C$`{tCxoqi=UcT9*LPGDaFc0hM}t?P<_K>Xs*FQS4v<1qpPVz!N@ zj+@R~B_T6MdrlK`M^g(BNS zPEQ_AM;9wDkf5L-7m%Bao0|jv1c$4)gPVyLhl4A_e^m1S)FWfzYUX0&Md& z6H`ZbH&J@}KMnoY&wupO!pr8rTXJyy&tbs_$o1zA7l;$c^eDDqc(2=O$B6zzTz_4K z%S#MHgzLX#FNSfnG9(0l9h5dQDw^;k(w}z&e{(JHKP>-ogr6fWR5^5|1tK6wASlR4 zYI-5=XQ5>p$X@g_i{=stg>t@@|LDeuSP=P!peGJ{KlmfdE{&$0P8Y_lZFK*l^1mJd%HTUmj^dS* zj-~v&E(suUem~*+SG|Wf(1|D8`Akr{&QwJI-;TM7wtwMYibnuRnh=p>18d^riQT^z zYA~fE^1tm1mKw_Y1Rfc-zS_-y^Sb^>6fS)1|DT0Fju}MZXvn_k(H{yl?eW|8K9dXO z;PZW12C|v)>))`y+{a&aeA3}NuB*FVbL~#fDvC&CDBnBwdO89>QH+XSEgo-+KM5-3 zh>5Z{%$k}^z2(RDJ*a;->pCW?PkO<*cg&)7)$DiJybUvYy8VeDcD6NwxmVt3IBOO! z3WI>mTH^g8dyenV#v-2Xx5ZbBG8{1C#UH)O_D1-ZMeJG+8p<0o9fx_WMzOAz!C({g z6ul26RWJ;;I%vqcmH6G9)0pU0Xar4wfZqx-O{9J4K`v}4KVFPH+iNXKJ;$a+Hk25j5X}vENGl^LRXRoYQdB$-UP*j&g z;m}0akfo)q`{H79@9OFC3VOU>J9gqDn8>S@)j?(ZR1= ztYSKDcT17YFf1(h=WL3zkao0kg&x>qD|fGx!q+{2J${bP|46afdOoSRejNkeinni= zV;Viv>V8KB{??Ov)(v?hno>Vh14{R)6o#_V)M?F+{qkIrnxY}9I=^FE$Tlz;!h1x2v@J7%PtW2?WEm&542TbJd<56cLP zlzk9nI_-{m_)zC?>u1HSv)pHLh{&bh|6IRwl^2BmDz_B{i8rudHy156pA zNyn_~zpBR@J*PwYo6Kye{`3RB>-N3S*)Tgww zFrpq_)1J2DQ&tZ9c=Vg3sT>RlR*RGj#?d!@P)3JGV|1ZJ?_r}r&|xf8+%)RLoh z#0*7^tq);=dy_+{4az6}Yc*qGsRybR_T$W|;sPQU(;BPgj{de>eIPw_Ydi^HL%?ZL zjyajrL&AMRERtLwv)D zlFHKHB()?l@^f}$GqwH&pGQ{RD}A#*eGqrGsS|H7!~?1+Ux?qmJ%VeCCuY6v23i}A z@P3tt$OeU_r(XQEJjKpR2(I?HmyfsLN;M`oNzPF%sR9^JE3T3P!e0@9Qi5IlhA3OcxhUh@gNOhxUsZkL$e4B*jJw ze&vf0Y*-o7L*<)!YgvD|B<*|)l@0ILNcx*Y8j@_qf30+1_j+MMhYjP>b5#%|v_vA>XVq@{4Vif7lS-Qo;8`=fVXy0Da#vr$dmk9nCdFDYj_~bB6=J#UM}nQKk?>U?1PSbv{cSfd$ytj?q>0A5<(Z_w9@CST5Ga!!n#dx=&X7922Jk2-vHYzjZmtNmHXaRF4u zYa66VrXQo{o`p=St7Y8ui$CIv-A=^M5O2_~NC;zau##G{cJI38+`XR;xPedG)W8zW zh#mo@F!q$Why+X~k)jdfgxs*;xf;#0*E@rm*n0Yatk=i~nY`FHKQ)3WCsPo5Ocieh zO=4hsQB^yNMz@~=A zbtB)DL_p%#4UO&P2b$C38$m+yssNj|ssl7scBz`K$wS-uC(Z1<;@)Smvba$kByj3km2=6XhGy#9ZO^Saqlevh6K;%_w6C^}*WRYrrQhu(_dW>y z-RMw7gX_z*WGN=}7@?fjYAV(;)cq$XpO$43%x>-hHzr!@`66>&ohMT{H`}lS`rE@c zU#X${+05flZ*v+X^R~wPpD0MEv-lb=mKZ3z+UA;^%d1L9aZ2l9sS{;02K?KGRqqwO zCe}+o(#oIEA<&Ph5=q9vPU=iZLTS-ZLCjnx>e9eh#(bRBJbAcMqG!VCtY&s!+rvuc8q@FjL^$#kBg8(K}PpY!&K5~2l5X^WscSnLu zT@E!yNGa_**UgqP5@~v7q`b8ybTxY^6;@(12uMlJY9#?Scb9yCB&di#xLs1CO(In; zI6_5d;s^T-_>J|i;uz9mSxpO~@U=fjRot^sZVej3rQa{?P3^srh)|LInNKyfghN9_ z)>~^HSlon(8e`L#8E)jWQ@Fs~sj>AfG!r1OL(;&ZA5IJ#Q@+X~M2}A97cHkPj-+FU z%Bmcr=!Yr+otrZv`2vmQu>>i!hwV`WWdq8e*TL3GxB*pghI%&H03RL)`#Ev8#f3x+)kWK`;gi(D$&W2#tnFjA5hQ(kp!bM^byZpvG0wA%VboXr@g#oz{+S2fS@7XpwatmLP|JE~11^ZzxmZOA+!J38 zw)S`S#AJe5^Q263Mc?{PJr?rr#))IRYXr|Zxt~nvNca{$eK2GiRdzMvzvexds>^lT zZ}9qD|8CVhCuK`m?$x+(+ zAk72~Szxf`@HAWM2aw2?ZOKMWw8vP5u!^HSiZ3sMLz{QC)80Y*NO8fcw$5X7)p|p( z<&fnFHQCXS&B12|t%1tPDi~yy{(BIj)A@wF)zO1$vzN>1>34>BJ03ja#iFZ^PPmBV z#MUxOSwcThkMheA%yt-PZeDYVU!oO9EMIk8$!-Z@DWOBka%wzDZ>()MLInXj#@`0b ziJ06k;acc1XV(V&X&m5sg;d)e zq5_>TIgmq9EP8CL*fcw3NU>mfPJniST!S8#;lgKUX?#d$slF7G!k>BoA!*2QKusH( z>ku*{8H|2^L4caEM4{V$bw6sTixzwr@vvuvY|_*iDx}=4mXm2M7tQnnQb}Uqre>Z} zJPZW+yXx@+&)l|E$fOl_qHaDHR^$7-w& zm~8ma{WbGCH;YzNaz!ZM{<=(%J?t5BTC3vGVxaTG(p3jPhNugw6_7;0>8y1myZwTWCpOmi^UY8yn0>V6e)zjtn#C^W4(!1F+HlE&?Z7C!NTrl`lX6KM83@$N(}E z9g|&zYdyo%!2_9c%KX=EQ^f=C-b|7+c( z+{+7C%{*gnApQO#byD@D9JpY2W3FSdIoHh6oyYXO8f%uFmP?>$*a+s{5-A#s+l5iQ zCwMWqIg|yEBb~?1#MnM>1>~YRWU=(W4{SC+3Ra`!b}v}=(erbeCpHZ(*fPb_be<%S zCEp~$Mhi6nik0oK@(MJmnCJLkMh&>+k%s3)PJIgv8F);E-oFqE!5*H|Bn{O5d}!8% z8zUNuySSd)O6xN0R#?c4giJaGtT9i)EJq_fEpd`j;t#7=L2&|JQiRc@|8M!hw!=o^g*sZiaE@g5nHgU9Vv6IyrOVy1DSGdQ4iZFZx;K{p?;$6Z`q+Lb4!g_JV((_<7aSOQE4rF zGDeLQe{B{BbJkl}8VUtN&c zVGnQ8t;k-h6(r_gBJ&9%*3Qc~41XG6oRmYhiWj|%)I(;@a#L^pwH1mDzV4=3%OVdA z`K^C0-N&eClW|a_9LlySqdKPGhk|P@xZi%YR83u0C2{i`mFCb#Qh-hJg&E@m86y9I zKispU#oeCWK#flvEQ+MgYv(0D#m(F_fa8!{s|8620$LDpA5o7T+6h zd=~#B-(}me2-zzLKGO@(le5+Po`Rx6hg*^pUNSJiYOnCa(=I9v1+fXKKba)pLS-3_ zqOe`H%{5n2_@!Uk91q}|VZgfSYd_dPgwA})i8*+;p3hUM%$VBvz8F3VxN7}c{`FX+ zNGYnwX9C4MPR>~2?(JRF{oT~xtuMrAxaP8xBVWe__NHsI5p1knWuB$lqMPYWrjP)- zhURTWC{lD>9K2S#s#gkB)#ylh)J)2F|q&_<3XpF6oVky16K90bzSqx@3->6 zq;v%Qb#717R4-O>tap)^P!J-@)bk+ZO{IE2W50#y9TW9DS%$S!FJ-`n$tCytgyJ)0#zUNTgSpVUV2cz@{t*8LJMADQywT#kR758>5!TVs{-bY6RU}7 z6g92Ys(=orc*|&(%JCAHfgPRWm+_em=m8v4IsuFYtfk-^Ivl_jl!!4A?Ka4Q`|292 z`l$o%!Z_MATK3w4^jd!{G1}fG4WfQPHC>cY9DBa?4F9>RT&Nh3djgQV{88Oiy=kGL z^XQvBG1PSBrTA{G1-T%sKGLRyFNlc@#=S818}pob7xrN}kuz8el<98t%v;l^jfZc- z(Bkq_bqKF!hpdw) zof`x*1cXpop0MDiYXK77aMdf=A&%(I@jw@vrd7%*_Ar$0bZZ{1jTR;A;XanS_V?~Tv<|A<${y;GucQCw zS7$$k`xLAa(h*=u--0vIXvirz?|%AeC^5(lW45YfQ-^^D58JQeao-tCnQj02u<`qD zSeK!@ZYN(KYesE#E{#E7DG{$P)?e&Bn836B{93QRFt&C?Thz0JB{MrZomPHRjs+=+ zJQo9{Hg%+f#iDJ%;PS^s1~ZnoGNv?;-8k5FlB^E`;XN_iqe-oBo!9EId5dgy8pJpW)WTI73DulC{Nt<$TJ@Nr3{4RV!483WqrOhsG<@Y@Vn=RC=5MekaBH zh)CuaY=M*fC{)(Z=k8Cj=}=)@Xh12NCrM8=?M;l}&ctvJq#xLF}-|MU24HcR^be+pONiOuo zW866coirk~}XGT(ysnUwX=D(6s>t3Lj(y6gK>b zrIlYdRr@tgyzj3IILF(i4UL%eU^a;vDVFX0@N2f}*Gv?VO9Hi&z%2!NkTsn|9li~= zT*Qoc{Yaj39e^goXf4l(p2c*SfopP6=DW$r9IL@@OgEC?ph@v#(32*hQUK^V5EPnM zv!Y@jeuLFz?IR)Kd{VdG9-4dpYT@at3UB=vWj(Tj5z2x02wEnOKM#!F_UAA?l!_lC zMt9?ii>xI+vZZsCL0hiz8XR&OcIG^1M9R|Kboww5%f;^utpXZXo5rH++!8_^>s;p( z48*HvjHz^Z8wr$|4gh1R zC{ItWXbp&RvQivEP5RKff9*Bh*)>-Fl!fQeVShr*1H_)VyTTY6!4Y=Y4$fTqI&4+6 zY8W;bFAiGqicq(-kKen0N|~@q8$R&ItDqQ>QAp_Sqmkn)a;4oQk;_mn zA_2+bBha0%J_1lQf#o3GWCn;~M8j}W7v3=X+nzGk_Nfm zT+^viob`I9UqHEWwHeJ3(b!fr#V*R|U*kfuj{6vEC$@DA3y#xf^`Q7JR$Il|kpuVsYqBojR zJQo@>mgQdtKX`vV09A~OkIPB?Hdk0@^a?Q;teb9vn8AvfChgjMRE9W2K89k4PW|HM zvukwEbBkKW$g{uu{=-be&kh=HgZ22_i+(XsP-S82-Z(7u(vTWG5biY!v3?#CfTd;x zz%Bey=%@2Y*{PuZaWplMQA|ACWpAuLK&<@<2i_)xY zC?^cF5qji3F#5G-cC@nK)Q!Dv5J)LPXJ~W3b%)Ec{UEs@!1}Ps_tAhn z!~WDw$7&?)v&$_MtuKu2vE7^o${;^#3u52S_|P4K>2ljiNYzuY7V!(R?SIuY50q7U zLt%)8yXfMv?cAvJA>bYU1`8BIP2j5Ikm4=x=l-30QT>2!EfJU(V-f^SmV8;ON3ZLz3iZCl1eJ!0FS%e>?2NyW-pKgPZFGUkmEch|5K8xoHK06DkD$$c_mInPQr>$S18 z4(W7>AYU)~85VZYw}cWSf^uk(q`*n@%!E6hEsSC?>uISQzeYK3w zopMqo)07!&!}VIqRf?TTcga5KT+lXv^IsUuaq_v#jGcwks#-%Cbidn2d*~P5tkbWT6yQTXD5kk=C)4^8zJs8$i z?USNF={Q+4gylVe%b_E>Sp_c)!X1R^xfw&l&&57BIT++79`~{4 zaDFTt`)3ZmT>O?;D&Aa?`fb)24wlWL>@8~bEO1&fLM;m!VUGhNRH!{p*#F&8$dYAfI5 zDgovvfCs!d@4YuaPf$|XOjZE5<#Pt{?MFwMPeZ;Cbzw&^ej${r*0Va;h9J51x?TTb|-E4h)_7CB)Dz&Smtimt|*S&3i&(MXW6)ccYpA2%3M;KJvY zjQ{PLK?himb~Da{jZ1x(yhWpQk~n7zM^xgq*(kuGk;Rz0KA%$gId;w7!VnQ}no=-~ zQ5qK5T+XUdbpA1k1}HaSDH+LNxh6|uK={_{M3iVNQthkbY<^>m!lD96`6orrX2vDS ze9ZCBDiERMG4AtD3_5ZW7#q!{@QJCVMM>e-vRW90jL)J9%B2>mw`eZj7j2&MaPVPr zCt>OfP?XaU$Y%3r_8aB2&Qmk8V!(T4;e$HEqON0R4UM+qV2ni<^95TiyB^-sbU99g z()yJ2*8B<^`INb6Z5$;t(k4K!m#Nryj2V|59e(s5lL3J=3l18w1PeIqwbR_cqvsi& zdBnOXi`pxix6%bJ=uGrdC9~wr&(aCJmf&!N^P*bQM0pYtWIXSXOnRXIWog;-evX?} zg*Mr(@B*@6@!Nyl(#la=#?O23;8q+{&c-MKhwx#Bq%;dh&eRzS7Q?sr%YHk%@nf>HJ$xdM=@I^xZi_royLd-HZNIquKv3`iN zwJxbsiMi-;M$fjqLH{<-!+PP(t~|7r44i&m>2Q)bPUi`bNY{OyXH%i2dr=k=e?N0D z^+r);o?OaVsguswvRqXT9#81wpP_AjWjvAjr33DFj*`s~pULnu!!dnGt{^Hm0(<^F zwEx#Cj;iN7G8jx*ll)<3C0y0~zNz_-{jvZfUBsVNn!7pidN;bvWx%AAv7`?54g!|& zInN2I0ndhO^EVa);%LPA_dynVG2I{b>O=|K?3!;hOkx#k*M9mQ(a==1SVke`v}cjP zZF|M0=_JD=E>S3PGA&vWrV@45^vEW5V{(u=nTM>2lZr~U9%>pkn#TH8hNFW~XPIMW zxSW|Z5=C=&%+m(5I2l=*OGsjWlwDdgO!P-`bZeRm1bh}JP-Pxg2x&EJSPr=BY)4+fI8#nX0kp#dAMNLp6Z_;lkte~H&-J8$cP5Kp z-i9VTtF=@0@u8IbF~FQd`EXR#jRW^jK90LdDTWc;stzI)umdiXg?0+8Eiq6TcMd!5 z4nZpK_v6TD)#l?iMm0Pc1D*A7XL1H3DFRGj4)6d;B7S^0@kNmEta{^OhGx(EyZ}%+ zN(G*MJi)D?CCRc$9^GQ-&d`hT#Wa)hZP}>+7S7)aUUrNKitX1!b=Bj$^k##Oqi2fDBKY`q=4Qo2(E?_(5Lt@ zu#*d_e()H<7`vRa%9+LOVK4N{Y(V2$Dxt9b_R){7Cm*XoURXjAy@+X<_Ea3s0$f*s z-!7EF7MRz`W=%V=!nawAGoL>bOljtN@)%A|LA!}SRJ3U4GxuNiOx4a$wN#beL_Je?nXSzm(>>VL-VFD)9YDHFQ$>PY`*Q&kjPWuxA91Y#d+eTHIGZUKkdF3oXh* zaCc_CgIbJnf`4ZWUzEkVNWtKah=VDR#ukme{1&+@OmDs3ps(eu)qo4sH-1Q(W8+Er z+JrJlU9yb|?Rs>T6348H&xF%lS>nqxP{l&Mn%g<}AB;IhxKn}|(fmum4ADlNSJrB9 zbgDhN{Vj&kq=+7Yx#zO5*n5A2SGgD`Uq(V^Mt`U5quFQAbkse!KVP$g-E#Rb-NFNY z%0c}x*%X%nH|N9*-T)izl3<)uRCpIpY!U%L%z1$@k&)DBuj zP2zq*`UJo*#*qT*8|%y`m9XXuTimiJv*9IX`0H&k4Qo0j8Otc?-ZU!NH=iW)1zXVW zwpyrnx53`4GOvGt4h5_ArSY>o4+kSjKVB0;GX=2)u4998)rz>k>_e7xlYZ`sWcx!lR zD5OdnhTXBfg|e8jA}s)zvId0F&Eqmv;dx2b&Cw%rJ)qHnWCTK!t+L#;??=S@L{MI( zlpT+>6dx5R8vPJZ%n_?A%!*1VjRB;7ICX*`Ab!4mzG}nf;isCZjSRzRJ{P^xr2f%( zJXHrSJb{y5lTPlp?=<{gYj|d&D>@ZE%!0&9@DOOT!nZ9Ylq?LP2S{*IwD zUL*;r8BOQ$-8?VSC&6rd^sFXb3ea(h+FoxL@LYT)-cgw9(_vv)E|1_eV4;XM+~Q6j zDlTkyX0Bs$lRdSxIOV!SbT(4;In2mm&DEs%Aln+$b=L9M3PHu}Hi5^&aPPFM9%_>f zXS?!9G<28GL+PGPaeBrhY#ADBE3nC$c)_Ze9F!fT0W5foou1QJs=XReR)g~q}r@}nZ^+%4rhgR@L0gC zR~}z)q#wN!!;xSf=eWQpJT!5DiyN6Rv`Z#NCWCL7N=bfmP(c6?lzzxD09x?z8+pR5 zC4Ea`Gx;0S9w(e5I0z1DaS1I5(NWb^+dUqmR4kr-TFdkD-a=u#6h4|RIgFd&-~FU9 z1nkqGht?ItQ6Bz>>1|K^b>NRUI%8dmFWJ8p&-du17LeZ-6EZ8ubw@U&qw?V>d**8; zg@-gN&$eIAvwcXI1vWogL(h~A$;|LhKc?5|!ecUhFZwcg$2P9u(azxpbmbE>(-90z z76vTcSWiCeB@IL}hvaCnDDBTbB?k7CP-`9CFio#$l@1VWdh*_`pW(t&F6SN$* z?3wys-S6HkmtIf-1aybSm4W^-;M2N4ztks96hjo?+8sd)&e>X1>;qEg^I#8!d zDEDO?EHMhG4oB;y}LZF+i`$+F+L%TK%aYYlD-#L z^O|pcfe#!klB32cpj6_RR-36J**+93?cv^yLz{uHgFfsc@?ilKEN)iK7h;Enol00S zgr@`k637a~G^ZF0ZEpewn2T+iyOE13i3;2XxlD54^sRLYwk5r10AU)b#`{6$d6@!5 zpU@CE)$o-77QzvnNM8gdrx~V)jeD>&a9>z~yU+7uLMg-p{BrJG%8c5(A%!D&s3Lf( z9xz#xR&RAN(i7t{F{B1$g*wDtq+E*4u(_0U7PdDze)MffW?w((?B-Ml9#1nIw7niG zVL1>we3-D@E3kT?m&uI*0PwlpcbNxE=M8_f(7s*$b`l6G{UEM3%j7OaI#_aoK&STO zQJsXwMA1mn7CX~g{EvmMsXc!yjVn4mYWt%)`W%1>GSs4~Om3?!OXn=6-^&X zjyt8z%(79Z>gE#=x_DOqR?Gj_id+;-S=gNg@;wl1cYj&=Vh5fW(Z`d&<}Xnm^1J=} zGr{(iW14>`|GzQxXxhIz`bIv%^>CS~VHgy%|CwHo#rJ@(-J*j&(e(VZ-s#E9ZT`2@ zz_i6J;U{4)kHyOQzfvR+Of?Dk6X#m}$W{TMu&a`Ua9a!}jFwteP$E_i zx%h=oy)$~kDxN=WyCi`NY=?_cGxRbvq zScq91x(FSqTh86$HY^mKKq%ZD7dfO8z9^Bv5myyiL_~M*(*fp)AMcF(jh~b z^Ay6@~x6B zD3T@sPCCr(d(L;ma}jiR5+>H;#i{?G_)bF{jiDg3zMgA19@$#eORR6cZm1fUeDT)N zM+1Sa>Si*vgHSGxviVDm287e=@oxDE2c9DE?hkXR^P!{=2FHMCW^}ExCV}t`gU;&J z=XZvJ>>bx@Vapdm$o#+`bBdF3wDVm{zDHF3fE)dBl~9*sibpt_+W&Cq7;u*HW|Lyy zkH2InjmN5wPcQl1d^ZMLnd*6S>fKxZUxfX-ry!60+1V5vft5hI-eNLNcLk&SG4Lb7 zAEPobFh|f9J^(Cz`+6;t<=J|BmyZcoV5U^gxY_>zkHxbZcgtoQfFPEIOvWj!qQoWL_J{I20? z60ABVNMgKg_CxZfQ!0hN&z?FFy64!I-$B=c+n()xAg=T_b!8>==$FPHm^3E7>gwv9wM8 zu=faYm0rDUYk59ZlT`a|v&OZ~{@cRKf-G2-kH3uo$yabK259|gwy1KpPd5awOz|EB z;h;%x!!?LC6FPYg&j5$xw}b0uT zJm-Fcxm)aRf2!YKQV477{)c&hRnAGQqaQ=2`;4wGqyzpn%je48PGG#6bi924KV5+n zgDRJsnbSA_0ROjsYrvI1pA+3HnkpJ^I95UtMu^Pu-KK@%5B~;tzYi zYVYW)@1a~&F$&+1*$Gfy!E=qgyvppJf{(*PGN+1Fj)-v0U}RRA_*V$+V(cq4Wj88t zG=Swh+3O`_|9yG!TebJDwJ99k<5H7#oKya7u}Pj@s8DzZ7574%F(paJ6ni;Q#iN9L=AS zi|D7Opr8hux_SBZeFeJCd9J3iM4AVXy-jCKuKpWN#g{@*{18+yCL~ zEQ8{TqAi^u0fL9%4haNr+}(q_yG!GipusHxfnGr*RA7%5AR?Zqh& zZ}pr#@&O!sCZ9htj(Y0_K*wLE;;9I^iiPFab(G!93}d|#Tj-1Td3Je3DDf;5d`v>z z+pZ3LaIl=jyny?Op-)h|@lZLQ;2L73h!u$55@yE#Yu^@j{r2Tcf9Y{p*ezmCUbOVg zjlvCOnFHfi_0I0O4n_K!P+;ME^GA3t3cWsmGuODa&nt%jXO73N5s`zM9vXtbp?@u_ ze_lnS4B()ORb)=Qg`b2MUYw*n^a)yYJqHzFA(|CTY3T377J<~xx)~1iW@2btC4}U+>Fv}MumK_au&(6?$>MC zeFSU{u@MhDF}6Em(l?Kba~%ZZ9~o%&WHKiBMW350V)2Xu>yfnU`d|HAKyDw%zG?os zKq6e+dCsB?I8Wrs-#FjC zTtC8b>SCrW$GuJlzawU>vsL{VjkSgbT9W)Gv?tWX~oJEdWPEdMu(#_5wV zN_`XtjmdDEk$x`XUnHkM!R9Rp-gj2>cdnz;BD%US&hpZ)z&nwAarvxAj`cWH)XG$_ z&D5VHQ^`h@I~uLiUsk&a;kxXfP@>e&w~bRkKI4ox>)1T*6tUuK!0MM=duw{rN|uLe=lAK2PUfG*_s~8bAXTZyPx_ zX6dv2;P=JGx1Zb_`t~D%abZFg5`Vq^A`kCsqi*y0(NP0u$w|W;gcvvwrO%?3wv%t> zjep44q@EdALx2mAuzR zSA3!mYDA660}xT|`)uL#qy)%fWRli5Fp`21B;;X+>MZ zml`b#0aAuZQGSb$D2>p&B=ycv@di?i!6l%GC%zjmOf@C}Uv}(Bvqh&iEe4eGb*BhW zf%igq6do+*c&&!s$c!NU;m?cdOM9Qy*j*_XuTczW%Z1FK1aM~I&jr_Uc!c+5EnvLe zIxWcPi<-`PP%@weM>f8wax`{ryIOQW+z|F*?{je$v!?@eZATNGIObAhAg?<~Z0rP5?kAdLe)A;OL(A;M=X z_GIx#GBWQ@T@JKm0b? zB#k9r;{IkT7zk*<$DG<&SNGC?S}XC^gZ9Qug!AA}O~rP-M43+w+h5spI({EphXAOD z|IGprNNVi*8Jt0?7uOX#(cDWy=bg`=)gRen8=!Mrkr0*R)feSGJCHVKev~(sh6qwC z^sI&LmU^Mjdd`Z*7RI8Xx*lY7_oY^u$W3t+?)_miPw%x&QO*|9>)rWB|A27cmCP== z-(pB!TQyKg=y<2~DhAHh;cbxmYr-<1zvA@yl;jh{D2!Tk?S^7_kY?HsKAVVQ4oR4L zJg9dR+%2SY|h_6*t;{Ij)KG!(epRUVR+1V z14`Y);4H4^V5?v;a?-c{YpX+b4^z&=bEPXneZ<21S7vFxUK*+V#)_<8A*BB4{-oz` z;X^}Lw=E}HE4LP76$YuBN+YIwM(r=JqNi~!NbWvd#q90deL5i1@f>@{f;C>t`nQTv z!Jf4Fi?==9&rE*zn!WGs-hwto53ziLm4PQyEUsc1>=Sl7v_YVV%OTjuugLt~O?Dl ze{A&`M@s5Td`;#?ijeiD-b_#R{=h~wCbbZ*_{}u~*n!^Z zfjEUJg31G$lOcykPB}Y&8aB9v=DgJ*on>X5Y_&cO`fA{)x*b_p?;=OsQHIUKFRl3t zHT=s^QAJ7YuL$jl=X%(flsC&wKK;|joM8{oGfrW0U2ETz6Mi`QLt2ax15+$7Y96*C zGmkzE!Do>Flr*^o0{o!BljiC3_kKx(Vr^~$)G4T+y-nkhE}7eFMyt@x0}8^1Rfx$} z<<4NK+(F<{T`=AjGtCHJei55_f})UWM&ONFCNg>-fl3ze&e6wI>o`=2J}L>E|xfU-02`(1T|IGU*ldRToPD>kLIjT;aRi$QowhYZ`B@e zH`3Sbr+##*vMQw6hl|^kmOQ}WY_LMR#pVOwDpnNx02KEtO(;IpQ+IXVGl3jWS5~}Y zHH~u~-Jr7(quqi#_%!|MYh&h>RcWVFpvJ2!L)0>=rJQL3FbRKsR1&8R!NQd*Davtd zRvO8^6y%r9Z|Xg3r82(g>;w1lq&&>6BiRJ12yXs%)Z03wbSnpmManzvl9421wT`{! zVr#{j95>IC%EW=StbEw?dmMdZ=}OEniMVxrHdxhsS*7#CO>t zE%w*@5H%4gnAu&I$flpPrHnBz4JD%gH5e?hH+Nqo1j^+rM4lq;OGRDkE7cA&5~_(b zS8D~t940w35P#P1^{(vuI#PtK2;?e!I`&%g@6jiUs?R};WsDDQ%e5#Y4DU{8n6D$T zM6Ul1m`cO2?c7FYh*x_Rn}Q)uC$)6+k(5P*8KjPuxJ4yS=`YOI_kQ69ggGetn5!@p z9nxnR>M`ePNgG?DrzaZpH?S_$XR^*j;BR&j!2!K}fPa*T;K9*}ZwYPN`B;suWW1S*ANQe2OWk+g zJ}NH5E=9|9R+!%EQ1)(7mJ*Twmn-BV$ZeCoV^jyNbus=2%2* z{ms8|fj5%AD&e3z;O@VHD=&5qj5Ul1j?iA{Ewb*T!>x%FNA@q!Lupqo*viGlDL`36 ze6mmCxr4eW>@sHX;M@F4duzJF=s=uhE8_g1{umP-F(sdlUkXCd80QrTvYZ2XfJcM=U&ILw+%7O2*9k^0DK0Fd-O& z$$F!I;x%!EZhd*BL6LP}tY~d~df)}ySKrurfm7yc67-8D5n@q2P7a%5sXNK}VZ&kl zw_gQjdn=4|IgbHT{(_60kX8Wal}p;!1~kjLau7m#h;5D*ynykX(2lE80fsew?}WXz zIWljjSaXMThB)zxJ*(d@la|~xf6R<)IFtj!366~Q>w=Iy+cnR>)wt*|_fyc{s2j|> z2kl)AUewHa2Wl7Q^KuYbyJc143;Cnvui~w(gdgztyz1$+NLuLa%t_)Ndvv?b+M}nUC~_4HO06=G&;q z{*vz3=AUM?=3%XgKZ{B1c1!(J?OZD+J6(<>CPz(He%l=eO^lwU0<~)w#vXsekG=e? ztGjOrSU4huUxR}#4FXmF<0bQ5SinI93pZ+8LXRi{v@iyF@69w#Uc#T~#q?+{K!9pt zK<_qH?>Gisd)3Mc=sN{DGkQ;`Ax_z87}I8jPV1*NArW1$iewFgc=wyml-Jlo(>>D^ zJB+$kg$rg&mA;Aw7#{kFxT4+yx_M%1B)hM^qVeK)buEXS_5`DbqbPdfBJwB3Dsl|0 zU=6q_Onq<5)=#PhZFykgy}B{8C?2K5Yt^!A;)$8~5OnHHXbRB{&l{u}bUI5eBEW`x z&xJsCOxI8~B1UB<@{LImc!W(6&NX7qdB6~yK^BSwnH3J(L2O0Rp>V3N3ihQa3NWsI zP}qd)^;*O~y$hb+eh%dl-cZxDR6KUHx{2H)>S3boCYP`^bjjCG%*-E1(e+S0O+k$a z9Lr|c^*3Tcv{Mw#Ok;+E>i#w28-j;9UpXyRpasFN_TqRXvx@2KZ3A29xteUXfHw{; z-7QQMt#VSRo+>mQ6>q7mKamnji<;^*UJ|ItT2qtQhvxas1@j96(wO4eRVc>IbYcG{ zqICy%q69xN(+AN4Unf))+F%h|m7dZZdr1kRnXg82>rQB#2&mTT%s}u6zjMgB{~dV8 z^kd1NB*!i2L}_*^xS=GfTJvue4X2M`4Mkkp9YXuAvWRYGd8rWd@f%V_k7#e~}QO6f5JS?cw#IjN#H)2`G zh0DsLdb_8gLP?5rM4~u##frcg#7wuDJY`qTrb!uoy&(oaBf?Ttj| z*t^y=!I^4dxFXr}%EY z8l2IYF&hQ0_Jp&=ARh0nw(HoHXN0%~l#eYGX!TdKFkMPNjZ+iezK>9ty!_m>f&EEw zFq@gxJa!Riy9)T^HWSI><`TQoDY7o7H7)E-dkWD?*H}%QhhJ z4lT-Z31Q?}O=qL;+%@%iwY|~e zPlSmA&!`}B;~1{!)Wc8v2@_TW;&fTAE(=)JLMy^{Fl1R2hGIYtUx~)0)%l<57wAR z%v@|hVF|y2k<2-^rCJEAL3ex$cJvz_RAH{svyntribJ4T)2=A>SA0i{QawR<-56^~ z(Oim~RmF6&4`ad$6+JGYzan#EK{ueR{Lx&@VFuAO4b`&bL{^HE9)y(Up@Kg=U|3|= zXFv>{{4Js~oFp^QjZ}drIZFY;XxHTIQvT-nf*rZ*MYp_t`CwjH{-}kKUlQT#_;Qow zN*;wW*Y7>appdOMw^y4CquSLav3=mb;DeQ6)`{I+>`8Y`HO7^>g1Tu+5Xtju>S z2Fc4jndZMUxo4l~X;yA%NwQ9-lJ!g(uICY37Dh^8R^5$RWs@Js%X*jvF$S2wVXDfuhA>9`$9k z%kSjwtKXW<>E~>`Y41UtB?_qGxQ8iUDGFNul8=}<4Pbq;C%_P$X4$2UA7Uvu{c&ZD ztly0Nb_S?S{KiE*8UL7nzts|+ualp5zB5}SXay7oW(h>N;Owi|Pq7WCLW6_|ZIIn* zr;}1aICn1!g!|8l@?AlWZvJ6+i9}lOHS;Lx{d^4%#;81-ubLh&a5orBnm8ImOqtIZqBmJnrL($pxMsFiqhD1;1@28UjN|oi9Ur1+UboN zFH7y^*rJ#+rV2{f22OJ>`rx<|T9g`Tpb7T&bfaFWr!7mnpeGlWyLe{X`?j<|_aIWA zJ@3mPN_*d-w-y05%o|NhjqR8;6@_6n|6aBGgmj&`{Yk8|D_^&#yoPDN$&Tbd z{i9xymJ+#)!Ofs_^tM<(eY^vU3qOy=!VmMm;32 zq*h>@wHx*Kyq{jr83qVk8f0dlWs_C|CbKQxEz$*N>C=ljh&=h=ve!a@9=P}jQp!(h&HqU=P}5wrTV!{-GK&I!kMC3hF1&Om9<&pS~+H`>XrOm_EdTQog%IAWthmWqFb{3i=m0b@1*#YuHST1&@xQ_&EtAiO{`XhS=tgms5{Cz zlkgrc_o-sCGl^gyJB^^_PEoF>s%`pr(znsXWr4LHpUL*lQ(3&R_NOZc@4xpY+*N+w zd)s+ZZ9q@5?Pj;V%oSL;nj~_B3U!0&lFIBZ-tYO&aBOr&napbSzqfYd7IC!=60vI# zm6tti+`EkcG32rItg)sSoTO71k3XSO?xUI<|3c(IFm*N6x?B7Ra1y!2 z$(Q%8wfHlq-`}t~1lrxWb>fZ%QDgX*OqsPBk~J?#iZGn7u6Of&&6ShDa=^?xBB}ep z){H)ve_Dj)r1ek+Q4zVZq%?l%;FPX8d7lXHtavC4hza=d@Vi?IwTOHFep#U4gV51z zzLXQ>EyZ;M3X3Cgj0?S@(VHr13+?~>;|FX44V{cc7qUj`^a2B^q;sJtH{Isw8?9Ik zyQ*(j-H87F34PuWi_Wr{bTZg(Mn?&4Rn)HXeSpijDwmzH26I!!Zw$O z;EKr!EGV6E8&xdTSsa9Hs=-hO%q-6+dkIsF2hRJX9nA)gY3L(`QkxzIK?*UQuDbSdb9&( zu1V-Wpk^P;zegw;Fc#EqB?o3p)3x*DxU!5q_#Zs25(Zdvc$_|7CZe_6W}c9>>$k_zdka_YXK z_+DJP2Hl!Tnc6V)A3Ui#XN4XyJjix`van8J@Lp^A zUHtP}Qn*I1M{V0^5nx4k-p_M-Qg3f@+s)joEFs_Vb$a=%(YyvM^iwWLaZ^P&^f418 zL2I!=C|`u>%52*jm2~|=JxQFCS79Zn5sa?WrxxenVNM*^5(>wKvgSdR8KFY|40d$G zsN%@zzDK%iF7k8DvDRxKyILvlA&&r4@RWkEc% zO~3J?u#z?}ande0ZqK#kw~6+=c6dt%HHLNjq`uVAXM3U2r6w(vMx_tRcaHk>O51Fi zJjWk9HGI|i*36dTJG59hA2Y8Y8v-3$hh?)=}-L z1G^dU)mfjNgEL{xRI+jy)!Q^o1L@ojmV8g^Rt9_Hv;?+azY=q@9dry|%=Wn)A&kl< z{^D-NAt+*xMR53t>Fr=Wh*jV>40Z!0hcMQEC~h3)RsPvsU?Vvi}3&qJed6wLeuA^plPNChQbXLh-HkO(bETK7H_q*~+GqMvBdSIqhN=F0@WyRgRlsFd* zbKJ;7|1*@qw>tL|x5ZpBJi^S@h1}-p`HNC6>sg610)?eMp62gUb?!eH4Gjf(s@%U*vtZj9l2T|&8XViVWX4_BN7c#BMum)O1(@3pTCs=Ve z>nU=_ToX`ZU6nQ);%VfG74BsVmuAf>b1Lh9E(hCWxKP|*i^@XR>Lj^BCw$ar+1y=q zz<64xDi7RQos;d1f0WNFU}$m6*Nk5u8C|t{BRsa6Vn3-*v(7j@FDd10^U0yn*Unqo z+je(O0tESLzl?)UxtnC)9A&{x`y5tcWdHCX8$sb3E8DY31Wn4|&Tp$ud*9DcBMk30 zd~scK;~(B+aH+1G*tI96-wqw(u^0Adr~ag-i(H6U=U)a3cmhu}0h(o)LGhL3 zEwB~+iMh>QX8=f9hrie3I{=iIe}P|58Io_Yvc)HoxCa(-OxJfX3BMt{~eU;Waxt`%i!0w>Sx6AdZHFA=w3XK>pOgEiwaYBvnIJvfpg}-Z};2lj# zY1IY2xz3Z;`wS@^Wbu@p8uBA6}~7 zBjv%!pN4Mg&(TQap_EJo;kc2nJ{)GS4{~^fIv3YQL*0{xRmLctQr0pvNVJH`EA6*C z4F$ATrez{-@1;fF%Z-5>!*KV>7g;?GdqbV|IyE6zdJRgNy`q=Js|9*Ck9D6mSNb#x zV@XU}hzuhV-WDqgXz!wEol-m9jLz5;do5VrQ!5>UK~d5<^>-w2d3bGuKA}%)rGI4q z_me!8A_SARN16RNfECgD=4IWHb%J(o$I>>?qhDlVb~wxzJk|WipEzI(bw9z}n`YHS zk>0n<>;x9C&-CNo$Z_ln$XTyiVp#m9LC-gzf_ReIAj^;zZ8n2Y{HcK+3mD;*o9*Bd5u zO9Pxm0i_0`GZkyPKWN|8!Z-~&E>`q02P@+$!d+S^l7JX$F<4-EwH4^?G-OS31M2g> zbn|46`k}{ATp><{=4PKHDfTg}IeNA3R$WLMEU_=YMIb8!FJ)TP(Ztt+)=KPuS0+#!92)VMMy)`8OK z>G88Bxz}#iBSiRPZ6*JH)#jFOZ6y{r5k&lE+i{%!n1dY3({1%q&!<+-Dz89(>UKL6 zBau7?Q-J}|WEF}!QZlIX7VMUXW0R#0SOd%kM| zp0OQ5RJO@U&eC}8;5+iHNE@17j5H+jT?B>GQ^#oR7<#1FwkG0^FHG(h=NeT?T;4>r zIpVm8c_koKLH4X`d*B#K%!}0E7=bm-rDwW0(YJO5)ci17O4NQD;$>R})PG&*G#H+B zXG2U)4SMtAF2{&BW*Ys%*f7YwOE6YAJBBb6u>jfP4h0>b&X3Mxf_u&o?;Pfw^=g)P zQj;`Sgs)J-sQUy3dkC#ChAZps4{+YgV6fNXG`@}@?s@6;;5Kyx*&7wpMNAAu;l1!{ z26{p%H#gL^(f6r_Z(QlILNOp9MZ&pF;(E`}Jj$ARWCNZb@qGy30+%0u0O{F_z@7PI zKHjDK!;Sd0?YSJ$JsuVfStb#YG}PpT8sk&Q0Q!iJqkDa+WV7Nu09{k6kY$0mhAhbI z&tj6{NXdWA=9(wVo9RX4KZAvzRMd~XMn$4#1q|~!)K87_RoD#ifaa{xGC7o8hO@r)8EG~JGLTtdAEwu_8#@Rg;N3>SIrkDoU8K*$ zyd3v+!MMCoDZ5U$ALLyxevNX7?p@dk@^Y?%8uw3LSjk2z`{sAdj}(#cE1lQ@Hkq8v z^&VaGVR>?P8CCiu^slNzB{#!P-*!`*R=f;yYNPqwHpq@tryiws+nh}OHfk`=Nkhle zd1%hX^~*h`0=jIPM@&qqMos>tx0T2?DD2^2a?cvIb1DZF3o8i%rb%8;n0~?TJu)ke zAloKV?OAcLvf%mMGv@gm_57u~(7s)yNDm1Lb>u9v65M;8hAh?#jyr2e4{?#G;Owvy zhWW@CeTVC_Sho{}UE2X(xQ_hM$W!dG5#Ct#*uo0T?vD<1lV1kPXP*E_|2G7Qv*0_x zO1~;nqQT{Dw@k;%PCO{;5S6GRLcCoP)dkU&dh=#S&@ATYyw<@Mjy)SV^3U+ze=|Xr zF`DnHmNNf<=A?=<5VvZn_1(ADbKll%tDnkkGZY)$D3q}zuomu@|Dd%ZFs{p2q>kgp z8Ve5?4x|o7K|&G)20-Yalt{L6fg0=OWMg!RveBX^p*!InOBx(%HVd*Jo@RFd3iI#$ ziu;(iOxLzgA-SQSLrMY<9l)y=4-#!C2A9Gk1`dZgN41*9f>)Y)iEqALvIWcI`e*wk zP(qF7SH*VIl=XGla!mlcdCH+D(>ciGjP{KlK2a2%BLFKx&U?FD;UvzekIQyc793 zXN(IUXcVm>g@NiOrVjf#7p+;GZIudr!sOqnM5kMX3&Jwr3s%jgb28W%J%%ea?cTW% zZi0$5fX)yo6h&j2Ez_LqZ4b-$U~n>Y zI+`bQtdp!kJegVo32C!5k0=90!Tq?Xh^QRttxwi}5apy}^>=(hDzQAcqmYRgjb zPwePc%Z<{rzu4A6EKRUFQw#TZb%&ZxyPT=AS+5ix-~o8q8q=|YDP39el=bK&Js#Cb zUrjKG%6AKWK$5_Wgr*%EKlOe`9Md;Z1*e68gB~1#T%ibBE0%v6y2KkA3P)CIf{uR2 z+K9#HfG@H>GB0?=oWyc?=R;n9nyHCi>ieR~dYE%oOyB%nM)__cyDahPB1#OQn=DgL zp(P;LG>p9^)@@DwsWDKC96K_kcDFgjbRiqAxtvDx6UffcOugc52uuUT*2nkpq`gqO zg(`pR9WcJ`*9}_WN6MmMs!7Vs_B;jDay3?Vfn>Vh0@t9~yqD8a^KxXazi?froOnH3 zT&zYi%KU#_VHS4FWO~`1&hg$Q4HAc5*+v&>;#1zn5Lw!hUHwx{@9aY9eh)*&wcv|Q zNK!v6@6PBPN8Kq>Hif`ciw+IS1Ogdi@l9!P)((MMoLDDZjEnjbNmztMk1@7sKu)DeW6_U3%{9+bAn5Mv-zM2>b@MHUrm3d7ZBo*E*;kDDGw?Ai^8jbs=bht z(0G;Carkgw}a-FF?Y90L3 zmQbtQemyFuHl353rDG|aWZpoy)o>SDzch)j{6N;0(&}Rln<2?#6tQd0zb&ipq*6AJ zDNGP4Y*FW~ZfR9KS6G#p>X}7xz{LuJBRQNn+REsZv8+$w^e1M&wJtmj2jX5 zKRU1Aux5y#tcs3KiY_k63UB@wFG9)3)Bj@iCe5PJv_V4g}t+8hrxXJLE>0=i?3OeoQcRm zD3kIrn5Z$n1PU2s_~GK1ef>vm$HqS9FFPTq{bQAp^4GxVi1dKQoM#idQ1YDDKzq&K zKMvJD*K?F{^qiT;^n4PmKSC_?Vz zmXfAXFz>Or!oGZ^%1}=+ZKS?HFj+)Lx^gVz`wC-VQ~*)i`KB4wp$px|)1B7nLSxFw zdXSz9M$MymsLap4xI$=$`eov;-W`Tan|y0gx`$Aib9U{jsWIv%v}yUKkh<2~tp73_ zdb_=e6(hRn@NtuP?WI0>sU7a(i;+T(ZYS0_N9Mw;l%mwfaPilVn=9W5jzJ%H0^`#( zS~Xtq4x1J}(Lkl^sowKAKrt6tFLU0|hnW!-!4&RkETx1E{8z#Oz_2B}w~u<1rEe)o zT;(S`O*#obmaY9nf>ev_I5O_4SfeSc50@qv@)skd>&^Mg%r59*5Um8)P!HV;8mu$> zFr&X{79!+1421rKue7jqwqCv@KQ$14w>n=y>yboIbiY3+?+7RVO8*}~AyWk^roa}P ztVb)AeE52u6I8TM364ChiGWT-3kgNkK(&5bY+@!LH&9xO`N}X+1Wf!>+JfR-aN|oB zCz#j=pvXP$$9_U><-=dW6nV1=`Ztv`z!u9_X+wn0=U4{>Yv>wVfkUEg^xlDsa_)1INg;1AiY@MNW z#GX%*rMCGOZKw@#)dyTE-%)pJ&;PoYTe1vD5JXTp`xaDjbT4i2-Y{^+D(gnr`-8ky zlZt^z3ujYZs+ouqT5R*aig$nE>LqC<#qF2(FxYhxLE%HuKRQqOC9^E1@;ASFb^AXP zf?clI~_R6k73G4LZ*e7Q@e|!^QtU`2qh`4-jAvvU5T~B9a6xE26L1vY7RDT-d z#s46V((dR3G8Y;?B?aW`7Sv&~k$F9-U5I*PV3X@+AM>m}NUr-Ojeli#_cjpDjB=nS zRhbaHO zS!BFPQ|_Xr-NV zmz_#H>1(?eqXqA-C!TgOQn@nENP zWSm(fuU{bf=>t6iPu9oWI1J6j0_oL!(Yo~1M%^s8aZ$VDU*g1NkhB*%d+KJov07+4 z^d^$sY!>8!@qKM&o>4DUH&CxN$z?OH0B}>jGVVu-js7?`D=g1Mf;3f`NFI%*71JZ} z;+@i%=~#o}_5_g)Y;e|zR=?L}LhB89vQr@0jH+V}VBy~rQAwwoyI-l=}-APyA13~v@{z%LD#>9%0N^BrjG|hdNb0j zY?-dU%QwqVG2+neK|Ij#x!7;|=8s1}b>gc4y&g~>N4TA6PuRRx)QRocI2KW$sioH< zp0`FS$6$e{#XSaT0otK#imGItoZp=$HeA>kq4#=~jp=&SH(_Qc@DpaeE z9ASAe+Px>T5pe%@?Z4JXT^9P09;}D^o4B`W7g1WX&5c{4g6K z*@4QCXaP;t&DGXBh~31_-Je5?w-j^bGti_k?+Glmujw1-`ukmV(=w2V*`2-b`ni-8Wp=KV zVvBk316I$Oc;pi4tn?U3VqJ-0=EC z`G5CZV6cQwF1y@1Q`&>mw)>7V9owbmUE2x`V(M{vHnv6QM9Eoy9z=Oz@ftp*pR8Zr zX1Lq>o)F6BA|NnFt8Q;5g=yJT;!OYizgz$@Gz9a;+{50%HRagG?o z=2ML>Vk~lXk9e1al>v5WP+U%=h+yLL3Epkctfx4XNAkrr*&5xoS!tOl7AL`LH`b>) z^|db%eOJNO%gqUECr#A^+D2A}Y~BGv|CZZNMvqrWy%y}!Yi0-(E^i;J14W6)_|DgA zx?>2joj>(3Rt{x6wRpZ@@jJ})ZbBBO^gG@IxZ=M3PdTL7SfWoeA%|k+6obn$kh&vb%B+TeB0G2Sz9{%gFS?9a~x7?*9|!Hx)rho9kMpD$Cqsh#Ao z64$+m;2tKF6;6+kK|lEOXT7&iiuJ@;!%s>K7ACBEW=F2^U^2yG*Bz>226uqG)qmGK zK_~Np<|XE$V;b9Lz#N&`8Lmcg%DaJt-mK{Y(xL@Q5{A8XF34;YsJ4b@p3CS z*BdE%|Db;suz|3BcG!(Z2MBGT0UJ>qT|XZ2IKB1fepQ?KX;-4JdK*6cEpW@5eHKop zr+$1k`*ba+jqXs*Pi;SJI5+wIW_!B7N5q$fa@NqoFOBD+#RWEZX=ke?d(cDp+GDh1`o#XU;H#s%HQM*iw>hAfx&q{DL?{BW_KY5*EzkR-z z!=gksnb3z7kYc!g157s(Ce%7x8pJILenG-l!U#Wb#G}~d49;>A)Jkq|ru;t?2~#tv zE{;*Rt)4%880z%0re-ohO03?6E;@!rc(mx8tUaZU%TEI<@0Vlx7(N!S#RSc5om94Q zZG*^Ln4)@8eGh77Zx;fwX^}uZedL@c*3IryVOu>Vz$n2w_!naAsr%=^CYM=;5Al^K zihexpO9kcl5bfd3!9?1=+ixd||JG>!t_7GMMZ&9iW^-D5Vo$$&#>(yP@WKd>mRn0a zvFT9asGtrw(ELL8o2}G-@1yp0Rdflo$XgkW2wy_^;eZW667Q=H+sR&LGVkB=K2jYm zzKQoU?5PU(T6W^E-PEbSoh?(sAQIwZIZv&I3d7bNdl;~co7koJHVRbU zm1XzT=-0jHE60$xVUqt=M49}`3%3#{)7Z~pBECW?0(Z``xwHrvs`HtO;B|BKoET$% z&+X0s%RCvyHJ$j)z3rtuft&ZzTT4RYsqV6UHs*xa96V`Y+HUuz6!FTVd|P==VP; z)D;H~7-e}5TWS`H6rilhnRp#;>%wZ~uQ0Q-ybX&yaTk|QE}j42W&6}^yO|(~U<>gH z+Fy`)Zf2N8^~xfrTWTzSR-d@*SjT<1DE@CqS^pp4W!xDR1DMZ+fOmBB2MDer{+r8H z3K`_Az>aE`2@a7;%a__muGCD=OQPCF5xo|Vl{LHAJaP#YvmLw#X5humMgzR5MxQ`s z#tLc-gq#p8fs$0Jh!Dl+$qf2}S7VfgrvSvV&o^kC;}(E+@aGaF5QI|ES zy5R#FPe_tFFbLqInj>#_n{R)glrHS+bZxKjf%c`MAYo-{Ws@NzS@UZ2&!et2!GGJ3 z>nz`OVZLL(eS099PIoam`DwLH8@s$xfE99CEUOQL=&7CCY!2X_{;bgHnsGEYHwm(%U*d>1PQ#81r~Q* z*UCSE2iQRSzo-^tJNh^XOjXj7CqQ$v=+7BMNA zd~|UBrT3mVAZy{Q?dusLMZqfvJ9L zzhB-}5j8G+E_LZQ`Yj{sq(AC~_}}6+{|h%}M+J$XfC}Zyz%vXaj0V+>=RWXi48idG zx_wW>Q4DhF1@7Hy2%HP8+U-M%Nab(@WmnghMc+JChmoqwv*8^!M{r;_NUJXWn_Sq+uN|jG6 z@@cY_x<2_4*j8SB_v^4}4swY1?!hLTd>z!O+@=GSFg0jPR=YE4^3tdoJX$@R6`4|= zs;|j82hDvW|7Y3eIY#OHG=fROH&}T;d>ZDXkNXlA=YRNovBxbbj&}z--mM|nBJ*v$ zzPp8~ehDt6;i_)E_&Uwcq5b+aFc@6ryxI}=K)2~wH%J!{KoUxV9*F_$idAg@eQkxp z_h9XL_~zB)of9&(4Un1k0LCOGNdFrKqIBa~z<@I8s+oE5fI(jOO`)rK3nzf)a(UXr z?8IxGCFojI;iRkKKnD zSeI5$<=bVVMh5*)ACE{emM{pzVb;nLxGC#-Anghu-|zCxVT<1XMNR^annTYkPUKj3 zxB?g_8}I;3eRTth7_z>(+X4)aS!bOi?6Q?t8(ksRz&HR2I-J)Sb(%3 zf?&|yA>Axeq$QPZkW{)`x;q4%*bt3B$n0=g*tXCON9s7TWlA?Ay9(Cq*4LSoXQztk5WdkJ)iIhx>G z#lituIOl^IMS&$mmtk?FGpFlDu)o%+(DjFx4|rcklM2|TgE5nBs5976b**F&PU>*{ zFPR1kIgy9cq8DJrdp59#EP;cg^>bJ1H_k5RufTxeYUoH#NqLkC!TF|(wa;18R#y2Y z4>cvi|M9O-DqTealYqNMz#WX%eYy-hNryS0PgR1r?Utpg!Ft`di21m%20BS?w&#ld zRT$OUFR%8zZBE`CHKu98#uP=5mNEMZYzHB*8qnjVv1Dew;UPZ*mWl+}P1}0aq8rz5 z24Beiatj=s?o#FA;&e4TOZE5Mx9{{E8M`{`G2bD>sMON`#y*EWrf8Wb{E++qcw6w1 zwlDnfKz}1wesk$}5M$uoLHIpRZAEnl!1(6xV4^VRjJ6u}x?Tde{c3kBpXN8v+kXz| zl06l5WBkc{)eGU{m9Ba)w5tW}Q9ER(Vr&-79@`ldxv&&!A2Rk8;zdj_0;kVUW*+bs zPeq`=(YF%gwmwMm7PBEkEDgVq`OzUVAB2?nWn&tr8po>7f}5jJLQCycDarU+S;%U( zy@hCt27v_=bj+#lB(XSMfL><@L*Qel-#fk15KNH3e81;ud+xl(HbbtV@wRe)qIkjR zBuUr%#nzZ(@K4Z3N$%#>V(aof5@FYpw2gO349vFuU^Z52<;;Sme7rIn$2S5zO}k9R zM4ld*G>f9z%g149kMI6px8F<&p%T~r^9!BXJx6<@m3<=1+V(wk;UV#t*=wxwa$CO(j&{hKu&K6)s<(eA zg7G9V8Z^j}$*bMV8k4QD+=%M&GmtTv1?i{7_&p>!8Wz{r-%d2;r~>T`8*KYIyJ|p7 z3`j37LrB4iM$<-#SSDV*LQ~J@Zi8zZt;VIXKN$JbG3RkOpkp)* zrW2HZG_U_{m12Z6Z+Q8w2}`K=W~yy=NBp$W%NcR`|Lz6g`;O)}eK0JBNV}?}Ld=lr z`cdd~(f6uloon#r$A!8HEeqCFHFZIE^_SgL+}_^i>FyVEUs6(v#}5a%Rg*L=r>Z|) z)P3(nqVO0dx9_HUArVf_Jtogx%Uo2``b=oYdtGq(4it3p+TR^q2gDv15cS9#cbZ5H zb`a`r56tzmCjRJHWn*ptIe#5L{hJc~wprlDXbHGXa4sE#al9koW-54%fmG`rfv(37 z+v3+*EsA@2koi0d3HvY!-}*PlFDEzEu6>06Ve%s;ufHL++#`8)p)Wd^o$< z8fq9HM~@!+zaPWy=(k_HG=F^yN`ZPpI3 zfb5~$NMwtt-q%oeG5xT1En#>!w)e;}u_80rrHn(TKUU^|!CBI7G4A;4{QC*4(+^Kf zte0$8VWUDSXrd-o2o&Xh`}{Ue9`9`wNF}{i(oapD?%P|hhA^EeZt`8MkWI4$9oH#l zx#T=kN~!vH`K(V(LmBXq6G(?2zMmVAxrDP}~kvIkq+%~8vc>AV7F9QWT_!L^I+Peg5&2WY0 zzYxR>Jm3o@gF!%uS?&xaeiam_r4Ghc%;Ct8y>M2dJA-po$P5TnBvrMYVni0BIDVJN zx?8uW8}JwuSeRrPS4%R1|9D-@_`&NBCrpe1J2G+%CDOtc6$NtRKb>Hppo(qRY_i-9 zT9@q>zG~eXJEohq?Uwu`7V)S_%LM3` z-7avyTtK}6?F%w<3{t-S;u%rqz^i%FG*7a_S&oH4ptm>qxdR7*(3!m8igTH@3lsuP z0P~aB8M86j^V;ahimUI==QNC+_MF|`9hUEekSi7)?!rafZA$eM5XQm!Fb7>azqPR_t8%v^W3}G~q()(%RMLRH9wIwLEunQ5UB}yy$gV>KYys zF7f@V#XHifVMP8(GAr_DpY_A}-_s1FBm@(vt8i5{;Zh;t-2Jif7L9G6#nvXko$oSC z6}P0fWk6Fyr=J?B^d2)AeQxDG(4lp#)w5;PR19GW+43#uDVHgD$Mj2r z!yv?z$s&=x>9TB&>AMX7N+>r$IL2H;sU2`Io#E^-aYQ#*ipwl$IXVlv@@>~S^_jlF zuTzmLf8cg~27~+d>xXYHDu8JzkEBR~<>F4hp44&(O9J_5RCDvkzbz&miZX27VdJFI zjcXsYP;H}o6X#S=_1^-;Au|X%YA_R8e7&c+_S5#$G04%!Tu$U2JQR9V`xzOcU(^LW zea~yC&B>bTqq*uG1VzpIuY>KuH#jbC$I090Rhl#CmV}l$DJCCDxmJ<*+kSqdu-C5} zsJlLz)U5}O*4!KzS+WZnQ#k_*TG2MdzXUvXC(!PqxQ+E20E}RB5x{FL&dbXXYn|l= z4v0a$+Hs>h+=o};h!8&LR*GdyMk9Ppz*e_GEy@}9jLCf?Bk)|i=j^q>B=Fw9!>ZK{ zg6U>?#^hI4JV8bJF3_+J#SI7VZahJe-7{mAC#hi8h5HGJBI@xnJnbal zXROBShcn@-F9E5KXu( zjdW@lEaILW|`Eh(P(Ra zWZ^R1;=?cg8&L64p#q*&@ax22{hd2R6ie$L3#T79KO^zF3!$Kx3wi{cId}CqvskSD z>3Q!P&%LO~U~_n~c@~N>*Gg9y#p22OhgAu@b;wUWT*5+lfDEZ%N5UXcVtcql_`3oG zKl`vrib*KMed=9jN2ZRceXj|670-dt=pn_%fNmj^&)*tVECf$4a;QD{Y`vqOX7x>! z__NE0f7oDP3B;J;W*D_{me$w(j>`GP-l_$$hj?#=JKvr=pBi#|w~?UmpZ%|2=|=l}kV=7_er z0h*QZ*fgt=Y!aAn!~YEOz*jmNBjDQC+3$R|{Qd8!pCcgvQ1}PiSG7(*HL6^hhzHig z>EfKZ&$a&W&A_Rf34#YC7WGE!|M7{LC4$o10Js)l#szdC8iIT&(_x|3?FyrhD8VQAy-MP8N7GLH^mEnIFYPg&R(19oD=Svg+ z@rlnm)f+lY0th(@IgY)6O`3?OR+HD2;D@{9%)i~eUkU<41_(NXY7cNvSEM5z?0_l| z-;dl_6e6=b;AVxt_bVh30Y=pY*ta?qJbD3-d|(F;tUqPPentt0yT+b3S0|s$UA86$ zK)9*Jo5XPfkKHbD0?>(spB@lG*C|jcNPFDkn`mMorOJVZ=g+K{^#kJoUhmYi%gQHNOG4-wL zr2tX|r$OoIePBpyS*xZDKC@T>Laz0swoBpX=Eu1gDw%0m!q1N0{2kK6s;MsISQJ`4BZB79U zzyumMoFr_WF@%$8(AP5`GmA%Hn*P_(3>%|RHdC%U@+e7m>!*^f_x)QT7D>R5Y;v`W z!h0J&lk?M{h7}bIxV;WY4_wnl6)VS5nGVTk-^7e|zo%&|;erD=pgZY6BS02+0jBu# zp{k}*%e3jmPIcPnLlKtFe**qjfs=bRE11A@?>ch?(I|~gtsNX>1YNc36HF3&wB2_q zF<;~+NXmRKdnpo=inp{8DT!$Z8dXQid;!kE1!f))nwc9N@OyKBT`e3F6oeh5CfWEx z7mQkqN&+p+=YWu`zyU;Wmaam;_ZrZO>HQl@S*3p?#LJ?UkMo&oH4@8@43Yd_2-^lK zIM(qDf|=>*2F+q1v}2kBk^ZkkSg}M-)AzE99#4Oj4iKs|jCeG`AZL0ieAvIDt(D^T z{nIXRik(5?CW%zY*)qpT%F;`|yXAH8;nIZVXqK$Mk!_(0YagTB{k{mRs&Abk%0U9~ z?O74dpz8tn@s5hNld@3O!?>6UW0_MWw?UR;xGyAh&`tBmyZ%92uh^}+tK*p~-a2?W zne?T-w*K5xPL~dMw6pWF@fg)9ZVKfk&;G5hC9~TWFzbK;R|#a09GA zng<&QO+GrTaD|6ETnOxaE6*i-b9w~;3g}=}1R_qLrIHEbs+RZF(KStz?I;=Z_!=mO z*bv(Ogokh>>-n7B+~-uyTCc@NK+FTpuru^W(bt-L3c^3ybDVmV&9z%IUW$-IU?6^m z4GJI1^8=LSTyS$FGq4y}8vm6lGMCzBR;@%uogCZFm%h5Rs2~4CyNM~cVg(w6^6@{@ ztwvI;7X!Cbx3Vn9@n2fp8oqG|=fFLiSbBi2Dz8rU?MI)?50Hl2gEJ2bBpZZ^;CK)Q zF;^Bg4E(nX;4r?08$DEqX37V8cX0zA6R5X`5phz_u3{_LTBy9s0 z3oL0vgU7zS7(T%Z5s-Bv8|4*#+H3zgKf}W%b&|=fEy8w{&QEh@`ocZ z%5arH+wq0>@$+tRB`Q5S|9x%{KEzgZiZ7DzzE+~AY0tB&o~xoHIcuM}Ntof7tz1%I zT|EJK*M&WGtTHvrH^}$Kf-E-Hp_qeDKa;g`wc=bBJgd`u&4F80Rd5OdU!BdG2T>=+ zFS4R3##tRG?b7u0m96@UqF=p^`j2NZ9(L;v)8~f`&m&*w1}ZB|?S3X@Nm2VP>i7lm z35o%=g0#2>85hj!>v-l&WEza$;|O#iS~URPP6yNiEi1pOBv4Dbvb=2t`>8oTLRJ@z zxSkO=*IXhOPw`@61Er@Dr4aX=x69y#M76f{6^_w|Kmq)gs3uR4=ipD3#XIKAm zLw$;*Z;jmL%uURgmcUe*xr2mRU_uZR`+A`oRq0`bgEcgR7GTmn6%wV3)aA zlQ07bOaqYEB3Ggf_al%BqEvgnIE~J4xi22wV)YHwK)udA>?^@b!-yuFB+bBAd|4oI zS$d}Ugpev2WtUZNsYO_1)hAMTz844erE>x2BL4&#$d488y#AaWb4R4qN&R8k(;?z_ zPa3cwL|T*W9hgt723zP}ZoGeU(>DP^&9UR9*zwQB_M zWa_8YmEHbul;A$7Ib5q_A3A>{cXmx;vRnq8HoTCm@!+5Jf~?rV7`~ z7JGuH%#sozdOa1QaGXSEFaaE9LTjdixUC>8SOhT`9`Qa>k{XQdI7A4k_05z_h4`Q9 zH7&nme%DSQ^pLF7z`**x;8KEU;G0PQC;sWaL_SWToLqfa%S#_ZWOtW{>b{HZYk&kw z5Z6}^QF^7UU_C1C-jJDk6Lj)VeNWGT$#~w~LPx=Nt8Kp>Pw~`(N-nyrM(a+$s1xv? zX6T!Qfm&#&R2h-}NAlPt-W*d|n_J+#rdl1o?+baG|wP3QSNn)wyOPJ_);N-~Q~ ztqn22`*?eTpvI-dcER(c7R)AVy^%+Sc#zT1Ql>|vs*?}!Z3=cRe-9a4x2Gr$k^{q@ zGhA?#zbE%J(65LbjlaTVMq<&8)p0Z5du_G9*wSNmUG3CvT8qyekX=BAU35I_ph#Hv zv~6da%%T6i+u%#m0j6Mq5(+SWFv7a1>M1$tt{hjHeRNrO23sj@B6K~WEi2Kak>)Sa z365;jlCDu{TMnp=Y1Jcu)J#c6V%)9g(5bnGTbX>$QF&A!ec{6YxN>6UczVy#2_Tio zmDu*(3=@-A=STUEV`F}gmwsKo@nm?6OU=i8N8vqvjv52cMHKnXQt38BKkyHB4~InA z?Qh4@t*XiJbgd=8XeypB5}}za88oTWACl~bXjh-<3t%qw78tUmyd=LQ2wVd`zm5@p zix!<4b4NgluV_Uo3UpmI>dXP)9@TGM1McEW=uCTvo9sj>$3X`tk?jOu#{JUHOGjP+ z^}4v=HZnU(fz6{tl-C()CT1%Vss5cO8xBP*nJby?s7w{2DkC$QxW<7pov4LxI*k$Z= zttrFvzJy5tq?AJne5M8i1&ZjA;Z4aeSNE=EE}DP`)&=j@?td9DA*rv!>Qw{ROpVG| zczu|}T1?c>gxm#sq5 zA+0bBxF;(B(q`W)!)OV%Us9oE9TwNqvTFJ&Gwq~zQC9GQ1tYfj%lYSOYJI6qFvWLs z&d=|nd_wemgXRRlWv7E^TGezgj9x*^N&T9Gw#EhEjqD8(YsC0>`5)nH#&uH0D#{F+ z8*Ki<{dfG0OWg@?AA_k1$)82qYL*1gzJa^k=oIgl92xqbj8z@#Z9jtP$V$}8`}SsS z!y?N6LKRHlp;rKJY%)zCrjC~1NY4%MkKE!6ozK_ebmz$dMNelRS>~u*v;uwUqzy}S z8=DvznE)A0)G#Beme#L(EMcPm4aq~li|fADCyyUJ)ZYA z`@NMZai`)t&o#J1PY%ibA^$ETBeHk)Wz+fB;#Pz6+Ru5W(ns`?u2+6X$)ULm|Iyq) zj%{q}xYVkI!oay+N%UG_8x#LfQ|g~7pvPlBU2bn*1BDRVeV&p|47mu56r*z5AN zRXm8RpP?K?fB04~ega7KtbIsZiV~OJ4)Wn3OK#vN9esd8VC6e*)mLPi^9s-g`qs9?}=qJ^ElnyD$h+4B$GiZ=&NQ&Gp0p` zc}_y7zlu8YOR_lp_;LnyLO4eSL3@JJ(i^}(Ik-Wg4xd&w^1cCMN51TLw?+#DORv7x z?-XaTL8@pxm>w}$qXM+dD(whl(}v-x>uZvh#0@O(Q^|EeVX-D zD&LNx?gxfO{Ed7L7a*FUaYklLWK2k4T5;bqj7}0Nn^;pi|8JX%4M(`p3sIMW?rogs zeKjvxiXiTY{Mc8xi(Y6QM-QX`7}(XK1s}+fYZX6>=V)q)nzGTdHG0cf6#r^b5sap9gn|BT-ir%>A8x%3P>aaRqGnN$9sH zUf##$X|*8Yo$b=!C2MEI^MYp%BeMJnlS+-4VDzldx@GG`+3Z(0DW@qM7rxX=m*3BxmCLTX%%bNXG@oHM*&8Y6Lr< z75)p|;z0urUdr=V{lvZ;zD}T*&Oxa_2F-jG_d5!zz;LLvFm;(0a3r0Bba4YQZ$NA~ zr0G%e-l_&09`lAQ8zk6w5}Ve*<8w117@ToA_d35&W%WZCR0)o{Xczkl1j1-Aziqu(tj=!{HX81sFy~ab5OXp)?INr zbhX-M%zQe~;}`4B8VRR?--4f}P=I?Eho*AY2*QiA00UziUcRMFkwCjksBJE0SEHJUWn1ju3$S1}1c9ga~FyQK~vT99=)1VWGPtGkEYa_PECqmfj z%aU&Aka+-j~Gc#DsH{}#E8f*O-kEHj(F}YynkdoFX(t_JKWNt^_ zm5;Y;urp~=-<0^wR8GA)-3R2Sv$lN{9qSLOT8-aicy^nZh)cU654YajzSE0}p$`R} zP3TKP#ga4nD^W|b3mp4t#Fk79K^DDMLFNqb%$RL_-r{4Nv2=aK&0#CK#dWhSdwXy> zn|1Tal50`Ml-rVEs~eq-$j;^dlABmXpToek-G2}Oh1~&=%bqw~dO*r$6ogOXfD#9q zSdLF3X@Q>P3C6K`TaUQycK(hc?oo>gz2SReifG|Gajq34P-^v2117uqFLg-(q)gqY zLi>-s&`7>@$APF}SUscMkF2*%jEq!mOnq$(`mX>O7XXn=899c3e2^Z3*Svh6d36vy z<>9KHa@b=l2!CaYx>t(aA729gW)%5Jw`}G|t3Ncw@G@dadkb|gx1=d5BpPk9v~>5i zP*mU`-G2j#0DsNg`kO2ApEpPky5+F!Sd}Mn@4KDCdM~Jf`4^xAXi~WLB$X!7?0=xX zd3d)G@!OLJF^{nAvF)(`7tHnruq@`|i7&qVxmwJ>fND2CH)Ke3x%bU=5g=?FF_sNJ z{O=bw1`l``@&xD4zvo4kPvGjPtgQT6SaJk#U8k+}dl)3EbuN24)n!}lf9ws2Tp}L> zElNOa^+y81hk)i6{Cb26p1}Aw{Q6zlF-7&i_nZs7M2}P^`5(_67DSB4%T1L)&D!$x z`u}VjEqvQP@kJB<_qIvhZ%=j$a6^Lx2?YHwX#W!sEbzRvVr2j08v#oH3#@LGZ1gAV zjd16kE%GxBD5{GMP45+g_Ec`L`u>`a3UnX7Yh@V$p&KUeQkZE60m9e09* z)kUXH_J6)J`)wAxl5TUqVPpwRvXbr=E*bIv-X;eMfZ<)`Yv|M<#mm+MbZJ|B517##QCZrJen{gMCv znGP8cH_F;|c0j&n;~iM4V~2)v!XFp;Pfb)u3ywm&OhcIwhfy}YATkq4Qr2twF9CgS zj9`NE`9v|Mg$V*ODzWr`?-7r%ue5Wa$^JcbqD5eRj72N&|C1i_QJ_iRTT_rM#0wT{ z!vXigR{0}(Fg&MYf%m+vqH;?&8>oal3^;iKj8KZ6rq$_CN)qqh1h6XL8SCN86=wa< z`%+Te_GE{xWT{aP;{%1T`L6Oa*RO}+!5^(DdotP&ACh~dpfE^-An*g#gLZ%m)z^1yTFHm`hA zMr^bUc&G_gbAv#C#28CPf?x7{qkH}J)dfGA#@egDFHAZb_V9^4VV)GeI3g1*cpnK{ zLHS=Frt=|=a};8zW-|c{$n6&mE%6~wROFq>+js8O=rp?V;u)+d|MQ$+lnwXVU%TOh z3HJ`f-w6KYHKfMb%@i`)3ebJUnQc7m7_o&xgR?M*v^uvv$x=HSr$9Q z1#fgXkz&t=Kn_<*nTSpezdjUGM#ddUNHSJ$|ayYSueK-KT|z7!Lz?L3nyeu zI+n!f|Gn8hIdD11$>%awL;NfaY{A#(OjN%<^m&a9&W_}MOaKrHW;}Qr(n4C?Ptan* z1M7kCloOx}#jp#-{A23V@sPpl@F=(LQxB)Zm9$w0qb6MRhd+bGS$$1Ztp%#<^W!&A zyLgIRV##t;2skh2tBVsG>DB*%5XA6sz|!!PW6PKjl;MZpD;AUd*V4L>^Yo`Vy#zJD z(kf9X7b#bHEX-7>kmm2)L$_^oJ9@41v$y)6Ey9Bz8lKXJGDZYmYVaIsy_moDPs|v; z*`Z0{zmlcM6_u5>prtAgYp4lIXyV@1I+a`UQtJE zzs`^hoK|FgoNj<{u2V#mf_dL32TsA<%zu6tuKaz99*bd&6)C4Ng@OHt{YnE{IO8C` z)XqQ$gfnMgqV|&CO{)KO2?bM{({3(JK}^ipRnJdv34&;A;Pys9r0gE+F@bMLMGfW) z66=FoKrZFNx9}vhm;?NPA>U=+tlq^2Bm-|uic#18G8>e> z&HthKt(;H~vVcgJm@}o#9?nzvaRE>`{jO3}>R}x4MZ3t4K$3Rg8Q3R>$u#?4TnX*) zHzYaQMNgF}!MaHB-~_Hs)C^{1$aouYbhV0g8tWut^3ea%lPJJq;EMe$e+9oRuk5yr zsE41!#YxF&oPk?a%g!H;BaCY&tPtUfoQg{e24t&^T?=BAxbtvZ2hNm2gA zJLx_}h0u5O2pDqdG#FzbXFI6)bHHrF=MK_DK`5M@n-=)dbSM>*P*DAL(>KSbqY0CY zczRJ32VrTu_ALh#ZBY)2D3#<&31i`*mp6Ep)nhi=+KiU(q; zC>6!=dw~u7y@x)Rpn8TOm3gQd9<+mb#g6*NXj{=S76R*MJuT2;q~%Uw8)i?@PMx7u zX2lYisg6i?(M`o+N9<&(5a(Vd(RJlu6K7Ci@zg1_cu4I!_GZd>{<8g`c-1XvK~g`teLGFk0$DzBl$GE4mgy^aLkMlV)*23>Ua2DKyu^$yI(vUu+R!inAy@BGG=%Z z5rFDrvw&#yJjioOKd=@gXv_DL@Kd{xSA{iMSwNA&Zu1>1M=)G8#Oiwm9eE*qiZS_h z0}u%7YEYO|18SQDqMm6$>_|(&2^3klFcZ zdLDg6Ya)fxfo(a1E&0AF2bmx@7xJ)uHuNp#ss?AvX{We`rYG)zKAikr47zFGO zp1s3WY$2pLU8W&yuDS#0v%7$5aF7efdFDVuD(PF*M-0gs3y`sPRMmlIOP9;eLz(az@pQCc~b8@cU)8cTR z@rz=M01=!M|UKKrycfd{_`-yx2{%b9aFL7?4aalE6&S=bv}Yr0D4^i_N^7l>3xv z$ed2tuA>y>itE6}cEoIfq9N0-j}C?wp%J2cOviX(ZAa4r)d1q;WyJX{GyWr(>n+#)VF+02LX3><1U4lLlYGy&8nXdY~Y0q`5OP# zadnfE_h}o&rQl`(0O9qO7E&dY22h11Cp9bz3jl`;o>8B9A2bO#?;i*qo^gD{!{-bt zS^Xeamv;R#cNZ`SkD8zgkzYEDX)>#DLKock9@z|>^yyxYUj2yh{`ms{PkVL2ji7kL ze+Gcj9wP7pEOvRrmJWwdn93=pE0`pMx`&!->S%!5+Zb`6g(Z@4>=i{ za~JLWqT8!|6BGmtBtMH6@vHfGn3d~?hD(c-8xF-PozGub6l(fOMfZ+~+eG_iw%t^J-I1xHgCoUAGKXTgOF@ux9W6s`8rz224=tn&O;k0K(==iRpO)uTrT z7q2=m_5m^e2f=4^bBiS8Xqx9eC-${GmB3=ALy&nwLAW+}x}H}wT8r+VOq2?*XK)9g z(yW%lz?u-bTw3 zD}*Get%UmxRxyD0MYvG}d0ha$Sq;(_7w^B?@k-)rf$VzX8$Zh5Z9LI&0o@Gi?qCWuYwF>A+m)eL?0m$Q z>CS3pjXEJvya9UNYFa z0HOvDnp7is@B&BSraWPp_ioRc9xIXz5O11((rU(}!bCjq@tjh{!fxqA%sHX*BE2 z0Vn0{WSO6gS$wAU)~0^q!{x^gW&Bxp#%&X}#?z9PhG@E(D6fle$H19)PaE+dI`EN2 z!p_XF)qaEBV#XpkKvZaUTNQIi^rqqFR{MdUKuvi19acvx-(XR1kIN_|X^fQ*%ept` zacPD=n7#nEpZvheLTuH;h`0RXMW~|frI(?$6l|P2gym&W-_!ZaDRGbOeeu378ZXa4 zO!DtC(%ek@zyKXntc4!ax9?Z{Bra_Y{KCtoR}boVjGf;`B7MJ|1KJE^8q(f}nN}E0 zZK^y}>{Ct6=B@a|F1_-C;Jc3p=QPju{gR&sXIB~}cWS|YHXuRvX?J!qoK_D(cQ(+ zk~pw_LK-u0_@Mfcupu;cXinsWknJ7zJ7|@@vJrG;w)6*UQ>b&6B!9lcH#jO9nmxw< zkZ71#PQ>n;^xQ~rurcDE_7tb6!fAL7;PW^1Wt8X$P;45;_%N2fyvV!e(6eiHAdtJ` zp2iN?Nncp8ouAHdIy#Px$Tlv+QcpyeNsAIB!eiQtv%GeMp{HF38RT!#a`TJ7OgF_5 z$NMPX+3QNX+BW?(F<9yWmLAQ2d|ej)nMj-`ry*v4H8IOdD)5oj!}id$%TJO$C$!Dw7H6u@jyRaWeO|T&gT&B1#2S2tl z4wt=G^lH~|7k_ums6P2%S?5Co4kP;z3*t0zhks=P?@}R+1UOS!J;rkp2rzvZE75bw z{Tv4P=Z7jDOXbHP5ohZdM0G&x@3>x&Q5d?|RvvT+AI5GCioAa=peM7VYYjPOjdbR) zw42_#wfw@~ns;6B<5dWqKr6u>!sxodHDhsQCZtRB`Uloc=*@tQ*9x&lLaE^DS-i)t z`j-P8tkNM(IsT!Gkpqd^1DzpY-knoz6OQ0l>o66osoLP5%hkq_^MxsRh_kbD_ON%k zL(3+nL3dkt?EtS&^w{mqGfQ`tsxOR^^T+aZCx-G~q3-kNVPRN`XwYf7_OKprnQ5EY zVq5i3k&=&g!1CrbVyeEhCr5ssIK&OQ(iu!D`sJUB_|zdoLZ5yC-V*mFW!8SFIk{-4 z+7w7=yqj&^_aQz{rRNl6-KL3;5NppUXbz-qMI$!}E#X$xR{ya{iPAx4v0>c7;N3r< zM`h#1@+C~cq{3LG#G(Cwwvi`?s%aI{Hd5B(d6{GQCgSH)Xim2JYfZD96asd2-O@|L zEq*>xbLa$MnE2da12sP#NSrxuH)h76Wsy@&$4N)(VD8dFcX$2z5+)jX4U(~Ig+0Q}J^|G8sf%*Unsb2t-(NZ*ib zNGR3=s2*uGt0QZlOz~;v)Xu*PqtI+}wvL61_rsHGczIz18djf-B@}2r=t1l+nP!qM zgExTHkp~^IF`0IIjDlEg=!9!cO5H%EPSIES1_QQRy9@>TuGfAiDjFJ914Ws@MKfdy zA($>lkCxa+hDGZ~bDz9Ubmx_uj74S_jv8I2PF#E%3VW_0=7+&*Ke`<0oyrgtF1**) z!e3#IBX6drJ;87k?R-u^iAB{nRTZ#7q42EX)2k?X zCQR=2L_L#LK54LV-vdNBAujL5$qw3NGS5y#K@DR=ke^dzunc{fS|aD!(#nT3^i~CC zL4;E^%eOPmf&-_+Sa-;A`pfb9xaDc~ z+{!XLq{m6Q{Y1AMX$Od|W5#VPy$)hu{g6t>M``Di-??tPI}D7qu9$Qnc`VD);e#8P zBiT$co|+aHC-gKqvn|r}8@x_ttPE>JqV-05DWS)KecR875T++3oVl_2#K;S!fU$?+ z4!&y>=hKDdQJg0_-(+&BGH2}iBu!an+Dy64yV_3}P_DmSRE!7OVb3iQ1P>a!pZG0@ zbY%L*58f%@c}TjZH!hgM8d_nTC3I+@R&xH)T2GO|qMN0lc$gI_WmI^wG;d9P=mPZm zq@oyXk?Lq~JC7ADP~T+Cl8ifXI}i*Gqgb!hy3$CnN(l5urx>j~Er_Bh!eSXDifk4^ zC@`DEHs}SX@BQKCy6@He)J31*=hnk1x5O9)d8jNyfa!r(R-w;hq@8C4s{j5Elk}AnRPf{M%#%)4CU}%eX#yo^0U>G zB*j#X)xbv*`bjb=kO6oJ$^7V@OflZ;u^BsIkI`U{gE~ms;qzA`DU}x_tF|9{kbw+k`zH}4%b~84quTwTRhaXasa1de^(U{9P zcp75h+IPNwZ|dTzQ`2e*Gy$_41@T_|R>mmI>Yz66$P0ae9a;pNx)|y0=Nh`83$@vD zzB(+*QfS>;*j*4_qk9yR2J@70l-c;BEl#pUez8;(w)KL8+Hyk*wx{|orlBzH3Q}P zzDQR-Izf_2M}m_A$W75;Uo={F!F`6|OGH8K?%TxH6dQ{l+qwkj&uTKb132`WZw1P| zwM8VKiK6+mx!tnBm#Kd`ETN_6M}K<~)p0iRo;4Oxp)3O)jLMJv@nw}X)z*4oawpzf z3@ExxqaTK%^qs@oJ%MB?ULHnV)4rF7KKfMjqCwAUvMHMpt8bSN3g+JoAhp9=nM@X< z#~je&2!69Ql+2YZlGxL<*k6D-MKsgkZ$BSAMDJV4=usVJeQyI%F-= zI&OsPsaV(RTZD=eRD;fF4QNESTHM12HNs(6i46)&yHX32fA<0iPOJ7}wbEQ)qG$_r z+(|@+8I>K5P(6c|Dy__sSLGkj*X~|l-f$%e6tzwF`hf5R zOfsLhdD$@pM*BmY?xP_yOEKAj8V|f#pjlJWHXw*)?vR7(vkV=Vn3gJf}8PXgi z7f~cKyQk`REr|(fPn#SyF^?5R76%TUTTQ;%oL};OgVf@AW>~MVfmS^MQ{#gJ5t|)1 z1(B0&5!AG5`p=zOL$M0mS5M9i=h-`%8$kUc$ATu2L2sWOaDaqVb*>2(V!!r#TY7eM zG7Oc%@sFqT?4@U%yHzY*z;cw7ty?uIw=Nu{oLu2Mh^l;`V0K7_p+F{u_ zUdvXG9+P&_OVUYTI$Tb>C~!4qb$Hn~d4-5QX)dC?zXcw$je#Fu^BaG$u5NTZ7aAHhG!-!(gLtV39y$cr< zq-AMe4GfnOyoGF@@-B$BVZ-hQ9>z~UM5T~|LZ^LHuz-$3KTXdqD9P|`m!b==zQ=2z zIu#kVWPTQ;9bOqhvGoyY|mt{-PX_#^w+3|Ibe`Ibc!-GuxgkoxR z6JipL7V6QF7xG;)8c&?X+B+jYEv%j$9t`yb{tUy}lh8s4@KHEhxY~7@e~nIP5p<7p zt+GOv8-N0r&|V8zx4ZXykx3&)x3YoVFry2$oQ5pJv!1r7i`e5tby|mpy9Ytoax&c3 z6wjo}YeD^tzIex@fFooBu9TbEBohn+^KT#C*K2JdN-G8yjj@EIKxT6@vY&w0pO%~T zHGhkx!h_5w+_$lfb;sA;b)M>hajl9W2d-}#vig}Rg_Xep16ctG4F!Q8Mhx zY=MGvk{cFWOTntk0)(_3tN131S@{^xp!Xt;=AbEpMWnCcvd!>w%FWdIyD-Ih!{Q;L zYl67LRnMmO^}q_&)g{H*hCN+(*eYC7MUSr@Umwm##H@CGXBj&5YiRF;5uvS3W5ujC z(d_W|sn%3jP|n6`nOaxdKHyDtM;BX9A-*>s>?&3&-nArB7$Qaj4|*$j;FY225ELH2 z$S8Wstfh+1TNfWNf;dFN9*~+3IEyfuQyO&kJ|UAhXzLoyq49}uk(Sc9^A@WJTOf?H>4C{In=A{+zCf^Q`BUNC%FO3jHtjjI|{(d#=WzJJkbg z-0A8-cpIV~uuPA4BHW|5i5E9APGHGn&gDr;NAwPj%y1%B-^2Y{$LnnEaVBhstjE~$ za`ne?azFE`U)PwAT%bezjjgw37Xd|SgV1T-d!kceeNBg0(-XP?dUhs7F%|ltyIVwWiw;K$W?~9U7JHuUU)LY;eNL`&Y7Pp>9@eMA$!MySc36g`+Ao&>3fBZ%(w+a5w5dt6I%M~4pt*T zs1lCqqN<~1%{+Z$GG05t+Rg|Y=7*Z4_9x@=E%OKDuF;s7Zw5jKKNqWAmmbM|F$DgV zLI=K&3N4Ud-j)Cu-H-=b0|SwI^5vqDC`Gp#>467KKHd?}}F*4Eni`rb0gcNG-my^^XPzMH%zdf(n)#euE0E}F z`+eC-yzgo$DyM~Q*b>9%f^lI-(WNDz1}g;oQ%feq>517~=E{&wScQ@`Z*?StaQb;TEz#VYJ^a;SW zXJp##jyDa6;3bhpB#jAb(pc|m;fcX|jIhf{bk%LvpnJJYXg%_n@Mz}Dl-+y+hulnW z#60i<4Ue{DG-E6%;#1ZPtF%A$;v!dIgcw3AI>r0YSmZ(_>{mqU-DU>Td)P>E*cp*{ zNoiSkQ7HOqT+_uRHP)S3w+kpECermA?<*d!gphl$INEdejvyGDDo`P$Fh$c`-qIJM z_#V3I2~xJGMQ^99GlxJ}YAN5$^Zz(|>!_-quWeX5r8$6fcPri9DF{d-0tStM9Ka*p zU6PV2c@Pnl?rs4EX+%O=8hqv>-{1HCJ@@n1`>y43Ef$A4Gkf;znb~t)*QUb^S3@^X z)9aq#rQd?>-jAa{fV`VJlfFL}!V0gW+fo-VzESoFdvLYs8;ZQye-kfy@`rC{cfFSh zajpY3ZKRew z^a9(;iFURFsS{QOf5K1U;{d5T$e0QJ+V$^|LyX|w;3m!4iS{fWe>J+3iZ$u>F}UCO zN6(`8(~3n9JRA0UA81{&_2+~I?x!2T!>OB=DPKq0qfQY`iF&o(dFn;d&z>46wBy?s z1qxsX3Z{p&a9EIT)X6wSjjG^FKDX=F{3IwI!_X1Z;Emu(Bk8E$t{4=@FJ|Nq47!>1^+J^JduI^w-yyrK) z4B;=a)S6==iE5sQ3R8~w`>!vxX$8Jf?_th)#)1;3t2g5qEq>5}E9pKluK0jy`)^G- zwUSGx)?k`42cJ~tSiv`89zyJ7jNpno_uiKc$!Goq*$Jn)+OxFQBN)b|Wao9?GOuZ@ zw|uYQ$Qt}JI3#hf63zR^4;vlr9Bn7QqJ9g)XO^F9f6dkY>a`y@7i^dW2}8kSX5T3P z=3w9aGO10Q;HoaTm-?b`af7bSQ2fO|KO8cw!nuCdZPvG2->v+6D@COe!SD93Miw2&do8JcH<>EuJ-zT(_TvKa&u>^uc8KZ zwS4@xoFn+vvjW+UQ zQGggzKg6dFM`1vRG?GZ(r)vx`l!vA=JTC88A(jzL-A{^VqVVlPeBgbTU;B>$@bY&? zr9Avh;R!q#Um^v`z|{N@L(cT4=k3wV8sDxl#;6bygpR2aeJ~5^X(&dw8OL#xhMCf+ zP2V|g+9S_bW4>Ao_5C;S{L=29y-wlEF7<3`V~4XZ_JyP1FE%_~Nw~Og$|IfX8NIvp z!(R8PcNb&$$=Y=i^@r_u?XF!QS69;;jw#U0-tccf zt+0QuwHUz8!u!d#FDg7-jJiGPF(unU>QVNjv=w0i+D*7(EWv7Qr`y3{gGZdJE zhEAPe{;pB|etfICO&#Dn(;kR0&2N;6I-dXv6L-1Ctc5mA+5jh_e4 z@-vLJ!6?W~kq5&$(*EaB1jA+V13+$my*<@|r|lL3e&Db~JCiOP@mmn#>rSbJX_XTP3y->?Drde-l}4V(HxceIDYx5=8hcD?duu1( z)l%eJ(2@CCo%>&I4^CFTf0%kImf~2=iDLzTF{Qs zT{{m)XkH}68=}TO`;sNcI^Tb1I9UfmYjL7)aIK8wl@LFJzy;)~u@ow%8O?4gBYTXm z$P)`nBEqbmcr06YkE$!FV$#Q;j}->x#(k=?iyK0b*rmMVKwsM7K*m^raytDXlw>9e zMH6P;GOhOTsC%Vb#(+v+jVkdap0SF_(842jd|%(hKnd<$)ogNWIfpjD$y+Rl7crLd z#5ZAQkaV2bTO9tWyb0HQmYljw70~f;m3`KkR;Kpm@gs9ZczPJEfU#8}eS5A72%_Mw z-2WNc7Ys?klIRnTB!K1Ihy6TUrg9l(t34=Nqq0Xha1K|2WO=PXb&kI}W7r{btCgz* zby#GqfLWM|l04#uvvJ`TyUfd*&WcGW@WT^-{yQOg|IR|#wEvHsY z?P(eFdO?a%ue@*1c=UP+PjM9!o$BJeB;FD0@UUPx#M3Pi?_8Db?zR*9X(HkY-H^|h zvZ>8j1o|kB7C$E)%dQKLN;r)mhrHz0T%N#(s12Ku7YF-`7O`>;zsO4MNb!3e#OSe_ zaZ-{+Lj#}q_8JacD*F;ICQhL~W#*B=B%o1C3;~`n;L##Y*`FkWHbv4Fg7J+t`l^_= zSNO%eNN#SY4b?N$Z_mbr7}>WbsxKE4MJU&>zi(C3=hQ^}T&aE0f1AfEahPOg`10iq zZ8MNT_cvqEt#b-W!}w8!kj}1-W?B>7^rZ1{IcU(pb2=@d4Ks?z=pZr?D$zDuphl4= zeGM!Z(8TygSBb8}F~^W?z_44Y|0@M%4lDEkJvu8_)#7hyyg-9}Wb;DSiyBw1PPpSG z*UIoh$w-K2{U*YrL&ils^kT(VmPGXEIe07uw^84UzzW54W5z$h>H9zY=dRdS#jdgw z{@z4gRv%`pov~Qr2QGCtScSX1HV@!hr1z7KPfG{M_CF0f{Evq_=Hig2uN%N2fmF5@ zN|xAtb4mVqx5YN=d4~;>K*w$NS6WCTa?t|05<p1!f4zg92|x0<=qNUM`*mqu$-yED!z3%}SC?82gCekD%0YVDcr&%t(J;S?Z7 zVb9<{bT3x7+{b`!>>)Y}eeUfX$Mg{FHA~0?3e!I`nLUj;z`}Y?bkBgR-QTs@Kyix?&tg>0h7MtwFfql=R*4m zVWsuowW6rs-=v!$RY2bnmZ)zZ8Z4`MV|e0$zu7?e{$%De?zTzFim!`V&n(5R(YRA^vj~IEs3YWd}8gtmpJW7R`dS2r1X%c z?r%6|wtw^GoOLCsq=D9dE_AK*2w*X0#O*es>};23d~HE_qqSRo=K*oOice<2MNse; zlJW{%1^oj}FVfEi*<`zJ7YB&5i8N)i4_7B%Oyys~evqTA^*nnmtI}iRN`e+g23^@8 zV4Av>8^B54N|RH>7LSQi6~7jn`S}F(QTj6xw`^UIe9*^XC=@aYw=WHLjm@gCeArR& z2-n6UJFV}pB-NnY0+2mAu24fB4hYxXNb{Ph{p{S;S@jZog%N;5rIN{1(Lb?48146# zMqCg$)X@wyF7osX=Q0RNMr%rqxWCrn{&uH?w;!_IuT32I7uO`_*`;!%cDNP?B!pN_)d+QJbAa4-@!~O%>o;9M0l3whKrnG+Iu>j(qpCGjQ_fJN>5b!jQ6QGU1C4VW_ z0u+I}2{*PUTuUb-Uz3N>Y)~;`$^SPGLIZ;Ja!LS&FN;h_`N^W0D;pa6ZCVJ5eXW{= z;39!EPQCfNs>u~gam4|I$GgsCbF%zCxAEsbfcd^g>&GX7-gvw;xJ~@?CDfZ%4Wop= zy~%)jGw`9L0rbW*8K`cUtkgVmG-3=p+XjgtNOz;uxUrA--*$qacH|7mh=1lo?Tkhm zA^)~x3bj*qrv!f8j>l3>bv#P5F~6*_xHP!${wyk7{+EUEi376j-#=x*0uCU~z!`Zx zrEA0hUVC7&3CSwODBmCk#!XQy#ruDZ8?Pca-|uu6q`=IAfMq7%IDl{j`td3hOpdmp zQQsRdIpjDCIyXN)DyK8E=y`p0e!R2u9EcHYq`mC>SB)%Q0kp%ZSEG(@77W^fy>%r2 z3t@j10@@igFzf?V2)Pgcp$8dp*B9%kD#UvHkC6?hiiG}cP0t^~CCeBVai9)DdOhza zlK21e4R{p*F8QCv^W<)5((t&G-ByjYK=VI4bORLk_qk^OI$rn-0G+nCz=lBWEGsq6 z-%D4ZIUI?H5aB(K^ozkTA1S>McY6@BFI#83Ckr!KJ^VSk97tVrttJG0cpv?+adtoL z#SI{(SgoLg_g;VWU+Y8D^}qh*z5YwCc)edR0NiUL2bkiU@Fdm${@8#2RUQ}U-Cc|V z5@JL#lb&(UXwd7o8-^L=5DXiDvJLl&D;3DWAAkx204ZKqTU$#bc%M7cyp(*(8_WVN z-z1<}88;|4|NA9oiNLk)SAR2dB;EyW|5Ui<^Eh%qLE)|!2P9a2hiMlmpM8oTWuN5u z{X^SWVQ9i@szjF_xM}lSZ^x*=UIgK^`=O=NZ&Z)VgNgyb(YPEnOn+T?1RFAAu$dkm z_})kA*83~HIxm$aY~0k>gj^TorrtXYA7+08)P(D0Ga>{T@-OGVoCZJCY2J`;kEUa>E;A7<$f4KY~13uFDx8Idx5IG1?NPw>| zzEh$CnEE$ND6?-DjkOuGf$2T@p8T3`Zr%i5_6+^kzx4)w{+-m-QWFd^gccZ+(5PeB z^{SDEAobV09XSUgC>%U~{CG3k@XjxBmX!zhEP%bg=g9||e{}v{&FmESuaVNAILT+x z$d!ei3~@AA=zd+ZUH-2q{~p^qB1kz_K?JPSuTQ4O|1tMiLe0O-HbC42=1wa&BiBOj z11t?gSOODpBq))>211o&QZ2+C95DqHH&rHO-*2{ebBH}w1swiISWRvdny_n{3ZPWP zCX8G&b@LdZm`(I0PYX15H{%8>u(N^_7`?`U4L=is?f=&nuH$X79^~Tt(cz;&zH17w z0^kYc|579K`XLrX+FK2BCG>o-e?+Jhqg~JWBWTXe#*DrJ@5t7+?n~yZC@(L6uRBw- zmK2{f2z4KIEJ_QR;(>|T)s>pB7vhEnXzSC`R4@4Poz`_o z*axJdq&QOK+2Q)~+3(G?KQ}u6Wgj^{2eHNZjO#9n5}-c-&ZkNV+I35h*;ZwZ%>Gz}{M#TMmr#X^3v_K2f`J&S54!TJU}E+V$UF&&%Bi5Z#SX-#!3ezo8<> z_oaHYJ+xV`1vw2Qed}~#5-J5gIBD`hnDs!rhGOUEQZv};_Hd2&uDfdhSQg^sQ6iCY znnaG2jA6u4^nn-1bD$*w(K0T&djJlMDGis`jp|)IWZ_*|R9dI>faCApz+DD^gEl!W z1{c=o?`eJM`=d(lztZ&Q%I^O%Df0)M__=Hn zX9R~w&JB8V9Km7va@5m&!r$evzO$8(aj!}{%N)b*L)R$P|*ClC61ld z(PVj3-TVRIvrpD$u z&}OLz(#@}LJOrEucTljvX?v)l4dG?t`|HEhEU?87OP|G%wy$oa?*WrQ`-`Az$rga= zuTyRjVM;Iu?nPPEf!YW|X;dfUaU8qdF<};G}W-E)3KCSF&ukI5=8vx98 z`2?P9j-3I~oAZfg#R8ub(A)9SmHwSP|KVgQ>N5}*{HUgM28pVIY5{9GzQav4v%+*iL2iM=$-c1_1m3CSbq+3|9C=|dZ;wblce08WzptS?L|@U z2`bu2AR?n{b3UfY|7+(xkZP{4;(dxCQ-jO}3EpNukn8pWDg@6*FCDvqDu5!!lwoZQ z>+lMA7vP>H`*1bYeDy_ko+z9LIN?LrhI_bL9xBx&+iTBL4k}L2AaI9xibL4Z)kJhJ!C(0 zM_?upJjcQM9?w*#Vyj@kgmL-ilvo^_?l2FLQqS)j1NlsaAt))*6-z7m<)HDFufeT< zqMY7ii1aWeVWk0~g^$oT_^uVYV(v_;@p2~V?Jws2v*}Bqb2+6$qL|xILMmPapzgeZ z%JJFnhdyy5_4Tco)F&5wRV}E_V3Z!Bv#vpZ8o{J}2KsuR-n`!jv-=x0B`*HtV;e5_ zNv!VXtddqeq<#q%zX7ER&dh-fH?dK*LXJEvoDWi%-qF)eMd;4};q(GOfG($H9t865 zUle@D$F2Z|coulxHl#zTkeay4v*l$Wy}M>@dPT$@2gnuf~wm zI8#8CnfVSW=MlaprCSUpaIcu6dYJy2<89eK6B~fypDDZj!a{B1EXi65yxMY*^~ef3 z47}X5qA=C7X?@9|)VK#McV)v;X9o~j>y7ePN8ljC z9oSJAouKLkP(6WWXX46-S#B!L{5!JfEVCs*`uB0rDZ6xzlUDTjv}i0me<--*Z%Z zOuR?#|2DIrMX>&G zqlmS=Qp@vTf?)xH{9Je2kYKTofF%ekqUwrSwd*#}>GKEjZs*#jQ#w!1Jo9%znGk0X zRgY4M>%x}IJ%tQ+1bS|b*!uRrS1JRVs+aH**{5&Ih%y5;+4*yye+N{6%vITk5hpLO z73H3og2#PfLfuq~H0_$F#5;AdPGVvr$hYCsL{xty6hp^*NyKS;eOf zuKC`$Izv9aKY z1OG~82|ofthX+&fUnnN&ff7%-R*1B;&Z|=I9d?tNO^}_?vGe-m4(>0=`Tm?opd zu&pe#XD7G<;$hNfAhPez`15D$DjMLyPVVk0F4%2CB9$kTKhWYvA9~&pJR=h&g$oFu zrR$KWXqn03FV#VkNO3F=SU3x80#Ey`U=k503(rA#g0qv;%S4YbNlT!*aksxQRq0LO zSJ7gZ?AbE^=XQBFOzuhhghXG`b}cAAvHYEQQKd&hgUV(|5^;=;(Ekz6j*a7){!MtU z_I||AvV6s8Z`_^2`kA%N#l{zs@1dnW_k1FDl`@!8Vp2WLn_`DUB8ciKeb@WL@l?-U zp?w+7786ytCCZJ*2(TrMH$V0zWO5huMpM8@y%BzA71dY}g4_;EX6GIS)GqtDw3C-o z&5e7)4hZZYNF2OhcsEcM4E6+x+}tWlwXl6#48&u`GR!g5)4U)lPJ$3OyVGgpGuqJ% z?d&B5p5B}~0jZ_}pR zAv@f{t#%1Rkkc34`+~8)+p3z9M*$J_b7HFay6KD!AcD;Z=MWYtn9S)HsEAkSqoNW7 z0$Pl%{!H>A@k3YD5Z4}Q6E3OU7PPsWjBR|WPO!R4NF<#f#!?=z5TwalM^Z=c`;akD zs2RUIBfkB&qF=@)nGLpgY~3YZCH;>g95gAU(Bi3*RE6%hL7=yt-bc=ofAiM{2$V=y zoiPQ^R@%R6?7T5N{yAwE`p!Az*qSxJh&QZN!Rt3?eiMbh^JLji$Ar{rSZvBjj!u#C2~pXN@6| z?2sX&3dtXX;@~{oxU29DebZX&^IZBSc0k=UQ_IbM0`#sjIS1D4KA7#nu$v&}7;W35? zfC47P#c?xYW%mNWuKG#(Xu5zQQ~*0t=Shyk>^bb`3cE$leJ6y}D`kQyLO#wv`)SRE z%D-pob_OpgsfpS-lU60A;!*TX=6B6`$?M|kDSRFV!^Bs@9NfgbjfH4CM)VkLWC!XA zDSbj#7XV9cJH&fTWkg`KZ;VN1m}==jx=j*m^tN`-;tU#s!^M~Qh-iT5F;Vlc*>HoS z3Z!_~elkU=%8%#oU-Zz-4cBI~t}_uF%(XFvovGm!<*YgFX*R~$E_XNSj*k(3^it|s zG^w~#K^q~?X!MWZ<828D9;Ct_w-5H!_*}W~!88);MEcbV9Is5eZ>990dq8g$Q*w!940i|wEt%-8|UKbmy@nztM8w-$r4nY^3|2?`$iaUafUD% zs3mZcQ)zH!6oj+L*z+ms|9nM~aGODi1Ba87$;)uBc|K*WX6Tb&?)$0JY@1w-aBVRgzI9}_^M1}7X)3*f5Rr}RB?w7kvTR8XMlq_mi@r2-+ zK~p50@#%_H;?hB}Xd~y=aLdNCUxvvf;u?hZXh$5h5n($rxLtJ(hjg@e=-${R6gVu| zQOV3Y{JsKYRPwTywcxl>C6Vd*jLCh;$IB8Hm?gS95AI30#%rXqUbqy`Oa>W{nS5m* z->8~!D6;9P)P2z0qz*>$dWj@-BW5o>(>JzLf3bSQ&r8jHlW=%-pKZ_rznhBDp7-DTm1k=!lhaifap&o5wEU_SYDthiTZu4`K1o^miNwe|lwCRDfta;x|q!VfgH;%(Fm53OIf z%?a@QF!1m4qMZytT4Mw$WBBdKwTxQHJCk@n5oE?A@54tWCy7EzJGFk|096|77b!2L zC;3*=j=pde_FQO3BNlVpuKI2Rl-4@|b?_RKl(fU5f)Zid57H99mKgHes!v zbQa-JC8dD{Tht=bJ_0sTlQRKE``@hG)%wwSa_TAiZr|X}(02-;Udl6gTXQLM`QO~-BK-7anTJu$n+*MoKaWLF#&rqVG&WUKVtKfg9J zYL|@l3tk26W$rNXy|e91+z$!CI%bHU7NcclQIN1RQ1J~vcEmxU__Itk7Q{+AufZwd zmCIb=r)RAovKtefQep7?;4;`V^7w;YCDrc4M`O1jYA1OH?URB5`%yzGR+?<$n;y7bric` zHy%?k0iOz?Aj9fjb@Af15`)W|l9ebVPc!lx5ho2Q?-dp&f?S)6==C8ANrF;zh?Ae2 z--E6G6WC_<^oLhDorz)3F1^K)=qd(IUlz_j*1az##9iqIGJ*-pEZJuVhpb*r zs(ZrU+e*t1_oZXzNpp`CR;)i1xv9`lti26+@O-{G266zE7VO(7DE{5)1*X6u()rL; zR93JbYFD3TSIpg|q`iZ(;GL3>%1T&)Z}O%80e%Q9Niu?rq|Et?(n}ngzFTCbTGJ*m zoi5>-;7%;TadMk8=JJADhyJ?lyg=*~0Yv#|gbX zYa*>BNKmY!fv;?kv$DX1lTmPOdZd%{t&_MEJ(g5o$5qp{+EZ|!b6UYt879016z&>l zy_cXV^5CiFQTa+eWzpuztg+{)S5{P8EBjf`nCTw4@8DeUZ; z04}Ltw`;TBRQC`kklr6Bk}X7yJV{o2O;2otf7$@F4A6xL`|;4n6kzv=?huJg@b-K$ zF&R+0v>Qz_FYP=o4QFqY8;e&N3X-d#{7(oI`WwR5I-P`3 zRlwtN0;%|`8%bL_eZ1S}vEAdyuX&V?BQU&| z8F8nNhE)7`Ve=30N=k%0bG)R$myal{G|oXR-!coMUohZ1Tk2IkCd3c-oBh(k)G6qk zRKu?hmz9pQ=*}zb@TbJRPnN^sbXx0qKFO&=R!xL!w0=*FR+%ynT}hn_k8+ohp65wC z9=|lRZSbKD;*}X{-pa~(w|7-EHi--eq1!oG)KZ0eP$)@^i=f7xSu|oSO0Tw(`&oPE z;|D_UB|-UHmd$qeDnA)N4+*iZd&O zBv=sLd>4-zZu^= zrbb~NkwsV0Sy?eznZW613Hjo|p+;n^+|4~>d(2iw_YkAn{H;ww5I1@~=7@{-hCQ;q zu*dd#e+v4$KeefxFLD?WU717{;@WQ)$aOtWB43dTt0q%mw|L6WD&=R9C#Q+Qtvfrj zKo{;3R0a4=^P8vRTeT_xzV7VNp4w z3YZD9xQcVGHj(=jOza<~M~{UrC-)nUXx}ZT-pzEe?X(WvEe=OD<; z;jR>vxh0$jU(IIvz2snc&ug#oq=6@38!xabQnZLd#_jZ7Q$jaaRMAQH-lx?UUIm)5{>&=kz)hM9O50lS(tgTpZw*gftDRF;zQ@w*Z1wB=&a@D zMMX*k+pkWBko>5Avg`oeil~=PE@jK%&f;+&L8U*zXUO7ve+#g#pmzT^8IW%US_@lIa%2Yt%G+0 z61HAZOddrk#<+zh8dAi36!e|t%zc(UvSiheBEpRM{vkUzd zh0rq2q|hfL6$e03CpS>pFLddlKIyVuo840kU$nXSh~ND}O8^3*S|lOfGPnCmFE4&~mM6dP@Qi6aH#r%eP6}ra-hv zPkrw(b|DbselotlKG-4SH3dUG%e_7_9bzCXF^kPEHR)r{wUQt5kjUZmG?9>$aqH1& zn3%@eCN`@2=(OeBhBJdIC&)_W8z2(tRB4P_vIeh7w!ZT#Gg|VWX7JH_mFmB#XI|iF zFT8)^r{+WUnIoE*=dRufDaA`=Tiwt=7%v=8{~NOIb<(c%16J<_L5W3Q zx}s%pkGI?~juGH#kVBU5@UEK!_42kHqS>^LQ@O<`YR(+xukQ}!3z4FTrq$=Eon-L} zCQ9)Rrh~hDFb}yZCy!kkI9VWkWrmQEb&VcWJy+(h2U9FtW)-)!yc5rt-AIZvAKNsy3Uo-LpqR zk0;Bv&Qhb;eTjNiPRIGH)}^BmZvq7cqy6N%YKR23&QZjJKA?z2&=kk1hlr_B?0L|? zjPy_P$+>a?QVEZxU;0Uxy>E%c&`Os4g_Td-`toKq4kIs7eY`*RUL~^Y77*VsCl1)8 zUqr%|WQGgyD@kS>I|~{4D19+)bYB5&bpfKG8r_IlV#9e8o+4$FPxSPLONcAj)O{m` z+4xcWHXoVo`SoV1wf;6X|6(1VzIV<65xLKFn$>;fJF4TO&lEEllllD{(5ur$%vlAm zwlX?JW9oXTe=}}VkYQb7igo%+1d~*tNd8`1zbKnI<`9)y??27qlFg1~bC-C%?Dvlk zzQsNivdX#3lf}<0@Dw{bxCi9{8y&~PzTgPfj%blT_R8k$6a;%4PMzH=sLiWdWkrXJ zbZ+naGRP4eQ3geH8Z2z8-;|z#_eb7IAj&6jy69_+(d9?zI{429d8wF}hT!y<=@WR$ zq5ViNK3^{?0wo!KcusQEx{wLIpx5wd)=`j(Uxd0^cY0h%%fIbE#=57xC)p?B5>_b3 z+4abGNzP4I;$&`N8+;5LEE&S?l|7j7-)CbAd)(L&M~;uDWg8-L8p<%C^7}cxDo^TH2WDP7 z9&wX(LQ^*N&6doX7KbI64%*cihtRW#BdWI@+9yb4kzQuJvH- zPgFXeALf$rq|Cbikv)_hoZ;)P`0~w}=Sp8xiUt4RrSqxLg~^ayzTGOz>xQ~oAV#%m zAZFm;zU!c)BxQ12{bW*pL(dr8R>D8wHj$Wr*`wW<%v}qJb8k<|$=Z24X5|%}z9iX; zir{K3K!d&ijvjTt3%%Z%_jBjw`L%Odqo2jd@gJ-Pl(g=FG=jh_=<aa~nAc*Zy|`0DMa5R2hb$(5UlE+>%1!GC$mK&3zMU@m%t+|3M>-n<8R~=q}g~PEiN&N8%_A%$Y zv%*Ds4s13(nMYzwlmqEu}pE zAYl_m6?$P{ymHUq^W%j9{awp=hwMIXc76@K-!Be#@2S2aCDKSX674;uBfjVClk@gm zn)L}kD#ByM)}1@72f-7zTm4@b9N`RpQE@AsOt23CYx*#iNTL(iTw7OLp{13Bv;99> z0BGZEDWT(FnaV}pFt!zDRTvY)y39OOxUoC+z=N77 zcy|7zOY~)_JWuCFyhUAbM+(y%70-Vr`&IOdwSH|r+LA$Rd>9I;cu?mQ^7;fO$A(Im z{t)%Y0{AHYO%!b6@GLjtv3`1EmSu)zg_RDIqnUhxSU;jQlVh*OcJ*C3O32MV=i!s4>)nkKq0g{zy3e6^EEyvwOeByn9_{YR^*3LnvJi;vW4-YX z9Q))9iA`!8^_SI&)u?$~RyL~Mnxqyzriq|gwKFgCbnPu}oJfB5Pa*)i&h5#!9IWnf za+geCA5w$vU#d(%UJD%{qltD~JXLm2ZNN{M!8gvcZ)eaTS`sjZUNBJl)GTYQU}w28 zcupTjU(Wn%jp&vWM$pNVlnlcs=w~4>BC-M)*L|)#na2-0`Hg~-HUbRDU+D&38ua2G zCwRoq^~)bELU>yUM=7>1Z#{SjT$duls^>&q7q zoF>#d5Ii6S4dW9al%rrVS+@~2t!Kr(euswz=xo_N#46gzG1KSkMNuHObDGNB`a2O& zvvx0lm)Ys5>Eshr5&;8XqL&ri`D+`*9GIpW(bfj|XuVl*o9LSOWyfFOF{sfr-3o?PKxOj?+H4$V2^mno2|Cm4pm>}o%K@emDViX>0 z@LC%y(`6!iJx|&~Pr*Dro4B5*;(C8lk^k!HFECNFv0;H!2q%RWrJ>s?wFi$NyHlc} zO9{{hDY%oww2(2hG>Nsd8TjO?WpTdniQv)UPGDwGQT_=jcy(rpdnDukmy2RDFPypu z;dQGEqoS#RCSRaDI|MxgvlSoq0;|~9N4)0m&~GSUFgcjCou9O)e7oIWLn`j}m2gJk z;r48OXPN2yC6<%f>*0aUI5L32i&p7nu`mm;plhw*<2W{VUH^6iawzF6nm({NS{bVx zNAnR$T=60%^RocK6V%_6-uZ;dp%;}pHDw5(V~hrJWdnQBPa;7NuKP5?fi7j`eAi7( zP{sNUwkNB5=&M`J1OI;We?Im%yZk>ta1l>~8iU+Br=g&sqzK?Ry*&5UKp+0~fa})( z>(3B4O28QCuy^ktpnqZ*N$GLx9>I{G7rFL|CMIjcy{5MH9x&P-xflL!)1}3^3h+9; z<>4_Zl+VVS(YkPNJ-(?_(}x+hLs{Z`rTjik-X<*5^cVyPYoZsfh@SN{B2W}H#O`ev==F24qSxCVx#xvx4-ftRvHU}_F#79W zL4&~z0-hYy`UQCl;U)(LAeNjs{&!)fGXV$5&To5W93vM*1cKOTv^oV8#DL0O1?K7# zc%m(n!$bQo{M^}~rr^7D*}$s-lI4>BWHu-f2q-+tS$h?#So47JC=BadQTn@rim|}T zD=8_8fYC?1%2WY@&g}Vh}ZHli~ zNWkZ(QR8bKP)z-s+XaDOIPGsBur`4D$;rA7|2xlY=%AnMg$&s@nFZLetN3;Jh!uSj z#Ox9Wk!r;eS*>J-mB9q(D^*spo&P$9BLU>eB|KRq%mPm!Po{Qj9=`sq1QYONRUbH5 z)d(4;8;ocPpyuZ=eZ>UNrD}_k&L2T-yMYf?h#tfU@_*cHP!7behsi;PHs~q{FroT+ z+uqkHHSsQ7oLWfM8l4RjSc%jyc_XE$ zGXd?j-T!!|N*FZm_Bj_3)B-3XzR_&i5xw?I5istjLG7}@)xfyp@6_E*TD@5qTO1x8zU+ zmK3@R2X}ldXumGV%GQJyK+8140%CodEQRzDdKUo-k1LGV?Cvy4NrtimQ%S~Z{#{-m z2#x4ibo{UGK>?$n^}EX*RBaG2bVxN?p~pDr@B#yqQk%C6ohQ%~Za{U$r|G-LXh7#~ zm+&klSKS+el1NtY?`zky2z6i=nvs+A^B9#pPRJ%2>SDClza=7a9BVm*Fw}c#%@?eN zc&w8^#_$_5*}dI6dO#F!u{VINw5(dARb?jiig7oH{vuBdfE1(Fq<4Hf`z?>EQCZJw zdO`6pI_zwx{$q}PKLEa?00>m2y)p;sQYgS{Zf1fdm8`Yqy`(Yd@8S@R>E`|IY^`|p z7>L8)bQat3n?HwL+|;-N%EIV)`em~)9ut8#Q=TzXC)9uH66>x+1EppQPuOT=+LN^XE54lC2DNSxg@+PiB}*~fos4vHx~%$k39Y-~}fLAZF1_#-*D7rO+i znc`Lkc5++lOC8q_muqO~PBDf_lROV(5$n>dPhW4S8# zj9><{Qj0jc94(&=zw0b-9lHp8`tj;9Zn9Z?F?U&&g6pCu5L`hgafxRkH5RYC&wLZx zdFpSmMMB>mMTO5B-j-Oj^LgX*k1v?q=?>Dn(G^O{n(id@tlw!4;#+gxOL8t7`h@eV zeCxhA$Zw2b_HTPdy{A7eJrg}1zLfiTEcUa6le)>_GFjd~&b_%AN}ui3erzm10g~wx zeRENkhxtnw{66yXnc=I&na*64nPoL&8hfi%*sI7m|0jEG6irphRcyPU?5`;esMFmE z5Tdxx73OAZh5 z{_y*+Yj&2%{C;aKt}u7Tx#Pd%7X|6v-quJStc0&}pXZmIf!5&6mGi+^X-dC69u2 zurRqJpDnN$IwG&HK9AxIsmAA7idOlohhb)1fxG5z8(!4MhE?89&_}8b3o7v`C8o8w zzzaJhkO`-#^c{R02?{UvqH%u=Pz99LZVI6MJM~%Rd@QZ0W*Uh9-d|*xW(Y)fP!-h$ zI;;GlnL+@7{-^23m5r#rqdOtwL1%QU@Ic1Q({1LsfWv|)fFQ3t0R=ee0%U(V>2ia_ za8>P2;SvE#Vqi8*O~BdyBKQf=jbF4dS=r?cSU{ss@3@_n+ckgk`RX`Os!Ya~h{a|I z?km<9J`WDeEmcI0_z51M6fniX+AzIw(U%d_(M6&y?si17KE48B~{ro{k?J*e{QM$I)Hic z8404hYrP0fimdtaF=UU|aKkW!Y@K44Q3A0Sk{hpt{LSnP0Jfr;x&pi*Y(;Y)V7x#3 zfckWmxze=yaM|;(!`pszI^wIzO9k|oj(U8^=U=I)(Hm@ zx^O0%dQ1DZxJn(i3!nuY7u0_*d~6eYw4&^XZ<*8@N2lN_EE%7GhB!1Kthpe3H=SNP4<_2Ett{v+#W+JqFcI!UWE+ z_a=}WC9G)lk=@(X_WP+we{0s=Rd-%-wpiXkom1{&{^Ez|OquD|eynOV3d=1;BtRf@ zh`07Jus4gJ9KMu|BsN~N0+Ri$DX>Vco#X^u=0`&K0-F5W z2<09$y4@SnBxI6avajXNP{^3u!$AW+`I&h#0@ z(_l#cU?OVhVg&2M(_lSfLQF)I_ws%EnU9(#;MDlo-gOVhm^1$Mg!sksO9_7v{?_6W0=t%fT|~K0dL|dYo+sL;kLj- zmRxG*I-56-iSAF(&!XBC-K}Lu^x+k)f^yylrk2Tr7!>A2$=)lb6))9=r;sahoCL&F z_sJ{*FMq$@L9shRF!{&395R>n>0lh2)L4!D86Cp-ctUiSXHP-m1^te( zm66f>*s<4nHuWF-Gz;Td_`zWL*-=%P^b;IS(Y{ETOnAJN@zr>V4Y9Hxq-CmDzgPhQ zKM378v#oWri?tK)?bm~P>R3{YVupzDd^iVtn}J9&?L1mClDneLc7}O{f+=|i$6rTO z%89+B(}T;(__%vjGoZ3=DN=8)uvsU7agUsS9_>tjgUiPzq*s(@kl(+h)ar60Ubbwf zr!v^DE(8>J$ySg?bi9^bk#Ne-Su{v?!M)_#d632|g)6=fvGq`9Et>C+Xh zhUZ0F_2BUE%Vxyn+3?i$HOU%I)I*#8h$)*y9H3c@;;O~i-1XE7rnx+pgU86d`8ZJQ zA|j}gJvmhE7C*ywejBr2fLaZ-;Zb6Av&W!ljg0);Fa>>uPt)8g8gS0tWjHZxb>Okp z`8SdNxY>&zp~Ib44}$h#^!;Q?k+K9O2S)cS?(m@7td@eZVdana1V3!YyK^-T34`qo zOYy?(d!Kr9PTYKM&aw#K+~XG)288c6*xe#0)HV@S29^xg3>CH@Z642#{PX8t!Y=|V~-f0=QRJ?Xt`9@cWy;Wi8z!1rr%wKxYAAGxcUE2j0*S7C< zAFtyX&*}FEN!kkc`T8Ab=)ARqQ}k4kd@suK>GZMIJ@l#-!;w2!m#u)`bYb0!mBA@35gjJkd=J%n_3Gjxd3-Q6$kAu+qmcEUn)!)uxt)2;Dxz^xH=WJ!R;(bg@g1#{ktOVd~--k+d=8zn3G@4(Y z_<{@nO9JPn`5sZE$N{pe-6Cj;!lvRIsu4r>N+XS5`#omZnpTR?pJ>crg zlY+$Cb(gUh1_b4 zt=zS|MZ+W&-!3CAH9y^?_KD3E*CT}u(}3bNmy1f-y|Nf&KKKGhc#A{S zK^LDky>mp?^MYktk8<%JH?Rz2%3@nVeAlrbmlgO~Yb!d`cA+!;{L`BI@{E8;Bw-Ck zl-JvTh^BH-^s>)0$>`$6aGKP(-1)c})V%V_@w5EQ5B=9C=0Y7S(dR@vR7)c5wlJr! z7`3@n1s;xZLFsLN+B_2v7|fr7v*;)lnj@0l$FRV>c~3ZcyZG9=8Rh0kq`~84a>y+xZxJ21mvQLDB9|u_}HH$l#-NInpxuq zFVcpn)TqDCtb7*AfF)u$&d(rc*%=ZYn~+$a+PV~W`!9zu4ImW09l=D_iS2l%tu#c9 zrts$5!kIxDB%+U3>P8`lG_v{O*p%bpR@i9N%<`ElAxh`{SZ;&#h68rNcEm2e%fqaN zyog-;?Vkbb}I8p4XHhugB#$R+ebEV+!Y-zzzQYs z?0xw`dsNP_o{k zG>p4i%jFOAi>Pawl6w%ddcz$Jz7|eg!kF4{l8|i)c8Lb;(dQ3v#k%=$fagMO*OCNoc z%AdIj4^GFvUG}WPGk;1A*i<<~FM;yl(OtDm*W&k;9p8S7SYCY1-D=B@t5YDb?r=4y z_j9phJ9>|A0q!+Ma=GfQT%DaPmGZ)eRBag5h7>hlB+si9D6n#U1aJCt`#9?KV{PGl z25Z%~JA-fIDGhHYZcbPNR!7s*W4esMje*<qTJaZ0XLl02W_@LoB@`17PQK_Kjf2xSv&}_9N z*RyCkSx`l|zU^w~nXnujX?n|wJww$x zWbBLwoVLW-)TJ(6+N31v*+>>1%3Hq^#OW|D%iW}wf5qh)Y)_A>kJx@76c7P zzd#sEC$NaomDE`qbkRn#Jei)MmsRFWTxV84w(|}Y@k4ltfhtOX+kbe!7M*SOORclX zcj_ko;J0sesnwin_I1})mbkWc9J5^;C*)8!Lc~6^`Kyu4*Li=yIYNRWqrAuP$SRac6qPagnY>Mhkl#T2E);?Nl{M&6R6_7Ckv6)kMNp=kk`78T8I8L(+D65(S>DG?O%y4NZy*Xd*%N8U7)zukQLeW)|(V zsM_WJq&23P*J2#F{!LfE9}@`>NtX-1uZ`>m7A40@OXCjO*^+LomZB0rH_Si_%Q$X= z^7eQv6ZaGnR6p?r)b|Wa!Dx6px{PYC&E|`Rg*p6}1L8><4r-)wBDWH^0zMif*OqOn zl~?~ZE%k|NoU-2aZJs(k69KWH*WuDkk<_Lde3*Tw_l5;nX`4)BV0|M>#@)~C4Obbq z<9m8bo~>r&9DMy7Ab%Y#z1!I^L2uj}!^HuMj3ulbE|96VDr!oXC55jb)Bv>OmL3G} z5vmFfQX3kUBvH|>GN$3I0TEQkg|JKN_JF#I_h&S{@fD36_J*OMokK&shE*b928UJT zqNHrzujTlBh#*)}gZXZ~lWna=E-0Tpu*541-J&NAuAL!Chi&g6BNenHa2SrC>atP> z45nsseHg#^%6>ho_wXZo*NRjw8W&7|C2BtTS1|`|XpJsy@#(}uSvT2~&e?6v8~^u0 zkWb|;ac-0^V(T8g^xM^!nrQ7M-!N-Dgi~x{`b0^WyE8dQkTu#jnfJ_ySKl6SHr+%= zQeU8O`D$OtNSAc`I4!&fk>dA#ER5m)ad&sNAR)xp6xC<+v5r-t^&RTok-45nrX*cO zmu}q7>nL?`k8{bJ$GFrSd}Aew*WYbm&@WC(Ee73%Q;%p41{~vwb22LNe1V_AT~Znm zx+fW>jxi(Y-%dX1T*$0Q>lUK+6LO{@dR8roCH)HY#y4s19ZShB-4X3)#03lIQe~wn zp#Ah?!Hvmvnt$nP2I36k4tn*W8MOBsXq*`(iEC$eUo#GWt30tldT{HnA6nKjYTaT~ zD#g~?u9lVF{9)BwC~;(#n0M(NC<{OhQaUgN+86m672B>7lH(p<`!|dns|F?Q%b78HUc%VOjGP21*OaZBw$;j$M;ixX8w;=fe0urRG z@}_d-#4e|^#{qxikmMMs&KM=S)uluhhPLlEcrM@OuUH#=Fx(G9sfb)QD19!jK`viC z-5uX|3mNf8cUB1Yp(U<{=4k={)9QRR-RO(sr@LcvPBUk*V#W25qF7v9wi&e^?_^__ zE0cjsQUqL*P&AKOwIy8=dqz`XYUe=)`9@Sw-8O#6{gKw>AjfrF#d0qLe*+!>jbyOU zWmH;GQTKn^fn!)bz#KfEne0Dbv!>lz--uI$dj5p^o#Rq>UINP~c|b}#=na~gL^p^$ zoRyl?6dAQujjUoxvZio49H(j&Rn=W`O48A-rt?<9+3|NM8j&vBb(3^TDCv3Nr<7DA zR9w=B&}ieYF>ucQQcXWr8avviF#SjIdv2UH_+Q}xlVTC1j-AB@sc@<*dS}OlzHa7| zo^A;$KfFsRM*c*X&-bTLgCe%J!@FS=EVL^qK3DrZrWaWtCSmD--p$}0f1;}6C)cb@ z0~fW62#sAYdy~XbA9~r=ODAPS(g@#CT#@cgI0d0-(QOU+*#s&ohgSYlncASPyA(VR zemGKtih(!5xT0^H0A+?E)88tGyn*BOI*ERkOonJrP3{s+Yw*E7vw!F^b#dKrx;xKv zYeuD|tzYT&>Gt=>(Uy8YHsK;EWy_uzZ=FTAKOQzPeru+5J4Qxw-+5mUs^d2rzc;V<*Hr+6;FGY9*hp>gXBN6}7 z^C8TM4dc0riQEZu>1oEIR0nQro_@TBGS@LGfXNi3xJT^oFygj`7RlrHipfhZh|Jd1 zjWHg`DZlG5Ao)@BL570SVAsz;6U5BJqw3Fcw{Fjlq&VKS41hy(&XZ;o9EQJ`_;eY= zNd|C|%H@OUSS!^v8>VE8Jy{(9V^~sbV+nGDf6~scVKa>COj>2e^bzo+GFOJRgZzVBo4$m#cyXIT6J2TG2c}ta zEdqxa{$rZxbx=gi)Ecx5#AL`*+{D?)SSQDt{M^(!X0bTtV7mEdh1@D|0p){@N&ol5 z#s`B*n?Oqf>loTz{b1~U%W7)>*gK2Qbi?AxZxE4QQ{3(xrAetx0#qE;vnErLIRD7@ zSNz;*&&od{V&&@#`kEo}LzEJDmNHVPmR&yUT5wx>Ty55VS+iQ@#3H*Xw>Y=u(sly2 z>!+q25y7orXcG`|xcqjRQDrFS33g9CnoK^HjEu+u^<{oOS08e`REVE5z3m{UUr2}u zsvp*{_GZKU$a~PRK=F-UdxAcP`D|Mqp)koX zjT-x)x60gA|0VLqkF&ui+X)Iyvmxtirm}5C@p;_In(R4l9p#eC1+fo|KUh@1^eOth zdcwAX7J6THW=?9Mu$S)1ZDmWof6KGy1&#?7^>Kxtt+^r1_}Itsk`eq`b9)3Y*sF4{ zcgOVVnKj>yE-Mg**mkiq<1O=DaIS#1fsg@?O2L-}niHj8jrhMa;9k^EOT3JDdLX52 z9!p>d+Fo09wSX>rTkcy=uVSTk3epc^wr*3a+==6j)*ZsX-Zq%!I3a%`Heznb3WRQn3wDQ{o&JBWgvl^@}2k=#_m73-o7<&e+28|f-ghC>bu zOnIAEl1Otx(DZU_3|bt&yBXFOWXMzCh@=pbgvfbC+6%qF$>k8m1Zj4|=+oyvKwvpd zyL_dHuDAxZk5{!qcwzEBac7K&RWXhag*0E^ak3|@EzSmOm>)CQfp}bw{TNLbsOjbuz6w1rjc6B%sOo&}U2>FtA^xMqT$TBjhq7tTUnh&$h zO@wWJUvur!ZoH72VR0Mg+@(7*^_3qwy;_r!YA1%=sr)*vq!0v87QN%2a0hns<%52} zx{>x%7phF>q6c~l z5y=lGR0f5XeT}Q|NejZfKL_zfkVW8aQgU881+yYYx9W{s?T_&z3q}pTmEfaj}D$Ts?4)8U!6r+3zf}Z z=`Hb>YVaWHu46$bT_gGh1R`#DF%l6l&xYpt(4pnqnri@mahs-(`f~L|ZmskZXpcH& z|4`|4tY;?|i56Q3qS>y(UpLQ@vL51}<<7ArrnJBW*Oh0CMk{ZBn2c6?&)j-%~K_yN{lU4ckzX)k!|~)nx&e z`X22l%~;b-dgEKmW2se#J>UDb?Xx1R3jmq1n8gPu0aL9u>7rS1;N6#oqQ>9w(?}fD z>(3S!JKlVoBK^B~GjLGDMEDfg^Y<`^NA&CNtINO7#TlL`zm|RSItLL|uX!WsH=^S& zE9rKzI~A+91as09DVToDA~F1!3q|{F3j5Pz(@`hZjVaIYBR9&9eO%%Oiyo08^U{5h z4LZeXvvDnd_IrmaUXg=uRrm5XZLiu}R!O7^T{daXEn6wEr)xXz9_JobncQ}Ti+=KK zR+k~~kXviOh^^V0q#KVyeya(aPo(M?H*hQ32{NgM=kV9FOr)IHC#&D}7}Q4z9m z1IXLRJIsQ+-we&XYP{!GG`Ls-v9hr4_7`$SuMa}6va&Tbq zcVqA&PlNzYX+nQyw1VI%g0B;!y|MXA{4pVTS^~0H<_@T=|6;Izy?b{US(fyAeb-L z^bQvX#OFVy1{BnTYUM0?CO&@1;tURF2I%hIvO4ZKnaQMqFWQ8g=?*Tt4tF~*&^f7_ z=UY!lpN`VYl$GMEX)wwu1&1yC;d2obo+|>f7Tvyn!o>Fsj7Llh>XrY$LrV_4!UN%} z9P-=5Ag*(GYe*tLJns_9ufrB zpdVIqA05ip`}ZAUIwAM~97D~!OjQJ;r~n*OmJz1-`v8u3Uv)|=#iX;%w$@K&NI`&Vy)Au)yw_C377 zzf2ZXXx5yuA~Ujk$hL9XfG+}T0xL@F>VEMRy+dtxV(RPhZ-O2Us_F6IsnyAlfw-Z} zLCaJd&(EFpdjKth1C_@dp4zORkqCr6lGn=i3q&87hf+eyg@3#qC_o6@_)~z;dBpe% z`Qvjb%9I^^QR+90jSK#lgog4ODkf6n{CDMXdm*Ge8U%ytGp}af_H6`xdY&}WDEvYa zK#CSE_-E@%QV+A7huIk>67HEiuTx;T1KXwcJNmkGgH8nst1J5;>VyDm)zY;SPUp}YU0|UvJ!wVONNz? zCL=O|7BPs@oFfFAr&@M7f7*@~5S$bMcpI6>C})qZAhcj_jVaFnfC8d=5R8E=UsQVA zwhfb!Al2>d*25>kID9Y87TkZnkRh0hkA*WR)T&2>p4I8o`|l9QzNsO+Iw7JBmB8A6 zS>O+HiSvn^&_yr0Ud>GDlf1V^7bD$8Q=Ll}TQztG1)b)gRdEzxS8nWTDXsy!^alGd zF5!cLp>Z*Zx%$fB1w`D13wCop7J#m<9MI@|N3Q#BQe|gB^d3Q)a4>!?bFPRy({WIT z=D7W91oA=JIP0ty@mjnFNS74XWZGTx#tOE)JyE8qur?^#cl%jmW+2poRpaYHCACsg zntPoON{uVu+?b8a1)%c;KZ_SRI8C|{Xm#BIXf`&g_>Lgn zOpSlIlT=R-6t^oUB8a*^M3&cZKfV2^7_Hh=+psuFk+_*H+f}#gUebWXu2Ua^Jz%+@ z*u4cz82kLi_eN5wi?8v-t)9Q%ESNqA>W@_mqWLxX@x}n%aVv9c-7K$&5^7z#+t*L! zKn>aUbV&Y_KD#+vHnBVfl7DcDF;7J$-}cM7y$_b<;Zj#icw`7J&VO`WnQ{ov5B+dI zT&lHdk1!DtaDj&qX+CY+>f`lyssmcC?&?yW+PI**kHS{-RO_$%eaRp=_T53#vH1_< z*R);`9pwO|B>VJoFD8R7lI21g6v(d^=Z^ZI&j^&M*^3R#;=MjucT3!SV_y*V-Rio{ z&T{*1yyTZMhUlrzado+ zLGK3#Jq#XXegDa@&w{|<}kvN2x}MDSVM4J`*UyX{3krm=QtC8FJeeFo%OOw*2&+(PH@fdAuk6Z zD*2p--T)gMBW(-pg=_zS$3G)Hh>%g?Z9jwOg)n9QhdbnjHk`%EE&}CRdp*YMo6`uY14D^+w;(b?`WQ=pazsbB(JiqA|YUlq87N5x$N5|#A=khd zPHk31;1x3mF}{(kQ?E_>0dUOjDum)A3`Ewj4fT^X=XDJGZ4M@z(IXE5y~MHY_J@r; z`pT#y97NYEF6+JFLonEo?J+NsReIa0()*3|&2z#*%;Bd120txgG5KQcZ4`ufB^6h*~txxns)!d55{6mb??Re6rF|>4wa#6O*(s zO|b4-mcz})@4dazwp)V(86 z3hT~6H#RTVi;C==s^|b7$+izlgNlA?u)zkv<`Dz(jt*<^*-5b%z&wcuXU%?_gerjY z!t_V(cJCa~PQloHn1255a})wQL`WZ06r8#-@fjj&B;G18Sv;s=xf(U;)LN5R^c@6 zPg#(X(9~#BhG%ERSqnmhgb^MQw{W@TBiv7s9C~6Md;Y7Xuk~7FiiFtZ=$<`lv!6 z8*IE5>KE+41+Niu(GPoR7lM=|Hg#x{V^guNCEbYBpq2gfy{TbwcplA>^~<-8T}%RV@oZH6YA`>as?J}rH9%J#*NF@M9>6&BvIIsb}ry;Sq= zwHP|*iF@led_vc4MHpM+Gfal#F(R;-WWtx-kF1HfO1I(`oZ)*c*QzGjOviLdqE+G9 zIiJg%2p^UYW2G@l&vp431fI7;2U2=b`;pa!q8+uK5kzkKOL^RcyzmhOfM3 z%q1U}%O-x%!Mp6y;`PV(`M%%PZ7)nv9Qq9`icpg>Gw$q1om(AKCPZn#(~e08E_C^s zO;Jl?sfrktMtFGV(%z0kfKP2d6W1XEo?daey*}jy?0l|cYyhH87g;Cy*Y&&H>*w0# z0~^fZ-~B6F6o(o?X@pamF3iTi6A2^a2ytV3-nw z1Iyt-=9n+*ksIvoqJOm1MNUI}-dH|f_j@MGPKfN?t=B1!m*zsw!DWl~M0Zihr=+rO z`k36%03Sbry*tyN6wPvTH>N?(Ie*c{=6y)}?=NzA-2UKv!oaEPe9O5w_)%GljZx`b z!HZ(;6adIpoE=5Esq;3~A4OA*j2~`=7>URQ%{lhm?K03Sr)Hgl@-k3ZG5GTpK5G4) zz4yFAYTHiEjQ&;o?e!i8JiLAeA=c6u>2WZp{gc6rFF$)}CdJn2cNnL1rQb9!ll$cl zwd*x1l#>RN_D86i7bXlNolmz#9 z>d@m{2|R6{JYm_Th*UgT*kGDjs9-;j!b%XXG_ zox{%!pD{s0518gvw56qy-3XTh@I)u#I#R4A?`;}nCVkYC;P}X!CQi=JeLE{OAJ1pgvl83@ocYysuP59DrKJB>rf$>@~|##|Ghsw@&Xg?YScOnH; zI>KG6S`UXGUD`TsD6Z`L<;_+csy$>F-;mQwGO^p!H^U;L`xu(;oUU*Op9pqGCs#o? zPd~Ji!8G#~#X?LI4?eC{xNsM2q50^163Ep(nUt&iKFsW9n`UxrZDeP6WmDZS&Ue+% z7~9I&4ZVV0#k+S&mr>zJ6+P6skqBT?i<=v6s1_IO?(lz0f**; zwGuk}uB;P6L=|MoZv<)nLf(z%hS7Nwo;*Q&ZuW&tK(Q*xRYvZme+B&8aVEZq_(oC^18Hpy(A6&Dvt~gZJI| z*IvoH@v_)xl&axoXsh&Z=HWb$DHSNHPIo?+g3K#yvi&c)|Iq>{5wPKYGf^K!ghnE- zWlTOEA`qYYJ4A-Q8m19@2~}o~sGdfC^(}KHon-cTWwf-TN-b&kFmk$lcJJ9j@My!b zmP9ZlPqM<_qg=>sSA`!HiNYlR0C&@Umef-!iVs4HnjQtcUX6;ihfUWqh<$gAfGZ_Z zedLnM=jFV=lPu>s!?0J>Ce8XB+(cx)x&b}*P%d2O{ceJK4MdYf9s zuDeuzNY~`w9Weex^TPx}Dx1AceY3U@DbS^$hgK7oX%RWx z80TDi`$PwMcS97@P4|2G0UWK;4%Q%T!kC-jJIQ;fmFXxk>M+}mIVLFwdtCQ0_bf4G zQ0KbR-{#J%lg71%uJu&EU!dT+M+Xr9P~Uy60~a&4 zj*uS-OgD8t?4Z3A~0AEcU8j5VubsaHyiz^B69E#MXoq0^Puij zOLYZ5r-@*YimQ-5ik`0gWKxH+g+L@>5%wU_yw=d4VPO!P8Sio@LR+Wxpw7gr&r)QM zly)3PO;cGhRqCZY1NT#+xd(^+v9v%t=(knlGnk%EJo`rhY|+gf1YDkAYW!Y#DCUqf ziJ8Yd@x1Jtdd)GNRgkEvkGxlm4U{zAP6~gS{j|JAk*-%r%3u~wij7^X4^x)$OFBw2 zf3F08E9U?94J};%iXHdap24-sBXN>|xg$>Bm);Q_xL*r=ztMCM)D&r6iEJ26x9o(v zu4j5`-7m(gc<$I!kEI*ouegM%S9-GopRo6tY%2Nb@o1ywjk%?c+ji)nrIg5L&T&t@ z=pRSz0aSskOnKg)Grl0o$XpqK1#21p+5D$OS&%j`6Gz?HE}W52Zm#egoO+wUSw ztMaoi@`7gBBhTCnp>pf4ZwCAKxW$aF+Mtqxc3KnE9ZHttu7*|9tHu%&?DJZ-gJ`tO95&)rOg?*zCwpijhV*#3zon&YRk--4Y(YaLg4fCKdC}DO4sM z1(Nv_wdR;>gj~${hEEIcV4y&#Qf!(oBGK&0lqn1y-i<}4YOHz?g|p4+M6irz>sfx zsf$7QBcV-Mb?_w$Ka`2=K2iLx|Si2f6A}Sdv4%UDds<@g14b} z<#yR)`fu{*juJ3bXbM7WMV5v7KGz{;f9wTsk<39UPe3z9+H5W_?a6DD`TUeIW~0OFxV7jNx%-En|qF zE?+W;>aKj<0B&3!LMmXj38YZ|1XyDrfo2#bbu7w_LpH|Wi=-|4c%l^8w*(WPph2qx znd^%-Rv$$L7s9njblq5o?*WA4hvq4~VPLKQHj|&a>Nf{hMfGosQlF}bd3H zgcJ`e{ys(kBUc0wCv}QCqGrhnp}Fj*Iqolg;Ka-gQ@7aAErBqrzxJgzhY5`OhAaOYH-5bRbLb{$dH?0MR;PuXqu{k zdwqh0L7lhQRm}X@pR%3A;sDcby+KJ+eP!_hUivc*sl({LF;JI7Vro&6_NcW~)2nY| zgEZ&J>ORX>)tPa&T>lP;@Lc?GXZ9Zs@?9DwYP4IysL(%TDu7SwX>orC&ix155r3$- z8=0@wMu}jJ-mUeN0jQI;d1{XEFX$(yi6EyhvS-w?XlHMh6#1{sMuu5gmK!>ZsoT@9 z$|b(jNUaowU$NhaUR&~da@@3R7@di3M2>|2e(A<~m+rQjvZK#(6P!5y-@<{NXuy{m zvplEyIJ=TFj$!#J=S72BaVgJDuO92%e%S==vgcNu4!8n$6mGYYF_v=CR?F-!za&AP zvO?`A2sB#*=ZevvbHyD5ni`gu%>Skr_^eR9DKego-AS7NtmSQR(!ehkC1na#5loy1 z(VHMfohjbd{q8)}7!rw=(q%*?YHbUd4F#v47<-(ajWi9KXZDb*K}Pvj(WBEAV+?3+ z|Lx)fmUhR;I`yqcKFykeu^6$NmCy&T6cmjmn{zoCndvnm^t!PexlnY`7*BO93RVWJ zLe}Wb>0O8SxufZ@@lHNj-oHgCn$OhF``nzbh1&z{i@%p?9;s zkFv}qx|nf|r#`u7d2cf%L&i>vE|XB4(Zmr0Baj)y0@S)CE$%TmPjiO0L>C*V6K>GV z#Q}04uF%9Yf?Qc{7)j_!ld&3_hyB64?1A5jOt)&7H+o`EQ~;OL+vEsk)L~LG-?Dwl z@rV(bc01=sVSPBOB+)1Ns*hCrEnUqFfcTrzn@~rh$bOe??g3h5w@B(xtxE>Kg(0<8 zx~y@!@I97}sE*w;nWe2F3~J{YAFwVY+$M69X~*fJBXCY=LPEY-y%tvg=JoB28`qre zChKVJ1KBvE_y|{jYWOrwe)m+L)To1Rb<@Pb3u?tRgB_hy5qHXt-ldeAmh;$LZZV-m zy|Abn4Nl~?PwAy3oNGTJ>Xg7GVy%+TrbGBdof(M8PoDwKur6vbHn6MvR-q!7KZ<s|Fm!-eC_Nku?uk%_i{g%+r2mn4eFO&Mf()Zmn|M*YLu2Ke)ML)?1q>~z#4m8kH` zEDzNH3Q2F;Mq`*y-g;pNCsC!A+09{kxCy=yg3sb47nYM;HY1oaNq7iV=%Th9!>A6# z^SkF|Lq|0m{B=#$F4}~?@(rT%lk_KBTUg(c0=*JYCK12UInnVy-* z(nc`D++&5lcPqz$<-j9VZaT0g2}rf*LssOlhV)GLy&c5Pv0Y$vENrD0*jW2P^c0Bg zEPV_=Hkdt~7_G}=6mP0q!&#Vsu|Gr1C}S;rDhMy@wEfJDbD`cWK*c5b)Yv#^o-o^LLihoDfo` z%-O??xXJ%~cg+izpV)Q;bzNSwPXxa&zagG#HodY9!n50)q;2Nac@#BK?sLE|)N%06 zW{uT(So`3;odUf_yLgqb$bzB;A&5WTi!9z0|5Mx3Pac>RXs4Q%Vk2gFgr5^zpu=1+ z`B=~RFJo0sa-h4J*DL#DsAM65GMl*2*+!-p%4BSpTiv^6R*3_%&320d05E4|%&(jf zl5yyQ_Dnv#oL9sa)y`LG;T#gX-u{Uu$)s-y@UO#99vmpvu`G#p6bs8N1r|^#Ps;{|DlKpJoSCyjVgs-veYCWN3p3z7OkKiA!j~*QNGx*F&UJU7(@qHVyD~f)IDSbI!p1 zyz8%Nyg-!1&?G+6G&D9II>8{U-4NLswKuS4u%UIZM8OrS3CcCk4nDX*;+ke1&*gIP zPlmt*UeH`nVjA9q?hi5XY`fz5GJN@A%R)-rm_l^QfIMx40Y`NXlVEa;Myo@y?AgK6x_5IKjb$aYVf9Z(WL7XyP_O+R(*JPRq{C3@0BO1EV{jBQRR)^g9f3L zpW@MdIK6fplUiJ%2sBrBhj0N2MUJ@Dg z8R8vV1;Nj8xmo48lbq;ME)U?;oBX(=YYD1FJ*!-cH+0kwTJSpr?$4V$Ypq5#h! zc!1jhv+vxAEbM~jn}>h;5D4#^^7$9?sBOX*uz{>@;*sm6*&t)uP07?1$AXO#k%-OP zvzZ1)Q0kv!7?b6|#8(E=^O=)LZtZ}M0McnufG-uyDN45?v$?bDNzcffKo9jR;``!e z+EeT8GvDgfGAUY+Anz6BtP?bjw7N`bUzxA=V!)H7fVJ@jQUM(_wze}dk64}{ijX*P zP$p8%U#Gu-e2-c8wf*w*&^b_K--G3q@(Fs(Y^ub-#u&a;*{;+T6l5yf(uo;*zbNH^ zOkhU|gqdh3X_UJ)Lu|#IkNv;W>OhxhRgqQXs3N!cc8CO&kk28Ok%YM)cvOHNerD%0 zd9Dx3j_Jcx!emCO&UKU{!HyC?8BN63>>Q+0>7lQCi-<2$3Hm7rFzD}QYA zb&J1(cjJwlAy>oh_W4PjYP*lu)NS}=rZoTT>7%qs^S@UMryoloD_cn+19HG10$Zc5 zEj;kz6<>;Nru}=6OXNvlNua>@Sk(Ja`%0J|20az-Xs}eSuKF-jUWEfSA0}-KCgjS3 zm5uqpa5^1!&KWpaLRriP)2FL4cb$r|YB!@gh$VH86X1h<|*~_9`Knw$Hp&iupNDPLveewa7Kz zPTfQX>-&UJnvT`}nyc@9$@^|I*u7z-OZzd0T-^!wN0Inno!tiSGb22>lxMD4l=h*5sZop}ELic$8EXVllH z#a1{K2G$CQxKHV&z93E)4@ZtkZLc(}COn@|8k)3Qz?O&)iXd5na*PZzhfj?TWVuq@UObKEyjjuad}D(dmeigbG)|f?`IYvP+vZ?G(|XGAKn!!t?*b!b%I194 zxI2H{>f8J7ue)B=dQ^ox_;DX#O2gykYa*ffQnCc9ms$!hGQ=Hm?dI8cdRb7@L=&=?k|WGBA9;-A^_Fm4`nKk3*s7F6e9C2n6IV+jsFQ#+ zdtUF9mK1lAPC4txJ6jJwoFvp@fz^ewPZ1GK2JLld`WJ+Usow*}Csp*Pp3!Tmt>O&srfnY)0KSYGGQ(x z(VNYrDz$@FCgwllg<%OIh!bWhq=(W}rCM5;)S%%3&kc~j7^h9mF^dy9{~Sw)yf)Z} z>WZ6)LV?Hs91)Z0vKOiA?U$IzEaG4}Y#Jt$V&N3VT;qZZ87m#q$(^1cY|bIk$Gq4YC&tfLhi>di znfT%$>fOFx)J`6+W2K1@f}J6{j+B3Fl44$HCo_(^PIny{#?7u1-lScz2j{Zn1{HFD zhlBPBHNoYRMb)sj?CGD6lTe+5HP$fLp|c;WzR<2*PBhu+tr#1UZCv|b(~>5lILURG zDlJXbw7NxMj1WMwWWICO_Ic;C7a6dL`~FdaO9;M0s@A033KFIE5{l-7w2sLQgGGk@ zG*7L-@SGp^5{KQhLJf-nh!F$I?$qDPU6AZ%wX+x=zAk}ci4{s_dc@wY50fy4w>>pG zE;st-?sUIp@>d7N2Yuxl_@qi1Rjy!fYuXE9EYQFMM-l%D$A7U<@JNAPFbJo`IFfY$<)6VusM zEtpF=**l!6GA3^mQdwI}f<4Jm6YncCV(8Kc6ta`DPtrJ2E7DjwWU?k2$vrFZkNxXU zlLto1BTyzTL)&4EwbyGqYOx( z(MXVKGND3EL?J*AoFF!G>v1e3ox(dDYZuli6Z+pqJ-|U*L8wzoKJo8{sAC~+>BY?1 zcz*Lf?7i&~!u;!D4(|Z2u2X=M>=}6Z_{7W?Ou}2h0?Aw>rFLu`Hd0wwb zRv3BMgLo^9_5SAzR2-lQC#Wy<%qi3ugb}Q{KEPei|5v&*g94CYV>nV$FHrj_z=$lH zdTV|}ypsho;`5QQzZnZ4>%F@39ol3}l`8moj#9XmPCf3vDz7~5<>I1Z6}v1A{n%u< z&JYl-!CNQ_lSmLQde zOQSnzDvcpqid&Z`x00X*i7tULTBe4gjdp3@$6BVugQDqL((H|ar! z7FQMbp9ZuXg0IY%*&zeF59kXbWQx%3apDToN}5fA7dv&)tV&fuLIp-!hliUctU&;w zzER}1xCbyrWNL0Oo`0S)rt|Ut*B9{JL8a$Ve36>}Jb!w?%BHM1ZM-;<&Z!Yy(&n*| z5M#KXWxQIp!bScs;aGJZ1e*8qhp4S$9u@KIe)(4vqEPH{4+OIDS*WSFCd^`;1<)TdosXEn8C?B?6Qir*`!B;;&P3?iJd97 zNynNus|2#UsLZxHBWP)!#hPk6vG3&lpJ)C5!woH-LJ%UbXqRsVb+oVE1>jz;3(C+d zPfLZjxlCh}vTqdNFgOZ7(4qgB_Q?GQE9+;wzYr?oh0qZKz9@IT=}-pp%K*wPgE%D_ zFhzhuBt^)crX{&c#&){Wzhc2KWYr)Uq`s*Qs+)~|#Z~^8-E}YfR~9!=#tl4rrWpl< zKL0bu7GDs&?$ZzutbWP^M(VZ61I^4oTY&?y6*!{jG9MrlMc*N1O+cc4!;v7&==%C~ zzhz1EVK-LkkWES^9&H;dW%t zyfEqizV!tH#Jw1v6?uRRJ})j||6f%tB|=d%7K+XWWGDlX=wFTSCIx$rcyQvbbmWw&&rCACjOQ6AS}=@;>m`wW`EpACIIun$mjbHtu91}N`Flc z)I)@C7V%#Rzmg{x>LNr%wwyg3qYwhNPNFND^5wVxvK2>&t$dW$=7J#8n{fXh4+ggJ zboA=($30rodS#wpuI0P(17bU?YIH|WFE~@|b6wqrOOTUDa6bc|)hk;q;=j3CX zLKqFc4a6z3!Loe?49`Bu+Iu|5L{r79pf+BQk+ZWxLJPcCz4GJsdf}F&NuSEY{;ktn zPR&1eD@46}3F7RVP#fI1ha4;i7WHDS+o!+A=nD!!qEGI;rb8IaZTwgIodUL5Xh!z< zq8cpZo#e>2)Q^7j9V4qzbN!cE>MJ14`NIv&%Ku^PEuf-~zP3^6a0DqCqNgf+k{I7j#sL*-sogXH+f9?9Hm6UJ!ePRS2hVH_pM#Rv^gHeavMC_d2I7^iRIOQ7|Kfj4Y> zz!Pi^L-vawtWE!dN95haRlATxJeew;l)*2+17m*Z_#Q|@1J!j?*Dk!i-{vPR+wH3W zG-B`er;C90+9Ko@fH5??XiKoL!e4<0Qku^!9>Leh!GvgFrwL~5U$a1?b_nIf)Pq;w zy5Hx1{oF`Ieo;O6O+rm*Z_o%P3V{3I$^eY$o#IS)Rb|4Jkvk?YbkbnFuVZA+H(Uck zZi&FWeq2j>Z%~7-o!nFzu)*!e;H8%h?KLrhfuiLHj4SvMIh6*gf92u^skqhNakzyY zEX(VO&&ATs@eYDh4TAgd4teYKCeXYR4AT7ENW1|2a|lKbw+r=qI$93Eq2tF_zSHQ= zXiDxhpg`4U?qg8g8x@E{0zD1&RsMPK9M~FE57%A@4$8cl^sFsyb80(iVWBhg(I!Ao z6o0FI4Is~yjM!szJpgjr=82Hz@jaFsT>zts&a)gP!!0~h<*9s((bK-WWW+Km+_g?1 zdn)hR__uXky4vgKu(`qQDNx(Jtyi-Ds2iiEhyr?Y&)sq^W{bT5p2rj;$G&Hr_phH= z>8O5B0O}fQL<&wn0~`x;j*oH)q)VE>rfd;0rM_iSZJYMrP7A(ER{5FF`nB+iuE<2nUv(+e{dh zIA~>!Dd-VO)YZdy^=IwFJq|8V#gL;NqcRwI4Gg9LP-7JRo>w@hfpqd~fzy*yZdrR= zj=Pv@HUFhX$_MMk{rcZhq?`D&hJd`{2B?EnK$fjJn7V05E-js04y54p_9F~iSzy&B zLDV_91%BH$j3%vr-Uw8%bq>#aoGyh^166$+p0c#wg$P@uW>xcAx*V(m9JM8hD=n#r zDc>{rR9yqqt3dP<{J=d)-=LJY9!con8q$D1ZtUPw7Kj*gd;eeZnlta!eZ7F5_pet@ zPXb188Og-&1_Uj!87GYmWP5xS&vR@&EEM2ls$lXwXKvuCx%*nw5fl3Ku#^Fe?(whc zX@?wt)!K9w|HuWMlT7b!c>?;!rZ2xeT8dW!=-<9~oY_X{pETVbEN+854&H9jM);`2 zZ{CEitQ)k8ZEjZ#SZV^B{{Y4es@xkcbC@Um;FBQ>0m}tN&S~$o|33%ZWQ?%5WiFn-s24kKTxa{;?mrXd4Gs*^t-8>CT@jn3M&TAAe z=l5in`K52)`sam9=V`GFnI)jo3V{mqUz~LOlO`McAZ3>~wppCRaK3>N4Lb}Hc54jl zBfcY+5KLxJaNEaE;Z(#QAbd%BhX7!1`?~}@;us@}+mNf}4Xg2;#6$h#a?dV;A$ zRr}LEgK7^j0CxCwI!}SlJE$rFaEhZFc8F=Pm=u}Epe*4k*#w8e<+OtFaUts%jY#ai zX$6LZIP1%!sT^aLqSHC-NC&4iBa3co=ar1(WfTkB_x} z0r>nc+HSHl?FE`H#a_}&4CAZsB?K`av{t+x@Q2lZJ|wl+aS;dBr3YN*D=_6;}`OZkiWjgLNY+~ zIb_u^ea-ERkNoBAUqM)_Zx?|z3wyA!8^eiki0U33)pm9MJLKq&t>nX)Pz1#TPNj{{ zXBm&1LD7|9cFnotNj3l9RFYdBO`6Dr89^#VCh2^f)HB zM7mx9wHcVc>H*|gE?p-j^?lKKFB`9aKqc6C78s3Q1JDD#7hdw z8UgPiwFf{m7GgZ1Qjl0e8&KRNF?WH%a4P$D=SGF#cCp-W50%NhvdDNJ!c|^`LH+*O zS-l{l`3O!S6A`RNPCfvkMTOxGJfOM#Z>zl891Zp^$O5-%+L6NPT07A0s(6Waj#+xJ zXtxCqAZ1EGuC!+dkO|rWC!ZIninDzjgYGA@U1jIi;D$$w%#~oPR#GCj z*QM6QEB&>-w90x7)7@h{$F$lC{*#^C-I;G` zWHHfU3*}XT{jB4BT(?)p{^3o;outCh+aJhdAF!FQzqh@mQ}-}AN4hSN{rS1!$%4n$ zk>G;IsCZ7=-=AOC|9XE}cH2Ai8%+~lmj-VRYnR#HqoC^LXF0^2mJHX;E&8L#Ne6UK z=Lq8MA*V;rBWg2B`=oJ0#q8+nU(0N}>q5+LUp4vB1N8{c9En!|kr{ekvssjJXT-Fa z4!L(@Gye}K=}Jl0;Ske7FyT3qE{k>sp;g3ckEib(j8a4g>An_es zzxXWl{O+qpp5tkoSQLk7^N^f#>a(6$iLDY$I7GZ%BHBO`)q%m*nEU?fJASyD;alLp zW}^A$2(Hvrr2VY%#8N8x;P0$sbO-S%9o|SW9%Fz4D2P<*>vqCxH(U5HyT@_V*k3%X2hsAH927K>4O@6IE%Wdcm6Vr*Bcw<$GkS~2mQ(OHl zWB#xxcY;s$F9;DHHicOq=~w&cYd`3BgZ%6hyqT^XRW``%(HR${Jn9r(+%gXg5;OA7(b5tNIqD^Ln zL~9ClUgS|aFme7)Y9=9{%ZbLsW7)9qXRp%!vy5pALiXn1bC2^3R(u=?A@l(}*s_3^ zU~<%JfgtMP#AVALz{BwkBCF>&_sedl=jYy3;~L{E`WNycC(!x;&@rR6GIcK$2s6b_AgpJQo@Y+oPjU{?%|Z1nS;&VzO|a94*d$n^B_^ z7oPbq(`4W%ql1~R^8FC~c-kdeMG zlL&*5>)ha8MB=4jniBEf3j%k|RS7=)6%heayALuWS~37vpFqiC3`L zA4M>8uMJ(odXK^5KVC#zYEE`nZAIV`U5JeR$9}BU8^Rymz5AaPpuaBl@HU#Bc_14# z{56O2ms2~XD1hl6f^E@Dn^!1=Qb98b3$Gs&`-LniI+Z832nKKsqdd;dK1Kj>Q>ZI4 zNF@2y`!tl>Ah6cP1(%r;)>x^!K!VYMRVY5hcA{ObDbfZNbi8v00xU`hM}-WE5outb zoM6}<2|Ksx6XZ#oCfxw8Wrs#;acGPB!P&*Q)>_MN)I%AV9%YFeQ*}5a!YdB1&oPP7 z&tUb>jx~GN_d>N0_dA6Wsv=Rh52;htyOD;8{3|!@I7btfI5|7ii39Jedix6t-r$C_ zW*B!%)oZ-%2%ra}0AhL3VHh6KeAH$7m8qpqxolgBd*_91}tV@P^S z`%Vz?*+C?QZJ}1*3jO&cRABICc|)lQMv`5Dw&(uV5paF95FMeFu~_>fse^h8yfYs_ z3jOh1bR*-#)4~7^`W2b2oBPH)2%wD32hX%D0Ho>;`tJ|=Ic4_WS$RTU!~#-M9LeP# z$5isHA+_>4yMVV!mnzMS5<~(cD?UiUBO`7hva-k*c-gG&HU7G|wS*eZYN5pFe;EAE z%1306D9UZw*pQLZZ~$=>EtJ>(*YqPPw6SD;!n+;IZ6W7Xpb$zrOmZ7$)35c16EYqb zVimc*^epHTIV-9Bp3T%u0+VTffL(Ue^ari(2+euY1M0twp1$*IzM)YS)3y~uF4#M; zgj>d?Aveix<1(nR=zz#L<~Y1hPM`g zo8=gb?S%IaUuG};23K=z@K*}JB#qx(;7RB}I0(0;qle@Ph%- zhb_CZ_!3QamP~Im;88d4HVB>C1&(azf~R)@$P5kBKHUTFxKOe+Kwr5v)i8>kr2`Qe zgpNLlAy9;QL2L3TtviwG+_Pj%vRR&QFpIAqo|nMecn@N9A8N=jbMR0k8JXW;6?cb} zgH2SanG+=%VujBF*@nsq-*B+hcuTYT2O{c#P8sGjMA&yaE@tSqhx{2G{FI;G3B*Vm zY$7hmcj6yB(Z47mw4ar6C3(cI`p(Oe&n_)76sE32V#CX%yh(Z0wAa-d6b?83=`j`BwrzA zmDyEu%XqZ-6WR}t$wkxMd;1(+$yHo>z&mUdQ`~V>iTV|W5*0bMg1+ZT_HtLuK-ZN8 zA56YB8D%`2Rzys`t9y{#e$#G}Er0$^kr*iSvIW5x#y-lHQApaazZDKPhjP9xv9rRQ zVxc0x(j4eRhO0l};qABl`)5yUx4HaKr`(Ye*-g|5`+*Yldt4#t3AL!A!(mr_rB3C3 zRVvC*X!Mbc^-Bx^G+6L0&8AZ~=7A1*y9e5TmqUF&=IKA$#H4KvMFhj;hEllF;Kv!@ z>KMP4JM~S6XFQx!vo-i^B_$_g%eS8LiatMamd8ETpffJO;1-wv7V~z=c*CX>cE8er z;m5l0TC8UjC@OIul2#g}-0gnCP|h1jJRFl3gq$*G1r}K*0q1>&msV2UpP_$yn?_X0 z48%TI_TMk%V6MTAf34t2KyzRGL+K^Ec}MOmx<1*}!jt%mMP=#Og#oaETpmzc7@C(G z1TH=ybD_XJBI=*a230jndYaHZW23L5UUBj_ijAIUeV183(3xpI_}zY*VLr8|GuvWA zt3Xm7I9bhCY|_}$L^m3c5lECOmlilfHRC`4_K!0bIGIAsZMCJ~;J2E*_21HiCH#6f zr?71Lxk9k;VfuMePYq^ZyJ=49#ggVklsr-!V~+nq+-F8MY~hEP!W#~$ESfP=uy;^6 z*{NB!in3Bp4C5~Qr&;&m+p+)Ly|)zS4DAMkfO`+SMXW}X)FhiNeTVe1yO(OrgbfKJ z`t~|1>yO0uYwMY~q|g*&&YTKpjUBnNPa@p2 z`*lKQbC1Hzh^t4H*dWa^Gq?K9(gq-u+ZwqALxkp$aSB=SZUoIQWkgnLIAb{Um#RuL zEh-a>V-;mHa4MtH zo*Q9l!6OqKiIT3Ww0*Q8Hx2Mgmyt}BQaI7ZuV7Komj-x=RO#>1d156F3VtPy9(WXX zs;-t^9JQ8RK%1U<5>L5R-gZGlSPl4+9Mabh5_!3lhSX*eely4%z4rIbd;xQN`9!Im zN4PVu)R&XQRz+mq@Ri@xQ7@V=H_n5V=$NY279Pi@mHY0sz25tlPA~oRybYHEp}fTW z$jmQtHmWy_E=xf?f`>D)r%B^MUPO1Yi`>t+kPo-0Z7X&wh+$kS_LW;cTjFkfJQXix z-3LEDN$`dDt(WYn%r!pb;egp>M`E{XAoNK}?HGrr4?jnvJ?kd2VsmoH!%r((ie@)& zE|G)>G$p>b;?xvgf1Poz(iTJ!mg)8A?x;Rv*h`)1`Wb#v1aAO0&!*!-mO_Uf5U)^&5R~t@{l+B?hKSpRXv}#Rrnnb;McoRV$uLt)zr z07{i5OUh}&43q^BE%M1_T=!?<@@OiG*dk-#yQG$KRw|@KrJuP)qz~yp^qH4;p z^3-lk%ru@GA%FO;XT;H7EpM^QvUlMnw@S#QQ0O%5Jx{Ft&3F>kd-xl=x7}mpd4yQcP3*5Q1n-tVQ3-w^S7rBhn0IIT5uW?v-|WsSv2^*A9^u){eG3xCMCIlK zR#nY2)t7Ej!`aU-Pk$pY0e=&MCD`{Q7@JV0si$SXcoT~6s z4lAkkj1rm>7~wDlv+hb&1Z$PuyqoD{h?meKzpRA{k|2Wmh)p&4MJsabk!d0I-=_%{ zT-iu}(riKHr>q^e?}q7Vw!RJ=6!tR9_!G=p_=8efkaDp=N2Tf(R_q}Ej)}}p7l(g>f#Xsh-!*bGyVw;Xrw@a%@-Hu$u zi{|Q4f9M7*#mm#Wg*dj@W{4g~tWlTAu5@IV~gRYO8^H?**}|j!Sr! z9Y^(DbUTzv!!l<NF^K4wTpt|iVWI*g4Qn>RmGSP;N2oWrOn5o ze`-&(R0a8Wg=?=U2c>?N5oG9g&i(Wja5h*!C*hyTP~$-x^yR4UKqz7wfL3K zU~L_#XWrHG-q%!lES`g}*^Gy${@x9Rd5&yThY%N$U$%>#5LLW`uh|c96XRACB6$1c z^8$kdHG=nFS2H~_;@6tX@flf7;0bU(Q{APzY8g-h!Gb=~$}9E4D0X)Ibr_`%I(N_} zAiYkFedbj=4~*sK=fFUB#(Z%e_%Ja?)H<#`i<+R4-wdK%#STv}LYmUMAqR3UI&B%k zM9MGdCjHnTd!>jmR0T~+@}#hv4{G2VJ9I)x5^9vk{0LHC??&2NfPXyLWtU|-+837D z)Ml#{`9*X=s$eKUh$Sh>y^SzUw&3uYsz5fGIs=?Tn*-YUWbYJrqI)X=4duJTmusuH!Z++RJ_`^_A&P#SR(_M{q8{@6r=;e*qytM0ZhQ*oZ zak=ZoKeV!`PP$xk`c;YMZH{q2i|y|r_HDw{6Z3LLBsDCP z2rkYtL5aY;YBh^g1k9V+>=^m(q92o)+8`x$9PFZ}9A&BzV81BOJ$0yNz%DnMhL{Dl zbMOROQ#+cLOT?BpVbTk;$gRO9Y32@f@(+9;EGnqPVV;87iH0i^St+JmN;CGWNs~&4 zm8FuHyx<8N_nlfK!H{uJsTMJTjlscdgS=daiFqgv)RC&?u$ z<+s*$3=J!#XI4^$pRji^%7tquZ=UL)uYj-pwZ@JMugTor>19MtR~hX*twEN4o2;9; zvajxridlQv*WuH?k0GQoVo}Wc0hSs$I0_7x*ajJW-s)!z@y=%SC6bH_3Fp$^U&j)W zH{^LLT1pFl^#8gVvW+Xvseko*ujMMBNhqeO%*L&?WkFIdEQYd?7W@A9uqaA6;>HCvye({ca8$JuT}IFxxf8bc zi6SVmBZw(4)7dr7)nU19E3~=NuTzhzPW8(n_v({hYFmGJ@#vY>-HMIQ!drPx=Syq7 z|KQGX4hFdTZ;bND_I$&(|B#iRnp56yID!?T_Lw6y6H^O3wrdB%Oj6SrK1)WA4*{;z zRH=1U1Ep4g@KUhxsO~)v8Ij$-a;bRw9$Mr>|G%iD+ST*qbPKL-?a*#dP#lfBK^E_z z=KS3|N~Z@g=qFS~>rV^GDB#-M+`ZmEPLhe>wIfaGC`lDW+!Cfnqcf?}{QXMgvnR|S z7mH*9R(@!mKd(hKaeGIRK~>(W4MykmgkKR71L}yURD94?@iFk~DMadnk==$>!S7<@ z1K+7kXhH76l!-DEB86t;vG<<0T61KMoC=8Cv4Raau|Q74X%%N&ws5iX)mpjZRa7vQ z@ZiwibwRcp9JqtYcQZsbGE7qnN z-v2GR_Wk>J_$`X!bu%z$$@n~U){1F|+?<2^jfC>_;C>2s(c&hvXIgApTk+DC_cx zFI)|3NaEH>dLKVs4DMxT8Hg1smk#mT?-^N(CWg(V3WhVYGr;P*gmAR*S#`HJvrh+k zEliSr3U$`0U*#~51 zHplYOR<8;m&tQY@UP2|$C@?n8$YW5xQpRn8Dms`LAV0s46ee@{%I>zs0rF}U~{NXvA-MoMue0~bx0Zrpf9v<^ThEx zEdwS&h2GLM$0Z&S+f`6di2DeE_kU>tq*V-tJ$Qed5nX7bK%$bz*6+m_;CqTVaI!a$ zpwnLY_M_ffDXg~6I=$hvzm6bQ1bf}|S8jBTH{!+HQq|Z=0>6Rbi|PHH-dpBq|Fx?! zp+Hh%n=jp*4BInnDeVx?`)jH*6RhWwGkT%xD`Ah%hABukrnG+moqlI+#ox`DN_oSt zvm|cr6=@qXz~26pRf#|q-P5gJozP0$Y+Z-#XcyIe2tjaqzCGwGkuzUDPotF$C%wE$ zdD$ANkyl}ByLyYi9qBZNDgM4w9N0X_wy6P!dsky>3_Ub^V)&xp<-}tJ z)6diN0+ivRGA9$0jK}MNT>W?P+DltU6Kk=nQn(EJA3^iaBNx8al8I2K@5=DH!1jo)tQHgu;v$nsp4{9C%eV#o|yXSG{ zsucl4N4tRO{hNXp`{{c7#7pUbeVY3xWrm$d}vxC*HHri2U z#tMEbO9QGIWKTVm?Y+$C?*WI$QbQEagqLr#-w2VGD08|cs2??xIlPp>9guO5w4J|F z?Qr@OyI$SWlwJ=X)s(XID@51OnZ10vY-iErQEsI}{yrk;Q>X|9yEIS0*39sy%@be5 zxTn2w{xl!0dy~=ulPC{Wdb?zk*eY#bW9%Ls(lPNBv4{q4_Y20?9)m%I*@c6qAs zOpV~ymfrZQ_ZA15EuMBF8-I28KqBfsE+nXjKEJ)88R~$DC4Gu6aVroPC42lc%@6n_g3b>{!aV z^yN8eEgI><4N?jpM{^85l=L03faGZm_Yr&qx#L6MM7e-|!r4(>!z&s#HjQkKEt zP*gT1Ld_p7$^i$X;05QyofV|lPX(XsZjna zvG-z0+}N-`+DM^qZze}8B;qn=%TAZY!g)A>(gN~^9ZX1sE6QUzmX&nXA&wx5zW%Pg zxC`u01_W0Bq{!)DvhTP+L&k4(g~+nT8b!>5Jmv2z9}8oj1Ik47?XM4Yte2h4&Y{WK z9$CN5IEuvn^DKuIo8s|Kyq#!-1dG<)zL+uS4up&s>14Bm8DpVf^KWDCB0*xyhWiOc$C8h{v@Bm6T{!-7`d)S0uEQdCr>kGxXg7Y}X;c2||t2?*E zp{`*|ubgeiBvV~eW)etHwaPTO@Re&Q9)s`p5|taxEZrnHcKM7eWxnhD(@2N{dLN9h zqQ>+l=I}6($d=4?;NHy?R&X`Kg%yEV@4+>MGdn<#LdwU znBnc@B?mTfM{Uwu2n^nRtl9DyZB=-9lyJ}`yjM+4$tQUR;zJ!f!Xy&Q!2H-tWOso6s;yYoP>}tuBV4N8l;j%;j z-JmK$uU09;zMYZuPHb$E72eJzS z({G7K-r*y@K)JsB&wO9owGJ2{Z_3A6MMUZZz;rHX;?ks!hZ>FKypa+9eru$F(Fz=Rhz$6(6>|}dzTU3B&a88aa1k(;CkR43m?434Y z=l^{Izp;sH{I3bTMOf^3ZQR$tLj~?u6^PQ~fO7(~OiKuUB?9(qb;~D&V3qK(+lhm# zqM%M-jV9^|ZnjTs&73|?Mu5xDMh#ED-Fu8Pd_Bh3i-i@lSmJ|Uim2z}fqp)b`^)#A zp5?QGrfp11*nwuAv2{k!8LX)*q~1{=;c+vHU%qa~f4;cPwzz*F_Uyu#V~h{j)5~%x z-so#1kj5B6J24cDVkaS?`Y=L#+;Y%Li|)Ape_DVW1+akG-b*Qp4UBtl(Yuq}du^+W z62QN=+{Mgd=O3a9(`KP2qvh$Lr0bxcIn>YJZM~N{ixP!A0=LP|7+QQ&Awa;SQ@j1-)nd| z;O3w!Q7Mf%_SeHc77iA?|BbUc%vT|Dxxe{;w7eKJ{`A7QOBSS8{<{&Bz<+T*njgI% zG=y2~2X>Z3|FHrV&=*BGdK}X;MY$U`MCBeW&=&AWOhr=e_CGD7(h$@dWnA` z8X*UxYF~OUiyG6;R4mYtuX4;1H^F_fI9-n>4XK-qe?Qsy!0b@@@dx)0Bb(@|ygI4> zOf7i#PzK9OocE=}Ph4lrS}Fg}T9GRTwl-6Ws)2*=2&?BtUaY?S5?B9n^Sd>0K$%NV z7AyX{G3pecEybk`yyZlY6fiYCtD6)585MjsU}J$d{6Axcm5tn}+1)N^Db&XBK?+11 zfNOoGsR^d89bvuFA_m6158imhZ5oJZU)0FE`ze8^dU(+PFDFEDy9pz)TVB;thV$N3 z0P_RDF$yH}8h@t|xdRN&(hK)1K%-g%#v{+PFfXUn5|I`RBcQN8i)zA*2K+I`2~!nQ z2nUt204MyID&@_!6aL8wIj4%OSOI44wLhp7zSe<|`br#hYlI`{1QZ1C+aF+L z6bg3(3JIS|zrc82n*+jm*l!GcqpR)O*TcEM4`@ZS<~+wv-~>OgGTcdyG5$cJhhXZX zEl-OvpQGO0z)ze_+swaRc{41tFOr%d#W8;{XB-U020mu}=#V6LgRM3vaA5ds#4ns^ zgc$s_D3?tOXi%Y2ZDP2xk18Cf1bn_l5?^d)2S2EP3wl>c1epLX**WhzI7(ycL`JIdHy1Q=5=UGdO<8mp0sUnMmVgj@>)SFwm3=DYa~7u5 zPG6)28ddtcT8BD43I?#FvJn_fj0yVVw;0iA{5~`9fCNaAXw)Lxo&r*|0KGALow9i zW!Yf#!e_Ub0Q8n&2Qd$p$WPmZC&VzRcPAJqWRqme&o9n*D2HHdE+C$((slkwbZZH_ z4!!Ll%M(ZaXye`+Fs#&l02OnH$I^j;lV=|{6!VFRRtG@3mBKQg?N*!lA5G#NedcZj z3clA^Yu9)09%%unW7&sWe$L;+=pc`wC%;0k$2(emUpk5hgg@1&j0Lp4n18JAY`)m} zMt=Rk9jGeGD70?8qH_KZwHK0glQ~2(!)r9A1IEC!<@Yxz_g#}|G3DLdO=J< z6FQ2)y4ScJV|WXwI0cd+gP7NN)K1)&qwaFv$lebaO;5bAy{uO=rF3?%04rTwvRnFg;f&&|ins;nU>-xEv~+XP?P=-8lwTO{c>(iq>*bEAk|`ZP(OVhn_SgD>S`7Y z+NF3pE_ewh)eN3MN38?3*?n0oImum|s)EMwNlw9t7}NP~*Y?c;pz&CLohp`sZ?nIm zxbI5568;-ed@uWZ0>*U(Vt`-N9W_!%#w?0BQL}wX{sC@pFPlIGdyTB5Yd`*24aDdB zc)Fk22g+_+k=`tKp9ip`lc?8F*8Vg9-upD=WMz;5yR*;elf8g{7uKMHWA?dURD>I? zOcQ6uD{8$4H>jRiGG+q8EyZ#kDUhrxF8CSoM|u3#az?xVTtRC{`-3Xp^!<07Zi!3n z0TpdWqn}T%oYw|XO(A5d$9p=oXLjgj07^FZ10)!A2E7!OVyHWioUX9W^8B$m7ZJ~3 zL*lOzr7W^`ICdHiA_XW>1C2nej+87C>GJ>@yjm`;=f+md>sFh6j1qd& zw`k{yVG;h?w-gs;^FT5z@}@v5{M745;BNrvUkHvda6I?9eZjVP2j|2AHK16)9D zf<6ndxuDc6&ULlXc`$1ZT6$$lZ^)?^KaM%Ru)9i^?w(O;FW@VG*QTta%V1q!_EWhN z;}athyW#;h4WiNLFHgJXOH)8|P zHq)%wtB(_WX{D-!AbE)*KQ;Jw%hM`7O*6nr>AMM5qW)|(eE@nNFXX(j{iw1JRDPICb)aE- zs+o{iG>Qb=ki`?+Sp9{4&`h5lr zhVaJ-y;P@jpt)ar+VStA<95m+h7}aNSW-~^lNVSPJ6h1xs}J?n@Y#>@@bb7#WEioeS+2@3h#2b zWr^YKXHqFH40gj1?-;)UW3wWe(COX*4!paU6b8FBv6P$R#UHff|0$LeP6Sv{^fP6lmj$sQJkl#&xdX&x=fa0wC4W!AGNFbYx-X}!K1Wdu6beN84hR*CX`*S9 z4{4T$kdd_S36N<$tmCtL?jELh0!8c{=;8?{55YnhW2~%`?>8;>81L zJ9XVE*?i|wy$+=b9Hg3!{ub6egDVB{B)fJef{LfxQSYE2&g7rRSpibOTddn`xkaAi zal`$UKhApqo@iAFw{x-4G?ln=0znlCc1Tpp0CP@`6}XVVrVw6PT+fcS)cN}O4Q71W zqzO`qdbU%^Z(@$(^Nzq@JY|Aggseprs=f#T0=1Y!MT z>d$&LAWv165*(OZ=AGijGBPbaMb&&hY!#6OTH=>i4-68 z%ACP`Y4P;${bmzjN2!LJNN^(b(>44kb3}@_X9RacVA(OcHw=zMmz3#y-sZ*W$$Dya zu=;m-fCAVu(pt!|j0j~4VLkB^8%fV7&^}ueXb`VY<^V?+R1w`n4 zqC1pv%!wRD9M|{J0(EishWUkxrckX+#GW;Z^mGp-i;@oF9yV8JJ&`SE$k7czUFf3L ze=x4BXN3KKW2tQbgRC6g?&{Kf6;&raddZM9d}Em%-)&|@%<}OXos+!t<>(T~Uh}ec z+~*44qgz-N+398qquad%cy&7)&1Oq$EXPK@n7hE3DlJjIhj2i-dBkYx>aA6x?j;Lx8WA+YYL64 zyZe@j9qQ($^?~V;W!X|e1yrHyBdF}dr#+EGK;V;nOg*+hr-KbwyHA4QboGpsm&FL< zc-h->EpFkb+;ny>v!K&*(siMjUsj-Iu2dl`_II8i9Xb&YSDOz^9}1n!H#SSx8vV zG=PcyIRUX^u_fGlBA-G352+nb0=-eQ@@I=RCcLWIuknNn500O+CUzJu*+%{=XehW` z^JT2=Wfwm{zGkp<&$>oWSK1VI{x^Es{rnCzB9*rb`6Q9Q;LU-U2pUukRl%*XPl|1? z#YhhMHajSa)Q5W8XWR~u)mu>#9B{mS{EVeW^{oVi`q=Y>pVc5TyewC!r2KCy#e}GV z$G3$g-_I|8)&ZQQ;g}Y4^~hkXgR7x*`L3zvWr3;e-?UNORrqG!TiZ9#a?aG-`Rz3R zSm*b_S`#{6&OcoV(kE;+OngMIg;aB<*Kdb%#!;kshY$O=Wu9|+>&6U5WloTpjtZ4$ z{yaT&FrJL=0=z{5l7vhVfLPM5#;_9SBj~c_W%mVRz16+;rmL~p`6+5`VeGdO=QABV z#heItsE*Je=x`0nOFqf2vnjl_FIe(iOXygj=k3j3tTAFNhZk_``t%wNrmPfD%m8n9 z=_w(*vHiAzqfyvnOEx@655<%w2cr=kFpE@Ut<$hJn)l0$TqW%1Qw ze5{{sq2!%|X!0)2=je~dXcy*)g{Bv$ zuZF4AW;*~(%77-pgy})7z#u;1UGFgZ}-ZH zJyovEX`1;ElVEW!$Zdm6IaiU5PkMFuW+P*@KlX2YH)l+BU5QQAJC#E%%Xi%-Sj$X` zqy{B7Mzj*o@}Qk2jD#Vjkq#yRDP(Q7C%(S2gQEx8zo(`^fc zz-PF6?e3HHGIiGX)++ti?01-Hdgf_? z)~Nn{0&||Ljb;wl@7yX*9YwNVOrFrnA9W|nXq^ya7oi97ucT;s8N5pBzetbtuRY-nFlJ633!TaVdMARMpmmYFgOw@DJCd(97sPN)VVM;e;53L#qLpz zDZT#3zxtu>fZLSkp%Ect|2$vW`aa2-c4ueXzpINA`-QF67&}&?fc!v^gC#b|wq#rX z#k=Z6$9d9-#KL1zg*Ly87}xo1#$OJiN0S9cuA=4VXnVUGekd2y475m+!daSlKx4c` zT_Tk+*OBpw$fVu5Iqd0AiU+%dKR@5L^O>z49CDx&ZA6sKKTQtEOinDVV2WoJ5JhB~ z6X#@}zJKGJ+V%w@3$Vb|(__;`i2i3Hmp>w&a!^ZybBa9;-S@vNkLh}ilsaga3FN~v zr<*8p9D+fLWgDwNMd2{VnCLda@gj?5rcOrTp;Zk)A|HLQVN>`j4-tosPD8VXjG7j} zk+Dj@$|>g9haax{%-zWOa+}C+E>>lV@gwJxc*fzPJv`s?$sJDWf$ED&2@U$LKa2z% zf>NLw4ao(qAfg8YK4wb>#2~KA-^bs0rWp4}&lpO-t~9K-6qnM+{w+d~FB~BfblkTB z_!);1c{+BNOWJPf{bg7fb{R62Vf+^zdE!+q9<{r@+7~(`X4#-9ATPQ4fAW4C4a}Sj zgTy!yxTfAP%OJ&4Mgq^wWe@$1Bm|wTzA@XXZbk1{#q&f?eR|b7J-fKl_gd?07L)$9 z8F*E~8$bF#%xXDg>5I546d8xz^|G3<{L?4BHEr{joAw)<8dB$gypeJA(?PutVK$7Y z411M)l#WBw zid-k+%&f6wEJqGbWj#h`?&)A)Y@_uVRr*88PmY_9EY37mS%12(PWjV)RIS`;Y>H;) zL?F-rM2tBy3!Zv=+Ir2Q=!9Lzj&Gzi!P&i~A1;UW;J0m>I^)&%I8y@KDLvcLXQ!OI zQ{a#TThwyo)OvA%36hUf1w%y}dW^>|=dW1H(Tqa+*TwPK&}qY2Q4-~~`=Q2aGloT~ zg8B~1ov^MOp5q##W|pDMqquX1AK!;!wVU?cPBEUU9ey|crw^j`<*nWT^_g2`*H*4q zsWeY?>Z70bKRija5+5`lBxq4WU@ME!)}e<~X4e%{PF6wN4Gz9qUqyi!D;Um0y^d5tEn z7#ky|-2Dkq@6-*O7+SW`M{SXnI05^Gzh8Q$HEGKMs5q5C@NmHUy>1=)R_yZNeT^hH z^L-bsPk$8J{#2QgRW19nBT-q}VrVt;jucvVF4UE){~qNt!;Y(o6F z#LAAY-|Y0;zh!z*d&Z+Xg82N&1eSfSAvlFLfN;Ll>1dP^Su}nUO;xSA;^#be zQ8?+df9alorz6&MPuG`x_}5S^p z&WQ%|BJM@0IKTy!iJ?=T0uZSIwV9=;1Vhg0#ec- zAWAn+7kKx9U;k&m@11#Pj(0B3J?HGb_S$Q&z4o)7 zHS>nn1=X^+_>CBGe5Nd&{w!ZLtKdAMCkAHF>idy66D@J+qmhI;!XNp>i}A?uaP=kx zUT;$Yn`E|iwA{PA_ott*Y4)?RY;&qdXL!n#s`-}rI`)JX;EtkkYFI{4)vqLM3zHcE zIIufD2Zf{EsU($hkXh8NfM2Ip55s<>h&hZT#l0c+8;Kw-FKDNBR4jr@0SX~m7}Rvw zhC?Ebq~%kyc4v!k5mJz{GN58oA7ij~+nu%w@}8aX%t+mK7Qbz` zP_3Y2C+;oKtAYb&OcuaC)-HQ;%1qSSQ=f*J%~5aU+yq5UmK}1_Q&OM6+=Iy4k&84_ z;GpJpKMmULQ&y>Q!|u1VBo#BTPAzk)_BTEUA+&r?P2P_0y~E7C77-(-P{HggH+D?f zJ-At}DMJ)q`xq)v*cb3AJg71Lj2$JNi}aKBvc5rNbHL`pPKC1RrYx!#4>K8CVQ}(k z$nOI_6gduuXl0NxQXE%S>uIo@Nu3b?V1jNM^Uay~sTIPXIO2^S1uImv4O2^=y*CNG z>ca_(hR@TH`^=-#wH$>l)hJQ3??4((GxpxA7KdCpp+Dm<8@B1O)DJ$uURL!xhz1k5+9h5mA zMISN7`v4xM7W}Quvi#{I8Txi~6f&-D1H5_pT-Bg(#CEj0GLAKuhs)1z)Y)I8-UPi? z$4q0Es@zWO4=yks7y6y%E9E`6b4l2W z$xubg@u8MaNj3vhYIK5M%4WP<)t^voCGht$FXL`|vu%HV^mNL|mq04HPw-s~<`Z|_ zvy_ZQtzaIq4|WsakOX(#_O)W3x5>Nvi4hDi=M)Pz2+%9gkuH^F;gyB5OXarX;a1qdzL96n+?&wdf>IWR zN>AQcwX2^~TVQL2%}su(WqVO~)ui>}mOc90kEY;|mv7wg5?>*e9$eewp9Y``r6`2})0&cYoT+n-7`t z)lL}C@?IRIecJoBpm@e$v^?v$Szcb#@{`TB4c|7W%{{rm14>_^VRba;)J_z|w&%Dv zeENLCrL{(*w6mh86iEgcE4}vuce@}^E_=Np+q!UX(9}%U1u~aOoMYfH>v2JRe*cvUHkAe!bfRxAKLi^avr?NDZ3NaYpZv*b-QBki!F_w z{B47p3Tm^)smkr^<4IdsM`p|%?vl&O9=-BEMc|4J~5ooK5G;c++n6}Sneau9XTqOqn%9Xxu=@tYqX zd2|Hd4CUW;t+e)DPE2bFuLRL%l>PMITCmTE9LF3)91H8#L{=UMP>vTqQCPN55hroJ zXP}z5x?rmBZe)~}${;O$R43rGG^iqw)z0JFf7OhgOJi9}_4}YtDDFIeek!EHyDvOi z(g7lu374yG_E=7DUn`B!w>Y_>dZNrb0G;GqJ;ltf|0&bToxO*fA>#;k9nGeaVnPgF z4m~m_@w)Icw%{3|HNegDp+;cRZO-ln8e^}zTMNTYV$F5Oo36IFA_cq7;tL%f?%S=` zuTzAZobCE|c0*h$(^L_O^+Y``x$KE&coV2-aqk?HH}`cd>Ib3YJHn#s3oJ@xYSDyz8-S_mJV1xH-FdEe8O>0b%!lNEhbQM)k6NJTlO=&Us!4ZR(eUsbgdGaS34ByIaof0y3;P7 zzq8Tsmg5s#rxt!D`1I+|6MxZN+SS)jRV-nv{S^D|Pvvu9FS+)D$npKiGD|nQ#rkhP z7aiWM{VnhDF0o$7`}ye)vEZp)F}3lsc2&>t(IKCO@~IQ@C4L$2FQC9*=I2e1B$o|a zd?AW82e8eZOJKbOK7mNu_ie^Jnj)fDicK$3lRb9;>}fz=i$fABtn<2- z_K}cX{_}z5QnGehyoI8Dj~DmSU65+My`-wsAEF;rhI{;qQWnWs!gNt1vs-9kH_@at zN|J74_P4h|$}PMYO$oX4Bmi#QEzT}|wN0~foT{uxxc~;|Dq}g#bP44mX_#(qA=ixF z*6(L;Gwyl`PPzj(X}qGdI=Npm2QcaF-QjJ$K+8Q;f^c%AF2~G$`VdU3+=?>+0+jSH zf%cwUzZXEI=MamQFQe*kpqrysXZy}4)xM3gk>JTMu@y!$L`eZl1Lj_yCmYsy`Hahp zB$Q?p4+hQ3M|po>Xw4UNo_rBpLxwg*_!g;fR0P~E7*Js7%iL#FGHG97N7?sk`nn9L zn68cIhDj-F)@*;N1|@Iay|d7uoTk#fcu6Nx@ zERvuPD*KaC4N~Q%>tb};!IA7~+j~k)%p%zALY!gUbY(?_*?F|?BqA2?`%;^sUCFuZ ztp?l>RSNxpWM;0oN5x&%dTNW*mcP-f22=3G9F^_z{sE&^UHxdEhk9fTCNeXRIRNm4 zQ&!Mgpwa+@ka8ey^G6_HaFO}n%gV>N_zev@PkhlGi+JM^fHj`ITRBCQwWi#C(Zvgx z*Z=1*EftR>TY@!@jfrRN)FHqUpy`q<9r%SaH5yDVwGX^3G!lr=)NfrTL82XdBx0Zl zwMgjV)tf+q$p<&4k>IBQlQqs@;yEJ}%ES35o{m78Is3vSLBBRa)u*4{cF>Y4vM>rBs%z?@MuYJ;$frWh-0;2Av_aN|mC0IRh4RcwZF{!cjE5Cm3z!L)*m zmkIN{Tzy0;5mWV z19Axs(Gb$23%6(XJ%muqgCO2R3L{4Vkr;1=s%7Zq3{U)8W(=P7CcoOSKkWx^Bu00GG!nqv7Qu^sIORDE}?NIZoq>Um@9Y9P!mP`Lh9-yh5 zfE&sE{S<(W1;|pA$1Ikp>QbOzY;3F{01Rw|x+4VuwC-${OHkNC6M|0`H_$cn3YPND z=YdkyV6ZrF^>QJA+8{0`wO^ggsQF#3>q7^M2Iaa8bF*|Tyd-W1Lu7R z6rDy~J^SLvQMXYiTNJpP?oL*qE|KaMSBc zkw`Sqs1KuEpeAo$4Cwax+0?m0*W=HBV14^tyBi!JJtp_*(Tlt6e1`d|l05D64!r`AvKM5(lEz<__eZx7J!8@>P zXJ(LunEN2~rb`+T=LHB8KcS&3hQl|6KTPREDm|9gb5KCfr3mB{@H1T`u>H|To+t=X z+G*mPrAYS%z%S+EsV|#sqzB3Ax+UyF(b^PVk%Pj)mbj;XLnEX83jUtT4Lu}4LCiyj zDEZ)Z0C&6`(s6<62YY`xplkO1`z4TG8r58)wO6E~=q;A}Gh5%k$k%br?fuI>#W(ao znzk4+LU|Yd1Srkm$8C&@83val0+Wbj@Kh1{lY$l{lpkWpTtHjBz~^&m=4q?ChpRyI z?ec1SabkJRJ}?3-(kvK&0`&d5Ic=)GZ2g?t#h#09SfU zk+H+@_Z<4a%7BP(cudkzd&6d^>qA$B?>+wU&;Oh|HBgTxU%c7@$*usAz0~hI30b)` zUue-X`k>8t(IFH#gg=FVsMj*|1m+=|&YCV^9c$DF#?oOg z;1|997vPqe=ME}|Rz7Dwpl!xjZVyO$5OU4m%U($2@97LJI_=$H(c!6wS~OMc`u(Cs zQBaGX7HP9yv*&uZmQ24jTz~fU5PZaN5}wpp7dB#c zZqxigUjgc=C)2j1WV8>N^b@l+>I)P2803pMeGcw!y7;T%QVl?=av{rAkGYFf9x!SW z!`Mk6O|I4ZWL--SKuC2yiv5YSwV0UeV1C35R-J^Pa{>4f1mZ+Se|5Y-zN5 z#=Ed?(oC;Vu>2|7FY&L^Uav_10D^-PK{r5?r%MgsN%Z`od=NW@bywcF`}zw*s(jnB zU*;GGBJmA$kk#}{+2n^W1BBvtr?}KiK}b;&Akcdcc@E!&Me@Sw2=b-309J_0PVz6v zyFMeZ64w>Xyq_Z6+`YR-h56xk;BP1#00);3nGYa}ea)HsrR+%&C?s+{YP_ZN1tJ=+ z^D>q!3LRG-1B}}}tEAet8!tkg1P&nB=rm@K&fIEViL&+fv>;U`qlai({F+ps)d3k( z&V298n~)6XS0AX|+TPkYr9-rea%MxV_P~f^^v0Lbi3=|zHrLapDsb199)hw`>P{cH zHMCrWk2G#{xz-;jYzI11U+eAWuCJ+>4d!^QU4bjz1=>8Wf)|wY5IV9>QAb5}KF0J(X3Z>#VeHv2wtadDha~ zxiFPgx3ER~71`xszEv2&0gNO31Zl!%mkck50gmLMxzH)6D|~@M<0Bj<^2? z0Qa8!3jqB5*W(4!a$;`p?GP&R4v6ax&n>zcB3_;ax!Bg5ccX+203Q1K)bUXH%cZM; z2iF8JkglFiEYMaiBzD962{Dt}0b?7+hDcRkTyQssV0~5j=gF8U?tbrO1;eT?kCu!i za5ho}QA+FT7VIT`o-1_A2MhQJFz~^)-aCmiya#}jDHtkJ>e58wH4U%`AE7XTehqMi z2{A*9Js|*(^w>UdcJp1A-FrO@wgHm(9>p6EmUP;jb$V;cP+QmPu?Mb(=R2UI?nU5; z^13d_5@8>9y2VsqiO3%G5%WoEAKWKMP&zvY6vmQOPtTxai7Z2=heyujhKg?`QJ_`rc&8e zY>pONY{z`)XxR`;`%@<33sV5JNo8HCx(z4vOhb4WdIx~nFM?{_-tD}6R0Gz_T_O-I zUur-j2kdH44xtDRiWuubUhFO_ACGx zKRf(p{*g5(fLMGlM}-^&xU^+g02#d&#EQ;|MR)F<^U9jpoh8E%+Wy96*WQ& z(dtc8gkHa;LxyV>`D5fQG21DEuqn!Hd``x$$AR2G_#KM+X+gk|+stn+SvQTrjqN#& z0?Q1yw}gUk+f~PgKt_n(8Q-F52;B@Qb3ILGz1U*3Y`mQfS5Ec-&$I}|GiO6jtIxv_ z4!=0kRJ2~rAz29eOyWgwPlKD_0e(Qh@|B3jbx1qx- z;hm)|Tiq$Oqwpu*F{++c>;*z8-r3NU7e+EkCz=L}LK+b$fLKj=d=@(@sWw+-t&O&Y40ds`$98~^Z*DrpAXj9dWu!ZiRK zpMX*kE-~{TD3wjjuAmhF0#om=8C+GrKhFAddm3-Yw~I2f>ezF)aW+CoP7HTb^55w< z_dboD$k@Xvb09BXyY-blo|#>;yB#rj2Zj4mj7>%~QdaftlV!`x8zf$qFsj_z@ z_tI&T&|wCP7+YS=3{AEH$FvQ;Ae*nB@pg+C1&6tfW8&E3x)-H5GB@3yZi59zG)UK? zLl`U-!O~ZSGXSXCfLPOrSZ9+Vx2P+3!eOi#0(eMKbuGVHO4AO+FAw+ZpYPz z$id@;Zo}T*hm9H1SFTX8%H5ZIESA+3)m?Ax)e%!qT~B-NfUK%_oNBLfTAA;>JvDyV z5jE!XsY^N;X?<*~vAn7mOdlvhQEjy75yp!p;99$?Z{0(zNLzvfqF*Jn(^SA66Hzd_ z6+r#$Q+i87%rC#5ltVx(sy)7DF38~mSb=!9ZmXXFI#^u*VxM9I)#44whxHtl;^9HL z*T_sX@}I{ObaE2)w;mjR0ib4{Rg`ApuJmevXs(qhjm&l}@wxPk@ZU<ROofW6dXK^Ti+r`w3puaexzvbfr##Tno|yyB>Bd> zF$wg75$icmnEV{@{8yl(U!z^)&5CM}_JKi4a2QbZS+;n4ZT#?E+^?{_YoFD*I1GM9 z{*BgHn|i+Ut+L9uNiFkXc7_cyH*q`)#k&6S{YxhP{+kMhYzCE@f=> zE=a?$Qdp9m)Ee>4LgNoVX8U{vVBW{d(Vd;##Y>1@Pzv>g>48R=n~TqpHW z=@|7RSuw94AqHfVG0=!UaEEYlfYh~<7Ya|L#uvMy1d3xHGC7RxVDb zVB^DCUeh7{{A6g+t0z)sT)kURP+XK;?O37ZTcl6KS>k+fI9NoY2lA^oo&bMA{6oQJ zj4-dpxiVA4Jp*N>;ccK^RVqd%fHW<^nw*)81S*NUNrEP4jyZ&(d1&-W^^uGs!2IIp z|GFnhuXS@`2@t|TTQxg~3W=Y`)E~#DitKJTOdu%CJ3iFy5n*#Z~ za?`%FNTWwd2AOEe94-}C`_yi`4A5BYM;C|&dN~66WkC#S zEPI@ariS0?P6e=&`txqSJ;%9o?#x?O(UWZv&FHv@`#~|^dVAzm@o0N}cT5?m z&f65W$$m=4K(oKxu>M@nU_1lGmYjA!fL=_mfvqLq!%4ZFeOMPn*t@lQ7vn$1cPtDP zoFhPv0AIyc1U1NjSSVP^SQI=sefKdqA+Oi1jqmjbGzJ!rN3Ew4oso%C0-`x36>537 z8u>q;)|hZ#naqX^sqtpV;lyWog{8;g0OOnbrT7+0w%FsB3k(4a`#0F@Lt1<-Y`nXd z1v|mWJ9Z0ZiY;;kH4n&vl8I%(nXe14M9jz9 z+8~9(*|W3W$W$T-`+Y*p1~vf>X}nuJQeZJCE4&ijp}o6u`5wgn=8EIg7LiW*Lv2tL zAWGNR-Zos{H1)k>S@KN)k4oSL!?IgpXCQ4RvF~#-qr=6e!(YALWfu4=79GnhDy|`e z@1PBEgA*w@s*&IBdN|`+(M8BxVrSgK>4j=D(|{6rZMhGM8JdSCdrQwOB6z}~@O{80jKgl3qhnpYCor&3m3LeFOLski zzz7{Hu1+I-wpvfcVXnP+pJU1(%l0s`$#75DpRki%ygoAUxFwj6xzrA%?1#qsB_YdZ zXm2_+`>-8-^QzDI6r7qqrIG98fKU(-7VX|-@cK#4q3L&)v%mZqa1Yah(j3yw?C6@K zJXCQ@SvMT)+S|lR$tyHN2)f?Y>-FZ2O51bLX7=2_new4epuWnmo$N?`)kpcLET`9c ztehI?hjBEblx=GKK-Kw`Y1aW$SiuzA9!pI9WZd9!Y`5W^_I6{SYX+6uOpeN@WW8i( z){`<%yCP-WgTmR6>MPO-7QoS1@Q56!i)>FiDB|=92IeP3v~s&r=7Zt+hquV_s8LuP zwNiUo0CgMns3WQA)hWmQhGyR@xi4w{OBbKaGcRk|?BMLV#W%v)`@XdnpRerEVIC-` z&^Uo6&tQ&E5{+3u7e-&=oUr_A3@6$F>?l;4t(GAoVLZ(2m1ixM{GHOGmwCeQ8Az2r zpSA_rfpx5sB?7Z_`#|#g(Y3TK<}I2dP}zhc^c+8{>tu@6Yu4nh+lqSX4YIHAIUi+u zwknN+U32?wye4R)BD!H8zM8B)n#U;d>-$Yw+@2u|H8jcIj<*G+PHTcZnxZrdb#gu> z+rnJ@pE2LR7ap~BbV9VANuo!OAk%xkex&E(t`vKa&?B#3*)nI~nO5>{85|LLtI&UU z$2cab$ZLxCvww4vfK<(Av7XJ2E$AQO_4m0-+pm!vbnvu)XC&?ovRI9PNqudS!@rjf z8A;Dn|1R~AZ8L82g=UTFb^9*|pwbibn&g8UML&Y;$<+`FdYw^Cqz~@q?(%4w%s;JX z!C=GdKGivnRq+@dXsY9*P~>UaN{Q6$N{P(#Hm#>d-6S~CZ3sXB-pJ2$~G>3#SG+psF1MS)LjN4pTB+x0g;nI&5h9 zI2@IKvCTm;m4`J)!^&$M<`@7Ee9z1jSWaSO#+}#NVcFuW1v#hX0!SuT`ICp^Kxy8J zb~%Dwu3#OayXZn^GRDfz+iDm3fOS4|ys;ELz)>*5ZFn%nOho!f>|^gD6ihTkXSV5R z>}#@Wf++NB2?hAfyU`2<{L=?sHD$54psC-kG#79Z=3yYuBo4kyhKalK4Ac%d@q{v& zLCA{>J|31cx*1KGR+LfE5~OdXNogNcusiqj?%}+7EB;ASG{N&#vX4}Fcg+e?v9I1BG zl)B-IhOjK0$S1tpepm2>nAbj?y+yP&#jQuP2E+)ijib^^)pT8Bm^eGxq-FN!4DxKI zHN&`XgG@r)hQVS0)oB0qbVSyHo;2Gzc%5+G4NwL7p>GnB-MU|XK}F9$8o5H5vw7W8 zoy9brWog$Ydeu4|fYzAL5}#_l*TV*S*{JBABbjyG`t0pF!% z<@V6VOWAsAH}vtD^=dQgyrpiP@Fv3=xkDZIc$6AYfhZegF9vb?nDf1&f^(k{#8Rx5 zjb{cR^c6;u$1P<*D@#O~6t2%~))1DLquPnB_2E*fZI{K$$;iW-F*?srVyO(>r$-9T z`yQT29@`dK9e)u?tIrJs2fLa@AeV5L>&Hfs;9U=nRyet;3Wx-GL`BcN0BKGd&~l_< zc?dy2ok-#<=mX*RPKbEY)o9m>=>wHR&6RyA4G*0TwPU+_Zb-Q|bgDhY?6eBiBaatr zUK`I;hzsZjYSN(|lhS(`j>QjzoY?h)nLt_t$V(KXpU104dObqd<2161R8SeW69;*g z0}GR?%cQQGwFeu?!&dzc$M2aasIFJM`AJvcF|m5hv*0d~*o+_PwY8mo57}iI8)W}_ z?WR>!?>0j0_@s0|84q{K!P{9(tEiPORznE?c|s4IB+)C_L^@<-2Y+AUsN3-DV>?Fc z;YCaeiXt@1vuLWd<_p~1O~b+%ekoY}>sv6COHOaCDcZ8U)V4GOd_dCu0NNGcrmDj+ic8=A|7C}n#43-fVz z9o+zVO;KZ^ZA6v1ux- zjC8HvRCs>cIYSGBW!ANBs~@eVsCHbeI%9*q)MvqX>Cupts6>*(GR1?S73b?|kM$Iz z$Iqe_uV`crA|k(wGt=t@DJ(V_VKX{V^cLy6J7w|<5d6~19K?pZg)~m^xx4Vd$xtij z7NYOcfH=I72)1HR1Oo;|0I6OZr*0YN;edrDNN5^=H4URaxPAQl_1&8_#fU|n-j|w> z&|CT364<_l8pqc1y;`yr85bq3uktHaIi+@&LOlcEEGQh$2<1}W8JQkPvh_pd!%Sc^ zylLlG&qAzIXVe1nvy^y2tdtD0La%go7<8R`4MFUB*k&iGbjXvemfM*d7G3;OoweU#u$+ku-a-lI3VK0M!~ne8CgeC{1% z6Nao}5g+<_KK{qTAq*lHSR(aWURnwc%Bo&W}&@_PjcCV8Y1U`Ds0UuaLQH z#8QgtrRQ;>17Ooksvna-SpkK;Z{{Tv{k z(pQmdbjR#!d4MBxV_e!O=IRNx=oXw%uTbVHz-i?0mv|-UH{)B5mjDh`J@+Ow2>c8A zt)LnrptRNrdH;axe6Msb$#fwAbtCKW8jnz%)Vo6pyhnMnQfnZrQ1kKnT6-DDo%h?s z^euz@!ydi%xIIwws#8NR*V3-HMe)cG_Be+OeNK&{BdzR3$6IGuQZ_fCyfnLIL^n5KG0%^W@{LN2 zY&5gT*5#qo#l#w@XixV-=^S}w1?HGT_ic~P!Y)5aVZLOD6S(k}%$-7!z@I9LB*x*? zbvq6OfNoyyZErKEMZ&U108=}R+q9gO)?;Hn{D%M2y6hM8ApMGhp_dSjxrbDRDJ&F`eIE(?%XI%&% zP-ZItte4(<)rP<^fpwh3v#TU6MIWa-Ia_@utUN8!j*UjB(R44T&ewp2s(~@vbFAgM zYZzdEv!18TIKS4N1*lhp{KBK?z?L_~FVq_xls7!X4xNaQ#)|kAbfoE_zj!XIL$_cc%pnWWI1*SSkL+?EoZ4>Nt@P}$z3P*akZ8Ce=T#s7 zLBZX)C5>yxhS+TiXMtQ__^34~$X+0j#W`NX^K-~xB>-e+fX$jW(fkh|jZK2#_y|8K z75It$@WXo&eWCMNXI576k419UKg>F2i2oRVXwT;B2DrE@kMwKY?A;0+=T*L(cSNbz z)ofa?INF>9=vf~+8rC06B&l`**Vb{eeSEW9XvIg_t9t?V{K&C8Whc3Z#@%dfa(T>zHpO97EpSDyE zpFbUrS71Yw2MPkvd9YC_dYerL{kXs*+~v91YQyEE)Xwd-tZ`MbwCE4Ht}o zIZU-DT_}u=SN9C;Do_{>L6GUd2>$iD(>l&uHbYT16`(3{J~k(@Al%<2?G55MEZ#QI zURn555HUs;e<)E;fo7yH1cJ|+I+nWRapXs#fG!kUYhu%JM<(qX;0k3G23(KWMJI=jFAP!8yd_9eNlWX4UK5&bL zwm8qqh1`?(Vb({iN_wdcv31H;4L_X2tP$N}ImkJS1*Ec9JtNGWX)8akdZX%VxSHo= zbM!G0OLSAzVV;fY=0j8)qG}?CF=<3sb$q|dO%3m{!E=Fydtt{(-9CfP%rYrS2=ep6 zgGkS?l@k&^#ZKGA<7+U}=z8_};T^}W5D$mBRbkZA5;@vIJUS+9=e@P)16lbGXE zH6)m+GB@pe*bFy1--3W0^;ici_)M3R10wZIq<&}GVeCLc8cq!&6%BO2b=-wqM*w5U z>WUc94~^})6sk4^@3v4ql^mb&AN<~glo*5GLzC@=URp6HqG_$@5M{t z0(g@;t8f^gtpb=N^Af#e4rpT<{{#R}l&yd0*g=2&b;Z9x&EskNwh6Iew!mXrv2MCe zqiQwE35xWOLtqh`kV#5GcvAqi7V5=KaAg1yC{=GYHikz1-u6W5>#dzAbQ%JFB_ev4#6lM+iO$& zZ==E>)<^~nV_rogR0w);#R=Ab(b=>V(6Bu#&({BTUD3!J2Oxgx%{G$~L96o7E(a_5 z7QlgJ2RB1RO8>c>`~c91h7CK!7?l))NusBnL|)#s2O9RpVvghQ@&0q*cNBntk8XP` zje}O%(_G5%HyOam+|!`G_7`F0U!#%+Q3GzsN^0Yi#$N%-zLKp%8_uBrtw*+7nVXK$z{x@{x&*oeU-jUCG@wz8WbU*URLlx0xz5q0=C&uyb}_+055{r z2)0|!VT6PT<^PUj!Y!a&isadRrl>kVVx3J39hYrRX9ggVPdN8L8vQ@!0`whj32`Cb zjeTz>0G}Z`Jil_~%K5oh&i3G+{Ml>CST$r1%GwBpv4iqav{Yw4{N~FKA!Z1+Bqxsv zeDx~+6~-VxT|5ywIx%r{T8BE3=1js6dKEJ|8S!I1kck}Z{(y)Khhur7U}Ru-eQaVt zY=CcIVu!q5A$w)zv(L{Sr__R8fb0hzn5MlP;L(4gQ7{{rRTE`Q^GtAT1j6mC}Z-&-V5-!L~UE!=md6$%u*#abN}DQS<->V-QB%4CV~13 zY8;JV%7cr>MX;dO@O~rJzNYYR5deuqJcFd*bWns~j35P45T2RqynM1M>GWI6!TUNl z|F>~ButDPpYC8lXBwRq_p0>ZWxa{`)n=7`8JLs{k@BS?UAQ8s*KnkQ2UU{N8^Y?)i zln>qRTuR~pX^1cw3ZMUE*Qs`~o?g|+QF{QDZ*4eAi2Oro{?L-NyFi?kcTbYPFryHq zMKs%A>H-l5kjq;Q*TOsWI6d$A6%C2ARm4Sl>mImRda=TW7g^OdE? ziC>sd?g4?h+|Xk|A)!MdVHE)yaIF?k8%~W4vgjD@cq84^QCkwgvH$myyKWo!6g&;o z=bPtewvCmF{~f&P2S9@jo>ruy_p1Qm9G}GBW&}@#-zNrx@Ubc+#u+qw?n;vq^rpWr zcn35RccM9i&`D(Iu1S3d`CiPX?O`!tH236(^Yt^;GUeZ(b>jY^I?{A;R0GbdL!AKx zR2eV#R@AbUlb^9aZcvl|a%Mc1xQUD(UIc(GSLL~Ou6aL7k=+g)=@9pS%{L&)c|?ug z`<9XCB(j9?k9fkmaM{A`Yf}3;|sqw=k%x zO{!|4`3{oitTNpg)j&NcaC*mW%P7~q_T}EYGV8HLqyq#D&9vxE=}(hH%eBhO( z!wmr|)+lDBcQ^Q-qgUeZ{AWf+)4{D$;}nR<6BSW&7#=y%TkI@;b6AMc>H;*4^IOe? zaUkE2hga%qsQ5sZQWT)3=;U-AF%BFgAQA|II)JN0mq;}L6hz;qa^af#Ptf-fPZm?O zsP<;MRE1*@D0oXZulevXH{E>6nay6&fx z>dTd!{(7JDM+Z!jeo0^p+Us`u4Azr;PYd9kIUpyJwK;$w>OKF96?(3J4F)iT4Ywk` z?G!uT(E_a^QA+zQb@lgco#OlA=SW9D9q2U=z(tsFqR&q?~k!{lZ9SOXq z0fV_(y-niiMwZORa`c!`NMwcJA9002Va~{DB@2G@ z1~-U&T!SZ=ejew{h|~9=8>C~HOBJ1hfik~}PBC&r(8kKS6?wFS(LTLCkReB^Q~UC3 z&FTIa=vjRSI9g|ih%bd3Wmn+{`nJ2aljAKN?ZP}G*5ehbP~}*Mr4i|-56akqubK9> za@1Ns<3Z8{R}(R|hv_jOK<(Dh(q{t4;Q71D1MRqu0$^&xRZqcb79V}zqY%J~_Yk1v z&~l!9{hUMQO={F&Sml%h!Y?dCo8cQW%;XL>^`|Zn_@&1^;jDQR(_0$UG{3#0>lg7s zhT7h*p}CpuI55X2YxUZk8&H(n_18-zeK9+M_Gdhjy4v>ZrJ1N>ID!jk-9OSONPKZ* z;1|7R;I*eQar^BJ{&&DajQb6$(PO2M9In4A$Mib~kJbd`npIY*^;Lb5pTX&D+}Aw) z>ax(AVo!*g6x8F7SB34L1bp!sM^qQ-m02Yu&|-nJQ6`(C^^@Ygj>d|{N^nwevz7YZ zqx?%d_t$LKMsE`5)@5<qKa%#dvQc+p!)GxD*tmP0t;ks?(ocx@Sg< z94G-0?Jf}kIc5@S)yw{o`ueXDJ>M|5X>q2e0FiD0F(^?g?@ZpES z%Vj3GD>DiDjT*gIes<3VC!C_zY7Zt+Ra6OP0!+bz&YO~kcb)4l=83wpFh(^~;&CFW zDFQOdx9e%rzk6k$5Pc@3KWV~d`-Lq`D7G8Hzp*!3RRiXGPwg8UN4bAHO^>R8%M)!g zRkFYcRt_xvv;fj2-LCx&)n-D`7h6O8O}~)9sF=Tg;kIZriQ+aQ@v129jVDjm&rhn& zYwe!G>!V-!Q1PYG=$)>HIy}MhTaXN*i8ke)`bP9=DUI6CAV;SptG4S8r=sJv#0Zu8 zsTcNaq-nv`#b+gfeNLqIcVVK|zzk<5n&)78oNW3IVNgyhZSVBL;_hMX)YAWIc3uH? z*)V_lmW>}YZ^nK|T1gxFfEoQd?qLMo2z{PGU&dS$_jxEKU)~W)B;jzYrxz7iGF?Xj zewTfHtX$B z$~hBnsD{?4GA=|T7Hxc=xy{s6hab<2tzy+)`Mt?f+>Sy70IA0B%mB2?H^Ic~S4z2r z$Q^$pK|D{B%}w%(WA<(RszJB)PfOt`q-AHCjSmcPbk8dm4w?=?E%*c;4}-b()fy{5 z>Vo3wiI6QHP>G^a>)OVp@Ag+mS?Mpjh)s|vkD9{*x+sG|4C}o{poR8h9#rNPnB-0r zu)gyVU({h*&bRNyjkEjR_X)+f8qg2`8U4d4OYDB4KC&o84!8|`Qjuc2SDSK6!AOn2 z>U$yNPwnUF`=}HkmJ=Pil3NHa{WwF&SZEafII=6XbE^OY(&o2WiYF>`l^Dx0cjf?X zsTR0T5Buy-@`n*g-Qln^Z5|fja!q6aH*ax^qoC%N>$rU&Z;c^Xa=)wVm6znea9LQ3S04;opfX?O11y(+MuebpO zG&8gc49pFZ!P>76&c8XM+Rsp5oid?PBSB_mkEc+HMQ<#aO;hhfSgcOJ`FEWST&H%r z7qui?hX{n`)0~0HLRXB#VuD2%*wUNWee@})-VkBfrMJqRXy`cKokD<$2UT(*?wtiN+G+n8bJ29P%Oo$N-RS-B4)aF zE97Q5cdzggH7Rbkd0K*h}oi{6_cpJS<%ukqj91 z#PM1Lw}`tmeZ{+E90E35>bB?F@j{Pe<5`vpo3HXM^d<=ptTp@iViJ(lTuEblcFGTn zWi0^f=@8dR&AlPzF?sPFARax0?L?IZaM1+jA~7Dj>7)Z!W=Mhdx1pPhv3Fe>*quL8 z>-o=ioG4a8ptsw&pb-fc&~3&?WS1T}$koT5?e$=y=z)Aw0xE&KDR*3&slpl?0wV6X zmFPt2C;fP2$y28X7{n2v{8v0q=*+q!sNsg)^x2X^Ac@fQJH+trFiW&3=5}_p^wo`2 z1nZ%s7~ztUO)8)V8t(EXr+Cd(IZq-CHf-JNOPH5CQghT_sq;op$XOG`>h(c^V5U3fdu>XIT5}`{ag2Zuj39%JL+ELO%dJd0@4oKD2@eg zVHQ4(NNJOB{3iNj*4A-pcG_NfsxME$U>4q%M<;86 zY9*nr*EWQk7~Ke)bMaCP4J_M2Db)%L#0r{+yxk~GLoo>kERs9O|FI2(c8ZTlIu_l9 zW9UX$NmwOO9}qj>HtL8uZ0+A|`iQQ?Q)2~u-OpMD8_$y*IV`|zFt5X)$a+4MXZhW^ zyWQ(@JDPwq?_i3XE=p1tH={$WA>|H0_$5dAG6`VI7(?Sa{-fM2spRF}^PR+3do(U1 zjc$jB$hZ^*c#s)FEWD3|qr^kCyJW^L% zV1B2jxBj_4YAo|c-+ggNnLB{*o0rn4`_*lSJVkilog@!mkN)Dm zAOf(>Zp-4(jts)7IbO+qU6{Mo)r7~8KqA#gKW`YvrGLk4!TvwOA%P+zB)^{uM52pg zXDE04DA%7DJ?WDs?4%E*o^=U2xpZnxq(E$icNtrg!2xxvZ)L2!0C@;fv%3P8hQYe{ zgr3YWEh^y+v@`hoqH{(+tVyckGV_(C9D|l_ z@{mLp3V!9Rs$K4EK`2cy>oSz~cONhNO9z8`N}JCagZ@qe1Sv>fzHzv&@_clCBGj3?>!Ab0@M`beD5Syupf2E z>BkjILL!Z@0&yfIm-C|izXg05VUj>Sq6eynv@^?Lj6eqxc-NKshoK&@$9NT2>Vt_y6BA@Rkd;2O|xpE>P&TGt>2dZA>q8 z0K{#3yD#FlbU0va7(c{m%RrI^u2v22?GNA0)&KV%R8lZDMvr@BL3jozw6lH}CbWBz zD8>N+(_g3UqyO3H0eQ>^0)^gbj>&u{K?0496n9Y=)YV5)plMH}lD}m^Q{vwjIuy-q z_!J+Bt_B5WSE`~3Amapo3WYw4Pr|?c$2$bA?jQsTy%flyzyxOmA-O0&0}~pk{b_z6 zmRss4lBfg%7=L+EmtU|Ifdt^HybNG>4itLOnT_f`q|pDE(noZK?mOnW+9x6|njiup z0zQ~>K<3=nZ!xnZBUR41fNr?;G3x2-GdaiN@Na6*Y~P=}vj&?t=ne1+5+E);kAS^f za3m>cluujD#Yjd-U;`NwpoHki(fOkrA*U+r(;HZ?5;xdT6ZY#-^lf9ov3xXgH3=MU z>^zmb;+5e89I@h|)8GMdsj0N^cZ?0jqAOFe-^}J5yImrGLz^BV;<7T(c3@D zQJvV;85G4;z1g;5dk%b+v+UbHKWp(#Vfj}G6i8l}MxxtbSY^7SG9xA4LE58cTa0VApZ^5Msq@aKpZ1$8 zK0QQy>e}UyA^6Szd@$&K-&VC|QTQo1$Knd_%0XCS#dzVfO{aym%f z$)WmTgx9hAV`=XQ$KuZP*H=fA_Wd^RhRTt*^bOme-fR|{Dm0e%=aTe_8qzu(hgu<} z3l?xW-fUFzjSDq6gk}x$B#568?g_>Jxr;gDE-W$~6zBeiOQq7qfD$A`rMsc%EiCPsW1kHm&41_c@XNazy+_ zuLA9>BXIWa!^}8D&D6Dm2q;pOi8&LCo08Br$wJ#JJaYUjqxd#KSn)QoO!&-B;O38t zuVbqow0o1rfixysh6~GjCZYv~<&!@LcsuLqzq>djLQRx^17@#6PWdlQ5>_Yx?tXLp z(oJB!14Y#<(cF%3(TC2ehJIoPJi2#p@Ye^av$T73R~vaYm`N~hryJD1lq_kxMSGv4 zW+BW>k3#RI6;}4jJUEGty z&l(NsTR94 zd9#O>x5c$+o9Svr7K0&2G(Ajm)ArdFT*};(tg=s=cVzJc5Z+JxZ^qzfRxo!5%|v^% zsc`Tul#69(Mrf4zJe#L)Cu?zFWiY~SeOCW@e2Qj8-RH2ri=oB0t63L}&^l?7o0Mr5 z7Rv6I`a^$cQn^($uoWj)hpH_8OH5{Z6Z|n+ zZ}@?1p3(a@n^c}Rx-<)E0MLGukP{Z}r}bB3F~<^d;|<9d^LV}9f-rYOkxL4uWBr9s z?UpBFW3r(p4do$W)B8+O?x%0W68?Qdh^67ATjK~Y;sD#zt!Hmn z&k77QHCT@k@}JS4nSx{RxOgKTJsSN%z)n8<>$6KTxpIOVscY^76ZX92OyAp|?})K! ziALC26%*No5gd@UvknB|Tp~Qm;#J{#!W)gzO(lNHOD#O1hjVA*VhEEm-N+HKy9Pm; zH_<@YwGJFURLdb#)#_@Kd~Ti-WgpT(*I9@qmIG1tzR7{p9zl5|-?z{B?aQNIQFlxl zJuj*$nD~)qdpe<4F8#k*bbpOkT~OO3bmmrRO?O<%KUs`wXb0 z&8h&NO8n`H$>Lx^=9AUoU(aGi#WwC5g0=h>P1sa3eTa7BRA@mSKqEg*H8j(ws^%i} zrJF6Cc*tjOf3Ym|6#DXZe8CY-A)IG$9oB4tA8e=9jozz!7-(tE3?)?2mE6L@lTVF!F%t}dQod<}ksHO={iv-@a;@~~Y-JU}qnoYT9r|M#mKuH<53w9lpc6OFIHe-(Y;iGH2;fgm zC`)LT0^gpSCM-B+8+6gvMoOL9T^0VdsU1tg9c}~+=3L{uU3Q14Z03KRuG`6GOM485 zI&B^6?@G%iQZLX}+2mF4y#|N6mtRo&aUE>f^nt3mG9R|*yAnXhn)sP_u`G+)(JOL= zc!qPvn(i8fX6ff&pPALTI#~V=m0US0irAFU$i7TWCK@tVm2>&xyBmR|@;XxQ?6_v| zXMihC#AOF7YG+K%_4gId@#ER@5z8zDjbGgRqr75+v`gvw^DWJ-3<2ORy_I~ zZM96CSH7)djWA2gx3&J^MH{>^%iD#X-xU!6?)AhiU~tn{+P$?nUh^Eu_BLaUUM8KV z?P$KpM-hlxXWtY)?BUdTTL%IVC&itHC5P-krgYF!@jxWtcfOeRNP&pwP?HXEFpmau zg~4f=N-(U=jJ4oJv9Ot>mj;UyR#9Z6qv;4p;^VB{Hh2A8*!*6=J!tyCLoy znoLK&(Aj{Vlx&1j+^kEI_PyLUWmZIXlB@4DR6ygGB*4rWDD%R51;t-$7Q|@K5ev@X zGq{o-Hb4KS0M8B!@}@wwH_etY?}lvBJx?-XB`--@%5DiFmGg7AZ+xG3vXs3_A)aQ~ zEk-ILw&NjY6eB-%NR*b2c%f^UuU#24y`N;Hyue7j-K3rUfcHjG)(iipiSG_jIj)L< z*ksoErv=VnG9;1E>$To3f1D2CIjK@lItL0Jhr}1hs;j=5mbC3+Xt*?6d$ib{F5Lt4 z+Rn;QpM;7y(*1{2|EMD1Z(~6XaCct87@|`G-en4m?^50S)-Sj~D|3{9eD=xbc(trw zfLa5SDvVmF{J$c@tX8*qhmM!PosS2QL^*@Qp4!7e_yX^mS85|3_`U@kVDf$Wgj7cYi3$D4Nj*Bc7QRll zK8~K3O3*aZV4Z#Q>3Luni<)w>>%utPGHNejK$|oD@Ny@&J zw>#nlZe{_Bs2Q&@m7QthsWest%6&081l!ZIiiM1qx+VpCt0VW03vh3+qtXZa62+`K z6vYp7f!}D=gS;||=wz(gn}v#7sYS1~t^mStqZxmM@+dkfAFoI_7(-%%n;-R?g9zP? z%sVe}?}T>V#-ZZ!u4mO=xK8|#?4popXz_TDF{l@?8P98Ms;2KgBUj|EpbmkRTi5RUqzOVpAk};ujnfhwdHK`LL+ObDeoHOro zoWc0>h_Ge0^Rw!R4&C#>kpG4Sh0#yQTzt8Bn%+?_)Dth|&|jX4o97euP)8e?#**VL zHvD?A=#|Fg4KKHU1=B0&UNT&tW;@%zz|FK`B#ctpGg$=qPlZ<~b!O_tN8K&SdSHFd z81)#qA0im>2c%(yHys2sB1Jh$^VO@RR}MM!BiL1teju$S*`0dti&iw7?foX46bAwY zn*J{jYW#SuVTjDyzIjjtNF0{v1N6QG9qIE^MTq@oh0x!i9{Y`nx-CFhCwE)xN3#lF z3>*SWti7~L`6OWlP^ACBY9`)dMH;mco(2<1QFw>Y5t75;;M9z_Lw_6TZnOdfS5NL4 zB{^YhkodqnW;n$*+;*ef-;nWnd6&m^*NdO~6MoniyJmXA6w4}Es1nGxry5-&j&?bY za<0vaQyDBQcT8#~@pD=F`6>4E_@%PVrZXVY;2M4*ptE^29R*3U z-l*0E1Ix&WlJw7)g#MGclol64ysOln59V8Jfmj`z6+9)P`iQxf3TnF*l8i`pxnXz{!#>FVsbiqGPj{sc%0%WDeo4?3NxY=KIFxTKMdj*oadT)PC$_?iC~W4 z-rM>eQTU9q4S-cL0!g5md3^(@LvH%aPah-u%3Y^t0M7VJ?}`qb4>t+T3VXp}Yrgnq ziuF#%m(HX;B70BTaeOMyIr{0GW8G5=l{LH3;0yUBD`_LB$XMeS)k>97@?2>8h(+h` zPFS0*JGFLnxCX2@KUB6<*R1IFfoY(phWKisJA1FVW!}P<@RhiZRiiSpT>q@Eod80W zd7JfK6dG*kI{2hlW+t3&!~Syg%Le0BwPt3JlOL%Cv+lMQ%!e-IgQK9l_QH!G&5Pi^ zs2yX1!Gn(Kz~z}Qe*g`Pe5jlnNrqDOk~?njt0a}9)`MS}oNT;OJa|kt|EYC~-fhCh zeaI#uslsa%%{mjB7_vdShxJ25Jpe|}33;&AixXSBTRmIODKmBVnpBtsj8FmojCJwb zk_d?aU4;IJLyKPisdqKKqs}TE8ZD17>h}mf)s(6yICF-vz3dZ@Wla1n*m6TrHF;_+ zC+52Wm7#N}{3d-m#;Q3_Wa>(U{7B%c?wCdJfuarV5s(oe_jH>We~%tTpMksZ@A!qF znsM{K>j|d$>e-zL$O80IKZZY3GxD|VkGDz8IVJ@N`KK!n>uu^J@Y1mx{=wZ3qZPNp zzPp3Xqy4U3N=Y?=jYHxMg6-K8uz1FSGke~f`E>-i|MnPoLsnD*cB>>g_YX;F1oZ(* zljLvlgGfa2u?2jaqrY~%xk{e=WCm7MMlQUG`q769HOmh##8-{ z?59ryiR{C~H(Cq!89%4nSe^zDv5EQyd3c9OR~=X}#@^DsS7;rcCV74)kqQIkY(%|5^% zSm5KL6@qZ|=@4EizI#KO{0m^>uU#Y-pnkqVy}wqqZo0js3I`={irC!Hc4h?GmGWA} z*195%hFriv{2Wae{(9#W#`?GFj_E!2e%?EAre$p}vAk}Dm79`|}BZkzel&lM? z0gXmrNlS|jg1-hzssT|XC@Y4d6{#PKexyLla?jwgcjyIWalRblKcpjVhIU*dHccLc)K#PTzWKnqf^}$n#bqcIv3^lIs%|BvR%`g!bMe=$&qA?jHiMz0B zaV?%VDDU+Sk-JYvq7C>#5oIse(;+P02z2dTi4 z=?2JoGB)K`kRA%E+?1{dd!RIwfcmdL*~WdYg9heM{W^I+-WUnBQejk3?Fq_f2YayS z1bbCY^~v{hhvT21S!?#Pe#OKKU~cpRE1@zvU9yjro|*za+$3N_E5G8Qx0HPBH$~VC zN8_ouuzC|qD@4oY+AVd-Myc_&NRrAuwBpUn^Ff=m)Ax(#;ug8lwBZW46^bHu zo>w7hEHxuUly#%997O3CEQ%%T$Otv5P|x5}E@Nhd6wKC*bdFtVDi44x#!SuMKYZ9rsP0S4+TrWND;AFWIfH8I zd^ld78B~|y&HVM%215cGtSp_5{C&L-GIg<+Ne4$3%(|>KqNh*Tl9n7@tdtv6hVtlk zE7N4qX&+gaUQtay`?=~KKR-{9fL>27CY4ib9OFN3aT&GhFdxe@Epd3`?d%c7<9v?7 zb0w{0(vy0Etp3RuAv7!yg-gYA&Yq9_Obd#^!enA2yX2Hty z3r3Tj-l2iZgMg&0K&xalT3G=h4V*e5VxVFZt_5@=b1v|H=bj*7)uG%W6+%2-b z%i!3P5lquKk#w`h&(}faOiEZA2`vyH`BHK$fS+;uD_~D8nv1$u9|MExuZof3 zC~uThO_u>{^{`MrjGbc;5e4r;}E zDW?5|PR0mtARhA7loH6z*@ZP9R>16o%v5w!;ka6+M;%?)JHC^r&rDRj{yAgUk#{HO zSrW(dk!nxYk@@{YoggjBM54n{n{Ac=Hx62{EK^o3>E$!(CYTQZKyH%`9fDx_*SHFB z)?3_nDbKe+Za^6@lW1O~*^tsg=>1bH=YJTLzf_*e!VtzklSc| zoy~}rAM$dicA0u1DVnudLOZM^KUE@;k;r%b%@jAM_pev~hG7O5 zz?>IM3b|>unIYbd=W`$5t5b0acS0iyVN&v zndnFIr&NAEVRyO1NIky1@}1}+q($lJx9BPQv96&HMqoW$;}1@N*Hbr3{oB(QA*OV3 zN9x`+Tz&9tFdF50XT_z#EePVi?1vl;_D`FmZSvjrKj8meWh}!}rau1h51NsOXgFTYceqh5qa`3xu9(MiT zZq^I2OTCK@rE&NefUV1h|69c0WkamYtrKiHSpXb7XLacc$&uk%JO8U6;DkEh;MuPS z)g0`M1@KrL*(ERc*@O0vQ_kSdcMH&G?_4n_V8suFh4;~ZXzO`WQ~}m8 zD}yHr@zQFwIgy>dNgA(ZQI*!8tpG37J}32g(b3eh>=b*e*wFQ&Tyd0IJR~DS$~k*Y zPtnZXDKnyTtA+QK?<|X`)KS_P=a~LNYcfb81fW@{G z$^0Ii_T}Bt6-3%1mdC6dEnoANCrkkf%Xf!m&y zqcsHja!3;nG5J`$n*SWZ%E@3=lxz5O|$*^p7Q>2u+oblvEN;TR9Ebi2U_z~ zy2m8LbNm9eS)18VRXjD%KDtJ+D&VP1G9Iq1wqRw6?H1qkUcA`zC1vznP%!~{h{ha2 zqtvSprt`3O;wnV12B4v9u9yFc|2bKwRVUeSbnLxfpz52;wQzUMkB#^sE4;crJ@Ml)mSZixcV>2? zU%AFNN%0N;%t6n~KPJ!vw)`^SNgIq=Xt{HX$ClRkHm1(=rSY{9*}X@6`{!FV#1Iy$ zu(R<5NJ2dE+?dS>Snsvr0boqO#p)k}(46<6)OG^}%e6FRU+a!UF>!zwZVzPX#I`a^ z+I6y4087Ao&|&vhd+!J8nXTDKHnH@JR;~i$meH3xIjzHsLc{|tie#d_7fslXc9VW(El^Fs37`*V&BDf1)oU;b@MrJ zJn-tm5W|N&Qp}luMV%*<-hX%a28*zp(MtSS>9PE1kF>pfqs+L&1;hDZ7;#}~ut=g- zKA4s770Stu`J-QnaQ}YJgA`Q6`J|PFhBNCL_A*H$q$!cz!CgM%#JJ7D-7A8=SjZ@H_Lu|>VT z^#a){ha9!WQ$b7p*mwXr0d#0&fmY50$5PKUrw&1J0& zw5+Mq&;OhpLdF^QRAht0$-*XNq?u#=z4q%%Lb20GzsHJshc5t}w?K428%W-@CDGkr zQ+H!NHvVeD0hxmsANUx)On`Lv&XtQFNT)9{P1TQob{x9Ki|3V2VBr0Gt6=R!zt=(b z_|ATd#oadd8UE+Qf0qYx5`Ns1Ud~m$9+p?~XuwjtM722aObY-!OI_`Y>sF;P_*lT6 zZ*n%A0$>UJT;%}DpbYb_#f+nnZ=^yXb)ii0@5wfk5^X*5$y`TLZktdDDP#BJK>izuSGS&Ig)w?B3GvQ;=g;4>lf zup3@91bioQOWBzbIBZViKn5duZ!BR0H$W!lUSLA#3q0qR?UHq%0!%1&86OLyz#}A& z0m?sPq~D>97Z5~8!V>b9<=cY|FFs#-m5HE4cP#dOtcv>UwLM3o0ps2gXzpqZr~6Sl za!?oWA3hX24-RCO<`j^gNO{_Gl`-k`h+WYK;I78{+=yy$$Ool^*>L13aWWCjA}|I~ zhvjZuhF}ltx&Mdrto!4%byhMJQvK!H4eLb zH$IhNs>j81B(h9-5sGJ6&U?rr_WswnqcF)Ji9u^Y9|WpE7Ix zH9k{b93v8?rWwt)`Us!$e)%*$tn)XTN~_c$dC6kJ7N({4G*cjAX+wUgCo`0UhX{{_ z{Lt9UH5h`~!{mWYqcArQut0=ULHFs^WQEZMZoE|m5aia2^>Vk14|F;vkt6tmo<_i2 zsMYo57r85DUSEgm$>!tPS6Xah9L20d+us)Nu=_+;gu}B1u}_`gfB(mQgK>|d;o#`3o1io#cPa;K z#q8Ij&dV+NF=_j5jC(`xVu~oDs$F~^Gt5#4V^#-Go0s>@M*3k!KXlL|=cCaFIR}FW z^zr~|`N?srFeL5?Frfv@yHHhAnUSb;1AkiO;J#iYKxWVf0I-CT5TWdvlNGZPn=c)zy_JX$I z`Su&g$7BV?PZo`CdWPXq69V-TZCk)YYeu&TibCt}v~nQEs>9XyCNoDjwZ8Mo!RFks zsSJbLDEZXemT&khuzp5iQ*HoH(W0g`UYTnU*bz(UM-gv-@b!1Nork=yuehnfCC;I8 zv=2_Welt{L$0BWxtA^vdAZ<(rQ;P^pAZpY616Zx$I1=?D-p3$>uPm}W*w1M&Kb;j& zQgezcL<$>CC)dG*C`+}S3s-|Fptl>!gUY4dX0*KkH+z3Mlh0D0Im`*>={&8v9em$% zjM>h&+p}{s+KprQoy!fm**Lertbqf=^sDn}h;a@Jj9NJ&Oa(P6OE;L21M8bu;+dJ) z#&Jmj(wQVLzhVqXCjJ#B>pW%K-BlHTJM4X$g<@pL<73a)DI&qF3X!NhhliRqrc<6Y z;{pGfB+dD1=WP@ya${BPfvV-E>FJODGwx^w5`*pCpD|T~edMTJ0Rv0(Yd``iKBJW4 zw6LFdD<5`~DpRQu2gUbrsqbSn(BWT`iL?tiRb+)uGSKCh6zqF`N3^8{WM0mWIyph~ zJZ}WU+*7r{fo`zheVuj|jODwrM`079Gs%Idx`Q!bBy{`u05tTy74CNJ4eC^Z(J!bWgeVf0440M_|fUSdT&jRB|8#J8cL_gHwkcNz&={!wo>!=j~lR$wL@6eY6GbT7jck$d_I*W zv!c<{-yX&d4-dCy1GiVbVs7+-8_EL#JkD>uFd3Md?|0dEMu602?k@WmP8-3c$th{S zTMq#j{{iLCQdM`OlG|9pVc%t z#-KFyXnOr3g&Ge|4cGVyw)u!|ydVkQmn~-EiDtilh*EGVkt2Z+nT}Y=+3NzaB>~nm zhKQt|1p9bnPC|nQ)+Y8{u@N_mFBOF_=hrGP1t%sX`%;@o)+Jj{)CL$8+3NkiZ9&o% z1sPC?nKzgN0BvLTlj~!BxQ)Un_Q}u3>m5`*mY{$s>{33Kr6L$3wCmsl=E`;0wBlTX z+DP{w(5xpNhJw9U1`=P}0Nc%RHhw;D>8RZ9iPFMjRV0PS+5UD&g^uOD8sv z5JDZz2nGl$CI@oYY-Vmxo3mZ2Vq`v|wHjG2qQ2EyXO{_J=;rIh$eYk13^TyxB8k*r zaPZN84$gccu-7!)HfS9RNkixxhFWC5?Bn92zhcXKR*~m}&Y+Nj&{*ePBiMEY3MlQ| z&zSo)r~}<+Ys>K?P9mt&3}zM9<1^S7*X4SUs0i-Y=h~NQ^L>V0cx78PhjT2`uO^<7 z5A2d!p{e`vm4uiPB>@9` zX+D;77HZmx-iQaMKw#Z`j|3?}tU&aNl%oaybC7OKw*{k4{cIu~?^V;4kfCkcsy_hf zN_w_*n0*W=?%d>8S0)+IkG19ZPDsnVvnnFlFHv=Ny^Ipf6Jxp6s`lHq6JxKTXs5I( zS3MC(hN-fu&;wg)nL%s#?8a9Eftt;w4oq{mf2Z`h_Dmbj3dDb*(@mq?F}$Dv@BNwV zNCs`KS^hu?e6u@TS+BKUG?G(-DR0#a!!dlK2ory^%rhfol3%;^$2H_zA(#J0>iU== zx;dFTMLvCX>{fxddM!Uy7o1qW^XX7Kc_Agv94N-5o4s=+un*zlYNG-9SsuSC-;F{C zAOyZ6pyK1M@+8~iz@|JKNF*=)3m6pi#Rju0#9U|tq~S~1azz*-G0+74l(PeKKe6z( z*vH#(Bn=KR(yC^NL{;upviYVGs;${qnVh`2FE{)Xj~4+*E1AKzR}p@FkiBfi4tB!| zbvbXHn^ew~C5d4LV=3U7Sbiow{m3e#RI}8xfo0bC9z5 z)$*qTZ?ePP;1fH7?PRzvGd=}6pFH!JCt)*pz1pn zYUmfbfn=oHZPO*=eo+Z!FZ&*n8d@%Nr+-*;-X2ZFWBSuaZ3q0;vA~IMTJeSo5urBG zgO)?WS2Qe4LXA6x%SJgNKVuS|O(#aKnWdTS5yil5E|odvN?-{px!m6?M@2p-_h_Uv zC#j0S<7$|gULuQqYYYbiVrfzqNCAUXTMI%P`rI>3oCovOnxif`VD;eK02{t7T606J z7Z{ai!D1(w&?)J6>&#vDZKJ!+M_oTaE1HPG?Fp6wc;{EP)qO$r)eDL(?dIhEMabcH zB6elsFi0*g;~KqN>8q?5x?f>!H{|@LCHokdEQRSf*v`tP{}VFfRa5=~Pjs|F5PyuZ zJwZe!gFx}>37V9FwD9}1XD(Xwuene*Wi7L-zzNK3nRvdqj*!E|2c$;S;Ht3EtC|o z(nOe|d~{479T@@V4r?;{04P08m2q*t>Sg+!tNoTT5*N#$~=B3(Bmy?NA-yOQ< zfq#;Uelx?3uzF<~HBv+;h%cB06yFxn@vWO3W6@7=^tZ+%76GHh7z6>BDR=jQA zy##<$I5`8>6Lg-AHVqYz=$o;EKi*2w?V9%JZdm%;wSq!-wsJYQ?{~8m{>Y=^I~+Lm zq;q`_LDgU3;ITe-e}W^^y#k(QTu8>yI-Yx9!3rJPQ*F~8KUWO7%XrXa9~sFhvuQ4Q zKo()_@miJUtu2YsWL)(VqSB=|)3>SU_km%bMTGgQRVoHr1O9-=%-la1DhawcP)FXh z-d+0jp&Eb);;fUCIO{xif!#rJ&*5=H4J{n(!)71#FLABOHTcT4lN2er&*@6U?_l`b z`^6=MQ!GR7`5hnhOfUUF|7k(h9t7m$<#ATQLQkkWHzNL4^Ic4wgos*WQJ!;s)$@r#tnk5Mr83SJ7HFt@!iZx@L*4*shEU~%NKXI#v% zWVtQ(UT6jg@vrvh-4jVJbKGkrnPjn~RQ`zkbZz#s(U+&f%Vq6??EkQqtYom9^!=`J zyhL&U>egwk&=v@50pSr4N=u-H+#svh{)!YXm({p{O`*!8<|dY-zF{60Qox)l?`IG0 zdove48|MbR`w2KbMtl65uMNQSn*E)|qeUNGo-zLmGBF}?SP9+qvKi;{1H$m}1eWlk zFQIOi^Mp|oGZArU(`oRBT@;NQp=%2^rqm#_3#_9{y-20F;qO7Lc>)wX?Vx0KSZ((p z!0iBTM;8(?=h;bNH@y806p+X1rtB)B zmDIggtY9thi-*3p-9&b&ULQb%z>11Y?^?m-fkgt)WpDiXbL;PN_QW#uGYphh5?+Gp zM>85^`egDypFfJcVOC;VvSefFpm#H1cUdOxwEtx8E>nofwnhV_$>KH;hoBzu`#(Zn zs}g|S{4#u!@*HQggjzkZMaH#Z(MQuitY8_x8zbs}Wu3gCZX*qGM~N=X>;nFB#STiV z__kOXRaO8N2|KkR?f>j=QhC07Sb@iE5k(NBvt-p3yL$9rq{n2(C^m3qHsf@d5Uq;K z9!4pTQ|8v|E-A7^k!b}6_O3xs0?ZTU-YL&mZHaUFf*2`@j~Ls@>jyAC5v#vcDktWR z*I2b=r73o2JX7Aah!S-HFbX%a?48Z<_90VSA1tbES>gK^m({N?N}|>yjmUH6_U~#u zm~amf`OR{pMX*2=4GWHPtV#W1hiCeT)K_; zwIlu(SB)BMhuP+Ev>^>)10aDDH|})GJsVxB1kSagV*A(;4hbrK44Qf1TKt5*%Cu{G zAMNEqx9Jwi{$Llzs1=-oC_UasE|s;1R&-APuOJia*Z#p4q?t;p~k zyXC5KUQ5VB&Zd;pwmYv>slmeuG_X8Fci{nn5X@RUzk}R3($9#Y+ih*jQADL!o_O=r ztakybHPIk^Z2pc!Y9_MfKc?ybRONUTTsQ+;rF7WjL^DJ{iTCU!i;FwglY2l1`h!&+ z$$z4Og9++J`ACeuM7r)B@7^tlINj*@p0Iy07~?ek)x?*@IxgX@mOgJDvz@jSpE_#u z>w_|+w9C+nqP0_%*R}}}B+LLKHO3S`-TF=gg%;c~uK*|+5tbNmj#kD%6od9K_6{{J z5K09W{}QB{EA{8-7q(F5=tyaxXUBD=ciYklMRZD6g1^YM1tz38X-myBoG7=nwo^Ok zTaH2vLO?HMd+c4XD}9YW3K|60%=&*$&#PPzE|)$ZtOQ=B*(BShvzso^O8DScmWCr6 zd3u$@ZX_nkeLViPmi`r>KL82nATF3ALtWSIpDW`MWHLzkW_w+y7MKj8Vu{P3S_!zt zuYtAgYE#$CDlq1_UJK|NfEtJ(Juq=f%^%UZ=QqJBH*%NWJ?9oEaH-K7t8YHv%H;%L zA}MQ>IH0?L_hL@iG2K`J1R+6-kXnnZQedPp-B#| zV5pzOZ}OMuK1oEl?j~?R+Ig#h7dtZ&9p1xd-bI4g4Tdlgq(JiK!oF9t2el=|tdZ`1 zM&}tw8FK}C3dYY1rMRg>z(anH7ai#rD5b9%=b9ND4S!5slEiLT#*$Kbw5rodZd9j12Q_Na&L>XClq1Xy$AjkdUT?sIq6BbS%2ly} zULgSAl=__>wW@!XJ8oZhkHj8O=HC7ie+#(Oye|KH>P8v>niN>ll@7*70P`UoEv)FA zZRbO!&wnZF>OBQ(yQEliTRQ>|7{DBGx_=Sy#ARl_n4KR$_AbX`euN`m@xAS+d z9hT<~l>9dX@}U`EGKOU)X$*&$i(SIy^W_5$ET?1ega2QYjprxu+^lVm8D_xOmc4{M zj3~?5Ovpnob72@Gid|` zr5OSTqVBPa>8_N1UtlI+c$d z9jZ(OL4phoOzd=wIJA6rX7bLs?#V7|L=Fhj=ywdXuX?(=6SFR!uo?ao(HM|8{igog zA=?M#p$K+i_Gw7?t7+m3=rrq}*@lGxX1dwBxzvik>gmU4|4U$oKm0`Gv{Bux`WnvM z=esq2L5`yf!r7q=N!vFfjUi7TkVplBGBWdBtGG5i2@s;(MdKz8(Cga55Fwi9@C#3s zAiiq-+r3m!t+Xn+0q{craC7mXXJW?lxP|BhK_>!EBc%)?uNs{tPbY$?W*{gc|=s?DpMT=k}(9i1itlY7?-@2$OPxD}S3ZF!65~oIpNsKi_)h zSE}g{yhU%13_aTw;E;8iu%7;lF7YOAbR3{mexTli!_vvbpY1&K0=VgWfHuGCX9y9L zndC}%nN5UOUs@54_cU`6hz*>vQO|Z3ED+y0ehz`*!S|2%xCW)y)EnFT7CWNGAgTzh z-Dibl6Z~f^NOFWC*yesDFAEghvwgKptNv9WQjt@UNisUm|w;LNY>!b@pM^)2Zq zjuBZFOPP-K5$ti%Cw!R4fo5*sdBm-n$)_*vw{k^mr^tIOyvoGms=E$g?`kH9(cda^ z#_sgL@mh4+-0Kz0;?w0-Q;KwtpZ#bDT=3A=0GXR(`;5N|kZ9qcA|^oUt^$zf-U0 zS1f)0VhvQp(U=-HM8;D6-gRp)`;Z8Tq$Yn{n{VFGQbdU@YEq)rH zi~B!^Dyhg?=EB2li33 zRvMaqajN%?G4fN@5A2P-!_-2OPqqwqN@m@(@ZdxY{p$`(~?vmyIo{l_N`4?fv zod(T@@lZz`66@<=Hk8hw&O=I7kx*|VVq#^;uc$0~_Y{clb+h?k&6B6Nu0-wuqoDiG zbx*4$rbxelP{;LVj(^}DoKPJ^Uv;=rObvQn5_=b*?_#{{?zJaIS$wU5LevI5d_MLOJKqX8a z%P)0jc{$OOokt`*<^i~rvCyavE)OX5^>v;|u$;MTzC!|lnVs9xQoa!RXf6TDgz17z z8~mhWZr#+IHIHdg=r-U z5_1zv?e|_6VT$IS2_hmvpzRT`ulJlQnj8^Wwd^vm(+!2u4|dv&am;>1-l+UtXmh;+ zP(FHt@?l({Wf$GPpmwX?4@E@5B%U>TZw{Cfr8pU}?|!P2TCBrMJyr&L&<~e^>u2^= z2`B<8K#2b=IF-7HWIxzIWmqQZK#)b~&BqsdOPc^j6uSA%n0>hY@x4%EhCe^GkHIwg z4j!7V&D9E!Hd#4zB`Y+vRA%9zhxC}q1MKwgXRcI#i=7%RJLvS6U5lT1zc8mWA75s2 zypeI?+cegQb@15hL;9G`#7a}bKbc=CQ0r_xy=cZ2U<6VyKK^`$S%tzS0urHkiVg+- zmZeVylk{#s%~$QhsA9F6NOP`W{U%bT@A!RitB&{pJXiVH=YUaHYZR`#upntvpGmO2 zD7&2L176eIcoJa9ma0bm1heW^l{%nor;swj%t?t}#>A=zOeJOaF|y@bj#monlbYC%r)Fgy`N5lXW7>P@ zQ|e1SY-q!;Ki9-ZQO4q}aO8JW(o&wv?7h3IzlLW(CK80tIN8ZPKi3K-v3Fwh4MgZs@uNUd67Tr}l#b00{%kRR;or4x zn=>^HD@y5f65+4|o}WVCfUy_rH&S}GGA3rqtLOqBd>9zh4-yNnxAvThD*gpzl_oW5 zue9)Z(ttw^Ko!u2Osm0Rbdn6}jhmm72M&5p=-uM*f&PH|MOFMQ4!$)|*iFsf9}o@f4Bb}xB2+n; zo2_0zJJo>^mtB*&5uUnUs-a!_CAab#=sax^uk6`o-GRS^DL`xAs`DbTfNSqy2`T|2@@HSuJe8;`fn$ClOr#wF4&i zYOFM5V>twHubxWk<9d>QGfh)lOoAWBdr~ISJc9_#xX!ctdEb747J~P7D-d7mM=L3` z$cpbDE52KE{aTbFFmMhhoB+6JD2*!mwdz~&$aUP;3!To86IIZE>6w2F&K94$U)Q*k z_>zE)8Kr;%thi>eN%6y1c?Rj}Sd6C6@oe=LYPF@}897J2C?9#fXx(6Rx4ndIM+``1 z){l~3;&*52D8Zv*=0>H!i(%w()Lf!zk?x%=9ZW&!$2Rh5?f=5!cpVdN5(j#cD&7@k zr>xI|&cOX}0?a*Hz$To8L42`Sc$0SX1Zc$OTMvN^Ity4KKl}kDqlEixVr1dpxvn%3 zrDr>$$v~))#tKevxBcxG3E5k8DJhl9`@x|RhIL#-e2WF(SeTv;D*P@+ECH1v&Pk6* z;zy$INM(F(J>;<~YeopEtO=nGbtlNzu(P>s+aHCSgTAC}G4Y);^D6Yu&sh_#&wnHdCPL#hJmZ>S@m5n7cxVFR>E{%Js-=_@{uRwgR|B zl^BN_W%4Upa^MD4lq3CIDP@o+;_ zQ1%_EN+YOsAtZLNEyVrTf+BEv+xLG>${u)OYjopPh5J0IqK2e}N+|~?hXo}q@%2P1 zf^8y6$3cUYfhAxTsZ}S`RAMkM7Mky66Q?{BdqA$iMl2y8+WGU-%^&uO-Zon^-;IDA z#;pmk0>GfEdtWrK1N1%)8a#1gKq2-Cv|AM?YSI|TS{O&qpZVv1S};*OXn`D3(4or&DC~JLJI(uEqx4-pdB9feR%~bdlVF-&pjGTK!_Q!cIFP_CsAEBa4D%saf zIJDGDCPzV8FcNVcTap&10V%qghWelYi6t_z#`R+^{mF|dX}4?EFU&Npvuo&|vOP`h zayrMU51=$3pW_fIt^glMrRh>HbdH9>=|SHUQvas41F#i$A9hi5e|sto zLfFwHLmyC~1$>NpVB|sr8=sU*U&Od~z5?`K8^}|e`H<|~`#bQIIP(L7l2QnyWrk@| z-faxx<;* zg13p#{Wh-HbuyC|vqwaYC*t;j49*0SE~)9jffBZ)VgCeTj0kP{#m1C#pr-)RdYgC< z3991~KH-ta4+i=Up={PWbPhVWhfsPQ z`>ngcyaovy`=OgJC7+tehl_MMZs|El;#cf75n5>ru&P+xqqVv8!Gmclx4c7VXl1YK@F zPp)l!3kr`S%@(?C?F*Ka5f-Abh7A+2qIL>X)3~5bN6KlQGemx%xnF;o(AT)+QAy#3 z{cXB!&Fb5SF@nT-rRg0LE{yIc zZ{5w6ah5;AEHX}#yP6NhymPQfs(bm zcW%*m4`tE3SH>OuV+7^B#d)VWozeF&hzcWD2)@l3fJ^P~%B<6~3e7Y|0y`yp!beg%gkC!|N0&)_vm*L74h`4d zZyka&WKTehBMAS}hT!0pThih9xX_TJrY}0ro~920H;k+y$(SRcoX#JIAw)~4%yG!H z^jp)dp+6ytPvIJ-@7qQIiSXuf0#mUd6P{Sah>j?IOEtTR%GrE8L&V?#2T&>Ka}+4W z5r6P-baYQPRoyZ2(Q06#WOUF@Se8e^xMI z`rqG@2z`vMeBdv504GGD;V)ph&qk)d40zMCqDh+n{XM$K=pB25GM^ zz;#>wy7ZO&?Coc-o&P3ARTo0JcrVpGiczJ3P%hjj$n&tY&=ivvy z^&s=%%=Pf^pZ?F=fC>hLF`esVN#$72xK$8&0YyEYuaxIY=l}aBH62tw=xF6La~nWO zhc7OqB%IHa4G>*<(?!}b5sf!nmF8 z4qOkVyp#o^&y7AAy>D&n{O}IK#esNL<`W-?@`(CZOcK z7Y7j6xRDyL)XMz_NfVv`;GunEvcYDuKDfW4?Dx}T4De0&Kg|^ct?L_*C!;^tnd0z5 z9<=yS7;s$nAmOJ6>CHD{D&aQJKT1lX%PkxntjZU;EnE4%SUI2sK7P zi!_}4?}f{wHVXm-{FEaP@JqFPc=rF@;c#84@Y_av8CX0Kui=%%+*^P#69{u%IH>6@rJuob`a!VS!>FTe$?IQVIV1 zKENsi`L#&$;GRA|`Ui-7le+TTbWiD#R}zP!k_042?0i` z^G_CU?V)pZzkad{xY$V8BGlO9r0SDJ^9592{;#b7Mq&_zjty<;*34U|Kp~Bnn&;b3 zRb0MZV3Bribu?u$DDfy_5IyXy0*MK#_oGl4OH+owFh-|B-F;jA(vu(k{{q1p^cP1! z)HYB+Cx!ZCM5&S)XgoA)ebD?H3pSsGmGwm33~6$o9}57g@w||L*3;pDVpW23syVjn7a)vjX^uZxGn(5ih@88zStIX{&{M-K zje>4BaN8qmW$aIyOJp%zC|VsZSyf8Q|Hit|^~2-JN%yu6AF&buaVS;K-@iov*dWXN z!WIqs{k48zM}*DVmnuJ(n=1ie+z%=!SvA|FJR;cD$B+gSNHmFGs&tX=7(G0*<=EaV zRSwVPmxEWX+oQfA-!i}U2QZRk3}pV5p8I#DaHEwnd%*AvPTq6*X$ENUuu?Fm z_6**}+Ty&BR*KKrjlCjNEYukJaRIN2xTz{>*o6cryQv;&%fx&>6b6}&OSi)b$LN-@ z5?H1%VI)aF0Q6JR*{}m5$HXl+b)jofCf&JH(5NQE_Z7J-$A`#XC*`^1a;k4_6O$Du z4EH&dj?)Q6pjsVujw_2GcJJfNcqR z;bk{-iM!kAokj*Bka<)Sd8`^BLEFNB>0R^3&J-*6%6)3;&oHZg_?^@t73FZO#jJI) zHGM#QufN(msk>qHc2LQ|m0rA)a7X)jT3Z-&)Iq3~h9||A|XGpHXr0(+DbBoy!y8X0mCZ1uGmH_~k4_b$Zj}eSH zrFWi;Db2*3^fk8E@MF(q>?(BVIYC8H9!l>@yUFvGOtlzsV_70myxjqE9*U57=>usx zvCpUZTKN0C+~>x+e8d@~?*l?kcS1I1tViPowu*K*w?k>LYQ6Afk{K@dc)jvU0YIK6f+Vcozvi9gy)NM){_~)_w%^Mdc zB`{lV?YN2kqPq$RDHoJ)y&OK08r@Pqrg7_~+iQx=!PO}zw^zwRahOU{KIk+k^qlaf z@{2*m1p}{RJgX1oKC!tgPCc_J7PD8xV=Cz^X8w7Syu%8yOnKx z+3WnqPf@^-E;O=joB%vo^dwXJ(`$VPp>fjU?5Nf4w+Eax+wNp?9MRkU%^fMayfb}w zpBewwJ8$Ecs>(9`%lQCd5M=(=K}VNaC$@}# z0~Lc70dZ!#kEG+kiX^b8R^t69HoSi#Tw&$G8S}j@GjXC-Varajn}2wg*o$Zeckw;oB2po-*_fJ( zIta9jVL~~WuA=Ab5GE@dK$x6)*ZU{h{b;_wjQK1mRlcRhF??Xtk}%J<6VP8r9Myz| z7%xPCFb=+_ZsQZ@O=YTrC$|^ku*I+6Y@!T2{)?wfxYl?6^HXRR#!9idB~3dy(6I_s z2M?UOv-K)7p(o_#xc&Ii6M4e7PCSEdKKbfax+nD0tbY=u4{&(Q$4+n#wP!zTglfv_ zdcv_o->+|Axvop3Jy`>wP)gbD$k#wERY|A|(QEjuaZvRu=2 z>51OvpxR5HcYMHPo-d_DO|lro!^G`u?|upwSA*7UX3ZLY0JfQ&kCFQ>_Tfse$Xg-9 zoDY4s6Ccp*qZYk$v?ufnlefq6gq%fFN=PW(=6!j{ifOGP0jy8bQ_8BbO(Tx~IM-Y) z-*aV%YTq+x(?F7$l_UhywtK)KqyVY7Z7jFwUwyg5ru-@*O6T&GHc#rxW~g253Z~e& z>9hcM(s&}vI2&UaFNe~x25fJs{^o~~$cF_a>EVDT=oLojXSD0m9k>;Bs%-v5_tBpr z-cMHr zjdEj|ZmHXqiLdW;#Uh^Jhd{JWA@lOb(?z->jNjf8c`Mh6%5SJTSZlUUy}_OJenI(( zLHV>@$<8WVl5pbHPJ!B-i!5UP9E=^O`jFt}b4dr1YNTb&>xd&z)Ft+LcMhj1ApV#4 zvNd92^FF)J8FLB5J_HBObkqfo#+_VL7gkxhgXvaLbET2T;`{2b)<%lXeigTauN zb8e|d=d5wxiHTbZl|^EIG#)5_78xcU&eQJoGIlU*?aB|;o?O0vA@9%|ZDqohx!=xbEV@M`4UG$biBnS$Lca2EUQBcw2HlQCd@>JK)2?qMcuu?PO zyl|=%wfsBK|6{W^fO5A@Re!~YP~m6FY-mY{8{p!^viSWQVB3fpeexpExF#sgGJMF5!l#0B>8_ER8qc`D?I37p#r2=FopE2bko%vk6mY zY-*EY!EfTdy14z=NKdDTPN=v3BI2_cfGz8)U{!gy(?O$F=|m*TVP`85S^L{wTzGRj zY7yCAx5dH4uEc|x`4&u%(-=6owKi~nkNTLQ*&k9fL;qnIR3)=v9b%ky*y?op&p+hw zxGxj=ltC6E8109d3imfqQe(Z)5B2Ai(n2g&pVWn@2tqh4@7()f^8eGH@?vY)b(SYW zTc}iY2fj4ewDjRgQ5z^7v*q^p-Vt{35L-CD47Seu;9N0`Jn$TKt(u?dr8^Dq-))3i z!RJkK7`xUNrD#X%{nJjGnw-%)E;2*{=3RF43K){C1~u6(pD_iop`_-mocn7XzAqvb5kHtY=mb0M}SD%L094OqRo>Rpc-AGx=-+hOUBkD=L(9CZ36Tj|A&&Ny= z^;jt(F^QM5jRor;9`VlIEAWY4`Tc)2=BM0}CFo-|% z`%TCjAc+ZH=RiWD1utb2hPqE%`~n?$geYKy4q;`^aFPG`_YbDj4WFvdbckwiB}UNF zS5!(K!H}Q$Ekn**`(5Xle~Oz6t>E=ch&0t zT~5Dlf9AmJDMFpoHs({<0hlg=sxk%nimOz4M||SW82s9_KW|S|Wax1LZGkW+PIY70 zx{i#qZ1%O4+FW_C91 z3tGGZAwinSFcceQhULF3Rr@lk_|;-?ceL-pdsZ|G51A>aA}teNbsK1e|DFyZ=R6TNvM9_R|M~~1fJz{ zc)aGA6E_W}Za`22`b-+L3j@)-^@#rmCPfIW%DIct#m|lM>!CT-Q7fQag{;t|Ac3dm zM78K(ie!k++n_&~4d@ZvyM_ctj{(tzv84BgMmK^{#+aIt0e!owDioHrQ1JPwn1rpn zgGwPlNMg`9(G3d57%6JCiIsT^a;f5jf4r_5yl(xlu;oKs4tiasz#BhbmlIxBch^+d zJ&q$i8xQ7wc71kyWx7G1BS0A9DmKVoIgWLH51ON2Rpb!Wj%|LCf|Y+ zP?=DN$Z)U-OQ{SBkdu0@DHQFTv3=rPW&6I804}+LhW1=LI{_swLgOre3^Mvo*<)I` zp5(+RKnY3t0V=>#y_`D0bjkaMv7JW8-b5MJ(u55LhpEptIL1i5t(3KlRQTuj!d4GM z=IL^Yh80!DJ}@P0_xs3p#$Ob6OeQ`w_u(|bfJ+mJ#EJ{_BOyxw0b3zsZwWB^N6X_P zht6iamfL@Oo`EhbCpD)B;%Q+c`oS=(w3os)5^tE7-m#dpqUss|jWVF+Y6bXiey1I8 zd}eiNh?AoeKNBXK#NSrNb=~3Mu7d?&14jX}m`gNW9=u7Z(H?g7f@Bpoy2UVf|JzhQ zyn{uGv`@XJEZ;7P8}sAAEsmYbagCuO>lP+~AB>B|EL%1n%Lc|JBUXMd`9pn1FkM!` zF4f;5g?jD8wp8P|x=l1rs0E!$FZ0&E4^Z-^B1(GPD!11q9vCklMBcT6PXKu@^ZUX+ zs;y8t{j9MoIx#sh7~hbc4IEQN))n>IKG-H#wL%apij-}3?#9HKxnzq5rg(*%_a6dz zlsXHJv07XMwUZ72Y5FF0UB1Kwc#A=M#w@6|){!Lf*NQ}<)Txy~hnK;R>q~dS_W4_Z zwa?$V-xGaEJWJX6b->a!_#oBhaq;DFr>c=!&wotMWU7CT%M)moEXj zTwvkwpc|PmBoQNf=tk6bBq2W5@4;E;S&VR8CkW(kIrDlz&ZJ)DW^9}>^y?2U%e%NVFs6Nqk8Y4%jQSn0X%FQDN>-Mr&k@;8 zCitv!-zos3q+B~RO;Ib2pFZFq^)zUgw1Hf0$n=wRlaxVwIUW&w0yShm2O?p9>;4H9S40L!HTEdp=rnZhT{tOdiv#*KLV{I z4f;?DY(jl~>oi;Je`x`90j1K`Ckl!Q^|q+5EKhwBtVqyMFO89xT6vb-3I)j0;t639 z!6t`yeX}{b(Aa1{UgySGR*W-SvNO+}z7Q;q#)t8fam;HlJi$@Mc-$iwo$--vjK zjIzHCvb%>2j20GfXC(Z4H*T$@JXDOiT7N6iyuqB#r$*tCXYdX8J>Jo?+L~k`SO(zQ;Kt{Hq|R zp=#iQlU%65Azo&z*7`yZWQ2v@SMZRA3l0rRN&Pr(F0x6mrnbKnw(Z^5k6e)~E5)Lf z-rH86tSN`=Z}N!LYd8{ZH!m!)gLl_5b)wQthaY8q#S>_)9%i!kZpqxV3IOvEi7r0} zg~aEl_pdGS=oki#&JiOZXgv!wy_;=$KRj+}+dKHBdrA=_6lu-rE0UcQUT*yD-o@+$ zm)8n~0%iws*u;m&9+URL?n~f<^O=9vU|MR41rl_gCEy1MUcDHMJCkw#6z9#g8w%vd z`{s9BF8S8fY{^RSrNv0=NVe!S(kHmQ8$o7B4;_ge-;4h|0ND#iioKpazyPr)M&8&& zV0v9wAYGc=aKn9iaF0m6!ULHLG=Dj<)KE6GDdF6--14;CP zNOlWUC5?a!k+WO)a$fQqB-^YPvM@DZ2tZ?(b5n0tgQ{>UOI&hCR+P&1kKq74=4Y|m zd~J!-e|hnC^(E+3-$Z!=iHSK5*1yZz>q|1}0QkXZ6=m;^gP*lqE%jRmtC(_*CmL%v;r**I0~`zP9nnVW_rnl;cR?0u{oNIuy>2cDjk&6|PV3O?EzUZ&99nPl-n#Ptd|k@rlc zT1w*g%6b%LLwUq<5_5EgA5*BfU6e7jIPu6eJRn!%{`&Ri9ZYBIqz)l8P4f{x+&m?7 zyn5pF9imVv|GVH~a4Q8X;$A;AIW+(bx@%YX?2kZ06sy{p6WGndvODmOgAn9>1ifZV zNN_ob-vrOf2fpxY=ic1U5%FHd_OsmZJYP(FDiF>DUx1#E02HV^>R?fRw&&`i-pY=H zdIQfsLQjk%m^n=!D$Rnt@S$f`m3D0(ItF(4Yf+qRI^`a_8k``O?FNK6!HR{B?o}~G zT~X46)*OF8GgZB#E@&gNe)@v_9Y5hFkU?5@KfR5iA_SJ0QDvYI`VeOTCp+n#t|srt z2+7Qcx7AudTJifJvimv$9oP~F^>+W>^cTCii;oj;{ z|0G}dVs0rU9Y4!w&hVM(wdU(@fVn8L*DI|d9~5>`R4dDz(sgY`?PyaQb;Hecd##U7 za{1hFe>!WIXR^Gos>PKfSU7%iO*l>sbH_m?+0#rC$_NBjf;GM!QPs6iCs|2#B`=og zjB9mTtU(RqNK%|H4euB6^+DN!;z{pFd2w~)UV@X z17$u-kBcP2WNEZ8a|2Q1~-Oy(Q!J7|orf)ih{Rcq>ca@sS?>_;!g^%6)-Rpxv{;gjKE?<~C za_BS`Enw}VBXTIp=erAUg}IQZ{`Np$)0(vzK>{)+I<0=s9)unE&?aOb>VXz~3X9rDBD0?=;i+jDw`z9JSLhW%@x zD7pf7175W^{OYE^E?+>GuevMKGRX5l6c(~|iR=Q=Ak%fCm7nSN!S)lks6g{Kx&5gt zb)Pys%=W95tmq1CF}&);M~U@w@aN^r=<+og(rxPa9RNWo-dQ0J7zO~HEbIu=I_5_< zrRseMU2@s1ah!_42M_a4o+%j!p*Mk7oxdEhjzj&td=*8Io*WG)sWi9HS19nj@gR?* zHyr;4^s^6X{`a^=T;WaLPocu)X~m0{!;pS~T=u7&){75%z7%?{LDkbJ6imHPM&T@&9qTc12($S zNW){;KJB2?cp19XBxQI)g*ZCy&PL0)Yi^3)dC0&NHAlhF?&Pj1g7m})Ri1a?pd5RkTi4OFj}G|afn`gEoo-|p5IFcHw*JxQ_L^PsV)HfLoopXmav`n z!3utKPHxGw?#KTF48lmDkN0AY$M1T3}| zX_k~B!YOA1g#@EPW{;=b^C$fbuiCLDlzjb`I=xU371w-7)&1+a=y$E3lLX^Wk(VO; z5YPZ4pg7{#{_yo0td}o}WH^ye05-;hlw+Ja_=X1-r>o%19L6U|Pkj&;gE|^F5F<(j zbR%H$ZkRccZgePlG(J7!kK_o5vFNCQtHJ`?{|h`MtblOkh&Qd^3uyY;hQ#GSI!BI^ zE;<+g85l2bR06)ySt{m?Q}5kFTl^4J@BIWGn3jcER0h+E&&}4$;Z`RF&yUdf1~qrFKENi@6>TVo$>)vq66Nn2CqoS5okRE ztgA$s}ILH)1IU3K!|kRa?pQ1|29Dq6os8nu@Z zoeD5QfpQT{7%Au#AX_SCOCLAyu`Qgy9|K9o<+0%C4AlPTz$MURB-Kf@wL&@VHqkNKGeA?Faje>+Il4Vp{)il)OQt z_#C=$Rg5wLIqt!3eg(+Rnjy#C!YRd@jpp?TNM{M2jl&Wt1!?Y>YmMVh>@7+A0CCAu4uXEyT43jtpRZAtQET;vN{FPVm7LxT6;d*2Ck;~HUl6rbsq6y z4U=-T%yuZ<0|}OERs&RXw@a277!9uQHr-{<)*%WOnd=?yhvqh-O}vHfP{(NN5QP5% z9nTwmCN)?SbY2|j`nWmlX+%1^AHKmR_Rm$e`F#qfQ1Ikt_6}6kc5c)ahT<><66zmo0 z?}ps`DBvzgfI%M`!yBo~Q52T%b^Fj4=EJ{1^s8J;dbcKqZDrzyN3(NMgR)^Bos3Fm8H

    ^M*lERY{v&i64-?5!m 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 Je8ANEe*l9K+dlvR diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/flattened/TestDateTime_flattened.sol b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/flattened/TestDateTime_flattened.sol deleted file mode 100644 index 4efeb9d..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/flattened/TestDateTime_flattened.sol +++ /dev/null @@ -1,439 +0,0 @@ -pragma solidity ^0.6.0; - - -// ---------------------------------------------------------------------------- -// BokkyPooBah's DateTime Library v1.01 -// -// A gas-efficient Solidity date and time library -// -// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary -// -// Tested date range 1970/01/01 to 2345/12/31 -// -// Conventions: -// Unit | Range | Notes -// :-------- |:-------------:|:----- -// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC -// year | 1970 ... 2345 | -// month | 1 ... 12 | -// day | 1 ... 31 | -// hour | 0 ... 23 | -// minute | 0 ... 59 | -// second | 0 ... 59 | -// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday -// -// -// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. -// ---------------------------------------------------------------------------- - -library BokkyPooBahsDateTimeLibrary { - - uint constant SECONDS_PER_DAY = 24 * 60 * 60; - uint constant SECONDS_PER_HOUR = 60 * 60; - uint constant SECONDS_PER_MINUTE = 60; - int constant OFFSET19700101 = 2440588; - - uint constant DOW_MON = 1; - uint constant DOW_TUE = 2; - uint constant DOW_WED = 3; - uint constant DOW_THU = 4; - uint constant DOW_FRI = 5; - uint constant DOW_SAT = 6; - uint constant DOW_SUN = 7; - - // ------------------------------------------------------------------------ - // Calculate the number of days from 1970/01/01 to year/month/day using - // the date conversion algorithm from - // http://aa.usno.navy.mil/faq/docs/JD_Formula.php - // and subtracting the offset 2440588 so that 1970/01/01 is day 0 - // - // days = day - // - 32075 - // + 1461 * (year + 4800 + (month - 14) / 12) / 4 - // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 - // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 - // - offset - // ------------------------------------------------------------------------ - function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) { - require(year >= 1970); - int _year = int(year); - int _month = int(month); - int _day = int(day); - - int __days = _day - - 32075 - + 1461 * (_year + 4800 + (_month - 14) / 12) / 4 - + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12 - - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4 - - OFFSET19700101; - - _days = uint(__days); - } - - // ------------------------------------------------------------------------ - // Calculate year/month/day from the number of days since 1970/01/01 using - // the date conversion algorithm from - // http://aa.usno.navy.mil/faq/docs/JD_Formula.php - // and adding the offset 2440588 so that 1970/01/01 is day 0 - // - // int L = days + 68569 + offset - // int N = 4 * L / 146097 - // L = L - (146097 * N + 3) / 4 - // year = 4000 * (L + 1) / 1461001 - // L = L - 1461 * year / 4 + 31 - // month = 80 * L / 2447 - // dd = L - 2447 * month / 80 - // L = month / 11 - // month = month + 2 - 12 * L - // year = 100 * (N - 49) + year + L - // ------------------------------------------------------------------------ - function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) { - int __days = int(_days); - - int L = __days + 68569 + OFFSET19700101; - int N = 4 * L / 146097; - L = L - (146097 * N + 3) / 4; - int _year = 4000 * (L + 1) / 1461001; - L = L - 1461 * _year / 4 + 31; - int _month = 80 * L / 2447; - int _day = L - 2447 * _month / 80; - L = _month / 11; - _month = _month + 2 - 12 * L; - _year = 100 * (N - 49) + _year + L; - - year = uint(_year); - month = uint(_month); - day = uint(_day); - } - - function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) { - timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; - } - function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) { - timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second; - } - function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) { - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function timestampToDateTime(uint timestamp) internal pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - uint secs = timestamp % SECONDS_PER_DAY; - hour = secs / SECONDS_PER_HOUR; - secs = secs % SECONDS_PER_HOUR; - minute = secs / SECONDS_PER_MINUTE; - second = secs % SECONDS_PER_MINUTE; - } - - function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) { - if (year >= 1970 && month > 0 && month <= 12) { - uint daysInMonth = _getDaysInMonth(year, month); - if (day > 0 && day <= daysInMonth) { - valid = true; - } - } - } - function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) { - if (isValidDate(year, month, day)) { - if (hour < 24 && minute < 60 && second < 60) { - valid = true; - } - } - } - function isLeapYear(uint timestamp) internal pure returns (bool leapYear) { - (uint year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); - leapYear = _isLeapYear(year); - } - function _isLeapYear(uint year) internal pure returns (bool leapYear) { - leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); - } - function isWeekDay(uint timestamp) internal pure returns (bool weekDay) { - weekDay = getDayOfWeek(timestamp) <= DOW_FRI; - } - function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) { - weekEnd = getDayOfWeek(timestamp) >= DOW_SAT; - } - function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) { - (uint year, uint month,) = _daysToDate(timestamp / SECONDS_PER_DAY); - daysInMonth = _getDaysInMonth(year, month); - } - function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) { - if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { - daysInMonth = 31; - } else if (month != 2) { - daysInMonth = 30; - } else { - daysInMonth = _isLeapYear(year) ? 29 : 28; - } - } - // 1 = Monday, 7 = Sunday - function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) { - uint _days = timestamp / SECONDS_PER_DAY; - dayOfWeek = (_days + 3) % 7 + 1; - } - - function getYear(uint timestamp) internal pure returns (uint year) { - (year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function getMonth(uint timestamp) internal pure returns (uint month) { - (,month,) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function getDay(uint timestamp) internal pure returns (uint day) { - (,,day) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function getHour(uint timestamp) internal pure returns (uint hour) { - uint secs = timestamp % SECONDS_PER_DAY; - hour = secs / SECONDS_PER_HOUR; - } - function getMinute(uint timestamp) internal pure returns (uint minute) { - uint secs = timestamp % SECONDS_PER_HOUR; - minute = secs / SECONDS_PER_MINUTE; - } - function getSecond(uint timestamp) internal pure returns (uint second) { - second = timestamp % SECONDS_PER_MINUTE; - } - - function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { - (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); - year += _years; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp >= timestamp); - } - function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { - (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); - month += _months; - year += (month - 1) / 12; - month = (month - 1) % 12 + 1; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp >= timestamp); - } - function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _days * SECONDS_PER_DAY; - require(newTimestamp >= timestamp); - } - function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _hours * SECONDS_PER_HOUR; - require(newTimestamp >= timestamp); - } - function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE; - require(newTimestamp >= timestamp); - } - function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _seconds; - require(newTimestamp >= timestamp); - } - - function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { - (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); - year -= _years; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp <= timestamp); - } - function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { - (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); - uint yearMonth = year * 12 + (month - 1) - _months; - year = yearMonth / 12; - month = yearMonth % 12 + 1; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp <= timestamp); - } - function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _days * SECONDS_PER_DAY; - require(newTimestamp <= timestamp); - } - function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _hours * SECONDS_PER_HOUR; - require(newTimestamp <= timestamp); - } - function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE; - require(newTimestamp <= timestamp); - } - function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _seconds; - require(newTimestamp <= timestamp); - } - - function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) { - require(fromTimestamp <= toTimestamp); - (uint fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); - (uint toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); - _years = toYear - fromYear; - } - function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) { - require(fromTimestamp <= toTimestamp); - (uint fromYear, uint fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); - (uint toYear, uint toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); - _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth; - } - function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) { - require(fromTimestamp <= toTimestamp); - _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY; - } - function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) { - require(fromTimestamp <= toTimestamp); - _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR; - } - function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) { - require(fromTimestamp <= toTimestamp); - _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE; - } - function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) { - require(fromTimestamp <= toTimestamp); - _seconds = toTimestamp - fromTimestamp; - } -} - -// ---------------------------------------------------------------------------- -// Testing BokkyPooBah's DateTime Library -// -// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary -// -// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. -// ---------------------------------------------------------------------------- - -contract TestDateTime { - using BokkyPooBahsDateTimeLibrary for uint; - - uint public nextYear; - - function test() public { - uint today = now; - nextYear = today.addYears(1); - } - - function timestampFromDate(uint year, uint month, uint day) public pure returns (uint timestamp) { - return BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day); - } - function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (uint timestamp) { - return BokkyPooBahsDateTimeLibrary.timestampFromDateTime(year, month, day, hour, minute, second); - } - function timestampToDate(uint timestamp) public pure returns (uint year, uint month, uint day) { - (year, month, day) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); - } - function timestampToDateTime(uint timestamp) public pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { - (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(timestamp); - } - - function isLeapYear(uint timestamp) public pure returns (bool leapYear) { - leapYear = BokkyPooBahsDateTimeLibrary.isLeapYear(timestamp); - } - function _isLeapYear(uint year) public pure returns (bool leapYear) { - leapYear = BokkyPooBahsDateTimeLibrary._isLeapYear(year); - } - function isWeekDay(uint timestamp) public pure returns (bool weekDay) { - weekDay = BokkyPooBahsDateTimeLibrary.isWeekDay(timestamp); - } - function isWeekEnd(uint timestamp) public pure returns (bool weekEnd) { - weekEnd = BokkyPooBahsDateTimeLibrary.isWeekEnd(timestamp); - } - - function getDaysInMonth(uint timestamp) public pure returns (uint daysInMonth) { - daysInMonth = BokkyPooBahsDateTimeLibrary.getDaysInMonth(timestamp); - } - function _getDaysInMonth(uint year, uint month) public pure returns (uint daysInMonth) { - daysInMonth = BokkyPooBahsDateTimeLibrary._getDaysInMonth(year, month); - } - function getDayOfWeek(uint timestamp) public pure returns (uint dayOfWeek) { - dayOfWeek = BokkyPooBahsDateTimeLibrary.getDayOfWeek(timestamp); - } - - function isValidDate(uint year, uint month, uint day) public pure returns (bool valid) { - valid = BokkyPooBahsDateTimeLibrary.isValidDate(year, month, day); - } - function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (bool valid) { - valid = BokkyPooBahsDateTimeLibrary.isValidDateTime(year, month, day, hour, minute, second); - } - - function getYear(uint timestamp) public pure returns (uint year) { - year = BokkyPooBahsDateTimeLibrary.getYear(timestamp); - } - function getMonth(uint timestamp) public pure returns (uint month) { - month = BokkyPooBahsDateTimeLibrary.getMonth(timestamp); - } - function getDay(uint timestamp) public pure returns (uint day) { - day = BokkyPooBahsDateTimeLibrary.getDay(timestamp); - } - function getHour(uint timestamp) public pure returns (uint hour) { - hour = BokkyPooBahsDateTimeLibrary.getHour(timestamp); - } - function getMinute(uint timestamp) public pure returns (uint minute) { - minute = BokkyPooBahsDateTimeLibrary.getMinute(timestamp); - } - function getSecond(uint timestamp) public pure returns (uint second) { - second = BokkyPooBahsDateTimeLibrary.getSecond(timestamp); - } - - function addYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addYears(timestamp, _years); - } - function addMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addMonths(timestamp, _months); - } - function addDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addDays(timestamp, _days); - } - function addHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addHours(timestamp, _hours); - } - function addMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addMinutes(timestamp, _minutes); - } - function addSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addSeconds(timestamp, _seconds); - } - - function subYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subYears(timestamp, _years); - } - function subMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subMonths(timestamp, _months); - } - function subDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subDays(timestamp, _days); - } - function subHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subHours(timestamp, _hours); - } - function subMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subMinutes(timestamp, _minutes); - } - function subSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subSeconds(timestamp, _seconds); - } - - function diffYears(uint fromTimestamp, uint toTimestamp) public pure returns (uint _years) { - _years = BokkyPooBahsDateTimeLibrary.diffYears(fromTimestamp, toTimestamp); - } - function diffMonths(uint fromTimestamp, uint toTimestamp) public pure returns (uint _months) { - _months = BokkyPooBahsDateTimeLibrary.diffMonths(fromTimestamp, toTimestamp); - } - function diffDays(uint fromTimestamp, uint toTimestamp) public pure returns (uint _days) { - _days = BokkyPooBahsDateTimeLibrary.diffDays(fromTimestamp, toTimestamp); - } - function diffHours(uint fromTimestamp, uint toTimestamp) public pure returns (uint _hours) { - _hours = BokkyPooBahsDateTimeLibrary.diffHours(fromTimestamp, toTimestamp); - } - function diffMinutes(uint fromTimestamp, uint toTimestamp) public pure returns (uint _minutes) { - _minutes = BokkyPooBahsDateTimeLibrary.diffMinutes(fromTimestamp, toTimestamp); - } - function diffSeconds(uint fromTimestamp, uint toTimestamp) public pure returns (uint _seconds) { - _seconds = BokkyPooBahsDateTimeLibrary.diffSeconds(fromTimestamp, toTimestamp); - } -} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/images/clocks.png b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/images/clocks.png deleted file mode 100644 index 419fd1b9763112e7055c70ba6063553b89fbc7a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1843439 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≶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 z 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

      LdX~CcOB^bYOTT+ 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

      PY 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

      MP&7{`%G3ox9F@nJ5Gf$AFzx2r1%JgIdD*eBL$> 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 z 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�kAC#czy9mZlbc`r+SgjG*1LdHALttX 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


      16osIiQ9?ygIMlKEQ(8-Nkz{FvZyz)h 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ÊbL| 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

      U72m^{xYmIp@iB!EFGlB>)a&a_aRxJg= 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

      EzO#bP?0B%_g(^uu3%fiN14k|<2H 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 \$contractsdir, - "remapdir:s" => \$remapdir, - "mainsol:s" => \$mainsol, - "outputsol:s" => \$outputsol, - "verbose" => \$verbose, - "help" => \$help) -or die $helptext; - -die $helptext - if defined $help; - -die $helptext - unless defined $mainsol; - -$contractsdir = $DEFAULTCONTRACTSDIR - unless defined $contractsdir; - -if (!defined $outputsol) { - $outputsol = $mainsol; - $outputsol =~ s/\.sol/_flattened\.sol/g; -} - -if (defined $verbose) { - printf "contractsdir: %s\n", $contractsdir; - printf "remapdir : %s\n", defined $remapdir ? $remapdir : "(no remapping)"; - printf "mainsol : %s\n", $mainsol; - printf "outputsol : %s\n", $outputsol -} - -open OUTPUT, ">$outputsol" - or die "Cannot open $outputsol for writing. Stopped"; - -processSol(catfile($contractsdir, $mainsol), 0); - -close OUTPUT - or die "Cannot close $outputsol. Stopped"; - -exit; - - -# ------------------------------------------------------------------------------ -# Process Solidity file -# ------------------------------------------------------------------------------ -sub processSol { - my ($sol, $level) = @_; - if (defined $remapdir) { - my ($splitfrom, $splitto) = split /=/, $remapdir; - # printf "%sSplit %s: %s => %s\n", " " x $level, $remapdir, $splitfrom, $splitto - # if defined $verbose; - if ($sol =~ /$splitfrom/) { - printf "%sRemapping %s\n", " " x $level, $sol - if defined $verbose; - $sol =~ s!$splitfrom!$splitto!; - printf "%s to %s\n", " " x $level, $sol - if defined $verbose; - } - } - my $dir = dirname($sol); - my $file = basename($sol); - $seen{$file} = 1; - printf "%sProcessing %s\n", " " x $level, $sol - if defined $verbose; - - open INPUT, "<$sol" - or die "Cannot open $sol for reading. Stopped"; - my @lines = ; - close INPUT - or die "Cannot close $sol. Stopped"; - - for my $line (@lines) { - chomp $line; - if ($line =~ /^import/) { - my $importfile = $line; - $importfile =~ s/import [\"\']//; - $importfile =~ s/[\"\'];.*$//; - $file = basename($importfile); - if ($seen{$file}) { - printf "%s Already Imported %s\n", " " x $level, catfile($dir, $importfile) - if defined $verbose; - } else { - printf "%s Importing %s\n", " " x $level, catfile($dir, $importfile) - if defined $verbose; - processSol(catfile($dir, $importfile), $level + 1) - } - } else { - if ($level == 0 || !($line =~ /^pragma/)) { - printf OUTPUT "%s\n", $line; - } - } - } -} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/00_runGeth.sh b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/00_runGeth.sh deleted file mode 100755 index bba6e36..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/00_runGeth.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -rm -f ./testchain/geth/chaindata/* - -# geth --datadir ./testchain init genesis.json - -# geth --datadir ./testchain --unlock 0 --password ./testpassword --rpc --rpccorsdomain '*' --rpcport 8646 --rpcapi "eth,net,web3,debug" --port 32323 --mine --minerthreads 1 --maxpeers 0 --targetgaslimit 994712388 console -geth --allow-insecure-unlock --dev --dev.period 1 --datadir ./testchain --rpc --rpccorsdomain '*' --rpcport 8646 --rpcapi "eth,net,web3,debug" --port 32323 --maxpeers 0 --targetgaslimit 994712388 console diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/01_test1.sh b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/01_test1.sh deleted file mode 100755 index e443682..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/01_test1.sh +++ /dev/null @@ -1,605 +0,0 @@ -#!/bin/bash -# ---------------------------------------------------------------------------------------------- -# Testing the smart contract -# -# Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2017. The MIT Licence. -# ---------------------------------------------------------------------------------------------- - -MODE=${1:-full} - -source settings -echo "---------- Settings ----------" | tee $TEST1OUTPUT -cat ./settings | tee -a $TEST1OUTPUT -echo "" | tee -a $TEST1OUTPUT - -CURRENTTIME=`date +%s` -CURRENTTIMES=`perl -le "print scalar localtime $CURRENTTIME"` -START_DATE=`echo "$CURRENTTIME+45" | bc` -START_DATE_S=`perl -le "print scalar localtime $START_DATE"` -END_DATE=`echo "$CURRENTTIME+60*2" | bc` -END_DATE_S=`perl -le "print scalar localtime $END_DATE"` - -printf "MODE = '$MODE'\n" | tee $TEST1OUTPUT -printf "GETHATTACHPOINT = '$GETHATTACHPOINT'\n" | tee -a $TEST1OUTPUT -printf "PASSWORD = '$PASSWORD'\n" | tee -a $TEST1OUTPUT -printf "SOURCEDIR = '$SOURCEDIR'\n" | tee -a $TEST1OUTPUT -printf "DATETIMELIBSOL = '$DATETIMELIBSOL'\n" | tee -a $TEST1OUTPUT -printf "DATETIMELIBJS = '$DATETIMELIBJS'\n" | tee -a $TEST1OUTPUT -printf "TESTDATETIMESOL = '$TESTDATETIMESOL'\n" | tee -a $TEST1OUTPUT -printf "TESTDATETIMEJS = '$TESTDATETIMEJS'\n" | tee -a $TEST1OUTPUT -printf "DEPLOYMENTDATA = '$DEPLOYMENTDATA'\n" | tee -a $TEST1OUTPUT -printf "TEST1OUTPUT = '$TEST1OUTPUT'\n" | tee -a $TEST1OUTPUT -printf "TEST1RESULTS = '$TEST1RESULTS'\n" | tee -a $TEST1OUTPUT -printf "CURRENTTIME = '$CURRENTTIME' '$CURRENTTIMES'\n" | tee -a $TEST1OUTPUT -printf "START_DATE = '$START_DATE' '$START_DATE_S'\n" | tee -a $TEST1OUTPUT -printf "END_DATE = '$END_DATE' '$END_DATE_S'\n" | tee -a $TEST1OUTPUT - -# Make copy of SOL file and modify start and end times --- -`cp $SOURCEDIR/$DATETIMELIBSOL .` -`cp $SOURCEDIR/$TESTDATETIMESOL .` - -# --- Modify parameters --- -# `perl -pi -e "s/START_DATE \= 1525132800.*$/START_DATE \= $START_DATE; \/\/ $START_DATE_S/" $CROWDSALESOL` -# `perl -pi -e "s/endDate \= 1527811200;.*$/endDate \= $END_DATE; \/\/ $END_DATE_S/" $CROWDSALESOL` - -DIFFS1=`diff $SOURCEDIR/$DATETIMELIBSOL $DATETIMELIBSOL` -echo "--- Differences $SOURCEDIR/$DATETIMELIBSOL $DATETIMELIBSOL ---" | tee -a $TEST1OUTPUT -echo "$DIFFS1" | tee -a $TEST1OUTPUT - -DIFFS1=`diff $SOURCEDIR/$TESTDATETIMESOL $TESTDATETIMESOL` -echo "--- Differences $SOURCEDIR/$TESTDATETIMESOL $TESTDATETIMESOL ---" | tee -a $TEST1OUTPUT -echo "$DIFFS1" | tee -a $TEST1OUTPUT - -solc_0.6.0 --version | tee -a $TEST1OUTPUT - -echo "var dateTimeLibOutput=`solc_0.6.0 --optimize --pretty-json --combined-json abi,bin,interface $DATETIMELIBSOL`;" > $DATETIMELIBJS -echo "var testDateTimeOutput=`solc_0.6.0 --optimize --pretty-json --combined-json abi,bin,interface $TESTDATETIMESOL`;" > $TESTDATETIMEJS -../scripts/solidityFlattener.pl --contractsdir=../contracts --mainsol=$TESTDATETIMESOL --outputsol=$TESTDATETIMEFLATTENED --verbose | tee -a $TEST1OUTPUT - -if [ "$MODE" = "compile" ]; then - echo "Compiling only" - exit 1; -fi - -geth --verbosity 3 attach $GETHATTACHPOINT << EOF | tee -a $TEST1OUTPUT -loadScript("$DATETIMELIBJS"); -loadScript("$TESTDATETIMEJS"); -loadScript("functions.js"); - -var dateTimeLibAbi = JSON.parse(dateTimeLibOutput.contracts["$DATETIMELIBSOL:BokkyPooBahsDateTimeLibrary"].abi); -var dateTimeLibBin = "0x" + dateTimeLibOutput.contracts["$DATETIMELIBSOL:BokkyPooBahsDateTimeLibrary"].bin; -var testDateTimeAbi = JSON.parse(testDateTimeOutput.contracts["$TESTDATETIMESOL:TestDateTime"].abi); -var testDateTimeBin = "0x" + testDateTimeOutput.contracts["$TESTDATETIMESOL:TestDateTime"].bin; - -console.log("DATA: dateTimeLibAbi=" + JSON.stringify(dateTimeLibAbi)); -console.log("DATA: dateTimeLibBin=" + JSON.stringify(dateTimeLibBin)); -console.log("DATA: testDateTimeAbi=" + JSON.stringify(testDateTimeAbi)); -console.log("DATA: testDateTimeBin=" + JSON.stringify(testDateTimeBin)); - -unlockAccounts("$PASSWORD"); -printBalances(); -console.log("RESULT: "); - - -// ----------------------------------------------------------------------------- -var deployDateTimeLibMessage = "Deploy DateTime Library"; -// ----------------------------------------------------------------------------- -console.log("RESULT: ----- " + deployDateTimeLibMessage + " -----"); -var dateTimeLibContract = web3.eth.contract(dateTimeLibAbi); -// console.log(JSON.stringify(dateTimeLibContract)); -var dateTimeLibTx = null; -var dateTimeLibAddress = null; -var currentBlock = eth.blockNumber; -var dateTimeLib = dateTimeLibContract.new({from: contractOwnerAccount, data: dateTimeLibBin, gas: 6000000, gasPrice: defaultGasPrice}, - function(e, contract) { - if (!e) { - if (!contract.address) { - dateTimeLibTx = contract.transactionHash; - } else { - dateTimeLibAddress = contract.address; - addAccount(dateTimeLibAddress, "DateTime Library"); - console.log("DATA: var dateTimeLibAddress=\"" + dateTimeLibAddress + "\";"); - console.log("DATA: var dateTimeLibAbi=" + JSON.stringify(dateTimeLibAbi) + ";"); - console.log("DATA: var dateTimeLib=eth.contract(dateTimeLibAbi).at(dateTimeLibAddress);"); - } - } - } -); -while (txpool.status.pending > 0) { -} -printBalances(); -failIfTxStatusError(dateTimeLibTx, deployDateTimeLibMessage); -printTxData("dateTimeLibTx", dateTimeLibTx); -console.log("RESULT: "); - - -// ----------------------------------------------------------------------------- -var testDateTimeMessage = "Deploy TestDateTime Contract"; -// ----------------------------------------------------------------------------- -console.log("RESULT: ---------- " + testDateTimeMessage + " ----------"); -// console.log("RESULT: testDateTimeBin='" + testDateTimeBin + "'"); -var newTestDateTimeBin = testDateTimeBin.replace(/__BokkyPooBahsDateTimeLibrary\.sol\:Bokk__/g, dateTimeLibAddress.substring(2, 42)); -// console.log("RESULT: newTestDateTimeBin='" + newTestDateTimeBin + "'"); -var testDateTimeContract = web3.eth.contract(testDateTimeAbi); -var testDateTimeTx = null; -var testDateTimeAddress = null; -var testDateTime = testDateTimeContract.new({from: contractOwnerAccount, data: newTestDateTimeBin, gas: 6000000, gasPrice: defaultGasPrice}, - function(e, contract) { - if (!e) { - if (!contract.address) { - testDateTimeTx = contract.transactionHash; - } else { - testDateTimeAddress = contract.address; - addAccount(testDateTimeAddress, "TestDateTime"); - console.log("DATA: var testDateTimeAddress=\"" + testDateTimeAddress + "\";"); - console.log("DATA: var testDateTimeAbi=" + JSON.stringify(testDateTimeAbi) + ";"); - console.log("DATA: var testDateTime=eth.contract(testDateTimeAbi).at(testDateTimeAddress);"); - console.log("DATA: console.log(\"testDateTime=\" + JSON.stringify(testDateTime));"); - } - } - } -); -while (txpool.status.pending > 0) { -} -printBalances(); -failIfTxStatusError(testDateTimeTx, testDateTimeMessage); -printTxData("testDateTimeAddress=" + testDateTimeAddress, testDateTimeTx); -console.log("RESULT: "); - -var failureDetected = false; -var timestamp; -var newTimestamp; -var expectedTimestamp; -var fromTimestamp; -var toTimestamp; - -if ("$MODE" == "full") { - console.log("RESULT: ---------- Test isLeapYear ----------"); - timestamp = testDateTime.timestampFromDateTime.call(2000, 5, 24, 1, 2, 3); - if (!assert(testDateTime.isLeapYear.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a leap year")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2100, 5, 24, 1, 2, 3); - if (!assert(!testDateTime.isLeapYear.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a not leap year")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2104, 5, 24, 1, 2, 3); - if (!assert(testDateTime.isLeapYear.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a leap year")) { - failureDetected = true; - } - console.log("RESULT: "); -} - -if ("$MODE" == "full") { - console.log("RESULT: ---------- Test isValidDate and isValidDateTime.call ----------"); - if (!assert(testDateTime.isValidDate.call(1969, 1, 1) == false, "testDateTime.isValidDate.call(1969, 1, 1) is false")) { - failureDetected = true; - } - if (!assert(testDateTime.isValidDate.call(1970, 1, 1) == true, "testDateTime.isValidDate.call(1970, 1, 1) is true")) { - failureDetected = true; - } - if (!assert(testDateTime.isValidDate.call(2000, 2, 29) == true, "testDateTime.isValidDate.call(2000, 2, 29) is true")) { - failureDetected = true; - } - if (!assert(testDateTime.isValidDate.call(2001, 2, 29) == false, "testDateTime.isValidDate.call(2001, 2, 29) is false")) { - failureDetected = true; - } - if (!assert(testDateTime.isValidDate.call(2001, 0, 1) == false, "testDateTime.isValidDate.call(2001, 0, 1) is false")) { - failureDetected = true; - } - if (!assert(testDateTime.isValidDate.call(2001, 1, 0) == false, "testDateTime.isValidDate.call(2001, 1, 0) is false")) { - failureDetected = true; - } - if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 0, 0, 0) == true, "testDateTime.isValidDateTime.call(2000, 2, 29, 0, 0, 0) is true")) { - failureDetected = true; - } - if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 1) == true, "testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 1) is true")) { - failureDetected = true; - } - if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 23, 1, 1) == true, "testDateTime.isValidDateTime.call(2000, 2, 29, 23, 1, 1) is true")) { - failureDetected = true; - } - if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 24, 1, 1) == false, "testDateTime.isValidDateTime.call(2000, 2, 29, 24, 1, 1) is false")) { - failureDetected = true; - } - if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 1, 59, 1) == true, "testDateTime.isValidDateTime.call(2000, 2, 29, 1, 59, 1) is true")) { - failureDetected = true; - } - if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 1, 60, 1) == false, "testDateTime.isValidDateTime.call(2000, 2, 29, 1, 60, 1) is false")) { - failureDetected = true; - } - if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 59) == true, "testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 59) is true")) { - failureDetected = true; - } - if (!assert(testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 60) == false, "testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 60) is false")) { - failureDetected = true; - } - console.log("RESULT: "); -} - -if ("$MODE" == "full") { - console.log("RESULT: ---------- Test _isLeapYear ----------"); - if (!assert(testDateTime._isLeapYear.call(2000), "2000 is a leap year")) { - failureDetected = true; - } - if (!assert(!testDateTime._isLeapYear.call(2100), "2100 is a not leap year")) { - failureDetected = true; - } - if (!assert(testDateTime._isLeapYear.call(2104), "2104 is a leap year")) { - failureDetected = true; - } - console.log("RESULT: "); -} - -if ("$MODE" == "full") { - console.log("RESULT: ---------- Test isWeekDay ----------"); - timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 24, 1, 2, 3); - if (!assert(testDateTime.isWeekDay.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a week day")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 25, 1, 2, 3); - if (!assert(testDateTime.isWeekDay.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a week day")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 26, 1, 2, 3); - if (!assert(!testDateTime.isWeekDay.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a not week day")) { - failureDetected = true; - } - console.log("RESULT: "); -} - -if ("$MODE" == "full") { - console.log("RESULT: ---------- Test isWeekEnd ----------"); - timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 24, 1, 2, 3); - if (!assert(!testDateTime.isWeekEnd.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a not a week end")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 25, 1, 2, 3); - if (!assert(!testDateTime.isWeekEnd.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a not a week end")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 26, 1, 2, 3); - if (!assert(testDateTime.isWeekEnd.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a week end")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 27, 1, 2, 3); - if (!assert(testDateTime.isWeekEnd.call(timestamp), testDateTime.timestampToDateTime.call(timestamp) + " is a week end")) { - failureDetected = true; - } - console.log("RESULT: "); -} - - -if ("$MODE" == "full") { - console.log("RESULT: ---------- Test getDaysInMonth ----------"); - timestamp = testDateTime.timestampFromDateTime.call(2000, 1, 24, 1, 2, 3); - if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 31, testDateTime.timestampToDateTime.call(timestamp) + " has 31 days")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2000, 2, 24, 1, 2, 3); - if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 29, testDateTime.timestampToDateTime.call(timestamp) + " has 29 days")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2001, 2, 24, 1, 2, 3); - if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 28, testDateTime.timestampToDateTime.call(timestamp) + " has 28 days")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2000, 3, 24, 1, 2, 3); - if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 31, testDateTime.timestampToDateTime.call(timestamp) + " has 31 days")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2000, 4, 24, 1, 2, 3); - if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 30, testDateTime.timestampToDateTime.call(timestamp) + " has 30 days")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2000, 5, 24, 1, 2, 3); - if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 31, testDateTime.timestampToDateTime.call(timestamp) + " has 31 days")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2000, 6, 24, 1, 2, 3); - if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 30, testDateTime.timestampToDateTime.call(timestamp) + " has 30 days")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2000, 7, 24, 1, 2, 3); - if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 31, testDateTime.timestampToDateTime.call(timestamp) + " has 31 days")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2000, 8, 24, 1, 2, 3); - if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 31, testDateTime.timestampToDateTime.call(timestamp) + " has 31 days")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2000, 9, 24, 1, 2, 3); - if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 30, testDateTime.timestampToDateTime.call(timestamp) + " has 30 days")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2000, 10, 24, 1, 2, 3); - if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 31, testDateTime.timestampToDateTime.call(timestamp) + " has 31 days")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2000, 11, 24, 1, 2, 3); - if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 30, testDateTime.timestampToDateTime.call(timestamp) + " has 30 days")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2000, 12, 24, 1, 2, 3); - if (!assert(testDateTime.getDaysInMonth.call(timestamp) == 31, testDateTime.timestampToDateTime.call(timestamp) + " has 31 days")) { - failureDetected = true; - } - console.log("RESULT: "); -} - - -if ("$MODE" == "full") { - console.log("RESULT: ---------- Test _getDaysInMonth ----------"); - if (!assert(testDateTime._getDaysInMonth.call(2000, 1) == 31, "2000/01 has 31 days")) { - failureDetected = true; - } - if (!assert(testDateTime._getDaysInMonth.call(2000, 2) == 29, "2000/02 has 29 days")) { - failureDetected = true; - } - if (!assert(testDateTime._getDaysInMonth.call(2001, 2) == 28, "2001/02 has 28 days")) { - failureDetected = true; - } - if (!assert(testDateTime._getDaysInMonth.call(2000, 3) == 31, "2000/03 has 31 days")) { - failureDetected = true; - } - if (!assert(testDateTime._getDaysInMonth.call(2000, 4) == 30, "2000/04 has 30 days")) { - failureDetected = true; - } - if (!assert(testDateTime._getDaysInMonth.call(2000, 5) == 31, "2000/05 has 31 days")) { - failureDetected = true; - } - if (!assert(testDateTime._getDaysInMonth.call(2000, 6) == 30, "2000/06 has 30 days")) { - failureDetected = true; - } - if (!assert(testDateTime._getDaysInMonth.call(2000, 7) == 31, "2000/07 has 31 days")) { - failureDetected = true; - } - if (!assert(testDateTime._getDaysInMonth.call(2000, 8) == 31, "2000/08 has 31 days")) { - failureDetected = true; - } - if (!assert(testDateTime._getDaysInMonth.call(2000, 9) == 30, "2000/09 has 30 days")) { - failureDetected = true; - } - if (!assert(testDateTime._getDaysInMonth.call(2000, 10) == 31, "2000/10 has 31 days")) { - failureDetected = true; - } - if (!assert(testDateTime._getDaysInMonth.call(2000, 11) == 30, "2000/11 has 30 days")) { - failureDetected = true; - } - if (!assert(testDateTime._getDaysInMonth.call(2000, 12) == 31, "2000/12 has 31 days")) { - failureDetected = true; - } - console.log("RESULT: "); -} - - -if ("$MODE" == "full") { - console.log("RESULT: ---------- Test getDayOfWeek ----------"); - timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 21, 1, 2, 3); - if (!assert(testDateTime.getDayOfWeek.call(timestamp) == 1, testDateTime.timestampToDateTime.call(timestamp) + " is 1 Monday")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 24, 1, 2, 3); - if (!assert(testDateTime.getDayOfWeek.call(timestamp) == 4, testDateTime.timestampToDateTime.call(timestamp) + " is 4 Thursday")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 26, 1, 2, 3); - if (!assert(testDateTime.getDayOfWeek.call(timestamp) == 6, testDateTime.timestampToDateTime.call(timestamp) + " is 6 Saturday")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 27, 1, 2, 3); - if (!assert(testDateTime.getDayOfWeek.call(timestamp) == 7, testDateTime.timestampToDateTime.call(timestamp) + " is 7 Sunday")) { - failureDetected = true; - } - console.log("RESULT: "); -} - - -if ("$MODE" == "full") { - console.log("RESULT: ---------- Test get* ----------"); - timestamp = testDateTime.timestampFromDateTime.call(2018, 5, 21, 1, 2, 3); - if (!assert(testDateTime.getYear.call(timestamp) == 2018, testDateTime.timestampToDateTime.call(timestamp) + " year is 2018")) { - failureDetected = true; - } - if (!assert(testDateTime.getMonth.call(timestamp) == 5, testDateTime.timestampToDateTime.call(timestamp) + " month is 5 May")) { - failureDetected = true; - } - if (!assert(testDateTime.getDay.call(timestamp) == 21, testDateTime.timestampToDateTime.call(timestamp) + " day is 21")) { - failureDetected = true; - } - if (!assert(testDateTime.getHour.call(timestamp) == 1, testDateTime.timestampToDateTime.call(timestamp) + " hour is 1")) { - failureDetected = true; - } - if (!assert(testDateTime.getMinute.call(timestamp) == 2, testDateTime.timestampToDateTime.call(timestamp) + " minute is 2")) { - failureDetected = true; - } - if (!assert(testDateTime.getSecond.call(timestamp) == 3, testDateTime.timestampToDateTime.call(timestamp) + " second is 3")) { - failureDetected = true; - } - console.log("RESULT: "); -} - -if ("$MODE" == "full") { - console.log("RESULT: ---------- Test add{Years|Months|Days|Hours|Minutes|Seconds} ----------"); - timestamp = testDateTime.timestampFromDateTime.call(2000, 2, 29, 1, 2, 3); - newTimestamp = testDateTime.addYears.call(timestamp, 3); - expectedTimestamp = testDateTime.timestampFromDateTime.call(2003, 2, 28, 1, 2, 3); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 3 years is 2003/02/28 01:02:03")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2018, 12, 31, 2, 3, 4); - newTimestamp = testDateTime.addYears.call(timestamp, 30); - expectedTimestamp = testDateTime.timestampFromDateTime.call(2048, 12, 31, 2, 3, 4); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 30 years is 2048/12/31 02:03:04")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2000, 1, 31, 1, 2, 3); - newTimestamp = testDateTime.addMonths.call(timestamp, 37); - expectedTimestamp = testDateTime.timestampFromDateTime.call(2003, 2, 28, 1, 2, 3); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 37 months is 2003/02/28 01:02:03")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2018, 12, 1, 2, 3, 4); - newTimestamp = testDateTime.addMonths.call(timestamp, 362); - expectedTimestamp = testDateTime.timestampFromDateTime.call(2049, 2, 1, 2, 3, 4); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 362 months is 2049/02/01 02:03:04")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2017, 1, 31, 1, 2, 3); - newTimestamp = testDateTime.addDays.call(timestamp, 37532); - expectedTimestamp = testDateTime.timestampFromDateTime.call(2119, 11, 5, 1, 2, 3); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 37,532 days is 2119/11/05 01:02:03")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2017, 1, 31, 1, 2, 3); - newTimestamp = testDateTime.addHours.call(timestamp, 900768); - expectedTimestamp = testDateTime.timestampFromDateTime.call(2119, 11, 5, 1, 2, 3); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 900,768 hours is 2119/11/05 01:02:03")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2017, 1, 31, 1, 2, 3); - newTimestamp = testDateTime.addMinutes.call(timestamp, 781920); - expectedTimestamp = testDateTime.timestampFromDateTime.call(2018, 7, 28, 1, 2, 3); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 781,920 minutes is 2018/07/28 01:02:03")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2017, 1, 31, 1, 2, 3); - newTimestamp = testDateTime.addSeconds.call(timestamp, "461548800"); - expectedTimestamp = testDateTime.timestampFromDateTime.call(2031, 9, 17, 1, 2, 3); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " + 461,548,800 seconds is 2031/09/17 01:02:03")) { - failureDetected = true; - } - console.log("RESULT: "); -} - -if ("$MODE" == "full") { - console.log("RESULT: ---------- Test sub{Years|Months|Days|Hours|Minutes|Seconds} ----------"); - timestamp = testDateTime.timestampFromDateTime.call(2000, 2, 29, 1, 2, 3); - newTimestamp = testDateTime.subYears.call(timestamp, 3); - expectedTimestamp = testDateTime.timestampFromDateTime.call(1997, 2, 28, 1, 2, 3); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " - 3 years is 1997/02/28 01:02:03")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2000, 2, 29, 1, 2, 3); - newTimestamp = testDateTime.subMonths.call(timestamp, 37); - expectedTimestamp = testDateTime.timestampFromDateTime.call(1997, 1, 29, 1, 2, 3); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " - 37 months is 1997/01/29 01:02:03")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2013, 1, 1, 1, 2, 3); - newTimestamp = testDateTime.subDays.call(timestamp, 3756); - expectedTimestamp = testDateTime.timestampFromDateTime.call(2002, 9, 20, 1, 2, 3); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " - 3,756 days is 2002/09/20 01:02:03")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2013, 1, 1, 1, 2, 3); - newTimestamp = testDateTime.subHours.call(timestamp, 3756 * 24); - expectedTimestamp = testDateTime.timestampFromDateTime.call(2002, 9, 20, 1, 2, 3); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " - 3,756 * 24 hours is 2002/09/20 01:02:03")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2015, 7, 15, 1, 2, 3); - newTimestamp = testDateTime.subHours.call(timestamp, "223776"); - expectedTimestamp = testDateTime.timestampFromDateTime.call(1990, 1, 3, 1, 2, 3); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " - 223,776 hours is 1990/01/03 01:02:03")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2018, 3, 1, 2, 3, 4); - newTimestamp = testDateTime.subMinutes.call(timestamp, "21600000"); - expectedTimestamp = testDateTime.timestampFromDateTime.call(1977, 2, 4, 2, 3, 4); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " - 21,600,000 minutes is 1977/02/04 02:03:04")) { - failureDetected = true; - } - timestamp = testDateTime.timestampFromDateTime.call(2020, 3, 19, 3, 4, 5); - newTimestamp = testDateTime.subSeconds.call(timestamp, "788227200"); - expectedTimestamp = testDateTime.timestampFromDateTime.call(1995, 3, 28, 3, 4, 5); - if (!assertIntEquals(newTimestamp, expectedTimestamp, testDateTime.timestampToDateTime.call(timestamp) + " - 788,227,200 seconds is 1995/03/28 03:04:05")) { - failureDetected = true; - } - console.log("RESULT: "); -} - -if ("$MODE" == "full") { - console.log("RESULT: ---------- Test diff{Years|Months|Days|Hours|Minutes|Seconds} ----------"); - fromTimestamp = testDateTime.timestampFromDateTime.call(2017, 10, 21, 1, 2, 3); - console.log("RESULT: fromTimestamp=" + fromTimestamp + " " + testDateTime.timestampToDateTime.call(fromTimestamp)); - toTimestamp = testDateTime.timestampFromDateTime.call(2019, 7, 18, 4, 5, 6); - console.log("RESULT: toTimestamp=" + toTimestamp + " " + testDateTime.timestampToDateTime.call(toTimestamp)); - - if (!assert(testDateTime.diffYears.call(fromTimestamp, toTimestamp) == 2, testDateTime.timestampToDateTime.call(fromTimestamp) + " to " + testDateTime.timestampToDateTime.call(toTimestamp) + " has 2 years diff")) { - failureDetected = true; - } - if (!assert(testDateTime.diffMonths.call(fromTimestamp, toTimestamp) == 21, testDateTime.timestampToDateTime.call(fromTimestamp) + " to " + testDateTime.timestampToDateTime.call(toTimestamp) + " has 21 months diff")) { - failureDetected = true; - } - if (!assert(testDateTime.diffDays.call(fromTimestamp, toTimestamp) == 635, testDateTime.timestampToDateTime.call(fromTimestamp) + " to " + testDateTime.timestampToDateTime.call(toTimestamp) + " has 635 days diff")) { - failureDetected = true; - } - if (!assert(testDateTime.diffHours.call(fromTimestamp, toTimestamp) == 15243, testDateTime.timestampToDateTime.call(fromTimestamp) + " to " + testDateTime.timestampToDateTime.call(toTimestamp) + " has 15,243 hours diff")) { - failureDetected = true; - } - if (!assert(testDateTime.diffMinutes.call(fromTimestamp, toTimestamp) == 914583, testDateTime.timestampToDateTime.call(fromTimestamp) + " to " + testDateTime.timestampToDateTime.call(toTimestamp) + " has 914,583 minutes diff")) { - failureDetected = true; - } - if (!assert(testDateTime.diffSeconds.call(fromTimestamp, toTimestamp) == 54874983, testDateTime.timestampToDateTime.call(fromTimestamp) + " to " + testDateTime.timestampToDateTime.call(toTimestamp) + " has 54,874,983 seconds diff")) { - failureDetected = true; - } - console.log("RESULT: "); -} - -if ("$MODE" == "full") { - console.log("RESULT: ---------- Test timestampToDateTime.call(...) and timestampFromDateTime.call(...) against JavaScript Date ----------"); - var now = new Date()/1000; - - var fromDate = 0; - // Year 2345 - var toDate = new Date()/1000 + 328 * 365 * 24 * 60 * 60; - // 9 weeks - // var step = 9 * 7 * 24 * 60 * 60; - // 1 year - var step = 365 * 24 * 60 * 60; - - var j = 0; - for (var i = fromDate; i <= toDate; i = parseInt(i) + step) { - j = parseInt(j * 999991) + 48611; - if (j > 365 * 24 * 60 * 60) { - j = j - 365 * 24 * 60 * 60; - } - i = parseInt(i) + j % 999991; - var fromTimestamp = testDateTime.timestampToDateTime.call(i); - var toTimestamp = testDateTime.timestampFromDateTime.call(fromTimestamp[0], fromTimestamp[1], fromTimestamp[2], fromTimestamp[3], fromTimestamp[4], fromTimestamp[5]); - var jsDate = new Date(i * 1000); - console.log("RESULT: timestampToDateTime.call(" + i + ")=" + JSON.stringify(fromTimestamp)); - console.log("RESULT: timestampFromDateTime.call(" + JSON.stringify(fromTimestamp) + ")=" + toTimestamp); - console.log("RESULT: jsDate(" + i + ")=" + jsDate.getUTCFullYear() + "/" + (parseInt(jsDate.getUTCMonth()) + 1) + "/" + jsDate.getUTCDate() + " " + - jsDate.getUTCHours() + ":" + jsDate.getUTCMinutes() + ":" + jsDate.getUTCSeconds()); - - if (jsDate.getUTCFullYear() == fromTimestamp[0] && parseInt(jsDate.getUTCMonth() + 1) == fromTimestamp[1] && jsDate.getUTCDate() == fromTimestamp[2] && - jsDate.getUTCHours() == fromTimestamp[3] && jsDate.getUTCMinutes() == fromTimestamp[4] && jsDate.getUTCSeconds() == fromTimestamp[5]) { - console.log("RESULT: PASS jsDate matches"); - } else { - console.log("RESULT: FAIL jsDate does not match"); - failureDetected = true; - } - if (i == toTimestamp) { - console.log("RESULT: PASS timestampToDateTime.call(" + i + ") => timestampFromDateTime.call(...) matches"); - } else { - console.log("RESULT: FAIL timestampToDateTime.call(" + i + ") => timestampFromDateTime.call(...) does not match"); - failureDetected = true; - } - console.log("RESULT: "); - } -} - -if (!failureDetected) { - console.log("RESULT: ---------- PASS - no failures detected ----------"); -} else { - console.log("RESULT: ---------- FAIL - some failures detected ----------"); -} - - -EOF -grep "DATA: " $TEST1OUTPUT | sed "s/DATA: //" > $DEPLOYMENTDATA -cat $DEPLOYMENTDATA -grep "RESULT: " $TEST1OUTPUT | sed "s/RESULT: //" > $TEST1RESULTS -cat $TEST1RESULTS diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/02_attachGeth.sh b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/02_attachGeth.sh deleted file mode 100755 index 52f2307..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/02_attachGeth.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - - -echo "Execute the following command to load the latest deployed contracts"; -echo "" -echo "loadScript(\"deploymentData.js\");" -echo "" - -geth attach ipc:./testchain/geth.ipc diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.js b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.js deleted file mode 100644 index 0cba4f1..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.js +++ /dev/null @@ -1,11 +0,0 @@ -var dateTimeLibOutput={ - "contracts": - { - "BokkyPooBahsDateTimeLibrary.sol:BokkyPooBahsDateTimeLibrary": - { - "abi": "[]", - "bin": "60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122075d49f0ac9a443fac8bb202f0adb9e02ed12cbbf6d4d258fcb57548a1e88719064736f6c63430006000033" - } - }, - "version": "0.6.0+commit.26b70077.Darwin.appleclang" -}; diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.sol b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.sol deleted file mode 100644 index fb16487..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/BokkyPooBahsDateTimeLibrary.sol +++ /dev/null @@ -1,300 +0,0 @@ -pragma solidity ^0.6.0; - -// ---------------------------------------------------------------------------- -// BokkyPooBah's DateTime Library v1.01 -// -// A gas-efficient Solidity date and time library -// -// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary -// -// Tested date range 1970/01/01 to 2345/12/31 -// -// Conventions: -// Unit | Range | Notes -// :-------- |:-------------:|:----- -// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC -// year | 1970 ... 2345 | -// month | 1 ... 12 | -// day | 1 ... 31 | -// hour | 0 ... 23 | -// minute | 0 ... 59 | -// second | 0 ... 59 | -// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday -// -// -// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. -// ---------------------------------------------------------------------------- - -library BokkyPooBahsDateTimeLibrary { - - uint constant SECONDS_PER_DAY = 24 * 60 * 60; - uint constant SECONDS_PER_HOUR = 60 * 60; - uint constant SECONDS_PER_MINUTE = 60; - int constant OFFSET19700101 = 2440588; - - uint constant DOW_MON = 1; - uint constant DOW_TUE = 2; - uint constant DOW_WED = 3; - uint constant DOW_THU = 4; - uint constant DOW_FRI = 5; - uint constant DOW_SAT = 6; - uint constant DOW_SUN = 7; - - // ------------------------------------------------------------------------ - // Calculate the number of days from 1970/01/01 to year/month/day using - // the date conversion algorithm from - // http://aa.usno.navy.mil/faq/docs/JD_Formula.php - // and subtracting the offset 2440588 so that 1970/01/01 is day 0 - // - // days = day - // - 32075 - // + 1461 * (year + 4800 + (month - 14) / 12) / 4 - // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 - // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 - // - offset - // ------------------------------------------------------------------------ - function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) { - require(year >= 1970); - int _year = int(year); - int _month = int(month); - int _day = int(day); - - int __days = _day - - 32075 - + 1461 * (_year + 4800 + (_month - 14) / 12) / 4 - + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12 - - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4 - - OFFSET19700101; - - _days = uint(__days); - } - - // ------------------------------------------------------------------------ - // Calculate year/month/day from the number of days since 1970/01/01 using - // the date conversion algorithm from - // http://aa.usno.navy.mil/faq/docs/JD_Formula.php - // and adding the offset 2440588 so that 1970/01/01 is day 0 - // - // int L = days + 68569 + offset - // int N = 4 * L / 146097 - // L = L - (146097 * N + 3) / 4 - // year = 4000 * (L + 1) / 1461001 - // L = L - 1461 * year / 4 + 31 - // month = 80 * L / 2447 - // dd = L - 2447 * month / 80 - // L = month / 11 - // month = month + 2 - 12 * L - // year = 100 * (N - 49) + year + L - // ------------------------------------------------------------------------ - function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) { - int __days = int(_days); - - int L = __days + 68569 + OFFSET19700101; - int N = 4 * L / 146097; - L = L - (146097 * N + 3) / 4; - int _year = 4000 * (L + 1) / 1461001; - L = L - 1461 * _year / 4 + 31; - int _month = 80 * L / 2447; - int _day = L - 2447 * _month / 80; - L = _month / 11; - _month = _month + 2 - 12 * L; - _year = 100 * (N - 49) + _year + L; - - year = uint(_year); - month = uint(_month); - day = uint(_day); - } - - function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) { - timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; - } - function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) { - timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second; - } - function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) { - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function timestampToDateTime(uint timestamp) internal pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { - (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); - uint secs = timestamp % SECONDS_PER_DAY; - hour = secs / SECONDS_PER_HOUR; - secs = secs % SECONDS_PER_HOUR; - minute = secs / SECONDS_PER_MINUTE; - second = secs % SECONDS_PER_MINUTE; - } - - function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) { - if (year >= 1970 && month > 0 && month <= 12) { - uint daysInMonth = _getDaysInMonth(year, month); - if (day > 0 && day <= daysInMonth) { - valid = true; - } - } - } - function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) { - if (isValidDate(year, month, day)) { - if (hour < 24 && minute < 60 && second < 60) { - valid = true; - } - } - } - function isLeapYear(uint timestamp) internal pure returns (bool leapYear) { - (uint year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); - leapYear = _isLeapYear(year); - } - function _isLeapYear(uint year) internal pure returns (bool leapYear) { - leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); - } - function isWeekDay(uint timestamp) internal pure returns (bool weekDay) { - weekDay = getDayOfWeek(timestamp) <= DOW_FRI; - } - function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) { - weekEnd = getDayOfWeek(timestamp) >= DOW_SAT; - } - function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) { - (uint year, uint month,) = _daysToDate(timestamp / SECONDS_PER_DAY); - daysInMonth = _getDaysInMonth(year, month); - } - function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) { - if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { - daysInMonth = 31; - } else if (month != 2) { - daysInMonth = 30; - } else { - daysInMonth = _isLeapYear(year) ? 29 : 28; - } - } - // 1 = Monday, 7 = Sunday - function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) { - uint _days = timestamp / SECONDS_PER_DAY; - dayOfWeek = (_days + 3) % 7 + 1; - } - - function getYear(uint timestamp) internal pure returns (uint year) { - (year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function getMonth(uint timestamp) internal pure returns (uint month) { - (,month,) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function getDay(uint timestamp) internal pure returns (uint day) { - (,,day) = _daysToDate(timestamp / SECONDS_PER_DAY); - } - function getHour(uint timestamp) internal pure returns (uint hour) { - uint secs = timestamp % SECONDS_PER_DAY; - hour = secs / SECONDS_PER_HOUR; - } - function getMinute(uint timestamp) internal pure returns (uint minute) { - uint secs = timestamp % SECONDS_PER_HOUR; - minute = secs / SECONDS_PER_MINUTE; - } - function getSecond(uint timestamp) internal pure returns (uint second) { - second = timestamp % SECONDS_PER_MINUTE; - } - - function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { - (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); - year += _years; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp >= timestamp); - } - function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { - (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); - month += _months; - year += (month - 1) / 12; - month = (month - 1) % 12 + 1; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp >= timestamp); - } - function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _days * SECONDS_PER_DAY; - require(newTimestamp >= timestamp); - } - function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _hours * SECONDS_PER_HOUR; - require(newTimestamp >= timestamp); - } - function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE; - require(newTimestamp >= timestamp); - } - function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp + _seconds; - require(newTimestamp >= timestamp); - } - - function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { - (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); - year -= _years; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp <= timestamp); - } - function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { - (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); - uint yearMonth = year * 12 + (month - 1) - _months; - year = yearMonth / 12; - month = yearMonth % 12 + 1; - uint daysInMonth = _getDaysInMonth(year, month); - if (day > daysInMonth) { - day = daysInMonth; - } - newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; - require(newTimestamp <= timestamp); - } - function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _days * SECONDS_PER_DAY; - require(newTimestamp <= timestamp); - } - function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _hours * SECONDS_PER_HOUR; - require(newTimestamp <= timestamp); - } - function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE; - require(newTimestamp <= timestamp); - } - function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { - newTimestamp = timestamp - _seconds; - require(newTimestamp <= timestamp); - } - - function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) { - require(fromTimestamp <= toTimestamp); - (uint fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); - (uint toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); - _years = toYear - fromYear; - } - function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) { - require(fromTimestamp <= toTimestamp); - (uint fromYear, uint fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); - (uint toYear, uint toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); - _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth; - } - function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) { - require(fromTimestamp <= toTimestamp); - _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY; - } - function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) { - require(fromTimestamp <= toTimestamp); - _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR; - } - function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) { - require(fromTimestamp <= toTimestamp); - _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE; - } - function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) { - require(fromTimestamp <= toTimestamp); - _seconds = toTimestamp - fromTimestamp; - } -} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/README.md b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/README.md deleted file mode 100644 index e9f9bc8..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# Contract - Testing - -
      - -
      - -# Table of contents - -* [Requirements](#requirements) -* [Executing The Tests](#executing-the-tests) -* [Notes](#notes) - -
      - -
      - -# Requirements - -* The tests works on OS/X. Should work in Linux. May work in Windows with Cygwin -* Geth/v1.9.9-stable-01744997/darwin-amd64/go1.13.5 running with the Byzantium fork switched on -* Solc 0.6.0+commit.26b70077.Darwin.appleclang - -
      - -
      - -# Executing The Tests - -* Run `geth` in dev mode - - ./00_runGeth.sh - -* Run the test in [01_test1.sh](01_test1.sh) - - ./01_test1.sh - -* See [test1results.txt](test1results.txt) for the results and [test1output.txt](test1output.txt) for the full output. - -
      - -
      - -# Notes - -* The tests were conducted using bash shell scripts running Geth/v1.9.9-stable-01744997/darwin-amd64/go1.13.5 JavaScript commands -* The smart contracts were compiled using Solidity 0.6.0+commit.26b70077.Darwin.appleclang -* The test script can be found in [01_test1.sh](01_test1.sh) -* The test results can be found in [test1results.txt](test1results.txt) with details in [test1output.txt](test1output.txt) -* The test can be run on OS/X, should run on Linux and may run on Windows with Cygwin -* The [genesis.json](genesis.json) allocates ethers to the test accounts, and specifies a high block gas limit to accommodate many transactions in the same block -* The [00_runGeth.sh](00_runGeth.sh) scripts starts `geth` with the parameter `--targetgaslimit 994712388` to keep the high block gas limit -* The reasons for using the test environment as listed above, instead of truffles/testrpc are: - * The test are conducted using the actual blockchain client software as is running on Mainnet and not just a mock environment like testrpc - * It is easy to change parameters like dates, addresses or blocknumbers using the Unix search/replace tools - * There have been issues in the part with version incompatibility between testrpc and solidity, i.e., version mismatches - * The intermediate and key results are all saved to later viewing diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.js b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.js deleted file mode 100644 index 5d7ac27..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.js +++ /dev/null @@ -1,16 +0,0 @@ -var testDateTimeOutput={ - "contracts": - { - "BokkyPooBahsDateTimeLibrary.sol:BokkyPooBahsDateTimeLibrary": - { - "abi": "[]", - "bin": "60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122075d49f0ac9a443fac8bb202f0adb9e02ed12cbbf6d4d258fcb57548a1e88719064736f6c63430006000033" - }, - "TestDateTime.sol:TestDateTime": - { - "abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"}],\"name\":\"_getDaysInMonth\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"daysInMonth\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"}],\"name\":\"_isLeapYear\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"leapYear\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_days\",\"type\":\"uint256\"}],\"name\":\"addDays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_hours\",\"type\":\"uint256\"}],\"name\":\"addHours\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minutes\",\"type\":\"uint256\"}],\"name\":\"addMinutes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_months\",\"type\":\"uint256\"}],\"name\":\"addMonths\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_seconds\",\"type\":\"uint256\"}],\"name\":\"addSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_years\",\"type\":\"uint256\"}],\"name\":\"addYears\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fromTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTimestamp\",\"type\":\"uint256\"}],\"name\":\"diffDays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"_days\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fromTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTimestamp\",\"type\":\"uint256\"}],\"name\":\"diffHours\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"_hours\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fromTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTimestamp\",\"type\":\"uint256\"}],\"name\":\"diffMinutes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"_minutes\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fromTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTimestamp\",\"type\":\"uint256\"}],\"name\":\"diffMonths\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"_months\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fromTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTimestamp\",\"type\":\"uint256\"}],\"name\":\"diffSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"_seconds\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fromTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTimestamp\",\"type\":\"uint256\"}],\"name\":\"diffYears\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"_years\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getDay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"day\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getDayOfWeek\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"dayOfWeek\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getDaysInMonth\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"daysInMonth\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getHour\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"hour\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getMinute\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"minute\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getMonth\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getSecond\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"second\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getYear\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"isLeapYear\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"leapYear\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"day\",\"type\":\"uint256\"}],\"name\":\"isValidDate\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"valid\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"day\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hour\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minute\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"second\",\"type\":\"uint256\"}],\"name\":\"isValidDateTime\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"valid\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"isWeekDay\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"weekDay\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"isWeekEnd\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"weekEnd\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextYear\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_days\",\"type\":\"uint256\"}],\"name\":\"subDays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_hours\",\"type\":\"uint256\"}],\"name\":\"subHours\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minutes\",\"type\":\"uint256\"}],\"name\":\"subMinutes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_months\",\"type\":\"uint256\"}],\"name\":\"subMonths\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_seconds\",\"type\":\"uint256\"}],\"name\":\"subSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_years\",\"type\":\"uint256\"}],\"name\":\"subYears\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newTimestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"test\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"day\",\"type\":\"uint256\"}],\"name\":\"timestampFromDate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"day\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hour\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minute\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"second\",\"type\":\"uint256\"}],\"name\":\"timestampFromDateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"timestampToDate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"day\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"timestampToDateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"month\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"day\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hour\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minute\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"second\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", - "bin": "608060405234801561001057600080fd5b506110ed806100206000396000f3fe608060405234801561001057600080fd5b506004361061023c5760003560e01c80637217523c1161013b578063b8d16dbc116100b8578063ea1c16901161007c578063ea1c169014610704578063f615ed5414610754578063f8a8fd6d14610777578063fa93f88314610781578063ff2258cb1461079e5761023c565b8063b8d16dbc14610649578063c7b6fd6a14610666578063c9d3462214610689578063d6582d0d146106ac578063de5101af146106c95761023c565b806392d66313116100ff57806392d66313146105ac5780639e524caa146105c9578063a324ad24146105ec578063ad203bd414610609578063b05eb08d1461062c5761023c565b80637217523c146105035780637be341091461052657806389a3a00d146105495780638aa001fc1461056c5780638d4a2d39146105895761023c565b80633e239e1a116101c9578063444fda821161018d578063444fda82146104425780634b321502146104655780635e05bd6d1461048857806362fb9697146104c357806365c72840146104e65761023c565b80633e239e1a1461039f5780633f9e0eb7146103bc5780634355644d146103df5780634371c46514610402578063442b8c791461041f5761023c565b806314b2d6dc1161021057806314b2d6dc146102be5780631f4f77b2146102fb57806322f8a2b8146103245780632af123b8146103415780633293d007146103645761023c565b80625015531461024157806302e98e0d1461027657806310848ddf14610299578063146bea7b146102b6575b600080fd5b6102646004803603604081101561025757600080fd5b50803590602001356107c1565b60408051918252519081900360200190f35b6102646004803603604081101561028c57600080fd5b50803590602001356107d4565b610264600480360360208110156102af57600080fd5b50356107e0565b6102646107f1565b6102e7600480360360608110156102d457600080fd5b50803590602081013590604001356107f7565b604080519115158252519081900360200190f35b6102646004803603606081101561031157600080fd5b508035906020810135906040013561080c565b6102646004803603602081101561033a57600080fd5b5035610819565b6102646004803603604081101561035757600080fd5b5080359060200135610824565b6102e7600480360360c081101561037a57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135610830565b610264600480360360208110156103b557600080fd5b503561084b565b610264600480360360408110156103d257600080fd5b5080359060200135610856565b610264600480360360408110156103f557600080fd5b5080359060200135610862565b6102e76004803603602081101561041857600080fd5b503561086e565b6102646004803603604081101561043557600080fd5b5080359060200135610879565b6102646004803603604081101561045857600080fd5b5080359060200135610885565b6102646004803603604081101561047b57600080fd5b5080359060200135610891565b610264600480360360c081101561049e57600080fd5b5080359060208101359060408101359060608101359060808101359060a0013561089d565b610264600480360360408110156104d957600080fd5b50803590602001356108b7565b610264600480360360208110156104fc57600080fd5b50356108c3565b6102646004803603604081101561051957600080fd5b50803590602001356108ce565b6102646004803603604081101561053c57600080fd5b50803590602001356108da565b6102646004803603604081101561055f57600080fd5b50803590602001356108e6565b6102646004803603602081101561058257600080fd5b50356108f2565b6102646004803603604081101561059f57600080fd5b50803590602001356108fd565b610264600480360360208110156105c257600080fd5b5035610909565b610264600480360360408110156105df57600080fd5b5080359060200135610914565b6102646004803603602081101561060257600080fd5b5035610920565b6102646004803603604081101561061f57600080fd5b508035906020013561092b565b6102e76004803603602081101561064257600080fd5b5035610937565b6102e76004803603602081101561065f57600080fd5b5035610942565b6102646004803603604081101561067c57600080fd5b508035906020013561094d565b6102646004803603604081101561069f57600080fd5b5080359060200135610959565b6102e7600480360360208110156106c257600080fd5b5035610965565b6106e6600480360360208110156106df57600080fd5b5035610970565b60408051938452602084019290925282820152519081900360600190f35b6107216004803603602081101561071a57600080fd5b503561098b565b604080519687526020870195909552858501939093526060850191909152608084015260a0830152519081900360c00190f35b6102646004803603604081101561076a57600080fd5b50803590602001356109b1565b61077f6109bd565b005b6102646004803603602081101561079757600080fd5b50356109d5565b610264600480360360408110156107b457600080fd5b50803590602001356109e0565b60006107cd83836109ec565b9392505050565b60006107cd8383610a00565b60006107eb82610a1d565b92915050565b60005481565b6000610804848484610a3f565b949350505050565b6000610804848484610a95565b60006107eb82610aaf565b60006107cd8383610ac2565b6000610840878787878787610adc565b979650505050505050565b60006107eb82610b1c565b60006107cd8383610b2a565b60006107cd8383610bb0565b60006107eb82610c2a565b60006107cd8383610c3f565b60006107cd8383610c66565b60006107cd8383610cc2565b6000610840878787878787610cd6565b9695505050505050565b60006107cd8383610d00565b60006107eb82610d14565b60006107cd8383610d23565b60006107cd8383610d38565b60006107cd8383610d8a565b60006107eb82610d9d565b60006107cd8383610da4565b60006107eb82610db4565b60006107cd8383610dcc565b60006107eb82610ddf565b60006107cd8383610dee565b60006107eb82610e6e565b60006107eb82610e93565b60006107cd8383610eb0565b60006107cd8383610ec5565b60006107eb82610ee0565b600080600061097e84610ef5565b9196909550909350915050565b60008060008060008061099d87610f06565b949c939b5091995097509550909350915050565b60006107cd8383610f45565b426109cf81600163ffffffff610c3f16565b60005550565b60006107eb82610f55565b60006107cd8383610f64565b610e1081028203828111156107eb57600080fd5b600081831115610a0f57600080fd5b603c8383035b049392505050565b60008080610a3062015180855b04610fa5565b50915091506108048282610b2a565b60006107b28410158015610a535750600083115b8015610a605750600c8311155b156107cd576000610a718585610b2a565b9050600083118015610a835750808311155b15610a8d57600191505b509392505050565b600062015180610aa685858561103b565b02949350505050565b6007620151809091046003010660010190565b600081831115610ad157600080fd5b610e10838303610a15565b6000610ae9878787610a3f565b156108ad57601884108015610afe5750603c83105b8015610b0a5750603c82105b156108ad575060019695505050505050565b610e10620151809091060490565b60008160011480610b3b5750816003145b80610b465750816005145b80610b515750816007145b80610b5c5750816008145b80610b67575081600a145b80610b72575081600c145b15610b7f5750601f6107eb565b81600214610b8f5750601e6107eb565b610b9883610e6e565b610ba357601c610ba6565b601d5b60ff169392505050565b6000808080610bc26201518087610a2a565b600c918801600019810183810494909401965094509250900660010191506000610bec8484610b2a565b905080821115610bfa578091505b62015180870662015180610c0f86868661103b565b0201945086851015610c2057600080fd5b5050505092915050565b60006006610c3783610aaf565b101592915050565b6000808080610c516201518087610a2a565b9187019450925090506000610bec8484610b2a565b6000808080610c786201518087610a2a565b918790039450925090506000610c8e8484610b2a565b905080821115610c9c578091505b62015180870662015180610cb186868661103b565b0201945086851115610c2057600080fd5b610e1081028201828110156107eb57600080fd5b600081603c8402610e10860262015180610cf18b8b8b61103b565b02010101979650505050505050565b600081831115610d0f57600080fd5b500390565b60006108046201518083610a2a565b6201518081028201828110156107eb57600080fd5b600081831115610d4757600080fd5b600080610d576201518086610a2a565b5091509150600080610d6e620151808781610a2a57fe5b50600c9586029590910201939093039190910395945050505050565b603c81028201828110156107eb57600080fd5b603c900690565b818101828110156107eb57600080fd5b6000610dc36201518083610a2a565b50909392505050565b603c81028203828111156107eb57600080fd5b6000610a8d6201518083610a2a565b6000808080610e006201518087610a2a565b91945092509050600c8084028301869003600019019081049350600c810660010192506000610e2f8585610b2a565b905080831115610e3d578092505b62015180880662015180610e5287878761103b565b0201955087861115610e6357600080fd5b505050505092915050565b600060048206158015610e8357506064820615155b806107eb57505061019090061590565b600080610ea36201518084610a2a565b505090506107cd81610e6e565b6201518081028203828111156107eb57600080fd5b600081831115610ed457600080fd5b62015180838303610a15565b60006005610eed83610aaf565b111592915050565b6000808061097e6201518085610a2a565b60008080808080610f1a6201518088610a2a565b91999098919750610e10620151809092068281049750603c9290068281049650919091069350915050565b808203828111156107eb57600080fd5b6000610e108206603c81610a15565b600081831115610f7357600080fd5b6000610f826201518085610a2a565b505090506000610f97620151808581610a2a57fe5b505091909103949350505050565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f8460500281610ffc57fe5b0590506000605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b60006107b284101561104c57600080fd5b838383600062253d8c600460036064611324600c600d19890105890101050205600c80600d19870105600c02600287030361016f028161108857fe5b0560046105b5600c600d1989010589016112c0010205617d4b860301010303905080945050505050939250505056fea2646970667358221220144bfa7ff851a685f881e93c3b88c3dce21cc7d3c01423e087bdfba5b17d290964736f6c63430006000033" - } - }, - "version": "0.6.0+commit.26b70077.Darwin.appleclang" -}; diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.sol b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.sol deleted file mode 100644 index 1c3d368..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/TestDateTime.sol +++ /dev/null @@ -1,141 +0,0 @@ -pragma solidity ^0.6.0; - -import "BokkyPooBahsDateTimeLibrary.sol"; - -// ---------------------------------------------------------------------------- -// Testing BokkyPooBah's DateTime Library -// -// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary -// -// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. -// ---------------------------------------------------------------------------- - -contract TestDateTime { - using BokkyPooBahsDateTimeLibrary for uint; - - uint public nextYear; - - function test() public { - uint today = now; - nextYear = today.addYears(1); - } - - function timestampFromDate(uint year, uint month, uint day) public pure returns (uint timestamp) { - return BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day); - } - function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (uint timestamp) { - return BokkyPooBahsDateTimeLibrary.timestampFromDateTime(year, month, day, hour, minute, second); - } - function timestampToDate(uint timestamp) public pure returns (uint year, uint month, uint day) { - (year, month, day) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); - } - function timestampToDateTime(uint timestamp) public pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { - (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(timestamp); - } - - function isLeapYear(uint timestamp) public pure returns (bool leapYear) { - leapYear = BokkyPooBahsDateTimeLibrary.isLeapYear(timestamp); - } - function _isLeapYear(uint year) public pure returns (bool leapYear) { - leapYear = BokkyPooBahsDateTimeLibrary._isLeapYear(year); - } - function isWeekDay(uint timestamp) public pure returns (bool weekDay) { - weekDay = BokkyPooBahsDateTimeLibrary.isWeekDay(timestamp); - } - function isWeekEnd(uint timestamp) public pure returns (bool weekEnd) { - weekEnd = BokkyPooBahsDateTimeLibrary.isWeekEnd(timestamp); - } - - function getDaysInMonth(uint timestamp) public pure returns (uint daysInMonth) { - daysInMonth = BokkyPooBahsDateTimeLibrary.getDaysInMonth(timestamp); - } - function _getDaysInMonth(uint year, uint month) public pure returns (uint daysInMonth) { - daysInMonth = BokkyPooBahsDateTimeLibrary._getDaysInMonth(year, month); - } - function getDayOfWeek(uint timestamp) public pure returns (uint dayOfWeek) { - dayOfWeek = BokkyPooBahsDateTimeLibrary.getDayOfWeek(timestamp); - } - - function isValidDate(uint year, uint month, uint day) public pure returns (bool valid) { - valid = BokkyPooBahsDateTimeLibrary.isValidDate(year, month, day); - } - function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (bool valid) { - valid = BokkyPooBahsDateTimeLibrary.isValidDateTime(year, month, day, hour, minute, second); - } - - function getYear(uint timestamp) public pure returns (uint year) { - year = BokkyPooBahsDateTimeLibrary.getYear(timestamp); - } - function getMonth(uint timestamp) public pure returns (uint month) { - month = BokkyPooBahsDateTimeLibrary.getMonth(timestamp); - } - function getDay(uint timestamp) public pure returns (uint day) { - day = BokkyPooBahsDateTimeLibrary.getDay(timestamp); - } - function getHour(uint timestamp) public pure returns (uint hour) { - hour = BokkyPooBahsDateTimeLibrary.getHour(timestamp); - } - function getMinute(uint timestamp) public pure returns (uint minute) { - minute = BokkyPooBahsDateTimeLibrary.getMinute(timestamp); - } - function getSecond(uint timestamp) public pure returns (uint second) { - second = BokkyPooBahsDateTimeLibrary.getSecond(timestamp); - } - - function addYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addYears(timestamp, _years); - } - function addMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addMonths(timestamp, _months); - } - function addDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addDays(timestamp, _days); - } - function addHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addHours(timestamp, _hours); - } - function addMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addMinutes(timestamp, _minutes); - } - function addSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.addSeconds(timestamp, _seconds); - } - - function subYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subYears(timestamp, _years); - } - function subMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subMonths(timestamp, _months); - } - function subDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subDays(timestamp, _days); - } - function subHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subHours(timestamp, _hours); - } - function subMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subMinutes(timestamp, _minutes); - } - function subSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { - newTimestamp = BokkyPooBahsDateTimeLibrary.subSeconds(timestamp, _seconds); - } - - function diffYears(uint fromTimestamp, uint toTimestamp) public pure returns (uint _years) { - _years = BokkyPooBahsDateTimeLibrary.diffYears(fromTimestamp, toTimestamp); - } - function diffMonths(uint fromTimestamp, uint toTimestamp) public pure returns (uint _months) { - _months = BokkyPooBahsDateTimeLibrary.diffMonths(fromTimestamp, toTimestamp); - } - function diffDays(uint fromTimestamp, uint toTimestamp) public pure returns (uint _days) { - _days = BokkyPooBahsDateTimeLibrary.diffDays(fromTimestamp, toTimestamp); - } - function diffHours(uint fromTimestamp, uint toTimestamp) public pure returns (uint _hours) { - _hours = BokkyPooBahsDateTimeLibrary.diffHours(fromTimestamp, toTimestamp); - } - function diffMinutes(uint fromTimestamp, uint toTimestamp) public pure returns (uint _minutes) { - _minutes = BokkyPooBahsDateTimeLibrary.diffMinutes(fromTimestamp, toTimestamp); - } - function diffSeconds(uint fromTimestamp, uint toTimestamp) public pure returns (uint _seconds) { - _seconds = BokkyPooBahsDateTimeLibrary.diffSeconds(fromTimestamp, toTimestamp); - } -} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/deploymentData.js b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/deploymentData.js deleted file mode 100644 index 48ea50b..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/deploymentData.js +++ /dev/null @@ -1,11 +0,0 @@ -dateTimeLibAbi=[] -dateTimeLibBin="0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122075d49f0ac9a443fac8bb202f0adb9e02ed12cbbf6d4d258fcb57548a1e88719064736f6c63430006000033" -testDateTimeAbi=[{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"_getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"name":"_isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"addDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"addHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"addMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"addMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"addSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"addYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffDays","outputs":[{"internalType":"uint256","name":"_days","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffHours","outputs":[{"internalType":"uint256","name":"_hours","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMinutes","outputs":[{"internalType":"uint256","name":"_minutes","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMonths","outputs":[{"internalType":"uint256","name":"_months","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffSeconds","outputs":[{"internalType":"uint256","name":"_seconds","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffYears","outputs":[{"internalType":"uint256","name":"_years","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDay","outputs":[{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDayOfWeek","outputs":[{"internalType":"uint256","name":"dayOfWeek","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getHour","outputs":[{"internalType":"uint256","name":"hour","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMinute","outputs":[{"internalType":"uint256","name":"minute","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMonth","outputs":[{"internalType":"uint256","name":"month","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getSecond","outputs":[{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getYear","outputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"isValidDate","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"isValidDateTime","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekDay","outputs":[{"internalType":"bool","name":"weekDay","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekEnd","outputs":[{"internalType":"bool","name":"weekEnd","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nextYear","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"subDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"subHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"subMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"subMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"subSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"subYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"test","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"timestampFromDate","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"timestampFromDateTime","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDate","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDateTime","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"}] -testDateTimeBin="0x608060405234801561001057600080fd5b506110ed806100206000396000f3fe608060405234801561001057600080fd5b506004361061023c5760003560e01c80637217523c1161013b578063b8d16dbc116100b8578063ea1c16901161007c578063ea1c169014610704578063f615ed5414610754578063f8a8fd6d14610777578063fa93f88314610781578063ff2258cb1461079e5761023c565b8063b8d16dbc14610649578063c7b6fd6a14610666578063c9d3462214610689578063d6582d0d146106ac578063de5101af146106c95761023c565b806392d66313116100ff57806392d66313146105ac5780639e524caa146105c9578063a324ad24146105ec578063ad203bd414610609578063b05eb08d1461062c5761023c565b80637217523c146105035780637be341091461052657806389a3a00d146105495780638aa001fc1461056c5780638d4a2d39146105895761023c565b80633e239e1a116101c9578063444fda821161018d578063444fda82146104425780634b321502146104655780635e05bd6d1461048857806362fb9697146104c357806365c72840146104e65761023c565b80633e239e1a1461039f5780633f9e0eb7146103bc5780634355644d146103df5780634371c46514610402578063442b8c791461041f5761023c565b806314b2d6dc1161021057806314b2d6dc146102be5780631f4f77b2146102fb57806322f8a2b8146103245780632af123b8146103415780633293d007146103645761023c565b80625015531461024157806302e98e0d1461027657806310848ddf14610299578063146bea7b146102b6575b600080fd5b6102646004803603604081101561025757600080fd5b50803590602001356107c1565b60408051918252519081900360200190f35b6102646004803603604081101561028c57600080fd5b50803590602001356107d4565b610264600480360360208110156102af57600080fd5b50356107e0565b6102646107f1565b6102e7600480360360608110156102d457600080fd5b50803590602081013590604001356107f7565b604080519115158252519081900360200190f35b6102646004803603606081101561031157600080fd5b508035906020810135906040013561080c565b6102646004803603602081101561033a57600080fd5b5035610819565b6102646004803603604081101561035757600080fd5b5080359060200135610824565b6102e7600480360360c081101561037a57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135610830565b610264600480360360208110156103b557600080fd5b503561084b565b610264600480360360408110156103d257600080fd5b5080359060200135610856565b610264600480360360408110156103f557600080fd5b5080359060200135610862565b6102e76004803603602081101561041857600080fd5b503561086e565b6102646004803603604081101561043557600080fd5b5080359060200135610879565b6102646004803603604081101561045857600080fd5b5080359060200135610885565b6102646004803603604081101561047b57600080fd5b5080359060200135610891565b610264600480360360c081101561049e57600080fd5b5080359060208101359060408101359060608101359060808101359060a0013561089d565b610264600480360360408110156104d957600080fd5b50803590602001356108b7565b610264600480360360208110156104fc57600080fd5b50356108c3565b6102646004803603604081101561051957600080fd5b50803590602001356108ce565b6102646004803603604081101561053c57600080fd5b50803590602001356108da565b6102646004803603604081101561055f57600080fd5b50803590602001356108e6565b6102646004803603602081101561058257600080fd5b50356108f2565b6102646004803603604081101561059f57600080fd5b50803590602001356108fd565b610264600480360360208110156105c257600080fd5b5035610909565b610264600480360360408110156105df57600080fd5b5080359060200135610914565b6102646004803603602081101561060257600080fd5b5035610920565b6102646004803603604081101561061f57600080fd5b508035906020013561092b565b6102e76004803603602081101561064257600080fd5b5035610937565b6102e76004803603602081101561065f57600080fd5b5035610942565b6102646004803603604081101561067c57600080fd5b508035906020013561094d565b6102646004803603604081101561069f57600080fd5b5080359060200135610959565b6102e7600480360360208110156106c257600080fd5b5035610965565b6106e6600480360360208110156106df57600080fd5b5035610970565b60408051938452602084019290925282820152519081900360600190f35b6107216004803603602081101561071a57600080fd5b503561098b565b604080519687526020870195909552858501939093526060850191909152608084015260a0830152519081900360c00190f35b6102646004803603604081101561076a57600080fd5b50803590602001356109b1565b61077f6109bd565b005b6102646004803603602081101561079757600080fd5b50356109d5565b610264600480360360408110156107b457600080fd5b50803590602001356109e0565b60006107cd83836109ec565b9392505050565b60006107cd8383610a00565b60006107eb82610a1d565b92915050565b60005481565b6000610804848484610a3f565b949350505050565b6000610804848484610a95565b60006107eb82610aaf565b60006107cd8383610ac2565b6000610840878787878787610adc565b979650505050505050565b60006107eb82610b1c565b60006107cd8383610b2a565b60006107cd8383610bb0565b60006107eb82610c2a565b60006107cd8383610c3f565b60006107cd8383610c66565b60006107cd8383610cc2565b6000610840878787878787610cd6565b9695505050505050565b60006107cd8383610d00565b60006107eb82610d14565b60006107cd8383610d23565b60006107cd8383610d38565b60006107cd8383610d8a565b60006107eb82610d9d565b60006107cd8383610da4565b60006107eb82610db4565b60006107cd8383610dcc565b60006107eb82610ddf565b60006107cd8383610dee565b60006107eb82610e6e565b60006107eb82610e93565b60006107cd8383610eb0565b60006107cd8383610ec5565b60006107eb82610ee0565b600080600061097e84610ef5565b9196909550909350915050565b60008060008060008061099d87610f06565b949c939b5091995097509550909350915050565b60006107cd8383610f45565b426109cf81600163ffffffff610c3f16565b60005550565b60006107eb82610f55565b60006107cd8383610f64565b610e1081028203828111156107eb57600080fd5b600081831115610a0f57600080fd5b603c8383035b049392505050565b60008080610a3062015180855b04610fa5565b50915091506108048282610b2a565b60006107b28410158015610a535750600083115b8015610a605750600c8311155b156107cd576000610a718585610b2a565b9050600083118015610a835750808311155b15610a8d57600191505b509392505050565b600062015180610aa685858561103b565b02949350505050565b6007620151809091046003010660010190565b600081831115610ad157600080fd5b610e10838303610a15565b6000610ae9878787610a3f565b156108ad57601884108015610afe5750603c83105b8015610b0a5750603c82105b156108ad575060019695505050505050565b610e10620151809091060490565b60008160011480610b3b5750816003145b80610b465750816005145b80610b515750816007145b80610b5c5750816008145b80610b67575081600a145b80610b72575081600c145b15610b7f5750601f6107eb565b81600214610b8f5750601e6107eb565b610b9883610e6e565b610ba357601c610ba6565b601d5b60ff169392505050565b6000808080610bc26201518087610a2a565b600c918801600019810183810494909401965094509250900660010191506000610bec8484610b2a565b905080821115610bfa578091505b62015180870662015180610c0f86868661103b565b0201945086851015610c2057600080fd5b5050505092915050565b60006006610c3783610aaf565b101592915050565b6000808080610c516201518087610a2a565b9187019450925090506000610bec8484610b2a565b6000808080610c786201518087610a2a565b918790039450925090506000610c8e8484610b2a565b905080821115610c9c578091505b62015180870662015180610cb186868661103b565b0201945086851115610c2057600080fd5b610e1081028201828110156107eb57600080fd5b600081603c8402610e10860262015180610cf18b8b8b61103b565b02010101979650505050505050565b600081831115610d0f57600080fd5b500390565b60006108046201518083610a2a565b6201518081028201828110156107eb57600080fd5b600081831115610d4757600080fd5b600080610d576201518086610a2a565b5091509150600080610d6e620151808781610a2a57fe5b50600c9586029590910201939093039190910395945050505050565b603c81028201828110156107eb57600080fd5b603c900690565b818101828110156107eb57600080fd5b6000610dc36201518083610a2a565b50909392505050565b603c81028203828111156107eb57600080fd5b6000610a8d6201518083610a2a565b6000808080610e006201518087610a2a565b91945092509050600c8084028301869003600019019081049350600c810660010192506000610e2f8585610b2a565b905080831115610e3d578092505b62015180880662015180610e5287878761103b565b0201955087861115610e6357600080fd5b505050505092915050565b600060048206158015610e8357506064820615155b806107eb57505061019090061590565b600080610ea36201518084610a2a565b505090506107cd81610e6e565b6201518081028203828111156107eb57600080fd5b600081831115610ed457600080fd5b62015180838303610a15565b60006005610eed83610aaf565b111592915050565b6000808061097e6201518085610a2a565b60008080808080610f1a6201518088610a2a565b91999098919750610e10620151809092068281049750603c9290068281049650919091069350915050565b808203828111156107eb57600080fd5b6000610e108206603c81610a15565b600081831115610f7357600080fd5b6000610f826201518085610a2a565b505090506000610f97620151808581610a2a57fe5b505091909103949350505050565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f8460500281610ffc57fe5b0590506000605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b60006107b284101561104c57600080fd5b838383600062253d8c600460036064611324600c600d19890105890101050205600c80600d19870105600c02600287030361016f028161108857fe5b0560046105b5600c600d1989010589016112c0010205617d4b860301010303905080945050505050939250505056fea2646970667358221220144bfa7ff851a685f881e93c3b88c3dce21cc7d3c01423e087bdfba5b17d290964736f6c63430006000033" -var dateTimeLibAddress="0x90d8927407c79c4a28ee879b821c76fc9bcc2688"; -var dateTimeLibAbi=[]; -var dateTimeLib=eth.contract(dateTimeLibAbi).at(dateTimeLibAddress); -var testDateTimeAddress="0x0e946b999033257976aa5cbe0e3530618ca1582d"; -var testDateTimeAbi=[{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"_getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"name":"_isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"addDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"addHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"addMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"addMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"addSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"addYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffDays","outputs":[{"internalType":"uint256","name":"_days","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffHours","outputs":[{"internalType":"uint256","name":"_hours","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMinutes","outputs":[{"internalType":"uint256","name":"_minutes","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMonths","outputs":[{"internalType":"uint256","name":"_months","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffSeconds","outputs":[{"internalType":"uint256","name":"_seconds","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffYears","outputs":[{"internalType":"uint256","name":"_years","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDay","outputs":[{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDayOfWeek","outputs":[{"internalType":"uint256","name":"dayOfWeek","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getHour","outputs":[{"internalType":"uint256","name":"hour","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMinute","outputs":[{"internalType":"uint256","name":"minute","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMonth","outputs":[{"internalType":"uint256","name":"month","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getSecond","outputs":[{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getYear","outputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"isValidDate","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"isValidDateTime","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekDay","outputs":[{"internalType":"bool","name":"weekDay","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekEnd","outputs":[{"internalType":"bool","name":"weekEnd","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nextYear","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"subDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"subHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"subMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"subMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"subSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"subYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"test","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"timestampFromDate","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"timestampFromDateTime","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDate","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDateTime","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"}]; -var testDateTime=eth.contract(testDateTimeAbi).at(testDateTimeAddress); -console.log("testDateTime=" + JSON.stringify(testDateTime)); diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/functions.js b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/functions.js deleted file mode 100644 index f8410d7..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/functions.js +++ /dev/null @@ -1,571 +0,0 @@ -// ETH/USD 19 May 2018 00:14 AEDT from CMC and ethgasstation.info -var ethPriceUSD = 675.71; -var defaultGasPrice = web3.toWei(16, "gwei"); - -// ----------------------------------------------------------------------------- -// Accounts -// ----------------------------------------------------------------------------- -var accounts = []; -var accountNames = {}; - -addAccount(eth.accounts[0], "Account #0 - Miner"); -addAccount(eth.accounts[1], "Account #1 - Contract Owner"); -addAccount(eth.accounts[2], "Account #2 - Alice"); -addAccount(eth.accounts[3], "Account #3 - Bob"); -addAccount(eth.accounts[4], "Account #4 - Carol"); -addAccount(eth.accounts[5], "Account #5 - Dave"); -addAccount(eth.accounts[6], "Account #6"); -addAccount(eth.accounts[7], "Account #7"); -addAccount(eth.accounts[8], "Account #8"); -addAccount(eth.accounts[9], "Account #9"); -addAccount(eth.accounts[10], "Account #10"); -addAccount(eth.accounts[11], "Account #11"); - -var minerAccount = eth.accounts[0]; -var contractOwnerAccount = eth.accounts[1]; -var aliceAccount = eth.accounts[2]; -var bobAccount = eth.accounts[3]; -var carolAccount = eth.accounts[4]; -var daveAccount = eth.accounts[5]; -var account6 = eth.accounts[6]; -var account7 = eth.accounts[7]; -var account8 = eth.accounts[8]; -var account9 = eth.accounts[9]; -var account10 = eth.accounts[10]; -var account11 = eth.accounts[11]; - -var baseBlock = eth.blockNumber; - -function unlockAccounts(password) { - for (var i = 0; i < eth.accounts.length && i < accounts.length; i++) { - personal.unlockAccount(eth.accounts[i], password, 100000); - if (i > 0 && eth.getBalance(eth.accounts[i]) == 0) { - personal.sendTransaction({from: eth.accounts[0], to: eth.accounts[i], value: web3.toWei(1000000, "ether")}); - } - } - while (txpool.status.pending > 0) { - } - baseBlock = eth.blockNumber; -} - -function addAccount(account, accountName) { - accounts.push(account); - accountNames[account] = accountName; -} - - -// ----------------------------------------------------------------------------- -// Token Contract -// ----------------------------------------------------------------------------- -var tokenContractAddress = null; -var tokenContractAbi = null; - -function addTokenContractAddressAndAbi(address, tokenAbi) { - tokenContractAddress = address; - tokenContractAbi = tokenAbi; -} - - -// ----------------------------------------------------------------------------- -// Account ETH and token balances -// ----------------------------------------------------------------------------- -function printBalances() { - var token = tokenContractAddress == null || tokenContractAbi == null ? null : web3.eth.contract(tokenContractAbi).at(tokenContractAddress); - var decimals = token == null ? 18 : token.decimals(); - var i = 0; - var totalTokenBalance = new BigNumber(0); - console.log("RESULT: # Account EtherBalanceChange Token Name"); - console.log("RESULT: -- ------------------------------------------ --------------------------- ------------------------------ ---------------------------"); - accounts.forEach(function(e) { - var etherBalanceBaseBlock = eth.getBalance(e, baseBlock); - var etherBalance = web3.fromWei(eth.getBalance(e).minus(etherBalanceBaseBlock), "ether"); - var tokenBalance = token == null ? new BigNumber(0) : token.balanceOf.call(e).shift(-decimals); - totalTokenBalance = totalTokenBalance.add(tokenBalance); - console.log("RESULT: " + pad2(i) + " " + e + " " + pad(etherBalance) + " " + padToken(tokenBalance, decimals) + " " + accountNames[e]); - i++; - }); - console.log("RESULT: -- ------------------------------------------ --------------------------- ------------------------------ ---------------------------"); - console.log("RESULT: " + padToken(totalTokenBalance, decimals) + " Total Token Balances"); - console.log("RESULT: -- ------------------------------------------ --------------------------- ------------------------------ ---------------------------"); - console.log("RESULT: "); -} - -function pad2(s) { - var o = s.toFixed(0); - while (o.length < 2) { - o = " " + o; - } - return o; -} - -function pad(s) { - var o = s.toFixed(18); - while (o.length < 27) { - o = " " + o; - } - return o; -} - -function padToken(s, decimals) { - var o = s.toFixed(decimals); - var l = parseInt(decimals)+12; - while (o.length < l) { - o = " " + o; - } - return o; -} - - -// ----------------------------------------------------------------------------- -// Transaction status -// ----------------------------------------------------------------------------- -function printTxData(name, txId) { - var tx = eth.getTransaction(txId); - var txReceipt = eth.getTransactionReceipt(txId); - var gasPrice = tx.gasPrice; - var gasCostETH = tx.gasPrice.mul(txReceipt.gasUsed).div(1e18); - var gasCostUSD = gasCostETH.mul(ethPriceUSD); - var block = eth.getBlock(txReceipt.blockNumber); - console.log("RESULT: " + name + " status=" + txReceipt.status + (txReceipt.status == 0 ? " Failure" : " Success") + " gas=" + tx.gas + - " gasUsed=" + txReceipt.gasUsed + " costETH=" + gasCostETH + " costUSD=" + gasCostUSD + - " @ ETH/USD=" + ethPriceUSD + " gasPrice=" + web3.fromWei(gasPrice, "gwei") + " gwei block=" + - txReceipt.blockNumber + " txIx=" + tx.transactionIndex + " txId=" + txId + - " @ " + block.timestamp + " " + new Date(block.timestamp * 1000).toUTCString()); -} - -function assert(condition, message) { - if (condition) { - console.log("RESULT: PASS " + message); - } else { - console.log("RESULT: FAIL " + message); - } - return condition; -} - -function assertIntEquals(result, expected, message) { - if (parseInt(result) == parseInt(expected)) { - console.log("RESULT: PASS " + message); - return true; - } else { - console.log("RESULT: FAIL " + message); - return false; - } -} - -function assertEtherBalance(account, expectedBalance) { - var etherBalance = web3.fromWei(eth.getBalance(account), "ether"); - if (etherBalance == expectedBalance) { - console.log("RESULT: OK " + account + " has expected balance " + expectedBalance); - } else { - console.log("RESULT: FAILURE " + account + " has balance " + etherBalance + " <> expected " + expectedBalance); - } -} - -function failIfTxStatusError(tx, msg) { - var status = eth.getTransactionReceipt(tx).status; - if (status == 0) { - console.log("RESULT: FAIL " + msg); - return 0; - } else { - console.log("RESULT: PASS " + msg); - return 1; - } -} - -function passIfTxStatusError(tx, msg) { - var status = eth.getTransactionReceipt(tx).status; - if (status == 1) { - console.log("RESULT: FAIL " + msg); - return 0; - } else { - console.log("RESULT: PASS " + msg); - return 1; - } -} - -function gasEqualsGasUsed(tx) { - var gas = eth.getTransaction(tx).gas; - var gasUsed = eth.getTransactionReceipt(tx).gasUsed; - return (gas == gasUsed); -} - -function failIfGasEqualsGasUsed(tx, msg) { - var gas = eth.getTransaction(tx).gas; - var gasUsed = eth.getTransactionReceipt(tx).gasUsed; - if (gas == gasUsed) { - console.log("RESULT: FAIL " + msg); - return 0; - } else { - console.log("RESULT: PASS " + msg); - return 1; - } -} - -function passIfGasEqualsGasUsed(tx, msg) { - var gas = eth.getTransaction(tx).gas; - var gasUsed = eth.getTransactionReceipt(tx).gasUsed; - if (gas == gasUsed) { - console.log("RESULT: PASS " + msg); - return 1; - } else { - console.log("RESULT: FAIL " + msg); - return 0; - } -} - -function failIfGasEqualsGasUsedOrContractAddressNull(contractAddress, tx, msg) { - if (contractAddress == null) { - console.log("RESULT: FAIL " + msg); - return 0; - } else { - var gas = eth.getTransaction(tx).gas; - var gasUsed = eth.getTransactionReceipt(tx).gasUsed; - if (gas == gasUsed) { - console.log("RESULT: FAIL " + msg); - return 0; - } else { - console.log("RESULT: PASS " + msg); - return 1; - } - } -} - - -//----------------------------------------------------------------------------- -// Wait one block -//----------------------------------------------------------------------------- -function waitOneBlock(oldCurrentBlock) { - while (eth.blockNumber <= oldCurrentBlock) { - } - console.log("RESULT: Waited one block"); - console.log("RESULT: "); - return eth.blockNumber; -} - - -//----------------------------------------------------------------------------- -// Pause for {x} seconds -//----------------------------------------------------------------------------- -function pause(message, addSeconds) { - var time = new Date((parseInt(new Date().getTime()/1000) + addSeconds) * 1000); - console.log("RESULT: Pausing '" + message + "' for " + addSeconds + "s=" + time + " now=" + new Date()); - while ((new Date()).getTime() <= time.getTime()) { - } - console.log("RESULT: Paused '" + message + "' for " + addSeconds + "s=" + time + " now=" + new Date()); - console.log("RESULT: "); -} - - -//----------------------------------------------------------------------------- -//Wait until some unixTime + additional seconds -//----------------------------------------------------------------------------- -function waitUntil(message, unixTime, addSeconds) { - var t = parseInt(unixTime) + parseInt(addSeconds) + parseInt(1); - var time = new Date(t * 1000); - console.log("RESULT: Waiting until '" + message + "' at " + unixTime + "+" + addSeconds + "s=" + time + " now=" + new Date()); - while ((new Date()).getTime() <= time.getTime()) { - } - console.log("RESULT: Waited until '" + message + "' at at " + unixTime + "+" + addSeconds + "s=" + time + " now=" + new Date()); - console.log("RESULT: "); -} - - -//----------------------------------------------------------------------------- -//Wait until some block -//----------------------------------------------------------------------------- -function waitUntilBlock(message, block, addBlocks) { - var b = parseInt(block) + parseInt(addBlocks); - console.log("RESULT: Waiting until '" + message + "' #" + block + "+" + addBlocks + "=#" + b + " currentBlock=" + eth.blockNumber); - while (eth.blockNumber <= b) { - } - console.log("RESULT: Waited until '" + message + "' #" + block + "+" + addBlocks + "=#" + b + " currentBlock=" + eth.blockNumber); - console.log("RESULT: "); -} - - -//----------------------------------------------------------------------------- -// Token Contract -//----------------------------------------------------------------------------- -var tokenFromBlock = 0; -function printTokenContractDetails() { - console.log("RESULT: tokenContractAddress=" + tokenContractAddress); - if (tokenContractAddress != null && tokenContractAbi != null) { - var contract = eth.contract(tokenContractAbi).at(tokenContractAddress); - var decimals = contract.decimals(); - console.log("RESULT: token.owner=" + contract.owner()); - console.log("RESULT: token.newOwner=" + contract.newOwner()); - console.log("RESULT: token.symbol=" + contract.symbol()); - console.log("RESULT: token.name=" + contract.name()); - console.log("RESULT: token.decimals=" + decimals); - console.log("RESULT: token.totalSupply=" + contract.totalSupply().shift(-decimals)); - // console.log("RESULT: token.transferable=" + contract.transferable()); - // console.log("RESULT: token.mintable=" + contract.mintable()); - // console.log("RESULT: token.minter=" + contract.minter()); - - var latestBlock = eth.blockNumber; - var i; - - var approvalEvents = contract.Approval({}, { fromBlock: tokenFromBlock, toBlock: latestBlock }); - i = 0; - approvalEvents.watch(function (error, result) { - console.log("RESULT: Approval " + i++ + " #" + result.blockNumber + " owner=" + result.args.owner + - " spender=" + result.args.spender + " tokens=" + result.args.tokens.shift(-decimals)); - }); - approvalEvents.stopWatching(); - - var transferEvents = contract.Transfer({}, { fromBlock: tokenFromBlock, toBlock: latestBlock }); - i = 0; - transferEvents.watch(function (error, result) { - console.log("RESULT: Transfer " + i++ + " #" + result.blockNumber + ": from=" + result.args.from + " to=" + result.args.to + - " tokens=" + result.args.tokens.shift(-decimals)); - }); - transferEvents.stopWatching(); - - tokenFromBlock = latestBlock + 1; - } -} - - -// ----------------------------------------------------------------------------- -// Club Contract -// ----------------------------------------------------------------------------- -var clubContractAddress = null; -var clubContractAbi = null; - -function addClubContractAddressAndAbi(address, clubAbi) { - clubContractAddress = address; - clubContractAbi = clubAbi; -} - -function displaySplit(data) { - var eth1 = data[0]; - var eth2 = data[1]; - var eth3 = data[2]; - var refund = data[3]; - var total = eth1.add(eth2).add(eth3).add(refund); - return "[eth1=" + eth1.shift(-18) + "; eth2=" + eth2.shift(-18) + "; eth3=" + eth3.shift(-18) + "; refund=" + refund.shift(-18) + "; total=" + total.shift(-18) + "]"; -} - -var clubFromBlock = 0; -function printClubContractDetails() { - console.log("RESULT: clubContractAddress=" + clubContractAddress); - if (clubContractAddress != null && clubContractAbi != null) { - var contract = eth.contract(clubContractAbi).at(clubContractAddress); - console.log("RESULT: club.token=" + contract.token()); - console.log("RESULT: club.initialised=" + contract.initialised()); - console.log("RESULT: club.numberOfMembers=" + contract.numberOfMembers()); - console.log("RESULT: club.getMembers=" + JSON.stringify(contract.getMembers())); - var i; - for (i = 0; i < contract.numberOfMembers(); i++) { - var member = contract.getMemberByIndex(i); - var data = contract.getMemberData(member); - console.log("RESULT: club.member[" + i + "]=" + member + " [" + data[0] + ", " + data[1] + ", '" + data[2] + "']"); - } - console.log("RESULT: club.numberOfProposals=" + contract.numberOfProposals()); - for (i = 0; i < contract.numberOfProposals(); i++) { - console.log("RESULT: club.getProposal[" + i + "]=" + JSON.stringify(contract.getProposal(i))); - } - console.log("RESULT: club.quorum=" + contract.quorum() + "%"); - console.log("RESULT: club.quorumDecayPerWeek=" + contract.quorumDecayPerWeek() + "%"); - console.log("RESULT: club.requiredMajority=" + contract.requiredMajority() + "%"); - - var now = new Date()/1000; - var line = ""; - for (i = 0; i < 10; i++) { - var date = parseInt(now) + 60 * 60 * 24 * 7 * i; - line = line + i + "w=" + contract.getQuorum(now, date) + "% "; - } - console.log("RESULT: club.getQuorum(now, * weeks)=" + line); - - var latestBlock = eth.blockNumber; - - var newProposalEvents = contract.NewProposal({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); - i = 0; - newProposalEvents.watch(function (error, result) { - console.log("RESULT: NewProposal " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); - var proposal = contract.getProposal(result.args.proposalId); - console.log("RESULT: - proposal=" + JSON.stringify(proposal)); - }); - newProposalEvents.stopWatching(); - - var votedEvents = contract.Voted({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); - i = 0; - votedEvents.watch(function (error, result) { - console.log("RESULT: Voted " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); - }); - votedEvents.stopWatching(); - - var voteResultEvents = contract.VoteResult({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); - i = 0; - voteResultEvents.watch(function (error, result) { - console.log("RESULT: VoteResult " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); - }); - voteResultEvents.stopWatching(); - - var memberAddedEvents = contract.MemberAdded({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); - i = 0; - memberAddedEvents.watch(function (error, result) { - console.log("RESULT: MemberAdded " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); - }); - memberAddedEvents.stopWatching(); - - var memberRemovedEvents = contract.MemberRemoved({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); - i = 0; - memberRemovedEvents.watch(function (error, result) { - console.log("RESULT: MemberRemoved " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); - }); - memberRemovedEvents.stopWatching(); - - var memberNameUpdatedEvents = contract.MemberNameUpdated({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); - i = 0; - memberNameUpdatedEvents.watch(function (error, result) { - console.log("RESULT: MemberNameUpdated " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); - }); - memberNameUpdatedEvents.stopWatching(); - - var tokenUpdatedEvents = contract.TokenUpdated({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); - i = 0; - tokenUpdatedEvents.watch(function (error, result) { - console.log("RESULT: TokenUpdated " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); - }); - tokenUpdatedEvents.stopWatching(); - - var tokensForNewMembersUpdatedEvents = contract.TokensForNewMembersUpdated({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); - i = 0; - tokensForNewMembersUpdatedEvents.watch(function (error, result) { - console.log("RESULT: TokensForNewMembersUpdated " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); - }); - tokensForNewMembersUpdatedEvents.stopWatching(); - - var etherDepositedEvents = contract.EtherDeposited({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); - i = 0; - etherDepositedEvents.watch(function (error, result) { - console.log("RESULT: EtherDeposited " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); - }); - etherDepositedEvents.stopWatching(); - - var etherTransferredEvents = contract.EtherTransferred({}, { fromBlock: clubFromBlock, toBlock: latestBlock }); - i = 0; - etherTransferredEvents.watch(function (error, result) { - console.log("RESULT: EtherTransferred " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); - }); - etherTransferredEvents.stopWatching(); - - clubFromBlock = latestBlock + 1; - } -} - - -// ----------------------------------------------------------------------------- -// ClubFactory Contract -// ----------------------------------------------------------------------------- -var clubFactoryContractAddress = null; -var clubFactoryContractAbi = null; - -function addClubFactoryContractAddressAndAbi(address, clubFactoryAbi) { - clubFactoryContractAddress = address; - clubFactoryContractAbi = clubFactoryAbi; -} - -var clubFactoryFromBlock = 0; - -function getClubAndTokenListing() { - var clubs = []; - var tokens = []; - console.log("RESULT: clubFactoryContractAddress=" + clubFactoryContractAddress); - if (clubFactoryContractAddress != null && clubFactoryContractAbi != null) { - var contract = eth.contract(clubFactoryContractAbi).at(clubFactoryContractAddress); - - var latestBlock = eth.blockNumber; - var i; - - var clubListingEvents = contract.ClubEthListing({}, { fromBlock: clubFactoryFromBlock, toBlock: latestBlock }); - i = 0; - clubListingEvents.watch(function (error, result) { - console.log("RESULT: get ClubEthListing " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); - clubs.push(result.args.clubAddress); - tokens.push(result.args.tokenAddress); - }); - clubListingEvents.stopWatching(); - } - return [clubs, tokens]; -} - -function printClubFactoryContractDetails() { - console.log("RESULT: clubFactoryContractAddress=" + clubFactoryContractAddress); - if (clubFactoryContractAddress != null && clubFactoryContractAbi != null) { - var contract = eth.contract(clubFactoryContractAbi).at(clubFactoryContractAddress); - console.log("RESULT: clubFactory.owner=" + contract.owner()); - console.log("RESULT: clubFactory.newOwner=" + contract.newOwner()); - - var latestBlock = eth.blockNumber; - var i; - - var ownershipTransferredEvents = contract.OwnershipTransferred({}, { fromBlock: clubFactoryFromBlock, toBlock: latestBlock }); - i = 0; - ownershipTransferredEvents.watch(function (error, result) { - console.log("RESULT: OwnershipTransferred " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); - }); - ownershipTransferredEvents.stopWatching(); - - var clubEthListingEvents = contract.ClubEthListing({}, { fromBlock: clubFactoryFromBlock, toBlock: latestBlock }); - i = 0; - clubEthListingEvents.watch(function (error, result) { - console.log("RESULT: ClubEthListing " + i++ + " #" + result.blockNumber + " " + JSON.stringify(result.args)); - }); - clubEthListingEvents.stopWatching(); - - clubFactoryFromBlock = latestBlock + 1; - } -} - - -// ----------------------------------------------------------------------------- -// Generate Summary JSON -// ----------------------------------------------------------------------------- -function generateSummaryJSON() { - console.log("JSONSUMMARY: {"); - if (crowdsaleContractAddress != null && crowdsaleContractAbi != null) { - var contract = eth.contract(crowdsaleContractAbi).at(crowdsaleContractAddress); - var blockNumber = eth.blockNumber; - var timestamp = eth.getBlock(blockNumber).timestamp; - console.log("JSONSUMMARY: \"blockNumber\": " + blockNumber + ","); - console.log("JSONSUMMARY: \"blockTimestamp\": " + timestamp + ","); - console.log("JSONSUMMARY: \"blockTimestampString\": \"" + new Date(timestamp * 1000).toUTCString() + "\","); - console.log("JSONSUMMARY: \"crowdsaleContractAddress\": \"" + crowdsaleContractAddress + "\","); - console.log("JSONSUMMARY: \"crowdsaleContractOwnerAddress\": \"" + contract.owner() + "\","); - console.log("JSONSUMMARY: \"tokenContractAddress\": \"" + contract.bttsToken() + "\","); - console.log("JSONSUMMARY: \"tokenContractDecimals\": " + contract.TOKEN_DECIMALS() + ","); - console.log("JSONSUMMARY: \"crowdsaleWalletAddress\": \"" + contract.wallet() + "\","); - console.log("JSONSUMMARY: \"crowdsaleTeamWalletAddress\": \"" + contract.teamWallet() + "\","); - console.log("JSONSUMMARY: \"crowdsaleTeamPercent\": " + contract.TEAM_PERCENT_GZE() + ","); - console.log("JSONSUMMARY: \"bonusListContractAddress\": \"" + contract.bonusList() + "\","); - console.log("JSONSUMMARY: \"tier1Bonus\": " + contract.TIER1_BONUS() + ","); - console.log("JSONSUMMARY: \"tier2Bonus\": " + contract.TIER2_BONUS() + ","); - console.log("JSONSUMMARY: \"tier3Bonus\": " + contract.TIER3_BONUS() + ","); - var startDate = contract.START_DATE(); - // BK TODO - Remove for production - startDate = 1512921600; - var endDate = contract.endDate(); - // BK TODO - Remove for production - endDate = 1513872000; - console.log("JSONSUMMARY: \"crowdsaleStart\": " + startDate + ","); - console.log("JSONSUMMARY: \"crowdsaleStartString\": \"" + new Date(startDate * 1000).toUTCString() + "\","); - console.log("JSONSUMMARY: \"crowdsaleEnd\": " + endDate + ","); - console.log("JSONSUMMARY: \"crowdsaleEndString\": \"" + new Date(endDate * 1000).toUTCString() + "\","); - console.log("JSONSUMMARY: \"usdPerEther\": " + contract.usdPerKEther().shift(-3) + ","); - console.log("JSONSUMMARY: \"usdPerGze\": " + contract.USD_CENT_PER_GZE().shift(-2) + ","); - console.log("JSONSUMMARY: \"gzePerEth\": " + contract.gzePerEth().shift(-18) + ","); - console.log("JSONSUMMARY: \"capInUsd\": " + contract.CAP_USD() + ","); - console.log("JSONSUMMARY: \"capInEth\": " + contract.capEth().shift(-18) + ","); - console.log("JSONSUMMARY: \"minimumContributionEth\": " + contract.MIN_CONTRIBUTION_ETH().shift(-18) + ","); - console.log("JSONSUMMARY: \"contributedEth\": " + contract.contributedEth().shift(-18) + ","); - console.log("JSONSUMMARY: \"contributedUsd\": " + contract.contributedUsd() + ","); - console.log("JSONSUMMARY: \"generatedGze\": " + contract.generatedGze().shift(-18) + ","); - console.log("JSONSUMMARY: \"lockedAccountThresholdUsd\": " + contract.lockedAccountThresholdUsd() + ","); - console.log("JSONSUMMARY: \"lockedAccountThresholdEth\": " + contract.lockedAccountThresholdEth().shift(-18) + ","); - console.log("JSONSUMMARY: \"precommitmentAdjusted\": " + contract.precommitmentAdjusted() + ","); - console.log("JSONSUMMARY: \"finalised\": " + contract.finalised()); - } - console.log("JSONSUMMARY: }"); -} diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/genesis.json b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/genesis.json deleted file mode 100644 index ca85b4a..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/genesis.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "config": { - "homesteadBlock": 1, - "byzantiumBlock": 2 - }, - "nonce": "0", - "difficulty": "0x400", - "mixhash": "0x00000000000000000000000000000000000000647572616c65787365646c6578", - "coinbase": "0x0000000000000000000000000000000000000000", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x", - "gasLimit": "0x3B4A1B44", - "alloc": { - "0xa00Af22D07c87d96EeeB0Ed583f8F6AC7812827E": { - "balance": "10000000000000000000000000" - }, - "0xa11AAE29840fBb5c86E6fd4cF809EBA183AEf433": { - "balance": "10000000000000000000000000" - }, - "0xa22AB8A9D641CE77e06D98b7D7065d324D3d6976": { - "balance": "10000000000000000000000000" - }, - "0xa33a6c312D9aD0E0F2E95541BeED0Cc081621fd0": { - "balance": "10000000000000000000000000" - }, - "0xa44a08d3F6933c69212114bb66E2Df1813651844": { - "balance": "10000000000000000000000000" - }, - "0xa55A151Eb00fded1634D27D1127b4bE4627079EA": { - "balance": "10000000000000000000000000" - }, - "0xa66a85ede0CBE03694AA9d9dE0BB19c99ff55bD9": { - "balance": "10000000000000000000000000" - }, - "0xa77A2b9D4B1c010A22A7c565Dc418cef683DbceC": { - "balance": "10000000000000000000000000" - }, - "0xA88A05d2b88283ce84C8325760B72a64591279a2": { - "balance": "10000000000000000000000000" - }, - "0xa99A0Ae3354c06B1459fd441a32a3F71005D7Da0": { - "balance": "10000000000000000000000000" - }, - "0xAAAA9De1E6C564446EBCA0fd102D8Bd92093c756": { - "balance": "10000000000000000000000000" - }, - "0xaBBa43E7594E3B76afB157989e93c6621497FD4b": { - "balance": "10000000000000000000000000" - }, - "0xacCa534c9f62Ab495bd986e002DdF0f054caAE4f": { - "balance": "10000000000000000000000000" - }, - "0xAddA9B762A00FF12711113bfDc36958B73d7F915": { - "balance": "10000000000000000000000000" - }, - "0xaeEa63B5479B50F79583ec49DACdcf86DDEff392": { - "balance": "10000000000000000000000000" - }, - "0xaFfa4D3A80Add8CE4018540e056DACb649589394": { - "balance": "10000000000000000000000000" - }, - "0xB00bfdE102270687324F9205b693859df64F8923": { - "balance": "10000000000000000000000000" - }, - "0xB11Be1D4EF8E94d01cB2695092A79d139A8DAD98": { - "balance": "10000000000000000000000000" - }, - "0xB22BE2D9eEF0d7E260CF96A64FEEa0B95ED3E74f": { - "balance": "10000000000000000000000000" - }, - "0xB33B7ecf5E47BE3981c74d989d3Af8b665b4B649": { - "balance": "10000000000000000000000000" - }, - "0xB44B43d59b738B088b690aE276C1E979aBa8268D": { - "balance": "10000000000000000000000000" - }, - "0xb55B57D113b45481E31AaF03D6F4e5Ad4ef325F8": { - "balance": "10000000000000000000000000" - }, - "0xb66BCB4e473De80E2C8A47CED10c22c705A5e602": { - "balance": "10000000000000000000000000" - }, - "0xB77BbBaa7c1649547Ae61de4B80B91568c28351A": { - "balance": "10000000000000000000000000" - }, - "0xB88B728490B417E29b0784Db30535dB343830dba": { - "balance": "10000000000000000000000000" - }, - "0xB99B3d1f72eDb05a0321dB58eddcF83FD73C4aDe": { - "balance": "10000000000000000000000000" - }, - "0xBaAb56DA883EDBe5314b8005BE410022c510cCae": { - "balance": "10000000000000000000000000" - }, - "0xbbbB9809DE0456Ce0E0Cd660E6E4CeabEf3F521c": { - "balance": "10000000000000000000000000" - }, - "0xBccB68DD0Ac87EF290aeF49870d155F076C87868": { - "balance": "10000000000000000000000000" - }, - "0xbDDB726ee06906e104DB210E6d0506F2B062e477": { - "balance": "10000000000000000000000000" - }, - "0xbeEB24ff18203658D0a1d4682ee3f36ad663eC87": { - "balance": "10000000000000000000000000" - }, - "0xbFfBd8F029EF0BD81cF754b53E8b3a5684F8b3fF": { - "balance": "10000000000000000000000000" - } - } -} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/settings b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/settings deleted file mode 100644 index 2ce4bf8..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/settings +++ /dev/null @@ -1,21 +0,0 @@ -GETHATTACHPOINT=ipc:./testchain/geth.ipc -PASSWORD= - -SOURCEDIR=../contracts - -DATETIMELIBSOL=BokkyPooBahsDateTimeLibrary.sol -DATETIMELIBJS=BokkyPooBahsDateTimeLibrary.js -TESTDATETIMESOL=TestDateTime.sol -TESTDATETIMEJS=TestDateTime.js -TESTDATETIMEFLATTENED=../flattened/TestDateTime_flattened.sol - -DEPLOYMENTDATA=deploymentData.js - -TEST1OUTPUT=test1output.txt -TEST1RESULTS=test1results.txt -TEST2OUTPUT=test2output.txt -TEST2RESULTS=test2results.txt -TEST3OUTPUT=test3output.txt -TEST3RESULTS=test3results.txt -TEST4OUTPUT=test4output.txt -TEST4RESULTS=test4results.txt diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1output.txt b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1output.txt deleted file mode 100644 index 979b4e0..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1output.txt +++ /dev/null @@ -1,3070 +0,0 @@ -MODE = 'full' -GETHATTACHPOINT = 'ipc:./testchain/geth.ipc' -PASSWORD = '' -SOURCEDIR = '../contracts' -DATETIMELIBSOL = 'BokkyPooBahsDateTimeLibrary.sol' -DATETIMELIBJS = 'BokkyPooBahsDateTimeLibrary.js' -TESTDATETIMESOL = 'TestDateTime.sol' -TESTDATETIMEJS = 'TestDateTime.js' -DEPLOYMENTDATA = 'deploymentData.js' -TEST1OUTPUT = 'test1output.txt' -TEST1RESULTS = 'test1results.txt' -CURRENTTIME = '1579355174' 'Sun Jan 19 00:46:14 2020' -START_DATE = '1579355219' 'Sun Jan 19 00:46:59 2020' -END_DATE = '1579355294' 'Sun Jan 19 00:48:14 2020' ---- Differences ../contracts/BokkyPooBahsDateTimeLibrary.sol BokkyPooBahsDateTimeLibrary.sol --- - ---- Differences ../contracts/TestDateTime.sol TestDateTime.sol --- - -solc, the solidity compiler commandline interface -Version: 0.6.0+commit.26b70077.Darwin.appleclang -contractsdir: ../contracts -remapdir : (no remapping) -mainsol : TestDateTime.sol -outputsol : ../flattened/TestDateTime_flattened.sol -Processing ../contracts/TestDateTime.sol - Importing ../contracts/BokkyPooBahsDateTimeLibrary.sol - Processing ../contracts/BokkyPooBahsDateTimeLibrary.sol -Welcome to the Geth JavaScript console! - -instance: Geth/v1.9.9-stable-01744997/darwin-amd64/go1.13.5 -coinbase: 0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e -at block: 5 (Sun, 19 Jan 2020 00:46:15 AEDT) - datadir: /Users/bok/Projects/BokkyPooBahsDateTimeLibrary/test/testchain - modules: admin:1.0 clique:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0 - -> -true -> -true -> -true -> -> -undefined -> -undefined -> -undefined -> -undefined -> -> -DATA: dateTimeLibAbi=[] -undefined -> -DATA: dateTimeLibBin="0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122075d49f0ac9a443fac8bb202f0adb9e02ed12cbbf6d4d258fcb57548a1e88719064736f6c63430006000033" -undefined -> -DATA: testDateTimeAbi=[{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"_getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"name":"_isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"addDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"addHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"addMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"addMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"addSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"addYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffDays","outputs":[{"internalType":"uint256","name":"_days","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffHours","outputs":[{"internalType":"uint256","name":"_hours","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMinutes","outputs":[{"internalType":"uint256","name":"_minutes","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMonths","outputs":[{"internalType":"uint256","name":"_months","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffSeconds","outputs":[{"internalType":"uint256","name":"_seconds","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffYears","outputs":[{"internalType":"uint256","name":"_years","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDay","outputs":[{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDayOfWeek","outputs":[{"internalType":"uint256","name":"dayOfWeek","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getHour","outputs":[{"internalType":"uint256","name":"hour","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMinute","outputs":[{"internalType":"uint256","name":"minute","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMonth","outputs":[{"internalType":"uint256","name":"month","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getSecond","outputs":[{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getYear","outputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"isValidDate","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"isValidDateTime","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekDay","outputs":[{"internalType":"bool","name":"weekDay","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekEnd","outputs":[{"internalType":"bool","name":"weekEnd","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nextYear","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"subDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"subHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"subMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"subMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"subSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"subYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"test","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"timestampFromDate","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"timestampFromDateTime","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDate","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDateTime","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"}] -undefined -> -DATA: testDateTimeBin="0x608060405234801561001057600080fd5b506110ed806100206000396000f3fe608060405234801561001057600080fd5b506004361061023c5760003560e01c80637217523c1161013b578063b8d16dbc116100b8578063ea1c16901161007c578063ea1c169014610704578063f615ed5414610754578063f8a8fd6d14610777578063fa93f88314610781578063ff2258cb1461079e5761023c565b8063b8d16dbc14610649578063c7b6fd6a14610666578063c9d3462214610689578063d6582d0d146106ac578063de5101af146106c95761023c565b806392d66313116100ff57806392d66313146105ac5780639e524caa146105c9578063a324ad24146105ec578063ad203bd414610609578063b05eb08d1461062c5761023c565b80637217523c146105035780637be341091461052657806389a3a00d146105495780638aa001fc1461056c5780638d4a2d39146105895761023c565b80633e239e1a116101c9578063444fda821161018d578063444fda82146104425780634b321502146104655780635e05bd6d1461048857806362fb9697146104c357806365c72840146104e65761023c565b80633e239e1a1461039f5780633f9e0eb7146103bc5780634355644d146103df5780634371c46514610402578063442b8c791461041f5761023c565b806314b2d6dc1161021057806314b2d6dc146102be5780631f4f77b2146102fb57806322f8a2b8146103245780632af123b8146103415780633293d007146103645761023c565b80625015531461024157806302e98e0d1461027657806310848ddf14610299578063146bea7b146102b6575b600080fd5b6102646004803603604081101561025757600080fd5b50803590602001356107c1565b60408051918252519081900360200190f35b6102646004803603604081101561028c57600080fd5b50803590602001356107d4565b610264600480360360208110156102af57600080fd5b50356107e0565b6102646107f1565b6102e7600480360360608110156102d457600080fd5b50803590602081013590604001356107f7565b604080519115158252519081900360200190f35b6102646004803603606081101561031157600080fd5b508035906020810135906040013561080c565b6102646004803603602081101561033a57600080fd5b5035610819565b6102646004803603604081101561035757600080fd5b5080359060200135610824565b6102e7600480360360c081101561037a57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135610830565b610264600480360360208110156103b557600080fd5b503561084b565b610264600480360360408110156103d257600080fd5b5080359060200135610856565b610264600480360360408110156103f557600080fd5b5080359060200135610862565b6102e76004803603602081101561041857600080fd5b503561086e565b6102646004803603604081101561043557600080fd5b5080359060200135610879565b6102646004803603604081101561045857600080fd5b5080359060200135610885565b6102646004803603604081101561047b57600080fd5b5080359060200135610891565b610264600480360360c081101561049e57600080fd5b5080359060208101359060408101359060608101359060808101359060a0013561089d565b610264600480360360408110156104d957600080fd5b50803590602001356108b7565b610264600480360360208110156104fc57600080fd5b50356108c3565b6102646004803603604081101561051957600080fd5b50803590602001356108ce565b6102646004803603604081101561053c57600080fd5b50803590602001356108da565b6102646004803603604081101561055f57600080fd5b50803590602001356108e6565b6102646004803603602081101561058257600080fd5b50356108f2565b6102646004803603604081101561059f57600080fd5b50803590602001356108fd565b610264600480360360208110156105c257600080fd5b5035610909565b610264600480360360408110156105df57600080fd5b5080359060200135610914565b6102646004803603602081101561060257600080fd5b5035610920565b6102646004803603604081101561061f57600080fd5b508035906020013561092b565b6102e76004803603602081101561064257600080fd5b5035610937565b6102e76004803603602081101561065f57600080fd5b5035610942565b6102646004803603604081101561067c57600080fd5b508035906020013561094d565b6102646004803603604081101561069f57600080fd5b5080359060200135610959565b6102e7600480360360208110156106c257600080fd5b5035610965565b6106e6600480360360208110156106df57600080fd5b5035610970565b60408051938452602084019290925282820152519081900360600190f35b6107216004803603602081101561071a57600080fd5b503561098b565b604080519687526020870195909552858501939093526060850191909152608084015260a0830152519081900360c00190f35b6102646004803603604081101561076a57600080fd5b50803590602001356109b1565b61077f6109bd565b005b6102646004803603602081101561079757600080fd5b50356109d5565b610264600480360360408110156107b457600080fd5b50803590602001356109e0565b60006107cd83836109ec565b9392505050565b60006107cd8383610a00565b60006107eb82610a1d565b92915050565b60005481565b6000610804848484610a3f565b949350505050565b6000610804848484610a95565b60006107eb82610aaf565b60006107cd8383610ac2565b6000610840878787878787610adc565b979650505050505050565b60006107eb82610b1c565b60006107cd8383610b2a565b60006107cd8383610bb0565b60006107eb82610c2a565b60006107cd8383610c3f565b60006107cd8383610c66565b60006107cd8383610cc2565b6000610840878787878787610cd6565b9695505050505050565b60006107cd8383610d00565b60006107eb82610d14565b60006107cd8383610d23565b60006107cd8383610d38565b60006107cd8383610d8a565b60006107eb82610d9d565b60006107cd8383610da4565b60006107eb82610db4565b60006107cd8383610dcc565b60006107eb82610ddf565b60006107cd8383610dee565b60006107eb82610e6e565b60006107eb82610e93565b60006107cd8383610eb0565b60006107cd8383610ec5565b60006107eb82610ee0565b600080600061097e84610ef5565b9196909550909350915050565b60008060008060008061099d87610f06565b949c939b5091995097509550909350915050565b60006107cd8383610f45565b426109cf81600163ffffffff610c3f16565b60005550565b60006107eb82610f55565b60006107cd8383610f64565b610e1081028203828111156107eb57600080fd5b600081831115610a0f57600080fd5b603c8383035b049392505050565b60008080610a3062015180855b04610fa5565b50915091506108048282610b2a565b60006107b28410158015610a535750600083115b8015610a605750600c8311155b156107cd576000610a718585610b2a565b9050600083118015610a835750808311155b15610a8d57600191505b509392505050565b600062015180610aa685858561103b565b02949350505050565b6007620151809091046003010660010190565b600081831115610ad157600080fd5b610e10838303610a15565b6000610ae9878787610a3f565b156108ad57601884108015610afe5750603c83105b8015610b0a5750603c82105b156108ad575060019695505050505050565b610e10620151809091060490565b60008160011480610b3b5750816003145b80610b465750816005145b80610b515750816007145b80610b5c5750816008145b80610b67575081600a145b80610b72575081600c145b15610b7f5750601f6107eb565b81600214610b8f5750601e6107eb565b610b9883610e6e565b610ba357601c610ba6565b601d5b60ff169392505050565b6000808080610bc26201518087610a2a565b600c918801600019810183810494909401965094509250900660010191506000610bec8484610b2a565b905080821115610bfa578091505b62015180870662015180610c0f86868661103b565b0201945086851015610c2057600080fd5b5050505092915050565b60006006610c3783610aaf565b101592915050565b6000808080610c516201518087610a2a565b9187019450925090506000610bec8484610b2a565b6000808080610c786201518087610a2a565b918790039450925090506000610c8e8484610b2a565b905080821115610c9c578091505b62015180870662015180610cb186868661103b565b0201945086851115610c2057600080fd5b610e1081028201828110156107eb57600080fd5b600081603c8402610e10860262015180610cf18b8b8b61103b565b02010101979650505050505050565b600081831115610d0f57600080fd5b500390565b60006108046201518083610a2a565b6201518081028201828110156107eb57600080fd5b600081831115610d4757600080fd5b600080610d576201518086610a2a565b5091509150600080610d6e620151808781610a2a57fe5b50600c9586029590910201939093039190910395945050505050565b603c81028201828110156107eb57600080fd5b603c900690565b818101828110156107eb57600080fd5b6000610dc36201518083610a2a565b50909392505050565b603c81028203828111156107eb57600080fd5b6000610a8d6201518083610a2a565b6000808080610e006201518087610a2a565b91945092509050600c8084028301869003600019019081049350600c810660010192506000610e2f8585610b2a565b905080831115610e3d578092505b62015180880662015180610e5287878761103b565b0201955087861115610e6357600080fd5b505050505092915050565b600060048206158015610e8357506064820615155b806107eb57505061019090061590565b600080610ea36201518084610a2a565b505090506107cd81610e6e565b6201518081028203828111156107eb57600080fd5b600081831115610ed457600080fd5b62015180838303610a15565b60006005610eed83610aaf565b111592915050565b6000808061097e6201518085610a2a565b60008080808080610f1a6201518088610a2a565b91999098919750610e10620151809092068281049750603c9290068281049650919091069350915050565b808203828111156107eb57600080fd5b6000610e108206603c81610a15565b600081831115610f7357600080fd5b6000610f826201518085610a2a565b505090506000610f97620151808581610a2a57fe5b505091909103949350505050565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f8460500281610ffc57fe5b0590506000605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b60006107b284101561104c57600080fd5b838383600062253d8c600460036064611324600c600d19890105890101050205600c80600d19870105600c02600287030361016f028161108857fe5b0560046105b5600c600d1989010589016112c0010205617d4b860301010303905080945050505050939250505056fea2646970667358221220144bfa7ff851a685f881e93c3b88c3dce21cc7d3c01423e087bdfba5b17d290964736f6c63430006000033" -undefined -> -> -undefined -> -RESULT: # Account EtherBalanceChange Token Name -RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- -RESULT: 0 0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e 0.000000000000000000 0.000000000000000000 Account #0 - Miner -RESULT: 1 0xa11aae29840fbb5c86e6fd4cf809eba183aef433 0.000000000000000000 0.000000000000000000 Account #1 - Contract Owner -RESULT: 2 0xa22ab8a9d641ce77e06d98b7d7065d324d3d6976 0.000000000000000000 0.000000000000000000 Account #2 - Alice -RESULT: 3 0xa33a6c312d9ad0e0f2e95541beed0cc081621fd0 0.000000000000000000 0.000000000000000000 Account #3 - Bob -RESULT: 4 0xa44a08d3f6933c69212114bb66e2df1813651844 0.000000000000000000 0.000000000000000000 Account #4 - Carol -RESULT: 5 0xa55a151eb00fded1634d27d1127b4be4627079ea 0.000000000000000000 0.000000000000000000 Account #5 - Dave -RESULT: 6 0xa66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 0.000000000000000000 0.000000000000000000 Account #6 -RESULT: 7 0xa77a2b9d4b1c010a22a7c565dc418cef683dbcec 0.000000000000000000 0.000000000000000000 Account #7 -RESULT: 8 0xa88a05d2b88283ce84c8325760b72a64591279a2 0.000000000000000000 0.000000000000000000 Account #8 -RESULT: 9 0xa99a0ae3354c06b1459fd441a32a3f71005d7da0 0.000000000000000000 0.000000000000000000 Account #9 -RESULT: 10 0xaaaa9de1e6c564446ebca0fd102d8bd92093c756 0.000000000000000000 0.000000000000000000 Account #10 -RESULT: 11 0xabba43e7594e3b76afb157989e93c6621497fd4b 0.000000000000000000 0.000000000000000000 Account #11 -RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- -RESULT: 0.000000000000000000 Total Token Balances -RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- -RESULT: -undefined -> -RESULT: -undefined -> -> -> -undefined -> -undefined -> -undefined -> -RESULT: ----- Deploy DateTime Library ----- -undefined -> -undefined -> -undefined -> -undefined -> -undefined -> -undefined -> -... -...... -......... -............ -............ -............ -............ -............ -............ -............ -............ -......... -...... -... -undefined -> -... -undefined -> -DATA: var dateTimeLibAddress="0x90d8927407c79c4a28ee879b821c76fc9bcc2688"; -DATA: var dateTimeLibAbi=[]; -DATA: var dateTimeLib=eth.contract(dateTimeLibAbi).at(dateTimeLibAddress); -RESULT: # Account EtherBalanceChange Token Name -RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- -RESULT: 0 0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e 0.001150736000000000 0.000000000000000000 Account #0 - Miner -RESULT: 1 0xa11aae29840fbb5c86e6fd4cf809eba183aef433 -0.001150736000000000 0.000000000000000000 Account #1 - Contract Owner -RESULT: 2 0xa22ab8a9d641ce77e06d98b7d7065d324d3d6976 0.000000000000000000 0.000000000000000000 Account #2 - Alice -RESULT: 3 0xa33a6c312d9ad0e0f2e95541beed0cc081621fd0 0.000000000000000000 0.000000000000000000 Account #3 - Bob -RESULT: 4 0xa44a08d3f6933c69212114bb66e2df1813651844 0.000000000000000000 0.000000000000000000 Account #4 - Carol -RESULT: 5 0xa55a151eb00fded1634d27d1127b4be4627079ea 0.000000000000000000 0.000000000000000000 Account #5 - Dave -RESULT: 6 0xa66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 0.000000000000000000 0.000000000000000000 Account #6 -RESULT: 7 0xa77a2b9d4b1c010a22a7c565dc418cef683dbcec 0.000000000000000000 0.000000000000000000 Account #7 -RESULT: 8 0xa88a05d2b88283ce84c8325760b72a64591279a2 0.000000000000000000 0.000000000000000000 Account #8 -RESULT: 9 0xa99a0ae3354c06b1459fd441a32a3f71005d7da0 0.000000000000000000 0.000000000000000000 Account #9 -RESULT: 10 0xaaaa9de1e6c564446ebca0fd102d8bd92093c756 0.000000000000000000 0.000000000000000000 Account #10 -RESULT: 11 0xabba43e7594e3b76afb157989e93c6621497fd4b 0.000000000000000000 0.000000000000000000 Account #11 -RESULT: 12 0x90d8927407c79c4a28ee879b821c76fc9bcc2688 0.000000000000000000 0.000000000000000000 DateTime Library -RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- -RESULT: 0.000000000000000000 Total Token Balances -RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- -RESULT: -undefined -> -RESULT: PASS Deploy DateTime Library -1 -> -RESULT: dateTimeLibTx status=0x1 Success gas=6000000 gasUsed=71921 costETH=0.001150736 costUSD=0.77756382256 @ ETH/USD=675.71 gasPrice=16 gwei block=19 txIx=0 txId=0x3d6e997266a4df7a6d24ad8461a47646aa30ac31435f55bc7f8d22226d67cd14 @ 1579355189 Sat, 18 Jan 2020 13:46:29 UTC -undefined -> -RESULT: -undefined -> -> -> -undefined -> -undefined -> -undefined -> -RESULT: ---------- Deploy TestDateTime Contract ---------- -undefined -> -undefined -> -undefined -> -undefined -> -undefined -> -undefined -> -undefined -> -... -...... -......... -............ -............ -............ -............ -............ -............ -............ -............ -............ -......... -...... -... -undefined -> -... -undefined -> -DATA: var testDateTimeAddress="0x0e946b999033257976aa5cbe0e3530618ca1582d"; -DATA: var testDateTimeAbi=[{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"_getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"name":"_isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"addDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"addHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"addMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"addMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"addSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"addYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffDays","outputs":[{"internalType":"uint256","name":"_days","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffHours","outputs":[{"internalType":"uint256","name":"_hours","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMinutes","outputs":[{"internalType":"uint256","name":"_minutes","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffMonths","outputs":[{"internalType":"uint256","name":"_months","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffSeconds","outputs":[{"internalType":"uint256","name":"_seconds","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"name":"diffYears","outputs":[{"internalType":"uint256","name":"_years","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDay","outputs":[{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDayOfWeek","outputs":[{"internalType":"uint256","name":"dayOfWeek","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getDaysInMonth","outputs":[{"internalType":"uint256","name":"daysInMonth","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getHour","outputs":[{"internalType":"uint256","name":"hour","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMinute","outputs":[{"internalType":"uint256","name":"minute","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getMonth","outputs":[{"internalType":"uint256","name":"month","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getSecond","outputs":[{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getYear","outputs":[{"internalType":"uint256","name":"year","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isLeapYear","outputs":[{"internalType":"bool","name":"leapYear","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"isValidDate","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"isValidDateTime","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekDay","outputs":[{"internalType":"bool","name":"weekDay","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"isWeekEnd","outputs":[{"internalType":"bool","name":"weekEnd","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nextYear","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"subDays","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_hours","type":"uint256"}],"name":"subHours","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"subMinutes","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_months","type":"uint256"}],"name":"subMonths","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_seconds","type":"uint256"}],"name":"subSeconds","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"_years","type":"uint256"}],"name":"subYears","outputs":[{"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"test","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"timestampFromDate","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"name":"timestampFromDateTime","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDate","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"timestampToDateTime","outputs":[{"internalType":"uint256","name":"year","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"hour","type":"uint256"},{"internalType":"uint256","name":"minute","type":"uint256"},{"internalType":"uint256","name":"second","type":"uint256"}],"stateMutability":"pure","type":"function"}]; -DATA: var testDateTime=eth.contract(testDateTimeAbi).at(testDateTimeAddress); -DATA: console.log("testDateTime=" + JSON.stringify(testDateTime)); -RESULT: # Account EtherBalanceChange Token Name -RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- -RESULT: 0 0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e 0.016965312000000000 0.000000000000000000 Account #0 - Miner -RESULT: 1 0xa11aae29840fbb5c86e6fd4cf809eba183aef433 -0.016965312000000000 0.000000000000000000 Account #1 - Contract Owner -RESULT: 2 0xa22ab8a9d641ce77e06d98b7d7065d324d3d6976 0.000000000000000000 0.000000000000000000 Account #2 - Alice -RESULT: 3 0xa33a6c312d9ad0e0f2e95541beed0cc081621fd0 0.000000000000000000 0.000000000000000000 Account #3 - Bob -RESULT: 4 0xa44a08d3f6933c69212114bb66e2df1813651844 0.000000000000000000 0.000000000000000000 Account #4 - Carol -RESULT: 5 0xa55a151eb00fded1634d27d1127b4be4627079ea 0.000000000000000000 0.000000000000000000 Account #5 - Dave -RESULT: 6 0xa66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 0.000000000000000000 0.000000000000000000 Account #6 -RESULT: 7 0xa77a2b9d4b1c010a22a7c565dc418cef683dbcec 0.000000000000000000 0.000000000000000000 Account #7 -RESULT: 8 0xa88a05d2b88283ce84c8325760b72a64591279a2 0.000000000000000000 0.000000000000000000 Account #8 -RESULT: 9 0xa99a0ae3354c06b1459fd441a32a3f71005d7da0 0.000000000000000000 0.000000000000000000 Account #9 -RESULT: 10 0xaaaa9de1e6c564446ebca0fd102d8bd92093c756 0.000000000000000000 0.000000000000000000 Account #10 -RESULT: 11 0xabba43e7594e3b76afb157989e93c6621497fd4b 0.000000000000000000 0.000000000000000000 Account #11 -RESULT: 12 0x90d8927407c79c4a28ee879b821c76fc9bcc2688 0.000000000000000000 0.000000000000000000 DateTime Library -RESULT: 13 0x0e946b999033257976aa5cbe0e3530618ca1582d 0.000000000000000000 0.000000000000000000 TestDateTime -RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- -RESULT: 0.000000000000000000 Total Token Balances -RESULT: -- ------------------------------------------ --------------------------- ------------------------------ --------------------------- -RESULT: -undefined -> -RESULT: PASS Deploy TestDateTime Contract -1 -> -RESULT: testDateTimeAddress=0x0e946b999033257976aa5cbe0e3530618ca1582d status=0x1 Success gas=6000000 gasUsed=988411 costETH=0.015814576 costUSD=10.68606714896 @ ETH/USD=675.71 gasPrice=16 gwei block=21 txIx=0 txId=0xdb67f4d0ee1587cd570fc563c69f73dcaffc9f2f4047a1d1792218bb920fbd58 @ 1579355191 Sat, 18 Jan 2020 13:46:31 UTC -undefined -> -RESULT: -undefined -> -> -undefined -> -undefined -> -undefined -> -undefined -> -undefined -> -undefined -> -> -... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -RESULT: ---------- Test isLeapYear ---------- -RESULT: PASS 2000,5,24,1,2,3 is a leap year -RESULT: PASS 2100,5,24,1,2,3 is a not leap year -RESULT: PASS 2104,5,24,1,2,3 is a leap year -RESULT: -undefined -> -> -... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -... -RESULT: ---------- Test isValidDate and isValidDateTime.call ---------- -RESULT: PASS testDateTime.isValidDate.call(1969, 1, 1) is false -RESULT: PASS testDateTime.isValidDate.call(1970, 1, 1) is true -RESULT: PASS testDateTime.isValidDate.call(2000, 2, 29) is true -RESULT: PASS testDateTime.isValidDate.call(2001, 2, 29) is false -RESULT: PASS testDateTime.isValidDate.call(2001, 0, 1) is false -RESULT: PASS testDateTime.isValidDate.call(2001, 1, 0) is false -RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 0, 0, 0) is true -RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 1) is true -RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 23, 1, 1) is true -RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 24, 1, 1) is false -RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 59, 1) is true -RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 60, 1) is false -RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 59) is true -RESULT: PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 60) is false -RESULT: -undefined -> -> -... -... -...... -...... -... -...... -...... -... -...... -...... -... -... -RESULT: ---------- Test _isLeapYear ---------- -RESULT: PASS 2000 is a leap year -RESULT: PASS 2100 is a not leap year -RESULT: PASS 2104 is a leap year -RESULT: -undefined -> -> -... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -RESULT: ---------- Test isWeekDay ---------- -RESULT: PASS 2018,5,24,1,2,3 is a week day -RESULT: PASS 2018,5,25,1,2,3 is a week day -RESULT: PASS 2018,5,26,1,2,3 is a not week day -RESULT: -undefined -> -> -... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -RESULT: ---------- Test isWeekEnd ---------- -RESULT: PASS 2018,5,24,1,2,3 is a not a week end -RESULT: PASS 2018,5,25,1,2,3 is a not a week end -RESULT: PASS 2018,5,26,1,2,3 is a week end -RESULT: PASS 2018,5,27,1,2,3 is a week end -RESULT: -undefined -> -> -> -... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -RESULT: ---------- Test getDaysInMonth ---------- -RESULT: PASS 2000,1,24,1,2,3 has 31 days -RESULT: PASS 2000,2,24,1,2,3 has 29 days -RESULT: PASS 2001,2,24,1,2,3 has 28 days -RESULT: PASS 2000,3,24,1,2,3 has 31 days -RESULT: PASS 2000,4,24,1,2,3 has 30 days -RESULT: PASS 2000,5,24,1,2,3 has 31 days -RESULT: PASS 2000,6,24,1,2,3 has 30 days -RESULT: PASS 2000,7,24,1,2,3 has 31 days -RESULT: PASS 2000,8,24,1,2,3 has 31 days -RESULT: PASS 2000,9,24,1,2,3 has 30 days -RESULT: PASS 2000,10,24,1,2,3 has 31 days -RESULT: PASS 2000,11,24,1,2,3 has 30 days -RESULT: PASS 2000,12,24,1,2,3 has 31 days -RESULT: -undefined -> -> -> -... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -... -RESULT: ---------- Test _getDaysInMonth ---------- -RESULT: PASS 2000/01 has 31 days -RESULT: PASS 2000/02 has 29 days -RESULT: PASS 2001/02 has 28 days -RESULT: PASS 2000/03 has 31 days -RESULT: PASS 2000/04 has 30 days -RESULT: PASS 2000/05 has 31 days -RESULT: PASS 2000/06 has 30 days -RESULT: PASS 2000/07 has 31 days -RESULT: PASS 2000/08 has 31 days -RESULT: PASS 2000/09 has 30 days -RESULT: PASS 2000/10 has 31 days -RESULT: PASS 2000/11 has 30 days -RESULT: PASS 2000/12 has 31 days -RESULT: -undefined -> -> -> -... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -...... -...... -... -... -RESULT: ---------- Test getDayOfWeek ---------- -RESULT: PASS 2018,5,21,1,2,3 is 1 Monday -RESULT: PASS 2018,5,24,1,2,3 is 4 Thursday -RESULT: PASS 2018,5,26,1,2,3 is 6 Saturday -RESULT: PASS 2018,5,27,1,2,3 is 7 Sunday -RESULT: -undefined -> -> -> -... -... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -... -RESULT: ---------- Test get* ---------- -RESULT: PASS 2018,5,21,1,2,3 year is 2018 -RESULT: PASS 2018,5,21,1,2,3 month is 5 May -RESULT: PASS 2018,5,21,1,2,3 day is 21 -RESULT: PASS 2018,5,21,1,2,3 hour is 1 -RESULT: PASS 2018,5,21,1,2,3 minute is 2 -RESULT: PASS 2018,5,21,1,2,3 second is 3 -RESULT: -undefined -> -> -... -... -... -... -... -...... -...... -... -... -... -... -...... -...... -... -... -... -... -...... -...... -... -... -... -... -...... -...... -... -... -... -... -...... -...... -... -... -... -... -...... -...... -... -... -... -... -...... -...... -... -... -... -... -...... -...... -... -... -RESULT: ---------- Test add{Years|Months|Days|Hours|Minutes|Seconds} ---------- -RESULT: PASS 2000,2,29,1,2,3 + 3 years is 2003/02/28 01:02:03 -RESULT: PASS 2018,12,31,2,3,4 + 30 years is 2048/12/31 02:03:04 -RESULT: PASS 2000,1,31,1,2,3 + 37 months is 2003/02/28 01:02:03 -RESULT: PASS 2018,12,1,2,3,4 + 362 months is 2049/02/01 02:03:04 -RESULT: PASS 2017,1,31,1,2,3 + 37,532 days is 2119/11/05 01:02:03 -RESULT: PASS 2017,1,31,1,2,3 + 900,768 hours is 2119/11/05 01:02:03 -RESULT: PASS 2017,1,31,1,2,3 + 781,920 minutes is 2018/07/28 01:02:03 -RESULT: PASS 2017,1,31,1,2,3 + 461,548,800 seconds is 2031/09/17 01:02:03 -RESULT: -undefined -> -> -... -... -... -... -... -...... -...... -... -... -... -... -...... -...... -... -... -... -... -...... -...... -... -... -... -... -...... -...... -... -... -... -... -...... -...... -... -... -... -... -...... -...... -... -... -... -... -...... -...... -... -... -RESULT: ---------- Test sub{Years|Months|Days|Hours|Minutes|Seconds} ---------- -RESULT: PASS 2000,2,29,1,2,3 - 3 years is 1997/02/28 01:02:03 -RESULT: PASS 2000,2,29,1,2,3 - 37 months is 1997/01/29 01:02:03 -RESULT: PASS 2013,1,1,1,2,3 - 3,756 days is 2002/09/20 01:02:03 -RESULT: PASS 2013,1,1,1,2,3 - 3,756 * 24 hours is 2002/09/20 01:02:03 -RESULT: PASS 2015,7,15,1,2,3 - 223,776 hours is 1990/01/03 01:02:03 -RESULT: PASS 2018,3,1,2,3,4 - 21,600,000 minutes is 1977/02/04 02:03:04 -RESULT: PASS 2020,3,19,3,4,5 - 788,227,200 seconds is 1995/03/28 03:04:05 -RESULT: -undefined -> -> -... -... -... -... -... -... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -...... -...... -... -... -RESULT: ---------- Test diff{Years|Months|Days|Hours|Minutes|Seconds} ---------- -RESULT: fromTimestamp=1508547723 2017,10,21,1,2,3 -RESULT: toTimestamp=1563422706 2019,7,18,4,5,6 -RESULT: PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 2 years diff -RESULT: PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 21 months diff -RESULT: PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 635 days diff -RESULT: PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 15,243 hours diff -RESULT: PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 914,583 minutes diff -RESULT: PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 54,874,983 seconds diff -RESULT: -undefined -> -> -... -... -... -... -... -... -... -... -... -... -... -... -... -...... -...... -......... -......... -...... -...... -...... -...... -...... -...... -...... -......... -...... -...... -......... -......... -......... -......... -......... -......... -...... -......... -......... -......... -......... -......... -...... -...... -... -RESULT: ---------- Test timestampToDateTime.call(...) and timestampFromDateTime.call(...) against JavaScript Date ---------- -RESULT: timestampToDateTime.call(48611)=["1970","1","1","13","30","11"] -RESULT: timestampFromDateTime.call(["1970","1","1","13","30","11"])=48611 -RESULT: jsDate(48611)=1970/1/1 13:30:11 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(48611) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(32096934)=["1971","1","7","11","48","54"] -RESULT: timestampFromDateTime.call(["1971","1","7","11","48","54"])=32096934 -RESULT: jsDate(32096934)=1971/1/7 11:48:54 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(32096934) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(64145254)=["1972","1","13","10","7","34"] -RESULT: timestampFromDateTime.call(["1972","1","13","10","7","34"])=64145254 -RESULT: jsDate(64145254)=1972/1/13 10:7:34 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(64145254) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(95729869)=["1973","1","12","23","37","49"] -RESULT: timestampFromDateTime.call(["1973","1","12","23","37","49"])=95729869 -RESULT: jsDate(95729869)=1973/1/12 23:37:49 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(95729869) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(127778192)=["1974","1","18","21","56","32"] -RESULT: timestampFromDateTime.call(["1974","1","18","21","56","32"])=127778192 -RESULT: jsDate(127778192)=1974/1/18 21:56:32 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(127778192) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(159826516)=["1975","1","24","20","15","16"] -RESULT: timestampFromDateTime.call(["1975","1","24","20","15","16"])=159826516 -RESULT: jsDate(159826516)=1975/1/24 20:15:16 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(159826516) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(191411131)=["1976","1","25","9","45","31"] -RESULT: timestampFromDateTime.call(["1976","1","25","9","45","31"])=191411131 -RESULT: jsDate(191411131)=1976/1/25 9:45:31 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(191411131) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(223459454)=["1977","1","30","8","4","14"] -RESULT: timestampFromDateTime.call(["1977","1","30","8","4","14"])=223459454 -RESULT: jsDate(223459454)=1977/1/30 8:4:14 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(223459454) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(255507778)=["1978","2","5","6","22","58"] -RESULT: timestampFromDateTime.call(["1978","2","5","6","22","58"])=255507778 -RESULT: jsDate(255507778)=1978/2/5 6:22:58 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(255507778) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(287092393)=["1979","2","5","19","53","13"] -RESULT: timestampFromDateTime.call(["1979","2","5","19","53","13"])=287092393 -RESULT: jsDate(287092393)=1979/2/5 19:53:13 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(287092393) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(319140716)=["1980","2","11","18","11","56"] -RESULT: timestampFromDateTime.call(["1980","2","11","18","11","56"])=319140716 -RESULT: jsDate(319140716)=1980/2/11 18:11:56 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(319140716) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(351189040)=["1981","2","16","16","30","40"] -RESULT: timestampFromDateTime.call(["1981","2","16","16","30","40"])=351189040 -RESULT: jsDate(351189040)=1981/2/16 16:30:40 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(351189040) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(382773655)=["1982","2","17","6","0","55"] -RESULT: timestampFromDateTime.call(["1982","2","17","6","0","55"])=382773655 -RESULT: jsDate(382773655)=1982/2/17 6:0:55 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(382773655) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(414821978)=["1983","2","23","4","19","38"] -RESULT: timestampFromDateTime.call(["1983","2","23","4","19","38"])=414821978 -RESULT: jsDate(414821978)=1983/2/23 4:19:38 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(414821978) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(446870302)=["1984","2","29","2","38","22"] -RESULT: timestampFromDateTime.call(["1984","2","29","2","38","22"])=446870302 -RESULT: jsDate(446870302)=1984/2/29 2:38:22 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(446870302) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(478454917)=["1985","2","28","16","8","37"] -RESULT: timestampFromDateTime.call(["1985","2","28","16","8","37"])=478454917 -RESULT: jsDate(478454917)=1985/2/28 16:8:37 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(478454917) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(510503240)=["1986","3","6","14","27","20"] -RESULT: timestampFromDateTime.call(["1986","3","6","14","27","20"])=510503240 -RESULT: jsDate(510503240)=1986/3/6 14:27:20 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(510503240) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(542551564)=["1987","3","12","12","46","4"] -RESULT: timestampFromDateTime.call(["1987","3","12","12","46","4"])=542551564 -RESULT: jsDate(542551564)=1987/3/12 12:46:4 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(542551564) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(574136179)=["1988","3","12","2","16","19"] -RESULT: timestampFromDateTime.call(["1988","3","12","2","16","19"])=574136179 -RESULT: jsDate(574136179)=1988/3/12 2:16:19 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(574136179) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(606184502)=["1989","3","18","0","35","2"] -RESULT: timestampFromDateTime.call(["1989","3","18","0","35","2"])=606184502 -RESULT: jsDate(606184502)=1989/3/18 0:35:2 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(606184502) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(638232826)=["1990","3","23","22","53","46"] -RESULT: timestampFromDateTime.call(["1990","3","23","22","53","46"])=638232826 -RESULT: jsDate(638232826)=1990/3/23 22:53:46 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(638232826) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(669817441)=["1991","3","24","12","24","1"] -RESULT: timestampFromDateTime.call(["1991","3","24","12","24","1"])=669817441 -RESULT: jsDate(669817441)=1991/3/24 12:24:1 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(669817441) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(701865764)=["1992","3","29","10","42","44"] -RESULT: timestampFromDateTime.call(["1992","3","29","10","42","44"])=701865764 -RESULT: jsDate(701865764)=1992/3/29 10:42:44 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(701865764) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(733914088)=["1993","4","4","9","1","28"] -RESULT: timestampFromDateTime.call(["1993","4","4","9","1","28"])=733914088 -RESULT: jsDate(733914088)=1993/4/4 9:1:28 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(733914088) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(765498703)=["1994","4","4","22","31","43"] -RESULT: timestampFromDateTime.call(["1994","4","4","22","31","43"])=765498703 -RESULT: jsDate(765498703)=1994/4/4 22:31:43 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(765498703) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(797547026)=["1995","4","10","20","50","26"] -RESULT: timestampFromDateTime.call(["1995","4","10","20","50","26"])=797547026 -RESULT: jsDate(797547026)=1995/4/10 20:50:26 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(797547026) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(829595350)=["1996","4","15","19","9","10"] -RESULT: timestampFromDateTime.call(["1996","4","15","19","9","10"])=829595350 -RESULT: jsDate(829595350)=1996/4/15 19:9:10 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(829595350) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(861179965)=["1997","4","16","8","39","25"] -RESULT: timestampFromDateTime.call(["1997","4","16","8","39","25"])=861179965 -RESULT: jsDate(861179965)=1997/4/16 8:39:25 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(861179965) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(893228288)=["1998","4","22","6","58","8"] -RESULT: timestampFromDateTime.call(["1998","4","22","6","58","8"])=893228288 -RESULT: jsDate(893228288)=1998/4/22 6:58:8 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(893228288) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(925276612)=["1999","4","28","5","16","52"] -RESULT: timestampFromDateTime.call(["1999","4","28","5","16","52"])=925276612 -RESULT: jsDate(925276612)=1999/4/28 5:16:52 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(925276612) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(956861227)=["2000","4","27","18","47","7"] -RESULT: timestampFromDateTime.call(["2000","4","27","18","47","7"])=956861227 -RESULT: jsDate(956861227)=2000/4/27 18:47:7 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(956861227) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(988909550)=["2001","5","3","17","5","50"] -RESULT: timestampFromDateTime.call(["2001","5","3","17","5","50"])=988909550 -RESULT: jsDate(988909550)=2001/5/3 17:5:50 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(988909550) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1020957874)=["2002","5","9","15","24","34"] -RESULT: timestampFromDateTime.call(["2002","5","9","15","24","34"])=1020957874 -RESULT: jsDate(1020957874)=2002/5/9 15:24:34 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1020957874) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1052542489)=["2003","5","10","4","54","49"] -RESULT: timestampFromDateTime.call(["2003","5","10","4","54","49"])=1052542489 -RESULT: jsDate(1052542489)=2003/5/10 4:54:49 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1052542489) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1084590812)=["2004","5","15","3","13","32"] -RESULT: timestampFromDateTime.call(["2004","5","15","3","13","32"])=1084590812 -RESULT: jsDate(1084590812)=2004/5/15 3:13:32 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1084590812) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1116639136)=["2005","5","21","1","32","16"] -RESULT: timestampFromDateTime.call(["2005","5","21","1","32","16"])=1116639136 -RESULT: jsDate(1116639136)=2005/5/21 1:32:16 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1116639136) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1148223751)=["2006","5","21","15","2","31"] -RESULT: timestampFromDateTime.call(["2006","5","21","15","2","31"])=1148223751 -RESULT: jsDate(1148223751)=2006/5/21 15:2:31 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1148223751) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1180272074)=["2007","5","27","13","21","14"] -RESULT: timestampFromDateTime.call(["2007","5","27","13","21","14"])=1180272074 -RESULT: jsDate(1180272074)=2007/5/27 13:21:14 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1180272074) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1212320398)=["2008","6","1","11","39","58"] -RESULT: timestampFromDateTime.call(["2008","6","1","11","39","58"])=1212320398 -RESULT: jsDate(1212320398)=2008/6/1 11:39:58 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1212320398) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1243905013)=["2009","6","2","1","10","13"] -RESULT: timestampFromDateTime.call(["2009","6","2","1","10","13"])=1243905013 -RESULT: jsDate(1243905013)=2009/6/2 1:10:13 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1243905013) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1275953336)=["2010","6","7","23","28","56"] -RESULT: timestampFromDateTime.call(["2010","6","7","23","28","56"])=1275953336 -RESULT: jsDate(1275953336)=2010/6/7 23:28:56 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1275953336) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1308001660)=["2011","6","13","21","47","40"] -RESULT: timestampFromDateTime.call(["2011","6","13","21","47","40"])=1308001660 -RESULT: jsDate(1308001660)=2011/6/13 21:47:40 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1308001660) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1339586275)=["2012","6","13","11","17","55"] -RESULT: timestampFromDateTime.call(["2012","6","13","11","17","55"])=1339586275 -RESULT: jsDate(1339586275)=2012/6/13 11:17:55 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1339586275) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1371634598)=["2013","6","19","9","36","38"] -RESULT: timestampFromDateTime.call(["2013","6","19","9","36","38"])=1371634598 -RESULT: jsDate(1371634598)=2013/6/19 9:36:38 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1371634598) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1403682922)=["2014","6","25","7","55","22"] -RESULT: timestampFromDateTime.call(["2014","6","25","7","55","22"])=1403682922 -RESULT: jsDate(1403682922)=2014/6/25 7:55:22 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1403682922) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1435267537)=["2015","6","25","21","25","37"] -RESULT: timestampFromDateTime.call(["2015","6","25","21","25","37"])=1435267537 -RESULT: jsDate(1435267537)=2015/6/25 21:25:37 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1435267537) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1467315860)=["2016","6","30","19","44","20"] -RESULT: timestampFromDateTime.call(["2016","6","30","19","44","20"])=1467315860 -RESULT: jsDate(1467315860)=2016/6/30 19:44:20 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1467315860) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1499364184)=["2017","7","6","18","3","4"] -RESULT: timestampFromDateTime.call(["2017","7","6","18","3","4"])=1499364184 -RESULT: jsDate(1499364184)=2017/7/6 18:3:4 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1499364184) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1530948799)=["2018","7","7","7","33","19"] -RESULT: timestampFromDateTime.call(["2018","7","7","7","33","19"])=1530948799 -RESULT: jsDate(1530948799)=2018/7/7 7:33:19 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1530948799) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1562997122)=["2019","7","13","5","52","2"] -RESULT: timestampFromDateTime.call(["2019","7","13","5","52","2"])=1562997122 -RESULT: jsDate(1562997122)=2019/7/13 5:52:2 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1562997122) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1595045446)=["2020","7","18","4","10","46"] -RESULT: timestampFromDateTime.call(["2020","7","18","4","10","46"])=1595045446 -RESULT: jsDate(1595045446)=2020/7/18 4:10:46 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1595045446) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1626630061)=["2021","7","18","17","41","1"] -RESULT: timestampFromDateTime.call(["2021","7","18","17","41","1"])=1626630061 -RESULT: jsDate(1626630061)=2021/7/18 17:41:1 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1626630061) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1658678384)=["2022","7","24","15","59","44"] -RESULT: timestampFromDateTime.call(["2022","7","24","15","59","44"])=1658678384 -RESULT: jsDate(1658678384)=2022/7/24 15:59:44 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1658678384) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1690726708)=["2023","7","30","14","18","28"] -RESULT: timestampFromDateTime.call(["2023","7","30","14","18","28"])=1690726708 -RESULT: jsDate(1690726708)=2023/7/30 14:18:28 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1690726708) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1722311323)=["2024","7","30","3","48","43"] -RESULT: timestampFromDateTime.call(["2024","7","30","3","48","43"])=1722311323 -RESULT: jsDate(1722311323)=2024/7/30 3:48:43 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1722311323) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1754359646)=["2025","8","5","2","7","26"] -RESULT: timestampFromDateTime.call(["2025","8","5","2","7","26"])=1754359646 -RESULT: jsDate(1754359646)=2025/8/5 2:7:26 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1754359646) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1786407970)=["2026","8","11","0","26","10"] -RESULT: timestampFromDateTime.call(["2026","8","11","0","26","10"])=1786407970 -RESULT: jsDate(1786407970)=2026/8/11 0:26:10 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1786407970) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1817992585)=["2027","8","11","13","56","25"] -RESULT: timestampFromDateTime.call(["2027","8","11","13","56","25"])=1817992585 -RESULT: jsDate(1817992585)=2027/8/11 13:56:25 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1817992585) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1850040908)=["2028","8","16","12","15","8"] -RESULT: timestampFromDateTime.call(["2028","8","16","12","15","8"])=1850040908 -RESULT: jsDate(1850040908)=2028/8/16 12:15:8 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1850040908) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1882089232)=["2029","8","22","10","33","52"] -RESULT: timestampFromDateTime.call(["2029","8","22","10","33","52"])=1882089232 -RESULT: jsDate(1882089232)=2029/8/22 10:33:52 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1882089232) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1913673847)=["2030","8","23","0","4","7"] -RESULT: timestampFromDateTime.call(["2030","8","23","0","4","7"])=1913673847 -RESULT: jsDate(1913673847)=2030/8/23 0:4:7 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1913673847) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1945722170)=["2031","8","28","22","22","50"] -RESULT: timestampFromDateTime.call(["2031","8","28","22","22","50"])=1945722170 -RESULT: jsDate(1945722170)=2031/8/28 22:22:50 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1945722170) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(1977770494)=["2032","9","2","20","41","34"] -RESULT: timestampFromDateTime.call(["2032","9","2","20","41","34"])=1977770494 -RESULT: jsDate(1977770494)=2032/9/2 20:41:34 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(1977770494) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2009355109)=["2033","9","3","10","11","49"] -RESULT: timestampFromDateTime.call(["2033","9","3","10","11","49"])=2009355109 -RESULT: jsDate(2009355109)=2033/9/3 10:11:49 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2009355109) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2041403432)=["2034","9","9","8","30","32"] -RESULT: timestampFromDateTime.call(["2034","9","9","8","30","32"])=2041403432 -RESULT: jsDate(2041403432)=2034/9/9 8:30:32 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2041403432) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2073451756)=["2035","9","15","6","49","16"] -RESULT: timestampFromDateTime.call(["2035","9","15","6","49","16"])=2073451756 -RESULT: jsDate(2073451756)=2035/9/15 6:49:16 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2073451756) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2105036371)=["2036","9","14","20","19","31"] -RESULT: timestampFromDateTime.call(["2036","9","14","20","19","31"])=2105036371 -RESULT: jsDate(2105036371)=2036/9/14 20:19:31 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2105036371) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2137084694)=["2037","9","20","18","38","14"] -RESULT: timestampFromDateTime.call(["2037","9","20","18","38","14"])=2137084694 -RESULT: jsDate(2137084694)=2037/9/20 18:38:14 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2137084694) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2169133018)=["2038","9","26","16","56","58"] -RESULT: timestampFromDateTime.call(["2038","9","26","16","56","58"])=2169133018 -RESULT: jsDate(2169133018)=2038/9/26 16:56:58 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2169133018) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2200717633)=["2039","9","27","6","27","13"] -RESULT: timestampFromDateTime.call(["2039","9","27","6","27","13"])=2200717633 -RESULT: jsDate(2200717633)=2039/9/27 6:27:13 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2200717633) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2232765956)=["2040","10","2","4","45","56"] -RESULT: timestampFromDateTime.call(["2040","10","2","4","45","56"])=2232765956 -RESULT: jsDate(2232765956)=2040/10/2 4:45:56 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2232765956) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2264814280)=["2041","10","8","3","4","40"] -RESULT: timestampFromDateTime.call(["2041","10","8","3","4","40"])=2264814280 -RESULT: jsDate(2264814280)=2041/10/8 3:4:40 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2264814280) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2296398895)=["2042","10","8","16","34","55"] -RESULT: timestampFromDateTime.call(["2042","10","8","16","34","55"])=2296398895 -RESULT: jsDate(2296398895)=2042/10/8 16:34:55 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2296398895) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2328447218)=["2043","10","14","14","53","38"] -RESULT: timestampFromDateTime.call(["2043","10","14","14","53","38"])=2328447218 -RESULT: jsDate(2328447218)=2043/10/14 14:53:38 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2328447218) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2360495542)=["2044","10","19","13","12","22"] -RESULT: timestampFromDateTime.call(["2044","10","19","13","12","22"])=2360495542 -RESULT: jsDate(2360495542)=2044/10/19 13:12:22 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2360495542) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2392080157)=["2045","10","20","2","42","37"] -RESULT: timestampFromDateTime.call(["2045","10","20","2","42","37"])=2392080157 -RESULT: jsDate(2392080157)=2045/10/20 2:42:37 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2392080157) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2424128480)=["2046","10","26","1","1","20"] -RESULT: timestampFromDateTime.call(["2046","10","26","1","1","20"])=2424128480 -RESULT: jsDate(2424128480)=2046/10/26 1:1:20 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2424128480) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2456176804)=["2047","10","31","23","20","4"] -RESULT: timestampFromDateTime.call(["2047","10","31","23","20","4"])=2456176804 -RESULT: jsDate(2456176804)=2047/10/31 23:20:4 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2456176804) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2487761419)=["2048","10","31","12","50","19"] -RESULT: timestampFromDateTime.call(["2048","10","31","12","50","19"])=2487761419 -RESULT: jsDate(2487761419)=2048/10/31 12:50:19 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2487761419) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2519809742)=["2049","11","6","11","9","2"] -RESULT: timestampFromDateTime.call(["2049","11","6","11","9","2"])=2519809742 -RESULT: jsDate(2519809742)=2049/11/6 11:9:2 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2519809742) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2551858066)=["2050","11","12","9","27","46"] -RESULT: timestampFromDateTime.call(["2050","11","12","9","27","46"])=2551858066 -RESULT: jsDate(2551858066)=2050/11/12 9:27:46 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2551858066) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2583442681)=["2051","11","12","22","58","1"] -RESULT: timestampFromDateTime.call(["2051","11","12","22","58","1"])=2583442681 -RESULT: jsDate(2583442681)=2051/11/12 22:58:1 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2583442681) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2615491004)=["2052","11","17","21","16","44"] -RESULT: timestampFromDateTime.call(["2052","11","17","21","16","44"])=2615491004 -RESULT: jsDate(2615491004)=2052/11/17 21:16:44 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2615491004) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2647539328)=["2053","11","23","19","35","28"] -RESULT: timestampFromDateTime.call(["2053","11","23","19","35","28"])=2647539328 -RESULT: jsDate(2647539328)=2053/11/23 19:35:28 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2647539328) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2679123943)=["2054","11","24","9","5","43"] -RESULT: timestampFromDateTime.call(["2054","11","24","9","5","43"])=2679123943 -RESULT: jsDate(2679123943)=2054/11/24 9:5:43 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2679123943) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2711172266)=["2055","11","30","7","24","26"] -RESULT: timestampFromDateTime.call(["2055","11","30","7","24","26"])=2711172266 -RESULT: jsDate(2711172266)=2055/11/30 7:24:26 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2711172266) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2743220590)=["2056","12","5","5","43","10"] -RESULT: timestampFromDateTime.call(["2056","12","5","5","43","10"])=2743220590 -RESULT: jsDate(2743220590)=2056/12/5 5:43:10 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2743220590) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2774805205)=["2057","12","5","19","13","25"] -RESULT: timestampFromDateTime.call(["2057","12","5","19","13","25"])=2774805205 -RESULT: jsDate(2774805205)=2057/12/5 19:13:25 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2774805205) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2806853528)=["2058","12","11","17","32","8"] -RESULT: timestampFromDateTime.call(["2058","12","11","17","32","8"])=2806853528 -RESULT: jsDate(2806853528)=2058/12/11 17:32:8 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2806853528) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2838901852)=["2059","12","17","15","50","52"] -RESULT: timestampFromDateTime.call(["2059","12","17","15","50","52"])=2838901852 -RESULT: jsDate(2838901852)=2059/12/17 15:50:52 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2838901852) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2870486467)=["2060","12","17","5","21","7"] -RESULT: timestampFromDateTime.call(["2060","12","17","5","21","7"])=2870486467 -RESULT: jsDate(2870486467)=2060/12/17 5:21:7 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2870486467) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2902534790)=["2061","12","23","3","39","50"] -RESULT: timestampFromDateTime.call(["2061","12","23","3","39","50"])=2902534790 -RESULT: jsDate(2902534790)=2061/12/23 3:39:50 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2902534790) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2934583114)=["2062","12","29","1","58","34"] -RESULT: timestampFromDateTime.call(["2062","12","29","1","58","34"])=2934583114 -RESULT: jsDate(2934583114)=2062/12/29 1:58:34 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2934583114) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2966167729)=["2063","12","29","15","28","49"] -RESULT: timestampFromDateTime.call(["2063","12","29","15","28","49"])=2966167729 -RESULT: jsDate(2966167729)=2063/12/29 15:28:49 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2966167729) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(2998216052)=["2065","1","3","13","47","32"] -RESULT: timestampFromDateTime.call(["2065","1","3","13","47","32"])=2998216052 -RESULT: jsDate(2998216052)=2065/1/3 13:47:32 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(2998216052) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3030264376)=["2066","1","9","12","6","16"] -RESULT: timestampFromDateTime.call(["2066","1","9","12","6","16"])=3030264376 -RESULT: jsDate(3030264376)=2066/1/9 12:6:16 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3030264376) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3061848991)=["2067","1","10","1","36","31"] -RESULT: timestampFromDateTime.call(["2067","1","10","1","36","31"])=3061848991 -RESULT: jsDate(3061848991)=2067/1/10 1:36:31 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3061848991) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3093897314)=["2068","1","15","23","55","14"] -RESULT: timestampFromDateTime.call(["2068","1","15","23","55","14"])=3093897314 -RESULT: jsDate(3093897314)=2068/1/15 23:55:14 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3093897314) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3125945638)=["2069","1","20","22","13","58"] -RESULT: timestampFromDateTime.call(["2069","1","20","22","13","58"])=3125945638 -RESULT: jsDate(3125945638)=2069/1/20 22:13:58 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3125945638) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3157530253)=["2070","1","21","11","44","13"] -RESULT: timestampFromDateTime.call(["2070","1","21","11","44","13"])=3157530253 -RESULT: jsDate(3157530253)=2070/1/21 11:44:13 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3157530253) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3189578576)=["2071","1","27","10","2","56"] -RESULT: timestampFromDateTime.call(["2071","1","27","10","2","56"])=3189578576 -RESULT: jsDate(3189578576)=2071/1/27 10:2:56 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3189578576) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3221626900)=["2072","2","2","8","21","40"] -RESULT: timestampFromDateTime.call(["2072","2","2","8","21","40"])=3221626900 -RESULT: jsDate(3221626900)=2072/2/2 8:21:40 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3221626900) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3253211515)=["2073","2","1","21","51","55"] -RESULT: timestampFromDateTime.call(["2073","2","1","21","51","55"])=3253211515 -RESULT: jsDate(3253211515)=2073/2/1 21:51:55 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3253211515) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3285259838)=["2074","2","7","20","10","38"] -RESULT: timestampFromDateTime.call(["2074","2","7","20","10","38"])=3285259838 -RESULT: jsDate(3285259838)=2074/2/7 20:10:38 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3285259838) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3317308162)=["2075","2","13","18","29","22"] -RESULT: timestampFromDateTime.call(["2075","2","13","18","29","22"])=3317308162 -RESULT: jsDate(3317308162)=2075/2/13 18:29:22 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3317308162) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3348892777)=["2076","2","14","7","59","37"] -RESULT: timestampFromDateTime.call(["2076","2","14","7","59","37"])=3348892777 -RESULT: jsDate(3348892777)=2076/2/14 7:59:37 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3348892777) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3380941100)=["2077","2","19","6","18","20"] -RESULT: timestampFromDateTime.call(["2077","2","19","6","18","20"])=3380941100 -RESULT: jsDate(3380941100)=2077/2/19 6:18:20 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3380941100) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3412989424)=["2078","2","25","4","37","4"] -RESULT: timestampFromDateTime.call(["2078","2","25","4","37","4"])=3412989424 -RESULT: jsDate(3412989424)=2078/2/25 4:37:4 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3412989424) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3444574039)=["2079","2","25","18","7","19"] -RESULT: timestampFromDateTime.call(["2079","2","25","18","7","19"])=3444574039 -RESULT: jsDate(3444574039)=2079/2/25 18:7:19 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3444574039) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3476622362)=["2080","3","2","16","26","2"] -RESULT: timestampFromDateTime.call(["2080","3","2","16","26","2"])=3476622362 -RESULT: jsDate(3476622362)=2080/3/2 16:26:2 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3476622362) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3508670686)=["2081","3","8","14","44","46"] -RESULT: timestampFromDateTime.call(["2081","3","8","14","44","46"])=3508670686 -RESULT: jsDate(3508670686)=2081/3/8 14:44:46 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3508670686) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3540255301)=["2082","3","9","4","15","1"] -RESULT: timestampFromDateTime.call(["2082","3","9","4","15","1"])=3540255301 -RESULT: jsDate(3540255301)=2082/3/9 4:15:1 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3540255301) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3572303624)=["2083","3","15","2","33","44"] -RESULT: timestampFromDateTime.call(["2083","3","15","2","33","44"])=3572303624 -RESULT: jsDate(3572303624)=2083/3/15 2:33:44 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3572303624) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3604351948)=["2084","3","20","0","52","28"] -RESULT: timestampFromDateTime.call(["2084","3","20","0","52","28"])=3604351948 -RESULT: jsDate(3604351948)=2084/3/20 0:52:28 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3604351948) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3635936563)=["2085","3","20","14","22","43"] -RESULT: timestampFromDateTime.call(["2085","3","20","14","22","43"])=3635936563 -RESULT: jsDate(3635936563)=2085/3/20 14:22:43 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3635936563) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3667984886)=["2086","3","26","12","41","26"] -RESULT: timestampFromDateTime.call(["2086","3","26","12","41","26"])=3667984886 -RESULT: jsDate(3667984886)=2086/3/26 12:41:26 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3667984886) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3700033210)=["2087","4","1","11","0","10"] -RESULT: timestampFromDateTime.call(["2087","4","1","11","0","10"])=3700033210 -RESULT: jsDate(3700033210)=2087/4/1 11:0:10 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3700033210) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3731617825)=["2088","4","1","0","30","25"] -RESULT: timestampFromDateTime.call(["2088","4","1","0","30","25"])=3731617825 -RESULT: jsDate(3731617825)=2088/4/1 0:30:25 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3731617825) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3763666148)=["2089","4","6","22","49","8"] -RESULT: timestampFromDateTime.call(["2089","4","6","22","49","8"])=3763666148 -RESULT: jsDate(3763666148)=2089/4/6 22:49:8 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3763666148) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3795714472)=["2090","4","12","21","7","52"] -RESULT: timestampFromDateTime.call(["2090","4","12","21","7","52"])=3795714472 -RESULT: jsDate(3795714472)=2090/4/12 21:7:52 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3795714472) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3827299087)=["2091","4","13","10","38","7"] -RESULT: timestampFromDateTime.call(["2091","4","13","10","38","7"])=3827299087 -RESULT: jsDate(3827299087)=2091/4/13 10:38:7 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3827299087) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3859347410)=["2092","4","18","8","56","50"] -RESULT: timestampFromDateTime.call(["2092","4","18","8","56","50"])=3859347410 -RESULT: jsDate(3859347410)=2092/4/18 8:56:50 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3859347410) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3891395734)=["2093","4","24","7","15","34"] -RESULT: timestampFromDateTime.call(["2093","4","24","7","15","34"])=3891395734 -RESULT: jsDate(3891395734)=2093/4/24 7:15:34 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3891395734) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3922980349)=["2094","4","24","20","45","49"] -RESULT: timestampFromDateTime.call(["2094","4","24","20","45","49"])=3922980349 -RESULT: jsDate(3922980349)=2094/4/24 20:45:49 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3922980349) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3955028672)=["2095","4","30","19","4","32"] -RESULT: timestampFromDateTime.call(["2095","4","30","19","4","32"])=3955028672 -RESULT: jsDate(3955028672)=2095/4/30 19:4:32 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3955028672) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(3987076996)=["2096","5","5","17","23","16"] -RESULT: timestampFromDateTime.call(["2096","5","5","17","23","16"])=3987076996 -RESULT: jsDate(3987076996)=2096/5/5 17:23:16 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(3987076996) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4018661611)=["2097","5","6","6","53","31"] -RESULT: timestampFromDateTime.call(["2097","5","6","6","53","31"])=4018661611 -RESULT: jsDate(4018661611)=2097/5/6 6:53:31 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4018661611) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4050709934)=["2098","5","12","5","12","14"] -RESULT: timestampFromDateTime.call(["2098","5","12","5","12","14"])=4050709934 -RESULT: jsDate(4050709934)=2098/5/12 5:12:14 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4050709934) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4082758258)=["2099","5","18","3","30","58"] -RESULT: timestampFromDateTime.call(["2099","5","18","3","30","58"])=4082758258 -RESULT: jsDate(4082758258)=2099/5/18 3:30:58 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4082758258) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4114342873)=["2100","5","18","17","1","13"] -RESULT: timestampFromDateTime.call(["2100","5","18","17","1","13"])=4114342873 -RESULT: jsDate(4114342873)=2100/5/18 17:1:13 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4114342873) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4146391196)=["2101","5","24","15","19","56"] -RESULT: timestampFromDateTime.call(["2101","5","24","15","19","56"])=4146391196 -RESULT: jsDate(4146391196)=2101/5/24 15:19:56 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4146391196) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4178439520)=["2102","5","30","13","38","40"] -RESULT: timestampFromDateTime.call(["2102","5","30","13","38","40"])=4178439520 -RESULT: jsDate(4178439520)=2102/5/30 13:38:40 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4178439520) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4210024135)=["2103","5","31","3","8","55"] -RESULT: timestampFromDateTime.call(["2103","5","31","3","8","55"])=4210024135 -RESULT: jsDate(4210024135)=2103/5/31 3:8:55 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4210024135) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4242072458)=["2104","6","5","1","27","38"] -RESULT: timestampFromDateTime.call(["2104","6","5","1","27","38"])=4242072458 -RESULT: jsDate(4242072458)=2104/6/5 1:27:38 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4242072458) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4274120782)=["2105","6","10","23","46","22"] -RESULT: timestampFromDateTime.call(["2105","6","10","23","46","22"])=4274120782 -RESULT: jsDate(4274120782)=2105/6/10 23:46:22 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4274120782) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4305705397)=["2106","6","11","13","16","37"] -RESULT: timestampFromDateTime.call(["2106","6","11","13","16","37"])=4305705397 -RESULT: jsDate(4305705397)=2106/6/11 13:16:37 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4305705397) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4337753720)=["2107","6","17","11","35","20"] -RESULT: timestampFromDateTime.call(["2107","6","17","11","35","20"])=4337753720 -RESULT: jsDate(4337753720)=2107/6/17 11:35:20 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4337753720) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4369802044)=["2108","6","22","9","54","4"] -RESULT: timestampFromDateTime.call(["2108","6","22","9","54","4"])=4369802044 -RESULT: jsDate(4369802044)=2108/6/22 9:54:4 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4369802044) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4401386659)=["2109","6","22","23","24","19"] -RESULT: timestampFromDateTime.call(["2109","6","22","23","24","19"])=4401386659 -RESULT: jsDate(4401386659)=2109/6/22 23:24:19 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4401386659) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4433434982)=["2110","6","28","21","43","2"] -RESULT: timestampFromDateTime.call(["2110","6","28","21","43","2"])=4433434982 -RESULT: jsDate(4433434982)=2110/6/28 21:43:2 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4433434982) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4465483306)=["2111","7","4","20","1","46"] -RESULT: timestampFromDateTime.call(["2111","7","4","20","1","46"])=4465483306 -RESULT: jsDate(4465483306)=2111/7/4 20:1:46 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4465483306) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4497067921)=["2112","7","4","9","32","1"] -RESULT: timestampFromDateTime.call(["2112","7","4","9","32","1"])=4497067921 -RESULT: jsDate(4497067921)=2112/7/4 9:32:1 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4497067921) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4529116244)=["2113","7","10","7","50","44"] -RESULT: timestampFromDateTime.call(["2113","7","10","7","50","44"])=4529116244 -RESULT: jsDate(4529116244)=2113/7/10 7:50:44 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4529116244) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4561164568)=["2114","7","16","6","9","28"] -RESULT: timestampFromDateTime.call(["2114","7","16","6","9","28"])=4561164568 -RESULT: jsDate(4561164568)=2114/7/16 6:9:28 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4561164568) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4592749183)=["2115","7","16","19","39","43"] -RESULT: timestampFromDateTime.call(["2115","7","16","19","39","43"])=4592749183 -RESULT: jsDate(4592749183)=2115/7/16 19:39:43 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4592749183) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4624797506)=["2116","7","21","17","58","26"] -RESULT: timestampFromDateTime.call(["2116","7","21","17","58","26"])=4624797506 -RESULT: jsDate(4624797506)=2116/7/21 17:58:26 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4624797506) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4656845830)=["2117","7","27","16","17","10"] -RESULT: timestampFromDateTime.call(["2117","7","27","16","17","10"])=4656845830 -RESULT: jsDate(4656845830)=2117/7/27 16:17:10 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4656845830) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4688430445)=["2118","7","28","5","47","25"] -RESULT: timestampFromDateTime.call(["2118","7","28","5","47","25"])=4688430445 -RESULT: jsDate(4688430445)=2118/7/28 5:47:25 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4688430445) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4720478768)=["2119","8","3","4","6","8"] -RESULT: timestampFromDateTime.call(["2119","8","3","4","6","8"])=4720478768 -RESULT: jsDate(4720478768)=2119/8/3 4:6:8 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4720478768) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4752527092)=["2120","8","8","2","24","52"] -RESULT: timestampFromDateTime.call(["2120","8","8","2","24","52"])=4752527092 -RESULT: jsDate(4752527092)=2120/8/8 2:24:52 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4752527092) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4784111707)=["2121","8","8","15","55","7"] -RESULT: timestampFromDateTime.call(["2121","8","8","15","55","7"])=4784111707 -RESULT: jsDate(4784111707)=2121/8/8 15:55:7 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4784111707) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4816160030)=["2122","8","14","14","13","50"] -RESULT: timestampFromDateTime.call(["2122","8","14","14","13","50"])=4816160030 -RESULT: jsDate(4816160030)=2122/8/14 14:13:50 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4816160030) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4848208354)=["2123","8","20","12","32","34"] -RESULT: timestampFromDateTime.call(["2123","8","20","12","32","34"])=4848208354 -RESULT: jsDate(4848208354)=2123/8/20 12:32:34 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4848208354) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4879792969)=["2124","8","20","2","2","49"] -RESULT: timestampFromDateTime.call(["2124","8","20","2","2","49"])=4879792969 -RESULT: jsDate(4879792969)=2124/8/20 2:2:49 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4879792969) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4911841292)=["2125","8","26","0","21","32"] -RESULT: timestampFromDateTime.call(["2125","8","26","0","21","32"])=4911841292 -RESULT: jsDate(4911841292)=2125/8/26 0:21:32 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4911841292) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4943889616)=["2126","8","31","22","40","16"] -RESULT: timestampFromDateTime.call(["2126","8","31","22","40","16"])=4943889616 -RESULT: jsDate(4943889616)=2126/8/31 22:40:16 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4943889616) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(4975474231)=["2127","9","1","12","10","31"] -RESULT: timestampFromDateTime.call(["2127","9","1","12","10","31"])=4975474231 -RESULT: jsDate(4975474231)=2127/9/1 12:10:31 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(4975474231) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5007522554)=["2128","9","6","10","29","14"] -RESULT: timestampFromDateTime.call(["2128","9","6","10","29","14"])=5007522554 -RESULT: jsDate(5007522554)=2128/9/6 10:29:14 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5007522554) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5039570878)=["2129","9","12","8","47","58"] -RESULT: timestampFromDateTime.call(["2129","9","12","8","47","58"])=5039570878 -RESULT: jsDate(5039570878)=2129/9/12 8:47:58 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5039570878) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5071155493)=["2130","9","12","22","18","13"] -RESULT: timestampFromDateTime.call(["2130","9","12","22","18","13"])=5071155493 -RESULT: jsDate(5071155493)=2130/9/12 22:18:13 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5071155493) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5103203816)=["2131","9","18","20","36","56"] -RESULT: timestampFromDateTime.call(["2131","9","18","20","36","56"])=5103203816 -RESULT: jsDate(5103203816)=2131/9/18 20:36:56 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5103203816) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5135252140)=["2132","9","23","18","55","40"] -RESULT: timestampFromDateTime.call(["2132","9","23","18","55","40"])=5135252140 -RESULT: jsDate(5135252140)=2132/9/23 18:55:40 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5135252140) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5166836755)=["2133","9","24","8","25","55"] -RESULT: timestampFromDateTime.call(["2133","9","24","8","25","55"])=5166836755 -RESULT: jsDate(5166836755)=2133/9/24 8:25:55 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5166836755) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5198885078)=["2134","9","30","6","44","38"] -RESULT: timestampFromDateTime.call(["2134","9","30","6","44","38"])=5198885078 -RESULT: jsDate(5198885078)=2134/9/30 6:44:38 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5198885078) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5230933402)=["2135","10","6","5","3","22"] -RESULT: timestampFromDateTime.call(["2135","10","6","5","3","22"])=5230933402 -RESULT: jsDate(5230933402)=2135/10/6 5:3:22 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5230933402) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5262518017)=["2136","10","5","18","33","37"] -RESULT: timestampFromDateTime.call(["2136","10","5","18","33","37"])=5262518017 -RESULT: jsDate(5262518017)=2136/10/5 18:33:37 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5262518017) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5294566340)=["2137","10","11","16","52","20"] -RESULT: timestampFromDateTime.call(["2137","10","11","16","52","20"])=5294566340 -RESULT: jsDate(5294566340)=2137/10/11 16:52:20 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5294566340) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5326614664)=["2138","10","17","15","11","4"] -RESULT: timestampFromDateTime.call(["2138","10","17","15","11","4"])=5326614664 -RESULT: jsDate(5326614664)=2138/10/17 15:11:4 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5326614664) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5358199279)=["2139","10","18","4","41","19"] -RESULT: timestampFromDateTime.call(["2139","10","18","4","41","19"])=5358199279 -RESULT: jsDate(5358199279)=2139/10/18 4:41:19 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5358199279) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5390247602)=["2140","10","23","3","0","2"] -RESULT: timestampFromDateTime.call(["2140","10","23","3","0","2"])=5390247602 -RESULT: jsDate(5390247602)=2140/10/23 3:0:2 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5390247602) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5422295926)=["2141","10","29","1","18","46"] -RESULT: timestampFromDateTime.call(["2141","10","29","1","18","46"])=5422295926 -RESULT: jsDate(5422295926)=2141/10/29 1:18:46 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5422295926) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5453880541)=["2142","10","29","14","49","1"] -RESULT: timestampFromDateTime.call(["2142","10","29","14","49","1"])=5453880541 -RESULT: jsDate(5453880541)=2142/10/29 14:49:1 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5453880541) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5485928864)=["2143","11","4","13","7","44"] -RESULT: timestampFromDateTime.call(["2143","11","4","13","7","44"])=5485928864 -RESULT: jsDate(5485928864)=2143/11/4 13:7:44 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5485928864) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5517977188)=["2144","11","9","11","26","28"] -RESULT: timestampFromDateTime.call(["2144","11","9","11","26","28"])=5517977188 -RESULT: jsDate(5517977188)=2144/11/9 11:26:28 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5517977188) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5549561803)=["2145","11","10","0","56","43"] -RESULT: timestampFromDateTime.call(["2145","11","10","0","56","43"])=5549561803 -RESULT: jsDate(5549561803)=2145/11/10 0:56:43 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5549561803) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5581610126)=["2146","11","15","23","15","26"] -RESULT: timestampFromDateTime.call(["2146","11","15","23","15","26"])=5581610126 -RESULT: jsDate(5581610126)=2146/11/15 23:15:26 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5581610126) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5613658450)=["2147","11","21","21","34","10"] -RESULT: timestampFromDateTime.call(["2147","11","21","21","34","10"])=5613658450 -RESULT: jsDate(5613658450)=2147/11/21 21:34:10 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5613658450) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5645243065)=["2148","11","21","11","4","25"] -RESULT: timestampFromDateTime.call(["2148","11","21","11","4","25"])=5645243065 -RESULT: jsDate(5645243065)=2148/11/21 11:4:25 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5645243065) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5677291388)=["2149","11","27","9","23","8"] -RESULT: timestampFromDateTime.call(["2149","11","27","9","23","8"])=5677291388 -RESULT: jsDate(5677291388)=2149/11/27 9:23:8 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5677291388) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5709339712)=["2150","12","3","7","41","52"] -RESULT: timestampFromDateTime.call(["2150","12","3","7","41","52"])=5709339712 -RESULT: jsDate(5709339712)=2150/12/3 7:41:52 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5709339712) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5740924327)=["2151","12","3","21","12","7"] -RESULT: timestampFromDateTime.call(["2151","12","3","21","12","7"])=5740924327 -RESULT: jsDate(5740924327)=2151/12/3 21:12:7 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5740924327) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5772972650)=["2152","12","8","19","30","50"] -RESULT: timestampFromDateTime.call(["2152","12","8","19","30","50"])=5772972650 -RESULT: jsDate(5772972650)=2152/12/8 19:30:50 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5772972650) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5805020974)=["2153","12","14","17","49","34"] -RESULT: timestampFromDateTime.call(["2153","12","14","17","49","34"])=5805020974 -RESULT: jsDate(5805020974)=2153/12/14 17:49:34 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5805020974) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5836605589)=["2154","12","15","7","19","49"] -RESULT: timestampFromDateTime.call(["2154","12","15","7","19","49"])=5836605589 -RESULT: jsDate(5836605589)=2154/12/15 7:19:49 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5836605589) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5868653912)=["2155","12","21","5","38","32"] -RESULT: timestampFromDateTime.call(["2155","12","21","5","38","32"])=5868653912 -RESULT: jsDate(5868653912)=2155/12/21 5:38:32 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5868653912) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5900702236)=["2156","12","26","3","57","16"] -RESULT: timestampFromDateTime.call(["2156","12","26","3","57","16"])=5900702236 -RESULT: jsDate(5900702236)=2156/12/26 3:57:16 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5900702236) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5932286851)=["2157","12","26","17","27","31"] -RESULT: timestampFromDateTime.call(["2157","12","26","17","27","31"])=5932286851 -RESULT: jsDate(5932286851)=2157/12/26 17:27:31 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5932286851) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5964335174)=["2159","1","1","15","46","14"] -RESULT: timestampFromDateTime.call(["2159","1","1","15","46","14"])=5964335174 -RESULT: jsDate(5964335174)=2159/1/1 15:46:14 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5964335174) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(5996383498)=["2160","1","7","14","4","58"] -RESULT: timestampFromDateTime.call(["2160","1","7","14","4","58"])=5996383498 -RESULT: jsDate(5996383498)=2160/1/7 14:4:58 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(5996383498) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6027968113)=["2161","1","7","3","35","13"] -RESULT: timestampFromDateTime.call(["2161","1","7","3","35","13"])=6027968113 -RESULT: jsDate(6027968113)=2161/1/7 3:35:13 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6027968113) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6060016436)=["2162","1","13","1","53","56"] -RESULT: timestampFromDateTime.call(["2162","1","13","1","53","56"])=6060016436 -RESULT: jsDate(6060016436)=2162/1/13 1:53:56 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6060016436) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6092064760)=["2163","1","19","0","12","40"] -RESULT: timestampFromDateTime.call(["2163","1","19","0","12","40"])=6092064760 -RESULT: jsDate(6092064760)=2163/1/19 0:12:40 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6092064760) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6123649375)=["2164","1","19","13","42","55"] -RESULT: timestampFromDateTime.call(["2164","1","19","13","42","55"])=6123649375 -RESULT: jsDate(6123649375)=2164/1/19 13:42:55 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6123649375) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6155697698)=["2165","1","24","12","1","38"] -RESULT: timestampFromDateTime.call(["2165","1","24","12","1","38"])=6155697698 -RESULT: jsDate(6155697698)=2165/1/24 12:1:38 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6155697698) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6187746022)=["2166","1","30","10","20","22"] -RESULT: timestampFromDateTime.call(["2166","1","30","10","20","22"])=6187746022 -RESULT: jsDate(6187746022)=2166/1/30 10:20:22 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6187746022) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6219330637)=["2167","1","30","23","50","37"] -RESULT: timestampFromDateTime.call(["2167","1","30","23","50","37"])=6219330637 -RESULT: jsDate(6219330637)=2167/1/30 23:50:37 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6219330637) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6251378960)=["2168","2","5","22","9","20"] -RESULT: timestampFromDateTime.call(["2168","2","5","22","9","20"])=6251378960 -RESULT: jsDate(6251378960)=2168/2/5 22:9:20 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6251378960) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6283427284)=["2169","2","10","20","28","4"] -RESULT: timestampFromDateTime.call(["2169","2","10","20","28","4"])=6283427284 -RESULT: jsDate(6283427284)=2169/2/10 20:28:4 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6283427284) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6315011899)=["2170","2","11","9","58","19"] -RESULT: timestampFromDateTime.call(["2170","2","11","9","58","19"])=6315011899 -RESULT: jsDate(6315011899)=2170/2/11 9:58:19 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6315011899) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6347060222)=["2171","2","17","8","17","2"] -RESULT: timestampFromDateTime.call(["2171","2","17","8","17","2"])=6347060222 -RESULT: jsDate(6347060222)=2171/2/17 8:17:2 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6347060222) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6379108546)=["2172","2","23","6","35","46"] -RESULT: timestampFromDateTime.call(["2172","2","23","6","35","46"])=6379108546 -RESULT: jsDate(6379108546)=2172/2/23 6:35:46 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6379108546) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6410693161)=["2173","2","22","20","6","1"] -RESULT: timestampFromDateTime.call(["2173","2","22","20","6","1"])=6410693161 -RESULT: jsDate(6410693161)=2173/2/22 20:6:1 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6410693161) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6442741484)=["2174","2","28","18","24","44"] -RESULT: timestampFromDateTime.call(["2174","2","28","18","24","44"])=6442741484 -RESULT: jsDate(6442741484)=2174/2/28 18:24:44 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6442741484) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6474789808)=["2175","3","6","16","43","28"] -RESULT: timestampFromDateTime.call(["2175","3","6","16","43","28"])=6474789808 -RESULT: jsDate(6474789808)=2175/3/6 16:43:28 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6474789808) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6506374423)=["2176","3","6","6","13","43"] -RESULT: timestampFromDateTime.call(["2176","3","6","6","13","43"])=6506374423 -RESULT: jsDate(6506374423)=2176/3/6 6:13:43 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6506374423) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6538422746)=["2177","3","12","4","32","26"] -RESULT: timestampFromDateTime.call(["2177","3","12","4","32","26"])=6538422746 -RESULT: jsDate(6538422746)=2177/3/12 4:32:26 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6538422746) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6570471070)=["2178","3","18","2","51","10"] -RESULT: timestampFromDateTime.call(["2178","3","18","2","51","10"])=6570471070 -RESULT: jsDate(6570471070)=2178/3/18 2:51:10 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6570471070) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6602055685)=["2179","3","18","16","21","25"] -RESULT: timestampFromDateTime.call(["2179","3","18","16","21","25"])=6602055685 -RESULT: jsDate(6602055685)=2179/3/18 16:21:25 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6602055685) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6634104008)=["2180","3","23","14","40","8"] -RESULT: timestampFromDateTime.call(["2180","3","23","14","40","8"])=6634104008 -RESULT: jsDate(6634104008)=2180/3/23 14:40:8 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6634104008) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6666152332)=["2181","3","29","12","58","52"] -RESULT: timestampFromDateTime.call(["2181","3","29","12","58","52"])=6666152332 -RESULT: jsDate(6666152332)=2181/3/29 12:58:52 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6666152332) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6697736947)=["2182","3","30","2","29","7"] -RESULT: timestampFromDateTime.call(["2182","3","30","2","29","7"])=6697736947 -RESULT: jsDate(6697736947)=2182/3/30 2:29:7 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6697736947) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6729785270)=["2183","4","5","0","47","50"] -RESULT: timestampFromDateTime.call(["2183","4","5","0","47","50"])=6729785270 -RESULT: jsDate(6729785270)=2183/4/5 0:47:50 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6729785270) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6761833594)=["2184","4","9","23","6","34"] -RESULT: timestampFromDateTime.call(["2184","4","9","23","6","34"])=6761833594 -RESULT: jsDate(6761833594)=2184/4/9 23:6:34 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6761833594) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6793418209)=["2185","4","10","12","36","49"] -RESULT: timestampFromDateTime.call(["2185","4","10","12","36","49"])=6793418209 -RESULT: jsDate(6793418209)=2185/4/10 12:36:49 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6793418209) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6825466532)=["2186","4","16","10","55","32"] -RESULT: timestampFromDateTime.call(["2186","4","16","10","55","32"])=6825466532 -RESULT: jsDate(6825466532)=2186/4/16 10:55:32 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6825466532) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6857514856)=["2187","4","22","9","14","16"] -RESULT: timestampFromDateTime.call(["2187","4","22","9","14","16"])=6857514856 -RESULT: jsDate(6857514856)=2187/4/22 9:14:16 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6857514856) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6889099471)=["2188","4","21","22","44","31"] -RESULT: timestampFromDateTime.call(["2188","4","21","22","44","31"])=6889099471 -RESULT: jsDate(6889099471)=2188/4/21 22:44:31 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6889099471) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6921147794)=["2189","4","27","21","3","14"] -RESULT: timestampFromDateTime.call(["2189","4","27","21","3","14"])=6921147794 -RESULT: jsDate(6921147794)=2189/4/27 21:3:14 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6921147794) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6953196118)=["2190","5","3","19","21","58"] -RESULT: timestampFromDateTime.call(["2190","5","3","19","21","58"])=6953196118 -RESULT: jsDate(6953196118)=2190/5/3 19:21:58 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6953196118) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(6984780733)=["2191","5","4","8","52","13"] -RESULT: timestampFromDateTime.call(["2191","5","4","8","52","13"])=6984780733 -RESULT: jsDate(6984780733)=2191/5/4 8:52:13 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(6984780733) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7016829056)=["2192","5","9","7","10","56"] -RESULT: timestampFromDateTime.call(["2192","5","9","7","10","56"])=7016829056 -RESULT: jsDate(7016829056)=2192/5/9 7:10:56 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7016829056) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7048877380)=["2193","5","15","5","29","40"] -RESULT: timestampFromDateTime.call(["2193","5","15","5","29","40"])=7048877380 -RESULT: jsDate(7048877380)=2193/5/15 5:29:40 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7048877380) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7080461995)=["2194","5","15","18","59","55"] -RESULT: timestampFromDateTime.call(["2194","5","15","18","59","55"])=7080461995 -RESULT: jsDate(7080461995)=2194/5/15 18:59:55 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7080461995) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7112510318)=["2195","5","21","17","18","38"] -RESULT: timestampFromDateTime.call(["2195","5","21","17","18","38"])=7112510318 -RESULT: jsDate(7112510318)=2195/5/21 17:18:38 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7112510318) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7144558642)=["2196","5","26","15","37","22"] -RESULT: timestampFromDateTime.call(["2196","5","26","15","37","22"])=7144558642 -RESULT: jsDate(7144558642)=2196/5/26 15:37:22 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7144558642) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7176143257)=["2197","5","27","5","7","37"] -RESULT: timestampFromDateTime.call(["2197","5","27","5","7","37"])=7176143257 -RESULT: jsDate(7176143257)=2197/5/27 5:7:37 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7176143257) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7208191580)=["2198","6","2","3","26","20"] -RESULT: timestampFromDateTime.call(["2198","6","2","3","26","20"])=7208191580 -RESULT: jsDate(7208191580)=2198/6/2 3:26:20 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7208191580) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7240239904)=["2199","6","8","1","45","4"] -RESULT: timestampFromDateTime.call(["2199","6","8","1","45","4"])=7240239904 -RESULT: jsDate(7240239904)=2199/6/8 1:45:4 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7240239904) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7271824519)=["2200","6","8","15","15","19"] -RESULT: timestampFromDateTime.call(["2200","6","8","15","15","19"])=7271824519 -RESULT: jsDate(7271824519)=2200/6/8 15:15:19 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7271824519) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7303872842)=["2201","6","14","13","34","2"] -RESULT: timestampFromDateTime.call(["2201","6","14","13","34","2"])=7303872842 -RESULT: jsDate(7303872842)=2201/6/14 13:34:2 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7303872842) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7335921166)=["2202","6","20","11","52","46"] -RESULT: timestampFromDateTime.call(["2202","6","20","11","52","46"])=7335921166 -RESULT: jsDate(7335921166)=2202/6/20 11:52:46 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7335921166) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7367505781)=["2203","6","21","1","23","1"] -RESULT: timestampFromDateTime.call(["2203","6","21","1","23","1"])=7367505781 -RESULT: jsDate(7367505781)=2203/6/21 1:23:1 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7367505781) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7399554104)=["2204","6","25","23","41","44"] -RESULT: timestampFromDateTime.call(["2204","6","25","23","41","44"])=7399554104 -RESULT: jsDate(7399554104)=2204/6/25 23:41:44 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7399554104) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7431602428)=["2205","7","1","22","0","28"] -RESULT: timestampFromDateTime.call(["2205","7","1","22","0","28"])=7431602428 -RESULT: jsDate(7431602428)=2205/7/1 22:0:28 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7431602428) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7463187043)=["2206","7","2","11","30","43"] -RESULT: timestampFromDateTime.call(["2206","7","2","11","30","43"])=7463187043 -RESULT: jsDate(7463187043)=2206/7/2 11:30:43 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7463187043) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7495235366)=["2207","7","8","9","49","26"] -RESULT: timestampFromDateTime.call(["2207","7","8","9","49","26"])=7495235366 -RESULT: jsDate(7495235366)=2207/7/8 9:49:26 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7495235366) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7527283690)=["2208","7","13","8","8","10"] -RESULT: timestampFromDateTime.call(["2208","7","13","8","8","10"])=7527283690 -RESULT: jsDate(7527283690)=2208/7/13 8:8:10 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7527283690) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7558868305)=["2209","7","13","21","38","25"] -RESULT: timestampFromDateTime.call(["2209","7","13","21","38","25"])=7558868305 -RESULT: jsDate(7558868305)=2209/7/13 21:38:25 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7558868305) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7590916628)=["2210","7","19","19","57","8"] -RESULT: timestampFromDateTime.call(["2210","7","19","19","57","8"])=7590916628 -RESULT: jsDate(7590916628)=2210/7/19 19:57:8 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7590916628) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7622964952)=["2211","7","25","18","15","52"] -RESULT: timestampFromDateTime.call(["2211","7","25","18","15","52"])=7622964952 -RESULT: jsDate(7622964952)=2211/7/25 18:15:52 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7622964952) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7654549567)=["2212","7","25","7","46","7"] -RESULT: timestampFromDateTime.call(["2212","7","25","7","46","7"])=7654549567 -RESULT: jsDate(7654549567)=2212/7/25 7:46:7 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7654549567) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7686597890)=["2213","7","31","6","4","50"] -RESULT: timestampFromDateTime.call(["2213","7","31","6","4","50"])=7686597890 -RESULT: jsDate(7686597890)=2213/7/31 6:4:50 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7686597890) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7718646214)=["2214","8","6","4","23","34"] -RESULT: timestampFromDateTime.call(["2214","8","6","4","23","34"])=7718646214 -RESULT: jsDate(7718646214)=2214/8/6 4:23:34 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7718646214) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7750230829)=["2215","8","6","17","53","49"] -RESULT: timestampFromDateTime.call(["2215","8","6","17","53","49"])=7750230829 -RESULT: jsDate(7750230829)=2215/8/6 17:53:49 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7750230829) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7782279152)=["2216","8","11","16","12","32"] -RESULT: timestampFromDateTime.call(["2216","8","11","16","12","32"])=7782279152 -RESULT: jsDate(7782279152)=2216/8/11 16:12:32 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7782279152) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7814327476)=["2217","8","17","14","31","16"] -RESULT: timestampFromDateTime.call(["2217","8","17","14","31","16"])=7814327476 -RESULT: jsDate(7814327476)=2217/8/17 14:31:16 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7814327476) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7845912091)=["2218","8","18","4","1","31"] -RESULT: timestampFromDateTime.call(["2218","8","18","4","1","31"])=7845912091 -RESULT: jsDate(7845912091)=2218/8/18 4:1:31 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7845912091) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7877960414)=["2219","8","24","2","20","14"] -RESULT: timestampFromDateTime.call(["2219","8","24","2","20","14"])=7877960414 -RESULT: jsDate(7877960414)=2219/8/24 2:20:14 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7877960414) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7910008738)=["2220","8","29","0","38","58"] -RESULT: timestampFromDateTime.call(["2220","8","29","0","38","58"])=7910008738 -RESULT: jsDate(7910008738)=2220/8/29 0:38:58 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7910008738) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7941593353)=["2221","8","29","14","9","13"] -RESULT: timestampFromDateTime.call(["2221","8","29","14","9","13"])=7941593353 -RESULT: jsDate(7941593353)=2221/8/29 14:9:13 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7941593353) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(7973641676)=["2222","9","4","12","27","56"] -RESULT: timestampFromDateTime.call(["2222","9","4","12","27","56"])=7973641676 -RESULT: jsDate(7973641676)=2222/9/4 12:27:56 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(7973641676) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8005690000)=["2223","9","10","10","46","40"] -RESULT: timestampFromDateTime.call(["2223","9","10","10","46","40"])=8005690000 -RESULT: jsDate(8005690000)=2223/9/10 10:46:40 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8005690000) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8037274615)=["2224","9","10","0","16","55"] -RESULT: timestampFromDateTime.call(["2224","9","10","0","16","55"])=8037274615 -RESULT: jsDate(8037274615)=2224/9/10 0:16:55 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8037274615) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8069322938)=["2225","9","15","22","35","38"] -RESULT: timestampFromDateTime.call(["2225","9","15","22","35","38"])=8069322938 -RESULT: jsDate(8069322938)=2225/9/15 22:35:38 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8069322938) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8101371262)=["2226","9","21","20","54","22"] -RESULT: timestampFromDateTime.call(["2226","9","21","20","54","22"])=8101371262 -RESULT: jsDate(8101371262)=2226/9/21 20:54:22 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8101371262) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8132955877)=["2227","9","22","10","24","37"] -RESULT: timestampFromDateTime.call(["2227","9","22","10","24","37"])=8132955877 -RESULT: jsDate(8132955877)=2227/9/22 10:24:37 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8132955877) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8165004200)=["2228","9","27","8","43","20"] -RESULT: timestampFromDateTime.call(["2228","9","27","8","43","20"])=8165004200 -RESULT: jsDate(8165004200)=2228/9/27 8:43:20 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8165004200) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8197052524)=["2229","10","3","7","2","4"] -RESULT: timestampFromDateTime.call(["2229","10","3","7","2","4"])=8197052524 -RESULT: jsDate(8197052524)=2229/10/3 7:2:4 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8197052524) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8228637139)=["2230","10","3","20","32","19"] -RESULT: timestampFromDateTime.call(["2230","10","3","20","32","19"])=8228637139 -RESULT: jsDate(8228637139)=2230/10/3 20:32:19 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8228637139) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8260685462)=["2231","10","9","18","51","2"] -RESULT: timestampFromDateTime.call(["2231","10","9","18","51","2"])=8260685462 -RESULT: jsDate(8260685462)=2231/10/9 18:51:2 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8260685462) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8292733786)=["2232","10","14","17","9","46"] -RESULT: timestampFromDateTime.call(["2232","10","14","17","9","46"])=8292733786 -RESULT: jsDate(8292733786)=2232/10/14 17:9:46 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8292733786) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8324318401)=["2233","10","15","6","40","1"] -RESULT: timestampFromDateTime.call(["2233","10","15","6","40","1"])=8324318401 -RESULT: jsDate(8324318401)=2233/10/15 6:40:1 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8324318401) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8356366724)=["2234","10","21","4","58","44"] -RESULT: timestampFromDateTime.call(["2234","10","21","4","58","44"])=8356366724 -RESULT: jsDate(8356366724)=2234/10/21 4:58:44 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8356366724) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8388415048)=["2235","10","27","3","17","28"] -RESULT: timestampFromDateTime.call(["2235","10","27","3","17","28"])=8388415048 -RESULT: jsDate(8388415048)=2235/10/27 3:17:28 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8388415048) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8419999663)=["2236","10","26","16","47","43"] -RESULT: timestampFromDateTime.call(["2236","10","26","16","47","43"])=8419999663 -RESULT: jsDate(8419999663)=2236/10/26 16:47:43 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8419999663) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8452047986)=["2237","11","1","15","6","26"] -RESULT: timestampFromDateTime.call(["2237","11","1","15","6","26"])=8452047986 -RESULT: jsDate(8452047986)=2237/11/1 15:6:26 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8452047986) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8484096310)=["2238","11","7","13","25","10"] -RESULT: timestampFromDateTime.call(["2238","11","7","13","25","10"])=8484096310 -RESULT: jsDate(8484096310)=2238/11/7 13:25:10 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8484096310) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8515680925)=["2239","11","8","2","55","25"] -RESULT: timestampFromDateTime.call(["2239","11","8","2","55","25"])=8515680925 -RESULT: jsDate(8515680925)=2239/11/8 2:55:25 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8515680925) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8547729248)=["2240","11","13","1","14","8"] -RESULT: timestampFromDateTime.call(["2240","11","13","1","14","8"])=8547729248 -RESULT: jsDate(8547729248)=2240/11/13 1:14:8 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8547729248) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8579777572)=["2241","11","18","23","32","52"] -RESULT: timestampFromDateTime.call(["2241","11","18","23","32","52"])=8579777572 -RESULT: jsDate(8579777572)=2241/11/18 23:32:52 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8579777572) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8611362187)=["2242","11","19","13","3","7"] -RESULT: timestampFromDateTime.call(["2242","11","19","13","3","7"])=8611362187 -RESULT: jsDate(8611362187)=2242/11/19 13:3:7 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8611362187) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8643410510)=["2243","11","25","11","21","50"] -RESULT: timestampFromDateTime.call(["2243","11","25","11","21","50"])=8643410510 -RESULT: jsDate(8643410510)=2243/11/25 11:21:50 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8643410510) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8675458834)=["2244","11","30","9","40","34"] -RESULT: timestampFromDateTime.call(["2244","11","30","9","40","34"])=8675458834 -RESULT: jsDate(8675458834)=2244/11/30 9:40:34 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8675458834) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8707043449)=["2245","11","30","23","10","49"] -RESULT: timestampFromDateTime.call(["2245","11","30","23","10","49"])=8707043449 -RESULT: jsDate(8707043449)=2245/11/30 23:10:49 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8707043449) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8739091772)=["2246","12","6","21","29","32"] -RESULT: timestampFromDateTime.call(["2246","12","6","21","29","32"])=8739091772 -RESULT: jsDate(8739091772)=2246/12/6 21:29:32 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8739091772) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8771140096)=["2247","12","12","19","48","16"] -RESULT: timestampFromDateTime.call(["2247","12","12","19","48","16"])=8771140096 -RESULT: jsDate(8771140096)=2247/12/12 19:48:16 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8771140096) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8802724711)=["2248","12","12","9","18","31"] -RESULT: timestampFromDateTime.call(["2248","12","12","9","18","31"])=8802724711 -RESULT: jsDate(8802724711)=2248/12/12 9:18:31 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8802724711) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8834773034)=["2249","12","18","7","37","14"] -RESULT: timestampFromDateTime.call(["2249","12","18","7","37","14"])=8834773034 -RESULT: jsDate(8834773034)=2249/12/18 7:37:14 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8834773034) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8866821358)=["2250","12","24","5","55","58"] -RESULT: timestampFromDateTime.call(["2250","12","24","5","55","58"])=8866821358 -RESULT: jsDate(8866821358)=2250/12/24 5:55:58 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8866821358) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8898405973)=["2251","12","24","19","26","13"] -RESULT: timestampFromDateTime.call(["2251","12","24","19","26","13"])=8898405973 -RESULT: jsDate(8898405973)=2251/12/24 19:26:13 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8898405973) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8930454296)=["2252","12","29","17","44","56"] -RESULT: timestampFromDateTime.call(["2252","12","29","17","44","56"])=8930454296 -RESULT: jsDate(8930454296)=2252/12/29 17:44:56 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8930454296) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8962502620)=["2254","1","4","16","3","40"] -RESULT: timestampFromDateTime.call(["2254","1","4","16","3","40"])=8962502620 -RESULT: jsDate(8962502620)=2254/1/4 16:3:40 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8962502620) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(8994087235)=["2255","1","5","5","33","55"] -RESULT: timestampFromDateTime.call(["2255","1","5","5","33","55"])=8994087235 -RESULT: jsDate(8994087235)=2255/1/5 5:33:55 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(8994087235) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9026135558)=["2256","1","11","3","52","38"] -RESULT: timestampFromDateTime.call(["2256","1","11","3","52","38"])=9026135558 -RESULT: jsDate(9026135558)=2256/1/11 3:52:38 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9026135558) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9058183882)=["2257","1","16","2","11","22"] -RESULT: timestampFromDateTime.call(["2257","1","16","2","11","22"])=9058183882 -RESULT: jsDate(9058183882)=2257/1/16 2:11:22 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9058183882) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9089768497)=["2258","1","16","15","41","37"] -RESULT: timestampFromDateTime.call(["2258","1","16","15","41","37"])=9089768497 -RESULT: jsDate(9089768497)=2258/1/16 15:41:37 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9089768497) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9121816820)=["2259","1","22","14","0","20"] -RESULT: timestampFromDateTime.call(["2259","1","22","14","0","20"])=9121816820 -RESULT: jsDate(9121816820)=2259/1/22 14:0:20 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9121816820) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9153865144)=["2260","1","28","12","19","4"] -RESULT: timestampFromDateTime.call(["2260","1","28","12","19","4"])=9153865144 -RESULT: jsDate(9153865144)=2260/1/28 12:19:4 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9153865144) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9185449759)=["2261","1","28","1","49","19"] -RESULT: timestampFromDateTime.call(["2261","1","28","1","49","19"])=9185449759 -RESULT: jsDate(9185449759)=2261/1/28 1:49:19 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9185449759) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9217498082)=["2262","2","3","0","8","2"] -RESULT: timestampFromDateTime.call(["2262","2","3","0","8","2"])=9217498082 -RESULT: jsDate(9217498082)=2262/2/3 0:8:2 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9217498082) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9249546406)=["2263","2","8","22","26","46"] -RESULT: timestampFromDateTime.call(["2263","2","8","22","26","46"])=9249546406 -RESULT: jsDate(9249546406)=2263/2/8 22:26:46 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9249546406) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9281131021)=["2264","2","9","11","57","1"] -RESULT: timestampFromDateTime.call(["2264","2","9","11","57","1"])=9281131021 -RESULT: jsDate(9281131021)=2264/2/9 11:57:1 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9281131021) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9313179344)=["2265","2","14","10","15","44"] -RESULT: timestampFromDateTime.call(["2265","2","14","10","15","44"])=9313179344 -RESULT: jsDate(9313179344)=2265/2/14 10:15:44 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9313179344) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9345227668)=["2266","2","20","8","34","28"] -RESULT: timestampFromDateTime.call(["2266","2","20","8","34","28"])=9345227668 -RESULT: jsDate(9345227668)=2266/2/20 8:34:28 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9345227668) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9376812283)=["2267","2","20","22","4","43"] -RESULT: timestampFromDateTime.call(["2267","2","20","22","4","43"])=9376812283 -RESULT: jsDate(9376812283)=2267/2/20 22:4:43 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9376812283) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9408860606)=["2268","2","26","20","23","26"] -RESULT: timestampFromDateTime.call(["2268","2","26","20","23","26"])=9408860606 -RESULT: jsDate(9408860606)=2268/2/26 20:23:26 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9408860606) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9440908930)=["2269","3","3","18","42","10"] -RESULT: timestampFromDateTime.call(["2269","3","3","18","42","10"])=9440908930 -RESULT: jsDate(9440908930)=2269/3/3 18:42:10 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9440908930) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9472493545)=["2270","3","4","8","12","25"] -RESULT: timestampFromDateTime.call(["2270","3","4","8","12","25"])=9472493545 -RESULT: jsDate(9472493545)=2270/3/4 8:12:25 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9472493545) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9504541868)=["2271","3","10","6","31","8"] -RESULT: timestampFromDateTime.call(["2271","3","10","6","31","8"])=9504541868 -RESULT: jsDate(9504541868)=2271/3/10 6:31:8 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9504541868) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9536590192)=["2272","3","15","4","49","52"] -RESULT: timestampFromDateTime.call(["2272","3","15","4","49","52"])=9536590192 -RESULT: jsDate(9536590192)=2272/3/15 4:49:52 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9536590192) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9568174807)=["2273","3","15","18","20","7"] -RESULT: timestampFromDateTime.call(["2273","3","15","18","20","7"])=9568174807 -RESULT: jsDate(9568174807)=2273/3/15 18:20:7 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9568174807) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9600223130)=["2274","3","21","16","38","50"] -RESULT: timestampFromDateTime.call(["2274","3","21","16","38","50"])=9600223130 -RESULT: jsDate(9600223130)=2274/3/21 16:38:50 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9600223130) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9632271454)=["2275","3","27","14","57","34"] -RESULT: timestampFromDateTime.call(["2275","3","27","14","57","34"])=9632271454 -RESULT: jsDate(9632271454)=2275/3/27 14:57:34 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9632271454) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9663856069)=["2276","3","27","4","27","49"] -RESULT: timestampFromDateTime.call(["2276","3","27","4","27","49"])=9663856069 -RESULT: jsDate(9663856069)=2276/3/27 4:27:49 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9663856069) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9695904392)=["2277","4","2","2","46","32"] -RESULT: timestampFromDateTime.call(["2277","4","2","2","46","32"])=9695904392 -RESULT: jsDate(9695904392)=2277/4/2 2:46:32 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9695904392) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9727952716)=["2278","4","8","1","5","16"] -RESULT: timestampFromDateTime.call(["2278","4","8","1","5","16"])=9727952716 -RESULT: jsDate(9727952716)=2278/4/8 1:5:16 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9727952716) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9759537331)=["2279","4","8","14","35","31"] -RESULT: timestampFromDateTime.call(["2279","4","8","14","35","31"])=9759537331 -RESULT: jsDate(9759537331)=2279/4/8 14:35:31 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9759537331) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9791585654)=["2280","4","13","12","54","14"] -RESULT: timestampFromDateTime.call(["2280","4","13","12","54","14"])=9791585654 -RESULT: jsDate(9791585654)=2280/4/13 12:54:14 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9791585654) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9823633978)=["2281","4","19","11","12","58"] -RESULT: timestampFromDateTime.call(["2281","4","19","11","12","58"])=9823633978 -RESULT: jsDate(9823633978)=2281/4/19 11:12:58 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9823633978) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9855218593)=["2282","4","20","0","43","13"] -RESULT: timestampFromDateTime.call(["2282","4","20","0","43","13"])=9855218593 -RESULT: jsDate(9855218593)=2282/4/20 0:43:13 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9855218593) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9887266916)=["2283","4","25","23","1","56"] -RESULT: timestampFromDateTime.call(["2283","4","25","23","1","56"])=9887266916 -RESULT: jsDate(9887266916)=2283/4/25 23:1:56 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9887266916) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9919315240)=["2284","4","30","21","20","40"] -RESULT: timestampFromDateTime.call(["2284","4","30","21","20","40"])=9919315240 -RESULT: jsDate(9919315240)=2284/4/30 21:20:40 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9919315240) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9950899855)=["2285","5","1","10","50","55"] -RESULT: timestampFromDateTime.call(["2285","5","1","10","50","55"])=9950899855 -RESULT: jsDate(9950899855)=2285/5/1 10:50:55 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9950899855) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(9982948178)=["2286","5","7","9","9","38"] -RESULT: timestampFromDateTime.call(["2286","5","7","9","9","38"])=9982948178 -RESULT: jsDate(9982948178)=2286/5/7 9:9:38 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(9982948178) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10014996502)=["2287","5","13","7","28","22"] -RESULT: timestampFromDateTime.call(["2287","5","13","7","28","22"])=10014996502 -RESULT: jsDate(10014996502)=2287/5/13 7:28:22 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10014996502) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10046581117)=["2288","5","12","20","58","37"] -RESULT: timestampFromDateTime.call(["2288","5","12","20","58","37"])=10046581117 -RESULT: jsDate(10046581117)=2288/5/12 20:58:37 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10046581117) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10078629440)=["2289","5","18","19","17","20"] -RESULT: timestampFromDateTime.call(["2289","5","18","19","17","20"])=10078629440 -RESULT: jsDate(10078629440)=2289/5/18 19:17:20 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10078629440) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10110677764)=["2290","5","24","17","36","4"] -RESULT: timestampFromDateTime.call(["2290","5","24","17","36","4"])=10110677764 -RESULT: jsDate(10110677764)=2290/5/24 17:36:4 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10110677764) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10142262379)=["2291","5","25","7","6","19"] -RESULT: timestampFromDateTime.call(["2291","5","25","7","6","19"])=10142262379 -RESULT: jsDate(10142262379)=2291/5/25 7:6:19 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10142262379) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10174310702)=["2292","5","30","5","25","2"] -RESULT: timestampFromDateTime.call(["2292","5","30","5","25","2"])=10174310702 -RESULT: jsDate(10174310702)=2292/5/30 5:25:2 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10174310702) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10206359026)=["2293","6","5","3","43","46"] -RESULT: timestampFromDateTime.call(["2293","6","5","3","43","46"])=10206359026 -RESULT: jsDate(10206359026)=2293/6/5 3:43:46 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10206359026) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10237943641)=["2294","6","5","17","14","1"] -RESULT: timestampFromDateTime.call(["2294","6","5","17","14","1"])=10237943641 -RESULT: jsDate(10237943641)=2294/6/5 17:14:1 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10237943641) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10269991964)=["2295","6","11","15","32","44"] -RESULT: timestampFromDateTime.call(["2295","6","11","15","32","44"])=10269991964 -RESULT: jsDate(10269991964)=2295/6/11 15:32:44 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10269991964) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10302040288)=["2296","6","16","13","51","28"] -RESULT: timestampFromDateTime.call(["2296","6","16","13","51","28"])=10302040288 -RESULT: jsDate(10302040288)=2296/6/16 13:51:28 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10302040288) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10333624903)=["2297","6","17","3","21","43"] -RESULT: timestampFromDateTime.call(["2297","6","17","3","21","43"])=10333624903 -RESULT: jsDate(10333624903)=2297/6/17 3:21:43 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10333624903) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10365673226)=["2298","6","23","1","40","26"] -RESULT: timestampFromDateTime.call(["2298","6","23","1","40","26"])=10365673226 -RESULT: jsDate(10365673226)=2298/6/23 1:40:26 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10365673226) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10397721550)=["2299","6","28","23","59","10"] -RESULT: timestampFromDateTime.call(["2299","6","28","23","59","10"])=10397721550 -RESULT: jsDate(10397721550)=2299/6/28 23:59:10 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10397721550) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10429306165)=["2300","6","29","13","29","25"] -RESULT: timestampFromDateTime.call(["2300","6","29","13","29","25"])=10429306165 -RESULT: jsDate(10429306165)=2300/6/29 13:29:25 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10429306165) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10461354488)=["2301","7","5","11","48","8"] -RESULT: timestampFromDateTime.call(["2301","7","5","11","48","8"])=10461354488 -RESULT: jsDate(10461354488)=2301/7/5 11:48:8 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10461354488) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10493402812)=["2302","7","11","10","6","52"] -RESULT: timestampFromDateTime.call(["2302","7","11","10","6","52"])=10493402812 -RESULT: jsDate(10493402812)=2302/7/11 10:6:52 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10493402812) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10524987427)=["2303","7","11","23","37","7"] -RESULT: timestampFromDateTime.call(["2303","7","11","23","37","7"])=10524987427 -RESULT: jsDate(10524987427)=2303/7/11 23:37:7 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10524987427) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10557035750)=["2304","7","16","21","55","50"] -RESULT: timestampFromDateTime.call(["2304","7","16","21","55","50"])=10557035750 -RESULT: jsDate(10557035750)=2304/7/16 21:55:50 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10557035750) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10589084074)=["2305","7","22","20","14","34"] -RESULT: timestampFromDateTime.call(["2305","7","22","20","14","34"])=10589084074 -RESULT: jsDate(10589084074)=2305/7/22 20:14:34 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10589084074) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10620668689)=["2306","7","23","9","44","49"] -RESULT: timestampFromDateTime.call(["2306","7","23","9","44","49"])=10620668689 -RESULT: jsDate(10620668689)=2306/7/23 9:44:49 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10620668689) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10652717012)=["2307","7","29","8","3","32"] -RESULT: timestampFromDateTime.call(["2307","7","29","8","3","32"])=10652717012 -RESULT: jsDate(10652717012)=2307/7/29 8:3:32 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10652717012) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10684765336)=["2308","8","3","6","22","16"] -RESULT: timestampFromDateTime.call(["2308","8","3","6","22","16"])=10684765336 -RESULT: jsDate(10684765336)=2308/8/3 6:22:16 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10684765336) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10716349951)=["2309","8","3","19","52","31"] -RESULT: timestampFromDateTime.call(["2309","8","3","19","52","31"])=10716349951 -RESULT: jsDate(10716349951)=2309/8/3 19:52:31 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10716349951) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10748398274)=["2310","8","9","18","11","14"] -RESULT: timestampFromDateTime.call(["2310","8","9","18","11","14"])=10748398274 -RESULT: jsDate(10748398274)=2310/8/9 18:11:14 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10748398274) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10780446598)=["2311","8","15","16","29","58"] -RESULT: timestampFromDateTime.call(["2311","8","15","16","29","58"])=10780446598 -RESULT: jsDate(10780446598)=2311/8/15 16:29:58 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10780446598) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10812031213)=["2312","8","15","6","0","13"] -RESULT: timestampFromDateTime.call(["2312","8","15","6","0","13"])=10812031213 -RESULT: jsDate(10812031213)=2312/8/15 6:0:13 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10812031213) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10844079536)=["2313","8","21","4","18","56"] -RESULT: timestampFromDateTime.call(["2313","8","21","4","18","56"])=10844079536 -RESULT: jsDate(10844079536)=2313/8/21 4:18:56 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10844079536) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10876127860)=["2314","8","27","2","37","40"] -RESULT: timestampFromDateTime.call(["2314","8","27","2","37","40"])=10876127860 -RESULT: jsDate(10876127860)=2314/8/27 2:37:40 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10876127860) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10907712475)=["2315","8","27","16","7","55"] -RESULT: timestampFromDateTime.call(["2315","8","27","16","7","55"])=10907712475 -RESULT: jsDate(10907712475)=2315/8/27 16:7:55 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10907712475) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10939760798)=["2316","9","1","14","26","38"] -RESULT: timestampFromDateTime.call(["2316","9","1","14","26","38"])=10939760798 -RESULT: jsDate(10939760798)=2316/9/1 14:26:38 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10939760798) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(10971809122)=["2317","9","7","12","45","22"] -RESULT: timestampFromDateTime.call(["2317","9","7","12","45","22"])=10971809122 -RESULT: jsDate(10971809122)=2317/9/7 12:45:22 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(10971809122) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11003393737)=["2318","9","8","2","15","37"] -RESULT: timestampFromDateTime.call(["2318","9","8","2","15","37"])=11003393737 -RESULT: jsDate(11003393737)=2318/9/8 2:15:37 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11003393737) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11035442060)=["2319","9","14","0","34","20"] -RESULT: timestampFromDateTime.call(["2319","9","14","0","34","20"])=11035442060 -RESULT: jsDate(11035442060)=2319/9/14 0:34:20 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11035442060) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11067490384)=["2320","9","18","22","53","4"] -RESULT: timestampFromDateTime.call(["2320","9","18","22","53","4"])=11067490384 -RESULT: jsDate(11067490384)=2320/9/18 22:53:4 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11067490384) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11099074999)=["2321","9","19","12","23","19"] -RESULT: timestampFromDateTime.call(["2321","9","19","12","23","19"])=11099074999 -RESULT: jsDate(11099074999)=2321/9/19 12:23:19 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11099074999) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11131123322)=["2322","9","25","10","42","2"] -RESULT: timestampFromDateTime.call(["2322","9","25","10","42","2"])=11131123322 -RESULT: jsDate(11131123322)=2322/9/25 10:42:2 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11131123322) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11163171646)=["2323","10","1","9","0","46"] -RESULT: timestampFromDateTime.call(["2323","10","1","9","0","46"])=11163171646 -RESULT: jsDate(11163171646)=2323/10/1 9:0:46 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11163171646) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11194756261)=["2324","9","30","22","31","1"] -RESULT: timestampFromDateTime.call(["2324","9","30","22","31","1"])=11194756261 -RESULT: jsDate(11194756261)=2324/9/30 22:31:1 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11194756261) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11226804584)=["2325","10","6","20","49","44"] -RESULT: timestampFromDateTime.call(["2325","10","6","20","49","44"])=11226804584 -RESULT: jsDate(11226804584)=2325/10/6 20:49:44 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11226804584) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11258852908)=["2326","10","12","19","8","28"] -RESULT: timestampFromDateTime.call(["2326","10","12","19","8","28"])=11258852908 -RESULT: jsDate(11258852908)=2326/10/12 19:8:28 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11258852908) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11290437523)=["2327","10","13","8","38","43"] -RESULT: timestampFromDateTime.call(["2327","10","13","8","38","43"])=11290437523 -RESULT: jsDate(11290437523)=2327/10/13 8:38:43 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11290437523) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11322485846)=["2328","10","18","6","57","26"] -RESULT: timestampFromDateTime.call(["2328","10","18","6","57","26"])=11322485846 -RESULT: jsDate(11322485846)=2328/10/18 6:57:26 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11322485846) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11354534170)=["2329","10","24","5","16","10"] -RESULT: timestampFromDateTime.call(["2329","10","24","5","16","10"])=11354534170 -RESULT: jsDate(11354534170)=2329/10/24 5:16:10 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11354534170) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11386118785)=["2330","10","24","18","46","25"] -RESULT: timestampFromDateTime.call(["2330","10","24","18","46","25"])=11386118785 -RESULT: jsDate(11386118785)=2330/10/24 18:46:25 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11386118785) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11418167108)=["2331","10","30","17","5","8"] -RESULT: timestampFromDateTime.call(["2331","10","30","17","5","8"])=11418167108 -RESULT: jsDate(11418167108)=2331/10/30 17:5:8 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11418167108) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11450215432)=["2332","11","4","15","23","52"] -RESULT: timestampFromDateTime.call(["2332","11","4","15","23","52"])=11450215432 -RESULT: jsDate(11450215432)=2332/11/4 15:23:52 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11450215432) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11481800047)=["2333","11","5","4","54","7"] -RESULT: timestampFromDateTime.call(["2333","11","5","4","54","7"])=11481800047 -RESULT: jsDate(11481800047)=2333/11/5 4:54:7 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11481800047) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11513848370)=["2334","11","11","3","12","50"] -RESULT: timestampFromDateTime.call(["2334","11","11","3","12","50"])=11513848370 -RESULT: jsDate(11513848370)=2334/11/11 3:12:50 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11513848370) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11545896694)=["2335","11","17","1","31","34"] -RESULT: timestampFromDateTime.call(["2335","11","17","1","31","34"])=11545896694 -RESULT: jsDate(11545896694)=2335/11/17 1:31:34 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11545896694) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11577481309)=["2336","11","16","15","1","49"] -RESULT: timestampFromDateTime.call(["2336","11","16","15","1","49"])=11577481309 -RESULT: jsDate(11577481309)=2336/11/16 15:1:49 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11577481309) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11609529632)=["2337","11","22","13","20","32"] -RESULT: timestampFromDateTime.call(["2337","11","22","13","20","32"])=11609529632 -RESULT: jsDate(11609529632)=2337/11/22 13:20:32 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11609529632) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11641577956)=["2338","11","28","11","39","16"] -RESULT: timestampFromDateTime.call(["2338","11","28","11","39","16"])=11641577956 -RESULT: jsDate(11641577956)=2338/11/28 11:39:16 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11641577956) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11673162571)=["2339","11","29","1","9","31"] -RESULT: timestampFromDateTime.call(["2339","11","29","1","9","31"])=11673162571 -RESULT: jsDate(11673162571)=2339/11/29 1:9:31 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11673162571) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11705210894)=["2340","12","3","23","28","14"] -RESULT: timestampFromDateTime.call(["2340","12","3","23","28","14"])=11705210894 -RESULT: jsDate(11705210894)=2340/12/3 23:28:14 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11705210894) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11737259218)=["2341","12","9","21","46","58"] -RESULT: timestampFromDateTime.call(["2341","12","9","21","46","58"])=11737259218 -RESULT: jsDate(11737259218)=2341/12/9 21:46:58 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11737259218) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11768843833)=["2342","12","10","11","17","13"] -RESULT: timestampFromDateTime.call(["2342","12","10","11","17","13"])=11768843833 -RESULT: jsDate(11768843833)=2342/12/10 11:17:13 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11768843833) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11800892156)=["2343","12","16","9","35","56"] -RESULT: timestampFromDateTime.call(["2343","12","16","9","35","56"])=11800892156 -RESULT: jsDate(11800892156)=2343/12/16 9:35:56 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11800892156) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11832940480)=["2344","12","21","7","54","40"] -RESULT: timestampFromDateTime.call(["2344","12","21","7","54","40"])=11832940480 -RESULT: jsDate(11832940480)=2344/12/21 7:54:40 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11832940480) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11864525095)=["2345","12","21","21","24","55"] -RESULT: timestampFromDateTime.call(["2345","12","21","21","24","55"])=11864525095 -RESULT: jsDate(11864525095)=2345/12/21 21:24:55 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11864525095) => timestampFromDateTime.call(...) matches -RESULT: -RESULT: timestampToDateTime.call(11896573418)=["2346","12","27","19","43","38"] -RESULT: timestampFromDateTime.call(["2346","12","27","19","43","38"])=11896573418 -RESULT: jsDate(11896573418)=2346/12/27 19:43:38 -RESULT: PASS jsDate matches -RESULT: PASS timestampToDateTime.call(11896573418) => timestampFromDateTime.call(...) matches -RESULT: -undefined -> -> -... -... -... -... -RESULT: ---------- PASS - no failures detected ---------- -undefined -> -> -> diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1results.txt b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1results.txt deleted file mode 100644 index dff152a..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/test1results.txt +++ /dev/null @@ -1,2422 +0,0 @@ - # Account EtherBalanceChange Token Name --- ------------------------------------------ --------------------------- ------------------------------ --------------------------- - 0 0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e 0.000000000000000000 0.000000000000000000 Account #0 - Miner - 1 0xa11aae29840fbb5c86e6fd4cf809eba183aef433 0.000000000000000000 0.000000000000000000 Account #1 - Contract Owner - 2 0xa22ab8a9d641ce77e06d98b7d7065d324d3d6976 0.000000000000000000 0.000000000000000000 Account #2 - Alice - 3 0xa33a6c312d9ad0e0f2e95541beed0cc081621fd0 0.000000000000000000 0.000000000000000000 Account #3 - Bob - 4 0xa44a08d3f6933c69212114bb66e2df1813651844 0.000000000000000000 0.000000000000000000 Account #4 - Carol - 5 0xa55a151eb00fded1634d27d1127b4be4627079ea 0.000000000000000000 0.000000000000000000 Account #5 - Dave - 6 0xa66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 0.000000000000000000 0.000000000000000000 Account #6 - 7 0xa77a2b9d4b1c010a22a7c565dc418cef683dbcec 0.000000000000000000 0.000000000000000000 Account #7 - 8 0xa88a05d2b88283ce84c8325760b72a64591279a2 0.000000000000000000 0.000000000000000000 Account #8 - 9 0xa99a0ae3354c06b1459fd441a32a3f71005d7da0 0.000000000000000000 0.000000000000000000 Account #9 -10 0xaaaa9de1e6c564446ebca0fd102d8bd92093c756 0.000000000000000000 0.000000000000000000 Account #10 -11 0xabba43e7594e3b76afb157989e93c6621497fd4b 0.000000000000000000 0.000000000000000000 Account #11 --- ------------------------------------------ --------------------------- ------------------------------ --------------------------- - 0.000000000000000000 Total Token Balances --- ------------------------------------------ --------------------------- ------------------------------ --------------------------- - - ------ Deploy DateTime Library ----- - # Account EtherBalanceChange Token Name --- ------------------------------------------ --------------------------- ------------------------------ --------------------------- - 0 0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e 0.001150736000000000 0.000000000000000000 Account #0 - Miner - 1 0xa11aae29840fbb5c86e6fd4cf809eba183aef433 -0.001150736000000000 0.000000000000000000 Account #1 - Contract Owner - 2 0xa22ab8a9d641ce77e06d98b7d7065d324d3d6976 0.000000000000000000 0.000000000000000000 Account #2 - Alice - 3 0xa33a6c312d9ad0e0f2e95541beed0cc081621fd0 0.000000000000000000 0.000000000000000000 Account #3 - Bob - 4 0xa44a08d3f6933c69212114bb66e2df1813651844 0.000000000000000000 0.000000000000000000 Account #4 - Carol - 5 0xa55a151eb00fded1634d27d1127b4be4627079ea 0.000000000000000000 0.000000000000000000 Account #5 - Dave - 6 0xa66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 0.000000000000000000 0.000000000000000000 Account #6 - 7 0xa77a2b9d4b1c010a22a7c565dc418cef683dbcec 0.000000000000000000 0.000000000000000000 Account #7 - 8 0xa88a05d2b88283ce84c8325760b72a64591279a2 0.000000000000000000 0.000000000000000000 Account #8 - 9 0xa99a0ae3354c06b1459fd441a32a3f71005d7da0 0.000000000000000000 0.000000000000000000 Account #9 -10 0xaaaa9de1e6c564446ebca0fd102d8bd92093c756 0.000000000000000000 0.000000000000000000 Account #10 -11 0xabba43e7594e3b76afb157989e93c6621497fd4b 0.000000000000000000 0.000000000000000000 Account #11 -12 0x90d8927407c79c4a28ee879b821c76fc9bcc2688 0.000000000000000000 0.000000000000000000 DateTime Library --- ------------------------------------------ --------------------------- ------------------------------ --------------------------- - 0.000000000000000000 Total Token Balances --- ------------------------------------------ --------------------------- ------------------------------ --------------------------- - -PASS Deploy DateTime Library -dateTimeLibTx status=0x1 Success gas=6000000 gasUsed=71921 costETH=0.001150736 costUSD=0.77756382256 @ ETH/USD=675.71 gasPrice=16 gwei block=19 txIx=0 txId=0x3d6e997266a4df7a6d24ad8461a47646aa30ac31435f55bc7f8d22226d67cd14 @ 1579355189 Sat, 18 Jan 2020 13:46:29 UTC - ----------- Deploy TestDateTime Contract ---------- - # Account EtherBalanceChange Token Name --- ------------------------------------------ --------------------------- ------------------------------ --------------------------- - 0 0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e 0.016965312000000000 0.000000000000000000 Account #0 - Miner - 1 0xa11aae29840fbb5c86e6fd4cf809eba183aef433 -0.016965312000000000 0.000000000000000000 Account #1 - Contract Owner - 2 0xa22ab8a9d641ce77e06d98b7d7065d324d3d6976 0.000000000000000000 0.000000000000000000 Account #2 - Alice - 3 0xa33a6c312d9ad0e0f2e95541beed0cc081621fd0 0.000000000000000000 0.000000000000000000 Account #3 - Bob - 4 0xa44a08d3f6933c69212114bb66e2df1813651844 0.000000000000000000 0.000000000000000000 Account #4 - Carol - 5 0xa55a151eb00fded1634d27d1127b4be4627079ea 0.000000000000000000 0.000000000000000000 Account #5 - Dave - 6 0xa66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 0.000000000000000000 0.000000000000000000 Account #6 - 7 0xa77a2b9d4b1c010a22a7c565dc418cef683dbcec 0.000000000000000000 0.000000000000000000 Account #7 - 8 0xa88a05d2b88283ce84c8325760b72a64591279a2 0.000000000000000000 0.000000000000000000 Account #8 - 9 0xa99a0ae3354c06b1459fd441a32a3f71005d7da0 0.000000000000000000 0.000000000000000000 Account #9 -10 0xaaaa9de1e6c564446ebca0fd102d8bd92093c756 0.000000000000000000 0.000000000000000000 Account #10 -11 0xabba43e7594e3b76afb157989e93c6621497fd4b 0.000000000000000000 0.000000000000000000 Account #11 -12 0x90d8927407c79c4a28ee879b821c76fc9bcc2688 0.000000000000000000 0.000000000000000000 DateTime Library -13 0x0e946b999033257976aa5cbe0e3530618ca1582d 0.000000000000000000 0.000000000000000000 TestDateTime --- ------------------------------------------ --------------------------- ------------------------------ --------------------------- - 0.000000000000000000 Total Token Balances --- ------------------------------------------ --------------------------- ------------------------------ --------------------------- - -PASS Deploy TestDateTime Contract -testDateTimeAddress=0x0e946b999033257976aa5cbe0e3530618ca1582d status=0x1 Success gas=6000000 gasUsed=988411 costETH=0.015814576 costUSD=10.68606714896 @ ETH/USD=675.71 gasPrice=16 gwei block=21 txIx=0 txId=0xdb67f4d0ee1587cd570fc563c69f73dcaffc9f2f4047a1d1792218bb920fbd58 @ 1579355191 Sat, 18 Jan 2020 13:46:31 UTC - ----------- Test isLeapYear ---------- -PASS 2000,5,24,1,2,3 is a leap year -PASS 2100,5,24,1,2,3 is a not leap year -PASS 2104,5,24,1,2,3 is a leap year - ----------- Test isValidDate and isValidDateTime.call ---------- -PASS testDateTime.isValidDate.call(1969, 1, 1) is false -PASS testDateTime.isValidDate.call(1970, 1, 1) is true -PASS testDateTime.isValidDate.call(2000, 2, 29) is true -PASS testDateTime.isValidDate.call(2001, 2, 29) is false -PASS testDateTime.isValidDate.call(2001, 0, 1) is false -PASS testDateTime.isValidDate.call(2001, 1, 0) is false -PASS testDateTime.isValidDateTime.call(2000, 2, 29, 0, 0, 0) is true -PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 1) is true -PASS testDateTime.isValidDateTime.call(2000, 2, 29, 23, 1, 1) is true -PASS testDateTime.isValidDateTime.call(2000, 2, 29, 24, 1, 1) is false -PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 59, 1) is true -PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 60, 1) is false -PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 59) is true -PASS testDateTime.isValidDateTime.call(2000, 2, 29, 1, 1, 60) is false - ----------- Test _isLeapYear ---------- -PASS 2000 is a leap year -PASS 2100 is a not leap year -PASS 2104 is a leap year - ----------- Test isWeekDay ---------- -PASS 2018,5,24,1,2,3 is a week day -PASS 2018,5,25,1,2,3 is a week day -PASS 2018,5,26,1,2,3 is a not week day - ----------- Test isWeekEnd ---------- -PASS 2018,5,24,1,2,3 is a not a week end -PASS 2018,5,25,1,2,3 is a not a week end -PASS 2018,5,26,1,2,3 is a week end -PASS 2018,5,27,1,2,3 is a week end - ----------- Test getDaysInMonth ---------- -PASS 2000,1,24,1,2,3 has 31 days -PASS 2000,2,24,1,2,3 has 29 days -PASS 2001,2,24,1,2,3 has 28 days -PASS 2000,3,24,1,2,3 has 31 days -PASS 2000,4,24,1,2,3 has 30 days -PASS 2000,5,24,1,2,3 has 31 days -PASS 2000,6,24,1,2,3 has 30 days -PASS 2000,7,24,1,2,3 has 31 days -PASS 2000,8,24,1,2,3 has 31 days -PASS 2000,9,24,1,2,3 has 30 days -PASS 2000,10,24,1,2,3 has 31 days -PASS 2000,11,24,1,2,3 has 30 days -PASS 2000,12,24,1,2,3 has 31 days - ----------- Test _getDaysInMonth ---------- -PASS 2000/01 has 31 days -PASS 2000/02 has 29 days -PASS 2001/02 has 28 days -PASS 2000/03 has 31 days -PASS 2000/04 has 30 days -PASS 2000/05 has 31 days -PASS 2000/06 has 30 days -PASS 2000/07 has 31 days -PASS 2000/08 has 31 days -PASS 2000/09 has 30 days -PASS 2000/10 has 31 days -PASS 2000/11 has 30 days -PASS 2000/12 has 31 days - ----------- Test getDayOfWeek ---------- -PASS 2018,5,21,1,2,3 is 1 Monday -PASS 2018,5,24,1,2,3 is 4 Thursday -PASS 2018,5,26,1,2,3 is 6 Saturday -PASS 2018,5,27,1,2,3 is 7 Sunday - ----------- Test get* ---------- -PASS 2018,5,21,1,2,3 year is 2018 -PASS 2018,5,21,1,2,3 month is 5 May -PASS 2018,5,21,1,2,3 day is 21 -PASS 2018,5,21,1,2,3 hour is 1 -PASS 2018,5,21,1,2,3 minute is 2 -PASS 2018,5,21,1,2,3 second is 3 - ----------- Test add{Years|Months|Days|Hours|Minutes|Seconds} ---------- -PASS 2000,2,29,1,2,3 + 3 years is 2003/02/28 01:02:03 -PASS 2018,12,31,2,3,4 + 30 years is 2048/12/31 02:03:04 -PASS 2000,1,31,1,2,3 + 37 months is 2003/02/28 01:02:03 -PASS 2018,12,1,2,3,4 + 362 months is 2049/02/01 02:03:04 -PASS 2017,1,31,1,2,3 + 37,532 days is 2119/11/05 01:02:03 -PASS 2017,1,31,1,2,3 + 900,768 hours is 2119/11/05 01:02:03 -PASS 2017,1,31,1,2,3 + 781,920 minutes is 2018/07/28 01:02:03 -PASS 2017,1,31,1,2,3 + 461,548,800 seconds is 2031/09/17 01:02:03 - ----------- Test sub{Years|Months|Days|Hours|Minutes|Seconds} ---------- -PASS 2000,2,29,1,2,3 - 3 years is 1997/02/28 01:02:03 -PASS 2000,2,29,1,2,3 - 37 months is 1997/01/29 01:02:03 -PASS 2013,1,1,1,2,3 - 3,756 days is 2002/09/20 01:02:03 -PASS 2013,1,1,1,2,3 - 3,756 * 24 hours is 2002/09/20 01:02:03 -PASS 2015,7,15,1,2,3 - 223,776 hours is 1990/01/03 01:02:03 -PASS 2018,3,1,2,3,4 - 21,600,000 minutes is 1977/02/04 02:03:04 -PASS 2020,3,19,3,4,5 - 788,227,200 seconds is 1995/03/28 03:04:05 - ----------- Test diff{Years|Months|Days|Hours|Minutes|Seconds} ---------- -fromTimestamp=1508547723 2017,10,21,1,2,3 -toTimestamp=1563422706 2019,7,18,4,5,6 -PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 2 years diff -PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 21 months diff -PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 635 days diff -PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 15,243 hours diff -PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 914,583 minutes diff -PASS 2017,10,21,1,2,3 to 2019,7,18,4,5,6 has 54,874,983 seconds diff - ----------- Test timestampToDateTime.call(...) and timestampFromDateTime.call(...) against JavaScript Date ---------- -timestampToDateTime.call(48611)=["1970","1","1","13","30","11"] -timestampFromDateTime.call(["1970","1","1","13","30","11"])=48611 -jsDate(48611)=1970/1/1 13:30:11 -PASS jsDate matches -PASS timestampToDateTime.call(48611) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(32096934)=["1971","1","7","11","48","54"] -timestampFromDateTime.call(["1971","1","7","11","48","54"])=32096934 -jsDate(32096934)=1971/1/7 11:48:54 -PASS jsDate matches -PASS timestampToDateTime.call(32096934) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(64145254)=["1972","1","13","10","7","34"] -timestampFromDateTime.call(["1972","1","13","10","7","34"])=64145254 -jsDate(64145254)=1972/1/13 10:7:34 -PASS jsDate matches -PASS timestampToDateTime.call(64145254) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(95729869)=["1973","1","12","23","37","49"] -timestampFromDateTime.call(["1973","1","12","23","37","49"])=95729869 -jsDate(95729869)=1973/1/12 23:37:49 -PASS jsDate matches -PASS timestampToDateTime.call(95729869) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(127778192)=["1974","1","18","21","56","32"] -timestampFromDateTime.call(["1974","1","18","21","56","32"])=127778192 -jsDate(127778192)=1974/1/18 21:56:32 -PASS jsDate matches -PASS timestampToDateTime.call(127778192) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(159826516)=["1975","1","24","20","15","16"] -timestampFromDateTime.call(["1975","1","24","20","15","16"])=159826516 -jsDate(159826516)=1975/1/24 20:15:16 -PASS jsDate matches -PASS timestampToDateTime.call(159826516) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(191411131)=["1976","1","25","9","45","31"] -timestampFromDateTime.call(["1976","1","25","9","45","31"])=191411131 -jsDate(191411131)=1976/1/25 9:45:31 -PASS jsDate matches -PASS timestampToDateTime.call(191411131) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(223459454)=["1977","1","30","8","4","14"] -timestampFromDateTime.call(["1977","1","30","8","4","14"])=223459454 -jsDate(223459454)=1977/1/30 8:4:14 -PASS jsDate matches -PASS timestampToDateTime.call(223459454) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(255507778)=["1978","2","5","6","22","58"] -timestampFromDateTime.call(["1978","2","5","6","22","58"])=255507778 -jsDate(255507778)=1978/2/5 6:22:58 -PASS jsDate matches -PASS timestampToDateTime.call(255507778) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(287092393)=["1979","2","5","19","53","13"] -timestampFromDateTime.call(["1979","2","5","19","53","13"])=287092393 -jsDate(287092393)=1979/2/5 19:53:13 -PASS jsDate matches -PASS timestampToDateTime.call(287092393) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(319140716)=["1980","2","11","18","11","56"] -timestampFromDateTime.call(["1980","2","11","18","11","56"])=319140716 -jsDate(319140716)=1980/2/11 18:11:56 -PASS jsDate matches -PASS timestampToDateTime.call(319140716) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(351189040)=["1981","2","16","16","30","40"] -timestampFromDateTime.call(["1981","2","16","16","30","40"])=351189040 -jsDate(351189040)=1981/2/16 16:30:40 -PASS jsDate matches -PASS timestampToDateTime.call(351189040) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(382773655)=["1982","2","17","6","0","55"] -timestampFromDateTime.call(["1982","2","17","6","0","55"])=382773655 -jsDate(382773655)=1982/2/17 6:0:55 -PASS jsDate matches -PASS timestampToDateTime.call(382773655) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(414821978)=["1983","2","23","4","19","38"] -timestampFromDateTime.call(["1983","2","23","4","19","38"])=414821978 -jsDate(414821978)=1983/2/23 4:19:38 -PASS jsDate matches -PASS timestampToDateTime.call(414821978) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(446870302)=["1984","2","29","2","38","22"] -timestampFromDateTime.call(["1984","2","29","2","38","22"])=446870302 -jsDate(446870302)=1984/2/29 2:38:22 -PASS jsDate matches -PASS timestampToDateTime.call(446870302) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(478454917)=["1985","2","28","16","8","37"] -timestampFromDateTime.call(["1985","2","28","16","8","37"])=478454917 -jsDate(478454917)=1985/2/28 16:8:37 -PASS jsDate matches -PASS timestampToDateTime.call(478454917) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(510503240)=["1986","3","6","14","27","20"] -timestampFromDateTime.call(["1986","3","6","14","27","20"])=510503240 -jsDate(510503240)=1986/3/6 14:27:20 -PASS jsDate matches -PASS timestampToDateTime.call(510503240) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(542551564)=["1987","3","12","12","46","4"] -timestampFromDateTime.call(["1987","3","12","12","46","4"])=542551564 -jsDate(542551564)=1987/3/12 12:46:4 -PASS jsDate matches -PASS timestampToDateTime.call(542551564) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(574136179)=["1988","3","12","2","16","19"] -timestampFromDateTime.call(["1988","3","12","2","16","19"])=574136179 -jsDate(574136179)=1988/3/12 2:16:19 -PASS jsDate matches -PASS timestampToDateTime.call(574136179) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(606184502)=["1989","3","18","0","35","2"] -timestampFromDateTime.call(["1989","3","18","0","35","2"])=606184502 -jsDate(606184502)=1989/3/18 0:35:2 -PASS jsDate matches -PASS timestampToDateTime.call(606184502) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(638232826)=["1990","3","23","22","53","46"] -timestampFromDateTime.call(["1990","3","23","22","53","46"])=638232826 -jsDate(638232826)=1990/3/23 22:53:46 -PASS jsDate matches -PASS timestampToDateTime.call(638232826) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(669817441)=["1991","3","24","12","24","1"] -timestampFromDateTime.call(["1991","3","24","12","24","1"])=669817441 -jsDate(669817441)=1991/3/24 12:24:1 -PASS jsDate matches -PASS timestampToDateTime.call(669817441) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(701865764)=["1992","3","29","10","42","44"] -timestampFromDateTime.call(["1992","3","29","10","42","44"])=701865764 -jsDate(701865764)=1992/3/29 10:42:44 -PASS jsDate matches -PASS timestampToDateTime.call(701865764) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(733914088)=["1993","4","4","9","1","28"] -timestampFromDateTime.call(["1993","4","4","9","1","28"])=733914088 -jsDate(733914088)=1993/4/4 9:1:28 -PASS jsDate matches -PASS timestampToDateTime.call(733914088) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(765498703)=["1994","4","4","22","31","43"] -timestampFromDateTime.call(["1994","4","4","22","31","43"])=765498703 -jsDate(765498703)=1994/4/4 22:31:43 -PASS jsDate matches -PASS timestampToDateTime.call(765498703) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(797547026)=["1995","4","10","20","50","26"] -timestampFromDateTime.call(["1995","4","10","20","50","26"])=797547026 -jsDate(797547026)=1995/4/10 20:50:26 -PASS jsDate matches -PASS timestampToDateTime.call(797547026) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(829595350)=["1996","4","15","19","9","10"] -timestampFromDateTime.call(["1996","4","15","19","9","10"])=829595350 -jsDate(829595350)=1996/4/15 19:9:10 -PASS jsDate matches -PASS timestampToDateTime.call(829595350) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(861179965)=["1997","4","16","8","39","25"] -timestampFromDateTime.call(["1997","4","16","8","39","25"])=861179965 -jsDate(861179965)=1997/4/16 8:39:25 -PASS jsDate matches -PASS timestampToDateTime.call(861179965) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(893228288)=["1998","4","22","6","58","8"] -timestampFromDateTime.call(["1998","4","22","6","58","8"])=893228288 -jsDate(893228288)=1998/4/22 6:58:8 -PASS jsDate matches -PASS timestampToDateTime.call(893228288) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(925276612)=["1999","4","28","5","16","52"] -timestampFromDateTime.call(["1999","4","28","5","16","52"])=925276612 -jsDate(925276612)=1999/4/28 5:16:52 -PASS jsDate matches -PASS timestampToDateTime.call(925276612) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(956861227)=["2000","4","27","18","47","7"] -timestampFromDateTime.call(["2000","4","27","18","47","7"])=956861227 -jsDate(956861227)=2000/4/27 18:47:7 -PASS jsDate matches -PASS timestampToDateTime.call(956861227) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(988909550)=["2001","5","3","17","5","50"] -timestampFromDateTime.call(["2001","5","3","17","5","50"])=988909550 -jsDate(988909550)=2001/5/3 17:5:50 -PASS jsDate matches -PASS timestampToDateTime.call(988909550) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1020957874)=["2002","5","9","15","24","34"] -timestampFromDateTime.call(["2002","5","9","15","24","34"])=1020957874 -jsDate(1020957874)=2002/5/9 15:24:34 -PASS jsDate matches -PASS timestampToDateTime.call(1020957874) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1052542489)=["2003","5","10","4","54","49"] -timestampFromDateTime.call(["2003","5","10","4","54","49"])=1052542489 -jsDate(1052542489)=2003/5/10 4:54:49 -PASS jsDate matches -PASS timestampToDateTime.call(1052542489) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1084590812)=["2004","5","15","3","13","32"] -timestampFromDateTime.call(["2004","5","15","3","13","32"])=1084590812 -jsDate(1084590812)=2004/5/15 3:13:32 -PASS jsDate matches -PASS timestampToDateTime.call(1084590812) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1116639136)=["2005","5","21","1","32","16"] -timestampFromDateTime.call(["2005","5","21","1","32","16"])=1116639136 -jsDate(1116639136)=2005/5/21 1:32:16 -PASS jsDate matches -PASS timestampToDateTime.call(1116639136) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1148223751)=["2006","5","21","15","2","31"] -timestampFromDateTime.call(["2006","5","21","15","2","31"])=1148223751 -jsDate(1148223751)=2006/5/21 15:2:31 -PASS jsDate matches -PASS timestampToDateTime.call(1148223751) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1180272074)=["2007","5","27","13","21","14"] -timestampFromDateTime.call(["2007","5","27","13","21","14"])=1180272074 -jsDate(1180272074)=2007/5/27 13:21:14 -PASS jsDate matches -PASS timestampToDateTime.call(1180272074) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1212320398)=["2008","6","1","11","39","58"] -timestampFromDateTime.call(["2008","6","1","11","39","58"])=1212320398 -jsDate(1212320398)=2008/6/1 11:39:58 -PASS jsDate matches -PASS timestampToDateTime.call(1212320398) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1243905013)=["2009","6","2","1","10","13"] -timestampFromDateTime.call(["2009","6","2","1","10","13"])=1243905013 -jsDate(1243905013)=2009/6/2 1:10:13 -PASS jsDate matches -PASS timestampToDateTime.call(1243905013) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1275953336)=["2010","6","7","23","28","56"] -timestampFromDateTime.call(["2010","6","7","23","28","56"])=1275953336 -jsDate(1275953336)=2010/6/7 23:28:56 -PASS jsDate matches -PASS timestampToDateTime.call(1275953336) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1308001660)=["2011","6","13","21","47","40"] -timestampFromDateTime.call(["2011","6","13","21","47","40"])=1308001660 -jsDate(1308001660)=2011/6/13 21:47:40 -PASS jsDate matches -PASS timestampToDateTime.call(1308001660) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1339586275)=["2012","6","13","11","17","55"] -timestampFromDateTime.call(["2012","6","13","11","17","55"])=1339586275 -jsDate(1339586275)=2012/6/13 11:17:55 -PASS jsDate matches -PASS timestampToDateTime.call(1339586275) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1371634598)=["2013","6","19","9","36","38"] -timestampFromDateTime.call(["2013","6","19","9","36","38"])=1371634598 -jsDate(1371634598)=2013/6/19 9:36:38 -PASS jsDate matches -PASS timestampToDateTime.call(1371634598) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1403682922)=["2014","6","25","7","55","22"] -timestampFromDateTime.call(["2014","6","25","7","55","22"])=1403682922 -jsDate(1403682922)=2014/6/25 7:55:22 -PASS jsDate matches -PASS timestampToDateTime.call(1403682922) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1435267537)=["2015","6","25","21","25","37"] -timestampFromDateTime.call(["2015","6","25","21","25","37"])=1435267537 -jsDate(1435267537)=2015/6/25 21:25:37 -PASS jsDate matches -PASS timestampToDateTime.call(1435267537) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1467315860)=["2016","6","30","19","44","20"] -timestampFromDateTime.call(["2016","6","30","19","44","20"])=1467315860 -jsDate(1467315860)=2016/6/30 19:44:20 -PASS jsDate matches -PASS timestampToDateTime.call(1467315860) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1499364184)=["2017","7","6","18","3","4"] -timestampFromDateTime.call(["2017","7","6","18","3","4"])=1499364184 -jsDate(1499364184)=2017/7/6 18:3:4 -PASS jsDate matches -PASS timestampToDateTime.call(1499364184) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1530948799)=["2018","7","7","7","33","19"] -timestampFromDateTime.call(["2018","7","7","7","33","19"])=1530948799 -jsDate(1530948799)=2018/7/7 7:33:19 -PASS jsDate matches -PASS timestampToDateTime.call(1530948799) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1562997122)=["2019","7","13","5","52","2"] -timestampFromDateTime.call(["2019","7","13","5","52","2"])=1562997122 -jsDate(1562997122)=2019/7/13 5:52:2 -PASS jsDate matches -PASS timestampToDateTime.call(1562997122) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1595045446)=["2020","7","18","4","10","46"] -timestampFromDateTime.call(["2020","7","18","4","10","46"])=1595045446 -jsDate(1595045446)=2020/7/18 4:10:46 -PASS jsDate matches -PASS timestampToDateTime.call(1595045446) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1626630061)=["2021","7","18","17","41","1"] -timestampFromDateTime.call(["2021","7","18","17","41","1"])=1626630061 -jsDate(1626630061)=2021/7/18 17:41:1 -PASS jsDate matches -PASS timestampToDateTime.call(1626630061) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1658678384)=["2022","7","24","15","59","44"] -timestampFromDateTime.call(["2022","7","24","15","59","44"])=1658678384 -jsDate(1658678384)=2022/7/24 15:59:44 -PASS jsDate matches -PASS timestampToDateTime.call(1658678384) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1690726708)=["2023","7","30","14","18","28"] -timestampFromDateTime.call(["2023","7","30","14","18","28"])=1690726708 -jsDate(1690726708)=2023/7/30 14:18:28 -PASS jsDate matches -PASS timestampToDateTime.call(1690726708) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1722311323)=["2024","7","30","3","48","43"] -timestampFromDateTime.call(["2024","7","30","3","48","43"])=1722311323 -jsDate(1722311323)=2024/7/30 3:48:43 -PASS jsDate matches -PASS timestampToDateTime.call(1722311323) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1754359646)=["2025","8","5","2","7","26"] -timestampFromDateTime.call(["2025","8","5","2","7","26"])=1754359646 -jsDate(1754359646)=2025/8/5 2:7:26 -PASS jsDate matches -PASS timestampToDateTime.call(1754359646) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1786407970)=["2026","8","11","0","26","10"] -timestampFromDateTime.call(["2026","8","11","0","26","10"])=1786407970 -jsDate(1786407970)=2026/8/11 0:26:10 -PASS jsDate matches -PASS timestampToDateTime.call(1786407970) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1817992585)=["2027","8","11","13","56","25"] -timestampFromDateTime.call(["2027","8","11","13","56","25"])=1817992585 -jsDate(1817992585)=2027/8/11 13:56:25 -PASS jsDate matches -PASS timestampToDateTime.call(1817992585) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1850040908)=["2028","8","16","12","15","8"] -timestampFromDateTime.call(["2028","8","16","12","15","8"])=1850040908 -jsDate(1850040908)=2028/8/16 12:15:8 -PASS jsDate matches -PASS timestampToDateTime.call(1850040908) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1882089232)=["2029","8","22","10","33","52"] -timestampFromDateTime.call(["2029","8","22","10","33","52"])=1882089232 -jsDate(1882089232)=2029/8/22 10:33:52 -PASS jsDate matches -PASS timestampToDateTime.call(1882089232) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1913673847)=["2030","8","23","0","4","7"] -timestampFromDateTime.call(["2030","8","23","0","4","7"])=1913673847 -jsDate(1913673847)=2030/8/23 0:4:7 -PASS jsDate matches -PASS timestampToDateTime.call(1913673847) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1945722170)=["2031","8","28","22","22","50"] -timestampFromDateTime.call(["2031","8","28","22","22","50"])=1945722170 -jsDate(1945722170)=2031/8/28 22:22:50 -PASS jsDate matches -PASS timestampToDateTime.call(1945722170) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(1977770494)=["2032","9","2","20","41","34"] -timestampFromDateTime.call(["2032","9","2","20","41","34"])=1977770494 -jsDate(1977770494)=2032/9/2 20:41:34 -PASS jsDate matches -PASS timestampToDateTime.call(1977770494) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2009355109)=["2033","9","3","10","11","49"] -timestampFromDateTime.call(["2033","9","3","10","11","49"])=2009355109 -jsDate(2009355109)=2033/9/3 10:11:49 -PASS jsDate matches -PASS timestampToDateTime.call(2009355109) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2041403432)=["2034","9","9","8","30","32"] -timestampFromDateTime.call(["2034","9","9","8","30","32"])=2041403432 -jsDate(2041403432)=2034/9/9 8:30:32 -PASS jsDate matches -PASS timestampToDateTime.call(2041403432) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2073451756)=["2035","9","15","6","49","16"] -timestampFromDateTime.call(["2035","9","15","6","49","16"])=2073451756 -jsDate(2073451756)=2035/9/15 6:49:16 -PASS jsDate matches -PASS timestampToDateTime.call(2073451756) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2105036371)=["2036","9","14","20","19","31"] -timestampFromDateTime.call(["2036","9","14","20","19","31"])=2105036371 -jsDate(2105036371)=2036/9/14 20:19:31 -PASS jsDate matches -PASS timestampToDateTime.call(2105036371) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2137084694)=["2037","9","20","18","38","14"] -timestampFromDateTime.call(["2037","9","20","18","38","14"])=2137084694 -jsDate(2137084694)=2037/9/20 18:38:14 -PASS jsDate matches -PASS timestampToDateTime.call(2137084694) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2169133018)=["2038","9","26","16","56","58"] -timestampFromDateTime.call(["2038","9","26","16","56","58"])=2169133018 -jsDate(2169133018)=2038/9/26 16:56:58 -PASS jsDate matches -PASS timestampToDateTime.call(2169133018) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2200717633)=["2039","9","27","6","27","13"] -timestampFromDateTime.call(["2039","9","27","6","27","13"])=2200717633 -jsDate(2200717633)=2039/9/27 6:27:13 -PASS jsDate matches -PASS timestampToDateTime.call(2200717633) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2232765956)=["2040","10","2","4","45","56"] -timestampFromDateTime.call(["2040","10","2","4","45","56"])=2232765956 -jsDate(2232765956)=2040/10/2 4:45:56 -PASS jsDate matches -PASS timestampToDateTime.call(2232765956) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2264814280)=["2041","10","8","3","4","40"] -timestampFromDateTime.call(["2041","10","8","3","4","40"])=2264814280 -jsDate(2264814280)=2041/10/8 3:4:40 -PASS jsDate matches -PASS timestampToDateTime.call(2264814280) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2296398895)=["2042","10","8","16","34","55"] -timestampFromDateTime.call(["2042","10","8","16","34","55"])=2296398895 -jsDate(2296398895)=2042/10/8 16:34:55 -PASS jsDate matches -PASS timestampToDateTime.call(2296398895) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2328447218)=["2043","10","14","14","53","38"] -timestampFromDateTime.call(["2043","10","14","14","53","38"])=2328447218 -jsDate(2328447218)=2043/10/14 14:53:38 -PASS jsDate matches -PASS timestampToDateTime.call(2328447218) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2360495542)=["2044","10","19","13","12","22"] -timestampFromDateTime.call(["2044","10","19","13","12","22"])=2360495542 -jsDate(2360495542)=2044/10/19 13:12:22 -PASS jsDate matches -PASS timestampToDateTime.call(2360495542) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2392080157)=["2045","10","20","2","42","37"] -timestampFromDateTime.call(["2045","10","20","2","42","37"])=2392080157 -jsDate(2392080157)=2045/10/20 2:42:37 -PASS jsDate matches -PASS timestampToDateTime.call(2392080157) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2424128480)=["2046","10","26","1","1","20"] -timestampFromDateTime.call(["2046","10","26","1","1","20"])=2424128480 -jsDate(2424128480)=2046/10/26 1:1:20 -PASS jsDate matches -PASS timestampToDateTime.call(2424128480) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2456176804)=["2047","10","31","23","20","4"] -timestampFromDateTime.call(["2047","10","31","23","20","4"])=2456176804 -jsDate(2456176804)=2047/10/31 23:20:4 -PASS jsDate matches -PASS timestampToDateTime.call(2456176804) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2487761419)=["2048","10","31","12","50","19"] -timestampFromDateTime.call(["2048","10","31","12","50","19"])=2487761419 -jsDate(2487761419)=2048/10/31 12:50:19 -PASS jsDate matches -PASS timestampToDateTime.call(2487761419) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2519809742)=["2049","11","6","11","9","2"] -timestampFromDateTime.call(["2049","11","6","11","9","2"])=2519809742 -jsDate(2519809742)=2049/11/6 11:9:2 -PASS jsDate matches -PASS timestampToDateTime.call(2519809742) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2551858066)=["2050","11","12","9","27","46"] -timestampFromDateTime.call(["2050","11","12","9","27","46"])=2551858066 -jsDate(2551858066)=2050/11/12 9:27:46 -PASS jsDate matches -PASS timestampToDateTime.call(2551858066) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2583442681)=["2051","11","12","22","58","1"] -timestampFromDateTime.call(["2051","11","12","22","58","1"])=2583442681 -jsDate(2583442681)=2051/11/12 22:58:1 -PASS jsDate matches -PASS timestampToDateTime.call(2583442681) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2615491004)=["2052","11","17","21","16","44"] -timestampFromDateTime.call(["2052","11","17","21","16","44"])=2615491004 -jsDate(2615491004)=2052/11/17 21:16:44 -PASS jsDate matches -PASS timestampToDateTime.call(2615491004) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2647539328)=["2053","11","23","19","35","28"] -timestampFromDateTime.call(["2053","11","23","19","35","28"])=2647539328 -jsDate(2647539328)=2053/11/23 19:35:28 -PASS jsDate matches -PASS timestampToDateTime.call(2647539328) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2679123943)=["2054","11","24","9","5","43"] -timestampFromDateTime.call(["2054","11","24","9","5","43"])=2679123943 -jsDate(2679123943)=2054/11/24 9:5:43 -PASS jsDate matches -PASS timestampToDateTime.call(2679123943) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2711172266)=["2055","11","30","7","24","26"] -timestampFromDateTime.call(["2055","11","30","7","24","26"])=2711172266 -jsDate(2711172266)=2055/11/30 7:24:26 -PASS jsDate matches -PASS timestampToDateTime.call(2711172266) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2743220590)=["2056","12","5","5","43","10"] -timestampFromDateTime.call(["2056","12","5","5","43","10"])=2743220590 -jsDate(2743220590)=2056/12/5 5:43:10 -PASS jsDate matches -PASS timestampToDateTime.call(2743220590) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2774805205)=["2057","12","5","19","13","25"] -timestampFromDateTime.call(["2057","12","5","19","13","25"])=2774805205 -jsDate(2774805205)=2057/12/5 19:13:25 -PASS jsDate matches -PASS timestampToDateTime.call(2774805205) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2806853528)=["2058","12","11","17","32","8"] -timestampFromDateTime.call(["2058","12","11","17","32","8"])=2806853528 -jsDate(2806853528)=2058/12/11 17:32:8 -PASS jsDate matches -PASS timestampToDateTime.call(2806853528) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2838901852)=["2059","12","17","15","50","52"] -timestampFromDateTime.call(["2059","12","17","15","50","52"])=2838901852 -jsDate(2838901852)=2059/12/17 15:50:52 -PASS jsDate matches -PASS timestampToDateTime.call(2838901852) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2870486467)=["2060","12","17","5","21","7"] -timestampFromDateTime.call(["2060","12","17","5","21","7"])=2870486467 -jsDate(2870486467)=2060/12/17 5:21:7 -PASS jsDate matches -PASS timestampToDateTime.call(2870486467) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2902534790)=["2061","12","23","3","39","50"] -timestampFromDateTime.call(["2061","12","23","3","39","50"])=2902534790 -jsDate(2902534790)=2061/12/23 3:39:50 -PASS jsDate matches -PASS timestampToDateTime.call(2902534790) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2934583114)=["2062","12","29","1","58","34"] -timestampFromDateTime.call(["2062","12","29","1","58","34"])=2934583114 -jsDate(2934583114)=2062/12/29 1:58:34 -PASS jsDate matches -PASS timestampToDateTime.call(2934583114) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2966167729)=["2063","12","29","15","28","49"] -timestampFromDateTime.call(["2063","12","29","15","28","49"])=2966167729 -jsDate(2966167729)=2063/12/29 15:28:49 -PASS jsDate matches -PASS timestampToDateTime.call(2966167729) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(2998216052)=["2065","1","3","13","47","32"] -timestampFromDateTime.call(["2065","1","3","13","47","32"])=2998216052 -jsDate(2998216052)=2065/1/3 13:47:32 -PASS jsDate matches -PASS timestampToDateTime.call(2998216052) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3030264376)=["2066","1","9","12","6","16"] -timestampFromDateTime.call(["2066","1","9","12","6","16"])=3030264376 -jsDate(3030264376)=2066/1/9 12:6:16 -PASS jsDate matches -PASS timestampToDateTime.call(3030264376) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3061848991)=["2067","1","10","1","36","31"] -timestampFromDateTime.call(["2067","1","10","1","36","31"])=3061848991 -jsDate(3061848991)=2067/1/10 1:36:31 -PASS jsDate matches -PASS timestampToDateTime.call(3061848991) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3093897314)=["2068","1","15","23","55","14"] -timestampFromDateTime.call(["2068","1","15","23","55","14"])=3093897314 -jsDate(3093897314)=2068/1/15 23:55:14 -PASS jsDate matches -PASS timestampToDateTime.call(3093897314) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3125945638)=["2069","1","20","22","13","58"] -timestampFromDateTime.call(["2069","1","20","22","13","58"])=3125945638 -jsDate(3125945638)=2069/1/20 22:13:58 -PASS jsDate matches -PASS timestampToDateTime.call(3125945638) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3157530253)=["2070","1","21","11","44","13"] -timestampFromDateTime.call(["2070","1","21","11","44","13"])=3157530253 -jsDate(3157530253)=2070/1/21 11:44:13 -PASS jsDate matches -PASS timestampToDateTime.call(3157530253) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3189578576)=["2071","1","27","10","2","56"] -timestampFromDateTime.call(["2071","1","27","10","2","56"])=3189578576 -jsDate(3189578576)=2071/1/27 10:2:56 -PASS jsDate matches -PASS timestampToDateTime.call(3189578576) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3221626900)=["2072","2","2","8","21","40"] -timestampFromDateTime.call(["2072","2","2","8","21","40"])=3221626900 -jsDate(3221626900)=2072/2/2 8:21:40 -PASS jsDate matches -PASS timestampToDateTime.call(3221626900) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3253211515)=["2073","2","1","21","51","55"] -timestampFromDateTime.call(["2073","2","1","21","51","55"])=3253211515 -jsDate(3253211515)=2073/2/1 21:51:55 -PASS jsDate matches -PASS timestampToDateTime.call(3253211515) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3285259838)=["2074","2","7","20","10","38"] -timestampFromDateTime.call(["2074","2","7","20","10","38"])=3285259838 -jsDate(3285259838)=2074/2/7 20:10:38 -PASS jsDate matches -PASS timestampToDateTime.call(3285259838) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3317308162)=["2075","2","13","18","29","22"] -timestampFromDateTime.call(["2075","2","13","18","29","22"])=3317308162 -jsDate(3317308162)=2075/2/13 18:29:22 -PASS jsDate matches -PASS timestampToDateTime.call(3317308162) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3348892777)=["2076","2","14","7","59","37"] -timestampFromDateTime.call(["2076","2","14","7","59","37"])=3348892777 -jsDate(3348892777)=2076/2/14 7:59:37 -PASS jsDate matches -PASS timestampToDateTime.call(3348892777) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3380941100)=["2077","2","19","6","18","20"] -timestampFromDateTime.call(["2077","2","19","6","18","20"])=3380941100 -jsDate(3380941100)=2077/2/19 6:18:20 -PASS jsDate matches -PASS timestampToDateTime.call(3380941100) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3412989424)=["2078","2","25","4","37","4"] -timestampFromDateTime.call(["2078","2","25","4","37","4"])=3412989424 -jsDate(3412989424)=2078/2/25 4:37:4 -PASS jsDate matches -PASS timestampToDateTime.call(3412989424) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3444574039)=["2079","2","25","18","7","19"] -timestampFromDateTime.call(["2079","2","25","18","7","19"])=3444574039 -jsDate(3444574039)=2079/2/25 18:7:19 -PASS jsDate matches -PASS timestampToDateTime.call(3444574039) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3476622362)=["2080","3","2","16","26","2"] -timestampFromDateTime.call(["2080","3","2","16","26","2"])=3476622362 -jsDate(3476622362)=2080/3/2 16:26:2 -PASS jsDate matches -PASS timestampToDateTime.call(3476622362) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3508670686)=["2081","3","8","14","44","46"] -timestampFromDateTime.call(["2081","3","8","14","44","46"])=3508670686 -jsDate(3508670686)=2081/3/8 14:44:46 -PASS jsDate matches -PASS timestampToDateTime.call(3508670686) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3540255301)=["2082","3","9","4","15","1"] -timestampFromDateTime.call(["2082","3","9","4","15","1"])=3540255301 -jsDate(3540255301)=2082/3/9 4:15:1 -PASS jsDate matches -PASS timestampToDateTime.call(3540255301) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3572303624)=["2083","3","15","2","33","44"] -timestampFromDateTime.call(["2083","3","15","2","33","44"])=3572303624 -jsDate(3572303624)=2083/3/15 2:33:44 -PASS jsDate matches -PASS timestampToDateTime.call(3572303624) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3604351948)=["2084","3","20","0","52","28"] -timestampFromDateTime.call(["2084","3","20","0","52","28"])=3604351948 -jsDate(3604351948)=2084/3/20 0:52:28 -PASS jsDate matches -PASS timestampToDateTime.call(3604351948) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3635936563)=["2085","3","20","14","22","43"] -timestampFromDateTime.call(["2085","3","20","14","22","43"])=3635936563 -jsDate(3635936563)=2085/3/20 14:22:43 -PASS jsDate matches -PASS timestampToDateTime.call(3635936563) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3667984886)=["2086","3","26","12","41","26"] -timestampFromDateTime.call(["2086","3","26","12","41","26"])=3667984886 -jsDate(3667984886)=2086/3/26 12:41:26 -PASS jsDate matches -PASS timestampToDateTime.call(3667984886) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3700033210)=["2087","4","1","11","0","10"] -timestampFromDateTime.call(["2087","4","1","11","0","10"])=3700033210 -jsDate(3700033210)=2087/4/1 11:0:10 -PASS jsDate matches -PASS timestampToDateTime.call(3700033210) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3731617825)=["2088","4","1","0","30","25"] -timestampFromDateTime.call(["2088","4","1","0","30","25"])=3731617825 -jsDate(3731617825)=2088/4/1 0:30:25 -PASS jsDate matches -PASS timestampToDateTime.call(3731617825) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3763666148)=["2089","4","6","22","49","8"] -timestampFromDateTime.call(["2089","4","6","22","49","8"])=3763666148 -jsDate(3763666148)=2089/4/6 22:49:8 -PASS jsDate matches -PASS timestampToDateTime.call(3763666148) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3795714472)=["2090","4","12","21","7","52"] -timestampFromDateTime.call(["2090","4","12","21","7","52"])=3795714472 -jsDate(3795714472)=2090/4/12 21:7:52 -PASS jsDate matches -PASS timestampToDateTime.call(3795714472) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3827299087)=["2091","4","13","10","38","7"] -timestampFromDateTime.call(["2091","4","13","10","38","7"])=3827299087 -jsDate(3827299087)=2091/4/13 10:38:7 -PASS jsDate matches -PASS timestampToDateTime.call(3827299087) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3859347410)=["2092","4","18","8","56","50"] -timestampFromDateTime.call(["2092","4","18","8","56","50"])=3859347410 -jsDate(3859347410)=2092/4/18 8:56:50 -PASS jsDate matches -PASS timestampToDateTime.call(3859347410) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3891395734)=["2093","4","24","7","15","34"] -timestampFromDateTime.call(["2093","4","24","7","15","34"])=3891395734 -jsDate(3891395734)=2093/4/24 7:15:34 -PASS jsDate matches -PASS timestampToDateTime.call(3891395734) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3922980349)=["2094","4","24","20","45","49"] -timestampFromDateTime.call(["2094","4","24","20","45","49"])=3922980349 -jsDate(3922980349)=2094/4/24 20:45:49 -PASS jsDate matches -PASS timestampToDateTime.call(3922980349) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3955028672)=["2095","4","30","19","4","32"] -timestampFromDateTime.call(["2095","4","30","19","4","32"])=3955028672 -jsDate(3955028672)=2095/4/30 19:4:32 -PASS jsDate matches -PASS timestampToDateTime.call(3955028672) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(3987076996)=["2096","5","5","17","23","16"] -timestampFromDateTime.call(["2096","5","5","17","23","16"])=3987076996 -jsDate(3987076996)=2096/5/5 17:23:16 -PASS jsDate matches -PASS timestampToDateTime.call(3987076996) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4018661611)=["2097","5","6","6","53","31"] -timestampFromDateTime.call(["2097","5","6","6","53","31"])=4018661611 -jsDate(4018661611)=2097/5/6 6:53:31 -PASS jsDate matches -PASS timestampToDateTime.call(4018661611) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4050709934)=["2098","5","12","5","12","14"] -timestampFromDateTime.call(["2098","5","12","5","12","14"])=4050709934 -jsDate(4050709934)=2098/5/12 5:12:14 -PASS jsDate matches -PASS timestampToDateTime.call(4050709934) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4082758258)=["2099","5","18","3","30","58"] -timestampFromDateTime.call(["2099","5","18","3","30","58"])=4082758258 -jsDate(4082758258)=2099/5/18 3:30:58 -PASS jsDate matches -PASS timestampToDateTime.call(4082758258) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4114342873)=["2100","5","18","17","1","13"] -timestampFromDateTime.call(["2100","5","18","17","1","13"])=4114342873 -jsDate(4114342873)=2100/5/18 17:1:13 -PASS jsDate matches -PASS timestampToDateTime.call(4114342873) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4146391196)=["2101","5","24","15","19","56"] -timestampFromDateTime.call(["2101","5","24","15","19","56"])=4146391196 -jsDate(4146391196)=2101/5/24 15:19:56 -PASS jsDate matches -PASS timestampToDateTime.call(4146391196) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4178439520)=["2102","5","30","13","38","40"] -timestampFromDateTime.call(["2102","5","30","13","38","40"])=4178439520 -jsDate(4178439520)=2102/5/30 13:38:40 -PASS jsDate matches -PASS timestampToDateTime.call(4178439520) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4210024135)=["2103","5","31","3","8","55"] -timestampFromDateTime.call(["2103","5","31","3","8","55"])=4210024135 -jsDate(4210024135)=2103/5/31 3:8:55 -PASS jsDate matches -PASS timestampToDateTime.call(4210024135) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4242072458)=["2104","6","5","1","27","38"] -timestampFromDateTime.call(["2104","6","5","1","27","38"])=4242072458 -jsDate(4242072458)=2104/6/5 1:27:38 -PASS jsDate matches -PASS timestampToDateTime.call(4242072458) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4274120782)=["2105","6","10","23","46","22"] -timestampFromDateTime.call(["2105","6","10","23","46","22"])=4274120782 -jsDate(4274120782)=2105/6/10 23:46:22 -PASS jsDate matches -PASS timestampToDateTime.call(4274120782) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4305705397)=["2106","6","11","13","16","37"] -timestampFromDateTime.call(["2106","6","11","13","16","37"])=4305705397 -jsDate(4305705397)=2106/6/11 13:16:37 -PASS jsDate matches -PASS timestampToDateTime.call(4305705397) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4337753720)=["2107","6","17","11","35","20"] -timestampFromDateTime.call(["2107","6","17","11","35","20"])=4337753720 -jsDate(4337753720)=2107/6/17 11:35:20 -PASS jsDate matches -PASS timestampToDateTime.call(4337753720) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4369802044)=["2108","6","22","9","54","4"] -timestampFromDateTime.call(["2108","6","22","9","54","4"])=4369802044 -jsDate(4369802044)=2108/6/22 9:54:4 -PASS jsDate matches -PASS timestampToDateTime.call(4369802044) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4401386659)=["2109","6","22","23","24","19"] -timestampFromDateTime.call(["2109","6","22","23","24","19"])=4401386659 -jsDate(4401386659)=2109/6/22 23:24:19 -PASS jsDate matches -PASS timestampToDateTime.call(4401386659) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4433434982)=["2110","6","28","21","43","2"] -timestampFromDateTime.call(["2110","6","28","21","43","2"])=4433434982 -jsDate(4433434982)=2110/6/28 21:43:2 -PASS jsDate matches -PASS timestampToDateTime.call(4433434982) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4465483306)=["2111","7","4","20","1","46"] -timestampFromDateTime.call(["2111","7","4","20","1","46"])=4465483306 -jsDate(4465483306)=2111/7/4 20:1:46 -PASS jsDate matches -PASS timestampToDateTime.call(4465483306) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4497067921)=["2112","7","4","9","32","1"] -timestampFromDateTime.call(["2112","7","4","9","32","1"])=4497067921 -jsDate(4497067921)=2112/7/4 9:32:1 -PASS jsDate matches -PASS timestampToDateTime.call(4497067921) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4529116244)=["2113","7","10","7","50","44"] -timestampFromDateTime.call(["2113","7","10","7","50","44"])=4529116244 -jsDate(4529116244)=2113/7/10 7:50:44 -PASS jsDate matches -PASS timestampToDateTime.call(4529116244) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4561164568)=["2114","7","16","6","9","28"] -timestampFromDateTime.call(["2114","7","16","6","9","28"])=4561164568 -jsDate(4561164568)=2114/7/16 6:9:28 -PASS jsDate matches -PASS timestampToDateTime.call(4561164568) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4592749183)=["2115","7","16","19","39","43"] -timestampFromDateTime.call(["2115","7","16","19","39","43"])=4592749183 -jsDate(4592749183)=2115/7/16 19:39:43 -PASS jsDate matches -PASS timestampToDateTime.call(4592749183) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4624797506)=["2116","7","21","17","58","26"] -timestampFromDateTime.call(["2116","7","21","17","58","26"])=4624797506 -jsDate(4624797506)=2116/7/21 17:58:26 -PASS jsDate matches -PASS timestampToDateTime.call(4624797506) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4656845830)=["2117","7","27","16","17","10"] -timestampFromDateTime.call(["2117","7","27","16","17","10"])=4656845830 -jsDate(4656845830)=2117/7/27 16:17:10 -PASS jsDate matches -PASS timestampToDateTime.call(4656845830) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4688430445)=["2118","7","28","5","47","25"] -timestampFromDateTime.call(["2118","7","28","5","47","25"])=4688430445 -jsDate(4688430445)=2118/7/28 5:47:25 -PASS jsDate matches -PASS timestampToDateTime.call(4688430445) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4720478768)=["2119","8","3","4","6","8"] -timestampFromDateTime.call(["2119","8","3","4","6","8"])=4720478768 -jsDate(4720478768)=2119/8/3 4:6:8 -PASS jsDate matches -PASS timestampToDateTime.call(4720478768) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4752527092)=["2120","8","8","2","24","52"] -timestampFromDateTime.call(["2120","8","8","2","24","52"])=4752527092 -jsDate(4752527092)=2120/8/8 2:24:52 -PASS jsDate matches -PASS timestampToDateTime.call(4752527092) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4784111707)=["2121","8","8","15","55","7"] -timestampFromDateTime.call(["2121","8","8","15","55","7"])=4784111707 -jsDate(4784111707)=2121/8/8 15:55:7 -PASS jsDate matches -PASS timestampToDateTime.call(4784111707) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4816160030)=["2122","8","14","14","13","50"] -timestampFromDateTime.call(["2122","8","14","14","13","50"])=4816160030 -jsDate(4816160030)=2122/8/14 14:13:50 -PASS jsDate matches -PASS timestampToDateTime.call(4816160030) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4848208354)=["2123","8","20","12","32","34"] -timestampFromDateTime.call(["2123","8","20","12","32","34"])=4848208354 -jsDate(4848208354)=2123/8/20 12:32:34 -PASS jsDate matches -PASS timestampToDateTime.call(4848208354) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4879792969)=["2124","8","20","2","2","49"] -timestampFromDateTime.call(["2124","8","20","2","2","49"])=4879792969 -jsDate(4879792969)=2124/8/20 2:2:49 -PASS jsDate matches -PASS timestampToDateTime.call(4879792969) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4911841292)=["2125","8","26","0","21","32"] -timestampFromDateTime.call(["2125","8","26","0","21","32"])=4911841292 -jsDate(4911841292)=2125/8/26 0:21:32 -PASS jsDate matches -PASS timestampToDateTime.call(4911841292) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4943889616)=["2126","8","31","22","40","16"] -timestampFromDateTime.call(["2126","8","31","22","40","16"])=4943889616 -jsDate(4943889616)=2126/8/31 22:40:16 -PASS jsDate matches -PASS timestampToDateTime.call(4943889616) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(4975474231)=["2127","9","1","12","10","31"] -timestampFromDateTime.call(["2127","9","1","12","10","31"])=4975474231 -jsDate(4975474231)=2127/9/1 12:10:31 -PASS jsDate matches -PASS timestampToDateTime.call(4975474231) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5007522554)=["2128","9","6","10","29","14"] -timestampFromDateTime.call(["2128","9","6","10","29","14"])=5007522554 -jsDate(5007522554)=2128/9/6 10:29:14 -PASS jsDate matches -PASS timestampToDateTime.call(5007522554) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5039570878)=["2129","9","12","8","47","58"] -timestampFromDateTime.call(["2129","9","12","8","47","58"])=5039570878 -jsDate(5039570878)=2129/9/12 8:47:58 -PASS jsDate matches -PASS timestampToDateTime.call(5039570878) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5071155493)=["2130","9","12","22","18","13"] -timestampFromDateTime.call(["2130","9","12","22","18","13"])=5071155493 -jsDate(5071155493)=2130/9/12 22:18:13 -PASS jsDate matches -PASS timestampToDateTime.call(5071155493) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5103203816)=["2131","9","18","20","36","56"] -timestampFromDateTime.call(["2131","9","18","20","36","56"])=5103203816 -jsDate(5103203816)=2131/9/18 20:36:56 -PASS jsDate matches -PASS timestampToDateTime.call(5103203816) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5135252140)=["2132","9","23","18","55","40"] -timestampFromDateTime.call(["2132","9","23","18","55","40"])=5135252140 -jsDate(5135252140)=2132/9/23 18:55:40 -PASS jsDate matches -PASS timestampToDateTime.call(5135252140) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5166836755)=["2133","9","24","8","25","55"] -timestampFromDateTime.call(["2133","9","24","8","25","55"])=5166836755 -jsDate(5166836755)=2133/9/24 8:25:55 -PASS jsDate matches -PASS timestampToDateTime.call(5166836755) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5198885078)=["2134","9","30","6","44","38"] -timestampFromDateTime.call(["2134","9","30","6","44","38"])=5198885078 -jsDate(5198885078)=2134/9/30 6:44:38 -PASS jsDate matches -PASS timestampToDateTime.call(5198885078) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5230933402)=["2135","10","6","5","3","22"] -timestampFromDateTime.call(["2135","10","6","5","3","22"])=5230933402 -jsDate(5230933402)=2135/10/6 5:3:22 -PASS jsDate matches -PASS timestampToDateTime.call(5230933402) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5262518017)=["2136","10","5","18","33","37"] -timestampFromDateTime.call(["2136","10","5","18","33","37"])=5262518017 -jsDate(5262518017)=2136/10/5 18:33:37 -PASS jsDate matches -PASS timestampToDateTime.call(5262518017) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5294566340)=["2137","10","11","16","52","20"] -timestampFromDateTime.call(["2137","10","11","16","52","20"])=5294566340 -jsDate(5294566340)=2137/10/11 16:52:20 -PASS jsDate matches -PASS timestampToDateTime.call(5294566340) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5326614664)=["2138","10","17","15","11","4"] -timestampFromDateTime.call(["2138","10","17","15","11","4"])=5326614664 -jsDate(5326614664)=2138/10/17 15:11:4 -PASS jsDate matches -PASS timestampToDateTime.call(5326614664) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5358199279)=["2139","10","18","4","41","19"] -timestampFromDateTime.call(["2139","10","18","4","41","19"])=5358199279 -jsDate(5358199279)=2139/10/18 4:41:19 -PASS jsDate matches -PASS timestampToDateTime.call(5358199279) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5390247602)=["2140","10","23","3","0","2"] -timestampFromDateTime.call(["2140","10","23","3","0","2"])=5390247602 -jsDate(5390247602)=2140/10/23 3:0:2 -PASS jsDate matches -PASS timestampToDateTime.call(5390247602) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5422295926)=["2141","10","29","1","18","46"] -timestampFromDateTime.call(["2141","10","29","1","18","46"])=5422295926 -jsDate(5422295926)=2141/10/29 1:18:46 -PASS jsDate matches -PASS timestampToDateTime.call(5422295926) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5453880541)=["2142","10","29","14","49","1"] -timestampFromDateTime.call(["2142","10","29","14","49","1"])=5453880541 -jsDate(5453880541)=2142/10/29 14:49:1 -PASS jsDate matches -PASS timestampToDateTime.call(5453880541) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5485928864)=["2143","11","4","13","7","44"] -timestampFromDateTime.call(["2143","11","4","13","7","44"])=5485928864 -jsDate(5485928864)=2143/11/4 13:7:44 -PASS jsDate matches -PASS timestampToDateTime.call(5485928864) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5517977188)=["2144","11","9","11","26","28"] -timestampFromDateTime.call(["2144","11","9","11","26","28"])=5517977188 -jsDate(5517977188)=2144/11/9 11:26:28 -PASS jsDate matches -PASS timestampToDateTime.call(5517977188) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5549561803)=["2145","11","10","0","56","43"] -timestampFromDateTime.call(["2145","11","10","0","56","43"])=5549561803 -jsDate(5549561803)=2145/11/10 0:56:43 -PASS jsDate matches -PASS timestampToDateTime.call(5549561803) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5581610126)=["2146","11","15","23","15","26"] -timestampFromDateTime.call(["2146","11","15","23","15","26"])=5581610126 -jsDate(5581610126)=2146/11/15 23:15:26 -PASS jsDate matches -PASS timestampToDateTime.call(5581610126) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5613658450)=["2147","11","21","21","34","10"] -timestampFromDateTime.call(["2147","11","21","21","34","10"])=5613658450 -jsDate(5613658450)=2147/11/21 21:34:10 -PASS jsDate matches -PASS timestampToDateTime.call(5613658450) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5645243065)=["2148","11","21","11","4","25"] -timestampFromDateTime.call(["2148","11","21","11","4","25"])=5645243065 -jsDate(5645243065)=2148/11/21 11:4:25 -PASS jsDate matches -PASS timestampToDateTime.call(5645243065) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5677291388)=["2149","11","27","9","23","8"] -timestampFromDateTime.call(["2149","11","27","9","23","8"])=5677291388 -jsDate(5677291388)=2149/11/27 9:23:8 -PASS jsDate matches -PASS timestampToDateTime.call(5677291388) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5709339712)=["2150","12","3","7","41","52"] -timestampFromDateTime.call(["2150","12","3","7","41","52"])=5709339712 -jsDate(5709339712)=2150/12/3 7:41:52 -PASS jsDate matches -PASS timestampToDateTime.call(5709339712) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5740924327)=["2151","12","3","21","12","7"] -timestampFromDateTime.call(["2151","12","3","21","12","7"])=5740924327 -jsDate(5740924327)=2151/12/3 21:12:7 -PASS jsDate matches -PASS timestampToDateTime.call(5740924327) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5772972650)=["2152","12","8","19","30","50"] -timestampFromDateTime.call(["2152","12","8","19","30","50"])=5772972650 -jsDate(5772972650)=2152/12/8 19:30:50 -PASS jsDate matches -PASS timestampToDateTime.call(5772972650) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5805020974)=["2153","12","14","17","49","34"] -timestampFromDateTime.call(["2153","12","14","17","49","34"])=5805020974 -jsDate(5805020974)=2153/12/14 17:49:34 -PASS jsDate matches -PASS timestampToDateTime.call(5805020974) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5836605589)=["2154","12","15","7","19","49"] -timestampFromDateTime.call(["2154","12","15","7","19","49"])=5836605589 -jsDate(5836605589)=2154/12/15 7:19:49 -PASS jsDate matches -PASS timestampToDateTime.call(5836605589) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5868653912)=["2155","12","21","5","38","32"] -timestampFromDateTime.call(["2155","12","21","5","38","32"])=5868653912 -jsDate(5868653912)=2155/12/21 5:38:32 -PASS jsDate matches -PASS timestampToDateTime.call(5868653912) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5900702236)=["2156","12","26","3","57","16"] -timestampFromDateTime.call(["2156","12","26","3","57","16"])=5900702236 -jsDate(5900702236)=2156/12/26 3:57:16 -PASS jsDate matches -PASS timestampToDateTime.call(5900702236) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5932286851)=["2157","12","26","17","27","31"] -timestampFromDateTime.call(["2157","12","26","17","27","31"])=5932286851 -jsDate(5932286851)=2157/12/26 17:27:31 -PASS jsDate matches -PASS timestampToDateTime.call(5932286851) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5964335174)=["2159","1","1","15","46","14"] -timestampFromDateTime.call(["2159","1","1","15","46","14"])=5964335174 -jsDate(5964335174)=2159/1/1 15:46:14 -PASS jsDate matches -PASS timestampToDateTime.call(5964335174) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(5996383498)=["2160","1","7","14","4","58"] -timestampFromDateTime.call(["2160","1","7","14","4","58"])=5996383498 -jsDate(5996383498)=2160/1/7 14:4:58 -PASS jsDate matches -PASS timestampToDateTime.call(5996383498) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6027968113)=["2161","1","7","3","35","13"] -timestampFromDateTime.call(["2161","1","7","3","35","13"])=6027968113 -jsDate(6027968113)=2161/1/7 3:35:13 -PASS jsDate matches -PASS timestampToDateTime.call(6027968113) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6060016436)=["2162","1","13","1","53","56"] -timestampFromDateTime.call(["2162","1","13","1","53","56"])=6060016436 -jsDate(6060016436)=2162/1/13 1:53:56 -PASS jsDate matches -PASS timestampToDateTime.call(6060016436) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6092064760)=["2163","1","19","0","12","40"] -timestampFromDateTime.call(["2163","1","19","0","12","40"])=6092064760 -jsDate(6092064760)=2163/1/19 0:12:40 -PASS jsDate matches -PASS timestampToDateTime.call(6092064760) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6123649375)=["2164","1","19","13","42","55"] -timestampFromDateTime.call(["2164","1","19","13","42","55"])=6123649375 -jsDate(6123649375)=2164/1/19 13:42:55 -PASS jsDate matches -PASS timestampToDateTime.call(6123649375) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6155697698)=["2165","1","24","12","1","38"] -timestampFromDateTime.call(["2165","1","24","12","1","38"])=6155697698 -jsDate(6155697698)=2165/1/24 12:1:38 -PASS jsDate matches -PASS timestampToDateTime.call(6155697698) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6187746022)=["2166","1","30","10","20","22"] -timestampFromDateTime.call(["2166","1","30","10","20","22"])=6187746022 -jsDate(6187746022)=2166/1/30 10:20:22 -PASS jsDate matches -PASS timestampToDateTime.call(6187746022) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6219330637)=["2167","1","30","23","50","37"] -timestampFromDateTime.call(["2167","1","30","23","50","37"])=6219330637 -jsDate(6219330637)=2167/1/30 23:50:37 -PASS jsDate matches -PASS timestampToDateTime.call(6219330637) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6251378960)=["2168","2","5","22","9","20"] -timestampFromDateTime.call(["2168","2","5","22","9","20"])=6251378960 -jsDate(6251378960)=2168/2/5 22:9:20 -PASS jsDate matches -PASS timestampToDateTime.call(6251378960) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6283427284)=["2169","2","10","20","28","4"] -timestampFromDateTime.call(["2169","2","10","20","28","4"])=6283427284 -jsDate(6283427284)=2169/2/10 20:28:4 -PASS jsDate matches -PASS timestampToDateTime.call(6283427284) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6315011899)=["2170","2","11","9","58","19"] -timestampFromDateTime.call(["2170","2","11","9","58","19"])=6315011899 -jsDate(6315011899)=2170/2/11 9:58:19 -PASS jsDate matches -PASS timestampToDateTime.call(6315011899) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6347060222)=["2171","2","17","8","17","2"] -timestampFromDateTime.call(["2171","2","17","8","17","2"])=6347060222 -jsDate(6347060222)=2171/2/17 8:17:2 -PASS jsDate matches -PASS timestampToDateTime.call(6347060222) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6379108546)=["2172","2","23","6","35","46"] -timestampFromDateTime.call(["2172","2","23","6","35","46"])=6379108546 -jsDate(6379108546)=2172/2/23 6:35:46 -PASS jsDate matches -PASS timestampToDateTime.call(6379108546) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6410693161)=["2173","2","22","20","6","1"] -timestampFromDateTime.call(["2173","2","22","20","6","1"])=6410693161 -jsDate(6410693161)=2173/2/22 20:6:1 -PASS jsDate matches -PASS timestampToDateTime.call(6410693161) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6442741484)=["2174","2","28","18","24","44"] -timestampFromDateTime.call(["2174","2","28","18","24","44"])=6442741484 -jsDate(6442741484)=2174/2/28 18:24:44 -PASS jsDate matches -PASS timestampToDateTime.call(6442741484) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6474789808)=["2175","3","6","16","43","28"] -timestampFromDateTime.call(["2175","3","6","16","43","28"])=6474789808 -jsDate(6474789808)=2175/3/6 16:43:28 -PASS jsDate matches -PASS timestampToDateTime.call(6474789808) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6506374423)=["2176","3","6","6","13","43"] -timestampFromDateTime.call(["2176","3","6","6","13","43"])=6506374423 -jsDate(6506374423)=2176/3/6 6:13:43 -PASS jsDate matches -PASS timestampToDateTime.call(6506374423) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6538422746)=["2177","3","12","4","32","26"] -timestampFromDateTime.call(["2177","3","12","4","32","26"])=6538422746 -jsDate(6538422746)=2177/3/12 4:32:26 -PASS jsDate matches -PASS timestampToDateTime.call(6538422746) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6570471070)=["2178","3","18","2","51","10"] -timestampFromDateTime.call(["2178","3","18","2","51","10"])=6570471070 -jsDate(6570471070)=2178/3/18 2:51:10 -PASS jsDate matches -PASS timestampToDateTime.call(6570471070) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6602055685)=["2179","3","18","16","21","25"] -timestampFromDateTime.call(["2179","3","18","16","21","25"])=6602055685 -jsDate(6602055685)=2179/3/18 16:21:25 -PASS jsDate matches -PASS timestampToDateTime.call(6602055685) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6634104008)=["2180","3","23","14","40","8"] -timestampFromDateTime.call(["2180","3","23","14","40","8"])=6634104008 -jsDate(6634104008)=2180/3/23 14:40:8 -PASS jsDate matches -PASS timestampToDateTime.call(6634104008) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6666152332)=["2181","3","29","12","58","52"] -timestampFromDateTime.call(["2181","3","29","12","58","52"])=6666152332 -jsDate(6666152332)=2181/3/29 12:58:52 -PASS jsDate matches -PASS timestampToDateTime.call(6666152332) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6697736947)=["2182","3","30","2","29","7"] -timestampFromDateTime.call(["2182","3","30","2","29","7"])=6697736947 -jsDate(6697736947)=2182/3/30 2:29:7 -PASS jsDate matches -PASS timestampToDateTime.call(6697736947) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6729785270)=["2183","4","5","0","47","50"] -timestampFromDateTime.call(["2183","4","5","0","47","50"])=6729785270 -jsDate(6729785270)=2183/4/5 0:47:50 -PASS jsDate matches -PASS timestampToDateTime.call(6729785270) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6761833594)=["2184","4","9","23","6","34"] -timestampFromDateTime.call(["2184","4","9","23","6","34"])=6761833594 -jsDate(6761833594)=2184/4/9 23:6:34 -PASS jsDate matches -PASS timestampToDateTime.call(6761833594) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6793418209)=["2185","4","10","12","36","49"] -timestampFromDateTime.call(["2185","4","10","12","36","49"])=6793418209 -jsDate(6793418209)=2185/4/10 12:36:49 -PASS jsDate matches -PASS timestampToDateTime.call(6793418209) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6825466532)=["2186","4","16","10","55","32"] -timestampFromDateTime.call(["2186","4","16","10","55","32"])=6825466532 -jsDate(6825466532)=2186/4/16 10:55:32 -PASS jsDate matches -PASS timestampToDateTime.call(6825466532) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6857514856)=["2187","4","22","9","14","16"] -timestampFromDateTime.call(["2187","4","22","9","14","16"])=6857514856 -jsDate(6857514856)=2187/4/22 9:14:16 -PASS jsDate matches -PASS timestampToDateTime.call(6857514856) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6889099471)=["2188","4","21","22","44","31"] -timestampFromDateTime.call(["2188","4","21","22","44","31"])=6889099471 -jsDate(6889099471)=2188/4/21 22:44:31 -PASS jsDate matches -PASS timestampToDateTime.call(6889099471) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6921147794)=["2189","4","27","21","3","14"] -timestampFromDateTime.call(["2189","4","27","21","3","14"])=6921147794 -jsDate(6921147794)=2189/4/27 21:3:14 -PASS jsDate matches -PASS timestampToDateTime.call(6921147794) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6953196118)=["2190","5","3","19","21","58"] -timestampFromDateTime.call(["2190","5","3","19","21","58"])=6953196118 -jsDate(6953196118)=2190/5/3 19:21:58 -PASS jsDate matches -PASS timestampToDateTime.call(6953196118) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(6984780733)=["2191","5","4","8","52","13"] -timestampFromDateTime.call(["2191","5","4","8","52","13"])=6984780733 -jsDate(6984780733)=2191/5/4 8:52:13 -PASS jsDate matches -PASS timestampToDateTime.call(6984780733) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7016829056)=["2192","5","9","7","10","56"] -timestampFromDateTime.call(["2192","5","9","7","10","56"])=7016829056 -jsDate(7016829056)=2192/5/9 7:10:56 -PASS jsDate matches -PASS timestampToDateTime.call(7016829056) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7048877380)=["2193","5","15","5","29","40"] -timestampFromDateTime.call(["2193","5","15","5","29","40"])=7048877380 -jsDate(7048877380)=2193/5/15 5:29:40 -PASS jsDate matches -PASS timestampToDateTime.call(7048877380) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7080461995)=["2194","5","15","18","59","55"] -timestampFromDateTime.call(["2194","5","15","18","59","55"])=7080461995 -jsDate(7080461995)=2194/5/15 18:59:55 -PASS jsDate matches -PASS timestampToDateTime.call(7080461995) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7112510318)=["2195","5","21","17","18","38"] -timestampFromDateTime.call(["2195","5","21","17","18","38"])=7112510318 -jsDate(7112510318)=2195/5/21 17:18:38 -PASS jsDate matches -PASS timestampToDateTime.call(7112510318) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7144558642)=["2196","5","26","15","37","22"] -timestampFromDateTime.call(["2196","5","26","15","37","22"])=7144558642 -jsDate(7144558642)=2196/5/26 15:37:22 -PASS jsDate matches -PASS timestampToDateTime.call(7144558642) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7176143257)=["2197","5","27","5","7","37"] -timestampFromDateTime.call(["2197","5","27","5","7","37"])=7176143257 -jsDate(7176143257)=2197/5/27 5:7:37 -PASS jsDate matches -PASS timestampToDateTime.call(7176143257) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7208191580)=["2198","6","2","3","26","20"] -timestampFromDateTime.call(["2198","6","2","3","26","20"])=7208191580 -jsDate(7208191580)=2198/6/2 3:26:20 -PASS jsDate matches -PASS timestampToDateTime.call(7208191580) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7240239904)=["2199","6","8","1","45","4"] -timestampFromDateTime.call(["2199","6","8","1","45","4"])=7240239904 -jsDate(7240239904)=2199/6/8 1:45:4 -PASS jsDate matches -PASS timestampToDateTime.call(7240239904) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7271824519)=["2200","6","8","15","15","19"] -timestampFromDateTime.call(["2200","6","8","15","15","19"])=7271824519 -jsDate(7271824519)=2200/6/8 15:15:19 -PASS jsDate matches -PASS timestampToDateTime.call(7271824519) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7303872842)=["2201","6","14","13","34","2"] -timestampFromDateTime.call(["2201","6","14","13","34","2"])=7303872842 -jsDate(7303872842)=2201/6/14 13:34:2 -PASS jsDate matches -PASS timestampToDateTime.call(7303872842) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7335921166)=["2202","6","20","11","52","46"] -timestampFromDateTime.call(["2202","6","20","11","52","46"])=7335921166 -jsDate(7335921166)=2202/6/20 11:52:46 -PASS jsDate matches -PASS timestampToDateTime.call(7335921166) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7367505781)=["2203","6","21","1","23","1"] -timestampFromDateTime.call(["2203","6","21","1","23","1"])=7367505781 -jsDate(7367505781)=2203/6/21 1:23:1 -PASS jsDate matches -PASS timestampToDateTime.call(7367505781) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7399554104)=["2204","6","25","23","41","44"] -timestampFromDateTime.call(["2204","6","25","23","41","44"])=7399554104 -jsDate(7399554104)=2204/6/25 23:41:44 -PASS jsDate matches -PASS timestampToDateTime.call(7399554104) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7431602428)=["2205","7","1","22","0","28"] -timestampFromDateTime.call(["2205","7","1","22","0","28"])=7431602428 -jsDate(7431602428)=2205/7/1 22:0:28 -PASS jsDate matches -PASS timestampToDateTime.call(7431602428) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7463187043)=["2206","7","2","11","30","43"] -timestampFromDateTime.call(["2206","7","2","11","30","43"])=7463187043 -jsDate(7463187043)=2206/7/2 11:30:43 -PASS jsDate matches -PASS timestampToDateTime.call(7463187043) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7495235366)=["2207","7","8","9","49","26"] -timestampFromDateTime.call(["2207","7","8","9","49","26"])=7495235366 -jsDate(7495235366)=2207/7/8 9:49:26 -PASS jsDate matches -PASS timestampToDateTime.call(7495235366) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7527283690)=["2208","7","13","8","8","10"] -timestampFromDateTime.call(["2208","7","13","8","8","10"])=7527283690 -jsDate(7527283690)=2208/7/13 8:8:10 -PASS jsDate matches -PASS timestampToDateTime.call(7527283690) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7558868305)=["2209","7","13","21","38","25"] -timestampFromDateTime.call(["2209","7","13","21","38","25"])=7558868305 -jsDate(7558868305)=2209/7/13 21:38:25 -PASS jsDate matches -PASS timestampToDateTime.call(7558868305) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7590916628)=["2210","7","19","19","57","8"] -timestampFromDateTime.call(["2210","7","19","19","57","8"])=7590916628 -jsDate(7590916628)=2210/7/19 19:57:8 -PASS jsDate matches -PASS timestampToDateTime.call(7590916628) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7622964952)=["2211","7","25","18","15","52"] -timestampFromDateTime.call(["2211","7","25","18","15","52"])=7622964952 -jsDate(7622964952)=2211/7/25 18:15:52 -PASS jsDate matches -PASS timestampToDateTime.call(7622964952) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7654549567)=["2212","7","25","7","46","7"] -timestampFromDateTime.call(["2212","7","25","7","46","7"])=7654549567 -jsDate(7654549567)=2212/7/25 7:46:7 -PASS jsDate matches -PASS timestampToDateTime.call(7654549567) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7686597890)=["2213","7","31","6","4","50"] -timestampFromDateTime.call(["2213","7","31","6","4","50"])=7686597890 -jsDate(7686597890)=2213/7/31 6:4:50 -PASS jsDate matches -PASS timestampToDateTime.call(7686597890) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7718646214)=["2214","8","6","4","23","34"] -timestampFromDateTime.call(["2214","8","6","4","23","34"])=7718646214 -jsDate(7718646214)=2214/8/6 4:23:34 -PASS jsDate matches -PASS timestampToDateTime.call(7718646214) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7750230829)=["2215","8","6","17","53","49"] -timestampFromDateTime.call(["2215","8","6","17","53","49"])=7750230829 -jsDate(7750230829)=2215/8/6 17:53:49 -PASS jsDate matches -PASS timestampToDateTime.call(7750230829) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7782279152)=["2216","8","11","16","12","32"] -timestampFromDateTime.call(["2216","8","11","16","12","32"])=7782279152 -jsDate(7782279152)=2216/8/11 16:12:32 -PASS jsDate matches -PASS timestampToDateTime.call(7782279152) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7814327476)=["2217","8","17","14","31","16"] -timestampFromDateTime.call(["2217","8","17","14","31","16"])=7814327476 -jsDate(7814327476)=2217/8/17 14:31:16 -PASS jsDate matches -PASS timestampToDateTime.call(7814327476) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7845912091)=["2218","8","18","4","1","31"] -timestampFromDateTime.call(["2218","8","18","4","1","31"])=7845912091 -jsDate(7845912091)=2218/8/18 4:1:31 -PASS jsDate matches -PASS timestampToDateTime.call(7845912091) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7877960414)=["2219","8","24","2","20","14"] -timestampFromDateTime.call(["2219","8","24","2","20","14"])=7877960414 -jsDate(7877960414)=2219/8/24 2:20:14 -PASS jsDate matches -PASS timestampToDateTime.call(7877960414) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7910008738)=["2220","8","29","0","38","58"] -timestampFromDateTime.call(["2220","8","29","0","38","58"])=7910008738 -jsDate(7910008738)=2220/8/29 0:38:58 -PASS jsDate matches -PASS timestampToDateTime.call(7910008738) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7941593353)=["2221","8","29","14","9","13"] -timestampFromDateTime.call(["2221","8","29","14","9","13"])=7941593353 -jsDate(7941593353)=2221/8/29 14:9:13 -PASS jsDate matches -PASS timestampToDateTime.call(7941593353) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(7973641676)=["2222","9","4","12","27","56"] -timestampFromDateTime.call(["2222","9","4","12","27","56"])=7973641676 -jsDate(7973641676)=2222/9/4 12:27:56 -PASS jsDate matches -PASS timestampToDateTime.call(7973641676) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8005690000)=["2223","9","10","10","46","40"] -timestampFromDateTime.call(["2223","9","10","10","46","40"])=8005690000 -jsDate(8005690000)=2223/9/10 10:46:40 -PASS jsDate matches -PASS timestampToDateTime.call(8005690000) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8037274615)=["2224","9","10","0","16","55"] -timestampFromDateTime.call(["2224","9","10","0","16","55"])=8037274615 -jsDate(8037274615)=2224/9/10 0:16:55 -PASS jsDate matches -PASS timestampToDateTime.call(8037274615) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8069322938)=["2225","9","15","22","35","38"] -timestampFromDateTime.call(["2225","9","15","22","35","38"])=8069322938 -jsDate(8069322938)=2225/9/15 22:35:38 -PASS jsDate matches -PASS timestampToDateTime.call(8069322938) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8101371262)=["2226","9","21","20","54","22"] -timestampFromDateTime.call(["2226","9","21","20","54","22"])=8101371262 -jsDate(8101371262)=2226/9/21 20:54:22 -PASS jsDate matches -PASS timestampToDateTime.call(8101371262) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8132955877)=["2227","9","22","10","24","37"] -timestampFromDateTime.call(["2227","9","22","10","24","37"])=8132955877 -jsDate(8132955877)=2227/9/22 10:24:37 -PASS jsDate matches -PASS timestampToDateTime.call(8132955877) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8165004200)=["2228","9","27","8","43","20"] -timestampFromDateTime.call(["2228","9","27","8","43","20"])=8165004200 -jsDate(8165004200)=2228/9/27 8:43:20 -PASS jsDate matches -PASS timestampToDateTime.call(8165004200) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8197052524)=["2229","10","3","7","2","4"] -timestampFromDateTime.call(["2229","10","3","7","2","4"])=8197052524 -jsDate(8197052524)=2229/10/3 7:2:4 -PASS jsDate matches -PASS timestampToDateTime.call(8197052524) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8228637139)=["2230","10","3","20","32","19"] -timestampFromDateTime.call(["2230","10","3","20","32","19"])=8228637139 -jsDate(8228637139)=2230/10/3 20:32:19 -PASS jsDate matches -PASS timestampToDateTime.call(8228637139) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8260685462)=["2231","10","9","18","51","2"] -timestampFromDateTime.call(["2231","10","9","18","51","2"])=8260685462 -jsDate(8260685462)=2231/10/9 18:51:2 -PASS jsDate matches -PASS timestampToDateTime.call(8260685462) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8292733786)=["2232","10","14","17","9","46"] -timestampFromDateTime.call(["2232","10","14","17","9","46"])=8292733786 -jsDate(8292733786)=2232/10/14 17:9:46 -PASS jsDate matches -PASS timestampToDateTime.call(8292733786) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8324318401)=["2233","10","15","6","40","1"] -timestampFromDateTime.call(["2233","10","15","6","40","1"])=8324318401 -jsDate(8324318401)=2233/10/15 6:40:1 -PASS jsDate matches -PASS timestampToDateTime.call(8324318401) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8356366724)=["2234","10","21","4","58","44"] -timestampFromDateTime.call(["2234","10","21","4","58","44"])=8356366724 -jsDate(8356366724)=2234/10/21 4:58:44 -PASS jsDate matches -PASS timestampToDateTime.call(8356366724) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8388415048)=["2235","10","27","3","17","28"] -timestampFromDateTime.call(["2235","10","27","3","17","28"])=8388415048 -jsDate(8388415048)=2235/10/27 3:17:28 -PASS jsDate matches -PASS timestampToDateTime.call(8388415048) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8419999663)=["2236","10","26","16","47","43"] -timestampFromDateTime.call(["2236","10","26","16","47","43"])=8419999663 -jsDate(8419999663)=2236/10/26 16:47:43 -PASS jsDate matches -PASS timestampToDateTime.call(8419999663) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8452047986)=["2237","11","1","15","6","26"] -timestampFromDateTime.call(["2237","11","1","15","6","26"])=8452047986 -jsDate(8452047986)=2237/11/1 15:6:26 -PASS jsDate matches -PASS timestampToDateTime.call(8452047986) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8484096310)=["2238","11","7","13","25","10"] -timestampFromDateTime.call(["2238","11","7","13","25","10"])=8484096310 -jsDate(8484096310)=2238/11/7 13:25:10 -PASS jsDate matches -PASS timestampToDateTime.call(8484096310) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8515680925)=["2239","11","8","2","55","25"] -timestampFromDateTime.call(["2239","11","8","2","55","25"])=8515680925 -jsDate(8515680925)=2239/11/8 2:55:25 -PASS jsDate matches -PASS timestampToDateTime.call(8515680925) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8547729248)=["2240","11","13","1","14","8"] -timestampFromDateTime.call(["2240","11","13","1","14","8"])=8547729248 -jsDate(8547729248)=2240/11/13 1:14:8 -PASS jsDate matches -PASS timestampToDateTime.call(8547729248) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8579777572)=["2241","11","18","23","32","52"] -timestampFromDateTime.call(["2241","11","18","23","32","52"])=8579777572 -jsDate(8579777572)=2241/11/18 23:32:52 -PASS jsDate matches -PASS timestampToDateTime.call(8579777572) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8611362187)=["2242","11","19","13","3","7"] -timestampFromDateTime.call(["2242","11","19","13","3","7"])=8611362187 -jsDate(8611362187)=2242/11/19 13:3:7 -PASS jsDate matches -PASS timestampToDateTime.call(8611362187) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8643410510)=["2243","11","25","11","21","50"] -timestampFromDateTime.call(["2243","11","25","11","21","50"])=8643410510 -jsDate(8643410510)=2243/11/25 11:21:50 -PASS jsDate matches -PASS timestampToDateTime.call(8643410510) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8675458834)=["2244","11","30","9","40","34"] -timestampFromDateTime.call(["2244","11","30","9","40","34"])=8675458834 -jsDate(8675458834)=2244/11/30 9:40:34 -PASS jsDate matches -PASS timestampToDateTime.call(8675458834) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8707043449)=["2245","11","30","23","10","49"] -timestampFromDateTime.call(["2245","11","30","23","10","49"])=8707043449 -jsDate(8707043449)=2245/11/30 23:10:49 -PASS jsDate matches -PASS timestampToDateTime.call(8707043449) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8739091772)=["2246","12","6","21","29","32"] -timestampFromDateTime.call(["2246","12","6","21","29","32"])=8739091772 -jsDate(8739091772)=2246/12/6 21:29:32 -PASS jsDate matches -PASS timestampToDateTime.call(8739091772) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8771140096)=["2247","12","12","19","48","16"] -timestampFromDateTime.call(["2247","12","12","19","48","16"])=8771140096 -jsDate(8771140096)=2247/12/12 19:48:16 -PASS jsDate matches -PASS timestampToDateTime.call(8771140096) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8802724711)=["2248","12","12","9","18","31"] -timestampFromDateTime.call(["2248","12","12","9","18","31"])=8802724711 -jsDate(8802724711)=2248/12/12 9:18:31 -PASS jsDate matches -PASS timestampToDateTime.call(8802724711) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8834773034)=["2249","12","18","7","37","14"] -timestampFromDateTime.call(["2249","12","18","7","37","14"])=8834773034 -jsDate(8834773034)=2249/12/18 7:37:14 -PASS jsDate matches -PASS timestampToDateTime.call(8834773034) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8866821358)=["2250","12","24","5","55","58"] -timestampFromDateTime.call(["2250","12","24","5","55","58"])=8866821358 -jsDate(8866821358)=2250/12/24 5:55:58 -PASS jsDate matches -PASS timestampToDateTime.call(8866821358) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8898405973)=["2251","12","24","19","26","13"] -timestampFromDateTime.call(["2251","12","24","19","26","13"])=8898405973 -jsDate(8898405973)=2251/12/24 19:26:13 -PASS jsDate matches -PASS timestampToDateTime.call(8898405973) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8930454296)=["2252","12","29","17","44","56"] -timestampFromDateTime.call(["2252","12","29","17","44","56"])=8930454296 -jsDate(8930454296)=2252/12/29 17:44:56 -PASS jsDate matches -PASS timestampToDateTime.call(8930454296) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8962502620)=["2254","1","4","16","3","40"] -timestampFromDateTime.call(["2254","1","4","16","3","40"])=8962502620 -jsDate(8962502620)=2254/1/4 16:3:40 -PASS jsDate matches -PASS timestampToDateTime.call(8962502620) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(8994087235)=["2255","1","5","5","33","55"] -timestampFromDateTime.call(["2255","1","5","5","33","55"])=8994087235 -jsDate(8994087235)=2255/1/5 5:33:55 -PASS jsDate matches -PASS timestampToDateTime.call(8994087235) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9026135558)=["2256","1","11","3","52","38"] -timestampFromDateTime.call(["2256","1","11","3","52","38"])=9026135558 -jsDate(9026135558)=2256/1/11 3:52:38 -PASS jsDate matches -PASS timestampToDateTime.call(9026135558) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9058183882)=["2257","1","16","2","11","22"] -timestampFromDateTime.call(["2257","1","16","2","11","22"])=9058183882 -jsDate(9058183882)=2257/1/16 2:11:22 -PASS jsDate matches -PASS timestampToDateTime.call(9058183882) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9089768497)=["2258","1","16","15","41","37"] -timestampFromDateTime.call(["2258","1","16","15","41","37"])=9089768497 -jsDate(9089768497)=2258/1/16 15:41:37 -PASS jsDate matches -PASS timestampToDateTime.call(9089768497) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9121816820)=["2259","1","22","14","0","20"] -timestampFromDateTime.call(["2259","1","22","14","0","20"])=9121816820 -jsDate(9121816820)=2259/1/22 14:0:20 -PASS jsDate matches -PASS timestampToDateTime.call(9121816820) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9153865144)=["2260","1","28","12","19","4"] -timestampFromDateTime.call(["2260","1","28","12","19","4"])=9153865144 -jsDate(9153865144)=2260/1/28 12:19:4 -PASS jsDate matches -PASS timestampToDateTime.call(9153865144) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9185449759)=["2261","1","28","1","49","19"] -timestampFromDateTime.call(["2261","1","28","1","49","19"])=9185449759 -jsDate(9185449759)=2261/1/28 1:49:19 -PASS jsDate matches -PASS timestampToDateTime.call(9185449759) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9217498082)=["2262","2","3","0","8","2"] -timestampFromDateTime.call(["2262","2","3","0","8","2"])=9217498082 -jsDate(9217498082)=2262/2/3 0:8:2 -PASS jsDate matches -PASS timestampToDateTime.call(9217498082) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9249546406)=["2263","2","8","22","26","46"] -timestampFromDateTime.call(["2263","2","8","22","26","46"])=9249546406 -jsDate(9249546406)=2263/2/8 22:26:46 -PASS jsDate matches -PASS timestampToDateTime.call(9249546406) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9281131021)=["2264","2","9","11","57","1"] -timestampFromDateTime.call(["2264","2","9","11","57","1"])=9281131021 -jsDate(9281131021)=2264/2/9 11:57:1 -PASS jsDate matches -PASS timestampToDateTime.call(9281131021) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9313179344)=["2265","2","14","10","15","44"] -timestampFromDateTime.call(["2265","2","14","10","15","44"])=9313179344 -jsDate(9313179344)=2265/2/14 10:15:44 -PASS jsDate matches -PASS timestampToDateTime.call(9313179344) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9345227668)=["2266","2","20","8","34","28"] -timestampFromDateTime.call(["2266","2","20","8","34","28"])=9345227668 -jsDate(9345227668)=2266/2/20 8:34:28 -PASS jsDate matches -PASS timestampToDateTime.call(9345227668) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9376812283)=["2267","2","20","22","4","43"] -timestampFromDateTime.call(["2267","2","20","22","4","43"])=9376812283 -jsDate(9376812283)=2267/2/20 22:4:43 -PASS jsDate matches -PASS timestampToDateTime.call(9376812283) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9408860606)=["2268","2","26","20","23","26"] -timestampFromDateTime.call(["2268","2","26","20","23","26"])=9408860606 -jsDate(9408860606)=2268/2/26 20:23:26 -PASS jsDate matches -PASS timestampToDateTime.call(9408860606) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9440908930)=["2269","3","3","18","42","10"] -timestampFromDateTime.call(["2269","3","3","18","42","10"])=9440908930 -jsDate(9440908930)=2269/3/3 18:42:10 -PASS jsDate matches -PASS timestampToDateTime.call(9440908930) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9472493545)=["2270","3","4","8","12","25"] -timestampFromDateTime.call(["2270","3","4","8","12","25"])=9472493545 -jsDate(9472493545)=2270/3/4 8:12:25 -PASS jsDate matches -PASS timestampToDateTime.call(9472493545) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9504541868)=["2271","3","10","6","31","8"] -timestampFromDateTime.call(["2271","3","10","6","31","8"])=9504541868 -jsDate(9504541868)=2271/3/10 6:31:8 -PASS jsDate matches -PASS timestampToDateTime.call(9504541868) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9536590192)=["2272","3","15","4","49","52"] -timestampFromDateTime.call(["2272","3","15","4","49","52"])=9536590192 -jsDate(9536590192)=2272/3/15 4:49:52 -PASS jsDate matches -PASS timestampToDateTime.call(9536590192) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9568174807)=["2273","3","15","18","20","7"] -timestampFromDateTime.call(["2273","3","15","18","20","7"])=9568174807 -jsDate(9568174807)=2273/3/15 18:20:7 -PASS jsDate matches -PASS timestampToDateTime.call(9568174807) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9600223130)=["2274","3","21","16","38","50"] -timestampFromDateTime.call(["2274","3","21","16","38","50"])=9600223130 -jsDate(9600223130)=2274/3/21 16:38:50 -PASS jsDate matches -PASS timestampToDateTime.call(9600223130) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9632271454)=["2275","3","27","14","57","34"] -timestampFromDateTime.call(["2275","3","27","14","57","34"])=9632271454 -jsDate(9632271454)=2275/3/27 14:57:34 -PASS jsDate matches -PASS timestampToDateTime.call(9632271454) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9663856069)=["2276","3","27","4","27","49"] -timestampFromDateTime.call(["2276","3","27","4","27","49"])=9663856069 -jsDate(9663856069)=2276/3/27 4:27:49 -PASS jsDate matches -PASS timestampToDateTime.call(9663856069) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9695904392)=["2277","4","2","2","46","32"] -timestampFromDateTime.call(["2277","4","2","2","46","32"])=9695904392 -jsDate(9695904392)=2277/4/2 2:46:32 -PASS jsDate matches -PASS timestampToDateTime.call(9695904392) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9727952716)=["2278","4","8","1","5","16"] -timestampFromDateTime.call(["2278","4","8","1","5","16"])=9727952716 -jsDate(9727952716)=2278/4/8 1:5:16 -PASS jsDate matches -PASS timestampToDateTime.call(9727952716) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9759537331)=["2279","4","8","14","35","31"] -timestampFromDateTime.call(["2279","4","8","14","35","31"])=9759537331 -jsDate(9759537331)=2279/4/8 14:35:31 -PASS jsDate matches -PASS timestampToDateTime.call(9759537331) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9791585654)=["2280","4","13","12","54","14"] -timestampFromDateTime.call(["2280","4","13","12","54","14"])=9791585654 -jsDate(9791585654)=2280/4/13 12:54:14 -PASS jsDate matches -PASS timestampToDateTime.call(9791585654) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9823633978)=["2281","4","19","11","12","58"] -timestampFromDateTime.call(["2281","4","19","11","12","58"])=9823633978 -jsDate(9823633978)=2281/4/19 11:12:58 -PASS jsDate matches -PASS timestampToDateTime.call(9823633978) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9855218593)=["2282","4","20","0","43","13"] -timestampFromDateTime.call(["2282","4","20","0","43","13"])=9855218593 -jsDate(9855218593)=2282/4/20 0:43:13 -PASS jsDate matches -PASS timestampToDateTime.call(9855218593) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9887266916)=["2283","4","25","23","1","56"] -timestampFromDateTime.call(["2283","4","25","23","1","56"])=9887266916 -jsDate(9887266916)=2283/4/25 23:1:56 -PASS jsDate matches -PASS timestampToDateTime.call(9887266916) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9919315240)=["2284","4","30","21","20","40"] -timestampFromDateTime.call(["2284","4","30","21","20","40"])=9919315240 -jsDate(9919315240)=2284/4/30 21:20:40 -PASS jsDate matches -PASS timestampToDateTime.call(9919315240) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9950899855)=["2285","5","1","10","50","55"] -timestampFromDateTime.call(["2285","5","1","10","50","55"])=9950899855 -jsDate(9950899855)=2285/5/1 10:50:55 -PASS jsDate matches -PASS timestampToDateTime.call(9950899855) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(9982948178)=["2286","5","7","9","9","38"] -timestampFromDateTime.call(["2286","5","7","9","9","38"])=9982948178 -jsDate(9982948178)=2286/5/7 9:9:38 -PASS jsDate matches -PASS timestampToDateTime.call(9982948178) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10014996502)=["2287","5","13","7","28","22"] -timestampFromDateTime.call(["2287","5","13","7","28","22"])=10014996502 -jsDate(10014996502)=2287/5/13 7:28:22 -PASS jsDate matches -PASS timestampToDateTime.call(10014996502) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10046581117)=["2288","5","12","20","58","37"] -timestampFromDateTime.call(["2288","5","12","20","58","37"])=10046581117 -jsDate(10046581117)=2288/5/12 20:58:37 -PASS jsDate matches -PASS timestampToDateTime.call(10046581117) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10078629440)=["2289","5","18","19","17","20"] -timestampFromDateTime.call(["2289","5","18","19","17","20"])=10078629440 -jsDate(10078629440)=2289/5/18 19:17:20 -PASS jsDate matches -PASS timestampToDateTime.call(10078629440) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10110677764)=["2290","5","24","17","36","4"] -timestampFromDateTime.call(["2290","5","24","17","36","4"])=10110677764 -jsDate(10110677764)=2290/5/24 17:36:4 -PASS jsDate matches -PASS timestampToDateTime.call(10110677764) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10142262379)=["2291","5","25","7","6","19"] -timestampFromDateTime.call(["2291","5","25","7","6","19"])=10142262379 -jsDate(10142262379)=2291/5/25 7:6:19 -PASS jsDate matches -PASS timestampToDateTime.call(10142262379) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10174310702)=["2292","5","30","5","25","2"] -timestampFromDateTime.call(["2292","5","30","5","25","2"])=10174310702 -jsDate(10174310702)=2292/5/30 5:25:2 -PASS jsDate matches -PASS timestampToDateTime.call(10174310702) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10206359026)=["2293","6","5","3","43","46"] -timestampFromDateTime.call(["2293","6","5","3","43","46"])=10206359026 -jsDate(10206359026)=2293/6/5 3:43:46 -PASS jsDate matches -PASS timestampToDateTime.call(10206359026) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10237943641)=["2294","6","5","17","14","1"] -timestampFromDateTime.call(["2294","6","5","17","14","1"])=10237943641 -jsDate(10237943641)=2294/6/5 17:14:1 -PASS jsDate matches -PASS timestampToDateTime.call(10237943641) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10269991964)=["2295","6","11","15","32","44"] -timestampFromDateTime.call(["2295","6","11","15","32","44"])=10269991964 -jsDate(10269991964)=2295/6/11 15:32:44 -PASS jsDate matches -PASS timestampToDateTime.call(10269991964) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10302040288)=["2296","6","16","13","51","28"] -timestampFromDateTime.call(["2296","6","16","13","51","28"])=10302040288 -jsDate(10302040288)=2296/6/16 13:51:28 -PASS jsDate matches -PASS timestampToDateTime.call(10302040288) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10333624903)=["2297","6","17","3","21","43"] -timestampFromDateTime.call(["2297","6","17","3","21","43"])=10333624903 -jsDate(10333624903)=2297/6/17 3:21:43 -PASS jsDate matches -PASS timestampToDateTime.call(10333624903) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10365673226)=["2298","6","23","1","40","26"] -timestampFromDateTime.call(["2298","6","23","1","40","26"])=10365673226 -jsDate(10365673226)=2298/6/23 1:40:26 -PASS jsDate matches -PASS timestampToDateTime.call(10365673226) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10397721550)=["2299","6","28","23","59","10"] -timestampFromDateTime.call(["2299","6","28","23","59","10"])=10397721550 -jsDate(10397721550)=2299/6/28 23:59:10 -PASS jsDate matches -PASS timestampToDateTime.call(10397721550) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10429306165)=["2300","6","29","13","29","25"] -timestampFromDateTime.call(["2300","6","29","13","29","25"])=10429306165 -jsDate(10429306165)=2300/6/29 13:29:25 -PASS jsDate matches -PASS timestampToDateTime.call(10429306165) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10461354488)=["2301","7","5","11","48","8"] -timestampFromDateTime.call(["2301","7","5","11","48","8"])=10461354488 -jsDate(10461354488)=2301/7/5 11:48:8 -PASS jsDate matches -PASS timestampToDateTime.call(10461354488) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10493402812)=["2302","7","11","10","6","52"] -timestampFromDateTime.call(["2302","7","11","10","6","52"])=10493402812 -jsDate(10493402812)=2302/7/11 10:6:52 -PASS jsDate matches -PASS timestampToDateTime.call(10493402812) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10524987427)=["2303","7","11","23","37","7"] -timestampFromDateTime.call(["2303","7","11","23","37","7"])=10524987427 -jsDate(10524987427)=2303/7/11 23:37:7 -PASS jsDate matches -PASS timestampToDateTime.call(10524987427) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10557035750)=["2304","7","16","21","55","50"] -timestampFromDateTime.call(["2304","7","16","21","55","50"])=10557035750 -jsDate(10557035750)=2304/7/16 21:55:50 -PASS jsDate matches -PASS timestampToDateTime.call(10557035750) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10589084074)=["2305","7","22","20","14","34"] -timestampFromDateTime.call(["2305","7","22","20","14","34"])=10589084074 -jsDate(10589084074)=2305/7/22 20:14:34 -PASS jsDate matches -PASS timestampToDateTime.call(10589084074) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10620668689)=["2306","7","23","9","44","49"] -timestampFromDateTime.call(["2306","7","23","9","44","49"])=10620668689 -jsDate(10620668689)=2306/7/23 9:44:49 -PASS jsDate matches -PASS timestampToDateTime.call(10620668689) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10652717012)=["2307","7","29","8","3","32"] -timestampFromDateTime.call(["2307","7","29","8","3","32"])=10652717012 -jsDate(10652717012)=2307/7/29 8:3:32 -PASS jsDate matches -PASS timestampToDateTime.call(10652717012) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10684765336)=["2308","8","3","6","22","16"] -timestampFromDateTime.call(["2308","8","3","6","22","16"])=10684765336 -jsDate(10684765336)=2308/8/3 6:22:16 -PASS jsDate matches -PASS timestampToDateTime.call(10684765336) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10716349951)=["2309","8","3","19","52","31"] -timestampFromDateTime.call(["2309","8","3","19","52","31"])=10716349951 -jsDate(10716349951)=2309/8/3 19:52:31 -PASS jsDate matches -PASS timestampToDateTime.call(10716349951) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10748398274)=["2310","8","9","18","11","14"] -timestampFromDateTime.call(["2310","8","9","18","11","14"])=10748398274 -jsDate(10748398274)=2310/8/9 18:11:14 -PASS jsDate matches -PASS timestampToDateTime.call(10748398274) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10780446598)=["2311","8","15","16","29","58"] -timestampFromDateTime.call(["2311","8","15","16","29","58"])=10780446598 -jsDate(10780446598)=2311/8/15 16:29:58 -PASS jsDate matches -PASS timestampToDateTime.call(10780446598) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10812031213)=["2312","8","15","6","0","13"] -timestampFromDateTime.call(["2312","8","15","6","0","13"])=10812031213 -jsDate(10812031213)=2312/8/15 6:0:13 -PASS jsDate matches -PASS timestampToDateTime.call(10812031213) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10844079536)=["2313","8","21","4","18","56"] -timestampFromDateTime.call(["2313","8","21","4","18","56"])=10844079536 -jsDate(10844079536)=2313/8/21 4:18:56 -PASS jsDate matches -PASS timestampToDateTime.call(10844079536) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10876127860)=["2314","8","27","2","37","40"] -timestampFromDateTime.call(["2314","8","27","2","37","40"])=10876127860 -jsDate(10876127860)=2314/8/27 2:37:40 -PASS jsDate matches -PASS timestampToDateTime.call(10876127860) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10907712475)=["2315","8","27","16","7","55"] -timestampFromDateTime.call(["2315","8","27","16","7","55"])=10907712475 -jsDate(10907712475)=2315/8/27 16:7:55 -PASS jsDate matches -PASS timestampToDateTime.call(10907712475) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10939760798)=["2316","9","1","14","26","38"] -timestampFromDateTime.call(["2316","9","1","14","26","38"])=10939760798 -jsDate(10939760798)=2316/9/1 14:26:38 -PASS jsDate matches -PASS timestampToDateTime.call(10939760798) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(10971809122)=["2317","9","7","12","45","22"] -timestampFromDateTime.call(["2317","9","7","12","45","22"])=10971809122 -jsDate(10971809122)=2317/9/7 12:45:22 -PASS jsDate matches -PASS timestampToDateTime.call(10971809122) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11003393737)=["2318","9","8","2","15","37"] -timestampFromDateTime.call(["2318","9","8","2","15","37"])=11003393737 -jsDate(11003393737)=2318/9/8 2:15:37 -PASS jsDate matches -PASS timestampToDateTime.call(11003393737) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11035442060)=["2319","9","14","0","34","20"] -timestampFromDateTime.call(["2319","9","14","0","34","20"])=11035442060 -jsDate(11035442060)=2319/9/14 0:34:20 -PASS jsDate matches -PASS timestampToDateTime.call(11035442060) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11067490384)=["2320","9","18","22","53","4"] -timestampFromDateTime.call(["2320","9","18","22","53","4"])=11067490384 -jsDate(11067490384)=2320/9/18 22:53:4 -PASS jsDate matches -PASS timestampToDateTime.call(11067490384) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11099074999)=["2321","9","19","12","23","19"] -timestampFromDateTime.call(["2321","9","19","12","23","19"])=11099074999 -jsDate(11099074999)=2321/9/19 12:23:19 -PASS jsDate matches -PASS timestampToDateTime.call(11099074999) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11131123322)=["2322","9","25","10","42","2"] -timestampFromDateTime.call(["2322","9","25","10","42","2"])=11131123322 -jsDate(11131123322)=2322/9/25 10:42:2 -PASS jsDate matches -PASS timestampToDateTime.call(11131123322) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11163171646)=["2323","10","1","9","0","46"] -timestampFromDateTime.call(["2323","10","1","9","0","46"])=11163171646 -jsDate(11163171646)=2323/10/1 9:0:46 -PASS jsDate matches -PASS timestampToDateTime.call(11163171646) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11194756261)=["2324","9","30","22","31","1"] -timestampFromDateTime.call(["2324","9","30","22","31","1"])=11194756261 -jsDate(11194756261)=2324/9/30 22:31:1 -PASS jsDate matches -PASS timestampToDateTime.call(11194756261) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11226804584)=["2325","10","6","20","49","44"] -timestampFromDateTime.call(["2325","10","6","20","49","44"])=11226804584 -jsDate(11226804584)=2325/10/6 20:49:44 -PASS jsDate matches -PASS timestampToDateTime.call(11226804584) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11258852908)=["2326","10","12","19","8","28"] -timestampFromDateTime.call(["2326","10","12","19","8","28"])=11258852908 -jsDate(11258852908)=2326/10/12 19:8:28 -PASS jsDate matches -PASS timestampToDateTime.call(11258852908) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11290437523)=["2327","10","13","8","38","43"] -timestampFromDateTime.call(["2327","10","13","8","38","43"])=11290437523 -jsDate(11290437523)=2327/10/13 8:38:43 -PASS jsDate matches -PASS timestampToDateTime.call(11290437523) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11322485846)=["2328","10","18","6","57","26"] -timestampFromDateTime.call(["2328","10","18","6","57","26"])=11322485846 -jsDate(11322485846)=2328/10/18 6:57:26 -PASS jsDate matches -PASS timestampToDateTime.call(11322485846) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11354534170)=["2329","10","24","5","16","10"] -timestampFromDateTime.call(["2329","10","24","5","16","10"])=11354534170 -jsDate(11354534170)=2329/10/24 5:16:10 -PASS jsDate matches -PASS timestampToDateTime.call(11354534170) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11386118785)=["2330","10","24","18","46","25"] -timestampFromDateTime.call(["2330","10","24","18","46","25"])=11386118785 -jsDate(11386118785)=2330/10/24 18:46:25 -PASS jsDate matches -PASS timestampToDateTime.call(11386118785) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11418167108)=["2331","10","30","17","5","8"] -timestampFromDateTime.call(["2331","10","30","17","5","8"])=11418167108 -jsDate(11418167108)=2331/10/30 17:5:8 -PASS jsDate matches -PASS timestampToDateTime.call(11418167108) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11450215432)=["2332","11","4","15","23","52"] -timestampFromDateTime.call(["2332","11","4","15","23","52"])=11450215432 -jsDate(11450215432)=2332/11/4 15:23:52 -PASS jsDate matches -PASS timestampToDateTime.call(11450215432) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11481800047)=["2333","11","5","4","54","7"] -timestampFromDateTime.call(["2333","11","5","4","54","7"])=11481800047 -jsDate(11481800047)=2333/11/5 4:54:7 -PASS jsDate matches -PASS timestampToDateTime.call(11481800047) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11513848370)=["2334","11","11","3","12","50"] -timestampFromDateTime.call(["2334","11","11","3","12","50"])=11513848370 -jsDate(11513848370)=2334/11/11 3:12:50 -PASS jsDate matches -PASS timestampToDateTime.call(11513848370) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11545896694)=["2335","11","17","1","31","34"] -timestampFromDateTime.call(["2335","11","17","1","31","34"])=11545896694 -jsDate(11545896694)=2335/11/17 1:31:34 -PASS jsDate matches -PASS timestampToDateTime.call(11545896694) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11577481309)=["2336","11","16","15","1","49"] -timestampFromDateTime.call(["2336","11","16","15","1","49"])=11577481309 -jsDate(11577481309)=2336/11/16 15:1:49 -PASS jsDate matches -PASS timestampToDateTime.call(11577481309) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11609529632)=["2337","11","22","13","20","32"] -timestampFromDateTime.call(["2337","11","22","13","20","32"])=11609529632 -jsDate(11609529632)=2337/11/22 13:20:32 -PASS jsDate matches -PASS timestampToDateTime.call(11609529632) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11641577956)=["2338","11","28","11","39","16"] -timestampFromDateTime.call(["2338","11","28","11","39","16"])=11641577956 -jsDate(11641577956)=2338/11/28 11:39:16 -PASS jsDate matches -PASS timestampToDateTime.call(11641577956) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11673162571)=["2339","11","29","1","9","31"] -timestampFromDateTime.call(["2339","11","29","1","9","31"])=11673162571 -jsDate(11673162571)=2339/11/29 1:9:31 -PASS jsDate matches -PASS timestampToDateTime.call(11673162571) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11705210894)=["2340","12","3","23","28","14"] -timestampFromDateTime.call(["2340","12","3","23","28","14"])=11705210894 -jsDate(11705210894)=2340/12/3 23:28:14 -PASS jsDate matches -PASS timestampToDateTime.call(11705210894) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11737259218)=["2341","12","9","21","46","58"] -timestampFromDateTime.call(["2341","12","9","21","46","58"])=11737259218 -jsDate(11737259218)=2341/12/9 21:46:58 -PASS jsDate matches -PASS timestampToDateTime.call(11737259218) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11768843833)=["2342","12","10","11","17","13"] -timestampFromDateTime.call(["2342","12","10","11","17","13"])=11768843833 -jsDate(11768843833)=2342/12/10 11:17:13 -PASS jsDate matches -PASS timestampToDateTime.call(11768843833) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11800892156)=["2343","12","16","9","35","56"] -timestampFromDateTime.call(["2343","12","16","9","35","56"])=11800892156 -jsDate(11800892156)=2343/12/16 9:35:56 -PASS jsDate matches -PASS timestampToDateTime.call(11800892156) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11832940480)=["2344","12","21","7","54","40"] -timestampFromDateTime.call(["2344","12","21","7","54","40"])=11832940480 -jsDate(11832940480)=2344/12/21 7:54:40 -PASS jsDate matches -PASS timestampToDateTime.call(11832940480) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11864525095)=["2345","12","21","21","24","55"] -timestampFromDateTime.call(["2345","12","21","21","24","55"])=11864525095 -jsDate(11864525095)=2345/12/21 21:24:55 -PASS jsDate matches -PASS timestampToDateTime.call(11864525095) => timestampFromDateTime.call(...) matches - -timestampToDateTime.call(11896573418)=["2346","12","27","19","43","38"] -timestampFromDateTime.call(["2346","12","27","19","43","38"])=11896573418 -jsDate(11896573418)=2346/12/27 19:43:38 -PASS jsDate matches -PASS timestampToDateTime.call(11896573418) => timestampFromDateTime.call(...) matches - ----------- PASS - no failures detected ---------- diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-30.360937280Z--a00af22d07c87d96eeeb0ed583f8f6ac7812827e b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-30.360937280Z--a00af22d07c87d96eeeb0ed583f8f6ac7812827e deleted file mode 100644 index 1326d83..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-30.360937280Z--a00af22d07c87d96eeeb0ed583f8f6ac7812827e +++ /dev/null @@ -1 +0,0 @@ -{"address":"a00af22d07c87d96eeeb0ed583f8f6ac7812827e","crypto":{"cipher":"aes-128-ctr","ciphertext":"7746ca0958bde0c8404f27e102f2fbb74eae623786ec344362e3434934a55b7d","cipherparams":{"iv":"5fc7dce773e69818a2d08f293657dbad"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f3675b3f9a1f414e429249eecc41c3ea20c6023012362fe8bf9e4ea231fc3801"},"mac":"c1fc366ec058c62c29e0e1668f997e20d08a9e57c7335dcf0d6d38e9faddfca5"},"id":"e3f0faf2-6ec2-4f29-a14e-c48d2d751b94","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-58.104082316Z--a11aae29840fbb5c86e6fd4cf809eba183aef433 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-58.104082316Z--a11aae29840fbb5c86e6fd4cf809eba183aef433 deleted file mode 100644 index aa5b3cb..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-37-58.104082316Z--a11aae29840fbb5c86e6fd4cf809eba183aef433 +++ /dev/null @@ -1 +0,0 @@ -{"address":"a11aae29840fbb5c86e6fd4cf809eba183aef433","crypto":{"cipher":"aes-128-ctr","ciphertext":"a025e7b46192578ac826200c281e6d7d83ba31c93c33c8d575dbe8fc1a75b1b9","cipherparams":{"iv":"b1e35272e6823a857e11627cfa20ffd6"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"0943b2a690f33601eba2a545435a3463d7d9b7ce96d15b544a0db14377ab5202"},"mac":"d2afc76e4fb19d01920e2822fd0cc760824b10e710ce565bdd1369d52fcdc741"},"id":"f1b73a4b-8229-4c3b-8844-f59f398087b0","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-21.169063367Z--a22ab8a9d641ce77e06d98b7d7065d324d3d6976 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-21.169063367Z--a22ab8a9d641ce77e06d98b7d7065d324d3d6976 deleted file mode 100644 index 3932072..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-21.169063367Z--a22ab8a9d641ce77e06d98b7d7065d324d3d6976 +++ /dev/null @@ -1 +0,0 @@ -{"address":"a22ab8a9d641ce77e06d98b7d7065d324d3d6976","crypto":{"cipher":"aes-128-ctr","ciphertext":"8a5a891ef2a10dc0d7faaa3bc01cd48d2bb38aca285f9acd73889f54e03ad017","cipherparams":{"iv":"17401904119a8f70861dfe9a9b02a463"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"e1e7f968847eaaf620f3c5e3541b6a3f0d8e00df9a9d470952eb6bf31cbb398b"},"mac":"de7767918e49ce2ec36b0dd8c85f8853f2b2db39da70f8b8a52d7d8c6856a6de"},"id":"baa6c875-74cf-4c02-ace7-c8c6aa32765f","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-41.707647638Z--a33a6c312d9ad0e0f2e95541beed0cc081621fd0 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-41.707647638Z--a33a6c312d9ad0e0f2e95541beed0cc081621fd0 deleted file mode 100644 index 677c783..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-38-41.707647638Z--a33a6c312d9ad0e0f2e95541beed0cc081621fd0 +++ /dev/null @@ -1 +0,0 @@ -{"address":"a33a6c312d9ad0e0f2e95541beed0cc081621fd0","crypto":{"cipher":"aes-128-ctr","ciphertext":"6291be87d8beb1a5a9833946c0727a93f531c341316d3ca32a97e36513b829bf","cipherparams":{"iv":"37e0e2897ff5de0a2b34ddbc7f67a7bd"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"2633c529cb47901bba6f3cf8acb8aa3f27d218e3120b1f0832f5acac7e12830a"},"mac":"b1ace4451045b2cb06507a719e7e9edb97b7c9ce38e42014472cbb4f52ed4d5f"},"id":"7ab0d4a9-c6b5-426f-9445-1604929628c2","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-39-04.584040707Z--a44a08d3f6933c69212114bb66e2df1813651844 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-39-04.584040707Z--a44a08d3f6933c69212114bb66e2df1813651844 deleted file mode 100644 index b31da20..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-39-04.584040707Z--a44a08d3f6933c69212114bb66e2df1813651844 +++ /dev/null @@ -1 +0,0 @@ -{"address":"a44a08d3f6933c69212114bb66e2df1813651844","crypto":{"cipher":"aes-128-ctr","ciphertext":"0334a6431e1278ef00ec18262d71325fb6cbec744708bdd306757d23bf9665b2","cipherparams":{"iv":"707c645f21c317d506b7f0d3073d85a1"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"7bc76dc778baef6878f043da5461f40faa700d029b8dbde5a10a7899129e329a"},"mac":"ffb6282494f01133507fc97bf57d8a7644205e0dab33dc977bf809e541c8f41e"},"id":"356880ad-1c9d-4bd1-92ce-48de1a668c8f","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-01.013666678Z--a55a151eb00fded1634d27d1127b4be4627079ea b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-01.013666678Z--a55a151eb00fded1634d27d1127b4be4627079ea deleted file mode 100644 index e728140..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-01.013666678Z--a55a151eb00fded1634d27d1127b4be4627079ea +++ /dev/null @@ -1 +0,0 @@ -{"address":"a55a151eb00fded1634d27d1127b4be4627079ea","crypto":{"cipher":"aes-128-ctr","ciphertext":"ee8985250e7b89990b8614f9ceec5f96f11e66ef147e2a689ac29bcdbab5142c","cipherparams":{"iv":"594d35ce8d73e0efb89ddc882f13d912"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"e9635fc62fb0b9db5c0ffa6cd415f7b58c3dc4b5d9af700aac347a568792dc82"},"mac":"6b035510432179623cbaa5d3306106d5c608695fde89d7ec2d3aff5f484a6376"},"id":"47bfbb81-5b55-4cf4-9289-80e2fe0fbd9c","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-37.426191216Z--a66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-37.426191216Z--a66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 deleted file mode 100644 index 8f16149..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-37.426191216Z--a66a85ede0cbe03694aa9d9de0bb19c99ff55bd9 +++ /dev/null @@ -1 +0,0 @@ -{"address":"a66a85ede0cbe03694aa9d9de0bb19c99ff55bd9","crypto":{"cipher":"aes-128-ctr","ciphertext":"f1b8dfabcdc9da96c9ee44a0ee7005b17bcdeda702e7fb17624a35bd51252d28","cipherparams":{"iv":"c762e2bd794022892e1d99c7494b7a41"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"d92954d1c8073978d17c5943b72aa826108c8cc927b1097a7ea3ef71b02d15cc"},"mac":"dd118288bb676dca7a7607ff86ed02eccfa4dfac2ebef69bf52dc0304e1af465"},"id":"396c5807-24e8-4a78-a76e-5dfcd0e2dfe4","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-58.899396047Z--a77a2b9d4b1c010a22a7c565dc418cef683dbcec b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-58.899396047Z--a77a2b9d4b1c010a22a7c565dc418cef683dbcec deleted file mode 100644 index a634564..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-42-58.899396047Z--a77a2b9d4b1c010a22a7c565dc418cef683dbcec +++ /dev/null @@ -1 +0,0 @@ -{"address":"a77a2b9d4b1c010a22a7c565dc418cef683dbcec","crypto":{"cipher":"aes-128-ctr","ciphertext":"6f4262c172be2e9053e556380e5ea842959e0ffa51c17fc270259832f3cfe91a","cipherparams":{"iv":"b056c35ee783e7bcdf58e70b717c8bf8"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"35a93f01a9cc1dcb323305b15cdd22ad899796f620783fab8512b0100eb478da"},"mac":"20088a8203dc6e2a8ff5288799700aaf969424912cdfd5b1e9262fd703ea2da8"},"id":"46a2e757-d4e9-40ba-aec4-6640d7b74347","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-09.150580614Z--a88a05d2b88283ce84c8325760b72a64591279a2 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-09.150580614Z--a88a05d2b88283ce84c8325760b72a64591279a2 deleted file mode 100644 index 2facc97..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-09.150580614Z--a88a05d2b88283ce84c8325760b72a64591279a2 +++ /dev/null @@ -1 +0,0 @@ -{"address":"a88a05d2b88283ce84c8325760b72a64591279a2","crypto":{"cipher":"aes-128-ctr","ciphertext":"3d3331aeb08de887031a50ec00c4385dc2f3ee28b3f720b788964b45a77321c7","cipherparams":{"iv":"c5024557ef11f71d86209aa5cb9c90bd"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"130cd49e03cbf0eccba0d430c7c545be2dd9ed78120b42a128974b63e644c283"},"mac":"e98487a07e49dcde74e890d1dd9ea51d07aa62ecf19d96c782599c265c5a90c7"},"id":"5083b6d1-3059-457f-bdae-6a413a222428","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-34.770098207Z--a99a0ae3354c06b1459fd441a32a3f71005d7da0 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-34.770098207Z--a99a0ae3354c06b1459fd441a32a3f71005d7da0 deleted file mode 100644 index c92351b..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-47-34.770098207Z--a99a0ae3354c06b1459fd441a32a3f71005d7da0 +++ /dev/null @@ -1 +0,0 @@ -{"address":"a99a0ae3354c06b1459fd441a32a3f71005d7da0","crypto":{"cipher":"aes-128-ctr","ciphertext":"92983913294e4fac0d23b2aa87371c63538e3735fc99c9212f4b3db8301ecccf","cipherparams":{"iv":"cab44152a75c5abccdb1f90a849c84ca"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"29ac10474ba160267a637197d12e938ee313daa501f6b0883ae96da4c19f6155"},"mac":"224930b5688b9e0cc77d321610e440c32af3372fe4b17d8e451bf2c3c89ddf25"},"id":"47cc9299-fea0-46c6-88e8-452fb714ca4c","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-17.400859858Z--aaaa9de1e6c564446ebca0fd102d8bd92093c756 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-17.400859858Z--aaaa9de1e6c564446ebca0fd102d8bd92093c756 deleted file mode 100644 index 9ed8a8c..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-17.400859858Z--aaaa9de1e6c564446ebca0fd102d8bd92093c756 +++ /dev/null @@ -1 +0,0 @@ -{"address":"aaaa9de1e6c564446ebca0fd102d8bd92093c756","crypto":{"cipher":"aes-128-ctr","ciphertext":"525cb018c05b12bb038b9802c8d28dda40bdd8027a5a94efdfe5f06d13428020","cipherparams":{"iv":"31b96dade192e677db9d03ca2da3dd4b"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"aaf8e556d62452fb946046397c8c58545cbb1e118a3f3e3b8cc2995a2e9020a7"},"mac":"bbc30ecbf1ca76ee507c08db2dc07611b29a69a5f3de3bb2b0c92a1b8e0cb6b3"},"id":"9ae73070-0b07-472c-bfe5-e07cbe66f289","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-35.122799190Z--abba43e7594e3b76afb157989e93c6621497fd4b b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-35.122799190Z--abba43e7594e3b76afb157989e93c6621497fd4b deleted file mode 100644 index 4d6513a..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-35.122799190Z--abba43e7594e3b76afb157989e93c6621497fd4b +++ /dev/null @@ -1 +0,0 @@ -{"address":"abba43e7594e3b76afb157989e93c6621497fd4b","crypto":{"cipher":"aes-128-ctr","ciphertext":"9d93b2417788589c2bbc56d829189ee7014a131cde75ff222ed95765760e33e9","cipherparams":{"iv":"72adceb8556da2df85337eb7e3857e91"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f81be6c897007703d414b4849894395cecb982380791ff29b9742ee7ab1b9437"},"mac":"ed0dbee8cbde6219c7c15c501ca31146705c0d310301aa73311c0bf943712127"},"id":"be47d6a6-f747-4741-bdfd-33182d2f674d","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-51.178332229Z--acca534c9f62ab495bd986e002ddf0f054caae4f b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-51.178332229Z--acca534c9f62ab495bd986e002ddf0f054caae4f deleted file mode 100644 index 1766622..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-58-51.178332229Z--acca534c9f62ab495bd986e002ddf0f054caae4f +++ /dev/null @@ -1 +0,0 @@ -{"address":"acca534c9f62ab495bd986e002ddf0f054caae4f","crypto":{"cipher":"aes-128-ctr","ciphertext":"95204bfd49fad4e3ef709e55857b0fa9f0e9d03c1e2219a44408bddafd45ba72","cipherparams":{"iv":"9ae7d4de6b7d7d78fd0c6499dda0f35d"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"2be91d7a047ae89c934f2b09b541887ac8a7dfb99df658e05f9ee05f2c5ef478"},"mac":"d9abc981e0b3d7ca60d3138dce58e5529bb12fee092cdd77a0a93b453e22dd3b"},"id":"3cae58b4-bdd3-43ee-929c-b1eff57e10ad","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-14.034178720Z--adda9b762a00ff12711113bfdc36958b73d7f915 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-14.034178720Z--adda9b762a00ff12711113bfdc36958b73d7f915 deleted file mode 100644 index 01d6310..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-14.034178720Z--adda9b762a00ff12711113bfdc36958b73d7f915 +++ /dev/null @@ -1 +0,0 @@ -{"address":"adda9b762a00ff12711113bfdc36958b73d7f915","crypto":{"cipher":"aes-128-ctr","ciphertext":"0bacd07a24fee23bcb01e05f7f75ba8fc862500a8c76274dcdb85c6f46886623","cipherparams":{"iv":"e7ec110f1ff5d8bfc45f7d73e19dbd9f"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"b774e6680f20cafce454fc994ad2ba33afd3556feeea7f5338bcaadeb3559de3"},"mac":"fec0ec38202864975845c5602150c62b8ade0538cfdb9b6a0cdbaf48a916d18c"},"id":"b6b3a3ab-35fe-48aa-a74a-681a08cfea36","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-33.471449656Z--aeea63b5479b50f79583ec49dacdcf86ddeff392 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-33.471449656Z--aeea63b5479b50f79583ec49dacdcf86ddeff392 deleted file mode 100644 index c79f607..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-33.471449656Z--aeea63b5479b50f79583ec49dacdcf86ddeff392 +++ /dev/null @@ -1 +0,0 @@ -{"address":"aeea63b5479b50f79583ec49dacdcf86ddeff392","crypto":{"cipher":"aes-128-ctr","ciphertext":"88e5fd79e85032bb427b082f9875de72b21aca1acb0370b59fe301306510f68f","cipherparams":{"iv":"da6522bfd41e2676def953ee017f5f23"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"a8770326e860c28a45d1aff231560bc00a69622dad0f50d9ff395ec1f6f1b453"},"mac":"128e84afe94656cc89e96180676607cfaae0c4b220eec2e11642b7cd38146226"},"id":"b6dcecff-9bbb-40c5-bcea-501e3d610c7b","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-51.697690594Z--affa4d3a80add8ce4018540e056dacb649589394 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-51.697690594Z--affa4d3a80add8ce4018540e056dacb649589394 deleted file mode 100644 index 613dde0..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-05-20T02-59-51.697690594Z--affa4d3a80add8ce4018540e056dacb649589394 +++ /dev/null @@ -1 +0,0 @@ -{"address":"affa4d3a80add8ce4018540e056dacb649589394","crypto":{"cipher":"aes-128-ctr","ciphertext":"575889b5c78941e143e3af18ab2fd614d6a36846dbc424bda006f40a8ccdd4ef","cipherparams":{"iv":"1a6fb0f7f7bbf9692568853037786fa2"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"4ec7f5ad42e5c55fd8eac0f0553a1e6a5c363d8e835fc048673560f9e36bfcfc"},"mac":"6373ec14230362fc815c2929b8058a83b9a2f3e6d3e92b35c2d2696a0ba4cf8d"},"id":"8af80842-e108-4256-b33f-9fa5fb5f6de5","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-46-38.500831000Z--b00bfde102270687324f9205b693859df64f8923 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-46-38.500831000Z--b00bfde102270687324f9205b693859df64f8923 deleted file mode 100644 index 3e5e325..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-46-38.500831000Z--b00bfde102270687324f9205b693859df64f8923 +++ /dev/null @@ -1 +0,0 @@ -{"address":"b00bfde102270687324f9205b693859df64f8923","crypto":{"cipher":"aes-128-ctr","ciphertext":"35a15a36140fe96dd1eca2b68fbbfd950e892edd5cb1885c99f0ef67ad83d93a","cipherparams":{"iv":"f1fe0fa1b348fb133087f82eb01780b8"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f152543f3b3ec82d834273256aff02ea0776323c31b3f1b5f2717e5bd428e9a3"},"mac":"851663b1e882a5443e64f886ae38aed51544f7603a73433d587272871316f5b8"},"id":"cb1bb6d8-9c68-46ce-93cb-36e33ffd19c6","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-13.633282000Z--b11be1d4ef8e94d01cb2695092a79d139a8dad98 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-13.633282000Z--b11be1d4ef8e94d01cb2695092a79d139a8dad98 deleted file mode 100644 index 1faa375..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-13.633282000Z--b11be1d4ef8e94d01cb2695092a79d139a8dad98 +++ /dev/null @@ -1 +0,0 @@ -{"address":"b11be1d4ef8e94d01cb2695092a79d139a8dad98","crypto":{"cipher":"aes-128-ctr","ciphertext":"4fcea88902f73ca1b8436f901116dd708e4f5523b377fd0712856f1aea29eb90","cipherparams":{"iv":"eb7e8d31dc6a2cfc97e246736d36e915"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"3b5af400423f21363f700cc06f83f59d5391812520572c76bcdab0f257f01651"},"mac":"1664521b7de10c689094f73b90f724ac864d56cbac4b84e7efd0730f70dba747"},"id":"f88012ab-cbc8-43b0-bd2f-0b7d2a3edc95","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-34.792913000Z--b22be2d9eef0d7e260cf96a64feea0b95ed3e74f b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-34.792913000Z--b22be2d9eef0d7e260cf96a64feea0b95ed3e74f deleted file mode 100644 index b5973bc..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-47-34.792913000Z--b22be2d9eef0d7e260cf96a64feea0b95ed3e74f +++ /dev/null @@ -1 +0,0 @@ -{"address":"b22be2d9eef0d7e260cf96a64feea0b95ed3e74f","crypto":{"cipher":"aes-128-ctr","ciphertext":"832a92865948d045dd35a0f2bce83bc6de81549b9d42dbd65c7a7fcd85dd3bf6","cipherparams":{"iv":"05e0d8e5a40ea28f19d4b6476fc00c9b"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"3b62430be26cdee906d5478258e0bb3161c71c285ea7cda7086679d83a81ac9f"},"mac":"d201c1b1b483b0f35e6cd3c683aee09825fc99c4eb696ae3095a857a23cade03"},"id":"bc0436d0-09ff-4445-8ac7-9908950ff795","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-50-14.030093000Z--b33b7ecf5e47be3981c74d989d3af8b665b4b649 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-50-14.030093000Z--b33b7ecf5e47be3981c74d989d3af8b665b4b649 deleted file mode 100644 index 94b58c8..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-50-14.030093000Z--b33b7ecf5e47be3981c74d989d3af8b665b4b649 +++ /dev/null @@ -1 +0,0 @@ -{"address":"b33b7ecf5e47be3981c74d989d3af8b665b4b649","crypto":{"cipher":"aes-128-ctr","ciphertext":"3a3b04be39786bf87a9f4b4b2690379b4eca20b8ad4d0da2006411f05c07efe3","cipherparams":{"iv":"c815748114f2d09d6d15d3a00b3a483d"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"d89f0c41bed67c651bfe912ea7ead8cb413b1ee0a69143a1260bd0bcae40ac84"},"mac":"89230f76ec55390f350b5382ac5d37e13e77d2d161d7de04b8610df7b55a7581"},"id":"2dab1c9d-f601-4650-b48e-dcdff71f507e","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-51-02.743266000Z--b44b43d59b738b088b690ae276c1e979aba8268d b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-51-02.743266000Z--b44b43d59b738b088b690ae276c1e979aba8268d deleted file mode 100644 index 29be954..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-51-02.743266000Z--b44b43d59b738b088b690ae276c1e979aba8268d +++ /dev/null @@ -1 +0,0 @@ -{"address":"b44b43d59b738b088b690ae276c1e979aba8268d","crypto":{"cipher":"aes-128-ctr","ciphertext":"e6bbab4c2bfcfaa33bbafacae6cc571b5db9857f3a7fdab78e876476635e3a00","cipherparams":{"iv":"f093dbbc316014d016b2bc32bd32780b"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"0080c34c2d31eecb545ebea48d24ee707d9e553fcc99f5c552def09806fba6f8"},"mac":"3eef10bc5656f54f38f4948af7e17ad970e739647487a9d1ecc797caecf2c06d"},"id":"a6c44866-ec89-4c2d-94a9-750a4150f24a","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-16.250696000Z--b55b57d113b45481e31aaf03d6f4e5ad4ef325f8 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-16.250696000Z--b55b57d113b45481e31aaf03d6f4e5ad4ef325f8 deleted file mode 100644 index d4bbda7..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-16.250696000Z--b55b57d113b45481e31aaf03d6f4e5ad4ef325f8 +++ /dev/null @@ -1 +0,0 @@ -{"address":"b55b57d113b45481e31aaf03d6f4e5ad4ef325f8","crypto":{"cipher":"aes-128-ctr","ciphertext":"2fce0fe5d7e583df0cef51e29bcc38dd0c398ae726875681e6d58cd82f462636","cipherparams":{"iv":"64d3586f82f429a940cb76913a3e5de0"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"6236c42555711facadffd9756963240c109fdf7a5b47fc2c136d4f597393c97e"},"mac":"3a523b8196c671c21e93d29c51dc5f44fb73aae24e79a8a22193d08241acb6de"},"id":"64956427-5805-4c06-bfaf-0ea4c2d22093","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-56.678333000Z--b66bcb4e473de80e2c8a47ced10c22c705a5e602 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-56.678333000Z--b66bcb4e473de80e2c8a47ced10c22c705a5e602 deleted file mode 100644 index 8fa9ba7..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-53-56.678333000Z--b66bcb4e473de80e2c8a47ced10c22c705a5e602 +++ /dev/null @@ -1 +0,0 @@ -{"address":"b66bcb4e473de80e2c8a47ced10c22c705a5e602","crypto":{"cipher":"aes-128-ctr","ciphertext":"fc80becce2d16f01c117c298bb24436e9eebfc43d07b76760ae62825a12569cc","cipherparams":{"iv":"42e5d0f5a5ea7b0e3e433edda6a4147b"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ab72efd6bdf0c9f07b272bc1a030db8918007b9b9faf3c8096e80db016c6dbe4"},"mac":"2b45bd7c8167b76c9c95c77747ac933318acaea2aade500f5394c5321f9a41c7"},"id":"45c4cf16-2bf0-46f3-bc41-1b582ba794fa","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-55-56.546405000Z--b77bbbaa7c1649547ae61de4b80b91568c28351a b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-55-56.546405000Z--b77bbbaa7c1649547ae61de4b80b91568c28351a deleted file mode 100644 index b055ced..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-55-56.546405000Z--b77bbbaa7c1649547ae61de4b80b91568c28351a +++ /dev/null @@ -1 +0,0 @@ -{"address":"b77bbbaa7c1649547ae61de4b80b91568c28351a","crypto":{"cipher":"aes-128-ctr","ciphertext":"767d6658fb2fe43c47de4b40a9fc2ce7bddd2f518566276da20f9f389d38e142","cipherparams":{"iv":"85d12a9dea777bf7537261405af7a3ff"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"b72744837e610dd9384af2ccaac73cd90fb41c543427e18bf706ec53f2270502"},"mac":"fa6fe6e6996ec6683bbba4851c6544f2484f898f3a1b247612b8fb811612fd94"},"id":"e18c9c63-ce88-4b96-8085-88549589cccf","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-58-22.605806000Z--b88b728490b417e29b0784db30535db343830dba b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-58-22.605806000Z--b88b728490b417e29b0784db30535db343830dba deleted file mode 100644 index 3fa0afe..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-58-22.605806000Z--b88b728490b417e29b0784db30535db343830dba +++ /dev/null @@ -1 +0,0 @@ -{"address":"b88b728490b417e29b0784db30535db343830dba","crypto":{"cipher":"aes-128-ctr","ciphertext":"31e956f9396b0d179c1136a03cfa7fc3c8f0f980b48537836aacec7f61bc8886","cipherparams":{"iv":"5d2778c9221aab3c0525f562b2f87ef5"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"d9f0731deef314e2772397e838b65410fa26d282d927c8254b839a4eac42e1fe"},"mac":"8c1e4c56aba715e04f0f8ce48460f47f194c10d7a18ca501ba6d019fa85f1768"},"id":"a0038920-3917-43eb-b308-80f7e660f77b","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-59-11.614985000Z--b99b3d1f72edb05a0321db58eddcf83fd73c4ade b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-59-11.614985000Z--b99b3d1f72edb05a0321db58eddcf83fd73c4ade deleted file mode 100644 index d5e45a0..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T03-59-11.614985000Z--b99b3d1f72edb05a0321db58eddcf83fd73c4ade +++ /dev/null @@ -1 +0,0 @@ -{"address":"b99b3d1f72edb05a0321db58eddcf83fd73c4ade","crypto":{"cipher":"aes-128-ctr","ciphertext":"05fd0fbb32d77fe2b2bc8f263b9537a55344c1c7548e523a4fb8c55d11994613","cipherparams":{"iv":"c111f6674336e452981b474d770d28e7"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"449f356632539f47beaff2a41cb55d28b00755aef0aaadf60ac1fed6a6fd94de"},"mac":"de231546e4b1b03da76dfab1f77b2658109234eddcd7e3c15da92d0931f5664f"},"id":"5bba5e7f-db58-45f4-adb4-c6d8a285b018","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-06.765694000Z--baab56da883edbe5314b8005be410022c510ccae b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-06.765694000Z--baab56da883edbe5314b8005be410022c510ccae deleted file mode 100644 index 9809c1c..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-06.765694000Z--baab56da883edbe5314b8005be410022c510ccae +++ /dev/null @@ -1 +0,0 @@ -{"address":"baab56da883edbe5314b8005be410022c510ccae","crypto":{"cipher":"aes-128-ctr","ciphertext":"2776d97b30f53bfda59941dc62a5e5267a383160e94e60c79877ad337b0d237f","cipherparams":{"iv":"c1d4d608e272f4fc02d8a9436161cae2"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"23244e4fd4394d6effe0c05af91af1db41b8e7ba7b953bf2bd8df10d549297a3"},"mac":"e3b0a4bc3cb9912247bc1285f2b5a2e4cd772872a1519efbd347c9fd3e1bde24"},"id":"c53d37a2-0791-4915-89d0-15beee16f8a2","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-29.951106000Z--bbbb9809de0456ce0e0cd660e6e4ceabef3f521c b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-29.951106000Z--bbbb9809de0456ce0e0cd660e6e4ceabef3f521c deleted file mode 100644 index 04a9661..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-00-29.951106000Z--bbbb9809de0456ce0e0cd660e6e4ceabef3f521c +++ /dev/null @@ -1 +0,0 @@ -{"address":"bbbb9809de0456ce0e0cd660e6e4ceabef3f521c","crypto":{"cipher":"aes-128-ctr","ciphertext":"60f89b1ca820a34e0d2c25321f338836ab3873efcc3ccefa99403bb8ef7d34ac","cipherparams":{"iv":"0ffce5b666507c9e1c910cdadd2b6661"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"facd3a865fc9d97ad636a1bd3e8ef540f2036ee4765468843a6786e6cb727aa7"},"mac":"dcbca27db50cd3ac35b75d28a17a50242d699b285ce822b9d409e1e927fa1913"},"id":"77d9c9bd-be5f-46de-861c-949cdf437610","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-29.293263000Z--bccb68dd0ac87ef290aef49870d155f076c87868 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-29.293263000Z--bccb68dd0ac87ef290aef49870d155f076c87868 deleted file mode 100644 index 959d4a8..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-29.293263000Z--bccb68dd0ac87ef290aef49870d155f076c87868 +++ /dev/null @@ -1 +0,0 @@ -{"address":"bccb68dd0ac87ef290aef49870d155f076c87868","crypto":{"cipher":"aes-128-ctr","ciphertext":"e2f82512052dc1e7ed9a435f08876b241f42332dfdfc96f6ee197310b2d50468","cipherparams":{"iv":"a12c55d704f3e2aa8b18eee04cbbddc0"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"91bbbf4f3301d395ebfffb741ffa1764ff198f7688f2211cd77f5b9b99d419d0"},"mac":"202a5b0fd250f90a786d01e9f17cd7eb431f5093abc74a96c6c0fd493844d56e"},"id":"f6728945-50eb-40d7-b74f-225210bdb27d","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-54.216243000Z--bddb726ee06906e104db210e6d0506f2b062e477 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-54.216243000Z--bddb726ee06906e104db210e6d0506f2b062e477 deleted file mode 100644 index f70f986..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-02-54.216243000Z--bddb726ee06906e104db210e6d0506f2b062e477 +++ /dev/null @@ -1 +0,0 @@ -{"address":"bddb726ee06906e104db210e6d0506f2b062e477","crypto":{"cipher":"aes-128-ctr","ciphertext":"fc86d192ff984371fe9a307a94622f52b83d243df1c1e2c87c95cfe404cab9d0","cipherparams":{"iv":"abac565370e5ef73b3a300b993eef903"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"0e17376f4214ed015ec12f9531eb7087293a792a27cfc799a718a34b4a9f006f"},"mac":"37e419d92fe7afe29dce9facd3be51929a0121f6579040fca8b7a7eaeb4f8360"},"id":"cdbc98f8-59c3-4823-9f6f-f02e652315fb","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-08-54.756436000Z--beeb24ff18203658d0a1d4682ee3f36ad663ec87 b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-08-54.756436000Z--beeb24ff18203658d0a1d4682ee3f36ad663ec87 deleted file mode 100644 index 9bf024d..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-08-54.756436000Z--beeb24ff18203658d0a1d4682ee3f36ad663ec87 +++ /dev/null @@ -1 +0,0 @@ -{"address":"beeb24ff18203658d0a1d4682ee3f36ad663ec87","crypto":{"cipher":"aes-128-ctr","ciphertext":"867f7f20c9bc0cc77e33f5ffe654ec64d700cbfe8b95a9cd35a035c669a4f7df","cipherparams":{"iv":"2ded8c674918626a2f8b0b2442f63b5e"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"9e48eb9d0e9d138512251dde8ccbed433616704bc88dc17d688199d24bfb504e"},"mac":"ea4a9704c4974fce6b85f3f95b31a1e64ed294c69ea2e5110f837ea73b85d595"},"id":"7af67eed-c600-4622-a939-6700bbd25c75","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-09-53.679255000Z--bffbd8f029ef0bd81cf754b53e8b3a5684f8b3ff b/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-09-53.679255000Z--bffbd8f029ef0bd81cf754b53e8b3a5684f8b3ff deleted file mode 100644 index e3a3b90..0000000 --- a/typescript/packages/account-modules/lib/BokkyPooBahsDateTimeLibrary/test/testchain/keystore/UTC--2017-11-23T04-09-53.679255000Z--bffbd8f029ef0bd81cf754b53e8b3a5684f8b3ff +++ /dev/null @@ -1 +0,0 @@ -{"address":"bffbd8f029ef0bd81cf754b53e8b3a5684f8b3ff","crypto":{"cipher":"aes-128-ctr","ciphertext":"74d1fbc0f815262e20f6dc089c7370c64678a56cc2ebf8bd54f0e8cff854e61f","cipherparams":{"iv":"46f9abced6bb053168b1cc1ed1c759a3"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ca6928880f930bc6ab285ccc798dc25de1540b059b885306825f7b98a8ffceb8"},"mac":"ec1dd0e7454ad21e9a22173e1209ea0355e96d583eb8fc4d4ff603de9155875b"},"id":"42466d6f-39e7-4b07-bafb-5409d60fc2bc","version":3} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/forge-std/.gitattributes b/typescript/packages/account-modules/lib/forge-std/.gitattributes deleted file mode 100644 index 27042d4..0000000 --- a/typescript/packages/account-modules/lib/forge-std/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -src/Vm.sol linguist-generated diff --git a/typescript/packages/account-modules/lib/forge-std/.github/CODEOWNERS b/typescript/packages/account-modules/lib/forge-std/.github/CODEOWNERS deleted file mode 100644 index 63b25bb..0000000 --- a/typescript/packages/account-modules/lib/forge-std/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @danipopes @klkvr @mattsse @grandizzy @yash-atreya @zerosnacks diff --git a/typescript/packages/account-modules/lib/forge-std/.github/workflows/ci.yml b/typescript/packages/account-modules/lib/forge-std/.github/workflows/ci.yml deleted file mode 100644 index c7a547c..0000000 --- a/typescript/packages/account-modules/lib/forge-std/.github/workflows/ci.yml +++ /dev/null @@ -1,82 +0,0 @@ -name: CI - -on: - workflow_dispatch: - pull_request: - push: - branches: - - master - -jobs: - build: - name: build +${{ matrix.toolchain }} ${{ matrix.flags }} - runs-on: ubuntu-latest - timeout-minutes: 10 - strategy: - fail-fast: false - matrix: - toolchain: [stable, nightly] - flags: - - "" - - --via-ir - - --use solc:0.8.17 --via-ir - - --use solc:0.8.17 - - --use solc:0.8.0 - - --use solc:0.7.6 - - --use solc:0.7.0 - - --use solc:0.6.2 - - --use solc:0.6.12 - steps: - - uses: actions/checkout@v4 - - uses: foundry-rs/foundry-toolchain@v1 - - run: forge --version - - run: forge build --skip test --deny-warnings ${{ matrix.flags }} - # via-ir compilation time checks. - - if: contains(matrix.flags, '--via-ir') - run: forge build --skip test --deny-warnings ${{ matrix.flags }} --contracts 'test/compilation/*' - - test: - runs-on: ubuntu-latest - timeout-minutes: 10 - strategy: - fail-fast: false - matrix: - toolchain: [stable, nightly] - steps: - - uses: actions/checkout@v4 - - uses: foundry-rs/foundry-toolchain@v1 - with: - version: ${{ matrix.toolchain }} - - run: forge --version - - run: forge test -vvv - - fmt: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: actions/checkout@v4 - - uses: foundry-rs/foundry-toolchain@v1 - - run: forge --version - - run: forge fmt --check - - typos: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: actions/checkout@v4 - - uses: crate-ci/typos@v1 - - ci-success: - runs-on: ubuntu-latest - if: always() - needs: - - build - - test - - fmt - - typos - timeout-minutes: 10 - steps: - - name: Decide whether the needed jobs succeeded or failed - uses: re-actors/alls-green@release/v1 - with: - jobs: ${{ toJSON(needs) }} diff --git a/typescript/packages/account-modules/lib/forge-std/.github/workflows/sync.yml b/typescript/packages/account-modules/lib/forge-std/.github/workflows/sync.yml deleted file mode 100644 index 9b170f0..0000000 --- a/typescript/packages/account-modules/lib/forge-std/.github/workflows/sync.yml +++ /dev/null @@ -1,31 +0,0 @@ -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@v4 - with: - fetch-depth: 0 - ref: v1 - - # The email is derived from the bots user id, - # found here: https://api.github.com/users/github-actions%5Bbot%5D - - 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/typescript/packages/account-modules/lib/forge-std/.gitignore b/typescript/packages/account-modules/lib/forge-std/.gitignore deleted file mode 100644 index 756106d..0000000 --- a/typescript/packages/account-modules/lib/forge-std/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -cache/ -out/ -.vscode -.idea diff --git a/typescript/packages/account-modules/lib/forge-std/CONTRIBUTING.md b/typescript/packages/account-modules/lib/forge-std/CONTRIBUTING.md deleted file mode 100644 index 89b75f3..0000000 --- a/typescript/packages/account-modules/lib/forge-std/CONTRIBUTING.md +++ /dev/null @@ -1,193 +0,0 @@ -## Contributing to Foundry - -Thanks for your interest in improving Foundry! - -There are multiple opportunities to contribute at any level. It doesn't matter if you are just getting started with Rust or are the most weathered expert, we can use your help. - -This document will help you get started. **Do not let the document intimidate you**. -It should be considered as a guide to help you navigate the process. - -The [dev Telegram][dev-tg] is available for any concerns you may have that are not covered in this guide. - -### Code of Conduct - -The Foundry project adheres to the [Rust Code of Conduct][rust-coc]. This code of conduct describes the _minimum_ behavior expected from all contributors. - -Instances of violations of the Code of Conduct can be reported by contacting the team at [me@gakonst.com](mailto:me@gakonst.com). - -### Ways to contribute - -There are fundamentally four ways an individual can contribute: - -1. **By opening an issue:** For example, if you believe that you have uncovered a bug - in Foundry, creating a new issue in the issue tracker is the way to report it. -2. **By adding context:** Providing additional context to existing issues, - such as screenshots and code snippets, which help resolve issues. -3. **By resolving issues:** Typically this is done in the form of either - demonstrating that the issue reported is not a problem after all, or more often, - by opening a pull request that fixes the underlying problem, in a concrete and - reviewable manner. - -**Anybody can participate in any stage of contribution**. We urge you to participate in the discussion -around bugs and participate in reviewing PRs. - -### Contributions Related to Spelling and Grammar - -At this time, we will not be accepting contributions that only fix spelling or grammatical errors in documentation, code or -elsewhere. - -### Asking for help - -If you have reviewed existing documentation and still have questions, or you are having problems, you can get help in the following ways: - -- **Asking in the support Telegram:** The [Foundry Support Telegram][support-tg] is a fast and easy way to ask questions. -- **Opening a discussion:** This repository comes with a discussions board where you can also ask for help. Click the "Discussions" tab at the top. - -As Foundry is still in heavy development, the documentation can be a bit scattered. -The [Foundry Book][foundry-book] is our current best-effort attempt at keeping up-to-date information. - -### Submitting a bug report - -When filing a new bug report in the issue tracker, you will be presented with a basic form to fill out. - -If you believe that you have uncovered a bug, please fill out the form to the best of your ability. Do not worry if you cannot answer every detail; just fill in what you can. Contributors will ask follow-up questions if something is unclear. - -The most important pieces of information we need in a bug report are: - -- The Foundry version you are on (and that it is up to date) -- The platform you are on (Windows, macOS, an M1 Mac or Linux) -- Code snippets if this is happening in relation to testing or building code -- Concrete steps to reproduce the bug - -In order to rule out the possibility of the bug being in your project, the code snippets should be as minimal -as possible. It is better if you can reproduce the bug with a small snippet as opposed to an entire project! - -See [this guide][mcve] on how to create a minimal, complete, and verifiable example. - -### Submitting a feature request - -When adding a feature request in the issue tracker, you will be presented with a basic form to fill out. - -Please include as detailed of an explanation as possible of the feature you would like, adding additional context if necessary. - -If you have examples of other tools that have the feature you are requesting, please include them as well. - -### Resolving an issue - -Pull requests are the way concrete changes are made to the code, documentation, and dependencies of Foundry. - -Even minor pull requests, such as those fixing wording, are greatly appreciated. Before making a large change, it is usually -a good idea to first open an issue describing the change to solicit feedback and guidance. This will increase -the likelihood of the PR getting merged. - -Please make sure that the following commands pass if you have changed the code: - -```sh -forge fmt --check -forge test -vvv -``` - -To make sure your changes are compatible with all compiler version targets, run the following commands: - -```sh -forge build --skip test --use solc:0.6.2 -forge build --skip test --use solc:0.6.12 -forge build --skip test --use solc:0.7.0 -forge build --skip test --use solc:0.7.6 -forge build --skip test --use solc:0.8.0 -``` - -The CI will also ensure that the code is formatted correctly and that the tests are passing across all compiler version targets. - -#### Adding cheatcodes - -Please follow the guide outlined in the [cheatcodes](https://github.com/foundry-rs/foundry/blob/master/docs/dev/cheatcodes.md#adding-a-new-cheatcode) documentation of Foundry. - -When making modifications to the native cheatcodes or adding new ones, please make sure to run [`./scripts/vm.py`](./scripts/vm.py) to update the cheatcodes in the [`src/Vm.sol`](./src/Vm.sol) file. - -By default the script will automatically generate the cheatcodes from the [`cheatcodes.json`](https://raw.githubusercontent.com/foundry-rs/foundry/master/crates/cheatcodes/assets/cheatcodes.json) file but alternatively you can provide a path to a JSON file containing the Vm interface, as generated by Foundry, with the `--from` flag. - -```sh -./scripts/vm.py --from path/to/cheatcodes.json -``` - -It is possible that the resulting [`src/Vm.sol`](./src/Vm.sol) file will have some changes that are not directly related to your changes, this is not a problem. - -#### Commits - -It is a recommended best practice to keep your changes as logically grouped as possible within individual commits. There is no limit to the number of commits any single pull request may have, and many contributors find it easier to review changes that are split across multiple commits. - -That said, if you have a number of commits that are "checkpoints" and don't represent a single logical change, please squash those together. - -#### Opening the pull request - -From within GitHub, opening a new pull request will present you with a template that should be filled out. Please try your best at filling out the details, but feel free to skip parts if you're not sure what to put. - -#### Discuss and update - -You will probably get feedback or requests for changes to your pull request. -This is a big part of the submission process, so don't be discouraged! Some contributors may sign off on the pull request right away, others may have more detailed comments or feedback. -This is a necessary part of the process in order to evaluate whether the changes are correct and necessary. - -**Any community member can review a PR, so you might get conflicting feedback**. -Keep an eye out for comments from code owners to provide guidance on conflicting feedback. - -#### Reviewing pull requests - -**Any Foundry community member is welcome to review any pull request**. - -All contributors who choose to review and provide feedback on pull requests have a responsibility to both the project and individual making the contribution. Reviews and feedback must be helpful, insightful, and geared towards improving the contribution as opposed to simply blocking it. If there are reasons why you feel the PR should not be merged, explain what those are. Do not expect to be able to block a PR from advancing simply because you say "no" without giving an explanation. Be open to having your mind changed. Be open to working _with_ the contributor to make the pull request better. - -Reviews that are dismissive or disrespectful of the contributor or any other reviewers are strictly counter to the Code of Conduct. - -When reviewing a pull request, the primary goals are for the codebase to improve and for the person submitting the request to succeed. **Even if a pull request is not merged, the submitter should come away from the experience feeling like their effort was not unappreciated**. Every PR from a new contributor is an opportunity to grow the community. - -##### Review a bit at a time - -Do not overwhelm new contributors. - -It is tempting to micro-optimize and make everything about relative performance, perfect grammar, or exact style matches. Do not succumb to that temptation.. - -Focus first on the most significant aspects of the change: - -1. Does this change make sense for Foundry? -2. Does this change make Foundry better, even if only incrementally? -3. Are there clear bugs or larger scale issues that need attending? -4. Are the commit messages readable and correct? If it contains a breaking change, is it clear enough? - -Note that only **incremental** improvement is needed to land a PR. This means that the PR does not need to be perfect, only better than the status quo. Follow-up PRs may be opened to continue iterating. - -When changes are necessary, _request_ them, do not _demand_ them, and **do not assume that the submitter already knows how to add a test or run a benchmark**. - -Specific performance optimization techniques, coding styles and conventions change over time. The first impression you give to a new contributor never does. - -Nits (requests for small changes that are not essential) are fine, but try to avoid stalling the pull request. Most nits can typically be fixed by the Foundry maintainers merging the pull request, but they can also be an opportunity for the contributor to learn a bit more about the project. - -It is always good to clearly indicate nits when you comment, e.g.: `Nit: change foo() to bar(). But this is not blocking`. - -If your comments were addressed but were not folded after new commits, or if they proved to be mistaken, please, [hide them][hiding-a-comment] with the appropriate reason to keep the conversation flow concise and relevant. - -##### Be aware of the person behind the code - -Be aware that _how_ you communicate requests and reviews in your feedback can have a significant impact on the success of the pull request. Yes, we may merge a particular change that makes Foundry better, but the individual might just not want to have anything to do with Foundry ever again. The goal is not just having good code. - -##### Abandoned or stale pull requests - -If a pull request appears to be abandoned or stalled, it is polite to first check with the contributor to see if they intend to continue the work before checking if they would mind if you took it over (especially if it just has nits left). When doing so, it is courteous to give the original contributor credit for the work they started, either by preserving their name and e-mail address in the commit log, or by using the `Author: ` or `Co-authored-by: ` metadata tag in the commits. - -_Adapted from the [ethers-rs contributing guide](https://github.com/gakonst/ethers-rs/blob/master/CONTRIBUTING.md)_. - -### Releasing - -Releases are automatically done by the release workflow when a tag is pushed, however, these steps still need to be taken: - -1. Ensure that the versions in the relevant `Cargo.toml` files are up-to-date. -2. Update documentation links -3. Perform a final audit for breaking changes. - -[rust-coc]: https://github.com/rust-lang/rust/blob/master/CODE_OF_CONDUCT.md -[dev-tg]: https://t.me/foundry_rs -[foundry-book]: https://github.com/foundry-rs/foundry-book -[support-tg]: https://t.me/foundry_support -[mcve]: https://stackoverflow.com/help/mcve -[hiding-a-comment]: https://help.github.com/articles/managing-disruptive-comments/#hiding-a-comment \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/forge-std/LICENSE-APACHE b/typescript/packages/account-modules/lib/forge-std/LICENSE-APACHE deleted file mode 100644 index cf01a49..0000000 --- a/typescript/packages/account-modules/lib/forge-std/LICENSE-APACHE +++ /dev/null @@ -1,203 +0,0 @@ -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/typescript/packages/account-modules/lib/forge-std/LICENSE-MIT b/typescript/packages/account-modules/lib/forge-std/LICENSE-MIT deleted file mode 100644 index 28f9830..0000000 --- a/typescript/packages/account-modules/lib/forge-std/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -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/typescript/packages/account-modules/lib/forge-std/README.md b/typescript/packages/account-modules/lib/forge-std/README.md deleted file mode 100644 index 51673e5..0000000 --- a/typescript/packages/account-modules/lib/forge-std/README.md +++ /dev/null @@ -1,266 +0,0 @@ -# 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://getfoundry.sh/reference/forge-std/overview/).** - -## 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 built-in 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 { - 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 addresses 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 - -Contains various assertions. - -### `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); -``` - -## Contributing - -See our [contributing guidelines](./CONTRIBUTING.md). - -## Getting Help - -First, see if the answer to your question can be found in [book](https://book.getfoundry.sh). - -If the answer is not there: - -- Join the [support Telegram](https://t.me/foundry_support) to get help, or -- Open a [discussion](https://github.com/foundry-rs/foundry/discussions/new/choose) with your question, or -- Open an issue with [the bug](https://github.com/foundry-rs/foundry/issues/new/choose) - -If you want to contribute, or follow along with contributor discussion, you can use our [main telegram](https://t.me/foundry_rs) to chat with us about the development of Foundry! - -## License - -Forge Standard Library is offered under either [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE) license. diff --git a/typescript/packages/account-modules/lib/forge-std/foundry.toml b/typescript/packages/account-modules/lib/forge-std/foundry.toml deleted file mode 100644 index 62ca21a..0000000 --- a/typescript/packages/account-modules/lib/forge-std/foundry.toml +++ /dev/null @@ -1,23 +0,0 @@ -[profile.default] -fs_permissions = [{ access = "read-write", path = "./"}] -optimizer = true -optimizer_runs = 200 - -[rpc_endpoints] -# The RPC URLs are modified versions of the default for testing initialization. -mainnet = "https://eth.merkle.io" # Different API key. -optimism_sepolia = "https://sepolia.optimism.io/" # Adds a trailing slash. -arbitrum_one_sepolia = "https://sepolia-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/typescript/packages/account-modules/lib/forge-std/package.json b/typescript/packages/account-modules/lib/forge-std/package.json deleted file mode 100644 index 74e5e66..0000000 --- a/typescript/packages/account-modules/lib/forge-std/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "forge-std", - "version": "1.10.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/typescript/packages/account-modules/lib/forge-std/scripts/vm.py b/typescript/packages/account-modules/lib/forge-std/scripts/vm.py deleted file mode 100755 index 3cd047d..0000000 --- a/typescript/packages/account-modules/lib/forge-std/scripts/vm.py +++ /dev/null @@ -1,646 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import copy -import json -import re -import subprocess -from enum import Enum as PyEnum -from pathlib import Path -from typing import Callable -from urllib import request - -VoidFn = Callable[[], None] - -CHEATCODES_JSON_URL = "https://raw.githubusercontent.com/foundry-rs/foundry/master/crates/cheatcodes/assets/cheatcodes.json" -OUT_PATH = "src/Vm.sol" - -VM_SAFE_DOC = """\ -/// 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. -""" - -VM_DOC = """\ -/// 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. -""" - - -def main(): - parser = argparse.ArgumentParser( - description="Generate Vm.sol based on the cheatcodes json created by Foundry") - parser.add_argument( - "--from", - metavar="PATH", - dest="path", - required=False, - help="path to a json file containing the Vm interface, as generated by Foundry") - args = parser.parse_args() - json_str = request.urlopen(CHEATCODES_JSON_URL).read().decode("utf-8") if args.path is None else Path(args.path).read_text() - contract = Cheatcodes.from_json(json_str) - - ccs = contract.cheatcodes - ccs = list(filter(lambda cc: cc.status not in ["experimental", "internal"], ccs)) - ccs.sort(key=lambda cc: cc.func.id) - - safe = list(filter(lambda cc: cc.safety == "safe", ccs)) - safe.sort(key=CmpCheatcode) - unsafe = list(filter(lambda cc: cc.safety == "unsafe", ccs)) - unsafe.sort(key=CmpCheatcode) - assert len(safe) + len(unsafe) == len(ccs) - - prefix_with_group_headers(safe) - prefix_with_group_headers(unsafe) - - out = "" - - out += "// Automatically @generated by scripts/vm.py. Do not modify manually.\n\n" - - pp = CheatcodesPrinter( - spdx_identifier="MIT OR Apache-2.0", - solidity_requirement=">=0.6.2 <0.9.0", - abicoder_pragma=True, - ) - pp.p_prelude() - pp.prelude = False - out += pp.finish() - - out += "\n\n" - out += VM_SAFE_DOC - vm_safe = Cheatcodes( - # TODO: Custom errors were introduced in 0.8.4 - errors=[], # contract.errors - events=contract.events, - enums=contract.enums, - structs=contract.structs, - cheatcodes=safe, - ) - pp.p_contract(vm_safe, "VmSafe") - out += pp.finish() - - out += "\n\n" - out += VM_DOC - vm_unsafe = Cheatcodes( - errors=[], - events=[], - enums=[], - structs=[], - cheatcodes=unsafe, - ) - pp.p_contract(vm_unsafe, "Vm", "VmSafe") - out += pp.finish() - - # Compatibility with <0.8.0 - def memory_to_calldata(m: re.Match) -> str: - return " calldata " + m.group(1) - - out = re.sub(r" memory (.*returns)", memory_to_calldata, out) - - with open(OUT_PATH, "w") as f: - f.write(out) - - forge_fmt = ["forge", "fmt", OUT_PATH] - res = subprocess.run(forge_fmt) - assert res.returncode == 0, f"command failed: {forge_fmt}" - - print(f"Wrote to {OUT_PATH}") - - -class CmpCheatcode: - cheatcode: "Cheatcode" - - def __init__(self, cheatcode: "Cheatcode"): - self.cheatcode = cheatcode - - def __lt__(self, other: "CmpCheatcode") -> bool: - return cmp_cheatcode(self.cheatcode, other.cheatcode) < 0 - - def __eq__(self, other: "CmpCheatcode") -> bool: - return cmp_cheatcode(self.cheatcode, other.cheatcode) == 0 - - def __gt__(self, other: "CmpCheatcode") -> bool: - return cmp_cheatcode(self.cheatcode, other.cheatcode) > 0 - - -def cmp_cheatcode(a: "Cheatcode", b: "Cheatcode") -> int: - if a.group != b.group: - return -1 if a.group < b.group else 1 - if a.status != b.status: - return -1 if a.status < b.status else 1 - if a.safety != b.safety: - return -1 if a.safety < b.safety else 1 - if a.func.id != b.func.id: - return -1 if a.func.id < b.func.id else 1 - return 0 - - -# HACK: A way to add group header comments without having to modify printer code -def prefix_with_group_headers(cheats: list["Cheatcode"]): - s = set() - for i, cheat in enumerate(cheats): - if cheat.group in s: - continue - - s.add(cheat.group) - - c = copy.deepcopy(cheat) - c.func.description = "" - c.func.declaration = f"// ======== {group(c.group)} ========" - cheats.insert(i, c) - return cheats - - -def group(s: str) -> str: - if s == "evm": - return "EVM" - if s == "json": - return "JSON" - return s[0].upper() + s[1:] - - -class Visibility(PyEnum): - EXTERNAL: str = "external" - PUBLIC: str = "public" - INTERNAL: str = "internal" - PRIVATE: str = "private" - - def __str__(self): - return self.value - - -class Mutability(PyEnum): - PURE: str = "pure" - VIEW: str = "view" - NONE: str = "" - - def __str__(self): - return self.value - - -class Function: - id: str - description: str - declaration: str - visibility: Visibility - mutability: Mutability - signature: str - selector: str - selector_bytes: bytes - - def __init__( - self, - id: str, - description: str, - declaration: str, - visibility: Visibility, - mutability: Mutability, - signature: str, - selector: str, - selector_bytes: bytes, - ): - self.id = id - self.description = description - self.declaration = declaration - self.visibility = visibility - self.mutability = mutability - self.signature = signature - self.selector = selector - self.selector_bytes = selector_bytes - - @staticmethod - def from_dict(d: dict) -> "Function": - return Function( - d["id"], - d["description"], - d["declaration"], - Visibility(d["visibility"]), - Mutability(d["mutability"]), - d["signature"], - d["selector"], - bytes(d["selectorBytes"]), - ) - - -class Cheatcode: - func: Function - group: str - status: str - safety: str - - def __init__(self, func: Function, group: str, status: str, safety: str): - self.func = func - self.group = group - self.status = status - self.safety = safety - - @staticmethod - def from_dict(d: dict) -> "Cheatcode": - return Cheatcode( - Function.from_dict(d["func"]), - str(d["group"]), - str(d["status"]), - str(d["safety"]), - ) - - -class Error: - name: str - description: str - declaration: str - - def __init__(self, name: str, description: str, declaration: str): - self.name = name - self.description = description - self.declaration = declaration - - @staticmethod - def from_dict(d: dict) -> "Error": - return Error(**d) - - -class Event: - name: str - description: str - declaration: str - - def __init__(self, name: str, description: str, declaration: str): - self.name = name - self.description = description - self.declaration = declaration - - @staticmethod - def from_dict(d: dict) -> "Event": - return Event(**d) - - -class EnumVariant: - name: str - description: str - - def __init__(self, name: str, description: str): - self.name = name - self.description = description - - -class Enum: - name: str - description: str - variants: list[EnumVariant] - - def __init__(self, name: str, description: str, variants: list[EnumVariant]): - self.name = name - self.description = description - self.variants = variants - - @staticmethod - def from_dict(d: dict) -> "Enum": - return Enum( - d["name"], - d["description"], - list(map(lambda v: EnumVariant(**v), d["variants"])), - ) - - -class StructField: - name: str - ty: str - description: str - - def __init__(self, name: str, ty: str, description: str): - self.name = name - self.ty = ty - self.description = description - - -class Struct: - name: str - description: str - fields: list[StructField] - - def __init__(self, name: str, description: str, fields: list[StructField]): - self.name = name - self.description = description - self.fields = fields - - @staticmethod - def from_dict(d: dict) -> "Struct": - return Struct( - d["name"], - d["description"], - list(map(lambda f: StructField(**f), d["fields"])), - ) - - -class Cheatcodes: - errors: list[Error] - events: list[Event] - enums: list[Enum] - structs: list[Struct] - cheatcodes: list[Cheatcode] - - def __init__( - self, - errors: list[Error], - events: list[Event], - enums: list[Enum], - structs: list[Struct], - cheatcodes: list[Cheatcode], - ): - self.errors = errors - self.events = events - self.enums = enums - self.structs = structs - self.cheatcodes = cheatcodes - - @staticmethod - def from_dict(d: dict) -> "Cheatcodes": - return Cheatcodes( - errors=[Error.from_dict(e) for e in d["errors"]], - events=[Event.from_dict(e) for e in d["events"]], - enums=[Enum.from_dict(e) for e in d["enums"]], - structs=[Struct.from_dict(e) for e in d["structs"]], - cheatcodes=[Cheatcode.from_dict(e) for e in d["cheatcodes"]], - ) - - @staticmethod - def from_json(s) -> "Cheatcodes": - return Cheatcodes.from_dict(json.loads(s)) - - @staticmethod - def from_json_file(file_path: str) -> "Cheatcodes": - with open(file_path, "r") as f: - return Cheatcodes.from_dict(json.load(f)) - - -class Item(PyEnum): - ERROR: str = "error" - EVENT: str = "event" - ENUM: str = "enum" - STRUCT: str = "struct" - FUNCTION: str = "function" - - -class ItemOrder: - _list: list[Item] - - def __init__(self, list: list[Item]) -> None: - assert len(list) <= len(Item), "list must not contain more items than Item" - assert len(list) == len(set(list)), "list must not contain duplicates" - self._list = list - pass - - def get_list(self) -> list[Item]: - return self._list - - @staticmethod - def default() -> "ItemOrder": - return ItemOrder( - [ - Item.ERROR, - Item.EVENT, - Item.ENUM, - Item.STRUCT, - Item.FUNCTION, - ] - ) - - -class CheatcodesPrinter: - buffer: str - - prelude: bool - spdx_identifier: str - solidity_requirement: str - abicoder_v2: bool - - block_doc_style: bool - - indent_level: int - _indent_str: str - - nl_str: str - - items_order: ItemOrder - - def __init__( - self, - buffer: str = "", - prelude: bool = True, - spdx_identifier: str = "UNLICENSED", - solidity_requirement: str = "", - abicoder_pragma: bool = False, - block_doc_style: bool = False, - indent_level: int = 0, - indent_with: int | str = 4, - nl_str: str = "\n", - items_order: ItemOrder = ItemOrder.default(), - ): - self.prelude = prelude - self.spdx_identifier = spdx_identifier - self.solidity_requirement = solidity_requirement - self.abicoder_v2 = abicoder_pragma - self.block_doc_style = block_doc_style - self.buffer = buffer - self.indent_level = indent_level - self.nl_str = nl_str - - if isinstance(indent_with, int): - assert indent_with >= 0 - self._indent_str = " " * indent_with - elif isinstance(indent_with, str): - self._indent_str = indent_with - else: - assert False, "indent_with must be int or str" - - self.items_order = items_order - - def finish(self) -> str: - ret = self.buffer.rstrip() - self.buffer = "" - return ret - - def p_contract(self, contract: Cheatcodes, name: str, inherits: str = ""): - if self.prelude: - self.p_prelude(contract) - - self._p_str("interface ") - name = name.strip() - if name != "": - self._p_str(name) - self._p_str(" ") - if inherits != "": - self._p_str("is ") - self._p_str(inherits) - self._p_str(" ") - self._p_str("{") - self._p_nl() - self._with_indent(lambda: self._p_items(contract)) - self._p_str("}") - self._p_nl() - - def _p_items(self, contract: Cheatcodes): - for item in self.items_order.get_list(): - if item == Item.ERROR: - self.p_errors(contract.errors) - elif item == Item.EVENT: - self.p_events(contract.events) - elif item == Item.ENUM: - self.p_enums(contract.enums) - elif item == Item.STRUCT: - self.p_structs(contract.structs) - elif item == Item.FUNCTION: - self.p_functions(contract.cheatcodes) - else: - assert False, f"unknown item {item}" - - def p_prelude(self, contract: Cheatcodes | None = None): - self._p_str(f"// SPDX-License-Identifier: {self.spdx_identifier}") - self._p_nl() - - if self.solidity_requirement != "": - req = self.solidity_requirement - elif contract and len(contract.errors) > 0: - req = ">=0.8.4 <0.9.0" - else: - req = ">=0.6.0 <0.9.0" - self._p_str(f"pragma solidity {req};") - self._p_nl() - - if self.abicoder_v2: - self._p_str("pragma experimental ABIEncoderV2;") - self._p_nl() - - self._p_nl() - - def p_errors(self, errors: list[Error]): - for error in errors: - self._p_line(lambda: self.p_error(error)) - - def p_error(self, error: Error): - self._p_comment(error.description, doc=True) - self._p_line(lambda: self._p_str(error.declaration)) - - def p_events(self, events: list[Event]): - for event in events: - self._p_line(lambda: self.p_event(event)) - - def p_event(self, event: Event): - self._p_comment(event.description, doc=True) - self._p_line(lambda: self._p_str(event.declaration)) - - def p_enums(self, enums: list[Enum]): - for enum in enums: - self._p_line(lambda: self.p_enum(enum)) - - def p_enum(self, enum: Enum): - self._p_comment(enum.description, doc=True) - self._p_line(lambda: self._p_str(f"enum {enum.name} {{")) - self._with_indent(lambda: self.p_enum_variants(enum.variants)) - self._p_line(lambda: self._p_str("}")) - - def p_enum_variants(self, variants: list[EnumVariant]): - for i, variant in enumerate(variants): - self._p_indent() - self._p_comment(variant.description) - - self._p_indent() - self._p_str(variant.name) - if i < len(variants) - 1: - self._p_str(",") - self._p_nl() - - def p_structs(self, structs: list[Struct]): - for struct in structs: - self._p_line(lambda: self.p_struct(struct)) - - def p_struct(self, struct: Struct): - self._p_comment(struct.description, doc=True) - self._p_line(lambda: self._p_str(f"struct {struct.name} {{")) - self._with_indent(lambda: self.p_struct_fields(struct.fields)) - self._p_line(lambda: self._p_str("}")) - - def p_struct_fields(self, fields: list[StructField]): - for field in fields: - self._p_line(lambda: self.p_struct_field(field)) - - def p_struct_field(self, field: StructField): - self._p_comment(field.description) - self._p_indented(lambda: self._p_str(f"{field.ty} {field.name};")) - - def p_functions(self, cheatcodes: list[Cheatcode]): - for cheatcode in cheatcodes: - self._p_line(lambda: self.p_function(cheatcode.func)) - - def p_function(self, func: Function): - self._p_comment(func.description, doc=True) - self._p_line(lambda: self._p_str(func.declaration)) - - def _p_comment(self, s: str, doc: bool = False): - s = s.strip() - if s == "": - return - - s = map(lambda line: line.lstrip(), s.split("\n")) - if self.block_doc_style: - self._p_str("/*") - if doc: - self._p_str("*") - self._p_nl() - for line in s: - self._p_indent() - self._p_str(" ") - if doc: - self._p_str("* ") - self._p_str(line) - self._p_nl() - self._p_indent() - self._p_str(" */") - self._p_nl() - else: - first_line = True - for line in s: - if not first_line: - self._p_indent() - first_line = False - - if doc: - self._p_str("/// ") - else: - self._p_str("// ") - self._p_str(line) - self._p_nl() - - def _with_indent(self, f: VoidFn): - self._inc_indent() - f() - self._dec_indent() - - def _p_line(self, f: VoidFn): - self._p_indent() - f() - self._p_nl() - - def _p_indented(self, f: VoidFn): - self._p_indent() - f() - - def _p_indent(self): - for _ in range(self.indent_level): - self._p_str(self._indent_str) - - def _p_nl(self): - self._p_str(self.nl_str) - - def _p_str(self, txt: str): - self.buffer += txt - - def _inc_indent(self): - self.indent_level += 1 - - def _dec_indent(self): - self.indent_level -= 1 - - -if __name__ == "__main__": - main() diff --git a/typescript/packages/account-modules/lib/forge-std/src/Base.sol b/typescript/packages/account-modules/lib/forge-std/src/Base.sol deleted file mode 100644 index 5b618c6..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/Base.sol +++ /dev/null @@ -1,42 +0,0 @@ -// 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 { - /// @dev Cheat code address. - /// Calculated as `address(uint160(uint256(keccak256("hevm cheat code"))))`. - address internal constant VM_ADDRESS = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D; - /// @dev console.sol and console2.sol work by executing a staticcall to this address. - /// Calculated as `address(uint160(uint88(bytes11("console.log"))))`. - address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67; - /// @dev Used when deploying with create2. - /// Taken from https://github.com/Arachnid/deterministic-deployment-proxy. - address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; - /// @dev The default address for tx.origin and msg.sender. - /// Calculated as `address(uint160(uint256(keccak256("foundry default caller"))))`. - address internal constant DEFAULT_SENDER = 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38; - /// @dev The address of the first contract `CREATE`d by a running test contract. - /// When running tests, each test contract is `CREATE`d by `DEFAULT_SENDER` with nonce 1. - /// Calculated as `VM.computeCreateAddress(VM.computeCreateAddress(DEFAULT_SENDER, 1), 1)`. - address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; - /// @dev Deterministic deployment address of the Multicall3 contract. - /// Taken from https://www.multicall3.com. - address internal constant MULTICALL3_ADDRESS = 0xcA11bde05977b3631167028862bE2a173976CA11; - /// @dev 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/typescript/packages/account-modules/lib/forge-std/src/Script.sol b/typescript/packages/account-modules/lib/forge-std/src/Script.sol deleted file mode 100644 index a2e2aa1..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/Script.sol +++ /dev/null @@ -1,28 +0,0 @@ -// 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 {StdConstants} from "./StdConstants.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/typescript/packages/account-modules/lib/forge-std/src/StdAssertions.sol b/typescript/packages/account-modules/lib/forge-std/src/StdAssertions.sol deleted file mode 100644 index 4248170..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/StdAssertions.sol +++ /dev/null @@ -1,764 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2 <0.9.0; -pragma experimental ABIEncoderV2; - -import {Vm} from "./Vm.sol"; - -abstract contract StdAssertions { - Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); - - event log(string); - event logs(bytes); - - event log_address(address); - event log_bytes32(bytes32); - event log_int(int256); - event log_uint(uint256); - 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, int256 val, uint256 decimals); - event log_named_decimal_uint(string key, uint256 val, uint256 decimals); - event log_named_int(string key, int256 val); - event log_named_uint(string key, uint256 val); - event log_named_bytes(string key, bytes val); - event log_named_string(string key, string val); - - 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); - - bytes32 private constant FAILED_SLOT = bytes32("failed"); - - bool private _failed; - - function failed() public view returns (bool) { - if (_failed) { - return true; - } else { - return vm.load(address(vm), FAILED_SLOT) != bytes32(0); - } - } - - function fail() internal virtual { - vm.store(address(vm), FAILED_SLOT, bytes32(uint256(1))); - _failed = true; - } - - function fail(string memory message) internal virtual { - fail(); - vm.assertTrue(false, message); - } - - function assertTrue(bool data) internal pure virtual { - if (!data) { - vm.assertTrue(data); - } - } - - function assertTrue(bool data, string memory err) internal pure virtual { - if (!data) { - vm.assertTrue(data, err); - } - } - - function assertFalse(bool data) internal pure virtual { - if (data) { - vm.assertFalse(data); - } - } - - function assertFalse(bool data, string memory err) internal pure virtual { - if (data) { - vm.assertFalse(data, err); - } - } - - function assertEq(bool left, bool right) internal pure virtual { - if (left != right) { - vm.assertEq(left, right); - } - } - - function assertEq(bool left, bool right, string memory err) internal pure virtual { - if (left != right) { - vm.assertEq(left, right, err); - } - } - - function assertEq(uint256 left, uint256 right) internal pure virtual { - if (left != right) { - vm.assertEq(left, right); - } - } - - function assertEq(uint256 left, uint256 right, string memory err) internal pure virtual { - if (left != right) { - vm.assertEq(left, right, err); - } - } - - function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertEqDecimal(left, right, decimals); - } - - function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertEqDecimal(left, right, decimals, err); - } - - function assertEq(int256 left, int256 right) internal pure virtual { - if (left != right) { - vm.assertEq(left, right); - } - } - - function assertEq(int256 left, int256 right, string memory err) internal pure virtual { - if (left != right) { - vm.assertEq(left, right, err); - } - } - - function assertEqDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertEqDecimal(left, right, decimals); - } - - function assertEqDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertEqDecimal(left, right, decimals, err); - } - - function assertEq(address left, address right) internal pure virtual { - if (left != right) { - vm.assertEq(left, right); - } - } - - function assertEq(address left, address right, string memory err) internal pure virtual { - if (left != right) { - vm.assertEq(left, right, err); - } - } - - function assertEq(bytes32 left, bytes32 right) internal pure virtual { - if (left != right) { - vm.assertEq(left, right); - } - } - - function assertEq(bytes32 left, bytes32 right, string memory err) internal pure virtual { - if (left != right) { - vm.assertEq(left, right, err); - } - } - - function assertEq32(bytes32 left, bytes32 right) internal pure virtual { - if (left != right) { - vm.assertEq(left, right); - } - } - - function assertEq32(bytes32 left, bytes32 right, string memory err) internal pure virtual { - if (left != right) { - vm.assertEq(left, right, err); - } - } - - function assertEq(string memory left, string memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(string memory left, string memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(bytes memory left, bytes memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bytes memory left, bytes memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(bool[] memory left, bool[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bool[] memory left, bool[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(uint256[] memory left, uint256[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(uint256[] memory left, uint256[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(int256[] memory left, int256[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(int256[] memory left, int256[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(address[] memory left, address[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(address[] memory left, address[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(bytes32[] memory left, bytes32[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bytes32[] memory left, bytes32[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(string[] memory left, string[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(string[] memory left, string[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(bytes[] memory left, bytes[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bytes[] memory left, bytes[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - // Legacy helper - function assertEqUint(uint256 left, uint256 right) internal pure virtual { - assertEq(left, right); - } - - function assertNotEq(bool left, bool right) internal pure virtual { - if (left == right) { - vm.assertNotEq(left, right); - } - } - - function assertNotEq(bool left, bool right, string memory err) internal pure virtual { - if (left == right) { - vm.assertNotEq(left, right, err); - } - } - - function assertNotEq(uint256 left, uint256 right) internal pure virtual { - if (left == right) { - vm.assertNotEq(left, right); - } - } - - function assertNotEq(uint256 left, uint256 right, string memory err) internal pure virtual { - if (left == right) { - vm.assertNotEq(left, right, err); - } - } - - function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertNotEqDecimal(left, right, decimals); - } - - function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) - internal - pure - virtual - { - vm.assertNotEqDecimal(left, right, decimals, err); - } - - function assertNotEq(int256 left, int256 right) internal pure virtual { - if (left == right) { - vm.assertNotEq(left, right); - } - } - - function assertNotEq(int256 left, int256 right, string memory err) internal pure virtual { - if (left == right) { - vm.assertNotEq(left, right, err); - } - } - - function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertNotEqDecimal(left, right, decimals); - } - - function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertNotEqDecimal(left, right, decimals, err); - } - - function assertNotEq(address left, address right) internal pure virtual { - if (left == right) { - vm.assertNotEq(left, right); - } - } - - function assertNotEq(address left, address right, string memory err) internal pure virtual { - if (left == right) { - vm.assertNotEq(left, right, err); - } - } - - function assertNotEq(bytes32 left, bytes32 right) internal pure virtual { - if (left == right) { - vm.assertNotEq(left, right); - } - } - - function assertNotEq(bytes32 left, bytes32 right, string memory err) internal pure virtual { - if (left == right) { - vm.assertNotEq(left, right, err); - } - } - - function assertNotEq32(bytes32 left, bytes32 right) internal pure virtual { - if (left == right) { - vm.assertNotEq(left, right); - } - } - - function assertNotEq32(bytes32 left, bytes32 right, string memory err) internal pure virtual { - if (left == right) { - vm.assertNotEq(left, right, err); - } - } - - function assertNotEq(string memory left, string memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(string memory left, string memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(bytes memory left, bytes memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bytes memory left, bytes memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(bool[] memory left, bool[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bool[] memory left, bool[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(uint256[] memory left, uint256[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(uint256[] memory left, uint256[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(int256[] memory left, int256[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(int256[] memory left, int256[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(address[] memory left, address[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(address[] memory left, address[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(bytes32[] memory left, bytes32[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bytes32[] memory left, bytes32[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(string[] memory left, string[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(string[] memory left, string[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(bytes[] memory left, bytes[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bytes[] memory left, bytes[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertLt(uint256 left, uint256 right) internal pure virtual { - if (left >= right) { - vm.assertLt(left, right); - } - } - - function assertLt(uint256 left, uint256 right, string memory err) internal pure virtual { - if (left >= right) { - vm.assertLt(left, right, err); - } - } - - function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertLtDecimal(left, right, decimals); - } - - function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertLtDecimal(left, right, decimals, err); - } - - function assertLt(int256 left, int256 right) internal pure virtual { - if (left >= right) { - vm.assertLt(left, right); - } - } - - function assertLt(int256 left, int256 right, string memory err) internal pure virtual { - if (left >= right) { - vm.assertLt(left, right, err); - } - } - - function assertLtDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertLtDecimal(left, right, decimals); - } - - function assertLtDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertLtDecimal(left, right, decimals, err); - } - - function assertGt(uint256 left, uint256 right) internal pure virtual { - if (left <= right) { - vm.assertGt(left, right); - } - } - - function assertGt(uint256 left, uint256 right, string memory err) internal pure virtual { - if (left <= right) { - vm.assertGt(left, right, err); - } - } - - function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertGtDecimal(left, right, decimals); - } - - function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertGtDecimal(left, right, decimals, err); - } - - function assertGt(int256 left, int256 right) internal pure virtual { - if (left <= right) { - vm.assertGt(left, right); - } - } - - function assertGt(int256 left, int256 right, string memory err) internal pure virtual { - if (left <= right) { - vm.assertGt(left, right, err); - } - } - - function assertGtDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertGtDecimal(left, right, decimals); - } - - function assertGtDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertGtDecimal(left, right, decimals, err); - } - - function assertLe(uint256 left, uint256 right) internal pure virtual { - if (left > right) { - vm.assertLe(left, right); - } - } - - function assertLe(uint256 left, uint256 right, string memory err) internal pure virtual { - if (left > right) { - vm.assertLe(left, right, err); - } - } - - function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertLeDecimal(left, right, decimals); - } - - function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertLeDecimal(left, right, decimals, err); - } - - function assertLe(int256 left, int256 right) internal pure virtual { - if (left > right) { - vm.assertLe(left, right); - } - } - - function assertLe(int256 left, int256 right, string memory err) internal pure virtual { - if (left > right) { - vm.assertLe(left, right, err); - } - } - - function assertLeDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertLeDecimal(left, right, decimals); - } - - function assertLeDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertLeDecimal(left, right, decimals, err); - } - - function assertGe(uint256 left, uint256 right) internal pure virtual { - if (left < right) { - vm.assertGe(left, right); - } - } - - function assertGe(uint256 left, uint256 right, string memory err) internal pure virtual { - if (left < right) { - vm.assertGe(left, right, err); - } - } - - function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertGeDecimal(left, right, decimals); - } - - function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertGeDecimal(left, right, decimals, err); - } - - function assertGe(int256 left, int256 right) internal pure virtual { - if (left < right) { - vm.assertGe(left, right); - } - } - - function assertGe(int256 left, int256 right, string memory err) internal pure virtual { - if (left < right) { - vm.assertGe(left, right, err); - } - } - - function assertGeDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertGeDecimal(left, right, decimals); - } - - function assertGeDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertGeDecimal(left, right, decimals, err); - } - - function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) internal pure virtual { - vm.assertApproxEqAbs(left, right, maxDelta); - } - - function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string memory err) - internal - pure - virtual - { - vm.assertApproxEqAbs(left, right, maxDelta, err); - } - - function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) - internal - pure - virtual - { - vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals); - } - - function assertApproxEqAbsDecimal( - uint256 left, - uint256 right, - uint256 maxDelta, - uint256 decimals, - string memory err - ) internal pure virtual { - vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals, err); - } - - function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) internal pure virtual { - vm.assertApproxEqAbs(left, right, maxDelta); - } - - function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string memory err) internal pure virtual { - vm.assertApproxEqAbs(left, right, maxDelta, err); - } - - function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) - internal - pure - virtual - { - vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals); - } - - function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals, string memory err) - internal - pure - virtual - { - vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals, err); - } - - function assertApproxEqRel( - uint256 left, - uint256 right, - uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% - ) internal pure virtual { - vm.assertApproxEqRel(left, right, maxPercentDelta); - } - - function assertApproxEqRel( - uint256 left, - uint256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - string memory err - ) internal pure virtual { - vm.assertApproxEqRel(left, right, maxPercentDelta, err); - } - - function assertApproxEqRelDecimal( - uint256 left, - uint256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - uint256 decimals - ) internal pure virtual { - vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals); - } - - function assertApproxEqRelDecimal( - uint256 left, - uint256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - uint256 decimals, - string memory err - ) internal pure virtual { - vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals, err); - } - - function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) internal pure virtual { - vm.assertApproxEqRel(left, right, maxPercentDelta); - } - - function assertApproxEqRel( - int256 left, - int256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - string memory err - ) internal pure virtual { - vm.assertApproxEqRel(left, right, maxPercentDelta, err); - } - - function assertApproxEqRelDecimal( - int256 left, - int256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - uint256 decimals - ) internal pure virtual { - vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals); - } - - function assertApproxEqRelDecimal( - int256 left, - int256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - uint256 decimals, - string memory err - ) internal pure virtual { - vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals, err); - } - - // Inherited from DSTest, not used but kept for backwards-compatibility - function checkEq0(bytes memory left, bytes memory right) internal pure returns (bool) { - return keccak256(left) == keccak256(right); - } - - function assertEq0(bytes memory left, bytes memory right) internal pure virtual { - assertEq(left, right); - } - - function assertEq0(bytes memory left, bytes memory right, string memory err) internal pure virtual { - assertEq(left, right, err); - } - - function assertNotEq0(bytes memory left, bytes memory right) internal pure virtual { - assertNotEq(left, right); - } - - function assertNotEq0(bytes memory left, bytes memory right, string memory err) internal pure virtual { - assertNotEq(left, right, err); - } - - 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); - revert("assertion failed"); - } - - 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); - revert("assertion failed"); - } - } -} diff --git a/typescript/packages/account-modules/lib/forge-std/src/StdChains.sol b/typescript/packages/account-modules/lib/forge-std/src/StdChains.sol deleted file mode 100644 index 0a872e7..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/StdChains.sol +++ /dev/null @@ -1,286 +0,0 @@ -// 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 - 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) { - 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' - // The upstream error thrown by forge for failing cheats changed so we check both the old and new versions - bytes memory oldNotFoundError = - abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias))); - bytes memory newNotFoundError = abi.encodeWithSignature( - "CheatcodeError(string)", string(abi.encodePacked("invalid rpc url: ", chainAlias)) - ); - bytes32 errHash = keccak256(err); - if ( - (errHash != keccak256(oldNotFoundError) && errHash != keccak256(newNotFoundError)) - || 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 `test_Rpcs` in `StdChains.t.sol` - setChainWithDefaultRpcUrl("anvil", ChainData("Anvil", 31337, "http://127.0.0.1:8545")); - setChainWithDefaultRpcUrl("mainnet", ChainData("Mainnet", 1, "https://eth.llamarpc.com")); - setChainWithDefaultRpcUrl( - "sepolia", ChainData("Sepolia", 11155111, "https://sepolia.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001") - ); - setChainWithDefaultRpcUrl("holesky", ChainData("Holesky", 17000, "https://rpc.holesky.ethpandaops.io")); - setChainWithDefaultRpcUrl("hoodi", ChainData("Hoodi", 560048, "https://rpc.hoodi.ethpandaops.io")); - setChainWithDefaultRpcUrl("optimism", ChainData("Optimism", 10, "https://mainnet.optimism.io")); - setChainWithDefaultRpcUrl( - "optimism_sepolia", ChainData("Optimism Sepolia", 11155420, "https://sepolia.optimism.io") - ); - setChainWithDefaultRpcUrl("arbitrum_one", ChainData("Arbitrum One", 42161, "https://arb1.arbitrum.io/rpc")); - setChainWithDefaultRpcUrl( - "arbitrum_one_sepolia", ChainData("Arbitrum One Sepolia", 421614, "https://sepolia-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_amoy", ChainData("Polygon Amoy", 80002, "https://rpc-amoy.polygon.technology") - ); - 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_sepolia", ChainData("Base Sepolia", 84532, "https://sepolia.base.org")); - setChainWithDefaultRpcUrl("base", ChainData("Base", 8453, "https://mainnet.base.org")); - setChainWithDefaultRpcUrl("blast_sepolia", ChainData("Blast Sepolia", 168587773, "https://sepolia.blast.io")); - setChainWithDefaultRpcUrl("blast", ChainData("Blast", 81457, "https://rpc.blast.io")); - setChainWithDefaultRpcUrl("fantom_opera", ChainData("Fantom Opera", 250, "https://rpc.ankr.com/fantom/")); - setChainWithDefaultRpcUrl( - "fantom_opera_testnet", ChainData("Fantom Opera Testnet", 4002, "https://rpc.ankr.com/fantom_testnet/") - ); - setChainWithDefaultRpcUrl("fraxtal", ChainData("Fraxtal", 252, "https://rpc.frax.com")); - setChainWithDefaultRpcUrl("fraxtal_testnet", ChainData("Fraxtal Testnet", 2522, "https://rpc.testnet.frax.com")); - setChainWithDefaultRpcUrl( - "berachain_bartio_testnet", ChainData("Berachain bArtio Testnet", 80084, "https://bartio.rpc.berachain.com") - ); - setChainWithDefaultRpcUrl("flare", ChainData("Flare", 14, "https://flare-api.flare.network/ext/C/rpc")); - setChainWithDefaultRpcUrl( - "flare_coston2", ChainData("Flare Coston2", 114, "https://coston2-api.flare.network/ext/C/rpc") - ); - - setChainWithDefaultRpcUrl("mode", ChainData("Mode", 34443, "https://mode.drpc.org")); - setChainWithDefaultRpcUrl("mode_sepolia", ChainData("Mode Sepolia", 919, "https://sepolia.mode.network")); - - setChainWithDefaultRpcUrl("zora", ChainData("Zora", 7777777, "https://zora.drpc.org")); - setChainWithDefaultRpcUrl( - "zora_sepolia", ChainData("Zora Sepolia", 999999999, "https://sepolia.rpc.zora.energy") - ); - - setChainWithDefaultRpcUrl("race", ChainData("Race", 6805, "https://racemainnet.io")); - setChainWithDefaultRpcUrl("race_sepolia", ChainData("Race Sepolia", 6806, "https://racemainnet.io")); - - setChainWithDefaultRpcUrl("metal", ChainData("Metal", 1750, "https://metall2.drpc.org")); - setChainWithDefaultRpcUrl("metal_sepolia", ChainData("Metal Sepolia", 1740, "https://testnet.rpc.metall2.com")); - - setChainWithDefaultRpcUrl("binary", ChainData("Binary", 624, "https://rpc.zero.thebinaryholdings.com")); - setChainWithDefaultRpcUrl( - "binary_sepolia", ChainData("Binary Sepolia", 625, "https://rpc.zero.thebinaryholdings.com") - ); - - setChainWithDefaultRpcUrl("orderly", ChainData("Orderly", 291, "https://rpc.orderly.network")); - setChainWithDefaultRpcUrl( - "orderly_sepolia", ChainData("Orderly Sepolia", 4460, "https://testnet-rpc.orderly.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/typescript/packages/account-modules/lib/forge-std/src/StdCheats.sol b/typescript/packages/account-modules/lib/forge-std/src/StdCheats.sol deleted file mode 100644 index 9f360de..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/StdCheats.sol +++ /dev/null @@ -1,829 +0,0 @@ -// 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 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 are reserved by Ethereum and may be on all EVM-compatible chains. - vm.assume(addr < address(0x1) || addr > address(0xff)); - - // 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 assumeUnusedAddress(address addr) internal view virtual { - uint256 size; - assembly { - size := extcodesize(addr) - } - vm.assume(size == 0); - - assumeNotPrecompile(addr); - assumeNotZeroAddress(addr); - assumeNotForgeAddress(addr); - } - - 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(vm.getBlockTimestamp() + time); - } - - function rewind(uint256 time) internal virtual { - vm.warp(vm.getBlockTimestamp() - 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_StdCheats("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_StdCheats(string memory p0) private view { - (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string)", p0)); - status; - } -} diff --git a/typescript/packages/account-modules/lib/forge-std/src/StdConstants.sol b/typescript/packages/account-modules/lib/forge-std/src/StdConstants.sol deleted file mode 100644 index 2047d2b..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/StdConstants.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2 <0.9.0; - -import {IMulticall3} from "./interfaces/IMulticall3.sol"; -import {Vm} from "./Vm.sol"; - -library StdConstants { - /// @dev Cheat code address. - /// Calculated as `address(uint160(uint256(keccak256("hevm cheat code"))))`. - Vm internal constant VM = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); - /// @dev console.sol and console2.sol work by executing a staticcall to this address. - /// Calculated as `address(uint160(uint88(bytes11("console.log"))))`. - address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67; - /// @dev Used when deploying with create2. - /// Taken from https://github.com/Arachnid/deterministic-deployment-proxy. - address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; - /// @dev The default address for tx.origin and msg.sender. - /// Calculated as `address(uint160(uint256(keccak256("foundry default caller"))))`. - address internal constant DEFAULT_SENDER = 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38; - /// @dev The address of the first contract `CREATE`d by a running test contract. - /// When running tests, each test contract is `CREATE`d by `DEFAULT_SENDER` with nonce 1. - /// Calculated as `VM.computeCreateAddress(VM.computeCreateAddress(DEFAULT_SENDER, 1), 1)`. - address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; - /// @dev Deterministic deployment address of the Multicall3 contract. - /// Taken from https://www.multicall3.com. - IMulticall3 internal constant MULTICALL3_ADDRESS = IMulticall3(0xcA11bde05977b3631167028862bE2a173976CA11); - /// @dev The order of the secp256k1 curve. - uint256 internal constant SECP256K1_ORDER = - 115792089237316195423570985008687907852837564279074904382605163141518161494337; -} diff --git a/typescript/packages/account-modules/lib/forge-std/src/StdError.sol b/typescript/packages/account-modules/lib/forge-std/src/StdError.sol deleted file mode 100644 index a302191..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/StdError.sol +++ /dev/null @@ -1,15 +0,0 @@ -// 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/typescript/packages/account-modules/lib/forge-std/src/StdInvariant.sol b/typescript/packages/account-modules/lib/forge-std/src/StdInvariant.sol deleted file mode 100644 index 056db98..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/StdInvariant.sol +++ /dev/null @@ -1,122 +0,0 @@ -// 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 FuzzArtifactSelector { - string artifact; - 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; - - FuzzArtifactSelector[] private _targetedArtifactSelectors; - - FuzzSelector[] private _excludedSelectors; - 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 excludeSelector(FuzzSelector memory newExcludedSelector_) internal { - _excludedSelectors.push(newExcludedSelector_); - } - - 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(FuzzArtifactSelector 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 excludeSelectors() public view returns (FuzzSelector[] memory excludedSelectors_) { - excludedSelectors_ = _excludedSelectors; - } - - 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 (FuzzArtifactSelector[] 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/typescript/packages/account-modules/lib/forge-std/src/StdJson.sol b/typescript/packages/account-modules/lib/forge-std/src/StdJson.sol deleted file mode 100644 index 2a033c0..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/StdJson.sol +++ /dev/null @@ -1,283 +0,0 @@ -// 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(""); -// json.readUint(""); -// ``` -// To write: -// ``` -// using stdJson for string; -// string memory json = "json"; -// json.serialize("a", uint256(123)); -// string memory semiFinal = json.serialize("b", string("test")); -// string memory finalJson = json.serialize("c", semiFinal); -// finalJson.write(""); -// ``` - -library stdJson { - VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); - - function keyExists(string memory json, string memory key) internal view returns (bool) { - return vm.keyExistsJson(json, key); - } - - 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 readUintOr(string memory json, string memory key, uint256 defaultValue) internal view returns (uint256) { - return keyExists(json, key) ? readUint(json, key) : defaultValue; - } - - function readUintArrayOr(string memory json, string memory key, uint256[] memory defaultValue) - internal - view - returns (uint256[] memory) - { - return keyExists(json, key) ? readUintArray(json, key) : defaultValue; - } - - function readIntOr(string memory json, string memory key, int256 defaultValue) internal view returns (int256) { - return keyExists(json, key) ? readInt(json, key) : defaultValue; - } - - function readIntArrayOr(string memory json, string memory key, int256[] memory defaultValue) - internal - view - returns (int256[] memory) - { - return keyExists(json, key) ? readIntArray(json, key) : defaultValue; - } - - function readBytes32Or(string memory json, string memory key, bytes32 defaultValue) - internal - view - returns (bytes32) - { - return keyExists(json, key) ? readBytes32(json, key) : defaultValue; - } - - function readBytes32ArrayOr(string memory json, string memory key, bytes32[] memory defaultValue) - internal - view - returns (bytes32[] memory) - { - return keyExists(json, key) ? readBytes32Array(json, key) : defaultValue; - } - - function readStringOr(string memory json, string memory key, string memory defaultValue) - internal - view - returns (string memory) - { - return keyExists(json, key) ? readString(json, key) : defaultValue; - } - - function readStringArrayOr(string memory json, string memory key, string[] memory defaultValue) - internal - view - returns (string[] memory) - { - return keyExists(json, key) ? readStringArray(json, key) : defaultValue; - } - - function readAddressOr(string memory json, string memory key, address defaultValue) - internal - view - returns (address) - { - return keyExists(json, key) ? readAddress(json, key) : defaultValue; - } - - function readAddressArrayOr(string memory json, string memory key, address[] memory defaultValue) - internal - view - returns (address[] memory) - { - return keyExists(json, key) ? readAddressArray(json, key) : defaultValue; - } - - function readBoolOr(string memory json, string memory key, bool defaultValue) internal view returns (bool) { - return keyExists(json, key) ? readBool(json, key) : defaultValue; - } - - function readBoolArrayOr(string memory json, string memory key, bool[] memory defaultValue) - internal - view - returns (bool[] memory) - { - return keyExists(json, key) ? readBoolArray(json, key) : defaultValue; - } - - function readBytesOr(string memory json, string memory key, bytes memory defaultValue) - internal - view - returns (bytes memory) - { - return keyExists(json, key) ? readBytes(json, key) : defaultValue; - } - - function readBytesArrayOr(string memory json, string memory key, bytes[] memory defaultValue) - internal - view - returns (bytes[] memory) - { - return keyExists(json, key) ? readBytesArray(json, key) : defaultValue; - } - - 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/typescript/packages/account-modules/lib/forge-std/src/StdMath.sol b/typescript/packages/account-modules/lib/forge-std/src/StdMath.sol deleted file mode 100644 index 459523b..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/StdMath.sol +++ /dev/null @@ -1,43 +0,0 @@ -// 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/typescript/packages/account-modules/lib/forge-std/src/StdStorage.sol b/typescript/packages/account-modules/lib/forge-std/src/StdStorage.sol deleted file mode 100644 index 1627af7..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/StdStorage.sol +++ /dev/null @@ -1,473 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2 <0.9.0; - -import {Vm} from "./Vm.sol"; - -struct FindData { - uint256 slot; - uint256 offsetLeft; - uint256 offsetRight; - bool found; -} - -struct StdStorage { - mapping(address => mapping(bytes4 => mapping(bytes32 => FindData))) finds; - bytes32[] _keys; - bytes4 _sig; - uint256 _depth; - address _target; - bytes32 _set; - bool _enable_packed_slots; - bytes _calldata; -} - -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"))))); - uint256 constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935; - - function sigs(string memory sigStr) internal pure returns (bytes4) { - return bytes4(keccak256(bytes(sigStr))); - } - - function getCallParams(StdStorage storage self) internal view returns (bytes memory) { - if (self._calldata.length == 0) { - return flatten(self._keys); - } else { - return self._calldata; - } - } - - // Calls target contract with configured parameters - function callTarget(StdStorage storage self) internal view returns (bool, bytes32) { - bytes memory cd = abi.encodePacked(self._sig, getCallParams(self)); - (bool success, bytes memory rdat) = self._target.staticcall(cd); - bytes32 result = bytesToBytes32(rdat, 32 * self._depth); - - return (success, result); - } - - // Tries mutating slot value to determine if the targeted value is stored in it. - // If current value is 0, then we are setting slot value to type(uint256).max - // Otherwise, we set it to 0. That way, return value should always be affected. - function checkSlotMutatesCall(StdStorage storage self, bytes32 slot) internal returns (bool) { - bytes32 prevSlotValue = vm.load(self._target, slot); - (bool success, bytes32 prevReturnValue) = callTarget(self); - - bytes32 testVal = prevReturnValue == bytes32(0) ? bytes32(UINT256_MAX) : bytes32(0); - vm.store(self._target, slot, testVal); - - (, bytes32 newReturnValue) = callTarget(self); - - vm.store(self._target, slot, prevSlotValue); - - return (success && (prevReturnValue != newReturnValue)); - } - - // Tries setting one of the bits in slot to 1 until return value changes. - // Index of resulted bit is an offset packed slot has from left/right side - function findOffset(StdStorage storage self, bytes32 slot, bool left) internal returns (bool, uint256) { - for (uint256 offset = 0; offset < 256; offset++) { - uint256 valueToPut = left ? (1 << (255 - offset)) : (1 << offset); - vm.store(self._target, slot, bytes32(valueToPut)); - - (bool success, bytes32 data) = callTarget(self); - - if (success && (uint256(data) > 0)) { - return (true, offset); - } - } - return (false, 0); - } - - function findOffsets(StdStorage storage self, bytes32 slot) internal returns (bool, uint256, uint256) { - bytes32 prevSlotValue = vm.load(self._target, slot); - - (bool foundLeft, uint256 offsetLeft) = findOffset(self, slot, true); - (bool foundRight, uint256 offsetRight) = findOffset(self, slot, false); - - // `findOffset` may mutate slot value, so we are setting it to initial value - vm.store(self._target, slot, prevSlotValue); - return (foundLeft && foundRight, offsetLeft, offsetRight); - } - - function find(StdStorage storage self) internal returns (FindData storage) { - return find(self, true); - } - - /// @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, bool _clear) internal returns (FindData storage) { - address who = self._target; - bytes4 fsig = self._sig; - uint256 field_depth = self._depth; - bytes memory params = getCallParams(self); - - // calldata to test against - if (self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found) { - if (_clear) { - clear(self); - } - return self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))]; - } - vm.record(); - (, bytes32 callResult) = callTarget(self); - (bytes32[] memory reads,) = vm.accesses(address(who)); - - if (reads.length == 0) { - revert("stdStorage find(StdStorage): No storage use detected for target."); - } else { - for (uint256 i = reads.length; --i >= 0;) { - bytes32 prev = vm.load(who, reads[i]); - if (prev == bytes32(0)) { - emit WARNING_UninitedSlot(who, uint256(reads[i])); - } - - if (!checkSlotMutatesCall(self, reads[i])) { - continue; - } - - (uint256 offsetLeft, uint256 offsetRight) = (0, 0); - - if (self._enable_packed_slots) { - bool found; - (found, offsetLeft, offsetRight) = findOffsets(self, reads[i]); - if (!found) { - continue; - } - } - - // Check that value between found offsets is equal to the current call result - uint256 curVal = (uint256(prev) & getMaskByOffsets(offsetLeft, offsetRight)) >> offsetRight; - - if (uint256(callResult) != curVal) { - continue; - } - - emit SlotFound(who, fsig, keccak256(abi.encodePacked(params, field_depth)), uint256(reads[i])); - self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))] = - FindData(uint256(reads[i]), offsetLeft, offsetRight, true); - break; - } - } - - require( - self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found, - "stdStorage find(StdStorage): Slot(s) not found." - ); - - if (_clear) { - clear(self); - } - return self.finds[who][fsig][keccak256(abi.encodePacked(params, 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_calldata(StdStorage storage self, bytes memory _calldata) internal returns (StdStorage storage) { - self._calldata = _calldata; - 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 enable_packed_slots(StdStorage storage self) internal returns (StdStorage storage) { - self._enable_packed_slots = true; - 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) { - FindData storage data = find(self, false); - uint256 mask = getMaskByOffsets(data.offsetLeft, data.offsetRight); - uint256 value = (uint256(vm.load(self._target, bytes32(data.slot))) & mask) >> data.offsetRight; - clear(self); - return abi.encode(value); - } - - 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, true).slot - 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, true).slot - 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; - } - - function clear(StdStorage storage self) internal { - delete self._target; - delete self._sig; - delete self._keys; - delete self._depth; - delete self._enable_packed_slots; - delete self._calldata; - } - - // Returns mask which contains non-zero bits for values between `offsetLeft` and `offsetRight` - // (slotValue & mask) >> offsetRight will be the value of the given packed variable - function getMaskByOffsets(uint256 offsetLeft, uint256 offsetRight) internal pure returns (uint256 mask) { - // mask = ((1 << (256 - (offsetRight + offsetLeft))) - 1) << offsetRight; - // using assembly because (1 << 256) causes overflow - assembly { - mask := shl(offsetRight, sub(shl(sub(256, add(offsetRight, offsetLeft)), 1), 1)) - } - } - - // Returns slot value with updated packed variable. - function getUpdatedSlotValue(bytes32 curValue, uint256 varValue, uint256 offsetLeft, uint256 offsetRight) - internal - pure - returns (bytes32 newValue) - { - return bytes32((uint256(curValue) & ~getMaskByOffsets(offsetLeft, offsetRight)) | (varValue << offsetRight)); - } -} - -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 find(self, true); - } - - function find(StdStorage storage self, bool _clear) internal returns (uint256) { - return stdStorageSafe.find(self, _clear).slot; - } - - 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 with_calldata(StdStorage storage self, bytes memory _calldata) internal returns (StdStorage storage) { - return stdStorageSafe.with_calldata(self, _calldata); - } - - function enable_packed_slots(StdStorage storage self) internal returns (StdStorage storage) { - return stdStorageSafe.enable_packed_slots(self); - } - - function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { - return stdStorageSafe.depth(self, _depth); - } - - function clear(StdStorage storage self) internal { - stdStorageSafe.clear(self); - } - - 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; - bytes memory params = stdStorageSafe.getCallParams(self); - - if (!self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found) { - find(self, false); - } - FindData storage data = self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))]; - if ((data.offsetLeft + data.offsetRight) > 0) { - uint256 maxVal = 2 ** (256 - (data.offsetLeft + data.offsetRight)); - require( - uint256(set) < maxVal, - string( - abi.encodePacked( - "stdStorage find(StdStorage): Packed slot. We can't fit value greater than ", - vm.toString(maxVal) - ) - ) - ); - } - bytes32 curVal = vm.load(who, bytes32(data.slot)); - bytes32 valToSet = stdStorageSafe.getUpdatedSlotValue(curVal, uint256(set), data.offsetLeft, data.offsetRight); - - vm.store(who, bytes32(data.slot), valToSet); - - (bool success, bytes32 callResult) = stdStorageSafe.callTarget(self); - - if (!success || callResult != set) { - vm.store(who, bytes32(data.slot), curVal); - revert("stdStorage find(StdStorage): Failed to write value."); - } - clear(self); - } - - 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); - } -} diff --git a/typescript/packages/account-modules/lib/forge-std/src/StdStyle.sol b/typescript/packages/account-modules/lib/forge-std/src/StdStyle.sol deleted file mode 100644 index d371e0c..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/StdStyle.sol +++ /dev/null @@ -1,333 +0,0 @@ -// 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/typescript/packages/account-modules/lib/forge-std/src/StdToml.sol b/typescript/packages/account-modules/lib/forge-std/src/StdToml.sol deleted file mode 100644 index 7ad3be2..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/StdToml.sol +++ /dev/null @@ -1,283 +0,0 @@ -// 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 TOML files -// To parse: -// ``` -// using stdToml for string; -// string memory toml = vm.readFile(""); -// toml.readUint(""); -// ``` -// To write: -// ``` -// using stdToml for string; -// string memory json = "json"; -// json.serialize("a", uint256(123)); -// string memory semiFinal = json.serialize("b", string("test")); -// string memory finalJson = json.serialize("c", semiFinal); -// finalJson.write(""); -// ``` - -library stdToml { - VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); - - function keyExists(string memory toml, string memory key) internal view returns (bool) { - return vm.keyExistsToml(toml, key); - } - - function parseRaw(string memory toml, string memory key) internal pure returns (bytes memory) { - return vm.parseToml(toml, key); - } - - function readUint(string memory toml, string memory key) internal pure returns (uint256) { - return vm.parseTomlUint(toml, key); - } - - function readUintArray(string memory toml, string memory key) internal pure returns (uint256[] memory) { - return vm.parseTomlUintArray(toml, key); - } - - function readInt(string memory toml, string memory key) internal pure returns (int256) { - return vm.parseTomlInt(toml, key); - } - - function readIntArray(string memory toml, string memory key) internal pure returns (int256[] memory) { - return vm.parseTomlIntArray(toml, key); - } - - function readBytes32(string memory toml, string memory key) internal pure returns (bytes32) { - return vm.parseTomlBytes32(toml, key); - } - - function readBytes32Array(string memory toml, string memory key) internal pure returns (bytes32[] memory) { - return vm.parseTomlBytes32Array(toml, key); - } - - function readString(string memory toml, string memory key) internal pure returns (string memory) { - return vm.parseTomlString(toml, key); - } - - function readStringArray(string memory toml, string memory key) internal pure returns (string[] memory) { - return vm.parseTomlStringArray(toml, key); - } - - function readAddress(string memory toml, string memory key) internal pure returns (address) { - return vm.parseTomlAddress(toml, key); - } - - function readAddressArray(string memory toml, string memory key) internal pure returns (address[] memory) { - return vm.parseTomlAddressArray(toml, key); - } - - function readBool(string memory toml, string memory key) internal pure returns (bool) { - return vm.parseTomlBool(toml, key); - } - - function readBoolArray(string memory toml, string memory key) internal pure returns (bool[] memory) { - return vm.parseTomlBoolArray(toml, key); - } - - function readBytes(string memory toml, string memory key) internal pure returns (bytes memory) { - return vm.parseTomlBytes(toml, key); - } - - function readBytesArray(string memory toml, string memory key) internal pure returns (bytes[] memory) { - return vm.parseTomlBytesArray(toml, key); - } - - function readUintOr(string memory toml, string memory key, uint256 defaultValue) internal view returns (uint256) { - return keyExists(toml, key) ? readUint(toml, key) : defaultValue; - } - - function readUintArrayOr(string memory toml, string memory key, uint256[] memory defaultValue) - internal - view - returns (uint256[] memory) - { - return keyExists(toml, key) ? readUintArray(toml, key) : defaultValue; - } - - function readIntOr(string memory toml, string memory key, int256 defaultValue) internal view returns (int256) { - return keyExists(toml, key) ? readInt(toml, key) : defaultValue; - } - - function readIntArrayOr(string memory toml, string memory key, int256[] memory defaultValue) - internal - view - returns (int256[] memory) - { - return keyExists(toml, key) ? readIntArray(toml, key) : defaultValue; - } - - function readBytes32Or(string memory toml, string memory key, bytes32 defaultValue) - internal - view - returns (bytes32) - { - return keyExists(toml, key) ? readBytes32(toml, key) : defaultValue; - } - - function readBytes32ArrayOr(string memory toml, string memory key, bytes32[] memory defaultValue) - internal - view - returns (bytes32[] memory) - { - return keyExists(toml, key) ? readBytes32Array(toml, key) : defaultValue; - } - - function readStringOr(string memory toml, string memory key, string memory defaultValue) - internal - view - returns (string memory) - { - return keyExists(toml, key) ? readString(toml, key) : defaultValue; - } - - function readStringArrayOr(string memory toml, string memory key, string[] memory defaultValue) - internal - view - returns (string[] memory) - { - return keyExists(toml, key) ? readStringArray(toml, key) : defaultValue; - } - - function readAddressOr(string memory toml, string memory key, address defaultValue) - internal - view - returns (address) - { - return keyExists(toml, key) ? readAddress(toml, key) : defaultValue; - } - - function readAddressArrayOr(string memory toml, string memory key, address[] memory defaultValue) - internal - view - returns (address[] memory) - { - return keyExists(toml, key) ? readAddressArray(toml, key) : defaultValue; - } - - function readBoolOr(string memory toml, string memory key, bool defaultValue) internal view returns (bool) { - return keyExists(toml, key) ? readBool(toml, key) : defaultValue; - } - - function readBoolArrayOr(string memory toml, string memory key, bool[] memory defaultValue) - internal - view - returns (bool[] memory) - { - return keyExists(toml, key) ? readBoolArray(toml, key) : defaultValue; - } - - function readBytesOr(string memory toml, string memory key, bytes memory defaultValue) - internal - view - returns (bytes memory) - { - return keyExists(toml, key) ? readBytes(toml, key) : defaultValue; - } - - function readBytesArrayOr(string memory toml, string memory key, bytes[] memory defaultValue) - internal - view - returns (bytes[] memory) - { - return keyExists(toml, key) ? readBytesArray(toml, key) : defaultValue; - } - - 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.writeToml(jsonKey, path); - } - - function write(string memory jsonKey, string memory path, string memory valueKey) internal { - vm.writeToml(jsonKey, path, valueKey); - } -} diff --git a/typescript/packages/account-modules/lib/forge-std/src/StdUtils.sol b/typescript/packages/account-modules/lib/forge-std/src/StdUtils.sol deleted file mode 100644 index 9321df1..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/StdUtils.sol +++ /dev/null @@ -1,208 +0,0 @@ -// 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 pure virtual returns (uint256 result) { - result = _bound(x, min, max); - console2_log_StdUtils("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 pure virtual returns (int256 result) { - result = _bound(x, min, max); - console2_log_StdUtils("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 - function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) { - console2_log_StdUtils("computeCreateAddress is deprecated. Please use vm.computeCreateAddress instead."); - return vm.computeCreateAddress(deployer, nonce); - } - - function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) - internal - pure - virtual - returns (address) - { - console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead."); - return vm.computeCreate2Address(salt, initcodeHash, deployer); - } - - /// @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) { - console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead."); - return vm.computeCreate2Address(salt, initCodeHash); - } - - /// @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))); - } - - // This section is used to prevent the compilation of console, which shortens the compilation time when console is - // not used elsewhere. We also trick the compiler into letting us make the console log methods as `pure` to avoid - // any breaking changes to function signatures. - 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 = CONSOLE2_ADDRESS; - /// @solidity memory-safe-assembly - assembly { - let payloadStart := add(payload, 32) - let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) - } - } - - function console2_log_StdUtils(string memory p0) private pure { - _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); - } - - function console2_log_StdUtils(string memory p0, uint256 p1) private pure { - _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); - } - - function console2_log_StdUtils(string memory p0, string memory p1) private pure { - _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); - } -} diff --git a/typescript/packages/account-modules/lib/forge-std/src/Test.sol b/typescript/packages/account-modules/lib/forge-std/src/Test.sol deleted file mode 100644 index 11b18f2..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/Test.sol +++ /dev/null @@ -1,34 +0,0 @@ -// 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 {StdConstants} from "./StdConstants.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 {stdToml} from "./StdToml.sol"; -import {StdUtils} from "./StdUtils.sol"; -import {Vm} from "./Vm.sol"; - -// 📦 BOILERPLATE -import {TestBase} from "./Base.sol"; - -// ⭐️ TEST -abstract contract Test is TestBase, StdAssertions, StdChains, StdCheats, StdInvariant, StdUtils { - // Note: IS_TEST() must return true. - bool public IS_TEST = true; -} diff --git a/typescript/packages/account-modules/lib/forge-std/src/Vm.sol b/typescript/packages/account-modules/lib/forge-std/src/Vm.sol deleted file mode 100644 index fc73cc1..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/Vm.sol +++ /dev/null @@ -1,2468 +0,0 @@ -// Automatically @generated by scripts/vm.py. Do not modify manually. - -// SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity >=0.6.2 <0.9.0; -pragma experimental ABIEncoderV2; - -/// 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 { - /// A modification applied to either `msg.sender` or `tx.origin`. Returned by `readCallers`. - enum CallerMode { - // No caller modification is currently active. - None, - // A one time broadcast triggered by a `vm.broadcast()` call is currently active. - Broadcast, - // A recurrent broadcast triggered by a `vm.startBroadcast()` call is currently active. - RecurrentBroadcast, - // A one time prank triggered by a `vm.prank()` call is currently active. - Prank, - // A recurrent prank triggered by a `vm.startPrank()` call is currently active. - RecurrentPrank - } - - /// The kind of account access that occurred. - enum AccountAccessKind { - // The account was called. - Call, - // The account was called via delegatecall. - DelegateCall, - // The account was called via callcode. - CallCode, - // The account was called via staticcall. - StaticCall, - // The account was created. - Create, - // The account was selfdestructed. - SelfDestruct, - // Synthetic access indicating the current context has resumed after a previous sub-context (AccountAccess). - Resume, - // The account's balance was read. - Balance, - // The account's codesize was read. - Extcodesize, - // The account's codehash was read. - Extcodehash, - // The account's code was copied. - Extcodecopy - } - - /// Forge execution contexts. - enum ForgeContext { - // Test group execution context (test, coverage or snapshot). - TestGroup, - // `forge test` execution context. - Test, - // `forge coverage` execution context. - Coverage, - // `forge snapshot` execution context. - Snapshot, - // Script group execution context (dry run, broadcast or resume). - ScriptGroup, - // `forge script` execution context. - ScriptDryRun, - // `forge script --broadcast` execution context. - ScriptBroadcast, - // `forge script --resume` execution context. - ScriptResume, - // Unknown `forge` execution context. - Unknown - } - - /// The transaction type (`txType`) of the broadcast. - enum BroadcastTxType { - // Represents a CALL broadcast tx. - Call, - // Represents a CREATE broadcast tx. - Create, - // Represents a CREATE2 broadcast tx. - Create2 - } - - /// An Ethereum log. Returned by `getRecordedLogs`. - struct Log { - // The topics of the log, including the signature, if any. - bytes32[] topics; - // The raw data of the log. - bytes data; - // The address of the log's emitter. - address emitter; - } - - /// An RPC URL and its alias. Returned by `rpcUrlStructs`. - struct Rpc { - // The alias of the RPC URL. - string key; - // The RPC URL. - string url; - } - - /// An RPC log object. Returned by `eth_getLogs`. - struct EthGetLogs { - // The address of the log's emitter. - address emitter; - // The topics of the log, including the signature, if any. - bytes32[] topics; - // The raw data of the log. - bytes data; - // The block hash. - bytes32 blockHash; - // The block number. - uint64 blockNumber; - // The transaction hash. - bytes32 transactionHash; - // The transaction index in the block. - uint64 transactionIndex; - // The log index. - uint256 logIndex; - // Whether the log was removed. - bool removed; - } - - /// A single entry in a directory listing. Returned by `readDir`. - struct DirEntry { - // The error message, if any. - string errorMessage; - // The path of the entry. - string path; - // The depth of the entry. - uint64 depth; - // Whether the entry is a directory. - bool isDir; - // Whether the entry is a symlink. - bool isSymlink; - } - - /// Metadata information about a file. - /// This structure is returned from the `fsMetadata` function and represents known - /// metadata about a file such as its permissions, size, modification - /// times, etc. - struct FsMetadata { - // True if this metadata is for a directory. - bool isDir; - // True if this metadata is for a symlink. - bool isSymlink; - // The size of the file, in bytes, this metadata is for. - uint256 length; - // True if this metadata is for a readonly (unwritable) file. - bool readOnly; - // The last modification time listed in this metadata. - uint256 modified; - // The last access time of this metadata. - uint256 accessed; - // The creation time listed in this metadata. - uint256 created; - } - - /// A wallet with a public and private key. - struct Wallet { - // The wallet's address. - address addr; - // The wallet's public key `X`. - uint256 publicKeyX; - // The wallet's public key `Y`. - uint256 publicKeyY; - // The wallet's private key. - uint256 privateKey; - } - - /// The result of a `tryFfi` call. - struct FfiResult { - // The exit code of the call. - int32 exitCode; - // The optionally hex-decoded `stdout` data. - bytes stdout; - // The `stderr` data. - bytes stderr; - } - - /// Information on the chain and fork. - struct ChainInfo { - // The fork identifier. Set to zero if no fork is active. - uint256 forkId; - // The chain ID of the current fork. - uint256 chainId; - } - - /// Information about a blockchain. - 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. - string rpcUrl; - } - - /// The result of a `stopAndReturnStateDiff` call. - struct AccountAccess { - // The chain and fork the access occurred. - ChainInfo chainInfo; - // The kind of account access that determines what the account is. - // If kind is Call, DelegateCall, StaticCall or CallCode, then the account is the callee. - // If kind is Create, then the account is the newly created account. - // If kind is SelfDestruct, then the account is the selfdestruct recipient. - // If kind is a Resume, then account represents a account context that has resumed. - AccountAccessKind kind; - // The account that was accessed. - // It's either the account created, callee or a selfdestruct recipient for CREATE, CALL or SELFDESTRUCT. - address account; - // What accessed the account. - address accessor; - // If the account was initialized or empty prior to the access. - // An account is considered initialized if it has code, a - // non-zero nonce, or a non-zero balance. - bool initialized; - // The previous balance of the accessed account. - uint256 oldBalance; - // The potential new balance of the accessed account. - // That is, all balance changes are recorded here, even if reverts occurred. - uint256 newBalance; - // Code of the account deployed by CREATE. - bytes deployedCode; - // Value passed along with the account access - uint256 value; - // Input data provided to the CREATE or CALL - bytes data; - // If this access reverted in either the current or parent context. - bool reverted; - // An ordered list of storage accesses made during an account access operation. - StorageAccess[] storageAccesses; - // Call depth traversed during the recording of state differences - uint64 depth; - } - - /// The storage accessed during an `AccountAccess`. - struct StorageAccess { - // The account whose storage was accessed. - address account; - // The slot that was accessed. - bytes32 slot; - // If the access was a write. - bool isWrite; - // The previous value of the slot. - bytes32 previousValue; - // The new value of the slot. - bytes32 newValue; - // If the access was reverted. - bool reverted; - } - - /// Gas used. Returned by `lastCallGas`. - struct Gas { - // The gas limit of the call. - uint64 gasLimit; - // The total gas used. - uint64 gasTotalUsed; - // DEPRECATED: The amount of gas used for memory expansion. Ref: - uint64 gasMemoryUsed; - // The amount of gas refunded. - int64 gasRefunded; - // The amount of gas remaining. - uint64 gasRemaining; - } - - /// The result of the `stopDebugTraceRecording` call - struct DebugStep { - // The stack before executing the step of the run. - // stack\[0\] represents the top of the stack. - // and only stack data relevant to the opcode execution is contained. - uint256[] stack; - // The memory input data before executing the step of the run. - // only input data relevant to the opcode execution is contained. - // e.g. for MLOAD, it will have memory\[offset:offset+32\] copied here. - // the offset value can be get by the stack data. - bytes memoryInput; - // The opcode that was accessed. - uint8 opcode; - // The call depth of the step. - uint64 depth; - // Whether the call end up with out of gas error. - bool isOutOfGas; - // The contract address where the opcode is running - address contractAddr; - } - - /// Represents a transaction's broadcast details. - struct BroadcastTxSummary { - // The hash of the transaction that was broadcasted - bytes32 txHash; - // Represent the type of transaction among CALL, CREATE, CREATE2 - BroadcastTxType txType; - // The address of the contract that was called or created. - // This is address of the contract that is created if the txType is CREATE or CREATE2. - address contractAddress; - // The block number the transaction landed in. - uint64 blockNumber; - // Status of the transaction, retrieved from the transaction receipt. - bool success; - } - - /// Holds a signed EIP-7702 authorization for an authority account to delegate to an implementation. - struct SignedDelegation { - // The y-parity of the recovered secp256k1 signature (0 or 1). - uint8 v; - // First 32 bytes of the signature. - bytes32 r; - // Second 32 bytes of the signature. - bytes32 s; - // The current nonce of the authority account at signing time. - // Used to ensure signature can't be replayed after account nonce changes. - uint64 nonce; - // Address of the contract implementation that will be delegated to. - // Gets encoded into delegation code: 0xef0100 || implementation. - address implementation; - } - - /// Represents a "potential" revert reason from a single subsequent call when using `vm.assumeNoReverts`. - /// Reverts that match will result in a FOUNDRY::ASSUME rejection, whereas unmatched reverts will be surfaced - /// as normal. - struct PotentialRevert { - // The allowed origin of the revert opcode; address(0) allows reverts from any address - address reverter; - // When true, only matches on the beginning of the revert data, otherwise, matches on entire revert data - bool partialMatch; - // The data to use to match encountered reverts - bytes revertData; - } - - /// An EIP-2930 access list item. - struct AccessListItem { - // The address to be added in access list. - address target; - // The storage keys to be added in access list. - bytes32[] storageKeys; - } - - // ======== Crypto ======== - - /// 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); - - /// 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); - - /// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language - /// at the derivation path `m/44'/60'/0'/0/{index}`. - function deriveKey(string calldata mnemonic, uint32 index, string calldata language) - external - pure - returns (uint256 privateKey); - - /// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language - /// at `{derivationPath}{index}`. - function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index, string calldata language) - external - pure - returns (uint256 privateKey); - - /// Derives secp256r1 public key from the provided `privateKey`. - function publicKeyP256(uint256 privateKey) external pure returns (uint256 publicKeyX, uint256 publicKeyY); - - /// Adds a private key to the local forge wallet and returns the address. - function rememberKey(uint256 privateKey) external returns (address keyAddr); - - /// Derive a set number of wallets from a mnemonic at the derivation path `m/44'/60'/0'/0/{0..count}`. - /// The respective private keys are saved to the local forge wallet for later use and their addresses are returned. - function rememberKeys(string calldata mnemonic, string calldata derivationPath, uint32 count) - external - returns (address[] memory keyAddrs); - - /// Derive a set number of wallets from a mnemonic in the specified language at the derivation path `m/44'/60'/0'/0/{0..count}`. - /// The respective private keys are saved to the local forge wallet for later use and their addresses are returned. - function rememberKeys( - string calldata mnemonic, - string calldata derivationPath, - string calldata language, - uint32 count - ) external returns (address[] memory keyAddrs); - - /// Signs data with a `Wallet`. - /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the - /// signature's `s` value, and the recovery id `v` in a single bytes32. - /// This format reduces the signature size from 65 to 64 bytes. - function signCompact(Wallet calldata wallet, bytes32 digest) external returns (bytes32 r, bytes32 vs); - - /// Signs `digest` with `privateKey` using the secp256k1 curve. - /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the - /// signature's `s` value, and the recovery id `v` in a single bytes32. - /// This format reduces the signature size from 65 to 64 bytes. - function signCompact(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 vs); - - /// Signs `digest` with signer provided to script using the secp256k1 curve. - /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the - /// signature's `s` value, and the recovery id `v` in a single bytes32. - /// This format reduces the signature size from 65 to 64 bytes. - /// If `--sender` is provided, the signer with provided address is used, otherwise, - /// if exactly one signer is provided to the script, that signer is used. - /// Raises error if signer passed through `--sender` does not match any unlocked signers or - /// if `--sender` is not provided and not exactly one signer is passed to the script. - function signCompact(bytes32 digest) external pure returns (bytes32 r, bytes32 vs); - - /// Signs `digest` with signer provided to script using the secp256k1 curve. - /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the - /// signature's `s` value, and the recovery id `v` in a single bytes32. - /// This format reduces the signature size from 65 to 64 bytes. - /// Raises error if none of the signers passed into the script have provided address. - function signCompact(address signer, bytes32 digest) external pure returns (bytes32 r, bytes32 vs); - - /// Signs `digest` with `privateKey` using the secp256r1 curve. - function signP256(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 s); - - /// Signs data with a `Wallet`. - function sign(Wallet calldata wallet, bytes32 digest) external returns (uint8 v, bytes32 r, bytes32 s); - - /// Signs `digest` with `privateKey` using the secp256k1 curve. - function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); - - /// Signs `digest` with signer provided to script using the secp256k1 curve. - /// If `--sender` is provided, the signer with provided address is used, otherwise, - /// if exactly one signer is provided to the script, that signer is used. - /// Raises error if signer passed through `--sender` does not match any unlocked signers or - /// if `--sender` is not provided and not exactly one signer is passed to the script. - function sign(bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); - - /// Signs `digest` with signer provided to script using the secp256k1 curve. - /// Raises error if none of the signers passed into the script have provided address. - function sign(address signer, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); - - // ======== Environment ======== - - /// Gets the environment variable `name` and parses it as `address`. - /// Reverts if the variable was not found or could not be parsed. - function envAddress(string calldata name) external view returns (address value); - - /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value); - - /// Gets the environment variable `name` and parses it as `bool`. - /// Reverts if the variable was not found or could not be parsed. - function envBool(string calldata name) external view returns (bool value); - - /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value); - - /// Gets the environment variable `name` and parses it as `bytes32`. - /// Reverts if the variable was not found or could not be parsed. - function envBytes32(string calldata name) external view returns (bytes32 value); - - /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value); - - /// Gets the environment variable `name` and parses it as `bytes`. - /// Reverts if the variable was not found or could not be parsed. - function envBytes(string calldata name) external view returns (bytes memory value); - - /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value); - - /// Gets the environment variable `name` and returns true if it exists, else returns false. - function envExists(string calldata name) external view returns (bool result); - - /// Gets the environment variable `name` and parses it as `int256`. - /// Reverts if the variable was not found or could not be parsed. - function envInt(string calldata name) external view returns (int256 value); - - /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value); - - /// Gets the environment variable `name` and parses it as `bool`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, bool defaultValue) external view returns (bool value); - - /// Gets the environment variable `name` and parses it as `uint256`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, uint256 defaultValue) external view returns (uint256 value); - - /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, address[] calldata defaultValue) - external - view - returns (address[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue) - external - view - returns (bytes32[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, string[] calldata defaultValue) - external - view - returns (string[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue) - external - view - returns (bytes[] memory value); - - /// Gets the environment variable `name` and parses it as `int256`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, int256 defaultValue) external view returns (int256 value); - - /// Gets the environment variable `name` and parses it as `address`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, address defaultValue) external view returns (address value); - - /// Gets the environment variable `name` and parses it as `bytes32`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, bytes32 defaultValue) external view returns (bytes32 value); - - /// Gets the environment variable `name` and parses it as `string`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata defaultValue) external view returns (string memory value); - - /// Gets the environment variable `name` and parses it as `bytes`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, bytes calldata defaultValue) external view returns (bytes memory value); - - /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue) - external - view - returns (bool[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue) - external - view - returns (uint256[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue) - external - view - returns (int256[] memory value); - - /// Gets the environment variable `name` and parses it as `string`. - /// Reverts if the variable was not found or could not be parsed. - function envString(string calldata name) external view returns (string memory value); - - /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envString(string calldata name, string calldata delim) external view returns (string[] memory value); - - /// Gets the environment variable `name` and parses it as `uint256`. - /// Reverts if the variable was not found or could not be parsed. - function envUint(string calldata name) external view returns (uint256 value); - - /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value); - - /// Returns true if `forge` command was executed in given context. - function isContext(ForgeContext context) external view returns (bool result); - - /// Sets environment variables. - function setEnv(string calldata name, string calldata value) external; - - // ======== EVM ======== - - /// 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); - - /// Gets the address for a given private key. - function addr(uint256 privateKey) external pure returns (address keyAddr); - - /// Gets all the logs according to specified filter. - function eth_getLogs(uint256 fromBlock, uint256 toBlock, address target, bytes32[] calldata topics) - external - returns (EthGetLogs[] memory logs); - - /// Gets the current `block.blobbasefee`. - /// You should use this instead of `block.blobbasefee` if you use `vm.blobBaseFee`, as `block.blobbasefee` is assumed to be constant across a transaction, - /// and as a result will get optimized out by the compiler. - /// See https://github.com/foundry-rs/foundry/issues/6180 - function getBlobBaseFee() external view returns (uint256 blobBaseFee); - - /// Gets the current `block.number`. - /// You should use this instead of `block.number` if you use `vm.roll`, as `block.number` is assumed to be constant across a transaction, - /// and as a result will get optimized out by the compiler. - /// See https://github.com/foundry-rs/foundry/issues/6180 - function getBlockNumber() external view returns (uint256 height); - - /// Gets the current `block.timestamp`. - /// You should use this instead of `block.timestamp` if you use `vm.warp`, as `block.timestamp` is assumed to be constant across a transaction, - /// and as a result will get optimized out by the compiler. - /// See https://github.com/foundry-rs/foundry/issues/6180 - function getBlockTimestamp() external view returns (uint256 timestamp); - - /// 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); - - /// 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 nonce of an account. - function getNonce(address account) external view returns (uint64 nonce); - - /// Get the nonce of a `Wallet`. - function getNonce(Wallet calldata wallet) external returns (uint64 nonce); - - /// Gets the RLP encoded block header for a given block number. - /// Returns the block header in the same format as `cast block --raw`. - function getRawBlockHeader(uint256 blockNumber) external view returns (bytes memory rlpHeader); - - /// Gets all the recorded logs. - function getRecordedLogs() external returns (Log[] memory logs); - - /// Returns state diffs from current `vm.startStateDiffRecording` session. - function getStateDiff() external view returns (string memory diff); - - /// Returns state diffs from current `vm.startStateDiffRecording` session, in json format. - function getStateDiffJson() external view returns (string memory diff); - - /// Gets the gas used in the last call from the callee perspective. - function lastCallGas() external view returns (Gas memory gas); - - /// Loads a storage slot from an address. - function load(address target, bytes32 slot) external view returns (bytes32 data); - - /// Pauses gas metering (i.e. gas usage is not counted). Noop if already paused. - function pauseGasMetering() external; - - /// Records all storage reads and writes. Use `accesses` to get the recorded data. - /// Subsequent calls to `record` will clear the previous data. - function record() external; - - /// Record all the transaction logs. - function recordLogs() external; - - /// Reset gas metering (i.e. gas usage is set to gas limit). - function resetGasMetering() external; - - /// Resumes gas metering (i.e. gas usage is counted again). Noop if already on. - function resumeGasMetering() external; - - /// Performs an Ethereum JSON-RPC request to the current fork URL. - function rpc(string calldata method, string calldata params) external returns (bytes memory data); - - /// Performs an Ethereum JSON-RPC request to the given endpoint. - function rpc(string calldata urlOrAlias, string calldata method, string calldata params) - external - returns (bytes memory data); - - /// Records the debug trace during the run. - function startDebugTraceRecording() external; - - /// Starts recording all map SSTOREs for later retrieval. - function startMappingRecording() external; - - /// Record all account accesses as part of CREATE, CALL or SELFDESTRUCT opcodes in order, - /// along with the context of the calls - function startStateDiffRecording() external; - - /// Stop debug trace recording and returns the recorded debug trace. - function stopAndReturnDebugTraceRecording() external returns (DebugStep[] memory step); - - /// Returns an ordered array of all account accesses from a `vm.startStateDiffRecording` session. - function stopAndReturnStateDiff() external returns (AccountAccess[] memory accountAccesses); - - /// Stops recording all map SSTOREs for later retrieval and clears the recorded data. - function stopMappingRecording() external; - - /// Stops recording storage reads and writes. - function stopRecord() external; - - // ======== Filesystem ======== - - /// 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; - - /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the - /// artifact in the form of :: where and parts are optional. - function deployCode(string calldata artifactPath) external returns (address deployedAddress); - - /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the - /// artifact in the form of :: where and parts are optional. - /// Additionally accepts abi-encoded constructor arguments. - function deployCode(string calldata artifactPath, bytes calldata constructorArgs) - external - returns (address deployedAddress); - - /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the - /// artifact in the form of :: where and parts are optional. - /// Additionally accepts `msg.value`. - function deployCode(string calldata artifactPath, uint256 value) external returns (address deployedAddress); - - /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the - /// artifact in the form of :: where and parts are optional. - /// Additionally accepts abi-encoded constructor arguments and `msg.value`. - function deployCode(string calldata artifactPath, bytes calldata constructorArgs, uint256 value) - external - returns (address deployedAddress); - - /// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the - /// artifact in the form of :: where and parts are optional. - function deployCode(string calldata artifactPath, bytes32 salt) external returns (address deployedAddress); - - /// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the - /// artifact in the form of :: where and parts are optional. - /// Additionally accepts abi-encoded constructor arguments. - function deployCode(string calldata artifactPath, bytes calldata constructorArgs, bytes32 salt) - external - returns (address deployedAddress); - - /// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the - /// artifact in the form of :: where and parts are optional. - /// Additionally accepts `msg.value`. - function deployCode(string calldata artifactPath, uint256 value, bytes32 salt) - external - returns (address deployedAddress); - - /// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the - /// artifact in the form of :: where and parts are optional. - /// Additionally accepts abi-encoded constructor arguments and `msg.value`. - function deployCode(string calldata artifactPath, bytes calldata constructorArgs, uint256 value, bytes32 salt) - external - returns (address deployedAddress); - - /// Returns true if the given path points to an existing entity, else returns false. - function exists(string calldata path) external view returns (bool result); - - /// Performs a foreign function call via the terminal. - function ffi(string[] calldata commandInput) external returns (bytes memory 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); - - /// Gets the artifact path from code (aka. creation code). - function getArtifactPathByCode(bytes calldata code) external view returns (string memory path); - - /// Gets the artifact path from deployed code (aka. runtime code). - function getArtifactPathByDeployedCode(bytes calldata deployedCode) external view returns (string memory path); - - /// Returns the most recent broadcast for the given contract on `chainId` matching `txType`. - /// For example: - /// The most recent deployment can be fetched by passing `txType` as `CREATE` or `CREATE2`. - /// The most recent call can be fetched by passing `txType` as `CALL`. - function getBroadcast(string calldata contractName, uint64 chainId, BroadcastTxType txType) - external - view - returns (BroadcastTxSummary memory); - - /// Returns all broadcasts for the given contract on `chainId` with the specified `txType`. - /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. - function getBroadcasts(string calldata contractName, uint64 chainId, BroadcastTxType txType) - external - view - returns (BroadcastTxSummary[] memory); - - /// Returns all broadcasts for the given contract on `chainId`. - /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. - function getBroadcasts(string calldata contractName, uint64 chainId) - external - view - returns (BroadcastTxSummary[] memory); - - /// Gets the creation bytecode from an artifact file. Takes in the relative path to the json file or the path to the - /// artifact in the form of :: where and parts are optional. - 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 or the path to the - /// artifact in the form of :: where and parts are optional. - function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); - - /// Returns the most recent deployment for the current `chainId`. - function getDeployment(string calldata contractName) external view returns (address deployedAddress); - - /// Returns the most recent deployment for the given contract on `chainId` - function getDeployment(string calldata contractName, uint64 chainId) - external - view - returns (address deployedAddress); - - /// Returns all deployments for the given contract on `chainId` - /// Sorted in descending order of deployment time i.e descending order of BroadcastTxSummary.blockNumber. - /// The most recent deployment is the first element, and the oldest is the last. - function getDeployments(string calldata contractName, uint64 chainId) - external - view - returns (address[] memory deployedAddresses); - - /// Returns true if the path exists on disk and is pointing at a directory, else returns false. - function isDir(string calldata path) external view 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 view returns (bool result); - - /// Get the path of the current project root. - function projectRoot() external view returns (string memory path); - - /// Prompts the user for a string value in the terminal. - function prompt(string calldata promptText) external returns (string memory input); - - /// Prompts the user for an address in the terminal. - function promptAddress(string calldata promptText) external returns (address); - - /// Prompts the user for a hidden string value in the terminal. - function promptSecret(string calldata promptText) external returns (string memory input); - - /// Prompts the user for hidden uint256 in the terminal (usually pk). - function promptSecretUint(string calldata promptText) external returns (uint256); - - /// Prompts the user for uint256 in the terminal. - function promptUint(string calldata promptText) external returns (uint256); - - /// Reads the directory at the given path recursively, up to `maxDepth`. - /// `maxDepth` defaults to 1, meaning only the direct children of the given directory will be returned. - /// Follows symbolic links if `followLinks` is true. - function readDir(string calldata path) external view returns (DirEntry[] memory entries); - - /// See `readDir(string)`. - function readDir(string calldata path, uint64 maxDepth) external view returns (DirEntry[] memory entries); - - /// See `readDir(string)`. - 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; - - /// 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); - - /// Returns the time since unix epoch in milliseconds. - function unixTime() external view returns (uint256 milliseconds); - - /// 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; - - // ======== JSON ======== - - /// Checks if `key` exists in a JSON object. - function keyExistsJson(string calldata json, string calldata key) external view returns (bool); - - /// Parses a string of JSON data at `key` and coerces it to `address`. - function parseJsonAddress(string calldata json, string calldata key) external pure returns (address); - - /// Parses a string of JSON data at `key` and coerces it to `address[]`. - function parseJsonAddressArray(string calldata json, string calldata key) - external - pure - returns (address[] memory); - - /// Parses a string of JSON data at `key` and coerces it to `bool`. - function parseJsonBool(string calldata json, string calldata key) external pure returns (bool); - - /// Parses a string of JSON data at `key` and coerces it to `bool[]`. - function parseJsonBoolArray(string calldata json, string calldata key) external pure returns (bool[] memory); - - /// Parses a string of JSON data at `key` and coerces it to `bytes`. - function parseJsonBytes(string calldata json, string calldata key) external pure returns (bytes memory); - - /// Parses a string of JSON data at `key` and coerces it to `bytes32`. - function parseJsonBytes32(string calldata json, string calldata key) external pure returns (bytes32); - - /// Parses a string of JSON data at `key` and coerces it to `bytes32[]`. - function parseJsonBytes32Array(string calldata json, string calldata key) - external - pure - returns (bytes32[] memory); - - /// Parses a string of JSON data at `key` and coerces it to `bytes[]`. - function parseJsonBytesArray(string calldata json, string calldata key) external pure returns (bytes[] memory); - - /// Parses a string of JSON data at `key` and coerces it to `int256`. - function parseJsonInt(string calldata json, string calldata key) external pure returns (int256); - - /// Parses a string of JSON data at `key` and coerces it to `int256[]`. - function parseJsonIntArray(string calldata json, string calldata key) external pure returns (int256[] memory); - - /// Returns an array of all the keys in a JSON object. - function parseJsonKeys(string calldata json, string calldata key) external pure returns (string[] memory keys); - - /// Parses a string of JSON data at `key` and coerces it to `string`. - function parseJsonString(string calldata json, string calldata key) external pure returns (string memory); - - /// Parses a string of JSON data at `key` and coerces it to `string[]`. - function parseJsonStringArray(string calldata json, string calldata key) external pure returns (string[] memory); - - /// Parses a string of JSON data at `key` and coerces it to type array corresponding to `typeDescription`. - function parseJsonTypeArray(string calldata json, string calldata key, string calldata typeDescription) - external - pure - returns (bytes memory); - - /// Parses a string of JSON data and coerces it to type corresponding to `typeDescription`. - function parseJsonType(string calldata json, string calldata typeDescription) - external - pure - returns (bytes memory); - - /// Parses a string of JSON data at `key` and coerces it to type corresponding to `typeDescription`. - function parseJsonType(string calldata json, string calldata key, string calldata typeDescription) - external - pure - returns (bytes memory); - - /// Parses a string of JSON data at `key` and coerces it to `uint256`. - function parseJsonUint(string calldata json, string calldata key) external pure returns (uint256); - - /// Parses a string of JSON data at `key` and coerces it to `uint256[]`. - function parseJsonUintArray(string calldata json, string calldata key) external pure returns (uint256[] memory); - - /// ABI-encodes a JSON object. - function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData); - - /// ABI-encodes a JSON object at `key`. - function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData); - - /// See `serializeJson`. - function serializeAddress(string calldata objectKey, string calldata valueKey, address value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBool(string calldata objectKey, string calldata valueKey, bool value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeInt(string calldata objectKey, string calldata valueKey, int256 value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values) - external - returns (string memory json); - - /// Serializes a key and value to a JSON object stored in-memory that can be later written to a file. - /// 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); - - /// See `serializeJson`. - function serializeJsonType(string calldata typeDescription, bytes calldata value) - external - pure - returns (string memory json); - - /// See `serializeJson`. - function serializeJsonType( - string calldata objectKey, - string calldata valueKey, - string calldata typeDescription, - bytes calldata value - ) external returns (string memory json); - - /// See `serializeJson`. - function serializeString(string calldata objectKey, string calldata valueKey, string calldata value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeUintToHex(string calldata objectKey, string calldata valueKey, uint256 value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) - external - returns (string memory json); - - /// 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; - - /// Checks if `key` exists in a JSON object - /// `keyExists` is being deprecated in favor of `keyExistsJson`. It will be removed in future versions. - function keyExists(string calldata json, string calldata key) external view returns (bool); - - // ======== Scripting ======== - - /// Attach an EIP-4844 blob to the next call - function attachBlob(bytes calldata blob) external; - - /// Designate the next call as an EIP-7702 transaction - function attachDelegation(SignedDelegation calldata signedDelegation) external; - - /// Designate the next call as an EIP-7702 transaction, with optional cross-chain validity. - function attachDelegation(SignedDelegation calldata signedDelegation, bool crossChain) external; - - /// Takes a signed transaction and broadcasts it to the network. - function broadcastRawTransaction(bytes calldata data) external; - - /// Has the next call (at this call depth only) create transactions that can later be signed and sent onchain. - /// Broadcasting address is determined by checking the following in order: - /// 1. If `--sender` argument was provided, that address is used. - /// 2. If exactly one signer (e.g. private key, hw wallet, keystore) is set when `forge broadcast` is invoked, that signer is used. - /// 3. Otherwise, default foundry sender (1804c8AB1F12E6bbf3894d4083f33e07309d1f38) is used. - 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; - - /// Returns addresses of available unlocked wallets in the script environment. - function getWallets() external returns (address[] memory wallets); - - /// Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction - function signAndAttachDelegation(address implementation, uint256 privateKey) - external - returns (SignedDelegation memory signedDelegation); - - /// Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction for specific nonce - function signAndAttachDelegation(address implementation, uint256 privateKey, uint64 nonce) - external - returns (SignedDelegation memory signedDelegation); - - /// Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction, with optional cross-chain validity. - function signAndAttachDelegation(address implementation, uint256 privateKey, bool crossChain) - external - returns (SignedDelegation memory signedDelegation); - - /// Sign an EIP-7702 authorization for delegation - function signDelegation(address implementation, uint256 privateKey) - external - returns (SignedDelegation memory signedDelegation); - - /// Sign an EIP-7702 authorization for delegation for specific nonce - function signDelegation(address implementation, uint256 privateKey, uint64 nonce) - external - returns (SignedDelegation memory signedDelegation); - - /// Sign an EIP-7702 authorization for delegation, with optional cross-chain validity. - function signDelegation(address implementation, uint256 privateKey, bool crossChain) - external - returns (SignedDelegation memory signedDelegation); - - /// Has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain. - /// Broadcasting address is determined by checking the following in order: - /// 1. If `--sender` argument was provided, that address is used. - /// 2. If exactly one signer (e.g. private key, hw wallet, keystore) is set when `forge broadcast` is invoked, that signer is used. - /// 3. Otherwise, default foundry sender (1804c8AB1F12E6bbf3894d4083f33e07309d1f38) is used. - 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; - - // ======== String ======== - - /// Returns true if `search` is found in `subject`, false otherwise. - function contains(string calldata subject, string calldata search) external returns (bool result); - - /// Returns the index of the first occurrence of a `key` in an `input` string. - /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `key` is not found. - /// Returns 0 in case of an empty `key`. - function indexOf(string calldata input, string calldata key) external pure returns (uint256); - - /// Parses the given `string` into an `address`. - function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue); - - /// Parses the given `string` into a `bool`. - function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue); - - /// Parses the given `string` into `bytes`. - function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue); - - /// Parses the given `string` into a `bytes32`. - function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue); - - /// Parses the given `string` into a `int256`. - function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue); - - /// Parses the given `string` into a `uint256`. - function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue); - - /// Replaces occurrences of `from` in the given `string` with `to`. - function replace(string calldata input, string calldata from, string calldata to) - external - pure - returns (string memory output); - - /// Splits the given `string` into an array of strings divided by the `delimiter`. - function split(string calldata input, string calldata delimiter) external pure returns (string[] memory outputs); - - /// Converts the given `string` value to Lowercase. - function toLowercase(string calldata input) external pure returns (string memory output); - - /// Converts the given value to a `string`. - function toString(address value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(bytes calldata value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(bytes32 value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(bool value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(uint256 value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(int256 value) external pure returns (string memory stringifiedValue); - - /// Converts the given `string` value to Uppercase. - function toUppercase(string calldata input) external pure returns (string memory output); - - /// Trims leading and trailing whitespace from the given `string` value. - function trim(string calldata input) external pure returns (string memory output); - - // ======== Testing ======== - - /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. - /// Formats values with decimals in failure message. - function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertApproxEqAbsDecimal( - uint256 left, - uint256 right, - uint256 maxDelta, - uint256 decimals, - string calldata error - ) external pure; - - /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. - /// Formats values with decimals in failure message. - function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertApproxEqAbsDecimal( - int256 left, - int256 right, - uint256 maxDelta, - uint256 decimals, - string calldata error - ) external pure; - - /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. - function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) external pure; - - /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. - /// Includes error message into revert string on failure. - function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string calldata error) external pure; - - /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. - function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) external pure; - - /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. - /// Includes error message into revert string on failure. - function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string calldata error) external pure; - - /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Formats values with decimals in failure message. - function assertApproxEqRelDecimal(uint256 left, uint256 right, uint256 maxPercentDelta, uint256 decimals) - external - pure; - - /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertApproxEqRelDecimal( - uint256 left, - uint256 right, - uint256 maxPercentDelta, - uint256 decimals, - string calldata error - ) external pure; - - /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Formats values with decimals in failure message. - function assertApproxEqRelDecimal(int256 left, int256 right, uint256 maxPercentDelta, uint256 decimals) - external - pure; - - /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertApproxEqRelDecimal( - int256 left, - int256 right, - uint256 maxPercentDelta, - uint256 decimals, - string calldata error - ) external pure; - - /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta) external pure; - - /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Includes error message into revert string on failure. - function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta, string calldata error) - external - pure; - - /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) external pure; - - /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Includes error message into revert string on failure. - function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta, string calldata error) - external - pure; - - /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message. - function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message. - /// Includes error message into revert string on failure. - function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Asserts that two `int256` values are equal, formatting them with decimals in failure message. - function assertEqDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Asserts that two `int256` values are equal, formatting them with decimals in failure message. - /// Includes error message into revert string on failure. - function assertEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Asserts that two `bool` values are equal. - function assertEq(bool left, bool right) external pure; - - /// Asserts that two `bool` values are equal and includes error message into revert string on failure. - function assertEq(bool left, bool right, string calldata error) external pure; - - /// Asserts that two `string` values are equal. - function assertEq(string calldata left, string calldata right) external pure; - - /// Asserts that two `string` values are equal and includes error message into revert string on failure. - function assertEq(string calldata left, string calldata right, string calldata error) external pure; - - /// Asserts that two `bytes` values are equal. - function assertEq(bytes calldata left, bytes calldata right) external pure; - - /// Asserts that two `bytes` values are equal and includes error message into revert string on failure. - function assertEq(bytes calldata left, bytes calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bool` values are equal. - function assertEq(bool[] calldata left, bool[] calldata right) external pure; - - /// Asserts that two arrays of `bool` values are equal and includes error message into revert string on failure. - function assertEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `uint256 values are equal. - function assertEq(uint256[] calldata left, uint256[] calldata right) external pure; - - /// Asserts that two arrays of `uint256` values are equal and includes error message into revert string on failure. - function assertEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `int256` values are equal. - function assertEq(int256[] calldata left, int256[] calldata right) external pure; - - /// Asserts that two arrays of `int256` values are equal and includes error message into revert string on failure. - function assertEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure; - - /// Asserts that two `uint256` values are equal. - function assertEq(uint256 left, uint256 right) external pure; - - /// Asserts that two arrays of `address` values are equal. - function assertEq(address[] calldata left, address[] calldata right) external pure; - - /// Asserts that two arrays of `address` values are equal and includes error message into revert string on failure. - function assertEq(address[] calldata left, address[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bytes32` values are equal. - function assertEq(bytes32[] calldata left, bytes32[] calldata right) external pure; - - /// Asserts that two arrays of `bytes32` values are equal and includes error message into revert string on failure. - function assertEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `string` values are equal. - function assertEq(string[] calldata left, string[] calldata right) external pure; - - /// Asserts that two arrays of `string` values are equal and includes error message into revert string on failure. - function assertEq(string[] calldata left, string[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bytes` values are equal. - function assertEq(bytes[] calldata left, bytes[] calldata right) external pure; - - /// Asserts that two arrays of `bytes` values are equal and includes error message into revert string on failure. - function assertEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure; - - /// Asserts that two `uint256` values are equal and includes error message into revert string on failure. - function assertEq(uint256 left, uint256 right, string calldata error) external pure; - - /// Asserts that two `int256` values are equal. - function assertEq(int256 left, int256 right) external pure; - - /// Asserts that two `int256` values are equal and includes error message into revert string on failure. - function assertEq(int256 left, int256 right, string calldata error) external pure; - - /// Asserts that two `address` values are equal. - function assertEq(address left, address right) external pure; - - /// Asserts that two `address` values are equal and includes error message into revert string on failure. - function assertEq(address left, address right, string calldata error) external pure; - - /// Asserts that two `bytes32` values are equal. - function assertEq(bytes32 left, bytes32 right) external pure; - - /// Asserts that two `bytes32` values are equal and includes error message into revert string on failure. - function assertEq(bytes32 left, bytes32 right, string calldata error) external pure; - - /// Asserts that the given condition is false. - function assertFalse(bool condition) external pure; - - /// Asserts that the given condition is false and includes error message into revert string on failure. - function assertFalse(bool condition, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than or equal to second. - /// Formats values with decimals in failure message. - function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than or equal to second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be greater than or equal to second. - /// Formats values with decimals in failure message. - function assertGeDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects first value to be greater than or equal to second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertGeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than or equal to second. - function assertGe(uint256 left, uint256 right) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than or equal to second. - /// Includes error message into revert string on failure. - function assertGe(uint256 left, uint256 right, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be greater than or equal to second. - function assertGe(int256 left, int256 right) external pure; - - /// Compares two `int256` values. Expects first value to be greater than or equal to second. - /// Includes error message into revert string on failure. - function assertGe(int256 left, int256 right, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than second. - /// Formats values with decimals in failure message. - function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be greater than second. - /// Formats values with decimals in failure message. - function assertGtDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects first value to be greater than second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertGtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than second. - function assertGt(uint256 left, uint256 right) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than second. - /// Includes error message into revert string on failure. - function assertGt(uint256 left, uint256 right, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be greater than second. - function assertGt(int256 left, int256 right) external pure; - - /// Compares two `int256` values. Expects first value to be greater than second. - /// Includes error message into revert string on failure. - function assertGt(int256 left, int256 right, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be less than or equal to second. - /// Formats values with decimals in failure message. - function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects first value to be less than or equal to second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be less than or equal to second. - /// Formats values with decimals in failure message. - function assertLeDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects first value to be less than or equal to second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertLeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be less than or equal to second. - function assertLe(uint256 left, uint256 right) external pure; - - /// Compares two `uint256` values. Expects first value to be less than or equal to second. - /// Includes error message into revert string on failure. - function assertLe(uint256 left, uint256 right, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be less than or equal to second. - function assertLe(int256 left, int256 right) external pure; - - /// Compares two `int256` values. Expects first value to be less than or equal to second. - /// Includes error message into revert string on failure. - function assertLe(int256 left, int256 right, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be less than second. - /// Formats values with decimals in failure message. - function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects first value to be less than second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be less than second. - /// Formats values with decimals in failure message. - function assertLtDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects first value to be less than second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertLtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be less than second. - function assertLt(uint256 left, uint256 right) external pure; - - /// Compares two `uint256` values. Expects first value to be less than second. - /// Includes error message into revert string on failure. - function assertLt(uint256 left, uint256 right, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be less than second. - function assertLt(int256 left, int256 right) external pure; - - /// Compares two `int256` values. Expects first value to be less than second. - /// Includes error message into revert string on failure. - function assertLt(int256 left, int256 right, string calldata error) external pure; - - /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message. - function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message. - /// Includes error message into revert string on failure. - function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message. - function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message. - /// Includes error message into revert string on failure. - function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Asserts that two `bool` values are not equal. - function assertNotEq(bool left, bool right) external pure; - - /// Asserts that two `bool` values are not equal and includes error message into revert string on failure. - function assertNotEq(bool left, bool right, string calldata error) external pure; - - /// Asserts that two `string` values are not equal. - function assertNotEq(string calldata left, string calldata right) external pure; - - /// Asserts that two `string` values are not equal and includes error message into revert string on failure. - function assertNotEq(string calldata left, string calldata right, string calldata error) external pure; - - /// Asserts that two `bytes` values are not equal. - function assertNotEq(bytes calldata left, bytes calldata right) external pure; - - /// Asserts that two `bytes` values are not equal and includes error message into revert string on failure. - function assertNotEq(bytes calldata left, bytes calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bool` values are not equal. - function assertNotEq(bool[] calldata left, bool[] calldata right) external pure; - - /// Asserts that two arrays of `bool` values are not equal and includes error message into revert string on failure. - function assertNotEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `uint256` values are not equal. - function assertNotEq(uint256[] calldata left, uint256[] calldata right) external pure; - - /// Asserts that two arrays of `uint256` values are not equal and includes error message into revert string on failure. - function assertNotEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `int256` values are not equal. - function assertNotEq(int256[] calldata left, int256[] calldata right) external pure; - - /// Asserts that two arrays of `int256` values are not equal and includes error message into revert string on failure. - function assertNotEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure; - - /// Asserts that two `uint256` values are not equal. - function assertNotEq(uint256 left, uint256 right) external pure; - - /// Asserts that two arrays of `address` values are not equal. - function assertNotEq(address[] calldata left, address[] calldata right) external pure; - - /// Asserts that two arrays of `address` values are not equal and includes error message into revert string on failure. - function assertNotEq(address[] calldata left, address[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bytes32` values are not equal. - function assertNotEq(bytes32[] calldata left, bytes32[] calldata right) external pure; - - /// Asserts that two arrays of `bytes32` values are not equal and includes error message into revert string on failure. - function assertNotEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `string` values are not equal. - function assertNotEq(string[] calldata left, string[] calldata right) external pure; - - /// Asserts that two arrays of `string` values are not equal and includes error message into revert string on failure. - function assertNotEq(string[] calldata left, string[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bytes` values are not equal. - function assertNotEq(bytes[] calldata left, bytes[] calldata right) external pure; - - /// Asserts that two arrays of `bytes` values are not equal and includes error message into revert string on failure. - function assertNotEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure; - - /// Asserts that two `uint256` values are not equal and includes error message into revert string on failure. - function assertNotEq(uint256 left, uint256 right, string calldata error) external pure; - - /// Asserts that two `int256` values are not equal. - function assertNotEq(int256 left, int256 right) external pure; - - /// Asserts that two `int256` values are not equal and includes error message into revert string on failure. - function assertNotEq(int256 left, int256 right, string calldata error) external pure; - - /// Asserts that two `address` values are not equal. - function assertNotEq(address left, address right) external pure; - - /// Asserts that two `address` values are not equal and includes error message into revert string on failure. - function assertNotEq(address left, address right, string calldata error) external pure; - - /// Asserts that two `bytes32` values are not equal. - function assertNotEq(bytes32 left, bytes32 right) external pure; - - /// Asserts that two `bytes32` values are not equal and includes error message into revert string on failure. - function assertNotEq(bytes32 left, bytes32 right, string calldata error) external pure; - - /// Asserts that the given condition is true. - function assertTrue(bool condition) external pure; - - /// Asserts that the given condition is true and includes error message into revert string on failure. - function assertTrue(bool condition, string calldata error) external pure; - - /// If the condition is false, discard this run's fuzz inputs and generate new ones. - function assume(bool condition) external pure; - - /// Discard this run's fuzz inputs and generate new ones if next call reverted. - function assumeNoRevert() external pure; - - /// Discard this run's fuzz inputs and generate new ones if next call reverts with the potential revert parameters. - function assumeNoRevert(PotentialRevert calldata potentialRevert) external pure; - - /// Discard this run's fuzz inputs and generate new ones if next call reverts with the any of the potential revert parameters. - function assumeNoRevert(PotentialRevert[] calldata potentialReverts) external pure; - - /// Writes a breakpoint to jump to in the debugger. - function breakpoint(string calldata char) external pure; - - /// Writes a conditional breakpoint to jump to in the debugger. - function breakpoint(string calldata char, bool value) external pure; - - /// Returns true if the current Foundry version is greater than or equal to the given version. - /// The given version string must be in the format `major.minor.patch`. - /// This is equivalent to `foundryVersionCmp(version) >= 0`. - function foundryVersionAtLeast(string calldata version) external view returns (bool); - - /// Compares the current Foundry version with the given version string. - /// The given version string must be in the format `major.minor.patch`. - /// Returns: - /// -1 if current Foundry version is less than the given version - /// 0 if current Foundry version equals the given version - /// 1 if current Foundry version is greater than the given version - /// This result can then be used with a comparison operator against `0`. - /// For example, to check if the current Foundry version is greater than or equal to `1.0.0`: - /// `if (foundryVersionCmp("1.0.0") >= 0) { ... }` - function foundryVersionCmp(string calldata version) external view returns (int256); - - /// Returns a Chain struct for specific alias - function getChain(string calldata chainAlias) external view returns (Chain memory chain); - - /// Returns a Chain struct for specific chainId - function getChain(uint256 chainId) external view returns (Chain memory chain); - - /// Returns the Foundry version. - /// Format: -+.. - /// Sample output: 0.3.0-nightly+3cb96bde9b.1737036656.debug - /// Note: Build timestamps may vary slightly across platforms due to separate CI jobs. - /// For reliable version comparisons, use UNIX format (e.g., >= 1700000000) - /// to compare timestamps while ignoring minor time differences. - function getFoundryVersion() external view returns (string memory version); - - /// 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 as structs. - function rpcUrlStructs() external view returns (Rpc[] memory urls); - - /// Returns all rpc urls and their aliases `[alias, url][]`. - function rpcUrls() external view returns (string[2][] memory urls); - - /// Suspends execution of the main thread for `duration` milliseconds. - function sleep(uint256 duration) external; - - // ======== Toml ======== - - /// Checks if `key` exists in a TOML table. - function keyExistsToml(string calldata toml, string calldata key) external view returns (bool); - - /// Parses a string of TOML data at `key` and coerces it to `address`. - function parseTomlAddress(string calldata toml, string calldata key) external pure returns (address); - - /// Parses a string of TOML data at `key` and coerces it to `address[]`. - function parseTomlAddressArray(string calldata toml, string calldata key) - external - pure - returns (address[] memory); - - /// Parses a string of TOML data at `key` and coerces it to `bool`. - function parseTomlBool(string calldata toml, string calldata key) external pure returns (bool); - - /// Parses a string of TOML data at `key` and coerces it to `bool[]`. - function parseTomlBoolArray(string calldata toml, string calldata key) external pure returns (bool[] memory); - - /// Parses a string of TOML data at `key` and coerces it to `bytes`. - function parseTomlBytes(string calldata toml, string calldata key) external pure returns (bytes memory); - - /// Parses a string of TOML data at `key` and coerces it to `bytes32`. - function parseTomlBytes32(string calldata toml, string calldata key) external pure returns (bytes32); - - /// Parses a string of TOML data at `key` and coerces it to `bytes32[]`. - function parseTomlBytes32Array(string calldata toml, string calldata key) - external - pure - returns (bytes32[] memory); - - /// Parses a string of TOML data at `key` and coerces it to `bytes[]`. - function parseTomlBytesArray(string calldata toml, string calldata key) external pure returns (bytes[] memory); - - /// Parses a string of TOML data at `key` and coerces it to `int256`. - function parseTomlInt(string calldata toml, string calldata key) external pure returns (int256); - - /// Parses a string of TOML data at `key` and coerces it to `int256[]`. - function parseTomlIntArray(string calldata toml, string calldata key) external pure returns (int256[] memory); - - /// Returns an array of all the keys in a TOML table. - function parseTomlKeys(string calldata toml, string calldata key) external pure returns (string[] memory keys); - - /// Parses a string of TOML data at `key` and coerces it to `string`. - function parseTomlString(string calldata toml, string calldata key) external pure returns (string memory); - - /// Parses a string of TOML data at `key` and coerces it to `string[]`. - function parseTomlStringArray(string calldata toml, string calldata key) external pure returns (string[] memory); - - /// Parses a string of TOML data at `key` and coerces it to type array corresponding to `typeDescription`. - function parseTomlTypeArray(string calldata toml, string calldata key, string calldata typeDescription) - external - pure - returns (bytes memory); - - /// Parses a string of TOML data and coerces it to type corresponding to `typeDescription`. - function parseTomlType(string calldata toml, string calldata typeDescription) - external - pure - returns (bytes memory); - - /// Parses a string of TOML data at `key` and coerces it to type corresponding to `typeDescription`. - function parseTomlType(string calldata toml, string calldata key, string calldata typeDescription) - external - pure - returns (bytes memory); - - /// Parses a string of TOML data at `key` and coerces it to `uint256`. - function parseTomlUint(string calldata toml, string calldata key) external pure returns (uint256); - - /// Parses a string of TOML data at `key` and coerces it to `uint256[]`. - function parseTomlUintArray(string calldata toml, string calldata key) external pure returns (uint256[] memory); - - /// ABI-encodes a TOML table. - function parseToml(string calldata toml) external pure returns (bytes memory abiEncodedData); - - /// ABI-encodes a TOML table at `key`. - function parseToml(string calldata toml, string calldata key) external pure returns (bytes memory abiEncodedData); - - /// Takes serialized JSON, converts to TOML and write a serialized TOML to a file. - function writeToml(string calldata json, string calldata path) external; - - /// Takes serialized JSON, converts to TOML and write a serialized TOML table to an **existing** TOML file, replacing a value with key = - /// This is useful to replace a specific value of a TOML file, without having to parse the entire thing. - function writeToml(string calldata json, string calldata path, string calldata valueKey) external; - - // ======== Utilities ======== - - /// Compute the address of a contract created with CREATE2 using the given CREATE2 deployer. - function computeCreate2Address(bytes32 salt, bytes32 initCodeHash, address deployer) - external - pure - returns (address); - - /// Compute the address of a contract created with CREATE2 using the default CREATE2 deployer. - function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) external pure returns (address); - - /// Compute the address a contract will be deployed at for a given deployer address and nonce. - function computeCreateAddress(address deployer, uint256 nonce) external pure returns (address); - - /// Utility cheatcode to copy storage of `from` contract to another `to` contract. - function copyStorage(address from, address to) external; - - /// Generates the struct hash of the canonical EIP-712 type representation and its abi-encoded data. - /// Supports 2 different inputs: - /// 1. Name of the type (i.e. "PermitSingle"): - /// * requires previous binding generation with `forge bind-json`. - /// * bindings will be retrieved from the path configured in `foundry.toml`. - /// 2. String representation of the type (i.e. "Foo(Bar bar) Bar(uint256 baz)"). - /// * Note: the cheatcode will use the canonical type even if the input is malformated - /// with the wrong order of elements or with extra whitespaces. - function eip712HashStruct(string calldata typeNameOrDefinition, bytes calldata abiEncodedData) - external - pure - returns (bytes32 typeHash); - - /// Generates the struct hash of the canonical EIP-712 type representation and its abi-encoded data. - /// Requires previous binding generation with `forge bind-json`. - /// Params: - /// * `bindingsPath`: path where the output of `forge bind-json` is stored. - /// * `typeName`: Name of the type (i.e. "PermitSingle"). - /// * `abiEncodedData`: ABI-encoded data for the struct that is being hashed. - function eip712HashStruct(string calldata bindingsPath, string calldata typeName, bytes calldata abiEncodedData) - external - pure - returns (bytes32 typeHash); - - /// Generates the hash of the canonical EIP-712 type representation. - /// Supports 2 different inputs: - /// 1. Name of the type (i.e. "Transaction"): - /// * requires previous binding generation with `forge bind-json`. - /// * bindings will be retrieved from the path configured in `foundry.toml`. - /// 2. String representation of the type (i.e. "Foo(Bar bar) Bar(uint256 baz)"). - /// * Note: the cheatcode will output the canonical type even if the input is malformated - /// with the wrong order of elements or with extra whitespaces. - function eip712HashType(string calldata typeNameOrDefinition) external pure returns (bytes32 typeHash); - - /// Generates the hash of the canonical EIP-712 type representation. - /// Requires previous binding generation with `forge bind-json`. - /// Params: - /// * `bindingsPath`: path where the output of `forge bind-json` is stored. - /// * `typeName`: Name of the type (i.e. "Transaction"). - function eip712HashType(string calldata bindingsPath, string calldata typeName) - external - pure - returns (bytes32 typeHash); - - /// Generates a ready-to-sign digest of human-readable typed data following the EIP-712 standard. - function eip712HashTypedData(string calldata jsonData) external pure returns (bytes32 digest); - - /// Returns ENS namehash for provided string. - function ensNamehash(string calldata name) external pure returns (bytes32); - - /// Gets the label for the specified address. - function getLabel(address account) external view returns (string memory currentLabel); - - /// Labels an address in call traces. - function label(address account, string calldata newLabel) external; - - /// Pauses collection of call traces. Useful in cases when you want to skip tracing of - /// complex calls which are not useful for debugging. - function pauseTracing() external view; - - /// Returns a random `address`. - function randomAddress() external view returns (address); - - /// Returns a random `bool`. - function randomBool() external view returns (bool); - - /// Returns a random byte array value of the given length. - function randomBytes(uint256 len) external view returns (bytes memory); - - /// Returns a random fixed-size byte array of length 4. - function randomBytes4() external view returns (bytes4); - - /// Returns a random fixed-size byte array of length 8. - function randomBytes8() external view returns (bytes8); - - /// Returns a random `int256` value. - function randomInt() external view returns (int256); - - /// Returns a random `int256` value of given bits. - function randomInt(uint256 bits) external view returns (int256); - - /// Returns a random uint256 value. - function randomUint() external view returns (uint256); - - /// Returns random uint256 value between the provided range (=min..=max). - function randomUint(uint256 min, uint256 max) external view returns (uint256); - - /// Returns a random `uint256` value of given bits. - function randomUint(uint256 bits) external view returns (uint256); - - /// Unpauses collection of call traces. - function resumeTracing() external view; - - /// Utility cheatcode to set arbitrary storage for given target address. - function setArbitraryStorage(address target) external; - - /// Utility cheatcode to set arbitrary storage for given target address and overwrite - /// any storage slots that have been previously set. - function setArbitraryStorage(address target, bool overwrite) external; - - /// Set RNG seed. - function setSeed(uint256 seed) external; - - /// Randomly shuffles an array. - function shuffle(uint256[] calldata array) external returns (uint256[] memory); - - /// Sorts an array in ascending order. - function sort(uint256[] calldata array) external returns (uint256[] memory); - - /// Encodes a `bytes` value to a base64url string. - function toBase64URL(bytes calldata data) external pure returns (string memory); - - /// Encodes a `string` value to a base64url string. - function toBase64URL(string calldata data) external pure returns (string memory); - - /// Encodes a `bytes` value to a base64 string. - function toBase64(bytes calldata data) external pure returns (string memory); - - /// Encodes a `string` value to a base64 string. - function toBase64(string calldata data) external pure returns (string memory); -} - -/// 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 ======== - - /// Utility cheatcode to set an EIP-2930 access list for all subsequent transactions. - function accessList(AccessListItem[] calldata access) external; - - /// Returns the identifier of the currently active fork. Reverts if no fork is currently active. - function activeFork() external view returns (uint256 forkId); - - /// In forking mode, explicitly grant the given address cheatcode access. - function allowCheatcodes(address account) external; - - /// Sets `block.blobbasefee` - function blobBaseFee(uint256 newBlobBaseFee) external; - - /// Sets the blobhashes in the transaction. - /// Not available on EVM versions before Cancun. - /// If used on unsupported EVM versions it will revert. - function blobhashes(bytes32[] calldata hashes) external; - - /// Sets `block.chainid`. - function chainId(uint256 newChainId) external; - - /// Clears all mocked calls. - function clearMockedCalls() external; - - /// Clones a source account code, state, balance and nonce to a target account and updates in-memory EVM state. - function cloneAccount(address source, address target) external; - - /// Sets `block.coinbase`. - function coinbase(address newCoinbase) external; - - /// Marks the slots of an account and the account address as cold. - function cool(address target) external; - - /// Utility cheatcode to mark specific storage slot as cold, simulating no prior read. - function coolSlot(address target, bytes32 slot) external; - - /// 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 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 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 the latest block and returns the identifier of the fork. - function createSelectFork(string calldata urlOrAlias) 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); - - /// Sets an address' balance. - function deal(address account, uint256 newBalance) external; - - /// Removes the snapshot with the given ID created by `snapshot`. - /// Takes the snapshot ID to delete. - /// Returns `true` if the snapshot was successfully deleted. - /// Returns `false` if the snapshot does not exist. - function deleteStateSnapshot(uint256 snapshotId) external returns (bool success); - - /// Removes _all_ snapshots previously created by `snapshot`. - function deleteStateSnapshots() external; - - /// Sets `block.difficulty`. - /// Not available on EVM versions from Paris onwards. Use `prevrandao` instead. - /// Reverts if used on unsupported EVM versions. - function difficulty(uint256 newDifficulty) external; - - /// Dump a genesis JSON file's `allocs` to disk. - function dumpState(string calldata pathToStateJson) external; - - /// Sets an address' code. - function etch(address target, bytes calldata newRuntimeBytecode) external; - - /// Sets `block.basefee`. - function fee(uint256 newBasefee) external; - - /// Gets the blockhashes from the current transaction. - /// Not available on EVM versions before Cancun. - /// If used on unsupported EVM versions it will revert. - function getBlobhashes() external view returns (bytes32[] memory hashes); - - /// Returns true if the account is marked as persistent. - function isPersistent(address account) external view returns (bool persistent); - - /// Load a genesis JSON file's `allocs` into the in-memory EVM state. - function loadAllocs(string calldata pathToAllocsJson) 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; - - /// See `makePersistent(address)`. - function makePersistent(address account0, address account1) external; - - /// See `makePersistent(address)`. - function makePersistent(address account0, address account1, address account2) external; - - /// See `makePersistent(address)`. - function makePersistent(address[] calldata accounts) 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; - - /// Reverts a call to an address with specified revert data. - /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. - function mockCallRevert(address callee, bytes4 data, bytes calldata revertData) external; - - /// Reverts a call to an address with a specific `msg.value`, with specified revert data. - /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. - function mockCallRevert(address callee, uint256 msgValue, bytes4 data, bytes calldata revertData) 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; - - /// 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. - /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. - function mockCall(address callee, bytes4 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. - /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. - function mockCall(address callee, uint256 msgValue, bytes4 data, bytes calldata returnData) external; - - /// Mocks multiple calls to an address, returning specified data for each call. - function mockCalls(address callee, bytes calldata data, bytes[] calldata returnData) external; - - /// Mocks multiple calls to an address with a specific `msg.value`, returning specified data for each call. - function mockCalls(address callee, uint256 msgValue, bytes calldata data, bytes[] calldata returnData) external; - - /// Whenever a call is made to `callee` with calldata `data`, this cheatcode instead calls - /// `target` with the same calldata. This functionality is similar to a delegate call made to - /// `target` contract from `callee`. - /// Can be used to substitute a call to a function with another implementation that captures - /// the primary logic of the original function but is easier to reason about. - /// If calldata is not a strict match then partial match by selector is attempted. - function mockFunction(address callee, address target, bytes calldata data) external; - - /// Utility cheatcode to remove any EIP-2930 access list set by `accessList` cheatcode. - function noAccessList() external; - - /// Sets the *next* call's `msg.sender` to be the input address. - function prank(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 the *next* delegate call's `msg.sender` to be the input address. - function prank(address msgSender, bool delegateCall) external; - - /// Sets the *next* delegate call's `msg.sender` to be the input address, and the `tx.origin` to be the second input. - function prank(address msgSender, address txOrigin, bool delegateCall) 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.prevrandao`. - /// Not available on EVM versions before Paris. Use `difficulty` instead. - /// If used on unsupported EVM versions it will revert. - function prevrandao(uint256 newPrevrandao) 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); - - /// Resets the nonce of an account to 0 for EOAs and 1 for contract accounts. - function resetNonce(address account) external; - - /// Revert the state of the EVM to a previous snapshot - /// Takes the snapshot ID to revert to. - /// Returns `true` if the snapshot was successfully reverted. - /// Returns `false` if the snapshot does not exist. - /// **Note:** This does not automatically delete the snapshot. To delete the snapshot use `deleteStateSnapshot`. - function revertToState(uint256 snapshotId) external returns (bool success); - - /// Revert the state of the EVM to a previous snapshot and automatically deletes the snapshots - /// Takes the snapshot ID to revert to. - /// Returns `true` if the snapshot was successfully reverted and deleted. - /// Returns `false` if the snapshot does not exist. - function revertToStateAndDelete(uint256 snapshotId) external returns (bool success); - - /// Revokes persistent status from the address, previously added via `makePersistent`. - function revokePersistent(address account) external; - - /// See `revokePersistent(address)`. - function revokePersistent(address[] calldata accounts) external; - - /// Sets `block.height`. - function roll(uint256 newHeight) external; - - /// 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; - - /// Set blockhash for the current block. - /// It only sets the blockhash for blocks where `block.number - 256 <= number < block.number`. - function setBlockhash(uint256 blockNumber, bytes32 blockHash) 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; - - /// Snapshot capture the gas usage of the last call by name from the callee perspective. - function snapshotGasLastCall(string calldata name) external returns (uint256 gasUsed); - - /// Snapshot capture the gas usage of the last call by name in a group from the callee perspective. - function snapshotGasLastCall(string calldata group, string calldata name) external returns (uint256 gasUsed); - - /// Snapshot the current state of the evm. - /// Returns the ID of the snapshot that was created. - /// To revert a snapshot use `revertToState`. - function snapshotState() external returns (uint256 snapshotId); - - /// Snapshot capture an arbitrary numerical value by name. - /// The group name is derived from the contract name. - function snapshotValue(string calldata name, uint256 value) external; - - /// Snapshot capture an arbitrary numerical value by name in a group. - function snapshotValue(string calldata group, string calldata name, uint256 value) external; - - /// Sets all subsequent calls' `msg.sender` to be the input address until `stopPrank` is called. - function startPrank(address msgSender) 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; - - /// Sets all subsequent delegate calls' `msg.sender` to be the input address until `stopPrank` is called. - function startPrank(address msgSender, bool delegateCall) external; - - /// Sets all subsequent delegate 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, bool delegateCall) external; - - /// Start a snapshot capture of the current gas usage by name. - /// The group name is derived from the contract name. - function startSnapshotGas(string calldata name) external; - - /// Start a snapshot capture of the current gas usage by name in a group. - function startSnapshotGas(string calldata group, string calldata name) external; - - /// Resets subsequent calls' `msg.sender` to be `address(this)`. - function stopPrank() external; - - /// Stop the snapshot capture of the current gas by latest snapshot name, capturing the gas used since the start. - function stopSnapshotGas() external returns (uint256 gasUsed); - - /// Stop the snapshot capture of the current gas usage by name, capturing the gas used since the start. - /// The group name is derived from the contract name. - function stopSnapshotGas(string calldata name) external returns (uint256 gasUsed); - - /// Stop the snapshot capture of the current gas usage by name in a group, capturing the gas used since the start. - function stopSnapshotGas(string calldata group, string calldata name) external returns (uint256 gasUsed); - - /// Stores a value to an address' storage slot. - function store(address target, bytes32 slot, bytes32 value) 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; - - /// Sets `tx.gasprice`. - function txGasPrice(uint256 newGasPrice) external; - - /// Utility cheatcode to mark specific storage slot as warm, simulating a prior read. - function warmSlot(address target, bytes32 slot) external; - - /// Sets `block.timestamp`. - function warp(uint256 newTimestamp) external; - - /// `deleteSnapshot` is being deprecated in favor of `deleteStateSnapshot`. It will be removed in future versions. - function deleteSnapshot(uint256 snapshotId) external returns (bool success); - - /// `deleteSnapshots` is being deprecated in favor of `deleteStateSnapshots`. It will be removed in future versions. - function deleteSnapshots() external; - - /// `revertToAndDelete` is being deprecated in favor of `revertToStateAndDelete`. It will be removed in future versions. - function revertToAndDelete(uint256 snapshotId) external returns (bool success); - - /// `revertTo` is being deprecated in favor of `revertToState`. It will be removed in future versions. - function revertTo(uint256 snapshotId) external returns (bool success); - - /// `snapshot` is being deprecated in favor of `snapshotState`. It will be removed in future versions. - function snapshot() external returns (uint256 snapshotId); - - // ======== Testing ======== - - /// 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; - - /// 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; - - /// Expects the deployment of the specified bytecode by the specified address using the CREATE opcode - function expectCreate(bytes calldata bytecode, address deployer) external; - - /// Expects the deployment of the specified bytecode by the specified address using the CREATE2 opcode - function expectCreate2(bytes calldata bytecode, address deployer) external; - - /// Prepare an expected anonymous log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData.). - /// Call this function, then emit an anonymous 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 expectEmitAnonymous(bool checkTopic0, bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) - external; - - /// Same as the previous method, but also checks supplied address against emitting contract. - function expectEmitAnonymous( - bool checkTopic0, - bool checkTopic1, - bool checkTopic2, - bool checkTopic3, - bool checkData, - address emitter - ) external; - - /// Prepare an expected anonymous log with all topic and data checks enabled. - /// Call this function, then emit an anonymous 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 expectEmitAnonymous() external; - - /// Same as the previous method, but also checks supplied address against emitting contract. - function expectEmitAnonymous(address emitter) 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; - - /// Expect a given number of logs with the provided topics. - function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, uint64 count) external; - - /// Expect a given number of logs from a specific emitter with the provided topics. - function expectEmit( - bool checkTopic1, - bool checkTopic2, - bool checkTopic3, - bool checkData, - address emitter, - uint64 count - ) external; - - /// Expect a given number of logs with all topic and data checks enabled. - function expectEmit(uint64 count) external; - - /// Expect a given number of logs from a specific emitter with all topic and data checks enabled. - function expectEmit(address emitter, uint64 count) external; - - /// Expects an error on next call that starts with the revert data. - function expectPartialRevert(bytes4 revertData) external; - - /// Expects an error on next call to reverter address, that starts with the revert data. - function expectPartialRevert(bytes4 revertData, address reverter) external; - - /// Expects an error on next call with any revert data. - function expectRevert() external; - - /// Expects an error on next call that exactly matches the revert data. - function expectRevert(bytes4 revertData) external; - - /// Expects a `count` number of reverts from the upcoming calls from the reverter address that match the revert data. - function expectRevert(bytes4 revertData, address reverter, uint64 count) external; - - /// Expects a `count` number of reverts from the upcoming calls from the reverter address that exactly match the revert data. - function expectRevert(bytes calldata revertData, address reverter, uint64 count) external; - - /// Expects an error on next call that exactly matches the revert data. - function expectRevert(bytes calldata revertData) external; - - /// Expects an error with any revert data on next call to reverter address. - function expectRevert(address reverter) external; - - /// Expects an error from reverter address on next call, with any revert data. - function expectRevert(bytes4 revertData, address reverter) external; - - /// Expects an error from reverter address on next call, that exactly matches the revert data. - function expectRevert(bytes calldata revertData, address reverter) external; - - /// Expects a `count` number of reverts from the upcoming calls with any revert data or reverter. - function expectRevert(uint64 count) external; - - /// Expects a `count` number of reverts from the upcoming calls that match the revert data. - function expectRevert(bytes4 revertData, uint64 count) external; - - /// Expects a `count` number of reverts from the upcoming calls that exactly match the revert data. - function expectRevert(bytes calldata revertData, uint64 count) external; - - /// Expects a `count` number of reverts from the upcoming calls from the reverter address. - function expectRevert(address reverter, uint64 count) 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 level of a test. - function skip(bool skipTest) external; - - /// Marks a test as skipped with a reason. Must be called at the top level of a test. - function skip(bool skipTest, string calldata reason) external; - - /// Stops all safe memory expectation in the current subcontext. - function stopExpectSafeMemory() external; - - // ======== Utilities ======== - - /// Causes the next contract creation (via new) to fail and return its initcode in the returndata buffer. - /// This allows type-safe access to the initcode payload that would be used for contract creation. - /// Example usage: - /// vm.interceptInitcode(); - /// bytes memory initcode; - /// try new MyContract(param1, param2) { assert(false); } - /// catch (bytes memory interceptedInitcode) { initcode = interceptedInitcode; } - function interceptInitcode() external; -} diff --git a/typescript/packages/account-modules/lib/forge-std/src/console.sol b/typescript/packages/account-modules/lib/forge-std/src/console.sol deleted file mode 100644 index 4fdb667..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/console.sol +++ /dev/null @@ -1,1560 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.4.22 <0.9.0; - -library console { - address constant CONSOLE_ADDRESS = - 0x000000000000000000636F6e736F6c652e6c6f67; - - function _sendLogPayloadImplementation(bytes memory payload) internal view { - address consoleAddress = CONSOLE_ADDRESS; - /// @solidity memory-safe-assembly - assembly { - pop( - staticcall( - gas(), - consoleAddress, - add(payload, 32), - mload(payload), - 0, - 0 - ) - ) - } - } - - function _castToPure( - function(bytes memory) internal view fnIn - ) internal pure returns (function(bytes memory) pure fnOut) { - assembly { - fnOut := fnIn - } - } - - function _sendLogPayload(bytes memory payload) internal pure { - _castToPure(_sendLogPayloadImplementation)(payload); - } - - 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)); - } -} diff --git a/typescript/packages/account-modules/lib/forge-std/src/console2.sol b/typescript/packages/account-modules/lib/forge-std/src/console2.sol deleted file mode 100644 index 03531d9..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/console2.sol +++ /dev/null @@ -1,4 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.4.22 <0.9.0; - -import {console as console2} from "./console.sol"; diff --git a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC1155.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC1155.sol deleted file mode 100644 index ffc8298..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC1155.sol +++ /dev/null @@ -1,105 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2; - -import {IERC165} from "./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/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC165.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC165.sol deleted file mode 100644 index 9af4bf8..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC165.sol +++ /dev/null @@ -1,12 +0,0 @@ -// 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/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC20.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC20.sol deleted file mode 100644 index ba40806..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC20.sol +++ /dev/null @@ -1,43 +0,0 @@ -// 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/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC4626.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC4626.sol deleted file mode 100644 index c645a0f..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC4626.sol +++ /dev/null @@ -1,190 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2; - -import {IERC20} from "./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 withdrawal 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 withdrawal. - /// - 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/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC6909.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC6909.sol deleted file mode 100644 index 6e11cb4..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC6909.sol +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2; - -import {IERC165} from "./IERC165.sol"; - -/// @dev Required interface of an ERC-6909 compliant contract, as defined in -/// https://eips.ethereum.org/EIPS/eip-6909 -interface IERC6909 is IERC165 { - /// @dev Emitted when the allowance of a `spender` for an `owner` is set for a token of type `id`. - event Approval(address indexed owner, address indexed spender, uint256 indexed id, uint256 amount); - - /// @dev Emitted when `owner` grants or revokes operator status for a `spender`. - event OperatorSet(address indexed owner, address indexed spender, bool approved); - - /// @dev Emitted when `amount` tokens of type `id` are moved from `sender` to `receiver` initiated by `caller`. - event Transfer( - address caller, address indexed sender, address indexed receiver, uint256 indexed id, uint256 amount - ); - - ///@dev Returns the amount of tokens of type `id` owned by `owner`. - function balanceOf(address owner, uint256 id) external view returns (uint256); - - /// @dev Returns the amount of tokens of type `id` that `spender` is allowed to spend on behalf of `owner`. - /// NOTE: Does not include operator allowances. - function allowance(address owner, address spender, uint256 id) external view returns (uint256); - - /// @dev Returns true if `spender` is set as an operator for `owner`. - function isOperator(address owner, address spender) external view returns (bool); - - /// @dev Sets an approval to `spender` for `amount` tokens of type `id` from the caller's tokens. - /// Must return true. - function approve(address spender, uint256 id, uint256 amount) external returns (bool); - - /// @dev Grants or revokes unlimited transfer permission of any token id to `spender` for the caller's tokens. - /// Must return true. - function setOperator(address spender, bool approved) external returns (bool); - - /// @dev Transfers `amount` of token type `id` from the caller's account to `receiver`. - /// Must return true. - function transfer(address receiver, uint256 id, uint256 amount) external returns (bool); - - /// @dev Transfers `amount` of token type `id` from `sender` to `receiver`. - /// Must return true. - function transferFrom(address sender, address receiver, uint256 id, uint256 amount) external returns (bool); -} - -/// @dev Optional extension of {IERC6909} that adds metadata functions. -interface IERC6909Metadata is IERC6909 { - /// @dev Returns the name of the token of type `id`. - function name(uint256 id) external view returns (string memory); - - /// @dev Returns the ticker symbol of the token of type `id`. - function symbol(uint256 id) external view returns (string memory); - - /// @dev Returns the number of decimals for the token of type `id`. - function decimals(uint256 id) external view returns (uint8); -} - -/// @dev Optional extension of {IERC6909} that adds content URI functions. -interface IERC6909ContentURI is IERC6909 { - /// @dev Returns URI for the contract. - function contractURI() external view returns (string memory); - - /// @dev Returns the URI for the token of type `id`. - function tokenURI(uint256 id) external view returns (string memory); -} - -/// @dev Optional extension of {IERC6909} that adds a token supply function. -interface IERC6909TokenSupply is IERC6909 { - /// @dev Returns the total supply of the token of type `id`. - function totalSupply(uint256 id) external view returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC721.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC721.sol deleted file mode 100644 index 21a4a94..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC721.sol +++ /dev/null @@ -1,164 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2; - -import {IERC165} from "./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/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7540.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7540.sol deleted file mode 100644 index 91a38ca..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7540.sol +++ /dev/null @@ -1,150 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2; - -import {IERC7575} from "./IERC7575.sol"; - -/// @dev Interface of the base operator logic of ERC7540, as defined in -/// https://eips.ethereum.org/EIPS/eip-7540 -interface IERC7540Operator { - /** - * @dev The event emitted when an operator is set. - * - * @param controller The address of the controller. - * @param operator The address of the operator. - * @param approved The approval status. - */ - event OperatorSet(address indexed controller, address indexed operator, bool approved); - - /** - * @dev Sets or removes an operator for the caller. - * - * @param operator The address of the operator. - * @param approved The approval status. - * @return Whether the call was executed successfully or not - */ - function setOperator(address operator, bool approved) external returns (bool); - - /** - * @dev Returns `true` if the `operator` is approved as an operator for an `controller`. - * - * @param controller The address of the controller. - * @param operator The address of the operator. - * @return status The approval status - */ - function isOperator(address controller, address operator) external view returns (bool status); -} - -/// @dev Interface of the asynchronous deposit Vault interface of ERC7540, as defined in -/// https://eips.ethereum.org/EIPS/eip-7540 -interface IERC7540Deposit is IERC7540Operator { - event DepositRequest( - address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets - ); - /** - * @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit. - * - * - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow. - * - MUST revert if all of assets cannot be requested for deposit. - * - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller, - * approval of ERC-20 tokens from owner to sender is NOT enough. - * - * @param assets the amount of deposit assets to transfer from owner - * @param controller the controller of the request who will be able to operate the request - * @param owner the source of the deposit assets - * - * NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token. - */ - - function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId); - - /** - * @dev Returns the amount of requested assets in Pending state. - * - * - MUST NOT include any assets in Claimable state for deposit or mint. - * - MUST NOT show any variations depending on the caller. - * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input. - */ - function pendingDepositRequest(uint256 requestId, address controller) - external - view - returns (uint256 pendingAssets); - - /** - * @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint. - * - * - MUST NOT include any assets in Pending state. - * - MUST NOT show any variations depending on the caller. - * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input. - */ - function claimableDepositRequest(uint256 requestId, address controller) - external - view - returns (uint256 claimableAssets); - - /** - * @dev Mints shares Vault shares to receiver by claiming the Request of the controller. - * - * - MUST emit the Deposit event. - * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator. - */ - function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares); - - /** - * @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller. - * - * - MUST emit the Deposit event. - * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator. - */ - function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets); -} - -/// @dev Interface of the asynchronous deposit Vault interface of ERC7540, as defined in -/// https://eips.ethereum.org/EIPS/eip-7540 -interface IERC7540Redeem is IERC7540Operator { - event RedeemRequest( - address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets - ); - - /** - * @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem. - * - * - MUST support a redeem Request flow where the control of shares is taken from sender directly - * where msg.sender has ERC-20 approval over the shares of owner. - * - MUST revert if all of shares cannot be requested for redeem. - * - * @param shares the amount of shares to be redeemed to transfer from owner - * @param controller the controller of the request who will be able to operate the request - * @param owner the source of the shares to be redeemed - * - * NOTE: most implementations will require pre-approval of the Vault with the Vault's share token. - */ - function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId); - - /** - * @dev Returns the amount of requested shares in Pending state. - * - * - MUST NOT include any shares in Claimable state for redeem or withdraw. - * - MUST NOT show any variations depending on the caller. - * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input. - */ - function pendingRedeemRequest(uint256 requestId, address controller) - external - view - returns (uint256 pendingShares); - - /** - * @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw. - * - * - MUST NOT include any shares in Pending state for redeem or withdraw. - * - MUST NOT show any variations depending on the caller. - * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input. - */ - function claimableRedeemRequest(uint256 requestId, address controller) - external - view - returns (uint256 claimableShares); -} - -/// @dev Interface of the fully asynchronous Vault interface of ERC7540, as defined in -/// https://eips.ethereum.org/EIPS/eip-7540 -interface IERC7540 is IERC7540Deposit, IERC7540Redeem, IERC7575 {} diff --git a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7575.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7575.sol deleted file mode 100644 index 207e3e7..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IERC7575.sol +++ /dev/null @@ -1,241 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2; - -import {IERC165} from "./IERC165.sol"; - -/// @dev Interface of the ERC7575 "Multi-Asset ERC-4626 Vaults", as defined in -/// https://eips.ethereum.org/EIPS/eip-7575 -interface IERC7575 is IERC165 { - 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 address of the share token - * - * - MUST be an ERC-20 token contract. - * - MUST NOT revert. - */ - function share() external view returns (address shareTokenAddress); - - /** - * @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 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 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); -} - -/// @dev Interface of the ERC20 share token, as defined in -/// https://eips.ethereum.org/EIPS/eip-7575 -interface IERC7575Share is IERC165 { - event VaultUpdate(address indexed asset, address vault); - - /** - * @dev Returns the address of the Vault for the given asset. - * - * @param asset the ERC-20 token to deposit with into the Vault - */ - function vault(address asset) external view returns (address); -} diff --git a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IMulticall3.sol b/typescript/packages/account-modules/lib/forge-std/src/interfaces/IMulticall3.sol deleted file mode 100644 index 0d031b7..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/interfaces/IMulticall3.sol +++ /dev/null @@ -1,73 +0,0 @@ -// 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/typescript/packages/account-modules/lib/forge-std/src/safeconsole.sol b/typescript/packages/account-modules/lib/forge-std/src/safeconsole.sol deleted file mode 100644 index 87c475a..0000000 --- a/typescript/packages/account-modules/lib/forge-std/src/safeconsole.sol +++ /dev/null @@ -1,13937 +0,0 @@ -// 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; - /// @solidity memory-safe-assembly - assembly { - pureSendLogPayload := fnIn - } - pureSendLogPayload(offset, size); - } - - function _sendLogPayloadView(uint256 offset, uint256 size) private view { - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - assembly { - pureMemcopy := fnIn - } - pureMemcopy(fromOffset, toOffset, length); - } - - function _memcopyView(uint256 fromOffset, uint256 toOffset, uint256 length) private view { - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - assembly { - m0 := mload(sub(offset, 0x60)) - m1 := mload(sub(offset, 0x40)) - m2 := mload(sub(offset, 0x20)) - // Selector of `log(bytes)`. - mstore(sub(offset, 0x60), 0x0be77f56) - mstore(sub(offset, 0x40), 0x20) - mstore(sub(offset, 0x20), length) - } - _sendLogPayload(offset - 0x44, length + 0x44); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - assembly { - m0 := mload(add(endOffset, 0x00)) - m1 := mload(add(endOffset, 0x20)) - m2 := mload(add(endOffset, 0x40)) - } - _memcopy(offset, offset + 0x60, length); - /// @solidity memory-safe-assembly - assembly { - // Selector of `log(bytes)`. - mstore(add(offset, 0x00), 0x0be77f56) - mstore(add(offset, 0x20), 0x20) - mstore(add(offset, 0x40), length) - } - _sendLogPayload(offset + 0x1c, length + 0x44); - _memcopy(offset + 0x60, offset, length); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - assembly { - m0 := mload(0x00) - m1 := mload(0x20) - // Selector of `log(address)`. - mstore(0x00, 0x2c2ecbc2) - mstore(0x20, p0) - } - _sendLogPayload(0x1c, 0x24); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - } - } - - function log(bool p0) internal pure { - bytes32 m0; - bytes32 m1; - /// @solidity memory-safe-assembly - assembly { - m0 := mload(0x00) - m1 := mload(0x20) - // Selector of `log(bool)`. - mstore(0x00, 0x32458eed) - mstore(0x20, p0) - } - _sendLogPayload(0x1c, 0x24); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - } - } - - function log(uint256 p0) internal pure { - bytes32 m0; - bytes32 m1; - /// @solidity memory-safe-assembly - assembly { - m0 := mload(0x00) - m1 := mload(0x20) - // Selector of `log(uint256)`. - mstore(0x00, 0xf82c50f1) - mstore(0x20, p0) - } - _sendLogPayload(0x1c, 0x24); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - } - } - - function log(bytes32 p0) internal pure { - bytes32 m0; - bytes32 m1; - bytes32 m2; - bytes32 m3; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - mstore(0x40, m2) - } - } - - function log(address p0, bool p1) internal pure { - bytes32 m0; - bytes32 m1; - bytes32 m2; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - mstore(0x40, m2) - } - } - - function log(address p0, uint256 p1) internal pure { - bytes32 m0; - bytes32 m1; - bytes32 m2; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - mstore(0x40, m2) - } - } - - function log(bool p0, bool p1) internal pure { - bytes32 m0; - bytes32 m1; - bytes32 m2; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - mstore(0x40, m2) - } - } - - function log(bool p0, uint256 p1) internal pure { - bytes32 m0; - bytes32 m1; - bytes32 m2; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - mstore(0x40, m2) - } - } - - function log(uint256 p0, bool p1) internal pure { - bytes32 m0; - bytes32 m1; - bytes32 m2; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - mstore(0x40, m2) - } - } - - function log(uint256 p0, uint256 p1) internal pure { - bytes32 m0; - bytes32 m1; - bytes32 m2; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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/typescript/packages/account-modules/lib/forge-std/test/CommonBase.t.sol b/typescript/packages/account-modules/lib/forge-std/test/CommonBase.t.sol deleted file mode 100644 index 4a6eb34..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/CommonBase.t.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {CommonBase} from "../src/Base.sol"; -import {StdConstants} from "../src/StdConstants.sol"; -import {Test} from "../src/Test.sol"; - -contract CommonBaseTest is Test { - function testVmAddressValue() public pure { - assertEq(VM_ADDRESS, address(StdConstants.VM)); - } - - function testConsoleValue() public pure { - assertEq(CONSOLE, StdConstants.CONSOLE); - } - - function testCreate2FactoryValue() public pure { - assertEq(CREATE2_FACTORY, StdConstants.CREATE2_FACTORY); - } - - function testDefaultSenderValue() public pure { - assertEq(DEFAULT_SENDER, StdConstants.DEFAULT_SENDER); - } - - function testDefaultTestContractValue() public pure { - assertEq(DEFAULT_TEST_CONTRACT, StdConstants.DEFAULT_TEST_CONTRACT); - } - - function testMulticall3AddressValue() public pure { - assertEq(MULTICALL3_ADDRESS, address(StdConstants.MULTICALL3_ADDRESS)); - } - - function testSecp256k1OrderValue() public pure { - assertEq(SECP256K1_ORDER, StdConstants.SECP256K1_ORDER); - } - - function testUint256MaxValue() public pure { - assertEq(UINT256_MAX, type(uint256).max); - } - - function testVmValue() public pure { - assertEq(address(vm), address(StdConstants.VM)); - } -} diff --git a/typescript/packages/account-modules/lib/forge-std/test/StdAssertions.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdAssertions.t.sol deleted file mode 100644 index acc0c1e..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/StdAssertions.t.sol +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {StdAssertions} from "../src/StdAssertions.sol"; -import {Vm} from "../src/Vm.sol"; - -interface VmInternal is Vm { - function _expectCheatcodeRevert(bytes memory message) external; -} - -contract StdAssertionsTest is StdAssertions { - string constant errorMessage = "User provided message"; - uint256 constant maxDecimals = 77; - - bool constant SHOULD_REVERT = true; - bool constant SHOULD_RETURN = false; - - bool constant STRICT_REVERT_DATA = true; - bool constant NON_STRICT_REVERT_DATA = false; - - VmInternal constant vm = VmInternal(address(uint160(uint256(keccak256("hevm cheat code"))))); - - 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)); - - assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); - } - - 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._expectCheatcodeRevert( - bytes( - string.concat( - "Call return data does not match: ", vm.toString(returnDataA), " != ", vm.toString(returnDataB) - ) - ) - ); - assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); - } - - 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)); - - assertEqCall(targetA, callDataA, targetB, callDataB, NON_STRICT_REVERT_DATA); - } - - 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._expectCheatcodeRevert( - bytes( - string.concat( - "Call revert data does not match: ", vm.toString(revertDataA), " != ", vm.toString(revertDataB) - ) - ) - ); - assertEqCall(targetA, callDataA, targetB, callDataB, STRICT_REVERT_DATA); - } - - 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.expectRevert(bytes("assertion failed")); - this.assertEqCallExternal(targetA, callDataA, targetB, callDataB, strictRevertData); - - vm.expectRevert(bytes("assertion failed")); - this.assertEqCallExternal(targetB, callDataB, targetA, callDataA, strictRevertData); - } - - // Helper function to test outcome of assertEqCall via `expect` cheatcodes - function assertEqCallExternal( - address targetA, - bytes memory callDataA, - address targetB, - bytes memory callDataB, - bool strictRevertData - ) public { - 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/typescript/packages/account-modules/lib/forge-std/test/StdChains.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdChains.t.sol deleted file mode 100644 index d88069b..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/StdChains.t.sol +++ /dev/null @@ -1,227 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {Test} from "../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://eth.merkle.io"); - assertEq(getChain("optimism_sepolia").rpcUrl, "https://sepolia.optimism.io/"); - assertEq(getChain("arbitrum_one_sepolia").rpcUrl, "https://sepolia-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://eth.merkle.io"); - - // 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"); - } - - // Named with a leading underscore to clarify this is not intended to be run as a normal test, - // and is intended to be used in the below `test_Rpcs` test. - 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. - // Currently commented out since this is slow and public RPCs are flaky, often resulting in failing CI. - // function test_Rpcs() public { - // _testRpc("mainnet"); - // _testRpc("sepolia"); - // _testRpc("holesky"); - // _testRpc("optimism"); - // _testRpc("optimism_sepolia"); - // _testRpc("arbitrum_one"); - // _testRpc("arbitrum_one_sepolia"); - // _testRpc("arbitrum_nova"); - // _testRpc("polygon"); - // _testRpc("polygon_amoy"); - // _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_sepolia"); - // _testRpc("base"); - // _testRpc("blast_sepolia"); - // _testRpc("blast"); - // _testRpc("fantom_opera"); - // _testRpc("fantom_opera_testnet"); - // _testRpc("fraxtal"); - // _testRpc("fraxtal_testnet"); - // _testRpc("berachain_bartio_testnet"); - // _testRpc("flare"); - // _testRpc("flare_coston2"); - // } - - function test_RevertIf_ChainNotFound() 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_RevertIf_SetChain_ChainIdExist_FirstTest() 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_RevertIf_ChainBubbleUp() public { - // We deploy a mock to properly test the revert. - StdChainsMock stdChainsMock = new StdChainsMock(); - - stdChainsMock.exposed_setChain("needs_undefined_env_var", ChainData("", 123456789, "")); - // Forge environment variable error. - vm.expectRevert(); - stdChainsMock.exposed_getChain("needs_undefined_env_var"); - } - - function test_RevertIf_SetChain_ChainIdExists_SecondTest() 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_RevertIf_SetEmptyAlias() 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_RevertIf_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_RevertIf_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_RevertIf_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_RevertIf_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_RevertIf_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", 9999999999999999999, "https://modified.chain/")); - vm.expectRevert("StdChains getChain(uint256): Chain with ID 123456789 not found."); - stdChainsMock.exposed_getChain(123456789); - - Chain memory modifiedChain = getChain(9999999999999999999); - assertEq(modifiedChain.name, "Modified Chain"); - assertEq(modifiedChain.chainId, 9999999999999999999); - assertEq(modifiedChain.rpcUrl, "https://modified.chain/"); - } - - function test_RevertIf_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(); - stdChainsMock.exposed_getChain(31337); - vm.expectRevert(); - stdChainsMock.exposed_getChain("sepolia"); - } -} diff --git a/typescript/packages/account-modules/lib/forge-std/test/StdCheats.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdCheats.t.sol deleted file mode 100644 index 57dbcc2..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/StdCheats.t.sol +++ /dev/null @@ -1,639 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {StdCheats} from "../src/StdCheats.sol"; -import {Test} from "../src/Test.sol"; -import {stdJson} from "../src/StdJson.sol"; -import {stdToml} from "../src/StdToml.sol"; -import {IERC20} from "../src/interfaces/IERC20.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 test_DealToken() 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_RevertIf_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 pure { - 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 view { - 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 view { - 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(); - - 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_sepolia").chainId); - assertTrue( - addr < address(1) || (addr > address(9) && addr < address(0x4200000000000000000000000000000000000000)) - || addr > address(0x4200000000000000000000000000000000000800) - ); - } - - function testFuzz_AssumeNotForgeAddress(address addr) external pure { - assumeNotForgeAddress(addr); - assertTrue( - addr != address(vm) && addr != 0x000000000000000000636F6e736F6c652e6c6f67 - && addr != 0x4e59b44847b379578588920cA78FbF26c0B4956C - ); - } - - function test_RevertIf_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 USDC_BLACKLISTED_USER = 0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD; - address internal constant USDT_BLACKLISTED_USER = 0x8f8a8F4B54a2aAC7799d7bc81368aC27b852822A; - - MockUSDT public USDT; - MockUSDC public USDC; - - function setUp() public { - USDT = new MockUSDT(); - USDC = new MockUSDC(); - - USDC.setBlacklisted(USDC_BLACKLISTED_USER, true); - USDT.setBlacklisted(USDT_BLACKLISTED_USER, true); - } - - function test_RevertIf_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 view { - assumeNotBlacklisted(address(USDC), addr); - assumeNotBlacklisted(address(USDT), addr); - assertTrue(true); - } - - function test_RevertIf_AssumeNoBlacklisted_USDC() external { - // We deploy a mock version so we can properly test the revert. - StdCheatsMock stdCheatsMock = new StdCheatsMock(); - vm.expectRevert(); - stdCheatsMock.exposed_assumeNotBlacklisted(address(USDC), USDC_BLACKLISTED_USER); - } - - function testFuzz_AssumeNotBlacklisted_USDC(address addr) external view { - assumeNotBlacklisted(address(USDC), addr); - assertFalse(USDCLike(USDC).isBlacklisted(addr)); - } - - function test_RevertIf_AssumeNoBlacklisted_USDT() external { - // We deploy a mock version so we can properly test the revert. - StdCheatsMock stdCheatsMock = new StdCheatsMock(); - vm.expectRevert(); - stdCheatsMock.exposed_assumeNotBlacklisted(address(USDT), USDT_BLACKLISTED_USER); - } - - function testFuzz_AssumeNotBlacklisted_USDT(address addr) external view { - assumeNotBlacklisted(address(USDT), addr); - assertFalse(USDTLike(USDT).isBlackListed(addr)); - } -} - -/// @dev https://etherscan.io/token/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48#readProxyContract -interface USDCLike { - function isBlacklisted(address) external view returns (bool); -} - -/// @dev https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7#readContract -interface USDTLike { - function isBlackListed(address) external view returns (bool); -} - -contract MockUSDT is USDTLike { - mapping(address => bool) private blacklist; - - function isBlackListed(address addr) external view returns (bool) { - return blacklist[addr]; - } - - function setBlacklisted(address addr, bool value) external { - blacklist[addr] = value; - } -} - -contract MockUSDC is USDCLike { - mapping(address => bool) private blacklist; - - function isBlacklisted(address addr) external view returns (bool) { - return blacklist[addr]; - } - - function setBlacklisted(address addr, bool value) external { - blacklist[addr] = value; - } -} - -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; -} - -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/typescript/packages/account-modules/lib/forge-std/test/StdConstants.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdConstants.t.sol deleted file mode 100644 index 7a00530..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/StdConstants.t.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {StdConstants} from "../src/StdConstants.sol"; -import {Test} from "../src/Test.sol"; - -contract StdConstantsTest is Test { - function testVm() public view { - assertEq(StdConstants.VM.getBlockNumber(), 1); - } - - function testVmDerivation() public pure { - assertEq(address(StdConstants.VM), address(uint160(uint256(keccak256("hevm cheat code"))))); - } - - function testConsoleDerivation() public pure { - assertEq(StdConstants.CONSOLE, address(uint160(uint88(bytes11("console.log"))))); - } - - function testDefaultSender() public view { - assertEq(StdConstants.DEFAULT_SENDER, msg.sender); - } - - function testDefaultSenderDerivation() public pure { - assertEq(StdConstants.DEFAULT_SENDER, address(uint160(uint256(keccak256("foundry default caller"))))); - } - - function testDefaultTestContract() public { - assertEq(StdConstants.DEFAULT_TEST_CONTRACT, address(new Dummy())); - } - - function testDefaultTestContractDerivation() public view { - assertEq(address(this), StdConstants.VM.computeCreateAddress(StdConstants.DEFAULT_SENDER, 1)); - assertEq(StdConstants.DEFAULT_TEST_CONTRACT, StdConstants.VM.computeCreateAddress(address(this), 1)); - } -} - -contract Dummy {} diff --git a/typescript/packages/account-modules/lib/forge-std/test/StdError.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdError.t.sol deleted file mode 100644 index 29803d5..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/StdError.t.sol +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -import {stdError} from "../src/StdError.sol"; -import {Test} from "../src/Test.sol"; - -contract StdErrorsTest is Test { - ErrorsTest test; - - function setUp() public { - test = new ErrorsTest(); - } - - function test_RevertIf_AssertionError() public { - vm.expectRevert(stdError.assertionError); - test.assertionError(); - } - - function test_RevertIf_ArithmeticError() public { - vm.expectRevert(stdError.arithmeticError); - test.arithmeticError(10); - } - - function test_RevertIf_DivisionError() public { - vm.expectRevert(stdError.divisionError); - test.divError(0); - } - - function test_RevertIf_ModError() public { - vm.expectRevert(stdError.divisionError); - test.modError(0); - } - - function test_RevertIf_EnumConversionError() public { - vm.expectRevert(stdError.enumConversionError); - test.enumConversion(1); - } - - function test_RevertIf_EncodeStgError() public { - vm.expectRevert(stdError.encodeStorageError); - test.encodeStgError(); - } - - function test_RevertIf_PopError() public { - vm.expectRevert(stdError.popError); - test.pop(); - } - - function test_RevertIf_IndexOOBError() public { - vm.expectRevert(stdError.indexOOBError); - test.indexOOBError(1); - } - - function test_RevertIf_MemOverflowError() public { - vm.expectRevert(stdError.memOverflowError); - test.mem(); - } - - function test_RevertIf_InternError() 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/typescript/packages/account-modules/lib/forge-std/test/StdJson.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdJson.t.sol deleted file mode 100644 index 6bedfcc..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/StdJson.t.sol +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {Test, stdJson} from "../src/Test.sol"; - -contract StdJsonTest is Test { - using stdJson for string; - - string root; - string path; - - function setUp() public { - root = vm.projectRoot(); - path = string.concat(root, "/test/fixtures/test.json"); - } - - struct SimpleJson { - uint256 a; - string b; - } - - struct NestedJson { - uint256 a; - string b; - SimpleJson c; - } - - function test_readJson() public view { - string memory json = vm.readFile(path); - assertEq(json.readUint(".a"), 123); - } - - function test_writeJson() public { - string memory json = "json"; - json.serialize("a", uint256(123)); - string memory semiFinal = json.serialize("b", string("test")); - string memory finalJson = json.serialize("c", semiFinal); - finalJson.write(path); - - string memory json_ = vm.readFile(path); - bytes memory data = json_.parseRaw("$"); - NestedJson memory decodedData = abi.decode(data, (NestedJson)); - - assertEq(decodedData.a, 123); - assertEq(decodedData.b, "test"); - assertEq(decodedData.c.a, 123); - assertEq(decodedData.c.b, "test"); - } -} diff --git a/typescript/packages/account-modules/lib/forge-std/test/StdMath.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdMath.t.sol deleted file mode 100644 index d1269a0..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/StdMath.t.sol +++ /dev/null @@ -1,202 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -import {stdMath} from "../src/StdMath.sol"; -import {Test, stdError} from "../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 pure { - 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 pure { - uint256 manualAbs = getAbs(a); - - uint256 abs = stdMath.abs(a); - - assertEq(abs, manualAbs); - } - - function test_GetDelta_Uint() external pure { - 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 pure { - uint256 manualDelta = a > b ? a - b : b - a; - - uint256 delta = stdMath.delta(a, b); - - assertEq(delta, manualDelta); - } - - function test_GetDelta_Int() external pure { - 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 pure { - 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 pure { - vm.assume(b != 0); - uint256 manualDelta = a > b ? a - b : 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 pure { - 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/typescript/packages/account-modules/lib/forge-std/test/StdStorage.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdStorage.t.sol deleted file mode 100644 index 46604f8..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/StdStorage.t.sol +++ /dev/null @@ -1,488 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {stdStorage, StdStorage} from "../src/StdStorage.sol"; -import {Test} from "../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 testFuzz_StorageCheckedWriteMapPacked(address addr, uint128 value) public { - stdstore.enable_packed_slots().target(address(test)).sig(test.read_struct_lower.selector).with_key(addr) - .checked_write(value); - assertEq(test.read_struct_lower(addr), value); - - stdstore.enable_packed_slots().target(address(test)).sig(test.read_struct_upper.selector).with_key(addr) - .checked_write(value); - assertEq(test.read_struct_upper(addr), value); - } - - function test_StorageCheckedWriteMapPackedFullSuccess() 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 test_RevertStorageConst() public { - StorageTestTarget target = new StorageTestTarget(test); - - vm.expectRevert("stdStorage find(StdStorage): No storage use detected for target."); - target.expectRevertStorageConst(); - } - - function testFuzz_StorageNativePack(uint248 val1, uint248 val2, bool boolVal1, bool boolVal2) public { - stdstore.enable_packed_slots().target(address(test)).sig(test.tA.selector).checked_write(val1); - stdstore.enable_packed_slots().target(address(test)).sig(test.tB.selector).checked_write(boolVal1); - stdstore.enable_packed_slots().target(address(test)).sig(test.tC.selector).checked_write(boolVal2); - stdstore.enable_packed_slots().target(address(test)).sig(test.tD.selector).checked_write(val2); - - assertEq(test.tA(), val1); - assertEq(test.tB(), boolVal1); - assertEq(test.tC(), boolVal2); - assertEq(test.tD(), val2); - } - - 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_RevertIf_ReadingNonBoolValue() 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); - } - - function testFuzz_Packed(uint256 val, uint8 elemToGet) public { - // This function tries an assortment of packed slots, shifts meaning number of elements - // that are packed. Shiftsizes are the size of each element, i.e. 8 means a data type that is 8 bits, 16 == 16 bits, etc. - // Combined, these determine how a slot is packed. Making it random is too hard to avoid global rejection limit - // and make it performant. - - // change the number of shifts - for (uint256 i = 1; i < 5; i++) { - uint256 shifts = i; - - elemToGet = uint8(bound(elemToGet, 0, shifts - 1)); - - uint256[] memory shiftSizes = new uint256[](shifts); - for (uint256 j; j < shifts; j++) { - shiftSizes[j] = 8 * (j + 1); - } - - test.setRandomPacking(val); - - uint256 leftBits; - uint256 rightBits; - for (uint256 j; j < shiftSizes.length; j++) { - if (j < elemToGet) { - leftBits += shiftSizes[j]; - } else if (elemToGet != j) { - rightBits += shiftSizes[j]; - } - } - - // we may have some right bits unaccounted for - leftBits += 256 - (leftBits + shiftSizes[elemToGet] + rightBits); - // clear left bits, then clear right bits and realign - uint256 expectedValToRead = (val << leftBits) >> (leftBits + rightBits); - - uint256 readVal = stdstore.target(address(test)).enable_packed_slots().sig( - "getRandomPacked(uint8,uint8[],uint8)" - ).with_calldata(abi.encode(shifts, shiftSizes, elemToGet)).read_uint(); - - assertEq(readVal, expectedValToRead); - } - } - - function testFuzz_Packed2(uint256 nvars, uint256 seed) public { - // Number of random variables to generate. - nvars = bound(nvars, 1, 20); - - // This will decrease as we generate values in the below loop. - uint256 bitsRemaining = 256; - - // Generate a random value and size for each variable. - uint256[] memory vals = new uint256[](nvars); - uint256[] memory sizes = new uint256[](nvars); - uint256[] memory offsets = new uint256[](nvars); - - for (uint256 i = 0; i < nvars; i++) { - // Generate a random value and size. - offsets[i] = i == 0 ? 0 : offsets[i - 1] + sizes[i - 1]; - - uint256 nvarsRemaining = nvars - i; - uint256 maxVarSize = bitsRemaining - nvarsRemaining + 1; - sizes[i] = bound(uint256(keccak256(abi.encodePacked(seed, i + 256))), 1, maxVarSize); - bitsRemaining -= sizes[i]; - - uint256 maxVal; - uint256 varSize = sizes[i]; - assembly { - // mask = (1 << varSize) - 1 - maxVal := sub(shl(varSize, 1), 1) - } - vals[i] = bound(uint256(keccak256(abi.encodePacked(seed, i))), 0, maxVal); - } - - // Pack all values into the slot. - for (uint256 i = 0; i < nvars; i++) { - stdstore.enable_packed_slots().target(address(test)).sig("getRandomPacked(uint256,uint256)").with_key( - sizes[i] - ).with_key(offsets[i]).checked_write(vals[i]); - } - - // Verify the read data matches. - for (uint256 i = 0; i < nvars; i++) { - uint256 readVal = stdstore.enable_packed_slots().target(address(test)).sig( - "getRandomPacked(uint256,uint256)" - ).with_key(sizes[i]).with_key(offsets[i]).read_uint(); - - uint256 retVal = test.getRandomPacked(sizes[i], offsets[i]); - - assertEq(readVal, vals[i]); - assertEq(retVal, vals[i]); - } - } - - function testEdgeCaseArray() public { - stdstore.target(address(test)).sig("edgeCaseArray(uint256)").with_key(uint256(0)).checked_write(1); - assertEq(test.edgeCaseArray(0), 1); - } -} - -contract StorageTestTarget { - using stdStorage for StdStorage; - - StdStorage internal stdstore; - StorageTest internal test; - - constructor(StorageTest test_) { - test = test_; - } - - function expectRevertStorageConst() public { - stdstore.target(address(test)).sig("const()").find(); - } -} - -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"); - - uint256 randomPacking; - - // Array with length matching values of elements. - uint256[] public edgeCaseArray = [3, 3, 3]; - - 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; - } - - function setRandomPacking(uint256 val) public { - randomPacking = val; - } - - function _getMask(uint256 size) internal pure returns (uint256 mask) { - assembly { - // mask = (1 << size) - 1 - mask := sub(shl(size, 1), 1) - } - } - - function setRandomPacking(uint256 val, uint256 size, uint256 offset) public { - // Generate mask based on the size of the value - uint256 mask = _getMask(size); - // Zero out all bits for the word we're about to set - uint256 cleanedWord = randomPacking & ~(mask << offset); - // Place val in the correct spot of the cleaned word - randomPacking = cleanedWord | val << offset; - } - - function getRandomPacked(uint256 size, uint256 offset) public view returns (uint256) { - // Generate mask based on the size of the value - uint256 mask = _getMask(size); - // Shift to place the bits in the correct position, and use mask to zero out remaining bits - return (randomPacking >> offset) & mask; - } - - function getRandomPacked(uint8 shifts, uint8[] memory shiftSizes, uint8 elem) public view returns (uint256) { - require(elem < shifts, "!elem"); - uint256 leftBits; - uint256 rightBits; - - for (uint256 i; i < shiftSizes.length; i++) { - if (i < elem) { - leftBits += shiftSizes[i]; - } else if (elem != i) { - rightBits += shiftSizes[i]; - } - } - - // we may have some right bits unaccounted for - leftBits += 256 - (leftBits + shiftSizes[elem] + rightBits); - - // clear left bits, then clear right bits and realign - return (randomPacking << leftBits) >> (leftBits + rightBits); - } -} diff --git a/typescript/packages/account-modules/lib/forge-std/test/StdStyle.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdStyle.t.sol deleted file mode 100644 index 974e756..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/StdStyle.t.sol +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {Test, console2, StdStyle} from "../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/typescript/packages/account-modules/lib/forge-std/test/StdToml.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdToml.t.sol deleted file mode 100644 index 5a45f4f..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/StdToml.t.sol +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {Test, stdToml} from "../src/Test.sol"; - -contract StdTomlTest is Test { - using stdToml for string; - - string root; - string path; - - function setUp() public { - root = vm.projectRoot(); - path = string.concat(root, "/test/fixtures/test.toml"); - } - - struct SimpleToml { - uint256 a; - string b; - } - - struct NestedToml { - uint256 a; - string b; - SimpleToml c; - } - - function test_readToml() public view { - string memory json = vm.readFile(path); - assertEq(json.readUint(".a"), 123); - } - - function test_writeToml() public { - string memory json = "json"; - json.serialize("a", uint256(123)); - string memory semiFinal = json.serialize("b", string("test")); - string memory finalJson = json.serialize("c", semiFinal); - finalJson.write(path); - - string memory toml = vm.readFile(path); - bytes memory data = toml.parseRaw("$"); - NestedToml memory decodedData = abi.decode(data, (NestedToml)); - - assertEq(decodedData.a, 123); - assertEq(decodedData.b, "test"); - assertEq(decodedData.c.a, 123); - assertEq(decodedData.c.b, "test"); - } -} diff --git a/typescript/packages/account-modules/lib/forge-std/test/StdUtils.t.sol b/typescript/packages/account-modules/lib/forge-std/test/StdUtils.t.sol deleted file mode 100644 index aee801b..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/StdUtils.t.sol +++ /dev/null @@ -1,342 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {Test, StdUtils} from "../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 pure returns (int256) { - return bound(num, min, max); - } - - function exposed_bound(uint256 num, uint256 min, uint256 max) external pure 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 pure { - 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 pure { - 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 pure { - 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 testFuzz_Bound_DistributionIsEven(uint256 min, uint256 size) public pure { - 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 testFuzz_Bound(uint256 num, uint256 min, uint256 max) public pure { - 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 pure { - 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_RevertIf_BoundMaxLessThanMin() 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 testFuzz_RevertIf_BoundMaxLessThanMin(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 pure { - 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 pure { - 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 pure { - 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 testFuzz_BoundInt_DistributionIsEven(int256 min, uint256 size) public pure { - 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 testFuzz_BoundInt(int256 num, int256 min, int256 max) public pure { - 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 pure { - 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 pure { - 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_RevertIf_BoundIntMaxLessThanMin() 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 testFuzz_RevertIf_BoundIntMaxLessThanMin(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 pure { - 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 pure { - 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_RevertIf_BytesLengthExceeds32() 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 pure { - address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; - uint256 nonce = 14; - address createAddress = computeCreateAddress(deployer, nonce); - assertEq(createAddress, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); - } - - /*////////////////////////////////////////////////////////////////////////// - COMPUTE CREATE2 ADDRESS - //////////////////////////////////////////////////////////////////////////*/ - - function test_ComputeCreate2Address() external pure { - 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 pure { - 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_RevertIf_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_RevertIf_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/typescript/packages/account-modules/lib/forge-std/test/Vm.t.sol b/typescript/packages/account-modules/lib/forge-std/test/Vm.t.sol deleted file mode 100644 index 1cf81c4..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/Vm.t.sol +++ /dev/null @@ -1,18 +0,0 @@ -// 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"; - -// These tests ensure that functions are never accidentally removed from a Vm interface, or -// inadvertently moved between Vm and VmSafe. These tests must be updated each time a function is -// added to or removed from Vm or VmSafe. -contract VmTest is Test { - function test_VmInterfaceId() public pure { - assertEq(type(Vm).interfaceId, bytes4(0xe835828d), "Vm"); - } - - function test_VmSafeInterfaceId() public pure { - assertEq(type(VmSafe).interfaceId, bytes4(0xf4408204), "VmSafe"); - } -} diff --git a/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationScript.sol b/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationScript.sol deleted file mode 100644 index d3d88a0..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationScript.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2 <0.9.0; - -pragma experimental ABIEncoderV2; - -import {Script} from "../../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/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationScriptBase.sol b/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationScriptBase.sol deleted file mode 100644 index 65b5bed..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationScriptBase.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2 <0.9.0; - -pragma experimental ABIEncoderV2; - -import {ScriptBase} from "../../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/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationTest.sol b/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationTest.sol deleted file mode 100644 index 2a9dec5..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationTest.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2 <0.9.0; - -pragma experimental ABIEncoderV2; - -import {Test} from "../../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/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationTestBase.sol b/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationTestBase.sol deleted file mode 100644 index 32b3fc5..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/compilation/CompilationTestBase.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2 <0.9.0; - -pragma experimental ABIEncoderV2; - -import {TestBase} from "../../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/typescript/packages/account-modules/lib/forge-std/test/fixtures/broadcast.log.json b/typescript/packages/account-modules/lib/forge-std/test/fixtures/broadcast.log.json deleted file mode 100644 index 0a0200b..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/fixtures/broadcast.log.json +++ /dev/null @@ -1,187 +0,0 @@ -{ - "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/typescript/packages/account-modules/lib/forge-std/test/fixtures/test.json b/typescript/packages/account-modules/lib/forge-std/test/fixtures/test.json deleted file mode 100644 index caebf6d..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/fixtures/test.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "a": 123, - "b": "test", - "c": { - "a": 123, - "b": "test" - } -} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/forge-std/test/fixtures/test.toml b/typescript/packages/account-modules/lib/forge-std/test/fixtures/test.toml deleted file mode 100644 index 60692bc..0000000 --- a/typescript/packages/account-modules/lib/forge-std/test/fixtures/test.toml +++ /dev/null @@ -1,6 +0,0 @@ -a = 123 -b = "test" - -[c] -a = 123 -b = "test" diff --git a/typescript/packages/account-modules/lib/modulekit/.changeset/README.md b/typescript/packages/account-modules/lib/modulekit/.changeset/README.md deleted file mode 100644 index e5b6d8d..0000000 --- a/typescript/packages/account-modules/lib/modulekit/.changeset/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Changesets - -Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works -with multi-package repos, or single-package repos to help you version and publish your code. You can -find the full documentation for it [in our repository](https://github.com/changesets/changesets) - -We have a quick list of common questions to get you started engaging with this project in -[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) diff --git a/typescript/packages/account-modules/lib/modulekit/.changeset/config.json b/typescript/packages/account-modules/lib/modulekit/.changeset/config.json deleted file mode 100644 index 91b6a95..0000000 --- a/typescript/packages/account-modules/lib/modulekit/.changeset/config.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", - "changelog": "@changesets/cli/changelog", - "commit": false, - "fixed": [], - "linked": [], - "access": "restricted", - "baseBranch": "main", - "updateInternalDependencies": "patch", - "ignore": [] -} diff --git a/typescript/packages/account-modules/lib/modulekit/.env-example b/typescript/packages/account-modules/lib/modulekit/.env-example deleted file mode 100644 index 5f2a817..0000000 --- a/typescript/packages/account-modules/lib/modulekit/.env-example +++ /dev/null @@ -1,2 +0,0 @@ -MAINNET_RPC_URL= - diff --git a/typescript/packages/account-modules/lib/modulekit/.github/workflows/ci.yaml b/typescript/packages/account-modules/lib/modulekit/.github/workflows/ci.yaml deleted file mode 100644 index 9e66804..0000000 --- a/typescript/packages/account-modules/lib/modulekit/.github/workflows/ci.yaml +++ /dev/null @@ -1,55 +0,0 @@ -on: - workflow_dispatch: - push: - branches: - - "main" - pull_request: - -jobs: - lint: - uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-lint.yaml@main" - - build: - uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-build.yaml@main" - - test: - needs: ["lint", "build"] - uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-test.yaml@main" - with: - foundry-fuzz-runs: 5000 - foundry-profile: "test" - match-path: "test/**/*.sol" - foundry-verbosity: 3 - foundry-gas-limit: "18446744073709551615" - foundry-memory-limit: 2147483648 - secrets: - MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} - TESTNET_RPC_URL: ${{ secrets.TESTNET_RPC_URL }} - - test-simulate: - needs: ["lint", "build"] - uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-test-simulate.yaml@main" - with: - foundry-fuzz-runs: 5000 - foundry-profile: "test" - match-path: "test/**/*.sol" - foundry-verbosity: 3 - foundry-gas-limit: "18446744073709551615" - foundry-memory-limit: 2147483648 - secrets: - MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} - TESTNET_RPC_URL: ${{ secrets.TESTNET_RPC_URL }} - - test-multi-account: - needs: ["lint", "build"] - uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-test-multi-account.yaml@main" - with: - foundry-fuzz-runs: 5000 - foundry-profile: "test" - match-path: "test/**/*.sol" - foundry-verbosity: 3 - foundry-gas-limit: "18446744073709551615" - foundry-memory-limit: 2147483648 - secrets: - MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} - TESTNET_RPC_URL: ${{ secrets.TESTNET_RPC_URL }} diff --git a/typescript/packages/account-modules/lib/modulekit/.github/workflows/dependency.yml b/typescript/packages/account-modules/lib/modulekit/.github/workflows/dependency.yml deleted file mode 100644 index 992e855..0000000 --- a/typescript/packages/account-modules/lib/modulekit/.github/workflows/dependency.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: Check Dependency Installation of ModuleKit - -on: - workflow_dispatch: - push: - branches: - - "main" - pull_request: - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1.2.0 - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: "20" - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 9.0.6 - - - name: Pack the package - id: npm-pack - run: | - PACKAGE_NAME=$(npm pack) - echo "package=$PACKAGE_NAME" >> $GITHUB_ENV - - - name: Run npm test - run: | - mkdir test-npm-install - cd test-npm-install - npm init -y - npm install "../${{ env.package }}" - mkdir -p src - echo 'import "modulekit/ModuleKit.sol";' > src/TestImport.sol - echo '[profile.default] - evm_version = "cancun" - src = "src" - out = "out" - libs = ["node_modules"]' > foundry.toml - cp node_modules/@rhinestone/modulekit/remappings.txt remappings.txt - forge build - - - name: Run pnpm test - run: | - mkdir test-pnpm-install - cd test-pnpm-install - pnpm init - pnpm install "../${{ env.package }}" --shamefully-hoist - mkdir -p src - echo 'import "modulekit/ModuleKit.sol";' > src/TestImport.sol - echo '[profile.default] - evm_version = "cancun" - src = "src" - out = "out" - libs = ["node_modules"]' > foundry.toml - cp node_modules/@rhinestone/modulekit/remappings.txt remappings.txt - forge build - - - name: Run via-ir test - run: | - mkdir test-via-ir - cd test-via-ir - pnpm init - pnpm install "../${{ env.package }}" --shamefully-hoist - mkdir -p src - echo 'import "modulekit/ModuleKit.sol";' > src/TestImport.sol - echo '[profile.default] - evm_version = "cancun" - src = "src" - out = "out" - libs = ["node_modules"]' > foundry.toml - cp node_modules/@rhinestone/modulekit/remappings.txt remappings.txt - forge build --via-ir - - - name: Clean up - run: | - rm "${{ env.package }}" - rm -rf test-npm-install - rm -rf test-pnpm-install diff --git a/typescript/packages/account-modules/lib/modulekit/.gitignore b/typescript/packages/account-modules/lib/modulekit/.gitignore deleted file mode 100644 index dad627c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/.gitignore +++ /dev/null @@ -1,19 +0,0 @@ -# Compiler files -cache/ -out/ - -# Ignores development broadcast logs -!/broadcast -/broadcast/*/31337/ -/broadcast/**/dry-run/ - -packages/modulekit/gas_calculations/*.json - - -# Dotenv file -.env -node_modules - -gas_calculations/**.json - -.DS_Store \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/modulekit/.npmrc b/typescript/packages/account-modules/lib/modulekit/.npmrc deleted file mode 100644 index bf2e764..0000000 --- a/typescript/packages/account-modules/lib/modulekit/.npmrc +++ /dev/null @@ -1 +0,0 @@ -shamefully-hoist=true diff --git a/typescript/packages/account-modules/lib/modulekit/.solhint.json b/typescript/packages/account-modules/lib/modulekit/.solhint.json deleted file mode 100644 index e6b6dbb..0000000 --- a/typescript/packages/account-modules/lib/modulekit/.solhint.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "solhint:recommended", - "rules": { - "avoid-low-level-calls": "off", - "code-complexity": ["error", 11], - "compiler-version": ["error", ">=0.8.0"], - "contract-name-camelcase": "off", - "const-name-snakecase": "off", - "func-name-mixedcase": "off", - "func-visibility": ["error", { "ignoreConstructors": true }], - "max-line-length": ["error", 123], - "named-parameters-mapping": "warn", - "no-empty-blocks": "off", - "not-rely-on-time": "off", - "one-contract-per-file": "off", - "var-name-mixedcase": "off", - "no-global-import": "off" - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/.solhintignore b/typescript/packages/account-modules/lib/modulekit/.solhintignore deleted file mode 100644 index 2a7a947..0000000 --- a/typescript/packages/account-modules/lib/modulekit/.solhintignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules/ -lib/ -src/integrations/interfaces/ -src/core/Licensing/ -test/ diff --git a/typescript/packages/account-modules/lib/modulekit/CHANGELOG.md b/typescript/packages/account-modules/lib/modulekit/CHANGELOG.md deleted file mode 100644 index da13102..0000000 --- a/typescript/packages/account-modules/lib/modulekit/CHANGELOG.md +++ /dev/null @@ -1,186 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Common Changelog](https://common-changelog.org/). - -[0.4.6]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.4.6 -[0.4.5]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.4.5 -[0.4.4]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.4.4 -[0.4.3]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.4.3 -[0.4.2]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.4.2 -[0.4.1]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.4.1 -[0.4.0]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.4.0 -[0.3.7]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.7 -[0.3.6]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.6 -[0.3.5]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.5 -[0.3.4]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.4 -[0.3.3]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.3 -[0.3.2]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.2 -[0.3.1]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.1 -[0.3.0]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.0 -[0.2.0]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.2.0 -[0.1.0]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.1.0 - -## [0.4.5] - 04-06-2024 - -### Fixed - -- Bugs in uninstall module functions - -## [0.4.4] - 04-06-2024 - -### Fixed - -- Specify correct Kernel version -- Dependency based CI - -## [0.4.3] - 30-05-2024 - -### Changed - -- Refactored multi-account handling -- Clean up compiler warnings and linting issues - -### Added - -- Kernel v3 support -- Factory base for accounts to use the Module Registry - -## [0.4.2] - 24-05-2024 - -### Fixed - -- Incorrectly parsing the account salt for call traces - -## [0.4.1] - 24-05-2024 - -### Changed - -- Integrated `Safe7579Launchpad` -- Cleaned up and standardized multi-account logic -- Removed redundant components - -### Added - -- Account factory template to guide integration of new accounts -- Multi-account ci -- Dependency installation ci - -## [0.4.0] - 21-05-2024 - -### Changed - -- `instance.expect4337Revert` now catches reverts in both validation and execution -- Gas calculations are now split by `_` on every thousand -- General restructuring of the codebase and split into multiple repositories - - Moved module bases and mocks to `@rhinestone/module-bases` - - Moved core modules to `@rhinestone/core-modules` - - Moved the Safe ERC-7579 adapter to `@rhinestone/safe7579` - -### Added - -- ERC-7484 support with interface, mock registry and registry adapter base -- Support for stateless validators -- Under-the-hood support for multi-hooks -- Base module for scheduling-based executors - -### Fixed - -- Bugs related to installation and uninstallation calldata -- Various other bugs - -## [0.3.7] - 09-03-2024 - -### Changed - -- Updated Registry Deployer - -## [0.3.6] - 09-03-2024 - -### Changed - -- Updated Registry Deployer - -## [0.3.5] - 09-03-2024 - -### Changed - -- Updated Registry Deployer - -## [0.3.4] - 05-03-2024 - -### Changed - -- Updated ERC-7579 reference implementation dependency to latest -- Simplified remappings -- Updated examples and tests - -## [0.3.3] - 29-02-2024 - -### Changed - -- Various bug fixes -- Updated ERC-7579 reference implementation dependency to latest - -## [0.3.2] - 28-02-2024 - -### Changed - -- Various bug fixes and improvements - -## [0.3.1] - 23-02-2024 - -### Changed - -- File structure: - - `packages` now includes the core components - - `examples` now includes the example modules - - `accounts` includes the account integrations (the ERC-7579 reference implementation is currently inside the `packages/modulekit` package) -- Support for the latest version of ERC-7579 -- Entrypoint address is now the official v0.7 EntryPoint address - -### Added - -- Module Examples are now in the `examples` folder - -## [0.3.0] - 01-02-2024 - -### Changed - -- Native ERC-7579 support -- Improved Folder structure -- Testing interface: - - `RhinestoneAccount` -> `AccountInstance` - - `install`, `uininstall` and `isInstalled` functions for module types have been collapsed into `installModule`, `uninstallModule` and `isModuleInstalled` respectively -- Safe suppport now via a Safe ERC7579 module (still experimental) - -### Added - -- Hooks and Fallbacks: `ERC7579HookBase` and `ERC7579FallbackBase` -- Module Bases -- Gas measurement helper: `instance.log4337Gas("identifier")` and `GAS=true forge test` -- ERC4337 rule validation support in Foundry: `SIMULATE=true forge test` - -### Removed - -- Unused components - -## [0.2.0] - 17-10-2023 - -### Changed - -- Folder structure for better readability -- Ported Rhinestone Manager to Singleton - -### Added - -- Biconomy account integration test helper -- Conditional Execution Manager -- DeFi integrations and actions -- Fallback handler - -### Removed - -- Recovery flow in Validator interface -- Various dependencies diff --git a/typescript/packages/account-modules/lib/modulekit/README.md b/typescript/packages/account-modules/lib/modulekit/README.md deleted file mode 100644 index 66510c3..0000000 --- a/typescript/packages/account-modules/lib/modulekit/README.md +++ /dev/null @@ -1,137 +0,0 @@ -# ModuleKit - -**A development kit for building and testing smart account modules** - -ModuleKit allows you to: - -- **Easily build smart account modules** with interfaces for: - - Validators - - Executors - - Hooks -- **Unit test** your modules using a dedicated helper library -- **Integration test** your modules using different modular ERC-4337 accounts and a helper library that abstracts away the complexity - -In-depth documentation is available at [docs.rhinestone.wtf](https://docs.rhinestone.wtf/modulekit/). - -> The ModuleKit is in active development and is subject to breaking changes. If you spot a bug, please take out an issue and we will fix it as soon as we can. - -## Using the ModuleKit - -### Installation - -#### Using our template - -Use the [module-template](https://github.com/rhinestonewtf/module-template) to create a new repo and install the dependencies: - -```bash -pnpm install -``` - -#### Using git submodules - -```bash -forge install rhinestonewtf/modulekit -cd lib/modulekit -pnpm install -``` - -#### Using a package manager - -```bash -pnpm install @rhinestone/modulekit --shamefully-hoist -cp node_modules/@rhinestone/modulekit/remappings.txt remappings.txt -``` - -### Usage - -The ModuleKit can be used to **build**, **test** and **deploy** smart account modules. The full documentation is available at [docs.rhinestone.wtf](https://docs.rhinestone.wtf/modulekit/), but the following aims to provide a quick overview. - -### Building modules - -Import Module bases from `modulekit/Modules.sol`. The core bases include: - -- `ERC7579ValidatorBase`: A base for building validators -- `ERC7579ExecutorBase`: A base for building executors -- `ERC7579HookBase`: A base for building hooks -- `ERC7579HookDestruct`: A base for building hooks with destructured calldata (e.g. `onExecute` or `onInstallModule`) -- `ERC7579FallbackBase`: A base for building fallbacks - -We also provide more advanced bases like: - -- `SchedulingBase`: A base for building schedule-based executors -- `ERC7484RegistryAdapter`: A base for querying the Module Registry - -### Testing modules - -The ModuleKit provides an integration test suite for testing your modules across different modular accounts. To use the test suite, inherit from `RhinestoneModuleKit` and create an account instance using `makeAccountInstance(accountName)`. To learn more about using this instance, visit the documentation for our [integration test suite](https://docs.rhinestone.wtf/modulekit/test/integration). - -You can then run the tests using the following commands: - -```bash -forge test -``` - -Using a different account type (one of `SAFE` and `KERNEL`): - -```bash -ACCOUNT_TYPE=SAFE forge test -``` - -To validate the ERC-4337 rules: - -```bash -SIMULATE=true forge test -``` - -To calculate gas consumption of modules using `instance.log4337Gas("identifier")`: - -```bash -GAS=true forge test -``` - -### Deploying modules - -To deploy modules using the [Module Registry](https://github.com/rhinestonewtf/registry/), you can use the `RegistryDeployer` in a foundry script. You can then deploy your module using the following command: - -```solidity -address module = deployModule({ - code: bytecode, - deployParams: deployParams, - salt: bytes32(0), - data: additionalData -}); -``` - -## Module Examples - -For module examples, check out our [core modules](https://github.com/rhinestonewtf/core-modules/) or our [experimental modules](https://github.com/rhinestonewtf/experimental-modules/) and for module inspiration see our [module idea list](https://rhinestone.notion.site/Module-ideas-for-product-inspo-338100a2c99540f490472b8aa839da11). For general examples, check out the [awesome modular accounts repo](https://github.com/rhinestonewtf/awesome-modular-accounts). - -## Using this repo - -To install dependencies, run: - -```bash -pnpm install -``` - -To build the project, run: - -```bash -pnpm build -``` - -To run tests, run: - -```bash -pnpm test -``` - -To run the linter, run: - -```bash -pnpm lint:sol -``` - -## Contributing - -For feature or change requests, feel free to open a PR, start a discussion or get in touch with us. diff --git a/typescript/packages/account-modules/lib/modulekit/docs/Accounts.md b/typescript/packages/account-modules/lib/modulekit/docs/Accounts.md deleted file mode 100644 index ece9fbd..0000000 --- a/typescript/packages/account-modules/lib/modulekit/docs/Accounts.md +++ /dev/null @@ -1,45 +0,0 @@ -# Accounts - -ModuleKit currently supports the following accounts: - -- [ERC-7579 Reference Implementation](https://github.com/erc7579/erc7579-implementation) -- [Safe](https://github.com/safe-global/safe-smart-account) via [Safe7579](https://github.com/rhinestonewtf/safe7579) -- [Kernel](https://github.com/zerodevapp/kernel) - -To use different accounts, a developer can simply change the account on which their tests are run (the default is the ERC-7579 Reference Implementation). To do this, run: - -```bash -ACCOUNT_TYPE=... pnpm test -``` - -where the options are: - -- `DEFAULT`: The ERC-7579 Reference Implementation (note: this is equivalent to emitting the `ACCOUNT_TYPE` environment variable) -- `SAFE`: The Safe account -- `KERNEL`: The Kernel account - -## Differences - -While ModuleKit aims to abstract as much about the accounts away from the developer as possible, there are some differences between the accounts that are important to note. Further, the ModuleKit uses these accounts in a way that might not allow the developer to make use of all features that an account has or might be using a flow different from what will be used in production. To ensure that you benefit from the abstraction of these differences, use the ModuleKit provided helper functions, through the `ModuleKitHelpers` library, rather than creating these integration flows from scratch. This document is aimed at giving an overview of these differences. - -### ERC-7579 Reference Implementation - -The ERC-7579 Reference Implementation is a simple implementation of the ERC-7579 standard. It is fairly minimal and unopinionated and hence the ModuleKit uses it as the default account. It also does not provide any further features beyond what is required by the standard, so the ModuleKit uses all of its' features. - -### Safe - -The Safe7579 is an adapter to Safe accounts that allows them to become compatible with the standard. Concretely, this means that it will be installed as a fallback handler on the Safe. The Safe7579 is also fairly minimal, but there are some key differences to the ERC-7579 Reference Implementation: - -- The Safe7579 does not have access to the `msg.value` sent to the account. -- The Safe7579 stores the account config (ie installed modules) in the adapter itself rather than in the account. -- The Safe7579 has both global hooks that get called on every execution and signature specific hooks that get called based on the function signature of the target. -- The Safe7579 should be used with its' launchpad to bootstrap the Safe. This means that the first UserOperation will be sent to the `setUp` function, however this is abstracted away from the developer in the ModuleKit. - -### Kernel - -The Kernel is a more complex account that has a lot of unique features and design choices. The ModuleKit does not use all of these features and instead uses only those features that are shared by other accounts. The Kernel has the following differences: - -- It supports policies and signers, which are new module types that other accounts do not (yet) support. -- Hooks are related to both validators and executors where each of these has an associated hook. The ModuleKit uses a multiplexer as the hook for each of these so that global hooks can be emulated on the Kernel. Note, that this might differ from a production setup. -- Validators need to be assigned function selectors that they are allowed to validate. The ModuleKit abstracts this away from the developer and allows any validator to sign any UserOperation with any calldata. -- Kernel requires non-root validators with hooks to use `executeUserOp`. Hence, almost all transactions will use this function rather than the direct entrypoint into the account. diff --git a/typescript/packages/account-modules/lib/modulekit/foundry.toml b/typescript/packages/account-modules/lib/modulekit/foundry.toml deleted file mode 100644 index a6c6894..0000000 --- a/typescript/packages/account-modules/lib/modulekit/foundry.toml +++ /dev/null @@ -1,27 +0,0 @@ -[profile.default] -solc_version = "0.8.25" -evm_version = "cancun" -src = "src" -out = "out" -script = "script" -libs = ["node_modules"] -fs_permissions = [{ access = "read", path = "out-optimized" }, { access = "read-write", path = "gas_calculations" }] -allow_paths = ["*", "/"] -ignored_warnings_from = ["node_modules", "src/integrations"] -gas_limit = "18446744073709551615" -memory_limit = 2147483648 -verbosity = 3 - -[rpc_endpoints] -mainnet = "${MAINNET_RPC_URL}" -testnet = "${TESTNET_RPC_URL}" - -[fmt] -bracket_spacing = true -int_types = "long" -line_length = 100 -multiline_func_header = "all" -number_underscore = "thousands" -quote_style = "double" -tab_width = 4 -wrap_comments = true diff --git a/typescript/packages/account-modules/lib/modulekit/gas_calculations/.gitkeep b/typescript/packages/account-modules/lib/modulekit/gas_calculations/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/typescript/packages/account-modules/lib/modulekit/octanerc.json b/typescript/packages/account-modules/lib/modulekit/octanerc.json deleted file mode 100644 index bafdf8e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/octanerc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "pathsToAnalyze": ["**/src/integrations/.*", "**/src/module-bases/.*"] -} diff --git a/typescript/packages/account-modules/lib/modulekit/package.json b/typescript/packages/account-modules/lib/modulekit/package.json deleted file mode 100644 index 69614a9..0000000 --- a/typescript/packages/account-modules/lib/modulekit/package.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "name": "@rhinestone/modulekit", - "version": "0.5.9", - "description": "A development kit for building and testing smart account modules.", - "license": "GPL-3.0", - "author": { - "name": "Rhinestone", - "url": "https://rhinestone.wtf" - }, - "scripts": { - "build": "forge build", - "fmt": "forge fmt", - "fmt:check": "forge fmt --check", - "build:optimized": "FOUNDRY_PROFILE=optimized forge build", - "build:smt": "FOUNDRY_PROFILE=smt forge build", - "clean": "rm -rf artifacts broadcast cache docs out out-optimized out-svg", - "gas:report": "forge test --gas-report --mp \"./test/integration/**/*.sol\" --nmt \"test(Fuzz)?_RevertWhen_\\w{1,}?\"", - "gas:snapshot": "forge snapshot --mp \"./test/integration/**/*.sol\" --nmt \"test(Fuzz)?_RevertWhen_\\w{1,}?\"", - "gas:snapshot:optimized": "pnpm run build:optimized && FOUNDRY_PROFILE=test-optimized forge snapshot --mp \"./test/integration/**/*.sol\" --nmt \"test(Fork)?(Fuzz)?_RevertWhen_\\w{1,}?\"", - "lint:sol": "forge fmt --check && pnpm solhint \"{script,src,test}/**/*.sol\"", - "test": "forge test", - "test:lite": "FOUNDRY_PROFILE=lite forge test", - "test:via-ir": "forge test --via-ir", - "test:optimized": "pnpm run build:optimized && FOUNDRY_PROFILE=test-optimized forge test", - "test:accounts": "forge test && ACCOUNT_TYPE=SAFE forge test && ACCOUNT_TYPE=KERNEL forge test && ACCOUNT_TYPE=NEXUS forge test", - "changeset": "changeset", - "changeset:release": "pnpm build && changeset publish", - "changeset:version": "changeset version && pnpm install --lockfile-only" - }, - "dependencies": { - "@ERC4337/account-abstraction": "github:kopy-kat/account-abstraction#develop", - "@ERC4337/account-abstraction-v0.6": "github:eth-infinitism/account-abstraction#v0.6.0", - "@prb/math": "^4.1.0", - "@rhinestone/erc4337-validation": "^0.0.5", - "@rhinestone/sentinellist": "github:rhinestonewtf/sentinellist", - "ds-test": "github:dapphub/ds-test", - "excessively-safe-call": "github:nomad-xyz/ExcessivelySafeCall", - "forge-std": "github:foundry-rs/forge-std", - "solady": "github:vectorized/solady", - "solarray": "github:sablier-labs/solarray", - "solhint": "^5.0.5" - }, - "devDependencies": { - "@changesets/cli": "^2.27.12" - }, - "files": [ - "src", - "foundry.toml", - "remappings.txt" - ], - "homepage": "https://docs.rhinestone.wtf/modulekit", - "repository": { - "type": "git", - "url": "git+https://github.com/rhinestonewtf/modulekit.git" - }, - "bugs": { - "url": "https://github.com/rhinestonewtf/modulekit/issues" - }, - "keywords": [ - "account abstraction", - "smart account modules" - ], - "publishConfig": { - "access": "public" - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/pnpm-lock.yaml b/typescript/packages/account-modules/lib/modulekit/pnpm-lock.yaml deleted file mode 100644 index 6c78dbc..0000000 --- a/typescript/packages/account-modules/lib/modulekit/pnpm-lock.yaml +++ /dev/null @@ -1,4803 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@ERC4337/account-abstraction': - specifier: github:kopy-kat/account-abstraction#develop - version: accountabstraction@https://codeload.github.com/kopy-kat/account-abstraction/tar.gz/c5887153fbfe3ed09b2637cac39873f96d676f38(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)) - '@ERC4337/account-abstraction-v0.6': - specifier: github:eth-infinitism/account-abstraction#v0.6.0 - version: accountabstraction@https://codeload.github.com/eth-infinitism/account-abstraction/tar.gz/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)) - '@prb/math': - specifier: ^4.1.0 - version: 4.1.0 - '@rhinestone/erc4337-validation': - specifier: ^0.0.5 - version: 0.0.5(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)) - '@rhinestone/sentinellist': - specifier: github:rhinestonewtf/sentinellist - version: https://codeload.github.com/rhinestonewtf/sentinellist/tar.gz/e722c5cc68c570d535bc3c9f85b3ce90cdc38807 - ds-test: - specifier: github:dapphub/ds-test - version: https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0 - excessively-safe-call: - specifier: github:nomad-xyz/ExcessivelySafeCall - version: '@nomad-xyz/excessively-safe-call@https://codeload.github.com/nomad-xyz/ExcessivelySafeCall/tar.gz/81cd99ce3e69117d665d7601c330ea03b97acce0' - forge-std: - specifier: github:foundry-rs/forge-std - version: https://codeload.github.com/foundry-rs/forge-std/tar.gz/3b20d60d14b343ee4f908cb8079495c07f5e8981 - solady: - specifier: github:vectorized/solady - version: https://codeload.github.com/vectorized/solady/tar.gz/59f28399b7e9202bc6145b082bf7ff025b8b1ddc - solarray: - specifier: github:sablier-labs/solarray - version: https://codeload.github.com/sablier-labs/solarray/tar.gz/6bf10cb34cdace52a3ba5fe437e78cc82df92684 - solhint: - specifier: ^5.0.5 - version: 5.0.5(typescript@4.9.5) - devDependencies: - '@changesets/cli': - specifier: ^2.27.12 - version: 2.27.12 - -packages: - - '@babel/code-frame@7.26.2': - resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.25.9': - resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} - engines: {node: '>=6.9.0'} - - '@babel/runtime@7.26.7': - resolution: {integrity: sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==} - engines: {node: '>=6.9.0'} - - '@changesets/apply-release-plan@7.0.8': - resolution: {integrity: sha512-qjMUj4DYQ1Z6qHawsn7S71SujrExJ+nceyKKyI9iB+M5p9lCL55afuEd6uLBPRpLGWQwkwvWegDHtwHJb1UjpA==} - - '@changesets/assemble-release-plan@6.0.5': - resolution: {integrity: sha512-IgvBWLNKZd6k4t72MBTBK3nkygi0j3t3zdC1zrfusYo0KpdsvnDjrMM9vPnTCLCMlfNs55jRL4gIMybxa64FCQ==} - - '@changesets/changelog-git@0.2.0': - resolution: {integrity: sha512-bHOx97iFI4OClIT35Lok3sJAwM31VbUM++gnMBV16fdbtBhgYu4dxsphBF/0AZZsyAHMrnM0yFcj5gZM1py6uQ==} - - '@changesets/cli@2.27.12': - resolution: {integrity: sha512-9o3fOfHYOvBnyEn0mcahB7wzaA3P4bGJf8PNqGit5PKaMEFdsRixik+txkrJWd2VX+O6wRFXpxQL8j/1ANKE9g==} - hasBin: true - - '@changesets/config@3.0.5': - resolution: {integrity: sha512-QyXLSSd10GquX7hY0Mt4yQFMEeqnO5z/XLpbIr4PAkNNoQNKwDyiSrx4yd749WddusH1v3OSiA0NRAYmH/APpQ==} - - '@changesets/errors@0.2.0': - resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} - - '@changesets/get-dependents-graph@2.1.2': - resolution: {integrity: sha512-sgcHRkiBY9i4zWYBwlVyAjEM9sAzs4wYVwJUdnbDLnVG3QwAaia1Mk5P8M7kraTOZN+vBET7n8KyB0YXCbFRLQ==} - - '@changesets/get-release-plan@4.0.6': - resolution: {integrity: sha512-FHRwBkY7Eili04Y5YMOZb0ezQzKikTka4wL753vfUA5COSebt7KThqiuCN9BewE4/qFGgF/5t3AuzXx1/UAY4w==} - - '@changesets/get-version-range-type@0.4.0': - resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} - - '@changesets/git@3.0.2': - resolution: {integrity: sha512-r1/Kju9Y8OxRRdvna+nxpQIsMsRQn9dhhAZt94FLDeu0Hij2hnOozW8iqnHBgvu+KdnJppCveQwK4odwfw/aWQ==} - - '@changesets/logger@0.1.1': - resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} - - '@changesets/parse@0.4.0': - resolution: {integrity: sha512-TS/9KG2CdGXS27S+QxbZXgr8uPsP4yNJYb4BC2/NeFUj80Rni3TeD2qwWmabymxmrLo7JEsytXH1FbpKTbvivw==} - - '@changesets/pre@2.0.1': - resolution: {integrity: sha512-vvBJ/If4jKM4tPz9JdY2kGOgWmCowUYOi5Ycv8dyLnEE8FgpYYUo1mgJZxcdtGGP3aG8rAQulGLyyXGSLkIMTQ==} - - '@changesets/read@0.6.2': - resolution: {integrity: sha512-wjfQpJvryY3zD61p8jR87mJdyx2FIhEcdXhKUqkja87toMrP/3jtg/Yg29upN+N4Ckf525/uvV7a4tzBlpk6gg==} - - '@changesets/should-skip-package@0.1.1': - resolution: {integrity: sha512-H9LjLbF6mMHLtJIc/eHR9Na+MifJ3VxtgP/Y+XLn4BF7tDTEN1HNYtH6QMcjP1uxp9sjaFYmW8xqloaCi/ckTg==} - - '@changesets/types@4.1.0': - resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} - - '@changesets/types@6.0.0': - resolution: {integrity: sha512-b1UkfNulgKoWfqyHtzKS5fOZYSJO+77adgL7DLRDr+/7jhChN+QcHnbjiQVOz/U+Ts3PGNySq7diAItzDgugfQ==} - - '@changesets/write@0.3.2': - resolution: {integrity: sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw==} - - '@ethereumjs/rlp@4.0.1': - resolution: {integrity: sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==} - engines: {node: '>=14'} - hasBin: true - - '@ethereumjs/util@8.1.0': - resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} - engines: {node: '>=14'} - - '@ethersproject/abi@5.7.0': - resolution: {integrity: sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==} - - '@ethersproject/abstract-provider@5.7.0': - resolution: {integrity: sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==} - - '@ethersproject/abstract-signer@5.7.0': - resolution: {integrity: sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==} - - '@ethersproject/address@5.7.0': - resolution: {integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==} - - '@ethersproject/base64@5.7.0': - resolution: {integrity: sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==} - - '@ethersproject/basex@5.7.0': - resolution: {integrity: sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==} - - '@ethersproject/bignumber@5.7.0': - resolution: {integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==} - - '@ethersproject/bytes@5.7.0': - resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==} - - '@ethersproject/constants@5.7.0': - resolution: {integrity: sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==} - - '@ethersproject/contracts@5.7.0': - resolution: {integrity: sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==} - - '@ethersproject/hash@5.7.0': - resolution: {integrity: sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==} - - '@ethersproject/hdnode@5.7.0': - resolution: {integrity: sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==} - - '@ethersproject/json-wallets@5.7.0': - resolution: {integrity: sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==} - - '@ethersproject/keccak256@5.7.0': - resolution: {integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==} - - '@ethersproject/logger@5.7.0': - resolution: {integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==} - - '@ethersproject/networks@5.7.1': - resolution: {integrity: sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==} - - '@ethersproject/pbkdf2@5.7.0': - resolution: {integrity: sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==} - - '@ethersproject/properties@5.7.0': - resolution: {integrity: sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==} - - '@ethersproject/providers@5.7.2': - resolution: {integrity: sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==} - - '@ethersproject/random@5.7.0': - resolution: {integrity: sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==} - - '@ethersproject/rlp@5.7.0': - resolution: {integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==} - - '@ethersproject/sha2@5.7.0': - resolution: {integrity: sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==} - - '@ethersproject/signing-key@5.7.0': - resolution: {integrity: sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==} - - '@ethersproject/solidity@5.7.0': - resolution: {integrity: sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==} - - '@ethersproject/strings@5.7.0': - resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==} - - '@ethersproject/transactions@5.7.0': - resolution: {integrity: sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==} - - '@ethersproject/units@5.7.0': - resolution: {integrity: sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==} - - '@ethersproject/wallet@5.7.0': - resolution: {integrity: sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==} - - '@ethersproject/web@5.7.1': - resolution: {integrity: sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==} - - '@ethersproject/wordlists@5.7.0': - resolution: {integrity: sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==} - - '@fastify/busboy@2.1.1': - resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} - engines: {node: '>=14'} - - '@gnosis.pm/safe-contracts@1.3.0': - resolution: {integrity: sha512-1p+1HwGvxGUVzVkFjNzglwHrLNA67U/axP0Ct85FzzH8yhGJb4t9jDjPYocVMzLorDoWAfKicGy1akPY9jXRVw==} - peerDependencies: - ethers: ^5.1.4 - - '@manypkg/find-root@1.1.0': - resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} - - '@manypkg/get-packages@1.1.3': - resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} - - '@metamask/eth-sig-util@4.0.1': - resolution: {integrity: sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==} - engines: {node: '>=12.0.0'} - - '@noble/curves@1.4.2': - resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} - - '@noble/hashes@1.2.0': - resolution: {integrity: sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==} - - '@noble/hashes@1.4.0': - resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} - engines: {node: '>= 16'} - - '@noble/hashes@1.7.1': - resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==} - engines: {node: ^14.21.3 || >=16} - - '@noble/secp256k1@1.7.1': - resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@nomad-xyz/excessively-safe-call@https://codeload.github.com/nomad-xyz/ExcessivelySafeCall/tar.gz/81cd99ce3e69117d665d7601c330ea03b97acce0': - resolution: {tarball: https://codeload.github.com/nomad-xyz/ExcessivelySafeCall/tar.gz/81cd99ce3e69117d665d7601c330ea03b97acce0} - version: 0.0.1-rc.1 - - '@nomicfoundation/edr-darwin-arm64@0.6.5': - resolution: {integrity: sha512-A9zCCbbNxBpLgjS1kEJSpqxIvGGAX4cYbpDYCU2f3jVqOwaZ/NU761y1SvuCRVpOwhoCXqByN9b7HPpHi0L4hw==} - engines: {node: '>= 18'} - - '@nomicfoundation/edr-darwin-x64@0.6.5': - resolution: {integrity: sha512-x3zBY/v3R0modR5CzlL6qMfFMdgwd6oHrWpTkuuXnPFOX8SU31qq87/230f4szM+ukGK8Hi+mNq7Ro2VF4Fj+w==} - engines: {node: '>= 18'} - - '@nomicfoundation/edr-linux-arm64-gnu@0.6.5': - resolution: {integrity: sha512-HGpB8f1h8ogqPHTyUpyPRKZxUk2lu061g97dOQ/W4CxevI0s/qiw5DB3U3smLvSnBHKOzYS1jkxlMeGN01ky7A==} - engines: {node: '>= 18'} - - '@nomicfoundation/edr-linux-arm64-musl@0.6.5': - resolution: {integrity: sha512-ESvJM5Y9XC03fZg9KaQg3Hl+mbx7dsSkTIAndoJS7X2SyakpL9KZpOSYrDk135o8s9P9lYJdPOyiq+Sh+XoCbQ==} - engines: {node: '>= 18'} - - '@nomicfoundation/edr-linux-x64-gnu@0.6.5': - resolution: {integrity: sha512-HCM1usyAR1Ew6RYf5AkMYGvHBy64cPA5NMbaeY72r0mpKaH3txiMyydcHibByOGdQ8iFLWpyUdpl1egotw+Tgg==} - engines: {node: '>= 18'} - - '@nomicfoundation/edr-linux-x64-musl@0.6.5': - resolution: {integrity: sha512-nB2uFRyczhAvWUH7NjCsIO6rHnQrof3xcCe6Mpmnzfl2PYcGyxN7iO4ZMmRcQS7R1Y670VH6+8ZBiRn8k43m7A==} - engines: {node: '>= 18'} - - '@nomicfoundation/edr-win32-x64-msvc@0.6.5': - resolution: {integrity: sha512-B9QD/4DSSCFtWicO8A3BrsnitO1FPv7axB62wq5Q+qeJ50yJlTmyeGY3cw62gWItdvy2mh3fRM6L1LpnHiB77A==} - engines: {node: '>= 18'} - - '@nomicfoundation/edr@0.6.5': - resolution: {integrity: sha512-tAqMslLP+/2b2sZP4qe9AuGxG3OkQ5gGgHE4isUuq6dUVjwCRPFhAOhpdFl+OjY5P3yEv3hmq9HjUGRa2VNjng==} - engines: {node: '>= 18'} - - '@nomicfoundation/ethereumjs-common@4.0.4': - resolution: {integrity: sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==} - - '@nomicfoundation/ethereumjs-rlp@5.0.4': - resolution: {integrity: sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==} - engines: {node: '>=18'} - hasBin: true - - '@nomicfoundation/ethereumjs-tx@5.0.4': - resolution: {integrity: sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==} - engines: {node: '>=18'} - peerDependencies: - c-kzg: ^2.1.2 - peerDependenciesMeta: - c-kzg: - optional: true - - '@nomicfoundation/ethereumjs-util@9.0.4': - resolution: {integrity: sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==} - engines: {node: '>=18'} - peerDependencies: - c-kzg: ^2.1.2 - peerDependenciesMeta: - c-kzg: - optional: true - - '@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2': - resolution: {integrity: sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==} - engines: {node: '>= 12'} - - '@nomicfoundation/solidity-analyzer-darwin-x64@0.1.2': - resolution: {integrity: sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==} - engines: {node: '>= 12'} - - '@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.2': - resolution: {integrity: sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==} - engines: {node: '>= 12'} - - '@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.2': - resolution: {integrity: sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==} - engines: {node: '>= 12'} - - '@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.2': - resolution: {integrity: sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==} - engines: {node: '>= 12'} - - '@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.2': - resolution: {integrity: sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==} - engines: {node: '>= 12'} - - '@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.2': - resolution: {integrity: sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==} - engines: {node: '>= 12'} - - '@nomicfoundation/solidity-analyzer@0.1.2': - resolution: {integrity: sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==} - engines: {node: '>= 12'} - - '@nomiclabs/hardhat-etherscan@2.1.8': - resolution: {integrity: sha512-0+rj0SsZotVOcTLyDOxnOc3Gulo8upo0rsw/h+gBPcmtj91YqYJNhdARHoBxOhhE8z+5IUQPx+Dii04lXT14PA==} - deprecated: The @nomiclabs/hardhat-etherscan package is deprecated, please use @nomicfoundation/hardhat-verify instead - peerDependencies: - hardhat: ^2.0.4 - - '@openzeppelin/contracts@4.9.6': - resolution: {integrity: sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA==} - - '@openzeppelin/contracts@5.0.1': - resolution: {integrity: sha512-yQJaT5HDp9hYOOp4jTYxMsR02gdFZFXhewX5HW9Jo4fsqSVqqyIO/xTHdWDaKX5a3pv1txmf076Lziz+sO7L1w==} - - '@openzeppelin/contracts@5.2.0': - resolution: {integrity: sha512-bxjNie5z89W1Ea0NZLZluFh8PrFNn9DH8DQlujEok2yjsOlraUPKID5p1Wk3qdNbf6XkQ1Os2RvfiHrrXLHWKA==} - - '@pnpm/config.env-replace@1.1.0': - resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} - engines: {node: '>=12.22.0'} - - '@pnpm/network.ca-file@1.0.2': - resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} - engines: {node: '>=12.22.0'} - - '@pnpm/npm-conf@2.3.1': - resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==} - engines: {node: '>=12'} - - '@prb/math@4.1.0': - resolution: {integrity: sha512-ef5Xrlh3BeX4xT5/Wi810dpEPq2bYPndRxgFIaKSU1F/Op/s8af03kyom+mfU7gEpvfIZ46xu8W0duiHplbBMg==} - - '@rhinestone/erc4337-validation@0.0.5': - resolution: {integrity: sha512-+WzDOn7Cp7DGw4oLsnWtcfqMkLTJAfC3qdTCYcZdDuBuSNST/E+7Gsau+5Uu97IYgTc7suTo+5OiP5k+E2q79A==} - - '@rhinestone/sentinellist@https://codeload.github.com/rhinestonewtf/sentinellist/tar.gz/e722c5cc68c570d535bc3c9f85b3ce90cdc38807': - resolution: {tarball: https://codeload.github.com/rhinestonewtf/sentinellist/tar.gz/e722c5cc68c570d535bc3c9f85b3ce90cdc38807} - version: 1.0.1 - - '@scure/base@1.1.9': - resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==} - - '@scure/bip32@1.1.5': - resolution: {integrity: sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==} - - '@scure/bip32@1.4.0': - resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} - - '@scure/bip39@1.1.1': - resolution: {integrity: sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==} - - '@scure/bip39@1.3.0': - resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} - - '@sentry/core@5.30.0': - resolution: {integrity: sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==} - engines: {node: '>=6'} - - '@sentry/hub@5.30.0': - resolution: {integrity: sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==} - engines: {node: '>=6'} - - '@sentry/minimal@5.30.0': - resolution: {integrity: sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==} - engines: {node: '>=6'} - - '@sentry/node@5.30.0': - resolution: {integrity: sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==} - engines: {node: '>=6'} - - '@sentry/tracing@5.30.0': - resolution: {integrity: sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==} - engines: {node: '>=6'} - - '@sentry/types@5.30.0': - resolution: {integrity: sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==} - engines: {node: '>=6'} - - '@sentry/utils@5.30.0': - resolution: {integrity: sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==} - engines: {node: '>=6'} - - '@sindresorhus/is@5.6.0': - resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} - engines: {node: '>=14.16'} - - '@solidity-parser/parser@0.19.0': - resolution: {integrity: sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==} - - '@szmarczak/http-timer@5.0.1': - resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} - engines: {node: '>=14.16'} - - '@thehubbleproject/bls@0.5.1': - resolution: {integrity: sha512-g5zeMZ8js/yg6MjFoC+pt0eqfCL2jC46yLY1LbKNriyqftB1tE3jpG/FMMDIW3x9/yRg/AgUb8Nluqj15tQs+A==} - - '@typechain/hardhat@2.3.1': - resolution: {integrity: sha512-BQV8OKQi0KAzLXCdsPO0pZBNQQ6ra8A2ucC26uFX/kquRBtJu1yEyWnVSmtr07b5hyRoJRpzUeINLnyqz4/MAw==} - peerDependencies: - hardhat: ^2.0.10 - lodash: ^4.17.15 - typechain: ^5.1.2 - - '@types/bn.js@4.11.6': - resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} - - '@types/bn.js@5.1.6': - resolution: {integrity: sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==} - - '@types/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - - '@types/glob@7.2.0': - resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} - - '@types/http-cache-semantics@4.0.4': - resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} - - '@types/lru-cache@5.1.1': - resolution: {integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==} - - '@types/minimatch@5.1.2': - resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} - - '@types/mocha@9.1.1': - resolution: {integrity: sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==} - - '@types/ms@2.1.0': - resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - - '@types/node@12.20.55': - resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - - '@types/node@20.17.17': - resolution: {integrity: sha512-/WndGO4kIfMicEQLTi/mDANUu/iVUhT7KboZPdEqqHQ4aTS+3qT3U5gIqWDFV+XouorjfgGqvKILJeHhuQgFYg==} - - '@types/node@22.13.1': - resolution: {integrity: sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==} - - '@types/pbkdf2@3.1.2': - resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} - - '@types/prettier@2.7.3': - resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} - - '@types/qs@6.9.18': - resolution: {integrity: sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==} - - '@types/secp256k1@4.0.6': - resolution: {integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==} - - abbrev@1.0.9: - resolution: {integrity: sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==} - - accountabstraction@https://codeload.github.com/eth-infinitism/account-abstraction/tar.gz/7174d6d845618dbd11cee68eefa715f5263690b6: - resolution: {tarball: https://codeload.github.com/eth-infinitism/account-abstraction/tar.gz/7174d6d845618dbd11cee68eefa715f5263690b6} - version: 0.6.0 - - accountabstraction@https://codeload.github.com/kopy-kat/account-abstraction/tar.gz/c5887153fbfe3ed09b2637cac39873f96d676f38: - resolution: {tarball: https://codeload.github.com/kopy-kat/account-abstraction/tar.gz/c5887153fbfe3ed09b2637cac39873f96d676f38} - version: 0.7.0 - - adm-zip@0.4.16: - resolution: {integrity: sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==} - engines: {node: '>=0.3.0'} - - aes-js@3.0.0: - resolution: {integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==} - - aes-js@3.1.2: - resolution: {integrity: sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==} - - agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - - aggregate-error@3.1.0: - resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} - engines: {node: '>=8'} - - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - - amdefine@1.0.1: - resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==} - engines: {node: '>=0.4.2'} - - ansi-align@3.0.1: - resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} - - ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - - ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - antlr4@4.13.2: - resolution: {integrity: sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg==} - engines: {node: '>=16'} - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - array-back@1.0.4: - resolution: {integrity: sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw==} - engines: {node: '>=0.12.0'} - - array-back@2.0.0: - resolution: {integrity: sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==} - engines: {node: '>=4'} - - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - - ast-parents@0.0.1: - resolution: {integrity: sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==} - - astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} - - async@1.5.2: - resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - at-least-node@1.0.0: - resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} - engines: {node: '>= 4.0.0'} - - axios@0.21.4: - resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - base-x@3.0.10: - resolution: {integrity: sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==} - - bech32@1.1.4: - resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} - - better-path-resolve@1.0.0: - resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} - engines: {node: '>=4'} - - bignumber.js@9.1.2: - resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} - - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - - blakejs@1.2.1: - resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} - - bn.js@4.11.6: - resolution: {integrity: sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==} - - bn.js@4.12.1: - resolution: {integrity: sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==} - - bn.js@5.2.1: - resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} - - boxen@5.1.2: - resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} - engines: {node: '>=10'} - - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - brorand@1.1.0: - resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - - browser-stdout@1.3.1: - resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} - - browserify-aes@1.2.0: - resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} - - bs58@4.0.1: - resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} - - bs58check@2.1.2: - resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - buffer-xor@1.0.3: - resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} - - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - cacheable-lookup@7.0.0: - resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} - engines: {node: '>=14.16'} - - cacheable-request@10.2.14: - resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} - engines: {node: '>=14.16'} - - call-bind-apply-helpers@1.0.1: - resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} - engines: {node: '>= 0.4'} - - call-bound@1.0.3: - resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} - engines: {node: '>= 0.4'} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - - cbor@5.2.0: - resolution: {integrity: sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==} - engines: {node: '>=6.0.0'} - - chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - chardet@0.7.0: - resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - - ci-info@2.0.0: - resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} - - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - - cipher-base@1.0.6: - resolution: {integrity: sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==} - engines: {node: '>= 0.10'} - - clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} - - cli-boxes@2.2.1: - resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} - engines: {node: '>=6'} - - cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - - color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - - command-exists@1.2.9: - resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} - - command-line-args@4.0.7: - resolution: {integrity: sha512-aUdPvQRAyBvQd2n7jXcsMDz68ckBJELXNzBybCHOibUWEg0mWTnaYCSRU8h9R+aNRSvDihJtssSRCiDRpLaezA==} - hasBin: true - - commander@10.0.1: - resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} - engines: {node: '>=14'} - - commander@8.3.0: - resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} - engines: {node: '>= 12'} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - config-chain@1.1.13: - resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} - - cookie@0.4.2: - resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} - engines: {node: '>= 0.6'} - - cosmiconfig@8.3.6: - resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} - engines: {node: '>=14'} - peerDependencies: - typescript: '>=4.9.5' - peerDependenciesMeta: - typescript: - optional: true - - create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} - - create-hmac@1.1.7: - resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - death@1.1.0: - resolution: {integrity: sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==} - - debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decamelize@4.0.0: - resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} - engines: {node: '>=10'} - - decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - - deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - defer-to-connect@2.0.1: - resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} - engines: {node: '>=10'} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - detect-indent@6.1.0: - resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} - engines: {node: '>=8'} - - diff@5.2.0: - resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} - engines: {node: '>=0.3.1'} - - difflib@0.2.4: - resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==} - - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - - ds-test@https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0: - resolution: {tarball: https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0} - version: 1.0.0 - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - elliptic@6.5.4: - resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} - - elliptic@6.6.1: - resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - encode-utf8@1.0.3: - resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} - - enquirer@2.4.1: - resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} - engines: {node: '>=8.6'} - - env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} - - error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - escodegen@1.8.1: - resolution: {integrity: sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==} - engines: {node: '>=0.12.0'} - hasBin: true - - esprima@2.7.3: - resolution: {integrity: sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==} - engines: {node: '>=0.10.0'} - hasBin: true - - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - - estraverse@1.9.3: - resolution: {integrity: sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==} - engines: {node: '>=0.10.0'} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - ethereum-bloom-filters@1.2.0: - resolution: {integrity: sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA==} - - ethereum-cryptography@0.1.3: - resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} - - ethereum-cryptography@1.2.0: - resolution: {integrity: sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==} - - ethereum-cryptography@2.2.1: - resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==} - - ethereumjs-abi@0.6.8: - resolution: {integrity: sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==} - deprecated: This library has been deprecated and usage is discouraged. - - ethereumjs-util@6.2.1: - resolution: {integrity: sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==} - - ethereumjs-util@7.1.5: - resolution: {integrity: sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==} - engines: {node: '>=10.0.0'} - - ethereumjs-wallet@1.0.2: - resolution: {integrity: sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA==} - deprecated: 'New package name format for new versions: @ethereumjs/wallet. Please update.' - - ethers@5.7.2: - resolution: {integrity: sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==} - - ethjs-unit@0.1.6: - resolution: {integrity: sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==} - engines: {node: '>=6.5.0', npm: '>=3'} - - ethjs-util@0.1.6: - resolution: {integrity: sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==} - engines: {node: '>=6.5.0', npm: '>=3'} - - evp_bytestokey@1.0.3: - resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} - - extendable-error@0.1.7: - resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} - - external-editor@3.1.0: - resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} - engines: {node: '>=4'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fast-uri@3.0.6: - resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} - - fastq@1.19.0: - resolution: {integrity: sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==} - - fdir@6.4.3: - resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - find-replace@1.0.3: - resolution: {integrity: sha512-KrUnjzDCD9426YnCP56zGYy/eieTnhtK6Vn++j+JJzmlsWWwEkDnsyVF575spT6HJ6Ow9tlbT3TQTDsa+O4UWA==} - engines: {node: '>=4.0.0'} - - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat@5.0.2: - resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} - hasBin: true - - fmix@0.1.0: - resolution: {integrity: sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==} - - follow-redirects@1.15.9: - resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - - forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/3b20d60d14b343ee4f908cb8079495c07f5e8981: - resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/3b20d60d14b343ee4f908cb8079495c07f5e8981} - version: 1.9.6 - - forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/8a225d81aa8e2e013580564588c79abb65eacc9e: - resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/8a225d81aa8e2e013580564588c79abb65eacc9e} - version: 1.9.3 - - form-data-encoder@2.1.4: - resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} - engines: {node: '>= 14.17'} - - form-data@4.0.1: - resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} - engines: {node: '>= 6'} - - fp-ts@1.19.3: - resolution: {integrity: sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==} - - fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} - - fs-extra@7.0.1: - resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} - engines: {node: '>=6 <7 || >=8'} - - fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - - fs-extra@9.1.0: - resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} - engines: {node: '>=10'} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-intrinsic@1.2.7: - resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - - ghost-testrpc@0.0.2: - resolution: {integrity: sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==} - hasBin: true - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob@5.0.15: - resolution: {integrity: sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==} - deprecated: Glob versions prior to v9 are no longer supported - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - - glob@8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} - engines: {node: '>=12'} - deprecated: Glob versions prior to v9 are no longer supported - - global-modules@2.0.0: - resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} - engines: {node: '>=6'} - - global-prefix@3.0.0: - resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} - engines: {node: '>=6'} - - globby@10.0.2: - resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==} - engines: {node: '>=8'} - - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - got@12.6.1: - resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==} - engines: {node: '>=14.16'} - - graceful-fs@4.2.10: - resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - handlebars@4.7.8: - resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} - engines: {node: '>=0.4.7'} - hasBin: true - - hardhat-deploy-ethers@0.3.0-beta.13: - resolution: {integrity: sha512-PdWVcKB9coqWV1L7JTpfXRCI91Cgwsm7KLmBcwZ8f0COSm1xtABHZTyz3fvF6p42cTnz1VM0QnfDvMFlIRkSNw==} - peerDependencies: - ethers: ^5.0.0 - hardhat: ^2.0.0 - - hardhat-deploy@0.11.45: - resolution: {integrity: sha512-aC8UNaq3JcORnEUIwV945iJuvBwi65tjHVDU3v6mOcqik7WAzHVCJ7cwmkkipsHrWysrB5YvGF1q9S1vIph83w==} - - hardhat@2.22.17: - resolution: {integrity: sha512-tDlI475ccz4d/dajnADUTRc1OJ3H8fpP9sWhXhBPpYsQOg8JHq5xrDimo53UhWPl7KJmAeDCm1bFG74xvpGRpg==} - hasBin: true - peerDependencies: - ts-node: '*' - typescript: '*' - peerDependenciesMeta: - ts-node: - optional: true - typescript: - optional: true - - has-flag@1.0.0: - resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==} - engines: {node: '>=0.10.0'} - - has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - hash-base@3.1.0: - resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} - engines: {node: '>=4'} - - hash.js@1.1.7: - resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - - heap@0.2.7: - resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} - - hmac-drbg@1.0.1: - resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} - - http-cache-semantics@4.1.1: - resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} - - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - - http2-wrapper@2.2.1: - resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==} - engines: {node: '>=10.19.0'} - - https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} - - human-id@1.0.2: - resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} - - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - immutable@4.3.7: - resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} - - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - - imul@1.0.1: - resolution: {integrity: sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA==} - engines: {node: '>=0.10.0'} - - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - - interpret@1.4.0: - resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} - engines: {node: '>= 0.10'} - - io-ts@1.10.4: - resolution: {integrity: sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==} - - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-hex-prefixed@1.0.0: - resolution: {integrity: sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==} - engines: {node: '>=6.5.0', npm: '>=3'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-plain-obj@2.1.0: - resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} - engines: {node: '>=8'} - - is-subdir@1.2.0: - resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} - engines: {node: '>=4'} - - is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - - is-windows@1.0.2: - resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} - engines: {node: '>=0.10.0'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - js-sha3@0.8.0: - resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true - - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - - json-stream-stringify@3.1.6: - resolution: {integrity: sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==} - engines: {node: '>=7.10.1'} - - jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - - jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - - jsonschema@1.5.0: - resolution: {integrity: sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==} - - keccak@3.0.4: - resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} - engines: {node: '>=10.0.0'} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - - latest-version@7.0.0: - resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==} - engines: {node: '>=14.16'} - - levn@0.3.0: - resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} - engines: {node: '>= 0.8.0'} - - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash.startcase@4.4.0: - resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} - - lodash.truncate@4.4.2: - resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} - - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - - log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - - lowercase-keys@3.0.0: - resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - lru_map@0.3.3: - resolution: {integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==} - - match-all@1.2.6: - resolution: {integrity: sha512-0EESkXiTkWzrQQntBu2uzKvLu6vVkUGz40nGPbSZuegcfE5UuSzNjLaIu76zJWuaT/2I3Z/8M06OlUOZLGwLlQ==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - mcl-wasm@1.8.0: - resolution: {integrity: sha512-j6kekpd/i6XLHKgUPLPOqts3EUIw+lOFPdyQ4cqepONZ2R/dtfc3+DnYMJXKXw4JF8c6hfcBZ04gbYWOXurv+Q==} - engines: {node: '>=14.17'} - - md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} - - memorystream@0.3.1: - resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} - engines: {node: '>= 0.10.0'} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micro-ftch@0.3.1: - resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - - mimic-response@4.0.0: - resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - - minimalistic-crypto-utils@1.0.1: - resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - - mnemonist@0.38.5: - resolution: {integrity: sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==} - - mocha@10.8.2: - resolution: {integrity: sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==} - engines: {node: '>= 14.0.0'} - hasBin: true - - mri@1.2.0: - resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} - engines: {node: '>=4'} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - murmur-128@0.2.1: - resolution: {integrity: sha512-WseEgiRkI6aMFBbj8Cg9yBj/y+OdipwVC7zUo3W2W1JAJITwouUOtpqsmGSg67EQmwwSyod7hsVsWY5LsrfQVg==} - - neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - - node-addon-api@2.0.2: - resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} - - node-addon-api@5.1.0: - resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} - - node-emoji@1.11.0: - resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} - - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - - node-gyp-build@4.8.4: - resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} - hasBin: true - - nofilter@1.0.4: - resolution: {integrity: sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==} - engines: {node: '>=8'} - - nopt@3.0.6: - resolution: {integrity: sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==} - hasBin: true - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - normalize-url@8.0.1: - resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} - engines: {node: '>=14.16'} - - number-to-bn@1.7.0: - resolution: {integrity: sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==} - engines: {node: '>=6.5.0', npm: '>=3'} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - obliterator@2.0.5: - resolution: {integrity: sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - optionator@0.8.3: - resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} - engines: {node: '>= 0.8.0'} - - os-tmpdir@1.0.2: - resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} - engines: {node: '>=0.10.0'} - - outdent@0.5.0: - resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} - - p-cancelable@3.0.0: - resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} - engines: {node: '>=12.20'} - - p-filter@2.1.0: - resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} - engines: {node: '>=8'} - - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - p-map@2.1.0: - resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} - engines: {node: '>=6'} - - p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} - - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - - package-json@8.1.1: - resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} - engines: {node: '>=14.16'} - - package-manager-detector@0.2.9: - resolution: {integrity: sha512-+vYvA/Y31l8Zk8dwxHhL3JfTuHPm6tlxM2A3GeQyl7ovYnSp1+mzAxClxaOr0qO1TtPxbQxetI7v5XqKLJZk7Q==} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - - pbkdf2@3.1.2: - resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} - engines: {node: '>=0.12'} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} - engines: {node: '>=12'} - - pify@4.0.1: - resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} - engines: {node: '>=6'} - - pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - - prelude-ls@1.1.2: - resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} - engines: {node: '>= 0.8.0'} - - prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} - hasBin: true - - proto-list@1.2.4: - resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} - engines: {node: '>=0.6'} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - quick-lru@5.1.1: - resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} - engines: {node: '>=10'} - - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - - raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} - engines: {node: '>= 0.8'} - - rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - - read-yaml-file@1.1.0: - resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} - engines: {node: '>=6'} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - - readdirp@4.1.1: - resolution: {integrity: sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==} - engines: {node: '>= 14.18.0'} - - rechoir@0.6.2: - resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} - engines: {node: '>= 0.10'} - - recursive-readdir@2.2.3: - resolution: {integrity: sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==} - engines: {node: '>=6.0.0'} - - regenerator-runtime@0.14.1: - resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - - registry-auth-token@5.0.3: - resolution: {integrity: sha512-1bpc9IyC+e+CNFRaWyn77tk4xGG4PPUyfakSmA6F6cvUDjrm58dfyJ3II+9yb10EDkHoy1LaPSmHaWLOH3m6HA==} - engines: {node: '>=14'} - - registry-url@6.0.1: - resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} - engines: {node: '>=12'} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - - resolve-alpn@1.2.1: - resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - - resolve@1.1.7: - resolution: {integrity: sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==} - - resolve@1.17.0: - resolution: {integrity: sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==} - - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} - engines: {node: '>= 0.4'} - hasBin: true - - responselike@3.0.0: - resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} - engines: {node: '>=14.16'} - - reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - ripemd160@2.0.2: - resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} - - rlp@2.2.7: - resolution: {integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==} - hasBin: true - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - sc-istanbul@0.4.6: - resolution: {integrity: sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==} - hasBin: true - - scrypt-js@3.0.1: - resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} - - secp256k1@4.0.4: - resolution: {integrity: sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==} - engines: {node: '>=18.0.0'} - - semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.1: - resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} - engines: {node: '>=10'} - hasBin: true - - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - - setimmediate@1.0.5: - resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} - hasBin: true - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - shelljs@0.8.5: - resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} - engines: {node: '>=4'} - hasBin: true - - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - - slice-ansi@4.0.0: - resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} - engines: {node: '>=10'} - - solady@https://codeload.github.com/vectorized/solady/tar.gz/59f28399b7e9202bc6145b082bf7ff025b8b1ddc: - resolution: {tarball: https://codeload.github.com/vectorized/solady/tar.gz/59f28399b7e9202bc6145b082bf7ff025b8b1ddc} - version: 0.1.6 - - solarray@https://codeload.github.com/sablier-labs/solarray/tar.gz/6bf10cb34cdace52a3ba5fe437e78cc82df92684: - resolution: {tarball: https://codeload.github.com/sablier-labs/solarray/tar.gz/6bf10cb34cdace52a3ba5fe437e78cc82df92684} - version: 1.0.0 - - solc@0.8.26: - resolution: {integrity: sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==} - engines: {node: '>=10.0.0'} - hasBin: true - - solhint@5.0.5: - resolution: {integrity: sha512-WrnG6T+/UduuzSWsSOAbfq1ywLUDwNea3Gd5hg6PS+pLUm8lz2ECNr0beX609clBxmDeZ3676AiA9nPDljmbJQ==} - hasBin: true - - solidity-coverage@0.8.14: - resolution: {integrity: sha512-ItAAObe5GaEOp20kXC2BZRnph+9P7Rtoqg2mQc2SXGEHgSDF2wWd1Wxz3ntzQWXkbCtIIGdJT918HG00cObwbA==} - hasBin: true - peerDependencies: - hardhat: ^2.11.0 - - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - - source-map@0.2.0: - resolution: {integrity: sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==} - engines: {node: '>=0.8.0'} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - spawndamnit@3.0.1: - resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} - - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - - stacktrace-parser@0.1.10: - resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} - engines: {node: '>=6'} - - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - - strip-hex-prefix@1.0.0: - resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} - engines: {node: '>=6.5.0', npm: '>=3'} - - strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - supports-color@3.2.3: - resolution: {integrity: sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==} - engines: {node: '>=0.8.0'} - - supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - table@6.9.0: - resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} - engines: {node: '>=10.0.0'} - - term-size@2.2.1: - resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} - engines: {node: '>=8'} - - test-value@2.1.0: - resolution: {integrity: sha512-+1epbAxtKeXttkGFMTX9H42oqzOTufR1ceCF+GYA5aOmvaPq9wd4PUS8329fn2RRLGNeUkgRLnVpycjx8DsO2w==} - engines: {node: '>=0.10.0'} - - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - - tinyglobby@0.2.10: - resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} - engines: {node: '>=12.0.0'} - - tmp@0.0.33: - resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} - engines: {node: '>=0.6.0'} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - - ts-essentials@7.0.3: - resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==} - peerDependencies: - typescript: '>=3.7.0' - - tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - - tsort@0.0.1: - resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} - - tweetnacl-util@0.15.1: - resolution: {integrity: sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==} - - tweetnacl@1.0.3: - resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} - - type-check@0.3.2: - resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} - engines: {node: '>= 0.8.0'} - - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - - type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - - type-fest@0.7.1: - resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} - engines: {node: '>=8'} - - typechain@5.2.0: - resolution: {integrity: sha512-0INirvQ+P+MwJOeMct+WLkUE4zov06QxC96D+i3uGFEHoiSkZN70MKDQsaj8zkL86wQwByJReI2e7fOUwECFuw==} - hasBin: true - peerDependencies: - typescript: '>=4.1.0' - - typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} - hasBin: true - - typical@2.6.1: - resolution: {integrity: sha512-ofhi8kjIje6npGozTip9Fr8iecmYfEbS06i0JnIg+rh51KakryWF4+jX8lLKZVhy6N+ID45WYSFCxPOdTWCzNg==} - - uglify-js@3.19.3: - resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} - engines: {node: '>=0.8.0'} - hasBin: true - - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - - undici-types@6.20.0: - resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} - - undici@5.28.5: - resolution: {integrity: sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==} - engines: {node: '>=14.0'} - - universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - utf8@3.0.0: - resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true - - web3-utils@1.10.4: - resolution: {integrity: sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==} - engines: {node: '>=8.0.0'} - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - - which@1.3.1: - resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} - hasBin: true - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - widest-line@3.1.0: - resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} - engines: {node: '>=8'} - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - - workerpool@6.5.1: - resolution: {integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - ws@7.4.6: - resolution: {integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==} - 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 - - ws@7.5.10: - resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} - 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 - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} - engines: {node: '>=10'} - - yargs-unparser@2.0.0: - resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} - engines: {node: '>=10'} - - yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - zksync-web3@0.14.4: - resolution: {integrity: sha512-kYehMD/S6Uhe1g434UnaMN+sBr9nQm23Ywn0EUP5BfQCsbjcr3ORuS68PosZw8xUTu3pac7G6YMSnNHk+fwzvg==} - deprecated: This package has been deprecated in favor of zksync-ethers@5.0.0 - peerDependencies: - ethers: ^5.7.0 - -snapshots: - - '@babel/code-frame@7.26.2': - dependencies: - '@babel/helper-validator-identifier': 7.25.9 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/helper-validator-identifier@7.25.9': {} - - '@babel/runtime@7.26.7': - dependencies: - regenerator-runtime: 0.14.1 - - '@changesets/apply-release-plan@7.0.8': - dependencies: - '@changesets/config': 3.0.5 - '@changesets/get-version-range-type': 0.4.0 - '@changesets/git': 3.0.2 - '@changesets/should-skip-package': 0.1.1 - '@changesets/types': 6.0.0 - '@manypkg/get-packages': 1.1.3 - detect-indent: 6.1.0 - fs-extra: 7.0.1 - lodash.startcase: 4.4.0 - outdent: 0.5.0 - prettier: 2.8.8 - resolve-from: 5.0.0 - semver: 7.7.1 - - '@changesets/assemble-release-plan@6.0.5': - dependencies: - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.1.2 - '@changesets/should-skip-package': 0.1.1 - '@changesets/types': 6.0.0 - '@manypkg/get-packages': 1.1.3 - semver: 7.7.1 - - '@changesets/changelog-git@0.2.0': - dependencies: - '@changesets/types': 6.0.0 - - '@changesets/cli@2.27.12': - dependencies: - '@changesets/apply-release-plan': 7.0.8 - '@changesets/assemble-release-plan': 6.0.5 - '@changesets/changelog-git': 0.2.0 - '@changesets/config': 3.0.5 - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.1.2 - '@changesets/get-release-plan': 4.0.6 - '@changesets/git': 3.0.2 - '@changesets/logger': 0.1.1 - '@changesets/pre': 2.0.1 - '@changesets/read': 0.6.2 - '@changesets/should-skip-package': 0.1.1 - '@changesets/types': 6.0.0 - '@changesets/write': 0.3.2 - '@manypkg/get-packages': 1.1.3 - ansi-colors: 4.1.3 - ci-info: 3.9.0 - enquirer: 2.4.1 - external-editor: 3.1.0 - fs-extra: 7.0.1 - mri: 1.2.0 - p-limit: 2.3.0 - package-manager-detector: 0.2.9 - picocolors: 1.1.1 - resolve-from: 5.0.0 - semver: 7.7.1 - spawndamnit: 3.0.1 - term-size: 2.2.1 - - '@changesets/config@3.0.5': - dependencies: - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.1.2 - '@changesets/logger': 0.1.1 - '@changesets/types': 6.0.0 - '@manypkg/get-packages': 1.1.3 - fs-extra: 7.0.1 - micromatch: 4.0.8 - - '@changesets/errors@0.2.0': - dependencies: - extendable-error: 0.1.7 - - '@changesets/get-dependents-graph@2.1.2': - dependencies: - '@changesets/types': 6.0.0 - '@manypkg/get-packages': 1.1.3 - picocolors: 1.1.1 - semver: 7.7.1 - - '@changesets/get-release-plan@4.0.6': - dependencies: - '@changesets/assemble-release-plan': 6.0.5 - '@changesets/config': 3.0.5 - '@changesets/pre': 2.0.1 - '@changesets/read': 0.6.2 - '@changesets/types': 6.0.0 - '@manypkg/get-packages': 1.1.3 - - '@changesets/get-version-range-type@0.4.0': {} - - '@changesets/git@3.0.2': - dependencies: - '@changesets/errors': 0.2.0 - '@manypkg/get-packages': 1.1.3 - is-subdir: 1.2.0 - micromatch: 4.0.8 - spawndamnit: 3.0.1 - - '@changesets/logger@0.1.1': - dependencies: - picocolors: 1.1.1 - - '@changesets/parse@0.4.0': - dependencies: - '@changesets/types': 6.0.0 - js-yaml: 3.14.1 - - '@changesets/pre@2.0.1': - dependencies: - '@changesets/errors': 0.2.0 - '@changesets/types': 6.0.0 - '@manypkg/get-packages': 1.1.3 - fs-extra: 7.0.1 - - '@changesets/read@0.6.2': - dependencies: - '@changesets/git': 3.0.2 - '@changesets/logger': 0.1.1 - '@changesets/parse': 0.4.0 - '@changesets/types': 6.0.0 - fs-extra: 7.0.1 - p-filter: 2.1.0 - picocolors: 1.1.1 - - '@changesets/should-skip-package@0.1.1': - dependencies: - '@changesets/types': 6.0.0 - '@manypkg/get-packages': 1.1.3 - - '@changesets/types@4.1.0': {} - - '@changesets/types@6.0.0': {} - - '@changesets/write@0.3.2': - dependencies: - '@changesets/types': 6.0.0 - fs-extra: 7.0.1 - human-id: 1.0.2 - prettier: 2.8.8 - - '@ethereumjs/rlp@4.0.1': {} - - '@ethereumjs/util@8.1.0': - dependencies: - '@ethereumjs/rlp': 4.0.1 - ethereum-cryptography: 2.2.1 - micro-ftch: 0.3.1 - - '@ethersproject/abi@5.7.0': - 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 - - '@ethersproject/abstract-provider@5.7.0': - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/networks': 5.7.1 - '@ethersproject/properties': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/web': 5.7.1 - - '@ethersproject/abstract-signer@5.7.0': - 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 - - '@ethersproject/address@5.7.0': - 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 - - '@ethersproject/base64@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - - '@ethersproject/basex@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/properties': 5.7.0 - - '@ethersproject/bignumber@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - bn.js: 5.2.1 - - '@ethersproject/bytes@5.7.0': - dependencies: - '@ethersproject/logger': 5.7.0 - - '@ethersproject/constants@5.7.0': - dependencies: - '@ethersproject/bignumber': 5.7.0 - - '@ethersproject/contracts@5.7.0': - 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 - - '@ethersproject/hash@5.7.0': - 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 - - '@ethersproject/hdnode@5.7.0': - 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 - - '@ethersproject/json-wallets@5.7.0': - 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 - - '@ethersproject/keccak256@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - js-sha3: 0.8.0 - - '@ethersproject/logger@5.7.0': {} - - '@ethersproject/networks@5.7.1': - dependencies: - '@ethersproject/logger': 5.7.0 - - '@ethersproject/pbkdf2@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/sha2': 5.7.0 - - '@ethersproject/properties@5.7.0': - dependencies: - '@ethersproject/logger': 5.7.0 - - '@ethersproject/providers@5.7.2': - 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.1 - '@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.1 - bech32: 1.1.4 - ws: 7.4.6 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@ethersproject/random@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - - '@ethersproject/rlp@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - - '@ethersproject/sha2@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - hash.js: 1.1.7 - - '@ethersproject/signing-key@5.7.0': - 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 - - '@ethersproject/solidity@5.7.0': - 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 - - '@ethersproject/strings@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/logger': 5.7.0 - - '@ethersproject/transactions@5.7.0': - 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 - - '@ethersproject/units@5.7.0': - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/logger': 5.7.0 - - '@ethersproject/wallet@5.7.0': - 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 - - '@ethersproject/web@5.7.1': - 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 - - '@ethersproject/wordlists@5.7.0': - 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 - - '@fastify/busboy@2.1.1': {} - - '@gnosis.pm/safe-contracts@1.3.0(ethers@5.7.2)': - dependencies: - ethers: 5.7.2 - - '@manypkg/find-root@1.1.0': - dependencies: - '@babel/runtime': 7.26.7 - '@types/node': 12.20.55 - find-up: 4.1.0 - fs-extra: 8.1.0 - - '@manypkg/get-packages@1.1.3': - dependencies: - '@babel/runtime': 7.26.7 - '@changesets/types': 4.1.0 - '@manypkg/find-root': 1.1.0 - fs-extra: 8.1.0 - globby: 11.1.0 - read-yaml-file: 1.1.0 - - '@metamask/eth-sig-util@4.0.1': - 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 - - '@noble/curves@1.4.2': - dependencies: - '@noble/hashes': 1.4.0 - - '@noble/hashes@1.2.0': {} - - '@noble/hashes@1.4.0': {} - - '@noble/hashes@1.7.1': {} - - '@noble/secp256k1@1.7.1': {} - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.0 - - '@nomad-xyz/excessively-safe-call@https://codeload.github.com/nomad-xyz/ExcessivelySafeCall/tar.gz/81cd99ce3e69117d665d7601c330ea03b97acce0': {} - - '@nomicfoundation/edr-darwin-arm64@0.6.5': {} - - '@nomicfoundation/edr-darwin-x64@0.6.5': {} - - '@nomicfoundation/edr-linux-arm64-gnu@0.6.5': {} - - '@nomicfoundation/edr-linux-arm64-musl@0.6.5': {} - - '@nomicfoundation/edr-linux-x64-gnu@0.6.5': {} - - '@nomicfoundation/edr-linux-x64-musl@0.6.5': {} - - '@nomicfoundation/edr-win32-x64-msvc@0.6.5': {} - - '@nomicfoundation/edr@0.6.5': - dependencies: - '@nomicfoundation/edr-darwin-arm64': 0.6.5 - '@nomicfoundation/edr-darwin-x64': 0.6.5 - '@nomicfoundation/edr-linux-arm64-gnu': 0.6.5 - '@nomicfoundation/edr-linux-arm64-musl': 0.6.5 - '@nomicfoundation/edr-linux-x64-gnu': 0.6.5 - '@nomicfoundation/edr-linux-x64-musl': 0.6.5 - '@nomicfoundation/edr-win32-x64-msvc': 0.6.5 - - '@nomicfoundation/ethereumjs-common@4.0.4': - dependencies: - '@nomicfoundation/ethereumjs-util': 9.0.4 - transitivePeerDependencies: - - c-kzg - - '@nomicfoundation/ethereumjs-rlp@5.0.4': {} - - '@nomicfoundation/ethereumjs-tx@5.0.4': - dependencies: - '@nomicfoundation/ethereumjs-common': 4.0.4 - '@nomicfoundation/ethereumjs-rlp': 5.0.4 - '@nomicfoundation/ethereumjs-util': 9.0.4 - ethereum-cryptography: 0.1.3 - - '@nomicfoundation/ethereumjs-util@9.0.4': - dependencies: - '@nomicfoundation/ethereumjs-rlp': 5.0.4 - ethereum-cryptography: 0.1.3 - - '@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2': - optional: true - - '@nomicfoundation/solidity-analyzer-darwin-x64@0.1.2': - optional: true - - '@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.2': - optional: true - - '@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.2': - optional: true - - '@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.2': - optional: true - - '@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.2': - optional: true - - '@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.2': - optional: true - - '@nomicfoundation/solidity-analyzer@0.1.2': - optionalDependencies: - '@nomicfoundation/solidity-analyzer-darwin-arm64': 0.1.2 - '@nomicfoundation/solidity-analyzer-darwin-x64': 0.1.2 - '@nomicfoundation/solidity-analyzer-linux-arm64-gnu': 0.1.2 - '@nomicfoundation/solidity-analyzer-linux-arm64-musl': 0.1.2 - '@nomicfoundation/solidity-analyzer-linux-x64-gnu': 0.1.2 - '@nomicfoundation/solidity-analyzer-linux-x64-musl': 0.1.2 - '@nomicfoundation/solidity-analyzer-win32-x64-msvc': 0.1.2 - - '@nomiclabs/hardhat-etherscan@2.1.8(hardhat@2.22.17(typescript@4.9.5))': - dependencies: - '@ethersproject/abi': 5.7.0 - '@ethersproject/address': 5.7.0 - cbor: 5.2.0 - debug: 4.4.0(supports-color@8.1.1) - fs-extra: 7.0.1 - hardhat: 2.22.17(typescript@4.9.5) - node-fetch: 2.7.0 - semver: 6.3.1 - transitivePeerDependencies: - - encoding - - supports-color - - '@openzeppelin/contracts@4.9.6': {} - - '@openzeppelin/contracts@5.0.1': {} - - '@openzeppelin/contracts@5.2.0': {} - - '@pnpm/config.env-replace@1.1.0': {} - - '@pnpm/network.ca-file@1.0.2': - dependencies: - graceful-fs: 4.2.10 - - '@pnpm/npm-conf@2.3.1': - dependencies: - '@pnpm/config.env-replace': 1.1.0 - '@pnpm/network.ca-file': 1.0.2 - config-chain: 1.1.13 - - '@prb/math@4.1.0': {} - - '@rhinestone/erc4337-validation@0.0.5(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5))': - dependencies: - '@openzeppelin/contracts': 5.0.1 - account-abstraction: accountabstraction@https://codeload.github.com/kopy-kat/account-abstraction/tar.gz/c5887153fbfe3ed09b2637cac39873f96d676f38(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)) - account-abstraction-v0.6: accountabstraction@https://codeload.github.com/eth-infinitism/account-abstraction/tar.gz/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)) - ds-test: https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0 - forge-std: https://codeload.github.com/foundry-rs/forge-std/tar.gz/8a225d81aa8e2e013580564588c79abb65eacc9e - prettier: 2.8.8 - solady: https://codeload.github.com/vectorized/solady/tar.gz/59f28399b7e9202bc6145b082bf7ff025b8b1ddc - transitivePeerDependencies: - - bufferutil - - encoding - - ethers - - hardhat - - lodash - - supports-color - - typechain - - utf-8-validate - - '@rhinestone/sentinellist@https://codeload.github.com/rhinestonewtf/sentinellist/tar.gz/e722c5cc68c570d535bc3c9f85b3ce90cdc38807': - dependencies: - forge-std: https://codeload.github.com/foundry-rs/forge-std/tar.gz/3b20d60d14b343ee4f908cb8079495c07f5e8981 - - '@scure/base@1.1.9': {} - - '@scure/bip32@1.1.5': - dependencies: - '@noble/hashes': 1.2.0 - '@noble/secp256k1': 1.7.1 - '@scure/base': 1.1.9 - - '@scure/bip32@1.4.0': - dependencies: - '@noble/curves': 1.4.2 - '@noble/hashes': 1.4.0 - '@scure/base': 1.1.9 - - '@scure/bip39@1.1.1': - dependencies: - '@noble/hashes': 1.2.0 - '@scure/base': 1.1.9 - - '@scure/bip39@1.3.0': - dependencies: - '@noble/hashes': 1.4.0 - '@scure/base': 1.1.9 - - '@sentry/core@5.30.0': - dependencies: - '@sentry/hub': 5.30.0 - '@sentry/minimal': 5.30.0 - '@sentry/types': 5.30.0 - '@sentry/utils': 5.30.0 - tslib: 1.14.1 - - '@sentry/hub@5.30.0': - dependencies: - '@sentry/types': 5.30.0 - '@sentry/utils': 5.30.0 - tslib: 1.14.1 - - '@sentry/minimal@5.30.0': - dependencies: - '@sentry/hub': 5.30.0 - '@sentry/types': 5.30.0 - tslib: 1.14.1 - - '@sentry/node@5.30.0': - 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.2 - https-proxy-agent: 5.0.1 - lru_map: 0.3.3 - tslib: 1.14.1 - transitivePeerDependencies: - - supports-color - - '@sentry/tracing@5.30.0': - dependencies: - '@sentry/hub': 5.30.0 - '@sentry/minimal': 5.30.0 - '@sentry/types': 5.30.0 - '@sentry/utils': 5.30.0 - tslib: 1.14.1 - - '@sentry/types@5.30.0': {} - - '@sentry/utils@5.30.0': - dependencies: - '@sentry/types': 5.30.0 - tslib: 1.14.1 - - '@sindresorhus/is@5.6.0': {} - - '@solidity-parser/parser@0.19.0': {} - - '@szmarczak/http-timer@5.0.1': - dependencies: - defer-to-connect: 2.0.1 - - '@thehubbleproject/bls@0.5.1': - dependencies: - ethers: 5.7.2 - mcl-wasm: 1.8.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@typechain/hardhat@2.3.1(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5))': - dependencies: - fs-extra: 9.1.0 - hardhat: 2.22.17(typescript@4.9.5) - lodash: 4.17.21 - typechain: 5.2.0(typescript@4.9.5) - - '@types/bn.js@4.11.6': - dependencies: - '@types/node': 22.13.1 - - '@types/bn.js@5.1.6': - dependencies: - '@types/node': 22.13.1 - - '@types/debug@4.1.12': - dependencies: - '@types/ms': 2.1.0 - - '@types/glob@7.2.0': - dependencies: - '@types/minimatch': 5.1.2 - '@types/node': 22.13.1 - - '@types/http-cache-semantics@4.0.4': {} - - '@types/lru-cache@5.1.1': {} - - '@types/minimatch@5.1.2': {} - - '@types/mocha@9.1.1': {} - - '@types/ms@2.1.0': {} - - '@types/node@12.20.55': {} - - '@types/node@20.17.17': - dependencies: - undici-types: 6.19.8 - - '@types/node@22.13.1': - dependencies: - undici-types: 6.20.0 - - '@types/pbkdf2@3.1.2': - dependencies: - '@types/node': 22.13.1 - - '@types/prettier@2.7.3': {} - - '@types/qs@6.9.18': {} - - '@types/secp256k1@4.0.6': - dependencies: - '@types/node': 22.13.1 - - abbrev@1.0.9: {} - - accountabstraction@https://codeload.github.com/eth-infinitism/account-abstraction/tar.gz/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)): - dependencies: - '@gnosis.pm/safe-contracts': 1.3.0(ethers@5.7.2) - '@nomiclabs/hardhat-etherscan': 2.1.8(hardhat@2.22.17(typescript@4.9.5)) - '@openzeppelin/contracts': 4.9.6 - '@thehubbleproject/bls': 0.5.1 - '@typechain/hardhat': 2.3.1(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)) - '@types/mocha': 9.1.1 - ethereumjs-util: 7.1.5 - ethereumjs-wallet: 1.0.2 - hardhat-deploy: 0.11.45 - hardhat-deploy-ethers: 0.3.0-beta.13(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5)) - solidity-coverage: 0.8.14(hardhat@2.22.17(typescript@4.9.5)) - source-map-support: 0.5.21 - table: 6.9.0 - typescript: 4.9.5 - transitivePeerDependencies: - - bufferutil - - encoding - - ethers - - hardhat - - lodash - - supports-color - - typechain - - utf-8-validate - - accountabstraction@https://codeload.github.com/kopy-kat/account-abstraction/tar.gz/c5887153fbfe3ed09b2637cac39873f96d676f38(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)): - dependencies: - '@nomiclabs/hardhat-etherscan': 2.1.8(hardhat@2.22.17(typescript@4.9.5)) - '@openzeppelin/contracts': 5.2.0 - '@thehubbleproject/bls': 0.5.1 - '@typechain/hardhat': 2.3.1(hardhat@2.22.17(typescript@4.9.5))(lodash@4.17.21)(typechain@5.2.0(typescript@4.9.5)) - '@types/debug': 4.1.12 - '@types/mocha': 9.1.1 - debug: 4.4.0(supports-color@8.1.1) - ethereumjs-util: 7.1.5 - ethereumjs-wallet: 1.0.2 - hardhat-deploy: 0.11.45 - hardhat-deploy-ethers: 0.3.0-beta.13(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5)) - solidity-coverage: 0.8.14(hardhat@2.22.17(typescript@4.9.5)) - source-map-support: 0.5.21 - table: 6.9.0 - typescript: 4.9.5 - transitivePeerDependencies: - - bufferutil - - encoding - - ethers - - hardhat - - lodash - - supports-color - - typechain - - utf-8-validate - - adm-zip@0.4.16: {} - - aes-js@3.0.0: {} - - aes-js@3.1.2: {} - - agent-base@6.0.2: - dependencies: - debug: 4.4.0(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - - aggregate-error@3.1.0: - dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 - - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ajv@8.17.1: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.0.6 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - amdefine@1.0.1: - optional: true - - ansi-align@3.0.1: - dependencies: - string-width: 4.2.3 - - ansi-colors@4.1.3: {} - - ansi-escapes@4.3.2: - dependencies: - type-fest: 0.21.3 - - ansi-regex@5.0.1: {} - - ansi-styles@3.2.1: - dependencies: - color-convert: 1.9.3 - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - antlr4@4.13.2: {} - - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - - argparse@2.0.1: {} - - array-back@1.0.4: - dependencies: - typical: 2.6.1 - - array-back@2.0.0: - dependencies: - typical: 2.6.1 - - array-union@2.1.0: {} - - ast-parents@0.0.1: {} - - astral-regex@2.0.0: {} - - async@1.5.2: {} - - asynckit@0.4.0: {} - - at-least-node@1.0.0: {} - - axios@0.21.4(debug@4.4.0): - dependencies: - follow-redirects: 1.15.9(debug@4.4.0) - transitivePeerDependencies: - - debug - - balanced-match@1.0.2: {} - - base-x@3.0.10: - dependencies: - safe-buffer: 5.2.1 - - bech32@1.1.4: {} - - better-path-resolve@1.0.0: - dependencies: - is-windows: 1.0.2 - - bignumber.js@9.1.2: {} - - binary-extensions@2.3.0: {} - - blakejs@1.2.1: {} - - bn.js@4.11.6: {} - - bn.js@4.12.1: {} - - bn.js@5.2.1: {} - - boxen@5.1.2: - dependencies: - ansi-align: 3.0.1 - camelcase: 6.3.0 - chalk: 4.1.2 - cli-boxes: 2.2.1 - string-width: 4.2.3 - type-fest: 0.20.2 - widest-line: 3.1.0 - wrap-ansi: 7.0.0 - - brace-expansion@1.1.11: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.1: - dependencies: - balanced-match: 1.0.2 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - brorand@1.1.0: {} - - browser-stdout@1.3.1: {} - - browserify-aes@1.2.0: - dependencies: - buffer-xor: 1.0.3 - cipher-base: 1.0.6 - create-hash: 1.2.0 - evp_bytestokey: 1.0.3 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - bs58@4.0.1: - dependencies: - base-x: 3.0.10 - - bs58check@2.1.2: - dependencies: - bs58: 4.0.1 - create-hash: 1.2.0 - safe-buffer: 5.2.1 - - buffer-from@1.1.2: {} - - buffer-xor@1.0.3: {} - - bytes@3.1.2: {} - - cacheable-lookup@7.0.0: {} - - cacheable-request@10.2.14: - dependencies: - '@types/http-cache-semantics': 4.0.4 - get-stream: 6.0.1 - http-cache-semantics: 4.1.1 - keyv: 4.5.4 - mimic-response: 4.0.0 - normalize-url: 8.0.1 - responselike: 3.0.0 - - call-bind-apply-helpers@1.0.1: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bound@1.0.3: - dependencies: - call-bind-apply-helpers: 1.0.1 - get-intrinsic: 1.2.7 - - callsites@3.1.0: {} - - camelcase@6.3.0: {} - - cbor@5.2.0: - dependencies: - bignumber.js: 9.1.2 - nofilter: 1.0.4 - - chalk@2.4.2: - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - chardet@0.7.0: {} - - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - - chokidar@4.0.3: - dependencies: - readdirp: 4.1.1 - - ci-info@2.0.0: {} - - ci-info@3.9.0: {} - - cipher-base@1.0.6: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - - clean-stack@2.2.0: {} - - cli-boxes@2.2.1: {} - - cliui@7.0.4: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - color-convert@1.9.3: - dependencies: - color-name: 1.1.3 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.3: {} - - color-name@1.1.4: {} - - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - command-exists@1.2.9: {} - - command-line-args@4.0.7: - dependencies: - array-back: 2.0.0 - find-replace: 1.0.3 - typical: 2.6.1 - - commander@10.0.1: {} - - commander@8.3.0: {} - - concat-map@0.0.1: {} - - config-chain@1.1.13: - dependencies: - ini: 1.3.8 - proto-list: 1.2.4 - - cookie@0.4.2: {} - - cosmiconfig@8.3.6(typescript@4.9.5): - dependencies: - import-fresh: 3.3.1 - js-yaml: 4.1.0 - parse-json: 5.2.0 - path-type: 4.0.0 - optionalDependencies: - typescript: 4.9.5 - - create-hash@1.2.0: - dependencies: - cipher-base: 1.0.6 - inherits: 2.0.4 - md5.js: 1.3.5 - ripemd160: 2.0.2 - sha.js: 2.4.11 - - create-hmac@1.1.7: - dependencies: - cipher-base: 1.0.6 - create-hash: 1.2.0 - inherits: 2.0.4 - ripemd160: 2.0.2 - safe-buffer: 5.2.1 - sha.js: 2.4.11 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - death@1.1.0: {} - - debug@4.4.0(supports-color@8.1.1): - dependencies: - ms: 2.1.3 - optionalDependencies: - supports-color: 8.1.1 - - decamelize@4.0.0: {} - - decompress-response@6.0.0: - dependencies: - mimic-response: 3.1.0 - - deep-extend@0.6.0: {} - - deep-is@0.1.4: {} - - defer-to-connect@2.0.1: {} - - delayed-stream@1.0.0: {} - - depd@2.0.0: {} - - detect-indent@6.1.0: {} - - diff@5.2.0: {} - - difflib@0.2.4: - dependencies: - heap: 0.2.7 - - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - - ds-test@https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - - elliptic@6.5.4: - dependencies: - bn.js: 4.12.1 - brorand: 1.1.0 - hash.js: 1.1.7 - hmac-drbg: 1.0.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - - elliptic@6.6.1: - dependencies: - bn.js: 4.12.1 - brorand: 1.1.0 - hash.js: 1.1.7 - hmac-drbg: 1.0.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - - emoji-regex@8.0.0: {} - - encode-utf8@1.0.3: {} - - enquirer@2.4.1: - dependencies: - ansi-colors: 4.1.3 - strip-ansi: 6.0.1 - - env-paths@2.2.1: {} - - error-ex@1.3.2: - dependencies: - is-arrayish: 0.2.1 - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - escalade@3.2.0: {} - - escape-string-regexp@1.0.5: {} - - escape-string-regexp@4.0.0: {} - - escodegen@1.8.1: - dependencies: - esprima: 2.7.3 - estraverse: 1.9.3 - esutils: 2.0.3 - optionator: 0.8.3 - optionalDependencies: - source-map: 0.2.0 - - esprima@2.7.3: {} - - esprima@4.0.1: {} - - estraverse@1.9.3: {} - - esutils@2.0.3: {} - - ethereum-bloom-filters@1.2.0: - dependencies: - '@noble/hashes': 1.7.1 - - ethereum-cryptography@0.1.3: - dependencies: - '@types/pbkdf2': 3.1.2 - '@types/secp256k1': 4.0.6 - blakejs: 1.2.1 - 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.4 - pbkdf2: 3.1.2 - randombytes: 2.1.0 - safe-buffer: 5.2.1 - scrypt-js: 3.0.1 - secp256k1: 4.0.4 - setimmediate: 1.0.5 - - ethereum-cryptography@1.2.0: - dependencies: - '@noble/hashes': 1.2.0 - '@noble/secp256k1': 1.7.1 - '@scure/bip32': 1.1.5 - '@scure/bip39': 1.1.1 - - ethereum-cryptography@2.2.1: - dependencies: - '@noble/curves': 1.4.2 - '@noble/hashes': 1.4.0 - '@scure/bip32': 1.4.0 - '@scure/bip39': 1.3.0 - - ethereumjs-abi@0.6.8: - dependencies: - bn.js: 4.12.1 - ethereumjs-util: 6.2.1 - - ethereumjs-util@6.2.1: - dependencies: - '@types/bn.js': 4.11.6 - bn.js: 4.12.1 - create-hash: 1.2.0 - elliptic: 6.6.1 - ethereum-cryptography: 0.1.3 - ethjs-util: 0.1.6 - rlp: 2.2.7 - - ethereumjs-util@7.1.5: - dependencies: - '@types/bn.js': 5.1.6 - bn.js: 5.2.1 - create-hash: 1.2.0 - ethereum-cryptography: 0.1.3 - rlp: 2.2.7 - - ethereumjs-wallet@1.0.2: - dependencies: - aes-js: 3.1.2 - bs58check: 2.1.2 - ethereum-cryptography: 0.1.3 - ethereumjs-util: 7.1.5 - randombytes: 2.1.0 - scrypt-js: 3.0.1 - utf8: 3.0.0 - uuid: 8.3.2 - - ethers@5.7.2: - 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 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - ethjs-unit@0.1.6: - dependencies: - bn.js: 4.11.6 - number-to-bn: 1.7.0 - - ethjs-util@0.1.6: - dependencies: - is-hex-prefixed: 1.0.0 - strip-hex-prefix: 1.0.0 - - evp_bytestokey@1.0.3: - dependencies: - md5.js: 1.3.5 - safe-buffer: 5.2.1 - - extendable-error@0.1.7: {} - - external-editor@3.1.0: - dependencies: - chardet: 0.7.0 - iconv-lite: 0.4.24 - tmp: 0.0.33 - - fast-deep-equal@3.1.3: {} - - fast-diff@1.3.0: {} - - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fast-uri@3.0.6: {} - - fastq@1.19.0: - dependencies: - reusify: 1.0.4 - - fdir@6.4.3(picomatch@4.0.2): - optionalDependencies: - picomatch: 4.0.2 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-replace@1.0.3: - dependencies: - array-back: 1.0.4 - test-value: 2.1.0 - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat@5.0.2: {} - - fmix@0.1.0: - dependencies: - imul: 1.0.1 - - follow-redirects@1.15.9(debug@4.4.0): - optionalDependencies: - debug: 4.4.0(supports-color@8.1.1) - - forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/3b20d60d14b343ee4f908cb8079495c07f5e8981: {} - - forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/8a225d81aa8e2e013580564588c79abb65eacc9e: {} - - form-data-encoder@2.1.4: {} - - form-data@4.0.1: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - - fp-ts@1.19.3: {} - - fs-extra@10.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - - fs-extra@7.0.1: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fs-extra@8.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fs-extra@9.1.0: - dependencies: - at-least-node: 1.0.0 - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - - fs.realpath@1.0.0: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - get-caller-file@2.0.5: {} - - get-intrinsic@1.2.7: - dependencies: - call-bind-apply-helpers: 1.0.1 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - get-stream@6.0.1: {} - - ghost-testrpc@0.0.2: - dependencies: - chalk: 2.4.2 - node-emoji: 1.11.0 - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob@5.0.15: - dependencies: - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - - glob@8.1.0: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - once: 1.4.0 - - global-modules@2.0.0: - dependencies: - global-prefix: 3.0.0 - - global-prefix@3.0.0: - dependencies: - ini: 1.3.8 - kind-of: 6.0.3 - which: 1.3.1 - - globby@10.0.2: - dependencies: - '@types/glob': 7.2.0 - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - glob: 7.2.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - - gopd@1.2.0: {} - - got@12.6.1: - dependencies: - '@sindresorhus/is': 5.6.0 - '@szmarczak/http-timer': 5.0.1 - cacheable-lookup: 7.0.0 - cacheable-request: 10.2.14 - decompress-response: 6.0.0 - form-data-encoder: 2.1.4 - get-stream: 6.0.1 - http2-wrapper: 2.2.1 - lowercase-keys: 3.0.0 - p-cancelable: 3.0.0 - responselike: 3.0.0 - - graceful-fs@4.2.10: {} - - graceful-fs@4.2.11: {} - - handlebars@4.7.8: - dependencies: - minimist: 1.2.8 - neo-async: 2.6.2 - source-map: 0.6.1 - wordwrap: 1.0.0 - optionalDependencies: - uglify-js: 3.19.3 - - hardhat-deploy-ethers@0.3.0-beta.13(ethers@5.7.2)(hardhat@2.22.17(typescript@4.9.5)): - dependencies: - ethers: 5.7.2 - hardhat: 2.22.17(typescript@4.9.5) - - hardhat-deploy@0.11.45: - dependencies: - '@ethersproject/abi': 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/contracts': 5.7.0 - '@ethersproject/providers': 5.7.2 - '@ethersproject/solidity': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/wallet': 5.7.0 - '@types/qs': 6.9.18 - axios: 0.21.4(debug@4.4.0) - chalk: 4.1.2 - chokidar: 3.6.0 - debug: 4.4.0(supports-color@8.1.1) - enquirer: 2.4.1 - ethers: 5.7.2 - form-data: 4.0.1 - fs-extra: 10.1.0 - match-all: 1.2.6 - murmur-128: 0.2.1 - qs: 6.14.0 - zksync-web3: 0.14.4(ethers@5.7.2) - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - hardhat@2.22.17(typescript@4.9.5): - dependencies: - '@ethersproject/abi': 5.7.0 - '@metamask/eth-sig-util': 4.0.1 - '@nomicfoundation/edr': 0.6.5 - '@nomicfoundation/ethereumjs-common': 4.0.4 - '@nomicfoundation/ethereumjs-tx': 5.0.4 - '@nomicfoundation/ethereumjs-util': 9.0.4 - '@nomicfoundation/solidity-analyzer': 0.1.2 - '@sentry/node': 5.30.0 - '@types/bn.js': 5.1.6 - '@types/lru-cache': 5.1.1 - adm-zip: 0.4.16 - aggregate-error: 3.1.0 - ansi-escapes: 4.3.2 - boxen: 5.1.2 - chokidar: 4.0.3 - ci-info: 2.0.0 - debug: 4.4.0(supports-color@8.1.1) - enquirer: 2.4.1 - env-paths: 2.2.1 - ethereum-cryptography: 1.2.0 - ethereumjs-abi: 0.6.8 - find-up: 5.0.0 - fp-ts: 1.19.3 - fs-extra: 7.0.1 - immutable: 4.3.7 - io-ts: 1.10.4 - json-stream-stringify: 3.1.6 - keccak: 3.0.4 - lodash: 4.17.21 - mnemonist: 0.38.5 - mocha: 10.8.2 - p-map: 4.0.0 - picocolors: 1.1.1 - raw-body: 2.5.2 - resolve: 1.17.0 - semver: 6.3.1 - solc: 0.8.26(debug@4.4.0) - source-map-support: 0.5.21 - stacktrace-parser: 0.1.10 - tinyglobby: 0.2.10 - tsort: 0.0.1 - undici: 5.28.5 - uuid: 8.3.2 - ws: 7.5.10 - optionalDependencies: - typescript: 4.9.5 - transitivePeerDependencies: - - bufferutil - - c-kzg - - supports-color - - utf-8-validate - - has-flag@1.0.0: {} - - has-flag@3.0.0: {} - - has-flag@4.0.0: {} - - has-symbols@1.1.0: {} - - hash-base@3.1.0: - dependencies: - inherits: 2.0.4 - readable-stream: 3.6.2 - safe-buffer: 5.2.1 - - hash.js@1.1.7: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - he@1.2.0: {} - - heap@0.2.7: {} - - hmac-drbg@1.0.1: - dependencies: - hash.js: 1.1.7 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - - http-cache-semantics@4.1.1: {} - - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - - http2-wrapper@2.2.1: - dependencies: - quick-lru: 5.1.1 - resolve-alpn: 1.2.1 - - https-proxy-agent@5.0.1: - dependencies: - agent-base: 6.0.2 - debug: 4.4.0(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - - human-id@1.0.2: {} - - iconv-lite@0.4.24: - dependencies: - safer-buffer: 2.1.2 - - ignore@5.3.2: {} - - immutable@4.3.7: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - imul@1.0.1: {} - - indent-string@4.0.0: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - - ini@1.3.8: {} - - interpret@1.4.0: {} - - io-ts@1.10.4: - dependencies: - fp-ts: 1.19.3 - - is-arrayish@0.2.1: {} - - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - - is-core-module@2.16.1: - dependencies: - hasown: 2.0.2 - - is-extglob@2.1.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-hex-prefixed@1.0.0: {} - - is-number@7.0.0: {} - - is-plain-obj@2.1.0: {} - - is-subdir@1.2.0: - dependencies: - better-path-resolve: 1.0.0 - - is-unicode-supported@0.1.0: {} - - is-windows@1.0.2: {} - - isexe@2.0.0: {} - - js-sha3@0.8.0: {} - - js-tokens@4.0.0: {} - - js-yaml@3.14.1: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - - js-yaml@4.1.0: - dependencies: - argparse: 2.0.1 - - json-buffer@3.0.1: {} - - json-parse-even-better-errors@2.3.1: {} - - json-schema-traverse@0.4.1: {} - - json-schema-traverse@1.0.0: {} - - json-stream-stringify@3.1.6: {} - - jsonfile@4.0.0: - optionalDependencies: - graceful-fs: 4.2.11 - - jsonfile@6.1.0: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - - jsonschema@1.5.0: {} - - keccak@3.0.4: - dependencies: - node-addon-api: 2.0.2 - node-gyp-build: 4.8.4 - readable-stream: 3.6.2 - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - kind-of@6.0.3: {} - - latest-version@7.0.0: - dependencies: - package-json: 8.1.1 - - levn@0.3.0: - dependencies: - prelude-ls: 1.1.2 - type-check: 0.3.2 - - lines-and-columns@1.2.4: {} - - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.startcase@4.4.0: {} - - lodash.truncate@4.4.2: {} - - lodash@4.17.21: {} - - log-symbols@4.1.0: - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - - lowercase-keys@3.0.0: {} - - lru_map@0.3.3: {} - - match-all@1.2.6: {} - - math-intrinsics@1.1.0: {} - - mcl-wasm@1.8.0: - dependencies: - '@types/node': 20.17.17 - - md5.js@1.3.5: - dependencies: - hash-base: 3.1.0 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - memorystream@0.3.1: {} - - merge2@1.4.1: {} - - micro-ftch@0.3.1: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mimic-response@3.1.0: {} - - mimic-response@4.0.0: {} - - minimalistic-assert@1.0.1: {} - - minimalistic-crypto-utils@1.0.1: {} - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.11 - - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.1 - - minimist@1.2.8: {} - - mkdirp@0.5.6: - dependencies: - minimist: 1.2.8 - - mkdirp@1.0.4: {} - - mnemonist@0.38.5: - dependencies: - obliterator: 2.0.5 - - mocha@10.8.2: - dependencies: - ansi-colors: 4.1.3 - browser-stdout: 1.3.1 - chokidar: 3.6.0 - debug: 4.4.0(supports-color@8.1.1) - diff: 5.2.0 - escape-string-regexp: 4.0.0 - find-up: 5.0.0 - glob: 8.1.0 - he: 1.2.0 - js-yaml: 4.1.0 - log-symbols: 4.1.0 - minimatch: 5.1.6 - ms: 2.1.3 - serialize-javascript: 6.0.2 - strip-json-comments: 3.1.1 - supports-color: 8.1.1 - workerpool: 6.5.1 - yargs: 16.2.0 - yargs-parser: 20.2.9 - yargs-unparser: 2.0.0 - - mri@1.2.0: {} - - ms@2.1.3: {} - - murmur-128@0.2.1: - dependencies: - encode-utf8: 1.0.3 - fmix: 0.1.0 - imul: 1.0.1 - - neo-async@2.6.2: {} - - node-addon-api@2.0.2: {} - - node-addon-api@5.1.0: {} - - node-emoji@1.11.0: - dependencies: - lodash: 4.17.21 - - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - - node-gyp-build@4.8.4: {} - - nofilter@1.0.4: {} - - nopt@3.0.6: - dependencies: - abbrev: 1.0.9 - - normalize-path@3.0.0: {} - - normalize-url@8.0.1: {} - - number-to-bn@1.7.0: - dependencies: - bn.js: 4.11.6 - strip-hex-prefix: 1.0.0 - - object-inspect@1.13.4: {} - - obliterator@2.0.5: {} - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - optionator@0.8.3: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.3.0 - prelude-ls: 1.1.2 - type-check: 0.3.2 - word-wrap: 1.2.5 - - os-tmpdir@1.0.2: {} - - outdent@0.5.0: {} - - p-cancelable@3.0.0: {} - - p-filter@2.1.0: - dependencies: - p-map: 2.1.0 - - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - p-map@2.1.0: {} - - p-map@4.0.0: - dependencies: - aggregate-error: 3.1.0 - - p-try@2.2.0: {} - - package-json@8.1.1: - dependencies: - got: 12.6.1 - registry-auth-token: 5.0.3 - registry-url: 6.0.1 - semver: 7.7.1 - - package-manager-detector@0.2.9: {} - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - parse-json@5.2.0: - dependencies: - '@babel/code-frame': 7.26.2 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - - path-exists@4.0.0: {} - - path-is-absolute@1.0.1: {} - - path-key@3.1.1: {} - - path-parse@1.0.7: {} - - path-type@4.0.0: {} - - pbkdf2@3.1.2: - dependencies: - create-hash: 1.2.0 - create-hmac: 1.1.7 - ripemd160: 2.0.2 - safe-buffer: 5.2.1 - sha.js: 2.4.11 - - picocolors@1.1.1: {} - - picomatch@2.3.1: {} - - picomatch@4.0.2: {} - - pify@4.0.1: {} - - pluralize@8.0.0: {} - - prelude-ls@1.1.2: {} - - prettier@2.8.8: {} - - proto-list@1.2.4: {} - - punycode@2.3.1: {} - - qs@6.14.0: - dependencies: - side-channel: 1.1.0 - - queue-microtask@1.2.3: {} - - quick-lru@5.1.1: {} - - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - - raw-body@2.5.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - - rc@1.2.8: - dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 - - read-yaml-file@1.1.0: - dependencies: - graceful-fs: 4.2.11 - js-yaml: 3.14.1 - pify: 4.0.1 - strip-bom: 3.0.0 - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 - - readdirp@4.1.1: {} - - rechoir@0.6.2: - dependencies: - resolve: 1.22.10 - - recursive-readdir@2.2.3: - dependencies: - minimatch: 3.1.2 - - regenerator-runtime@0.14.1: {} - - registry-auth-token@5.0.3: - dependencies: - '@pnpm/npm-conf': 2.3.1 - - registry-url@6.0.1: - dependencies: - rc: 1.2.8 - - require-directory@2.1.1: {} - - require-from-string@2.0.2: {} - - resolve-alpn@1.2.1: {} - - resolve-from@4.0.0: {} - - resolve-from@5.0.0: {} - - resolve@1.1.7: {} - - resolve@1.17.0: - dependencies: - path-parse: 1.0.7 - - resolve@1.22.10: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - responselike@3.0.0: - dependencies: - lowercase-keys: 3.0.0 - - reusify@1.0.4: {} - - ripemd160@2.0.2: - dependencies: - hash-base: 3.1.0 - inherits: 2.0.4 - - rlp@2.2.7: - dependencies: - bn.js: 5.2.1 - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - safe-buffer@5.2.1: {} - - safer-buffer@2.1.2: {} - - sc-istanbul@0.4.6: - dependencies: - abbrev: 1.0.9 - async: 1.5.2 - escodegen: 1.8.1 - esprima: 2.7.3 - glob: 5.0.15 - handlebars: 4.7.8 - js-yaml: 3.14.1 - mkdirp: 0.5.6 - nopt: 3.0.6 - once: 1.4.0 - resolve: 1.1.7 - supports-color: 3.2.3 - which: 1.3.1 - wordwrap: 1.0.0 - - scrypt-js@3.0.1: {} - - secp256k1@4.0.4: - dependencies: - elliptic: 6.6.1 - node-addon-api: 5.1.0 - node-gyp-build: 4.8.4 - - semver@5.7.2: {} - - semver@6.3.1: {} - - semver@7.7.1: {} - - serialize-javascript@6.0.2: - dependencies: - randombytes: 2.1.0 - - setimmediate@1.0.5: {} - - setprototypeof@1.2.0: {} - - sha.js@2.4.11: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - shelljs@0.8.5: - dependencies: - glob: 7.2.3 - interpret: 1.4.0 - rechoir: 0.6.2 - - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.3 - es-errors: 1.3.0 - get-intrinsic: 1.2.7 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.3 - es-errors: 1.3.0 - get-intrinsic: 1.2.7 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - - signal-exit@4.1.0: {} - - slash@3.0.0: {} - - slice-ansi@4.0.0: - dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - - solady@https://codeload.github.com/vectorized/solady/tar.gz/59f28399b7e9202bc6145b082bf7ff025b8b1ddc: {} - - solarray@https://codeload.github.com/sablier-labs/solarray/tar.gz/6bf10cb34cdace52a3ba5fe437e78cc82df92684: {} - - solc@0.8.26(debug@4.4.0): - dependencies: - command-exists: 1.2.9 - commander: 8.3.0 - follow-redirects: 1.15.9(debug@4.4.0) - js-sha3: 0.8.0 - memorystream: 0.3.1 - semver: 5.7.2 - tmp: 0.0.33 - transitivePeerDependencies: - - debug - - solhint@5.0.5(typescript@4.9.5): - dependencies: - '@solidity-parser/parser': 0.19.0 - ajv: 6.12.6 - antlr4: 4.13.2 - ast-parents: 0.0.1 - chalk: 4.1.2 - commander: 10.0.1 - cosmiconfig: 8.3.6(typescript@4.9.5) - fast-diff: 1.3.0 - glob: 8.1.0 - ignore: 5.3.2 - js-yaml: 4.1.0 - latest-version: 7.0.0 - lodash: 4.17.21 - pluralize: 8.0.0 - semver: 7.7.1 - strip-ansi: 6.0.1 - table: 6.9.0 - text-table: 0.2.0 - optionalDependencies: - prettier: 2.8.8 - transitivePeerDependencies: - - typescript - - solidity-coverage@0.8.14(hardhat@2.22.17(typescript@4.9.5)): - dependencies: - '@ethersproject/abi': 5.7.0 - '@solidity-parser/parser': 0.19.0 - chalk: 2.4.2 - death: 1.1.0 - difflib: 0.2.4 - fs-extra: 8.1.0 - ghost-testrpc: 0.0.2 - global-modules: 2.0.0 - globby: 10.0.2 - hardhat: 2.22.17(typescript@4.9.5) - jsonschema: 1.5.0 - lodash: 4.17.21 - mocha: 10.8.2 - node-emoji: 1.11.0 - pify: 4.0.1 - recursive-readdir: 2.2.3 - sc-istanbul: 0.4.6 - semver: 7.7.1 - shelljs: 0.8.5 - web3-utils: 1.10.4 - - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.2.0: - dependencies: - amdefine: 1.0.1 - optional: true - - source-map@0.6.1: {} - - spawndamnit@3.0.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - sprintf-js@1.0.3: {} - - stacktrace-parser@0.1.10: - dependencies: - type-fest: 0.7.1 - - statuses@2.0.1: {} - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-bom@3.0.0: {} - - strip-hex-prefix@1.0.0: - dependencies: - is-hex-prefixed: 1.0.0 - - strip-json-comments@2.0.1: {} - - strip-json-comments@3.1.1: {} - - supports-color@3.2.3: - dependencies: - has-flag: 1.0.0 - - supports-color@5.5.0: - dependencies: - has-flag: 3.0.0 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-color@8.1.1: - dependencies: - has-flag: 4.0.0 - - supports-preserve-symlinks-flag@1.0.0: {} - - table@6.9.0: - dependencies: - ajv: 8.17.1 - lodash.truncate: 4.4.2 - slice-ansi: 4.0.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - term-size@2.2.1: {} - - test-value@2.1.0: - dependencies: - array-back: 1.0.4 - typical: 2.6.1 - - text-table@0.2.0: {} - - tinyglobby@0.2.10: - dependencies: - fdir: 6.4.3(picomatch@4.0.2) - picomatch: 4.0.2 - - tmp@0.0.33: - dependencies: - os-tmpdir: 1.0.2 - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - toidentifier@1.0.1: {} - - tr46@0.0.3: {} - - ts-essentials@7.0.3(typescript@4.9.5): - dependencies: - typescript: 4.9.5 - - tslib@1.14.1: {} - - tsort@0.0.1: {} - - tweetnacl-util@0.15.1: {} - - tweetnacl@1.0.3: {} - - type-check@0.3.2: - dependencies: - prelude-ls: 1.1.2 - - type-fest@0.20.2: {} - - type-fest@0.21.3: {} - - type-fest@0.7.1: {} - - typechain@5.2.0(typescript@4.9.5): - dependencies: - '@types/prettier': 2.7.3 - command-line-args: 4.0.7 - debug: 4.4.0(supports-color@8.1.1) - fs-extra: 7.0.1 - glob: 7.2.3 - js-sha3: 0.8.0 - lodash: 4.17.21 - mkdirp: 1.0.4 - prettier: 2.8.8 - ts-essentials: 7.0.3(typescript@4.9.5) - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color - - typescript@4.9.5: {} - - typical@2.6.1: {} - - uglify-js@3.19.3: - optional: true - - undici-types@6.19.8: {} - - undici-types@6.20.0: {} - - undici@5.28.5: - dependencies: - '@fastify/busboy': 2.1.1 - - universalify@0.1.2: {} - - universalify@2.0.1: {} - - unpipe@1.0.0: {} - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - utf8@3.0.0: {} - - util-deprecate@1.0.2: {} - - uuid@8.3.2: {} - - web3-utils@1.10.4: - dependencies: - '@ethereumjs/util': 8.1.0 - bn.js: 5.2.1 - ethereum-bloom-filters: 1.2.0 - ethereum-cryptography: 2.2.1 - ethjs-unit: 0.1.6 - number-to-bn: 1.7.0 - randombytes: 2.1.0 - utf8: 3.0.0 - - webidl-conversions@3.0.1: {} - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - - which@1.3.1: - dependencies: - isexe: 2.0.0 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - widest-line@3.1.0: - dependencies: - string-width: 4.2.3 - - word-wrap@1.2.5: {} - - wordwrap@1.0.0: {} - - workerpool@6.5.1: {} - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrappy@1.0.2: {} - - ws@7.4.6: {} - - ws@7.5.10: {} - - y18n@5.0.8: {} - - yargs-parser@20.2.9: {} - - yargs-unparser@2.0.0: - dependencies: - camelcase: 6.3.0 - decamelize: 4.0.0 - flat: 5.0.2 - is-plain-obj: 2.1.0 - - yargs@16.2.0: - dependencies: - cliui: 7.0.4 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 - - yocto-queue@0.1.0: {} - - zksync-web3@0.14.4(ethers@5.7.2): - dependencies: - ethers: 5.7.2 diff --git a/typescript/packages/account-modules/lib/modulekit/remappings.txt b/typescript/packages/account-modules/lib/modulekit/remappings.txt deleted file mode 100644 index 556ee76..0000000 --- a/typescript/packages/account-modules/lib/modulekit/remappings.txt +++ /dev/null @@ -1,12 +0,0 @@ -erc4337-validation/=node_modules/@rhinestone/erc4337-validation/src/ -@ERC4337/=node_modules/@ERC4337/ -account-abstraction/=node_modules/@ERC4337/account-abstraction/contracts/ -account-abstraction-v0.6/=node_modules/@ERC4337/account-abstraction-v0.6/contracts/ -modulekit/=node_modules/@rhinestone/modulekit/src/ -@openzeppelin/=node_modules/@openzeppelin/ -ds-test/=node_modules/ds-test/src/ -forge-std/=node_modules/forge-std/src/ -solady/=node_modules/solady/src/ -solarray/=node_modules/solarray/src/ -@prb/math/=node_modules/@prb/math/src/ -ExcessivelySafeCall/=node_modules/excessively-safe-call/src/ \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/modulekit/src/Accounts.sol b/typescript/packages/account-modules/lib/modulekit/src/Accounts.sol deleted file mode 100644 index 42fa96f..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/Accounts.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/* solhint-disable no-unused-import */ - -/*////////////////////////////////////////////////////////////// - COMMON -//////////////////////////////////////////////////////////////*/ - -import { IERC7579Account } from "./accounts/common/interfaces/IERC7579Account.sol"; - -/*////////////////////////////////////////////////////////////// - 7579 REFERENCE -//////////////////////////////////////////////////////////////*/ - -import { IMSA } from "./accounts/erc7579/interfaces/IMSA.sol"; - -/*////////////////////////////////////////////////////////////// - KERNEL -//////////////////////////////////////////////////////////////*/ - -import { IERC7579Account as IKernelAccount } from "./accounts/kernel/interfaces/IERC7579Account.sol"; - -/*////////////////////////////////////////////////////////////// - SAFE -//////////////////////////////////////////////////////////////*/ - -import { ISafe7579 } from "./accounts/safe/interfaces/ISafe7579.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/Helpers.sol b/typescript/packages/account-modules/lib/modulekit/src/Helpers.sol deleted file mode 100644 index abfcd14..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/Helpers.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/* solhint-disable no-unused-import */ - -/*////////////////////////////////////////////////////////////// - 4337 -//////////////////////////////////////////////////////////////*/ - -import { ERC4337Helpers } from "./test/utils/ERC4337Helpers.sol"; - -/*////////////////////////////////////////////////////////////// - 7579 REFERENCE -//////////////////////////////////////////////////////////////*/ - -import { ERC7579Helpers } from "./test/helpers/ERC7579Helpers.sol"; - -/*////////////////////////////////////////////////////////////// - KERNEL -//////////////////////////////////////////////////////////////*/ - -import { KernelHelpers } from "./test/helpers/KernelHelpers.sol"; - -/*////////////////////////////////////////////////////////////// - NEXUS -//////////////////////////////////////////////////////////////*/ - -import { NexusHelpers } from "./test/helpers/NexusHelpers.sol"; - -/*////////////////////////////////////////////////////////////// - SAFE -//////////////////////////////////////////////////////////////*/ - -import { SafeHelpers } from "./test/helpers/SafeHelpers.sol"; - -/*////////////////////////////////////////////////////////////// - UTIL -//////////////////////////////////////////////////////////////*/ - -import { ecdsaSign } from "./test/utils/ECDSA.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/Integrations.sol b/typescript/packages/account-modules/lib/modulekit/src/Integrations.sol deleted file mode 100644 index 1b50604..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/Integrations.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/* solhint-disable no-unused-import */ - -/*////////////////////////////////////////////////////////////// - ERCs -//////////////////////////////////////////////////////////////*/ - -import { ERC20Integration } from "./integrations/ERC20.sol"; -import { ERC721Integration } from "./integrations/ERC721.sol"; -import { ERC4626Integration } from "./integrations/ERC4626.sol"; - -/*////////////////////////////////////////////////////////////// - UNIV3 -//////////////////////////////////////////////////////////////*/ - -import { UniswapV3Integration, SWAPROUTER_ADDRESS } from "./integrations/uniswap/v3/Uniswap.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/Interfaces.sol b/typescript/packages/account-modules/lib/modulekit/src/Interfaces.sol deleted file mode 100644 index bc6f3b2..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/Interfaces.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/* solhint-disable no-unused-import */ - -/*////////////////////////////////////////////////////////////// - ERCs/EIPs -//////////////////////////////////////////////////////////////*/ - -import { IERC1271, EIP1271_MAGIC_VALUE } from "./module-bases/interfaces/IERC1271.sol"; -import { IERC7484 } from "./module-bases/interfaces/IERC7484.sol"; -import { - IERC6682, - IERC3156FlashLender, - IERC3156FlashBorrower -} from "./module-bases/interfaces/Flashloan.sol"; -import { IERC712 } from "./module-bases/interfaces/IERC712.sol"; - -/*////////////////////////////////////////////////////////////// - MODULES -//////////////////////////////////////////////////////////////*/ - -import { IStatelessValidator } from "./module-bases/interfaces/IStatelessValidator.sol"; -import { IPolicy } from "./module-bases/interfaces/IPolicy.sol"; - -/*////////////////////////////////////////////////////////////// - TYPES -//////////////////////////////////////////////////////////////*/ - -import { FlashLoanType } from "./module-bases/interfaces/Flashloan.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/Mocks.sol b/typescript/packages/account-modules/lib/modulekit/src/Mocks.sol deleted file mode 100644 index 972caaf..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/Mocks.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/* solhint-disable no-unused-import */ - -/*////////////////////////////////////////////////////////////// - AUX -//////////////////////////////////////////////////////////////*/ - -import { MockRegistry } from "./module-bases/mocks/MockRegistry.sol"; -import { MockTarget } from "./module-bases/mocks/MockTarget.sol"; -import { MockHookMultiPlexer } from "./module-bases/mocks/MockHookMultiPlexer.sol"; -import { MockPolicy } from "./module-bases/mocks/MockPolicy.sol"; - -/*////////////////////////////////////////////////////////////// - MODULES -//////////////////////////////////////////////////////////////*/ - -import { MockValidator } from "./module-bases/mocks/MockValidator.sol"; -import { MockStatelessValidator } from "./module-bases/mocks/MockStatelessValidator.sol"; -import { MockHybridValidator } from "./module-bases/mocks/MockHybridValidator.sol"; -import { MockExecutor } from "./module-bases/mocks/MockExecutor.sol"; -import { MockHook } from "./module-bases/mocks/MockHook.sol"; -import { MockFallback } from "./module-bases/mocks/MockFallback.sol"; - -/*////////////////////////////////////////////////////////////// - TOKENS -//////////////////////////////////////////////////////////////*/ - -import { MockERC20 } from "./mocks/MockERC20.sol"; -import { MockERC721 } from "./mocks/MockERC721.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/ModuleKit.sol b/typescript/packages/account-modules/lib/modulekit/src/ModuleKit.sol deleted file mode 100644 index f2c0b0f..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/ModuleKit.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/* solhint-disable no-unused-import */ - -/*////////////////////////////////////////////////////////////// - MODULEKIT -//////////////////////////////////////////////////////////////*/ - -import { - UserOpData, - AccountInstance, - RhinestoneModuleKit, - AccountType -} from "./test/RhinestoneModuleKit.sol"; -import { ModuleKitHelpers } from "./test/ModuleKitHelpers.sol"; - -/*////////////////////////////////////////////////////////////// - 4337 -////////////////////////////////////////////////////////////*/ - -import { PackedUserOperation } from "./external/ERC4337.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/Modules.sol b/typescript/packages/account-modules/lib/modulekit/src/Modules.sol deleted file mode 100644 index e426671..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/Modules.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/* solhint-disable no-unused-import */ - -/*////////////////////////////////////////////////////////////// - INTERFACES -//////////////////////////////////////////////////////////////*/ - -import { - IValidator as IERC7579Validator, - IExecutor as IERC7579Executor, - IFallback as IERC7579Fallback, - IHook as IERC7579Hook, - IModule as IERC7579Module -} from "./accounts/common/interfaces/IERC7579Module.sol"; - -/*////////////////////////////////////////////////////////////// - BASES -//////////////////////////////////////////////////////////////*/ - -// Core -import { ERC7579ModuleBase } from "./module-bases/ERC7579ModuleBase.sol"; - -// Validators -import { ERC7579ValidatorBase } from "./module-bases/ERC7579ValidatorBase.sol"; -import { ERC7579StatelessValidatorBase } from "./module-bases/ERC7579StatelessValidatorBase.sol"; -import { ERC7579HybridValidatorBase } from "./module-bases/ERC7579HybridValidatorBase.sol"; - -// Executors -import { ERC7579ExecutorBase } from "./module-bases/ERC7579ExecutorBase.sol"; - -// Hooks -import { ERC7579HookBase } from "./module-bases/ERC7579HookBase.sol"; -import { ERC7579HookDestruct } from "./module-bases/ERC7579HookDestruct.sol"; -import { ERC7579HookDestructSingleHook } from "./module-bases/ERC7579HookDestructSingleHook.sol"; - -// Fallbacks -import { ERC7579FallbackBase } from "./module-bases/ERC7579FallbackBase.sol"; - -// Misc -import { SchedulingBase } from "./module-bases/SchedulingBase.sol"; -import { ERC7484RegistryAdapter } from "./module-bases/ERC7484RegistryAdapter.sol"; - -// Policies -import { ERC7579PolicyBase } from "./module-bases/ERC7579PolicyBase.sol"; -import { ERC1271Policy } from "./module-bases/ERC1271Policy.sol"; -import { ERC7579ActionPolicy } from "./module-bases/ERC7579ActionPolicy.sol"; -import { ERC7579UserOpPolicy } from "./module-bases/ERC7579UserOpPolicy.sol"; - -/*////////////////////////////////////////////////////////////// - UTIL -//////////////////////////////////////////////////////////////*/ - -import { TrustedForwarder } from "./module-bases/utils/TrustedForwarder.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC4337Account.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC4337Account.sol deleted file mode 100644 index 78510c4..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC4337Account.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { PackedUserOperation } from - "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; - -interface IERC4337Account { - /** - * Validate user's signature and nonce - * the entryPoint will make the call to the recipient only if this validation call returns - * successfully. - * signature failure should be reported by returning SIG_VALIDATION_FAILED (1). - * This allows making a "simulation call" without a valid signature - * Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to - * signal failure. - * - * @dev Must validate caller is the entryPoint. - * Must validate the signature and nonce - * @param userOp - The operation that is about to be executed. - * @param userOpHash - Hash of the user's request data. can be used as the basis for - * signature. - * @param missingAccountFunds - Missing funds on the account's deposit in the entrypoint. - * This is the minimum amount to transfer to the sender(entryPoint) - * to be - * able to make the call. The excess is left as a deposit in the - * entrypoint - * for future calls. Can be withdrawn anytime using - * "entryPoint.withdrawTo()". - * In case there is a paymaster in the request (or the current - * deposit is high - * enough), this value will be zero. - * @return validationData - Packaged ValidationData structure. use `_packValidationData` - * and - * `_unpackValidationData` to encode and decode. - * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark - * signature failure, - * otherwise, an address of an "authorizer" contract. - * <6-byte> validUntil - Last timestamp this operation is valid. 0 - * for "indefinite" - * <6-byte> validAfter - First timestamp this operation is valid - * If an account doesn't use time-range, it - * is enough to - * return SIG_VALIDATION_FAILED value (1) for - * signature failure. - * Note that the validation code cannot use block.timestamp (or - * block.number) directly. - */ - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash, - uint256 missingAccountFunds - ) - external - payable - returns (uint256 validationData); - - /** - * Account may implement this execute method. - * passing this methodSig at the beginning of callData will cause the entryPoint to pass the - * full UserOp (and hash) - * to the account. - * The account should skip the methodSig, and use the callData (and optionally, other UserOp - * fields) - * - * @param userOp - The operation that was just validated. - * @param userOpHash - Hash of the user's request data. - */ - function executeUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) - external - payable; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Account.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Account.sol deleted file mode 100644 index 6bf4db0..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Account.sol +++ /dev/null @@ -1,131 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/* solhint-disable no-unused-import */ - -// Types -import { CallType, ExecType, ModeCode } from "../lib/ModeLib.sol"; - -// Structs -struct Execution { - address target; - uint256 value; - bytes callData; -} - -interface IERC7579Account { - event ModuleInstalled(uint256 moduleTypeId, address module); - event ModuleUninstalled(uint256 moduleTypeId, address module); - - /** - * @dev Executes a transaction on behalf of the account. - * This function is intended to be called by ERC-4337 EntryPoint.sol - * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf - * - * @dev MSA MUST implement this function signature. - * If a mode is requested that is not supported by the Account, it MUST revert - * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details - * @param executionCalldata The encoded execution call data - */ - function execute(ModeCode mode, bytes calldata executionCalldata) external payable; - - /** - * @dev Executes a transaction on behalf of the account. - * This function is intended to be called by Executor Modules - * @dev Ensure adequate authorization control: i.e. onlyExecutorModule - * - * @dev MSA MUST implement this function signature. - * If a mode is requested that is not supported by the Account, it MUST revert - * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details - * @param executionCalldata The encoded execution call data - */ - function executeFromExecutor( - ModeCode mode, - bytes calldata executionCalldata - ) - external - payable - returns (bytes[] memory returnData); - - /** - * @dev ERC-1271 isValidSignature - * This function is intended to be used to validate a smart account signature - * and may forward the call to a validator module - * - * @param hash The hash of the data that is signed - * @param data The data that is signed - */ - function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4); - - /** - * @dev installs a Module of a certain type on the smart account - * @dev Implement Authorization control of your chosing - * @param moduleTypeId the module type ID according the ERC-7579 spec - * @param module the module address - * @param initData arbitrary data that may be required on the module during `onInstall` - * initialization. - */ - function installModule( - uint256 moduleTypeId, - address module, - bytes calldata initData - ) - external - payable; - - /** - * @dev uninstalls a Module of a certain type on the smart account - * @dev Implement Authorization control of your chosing - * @param moduleTypeId the module type ID according the ERC-7579 spec - * @param module the module address - * @param deInitData arbitrary data that may be required on the module during `onUninstall` - * de-initialization. - */ - function uninstallModule( - uint256 moduleTypeId, - address module, - bytes calldata deInitData - ) - external - payable; - - /** - * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol) - * @param encodedMode the encoded mode - */ - function supportsExecutionMode(ModeCode encodedMode) external view returns (bool); - - /** - * Function to check if the account supports installation of a certain module type Id - * @param moduleTypeId the module type ID according the ERC-7579 spec - */ - function supportsModule(uint256 moduleTypeId) external view returns (bool); - - /** - * Function to check if the account has a certain module installed - * @param moduleTypeId the module type ID according the ERC-7579 spec - * Note: keep in mind that some contracts can be multiple module types at the same time. It - * thus may be necessary to query multiple module types - * @param module the module address - * @param additionalContext additional context data that the smart account may interpret to - * identifiy conditions under which the module is installed. - * usually this is not necessary, but for some special hooks that - * are stored in mappings, this param might be needed - */ - function isModuleInstalled( - uint256 moduleTypeId, - address module, - bytes calldata additionalContext - ) - external - view - returns (bool); - - /** - * @dev Returns the account id of the smart account - * @return accountImplementationId the account id of the smart account - * the accountId should be structured like so: - * "vendorname.accountname.semver" - */ - function accountId() external view returns (string memory accountImplementationId); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Module.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Module.sol deleted file mode 100644 index 25990c6..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/common/interfaces/IERC7579Module.sol +++ /dev/null @@ -1,162 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { PackedUserOperation } from - "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; - -// Constants -uint256 constant VALIDATION_SUCCESS = 0; -uint256 constant VALIDATION_FAILED = 1; -uint256 constant MODULE_TYPE_VALIDATOR = 1; -uint256 constant MODULE_TYPE_EXECUTOR = 2; -uint256 constant MODULE_TYPE_FALLBACK = 3; -uint256 constant MODULE_TYPE_HOOK = 4; -uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC1271 = 8; -uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC4337 = 9; - -interface IModule { - error ModuleAlreadyInitialized(address smartAccount); - error NotInitialized(address smartAccount); - - /** - * @dev This function is called by the smart account during installation of the module - * @param data arbitrary data that may be required on the module during `onInstall` - * initialization - * - * MUST revert on error (i.e. if module is already enabled) - */ - function onInstall(bytes calldata data) external; - - /** - * @dev This function is called by the smart account during uninstallation of the module - * @param data arbitrary data that may be required on the module during `onUninstall` - * de-initialization - * - * MUST revert on error - */ - function onUninstall(bytes calldata data) external; - - /** - * @dev Returns boolean value if module is a certain type - * @param moduleTypeId the module type ID according the ERC-7579 spec - * - * MUST return true if the module is of the given type and false otherwise - */ - function isModuleType(uint256 moduleTypeId) external view returns (bool); - - /** - * @dev Returns if the module was already initialized for a provided smartaccount - */ - function isInitialized(address smartAccount) external view returns (bool); -} - -interface IValidator is IModule { - error InvalidTargetAddress(address target); - - /** - * @dev Validates a transaction on behalf of the account. - * This function is intended to be called by the MSA during the ERC-4337 validaton phase - * Note: solely relying on bytes32 hash and signature is not sufficient for some - * validation implementations (i.e. SessionKeys often need access to userOp.calldata) - * @param userOp The user operation to be validated. The userOp MUST NOT contain any metadata. - * The MSA MUST clean up the userOp before sending it to the validator. - * @param userOpHash The hash of the user operation to be validated - * @return return value according to ERC-4337 - */ - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) - external - payable - returns (uint256); - - /** - * Validator can be used for ERC-1271 validation - */ - function isValidSignatureWithSender( - address sender, - bytes32 hash, - bytes calldata data - ) - external - view - returns (bytes4); -} - -interface IExecutor is IModule { } - -interface IHook is IModule { - function preCheck( - address msgSender, - uint256 msgValue, - bytes calldata msgData - ) - external - returns (bytes memory hookData); - - function postCheck(bytes calldata hookData) external; -} - -interface IFallback is IModule { } - -interface IPolicy is IModule { - function checkUserOpPolicy( - bytes32 id, - PackedUserOperation calldata userOp - ) - external - payable - returns (uint256); - function checkSignaturePolicy( - bytes32 id, - address sender, - bytes32 hash, - bytes calldata sig - ) - external - view - returns (uint256); -} - -interface ISigner is IModule { - function checkUserOpSignature( - bytes32 id, - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) - external - payable - returns (uint256); - function checkSignature( - bytes32 id, - address sender, - bytes32 hash, - bytes calldata sig - ) - external - view - returns (bytes4); -} - -interface IPreValidationHookERC1271 is IModule { - function preValidationHookERC1271( - address sender, - bytes32 hash, - bytes calldata data - ) - external - view - returns (bytes32 hookHash, bytes memory hookSignature); -} - -interface IPreValidationHookERC4337 is IModule { - function preValidationHookERC4337( - PackedUserOperation calldata userOp, - uint256 missingAccountFunds, - bytes32 userOpHash - ) - external - returns (bytes32 hookHash, bytes memory hookSignature); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/common/lib/ModeLib.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/common/lib/ModeLib.sol deleted file mode 100644 index 4500cd6..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/common/lib/ModeLib.sol +++ /dev/null @@ -1,160 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity >=0.8.0 <0.9.0; - -/** - * @title ModeLib - * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) - * To allow smart accounts to be very simple, but allow for more complex execution, A custom mode - * encoding is used. - * Function Signature of execute function: - * function execute(ModeCode mode, bytes calldata executionCalldata) external payable; - * This allows for a single bytes32 to be used to encode the execution mode, calltype, execType and - * context. - * NOTE: Simple Account implementations only have to scope for the most significant byte. Account that - * implement - * more complex execution modes may use the entire bytes32. - * - * |--------------------------------------------------------------------| - * | CALLTYPE | EXECTYPE | UNUSED | ModeSelector | ModePayload | - * |--------------------------------------------------------------------| - * | 1 byte | 1 byte | 4 bytes | 4 bytes | 22 bytes | - * |--------------------------------------------------------------------| - * - * CALLTYPE: 1 byte - * CallType is used to determine how the executeCalldata paramter of the execute function has to be - * decoded. - * It can be either single, batch or delegatecall. In the future different calls could be added. - * CALLTYPE can be used by a validation module to determine how to decode . - * - * EXECTYPE: 1 byte - * ExecType is used to determine how the account should handle the execution. - * It can indicate if the execution should revert on failure or continue execution. - * In the future more execution modes may be added. - * Default Behavior (EXECTYPE = 0x00) is to revert on a single failed execution. If one execution in - * a batch fails, the entire batch is reverted - * - * UNUSED: 4 bytes - * Unused bytes are reserved for future use. - * - * ModeSelector: bytes4 - * The "optional" mode selector can be used by account vendors, to implement custom behavior in - * their accounts. - * the way a ModeSelector is to be calculated is bytes4(keccak256("vendorname.featurename")) - * this is to prevent collisions between different vendors, while allowing innovation and the - * development of new features without coordination between ERC-7579 implementing accounts - * - * ModePayload: 22 bytes - * Mode payload is used to pass additional data to the smart account execution, this may be - * interpreted depending on the ModeSelector - * - * ExecutionCallData: n bytes - * single, delegatecall or batch exec abi.encoded as bytes - */ - -// Custom type for improved developer experience -type ModeCode is bytes32; - -type CallType is bytes1; - -type ExecType is bytes1; - -type ModeSelector is bytes4; - -type ModePayload is bytes22; - -// Default CallType -CallType constant CALLTYPE_SINGLE = CallType.wrap(0x00); -// Batched CallType -CallType constant CALLTYPE_BATCH = CallType.wrap(0x01); -CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); -// @dev Implementing delegatecall is OPTIONAL! -// implement delegatecall with extreme care. -CallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF); - -// @dev default behavior is to revert on failure -// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure -// Since this is value 0x00, no additional encoding is required for simple accounts -ExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00); -// @dev account may elect to change execution behavior. For example "try exec" / "allow fail" -ExecType constant EXECTYPE_TRY = ExecType.wrap(0x01); - -ModeSelector constant MODE_DEFAULT = ModeSelector.wrap(bytes4(0x00000000)); -// Example declaration of a custom mode selector -ModeSelector constant MODE_OFFSET = ModeSelector.wrap(bytes4(keccak256("default.mode.offset"))); - -/** - * @dev ModeLib is a helper library to encode/decode ModeCodes - */ -library ModeLib { - function decode(ModeCode mode) - internal - pure - returns ( - CallType _calltype, - ExecType _execType, - ModeSelector _modeSelector, - ModePayload _modePayload - ) - { - // solhint-disable-next-line no-inline-assembly - assembly { - _calltype := mode - _execType := shl(8, mode) - _modeSelector := shl(48, mode) - _modePayload := shl(80, mode) - } - } - - function encode( - CallType callType, - ExecType execType, - ModeSelector mode, - ModePayload payload - ) - internal - pure - returns (ModeCode) - { - return ModeCode.wrap( - bytes32( - abi.encodePacked(callType, execType, bytes4(0), ModeSelector.unwrap(mode), payload) - ) - ); - } - - function encodeSimpleBatch() internal pure returns (ModeCode mode) { - mode = encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00)); - } - - function encodeSimpleSingle() internal pure returns (ModeCode mode) { - mode = encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00)); - } - - function getCallType(ModeCode mode) internal pure returns (CallType calltype) { - // solhint-disable-next-line no-inline-assembly - assembly { - calltype := mode - } - } -} - -using { eqModeSelector as == } for ModeSelector global; -using { eqCallType as == } for CallType global; -using { neqCallType as != } for CallType global; -using { eqExecType as == } for ExecType global; - -function eqCallType(CallType a, CallType b) pure returns (bool) { - return CallType.unwrap(a) == CallType.unwrap(b); -} - -function neqCallType(CallType a, CallType b) pure returns (bool) { - return CallType.unwrap(a) == CallType.unwrap(b); -} - -function eqExecType(ExecType a, ExecType b) pure returns (bool) { - return ExecType.unwrap(a) == ExecType.unwrap(b); -} - -function eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) { - return ModeSelector.unwrap(a) == ModeSelector.unwrap(b); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/ERC7579Factory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/ERC7579Factory.sol deleted file mode 100644 index 073078d..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/ERC7579Factory.sol +++ /dev/null @@ -1,151 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IAccountFactory } from "../../accounts/factory/interface/IAccountFactory.sol"; -import { IMSA } from "./interfaces/IMSA.sol"; -import { IERC7579Account } from "../../accounts/common/interfaces/IERC7579Account.sol"; -import { - IERC7579Bootstrap, - BootstrapConfig as ERC7579BootstrapConfig -} from "../../accounts/erc7579/interfaces/IERC7579Bootstrap.sol"; - -// Precompiles -import { ERC7579Precompiles } from "../../deployment/precompiles/ERC7579Precompiles.sol"; - -contract ERC7579Factory is IAccountFactory, ERC7579Precompiles { - IERC7579Account public implementation; - IERC7579Bootstrap public bootstrapDefault; - - function init() public override { - implementation = deployERC7579Account(); - bootstrapDefault = deployERC7579Bootstrap(); - } - - function createAccount(bytes32 salt, bytes memory initCode) public override returns (address) { - return deployMSAPRoxy(salt, address(implementation), initCode); - } - - function createAccountWithModules( - bytes32 salt, - ERC7579BootstrapConfig[] calldata validators, - ERC7579BootstrapConfig[] calldata executors, - ERC7579BootstrapConfig calldata _fallback, - ERC7579BootstrapConfig[] calldata hooks - ) - public - payable - virtual - returns (address) - { - bytes memory initData = abi.encode( - bootstrapDefault, - abi.encodeCall(IERC7579Bootstrap.initMSA, (validators, executors, _fallback, hooks)) - ); - - address account = deployMSAPRoxy(salt, address(implementation), initData); - - return account; - } - - function getInitData(bytes memory initCode) public view returns (bytes memory _init) { - ( - ERC7579BootstrapConfig[] memory _validators, - ERC7579BootstrapConfig[] memory _executors, - ERC7579BootstrapConfig memory hook, - ERC7579BootstrapConfig[] memory fallbacks - ) = abi.decode( - initCode, - ( - ERC7579BootstrapConfig[], - ERC7579BootstrapConfig[], - ERC7579BootstrapConfig, - ERC7579BootstrapConfig[] - ) - ); - _init = abi.encode( - address(bootstrapDefault), - abi.encodeCall(IERC7579Bootstrap.initMSA, (_validators, _executors, hook, fallbacks)) - ); - } - - function getInitData( - IAccountFactory.ModuleInitData[] memory _validators, - IAccountFactory.ModuleInitData[] memory _executors, - IAccountFactory.ModuleInitData memory _hook, - IAccountFactory.ModuleInitData[] memory _fallbacks - ) - public - view - returns (bytes memory _init) - { - ERC7579BootstrapConfig[] memory validators = - abi.decode(abi.encode(_validators), (ERC7579BootstrapConfig[])); - ERC7579BootstrapConfig[] memory executors = - abi.decode(abi.encode(_executors), (ERC7579BootstrapConfig[])); - ERC7579BootstrapConfig memory hook = abi.decode(abi.encode(_hook), (ERC7579BootstrapConfig)); - ERC7579BootstrapConfig[] memory fallbacks = - abi.decode(abi.encode(_fallbacks), (ERC7579BootstrapConfig[])); - - _init = abi.encode( - address(bootstrapDefault), - abi.encodeCall(IERC7579Bootstrap.initMSA, (validators, executors, hook, fallbacks)) - ); - } - - function getAddress( - bytes32 salt, - bytes memory initCode - ) - public - view - override - returns (address) - { - bytes32 hash = keccak256( - abi.encodePacked( - bytes1(0xff), - address(this), - salt, - keccak256( - abi.encodePacked( - MSAPROXY_BYTECODE, - abi.encode( - address(implementation), - abi.encodeCall(IMSA.initializeAccount, initCode) - ) - ) - ) - ) - ); - - return address(uint160(uint256(hash))); - } - - function getInitData( - address validator, - bytes memory initData - ) - public - view - override - returns (bytes memory _init) - { - ERC7579BootstrapConfig[] memory _validators = new ERC7579BootstrapConfig[](1); - _validators[0].module = validator; - _validators[0].data = initData; - ERC7579BootstrapConfig[] memory _executors = new ERC7579BootstrapConfig[](0); - - ERC7579BootstrapConfig memory _hook; - - ERC7579BootstrapConfig[] memory _fallBacks = new ERC7579BootstrapConfig[](0); - _init = abi.encode( - address(bootstrapDefault), - abi.encodeCall(IERC7579Bootstrap.initMSA, (_validators, _executors, _hook, _fallBacks)) - ); - } - - function _getSalt(bytes32 _salt, bytes memory initCode) internal pure returns (bytes32 salt) { - salt = keccak256(abi.encodePacked(_salt, initCode)); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/helpers/ExecutionHelper.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/helpers/ExecutionHelper.sol deleted file mode 100644 index 2f803af..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/helpers/ExecutionHelper.sol +++ /dev/null @@ -1,139 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -// Types -import { Execution } from "../../common/interfaces/IERC7579Account.sol"; - -/** - * @title Execution - * @dev This contract executes calls in the context of this contract. - * @author zeroknots.eth | rhinestone.wtf - * shoutout to solady (vectorized, ross) for this code - * https://github.com/Vectorized/solady/blob/main/src/accounts/ERC4337.sol - */ -contract ExecutionHelper { - error ExecutionFailed(); - - event TryExecuteUnsuccessful(uint256 batchExecutionindex, bytes result); - - function _execute(Execution[] calldata executions) internal returns (bytes[] memory result) { - uint256 length = executions.length; - result = new bytes[](length); - - for (uint256 i; i < length; i++) { - Execution calldata _exec = executions[i]; - result[i] = _execute(_exec.target, _exec.value, _exec.callData); - } - } - - function _tryExecute(Execution[] calldata executions) - internal - returns (bytes[] memory result) - { - uint256 length = executions.length; - result = new bytes[](length); - - for (uint256 i; i < length; i++) { - Execution calldata _exec = executions[i]; - bool success; - (success, result[i]) = _tryExecute(_exec.target, _exec.value, _exec.callData); - if (!success) emit TryExecuteUnsuccessful(i, result[i]); - } - } - - function _execute( - address target, - uint256 value, - bytes calldata callData - ) - internal - virtual - returns (bytes memory result) - { - /// @solidity memory-safe-assembly - // solhint-disable-next-line no-inline-assembly - assembly { - result := mload(0x40) - calldatacopy(result, callData.offset, callData.length) - if iszero(call(gas(), target, value, result, callData.length, codesize(), 0x00)) { - // Bubble up the revert if the call reverts. - returndatacopy(result, 0x00, returndatasize()) - revert(result, returndatasize()) - } - mstore(result, returndatasize()) // Store the length. - let o := add(result, 0x20) - returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. - mstore(0x40, add(o, returndatasize())) // Allocate the memory. - } - } - - function _tryExecute( - address target, - uint256 value, - bytes calldata callData - ) - internal - virtual - returns (bool success, bytes memory result) - { - /// @solidity memory-safe-assembly - // solhint-disable-next-line no-inline-assembly - assembly { - result := mload(0x40) - calldatacopy(result, callData.offset, callData.length) - success := call(gas(), target, value, result, callData.length, codesize(), 0x00) - mstore(result, returndatasize()) // Store the length. - let o := add(result, 0x20) - returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. - mstore(0x40, add(o, returndatasize())) // Allocate the memory. - } - } - - /// @dev Execute a delegatecall with `delegate` on this account. - function _executeDelegatecall( - address delegate, - bytes calldata callData - ) - internal - returns (bytes memory result) - { - /// @solidity memory-safe-assembly - // solhint-disable-next-line no-inline-assembly - assembly { - result := mload(0x40) - calldatacopy(result, callData.offset, callData.length) - // Forwards the `data` to `delegate` via delegatecall. - if iszero(delegatecall(gas(), delegate, result, callData.length, codesize(), 0x00)) { - // Bubble up the revert if the call reverts. - returndatacopy(result, 0x00, returndatasize()) - revert(result, returndatasize()) - } - mstore(result, returndatasize()) // Store the length. - let o := add(result, 0x20) - returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. - mstore(0x40, add(o, returndatasize())) // Allocate the memory. - } - } - - /// @dev Execute a delegatecall with `delegate` on this account and catch reverts. - function _tryExecuteDelegatecall( - address delegate, - bytes calldata callData - ) - internal - returns (bool success, bytes memory result) - { - /// @solidity memory-safe-assembly - // solhint-disable-next-line no-inline-assembly - assembly { - result := mload(0x40) - calldatacopy(result, callData.offset, callData.length) - // Forwards the `data` to `delegate` via delegatecall. - success := delegatecall(gas(), delegate, result, callData.length, codesize(), 0x00) - mstore(result, returndatasize()) // Store the length. - let o := add(result, 0x20) - returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. - mstore(0x40, add(o, returndatasize())) // Allocate the memory. - } - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IERC7579Bootstrap.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IERC7579Bootstrap.sol deleted file mode 100644 index 727a85e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IERC7579Bootstrap.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IModule } from "../../common/interfaces/IERC7579Module.sol"; - -// Structs -struct BootstrapConfig { - address module; - bytes data; -} - -interface IERC7579Bootstrap { - function singleInitMSA(IModule validator, bytes calldata data) external; - - /** - * This function is intended to be called by the MSA with a delegatecall. - * Make sure that the MSA already initilazed the linked lists in the ModuleManager prior to - * calling this function - */ - function initMSA( - BootstrapConfig[] calldata $valdiators, - BootstrapConfig[] calldata $executors, - BootstrapConfig calldata _hook, - BootstrapConfig[] calldata _fallbacks - ) - external; - - function _getInitMSACalldata( - BootstrapConfig[] calldata $valdiators, - BootstrapConfig[] calldata $executors, - BootstrapConfig calldata _hook, - BootstrapConfig[] calldata _fallbacks - ) - external - view - returns (bytes memory init); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IMSA.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IMSA.sol deleted file mode 100644 index 12a7810..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/interfaces/IMSA.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IERC7579Account } from "../../common/interfaces/IERC7579Account.sol"; -import { IERC4337Account } from "../../common/interfaces/IERC4337Account.sol"; - -// Types -import { CallType, ExecType } from "../../common/lib/ModeLib.sol"; - -interface IMSA is IERC7579Account, IERC4337Account { - // Error thrown when an unsupported ModuleType is requested - error UnsupportedModuleType(uint256 moduleTypeId); - // Error thrown when an execution with an unsupported CallType was made - error UnsupportedCallType(CallType callType); - // Error thrown when an execution with an unsupported ExecType was made - error UnsupportedExecType(ExecType execType); - // Error thrown when account initialization fails - error AccountInitializationFailed(); - // Error thrown when account installs/unistalls module with mismatched input `moduleTypeId` - error MismatchModuleTypeId(uint256 moduleTypeId); - - /** - * @dev Initializes the account. Function might be called directly, or by a Factory - * @param data. encoded data that can be used during the initialization phase - */ - function initializeAccount(bytes calldata data) external payable; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/lib/ExecutionLib.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/lib/ExecutionLib.sol deleted file mode 100644 index 862e39e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/erc7579/lib/ExecutionLib.sol +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { Execution } from "../../common/interfaces/IERC7579Account.sol"; - -/** - * Helper Library for decoding Execution calldata - * malloc for memory allocation is bad for gas. use this assembly instead - */ -library ExecutionLib { - error ERC7579DecodingError(); - - /** - * @notice Decode a batch of `Execution` executionBatch from a `bytes` calldata. - * @dev code is copied from solady's LibERC7579.sol - * https://github.com/Vectorized/solady/blob/740812cedc9a1fc11e17cb3d4569744367dedf19/src/accounts/LibERC7579.sol#L146 - * Credits to Vectorized and the Solady Team - */ - function decodeBatch(bytes calldata executionCalldata) - internal - pure - returns (Execution[] calldata executionBatch) - { - /// @solidity memory-safe-assembly - assembly { - let u := calldataload(executionCalldata.offset) - let s := add(executionCalldata.offset, u) - let e := sub(add(executionCalldata.offset, executionCalldata.length), 0x20) - executionBatch.offset := add(s, 0x20) - executionBatch.length := calldataload(s) - if or(shr(64, u), gt(add(s, shl(5, executionBatch.length)), e)) { - mstore(0x00, 0xba597e7e) // `DecodingError()`. - revert(0x1c, 0x04) - } - if executionBatch.length { - // Perform bounds checks on the decoded `executionBatch`. - // Loop runs out-of-gas if `executionBatch.length` is big enough to cause overflows. - for { let i := executionBatch.length } 1 { } { - i := sub(i, 1) - let p := calldataload(add(executionBatch.offset, shl(5, i))) - let c := add(executionBatch.offset, p) - let q := calldataload(add(c, 0x40)) - let o := add(c, q) - // forgefmt: disable-next-item - if or(shr(64, or(calldataload(o), or(p, q))), - or(gt(add(c, 0x40), e), gt(add(o, calldataload(o)), e))) { - mstore(0x00, 0xba597e7e) // `DecodingError()`. - revert(0x1c, 0x04) - } - if iszero(i) { break } - } - } - } - } - - function encodeBatch(Execution[] memory executions) - internal - pure - returns (bytes memory callData) - { - callData = abi.encode(executions); - } - - function decodeSingle(bytes calldata executionCalldata) - internal - pure - returns (address target, uint256 value, bytes calldata callData) - { - target = address(bytes20(executionCalldata[0:20])); - value = uint256(bytes32(executionCalldata[20:52])); - callData = executionCalldata[52:]; - } - - function encodeSingle( - address target, - uint256 value, - bytes memory callData - ) - internal - pure - returns (bytes memory userOpCalldata) - { - userOpCalldata = abi.encodePacked(target, value, callData); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/factory/interface/IAccountFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/factory/interface/IAccountFactory.sol deleted file mode 100644 index 5bbb32a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/factory/interface/IAccountFactory.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -interface IAccountFactory { - struct ModuleInitData { - address module; - bytes data; - } - - function init() external; - - function createAccount( - bytes32 salt, - bytes memory initCode - ) - external - returns (address account); - - function getAddress(bytes32 salt, bytes memory initCode) external returns (address); - - function getInitData( - address validator, - bytes memory initData - ) - external - returns (bytes memory init); - - function getInitData( - IAccountFactory.ModuleInitData[] memory validators, - IAccountFactory.ModuleInitData[] memory executors, - IAccountFactory.ModuleInitData memory hook, - IAccountFactory.ModuleInitData[] memory fallbacks - ) - external - returns (bytes memory _init); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/factory/template/FactoryTemplate.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/factory/template/FactoryTemplate.sol deleted file mode 100644 index 9a5d4ba..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/factory/template/FactoryTemplate.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -abstract contract FactoryTemplate { - constructor() { - // Deploy any required contracts - } - - function createAccountName( - bytes32 salt, - bytes memory initCode - ) - public - returns (address account) - { - // Deploy the account - } - - function getAddressAccountName( - bytes32 salt, - bytes memory initCode - ) - public - view - returns (address) - { - // Return the address of the account - } - - function getInitDataAccountName( - address validator, - bytes memory initData - ) - public - returns (bytes memory init) - { - // Return the init data - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/KernelFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/KernelFactory.sol deleted file mode 100644 index 3803ae9..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/KernelFactory.sol +++ /dev/null @@ -1,181 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -import { IKernelFactory as IKernelAccountFactory } from - "../../accounts/kernel/interfaces/IKernelFactory.sol"; -import { IKernel } from "../../accounts/kernel/interfaces/IKernel.sol"; -import { ENTRYPOINT_ADDR } from "../../deployment/predeploy/EntryPoint.sol"; -import { ValidatorLib } from "../../accounts/kernel/lib/ValidationTypeLib.sol"; -import { ValidationId } from "../../accounts/kernel/types/Types.sol"; -import { IValidator } from "../../accounts/common/interfaces/IERC7579Module.sol"; -import { IHook } from "../../accounts/kernel/interfaces/IERC7579Module.sol"; -import { IAccountFactory } from "../../accounts/factory/interface/IAccountFactory.sol"; -import { MockHookMultiPlexer } from "../../Mocks.sol"; -import { KernelPrecompiles } from "../../deployment/precompiles/KernelPrecompiles.sol"; -import { - MODULE_TYPE_VALIDATOR, - MODULE_TYPE_EXECUTOR, - MODULE_TYPE_FALLBACK -} from "./types/Constants.sol"; - -struct ModuleBootstrapConfig { - address module; - bytes initData; -} - -contract KernelFactory is IAccountFactory, KernelPrecompiles { - IKernelAccountFactory public factory; - IKernel public kernelImpl; - MockHookMultiPlexer public hookMultiPlexer; - - function init() public override { - kernelImpl = deployKernel(ENTRYPOINT_ADDR); - factory = deployKernelFactory(address(kernelImpl)); - hookMultiPlexer = new MockHookMultiPlexer(); - } - - function createAccount( - bytes32 salt, - bytes memory data - ) - public - override - returns (address account) - { - account = factory.createAccount(data, salt); - } - - function getAddress(bytes32 salt, bytes memory data) public override returns (address) { - return factory.getAddress(data, salt); - } - - function getInitData( - address validator, - bytes memory initData - ) - public - view - override - returns (bytes memory _init) - { - ValidationId rootValidator = ValidatorLib.validatorToIdentifier(IValidator(validator)); - - _init = abi.encodeCall( - IKernel.initialize, - (rootValidator, IHook(address(hookMultiPlexer)), initData, hex"00", new bytes[](0)) - ); - } - - function getInitData( - IAccountFactory.ModuleInitData[] memory validators, - IAccountFactory.ModuleInitData[] memory executors, - IAccountFactory.ModuleInitData memory hook, - IAccountFactory.ModuleInitData[] memory fallbacks - ) - public - pure - override - returns (bytes memory _init) - { - address[] memory attesters = new address[](1); - attesters[0] = address(0x000000333034E9f539ce08819E12c1b8Cb29084d); - - ValidationId rootValidator = - ValidatorLib.validatorToIdentifier(IValidator(validators[0].module)); - // Encode the rest of the validators, executors and fallbacks are onInstall calls with the - // appropriate address and initData - bytes[] memory otherModules = - new bytes[](validators.length - 1 + executors.length + fallbacks.length); - uint256 index = 0; - for (uint256 i = 1; i < validators.length; i++) { - otherModules[index] = abi.encodeCall( - IKernel.installModule, - (MODULE_TYPE_VALIDATOR, validators[i].module, validators[i].data) - ); - index++; - } - for (uint256 i = 0; i < executors.length; i++) { - otherModules[index] = abi.encodeCall( - IKernel.installModule, - (MODULE_TYPE_EXECUTOR, executors[i].module, executors[i].data) - ); - index++; - } - for (uint256 i = 0; i < fallbacks.length; i++) { - otherModules[index] = abi.encodeCall( - IKernel.installModule, - (MODULE_TYPE_FALLBACK, fallbacks[i].module, fallbacks[i].data) - ); - index++; - } - _init = abi.encodeCall( - IKernel.initialize, - ( - rootValidator, - IHook(address(hook.module)), - validators[0].data, - hook.data, - otherModules - ) - ); - } - - function getInitData(bytes memory initData) public pure returns (bytes memory _init) { - ( - ModuleBootstrapConfig[] memory validators, - ModuleBootstrapConfig[] memory executors, - ModuleBootstrapConfig memory hook, - ModuleBootstrapConfig[] memory fallbacks - ) = abi.decode( - initData, - ( - ModuleBootstrapConfig[], - ModuleBootstrapConfig[], - ModuleBootstrapConfig, - ModuleBootstrapConfig[] - ) - ); - ValidationId rootValidator = - ValidatorLib.validatorToIdentifier(IValidator(validators[0].module)); - // Encode the rest of the validators, executors and fallbacks are onInstall calls with the - // appropriate address and initData - bytes[] memory otherModules = - new bytes[](validators.length - 1 + executors.length + fallbacks.length); - uint256 index = 0; - for (uint256 i = 1; i < validators.length; i++) { - otherModules[index] = abi.encodeCall( - IKernel.installModule, - (MODULE_TYPE_VALIDATOR, validators[i].module, validators[i].initData) - ); - index++; - } - for (uint256 i = 0; i < executors.length; i++) { - otherModules[index] = abi.encodeCall( - IKernel.installModule, - (MODULE_TYPE_EXECUTOR, executors[i].module, executors[i].initData) - ); - index++; - } - for (uint256 i = 0; i < fallbacks.length; i++) { - otherModules[index] = abi.encodeCall( - IKernel.installModule, - (MODULE_TYPE_FALLBACK, fallbacks[i].module, fallbacks[i].initData) - ); - index++; - } - _init = abi.encodeCall( - IKernel.initialize, - ( - rootValidator, - IHook(address(hook.module)), - validators[0].initData, - hook.initData, - otherModules - ) - ); - } - - function setHookMultiPlexer(address hook) public { - hookMultiPlexer = MockHookMultiPlexer(hook); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccount.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccount.sol deleted file mode 100644 index 3c071f5..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccount.sol +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { PackedUserOperation } from - "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; -import "../types/Types.sol"; - -interface IAccount { - /** - * Validate user's signature and nonce - * the entryPoint will make the call to the recipient only if this validation call returns - * successfully. - * signature failure should be reported by returning SIG_VALIDATION_FAILED (1). - * This allows making a "simulation call" without a valid signature - * Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to - * signal failure. - * - * @dev Must validate caller is the entryPoint. - * Must validate the signature and nonce - * @param userOp - The operation that is about to be executed. - * @param userOpHash - Hash of the user's request data. can be used as the basis for - * signature. - * @param missingAccountFunds - Missing funds on the account's deposit in the entrypoint. - * This is the minimum amount to transfer to the sender(entryPoint) - * to be - * able to make the call. The excess is left as a deposit in the - * entrypoint - * for future calls. Can be withdrawn anytime using - * "entryPoint.withdrawTo()". - * In case there is a paymaster in the request (or the current - * deposit is high - * enough), this value will be zero. - * @return validationData - Packaged ValidationData structure. use `_packValidationData` - * and - * `_unpackValidationData` to encode and decode. - * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark - * signature failure, - * otherwise, an address of an "authorizer" contract. - * <6-byte> validUntil - Last timestamp this operation is valid. 0 - * for "indefinite" - * <6-byte> validAfter - First timestamp this operation is valid - * If an account doesn't use time-range, it - * is enough to - * return SIG_VALIDATION_FAILED value (1) for - * signature failure. - * Note that the validation code cannot use block.timestamp (or - * block.number) directly. - */ - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash, - uint256 missingAccountFunds - ) - external - payable - returns (ValidationData validationData); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccountExecute.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccountExecute.sol deleted file mode 100644 index ca16aa4..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IAccountExecute.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { PackedUserOperation } from - "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; - -interface IAccountExecute { - /** - * Account may implement this execute method. - * passing this methodSig at the beginning of callData will cause the entryPoint to pass the - * full UserOp (and hash) - * to the account. - * The account should skip the methodSig, and use the callData (and optionally, other UserOp - * fields) - * - * @param userOp - The operation that was just validated. - * @param userOpHash - Hash of the user's request data. - */ - function executeUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) - external - payable; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Account.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Account.sol deleted file mode 100644 index b4080e5..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Account.sol +++ /dev/null @@ -1,133 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/* solhint-disable no-unused-import */ - -// Types -import { CallType, ExecType, ExecMode } from "../lib/ExecLib.sol"; -import { PackedUserOperation } from - "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; - -// Structs -struct Execution { - address target; - uint256 value; - bytes callData; -} - -interface IERC7579Account { - event ModuleInstalled(uint256 moduleTypeId, address module); - event ModuleUninstalled(uint256 moduleTypeId, address module); - - /** - * @dev Executes a transaction on behalf of the account. - * This function is intended to be called by ERC-4337 EntryPoint.sol - * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf - * - * @dev MSA MUST implement this function signature. - * If a mode is requested that is not supported by the Account, it MUST revert - * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details - * @param executionCalldata The encoded execution call data - */ - function execute(ExecMode mode, bytes calldata executionCalldata) external payable; - - /** - * @dev Executes a transaction on behalf of the account. - * This function is intended to be called by Executor Modules - * @dev Ensure adequate authorization control: i.e. onlyExecutorModule - * - * @dev MSA MUST implement this function signature. - * If a mode is requested that is not supported by the Account, it MUST revert - * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details - * @param executionCalldata The encoded execution call data - */ - function executeFromExecutor( - ExecMode mode, - bytes calldata executionCalldata - ) - external - payable - returns (bytes[] memory returnData); - - /** - * @dev ERC-1271 isValidSignature - * This function is intended to be used to validate a smart account signature - * and may forward the call to a validator module - * - * @param hash The hash of the data that is signed - * @param data The data that is signed - */ - function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4); - - /** - * @dev installs a Module of a certain type on the smart account - * @dev Implement Authorization control of your choosing - * @param moduleTypeId the module type ID according the ERC-7579 spec - * @param module the module address - * @param initData arbitrary data that may be required on the module during `onInstall` - * initialization. - */ - function installModule( - uint256 moduleTypeId, - address module, - bytes calldata initData - ) - external - payable; - - /** - * @dev uninstalls a Module of a certain type on the smart account - * @dev Implement Authorization control of your choosing - * @param moduleTypeId the module type ID according the ERC-7579 spec - * @param module the module address - * @param deInitData arbitrary data that may be required on the module during `onUninstall` - * de-initialization. - */ - function uninstallModule( - uint256 moduleTypeId, - address module, - bytes calldata deInitData - ) - external - payable; - - /** - * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol) - * @param encodedMode the encoded mode - */ - function supportsExecutionMode(ExecMode encodedMode) external view returns (bool); - - /** - * Function to check if the account supports installation of a certain module type Id - * @param moduleTypeId the module type ID according the ERC-7579 spec - */ - function supportsModule(uint256 moduleTypeId) external view returns (bool); - - /** - * Function to check if the account has a certain module installed - * @param moduleTypeId the module type ID according the ERC-7579 spec - * Note: keep in mind that some contracts can be multiple module types at the same time. It - * thus may be necessary to query multiple module types - * @param module the module address - * @param additionalContext additional context data that the smart account may interpret to - * identify conditions under which the module is installed. - * usually this is not necessary, but for some special hooks that - * are stored in mappings, this param might be needed - */ - function isModuleInstalled( - uint256 moduleTypeId, - address module, - bytes calldata additionalContext - ) - external - view - returns (bool); - - /** - * @dev Returns the account id of the smart account - * @return accountImplementationId the account id of the smart account - * the accountId should be structured like so: - * "vendorname.accountname.semver" - */ - function accountId() external view returns (string memory accountImplementationId); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Module.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Module.sol deleted file mode 100644 index 90a7272..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IERC7579Module.sol +++ /dev/null @@ -1,133 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.21; - -// Types -import { PackedUserOperation } from - "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; - -interface IModule { - error ModuleAlreadyInitialized(address smartAccount); - error NotInitialized(address smartAccount); - - /** - * @dev This function is called by the smart account during installation of the module - * @param data arbitrary data that may be required on the module during `onInstall` - * initialization - * - * MUST revert on error (i.e. if module is already enabled) - */ - function onInstall(bytes calldata data) external payable; - - /** - * @dev This function is called by the smart account during uninstallation of the module - * @param data arbitrary data that may be required on the module during `onUninstall` - * de-initialization - * - * MUST revert on error - */ - function onUninstall(bytes calldata data) external payable; - - /** - * @dev Returns boolean value if module is a certain type - * @param moduleTypeId the module type ID according the ERC-7579 spec - * - * MUST return true if the module is of the given type and false otherwise - */ - function isModuleType(uint256 moduleTypeId) external view returns (bool); - - /** - * @dev Returns if the module was already initialized for a provided smartaccount - */ - function isInitialized(address smartAccount) external view returns (bool); -} - -interface IValidator is IModule { - error InvalidTargetAddress(address target); - - /** - * @dev Validates a transaction on behalf of the account. - * This function is intended to be called by the MSA during the ERC-4337 validation - * phase - * Note: solely relying on bytes32 hash and signature is not sufficient for some - * validation implementations (i.e. SessionKeys often need access to userOp.calldata) - * @param userOp The user operation to be validated. The userOp MUST NOT contain any metadata. - * The MSA MUST clean up the userOp before sending it to the validator. - * @param userOpHash The hash of the user operation to be validated - * @return return value according to ERC-4337 - */ - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) - external - payable - returns (uint256); - - /** - * Validator can be used for ERC-1271 validation - */ - function isValidSignatureWithSender( - address sender, - bytes32 hash, - bytes calldata data - ) - external - view - returns (bytes4); -} - -interface IExecutor is IModule { } - -interface IHook is IModule { - function preCheck( - address msgSender, - uint256 msgValue, - bytes calldata msgData - ) - external - payable - returns (bytes memory hookData); - - function postCheck(bytes calldata hookData) external payable; -} - -interface IFallback is IModule { } - -interface IPolicy is IModule { - function checkUserOpPolicy( - bytes32 id, - PackedUserOperation calldata userOp - ) - external - payable - returns (uint256); - function checkSignaturePolicy( - bytes32 id, - address sender, - bytes32 hash, - bytes calldata sig - ) - external - view - returns (uint256); -} - -interface ISigner is IModule { - function checkUserOpSignature( - bytes32 id, - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) - external - payable - returns (uint256); - function checkSignature( - bytes32 id, - address sender, - bytes32 hash, - bytes calldata sig - ) - external - view - returns (bytes4); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernel.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernel.sol deleted file mode 100644 index aa2b408..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernel.sol +++ /dev/null @@ -1,151 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IERC7579Account } from "./IERC7579Account.sol"; -import { IAccount, ValidationData } from "./IAccount.sol"; -import { IAccountExecute } from "./IAccountExecute.sol"; -import { IHook } from "./IERC7579Module.sol"; - -// Types -import { ValidationId, ValidationConfig } from "../lib/ValidationTypeLib.sol"; -import { PackedUserOperation } from - "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; -import { ExecMode } from "../lib/ExecLib.sol"; - -interface IKernel is IAccount, IAccountExecute, IERC7579Account { - function initialize( - ValidationId _rootValidator, - IHook hook, - bytes calldata validatorData, - bytes calldata hookData, - bytes[] calldata initConfig - ) - external; - - function upgradeTo(address _newImplementation) external payable; - - function onERC721Received( - address, - address, - uint256, - bytes calldata - ) - external - pure - returns (bytes4); - - function onERC1155Received( - address, - address, - uint256, - uint256, - bytes calldata - ) - external - pure - returns (bytes4); - - function onERC1155BatchReceived( - address, - address, - uint256[] calldata, - uint256[] calldata, - bytes calldata - ) - external - pure - returns (bytes4); - - // validation part - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash, - uint256 missingAccountFunds - ) - external - payable - returns (ValidationData validationData); - - // --- Execution --- - function executeUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) - external - payable; - - function executeFromExecutor( - ExecMode execMode, - bytes calldata executionCalldata - ) - external - payable - returns (bytes[] memory returnData); - - function execute(ExecMode execMode, bytes calldata executionCalldata) external payable; - - function isValidSignature( - bytes32 hash, - bytes calldata signature - ) - external - view - returns (bytes4); - - function installModule( - uint256 moduleType, - address module, - bytes calldata initData - ) - external - payable; - - function installValidations( - ValidationId[] calldata vIds, - ValidationConfig[] memory configs, - bytes[] calldata validationData, - bytes[] calldata hookData - ) - external - payable; - - function uninstallValidation( - ValidationId vId, - bytes calldata deinitData, - bytes calldata hookDeinitData - ) - external - payable; - - function invalidateNonce(uint32 nonce) external payable; - - function uninstallModule( - uint256 moduleType, - address module, - bytes calldata deInitData - ) - external - payable; - - function supportsModule(uint256 moduleTypeId) external pure returns (bool); - - function isModuleInstalled( - uint256 moduleType, - address module, - bytes calldata additionalContext - ) - external - view - returns (bool); - - function accountId() external pure returns (string memory accountImplementationId); - - function supportsExecutionMode(ExecMode mode) external pure returns (bool); - - function isAllowedSelector(ValidationId vId, bytes4 selector) external view returns (bool); - - function _toWrappedHash(bytes32 hash) external view returns (bytes32); - - function validationConfig(ValidationId vId) external view returns (ValidationConfig memory); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernelFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernelFactory.sol deleted file mode 100644 index 5118e31..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IKernelFactory.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -interface IKernelFactory { - function createAccount(bytes calldata data, bytes32 salt) external payable returns (address); - function getAddress(bytes calldata data, bytes32 salt) external returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IValidationManager.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IValidationManager.sol deleted file mode 100644 index 7266e5a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/interfaces/IValidationManager.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IHook, ISigner } from "../../../accounts/common/interfaces/IERC7579Module.sol"; - -// Types -import { PassFlag, PolicyData, ValidationId, PermissionId } from "../lib/ValidationTypeLib.sol"; - -// erc7579 plugins -struct ValidationConfig { - uint32 nonce; // 4 bytes - IHook hook; // 20 bytes address(1) : hook not required, address(0) : validator not installed -} - -struct PermissionConfig { - PassFlag permissionFlag; - ISigner signer; - PolicyData[] policyData; -} - -struct ValidationStorage { - ValidationId rootValidator; - uint32 currentNonce; - uint32 validNonceFrom; - mapping(ValidationId => ValidationConfig) validationConfig; - mapping(ValidationId => mapping(bytes4 => bool)) allowedSelectors; - // validation = validator | permission - // validator == 1 validator - // permission == 1 signer + N policies - mapping(PermissionId => PermissionConfig) permissionConfig; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ExecLib.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ExecLib.sol deleted file mode 100644 index 7e5c958..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ExecLib.sol +++ /dev/null @@ -1,325 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { ExecMode, CallType, ExecType, ExecModeSelector, ExecModePayload } from "../types/Types.sol"; -import { - CALLTYPE_SINGLE, - CALLTYPE_BATCH, - EXECTYPE_DEFAULT, - EXEC_MODE_DEFAULT, - EXECTYPE_TRY, - CALLTYPE_DELEGATECALL -} from "../types/Constants.sol"; -import { Execution } from "../types/Structs.sol"; - -/** - * @dev ExecLib is a helper library for execution - */ -library ExecLib { - error ExecutionFailed(); - - event TryExecuteUnsuccessful(uint256 batchExecutionindex, bytes result); - - function execute( - ExecMode execMode, - bytes calldata executionCalldata - ) - internal - returns (bytes[] memory returnData) - { - (CallType callType, ExecType execType,,) = decode(execMode); - - // check if calltype is batch or single - if (callType == CALLTYPE_BATCH) { - // destructure executionCallData according to batched exec - Execution[] calldata executions = decodeBatch(executionCalldata); - // check if execType is revert or try - if (execType == EXECTYPE_DEFAULT) returnData = execute(executions); - else if (execType == EXECTYPE_TRY) returnData = tryExecute(executions); - else revert("Unsupported"); - } else if (callType == CALLTYPE_SINGLE) { - // destructure executionCallData according to single exec - (address target, uint256 value, bytes calldata callData) = - decodeSingle(executionCalldata); - returnData = new bytes[](1); - bool success; - // check if execType is revert or try - if (execType == EXECTYPE_DEFAULT) { - returnData[0] = execute(target, value, callData); - } else if (execType == EXECTYPE_TRY) { - (success, returnData[0]) = tryExecute(target, value, callData); - if (!success) emit TryExecuteUnsuccessful(0, returnData[0]); - } else { - revert("Unsupported"); - } - } else if (callType == CALLTYPE_DELEGATECALL) { - returnData = new bytes[](1); - address delegate = address(bytes20(executionCalldata[0:20])); - bytes calldata callData = executionCalldata[20:]; - bool success; - (success, returnData[0]) = executeDelegatecall(delegate, callData); - if (execType == EXECTYPE_TRY) { - if (!success) emit TryExecuteUnsuccessful(0, returnData[0]); - } else if (execType == EXECTYPE_DEFAULT) { - if (!success) revert("Delegatecall failed"); - } else { - revert("Unsupported"); - } - } else { - revert("Unsupported"); - } - } - - function execute(Execution[] calldata executions) internal returns (bytes[] memory result) { - uint256 length = executions.length; - result = new bytes[](length); - - for (uint256 i; i < length; i++) { - Execution calldata _exec = executions[i]; - result[i] = execute(_exec.target, _exec.value, _exec.callData); - } - } - - function tryExecute(Execution[] calldata executions) internal returns (bytes[] memory result) { - uint256 length = executions.length; - result = new bytes[](length); - - for (uint256 i; i < length; i++) { - Execution calldata _exec = executions[i]; - bool success; - (success, result[i]) = tryExecute(_exec.target, _exec.value, _exec.callData); - if (!success) emit TryExecuteUnsuccessful(i, result[i]); - } - } - - function execute( - address target, - uint256 value, - bytes calldata callData - ) - internal - returns (bytes memory result) - { - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) - calldatacopy(result, callData.offset, callData.length) - if iszero(call(gas(), target, value, result, callData.length, codesize(), 0x00)) { - // Bubble up the revert if the call reverts. - returndatacopy(result, 0x00, returndatasize()) - revert(result, returndatasize()) - } - mstore(result, returndatasize()) // Store the length. - let o := add(result, 0x20) - returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. - mstore(0x40, add(o, returndatasize())) // Allocate the memory. - } - } - - function tryExecute( - address target, - uint256 value, - bytes calldata callData - ) - internal - returns (bool success, bytes memory result) - { - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) - calldatacopy(result, callData.offset, callData.length) - success := call(gas(), target, value, result, callData.length, codesize(), 0x00) - mstore(result, returndatasize()) // Store the length. - let o := add(result, 0x20) - returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. - mstore(0x40, add(o, returndatasize())) // Allocate the memory. - } - } - - /// @dev Execute a delegatecall with `delegate` on this account. - function executeDelegatecall( - address delegate, - bytes calldata callData - ) - internal - returns (bool success, bytes memory result) - { - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) - calldatacopy(result, callData.offset, callData.length) - // Forwards the `data` to `delegate` via delegatecall. - success := delegatecall(gas(), delegate, result, callData.length, codesize(), 0x00) - mstore(result, returndatasize()) // Store the length. - let o := add(result, 0x20) - returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. - mstore(0x40, add(o, returndatasize())) // Allocate the memory. - } - } - - function decode(ExecMode mode) - internal - pure - returns ( - CallType _calltype, - ExecType _execType, - ExecModeSelector _modeSelector, - ExecModePayload _modePayload - ) - { - assembly { - _calltype := mode - _execType := shl(8, mode) - _modeSelector := shl(48, mode) - _modePayload := shl(80, mode) - } - } - - function encode( - CallType callType, - ExecType execType, - ExecModeSelector mode, - ExecModePayload payload - ) - internal - pure - returns (ExecMode) - { - return ExecMode.wrap( - bytes32( - abi.encodePacked( - callType, execType, bytes4(0), ExecModeSelector.unwrap(mode), payload - ) - ) - ); - } - - function encodeSimpleBatch() internal pure returns (ExecMode mode) { - mode = - encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, EXEC_MODE_DEFAULT, ExecModePayload.wrap(0x00)); - } - - function encodeSimpleSingle() internal pure returns (ExecMode mode) { - mode = - encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, EXEC_MODE_DEFAULT, ExecModePayload.wrap(0x00)); - } - - function getCallType(ExecMode mode) internal pure returns (CallType calltype) { - assembly { - calltype := mode - } - } - - function decodeBatch(bytes calldata callData) - internal - pure - returns (Execution[] calldata executionBatch) - { - /* - * Batch Call Calldata Layout - * Offset (in bytes) | Length (in bytes) | Contents - * 0x0 | 0x4 | bytes4 function selector - * 0x4 | - | - abi.encode(IERC7579Execution.Execution[]) - */ - // solhint-disable-next-line no-inline-assembly - assembly ("memory-safe") { - let dataPointer := add(callData.offset, calldataload(callData.offset)) - - // Extract the ERC7579 Executions - executionBatch.offset := add(dataPointer, 32) - executionBatch.length := calldataload(dataPointer) - } - } - - function encodeBatch(Execution[] memory executions) - internal - pure - returns (bytes memory callData) - { - callData = abi.encode(executions); - } - - function decodeSingle(bytes calldata executionCalldata) - internal - pure - returns (address target, uint256 value, bytes calldata callData) - { - target = address(bytes20(executionCalldata[0:20])); - value = uint256(bytes32(executionCalldata[20:52])); - callData = executionCalldata[52:]; - } - - function encodeSingle( - address target, - uint256 value, - bytes memory callData - ) - internal - pure - returns (bytes memory userOpCalldata) - { - userOpCalldata = abi.encodePacked(target, value, callData); - } - - function doFallback2771Static(address fallbackHandler) - internal - view - returns (bool success, bytes memory result) - { - assembly { - function allocate(length) -> pos { - pos := mload(0x40) - mstore(0x40, add(pos, length)) - } - - let calldataPtr := allocate(calldatasize()) - calldatacopy(calldataPtr, 0, calldatasize()) - - // The msg.sender address is shifted to the left by 12 bytes to remove the padding - // Then the address without padding is stored right after the calldata - let senderPtr := allocate(20) - mstore(senderPtr, shl(96, caller())) - - // Add 20 bytes for the address appended add the end - success := - staticcall(gas(), fallbackHandler, calldataPtr, add(calldatasize(), 20), 0, 0) - - result := mload(0x40) - mstore(result, returndatasize()) // Store the length. - let o := add(result, 0x20) - returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. - mstore(0x40, add(o, returndatasize())) // Allocate the memory. - } - } - - function doFallback2771Call(address target) - internal - returns (bool success, bytes memory result) - { - assembly { - function allocate(length) -> pos { - pos := mload(0x40) - mstore(0x40, add(pos, length)) - } - - let calldataPtr := allocate(calldatasize()) - calldatacopy(calldataPtr, 0, calldatasize()) - - // The msg.sender address is shifted to the left by 12 bytes to remove the padding - // Then the address without padding is stored right after the calldata - let senderPtr := allocate(20) - mstore(senderPtr, shl(96, caller())) - - // Add 20 bytes for the address appended add the end - success := call(gas(), target, 0, calldataPtr, add(calldatasize(), 20), 0, 0) - - result := mload(0x40) - mstore(result, returndatasize()) // Store the length. - let o := add(result, 0x20) - returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. - mstore(0x40, add(o, returndatasize())) // Allocate the memory. - } - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ValidationTypeLib.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ValidationTypeLib.sol deleted file mode 100644 index 03ea29e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/lib/ValidationTypeLib.sol +++ /dev/null @@ -1,244 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IValidator, IPolicy, IHook, ISigner } from "../../common/interfaces/IERC7579Module.sol"; - -// Types -import { - PassFlag, - ValidationType, - ValidationId, - ValidationMode, - PolicyData, - PermissionId -} from "../types/Types.sol"; -import { VALIDATION_TYPE_PERMISSION } from "../types/Constants.sol"; - -// erc7579 plugins -struct ValidationConfig { - uint32 nonce; // 4 bytes - IHook hook; // 20 bytes address(1) : hook not required, address(0) : validator not installed -} - -struct PermissionConfig { - PassFlag permissionFlag; - ISigner signer; - PolicyData[] policyData; -} - -struct ValidationStorage { - ValidationId rootValidator; - uint32 currentNonce; - uint32 validNonceFrom; - mapping(ValidationId => ValidationConfig) validationConfig; - mapping(ValidationId => mapping(bytes4 => bool)) allowedSelectors; - // validation = validator | permission - // validator == 1 validator - // permission == 1 signer + N policies - mapping(PermissionId => PermissionConfig) permissionConfig; -} - -library ValidatorLib { - function encodeFlag( - bool skipUserOp, - bool skipSignature - ) - internal - pure - returns (PassFlag flag) - { - assembly { - if skipUserOp { - flag := 0x0001000000000000000000000000000000000000000000000000000000000000 - } - if skipSignature { - flag := or(flag, 0x0002000000000000000000000000000000000000000000000000000000000000) - } - } - } - - function encodePolicyData( - bool skipUserOp, - bool skipSig, - address policy - ) - internal - pure - returns (PolicyData data) - { - assembly { - if skipUserOp { - data := 0x0001000000000000000000000000000000000000000000000000000000000000 - } - if skipSig { - data := or(data, 0x0002000000000000000000000000000000000000000000000000000000000000) - } - data := or(data, shl(80, policy)) - } - } - - function encodePermissionAsNonce( - bytes1 mode, - bytes4 permissionId, - uint16 nonceKey, - uint64 nonce - ) - internal - pure - returns (uint256 res) - { - return encodeAsNonce( - mode, - ValidationType.unwrap(VALIDATION_TYPE_PERMISSION), - bytes20(permissionId), - nonceKey, - nonce - ); - } - - function encodeAsNonce( - bytes1 mode, - bytes1 vType, - bytes20 ValidationIdWithoutType, - uint16 nonceKey, - uint64 nonce - ) - internal - pure - returns (uint256 res) - { - assembly { - res := nonce - res := or(res, shl(64, nonceKey)) - res := or(res, shr(16, ValidationIdWithoutType)) - res := or(res, shr(8, vType)) - res := or(res, mode) - } - } - - function encodeAsNonceKey( - bytes1 mode, - bytes1 vType, - bytes20 ValidationIdWithoutType, - uint16 nonceKey - ) - internal - pure - returns (uint192 res) - { - assembly { - res := or(nonceKey, shr(80, ValidationIdWithoutType)) - res := or(res, shr(72, vType)) - res := or(res, shr(64, mode)) - } - } - - function decodeNonce(uint256 nonce) - internal - pure - returns (ValidationMode mode, ValidationType vType, ValidationId identifier) - { - // 2bytes mode (1byte currentMode, 1byte type) - // 21bytes identifier - // 1byte mode | 1byte type | 20bytes identifierWithoutType | 2byte nonceKey | 8byte nonce - // == 32bytes - assembly { - mode := nonce - vType := shl(8, nonce) - identifier := shl(8, nonce) - switch shr(248, identifier) - case 0x0000000000000000000000000000000000000000000000000000000000000002 { - identifier := - and(identifier, 0xffffffffff000000000000000000000000000000000000000000000000000000) - } - } - } - - function decodeSignature(bytes calldata signature) - internal - pure - returns (ValidationId vId, bytes calldata sig) - { - assembly { - vId := calldataload(signature.offset) - switch shr(248, vId) - case 0 { - // sudo mode - vId := 0x00 - sig.offset := add(signature.offset, 1) - sig.length := sub(signature.length, 1) - } - case 1 { - // validator mode - sig.offset := add(signature.offset, 21) - sig.length := sub(signature.length, 21) - } - case 2 { - vId := and(vId, 0xffffffffff000000000000000000000000000000000000000000000000000000) - sig.offset := add(signature.offset, 5) - sig.length := sub(signature.length, 5) - } - default { revert(0x00, 0x00) } - } - } - - function decodePolicyData(PolicyData data) - internal - pure - returns (PassFlag flag, IPolicy policy) - { - assembly { - flag := data - policy := shr(80, data) - } - } - - function validatorToIdentifier(IValidator validator) internal pure returns (ValidationId vId) { - assembly { - vId := 0x0100000000000000000000000000000000000000000000000000000000000000 - vId := or(vId, shl(88, validator)) - } - } - - function getType(ValidationId validator) internal pure returns (ValidationType vType) { - assembly { - vType := validator - } - } - - function getValidator(ValidationId validator) internal pure returns (IValidator v) { - assembly { - v := shr(88, validator) - } - } - - function getPermissionId(ValidationId validator) internal pure returns (PermissionId id) { - assembly { - id := shl(8, validator) - } - } - - function permissionToIdentifier(PermissionId permissionId) - internal - pure - returns (ValidationId vId) - { - assembly { - vId := 0x0200000000000000000000000000000000000000000000000000000000000000 - vId := or(vId, shr(8, permissionId)) - } - } - - function getPolicy(PolicyData data) internal pure returns (IPolicy vId) { - assembly { - vId := shr(80, data) - } - } - - function getPermissionSkip(PolicyData data) internal pure returns (PassFlag flag) { - assembly { - flag := data - } - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/mock/MockFallback.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/mock/MockFallback.sol deleted file mode 100644 index e078530..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/mock/MockFallback.sol +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/* solhint-disable no-unused-import */ - -// Interfaces -import { IERC7579Account } from "../interfaces/IERC7579Account.sol"; -import { IFallback } from "../interfaces/IERC7579Module.sol"; - -// Types -import { CallType, ExecType, ExecMode, ExecLib } from "../lib/ExecLib.sol"; -import { EXEC_MODE_DEFAULT } from "../types/Constants.sol"; - -contract Callee { - address public lastCaller; - - function calleeTest() external { - lastCaller = msg.sender; - } -} - -contract MockFallback is IFallback { - mapping(address account => bytes accountData) public data; - - uint256 public valueStored; - - bool public isExecutor; - - Callee public callee; - - constructor() { - callee = new Callee(); - } - - function setExecutorMode(bool _isExecutor) external payable { - isExecutor = _isExecutor; - } - - function onInstall(bytes calldata _data) external payable override { - data[msg.sender] = _data; - } - - function onUninstall(bytes calldata) external payable override { - delete data[msg.sender]; - } - - function isModuleType(uint256 moduleTypeId) external view override returns (bool) { - return moduleTypeId == 3 || (isExecutor && moduleTypeId == 2); - } - - function isInitialized(address smartAccount) external view override returns (bool) { - return data[smartAccount].length > 0; - } - - function fallbackFunction(uint256 v) external pure returns (uint256) { - return v * v; - } - - function getData() external view returns (bytes memory) { - return data[msg.sender]; - } - - function getCaller() external pure returns (address) { - return address(bytes20(msg.data[msg.data.length - 20:])); - } - - function setData(uint256 value) external { - valueStored = value; - if (isExecutor) { - IERC7579Account(msg.sender).executeFromExecutor( - ExecLib.encodeSimpleSingle(), - ExecLib.encodeSingle( - address(callee), 0, abi.encodeWithSelector(Callee.calleeTest.selector) - ) - ); - } - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Constants.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Constants.sol deleted file mode 100644 index 607b736..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Constants.sol +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -import { CallType, ExecType, ExecModeSelector } from "./Types.sol"; -import { PassFlag, ValidationMode, ValidationType } from "./Types.sol"; -import { ValidationData } from "./Types.sol"; - -// --- ERC7579 calltypes --- -// Default CallType -CallType constant CALLTYPE_SINGLE = CallType.wrap(0x00); -// Batched CallType -CallType constant CALLTYPE_BATCH = CallType.wrap(0x01); -CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); -// @dev Implementing delegatecall is OPTIONAL! -// implement delegatecall with extreme care. -CallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF); - -// --- ERC7579 exectypes --- -// @dev default behavior is to revert on failure -// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure -// Since this is value 0x00, no additional encoding is required for simple accounts -ExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00); -// @dev account may elect to change execution behavior. For example "try exec" / "allow fail" -ExecType constant EXECTYPE_TRY = ExecType.wrap(0x01); - -// --- ERC7579 mode selector --- -ExecModeSelector constant EXEC_MODE_DEFAULT = ExecModeSelector.wrap(bytes4(0x00000000)); - -// --- Kernel permission skip flags --- -PassFlag constant SKIP_USEROP = PassFlag.wrap(0x0001); -PassFlag constant SKIP_SIGNATURE = PassFlag.wrap(0x0002); - -// --- Kernel validation modes --- -ValidationMode constant VALIDATION_MODE_DEFAULT = ValidationMode.wrap(0x00); -ValidationMode constant VALIDATION_MODE_ENABLE = ValidationMode.wrap(0x01); -ValidationMode constant VALIDATION_MODE_INSTALL = ValidationMode.wrap(0x02); - -// --- Kernel validation types --- -ValidationType constant VALIDATION_TYPE_ROOT = ValidationType.wrap(0x00); -ValidationType constant VALIDATION_TYPE_VALIDATOR = ValidationType.wrap(0x01); -ValidationType constant VALIDATION_TYPE_PERMISSION = ValidationType.wrap(0x02); - -// --- storage slots --- -// bytes32(uint256(keccak256('kernel.v3.selector')) - 1) -bytes32 constant SELECTOR_MANAGER_STORAGE_SLOT = - 0x7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b; -// bytes32(uint256(keccak256('kernel.v3.executor')) - 1) -bytes32 constant EXECUTOR_MANAGER_STORAGE_SLOT = - 0x1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b86; -// bytes32(uint256(keccak256('kernel.v3.hook')) - 1) -bytes32 constant HOOK_MANAGER_STORAGE_SLOT = - 0x4605d5f70bb605094b2e761eccdc27bed9a362d8612792676bf3fb9b12832ffc; -// bytes32(uint256(keccak256('kernel.v3.validation')) - 1) -bytes32 constant VALIDATION_MANAGER_STORAGE_SLOT = - 0x7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f; -bytes32 constant ERC1967_IMPLEMENTATION_SLOT = - 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; - -// --- Kernel validation nonce incremental size limit --- -uint32 constant MAX_NONCE_INCREMENT_SIZE = 10; - -// -- EIP712 type hash --- -bytes32 constant ENABLE_TYPE_HASH = - 0xb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c505; -bytes32 constant KERNEL_WRAPPER_TYPE_HASH = - 0x1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c83; - -// --- ERC constants --- -// ERC4337 constants -uint256 constant SIG_VALIDATION_FAILED_UINT = 1; -uint256 constant SIG_VALIDATION_SUCCESS_UINT = 0; -ValidationData constant SIG_VALIDATION_FAILED = ValidationData.wrap(SIG_VALIDATION_FAILED_UINT); - -// ERC-1271 constants -bytes4 constant ERC1271_MAGICVALUE = 0x1626ba7e; -bytes4 constant ERC1271_INVALID = 0xffffffff; - -uint256 constant MODULE_TYPE_VALIDATOR = 1; -uint256 constant MODULE_TYPE_EXECUTOR = 2; -uint256 constant MODULE_TYPE_FALLBACK = 3; -uint256 constant MODULE_TYPE_HOOK = 4; -uint256 constant MODULE_TYPE_POLICY = 5; -uint256 constant MODULE_TYPE_SIGNER = 6; diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Structs.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Structs.sol deleted file mode 100644 index edf9dbe..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Structs.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -struct Execution { - address target; - uint256 value; - bytes callData; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Types.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Types.sol deleted file mode 100644 index e1e7196..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/kernel/types/Types.sol +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Custom type for improved developer experience -type ExecMode is bytes32; - -type CallType is bytes1; - -type ExecType is bytes1; - -type ExecModeSelector is bytes4; - -type ExecModePayload is bytes22; - -using { eqModeSelector as == } for ExecModeSelector global; -using { eqCallType as == } for CallType global; -using { notEqCallType as != } for CallType global; -using { eqExecType as == } for ExecType global; - -function eqCallType(CallType a, CallType b) pure returns (bool) { - return CallType.unwrap(a) == CallType.unwrap(b); -} - -function notEqCallType(CallType a, CallType b) pure returns (bool) { - return CallType.unwrap(a) != CallType.unwrap(b); -} - -function eqExecType(ExecType a, ExecType b) pure returns (bool) { - return ExecType.unwrap(a) == ExecType.unwrap(b); -} - -function eqModeSelector(ExecModeSelector a, ExecModeSelector b) pure returns (bool) { - return ExecModeSelector.unwrap(a) == ExecModeSelector.unwrap(b); -} - -type ValidationMode is bytes1; - -type ValidationId is bytes21; - -type ValidationType is bytes1; - -type PermissionId is bytes4; - -type PolicyData is bytes22; // 2bytes for flag on skip, 20 bytes for validator address - -type PassFlag is bytes2; - -using { vModeEqual as == } for ValidationMode global; -using { vTypeEqual as == } for ValidationType global; -using { vIdentifierEqual as == } for ValidationId global; -using { vModeNotEqual as != } for ValidationMode global; -using { vTypeNotEqual as != } for ValidationType global; -using { vIdentifierNotEqual as != } for ValidationId global; - -// nonce = uint192(key) + nonce -// key = mode + (vtype + validationDataWithoutType) + 2bytes parallelNonceKey -// key = 0x00 + 0x00 + 0x000 .. 00 + 0x0000 -// key = 0x00 + 0x01 + 0x1234...ff + 0x0000 -// key = 0x00 + 0x02 + ( ) + 0x000 - -function vModeEqual(ValidationMode a, ValidationMode b) pure returns (bool) { - return ValidationMode.unwrap(a) == ValidationMode.unwrap(b); -} - -function vModeNotEqual(ValidationMode a, ValidationMode b) pure returns (bool) { - return ValidationMode.unwrap(a) != ValidationMode.unwrap(b); -} - -function vTypeEqual(ValidationType a, ValidationType b) pure returns (bool) { - return ValidationType.unwrap(a) == ValidationType.unwrap(b); -} - -function vTypeNotEqual(ValidationType a, ValidationType b) pure returns (bool) { - return ValidationType.unwrap(a) != ValidationType.unwrap(b); -} - -function vIdentifierEqual(ValidationId a, ValidationId b) pure returns (bool) { - return ValidationId.unwrap(a) == ValidationId.unwrap(b); -} - -function vIdentifierNotEqual(ValidationId a, ValidationId b) pure returns (bool) { - return ValidationId.unwrap(a) != ValidationId.unwrap(b); -} - -type ValidationData is uint256; - -type ValidAfter is uint48; - -type ValidUntil is uint48; - -function getValidationResult(ValidationData validationData) pure returns (address result) { - // solhint-disable-next-line no-inline-assembly - assembly { - result := validationData - } -} - -function packValidationData(ValidAfter validAfter, ValidUntil validUntil) pure returns (uint256) { - return uint256(ValidAfter.unwrap(validAfter)) << 208 - | uint256(ValidUntil.unwrap(validUntil)) << 160; -} - -function parseValidationData(uint256 validationData) - pure - returns (ValidAfter validAfter, ValidUntil validUntil, address result) -{ - // solhint-disable-next-line no-inline-assembly - assembly { - result := validationData - validUntil := and(shr(160, validationData), 0xffffffffffff) - switch iszero(validUntil) - case 1 { validUntil := 0xffffffffffff } - validAfter := shr(208, validationData) - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/NexusFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/NexusFactory.sol deleted file mode 100644 index 14582c0..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/NexusFactory.sol +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IAccountFactory } from "../factory/interface/IAccountFactory.sol"; -import { INexusAccountFactory } from "../nexus/interfaces/INexusAccountFactory.sol"; -import { - INexusBootstrap, - BootstrapConfig as NexusBootstrapConfig -} from "../nexus/interfaces/INexusBootstrap.sol"; -import { IERC7484 } from "../../Interfaces.sol"; -import { INexus } from "./interfaces/INexus.sol"; - -// Constants -import { ENTRYPOINT_ADDR } from "../../deployment/predeploy/EntryPoint.sol"; -import { REGISTRY_ADDR } from "../../deployment/predeploy/Registry.sol"; - -// Utils -import { NexusPrecompiles } from "../../deployment/precompiles/NexusPrecompiles.sol"; - -contract NexusFactory is IAccountFactory, NexusPrecompiles { - INexusAccountFactory public factory; - INexusBootstrap public bootstrapDefault; - address public nexusImpl; - - function init() public override { - // Deploy precompiled contracts - nexusImpl = deployNexus(ENTRYPOINT_ADDR); - factory = deployNexusAccountFactory(nexusImpl, address(this)); - bootstrapDefault = deployNexusBootstrap(); - } - - function createAccount( - bytes32 salt, - bytes memory initCode - ) - public - override - returns (address account) - { - return deployNexusProxy(salt, nexusImpl, initCode); - } - - function getAddress( - bytes32 salt, - bytes memory initCode - ) - public - view - override - returns (address) - { - bytes32 hash = keccak256( - abi.encodePacked( - bytes1(0xff), - address(this), - salt, - keccak256( - abi.encodePacked( - NEXUS_PROXY_BYTECODE, - abi.encode( - address(nexusImpl), abi.encodeCall(INexus.initializeAccount, initCode) - ) - ) - ) - ) - ); - - return address(uint160(uint256(hash))); - } - - function getInitData( - address validator, - bytes memory initData - ) - public - view - override - returns (bytes memory _init) - { - NexusBootstrapConfig memory config = - NexusBootstrapConfig({ module: validator, data: initData }); - - address[] memory attesters = new address[](1); - attesters[0] = address(0x000000333034E9f539ce08819E12c1b8Cb29084d); - - return bootstrapDefault.getInitNexusWithSingleValidatorCalldata( - config, IERC7484(REGISTRY_ADDR), attesters, 1 - ); - } - - function createAccountWithModules( - bytes32 salt, - NexusBootstrapConfig[] calldata validators, - NexusBootstrapConfig[] calldata executors, - NexusBootstrapConfig calldata hook, - NexusBootstrapConfig[] calldata fallbacks - ) - public - payable - virtual - returns (address) - { - address[] memory attesters = new address[](1); - attesters[0] = address(0x000000333034E9f539ce08819E12c1b8Cb29084d); - - bytes memory initData = abi.encode( - bootstrapDefault, - abi.encodeCall( - INexusBootstrap.initNexus, - (validators, executors, hook, fallbacks, IERC7484(REGISTRY_ADDR), attesters, 1) - ) - ); - - address account = deployNexusProxy(salt, nexusImpl, initData); - - return account; - } - - function getInitData( - IAccountFactory.ModuleInitData[] memory _validators, - IAccountFactory.ModuleInitData[] memory _executors, - IAccountFactory.ModuleInitData memory _hook, - IAccountFactory.ModuleInitData[] memory _fallbacks - ) - public - view - override - returns (bytes memory _init) - { - NexusBootstrapConfig[] memory validators = - abi.decode(abi.encode(_validators), (NexusBootstrapConfig[])); - NexusBootstrapConfig[] memory executors = - abi.decode(abi.encode(_executors), (NexusBootstrapConfig[])); - NexusBootstrapConfig memory hook = abi.decode(abi.encode(_hook), (NexusBootstrapConfig)); - NexusBootstrapConfig[] memory fallbacks = - abi.decode(abi.encode(_fallbacks), (NexusBootstrapConfig[])); - - address[] memory attesters = new address[](1); - attesters[0] = address(0x000000333034E9f539ce08819E12c1b8Cb29084d); - - _init = abi.encode( - address(bootstrapDefault), - abi.encodeCall( - INexusBootstrap.initNexus, - (validators, executors, hook, fallbacks, IERC7484(REGISTRY_ADDR), attesters, 1) - ) - ); - } - - function getInitData(bytes memory initData) public view returns (bytes memory _init) { - ( - NexusBootstrapConfig[] memory validators, - NexusBootstrapConfig[] memory executors, - NexusBootstrapConfig memory hook, - NexusBootstrapConfig[] memory fallbacks - ) = abi.decode( - initData, - ( - NexusBootstrapConfig[], - NexusBootstrapConfig[], - NexusBootstrapConfig, - NexusBootstrapConfig[] - ) - ); - address[] memory attesters = new address[](1); - attesters[0] = address(0x000000333034E9f539ce08819E12c1b8Cb29084d); - - _init = abi.encode( - address(bootstrapDefault), - abi.encodeCall( - INexusBootstrap.initNexus, - (validators, executors, hook, fallbacks, IERC7484(REGISTRY_ADDR), attesters, 1) - ) - ); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexus.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexus.sol deleted file mode 100644 index 529f44f..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexus.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// ────────────────────────────────────────────────────────────────────────────── -// _ __ _ __ -// / | / /__ | |/ /_ _______ -// / |/ / _ \| / / / / ___/ -// / /| / __/ / /_/ (__ ) -// /_/ |_/\___/_/|_\__,_/____/ -// -// ────────────────────────────────────────────────────────────────────────────── -// Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, -// developed by Biconomy. -// Learn more at https://biconomy.io. To report security issues, please contact us at: -// security@biconomy.io - -import { IERC4337Account } from "../../common/interfaces/IERC4337Account.sol"; -import { IERC7579Account } from "../../common/interfaces/IERC7579Account.sol"; - -/// @title Nexus - INexus Interface -/// @notice Integrates ERC-4337 and ERC-7579 standards to manage smart accounts within the Nexus -/// suite. -/// @dev Consolidates ERC-4337 user operations and ERC-7579 configurations into a unified interface -/// for smart account management. -/// It extends both IERC4337Account and IERC7579Account, enhancing modular capabilities and -/// supporting advanced contract architectures. -/// Includes error definitions for robust handling of common issues such as unsupported module types -/// and execution failures. -/// The initialize function sets up the account with validators and configurations, ensuring -/// readiness for use. -/// @author @livingrockrises | Biconomy | chirag@biconomy.io -/// @author @aboudjem | Biconomy | adam.boudjemaa@biconomy.io -/// @author @filmakarov | Biconomy | filipp.makarov@biconomy.io -/// @author @zeroknots | Rhinestone.wtf | zeroknots.eth -/// Special thanks to the Solady team for foundational contributions: -/// https://github.com/Vectorized/solady -interface INexus is IERC4337Account, IERC7579Account { - /// @notice Initializes the smart account with a validator and custom data. - /// @dev This method sets up the account for operation, linking it with a validator and - /// initializing it with specific data. - /// Can be called directly or via a factory. - /// @param initData Encoded data used for the account's configuration during initialization. - function initializeAccount(bytes calldata initData) external payable; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusAccountFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusAccountFactory.sol deleted file mode 100644 index 00265ba..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusAccountFactory.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -interface INexusAccountFactory { - /// @notice Creates a new Nexus account with the provided initialization data. - /// @param initData Initialization data to be called on the new Smart Account. - /// @param salt Unique salt for the Smart Account creation. - /// @return The address of the newly created Nexus account. - function createAccount( - bytes calldata initData, - bytes32 salt - ) - external - payable - returns (address payable); - - /// @notice Computes the expected address of a Nexus contract using the factory's deterministic - /// deployment algorithm. - /// @param initData Initialization data to be called on the new Smart Account. - /// @param salt Unique salt for the Smart Account creation. - /// @return expectedAddress The expected address at which the Nexus contract will be deployed if - /// the provided parameters are used. - function computeAccountAddress( - bytes calldata initData, - bytes32 salt - ) - external - view - returns (address payable expectedAddress); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusBootstrap.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusBootstrap.sol deleted file mode 100644 index e973811..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/nexus/interfaces/INexusBootstrap.sol +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IModule as IERC7579Module } from "../../../accounts/common/interfaces/IERC7579Module.sol"; -import { IERC7484 } from "../../../Interfaces.sol"; - -// Structs -struct BootstrapConfig { - address module; - bytes data; -} - -interface INexusBootstrap { - /// @notice Initializes the Nexus account with a single validator. - /// @dev Intended to be called by the Nexus with a delegatecall. - /// @param validator The address of the validator module. - /// @param data The initialization data for the validator module. - function initNexusWithSingleValidator( - IERC7579Module validator, - bytes calldata data, - IERC7484 registry, - address[] calldata attesters, - uint8 threshold - ) - external; - - /// @notice Initializes the Nexus account with multiple modules. - /// @dev Intended to be called by the Nexus with a delegatecall. - /// @param validators The configuration array for validator modules. - /// @param executors The configuration array for executor modules. - /// @param hook The configuration for the hook module. - /// @param fallbacks The configuration array for fallback handler modules. - function initNexus( - BootstrapConfig[] calldata validators, - BootstrapConfig[] calldata executors, - BootstrapConfig calldata hook, - BootstrapConfig[] calldata fallbacks, - IERC7484 registry, - address[] calldata attesters, - uint8 threshold - ) - external; - - /// @notice Initializes the Nexus account with a scoped set of modules. - /// @dev Intended to be called by the Nexus with a delegatecall. - /// @param validators The configuration array for validator modules. - /// @param hook The configuration for the hook module. - function initNexusScoped( - BootstrapConfig[] calldata validators, - BootstrapConfig calldata hook, - IERC7484 registry, - address[] calldata attesters, - uint8 threshold - ) - external; - - /// @notice Prepares calldata for the initNexus function. - /// @param validators The configuration array for validator modules. - /// @param executors The configuration array for executor modules. - /// @param hook The configuration for the hook module. - /// @param fallbacks The configuration array for fallback handler modules. - /// @return init The prepared calldata for initNexus. - function getInitNexusCalldata( - BootstrapConfig[] calldata validators, - BootstrapConfig[] calldata executors, - BootstrapConfig calldata hook, - BootstrapConfig[] calldata fallbacks, - IERC7484 registry, - address[] calldata attesters, - uint8 threshold - ) - external - view - returns (bytes memory init); - - /// @notice Prepares calldata for the initNexusScoped function. - /// @param validators The configuration array for validator modules. - /// @param hook The configuration for the hook module. - /// @return init The prepared calldata for initNexusScoped. - function getInitNexusScopedCalldata( - BootstrapConfig[] calldata validators, - BootstrapConfig calldata hook, - IERC7484 registry, - address[] calldata attesters, - uint8 threshold - ) - external - view - returns (bytes memory init); - - /// @notice Prepares calldata for the initNexusWithSingleValidator function. - /// @param validator The configuration for the validator module. - /// @return init The prepared calldata for initNexusWithSingleValidator. - function getInitNexusWithSingleValidatorCalldata( - BootstrapConfig calldata validator, - IERC7484 registry, - address[] calldata attesters, - uint8 threshold - ) - external - view - returns (bytes memory init); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/SafeFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/SafeFactory.sol deleted file mode 100644 index 58f5596..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/SafeFactory.sol +++ /dev/null @@ -1,190 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { ISafe7579 } from "../../accounts/safe/interfaces/ISafe7579.sol"; -import { - ISafe7579Launchpad, ModuleInit -} from "../../accounts/safe/interfaces/ISafe7579Launchpad.sol"; -import { IAccountFactory } from "../../accounts/factory/interface/IAccountFactory.sol"; -import { ISafeProxyFactory } from "./interfaces/ISafeProxyFactory.sol"; - -// Utils -import { ENTRYPOINT_ADDR } from "../../deployment/predeploy/EntryPoint.sol"; -import { REGISTRY_ADDR } from "../../deployment/predeploy/Registry.sol"; -import { makeAddr } from "../../test/utils/Vm.sol"; -import { Solarray } from "solarray/Solarray.sol"; - -// Precompiles -import { Safe7579Precompiles } from "../../deployment/precompiles/Safe7579Precompiles.sol"; - -contract SafeFactory is IAccountFactory, Safe7579Precompiles { - // singletons - ISafe7579 public safe7579; - ISafe7579Launchpad public launchpad; - address public safeSingleton; - ISafeProxyFactory public safeProxyFactory; - - function init() public override { - safe7579 = deploySafe7579(); - launchpad = deploySafe7579Launchpad(ENTRYPOINT_ADDR, REGISTRY_ADDR); - safeSingleton = deploySafeSingleton(); - safeProxyFactory = deploySafeProxyFactory(); - } - - function createAccount( - bytes32 salt, - bytes memory initCode - ) - public - override - returns (address safe) - { - ISafe7579Launchpad.InitData memory initData = - abi.decode(initCode, (ISafe7579Launchpad.InitData)); - bytes32 initHash = launchpad.hash(initData); - - bytes memory factoryInitializer = - abi.encodeCall(ISafe7579Launchpad.preValidationSetup, (initHash, address(0), "")); - - safe = address( - safeProxyFactory.createProxyWithNonce( - address(launchpad), factoryInitializer, uint256(salt) - ) - ); - } - - function getAddress( - bytes32 salt, - bytes memory initCode - ) - public - view - override - returns (address) - { - ISafe7579Launchpad.InitData memory initData = - abi.decode(initCode, (ISafe7579Launchpad.InitData)); - bytes32 initHash = launchpad.hash(initData); - - bytes memory factoryInitializer = - abi.encodeCall(ISafe7579Launchpad.preValidationSetup, (initHash, address(0), "")); - - return launchpad.predictSafeAddress({ - singleton: address(launchpad), - safeProxyFactory: address(safeProxyFactory), - creationCode: SAFE_PROXY_BYTECODE, - salt: salt, - factoryInitializer: factoryInitializer - }); - } - - function getInitData( - address validator, - bytes memory initData - ) - public - view - override - returns (bytes memory _init) - { - ModuleInit[] memory validators = new ModuleInit[](1); - validators[0] = ModuleInit({ module: address(validator), initData: initData }); - ModuleInit[] memory executors = new ModuleInit[](0); - ModuleInit[] memory fallbacks = new ModuleInit[](0); - ModuleInit[] memory hooks = new ModuleInit[](0); - - ISafe7579Launchpad.InitData memory initDataSafe = ISafe7579Launchpad.InitData({ - singleton: address(safeSingleton), - owners: Solarray.addresses(makeAddr("owner1")), - threshold: 1, - setupTo: address(launchpad), - setupData: abi.encodeCall( - ISafe7579Launchpad.initSafe7579, - ( - address(safe7579), - executors, - fallbacks, - hooks, - Solarray.addresses(makeAddr("attester1"), makeAddr("attester2")), - 2 - ) - ), - safe7579: ISafe7579(safe7579), - validators: validators, - callData: "" - }); - _init = abi.encode(initDataSafe); - } - - function getInitData( - IAccountFactory.ModuleInitData[] memory _validators, - IAccountFactory.ModuleInitData[] memory _executors, - IAccountFactory.ModuleInitData memory _hook, - IAccountFactory.ModuleInitData[] memory _fallbacks - ) - public - view - returns (bytes memory _init) - { - ModuleInit[] memory validators = abi.decode(abi.encode(_validators), (ModuleInit[])); - ModuleInit[] memory executors = abi.decode(abi.encode(_executors), (ModuleInit[])); - ModuleInit memory hook = abi.decode(abi.encode(_hook), (ModuleInit)); - ModuleInit[] memory hooks = new ModuleInit[](1); - hooks[0] = hook; - ModuleInit[] memory fallbacks = abi.decode(abi.encode(_fallbacks), (ModuleInit[])); - - ISafe7579Launchpad.InitData memory initDataSafe = ISafe7579Launchpad.InitData({ - singleton: address(safeSingleton), - owners: Solarray.addresses(makeAddr("owner1")), - threshold: 1, - setupTo: address(launchpad), - setupData: abi.encodeCall( - ISafe7579Launchpad.initSafe7579, - ( - address(safe7579), - executors, - fallbacks, - hooks, - Solarray.addresses(makeAddr("attester1"), makeAddr("attester2")), - 2 - ) - ), - safe7579: ISafe7579(safe7579), - validators: validators, - callData: "" - }); - _init = abi.encode(initDataSafe); - } - - function getInitData(bytes memory initData) public view returns (bytes memory _init) { - ( - ModuleInit[] memory validators, - ModuleInit[] memory executors, - ModuleInit[] memory hooks, - ModuleInit[] memory fallbacks - ) = abi.decode(initData, (ModuleInit[], ModuleInit[], ModuleInit[], ModuleInit[])); - ISafe7579Launchpad.InitData memory initDataSafe = ISafe7579Launchpad.InitData({ - singleton: address(safeSingleton), - owners: Solarray.addresses(makeAddr("owner1")), - threshold: 1, - setupTo: address(launchpad), - setupData: abi.encodeCall( - ISafe7579Launchpad.initSafe7579, - ( - address(safe7579), - executors, - fallbacks, - hooks, - Solarray.addresses(makeAddr("attester1"), makeAddr("attester2")), - 2 - ) - ), - safe7579: ISafe7579(safe7579), - validators: validators, - callData: "" - }); - - _init = abi.encode(initDataSafe); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7484.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7484.sol deleted file mode 100644 index 2c756f7..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7484.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -interface IERC7484 { - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Check with Registry internal attesters */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - function check(address module) external view; - - function checkForAccount(address smartAccount, address module) external view; - - function check(address module, uint256 moduleType) external view; - - function checkForAccount( - address smartAccount, - address module, - uint256 moduleType - ) - external - view; - - /** - * Allows Smart Accounts - the end users of the registry - to appoint - * one or many attesters as trusted. - * @dev this function reverts, if address(0), or duplicates are provided in attesters[] - * - * @param threshold The minimum number of attestations required for a module - * to be considered secure. - * @param attesters The addresses of the attesters to be trusted. - */ - function trustAttesters(uint8 threshold, address[] calldata attesters) external; - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Check with external attester(s) */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - function check(address module, address[] calldata attesters, uint256 threshold) external view; - - function check( - address module, - uint256 moduleType, - address[] calldata attesters, - uint256 threshold - ) - external - view; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7579Account.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7579Account.sol deleted file mode 100644 index 50a5a2e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/IERC7579Account.sol +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { CallType, ExecType, ModeCode } from "../../common/lib/ModeLib.sol"; - -// Structs -struct Execution { - address target; - uint256 value; - bytes callData; -} - -interface IERC7579AccountEvents { - event ModuleInstalled(uint256 moduleTypeId, address module); - event ModuleUninstalled(uint256 moduleTypeId, address module); -} - -interface IERC7579AccountView { - /** - * @dev Returns the account id of the smart account - * @return accountImplementationId the account id of the smart account - * the accountId should be structured like so: - * "vendorname.accountname.semver" - */ - function accountId() external view returns (string memory accountImplementationId); - - /** - * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol) - * @param encodedMode the encoded mode - */ - function supportsExecutionMode(ModeCode encodedMode) external view returns (bool); - - /** - * Function to check if the account supports installation of a certain module type Id - * @param moduleTypeId the module type ID according the ERC-7579 spec - */ - function supportsModule(uint256 moduleTypeId) external view returns (bool); -} - -interface IERC7579Account is IERC7579AccountEvents, IERC7579AccountView { - // Error thrown when an unsupported ModuleType is requested - error UnsupportedModuleType(uint256 moduleTypeId); - // Error thrown when an execution with an unsupported CallType was made - error UnsupportedCallType(CallType callType); - // Error thrown when an execution with an unsupported ExecType was made - error UnsupportedExecType(ExecType execType); - /** - * @dev Executes a transaction on behalf of the account. - * This function is intended to be called by ERC-4337 EntryPoint.sol - * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf - * - * @dev MSA MUST implement this function signature. - * If a mode is requested that is not supported by the Account, it MUST revert - * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details - * @param executionCalldata The encoded execution call data - */ - - function execute(ModeCode mode, bytes calldata executionCalldata) external; - - /** - * @dev Executes a transaction on behalf of the account. - * This function is intended to be called by Executor Modules - * @dev Ensure adequate authorization control: i.e. onlyExecutorModule - * - * @dev MSA MUST implement this function signature. - * If a mode is requested that is not supported by the Account, it MUST revert - * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details - * @param executionCalldata The encoded execution call data - */ - function executeFromExecutor( - ModeCode mode, - bytes calldata executionCalldata - ) - external - returns (bytes[] memory returnData); - - /** - * @dev ERC-1271 isValidSignature - * This function is intended to be used to validate a smart account signature - * and may forward the call to a validator module - * - * @param hash The hash of the data that is signed - * @param data The data that is signed - */ - function isValidSignature(bytes32 hash, bytes calldata data) external returns (bytes4); - - /** - * @dev installs a Module of a certain type on the smart account - * @dev Implement Authorization control of your chosing - * @param moduleTypeId the module type ID according the ERC-7579 spec - * @param module the module address - * @param initData arbitrary data that may be required on the module during `onInstall` - * initialization. - */ - function installModule( - uint256 moduleTypeId, - address module, - bytes calldata initData - ) - external; - - /** - * @dev uninstalls a Module of a certain type on the smart account - * @dev Implement Authorization control of your chosing - * @param moduleTypeId the module type ID according the ERC-7579 spec - * @param module the module address - * @param deInitData arbitrary data that may be required on the module during `onUninstall` - * de-initialization. - */ - function uninstallModule( - uint256 moduleTypeId, - address module, - bytes calldata deInitData - ) - external; - - /** - * Function to check if the account has a certain module installed - * @param moduleTypeId the module type ID according the ERC-7579 spec - * Note: keep in mind that some contracts can be multiple module types at the same time. It - * thus may be necessary to query multiple module types - * @param module the module address - * @param additionalContext additional context data that the smart account may interpret to - * identifiy conditions under which the module is installed. - * usually this is not necessary, but for some special hooks that - * are stored in mappings, this param might be needed - */ - function isModuleInstalled( - uint256 moduleTypeId, - address module, - bytes calldata additionalContext - ) - external - view - returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579.sol deleted file mode 100644 index 754bfc3..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579.sol +++ /dev/null @@ -1,268 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IERC7579Account } from "./IERC7579Account.sol"; -import { ISafeOp } from "./ISafeOp.sol"; - -// Types -import "../types/DataTypes.sol"; -import { ModeCode } from "../../common/lib/ModeLib.sol"; -import { PackedUserOperation } from - "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; - -/** - * @title ERC7579 Adapter for Safe accounts. - * creates full ERC7579 compliance to Safe accounts - * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) - */ -interface ISafe7579 is IERC7579Account, ISafeOp { - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Validation */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /** - * ERC4337 v0.7 validation function - * @dev expects that a ERC7579 validator module is encoded within the UserOp nonce. - * if no validator module is provided, it will fallback to validate the transaction with - * Safe's signers - */ - function validateUserOp( - PackedUserOperation memory userOp, - bytes32 userOpHash, - uint256 missingAccountFunds - ) - external - returns (uint256 packedValidSig); - - /** - * Will use Safe's signed messages or checkSignatures features or ERC7579 validation modules - * if no signature is provided, it makes use of Safe's signedMessages - * if address(0) or a non-installed validator module is provided, it will use Safe's - * checkSignatures - * if a valid validator module is provided, it will use the module's validateUserOp function - * @param hash message hash of ERC1271 request - * @param data abi.encodePacked(address validationModule, bytes signatures) - */ - function isValidSignature( - bytes32 hash, - bytes memory data - ) - external - view - returns (bytes4 magicValue); - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Executions */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /** - * @dev Executes a transaction on behalf of the Safe account. - * This function is intended to be called by ERC-4337 EntryPoint.sol - * @dev If a global hook and/or selector hook is set, it will be called - * @dev AccessControl: only Self of Entrypoint can install modules - * Safe7579 supports the following feature set: - * CallTypes: - * - CALLTYPE_SINGLE - * - CALLTYPE_BATCH - * - CALLTYPE_DELEGATECALL - * ExecTypes: - * - EXECTYPE_DEFAULT (revert if not successful) - * - EXECTYPE_TRY - * If a different mode is selected, this function will revert - * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details - * @param executionCalldata The encoded execution call data - */ - function execute(ModeCode mode, bytes memory executionCalldata) external; - - /** - * @dev Executes a transaction on behalf of the Safe account. - * This function is intended to be called by executor modules - * @dev If a global hook and/or selector hook is set, it will be called - * @dev AccessControl: only enabled executor modules - * Safe7579 supports the following feature set: - * CallTypes: - * - CALLTYPE_SINGLE - * - CALLTYPE_BATCH - * - CALLTYPE_DELEGATECALL - * ExecTypes: - * - EXECTYPE_DEFAULT (revert if not successful) - * - EXECTYPE_TRY - * If a different mode is selected, this function will revert - * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details - * @param executionCalldata The encoded execution call data - */ - function executeFromExecutor( - ModeCode mode, - bytes memory executionCalldata - ) - external - returns (bytes[] memory returnDatas); - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Manage Modules */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /** - * Installs a 7579 Module of a certain type on the smart account - * @dev The module has to be initialized from msg.sender == SafeProxy, we thus use a - * delegatecall to DCUtil, which calls the onInstall/onUninstall function on the ERC7579 - * module and emits the ModuleInstall/ModuleUnintall events - * @dev AccessControl: only Self of Entrypoint can install modules - * @dev If the safe set a registry, ERC7484 registry will be queried before installing - * @dev If a global hook and/or selector hook is set, it will be called - * @param moduleType the module type ID according the ERC-7579 spec - * Note: MULTITYPE_MODULE (uint(0)) is a special type to install a module with - * multiple types - * @param module the module address - * @param initData arbitrary data that may be required on the module during `onInstall` - * initialization. - */ - function installModule(uint256 moduleType, address module, bytes memory initData) external; - - /** - * Uninstalls a Module of a certain type on the smart account. - * @dev The module has to be initialized from msg.sender == SafeProxy, we thus use a - * delegatecall to DCUtil, which calls the onInstall/onUninstall function on the ERC7579 - * module and emits the ModuleInstall/ModuleUnintall events - * @dev AccessControl: only Self of Entrypoint can install modules - * @dev If a global hook and/or selector hook is set, it will be called - * @param moduleType the module type ID according the ERC-7579 spec - * @param module the module address - * @param deInitData arbitrary data that may be required on the module during `onUninstall` - * de-initialization. - */ - function uninstallModule( - uint256 moduleType, - address module, - bytes memory deInitData - ) - external; - - /** - * Function to check if the account has a certain module installed - * @param moduleType the module type ID according the ERC-7579 spec - * Note: keep in mind that some contracts can be multiple module types at the same time. It - * thus may be necessary to query multiple module types - * @param module the module address - * @param additionalContext additional context data that the smart account may interpret to - * identifiy conditions under which the module is installed. - * usually this is not necessary, but for some special hooks that - * are stored in mappings, this param might be needed - */ - function isModuleInstalled( - uint256 moduleType, - address module, - bytes memory additionalContext - ) - external - view - returns (bool); - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Initialize Safe7579 */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /** - * This function can be called by the Launchpad.initSafe7579() or by already existing Safes that - * want to use Safe7579 - * if this is called by the Launchpad, it is expected that launchpadValidators() was called - * previously, and the param validators is empty - * @param validators validator modules and initData - * @param executors executor modules and initData - * @param executors executor modules and initData - * @param fallbacks fallback modules and initData - * @param hooks hook module and initData - * @param registryInit (OPTIONAL) registry, attesters and threshold for IERC7484 Registry - * If not provided, the registry will be set to the zero address, and no - * registry checks will be performed - */ - function initializeAccount( - ModuleInit[] memory validators, - ModuleInit[] memory executors, - ModuleInit[] memory fallbacks, - ModuleInit[] memory hooks, - RegistryInit memory registryInit - ) - external; - - /** - * This function is intended to be called by Launchpad.validateUserOp() - * @dev it will initialize the SentinelList4337 list for validators, and sstore all - * validators - * @dev Since this function has to be 4337 compliant (storage access), only validator storage is acccess - * @dev Note: this function DOES NOT call onInstall() on the validator modules or emit - * ModuleInstalled events. this has to be done by the launchpad - */ - function initializeAccountWithValidators(ModuleInit[] memory validators) external; - - /** - * Configure the Safe7579 with a IERC7484 registry - * @param registry IERC7484 registry - * @param attesters list of attesters - * @param threshold number of attesters required - */ - function setRegistry(IERC7484 registry, address[] memory attesters, uint8 threshold) external; - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Query Account Details */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - function getValidatorsPaginated( - address cursor, - uint256 pageSize - ) - external - view - returns (address[] memory array, address next); - - /** - * Get the current active global hook - */ - function getActiveHook() external view returns (address hook); - - /** - * Get the current active selector hook - */ - function getActiveHook(bytes4 selector) external view returns (address hook); - - function getExecutorsPaginated( - address cursor, - uint256 size - ) - external - view - returns (address[] memory array, address next); - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Query Misc */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /** - * Safe7579 is using validator selection encoding in the userop nonce. - * to make it easier for SDKs / devs to integrate, this function can be - * called to get the next nonce for a specific validator - * @param safe address of safe account - * @param validator ERC7579 validator to encode - */ - function getNonce(address safe, address validator) external view returns (uint256 nonce); - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Custom Errors */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - error InvalidModule(address module); - error InvalidModuleType(address module, uint256 moduleType); - - // fallback handlers - error InvalidInput(); - error InvalidCallType(CallType callType); - error NoFallbackHandler(bytes4 msgSig); - error InvalidFallbackHandler(bytes4 msgSig); - error FallbackInstalled(bytes4 msgSig); - - // Hooks - error HookAlreadyInstalled(address currentHook); - error InvalidHookType(); - - // Registry Adapter - event ERC7484RegistryConfigured(address indexed smartAccount, IERC7484 indexed registry); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579Launchpad.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579Launchpad.sol deleted file mode 100644 index ba6912f..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafe7579Launchpad.sol +++ /dev/null @@ -1,130 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { - IAccount, - PackedUserOperation -} from "@ERC4337/account-abstraction/contracts/interfaces/IAccount.sol"; -import { ISafe7579 } from "./ISafe7579.sol"; - -// Types -import { ModuleInit } from "../types/DataTypes.sol"; - -interface ISafe7579Launchpad is IAccount { - /** - * @notice The keccak256 hash of the EIP-712 InitData struct, representing the structure - */ - struct InitData { - address singleton; - address[] owners; - uint256 threshold; - address setupTo; - bytes setupData; - ISafe7579 safe7579; - ModuleInit[] validators; - bytes callData; - } - - /** - * This function is intended to be delegatecalled by the ISafe.setup function. It configures the - * Safe7579 for the user for all module types except validators, which were initialized in the - * validateUserOp function. - */ - function initSafe7579( - address safe7579, - ModuleInit[] calldata executors, - ModuleInit[] calldata fallbacks, - ModuleInit[] calldata hooks, - address[] calldata attesters, - uint8 threshold - ) - external; - - /** - * This function allows existing safe accounts to add the Safe7579 adapter to their account - */ - function addSafe7579( - address safe7579, - ModuleInit[] calldata validators, - ModuleInit[] calldata executors, - ModuleInit[] calldata fallbacks, - ModuleInit[] calldata hooks, - address[] calldata attesters, - uint8 threshold - ) - external; - - /** - * SafeProxyFactory will create a SafeProxy and using this contract as the singleton - * implementation and call this function to initialize the account. - * will write initHash into SafeProxy storage - * @param initHash will be calculated offchain using this.hash(InitData) - * @param to optional parameter for a delegatecall - * @param preInit optional parameter for a delegatecall - */ - function preValidationSetup(bytes32 initHash, address to, bytes calldata preInit) external; - - /** - * Upon creation of SafeProxy by SafeProxyFactory, EntryPoint invokes this function to verify - * the transaction. It ensures that only this.setupSafe() can be called by EntryPoint during - * execution. The function validates the hash of InitData in userOp.callData against the hash - * stored in preValidationSetup. This function abides by ERC4337 storage restrictions, allowing - * Safe7579 adapter initialization only in Validation Modules compliant with 4337. It installs - * validators from InitData onto the Safe7579 adapter for the account. When called by EP, the - * SafeProxy singleton address remains unupgraded to SafeSingleton, preventing - * execTransactionFromModule by Safe7579 Adapter. Initialization of Validator Modules is - * achieved through a direct call to onInstall(). This delegatecalled function initializes the - * Validator Module with the correct msg.sender. Once all validator modules are set up, they can - * be used to validate the userOp. Parameters include userOp (EntryPoint v0.7 userOp), - * userOpHash, and missingAccountFunds representing the gas payment required. - * - * @param userOp EntryPoint v0.7 userOp. - * @param userOpHash hash of userOp - * @param missingAccountFunds amount of gas that has to be paid - * @return validationData 4337 packed validation data returned by the validator module - */ - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash, - uint256 missingAccountFunds - ) - external - returns (uint256 validationData); - - /** - * During the execution phase of ERC4337, this function upgrades the SafeProxy to the actual - * SafeSingleton implementation. Subsequently, it invokes the ISafe.setup() function to - * initialize the Safe Account. The setup() function should ensure the completion of Safe7579 - * Adapter initialization with InitData.setupTo as address(this) and InitData.setupData encoding - * the call to this.initSafe7579(). SafeProxy.setup() delegatecalls this function to install - * executors, fallbacks, hooks, and registry configurations on the Safe7579 adapter. As this - * occurs in the ERC4337 execution phase, storage restrictions are not applicable. - * - * @param initData initData to initialize the Safe and Safe7579 Adapter - */ - function setupSafe(InitData calldata initData) external; - - function getInitHash() external view returns (bytes32); - - /** - * Helper function that can be used offchain to predict the counterfactual Safe address. - * @dev factoryInitializer is expected to be: - * abi.encodeCall(Safe7579Launchpad.preValidationSetup, (initHash, to, callData)); - */ - function predictSafeAddress( - address singleton, - address safeProxyFactory, - bytes memory creationCode, - bytes32 salt, - bytes memory factoryInitializer - ) - external - pure - returns (address safeProxy); - - /** - * Create unique InitData hash. Using all params but excluding data.callData from hash - */ - function hash(InitData memory data) external pure returns (bytes32); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeOp.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeOp.sol deleted file mode 100644 index b9a0a90..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeOp.sol +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol"; - -bytes32 constant SAFE_OP_TYPEHASH = - 0xc03dfc11d8b10bf9cf703d558958c8c42777f785d998c62060d85a4f0ef6ea7f; - -interface ISafeOp { - /** - * @notice The EIP-712 type-hash for a SafeOp, representing the structure of a User Operation - * for - * the Safe. - * {address} safe - The address of the safe on which the operation is performed. - * {uint256} nonce - A unique number associated with the user operation, preventing replay - * attacks - * by ensuring each operation is unique. - * {bytes} initCode - The packed encoding of a factory address and its factory-specific data - * for - * creating a new Safe account. - * {bytes} callData - The bytes representing the data of the function call to be executed. - * {uint128} verificationGasLimit - The maximum amount of gas allowed for the verification - * process. - * {uint128} callGasLimit - The maximum amount of gas allowed for executing the function call. - * {uint256} preVerificationGas - The amount of gas allocated for pre-verification steps before - * executing the main operation. - * {uint128} maxPriorityFeePerGas - The maximum priority fee per gas that the user is willing - * to - * pay for the transaction. - * {uint128} maxFeePerGas - The maximum fee per gas that the user is willing to pay for the - * transaction. - * {bytes} paymasterAndData - The packed encoding of a paymaster address and its - * paymaster-specific - * data for sponsoring the user operation. - * {uint48} validAfter - A timestamp representing from when the user operation is valid. - * {uint48} validUntil - A timestamp representing until when the user operation is valid, or 0 - * to - * indicated "forever". - * {address} entryPoint - The address of the entry point that will execute the user operation. - * @dev When validating the user operation, the signature timestamps are pre-pended to the - * signature - * bytes. Equal to: - * keccak256( - * "SafeOp(address safe,uint256 nonce,bytes initCode,bytes callData,uint128 - * verificationGasLimit,uint128 callGasLimit,uint256 preVerificationGas,uint128 - * maxPriorityFeePerGas,uint128 maxFeePerGas,bytes paymasterAndData,uint48 validAfter,uint48 - * validUntil,address entryPoint)" - * ) = 0xc03dfc11d8b10bf9cf703d558958c8c42777f785d998c62060d85a4f0ef6ea7f - */ - struct EncodedSafeOpStruct { - bytes32 typeHash; - address safe; - uint256 nonce; - bytes32 initCodeHash; - bytes32 callDataHash; - uint128 verificationGasLimit; - uint128 callGasLimit; - uint256 preVerificationGas; - uint128 maxPriorityFeePerGas; - uint128 maxFeePerGas; - bytes32 paymasterAndDataHash; - uint48 validAfter; - uint48 validUntil; - address entryPoint; - } - - function domainSeparator() external view returns (bytes32); - - function getSafeOp( - PackedUserOperation calldata userOp, - address entryPoint - ) - external - view - returns ( - bytes memory operationData, - uint48 validAfter, - uint48 validUntil, - bytes calldata signatures - ); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeProxyFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeProxyFactory.sol deleted file mode 100644 index aecb094..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/interfaces/ISafeProxyFactory.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -interface ISafeProxyFactory { - function proxyCreationCode() external pure returns (bytes memory); - - function createProxyWithNonce( - address _singleton, - bytes memory initializer, - uint256 saltNonce - ) - external - returns (address proxy); - - function createChainSpecificProxyWithNonce( - address _singleton, - bytes memory initializer, - uint256 saltNonce - ) - external - returns (address proxy); - - function createProxyWithCallback( - address _singleton, - bytes memory initializer, - uint256 saltNonce, - address callback - ) - external - returns (address proxy); - - function getChainId() external view returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/types/DataTypes.sol b/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/types/DataTypes.sol deleted file mode 100644 index 3e755a3..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/accounts/safe/types/DataTypes.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IERC7484 } from "../interfaces/IERC7484.sol"; - -// Types -import { CallType } from "../../common/lib/ModeLib.sol"; - -struct FallbackHandler { - address handler; - CallType calltype; -} - -enum HookType { - GLOBAL, - SIG -} - -struct ModuleInit { - address module; - bytes initData; -} - -struct RegistryInit { - IERC7484 registry; - address[] attesters; - uint8 threshold; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/BytecodeDeployer.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/BytecodeDeployer.sol deleted file mode 100644 index a357a0c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/BytecodeDeployer.sol +++ /dev/null @@ -1,32 +0,0 @@ -// // SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/// @dev Deploys contracts using CREATE and CREATE2 -contract BytecodeDeployer { - /// @notice Deploys a contract using CREATE, reverts on failure - function _deploy(bytes memory creationBytecode) internal returns (address contractAddress) { - // solhint-disable-next-line no-inline-assembly - assembly { - contractAddress := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) - } - // solhint-disable-next-line gas-custom-errors - require(contractAddress != address(0), "Deployer: deployment failed"); - } - - /// @notice Deploys a contract using CREATE2, reverts on failure - function _deploy2( - bytes memory creationBytecode, - bytes32 salt - ) - internal - returns (address contractAddress) - { - // solhint-disable-next-line no-inline-assembly - assembly { - contractAddress := - create2(0, add(creationBytecode, 0x20), mload(creationBytecode), salt) - } - // solhint-disable-next-line gas-custom-errors - require(contractAddress != address(0), "Deployer: deployment failed"); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/ERC7579Precompiles.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/ERC7579Precompiles.sol deleted file mode 100644 index 335c438..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/ERC7579Precompiles.sol +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IERC7579Account } from "../../accounts/common/interfaces/IERC7579Account.sol"; -import { IERC7579Bootstrap } from "../../accounts/erc7579/interfaces/IERC7579Bootstrap.sol"; -import { IMSA } from "../../accounts/erc7579/interfaces/IMSA.sol"; - -// Utils -import { BytecodeDeployer } from "./BytecodeDeployer.sol"; - -interface RhinestoneBootstrap { - function init() external; -} - -/// @notice Precompiled erc7579 contracts -contract ERC7579Precompiles is BytecodeDeployer { - /*////////////////////////////////////////////////////////////// - DEPLOY - //////////////////////////////////////////////////////////////*/ - - function deployERC7579Account() internal returns (IERC7579Account) { - return IERC7579Account(_deploy(ERC7579_BYTECODE)); - } - - function deployMSAPRoxy( - bytes32 salt, - address implementation, - bytes memory initCode - ) - internal - returns (address) - { - return _deploy2( - bytes.concat( - MSAPROXY_BYTECODE, - abi.encode( - implementation, - abi.encodeWithSelector(IMSA.initializeAccount.selector, initCode) - ) - ), - salt - ); - } - - function deployERC7579Bootstrap() internal returns (IERC7579Bootstrap) { - return IERC7579Bootstrap(_deploy(ERC7579_BOOTSTRAP_BYTECODE)); - } - - function deployRhinestoneBootstrap() internal returns (RhinestoneBootstrap) { - return RhinestoneBootstrap(_deploy(ERC7579_RHINESTONE_TRAMPOLOINE_BYTECODE)); - } - - /*////////////////////////////////////////////////////////////// - BYTECODES - //////////////////////////////////////////////////////////////*/ - - /* solhint-disable max-line-length */ - bytes public constant ERC7579_BYTECODE = - hex"6080604052348015600e575f5ffd5b506175818061001c5f395ff3fe60806040526004361061012d575f3560e01c80639517e29f116100aa578063d691c9641161006e578063d691c96414610620578063e9ae5c5314610650578063ea5f61d01461066c578063eab77e17146106a9578063eac9b20d146106d1578063f2dc691d1461070d57610134565b80639517e29f146105585780639cfd7cff14610574578063a71763a81461059e578063b0d691fe146105ba578063d03c7914146105e457610134565b8063492a88a2116100f1578063492a88a21461048f5780634b6a1419146104b95780635faac46b146104d55780638626e88b146105125780638dd7712f1461053c57610134565b80630a664dba14610381578063112d3a7d146103ab5780631626ba7e146103e757806319822f7c146104235780631de6f24f1461045357610134565b3661013457005b5f3560e01c63bc197c81811463f23a6e6182141763150b7a028214171561015f57806020526020603cf35b505f610169610749565b6002015f5f357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f2090505f815f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f825f0160149054906101000a900460f81b90505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036102ab575f357fffffffff00000000000000000000000000000000000000000000000000000000166040517f48c9ceda0000000000000000000000000000000000000000000000000000000081526004016102a29190615b6c565b60405180910390fd5b6102b98160fe60f81b610777565b15610315576102d4565b5f6040519050818101604052919050565b6102dd366102c3565b365f82376102eb60146102c3565b3360601b81525f5f6014360184875afa6103043d6102c3565b3d5f823e81610311573d81fd5b3d81f35b610322815f60f81b610777565b1561037f5761033d565b5f6040519050818101604052919050565b6103463661032c565b365f8237610354601461032c565b3360601b81525f5f60143601845f885af161036e3d61032c565b3d5f823e8161037b573d81fd5b3d81f35b005b34801561038c575f5ffd5b506103956107c7565b6040516103a29190615bc4565b60405180910390f35b3480156103b6575f5ffd5b506103d160048036038101906103cc9190615cac565b6107d5565b6040516103de9190615d37565b60405180910390f35b3480156103f2575f5ffd5b5061040d60048036038101906104089190615d83565b610876565b60405161041a9190615b6c565b60405180910390f35b61043d6004803603810190610438919061606d565b610a3d565b60405161044a91906160e8565b60405180910390f35b34801561045e575f5ffd5b5061047960048036038101906104749190616101565b610bf2565b6040516104869190615bc4565b60405180910390f35b34801561049a575f5ffd5b506104a3610c03565b6040516104b09190615d37565b60405180910390f35b6104d360048036038101906104ce919061612c565b610c78565b005b3480156104e0575f5ffd5b506104fb60048036038101906104f69190616177565b610d66565b60405161050992919061626c565b60405180910390f35b34801561051d575f5ffd5b50610526610d97565b6040516105339190616351565b60405180910390f35b61055660048036038101906105519190616394565b610e13565b005b610572600480360381019061056d9190615cac565b610f4d565b005b34801561057f575f5ffd5b5061058861161e565b604051610595919061644e565b60405180910390f35b6105b860048036038101906105b39190615cac565b61165b565b005b3480156105c5575f5ffd5b506105ce611a32565b6040516105db9190615bc4565b60405180910390f35b3480156105ef575f5ffd5b5061060a60048036038101906106059190616498565b611a49565b6040516106179190615d37565b60405180910390f35b61063a600480360381019061063591906164c3565b611b04565b604051610647919061662d565b60405180910390f35b61066a600480360381019061066591906164c3565b61252d565b005b348015610677575f5ffd5b50610692600480360381019061068d9190616177565b612c31565b6040516106a092919061626c565b60405180910390f35b3480156106b4575f5ffd5b506106cf60048036038101906106ca9190616713565b612c63565b005b3480156106dc575f5ffd5b506106f760048036038101906106f291906167ae565b612dc0565b6040516107049190616851565b60405180910390f35b348015610718575f5ffd5b50610733600480360381019061072e9190616101565b612ee0565b6040516107409190615d37565b60405180910390f35b5f5f7fe3a55571e8f241b58442871487cc151a8cb048bb4ad24e833467f724ec89a9005f1b90508091505090565b5f817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b5f6107d0612f4b565b905090565b5f600185036107ee576107e784612f7a565b905061086e565b60028503610806576107ff84612fa3565b905061086e565b6003850361082d57610826838381019061082091906167ae565b85612fcd565b905061086e565b600485036108455761083e84613083565b905061086e565b60088514806108545750600985145b1561086a5761086384866130c1565b905061086e565b5f90505b949350505050565b5f5f83835f9060149261088b93929190616872565b9061089691906168ed565b60601c90506108a481612f7a565b61098f576108b0613101565b610952575f61090a6108c18761311e565b86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505061314e565b90503073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361095057631626ba7e60e01b92505050610a36565b505b806040517fb927fe5e0000000000000000000000000000000000000000000000000000000081526004016109869190615bc4565b60405180910390fd5b60606109ad86868660149080926109a893929190616872565b6131df565b80925081975050508173ffffffffffffffffffffffffffffffffffffffff1663f551e2ee3388846040518463ffffffff1660e01b81526004016109f2939291906169a2565b602060405180830381865afa158015610a0d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a3191906169f2565b925050505b9392505050565b5f610a46611a32565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610aaa576040517fac52ccbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815f5f866020015190508060601c9150610ac382612f7a565b610b4257610acf613101565b610b37575f610aeb610ae08861311e565b89610100015161314e565b90503073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610b2c5760019450505050610bda565b5f9450505050610bda565b600193505050610bda565b610b4d868887613306565b886101000181905281975050508173ffffffffffffffffffffffffffffffffffffffff16639700320388886040518363ffffffff1660e01b8152600401610b95929190616b03565b6020604051808303815f875af1158015610bb1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bd59190616b45565b935050505b8015610bea575f385f3884335af1505b509392505050565b5f610bfc826133e8565b9050919050565b5f3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c69576040517f0e93a1f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c71613492565b6001905090565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610cb457610cb36134bc565b5b610cbc613532565b5f7feadcdba66a79ab5dce91622d1d75c8cff5cff0b96944c3bf1072cd08ce018329303f1490508015610d4057610d147fe3a55571e8f241b58442871487cc151a8cb048bb4ad24e833467f724ec89a9005f1b613557565b610d3f7fcd97a6611018468306afd07ac8b14141bc76df8b844b3bcba1768d81e45982005f1b613557565b5b5f5f8484810190610d519190616bab565b91509150610d5f82826135a6565b5050505050565b60605f5f610d72610749565b5f019050610d8b85858361361b9092919063ffffffff16565b92509250509250929050565b60605f7fc473de86d0138e06e4d4918a106463a7cc005258d2e21915272bcb4594c189009050805f01805480602002602001604051908101604052809291908181526020018280548015610e0857602002820191905f5260205f20905b815481526020019060010190808311610df4575b505050505091505090565b610e1b611a32565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610e7f576040517fac52ccbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b365f838060600190610e919190616c11565b6004908092610ea293929190616872565b915091505f3073ffffffffffffffffffffffffffffffffffffffff168383604051610ece929190616ca1565b5f60405180830381855af49150503d805f8114610f06576040519150601f19603f3d011682016040523d82523d5f602084013e610f0b565b606091505b5050905080610f46576040517facfdb44400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b610f55611a32565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480610fb957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b610fef576040517fac52ccbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610ff8612f4b565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036112ae5783855f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146110ee578073ffffffffffffffffffffffffffffffffffffffff166396fb721784846040518363ffffffff1660e01b81526004016110c1929190616cb9565b5f6040518083038186803b1580156110d7575f5ffd5b505afa1580156110e9573d5f5f3e3d5ffd5b505050505b8673ffffffffffffffffffffffffffffffffffffffff1663ecd05961896040518263ffffffff1660e01b815260040161112791906160e8565b602060405180830381865afa158015611142573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111669190616d0a565b6111a757876040517fd393448a00000000000000000000000000000000000000000000000000000000815260040161119e91906160e8565b60405180910390fd5b600188036111bf576111ba87878761393e565b61126d565b600288036111d7576111d28787876139cc565b61126c565b600388036111ef576111ea878787613a5b565b61126b565b6004880361120757611202878787613cb8565b61126a565b60088814806112165750600988145b1561122c5761122787898888613daa565b611269565b876040517f41c38b3000000000000000000000000000000000000000000000000000000000815260040161126091906160e8565b60405180910390fd5b5b5b5b5b7fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123888860405161129e929190616d35565b60405180910390a1505050611617565b5f8173ffffffffffffffffffffffffffffffffffffffff1663d68f602533345f366040518563ffffffff1660e01b81526004016112ee9493929190616d88565b5f604051808303815f875af1158015611309573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906113319190616e34565b905084865f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146113f4578073ffffffffffffffffffffffffffffffffffffffff166396fb721784846040518363ffffffff1660e01b81526004016113c7929190616cb9565b5f6040518083038186803b1580156113dd575f5ffd5b505afa1580156113ef573d5f5f3e3d5ffd5b505050505b8773ffffffffffffffffffffffffffffffffffffffff1663ecd059618a6040518263ffffffff1660e01b815260040161142d91906160e8565b602060405180830381865afa158015611448573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061146c9190616d0a565b6114ad57886040517fd393448a0000000000000000000000000000000000000000000000000000000081526004016114a491906160e8565b60405180910390fd5b600189036114c5576114c088888861393e565b611573565b600289036114dd576114d88888886139cc565b611572565b600389036114f5576114f0888888613a5b565b611571565b6004890361150d57611508888888613cb8565b611570565b600889148061151c5750600989145b156115325761152d888a8989613daa565b61156f565b886040517f41c38b3000000000000000000000000000000000000000000000000000000000815260040161156691906160e8565b60405180910390fd5b5b5b5b5b7fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef12389896040516115a4929190616d35565b60405180910390a15050508173ffffffffffffffffffffffffffffffffffffffff1663173bf7da826040518263ffffffff1660e01b81526004016115e89190616e7b565b5f604051808303815f87803b1580156115ff575f5ffd5b505af1158015611611573d5f5f3e3d5ffd5b50505050505b5050505050565b60606040518060400160405280601b81526020017f754d53412e616476616e6365642f77697468486f6f6b2e76302e310000000000815250905090565b611663611a32565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806116c757503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b6116fd576040517fac52ccbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611706612f4b565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361183f57600185036117535761174e848484613f6f565b611801565b6002850361176b57611766848484614014565b611800565b600385036117835761177e8484846140ba565b6117ff565b6004850361179b5761179684848461447d565b6117fe565b60088514806117aa5750600985145b156117c0576117bb848685856144f3565b6117fd565b846040517f41c38b300000000000000000000000000000000000000000000000000000000081526004016117f491906160e8565b60405180910390fd5b5b5b5b5b7f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e8585604051611832929190616d35565b60405180910390a1611a2b565b5f8173ffffffffffffffffffffffffffffffffffffffff1663d68f602533345f366040518563ffffffff1660e01b815260040161187f9493929190616d88565b5f604051808303815f875af115801561189a573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906118c29190616e34565b9050600186036118dc576118d7858585613f6f565b61198a565b600286036118f4576118ef858585614014565b611989565b6003860361190c576119078585856140ba565b611988565b600486036119245761191f85858561447d565b611987565b60088614806119335750600986145b1561194957611944858786866144f3565b611986565b856040517f41c38b3000000000000000000000000000000000000000000000000000000000815260040161197d91906160e8565b60405180910390fd5b5b5b5b5b7f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e86866040516119bb929190616d35565b60405180910390a18173ffffffffffffffffffffffffffffffffffffffff1663173bf7da826040518263ffffffff1660e01b81526004016119fc9190616e7b565b5f604051808303815f87803b158015611a13575f5ffd5b505af1158015611a25573d5f5f3e3d5ffd5b50505050505b5050505050565b5f6f71727de22e5e9d8baf0edac6f37da032905090565b5f5f5f611a5584614726565b505091509150611a6982600160f81b610777565b15611a775760019250611aba565b611a84825f60f81b610777565b15611a925760019250611ab9565b611aa08260ff60f81b610777565b15611aae5760019250611ab8565b5f92505050611aff565b5b5b611ac7815f60f81b614746565b15611ad55760019250611afc565b611ae381600160f81b614746565b15611af15760019250611afb565b5f92505050611aff565b5b50505b919050565b60605f611b0f610749565b6001019050611b27338261479690919063ffffffff16565b611b6857336040517fb927fe5e000000000000000000000000000000000000000000000000000000008152600401611b5f9190615bc4565b60405180910390fd5b5f611b71612f4b565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611ff1573360025f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611c68578073ffffffffffffffffffffffffffffffffffffffff166396fb721784846040518363ffffffff1660e01b8152600401611c3b929190616cb9565b5f6040518083038186803b158015611c51575f5ffd5b505afa158015611c63573d5f5f3e3d5ffd5b505050505b5f5f611c738b614726565b505091509150611c8782600160f81b610777565b15611d2857365f611c988c8c614865565b91509150611ca9835f60f81b614746565b15611cbf57611cb8828261490e565b9950611d21565b611ccd83600160f81b614746565b15611ce357611cdc82826149fc565b9950611d20565b826040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611d179190616eaa565b60405180910390fd5b5b5050611fe7565b611d35825f60f81b610777565b15611eca575f5f365f611d488e8e614b49565b9350935093509350600167ffffffffffffffff811115611d6b57611d6a615df4565b5b604051908082528060200260200182016040528015611d9e57816020015b6060815260200190600190039081611d895790505b509b505f611daf865f60f81b614746565b15611de357611dc085858585614bb3565b8d5f81518110611dd357611dd2616ec3565b5b6020026020010181905250611ec0565b611df186600160f81b614746565b15611e8257611e0285858585614bec565b8e5f81518110611e1557611e14616ec3565b5b60200260200101819052819250505080611e7d577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb75f8e5f81518110611e5e57611e5d616ec3565b5b6020026020010151604051611e74929190616f32565b60405180910390a15b611ebf565b856040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611eb69190616eaa565b60405180910390fd5b5b5050505050611fe6565b611ed88260ff60f81b610777565b15611fa8575f8a8a5f90601492611ef193929190616872565b90611efc91906168ed565b60601c9050365f8c8c6014908092611f1693929190616872565b91509150611f27845f60f81b614746565b15611f3d57611f37838383614c1d565b50611fa0565b611f4b84600160f81b614746565b15611f6257611f5b838383614c54565b5050611f9f565b836040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611f969190616eaa565b60405180910390fd5b5b505050611fe5565b816040517fb96fcfe4000000000000000000000000000000000000000000000000000000008152600401611fdc9190616f6f565b60405180910390fd5b5b5b5050505050612524565b5f8173ffffffffffffffffffffffffffffffffffffffff1663d68f602533345f366040518563ffffffff1660e01b81526004016120319493929190616d88565b5f604051808303815f875af115801561204c573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906120749190616e34565b90503360025f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612138578073ffffffffffffffffffffffffffffffffffffffff166396fb721784846040518363ffffffff1660e01b815260040161210b929190616cb9565b5f6040518083038186803b158015612121575f5ffd5b505afa158015612133573d5f5f3e3d5ffd5b505050505b5f5f6121438c614726565b50509150915061215782600160f81b610777565b156121f857365f6121688d8d614865565b91509150612179835f60f81b614746565b1561218f57612188828261490e565b9a506121f1565b61219d83600160f81b614746565b156121b3576121ac82826149fc565b9a506121f0565b826040517f1187dc060000000000000000000000000000000000000000000000000000000081526004016121e79190616eaa565b60405180910390fd5b5b50506124b7565b612205825f60f81b610777565b1561239a575f5f365f6122188f8f614b49565b9350935093509350600167ffffffffffffffff81111561223b5761223a615df4565b5b60405190808252806020026020018201604052801561226e57816020015b60608152602001906001900390816122595790505b509c505f61227f865f60f81b614746565b156122b35761229085858585614bb3565b8e5f815181106122a3576122a2616ec3565b5b6020026020010181905250612390565b6122c186600160f81b614746565b15612352576122d285858585614bec565b8f5f815181106122e5576122e4616ec3565b5b6020026020010181905281925050508061234d577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb75f8f5f8151811061232e5761232d616ec3565b5b6020026020010151604051612344929190616f32565b60405180910390a15b61238f565b856040517f1187dc060000000000000000000000000000000000000000000000000000000081526004016123869190616eaa565b60405180910390fd5b5b50505050506124b6565b6123a88260ff60f81b610777565b15612478575f8b8b5f906014926123c193929190616872565b906123cc91906168ed565b60601c9050365f8d8d60149080926123e693929190616872565b915091506123f7845f60f81b614746565b1561240d57612407838383614c1d565b50612470565b61241b84600160f81b614746565b156124325761242b838383614c54565b505061246f565b836040517f1187dc060000000000000000000000000000000000000000000000000000000081526004016124669190616eaa565b60405180910390fd5b5b5050506124b5565b816040517fb96fcfe40000000000000000000000000000000000000000000000000000000081526004016124ac9190616f6f565b60405180910390fd5b5b5b50505050508173ffffffffffffffffffffffffffffffffffffffff1663173bf7da826040518263ffffffff1660e01b81526004016124f59190616e7b565b5f604051808303815f87803b15801561250c575f5ffd5b505af115801561251e573d5f5f3e3d5ffd5b50505050505b50509392505050565b612535611a32565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061259957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b6125cf576040517fac52ccbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6125d8612f4b565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036128a8575f5f61261886614726565b50509150915061262c82600160f81b610777565b156126cb57365f61263d8787614865565b9150915061264e835f60f81b614746565b156126635761265d828261490e565b506126c4565b61267183600160f81b614746565b156126865761268082826149fc565b506126c3565b826040517f1187dc060000000000000000000000000000000000000000000000000000000081526004016126ba9190616eaa565b60405180910390fd5b5b50506128a1565b6126d8825f60f81b610777565b15612784575f5f365f6126eb8989614b49565b9350935093509350612700855f60f81b614746565b156127175761271184848484614bb3565b5061277b565b61272585600160f81b614746565b1561273d5761273684848484614bec565b505061277a565b846040517f1187dc060000000000000000000000000000000000000000000000000000000081526004016127719190616eaa565b60405180910390fd5b5b505050506128a0565b6127928260ff60f81b610777565b15612862575f85855f906014926127ab93929190616872565b906127b691906168ed565b60601c9050365f878760149080926127d093929190616872565b915091506127e1845f60f81b614746565b156127f7576127f1838383614c1d565b5061285a565b61280584600160f81b614746565b1561281c57612815838383614c54565b5050612859565b836040517f1187dc060000000000000000000000000000000000000000000000000000000081526004016128509190616eaa565b60405180910390fd5b5b50505061289f565b816040517fb96fcfe40000000000000000000000000000000000000000000000000000000081526004016128969190616f6f565b60405180910390fd5b5b5b5050612c2b565b5f8173ffffffffffffffffffffffffffffffffffffffff1663d68f602533345f366040518563ffffffff1660e01b81526004016128e89493929190616d88565b5f604051808303815f875af1158015612903573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061292b9190616e34565b90505f5f61293887614726565b50509150915061294c82600160f81b610777565b156129eb57365f61295d8888614865565b9150915061296e835f60f81b614746565b156129835761297d828261490e565b506129e4565b61299183600160f81b614746565b156129a6576129a082826149fc565b506129e3565b826040517f1187dc060000000000000000000000000000000000000000000000000000000081526004016129da9190616eaa565b60405180910390fd5b5b5050612bc1565b6129f8825f60f81b610777565b15612aa4575f5f365f612a0b8a8a614b49565b9350935093509350612a20855f60f81b614746565b15612a3757612a3184848484614bb3565b50612a9b565b612a4585600160f81b614746565b15612a5d57612a5684848484614bec565b5050612a9a565b846040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401612a919190616eaa565b60405180910390fd5b5b50505050612bc0565b612ab28260ff60f81b610777565b15612b82575f86865f90601492612acb93929190616872565b90612ad691906168ed565b60601c9050365f88886014908092612af093929190616872565b91509150612b01845f60f81b614746565b15612b1757612b11838383614c1d565b50612b7a565b612b2584600160f81b614746565b15612b3c57612b35838383614c54565b5050612b79565b836040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401612b709190616eaa565b60405180910390fd5b5b505050612bbf565b816040517fb96fcfe4000000000000000000000000000000000000000000000000000000008152600401612bb69190616f6f565b60405180910390fd5b5b5b50508173ffffffffffffffffffffffffffffffffffffffff1663173bf7da826040518263ffffffff1660e01b8152600401612bfc9190616e7b565b5f604051808303815f87803b158015612c13575f5ffd5b505af1158015612c25573d5f5f3e3d5ffd5b50505050505b50505050565b60605f5f612c3d610749565b6001019050612c5785858361361b9092919063ffffffff16565b92509250509250929050565b612c6b611a32565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480612ccf57503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b612d05576040517fac52ccbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f838390501115612dba578373ffffffffffffffffffffffffffffffffffffffff1663f05c04e18285856040518463ffffffff1660e01b8152600401612d8c9392919061701d565b5f604051808303815f87803b158015612da3575f5ffd5b505af1158015612db5573d5f5f3e3d5ffd5b505050505b50505050565b612dc8615ae2565b612dd0610749565b6002015f837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f206040518060400160405290815f82015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f820160149054906101000a900460f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815250509050919050565b5f60018203612ef25760019050612f46565b60028203612f035760019050612f46565b60038203612f145760019050612f46565b60048203612f255760019050612f46565b6008821480612f345750600982145b15612f425760019050612f46565b5f90505b919050565b5f5f7fcd97a6611018468306afd07ac8b14141bc76df8b844b3bcba1768d81e45982005f1b9050805491505090565b5f5f612f84610749565b5f019050612f9b838261479690919063ffffffff16565b915050919050565b5f5f612fad610749565b6001019050612fc5838261479690919063ffffffff16565b915050919050565b5f5f612fd7610749565b6002015f857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f2090508273ffffffffffffffffffffffffffffffffffffffff16815f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161491505092915050565b5f8173ffffffffffffffffffffffffffffffffffffffff166130a3612f4b565b73ffffffffffffffffffffffffffffffffffffffff16149050919050565b5f8273ffffffffffffffffffffffffffffffffffffffff166130e2836133e8565b73ffffffffffffffffffffffffffffffffffffffff1614905092915050565b5f5f61310b610749565b9050613118815f01614c83565b91505090565b5f816020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c6004209050919050565b5f6040516001156131d857825160408114613171576041811461319057506131cb565b6040840151601b8160ff1c016020528060011b60011c606052506131a3565b60608401515f1a60205260408401516060525b50835f5260208301516040526020600160805f60015afa5191505f606052806040523d6131d8575b638baa579f5f526004601cfd5b5092915050565b5f60605f6131ed60086133e8565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036132775785858581818080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050509050905092509250506132fe565b8073ffffffffffffffffffffffffffffffffffffffff16637a0468b7338888886040518563ffffffff1660e01b81526004016132b6949392919061704d565b5f60405180830381865afa1580156132d0573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906132f8919061709f565b92509250505b935093915050565b5f60605f61331460096133e8565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361335a578585610100015192509250506133e0565b8073ffffffffffffffffffffffffffffffffffffffff1663e24f8f938686896040518463ffffffff1660e01b8152600401613397939291906170f9565b5f604051808303815f875af11580156133b2573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906133da919061709f565b92509250505b935093915050565b5f5f6133f2614d19565b90506008830361342757805f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505061348d565b6009830361345b57806001015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505061348d565b6040517f5691922f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b61349a614d47565b6134a2614e67565b6134b26134ad612f4b565b614f88565b6134ba613532565b565b5f60ff5f1b1960017ff63b257b7881773a84d328ab92140e19ab791f7b439c76ba9837aa0d6ad30af05f1c6134f19190617162565b60405160200161350191906160e8565b60405160208183030381529060405280519060200120169050805c8061352e5763aed595955f526004601cfd5b5050565b5f61353b610749565b905061354981600101615068565b613554815f01615068565b50565b5f7fc473de86d0138e06e4d4918a106463a7cc005258d2e21915272bcb4594c189009050805f0182908060018154018082558091505060019003905f5260205f20015f90919091909150555050565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040516135cc91906171c5565b5f60405180830381855af49150503d805f8114613604576040519150601f19603f3d011682016040523d82523d5f602084013e613609565b606091505b5050905080613616575f5ffd5b505050565b60605f600173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415801561366257506136608585614796565b155b156136a457836040517f7c84ecfb00000000000000000000000000000000000000000000000000000000815260040161369b9190615bc4565b60405180910390fd5b5f83036136dd576040517ff725081700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8267ffffffffffffffff8111156136f7576136f6615df4565b5b6040519080825280602002602001820160405280156137255781602001602082028036833780820191505090505b5091505f5f9050855f015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156137f65750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b801561380157508381105b156138c7578183828151811061381a57613819616ec3565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050855f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16915080806138bf906171db565b91505061378d565b600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415801561390357505f81115b1561393257826001826139169190617162565b8151811061392757613926616ec3565b5b602002602001015191505b80835250935093915050565b5f613947610749565b5f01905061395e848261512990919063ffffffff16565b8373ffffffffffffffffffffffffffffffffffffffff16636d61fe7084846040518363ffffffff1660e01b8152600401613999929190617222565b5f604051808303815f87803b1580156139b0575f5ffd5b505af11580156139c2573d5f5f3e3d5ffd5b5050505050505050565b5f6139d5610749565b60010190506139ed848261512990919063ffffffff16565b8373ffffffffffffffffffffffffffffffffffffffff16636d61fe7084846040518363ffffffff1660e01b8152600401613a28929190617222565b5f604051808303815f87803b158015613a3f575f5ffd5b505af1158015613a51573d5f5f3e3d5ffd5b5050505050505050565b5f82825f90600492613a6f93929190616872565b90613a7a9190617244565b90505f83836004818110613a9157613a90616ec3565b5b9050013560f81c60f81b90505f84846005908092613ab193929190616872565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050509050613afe836153f9565b15613b3e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613b35906172ec565b60405180910390fd5b60405180604001604052808773ffffffffffffffffffffffffffffffffffffffff168152602001837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815250613b93610749565b6002015f857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151815f0160146101000a81548160ff021916908360f81c02179055509050508573ffffffffffffffffffffffffffffffffffffffff16636d61fe70826040518263ffffffff1660e01b8152600401613c839190616e7b565b5f604051808303815f87803b158015613c9a575f5ffd5b505af1158015613cac573d5f5f3e3d5ffd5b50505050505050505050565b5f613cc1612f4b565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614613d3357806040517f741cbe03000000000000000000000000000000000000000000000000000000008152600401613d2a9190615bc4565b60405180910390fd5b613d3c846154af565b8373ffffffffffffffffffffffffffffffffffffffff16636d61fe7084846040518363ffffffff1660e01b8152600401613d77929190617222565b5f604051808303815f87803b158015613d8e575f5ffd5b505af1158015613da0573d5f5f3e3d5ffd5b5050505050505050565b5f613db3614d19565b90505f613dbf856133e8565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614613e3157806040517f786ae235000000000000000000000000000000000000000000000000000000008152600401613e289190615bc4565b60405180910390fd5b613e3b86866154dc565b60088503613ed257815f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636d61fe7085856040518363ffffffff1660e01b8152600401613ea0929190617222565b5f604051808303815f87803b158015613eb7575f5ffd5b505af1158015613ec9573d5f5f3e3d5ffd5b50505050613f67565b60098503613f6657816001015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636d61fe7085856040518363ffffffff1660e01b8152600401613f38929190617222565b5f604051808303815f87803b158015613f4f575f5ffd5b505af1158015613f61573d5f5f3e3d5ffd5b505050505b5b505050505050565b5f613f78610749565b5f0190505f5f8484810190613f8d9190616bab565b91509150613fa68287856155bc9092919063ffffffff16565b8573ffffffffffffffffffffffffffffffffffffffff16638a91b0e3826040518263ffffffff1660e01b8152600401613fdf9190616e7b565b5f604051808303815f87803b158015613ff6575f5ffd5b505af1158015614008573d5f5f3e3d5ffd5b50505050505050505050565b5f61401d610749565b60010190505f5f84848101906140339190616bab565b9150915061404c8287856155bc9092919063ffffffff16565b8573ffffffffffffffffffffffffffffffffffffffff16638a91b0e3826040518263ffffffff1660e01b81526004016140859190616e7b565b5f604051808303815f87803b15801561409c575f5ffd5b505af11580156140ae573d5f5f3e3d5ffd5b50505050505050505050565b5f82825f906004926140ce93929190616872565b906140d99190617244565b90505f838360049080926140ef93929190616872565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050905061413c826153f9565b61417b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161417290617354565b60405180910390fd5b5f614184610749565b6002015f847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f206040518060400160405290815f82015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f820160149054906101000a900460f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152505090508573ffffffffffffffffffffffffffffffffffffffff16815f015173ffffffffffffffffffffffffffffffffffffffff1614614300576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016142f7906173e2565b60405180910390fd5b60405180604001604052805f73ffffffffffffffffffffffffffffffffffffffff1681526020015f60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815250614358610749565b6002015f857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151815f0160146101000a81548160ff021916908360f81c02179055509050508573ffffffffffffffffffffffffffffffffffffffff16638a91b0e3836040518263ffffffff1660e01b81526004016144489190616e7b565b5f604051808303815f87803b15801561445f575f5ffd5b505af1158015614471573d5f5f3e3d5ffd5b50505050505050505050565b6144865f6154af565b8273ffffffffffffffffffffffffffffffffffffffff16638a91b0e383836040518363ffffffff1660e01b81526004016144c1929190617222565b5f604051808303815f87803b1580156144d8575f5ffd5b505af11580156144ea573d5f5f3e3d5ffd5b50505050505050565b5f6144fc614d19565b905060088414801561455b57508473ffffffffffffffffffffffffffffffffffffffff16815f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b156145ef57805f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638a91b0e384846040518363ffffffff1660e01b81526004016145bd929190617222565b5f604051808303815f87803b1580156145d4575f5ffd5b505af11580156145e6573d5f5f3e3d5ffd5b50505050614715565b60098414801561464d57508473ffffffffffffffffffffffffffffffffffffffff16816001015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b156146e257806001015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638a91b0e384846040518363ffffffff1660e01b81526004016146b0929190617222565b5f604051808303815f87803b1580156146c7575f5ffd5b505af11580156146d9573d5f5f3e3d5ffd5b50505050614714565b6040517f5691922f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b61471f5f856154dc565b5050505050565b5f5f5f5f8493508460081b92508460301b91508460501b90509193509193565b5f817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b5f8173ffffffffffffffffffffffffffffffffffffffff16600173ffffffffffffffffffffffffffffffffffffffff161415801561485d57505f73ffffffffffffffffffffffffffffffffffffffff16835f015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b905092915050565b365f833580850160208587010360208201945081359350808460051b8301118360401c171561489b5763ba597e7e5f526004601cfd5b831561490457835b600115614902576001810390508060051b86013580870160408101358082018581358201118660408501111782851782351760401c17156148eb5763ba597e7e5f526004601cfd5b846148f95750505050614902565b505050506148a3565b505b5050509250929050565b60605f8383905090508067ffffffffffffffff81111561493157614930615df4565b5b60405190808252806020026020018201604052801561496457816020015b606081526020019060019003908161494f5790505b5091505f5b818110156149f4573685858381811061498557614984616ec3565b5b90506020028101906149979190617400565b90506149c8815f0160208101906149ae9190617427565b82602001358380604001906149c39190616c11565b614bb3565b8483815181106149db576149da616ec3565b5b6020026020010181905250508080600101915050614969565b505092915050565b60605f8383905090508067ffffffffffffffff811115614a1f57614a1e615df4565b5b604051908082528060200260200182016040528015614a5257816020015b6060815260200190600190039081614a3d5790505b5091505f5b81811015614b415736858583818110614a7357614a72616ec3565b5b9050602002810190614a859190617400565b90505f614ab7825f016020810190614a9d9190617427565b8360200135848060400190614ab29190616c11565b614bec565b868581518110614aca57614ac9616ec3565b5b60200260200101819052819250505080614b32577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb783868581518110614b1357614b12616ec3565b5b6020026020010151604051614b29929190617452565b60405180910390a15b50508080600101915050614a57565b505092915050565b5f5f365f85855f90601492614b6093929190616872565b90614b6b91906168ed565b60601c93508585601490603492614b8493929190616872565b90614b8f9190617480565b5f1c925085856034908092614ba693929190616872565b9150915092959194509250565b60606040519050818382375f38838387895af1614bd2573d5f823e3d81fd5b3d8152602081013d5f823e3d810160405250949350505050565b5f60606040519050828482375f388483888a5af191503d8152602081013d5f823e3d81016040525094509492505050565b60606040519050818382375f388383875af4614c3b573d5f823e3d81fd5b3d8152602081013d5f823e3d8101604052509392505050565b5f60606040519050828482375f388483885af491503d8152602081013d5f823e3d810160405250935093915050565b5f5f73ffffffffffffffffffffffffffffffffffffffff16825f015f600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614159050919050565b5f5f7f088e45215d3756b04bd240e41d75700a696139d5b53082481ffc3914e48400005f1b90508091505090565b5f614d50610749565b5f0190505f614d6960018361588b90919063ffffffff16565b90505b600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614614e5a578073ffffffffffffffffffffffffffffffffffffffff16638a91b0e36040518163ffffffff1660e01b8152600401614dd790617501565b5f604051808303815f87803b158015614dee575f5ffd5b505af1925050508015614dff575060015b614e3f577f6c31ee2929752d85a6dc461efcf817aa81394aff41db1856ebfd71679fffc57081604051614e32919061751f565b60405180910390a1614e40565b5b614e53818361588b90919063ffffffff16565b9050614d6c565b614e6382615962565b5050565b5f614e70610749565b60010190505f614e8a60018361588b90919063ffffffff16565b90505b600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614614f7b578073ffffffffffffffffffffffffffffffffffffffff16638a91b0e36040518163ffffffff1660e01b8152600401614ef890617501565b5f604051808303815f87803b158015614f0f575f5ffd5b505af1925050508015614f20575060015b614f60577ffdea4600cf09065ff861064d4cd43cde3fae2134d9fbe6d66fd77cc67135c88281604051614f53919061751f565b60405180910390a1614f61565b5b614f74818361588b90919063ffffffff16565b9050614e8d565b614f8482615962565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614615065578073ffffffffffffffffffffffffffffffffffffffff16638a91b0e36040518163ffffffff1660e01b8152600401614ff290617501565b5f604051808303815f87803b158015615009575f5ffd5b505af192505050801561501a575060015b61505a577f57af23cbd8e148da6020d15e1ff9fb3c531aa9003d6bab6915013a7d8fd032368160405161504d919061751f565b60405180910390a161505b565b5b6150645f6154af565b5b50565b61507181614c83565b156150a8576040517f53c85e6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001815f015f600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16148061518f5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b156151d157806040517f7c84ecfb0000000000000000000000000000000000000000000000000000000081526004016151c89190615bc4565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16825f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461529e57806040517f40d3d1a40000000000000000000000000000000000000000000000000000000081526004016152959190615bc4565b60405180910390fd5b815f015f600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16825f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080825f015f600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b5f5f615403610749565b6002015f847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f2090505f73ffffffffffffffffffffffffffffffffffffffff16815f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415915050919050565b5f7fcd97a6611018468306afd07ac8b14141bc76df8b844b3bcba1768d81e45982005f1b90508181555050565b5f6154e5614d19565b9050600882036155355782815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506155b7565b600982036155845782816001015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506155b6565b6040517f5691922f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b505050565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614806156225750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b1561566457816040517f7c84ecfb00000000000000000000000000000000000000000000000000000000815260040161565b9190615bc4565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16835f015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461573157806040517f7c84ecfb0000000000000000000000000000000000000000000000000000000081526004016157289190615bc4565b60405180910390fd5b825f015f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16835f015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f835f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505050565b5f5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036158fc57816040517f7c84ecfb0000000000000000000000000000000000000000000000000000000081526004016158f39190615bc4565b60405180910390fd5b825f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905092915050565b5f815f015f600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614615ade575f819050825f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505f835f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506159c5565b5050565b60405180604001604052805f73ffffffffffffffffffffffffffffffffffffffff1681526020015f7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681525090565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b615b6681615b32565b82525050565b5f602082019050615b7f5f830184615b5d565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f615bae82615b85565b9050919050565b615bbe81615ba4565b82525050565b5f602082019050615bd75f830184615bb5565b92915050565b5f604051905090565b5f5ffd5b5f5ffd5b5f819050919050565b615c0081615bee565b8114615c0a575f5ffd5b50565b5f81359050615c1b81615bf7565b92915050565b615c2a81615ba4565b8114615c34575f5ffd5b50565b5f81359050615c4581615c21565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112615c6c57615c6b615c4b565b5b8235905067ffffffffffffffff811115615c8957615c88615c4f565b5b602083019150836001820283011115615ca557615ca4615c53565b5b9250929050565b5f5f5f5f60608587031215615cc457615cc3615be6565b5b5f615cd187828801615c0d565b9450506020615ce287828801615c37565b935050604085013567ffffffffffffffff811115615d0357615d02615bea565b5b615d0f87828801615c57565b925092505092959194509250565b5f8115159050919050565b615d3181615d1d565b82525050565b5f602082019050615d4a5f830184615d28565b92915050565b5f819050919050565b615d6281615d50565b8114615d6c575f5ffd5b50565b5f81359050615d7d81615d59565b92915050565b5f5f5f60408486031215615d9a57615d99615be6565b5b5f615da786828701615d6f565b935050602084013567ffffffffffffffff811115615dc857615dc7615bea565b5b615dd486828701615c57565b92509250509250925092565b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b615e2a82615de4565b810181811067ffffffffffffffff82111715615e4957615e48615df4565b5b80604052505050565b5f615e5b615bdd565b9050615e678282615e21565b919050565b5f5ffd5b5f5ffd5b5f67ffffffffffffffff821115615e8e57615e8d615df4565b5b615e9782615de4565b9050602081019050919050565b828183375f83830152505050565b5f615ec4615ebf84615e74565b615e52565b905082815260208101848484011115615ee057615edf615e70565b5b615eeb848285615ea4565b509392505050565b5f82601f830112615f0757615f06615c4b565b5b8135615f17848260208601615eb2565b91505092915050565b5f6101208284031215615f3657615f35615de0565b5b615f41610120615e52565b90505f615f5084828501615c37565b5f830152506020615f6384828501615c0d565b602083015250604082013567ffffffffffffffff811115615f8757615f86615e6c565b5b615f9384828501615ef3565b604083015250606082013567ffffffffffffffff811115615fb757615fb6615e6c565b5b615fc384828501615ef3565b6060830152506080615fd784828501615d6f565b60808301525060a0615feb84828501615c0d565b60a08301525060c0615fff84828501615d6f565b60c08301525060e082013567ffffffffffffffff81111561602357616022615e6c565b5b61602f84828501615ef3565b60e08301525061010082013567ffffffffffffffff81111561605457616053615e6c565b5b61606084828501615ef3565b6101008301525092915050565b5f5f5f6060848603121561608457616083615be6565b5b5f84013567ffffffffffffffff8111156160a1576160a0615bea565b5b6160ad86828701615f20565b93505060206160be86828701615d6f565b92505060406160cf86828701615c0d565b9150509250925092565b6160e281615bee565b82525050565b5f6020820190506160fb5f8301846160d9565b92915050565b5f6020828403121561611657616115615be6565b5b5f61612384828501615c0d565b91505092915050565b5f5f6020838503121561614257616141615be6565b5b5f83013567ffffffffffffffff81111561615f5761615e615bea565b5b61616b85828601615c57565b92509250509250929050565b5f5f6040838503121561618d5761618c615be6565b5b5f61619a85828601615c37565b92505060206161ab85828601615c0d565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6161e781615ba4565b82525050565b5f6161f883836161de565b60208301905092915050565b5f602082019050919050565b5f61621a826161b5565b61622481856161bf565b935061622f836161cf565b805f5b8381101561625f57815161624688826161ed565b975061625183616204565b925050600181019050616232565b5085935050505092915050565b5f6040820190508181035f8301526162848185616210565b90506162936020830184615bb5565b9392505050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6162cc81615d50565b82525050565b5f6162dd83836162c3565b60208301905092915050565b5f602082019050919050565b5f6162ff8261629a565b61630981856162a4565b9350616314836162b4565b805f5b8381101561634457815161632b88826162d2565b9750616336836162e9565b925050600181019050616317565b5085935050505092915050565b5f6020820190508181035f83015261636981846162f5565b905092915050565b5f5ffd5b5f610120828403121561638b5761638a616371565b5b81905092915050565b5f5f604083850312156163aa576163a9615be6565b5b5f83013567ffffffffffffffff8111156163c7576163c6615bea565b5b6163d385828601616375565b92505060206163e485828601615d6f565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f616420826163ee565b61642a81856163f8565b935061643a818560208601616408565b61644381615de4565b840191505092915050565b5f6020820190508181035f8301526164668184616416565b905092915050565b61647781615d50565b8114616481575f5ffd5b50565b5f813590506164928161646e565b92915050565b5f602082840312156164ad576164ac615be6565b5b5f6164ba84828501616484565b91505092915050565b5f5f5f604084860312156164da576164d9615be6565b5b5f6164e786828701616484565b935050602084013567ffffffffffffffff81111561650857616507615bea565b5b61651486828701615c57565b92509250509250925092565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f81519050919050565b5f82825260208201905092915050565b5f61656d82616549565b6165778185616553565b9350616587818560208601616408565b61659081615de4565b840191505092915050565b5f6165a68383616563565b905092915050565b5f602082019050919050565b5f6165c482616520565b6165ce818561652a565b9350836020820285016165e08561653a565b805f5b8581101561661b57848403895281516165fc858261659b565b9450616607836165ae565b925060208a019950506001810190506165e3565b50829750879550505050505092915050565b5f6020820190508181035f83015261664581846165ba565b905092915050565b5f61665782615ba4565b9050919050565b6166678161664d565b8114616671575f5ffd5b50565b5f813590506166828161665e565b92915050565b5f5f83601f84011261669d5761669c615c4b565b5b8235905067ffffffffffffffff8111156166ba576166b9615c4f565b5b6020830191508360208202830111156166d6576166d5615c53565b5b9250929050565b5f60ff82169050919050565b6166f2816166dd565b81146166fc575f5ffd5b50565b5f8135905061670d816166e9565b92915050565b5f5f5f5f6060858703121561672b5761672a615be6565b5b5f61673887828801616674565b945050602085013567ffffffffffffffff81111561675957616758615bea565b5b61676587828801616688565b93509350506040616778878288016166ff565b91505092959194509250565b61678d81615b32565b8114616797575f5ffd5b50565b5f813590506167a881616784565b92915050565b5f602082840312156167c3576167c2615be6565b5b5f6167d08482850161679a565b91505092915050565b5f7fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b5f61680e826167d9565b9050919050565b61681e81616804565b82525050565b604082015f8201516168385f8501826161de565b50602082015161684b6020850182616815565b50505050565b5f6040820190506168645f830184616824565b92915050565b5f5ffd5b5f5ffd5b5f5f858511156168855761688461686a565b5b838611156168965761689561686e565b5b6001850283019150848603905094509492505050565b5f82905092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b5f82821b905092915050565b5f6168f883836168ac565b8261690381356168b6565b925060148210156169435761693e7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000836014036008026168e1565b831692505b505092915050565b61695481615d50565b82525050565b5f82825260208201905092915050565b5f61697482616549565b61697e818561695a565b935061698e818560208601616408565b61699781615de4565b840191505092915050565b5f6060820190506169b55f830186615bb5565b6169c2602083018561694b565b81810360408301526169d4818461696a565b9050949350505050565b5f815190506169ec81616784565b92915050565b5f60208284031215616a0757616a06615be6565b5b5f616a14848285016169de565b91505092915050565b616a2681615bee565b82525050565b5f61012083015f830151616a425f8601826161de565b506020830151616a556020860182616a1d565b5060408301518482036040860152616a6d8282616563565b91505060608301518482036060860152616a878282616563565b9150506080830151616a9c60808601826162c3565b5060a0830151616aaf60a0860182616a1d565b5060c0830151616ac260c08601826162c3565b5060e083015184820360e0860152616ada8282616563565b915050610100830151848203610100860152616af68282616563565b9150508091505092915050565b5f6040820190508181035f830152616b1b8185616a2c565b9050616b2a602083018461694b565b9392505050565b5f81519050616b3f81615bf7565b92915050565b5f60208284031215616b5a57616b59615be6565b5b5f616b6784828501616b31565b91505092915050565b5f616b7a82615b85565b9050919050565b616b8a81616b70565b8114616b94575f5ffd5b50565b5f81359050616ba581616b81565b92915050565b5f5f60408385031215616bc157616bc0615be6565b5b5f616bce85828601616b97565b925050602083013567ffffffffffffffff811115616bef57616bee615bea565b5b616bfb85828601615ef3565b9150509250929050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83356001602003843603038112616c2d57616c2c616c05565b5b80840192508235915067ffffffffffffffff821115616c4f57616c4e616c09565b5b602083019250600182023603831315616c6b57616c6a616c0d565b5b509250929050565b5f81905092915050565b5f616c888385616c73565b9350616c95838584615ea4565b82840190509392505050565b5f616cad828486616c7d565b91508190509392505050565b5f604082019050616ccc5f830185615bb5565b616cd960208301846160d9565b9392505050565b616ce981615d1d565b8114616cf3575f5ffd5b50565b5f81519050616d0481616ce0565b92915050565b5f60208284031215616d1f57616d1e615be6565b5b5f616d2c84828501616cf6565b91505092915050565b5f604082019050616d485f8301856160d9565b616d556020830184615bb5565b9392505050565b5f616d67838561695a565b9350616d74838584615ea4565b616d7d83615de4565b840190509392505050565b5f606082019050616d9b5f830187615bb5565b616da860208301866160d9565b8181036040830152616dbb818486616d5c565b905095945050505050565b5f616dd8616dd384615e74565b615e52565b905082815260208101848484011115616df457616df3615e70565b5b616dff848285616408565b509392505050565b5f82601f830112616e1b57616e1a615c4b565b5b8151616e2b848260208601616dc6565b91505092915050565b5f60208284031215616e4957616e48615be6565b5b5f82015167ffffffffffffffff811115616e6657616e65615bea565b5b616e7284828501616e07565b91505092915050565b5f6020820190508181035f830152616e93818461696a565b905092915050565b616ea481616804565b82525050565b5f602082019050616ebd5f830184616e9b565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f819050919050565b5f819050919050565b5f616f1c616f17616f1284616ef0565b616ef9565b615bee565b9050919050565b616f2c81616f02565b82525050565b5f604082019050616f455f830185616f23565b8181036020830152616f57818461696a565b90509392505050565b616f6981616804565b82525050565b5f602082019050616f825f830184616f60565b92915050565b616f91816166dd565b82525050565b5f819050919050565b5f616fae6020840184615c37565b905092915050565b5f602082019050919050565b5f616fcd83856161bf565b9350616fd882616f97565b805f5b8581101561701057616fed8284616fa0565b616ff788826161ed565b975061700283616fb6565b925050600181019050616fdb565b5085925050509392505050565b5f6040820190506170305f830186616f88565b8181036020830152617043818486616fc2565b9050949350505050565b5f6060820190506170605f830187615bb5565b61706d602083018661694b565b8181036040830152617080818486616d5c565b905095945050505050565b5f8151905061709981615d59565b92915050565b5f5f604083850312156170b5576170b4615be6565b5b5f6170c28582860161708b565b925050602083015167ffffffffffffffff8111156170e3576170e2615bea565b5b6170ef85828601616e07565b9150509250929050565b5f6060820190508181035f8301526171118186616a2c565b905061712060208301856160d9565b61712d604083018461694b565b949350505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61716c82615bee565b915061717783615bee565b925082820390508181111561718f5761718e617135565b5b92915050565b5f61719f82616549565b6171a98185616c73565b93506171b9818560208601616408565b80840191505092915050565b5f6171d08284617195565b915081905092915050565b5f6171e582615bee565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361721757617216617135565b5b600182019050919050565b5f6020820190508181035f83015261723b818486616d5c565b90509392505050565b5f61724f83836168ac565b8261725a8135615b32565b9250600482101561729a576172957fffffffff00000000000000000000000000000000000000000000000000000000836004036008026168e1565b831692505b505092915050565b7f46756e6374696f6e2073656c6563746f7220616c7265616479207573656400005f82015250565b5f6172d6601e836163f8565b91506172e1826172a2565b602082019050919050565b5f6020820190508181035f830152617303816172ca565b9050919050565b7f46756e6374696f6e2073656c6563746f72206e6f7420757365640000000000005f82015250565b5f61733e601a836163f8565b91506173498261730a565b602082019050919050565b5f6020820190508181035f83015261736b81617332565b9050919050565b7f46756e6374696f6e2073656c6563746f72206e6f7420757365642062792074685f8201527f69732068616e646c657200000000000000000000000000000000000000000000602082015250565b5f6173cc602a836163f8565b91506173d782617372565b604082019050919050565b5f6020820190508181035f8301526173f9816173c0565b9050919050565b5f8235600160600383360303811261741b5761741a616c05565b5b80830191505092915050565b5f6020828403121561743c5761743b615be6565b5b5f61744984828501615c37565b91505092915050565b5f6040820190506174655f8301856160d9565b8181036020830152617477818461696a565b90509392505050565b5f61748b83836168ac565b826174968135615d50565b925060208210156174d6576174d17fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff836020036008026168e1565b831692505b505092915050565b50565b5f6174ec5f8361695a565b91506174f7826174de565b5f82019050919050565b5f6020820190508181035f830152617518816174e1565b9050919050565b5f6040820190506175325f830184615bb5565b8181036020830152617543816174e1565b90509291505056fea2646970667358221220a3ab10abccfc1e4991ad9a5f687ec3515e4bba3b7da0e732e5f7a7255be4dc6964736f6c634300081c0033"; - bytes public constant ERC7579_BOOTSTRAP_BYTECODE = - hex"6080604052348015600e575f5ffd5b506123028061001c5f395ff3fe60806040526004361061007e575f3560e01c80636b0d5cc41161004d5780636b0d5cc41461039d578063b0d691fe146103c5578063ea5f61d0146103ef578063eac9b20d1461042c57610085565b80630a664dba146102d25780635e87556d146102fc5780635faac46b14610338578063642219af1461037557610085565b3661008557005b5f3560e01c63bc197c81811463f23a6e6182141763150b7a02821417156100b057806020526020603cf35b505f6100ba610468565b6002015f5f357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f2090505f815f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f825f0160149054906101000a900460f81b90505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036101fc575f357fffffffff00000000000000000000000000000000000000000000000000000000166040517f48c9ceda0000000000000000000000000000000000000000000000000000000081526004016101f39190611706565b60405180910390fd5b61020a8160fe60f81b610496565b1561026657610225565b5f6040519050818101604052919050565b61022e36610214565b365f823761023c6014610214565b3360601b81525f5f6014360184875afa6102553d610214565b3d5f823e81610262573d81fd5b3d81f35b610273815f60f81b610496565b156102d05761028e565b5f6040519050818101604052919050565b6102973661027d565b365f82376102a5601461027d565b3360601b81525f5f60143601845f885af16102bf3d61027d565b3d5f823e816102cc573d81fd5b3d81f35b005b3480156102dd575f5ffd5b506102e66104e6565b6040516102f3919061175e565b60405180910390f35b348015610307575f5ffd5b50610322600480360381019061031d9190611802565b6104f4565b60405161032f9190611952565b60405180910390f35b348015610343575f5ffd5b5061035e600480360381019061035991906119cf565b61059f565b60405161036c929190611ac4565b60405180910390f35b348015610380575f5ffd5b5061039b60048036038101906103969190611802565b6105d0565b005b3480156103a8575f5ffd5b506103c360048036038101906103be9190611b82565b6108c3565b005b3480156103d0575f5ffd5b506103d96108d3565b6040516103e6919061175e565b60405180910390f35b3480156103fa575f5ffd5b50610415600480360381019061041091906119cf565b6108ea565b604051610423929190611ac4565b60405180910390f35b348015610437575f5ffd5b50610452600480360381019061044d9190611c09565b61091c565b60405161045f9190611cac565b60405180910390f35b5f5f7fe3a55571e8f241b58442871487cc151a8cb048bb4ad24e833467f724ec89a9005f1b90508091505090565b5f817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b5f6104ef610a3c565b905090565b6060303073ffffffffffffffffffffffffffffffffffffffff1663642219af8a8a8a8a8a8a8a6040516024016105309796959493929190611efc565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051602001610583929190611f61565b6040516020818303038152906040529050979650505050505050565b60605f5f6105ab610468565b5f0190506105c4858583610a6b9092919063ffffffff16565b92509250509250929050565b5f5b8787905081101561065c5761064f8888838181106105f3576105f2611f8f565b5b90506020028101906106059190611fc8565b5f0160208101906106169190611fef565b89898481811061062957610628611f8f565b5b905060200281019061063b9190611fc8565b806020019061064a919061201a565b610d8e565b80806001019150506105d2565b505f5b85859050811015610753575f73ffffffffffffffffffffffffffffffffffffffff1686868381811061069457610693611f8f565b5b90506020028101906106a69190611fc8565b5f0160208101906106b79190611fef565b73ffffffffffffffffffffffffffffffffffffffff160315610746576107458686838181106106e9576106e8611f8f565b5b90506020028101906106fb9190611fc8565b5f01602081019061070c9190611fef565b87878481811061071f5761071e611f8f565b5b90506020028101906107319190611fc8565b8060200190610740919061201a565b610e1c565b5b808060010191505061065f565b505f73ffffffffffffffffffffffffffffffffffffffff16835f01602081019061077d9190611fef565b73ffffffffffffffffffffffffffffffffffffffff16146107c3576107c2835f0160208101906107ad9190611fef565b8480602001906107bd919061201a565b610eab565b5b5f5b828290508110156108b9575f73ffffffffffffffffffffffffffffffffffffffff168383838181106107fa576107f9611f8f565b5b905060200281019061080c9190611fc8565b5f01602081019061081d9190611fef565b73ffffffffffffffffffffffffffffffffffffffff1603156108ac576108ab83838381811061084f5761084e611f8f565b5b90506020028101906108619190611fc8565b5f0160208101906108729190611fef565b84848481811061088557610884611f8f565b5b90506020028101906108979190611fc8565b80602001906108a6919061201a565b610f9d565b5b80806001019150506107c5565b5050505050505050565b6108ce838383610d8e565b505050565b5f6f71727de22e5e9d8baf0edac6f37da032905090565b60605f5f6108f6610468565b6001019050610910858583610a6b9092919063ffffffff16565b92509250509250929050565b61092461167c565b61092c610468565b6002015f837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f206040518060400160405290815f82015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f820160149054906101000a900460f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815250509050919050565b5f5f7fcd97a6611018468306afd07ac8b14141bc76df8b844b3bcba1768d81e45982005f1b9050805491505090565b60605f600173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614158015610ab25750610ab085856111fa565b155b15610af457836040517f7c84ecfb000000000000000000000000000000000000000000000000000000008152600401610aeb919061175e565b60405180910390fd5b5f8303610b2d576040517ff725081700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8267ffffffffffffffff811115610b4757610b4661207c565b5b604051908082528060200260200182016040528015610b755781602001602082028036833780820191505090505b5091505f5f9050855f015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610c465750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b8015610c5157508381105b15610d175781838281518110610c6a57610c69611f8f565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050855f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691508080610d0f906120d6565b915050610bdd565b600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610d5357505f81115b15610d825782600182610d66919061211d565b81518110610d7757610d76611f8f565b5b602002602001015191505b80835250935093915050565b5f610d97610468565b5f019050610dae84826112c990919063ffffffff16565b8373ffffffffffffffffffffffffffffffffffffffff16636d61fe7084846040518363ffffffff1660e01b8152600401610de992919061217c565b5f604051808303815f87803b158015610e00575f5ffd5b505af1158015610e12573d5f5f3e3d5ffd5b5050505050505050565b5f610e25610468565b6001019050610e3d84826112c990919063ffffffff16565b8373ffffffffffffffffffffffffffffffffffffffff16636d61fe7084846040518363ffffffff1660e01b8152600401610e7892919061217c565b5f604051808303815f87803b158015610e8f575f5ffd5b505af1158015610ea1573d5f5f3e3d5ffd5b5050505050505050565b5f610eb4610a3c565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610f2657806040517f741cbe03000000000000000000000000000000000000000000000000000000008152600401610f1d919061175e565b60405180910390fd5b610f2f84611599565b8373ffffffffffffffffffffffffffffffffffffffff16636d61fe7084846040518363ffffffff1660e01b8152600401610f6a92919061217c565b5f604051808303815f87803b158015610f81575f5ffd5b505af1158015610f93573d5f5f3e3d5ffd5b5050505050505050565b5f82825f90600492610fb1939291906121a6565b90610fbc91906121f6565b90505f83836004818110610fd357610fd2611f8f565b5b9050013560f81c60f81b90505f84846005908092610ff3939291906121a6565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050509050611040836115c6565b15611080576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611077906122ae565b60405180910390fd5b60405180604001604052808773ffffffffffffffffffffffffffffffffffffffff168152602001837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152506110d5610468565b6002015f857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151815f0160146101000a81548160ff021916908360f81c02179055509050508573ffffffffffffffffffffffffffffffffffffffff16636d61fe70826040518263ffffffff1660e01b81526004016111c59190611952565b5f604051808303815f87803b1580156111dc575f5ffd5b505af11580156111ee573d5f5f3e3d5ffd5b50505050505050505050565b5f8173ffffffffffffffffffffffffffffffffffffffff16600173ffffffffffffffffffffffffffffffffffffffff16141580156112c157505f73ffffffffffffffffffffffffffffffffffffffff16835f015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16148061132f5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b1561137157806040517f7c84ecfb000000000000000000000000000000000000000000000000000000008152600401611368919061175e565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16825f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461143e57806040517f40d3d1a4000000000000000000000000000000000000000000000000000000008152600401611435919061175e565b60405180910390fd5b815f015f600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16825f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080825f015f600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b5f7fcd97a6611018468306afd07ac8b14141bc76df8b844b3bcba1768d81e45982005f1b90508181555050565b5f5f6115d0610468565b6002015f847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f2090505f73ffffffffffffffffffffffffffffffffffffffff16815f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415915050919050565b60405180604001604052805f73ffffffffffffffffffffffffffffffffffffffff1681526020015f7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681525090565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b611700816116cc565b82525050565b5f6020820190506117195f8301846116f7565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6117488261171f565b9050919050565b6117588161173e565b82525050565b5f6020820190506117715f83018461174f565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f8401126117a05761179f61177f565b5b8235905067ffffffffffffffff8111156117bd576117bc611783565b5b6020830191508360208202830111156117d9576117d8611787565b5b9250929050565b5f5ffd5b5f604082840312156117f9576117f86117e0565b5b81905092915050565b5f5f5f5f5f5f5f6080888a03121561181d5761181c611777565b5b5f88013567ffffffffffffffff81111561183a5761183961177b565b5b6118468a828b0161178b565b9750975050602088013567ffffffffffffffff8111156118695761186861177b565b5b6118758a828b0161178b565b9550955050604088013567ffffffffffffffff8111156118985761189761177b565b5b6118a48a828b016117e4565b935050606088013567ffffffffffffffff8111156118c5576118c461177b565b5b6118d18a828b0161178b565b925092505092959891949750929550565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f611924826118e2565b61192e81856118ec565b935061193e8185602086016118fc565b6119478161190a565b840191505092915050565b5f6020820190508181035f83015261196a818461191a565b905092915050565b61197b8161173e565b8114611985575f5ffd5b50565b5f8135905061199681611972565b92915050565b5f819050919050565b6119ae8161199c565b81146119b8575f5ffd5b50565b5f813590506119c9816119a5565b92915050565b5f5f604083850312156119e5576119e4611777565b5b5f6119f285828601611988565b9250506020611a03858286016119bb565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b611a3f8161173e565b82525050565b5f611a508383611a36565b60208301905092915050565b5f602082019050919050565b5f611a7282611a0d565b611a7c8185611a17565b9350611a8783611a27565b805f5b83811015611ab7578151611a9e8882611a45565b9750611aa983611a5c565b925050600181019050611a8a565b5085935050505092915050565b5f6040820190508181035f830152611adc8185611a68565b9050611aeb602083018461174f565b9392505050565b5f611afc8261173e565b9050919050565b611b0c81611af2565b8114611b16575f5ffd5b50565b5f81359050611b2781611b03565b92915050565b5f5f83601f840112611b4257611b4161177f565b5b8235905067ffffffffffffffff811115611b5f57611b5e611783565b5b602083019150836001820283011115611b7b57611b7a611787565b5b9250929050565b5f5f5f60408486031215611b9957611b98611777565b5b5f611ba686828701611b19565b935050602084013567ffffffffffffffff811115611bc757611bc661177b565b5b611bd386828701611b2d565b92509250509250925092565b611be8816116cc565b8114611bf2575f5ffd5b50565b5f81359050611c0381611bdf565b92915050565b5f60208284031215611c1e57611c1d611777565b5b5f611c2b84828501611bf5565b91505092915050565b5f7fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b5f611c6982611c34565b9050919050565b611c7981611c5f565b82525050565b604082015f820151611c935f850182611a36565b506020820151611ca66020850182611c70565b50505050565b5f604082019050611cbf5f830184611c7f565b92915050565b5f82825260208201905092915050565b5f819050919050565b5f611cec6020840184611988565b905092915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83356001602003843603038112611d1c57611d1b611cfc565b5b83810192508235915060208301925067ffffffffffffffff821115611d4457611d43611cf4565b5b600182023603831315611d5a57611d59611cf8565b5b509250929050565b5f82825260208201905092915050565b828183375f83830152505050565b5f611d8b8385611d62565b9350611d98838584611d72565b611da18361190a565b840190509392505050565b5f60408301611dbd5f840184611cde565b611dc95f860182611a36565b50611dd76020840184611d00565b8583036020870152611dea838284611d80565b925050508091505092915050565b5f611e038383611dac565b905092915050565b5f82356001604003833603038112611e2657611e25611cfc565b5b82810191505092915050565b5f602082019050919050565b5f611e498385611cc5565b935083602084028501611e5b84611cd5565b805f5b87811015611e9e578484038952611e758284611e0b565b611e7f8582611df8565b9450611e8a83611e32565b925060208a01995050600181019050611e5e565b50829750879450505050509392505050565b5f60408301611ec15f840184611cde565b611ecd5f860182611a36565b50611edb6020840184611d00565b8583036020870152611eee838284611d80565b925050508091505092915050565b5f6080820190508181035f830152611f1581898b611e3e565b90508181036020830152611f2a818789611e3e565b90508181036040830152611f3e8186611eb0565b90508181036060830152611f53818486611e3e565b905098975050505050505050565b5f604082019050611f745f83018561174f565b8181036020830152611f86818461191a565b90509392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f82356001604003833603038112611fe357611fe2611fbc565b5b80830191505092915050565b5f6020828403121561200457612003611777565b5b5f61201184828501611988565b91505092915050565b5f5f8335600160200384360303811261203657612035611fbc565b5b80840192508235915067ffffffffffffffff82111561205857612057611fc0565b5b60208301925060018202360383131561207457612073611fc4565b5b509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6120e08261199c565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612112576121116120a9565b5b600182019050919050565b5f6121278261199c565b91506121328361199c565b925082820390508181111561214a576121496120a9565b5b92915050565b5f61215b83856118ec565b9350612168838584611d72565b6121718361190a565b840190509392505050565b5f6020820190508181035f830152612195818486612150565b90509392505050565b5f5ffd5b5f5ffd5b5f5f858511156121b9576121b861219e565b5b838611156121ca576121c96121a2565b5b6001850283019150848603905094509492505050565b5f82905092915050565b5f82821b905092915050565b5f61220183836121e0565b8261220c81356116cc565b9250600482101561224c576122477fffffffff00000000000000000000000000000000000000000000000000000000836004036008026121ea565b831692505b505092915050565b5f82825260208201905092915050565b7f46756e6374696f6e2073656c6563746f7220616c7265616479207573656400005f82015250565b5f612298601e83612254565b91506122a382612264565b602082019050919050565b5f6020820190508181035f8301526122c58161228c565b905091905056fea2646970667358221220b90741b9c42163f6c8d87ffeafdf59adca32d114497979a80f2aabbe52604d3764736f6c634300081c0033"; - bytes public constant ERC7579_RHINESTONE_TRAMPOLOINE_BYTECODE = - hex"6080604052348015600e575f5ffd5b5061081d8061001c5f395ff3fe608060405260043610610058575f3560e01c80630a664dba146101b55780635faac46b146101e6578063b0d691fe14610213578063e1c7392a14610235578063ea5f61d014610249578063eac9b20d146102685761005f565b3661005f57005b5f3560e01c63bc197c81811463f23a6e6182141763150b7a028214171561008a57806020526020603cf35b505f80356001600160e01b03191681527ff88ce1fdb7fb1cbd3282e49729100fa3f2d6ee9f797961fe4fb1871cea89ea046020526040902080546001600160a01b03811690600160a01b900460f81b8161010957604051632464e76d60e11b81526001600160e01b03195f351660048201526024015b60405180910390fd5b61011781607f60f91b61032e565b156101685760408051368101909152365f823760408051601481019091523360601b90525f803660140183865afa90506101573d60408051918201905290565b3d5f823e81610164573d81fd5b3d81f35b610172815f61032e565b156101b35760408051368101909152365f823760408051601481019091523360601b90525f80366014018382875af190506101573d60408051918201905290565b005b3480156101c0575f5ffd5b506101c9610345565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101f1575f5ffd5b5061020561020036600461068d565b610373565b6040516101dd9291906106c2565b34801561021e575f5ffd5b506f71727de22e5e9d8baf0edac6f37da0326101c9565b348015610240575f5ffd5b506101b36103ae565b348015610254575f5ffd5b5061020561026336600461068d565b610480565b348015610273575f5ffd5b50610300610282366004610724565b6040805180820182525f80825260209182018190526001600160e01b03199390931683527ff88ce1fdb7fb1cbd3282e49729100fa3f2d6ee9f797961fe4fb1871cea89ea048152918190208151808301909252546001600160a01b0381168252600160a01b900460f81b6001600160f81b0319169181019190915290565b6040805182516001600160a01b031681526020928301516001600160f81b03191692810192909252016101dd565b6001600160f81b0319828116908216145b92915050565b5f61036e7f36e05829dd1b9a4411d96a3549582172d7f071c1c0db5c573fcf94eb284316085490565b905090565b60605f7ff88ce1fdb7fb1cbd3282e49729100fa3f2d6ee9f797961fe4fb1871cea89ea026103a28186866104ab565b92509250509250929050565b6103ea7334dedac925c00d63bd91800ff821e535fe59d6f57f36e05829dd1b9a4411d96a3549582172d7f071c1c0db5c573fcf94eb2843160855565b60408051737066f491ce8b5f782f315dfbd549f2107a32641360611b60208201528151601481830301815260348201928390526306d61fe760e41b9092527334dedac925c00d63bd91800ff821e535fe59d6f591636d61fe7091610451919060380161074b565b5f604051808303815f87803b158015610468575f5ffd5b505af115801561047a573d5f5f3e3d5ffd5b50505050565b60605f7ff88ce1fdb7fb1cbd3282e49729100fa3f2d6ee9f797961fe4fb1871cea89ea036103a28186865b60605f6001600160a01b0384166001148015906104cf57506104cd8585610653565b155b156104f857604051637c84ecfb60e01b81526001600160a01b0385166004820152602401610100565b825f036105185760405163f725081760e01b815260040160405180910390fd5b8267ffffffffffffffff81111561053157610531610780565b60405190808252806020026020018201604052801561055a578160200160208202803683370190505b506001600160a01b038086165f90815260208890526040812054929450911691505b6001600160a01b0382161580159061059e57506001600160a01b038216600114155b80156105a957508381105b1561060257818382815181106105c1576105c1610794565b6001600160a01b039283166020918202929092018101919091529281165f9081529287905260409092205490911690806105fa816107bc565b91505061057c565b6001600160a01b03821660011480159061061b57505f81115b15610647578261062c6001836107d4565b8151811061063c5761063c610794565b602002602001015191505b80835250935093915050565b5f60016001600160a01b0383161480159061068657506001600160a01b038281165f908152602085905260409020541615155b9392505050565b5f5f6040838503121561069e575f5ffd5b82356001600160a01b03811681146106b4575f5ffd5b946020939093013593505050565b604080825283519082018190525f9060208501906060840190835b818110156107045783516001600160a01b03168352602093840193909201916001016106dd565b50506001600160a01b039490941660209390930192909252509092915050565b5f60208284031215610734575f5ffd5b81356001600160e01b031981168114610686575f5ffd5b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f600182016107cd576107cd6107a8565b5060010190565b8181038181111561033f5761033f6107a856fea26469706673582212208b8d179eb9f1d514092184d86650903af803b01f367d0d2440620538d93230ac64736f6c634300081b0033"; - bytes public constant MSAPROXY_BYTECODE = - hex"60806040526040516107983803806107988339818101604052810190610025919061054b565b61003361004a60201b60201c565b61004382826100af60201b60201c565b50506106b8565b5f60ff5f1b1960017ff63b257b7881773a84d328ab92140e19ab791f7b439c76ba9837aa0d6ad30af05f1c61007f91906105db565b60405160200161008f919061061d565b604051602081830303815290604052805190602001201690506001815d50565b6100be8261013360201b60201c565b8173ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a25f815111156101205761011a828261020260201b60201c565b5061012f565b61012e61028860201b60201c565b5b5050565b5f8173ffffffffffffffffffffffffffffffffffffffff163b0361018e57806040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526004016101859190610645565b60405180910390fd5b806101c07f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5f1b6102c460201b60201c565b5f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60605f5f8473ffffffffffffffffffffffffffffffffffffffff168460405161022b91906106a2565b5f60405180830381855af49150503d805f8114610263576040519150601f19603f3d011682016040523d82523d5f602084013e610268565b606091505b509150915061027e8583836102cd60201b60201c565b9250505092915050565b5f3411156102c2576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f819050919050565b6060826102e8576102e38261036060201b60201c565b610358565b5f825114801561030e57505f8473ffffffffffffffffffffffffffffffffffffffff163b145b1561035057836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016103479190610645565b60405180910390fd5b819050610359565b5b9392505050565b5f815111156103725780518082602001fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f604051905090565b5f5ffd5b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6103de826103b5565b9050919050565b6103ee816103d4565b81146103f8575f5ffd5b50565b5f81519050610409816103e5565b92915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61045d82610417565b810181811067ffffffffffffffff8211171561047c5761047b610427565b5b80604052505050565b5f61048e6103a4565b905061049a8282610454565b919050565b5f67ffffffffffffffff8211156104b9576104b8610427565b5b6104c282610417565b9050602081019050919050565b8281835e5f83830152505050565b5f6104ef6104ea8461049f565b610485565b90508281526020810184848401111561050b5761050a610413565b5b6105168482856104cf565b509392505050565b5f82601f8301126105325761053161040f565b5b81516105428482602086016104dd565b91505092915050565b5f5f60408385031215610561576105606103ad565b5b5f61056e858286016103fb565b925050602083015167ffffffffffffffff81111561058f5761058e6103b1565b5b61059b8582860161051e565b9150509250929050565b5f819050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6105e5826105a5565b91506105f0836105a5565b9250828203905081811115610608576106076105ae565b5b92915050565b610617816105a5565b82525050565b5f6020820190506106305f83018461060e565b92915050565b61063f816103d4565b82525050565b5f6020820190506106585f830184610636565b92915050565b5f81519050919050565b5f81905092915050565b5f61067c8261065e565b6106868185610668565b93506106968185602086016104cf565b80840191505092915050565b5f6106ad8284610672565b915081905092915050565b60d4806106c45f395ff3fe6080604052600a600c565b005b60186014601a565b6026565b565b5f60216044565b905090565b365f5f375f5f365f845af43d5f5f3e805f81146040573d5ff35b3d5ffd5b5f606e7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5f1b6095565b5f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b5f81905091905056fea2646970667358221220c1de7109ed587fe9e758c24d4d24494182d4b6d7c4bdda4e7a5f1fea44ff709564736f6c634300081c0033"; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/KernelPrecompiles.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/KernelPrecompiles.sol deleted file mode 100644 index 5bb8cf0..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/KernelPrecompiles.sol +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IKernel } from "../../accounts/kernel/interfaces/IKernel.sol"; -import { IKernelFactory } from "../../accounts/kernel/interfaces/IKernelFactory.sol"; - -// Types -import { ValidationId } from "../../accounts/kernel/types/Types.sol"; - -// Utils -import { label } from "../../test/utils/Vm.sol"; -import { BytecodeDeployer } from "./BytecodeDeployer.sol"; - -interface ISetSelector is IKernel { - function setSelector(ValidationId vId, bytes4 selector, bool allowed) external; -} - -/// @notice Precompiled Kernel contracts -contract KernelPrecompiles is BytecodeDeployer { - /*////////////////////////////////////////////////////////////// - DEPLOY - //////////////////////////////////////////////////////////////*/ - - function deployKernel(address entrypoint) internal returns (IKernel kernel) { - // Concat constructor params to bytecode - bytes memory creationBytecode = bytes.concat(KERNEL_BYTECODE, abi.encode(entrypoint)); - kernel = IKernel(_deploy(creationBytecode)); - label(address(kernel), "Kernel"); - } - - function deployKernelWithSetSelector(address entrypoint) - internal - returns (ISetSelector kernel) - { - // Concat constructor params to bytecode - bytes memory creationBytecode = - bytes.concat(KERNEL_WITH_SETSELECTOR_BYTECODE, abi.encode(entrypoint)); - kernel = ISetSelector(_deploy(creationBytecode)); - label(address(kernel), "SetSelector"); - } - - function deployKernelFactory(address kernelImpl) - internal - returns (IKernelFactory kernelFactory) - { - // Concat constructor params to bytecode - bytes memory creationBytecode = - bytes.concat(KERNEL_FACTORY_BYTECODE, abi.encode(kernelImpl)); - kernelFactory = IKernelFactory(_deploy(creationBytecode)); - label(address(kernelFactory), "KernelFactory"); - } - - /*////////////////////////////////////////////////////////////// - BYTECODES - //////////////////////////////////////////////////////////////*/ - - /* solhint-disable max-line-length */ - bytes public constant KERNEL_BYTECODE = - hex"61014060405234801561001157600080fd5b506040516172093803806172098339810160408190526100309161015a565b306080524660a05260608061007a604080518082018252600681526512d95c9b995b60d21b60208083019190915282518084019093526005835264302e332e3160d81b9083015291565b815160209283012081519183019190912060c082905260e0819052604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8152808501939093528281019190915246606083015230608083015260a0909120610100526001600160a01b03851661012052805163deadbeef60e01b92810192909252805160048184030181526024909201905261011b9250905061018a565b7f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f80546001600160a81b03191660589290921c919091179055506101c8565b60006020828403121561016c57600080fd5b81516001600160a01b038116811461018357600080fd5b9392505050565b805160208201516001600160581b03198116919060158210156101c1576001600160581b0319601583900360031b81901b82161692505b5050919050565b60805160a05160c05160e0516101005161012051616fa5610264600039600081816102ef0152818161069401528181610cb701528181610fec015281816111b6015281816115a301528181611a7101528181611b9501528181611d590152818161253901528181612e6b015261303c0152600061465b01526000614715015260006146ef0152600061469f0152600061467c0152616fa56000f3fe6080604052600436106101d15760003560e01c80639517e29f116100f7578063c3e5897811610095578063e9ae5c5311610064578063e9ae5c53146107ef578063f1f7f0f914610802578063f23a6e6114610830578063f2dc691d1461085d57610210565b8063c3e589781461076f578063d03c79141461079c578063d691c964146107bc578063e6f3d50a146107dc57610210565b8063a71763a8116100d1578063a71763a8146106ce578063adb610a3146106e1578063b8afe17d146106f6578063bc197c811461074057610210565b80639517e29f1461062a5780639cfd7cff1461063d578063a65d69d41461068257610210565b806352141cd91161016f57806384b0196e1161013e57806384b0196e146105b25780638dd7712f146105da57806390ef8862146105ed5780639198bdf51461061757610210565b806352141cd9146104ed57806357b3a5f4146105005780636e6fa0c61461055a578063721e67f41461057a57610210565b806319822f7c116101ab57806319822f7c146104845780631f1b92e3146104a55780633659cfe6146104ba5780633c3b752b146104cd57610210565b8063112d3a7d146103ea578063150b7a021461041f5780631626ba7e1461046457610210565b3661021057604080513381523460208201527f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f88525874910160405180910390a1005b60006102276000356001600160e01b03191661087d565b604080516060808201835283546001600160a01b039081168084526001909501549081166020840152600160a01b900460f81b6001600160f81b03191692820192909252925060009161028d57604051631cd4b64760e21b815260040160405180910390fd5b82516060906001600160a01b03166001148015906102b6575083516001600160a01b0390811614155b156102d15783516102ca90346000366108b7565b905061032d565b83516001600160a01b03908116900361032d57336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461032d576040516348f5c3ed60e01b815260040160405180910390fd5b604084015161033d90600061093c565b156103595761034f8460200151610953565b909350915061039e565b6040840151610370906001600160f81b031961093c565b156103855761034f84602001516000366109a3565b604051632d6a6bb760e01b815260040160405180910390fd5b826103ab57815160208301fd5b83516001600160a01b03166001148015906103d1575083516001600160a01b0390811614155b156103e25783516103e290826109d2565b815160208301f35b3480156103f657600080fd5b5061040a610405366004615f19565b610a34565b60405190151581526020015b60405180910390f35b34801561042b57600080fd5b5061044b61043a366004615f74565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001610416565b34801561047057600080fd5b5061044b61047f366004615fe6565b610b09565b61049761049236600461604a565b610caa565b604051908152602001610416565b6104b86104b33660046160ab565b610fc5565b005b6104b86104c83660046160c6565b61119c565b3480156104d957600080fd5b506104b86104e836600461613f565b6113b5565b6104b86104fb366004616205565b611589565b34801561050c57600080fd5b5061052061051b3660046162b1565b61191e565b6040805182516001600160a01b03908116825260208085015190911690820152918101516001600160f81b03191690820152606001610416565b34801561056657600080fd5b5061040a6105753660046162ce565b61198a565b34801561058657600080fd5b5061059a6105953660046160c6565b6119d2565b60405190516001600160a01b03168152602001610416565b3480156105be57600080fd5b506105c7611a08565b6040516104169796959493929190616355565b6104b86105e83660046163ed565b611a66565b3480156105f957600080fd5b50610602611b5e565b60405163ffffffff9091168152602001610416565b6104b86106253660046164c2565b611b7b565b6104b8610638366004615f19565b611d3f565b34801561064957600080fd5b5060408051808201825260168152756b65726e656c2e616476616e6365642e76302e332e3160501b60208201529051610416919061663d565b34801561068e57600080fd5b506106b67f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610416565b6104b86106dc366004615f19565b61251f565b3480156106ed57600080fd5b50610602612b78565b34801561070257600080fd5b50610716610711366004616650565b612b95565b60408051825163ffffffff1681526020928301516001600160a01b03169281019290925201610416565b34801561074c57600080fd5b5061044b61075b36600461666b565b63bc197c8160e01b98975050505050505050565b34801561077b57600080fd5b5061078f61078a3660046162b1565b612bfd565b604051610416919061671f565b3480156107a857600080fd5b5061040a6107b73660046167a2565b612cd9565b6107cf6107ca366004615fe6565b612dc6565b60405161041691906167bb565b6104b86107ea366004616820565b612e51565b6104b86107fd366004615fe6565b613022565b34801561080e57600080fd5b506108176131db565b6040516001600160581b03199091168152602001610416565b34801561083c57600080fd5b5061044b61084b366004616887565b63f23a6e6160e01b9695505050505050565b34801561086957600080fd5b5061040a6108783660046167a2565b6131ee565b6001600160e01b03191660009081527f7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b6020526040902090565b60405163d68f602560e01b81526060906001600160a01b0386169063d68f6025906108ec90339088908890889060040161690d565b6000604051808303816000875af115801561090b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109339190810190616966565b95945050505050565b6001600160f81b0319828116908216145b92915050565b6000606060408051368101909152366000823760408051601481019091523360601b9052600080366014018382885af192505060405190503d8152602081013d6000823e3d810160405250915091565b604051600090828482376000388483885af491503d8152602081013d6000823e3d810160405250935093915050565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906109fe90849060040161663d565b600060405180830381600087803b158015610a1857600080fd5b505af1158015610a2c573d6000803e3d6000fd5b505050505050565b600060018503610a91576000610a4861320e565b6001016000610a5d8760581b600160f81b1790565b6001600160581b0319168152602081019190915260400160002054600160201b90046001600160a01b031614159050610b01565b60028503610ab7576000610aa485613232565b546001600160a01b031614159050610b01565b60038503610afd576001600160a01b038416610ae8610ada6004600086886169d8565b610ae391616a02565b61087d565b600101546001600160a01b0316149050610b01565b5060005b949350505050565b600080610b1461320e565b90506000366000610b25878761326b565b925092509250610b3c610b358490565b600061093c565b15610b4957835460581b92505b6001600160581b031983166000908152600185016020526040902054600160201b90046001600160a01b0316610b9257604051631a0a9b9f60e21b815260040160405180910390fd5b610ba083600160f81b61093c565b15610c3a576000610bb18460581c90565b9050806001600160a01b031663f551e2ee33610bcc8c6132d8565b86866040518563ffffffff1660e01b8152600401610bed949392919061690d565b602060405180830381865afa158015610c0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2e9190616a3a565b95505050505050610ca3565b6000610c468460081b90565b6001600160e01b03198116600090815260038701602052604090205490915060f01b600160f11b811615610c8d57604051635b71057960e01b815260040160405180910390fd5b610c9a82338c878761332e565b96505050505050505b9392505050565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610cf5576040516348f5c3ed60e01b815260040160405180910390fd5b6000610cff61320e565b90506000806000610d13886020013561342c565b91945092509050610d2582600061093c565b15610d315750825460581b5b610d3d83828a8a61345a565b6001600160581b031982166000908152600186016020908152604080832081518083019092525463ffffffff81168252600160201b90046001600160a01b031691810191909152919650610d92908490613656565b8015610db057508454815163ffffffff600160c81b90920482169116105b15610dce57604051633ab3447f60e11b815260040160405180910390fd5b60208101516001600160a01b038116610dfa57604051631a0a9b9f60e21b815260040160405180910390fd5b600089815260208190526040902080546001600160a01b0319166001600160a01b03831690811790915560001901610ec257610e37846000613656565b8015610e9f57506001600160581b031983166000908152600287016020526040812090610e6760608d018d616a57565b610e76916004916000916169d8565b610e7f91616a02565b6001600160e01b031916815260208101919091526040016000205460ff16155b15610ebd57604051631a0a9b9f60e21b815260040160405180910390fd5b610fa8565b610ecd846000613656565b8015610f3557506001600160581b031983166000908152600287016020526040812090610efd60608d018d616a57565b610f0c916008916004916169d8565b610f1591616a02565b6001600160e01b031916815260208101919091526040016000205460ff16155b15610f5357604051631a0a9b9f60e21b815260040160405180910390fd5b638dd7712f60e01b610f6860608c018c616a57565b610f77916004916000916169d8565b610f8091616a02565b6001600160e01b03191614610fa85760405163dbbb044b60e01b815260040160405180910390fd5b8715610fb857343434348b335af1505b5050505050509392505050565b6000610fdf610fd261320e565b546001600160a81b031690565b9050336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480159061101a5750333014155b1561118f5760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015611063573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110879190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f6025906110c190339034908690369060040161690d565b6000604051808303816000875af11580156110e0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111089190810190616966565b905061111383613669565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061113f90849060040161663d565b600060405180830381600087803b15801561115957600080fd5b505af115801561116d573d6000803e3d6000fd5b50505050505050565b6040516348f5c3ed60e01b815260040160405180910390fd5b61119882613669565b5050565b60006111a9610fd261320e565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015906111e45750333014155b156113595760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa15801561122d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112519190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f60259061128b90339034908690369060040161690d565b6000604051808303816000875af11580156112aa573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112d29190810190616966565b9050827f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55826001600160a01b03167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a2604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061113f90849060040161663d565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8290556040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a25050565b60006113bf61320e565b805490915060581b6001600160581b031916156114195760405162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b60448201526064015b60405180910390fd5b6001600160581b0319891661144157604051631a0a9b9f60e21b815260040160405180910390fd5b8861145081600160f81b613656565b8015611465575061146581600160f91b613656565b15611483576040516361c4e91b60e11b815260040160405180910390fd5b61148c8a61374b565b60408051808201909152600181526001600160a01b038a166020820152825463ffffffff60a81b1916600160a81b1783556114cb8b828b8b8b8b6137ad565b60005b8481101561157b576000308787848181106114eb576114eb616abf565b90506020028101906114fd9190616a57565b60405161150b929190616ad5565b6000604051808303816000865af19150503d8060008114611548576040519150601f19603f3d011682016040523d82523d6000602084013e61154d565b606091505b505090508061157257604051636534eae560e11b815260048101839052602401611410565b506001016114ce565b505050505050505050505050565b6000611596610fd261320e565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015906115d15750333014155b1561181d5760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa15801561161a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163e9190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f60259061167890339034908690369060040161690d565b6000604051808303816000875af1158015611697573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116bf9190810190616966565b905060006116cb61320e565b90506001600160581b031989166116f557604051631a0a9b9f60e21b815260040160405180910390fd5b8861170481600160f81b613656565b8015611719575061171981600160f91b613656565b15611737576040516361c4e91b60e11b815260040160405180910390fd5b6117408a61374b565b600061174a61320e565b6001600160581b03198c1660009081526001919091016020526040902054600160201b90046001600160a01b0316036117b757604080518082019091528254600160a81b900463ffffffff1681526001600160a01b038a1660208201526117b58b828b8b8b8b6137ad565b505b5050604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906117e590849060040161663d565b600060405180830381600087803b1580156117ff57600080fd5b505af1158015611813573d6000803e3d6000fd5b505050505061116d565b600061182761320e565b90506001600160581b0319881661185157604051631a0a9b9f60e21b815260040160405180910390fd5b8761186081600160f81b613656565b8015611875575061187581600160f91b613656565b15611893576040516361c4e91b60e11b815260040160405180910390fd5b61189c8961374b565b60006118a661320e565b6001600160581b03198b1660009081526001919091016020526040902054600160201b90046001600160a01b03160361191357604080518082019091528254600160a81b900463ffffffff1681526001600160a01b03891660208201526119118a828a8a8a8a6137ad565b505b505050505050505050565b60408051606081018252600080825260208201819052918101919091526119448261087d565b6040805160608101825282546001600160a01b0390811682526001909301549283166020820152600160a01b90920460f81b6001600160f81b0319169082015292915050565b600061199461320e565b6001600160581b031984166000908152600291909101602090815260408083206001600160e01b03198616845290915290205460ff16905092915050565b6040805160208101909152600081526119ea82613232565b604080516020810190915290546001600160a01b0316815292915050565b600f60f81b6060806000808083611a54604080518082018252600681526512d95c9b995b60d21b60208083019190915282518084019093526005835264302e332e3160d81b9083015291565b97989097965046955030945091925090565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611aaf576040516348f5c3ed60e01b815260040160405180910390fd5b6000818152602081905260409020546060906001600160a01b031660018114611afa57611af78134611ae46060880188616a57565b611af29160049082906169d8565b6108b7565b91505b600080611b2130611b0e6060890189616a57565b611b1c9160049082906169d8565b6109a3565b9150915081611b435760405163f21e646b60e01b815260040160405180910390fd5b6001600160a01b038316600114610a2c57610a2c83856109d2565b6000611b6861320e565b54600160c81b900463ffffffff16919050565b6000611b88610fd261320e565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801590611bc35750333014155b15611d265760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015611c0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c309190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f602590611c6a90339034908690369060040161690d565b6000604051808303816000875af1158015611c89573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611cb19190810190616966565b9050611cc2898989898989896139fc565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da90611cee90849060040161663d565b600060405180830381600087803b158015611d0857600080fd5b505af1158015611d1c573d6000803e3d6000fd5b5050505050611d35565b611d35888888888888886139fc565b5050505050505050565b6000611d4c610fd261320e565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801590611d875750333014155b156122265760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015611dd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df49190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f602590611e2e90339034908690369060040161690d565b6000604051808303816000875af1158015611e4d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e759190810190616966565b905060018603611fb2576000611e8961320e565b90506000611e9d8760581b600160f81b1790565b82546001600160581b03198216600090815260018501602052604090205491925063ffffffff600160a81b9091048116911603611efd578154600163ffffffff600160a81b808404821692909201160263ffffffff60a81b199091161782555b604080518082019091528254600160a81b900463ffffffff16815260009060208101611f2c6014848a8c6169d8565b611f3591616ae5565b60601c9052905060148781013588016034818101929182013591818b01358b0180830192908201359160548d01358d01918201910135611f798888888888886137ad565b6004819003611fa457611fa488611f946004600085876169d8565b611f9d91616a02565b6001613aa0565b5050505050505050506121c2565b6002860361201957601484810135850160348181019291820135918188013588019182019181013590600090611fea90828a8c6169d8565b611ff391616ae5565b60601c90506120048a868684613b33565b61200f818484613b99565b50505050506121c2565b600386036120a9576018848101358501603881810192918201359181880135880191820191013561207c612051600460008a8c6169d8565b61205a91616a02565b8a612069601860048c8e6169d8565b61207291616ae5565b60601c8787613d6a565b6120a061208d601860048a8c6169d8565b61209691616ae5565b60601c8383613b99565b505050506121c2565b6004860361213d576040516306d61fe760e41b81526001600160a01b03861690636d61fe70906120df9087908790600401616b25565b600060405180830381600087803b1580156120f957600080fd5b505af115801561210d573d6000803e3d6000fd5b50505050600080516020616f658339815191528686604051612130929190616b39565b60405180910390a16121c2565b60058603612173576040516306d61fe760e41b81526001600160a01b03861690636d61fe70906120df9087908790600401616b25565b600686036121a9576040516306d61fe760e41b81526001600160a01b03861690636d61fe70906120df9087908790600401616b25565b604051631092ef5760e11b815260040160405180910390fd5b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906121ee90849060040161663d565b600060405180830381600087803b15801561220857600080fd5b505af115801561221c573d6000803e3d6000fd5b5050505050612518565b6001850361235157600061223861320e565b9050600061224c8660581b600160f81b1790565b82546001600160581b03198216600090815260018501602052604090205491925063ffffffff600160a81b90910481169116036122ac578154600163ffffffff600160a81b808404821692909201160263ffffffff60a81b199091161782555b604080518082019091528254600160a81b900463ffffffff168152600090602081016122db601484898b6169d8565b6122e491616ae5565b60601c9052905060148681013587016034818101929182013591818a01358a0180830192908201359160548c01358c019182019101356123288888888888886137ad565b60048190036123435761234388611f946004600085876169d8565b505050505050505050612518565b600285036123ae576014838101358401603481810192918201359181870135870191820191810135906000906123899082898b6169d8565b61239291616ae5565b60601c90506123a389868684613b33565b61221c818484613b99565b6003850361241857601883810135840160388181019291820135918187013587019182019101356123fe6123e660046000898b6169d8565b6123ef91616a02565b89612069601860048b8d6169d8565b61240f61208d60186004898b6169d8565b50505050612518565b600485036124ac576040516306d61fe760e41b81526001600160a01b03851690636d61fe709061244e9086908690600401616b25565b600060405180830381600087803b15801561246857600080fd5b505af115801561247c573d6000803e3d6000fd5b50505050600080516020616f65833981519152858560405161249f929190616b39565b60405180910390a1612518565b600585036124e2576040516306d61fe760e41b81526001600160a01b03851690636d61fe709061244e9086908690600401616b25565b600685036121a9576040516306d61fe760e41b81526001600160a01b03851690636d61fe709061244e9086908690600401616b25565b5050505050565b600061252c610fd261320e565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015906125675750333014155b156128ed5760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa1580156125b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d49190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f60259061260e90339034908690369060040161690d565b6000604051808303816000875af115801561262d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126559190810190616966565b9050856001036126855760006126718660581b600160f81b1790565b905061267e818686613edb565b50506121c2565b8560020361269e5761269885858561401f565b506121c2565b856003036126d65760006126b560048286886169d8565b6126be91616a02565b905061267e816126d1866004818a6169d8565b6140bb565b856004036127f35760006126e861320e565b5460581b90506001600160a01b03861661270061320e565b6001600160581b0319831660009081526001919091016020526040902054600160201b90046001600160a01b03160361278557600161273d61320e565b6001600160581b0319831660009081526001919091016020526040902080546001600160a01b0392909216600160201b02640100000000600160c01b03199092169190911790555b6127c58686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141a192505050565b50600080516020616f8583398151915287876040516127e5929190616b39565b60405180910390a1506121c2565b856005036128db57600061280561320e565b5460581b9050600061281a60208287896169d8565b61282391616b50565b9050612834825b600160f91b61093c565b1561286c576128438260081b90565b6001600160e01b031916810361286c576040516313002bdd60e31b815260040160405180910390fd5b6128ac8787878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141a192505050565b50600080516020616f8583398151915288886040516128cc929190616b39565b60405180910390a150506121c2565b856006036121a957600061280561320e565b8460010361291b5760006129078560581b600160f81b1790565b9050612914818585613edb565b5050612518565b846002036129345761292e84848461401f565b50612518565b8460030361296757600061294b60048285876169d8565b61295491616a02565b9050612914816126d185600481896169d8565b84600403612a8457600061297961320e565b5460581b90506001600160a01b03851661299161320e565b6001600160581b0319831660009081526001919091016020526040902054600160201b90046001600160a01b031603612a165760016129ce61320e565b6001600160581b0319831660009081526001919091016020526040902080546001600160a01b0392909216600160201b02640100000000600160c01b03199092169190911790555b612a568585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141a192505050565b50600080516020616f858339815191528686604051612a76929190616b39565b60405180910390a150612518565b84600503612b66576000612a9661320e565b5460581b90506000612aab60208286886169d8565b612ab491616b50565b9050612abf8261282a565b15612af757612ace8260081b90565b6001600160e01b0319168103612af7576040516313002bdd60e31b815260040160405180910390fd5b612b378686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141a192505050565b50600080516020616f858339815191528787604051612b57929190616b39565b60405180910390a15050612518565b846006036121a9576000612a9661320e565b6000612b8261320e565b54600160a81b900463ffffffff16919050565b6040805180820190915260008082526020820152612bb161320e565b6001600160581b03199290921660009081526001909201602090815260409283902083518085019094525463ffffffff81168452600160201b90046001600160a01b0316908301525090565b60408051606080820183526000808352602083015291810191909152612c2161320e565b6001600160e01b03198316600090815260039190910160209081526040918290208251606081018452815460f081901b6001600160f01b03191682526201000090046001600160a01b03168184015260018201805485518186028101860187528181529295939493860193830182828015612cc957602002820191906000526020600020905b815460501b6001600160501b0319168152600190910190602001808311612ca7575b5050505050815250509050919050565b600081600881901b603082901b605083901b612cf984600160f81b613656565b8015612d0b5750612d0b846000613656565b8015612d245750612d24846001600160f81b0319613656565b8015612d395750612d3984607f60f91b613656565b15612d4a5750600095945050505050565b6001600160f81b03198316600160f81b14801590612d7157506001600160f81b0319831615155b15612d825750600095945050505050565b6001600160e01b0319821615612d9e5750600095945050505050565b6001600160501b0319811615612dba5750600095945050505050565b50600195945050505050565b60606000612dd333613232565b546001600160a01b0316905080612dfd5760405163710c949760e01b815260040160405180910390fd5b60606001600160a01b038216600114612e2057612e1d82346000366108b7565b90505b612e2b868686614248565b92506001600160a01b038216600114612e4857612e4882826109d2565b50509392505050565b6000612e5e610fd261320e565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801590612e995750333014155b156130085760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015612ee2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f069190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f602590612f4090339034908690369060040161690d565b6000604051808303816000875af1158015612f5f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612f879190810190616966565b90506000612f96888888613edb565b9050612fa3818686614590565b50604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da90612fd090849060040161663d565b600060405180830381600087803b158015612fea57600080fd5b505af1158015612ffe573d6000803e3d6000fd5b5050505050610a2c565b6000613015878787613edb565b905061116d818585614590565b600061302f610fd261320e565b9050336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480159061306a5750333014155b156131ca5760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa1580156130b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130d79190616a9d565b156111765760405163d68f602560e01b81526000906001600160a01b0383169063d68f60259061311190339034908690369060040161690d565b6000604051808303816000875af1158015613130573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526131589190810190616966565b9050613165858585614248565b50604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061319290849060040161663d565b600060405180830381600087803b1580156131ac57600080fd5b505af11580156131c0573d6000803e3d6000fd5b50505050506131d5565b612518848484614248565b50505050565b60006131e561320e565b5460581b919050565b6000600782101561320157506001919050565b506000919050565b919050565b7f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f90565b6001600160a01b031660009081527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b866020526040902090565b813536600060f883901c801561329057600181146132a557600281146132b657600080fd5b600093506001860192506001850391506132d0565b6015860192506015850391506132d0565b6001600160d81b0319841693506005860192506005850391505b509250925092565b604080517f1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c83602082015290810182905260009061094d906060015b60405160208183030381529060405280519060200120614659565b60008060003660006133438a8a8a8a8a614771565b93509350935093506000806133578561487d565b50915091508165ffffffffffff1642108061337957508065ffffffffffff1642115b1561339557506001600160e01b03199550610933945050505050565b6001600160a01b03861663392dffaf6001600160e01b03198e168d6133b98e6132d8565b88886040518663ffffffff1660e01b81526004016133db959493929190616b6e565b602060405180830381865afa1580156133f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061341c9190616a3a565b9c9b505050505050505050505050565b80600881901b8060ff60f084901c166001198101613452576001600160d81b0319821691505b509193909250565b60008061346561320e565b9050600061347285616bf8565b9050366000613485610100880188616a57565b909250905061349889600160f81b61093c565b156134f6576134b4886134af6101008a018a616a57565b6148b0565b604080516020601f8401819004810282018101909252828152939850919450925083908390819084018382808284376000920191909152505050506101008401525b8761350581600160f81b61093c565b156135945761358d866135188b60581c90565b6001600160a01b03166397003203878b6040518363ffffffff1660e01b8152600401613545929190616d9b565b6020604051808303816000875af1158015613564573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135889190616dbd565b6148dd565b9550613649565b60006135a08a60081b90565b6001600160e01b03198116600090815260038801602052604090205490915060f01b600160f01b16156135e6576040516314b9743f60e01b815260040160405180910390fd5b6000806135f58388888861499b565b9150915061360389836148dd565b985061364389826001600160a01b0316630ccab7a1866001600160e01b0319168b8f6040518463ffffffff1660e01b815260040161354593929190616dd6565b98505050505b5050505050949350505050565b6001600160f81b03199081169116141590565b600061367361320e565b805490915063ffffffff8084169161369591600a91600160a81b900416616dff565b63ffffffff1610156136ba5760405163e60fd64760e01b815260040160405180910390fd5b805463ffffffff600160c81b9091048116908316116136ec57604051633ab3447f60e11b815260040160405180910390fd5b805463ffffffff60c81b1916600160c81b63ffffffff8481168202929092178084559081048216600160a81b909104909116101561119857805463ffffffff60a81b198116600160c81b90910463ffffffff16600160a81b0217905550565b600061375561320e565b80546001600160a81b031916605884901c1781556040516001600160581b0319841681529091507f6789ec0c85d6458d897a36a70129b101f8b4d84c6e218046c3107373dbcbae889060200160405180910390a15050565b60006137b761320e565b80546001600160581b03198916600090815260018301602052604090205491925063ffffffff600160a81b9091048116911603613817578054600163ffffffff600160a81b808404821692909201160263ffffffff60a81b199091161781555b60208601516001600160a01b031661383157600160208701525b85518154600160a81b900463ffffffff9081169116141580613879575085516001600160581b03198816600090815260018301602052604090205463ffffffff918216911610155b1561389757604051633ab3447f60e11b815260040160405180910390fd5b6001600160581b03198716600090815260018083016020908152604090922088518154938a01516001600160a01b0316600160201b81026001600160c01b031990951663ffffffff90921691909117939093179055146139005761390086602001518484613b99565b8661390f81600160f81b61093c565b156139b15760006139208960581c90565b6040516306d61fe760e41b81529091506001600160a01b03821690636d61fe7090613951908a908a90600401616b25565b600060405180830381600087803b15801561396b57600080fd5b505af115801561397f573d6000803e3d6000fd5b50505050600080516020616f658339815191526001826040516139a3929190616b39565b60405180910390a150611d35565b6139bf81600160f91b61093c565b156139e35760006139d08960081b90565b90506139dd818888614c7b565b50611d35565b6040516361c4e91b60e11b815260040160405180910390fd5b60005b86811015611d3557613a98888883818110613a1c57613a1c616abf565b9050602002016020810190613a319190616650565b878381518110613a4357613a43616abf565b6020026020010151878785818110613a5d57613a5d616abf565b9050602002810190613a6f9190616a57565b878787818110613a8157613a81616abf565b9050602002810190613a939190616a57565b6137ad565b6001016139ff565b6000613aaa61320e565b6001600160581b03198516600081815260028301602090815260408083206001600160e01b0319891680855290835292819020805488151560ff1990911681179091558151938452918301939093528183015290519192507f9d17cd6d095ac90a655405ab29f30a7ee7e88ef3974c1bf7544bf591043bb71a919081900360600190a150505050565b613b3d84826150d4565b6040516306d61fe760e41b81526001600160a01b03851690636d61fe7090613b6b9086908690600401616b25565b600060405180830381600087803b158015613b8557600080fd5b505af1158015611d35573d6000803e3d6000fd5b6001600160a01b0383161580613bb857506001600160a01b0383166001145b15613bc257505050565b60405163d60b347f60e01b81523060048201526001600160a01b0384169063d60b347f90602401602060405180830381865afa158015613c06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2a9190616a9d565b613c9e576001600160a01b038316636d61fe70613c4a83600181876169d8565b6040518363ffffffff1660e01b8152600401613c67929190616b25565b600060405180830381600087803b158015613c8157600080fd5b505af1158015613c95573d6000803e3d6000fd5b50505050613d3d565b6001600160f81b03198282600081613cb857613cb8616abf565b9050013560f81c60f81b6001600160f81b03191603613d3d576001600160a01b038316636d61fe70613ced83600181876169d8565b6040518363ffffffff1660e01b8152600401613d0a929190616b25565b600060405180830381600087803b158015613d2457600080fd5b505af1158015613d38573d6000803e3d6000fd5b505050505b600080516020616f65833981519152600484604051613d5d929190616b39565b60405180910390a1505050565b6001600160a01b038316613d83576001600160a01b0392505b6000613d8e8661087d565b9050600083836000818110613da557613da5616abf565b9050013560f81c60f81b9050613dbf81600060f81b61093c565b15613e5c576001600160a01b038616636d61fe70613de085600181896169d8565b6040518363ffffffff1660e01b8152600401613dfd929190616b25565b600060405180830381600087803b158015613e1757600080fd5b505af1158015613e2b573d6000803e3d6000fd5b50505050600080516020616f65833981519152600387604051613e4f929190616b39565b60405180910390a1613e8c565b613e6e816001600160f81b0319613656565b15613e8c57604051632d6a6bb760e01b815260040160405180910390fd5b81546001600160a01b039586166001600160a01b03199091161782556001909101805460f89290921c600160a01b026001600160a81b0319909216959094169490941793909317909155505050565b600080613ee661320e565b805490915060581b6001600160581b031990811690861603613f1b576040516313002bdd60e31b815260040160405180910390fd5b6001600160581b03198516600090815260018201602052604090208054640100000000600160c01b03198116909155600160201b90046001600160a01b0316915084613f6b81600160f81b61093c565b15613fed576000613f7c8760581c90565b9050613fbe8187878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141a192505050565b50600080516020616f85833981519152600182604051613fdf929190616b39565b60405180910390a150612e48565b613ffb81600160f91b61093c565b156139e357600061400c8760081b90565b905061401981878761512e565b50612e48565b60008061402b85613232565b80546001600160a01b031981168255604080516020601f88018190048102820181019092528681526001600160a01b03909216945091925061408a9187919087908790819084018382808284376000920191909152506141a192505050565b50600080516020616f858339815191526002866040516140ab929190616b39565b60405180910390a1509392505050565b6000806140c78561087d565b80546001600160a01b03198116825560018201546001600160a01b03909116935090915061410090600160a01b900460f81b600061093c565b15614189576001810154604080516020601f8701819004810282018101909252858152614151926001600160a01b03169187908790819084018382808284376000920191909152506141a192505050565b506001810154604051600080516020616f8583398151915291614180916003916001600160a01b031690616b39565b60405180910390a15b60010180546001600160a81b03191690559392505050565b60006141fb835a600080638a91b0e360e01b876040516024016141c4919061663d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526152f8565b50604080516001600160a01b038616815282151560208201529192507f2b82f87bf66300af618a9621d3f221edfab735f5bacb4e004cce1b62375396c3910160405180910390a192915050565b606083600881901b61425e82600160f81b61093c565b156142e8578435850160208101903561427883600061093c565b1561428e576142878282615382565b94506142e1565b61429c83600160f81b61093c565b156142ab576142878282615452565b60405162461bcd60e51b815260206004820152600b60248201526a155b9cdd5c1c1bdc9d195960aa1b6044820152606401611410565b5050612e48565b6142f382600061093c565b1561442157600080366000614308898961557f565b6040805160018082528183019092529498509296509094509250816020015b6060815260200190600190039081614327579050509650600061434a868261093c565b1561437e5761435b858585856155d0565b8860008151811061436e5761436e616abf565b6020026020010181905250614417565b61438c86600160f81b61093c565b156142ab5761439d85858585615606565b896000815181106143b0576143b0616abf565b6020908102919091010152905080614417577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb76000896000815181106143f8576143f8616abf565b602002602001015160405161440e929190616e29565b60405180910390a15b5050505050612e48565b614433826001600160f81b031961093c565b156142ab5760408051600180825281830190925290816020015b606081526020019060019003908161444d579050509250600061447360148287896169d8565b61447c91616ae5565b60601c9050366000614491876014818b6169d8565b9150915060006144a28484846109a3565b886000815181106144b5576144b5616abf565b602090810291909101015290506144d085600160f81b61093c565b15614534578061452f577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb760008860008151811061451057614510616abf565b6020026020010151604051614526929190616e29565b60405180910390a15b614587565b61453f85600061093c565b156142ab578061452f5760405162461bcd60e51b815260206004820152601360248201527211195b1959d85d1958d85b1b0819985a5b1959606a1b6044820152606401611410565b50505050612e48565b6001600160a01b03831615806145af57506001600160a01b0383166001145b156145b957505050565b6001600160f81b031982826000816145d3576145d3616abf565b9050013560f81c60f81b6001600160f81b0319160361463957614637836145fd83600181876169d8565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141a192505050565b505b600080516020616f85833981519152600484604051613d5d929190616b39565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030147f000000000000000000000000000000000000000000000000000000000000000046141661474c5750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f000000000000000000000000000000000000000000000000000000000000000060208201527f00000000000000000000000000000000000000000000000000000000000000009181019190915246606082015230608082015260a090205b67190100000000000060005280601a5281603a52604260182090506000603a52919050565b6000803660008061478061320e565b60408051610120810182526000808252602082018190529181018290526080810182905260a0810191909152606060c082018190526001600160e01b03198d16908201526001600160a01b038b1660e082015261010081018a90529091506147ea81838a8a615637565b878760008181106147fd576147fd616abf565b9091013560f81c60ff1490506148265760405163b32eeb6960e01b815260040160405180910390fd5b614833876001818b6169d8565b60608301516001600160e01b0319166000908152600394909401602052604093849020549390920151620100009093046001600160a01b03169c929b509950975095505050505050565b600060a082901c65ffffffffffff1682811560001981016148a25765ffffffffffff92505b508360d01c92509193909250565b60003660006148c08686866158a4565b925050506094830135830160348101906014013593509350939050565b600081830160601b8260601b81148460601b8214176001600160a01b03848618161517600181146149115760019250614993565b6001600160d01b031980851690861681811881831102188686176001600160a01b031617935065ffffffffffff60a01b861690816149565765ffffffffffff60a01b91505b5065ffffffffffff60a01b851680614974575065ffffffffffff60a01b5b80821890821102188061498d575065ffffffffffff60a01b5b92909217915b505092915050565b60008060006149a861320e565b6001600160e01b03198816600090815260038201602052604081209192506001909101905b8154811015614bbf57600080614a068484815481106149ee576149ee616abf565b60009182526020909120015460501b90605082901c90565b91509150600089896000818110614a1f57614a1f616abf565b919091013560f81c915050838103614ab2576000614a41600960018c8e6169d8565b614a4a91616e42565b60c01c9050614a5f6009808301908c8e6169d8565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101008d0152614aa88a60098301818e6169d8565b9a509a5050614aec565b838160ff161015614ad657604051630760bdcf60e11b815260040160405180910390fd5b6040805160208101909152600081526101008c01525b600160f01b8316600003614bb4576000826001600160a01b0316637129edce8e6001600160e01b0319168e6040518363ffffffff1660e01b8152600401614b34929190616e78565b6020604051808303816000875af1158015614b53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b779190616dbd565b9050806001600160a01b03811615614ba557604051631f24c1fb60e11b815260048101879052602401611410565b614baf8a836148dd565b995050505b5050506001016149cd565b5085856000818110614bd357614bd3616abf565b9091013560f81c60ff149050614bfc5760405163b32eeb6960e01b815260040160405180910390fd5b614c0985600181896169d8565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052506101008c01949094525050506001600160e01b03198916815260039092016020525060409020546001600160a01b036201000090910416905094509492505050565b6000614c8561320e565b90508235830160208101903560fe811180614c9e575080155b15614cbc5760405163b62d956d60e01b815260040160405180910390fd5b6001600160e01b03198616600090815260038401602052604090206001015415614d0a576001600160e01b0319861660009081526003840160205260408120614d0a91600190910190615e77565b60005b6000198201811015614efe576001600160e01b0319871660009081526003850160205260409020600101838383818110614d4957614d49616abf565b9050602002810190614d5b9190616a57565b614d6a916016916000916169d8565b614d7391616e91565b81546001810183556000928352602090922090910180546001600160b01b03191660509290921c919091179055828282818110614db257614db2616abf565b9050602002810190614dc49190616a57565b614dd3916016916002916169d8565b614ddc91616ae5565b60601c636d61fe706001600160e01b03198916858585818110614e0157614e01616abf565b9050602002810190614e139190616a57565b614e219160169082906169d8565b604051602001614e3393929190616ec7565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401614e5e919061663d565b600060405180830381600087803b158015614e7857600080fd5b505af1158015614e8c573d6000803e3d6000fd5b50505050600080516020616f658339815191526005848484818110614eb357614eb3616abf565b9050602002810190614ec59190616a57565b614ed4916016916002916169d8565b614edd91616ae5565b60601c604051614eee929190616b39565b60405180910390a1600101614d0d565b50600082826000198101818110614f1757614f17616abf565b9050602002810190614f299190616a57565b614f38916016916002916169d8565b614f4191616ae5565b6001600160e01b031988166000908152600386016020526040902080546201000060609390931c92830262010000600160b01b0319909116179055905082826000198101818110614f9457614f94616abf565b9050602002810190614fa69190616a57565b614fb5916002916000916169d8565b614fbe91616ee1565b6001600160e01b0319881660008181526003870160205260409020805461ffff191660f09390931c929092179091556001600160a01b03821690636d61fe70908585600019810181811061501457615014616abf565b90506020028101906150269190616a57565b6150349160169082906169d8565b60405160200161504693929190616ec7565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401615071919061663d565b600060405180830381600087803b15801561508b57600080fd5b505af115801561509f573d6000803e3d6000fd5b50505050600080516020616f658339815191526006826040516150c3929190616b39565b60405180910390a150505050505050565b6001600160a01b0381166150e6575060015b60006150f183613232565b80546001600160a01b0319166001600160a01b038416178155604051909150600080516020616f6583398151915290613d5d906002908690616b39565b81358201602081019035600061514261320e565b6001600160e01b031987166000908152600391909101602052604090206001808201549192500182146151885760405163013dcc8d60e31b815260040160405180910390fd5b6001810160005b815481101561523d5760006151af8383815481106149ee576149ee616abf565b91505061520b818a6001600160e01b0319168888868181106151d3576151d3616abf565b90506020028101906151e59190616a57565b6040516020016151f793929190616ec7565b6040516020818303038152906040526141a1565b50600080516020616f8583398151915260058260405161522c929190616b39565b60405180910390a15060010161518f565b5061524661320e565b6001600160e01b0319881660009081526003919091016020526040812061527291600190910190615e77565b81546152a8906201000090046001600160a01b03166001600160e01b03198916868660001981018181106151d3576151d3616abf565b508154604051600080516020616f85833981519152916152da916006916201000090046001600160a01b031690616b39565b60405180910390a15080546001600160b01b03191690555050505050565b6000606060008060008661ffff166001600160401b0381111561531d5761531d616431565b6040519080825280601f01601f191660200182016040528015615347576020820181803683370190505b5090506000808751602089018b8e8ef191503d925086831115615368578692505b828152826000602083013e90999098509650505050505050565b606081806001600160401b0381111561539d5761539d616431565b6040519080825280602002602001820160405280156153d057816020015b60608152602001906001900390816153bb5790505b50915060005b8181101561499357368585838181106153f1576153f1616abf565b90506020028101906154039190616f17565b905061542c61541560208301836160c6565b60208301356154276040850185616a57565b6155d0565b84838151811061543e5761543e616abf565b6020908102919091010152506001016153d6565b606081806001600160401b0381111561546d5761546d616431565b6040519080825280602002602001820160405280156154a057816020015b606081526020019060019003908161548b5790505b50915060005b8181101561499357368585838181106154c1576154c1616abf565b90506020028101906154d39190616f17565b905060006154fe6154e760208401846160c6565b60208401356154f96040860186616a57565b615606565b86858151811061551057615510616abf565b6020908102919091010152905080615575577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb78386858151811061555657615556616abf565b602002602001015160405161556c929190616e29565b60405180910390a15b50506001016154a6565b600080368161559160148287896169d8565b61559a91616ae5565b60601c93506155ad6034601487896169d8565b6155b691616b50565b92506155c585603481896169d8565b949793965094505050565b60405181838237600038838387895af16155ed573d6000823e3d81fd5b3d8152602081013d6000823e3d01604052949350505050565b604051600090828482376000388483888a5af191503d8152602081013d6000823e3d81016040525094509492505050565b60608401516001600160e01b03191660009081526003840160205260408120600101905b8154811015610a2c576156798282815481106149ee576149ee616abf565b6001600160a01b031660a08801526001600160f01b031916608087015283836000816156a7576156a7616abf565b919091013560f81c8088528290039050615744576156c96009600185876169d8565b6156d291616e42565b60c01c602087018190526156ed9060099081019085876169d8565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050505060c0870152602086015161573b90849060090181876169d8565b935093506157b0565b855160ff1681111561576957604051630760bdcf60e11b815260040160405180910390fd5b61577660008085876169d8565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050505060c08701525b6080860151600160f11b1660000361589c5760a0860151606087015160e088015161010089015160c08a015160405163184dfdbb60e11b81526000956001600160a01b03169463309bfb7694615817946001600160e01b0319909216939092600401616f37565b602060405180830381865afa158015615834573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906158589190616dbd565b9050806001600160a01b0381161561588657604051631f24c1fb60e11b815260048101849052602401611410565b6158948860400151836148dd565b604089015250505b60010161565b565b600036600080366000366000366000806158bf8e8e8e61592a565b9750975097509750975097509750975060748d013560348e0101995060208a033598506158ed818b8b615adf565b9a506158fd8e89898989896137ad565b6159078383615c7f565b6159198e611f946004600086886169d8565b505050505050505050509392505050565b604080518082019091526000808252602082015236600036600036600080600061595261320e565b9050615962601460008c8e6169d8565b61596b91616ae5565b60601c89602001906001600160a01b031690816001600160a01b0316815250508060000160159054906101000a900463ffffffff16896000019063ffffffff16908163ffffffff168152505060148b013560348c010197506020880335965060348b013560348c010195506020860335945060548b013560348c0101935060208403359250615acf7fb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c50560001b8d8360000160159054906101000a900463ffffffff168c602001518c8c604051615a42929190616ad5565b60405180910390208b8b604051615a5a929190616ad5565b60405180910390208a8a604051615a72929190616ad5565b6040805191829003822060208301989098526001600160581b03199096169581019590955263ffffffff90931660608501526001600160a01b03909116608084015260a083015260c082015260e081019190915261010001613313565b9150509397509397509397509397565b600080615aea61320e565b805490915060581b6000615b0282600160f81b61093c565b15615b8e578254604051637aa8f17760e11b81526001600160a81b038216916001600160a01b03169063f551e2ee90615b459030908c908c908c9060040161690d565b602060405180830381865afa158015615b62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615b869190616a3a565b915050615c44565b615b9c82600160f91b61093c565b156139e357825460601b6000615bb582308b8b8b614771565b60405163392dffaf60e01b8152919b5099509097509091506001600160a01b0382169063392dffaf90615bfe906001600160e01b031986169030908e908e908e90600401616b6e565b602060405180830381865afa158015615c1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615c3f9190616a3a565b925050505b630b135d3f60e11b6001600160e01b0319821614615c75576040516362467c7760e11b815260040160405180910390fd5b5050509392505050565b6000615c8e60048284866169d8565b615c9791616a02565b905060048210615e7257602c8210615e2b57366000818180615cbd60186004898b6169d8565b615cc691616ae5565b60601c9050602c880135604c890101945060208503359350604c880135604c890101925060208303359150615d1b85856000818110615d0757615d07616abf565b9050013560f81c60f81b600060f81b61093c565b8015615d8b575060405163ecd0596160e01b8152600260048201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015615d67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615d8b9190616a9d565b15615de157606c8801358801604c810190602c01356000615daf60148284866169d8565b615db891616ae5565b60601c9050615dc784826150d4565b615ddd81615dd884601481886169d8565b613b99565b5050505b615e078682615df4602c60188c8e6169d8565b615dfd91616ae5565b60601c8888613d6a565b611d35615e18602c60188a8c6169d8565b615e2191616ae5565b60601c8484613b99565b60048214615e725760405162461bcd60e51b8152602060048201526014602482015273496e76616c69642073656c6563746f724461746160601b6044820152606401611410565b505050565b5080546000825590600052602060002090810190615e959190615e98565b50565b5b80821115615ead5760008155600101615e99565b5090565b6001600160a01b0381168114615e9557600080fd5b803561320981615eb1565b60008083601f840112615ee357600080fd5b5081356001600160401b03811115615efa57600080fd5b602083019150836020828501011115615f1257600080fd5b9250929050565b60008060008060608587031215615f2f57600080fd5b843593506020850135615f4181615eb1565b925060408501356001600160401b03811115615f5c57600080fd5b615f6887828801615ed1565b95989497509550505050565b600080600080600060808688031215615f8c57600080fd5b8535615f9781615eb1565b94506020860135615fa781615eb1565b93506040860135925060608601356001600160401b03811115615fc957600080fd5b615fd588828901615ed1565b969995985093965092949392505050565b600080600060408486031215615ffb57600080fd5b8335925060208401356001600160401b0381111561601857600080fd5b61602486828701615ed1565b9497909650939450505050565b6000610120828403121561604457600080fd5b50919050565b60008060006060848603121561605f57600080fd5b83356001600160401b0381111561607557600080fd5b61608186828701616031565b9660208601359650604090950135949350505050565b803563ffffffff8116811461320957600080fd5b6000602082840312156160bd57600080fd5b610ca382616097565b6000602082840312156160d857600080fd5b8135610ca381615eb1565b80356001600160581b03198116811461320957600080fd5b60008083601f84011261610d57600080fd5b5081356001600160401b0381111561612457600080fd5b6020830191508360208260051b8501011115615f1257600080fd5b60008060008060008060008060a0898b03121561615b57600080fd5b616164896160e3565b9750602089013561617481615eb1565b965060408901356001600160401b0381111561618f57600080fd5b61619b8b828c01615ed1565b90975095505060608901356001600160401b038111156161ba57600080fd5b6161c68b828c01615ed1565b90955093505060808901356001600160401b038111156161e557600080fd5b6161f18b828c016160fb565b999c989b5096995094979396929594505050565b6000806000806000806080878903121561621e57600080fd5b616227876160e3565b9550602087013561623781615eb1565b945060408701356001600160401b0381111561625257600080fd5b61625e89828a01615ed1565b90955093505060608701356001600160401b0381111561627d57600080fd5b61628989828a01615ed1565b979a9699509497509295939492505050565b6001600160e01b031981168114615e9557600080fd5b6000602082840312156162c357600080fd5b8135610ca38161629b565b600080604083850312156162e157600080fd5b6162ea836160e3565b915060208301356162fa8161629b565b809150509250929050565b60005b83811015616320578181015183820152602001616308565b50506000910152565b60008151808452616341816020860160208601616305565b601f01601f19169290920160200192915050565b60ff60f81b8816815260e06020820152600061637460e0830189616329565b82810360408401526163868189616329565b606084018890526001600160a01b038716608085015260a0840186905283810360c08501528451808252602080870193509091019060005b818110156163dc5783518352602093840193909201916001016163be565b50909b9a5050505050505050505050565b6000806040838503121561640057600080fd5b82356001600160401b0381111561641657600080fd5b61642285828601616031565b95602094909401359450505050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171561646957616469616431565b60405290565b60405161012081016001600160401b038111828210171561646957616469616431565b604051601f8201601f191681016001600160401b03811182821017156164ba576164ba616431565b604052919050565b60008060008060008060006080888a0312156164dd57600080fd5b87356001600160401b038111156164f357600080fd5b6164ff8a828b016160fb565b90985096505060208801356001600160401b0381111561651e57600080fd5b8801601f81018a1361652f57600080fd5b80356001600160401b0381111561654857616548616431565b61655760208260051b01616492565b8082825260208201915060208360061b85010192508c83111561657957600080fd5b6020840193505b828410156165d5576040848e03121561659857600080fd5b6165a0616447565b6165a985616097565b815260208501356165b981615eb1565b8060208301525080835250602082019150604084019350616580565b975050505060408801356001600160401b038111156165f357600080fd5b6165ff8a828b016160fb565b90955093505060608801356001600160401b0381111561661e57600080fd5b61662a8a828b016160fb565b989b979a50959850939692959293505050565b602081526000610ca36020830184616329565b60006020828403121561666257600080fd5b610ca3826160e3565b60008060008060008060008060a0898b03121561668757600080fd5b883561669281615eb1565b975060208901356166a281615eb1565b965060408901356001600160401b038111156166bd57600080fd5b6166c98b828c016160fb565b90975095505060608901356001600160401b038111156166e857600080fd5b6166f48b828c016160fb565b90955093505060808901356001600160401b0381111561671357600080fd5b6161f18b828c01615ed1565b602080825282516001600160f01b03191682820152828101516001600160a01b03166040808401919091528301516060808401528051608084018190526000929190910190829060a08501905b808310156167985783516001600160501b0319168252602093840193600193909301929091019061676c565b5095945050505050565b6000602082840312156167b457600080fd5b5035919050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b8281101561681457603f198786030184526167ff858351616329565b945060209384019391909101906001016167e3565b50929695505050505050565b60008060008060006060868803121561683857600080fd5b616841866160e3565b945060208601356001600160401b0381111561685c57600080fd5b61686888828901615ed1565b90955093505060408601356001600160401b03811115615fc957600080fd5b60008060008060008060a087890312156168a057600080fd5b86356168ab81615eb1565b955060208701356168bb81615eb1565b9450604087013593506060870135925060808701356001600160401b0381111561627d57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60018060a01b03851681528360208201526060604082015260006169356060830184866168e4565b9695505050505050565b60006001600160401b0382111561695857616958616431565b50601f01601f191660200190565b60006020828403121561697857600080fd5b81516001600160401b0381111561698e57600080fd5b8201601f8101841361699f57600080fd5b80516169b26169ad8261693f565b616492565b8181528560208385010111156169c757600080fd5b610933826020830160208601616305565b600080858511156169e857600080fd5b838611156169f557600080fd5b5050820193919092039150565b80356001600160e01b03198116906004841015616a33576001600160e01b0319600485900360031b81901b82161691505b5092915050565b600060208284031215616a4c57600080fd5b8151610ca38161629b565b6000808335601e19843603018112616a6e57600080fd5b8301803591506001600160401b03821115616a8857600080fd5b602001915036819003821315615f1257600080fd5b600060208284031215616aaf57600080fd5b81518015158114610ca357600080fd5b634e487b7160e01b600052603260045260246000fd5b8183823760009101908152919050565b80356bffffffffffffffffffffffff198116906014841015616a33576bffffffffffffffffffffffff1960149490940360031b84901b1690921692915050565b602081526000610b016020830184866168e4565b9182526001600160a01b0316602082015260400190565b8035602083101561094d57600019602084900360031b1b1692915050565b85815260018060a01b0385166020820152836040820152608060608201526000616b9c6080830184866168e4565b979650505050505050565b600082601f830112616bb857600080fd5b8135616bc66169ad8261693f565b818152846020838601011115616bdb57600080fd5b816020850160208301376000918101602001919091529392505050565b60006101208236031215616c0b57600080fd5b616c1361646f565b616c1c83615ec6565b81526020838101359082015260408301356001600160401b03811115616c4157600080fd5b616c4d36828601616ba7565b60408301525060608301356001600160401b03811115616c6c57600080fd5b616c7836828601616ba7565b6060830152506080838101359082015260a0808401359082015260c0808401359082015260e08301356001600160401b03811115616cb557600080fd5b616cc136828601616ba7565b60e0830152506101008301356001600160401b03811115616ce157600080fd5b616ced36828601616ba7565b6101008301525092915050565b80516001600160a01b0316825260208101516020830152600060408201516101206040850152616d2e610120850182616329565b905060608301518482036060860152616d478282616329565b9150506080830151608085015260a083015160a085015260c083015160c085015260e083015184820360e0860152616d7f8282616329565b9150506101008301518482036101008601526109338282616329565b604081526000616dae6040830185616cfa565b90508260208301529392505050565b600060208284031215616dcf57600080fd5b5051919050565b838152606060208201526000616def6060830185616cfa565b9050826040830152949350505050565b63ffffffff818116838216019081111561094d57634e487b7160e01b600052601160045260246000fd5b828152604060208201526000610b016040830184616329565b80356001600160c01b03198116906008841015616a33576001600160c01b031960089490940360031b84901b1690921692915050565b828152604060208201526000610b016040830184616cfa565b80356001600160501b03198116906016841015616a33576001600160501b031960169490940360031b84901b1690921692915050565b838152818360208301376000910160200190815292915050565b80356001600160f01b03198116906002841015616a33576001600160f01b031960029490940360031b84901b1690921692915050565b60008235605e19833603018112616f2d57600080fd5b9190910192915050565b84815260018060a01b0384166020820152826040820152608060608201526000616935608083018461632956fed21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e"; - bytes public constant KERNEL_WITH_SETSELECTOR_BYTECODE = - hex"61014060405234801561001157600080fd5b506040516172913803806172918339810160408190526100309161015a565b306080524660a05260608061007a604080518082018252600681526512d95c9b995b60d21b60208083019190915282518084019093526005835264302e332e3160d81b9083015291565b815160209283012081519183019190912060c082905260e0819052604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8152808501939093528281019190915246606083015230608083015260a0909120610100526001600160a01b03851661012052805163deadbeef60e01b92810192909252805160048184030181526024909201905261011b9250905061018a565b7f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f80546001600160a81b03191660589290921c919091179055506101c8565b60006020828403121561016c57600080fd5b81516001600160a01b038116811461018357600080fd5b9392505050565b805160208201516001600160581b03198116919060158210156101c1576001600160581b0319601583900360031b81901b82161692505b5050919050565b60805160a05160c05160e051610100516101205161702d610264600039600081816102fa015281816106bf01528181610ce201528181611017015281816111e1015281816115de01528181611aac01528181611bd001528181611d940152818161257401528181612ea6015261307701526000614696015260006147500152600061472a015260006146da015260006146b7015261702d6000f3fe6080604052600436106101dc5760003560e01c80639198bdf511610102578063c3e5897811610095578063e9ae5c5311610064578063e9ae5c531461081a578063f1f7f0f91461082d578063f23a6e611461085b578063f2dc691d146108885761021b565b8063c3e589781461079a578063d03c7914146107c7578063d691c964146107e7578063e6f3d50a146108075761021b565b8063a71763a8116100d1578063a71763a8146106f9578063adb610a31461070c578063b8afe17d14610721578063bc197c811461076b5761021b565b80639198bdf5146106425780639517e29f146106555780639cfd7cff14610668578063a65d69d4146106ad5761021b565b80633c3b752b1161017a578063721e67f411610149578063721e67f4146105a557806384b0196e146105dd5780638dd7712f1461060557806390ef8862146106185761021b565b80633c3b752b146104f857806352141cd91461051857806357b3a5f41461052b5780636e6fa0c6146105855761021b565b806319822f7c116101b657806319822f7c1461048f5780631f1b92e3146104b05780633659cfe6146104c557806337bb6ef2146104d85761021b565b8063112d3a7d146103f5578063150b7a021461042a5780631626ba7e1461046f5761021b565b3661021b57604080513381523460208201527f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f88525874910160405180910390a1005b60006102326000356001600160e01b0319166108a8565b604080516060808201835283546001600160a01b039081168084526001909501549081166020840152600160a01b900460f81b6001600160f81b03191692820192909252925060009161029857604051631cd4b64760e21b815260040160405180910390fd5b82516060906001600160a01b03166001148015906102c1575083516001600160a01b0390811614155b156102dc5783516102d590346000366108e2565b9050610338565b83516001600160a01b03908116900361033857336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610338576040516348f5c3ed60e01b815260040160405180910390fd5b6040840151610348906000610967565b156103645761035a846020015161097e565b90935091506103a9565b604084015161037b906001600160f81b0319610967565b156103905761035a84602001516000366109ce565b604051632d6a6bb760e01b815260040160405180910390fd5b826103b657815160208301fd5b83516001600160a01b03166001148015906103dc575083516001600160a01b0390811614155b156103ed5783516103ed90826109fd565b815160208301f35b34801561040157600080fd5b50610415610410366004615f4f565b610a5f565b60405190151581526020015b60405180910390f35b34801561043657600080fd5b50610456610445366004615faa565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001610421565b34801561047b57600080fd5b5061045661048a36600461601c565b610b34565b6104a261049d366004616080565b610cd5565b604051908152602001610421565b6104c36104be3660046160e1565b610ff0565b005b6104c36104d33660046160fc565b6111c7565b3480156104e457600080fd5b506104c36104f3366004616155565b6113e0565b34801561050457600080fd5b506104c36105133660046161e2565b6113f0565b6104c36105263660046162a8565b6115c4565b34801561053757600080fd5b5061054b61054636600461633e565b611959565b6040805182516001600160a01b03908116825260208085015190911690820152918101516001600160f81b03191690820152606001610421565b34801561059157600080fd5b506104156105a036600461635b565b6119c5565b3480156105b157600080fd5b506105c56105c03660046160fc565b611a0d565b60405190516001600160a01b03168152602001610421565b3480156105e957600080fd5b506105f2611a43565b60405161042197969594939291906163e2565b6104c361061336600461647a565b611aa1565b34801561062457600080fd5b5061062d611b99565b60405163ffffffff9091168152602001610421565b6104c361065036600461654f565b611bb6565b6104c3610663366004615f4f565b611d7a565b34801561067457600080fd5b5060408051808201825260168152756b65726e656c2e616476616e6365642e76302e332e3160501b6020820152905161042191906166ca565b3480156106b957600080fd5b506106e17f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610421565b6104c3610707366004615f4f565b61255a565b34801561071857600080fd5b5061062d612bb3565b34801561072d57600080fd5b5061074161073c3660046166dd565b612bd0565b60408051825163ffffffff1681526020928301516001600160a01b03169281019290925201610421565b34801561077757600080fd5b506104566107863660046166f8565b63bc197c8160e01b98975050505050505050565b3480156107a657600080fd5b506107ba6107b536600461633e565b612c38565b60405161042191906167ac565b3480156107d357600080fd5b506104156107e236600461682f565b612d14565b6107fa6107f536600461601c565b612e01565b6040516104219190616848565b6104c36108153660046168ad565b612e8c565b6104c361082836600461601c565b61305d565b34801561083957600080fd5b50610842613216565b6040516001600160581b03199091168152602001610421565b34801561086757600080fd5b50610456610876366004616914565b63f23a6e6160e01b9695505050505050565b34801561089457600080fd5b506104156108a336600461682f565b613229565b6001600160e01b03191660009081527f7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b6020526040902090565b60405163d68f602560e01b81526060906001600160a01b0386169063d68f60259061091790339088908890889060040161699a565b6000604051808303816000875af1158015610936573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261095e91908101906169f3565b95945050505050565b6001600160f81b0319828116908216145b92915050565b6000606060408051368101909152366000823760408051601481019091523360601b9052600080366014018382885af192505060405190503d8152602081013d6000823e3d810160405250915091565b604051600090828482376000388483885af491503d8152602081013d6000823e3d810160405250935093915050565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da90610a299084906004016166ca565b600060405180830381600087803b158015610a4357600080fd5b505af1158015610a57573d6000803e3d6000fd5b505050505050565b600060018503610abc576000610a73613249565b6001016000610a888760581b600160f81b1790565b6001600160581b0319168152602081019190915260400160002054600160201b90046001600160a01b031614159050610b2c565b60028503610ae2576000610acf8561326d565b546001600160a01b031614159050610b2c565b60038503610b28576001600160a01b038416610b13610b05600460008688616a65565b610b0e91616a8f565b6108a8565b600101546001600160a01b0316149050610b2c565b5060005b949350505050565b600080610b3f613249565b90506000366000610b5087876132a6565b925092509250610b67610b608490565b6000610967565b15610b7457835460581b92505b6001600160581b031983166000908152600185016020526040902054600160201b90046001600160a01b0316610bbd57604051631a0a9b9f60e21b815260040160405180910390fd5b610bcb83600160f81b610967565b15610c65576000610bdc8460581c90565b9050806001600160a01b031663f551e2ee33610bf78c613313565b86866040518563ffffffff1660e01b8152600401610c18949392919061699a565b602060405180830381865afa158015610c35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c599190616ac7565b95505050505050610cce565b6000610c718460081b90565b6001600160e01b03198116600090815260038701602052604090205490915060f01b600160f11b811615610cb857604051635b71057960e01b815260040160405180910390fd5b610cc582338c8787613369565b96505050505050505b9392505050565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d20576040516348f5c3ed60e01b815260040160405180910390fd5b6000610d2a613249565b90506000806000610d3e8860200135613467565b91945092509050610d50826000610967565b15610d5c5750825460581b5b610d6883828a8a613495565b6001600160581b031982166000908152600186016020908152604080832081518083019092525463ffffffff81168252600160201b90046001600160a01b031691810191909152919650610dbd908490613691565b8015610ddb57508454815163ffffffff600160c81b90920482169116105b15610df957604051633ab3447f60e11b815260040160405180910390fd5b60208101516001600160a01b038116610e2557604051631a0a9b9f60e21b815260040160405180910390fd5b600089815260208190526040902080546001600160a01b0319166001600160a01b03831690811790915560001901610eed57610e62846000613691565b8015610eca57506001600160581b031983166000908152600287016020526040812090610e9260608d018d616ae4565b610ea191600491600091616a65565b610eaa91616a8f565b6001600160e01b031916815260208101919091526040016000205460ff16155b15610ee857604051631a0a9b9f60e21b815260040160405180910390fd5b610fd3565b610ef8846000613691565b8015610f6057506001600160581b031983166000908152600287016020526040812090610f2860608d018d616ae4565b610f3791600891600491616a65565b610f4091616a8f565b6001600160e01b031916815260208101919091526040016000205460ff16155b15610f7e57604051631a0a9b9f60e21b815260040160405180910390fd5b638dd7712f60e01b610f9360608c018c616ae4565b610fa291600491600091616a65565b610fab91616a8f565b6001600160e01b03191614610fd35760405163dbbb044b60e01b815260040160405180910390fd5b8715610fe357343434348b335af1505b5050505050509392505050565b600061100a610ffd613249565b546001600160a81b031690565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015906110455750333014155b156111ba5760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa15801561108e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b29190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f6025906110ec90339034908690369060040161699a565b6000604051808303816000875af115801561110b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261113391908101906169f3565b905061113e836136a4565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061116a9084906004016166ca565b600060405180830381600087803b15801561118457600080fd5b505af1158015611198573d6000803e3d6000fd5b50505050505050565b6040516348f5c3ed60e01b815260040160405180910390fd5b6111c3826136a4565b5050565b60006111d4610ffd613249565b9050336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480159061120f5750333014155b156113845760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015611258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127c9190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f6025906112b690339034908690369060040161699a565b6000604051808303816000875af11580156112d5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112fd91908101906169f3565b9050827f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55826001600160a01b03167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a2604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061116a9084906004016166ca565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8290556040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a25050565b6113eb838383613786565b505050565b60006113fa613249565b805490915060581b6001600160581b031916156114545760405162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b60448201526064015b60405180910390fd5b6001600160581b0319891661147c57604051631a0a9b9f60e21b815260040160405180910390fd5b8861148b81600160f81b613691565b80156114a057506114a081600160f91b613691565b156114be576040516361c4e91b60e11b815260040160405180910390fd5b6114c78a613819565b60408051808201909152600181526001600160a01b038a166020820152825463ffffffff60a81b1916600160a81b1783556115068b828b8b8b8b61387b565b60005b848110156115b65760003087878481811061152657611526616b47565b90506020028101906115389190616ae4565b604051611546929190616b5d565b6000604051808303816000865af19150503d8060008114611583576040519150601f19603f3d011682016040523d82523d6000602084013e611588565b606091505b50509050806115ad57604051636534eae560e11b81526004810183905260240161144b565b50600101611509565b505050505050505050505050565b60006115d1610ffd613249565b9050336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480159061160c5750333014155b156118585760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015611655573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116799190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f6025906116b390339034908690369060040161699a565b6000604051808303816000875af11580156116d2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116fa91908101906169f3565b90506000611706613249565b90506001600160581b0319891661173057604051631a0a9b9f60e21b815260040160405180910390fd5b8861173f81600160f81b613691565b8015611754575061175481600160f91b613691565b15611772576040516361c4e91b60e11b815260040160405180910390fd5b61177b8a613819565b6000611785613249565b6001600160581b03198c1660009081526001919091016020526040902054600160201b90046001600160a01b0316036117f257604080518082019091528254600160a81b900463ffffffff1681526001600160a01b038a1660208201526117f08b828b8b8b8b61387b565b505b5050604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906118209084906004016166ca565b600060405180830381600087803b15801561183a57600080fd5b505af115801561184e573d6000803e3d6000fd5b5050505050611198565b6000611862613249565b90506001600160581b0319881661188c57604051631a0a9b9f60e21b815260040160405180910390fd5b8761189b81600160f81b613691565b80156118b057506118b081600160f91b613691565b156118ce576040516361c4e91b60e11b815260040160405180910390fd5b6118d789613819565b60006118e1613249565b6001600160581b03198b1660009081526001919091016020526040902054600160201b90046001600160a01b03160361194e57604080518082019091528254600160a81b900463ffffffff1681526001600160a01b038916602082015261194c8a828a8a8a8a61387b565b505b505050505050505050565b604080516060810182526000808252602082018190529181019190915261197f826108a8565b6040805160608101825282546001600160a01b0390811682526001909301549283166020820152600160a01b90920460f81b6001600160f81b0319169082015292915050565b60006119cf613249565b6001600160581b031984166000908152600291909101602090815260408083206001600160e01b03198616845290915290205460ff16905092915050565b604080516020810190915260008152611a258261326d565b604080516020810190915290546001600160a01b0316815292915050565b600f60f81b6060806000808083611a8f604080518082018252600681526512d95c9b995b60d21b60208083019190915282518084019093526005835264302e332e3160d81b9083015291565b97989097965046955030945091925090565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611aea576040516348f5c3ed60e01b815260040160405180910390fd5b6000818152602081905260409020546060906001600160a01b031660018114611b3557611b328134611b1f6060880188616ae4565b611b2d916004908290616a65565b6108e2565b91505b600080611b5c30611b496060890189616ae4565b611b57916004908290616a65565b6109ce565b9150915081611b7e5760405163f21e646b60e01b815260040160405180910390fd5b6001600160a01b038316600114610a5757610a5783856109fd565b6000611ba3613249565b54600160c81b900463ffffffff16919050565b6000611bc3610ffd613249565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801590611bfe5750333014155b15611d615760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015611c47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c6b9190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f602590611ca590339034908690369060040161699a565b6000604051808303816000875af1158015611cc4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611cec91908101906169f3565b9050611cfd89898989898989613aca565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da90611d299084906004016166ca565b600060405180830381600087803b158015611d4357600080fd5b505af1158015611d57573d6000803e3d6000fd5b5050505050611d70565b611d7088888888888888613aca565b5050505050505050565b6000611d87610ffd613249565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801590611dc25750333014155b156122615760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015611e0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2f9190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f602590611e6990339034908690369060040161699a565b6000604051808303816000875af1158015611e88573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611eb091908101906169f3565b905060018603611fed576000611ec4613249565b90506000611ed88760581b600160f81b1790565b82546001600160581b03198216600090815260018501602052604090205491925063ffffffff600160a81b9091048116911603611f38578154600163ffffffff600160a81b808404821692909201160263ffffffff60a81b199091161782555b604080518082019091528254600160a81b900463ffffffff16815260009060208101611f676014848a8c616a65565b611f7091616b6d565b60601c9052905060148781013588016034818101929182013591818b01358b0180830192908201359160548d01358d01918201910135611fb488888888888861387b565b6004819003611fdf57611fdf88611fcf600460008587616a65565b611fd891616a8f565b6001613786565b5050505050505050506121fd565b600286036120545760148481013585016034818101929182013591818801358801918201918101359060009061202590828a8c616a65565b61202e91616b6d565b60601c905061203f8a868684613b6e565b61204a818484613bd4565b50505050506121fd565b600386036120e457601884810135850160388181019291820135918188013588019182019101356120b761208c600460008a8c616a65565b61209591616a8f565b8a6120a4601860048c8e616a65565b6120ad91616b6d565b60601c8787613da5565b6120db6120c8601860048a8c616a65565b6120d191616b6d565b60601c8383613bd4565b505050506121fd565b60048603612178576040516306d61fe760e41b81526001600160a01b03861690636d61fe709061211a9087908790600401616bad565b600060405180830381600087803b15801561213457600080fd5b505af1158015612148573d6000803e3d6000fd5b50505050600080516020616fed833981519152868660405161216b929190616bc1565b60405180910390a16121fd565b600586036121ae576040516306d61fe760e41b81526001600160a01b03861690636d61fe709061211a9087908790600401616bad565b600686036121e4576040516306d61fe760e41b81526001600160a01b03861690636d61fe709061211a9087908790600401616bad565b604051631092ef5760e11b815260040160405180910390fd5b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906122299084906004016166ca565b600060405180830381600087803b15801561224357600080fd5b505af1158015612257573d6000803e3d6000fd5b5050505050612553565b6001850361238c576000612273613249565b905060006122878660581b600160f81b1790565b82546001600160581b03198216600090815260018501602052604090205491925063ffffffff600160a81b90910481169116036122e7578154600163ffffffff600160a81b808404821692909201160263ffffffff60a81b199091161782555b604080518082019091528254600160a81b900463ffffffff16815260009060208101612316601484898b616a65565b61231f91616b6d565b60601c9052905060148681013587016034818101929182013591818a01358a0180830192908201359160548c01358c0191820191013561236388888888888861387b565b600481900361237e5761237e88611fcf600460008587616a65565b505050505050505050612553565b600285036123e9576014838101358401603481810192918201359181870135870191820191810135906000906123c49082898b616a65565b6123cd91616b6d565b60601c90506123de89868684613b6e565b612257818484613bd4565b60038503612453576018838101358401603881810192918201359181870135870191820191013561243961242160046000898b616a65565b61242a91616a8f565b896120a4601860048b8d616a65565b61244a6120c860186004898b616a65565b50505050612553565b600485036124e7576040516306d61fe760e41b81526001600160a01b03851690636d61fe70906124899086908690600401616bad565b600060405180830381600087803b1580156124a357600080fd5b505af11580156124b7573d6000803e3d6000fd5b50505050600080516020616fed83398151915285856040516124da929190616bc1565b60405180910390a1612553565b6005850361251d576040516306d61fe760e41b81526001600160a01b03851690636d61fe70906124899086908690600401616bad565b600685036121e4576040516306d61fe760e41b81526001600160a01b03851690636d61fe70906124899086908690600401616bad565b5050505050565b6000612567610ffd613249565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015906125a25750333014155b156129285760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa1580156125eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061260f9190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f60259061264990339034908690369060040161699a565b6000604051808303816000875af1158015612668573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261269091908101906169f3565b9050856001036126c05760006126ac8660581b600160f81b1790565b90506126b9818686613f16565b50506121fd565b856002036126d9576126d385858561405a565b506121fd565b856003036127115760006126f06004828688616a65565b6126f991616a8f565b90506126b98161270c866004818a616a65565b6140f6565b8560040361282e576000612723613249565b5460581b90506001600160a01b03861661273b613249565b6001600160581b0319831660009081526001919091016020526040902054600160201b90046001600160a01b0316036127c0576001612778613249565b6001600160581b0319831660009081526001919091016020526040902080546001600160a01b0392909216600160201b02640100000000600160c01b03199092169190911790555b6128008686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141dc92505050565b5060008051602061700d8339815191528787604051612820929190616bc1565b60405180910390a1506121fd565b85600503612916576000612840613249565b5460581b905060006128556020828789616a65565b61285e91616bd8565b905061286f825b600160f91b610967565b156128a75761287e8260081b90565b6001600160e01b03191681036128a7576040516313002bdd60e31b815260040160405180910390fd5b6128e78787878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141dc92505050565b5060008051602061700d8339815191528888604051612907929190616bc1565b60405180910390a150506121fd565b856006036121e4576000612840613249565b846001036129565760006129428560581b600160f81b1790565b905061294f818585613f16565b5050612553565b8460020361296f5761296984848461405a565b50612553565b846003036129a25760006129866004828587616a65565b61298f91616a8f565b905061294f8161270c8560048189616a65565b84600403612abf5760006129b4613249565b5460581b90506001600160a01b0385166129cc613249565b6001600160581b0319831660009081526001919091016020526040902054600160201b90046001600160a01b031603612a51576001612a09613249565b6001600160581b0319831660009081526001919091016020526040902080546001600160a01b0392909216600160201b02640100000000600160c01b03199092169190911790555b612a918585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141dc92505050565b5060008051602061700d8339815191528686604051612ab1929190616bc1565b60405180910390a150612553565b84600503612ba1576000612ad1613249565b5460581b90506000612ae66020828688616a65565b612aef91616bd8565b9050612afa82612865565b15612b3257612b098260081b90565b6001600160e01b0319168103612b32576040516313002bdd60e31b815260040160405180910390fd5b612b728686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141dc92505050565b5060008051602061700d8339815191528787604051612b92929190616bc1565b60405180910390a15050612553565b846006036121e4576000612ad1613249565b6000612bbd613249565b54600160a81b900463ffffffff16919050565b6040805180820190915260008082526020820152612bec613249565b6001600160581b03199290921660009081526001909201602090815260409283902083518085019094525463ffffffff81168452600160201b90046001600160a01b0316908301525090565b60408051606080820183526000808352602083015291810191909152612c5c613249565b6001600160e01b03198316600090815260039190910160209081526040918290208251606081018452815460f081901b6001600160f01b03191682526201000090046001600160a01b03168184015260018201805485518186028101860187528181529295939493860193830182828015612d0457602002820191906000526020600020905b815460501b6001600160501b0319168152600190910190602001808311612ce2575b5050505050815250509050919050565b600081600881901b603082901b605083901b612d3484600160f81b613691565b8015612d465750612d46846000613691565b8015612d5f5750612d5f846001600160f81b0319613691565b8015612d745750612d7484607f60f91b613691565b15612d855750600095945050505050565b6001600160f81b03198316600160f81b14801590612dac57506001600160f81b0319831615155b15612dbd5750600095945050505050565b6001600160e01b0319821615612dd95750600095945050505050565b6001600160501b0319811615612df55750600095945050505050565b50600195945050505050565b60606000612e0e3361326d565b546001600160a01b0316905080612e385760405163710c949760e01b815260040160405180910390fd5b60606001600160a01b038216600114612e5b57612e5882346000366108e2565b90505b612e66868686614283565b92506001600160a01b038216600114612e8357612e8382826109fd565b50509392505050565b6000612e99610ffd613249565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801590612ed45750333014155b156130435760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015612f1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f419190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f602590612f7b90339034908690369060040161699a565b6000604051808303816000875af1158015612f9a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612fc291908101906169f3565b90506000612fd1888888613f16565b9050612fde8186866145cb565b50604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da9061300b9084906004016166ca565b600060405180830381600087803b15801561302557600080fd5b505af1158015613039573d6000803e3d6000fd5b5050505050610a57565b6000613050878787613f16565b90506111988185856145cb565b600061306a610ffd613249565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015906130a55750333014155b156132055760405163ecd0596160e01b81526004808201526001600160a01b0382169063ecd0596190602401602060405180830381865afa1580156130ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131129190616b2a565b156111a15760405163d68f602560e01b81526000906001600160a01b0383169063d68f60259061314c90339034908690369060040161699a565b6000604051808303816000875af115801561316b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261319391908101906169f3565b90506131a0858585614283565b50604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906131cd9084906004016166ca565b600060405180830381600087803b1580156131e757600080fd5b505af11580156131fb573d6000803e3d6000fd5b5050505050613210565b612553848484614283565b50505050565b6000613220613249565b5460581b919050565b6000600782101561323c57506001919050565b506000919050565b919050565b7f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f90565b6001600160a01b031660009081527f1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b866020526040902090565b813536600060f883901c80156132cb57600181146132e057600281146132f157600080fd5b6000935060018601925060018503915061330b565b60158601925060158503915061330b565b6001600160d81b0319841693506005860192506005850391505b509250925092565b604080517f1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c836020820152908101829052600090610978906060015b60405160208183030381529060405280519060200120614694565b600080600036600061337e8a8a8a8a8a6147ac565b9350935093509350600080613392856148b8565b50915091508165ffffffffffff164210806133b457508065ffffffffffff1642115b156133d057506001600160e01b0319955061095e945050505050565b6001600160a01b03861663392dffaf6001600160e01b03198e168d6133f48e613313565b88886040518663ffffffff1660e01b8152600401613416959493929190616bf6565b602060405180830381865afa158015613433573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134579190616ac7565b9c9b505050505050505050505050565b80600881901b8060ff60f084901c16600119810161348d576001600160d81b0319821691505b509193909250565b6000806134a0613249565b905060006134ad85616c80565b90503660006134c0610100880188616ae4565b90925090506134d389600160f81b610967565b15613531576134ef886134ea6101008a018a616ae4565b6148eb565b604080516020601f8401819004810282018101909252828152939850919450925083908390819084018382808284376000920191909152505050506101008401525b8761354081600160f81b610967565b156135cf576135c8866135538b60581c90565b6001600160a01b03166397003203878b6040518363ffffffff1660e01b8152600401613580929190616e23565b6020604051808303816000875af115801561359f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135c39190616e45565b614918565b9550613684565b60006135db8a60081b90565b6001600160e01b03198116600090815260038801602052604090205490915060f01b600160f01b1615613621576040516314b9743f60e01b815260040160405180910390fd5b600080613630838888886149d6565b9150915061363e8983614918565b985061367e89826001600160a01b0316630ccab7a1866001600160e01b0319168b8f6040518463ffffffff1660e01b815260040161358093929190616e5e565b98505050505b5050505050949350505050565b6001600160f81b03199081169116141590565b60006136ae613249565b805490915063ffffffff808416916136d091600a91600160a81b900416616e87565b63ffffffff1610156136f55760405163e60fd64760e01b815260040160405180910390fd5b805463ffffffff600160c81b90910481169083161161372757604051633ab3447f60e11b815260040160405180910390fd5b805463ffffffff60c81b1916600160c81b63ffffffff8481168202929092178084559081048216600160a81b90910490911610156111c357805463ffffffff60a81b198116600160c81b90910463ffffffff16600160a81b0217905550565b6000613790613249565b6001600160581b03198516600081815260028301602090815260408083206001600160e01b0319891680855290835292819020805488151560ff1990911681179091558151938452918301939093528183015290519192507f9d17cd6d095ac90a655405ab29f30a7ee7e88ef3974c1bf7544bf591043bb71a919081900360600190a150505050565b6000613823613249565b80546001600160a81b031916605884901c1781556040516001600160581b0319841681529091507f6789ec0c85d6458d897a36a70129b101f8b4d84c6e218046c3107373dbcbae889060200160405180910390a15050565b6000613885613249565b80546001600160581b03198916600090815260018301602052604090205491925063ffffffff600160a81b90910481169116036138e5578054600163ffffffff600160a81b808404821692909201160263ffffffff60a81b199091161781555b60208601516001600160a01b03166138ff57600160208701525b85518154600160a81b900463ffffffff9081169116141580613947575085516001600160581b03198816600090815260018301602052604090205463ffffffff918216911610155b1561396557604051633ab3447f60e11b815260040160405180910390fd5b6001600160581b03198716600090815260018083016020908152604090922088518154938a01516001600160a01b0316600160201b81026001600160c01b031990951663ffffffff90921691909117939093179055146139ce576139ce86602001518484613bd4565b866139dd81600160f81b610967565b15613a7f5760006139ee8960581c90565b6040516306d61fe760e41b81529091506001600160a01b03821690636d61fe7090613a1f908a908a90600401616bad565b600060405180830381600087803b158015613a3957600080fd5b505af1158015613a4d573d6000803e3d6000fd5b50505050600080516020616fed833981519152600182604051613a71929190616bc1565b60405180910390a150611d70565b613a8d81600160f91b610967565b15613ab1576000613a9e8960081b90565b9050613aab818888614cb6565b50611d70565b6040516361c4e91b60e11b815260040160405180910390fd5b60005b86811015611d7057613b66888883818110613aea57613aea616b47565b9050602002016020810190613aff91906166dd565b878381518110613b1157613b11616b47565b6020026020010151878785818110613b2b57613b2b616b47565b9050602002810190613b3d9190616ae4565b878787818110613b4f57613b4f616b47565b9050602002810190613b619190616ae4565b61387b565b600101613acd565b613b78848261510f565b6040516306d61fe760e41b81526001600160a01b03851690636d61fe7090613ba69086908690600401616bad565b600060405180830381600087803b158015613bc057600080fd5b505af1158015611d70573d6000803e3d6000fd5b6001600160a01b0383161580613bf357506001600160a01b0383166001145b15613bfd57505050565b60405163d60b347f60e01b81523060048201526001600160a01b0384169063d60b347f90602401602060405180830381865afa158015613c41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c659190616b2a565b613cd9576001600160a01b038316636d61fe70613c858360018187616a65565b6040518363ffffffff1660e01b8152600401613ca2929190616bad565b600060405180830381600087803b158015613cbc57600080fd5b505af1158015613cd0573d6000803e3d6000fd5b50505050613d78565b6001600160f81b03198282600081613cf357613cf3616b47565b9050013560f81c60f81b6001600160f81b03191603613d78576001600160a01b038316636d61fe70613d288360018187616a65565b6040518363ffffffff1660e01b8152600401613d45929190616bad565b600060405180830381600087803b158015613d5f57600080fd5b505af1158015613d73573d6000803e3d6000fd5b505050505b600080516020616fed833981519152600484604051613d98929190616bc1565b60405180910390a1505050565b6001600160a01b038316613dbe576001600160a01b0392505b6000613dc9866108a8565b9050600083836000818110613de057613de0616b47565b9050013560f81c60f81b9050613dfa81600060f81b610967565b15613e97576001600160a01b038616636d61fe70613e1b8560018189616a65565b6040518363ffffffff1660e01b8152600401613e38929190616bad565b600060405180830381600087803b158015613e5257600080fd5b505af1158015613e66573d6000803e3d6000fd5b50505050600080516020616fed833981519152600387604051613e8a929190616bc1565b60405180910390a1613ec7565b613ea9816001600160f81b0319613691565b15613ec757604051632d6a6bb760e01b815260040160405180910390fd5b81546001600160a01b039586166001600160a01b03199091161782556001909101805460f89290921c600160a01b026001600160a81b0319909216959094169490941793909317909155505050565b600080613f21613249565b805490915060581b6001600160581b031990811690861603613f56576040516313002bdd60e31b815260040160405180910390fd5b6001600160581b03198516600090815260018201602052604090208054640100000000600160c01b03198116909155600160201b90046001600160a01b0316915084613fa681600160f81b610967565b15614028576000613fb78760581c90565b9050613ff98187878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141dc92505050565b5060008051602061700d83398151915260018260405161401a929190616bc1565b60405180910390a150612e83565b61403681600160f91b610967565b15613ab15760006140478760081b90565b9050614054818787615169565b50612e83565b6000806140668561326d565b80546001600160a01b031981168255604080516020601f88018190048102820181019092528681526001600160a01b0390921694509192506140c59187919087908790819084018382808284376000920191909152506141dc92505050565b5060008051602061700d8339815191526002866040516140e6929190616bc1565b60405180910390a1509392505050565b600080614102856108a8565b80546001600160a01b03198116825560018201546001600160a01b03909116935090915061413b90600160a01b900460f81b6000610967565b156141c4576001810154604080516020601f870181900481028201810190925285815261418c926001600160a01b03169187908790819084018382808284376000920191909152506141dc92505050565b50600181015460405160008051602061700d833981519152916141bb916003916001600160a01b031690616bc1565b60405180910390a15b60010180546001600160a81b03191690559392505050565b6000614236835a600080638a91b0e360e01b876040516024016141ff91906166ca565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152615333565b50604080516001600160a01b038616815282151560208201529192507f2b82f87bf66300af618a9621d3f221edfab735f5bacb4e004cce1b62375396c3910160405180910390a192915050565b606083600881901b61429982600160f81b610967565b1561432357843585016020810190356142b3836000610967565b156142c9576142c282826153bd565b945061431c565b6142d783600160f81b610967565b156142e6576142c2828261548d565b60405162461bcd60e51b815260206004820152600b60248201526a155b9cdd5c1c1bdc9d195960aa1b604482015260640161144b565b5050612e83565b61432e826000610967565b1561445c5760008036600061434389896155ba565b6040805160018082528183019092529498509296509094509250816020015b606081526020019060019003908161436257905050965060006143858682610967565b156143b9576143968585858561560b565b886000815181106143a9576143a9616b47565b6020026020010181905250614452565b6143c786600160f81b610967565b156142e6576143d885858585615641565b896000815181106143eb576143eb616b47565b6020908102919091010152905080614452577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb760008960008151811061443357614433616b47565b6020026020010151604051614449929190616eb1565b60405180910390a15b5050505050612e83565b61446e826001600160f81b0319610967565b156142e65760408051600180825281830190925290816020015b606081526020019060019003908161448857905050925060006144ae6014828789616a65565b6144b791616b6d565b60601c90503660006144cc876014818b616a65565b9150915060006144dd8484846109ce565b886000815181106144f0576144f0616b47565b6020908102919091010152905061450b85600160f81b610967565b1561456f578061456a577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb760008860008151811061454b5761454b616b47565b6020026020010151604051614561929190616eb1565b60405180910390a15b6145c2565b61457a856000610967565b156142e6578061456a5760405162461bcd60e51b815260206004820152601360248201527211195b1959d85d1958d85b1b0819985a5b1959606a1b604482015260640161144b565b50505050612e83565b6001600160a01b03831615806145ea57506001600160a01b0383166001145b156145f457505050565b6001600160f81b0319828260008161460e5761460e616b47565b9050013560f81c60f81b6001600160f81b0319160361467457614672836146388360018187616a65565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141dc92505050565b505b60008051602061700d833981519152600484604051613d98929190616bc1565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030147f00000000000000000000000000000000000000000000000000000000000000004614166147875750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f000000000000000000000000000000000000000000000000000000000000000060208201527f00000000000000000000000000000000000000000000000000000000000000009181019190915246606082015230608082015260a090205b67190100000000000060005280601a5281603a52604260182090506000603a52919050565b600080366000806147bb613249565b60408051610120810182526000808252602082018190529181018290526080810182905260a0810191909152606060c082018190526001600160e01b03198d16908201526001600160a01b038b1660e082015261010081018a905290915061482581838a8a615672565b8787600081811061483857614838616b47565b9091013560f81c60ff1490506148615760405163b32eeb6960e01b815260040160405180910390fd5b61486e876001818b616a65565b60608301516001600160e01b0319166000908152600394909401602052604093849020549390920151620100009093046001600160a01b03169c929b509950975095505050505050565b600060a082901c65ffffffffffff1682811560001981016148dd5765ffffffffffff92505b508360d01c92509193909250565b60003660006148fb8686866158df565b925050506094830135830160348101906014013593509350939050565b600081830160601b8260601b81148460601b8214176001600160a01b038486181615176001811461494c57600192506149ce565b6001600160d01b031980851690861681811881831102188686176001600160a01b031617935065ffffffffffff60a01b861690816149915765ffffffffffff60a01b91505b5065ffffffffffff60a01b8516806149af575065ffffffffffff60a01b5b8082189082110218806149c8575065ffffffffffff60a01b5b92909217915b505092915050565b60008060006149e3613249565b6001600160e01b03198816600090815260038201602052604081209192506001909101905b8154811015614bfa57600080614a41848481548110614a2957614a29616b47565b60009182526020909120015460501b90605082901c90565b91509150600089896000818110614a5a57614a5a616b47565b919091013560f81c915050838103614aed576000614a7c600960018c8e616a65565b614a8591616eca565b60c01c9050614a9a6009808301908c8e616a65565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101008d0152614ae38a60098301818e616a65565b9a509a5050614b27565b838160ff161015614b1157604051630760bdcf60e11b815260040160405180910390fd5b6040805160208101909152600081526101008c01525b600160f01b8316600003614bef576000826001600160a01b0316637129edce8e6001600160e01b0319168e6040518363ffffffff1660e01b8152600401614b6f929190616f00565b6020604051808303816000875af1158015614b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bb29190616e45565b9050806001600160a01b03811615614be057604051631f24c1fb60e11b81526004810187905260240161144b565b614bea8a83614918565b995050505b505050600101614a08565b5085856000818110614c0e57614c0e616b47565b9091013560f81c60ff149050614c375760405163b32eeb6960e01b815260040160405180910390fd5b614c448560018189616a65565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052506101008c01949094525050506001600160e01b03198916815260039092016020525060409020546001600160a01b036201000090910416905094509492505050565b6000614cc0613249565b90508235830160208101903560fe811180614cd9575080155b15614cf75760405163b62d956d60e01b815260040160405180910390fd5b6001600160e01b03198616600090815260038401602052604090206001015415614d45576001600160e01b0319861660009081526003840160205260408120614d4591600190910190615ead565b60005b6000198201811015614f39576001600160e01b0319871660009081526003850160205260409020600101838383818110614d8457614d84616b47565b9050602002810190614d969190616ae4565b614da591601691600091616a65565b614dae91616f19565b81546001810183556000928352602090922090910180546001600160b01b03191660509290921c919091179055828282818110614ded57614ded616b47565b9050602002810190614dff9190616ae4565b614e0e91601691600291616a65565b614e1791616b6d565b60601c636d61fe706001600160e01b03198916858585818110614e3c57614e3c616b47565b9050602002810190614e4e9190616ae4565b614e5c916016908290616a65565b604051602001614e6e93929190616f4f565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401614e9991906166ca565b600060405180830381600087803b158015614eb357600080fd5b505af1158015614ec7573d6000803e3d6000fd5b50505050600080516020616fed8339815191526005848484818110614eee57614eee616b47565b9050602002810190614f009190616ae4565b614f0f91601691600291616a65565b614f1891616b6d565b60601c604051614f29929190616bc1565b60405180910390a1600101614d48565b50600082826000198101818110614f5257614f52616b47565b9050602002810190614f649190616ae4565b614f7391601691600291616a65565b614f7c91616b6d565b6001600160e01b031988166000908152600386016020526040902080546201000060609390931c92830262010000600160b01b0319909116179055905082826000198101818110614fcf57614fcf616b47565b9050602002810190614fe19190616ae4565b614ff091600291600091616a65565b614ff991616f69565b6001600160e01b0319881660008181526003870160205260409020805461ffff191660f09390931c929092179091556001600160a01b03821690636d61fe70908585600019810181811061504f5761504f616b47565b90506020028101906150619190616ae4565b61506f916016908290616a65565b60405160200161508193929190616f4f565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016150ac91906166ca565b600060405180830381600087803b1580156150c657600080fd5b505af11580156150da573d6000803e3d6000fd5b50505050600080516020616fed8339815191526006826040516150fe929190616bc1565b60405180910390a150505050505050565b6001600160a01b038116615121575060015b600061512c8361326d565b80546001600160a01b0319166001600160a01b038416178155604051909150600080516020616fed83398151915290613d98906002908690616bc1565b81358201602081019035600061517d613249565b6001600160e01b031987166000908152600391909101602052604090206001808201549192500182146151c35760405163013dcc8d60e31b815260040160405180910390fd5b6001810160005b81548110156152785760006151ea838381548110614a2957614a29616b47565b915050615246818a6001600160e01b03191688888681811061520e5761520e616b47565b90506020028101906152209190616ae4565b60405160200161523293929190616f4f565b6040516020818303038152906040526141dc565b5060008051602061700d833981519152600582604051615267929190616bc1565b60405180910390a1506001016151ca565b50615281613249565b6001600160e01b031988166000908152600391909101602052604081206152ad91600190910190615ead565b81546152e3906201000090046001600160a01b03166001600160e01b031989168686600019810181811061520e5761520e616b47565b50815460405160008051602061700d83398151915291615315916006916201000090046001600160a01b031690616bc1565b60405180910390a15080546001600160b01b03191690555050505050565b6000606060008060008661ffff166001600160401b03811115615358576153586164be565b6040519080825280601f01601f191660200182016040528015615382576020820181803683370190505b5090506000808751602089018b8e8ef191503d9250868311156153a3578692505b828152826000602083013e90999098509650505050505050565b606081806001600160401b038111156153d8576153d86164be565b60405190808252806020026020018201604052801561540b57816020015b60608152602001906001900390816153f65790505b50915060005b818110156149ce573685858381811061542c5761542c616b47565b905060200281019061543e9190616f9f565b905061546761545060208301836160fc565b60208301356154626040850185616ae4565b61560b565b84838151811061547957615479616b47565b602090810291909101015250600101615411565b606081806001600160401b038111156154a8576154a86164be565b6040519080825280602002602001820160405280156154db57816020015b60608152602001906001900390816154c65790505b50915060005b818110156149ce57368585838181106154fc576154fc616b47565b905060200281019061550e9190616f9f565b9050600061553961552260208401846160fc565b60208401356155346040860186616ae4565b615641565b86858151811061554b5761554b616b47565b60209081029190910101529050806155b0577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb78386858151811061559157615591616b47565b60200260200101516040516155a7929190616eb1565b60405180910390a15b50506001016154e1565b60008036816155cc6014828789616a65565b6155d591616b6d565b60601c93506155e8603460148789616a65565b6155f191616bd8565b92506156008560348189616a65565b949793965094505050565b60405181838237600038838387895af1615628573d6000823e3d81fd5b3d8152602081013d6000823e3d01604052949350505050565b604051600090828482376000388483888a5af191503d8152602081013d6000823e3d81016040525094509492505050565b60608401516001600160e01b03191660009081526003840160205260408120600101905b8154811015610a57576156b4828281548110614a2957614a29616b47565b6001600160a01b031660a08801526001600160f01b031916608087015283836000816156e2576156e2616b47565b919091013560f81c808852829003905061577f57615704600960018587616a65565b61570d91616eca565b60c01c60208701819052615728906009908101908587616a65565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050505060c087015260208601516157769084906009018187616a65565b935093506157eb565b855160ff168111156157a457604051630760bdcf60e11b815260040160405180910390fd5b6157b16000808587616a65565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050505060c08701525b6080860151600160f11b166000036158d75760a0860151606087015160e088015161010089015160c08a015160405163184dfdbb60e11b81526000956001600160a01b03169463309bfb7694615852946001600160e01b0319909216939092600401616fbf565b602060405180830381865afa15801561586f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906158939190616e45565b9050806001600160a01b038116156158c157604051631f24c1fb60e11b81526004810184905260240161144b565b6158cf886040015183614918565b604089015250505b600101615696565b600036600080366000366000366000806158fa8e8e8e615965565b9750975097509750975097509750975060748d013560348e0101995060208a03359850615928818b8b615b1a565b9a506159388e898989898961387b565b6159428383615cba565b6159548e611fcf600460008688616a65565b505050505050505050509392505050565b604080518082019091526000808252602082015236600036600036600080600061598d613249565b905061599d601460008c8e616a65565b6159a691616b6d565b60601c89602001906001600160a01b031690816001600160a01b0316815250508060000160159054906101000a900463ffffffff16896000019063ffffffff16908163ffffffff168152505060148b013560348c010197506020880335965060348b013560348c010195506020860335945060548b013560348c0101935060208403359250615b0a7fb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c50560001b8d8360000160159054906101000a900463ffffffff168c602001518c8c604051615a7d929190616b5d565b60405180910390208b8b604051615a95929190616b5d565b60405180910390208a8a604051615aad929190616b5d565b6040805191829003822060208301989098526001600160581b03199096169581019590955263ffffffff90931660608501526001600160a01b03909116608084015260a083015260c082015260e08101919091526101000161334e565b9150509397509397509397509397565b600080615b25613249565b805490915060581b6000615b3d82600160f81b610967565b15615bc9578254604051637aa8f17760e11b81526001600160a81b038216916001600160a01b03169063f551e2ee90615b809030908c908c908c9060040161699a565b602060405180830381865afa158015615b9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615bc19190616ac7565b915050615c7f565b615bd782600160f91b610967565b15613ab157825460601b6000615bf082308b8b8b6147ac565b60405163392dffaf60e01b8152919b5099509097509091506001600160a01b0382169063392dffaf90615c39906001600160e01b031986169030908e908e908e90600401616bf6565b602060405180830381865afa158015615c56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615c7a9190616ac7565b925050505b630b135d3f60e11b6001600160e01b0319821614615cb0576040516362467c7760e11b815260040160405180910390fd5b5050509392505050565b6000615cc96004828486616a65565b615cd291616a8f565b9050600482106113eb57602c8210615e6657366000818180615cf860186004898b616a65565b615d0191616b6d565b60601c9050602c880135604c890101945060208503359350604c880135604c890101925060208303359150615d5685856000818110615d4257615d42616b47565b9050013560f81c60f81b600060f81b610967565b8015615dc6575060405163ecd0596160e01b8152600260048201526001600160a01b0382169063ecd0596190602401602060405180830381865afa158015615da2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615dc69190616b2a565b15615e1c57606c8801358801604c810190602c01356000615dea6014828486616a65565b615df391616b6d565b60601c9050615e02848261510f565b615e1881615e138460148188616a65565b613bd4565b5050505b615e428682615e2f602c60188c8e616a65565b615e3891616b6d565b60601c8888613da5565b611d70615e53602c60188a8c616a65565b615e5c91616b6d565b60601c8484613bd4565b600482146113eb5760405162461bcd60e51b8152602060048201526014602482015273496e76616c69642073656c6563746f724461746160601b604482015260640161144b565b5080546000825590600052602060002090810190615ecb9190615ece565b50565b5b80821115615ee35760008155600101615ecf565b5090565b6001600160a01b0381168114615ecb57600080fd5b803561324481615ee7565b60008083601f840112615f1957600080fd5b5081356001600160401b03811115615f3057600080fd5b602083019150836020828501011115615f4857600080fd5b9250929050565b60008060008060608587031215615f6557600080fd5b843593506020850135615f7781615ee7565b925060408501356001600160401b03811115615f9257600080fd5b615f9e87828801615f07565b95989497509550505050565b600080600080600060808688031215615fc257600080fd5b8535615fcd81615ee7565b94506020860135615fdd81615ee7565b93506040860135925060608601356001600160401b03811115615fff57600080fd5b61600b88828901615f07565b969995985093965092949392505050565b60008060006040848603121561603157600080fd5b8335925060208401356001600160401b0381111561604e57600080fd5b61605a86828701615f07565b9497909650939450505050565b6000610120828403121561607a57600080fd5b50919050565b60008060006060848603121561609557600080fd5b83356001600160401b038111156160ab57600080fd5b6160b786828701616067565b9660208601359650604090950135949350505050565b803563ffffffff8116811461324457600080fd5b6000602082840312156160f357600080fd5b610cce826160cd565b60006020828403121561610e57600080fd5b8135610cce81615ee7565b80356001600160581b03198116811461324457600080fd5b6001600160e01b031981168114615ecb57600080fd5b8015158114615ecb57600080fd5b60008060006060848603121561616a57600080fd5b61617384616119565b9250602084013561618381616131565b9150604084013561619381616147565b809150509250925092565b60008083601f8401126161b057600080fd5b5081356001600160401b038111156161c757600080fd5b6020830191508360208260051b8501011115615f4857600080fd5b60008060008060008060008060a0898b0312156161fe57600080fd5b61620789616119565b9750602089013561621781615ee7565b965060408901356001600160401b0381111561623257600080fd5b61623e8b828c01615f07565b90975095505060608901356001600160401b0381111561625d57600080fd5b6162698b828c01615f07565b90955093505060808901356001600160401b0381111561628857600080fd5b6162948b828c0161619e565b999c989b5096995094979396929594505050565b600080600080600080608087890312156162c157600080fd5b6162ca87616119565b955060208701356162da81615ee7565b945060408701356001600160401b038111156162f557600080fd5b61630189828a01615f07565b90955093505060608701356001600160401b0381111561632057600080fd5b61632c89828a01615f07565b979a9699509497509295939492505050565b60006020828403121561635057600080fd5b8135610cce81616131565b6000806040838503121561636e57600080fd5b61637783616119565b9150602083013561638781616131565b809150509250929050565b60005b838110156163ad578181015183820152602001616395565b50506000910152565b600081518084526163ce816020860160208601616392565b601f01601f19169290920160200192915050565b60ff60f81b8816815260e06020820152600061640160e08301896163b6565b828103604084015261641381896163b6565b606084018890526001600160a01b038716608085015260a0840186905283810360c08501528451808252602080870193509091019060005b8181101561646957835183526020938401939092019160010161644b565b50909b9a5050505050505050505050565b6000806040838503121561648d57600080fd5b82356001600160401b038111156164a357600080fd5b6164af85828601616067565b95602094909401359450505050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156164f6576164f66164be565b60405290565b60405161012081016001600160401b03811182821017156164f6576164f66164be565b604051601f8201601f191681016001600160401b0381118282101715616547576165476164be565b604052919050565b60008060008060008060006080888a03121561656a57600080fd5b87356001600160401b0381111561658057600080fd5b61658c8a828b0161619e565b90985096505060208801356001600160401b038111156165ab57600080fd5b8801601f81018a136165bc57600080fd5b80356001600160401b038111156165d5576165d56164be565b6165e460208260051b0161651f565b8082825260208201915060208360061b85010192508c83111561660657600080fd5b6020840193505b82841015616662576040848e03121561662557600080fd5b61662d6164d4565b616636856160cd565b8152602085013561664681615ee7565b806020830152508083525060208201915060408401935061660d565b975050505060408801356001600160401b0381111561668057600080fd5b61668c8a828b0161619e565b90955093505060608801356001600160401b038111156166ab57600080fd5b6166b78a828b0161619e565b989b979a50959850939692959293505050565b602081526000610cce60208301846163b6565b6000602082840312156166ef57600080fd5b610cce82616119565b60008060008060008060008060a0898b03121561671457600080fd5b883561671f81615ee7565b9750602089013561672f81615ee7565b965060408901356001600160401b0381111561674a57600080fd5b6167568b828c0161619e565b90975095505060608901356001600160401b0381111561677557600080fd5b6167818b828c0161619e565b90955093505060808901356001600160401b038111156167a057600080fd5b6162948b828c01615f07565b602080825282516001600160f01b03191682820152828101516001600160a01b03166040808401919091528301516060808401528051608084018190526000929190910190829060a08501905b808310156168255783516001600160501b031916825260209384019360019390930192909101906167f9565b5095945050505050565b60006020828403121561684157600080fd5b5035919050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b828110156168a157603f1987860301845261688c8583516163b6565b94506020938401939190910190600101616870565b50929695505050505050565b6000806000806000606086880312156168c557600080fd5b6168ce86616119565b945060208601356001600160401b038111156168e957600080fd5b6168f588828901615f07565b90955093505060408601356001600160401b03811115615fff57600080fd5b60008060008060008060a0878903121561692d57600080fd5b863561693881615ee7565b9550602087013561694881615ee7565b9450604087013593506060870135925060808701356001600160401b0381111561632057600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60018060a01b03851681528360208201526060604082015260006169c2606083018486616971565b9695505050505050565b60006001600160401b038211156169e5576169e56164be565b50601f01601f191660200190565b600060208284031215616a0557600080fd5b81516001600160401b03811115616a1b57600080fd5b8201601f81018413616a2c57600080fd5b8051616a3f616a3a826169cc565b61651f565b818152856020838501011115616a5457600080fd5b61095e826020830160208601616392565b60008085851115616a7557600080fd5b83861115616a8257600080fd5b5050820193919092039150565b80356001600160e01b03198116906004841015616ac0576001600160e01b0319600485900360031b81901b82161691505b5092915050565b600060208284031215616ad957600080fd5b8151610cce81616131565b6000808335601e19843603018112616afb57600080fd5b8301803591506001600160401b03821115616b1557600080fd5b602001915036819003821315615f4857600080fd5b600060208284031215616b3c57600080fd5b8151610cce81616147565b634e487b7160e01b600052603260045260246000fd5b8183823760009101908152919050565b80356bffffffffffffffffffffffff198116906014841015616ac0576bffffffffffffffffffffffff1960149490940360031b84901b1690921692915050565b602081526000610b2c602083018486616971565b9182526001600160a01b0316602082015260400190565b8035602083101561097857600019602084900360031b1b1692915050565b85815260018060a01b0385166020820152836040820152608060608201526000616c24608083018486616971565b979650505050505050565b600082601f830112616c4057600080fd5b8135616c4e616a3a826169cc565b818152846020838601011115616c6357600080fd5b816020850160208301376000918101602001919091529392505050565b60006101208236031215616c9357600080fd5b616c9b6164fc565b616ca483615efc565b81526020838101359082015260408301356001600160401b03811115616cc957600080fd5b616cd536828601616c2f565b60408301525060608301356001600160401b03811115616cf457600080fd5b616d0036828601616c2f565b6060830152506080838101359082015260a0808401359082015260c0808401359082015260e08301356001600160401b03811115616d3d57600080fd5b616d4936828601616c2f565b60e0830152506101008301356001600160401b03811115616d6957600080fd5b616d7536828601616c2f565b6101008301525092915050565b80516001600160a01b0316825260208101516020830152600060408201516101206040850152616db66101208501826163b6565b905060608301518482036060860152616dcf82826163b6565b9150506080830151608085015260a083015160a085015260c083015160c085015260e083015184820360e0860152616e0782826163b6565b91505061010083015184820361010086015261095e82826163b6565b604081526000616e366040830185616d82565b90508260208301529392505050565b600060208284031215616e5757600080fd5b5051919050565b838152606060208201526000616e776060830185616d82565b9050826040830152949350505050565b63ffffffff818116838216019081111561097857634e487b7160e01b600052601160045260246000fd5b828152604060208201526000610b2c60408301846163b6565b80356001600160c01b03198116906008841015616ac0576001600160c01b031960089490940360031b84901b1690921692915050565b828152604060208201526000610b2c6040830184616d82565b80356001600160501b03198116906016841015616ac0576001600160501b031960169490940360031b84901b1690921692915050565b838152818360208301376000910160200190815292915050565b80356001600160f01b03198116906002841015616ac0576001600160f01b031960029490940360031b84901b1690921692915050565b60008235605e19833603018112616fb557600080fd5b9190910192915050565b84815260018060a01b03841660208201528260408201526080606082015260006169c260808301846163b656fed21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e"; - bytes public constant KERNEL_FACTORY_BYTECODE = - hex"60a0604052348015600f57600080fd5b506040516104ce3803806104ce833981016040819052602c91603c565b6001600160a01b0316608052606a565b600060208284031215604d57600080fd5b81516001600160a01b0381168114606357600080fd5b9392505050565b60805161043d6100916000396000818160870152818160f10152610159015261043d6000f3fe6080604052600436106100345760003560e01c806348aac392146100395780635c60da1b14610075578063ea6d13ac146100a9575b600080fd5b34801561004557600080fd5b506100596100543660046103a2565b6100bc565b6040516001600160a01b03909116815260200160405180910390f35b34801561008157600080fd5b506100597f000000000000000000000000000000000000000000000000000000000000000081565b6100596100b73660046103a2565b610120565b6000808484846040516020016100d49392919061041b565b6040516020818303038152906040528051906020012090506101177f00000000000000000000000000000000000000000000000000000000000000008230610213565b95945050505050565b6000808484846040516020016101389392919061041b565b60405160208183030381529060405280519060200120905060008061017e347f00000000000000000000000000000000000000000000000000000000000000008561029c565b9150915081610209576000816001600160a01b031688886040516101a392919061042d565b6000604051808303816000865af19150503d80600081146101e0576040519150601f19603f3d011682016040523d82523d6000602084013e6101e5565b606091505b50509050806102075760405163487e630960e11b815260040160405180910390fd5b505b9695505050505050565b60008061028f85604080517fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f360609081527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e20768352616009602052601e9390935268603d3d8160223d3973600a52605f6021209152600090915290565b9050610117818585610380565b6000806040517fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f36060527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e207660405261600960205284601e5268603d3d8160223d3973600a52605f60212060358201523060581b815260ff8153836015820152605581209150813b6103485783605f602188f59150816103435763301164256000526004601cfd5b61036e565b60019250851561036e5760003860003889865af161036e5763b12d13eb6000526004601cfd5b80604052506000606052935093915050565b600060ff60005350603592835260601b60015260155260556000908120915290565b6000806000604084860312156103b757600080fd5b833567ffffffffffffffff8111156103ce57600080fd5b8401601f810186136103df57600080fd5b803567ffffffffffffffff8111156103f657600080fd5b86602082840101111561040857600080fd5b6020918201979096509401359392505050565b82848237909101908152602001919050565b818382376000910190815291905056"; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/NexusPrecompiles.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/NexusPrecompiles.sol deleted file mode 100644 index 6a82de4..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/NexusPrecompiles.sol +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { INexusAccountFactory } from "../../accounts/nexus/interfaces/INexusAccountFactory.sol"; -import { INexusBootstrap } from "../../accounts/nexus/interfaces/INexusBootstrap.sol"; -import { INexus } from "../../accounts/nexus/interfaces/INexus.sol"; - -// Utils -import { label } from "../../test/utils/Vm.sol"; -import { BytecodeDeployer } from "./BytecodeDeployer.sol"; - -/// @notice Nexus contracts precompiled using --via-ir -contract NexusPrecompiles is BytecodeDeployer { - /*////////////////////////////////////////////////////////////// - DEPLOY - //////////////////////////////////////////////////////////////*/ - - /// @notice Deploys Nexus from --via-ir precompiled bytecode - function deployNexus(address anEntryPoint) public returns (address nexus) { - // Concat constructor params to bytecode - bytes memory creationBytecode = bytes.concat(NEXUS_BYTECODE, abi.encode(anEntryPoint)); - // Deploy contract - nexus = _deploy(creationBytecode); - // Label contract - label(nexus, "Nexus"); - } - - /// @notice Deploys NexusProxy from --via-ir precompiled bytecode - function deployNexusProxy( - bytes32 salt, - address implementation, - bytes memory initCode - ) - internal - returns (address) - { - return _deploy2( - bytes.concat( - NEXUS_PROXY_BYTECODE, - abi.encode( - implementation, - abi.encodeWithSelector(INexus.initializeAccount.selector, initCode) - ) - ), - salt - ); - } - - /// @notice Deploys NexusAccountFactory from --via-ir precompiled bytecode - function deployNexusAccountFactory( - address implementation, - address owner - ) - public - returns (INexusAccountFactory factory) - { - // Concat constructor params to bytecode - bytes memory creationBytecode = - bytes.concat(NEXUS_ACCOUNT_FACTORY_BYTECODE, abi.encode(implementation, owner)); - // Deploy contract - factory = INexusAccountFactory(_deploy(creationBytecode)); - // Label contract - label(address(factory), "NexusAccountFactory"); - } - - /// @notice Deploys the NexusBootstrap contract from --via-ir precompiled bytecode - function deployNexusBootstrap() public returns (INexusBootstrap bootstrap) { - // Deploy contract - bootstrap = INexusBootstrap(_deploy(NEXUS_BOOTSTRAP_BYTECODE)); - // Label contract - label(address(bootstrap), "NexusBootstrap"); - } - - /*////////////////////////////////////////////////////////////// - BYTECODES - //////////////////////////////////////////////////////////////*/ - - /* solhint-disable max-line-length */ - bytes public constant NEXUS_BYTECODE = - hex"6101606040523061014052348015610015575f5ffd5b50604051615904380380615904833981016040819052610034916101d4565b306080524660a05260608061007d6040805180820182526005808252644e6578757360d81b602080840191909152835180850190945290835264312e302e3160d81b9083015291565b815160209283012081519183019190912060c082905260e0819052604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8152938401929092529082015246606082015230608082015260a090206101005250506001600160a01b038116610107576040516307e355bf60e31b815260040160405180910390fd5b6001600160a01b0381166101205261011d610123565b50610201565b7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0061016d7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01610179565b61017681610179565b50565b60015f908152602082905260409020546001600160a01b0316156101b0576040516329e42f3360e11b815260040160405180910390fd5b60015f818152602092909252604090912080546001600160a01b0319169091179055565b5f602082840312156101e4575f5ffd5b81516001600160a01b03811681146101fa575f5ffd5b9392505050565b60805160a05160c05160e05161010051610120516101405161562d6102d75f395f818161111801526127d101525f818161062a01528181610adf01528181610d7201528181610eae01528181610ef90152818161125b0152818161156b0152818161161101528181611ae201528181611b320152818161209e0152818161211a0152818161232f01526138b101525f818161260c01526128c301525f81816126c6015261297d01525f81816126a0015261295701525f8181612650015261290701525f818161262d01526128e4015261562d5ff3fe6080604052600436106101db575f3560e01c80638dd7712f11610101578063cd64f80a11610094578063e9ae5c5311610063578063e9ae5c53146106f2578063ea5f61d014610705578063eab77e1714610724578063f2dc691d14610737576101e2565b8063cd64f80a14610681578063d03c791414610694578063d691c964146106b3578063d86f2b3c146106d3576101e2565b8063aaf10f42116100d0578063aaf10f4214610608578063b0d691fe1461061c578063b46b61a91461064e578063c399ec881461066d576101e2565b80638dd7712f146105845780639517e29f146105975780639cfd7cff146105aa578063a71763a8146105f5576101e2565b80634b6a1419116101795780635faac46b116101485780635faac46b146104f35780636575f6aa146105205780637b1039991461053f57806384b0196e1461055d576101e2565b80634b6a1419146104a65780634d44560d146104b95780634f1ef286146104cc57806352d1902d146104df576101e2565b806319822f7c116101b557806319822f7c146103a95780633644e515146103d6578063481ddd23146103ea5780634a58db191461049c576101e2565b80630a664dba14610311578063112d3a7d146103425780631626ba7e14610371576101e2565b366101e257005b5f3660605f6102055f5160206155a65f395f51905f52546001600160a01b031690565b90506001600160a01b0381166102265761021f8484610756565b9150610305565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f60259061025a9033903490869036906004016148ba565b5f604051808303815f875af1158015610275573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261029c9190810190614982565b90506102a88585610756565b9250604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906102d6908490600401614a2a565b5f604051808303815f87803b1580156102ed575f5ffd5b505af11580156102ff573d5f5f3e3d5ffd5b50505050505b50915050805190602001f35b34801561031c575f5ffd5b5061032561096f565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561034d575f5ffd5b5061036161035c366004614aa0565b610993565b6040519015158152602001610339565b34801561037c575f5ffd5b5061039061038b366004614af8565b6109ab565b6040516001600160e01b03199091168152602001610339565b3480156103b4575f5ffd5b506103c86103c3366004614b57565b610ad2565b604051908152602001610339565b3480156103e1575f5ffd5b506103c8610d67565b3480156103f5575f5ffd5b50610474610404366004614bb6565b6001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260209081526040918290208251808401909352546001600160a01b038116808452600160a01b90910460f81b6001600160f81b031916929091018290529091565b604080516001600160f81b031990931683526001600160a01b03909116602083015201610339565b6104a4610d70565b005b6104a46104b4366004614bd1565b610da4565b6104a46104c7366004614c04565b610ea3565b6104a46104da366004614c2e565b610f58565b3480156104ea575f5ffd5b506103c8611115565b3480156104fe575f5ffd5b5061051261050d366004614c04565b611172565b604051610339929190614c66565b34801561052b575f5ffd5b506103c861053a366004614cc5565b611198565b34801561054a575f5ffd5b505f54610325906001600160a01b031681565b348015610568575f5ffd5b506105716111a8565b6040516103399796959493929190614cdc565b6104a4610592366004614d76565b611250565b6104a46105a5366004614aa0565b611560565b3480156105b5575f5ffd5b50604080518082018252601481527f6269636f6e6f6d792e6e657875732e312e302e30000000000000000000000000602082015290516103399190614a2a565b6104a4610603366004614aa0565b611606565b348015610613575f5ffd5b50610325611907565b348015610627575f5ffd5b507f0000000000000000000000000000000000000000000000000000000000000000610325565b348015610659575f5ffd5b50610390610668366004614af8565b61193e565b348015610678575f5ffd5b506103c8611ade565b6104a461068f366004614c2e565b611b27565b34801561069f575f5ffd5b506103616106ae366004614cc5565b611d62565b6106c66106c1366004614af8565b611dd0565b6040516103399190614db8565b3480156106de575f5ffd5b506103c86106ed366004614e1b565b61204e565b6104a4610700366004614af8565b61210f565b348015610710575f5ffd5b5061051261071f366004614c04565b6122f6565b6104a4610732366004614e52565b612324565b348015610742575f5ffd5b50610361610751366004614cc5565b612383565b5f80356001600160e01b03191681527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260408120805460609291906001600160a01b03811690600160a01b900460f81b81156108d3576001600160f81b03198116607f60f91b0361082c57816001600160a01b03166107d888886123dd565b6040516107e59190614eed565b5f60405180830381855afa9150503d805f811461081d576040519150601f19603f3d011682016040523d82523d5f602084013e610822565b606091505b50955093506108c1565b6001600160f81b0319811661089757816001600160a01b03163461085089896123dd565b60405161085d9190614eed565b5f6040518083038185875af1925050503d805f811461081d576040519150601f19603f3d011682016040523d82523d5f602084013e610822565b604051632e5bf3f960e21b81526001600160f81b0319821660048201526024015b60405180910390fd5b836108ce57845160208601fd5b610965565b5f3560e01c63150b7a02811463f23a6e61821463bc197c81831417171561091257600194506040519550600486528060e01b6020870152602486016040525b6001600160e01b03195f351685610962576040517f08c63e270000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016108b8565b50505b5050505092915050565b5f61098e5f5160206155a65f395f51905f52546001600160a01b031690565b905090565b5f6109a085858585612412565b90505b949350505050565b5f8181036109e4576109c061ffff8319614f17565b6109cc90617739614f36565b84036109e4576109dd84848461193e565b9050610acb565b5f6109f26014828587614f4d565b6109fb91614f74565b60601c9050610a09816124d1565b8190610a345760405163342cf00f60e11b81526001600160a01b0390911660048201526024016108b8565b506001600160a01b03811663f551e2ee3387610a53876014818b614f4d565b6040518563ffffffff1660e01b8152600401610a7294939291906148ba565b602060405180830381865afa925050508015610aab575060408051601f3d908101601f19168201909252610aa891810190614fb4565b60015b610ac057506001600160e01b03199050610acb565b9150610acb9050565b505b9392505050565b5f81336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610b1d57604051635629665f60e11b815260040160405180910390fd5b5f602086013560401c6001600160a01b03169050600160f81b602087013560031a60f81b03610c4d575f610b508761501c565b9050610b6986610b646101008a018a61511c565b6124e9565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250505050610100820152610bab826124d1565b8290610bd65760405163342cf00f60e11b81526001600160a01b0390911660048201526024016108b8565b50604051639700320360e01b81526001600160a01b03831690639700320390610c059084908a9060040161515f565b6020604051808303815f875af1158015610c21573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c45919061522b565b935050610d4f565b610c56816124d1565b15610cd057604051639700320360e01b81526001600160a01b03821690639700320390610c899089908990600401615359565b6020604051808303815f875af1158015610ca5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cc9919061522b565b9250610d4f565b60015f525f5160206155865f395f51905f526020527ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7546001600160a01b0316610d2b57610cc9610d2561010088018861511c565b87612576565b60405163342cf00f60e11b81526001600160a01b03821660048201526024016108b8565b508015610ac9575f385f3884335af150509392505050565b5f61098e61260a565b7f00000000000000000000000000000000000000000000000000000000000000005f38818134855af1610da1575f38fd5b50565b333014610db357610db36126ff565b610dbb612738565b5f80610dc98385018561537a565b915091505f826001600160a01b031682604051610de69190614eed565b5f60405180830381855af49150503d805f8114610e1e576040519150601f19603f3d011682016040523d82523d5f602084013e610e23565b606091505b5050905080610e5e576040517f315927c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e66612778565b610e9c576040517fc4d0a0b100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480610ed957503330145b610ef657604051635629665f60e11b815260040160405180910390fd5b5f7f0000000000000000000000000000000000000000000000000000000000000000905060405183601452826034526f205c28780000000000000000000000005f525f38604460105f865af1610f4e573d5f823e3d81fd5b505f603452505050565b5f610f775f5160206155a65f395f51905f52546001600160a01b031690565b90506001600160a01b038116610fe4576001600160a01b038416610fae5760405163325c055b60e21b815260040160405180910390fd5b833b151580610fd05760405163325c055b60e21b815260040160405180910390fd5b843055610fde8585856127cf565b5061110f565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f6025906110189033903490869036906004016148ba565b5f604051808303815f875af1158015611033573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261105a9190810190614982565b90506001600160a01b0385166110835760405163325c055b60e21b815260040160405180910390fd5b843b1515806110a55760405163325c055b60e21b815260040160405180910390fd5b8530556110b38686866127cf565b50604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906110e0908490600401614a2a565b5f604051808303815f87803b1580156110f7575f5ffd5b505af1158015611109573d5f5f3e3d5ffd5b50505050505b50505050565b5f7f000000000000000000000000000000000000000000000000000000000000000030811461114b57639f03a0265f526004601cfd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91505090565b60605f61118d5f5160206155865f395f51905f5285856128a7565b909590945092505050565b5f6111a2826128c1565b92915050565b7f0f000000000000000000000000000000000000000000000000000000000000006060805f80808361123e60408051808201825260058082527f4e6578757300000000000000000000000000000000000000000000000000000060208084019190915283518085019094529083527f312e302e310000000000000000000000000000000000000000000000000000009083015291565b97989097965046955030945091925090565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461129957604051635629665f60e11b815260040160405180910390fd5b5f6112b85f5160206155a65f395f51905f52546001600160a01b031690565b90506001600160a01b0381166113c657365f6112d7606086018661511c565b6112e5916004908290614f4d565b915091505f5f306001600160a01b031684846040516113059291906153c7565b5f60405180830381855af49150503d805f811461133d576040519150601f19603f3d011682016040523d82523d5f602084013e611342565b606091505b5091509150811561138b577fd3fddfd1276d1cc278f10907710a44474a32f917b2fcfa198f46ca7689215e2f878260405161137e9291906153d6565b60405180910390a16113bd565b6040517facfdb44400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f6025906113fa9033903490869036906004016148ba565b5f604051808303815f875af1158015611415573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261143c9190810190614982565b9050365f61144d606087018761511c565b61145b916004908290614f4d565b915091505f5f306001600160a01b0316848460405161147b9291906153c7565b5f60405180830381855af49150503d805f81146114b3576040519150601f19603f3d011682016040523d82523d5f602084013e6114b8565b606091505b5091509150811561138b577fd3fddfd1276d1cc278f10907710a44474a32f917b2fcfa198f46ca7689215e2f88826040516114f49291906153d6565b60405180910390a15050604051630b9dfbed60e11b81526001600160a01b038516925063173bf7da915061152c908490600401614a2a565b5f604051808303815f87803b158015611543575f5ffd5b505af1158015611555573d5f5f3e3d5ffd5b50505050505b505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061159657503330145b6115b357604051635629665f60e11b815260040160405180910390fd5b6115bf848484846129d7565b604080518581526001600160a01b03851660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123910160405180910390a150505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061163c57503330145b61165957604051635629665f60e11b815260040160405180910390fd5b5f6116785f5160206155a65f395f51905f52546001600160a01b031690565b90506001600160a01b03811661175b5761169485858585612412565b858590916116c757604051635f300b3960e11b815260048101929092526001600160a01b031660248201526044016108b8565b5050604080518681526001600160a01b03861660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e910160405180910390a1600185036117225761171d848484612bbc565b610e9c565b600285036117355761171d848484612c8a565b600385036117485761171d848484612d23565b6004850361171d5761171d848484612e2a565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f60259061178f9033903490869036906004016148ba565b5f604051808303815f875af11580156117aa573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526117d19190810190614982565b90506117df86868686612412565b8686909161181257604051635f300b3960e11b815260048101929092526001600160a01b031660248201526044016108b8565b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e910160405180910390a16001860361186d57611868858585612bbc565b6118a6565b6002860361188057611868858585612c8a565b6003860361189357611868858585612d23565b600486036118a6576118a6858585612e2a565b604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906118d2908490600401614a2a565b5f604051808303815f87803b1580156118e9575f5ffd5b505af11580156118fb573d5f5f3e3d5ffd5b50505050505050505050565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b03811661193b575030545b90565b60015f9081525f5160206155865f395f51905f5260208190527ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7548291906001600160a01b03165b6001600160a01b038116158015906119a857506001600160a01b038116600114155b15611ab3576040517ff551e2ee0000000000000000000000000000000000000000000000000000000081525f906001600160a01b0383169063f551e2ee906119fa9033908c908c908c906004016148ba565b602060405180830381865afa158015611a15573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a399190614fb4565b90507fffff00000000000000000000000000000000000000000000000000000000000081167f7739000000000000000000000000000000000000000000000000000000000000148015611a9857506001600160e01b0319808516908216115b15611aa1578093505b611aab8383612e67565b915050611986565b50506001600160e01b0319811615611acb5780611ad5565b6001600160e01b03195b95945050505050565b5f5f7f00000000000000000000000000000000000000000000000000000000000000009050306020526370a082315f526020806024601c845afa601f3d11166020510291505090565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611b7057604051635629665f60e11b815260040160405180910390fd5b611b7d6004848484612412565b6004849091611bb157604051635f300b3960e11b815260048101929092526001600160a01b031660248201526044016108b8565b50505f611bc85f5160206155865f395f51905f5290565b6001600160a01b0385165f908152600482016020526040812054919250819003611c48576001600160a01b0385165f81815260048401602090815260409182902042908190558251938452908301527f2841d18703faaff388732165e48fe431468531b1b1e626b1b7cbcbfc0d79c74091015b60405180910390a1610e9c565b611c56620151806003614f36565b611c6090826153fa565b4210611cb9576001600160a01b0385165f81815260048401602090815260409182902042908190558251938452908301527fcbd44a75f6935b5837022648b6c8487db984701200c5381c7c0f8c2b1d69b9da9101611c3b565b611cc662015180826153fa565b4210611d30576001600160a01b0385165f908152600483016020526040812055611cf1858585612e2a565b60408051600481526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e9101611c3b565b6040517f07f2f2d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81600881901b6001600160f81b031982161580611d8d57506001600160f81b03198216600160f81b145b80611da157506001600160f81b0319808316145b80156109a357506001600160f81b0319811615806109a357506001600160f81b03198116600160f81b146109a3565b6060611dee335f5160206155865f395f51905f525b60010190612eba565b3390611e32576040517fb927fe5e0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016108b8565b505f611e525f5160206155a65f395f51905f52546001600160a01b031690565b90506001600160a01b038116611f0057336002611e6f8282612ef2565b86600881901b6001600160f81b03198216611e9657611e8f888883612f74565b9550611ef7565b6001600160f81b03198216600160f81b03611eb657611e8f8888836130c9565b6001600160f81b031980831603611ed257611e8f888883613142565b604051632e5bf3f960e21b81526001600160f81b0319831660048201526024016108b8565b50505050610ac9565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f602590611f349033903490869036906004016148ba565b5f604051808303815f875af1158015611f4f573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611f769190810190614982565b9050336002611f858282612ef2565b87600881901b6001600160f81b03198216611fac57611fa5898983612f74565b9650611fe8565b6001600160f81b03198216600160f81b03611fcc57611fa58989836130c9565b6001600160f81b031980831603611ed257611fa5898983613142565b5050604051630b9dfbed60e11b81526001600160a01b038516925063173bf7da9150612018908490600401614a2a565b5f604051808303815f87803b15801561202f575f5ffd5b505af1158015612041573d5f5f3e3d5ffd5b5050505050509392505050565b6040517f35567e1a00000000000000000000000000000000000000000000000000000000815230600482015277ffffffffffffffffffffffffffffffffffffffffffffffff821660248201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906335567e1a90604401602060405180830381865afa1580156120eb573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111a2919061522b565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461215857604051635629665f60e11b815260040160405180910390fd5b5f6121775f5160206155a65f395f51905f52546001600160a01b031690565b90506001600160a01b0381166121ef5783600881901b6001600160f81b031982166121ac576121a7858583613290565b6121e8565b6001600160f81b03198216600160f81b036121cc576121a785858361335c565b6001600160f81b031980831603611ed2576121a78585836133c9565b505061110f565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f6025906122239033903490869036906004016148ba565b5f604051808303815f875af115801561223e573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526122659190810190614982565b905084600881901b6001600160f81b0319821661228c57612287868683613290565b6122c8565b6001600160f81b03198216600160f81b036122ac5761228786868361335c565b6001600160f81b031980831603611ed2576122878686836133c9565b5050604051630b9dfbed60e11b81526001600160a01b0383169063173bf7da906110e0908490600401614a2a565b60605f61118d7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0185856128a7565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061235a57503330145b61237757604051635629665f60e11b815260040160405180910390fd5b61110f8484848461346d565b5f6001820361239457506001919050565b600282036123a457506001919050565b600382036123b457506001919050565b600482036123c457506001919050565b816123d157506001919050565b505f919050565b919050565b6060604080513681016020019091529050601436018152365f602083013760408051601481019091523360601b905292915050565b5f6001850361242b57612424846124d1565b90506109a3565b6002850361243c576124248461353f565b600385036124b9575f6004831061246a5761245a60045f8587614f4d565b6124639161540d565b905061246d565b505f5b6001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260409020546001600160a01b0385811691161490506109a3565b600485036124ca5761242484613557565b505f6109a3565b5f6111a25f5160206155865f395f51905f5283612eba565b365f5f5f365f365f6124fb8a8a613590565b909e509c50949a5092985090965094509250905061252661251f87878e88886135e4565b8383613679565b61255c576040517f46fdc33300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612568858786866129d7565b505050505050935093915050565b5f5f6125e46125a9846020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c60042090565b86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061378d92505050565b9050306001600160a01b038216036125ff575f915050610acb565b506001949350505050565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030147f000000000000000000000000000000000000000000000000000000000000000046141661193b5750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f000000000000000000000000000000000000000000000000000000000000000060208201527f00000000000000000000000000000000000000000000000000000000000000009181019190915246606082015230608082015260a0902090565b7f90b772c2cb8a51aa7a8a65fc23543c6d022d5b3f8e2b92eed79fba7eef829300805c806127345763aed595955f526004601cfd5b5050565b5f5160206155865f395f51905f5261276f7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01613832565b610da181613832565b5f6001612794815f5160206155865f395f51905f525b90612e67565b6001600160a01b03161415801561098e57505f6127bf60015f5160206155865f395f51905f5261278e565b6001600160a01b03161415905090565b7f000000000000000000000000000000000000000000000000000000000000000030810361280457639f03a0265f526004601cfd5b61280d846138a6565b8360601b60601c93506352d1902d6001527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80602060016004601d895afa511461285f576355299b496001526004601dfd5b847fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f38a2849055811561110f57604051828482375f388483885af4610e9c573d5f823e3d81fd5b60605f6128b58585856138f9565b90969095509350505050565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030147f00000000000000000000000000000000000000000000000000000000000000004614166129b45750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f000000000000000000000000000000000000000000000000000000000000000060208201527f00000000000000000000000000000000000000000000000000000000000000009181019190915246606082015230608082015260a090205b6719010000000000005f5280601a5281603a52604260182090505f603a52919050565b5f6129f65f5160206155a65f395f51905f52546001600160a01b031690565b90506001600160a01b038116612aa5576001600160a01b038416612a2d57604051635316c18d60e01b815260040160405180910390fd5b60018503612a405761171d848484613aba565b60028503612a535761171d848484613b93565b60038503612a665761171d848484613c51565b60048503612a795761171d848484613fa5565b84612a895761171d8484846140fc565b6040516304c1896960e11b8152600481018690526024016108b8565b60405163d68f602560e01b81525f906001600160a01b0383169063d68f602590612ad99033903490869036906004016148ba565b5f604051808303815f875af1158015612af4573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612b1b9190810190614982565b90506001600160a01b038516612b4457604051635316c18d60e01b815260040160405180910390fd5b60018603612b5757611868858585613aba565b60028603612b6a57611868858585613b93565b60038603612b7d57611868858585613c51565b60048603612b9057611868858585613fa5565b85612ba0576118688585856140fc565b6040516304c1896960e11b8152600481018790526024016108b8565b5f5160206155865f395f51905f525f80612bd88585018661537a565b9092509050612be8838388614255565b612bf0612778565b612c26576040517fcc319d8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115555a5f5f638a91b0e360e01b85604051602401612c459190614a2a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b038b1693929190614328565b5f80612c988385018561537a565b91509150612cbf8286612cb55f5160206155865f395f51905f5290565b6001019190614255565b6113bd5a5f5f638a91b0e360e01b85604051602401612cde9190614a2a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b038a1693929190614328565b604080518082019091525f80825260208201525f5160206155865f395f51905f526002015f612d556004828688614f4d565b612d5e9161540d565b6001600160e01b03191681526020808201929092526040015f2082518154939092015160f81c600160a01b0274ffffffffffffffffffffffffffffffffffffffffff199093166001600160a01b0390921691909117919091179055610e9c5a5f80638a91b0e360e01b612dd4866004818a614f4d565b604051602401612de5929190615442565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b03881693929190614328565b5f5160206155a65f395f51905f5280546001600160a01b0319169055610e9c5a5f5f638a91b0e360e01b8686604051602401612de5929190615442565b5f6001600160a01b038216612e9a57604051637c84ecfb60e01b81526001600160a01b03831660048201526024016108b8565b506001600160a01b039081165f9081526020929092526040909120541690565b5f60016001600160a01b03831614801590610acb5750506001600160a01b039081165f90815260209290925260409091205416151590565b5f546001600160a01b0316801561155b576040517f96fb72170000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490528216906396fb7217906044015f6040518083038186803b158015612f62575f5ffd5b505afa1580156113bd573d5f5f3e3d5ffd5b60605f5f365f612f8488886143ae565b6040805160018082528183019092529498509296509094509250816020015b6060815260200190600190039081612fa357509095505f90506001600160f81b03198716612ff957612fd7858585856143fe565b865f81518110612fe957612fe9615455565b60200260200101819052506130bd565b6001600160f81b03198716600160f81b036130985761301a85858585614431565b875f8151811061302c5761302c615455565b6020908102919091010152905080613093577fb5282692b8c578af7fb880895d599035496b5e64d1f14bf428a1ed3bc406f6628383885f8151811061307357613073615455565b602002602001015160405161308a93929190615469565b60405180910390a15b6130bd565b6040516308c3ee0360e11b81526001600160f81b0319881660048201526024016108b8565b50505050509392505050565b6060833584016020810190356001600160f81b031984166130f5576130ee828261445f565b9250613139565b6001600160f81b03198416600160f81b03613114576130ee8282614535565b6040516308c3ee0360e11b81526001600160f81b0319851660048201526024016108b8565b50509392505050565b60605f365f613151878761466c565b6040805160018082528183019092529396509194509250816020015b606081526020019060019003908161316d57509094505f90506001600160f81b031986166131c2576131a08484846146a2565b855f815181106131b2576131b2615455565b6020026020010181905250613285565b6001600160f81b03198616600160f81b03613260576131e28484846146d3565b865f815181106131f4576131f4615455565b602090810291909101015290508061325b577f5bd4c60b4b38b664d8fb5944eb974e3d85083d79afe5ce934ccabcc913707c108383875f8151811061323b5761323b615455565b602002602001015160405161325293929190615469565b60405180910390a15b613285565b6040516308c3ee0360e11b81526001600160f81b0319871660048201526024016108b8565b505050509392505050565b5f5f365f61329e87876143ae565b929650909450925090506001600160f81b031985166132c8576132c3848484846146ff565b6113bd565b6001600160f81b03198516600160f81b03613337575f5f6132eb86868686614431565b9150915081613330577fb5282692b8c578af7fb880895d599035496b5e64d1f14bf428a1ed3bc406f66284848360405161332793929190615469565b60405180910390a15b50506113bd565b6040516308c3ee0360e11b81526001600160f81b0319861660048201526024016108b8565b823583016020810190356001600160f81b0319831661337f5761171d8282614723565b6001600160f81b03198316600160f81b036133a45761339e8282614535565b50610e9c565b6040516308c3ee0360e11b81526001600160f81b0319841660048201526024016108b8565b5f365f6133d6868661466c565b919450925090506001600160f81b031984166133fc576133f7838383614783565b613465565b6001600160f81b03198416600160f81b03613114575f5f61341e8585856146d3565b9150915081611555577f5bd4c60b4b38b664d8fb5944eb974e3d85083d79afe5ce934ccabcc913707c1084848360405161345a93929190615469565b60405180910390a150505b505050505050565b5f80546001600160a01b0319166001600160a01b03861690811790915515613506576040517ff05c04e10000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063f05c04e1906134d89084908790879060040161548e565b5f604051808303815f87803b1580156134ef575f5ffd5b505af1158015613501573d5f5f3e3d5ffd5b505050505b6040516001600160a01b038516907ff98c8404c5b1bfef2e6ba9233c6e88845aedfd36eea8b192725d8c199571cf32905f90a250505050565b5f6111a2825f5160206155865f395f51905f52611de5565b5f816001600160a01b03166135805f5160206155a65f395f51905f52546001600160a01b031690565b6001600160a01b03161492915050565b813560601c6014830135603880850190603486013560e090811c91603c838901818101939281013590921c9136915f9184018b9003016135d28a82818e614f4d565b92509250509295985092959890939650565b5f6040518060800160405280605b81526020016155c6605b91398051906020012086868686866040516136189291906153c7565b60405190819003812061365895949392916020019485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b60405160208183030381529060405280519060200120905095945050505050565b5f806136886014828587614f4d565b61369191614f74565b60601c905061369f816124d1565b6136c75760405163342cf00f60e11b81526001600160a01b03821660048201526024016108b8565b5f6136d1866128c1565b90506001600160a01b03821663f551e2ee30836136f1886014818c614f4d565b6040518563ffffffff1660e01b815260040161371094939291906148ba565b602060405180830381865afa925050508015613749575060408051601f3d908101601f1916820190925261374691810190614fb4565b60015b613757575f92505050610acb565b6001600160e01b0319167f1626ba7e00000000000000000000000000000000000000000000000000000000149250610acb915050565b5f6040518251604081146137a957604181146137e3575061381e565b604084015160ff81901c601b016020527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166060526137f6565b60608401515f1a60205260408401516060525b50835f5260208301516040526020600160805f60015afa5191505f606052806040523d61382b575b638baa579f5f526004601cfd5b5092915050565b60015f908152602082905260409020546001600160a01b031615613882576040517f53c85e6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015f818152602092909252604090912080546001600160a01b0319169091179055565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806138dc57503330145b610da157604051635629665f60e11b815260040160405180910390fd5b60605f6001600160a01b03841660011480159061391d575061391b8585612eba565b155b1561394657604051637c84ecfb60e01b81526001600160a01b03851660048201526024016108b8565b825f0361397f576040517ff725081700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8267ffffffffffffffff811115613998576139986148ec565b6040519080825280602002602001820160405280156139c1578160200160208202803683370190505b506001600160a01b038086165f90815260208890526040812054929450911691505b6001600160a01b03821615801590613a0557506001600160a01b038216600114155b8015613a1057508381105b15613a695781838281518110613a2857613a28615455565b6001600160a01b039283166020918202929092018101919091529281165f908152928790526040909220549091169080613a61816154e5565b9150506139e3565b6001600160a01b038216600114801590613a8257505f81115b15613aae5782613a936001836154fd565b81518110613aa357613aa3615455565b602002602001015191505b80835250935093915050565b826001613ac78282612ef2565b60405163ecd0596160e01b8152600160048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015613b0a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b2e9190615510565b613b4e576040516369c9a24560e11b8152600160048201526024016108b8565b613b655f5160206155865f395f51905f52866147a5565b6040516306d61fe760e41b81526001600160a01b03861690636d61fe70906110e09087908790600401615442565b826002613ba08282612ef2565b60405163ecd0596160e01b8152600260048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015613be3573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613c079190615510565b613c27576040516369c9a24560e11b8152600260048201526024016108b8565b613b657f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01866147a5565b826003613c5e8282612ef2565b60405163ecd0596160e01b8152600360048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015613ca1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613cc59190615510565b613ce5576040516369c9a24560e11b8152600360048201526024016108b8565b5f613cf36004828688614f4d565b613cfc9161540d565b90505f85856004818110613d1257613d12615455565b909101356001600160f81b031916915050801580613d3d57506001600160f81b03198116607f60f91b145b613d73576040517f867a1dcf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613d81866005818a614f4d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152509293505050506001600160e01b031983166306d61fe760e41b1480613de657506001600160e01b03198316638a91b0e360e01b145b80613df957506001600160e01b03198316155b15613e30576040517fc001660b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160e01b031983165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f02602052604090205483906001600160a01b031615613eb7576040517fa56a04dd0000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016108b8565b506040805180820182526001600160a01b038a81168083526001600160f81b0319861660208085019182526001600160e01b031989165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0290915285902093518454915160f81c600160a01b0274ffffffffffffffffffffffffffffffffffffffffff199092169316929092179190911790915590516306d61fe760e41b8152636d61fe7090613f6e908490600401614a2a565b5f604051808303815f87803b158015613f85575f5ffd5b505af1158015613f97573d5f5f3e3d5ffd5b505050505050505050505050565b826004613fb28282612ef2565b60405163ecd0596160e01b81526004808201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015613ff4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906140189190615510565b614037576040516369c9a24560e11b81526004818101526024016108b8565b5f6140565f5160206155a65f395f51905f52546001600160a01b031690565b9050806001600160a01b038116156140a6576040517f741cbe030000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016108b8565b505f5160206155a65f395f51905f5280546001600160a01b0319166001600160a01b0388161790556040516306d61fe760e41b81526001600160a01b03871690636d61fe70906118d29088908890600401615442565b81358201602081810191359084810135850190810190358281811461414d576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b81811015611109575f86868381811061416a5761416a615455565b905060200201359050600181036141ad576141a88a86868581811061419157614191615455565b90506020028101906141a3919061511c565b613aba565b61424c565b600281036141e2576141a88a8686858181106141cb576141cb615455565b90506020028101906141dd919061511c565b613b93565b60038103614217576141a88a86868581811061420057614200615455565b9050602002810190614212919061511c565b613c51565b6004810361424c5761424c8a86868581811061423557614235615455565b9050602002810190614247919061511c565b613fa5565b5060010161414f565b6001600160a01b038116158061427457506001600160a01b0381166001145b1561429d57604051637c84ecfb60e01b81526001600160a01b03831660048201526024016108b8565b6001600160a01b038281165f908152602085905260409020548116908216146142e457604051637c84ecfb60e01b81526001600160a01b03821660048201526024016108b8565b6001600160a01b039081165f8181526020949094526040808520805494841686529085208054949093166001600160a01b0319948516179092559092528154169055565b5f60605f5f5f8661ffff1667ffffffffffffffff81111561434b5761434b6148ec565b6040519080825280601f01601f191660200182016040528015614375576020820181803683370190505b5090505f5f8751602089018b8e8ef191503d925086831115614395578692505b828152825f602083013e90999098509650505050505050565b5f8036816143bf6014828789614f4d565b6143c891614f74565b60601c93506143db603460148789614f4d565b6143e49161552f565b92506143f38560348189614f4d565b949793965094505050565b604051818382375f38838387895af1614419573d5f823e3d81fd5b3d8152602081013d5f823e3d01604052949350505050565b6040515f90828482375f388483888a5af191503d8152602081013d5f823e3d81016040525094509492505050565b60608167ffffffffffffffff81111561447a5761447a6148ec565b6040519080825280602002602001820160405280156144ad57816020015b60608152602001906001900390816144985790505b509050365f5b8381101561452d578484828181106144cd576144cd615455565b90506020028101906144df919061554c565b91506145086144f1602084018461556a565b6020840135614503604086018661511c565b6143fe565b83828151811061451a5761451a615455565b60209081029190910101526001016144b3565b505092915050565b60608167ffffffffffffffff811115614550576145506148ec565b60405190808252806020026020018201604052801561458357816020015b606081526020019060019003908161456e5790505b509050365f5b8381101561452d578484828181106145a3576145a3615455565b90506020028101906145b5919061554c565b91505f6145df6145c8602085018561556a565b60208501356145da604087018761511c565b614431565b8584815181106145f1576145f1615455565b6020908102919091010152905080614663577fb5282692b8c578af7fb880895d599035496b5e64d1f14bf428a1ed3bc406f662614631604085018561511c565b86858151811061464357614643615455565b602002602001015160405161465a93929190615469565b60405180910390a15b50600101614589565b5f368161467c6014828688614f4d565b61468591614f74565b60601c92506146978460148188614f4d565b915091509250925092565b604051818382375f388383875af46146bc573d5f823e3d81fd5b3d8152602081013d5f823e3d016040529392505050565b6040515f90828482375f388483885af491503d8152602081013d5f823e3d810160405250935093915050565b604051818382375f38838387895af161471a573d5f823e3d81fd5b01604052505050565b365f5b8281101561110f5783838281811061474057614740615455565b9050602002810190614752919061554c565b915061477b614764602084018461556a565b6020840135614776604086018661511c565b6146ff565b600101614726565b604051818382375f388383875af461479d573d5f823e3d81fd5b016040525050565b6001600160a01b03811615806147c457506001600160a01b0381166001145b156147ed57604051637c84ecfb60e01b81526001600160a01b03821660048201526024016108b8565b6001600160a01b038181165f908152602084905260409020541615614849576040517f40d3d1a40000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108b8565b60015f818152602093909352604080842080546001600160a01b039485168087529286208054959091166001600160a01b03199586161790559190935280549091169091179055565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b0385168152836020820152606060408201525f6148e2606083018486614892565b9695505050505050565b634e487b7160e01b5f52604160045260245ffd5b604051610120810167ffffffffffffffff81118282101715614924576149246148ec565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614953576149536148ec565b604052919050565b5f67ffffffffffffffff821115614974576149746148ec565b50601f01601f191660200190565b5f60208284031215614992575f5ffd5b815167ffffffffffffffff8111156149a8575f5ffd5b8201601f810184136149b8575f5ffd5b80516149cb6149c68261495b565b61492a565b8181528560208385010111156149df575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610acb60208301846149fc565b6001600160a01b0381168114610da1575f5ffd5b80356123d881614a3c565b5f5f83601f840112614a6b575f5ffd5b50813567ffffffffffffffff811115614a82575f5ffd5b602083019150836020828501011115614a99575f5ffd5b9250929050565b5f5f5f5f60608587031215614ab3575f5ffd5b843593506020850135614ac581614a3c565b9250604085013567ffffffffffffffff811115614ae0575f5ffd5b614aec87828801614a5b565b95989497509550505050565b5f5f5f60408486031215614b0a575f5ffd5b83359250602084013567ffffffffffffffff811115614b27575f5ffd5b614b3386828701614a5b565b9497909650939450505050565b5f6101208284031215614b51575f5ffd5b50919050565b5f5f5f60608486031215614b69575f5ffd5b833567ffffffffffffffff811115614b7f575f5ffd5b614b8b86828701614b40565b9660208601359650604090950135949350505050565b6001600160e01b031981168114610da1575f5ffd5b5f60208284031215614bc6575f5ffd5b8135610acb81614ba1565b5f5f60208385031215614be2575f5ffd5b823567ffffffffffffffff811115614bf8575f5ffd5b6128b585828601614a5b565b5f5f60408385031215614c15575f5ffd5b8235614c2081614a3c565b946020939093013593505050565b5f5f5f60408486031215614c40575f5ffd5b8335614c4b81614a3c565b9250602084013567ffffffffffffffff811115614b27575f5ffd5b604080825283519082018190525f9060208501906060840190835b81811015614ca85783516001600160a01b0316835260209384019390920191600101614c81565b505080925050506001600160a01b03831660208301529392505050565b5f60208284031215614cd5575f5ffd5b5035919050565b6001600160f81b03198816815260e060208201525f614cfe60e08301896149fc565b8281036040840152614d1081896149fc565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015614d65578351835260209384019390920191600101614d47565b50909b9a5050505050505050505050565b5f5f60408385031215614d87575f5ffd5b823567ffffffffffffffff811115614d9d575f5ffd5b614da985828601614b40565b95602094909401359450505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015614e0f57603f19878603018452614dfa8583516149fc565b94506020938401939190910190600101614dde565b50929695505050505050565b5f60208284031215614e2b575f5ffd5b813577ffffffffffffffffffffffffffffffffffffffffffffffff81168114610acb575f5ffd5b5f5f5f5f60608587031215614e65575f5ffd5b8435614e7081614a3c565b9350602085013567ffffffffffffffff811115614e8b575f5ffd5b8501601f81018713614e9b575f5ffd5b803567ffffffffffffffff811115614eb1575f5ffd5b8760208260051b8401011115614ec5575f5ffd5b60209190910193509150604085013560ff81168114614ee2575f5ffd5b939692955090935050565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52601160045260245ffd5b5f82614f3157634e487b7160e01b5f52601260045260245ffd5b500490565b80820281158282048414176111a2576111a2614f03565b5f5f85851115614f5b575f5ffd5b83861115614f67575f5ffd5b5050820193919092039150565b80356bffffffffffffffffffffffff19811690601484101561382b576bffffffffffffffffffffffff1960149490940360031b84901b1690921692915050565b5f60208284031215614fc4575f5ffd5b8151610acb81614ba1565b5f82601f830112614fde575f5ffd5b8135614fec6149c68261495b565b818152846020838601011115615000575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f610120823603121561502d575f5ffd5b615035614900565b61503e83614a50565b815260208381013590820152604083013567ffffffffffffffff811115615063575f5ffd5b61506f36828601614fcf565b604083015250606083013567ffffffffffffffff81111561508e575f5ffd5b61509a36828601614fcf565b6060830152506080838101359082015260a0808401359082015260c0808401359082015260e083013567ffffffffffffffff8111156150d7575f5ffd5b6150e336828601614fcf565b60e08301525061010083013567ffffffffffffffff811115615103575f5ffd5b61510f36828601614fcf565b6101008301525092915050565b5f5f8335601e19843603018112615131575f5ffd5b83018035915067ffffffffffffffff82111561514b575f5ffd5b602001915036819003821315614a99575f5ffd5b604081526151796040820184516001600160a01b03169052565b602083015160608201525f6040840151610120608084015261519f6101608401826149fc565b90506060850151603f198483030160a08501526151bc82826149fc565b915050608085015160c084015260a085015160e084015260c085015161010084015260e0850151603f19848303016101208501526151fa82826149fc565b915050610100850151603f198483030161014085015261521a82826149fc565b925050508260208301529392505050565b5f6020828403121561523b575f5ffd5b5051919050565b5f5f8335601e19843603018112615257575f5ffd5b830160208101925035905067ffffffffffffffff811115615276575f5ffd5b803603821315614a99575f5ffd5b61529e8261529183614a50565b6001600160a01b03169052565b602081810135908301525f6152b66040830183615242565b61012060408601526152cd61012086018284614892565b9150506152dd6060840184615242565b85830360608701526152f0838284614892565b6080868101359088015260a0808701359088015260c08087013590880152925061532091505060e0840184615242565b85830360e0870152615333838284614892565b92505050615345610100840184615242565b8583036101008701526148e2838284614892565b604081525f61536b6040830185615284565b90508260208301529392505050565b5f5f6040838503121561538b575f5ffd5b823561539681614a3c565b9150602083013567ffffffffffffffff8111156153b1575f5ffd5b6153bd85828601614fcf565b9150509250929050565b818382375f9101908152919050565b604081525f6153e86040830185615284565b8281036020840152611ad581856149fc565b808201808211156111a2576111a2614f03565b80356001600160e01b0319811690600484101561382b576001600160e01b0319808560040360031b1b82161691505092915050565b602081525f6109a3602083018486614892565b634e487b7160e01b5f52603260045260245ffd5b604081525f61547c604083018587614892565b82810360208401526148e281856149fc565b60ff8416815260406020820181905281018290525f8360608301825b858110156154da5782356154bd81614a3c565b6001600160a01b03168252602092830192909101906001016154aa565b509695505050505050565b5f600182016154f6576154f6614f03565b5060010190565b818103818111156111a2576111a2614f03565b5f60208284031215615520575f5ffd5b81518015158114610acb575f5ffd5b803560208310156111a2575f19602084900360031b1b1692915050565b5f8235605e19833603018112615560575f5ffd5b9190910192915050565b5f6020828403121561557a575f5ffd5b8135610acb81614a3c56fe0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f000bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f034d6f64756c65456e61626c654d6f64652861646472657373206d6f64756c652c75696e74323536206d6f64756c65547970652c6279746573333220757365724f70486173682c6279746573333220696e6974446174614861736829a164736f6c634300081b000a"; - bytes public constant NEXUS_ACCOUNT_FACTORY_BYTECODE = - hex"60a060405234801561000f575f5ffd5b50604051610fe5380380610fe583398101604081905261002e916100f1565b8061003881610099565b506001600160a01b03821661006057604051630abd577760e01b815260040160405180910390fd5b6001600160a01b038116610087576040516342bcdf7f60e11b815260040160405180910390fd5b506001600160a01b0316608052610122565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b80516001600160a01b03811681146100ec575f5ffd5b919050565b5f5f60408385031215610102575f5ffd5b61010b836100d6565b9150610119602084016100d6565b90509250929050565b608051610e9e6101475f395f818160ed015281816104a801526105ca0152610e9e5ff3fe6080604052600436106100ce575f3560e01c80638da5cb5b1161007c578063f04e283e11610057578063f04e283e146101b8578063f2fde38b146101cb578063fafa2b42146101de578063fee81cf4146101fd575f5ffd5b80638da5cb5b1461016e578063b36f970514610186578063ea6d13ac146101a5575f5ffd5b80634a1ce599116100ac5780634a1ce5991461013f57806354d1f13d1461015e578063715018a614610166575f5ffd5b806325692962146100d2578063290ab984146100dc578063451711591461012c575b5f5ffd5b6100da61023c565b005b3480156100e7575f5ffd5b5061010f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6100da61013a366004610913565b610289565b34801561014a575f5ffd5b506100da610159366004610952565b610332565b6100da6103b2565b6100da6103eb565b348015610179575f5ffd5b50638b78c6d8195461010f565b348015610191575f5ffd5b506100da6101a0366004610974565b6103fe565b61010f6101b33660046109a0565b6104a0565b6100da6101c6366004610952565b610561565b6100da6101d9366004610952565b61059e565b3480156101e9575f5ffd5b5061010f6101f83660046109a0565b6105c4565b348015610208575f5ffd5b5061022e610217366004610952565b63389a75e1600c9081525f91909152602090205490565b604051908152602001610123565b5f6202a30067ffffffffffffffff164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f5fa250565b61029161062d565b6001600160a01b0382166102b8576040516391fdf19160e01b815260040160405180910390fd5b6040517f0396cb6000000000000000000000000000000000000000000000000000000000815263ffffffff821660048201526001600160a01b03831690630396cb609034906024015f604051808303818588803b158015610317575f5ffd5b505af1158015610329573d5f5f3e3d5ffd5b50505050505050565b61033a61062d565b6001600160a01b038116610361576040516391fdf19160e01b815260040160405180910390fd5b806001600160a01b031663bb9fe6bf6040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610399575f5ffd5b505af11580156103ab573d5f5f3e3d5ffd5b5050505050565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f5fa2565b6103f361062d565b6103fc5f610647565b565b61040661062d565b6001600160a01b03821661042d576040516391fdf19160e01b815260040160405180910390fd5b6040517fc23a5cea0000000000000000000000000000000000000000000000000000000081526001600160a01b03828116600483015283169063c23a5cea906024015f604051808303815f87803b158015610486575f5ffd5b505af1158015610498573d5f5f3e3d5ffd5b505050505050565b5f5f5f6105037f00000000000000000000000000000000000000000000000000000000000000008588888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061068492505050565b91509150816105585783868660405161051d929190610a12565b604051908190038120906001600160a01b038416907f47e5b5fc3bda028416e26dcf66ca5186488c0717e8ab55bb01806113f1839d58905f90a45b95945050505050565b61056961062d565b63389a75e1600c52805f526020600c20805442111561058f57636f5e88185f526004601cfd5b5f905561059b81610647565b50565b6105a661062d565b8060601b6105bb57637448fbae5f526004601cfd5b61059b81610647565b5f6106257f00000000000000000000000000000000000000000000000000000000000000008386868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506107c792505050565b949350505050565b638b78c6d8195433146103fc576382b429005f526004601cfd5b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b5f5f6106918585856107c7565b90505f816001600160a01b03163b1191508161073457833486856040516024016106bb9190610a4f565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16634b6a141960e01b17905251610704906108f2565b61070f929190610a61565b82906040518091039083f59150508015801561072d573d5f5f3e3d5ffd5b50506107bf565b5f816001600160a01b0316346040515f6040518083038185875af1925050503d805f811461077d576040519150601f19603f3d011682016040523d82523d5f602084013e610782565b606091505b50509050806107bd576040517f6d963f8800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b935093915050565b5f5f604051806020016107d9906108f2565b6020820181038252601f19601f8201166040525085846040516024016107ff9190610a4f565b60408051601f19818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16634b6a141960e01b179052905161084d93929101610a61565b60408051601f198184030181529082905261086b9291602001610a99565b60408051601f1981840301815282825280516020918201207fff00000000000000000000000000000000000000000000000000000000000000828501523060601b6bffffffffffffffffffffffff19166021850152603584019790975260558084019790975281518084039097018752607590920190528451940193909320949350505050565b6103e480610aae83390190565b6001600160a01b038116811461059b575f5ffd5b5f5f60408385031215610924575f5ffd5b823561092f816108ff565b9150602083013563ffffffff81168114610947575f5ffd5b809150509250929050565b5f60208284031215610962575f5ffd5b813561096d816108ff565b9392505050565b5f5f60408385031215610985575f5ffd5b8235610990816108ff565b91506020830135610947816108ff565b5f5f5f604084860312156109b2575f5ffd5b833567ffffffffffffffff8111156109c8575f5ffd5b8401601f810186136109d8575f5ffd5b803567ffffffffffffffff8111156109ee575f5ffd5b8660208284010111156109ff575f5ffd5b6020918201979096509401359392505050565b818382375f9101908152919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61096d6020830184610a21565b6001600160a01b0383168152604060208201525f6106256040830184610a21565b5f81518060208401855e5f93019283525090919050565b5f610625610aa78386610a82565b84610a8256fe60806040526040516103e43803806103e48339810160408190526100229161026c565b61002a61003b565b6100348282610063565b5050610351565b7f90b772c2cb8a51aa7a8a65fc23543c6d022d5b3f8e2b92eed79fba7eef8293006001815d50565b61006c826100c1565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156100b5576100b0828261013c565b505050565b6100bd6101af565b5050565b806001600160a01b03163b5f036100fb57604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f5f846001600160a01b031684604051610158919061033b565b5f60405180830381855af49150503d805f8114610190576040519150601f19603f3d011682016040523d82523d5f602084013e610195565b606091505b5090925090506101a68583836101d0565b95945050505050565b34156101ce5760405163b398979f60e01b815260040160405180910390fd5b565b6060826101e5576101e08261022f565b610228565b81511580156101fc57506001600160a01b0384163b155b1561022557604051639996b31560e01b81526001600160a01b03851660048201526024016100f2565b50805b9392505050565b80511561023f5780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b634e487b7160e01b5f52604160045260245ffd5b5f5f6040838503121561027d575f5ffd5b82516001600160a01b0381168114610293575f5ffd5b60208401519092506001600160401b038111156102ae575f5ffd5b8301601f810185136102be575f5ffd5b80516001600160401b038111156102d7576102d7610258565b604051601f8201601f19908116603f011681016001600160401b038111828210171561030557610305610258565b60405281815282820160200187101561031c575f5ffd5b8160208401602083015e5f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b60878061035d5f395ff3fe6080604052600a600c565b005b60186014601a565b605d565b565b5f60587f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b905090565b365f5f375f5f365f845af43d5f5f3e8080156076573d5ff35b3d5ffdfea164736f6c634300081b000aa164736f6c634300081b000a"; - bytes public constant NEXUS_BOOTSTRAP_BYTECODE = - hex"610120604052348015600f575f5ffd5b50306080524660a0526060806061604080518082018252600e81526d04e65787573426f6f7473747261760941b602080830191909152825180840190935260058352640312e302e360dc1b9083015291565b815160209283012081519183019190912060c082905260e0819052604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8152938401929092529082015246606082015230608082015260a09020610100525060c99050565b60805160a05160c05160e051610100516122b36100f75f395f50505f50505f50505f50505f50506122b35ff3fe6080604052600436106100ca575f3560e01c8063837b892e116100735780639e2533ed1161004d5780639e2533ed1461040d578063d6fe71f11461042c578063ea5f61d01461043f576100d1565b8063837b892e1461039b57806384b0196e146103c757806385a924cc146103ee576100d1565b806355470cf1116100a457806355470cf11461033d5780635faac46b146103505780637b1039991461037d576100d1565b806301fe9ff2146102455780630a664dba1461025a578063481ddd231461028b576100d1565b366100d157005b5f3660605f6101077f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03546001600160a01b031690565b90506001600160a01b03811661012857610121848461045e565b9150610239565b6040517fd68f60250000000000000000000000000000000000000000000000000000000081525f906001600160a01b0383169063d68f60259061017590339034908690369060040161188d565b5f604051808303815f875af1158015610190573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526101b791908101906118d3565b90506101c3858561045e565b92506040517f173bf7da0000000000000000000000000000000000000000000000000000000081526001600160a01b0383169063173bf7da9061020a9084906004016119b4565b5f604051808303815f87803b158015610221575f5ffd5b505af1158015610233573d5f5f3e3d5ffd5b50505050505b50915050805190602001f35b610258610253366004611a45565b61068e565b005b348015610265575f5ffd5b5061026e6106ae565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610296575f5ffd5b506103156102a5366004611b16565b6001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260209081526040918290208251808401909352546001600160a01b038116808452600160a01b90910460f81b6001600160f81b031916929091018290529091565b604080516001600160f81b031990931683526001600160a01b03909116602083015201610282565b61025861034b366004611b53565b6106e5565b34801561035b575f5ffd5b5061036f61036a366004611bc7565b6107ae565b604051610282929190611bf1565b348015610388575f5ffd5b505f5461026e906001600160a01b031681565b3480156103a6575f5ffd5b506103ba6103b5366004611c50565b6107e7565b60405161028291906119b4565b3480156103d2575f5ffd5b506103db61087c565b6040516102829796959493929190611cdd565b3480156103f9575f5ffd5b506103ba610408366004611b53565b610924565b348015610418575f5ffd5b506103ba610427366004611d77565b6109ad565b61025861043a366004611d77565b610a42565b34801561044a575f5ffd5b5061036f610459366004611bc7565b610c6e565b5f80356001600160e01b03191681527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260408120805460609291906001600160a01b03811690600160a01b900460f81b81156105f2576104c581607f60f91b610c9c565b1561053257816001600160a01b03166104de8888610cb3565b6040516104eb9190611e90565b5f60405180830381855afa9150503d805f8114610523576040519150601f19603f3d011682016040523d82523d5f602084013e610528565b606091505b50955093506105e0565b61053c815f610c9c565b1561059d57816001600160a01b0316346105568989610cb3565b6040516105639190611e90565b5f6040518083038185875af1925050503d805f8114610523576040519150601f19603f3d011682016040523d82523d5f602084013e610528565b6040517fb96fcfe40000000000000000000000000000000000000000000000000000000081526001600160f81b0319821660048201526024015b60405180910390fd5b836105ed57845160208601fd5b610684565b5f3560e01c63150b7a02811463f23a6e61821463bc197c81831417171561063157600194506040519550600486528060e01b6020870152602486016040525b6001600160e01b03195f351685610681576040517f08c63e270000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016105d7565b50505b5050505092915050565b61069a84848484610ce8565b6106a5878787610dc7565b50505050505050565b5f6106e07f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03546001600160a01b031690565b905090565b6106f184848484610ce8565b5f5b8681101561076f5761076788888381811061071057610710611ea6565b90506020028101906107229190611eba565b610730906020810190611ed8565b89898481811061074257610742611ea6565b90506020028101906107549190611eba565b610762906020810190611ef3565b610dc7565b6001016106f3565b505f61077e6020870187611ed8565b6001600160a01b0316146106a5576106a561079c6020870187611ed8565b6107a96020880188611ef3565b610ee7565b60605f6107dc7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0085856110a6565b909590945092505050565b606030806301fe9ff26107fd60208a018a611ed8565b61080a60208b018b611ef3565b8a8a8a8a6040516024016108249796959493929190611f7e565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050604051602001610862929190611fda565b604051602081830303815290604052905095945050505050565b7f0f000000000000000000000000000000000000000000000000000000000000006060805f808083610912604080518082018252600e81527f4e65787573426f6f7473747261700000000000000000000000000000000000006020808301919091528251808401909352600583527f312e302e300000000000000000000000000000000000000000000000000000009083015291565b97989097965046955030945091925090565b606030306001600160a01b03166355470cf18a8a8a8a8a8a8a60405160240161095397969594939291906120e4565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050604051602001610991929190611fda565b6040516020818303038152906040529050979650505050505050565b606030306001600160a01b031663d6fe71f18e8e8e8e8e8e8e8e8e8e8e6040516024016109e49b9a9998979695949392919061212d565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050604051602001610a22929190611fda565b60405160208183030381529060405290509b9a5050505050505050505050565b610a4e84848484610ce8565b5f5b8a811015610aa757610a9f8c8c83818110610a6d57610a6d611ea6565b9050602002810190610a7f9190611eba565b610a8d906020810190611ed8565b8d8d8481811061074257610742611ea6565b600101610a50565b505f5b88811015610b67575f8a8a83818110610ac557610ac5611ea6565b9050602002810190610ad79190611eba565b610ae5906020810190611ed8565b6001600160a01b031614610b5f57610b5f8a8a83818110610b0857610b08611ea6565b9050602002810190610b1a9190611eba565b610b28906020810190611ed8565b8b8b84818110610b3a57610b3a611ea6565b9050602002810190610b4c9190611eba565b610b5a906020810190611ef3565b6110c0565b600101610aaa565b505f610b766020890189611ed8565b6001600160a01b031614610ba157610ba1610b946020890189611ed8565b6107a960208a018a611ef3565b5f5b85811015610c60575f878783818110610bbe57610bbe611ea6565b9050602002810190610bd09190611eba565b610bde906020810190611ed8565b6001600160a01b031614610c5857610c58878783818110610c0157610c01611ea6565b9050602002810190610c139190611eba565b610c21906020810190611ed8565b888884818110610c3357610c33611ea6565b9050602002810190610c459190611eba565b610c53906020810190611ef3565b61117e565b600101610ba3565b505050505050505050505050565b60605f6107dc7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0185856110a6565b6001600160f81b0319828116908216145b92915050565b6060604080513681016020019091529050601436018152365f602083013760408051601481019091523360601b905292915050565b5f805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03861690811790915515610d8e576040517ff05c04e10000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063f05c04e190610d60908490879087906004016121bc565b5f604051808303815f87803b158015610d77575f5ffd5b505af1158015610d89573d5f5f3e3d5ffd5b505050505b6040516001600160a01b038516907ff98c8404c5b1bfef2e6ba9233c6e88845aedfd36eea8b192725d8c199571cf32905f90a250505050565b826001610dd482826114e9565b60405163ecd0596160e01b8152600160048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015610e17573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e3b91906121d8565b610e5b576040516369c9a24560e11b8152600160048201526024016105d7565b610e857f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0086611570565b6040516306d61fe760e41b81526001600160a01b03861690636d61fe7090610eb390879087906004016121f7565b5f604051808303815f87803b158015610eca575f5ffd5b505af1158015610edc573d5f5f3e3d5ffd5b505050505050505050565b826004610ef482826114e9565b60405163ecd0596160e01b81526004808201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015610f36573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f5a91906121d8565b610f79576040516369c9a24560e11b81526004818101526024016105d7565b5f610fab7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03546001600160a01b031690565b9050806001600160a01b03811615610ffb576040517f741cbe030000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016105d7565b507f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0388161790556040516306d61fe760e41b81526001600160a01b03871690636d61fe709061107190889088906004016121f7565b5f604051808303815f87803b158015611088575f5ffd5b505af115801561109a573d5f5f3e3d5ffd5b50505050505050505050565b60605f6110b485858561166a565b90969095509350505050565b8260026110cd82826114e9565b60405163ecd0596160e01b8152600260048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015611110573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061113491906121d8565b611154576040516369c9a24560e11b8152600260048201526024016105d7565b610e857f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0186611570565b82600361118b82826114e9565b60405163ecd0596160e01b8152600360048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa1580156111ce573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111f291906121d8565b611212576040516369c9a24560e11b8152600360048201526024016105d7565b5f611220600482868861220a565b61122991612231565b90505f8585600481811061123f5761123f611ea6565b9050013560f81c60f81b9050611258815f60f81b610c9c565b8061126c575061126c81607f60f91b610c9c565b6112a2576040517f867a1dcf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112b0866005818a61220a565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152509293505050506001600160e01b031983166306d61fe760e41b148061132e57506001600160e01b031983167f8a91b0e300000000000000000000000000000000000000000000000000000000145b8061134157506001600160e01b03198316155b15611378576040517fc001660b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160e01b031983165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f02602052604090205483906001600160a01b0316156113ff576040517fa56a04dd0000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016105d7565b506040805180820182526001600160a01b038a81168083526001600160f81b0319861660208085019182526001600160e01b031989165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0290915285902093518454915160f81c600160a01b027fffffffffffffffffffffff0000000000000000000000000000000000000000009092169316929092179190911790915590516306d61fe760e41b8152636d61fe70906114c09084906004016119b4565b5f604051808303815f87803b1580156114d7575f5ffd5b505af1158015610c60573d5f5f3e3d5ffd5b5f546001600160a01b0316801561156b576040517f96fb72170000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490528216906396fb7217906044015f6040518083038186803b158015611559575f5ffd5b505afa1580156106a5573d5f5f3e3d5ffd5b505050565b6001600160a01b038116158061158f57506001600160a01b0381166001145b156115b857604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105d7565b6001600160a01b038181165f908152602084905260409020541615611614576040517f40d3d1a40000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016105d7565b60015f818152602093909352604080842080546001600160a01b0394851680875292862080549590911673ffffffffffffffffffffffffffffffffffffffff199586161790559190935280549091169091179055565b60605f6001600160a01b03841660011480159061168e575061168c858561182b565b155b156116b757604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105d7565b825f036116f0576040517ff725081700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8267ffffffffffffffff811115611709576117096118bf565b604051908082528060200260200182016040528015611732578160200160208202803683370190505b506001600160a01b038086165f90815260208890526040812054929450911691505b6001600160a01b0382161580159061177657506001600160a01b038216600114155b801561178157508381105b156117da578183828151811061179957611799611ea6565b6001600160a01b039283166020918202929092018101919091529281165f9081529287905260409092205490911690806117d28161227b565b915050611754565b6001600160a01b0382166001148015906117f357505f81115b1561181f5782611804600183612293565b8151811061181457611814611ea6565b602002602001015191505b80835250935093915050565b5f60016001600160a01b0383161480159061185e57506001600160a01b038281165f908152602085905260409020541615155b9392505050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b0385168152836020820152606060408201525f6118b5606083018486611865565b9695505050505050565b634e487b7160e01b5f52604160045260245ffd5b5f602082840312156118e3575f5ffd5b815167ffffffffffffffff8111156118f9575f5ffd5b8201601f81018413611909575f5ffd5b805167ffffffffffffffff811115611923576119236118bf565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715611952576119526118bf565b604052818152828201602001861015611969575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61185e6020830184611986565b6001600160a01b03811681146119da575f5ffd5b50565b80356119e8816119c6565b919050565b5f5f83601f8401126119fd575f5ffd5b50813567ffffffffffffffff811115611a14575f5ffd5b6020830191508360208260051b8501011115611a2e575f5ffd5b9250929050565b803560ff811681146119e8575f5ffd5b5f5f5f5f5f5f5f60a0888a031215611a5b575f5ffd5b8735611a66816119c6565b9650602088013567ffffffffffffffff811115611a81575f5ffd5b8801601f81018a13611a91575f5ffd5b803567ffffffffffffffff811115611aa7575f5ffd5b8a6020828401011115611ab8575f5ffd5b60209190910196509450611ace604089016119dd565b9350606088013567ffffffffffffffff811115611ae9575f5ffd5b611af58a828b016119ed565b9094509250611b08905060808901611a35565b905092959891949750929550565b5f60208284031215611b26575f5ffd5b81356001600160e01b03198116811461185e575f5ffd5b5f60408284031215611b4d575f5ffd5b50919050565b5f5f5f5f5f5f5f60a0888a031215611b69575f5ffd5b873567ffffffffffffffff811115611b7f575f5ffd5b611b8b8a828b016119ed565b909850965050602088013567ffffffffffffffff811115611baa575f5ffd5b611bb68a828b01611b3d565b9550506040880135611ace816119c6565b5f5f60408385031215611bd8575f5ffd5b8235611be3816119c6565b946020939093013593505050565b604080825283519082018190525f9060208501906060840190835b81811015611c335783516001600160a01b0316835260209384019390920191600101611c0c565b505080925050506001600160a01b03831660208301529392505050565b5f5f5f5f5f60808688031215611c64575f5ffd5b853567ffffffffffffffff811115611c7a575f5ffd5b611c8688828901611b3d565b9550506020860135611c97816119c6565b9350604086013567ffffffffffffffff811115611cb2575f5ffd5b611cbe888289016119ed565b9094509250611cd1905060608701611a35565b90509295509295909350565b6001600160f81b03198816815260e060208201525f611cff60e0830189611986565b8281036040840152611d118189611986565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015611d66578351835260209384019390920191600101611d48565b50909b9a5050505050505050505050565b5f5f5f5f5f5f5f5f5f5f5f60e08c8e031215611d91575f5ffd5b8b3567ffffffffffffffff811115611da7575f5ffd5b611db38e828f016119ed565b909c509a505060208c013567ffffffffffffffff811115611dd2575f5ffd5b611dde8e828f016119ed565b909a5098505060408c013567ffffffffffffffff811115611dfd575f5ffd5b611e098e828f01611b3d565b97505060608c013567ffffffffffffffff811115611e25575f5ffd5b611e318e828f016119ed565b9097509550611e44905060808d016119dd565b935060a08c013567ffffffffffffffff811115611e5f575f5ffd5b611e6b8e828f016119ed565b9094509250611e7e905060c08d01611a35565b90509295989b509295989b9093969950565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52603260045260245ffd5b5f8235603e19833603018112611ece575f5ffd5b9190910192915050565b5f60208284031215611ee8575f5ffd5b813561185e816119c6565b5f5f8335601e19843603018112611f08575f5ffd5b83018035915067ffffffffffffffff821115611f22575f5ffd5b602001915036819003821315611a2e575f5ffd5b8183526020830192505f815f5b84811015611f74578135611f56816119c6565b6001600160a01b031686526020958601959190910190600101611f43565b5093949350505050565b6001600160a01b038816815260a060208201525f611fa060a08301888a611865565b6001600160a01b03871660408401528281036060840152611fc2818688611f36565b91505060ff8316608083015298975050505050505050565b6001600160a01b0383168152604060208201525f611ffb6040830184611986565b949350505050565b5f813561200f816119c6565b6001600160a01b03168352602082013536839003601e19018112612031575f5ffd5b820160208101903567ffffffffffffffff81111561204d575f5ffd5b80360382131561205b575f5ffd5b60406020860152612070604086018284611865565b95945050505050565b5f8383855260208501945060208460051b820101835f5b868110156120d857838303601f19018852813536879003603e190181126120b5575f5ffd5b6120c184888301612003565b6020998a0199909450929092019150600101612090565b50909695505050505050565b60a081525f6120f760a08301898b612079565b82810360208401526121098189612003565b90506001600160a01b03871660408401528281036060840152611fc2818688611f36565b60e081525f61214060e083018d8f612079565b8281036020840152612153818c8e612079565b90508281036040840152612167818b612003565b9050828103606084015261217c81898b612079565b90506001600160a01b038716608084015282810360a08401526121a0818688611f36565b91505060ff831660c08301529c9b505050505050505050505050565b60ff84168152604060208201525f612070604083018486611f36565b5f602082840312156121e8575f5ffd5b8151801515811461185e575f5ffd5b602081525f611ffb602083018486611865565b5f5f85851115612218575f5ffd5b83861115612224575f5ffd5b5050820193919092039150565b80356001600160e01b03198116906004841015612260576001600160e01b0319808560040360031b1b82161691505b5092915050565b634e487b7160e01b5f52601160045260245ffd5b5f6001820161228c5761228c612267565b5060010190565b81810381811115610cad57610cad61226756fea164736f6c634300081b000a"; - bytes public constant NEXUS_PROXY_BYTECODE = - hex"60806040526040516103e43803806103e48339810160408190526100229161026c565b61002a61003b565b6100348282610063565b5050610351565b7f90b772c2cb8a51aa7a8a65fc23543c6d022d5b3f8e2b92eed79fba7eef8293006001815d50565b61006c826100c1565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156100b5576100b0828261013c565b505050565b6100bd6101af565b5050565b806001600160a01b03163b5f036100fb57604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f5f846001600160a01b031684604051610158919061033b565b5f60405180830381855af49150503d805f8114610190576040519150601f19603f3d011682016040523d82523d5f602084013e610195565b606091505b5090925090506101a68583836101d0565b95945050505050565b34156101ce5760405163b398979f60e01b815260040160405180910390fd5b565b6060826101e5576101e08261022f565b610228565b81511580156101fc57506001600160a01b0384163b155b1561022557604051639996b31560e01b81526001600160a01b03851660048201526024016100f2565b50805b9392505050565b80511561023f5780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b634e487b7160e01b5f52604160045260245ffd5b5f5f6040838503121561027d575f5ffd5b82516001600160a01b0381168114610293575f5ffd5b60208401519092506001600160401b038111156102ae575f5ffd5b8301601f810185136102be575f5ffd5b80516001600160401b038111156102d7576102d7610258565b604051601f8201601f19908116603f011681016001600160401b038111828210171561030557610305610258565b60405281815282820160200187101561031c575f5ffd5b8160208401602083015e5f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b60878061035d5f395ff3fe6080604052600a600c565b005b60186014601a565b605d565b565b5f60587f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b905090565b365f5f375f5f365f845af43d5f5f3e8080156076573d5ff35b3d5ffdfea164736f6c634300081b000a"; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/Safe7579Precompiles.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/Safe7579Precompiles.sol deleted file mode 100644 index 0f8e6c8..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/Safe7579Precompiles.sol +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { ISafe7579 } from "../../accounts/safe/interfaces/ISafe7579.sol"; -import { ISafe7579Launchpad } from "../../accounts/safe/interfaces/ISafe7579Launchpad.sol"; -import { ISafeProxyFactory } from "../../accounts/safe/interfaces/ISafeProxyFactory.sol"; - -// Utils -import { label } from "../../test/utils/Vm.sol"; -import { BytecodeDeployer } from "./BytecodeDeployer.sol"; - -/// @notice Precompiled Safe7579 contracts -contract Safe7579Precompiles is BytecodeDeployer { - /*////////////////////////////////////////////////////////////// - DEPLOY - //////////////////////////////////////////////////////////////*/ - - function deploySafe7579() internal returns (ISafe7579 safe) { - safe = ISafe7579(_deploy(SAFE7579_BYTECODE)); - label(address(safe), "Safe7579"); - } - - function deploySafe7579Launchpad( - address entrypoint, - address registry - ) - internal - returns (ISafe7579Launchpad safeLaunchpad) - { - // Concat constructor params to bytecode - bytes memory creationBytecode = - bytes.concat(SAFE7579_LAUNCHPAD_BYTECODE, abi.encode(entrypoint, registry)); - safeLaunchpad = ISafe7579Launchpad(_deploy(creationBytecode)); - label(address(safeLaunchpad), "Safe7579Launchpad"); - } - - function deploySafeSingleton() internal returns (address safeSingleton) { - safeSingleton = _deploy(SAFE_SINGLETON_BYTECODE); - label(safeSingleton, "SafeSingleton"); - } - - function deploySafeProxyFactory() internal returns (ISafeProxyFactory safeProxyFactory) { - safeProxyFactory = ISafeProxyFactory(_deploy(SAFE_PROXY_FACTORY_BYTECODE)); - label(address(safeProxyFactory), "SafeProxyFactory"); - } - - /*////////////////////////////////////////////////////////////// - BYTECODES - //////////////////////////////////////////////////////////////*/ - - /* solhint-disable max-line-length */ - bytes public constant SAFE7579_BYTECODE = - hex"60a060405234801561000f575f5ffd5b5060405161001c90610047565b604051809103905ff080158015610035573d5f5f3e3d5ffd5b506001600160a01b0316608052610054565b610988806153b883390190565b6080516152ff6100b95f395f81816112750152818161148a0152818161160a01528181611e3c0152818161242f015281816125080152818161259e01528181612634015281816138ef015281816139a601528181613dcf0152613ee701526152ff5ff3fe608060405260043610610138575f3560e01c8063a71763a8116100aa578063d828435d1161006e578063d828435d146104b7578063e9ae5c53146104d6578063ea5f61d0146104f5578063eab77e1714610514578063f2dc691d14610533578063f698da25146105525761013f565b8063a71763a8146103e2578063b0d691fe14610401578063b875d5d814610423578063d03c79141461046c578063d691c9641461048b5761013f565b8063540fb4f9116100fc578063540fb4f9146102dc57806355d559f4146102fd5780635faac46b1461032c57806379aad60e146103595780639517e29f146103785780639cfd7cff146103975761013f565b80630a664dba146101e7578063112d3a7d146102295780631626ba7e1461025857806319822f7c14610290578063236b58a1146102bd5761013f565b3661013f57005b5f3660605f3560e01c63bc197c81811463f23a6e6182141763150b7a028214171561016e57806020526020603cf35b50335f818152600460209081526040808320546001600160e01b031984351680855260058452828520958552949092528220546001600160a01b0391821692911690806101bb8484610566565b915091506101c98888610621565b95506101d784848484610730565b5050505050915050805190602001f35b3480156101f2575f5ffd5b50335f908152600460205260409020546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b348015610234575f5ffd5b5061024861024336600461419d565b6107b1565b6040519015158152602001610220565b348015610263575f5ffd5b506102776102723660046141f4565b610843565b6040516001600160e01b03199091168152602001610220565b34801561029b575f5ffd5b506102af6102aa36600461441e565b610bd8565b604051908152602001610220565b3480156102c8575f5ffd5b5061020c6102d7366004614467565b610d04565b3480156102e7575f5ffd5b506102fb6102f63660046144d4565b610d6d565b005b348015610308575f5ffd5b5061031c6103173660046145c5565b610e1d565b6040516102209493929190614641565b348015610337575f5ffd5b5061034b61034636600461468c565b610fde565b6040516102209291906146b6565b348015610364575f5ffd5b506102fb610373366004614718565b610ff9565b348015610383575f5ffd5b506102fb61039236600461419d565b6110fc565b3480156103a2575f5ffd5b50604080518082018252601a81527f7268696e6573746f6e652e73616665373537392e76312e302e30000000000000602082015290516102209190614756565b3480156103ed575f5ffd5b506102fb6103fc36600461419d565b6112e5565b34801561040c575f5ffd5b506f71727de22e5e9d8baf0edac6f37da03261020c565b34801561042e575f5ffd5b5061020c61043d36600461477d565b6001600160e01b0319165f9081526005602090815260408083203384529091529020546001600160a01b031690565b348015610477575f5ffd5b50610248610486366004614467565b611648565b348015610496575f5ffd5b506104aa6104a53660046141f4565b6116f3565b6040516102209190614798565b3480156104c2575f5ffd5b506102af6104d13660046147fb565b6117db565b3480156104e1575f5ffd5b506102fb6104f03660046141f4565b611878565b348015610500575f5ffd5b5061034b61050f36600461468c565b611c11565b34801561051f575f5ffd5b506102fb61052e366004614837565b611c21565b34801561053e575f5ffd5b5061024861054d366004614467565b611c90565b34801561055d575f5ffd5b506102af611cd8565b6060806001600160a01b038416156105e4576105cb33855f610586611d30565b345f3660405160240161059c94939291906148c1565b60408051601f198184030181529190526020810180516001600160e01b031663d68f602560e01b179052611d3c565b9150818060200190518101906105e1919061493f565b91505b6001600160a01b0383161561061a5761060133845f610586611d30565b905080806020019051810190610617919061493f565b90505b9250929050565b5f80356001600160e01b031916815260036020908152604080832033845290915290208054606091906001600160a01b03811690600160a01b900460f81b8161068f57604051632464e76d60e11b81526001600160e01b03195f351660048201526024015b60405180910390fd5b61069d81607f60f91b611dde565b156106e1576106d7338388886106b1611d30565b6040516020016106c393929190614970565b604051602081830303815290604052611df0565b935050505061072a565b6106eb815f611dde565b15610726576106d733835f8989610700611d30565b60405160200161071293929190614970565b604051602081830303815290604052611d3c565b5050505b92915050565b6001600160a01b038416156107855761078533855f856040516024016107569190614756565b60408051601f198184030181529190526020810180516001600160e01b0316630b9dfbed60e11b179052611ec1565b6001600160a01b038316156107ab576107ab33845f846040516024016107569190614756565b50505050565b5f600185036107e257336001600160a01b038516036107d25750600161083b565b6107db84611f5c565b905061083b565b600285036107f3576107db84611f69565b60038503610806576107db848484611f76565b60048503610819576107db848484611fc0565b60088514806108285750600985145b15610838576107db848484611ff9565b505f5b949350505050565b5f338282036109ee5761085f610857611d30565b868686612069565b50809550505f610928826001600160a01b031663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108a4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108c89190614996565b60408051602081018a90527f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca91015b60408051601f1981840301815282825280516020918201209083015201604051602081830303815290604052612140565b8051602090910120604051635ae6bd3760e01b8152600481018290529091506001600160a01b03831690635ae6bd3790602401602060405180830381865afa158015610976573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061099a9190614996565b5f036109dc5760405162461bcd60e51b815260206004820152601160248201527012185cda081b9bdd08185c1c1c9bdd9959607a1b6044820152606401610686565b50630b135d3f60e11b9150610bd19050565b5f6109fc60148286886149ad565b610a05916149d4565b60601c90506060610a2a610a17611d30565b88610a25886014818c6149ad565b612069565b90975090506001600160a01b0382161580610a4b5750610a4982611f5c565b155b15610b63575f610ae7846001600160a01b031663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a90573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ab49190614996565b60408051602081018c90527f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca91016108f7565b8051602082012060405163934f3a1160e01b8152919250906001600160a01b0386169063934f3a1190610b2290849086908890600401614a21565b5f6040518083038186803b158015610b38575f5ffd5b505afa158015610b4a573d5f5f3e3d5ffd5b50630b135d3f60e11b9850610bd1975050505050505050565b5f610bb43384610b71611d30565b8b86604051602401610b8593929190614a4b565b60408051601f198184030181529190526020810180516001600160e01b0316637aa8f17760e11b179052611df0565b905080806020019051810190610bca9190614a7a565b9450505050505b9392505050565b5f6f71727de22e5e9d8baf0edac6f37da032610bf2611d30565b6001600160a01b031614610c1957604051635629665f60e11b815260040160405180910390fd5b6020840151606081901c90610c2f8587866121ba565b61010088015294506001600160a01b0382161580610c535750610c5182611f5c565b155b15610c6857610c6186612258565b9250610ccb565b5f610cb133845f8a8a604051602401610c82929190614b35565b60408051601f198184030181529190526020810180516001600160e01b0316639700320360e01b179052611d3c565b905080806020019051810190610cc79190614996565b9350505b8315610cfb57610cfb336f71727de22e5e9d8baf0edac6f37da0328660405180602001604052805f815250611ec1565b50509392505050565b5f60098203610d2a575050335f908152600660205260409020546001600160a01b031690565b60088203610d4f575050335f908152600760205260409020546001600160a01b031690565b604051635691922f60e01b815260040160405180910390fd5b919050565b6f71727de22e5e9d8baf0edac6f37da032610d86611d30565b6001600160a01b03161480610db35750610d9e611d30565b6001600160a01b0316336001600160a01b0316145b610dd057604051635629665f60e11b815260040160405180910390fd5b610e02610de06020830183614b56565b610ded6020840184614b71565b610dfd6060860160408701614bb6565b612303565b610e1289898989898989896123b7565b505050505050505050565b6101008201516060905f9081908390610e38818460066126a2565b610e4190614bcf565b60d01c9350610e53816006600c6126a2565b610e5c90614bcf565b60d01c9250610e6c81600c612707565b9150505f604051806101c001604052807fc03dfc11d8b10bf9cf703d558958c8c42777f785d998c62060d85a4f0ef6ea7f5f1b8152602001885f01516001600160a01b031681526020018860200151815260200188604001518051906020012081526020018860600151805190602001208152602001610eeb89612715565b6001600160801b03168152602001610f0289612724565b6001600160801b031681526020018860a001518152602001610f2389612739565b6001600160801b03168152602001610f3a89612748565b6001600160801b0316815260e089015180516020918201209082015265ffffffffffff8087166040830152851660608201526001600160a01b0388166080909101526101c08120909150601960f81b600160f81b610f96611cd8565b6040516001600160f81b031993841660208201529290911660218301526022820152604281018290526062016040516020818303038152906040529550505092959194509250565b60605f610fee600133868661275d565b915091509250929050565b6f71727de22e5e9d8baf0edac6f37da032611012611d30565b6001600160a01b0316148061103f575061102a611d30565b6001600160a01b0316336001600160a01b0316145b61105c57604051635629665f60e11b815260040160405180910390fd5b61106760013361291c565b6110f857611076600133612947565b805f5b818110156110cb573684848381811061109457611094614c09565b90506020028101906110a69190614c1d565b90506110c2336110b96020840184614b56565b600191906129a6565b50600101611079565b5060405133907ff48581d8a62b775b74f2fb67f1d5806a9a356fbcc598040ab3071d3e37af40c2905f90a2505b5050565b335f908152600460209081526040808320547fd00bcad91b775f25eb0aee15808d12dfdaa6dc5a7d6b754e26f9c205d2a3b8df909252822054639517e29f60e01b926001600160a01b039283169290911690806111598484610566565b915091506111746f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316611185611d30565b6001600160a01b031614806111b2575061119d611d30565b6001600160a01b0316336001600160a01b0316145b6111cf57604051635629665f60e11b815260040160405180910390fd5b606060018a036111eb576111e4898989612a99565b905061126f565b60028a036111fe576111e4898989612af4565b60038a03611211576111e4898989612b0f565b60048a03611224576111e4898989612c8a565b89611234576111e4898989612e07565b60088a1480611243575060098a145b15611253576111e4898989612fb5565b60405163041c38b360e41b8152600481018b9052602401610686565b6112d8337f00000000000000000000000000000000000000000000000000000000000000008c8c856040516024016112a993929190614c3b565b60408051601f198184030181529190526020810180516001600160e01b0316639517e29f60e01b179052612ff0565b50610e1284848484610730565b335f908152600460209081526040808320547fc45a7acaba78a7b4c4432b604d301355b314c0a7811768a1ee2563c9d34ca4e09092529091205484916314e2ec7560e31b916001600160a01b0391821691908116908416821480159061135d5750806001600160a01b0316846001600160a01b031614155b15611501575f5f61136e8484610566565b915091506113896f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b031661139a611d30565b6001600160a01b031614806113c757506113b2611d30565b6001600160a01b0316336001600160a01b0316145b6113e457604051635629665f60e11b815260040160405180910390fd5b606060018b03611400576113f98a8a8a613085565b9050611484565b60028b03611413576113f98a8a8a6130a5565b60038b03611426576113f98a8a8a6130c5565b60048b03611439576113f98a8a8a61310f565b8a611449576113f98a8a8a6131c3565b60088b1480611458575060098b145b15611468576113f98a8a8a613314565b60405163041c38b360e41b8152600481018c9052602401610686565b6114ed337f00000000000000000000000000000000000000000000000000000000000000008d8d856040516024016114be93929190614c3b565b60408051601f198184030181529190526020810180516001600160e01b0316637827252560e01b17905261337a565b506114fa84848484610730565b505061163e565b6f71727de22e5e9d8baf0edac6f37da03261151a611d30565b6001600160a01b031614806115475750611532611d30565b6001600160a01b0316336001600160a01b0316145b61156457604051635629665f60e11b815260040160405180910390fd5b60606001890361158057611579888888613085565b9050611604565b60028903611593576115798888886130a5565b600389036115a6576115798888886130c5565b600489036115b95761157988888861310f565b886115c9576115798888886131c3565b60088914806115d85750600989145b156115e857611579888888613314565b60405163041c38b360e41b8152600481018a9052602401610686565b610e12337f00000000000000000000000000000000000000000000000000000000000000008b8b856040516024016114be93929190614c3b565b5050505050505050565b5f81600881901b61165d82600160f81b611dde565b1561166b57600192506116ac565b611675825f611dde565b1561168357600192506116ac565b611695826001600160f81b0319611dde565b156116a357600192506116ac565b505f9392505050565b8280156116be57506116be815f611dde565b156116ca575050919050565b8280156116e057506116e081600160f81b611dde565b156116a3575050919050565b5050919050565b6060611705611700611d30565b611f69565b61173657611711611d30565b604051635c93ff2f60e11b81526001600160a01b039091166004820152602401610686565b335f908152600460209081526040808320547f4162c930ade27880570b0eb31efbc8a626b97e81a40ced27163509dfe16398829092528220546335a4725960e21b926001600160a01b039283169290911690806117938484610566565b9150915061179f611d30565b60026117ab828261342a565b8a600881901b6117bd81838e8e6134b0565b9950505050506117cf84848484610730565b50505050509392505050565b5f602082901b640100000000600160c01b03166f71727de22e5e9d8baf0edac6f37da032604051631aab3f0d60e11b81526001600160a01b0386811660048301526001600160c01b038416602483015291909116906335567e1a90604401602060405180830381865afa158015611854573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061083b9190614996565b335f908152600460209081526040808320547fccfe1b2bef70acd8e661aeb5430e147f4c75cb320972acba718a28da428e1a3090925282205463e9ae5c5360e01b926001600160a01b039283169290911690806118d58484610566565b915091506118f06f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316611901611d30565b6001600160a01b0316148061192e5750611919611d30565b6001600160a01b0316336001600160a01b0316145b61194b57604051635629665f60e11b815260040160405180910390fd5b87600881901b3361195c825f611dde565b15611ab45761196f83600160f81b611dde565b1561199657365f6119808c8c613853565b9150915061198f8383836138e9565b5050611c02565b6119a0835f611dde565b15611a05575f5f365f6119b38e8e613950565b93509350935093506119fc85858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ec192505050565b50505050611c02565b611a17836001600160f81b0319611dde565b15611a99575f611a2a6014828c8e6149ad565b611a33916149d4565b60601c9050365f8c8c6014908092611a4d939291906149ad565b91509150611a91848484848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612ff092505050565b505050611c02565b82604051632e5bf3f960e21b81526004016106869190614c64565b611ac282600160f81b611dde565b15611be757611ad583600160f81b611dde565b15611af557365f611ae68c8c613853565b9150915061198f8383836139a0565b611aff835f611dde565b15611b5b575f5f365f611b128e8e613950565b93509350935093506119fc85858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250613a0792505050565b611b6d836001600160f81b0319611dde565b15611a99575f611b806014828c8e6149ad565b611b89916149d4565b60601c9050365f8c8c6014908092611ba3939291906149ad565b91509150611a91848484848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061337a92505050565b816040516308c3ee0360e11b81526004016106869190614c64565b50505061163e84848484610730565b60605f610fee600233868661275d565b6f71727de22e5e9d8baf0edac6f37da032611c3a611d30565b6001600160a01b03161480611c675750611c52611d30565b6001600160a01b0316336001600160a01b0316145b611c8457604051635629665f60e11b815260040160405180910390fd5b6107ab84848484612303565b5f60018203611ca157506001919050565b60028203611cb157506001919050565b60038203611cc157506001919050565b60048203611cd157506001919050565b505f919050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218602082015246918101919091523060608201525f9060800160405160208183030381529060405280519060200120905090565b60131936013560601c90565b60605f856001600160a01b0316635229073f8686865f6040518563ffffffff1660e01b8152600401611d719493929190614cad565b5f604051808303815f875af1158015611d8c573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611db39190810190614cf1565b9250905080611dd557604051632b3f6d1160e21b815260040160405180910390fd5b50949350505050565b6001600160f81b031990811691161490565b60605f8383604051602401611e06929190614d3b565b60408051601f198184030181529181526020820180516001600160e01b0316636a22165760e01b179052519091505f90611e66907f0000000000000000000000000000000000000000000000000000000000000000908490602401614d3b565b60408051601f19818403018152919052602080820180516001600160e01b031663b4faba0960e01b178152825192935090915f91895afa5060203d036040519350808401604052806020853e505f51610cfb57825160208401fd5b60405163468721a760e01b81525f906001600160a01b0386169063468721a790611ef5908790879087908790600401614cad565b6020604051808303815f875af1158015611f11573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f359190614d5e565b905080611f5557604051632b3f6d1160e21b815260040160405180910390fd5b5050505050565b5f61072a60013384613ab7565b5f61072a60023384613ab7565b5f80611f848385018561477d565b6001600160e01b0319165f9081526003602090815260408083203384529091529020546001600160a01b03908116908616149150509392505050565b5f8080611fcf84860186614d85565b915091505f611fde8383613af9565b6001600160a01b039081169088161493505050509392505050565b5f8061200783850185614467565b905060098103612035575050335f908152600660205260409020546001600160a01b03848116911614610bd1565b60088103610d4f575050335f908152600760205260409020546001600160a01b03848116911614610bd1565b509392505050565b5f60605f6120776008610d04565b90506001600160a01b0381166120ce5785858581818080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525095985091965061213795505050505050565b5f61211a33838a8a8a8a6040516024016120eb94939291906148c1565b60408051601f198184030181529190526020810180516001600160e01b0316637a0468b760e01b179052611df0565b9050808060200190518101906121309190614daf565b9350935050505b94509492505050565b6060601960f81b600160f81b858585604051602001612160929190614ddd565b60408051808303601f190181529082905280516020918201206001600160f81b0319958616918301919091529290931660218401526022830152604282015260620160405160208183030381529060405290509392505050565b5f60605f6121c86009610d04565b90506001600160a01b0381166121e8575050506101008201518390612250565b5f61223333835f89898c60405160240161220493929190614dfd565b60408051601f198184030181529190526020810180516001600160e01b031663e24f8f9360e01b179052611d3c565b9050808060200190518101906122499190614daf565b9350935050505b935093915050565b5f80808080612277866f71727de22e5e9d8baf0edac6f37da032610e1d565b8351602085012060405163934f3a1160e01b81529498509296509094509250339163934f3a11916122ae9188908690600401614a21565b5f6040518083038186803b1580156122c4575f5ffd5b505afa9250505080156122d5575060015b6122ec576122e560018385613b8c565b94506122fa565b6122f75f8385613b8c565b94505b50505050919050565b335f90815260208190526040902080546001600160a01b0319166001600160a01b0386169081179091551561237c5761237c33855f84878760405160240161234d93929190614e21565b60408051601f198184030181529190526020810180516001600160e01b031663f05c04e160e01b179052611ec1565b6040516001600160a01b0385169033907f9452c8fb077c3ea8f28a77c87488af657b1e44d010ad9a5992d73870da040e94905f90a350505050565b6060876123c560013361291c565b61247f576123d4600133612947565b5f5b8181101561247957368b8b838181106123f1576123f1614c09565b90506020028101906124039190614c1d565b90506124276124156020830183614b56565b6124226020840184614e78565b612a99565b9350612470337f0000000000000000000000000000000000000000000000000000000000000000600161245d6020860186614b56565b886040516024016112a993929190614c3b565b506001016123d6565b506124a0565b80156124a05760405163d8e3ed1b60e01b8152336004820152602401610686565b6124ab600233612947565b50855f5b8181101561253f57368989838181106124ca576124ca614c09565b90506020028101906124dc9190614c1d565b90506125006124ee6020830183614b56565b6124fb6020840184614e78565b612af4565b9350612536337f0000000000000000000000000000000000000000000000000000000000000000600261245d6020860186614b56565b506001016124af565b508490505f5b818110156125d5573687878381811061256057612560614c09565b90506020028101906125729190614c1d565b90506125966125846020830183614b56565b6125916020840184614e78565b612b0f565b93506125cc337f0000000000000000000000000000000000000000000000000000000000000000600361245d6020860186614b56565b50600101612545565b508290505f5b8181101561266b57368585838181106125f6576125f6614c09565b90506020028101906126089190614c1d565b905061262c61261a6020830183614b56565b6126276020840184614e78565b612c8a565b9350612662337f0000000000000000000000000000000000000000000000000000000000000000600461245d6020860186614b56565b506001016125db565b5060405133907ff48581d8a62b775b74f2fb67f1d5806a9a356fbcc598040ab3071d3e37af40c2905f90a250505050505050505050565b606083518281116126b1578092505b8381116126bc578093505b5081831015610bd15750604051828203848401601f19601f830181165b82810151858201528101806126d9575050508060208301015f81526020810160405250808252509392505050565b6060610bd183835f196126a2565b5f61072a826080015160801c90565b5f61072a82608001516001600160801b031690565b5f61072a8260c0015160801c90565b5f61072a8260c001516001600160801b031690565b60605f6001600160a01b0384166001148015906127825750612780868686613ab7565b155b156127ab57604051637c84ecfb60e01b81526001600160a01b0385166004820152602401610686565b825f036127cb5760405163f725081760e01b815260040160405180910390fd5b826001600160401b038111156127e3576127e361423b565b60405190808252806020026020018201604052801561280c578160200160208202803683370190505b506001600160a01b038086165f908152602089815260408083208a85168452909152812054929450911691505b6001600160a01b0382161580159061285b57506001600160a01b038216600114155b801561286657508381105b156128ca578183828151811061287e5761287e614c09565b6001600160a01b039283166020918202929092018101919091529281165f90815288845260408082208984168352909452929092205490911690806128c281614ece565b915050612839565b6001600160a01b0382166001148015906128e357505f81115b1561290f57826128f4600183614ee6565b8151811061290457612904614c09565b602002602001015191505b8083525094509492505050565b60015f908152602092835260408082206001600160a01b039384168352909352919091205416151590565b612951828261291c565b1561296f576040516329e42f3360e11b815260040160405180910390fd5b60015f818152602093845260408082206001600160a01b0394909416825292909352912080546001600160a01b0319169091179055565b6001600160a01b03811615806129c557506001600160a01b0381166001145b156129ee57604051637c84ecfb60e01b81526001600160a01b0382166004820152602401610686565b6001600160a01b038181165f9081526020858152604080832086851684529091529020541615612a3c57604051631034f46960e21b81526001600160a01b0382166004820152602401610686565b60015f908152602084815260408083206001600160a01b039586168085528184528285208054968816808752988552838620918652908452919093208054949095166001600160a01b031994851617909455528154169091179055565b6060836001612aa8828261342a565b612ab4600133886129a6565b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250929998505050505050505050565b6060836002612b03828261342a565b612ab4600233886129a6565b6060836003612b1e828261342a565b5f8080612b2d87890189614ef9565b919450925090506001600160e01b031983166306d61fe760e41b1480612b6357506001600160e01b03198316638a91b0e360e01b145b15612b8d576040516379bd117b60e01b81526001600160e01b031984166004820152602401610686565b612b97825f611dde565b8015612bac5750612bac82607f60f91b611dde565b15612bcc57816040516376087dc160e01b81526004016106869190614c64565b6001600160e01b031983165f9081526003602090815260408083203384529091529020546001600160a01b031615612c23576040516374420d1560e01b81526001600160e01b031984166004820152602401610686565b6001600160e01b03199092165f908152600360209081526040808320338452909152902080546001600160a01b038a166001600160a01b031960f89490941c600160a01b02939093166001600160a81b031990911617919091179055925050509392505050565b6060836004612c99828261342a565b5f8080612ca887890189614f62565b919450925090505f80846001811115612cc357612cc3614c79565b148015612cd857506001600160e01b03198316155b15612d4c5750335f908152600460205260409020546001600160a01b03168015612d205760405163741cbe0360e01b81526001600160a01b0382166004820152602401610686565b335f90815260046020526040902080546001600160a01b0319166001600160a01b038c16179055612dfa565b6001846001811115612d6057612d60614c79565b03610d4f57506001600160e01b031982165f9081526005602090815260408083203384529091529020546001600160a01b03168015612dbd5760405163741cbe0360e01b81526001600160a01b0382166004820152602401610686565b6001600160e01b031983165f908152600560209081526040808320338452909152902080546001600160a01b0319166001600160a01b038c161790555b5098975050505050505050565b60608235830160208181019135908581013586018082019190359060408801358801908101903584838114612e4f5760405163b4fa3fb360e01b815260040160405180910390fd5b5f5b81811015612f6f575f888883818110612e6c57612e6c614c09565b90506020020135905060018103612eab57612ea58d888885818110612e9357612e93614c09565b90506020028101906124229190614e78565b50612f66565b60028103612edb57612ea58d888885818110612ec957612ec9614c09565b90506020028101906124fb9190614e78565b60038103612f0b57612ea58d888885818110612ef957612ef9614c09565b90506020028101906125919190614e78565b60048103612f3b57612ea58d888885818110612f2957612f29614c09565b90506020028101906126279190614e78565b60405163484d218160e01b81526001600160a01b038e16600482015260248101829052604401610686565b50600101612e51565b5082828080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250929e9d5050505050505050505050505050565b60605f612fc483850185614f8d565b925090506008198101612fdf57612fda85613bc2565b612061565b60088103610d4f57612fda85613c4a565b60405163468721a760e01b81525f906001600160a01b0385169063468721a79061302590869085908790600190600401614cad565b6020604051808303815f875af1158015613041573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130659190614d5e565b9050806107ab57604051632b3f6d1160e21b815260040160405180910390fd5b60605f61309483850185614fc6565b925090506120616001338388613cd2565b60605f6130b483850185614fc6565b925090506120616002338388613cd2565b60605f6130d483850185614ffc565b6001600160e01b03199091165f908152600360209081526040808320338452909152902080546001600160a01b031916905595945050505050565b60605f8061311f84860186614f62565b945090925090505f82600181111561313957613139614c79565b14801561314e57506001600160e01b03198116155b1561317457335f90815260046020526040902080546001600160a01b0319169055610cfb565b600182600181111561318857613188614c79565b03610d4f576001600160e01b031981165f908152600560209081526040808320338452909152902080546001600160a01b0319169055610cfb565b6060823583016020818101913590858101358601808201919035906040880135880190810190358483811461320b5760405163b4fa3fb360e01b815260040160405180910390fd5b5f5b81811015612f6f575f88888381811061322857613228614c09565b9050602002013590506001810361326c576132668d88888581811061324f5761324f614c09565b90506020028101906132619190614e78565b613085565b5061330b565b600281036132a1576132668d88888581811061328a5761328a614c09565b905060200281019061329c9190614e78565b6130a5565b600381036132d6576132668d8888858181106132bf576132bf614c09565b90506020028101906132d19190614e78565b6130c5565b60048103612f3b576132668d8888858181106132f4576132f4614c09565b90506020028101906133069190614e78565b61310f565b5060010161320d565b60605f61332383850185614f8d565b92509050600819810161335157335f90815260066020526040902080546001600160a01b0319169055612061565b60088103610d4f57335f90815260076020526040902080546001600160a01b0319169055612061565b60405163468721a760e01b81525f906001600160a01b0385169063468721a7906133af90869085908790600190600401614cad565b6020604051808303815f875af11580156133cb573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133ef9190614d5e565b9050806107ab57604080516001600160a01b03861681525f60208201525f5160206152aa5f395f51905f52910160405180910390a150505050565b335f908152602081905260409020546001600160a01b031680156134ab5760405163529562a160e01b81523360048201526001600160a01b0384811660248301526044820184905282169063529562a1906064015f6040518083038186803b158015613494575f5ffd5b505afa1580156134a6573d5f5f3e3d5ffd5b505050505b505050565b60606134bc855f611dde565b156136a5576134cf84600160f81b611dde565b156134f857365f6134e08585613853565b915091506134ef338383613dc7565b9250505061083b565b613502845f611dde565b156135b2575f5f365f6135158787613950565b6040805160018082528183019092529498509296509094509250816020015b606081526020019060019003908161353457905050945061358c33858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611d3c92505050565b855f8151811061359e5761359e614c09565b60200260200101819052505050505061083b565b6135c4846001600160f81b0319611dde565b1561368a575f6135d760148285876149ad565b6135e0916149d4565b60601c9050365f6135f485601481896149ad565b604080516001808252818301909252929450909250816020015b606081526020019060019003908161360e579050509350613665338484848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250613e4392505050565b845f8151811061367757613677614c09565b602002602001018190525050505061083b565b83604051632e5bf3f960e21b81526004016106869190614c64565b6136b385600160f81b611dde565b15613838576136c684600160f81b611dde565b156136f157365f6136d78585613853565b915091506136e6338383613edd565b935061083b92505050565b6136fb845f611dde565b15613785575f5f365f61370e8787613950565b6040805160018082528183019092529498509296509094509250816020015b606081526020019060019003908161372d57905050945061358c33858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250613fd092505050565b613797846001600160f81b0319611dde565b1561368a575f6137aa60148285876149ad565b6137b3916149d4565b60601c9050365f6137c785601481896149ad565b604080516001808252818301909252929450909250816020015b60608152602001906001900390816137e1579050509350613665338484848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061408792505050565b846040516308c3ee0360e11b81526004016106869190614c64565b365f833580850160208587010360208201945081359350808460051b8301118360401c17156138895763ba597e7e5f526004601cfd5b83156138df578392505b6001830392508260051b850135915081850160408101358082018381358201118460408501111782861782351760401c17156138d65763ba597e7e5f526004601cfd5b50505082613893575b5050509250929050565b6134ab837f00000000000000000000000000000000000000000000000000000000000000008484604051602401613921929190615018565b60408051601f198184030181529190526020810180516001600160e01b0316633f707e6b60e01b179052612ff0565b5f80368161396160148287896149ad565b61396a916149d4565b60601c935061397d6034601487896149ad565b613986916150f8565b925061399585603481896149ad565b949793965094505050565b6134ab837f000000000000000000000000000000000000000000000000000000000000000084846040516024016139d8929190615018565b60408051601f198184030181529190526020810180516001600160e01b0316632864481160e11b17905261337a565b60405163468721a760e01b81525f906001600160a01b0386169063468721a790613a3b908790879087908790600401614cad565b6020604051808303815f875af1158015613a57573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a7b9190614d5e565b905080611f5557604080516001600160a01b03871681525f60208201525f5160206152aa5f395f51905f52910160405180910390a15050505050565b5f60016001600160a01b0383161480159061083b5750506001600160a01b039081165f9081526020938452604080822093831682529290935291205416151590565b5f80836001811115613b0d57613b0d614c79565b148015613b2257506001600160e01b03198216155b15613b415750335f908152600460205260409020546001600160a01b03165b6001836001811115613b5557613b55614c79565b0361072a57506001600160e01b0319165f9081526005602090815260408083203384529091529020546001600160a01b0316919050565b5f60d08265ffffffffffff16901b60a08465ffffffffffff16901b85613bb2575f613bb5565b60015b60ff161717949350505050565b806009613bcf828261342a565b335f908152600660205260409020546001600160a01b03168015613c185760405163b9aa8b3f60e01b81526001600160a01b038216600482015260096024820152604401610686565b5050335f90815260066020526040902080546001600160a01b0319166001600160a01b03939093169290921790915550565b806008613c57828261342a565b335f908152600760205260409020546001600160a01b03168015613ca05760405163b9aa8b3f60e01b81526001600160a01b038216600482015260086024820152604401610686565b5050335f90815260076020526040902080546001600160a01b0319166001600160a01b03939093169290921790915550565b6001600160a01b0381161580613cf157506001600160a01b0381166001145b15613d1a57604051637c84ecfb60e01b81526001600160a01b0383166004820152602401610686565b6001600160a01b038281165f908152602086815260408083208785168452909152902054811690821614613d6c57604051637c84ecfb60e01b81526001600160a01b0382166004820152602401610686565b6001600160a01b039081165f908152602085815260408083209584168084528683528184208054968616855297835281842090845282529091208054939092166001600160a01b031993841617909155919091528154169055565b6060613e30847f00000000000000000000000000000000000000000000000000000000000000008585604051602401613e01929190615018565b60408051601f198184030181529190526020810180516001600160e01b0316636108557360e01b179052613e43565b80602001905181019061083b91906151bf565b60605f846001600160a01b0316635229073f855f8660016040518563ffffffff1660e01b8152600401613e799493929190614cad565b5f604051808303815f875af1158015613e94573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052613ebb9190810190614cf1565b925090508061206157604051632b3f6d1160e21b815260040160405180910390fd5b6060805f613f48867f00000000000000000000000000000000000000000000000000000000000000008787604051602401613f19929190615018565b60408051601f198184030181529190526020810180516001600160e01b0316639abb6e1760e01b179052614087565b905080806020019051810190613f5e91906151f0565b815191945092505f5b81811015613fc557848181518110613f8157613f81614c09565b6020026020010151613fbd57604080516001600160a01b038a168152602081018390525f5160206152aa5f395f51905f52910160405180910390a15b600101613f67565b505050935093915050565b60605f856001600160a01b0316635229073f8686865f6040518563ffffffff1660e01b81526004016140059493929190614cad565b5f604051808303815f875af1158015614020573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526140479190810190614cf1565b9250905080611dd557604080516001600160a01b03881681525f60208201525f5160206152aa5f395f51905f52910160405180910390a150949350505050565b60605f846001600160a01b0316635229073f855f8660016040518563ffffffff1660e01b81526004016140bd9493929190614cad565b5f604051808303815f875af11580156140d8573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526140ff9190810190614cf1565b925090508061206157604080516001600160a01b03871681525f60208201525f5160206152aa5f395f51905f52910160405180910390a1509392505050565b6001600160a01b0381168114614152575f5ffd5b50565b8035610d688161413e565b5f5f83601f840112614170575f5ffd5b5081356001600160401b03811115614186575f5ffd5b60208301915083602082850101111561061a575f5ffd5b5f5f5f5f606085870312156141b0575f5ffd5b8435935060208501356141c28161413e565b925060408501356001600160401b038111156141dc575f5ffd5b6141e887828801614160565b95989497509550505050565b5f5f5f60408486031215614206575f5ffd5b8335925060208401356001600160401b03811115614222575f5ffd5b61422e86828701614160565b9497909650939450505050565b634e487b7160e01b5f52604160045260245ffd5b60405161012081016001600160401b03811182821017156142725761427261423b565b60405290565b604051601f8201601f191681016001600160401b03811182821017156142a0576142a061423b565b604052919050565b5f6001600160401b038211156142c0576142c061423b565b50601f01601f191660200190565b5f82601f8301126142dd575f5ffd5b81356142f06142eb826142a8565b614278565b818152846020838601011115614304575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f6101208284031215614331575f5ffd5b61433961424f565b905061434482614155565b81526020828101359082015260408201356001600160401b03811115614368575f5ffd5b614374848285016142ce565b60408301525060608201356001600160401b03811115614392575f5ffd5b61439e848285016142ce565b6060830152506080828101359082015260a0808301359082015260c0808301359082015260e08201356001600160401b038111156143da575f5ffd5b6143e6848285016142ce565b60e0830152506101008201356001600160401b03811115614405575f5ffd5b614411848285016142ce565b6101008301525092915050565b5f5f5f60608486031215614430575f5ffd5b83356001600160401b03811115614445575f5ffd5b61445186828701614320565b9660208601359650604090950135949350505050565b5f60208284031215614477575f5ffd5b5035919050565b5f5f83601f84011261448e575f5ffd5b5081356001600160401b038111156144a4575f5ffd5b6020830191508360208260051b850101111561061a575f5ffd5b5f606082840312156144ce575f5ffd5b50919050565b5f5f5f5f5f5f5f5f5f60a08a8c0312156144ec575f5ffd5b89356001600160401b03811115614501575f5ffd5b61450d8c828d0161447e565b909a5098505060208a01356001600160401b0381111561452b575f5ffd5b6145378c828d0161447e565b90985096505060408a01356001600160401b03811115614555575f5ffd5b6145618c828d0161447e565b90965094505060608a01356001600160401b0381111561457f575f5ffd5b61458b8c828d0161447e565b90945092505060808a01356001600160401b038111156145a9575f5ffd5b6145b58c828d016144be565b9150509295985092959850929598565b5f5f604083850312156145d6575f5ffd5b82356001600160401b038111156145eb575f5ffd5b6145f785828601614320565b92505060208301356146088161413e565b809150509250929050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b608081525f6146536080830187614613565b65ffffffffffff8616602084015265ffffffffffff8516604084015282810360608401526146818185614613565b979650505050505050565b5f5f6040838503121561469d575f5ffd5b82356146a88161413e565b946020939093013593505050565b604080825283519082018190525f9060208501906060840190835b818110156146f85783516001600160a01b03168352602093840193909201916001016146d1565b50506001600160a01b039490941660209390930192909252509092915050565b5f5f60208385031215614729575f5ffd5b82356001600160401b0381111561473e575f5ffd5b61474a8582860161447e565b90969095509350505050565b602081525f610bd16020830184614613565b6001600160e01b031981168114614152575f5ffd5b5f6020828403121561478d575f5ffd5b8135610bd181614768565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b828110156147ef57603f198786030184526147da858351614613565b945060209384019391909101906001016147be565b50929695505050505050565b5f5f6040838503121561480c575f5ffd5b82356148178161413e565b915060208301356146088161413e565b803560ff81168114610d68575f5ffd5b5f5f5f5f6060858703121561484a575f5ffd5b84356148558161413e565b935060208501356001600160401b0381111561486f575f5ffd5b61487b8782880161447e565b909450925061488e905060408601614827565b905092959194509250565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b60018060a01b0385168152836020820152606060408201525f6148e8606083018486614899565b9695505050505050565b5f82601f830112614901575f5ffd5b815161490f6142eb826142a8565b818152846020838601011115614923575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b5f6020828403121561494f575f5ffd5b81516001600160401b03811115614964575f5ffd5b61083b848285016148f2565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b5f602082840312156149a6575f5ffd5b5051919050565b5f5f858511156149bb575f5ffd5b838611156149c7575f5ffd5b5050820193919092039150565b80356bffffffffffffffffffffffff198116906014841015614a1a576bffffffffffffffffffffffff196bffffffffffffffffffffffff198560140360031b1b82161691505b5092915050565b838152606060208201525f614a396060830185614613565b82810360408401526148e88185614613565b60018060a01b0384168152826020820152606060408201525f614a716060830184614613565b95945050505050565b5f60208284031215614a8a575f5ffd5b8151610bd181614768565b80516001600160a01b03168252602081015160208301525f60408201516101206040850152614ac8610120850182614613565b905060608301518482036060860152614ae18282614613565b9150506080830151608085015260a083015160a085015260c083015160c085015260e083015184820360e0860152614b198282614613565b915050610100830151848203610100860152614a718282614613565b604081525f614b476040830185614a95565b90508260208301529392505050565b5f60208284031215614b66575f5ffd5b8135610bd18161413e565b5f5f8335601e19843603018112614b86575f5ffd5b8301803591506001600160401b03821115614b9f575f5ffd5b6020019150600581901b360382131561061a575f5ffd5b5f60208284031215614bc6575f5ffd5b610bd182614827565b805160208201516001600160d01b03198116919060068210156116ec576001600160d01b031960069290920360031b82901b161692915050565b634e487b7160e01b5f52603260045260245ffd5b5f8235603e19833603018112614c31575f5ffd5b9190910192915050565b8381526001600160a01b03831660208201526060604082018190525f90614a7190830184614613565b6001600160f81b031991909116815260200190565b634e487b7160e01b5f52602160045260245ffd5b60028110614ca957634e487b7160e01b5f52602160045260245ffd5b9052565b60018060a01b0385168152836020820152608060408201525f614cd36080830185614613565b9050614a716060830184614c8d565b80518015158114610d68575f5ffd5b5f5f60408385031215614d02575f5ffd5b614d0b83614ce2565b915060208301516001600160401b03811115614d25575f5ffd5b614d31858286016148f2565b9150509250929050565b6001600160a01b03831681526040602082018190525f9061083b90830184614613565b5f60208284031215614d6e575f5ffd5b610bd182614ce2565b803560028110610d68575f5ffd5b5f5f60408385031215614d96575f5ffd5b614d9f83614d77565b9150602083013561460881614768565b5f5f60408385031215614dc0575f5ffd5b825160208401519092506001600160401b03811115614d25575f5ffd5b8281525f82518060208501602085015e5f92016020019182525092915050565b606081525f614e0f6060830186614a95565b60208301949094525060400152919050565b60ff8416815260406020820181905281018290525f8360608301825b85811015614e6d578235614e508161413e565b6001600160a01b0316825260209283019290910190600101614e3d565b509695505050505050565b5f5f8335601e19843603018112614e8d575f5ffd5b8301803591506001600160401b03821115614ea6575f5ffd5b60200191503681900382131561061a575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b5f60018201614edf57614edf614eba565b5060010190565b8181038181111561072a5761072a614eba565b5f5f5f60608486031215614f0b575f5ffd5b8335614f1681614768565b925060208401356001600160f81b031981168114614f32575f5ffd5b915060408401356001600160401b03811115614f4c575f5ffd5b614f58868287016142ce565b9150509250925092565b5f5f5f60608486031215614f74575f5ffd5b614f7d84614d77565b92506020840135614f3281614768565b5f5f60408385031215614f9e575f5ffd5b8235915060208301356001600160401b03811115614fba575f5ffd5b614d31858286016142ce565b5f5f60408385031215614fd7575f5ffd5b8235614fe28161413e565b915060208301356001600160401b03811115614fba575f5ffd5b5f5f6040838503121561500d575f5ffd5b8235614fe281614768565b602080825281018290525f6040600584901b830181019083018583605e1936839003015b878210156150eb57868503603f19018452823581811261505a575f5ffd5b890180356150678161413e565b6001600160a01b0316865260208181013590870152604081013536829003601e19018112615093575f5ffd5b016020810190356001600160401b038111156150ad575f5ffd5b8036038213156150bb575f5ffd5b606060408801526150d0606088018284614899565b9650505060208301925060208401935060018201915061503c565b5092979650505050505050565b8035602083101561072a575f19602084900360031b1b1692915050565b5f6001600160401b0382111561512d5761512d61423b565b5060051b60200190565b5f82601f830112615146575f5ffd5b81516151546142eb82615115565b8082825260208201915060208360051b860101925085831115615175575f5ffd5b602085015b838110156151b55780516001600160401b03811115615197575f5ffd5b6151a6886020838a01016148f2565b8452506020928301920161517a565b5095945050505050565b5f602082840312156151cf575f5ffd5b81516001600160401b038111156151e4575f5ffd5b61083b84828501615137565b5f5f60408385031215615201575f5ffd5b82516001600160401b03811115615216575f5ffd5b8301601f81018513615226575f5ffd5b80516152346142eb82615115565b8082825260208201915060208360051b850101925087831115615255575f5ffd5b6020840193505b8284101561527e5761526d84614ce2565b82526020938401939091019061525c565b8095505050505060208301516001600160401b0381111561529d575f5ffd5b614d318582860161513756feb8bc84bd77f5eb08210b8eb20fd63b3ec6a7992d277ab94663bae0e066f792aca264697066735822122057e35612c96749b4d4d6b3f02cc1e78c7c3495436185ad1901de41fed60d2a6464736f6c634300081c00336080604052348015600e575f5ffd5b5061096c8061001c5f395ff3fe608060405234801561000f575f5ffd5b506004361061007a575f3560e01c80636a221657116100585780636a221657146100cf57806378272525146100e25780639517e29f146100f55780639abb6e1714610108575f5ffd5b80633f707e6b1461007e57806350c890221461009357806361085573146100a6575b5f5ffd5b61009161008c3660046105a0565b610129565b005b6100916100a13660046105a0565b610192565b6100b96100b43660046105a0565b6101f6565b6040516100c6919061068b565b60405180910390f35b6100916100dd3660046106d3565b6102b7565b6100916100f0366004610797565b6102d8565b610091610103366004610797565b61037c565b61011b6101163660046105a0565b610416565b6040516100c692919061081a565b805f5b8181101561018c573684848381811061014757610147610873565b90506020028101906101599190610887565b905061018261016b60208301836108a5565b602083013561017d60408501856108be565b61053f565b505060010161012c565b50505050565b805f5b8181101561018c57368484838181106101b0576101b0610873565b90506020028101906101c29190610887565b90506101eb6101d460208301836108a5565b60208301356101e660408501856108be565b610572565b505050600101610195565b6060818067ffffffffffffffff811115610212576102126106bf565b60405190808252806020026020018201604052801561024557816020015b60608152602001906001900390816102305790505b5091505f5b818110156102af573685858381811061026557610265610873565b90506020028101906102779190610887565b905061028961016b60208301836108a5565b84838151811061029b5761029b610873565b60209081029190910101525060010161024a565b505092915050565b6040515f5f835160208501865afa3d5f833e80156102d3573d82f35b503d81fd5b604051638a91b0e360e01b81526001600160a01b03841690638a91b0e3906103069085908590600401610908565b5f604051808303815f87803b15801561031d575f5ffd5b505af115801561032f573d5f5f3e3d5ffd5b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e93500190505b60405180910390a150505050565b6040516306d61fe760e41b81526001600160a01b03841690636d61fe70906103aa9085908590600401610908565b5f604051808303815f87803b1580156103c1575f5ffd5b505af11580156103d3573d5f5f3e3d5ffd5b5050604080518781526001600160a01b03871660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905061036e565b606080828067ffffffffffffffff811115610433576104336106bf565b60405190808252806020026020018201604052801561046657816020015b60608152602001906001900390816104515790505b5091508067ffffffffffffffff811115610482576104826106bf565b6040519080825280602002602001820160405280156104ab578160200160208202803683370190505b5092505f5b8181101561053657368686838181106104cb576104cb610873565b90506020028101906104dd9190610887565b90506104ef6101d460208301836108a5565b86848151811061050157610501610873565b6020026020010186858151811061051a5761051a610873565b60209081029190910101919091529015159052506001016104b0565b50509250929050565b604051818382375f38838387895af161055a573d5f823e3d81fd5b3d8152602081013d5f823e3d01604052949350505050565b6040515f90828482375f388483888a5af191503d8152602081013d5f823e3d81016040525094509492505050565b5f5f602083850312156105b1575f5ffd5b823567ffffffffffffffff8111156105c7575f5ffd5b8301601f810185136105d7575f5ffd5b803567ffffffffffffffff8111156105ed575f5ffd5b8560208260051b8401011115610601575f5ffd5b6020919091019590945092505050565b5f82825180855260208501945060208160051b830101602085015f5b8381101561067f57601f19858403018852815180518085528060208301602087015e5f602082870101526020601f19601f8301168601019450505060208201915060208801975060018101905061062d565b50909695505050505050565b602081525f61069d6020830184610611565b9392505050565b80356001600160a01b03811681146106ba575f5ffd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156106e4575f5ffd5b6106ed836106a4565b9150602083013567ffffffffffffffff811115610708575f5ffd5b8301601f81018513610718575f5ffd5b803567ffffffffffffffff811115610732576107326106bf565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610761576107616106bf565b604052818152828201602001871015610778575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f5f5f5f606085870312156107aa575f5ffd5b843593506107ba602086016106a4565b9250604085013567ffffffffffffffff8111156107d5575f5ffd5b8501601f810187136107e5575f5ffd5b803567ffffffffffffffff8111156107fb575f5ffd5b87602082840101111561080c575f5ffd5b949793965060200194505050565b604080825283519082018190525f9060208501906060840190835b818110156108555783511515835260209384019390920191600101610835565b505083810360208501526108698186610611565b9695505050505050565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e1983360301811261089b575f5ffd5b9190910192915050565b5f602082840312156108b5575f5ffd5b61069d826106a4565b5f5f8335601e198436030181126108d3575f5ffd5b83018035915067ffffffffffffffff8211156108ed575f5ffd5b602001915036819003821315610901575f5ffd5b9250929050565b60208152816020820152818360408301375f818301604090810191909152601f909201601f1916010191905056fea264697066735822122022c9b200e3f870ce04690a2b55157c10e84d8f3789b97d1df9409e173a99a39764736f6c634300081c0033"; - bytes public constant SAFE7579_LAUNCHPAD_BYTECODE = - hex"60e060405234801561000f575f5ffd5b50604051612d0b380380612d0b83398101604081905261002e91610087565b6001600160a01b03821661005557604051632039d3c960e01b815260040160405180910390fd5b306080526001600160a01b0391821660a0521660c0526100bf565b6001600160a01b0381168114610084575f5ffd5b50565b5f5f60408385031215610098575f5ffd5b82516100a381610070565b60208401519092506100b481610070565b809150509250929050565b60805160a05160c051612beb6101205f395f8181610151015281816104720152610ede01525f81816101a10152818161059901528181610fb901526112e701525f818160f0015281816105440152818161095501526110210152612beb5ff3fe6080604052600436106100e7575f3560e01c8063663c87d811610087578063d78343d911610057578063d78343d914610335578063d9ed0e8f14610354578063f2dc691d14610373578063f698da2514610392575f5ffd5b8063663c87d81461027d578063928107f91461029c5780639cfd7cff146102bb578063d03c791414610306575f5ffd5b806319822f7c116100c257806319822f7c146101e25780633c9de1b81461020f5780634fff40e11461022f57806355d559f41461024e575f5ffd5b806306433b1b14610140578063137e051e1461019057806315cca638146101c3575f5ffd5b3661013c575f547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161461013a576040516308e3edd160e41b815260040160405180910390fd5b005b5f5ffd5b34801561014b575f5ffd5b506101737f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019b575f5ffd5b506101737f000000000000000000000000000000000000000000000000000000000000000081565b3480156101ce575f5ffd5b5061013a6101dd36600461198b565b6103a6565b3480156101ed575f5ffd5b506102016101fc366004611a75565b61053f565b604051908152602001610187565b34801561021a575f5ffd5b505f516020612b965f395f51905f5254610201565b34801561023a575f5ffd5b5061013a610249366004611ac3565b610951565b348015610259575f5ffd5b5061026d610268366004611c70565b610a79565b6040516101879493929190611dd4565b348015610288575f5ffd5b50610173610297366004611e1f565b610c3a565b3480156102a7575f5ffd5b506102016102b636600461200f565b610d13565b3480156102c6575f5ffd5b50604080518082018252601a81527f7268696e6573746f6e652e73616665373537392e76312e302e30000000000000602082015290516101879190612135565b348015610311575f5ffd5b50610325610320366004612147565b610d64565b6040519015158152602001610187565b348015610340575f5ffd5b5061013a61034f36600461215e565b610e12565b34801561035f575f5ffd5b5061013a61036e36600461227e565b610fae565b34801561037e575f5ffd5b5061032561038d366004612147565b611226565b34801561039d575f5ffd5b50610201611273565b3330146103c657604051630a57d61d60e01b815260040160405180910390fd5b60405163610b592560e01b81526001600160a01b038b166004820152309063610b5925906024015f604051808303815f87803b158015610404575f5ffd5b505af1158015610416573d5f5f3e3d5ffd5b5050604080515f8082526020820190925230935063540fb4f992509061045e565b604080518082019091525f8152606060208201528152602001906001900390816104375790505b508b8b8b8b8b8b60405180606001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018d8d808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050509082525060ff8c166020909101526040516001600160e01b031960e08b901b1681526105069897969594939291906004016124a8565b5f604051808303815f87803b15801561051d575f5ffd5b505af115801561052f573d5f5f3e3d5ffd5b5050505050505050505050505050565b5f80547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161461058e576040516308e3edd160e41b815260040160405180910390fd5b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146105d757604051632039d3c960e01b815260040160405180910390fd5b6105e4606085018561251a565b6105f2916004915f9161255c565b6105fb91612583565b6001600160e01b03191663d9ed0e8f60e01b1461062b5760405163c3d40f7760e01b815260040160405180910390fd5b5f610639606086018661251a565b61064791600490829061255c565b810190610654919061200f565b905061066b5f516020612b965f395f51905f525490565b61067482610d13565b146106925760405163278328b160e21b815260040160405180910390fd5b5f5f866020013590508060601c91505f8360a001516001600160a01b03168460c001516040516024016106c591906125bb565b60408051601f19818403018152918152602080830180516001600160e01b0316633cd56b0760e11b17905290516106ff92913391016125e4565b60408051601f19818403018152908290526107199161260b565b5f604051808303815f865af19150503d805f8114610752576040519150601f19603f3d011682016040523d82523d5f602084013e610757565b606091505b50509050806107795760405163c3d40f7760e01b815260040160405180910390fd5b60c0840151515f90815b81811015610893575f8760c0015182815181106107a2576107a2612616565b60200260200101515f01519050806001600160a01b0316636d61fe708960c0015184815181106107d4576107d4612616565b6020026020010151602001516040518263ffffffff1660e01b81526004016107fc9190612135565b5f604051808303815f87803b158015610813575f5ffd5b505af1158015610825573d5f5f3e3d5ffd5b505060408051600181526001600160a01b03851660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905060405180910390a1866001600160a01b0316816001600160a01b03160361088a57600193505b50600101610783565b50811561090f57604051639700320360e01b81526001600160a01b038616906397003203906108c8908d908d90600401612709565b6020604051808303815f875af11580156108e4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610908919061272a565b9650610934565b5f5f5f61091c898e6112cb565b92509250925061092e83158383611437565b99505050505b8715610944575f5f5f5f8b335af1505b5050505050509392505050565b5f547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161461099f576040516308e3edd160e41b815260040160405180910390fd5b5f6109b55f516020612b965f395f51905f525490565b146109d35760405163d4d496e560e01b815260040160405180910390fd5b6109e8845f516020612b965f395f51905f5255565b6001600160a01b03831615610a73575f836001600160a01b03168383604051610a12929190612741565b5f60405180830381855af49150503d805f8114610a4a576040519150601f19603f3d011682016040523d82523d5f602084013e610a4f565b606091505b5050905080610a7157604051631f57fed560e31b815260040160405180910390fd5b505b50505050565b6101008201516060905f9081908390610a948184600661146f565b610a9d90612750565b60d01c9350610aaf816006600c61146f565b610ab890612750565b60d01c9250610ac881600c6114d4565b9150505f604051806101c001604052807fc03dfc11d8b10bf9cf703d558958c8c42777f785d998c62060d85a4f0ef6ea7f5f1b8152602001885f01516001600160a01b031681526020018860200151815260200188604001518051906020012081526020018860600151805190602001208152602001610b47896114e2565b6001600160801b03168152602001610b5e896114f7565b6001600160801b031681526020018860a001518152602001610b7f8961150c565b6001600160801b03168152602001610b968961151b565b6001600160801b0316815260e089015180516020918201209082015265ffffffffffff8087166040830152851660608201526001600160a01b0388166080909101526101c08120909150601960f81b600160f81b610bf2611273565b6040516001600160f81b031993841660208201529290911660218301526022820152604281018290526062016040516020818303038152906040529550505092959194509250565b5f818051906020012083604051602001610c5e929190918252602082015260400190565b60405160208183030381529060405280519060200120925060ff60f81b858486896001600160a01b0316604051602001610c9992919061278a565b60405160208183030381529060405280519060200120604051602001610cf194939291906001600160f81b031994909416845260609290921b6001600160601b03191660018401526015830152603582015260550190565b60408051601f1981840301815291905280516020909101209695505050505050565b80516020808301516040808501516060860151608087015160a088015160c089015194515f98610d479890979691016127a2565b604051602081830303815290604052805190602001209050919050565b5f81600881901b6001600160f81b03198216600160f81b03610d895760019250610dc4565b6001600160f81b03198216610da15760019250610dc4565b6001600160f81b031980831603610dbb5760019250610dc4565b505f9392505050565b828015610dd957506001600160f81b03198116155b15610de5575050919050565b828015610dff57506001600160f81b03198116600160f81b145b15610dbb575050919050565b5050919050565b60405163610b592560e01b81526001600160a01b038d166004820152309063610b5925906024015f604051808303815f87803b158015610e50575f5ffd5b505af1158015610e62573d5f5f3e3d5ffd5b505060405163f08a032360e01b81526001600160a01b038f16600482015230925063f08a032391506024015f604051808303815f87803b158015610ea4575f5ffd5b505af1158015610eb6573d5f5f3e3d5ffd5b50505050306001600160a01b031663540fb4f98c8c8c8c8c8c8c8c60405180606001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018e8e808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050509082525060ff8d166020909101526040516001600160e01b031960e08c901b168152610f739998979695949392919060040161281e565b5f604051808303815f87803b158015610f8a575f5ffd5b505af1158015610f9c573d5f5f3e3d5ffd5b50505050505050505050505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610ff757604051632039d3c960e01b815260040160405180910390fd5b6110046020820182612892565b5f80546001600160a01b0319166001600160a01b039283161790557f0000000000000000000000000000000000000000000000000000000000000000166110516080830160608401612892565b6001600160a01b03161461107857604051633007073760e01b815260040160405180910390fd5b6302b994c760e31b61108d608083018361251a565b61109b916004915f9161255c565b6110a491612583565b6001600160e01b031916146110cc57604051633007073760e01b815260040160405180910390fd5b3063b63e800d6110df60208401846128ad565b60408501356110f46080870160608801612892565b611101608088018861251a565b61111160c08a0160a08b01612892565b5f5f5f6040518b63ffffffff1660e01b81526004016111399a999897969594939291906128f2565b5f604051808303815f87803b158015611150575f5ffd5b505af1158015611162573d5f5f3e3d5ffd5b50505f5f516020612b965f395f51905f52555061117c9050565b5f8061118e60c0840160a08501612892565b6001600160a01b03166111a460e085018561251a565b306040516020016111b7939291906129a8565b60408051601f19818403018152908290526111d19161260b565b5f604051808303815f865af19150503d805f811461120a576040519150601f19603f3d011682016040523d82523d5f602084013e61120f565b606091505b50915091508161122157805160208201fd5b505050565b5f6001820361123757506001919050565b6002820361124757506001919050565b6003820361125757506001919050565b6004820361126757506001919050565b505f919050565b919050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218602082015246918101919091523060608201525f9060800160405160208183030381529060405280519060200120905090565b5f5f5f6060808660a001516001600160a01b03166355d559f4877f00000000000000000000000000000000000000000000000000000000000000006040518363ffffffff1660e01b81526004016113239291906129c9565b5f60405180830381865afa15801561133d573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526113649190810190612a54565b8351602085012060408c0151929850929650929450919250905f9061138c9083908590611530565b9050611397816116de565b60208901516113a5816116de565b6113ae816116ea565b80515f805b82811015611424575f6113e88583815181106113d1576113d1612616565b6020026020010151876116f390919063ffffffff16565b509050801561141b57826113fb81612aeb565b9350508d60400151831061141b5760019b50505050505050505050611430565b506001016113b3565b505f9950505050505050505b9250925092565b5f60d08265ffffffffffff16901b60a08465ffffffffffff16901b8561145d575f611460565b60015b60ff16171790505b9392505050565b6060835182811161147e578092505b838111611489578093505b50818310156114685750604051828203848401601f19601f830181165b82810151858201528101806114a6575050508060208301015f81526020810160405250808252509392505050565b606061146883835f1961146f565b5f6114f1826080015160801c90565b92915050565b5f6114f182608001516001600160801b031690565b5f6114f18260c0015160801c90565b5f6114f18260c001516001600160801b031690565b81516060905f611541604183612b03565b9050806001600160401b0381111561155b5761155b611b46565b604051908082528060200260200182016040528015611584578160200160208202803683370190505b509250838110156115a857604051638baa579f60e01b815260040160405180910390fd5b5f5f5b828110156116b2575f5f5f5f6115d88b8660410201602081015160408201516060909201515f1a92909190565b9250925092508260ff165f036115fc576115f58c8c84848c611714565b935061165a565b601e8360ff16111561164b576115f56116398d6020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c60042090565b611644600486612b22565b84846117dc565b6116578c8484846117dc565b93505b6001600160a01b03841615611677578561167381612aeb565b9650505b8389868151811061168a5761168a612616565b6001600160a01b03909216602092830291909101909101525050600190920191506115ab9050565b50848110156116d457604051638baa579f60e01b815260040160405180910390fd5b5050509392505050565b6116e781611816565b50565b6116e78161186b565b5f8061170984846001600160a01b03165f6118b4565b909590945092505050565b838201602001518390826117288583612b3b565b611733906020612b3b565b1115611742575f9150506117d3565b604051630b135d3f60e11b808252878601602001916001600160a01b03851690631626ba7e90611778908c908690600401612b4e565b602060405180830381865afa158015611793573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117b79190612b6e565b6001600160e01b031916146117d0575f925050506117d3565b50505b95945050505050565b5f604051855f5260ff851660205283604052826060526020604060805f60015afa505f6060523d6060185191508060405250949350505050565b80515f82528060051b8201601f19602084015b602001828111611864578051828201805182811161184957505050611829565b5b60208201528301805182811161184a575060200152611829565b5050509052565b60028151106116e7576020810160408201600183510160051b83015b815183511461189b57602083019250815183525b60208201915080820361188757505081900360051c9052565b5f5f5f19600186515f87870197505b81830160011c94508460051b89015187019050878114828411176118fd578088116118f25783850191506118c3565b6001850192506118c3565b84151597148716989290930190950295509350505050565b6001600160a01b03811681146116e7575f5ffd5b803561126e81611915565b5f5f83601f840112611944575f5ffd5b5081356001600160401b0381111561195a575f5ffd5b6020830191508360208260051b8501011115611974575f5ffd5b9250929050565b803560ff8116811461126e575f5ffd5b5f5f5f5f5f5f5f5f5f5f60c08b8d0312156119a4575f5ffd5b6119ad8b611929565b995060208b01356001600160401b038111156119c7575f5ffd5b6119d38d828e01611934565b909a5098505060408b01356001600160401b038111156119f1575f5ffd5b6119fd8d828e01611934565b90985096505060608b01356001600160401b03811115611a1b575f5ffd5b611a278d828e01611934565b90965094505060808b01356001600160401b03811115611a45575f5ffd5b611a518d828e01611934565b9094509250611a64905060a08c0161197b565b90509295989b9194979a5092959850565b5f5f5f60608486031215611a87575f5ffd5b83356001600160401b03811115611a9c575f5ffd5b84016101208187031215611aae575f5ffd5b95602085013595506040909401359392505050565b5f5f5f5f60608587031215611ad6575f5ffd5b843593506020850135611ae881611915565b925060408501356001600160401b03811115611b02575f5ffd5b8501601f81018713611b12575f5ffd5b80356001600160401b03811115611b27575f5ffd5b876020828401011115611b38575f5ffd5b949793965060200194505050565b634e487b7160e01b5f52604160045260245ffd5b60405161012081016001600160401b0381118282101715611b7d57611b7d611b46565b60405290565b604080519081016001600160401b0381118282101715611b7d57611b7d611b46565b60405161010081016001600160401b0381118282101715611b7d57611b7d611b46565b604051601f8201601f191681016001600160401b0381118282101715611bf057611bf0611b46565b604052919050565b5f6001600160401b03821115611c1057611c10611b46565b50601f01601f191660200190565b5f82601f830112611c2d575f5ffd5b8135611c40611c3b82611bf8565b611bc8565b818152846020838601011115611c54575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f60408385031215611c81575f5ffd5b82356001600160401b03811115611c96575f5ffd5b83016101208186031215611ca8575f5ffd5b611cb0611b5a565b611cb982611929565b81526020828101359082015260408201356001600160401b03811115611cdd575f5ffd5b611ce987828501611c1e565b60408301525060608201356001600160401b03811115611d07575f5ffd5b611d1387828501611c1e565b6060830152506080828101359082015260a0808301359082015260c0808301359082015260e08201356001600160401b03811115611d4f575f5ffd5b611d5b87828501611c1e565b60e0830152506101008201356001600160401b03811115611d7a575f5ffd5b611d8687828501611c1e565b610100830152509250611d9d905060208401611929565b90509250929050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b608081525f611de66080830187611da6565b65ffffffffffff8616602084015265ffffffffffff851660408401528281036060840152611e148185611da6565b979650505050505050565b5f5f5f5f5f60a08688031215611e33575f5ffd5b8535611e3e81611915565b94506020860135611e4e81611915565b935060408601356001600160401b03811115611e68575f5ffd5b611e7488828901611c1e565b9350506060860135915060808601356001600160401b03811115611e96575f5ffd5b611ea288828901611c1e565b9150509295509295909350565b5f6001600160401b03821115611ec757611ec7611b46565b5060051b60200190565b5f82601f830112611ee0575f5ffd5b8135611eee611c3b82611eaf565b8082825260208201915060208360051b860101925085831115611f0f575f5ffd5b602085015b83811015611f35578035611f2781611915565b835260209283019201611f14565b5095945050505050565b5f82601f830112611f4e575f5ffd5b8135611f5c611c3b82611eaf565b8082825260208201915060208360051b860101925085831115611f7d575f5ffd5b602085015b83811015611f355780356001600160401b03811115611f9f575f5ffd5b86016040818903601f19011215611fb4575f5ffd5b611fbc611b83565b6020820135611fca81611915565b815260408201356001600160401b03811115611fe4575f5ffd5b611ff38a602083860101611c1e565b6020830152508085525050602083019250602081019050611f82565b5f6020828403121561201f575f5ffd5b81356001600160401b03811115612034575f5ffd5b82016101008185031215612046575f5ffd5b61204e611ba5565b61205782611929565b815260208201356001600160401b03811115612071575f5ffd5b61207d86828501611ed1565b6020830152506040828101359082015261209960608301611929565b606082015260808201356001600160401b038111156120b6575f5ffd5b6120c286828501611c1e565b6080830152506120d460a08301611929565b60a082015260c08201356001600160401b038111156120f1575f5ffd5b6120fd86828501611f3f565b60c08301525060e08201356001600160401b0381111561211b575f5ffd5b61212786828501611c1e565b60e083015250949350505050565b602081525f6114686020830184611da6565b5f60208284031215612157575f5ffd5b5035919050565b5f5f5f5f5f5f5f5f5f5f5f5f60e08d8f031215612179575f5ffd5b6121828d611929565b9b506001600160401b0360208e0135111561219b575f5ffd5b6121ab8e60208f01358f01611934565b909b5099506001600160401b0360408e013511156121c7575f5ffd5b6121d78e60408f01358f01611934565b90995097506001600160401b0360608e013511156121f3575f5ffd5b6122038e60608f01358f01611934565b90975095506001600160401b0360808e0135111561221f575f5ffd5b61222f8e60808f01358f01611934565b90955093506001600160401b0360a08e0135111561224b575f5ffd5b61225b8e60a08f01358f01611934565b909350915061226c60c08e0161197b565b90509295989b509295989b509295989b565b5f6020828403121561228e575f5ffd5b81356001600160401b038111156122a3575f5ffd5b82016101008185031215611468575f5ffd5b5f82825180855260208501945060208160051b830101602085015f5b8381101561232357848303601f19018852815180516001600160a01b0316845260209081015160409185018290529061230c90850182611da6565b6020998a01999094509290920191506001016122d1565b50909695505050505050565b5f5f8335601e19843603018112612344575f5ffd5b83016020810192503590506001600160401b03811115612362575f5ffd5b803603821315611974575f5ffd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f8383855260208501945060208460051b820101835f5b8681101561232357838303601f19018852813536879003603e190181126123d4575f5ffd5b860180356123e181611915565b6001600160a01b031684526123f9602082018261232f565b915060406020860152612410604086018383612370565b60209a8b019a909550939093019250506001016123af565b5f8151808452602084019350602083015f5b828110156124615781516001600160a01b031686526020958601959091019060010161243a565b5093949350505050565b60018060a01b0381511682525f6020820151606060208501526124916060850182612428565b60409384015160ff16949093019390935250919050565b60a081525f6124ba60a083018b6122b5565b82810360208401526124cd818a8c612398565b905082810360408401526124e281888a612398565b905082810360608401526124f7818688612398565b9050828103608084015261250b818561246b565b9b9a5050505050505050505050565b5f5f8335601e1984360301811261252f575f5ffd5b8301803591506001600160401b03821115612548575f5ffd5b602001915036819003821315611974575f5ffd5b5f5f8585111561256a575f5ffd5b83861115612576575f5ffd5b5050820193919092039150565b80356001600160e01b031981169060048410156125b4576001600160e01b0319600485900360031b81901b82161691505b5092915050565b602081525f61146860208301846122b5565b5f81518060208401855e5f93019283525090919050565b5f6125ef82856125cd565b60609390931b6001600160601b03191683525050601401919050565b5f61146882846125cd565b634e487b7160e01b5f52603260045260245ffd5b6126448261263783611929565b6001600160a01b03169052565b602081810135908301525f61265c604083018361232f565b610120604086015261267361012086018284612370565b915050612683606084018461232f565b8583036060870152612696838284612370565b6080868101359088015260a0808701359088015260c0808701359088015292506126c691505060e084018461232f565b85830360e08701526126d9838284612370565b925050506126eb61010084018461232f565b8583036101008701526126ff838284612370565b9695505050505050565b604081525f61271b604083018561262a565b90508260208301529392505050565b5f6020828403121561273a575f5ffd5b5051919050565b818382375f9101908152919050565b805160208201516001600160d01b0319811691906006821015610e0b576001600160d01b031960069290920360031b82901b161692915050565b5f61279582856125cd565b9283525050602001919050565b6001600160a01b038816815260e0602082018190525f906127c590830189612428565b604083018890526001600160a01b038716606084015282810360808401526127ed8187611da6565b6001600160a01b03861660a085015283810360c0850152905061281081856122b5565b9a9950505050505050505050565b60a081525f61283160a083018b8d612398565b8281036020840152612844818a8c612398565b9050828103604084015261285981888a612398565b9050828103606084015261286e818688612398565b90508281036080840152612882818561246b565b9c9b505050505050505050505050565b5f602082840312156128a2575f5ffd5b813561146881611915565b5f5f8335601e198436030181126128c2575f5ffd5b8301803591506001600160401b038211156128db575f5ffd5b6020019150600581901b3603821315611974575f5ffd5b61010080825281018a90525f8b6101208301825b8d81101561293657823561291981611915565b6001600160a01b0316825260209283019290910190600101612906565b508b6020850152612952604085018c6001600160a01b03169052565b8381036060850152612965818a8c612370565b9250505061297e60808301876001600160a01b03169052565b6001600160a01b03851660a08301528360c083015261250b60e08301846001600160a01b03169052565b8284823760609190911b6001600160601b0319169101908152601401919050565b604081525f6129db604083018561262a565b905060018060a01b03831660208301529392505050565b5f82601f830112612a01575f5ffd5b8151612a0f611c3b82611bf8565b818152846020838601011115612a23575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b805165ffffffffffff8116811461126e575f5ffd5b5f5f5f5f60808587031215612a67575f5ffd5b84516001600160401b03811115612a7c575f5ffd5b612a88878288016129f2565b945050612a9760208601612a3f565b9250612aa560408601612a3f565b915060608501516001600160401b03811115612abf575f5ffd5b612acb878288016129f2565b91505092959194509250565b634e487b7160e01b5f52601160045260245ffd5b5f60018201612afc57612afc612ad7565b5060010190565b5f82612b1d57634e487b7160e01b5f52601260045260245ffd5b500490565b60ff82811682821603908111156114f1576114f1612ad7565b808201808211156114f1576114f1612ad7565b828152604060208201525f612b666040830184611da6565b949350505050565b5f60208284031215612b7e575f5ffd5b81516001600160e01b031981168114611468575f5ffdfe982e06ee6a56dfc0f1ac189a5d23506361ca0a3ce45a9c7b8d33d65d43746a24a2646970667358221220cbd281b9702b507f3035a563b8dd778e1de241408898a1097f986f9f583f684964736f6c634300081c0033"; - bytes public constant SAFE_PROXY_BYTECODE = - hex"6080604052348015600e575f5ffd5b50604051610163380380610163833981016040819052602b9160b2565b6001600160a01b038116608f5760405162461bcd60e51b815260206004820152602260248201527f496e76616c69642073696e676c65746f6e20616464726573732070726f766964604482015261195960f21b606482015260840160405180910390fd5b5f80546001600160a01b0319166001600160a01b039290921691909117905560dd565b5f6020828403121560c1575f5ffd5b81516001600160a01b038116811460d6575f5ffd5b9392505050565b607a806100e95f395ff3fe60806040525f80546001600160a01b03169035632cf35bc960e11b01602657805f5260205ff35b365f5f375f5f365f845af490503d5f5f3e80603f573d5ffd5b503d5ff3fea2646970667358221220640def201af13e0821a9dcaf5c656634c958a7cf37a69d829387126c436276e364736f6c634300081c0033"; - bytes public constant SAFE_SINGLETON_BYTECODE = - hex"6080604052348015600e575f80fd5b506001600455612fad806100215f395ff3fe6080604052600436106101d0575f3560e01c8063affed0e0116100f6578063e19a9dd911610094578063f08a032311610063578063f08a0323146105d2578063f698da25146105f1578063f8dc5dd914610605578063ffa1ad74146106245761020c565b8063e19a9dd914610561578063e318b52b14610580578063e75235b81461059f578063e86637db146105b35761020c565b8063cc2f8452116100d0578063cc2f8452146104d7578063d4d9bdcd14610504578063d8d11f7814610523578063e009cfde146105425761020c565b8063affed0e014610484578063b4faba0914610499578063b63e800d146104b85761020c565b80635624b25b1161016e5780636a7612021161013d5780636a761202146103fb5780637d8329741461040e578063934f3a1114610444578063a0e67e2b146104635761020c565b80635624b25b146103665780635ae6bd3714610392578063610b5925146103bd578063694e80c3146103dc5761020c565b80632f54bf6e116101aa5780632f54bf6e146102df5780633408e470146102fe578063468721a71461031a5780635229073f146103395761020c565b80630d582f131461026b57806312fb68e01461028c5780632d9ad53d146102ab5761020c565b3661020c5760405134815233907f3d0ce9bfc3ed7d6862dbb28b2dea94561fe714a1b4d019aa8af39730d1ad7c3d9060200160405180910390a2005b348015610217575f80fd5b507f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d580548061024257005b365f80373360601b36525f80601436015f80855af190503d5f803e80610266573d5ffd5b503d5ff35b348015610276575f80fd5b5061028a610285366004612507565b610654565b005b348015610297575f80fd5b5061028a6102a63660046125ce565b6107a9565b3480156102b6575f80fd5b506102ca6102c536600461263e565b610c3a565b60405190151581526020015b60405180910390f35b3480156102ea575f80fd5b506102ca6102f936600461263e565b610c73565b348015610309575f80fd5b50465b6040519081526020016102d6565b348015610325575f80fd5b506102ca610334366004612667565b610ca9565b348015610344575f80fd5b50610358610353366004612667565b610d7d565b6040516102d69291906126fb565b348015610371575f80fd5b50610385610380366004612715565b610db1565b6040516102d69190612735565b34801561039d575f80fd5b5061030c6103ac366004612747565b60076020525f908152604090205481565b3480156103c8575f80fd5b5061028a6103d736600461263e565b610e2b565b3480156103e7575f80fd5b5061028a6103f6366004612747565b610f62565b6102ca6104093660046127a3565b611000565b348015610419575f80fd5b5061030c610428366004612507565b600860209081525f928352604080842090915290825290205481565b34801561044f575f80fd5b5061028a61045e366004612873565b611339565b34801561046e575f80fd5b50610477611383565b6040516102d6919061291e565b34801561048f575f80fd5b5061030c60055481565b3480156104a4575f80fd5b5061028a6104b3366004612930565b611471565b3480156104c3575f80fd5b5061028a6104d236600461297d565b611490565b3480156104e2575f80fd5b506104f66104f1366004612507565b61158f565b6040516102d6929190612a67565b34801561050f575f80fd5b5061028a61051e366004612747565b611747565b34801561052e575f80fd5b5061030c61053d366004612a90565b6117da565b34801561054d575f80fd5b5061028a61055c366004612b49565b611806565b34801561056c575f80fd5b5061028a61057b36600461263e565b611926565b34801561058b575f80fd5b5061028a61059a366004612b80565b611a39565b3480156105aa575f80fd5b5060045461030c565b3480156105be575f80fd5b506103856105cd366004612a90565b611c10565b3480156105dd575f80fd5b5061028a6105ec36600461263e565b611ce7565b3480156105fc575f80fd5b5061030c611d2e565b348015610610575f80fd5b5061028a61061f366004612bc8565b611d84565b34801561062f575f80fd5b5061038560405180604001604052806005815260200164312e342e3160d81b81525081565b61065c611eec565b6001600160a01b0382161580159061067e57506001600160a01b038216600114155b801561069357506001600160a01b0382163014155b6106b85760405162461bcd60e51b81526004016106af90612c06565b60405180910390fd5b6001600160a01b038281165f9081526002602052604090205416156106ef5760405162461bcd60e51b81526004016106af90612c25565b60026020527fe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e080546001600160a01b038481165f818152604081208054939094166001600160a01b03199384161790935560018352835490911617909155600380549161075b83612c58565b90915550506040516001600160a01b038316907f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea26905f90a280600454146107a5576107a581610f62565b5050565b6107b4816041611f25565b825110156107ec5760405162461bcd60e51b8152602060048201526005602482015264047533032360dc1b60448201526064016106af565b5f80805f805f5b86811015610c2e576041818102890160208101516040820151919092015160ff16955090935091505f8490036109fe57885160208a01208a146108605760405162461bcd60e51b8152602060048201526005602482015264475330323760d81b60448201526064016106af565b9193508391610870876041611f25565b8210156108a75760405162461bcd60e51b8152602060048201526005602482015264475330323160d81b60448201526064016106af565b87516108b4836020611f5c565b11156108ea5760405162461bcd60e51b815260206004820152600560248201526423a998191960d91b60448201526064016106af565b60208289018101518951909161090d908390610907908790611f5c565b90611f5c565b11156109435760405162461bcd60e51b8152602060048201526005602482015264475330323360d81b60448201526064016106af565b6040516320c13b0b60e01b8082528a8501602001916001600160a01b038916906320c13b0b90610979908f908690600401612c70565b602060405180830381865afa158015610994573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109b89190612c94565b6001600160e01b031916146109f75760405162461bcd60e51b815260206004820152600560248201526411d4cc0c8d60da1b60448201526064016106af565b5050610b9e565b8360ff16600103610a7f579193508391336001600160a01b0384161480610a4657506001600160a01b0385165f9081526008602090815260408083208d845290915290205415155b610a7a5760405162461bcd60e51b8152602060048201526005602482015264475330323560d81b60448201526064016106af565b610b9e565b601e8460ff161115610b41576040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c81018b9052600190605c0160405160208183030381529060405280519060200120600486610ae49190612cbb565b604080515f8152602081018083529390935260ff90911690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015610b30573d5f803e3d5ffd5b505050602060405103519450610b9e565b604080515f8152602081018083528c905260ff861691810191909152606081018490526080810183905260019060a0016020604051602081039080840390855afa158015610b91573d5f803e3d5ffd5b5050506020604051035194505b856001600160a01b0316856001600160a01b0316118015610bd757506001600160a01b038581165f908152600260205260409020541615155b8015610bed57506001600160a01b038516600114155b610c215760405162461bcd60e51b815260206004820152600560248201526423a998191b60d91b60448201526064016106af565b93945084936001016107f3565b50505050505050505050565b5f60016001600160a01b03831614801590610c6d57506001600160a01b038281165f908152600160205260409020541615155b92915050565b5f6001600160a01b038216600114801590610c6d5750506001600160a01b039081165f9081526002602052604090205416151590565b5f33600114801590610cd15750335f908152600160205260409020546001600160a01b031615155b610d055760405162461bcd60e51b815260206004820152600560248201526411d4cc4c0d60da1b60448201526064016106af565b610d13858585855f19611f76565b90508015610d4a5760405133907f6895c13664aa4f67288b25d7a21d7aaa34916e355fb9b6fae0a139a9085becb8905f90a2610d75565b60405133907facd2c8702804128fdb0db2bb49f6d127dd0181c13fd45dbfe16de0930e2bd375905f90a25b949350505050565b5f6060610d8c86868686610ca9565b915060405160203d0181016040523d81523d5f602083013e8091505094509492505050565b60605f610dbf836020612cd4565b67ffffffffffffffff811115610dd757610dd7612531565b6040519080825280601f01601f191660200182016040528015610e01576020820181803683370190505b5090505f5b83811015610e235784810154602080830284010152600101610e06565b509392505050565b610e33611eec565b6001600160a01b03811615801590610e5557506001600160a01b038116600114155b610e895760405162461bcd60e51b8152602060048201526005602482015264475331303160d81b60448201526064016106af565b6001600160a01b038181165f908152600160205260409020541615610ed85760405162461bcd60e51b815260206004820152600560248201526423a998981960d91b60448201526064016106af565b600160208190527fcc69885fda6bcc1a4ace058b4a62bf5e179ea78fd58a1ccd71c22cc9b688792f80546001600160a01b038481165f81815260408082208054949095166001600160a01b031994851617909455948552835490911681179092555190917fecdf3a3effea5783a3c4c2140e677577666428d44ed9d474a0b3a4c9943f844091a250565b610f6a611eec565b600354811115610f8c5760405162461bcd60e51b81526004016106af90612ceb565b6001811015610fc55760405162461bcd60e51b815260206004820152600560248201526423a999181960d91b60448201526064016106af565b60048190556040518181527f610f7ff2b304ae8903c3de74c60c6ab1f7d6226b3f52c5161905bb5ad4039c939060200160405180910390a150565b5f805f6110188e8e8e8e8e8e8e8e8e8e600554611c10565b600580549192505f61102983612c58565b9091555050805160208201209150611042828286611339565b505f61106c7f4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c85490565b90506001600160a01b038116156110ed57806001600160a01b03166375f0bb528f8f8f8f8f8f8f8f8f8f8f336040518d63ffffffff1660e01b81526004016110bf9c9b9a99989796959493929190612d3e565b5f604051808303815f87803b1580156110d6575f80fd5b505af11580156110e8573d5f803e3d5ffd5b505050505b6111196110fc8a6109c4612e01565b603f6111098c6040612cd4565b6111139190612e14565b90611fba565b611125906101f4612e01565b5a101561115c5760405162461bcd60e51b8152602060048201526005602482015264047533031360dc1b60448201526064016106af565b5f5a90506111ca8f8f8f8f8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050508e8c5f146111b7578e611f76565b6109c45a6111c59190612e33565b611f76565b93506111d75a8290611fd0565b905083806111e457508915155b806111ee57508715155b6112225760405162461bcd60e51b8152602060048201526005602482015264475330313360d81b60448201526064016106af565b5f881561123957611236828b8b8b8b611fe8565b90505b841561127e57837f442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e8260405161127191815260200190565b60405180910390a26112b9565b837f23428b18acfb3ea64b08dc0c1d296ea9c09702c09083ca5272e64d115b687d23826040516112b091815260200190565b60405180910390a25b50506001600160a01b0381161561132857604051631264e26d60e31b81526004810183905283151560248201526001600160a01b038216906393271368906044015f604051808303815f87803b158015611311575f80fd5b505af1158015611323573d5f803e3d5ffd5b505050505b50509b9a5050505050505050505050565b600454806113715760405162461bcd60e51b8152602060048201526005602482015264475330303160d81b60448201526064016106af565b61137d848484846107a9565b50505050565b60605f60035467ffffffffffffffff8111156113a1576113a1612531565b6040519080825280602002602001820160405280156113ca578160200160208202803683370190505b5060015f90815260026020527fe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e054919250906001600160a01b03165b6001600160a01b038116600114611469578083838151811061142a5761142a612e46565b6001600160a01b039283166020918202929092018101919091529181165f9081526002909252604090912054168161146181612c58565b925050611406565b509092915050565b5f80825160208401855af4805f52503d6020523d5f60403e60403d015ffd5b6114cd8a8a808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152508c92506120ec915050565b6001600160a01b038416156114e5576114e5846122c2565b6115248787878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061232692505050565b811561153a57611538825f60018685611fe8565b505b336001600160a01b03167f141df868a6331af528e38c83b7aa03edc19be66e37ae67f9285bf4f8e3c6a1a88b8b8b8b8960405161157b959493929190612e5a565b60405180910390a250505050505050505050565b60605f6001600160a01b038416600114806115ae57506115ae84610c3a565b6115e25760405162461bcd60e51b8152602060048201526005602482015264475331303560d81b60448201526064016106af565b5f83116116195760405162461bcd60e51b815260206004820152600560248201526423a998981b60d91b60448201526064016106af565b8267ffffffffffffffff81111561163257611632612531565b60405190808252806020026020018201604052801561165b578160200160208202803683370190505b506001600160a01b038086165f90815260016020526040812054929450911691505b6001600160a01b0382161580159061169f57506001600160a01b038216600114155b80156116aa57508381105b1561170457818382815181106116c2576116c2612e46565b6001600160a01b039283166020918202929092018101919091529281165f908152600190935260409092205490911690806116fc81612c58565b91505061167d565b6001600160a01b03821660011461173c5782611721600183612e33565b8151811061173157611731612e46565b602002602001015191505b808352509250929050565b335f908152600260205260409020546001600160a01b03166117935760405162461bcd60e51b8152602060048201526005602482015264047533033360dc1b60448201526064016106af565b335f818152600860209081526040808320858452909152808220600190555183917ff2a0eb156472d1440255b0d7c1e19cc07115d1051fe605b0dce69acfec884d9c91a350565b5f6117ee8c8c8c8c8c8c8c8c8c8c8c611c10565b8051906020012090509b9a5050505050505050505050565b61180e611eec565b6001600160a01b0381161580159061183057506001600160a01b038116600114155b6118645760405162461bcd60e51b8152602060048201526005602482015264475331303160d81b60448201526064016106af565b6001600160a01b038281165f908152600160205260409020548116908216146118b75760405162461bcd60e51b8152602060048201526005602482015264475331303360d81b60448201526064016106af565b6001600160a01b038181165f81815260016020526040808220805487861684528284208054919096166001600160a01b0319918216179095558383528054909416909355915190917faab4fa2b463f581b2b32cb3b7e3b704b9ce37cc209b5fb4d77e593ace405427691a25050565b61192e611eec565b6001600160a01b038116156119de576040516301ffc9a760e01b815263736bd41d60e11b60048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa158015611986573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119aa9190612ec5565b6119de5760405162461bcd60e51b8152602060048201526005602482015264047533330360dc1b60448201526064016106af565b7f4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c88181556040516001600160a01b038316907f1151116914515bc0891ff9047a6cb32cf902546f83066499bcf8ba33d2353fa2905f90a25050565b611a41611eec565b6001600160a01b03811615801590611a6357506001600160a01b038116600114155b8015611a7857506001600160a01b0381163014155b611a945760405162461bcd60e51b81526004016106af90612c06565b6001600160a01b038181165f908152600260205260409020541615611acb5760405162461bcd60e51b81526004016106af90612c25565b6001600160a01b03821615801590611aed57506001600160a01b038216600114155b611b095760405162461bcd60e51b81526004016106af90612c06565b6001600160a01b038381165f90815260026020526040902054811690831614611b5c5760405162461bcd60e51b8152602060048201526005602482015264475332303560d81b60448201526064016106af565b6001600160a01b038281165f81815260026020526040808220805486861680855283852080549288166001600160a01b03199384161790559589168452828420805482169096179095558383528054909416909355915190917ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf91a26040516001600160a01b038216907f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea26905f90a2505050565b60605f7fbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d85f1b8d8d8d8d604051611c48929190612ee4565b604051908190038120611c6e949392918e908e908e908e908e908e908e90602001612ef3565b60408051601f1981840301815291905280516020909101209050601960f81b600160f81b611c9a611d2e565b6040516001600160f81b031993841660208201529290911660218301526022820152604281018290526062016040516020818303038152906040529150509b9a5050505050505050505050565b611cef611eec565b611cf8816122c2565b6040516001600160a01b038216907f5ac6c46c93c8d0e53714ba3b53db3e7c046da994313d7ed0d192028bc7c228b0905f90a250565b5f7f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692184660408051602081019390935282015230606082015260800160405160208183030381529060405280519060200120905090565b611d8c611eec565b806001600354611d9c9190612e33565b1015611dba5760405162461bcd60e51b81526004016106af90612ceb565b6001600160a01b03821615801590611ddc57506001600160a01b038216600114155b611df85760405162461bcd60e51b81526004016106af90612c06565b6001600160a01b038381165f90815260026020526040902054811690831614611e4b5760405162461bcd60e51b8152602060048201526005602482015264475332303560d81b60448201526064016106af565b6001600160a01b038281165f81815260026020526040808220805488861684529183208054929095166001600160a01b03199283161790945591815282549091169091556003805491611e9d83612f62565b90915550506040516001600160a01b038316907ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf905f90a28060045414611ee757611ee781610f62565b505050565b333014611f235760405162461bcd60e51b8152602060048201526005602482015264475330333160d81b60448201526064016106af565b565b5f825f03611f3457505f610c6d565b5f611f3f8385612cd4565b905082611f4c8583612e14565b14611f55575f80fd5b9392505050565b5f80611f688385612e01565b905083811015611f55575f80fd5b5f6001836001811115611f8b57611f8b612d0a565b03611fa2575f808551602087018986f49050611fb1565b5f80855160208701888a87f190505b95945050505050565b5f81831015611fc95781611f55565b5090919050565b5f82821115611fdd575f80fd5b5f610d758385612e33565b5f806001600160a01b03831615611fff5782612001565b325b90506001600160a01b038416612093576120333a8610612021573a612023565b855b61202d8989611f5c565b90611f25565b6040519092506001600160a01b0382169083156108fc029084905f818181858888f1935050505061208e5760405162461bcd60e51b8152602060048201526005602482015264475330313160d81b60448201526064016106af565b6120e2565b6120a18561202d8989611f5c565b91506120ae848284612454565b6120e25760405162461bcd60e51b815260206004820152600560248201526423a998189960d91b60448201526064016106af565b5095945050505050565b600454156121245760405162461bcd60e51b8152602060048201526005602482015264047533230360dc1b60448201526064016106af565b81518111156121455760405162461bcd60e51b81526004016106af90612ceb565b600181101561217e5760405162461bcd60e51b815260206004820152600560248201526423a999181960d91b60448201526064016106af565b60015f5b8351811015612290575f84828151811061219e5761219e612e46565b602002602001015190505f6001600160a01b0316816001600160a01b0316141580156121d457506001600160a01b038116600114155b80156121e957506001600160a01b0381163014155b80156122075750806001600160a01b0316836001600160a01b031614155b6122235760405162461bcd60e51b81526004016106af90612c06565b6001600160a01b038181165f90815260026020526040902054161561225a5760405162461bcd60e51b81526004016106af90612c25565b6001600160a01b039283165f90815260026020526040902080546001600160a01b03191693821693909317909255600101612182565b506001600160a01b03165f90815260026020526040902080546001600160a01b03191660011790559051600355600455565b306001600160a01b038216036123025760405162461bcd60e51b8152602060048201526005602482015264047533430360dc1b60448201526064016106af565b7f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d555565b60015f8190526020527fcc69885fda6bcc1a4ace058b4a62bf5e179ea78fd58a1ccd71c22cc9b688792f546001600160a01b03161561238f5760405162461bcd60e51b8152602060048201526005602482015264047533130360dc1b60448201526064016106af565b60015f81905260208190527fcc69885fda6bcc1a4ace058b4a62bf5e179ea78fd58a1ccd71c22cc9b688792f80546001600160a01b03191690911790556001600160a01b038216156107a557813b6124115760405162461bcd60e51b815260206004820152600560248201526423a998181960d91b60448201526064016106af565b612420825f8360015f19611f76565b6107a55760405162461bcd60e51b8152602060048201526005602482015264047533030360dc1b60448201526064016106af565b604080516001600160a01b03841660248201526044808201849052825180830390910181526064909101909152602080820180516001600160e01b031663a9059cbb60e01b17815282515f93929184919082896127105a03f13d80156124c457602081146124cc575f93506124d6565b8193506124d6565b5f51158215171593505b5050509392505050565b6001600160a01b03811681146124f4575f80fd5b50565b8035612502816124e0565b919050565b5f8060408385031215612518575f80fd5b8235612523816124e0565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f830112612554575f80fd5b813567ffffffffffffffff8082111561256f5761256f612531565b604051601f8301601f19908116603f0116810190828211818310171561259757612597612531565b816040528381528660208588010111156125af575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f805f80608085870312156125e1575f80fd5b84359350602085013567ffffffffffffffff808211156125ff575f80fd5b61260b88838901612545565b94506040870135915080821115612620575f80fd5b5061262d87828801612545565b949793965093946060013593505050565b5f6020828403121561264e575f80fd5b8135611f55816124e0565b803560028110612502575f80fd5b5f805f806080858703121561267a575f80fd5b8435612685816124e0565b935060208501359250604085013567ffffffffffffffff8111156126a7575f80fd5b6126b387828801612545565b9250506126c260608601612659565b905092959194509250565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b8215158152604060208201525f610d7560408301846126cd565b5f8060408385031215612726575f80fd5b50508035926020909101359150565b602081525f611f5560208301846126cd565b5f60208284031215612757575f80fd5b5035919050565b5f8083601f84011261276e575f80fd5b50813567ffffffffffffffff811115612785575f80fd5b60208301915083602082850101111561279c575f80fd5b9250929050565b5f805f805f805f805f805f6101408c8e0312156127be575f80fd5b6127c78c6124f7565b9a5060208c0135995067ffffffffffffffff8060408e013511156127e9575f80fd5b6127f98e60408f01358f0161275e565b909a50985061280a60608e01612659565b975060808d0135965060a08d0135955060c08d0135945061282d60e08e016124f7565b935061283c6101008e016124f7565b9250806101208e0135111561284f575f80fd5b506128618d6101208e01358e01612545565b90509295989b509295989b9093969950565b5f805f60608486031215612885575f80fd5b83359250602084013567ffffffffffffffff808211156128a3575f80fd5b6128af87838801612545565b935060408601359150808211156128c4575f80fd5b506128d186828701612545565b9150509250925092565b5f815180845260208085019450602084015f5b838110156129135781516001600160a01b0316875295820195908201906001016128ee565b509495945050505050565b602081525f611f5560208301846128db565b5f8060408385031215612941575f80fd5b823561294c816124e0565b9150602083013567ffffffffffffffff811115612967575f80fd5b61297385828601612545565b9150509250929050565b5f805f805f805f805f806101008b8d031215612997575f80fd5b8a3567ffffffffffffffff808211156129ae575f80fd5b818d0191508d601f8301126129c1575f80fd5b8135818111156129cf575f80fd5b8e60208260051b85010111156129e3575f80fd5b60208381019d50909b508d013599506129fe60408e016124f7565b985060608d0135915080821115612a13575f80fd5b50612a208d828e0161275e565b9097509550612a33905060808c016124f7565b9350612a4160a08c016124f7565b925060c08b01359150612a5660e08c016124f7565b90509295989b9194979a5092959850565b604081525f612a7960408301856128db565b905060018060a01b03831660208301529392505050565b5f805f805f805f805f805f6101408c8e031215612aab575f80fd5b8b35612ab6816124e0565b9a5060208c0135995060408c013567ffffffffffffffff811115612ad8575f80fd5b612ae48e828f0161275e565b909a509850612af7905060608d01612659565b965060808c0135955060a08c0135945060c08c0135935060e08c0135612b1c816124e0565b92506101008c0135612b2d816124e0565b809250506101208c013590509295989b509295989b9093969950565b5f8060408385031215612b5a575f80fd5b8235612b65816124e0565b91506020830135612b75816124e0565b809150509250929050565b5f805f60608486031215612b92575f80fd5b8335612b9d816124e0565b92506020840135612bad816124e0565b91506040840135612bbd816124e0565b809150509250925092565b5f805f60608486031215612bda575f80fd5b8335612be5816124e0565b92506020840135612bf5816124e0565b929592945050506040919091013590565b602080825260059082015264475332303360d81b604082015260600190565b60208082526005908201526411d4cc8c0d60da1b604082015260600190565b634e487b7160e01b5f52601160045260245ffd5b5f60018201612c6957612c69612c44565b5060010190565b604081525f612c8260408301856126cd565b8281036020840152611fb181856126cd565b5f60208284031215612ca4575f80fd5b81516001600160e01b031981168114611f55575f80fd5b60ff8281168282160390811115610c6d57610c6d612c44565b8082028115828204841417610c6d57610c6d612c44565b602080825260059082015264475332303160d81b604082015260600190565b634e487b7160e01b5f52602160045260245ffd5b60028110612d3a57634e487b7160e01b5f52602160045260245ffd5b9052565b6001600160a01b038d168152602081018c90526101606040820181905281018a90525f6101808b8d828501375f838d01820152601f8c01601f19168301612d88606085018d612d1e565b8a60808501528960a08501528860c0850152612daf60e08501896001600160a01b03169052565b6001600160a01b0387166101008501528184820301610120850152612dd6828201876126cd565b92505050612df06101408301846001600160a01b03169052565b9d9c50505050505050505050505050565b80820180821115610c6d57610c6d612c44565b5f82612e2e57634e487b7160e01b5f52601260045260245ffd5b500490565b81810381811115610c6d57610c6d612c44565b634e487b7160e01b5f52603260045260245ffd5b608080825281018590525f8660a08301825b88811015612e9c578235612e7f816124e0565b6001600160a01b0316825260209283019290910190600101612e6c565b50602084019690965250506001600160a01b039283166040820152911660609091015292915050565b5f60208284031215612ed5575f80fd5b81518015158114611f55575f80fd5b818382375f9101908152919050565b8b81526001600160a01b038b81166020830152604082018b9052606082018a9052610160820190612f27608084018b612d1e565b60a083019890985260c082019690965260e0810194909452918516610100840152909316610120820152610140019190915295945050505050565b5f81612f7057612f70612c44565b505f19019056fea2646970667358221220d98ce5a63765aa68dee25f430f678dd1c6cba6c1883c4942b2363d367a9039f464736f6c63430008190033"; - bytes public constant SAFE_PROXY_FACTORY_BYTECODE = - hex"6080604052348015600e575f5ffd5b506107668061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610055575f3560e01c80631688f0b9146100595780633408e4701461008957806353e5d93514610097578063d18af54d146100ac578063ec9e80bb146100bf575b5f5ffd5b61006c610067366004610472565b6100d2565b6040516001600160a01b0390911681526020015b60405180910390f35b604051468152602001610080565b61009f610166565b60405161008091906104f6565b61006c6100ba36600461050f565b610190565b61006c6100cd366004610472565b61025f565b5f5f8380519060200120836040516020016100f7929190918252602082015260400190565b60405160208183030381529060405280519060200120905061011a858583610290565b6040516001600160a01b038781168252919350908316907f4f51faf6c4561ff95f067657e43439f0f856d97c04d9ec9070a6199ad418e2359060200160405180910390a2509392505050565b606060405180602001610178906103af565b601f1982820381018352601f90910116604052919050565b5f5f83836040516020016101c092919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b604051602081830303815290604052805190602001205f1c90506101e58686836100d2565b91506001600160a01b03831615610256576040516303ca56a360e31b81526001600160a01b03841690631e52b518906102289085908a908a908a90600401610577565b5f604051808303815f87803b15801561023f575f5ffd5b505af1158015610251573d5f5f3e3d5ffd5b505050505b50949350505050565b5f5f8380519060200120836102714690565b60408051602081019490945283019190915260608201526080016100f7565b5f833b6102e45760405162461bcd60e51b815260206004820152601f60248201527f53696e676c65746f6e20636f6e7472616374206e6f74206465706c6f7965640060448201526064015b60405180910390fd5b5f604051806020016102f5906103af565b601f1982820381018352601f90910116604081905261032291906001600160a01b038816906020016105b3565b6040516020818303038152906040529050828151826020015ff591506001600160a01b03821661038a5760405162461bcd60e51b815260206004820152601360248201527210dc99585d194c8818d85b1b0819985a5b1959606a1b60448201526064016102db565b8351156103a7575f5f5f8651602088015f875af1036103a7575f5ffd5b509392505050565b610163806105ce83390190565b6001600160a01b03811681146103d0575f5ffd5b50565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126103f6575f5ffd5b813567ffffffffffffffff811115610410576104106103d3565b604051601f8201601f19908116603f0116810167ffffffffffffffff8111828210171561043f5761043f6103d3565b604052818152838201602001851015610456575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f5f60608486031215610484575f5ffd5b833561048f816103bc565b9250602084013567ffffffffffffffff8111156104aa575f5ffd5b6104b6868287016103e7565b93969395505050506040919091013590565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61050860208301846104c8565b9392505050565b5f5f5f5f60808587031215610522575f5ffd5b843561052d816103bc565b9350602085013567ffffffffffffffff811115610548575f5ffd5b610554878288016103e7565b93505060408501359150606085013561056c816103bc565b939692955090935050565b6001600160a01b038581168252841660208201526080604082018190525f906105a2908301856104c8565b905082606083015295945050505050565b5f83518060208601845e919091019182525060200191905056fe6080604052348015600e575f5ffd5b50604051610163380380610163833981016040819052602b9160b2565b6001600160a01b038116608f5760405162461bcd60e51b815260206004820152602260248201527f496e76616c69642073696e676c65746f6e20616464726573732070726f766964604482015261195960f21b606482015260840160405180910390fd5b5f80546001600160a01b0319166001600160a01b039290921691909117905560dd565b5f6020828403121560c1575f5ffd5b81516001600160a01b038116811460d6575f5ffd5b9392505050565b607a806100e95f395ff3fe60806040525f80546001600160a01b03169035632cf35bc960e11b01602657805f5260205ff35b365f5f375f5f365f845af490503d5f5f3e80603f573d5ffd5b503d5ff3fea2646970667358221220640def201af13e0821a9dcaf5c656634c958a7cf37a69d829387126c436276e364736f6c634300081c0033a2646970667358221220e6be85b164b5d425d66785699e181cd85bffd8ff4fcbc6d6b2c6e7b4dacdeb4664736f6c634300081c0033"; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/SmartSessionsPrecompiles.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/SmartSessionsPrecompiles.sol deleted file mode 100644 index 853ccf6..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/precompiles/SmartSessionsPrecompiles.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/* solhint-disable max-line-length */ -import { etch } from "../../test/utils/Vm.sol"; - -// Interfaces -import { ISmartSession } from "../../integrations/interfaces/ISmartSession.sol"; - -/// @dev Preset smart session contract address -address constant SMARTSESSION_ADDR = 0x0000000071727De22e5E9D8bAF0EDAc6F37da034; - -function etchSmartSessions() returns (ISmartSession) { - etch(address(SMARTSESSION_ADDR), SMART_SESSION_DEPLOYED_BYTECODE); - return ISmartSession(SMARTSESSION_ADDR); -} - -/*////////////////////////////////////////////////////////////// - BYTECODES -//////////////////////////////////////////////////////////////*/ - -bytes constant SMART_SESSION_DEPLOYED_BYTECODE = - hex"608060405234801561001057600080fd5b506004361061025c5760003560e01c80639700320311610145578063d527ed6e116100bd578063f551e2ee1161008c578063f77a7eac11610071578063f77a7eac14610587578063f867b08e1461059a578063f9b80369146105ad57600080fd5b8063f551e2ee14610530578063f55af6d11461057457600080fd5b8063d527ed6e146104d0578063d60b347f146104e3578063d620c85a146104f6578063ecd059611461051c57600080fd5b8063adbc532f11610114578063c9a5ec39116100f9578063c9a5ec3914610497578063d056b06d146104aa578063d0e6f608146104bd57600080fd5b8063adbc532f14610471578063af29e6b21461048457600080fd5b80639700320314610418578063a67c714e1461042b578063a7ef62051461043e578063a9fa4b441461045157600080fd5b8063454c9d82116101d85780636d61fe70116101a7578063795f92691161018c578063795f9269146103be5780638a91b0e3146103f257806396e729621461040557600080fd5b80636d61fe70146103985780636e79eee0146103ab57600080fd5b8063454c9d821461033e578063496c8a91146103515780634e33ad2e1461037257806367bb29c41461038557600080fd5b806328f7392d1161022f57806330ce43401161021457806330ce4340146102f8578063364d240f1461030b57806344d1628c1461031e57600080fd5b806328f7392d146102d05780632dadb5e9146102e557600080fd5b806309e5aef8146102615780630ac8f150146102895780631097109e146102aa5780632445e73e146102bd575b600080fd5b61027461026f3660046145c3565b6105c0565b60405190151581526020015b60405180910390f35b61029c61029736600461460d565b6105ef565b604051908152602001610280565b6102746102b836600461468d565b610600565b6102746102cb36600461468d565b610610565b6102e36102de3660046146e9565b610620565b005b6102746102f336600461468d565b6106ce565b6102746103063660046148aa565b6106de565b6102e3610319366004614903565b61070c565b61033161032c366004614982565b610802565b60405161028091906149ae565b6102e361034c366004614b00565b61081d565b61036461035f366004614982565b610883565b604051610280929190614b8d565b6102e3610380366004614cbe565b6108c5565b61029c610393366004614ded565b61091e565b6102e36103a6366004614f6d565b610955565b6102e36103b9366004614faf565b6109bd565b61029c6103cc366004614fea565b6000918252602082815260408084206001600160a01b0393909316845291905290205490565b6102e3610400366004614f6d565b610aae565b6102e361041336600461500f565b610aea565b61029c610426366004615031565b610bb9565b610331610439366004614982565b610d55565b61027461044c36600461506e565b610d70565b61046461045f366004614982565b610d89565b60405161028091906150b0565b61027461047f366004614fea565b610da4565b6102746104923660046150e8565b610db2565b6102746104a5366004614fea565b610dcb565b6102e36104b836600461511d565b610df6565b6104646104cb366004614982565b610e54565b6103316104de3660046150e8565b610e6f565b6102746104f1366004615169565b610e9d565b7fd620c85a0000000000000000000000000000000000000000000000000000000061029c565b61027461052a366004615186565b60011490565b61054361053e36600461519f565b610eb4565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610280565b6104646105823660046151ef565b610f1a565b61027461059536600461506e565b611179565b6102e36105a8366004615186565b611192565b6102e36105bb366004615186565b6112e8565b600082815260036020908152604080832086845290915281206105e4908684611363565b90505b949350505050565b60006105fa82611394565b92915050565b60006105e46002858786866113e5565b60006105e46001858786866113e5565b61062c6005338461147d565b151560000361066f576040517f92d69f9c000000000000000000000000000000000000000000000000000000008152600481018390526024015b60405180910390fd5b61068f61067c8280615225565b6106859161528d565b60079084336114a9565b6106ca6003836106a66106a186611508565b611543565b6106b36020860186615225565b6106bc9161529a565b60029392919033600161154f565b5050565b60006105e4600385878686611709565b6000610702846106ed846117d5565b6000868152600760205260409020919061147d565b90505b9392505050565b6107186005338761147d565b1515600003610756576040517f92d69f9c00000000000000000000000000000000000000000000000000000000815260048101869052602401610666565b60005b818110156107ea5760006107c4848484818110610778576107786152a7565b905060200281019061078a91906152d6565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506117d592505050565b60008881526007602052604090209091506107e09033836117e8565b5050600101610759565b506107fb60026003338888886117f5565b5050505050565b60008181526001602052604090206060906107059084611897565b6108296005338461147d565b1515600003610867576040517f92d69f9c00000000000000000000000000000000000000000000000000000000815260048101839052602401610666565b6106ca60018361087681611543565b600192919085338561154f565b60008181526008602090815260408083206001600160a01b03808716855292529091208054909116906060906108bb600182016118a5565b9150509250929050565b6108d16005338461147d565b151560000361090f576040517f92d69f9c00000000000000000000000000000000000000000000000000000000815260048101839052602401610666565b6106ca600383833360016118b0565b6000848152602081815260408083206001600160a01b038716845290915281205461094b84868584611a41565b9695505050505050565b6000610962600533611a50565b111561099c576040517fbcf00e1d000000000000000000000000000000000000000000000000000000008152336004820152602401610666565b60008190036109a9575050565b813582016020810190356107fb8282610f1a565b6109c96005338661147d565b1515600003610a07576040517f92d69f9c00000000000000000000000000000000000000000000000000000000815260048101859052602401610666565b6000838152600360205260409020610a24906002338786866117f5565b60008381526003602090815260408083208784529091529020610a479033611a50565b600003610aa8576000848152600460205260409020610a679033856117e8565b506040805185815260208101859052338183015290517ffb5966a10bbfa837a7964784b0eb92d624218037b24ae5d1aeae23157f21453f9181900360600190a15b50505050565b6000610abb600533611a50565b905060005b81811015610aa8576000610ad660053383611a5c565b9050610ae181611192565b50600101610ac0565b610af66005338461147d565b1515600003610b34576040517f92d69f9c00000000000000000000000000000000000000000000000000000000815260048101839052602401610666565b60008181526003602090815260408083208584529091529020610b579033611a69565b6000828152600460205260409020610b709033836117e8565b50604080518381526020810183905233918101919091527ffb5966a10bbfa837a7964784b0eb92d624218037b24ae5d1aeae23157f21453f906060015b60405180910390a15050565b600080610bc96020850185615169565b90506001600160a01b0381163314610c18576040517f04a4ab940000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610666565b6000803681610c33610c2e6101008a018a6152d6565b611a73565b9350935093509350610c55846002811115610c5057610c5061533b565b611b08565b15610cac57610ca583888a610c9f86868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b2592505050565b89611b43565b9550610d4a565b610cc6846002811115610cc157610cc161533b565b611fcb565b15610d1657610cd361451e565b6060610cdf8484611fef565b60408201519193509150610cf290612056565b9450610d0082868989612079565b610d0d858a8c848b611b43565b97505050610d4a565b836040517f97dc33dc000000000000000000000000000000000000000000000000000000008152600401610666919061536a565b505050505092915050565b60008181526002602052604090206060906107059084611897565b6000828152600260205260408120610702908584611363565b60008181526004602052604090206060906107059084611897565b60006107056005838561147d565b600082815260046020526040812061070290858461147d565b60008281526008602090815260408083206001600160a01b0380861685529252822054161515610705565b610e026005338561147d565b1515600003610e40576040517f92d69f9c00000000000000000000000000000000000000000000000000000000815260048101849052602401610666565b610e4f600180338686866117f5565b505050565b60008181526007602052604090206060906107059084611897565b60008181526003602090815260408083208584529091529020606090610e959085611897565b509392505050565b600080610eab600584611a50565b15159392505050565b6000306001600160a01b03861603610eed57507fffffffff000000000000000000000000000000000000000000000000000000006105e7565b6000610f038686610efe87876122a7565b6122dd565b15600003631626ba7e1760e01b9695505050505050565b6060816000819003610f58576040517f5cb045db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff811115610f7157610f71614737565b604051908082528060200260200182016040528015610f9a578160200160208202803683370190505b50915060005b818110156111715736858583818110610fbb57610fbb6152a7565b9050602002810190610fcd9190615384565b90506000610fda82611394565b905061100e600182610feb81611543565b610ff86060870187615225565b6110019161529a565b600193929190338561154f565b61103b6003826110206106a185611508565b61102d60808701876153c2565b6106b3906020810190615225565b61106861104b60808401846153c2565b6110559080615225565b61105e9161528d565b60079083336114a9565b61108e8161107960a0850185615225565b611082916153f6565b600391903360016118b0565b61109a600533836124c4565b506110fd81336110ad6020860186615169565b6110ba60208701876152d6565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250600896959493925060019150506124d1565b80858481518110611110576111106152a7565b6020026020010181815250507fc5c98ce9477fc2c88a84abed218cda086be8442fc2eecb9e1ce33941d28741b6813360405161115f9291909182526001600160a01b0316602082015260400190565b60405180910390a15050600101610fa0565b505092915050565b6000828152600160205260408120610702908584611363565b806111cc576040517f92d69f9c00000000000000000000000000000000000000000000000000000000815260048101829052602401610666565b60008181526001602052604090206111e49033611a69565b60008181526002602052604090206111fc9033611a69565b60008181526004602052604081206112149033611a50565b905060005b8181101561126957600083815260046020526040812061123a903384611a5c565b600081815260036020908152604080832088845290915290209091506112609033611a69565b50600101611219565b5060008281526004602052604090206112829033611a69565b61128e600883336126ea565b61129a600533846117e8565b5060008281526007602052604090206112b39033611a69565b604080518381523360208201527f1ff4377bcf87e5e9c2ec7fdc4732408c1073dd4b9f49e719d783b1e4fb0f62819101610bad565b60008181526020818152604080832033845290915281208054908261130c83615432565b9091555090507fb21cd80665df6c8932e067c1fb0835dc3bc61d85bcab4c90a9992b692d8e17e2823361134084600161546a565b604080519384526001600160a01b03909216602084015290820152606001610bad565b6001600160a01b03818116600090815260018501602090815260408083209386168352929052908120541515610702565b60006113a36020830183615169565b6113b060208401846152d6565b84604001356040516020016113c894939291906154a8565b604051602081830303815290604052805190602001209050919050565b6000818082036113f9576001915050611474565b60005b8181101561146d576000858583818110611418576114186152a7565b905060200281019061142a91906153c2565b611433906154dc565b805160008a815260208c90526040902091925090611452908983611363565b611463576000945050505050611474565b50506001016113fc565b5060019150505b95945050505050565b600081815260018401602090815260408083206001600160a01b03861684529091528120541515610702565b825160005b818110156115005760006114da8683815181106114cd576114cd6152a7565b60200260200101516117d5565b60008681526020899052604090209091506114f69085836124c4565b50506001016114ae565b505050505050565b6040517f455243313237313a2000000000000000000000000000000000000000000000006020820152602981018290526000906049016113c8565b60006105fa8233612782565b825160005b818110156116fe576000858281518110611570576115706152a7565b60209081029190910101515190506115916001600160a01b0382168a6127dd565b831561161f576040517f4c13560c0000000000000000000000000000000000000000000000000000000081526001600160a01b038087166004830152821660248201526e69e2a187aeffb852bf3ccdc95151b290634c13560c9060440160006040518083038186803b15801561160657600080fd5b505afa15801561161a573d6000803e3d6000fd5b505050505b600088815260208b905260409020611638908683612a1c565b50806001600160a01b031663989c9e46868989868151811061165c5761165c6152a7565b6020026020010151602001516040518463ffffffff1660e01b8152600401611686939291906154e8565b600060405180830381600087803b1580156116a057600080fd5b505af11580156116b4573d6000803e3d6000fd5b505050507f1c5ea73ef804151087de6d0ce7a77287b15cfc4f51654cac5bfe6c558547f827888a83886040516116ed9493929190615510565b60405180910390a150600101611554565b505050505050505050565b60008180820361171d576001915050611474565b60005b8181101561146d573685858381811061173b5761173b6152a7565b905060200281019061174d919061554c565b905060006117806117616020840184615580565b6117716040850160208601615169565b6001600160a01b031690612a32565b90506117ba89896117946040860186615225565b8e60000160008781526020019081526020016000206113e590949392919063ffffffff16565b6117cb576000945050505050611474565b5050600101611720565b6000816040516020016113c8919061559d565b6000610702848484612a94565b8060005b8181101561188d576000848483818110611815576118156152a7565b905060200201602081019061182a9190615169565b600087815260208b905260409020909150611846908883612b79565b507fb2a53c8ed9d14361634fc2a7835a222e5dbec408b6cef4e06768e844613fa7548689838a60405161187c9493929190615510565b60405180910390a1506001016117f9565b5050505050505050565b606060006105e78484612b8f565b60606105fa82612b9b565b836118ea576040517f526d0da500000000000000000000000000000000000000000000000000000000815260048101859052602401610666565b825160005b81811015611a3857600085828151811061190b5761190b6152a7565b6020026020010151905060006001600160a01b031681602001516001600160a01b03161480611946575060208101516001600160a01b031630145b1561197d576040517fe068d3a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602082015160009161199a916001600160a01b031690612a32565b9050806119d3576040517fe068d3a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600088815260018a01602052604090206119ee9087836124c4565b50611a2e6002896119ff8185612c65565b85604001518a8a8f600001600089815260200190815260200160002061154f909695949392919063ffffffff16565b50506001016118ef565b50505050505050565b60006105e48585308686612c7a565b60006107058383612d70565b6000610702848484612d7c565b6106ca8282612d89565b6000803681611a8560018287896155af565b611a8e916155d9565b60f81c6002811115611aa257611aa261533b565b9350611ab9846002811115610cc157610cc161533b565b15611ad457611acb85600181896155af565b91509150611aff565b611ae26021600187896155af565b611aeb9161563f565b9250611afa85602181896155af565b915091505b92959194509250565b6000805b826002811115611b1e57611b1e61533b565b1492915050565b6060611b3082612dd9565b8060200190518101906105fa91906156c2565b6000611b516005838861147d565b611b8a576040517f526d0da500000000000000000000000000000000000000000000000000000000815260048101879052602401610666565b611c0e8487611b9881611543565b87604051602401611baa92919061575b565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f7129edce0000000000000000000000000000000000000000000000000000000017905260019291906000612e98565b90506000611c1f60608601866152d6565b611c2e916004916000916155af565b611c37916158ad565b90507f1651a3ad000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601611e3657600080611c9a611c9560608901896152d6565b612f5c565b90925090507fff00000000000000000000000000000000000000000000000000000000000000811615611cf9576040517f6c4872f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fff0000000000000000000000000000000000000000000000000000000000000082167f010000000000000000000000000000000000000000000000000000000000000003611d6157611d5a611d536003898c6001612f86565b859061306f565b9350611e2f565b7fff000000000000000000000000000000000000000000000000000000000000008216611dfd576000803681611dbc611db7611da060608e018e6152d6565b506024818101359091019081019160049091013590565b613198565b9350935093509350611df2611deb8c8f87878787600160036000016131de90979695949392919063ffffffff16565b899061306f565b975050505050611e2f565b6040517f6c4872f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050611f9e565b7f72288ed1000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601611eb1576040517f6c4872f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611eeb611ec360608801886152d6565b611ed2916004916000916155af565b611edb916158ad565b6001600160a01b03861690612a32565b9050611f9a611f93878a611eff8186612c65565b88806000611f1060608f018f6152d6565b604051602401611f2596959493929190615912565b60408051601f19818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f05c008950000000000000000000000000000000000000000000000000000000017905260008881526003909152209291906001612e98565b849061306f565b9250505b6000611fae600888868b8961357f565b905080611fc057600192505050611474565b505095945050505050565b60006001826002811115611fe157611fe161533b565b14806105fa57506002611b0c565b611ff761451e565b606061203884848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612dd992505050565b80602001905181019061204b9190615d84565b909590945092505050565b60008160000151826020015183604001516040516020016113c893929190615e8a565b6000838152602081815260408083206001600160a01b03861684529091528120805490826120a683615432565b90915550905060006120ba8685848661368f565b60608701516040517f1626ba7e000000000000000000000000000000000000000000000000000000008082529293506001600160a01b03871691631626ba7e91612108918691600401615ebc565b602060405180830381865afa158015612125573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121499190615ed5565b7fffffffff0000000000000000000000000000000000000000000000000000000016146121b4576040517f3ca8ef0c0000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260248101829052604401610666565b60006121d08460028111156121cb576121cb61533b565b6137a0565b90506121f76001876121e181611543565b60408b0151606001516001939291908a8761154f565b6040870151608001515161220f9060079088886114a9565b61223b6003876122216106a18a611508565b60408b015160800151602001516002939291908a8761154f565b604087015160a0015161225490600390889088856118b0565b60008681526008602090815260408083206001600160a01b03808a1685529252909120541661229b576040870151805160209091015161229b9160089189918991866124d1565b61188d600533886124c4565b36600083839150915061ffff60605119046164920260208203830135036122d657506040810135016020810190355b9250929050565b6000806122e86137a9565b604051909150849084908183017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe013560f01c8060420180880389016119016000526040816020378215828a10178b6042601e2018171561234e57600096505050612495565b7f5479706564446174615369676e280000000000000000000000000000000000008452600e8401836040830182376040820196508395506f07fffffe000000000000010000000000815160001a1c6028858301525b6028825160001a146123cb578065120100000001835160001a1c1790506001820191506123a3565b7f20636f6e74656e74732c627974657331206669656c64732c737472696e67206e82527f616d652c737472696e672076657273696f6e2c75696e7432353620636861696e60208301527f49642c6164647265737320766572696679696e67436f6e74726163742c62797460408301527f657333322073616c742c75696e743235365b5d20657874656e73696f6e7329006060830152607f82019150846040840183376040838a37908401859003852088526101208820604052600116604201601e209a5050909603955b50604052826124aa57600093505050506105e7565b6124b8888888888686613883565b98975050505050505050565b60006107028484846139c7565b6001600160a01b038316158061256657506040517fecd05961000000000000000000000000000000000000000000000000000000008152600760048201526001600160a01b0384169063ecd0596190602401602060405180830381865afa158015612540573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125649190615ef2565b155b156125a8576040517fa7eae1120000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610666565b801561263d576040517f529562a10000000000000000000000000000000000000000000000000000000081526001600160a01b03808616600483015284166024820152600760448201526e69e2a187aeffb852bf3ccdc95151b29063529562a19060640160006040518083038186803b15801561262457600080fd5b505afa158015612638573d6000803e3d6000fd5b505050505b6000858152602087815260408083206001600160a01b038881168552925290912080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169185169190911781556126986001820184613a50565b604080518781526001600160a01b03868116602083015287168183015290517f9e1deb1dcdedd38e68d5543a9a6be8416a0e0a5627628e47780bd6ef8abc1a3c9181900360600190a150505050505050565b6000828152602084815260408083206001600160a01b03858116808652918452938290208054835188815295169385019390935290830152907f1b8b78a1623842b0534f626565151ce282cc88268c30bf8d525c59d0c22f21db9060600160405180910390a180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168155610aa860018201613aae565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606083901b166020820152603481018390526000906054015b60405160208183030381529060405280519060200120905092915050565b600060018260038111156127f3576127f361533b565b036128a1576040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f7129edce0000000000000000000000000000000000000000000000000000000060048201526001600160a01b038416906301ffc9a7906024015b602060405180830381865afa158015612876573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061289a9190615ef2565b90506129da565b60028260038111156128b5576128b561533b565b0361291f576040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f05c008950000000000000000000000000000000000000000000000000000000060048201526001600160a01b038416906301ffc9a790602401612859565b60038260038111156129335761293361533b565b0361299d576040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527fcbf345050000000000000000000000000000000000000000000000000000000060048201526001600160a01b038416906301ffc9a790602401612859565b6040517f6a01dd010000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610666565b80610e4f576040517f6a01dd010000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610666565b600061070284846001600160a01b0385166139c7565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b1660208201527fffffffff00000000000000000000000000000000000000000000000000000000821660348201526000906038016127bf565b600081815260018401602090815260408083206001600160a01b03861684529091528120548015612b6f576000612acc600183615f14565b905060006001612adc8888613ad0565b612ae69190615f14565b9050808214612b32576000612afc888884613ae4565b9050612b0a88888584613af1565b600090815260018801602090815260408083206001600160a01b038a16845290915290208390555b612b3c8787613afd565b50505060008281526001808601602090815260408084206001600160a01b03881685529091528220919091559050610705565b6000915050610705565b600061070284846001600160a01b038516612a94565b60606107058383613b07565b80546060906000612bad602083615f27565b612bb890600161546a565b90506001840160008267ffffffffffffffff811115612bd957612bd9614737565b604051908082528060200260200182016040528015612c02578160200160208202803683370190505b50905060005b83811015612c3f57600081840154905080838381518110612c2b57612c2b6152a7565b602090810291909101015250600101612c08565b5080604051602001612c519190615f62565b604080519190529384525091949350505050565b6000610705612c748484613b13565b33612782565b60007f45f5f60cec99c2d0a0198ec513b02d6926b8ec63dfaf7e9afba954108dd97ebd8585856002811115612cb157612cb161533b565b895160408b01516020808d0151805191012060608d0151612cd190613b2f565b612cde8e60800151613baa565b612ceb8f60a00151613c26565b60408051602081019b909b526001600160a01b03998a16908b015296881660608a015260ff90951660808901529590921660a087015260c086015260e085015261010084019290925261012083019190915261014082015261016081018390526101800160405160208183030381529060405280519060200120905095945050505050565b60006107058383613ad0565b6000610702848484613ae4565b6000612d958383612d70565b905060015b818111610aa8576000612db78585612db28587615f14565b612d7c565b9050612dc4858583612a94565b50508080612dd190615432565b915050612d9a565b60405181516020838101938184019201015b80841015612e7f5783518060001a8060051c80612e1e575060018681015185529581016002019593019092019150612deb565b600781148360011a600701821881028218600201600185836001011a85601f1660081b01018088036020821860208311028218915060005b818101518a8201528201838110612e56579a84016002019a988301985050505050505050612deb565b50601f1982820301825260008152602001604052919050565b600080612ebf612eab6020880188615169565b600087815260208a90526040902090611897565b805190915080841115612f01576040517f1c792c0500000000000000000000000000000000000000000000000000000000815260048101879052602401610666565b60005b81811015612f5057612f46611d538888868581518110612f2657612f266152a7565b60200260200101516001600160a01b0316613c829092919063ffffffff16565b9350600101612f04565b50505095945050505050565b60008080612f6e6024600486886155af565b612f779161563f565b95600887901b95509350505050565b60003681612fab612f9d611da060608901896152d6565b508035016020810191903590565b9092509050806000819003612fec576040517f56d93c1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015613063573684848381811061300a5761300a6152a7565b905060200281019061301c919061554c565b9050600061304b8b8b8b6130336020870187615169565b602087013561304560408901896152d6565b8f6131de565b9050613057878261306f565b96505050600101612fef565b50505050949350505050565b600081830160601b8260601b81148460601b8214176001600160a01b03848618161517600181146130a35760019250611171565b7fffffffffffff000000000000000000000000000000000000000000000000000080851690861681811881831102188686176001600160a01b031617935079ffffffffffff0000000000000000000000000000000000000000861690816131225779ffffffffffff000000000000000000000000000000000000000091505b5079ffffffffffff0000000000000000000000000000000000000000851680613162575079ffffffffffff00000000000000000000000000000000000000005b80821890821102188061318c575079ffffffffffff00000000000000000000000000000000000000005b92909217949350505050565b60008036816131aa60148287896155af565b6131b391615f98565b60601c93506131c66034601487896155af565b6131cf9161563f565b9250611afa85603481896155af565b600080600484101561321157507fffffffff0000000000000000000000000000000000000000000000000000000061322b565b61321f6004600086886155af565b613228916158ad565b90505b7fffffffff0000000000000000000000000000000000000000000000000000000081167fe9ae5c5300000000000000000000000000000000000000000000000000000000148015613299575061328460208a018a615169565b6001600160a01b0316876001600160a01b0316145b156132d0576040517f540733ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001600160a01b03881601613332576040517f82d5d76a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006133476001600160a01b03891683612a32565b90506133e78a8a6133588185612c65565b61336560208f018f615169565b8c8c8c8c60405160240161337e96959493929190615912565b6040516020818303038152906040526305c0089560e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050878f6000878152602001908152602001600020613d4490949392919063ffffffff16565b92506350ffbaad8303613571576040516c0100000000000000000000000060208201527c0100000000000000000000000000000000000000000000000000000000603482015261356e908b908b9061346190603801604051602081830303815290604052805190602001208d612c6590919063ffffffff16565b61346e60208f018f615169565b8c8c8c8c60405160240161348796959493929190615912565b6040516020818303038152906040526305c0089560e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050878f600060018060e01b60405160200161353992919060609290921b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001682527fffffffff0000000000000000000000000000000000000000000000000000000016601482015260180190565b604051602081830303815290604052805190602001208152602001908152602001600020612e9890949392919063ffffffff16565b92505b505098975050505050505050565b6000828152602086815260408083206001600160a01b038088168552925282205416806135ea576040517f6aeeaff8000000000000000000000000000000000000000000000000000000008152600481018590526001600160a01b0386166024820152604401610666565b6000848152602088815260408083206001600160a01b03898116855292529091209082169063940d38409088908690613625906001016118a5565b6040518463ffffffff1660e01b815260040161364393929190615ffd565b602060405180830381865afa158015613660573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136849190615ef2565b979650505050505050565b604084015160009081906136a590868587611a41565b905060008660200151876000015160ff16815181106136c6576136c66152a7565b602002602001015160000151905060008760200151886000015160ff16815181106136f3576136f36152a7565b6020026020010151602001519050468267ffffffffffffffff1614613750576040517fe75e237900000000000000000000000000000000000000000000000000000000815267ffffffffffffffff83166004820152602401610666565b828114613793576040517f0b08d5be0000000000000000000000000000000000000000000000000000000081526004810182905260248101849052604401610666565b6124b88860200151613ddf565b60006001611b0c565b600080600080600080600080336001600160a01b03166384b0196e6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156137f3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261381b9190810190616086565b604080516101208101825260009890981a60f81b9088015285516020968701206060880152845194860194909420608087015260a08601929092526001600160a01b031660c085015260e0840152805160051b91012061010082015298975050505050505050565b6000806138c584848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506117d592505050565b905060006138d6602082888a6155af565b6138df9161563f565b90506138ee866020818a6155af565b90975095506138ff6005338361147d565b61390e5760009250505061094b565b600081815260076020526040902061392790338461147d565b6139365760009250505061094b565b600061395d338b8b8b8b8761394d6106a18a611508565b6002969594939291906000613f04565b905080613970576000935050505061094b565b6139b98933848b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060089695949392505061357f9050565b9a9950505050505050505050565b600081815260018401602090815260408083206001600160a01b0386168452909152812054613a48576000838152602085815260409091208054600101918202810184905555613a178484613ad0565b60008381526001808701602090815260408084206001600160a01b0389168552909152909120919091559050610705565b506000610705565b61014081511115613a6057600080fd5b6060613a6b82614027565b90845580519091506001840160005b82811015611500576000848281518110613a9657613a966152a7565b60209081029190910101518383015550600101613a7a565b600080825560018201905b600a811015610e4f57600082820155600101613ab9565b600081815260208390526040812054610705565b60006107028484846140e0565b610aa8848484846140f8565b6106ca8282614111565b6060610705838361416e565b60408051602081018490529081018290526000906060016127bf565b805160009081613b4f8260408051828152600190920160051b8201905290565b905060005b82811015613b9a57613b9181613b82878481518110613b7557613b756152a7565b602002602001015161420a565b600190910160051b8401528290565b50600101613b54565b50805160051b60208201206105e7565b6040805160038152608081019091527fdd8bf2f9b88fa557b2cb00ffd37dc4a3b8f3ff1d0d9e03c6f7c183f38869e91d6020820152600090613c036001613bf48560000151614275565b600190910160051b8301528190565b50613c166002613bf48560200151613b2f565b50805160051b6020820120610705565b805160009081613c468260408051828152600190920160051b8201905290565b905060005b82811015613b9a57613c7981613b82878481518110613c6c57613c6c6152a7565b60200260200101516142ff565b50600101613c4b565b60008080613cbd6001600160a01b0387167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360208861438e565b91509150600082613cde5763f427075260005260208201516020526024601cfd5b5060208101519250826001600160a01b03811615613d3a576040517f3b577361000000000000000000000000000000000000000000000000000000008152600481018790526001600160a01b0388166024820152604401610666565b5050509392505050565b600080613d57612eab6020880188615169565b805190915080841115613d72576350ffbaad92505050611474565b60005b81811015613da157613d97611d538888868581518110612f2657612f266152a7565b9350600101613d75565b506350ffbaad8303611fc0576040517f2d39e3f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000807f9af9262be547d4cc9dd06591bab37efd72d2b9d5fca173afd326b5b5410dac18613e0c84614419565b60408051602081019390935282015260600160408051601f1981840301815282825280516020918201207fb03948446334eb9b2196d5eb166f69b9d49403eb4a12f36de8d3f9f3cb8e15c3918401919091527f174e195918c922f8ce2a6d59c7e3e4eb4908dcdb2e305d06e24a973039099ed4918301919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606083015291506107059060800160408051601f198184030181529082905280516020909101207f190100000000000000000000000000000000000000000000000000000000000082526002820152602281018390526042902090565b600083815260208a9052604081208190613f1e908b611897565b805190915080841115613f60576040517f1c792c0500000000000000000000000000000000000000000000000000000000815260048101879052602401610666565b60005b8181101561401657828181518110613f7d57613f7d6152a7565b60200260200101516001600160a01b031663cbf34505878d8f8e8e8e6040518763ffffffff1660e01b8152600401613fba96959493929190615912565b602060405180830381865afa158015613fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ffb9190615ef2565b93508361400e576000935050505061401a565b600101613f63565b5050505b9998505050505050505050565b8051606061014082111561403a57600080fd5b6000614047602084615f27565b61405290600161546a565b90508067ffffffffffffffff81111561406d5761406d614737565b604051908082528060200260200182016040528015614096578160200160208202803683370190505b50915060005b818110156140d9576000602060018301028601519050808483815181106140c5576140c56152a7565b60209081029190910101525060010161409c565b5050915091565b60008281526020849052604081206107029083614475565b6000838152602085905260409020610aa890838361449d565b6000818152602083905260408120805490918190036141305750505050565b6141468261413f600184615f14565b600061449d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190555050565b60008181526020839052604090208054606091908067ffffffffffffffff81111561419b5761419b614737565b6040519080825280602002602001820160405280156141c4578160200160208202803683370190505b50925060005b81811015614201576141dc8382614475565b8482815181106141ee576141ee6152a7565b60209081029190910101526001016141ca565b50505092915050565b80516020808301518051908201206040516000936113c8937fdddac12cd8b10a071bea04226e97ac9490698394e19224abc47a5cfeeeb6ee97939192019283526001600160a01b03919091166020830152604082015260600190565b60019190910160051b82015290565b8051600090816142958260408051828152600190920160051b8201905290565b905060005b82811015613b9a576142f6818683815181106142b8576142b86152a7565b60200260200101516040516020016142d0919061559d565b60405160208183030381529060405280519060200120846142669092919063ffffffff16565b5060010161429a565b60007f35809859dccf8877c407a59527c2f00fb81ca9c198ebcb0c832c3deaa38d350260001b8260000151836020015161433c8560400151613b2f565b6040805160208101959095527fffffffff00000000000000000000000000000000000000000000000000000000909316928401929092526001600160a01b03166060830152608082015260a0016113c8565b6000606060008060008661ffff1667ffffffffffffffff8111156143b4576143b4614737565b6040519080825280601f01601f1916602001820160405280156143de576020820181803683370190505b5090506000808751602089018b8e8ef191503d9250868311156143ff578692505b828152826000602083013e90999098509650505050505050565b8051600090816144398260408051828152600190920160051b8201905290565b905060005b82811015613b9a5761446c81613b8287848151811061445f5761445f6152a7565b60200260200101516144c7565b5060010161443e565b60008254821061449157638277484f600052816020526024601cfd5b50600101602002015490565b825482106144b757638277484f600052816020526024601cfd5b8060018301602002840155505050565b80516020808301516040516000936113c8937f9c5d301c45209fe15c8bb85bc08d4234ac9e1d48c0d22b7ab701ae25e640086b9391920192835267ffffffffffffffff919091166020830152604082015260600190565b60408051608081018252600081526060602082015290810161453e61454b565b8152602001606081525090565b6040518060c0016040528060006001600160a01b0316815260200160608152602001600080191681526020016060815260200161453e604051806040016040528060608152602001606081525090565b6001600160a01b03811681146145b057600080fd5b50565b80356145be8161459b565b919050565b600080600080608085870312156145d957600080fd5b84356145e48161459b565b9350602085013592506040850135915060608501356146028161459b565b939692955090935050565b60006020828403121561461f57600080fd5b813567ffffffffffffffff81111561463657600080fd5b820160c0818503121561070557600080fd5b60008083601f84011261465a57600080fd5b50813567ffffffffffffffff81111561467257600080fd5b6020830191508360208260051b85010111156122d657600080fd5b600080600080606085870312156146a357600080fd5b84356146ae8161459b565b935060208501359250604085013567ffffffffffffffff8111156146d157600080fd5b6146dd87828801614648565b95989497509550505050565b600080604083850312156146fc57600080fd5b82359150602083013567ffffffffffffffff81111561471a57600080fd5b83016040818603121561472c57600080fd5b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561478957614789614737565b60405290565b6040516060810167ffffffffffffffff8111828210171561478957614789614737565b60405160c0810167ffffffffffffffff8111828210171561478957614789614737565b6040516080810167ffffffffffffffff8111828210171561478957614789614737565b604051601f8201601f1916810167ffffffffffffffff8111828210171561482157614821614737565b604052919050565b600067ffffffffffffffff82111561484357614843614737565b50601f01601f191660200190565b600082601f83011261486257600080fd5b813560208301600061487b61487684614829565b6147f8565b905082815285838301111561488f57600080fd5b82826020830137600092810160200192909252509392505050565b6000806000606084860312156148bf57600080fd5b83356148ca8161459b565b925060208401359150604084013567ffffffffffffffff8111156148ed57600080fd5b6148f986828701614851565b9150509250925092565b60008060008060006060868803121561491b57600080fd5b85359450602086013567ffffffffffffffff81111561493957600080fd5b61494588828901614648565b909550935050604086013567ffffffffffffffff81111561496557600080fd5b61497188828901614648565b969995985093965092949392505050565b6000806040838503121561499557600080fd5b82356149a08161459b565b946020939093013593505050565b602080825282518282018190526000918401906040840190835b818110156149ef5783516001600160a01b03168352602093840193909201916001016149c8565b509095945050505050565b600067ffffffffffffffff821115614a1457614a14614737565b5060051b60200190565b600060408284031215614a3057600080fd5b614a38614766565b90508135614a458161459b565b8152602082013567ffffffffffffffff811115614a6157600080fd5b614a6d84828501614851565b60208301525092915050565b6000614a87614876846149fa565b838152905060208101600584901b830185811115614aa457600080fd5b835b81811015613d3a57803567ffffffffffffffff811115614ac557600080fd5b614ad188828801614a1e565b84525060209283019201614aa6565b600082601f830112614af157600080fd5b61070583833560208501614a79565b60008060408385031215614b1357600080fd5b82359150602083013567ffffffffffffffff811115614b3157600080fd5b6108bb85828601614ae0565b60005b83811015614b58578181015183820152602001614b40565b50506000910152565b60008151808452614b79816020860160208601614b3d565b601f01601f19169290920160200192915050565b6001600160a01b03831681526040602082015260006107026040830184614b61565b7fffffffff00000000000000000000000000000000000000000000000000000000811681146145b057600080fd5b6000614beb614876846149fa565b838152905060208101600584901b830185811115614c0857600080fd5b835b81811015613d3a57803567ffffffffffffffff811115614c2957600080fd5b850160608189031215614c3b57600080fd5b614c4361478f565b8135614c4e81614baf565b81526020820135614c5e8161459b565b6020820152604082013567ffffffffffffffff811115614c7d57600080fd5b614c898a828501614ae0565b60408301525084525060209283019201614c0a565b600082601f830112614caf57600080fd5b61070583833560208501614bdd565b60008060408385031215614cd157600080fd5b82359150602083013567ffffffffffffffff811115614cef57600080fd5b6108bb85828601614c9e565b6000614d09614876846149fa565b838152905060208101600584901b830185811115614d2657600080fd5b835b81811015613d3a57803567ffffffffffffffff811115614d4757600080fd5b614d5388828801614851565b84525060209283019201614d28565b600060408284031215614d7457600080fd5b614d7c614766565b9050813567ffffffffffffffff811115614d9557600080fd5b8201601f81018413614da657600080fd5b614db584823560208401614cfb565b825250602082013567ffffffffffffffff811115614dd257600080fd5b614a6d84828501614ae0565b8035600381106145be57600080fd5b60008060008060808587031215614e0357600080fd5b843593506020850135614e158161459b565b9250604085013567ffffffffffffffff811115614e3157600080fd5b850160c08188031215614e4357600080fd5b614e4b6147b2565b614e54826145b3565b8152602082013567ffffffffffffffff811115614e7057600080fd5b614e7c89828501614851565b60208301525060408281013590820152606082013567ffffffffffffffff811115614ea657600080fd5b614eb289828501614ae0565b606083015250608082013567ffffffffffffffff811115614ed257600080fd5b614ede89828501614d62565b60808301525060a082013567ffffffffffffffff811115614efe57600080fd5b614f0a89828501614c9e565b60a0830152509250614f20905060608601614dde565b905092959194509250565b60008083601f840112614f3d57600080fd5b50813567ffffffffffffffff811115614f5557600080fd5b6020830191508360208285010111156122d657600080fd5b60008060208385031215614f8057600080fd5b823567ffffffffffffffff811115614f9757600080fd5b614fa385828601614f2b565b90969095509350505050565b60008060008060608587031215614fc557600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156146d157600080fd5b60008060408385031215614ffd57600080fd5b82359150602083013561472c8161459b565b6000806040838503121561502257600080fd5b50508035926020909101359150565b6000806040838503121561504457600080fd5b823567ffffffffffffffff81111561505b57600080fd5b830161012081860312156149a057600080fd5b60008060006060848603121561508357600080fd5b833561508e8161459b565b92506020840135915060408401356150a58161459b565b809150509250925092565b602080825282518282018190526000918401906040840190835b818110156149ef5783518352602093840193909201916001016150ca565b6000806000606084860312156150fd57600080fd5b83356151088161459b565b95602085013595506040909401359392505050565b60008060006040848603121561513257600080fd5b83359250602084013567ffffffffffffffff81111561515057600080fd5b61515c86828701614648565b9497909650939450505050565b60006020828403121561517b57600080fd5b81356107058161459b565b60006020828403121561519857600080fd5b5035919050565b600080600080606085870312156151b557600080fd5b84356151c08161459b565b935060208501359250604085013567ffffffffffffffff8111156151e357600080fd5b6146dd87828801614f2b565b6000806020838503121561520257600080fd5b823567ffffffffffffffff81111561521957600080fd5b614fa385828601614648565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261525a57600080fd5b83018035915067ffffffffffffffff82111561527557600080fd5b6020019150600581901b36038213156122d657600080fd5b6000610705368484614cfb565b6000610705368484614a79565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261530b57600080fd5b83018035915067ffffffffffffffff82111561532657600080fd5b6020019150368190038213156122d657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b602081016003831061537e5761537e61533b565b91905290565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff418336030181126153b857600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18336030181126153b857600080fd5b6000610705368484614bdd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361546357615463615403565b5060010190565b808201808211156105fa576105fa615403565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b6001600160a01b03851681526060602082015260006154cb60608301858761547d565b905082604083015295945050505050565b60006105fa3683614a1e565b6001600160a01b03841681528260208201526060604082015260006105e46060830184614b61565b84815260808101600485106155275761552761533b565b60208201949094526001600160a01b0392831660408201529116606090910152919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa18336030181126153b857600080fd5b60006020828403121561559257600080fd5b813561070581614baf565b600082516153b8818460208701614b3d565b600080858511156155bf57600080fd5b838611156155cc57600080fd5b5050820193919092039150565b80357fff000000000000000000000000000000000000000000000000000000000000008116906001841015615638577fff00000000000000000000000000000000000000000000000000000000000000808560010360031b1b82161691505b5092915050565b803560208310156105fa577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b600082601f83011261568c57600080fd5b81516020830160006156a061487684614829565b90508281528583830111156156b457600080fd5b611474836020830184614b3d565b6000602082840312156156d457600080fd5b815167ffffffffffffffff8111156156eb57600080fd5b6105e78482850161567b565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261572c57600080fd5b830160208101925035905067ffffffffffffffff81111561574c57600080fd5b8036038213156122d657600080fd5b8281526040602082015261578260408201615775846145b3565b6001600160a01b03169052565b60208201356060820152600061579b60408401846156f7565b61012060808501526157b26101608501828461547d565b9150506157c260608501856156f7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08584030160a08601526157f783828461547d565b608087013560c08781019190915260a088013560e0808901919091529088013561010088015290935061582f925086019050856156f7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08584030161012086015261586583828461547d565b925050506158776101008501856156f7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08584030161014086015261368483828461547d565b80357fffffffff000000000000000000000000000000000000000000000000000000008116906004841015615638577fffffffff00000000000000000000000000000000000000000000000000000000808560040360031b1b82161691505092915050565b8681526001600160a01b03861660208201526001600160a01b038516604082015283606082015260a0608082015260006124b860a08301848661547d565b600082601f83011261596157600080fd5b815161596f614876826149fa565b8082825260208201915060208360061b86010192508583111561599157600080fd5b602085015b838110156159ea57604081880312156159ae57600080fd5b6159b6614766565b815167ffffffffffffffff811681146159ce57600080fd5b8152602082810151818301529084529290920191604001615996565b5095945050505050565b80516145be8161459b565b600082601f830112615a1057600080fd5b8151615a1e614876826149fa565b8082825260208201915060208360051b860101925085831115615a4057600080fd5b602085015b838110156159ea57805167ffffffffffffffff811115615a6457600080fd5b86016040818903601f19011215615a7a57600080fd5b615a82614766565b6020820151615a908161459b565b8152604082015167ffffffffffffffff811115615aac57600080fd5b615abb8a60208386010161567b565b6020830152508085525050602083019250602081019050615a45565b600060408284031215615ae957600080fd5b615af1614766565b9050815167ffffffffffffffff811115615b0a57600080fd5b8201601f81018413615b1b57600080fd5b8051615b29614876826149fa565b8082825260208201915060208360051b850101925086831115615b4b57600080fd5b602084015b83811015615b8d57805167ffffffffffffffff811115615b6f57600080fd5b615b7e8960208389010161567b565b84525060209283019201615b50565b508452505050602082015167ffffffffffffffff811115615bad57600080fd5b614a6d848285016159ff565b600082601f830112615bca57600080fd5b8151615bd8614876826149fa565b8082825260208201915060208360051b860101925085831115615bfa57600080fd5b602085015b838110156159ea57805167ffffffffffffffff811115615c1e57600080fd5b86016060818903601f19011215615c3457600080fd5b615c3c61478f565b6020820151615c4a81614baf565b81526040820151615c5a8161459b565b6020820152606082015167ffffffffffffffff811115615c7957600080fd5b615c888a6020838601016159ff565b60408301525084525060209283019201615bff565b600060c08284031215615caf57600080fd5b615cb76147b2565b9050615cc2826159f4565b8152602082015167ffffffffffffffff811115615cde57600080fd5b615cea8482850161567b565b60208301525060408281015190820152606082015167ffffffffffffffff811115615d1457600080fd5b615d20848285016159ff565b606083015250608082015167ffffffffffffffff811115615d4057600080fd5b615d4c84828501615ad7565b60808301525060a082015167ffffffffffffffff811115615d6c57600080fd5b615d7884828501615bb9565b60a08301525092915050565b60008060408385031215615d9757600080fd5b825167ffffffffffffffff811115615dae57600080fd5b830160808186031215615dc057600080fd5b615dc86147d5565b815160ff81168114615dd957600080fd5b8152602082015167ffffffffffffffff811115615df557600080fd5b615e0187828501615950565b602083015250604082015167ffffffffffffffff811115615e2157600080fd5b615e2d87828501615c9d565b604083015250606082015167ffffffffffffffff811115615e4d57600080fd5b615e598782850161567b565b6060830152508093505050602083015167ffffffffffffffff811115615e7e57600080fd5b6108bb8582860161567b565b6001600160a01b0384168152606060208201526000615eac6060830185614b61565b9050826040830152949350505050565b8281526040602082015260006107026040830184614b61565b600060208284031215615ee757600080fd5b815161070581614baf565b600060208284031215615f0457600080fd5b8151801515811461070557600080fd5b818103818111156105fa576105fa615403565b600082615f5d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8151600090829060208501835b82811015615f8d578151845260209384019390910190600101615f6f565b509195945050505050565b80357fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008116906014841015615638577fffffffffffffffffffffffffffffffffffffffff000000000000000000000000808560140360031b1b82161691505092915050565b8381526060602082015260006160166060830185614b61565b828103604084015261094b8185614b61565b600082601f83011261603957600080fd5b8151616047614876826149fa565b8082825260208201915060208360051b86010192508583111561606957600080fd5b602085015b838110156159ea57805183526020928301920161606e565b600080600080600080600060e0888a0312156160a157600080fd5b87517fff00000000000000000000000000000000000000000000000000000000000000811681146160d157600080fd5b602089015190975067ffffffffffffffff8111156160ee57600080fd5b6160fa8a828b0161567b565b965050604088015167ffffffffffffffff81111561611757600080fd5b6161238a828b0161567b565b60608a0151909650945061613b9050608089016159f4565b60a089015160c08a0151919450925067ffffffffffffffff81111561615f57600080fd5b61616b8a828b01616028565b9150509295989194975092955056fea164736f6c634300081b000a"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/EntryPoint.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/EntryPoint.sol deleted file mode 100644 index 3c71244..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/EntryPoint.sol +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Utils -import { etch } from "../../test/utils/Vm.sol"; - -// Interfaces -import { IEntryPoint } from "../../external/ERC4337.sol"; - -// External Dependencies -import { SenderCreator } from "@ERC4337/account-abstraction/contracts/core/EntryPoint.sol"; -import { EntryPointSimulations } from - "@ERC4337/account-abstraction/contracts/core/EntryPointSimulations.sol"; - -contract EntryPointSimulationsPatch is EntryPointSimulations { - address public _entrypointAddr = address(this); - - SenderCreator public _newSenderCreator; - - function init(address entrypointAddr) public { - _entrypointAddr = entrypointAddr; - initSenderCreator(); - } - - function initSenderCreator() internal override { - //this is the address of the first contract created with CREATE by this address. - address createdObj = address( - uint160(uint256(keccak256(abi.encodePacked(hex"d694", _entrypointAddr, hex"01")))) - ); - _newSenderCreator = SenderCreator(createdObj); - } - - function senderCreator() internal view virtual override returns (SenderCreator) { - return _newSenderCreator; - } -} - -/// @dev Preset entrypoint address -address constant ENTRYPOINT_ADDR = 0x0000000071727De22E5E9d8BAf0edAc6f37da032; - -function etchEntrypoint() returns (IEntryPoint) { - address payable entryPoint = payable(address(new EntryPointSimulationsPatch())); - etch(ENTRYPOINT_ADDR, entryPoint.code); - EntryPointSimulationsPatch(payable(ENTRYPOINT_ADDR)).init(entryPoint); - - return IEntryPoint(ENTRYPOINT_ADDR); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/MockFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/MockFactory.sol deleted file mode 100644 index 66592f5..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/MockFactory.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; -/* solhint-enable no-unused-import */ - -// Dependencies -import { MockUniswap, ISwapRouter } from "../../integrations/uniswap/MockUniswap.sol"; -import { SWAPROUTER_ADDRESS } from "../../integrations/uniswap/helpers/MainnetAddresses.sol"; - -// Utils -import { etch } from "../../test/utils/Vm.sol"; - -contract MockFactory { - ISwapRouter public uniswap; - - constructor() { - if (SWAPROUTER_ADDRESS.code.length == 0) { - MockUniswap _mockUniswap = new MockUniswap(); - etch(SWAPROUTER_ADDRESS, address(_mockUniswap).code); - uniswap = ISwapRouter(SWAPROUTER_ADDRESS); - } - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/Registry.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/Registry.sol deleted file mode 100644 index 3557324..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/predeploy/Registry.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IERC7484 } from "../../Interfaces.sol"; - -// Mocks -import { MockRegistry } from "../../Mocks.sol"; - -// Utils -import { etch } from "../../test/utils/Vm.sol"; - -/// @dev Preset registry address -address constant REGISTRY_ADDR = 0x000000000069E2a187AEFFb852bF3cCdC95151B2; - -function etchRegistry() returns (IERC7484) { - address _registry = address(new MockRegistry()); - etch(REGISTRY_ADDR, _registry.code); - return IERC7484(REGISTRY_ADDR); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/RegistryDeployer.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/RegistryDeployer.sol deleted file mode 100644 index 1d09abf..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/RegistryDeployer.sol +++ /dev/null @@ -1,216 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IRegistry, IExternalResolver } from "./interfaces/IRegistry.sol"; -import { IExternalSchemaValidator } from "./interfaces/IExternalSchemaValidator.sol"; - -// Types -import { - ResolverRecord, - ModuleRecord, - ResolverUID, - AttestationRecord, - AttestationRequest, - ModuleType, - SchemaUID, - SchemaRecord -} from "./types/DataTypes.sol"; - -/// @dev Preset registry address -address constant REGISTRY_ADDR = 0x000000000069E2a187AEFFb852bF3cCdC95151B2; - -contract RegistryDeployer { - IRegistry internal registry = IRegistry(REGISTRY_ADDR); - - // Default resolver - ResolverUID internal resolverUID = - ResolverUID.wrap(0xdbca873b13c783c0c9c6ddfc4280e505580bf6cc3dac83f8a0f7b44acaafca4f); - - SchemaUID internal schemaUID = - SchemaUID.wrap(0x93d46fcca4ef7d66a413c7bde08bb1ff14bacbd04c4069bb24cd7c21729d7bf1); - - address internal mockAttester = 0xA4C777199658a41688E9488c4EcbD7a2925Cc23A; - - error InvalidResolver(); - - /*////////////////////////////////////////////////////////////// - DEPLOYMENT - //////////////////////////////////////////////////////////////*/ - - function deployModule( - bytes memory initCode, - bytes32 salt, - bytes memory metadata, - bytes memory resolverContext - ) - public - returns (address moduleAddr) - { - ResolverUID _resolverUID = findResolver(); - moduleAddr = registry.deployModule({ - resolverUID: _resolverUID, - initCode: initCode, - salt: salt, - metadata: metadata, - resolverContext: resolverContext - }); - } - - function deployModuleViaFactory( - address factory, - bytes memory callOnFactory, - bytes memory metadata, - bytes memory resolverContext - ) - public - returns (address moduleAddr) - { - ResolverUID _resolverUID = findResolver(); - moduleAddr = registry.deployViaFactory({ - factory: factory, - callOnFactory: callOnFactory, - metadata: metadata, - resolverUID: _resolverUID, - resolverContext: resolverContext - }); - } - - function predictModuleAddress( - bytes32 salt, - bytes memory initCode - ) - public - view - returns (address) - { - return registry.calcModuleAddress(salt, initCode); - } - - /*////////////////////////////////////////////////////////////// - REGISTRATION - //////////////////////////////////////////////////////////////*/ - - function registerModule( - address module, - bytes memory metadata, - bytes memory resolverContext - ) - public - { - ResolverUID _resolverUID = findResolver(); - registry.registerModule({ - resolverUID: _resolverUID, - moduleAddress: module, - metadata: metadata, - resolverContext: resolverContext - }); - } - - function findModule(address moduleAddress) public view returns (ModuleRecord memory) { - return registry.findModule(moduleAddress); - } - - /*////////////////////////////////////////////////////////////// - ATTESTATION - //////////////////////////////////////////////////////////////*/ - - function mockAttestToModule( - address module, - bytes memory attestationData, - ModuleType[] memory moduleTypes - ) - public - { - // solhint-disable-next-line gas-custom-errors - require(isContract(mockAttester), "MockAttester not deployed"); - - SchemaUID _schemaUID = findSchema(); - AttestationRequest memory request = AttestationRequest({ - moduleAddress: module, - expirationTime: 0, - data: attestationData, - moduleTypes: moduleTypes - }); - (bool success,) = mockAttester.call( - abi.encodeWithSignature( - "attest(address,bytes32,(address,uint48,bytes,uint256[]))", - REGISTRY_ADDR, - _schemaUID, - request - ) - ); - - // solhint-disable-next-line gas-custom-errors - require(success, "Mock attestation failed"); - } - - function isModuleAttestedMock(address module) public view returns (bool) { - AttestationRecord memory attestation = - registry.findAttestation({ module: module, attester: mockAttester }); - return attestation.time > 0 && attestation.expirationTime < block.timestamp - && attestation.revocationTime == 0; - } - - /*////////////////////////////////////////////////////////////// - MANAGEMENT - //////////////////////////////////////////////////////////////*/ - - function findResolver() public view returns (ResolverUID _resolverUID) { - _resolverUID = resolverUID; - ResolverRecord memory resolver = registry.findResolver(resolverUID); - if (address(resolver.resolver) == address(0)) { - revert InvalidResolver(); - } - } - - function registerResolver(address resolver) public returns (ResolverUID _resolverUID) { - _resolverUID = registry.registerResolver(IExternalResolver(resolver)); - } - - function findSchema() public view returns (SchemaUID _schemaUID) { - _schemaUID = schemaUID; - SchemaRecord memory schema = registry.findSchema(schemaUID); - if (schema.registeredAt == 0) { - revert InvalidResolver(); - } - } - - function registerSchema( - string memory schema, - address validator - ) - public - returns (SchemaUID _schemaUID) - { - _schemaUID = registry.registerSchema({ - schema: schema, - validator: IExternalSchemaValidator(validator) - }); - } - - function setRegistry(address _registry) public { - registry = IRegistry(_registry); - } - - function setResolverUID(ResolverUID _resolverUID) public { - resolverUID = _resolverUID; - } - - function setSchemaUID(SchemaUID _schemaUID) public { - schemaUID = _schemaUID; - } - - /*////////////////////////////////////////////////////////////// - OTHER - //////////////////////////////////////////////////////////////*/ - - function isContract(address _addr) internal view returns (bool _isContract) { - uint32 size; - // solhint-disable-next-line no-inline-assembly - assembly { - size := extcodesize(_addr) - } - return (size > 0); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IERC7484.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IERC7484.sol deleted file mode 100644 index 152a069..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IERC7484.sol +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -// Types -import { ModuleType } from "../types/DataTypes.sol"; - -interface IERC7484 { - event NewTrustedAttesters(address indexed smartAccount); - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Check with Registry internal attesters */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - function check(address module) external view; - - function checkForAccount(address smartAccount, address module) external view; - - function check(address module, ModuleType moduleType) external view; - - function checkForAccount( - address smartAccount, - address module, - ModuleType moduleType - ) - external - view; - - /** - * Allows Smart Accounts - the end users of the registry - to appoint - * one or many attesters as trusted. - * @dev this function reverts, if address(0), or duplicates are provided in attesters[] - * - * @param threshold The minimum number of attestations required for a module - * to be considered secure. - * @param attesters The addresses of the attesters to be trusted. - */ - function trustAttesters(uint8 threshold, address[] calldata attesters) external; - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Check with external attester(s) */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - function check(address module, address[] calldata attesters, uint256 threshold) external view; - - function check( - address module, - ModuleType moduleType, - address[] calldata attesters, - uint256 threshold - ) - external - view; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalResolver.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalResolver.sol deleted file mode 100644 index bdaa2f3..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalResolver.sol +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -// Interfaces -import { IERC165 } from "forge-std/interfaces/IERC165.sol"; - -// Types -import { AttestationRecord, ModuleRecord } from "../types/DataTypes.sol"; - -/** - * @title The interface of an optional schema resolver. - * @dev The resolver is responsible for validating the schema and attestation data. - * @dev The resolver is also responsible for processing the attestation and revocation requests. - * - */ -interface IExternalResolver is IERC165 { - /** - * @dev Processes an attestation and verifies whether it's valid. - * - * @param attestation The new attestation. - * - * @return Whether the attestation is valid. - */ - function resolveAttestation(AttestationRecord calldata attestation) - external - payable - returns (bool); - - function resolveAttestation(AttestationRecord[] calldata attestation) - external - payable - returns (bool); - - /** - * @dev Processes an attestation revocation and verifies if it can be revoked. - * - * @param attestation The existing attestation to be revoked. - * - * @return Whether the attestation can be revoked. - */ - function resolveRevocation(AttestationRecord calldata attestation) - external - payable - returns (bool); - function resolveRevocation(AttestationRecord[] calldata attestation) - external - payable - returns (bool); - - /** - * @dev Processes a Module Registration - * - * @param sender The msg.sender of the module registration - * @param moduleAddress address of the module - * @param record Module registration artefact - * - * @return Whether the registration is valid - */ - function resolveModuleRegistration( - address sender, - address moduleAddress, - ModuleRecord calldata record, - bytes calldata resolverContext - ) - external - payable - returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalSchemaValidator.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalSchemaValidator.sol deleted file mode 100644 index 7d84a3d..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IExternalSchemaValidator.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -// Interfaces -import { IERC165 } from "forge-std/interfaces/IERC165.sol"; - -// Types -import { AttestationRecord } from "../types/DataTypes.sol"; - -/** - * @title The interface of an optional schema resolver. - */ -interface IExternalSchemaValidator is IERC165 { - /** - * @notice Validates an attestation request. - */ - function validateSchema(AttestationRecord calldata attestation) external returns (bool); - - /** - * @notice Validates an array of attestation requests. - */ - function validateSchema(AttestationRecord[] calldata attestations) external returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IRegistry.sol deleted file mode 100644 index 003afed..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/interfaces/IRegistry.sol +++ /dev/null @@ -1,419 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -// Interfaces -import { IExternalSchemaValidator } from "./IExternalSchemaValidator.sol"; -import { IExternalResolver } from "./IExternalResolver.sol"; -import { IERC7484 } from "./IERC7484.sol"; - -// Types -import { - AttestationDataRef, - AttestationRecord, - AttestationRequest, - ModuleRecord, - ResolverUID, - ResolverRecord, - RevocationRequest, - SchemaUID, - SchemaRecord -} from "../types/DataTypes.sol"; - -/** - * Interface definition of all features of the registry: - * - Register Schemas - * - Register External Resolvers - * - Register Modules - * - Make Attestations - * - Make Revocations - * - Delegate Trust to Attester(s) - * - * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) - */ -interface IRegistry is IERC7484 { - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Smart Account - Trust Management */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - error InvalidResolver(IExternalResolver resolver); - error InvalidResolverUID(ResolverUID uid); - error InvalidTrustedAttesterInput(); - error NoTrustedAttestersFound(); - error RevokedAttestation(address attester); - error InvalidModuleType(); - error AttestationNotFound(); - - error InsufficientAttestations(); - - /** - * Get trusted attester for a specific Smart Account - * @param smartAccount The address of the Smart Account - */ - function findTrustedAttesters(address smartAccount) - external - view - returns (address[] memory attesters); - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Attestations */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - event Revoked(address indexed moduleAddress, address indexed revoker, SchemaUID schema); - event Attested( - address indexed moduleAddress, - address indexed attester, - SchemaUID schemaUID, - AttestationDataRef indexed sstore2Pointer - ); - - error AlreadyRevoked(); - error AlreadyAttested(); - error ModuleNotFoundInRegistry(address module); - error AccessDenied(); - error InvalidAttestation(); - error InvalidExpirationTime(); - error DifferentResolvers(); - error InvalidSignature(); - error InvalidModuleTypes(); - - /** - * Allows `msg.sender` to attest to multiple modules' security status. - * The `AttestationRequest.Data` provided should match the attestation - * schema defined by the Schema corresponding to the SchemaUID - * - * @dev This function will revert if the same module is attested twice by the same attester. - * If you want to re-attest, you have to revoke your attestation first, and then attest - * again. - * - * @param schemaUID The SchemaUID of the schema the attestation is based on. - * @param request a single AttestationRequest - */ - function attest(SchemaUID schemaUID, AttestationRequest calldata request) external; - - /** - * Allows `msg.sender` to attest to multiple modules' security status. - * The `AttestationRequest.Data` provided should match the attestation - * schema defined by the Schema corresponding to the SchemaUID - * - * @dev This function will revert if the same module is attested twice by the same attester. - * If you want to re-attest, you have to revoke your attestation first, and then attest - * again. - * - * @param schemaUID The SchemaUID of the schema the attestation is based on. - * @param requests An array of AttestationRequest - */ - function attest(SchemaUID schemaUID, AttestationRequest[] calldata requests) external; - - /** - * Allows attester to attest by signing an `AttestationRequest` (`ECDSA` or `ERC1271`) - * The `AttestationRequest.Data` provided should match the attestation - * schema defined by the Schema corresponding to the SchemaUID - * - * @dev This function will revert if the same module is attested twice by the same attester. - * If you want to re-attest, you have to revoke your attestation first, and then attest - * again. - * - * @param schemaUID The SchemaUID of the schema the attestation is based on. - * @param attester The address of the attester - * @param request An AttestationRequest - * @param signature The signature of the attester. ECDSA or ERC1271 - */ - function attest( - SchemaUID schemaUID, - address attester, - AttestationRequest calldata request, - bytes calldata signature - ) - external; - - /** - * Allows attester to attest by signing an `AttestationRequest` (`ECDSA` or `ERC1271`) - * The `AttestationRequest.Data` provided should match the attestation - * schema defined by the Schema corresponding to the SchemaUID - * - * @dev This function will revert if the same module is attested twice by the same attester. - * If you want to re-attest, you have to revoke your attestation first, and then attest - * again. - * - * @param schemaUID The SchemaUID of the schema the attestation is based on. - * @param attester The address of the attester - * @param requests An array of AttestationRequest - * @param signature The signature of the attester. ECDSA or ERC1271 - */ - function attest( - SchemaUID schemaUID, - address attester, - AttestationRequest[] calldata requests, - bytes calldata signature - ) - external; - - /** - * Getter function to get AttestationRequest made by one attester - */ - function findAttestation( - address module, - address attester - ) - external - view - returns (AttestationRecord memory attestation); - - /** - * Getter function to get AttestationRequest made by multiple attesters - */ - function findAttestations( - address module, - address[] calldata attesters - ) - external - view - returns (AttestationRecord[] memory attestations); - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Revocations */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /** - * Allows `msg.sender` to revoke an attestation made by the same `msg.sender` - * - * @dev this function will revert if the attestation is not found - * @dev this function will revert if the attestation is already revoked - * - * @param request single RevocationRequest - */ - function revoke(RevocationRequest calldata request) external; - - /** - * Allows msg.sender to revoke multiple attestation made by the same msg.sender - * - * @dev this function will revert if the attestation is not found - * @dev this function will revert if the attestation is already revoked - * - * @param requests the RevocationRequests - */ - function revoke(RevocationRequest[] calldata requests) external; - - /** - * Allows attester to revoke an attestation by signing an `RevocationRequest` (`ECDSA` or - * `ERC1271`) - * - * @param attester the signer / revoker - * @param request single RevocationRequest - * @param signature ECDSA or ERC1271 signature - */ - function revoke( - address attester, - RevocationRequest calldata request, - bytes calldata signature - ) - external; - - /** - * Allows attester to revoke an attestation by signing an `RevocationRequest` (`ECDSA` or - * `ERC1271`) - * @dev if you want to revoke multiple attestations, but from different attesters, call this - * function multiple times - * - * @param attester the signer / revoker - * @param requests array of RevocationRequests - * @param signature ECDSA or ERC1271 signature - */ - function revoke( - address attester, - RevocationRequest[] calldata requests, - bytes calldata signature - ) - external; - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Module Registration */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - // Event triggered when a module is deployed. - event ModuleRegistration(address indexed implementation); - - error AlreadyRegistered(address module); - error InvalidDeployment(); - error ModuleAddressIsNotContract(address moduleAddress); - error FactoryCallFailed(address factory); - - /** - * Module Developers can deploy their module Bytecode directly via the registry. - * This registry implements a `CREATE2` factory, that allows module developers to register and - * deploy module bytecode - * @param salt The salt to be used in the `CREATE2` factory. This adheres to - * Pr000xy/Create2Factory.sol salt formatting. - * The salt's first bytes20 should be the address of the sender - * or bytes20(0) to bypass the check (this will lose replay protection) - * @param resolverUID The resolverUID to be used in the `CREATE2` factory - * @param initCode The initCode to be used in the `CREATE2` factory - * @param metadata The metadata to be stored on the registry. - * This field is optional, and might be used by the module developer to store - * additional - * information about the module or facilitate business logic with the Resolver stub - * @param resolverContext bytes that will be passed to the resolver contract - */ - function deployModule( - bytes32 salt, - ResolverUID resolverUID, - bytes calldata initCode, - bytes calldata metadata, - bytes calldata resolverContext - ) - external - payable - returns (address moduleAddress); - - /** - * In order to make the integration into existing business logics possible, - * the Registry is able to utilize external factories that can be utilized to deploy the - * modules. - * @dev Registry can use other factories to deploy the module. - * @dev Note that this function will call the external factory via the FactoryTrampoline - * contract. - * Factory MUST not assume that msg.sender == registry - * @dev This function is used to deploy and register a module using a factory contract. - * Since one of the parameters of this function is a unique resolverUID and any - * registered module address can only be registered once, - * using this function is of risk for a frontrun attack - */ - function deployViaFactory( - address factory, - bytes calldata callOnFactory, - bytes calldata metadata, - ResolverUID resolverUID, - bytes calldata resolverContext - ) - external - payable - returns (address moduleAddress); - - /** - * Already deployed module addresses can be registered on the registry - * @dev This function is used to deploy and register an already deployed module. - * Since one of the parameters of this function is a unique resolverUID and any - * registered module address can only be registered once, - * using this function is of risk for a frontrun attack - * @dev the sender address of this registration is set to address(0) since anyone can invoke - * this function - * @param resolverUID The resolverUID to be used for the module - * @param moduleAddress The address of the module to be registered - * @param metadata The metadata to be stored on the registry. - * This field is optional, and might be used by the module developer to store - * additional - * information about the module or facilitate business logic with the Resolver stub - * @param resolverContext bytes that will be passed to the resolver contract - */ - function registerModule( - ResolverUID resolverUID, - address moduleAddress, - bytes calldata metadata, - bytes calldata resolverContext - ) - external; - - /** - * in conjunction with the deployModule() function, this function let's you - * predict the address of a CREATE2 module deployment - * @param salt CREATE2 salt - * @param initCode module initcode - * @return moduleAddress counterfactual address of the module deployment - */ - function calcModuleAddress( - bytes32 salt, - bytes calldata initCode - ) - external - view - returns (address); - - /** - * Getter function to get the stored ModuleRecord for a specific module address. - * @param moduleAddress The address of the module - */ - function findModule(address moduleAddress) - external - view - returns (ModuleRecord memory moduleRecord); - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Manage Schemas */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - event SchemaRegistered(SchemaUID indexed uid, address indexed registerer); - - error SchemaAlreadyExists(SchemaUID uid); - - error InvalidSchema(); - error InvalidSchemaValidator(IExternalSchemaValidator validator); - - /** - * Register Schema and (optional) external `IExternalSchemaValidator` - * A Schema describe the structure of the data of attestations - * every attestation made on this registry, will reference a SchemaUID to - * make it possible to decode attestation data in human readable form - * overwriting a schema is not allowed, and will revert - * @param schema ABI schema used to encode attestations that are made with this schema - * @param validator (optional) external schema validator that will be used to validate - * attestations. - * use address(0), if you don't need an external validator - * @return uid SchemaUID of the registered schema - */ - function registerSchema( - string calldata schema, - IExternalSchemaValidator validator // OPTIONAL - ) - external - returns (SchemaUID uid); - - /** - * Getter function to retrieve SchemaRecord - */ - function findSchema(SchemaUID uid) external view returns (SchemaRecord memory record); - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Manage Resolvers */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - event NewResolver(ResolverUID indexed uid, address indexed resolver); - event NewResolverOwner(ResolverUID indexed uid, address newOwner); - - error ResolverAlreadyExists(); - - /** - * Allows Marketplace Agents to register external resolvers. - * @param resolver external resolver contract - * @return uid ResolverUID of the registered resolver - */ - function registerResolver(IExternalResolver resolver) external returns (ResolverUID uid); - - /** - * Entities that previously registered an external resolver, may update the implementation - * address. - * @param uid The UID of the resolver. - * @param resolver The new resolver implementation address. - */ - function setResolver(ResolverUID uid, IExternalResolver resolver) external; - - /** - * Transfer ownership of resolverUID to a new address - * @param uid The UID of the resolver to transfer ownership for - * @param newOwner The address of the new owner - */ - function transferResolverOwnership(ResolverUID uid, address newOwner) external; - - /** - * Getter function to get the ResolverRecord of a registered resolver - * @param uid The UID of the resolver. - */ - function findResolver(ResolverUID uid) external view returns (ResolverRecord memory record); - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Stub Errors */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - error ExternalError_SchemaValidation(); - error ExternalError_ResolveAttestation(); - error ExternalError_ResolveRevocation(); - error ExternalError_ModuleRegistration(); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/types/DataTypes.sol b/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/types/DataTypes.sol deleted file mode 100644 index 0343305..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/deployment/registry/types/DataTypes.sol +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IExternalSchemaValidator } from "../interfaces/IExternalSchemaValidator.sol"; -import { IExternalResolver } from "../interfaces/IExternalResolver.sol"; - -/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ -/* Storage Structs */ -/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - -struct AttestationRecord { - uint48 time; // The time when the attestation was created (Unix timestamp). - uint48 expirationTime; // The time when the attestation expires (Unix timestamp). - uint48 revocationTime; // The time when the attestation was revoked (Unix timestamp). - PackedModuleTypes moduleTypes; // bit-wise encoded module types. See ModuleTypeLib - address moduleAddress; // The implementation address of the module that is being attested. - address attester; // The attesting account. - AttestationDataRef dataPointer; // SSTORE2 pointer to the attestation data. - SchemaUID schemaUID; // The unique identifier of the schema. -} - -struct ModuleRecord { - ResolverUID resolverUID; // The unique identifier of the resolver. - address sender; // The address of the sender who deployed the contract - bytes metadata; // Additional data related to the contract deployment -} - -struct SchemaRecord { - uint48 registeredAt; // The time when the schema was registered (Unix timestamp). - IExternalSchemaValidator validator; // Optional external schema validator. - string schema; // Custom specification of the schema (e.g., an ABI). -} - -struct ResolverRecord { - IExternalResolver resolver; // Optional resolver. - address resolverOwner; // The address of the account used to register the resolver. -} - -// Struct that represents a trusted attester. -struct TrustedAttesterRecord { - uint8 attesterCount; // number of attesters in the linked list - uint8 threshold; // minimum number of attesters required - address attester; // first attester in linked list. (packed to save gas) - mapping(address attester => mapping(address account => address linkedAttester)) linkedAttesters; -} - -/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ -/* Attestation / Revocation Requests */ -/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - -/** - * @dev A struct representing the arguments of the attestation request. - */ -struct AttestationRequest { - address moduleAddress; // The moduleAddress of the attestation. - uint48 expirationTime; // The time when the attestation expires (Unix timestamp). - bytes data; // Custom attestation data. - ModuleType[] moduleTypes; // optional: The type(s) of the module. -} - -/** - * @dev A struct representing the arguments of the revocation request. - */ -struct RevocationRequest { - address moduleAddress; // The module address. -} - -/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ -/* Custom Types */ -/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - -//---------------------- SchemaUID ------------------------------| -type SchemaUID is bytes32; - -using { schemaEq as == } for SchemaUID global; -using { schemaNotEq as != } for SchemaUID global; - -function schemaEq(SchemaUID uid1, SchemaUID uid2) pure returns (bool) { - return SchemaUID.unwrap(uid1) == SchemaUID.unwrap(uid2); -} - -function schemaNotEq(SchemaUID uid1, SchemaUID uid2) pure returns (bool) { - return SchemaUID.unwrap(uid1) != SchemaUID.unwrap(uid2); -} - -//--------------------- ResolverUID -----------------------------| -type ResolverUID is bytes32; - -using { resolverEq as == } for ResolverUID global; -using { resolverNotEq as != } for ResolverUID global; - -function resolverEq(ResolverUID uid1, ResolverUID uid2) pure returns (bool) { - return ResolverUID.unwrap(uid1) == ResolverUID.unwrap(uid2); -} - -function resolverNotEq(ResolverUID uid1, ResolverUID uid2) pure returns (bool) { - return ResolverUID.unwrap(uid1) != ResolverUID.unwrap(uid2); -} - -type AttestationDataRef is address; - -using { attestationDataRefEq as == } for AttestationDataRef global; - -function attestationDataRefEq( - AttestationDataRef uid1, - AttestationDataRef uid2 -) - pure - returns (bool) -{ - return AttestationDataRef.unwrap(uid1) == AttestationDataRef.unwrap(uid2); -} - -type PackedModuleTypes is uint32; - -type ModuleType is uint256; - -using { moduleTypeEq as == } for ModuleType global; -using { moduleTypeNeq as != } for ModuleType global; - -function moduleTypeEq(ModuleType uid1, ModuleType uid2) pure returns (bool) { - return ModuleType.unwrap(uid1) == ModuleType.unwrap(uid2); -} - -function moduleTypeNeq(ModuleType uid1, ModuleType uid2) pure returns (bool) { - return ModuleType.unwrap(uid1) != ModuleType.unwrap(uid2); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/external/ERC4337.sol b/typescript/packages/account-modules/lib/modulekit/src/external/ERC4337.sol deleted file mode 100644 index 65296e5..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/external/ERC4337.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/* solhint-disable no-unused-import */ - -/*////////////////////////////////////////////////////////////// - USEROP -//////////////////////////////////////////////////////////////*/ - -import { PackedUserOperation } from - "@ERC4337/account-abstraction/contracts/interfaces/PackedUserOperation.sol"; -import { UserOperationLib } from "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; - -/*////////////////////////////////////////////////////////////// - ENTRYPOINT -//////////////////////////////////////////////////////////////*/ - -import { EntryPointSimulations } from - "@ERC4337/account-abstraction/contracts/core/EntryPointSimulations.sol"; - -/*////////////////////////////////////////////////////////////// - VALIDATION -//////////////////////////////////////////////////////////////*/ - -import { - ValidationData, - _packValidationData -} from "@ERC4337/account-abstraction/contracts/core/Helpers.sol"; - -/*////////////////////////////////////////////////////////////// - INTERFACES -//////////////////////////////////////////////////////////////*/ - -import { IStakeManager } from "@ERC4337/account-abstraction/contracts/interfaces/IStakeManager.sol"; -import { IAccount as IERC4337 } from - "@ERC4337/account-abstraction/contracts/interfaces/IAccount.sol"; -import { IAccountExecute } from - "@ERC4337/account-abstraction/contracts/interfaces/IAccountExecute.sol"; -import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/IEntryPoint.sol"; -import { IEntryPointSimulations } from - "@ERC4337/account-abstraction/contracts/interfaces/IEntryPointSimulations.sol"; diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC20.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC20.sol deleted file mode 100644 index 94686d8..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC20.sol +++ /dev/null @@ -1,129 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IERC20 } from "forge-std/interfaces/IERC20.sol"; - -// Types -import { Execution } from "../accounts/erc7579/lib/ExecutionLib.sol"; - -// Dependencies -import { ERC7579Exec } from "./ERC7579Exec.sol"; - -library ERC20Integration { - using ERC7579Exec for address; - - error SafeERC20TransferFailed(); - - function safeApprove( - IERC20 token, - address spender, - uint256 amount - ) - internal - pure - returns (Execution memory exec0, Execution memory exec1) - { - exec0 = Execution({ - target: address(token), - value: 0, - callData: abi.encodeCall(IERC20.approve, (spender, 0)) - }); - exec1 = Execution({ - target: address(token), - value: 0, - callData: abi.encodeCall(IERC20.approve, (spender, amount)) - }); - } - - function approve( - IERC20 token, - address spender, - uint256 amount - ) - internal - pure - returns (Execution memory exec) - { - exec = Execution({ - target: address(token), - value: 0, - callData: abi.encodeCall(IERC20.approve, (spender, amount)) - }); - } - - function safeTransfer(IERC20 token, address to, uint256 amount) internal { - safeTransfer(token, msg.sender, to, amount); - } - - function safeTransfer(IERC20 token, address account, address to, uint256 amount) internal { - bytes memory ret = account.exec7579({ - to: address(token), - value: 0, - data: abi.encodeCall(IERC20.transfer, (to, amount)) - }); - if (ret.length != 0) { - bool success = abi.decode(ret, (bool)); - if (!success) revert SafeERC20TransferFailed(); - } - } - - function safeTransferFrom(IERC20 token, address from, address to, uint256 amount) internal { - safeTransferFrom(token, msg.sender, from, to, amount); - } - - function safeTransferFrom( - IERC20 token, - address account, - address from, - address to, - uint256 amount - ) - internal - { - bytes memory ret = account.exec7579({ - to: address(token), - value: 0, - data: abi.encodeCall(IERC20.transferFrom, (from, to, amount)) - }); - - bytes[] memory retValues = abi.decode(ret, (bytes[])); - if (retValues[0].length != 0) { - bool success = abi.decode(retValues[0], (bool)); - if (!success) revert SafeERC20TransferFailed(); - } - } - - function transfer( - IERC20 token, - address to, - uint256 amount - ) - internal - pure - returns (Execution memory exec) - { - exec = Execution({ - target: address(token), - value: 0, - callData: abi.encodeCall(IERC20.transfer, (to, amount)) - }); - } - - function transferFrom( - IERC20 token, - address from, - address to, - uint256 amount - ) - internal - pure - returns (Execution memory exec) - { - exec = Execution({ - target: address(token), - value: 0, - callData: abi.encodeCall(IERC20.transferFrom, (from, to, amount)) - }); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC4626.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC4626.sol deleted file mode 100644 index e9883e8..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC4626.sol +++ /dev/null @@ -1,76 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IERC4626 } from "forge-std/interfaces/IERC4626.sol"; - -// Types -import { Execution } from "../accounts/erc7579/lib/ExecutionLib.sol"; - -library ERC4626Integration { - function deposit( - IERC4626 vault, - uint256 assets, - address receiver - ) - internal - pure - returns (Execution memory exec) - { - exec = Execution({ - target: address(vault), - value: 0, - callData: abi.encodeCall(IERC4626.deposit, (assets, receiver)) - }); - } - - function mint( - IERC4626 vault, - uint256 shares, - address receiver - ) - internal - pure - returns (Execution memory exec) - { - exec = Execution({ - target: address(vault), - value: 0, - callData: abi.encodeCall(IERC4626.mint, (shares, receiver)) - }); - } - - function withdraw( - IERC4626 vault, - uint256 assets, - address receiver, - address owner - ) - internal - pure - returns (Execution memory exec) - { - exec = Execution({ - target: address(vault), - value: 0, - callData: abi.encodeCall(IERC4626.withdraw, (assets, receiver, owner)) - }); - } - - function redeem( - IERC4626 vault, - uint256 shares, - address receiver, - address owner - ) - internal - pure - returns (Execution memory exec) - { - exec = Execution({ - target: address(vault), - value: 0, - callData: abi.encodeCall(IERC4626.redeem, (shares, receiver, owner)) - }); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC721.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC721.sol deleted file mode 100644 index 73ca531..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC721.sol +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IERC721 } from "forge-std/interfaces/IERC721.sol"; - -// Types -import { Execution } from "../accounts/erc7579/lib/ExecutionLib.sol"; - -library ERC721Integration { - function approve( - IERC721 token, - address spender, - uint256 tokenId - ) - internal - pure - returns (Execution memory exec) - { - exec = Execution({ - target: address(token), - value: 0, - callData: abi.encodeCall(IERC721.approve, (spender, tokenId)) - }); - } - - function transferFrom( - IERC721 token, - address from, - address to, - uint256 tokenId - ) - internal - pure - returns (Execution memory exec) - { - exec = Execution({ - target: address(token), - value: 0, - callData: abi.encodeCall(IERC721.transferFrom, (from, to, tokenId)) - }); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC7579Exec.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC7579Exec.sol deleted file mode 100644 index a6ba148..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/ERC7579Exec.sol +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -// Libraries -import { - Execution, - ExecutionLib as ERC7579ExecutionLib -} from "../accounts/erc7579/lib/ExecutionLib.sol"; -import { - ModeLib as ERC7579ModeLib, - CALLTYPE_SINGLE, - CALLTYPE_BATCH, - EXECTYPE_DEFAULT, - CALLTYPE_DELEGATECALL, - MODE_DEFAULT, - ModePayload, - ModeCode -} from "../accounts/common/lib/ModeLib.sol"; - -// Interfaces -import { IERC7579Account } from "../accounts/common/interfaces/IERC7579Account.sol"; - -library ERC7579Exec { - function exec7579( - address account, - address to, - uint256 value, - bytes memory data - ) - internal - returns (bytes memory result) - { - ModeCode modeCode = ERC7579ModeLib.encode({ - callType: CALLTYPE_SINGLE, - execType: EXECTYPE_DEFAULT, - mode: MODE_DEFAULT, - payload: ModePayload.wrap(bytes22(0)) - }); - - return IERC7579Account(account).executeFromExecutor( - modeCode, ERC7579ExecutionLib.encodeSingle(to, value, data) - )[0]; - } - - function exec7579( - address to, - uint256 value, - bytes memory data - ) - internal - returns (bytes memory result) - { - return exec7579(msg.sender, to, value, data); - } - - function exec7579( - address account, - Execution[] memory execs - ) - internal - returns (bytes[] memory results) - { - ModeCode modeCode = ERC7579ModeLib.encode({ - callType: CALLTYPE_BATCH, - execType: EXECTYPE_DEFAULT, - mode: MODE_DEFAULT, - payload: ModePayload.wrap(bytes22(0)) - }); - results = IERC7579Account(account).executeFromExecutor( - modeCode, ERC7579ExecutionLib.encodeBatch(execs) - ); - } - - function exec7579(Execution[] memory execs) internal returns (bytes[] memory results) { - return exec7579(msg.sender, execs); - } - - // Note: Not every account will support delegatecalls - function exec7579( - address account, - address delegateTarget, - bytes memory callData - ) - internal - returns (bytes[] memory results) - { - ModeCode modeCode = ERC7579ModeLib.encode({ - callType: CALLTYPE_DELEGATECALL, - execType: EXECTYPE_DEFAULT, - mode: MODE_DEFAULT, - payload: ModePayload.wrap(bytes22(0)) - }); - results = IERC7579Account(account).executeFromExecutor( - modeCode, abi.encodePacked(delegateTarget, callData) - ); - } - - // Note: Not every account will support delegatecalls - function exec7579( - address delegateTarget, - bytes memory callData - ) - internal - returns (bytes[] memory results) - { - return exec7579(msg.sender, delegateTarget, callData); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IBotRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IBotRegistry.sol deleted file mode 100644 index 5bdda17..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IBotRegistry.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IBotRegistry { - function botList(address) public view virtual returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDFSRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDFSRegistry.sol deleted file mode 100644 index b9b6fd8..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDFSRegistry.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IDFSRegistry { - function getAddr(bytes4 _id) public view virtual returns (address); - - function addNewContract( - bytes32 _id, - address _contractAddr, - uint256 _waitPeriod - ) - public - virtual; - - function startContractChange(bytes32 _id, address _newContractAddr) public virtual; - - function approveContractChange(bytes32 _id) public virtual; - - function cancelContractChange(bytes32 _id) public virtual; - - function changeWaitPeriod(bytes32 _id, uint256 _newWaitPeriod) public virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDSProxy.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDSProxy.sol deleted file mode 100644 index 470ed87..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IDSProxy.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IDSProxy { - // function execute(bytes memory _code, bytes memory _data) - // public - // payable - // virtual - // returns (address, bytes32); - - function execute( - address _target, - bytes memory _data - ) - public - payable - virtual - returns (bytes32); - - function setCache(address _cacheAddr) public payable virtual returns (bool); - - function owner() public view virtual returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC20.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC20.sol deleted file mode 100644 index 6cddc56..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC20.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface IERC20 { - function name() external view returns (string memory); - function symbol() external view returns (string memory); - function decimals() external view returns (uint256 digits); - function totalSupply() external view returns (uint256 supply); - - function balanceOf(address _owner) external view returns (uint256 balance); - - function transfer(address _to, uint256 _value) external returns (bool success); - - function transferFrom( - address _from, - address _to, - uint256 _value - ) - external - returns (bool success); - - function approve(address _spender, uint256 _value) external returns (bool success); - - function allowance( - address _owner, - address _spender - ) - external - view - returns (uint256 remaining); - - event Approval(address indexed _owner, address indexed _spender, uint256 _value); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC4626.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC4626.sol deleted file mode 100644 index 48b3534..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC4626.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -import "./IERC20.sol"; - -interface IERC4626 is 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 previewDeposit(uint256 _assets) external view returns (uint256 shares); - function previewMint(uint256 _shares) external view returns (uint256 assets); - function previewWithdraw(uint256 _assets) external view returns (uint256 shares); - function previewRedeem(uint256 _shares) external view returns (uint256 assets); - - function asset() external view returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721.sol deleted file mode 100644 index 2abd072..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface IERC721 { - function balanceOf(address owner) external view returns (uint256 balance); - function ownerOf(uint256 tokenId) external view returns (address owner); - function safeTransferFrom( - address from, - address to, - uint256 tokenId, - bytes calldata data - ) - external; - function safeTransferFrom(address from, address to, uint256 tokenId) external; - function transferFrom(address from, address to, uint256 tokenId) external; - function approve(address to, uint256 tokenId) external; - function setApprovalForAll(address operator, bool _approved) external; - function getApproved(uint256 tokenId) external view returns (address operator); - function isApprovedForAll(address owner, address operator) external view returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721Enumerable.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721Enumerable.sol deleted file mode 100644 index 0b1b2d9..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IERC721Enumerable.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -import "./IERC721.sol"; - -interface IERC721Enumerable is IERC721 { - function totalSupply() external view returns (uint256); - function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); - function tokenByIndex(uint256 index) external view returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IFLParamGetter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IFLParamGetter.sol deleted file mode 100644 index 43ed7a8..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IFLParamGetter.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IFLParamGetter { - function getFlashLoanParams(bytes memory _data) - public - view - virtual - returns (address[] memory tokens, uint256[] memory amount, uint256[] memory modes); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IGasToken.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IGasToken.sol deleted file mode 100644 index 3ca6f7c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IGasToken.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -import "./IERC20.sol"; - -abstract contract IGasToken is IERC20 { - function free(uint256 value) public virtual returns (bool success); - - function freeUpTo(uint256 value) public virtual returns (uint256 freed); - - function freeFrom(address from, uint256 value) public virtual returns (bool success); - - function freeFromUpTo(address from, uint256 value) public virtual returns (uint256 freed); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ILendingPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ILendingPool.sol deleted file mode 100644 index 0e8e6ec..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ILendingPool.sol +++ /dev/null @@ -1,187 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract ILendingPool { - function flashLoan( - address payable _receiver, - address _reserve, - uint256 _amount, - bytes calldata _params - ) - external - virtual; - - function deposit( - address _reserve, - uint256 _amount, - uint16 _referralCode - ) - external - payable - virtual; - - function setUserUseReserveAsCollateral( - address _reserve, - bool _useAsCollateral - ) - external - virtual; - - function borrow( - address _reserve, - uint256 _amount, - uint256 _interestRateMode, - uint16 _referralCode - ) - external - virtual; - - function repay( - address _reserve, - uint256 _amount, - address payable _onBehalfOf - ) - external - payable - virtual; - - function swapBorrowRateMode(address _reserve) external virtual; - - function getReserves() external view virtual returns (address[] memory); - - /// @param _reserve underlying token address - function getReserveData(address _reserve) - external - view - virtual - returns ( - uint256 totalLiquidity, // reserve total liquidity - uint256 availableLiquidity, // reserve available liquidity for borrowing - uint256 totalBorrowsStable, // total amount of outstanding borrows at Stable rate - uint256 totalBorrowsVariable, // total amount of outstanding borrows at Variable rate - uint256 liquidityRate, // current deposit APY of the reserve for depositors, in Ray - // units. - uint256 variableBorrowRate, // current variable rate APY of the reserve pool, in Ray - // units. - uint256 stableBorrowRate, // current stable rate APY of the reserve pool, in Ray units. - uint256 averageStableBorrowRate, // current average stable borrow rate - uint256 utilizationRate, // expressed as total borrows/total liquidity. - uint256 liquidityIndex, // cumulative liquidity index - uint256 variableBorrowIndex, // cumulative variable borrow index - address aTokenAddress, // aTokens contract address for the specific _reserve - uint40 lastUpdateTimestamp - ); // timestamp of the last update of reserve data - - /// @param _user users address - function getUserAccountData(address _user) - external - view - virtual - returns ( - uint256 totalLiquidityETH, // user aggregated deposits across all the reserves. In Wei - uint256 totalCollateralETH, // user aggregated collateral across all the reserves. In - // Wei - uint256 totalBorrowsETH, // user aggregated outstanding borrows across all the reserves. - // In Wei - uint256 totalFeesETH, // user aggregated current outstanding fees in ETH. In Wei - uint256 availableBorrowsETH, // user available amount to borrow in ETH - uint256 currentLiquidationThreshold, // user current average liquidation threshold - // across all the collaterals deposited - uint256 ltv, // user average Loan-to-Value between all the collaterals - uint256 healthFactor - ); // user current Health Factor - - /// @param _reserve underlying token address - /// @param _user users address - function getUserReserveData( - address _reserve, - address _user - ) - external - view - virtual - returns ( - uint256 currentATokenBalance, // user current reserve aToken balance - uint256 currentBorrowBalance, // user current reserve outstanding borrow balance - uint256 principalBorrowBalance, // user balance of borrowed asset - uint256 borrowRateMode, // user borrow rate mode either Stable or Variable - uint256 borrowRate, // user current borrow rate APY - uint256 liquidityRate, // user current earn rate on _reserve - uint256 originationFee, // user outstanding loan origination fee - uint256 variableBorrowIndex, // user variable cumulative index - uint256 lastUpdateTimestamp, // Timestamp of the last data update - bool usageAsCollateralEnabled - ); // Whether the user's current reserve is enabled as a collateral - - function getReserveConfigurationData(address _reserve) - external - view - virtual - returns ( - uint256 ltv, - uint256 liquidationThreshold, - uint256 liquidationBonus, - address rateStrategyAddress, - bool usageAsCollateralEnabled, - bool borrowingEnabled, - bool stableBorrowRateEnabled, - bool isActive - ); - - // ------------------ LendingPoolCoreData ------------------------ - function getReserveATokenAddress(address _reserve) public view virtual returns (address); - - function getReserveConfiguration(address _reserve) - external - view - virtual - returns (uint256, uint256, uint256, bool); - - function getUserUnderlyingAssetBalance( - address _reserve, - address _user - ) - public - view - virtual - returns (uint256); - - function getReserveCurrentLiquidityRate(address _reserve) - public - view - virtual - returns (uint256); - - function getReserveCurrentVariableBorrowRate(address _reserve) - public - view - virtual - returns (uint256); - - function getReserveTotalLiquidity(address _reserve) public view virtual returns (uint256); - - function getReserveAvailableLiquidity(address _reserve) public view virtual returns (uint256); - - function getReserveTotalBorrowsVariable(address _reserve) - public - view - virtual - returns (uint256); - - // ---------------- LendingPoolDataProvider --------------------- - function calculateUserGlobalData(address _user) - public - view - virtual - returns ( - uint256 totalLiquidityBalanceETH, - uint256 totalCollateralBalanceETH, - uint256 totalBorrowBalanceETH, - uint256 totalFeesETH, - uint256 currentLtv, - uint256 currentLiquidationThreshold, - uint256 healthFactor, - bool healthFactorBelowThreshold - ); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IMCDPriceVerifier.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IMCDPriceVerifier.sol deleted file mode 100644 index 7341c60..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IMCDPriceVerifier.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IMCDPriceVerifier { - function verifyVaultNextPrice( - uint256 _nextPrice, - uint256 _cdpId - ) - public - view - virtual - returns (bool); - function verifyNextPrice(uint256 _nextPrice, bytes32 _ilk) public view virtual returns (bool); - function setAuthorized(address _address, bool _allowed) public virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyERC20.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyERC20.sol deleted file mode 100644 index 35edd40..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyERC20.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface IProxyERC20 { - function target() external returns (address); - function tokenState() external returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyRegistry.sol deleted file mode 100644 index 09acf2a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IProxyRegistry.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IProxyRegistry { - function proxies(address _owner) public view virtual returns (address); - function build(address) public virtual returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISmartSession.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISmartSession.sol deleted file mode 100644 index 36fefb3..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISmartSession.sol +++ /dev/null @@ -1,364 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -// Interfaces -import { IModule } from "../../accounts/common/interfaces/IERC7579Module.sol"; - -// Types -import { PackedUserOperation } from "../../external/ERC4337.sol"; - -/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ -/* Custom Types & Constants */ -/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - -type PermissionId is bytes32; - -type ActionId is bytes32; - -type ValidationData is uint256; - -using { permissionIdEq as == } for PermissionId global; -using { permissionIdNeq as != } for PermissionId global; - -function permissionIdEq(PermissionId uid1, PermissionId uid2) pure returns (bool) { - return PermissionId.unwrap(uid1) == PermissionId.unwrap(uid2); -} - -function permissionIdNeq(PermissionId uid1, PermissionId uid2) pure returns (bool) { - return PermissionId.unwrap(uid1) != PermissionId.unwrap(uid2); -} - -/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ -/* Parameters */ -/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - -enum SmartSessionMode { - USE, - ENABLE, - UNSAFE_ENABLE -} - -enum PolicyType { - NA, - USER_OP, - ACTION, - ERC1271 -} - -struct EnableSession { - uint8 chainDigestIndex; - ChainDigest[] hashesAndChainIds; - Session sessionToEnable; - // in order to enable a session, the smart account has to sign a digest. The signature for this - // is stored here. - bytes permissionEnableSig; -} - -struct ChainDigest { - uint64 chainId; - bytes32 sessionDigest; -} - -// Action data is a struct that contains the actionId and the policies that are associated with this -// action. -struct ActionData { - bytes4 actionTargetSelector; - address actionTarget; - PolicyData[] actionPolicies; -} - -// Policy data is a struct that contains the policy address and the initialization data for the -// policy. -struct PolicyData { - address policy; - bytes initData; -} - -struct ERC7739Data { - string[] allowedERC7739Content; - PolicyData[] erc1271Policies; -} - -/** - * - * Represents a Session structure with various attributes for managing user operations and policies. - * - * Attributes: - * sessionValidator (ISessionValidator): The validator contract for signing user operations. - * Every userOp must be signed by the session key "owner". The signature is validated - * via a stateless external contract (ISessionValidator) that can implement different - * means of validation. - * - * sessionValidatorInitData (bytes): Initialization data for the ISessionValidator contract. - * The ISessionValidator contract can be configured with different parameters that are - * passed in this field. - * - * salt (bytes32): A unique identifier to prevent collision between sessions. - * A session key owner can have multiple sessions with the same parameters. To facilitate - * this, a salt is necessary to avoid collision. - * - * userOpPolicies (PolicyData[]): An array of policy data for user operations. - * When every session can have multiple policies set. - * - * erc7739Policies (ERC7739Data): ERC1271 Policies specific to the ERC7739 standard. - * - * actions (ActionData[]): An array of action data for specifying function-specific policies. - * A common use case of session keys is to scope access to a specific target and function - * selector. SmartSession calls this "Action". With ActionData, we can specify policies - * that are only run if a 7579 execution contains a specific action. - */ -struct Session { - ISessionValidator sessionValidator; - bytes sessionValidatorInitData; - bytes32 salt; - PolicyData[] userOpPolicies; - ERC7739Data erc7739Policies; - ActionData[] actions; -} - -/** - * @title ISmartSession - * @author Filipp Makarov (Biconomy) & zeroknots.eth (Rhinestone) - * @dev A collaborative effort between Rhinestone and Biconomy to create a powerful - * and flexible session key management system for ERC-4337 and ERC-7579 accounts. - * SmartSession is an advanced module for ERC-4337 and ERC-7579 compatible smart contract wallets, - * enabling granular - * control over session keys. It allows users to create and manage temporary, limited-permission - * access to their - * accounts through configurable policies. The module supports various policy types, including user - * operation - * validation, action-specific policies, and ERC-1271 signature validation. SmartSession implements - * a unique "enable - * flow" that allows session keys to be created within the first user operation, enhancing security - * and user experience. - * It uses a nested EIP-712 approach for signature validation, providing phishing resistance and - * compatibility with - * existing wallet interfaces. The module also supports batched executions and integrates with - * external policy contracts - * for flexible permission management. Overall, SmartSession offers a comprehensive solution for - * secure, temporary - * account access in the evolving landscape of account abstraction. - */ -interface ISmartSession { - error AssociatedArray_OutOfBounds(uint256 index); - error ChainIdMismatch(uint64 providedChainId); - error HashIndexOutOfBounds(uint256 index); - error HashMismatch(bytes32 providedHash, bytes32 computedHash); - error InvalidData(); - error InvalidActionId(); - error NoExecutionsInBatch(); - error InvalidTarget(); - error InvalidEnableSignature(address account, bytes32 hash); - error InvalidISessionValidator(ISessionValidator sessionValidator); - error InvalidSelfCall(); - error InvalidSession(PermissionId permissionId); - error InvalidSessionKeySignature( - PermissionId permissionId, address sessionValidator, address account, bytes32 userOpHash - ); - error SmartSessionModuleAlreadyInstalled(address account); - error InvalidPermissionId(PermissionId permissionId); - error InvalidCallTarget(); - error InvalidUserOpSender(address sender); - error NoPoliciesSet(PermissionId permissionId); - error PartlyEnabledActions(); - error PartlyEnabledPolicies(); - error PolicyViolation(PermissionId permissionId, address policy); - error SignerNotFound(PermissionId permissionId, address account); - error UnsupportedExecutionType(); - error UnsupportedPolicy(address policy); - error UnsupportedSmartSessionMode(SmartSessionMode mode); - error ForbiddenValidationData(); - - event NonceIterated(PermissionId permissionId, address account, uint256 newValue); - event SessionValidatorEnabled( - PermissionId permissionId, address sessionValidator, address smartAccount - ); - event SessionValidatorDisabled( - PermissionId permissionId, address sessionValidator, address smartAccount - ); - event PolicyDisabled( - PermissionId permissionId, PolicyType policyType, address policy, address smartAccount - ); - event ActionIdDisabled(PermissionId permissionId, ActionId actionId, address smartAccount); - event PolicyEnabled( - PermissionId permissionId, PolicyType policyType, address policy, address smartAccount - ); - event SessionCreated(PermissionId permissionId, address account); - event SessionRemoved(PermissionId permissionId, address smartAccount); - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* ERC7579 */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /** - * ERC4337/ERC7579 validation function - * the primary purpose of this function, is to validate if a userOp forwarded by a 7579 account - * is valid. - * This function will dissect the userop.signature field, and parse out the provided - * PermissionId, which identifies - * a - * unique ID of a dapp for a specific user. n Policies and one Signer contract are mapped to - * this Id and will be - * checked. Only UserOps that pass policies and signer checks, are considered valid. - * Enable Flow: - * SmartSessions allows session keys to be created within the "first" UserOp. If the enable - * flow is chosen, the - * EnableSession data, which is packed in userOp.signature is parsed, and stored in the - * SmartSession storage. - * - */ - function validateUserOp( - PackedUserOperation memory userOp, - bytes32 userOpHash - ) - external - returns (ValidationData vd); - /** - * ERC7579 compliant onInstall function. - * expected to abi.encode(Session[]) for the enable data - * - * Note: It's possible to install the smartsession module with data = "" - */ - function onInstall(bytes memory data) external; - - /** - * ERC7579 compliant uninstall function. - * will wipe all configIds and associated Policies / Signers - */ - function onUninstall(bytes memory) external; - - /** - * ERC7579 compliant ERC1271 function - * this function allows session keys to sign ERC1271 requests. - */ - function isValidSignatureWithSender( - address sender, - bytes32 hash, - bytes memory signature - ) - external - view - returns (bytes4 result); - - function isInitialized(address smartAccount) external view returns (bool); - function isModuleType(uint256 typeID) external pure returns (bool); - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Manage Sessions */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - function enableActionPolicies( - PermissionId permissionId, - ActionData[] memory actionPolicies - ) - external; - function enableERC1271Policies( - PermissionId permissionId, - ERC7739Data calldata erc1271Policies - ) - external; - function enableSessions(Session[] memory sessions) - external - returns (PermissionId[] memory permissionIds); - function enableUserOpPolicies( - PermissionId permissionId, - PolicyData[] memory userOpPolicies - ) - external; - function disableActionPolicies( - PermissionId permissionId, - ActionId actionId, - address[] memory policies - ) - external; - function disableActionId(PermissionId permissionId, ActionId actionId) external; - function disableERC1271Policies( - PermissionId permissionId, - address[] memory policies, - string[] calldata contents - ) - external; - function disableUserOpPolicies(PermissionId permissionId, address[] memory policies) external; - function removeSession(PermissionId permissionId) external; - function revokeEnableSignature(PermissionId permissionId) external; - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* View Functions */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - function getSessionDigest( - PermissionId permissionId, - address account, - Session memory data, - SmartSessionMode mode - ) - external - view - returns (bytes32); - - function getNonce(PermissionId permissionId, address account) external view returns (uint256); - function getPermissionId(Session memory session) - external - pure - returns (PermissionId permissionId); - function isPermissionEnabled( - PermissionId permissionId, - address account - ) - external - view - returns (bool); - function isISessionValidatorSet( - PermissionId permissionId, - address account - ) - external - view - returns (bool); - function areUserOpPoliciesEnabled( - address account, - PermissionId permissionId, - PolicyData[] calldata userOpPolicies - ) - external - view - returns (bool); - function areERC1271PoliciesEnabled( - address account, - PermissionId permissionId, - PolicyData[] calldata erc1271Policies - ) - external - view - returns (bool); - function areActionsEnabled( - address account, - PermissionId permissionId, - ActionData[] calldata actions - ) - external - view - returns (bool); -} - -/** - * ISessionValidator is a contract that validates signatures for a given session. - * this interface expects to validate the signature in a stateless way. - * all parameters required to validate the signature are passed in the function call. - * Only one ISessionValidator is responsible to validate a userOp. - * if you want to use multiple validators, you can create a ISessionValidator that aggregates - * multiple signatures that - * are packed into userOp.signature - * It is used to validate the signature of a session. - * hash The userOp hash - * sig The signature of userOp - * data the config data that is used to validate the signature - */ -interface ISessionValidator is IModule { - function validateSignatureWithData( - bytes32 hash, - bytes calldata sig, - bytes calldata data - ) - external - view - returns (bool validSig); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISubscriptions.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISubscriptions.sol deleted file mode 100644 index d6ee534..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ISubscriptions.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface ISubscriptions { - function unsubscribe() external; - function unsubscribe(uint256 _cdpId) external; - function subscribersPos(uint256) external view returns (uint256 arrPos, bool subscribed); - function subscribersPos(address) external view returns (uint256 arrPos, bool subscribed); - function isSubscribed(address _user) external view returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ITrigger.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ITrigger.sol deleted file mode 100644 index 491425d..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/ITrigger.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract ITrigger { - function isTriggered(bytes memory, bytes memory) public virtual returns (bool); - function isChangeable() public virtual returns (bool); - function changedSubData(bytes memory) public virtual returns (bytes memory); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IWETH.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IWETH.sol deleted file mode 100644 index a7128f1..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/IWETH.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -import "forge-std/interfaces/IERC20.sol"; - -abstract contract IWETH { - function allowance(address, address) public view virtual returns (uint256); - - function balanceOf(address) public view virtual returns (uint256); - - function approve(address, uint256) public virtual; - - function transfer(address, uint256) public virtual returns (bool); - - function transferFrom(address, address, uint256) public virtual returns (bool); - - function deposit() public payable virtual; - - function withdraw(uint256) public virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/ICBETH.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/ICBETH.sol deleted file mode 100644 index 5247f31..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/ICBETH.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface ICBETH { - function exchangeRate() external view returns (uint256 wethAmountPerCBETH); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IRETH.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IRETH.sol deleted file mode 100644 index 90dbbec..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IRETH.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface IRETH { - function getEthValue(uint256 rethAmount) external view returns (uint256 wethAmount); - function getRethValue(uint256 wethAmount) external view returns (uint256 rethAmount); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IWstETH.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IWstETH.sol deleted file mode 100644 index 9f8398d..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/LSTs/IWstETH.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface IWstETH { - function getStETHByWstETH(uint256 wstethAmount) external view returns (uint256 wethAmount); - function getWstETHByStETH(uint256 wethAmount) external view returns (uint256 wstethAmount); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IAToken.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IAToken.sol deleted file mode 100644 index 7b4f5f6..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IAToken.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IAToken { - function redeem(uint256 _amount) external virtual; - function balanceOf(address _owner) external view virtual returns (uint256 balance); - function UNDERLYING_ASSET_ADDRESS() external view virtual returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendToAaveMigrator.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendToAaveMigrator.sol deleted file mode 100644 index e5c69f6..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendToAaveMigrator.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract ILendToAaveMigrator { - function migrateFromLEND(uint256 amount) external virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPool.sol deleted file mode 100644 index 30eb802..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPool.sol +++ /dev/null @@ -1,179 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -abstract contract ILendingPool { - function flashLoan( - address payable _receiver, - address _reserve, - uint256 _amount, - bytes calldata _params - ) - external - virtual; - function deposit( - address _reserve, - uint256 _amount, - uint16 _referralCode - ) - external - payable - virtual; - function setUserUseReserveAsCollateral( - address _reserve, - bool _useAsCollateral - ) - external - virtual; - function borrow( - address _reserve, - uint256 _amount, - uint256 _interestRateMode, - uint16 _referralCode - ) - external - virtual; - function repay( - address _reserve, - uint256 _amount, - address payable _onBehalfOf - ) - external - payable - virtual; - function swapBorrowRateMode(address _reserve) external virtual; - function getReserves() external view virtual returns (address[] memory); - - /// @param _reserve underlying token address - function getReserveData(address _reserve) - external - view - virtual - returns ( - uint256 totalLiquidity, // reserve total liquidity - uint256 availableLiquidity, // reserve available liquidity for borrowing - uint256 totalBorrowsStable, // total amount of outstanding borrows at Stable rate - uint256 totalBorrowsVariable, // total amount of outstanding borrows at Variable rate - uint256 liquidityRate, // current deposit APY of the reserve for depositors, in Ray - // units. - uint256 variableBorrowRate, // current variable rate APY of the reserve pool, in Ray - // units. - uint256 stableBorrowRate, // current stable rate APY of the reserve pool, in Ray units. - uint256 averageStableBorrowRate, // current average stable borrow rate - uint256 utilizationRate, // expressed as total borrows/total liquidity. - uint256 liquidityIndex, // cumulative liquidity index - uint256 variableBorrowIndex, // cumulative variable borrow index - address aTokenAddress, // aTokens contract address for the specific _reserve - uint40 lastUpdateTimestamp - ); // timestamp of the last update of reserve data - - /// @param _user users address - function getUserAccountData(address _user) - external - view - virtual - returns ( - uint256 totalLiquidityETH, // user aggregated deposits across all the reserves. In Wei - uint256 totalCollateralETH, // user aggregated collateral across all the reserves. In - // Wei - uint256 totalBorrowsETH, // user aggregated outstanding borrows across all the reserves. - // In Wei - uint256 totalFeesETH, // user aggregated current outstanding fees in ETH. In Wei - uint256 availableBorrowsETH, // user available amount to borrow in ETH - uint256 currentLiquidationThreshold, // user current average liquidation threshold - // across all the collaterals deposited - uint256 ltv, // user average Loan-to-Value between all the collaterals - uint256 healthFactor - ); // user current Health Factor - - /// @param _reserve underlying token address - /// @param _user users address - function getUserReserveData( - address _reserve, - address _user - ) - external - view - virtual - returns ( - uint256 currentATokenBalance, // user current reserve aToken balance - uint256 currentBorrowBalance, // user current reserve outstanding borrow balance - uint256 principalBorrowBalance, // user balance of borrowed asset - uint256 borrowRateMode, // user borrow rate mode either Stable or Variable - uint256 borrowRate, // user current borrow rate APY - uint256 liquidityRate, // user current earn rate on _reserve - uint256 originationFee, // user outstanding loan origination fee - uint256 variableBorrowIndex, // user variable cumulative index - uint256 lastUpdateTimestamp, // Timestamp of the last data update - bool usageAsCollateralEnabled - ); // Whether the user's current reserve is enabled as a collateral - - function getReserveConfigurationData(address _reserve) - external - view - virtual - returns ( - uint256 ltv, - uint256 liquidationThreshold, - uint256 liquidationBonus, - address rateStrategyAddress, - bool usageAsCollateralEnabled, - bool borrowingEnabled, - bool stableBorrowRateEnabled, - bool isActive - ); - - // ------------------ LendingPoolCoreData ------------------------ - function getReserveATokenAddress(address _reserve) public view virtual returns (address); - function getReserveConfiguration(address _reserve) - external - view - virtual - returns (uint256, uint256, uint256, bool); - function getUserUnderlyingAssetBalance( - address _reserve, - address _user - ) - public - view - virtual - returns (uint256); - - function getReserveCurrentLiquidityRate(address _reserve) - public - view - virtual - returns (uint256); - function getReserveCurrentVariableBorrowRate(address _reserve) - public - view - virtual - returns (uint256); - function getReserveCurrentStableBorrowRate(address _reserve) - public - view - virtual - returns (uint256); - function getReserveTotalLiquidity(address _reserve) public view virtual returns (uint256); - function getReserveAvailableLiquidity(address _reserve) public view virtual returns (uint256); - function getReserveTotalBorrowsVariable(address _reserve) - public - view - virtual - returns (uint256); - - // ---------------- LendingPoolDataProvider --------------------- - function calculateUserGlobalData(address _user) - public - view - virtual - returns ( - uint256 totalLiquidityBalanceETH, - uint256 totalCollateralBalanceETH, - uint256 totalBorrowBalanceETH, - uint256 totalFeesETH, - uint256 currentLtv, - uint256 currentLiquidationThreshold, - uint256 healthFactor, - bool healthFactorBelowThreshold - ); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPoolAddressesProvider.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPoolAddressesProvider.sol deleted file mode 100644 index 5159835..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/ILendingPoolAddressesProvider.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract ILendingPoolAddressesProvider { - function getLendingPool() public view virtual returns (address); - - function setLendingPoolImpl(address _pool) public virtual; - - function getLendingPoolCore() public view virtual returns (address payable); - - function setLendingPoolCoreImpl(address _lendingPoolCore) public virtual; - - function getLendingPoolConfigurator() public view virtual returns (address); - - function setLendingPoolConfiguratorImpl(address _configurator) public virtual; - - function getLendingPoolDataProvider() public view virtual returns (address); - - function setLendingPoolDataProviderImpl(address _provider) public virtual; - - function getLendingPoolParametersProvider() public view virtual returns (address); - - function setLendingPoolParametersProviderImpl(address _parametersProvider) public virtual; - - function getTokenDistributor() public view virtual returns (address); - - function setTokenDistributor(address _tokenDistributor) public virtual; - - function getFeeProvider() public view virtual returns (address); - - function setFeeProviderImpl(address _feeProvider) public virtual; - - function getLendingPoolLiquidationManager() public view virtual returns (address); - - function setLendingPoolLiquidationManager(address _manager) public virtual; - - function getLendingPoolManager() public view virtual returns (address); - - function setLendingPoolManager(address _lendingPoolManager) public virtual; - - function getPriceOracle() public view virtual returns (address); - - function setPriceOracle(address _priceOracle) public virtual; - - function getLendingRateOracle() public view virtual returns (address); - - function setLendingRateOracle(address _lendingRateOracle) public virtual; -} - -library EthAddressLib { - function ethAddress() internal pure returns (address) { - return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IStkAave.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IStkAave.sol deleted file mode 100644 index abd0157..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aave/IStkAave.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IStkAave { - function cooldown() external virtual; - function redeem(address to, uint256 amount) external virtual; - function REWARD_TOKEN() external view virtual returns (address); - function stake(address onBehalfOf, uint256 amount) external virtual; - function claimRewards(address to, uint256 amount) external virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveIncentivesController.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveIncentivesController.sol deleted file mode 100644 index 6007d8f..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveIncentivesController.sol +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: agpl-3.0 -pragma solidity ^0.8.10; -pragma experimental ABIEncoderV2; - -interface IAaveIncentivesController { - event RewardsAccrued(address indexed user, uint256 amount); - - event RewardsClaimed( - address indexed user, address indexed to, address indexed claimer, uint256 amount - ); - - event ClaimerSet(address indexed user, address indexed claimer); - - /** - * @dev Whitelists an address to claim the rewards on behalf of another address - * @param user The address of the user - * @param claimer The address of the claimer - */ - function setClaimer(address user, address claimer) external; - - /** - * @dev Returns the whitelisted claimer for a certain address (0x0 if not set) - * @param user The address of the user - * @return The claimer address - */ - function getClaimer(address user) external view returns (address); - - /** - * @dev Configure assets for a certain rewards emission - * @param assets The assets to incentivize - * @param emissionsPerSecond The emission for each asset - */ - function configureAssets( - address[] calldata assets, - uint256[] calldata emissionsPerSecond - ) - external; - - /** - * @dev Called by the corresponding asset on any update that affects the rewards distribution - * @param asset The address of the user - * @param userBalance The balance of the user of the asset in the lending pool - * @param totalSupply The total supply of the asset in the lending pool - * - */ - function handleAction(address asset, uint256 userBalance, uint256 totalSupply) external; - - /** - * @dev Returns the total of rewards of an user, already accrued + not yet accrued - * @param user The address of the user - * @return The rewards - * - */ - function getRewardsBalance( - address[] calldata assets, - address user - ) - external - view - returns (uint256); - - /** - * @dev Claims reward for an user, on all the assets of the lending pool, accumulating the - * pending rewards - * @param amount Amount of rewards to claim - * @param to Address that will be receiving the rewards - * @return Rewards claimed - * - */ - function claimRewards( - address[] calldata assets, - uint256 amount, - address to - ) - external - returns (uint256); - - /** - * @dev Claims reward for an user on behalf, on all the assets of the lending pool, accumulating - * the pending rewards. The caller must - * be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager - * @param amount Amount of rewards to claim - * @param user Address to check and claim rewards - * @param to Address that will be receiving the rewards - * @return Rewards claimed - * - */ - function claimRewardsOnBehalf( - address[] calldata assets, - uint256 amount, - address user, - address to - ) - external - returns (uint256); - - /** - * @dev returns the unclaimed rewards of the user - * @param user the address of the user - * @return the unclaimed user rewards - */ - function getUserUnclaimedRewards(address user) external view returns (uint256); - - /** - * @dev for backward compatibility with previous implementation of the Incentives controller - */ - function REWARD_TOKEN() external view returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveProtocolDataProviderV2.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveProtocolDataProviderV2.sol deleted file mode 100644 index 4adde7c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IAaveProtocolDataProviderV2.sol +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IAaveProtocolDataProviderV2 { - struct TokenData { - string symbol; - address tokenAddress; - } - - function getAllReservesTokens() external view virtual returns (TokenData[] memory); - - function getAllATokens() external view virtual returns (TokenData[] memory); - - function getReserveConfigurationData(address asset) - external - view - virtual - returns ( - uint256 decimals, - uint256 ltv, - uint256 liquidationThreshold, - uint256 liquidationBonus, - uint256 reserveFactor, - bool usageAsCollateralEnabled, - bool borrowingEnabled, - bool stableBorrowRateEnabled, - bool isActive, - bool isFrozen - ); - - function getReserveData(address asset) - external - view - virtual - returns ( - uint256 availableLiquidity, - uint256 totalStableDebt, - uint256 totalVariableDebt, - uint256 liquidityRate, - uint256 variableBorrowRate, - uint256 stableBorrowRate, - uint256 averageStableBorrowRate, - uint256 liquidityIndex, - uint256 variableBorrowIndex, - uint40 lastUpdateTimestamp - ); - - function getUserReserveData( - address asset, - address user - ) - external - view - virtual - returns ( - uint256 currentATokenBalance, - uint256 currentStableDebt, - uint256 currentVariableDebt, - uint256 principalStableDebt, - uint256 scaledVariableDebt, - uint256 stableBorrowRate, - uint256 liquidityRate, - uint40 stableRateLastUpdated, - bool usageAsCollateralEnabled - ); - - function getReserveTokensAddresses(address asset) - external - view - virtual - returns ( - address aTokenAddress, - address stableDebtTokenAddress, - address variableDebtTokenAddress - ); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolAddressesProviderV2.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolAddressesProviderV2.sol deleted file mode 100644 index 4819a5a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolAddressesProviderV2.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: agpl-3.0 -pragma solidity ^0.8.10; - -interface ILendingPoolAddressesProviderV2 { - event LendingPoolUpdated(address indexed newAddress); - event ConfigurationAdminUpdated(address indexed newAddress); - event EmergencyAdminUpdated(address indexed newAddress); - event LendingPoolConfiguratorUpdated(address indexed newAddress); - event LendingPoolCollateralManagerUpdated(address indexed newAddress); - event PriceOracleUpdated(address indexed newAddress); - event LendingRateOracleUpdated(address indexed newAddress); - event ProxyCreated(bytes32 id, address indexed newAddress); - event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy); - - function setAddress(bytes32 id, address newAddress) external; - - function setAddressAsProxy(bytes32 id, address impl) external; - - function getAddress(bytes32 id) external view returns (address); - - function getLendingPool() external view returns (address); - - function setLendingPoolImpl(address pool) external; - - function getLendingPoolConfigurator() external view returns (address); - - function setLendingPoolConfiguratorImpl(address configurator) external; - - function getLendingPoolCollateralManager() external view returns (address); - - function setLendingPoolCollateralManager(address manager) external; - - function getPoolAdmin() external view returns (address); - - function setPoolAdmin(address admin) external; - - function getEmergencyAdmin() external view returns (address); - - function setEmergencyAdmin(address admin) external; - - function getPriceOracle() external view returns (address); - - function setPriceOracle(address priceOracle) external; - - function getLendingRateOracle() external view returns (address); - - function setLendingRateOracle(address lendingRateOracle) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolV2.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolV2.sol deleted file mode 100644 index 733e18c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolV2.sol +++ /dev/null @@ -1,517 +0,0 @@ -// SPDX-License-Identifier: agpl-3.0 -pragma solidity ^0.8.10; - -import "./ILendingPoolAddressesProviderV2.sol"; - -library DataTypes { - // refer to the whitepaper, section 1.1 basic concepts for a formal description of these - // properties. - struct ReserveData { - //stores the reserve configuration - ReserveConfigurationMap configuration; - //the liquidity index. Expressed in ray - uint128 liquidityIndex; - //variable borrow index. Expressed in ray - uint128 variableBorrowIndex; - //the current supply rate. Expressed in ray - uint128 currentLiquidityRate; - //the current variable borrow rate. Expressed in ray - uint128 currentVariableBorrowRate; - //the current stable borrow rate. Expressed in ray - uint128 currentStableBorrowRate; - uint40 lastUpdateTimestamp; - //tokens addresses - address aTokenAddress; - address stableDebtTokenAddress; - address variableDebtTokenAddress; - //address of the interest rate strategy - address interestRateStrategyAddress; - //the id of the reserve. Represents the position in the list of the active reserves - uint8 id; - } - - struct ReserveConfigurationMap { - //bit 0-15: LTV - //bit 16-31: Liq. threshold - //bit 32-47: Liq. bonus - //bit 48-55: Decimals - //bit 56: Reserve is active - //bit 57: reserve is frozen - //bit 58: borrowing is enabled - //bit 59: stable rate borrowing enabled - //bit 60-63: reserved - //bit 64-79: reserve factor - uint256 data; - } - - struct UserConfigurationMap { - uint256 data; - } - - enum InterestRateMode { - NONE, - STABLE, - VARIABLE - } -} - -interface ILendingPoolV2 { - /** - * @dev Emitted on deposit() - * @param reserve The address of the underlying asset of the reserve - * @param user The address initiating the deposit - * @param onBehalfOf The beneficiary of the deposit, receiving the aTokens - * @param amount The amount deposited - * @param referral The referral code used - * - */ - event Deposit( - address indexed reserve, - address user, - address indexed onBehalfOf, - uint256 amount, - uint16 indexed referral - ); - - /** - * @dev Emitted on withdraw() - * @param reserve The address of the underlyng asset being withdrawn - * @param user The address initiating the withdrawal, owner of aTokens - * @param to Address that will receive the underlying - * @param amount The amount to be withdrawn - * - */ - event Withdraw( - address indexed reserve, address indexed user, address indexed to, uint256 amount - ); - - /** - * @dev Emitted on borrow() and flashLoan() when debt needs to be opened - * @param reserve The address of the underlying asset being borrowed - * @param user The address of the user initiating the borrow(), receiving the funds on borrow() - * or just - * initiator of the transaction on flashLoan() - * @param onBehalfOf The address that will be getting the debt - * @param amount The amount borrowed out - * @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable - * @param borrowRate The numeric rate at which the user has borrowed - * @param referral The referral code used - * - */ - event Borrow( - address indexed reserve, - address user, - address indexed onBehalfOf, - uint256 amount, - uint256 borrowRateMode, - uint256 borrowRate, - uint16 indexed referral - ); - - /** - * @dev Emitted on repay() - * @param reserve The address of the underlying asset of the reserve - * @param user The beneficiary of the repayment, getting his debt reduced - * @param repayer The address of the user initiating the repay(), providing the funds - * @param amount The amount repaid - * - */ - event Repay( - address indexed reserve, address indexed user, address indexed repayer, uint256 amount - ); - - /** - * @dev Emitted on swapBorrowRateMode() - * @param reserve The address of the underlying asset of the reserve - * @param user The address of the user swapping his rate mode - * @param rateMode The rate mode that the user wants to swap to - * - */ - event Swap(address indexed reserve, address indexed user, uint256 rateMode); - - /** - * @dev Emitted on setUserUseReserveAsCollateral() - * @param reserve The address of the underlying asset of the reserve - * @param user The address of the user enabling the usage as collateral - * - */ - event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); - - /** - * @dev Emitted on setUserUseReserveAsCollateral() - * @param reserve The address of the underlying asset of the reserve - * @param user The address of the user enabling the usage as collateral - * - */ - event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); - - /** - * @dev Emitted on rebalanceStableBorrowRate() - * @param reserve The address of the underlying asset of the reserve - * @param user The address of the user for which the rebalance has been executed - * - */ - event RebalanceStableBorrowRate(address indexed reserve, address indexed user); - - /** - * @dev Emitted on flashLoan() - * @param target The address of the flash loan receiver contract - * @param initiator The address initiating the flash loan - * @param asset The address of the asset being flash borrowed - * @param amount The amount flash borrowed - * @param premium The fee flash borrowed - * @param referralCode The referral code used - * - */ - event FlashLoan( - address indexed target, - address indexed initiator, - address indexed asset, - uint256 amount, - uint256 premium, - uint16 referralCode - ); - - /** - * @dev Emitted when the pause is triggered. - */ - event Paused(); - - /** - * @dev Emitted when the pause is lifted. - */ - event Unpaused(); - - /** - * @dev Emitted when a borrower is liquidated. This event is emitted by the LendingPool via - * LendingPoolCollateral manager using a DELEGATECALL - * This allows to have the events in the generated ABI for LendingPool. - * @param collateralAsset The address of the underlying asset used as collateral, to receive as - * result of the liquidation - * @param debtAsset The address of the underlying borrowed asset to be repaid with the - * liquidation - * @param user The address of the borrower getting liquidated - * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover - * @param liquidatedCollateralAmount The amount of collateral received by the liiquidator - * @param liquidator The address of the liquidator - * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, - * `false` if he wants - * to receive the underlying collateral asset directly - * - */ - event LiquidationCall( - address indexed collateralAsset, - address indexed debtAsset, - address indexed user, - uint256 debtToCover, - uint256 liquidatedCollateralAmount, - address liquidator, - bool receiveAToken - ); - - /** - * @dev Emitted when the state of a reserve is updated. NOTE: This event is actually declared - * in the ReserveLogic library and emitted in the updateInterestRates() function. Since the - * function is internal, - * the event will actually be fired by the LendingPool contract. The event is therefore - * replicated here so it - * gets added to the LendingPool ABI - * @param reserve The address of the underlying asset of the reserve - * @param liquidityRate The new liquidity rate - * @param stableBorrowRate The new stable borrow rate - * @param variableBorrowRate The new variable borrow rate - * @param liquidityIndex The new liquidity index - * @param variableBorrowIndex The new variable borrow index - * - */ - event ReserveDataUpdated( - address indexed reserve, - uint256 liquidityRate, - uint256 stableBorrowRate, - uint256 variableBorrowRate, - uint256 liquidityIndex, - uint256 variableBorrowIndex - ); - - /** - * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying - * aTokens. - * - E.g. User deposits 100 USDC and gets in return 100 aUSDC - * @param asset The address of the underlying asset to deposit - * @param amount The amount to be deposited - * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user - * wants to receive them on his own wallet, or a different address if the beneficiary of - * aTokens - * is a different wallet - * @param referralCode Code used to register the integrator originating the operation, for - * potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - * - */ - function deposit( - address asset, - uint256 amount, - address onBehalfOf, - uint16 referralCode - ) - external; - - /** - * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent - * aTokens owned - * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC - * @param asset The address of the underlying asset to withdraw - * @param amount The underlying amount to be withdrawn - * - Send the value type(uint256).max in order to withdraw the whole aToken balance - * @param to Address that will receive the underlying, same as msg.sender if the user - * wants to receive it on his own wallet, or a different address if the beneficiary is a - * different wallet - * - */ - function withdraw(address asset, uint256 amount, address to) external; - - /** - * @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided - * that the borrower - * already deposited enough collateral, or he was given enough allowance by a credit delegator - * on the - * corresponding debt token (StableDebtToken or VariableDebtToken) - * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC - * in his wallet - * and 100 stable/variable debt tokens, depending on the `interestRateMode` - * @param asset The address of the underlying asset to borrow - * @param amount The amount to be borrowed - * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for - * Stable, 2 for Variable - * @param referralCode Code used to register the integrator originating the operation, for - * potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - * @param onBehalfOf Address of the user who will receive the debt. Should be the address of the - * borrower itself - * calling the function if he wants to borrow against his own collateral, or the address of the - * credit delegator - * if he has been given credit delegation allowance - * - */ - function borrow( - address asset, - uint256 amount, - uint256 interestRateMode, - uint16 referralCode, - address onBehalfOf - ) - external; - - /** - * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens - * owned - * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` - * address - * @param asset The address of the borrowed underlying asset previously borrowed - * @param amount The amount to repay - * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the - * specific `debtMode` - * @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, - * 2 for Variable - * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the - * address of the - * user calling the function if he wants to reduce/remove his own debt, or the address of any - * other - * other borrower whose debt should be removed - * - */ - function repay(address asset, uint256 amount, uint256 rateMode, address onBehalfOf) external; - - /** - * @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa - * @param asset The address of the underlying asset borrowed - * @param rateMode The rate mode that the user wants to swap to - * - */ - function swapBorrowRateMode(address asset, uint256 rateMode) external; - - /** - * @dev Rebalances the stable interest rate of a user to the current stable rate defined on the - * reserve. - * - Users can be rebalanced if the following conditions are satisfied: - * 1. Usage ratio is above 95% - * 2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which - * means that too much has been - * borrowed at a stable rate and depositors are not earning enough - * @param asset The address of the underlying asset borrowed - * @param user The address of the user to be rebalanced - * - */ - function rebalanceStableBorrowRate(address asset, address user) external; - - /** - * @dev Allows depositors to enable/disable a specific deposited asset as collateral - * @param asset The address of the underlying asset deposited - * @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` - * otherwise - * - */ - function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external; - - /** - * @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1 - * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, - * and receives - * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk - * @param collateralAsset The address of the underlying asset used as collateral, to receive as - * result of the liquidation - * @param debtAsset The address of the underlying borrowed asset to be repaid with the - * liquidation - * @param user The address of the borrower getting liquidated - * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover - * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, - * `false` if he wants - * to receive the underlying collateral asset directly - * - */ - function liquidationCall( - address collateralAsset, - address debtAsset, - address user, - uint256 debtToCover, - bool receiveAToken - ) - external; - - /** - * @dev Allows smartcontracts to access the liquidity of the pool within one transaction, - * as long as the amount taken plus a fee is returned. - * IMPORTANT There are security concerns for developers of flashloan receiver contracts that - * must be kept into consideration. - * For further details please visit https://developers.aave.com - * @param receiverAddress The address of the contract receiving the funds, implementing the - * IFlashLoanReceiver interface - * @param assets The addresses of the assets being flash-borrowed - * @param amounts The amounts amounts being flash-borrowed - * @param modes Types of the debt to open if the flash loan is not returned: - * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver - * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the - * `onBehalfOf` address - * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the - * `onBehalfOf` address - * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 - * or 2 - * @param params Variadic packed params to pass to the receiver as extra information - * @param referralCode Code used to register the integrator originating the operation, for - * potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - * - */ - function flashLoan( - address receiverAddress, - address[] calldata assets, - uint256[] calldata amounts, - uint256[] calldata modes, - address onBehalfOf, - bytes calldata params, - uint16 referralCode - ) - external; - - /** - * @dev Returns the user account data across all the reserves - * @param user The address of the user - * @return totalCollateralETH the total collateral in ETH of the user - * @return totalDebtETH the total debt in ETH of the user - * @return availableBorrowsETH the borrowing power left of the user - * @return currentLiquidationThreshold the liquidation threshold of the user - * @return ltv the loan to value of the user - * @return healthFactor the current health factor of the user - * - */ - function getUserAccountData(address user) - external - view - returns ( - uint256 totalCollateralETH, - uint256 totalDebtETH, - uint256 availableBorrowsETH, - uint256 currentLiquidationThreshold, - uint256 ltv, - uint256 healthFactor - ); - - function initReserve( - address reserve, - address aTokenAddress, - address stableDebtAddress, - address variableDebtAddress, - address interestRateStrategyAddress - ) - external; - - function setReserveInterestRateStrategyAddress( - address reserve, - address rateStrategyAddress - ) - external; - - function setConfiguration(address reserve, uint256 configuration) external; - - /** - * @dev Returns the configuration of the reserve - * @param asset The address of the underlying asset of the reserve - * @return The configuration of the reserve - * - */ - function getConfiguration(address asset) - external - view - returns (DataTypes.ReserveConfigurationMap memory); - - /** - * @dev Returns the configuration of the user across all the reserves - * @param user The user address - * @return The configuration of the user - * - */ - function getUserConfiguration(address user) - external - view - returns (DataTypes.UserConfigurationMap memory); - - /** - * @dev Returns the normalized income normalized income of the reserve - * @param asset The address of the underlying asset of the reserve - * @return The reserve's normalized income - */ - function getReserveNormalizedIncome(address asset) external view returns (uint256); - - /** - * @dev Returns the normalized variable debt per unit of asset - * @param asset The address of the underlying asset of the reserve - * @return The reserve normalized variable debt - */ - function getReserveNormalizedVariableDebt(address asset) external view returns (uint256); - - /** - * @dev Returns the state and configuration of the reserve - * @param asset The address of the underlying asset of the reserve - * @return The state of the reserve - * - */ - function getReserveData(address asset) external view returns (DataTypes.ReserveData memory); - - function finalizeTransfer( - address asset, - address from, - address to, - uint256 amount, - uint256 balanceFromAfter, - uint256 balanceToBefore - ) - external; - - function getReservesList() external view returns (address[] memory); - - function getAddressesProvider() external view returns (ILendingPoolAddressesProviderV2); - - function setPause(bool val) external; - - function paused() external view returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IPriceOracleGetterAave.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IPriceOracleGetterAave.sol deleted file mode 100644 index 08946c2..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IPriceOracleGetterAave.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: agpl-3.0 - -pragma solidity ^0.8.10; - -abstract contract IPriceOracleGetterAave { - function getAssetPrice(address _asset) external view virtual returns (uint256); - function getAssetsPrices(address[] calldata _assets) - external - view - virtual - returns (uint256[] memory); - function getSourceOfAsset(address _asset) external view virtual returns (address); - function getFallbackOracle() external view virtual returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IStakedToken.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IStakedToken.sol deleted file mode 100644 index 7797957..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV2/IStakedToken.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IStakedToken { - function getTotalRewardsBalance(address) external view returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/DataTypes.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/DataTypes.sol deleted file mode 100644 index d65eced..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/DataTypes.sol +++ /dev/null @@ -1,271 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.10; - -library DataTypes { - struct ReserveData { - //stores the reserve configuration - ReserveConfigurationMap configuration; - //the liquidity index. Expressed in ray - uint128 liquidityIndex; - //the current supply rate. Expressed in ray - uint128 currentLiquidityRate; - //variable borrow index. Expressed in ray - uint128 variableBorrowIndex; - //the current variable borrow rate. Expressed in ray - uint128 currentVariableBorrowRate; - //the current stable borrow rate. Expressed in ray - uint128 currentStableBorrowRate; - //timestamp of last update - uint40 lastUpdateTimestamp; - //the id of the reserve. Represents the position in the list of the active reserves - uint16 id; - //aToken address - address aTokenAddress; - //stableDebtToken address - address stableDebtTokenAddress; - //variableDebtToken address - address variableDebtTokenAddress; - //address of the interest rate strategy - address interestRateStrategyAddress; - //the current treasury balance, scaled - uint128 accruedToTreasury; - //the outstanding unbacked aTokens minted through the bridging feature - uint128 unbacked; - //the outstanding debt borrowed against this asset in isolation mode - uint128 isolationModeTotalDebt; - } - - struct ReserveConfigurationMap { - //bit 0-15: LTV - //bit 16-31: Liq. threshold - //bit 32-47: Liq. bonus - //bit 48-55: Decimals - //bit 56: reserve is active - //bit 57: reserve is frozen - //bit 58: borrowing is enabled - //bit 59: stable rate borrowing enabled - //bit 60: asset is paused - //bit 61: borrowing in isolation mode is enabled - //bit 62-63: reserved - //bit 64-79: reserve factor - //bit 80-115 borrow cap in whole tokens, borrowCap == 0 => no cap - //bit 116-151 supply cap in whole tokens, supplyCap == 0 => no cap - //bit 152-167 liquidation protocol fee - //bit 168-175 eMode category - //bit 176-211 unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled - //bit 212-251 debt ceiling for isolation mode with - // (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals - //bit 252-255 unused - uint256 data; - } - - struct UserConfigurationMap { - /** - * @dev Bitmap of the users collaterals and borrows. It is divided in pairs of bits, one - * pair per asset. - * The first bit indicates if an asset is used as collateral by the user, the second whether - * an - * asset is borrowed by the user. - */ - uint256 data; - } - - struct EModeCategory { - // each eMode category has a custom ltv and liquidation threshold - uint16 ltv; - uint16 liquidationThreshold; - uint16 liquidationBonus; - // each eMode category may or may not have a custom oracle to override the individual assets - // price oracles - address priceSource; - string label; - } - - enum InterestRateMode { - NONE, - STABLE, - VARIABLE - } - - struct ReserveCache { - uint256 currScaledVariableDebt; - uint256 nextScaledVariableDebt; - uint256 currPrincipalStableDebt; - uint256 currAvgStableBorrowRate; - uint256 currTotalStableDebt; - uint256 nextAvgStableBorrowRate; - uint256 nextTotalStableDebt; - uint256 currLiquidityIndex; - uint256 nextLiquidityIndex; - uint256 currVariableBorrowIndex; - uint256 nextVariableBorrowIndex; - uint256 currLiquidityRate; - uint256 currVariableBorrowRate; - uint256 reserveFactor; - ReserveConfigurationMap reserveConfiguration; - address aTokenAddress; - address stableDebtTokenAddress; - address variableDebtTokenAddress; - uint40 reserveLastUpdateTimestamp; - uint40 stableDebtLastUpdateTimestamp; - } - - struct ExecuteLiquidationCallParams { - uint256 reservesCount; - uint256 debtToCover; - address collateralAsset; - address debtAsset; - address user; - bool receiveAToken; - address priceOracle; - uint8 userEModeCategory; - address priceOracleSentinel; - } - - struct ExecuteSupplyParams { - address asset; - uint256 amount; - address onBehalfOf; - uint16 referralCode; - } - - struct ExecuteBorrowParams { - address asset; - address user; - address onBehalfOf; - uint256 amount; - InterestRateMode interestRateMode; - uint16 referralCode; - bool releaseUnderlying; - uint256 maxStableRateBorrowSizePercent; - uint256 reservesCount; - address oracle; - uint8 userEModeCategory; - address priceOracleSentinel; - } - - struct ExecuteRepayParams { - address asset; - uint256 amount; - InterestRateMode interestRateMode; - address onBehalfOf; - bool useATokens; - } - - struct ExecuteWithdrawParams { - address asset; - uint256 amount; - address to; - uint256 reservesCount; - address oracle; - uint8 userEModeCategory; - } - - struct ExecuteSetUserEModeParams { - uint256 reservesCount; - address oracle; - uint8 categoryId; - } - - struct FinalizeTransferParams { - address asset; - address from; - address to; - uint256 amount; - uint256 balanceFromBefore; - uint256 balanceToBefore; - uint256 reservesCount; - address oracle; - uint8 fromEModeCategory; - } - - struct FlashloanParams { - address receiverAddress; - address[] assets; - uint256[] amounts; - uint256[] interestRateModes; - address onBehalfOf; - bytes params; - uint16 referralCode; - uint256 flashLoanPremiumToProtocol; - uint256 flashLoanPremiumTotal; - uint256 maxStableRateBorrowSizePercent; - uint256 reservesCount; - address addressesProvider; - uint8 userEModeCategory; - bool isAuthorizedFlashBorrower; - } - - struct FlashloanSimpleParams { - address receiverAddress; - address asset; - uint256 amount; - bytes params; - uint16 referralCode; - uint256 flashLoanPremiumToProtocol; - uint256 flashLoanPremiumTotal; - } - - struct FlashLoanRepaymentParams { - uint256 amount; - uint256 totalPremium; - uint256 flashLoanPremiumToProtocol; - address asset; - address receiverAddress; - uint16 referralCode; - } - - struct CalculateUserAccountDataParams { - UserConfigurationMap userConfig; - uint256 reservesCount; - address user; - address oracle; - uint8 userEModeCategory; - } - - struct ValidateBorrowParams { - ReserveCache reserveCache; - UserConfigurationMap userConfig; - address asset; - address userAddress; - uint256 amount; - InterestRateMode interestRateMode; - uint256 maxStableLoanPercent; - uint256 reservesCount; - address oracle; - uint8 userEModeCategory; - address priceOracleSentinel; - bool isolationModeActive; - address isolationModeCollateralAddress; - uint256 isolationModeDebtCeiling; - } - - struct ValidateLiquidationCallParams { - ReserveCache debtReserveCache; - uint256 totalDebt; - uint256 healthFactor; - address priceOracleSentinel; - } - - struct CalculateInterestRatesParams { - uint256 unbacked; - uint256 liquidityAdded; - uint256 liquidityTaken; - uint256 totalStableDebt; - uint256 totalVariableDebt; - uint256 averageStableBorrowRate; - uint256 reserveFactor; - address reserve; - address aToken; - } - - struct InitReserveParams { - address asset; - address aTokenAddress; - address stableDebtAddress; - address variableDebtAddress; - address interestRateStrategyAddress; - uint16 reservesCount; - uint16 maxNumberReserves; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveProtocolDataProvider.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveProtocolDataProvider.sol deleted file mode 100644 index 44c4f12..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveProtocolDataProvider.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0 -pragma solidity ^0.8.10; - -interface IAaveProtocolDataProvider { - /** - * @notice Returns the user data in a reserve - * @param asset The address of the underlying asset of the reserve - * @param user The address of the user - * @return currentATokenBalance The current AToken balance of the user - * @return currentStableDebt The current stable debt of the user - * @return currentVariableDebt The current variable debt of the user - * @return principalStableDebt The principal stable debt of the user - * @return scaledVariableDebt The scaled variable debt of the user - * @return stableBorrowRate The stable borrow rate of the user - * @return liquidityRate The liquidity rate of the reserve - * @return stableRateLastUpdated The timestamp of the last update of the user stable rate - * @return usageAsCollateralEnabled True if the user is using the asset as collateral, false - * otherwise - * - */ - function getUserReserveData( - address asset, - address user - ) - external - view - returns ( - uint256 currentATokenBalance, - uint256 currentStableDebt, - uint256 currentVariableDebt, - uint256 principalStableDebt, - uint256 scaledVariableDebt, - uint256 stableBorrowRate, - uint256 liquidityRate, - uint40 stableRateLastUpdated, - bool usageAsCollateralEnabled - ); - function getSiloedBorrowing(address asset) external view returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveV3Oracle.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveV3Oracle.sol deleted file mode 100644 index 6d97442..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IAaveV3Oracle.sol +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0 -pragma solidity ^0.8.10; - -import { IPriceOracleGetter } from "./IPriceOracleGetter.sol"; -import { IPoolAddressesProvider } from "./IPoolAddressesProvider.sol"; - -interface IAaveV3Oracle is IPriceOracleGetter { - /** - * @dev Emitted after the base currency is set - * @param baseCurrency The base currency of used for price quotes - * @param baseCurrencyUnit The unit of the base currency - */ - event BaseCurrencySet(address indexed baseCurrency, uint256 baseCurrencyUnit); - - /** - * @dev Emitted after the price source of an asset is updated - * @param asset The address of the asset - * @param source The price source of the asset - */ - event AssetSourceUpdated(address indexed asset, address indexed source); - - /** - * @dev Emitted after the address of fallback oracle is updated - * @param fallbackOracle The address of the fallback oracle - */ - event FallbackOracleUpdated(address indexed fallbackOracle); - - /** - * @notice Returns the PoolAddressesProvider - * @return The address of the PoolAddressesProvider contract - */ - function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider); - - /** - * @notice Sets or replaces price sources of assets - * @param assets The addresses of the assets - * @param sources The addresses of the price sources - */ - function setAssetSources(address[] calldata assets, address[] calldata sources) external; - - /** - * @notice Sets the fallback oracle - * @param fallbackOracle The address of the fallback oracle - */ - function setFallbackOracle(address fallbackOracle) external; - - /** - * @notice Returns a list of prices from a list of assets addresses - * @param assets The list of assets addresses - * @return The prices of the given assets - */ - function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory); - - /** - * @notice Returns the address of the source for an asset address - * @param asset The address of the asset - * @return The address of the source - */ - function getSourceOfAsset(address asset) external view returns (address); - - /** - * @notice Returns the address of the fallback oracle - * @return The address of the fallback oracle - */ - function getFallbackOracle() external view returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IL2PoolV3.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IL2PoolV3.sol deleted file mode 100644 index 1ae63ad..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IL2PoolV3.sol +++ /dev/null @@ -1,140 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0 -import "./IPoolV3.sol"; - -pragma solidity ^0.8.10; - -interface IL2PoolV3 is IPoolV3 { - /** - * @notice Calldata efficient wrapper of the supply function on behalf of the caller - * @param args Arguments for the supply function packed in one bytes32 - * 96 bits 16 bits 128 bits 16 bits - * | 0-padding | referralCode | shortenedAmount | assetId | - * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value - * will be expanded to - * type(uint256).max - * @dev assetId is the index of the asset in the reservesList. - */ - function supply(bytes32 args) external; - - /** - * @notice Calldata efficient wrapper of the supplyWithPermit function on behalf of the caller - * @param args Arguments for the supply function packed in one bytes32 - * 56 bits 8 bits 32 bits 16 bits 128 bits 16 bits - * | 0-padding | permitV | shortenedDeadline | referralCode | shortenedAmount | assetId | - * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value - * will be expanded to - * type(uint256).max - * @dev assetId is the index of the asset in the reservesList. - * @param r The R parameter of ERC712 permit sig - * @param s The S parameter of ERC712 permit sig - */ - function supplyWithPermit(bytes32 args, bytes32 r, bytes32 s) external; - - /** - * @notice Calldata efficient wrapper of the withdraw function, withdrawing to the caller - * @param args Arguments for the withdraw function packed in one bytes32 - * 112 bits 128 bits 16 bits - * | 0-padding | shortenedAmount | assetId | - * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value - * will be expanded to - * type(uint256).max - * @dev assetId is the index of the asset in the reservesList. - */ - function withdraw(bytes32 args) external; - - /** - * @notice Calldata efficient wrapper of the borrow function, borrowing on behalf of the caller - * @param args Arguments for the borrow function packed in one bytes32 - * 88 bits 16 bits 8 bits 128 bits 16 bits - * | 0-padding | referralCode | shortenedInterestRateMode | shortenedAmount | assetId | - * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value - * will be expanded to - * type(uint256).max - * @dev assetId is the index of the asset in the reservesList. - */ - function borrow(bytes32 args) external; - - /** - * @notice Calldata efficient wrapper of the repay function, repaying on behalf of the caller - * @param args Arguments for the repay function packed in one bytes32 - * 104 bits 8 bits 128 bits 16 bits - * | 0-padding | shortenedInterestRateMode | shortenedAmount | assetId | - * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value - * will be expanded to - * type(uint256).max - * @dev assetId is the index of the asset in the reservesList. - * @return The final amount repaid - */ - function repay(bytes32 args) external returns (uint256); - - /** - * @notice Calldata efficient wrapper of the repayWithPermit function, repaying on behalf of the - * caller - * @param args Arguments for the repayWithPermit function packed in one bytes32 - * 64 bits 8 bits 32 bits 8 bits 128 bits 16 - * bits - * | 0-padding | permitV | shortenedDeadline | shortenedInterestRateMode | shortenedAmount | - * assetId | - * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value - * will be expanded to - * type(uint256).max - * @dev assetId is the index of the asset in the reservesList. - * @param r The R parameter of ERC712 permit sig - * @param s The S parameter of ERC712 permit sig - * @return The final amount repaid - */ - function repayWithPermit(bytes32 args, bytes32 r, bytes32 s) external returns (uint256); - - /** - * @notice Calldata efficient wrapper of the repayWithATokens function - * @param args Arguments for the repayWithATokens function packed in one bytes32 - * 104 bits 8 bits 128 bits 16 bits - * | 0-padding | shortenedInterestRateMode | shortenedAmount | assetId | - * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value - * will be expanded to - * type(uint256).max - * @dev assetId is the index of the asset in the reservesList. - * @return The final amount repaid - */ - function repayWithATokens(bytes32 args) external returns (uint256); - - /** - * @notice Calldata efficient wrapper of the swapBorrowRateMode function - * @param args Arguments for the swapBorrowRateMode function packed in one bytes32 - * 232 bits 8 bits 16 bits - * | 0-padding | shortenedInterestRateMode | assetId | - * @dev assetId is the index of the asset in the reservesList. - */ - function swapBorrowRateMode(bytes32 args) external; - - /** - * @notice Calldata efficient wrapper of the rebalanceStableBorrowRate function - * @param args Arguments for the rebalanceStableBorrowRate function packed in one bytes32 - * 80 bits 160 bits 16 bits - * | 0-padding | user address | assetId | - * @dev assetId is the index of the asset in the reservesList. - */ - function rebalanceStableBorrowRate(bytes32 args) external; - - /** - * @notice Calldata efficient wrapper of the setUserUseReserveAsCollateral function - * @param args Arguments for the setUserUseReserveAsCollateral function packed in one bytes32 - * 239 bits 1 bit 16 bits - * | 0-padding | useAsCollateral | assetId | - * @dev assetId is the index of the asset in the reservesList. - */ - function setUserUseReserveAsCollateral(bytes32 args) external; - - /** - * @notice Calldata efficient wrapper of the liquidationCall function - * @param args1 part of the arguments for the liquidationCall function packed in one bytes32 - * 64 bits 160 bits 16 bits 16 bits - * | 0-padding | user address | debtAssetId | collateralAssetId | - * @param args2 part of the arguments for the liquidationCall function packed in one bytes32 - * 127 bits 1 bit 128 bits - * | 0-padding | receiveAToken | shortenedDebtToCover | - * @dev the shortenedDebtToCover is cast to 256 bits at decode time, - * if type(uint128).max the value will be expanded to type(uint256).max - */ - function liquidationCall(bytes32 args1, bytes32 args2) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolAddressesProvider.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolAddressesProvider.sol deleted file mode 100644 index cc8135b..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolAddressesProvider.sol +++ /dev/null @@ -1,229 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0 -pragma solidity ^0.8.10; - -interface IPoolAddressesProvider { - /** - * @dev Emitted when the market identifier is updated. - * @param oldMarketId The old id of the market - * @param newMarketId The new id of the market - */ - event MarketIdSet(string indexed oldMarketId, string indexed newMarketId); - - /** - * @dev Emitted when the pool is updated. - * @param oldAddress The old address of the Pool - * @param newAddress The new address of the Pool - */ - event PoolUpdated(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when the pool configurator is updated. - * @param oldAddress The old address of the PoolConfigurator - * @param newAddress The new address of the PoolConfigurator - */ - event PoolConfiguratorUpdated(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when the price oracle is updated. - * @param oldAddress The old address of the PriceOracle - * @param newAddress The new address of the PriceOracle - */ - event PriceOracleUpdated(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when the ACL manager is updated. - * @param oldAddress The old address of the ACLManager - * @param newAddress The new address of the ACLManager - */ - event ACLManagerUpdated(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when the ACL admin is updated. - * @param oldAddress The old address of the ACLAdmin - * @param newAddress The new address of the ACLAdmin - */ - event ACLAdminUpdated(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when the price oracle sentinel is updated. - * @param oldAddress The old address of the PriceOracleSentinel - * @param newAddress The new address of the PriceOracleSentinel - */ - event PriceOracleSentinelUpdated(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when the pool data provider is updated. - * @param oldAddress The old address of the PoolDataProvider - * @param newAddress The new address of the PoolDataProvider - */ - event PoolDataProviderUpdated(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when a new proxy is created. - * @param id The identifier of the proxy - * @param proxyAddress The address of the created proxy contract - * @param implementationAddress The address of the implementation contract - */ - event ProxyCreated( - bytes32 indexed id, address indexed proxyAddress, address indexed implementationAddress - ); - - /** - * @dev Emitted when a new non-proxied contract address is registered. - * @param id The identifier of the contract - * @param oldAddress The address of the old contract - * @param newAddress The address of the new contract - */ - event AddressSet(bytes32 indexed id, address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when the implementation of the proxy registered with id is updated - * @param id The identifier of the contract - * @param proxyAddress The address of the proxy contract - * @param oldImplementationAddress The address of the old implementation contract - * @param newImplementationAddress The address of the new implementation contract - */ - event AddressSetAsProxy( - bytes32 indexed id, - address indexed proxyAddress, - address oldImplementationAddress, - address indexed newImplementationAddress - ); - - /** - * @notice Returns the id of the Aave market to which this contract points to. - * @return The market id - * - */ - function getMarketId() external view returns (string memory); - - /** - * @notice Associates an id with a specific PoolAddressesProvider. - * @dev This can be used to create an onchain registry of PoolAddressesProviders to - * identify and validate multiple Aave markets. - * @param newMarketId The market id - */ - function setMarketId(string calldata newMarketId) external; - - /** - * @notice Returns an address by its identifier. - * @dev The returned address might be an EOA or a contract, potentially proxied - * @dev It returns ZERO if there is no registered address with the given id - * @param id The id - * @return The address of the registered for the specified id - */ - function getAddress(bytes32 id) external view returns (address); - - /** - * @notice General function to update the implementation of a proxy registered with - * certain `id`. If there is no proxy registered, it will instantiate one and - * set as implementation the `newImplementationAddress`. - * @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit - * setter function, in order to avoid unexpected consequences - * @param id The id - * @param newImplementationAddress The address of the new implementation - */ - function setAddressAsProxy(bytes32 id, address newImplementationAddress) external; - - /** - * @notice Sets an address for an id replacing the address saved in the addresses map. - * @dev IMPORTANT Use this function carefully, as it will do a hard replacement - * @param id The id - * @param newAddress The address to set - */ - function setAddress(bytes32 id, address newAddress) external; - - /** - * @notice Returns the address of the Pool proxy. - * @return The Pool proxy address - * - */ - function getPool() external view returns (address); - - /** - * @notice Updates the implementation of the Pool, or creates a proxy - * setting the new `pool` implementation when the function is called for the first time. - * @param newPoolImpl The new Pool implementation - * - */ - function setPoolImpl(address newPoolImpl) external; - - /** - * @notice Returns the address of the PoolConfigurator proxy. - * @return The PoolConfigurator proxy address - * - */ - function getPoolConfigurator() external view returns (address); - - /** - * @notice Updates the implementation of the PoolConfigurator, or creates a proxy - * setting the new `PoolConfigurator` implementation when the function is called for the first - * time. - * @param newPoolConfiguratorImpl The new PoolConfigurator implementation - * - */ - function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external; - - /** - * @notice Returns the address of the price oracle. - * @return The address of the PriceOracle - */ - function getPriceOracle() external view returns (address); - - /** - * @notice Updates the address of the price oracle. - * @param newPriceOracle The address of the new PriceOracle - */ - function setPriceOracle(address newPriceOracle) external; - - /** - * @notice Returns the address of the ACL manager. - * @return The address of the ACLManager - */ - function getACLManager() external view returns (address); - - /** - * @notice Updates the address of the ACL manager. - * @param newAclManager The address of the new ACLManager - * - */ - function setACLManager(address newAclManager) external; - - /** - * @notice Returns the address of the ACL admin. - * @return The address of the ACL admin - */ - function getACLAdmin() external view returns (address); - - /** - * @notice Updates the address of the ACL admin. - * @param newAclAdmin The address of the new ACL admin - */ - function setACLAdmin(address newAclAdmin) external; - - /** - * @notice Returns the address of the price oracle sentinel. - * @return The address of the PriceOracleSentinel - */ - function getPriceOracleSentinel() external view returns (address); - - /** - * @notice Updates the address of the price oracle sentinel. - * @param newPriceOracleSentinel The address of the new PriceOracleSentinel - * - */ - function setPriceOracleSentinel(address newPriceOracleSentinel) external; - - /** - * @notice Returns the address of the data provider. - * @return The address of the DataProvider - */ - function getPoolDataProvider() external view returns (address); - - /** - * @notice Updates the address of the data provider. - * @param newDataProvider The address of the new DataProvider - * - */ - function setPoolDataProvider(address newDataProvider) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolV3.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolV3.sol deleted file mode 100644 index 847fa5f..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPoolV3.sol +++ /dev/null @@ -1,867 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0 -pragma solidity ^0.8.10; - -import { IPoolAddressesProvider } from "./IPoolAddressesProvider.sol"; -import { DataTypes } from "./DataTypes.sol"; - -interface IPoolV3 { - /** - * @dev Emitted on mintUnbacked() - * @param reserve The address of the underlying asset of the reserve - * @param user The address initiating the supply - * @param onBehalfOf The beneficiary of the supplied assets, receiving the aTokens - * @param amount The amount of supplied assets - * @param referralCode The referral code used - * - */ - event MintUnbacked( - address indexed reserve, - address user, - address indexed onBehalfOf, - uint256 amount, - uint16 indexed referralCode - ); - - /** - * @dev Emitted on backUnbacked() - * @param reserve The address of the underlying asset of the reserve - * @param backer The address paying for the backing - * @param amount The amount added as backing - * @param fee The amount paid in fees - * - */ - event BackUnbacked( - address indexed reserve, address indexed backer, uint256 amount, uint256 fee - ); - - /** - * @dev Emitted on supply() - * @param reserve The address of the underlying asset of the reserve - * @param user The address initiating the supply - * @param onBehalfOf The beneficiary of the supply, receiving the aTokens - * @param amount The amount supplied - * @param referralCode The referral code used - * - */ - event Supply( - address indexed reserve, - address user, - address indexed onBehalfOf, - uint256 amount, - uint16 indexed referralCode - ); - - /** - * @dev Emitted on withdraw() - * @param reserve The address of the underlying asset being withdrawn - * @param user The address initiating the withdrawal, owner of aTokens - * @param to The address that will receive the underlying - * @param amount The amount to be withdrawn - * - */ - event Withdraw( - address indexed reserve, address indexed user, address indexed to, uint256 amount - ); - - /** - * @dev Emitted on borrow() and flashLoan() when debt needs to be opened - * @param reserve The address of the underlying asset being borrowed - * @param user The address of the user initiating the borrow(), receiving the funds on borrow() - * or just - * initiator of the transaction on flashLoan() - * @param onBehalfOf The address that will be getting the debt - * @param amount The amount borrowed out - * @param interestRateMode The rate mode: 1 for Stable, 2 for Variable - * @param borrowRate The numeric rate at which the user has borrowed, expressed in ray - * @param referralCode The referral code used - * - */ - event Borrow( - address indexed reserve, - address user, - address indexed onBehalfOf, - uint256 amount, - DataTypes.InterestRateMode interestRateMode, - uint256 borrowRate, - uint16 indexed referralCode - ); - - /** - * @dev Emitted on repay() - * @param reserve The address of the underlying asset of the reserve - * @param user The beneficiary of the repayment, getting his debt reduced - * @param repayer The address of the user initiating the repay(), providing the funds - * @param amount The amount repaid - * @param useATokens True if the repayment is done using aTokens, `false` if done with - * underlying asset directly - * - */ - event Repay( - address indexed reserve, - address indexed user, - address indexed repayer, - uint256 amount, - bool useATokens - ); - - /** - * @dev Emitted on swapBorrowRateMode() - * @param reserve The address of the underlying asset of the reserve - * @param user The address of the user swapping his rate mode - * @param interestRateMode The current interest rate mode of the position being swapped: 1 for - * Stable, 2 for Variable - * - */ - event SwapBorrowRateMode( - address indexed reserve, address indexed user, DataTypes.InterestRateMode interestRateMode - ); - - /** - * @dev Emitted on borrow(), repay() and liquidationCall() when using isolated assets - * @param asset The address of the underlying asset of the reserve - * @param totalDebt The total isolation mode debt for the reserve - */ - event IsolationModeTotalDebtUpdated(address indexed asset, uint256 totalDebt); - - /** - * @dev Emitted when the user selects a certain asset category for eMode - * @param user The address of the user - * @param categoryId The category id - * - */ - event UserEModeSet(address indexed user, uint8 categoryId); - - /** - * @dev Emitted on setUserUseReserveAsCollateral() - * @param reserve The address of the underlying asset of the reserve - * @param user The address of the user enabling the usage as collateral - * - */ - event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); - - /** - * @dev Emitted on setUserUseReserveAsCollateral() - * @param reserve The address of the underlying asset of the reserve - * @param user The address of the user enabling the usage as collateral - * - */ - event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); - - /** - * @dev Emitted on rebalanceStableBorrowRate() - * @param reserve The address of the underlying asset of the reserve - * @param user The address of the user for which the rebalance has been executed - * - */ - event RebalanceStableBorrowRate(address indexed reserve, address indexed user); - - /** - * @dev Emitted on flashLoan() - * @param target The address of the flash loan receiver contract - * @param initiator The address initiating the flash loan - * @param asset The address of the asset being flash borrowed - * @param amount The amount flash borrowed - * @param interestRateMode The flashloan mode: 0 for regular flashloan, 1 for Stable debt, 2 for - * Variable debt - * @param premium The fee flash borrowed - * @param referralCode The referral code used - * - */ - event FlashLoan( - address indexed target, - address initiator, - address indexed asset, - uint256 amount, - DataTypes.InterestRateMode interestRateMode, - uint256 premium, - uint16 indexed referralCode - ); - - /** - * @dev Emitted when a borrower is liquidated. - * @param collateralAsset The address of the underlying asset used as collateral, to receive as - * result of the liquidation - * @param debtAsset The address of the underlying borrowed asset to be repaid with the - * liquidation - * @param user The address of the borrower getting liquidated - * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover - * @param liquidatedCollateralAmount The amount of collateral received by the liquidator - * @param liquidator The address of the liquidator - * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` - * if he wants - * to receive the underlying collateral asset directly - * - */ - event LiquidationCall( - address indexed collateralAsset, - address indexed debtAsset, - address indexed user, - uint256 debtToCover, - uint256 liquidatedCollateralAmount, - address liquidator, - bool receiveAToken - ); - - /** - * @dev Emitted when the state of a reserve is updated. - * @param reserve The address of the underlying asset of the reserve - * @param liquidityRate The next liquidity rate - * @param stableBorrowRate The next stable borrow rate - * @param variableBorrowRate The next variable borrow rate - * @param liquidityIndex The next liquidity index - * @param variableBorrowIndex The next variable borrow index - * - */ - event ReserveDataUpdated( - address indexed reserve, - uint256 liquidityRate, - uint256 stableBorrowRate, - uint256 variableBorrowRate, - uint256 liquidityIndex, - uint256 variableBorrowIndex - ); - - /** - * @dev Emitted when the protocol treasury receives minted aTokens from the accrued interest. - * @param reserve The address of the reserve - * @param amountMinted The amount minted to the treasury - * - */ - event MintedToTreasury(address indexed reserve, uint256 amountMinted); - - /** - * @dev Mints an `amount` of aTokens to the `onBehalfOf` - * @param asset The address of the underlying asset to mint - * @param amount The amount to mint - * @param onBehalfOf The address that will receive the aTokens - * @param referralCode Code used to register the integrator originating the operation, for - * potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - * - */ - function mintUnbacked( - address asset, - uint256 amount, - address onBehalfOf, - uint16 referralCode - ) - external; - - /** - * @dev Back the current unbacked underlying with `amount` and pay `fee`. - * @param asset The address of the underlying asset to back - * @param amount The amount to back - * @param fee The amount paid in fees - * - */ - function backUnbacked(address asset, uint256 amount, uint256 fee) external; - - /** - * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return - * overlying aTokens. - * - E.g. User supplies 100 USDC and gets in return 100 aUSDC - * @param asset The address of the underlying asset to supply - * @param amount The amount to be supplied - * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user - * wants to receive them on his own wallet, or a different address if the beneficiary of - * aTokens - * is a different wallet - * @param referralCode Code used to register the integrator originating the operation, for - * potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - * - */ - function supply( - address asset, - uint256 amount, - address onBehalfOf, - uint16 referralCode - ) - external; - - /** - * @notice Supply with transfer approval of asset to be supplied done via permit function - * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713 - * @param asset The address of the underlying asset to supply - * @param amount The amount to be supplied - * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user - * wants to receive them on his own wallet, or a different address if the beneficiary of - * aTokens - * is a different wallet - * @param deadline The deadline timestamp that the permit is valid - * @param referralCode Code used to register the integrator originating the operation, for - * potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - * @param permitV The V parameter of ERC712 permit sig - * @param permitR The R parameter of ERC712 permit sig - * @param permitS The S parameter of ERC712 permit sig - * - */ - function supplyWithPermit( - address asset, - uint256 amount, - address onBehalfOf, - uint16 referralCode, - uint256 deadline, - uint8 permitV, - bytes32 permitR, - bytes32 permitS - ) - external; - - /** - * @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent - * aTokens owned - * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC - * @param asset The address of the underlying asset to withdraw - * @param amount The underlying amount to be withdrawn - * - Send the value type(uint256).max in order to withdraw the whole aToken balance - * @param to The address that will receive the underlying, same as msg.sender if the user - * wants to receive it on his own wallet, or a different address if the beneficiary is a - * different wallet - * @return The final amount withdrawn - * - */ - function withdraw(address asset, uint256 amount, address to) external returns (uint256); - - /** - * @notice Allows users to borrow a specific `amount` of the reserve underlying asset, provided - * that the borrower - * already supplied enough collateral, or he was given enough allowance by a credit delegator on - * the - * corresponding debt token (StableDebtToken or VariableDebtToken) - * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC - * in his wallet - * and 100 stable/variable debt tokens, depending on the `interestRateMode` - * @param asset The address of the underlying asset to borrow - * @param amount The amount to be borrowed - * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for - * Stable, 2 for Variable - * @param referralCode The code used to register the integrator originating the operation, for - * potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - * @param onBehalfOf The address of the user who will receive the debt. Should be the address of - * the borrower itself - * calling the function if he wants to borrow against his own collateral, or the address of the - * credit delegator - * if he has been given credit delegation allowance - * - */ - function borrow( - address asset, - uint256 amount, - uint256 interestRateMode, - uint16 referralCode, - address onBehalfOf - ) - external; - - /** - * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens - * owned - * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` - * address - * @param asset The address of the borrowed underlying asset previously borrowed - * @param amount The amount to repay - * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the - * specific `debtMode` - * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for - * Stable, 2 for Variable - * @param onBehalfOf The address of the user who will get his debt reduced/removed. Should be - * the address of the - * user calling the function if he wants to reduce/remove his own debt, or the address of any - * other - * other borrower whose debt should be removed - * @return The final amount repaid - * - */ - function repay( - address asset, - uint256 amount, - uint256 interestRateMode, - address onBehalfOf - ) - external - returns (uint256); - - /** - * @notice Repay with transfer approval of asset to be repaid done via permit function - * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713 - * @param asset The address of the borrowed underlying asset previously borrowed - * @param amount The amount to repay - * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the - * specific `debtMode` - * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for - * Stable, 2 for Variable - * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the - * address of the - * user calling the function if he wants to reduce/remove his own debt, or the address of any - * other - * other borrower whose debt should be removed - * @param deadline The deadline timestamp that the permit is valid - * @param permitV The V parameter of ERC712 permit sig - * @param permitR The R parameter of ERC712 permit sig - * @param permitS The S parameter of ERC712 permit sig - * @return The final amount repaid - * - */ - function repayWithPermit( - address asset, - uint256 amount, - uint256 interestRateMode, - address onBehalfOf, - uint256 deadline, - uint8 permitV, - bytes32 permitR, - bytes32 permitS - ) - external - returns (uint256); - - /** - * @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning - * the - * equivalent debt tokens - * - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable/stable debt tokens - * @dev Passing uint256.max as amount will clean up any residual aToken dust balance, if the - * user aToken - * balance is not enough to cover the whole debt - * @param asset The address of the borrowed underlying asset previously borrowed - * @param amount The amount to repay - * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the - * specific `debtMode` - * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for - * Stable, 2 for Variable - * @return The final amount repaid - * - */ - function repayWithATokens( - address asset, - uint256 amount, - uint256 interestRateMode - ) - external - returns (uint256); - - /** - * @notice Allows a borrower to swap his debt between stable and variable mode, or vice versa - * @param asset The address of the underlying asset borrowed - * @param interestRateMode The current interest rate mode of the position being swapped: 1 for - * Stable, 2 for Variable - * - */ - function swapBorrowRateMode(address asset, uint256 interestRateMode) external; - - /** - * @notice Rebalances the stable interest rate of a user to the current stable rate defined on - * the reserve. - * - Users can be rebalanced if the following conditions are satisfied: - * 1. Usage ratio is above 95% - * 2. the current supply APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which - * means that too - * much has been borrowed at a stable rate and suppliers are not earning enough - * @param asset The address of the underlying asset borrowed - * @param user The address of the user to be rebalanced - * - */ - function rebalanceStableBorrowRate(address asset, address user) external; - - /** - * @notice Allows suppliers to enable/disable a specific supplied asset as collateral - * @param asset The address of the underlying asset supplied - * @param useAsCollateral True if the user wants to use the supply as collateral, false - * otherwise - * - */ - function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external; - - /** - * @notice Function to liquidate a non-healthy position collateral-wise, with Health Factor - * below 1 - * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, - * and receives - * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk - * @param collateralAsset The address of the underlying asset used as collateral, to receive as - * result of the liquidation - * @param debtAsset The address of the underlying borrowed asset to be repaid with the - * liquidation - * @param user The address of the borrower getting liquidated - * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover - * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` - * if he wants - * to receive the underlying collateral asset directly - * - */ - function liquidationCall( - address collateralAsset, - address debtAsset, - address user, - uint256 debtToCover, - bool receiveAToken - ) - external; - - /** - * @notice Allows smartcontracts to access the liquidity of the pool within one transaction, - * as long as the amount taken plus a fee is returned. - * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts - * that must be kept - * into consideration. For further details please visit https://developers.aave.com - * @param receiverAddress The address of the contract receiving the funds, implementing - * IFlashLoanReceiver interface - * @param assets The addresses of the assets being flash-borrowed - * @param amounts The amounts of the assets being flash-borrowed - * @param interestRateModes Types of the debt to open if the flash loan is not returned: - * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver - * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the - * `onBehalfOf` address - * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the - * `onBehalfOf` address - * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 - * or 2 - * @param params Variadic packed params to pass to the receiver as extra information - * @param referralCode The code used to register the integrator originating the operation, for - * potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - * - */ - function flashLoan( - address receiverAddress, - address[] calldata assets, - uint256[] calldata amounts, - uint256[] calldata interestRateModes, - address onBehalfOf, - bytes calldata params, - uint16 referralCode - ) - external; - - /** - * @notice Allows smartcontracts to access the liquidity of the pool within one transaction, - * as long as the amount taken plus a fee is returned. - * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts - * that must be kept - * into consideration. For further details please visit https://developers.aave.com - * @param receiverAddress The address of the contract receiving the funds, implementing - * IFlashLoanSimpleReceiver interface - * @param asset The address of the asset being flash-borrowed - * @param amount The amount of the asset being flash-borrowed - * @param params Variadic packed params to pass to the receiver as extra information - * @param referralCode The code used to register the integrator originating the operation, for - * potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - * - */ - function flashLoanSimple( - address receiverAddress, - address asset, - uint256 amount, - bytes calldata params, - uint16 referralCode - ) - external; - - /** - * @notice Returns the user account data across all the reserves - * @param user The address of the user - * @return totalCollateralBase The total collateral of the user in the base currency used by the - * price feed - * @return totalDebtBase The total debt of the user in the base currency used by the price feed - * @return availableBorrowsBase The borrowing power left of the user in the base currency used - * by the price feed - * @return currentLiquidationThreshold The liquidation threshold of the user - * @return ltv The loan to value of The user - * @return healthFactor The current health factor of the user - * - */ - function getUserAccountData(address user) - external - view - returns ( - uint256 totalCollateralBase, - uint256 totalDebtBase, - uint256 availableBorrowsBase, - uint256 currentLiquidationThreshold, - uint256 ltv, - uint256 healthFactor - ); - - /** - * @notice Initializes a reserve, activating it, assigning an aToken and debt tokens and an - * interest rate strategy - * @dev Only callable by the PoolConfigurator contract - * @param asset The address of the underlying asset of the reserve - * @param aTokenAddress The address of the aToken that will be assigned to the reserve - * @param stableDebtAddress The address of the StableDebtToken that will be assigned to the - * reserve - * @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the - * reserve - * @param interestRateStrategyAddress The address of the interest rate strategy contract - * - */ - function initReserve( - address asset, - address aTokenAddress, - address stableDebtAddress, - address variableDebtAddress, - address interestRateStrategyAddress - ) - external; - - /** - * @notice Drop a reserve - * @dev Only callable by the PoolConfigurator contract - * @param asset The address of the underlying asset of the reserve - * - */ - function dropReserve(address asset) external; - - /** - * @notice Updates the address of the interest rate strategy contract - * @dev Only callable by the PoolConfigurator contract - * @param asset The address of the underlying asset of the reserve - * @param rateStrategyAddress The address of the interest rate strategy contract - * - */ - function setReserveInterestRateStrategyAddress( - address asset, - address rateStrategyAddress - ) - external; - - /** - * @notice Sets the configuration bitmap of the reserve as a whole - * @dev Only callable by the PoolConfigurator contract - * @param asset The address of the underlying asset of the reserve - * @param configuration The new configuration bitmap - * - */ - function setConfiguration( - address asset, - DataTypes.ReserveConfigurationMap calldata configuration - ) - external; - - /** - * @notice Returns the configuration of the reserve - * @param asset The address of the underlying asset of the reserve - * @return The configuration of the reserve - * - */ - function getConfiguration(address asset) - external - view - returns (DataTypes.ReserveConfigurationMap memory); - - /** - * @notice Returns the configuration of the user across all the reserves - * @param user The user address - * @return The configuration of the user - * - */ - function getUserConfiguration(address user) - external - view - returns (DataTypes.UserConfigurationMap memory); - - /** - * @notice Returns the normalized income normalized income of the reserve - * @param asset The address of the underlying asset of the reserve - * @return The reserve's normalized income - */ - function getReserveNormalizedIncome(address asset) external view returns (uint256); - - /** - * @notice Returns the normalized variable debt per unit of asset - * @param asset The address of the underlying asset of the reserve - * @return The reserve normalized variable debt - */ - function getReserveNormalizedVariableDebt(address asset) external view returns (uint256); - - /** - * @notice Returns the state and configuration of the reserve - * @param asset The address of the underlying asset of the reserve - * @return The state and configuration data of the reserve - * - */ - function getReserveData(address asset) external view returns (DataTypes.ReserveData memory); - - /** - * @notice Validates and finalizes an aToken transfer - * @dev Only callable by the overlying aToken of the `asset` - * @param asset The address of the underlying asset of the aToken - * @param from The user from which the aTokens are transferred - * @param to The user receiving the aTokens - * @param amount The amount being transferred/withdrawn - * @param balanceFromBefore The aToken balance of the `from` user before the transfer - * @param balanceToBefore The aToken balance of the `to` user before the transfer - */ - function finalizeTransfer( - address asset, - address from, - address to, - uint256 amount, - uint256 balanceFromBefore, - uint256 balanceToBefore - ) - external; - - /** - * @notice Returns the list of the initialized reserves - * @dev It does not include dropped reserves - * @return The addresses of the reserves - * - */ - function getReservesList() external view returns (address[] memory); - - /** - * @notice Returns the PoolAddressesProvider connected to this contract - * @return The address of the PoolAddressesProvider - * - */ - function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider); - - /** - * @notice Updates the protocol fee on the bridging - * @param bridgeProtocolFee The part of the premium sent to the protocol treasury - */ - function updateBridgeProtocolFee(uint256 bridgeProtocolFee) external; - - /** - * @notice Updates flash loan premiums. Flash loan premium consists of two parts: - * - A part is sent to aToken holders as extra, one time accumulated interest - * - A part is collected by the protocol treasury - * @dev The total premium is calculated on the total borrowed amount - * @dev The premium to protocol is calculated on the total premium, being a percentage of - * `flashLoanPremiumTotal` - * @dev Only callable by the PoolConfigurator contract - * @param flashLoanPremiumTotal The total premium, expressed in bps - * @param flashLoanPremiumToProtocol The part of the premium sent to the protocol treasury, - * expressed in bps - */ - function updateFlashloanPremiums( - uint128 flashLoanPremiumTotal, - uint128 flashLoanPremiumToProtocol - ) - external; - - /** - * @notice Configures a new category for the eMode. - * @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same - * category. - * The category 0 is reserved as it's the default for volatile assets - * @param id The id of the category - * @param config The configuration of the category - */ - function configureEModeCategory(uint8 id, DataTypes.EModeCategory memory config) external; - - /** - * @notice Returns the data of an eMode category - * @param id The id of the category - * @return The configuration data of the category - */ - function getEModeCategoryData(uint8 id) - external - view - returns (DataTypes.EModeCategory memory); - - /** - * @notice Allows a user to use the protocol in eMode - * @param categoryId The id of the category - */ - function setUserEMode(uint8 categoryId) external; - - /** - * @notice Returns the eMode the user is using - * @param user The address of the user - * @return The eMode id - */ - function getUserEMode(address user) external view returns (uint256); - - /** - * @notice Resets the isolation mode total debt of the given asset to zero - * @dev It requires the given asset has zero debt ceiling - * @param asset The address of the underlying asset to reset the isolationModeTotalDebt - */ - function resetIsolationModeTotalDebt(address asset) external; - - /** - * @notice Returns the percentage of available liquidity that can be borrowed at once at stable - * rate - * @return The percentage of available liquidity to borrow, expressed in bps - */ - function MAX_STABLE_RATE_BORROW_SIZE_PERCENT() external view returns (uint256); - - /** - * @notice Returns the total fee on flash loans - * @return The total fee on flashloans - */ - function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128); - - /** - * @notice Returns the part of the bridge fees sent to protocol - * @return The bridge fee sent to the protocol treasury - */ - function BRIDGE_PROTOCOL_FEE() external view returns (uint256); - - /** - * @notice Returns the part of the flashloan fees sent to protocol - * @return The flashloan fee sent to the protocol treasury - */ - function FLASHLOAN_PREMIUM_TO_PROTOCOL() external view returns (uint128); - - /** - * @notice Returns the maximum number of reserves supported to be listed in this Pool - * @return The maximum number of reserves supported - */ - function MAX_NUMBER_RESERVES() external view returns (uint16); - - /** - * @notice Mints the assets accrued through the reserve factor to the treasury in the form of - * aTokens - * @param assets The list of reserves for which the minting needs to be executed - * - */ - function mintToTreasury(address[] calldata assets) external; - - /** - * @notice Rescue and transfer tokens locked in this contract - * @param token The address of the token - * @param to The address of the recipient - * @param amount The amount of token to transfer - */ - function rescueTokens(address token, address to, uint256 amount) external; - - /** - * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return - * overlying aTokens. - * - E.g. User supplies 100 USDC and gets in return 100 aUSDC - * @dev Deprecated: Use the `supply` function instead - * @param asset The address of the underlying asset to supply - * @param amount The amount to be supplied - * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user - * wants to receive them on his own wallet, or a different address if the beneficiary of - * aTokens - * is a different wallet - * @param referralCode Code used to register the integrator originating the operation, for - * potential rewards. - * 0 if the action is executed directly by the user, without any middle-man - * - */ - function deposit( - address asset, - uint256 amount, - address onBehalfOf, - uint16 referralCode - ) - external; - - /** - * @notice Returns the address of the underlying asset of a reserve by the reserve id as stored - * in the DataTypes.ReserveData struct - * @param id The id of the reserve as stored in the DataTypes.ReserveData struct - * @return The address of the reserve associated with id - * - */ - function getReserveAddressById(uint16 id) external view returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleGetter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleGetter.sol deleted file mode 100644 index 51b7652..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleGetter.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0 -pragma solidity ^0.8.10; - -interface IPriceOracleGetter { - /** - * @notice Returns the base currency address - * @dev Address 0x0 is reserved for USD as base currency. - * @return Returns the base currency address. - * - */ - function BASE_CURRENCY() external view returns (address); - - /** - * @notice Returns the base currency unit - * @dev 1 ether for ETH, 1e8 for USD. - * @return Returns the base currency unit. - * - */ - function BASE_CURRENCY_UNIT() external view returns (uint256); - - /** - * @notice Returns the asset price in the base currency - * @param asset The address of the asset - * @return The price of the asset - * - */ - function getAssetPrice(address asset) external view returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleSentinel.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleSentinel.sol deleted file mode 100644 index 5673dc8..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleSentinel.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0 -pragma solidity ^0.8.0; - -interface IPriceOracleSentinel { - /** - * @dev Emitted after the sequencer oracle is updated - * @param newSequencerOracle The new sequencer oracle - */ - event SequencerOracleUpdated(address newSequencerOracle); - - /** - * @dev Emitted after the grace period is updated - * @param newGracePeriod The new grace period value - */ - event GracePeriodUpdated(uint256 newGracePeriod); - - /** - * @notice Returns true if the `borrow` operation is allowed. - * @dev Operation not allowed when PriceOracle is down or grace period not passed. - * @return True if the `borrow` operation is allowed, false otherwise. - */ - function isBorrowAllowed() external view returns (bool); - - /** - * @notice Returns true if the `liquidation` operation is allowed. - * @dev Operation not allowed when PriceOracle is down or grace period not passed. - * @return True if the `liquidation` operation is allowed, false otherwise. - */ - function isLiquidationAllowed() external view returns (bool); - - /** - * @notice Updates the address of the sequencer oracle - * @param newSequencerOracle The address of the new Sequencer Oracle to use - */ - function setSequencerOracle(address newSequencerOracle) external; - - /** - * @notice Updates the duration of the grace period - * @param newGracePeriod The value of the new grace period duration - */ - function setGracePeriod(uint256 newGracePeriod) external; - - /** - * @notice Returns the SequencerOracle - * @return The address of the sequencer oracle contract - */ - function getSequencerOracle() external view returns (address); - - /** - * @notice Returns the grace period - * @return The duration of the grace period - */ - function getGracePeriod() external view returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsController.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsController.sol deleted file mode 100644 index e9f7c73..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsController.sol +++ /dev/null @@ -1,189 +0,0 @@ -// SPDX-License-Identifier: agpl-3.0 -pragma solidity ^0.8.10; - -import { IRewardsDistributor } from "./IRewardsDistributor.sol"; - -interface IRewardsController is IRewardsDistributor { - /** - * @dev Emitted when a new address is whitelisted as claimer of rewards on behalf of a user - * @param user The address of the user - * @param claimer The address of the claimer - */ - event ClaimerSet(address indexed user, address indexed claimer); - - /** - * @dev Emitted when rewards are claimed - * @param user The address of the user rewards has been claimed on behalf of - * @param reward The address of the token reward is claimed - * @param to The address of the receiver of the rewards - * @param claimer The address of the claimer - * @param amount The amount of rewards claimed - */ - event RewardsClaimed( - address indexed user, - address indexed reward, - address indexed to, - address claimer, - uint256 amount - ); - - /** - * @dev Emitted when a transfer strategy is installed for the reward distribution - * @param reward The address of the token reward - * @param transferStrategy The address of TransferStrategy contract - */ - event TransferStrategyInstalled(address indexed reward, address indexed transferStrategy); - - /** - * @dev Emitted when the reward oracle is updated - * @param reward The address of the token reward - * @param rewardOracle The address of oracle - */ - event RewardOracleUpdated(address indexed reward, address indexed rewardOracle); - - /** - * @dev Whitelists an address to claim the rewards on behalf of another address - * @param user The address of the user - * @param claimer The address of the claimer - */ - function setClaimer(address user, address claimer) external; - - /** - * @dev Get the price aggregator oracle address - * @param reward The address of the reward - * @return The price oracle of the reward - */ - function getRewardOracle(address reward) external view returns (address); - - /** - * @dev Returns the whitelisted claimer for a certain address (0x0 if not set) - * @param user The address of the user - * @return The claimer address - */ - function getClaimer(address user) external view returns (address); - - /** - * @dev Returns the Transfer Strategy implementation contract address being used for a reward - * address - * @param reward The address of the reward - * @return The address of the TransferStrategy contract - */ - function getTransferStrategy(address reward) external view returns (address); - - /** - * @dev Called by the corresponding asset on any update that affects the rewards distribution - * @param user The address of the user - * @param userBalance The user balance of the asset - * @param totalSupply The total supply of the asset - * - */ - function handleAction(address user, uint256 userBalance, uint256 totalSupply) external; - - /** - * @dev Claims reward for a user to the desired address, on all the assets of the pool, - * accumulating the pending rewards - * @param assets List of assets to check eligible distributions before claiming rewards - * @param amount The amount of rewards to claim - * @param to The address that will be receiving the rewards - * @param reward The address of the reward token - * @return The amount of rewards claimed - * - */ - function claimRewards( - address[] calldata assets, - uint256 amount, - address to, - address reward - ) - external - returns (uint256); - - /** - * @dev Claims reward for a user on behalf, on all the assets of the pool, accumulating the - * pending rewards. The - * caller must be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager - * @param assets The list of assets to check eligible distributions before claiming rewards - * @param amount The amount of rewards to claim - * @param user The address to check and claim rewards - * @param to The address that will be receiving the rewards - * @param reward The address of the reward token - * @return The amount of rewards claimed - * - */ - function claimRewardsOnBehalf( - address[] calldata assets, - uint256 amount, - address user, - address to, - address reward - ) - external - returns (uint256); - - /** - * @dev Claims reward for msg.sender, on all the assets of the pool, accumulating the pending - * rewards - * @param assets The list of assets to check eligible distributions before claiming rewards - * @param amount The amount of rewards to claim - * @param reward The address of the reward token - * @return The amount of rewards claimed - * - */ - function claimRewardsToSelf( - address[] calldata assets, - uint256 amount, - address reward - ) - external - returns (uint256); - - /** - * @dev Claims all rewards for a user to the desired address, on all the assets of the pool, - * accumulating the pending rewards - * @param assets The list of assets to check eligible distributions before claiming rewards - * @param to The address that will be receiving the rewards - * @return rewardsList List of addresses of the reward tokens - * @return claimedAmounts List that contains the claimed amount per reward, following same order - * as "rewardList" - * - */ - function claimAllRewards( - address[] calldata assets, - address to - ) - external - returns (address[] memory rewardsList, uint256[] memory claimedAmounts); - - /** - * @dev Claims all rewards for a user on behalf, on all the assets of the pool, accumulating the - * pending rewards. The caller must - * be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager - * @param assets The list of assets to check eligible distributions before claiming rewards - * @param user The address to check and claim rewards - * @param to The address that will be receiving the rewards - * @return rewardsList List of addresses of the reward tokens - * @return claimedAmounts List that contains the claimed amount per reward, following same order - * as "rewardsList" - * - */ - function claimAllRewardsOnBehalf( - address[] calldata assets, - address user, - address to - ) - external - returns (address[] memory rewardsList, uint256[] memory claimedAmounts); - - /** - * @dev Claims all reward for msg.sender, on all the assets of the pool, accumulating the - * pending rewards - * @param assets The list of assets to check eligible distributions before claiming rewards - * @return rewardsList List of addresses of the reward tokens - * @return claimedAmounts List that contains the claimed amount per reward, following same order - * as "rewardsList" - * - */ - function claimAllRewardsToSelf(address[] calldata assets) - external - returns (address[] memory rewardsList, uint256[] memory claimedAmounts); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsDistributor.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsDistributor.sol deleted file mode 100644 index 52b4ba1..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/aaveV3/IRewardsDistributor.sol +++ /dev/null @@ -1,201 +0,0 @@ -// SPDX-License-Identifier: agpl-3.0 -pragma solidity ^0.8.10; - -interface IRewardsDistributor { - /** - * @dev Emitted when the configuration of the rewards of an asset is updated. - * @param asset The address of the incentivized asset - * @param reward The address of the reward token - * @param oldEmission The old emissions per second value of the reward distribution - * @param newEmission The new emissions per second value of the reward distribution - * @param oldDistributionEnd The old end timestamp of the reward distribution - * @param newDistributionEnd The new end timestamp of the reward distribution - * @param assetIndex The index of the asset distribution - */ - event AssetConfigUpdated( - address indexed asset, - address indexed reward, - uint256 oldEmission, - uint256 newEmission, - uint256 oldDistributionEnd, - uint256 newDistributionEnd, - uint256 assetIndex - ); - - /** - * @dev Emitted when rewards of an asset are accrued on behalf of a user. - * @param asset The address of the incentivized asset - * @param reward The address of the reward token - * @param user The address of the user that rewards are accrued on behalf of - * @param assetIndex The index of the asset distribution - * @param userIndex The index of the asset distribution on behalf of the user - * @param rewardsAccrued The amount of rewards accrued - */ - event Accrued( - address indexed asset, - address indexed reward, - address indexed user, - uint256 assetIndex, - uint256 userIndex, - uint256 rewardsAccrued - ); - - /** - * @dev Emitted when the emission manager address is updated. - * @param oldEmissionManager The address of the old emission manager - * @param newEmissionManager The address of the new emission manager - */ - event EmissionManagerUpdated( - address indexed oldEmissionManager, address indexed newEmissionManager - ); - - /** - * @dev Sets the end date for the distribution - * @param asset The asset to incentivize - * @param reward The reward token that incentives the asset - * @param newDistributionEnd The end date of the incentivization, in unix time format - * - */ - function setDistributionEnd( - address asset, - address reward, - uint32 newDistributionEnd - ) - external; - - /** - * @dev Sets the emission per second of a set of reward distributions - * @param asset The asset is being incentivized - * @param rewards List of reward addresses are being distributed - * @param newEmissionsPerSecond List of new reward emissions per second - */ - function setEmissionPerSecond( - address asset, - address[] calldata rewards, - uint88[] calldata newEmissionsPerSecond - ) - external; - - /** - * @dev Gets the end date for the distribution - * @param asset The incentivized asset - * @param reward The reward token of the incentivized asset - * @return The timestamp with the end of the distribution, in unix time format - * - */ - function getDistributionEnd(address asset, address reward) external view returns (uint256); - - /** - * @dev Returns the index of a user on a reward distribution - * @param user Address of the user - * @param asset The incentivized asset - * @param reward The reward token of the incentivized asset - * @return The current user asset index, not including new distributions - * - */ - function getUserAssetIndex( - address user, - address asset, - address reward - ) - external - view - returns (uint256); - - /** - * @dev Returns the configuration of the distribution reward for a certain asset - * @param asset The incentivized asset - * @param reward The reward token of the incentivized asset - * @return The index of the asset distribution - * @return The emission per second of the reward distribution - * @return The timestamp of the last update of the index - * @return The timestamp of the distribution end - * - */ - function getRewardsData( - address asset, - address reward - ) - external - view - returns (uint256, uint256, uint256, uint256); - - /** - * @dev Returns the list of available reward token addresses of an incentivized asset - * @param asset The incentivized asset - * @return List of rewards addresses of the input asset - * - */ - function getRewardsByAsset(address asset) external view returns (address[] memory); - - /** - * @dev Returns the list of available reward addresses - * @return List of rewards supported in this contract - * - */ - function getRewardsList() external view returns (address[] memory); - - /** - * @dev Returns the accrued rewards balance of a user, not including virtually accrued rewards - * since last distribution. - * @param user The address of the user - * @param reward The address of the reward token - * @return Unclaimed rewards, not including new distributions - * - */ - function getUserAccruedRewards(address user, address reward) external view returns (uint256); - - /** - * @dev Returns a single rewards balance of a user, including virtually accrued and unrealized - * claimable rewards. - * @param assets List of incentivized assets to check eligible distributions - * @param user The address of the user - * @param reward The address of the reward token - * @return The rewards amount - * - */ - function getUserRewards( - address[] calldata assets, - address user, - address reward - ) - external - view - returns (uint256); - - /** - * @dev Returns a list all rewards of a user, including already accrued and unrealized claimable - * rewards - * @param assets List of incentivized assets to check eligible distributions - * @param user The address of the user - * @return The list of reward addresses - * @return The list of unclaimed amount of rewards - * - */ - function getAllUserRewards( - address[] calldata assets, - address user - ) - external - view - returns (address[] memory, uint256[] memory); - - /** - * @dev Returns the decimals of an asset to calculate the distribution delta - * @param asset The address to retrieve decimals - * @return The decimals of an underlying asset - */ - function getAssetDecimals(address asset) external view returns (uint8); - - /** - * @dev Returns the address of the emission manager - * @return The address of the EmissionManager - */ - function getEmissionManager() external view returns (address); - - /** - * @dev Updates the address of the emission manager - * @param emissionManager The address of the new EmissionManager - */ - function setEmissionManager(address emissionManager) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoanRecipient.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoanRecipient.sol deleted file mode 100644 index d5c07b4..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoanRecipient.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IFlashLoanRecipient { - /** - * @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the - * recipient. - * - * At the time of the call, the Vault will have transferred `amounts` for `tokens` to the - * recipient. Before this - * call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token - * back to the - * Vault, or else the entire flash loan will revert. - * - * `userData` is the same value passed in the `IVault.flashLoan` call. - */ - function receiveFlashLoan( - address[] memory tokens, - uint256[] memory amounts, - uint256[] memory feeAmounts, - bytes memory userData - ) - external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoans.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoans.sol deleted file mode 100644 index 45f70e2..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IFlashLoans.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IFlashLoans { - function flashLoan( - address recipient, - address[] memory tokens, - uint256[] memory amounts, - bytes memory userData - ) - external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IMerkleRedeem.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IMerkleRedeem.sol deleted file mode 100644 index fb2b316..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IMerkleRedeem.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; -pragma experimental ABIEncoderV2; - -interface IMerkleRedeem { - struct Claim { - uint256 week; - uint256 balance; - bytes32[] merkleProof; - } - - function claimWeeks(address _liquidityProvider, Claim[] memory claims) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IPool.sol deleted file mode 100644 index 2b035fc..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IPool.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IPool { - function getPoolId() external view returns (bytes32); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IVault.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IVault.sol deleted file mode 100644 index e293711..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/balancer/IVault.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; -pragma experimental ABIEncoderV2; - -interface IAsset { } - -interface IVault { - function joinPool( - bytes32 poolId, - address sender, - address recipient, - JoinPoolRequest memory request - ) - external - payable; - - struct JoinPoolRequest { - IAsset[] assets; - uint256[] maxAmountsIn; - bytes userData; - bool fromInternalBalance; - } - - function exitPool( - bytes32 poolId, - address sender, - address payable recipient, - ExitPoolRequest memory request - ) - external; - - struct ExitPoolRequest { - IAsset[] assets; - uint256[] minAmountsOut; - bytes userData; - bool toInternalBalance; - } - - function getPoolTokens(bytes32 poolId) - external - view - returns (address[] memory tokens, uint256[] memory balances, uint256 lastChangeBlock); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/bprotocol/IBAMM.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/bprotocol/IBAMM.sol deleted file mode 100644 index c1bd8e0..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/bprotocol/IBAMM.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IBAMM { - function deposit(uint256) external; - function withdraw(uint256) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IAggregatorV3.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IAggregatorV3.sol deleted file mode 100644 index c1df605..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IAggregatorV3.sol +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IAggregatorV3 { - function decimals() external view returns (uint8); - - function description() external view returns (string memory); - - function version() external view returns (uint256); - - // getRoundData and latestRoundData should both raise "No data present" - // if they do not have data to report, instead of returning unset values - // which could be misinterpreted as actual reported values. - function getRoundData(uint80 _roundId) - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - function latestRoundData() - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - function latestAnswer() external view returns (uint256); - - function getTimestamp(uint256 _roundId) external view returns (uint256); - - function phaseId() external view returns (uint16); - - function phaseAggregators(uint16 _phaseId) external view returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IFeedRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IFeedRegistry.sol deleted file mode 100644 index af2dc7a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IFeedRegistry.sol +++ /dev/null @@ -1,183 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IFeedRegistry { - struct Phase { - uint16 phaseId; - uint80 startingAggregatorRoundId; - uint80 endingAggregatorRoundId; - } - - event FeedProposed( - address indexed asset, - address indexed denomination, - address indexed proposedAggregator, - address currentAggregator, - address sender - ); - event FeedConfirmed( - address indexed asset, - address indexed denomination, - address indexed latestAggregator, - address previousAggregator, - uint16 nextPhaseId, - address sender - ); - - // V3 AggregatorV3Interface - - function decimals(address base, address quote) external view returns (uint8); - - function description(address base, address quote) external view returns (string memory); - - function version(address base, address quote) external view returns (uint256); - - function latestRoundData( - address base, - address quote - ) - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - function getRoundData( - address base, - address quote, - uint80 _roundId - ) - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - // V2 AggregatorInterface - - function latestAnswer(address base, address quote) external view returns (int256 answer); - - function latestTimestamp( - address base, - address quote - ) - external - view - returns (uint256 timestamp); - - function latestRound(address base, address quote) external view returns (uint256 roundId); - - function getAnswer( - address base, - address quote, - uint256 roundId - ) - external - view - returns (int256 answer); - - function getTimestamp( - address base, - address quote, - uint256 roundId - ) - external - view - returns (uint256 timestamp); - - function isFeedEnabled(address aggregator) external view returns (bool); - - function getPhase( - address base, - address quote, - uint16 phaseId - ) - external - view - returns (Phase memory phase); - - // Round helpers - - function getPhaseRange( - address base, - address quote, - uint16 phaseId - ) - external - view - returns (uint80 startingRoundId, uint80 endingRoundId); - - function getPreviousRoundId( - address base, - address quote, - uint80 roundId - ) - external - view - returns (uint80 previousRoundId); - - function getNextRoundId( - address base, - address quote, - uint80 roundId - ) - external - view - returns (uint80 nextRoundId); - - // Feed management - - function proposeFeed(address base, address quote, address aggregator) external; - - function confirmFeed(address base, address quote, address aggregator) external; - - // Proposed aggregator - - function proposedGetRoundData( - address base, - address quote, - uint80 roundId - ) - external - view - returns ( - uint80 id, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - function proposedLatestRoundData( - address base, - address quote - ) - external - view - returns ( - uint80 id, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - // Phases - function getCurrentPhaseId( - address base, - address quote - ) - external - view - returns (uint16 currentPhaseId); - - function getFeed(address base, address quote) external view returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IPhaseAggregator.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IPhaseAggregator.sol deleted file mode 100644 index 1a4f7bc..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/chainlink/IPhaseAggregator.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IPhaseAggregator { - function latestRoundData() - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICToken.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICToken.sol deleted file mode 100644 index 3bac54c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICToken.sol +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -import "../IERC20.sol"; - -abstract contract ICToken is IERC20 { - function mint(uint256 mintAmount) external virtual returns (uint256); - function mint() external payable virtual; - - function accrueInterest() public virtual returns (uint256); - - function redeem(uint256 redeemTokens) external virtual returns (uint256); - - function redeemUnderlying(uint256 redeemAmount) external virtual returns (uint256); - - function borrow(uint256 borrowAmount) external virtual returns (uint256); - function borrowIndex() public view virtual returns (uint256); - function borrowBalanceStored(address) public view virtual returns (uint256); - - function repayBorrow(uint256 repayAmount) external virtual returns (uint256); - - function repayBorrow() external payable virtual; - - function repayBorrowBehalf( - address borrower, - uint256 repayAmount - ) - external - virtual - returns (uint256); - - function repayBorrowBehalf(address borrower) external payable virtual; - - function liquidateBorrow( - address borrower, - uint256 repayAmount, - address cTokenCollateral - ) - external - virtual - returns (uint256); - - function liquidateBorrow(address borrower, address cTokenCollateral) external payable virtual; - - function exchangeRateCurrent() external virtual returns (uint256); - - function supplyRatePerBlock() external virtual returns (uint256); - - function borrowRatePerBlock() external virtual returns (uint256); - - function totalReserves() external virtual returns (uint256); - - function reserveFactorMantissa() external virtual returns (uint256); - - function borrowBalanceCurrent(address account) external virtual returns (uint256); - - function totalBorrowsCurrent() external virtual returns (uint256); - - function getCash() external virtual returns (uint256); - - function balanceOfUnderlying(address owner) external virtual returns (uint256); - - function underlying() external virtual returns (address); - - function getAccountSnapshot(address account) - external - view - virtual - returns (uint256, uint256, uint256, uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICompoundOracle.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICompoundOracle.sol deleted file mode 100644 index c7fa324..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/ICompoundOracle.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract ICompoundOracle { - function getUnderlyingPrice(address cToken) external view virtual returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/IComptroller.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/IComptroller.sol deleted file mode 100644 index a6f4699..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compound/IComptroller.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IComptroller { - struct CompMarketState { - uint224 index; - uint32 block; - } - - mapping(address => uint256) public compSpeeds; - - mapping(address => uint256) public borrowCaps; - - mapping(address => uint256) public compBorrowSpeeds; - mapping(address => uint256) public compSupplySpeeds; - - function claimComp(address holder) public virtual; - function claimComp(address holder, address[] memory cTokens) public virtual; - function claimComp( - address[] memory holders, - address[] memory cTokens, - bool borrowers, - bool suppliers - ) - public - virtual; - - function compSupplyState(address) public view virtual returns (CompMarketState memory); - function compSupplierIndex(address, address) public view virtual returns (uint256); - function compAccrued(address) public view virtual returns (uint256); - - function compBorrowState(address) public view virtual returns (CompMarketState memory); - function compBorrowerIndex(address, address) public view virtual returns (uint256); - - function enterMarkets(address[] calldata cTokens) external virtual returns (uint256[] memory); - - function exitMarket(address cToken) external virtual returns (uint256); - - function getAssetsIn(address account) external view virtual returns (address[] memory); - - function markets(address account) public view virtual returns (bool, uint256); - - function getAccountLiquidity(address account) - external - view - virtual - returns (uint256, uint256, uint256); - - function oracle() public view virtual returns (address); - - function mintGuardianPaused(address cToken) external view virtual returns (bool); - function borrowGuardianPaused(address cToken) external view virtual returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/IComet.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/IComet.sol deleted file mode 100644 index ab3c471..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/IComet.sol +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IComet { - struct AssetInfo { - uint8 offset; - address asset; - address priceFeed; - uint64 scale; - uint64 borrowCollateralFactor; - uint64 liquidateCollateralFactor; - uint64 liquidationFactor; - uint128 supplyCap; - } - - struct TotalsCollateral { - uint128 totalSupplyAsset; - uint128 _reserved; - } - - struct UserCollateral { - uint128 balance; - uint128 _reserved; - } - - struct UserBasic { - int104 principal; - uint64 baseTrackingIndex; - uint64 baseTrackingAccrued; - uint16 assetsIn; - uint8 _reserved; - } - - struct TotalsBasic { - uint64 baseSupplyIndex; - uint64 baseBorrowIndex; - uint64 trackingSupplyIndex; - uint64 trackingBorrowIndex; - uint104 totalSupplyBase; - uint104 totalBorrowBase; - uint40 lastAccrualTime; - uint8 pauseFlags; - } - - function totalsBasic() public view virtual returns (TotalsBasic memory); - - function totalsCollateral(address) public virtual returns (TotalsCollateral memory); - - function supply(address asset, uint256 amount) external virtual; - function supplyTo(address dst, address asset, uint256 amount) external virtual; - function supplyFrom( - address from, - address dst, - address asset, - uint256 amount - ) - external - virtual; - - function transfer(address dst, uint256 amount) external virtual returns (bool); - function transferFrom( - address src, - address dst, - uint256 amount - ) - external - virtual - returns (bool); - - function transferAsset(address dst, address asset, uint256 amount) external virtual; - function transferAssetFrom( - address src, - address dst, - address asset, - uint256 amount - ) - external - virtual; - - function withdraw(address asset, uint256 amount) external virtual; - function withdrawTo(address to, address asset, uint256 amount) external virtual; - function withdrawFrom( - address src, - address to, - address asset, - uint256 amount - ) - external - virtual; - - function accrueAccount(address account) external virtual; - function getSupplyRate(uint256 utilization) public view virtual returns (uint64); - function getBorrowRate(uint256 utilization) public view virtual returns (uint64); - function getUtilization() public view virtual returns (uint256); - - function governor() external view virtual returns (address); - function baseToken() external view virtual returns (address); - function baseTokenPriceFeed() external view virtual returns (address); - - function balanceOf(address account) public view virtual returns (uint256); - function collateralBalanceOf( - address account, - address asset - ) - external - view - virtual - returns (uint128); - function borrowBalanceOf(address account) public view virtual returns (uint256); - function totalSupply() external view virtual returns (uint256); - - function numAssets() public view virtual returns (uint8); - function getAssetInfo(uint8 i) public view virtual returns (AssetInfo memory); - function getAssetInfoByAddress(address asset) public view virtual returns (AssetInfo memory); - function getPrice(address priceFeed) public view virtual returns (uint256); - - function allow(address manager, bool isAllowed) external virtual; - function allowance(address owner, address spender) external view virtual returns (uint256); - - function isSupplyPaused() external view virtual returns (bool); - function isTransferPaused() external view virtual returns (bool); - function isWithdrawPaused() external view virtual returns (bool); - function isAbsorbPaused() external view virtual returns (bool); - function baseIndexScale() external pure virtual returns (uint64); - - function userBasic(address) external view virtual returns (UserBasic memory); - function userCollateral( - address, - address - ) - external - view - virtual - returns (UserCollateral memory); - function priceScale() external pure virtual returns (uint64); - function factorScale() external pure virtual returns (uint64); - - function baseBorrowMin() external pure virtual returns (uint256); - function baseTrackingBorrowSpeed() external pure virtual returns (uint256); - function baseTrackingSupplySpeed() external pure virtual returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometExt.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometExt.sol deleted file mode 100644 index 7263313..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometExt.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract ICometExt { - function allow(address manager, bool isAllowed) external virtual; - function collateralBalanceOf( - address account, - address asset - ) - external - view - virtual - returns (uint128); - function allowance(address owner, address spender) external view virtual returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometRewards.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometRewards.sol deleted file mode 100644 index dc71e95..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/compoundV3/ICometRewards.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract ICometRewards { - struct RewardConfig { - address token; - uint64 rescaleFactor; - bool shouldUpscale; - } - - struct RewardOwed { - address token; - uint256 owed; - } - - function rewardConfig(address) external virtual returns (RewardConfig memory); - - function claimTo(address comet, address src, address to, bool shouldAccrue) external virtual; - - function rewardsClaimed( - address _market, - address _user - ) - external - view - virtual - returns (uint256); - function getRewardOwed( - address _market, - address _user - ) - external - virtual - returns (RewardOwed memory); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBaseRewardPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBaseRewardPool.sol deleted file mode 100644 index 842762a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBaseRewardPool.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: SEE LICENSE IN LICENSE -pragma solidity ^0.8.10; - -interface IBaseRewardPool { - function extraRewardsLength() external view returns (uint256); - function extraRewards(uint256) external view returns (address); - - function earned(address) external view returns (uint256); - function balanceOf(address) external view returns (uint256); - - function getReward(address, bool) external returns (bool); - function stakeFor(address, uint256) external; - - function withdraw(uint256, bool) external returns (bool); - function withdrawAndUnwrap(uint256, bool) external returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBooster.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBooster.sol deleted file mode 100644 index c6811df..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IBooster.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: SEE LICENSE IN LICENSE -pragma solidity ^0.8.10; - -interface IBooster { - struct PoolInfo { - address lpToken; - address token; - address gauge; - address crvRewards; - address stash; - bool shutdown; - } - - function poolInfo(uint256) external view returns (PoolInfo memory); - function deposit(uint256, uint256, bool) external returns (bool); - function withdraw(uint256, uint256) external returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IConvexToken.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IConvexToken.sol deleted file mode 100644 index 982c5ce..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IConvexToken.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -import "../../interfaces/IERC20.sol"; - -interface IConvexToken is IERC20 { - function reductionPerCliff() external view returns (uint256); - function totalCliffs() external view returns (uint256); - function maxSupply() external view returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IRewardPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IRewardPool.sol deleted file mode 100644 index 023e762..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/convex/IRewardPool.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IRewardPool { - function rewardToken() external view returns (address); - function earned(address) external view returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IAddressProvider.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IAddressProvider.sol deleted file mode 100644 index 91aee49..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IAddressProvider.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; -pragma experimental ABIEncoderV2; - -interface IAddressProvider { - function admin() external view returns (address); - function get_registry() external view returns (address); - function get_address(uint256 _id) external view returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurve3PoolZap.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurve3PoolZap.sol deleted file mode 100644 index 87a6110..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurve3PoolZap.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface ICurve3PoolZap { - function add_liquidity(address, uint256[4] memory, uint256) external; - function remove_liquidity(address, uint256, uint256[4] memory) external; - function remove_liquidity_one_coin(address, uint256, int128, uint256) external; - function remove_liquidity_imbalance(address, uint256[4] memory, uint256) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurveFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurveFactory.sol deleted file mode 100644 index ce5f462..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ICurveFactory.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface ICurveFactoryLP { - function minter() external view returns (address); - function name() external view returns (string memory); -} - -interface ICurveFactoryPool { - function token() external view returns (address); - function factory() external view returns (address); - function get_virtual_price() external view returns (uint256); -} - -interface ICurveFactory { - function get_coins(address) external view returns (address[2] memory); - function get_decimals(address) external view returns (uint256[2] memory); - function get_balances(address) external view returns (uint256[2] memory); - function get_gauge(address) external view returns (address); -} - -interface IGaugeController { - function gauge_types(address) external view returns (int128); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IDepositZap.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IDepositZap.sol deleted file mode 100644 index cce1e91..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IDepositZap.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IDepositZap { - function pool() external view returns (address); - function curve() external view returns (address); - function token() external view returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IFeeDistributor.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IFeeDistributor.sol deleted file mode 100644 index 89fe0c3..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IFeeDistributor.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; -pragma experimental ABIEncoderV2; - -interface IFeeDistributor { - function claim(address) external returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ILiquidityGauge.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ILiquidityGauge.sol deleted file mode 100644 index 6f72113..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ILiquidityGauge.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; -pragma experimental ABIEncoderV2; - -interface ILiquidityGauge { - function lp_token() external view returns (address); - function balanceOf(address) external view returns (uint256); - - function deposit(uint256 _amount, address _receiver) external; - function approved_to_deposit( - address _depositor, - address _recipient - ) - external - view - returns (bool); - function set_approve_deposit(address _depositor, bool _canDeposit) external; - - function withdraw(uint256 _amount) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IMinter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IMinter.sol deleted file mode 100644 index 5dd0196..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IMinter.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; -pragma experimental ABIEncoderV2; - -interface IMinter { - function mint(address _gaugeAddr) external; - function mint_many(address[8] memory _gaugeAddrs) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IRegistry.sol deleted file mode 100644 index 656efa3..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IRegistry.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IRegistry { - function get_lp_token(address) external view returns (address); - function get_pool_from_lp_token(address) external view returns (address); - function get_pool_name(address) external view returns (string memory); - function get_coins(address) external view returns (address[8] memory); - function get_n_coins(address) external view returns (uint256[2] memory); - function get_underlying_coins(address) external view returns (address[8] memory); - function get_decimals(address) external view returns (uint256[8] memory); - function get_underlying_decimals(address) external view returns (uint256[8] memory); - function get_balances(address) external view returns (uint256[8] memory); - function get_underlying_balances(address) external view returns (uint256[8] memory); - function get_virtual_price_from_lp_token(address) external view returns (uint256); - function get_gauges(address) external view returns (address[10] memory, int128[10] memory); - function pool_count() external view returns (uint256); - function pool_list(uint256) external view returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ISwaps.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ISwaps.sol deleted file mode 100644 index f04a43a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/ISwaps.sol +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; -pragma experimental ABIEncoderV2; - -interface ISwaps { - ///@notice Perform an exchange using the pool that offers the best rate - ///@dev Prior to calling this function, the caller must approve - /// this contract to transfer `_amount` coins from `_from` - /// Does NOT check rates in factory-deployed pools - ///@param _from Address of coin being sent - ///@param _to Address of coin being received - ///@param _amount Quantity of `_from` being sent - ///@param _expected Minimum quantity of `_from` received - /// in order for the transaction to succeed - ///@param _receiver Address to transfer the received tokens to - ///@return uint256 Amount received - function exchange_with_best_rate( - address _from, - address _to, - uint256 _amount, - uint256 _expected, - address _receiver - ) - external - payable - returns (uint256); - - ///@notice Perform an exchange using a specific pool - ///@dev Prior to calling this function, the caller must approve - /// this contract to transfer `_amount` coins from `_from` - /// Works for both regular and factory-deployed pools - ///@param _pool Address of the pool to use for the swap - ///@param _from Address of coin being sent - ///@param _to Address of coin being received - ///@param _amount Quantity of `_from` being sent - ///@param _expected Minimum quantity of `_from` received - /// in order for the transaction to succeed - ///@param _receiver Address to transfer the received tokens to - ///@return uint256 Amount received - function exchange( - address _pool, - address _from, - address _to, - uint256 _amount, - uint256 _expected, - address _receiver - ) - external - payable - returns (uint256); - - ///@notice Find the pool offering the best rate for a given swap. - ///@dev Checks rates for regular and factory pools - ///@param _from Address of coin being sent - ///@param _to Address of coin being received - ///@param _amount Quantity of `_from` being sent - ///@param _exclude_pools A list of up to 8 addresses which shouldn't be returned - ///@return Pool address, amount received - function get_best_rate( - address _from, - address _to, - uint256 _amount, - address[8] memory _exclude_pools - ) - external - view - returns (address, uint256); - - ///@notice Get the current number of coins received in an exchange - ///@dev Works for both regular and factory-deployed pools - ///@param _pool Pool address - ///@param _from Address of coin to be sent - ///@param _to Address of coin to be received - ///@param _amount Quantity of `_from` to be sent - ///@return Quantity of `_to` to be received - function get_exchange_amount( - address _pool, - address _from, - address _to, - uint256 _amount - ) - external - view - returns (uint256); - - ///@notice Get the current number of coins required to receive the given amount in an exchange - ///@param _pool Pool address - ///@param _from Address of coin to be sent - ///@param _to Address of coin to be received - ///@param _amount Quantity of `_to` to be received - ///@return Quantity of `_from` to be sent - function get_input_amount( - address _pool, - address _from, - address _to, - uint256 _amount - ) - external - view - returns (uint256); - - ///@notice Get the current number of coins required to receive the given amount in an exchange - ///@param _pool Pool address - ///@param _from Address of coin to be sent - ///@param _to Address of coin to be received - ///@param _amounts Quantity of `_to` to be received - ///@return Quantity of `_from` to be sent - function get_exchange_amounts( - address _pool, - address _from, - address _to, - uint256[] memory _amounts - ) - external - view - returns (uint256[] memory); - - ///@notice Set calculator contract - ///@dev Used to calculate `get_dy` for a pool - ///@param _pool Pool address - ///@return `CurveCalc` address - function get_calculator(address _pool) external view returns (address); - - /// @notice Perform up to four swaps in a single transaction - /// @dev Routing and swap params must be determined off-chain. This - /// functionality is designed for gas efficiency over ease-of-use. - /// @param _route Array of [initial token, pool, token, pool, token, ...] - /// The array is iterated until a pool address of 0x00, then the last - /// given token is transferred to `_receiver` - /// @param _swap_params Multidimensional array of [i, j, swap type] where i and j are the - /// correct - /// values for the n'th pool in `_route`. The swap type should be 1 for - /// a stableswap `exchange`, 2 for stableswap `exchange_underlying`, 3 - /// for a cryptoswap `exchange`, 4 for a cryptoswap `exchange_underlying`, - /// 5 for Polygon factory metapools `exchange_underlying`, 6-8 for - /// underlying coin -> LP token "exchange" (actually `add_liquidity`), 9 and 10 - /// for LP token -> underlying coin "exchange" (actually `remove_liquidity_one_coin`) - /// @param _amount The amount of `_route[0]` token being sent. - /// @param _expected The minimum amount received after the final swap. - /// @param _pools Array of pools for swaps via zap contracts. This parameter is only needed for - /// Polygon meta-factories underlying swaps. - /// @param _receiver Address to transfer the final output token to. - /// @return Received amount of the final output token - function exchange_multiple( - address[9] memory _route, - uint256[3][4] memory _swap_params, - uint256 _amount, - uint256 _expected, - address[4] memory _pools, - address _receiver - ) - external - payable - returns (uint256); - - function exchange_multiple( - address[9] memory _route, - uint256[3][4] memory _swap_params, - uint256 _amount, - uint256 _expected - ) - external - payable - returns (uint256); - - function get_exchange_multiple_amount( - address[9] memory _route, - uint256[3][4] memory _swap_params, - uint256 _amount - ) - external - view - returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IVotingEscrow.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IVotingEscrow.sol deleted file mode 100644 index b46d15e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/IVotingEscrow.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; -pragma experimental ABIEncoderV2; - -interface IVotingEscrow { - function create_lock(uint256 _amount, uint256 _unlockTime) external; - function increase_amount(uint256 _amount) external; - function increase_unlock_time(uint256 _unlockTime) external; - function withdraw() external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/stethPool/ICurveStethPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/stethPool/ICurveStethPool.sol deleted file mode 100644 index 92fcabd..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curve/stethPool/ICurveStethPool.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface ICurveStethPool { - function add_liquidity(uint256[2] memory, uint256) external payable returns (uint256); - function remove_liquidity(uint256, uint256[2] memory) external returns (uint256[2] memory); - function remove_liquidity_imbalance(uint256[2] memory, uint256) external returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curveusd/ICurveUsd.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curveusd/ICurveUsd.sol deleted file mode 100644 index cf8564a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/curveusd/ICurveUsd.sol +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface ICrvUsdController { - function create_loan( - uint256 _collateralAmount, - uint256 _debtAmount, - uint256 _nBands - ) - external - payable; - function create_loan_extended( - uint256 _collateralAmount, - uint256 _debtAmount, - uint256 _nBands, - address _callbacker, - uint256[] memory _callbackArgs - ) - external - payable; - - /// @dev all functions below: if _collateralAmount is 0 will just return - function add_collateral(uint256 _collateralAmount) external payable; - function add_collateral(uint256 _collateralAmount, address _for) external payable; - - function remove_collateral(uint256 _collateralAmount) external; - /// @param _useEth relevant only for ETH collateral pools (currently not deployed) - function remove_collateral(uint256 _collateralAmount, bool _useEth) external; - - /// @dev all functions below: if _debtAmount is 0 will just return - function borrow_more(uint256 _collateralAmount, uint256 _debtAmount) external payable; - - /// @dev if _debtAmount > debt will do full repay - function repay(uint256 _debtAmount) external payable; - function repay(uint256 _debtAmount, address _for) external payable; - /// @param _maxActiveBand Don't allow active band to be higher than this (to prevent - /// front-running the repay) - function repay(uint256 _debtAmount, address _for, int256 _maxActiveBand) external payable; - function repay( - uint256 _debtAmount, - address _for, - int256 _maxActiveBand, - bool _useEth - ) - external - payable; - function repay_extended(address _callbacker, uint256[] memory _callbackArgs) external; - - function liquidate(address user, uint256 min_x) external; - function liquidate(address user, uint256 min_x, bool _useEth) external; - function liquidate_extended( - address user, - uint256 min_x, - uint256 frac, - bool use_eth, - address callbacker, - uint256[] memory _callbackArgs - ) - external; - - /// GETTERS - function amm() external view returns (address); - function monetary_policy() external view returns (address); - function collateral_token() external view returns (address); - function debt(address) external view returns (uint256); - function total_debt() external view returns (uint256); - function health_calculator( - address, - int256, - int256, - bool, - uint256 - ) - external - view - returns (int256); - function health_calculator(address, int256, int256, bool) external view returns (int256); - function health(address) external view returns (int256); - function health(address, bool) external view returns (int256); - function max_borrowable( - uint256 collateralAmount, - uint256 nBands - ) - external - view - returns (uint256); - function min_collateral(uint256 debtAmount, uint256 nBands) external view returns (uint256); - function calculate_debt_n1(uint256, uint256, uint256) external view returns (int256); - function minted() external view returns (uint256); - function redeemed() external view returns (uint256); - function amm_price() external view returns (uint256); - function user_state(address) external view returns (uint256[4] memory); - function user_prices(address) external view returns (uint256[2] memory); - function loan_exists(address) external view returns (bool); - function liquidation_discount() external view returns (uint256); -} - -interface ICrvUsdControllerFactory { - function get_controller(address) external view returns (address); - function debt_ceiling(address) external view returns (uint256); -} - -interface ILLAMMA { - function active_band_with_skip() external view returns (int256); - function get_sum_xy(address) external view returns (uint256[2] memory); - function get_xy(address) external view returns (uint256[][2] memory); - function get_p() external view returns (uint256); - function read_user_tick_numbers(address) external view returns (int256[2] memory); - function p_oracle_up(int256) external view returns (uint256); - function p_oracle_down(int256) external view returns (uint256); - function p_current_up(int256) external view returns (uint256); - function p_current_down(int256) external view returns (uint256); - function bands_x(int256) external view returns (uint256); - function bands_y(int256) external view returns (uint256); - function get_base_price() external view returns (uint256); - function price_oracle() external view returns (uint256); - function active_band() external view returns (int256); - function A() external view returns (uint256); - function min_band() external view returns (int256); - function max_band() external view returns (int256); - function rate() external view returns (uint256); - function exchange( - uint256 i, - uint256 j, - uint256 in_amount, - uint256 min_amount - ) - external - returns (uint256[2] memory); - function coins(uint256 i) external view returns (address); - function user_state(address _user) external view returns (uint256[4] memory); -} - -interface IAGG { - function rate() external view returns (uint256); - function rate0() external view returns (uint256); - function target_debt_fraction() external view returns (uint256); - function sigma() external view returns (int256); - function peg_keepers(uint256) external view returns (address); -} - -interface IPegKeeper { - function debt() external view returns (uint256); -} - -interface ICurveUsdSwapper { - function encodeSwapParams( - uint256[3][4] memory swapParams, - uint32 gasUsed, - uint32 dfsFeeDivider, - uint8 useSteth - ) - external - pure - returns (uint256 encoded); - function setAdditionalRoutes(address[6] memory _additionalRoutes) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/dydx/ISoloMargin.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/dydx/ISoloMargin.sol deleted file mode 100644 index f0eab06..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/dydx/ISoloMargin.sol +++ /dev/null @@ -1,463 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -pragma solidity ^0.8.10; - -library Account { - enum Status { - Normal, - Liquid, - Vapor - } - - struct Info { - address owner; // The address that owns the account - uint256 number; // A nonce that allows a single address to control many accounts - } - - struct Storage { - mapping(uint256 => Types.Par) balances; // Mapping from marketId to principal - Status status; - } -} - -library Actions { - enum ActionType { - Deposit, // supply tokens - Withdraw, // borrow tokens - Transfer, // transfer balance between accounts - Buy, // buy an amount of some token (public virtually) - Sell, // sell an amount of some token (public virtually) - Trade, // trade tokens against another account - Liquidate, // liquidate an undercollateralized or expiring account - Vaporize, // use excess tokens to zero-out a completely negative account - Call // send arbitrary data to an address - - } - - enum AccountLayout { - OnePrimary, - TwoPrimary, - PrimaryAndSecondary - } - - enum MarketLayout { - ZeroMarkets, - OneMarket, - TwoMarkets - } - - struct ActionArgs { - ActionType actionType; - uint256 accountId; - Types.AssetAmount amount; - uint256 primaryMarketId; - uint256 secondaryMarketId; - address otherAddress; - uint256 otherAccountId; - bytes data; - } - - struct DepositArgs { - Types.AssetAmount amount; - Account.Info account; - uint256 market; - address from; - } - - struct WithdrawArgs { - Types.AssetAmount amount; - Account.Info account; - uint256 market; - address to; - } - - struct TransferArgs { - Types.AssetAmount amount; - Account.Info accountOne; - Account.Info accountTwo; - uint256 market; - } - - struct BuyArgs { - Types.AssetAmount amount; - Account.Info account; - uint256 makerMarket; - uint256 takerMarket; - address exchangeWrapper; - bytes orderData; - } - - struct SellArgs { - Types.AssetAmount amount; - Account.Info account; - uint256 takerMarket; - uint256 makerMarket; - address exchangeWrapper; - bytes orderData; - } - - struct TradeArgs { - Types.AssetAmount amount; - Account.Info takerAccount; - Account.Info makerAccount; - uint256 inputMarket; - uint256 outputMarket; - address autoTrader; - bytes tradeData; - } - - struct LiquidateArgs { - Types.AssetAmount amount; - Account.Info solidAccount; - Account.Info liquidAccount; - uint256 owedMarket; - uint256 heldMarket; - } - - struct VaporizeArgs { - Types.AssetAmount amount; - Account.Info solidAccount; - Account.Info vaporAccount; - uint256 owedMarket; - uint256 heldMarket; - } - - struct CallArgs { - Account.Info account; - address callee; - bytes data; - } -} - -library Decimal { - struct D256 { - uint256 value; - } -} - -library Interest { - struct Rate { - uint256 value; - } - - struct Index { - uint96 borrow; - uint96 supply; - uint32 lastUpdate; - } -} - -library Monetary { - struct Price { - uint256 value; - } - - struct Value { - uint256 value; - } -} - -library Storage { - // All information necessary for tracking a market - struct Market { - // Contract address of the associated ERC20 token - address token; - // Total aggregated supply and borrow amount of the entire market - Types.TotalPar totalPar; - // Interest index of the market - Interest.Index index; - // Contract address of the price oracle for this market - address priceOracle; - // Contract address of the interest setter for this market - address interestSetter; - // Multiplier on the marginRatio for this market - Decimal.D256 marginPremium; - // Multiplier on the liquidationSpread for this market - Decimal.D256 spreadPremium; - // Whether additional borrows are allowed for this market - bool isClosing; - } - - // The global risk parameters that govern the health and security of the system - struct RiskParams { - // Required ratio of over-collateralization - Decimal.D256 marginRatio; - // Percentage penalty incurred by liquidated accounts - Decimal.D256 liquidationSpread; - // Percentage of the borrower's interest fee that gets passed to the suppliers - Decimal.D256 earningsRate; - // The minimum absolute borrow value of an account - // There must be sufficient incentivize to liquidate undercollateralized accounts - Monetary.Value minBorrowedValue; - } - - // The maximum RiskParam values that can be set - struct RiskLimits { - uint64 marginRatioMax; - uint64 liquidationSpreadMax; - uint64 earningsRateMax; - uint64 marginPremiumMax; - uint64 spreadPremiumMax; - uint128 minBorrowedValueMax; - } - - // The entire storage state of Solo - struct State { - // number of markets - uint256 numMarkets; - // marketId => Market - mapping(uint256 => Market) markets; - // owner => account number => Account - mapping(address => mapping(uint256 => Account.Storage)) accounts; - // Addresses that can control other users accounts - mapping(address => mapping(address => bool)) operators; - // Addresses that can control all users accounts - mapping(address => bool) globalOperators; - // mutable risk parameters of the system - RiskParams riskParams; - // immutable risk limits of the system - RiskLimits riskLimits; - } -} - -library Types { - enum AssetDenomination { - Wei, // the amount is denominated in wei - Par // the amount is denominated in par - - } - - enum AssetReference { - Delta, // the amount is given as a delta from the current value - Target // the amount is given as an exact number to end up at - - } - - struct AssetAmount { - bool sign; // true if positive - AssetDenomination denomination; - AssetReference ref; - uint256 value; - } - - struct TotalPar { - uint128 borrow; - uint128 supply; - } - - struct Par { - bool sign; // true if positive - uint128 value; - } - - struct Wei { - bool sign; // true if positive - uint256 value; - } -} - -abstract contract ISoloMargin { - struct OperatorArg { - address operator; - bool trusted; - } - - function ownerSetSpreadPremium( - uint256 marketId, - Decimal.D256 memory spreadPremium - ) - public - virtual; - - function getIsGlobalOperator(address operator) public view virtual returns (bool); - - function getMarketTokenAddress(uint256 marketId) public view virtual returns (address); - - function ownerSetInterestSetter(uint256 marketId, address interestSetter) public virtual; - - function getAccountValues(Account.Info memory account) - public - view - virtual - returns (Monetary.Value memory, Monetary.Value memory); - - function getMarketPriceOracle(uint256 marketId) public view virtual returns (address); - - function getMarketInterestSetter(uint256 marketId) public view virtual returns (address); - - function getMarketSpreadPremium(uint256 marketId) - public - view - virtual - returns (Decimal.D256 memory); - - function getNumMarkets() public view virtual returns (uint256); - - function ownerWithdrawUnsupportedTokens( - address token, - address recipient - ) - public - virtual - returns (uint256); - - function ownerSetMinBorrowedValue(Monetary.Value memory minBorrowedValue) public virtual; - - function ownerSetLiquidationSpread(Decimal.D256 memory spread) public virtual; - - function ownerSetEarningsRate(Decimal.D256 memory earningsRate) public virtual; - - function getIsLocalOperator(address, address) public view virtual returns (bool); - - function getAccountPar( - Account.Info memory account, - uint256 marketId - ) - public - view - virtual - returns (Types.Par memory); - - function ownerSetMarginPremium( - uint256 marketId, - Decimal.D256 memory marginPremium - ) - public - virtual; - - function getMarginRatio() public view virtual returns (Decimal.D256 memory); - - function getMarketCurrentIndex(uint256 marketId) - public - view - virtual - returns (Interest.Index memory); - - function getMarketIsClosing(uint256 marketId) public view virtual returns (bool); - - function getRiskParams() public view virtual returns (Storage.RiskParams memory); - - function getAccountBalances(Account.Info memory account) - public - view - virtual - returns (address[] memory, Types.Par[] memory, Types.Wei[] memory); - - function renounceOwnership() public virtual; - - function getMinBorrowedValue() public view virtual returns (Monetary.Value memory); - - function setOperators(OperatorArg[] memory args) public virtual; - - function getMarketPrice(uint256 marketId) public view virtual returns (address); - - function owner() public view virtual returns (address); - - function isOwner() public view virtual returns (bool); - - function ownerWithdrawExcessTokens( - uint256 marketId, - address recipient - ) - public - virtual - returns (uint256); - - function ownerAddMarket( - address token, - address priceOracle, - address interestSetter, - Decimal.D256 memory marginPremium, - Decimal.D256 memory spreadPremium - ) - public - virtual; - - function operate( - Account.Info[] memory accounts, - Actions.ActionArgs[] memory actions - ) - public - virtual; - - function getMarketWithInfo(uint256 marketId) - public - view - virtual - returns ( - Storage.Market memory, - Interest.Index memory, - Monetary.Price memory, - Interest.Rate memory - ); - - function ownerSetMarginRatio(Decimal.D256 memory ratio) public virtual; - - function getLiquidationSpread() public view virtual returns (Decimal.D256 memory); - - function getAccountWei( - Account.Info memory account, - uint256 marketId - ) - public - view - virtual - returns (Types.Wei memory); - - function getMarketTotalPar(uint256 marketId) - public - view - virtual - returns (Types.TotalPar memory); - - function getLiquidationSpreadForPair( - uint256 heldMarketId, - uint256 owedMarketId - ) - public - view - virtual - returns (Decimal.D256 memory); - - function getNumExcessTokens(uint256 marketId) public view virtual returns (Types.Wei memory); - - function getMarketCachedIndex(uint256 marketId) - public - view - virtual - returns (Interest.Index memory); - - function getAccountStatus(Account.Info memory account) public view virtual returns (uint8); - - function getEarningsRate() public view virtual returns (Decimal.D256 memory); - - function ownerSetPriceOracle(uint256 marketId, address priceOracle) public virtual; - - function getRiskLimits() public view virtual returns (Storage.RiskLimits memory); - - function getMarket(uint256 marketId) public view virtual returns (Storage.Market memory); - - function ownerSetIsClosing(uint256 marketId, bool isClosing) public virtual; - - function ownerSetGlobalOperator(address operator, bool approved) public virtual; - - function transferOwnership(address newOwner) public virtual; - - function getAdjustedAccountValues(Account.Info memory account) - public - view - virtual - returns (Monetary.Value memory, Monetary.Value memory); - - function getMarketMarginPremium(uint256 marketId) - public - view - virtual - returns (Decimal.D256 memory); - - function getMarketInterestRate(uint256 marketId) - public - view - virtual - returns (Interest.Rate memory); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IDToken.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IDToken.sol deleted file mode 100644 index 9002e84..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IDToken.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IDToken { - function flashLoan(uint256 amount, bytes calldata data) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IEulerMarkets.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IEulerMarkets.sol deleted file mode 100644 index dc22050..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/euler/IEulerMarkets.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IEulerMarkets { - function underlyingToDToken(address underlying) external view returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeV3.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeV3.sol deleted file mode 100644 index a355aee..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeV3.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface IExchangeV3 { - function sell( - address _srcAddr, - address _destAddr, - uint256 _srcAmount, - bytes memory _additionalData - ) - external - returns (uint256); - - function buy( - address _srcAddr, - address _destAddr, - uint256 _destAmount, - bytes memory _additionalData - ) - external - returns (uint256); - - function getSellRate( - address _srcAddr, - address _destAddr, - uint256 _srcAmount, - bytes memory _additionalData - ) - external - returns (uint256); - - function getBuyRate( - address _srcAddr, - address _destAddr, - uint256 _srcAmount, - bytes memory _additionalData - ) - external - returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeWrapper.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeWrapper.sol deleted file mode 100644 index cfa9538..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IExchangeWrapper.sol +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface IExchangeWrapper { - function sell( - address _srcAddr, - address _destAddr, - uint256 _srcAmount, - bytes memory _additionalData - ) - external - payable - returns (uint256); - - function buy( - address _srcAddr, - address _destAddr, - uint256 _destAmount, - bytes memory _additionalData - ) - external - payable - returns (uint256); - - function getSellRate( - address _srcAddr, - address _destAddr, - uint256 _srcAmount, - bytes memory _additionalData - ) - external - view - returns (uint256); - - function getBuyRate( - address _srcAddr, - address _destAddr, - uint256 _srcAmount, - bytes memory _additionalData - ) - external - view - returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IKyberNetworkProxy.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IKyberNetworkProxy.sol deleted file mode 100644 index 385f8a6..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IKyberNetworkProxy.sol +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -import "../IERC20.sol"; - -abstract contract KyberNetworkProxyInterface { - function maxGasPrice() external view virtual returns (uint256); - - function getUserCapInWei(address user) external view virtual returns (uint256); - - function getUserCapInTokenWei( - address user, - IERC20 token - ) - external - view - virtual - returns (uint256); - - function enabled() external view virtual returns (bool); - - function info(bytes32 id) external view virtual returns (uint256); - - function getExpectedRate( - IERC20 src, - IERC20 dest, - uint256 srcQty - ) - public - view - virtual - returns (uint256 expectedRate, uint256 slippageRate); - - function tradeWithHint( - IERC20 src, - uint256 srcAmount, - IERC20 dest, - address destAddress, - uint256 maxDestAmount, - uint256 minConversionRate, - address walletId, - bytes memory hint - ) - public - payable - virtual - returns (uint256); - - function trade( - IERC20 src, - uint256 srcAmount, - IERC20 dest, - address destAddress, - uint256 maxDestAmount, - uint256 minConversionRate, - address walletId - ) - public - payable - virtual - returns (uint256); - - function swapEtherToToken( - IERC20 token, - uint256 minConversionRate - ) - external - payable - virtual - returns (uint256); - - function swapTokenToEther( - IERC20 token, - uint256 tokenQty, - uint256 minRate - ) - external - payable - virtual - returns (uint256); - - function swapTokenToToken( - IERC20 src, - uint256 srcAmount, - IERC20 dest, - uint256 minConversionRate - ) - public - virtual - returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOasis.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOasis.sol deleted file mode 100644 index e96ee2a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOasis.sol +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IOasis { - function getBuyAmount( - address tokenToBuy, - address tokenToPay, - uint256 amountToPay - ) - external - view - virtual - returns (uint256 amountBought); - - function getPayAmount( - address tokenToPay, - address tokenToBuy, - uint256 amountToBuy - ) - public - view - virtual - returns (uint256 amountPaid); - - function sellAllAmount( - address pay_gem, - uint256 pay_amt, - address buy_gem, - uint256 min_fill_amount - ) - public - virtual - returns (uint256 fill_amt); - - function buyAllAmount( - address buy_gem, - uint256 buy_amt, - address pay_gem, - uint256 max_fill_amount - ) - public - virtual - returns (uint256 fill_amt); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOffchainWrapper.sol.bak b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOffchainWrapper.sol.bak deleted file mode 100644 index c23b913..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IOffchainWrapper.sol.bak +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -import "../../exchangeV3/DFSExchangeData.sol"; - -abstract contract IOffchainWrapper is DFSExchangeData { - function takeOrder( - ExchangeData memory _exData, - ExchangeActionType _type - ) - public - payable - virtual - returns (bool success, uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IPair.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IPair.sol deleted file mode 100644 index ca0102b..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IPair.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -import "../IERC20.sol"; - -abstract contract IPair is IERC20 { - function token0() external view virtual returns (address); - function token1() external view virtual returns (address); - function getReserves() - external - view - virtual - returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); - function price0CumulativeLast() external view virtual returns (uint256); - function price1CumulativeLast() external view virtual returns (uint256); - function kLast() external view virtual returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IQuoter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IQuoter.sol deleted file mode 100644 index a559f3c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IQuoter.sol +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.8.10; - -/// @title Quoter Interface -/// @notice Supports quoting the calculated amounts from exact input or exact output swaps -/// @dev These functions are not marked view because they rely on calling non-view functions and -/// reverting -/// to compute the result. They are also not gas efficient and should not be called on-chain. -interface IQuoter { - /// @notice Returns the amount out received for a given exact input swap without executing the - /// swap - /// @param path The path of the swap, i.e. each token pair and the pool fee - /// @param amountIn The amount of the first token to swap - /// @return amountOut The amount of the last token that would be received - function quoteExactInput( - bytes memory path, - uint256 amountIn - ) - external - returns (uint256 amountOut); - - /// @notice Returns the amount out received for a given exact input but for a swap of a single - /// pool - /// @param tokenIn The token being swapped in - /// @param tokenOut The token being swapped out - /// @param fee The fee of the token pool to consider for the pair - /// @param amountIn The desired input amount - /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap - /// @return amountOut The amount of `tokenOut` that would be received - function quoteExactInputSingle( - address tokenIn, - address tokenOut, - uint24 fee, - uint256 amountIn, - uint160 sqrtPriceLimitX96 - ) - external - returns (uint256 amountOut); - - /// @notice Returns the amount in required for a given exact output swap without executing the - /// swap - /// @param path The path of the swap, i.e. each token pair and the pool fee - /// @param amountOut The amount of the last token to receive - /// @return amountIn The amount of first token required to be paid - function quoteExactOutput( - bytes memory path, - uint256 amountOut - ) - external - returns (uint256 amountIn); - - /// @notice Returns the amount in required to receive the given exact output amount but for a - /// swap of a single pool - /// @param tokenIn The token being swapped in - /// @param tokenOut The token being swapped out - /// @param fee The fee of the token pool to consider for the pair - /// @param amountOut The desired output amount - /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap - /// @return amountIn The amount required as the input for the swap in order to receive - /// `amountOut` - function quoteExactOutputSingle( - address tokenIn, - address tokenOut, - uint24 fee, - uint256 amountOut, - uint160 sqrtPriceLimitX96 - ) - external - returns (uint256 amountIn); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/ISwapRouter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/ISwapRouter.sol deleted file mode 100644 index c00309a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/ISwapRouter.sol +++ /dev/null @@ -1,105 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.8.10; - -/// @title Callback for IUniswapV3PoolActions#swap -/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface -interface IUniswapV3SwapCallback { - /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. - /// @dev In the implementation you must pay the pool tokens owed for the swap. - /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical - /// UniswapV3Factory. - /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. - /// @param amount0Delta The amount of token0 that was sent (negative) or must be received - /// (positive) by the pool by - /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. - /// @param amount1Delta The amount of token1 that was sent (negative) or must be received - /// (positive) by the pool by - /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. - /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call - function uniswapV3SwapCallback( - int256 amount0Delta, - int256 amount1Delta, - bytes calldata data - ) - external; -} - -/// @title Router token swapping functionality -/// @notice Functions for swapping tokens via Uniswap V3 -interface ISwapRouter is IUniswapV3SwapCallback { - struct ExactInputSingleParams { - address tokenIn; - address tokenOut; - uint24 fee; - address recipient; - uint256 deadline; - uint256 amountIn; - uint256 amountOutMinimum; - uint160 sqrtPriceLimitX96; - } - - /// @notice Swaps `amountIn` of one token for as much as possible of another token - /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in - /// calldata - /// @return amountOut The amount of the received token - function exactInputSingle(ExactInputSingleParams calldata params) - external - payable - returns (uint256 amountOut); - - struct ExactInputParams { - bytes path; - address recipient; - uint256 deadline; - uint256 amountIn; - uint256 amountOutMinimum; - } - - /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified - /// path - /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` - /// in calldata - /// @return amountOut The amount of the received token - function exactInput(ExactInputParams calldata params) - external - payable - returns (uint256 amountOut); - - struct ExactOutputSingleParams { - address tokenIn; - address tokenOut; - uint24 fee; - address recipient; - uint256 deadline; - uint256 amountOut; - uint256 amountInMaximum; - uint160 sqrtPriceLimitX96; - } - - /// @notice Swaps as little as possible of one token for `amountOut` of another token - /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in - /// calldata - /// @return amountIn The amount of the input token - function exactOutputSingle(ExactOutputSingleParams calldata params) - external - payable - returns (uint256 amountIn); - - struct ExactOutputParams { - bytes path; - address recipient; - uint256 deadline; - uint256 amountOut; - uint256 amountInMaximum; - } - - /// @notice Swaps as little as possible of one token for `amountOut` of another along the - /// specified path (reversed) - /// @param params The parameters necessary for the multi-hop swap, encoded as - /// `ExactOutputParams` in calldata - /// @return amountIn The amount of the input token - function exactOutput(ExactOutputParams calldata params) - external - payable - returns (uint256 amountIn); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IUniswapRouter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IUniswapRouter.sol deleted file mode 100644 index d1587a0..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/exchange/IUniswapRouter.sol +++ /dev/null @@ -1,117 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IUniswapRouter { - function swapExactTokensForETH( - uint256 amountIn, - uint256 amountOutMin, - address[] calldata path, - address to, - uint256 deadline - ) - external - virtual - returns (uint256[] memory amounts); - - function swapExactTokensForTokens( - uint256 amountIn, - uint256 amountOutMin, - address[] calldata path, - address to, - uint256 deadline - ) - external - virtual - returns (uint256[] memory amounts); - - function swapTokensForExactETH( - uint256 amountOut, - uint256 amountInMax, - address[] calldata path, - address to, - uint256 deadline - ) - external - virtual - returns (uint256[] memory amounts); - - function swapTokensForExactTokens( - uint256 amountOut, - uint256 amountInMax, - address[] calldata path, - address to, - uint256 deadline - ) - external - virtual - returns (uint256[] memory amounts); - - function addLiquidity( - address tokenA, - address tokenB, - uint256 amountADesired, - uint256 amountBDesired, - uint256 amountAMin, - uint256 amountBMin, - address to, - uint256 deadline - ) - external - virtual - returns (uint256 amountA, uint256 amountB, uint256 liquidity); - - function addLiquidityETH( - address token, - uint256 amountTokenDesired, - uint256 amountTokenMin, - uint256 amountETHMin, - address to, - uint256 deadline - ) - external - payable - virtual - returns (uint256 amountToken, uint256 amountETH, uint256 liquidity); - - function removeLiquidity( - address tokenA, - address tokenB, - uint256 liquidity, - uint256 amountAMin, - uint256 amountBMin, - address to, - uint256 deadline - ) - external - virtual - returns (uint256 amountA, uint256 amountB); - - function quote( - uint256 amountA, - uint256 reserveA, - uint256 reserveB - ) - public - pure - virtual - returns (uint256 amountB); - - function getAmountsOut( - uint256 amountIn, - address[] memory path - ) - public - view - virtual - returns (uint256[] memory amounts); - - function getAmountsIn( - uint256 amountOut, - address[] memory path - ) - public - view - virtual - returns (uint256[] memory amounts); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashBorrower.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashBorrower.sol deleted file mode 100644 index 3b95b5d..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashBorrower.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -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/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashLender.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashLender.sol deleted file mode 100644 index 28dcf8c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashLender.sol +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -import "./IERC3156FlashBorrower.sol"; - -interface IERC3156FlashLender { - /** - * @dev The amount of currency available to be lent. - * @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/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IFlashLoanBase.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IFlashLoanBase.sol deleted file mode 100644 index 353f976..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/flashloan/IFlashLoanBase.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -abstract contract IFlashLoanBase { - struct FlashLoanParams { - address[] tokens; - uint256[] amounts; - uint256[] modes; - address onBehalfOf; - address flParamGetterAddr; - bytes flParamGetterData; - bytes recipeData; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniPool.sol deleted file mode 100644 index 149c713..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniPool.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; - -interface IGUniPool { - function token0() external view returns (address); - function token1() external view returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniRouter02.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniRouter02.sol deleted file mode 100644 index 384e927..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/guni/IGUniRouter02.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; -pragma abicoder v2; - -interface IGUniRouter02 { - function removeLiquidity( - address pool, - uint256 burnAmount, - uint256 amount0Min, - uint256 amount1Min, - address receiver - ) - external - returns (uint256 amount0, uint256 amount1, uint128 liquidityBurned); - - function rebalanceAndAddLiquidity( - address pool, - uint256 amount0In, - uint256 amount1In, - uint256 amountSwap, - bool zeroForOne, - address[] memory swapActions, - bytes[] memory swapDatas, - uint256 amount0Min, - uint256 amount1Min, - address receiver - ) - external - returns (uint256 amount0, uint256 amount1, uint256 mintAmount); - - function addLiquidity( - address pool, - uint256 amount0Max, - uint256 amount1Max, - uint256 amount0Min, - uint256 amount1Min, - address receiver - ) - external - returns (uint256 amount0, uint256 amount1, uint256 mintAmount); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaAccountV2.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaAccountV2.sol deleted file mode 100644 index 4674f1c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaAccountV2.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; -pragma abicoder v2; - -interface IInstaAccountV2 { - function cast(string[] memory, bytes[] memory, address) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaIndex.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaIndex.sol deleted file mode 100644 index e82d80a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaIndex.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IInstaIndex { - function build( - address _owner, - uint256 accountVersion, - address _origin - ) - external - returns (address _account); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaMakerDAOMerkleDistributor.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaMakerDAOMerkleDistributor.sol deleted file mode 100644 index 7ad6a1e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/insta/IInstaMakerDAOMerkleDistributor.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IInstaMakerDAOMerkleDistributor { - function claim( - uint256 index, - uint256 vaultId, - address dsa, - address owner, - uint256 rewardAmount, - uint256 networthAmount, - bytes32[] calldata merkleProof - ) - external; - - function getPosition( - uint256 id, - uint256 rewardAmount, - uint256 networthAmount - ) - external - view - returns (uint256 claimableRewardAmount, uint256 claimableNetworth); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IAggregationExecutor.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IAggregationExecutor.sol deleted file mode 100644 index 814ded6..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IAggregationExecutor.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IAggregationExecutor { - function callBytes(bytes calldata data) external payable; // 0xd9c45357 - - // callbytes per swap sequence - function swapSingleSequence(bytes calldata data) external; - - function finalTransactionProcessing( - address tokenIn, - address tokenOut, - address to, - bytes calldata destTokenFeeData - ) - external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IExecutorHelper.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IExecutorHelper.sol deleted file mode 100644 index d901ed2..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IExecutorHelper.sol +++ /dev/null @@ -1,382 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IExecutorHelper { - struct Swap { - bytes data; - bytes4 functionSelector; - } - - struct SwapExecutorDescription { - Swap[][] swapSequences; - address tokenIn; - address tokenOut; - uint256 minTotalAmountOut; - address to; - uint256 deadline; - bytes destTokenFeeData; - } - - struct UniSwap { - address pool; - address tokenIn; - address tokenOut; - address recipient; - uint256 collectAmount; // amount that should be transferred to the pool - uint32 swapFee; - uint32 feePrecision; - uint32 tokenWeightInput; - } - - struct StableSwap { - address pool; - address tokenFrom; - address tokenTo; - uint8 tokenIndexFrom; - uint8 tokenIndexTo; - uint256 dx; - uint256 poolLength; - address poolLp; - bool isSaddle; // true: saddle, false: stable - } - - struct CurveSwap { - address pool; - address tokenFrom; - address tokenTo; - int128 tokenIndexFrom; - int128 tokenIndexTo; - uint256 dx; - bool usePoolUnderlying; - bool useTriCrypto; - } - - struct UniswapV3KSElastic { - address recipient; - address pool; - address tokenIn; - address tokenOut; - uint256 swapAmount; - uint160 sqrtPriceLimitX96; - bool isUniV3; // true = UniV3, false = KSElastic - } - - struct BalancerV2 { - address vault; - bytes32 poolId; - address assetIn; - address assetOut; - uint256 amount; - } - - struct DODO { - address recipient; - address pool; - address tokenFrom; - address tokenTo; - uint256 amount; - address sellHelper; - bool isSellBase; - bool isVersion2; - } - - struct GMX { - address vault; - address tokenIn; - address tokenOut; - uint256 amount; - address receiver; - } - - struct Synthetix { - address synthetixProxy; - address tokenIn; - address tokenOut; - bytes32 sourceCurrencyKey; - uint256 sourceAmount; - bytes32 destinationCurrencyKey; - bool useAtomicExchange; - } - - struct Platypus { - address pool; - address tokenIn; - address tokenOut; - address recipient; - uint256 collectAmount; // amount that should be transferred to the pool - } - - struct PSM { - address router; - address tokenIn; - address tokenOut; - uint256 amountIn; - address recipient; - } - - struct WSTETH { - address pool; - uint256 amount; - bool isWrapping; - } - - struct Maverick { - address pool; - address tokenIn; - address tokenOut; - address recipient; - uint256 swapAmount; - uint256 sqrtPriceLimitD18; - } - - struct SyncSwap { - bytes _data; - address vault; - address tokenIn; - address pool; - uint256 collectAmount; - } - - struct AlgebraV1 { - address recipient; - address pool; - address tokenIn; - address tokenOut; - uint256 swapAmount; - uint160 sqrtPriceLimitX96; - uint256 senderFeeOnTransfer; // [ FoT_FLAG(1 bit) ... SENDER_ADDRESS(160 bits) ] - } - - struct BalancerBatch { - address vault; - bytes32[] poolIds; - address[] path; // swap path from assetIn to assetOut - bytes[] userDatas; - uint256 amountIn; // assetIn amount - } - - struct Mantis { - address pool; - address tokenIn; - address tokenOut; - uint256 amount; - address recipient; - } - - struct IziSwap { - address pool; - address tokenIn; - address tokenOut; - address recipient; - uint256 swapAmount; - int24 limitPoint; - } - - function executeUniswap( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeStableSwap( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeCurve( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeKSClassic( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeUniV3KSElastic( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeRfq( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeBalV2( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeDODO( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeVelodrome( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeGMX( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executePlatypus( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeWrappedstETH( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeStEth( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeSynthetix( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeHashflow( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executePSM( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeFrax( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeCamelot( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeKyberLimitOrder( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeMaverick( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeSyncSwap( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeAlgebraV1( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeBalancerBatch( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeWombat( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeMantis( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); - - function executeIziSwap( - bytes memory data, - uint256 flagsAndPrevAmountOut - ) - external - payable - returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IMetaAggregationRouterV2.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IMetaAggregationRouterV2.sol deleted file mode 100644 index 219efab..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/kyber/IMetaAggregationRouterV2.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -import { IERC20 } from "../IERC20.sol"; -import { IAggregationExecutor } from "./IAggregationExecutor.sol"; - -interface IMetaAggregationRouterV2 { - struct SwapDescriptionV2 { - IERC20 srcToken; - IERC20 dstToken; - address[] srcReceivers; // transfer src token to these addresses, default - uint256[] srcAmounts; - address[] feeReceivers; - uint256[] feeAmounts; - address dstReceiver; - uint256 amount; - uint256 minReturnAmount; - uint256 flags; - bytes permit; - } - - /// @dev use for swapGeneric and swap to avoid stack too deep - struct SwapExecutionParams { - address callTarget; // call this address - address approveTarget; // approve this address if _APPROVE_FUND set - bytes targetData; - SwapDescriptionV2 desc; - bytes clientData; - } - - function swap(SwapExecutionParams calldata execution) - external - payable - returns (uint256, uint256); - - function swapSimpleMode( - IAggregationExecutor caller, - SwapDescriptionV2 memory desc, - bytes calldata executorData, - bytes calldata clientData - ) - external - returns (uint256, uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/lido/IWStEth.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/lido/IWStEth.sol deleted file mode 100644 index 7f329b6..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/lido/IWStEth.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -// Interface for wrapping and unwrapping StEth -interface IWStEth { - function wrap(uint256 _stETHAmount) external returns (uint256); - function unwrap(uint256 _wstETHAmount) external returns (uint256); - function stEthPerToken() external view returns (uint256); - function tokensPerStEth() external view returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFT.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFT.sol deleted file mode 100644 index da0e374..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFT.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -import "../IERC721Enumerable.sol"; - -interface IBondNFT is IERC721Enumerable { - struct BondExtraData { - uint80 initialHalfDna; - uint80 finalHalfDna; - uint32 troveSize; // Debt in LUSD - uint32 lqtyAmount; // Holding LQTY, staking or deposited into Pickle - uint32 curveGaugeSlopes; // For 3CRV and Frax pools combined - } - - function getBondAmount(uint256 _tokenID) external view returns (uint256 amount); - function getBondStartTime(uint256 _tokenID) external view returns (uint256 startTime); - function getBondEndTime(uint256 _tokenID) external view returns (uint256 endTime); - function getBondInitialHalfDna(uint256 _tokenID) - external - view - returns (uint80 initialHalfDna); - function getBondInitialDna(uint256 _tokenID) external view returns (uint256 initialDna); - function getBondFinalHalfDna(uint256 _tokenID) external view returns (uint80 finalHalfDna); - function getBondFinalDna(uint256 _tokenID) external view returns (uint256 finalDna); - function getBondStatus(uint256 _tokenID) external view returns (uint8 status); - function getBondExtraData(uint256 _tokenID) external view returns (BondExtraData memory); - function tokenURI(uint256 _tokenID) external view returns (string memory); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFTArtwork.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFTArtwork.sol deleted file mode 100644 index 6058725..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBondNFTArtwork.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -import "./IBondNFT.sol"; - -interface IBondNFTArtwork { - function tokenURI( - uint256 _tokenID, - IBondNFT.BondExtraData calldata _bondExtraData - ) - external - view - returns (string memory); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBorrowerOperations.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBorrowerOperations.sol deleted file mode 100644 index 830d0ce..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IBorrowerOperations.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -// Common interface for the Trove Manager. -interface IBorrowerOperations { - // --- Events --- - - event TroveManagerAddressChanged(address _newTroveManagerAddress); - event ActivePoolAddressChanged(address _activePoolAddress); - event DefaultPoolAddressChanged(address _defaultPoolAddress); - event StabilityPoolAddressChanged(address _stabilityPoolAddress); - event GasPoolAddressChanged(address _gasPoolAddress); - event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress); - event PriceFeedAddressChanged(address _newPriceFeedAddress); - event SortedTrovesAddressChanged(address _sortedTrovesAddress); - event LUSDTokenAddressChanged(address _lusdTokenAddress); - event LQTYStakingAddressChanged(address _lqtyStakingAddress); - - event TroveCreated(address indexed _borrower, uint256 arrayIndex); - event TroveUpdated( - address indexed _borrower, uint256 _debt, uint256 _coll, uint256 stake, uint8 operation - ); - event LUSDBorrowingFeePaid(address indexed _borrower, uint256 _LUSDFee); - - // --- Functions --- - - function openTrove( - uint256 _maxFee, - uint256 _LUSDAmount, - address _upperHint, - address _lowerHint - ) - external - payable; - - function addColl(address _upperHint, address _lowerHint) external payable; - - function moveETHGainToTrove( - address _user, - address _upperHint, - address _lowerHint - ) - external - payable; - - function withdrawColl(uint256 _amount, address _upperHint, address _lowerHint) external; - - function withdrawLUSD( - uint256 _maxFee, - uint256 _amount, - address _upperHint, - address _lowerHint - ) - external; - - function repayLUSD(uint256 _amount, address _upperHint, address _lowerHint) external; - - function closeTrove() external; - - function adjustTrove( - uint256 _maxFee, - uint256 _collWithdrawal, - uint256 _debtChange, - bool isDebtIncrease, - address _upperHint, - address _lowerHint - ) - external - payable; - - function claimCollateral() external; - - function getCompositeDebt(uint256 _debt) external pure returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IChickenBondManager.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IChickenBondManager.sol deleted file mode 100644 index ccc4b72..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IChickenBondManager.sol +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface IChickenBondManager { - // Valid values for `status` returned by `getBondData()` - enum BondStatus { - nonExistent, - active, - chickenedOut, - chickenedIn - } - - struct BondData { - uint256 lusdAmount; - uint64 claimedBLUSD; // In BLUSD units without decimals - uint64 startTime; - uint64 endTime; // Timestamp of chicken in/out event - BondStatus status; - } - - function lusdToken() external view returns (address); - function bLUSDToken() external view returns (address); - function curvePool() external view returns (address); - function bammSPVault() external view returns (address); - function yearnCurveVault() external view returns (address); - - function countChickenIn() external view returns (uint256); - function countChickenOut() external view returns (uint256); - - // constants - function INDEX_OF_LUSD_TOKEN_IN_CURVE_POOL() external pure returns (int128); - function CHICKEN_IN_AMM_FEE() external view returns (uint256); - - function createBond(uint256 _lusdAmount) external returns (uint256); - function createBondWithPermit( - address owner, - uint256 amount, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) - external - returns (uint256); - function chickenOut(uint256 _bondID, uint256 _minLUSD) external; - function chickenIn(uint256 _bondID) external; - function redeem( - uint256 _bLUSDToRedeem, - uint256 _minLUSDFromBAMMSPVault - ) - external - returns (uint256, uint256); - - // getters - function calcRedemptionFeePercentage(uint256 _fractionOfBLUSDToRedeem) - external - view - returns (uint256); - function getBondData(uint256 _bondID) external view returns (BondData memory); - function getLUSDToAcquire(uint256 _bondID) external view returns (uint256); - function calcAccruedBLUSD(uint256 _bondID) external view returns (uint256); - function calcBondBLUSDCap(uint256 _bondID) external view returns (uint256); - function getLUSDInBAMMSPVault() external view returns (uint256); - function calcTotalYearnCurveVaultShareValue() external view returns (uint256); - function calcTotalLUSDValue() external view returns (uint256); - function getPendingLUSD() external view returns (uint256); - function getAcquiredLUSDInSP() external view returns (uint256); - function getAcquiredLUSDInCurve() external view returns (uint256); - function getTotalAcquiredLUSD() external view returns (uint256); - function getPermanentLUSD() external view returns (uint256); - function getOwnedLUSDInSP() external view returns (uint256); - function getOwnedLUSDInCurve() external view returns (uint256); - function calcSystemBackingRatio() external view returns (uint256); - function calcUpdatedAccrualParameter() external view returns (uint256); - function getBAMMLUSDDebt() external view returns (uint256); - function getOpenBondCount() external view returns (uint256); - function getTreasury() - external - view - returns (uint256 _pendingLUSD, uint256 _totalAcquiredLUSD, uint256 _permanentLUSD); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ICollSurplusPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ICollSurplusPool.sol deleted file mode 100644 index 86bb605..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ICollSurplusPool.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface ICollSurplusPool { - // --- Events --- - - event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress); - event TroveManagerAddressChanged(address _newTroveManagerAddress); - event ActivePoolAddressChanged(address _newActivePoolAddress); - - event CollBalanceUpdated(address indexed _account, uint256 _newBalance); - event EtherSent(address _to, uint256 _amount); - - // --- Contract setters --- - - function setAddresses( - address _borrowerOperationsAddress, - address _troveManagerAddress, - address _activePoolAddress - ) - external; - - function getETH() external view returns (uint256); - - function getCollateral(address _account) external view returns (uint256); - - function accountSurplus(address _account, uint256 _amount) external; - - function claimColl(address _account) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IHintHelpers.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IHintHelpers.sol deleted file mode 100644 index 4741924..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IHintHelpers.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface IHintHelpers { - function getRedemptionHints( - uint256 _LUSDamount, - uint256 _price, - uint256 _maxIterations - ) - external - view - returns ( - address firstRedemptionHint, - uint256 partialRedemptionHintNICR, - uint256 truncatedLUSDamount - ); - - function getApproxHint( - uint256 _CR, - uint256 _numTrials, - uint256 _inputRandomSeed - ) - external - view - returns (address hintAddress, uint256 diff, uint256 latestRandomSeed); - - function computeNominalCR(uint256 _coll, uint256 _debt) external pure returns (uint256); - - function computeCR( - uint256 _coll, - uint256 _debt, - uint256 _price - ) - external - pure - returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ILQTYStaking.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ILQTYStaking.sol deleted file mode 100644 index 7b58de2..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ILQTYStaking.sol +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface ILQTYStaking { - // --- Events -- - - event LQTYTokenAddressSet(address _lqtyTokenAddress); - event LUSDTokenAddressSet(address _lusdTokenAddress); - event TroveManagerAddressSet(address _troveManager); - event BorrowerOperationsAddressSet(address _borrowerOperationsAddress); - event ActivePoolAddressSet(address _activePoolAddress); - - event StakeChanged(address indexed staker, uint256 newStake); - event StakingGainsWithdrawn(address indexed staker, uint256 LUSDGain, uint256 ETHGain); - event F_ETHUpdated(uint256 _F_ETH); - event F_LUSDUpdated(uint256 _F_LUSD); - event TotalLQTYStakedUpdated(uint256 _totalLQTYStaked); - event EtherSent(address _account, uint256 _amount); - event StakerSnapshotsUpdated(address _staker, uint256 _F_ETH, uint256 _F_LUSD); - - // --- Functions --- - - function setAddresses( - address _lqtyTokenAddress, - address _lusdTokenAddress, - address _troveManagerAddress, - address _borrowerOperationsAddress, - address _activePoolAddress - ) - external; - - function stake(uint256 _LQTYamount) external; - - function unstake(uint256 _LQTYamount) external; - - function increaseF_ETH(uint256 _ETHFee) external; - - function increaseF_LUSD(uint256 _LQTYFee) external; - - function getPendingETHGain(address _user) external view returns (uint256); - - function getPendingLUSDGain(address _user) external view returns (uint256); - - function stakes(address) external view returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IPriceFeed.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IPriceFeed.sol deleted file mode 100644 index 9334a2f..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IPriceFeed.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface IPriceFeed { - function lastGoodPrice() external pure returns (uint256); - function fetchPrice() external returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ISortedTroves.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ISortedTroves.sol deleted file mode 100644 index 8e1fdc3..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ISortedTroves.sol +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -// Common interface for the SortedTroves Doubly Linked List. -interface ISortedTroves { - // --- Events --- - - event SortedTrovesAddressChanged(address _sortedDoublyLLAddress); - event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress); - event NodeAdded(address _id, uint256 _NICR); - event NodeRemoved(address _id); - - // --- Functions --- - - function setParams( - uint256 _size, - address _TroveManagerAddress, - address _borrowerOperationsAddress - ) - external; - - function insert(address _id, uint256 _ICR, address _prevId, address _nextId) external; - - function remove(address _id) external; - - function reInsert(address _id, uint256 _newICR, address _prevId, address _nextId) external; - - function contains(address _id) external view returns (bool); - - function isFull() external view returns (bool); - - function isEmpty() external view returns (bool); - - function getSize() external view returns (uint256); - - function getMaxSize() external view returns (uint256); - - function getFirst() external view returns (address); - - function getLast() external view returns (address); - - function getNext(address _id) external view returns (address); - - function getPrev(address _id) external view returns (address); - - function validInsertPosition( - uint256 _ICR, - address _prevId, - address _nextId - ) - external - view - returns (bool); - - function findInsertPosition( - uint256 _ICR, - address _prevId, - address _nextId - ) - external - view - returns (address, address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IStabilityPool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IStabilityPool.sol deleted file mode 100644 index bd92aad..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/IStabilityPool.sol +++ /dev/null @@ -1,168 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IStabilityPool { - // --- Events --- - - event StabilityPoolETHBalanceUpdated(uint256 _newBalance); - event StabilityPoolLUSDBalanceUpdated(uint256 _newBalance); - - event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress); - event TroveManagerAddressChanged(address _newTroveManagerAddress); - event ActivePoolAddressChanged(address _newActivePoolAddress); - event DefaultPoolAddressChanged(address _newDefaultPoolAddress); - event LUSDTokenAddressChanged(address _newLUSDTokenAddress); - event SortedTrovesAddressChanged(address _newSortedTrovesAddress); - event PriceFeedAddressChanged(address _newPriceFeedAddress); - event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress); - - event P_Updated(uint256 _P); - event S_Updated(uint256 _S, uint128 _epoch, uint128 _scale); - event G_Updated(uint256 _G, uint128 _epoch, uint128 _scale); - event EpochUpdated(uint128 _currentEpoch); - event ScaleUpdated(uint128 _currentScale); - - event FrontEndRegistered(address indexed _frontEnd, uint256 _kickbackRate); - event FrontEndTagSet(address indexed _depositor, address indexed _frontEnd); - - event DepositSnapshotUpdated(address indexed _depositor, uint256 _P, uint256 _S, uint256 _G); - event FrontEndSnapshotUpdated(address indexed _frontEnd, uint256 _P, uint256 _G); - event UserDepositChanged(address indexed _depositor, uint256 _newDeposit); - event FrontEndStakeChanged( - address indexed _frontEnd, uint256 _newFrontEndStake, address _depositor - ); - - event ETHGainWithdrawn(address indexed _depositor, uint256 _ETH, uint256 _LUSDLoss); - event LQTYPaidToDepositor(address indexed _depositor, uint256 _LQTY); - event LQTYPaidToFrontEnd(address indexed _frontEnd, uint256 _LQTY); - event EtherSent(address _to, uint256 _amount); - - // --- Functions --- - - /* - * Called only once on init, to set addresses of other Liquity contracts - * Callable only by owner, renounces ownership at the end - */ - function setAddresses( - address _borrowerOperationsAddress, - address _troveManagerAddress, - address _activePoolAddress, - address _lusdTokenAddress, - address _sortedTrovesAddress, - address _priceFeedAddress, - address _communityIssuanceAddress - ) - external; - - /* - * Initial checks: - * - Frontend is registered or zero address - * - Sender is not a registered frontend - * - _amount is not zero - * --- - * - Triggers a LQTY issuance, based on time passed since the last issuance. The LQTY issuance is - shared between *all* depositors and front ends - * - Tags the deposit with the provided front end tag param, if it's a new deposit - * - Sends depositor's accumulated gains (LQTY, ETH) to depositor - * - Sends the tagged front end's accumulated LQTY gains to the tagged front end - * - Increases deposit and tagged front end's stake, and takes new snapshots for each. - */ - function provideToSP(uint256 _amount, address _frontEndTag) external; - - /* - * Initial checks: - * - _amount is zero or there are no under collateralized troves left in the system - * - User has a non zero deposit - * --- - * - Triggers a LQTY issuance, based on time passed since the last issuance. The LQTY issuance is - shared between *all* depositors and front ends - * - Removes the deposit's front end tag if it is a full withdrawal - * - Sends all depositor's accumulated gains (LQTY, ETH) to depositor - * - Sends the tagged front end's accumulated LQTY gains to the tagged front end - * - Decreases deposit and tagged front end's stake, and takes new snapshots for each. - * - * If _amount > userDeposit, the user withdraws all of their compounded deposit. - */ - function withdrawFromSP(uint256 _amount) external; - - /* - * Initial checks: - * - User has a non zero deposit - * - User has an open trove - * - User has some ETH gain - * --- - * - Triggers a LQTY issuance, based on time passed since the last issuance. The LQTY issuance is - shared between *all* depositors and front ends - * - Sends all depositor's LQTY gain to depositor - * - Sends all tagged front end's LQTY gain to the tagged front end - * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove - * - Leaves their compounded deposit in the Stability Pool - * - Updates snapshots for deposit and tagged front end stake - */ - function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external; - - /* - * Initial checks: - * - Frontend (sender) not already registered - * - User (sender) has no deposit - * - _kickbackRate is in the range [0, 100%] - * --- - * Front end makes a one-time selection of kickback rate upon registering - */ - function registerFrontEnd(uint256 _kickbackRate) external; - - /* - * Initial checks: - * - Caller is TroveManager - * --- - * Cancels out the specified debt against the LUSD contained in the Stability Pool (as far as - possible) - * and transfers the Trove's ETH collateral from ActivePool to StabilityPool. - * Only called by liquidation functions in the TroveManager. - */ - function offset(uint256 _debt, uint256 _coll) external; - - /* - * Returns the total amount of ETH held by the pool, accounted in an internal variable instead of - `balance`, - * to exclude edge cases like ETH received from a self-destruct. - */ - function getETH() external view returns (uint256); - - /* - * Returns LUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is - offset. - */ - function getTotalLUSDDeposits() external view returns (uint256); - - /* - * Calculates the ETH gain earned by the deposit since its last snapshots were taken. - */ - function getDepositorETHGain(address _depositor) external view returns (uint256); - - /* - * Calculate the LQTY gain earned by a deposit since its last snapshots were taken. - * If not tagged with a front end, the depositor gets a 100% cut of what their deposit earned. - * Otherwise, their cut of the deposit's earnings is equal to the kickbackRate, set by the front - end through - * which they made their deposit. - */ - function getDepositorLQTYGain(address _depositor) external view returns (uint256); - - /* - * Return the LQTY gain earned by the front end. - */ - function getFrontEndLQTYGain(address _frontEnd) external view returns (uint256); - - /* - * Return the user's compounded deposit. - */ - function getCompoundedLUSDDeposit(address _depositor) external view returns (uint256); - - /* - * Return the front end's compounded stake. - * - * The front end's compounded stake is equal to the sum of its depositors' compounded deposits. - */ - function getCompoundedFrontEndStake(address _frontEnd) external view returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ITroveManager.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ITroveManager.sol deleted file mode 100644 index 1cca992..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/liquity/ITroveManager.sol +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -// Common interface for the Trove Manager. -interface ITroveManager { - // --- Events --- - - event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress); - event PriceFeedAddressChanged(address _newPriceFeedAddress); - event LUSDTokenAddressChanged(address _newLUSDTokenAddress); - event ActivePoolAddressChanged(address _activePoolAddress); - event DefaultPoolAddressChanged(address _defaultPoolAddress); - event StabilityPoolAddressChanged(address _stabilityPoolAddress); - event GasPoolAddressChanged(address _gasPoolAddress); - event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress); - event SortedTrovesAddressChanged(address _sortedTrovesAddress); - event LQTYTokenAddressChanged(address _lqtyTokenAddress); - event LQTYStakingAddressChanged(address _lqtyStakingAddress); - - event Liquidation( - uint256 _liquidatedDebt, - uint256 _liquidatedColl, - uint256 _collGasCompensation, - uint256 _LUSDGasCompensation - ); - event Redemption( - uint256 _attemptedLUSDAmount, uint256 _actualLUSDAmount, uint256 _ETHSent, uint256 _ETHFee - ); - event TroveUpdated( - address indexed _borrower, uint256 _debt, uint256 _coll, uint256 stake, uint8 operation - ); - event TroveLiquidated(address indexed _borrower, uint256 _debt, uint256 _coll, uint8 operation); - event BaseRateUpdated(uint256 _baseRate); - event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime); - event TotalStakesUpdated(uint256 _newTotalStakes); - event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot); - event LTermsUpdated(uint256 _L_ETH, uint256 _L_LUSDDebt); - event TroveSnapshotsUpdated(uint256 _L_ETH, uint256 _L_LUSDDebt); - event TroveIndexUpdated(address _borrower, uint256 _newIndex); - - function getTroveOwnersCount() external view returns (uint256); - - function getTroveFromTroveOwnersArray(uint256 _index) external view returns (address); - - function getNominalICR(address _borrower) external view returns (uint256); - function getCurrentICR(address _borrower, uint256 _price) external view returns (uint256); - - function liquidate(address _borrower) external; - - function liquidateTroves(uint256 _n) external; - - function batchLiquidateTroves(address[] calldata _troveArray) external; - - function redeemCollateral( - uint256 _LUSDAmount, - address _firstRedemptionHint, - address _upperPartialRedemptionHint, - address _lowerPartialRedemptionHint, - uint256 _partialRedemptionHintNICR, - uint256 _maxIterations, - uint256 _maxFee - ) - external; - - function updateStakeAndTotalStakes(address _borrower) external returns (uint256); - - function updateTroveRewardSnapshots(address _borrower) external; - - function addTroveOwnerToArray(address _borrower) external returns (uint256 index); - - function applyPendingRewards(address _borrower) external; - - function getPendingETHReward(address _borrower) external view returns (uint256); - - function getPendingLUSDDebtReward(address _borrower) external view returns (uint256); - - function hasPendingRewards(address _borrower) external view returns (bool); - - function getEntireDebtAndColl(address _borrower) - external - view - returns ( - uint256 debt, - uint256 coll, - uint256 pendingLUSDDebtReward, - uint256 pendingETHReward - ); - - function closeTrove(address _borrower) external; - - function removeStake(address _borrower) external; - - function getRedemptionRate() external view returns (uint256); - function getRedemptionRateWithDecay() external view returns (uint256); - - function getRedemptionFeeWithDecay(uint256 _ETHDrawn) external view returns (uint256); - - function getBorrowingRate() external view returns (uint256); - function getBorrowingRateWithDecay() external view returns (uint256); - - function getBorrowingFee(uint256 LUSDDebt) external view returns (uint256); - function getBorrowingFeeWithDecay(uint256 _LUSDDebt) external view returns (uint256); - - function decayBaseRateFromBorrowing() external; - - function getTroveStatus(address _borrower) external view returns (uint256); - - function getTroveStake(address _borrower) external view returns (uint256); - - function getTroveDebt(address _borrower) external view returns (uint256); - - function getTroveColl(address _borrower) external view returns (uint256); - - function setTroveStatus(address _borrower, uint256 num) external; - - function increaseTroveColl( - address _borrower, - uint256 _collIncrease - ) - external - returns (uint256); - - function decreaseTroveColl( - address _borrower, - uint256 _collDecrease - ) - external - returns (uint256); - - function increaseTroveDebt( - address _borrower, - uint256 _debtIncrease - ) - external - returns (uint256); - - function decreaseTroveDebt( - address _borrower, - uint256 _collDecrease - ) - external - returns (uint256); - - function getTCR(uint256 _price) external view returns (uint256); - - function checkRecoveryMode(uint256 _price) external view returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICat.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICat.sol deleted file mode 100644 index ee6dfc0..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICat.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract ICat { - struct Ilk { - address flip; // Liquidator - uint256 chop; // Liquidation Penalty [ray] - uint256 lump; // Liquidation Quantity [wad] - } - - mapping(bytes32 => Ilk) public ilks; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICdpRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICdpRegistry.sol deleted file mode 100644 index 8ed91fd..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICdpRegistry.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -import "./IVat.sol"; -import "./IGem.sol"; - -abstract contract ICdpRegistry { - function open(bytes32 ilk, address usr) public virtual returns (uint256); - - function cdps(bytes32, address) public view virtual returns (uint256); - function owns(uint256) public view virtual returns (address); - function ilks(uint256) public view virtual returns (bytes32); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropJoin.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropJoin.sol deleted file mode 100644 index 9303f9a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropJoin.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -import "./IJoin.sol"; - -abstract contract ICropJoin is IJoin { - function bonus() external virtual returns (IGem); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropper.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropper.sol deleted file mode 100644 index 8420d81..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ICropper.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface ICropper { - function proxy(address) external view returns (address); - function getOrCreateProxy(address) external returns (address); - function join(address, address, uint256) external; - function exit(address, address, uint256) external; - function flee(address, address, uint256) external; - function frob(bytes32, address, address, address, int256, int256) external; - function quit(bytes32, address, address) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDSPause.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDSPause.sol deleted file mode 100644 index 0b26486..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDSPause.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IDSPause { - function plot(address usr, bytes32 tag, bytes memory fax, uint256 eta) public virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDaiJoin.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDaiJoin.sol deleted file mode 100644 index 16693df..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDaiJoin.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -import "./IVat.sol"; -import "./IGem.sol"; - -abstract contract IDaiJoin { - function vat() public virtual returns (IVat); - function dai() public virtual returns (IGem); - function join(address, uint256) public payable virtual; - function exit(address, uint256) public virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDssSpell.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDssSpell.sol deleted file mode 100644 index ec45430..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IDssSpell.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IDssSpell { - function cast() public virtual; - function done() public view virtual returns (bool); - function nextCastTime() public view virtual returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGem.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGem.sol deleted file mode 100644 index 1ddcb52..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGem.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IGem { - function dec() public virtual returns (uint256); - function gem() public virtual returns (IGem); - function join(address, uint256) public payable virtual; - function exit(address, uint256) public virtual; - - function approve(address, uint256) public virtual; - function transfer(address, uint256) public virtual returns (bool); - function transferFrom(address, address, uint256) public virtual returns (bool); - function deposit() public payable virtual; - function withdraw(uint256) public virtual; - function allowance(address, address) public virtual returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGetCdps.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGetCdps.sol deleted file mode 100644 index 28d6af6..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IGetCdps.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -abstract contract IGetCdps { - function getCdpsAsc( - address manager, - address guy - ) - external - view - virtual - returns (uint256[] memory ids, address[] memory urns, bytes32[] memory ilks); - - function getCdpsDesc( - address manager, - address guy - ) - external - view - virtual - returns (uint256[] memory ids, address[] memory urns, bytes32[] memory ilks); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJoin.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJoin.sol deleted file mode 100644 index d857aaa..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJoin.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -import "./IGem.sol"; - -abstract contract IJoin { - bytes32 public ilk; - - function dec() public view virtual returns (uint256); - function gem() public view virtual returns (IGem); - function join(address, uint256) public payable virtual; - function exit(address, uint256) public virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJug.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJug.sol deleted file mode 100644 index f1b0595..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IJug.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IJug { - struct Ilk { - uint256 duty; - uint256 rho; - } - - mapping(bytes32 => Ilk) public ilks; - - function drip(bytes32) public virtual returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IManager.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IManager.sol deleted file mode 100644 index 85fb930..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IManager.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IManager { - function last(address) public virtual returns (uint256); - function cdpCan(address, uint256, address) public view virtual returns (uint256); - function ilks(uint256) public view virtual returns (bytes32); - function owns(uint256) public view virtual returns (address); - function urns(uint256) public view virtual returns (address); - function vat() public view virtual returns (address); - function open(bytes32, address) public virtual returns (uint256); - function give(uint256, address) public virtual; - function cdpAllow(uint256, address, uint256) public virtual; - function urnAllow(address, uint256) public virtual; - function frob(uint256, int256, int256) public virtual; - function flux(uint256, address, uint256) public virtual; - function move(uint256, address, uint256) public virtual; - function exit(address, uint256, address, uint256) public virtual; - function quit(uint256, address) public virtual; - function enter(address, uint256) public virtual; - function shift(uint256, uint256) public virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IOsm.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IOsm.sol deleted file mode 100644 index fe1653b..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IOsm.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -abstract contract IOsm { - mapping(address => uint256) public bud; - - function peep() external view virtual returns (bytes32, bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPipInterface.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPipInterface.sol deleted file mode 100644 index 7899a7e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPipInterface.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IPipInterface { - function read() public virtual returns (bytes32); - function poke() external virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPot.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPot.sol deleted file mode 100644 index c796eb5..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IPot.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IPot { - function pie(address) external view returns (uint256); - function vat() external view returns (address); - function chi() external view returns (uint256); - function rho() external view returns (uint256); - function drip() external returns (uint256); - function join(uint256) external; - function exit(uint256) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ISpotter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ISpotter.sol deleted file mode 100644 index b39cc74..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/ISpotter.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -import "./IPipInterface.sol"; - -abstract contract ISpotter { - struct Ilk { - IPipInterface pip; - uint256 mat; - } - - mapping(bytes32 => Ilk) public ilks; - - uint256 public par; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IVat.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IVat.sol deleted file mode 100644 index a184829..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mcd/IVat.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IVat { - struct Urn { - uint256 ink; // Locked Collateral [wad] - uint256 art; // Normalised Debt [wad] - } - - struct Ilk { - uint256 Art; // Total Normalised Debt [wad] - uint256 rate; // Accumulated Rates [ray] - uint256 spot; // Price with Safety Margin [ray] - uint256 line; // Debt Ceiling [rad] - uint256 dust; // Urn Debt Floor [rad] - } - - mapping(bytes32 => mapping(address => Urn)) public urns; - mapping(bytes32 => Ilk) public ilks; - mapping(bytes32 => mapping(address => uint256)) public gem; // [wad] - - function can(address, address) public view virtual returns (uint256); - function dai(address) public view virtual returns (uint256); - function frob(bytes32, address, address, address, int256, int256) public virtual; - function hope(address) public virtual; - function nope(address) public virtual; - function move(address, address, uint256) public virtual; - function fork(bytes32, address, address, int256, int256) public virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorpho.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorpho.sol deleted file mode 100644 index b3d3eae..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorpho.sol +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: GNU AGPLv3 -pragma solidity ^0.8.0; - -import "./MorphoTypes.sol"; - -interface IMorpho { - /// STORAGE /// - - function NO_REFERRAL_CODE() external view returns (uint8); - function VARIABLE_INTEREST_MODE() external view returns (uint8); - function MAX_BASIS_POINTS() external view returns (uint16); - function DEFAULT_LIQUIDATION_CLOSE_FACTOR() external view returns (uint16); - function HEALTH_FACTOR_LIQUIDATION_THRESHOLD() external view returns (uint256); - function MAX_NB_OF_MARKETS() external view returns (uint256); - function BORROWING_MASK() external view returns (bytes32); - function ONE() external view returns (bytes32); - - function isClaimRewardsPaused() external view returns (bool); - function defaultMaxGasForMatching() external view returns (Types.MaxGasForMatching memory); - function maxSortedUsers() external view returns (uint256); - function supplyBalanceInOf( - address, - address - ) - external - view - returns (Types.SupplyBalance memory); - function borrowBalanceInOf( - address, - address - ) - external - view - returns (Types.BorrowBalance memory); - function deltas(address) external view returns (Types.Delta memory); - function market(address) external view returns (Types.Market memory); - function p2pSupplyIndex(address) external view returns (uint256); - function p2pBorrowIndex(address) external view returns (uint256); - function poolIndexes(address) external view returns (Types.PoolIndexes memory); - function interestRatesManager() external view returns (address); - function rewardsManager() external view returns (address); - function entryPositionsManager() external view returns (address); - function exitPositionsManager() external view returns (address); - function aaveIncentivesController() external view returns (address); - function addressesProvider() external view returns (address); - function incentivesVault() external view returns (address); - function pool() external view returns (address); - function treasuryVault() external view returns (address); - function borrowMask(address) external view returns (bytes32); - function userMarkets(address) external view returns (bytes32); - - /// UTILS /// - - function updateIndexes(address _poolToken) external; - - /// GETTERS /// - - function getMarketsCreated() external view returns (address[] memory marketsCreated_); - function getHead( - address _poolToken, - Types.PositionType _positionType - ) - external - view - returns (address head); - function getNext( - address _poolToken, - Types.PositionType _positionType, - address _user - ) - external - view - returns (address next); - - /// GOVERNANCE /// - - function setMaxSortedUsers(uint256 _newMaxSortedUsers) external; - function setDefaultMaxGasForMatching(Types.MaxGasForMatching memory _maxGasForMatching) - external; - function setTreasuryVault(address _newTreasuryVaultAddress) external; - function setIncentivesVault(address _newIncentivesVault) external; - function setRewardsManager(address _rewardsManagerAddress) external; - function setP2PDisabledStatus(address _poolToken, bool _isP2PDisabled) external; - function setReserveFactor(address _poolToken, uint256 _newReserveFactor) external; - function setP2PIndexCursor(address _poolToken, uint16 _p2pIndexCursor) external; - function setPauseStatusForAllMarkets(bool _newStatus) external; - function setClaimRewardsPauseStatus(bool _newStatus) external; - function setPauseStatus(address _poolToken, bool _newStatus) external; - function setPartialPauseStatus(address _poolToken, bool _newStatus) external; - function setExitPositionsManager(address _exitPositionsManager) external; - function setEntryPositionsManager(address _entryPositionsManager) external; - function setInterestRatesManager(address _interestRatesManager) external; - function claimToTreasury( - address[] calldata _poolTokens, - uint256[] calldata _amounts - ) - external; - function createMarket( - address _underlyingToken, - uint16 _reserveFactor, - uint16 _p2pIndexCursor - ) - external; - - /// USERS /// - - function supply(address _poolToken, uint256 _amount) external; - function supply(address _poolToken, address _onBehalf, uint256 _amount) external; - function supply( - address _poolToken, - address _onBehalf, - uint256 _amount, - uint256 _maxGasForMatching - ) - external; - function borrow(address _poolToken, uint256 _amount) external; - function borrow(address _poolToken, uint256 _amount, uint256 _maxGasForMatching) external; - function withdraw(address _poolToken, uint256 _amount) external; - function withdraw(address _poolToken, uint256 _amount, address _receiver) external; - function repay(address _poolToken, uint256 _amount) external; - function repay(address _poolToken, address _onBehalf, uint256 _amount) external; - function liquidate( - address _poolTokenBorrowed, - address _poolTokenCollateral, - address _borrower, - uint256 _amount - ) - external; - function claimRewards( - address[] calldata _assets, - bool _tradeForMorphoToken - ) - external - returns (uint256 claimedAmount); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV2Lens.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV2Lens.sol deleted file mode 100644 index 0630363..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV2Lens.sol +++ /dev/null @@ -1,257 +0,0 @@ -// SPDX-License-Identifier: GNU AGPLv3 -pragma solidity >=0.8.0; - -import "./MorphoTypes.sol"; - -interface IMorphoAaveV2Lens { - /// STORAGE /// - - function DEFAULT_LIQUIDATION_CLOSE_FACTOR() external view returns (uint16); - - function HEALTH_FACTOR_LIQUIDATION_THRESHOLD() external view returns (uint256); - - function ST_ETH() external view returns (address); - - function ST_ETH_BASE_REBASE_INDEX() external view returns (uint256); - - function morpho() external view returns (address); - - function addressesProvider() external view returns (address); - - function pool() external view returns (address); - - /// GENERAL /// - - function getTotalSupply() - external - view - returns (uint256 p2pSupplyAmount, uint256 poolSupplyAmount, uint256 totalSupplyAmount); - - function getTotalBorrow() - external - view - returns (uint256 p2pBorrowAmount, uint256 poolBorrowAmount, uint256 totalBorrowAmount); - - /// MARKETS /// - - function isMarketCreated(address _poolToken) external view returns (bool); - - /// @dev Deprecated. - function isMarketCreatedAndNotPaused(address _poolToken) external view returns (bool); - - /// @dev Deprecated. - function isMarketCreatedAndNotPausedNorPartiallyPaused(address _poolToken) - external - view - returns (bool); - - function getAllMarkets() external view returns (address[] memory marketsCreated_); - - function getMainMarketData(address _poolToken) - external - view - returns ( - uint256 avgSupplyRatePerYear, - uint256 avgBorrowRatePerYear, - uint256 p2pSupplyAmount, - uint256 p2pBorrowAmount, - uint256 poolSupplyAmount, - uint256 poolBorrowAmount - ); - - function getAdvancedMarketData(address _poolToken) - external - view - returns ( - Types.Indexes memory indexes, - uint32 lastUpdateTimestamp, - uint256 p2pSupplyDelta, - uint256 p2pBorrowDelta - ); - - function getMarketConfiguration(address _poolToken) - external - view - returns ( - address underlying, - bool isCreated, - bool isP2PDisabled, - bool isPaused, - bool isPartiallyPaused, - uint16 reserveFactor, - uint16 p2pIndexCursor, - uint256 loanToValue, - uint256 liquidationThreshold, - uint256 liquidationBonus, - uint256 decimals - ); - - function getMarketPauseStatus(address _poolToken) - external - view - returns (Types.MarketPauseStatus memory); - - function getTotalMarketSupply(address _poolToken) - external - view - returns (uint256 p2pSupplyAmount, uint256 poolSupplyAmount); - - function getTotalMarketBorrow(address _poolToken) - external - view - returns (uint256 p2pBorrowAmount, uint256 poolBorrowAmount); - - /// INDEXES /// - - function getCurrentP2PSupplyIndex(address _poolToken) external view returns (uint256); - - function getCurrentP2PBorrowIndex(address _poolToken) external view returns (uint256); - - function getIndexes(address _poolToken) external view returns (Types.Indexes memory indexes); - - /// USERS /// - - function getEnteredMarkets(address _user) - external - view - returns (address[] memory enteredMarkets); - - function getUserHealthFactor(address _user) external view returns (uint256 healthFactor); - - function getUserBalanceStates(address _user) - external - view - returns (Types.LiquidityData memory assetData); - - function getCurrentSupplyBalanceInOf( - address _poolToken, - address _user - ) - external - view - returns (uint256 balanceInP2P, uint256 balanceOnPool, uint256 totalBalance); - - function getCurrentBorrowBalanceInOf( - address _poolToken, - address _user - ) - external - view - returns (uint256 balanceInP2P, uint256 balanceOnPool, uint256 totalBalance); - - function getUserMaxCapacitiesForAsset( - address _user, - address _poolToken - ) - external - view - returns (uint256 withdrawable, uint256 borrowable); - - function getUserHypotheticalBalanceStates( - address _user, - address _poolToken, - uint256 _withdrawnAmount, - uint256 _borrowedAmount - ) - external - view - returns (Types.LiquidityData memory assetData); - - function getUserHypotheticalHealthFactor( - address _user, - address _poolToken, - uint256 _withdrawnAmount, - uint256 _borrowedAmount - ) - external - view - returns (uint256 healthFactor); - - function getUserLiquidityDataForAsset( - address _user, - address _poolToken, - address _oracle - ) - external - view - returns (Types.AssetLiquidityData memory assetData); - - function isLiquidatable(address _user) external view returns (bool); - - function isLiquidatable(address _user, address _poolToken) external view returns (bool); - - function computeLiquidationRepayAmount( - address _user, - address _poolTokenBorrowed, - address _poolTokenCollateral - ) - external - view - returns (uint256 toRepay); - - /// RATES /// - - function getNextUserSupplyRatePerYear( - address _poolToken, - address _user, - uint256 _amount - ) - external - view - returns ( - uint256 nextSupplyRatePerYear, - uint256 balanceInP2P, - uint256 balanceOnPool, - uint256 totalBalance - ); - - function getNextUserBorrowRatePerYear( - address _poolToken, - address _user, - uint256 _amount - ) - external - view - returns ( - uint256 nextBorrowRatePerYear, - uint256 balanceInP2P, - uint256 balanceOnPool, - uint256 totalBalance - ); - - function getCurrentUserSupplyRatePerYear( - address _poolToken, - address _user - ) - external - view - returns (uint256); - - function getCurrentUserBorrowRatePerYear( - address _poolToken, - address _user - ) - external - view - returns (uint256); - - function getAverageSupplyRatePerYear(address _poolToken) - external - view - returns (uint256 avgSupplyRatePerYear, uint256 p2pSupplyAmount, uint256 poolSupplyAmount); - - function getAverageBorrowRatePerYear(address _poolToken) - external - view - returns (uint256 avgBorrowRatePerYear, uint256 p2pBorrowAmount, uint256 poolBorrowAmount); - - function getRatesPerYear(address _poolToken) - external - view - returns ( - uint256 p2pSupplyRate, - uint256 p2pBorrowRate, - uint256 poolSupplyRate, - uint256 poolBorrowRate - ); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV3.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV3.sol deleted file mode 100644 index c61d211..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV3.sol +++ /dev/null @@ -1,236 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity ^0.8.10; - -import { Types } from "./MorphoTypesAaveV3.sol"; - -interface IMorphoGetters { - function DOMAIN_SEPARATOR() external view returns (bytes32); - function pool() external view returns (address); - function addressesProvider() external view returns (address); - function eModeCategoryId() external view returns (uint256); - - function market(address underlying) external view returns (Types.Market memory); - function marketsCreated() external view returns (address[] memory); - - function scaledCollateralBalance( - address underlying, - address user - ) - external - view - returns (uint256); - function scaledP2PBorrowBalance( - address underlying, - address user - ) - external - view - returns (uint256); - function scaledP2PSupplyBalance( - address underlying, - address user - ) - external - view - returns (uint256); - function scaledPoolBorrowBalance( - address underlying, - address user - ) - external - view - returns (uint256); - function scaledPoolSupplyBalance( - address underlying, - address user - ) - external - view - returns (uint256); - - function supplyBalance(address underlying, address user) external view returns (uint256); - function borrowBalance(address underlying, address user) external view returns (uint256); - function collateralBalance(address underlying, address user) external view returns (uint256); - - function userCollaterals(address user) external view returns (address[] memory); - function userBorrows(address user) external view returns (address[] memory); - - function isManaging(address delegator, address manager) external view returns (bool); - function userNonce(address user) external view returns (uint256); - - function defaultIterations() external view returns (Types.Iterations memory); - function positionsManager() external view returns (address); - function rewardsManager() external view returns (address); - function treasuryVault() external view returns (address); - - function isClaimRewardsPaused() external view returns (bool); - - function updatedIndexes(address underlying) external view returns (Types.Indexes256 memory); - function liquidityData(address user) external view returns (Types.LiquidityData memory); - function getNext( - address underlying, - Types.Position position, - address user - ) - external - view - returns (address); - function getBucketsMask( - address underlying, - Types.Position position - ) - external - view - returns (uint256); -} - -interface IMorphoSetters { - function createMarket( - address underlying, - uint16 reserveFactor, - uint16 p2pIndexCursor - ) - external; - function increaseP2PDeltas(address underlying, uint256 amount) external; - function claimToTreasury(address[] calldata underlyings, uint256[] calldata amounts) external; - - function setPositionsManager(address positionsManager) external; - function setRewardsManager(address rewardsManager) external; - function setTreasuryVault(address treasuryVault) external; - function setDefaultIterations(Types.Iterations memory defaultIterations) external; - function setP2PIndexCursor(address underlying, uint16 p2pIndexCursor) external; - function setReserveFactor(address underlying, uint16 newReserveFactor) external; - - function setIsClaimRewardsPaused(bool isPaused) external; - function setIsPaused(address underlying, bool isPaused) external; - function setIsPausedForAllMarkets(bool isPaused) external; - function setIsSupplyPaused(address underlying, bool isPaused) external; - function setIsSupplyCollateralPaused(address underlying, bool isPaused) external; - function setIsBorrowPaused(address underlying, bool isPaused) external; - function setIsRepayPaused(address underlying, bool isPaused) external; - function setIsWithdrawPaused(address underlying, bool isPaused) external; - function setIsWithdrawCollateralPaused(address underlying, bool isPaused) external; - function setIsLiquidateBorrowPaused(address underlying, bool isPaused) external; - function setIsLiquidateCollateralPaused(address underlying, bool isPaused) external; - function setIsP2PDisabled(address underlying, bool isP2PDisabled) external; - function setIsDeprecated(address underlying, bool isDeprecated) external; -} - -interface IMorphoAaveV3 is IMorphoGetters, IMorphoSetters { - function initialize( - address addressesProvider, - uint8 eModeCategoryId, - address newPositionsManager, - Types.Iterations memory newDefaultIterations - ) - external; - - function supply( - address underlying, - uint256 amount, - address onBehalf, - uint256 maxIterations - ) - external - returns (uint256 supplied); - function supplyWithPermit( - address underlying, - uint256 amount, - address onBehalf, - uint256 maxIterations, - uint256 deadline, - Types.Signature calldata signature - ) - external - returns (uint256 supplied); - function supplyCollateral( - address underlying, - uint256 amount, - address onBehalf - ) - external - returns (uint256 supplied); - function supplyCollateralWithPermit( - address underlying, - uint256 amount, - address onBehalf, - uint256 deadline, - Types.Signature calldata signature - ) - external - returns (uint256 supplied); - - function borrow( - address underlying, - uint256 amount, - address onBehalf, - address receiver, - uint256 maxIterations - ) - external - returns (uint256 borrowed); - - function repay( - address underlying, - uint256 amount, - address onBehalf - ) - external - returns (uint256 repaid); - function repayWithPermit( - address underlying, - uint256 amount, - address onBehalf, - uint256 deadline, - Types.Signature calldata signature - ) - external - returns (uint256 repaid); - - function withdraw( - address underlying, - uint256 amount, - address onBehalf, - address receiver, - uint256 maxIterations - ) - external - returns (uint256 withdrawn); - function withdrawCollateral( - address underlying, - uint256 amount, - address onBehalf, - address receiver - ) - external - returns (uint256 withdrawn); - - function approveManager(address manager, bool isAllowed) external; - function approveManagerWithSig( - address delegator, - address manager, - bool isAllowed, - uint256 nonce, - uint256 deadline, - Types.Signature calldata signature - ) - external; - - function isManagedBy(address delegator, address manager) external view returns (bool); - - function liquidate( - address underlyingBorrowed, - address underlyingCollateral, - address user, - uint256 amount - ) - external - returns (uint256 repaid, uint256 seized); - - function claimRewards( - address[] calldata assets, - address onBehalf - ) - external - returns (address[] memory rewardTokens, uint256[] memory claimedAmounts); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IRewardsDistributor.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IRewardsDistributor.sol deleted file mode 100644 index 676f222..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/IRewardsDistributor.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IRewardsDistributor { - function claimed(address account) external view returns (uint256); - - function claim(address _account, uint256 _claimable, bytes32[] calldata _proof) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypes.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypes.sol deleted file mode 100644 index 6879fc1..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypes.sol +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: GNU AGPLv3 -pragma solidity ^0.8.0; - -/// @title Types. -/// @author Morpho Labs. -/// @custom:contact security@morpho.xyz -/// @dev Common types and structs used in Morpho contracts. -library Types { - /// ENUMS /// - - enum PositionType { - SUPPLIERS_IN_P2P, - SUPPLIERS_ON_POOL, - BORROWERS_IN_P2P, - BORROWERS_ON_POOL - } - - /// STRUCTS /// - - struct SupplyBalance { - uint256 inP2P; // In peer-to-peer supply scaled unit, a unit that grows in underlying value, - // to keep track of the interests earned by suppliers in peer-to-peer. Multiply by the - // peer-to-peer supply index to get the underlying amount. - uint256 onPool; // In pool supply scaled unit. Multiply by the pool supply index to get the - // underlying amount. - } - - struct BorrowBalance { - uint256 inP2P; // In peer-to-peer borrow scaled unit, a unit that grows in underlying value, - // to keep track of the interests paid by borrowers in peer-to-peer. Multiply by the - // peer-to-peer borrow index to get the underlying amount. - uint256 onPool; // In pool borrow scaled unit, a unit that grows in value, to keep track of - // the debt increase when borrowers are on Aave. Multiply by the pool borrow index to - // get the underlying amount. - } - - struct Indexes { - uint256 p2pSupplyIndex; // The peer-to-peer supply index (in ray), used to multiply the - // scaled peer-to-peer supply balance and get the peer-to-peer supply balance (in - // underlying). - uint256 p2pBorrowIndex; // The peer-to-peer borrow index (in ray), used to multiply the - // scaled peer-to-peer borrow balance and get the peer-to-peer borrow balance (in - // underlying). - uint256 poolSupplyIndex; // The pool supply index (in ray), used to multiply the scaled pool - // supply balance and get the pool supply balance (in underlying). - uint256 poolBorrowIndex; // The pool borrow index (in ray), used to multiply the scaled pool - // borrow balance and get the pool borrow balance (in underlying). - } - - // Max gas to consume during the matching process for supply, borrow, withdraw and repay - // functions. - struct MaxGasForMatching { - uint64 supply; - uint64 borrow; - uint64 withdraw; - uint64 repay; - } - - struct Delta { - uint256 p2pSupplyDelta; // Difference between the stored peer-to-peer supply amount and the - // real peer-to-peer supply amount (in pool supply unit). - uint256 p2pBorrowDelta; // Difference between the stored peer-to-peer borrow amount and the - // real peer-to-peer borrow amount (in pool borrow unit). - uint256 p2pSupplyAmount; // Sum of all stored peer-to-peer supply (in peer-to-peer supply - // unit). - uint256 p2pBorrowAmount; // Sum of all stored peer-to-peer borrow (in peer-to-peer borrow - // unit). - } - - struct AssetLiquidityData { - uint256 decimals; // The number of decimals of the underlying token. - uint256 tokenUnit; // The token unit considering its decimals. - uint256 liquidationThreshold; // The liquidation threshold applied on this token (in basis - // point). - uint256 ltv; // The LTV applied on this token (in basis point). - uint256 underlyingPrice; // The price of the token (in ETH). - uint256 collateralEth; // The collateral value of the asset (in ETH). - uint256 debtEth; // The debt value of the asset (in ETH). - } - - struct LiquidityData { - uint256 collateralEth; // The collateral value (in ETH). - uint256 borrowableEth; // The maximum debt value allowed to borrow (in ETH). - uint256 maxDebtEth; // The maximum debt value allowed before being liquidatable (in ETH). - uint256 debtEth; // The debt value (in ETH). - } - - // Variables are packed together to save gas (will not exceed their limit during Morpho's - // lifetime). - struct PoolIndexes { - uint32 lastUpdateTimestamp; // The last time the local pool and peer-to-peer indexes were - // updated. - uint112 poolSupplyIndex; // Last pool supply index. Note that for the stEth market, the pool - // supply index is tweaked to take into account the staking rewards. - uint112 poolBorrowIndex; // Last pool borrow index. Note that for the stEth market, the pool - // borrow index is tweaked to take into account the staking rewards. - } - - struct Market { - address underlyingToken; // The address of the market's underlying token. - uint16 reserveFactor; // Proportion of the additional interest earned being matched - // peer-to-peer on Morpho compared to being on the pool. It is sent to the DAO for each - // market. The default value is 0. In basis point (100% = 10 000). - uint16 p2pIndexCursor; // Position of the peer-to-peer rate in the pool's spread. Determine - // the weights of the weighted arithmetic average in the indexes computations ((1 - - // p2pIndexCursor) * r^S + p2pIndexCursor * r^B) (in basis point). - bool isCreated; // Whether or not this market is created. - bool isPaused; // Deprecated. - bool isPartiallyPaused; // Deprecated. - bool isP2PDisabled; // Whether the peer-to-peer market is open or not. - } - - struct MarketPauseStatus { - bool isSupplyPaused; // Whether the supply is paused or not. - bool isBorrowPaused; // Whether the borrow is paused or not - bool isWithdrawPaused; // Whether the withdraw is paused or not. Note that a "withdraw" is - // still possible using a liquidation (if not paused). - bool isRepayPaused; // Whether the repay is paused or not. Note that a "repay" is still - // possible using a liquidation (if not paused). - bool isLiquidateCollateralPaused; // Whether the liquidation on this market as collateral is - // paused or not. - bool isLiquidateBorrowPaused; // Whether the liquidatation on this market as borrow is - // paused or not. - bool isDeprecated; // Whether a market is deprecated or not. - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypesAaveV3.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypesAaveV3.sol deleted file mode 100644 index 707d712..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/morpho/MorphoTypesAaveV3.sol +++ /dev/null @@ -1,991 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity ^0.8.10; - -library BucketDLL { - /// STRUCTS /// - - struct Account { - address prev; - address next; - } - - struct List { - mapping(address => Account) accounts; - } - - /// INTERNAL /// - - /// @notice Returns the address at the head of the `_list`. - /// @param _list The list from which to get the head. - /// @return The address of the head. - function getHead(List storage _list) internal view returns (address) { - return _list.accounts[address(0)].next; - } - - /// @notice Returns the address at the tail of the `_list`. - /// @param _list The list from which to get the tail. - /// @return The address of the tail. - function getTail(List storage _list) internal view returns (address) { - return _list.accounts[address(0)].prev; - } - - /// @notice Returns the next id address from the current `_id`. - /// @param _list The list to search in. - /// @param _id The address of the current account. - /// @return The address of the next account. - function getNext(List storage _list, address _id) internal view returns (address) { - return _list.accounts[_id].next; - } - - /// @notice Returns the previous id address from the current `_id`. - /// @param _list The list to search in. - /// @param _id The address of the current account. - /// @return The address of the previous account. - function getPrev(List storage _list, address _id) internal view returns (address) { - return _list.accounts[_id].prev; - } - - /// @notice Removes an account of the `_list`. - /// @dev This function should not be called with `_id` equal to address 0. - /// @param _list The list to search in. - /// @param _id The address of the account. - /// @return Whether the bucket is empty after removal. - function remove(List storage _list, address _id) internal returns (bool) { - Account memory account = _list.accounts[_id]; - address prev = account.prev; - address next = account.next; - - _list.accounts[prev].next = next; - _list.accounts[next].prev = prev; - - delete _list.accounts[_id]; - - return (prev == address(0) && next == address(0)); - } - - /// @notice Inserts an account in the `_list`. - /// @dev This function should not be called with `_id` equal to address 0. - /// @param _list The list to search in. - /// @param _id The address of the account. - /// @param _head Tells whether to insert at the head or at the tail of the list. - /// @return Whether the bucket was empty before insertion. - function insert(List storage _list, address _id, bool _head) internal returns (bool) { - if (_head) { - address head = _list.accounts[address(0)].next; - _list.accounts[address(0)].next = _id; - _list.accounts[head].prev = _id; - _list.accounts[_id].next = head; - return head == address(0); - } else { - address tail = _list.accounts[address(0)].prev; - _list.accounts[address(0)].prev = _id; - _list.accounts[tail].next = _id; - _list.accounts[_id].prev = tail; - return tail == address(0); - } - } -} - -library LogarithmicBuckets { - using BucketDLL for BucketDLL.List; - - struct Buckets { - mapping(uint256 => BucketDLL.List) buckets; - mapping(address => uint256) valueOf; - uint256 bucketsMask; - } - - /// ERRORS /// - - /// @notice Thrown when the address is zero at insertion. - error ZeroAddress(); - - /// @notice Thrown when 0 value is inserted. - error ZeroValue(); - - /// INTERNAL /// - - /// @notice Updates an account in the `_buckets`. - /// @param _buckets The buckets to update. - /// @param _id The address of the account. - /// @param _newValue The new value of the account. - /// @param _head Indicates whether to insert the new values at the head or at the tail of the - /// buckets list. - function update( - Buckets storage _buckets, - address _id, - uint256 _newValue, - bool _head - ) - internal - { - if (_id == address(0)) revert ZeroAddress(); - uint256 value = _buckets.valueOf[_id]; - _buckets.valueOf[_id] = _newValue; - - if (value == 0) { - if (_newValue == 0) revert ZeroValue(); - _insert(_buckets, _id, computeBucket(_newValue), _head); - return; - } - - uint256 currentBucket = computeBucket(value); - if (_newValue == 0) { - _remove(_buckets, _id, currentBucket); - return; - } - - uint256 newBucket = computeBucket(_newValue); - if (newBucket != currentBucket) { - _remove(_buckets, _id, currentBucket); - _insert(_buckets, _id, newBucket, _head); - } - } - - /// @notice Returns the address in `_buckets` that is a candidate for matching the value - /// `_value`. - /// @param _buckets The buckets to get the head. - /// @param _value The value to match. - /// @return The address of the head. - function getMatch(Buckets storage _buckets, uint256 _value) internal view returns (address) { - uint256 bucketsMask = _buckets.bucketsMask; - if (bucketsMask == 0) return address(0); - uint256 lowerMask = setLowerBits(_value); - - uint256 next = nextBucket(lowerMask, bucketsMask); - - if (next != 0) return _buckets.buckets[next].getHead(); - - uint256 prev = prevBucket(lowerMask, bucketsMask); - - return _buckets.buckets[prev].getHead(); - } - - /// PRIVATE /// - - /// @notice Removes an account in the `_buckets`. - /// @dev Does not update the value. - /// @param _buckets The buckets to modify. - /// @param _id The address of the account to remove. - /// @param _bucket The mask of the bucket where to remove. - function _remove(Buckets storage _buckets, address _id, uint256 _bucket) private { - if (_buckets.buckets[_bucket].remove(_id)) _buckets.bucketsMask &= ~_bucket; - } - - /// @notice Inserts an account in the `_buckets`. - /// @dev Expects that `_id` != 0. - /// @dev Does not update the value. - /// @param _buckets The buckets to modify. - /// @param _id The address of the account to update. - /// @param _bucket The mask of the bucket where to insert. - /// @param _head Whether to insert at the head or at the tail of the list. - function _insert(Buckets storage _buckets, address _id, uint256 _bucket, bool _head) private { - if (_buckets.buckets[_bucket].insert(_id, _head)) _buckets.bucketsMask |= _bucket; - } - - /// PURE HELPERS /// - - /// @notice Returns the bucket in which the given value would fall. - function computeBucket(uint256 _value) internal pure returns (uint256) { - uint256 lowerMask = setLowerBits(_value); - return lowerMask ^ (lowerMask >> 1); - } - - /// @notice Sets all the bits lower than (or equal to) the highest bit in the input. - /// @dev This is the same as rounding the input the nearest upper value of the form `2 ** n - - /// 1`. - function setLowerBits(uint256 x) internal pure returns (uint256 y) { - assembly { - x := or(x, shr(1, x)) - x := or(x, shr(2, x)) - x := or(x, shr(4, x)) - x := or(x, shr(8, x)) - x := or(x, shr(16, x)) - x := or(x, shr(32, x)) - x := or(x, shr(64, x)) - y := or(x, shr(128, x)) - } - } - - /// @notice Returns the following bucket which contains greater values. - /// @dev The bucket returned is the lowest that is in `bucketsMask` and not in `lowerMask`. - function nextBucket( - uint256 lowerMask, - uint256 bucketsMask - ) - internal - pure - returns (uint256 bucket) - { - assembly { - let higherBucketsMask := and(not(lowerMask), bucketsMask) - bucket := and(higherBucketsMask, add(not(higherBucketsMask), 1)) - } - } - - /// @notice Returns the preceding bucket which contains smaller values. - /// @dev The bucket returned is the highest that is in both `bucketsMask` and `lowerMask`. - function prevBucket(uint256 lowerMask, uint256 bucketsMask) internal pure returns (uint256) { - uint256 lowerBucketsMask = setLowerBits(lowerMask & bucketsMask); - return lowerBucketsMask ^ (lowerBucketsMask >> 1); - } -} - -library DataTypesAaveV3 { - struct ReserveData { - //stores the reserve configuration - ReserveConfigurationMap configuration; - //the liquidity index. Expressed in ray - uint128 liquidityIndex; - //the current supply rate. Expressed in ray - uint128 currentLiquidityRate; - //variable borrow index. Expressed in ray - uint128 variableBorrowIndex; - //the current variable borrow rate. Expressed in ray - uint128 currentVariableBorrowRate; - //the current stable borrow rate. Expressed in ray - uint128 currentStableBorrowRate; - //timestamp of last update - uint40 lastUpdateTimestamp; - //the id of the reserve. Represents the position in the list of the active reserves - uint16 id; - //aToken address - address aTokenAddress; - //stableDebtToken address - address stableDebtTokenAddress; - //variableDebtToken address - address variableDebtTokenAddress; - //address of the interest rate strategy - address interestRateStrategyAddress; - //the current treasury balance, scaled - uint128 accruedToTreasury; - //the outstanding unbacked aTokens minted through the bridging feature - uint128 unbacked; - //the outstanding debt borrowed against this asset in isolation mode - uint128 isolationModeTotalDebt; - } - - struct ReserveConfigurationMap { - //bit 0-15: LTV - //bit 16-31: Liq. threshold - //bit 32-47: Liq. bonus - //bit 48-55: Decimals - //bit 56: reserve is active - //bit 57: reserve is frozen - //bit 58: borrowing is enabled - //bit 59: stable rate borrowing enabled - //bit 60: asset is paused - //bit 61: borrowing in isolation mode is enabled - //bit 62-63: reserved - //bit 64-79: reserve factor - //bit 80-115 borrow cap in whole tokens, borrowCap == 0 => no cap - //bit 116-151 supply cap in whole tokens, supplyCap == 0 => no cap - //bit 152-167 liquidation protocol fee - //bit 168-175 eMode category - //bit 176-211 unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled - //bit 212-251 debt ceiling for isolation mode with - // (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals - //bit 252-255 unused - uint256 data; - } - - struct UserConfigurationMap { - /** - * @dev Bitmap of the users collaterals and borrows. It is divided in pairs of bits, one - * pair per asset. - * The first bit indicates if an asset is used as collateral by the user, the second whether - * an - * asset is borrowed by the user. - */ - uint256 data; - } - - struct EModeCategory { - // each eMode category has a custom ltv and liquidation threshold - uint16 ltv; - uint16 liquidationThreshold; - uint16 liquidationBonus; - // each eMode category may or may not have a custom oracle to override the individual assets - // price oracles - address priceSource; - string label; - } - - enum InterestRateMode { - NONE, - STABLE, - VARIABLE - } - - struct ReserveCache { - uint256 currScaledVariableDebt; - uint256 nextScaledVariableDebt; - uint256 currPrincipalStableDebt; - uint256 currAvgStableBorrowRate; - uint256 currTotalStableDebt; - uint256 nextAvgStableBorrowRate; - uint256 nextTotalStableDebt; - uint256 currLiquidityIndex; - uint256 nextLiquidityIndex; - uint256 currVariableBorrowIndex; - uint256 nextVariableBorrowIndex; - uint256 currLiquidityRate; - uint256 currVariableBorrowRate; - uint256 reserveFactor; - ReserveConfigurationMap reserveConfiguration; - address aTokenAddress; - address stableDebtTokenAddress; - address variableDebtTokenAddress; - uint40 reserveLastUpdateTimestamp; - uint40 stableDebtLastUpdateTimestamp; - } - - struct ExecuteLiquidationCallParams { - uint256 reservesCount; - uint256 debtToCover; - address collateralAsset; - address debtAsset; - address user; - bool receiveAToken; - address priceOracle; - uint8 userEModeCategory; - address priceOracleSentinel; - } - - struct ExecuteSupplyParams { - address asset; - uint256 amount; - address onBehalfOf; - uint16 referralCode; - } - - struct ExecuteBorrowParams { - address asset; - address user; - address onBehalfOf; - uint256 amount; - InterestRateMode interestRateMode; - uint16 referralCode; - bool releaseUnderlying; - uint256 maxStableRateBorrowSizePercent; - uint256 reservesCount; - address oracle; - uint8 userEModeCategory; - address priceOracleSentinel; - } - - struct ExecuteRepayParams { - address asset; - uint256 amount; - InterestRateMode interestRateMode; - address onBehalfOf; - bool useATokens; - } - - struct ExecuteWithdrawParams { - address asset; - uint256 amount; - address to; - uint256 reservesCount; - address oracle; - uint8 userEModeCategory; - } - - struct ExecuteSetUserEModeParams { - uint256 reservesCount; - address oracle; - uint8 categoryId; - } - - struct FinalizeTransferParams { - address asset; - address from; - address to; - uint256 amount; - uint256 balanceFromBefore; - uint256 balanceToBefore; - uint256 reservesCount; - address oracle; - uint8 fromEModeCategory; - } - - struct FlashloanParams { - address receiverAddress; - address[] assets; - uint256[] amounts; - uint256[] interestRateModes; - address onBehalfOf; - bytes params; - uint16 referralCode; - uint256 flashLoanPremiumToProtocol; - uint256 flashLoanPremiumTotal; - uint256 maxStableRateBorrowSizePercent; - uint256 reservesCount; - address addressesProvider; - uint8 userEModeCategory; - bool isAuthorizedFlashBorrower; - } - - struct FlashloanSimpleParams { - address receiverAddress; - address asset; - uint256 amount; - bytes params; - uint16 referralCode; - uint256 flashLoanPremiumToProtocol; - uint256 flashLoanPremiumTotal; - } - - struct FlashLoanRepaymentParams { - uint256 amount; - uint256 totalPremium; - uint256 flashLoanPremiumToProtocol; - address asset; - address receiverAddress; - uint16 referralCode; - } - - struct CalculateUserAccountDataParams { - UserConfigurationMap userConfig; - uint256 reservesCount; - address user; - address oracle; - uint8 userEModeCategory; - } - - struct ValidateBorrowParams { - ReserveCache reserveCache; - UserConfigurationMap userConfig; - address asset; - address userAddress; - uint256 amount; - InterestRateMode interestRateMode; - uint256 maxStableLoanPercent; - uint256 reservesCount; - address oracle; - uint8 userEModeCategory; - address priceOracleSentinel; - bool isolationModeActive; - address isolationModeCollateralAddress; - uint256 isolationModeDebtCeiling; - } - - struct ValidateLiquidationCallParams { - ReserveCache debtReserveCache; - uint256 totalDebt; - uint256 healthFactor; - address priceOracleSentinel; - } - - struct CalculateInterestRatesParams { - uint256 unbacked; - uint256 liquidityAdded; - uint256 liquidityTaken; - uint256 totalStableDebt; - uint256 totalVariableDebt; - uint256 averageStableBorrowRate; - uint256 reserveFactor; - address reserve; - address aToken; - } - - struct InitReserveParams { - address asset; - address aTokenAddress; - address stableDebtAddress; - address variableDebtAddress; - address interestRateStrategyAddress; - uint16 reservesCount; - uint16 maxNumberReserves; - } -} - -interface IPriceOracleGetter { - /** - * @notice Returns the base currency address - * @dev Address 0x0 is reserved for USD as base currency. - * @return Returns the base currency address. - */ - function BASE_CURRENCY() external view returns (address); - - /** - * @notice Returns the base currency unit - * @dev 1 ether for ETH, 1e8 for USD. - * @return Returns the base currency unit. - */ - function BASE_CURRENCY_UNIT() external view returns (uint256); - - /** - * @notice Returns the asset price in the base currency - * @param asset The address of the asset - * @return The price of the asset - */ - function getAssetPrice(address asset) external view returns (uint256); -} - -interface IAavePoolAddressesProvider { - /** - * @dev Emitted when the market identifier is updated. - * @param oldMarketId The old id of the market - * @param newMarketId The new id of the market - */ - event MarketIdSet(string indexed oldMarketId, string indexed newMarketId); - - /** - * @dev Emitted when the pool is updated. - * @param oldAddress The old address of the Pool - * @param newAddress The new address of the Pool - */ - event PoolUpdated(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when the pool configurator is updated. - * @param oldAddress The old address of the PoolConfigurator - * @param newAddress The new address of the PoolConfigurator - */ - event PoolConfiguratorUpdated(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when the price oracle is updated. - * @param oldAddress The old address of the PriceOracle - * @param newAddress The new address of the PriceOracle - */ - event PriceOracleUpdated(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when the ACL manager is updated. - * @param oldAddress The old address of the ACLManager - * @param newAddress The new address of the ACLManager - */ - event ACLManagerUpdated(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when the ACL admin is updated. - * @param oldAddress The old address of the ACLAdmin - * @param newAddress The new address of the ACLAdmin - */ - event ACLAdminUpdated(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when the price oracle sentinel is updated. - * @param oldAddress The old address of the PriceOracleSentinel - * @param newAddress The new address of the PriceOracleSentinel - */ - event PriceOracleSentinelUpdated(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when the pool data provider is updated. - * @param oldAddress The old address of the PoolDataProvider - * @param newAddress The new address of the PoolDataProvider - */ - event PoolDataProviderUpdated(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when a new proxy is created. - * @param id The identifier of the proxy - * @param proxyAddress The address of the created proxy contract - * @param implementationAddress The address of the implementation contract - */ - event ProxyCreated( - bytes32 indexed id, address indexed proxyAddress, address indexed implementationAddress - ); - - /** - * @dev Emitted when a new non-proxied contract address is registered. - * @param id The identifier of the contract - * @param oldAddress The address of the old contract - * @param newAddress The address of the new contract - */ - event AddressSet(bytes32 indexed id, address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when the implementation of the proxy registered with id is updated - * @param id The identifier of the contract - * @param proxyAddress The address of the proxy contract - * @param oldImplementationAddress The address of the old implementation contract - * @param newImplementationAddress The address of the new implementation contract - */ - event AddressSetAsProxy( - bytes32 indexed id, - address indexed proxyAddress, - address oldImplementationAddress, - address indexed newImplementationAddress - ); - - /** - * @notice Returns the id of the Aave market to which this contract points to. - * @return The market id - */ - function getMarketId() external view returns (string memory); - - /** - * @notice Associates an id with a specific PoolAddressesProvider. - * @dev This can be used to create an onchain registry of PoolAddressesProviders to - * identify and validate multiple Aave markets. - * @param newMarketId The market id - */ - function setMarketId(string calldata newMarketId) external; - - /** - * @notice Returns an address by its identifier. - * @dev The returned address might be an EOA or a contract, potentially proxied - * @dev It returns ZERO if there is no registered address with the given id - * @param id The id - * @return The address of the registered for the specified id - */ - function getAddress(bytes32 id) external view returns (address); - - /** - * @notice General function to update the implementation of a proxy registered with - * certain `id`. If there is no proxy registered, it will instantiate one and - * set as implementation the `newImplementationAddress`. - * @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit - * setter function, in order to avoid unexpected consequences - * @param id The id - * @param newImplementationAddress The address of the new implementation - */ - function setAddressAsProxy(bytes32 id, address newImplementationAddress) external; - - /** - * @notice Sets an address for an id replacing the address saved in the addresses map. - * @dev IMPORTANT Use this function carefully, as it will do a hard replacement - * @param id The id - * @param newAddress The address to set - */ - function setAddress(bytes32 id, address newAddress) external; - - /** - * @notice Returns the address of the Pool proxy. - * @return The Pool proxy address - */ - function getPool() external view returns (address); - - /** - * @notice Updates the implementation of the Pool, or creates a proxy - * setting the new `pool` implementation when the function is called for the first time. - * @param newPoolImpl The new Pool implementation - */ - function setPoolImpl(address newPoolImpl) external; - - /** - * @notice Returns the address of the PoolConfigurator proxy. - * @return The PoolConfigurator proxy address - */ - function getPoolConfigurator() external view returns (address); - - /** - * @notice Updates the implementation of the PoolConfigurator, or creates a proxy - * setting the new `PoolConfigurator` implementation when the function is called for the first - * time. - * @param newPoolConfiguratorImpl The new PoolConfigurator implementation - */ - function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external; - - /** - * @notice Returns the address of the price oracle. - * @return The address of the PriceOracle - */ - function getPriceOracle() external view returns (address); - - /** - * @notice Updates the address of the price oracle. - * @param newPriceOracle The address of the new PriceOracle - */ - function setPriceOracle(address newPriceOracle) external; - - /** - * @notice Returns the address of the ACL manager. - * @return The address of the ACLManager - */ - function getACLManager() external view returns (address); - - /** - * @notice Updates the address of the ACL manager. - * @param newAclManager The address of the new ACLManager - */ - function setACLManager(address newAclManager) external; - - /** - * @notice Returns the address of the ACL admin. - * @return The address of the ACL admin - */ - function getACLAdmin() external view returns (address); - - /** - * @notice Updates the address of the ACL admin. - * @param newAclAdmin The address of the new ACL admin - */ - function setACLAdmin(address newAclAdmin) external; - - /** - * @notice Returns the address of the price oracle sentinel. - * @return The address of the PriceOracleSentinel - */ - function getPriceOracleSentinel() external view returns (address); - - /** - * @notice Updates the address of the price oracle sentinel. - * @param newPriceOracleSentinel The address of the new PriceOracleSentinel - */ - function setPriceOracleSentinel(address newPriceOracleSentinel) external; - - /** - * @notice Returns the address of the data provider. - * @return The address of the DataProvider - */ - function getPoolDataProvider() external view returns (address); - - /** - * @notice Updates the address of the data provider. - * @param newDataProvider The address of the new DataProvider - */ - function setPoolDataProvider(address newDataProvider) external; -} - -interface IAaveOracle is IPriceOracleGetter { - /** - * @dev Emitted after the base currency is set - * @param baseCurrency The base currency of used for price quotes - * @param baseCurrencyUnit The unit of the base currency - */ - event BaseCurrencySet(address indexed baseCurrency, uint256 baseCurrencyUnit); - - /** - * @dev Emitted after the price source of an asset is updated - * @param asset The address of the asset - * @param source The price source of the asset - */ - event AssetSourceUpdated(address indexed asset, address indexed source); - - /** - * @dev Emitted after the address of fallback oracle is updated - * @param fallbackOracle The address of the fallback oracle - */ - event FallbackOracleUpdated(address indexed fallbackOracle); - - /** - * @notice Returns the PoolAddressesProvider - * @return The address of the PoolAddressesProvider contract - */ - function ADDRESSES_PROVIDER() external view returns (IAavePoolAddressesProvider); - - /** - * @notice Sets or replaces price sources of assets - * @param assets The addresses of the assets - * @param sources The addresses of the price sources - */ - function setAssetSources(address[] calldata assets, address[] calldata sources) external; - - /** - * @notice Sets the fallback oracle - * @param fallbackOracle The address of the fallback oracle - */ - function setFallbackOracle(address fallbackOracle) external; - - /** - * @notice Returns a list of prices from a list of assets addresses - * @param assets The list of assets addresses - * @return The prices of the given assets - */ - function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory); - - /** - * @notice Returns the address of the source for an asset address - * @param asset The address of the asset - * @return The address of the source - */ - function getSourceOfAsset(address asset) external view returns (address); - - /** - * @notice Returns the address of the fallback oracle - * @return The address of the fallback oracle - */ - function getFallbackOracle() external view returns (address); -} - -/// @title Type -/// @author Morpho Labs -/// @custom:contact security@morpho.xyz -/// @notice Library exposing all Types used in Morpho. -library Types { - /* ENUMS */ - - enum Position { - POOL_SUPPLIER, - P2P_SUPPLIER, - POOL_BORROWER, - P2P_BORROWER - } - - /* NESTED STRUCTS */ - - struct MarketSideDelta { - uint256 scaledDelta; // In pool unit. - uint256 scaledP2PTotal; // In peer-to-peer unit. - } - - struct Deltas { - MarketSideDelta supply; - MarketSideDelta borrow; - } - - struct MarketSideIndexes { - uint128 poolIndex; - uint128 p2pIndex; - } - - struct Indexes { - MarketSideIndexes supply; - MarketSideIndexes borrow; - } - - struct PauseStatuses { - bool isP2PDisabled; - bool isSupplyPaused; - bool isSupplyCollateralPaused; - bool isBorrowPaused; - bool isWithdrawPaused; - bool isWithdrawCollateralPaused; - bool isRepayPaused; - bool isLiquidateCollateralPaused; - bool isLiquidateBorrowPaused; - bool isDeprecated; - } - - /* STORAGE STRUCTS */ - - // This market struct is able to be passed into memory. - struct Market { - // SLOT 0-1 - Indexes indexes; - // SLOT 2-5 - Deltas deltas; // 1024 bits - // SLOT 6 - address underlying; // 160 bits - PauseStatuses pauseStatuses; // 80 bits - bool isCollateral; // 8 bits - // SLOT 7 - address variableDebtToken; // 160 bits - uint32 lastUpdateTimestamp; // 32 bits - uint16 reserveFactor; // 16 bits - uint16 p2pIndexCursor; // 16 bits - // SLOT 8 - address aToken; // 160 bits - // SLOT 9 - address stableDebtToken; // 160 bits - // SLOT 10 - uint256 idleSupply; // 256 bits - } - - // Contains storage-only dynamic arrays and mappings. - struct MarketBalances { - LogarithmicBuckets.Buckets poolSuppliers; // In pool unit. - LogarithmicBuckets.Buckets p2pSuppliers; // In peer-to-peer unit. - LogarithmicBuckets.Buckets poolBorrowers; // In pool unit. - LogarithmicBuckets.Buckets p2pBorrowers; // In peer-to-peer unit. - mapping(address => uint256) collateral; // In pool unit. - } - - struct Iterations { - uint128 repay; - uint128 withdraw; - } - - /* STACK AND RETURN STRUCTS */ - - struct LiquidityData { - uint256 borrowable; // The maximum debt value allowed to borrow (in base currency). - uint256 maxDebt; // The maximum debt value allowed before being liquidatable (in base - // currency). - uint256 debt; // The debt value (in base currency). - } - - struct IndexesParams { - MarketSideIndexes256 lastSupplyIndexes; - MarketSideIndexes256 lastBorrowIndexes; - uint256 poolSupplyIndex; // The current pool supply index. - uint256 poolBorrowIndex; // The current pool borrow index. - uint256 reserveFactor; // The reserve factor percentage (10 000 = 100%). - uint256 p2pIndexCursor; // The peer-to-peer index cursor (10 000 = 100%). - Deltas deltas; // The deltas and peer-to-peer amounts. - uint256 proportionIdle; // in ray. - } - - struct GrowthFactors { - uint256 poolSupplyGrowthFactor; // The pool's supply index growth factor (in ray). - uint256 p2pSupplyGrowthFactor; // Peer-to-peer supply index growth factor (in ray). - uint256 poolBorrowGrowthFactor; // The pool's borrow index growth factor (in ray). - uint256 p2pBorrowGrowthFactor; // Peer-to-peer borrow index growth factor (in ray). - } - - struct MarketSideIndexes256 { - uint256 poolIndex; - uint256 p2pIndex; - } - - struct Indexes256 { - MarketSideIndexes256 supply; - MarketSideIndexes256 borrow; - } - - struct Signature { - uint8 v; - bytes32 r; - bytes32 s; - } - - struct MatchingEngineVars { - address underlying; - MarketSideIndexes256 indexes; - uint256 amount; - uint256 maxIterations; - bool borrow; - function (address, address, uint256, uint256, bool) returns (uint256, uint256) updateDS; // This - // function will be used to update the data-structure. - bool demoting; // True for demote, False for promote. - function(uint256, uint256, MarketSideIndexes256 memory, uint256) - pure returns (uint256, uint256, uint256) step; // This function will be used to decide - // whether to use the algorithm for promoting or for demoting. - } - - struct LiquidityVars { - address user; - IAaveOracle oracle; - DataTypesAaveV3.EModeCategory eModeCategory; - } - - struct PromoteVars { - address underlying; - uint256 amount; - uint256 p2pIndex; - uint256 maxIterations; - function(address, uint256, uint256) returns (uint256, uint256) promote; - } - - struct BorrowWithdrawVars { - uint256 onPool; - uint256 inP2P; - uint256 toWithdraw; - uint256 toBorrow; - } - - struct SupplyRepayVars { - uint256 onPool; - uint256 inP2P; - uint256 toSupply; - uint256 toRepay; - } - - struct LiquidateVars { - uint256 closeFactor; - uint256 seized; - } - - struct AmountToSeizeVars { - uint256 liquidationBonus; - uint256 borrowedTokenUnit; - uint256 collateralTokenUnit; - uint256 borrowedPrice; - uint256 collateralPrice; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/IBoostedVaultWithLockup.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/IBoostedVaultWithLockup.sol deleted file mode 100644 index 889bb64..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/IBoostedVaultWithLockup.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IBoostedVaultWithLockup { - function rawBalanceOf(address) external view returns (uint256); - - // @dev Stakes a given amount of the StakingToken for the sender - // @param _amount Units of StakingToken - function stake(uint256 _amount) external; - - // @dev Stakes a given amount of the StakingToken for a given beneficiary - // @param _beneficiary Staked tokens are credited to this address - // @param _amount Units of StakingToken - function stake(address _beneficiary, uint256 _amount) external; - - // @dev Withdraws stake from pool and claims any unlocked rewards. - // Note, this function is costly - the args for _claimRewards - // should be determined off chain and then passed to other fn - function exit() external; - - // @dev Withdraws stake from pool and claims any unlocked rewards. - // @param _first Index of the first array element to claim - // @param _last Index of the last array element to claim - function exit(uint256 _first, uint256 _last) external; - - // @dev Withdraws given stake amount from the pool - // @param _amount Units of the staked token to withdraw - function withdraw(uint256 _amount) external; - - // @dev Claims only the tokens that have been immediately unlocked, not including - // those that are in the lockers. - function claimReward() external; - - // @dev Claims all unlocked rewards for sender. - // Note, this function is costly - the args for _claimRewards - // should be determined off chain and then passed to other fn - function claimRewards() external; - - // @dev Claims all unlocked rewards for sender. Both immediately unlocked - // rewards and also locked rewards past their time lock. - // @param _first Index of the first array element to claim - // @param _last Index of the last array element to claim - function claimRewards(uint256 _first, uint256 _last) external; - - // @dev Pokes a given account to reset the boost - function pokeBoost(address _account) external; - - // @dev Gets the RewardsToken - function getRewardToken() external view returns (address); - - // @dev Gets the last applicable timestamp for this reward period - function lastTimeRewardApplicable() external view returns (uint256); - - // @dev Calculates the amount of unclaimed rewards per token since last update, - // and sums with stored to give the new cumulative reward per token - // @return 'Reward' per staked token - function rewardPerToken() external view returns (uint256); - - // @dev Returned the units of IMMEDIATELY claimable rewards a user has to receive. Note - this - // does NOT include the majority of rewards which will be locked up. - // @param _account User address - // @return Total reward amount earned - function earned(address _account) external view returns (uint256); - - // @dev Calculates all unclaimed reward data, finding both immediately unlocked rewards - // and those that have passed their time lock. - // @param _account User address - // @return amount Total units of unclaimed rewards - // @return first Index of the first userReward that has unlocked - // @return last Index of the last userReward that has unlocked - function unclaimedRewards(address _account) - external - view - returns (uint256 amount, uint256 first, uint256 last); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ISavingsContractV2.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ISavingsContractV2.sol deleted file mode 100644 index 6410152..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ISavingsContractV2.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface ISavingsContractV2 { - // DEPRECATED but still backwards compatible - function redeem(uint256 _amount) external returns (uint256 massetReturned); - - function creditBalances(address) external view returns (uint256); // V1 & V2 (use balanceOf) - - // -------------------------------------------- - - function approve(address, uint256) external; - function depositInterest(uint256 _amount) external; // V1 & V2 - - function depositSavings(uint256 _amount) external returns (uint256 creditsIssued); // V1 & V2 - - function depositSavings( - uint256 _amount, - address _beneficiary - ) - external - returns (uint256 creditsIssued); // V2 - - function redeemCredits(uint256 _amount) external returns (uint256 underlyingReturned); // V2 - - function redeemUnderlying(uint256 _amount) external returns (uint256 creditsBurned); // V2 - - function exchangeRate() external view returns (uint256); // V1 & V2 - - function balanceOfUnderlying(address _user) external view returns (uint256 balance); // V2 - - function underlyingToCredits(uint256 _credits) external view returns (uint256 underlying); // V2 - - function creditsToUnderlying(uint256 _underlying) external view returns (uint256 credits); // V2 -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ImAsset.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ImAsset.sol deleted file mode 100644 index 40c96cb..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/mstable/ImAsset.sol +++ /dev/null @@ -1,151 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; -pragma experimental ABIEncoderV2; - -// Status of the Basset - has it broken its peg? -enum BassetStatus { - Default, - Normal, - BrokenBelowPeg, - BrokenAbovePeg, - Blacklisted, - Liquidating, - Liquidated, - Failed -} - -struct BassetPersonal { - // Address of the bAsset - address addr; - // Address of the bAsset - address integrator; - // An ERC20 can charge transfer fee, for example USDT, DGX tokens. - bool hasTxFee; // takes a byte in storage - // Status of the bAsset - BassetStatus status; -} - -struct BassetData { - // 1 Basset * ratio / ratioScale == x Masset (relative value) - // If ratio == 10e8 then 1 bAsset = 10 mAssets - // A ratio is divised as 10^(18-tokenDecimals) * measurementMultiple(relative value of 1 base - // unit) - uint128 ratio; - // Amount of the Basset that is held in Collateral - uint128 vaultBalance; -} - -interface ImAsset { - // Mint - function mint( - address _input, - uint256 _inputQuantity, - uint256 _minOutputQuantity, - address _recipient - ) - external - returns (uint256 mintOutput); - - function mintMulti( - address[] calldata _inputs, - uint256[] calldata _inputQuantities, - uint256 _minOutputQuantity, - address _recipient - ) - external - returns (uint256 mintOutput); - - function getMintOutput( - address _input, - uint256 _inputQuantity - ) - external - view - returns (uint256 mintOutput); - - function getMintMultiOutput( - address[] calldata _inputs, - uint256[] calldata _inputQuantities - ) - external - view - returns (uint256 mintOutput); - - // Swaps - function swap( - address _input, - address _output, - uint256 _inputQuantity, - uint256 _minOutputQuantity, - address _recipient - ) - external - returns (uint256 swapOutput); - - function getSwapOutput( - address _input, - address _output, - uint256 _inputQuantity - ) - external - view - returns (uint256 swapOutput); - - // Redemption - function redeem( - address _output, - uint256 _mAssetQuantity, - uint256 _minOutputQuantity, - address _recipient - ) - external - returns (uint256 outputQuantity); - - function redeemMasset( - uint256 _mAssetQuantity, - uint256[] calldata _minOutputQuantities, - address _recipient - ) - external - returns (uint256[] memory outputQuantities); - - function redeemExactBassets( - address[] calldata _outputs, - uint256[] calldata _outputQuantities, - uint256 _maxMassetQuantity, - address _recipient - ) - external - returns (uint256 mAssetRedeemed); - - function getRedeemOutput( - address _output, - uint256 _mAssetQuantity - ) - external - view - returns (uint256 bAssetOutput); - - function getRedeemExactBassetsOutput( - address[] calldata _outputs, - uint256[] calldata _outputQuantities - ) - external - view - returns (uint256 mAssetAmount); - - // Views - function getBasket() external view returns (bool, bool); - - function getBasset(address _token) - external - view - returns (BassetPersonal memory personal, BassetData memory data); - - function getBassets() - external - view - returns (BassetPersonal[] memory personal, BassetData[] memory data); - - function bAssetIndexes(address) external view returns (uint8); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IQiDaoRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IQiDaoRegistry.sol deleted file mode 100644 index 7eeed30..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IQiDaoRegistry.sol +++ /dev/null @@ -1,2 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IStablecoin.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IStablecoin.sol deleted file mode 100644 index b6fd804..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/qidao/IStablecoin.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IStablecoin { - function getDebtCeiling() external view returns (uint256); - - function balanceOf(address account) external view returns (uint256); - - function getClosingFee() external view returns (uint256); - - function getOpeningFee() external view returns (uint256); - - function getTokenPriceSource() external view returns (uint256); - - function getEthPriceSource() external view returns (uint256); - - function createVault() external returns (uint256); - - function destroyVault(uint256 vaultID) external; - - function transferVault(uint256 vaultID, address to) external; - - function depositCollateral(uint256 vaultID) external payable; - - function depositCollateral(uint256 vaultID, uint256 amount) external payable; - - function withdrawCollateral(uint256 vaultID, uint256 amount) external; - - function borrowToken(uint256 vaultID, uint256 amount) external; - - function vaultDebt(uint256 vaultId) external view returns (uint256); - - function payBackToken(uint256 vaultID, uint256 amount) external; - - function buyRiskyVault(uint256 vaultID) external; - - function collateral() external view returns (address); - - function tokenOfOwnerByIndex( - address owner, - uint256 index - ) - external - view - returns (uint256 tokenId); - - function vaultCollateral(uint256 vaultId) external view returns (uint256 collAmount); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundController.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundController.sol deleted file mode 100644 index b9f474e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundController.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface IFundController { - function fuseAssets(uint8, string memory) external view returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundManager.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundManager.sol deleted file mode 100644 index 653f90d..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundManager.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface IFundManager { - function depositTo(address to, string memory currencyCode, uint256 amount) external; - function withdraw(string calldata currencyCode, uint256 amount) external returns (uint256); - function getRawFundBalance(string memory currencyCode) external returns (uint256); - function rariFundToken() external view returns (address); - function getFundBalance() external returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundProxy.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundProxy.sol deleted file mode 100644 index 5112045..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFundProxy.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface IFundProxy { - function getRawFundBalancesAndPrices() - external - returns ( - string[] memory, - uint256[] memory, - uint8[][] memory, - uint256[][] memory, - uint256[] memory - ); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFuseAsset.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFuseAsset.sol deleted file mode 100644 index be49e27..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/rari/IFuseAsset.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -interface IFuseAsset { - function getCash() external returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IBasicTokenAdapters.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IBasicTokenAdapters.sol deleted file mode 100644 index f4ba13b..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IBasicTokenAdapters.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IBasicTokenAdapters { - bytes32 public collateralType; - - function decimals() public view virtual returns (uint256); - function collateral() public view virtual returns (address); - function join(address, uint256) public payable virtual; - function exit(address, uint256) public virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ICoinJoin.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ICoinJoin.sol deleted file mode 100644 index 7c9df67..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ICoinJoin.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -abstract contract ICoinJoin { - uint256 public decimals; - - function join(address account, uint256 wad) external virtual; - - function exit(address account, uint256 wad) external virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IFSMWrapper.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IFSMWrapper.sol deleted file mode 100644 index a522364..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IFSMWrapper.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IFSMWrapper { - function getNextResultWithValidity() external view returns (uint256 price, bool valid); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IGetSafes.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IGetSafes.sol deleted file mode 100644 index 3a61962..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IGetSafes.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IGetSafes { - function getSafesAsc( - address manager, - address guy - ) - external - view - virtual - returns (uint256[] memory ids, address[] memory safes, bytes32[] memory collateralTypes); - function getSafesDesc( - address manager, - address guy - ) - external - view - virtual - returns (uint256[] memory ids, address[] memory safes, bytes32[] memory collateralTypes); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IMedianOracle.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IMedianOracle.sol deleted file mode 100644 index c425d26..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IMedianOracle.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IMedianOracle { - function read() external view virtual returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IOracleRelayer.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IOracleRelayer.sol deleted file mode 100644 index 4a3319d..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/IOracleRelayer.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IOracleRelayer { - struct CollateralType { - address orcl; - uint256 safetyCRatio; - } - - mapping(bytes32 => CollateralType) public collateralTypes; - - function redemptionPrice() public virtual returns (uint256); - - uint256 public redemptionRate; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEEngine.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEEngine.sol deleted file mode 100644 index bee8b78..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEEngine.sol +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract ISAFEEngine { - struct SAFE { - uint256 lockedCollateral; - uint256 generatedDebt; - } - - struct CollateralType { - // Total debt issued for this specific collateral type - uint256 debtAmount; // [wad] - // Accumulator for interest accrued on this collateral type - uint256 accumulatedRate; // [ray] - // Floor price at which a SAFE is allowed to generate debt - uint256 safetyPrice; // [ray] - // Maximum amount of debt that can be generated with this collateral type - uint256 debtCeiling; // [rad] - // Minimum amount of debt that must be generated by a SAFE using this collateral - uint256 debtFloor; // [rad] - // Price at which a SAFE gets liquidated - uint256 liquidationPrice; // [ray] - } - - mapping(bytes32 => mapping(address => SAFE)) public safes; - mapping(bytes32 => CollateralType) public collateralTypes; - mapping(bytes32 => mapping(address => uint256)) public tokenCollateral; - - function safeRights(address, address) public view virtual returns (uint256); - function coinBalance(address) public view virtual returns (uint256); - function modifySAFECollateralization( - bytes32, - address, - address, - address, - int256, - int256 - ) - public - virtual; - function approveSAFEModification(address) public virtual; - function transferInternalCoins(address, address, uint256) public virtual; - function transferSAFECollateralAndDebt( - bytes32, - address, - address, - int256, - int256 - ) - public - virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEManager.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEManager.sol deleted file mode 100644 index 7fbc03c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFEManager.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract ISAFEManager { - function lastSAFEID(address) public view virtual returns (uint256); - function safeCan(address, uint256, address) public view virtual returns (uint256); - function collateralTypes(uint256) public view virtual returns (bytes32); - function ownsSAFE(uint256) public view virtual returns (address); - function safes(uint256) public view virtual returns (address); - function safeEngine() public view virtual returns (address); - function openSAFE(bytes32, address) public virtual returns (uint256); - function transferSAFEOwnership(uint256, address) public virtual; - function allowSAFE(uint256, address, uint256) public virtual; - function handlerAllowed(address, uint256) public virtual; - function modifySAFECollateralization(uint256, int256, int256) public virtual; - function transferCollateral(uint256, address, uint256) public virtual; - function transferInternalCoins(uint256, address, uint256) public virtual; - function quitSystem(uint256, address) public virtual; - function enterSystem(address, uint256) public virtual; - function moveSAFE(uint256, uint256) public virtual; - function safeCount(address) public view virtual returns (uint256); - function safei() public view virtual returns (uint256); - function protectSAFE(uint256, address, address) public virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFESaviour.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFESaviour.sol deleted file mode 100644 index 882b7c8..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ISAFESaviour.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract ISAFESaviour { - function deposit(uint256 safeID, uint256 lpTokenAmount) public virtual; - function withdraw(uint256 safeID, uint256 lpTokenAmount, address dst) public virtual; - function lpToken() public view virtual returns (address); - function lpTokenCover(address) public view virtual returns (uint256); - function getReserves(uint256, address) public virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ITaxCollector.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ITaxCollector.sol deleted file mode 100644 index 901fe0c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/reflexer/ITaxCollector.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract ITaxCollector { - struct CollateralType { - uint256 stabilityFee; - uint256 updateTime; - } - - mapping(bytes32 => CollateralType) public collateralTypes; - - function taxSingle(bytes32) public virtual returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/spark/IsDAI.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/spark/IsDAI.sol deleted file mode 100644 index 52746fe..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/spark/IsDAI.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -import "../IERC20.sol"; - -interface IsDAI is IERC20 { - function deposit(uint256 _amount, address _receiver) external; - function mint(uint256 _shares, address _receiver) external; - function withdraw(uint256 _amount, address _receiver, address _owner) external; - function redeem(uint256 _shares, address _receiver, address _owner) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/strategy/ISubStorage.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/strategy/ISubStorage.sol deleted file mode 100644 index 8bd5c8b..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/strategy/ISubStorage.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract ISubStorage { - function updateSubTriggerData( - uint256 _subId, - bytes memory _triggerData, - uint256 _triggerNum - ) - public - virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Factory.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Factory.sol deleted file mode 100644 index a45a9dc..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Factory.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IUniswapV2Factory { - function getPair(address tokenA, address tokenB) external view virtual returns (address pair); - function allPairs(uint256) external view virtual returns (address pair); - function allPairsLength() external view virtual returns (uint256); - function feeTo() external view virtual returns (address); - function feeToSetter() external view virtual returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Pair.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Pair.sol deleted file mode 100644 index 1c692b3..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Pair.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IUniswapV2Pair { - function token0() external view returns (address); - function token1() external view returns (address); - function getReserves() - external - view - returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IQuoter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IQuoter.sol deleted file mode 100644 index 49d924b..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IQuoter.sol +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.8.4; - -/// @title Quoter Interface -/// @notice Supports quoting the calculated amounts from exact input or exact output swaps -/// @dev These functions are not marked view because they rely on calling non-view functions and -/// reverting -/// to compute the result. They are also not gas efficient and should not be called on-chain. -interface IQuoter { - /// @notice Returns the amount out received for a given exact input swap without executing the - /// swap - /// @param path The path of the swap, i.e. each token pair and the pool fee - /// @param amountIn The amount of the first token to swap - /// @return amountOut The amount of the last token that would be received - function quoteExactInput( - bytes memory path, - uint256 amountIn - ) - external - returns (uint256 amountOut); - - /// @notice Returns the amount out received for a given exact input but for a swap of a single - /// pool - /// @param tokenIn The token being swapped in - /// @param tokenOut The token being swapped out - /// @param fee The fee of the token pool to consider for the pair - /// @param amountIn The desired input amount - /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap - /// @return amountOut The amount of `tokenOut` that would be received - function quoteExactInputSingle( - address tokenIn, - address tokenOut, - uint24 fee, - uint256 amountIn, - uint160 sqrtPriceLimitX96 - ) - external - returns (uint256 amountOut); - - /// @notice Returns the amount in required for a given exact output swap without executing the - /// swap - /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be - /// provided in reverse order - /// @param amountOut The amount of the last token to receive - /// @return amountIn The amount of first token required to be paid - function quoteExactOutput( - bytes memory path, - uint256 amountOut - ) - external - returns (uint256 amountIn); - - /// @notice Returns the amount in required to receive the given exact output amount but for a - /// swap of a single pool - /// @param tokenIn The token being swapped in - /// @param tokenOut The token being swapped out - /// @param fee The fee of the token pool to consider for the pair - /// @param amountOut The desired output amount - /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap - /// @return amountIn The amount required as the input for the swap in order to receive - /// `amountOut` - function quoteExactOutputSingle( - address tokenIn, - address tokenOut, - uint24 fee, - uint256 amountOut, - uint160 sqrtPriceLimitX96 - ) - external - returns (uint256 amountIn); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/ISwapRouter.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/ISwapRouter.sol deleted file mode 100644 index f9e95b1..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/ISwapRouter.sol +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.8.4; -pragma abicoder v2; - -import { IUniswapV3SwapCallback } from "./IUniswapV3SwapCallback.sol"; - -/// @title Router token swapping functionality -/// @notice Functions for swapping tokens via Uniswap V3 -interface ISwapRouter is IUniswapV3SwapCallback { - struct ExactInputSingleParams { - address tokenIn; - address tokenOut; - uint24 fee; - address recipient; - uint256 deadline; - uint256 amountIn; - uint256 amountOutMinimum; - uint160 sqrtPriceLimitX96; - } - - /// @notice Swaps `amountIn` of one token for as much as possible of another token - /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in - /// calldata - /// @return amountOut The amount of the received token - function exactInputSingle(ExactInputSingleParams calldata params) - external - payable - returns (uint256 amountOut); - - struct ExactInputParams { - bytes path; - address recipient; - uint256 deadline; - uint256 amountIn; - uint256 amountOutMinimum; - } - - /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified - /// path - /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` - /// in calldata - /// @return amountOut The amount of the received token - function exactInput(ExactInputParams calldata params) - external - payable - returns (uint256 amountOut); - - struct ExactOutputSingleParams { - address tokenIn; - address tokenOut; - uint24 fee; - address recipient; - uint256 deadline; - uint256 amountOut; - uint256 amountInMaximum; - uint160 sqrtPriceLimitX96; - } - - /// @notice Swaps as little as possible of one token for `amountOut` of another token - /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in - /// calldata - /// @return amountIn The amount of the input token - function exactOutputSingle(ExactOutputSingleParams calldata params) - external - payable - returns (uint256 amountIn); - - struct ExactOutputParams { - bytes path; - address recipient; - uint256 deadline; - uint256 amountOut; - uint256 amountInMaximum; - } - - /// @notice Swaps as little as possible of one token for `amountOut` of another along the - /// specified path (reversed) - /// @param params The parameters necessary for the multi-hop swap, encoded as - /// `ExactOutputParams` in calldata - /// @return amountIn The amount of the input token - function exactOutput(ExactOutputParams calldata params) - external - payable - returns (uint256 amountIn); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Factory.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Factory.sol deleted file mode 100644 index 1b762e8..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Factory.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IUniswapV3Factory { - function getPool( - address token0, - address token1, - uint24 fee - ) - external - view - virtual - returns (address poolAddress); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3FlashCallback.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3FlashCallback.sol deleted file mode 100644 index dd6eb78..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3FlashCallback.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.8.10; - -interface IUniswapV3FlashCallback { - function uniswapV3FlashCallback(uint256 fee0, uint256 fee1, bytes memory data) external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3NonfungiblePositionManager.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3NonfungiblePositionManager.sol deleted file mode 100644 index b48467e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3NonfungiblePositionManager.sol +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.8.10; - -abstract contract IUniswapV3NonfungiblePositionManager { - struct MintParams { - address token0; - address token1; - uint24 fee; - int24 tickLower; - int24 tickUpper; - uint256 amount0Desired; - uint256 amount1Desired; - uint256 amount0Min; - uint256 amount1Min; - address recipient; - uint256 deadline; - } - - function mint(MintParams calldata params) - external - payable - virtual - returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); - - struct IncreaseLiquidityParams { - uint256 tokenId; - uint256 amount0Desired; - uint256 amount1Desired; - uint256 amount0Min; - uint256 amount1Min; - uint256 deadline; - } - - function increaseLiquidity(IncreaseLiquidityParams calldata params) - external - payable - virtual - returns (uint128 liquidity, uint256 amount0, uint256 amount1); - - struct DecreaseLiquidityParams { - uint256 tokenId; - uint128 liquidity; - uint256 amount0Min; - uint256 amount1Min; - uint256 deadline; - } - - function decreaseLiquidity(DecreaseLiquidityParams calldata params) - external - payable - virtual - returns (uint256 amount0, uint256 amount1); - - struct CollectParams { - uint256 tokenId; - address recipient; - uint128 amount0Max; - uint128 amount1Max; - } - - function collect(CollectParams calldata params) - external - payable - virtual - returns (uint256 amount0, uint256 amount1); - - function positions(uint256 tokenId) - external - view - virtual - returns ( - uint96 nonce, - address operator, - address token0, - address token1, - uint24 fee, - int24 tickLower, - int24 tickUpper, - uint128 liquidity, - uint256 feeGrowthInside0LastX128, - uint256 feeGrowthInside1LastX128, - uint128 tokensOwed0, - uint128 tokensOwed1 - ); - function balanceOf(address owner) external view virtual returns (uint256 balance); - function tokenOfOwnerByIndex( - address owner, - uint256 index - ) - external - view - virtual - returns (uint256 tokenId); - function approve(address to, uint256 tokenId) public virtual; - - /// @notice Creates a new pool if it does not exist, then initializes if not initialized - /// @dev This method can be bundled with others via IMulticall for the first action (e.g. mint) - /// performed against a pool - /// @param token0 The contract address of token0 of the pool - /// @param token1 The contract address of token1 of the pool - /// @param fee The fee amount of the v3 pool for the specified token pair - /// @param sqrtPriceX96 The initial square root price of the pool as a Q64.96 value - /// @return pool Returns the pool address based on the pair of tokens and fee, will return the - /// newly created pool address if necessary - function createAndInitializePoolIfNecessary( - address token0, - address token1, - uint24 fee, - uint160 sqrtPriceX96 - ) - external - payable - virtual - returns (address pool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Pool.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Pool.sol deleted file mode 100644 index 4c4d99a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Pool.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IUniswapV3Pool { - struct Slot0 { - // the current price - uint160 sqrtPriceX96; - // the current tick - int24 tick; - // the most-recently updated index of the observations array - uint16 observationIndex; - // the current maximum number of observations that are being stored - uint16 observationCardinality; - // the next maximum number of observations to store, triggered in observations.write - uint16 observationCardinalityNext; - // the current protocol fee as a percentage of the swap fee taken on withdrawal - // represented as an integer denominator (1/x)% - uint8 feeProtocol; - // whether the pool is locked - bool unlocked; - } - - function slot0() external view virtual returns (Slot0 memory); - - function fee() external view virtual returns (uint24 fee); - - function flash( - address recipient, - uint256 amount0, - uint256 amount1, - bytes memory data - ) - external - virtual; - - function token0() external view virtual returns (address); - function token1() external view virtual returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3SwapCallback.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3SwapCallback.sol deleted file mode 100644 index 457bcee..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3SwapCallback.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.8.0; - -/// @title Callback for IUniswapV3PoolActions#swap -/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface -interface IUniswapV3SwapCallback { - /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. - /// @dev In the implementation you must pay the pool tokens owed for the swap. - /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical - /// UniswapV3Factory. - /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. - /// @param amount0Delta The amount of token0 that was sent (negative) or must be received - /// (positive) by the pool by - /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. - /// @param amount1Delta The amount of token1 that was sent (negative) or must be received - /// (positive) by the pool by - /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. - /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call - function uniswapV3SwapCallback( - int256 amount0Delta, - int256 amount1Delta, - bytes calldata data - ) - external; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYVault.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYVault.sol deleted file mode 100644 index a393f1a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYVault.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.8.0 <0.9.0; - -interface IYVault { - function withdraw(uint256 _shares) external; - function deposit(uint256 _amount, address _recipient) external; - function token() external view returns (address); - - function totalSupply() external view returns (uint256); - function totalAssets() external view returns (uint256); - function withdrawalQueue(uint256 i) external view returns (address); - - function strategies(address) - external - view - returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYearnRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYearnRegistry.sol deleted file mode 100644 index 5df2617..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/interfaces/yearn/IYearnRegistry.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.10; - -abstract contract IYearnRegistry { - function latestVault(address) external view virtual returns (address); - function numVaults(address) external view virtual returns (uint256); - function vaults(address, uint256) external view virtual returns (address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/registry/ExampleFactory.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/registry/ExampleFactory.sol deleted file mode 100644 index 70d77a1..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/registry/ExampleFactory.sol +++ /dev/null @@ -1,147 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IMSA } from "../../accounts/erc7579/interfaces/IMSA.sol"; -import { - IERC7579Bootstrap, - BootstrapConfig -} from "../../accounts/erc7579/interfaces/IERC7579Bootstrap.sol"; -import { IModule as IERC7579Module } from "../../accounts/common/interfaces/IERC7579Module.sol"; - -// Dependencies -import { FactoryBase } from "./FactoryBase.sol"; - -// Precompiles -import { ERC7579Precompiles } from "../../deployment/precompiles/ERC7579Precompiles.sol"; - -contract ExampleFactory is FactoryBase, ERC7579Precompiles { - address public immutable IMPLEMENTATION; - address public immutable BOOTSTRAP; - - constructor( - address _msaImplementation, - address _bootstrap, - address _registry, - address[] memory _trustedAttesters, - uint8 _threshold - ) - FactoryBase(_registry, _trustedAttesters, _threshold) - { - IMPLEMENTATION = _msaImplementation; - BOOTSTRAP = _bootstrap; - } - - function createAccount( - bytes32 salt, - address validator, - bytes calldata validatorInitData - ) - public - payable - virtual - returns (address) - { - _checkRegistry(validator, 1); - - bytes memory initData = abi.encode( - BOOTSTRAP, - abi.encodeCall( - IERC7579Bootstrap.singleInitMSA, (IERC7579Module(validator), validatorInitData) - ) - ); - - address account = deployMSAPRoxy(salt, IMPLEMENTATION, initData); - - return account; - } - - function getAddress( - bytes32 salt, - address validator, - bytes calldata validatorInitData - ) - public - virtual - returns (address) - { - _checkRegistry(validator, 1); - - bytes memory initData = abi.encode( - BOOTSTRAP, - abi.encodeCall( - IERC7579Bootstrap.singleInitMSA, (IERC7579Module(validator), validatorInitData) - ) - ); - - bytes32 hash = keccak256( - abi.encodePacked( - bytes1(0xff), - address(this), - salt, - keccak256( - abi.encodePacked( - MSAPROXY_BYTECODE, - abi.encode(IMPLEMENTATION, abi.encodeCall(IMSA.initializeAccount, initData)) - ) - ) - ) - ); - - return address(uint160(uint256(hash))); - } - - function getAddress( - bytes32 salt, - bytes memory initData - ) - public - view - virtual - returns (address) - { - bytes32 hash = keccak256( - abi.encodePacked( - bytes1(0xff), - address(this), - salt, - keccak256( - abi.encodePacked( - MSAPROXY_BYTECODE, - abi.encode(IMPLEMENTATION, abi.encodeCall(IMSA.initializeAccount, initData)) - ) - ) - ) - ); - - return address(uint160(uint256(hash))); - } - - function getInitCode( - bytes32 salt, - address validator, - bytes calldata validatorInitData - ) - public - view - virtual - returns (bytes memory initCode) - { - initCode = abi.encodePacked( - address(this), abi.encodeCall(this.createAccount, (salt, validator, validatorInitData)) - ); - } - - function _getSalt( - bytes32 _salt, - address validator, - bytes calldata validatorInitData - ) - public - pure - virtual - returns (bytes32 salt) - { - salt = keccak256(abi.encodePacked(_salt, validator, validatorInitData)); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/registry/FactoryBase.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/registry/FactoryBase.sol deleted file mode 100644 index d091fa5..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/registry/FactoryBase.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IERC7484 } from "../../Interfaces.sol"; - -abstract contract FactoryBase { - IERC7484 public immutable REGISTRY; - - address[] public trustedAttesters; - uint8 public threshold; - - constructor(address _registry, address[] memory _trustedAttesters, uint8 _threshold) { - REGISTRY = IERC7484(_registry); - trustedAttesters = _trustedAttesters; - threshold = _threshold; - } - - function _checkRegistry(address module, uint256 moduleType) internal view { - REGISTRY.check(module, moduleType, trustedAttesters, threshold); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/MockUniswap.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/MockUniswap.sol deleted file mode 100644 index 180e051..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/MockUniswap.sol +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { ISwapRouter } from "../interfaces/uniswap/v3/ISwapRouter.sol"; - -contract MockUniswap is ISwapRouter { - function uniswapV3SwapCallback( - int256 amount0Delta, - int256 amount1Delta, - bytes calldata data - ) - external - override - { } - - function exactInputSingle(ExactInputSingleParams calldata params) - external - payable - override - returns (uint256 amountOut) - { - return params.amountIn; - } - - function exactInput(ExactInputParams calldata params) - external - payable - override - returns (uint256 amountOut) - { - return params.amountIn; - } - - function exactOutputSingle(ExactOutputSingleParams calldata params) - external - payable - override - returns (uint256 amountIn) - { - return params.amountOut; - } - - function exactOutput(ExactOutputParams calldata params) - external - payable - override - returns (uint256 amountIn) - { - return params.amountOut; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/helpers/MainnetAddresses.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/helpers/MainnetAddresses.sol deleted file mode 100644 index 841d7c0..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/helpers/MainnetAddresses.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -address payable constant SWAPROUTER_ADDRESS = payable(0xE592427A0AEce92De3Edee1F18E0157C05861564); -uint24 constant SWAPROUTER_DEFAULTFEE = 3000; -address constant QUOTER_ADDRESS = 0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6; -address constant FACTORY_ADDRESS = 0x1F98431c8aD98523631AE4a59f267346ea31F984; diff --git a/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/v3/Uniswap.sol b/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/v3/Uniswap.sol deleted file mode 100644 index eed3435..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/integrations/uniswap/v3/Uniswap.sol +++ /dev/null @@ -1,197 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Helpers -import { - SWAPROUTER_ADDRESS, - SWAPROUTER_DEFAULTFEE, - FACTORY_ADDRESS -} from "../helpers/MainnetAddresses.sol"; - -// Interfaces -import { ISwapRouter } from "../../interfaces/uniswap/v3/ISwapRouter.sol"; -import { IUniswapV3Factory } from "../../interfaces/uniswap/v3/IUniswapV3Factory.sol"; -import { IUniswapV3Pool } from "../../interfaces/uniswap/v3/IUniswapV3Pool.sol"; -import { IERC20 } from "forge-std/interfaces/IERC20.sol"; - -// Dependencies -import { ERC20Integration } from "../../ERC20.sol"; - -// Types -import { Execution } from "../../../accounts/erc7579/lib/ExecutionLib.sol"; - -/// @author zeroknots -library UniswapV3Integration { - using ERC20Integration for IERC20; - - error PoolDoesNotExist(); - - function approveAndSwap( - address smartAccount, - IERC20 tokenIn, - IERC20 tokenOut, - uint256 amountIn, - uint160 sqrtPriceLimitX96 - ) - internal - view - returns (Execution[] memory exec) - { - exec = new Execution[](3); - (exec[0], exec[1]) = ERC20Integration.safeApprove(tokenIn, SWAPROUTER_ADDRESS, amountIn); - exec[2] = swapExactInputSingle(smartAccount, tokenIn, tokenOut, amountIn, sqrtPriceLimitX96); - } - - function swapExactInputSingle( - address smartAccount, - IERC20 tokenIn, - IERC20 tokenOut, - uint256 amountIn, - uint160 sqrtPriceLimitX96 - ) - internal - view - returns (Execution memory exec) - { - exec = Execution({ - target: SWAPROUTER_ADDRESS, - value: 0, - callData: abi.encodeCall( - ISwapRouter.exactInputSingle, - ( - ISwapRouter.ExactInputSingleParams({ - tokenIn: address(tokenIn), - tokenOut: address(tokenOut), - fee: SWAPROUTER_DEFAULTFEE, - recipient: smartAccount, - deadline: block.timestamp, - amountIn: amountIn, - amountOutMinimum: 0, - sqrtPriceLimitX96: sqrtPriceLimitX96 - }) - ) - ) - }); - } - - function swapExactOutputSingle( - address smartAccount, - IERC20 tokenIn, - IERC20 tokenOut, - uint256 amountOut, - uint256 amountInMaximum - ) - internal - view - returns (Execution memory exec) - { - exec = Execution({ - target: SWAPROUTER_ADDRESS, - value: 0, - callData: abi.encodeCall( - ISwapRouter.exactOutputSingle, - ( - ISwapRouter.ExactOutputSingleParams({ - tokenIn: address(tokenIn), - tokenOut: address(tokenOut), - fee: SWAPROUTER_DEFAULTFEE, - recipient: smartAccount, - deadline: block.timestamp, - amountOut: amountOut, - amountInMaximum: amountInMaximum, - sqrtPriceLimitX96: 0 - }) - ) - ) - }); - } - - function getPoolAddress( - address token0, - address token1 - ) - public - view - returns (address poolAddress) - { - IUniswapV3Factory factory = IUniswapV3Factory(FACTORY_ADDRESS); - poolAddress = factory.getPool(token0, token1, SWAPROUTER_DEFAULTFEE); - if (poolAddress == address(0)) { - revert PoolDoesNotExist(); - } - return poolAddress; - } - - function getSqrtPriceX96(address poolAddress) public view returns (uint160 sqrtPriceX96) { - IUniswapV3Pool pool = IUniswapV3Pool(poolAddress); - IUniswapV3Pool.Slot0 memory slot0 = pool.slot0(); - sqrtPriceX96 = slot0.sqrtPriceX96; - } - - function sqrtPriceX96toPriceRatio(uint160 sqrtPriceX96) - internal - pure - returns (uint256 priceRatio) - { - uint256 decodedSqrtPrice = (sqrtPriceX96 * 10 ** 9) / (2 ** 96); - priceRatio = decodedSqrtPrice * decodedSqrtPrice; - } - - function priceRatioToPrice( - uint256 priceRatio, - address poolAddress, - address tokenSwappedFrom - ) - internal - view - returns (uint256 price) - { - IUniswapV3Pool pool = IUniswapV3Pool(poolAddress); - address poolToken0 = pool.token0(); - address poolToken1 = pool.token1(); - uint256 token0Decimals = IERC20(poolToken0).decimals(); - uint256 token1Decimals = IERC20(poolToken1).decimals(); - - bool swapToken0to1 = (tokenSwappedFrom == poolToken0); - if (swapToken0to1) { - price = (10 ** token1Decimals * 10 ** 18) / priceRatio; - } else { - price = (priceRatio * 10 ** token0Decimals) / 10 ** 18; - } - return price; - } - - function priceRatioToSqrtPriceX96(uint256 priceRatio) internal pure returns (uint160) { - // Scale priceRatio to 18 decimals for precision - uint256 sqrtPriceRatio = sqrt256(priceRatio); - - uint256 sqrtPriceX96 = (sqrtPriceRatio * 2 ** 96) / 1e9; // Adjust back from the scaling - - return uint160(sqrtPriceX96); - } - - function checkTokenOrder( - address tokenSwappedFrom, - address poolAddress - ) - internal - view - returns (bool swapToken0to1) - { - address poolToken0 = IUniswapV3Pool(poolAddress).token0(); - swapToken0to1 = (tokenSwappedFrom == poolToken0); - } - - function sqrt256(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; - } - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC20.sol b/typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC20.sol deleted file mode 100644 index dc66d41..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC20.sol +++ /dev/null @@ -1,257 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -import { IERC20 } from "forge-std/interfaces/IERC20.sol"; - -/// @notice This is a mock contract of the ERC20 standard for testing purposes only, it SHOULD NOT -/// be used in production. -/// @dev Forked from: -/// https://github.com/transmissions11/solmate/blob/0384dbaaa4fcb5715738a9254a7c0a4cb62cf458/src/tokens/ERC20.sol -contract MockERC20 is IERC20 { - /*////////////////////////////////////////////////////////////// - METADATA STORAGE - //////////////////////////////////////////////////////////////*/ - - string internal _name; - - string internal _symbol; - - uint8 internal _decimals; - - function name() external view override returns (string memory) { - return _name; - } - - function symbol() external view override returns (string memory) { - return _symbol; - } - - function decimals() external view override returns (uint8) { - return _decimals; - } - - /*////////////////////////////////////////////////////////////// - ERC20 STORAGE - //////////////////////////////////////////////////////////////*/ - - uint256 internal _totalSupply; - - mapping(address => uint256) internal _balanceOf; - - mapping(address => mapping(address => uint256)) internal _allowance; - - function totalSupply() external view override returns (uint256) { - return _totalSupply; - } - - function balanceOf(address owner) external view override returns (uint256) { - return _balanceOf[owner]; - } - - function allowance(address owner, address spender) external view override returns (uint256) { - return _allowance[owner][spender]; - } - - /*////////////////////////////////////////////////////////////// - EIP-2612 STORAGE - //////////////////////////////////////////////////////////////*/ - - uint256 internal INITIAL_CHAIN_ID; - - bytes32 internal INITIAL_DOMAIN_SEPARATOR; - - mapping(address => uint256) public nonces; - - /*////////////////////////////////////////////////////////////// - INITIALIZE - //////////////////////////////////////////////////////////////*/ - - /// @dev A bool to track whether the contract has been initialized. - bool private initialized; - - /// @dev To hide constructor warnings across solc versions due to different constructor - /// visibility requirements and - /// syntaxes, we add an initialization function that can be called only once. - function initialize(string memory name_, string memory symbol_, uint8 decimals_) public { - require(!initialized, "ALREADY_INITIALIZED"); - - _name = name_; - _symbol = symbol_; - _decimals = decimals_; - - INITIAL_CHAIN_ID = _pureChainId(); - INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); - - initialized = true; - } - - /*////////////////////////////////////////////////////////////// - ERC20 LOGIC - //////////////////////////////////////////////////////////////*/ - - function approve(address spender, uint256 amount) public virtual override returns (bool) { - _allowance[msg.sender][spender] = amount; - - emit Approval(msg.sender, spender, amount); - - return true; - } - - function transfer(address to, uint256 amount) public virtual override returns (bool) { - _balanceOf[msg.sender] = _sub(_balanceOf[msg.sender], amount); - _balanceOf[to] = _add(_balanceOf[to], amount); - - emit Transfer(msg.sender, to, amount); - - return true; - } - - function transferFrom( - address from, - address to, - uint256 amount - ) - public - virtual - override - returns (bool) - { - uint256 allowed = _allowance[from][msg.sender]; // Saves gas for limited approvals. - - if (allowed != ~uint256(0)) _allowance[from][msg.sender] = _sub(allowed, amount); - - _balanceOf[from] = _sub(_balanceOf[from], amount); - _balanceOf[to] = _add(_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"); - - 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 - _pureChainId() == 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"), - _pureChainId(), - address(this) - ) - ); - } - - /*////////////////////////////////////////////////////////////// - INTERNAL MINT/BURN LOGIC - //////////////////////////////////////////////////////////////*/ - - function _mint(address to, uint256 amount) internal virtual { - _totalSupply = _add(_totalSupply, amount); - _balanceOf[to] = _add(_balanceOf[to], amount); - - emit Transfer(address(0), to, amount); - } - - function _burn(address from, uint256 amount) internal virtual { - _balanceOf[from] = _sub(_balanceOf[from], amount); - _totalSupply = _sub(_totalSupply, amount); - - emit Transfer(from, address(0), amount); - } - - /*////////////////////////////////////////////////////////////// - INTERNAL SAFE MATH LOGIC - //////////////////////////////////////////////////////////////*/ - - function _add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "ERC20: addition overflow"); - return c; - } - - function _sub(uint256 a, uint256 b) internal pure returns (uint256) { - require(a >= b, "ERC20: subtraction underflow"); - return a - b; - } - - /*////////////////////////////////////////////////////////////// - HELPERS - //////////////////////////////////////////////////////////////*/ - - // 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(); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC721.sol b/typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC721.sol deleted file mode 100644 index 46ae594..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/mocks/MockERC721.sol +++ /dev/null @@ -1,258 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -import { IERC721Metadata, IERC721TokenReceiver } from "forge-std/interfaces/IERC721.sol"; - -/// @notice This is a mock contract of the ERC721 standard for testing purposes only, it SHOULD NOT -/// be used in production. -/// @dev Forked from: -/// https://github.com/transmissions11/solmate/blob/0384dbaaa4fcb5715738a9254a7c0a4cb62cf458/src/tokens/ERC721.sol -contract MockERC721 is IERC721Metadata { - /*////////////////////////////////////////////////////////////// - METADATA STORAGE/LOGIC - //////////////////////////////////////////////////////////////*/ - - string internal _name; - - string internal _symbol; - - function name() external view override returns (string memory) { - return _name; - } - - function symbol() external view override returns (string memory) { - return _symbol; - } - - function tokenURI(uint256 id) public view virtual override returns (string memory) { } - - /*////////////////////////////////////////////////////////////// - ERC721 BALANCE/OWNER STORAGE - //////////////////////////////////////////////////////////////*/ - - mapping(uint256 => address) internal _ownerOf; - - mapping(address => uint256) internal _balanceOf; - - function ownerOf(uint256 id) public view virtual override returns (address owner) { - require((owner = _ownerOf[id]) != address(0), "NOT_MINTED"); - } - - function balanceOf(address owner) public view virtual override returns (uint256) { - require(owner != address(0), "ZERO_ADDRESS"); - - return _balanceOf[owner]; - } - - /*////////////////////////////////////////////////////////////// - ERC721 APPROVAL STORAGE - //////////////////////////////////////////////////////////////*/ - - mapping(uint256 => address) internal _getApproved; - - mapping(address => mapping(address => bool)) internal _isApprovedForAll; - - function getApproved(uint256 id) public view virtual override returns (address) { - return _getApproved[id]; - } - - function isApprovedForAll( - address owner, - address operator - ) - public - view - virtual - override - returns (bool) - { - return _isApprovedForAll[owner][operator]; - } - - /*////////////////////////////////////////////////////////////// - INITIALIZE - //////////////////////////////////////////////////////////////*/ - - /// @dev A bool to track whether the contract has been initialized. - bool private initialized; - - /// @dev To hide constructor warnings across solc versions due to different constructor - /// visibility requirements and - /// syntaxes, we add an initialization function that can be called only once. - function initialize(string memory name_, string memory symbol_) public { - require(!initialized, "ALREADY_INITIALIZED"); - - _name = name_; - _symbol = symbol_; - - initialized = true; - } - - /*////////////////////////////////////////////////////////////// - ERC721 LOGIC - //////////////////////////////////////////////////////////////*/ - - function approve(address spender, uint256 id) public payable virtual override { - 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 override { - _isApprovedForAll[msg.sender][operator] = approved; - - emit ApprovalForAll(msg.sender, operator, approved); - } - - function transferFrom(address from, address to, uint256 id) public payable virtual override { - 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. - _balanceOf[from]--; - - _balanceOf[to]++; - - _ownerOf[id] = to; - - delete _getApproved[id]; - - emit Transfer(from, to, id); - } - - function safeTransferFrom( - address from, - address to, - uint256 id - ) - public - payable - virtual - override - { - transferFrom(from, to, id); - - require( - !_isContract(to) - || IERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") - == IERC721TokenReceiver.onERC721Received.selector, - "UNSAFE_RECIPIENT" - ); - } - - function safeTransferFrom( - address from, - address to, - uint256 id, - bytes memory data - ) - public - payable - virtual - override - { - transferFrom(from, to, id); - - require( - !_isContract(to) - || IERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) - == IERC721TokenReceiver.onERC721Received.selector, - "UNSAFE_RECIPIENT" - ); - } - - /*////////////////////////////////////////////////////////////// - ERC165 LOGIC - //////////////////////////////////////////////////////////////*/ - - function supportsInterface(bytes4 interfaceId) public view virtual override 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. - - _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"); - - _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( - !_isContract(to) - || IERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") - == IERC721TokenReceiver.onERC721Received.selector, - "UNSAFE_RECIPIENT" - ); - } - - function _safeMint(address to, uint256 id, bytes memory data) internal virtual { - _mint(to, id); - - require( - !_isContract(to) - || IERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) - == IERC721TokenReceiver.onERC721Received.selector, - "UNSAFE_RECIPIENT" - ); - } - - /*////////////////////////////////////////////////////////////// - HELPERS - //////////////////////////////////////////////////////////////*/ - - function _isContract(address _addr) private view returns (bool) { - uint256 codeLength; - - // Assembly required for versions < 0.8.0 to check extcodesize. - assembly { - codeLength := extcodesize(_addr) - } - - return codeLength > 0; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC1271Policy.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC1271Policy.sol deleted file mode 100644 index 746ef48..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC1271Policy.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { ERC7579PolicyBase } from "./ERC7579PolicyBase.sol"; -import { ConfigId, I1271Policy } from "./interfaces/IPolicy.sol"; - -abstract contract ERC1271Policy is ERC7579PolicyBase, I1271Policy { - function check1271SignedAction( - ConfigId id, - address requestSender, - address account, - bytes32 hash, - bytes calldata signature - ) - external - view - virtual - returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7484RegistryAdapter.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7484RegistryAdapter.sol deleted file mode 100644 index 9893ce2..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7484RegistryAdapter.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { IERC7484 } from "./interfaces/IERC7484.sol"; - -abstract contract ERC7484RegistryAdapter { - // registry address - IERC7484 public immutable REGISTRY; - - /** - * Contract constructor - * @dev sets the registry as an immutable variable - * - * @param _registry The registry address - */ - constructor(IERC7484 _registry) { - // set the registry - REGISTRY = _registry; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ActionPolicy.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ActionPolicy.sol deleted file mode 100644 index 4e0f684..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ActionPolicy.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { ERC7579PolicyBase } from "./ERC7579PolicyBase.sol"; -import { ConfigId, IActionPolicy } from "./interfaces/IPolicy.sol"; - -abstract contract ERC7579ActionPolicy is ERC7579PolicyBase, IActionPolicy { - function checkAction( - ConfigId id, - address account, - address target, - uint256 value, - bytes calldata data - ) - external - virtual - returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ExecutorBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ExecutorBase.sol deleted file mode 100644 index 7dcc04b..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ExecutorBase.sol +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { IExecutor as IERC7579Executor } from "../accounts/common/interfaces/IERC7579Module.sol"; -import { IERC7579Account } from "../accounts/common/interfaces/IERC7579Account.sol"; -import { - Execution, - ExecutionLib as ERC7579ExecutionLib -} from "../accounts/erc7579/lib/ExecutionLib.sol"; -import { - ModeCode, - ModeLib as ERC7579ModeLib, - CALLTYPE_SINGLE, - EXECTYPE_DEFAULT, - MODE_DEFAULT, - ModePayload, - CALLTYPE_BATCH, - EXECTYPE_DEFAULT, - MODE_DEFAULT, - CALLTYPE_DELEGATECALL -} from "../accounts/common/lib/ModeLib.sol"; -import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; - -abstract contract ERC7579ExecutorBase is IERC7579Executor, ERC7579ModuleBase { - function _execute( - address account, - address to, - uint256 value, - bytes memory data - ) - internal - returns (bytes memory result) - { - ModeCode modeCode = ERC7579ModeLib.encode({ - callType: CALLTYPE_SINGLE, - execType: EXECTYPE_DEFAULT, - mode: MODE_DEFAULT, - payload: ModePayload.wrap(bytes22(0)) - }); - - return IERC7579Account(account).executeFromExecutor( - modeCode, ERC7579ExecutionLib.encodeSingle(to, value, data) - )[0]; - } - - function _execute( - address to, - uint256 value, - bytes memory data - ) - internal - returns (bytes memory result) - { - return _execute(msg.sender, to, value, data); - } - - function _execute( - address account, - Execution[] memory execs - ) - internal - returns (bytes[] memory results) - { - ModeCode modeCode = ERC7579ModeLib.encode({ - callType: CALLTYPE_BATCH, - execType: EXECTYPE_DEFAULT, - mode: MODE_DEFAULT, - payload: ModePayload.wrap(bytes22(0)) - }); - results = IERC7579Account(account).executeFromExecutor( - modeCode, ERC7579ExecutionLib.encodeBatch(execs) - ); - } - - function _execute(Execution[] memory execs) internal returns (bytes[] memory results) { - return _execute(msg.sender, execs); - } - - // Note: Not every account will support delegatecalls - function _executeDelegateCall( - address account, - address delegateTarget, - bytes memory callData - ) - internal - returns (bytes[] memory results) - { - ModeCode modeCode = ERC7579ModeLib.encode({ - callType: CALLTYPE_DELEGATECALL, - execType: EXECTYPE_DEFAULT, - mode: MODE_DEFAULT, - payload: ModePayload.wrap(bytes22(0)) - }); - results = IERC7579Account(account).executeFromExecutor( - modeCode, abi.encodePacked(delegateTarget, callData) - ); - } - - // Note: Not every account will support delegatecalls - function _executeDelegateCall( - address delegateTarget, - bytes memory callData - ) - internal - returns (bytes[] memory results) - { - return _executeDelegateCall(msg.sender, delegateTarget, callData); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579FallbackBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579FallbackBase.sol deleted file mode 100644 index e071370..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579FallbackBase.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { IFallback as IERC7579Fallback } from "../accounts/common/interfaces/IERC7579Module.sol"; -import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; - -abstract contract ERC7579FallbackBase is IERC7579Fallback, ERC7579ModuleBase { - /** - * @notice Allows fetching the original caller address. - * @dev This is only reliable in combination with a FallbackManager that supports this (e.g. Safe - * contract >=1.3.0). - * When using this functionality make sure that the linked _manager (aka msg.sender) - * supports this. - * This function does not rely on a trusted forwarder. Use the returned value only to - * check information against the calling manager. - * @return sender Original caller address. - */ - function _msgSender() internal pure returns (address sender) { - // The assembly code is more direct than the Solidity version using `abi.decode`. - /* solhint-disable no-inline-assembly */ - /// @solidity memory-safe-assembly - assembly { - sender := shr(96, calldataload(sub(calldatasize(), 20))) - } - /* solhint-enable no-inline-assembly */ - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookBase.sol deleted file mode 100644 index 342c3f8..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookBase.sol +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { IHook as IERC7579Hook } from "../accounts/common/interfaces/IERC7579Module.sol"; -import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; -import { TrustedForwarder } from "./utils/TrustedForwarder.sol"; - -abstract contract ERC7579HookBase is IERC7579Hook, ERC7579ModuleBase, TrustedForwarder { - /** - * Precheck hook - * - * @param msgSender sender of the transaction - * @param msgValue value of the transaction - * @param msgData data of the transaction - * - * @return hookData data for the postcheck hook - */ - function preCheck( - address msgSender, - uint256 msgValue, - bytes calldata msgData - ) - external - virtual - returns (bytes memory hookData) - { - // route to internal function - return _preCheck(_getAccount(), msgSender, msgValue, msgData); - } - - /** - * Postcheck hook - * - * @param hookData data from the precheck hook - */ - function postCheck(bytes calldata hookData) external virtual { - // route to internal function - _postCheck(_getAccount(), hookData); - } - - /** - * Precheck hook - * - * @param account account of the transaction - * @param msgSender sender of the transaction - * @param msgValue value of the transaction - * @param msgData data of the transaction - * - * @return hookData data for the postcheck hook - */ - function _preCheck( - address account, - address msgSender, - uint256 msgValue, - bytes calldata msgData - ) - internal - virtual - returns (bytes memory hookData); - - /** - * Postcheck hook - * - * @param account account of the transaction - * @param hookData data from the precheck hook - */ - function _postCheck(address account, bytes calldata hookData) internal virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestruct.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestruct.sol deleted file mode 100644 index a67143f..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestruct.sol +++ /dev/null @@ -1,275 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { IERC7579Account } from "../accounts/common/interfaces/IERC7579Account.sol"; -import { IHook as IERC7579Hook } from "../accounts/common/interfaces/IERC7579Module.sol"; -import { ExecutionLib, Execution } from "../accounts/erc7579/lib/ExecutionLib.sol"; -import { - ModeLib, - CallType, - ModeCode, - CALLTYPE_SINGLE, - CALLTYPE_BATCH, - CALLTYPE_DELEGATECALL -} from "../accounts/common/lib/ModeLib.sol"; -import { IAccountExecute } from "../external/ERC4337.sol"; -import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; -import { TrustedForwarder } from "./utils/TrustedForwarder.sol"; - -uint256 constant EXECUSEROP_OFFSET = 164; -uint256 constant EXEC_OFFSET = 100; -uint256 constant INSTALL_OFFSET = 132; - -abstract contract ERC7579HookDestruct is IERC7579Hook, ERC7579ModuleBase, TrustedForwarder { - error HookInvalidSelector(); - error InvalidCallType(); - - /*////////////////////////////////////////////////////////////////////////// - CALLDATA DECODING - //////////////////////////////////////////////////////////////////////////*/ - - function preCheck( - address msgSender, - uint256 msgValue, - bytes calldata msgData - ) - external - virtual - override - returns (bytes memory hookData) - { - bytes4 selector = bytes4(msgData[0:4]); - - if (selector == IAccountExecute.executeUserOp.selector) { - uint256 offset = - uint256(bytes32(msgData[EXECUSEROP_OFFSET:EXECUSEROP_OFFSET + 32])) + 68; - uint256 paramLen = uint256(bytes32(msgData[offset:offset + 32])); - offset += 32; - bytes calldata _msgData = msgData[offset:offset + paramLen]; - return _decodeCallData(msgSender, msgValue, _msgData); - } else { - return _decodeCallData(msgSender, msgValue, msgData); - } - } - - function _decodeCallData( - address msgSender, - uint256 msgValue, - bytes calldata msgData - ) - internal - returns (bytes memory hookData) - { - bytes4 selector = bytes4(msgData[0:4]); - if (selector == IERC7579Account.execute.selector) { - return _handle4337Executions(msgSender, msgData); - } else if (selector == IERC7579Account.executeFromExecutor.selector) { - return _handleExecutorExecutions(msgSender, msgData); - } else if (selector == IERC7579Account.installModule.selector) { - uint256 paramLen = msgData.length > INSTALL_OFFSET - ? uint256(bytes32(msgData[INSTALL_OFFSET - 32:INSTALL_OFFSET])) - : uint256(0); - bytes calldata initData = msgData.length > INSTALL_OFFSET - ? msgData[INSTALL_OFFSET:INSTALL_OFFSET + paramLen] - : msgData[0:0]; - uint256 moduleType = uint256(bytes32(msgData[4:36])); - address module = address(bytes20((msgData[48:68]))); - return onInstallModule(_getAccount(), msgSender, moduleType, module, initData); - } else if (selector == IERC7579Account.uninstallModule.selector) { - uint256 paramLen = msgData.length > INSTALL_OFFSET - ? uint256(bytes32(msgData[INSTALL_OFFSET - 32:INSTALL_OFFSET])) - : uint256(0); - bytes calldata initData = msgData.length > INSTALL_OFFSET - ? msgData[INSTALL_OFFSET:INSTALL_OFFSET + paramLen] - : msgData[0:0]; - - uint256 moduleType = uint256(bytes32(msgData[4:36])); - address module = address(bytes20((msgData[48:68]))); - - return onUninstallModule(_getAccount(), msgSender, moduleType, module, initData); - } else { - return onUnknownFunction(_getAccount(), msgSender, msgValue, msgData); - } - } - - function _handle4337Executions( - address msgSender, - bytes calldata msgData - ) - internal - returns (bytes memory hookData) - { - uint256 paramLen = uint256(bytes32(msgData[EXEC_OFFSET - 32:EXEC_OFFSET])); - bytes calldata encodedExecutions = msgData[EXEC_OFFSET:EXEC_OFFSET + paramLen]; - - ModeCode mode = ModeCode.wrap(bytes32(msgData[4:36])); - CallType calltype = ModeLib.getCallType(mode); - - if (calltype == CALLTYPE_SINGLE) { - (address to, uint256 value, bytes calldata callData) = - ExecutionLib.decodeSingle(encodedExecutions); - return onExecute(_getAccount(), msgSender, to, value, callData); - } else if (calltype == CALLTYPE_BATCH) { - Execution[] calldata execs = ExecutionLib.decodeBatch(encodedExecutions); - return onExecuteBatch(_getAccount(), msgSender, execs); - } else if (calltype == CALLTYPE_DELEGATECALL) { - address to = address(bytes20(encodedExecutions[0:20])); - bytes calldata callData = encodedExecutions[20:]; - return onExecuteDelegateCall(_getAccount(), msgSender, to, callData); - } else { - revert InvalidCallType(); - } - } - - function _handleExecutorExecutions( - address msgSender, - bytes calldata msgData - ) - internal - returns (bytes memory hookData) - { - uint256 paramLen = uint256(bytes32(msgData[EXEC_OFFSET - 32:EXEC_OFFSET])); - bytes calldata encodedExecutions = msgData[EXEC_OFFSET:EXEC_OFFSET + paramLen]; - - ModeCode mode = ModeCode.wrap(bytes32(msgData[4:36])); - CallType calltype = ModeLib.getCallType(mode); - - if (calltype == CALLTYPE_SINGLE) { - (address to, uint256 value, bytes calldata callData) = - ExecutionLib.decodeSingle(encodedExecutions); - return onExecuteFromExecutor(_getAccount(), msgSender, to, value, callData); - } else if (calltype == CALLTYPE_BATCH) { - Execution[] calldata execs = ExecutionLib.decodeBatch(encodedExecutions); - return onExecuteBatchFromExecutor(_getAccount(), msgSender, execs); - } else if (calltype == CALLTYPE_DELEGATECALL) { - address to = address(bytes20(encodedExecutions[0:20])); - bytes calldata callData = encodedExecutions[20:]; - return onExecuteDelegateCallFromExecutor(_getAccount(), msgSender, to, callData); - } else { - revert InvalidCallType(); - } - } - - function postCheck(bytes calldata hookData) external virtual override { - onPostCheck(_getAccount(), hookData); - } - - /*////////////////////////////////////////////////////////////////////////// - EXECUTION - //////////////////////////////////////////////////////////////////////////*/ - - function onExecute( - address account, - address msgSender, - address target, - uint256 value, - bytes calldata callData - ) - internal - virtual - returns (bytes memory hookData) - { } - - function onExecuteBatch( - address account, - address msgSender, - Execution[] calldata - ) - internal - virtual - returns (bytes memory hookData) - { } - - function onExecuteDelegateCall( - address account, - address msgSender, - address target, - bytes calldata callData - ) - internal - virtual - returns (bytes memory hookData) - { } - - function onExecuteFromExecutor( - address account, - address msgSender, - address target, - uint256 value, - bytes calldata callData - ) - internal - virtual - returns (bytes memory hookData) - { } - - function onExecuteBatchFromExecutor( - address account, - address msgSender, - Execution[] calldata - ) - internal - virtual - returns (bytes memory hookData) - { } - - function onExecuteDelegateCallFromExecutor( - address account, - address msgSender, - address target, - bytes calldata callData - ) - internal - virtual - returns (bytes memory hookData) - { } - - /*////////////////////////////////////////////////////////////////////////// - CONFIG - //////////////////////////////////////////////////////////////////////////*/ - - function onInstallModule( - address account, - address msgSender, - uint256 moduleType, - address module, - bytes calldata initData - ) - internal - virtual - returns (bytes memory hookData) - { } - - function onUninstallModule( - address account, - address msgSender, - uint256 moduleType, - address module, - bytes calldata deInitData - ) - internal - virtual - returns (bytes memory hookData) - { } - - /*////////////////////////////////////////////////////////////////////////// - UNKNOWN FUNCTION - //////////////////////////////////////////////////////////////////////////*/ - - function onUnknownFunction( - address account, - address msgSender, - uint256 msgValue, - bytes calldata msgData - ) - internal - virtual - returns (bytes memory hookData) - { } - - /*////////////////////////////////////////////////////////////////////////// - POSTCHECK - //////////////////////////////////////////////////////////////////////////*/ - - function onPostCheck(address account, bytes calldata hookData) internal virtual { } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestructSingleHook.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestructSingleHook.sol deleted file mode 100644 index fbc21d6..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HookDestructSingleHook.sol +++ /dev/null @@ -1,275 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { IERC7579Account } from "../accounts/common/interfaces/IERC7579Account.sol"; -import { IHook as IERC7579Hook } from "../accounts/common/interfaces/IERC7579Module.sol"; -import { ExecutionLib, Execution } from "../accounts/erc7579/lib/ExecutionLib.sol"; -import { - ModeLib, - CallType, - ModeCode, - CALLTYPE_SINGLE, - CALLTYPE_BATCH, - CALLTYPE_DELEGATECALL -} from "../accounts/common/lib/ModeLib.sol"; -import { IAccountExecute } from "../external/ERC4337.sol"; -import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; -import { TrustedForwarder } from "./utils/TrustedForwarder.sol"; - -uint256 constant EXECUSEROP_OFFSET = 164; -uint256 constant EXEC_OFFSET = 100; -uint256 constant INSTALL_OFFSET = 132; - -abstract contract ERC7579HookDestructSingleHook is IERC7579Hook, ERC7579ModuleBase { - error HookInvalidSelector(); - error InvalidCallType(); - - /*////////////////////////////////////////////////////////////////////////// - CALLDATA DECODING - //////////////////////////////////////////////////////////////////////////*/ - - function preCheck( - address msgSender, - uint256 msgValue, - bytes calldata msgData - ) - external - virtual - override - returns (bytes memory hookData) - { - bytes4 selector = bytes4(msgData[0:4]); - - if (selector == IAccountExecute.executeUserOp.selector) { - uint256 offset = - uint256(bytes32(msgData[EXECUSEROP_OFFSET:EXECUSEROP_OFFSET + 32])) + 68; - uint256 paramLen = uint256(bytes32(msgData[offset:offset + 32])); - offset += 32; - bytes calldata _msgData = msgData[offset:offset + paramLen]; - return _decodeCallData(msgSender, msgValue, _msgData); - } else { - return _decodeCallData(msgSender, msgValue, msgData); - } - } - - function _decodeCallData( - address msgSender, - uint256 msgValue, - bytes calldata msgData - ) - internal - returns (bytes memory hookData) - { - bytes4 selector = bytes4(msgData[0:4]); - if (selector == IERC7579Account.execute.selector) { - return _handle4337Executions(msgSender, msgData); - } else if (selector == IERC7579Account.executeFromExecutor.selector) { - return _handleExecutorExecutions(msgSender, msgData); - } else if (selector == IERC7579Account.installModule.selector) { - uint256 paramLen = msgData.length > INSTALL_OFFSET - ? uint256(bytes32(msgData[INSTALL_OFFSET - 32:INSTALL_OFFSET])) - : uint256(0); - bytes calldata initData = msgData.length > INSTALL_OFFSET - ? msgData[INSTALL_OFFSET:INSTALL_OFFSET + paramLen] - : msgData[0:0]; - uint256 moduleType = uint256(bytes32(msgData[4:36])); - address module = address(bytes20((msgData[48:68]))); - return onInstallModule(msg.sender, msgSender, moduleType, module, initData); - } else if (selector == IERC7579Account.uninstallModule.selector) { - uint256 paramLen = msgData.length > INSTALL_OFFSET - ? uint256(bytes32(msgData[INSTALL_OFFSET - 32:INSTALL_OFFSET])) - : uint256(0); - bytes calldata initData = msgData.length > INSTALL_OFFSET - ? msgData[INSTALL_OFFSET:INSTALL_OFFSET + paramLen] - : msgData[0:0]; - - uint256 moduleType = uint256(bytes32(msgData[4:36])); - address module = address(bytes20((msgData[48:68]))); - - return onUninstallModule(msg.sender, msgSender, moduleType, module, initData); - } else { - return onUnknownFunction(msg.sender, msgSender, msgValue, msgData); - } - } - - function _handle4337Executions( - address msgSender, - bytes calldata msgData - ) - internal - returns (bytes memory hookData) - { - uint256 paramLen = uint256(bytes32(msgData[EXEC_OFFSET - 32:EXEC_OFFSET])); - bytes calldata encodedExecutions = msgData[EXEC_OFFSET:EXEC_OFFSET + paramLen]; - - ModeCode mode = ModeCode.wrap(bytes32(msgData[4:36])); - CallType calltype = ModeLib.getCallType(mode); - - if (calltype == CALLTYPE_SINGLE) { - (address to, uint256 value, bytes calldata callData) = - ExecutionLib.decodeSingle(encodedExecutions); - return onExecute(msg.sender, msgSender, to, value, callData); - } else if (calltype == CALLTYPE_BATCH) { - Execution[] calldata execs = ExecutionLib.decodeBatch(encodedExecutions); - return onExecuteBatch(msg.sender, msgSender, execs); - } else if (calltype == CALLTYPE_DELEGATECALL) { - address to = address(bytes20(encodedExecutions[0:20])); - bytes calldata callData = encodedExecutions[20:]; - return onExecuteDelegateCall(msg.sender, msgSender, to, callData); - } else { - revert InvalidCallType(); - } - } - - function _handleExecutorExecutions( - address msgSender, - bytes calldata msgData - ) - internal - returns (bytes memory hookData) - { - uint256 paramLen = uint256(bytes32(msgData[EXEC_OFFSET - 32:EXEC_OFFSET])); - bytes calldata encodedExecutions = msgData[EXEC_OFFSET:EXEC_OFFSET + paramLen]; - - ModeCode mode = ModeCode.wrap(bytes32(msgData[4:36])); - CallType calltype = ModeLib.getCallType(mode); - - if (calltype == CALLTYPE_SINGLE) { - (address to, uint256 value, bytes calldata callData) = - ExecutionLib.decodeSingle(encodedExecutions); - return onExecuteFromExecutor(msg.sender, msgSender, to, value, callData); - } else if (calltype == CALLTYPE_BATCH) { - Execution[] calldata execs = ExecutionLib.decodeBatch(encodedExecutions); - return onExecuteBatchFromExecutor(msg.sender, msgSender, execs); - } else if (calltype == CALLTYPE_DELEGATECALL) { - address to = address(bytes20(encodedExecutions[0:20])); - bytes calldata callData = encodedExecutions[20:]; - return onExecuteDelegateCallFromExecutor(msg.sender, msgSender, to, callData); - } else { - revert InvalidCallType(); - } - } - - function postCheck(bytes calldata hookData) external virtual override { - onPostCheck(msg.sender, hookData); - } - - /*////////////////////////////////////////////////////////////////////////// - EXECUTION - //////////////////////////////////////////////////////////////////////////*/ - - function onExecute( - address account, - address msgSender, - address target, - uint256 value, - bytes calldata callData - ) - internal - virtual - returns (bytes memory hookData) - { } - - function onExecuteBatch( - address account, - address msgSender, - Execution[] calldata - ) - internal - virtual - returns (bytes memory hookData) - { } - - function onExecuteDelegateCall( - address account, - address msgSender, - address target, - bytes calldata callData - ) - internal - virtual - returns (bytes memory hookData) - { } - - function onExecuteFromExecutor( - address account, - address msgSender, - address target, - uint256 value, - bytes calldata callData - ) - internal - virtual - returns (bytes memory hookData) - { } - - function onExecuteBatchFromExecutor( - address account, - address msgSender, - Execution[] calldata - ) - internal - virtual - returns (bytes memory hookData) - { } - - function onExecuteDelegateCallFromExecutor( - address account, - address msgSender, - address target, - bytes calldata callData - ) - internal - virtual - returns (bytes memory hookData) - { } - - /*////////////////////////////////////////////////////////////////////////// - CONFIG - //////////////////////////////////////////////////////////////////////////*/ - - function onInstallModule( - address account, - address msgSender, - uint256 moduleType, - address module, - bytes calldata initData - ) - internal - virtual - returns (bytes memory hookData) - { } - - function onUninstallModule( - address account, - address msgSender, - uint256 moduleType, - address module, - bytes calldata deInitData - ) - internal - virtual - returns (bytes memory hookData) - { } - - /*////////////////////////////////////////////////////////////////////////// - UNKNOWN FUNCTION - //////////////////////////////////////////////////////////////////////////*/ - - function onUnknownFunction( - address account, - address msgSender, - uint256 msgValue, - bytes calldata msgData - ) - internal - virtual - returns (bytes memory hookData) - { } - - /*////////////////////////////////////////////////////////////////////////// - POSTCHECK - //////////////////////////////////////////////////////////////////////////*/ - - function onPostCheck(address account, bytes calldata hookData) internal virtual { } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HybridValidatorBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HybridValidatorBase.sol deleted file mode 100644 index a3d157a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579HybridValidatorBase.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -/* solhint-disable no-unused-import */ - -import { - PackedUserOperation, - _packValidationData as _packValidationData4337 -} from "../external/ERC4337.sol"; -import { ERC7579ValidatorBase } from "./ERC7579ValidatorBase.sol"; -import { ERC7579StatelessValidatorBase } from "./ERC7579StatelessValidatorBase.sol"; - -/// @notice Base contract for hybrid validators, which are both stateful and stateless. -abstract contract ERC7579HybridValidatorBase is - ERC7579ValidatorBase, - ERC7579StatelessValidatorBase -{ } diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ModuleBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ModuleBase.sol deleted file mode 100644 index e7e5ca8..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ModuleBase.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { IModule as IERC7579Module } from "../accounts/common/interfaces/IERC7579Module.sol"; -import { - MODULE_TYPE_VALIDATOR, - MODULE_TYPE_EXECUTOR, - MODULE_TYPE_FALLBACK, - MODULE_TYPE_HOOK, - MODULE_TYPE_POLICY, - MODULE_TYPE_SIGNER, - MODULE_TYPE_STATELESS_VALIDATOR -} from "./utils/ERC7579Constants.sol"; - -abstract contract ERC7579ModuleBase is IERC7579Module { - uint256 internal constant TYPE_VALIDATOR = MODULE_TYPE_VALIDATOR; - uint256 internal constant TYPE_EXECUTOR = MODULE_TYPE_EXECUTOR; - uint256 internal constant TYPE_FALLBACK = MODULE_TYPE_FALLBACK; - uint256 internal constant TYPE_HOOK = MODULE_TYPE_HOOK; - uint256 internal constant TYPE_POLICY = MODULE_TYPE_POLICY; - uint256 internal constant TYPE_SIGNER = MODULE_TYPE_SIGNER; - uint256 internal constant TYPE_STATELESS_VALIDATOR = MODULE_TYPE_STATELESS_VALIDATOR; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579PolicyBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579PolicyBase.sol deleted file mode 100644 index df6c98f..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579PolicyBase.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; -import { IPolicy, ConfigId } from "./interfaces/IPolicy.sol"; - -abstract contract ERC7579PolicyBase is ERC7579ModuleBase, IPolicy { - function initializeWithMultiplexer( - address account, - ConfigId configId, - bytes calldata initData - ) - external - virtual; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579StatelessValidatorBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579StatelessValidatorBase.sol deleted file mode 100644 index 272d28a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579StatelessValidatorBase.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; -import { IStatelessValidator } from "./interfaces/IStatelessValidator.sol"; - -abstract contract ERC7579StatelessValidatorBase is ERC7579ModuleBase, IStatelessValidator { - function validateSignatureWithData( - bytes32, - bytes calldata, - bytes calldata - ) - external - view - virtual - returns (bool validSig); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579UserOpPolicy.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579UserOpPolicy.sol deleted file mode 100644 index 2d545bf..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579UserOpPolicy.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { ERC7579PolicyBase } from "./ERC7579PolicyBase.sol"; -import { ConfigId, IUserOpPolicy } from "./interfaces/IPolicy.sol"; -import { PackedUserOperation } from "../external/ERC4337.sol"; - -abstract contract ERC7579UserOpPolicy is ERC7579PolicyBase, IUserOpPolicy { - function checkUserOp( - ConfigId id, - PackedUserOperation calldata userOp - ) - external - virtual - returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorBase.sol deleted file mode 100644 index 8c23254..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorBase.sol +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { - PackedUserOperation, - _packValidationData as _packValidationData4337 -} from "../external/ERC4337.sol"; -import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; - -abstract contract ERC7579ValidatorBase is ERC7579ModuleBase { - type ValidationData is uint256; - - ValidationData internal constant VALIDATION_SUCCESS = ValidationData.wrap(0); - ValidationData internal constant VALIDATION_FAILED = ValidationData.wrap(1); - bytes4 internal constant EIP1271_SUCCESS = 0x1626ba7e; - bytes4 internal constant EIP1271_FAILED = 0xFFFFFFFF; - - /** - * Helper to pack the return value for validateUserOp, when not using an aggregator. - * @param sigFailed - True for signature failure, false for success. - * @param validUntil - Last timestamp this UserOperation is valid (or zero for - * infinite). - * @param validAfter - First timestamp this UserOperation is valid. - */ - function _packValidationData( - bool sigFailed, - uint48 validUntil, - uint48 validAfter - ) - internal - pure - returns (ValidationData) - { - return ValidationData.wrap(_packValidationData4337(sigFailed, validUntil, validAfter)); - } - - function _unpackValidationData(ValidationData _packedData) - internal - pure - returns (bool sigFailed, uint48 validUntil, uint48 validAfter) - { - uint256 packedData = ValidationData.unwrap(_packedData); - sigFailed = (packedData & 1) == 1; - validUntil = uint48((packedData >> 160) & ((1 << 48) - 1)); - validAfter = uint48((packedData >> (160 + 48)) & ((1 << 48) - 1)); - } - - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) - external - virtual - returns (ValidationData); - - function isValidSignatureWithSender( - address sender, - bytes32 hash, - bytes calldata data - ) - external - view - virtual - returns (bytes4); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorMaster.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorMaster.sol deleted file mode 100644 index 619d03c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/ERC7579ValidatorMaster.sol +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { - PackedUserOperation, - _packValidationData as _packValidationData4337 -} from "../external/ERC4337.sol"; -import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; - -abstract contract ERC7579ValidatorBase is ERC7579ModuleBase { - type ValidationData is uint256; - - ValidationData internal constant VALIDATION_FAILED = ValidationData.wrap(1); - bytes4 internal constant EIP1271_SUCCESS = 0x1626ba7e; - bytes4 internal constant EIP1271_FAILED = 0xFFFFFFFF; - - modifier notInitialized() virtual; - modifier alreadyInitialized() virtual; - - // Modules may be intalled without being added to the account - function onInstall(bytes calldata data) external virtual override notInitialized { - _onInstall(data); - } - - function onUninstall(bytes calldata data) external virtual override alreadyInitialized { - _onUninstall(data); - } - - function _onInstall(bytes calldata data) internal virtual; - function _onUninstall(bytes calldata data) internal virtual; - - /** - * Helper to pack the return value for validateUserOp, when not using an aggregator. - * @param sigFailed - True for signature failure, false for success. - * @param validUntil - Last timestamp this UserOperation is valid (or zero for - * infinite). - * @param validAfter - First timestamp this UserOperation is valid. - */ - function _packValidationData( - bool sigFailed, - uint48 validUntil, - uint48 validAfter - ) - internal - pure - returns (ValidationData) - { - return ValidationData.wrap(_packValidationData4337(sigFailed, validUntil, validAfter)); - } - - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) - external - virtual - returns (ValidationData); - - function isValidSignatureWithSender( - address sender, - bytes32 hash, - bytes calldata data - ) - external - view - virtual - returns (bytes4); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/SchedulingBase.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/SchedulingBase.sol deleted file mode 100644 index a8354b5..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/SchedulingBase.sol +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { ERC7579ExecutorBase } from "./ERC7579ExecutorBase.sol"; - -abstract contract SchedulingBase is ERC7579ExecutorBase { - /*////////////////////////////////////////////////////////////////////////// - CONSTANTS & STORAGE - //////////////////////////////////////////////////////////////////////////*/ - - error InvalidExecution(); - - event ExecutionAdded(address indexed smartAccount, uint256 indexed jobId); - event ExecutionTriggered(address indexed smartAccount, uint256 indexed jobId); - event ExecutionStatusUpdated(address indexed smartAccount, uint256 indexed jobId); - event ExecutionsCancelled(address indexed smartAccount); - - mapping(address smartAccount => mapping(uint256 jobId => ExecutionConfig)) public executionLog; - - mapping(address smartAccount => uint256 jobCount) public accountJobCount; - - struct ExecutionConfig { - uint48 executeInterval; - uint16 numberOfExecutions; - uint16 numberOfExecutionsCompleted; - uint48 startDate; - bool isEnabled; - uint48 lastExecutionTime; - bytes executionData; - } - - struct ExecutorAccess { - uint256 jobId; - } - - /*////////////////////////////////////////////////////////////////////////// - CONFIG - //////////////////////////////////////////////////////////////////////////*/ - - function _onInstall(bytes calldata packedSchedulingData) internal { - address account = msg.sender; - if (isInitialized(account)) { - revert ModuleAlreadyInitialized(account); - } - - _createExecution({ orderData: packedSchedulingData }); - } - - function _onUninstall() internal { - address account = msg.sender; - - uint256 count = accountJobCount[account]; - for (uint256 i = 1; i <= count; i++) { - delete executionLog[account][i]; - } - accountJobCount[account] = 0; - - emit ExecutionsCancelled(account); - } - - function isInitialized(address smartAccount) public view returns (bool) { - return accountJobCount[smartAccount] != 0; - } - - function addOrder(bytes calldata orderData) external { - address account = msg.sender; - if (!isInitialized(account)) revert NotInitialized(account); - - _createExecution({ orderData: orderData }); - } - - function toggleOrder(uint256 jobId) external { - address account = msg.sender; - - ExecutionConfig storage executionConfig = executionLog[account][jobId]; - - if (executionConfig.numberOfExecutions == 0) { - revert InvalidExecution(); - } - - executionConfig.isEnabled = !executionConfig.isEnabled; - - emit ExecutionStatusUpdated(account, jobId); - } - - /*////////////////////////////////////////////////////////////////////////// - INTERNAL - //////////////////////////////////////////////////////////////////////////*/ - - function _createExecution(bytes calldata orderData) internal { - address account = msg.sender; - - uint256 jobId = accountJobCount[account] + 1; - accountJobCount[account]++; - - // prevent user from supplying an invalid number of execution (0) - uint16 nrOfExecutions = uint16(bytes2(orderData[6:8])); - if (nrOfExecutions == 0) revert InvalidExecution(); - - executionLog[account][jobId] = ExecutionConfig({ - numberOfExecutionsCompleted: 0, - isEnabled: true, - lastExecutionTime: 0, - executeInterval: uint48(bytes6(orderData[0:6])), - numberOfExecutions: nrOfExecutions, - startDate: uint48(bytes6(orderData[8:14])), - executionData: orderData[14:] - }); - - emit ExecutionAdded(account, jobId); - } - - function _isExecutionValid(uint256 jobId) internal view { - ExecutionConfig storage executionConfig = executionLog[msg.sender][jobId]; - - if (!executionConfig.isEnabled) { - revert InvalidExecution(); - } - - if (executionConfig.lastExecutionTime + executionConfig.executeInterval > block.timestamp) { - revert InvalidExecution(); - } - - if (executionConfig.numberOfExecutionsCompleted >= executionConfig.numberOfExecutions) { - revert InvalidExecution(); - } - - if (executionConfig.startDate > block.timestamp) { - revert InvalidExecution(); - } - } - - modifier canExecute(uint256 jobId) { - _isExecutionValid(jobId); - _; - } - - /*////////////////////////////////////////////////////////////////////////// - METADATA - //////////////////////////////////////////////////////////////////////////*/ - - function isModuleType(uint256 typeID) external pure override returns (bool) { - return typeID == TYPE_EXECUTOR; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/Flashloan.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/Flashloan.sol deleted file mode 100644 index e52e59d..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/Flashloan.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -enum FlashLoanType { - ERC20, - ERC721 -} - -interface IERC6682 { - function flashFeeToken() external view returns (address); - function flashFee(address token, uint256 tokenId) external view returns (uint256); - function availableForFlashLoan(address token, uint256 tokenId) external view returns (bool); -} - -/** - * @dev Interface of the ERC3156 FlashLender, as defined in - * https://eips.ethereum.org/EIPS/eip-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); -} - -/** - * @dev Interface of the ERC3156 FlashBorrower, as defined in - * https://eips.ethereum.org/EIPS/eip-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/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC1271.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC1271.sol deleted file mode 100644 index 2bce20b..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC1271.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -// bytes4(keccak256("isValidSignature(bytes32,bytes)") -bytes4 constant EIP1271_MAGIC_VALUE = 0x1626ba7e; - -interface IERC1271 { - /** - * @dev Should return whether the signature provided is valid for the provided data - * @param _dataHash Arbitrary length data signed on behalf of address(this) - * @param _signature Signature byte array associated with _data - * - * MUST return the bytes4 magic value 0x1626ba7e when function passes. - * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > - * 0.5) - * MUST allow external calls - */ - function isValidSignature( - bytes32 _dataHash, - bytes calldata _signature - ) - external - view - returns (bytes4); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC712.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC712.sol deleted file mode 100644 index 9b88f2c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC712.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -interface IERC712 { - function domainSeparator() external view returns (bytes32); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC7484.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC7484.sol deleted file mode 100644 index bc07019..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IERC7484.sol +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -interface IERC7484 { - event NewTrustedAttesters(); - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Check with Registry internal attesters */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - function check(address module) external view; - - function checkForAccount(address smartAccount, address module) external view; - - function check(address module, uint256 moduleType) external view; - - function checkForAccount( - address smartAccount, - address module, - uint256 moduleType - ) - external - view; - - /** - * Allows Smart Accounts - the end users of the registry - to appoint - * one or many attesters as trusted. - * @dev this function reverts, if address(0), or duplicates are provided in attesters[] - * - * @param threshold The minimum number of attestations required for a module - * to be considered secure. - * @param attesters The addresses of the attesters to be trusted. - */ - function trustAttesters(uint8 threshold, address[] calldata attesters) external; - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Check with external attester(s) */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - function check(address module, address[] calldata attesters, uint256 threshold) external view; - - function check( - address module, - uint256 moduleType, - address[] calldata attesters, - uint256 threshold - ) - external - view; -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IPolicy.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IPolicy.sol deleted file mode 100644 index 63e1829..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IPolicy.sol +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -// solhint-disable no-unused-import -import { PackedUserOperation, _packValidationData } from "../../external/ERC4337.sol"; -import { - IModule as IERC7579Module, - VALIDATION_SUCCESS, - VALIDATION_FAILED -} from "../../accounts/common/interfaces/IERC7579Module.sol"; -import { IERC165 } from "forge-std/interfaces/IERC165.sol"; - -type ConfigId is bytes32; - -/** - * IPolicy are external contracts that enforce policies / permission on 4337/7579 executions - * Since it's not the account calling into this contract, and check functions are called during the - * ERC4337 validation - * phase, IPolicy implementations MUST follow ERC4337 storage and opcode restrictions - * A recommend storage layout to store policy related data: - * mapping(id => msg.sender => userOp.sender(account) => state) - * ^ smartSession ^ smart account (associated storage) - */ -interface IPolicy is IERC165, IERC7579Module { - function isInitialized(address account, ConfigId configId) external view returns (bool); - function isInitialized( - address account, - address mulitplexer, - ConfigId configId - ) - external - view - returns (bool); - - /** - * This function may be called by the multiplexer (SmartSessions) without deinitializing first. - * Policies MUST overwrite the current state when this happens - */ - function initializeWithMultiplexer( - address account, - ConfigId configId, - bytes calldata initData - ) - external; -} - -/** - * IUserOpPolicy is a policy that enforces restrictions on user operations. It is called during the - * validation phase - * of the ERC4337 execution. - * Use this policy to enforce restrictions on user operations (userOp.gas, Time based restrictions). - * The checkUserOpPolicy function should return a uint256 value that represents the policy's - * decision. - * The policy's decision should be one of the following: - * - VALIDATION_SUCCESS: The user operation is allowed. - * - VALIDATION_FAILED: The user operation is not allowed. - */ -interface IUserOpPolicy is IPolicy { - function checkUserOpPolicy( - ConfigId id, - PackedUserOperation calldata userOp - ) - external - returns (uint256); -} - -/** - * IActionPolicy is a policy that enforces restrictions on actions. It is called during the - * validation phase - * of the ERC4337 execution. - * ERC7579 accounts natively support batched executions. So in one userOp, multiple actions can be - * executed. - * SmartSession will destruct the execution batch, and call the policy for each action, if the - * policy is installed for - * the actionId for the account. - * Use this policy to enforce restrictions on individual actions (i.e. transfers, approvals, etc). - * The checkAction function should return a uint256 value that represents the policy's decision. - * The policy's decision should be one of the following: - * - VALIDATION_SUCCESS: The action is allowed. - * - VALIDATION_FAILED: The action is not allowed. - */ -interface IActionPolicy is IPolicy { - function checkAction( - ConfigId id, - address account, - address target, - uint256 value, - bytes calldata data - ) - external - returns (uint256); -} - -/** - * I1271Policy is a policy that enforces restrictions on 1271 signed actions. It is called during an - * ERC1271 signature - * validation - */ -interface I1271Policy is IPolicy { - // request sender is probably protocol, so can introduce policies based on it. - function check1271SignedAction( - ConfigId id, - address requestSender, - address account, - bytes32 hash, - bytes calldata signature - ) - external - view - returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IStatelessValidator.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IStatelessValidator.sol deleted file mode 100644 index 59c367e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/interfaces/IStatelessValidator.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -interface IStatelessValidator { - function validateSignatureWithData( - bytes32 hash, - bytes calldata signature, - bytes calldata data - ) - external - view - returns (bool); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockExecutor.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockExecutor.sol deleted file mode 100644 index f77c19d..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockExecutor.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -import { ERC7579ExecutorBase } from "../ERC7579ExecutorBase.sol"; -// solhint-disable-next-line no-unused-import -import { IERC7579Account } from "../../accounts/common/interfaces/IERC7579Account.sol"; - -contract MockExecutor is ERC7579ExecutorBase { - function onInstall(bytes calldata data) external override { } - - function onUninstall(bytes calldata data) external override { } - - function exec( - address account, - address to, - uint256 value, - bytes calldata callData - ) - external - returns (bytes memory) - { - return _execute(account, to, value, callData); - } - - function isModuleType(uint256 typeID) external pure override returns (bool) { - return typeID == TYPE_EXECUTOR; - } - - function isInitialized( - address // smartAccount - ) - external - pure - returns (bool) - { - return false; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockFallback.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockFallback.sol deleted file mode 100644 index d140019..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockFallback.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -import { ERC7579FallbackBase } from "../ERC7579FallbackBase.sol"; - -contract MockFallback is ERC7579FallbackBase { - function onInstall(bytes calldata data) external override { } - - function onUninstall(bytes calldata data) external override { } - - function targetFunction() external pure returns (bool) { - return true; - } - - function isModuleType(uint256 typeID) external pure returns (bool) { - return typeID == TYPE_FALLBACK; - } - - function isInitialized( - address // smartAccount - ) - external - pure - returns (bool) - { - return false; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHook.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHook.sol deleted file mode 100644 index 6906f9e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHook.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -import { ERC7579HookBase } from "../ERC7579HookBase.sol"; - -contract MockHook is ERC7579HookBase { - function onInstall(bytes calldata data) external override { } - - function onUninstall(bytes calldata data) external override { } - - function _preCheck( - address account, - address msgSender, - uint256 msgValue, - bytes calldata msgData - ) - internal - override - returns (bytes memory hookData) - { } - function _postCheck(address account, bytes calldata hookData) internal override { } - - function isInitialized( - address // smartAccount - ) - external - pure - returns (bool) - { - return false; - } - - function isModuleType(uint256 typeID) external pure returns (bool) { - return typeID == TYPE_HOOK; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHookMultiPlexer.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHookMultiPlexer.sol deleted file mode 100644 index 0362dd0..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHookMultiPlexer.sol +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -import { ERC7579HookBase } from "../ERC7579HookBase.sol"; - -contract MockHookMultiPlexer is ERC7579HookBase { - error PreCheckFailed(address hook); - error PostCheckFailed(address hook); - - struct Hook { - address hook; - bool isInitialized; - } - - mapping(address account => Hook[] hookData) public hooks; - - function onInstall(bytes calldata data) external override { - if (data.length == 0) return; - (address[] memory _hooks) = abi.decode(data, (address[])); - for (uint256 i = 0; i < _hooks.length; i++) { - Hook memory _hook = Hook(_hooks[i], true); - hooks[msg.sender].push(_hook); - } - } - - function onUninstall(bytes calldata) external override { - delete hooks[msg.sender]; - } - - function addHook(address hook) external { - Hook memory _hook = Hook(hook, false); - hooks[msg.sender].push(_hook); - } - - function removeHook(address hook) external { - Hook[] storage _hooks = hooks[msg.sender]; - for (uint256 i = 0; i < _hooks.length; i++) { - if (_hooks[i].hook == hook) { - _hooks[i] = _hooks[_hooks.length - 1]; - _hooks.pop(); - break; - } - } - } - - function isHookInstalled(address account, address hook) external view returns (bool) { - Hook[] memory _hooks = hooks[account]; - for (uint256 i = 0; i < _hooks.length; i++) { - if (_hooks[i].hook == hook) return true; - } - return false; - } - - function _preCheck( - address account, - address msgSender, - uint256 msgValue, - bytes calldata msgData - ) - internal - override - returns (bytes memory hookData) - { - uint256 length = hooks[account].length; - if (length == 0) return hookData; - - bytes[] memory _hookData = new bytes[](length); - for (uint256 i = 0; i < length; i++) { - Hook storage _hook = hooks[account][i]; - if (!_hook.isInitialized) { - _hook.isInitialized = true; - } - (bool success, bytes memory _ret) = _hook.hook.call( - abi.encodePacked( - abi.encodeCall(ERC7579HookBase.preCheck, (msgSender, msgValue, msgData)), - address(this), - msg.sender - ) - ); - if (!success) revert PreCheckFailed(_hook.hook); - _hookData[i] = abi.decode(_ret, (bytes)); - } - hookData = abi.encode(_hookData); - } - - function _postCheck(address account, bytes calldata hookData) internal override { - uint256 length = hooks[account].length; - if (length == 0) return; - - bytes[] memory _hookData = new bytes[](length); - if (hookData.length != 0) { - _hookData = abi.decode(hookData, (bytes[])); - } - for (uint256 i = 0; i < length; i++) { - Hook storage _hook = hooks[account][i]; - if (_hook.isInitialized) { - (bool success,) = _hook.hook.call( - abi.encodePacked( - abi.encodeCall(ERC7579HookBase.postCheck, (_hookData[i])), - address(this), - msg.sender - ) - ); - if (!success) revert PostCheckFailed(_hook.hook); - } - } - } - - function isInitialized(address smartAccount) external view returns (bool) { - return hooks[smartAccount].length > 0; - } - - function isModuleType(uint256 typeID) external pure returns (bool) { - return typeID == TYPE_HOOK; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHybridValidator.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHybridValidator.sol deleted file mode 100644 index fa9a5ae..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockHybridValidator.sol +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -import { ERC7579HybridValidatorBase } from "../ERC7579HybridValidatorBase.sol"; -import { PackedUserOperation } from "../../external/ERC4337.sol"; - -contract MockHybridValidator is ERC7579HybridValidatorBase { - function onInstall(bytes calldata data) external virtual override { } - - function onUninstall(bytes calldata data) external virtual override { } - - function validateUserOp( - PackedUserOperation calldata, // userOp - bytes32 // userOpHash - ) - external - virtual - override - returns (ValidationData) - { - return - _packValidationData({ sigFailed: false, validUntil: type(uint48).max, validAfter: 0 }); - } - - function isValidSignatureWithSender( - address, // sender - bytes32, // hash - bytes calldata // data - ) - external - view - virtual - override - returns (bytes4) - { - return EIP1271_SUCCESS; - } - - function isModuleType(uint256 typeID) external pure override returns (bool) { - return typeID == TYPE_VALIDATOR || typeID == TYPE_STATELESS_VALIDATOR; - } - - function isInitialized( - address // smartAccount - ) - external - pure - returns (bool) - { - return false; - } - - function validateSignatureWithData( - bytes32, - bytes calldata, - bytes calldata - ) - external - pure - override - returns (bool validSig) - { - return true; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockPolicy.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockPolicy.sol deleted file mode 100644 index 398da15..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockPolicy.sol +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -import { PackedUserOperation } from - "@ERC4337/account-abstraction/contracts/interfaces/PackedUserOperation.sol"; - -contract MockPolicy { - mapping(address account => uint256 validation) public validationData; - mapping( - bytes32 id => mapping(address msgSender => mapping(address userOpSender => uint256 calls)) - ) public userOpState; - mapping( - bytes32 id => mapping(address msgSender => mapping(address userOpSender => uint256 calls)) - ) public actionState; - - function setValidationData(address account, uint256 validation) external { - validationData[account] = validation; - } - - function initializeWithMultiplexer( - address account, - bytes32 configId, - bytes calldata - ) - external - { - userOpState[configId][msg.sender][account] = 1; - } - - function checkUserOpPolicy( - bytes32 id, - PackedUserOperation calldata userOp - ) - external - returns (uint256) - { - userOpState[id][msg.sender][userOp.sender] += 1; - return validationData[userOp.sender]; - } - - function checkAction( - bytes32 id, - address account, - address, - uint256, - bytes calldata - ) - external - returns (uint256) - { - actionState[id][msg.sender][account] += 1; - return validationData[account]; - } - - function supportsInterface(bytes4) external pure returns (bool) { - return true; - } - - function check1271SignedAction( - bytes32, - address, - address, - bytes32, - bytes calldata - ) - external - pure - returns (bool) - { - return true; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockRegistry.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockRegistry.sol deleted file mode 100644 index 4f1c092..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockRegistry.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -import { IERC7484 } from "../interfaces/IERC7484.sol"; - -/// @title MockRegistry -/// @author zeroknots -contract MockRegistry is IERC7484 { - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Check with Registry internal attesters */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - function check(address module) external view { } - - function checkForAccount(address smartAccount, address module) external view { } - - function check(address module, uint256 moduleType) external view { } - - function checkForAccount( - address smartAccount, - address module, - uint256 moduleType - ) - external - view - { } - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* Check with external attester(s) */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - function check(address module, address[] calldata attesters, uint256 threshold) external view { } - - function check( - address module, - uint256 moduleType, - address[] calldata attesters, - uint256 threshold - ) - external - view - { } - - function trustAttesters(uint8 threshold, address[] calldata attesters) external { } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockStatelessValidator.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockStatelessValidator.sol deleted file mode 100644 index 835469e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockStatelessValidator.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -import { ERC7579StatelessValidatorBase } from "../ERC7579StatelessValidatorBase.sol"; - -contract MockStatelessValidator is ERC7579StatelessValidatorBase { - function onInstall(bytes calldata data) external virtual { } - - function onUninstall(bytes calldata data) external virtual { } - - function isModuleType(uint256 typeID) external pure returns (bool) { - return typeID == 7; - } - - function isInitialized(address) external pure returns (bool) { - return true; - } - - function validateSignatureWithData( - bytes32, - bytes calldata, - bytes calldata - ) - external - pure - override - returns (bool validSig) - { - return true; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockTarget.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockTarget.sol deleted file mode 100644 index 12a3ef5..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockTarget.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -contract MockTarget { - error Unauthorized(); - - uint256 public value; - - function set(uint256 _value) public payable returns (uint256) { - value = _value; - return _value; - } - - function setAccessControl(uint256 _value) public returns (uint256) { - if (msg.sender != address(this)) { - revert Unauthorized(); - } - value = _value; - return _value; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockValidator.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockValidator.sol deleted file mode 100644 index 0b77c2f..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/mocks/MockValidator.sol +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -/* solhint-disable no-unused-vars */ -import { ERC7579ValidatorBase } from "../ERC7579ValidatorBase.sol"; -import { PackedUserOperation } from "../../external/ERC4337.sol"; - -contract MockValidator is ERC7579ValidatorBase { - function onInstall(bytes calldata data) external virtual override { } - - function onUninstall(bytes calldata data) external virtual override { } - - function validateUserOp( - PackedUserOperation calldata, // userOp - bytes32 // userOpHash - ) - external - virtual - override - returns (ValidationData) - { - return - _packValidationData({ sigFailed: false, validUntil: type(uint48).max, validAfter: 0 }); - } - - function isValidSignatureWithSender( - address, // sender - bytes32, // hash - bytes calldata // data - ) - external - view - virtual - override - returns (bytes4) - { - return EIP1271_SUCCESS; - } - - function isModuleType(uint256 typeID) external pure override returns (bool) { - return typeID == TYPE_VALIDATOR; - } - - function isInitialized( - address // smartAccount - ) - external - pure - returns (bool) - { - return false; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579Constants.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579Constants.sol deleted file mode 100644 index e075df5..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579Constants.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -uint256 constant MODULE_TYPE_VALIDATOR = 1; -uint256 constant MODULE_TYPE_EXECUTOR = 2; -uint256 constant MODULE_TYPE_FALLBACK = 3; -uint256 constant MODULE_TYPE_HOOK = 4; -uint256 constant MODULE_TYPE_POLICY = 5; -uint256 constant MODULE_TYPE_SIGNER = 6; -uint256 constant MODULE_TYPE_STATELESS_VALIDATOR = 7; -uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC1271 = 8; -uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC4337 = 9; diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579ValidatorLib.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579ValidatorLib.sol deleted file mode 100644 index cfc4173..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/ERC7579ValidatorLib.sol +++ /dev/null @@ -1,190 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -// solhint-disable-next-line no-unused-import -import { IERC7579Account, Execution } from "../../accounts/common/interfaces/IERC7579Account.sol"; -import { PackedUserOperation, UserOperationLib } from "../../external/ERC4337.sol"; - -enum ACCOUNT_EXEC_TYPE { - EXEC_SINGLE, - EXEC_BATCH, - EXEC_SINGLE_FROM_EXECUTOR, - EXEC_BATCH_FROM_EXECUTOR, - UNINSTALL_HOOK, - INSTALL_VALIDATOR, - INSTALL_EXECUTOR, - ERROR -} - -library ERC7579ValidatorLib { - error InvalidExecutionType(); - - function decodeExecType(PackedUserOperation calldata _ops) - internal - pure - returns (ACCOUNT_EXEC_TYPE _type) - { - return decodeExecType(_ops.callData); - } - - function decodeExecType(bytes calldata userOpCalldata) - internal - pure - returns (ACCOUNT_EXEC_TYPE _type) - { - // bytes4 functionSig = bytes4(userOpCalldata[:4]); - - // if (IERC7579Account.execute.selector == functionSig) { - // _type = ACCOUNT_EXEC_TYPE.EXEC_SINGLE; - // } else if (IERC7579Account.executeBatch.selector == functionSig) { - // _type = ACCOUNT_EXEC_TYPE.EXEC_BATCH; - // } else if (IERC7579Account.executeFromExecutor.selector == functionSig) { - // _type = ACCOUNT_EXEC_TYPE.EXEC_SINGLE_FROM_EXECUTOR; - // } else if (IERC7579Account.executeBatchFromExecutor.selector == functionSig) { - // _type = ACCOUNT_EXEC_TYPE.EXEC_BATCH_FROM_EXECUTOR; - // } else if (IERC7579Account.installValidator.selector == functionSig) { - // _type = ACCOUNT_EXEC_TYPE.INSTALL_VALIDATOR; - // } else if (IERC7579Account.installExecutor.selector == functionSig) { - // _type = ACCOUNT_EXEC_TYPE.INSTALL_EXECUTOR; - // } else if (IERC7579Account.uninstallHook.selector == functionSig) { - // _type = ACCOUNT_EXEC_TYPE.UNINSTALL_HOOK; - // } else { - // _type = ACCOUNT_EXEC_TYPE.ERROR; - // } - } - - function decodeCalldataBatch(bytes calldata userOpCalldata) - internal - pure - returns (Execution[] calldata executionBatch) - { - /* - * Batch Call Calldata Layout - * Offset (in bytes) | Length (in bytes) | Contents - * 0x0 | 0x4 | bytes4 function selector - * 0x4 | - | - abi.encode(Execution[]) - */ - // solhint-disable-next-line no-inline-assembly - assembly ("memory-safe") { - let offset := add(userOpCalldata.offset, 0x4) - let baseOffset := offset - - let dataPointer := add(baseOffset, calldataload(offset)) - - // Extract the ERC7579 Executions - executionBatch.offset := add(dataPointer, 32) - executionBatch.length := calldataload(dataPointer) - } - } - - function decodeCalldataSingle(bytes calldata userOpCalldata) - internal - pure - returns (address destination, uint256 value, bytes calldata callData) - { - bytes calldata accountExecCallData = userOpCalldata[4:]; - destination = address(bytes20(accountExecCallData[12:32])); - value = uint256(bytes32(accountExecCallData[32:64])); - callData = accountExecCallData[128:userOpCalldata.length - 32]; - } - - function decodeConfig(bytes calldata callData) - internal - pure - returns (address module, bytes calldata _callData) - { - module = address(bytes20(callData[12:32])); - _callData = callData[32:]; - } - - function validateWith( - PackedUserOperation calldata userOp, - function(PackedUserOperation calldata,address,uint256,bytes calldata) internal returns(uint48,uint48) - validationFunction - ) - internal - returns (uint48 validUntil, uint48 validAfter) - { - ACCOUNT_EXEC_TYPE _type = decodeExecType(userOp); - - address target; - uint256 value; - bytes calldata callData; - if (ACCOUNT_EXEC_TYPE.EXEC_SINGLE == _type) { - (target, value, callData) = decodeCalldataSingle(userOp.callData); - (validUntil, validAfter) = validationFunction(userOp, target, value, callData); - } else if (ACCOUNT_EXEC_TYPE.EXEC_BATCH == _type) { - Execution[] calldata executionBatch = decodeCalldataBatch(userOp.callData); - uint256 length = executionBatch.length; - for (uint256 i; i < length; i++) { - Execution calldata execution = executionBatch[i]; - (target, value, callData) = (execution.target, execution.value, execution.callData); - (uint256 _newValidUntil, uint256 _newValidAfter) = - validationFunction(userOp, target, value, callData); - (validUntil, validAfter) = - getValidUntil(validUntil, validAfter, _newValidUntil, _newValidAfter); - } - } else { - revert InvalidExecutionType(); - } - } -} - -abstract contract Decoder { - using ERC7579ValidatorLib for *; - using UserOperationLib for *; - - function validate(PackedUserOperation calldata userOp) internal { - ACCOUNT_EXEC_TYPE accountExecType = userOp.callData.decodeExecType(); - address smartAccount = userOp.getSender(); - - if (ACCOUNT_EXEC_TYPE.EXEC_SINGLE == accountExecType) { - (address target, uint256 value, bytes calldata data) = - ERC7579ValidatorLib.decodeCalldataSingle(userOp.callData); - onValidate(smartAccount, target, value, data); - } else if (ACCOUNT_EXEC_TYPE.EXEC_BATCH == accountExecType) { - Execution[] calldata executionBatch = - ERC7579ValidatorLib.decodeCalldataBatch(userOp.callData); - uint256 length; - for (uint256 i; i < length; i++) { - Execution calldata execution = executionBatch[i]; - onValidate(smartAccount, execution.target, execution.value, execution.callData); - } - } else { - revert ERC7579ValidatorLib.InvalidExecutionType(); - } - } - - function onValidate( - address smartAccount, - address target, - uint256 value, - bytes calldata data - ) - internal - virtual - returns (bytes[] memory); -} - -function getValidUntil( - uint256 maxValidUntil, - uint256 minValidAfter, - uint256 newValidUntil, - uint256 newValidAfter -) - pure - returns (uint48 _maxValidUntil, uint48 _minValidAfter) -{ - if (newValidUntil > maxValidUntil) { - _maxValidUntil = uint48(newValidUntil); - } else { - _maxValidUntil = uint48(maxValidUntil); - } - - if (newValidAfter > minValidAfter) { - _minValidAfter = uint48(newValidAfter); - } else { - _minValidAfter = uint48(minValidAfter); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/TrustedForwarder.sol b/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/TrustedForwarder.sol deleted file mode 100644 index da84eec..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/module-bases/utils/TrustedForwarder.sol +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -abstract contract TrustedForwarder { - // account => trustedForwarder - mapping(address account => address trustedForwarder) public trustedForwarder; - - /** - * Set the trusted forwarder for an account - * - * @param forwarder The address of the trusted forwarder - */ - function setTrustedForwarder(address forwarder) external { - trustedForwarder[msg.sender] = forwarder; - } - - /** - * Clear the trusted forwarder for an account - */ - function clearTrustedForwarder() public { - trustedForwarder[msg.sender] = address(0); - } - - /** - * Check if a forwarder is trusted for an account - * - * @param forwarder The address of the forwarder - * @param account The address of the account - * - * @return true if the forwarder is trusted for the account - */ - function isTrustedForwarder(address forwarder, address account) public view returns (bool) { - return forwarder == trustedForwarder[account]; - } - - /** - * Get the sender of the transaction - * - * @return account the sender of the transaction - */ - function _getAccount() internal view returns (address account) { - account = msg.sender; - address _account; - address forwarder; - if (msg.data.length >= 40) { - // solhint-disable-next-line no-inline-assembly - assembly { - _account := shr(96, calldataload(sub(calldatasize(), 20))) - forwarder := shr(96, calldataload(sub(calldatasize(), 40))) - } - if (forwarder == msg.sender && isTrustedForwarder(forwarder, _account)) { - account = _account; - } - } - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/Auxiliary.sol b/typescript/packages/account-modules/lib/modulekit/src/test/Auxiliary.sol deleted file mode 100644 index 89831ee..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/Auxiliary.sol +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IEntryPoint, PackedUserOperation } from "../external/ERC4337.sol"; -import { IERC7579Bootstrap } from "../accounts/erc7579/interfaces/IERC7579Bootstrap.sol"; -import { IERC7484 } from "../Interfaces.sol"; -import { ISmartSession } from "../integrations/interfaces/ISmartSession.sol"; - -// Deployments -import { etchEntrypoint } from "../deployment/predeploy/EntryPoint.sol"; -import { etchSmartSessions } from "../deployment/precompiles/SmartSessionsPrecompiles.sol"; -import { etchRegistry } from "../deployment/predeploy/Registry.sol"; - -// External Dependencies -import { EntryPointSimulations } from - "@ERC4337/account-abstraction/contracts/core/EntryPointSimulations.sol"; -import { IEntryPointSimulations } from - "@ERC4337/account-abstraction/contracts/interfaces/IEntryPointSimulations.sol"; - -// Mocks -import { MockFactory } from "../deployment/predeploy/MockFactory.sol"; - -// Utils -import { UserOpGasLog } from "./utils/gas/UserOpGasLog.sol"; -import "./utils/Vm.sol"; -import "./utils/Log.sol"; - -/// @notice Auxiliary structs to hold all the necessary auxiliary contracts for testing. -/// @param entrypoint The entrypoint contract. -/// @param gasSimulation The gas simulation contract. -/// @param registry The registry contract. -/// @param mockFactory The mock factory contract. -/// @param smartSession The smart session contract. -struct Auxiliary { - IEntryPoint entrypoint; - UserOpGasLog gasSimulation; - IERC7484 registry; - MockFactory mockFactory; - ISmartSession smartSession; -} - -/// @notice Auxiliary factory to deploy all the necessary auxiliary contracts for testing. -contract AuxiliaryFactory { - /// @notice Stores the auxiliary contracts. - Auxiliary public auxiliary; - - /// @notice Initializes and labels all the auxiliary contracts. - function init() internal virtual { - auxiliary.mockFactory = new MockFactory(); - label(address(auxiliary.mockFactory), "Mock Factory"); - auxiliary.gasSimulation = new UserOpGasLog(); - auxiliary.entrypoint = etchEntrypoint(); - label(address(auxiliary.entrypoint), "EntryPoint"); - auxiliary.registry = etchRegistry(); - label(address(auxiliary.registry), "ERC7484Registry"); - auxiliary.smartSession = etchSmartSessions(); - label(address(auxiliary.smartSession), "SmartSession"); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/ModuleKitHelpers.sol b/typescript/packages/account-modules/lib/modulekit/src/test/ModuleKitHelpers.sol deleted file mode 100644 index 55252ec..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/ModuleKitHelpers.sol +++ /dev/null @@ -1,1322 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { - AccountInstance, - UserOpData, - ExecutionReturnData, - AccountType, - DEFAULT, - SAFE, - NEXUS, - KERNEL, - CUSTOM -} from "./RhinestoneModuleKit.sol"; -import { PackedUserOperation } from "../external/ERC4337.sol"; -import { MODULE_TYPE_HOOK } from "../accounts/common/interfaces/IERC7579Module.sol"; -import { Execution } from "../accounts/erc7579/lib/ExecutionLib.sol"; -import { - Session, - PermissionId, - ActionData, - PolicyData, - ERC7739Data, - ISessionValidator, - SmartSessionMode, - ISmartSession, - EnableSession, - ChainDigest -} from "../integrations/interfaces/ISmartSession.sol"; -import { Solarray } from "solarray/Solarray.sol"; - -// Helpers -import { ERC4337Helpers } from "./utils/ERC4337Helpers.sol"; -import { HelperBase } from "./helpers/HelperBase.sol"; -import { KernelHelpers } from "./helpers/KernelHelpers.sol"; - -// Utils -import { - prank, - VmSafe, - startStateDiffRecording as vmStartStateDiffRecording, - stopAndReturnStateDiff as vmStopAndReturnStateDiff, - getMappingKeyAndParentOf, - envOr, - setEnv -} from "./utils/Vm.sol"; -import { - getAccountType as getAccountTypeFromStorage, - writeAccountType, - writeExpectRevert, - writeGasIdentifier, - writeSimulateUserOp, - writeStorageCompliance, - getStorageCompliance, - getSimulateUserOp, - writeAccountEnv, - getFactory, - getHelper as getHelperFromStorage, - getAccountEnv as getAccountEnvFromStorage, - getInstalledModules as getInstalledModulesFromStorage, - writeInstalledModule as writeInstalledModuleToStorage, - removeInstalledModule as removeInstalledModuleFromStorage, - InstalledModule -} from "./utils/Storage.sol"; -import { recordLogs, VmSafe, getRecordedLogs } from "./utils/Vm.sol"; - -// Libraries -import { EncodeLib, HashLib } from "../test/helpers/SmartSessionHelpers.sol"; - -/// @notice A library that contains helper functions for building, testing, deploying, and -/// interacting with ERC7579 accounts and modules -library ModuleKitHelpers { - /*////////////////////////////////////////////////////////////////////////// - ERRORS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Thrown when an invalid account type is provided, currently only DEFAULT, SAFE, - /// KERNEL, CUSTOM, and NEXUS are supported account types - error InvalidAccountType(); - - /// @notice Thrown when the smart sessions module is not installed - error SmartSessionNotInstalled(); - - /*////////////////////////////////////////////////////////////////////////// - LIBRARIES - //////////////////////////////////////////////////////////////////////////*/ - - using ModuleKitHelpers for AccountInstance; - using ModuleKitHelpers for UserOpData; - using ModuleKitHelpers for AccountType; - - /*////////////////////////////////////////////////////////////////////////// - EXECUTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Executes userOps on the entrypoint - /// @param userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint - /// @return ExecutionReturnData struct containing the logs from the execution - function execUserOps(UserOpData memory userOpData) - internal - returns (ExecutionReturnData memory) - { - // Send userOp to entrypoint - return ERC4337Helpers.exec4337(userOpData.userOp, userOpData.entrypoint); - } - - /// @notice Configures a userOp to execute a single operation - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param target The address of the contract to call - /// @param value The amount of ether to send - /// @param callData The data to send to the contract - /// @param txValidator The address of the transaction validator - /// @return userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint - function getExecOps( - AccountInstance memory instance, - address target, - uint256 value, - bytes memory callData, - address txValidator - ) - internal - returns (UserOpData memory userOpData) - { - bytes memory erc7579ExecCall = - HelperBase(instance.accountHelper).encode(target, value, callData); - (userOpData.userOp, userOpData.userOpHash) = - HelperBase(instance.accountHelper).execUserOp(instance, erc7579ExecCall, txValidator); - userOpData.entrypoint = instance.aux.entrypoint; - } - - /// @notice Configures a userOp to execute multiple operations - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param executions An array of Execution structs containing the target, value, and callData - /// @param txValidator The address of the transaction validator - /// @return userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint - function getExecOps( - AccountInstance memory instance, - Execution[] memory executions, - address txValidator - ) - internal - returns (UserOpData memory userOpData) - { - bytes memory erc7579ExecCall = HelperBase(instance.accountHelper).encode(executions); - (userOpData.userOp, userOpData.userOpHash) = - HelperBase(instance.accountHelper).execUserOp(instance, erc7579ExecCall, txValidator); - userOpData.entrypoint = instance.aux.entrypoint; - } - - /// @notice Configures a userOp to execute a single operation, signs it with the default - /// signature, and sends it to the entrypoint for execution - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param target The address of the contract to call - /// @param value The amount of ether to send - /// @param callData The data to send to the contract - /// @return userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint - function exec( - AccountInstance memory instance, - address target, - uint256 value, - bytes memory callData - ) - internal - returns (UserOpData memory userOpData) - { - // Get userOpData - userOpData = - instance.getExecOps(target, value, callData, address(instance.defaultValidator)); - // Sign userOp with default signature - userOpData = userOpData.signDefault(); - userOpData.entrypoint = instance.aux.entrypoint; - // Send userOp to entrypoint - userOpData.execUserOps(); - } - - /// @notice Executes a single operation on the entrypoint with value 0 - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param target The address of the contract to call - /// @param callData The data to send to the contract - function exec( - AccountInstance memory instance, - address target, - bytes memory callData - ) - internal - returns (UserOpData memory userOpData) - { - return exec(instance, target, 0, callData); - } - - /*////////////////////////////////////////////////////////////// - HOOKS - //////////////////////////////////////////////////////////////*/ - - /// @notice A hook used to initiate state diff recording before installing a module - function preEnvHook() internal { - if (envOr("COMPLIANCE", false) || getStorageCompliance()) { - // Start state diff recording - vmStartStateDiffRecording(); - } - } - - /// @notice A hook used to stop state diff recording and verify that storage was cleared after - /// uninstalling a module - function postEnvHook(AccountInstance memory instance, bytes memory data) internal { - if (envOr("COMPLIANCE", false) || getStorageCompliance()) { - address module = abi.decode(data, (address)); - // Stop state diff recording and return account accesses - VmSafe.AccountAccess[] memory accountAccesses = vmStopAndReturnStateDiff(); - // Check if storage was cleared - verifyModuleStorageWasCleared(instance, accountAccesses, module); - } - } - - /*////////////////////////////////////////////////////////////////////////// - MODULE CONFIG - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Installs a module on an account by generating a userOp and sending it to the - /// entrypoint - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param moduleTypeId The type of the module to install - /// @param module The address of the module to install - /// @param data Arbitrary data that may be required on the module during `onInstall` - /// initialization - /// @return userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint - function installModule( - AccountInstance memory instance, - uint256 moduleTypeId, - address module, - bytes memory data - ) - internal - returns (UserOpData memory userOpData) - { - // Run preEnvHook - preEnvHook(); - userOpData = instance.getInstallModuleOps( - moduleTypeId, module, data, address(instance.defaultValidator) - ); - // sign userOp with default signature - userOpData = userOpData.signDefault(); - userOpData.entrypoint = instance.aux.entrypoint; - // send userOp to entrypoint - userOpData.execUserOps(); - } - - /// @notice Uninstalls a module on an account by generating a userOp and sending it to the - /// entrypoint - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param moduleTypeId The type of the module to uninstall - /// @param module The address of the module to uninstall - /// @param data Arbitrary data that may be required on the module during `onUninstall` - /// de-initialization - /// @return userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint - function uninstallModule( - AccountInstance memory instance, - uint256 moduleTypeId, - address module, - bytes memory data - ) - internal - returns (UserOpData memory userOpData) - { - userOpData = instance.getUninstallModuleOps( - moduleTypeId, module, data, address(instance.defaultValidator) - ); - // sign userOp with default signature - userOpData = userOpData.signDefault(); - userOpData.entrypoint = instance.aux.entrypoint; - - // send userOp to entrypoint - userOpData.execUserOps(); - // Run postEnvHook - postEnvHook(instance, abi.encode(module)); - } - - /// @notice Checks if a module is installed on an account - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param moduleTypeId The type of the module to check - /// @param module The address of the module to check - /// @return bool True if the module is installed, false otherwise - function isModuleInstalled( - AccountInstance memory instance, - uint256 moduleTypeId, - address module - ) - internal - returns (bool) - { - return instance.account.code.length > 0 - && HelperBase(instance.accountHelper).isModuleInstalled(instance, moduleTypeId, module); - } - - /// @notice Checks if a module is installed on an account by using additional data - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param moduleTypeId The type of the module to check - /// @param module The address of the module to check - /// @param data Arbitrary data that may be required - function isModuleInstalled( - AccountInstance memory instance, - uint256 moduleTypeId, - address module, - bytes memory data - ) - internal - returns (bool) - { - return HelperBase(instance.accountHelper).isModuleInstalled( - instance, moduleTypeId, module, data - ); - } - - /// @notice Gets the data required to install a module - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param moduleTypeId The type of the module to install - /// @param module The address of the module to install - /// @param data Arbitrary data that may be required on the module during `onInstall` - /// initialization - /// @return bytes The data required to install the module - function getInstallModuleData( - AccountInstance memory instance, - uint256 moduleTypeId, - address module, - bytes memory data - ) - internal - view - returns (bytes memory) - { - return HelperBase(instance.accountHelper).getInstallModuleData( - instance, moduleTypeId, module, data - ); - } - - /// @notice Gets the data required to uninstall a module - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param moduleTypeId The type of the module to uninstall - /// @param module The address of the module to uninstall - /// @param data Arbitrary data that may be required on the module during `onUninstall` - /// de-initialization - /// @return bytes The data required to uninstall the module - function getUninstallModuleData( - AccountInstance memory instance, - uint256 moduleTypeId, - address module, - bytes memory data - ) - internal - view - returns (bytes memory) - { - return HelperBase(instance.accountHelper).getUninstallModuleData( - instance, moduleTypeId, module, data - ); - } - - /// @notice Generates a userOp to install a module on an account - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param module The address of the module to install - /// @param initData Arbitrary data that may be required on the module during `onInstall` - /// initialization - /// @param txValidator The address of the transaction validator - /// @return userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint - function getInstallModuleOps( - AccountInstance memory instance, - uint256 moduleType, - address module, - bytes memory initData, - address txValidator - ) - internal - returns (UserOpData memory userOpData) - { - // get userOp with correct nonce for selected txValidator - (userOpData.userOp, userOpData.userOpHash) = HelperBase(instance.accountHelper) - .configModuleUserOp(instance, moduleType, module, initData, true, txValidator); - userOpData.entrypoint = instance.aux.entrypoint; - } - - /// @notice Generates a userOp to uninstall a module on an account - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param module The address of the module to uninstall - /// @param initData Arbitrary data that may be required on the module during `onUninstall` - /// de-initialization - /// @param txValidator The address of the transaction validator - /// @return userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint - function getUninstallModuleOps( - AccountInstance memory instance, - uint256 moduleType, - address module, - bytes memory initData, - address txValidator - ) - internal - returns (UserOpData memory userOpData) - { - // get userOp with correct nonce for selected txValidator - (userOpData.userOp, userOpData.userOpHash) = HelperBase(instance.accountHelper) - .configModuleUserOp(instance, moduleType, module, initData, false, txValidator); - userOpData.entrypoint = instance.aux.entrypoint; - } - - /// @notice Gets all installed modules on an account - /// @param instance AccountInstance struct containing the account and accountHelper - /// @return InstalledModule[] An array of InstalledModule structs containing the module type and - /// address - function getInstalledModules(AccountInstance memory instance) - internal - view - returns (InstalledModule[] memory) - { - return getInstalledModulesFromStorage(instance.account); - } - - /// @notice Writes an installed module struct data to storage - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param module InstalledModule struct containing the module type and address - function writeInstalledModule( - AccountInstance memory instance, - InstalledModule memory module - ) - internal - { - writeInstalledModuleToStorage(module, instance.account); - } - - /// @notice Removes an installed module from storage - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param moduleType The type of the module to remove - /// @param moduleAddress The address of the module to remove - function removeInstalledModule( - AccountInstance memory instance, - uint256 moduleType, - address moduleAddress - ) - internal - { - // Get installed modules for account - InstalledModule[] memory installedModules = getInstalledModules(instance); - // Find module to remove (not super scalable at high module counts) - for (uint256 i; i < installedModules.length; i++) { - if ( - installedModules[i].moduleType == moduleType - && installedModules[i].moduleAddress == moduleAddress - ) { - // Remove module from storage - removeInstalledModuleFromStorage(i, instance.account); - return; - } - } - } - - /// @notice Starts recording the state diff - function startStateDiffRecording(AccountInstance memory) internal { - vmStartStateDiffRecording(); - } - - /// @notice Stop recording the state diff and return the account accesses - /// @return VmSafe.AccountAccess[] An array of AccountAccess structs containing the account - function stopAndReturnStateDiff(AccountInstance memory) - internal - returns (VmSafe.AccountAccess[] memory) - { - return vmStopAndReturnStateDiff(); - } - - /// @notice Verifies from an accountAccesses array that storage was correctly cleared after - /// uninstalling a module, reverts if storage was not cleared correctly - /// @param accountAccesses An array of AccountAccess structs containing the account - /// @param module The address of the module to check - function verifyModuleStorageWasCleared( - AccountInstance memory, - VmSafe.AccountAccess[] memory accountAccesses, - address module - ) - internal - view - { - bytes32[] memory seenSlots = new bytes32[](1000); - bytes32[] memory finalValues = new bytes32[](1000); - uint256 numSlots; - - // Loop through account accesses - for (uint256 i; i < accountAccesses.length; i++) { - // Skip tests - if (accountAccesses[i].accessor == address(this)) { - continue; - } - - // If we are accessing the storage of the module check writes and clears - if (accountAccesses[i].account == module) { - // Process all storage accesses for this module - for (uint256 j; j < accountAccesses[i].storageAccesses.length; j++) { - VmSafe.StorageAccess memory access = accountAccesses[i].storageAccesses[j]; - - // Skip reads - if (!access.isWrite) { - continue; - } - - // Find if we've seen this slot - bool found; - for (uint256 k; k < numSlots; k++) { - if (seenSlots[k] == access.slot) { - finalValues[k] = access.newValue; - found = true; - break; - } - } - - // If not seen, add it - if (!found) { - seenSlots[numSlots] = access.slot; - finalValues[numSlots] = access.newValue; - numSlots++; - } - } - } - } - - // Check if any slot's final value is non-zero - for (uint256 i; i < numSlots; i++) { - if (finalValues[i] != bytes32(0)) { - revert("Storage not cleared after uninstalling module"); - } - } - } - - /*////////////////////////////////////////////////////////////////////////// - CONTROL FLOW - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Sets the expect revert flag to true - function expect4337Revert(AccountInstance memory) internal { - writeExpectRevert(""); - } - - /// @notice Sets the expect revert flag to true for a given selector - /// @param selector The selector of the function that is expected to revert - function expect4337Revert(AccountInstance memory, bytes4 selector) internal { - writeExpectRevert(abi.encodePacked(selector)); - } - - /// @notice Sets the expect revert flag to true for a given message - /// @param message The message that is expected to revert - function expect4337Revert(AccountInstance memory, bytes memory message) internal { - writeExpectRevert(message); - } - - /// @notice Logs the gas used by an ERC-4337 transaction - /// @dev needs to be called before an exec4337 call - /// @dev the id needs to be unique across your tests, otherwise the gas calculations will - /// overwrite each other - /// @param id Identifier for the gas calculation, which will be used as the filename - function log4337Gas(AccountInstance memory, /* instance */ string memory id) internal { - writeGasIdentifier(id); - } - - /// @notice Writes the simulate user op flag to storage - /// @param value The value to write to storage (true or false) - function simulateUserOp(AccountInstance memory, bool value) internal { - writeSimulateUserOp(value); - string memory strValue = value ? "true" : "false"; - setEnv("SIMULATE", strValue); - } - - /// @notice Writes the storage compliance flag to storage - /// @param value The value to write to storage (true or false) - function storageCompliance(AccountInstance memory, bool value) internal { - writeStorageCompliance(value); - } - - /*////////////////////////////////////////////////////////////////////////// - ACCOUNT UTILS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Converts an AccountType enum to a string - /// @param _accountType The AccountType enum to convert - /// @return accountType The string representation of the AccountType - function toString(AccountType _accountType) internal pure returns (string memory accountType) { - if (_accountType == AccountType.DEFAULT) { - return DEFAULT; - } else if (_accountType == AccountType.SAFE) { - return SAFE; - } else if (_accountType == AccountType.KERNEL) { - return KERNEL; - } else if (_accountType == AccountType.CUSTOM) { - return CUSTOM; - } else if (_accountType == AccountType.NEXUS) { - return NEXUS; - } else { - revert InvalidAccountType(); - } - } - - /// @notice Converts a string to an AccountType enum - /// @param _accountType The string to convert - /// @return accountType The AccountType enum - function toAccountType(string memory _accountType) - internal - pure - returns (AccountType accountType) - { - if (keccak256(abi.encodePacked(_accountType)) == keccak256(abi.encodePacked(DEFAULT))) { - return AccountType.DEFAULT; - } else if (keccak256(abi.encodePacked(_accountType)) == keccak256(abi.encodePacked(SAFE))) { - return AccountType.SAFE; - } else if (keccak256(abi.encodePacked(_accountType)) == keccak256(abi.encodePacked(KERNEL))) - { - return AccountType.KERNEL; - } else if (keccak256(abi.encodePacked(_accountType)) == keccak256(abi.encodePacked(CUSTOM))) - { - return AccountType.CUSTOM; - } else if (keccak256(abi.encodePacked(_accountType)) == keccak256(abi.encodePacked(NEXUS))) - { - return AccountType.NEXUS; - } else { - revert InvalidAccountType(); - } - } - - /// @notice Deploys an account, writes installed modules to storage from recorded logs - /// @param instance AccountInstance struct containing the account and accountHelper - function deployAccount(AccountInstance memory instance) internal { - // Record logs to track installed modules - recordLogs(); - // Deploy account - HelperBase(instance.accountHelper).deployAccount(instance); - // Parse logs and determine if a module was installed - VmSafe.Log[] memory logs = getRecordedLogs(); - for (uint256 i; i < logs.length; i++) { - // ModuleInstalled(uint256, address) - if ( - logs[i].topics[0] - == 0xd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123 - ) { - (uint256 moduleType, address module) = abi.decode(logs[i].data, (uint256, address)); - writeInstalledModuleToStorage(InstalledModule(moduleType, module), logs[i].emitter); - } - } - } - - /// @notice Sets the account type in storage - /// @param env The AccountType enum to set - function setAccountType(AccountInstance memory, AccountType env) internal { - setAccountType(env); - } - - /// @notice Sets the account type in storage - /// @param env The AccountType enum to set - function setAccountType(AccountType env) internal { - writeAccountType(env.toString()); - } - - /// @notice Sets the account type in storage from a string - /// @param env The string to set - function setAccountEnv(AccountInstance memory, string memory env) internal { - setAccountEnv(env); - } - - /// @notice Sets the account type in storage from a string - /// @param env The string to set - function setAccountEnv(string memory env) internal { - _setAccountEnv(env); - } - - /// @notice Sets the account type in storage from an enum - /// @param env The AccountType enum to set - function setAccountEnv(AccountType env) internal { - _setAccountEnv(env.toString()); - } - - /// @notice Gets the account type from storage - /// @return accountType The account type - function getAccountType() internal view returns (AccountType accountType) { - bytes32 accountTypeHash = getAccountTypeFromStorage(); - if (accountTypeHash == keccak256(abi.encodePacked(DEFAULT))) { - return AccountType.DEFAULT; - } else if (accountTypeHash == keccak256(abi.encodePacked(SAFE))) { - return AccountType.SAFE; - } else if (accountTypeHash == keccak256(abi.encodePacked(KERNEL))) { - return AccountType.KERNEL; - } else if (accountTypeHash == keccak256(abi.encodePacked(CUSTOM))) { - return AccountType.CUSTOM; - } else if (accountTypeHash == keccak256(abi.encodePacked(NEXUS))) { - return AccountType.NEXUS; - } else { - revert InvalidAccountType(); - } - } - - /// @notice Gets the account type from storage for an AccountInstance - function getAccountType(AccountInstance memory) - internal - view - returns (AccountType accountType) - { - return getAccountType(); - } - - /// @notice Sets the account type in storage from a string - function _setAccountEnv(string memory env) private { - address factory = getFactory(env); - address helper = getHelperFromStorage(env); - if (keccak256(abi.encodePacked(env)) == keccak256(abi.encodePacked(DEFAULT))) { - writeAccountEnv(env, factory, helper); - } else if (keccak256(abi.encodePacked(env)) == keccak256(abi.encodePacked(SAFE))) { - writeAccountEnv(env, factory, helper); - } else if (keccak256(abi.encodePacked(env)) == keccak256(abi.encodePacked(KERNEL))) { - writeAccountEnv(env, factory, helper); - } else if (keccak256(abi.encodePacked(env)) == keccak256(abi.encodePacked(CUSTOM))) { - writeAccountEnv(env, factory, helper); - } else if (keccak256(abi.encodePacked(env)) == keccak256(abi.encodePacked(NEXUS))) { - writeAccountEnv(env, factory, helper); - } else { - revert InvalidAccountType(); - } - } - - /// @notice Gets the account environment from storage - function getAccountEnv() internal view returns (AccountType env, address, address) { - (bytes32 envHash, address factory, address helper) = getAccountEnvFromStorage(); - if (envHash == keccak256(abi.encodePacked(DEFAULT))) { - return (AccountType.DEFAULT, factory, helper); - } else if (envHash == keccak256(abi.encodePacked(SAFE))) { - return (AccountType.SAFE, factory, helper); - } else if (envHash == keccak256(abi.encodePacked(KERNEL))) { - return (AccountType.KERNEL, factory, helper); - } else if (envHash == keccak256(abi.encodePacked(CUSTOM))) { - return (AccountType.CUSTOM, factory, helper); - } else if (envHash == keccak256(abi.encodePacked(NEXUS))) { - return (AccountType.NEXUS, factory, helper); - } else { - revert InvalidAccountType(); - } - } - - /// @notice Gets the account environment from storage for an AccountInstance - function getAccountEnv(AccountInstance memory) - internal - view - returns (AccountType env, address, address) - { - return getAccountEnv(); - } - - /// @notice Gets the helper from storage for an AccountType - /// @param env The AccountType enum to get the helper for - /// @return address The address of the helper - function getHelper(AccountType env) internal view returns (address) { - if (env == AccountType.DEFAULT) { - return getHelperFromStorage(DEFAULT); - } else if (env == AccountType.SAFE) { - return getHelperFromStorage(SAFE); - } else if (env == AccountType.KERNEL) { - return getHelperFromStorage(KERNEL); - } else if (env == AccountType.CUSTOM) { - return getHelperFromStorage(CUSTOM); - } else if (env == AccountType.NEXUS) { - return getHelperFromStorage(NEXUS); - } else { - revert InvalidAccountType(); - } - } - - /// @dev Used to deploy an account if it has not been deployed - modifier withAccountDeployed(AccountInstance memory instance) { - if (instance.account.code.length == 0) { - deployAccount(instance); - } - _; - } - - /*////////////////////////////////////////////////////////////////////////// - SIGNATURE UTILS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Checks if a signature is valid by calling the accountHelper of the account instance - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param validator The address of the validator - /// @param hash The hash to validate - /// @param signature The signature to validate - /// @return bool True if the signature is valid, false otherwise - function isValidSignature( - AccountInstance memory instance, - address validator, - bytes32 hash, - bytes memory signature - ) - internal - returns (bool) - { - return HelperBase(instance.accountHelper).isValidSignature( - instance, validator, hash, signature - ); - } - - /// @notice Formats a hash for ERC-1271 validation by calling the accountHelper of the account - /// instance - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param validator The address of the validator - /// @param hash The hash to format - /// @return bytes32 The formatted hash - function formatERC1271Hash( - AccountInstance memory instance, - address validator, - bytes32 hash - ) - internal - returns (bytes32) - { - return HelperBase(instance.accountHelper).formatERC1271Hash(instance, validator, hash); - } - - /// @notice Formats a signature for ERC-1271 validation by calling the accountHelper of the - /// account instance - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param validator The address of the validator - /// @param signature The signature to format - /// @return bytes The formatted signature - function formatERC1271Signature( - AccountInstance memory instance, - address validator, - bytes memory signature - ) - internal - returns (bytes memory) - { - return HelperBase(instance.accountHelper).formatERC1271Signature( - instance, validator, signature - ); - } - - /// @notice Adds a default signature to a UserOpData struct - /// @param userOpData UserOpData struct with the default signature added - function signDefault(UserOpData memory userOpData) internal pure returns (UserOpData memory) { - userOpData.userOp.signature = "DEFAULT SIGNATURE"; - return userOpData; - } - - /// @notice Signs a hash with a default signature - /// @param hash The hash to sign - /// @return bytes The signature - function ecdsaSignDefault(bytes32 hash) internal pure returns (bytes memory) { - (uint8 v, bytes32 r, bytes32 s) = (27, hash, hash); - return abi.encodePacked(r, s, v); - } - - /*////////////////////////////////////////////////////////////// - SMART SESSIONS - //////////////////////////////////////////////////////////////*/ - - /// @dev Makes sure the smart sessions module is installed - modifier withSmartSessionsInstalled(AccountInstance memory instance) { - if (!instance.isModuleInstalled(1, address(instance.smartSession))) { - revert SmartSessionNotInstalled(); - } - _; - } - - /// @notice Adds a session to the account with the default validator - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param session The session to add - function addSession( - AccountInstance memory instance, - Session memory session - ) - internal - withAccountDeployed(instance) - returns (PermissionId permissionIds) - { - // Check if smart sessions module is already installed - if (!instance.isModuleInstalled(1, address(instance.smartSession))) { - // Install smart sessions module - instance.installModule(1, address(instance.smartSession), ""); - } - // Enable session - Session[] memory sessions = new Session[](1); - sessions[0] = session; - prank(instance.account); - permissionIds = instance.smartSession.enableSessions(sessions)[0]; - } - - /// @notice Adds a session to the account with the default validator - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param salt The salt to use for the session - /// @param userOpPolicies The user operation policies to use for the session - /// @param erc7739Policy The ERC-7739 policy to use for the session - /// @param actionDatas The action datas to use for the session - /// @return permissionIds The permission id of the Session - function addSession( - AccountInstance memory instance, - bytes32 salt, - PolicyData[] memory userOpPolicies, - ERC7739Data memory erc7739Policy, - ActionData[] memory actionDatas - ) - internal - withAccountDeployed(instance) - returns (PermissionId permissionIds) - { - // Check if smart sessions module is already installed - if (!instance.isModuleInstalled(1, address(instance.smartSession))) { - // Install smart sessions module - instance.installModule(1, address(instance.smartSession), ""); - } - // Setup session data - Session memory session = Session( - ISessionValidator(address(instance.defaultSessionValidator)), - "mockInitData", - salt, - userOpPolicies, - erc7739Policy, - actionDatas - ); - // Enable session - return instance.addSession(session); - } - - /// @notice Removes a session from the account - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param permissionId The permission id of the session to remove - function removeSession( - AccountInstance memory instance, - PermissionId permissionId - ) - internal - withAccountDeployed(instance) - withSmartSessionsInstalled(instance) - { - // Remove session - prank(instance.account); - instance.smartSession.removeSession(permissionId); - } - - /// @notice Checks if a permission is enabled - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param permissionId The permission id to check - /// @return bool True if the permission is enabled, false otherwise - function isPermissionEnabled( - AccountInstance memory instance, - PermissionId permissionId - ) - internal - withAccountDeployed(instance) - withSmartSessionsInstalled(instance) - returns (bool) - { - // Check if session is enabled - return instance.smartSession.isPermissionEnabled(permissionId, instance.account); - } - - /// @notice Gets the permission id of a session - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param session The session to get the permission id of - /// @return permissionId The permission id of the session - function getPermissionId( - AccountInstance memory instance, - Session memory session - ) - internal - withSmartSessionsInstalled(instance) - returns (PermissionId permissionId) - { - // Check if smart sessions module is installed - if (!instance.isModuleInstalled(1, address(instance.smartSession))) { - revert SmartSessionNotInstalled(); - } - return instance.smartSession.getPermissionId(session); - } - - /// @notice Gets the session digest - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param session The session to get the digest of - /// @param mode The SmartSessionMode to use - /// @return bytes32 The session digest - function getSessionDigest( - AccountInstance memory instance, - Session memory session, - SmartSessionMode mode - ) - internal - withSmartSessionsInstalled(instance) - returns (bytes32) - { - return instance.smartSession.getSessionDigest( - getPermissionId(instance, session), instance.account, session, mode - ); - } - - /// @notice Gets the session nonce - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param permissionId The permission id of the session to get the nonce of - /// @return uint256 The session nonce - function getSessionNonce( - AccountInstance memory instance, - PermissionId permissionId - ) - internal - withSmartSessionsInstalled(instance) - returns (uint256) - { - return instance.smartSession.getNonce(permissionId, instance.account); - } - - /// @notice Encodes a signature for a user operation using the correct format - /// @param instance AccountInstance struct - /// @param userOperation The user operation to encode the signature for - /// @param mode The SmartSessionMode to use - /// @param session The session to use - /// @return bytes The encoded signature - function encodeSignature( - AccountInstance memory instance, - PackedUserOperation memory userOperation, - SmartSessionMode mode, - Session memory session - ) - internal - returns (bytes memory) - { - // Get permission id - PermissionId permissionId = getPermissionId(instance, session); - // Encode based on mode - if (mode == SmartSessionMode.USE) { - return EncodeLib.encodeUse(permissionId, userOperation.signature); - } else { - revert("Missing signFunction and validator params"); - } - } - - /// @notice Encodes the signature for a user operation using the correct format and passed - /// signing function and validator - /// @param instance AccountInstance struct - /// @param userOperation The user operation to encode the signature for - /// @param mode The SmartSessionMode to use - /// @param session The session to use - /// @param signFunction The signing function to use - /// @param validator The validator to use - /// @return bytes The encoded signature - function encodeSignature( - AccountInstance memory instance, - PackedUserOperation memory userOperation, - SmartSessionMode mode, - Session memory session, - function (bytes32) internal returns (bytes memory) signFunction, - address validator - ) - internal - returns (bytes memory) - { - // Get permission id - PermissionId permissionId = getPermissionId(instance, session); - // Encode based on mode - if (mode == SmartSessionMode.USE) { - return EncodeLib.encodeUse(permissionId, userOperation.signature); - } else { - // Create enable session data - EnableSession memory enableData = makeMultiChainEnableData(instance, session, mode); - // Get the hash - bytes32 hash = HashLib.multichainDigest(enableData.hashesAndChainIds); - // Sign the enable hash - enableData.permissionEnableSig = abi.encodePacked(validator, signFunction(hash)); - // Encode based on mode - if (mode == SmartSessionMode.UNSAFE_ENABLE) { - return EncodeLib.encodeUnsafeEnable(userOperation.signature, enableData); - } else { - return EncodeLib.encodeEnable(userOperation.signature, enableData); - } - } - } - - /// @notice Encodes the signature for a user operation using the USE mode - /// @param instance AccountInstance struct - /// @param userOperation The user operation to encode the signature for - /// @param session The session to use - /// @return bytes The encoded signature - function encodeSignatureUseMode( - AccountInstance memory instance, - PackedUserOperation memory userOperation, - Session memory session - ) - internal - returns (bytes memory) - { - return instance.encodeSignature( - userOperation, - SmartSessionMode.USE, - session, - ecdsaSignDefault, // Irrelevant in use mode - address(0) // Irrelevant in use mode - ); - } - - /// @notice Encodes the signature for a user operation using the ENABLE mode - /// @param instance AccountInstance struct - /// @param userOperation The user operation to encode the signature for - /// @param session The session to use - /// @param signFunction The signing function to use - /// @param validator The validator to use - /// @return bytes The encoded signature - function encodeSignatureEnableMode( - AccountInstance memory instance, - PackedUserOperation memory userOperation, - Session memory session, - function (bytes32) internal returns (bytes memory) signFunction, - address validator - ) - internal - returns (bytes memory) - { - return instance.encodeSignature( - userOperation, SmartSessionMode.ENABLE, session, signFunction, validator - ); - } - - /// @notice Encodes the signature for a user operation using the UNSAFE_ENABLE mode - /// @param instance AccountInstance struct - /// @param userOperation The user operation to encode the signature for - /// @param session The session to use - /// @param signFunction The signing function to use - /// @param validator The validator to use - /// @return bytes The encoded signature - function encodeSignatureUnsafeEnableMode( - AccountInstance memory instance, - PackedUserOperation memory userOperation, - Session memory session, - function (bytes32) internal returns (bytes memory) signFunction, - address validator - ) - internal - returns (bytes memory) - { - return instance.encodeSignature( - userOperation, SmartSessionMode.UNSAFE_ENABLE, session, signFunction, validator - ); - } - - /// @notice Checks if a session is enabled - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param session The session to check - /// @return bool True if the session is enabled, false otherwise - function isSessionEnabled( - AccountInstance memory instance, - Session memory session - ) - internal - withSmartSessionsInstalled(instance) - returns (bool) - { - // Get permission id - PermissionId permissionId = getPermissionId(instance, session); - return instance.smartSession.isISessionValidatorSet(permissionId, instance.account) - && instance.smartSession.areUserOpPoliciesEnabled( - instance.account, permissionId, session.userOpPolicies - ) - && instance.smartSession.areActionsEnabled(instance.account, permissionId, session.actions) - && instance.smartSession.areERC1271PoliciesEnabled( - instance.account, permissionId, session.erc7739Policies.erc1271Policies - ); - } - - /// @dev Kernel requires us to temporarily disable the hook multiplexer to use smart sessions - modifier withHookFixForKernel(AccountInstance memory instance) { - // Check if account is KERNEL - if (instance.accountType == AccountType.KERNEL) { - // Cache hook multiplexer - address hookMultiplexer = - KernelHelpers(instance.accountHelper).getHookMultiPlexer(instance); - // Uninstall MockHookMultiplexer - instance.uninstallModule(MODULE_TYPE_HOOK, hookMultiplexer, ""); - // Set hook multiplexer to address(1) - KernelHelpers(instance.accountHelper).setHookMultiPlexer(instance, address(1)); - _; - // Set hook multiplexer back to MockHookMultiplexer - KernelHelpers(instance.accountHelper).setHookMultiPlexer(instance, hookMultiplexer); - // Reinstall MockHookMultiplexer - instance.installModule(MODULE_TYPE_HOOK, hookMultiplexer, ""); - } else { - _; - } - } - - /// @notice Uses a session to execute a user operation - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param session The session to use - /// @param target The target address of the user operation - /// @param value The value of the user operation - /// @param callData The call data of the user operation - function useSession( - AccountInstance memory instance, - Session memory session, - address target, - uint256 value, - bytes memory callData - ) - internal - withHookFixForKernel(instance) - { - // Check if smart sessions module is already installed - if (!instance.isModuleInstalled(1, address(instance.smartSession))) { - // Install smart sessions module - instance.installModule(1, address(instance.smartSession), ""); - } - - // Get user ops - UserOpData memory userOpData = - instance.getExecOps(target, value, callData, address(instance.smartSession)); - - // Get permission id - PermissionId permissionId = getPermissionId(instance, session); - - // Check if session is enabled and enable if not - if (!isSessionEnabled(instance, session)) { - prank(instance.account); - Session[] memory sessions = new Session[](1); - sessions[0] = session; - instance.smartSession.enableSessions(sessions); - } - - // Sign user op - userOpData.userOp.signature = EncodeLib.encodeUse(permissionId, userOpData.userOp.signature); - - // Execute user op - userOpData.execUserOps(); - } - - /// @notice Uses a session to execute a batch of user operations - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param session The session to use - /// @param executions The executions to execute - function useSession( - AccountInstance memory instance, - Session memory session, - Execution[] memory executions - ) - internal - withHookFixForKernel(instance) - { - // Check if smart sessions module is already installed - if (!instance.isModuleInstalled(1, address(instance.smartSession))) { - // Install smart sessions module - instance.installModule(1, address(instance.smartSession), ""); - } - - // Get user ops for multiple executions - UserOpData memory userOpData = - instance.getExecOps(executions, address(instance.smartSession)); - - // Get permission id - PermissionId permissionId = getPermissionId(instance, session); - - // Check if session is enabled and enable if not - if (!isSessionEnabled(instance, session)) { - prank(instance.account); - Session[] memory sessions = new Session[](1); - sessions[0] = session; - instance.smartSession.enableSessions(sessions); - } - - // Sign user op - userOpData.userOp.signature = EncodeLib.encodeUse(permissionId, userOpData.userOp.signature); - - // Execute user op - userOpData.execUserOps(); - } - - /// @notice Creates multi-chain enable data for a session - /// @param instance AccountInstance struct containing the account and accountHelper - /// @param session The session to enable - /// @param mode The SmartSessionMode to use - /// @return enableData The enable session data - function makeMultiChainEnableData( - AccountInstance memory instance, - Session memory session, - SmartSessionMode mode - ) - internal - returns (EnableSession memory enableData) - { - PermissionId permissionId = instance.getPermissionId(session); - bytes32 sessionDigest = instance.smartSession.getSessionDigest({ - permissionId: permissionId, - account: instance.account, - data: session, - mode: mode - }); - - ChainDigest[] memory chainDigests = ModuleKitHelpers.encodeHashesAndChainIds( - Solarray.uint64s(181_818, uint64(block.chainid), 777), - Solarray.bytes32s(sessionDigest, sessionDigest, sessionDigest) - ); - - enableData = EnableSession({ - chainDigestIndex: 1, - hashesAndChainIds: chainDigests, - sessionToEnable: session, - permissionEnableSig: "" - }); - } - - /// @dev Encodes hashes and chain ids to a ChainDigest array - /// @param chainIds The chain ids to encode - /// @param hashes The hashes to encode - /// @return ChainDigest[] The encoded ChainDigest array - function encodeHashesAndChainIds( - uint64[] memory chainIds, - bytes32[] memory hashes - ) - internal - pure - returns (ChainDigest[] memory) - { - uint256 length = chainIds.length; - ChainDigest[] memory hashesAndChainIds = new ChainDigest[](length); - for (uint256 i; i < length; i++) { - hashesAndChainIds[i] = ChainDigest({ chainId: chainIds[i], sessionDigest: hashes[i] }); - } - return hashesAndChainIds; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/RhinestoneModuleKit.sol b/typescript/packages/account-modules/lib/modulekit/src/test/RhinestoneModuleKit.sol deleted file mode 100644 index 069e9e5..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/RhinestoneModuleKit.sol +++ /dev/null @@ -1,471 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Factories -import { SafeFactory } from "../accounts/safe/SafeFactory.sol"; -import { ERC7579Factory } from "../accounts/erc7579/ERC7579Factory.sol"; -import { KernelFactory } from "../accounts/kernel/KernelFactory.sol"; -import { NexusFactory } from "../accounts/nexus/NexusFactory.sol"; - -// Auxiliaries -import { Auxiliary, AuxiliaryFactory } from "./Auxiliary.sol"; - -// Helpers -import { HelperBase } from "./helpers/HelperBase.sol"; -import { ERC7579Helpers } from "./helpers/ERC7579Helpers.sol"; -import { SafeHelpers } from "./helpers/SafeHelpers.sol"; -import { KernelHelpers } from "./helpers/KernelHelpers.sol"; -import { NexusHelpers } from "./helpers/NexusHelpers.sol"; -import { ModuleKitHelpers } from "./ModuleKitHelpers.sol"; - -// Interfaces -import { IAccountFactory } from "../accounts/factory/interface/IAccountFactory.sol"; -import { PackedUserOperation, IStakeManager, IEntryPoint } from "../external/ERC4337.sol"; -import { ISmartSession, ISessionValidator } from "../integrations/interfaces/ISmartSession.sol"; -import { IValidator as IERC7579Validator } from "../accounts/common/interfaces/IERC7579Module.sol"; - -// Deployment -import { ENTRYPOINT_ADDR } from "../deployment/predeploy/EntryPoint.sol"; -import { SMARTSESSION_ADDR } from "../deployment/precompiles/SmartSessionsPrecompiles.sol"; - -// Mocks -import { MockValidator, MockStatelessValidator } from "../Mocks.sol"; - -// Utils -import { envOr, prank, label, deal, toString } from "../test/utils/Vm.sol"; -import { VmSafe } from "./utils/Vm.sol"; -import { - getAccountEnv, - getHelper, - getFactory, - getAccountType, - writeAccountEnv, - writeFactory, - writeHelper -} from "./utils/Storage.sol"; - -/*////////////////////////////////////////////////////////////// - CONSTANTS -//////////////////////////////////////////////////////////////*/ - -string constant DEFAULT = "DEFAULT"; -string constant SAFE = "SAFE"; -string constant KERNEL = "KERNEL"; -string constant CUSTOM = "CUSTOM"; -string constant NEXUS = "NEXUS"; - -/*////////////////////////////////////////////////////////////// - ENUMS -//////////////////////////////////////////////////////////////*/ - -/// @notice Currently supported account types -enum AccountType { - DEFAULT, - SAFE, - KERNEL, - CUSTOM, - NEXUS -} - -/*////////////////////////////////////////////////////////////// - STRUCTS -//////////////////////////////////////////////////////////////*/ - -/// @title AccountInstance -/// @notice A struct that contains all the necessary information for an account used during testing -/// @param account The address of the account -/// @param accountType The type of the account -/// @param accountHelper The address of the account helper -/// @param aux Auxiliary contracts -/// @param defaultValidator The default validator address -/// @param salt The salt used to create the account -/// @param initCode The init code used to create the account -/// @param accountFactory The address of the account factory -/// @param smartSession The address of the smart session contract -/// @param defaultSessionValidator The default session validator address -struct AccountInstance { - address account; - AccountType accountType; - address accountHelper; - Auxiliary aux; - IERC7579Validator defaultValidator; - bytes32 salt; - bytes initCode; - address accountFactory; - ISmartSession smartSession; - ISessionValidator defaultSessionValidator; -} - -/// @title UserOpData -/// @param userOp The user operation -/// @param userOpHash The hash of the user operation -/// @param entrypoint The entrypoint contract -struct UserOpData { - PackedUserOperation userOp; - bytes32 userOpHash; - IEntryPoint entrypoint; -} - -/// @title ExecutionReturnData -/// @param logs Execution logs -struct ExecutionReturnData { - VmSafe.Log[] logs; -} - -/// @title RhinestoneModuleKit -/// @notice A development kit for building and testing smart account modules -contract RhinestoneModuleKit is AuxiliaryFactory { - /*////////////////////////////////////////////////////////////// - LIBRARIES - //////////////////////////////////////////////////////////////*/ - - using ModuleKitHelpers for *; - - /*////////////////////////////////////////////////////////////// - STORAGE - //////////////////////////////////////////////////////////////*/ - - /// @notice The default validator used for testing - MockValidator public _defaultValidator; - /// @notice The default stateless validator used for testing smart sessions - MockStatelessValidator public _defaultSessionValidator; - /// @notice Whether the module kit has been initialized on a specific chain - mapping(uint256 chainId => bool initialized) public isInit; - - /*////////////////////////////////////////////////////////////// - INIT - //////////////////////////////////////////////////////////////*/ - - /// @notice Initialize the module kit with the provided environment, deploy the factories, - /// helpers, and validators, and stake them on the entrypoint - function _initializeModuleKit(string memory _env) internal { - // Init - super.init(); - isInit[block.chainid] = true; - - // Factories - writeFactory(address(new ERC7579Factory()), DEFAULT); - writeFactory(address(new SafeFactory()), SAFE); - writeFactory(address(new KernelFactory()), KERNEL); - writeFactory(address(new NexusFactory()), NEXUS); - writeFactory(address(new ERC7579Factory()), CUSTOM); - - // Helpers - writeHelper(address(new ERC7579Helpers()), DEFAULT); - writeHelper(address(new SafeHelpers()), SAFE); - writeHelper(address(new KernelHelpers()), KERNEL); - writeHelper(address(new NexusHelpers()), NEXUS); - writeHelper(address(new ERC7579Helpers()), CUSTOM); - - // Initialize factories - IAccountFactory safeFactory = IAccountFactory(getFactory(SAFE)); - IAccountFactory kernelFactory = IAccountFactory(getFactory(KERNEL)); - IAccountFactory erc7579Factory = IAccountFactory(getFactory(DEFAULT)); - IAccountFactory nexusFactory = IAccountFactory(getFactory(NEXUS)); - IAccountFactory customFactory = IAccountFactory(getFactory(CUSTOM)); - safeFactory.init(); - kernelFactory.init(); - erc7579Factory.init(); - nexusFactory.init(); - customFactory.init(); - - // Label factories - label(address(safeFactory), "SafeFactory"); - label(address(kernelFactory), "KernelFactory"); - label(address(erc7579Factory), "ERC7579Factory"); - label(address(nexusFactory), "NexusFactory"); - label(address(customFactory), "CustomFactory"); - - // Stake factory on EntryPoint - deal(address(safeFactory), 10 ether); - deal(address(kernelFactory), 10 ether); - deal(address(erc7579Factory), 10 ether); - deal(address(nexusFactory), 10 ether); - deal(address(customFactory), 10 ether); - - // Stake on EntryPoint - prank(address(safeFactory)); - IStakeManager(ENTRYPOINT_ADDR).addStake{ value: 10 ether }(100_000); - prank(address(kernelFactory)); - IStakeManager(ENTRYPOINT_ADDR).addStake{ value: 10 ether }(100_000); - prank(address(erc7579Factory)); - IStakeManager(ENTRYPOINT_ADDR).addStake{ value: 10 ether }(100_000); - prank(address(nexusFactory)); - IStakeManager(ENTRYPOINT_ADDR).addStake{ value: 10 ether }(100_000); - - // Set env - ModuleKitHelpers.setAccountEnv(_env); - - // Set factory - IAccountFactory accountFactory = IAccountFactory(getFactory(_env)); - label(address(accountFactory), "AccountFactory"); - - // Set default validator - _defaultValidator = new MockValidator(); - label(address(_defaultValidator), "DefaultValidator"); - - // Set session validator - _defaultSessionValidator = new MockStatelessValidator(); - label(address(_defaultSessionValidator), "SessionValidator"); - } - - /*////////////////////////////////////////////////////////////// - ACCOUNT INSTANCE - //////////////////////////////////////////////////////////////*/ - - /// @notice Create an account instance with the provided salt - /// @param salt The salt used to create the account - /// @return instance The account instance - function makeAccountInstance(bytes32 salt) - internal - initializeModuleKit - returns (AccountInstance memory instance) - { - (AccountType env, address accountFactoryAddress, address accountHelper) = - ModuleKitHelpers.getAccountEnv(); - IAccountFactory accountFactory = IAccountFactory(accountFactoryAddress); - bytes memory initData = accountFactory.getInitData(address(_defaultValidator), ""); - address account = accountFactory.getAddress(salt, initData); - bytes memory initCode = abi.encodePacked( - address(accountFactory), abi.encodeCall(accountFactory.createAccount, (salt, initData)) - ); - - label(address(account), toString(salt)); - deal(account, 10 ether); - instance = _makeAccountInstance({ - salt: salt, - accountType: env, - helper: accountHelper, - account: account, - initCode: initCode, - validator: address(_defaultValidator), - accountFactory: address(accountFactory), - sessionValidator: address(_defaultSessionValidator) - }); - } - - // @notice Create an account instance with the provided salt, account, and init code - // @param salt The salt used to create the account - // @param account The address of the account - // @param initCode The init code used to create the account - function makeAccountInstance( - bytes32 salt, - address account, - bytes memory initCode - ) - internal - initializeModuleKit - returns (AccountInstance memory instance) - { - address accountHelper = ModuleKitHelpers.getHelper(ModuleKitHelpers.getAccountType()); - instance = makeAccountInstance({ - salt: salt, - helper: accountHelper, - account: account, - initCode: initCode - }); - } - - /// @notice Create an account instance with the provided salt, account,executors, validators, - /// hook, and fallback arrays - /// @param salt The salt used to create the account - /// @param validators The array of ModuleInitData for validators - /// @param executors The array of ModuleInitData for executors - /// @param hook The ModuleInitData for the hook - /// @param fallbacks The array of ModuleInitData for fallbacks - /// @return instance The account instance - function makeAccountInstance( - bytes32 salt, - IAccountFactory.ModuleInitData[] memory validators, - IAccountFactory.ModuleInitData[] memory executors, - IAccountFactory.ModuleInitData memory hook, - IAccountFactory.ModuleInitData[] memory fallbacks - ) - internal - initializeModuleKit - returns (AccountInstance memory instance) - { - (, address accountFactoryAddress, address accountHelper) = ModuleKitHelpers.getAccountEnv(); - IAccountFactory accountFactory = IAccountFactory(accountFactoryAddress); - bytes memory initData = accountFactory.getInitData(validators, executors, hook, fallbacks); - address account = accountFactory.getAddress(salt, initData); - bytes memory initCode = abi.encodePacked( - address(accountFactory), abi.encodeCall(accountFactory.createAccount, (salt, initData)) - ); - label(address(account), toString(salt)); - deal(account, 10 ether); - instance = makeAccountInstance({ - salt: salt, - helper: accountHelper, - account: account, - initCode: initCode, - defaultValidator: address(validators[0].module), - defaultSessionValidator: address(executors[0].module) - }); - } - - /// @notice Create an account instance with the provided salt, account, init code, and helper. - /// Funds the account with 10 ether. - /// @param salt The salt used to create the account - /// @param account The address of the account - /// @param initCode The init code used to create the account - /// @param helper The address of the account helper - /// @return instance The account instance - function makeAccountInstance( - bytes32 salt, - address account, - bytes memory initCode, - address helper - ) - internal - initializeModuleKit - returns (AccountInstance memory instance) - { - label(address(account), toString(salt)); - deal(account, 10 ether); - - address _factory; - assembly { - _factory := mload(add(initCode, 20)) - } - - AccountType env = ModuleKitHelpers.getAccountType(); - - instance = _makeAccountInstance({ - salt: salt, - accountType: env, - helper: helper, - account: account, - initCode: initCode, - validator: address(_defaultValidator), - accountFactory: _factory, - sessionValidator: address(_defaultSessionValidator) - }); - - ModuleKitHelpers.setAccountType(AccountType.CUSTOM); - } - - /// @notice Create an account instance with the provided salt, account, init code, helper, - /// default validator, - /// and default session validator. Funds the account with 10 ether. - /// @param salt The salt used to create the account - /// @param account The address of the account - /// @param initCode The init code used to create the account - /// @param helper The address of the account helper - /// @param defaultValidator The address of the default validator - /// @param defaultSessionValidator The address of the default session validator - /// @return instance The account instance - function makeAccountInstance( - bytes32 salt, - address account, - bytes memory initCode, - address helper, - address defaultValidator, - address defaultSessionValidator - ) - internal - initializeModuleKit - returns (AccountInstance memory instance) - { - label(address(account), toString(salt)); - deal(account, 10 ether); - - address _factory; - assembly { - _factory := mload(add(initCode, 20)) - } - - AccountType env = instance.getAccountType(); - - instance = _makeAccountInstance({ - salt: salt, - accountType: env, - helper: helper, - account: account, - initCode: initCode, - validator: defaultValidator, - accountFactory: _factory, - sessionValidator: defaultSessionValidator - }); - ModuleKitHelpers.setAccountType(AccountType.CUSTOM); - } - - /// @notice Create an account instance with the provided salt, account, init code, account - /// factory, validator, session validator, account type, and helper - /// @param salt The salt used to create the account - /// @param account The address of the account - /// @param initCode The init code used to create the account - /// @param accountFactory The address of the account factory - /// @param validator The address of the validator - /// @param sessionValidator The address of the session validator - /// @param accountType The type of the account - /// @param helper The address of the account helper - /// @return instance The account instance - function _makeAccountInstance( - bytes32 salt, - address account, - bytes memory initCode, - address accountFactory, - address validator, - address sessionValidator, - AccountType accountType, - address helper - ) - internal - view - returns (AccountInstance memory instance) - { - instance = AccountInstance({ - accountType: accountType, - accountHelper: helper, - account: account, - aux: auxiliary, - salt: salt, - defaultValidator: IERC7579Validator(validator), - initCode: initCode, - accountFactory: accountFactory, - smartSession: ISmartSession(SMARTSESSION_ADDR), - defaultSessionValidator: ISessionValidator(sessionValidator) - }); - } - - /*////////////////////////////////////////////////////////////// - MODIFIERS - //////////////////////////////////////////////////////////////*/ - - /// @dev Initialize the module kit with the provided environment if it has not been initialized - modifier initializeModuleKit() { - if (!isInit[block.chainid]) { - string memory _env = envOr("ACCOUNT_TYPE", DEFAULT); - _initializeModuleKit(_env); - } - _; - } - - /// @dev Set the account type for a function, and restore the previous account type - /// after the function call. Useful for testing different account types in the same test - /// @param env The account type to set - modifier usingAccountEnv(AccountType env) { - // If the module kit is not initialized, initialize it - if (!isInit[block.chainid]) { - _initializeModuleKit(env.toString()); - } else { - // Cache the current env to restore it after the function call - (AccountType _oldEnv, address _oldAccountFactory, address _oldAccountHelper) = - ModuleKitHelpers.getAccountEnv(); - // Set the new env - ModuleKitHelpers.setAccountEnv(env); - _; - // Restore the old env - ModuleKitHelpers.setAccountEnv(_oldEnv); - } - } - - /// @notice Verify that the storage of a module was cleared after a function call - modifier withModuleStorageClearValidation(AccountInstance memory instance, address module) { - instance.startStateDiffRecording(); - _; - VmSafe.AccountAccess[] memory accountAccess = instance.stopAndReturnStateDiff(); - instance.verifyModuleStorageWasCleared(accountAccess, module); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/ERC7579Helpers.sol b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/ERC7579Helpers.sol deleted file mode 100644 index 17ef9b1..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/ERC7579Helpers.sol +++ /dev/null @@ -1,164 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { AccountInstance } from "../RhinestoneModuleKit.sol"; -import { CallType } from "../../accounts/common/lib/ModeLib.sol"; - -// Dependencies -import { HelperBase } from "./HelperBase.sol"; - -// Interfaces -import { IAccountModulesPaginated } from "./interfaces/IAccountModulesPaginated.sol"; -import { IERC1271, EIP1271_MAGIC_VALUE } from "../../Interfaces.sol"; - -/// @notice Helper functions for ERC7579 reference implementation based Accounts -contract ERC7579Helpers is HelperBase { - /*////////////////////////////////////////////////////////////////////////// - MODULE CONFIG - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice get callData to uninstall a validator on an ERC7579 Account - /// @param instance AccountInstance the account instance to uninstall the validator from - /// @param module address the address of the module to uninstall - /// @param initData bytes the data to pass to the module - function getUninstallValidatorData( - AccountInstance memory instance, - address module, - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory data) - { - // get previous validator in sentinel list - address previous; - - (address[] memory array,) = - IAccountModulesPaginated(instance.account).getValidatorsPaginated(address(0x1), 100); - - if (array.length == 1) { - previous = address(0x1); - } else if (array[0] == module) { - previous = address(0x1); - } else { - for (uint256 i = 1; i < array.length; i++) { - if (array[i] == module) previous = array[i - 1]; - } - } - data = abi.encode(previous, initData); - } - - /// @notice get callData to install a validator on an ERC7579 Account - /// @param instance AccountInstance the account instance to install the validator on - /// @param module address the address of the module to install - /// @param initData bytes the data to pass to the module - function getUninstallExecutorData( - AccountInstance memory instance, - address module, - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory data) - { - // get previous executor in sentinel list - address previous; - - (address[] memory array,) = - IAccountModulesPaginated(instance.account).getExecutorsPaginated(address(0x1), 100); - - if (array.length == 1) { - previous = address(0x1); - } else if (array[0] == module) { - previous = address(0x1); - } else { - for (uint256 i = 1; i < array.length; i++) { - if (array[i] == module) previous = array[i - 1]; - } - } - data = abi.encode(previous, initData); - } - - /// @notice get callData to install a fallback on an ERC7579 Account - /// @param initData bytes the data to pass to the module - function getInstallFallbackData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - pure - virtual - override - returns (bytes memory data) - { - (bytes4 selector, CallType callType, bytes memory _initData) = - abi.decode(initData, (bytes4, CallType, bytes)); - data = abi.encodePacked(selector, callType, _initData); - } - - /// @notice get callData to uninstall a fallback on an ERC7579 Account - /// @param initData bytes the data to pass to the module - function getUninstallFallbackData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - pure - virtual - override - returns (bytes memory data) - { - (bytes4 selector,, bytes memory _initData) = abi.decode(initData, (bytes4, CallType, bytes)); - data = abi.encodePacked(selector, _initData); - } - - /*////////////////////////////////////////////////////////////////////////// - SIGNATURE UTILS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Check if a signature is valid for an account, returns true if isValidSignature - /// returns EIP1271_MAGIC_VALUE - /// @param instance AccountInstance the account instance to check the signature on - /// @param validator address the address of the validator - /// @param hash bytes32 the hash to check the signature against - /// @param signature bytes the signature to check - function isValidSignature( - AccountInstance memory instance, - address validator, - bytes32 hash, - bytes memory signature - ) - public - virtual - override - deployAccountForAction(instance) - returns (bool isValid) - { - isValid = IERC1271(instance.account).isValidSignature( - hash, abi.encodePacked(validator, signature) - ) == EIP1271_MAGIC_VALUE; - } - - /// @notice Format a ERC1271 signature for an account - /// @param validator address the address of the validator - /// @param signature bytes the signature to format - function formatERC1271Signature( - AccountInstance memory, // instance - address validator, - bytes memory signature - ) - public - virtual - override - returns (bytes memory) - { - return abi.encodePacked(validator, signature); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/HelperBase.sol b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/HelperBase.sol deleted file mode 100644 index 6e7bcfd..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/HelperBase.sol +++ /dev/null @@ -1,661 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Interfaces -import { IERC7579Account } from "../../accounts/common/interfaces/IERC7579Account.sol"; -import { - IModule as IERC7579Module, - MODULE_TYPE_VALIDATOR, - MODULE_TYPE_EXECUTOR, - MODULE_TYPE_HOOK, - MODULE_TYPE_FALLBACK, - MODULE_TYPE_PREVALIDATION_HOOK_ERC1271, - MODULE_TYPE_PREVALIDATION_HOOK_ERC4337 -} from "../../accounts/common/interfaces/IERC7579Module.sol"; -import { IERC1271, EIP1271_MAGIC_VALUE } from "../../Interfaces.sol"; - -// Libraries -import { - ModeLib, - ModeCode, - CALLTYPE_SINGLE, - CALLTYPE_BATCH, - MODE_DEFAULT, - EXECTYPE_DEFAULT, - CALLTYPE_BATCH, - ModePayload -} from "../../accounts/common/lib/ModeLib.sol"; - -// Types -import { PackedUserOperation } from "../../external/ERC4337.sol"; -import { AccountInstance } from "../RhinestoneModuleKit.sol"; -import { Execution } from "../../accounts/erc7579/lib/ExecutionLib.sol"; - -// Utils -import "../utils/Vm.sol"; - -/// @dev Base helper that includes common functions for different ERC7579 Account implementations -abstract contract HelperBase { - /*////////////////////////////////////////////////////////////////////////// - EXECUTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Gets userOp and userOpHash for an executing calldata on an account instance - /// @param instance AccountInstance the account instance to execute the userop for - /// @param callData bytes the calldata to execute - /// @param txValidator address the address of the validator - /// @return userOp PackedUserOperation the packed user operation - /// @return userOpHash bytes32 the hash of the user operation - function execUserOp( - AccountInstance memory instance, - bytes memory callData, - address txValidator - ) - public - virtual - returns (PackedUserOperation memory userOp, bytes32 userOpHash) - { - bytes memory initCode; - bool notDeployedYet = instance.account.code.length == 0; - if (notDeployedYet) { - initCode = instance.initCode; - } - - userOp = PackedUserOperation({ - sender: instance.account, - nonce: getNonce(instance, callData, txValidator), - initCode: initCode, - callData: callData, - accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), - preVerificationGas: 2e6, - gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), - paymasterAndData: bytes(""), - signature: bytes("") - }); - - userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); - } - - /*////////////////////////////////////////////////////////////////////////// - MODULE CONFIG - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Configures a userop for an account instance to install or uninstall a module - /// @param instance AccountInstance the account instance to configure the userop for - /// @param moduleType uint256 the type of the module - /// @param module address the address of the module - /// @param initData bytes the data to pass to the module - /// @param isInstall bool whether to install or uninstall the module - /// @param txValidator address the address of the validator - /// @return userOp PackedUserOperation the packed user operation - /// @return userOpHash bytes32 the hash of the user operation - function configModuleUserOp( - AccountInstance memory instance, - uint256 moduleType, - address module, - bytes memory initData, - bool isInstall, - address txValidator - ) - public - virtual - returns (PackedUserOperation memory userOp, bytes32 userOpHash) - { - bytes memory initCode; - if (instance.account.code.length == 0) { - initCode = instance.initCode; - } - bytes memory callData; - if (isInstall) { - initData = getInstallModuleData(instance, moduleType, module, initData); - callData = getInstallModuleCallData(instance, moduleType, module, initData); - } else { - initData = getUninstallModuleData(instance, moduleType, module, initData); - callData = getUninstallModuleCallData(instance, moduleType, module, initData); - } - - userOp = PackedUserOperation({ - sender: instance.account, - nonce: getNonce(instance, callData, txValidator), - initCode: initCode, - callData: callData, - accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), - preVerificationGas: 2e6, - gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), - paymasterAndData: bytes(""), - signature: bytes("") - }); - - userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); - } - - /// @notice get callData to install a module on an ERC7579 Account - /// @param moduleType uint256 the type of the module - /// @param module address the address of the module to install - /// @param initData bytes the data to pass to the module - /// @return callData bytes the callData to install the module - function getInstallModuleCallData( - AccountInstance memory, // instance - uint256 moduleType, - address module, - bytes memory initData - ) - public - view - virtual - returns (bytes memory callData) - { - callData = abi.encodeCall(IERC7579Account.installModule, (moduleType, module, initData)); - } - - /// @notice get callData to uninstall a module on an ERC7579 Account - /// @param moduleType uint256 the type of the module - /// @param module address the address of the module to uninstall - /// @param initData bytes the data to pass to the module - /// @return callData bytes the callData to uninstall the module - function getUninstallModuleCallData( - AccountInstance memory, // instance - uint256 moduleType, - address module, - bytes memory initData - ) - public - view - virtual - returns (bytes memory callData) - { - callData = abi.encodeCall(IERC7579Account.uninstallModule, (moduleType, module, initData)); - } - - /// @notice get callData to install a validator on an ERC7579 Account - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to install the validator - function getInstallValidatorData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - returns (bytes memory data) - { - data = initData; - } - - /// @notice get callData to uninstall a validator on an ERC7579 Account - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to uninstall the validator - function getUninstallValidatorData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - returns (bytes memory data) - { - data = initData; - } - - /// @notice get callData to install executor on an ERC7579 Account - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to install the executor - function getInstallExecutorData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - returns (bytes memory data) - { - data = initData; - } - - /// @notice get callData to uninstall executor on an ERC7579 Account - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to uninstall the executor - function getUninstallExecutorData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - returns (bytes memory data) - { - data = initData; - } - - /// @notice get callData to install hook on an ERC7579 Account - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to install the hook - function getInstallHookData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - returns (bytes memory data) - { - data = initData; - } - - /// @notice get callData to uninstall hook on an ERC7579 Account - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to uninstall the hook - function getUninstallHookData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - pure - virtual - returns (bytes memory data) - { - data = initData; - } - - /// @notice get callData to install fallback on an ERC7579 Account - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to install the fallback - function getInstallFallbackData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - returns (bytes memory data) - { - data = initData; - } - - /// @notice get callData to uninstall fallback on an ERC7579 Account - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to uninstall the fallback - function getUninstallFallbackData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - pure - virtual - returns (bytes memory data) - { - data = initData; - } - - /// @notice get callData to install an ERC1271 prevalidation hook - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to install the prevalidation hook ERC1271 - function getInstallPrevalidationHookERC1271Data( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - returns (bytes memory data) - { - data = initData; - } - - /// @notice get callData to install an ERC4337 prevalidation hook ERC4337 - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to install the prevalidation hook ERC4337 - function getInstallPrevalidationHookERC4337Data( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - returns (bytes memory data) - { - data = initData; - } - - /// @notice get callData to uninstall an ERC1271 prevalidation hook - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to uninstall the prevalidation hook ERC1271 - function getUninstallPrevalidationHookERC1271Data( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - returns (bytes memory data) - { - data = initData; - } - - /// @notice get callData to uninstall an ERC4337 prevalidation hook - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to uninstall the prevalidation hook ERC4337 - function getUninstallPrevalidationHookERC4337Data( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - returns (bytes memory data) - { - data = initData; - } - - /*////////////////////////////////////////////////////////////////////////// - MODULE UTILS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Checks if a module is installed on an ERC7579 Account - /// @param instance AccountInstance the account instance to check the module on - /// @param moduleTypeId uint256 the type of the module - /// @param module address the address of the module to check - /// @return bool whether the module is installed - function isModuleInstalled( - AccountInstance memory instance, - uint256 moduleTypeId, - address module - ) - public - virtual - deployAccountForAction(instance) - returns (bool) - { - return isModuleInstalled(instance, moduleTypeId, module, ""); - } - - /// @notice Checks if a module is installed on an ERC7579 Account - /// @param instance AccountInstance the account instance to check the module on - /// @param moduleTypeId uint256 the type of the module - /// @param module address the address of the module to check - /// @param additionalContext bytes additional context to pass to the module - /// @return bool whether the module is installed - function isModuleInstalled( - AccountInstance memory instance, - uint256 moduleTypeId, - address module, - bytes memory additionalContext - ) - public - virtual - deployAccountForAction(instance) - returns (bool) - { - return IERC7579Account(instance.account).isModuleInstalled( - moduleTypeId, module, additionalContext - ); - } - - /// @notice Gets the data to install a module on an ERC7579 Account, based on the module type - /// @param instance AccountInstance the account instance to install the module on - /// @param moduleType uint256 the type of the module - /// @param module address the address of the module to install - /// @param initData bytes the data to pass to the module - /// @return data bytes the data to install the module - function getInstallModuleData( - AccountInstance memory instance, - uint256 moduleType, - address module, - bytes memory initData - ) - public - view - virtual - returns (bytes memory) - { - if (moduleType == MODULE_TYPE_VALIDATOR) { - return getInstallValidatorData(instance, module, initData); - } else if (moduleType == MODULE_TYPE_EXECUTOR) { - return getInstallExecutorData(instance, module, initData); - } else if (moduleType == MODULE_TYPE_HOOK) { - return getInstallHookData(instance, module, initData); - } else if (moduleType == MODULE_TYPE_FALLBACK) { - return getInstallFallbackData(instance, module, initData); - } else if (moduleType == MODULE_TYPE_PREVALIDATION_HOOK_ERC1271) { - return getInstallPrevalidationHookERC1271Data(instance, module, initData); - } else if (moduleType == MODULE_TYPE_PREVALIDATION_HOOK_ERC4337) { - return getInstallPrevalidationHookERC4337Data(instance, module, initData); - } else { - revert("Invalid module type"); - } - } - - /// @notice Gets the data to uninstall a module on an ERC7579 Account, based on the module type - /// @param instance AccountInstance the account instance to uninstall the module from - /// @param moduleType uint256 the type of the module - /// @param module address the address of the module to uninstall - /// @param initData bytes the data to pass to the module - /// @return data bytes the data to uninstall the module - function getUninstallModuleData( - AccountInstance memory instance, - uint256 moduleType, - address module, - bytes memory initData - ) - public - view - virtual - returns (bytes memory) - { - if (moduleType == MODULE_TYPE_VALIDATOR) { - return getUninstallValidatorData(instance, module, initData); - } else if (moduleType == MODULE_TYPE_EXECUTOR) { - return getUninstallExecutorData(instance, module, initData); - } else if (moduleType == MODULE_TYPE_HOOK) { - return getUninstallHookData(instance, module, initData); - } else if (moduleType == MODULE_TYPE_FALLBACK) { - return getUninstallFallbackData(instance, module, initData); - } else if (moduleType == MODULE_TYPE_PREVALIDATION_HOOK_ERC1271) { - return getUninstallPrevalidationHookERC1271Data(instance, module, initData); - } else if (moduleType == MODULE_TYPE_PREVALIDATION_HOOK_ERC4337) { - return getUninstallPrevalidationHookERC4337Data(instance, module, initData); - } else { - revert("Invalid module type"); - } - } - - /*////////////////////////////////////////////////////////////////////////// - SIGNATURE UTILS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Checks if a signature is valid for an account instance - /// @param instance AccountInstance the account instance to check the signature on - /// @param hash bytes32 the hash to check the signature against - /// @param signature bytes the signature to check - /// @return isValid bool whether the signature is valid, returns true if isValidSignature - /// returns EIP1271_MAGIC_VALUE - function isValidSignature( - AccountInstance memory instance, - address, // validator - bytes32 hash, - bytes memory signature - ) - public - virtual - deployAccountForAction(instance) - returns (bool isValid) - { - isValid = - IERC1271(instance.account).isValidSignature(hash, signature) == EIP1271_MAGIC_VALUE; - } - - /// @notice Formats a hash for an ERC1271 signature - /// @param hash bytes32 the hash to format - /// @return bytes32 the formatted hash - function formatERC1271Hash( - AccountInstance memory, // instance - address, //validator - bytes32 hash - ) - public - virtual - returns (bytes32) - { - return hash; - } - - /// @notice Formats a signature for an ERC1271 signature - /// @param signature bytes the signature to format - /// @return bytes the formatted signature - function formatERC1271Signature( - AccountInstance memory, // instance - address, // validator - bytes memory signature - ) - public - virtual - returns (bytes memory) - { - return signature; - } - - /*////////////////////////////////////////////////////////////////////////// - ACCOUNT UTILS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Deploys an account instance, if it has not been deployed yet - /// reverts if no initCode is provided - /// @param instance AccountInstance the account instance to deploy - function deployAccount(AccountInstance memory instance) public virtual { - if (instance.account.code.length == 0) { - if (instance.initCode.length == 0) { - revert("deployAccount: no initCode provided"); - } else { - bytes memory initCode = instance.initCode; - assembly { - let factory := mload(add(initCode, 20)) - let success := call(gas(), factory, 0, add(initCode, 52), mload(initCode), 0, 0) - if iszero(success) { revert(0, 0) } - } - } - } - } - - /// @notice Deploys an account instance, if it has not been deployed yet, and reverts to the - /// snapshot after the action - modifier deployAccountForAction(AccountInstance memory instance) { - bool isAccountDeployed = instance.account.code.length != 0; - uint256 snapShotId; - if (!isAccountDeployed) { - snapShotId = snapshot(); - deployAccount(instance); - } - - _; - - if (!isAccountDeployed) { - revertTo(snapShotId); - } - } - - /*////////////////////////////////////////////////////////////////////////// - UTILS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Encode a single ERC7579 Execution Transaction - /// @param target address the target - /// @param value uint256 the value - /// @param callData bytes the callData of the call - /// @return erc7579Tx bytes the encoded ERC7579 transaction - function encode( - address target, - uint256 value, - bytes memory callData - ) - public - pure - virtual - returns (bytes memory erc7579Tx) - { - ModeCode mode = ModeLib.encode({ - callType: CALLTYPE_SINGLE, - execType: EXECTYPE_DEFAULT, - mode: MODE_DEFAULT, - payload: ModePayload.wrap(bytes22(0)) - }); - bytes memory data = abi.encodePacked(target, value, callData); - return abi.encodeCall(IERC7579Account.execute, (mode, data)); - } - - /// @notice Encode a batch of ERC7579 Execution Transactions - /// @param executions Execution[] the array of executions - /// @return erc7579Tx bytes the encoded ERC7579 transaction - function encode(Execution[] memory executions) - public - pure - virtual - returns (bytes memory erc7579Tx) - { - ModeCode mode = ModeLib.encode({ - callType: CALLTYPE_BATCH, - execType: EXECTYPE_DEFAULT, - mode: MODE_DEFAULT, - payload: ModePayload.wrap(bytes22(0)) - }); - return abi.encodeCall(IERC7579Account.execute, (mode, abi.encode(executions))); - } - - /// @notice Convert arrays of targets, values, and callDatas to an array of Executions - /// @param targets address[] the array of targets - /// @param values uint256[] the array of values - /// @param callDatas bytes[] the array of callDatas - /// @return executions Execution[] the array of encoded executions - function toExecutions( - address[] memory targets, - uint256[] memory values, - bytes[] memory callDatas - ) - public - pure - virtual - returns (Execution[] memory executions) - { - executions = new Execution[](targets.length); - if (targets.length != values.length && values.length != callDatas.length) { - revert("Length Mismatch"); - } - - for (uint256 i; i < targets.length; i++) { - executions[i] = - Execution({ target: targets[i], value: values[i], callData: callDatas[i] }); - } - } - - /*////////////////////////////////////////////////////////////////////////// - NONCE - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Get the nonce for an account instance - /// @param instance AccountInstance the account instance to get the nonce for - /// @param txValidator address the address of the validator - /// @return nonce uint256 the nonce - function getNonce( - AccountInstance memory instance, - bytes memory, - address txValidator - ) - public - virtual - returns (uint256 nonce) - { - uint192 key = uint192(bytes24(bytes20(address(txValidator)))); - nonce = instance.aux.entrypoint.getNonce(address(instance.account), key); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/KernelHelpers.sol b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/KernelHelpers.sol deleted file mode 100644 index f8a7410..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/KernelHelpers.sol +++ /dev/null @@ -1,584 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { AccountInstance } from "../RhinestoneModuleKit.sol"; -import { ValidationType, ValidationMode, ValidationId } from "../../accounts/kernel/types/Types.sol"; -import { - VALIDATION_TYPE_PERMISSION, - VALIDATION_TYPE_ROOT, - VALIDATION_TYPE_VALIDATOR, - VALIDATION_MODE_DEFAULT, - VALIDATION_MODE_ENABLE, - MODULE_TYPE_EXECUTOR, - MODULE_TYPE_HOOK, - MODULE_TYPE_VALIDATOR, - KERNEL_WRAPPER_TYPE_HASH -} from "../../accounts/kernel/types/Constants.sol"; -import { CallType } from "../../accounts/common/lib/ModeLib.sol"; -import { Execution } from "../../accounts/erc7579/lib/ExecutionLib.sol"; -import { PackedUserOperation } from "../../external/ERC4337.sol"; - -// Libraries -import { ValidatorLib, ValidationConfig } from "../../accounts/kernel/lib/ValidationTypeLib.sol"; - -// Deployments -import { ENTRYPOINT_ADDR } from "../../deployment/predeploy/EntryPoint.sol"; -import { KernelPrecompiles, ISetSelector } from "../../deployment/precompiles/KernelPrecompiles.sol"; - -// Interfaces -import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/IEntryPoint.sol"; -import { IERC7579Account } from "../../accounts/kernel/interfaces/IERC7579Account.sol"; -import { IKernel } from "../../accounts/kernel/interfaces/IKernel.sol"; -import { IValidator, IModule } from "../../accounts/common/interfaces/IERC7579Module.sol"; -import { IERC1271, EIP1271_MAGIC_VALUE } from "../../Interfaces.sol"; - -// Mocks -import { MockFallback } from "../../accounts/kernel/mock/MockFallback.sol"; -import { MockHookMultiPlexer } from "../../Mocks.sol"; - -// Dependencies -import { HelperBase } from "./HelperBase.sol"; -import { TrustedForwarder } from "../../Modules.sol"; -import { KernelFactory } from "../../accounts/kernel/KernelFactory.sol"; - -// Utils -import { etch } from "../utils/Vm.sol"; - -// External Dependencies -import { EIP712 } from "solady/utils/EIP712.sol"; - -/// @notice Helper functions for the Kernel ERC7579 account implementation -contract KernelHelpers is HelperBase, KernelPrecompiles { - /*////////////////////////////////////////////////////////////////////////// - EXECUTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Gets userOp and userOpHash for an executing calldata on an account instance - /// @param instance AccountInstance the account instance to execute the userop for - /// @param callData bytes the calldata to execute - /// @param txValidator address the address of the validator - /// @return userOp PackedUserOperation the packed user operation - /// @return userOpHash bytes32 the hash of the user operation - function execUserOp( - AccountInstance memory instance, - bytes memory callData, - address txValidator - ) - public - virtual - override - returns (PackedUserOperation memory userOp, bytes32 userOpHash) - { - bytes memory initCode; - bool notDeployedYet = instance.account.code.length == 0; - if (notDeployedYet) { - initCode = instance.initCode; - } - uint256 nonce = getNonce(instance, callData, txValidator); - - address execHook = getExecHook(instance, txValidator); - if (execHook != address(0) && execHook != address(1)) { - callData = abi.encodePacked(IKernel.executeUserOp.selector, callData); - } - - userOp = PackedUserOperation({ - sender: instance.account, - nonce: nonce, - initCode: initCode, - callData: callData, - accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), - preVerificationGas: 2e6, - gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), - paymasterAndData: bytes(""), - signature: bytes("") - }); - - userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); - } - - /*////////////////////////////////////////////////////////////////////////// - NONCE - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Gets the nonce for an account instance - /// @param instance AccountInstance the account instance to get the nonce for - /// @param callData bytes the calldata to execute - /// @param txValidator address the address of the validator - function getNonce( - AccountInstance memory instance, - bytes memory callData, - address txValidator - ) - public - virtual - override - returns (uint256 nonce) - { - ValidationType vType; - if (txValidator == address(instance.defaultValidator)) { - vType = VALIDATION_TYPE_ROOT; - } else { - enableValidator(instance, callData, txValidator); - vType = VALIDATION_TYPE_VALIDATOR; - } - nonce = encodeNonce(vType, false, instance.account, txValidator); - } - - /// @notice Encodes the nonce for an account instance in the Kernel format - /// @param vType ValidationType the validation type - /// @param enable bool whether to enable the validator - /// @param account address the address of the account - /// @param validator address the address of the validator - /// @return nonce uint256 the encoded nonce - function encodeNonce( - ValidationType vType, - bool enable, - address account, - address validator - ) - public - view - returns (uint256 nonce) - { - uint192 nonceKey = 0; - if (vType == VALIDATION_TYPE_ROOT) { - nonceKey = 0; - } else if (vType == VALIDATION_TYPE_VALIDATOR) { - ValidationMode mode = VALIDATION_MODE_DEFAULT; - if (enable) { - mode = VALIDATION_MODE_ENABLE; - } - nonceKey = ValidatorLib.encodeAsNonceKey( - ValidationMode.unwrap(mode), - ValidationType.unwrap(vType), - bytes20(validator), - 0 // parallel key - ); - } else { - revert("Invalid validation type"); - } - return IEntryPoint(ENTRYPOINT_ADDR).getNonce(account, nonceKey); - } - - /*////////////////////////////////////////////////////////////////////////// - MODULE CONFIG - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Configures a userop for an account instance to install or uninstall a module - /// @param instance AccountInstance the account instance to configure the userop for - /// @param moduleType uint256 the type of the module - /// @param module address the address of the module - /// @param initData bytes the data to pass to the module - /// @param isInstall bool whether to install or uninstall the module - /// @param txValidator address the address of the validator - /// @return userOp PackedUserOperation the packed user operation - /// @return userOpHash bytes32 the hash of the user operation - function configModuleUserOp( - AccountInstance memory instance, - uint256 moduleType, - address module, - bytes memory initData, - bool isInstall, - address txValidator - ) - public - virtual - override - returns (PackedUserOperation memory userOp, bytes32 userOpHash) - { - bytes memory initCode; - if (instance.account.code.length == 0) { - initCode = instance.initCode; - } - bytes memory callData; - if (isInstall) { - initData = getInstallModuleData({ - instance: instance, - moduleType: moduleType, - module: module, - initData: initData - }); - callData = getInstallModuleCallData({ - instance: instance, - moduleType: moduleType, - module: module, - initData: initData - }); - } else { - initData = getUninstallModuleData({ - instance: instance, - moduleType: moduleType, - module: module, - initData: initData - }); - callData = getUninstallModuleCallData({ - instance: instance, - moduleType: moduleType, - module: module, - initData: initData - }); - } - - address execHook = getExecHook(instance, txValidator); - if (execHook != address(0) && execHook != address(1)) { - callData = abi.encodePacked(IKernel.executeUserOp.selector, callData); - } - - userOp = PackedUserOperation({ - sender: instance.account, - nonce: getNonce(instance, callData, txValidator), - initCode: initCode, - callData: callData, - accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), - preVerificationGas: 2e6, - gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), - paymasterAndData: bytes(""), - signature: bytes("") - }); - - userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); - } - - /// @notice Enables a validator for an account instance - /// @param instance AccountInstance the account instance to enable the validator for - /// @param callData bytes the calldata to execute - /// @param txValidator address the address of the validator - function enableValidator( - AccountInstance memory instance, - bytes memory callData, - address txValidator - ) - internal - deployAccountForAction(instance) - { - ValidationId vId = ValidatorLib.validatorToIdentifier(IValidator(txValidator)); - bytes4 selector; - assembly { - selector := mload(add(callData, 32)) - } - bool isAllowedSelector = IKernel(payable(instance.account)).isAllowedSelector(vId, selector); - if (!isAllowedSelector) { - bytes memory accountCode = instance.account.code; - address _setSelector = address(deployKernelWithSetSelector(ENTRYPOINT_ADDR)); - etch(instance.account, _setSelector.code); - ISetSelector(payable(instance.account)).setSelector(vId, selector, true); - etch(instance.account, accountCode); - } - } - - /// @notice Gets the data to install a validator on an account instance - /// @dev - /// https://github.com/zerodevapp/kernel/blob/a807c8ec354a77ebb7cdb73c5be9dd315cda0df2/../../Kernel.sol#L311-L321 - /// @param instance AccountInstance the account instance to install the validator on - /// implementation) - /// @param initData the data to pass to the validator - /// @return data the data to install the validator - function getInstallValidatorData( - AccountInstance memory instance, - address, // module - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory data) - { - data = abi.encodePacked( - getHookMultiPlexer(instance), abi.encode(initData, hex"00", bytes(hex"00000001")) - ); - } - - /// @notice Gets the data to install an executor on an account instance - /// @dev - /// https://github.com/zerodevapp/kernel/blob/a807c8ec354a77ebb7cdb73c5be9dd315cda0df2/../../Kernel.sol#L324-L334 - /// @param instance AccountInstance the account instance to install the executor on - /// @param initData the data to pass to the executor - /// @return data the data to install the executor - function getInstallExecutorData( - AccountInstance memory instance, - address, // module - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory data) - { - data = abi.encodePacked( - getHookMultiPlexer(instance), abi.encode(initData, abi.encodePacked(bytes1(0x00), "")) - ); - } - - /// @notice Gets the data to install a fallback on an account instance - /// @dev - /// https://github.com/zerodevapp/kernel/blob/a807c8ec354a77ebb7cdb73c5be9dd315cda0df2/../../Kernel.sol#L336-L345 - /// @param instance AccountInstance the account instance to install the fallback on - /// @param initData the data to pass to the fallback - /// @return data the data to install the fallback - function getInstallFallbackData( - AccountInstance memory instance, - address, // module - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory data) - { - (bytes4 selector, CallType callType, bytes memory _initData) = - abi.decode(initData, (bytes4, CallType, bytes)); - data = abi.encodePacked( - selector, - getHookMultiPlexer(instance), - abi.encode(abi.encodePacked(callType, _initData), abi.encodePacked(bytes1(0x00), "")) - ); - } - - /// @notice Gets the data to uninstall a fallback on an account instance - /// @dev - /// https://github.com/zerodevapp/kernel/blob/a807c8ec354a77ebb7cdb73c5be9dd315cda0df2/../../Kernel.sol#L402-L403 - /// @param initData the data to pass to the fallback - /// @return data the data to uninstall the fallback - function getUninstallFallbackData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - pure - virtual - override - returns (bytes memory data) - { - (bytes4 selector,, bytes memory _initData) = abi.decode(initData, (bytes4, CallType, bytes)); - data = abi.encodePacked(selector, _initData); - } - - /// @notice Gets the data to install a module on an account instance - /// @param instance AccountInstance the account instance to install the module on - /// @param moduleType uint256 the type of the module - /// @param module address the address of the module to install - /// @param initData bytes the data to pass to the module - /// @return callData the data to install the module - function getInstallModuleCallData( - AccountInstance memory instance, - uint256 moduleType, - address module, - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory callData) - { - if (moduleType == MODULE_TYPE_HOOK) { - Execution[] memory executions = new Execution[](3); - executions[0] = Execution({ - target: getHookMultiPlexer(instance), - value: 0, - callData: abi.encodeCall(MockHookMultiPlexer.addHook, (module)) - }); - executions[1] = Execution({ - target: module, - value: 0, - callData: abi.encodeCall(IModule.onInstall, (initData)) - }); - executions[2] = Execution({ - target: module, - value: 0, - callData: abi.encodeCall( - TrustedForwarder.setTrustedForwarder, (getHookMultiPlexer(instance)) - ) - }); - callData = encode({ executions: executions }); - } else { - callData = abi.encodeCall(IERC7579Account.installModule, (moduleType, module, initData)); - } - } - - /// @notice Gets the data to uninstall a module on an account instance - /// @param instance AccountInstance the account instance to uninstall the module from - /// @param moduleType uint256 the type of the module - /// @param module address the address of the module to uninstall - /// @param initData bytes the data to pass to the module - /// @return callData the data to uninstall the module - function getUninstallModuleCallData( - AccountInstance memory instance, - uint256 moduleType, - address module, - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory callData) - { - if (moduleType == MODULE_TYPE_HOOK) { - Execution[] memory executions = new Execution[](3); - executions[0] = Execution({ - target: getHookMultiPlexer(instance), - value: 0, - callData: abi.encodeCall(MockHookMultiPlexer.removeHook, (module)) - }); - executions[1] = Execution({ - target: module, - value: 0, - callData: abi.encodeCall(IModule.onUninstall, (initData)) - }); - executions[2] = Execution({ - target: module, - value: 0, - callData: abi.encodeCall(TrustedForwarder.clearTrustedForwarder, ()) - }); - callData = encode({ executions: executions }); - } else { - callData = - abi.encodeCall(IERC7579Account.uninstallModule, (moduleType, module, initData)); - } - } - - /// @notice Checks if a module is installed on an account instance - /// @param instance AccountInstance the account instance to check the module on - /// @param moduleTypeId uint256 the type of the module - /// @param module address the address of the module to check - /// @param data bytes the data to pass to the module - /// @return bool whether the module is installed - function isModuleInstalled( - AccountInstance memory instance, - uint256 moduleTypeId, - address module, - bytes memory data - ) - public - virtual - override - deployAccountForAction(instance) - returns (bool) - { - if (moduleTypeId == MODULE_TYPE_HOOK) { - return MockHookMultiPlexer(getHookMultiPlexer(instance)).isHookInstalled( - instance.account, module - ); - } - - return IERC7579Account(instance.account).isModuleInstalled(moduleTypeId, module, data); - } - - /*////////////////////////////////////////////////////////////////////////// - SIGNATURE UTILS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Checks if a signature is valid for an account instance - /// @param instance AccountInstance the account instance to check the signature on - /// @param validator address the address of the validator - /// @param hash bytes32 the hash of the data that is signed - /// @param signature bytes the signature to check - /// @return isValid bool whether the signature is valid, return true if isValidSignature return - /// EIP1271_MAGIC_VALUE - function isValidSignature( - AccountInstance memory instance, - address validator, - bytes32 hash, - bytes memory signature - ) - public - virtual - override - deployAccountForAction(instance) - returns (bool isValid) - { - isValid = IERC1271(instance.account).isValidSignature( - hash, - abi.encodePacked(ValidatorLib.validatorToIdentifier(IValidator(validator)), signature) - ) == EIP1271_MAGIC_VALUE; - } - - /// @notice Formats a ERC1271 hash for an account instance - /// @param instance AccountInstance the account instance to format the signature for - /// @param hash bytes32 the hash to format - /// @return bytes the formatted signature hash - function formatERC1271Hash( - AccountInstance memory instance, - address, // validator - bytes32 hash - ) - public - virtual - override - deployAccountForAction(instance) - returns (bytes32) - { - return IKernel(payable(instance.account))._toWrappedHash(hash); - } - - /// @notice Formats an ERC1271 signature for an account instance - /// @param validator address the address of the validator - /// @param signature bytes the signature to format - /// @return bytes the formatted signature - function formatERC1271Signature( - AccountInstance memory, // instance - address validator, - bytes memory signature - ) - public - virtual - override - returns (bytes memory) - { - return - abi.encodePacked(ValidatorLib.validatorToIdentifier(IValidator(validator)), signature); - } - - /*////////////////////////////////////////////////////////////// - HOOK MULTIPLEXER - //////////////////////////////////////////////////////////////*/ - - /// @notice Gets the hook multiplexer for an account instance - /// @param instance AccountInstance the account instance to get the hook multiplexer for - /// @return address the address of the hook multiplexer - function getHookMultiPlexer(AccountInstance memory instance) public view returns (address) { - return address(KernelFactory(instance.accountFactory).hookMultiPlexer()); - } - - /// @notice Sets the hook multiplexer for an account instance - /// @param instance AccountInstance the account instance to set the hook multiplexer for - /// @param hookMultiPlexer address the address of the hook multiplexer - function setHookMultiPlexer( - AccountInstance memory instance, - address hookMultiPlexer - ) - public - virtual - deployAccountForAction(instance) - { - KernelFactory(instance.accountFactory).setHookMultiPlexer(hookMultiPlexer); - } - - /*////////////////////////////////////////////////////////////////////////// - INTERNAL - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Gets the exec hook for an account instance - /// @param instance AccountInstance the account instance to get the exec hook for - /// @param txValidator address the address of the validator - /// @return address the address of the exec hook - function getExecHook( - AccountInstance memory instance, - address txValidator - ) - internal - deployAccountForAction(instance) - returns (address) - { - ValidationId vId = ValidatorLib.validatorToIdentifier(IValidator(txValidator)); - ValidationConfig memory validationConfig = - IKernel(payable(instance.account)).validationConfig(vId); - return address(validationConfig.hook); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/NexusHelpers.sol b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/NexusHelpers.sol deleted file mode 100644 index 4fe0f65..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/NexusHelpers.sol +++ /dev/null @@ -1,292 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { PackedUserOperation } from "../../external/ERC4337.sol"; -import { AccountInstance } from "../RhinestoneModuleKit.sol"; -import { CallType } from "../../accounts/common/lib/ModeLib.sol"; - -// Interfaces -import { IAccountModulesPaginated } from "./interfaces/IAccountModulesPaginated.sol"; -import { IERC1271, EIP1271_MAGIC_VALUE } from "../../Interfaces.sol"; - -// Dependencies -import { HelperBase } from "./HelperBase.sol"; - -/// @notice Helper functions for the Nexus ERC7579 implementation -contract NexusHelpers is HelperBase { - /*////////////////////////////////////////////////////////////////////////// - EXECUTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Gets userOp and userOpHash for an executing calldata on an account instance - /// @param instance AccountInstance the account instance to execute the callData on - /// @param callData bytes the calldata to execute - /// @param txValidator address the address of the validator - /// @return userOp PackedUserOperation the user operation - /// @return userOpHash bytes32 the hash of the user operation - function execUserOp( - AccountInstance memory instance, - bytes memory callData, - address txValidator - ) - public - view - override - returns (PackedUserOperation memory userOp, bytes32 userOpHash) - { - bytes memory initCode; - bool notDeployedYet = instance.account.code.length == 0; - if (notDeployedYet) { - initCode = instance.initCode; - } - - userOp = PackedUserOperation({ - sender: instance.account, - nonce: getNonce(instance, 0x00, txValidator), - initCode: initCode, - callData: callData, - accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), - preVerificationGas: 2e6, - gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), - paymasterAndData: bytes(""), - signature: bytes("") - }); - - userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); - } - - /*////////////////////////////////////////////////////////////// - NONCE - //////////////////////////////////////////////////////////////*/ - - /// @notice Gets the nonce for an account instance - /// @param instance AccountInstance the account instance to get the nonce for - /// @param vMode bytes1 the mode of the validator - /// @param validator address the address of the validator - /// @return nonce uint256 the nonce - function getNonce( - AccountInstance memory instance, - bytes1 vMode, - address validator - ) - internal - view - returns (uint256 nonce) - { - uint192 key = makeNonceKey(vMode, validator); - nonce = instance.aux.entrypoint.getNonce(address(instance.account), key); - } - - /// @notice Makes a nonce key for an account instance - /// @param vMode bytes1 the mode of the validator - /// @param validator address the address of the validator - function makeNonceKey(bytes1 vMode, address validator) internal pure returns (uint192 key) { - // solhint-disable-next-line no-inline-assembly - assembly { - key := or(shr(88, vMode), validator) - } - } - - /*////////////////////////////////////////////////////////////////////////// - MODULE CONFIG - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Configures a userop for an account instance to install or uninstall a module - /// @param instance AccountInstance the account instance to configure the userop for - /// @param moduleType uint256 the type of the module - /// @param module address the address of the module - /// @param initData data the data to pass to the module - /// @param isInstall bool whether to install or uninstall the module - /// @param txValidator address the address of the validator - /// @return userOp PackedUserOperation the packed user operation - /// @return userOpHash bytes32 the hash of the user operation - function configModuleUserOp( - AccountInstance memory instance, - uint256 moduleType, - address module, - bytes memory initData, - bool isInstall, - address txValidator - ) - public - view - override - returns (PackedUserOperation memory userOp, bytes32 userOpHash) - { - bytes memory initCode; - if (instance.account.code.length == 0) { - initCode = instance.initCode; - } - bytes memory callData; - if (isInstall) { - initData = getInstallModuleData(instance, moduleType, module, initData); - callData = getInstallModuleCallData(instance, moduleType, module, initData); - } else { - initData = getUninstallModuleData(instance, moduleType, module, initData); - callData = getUninstallModuleCallData(instance, moduleType, module, initData); - } - - userOp = PackedUserOperation({ - sender: instance.account, - nonce: getNonce(instance, 0x00, txValidator), - initCode: initCode, - callData: callData, - accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), - preVerificationGas: 2e6, - gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), - paymasterAndData: bytes(""), - signature: bytes("") - }); - - userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); - } - - /// @notice Gets the data to install a validator on an account instance - /// @param instance AccountInstance the account instance to install the validator on - /// @param initData the data to pass to the validator - /// @return data the data to install the validator - function getUninstallValidatorData( - AccountInstance memory instance, - address module, - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory data) - { - // get previous validator in sentinel list - address previous; - - (address[] memory array,) = - IAccountModulesPaginated(instance.account).getValidatorsPaginated(address(0x1), 100); - - if (array.length == 1) { - previous = address(0x1); - } else if (array[0] == module) { - previous = address(0x1); - } else { - for (uint256 i = 1; i < array.length; i++) { - if (array[i] == module) previous = array[i - 1]; - } - } - data = abi.encode(previous, initData); - } - - /// @notice Gets the data to install a validator on an account instance - /// @param instance AccountInstance the account instance to install the validator on - /// @param initData the data to pass to the validator - /// @return data the data to install the validator - function getUninstallExecutorData( - AccountInstance memory instance, - address module, - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory data) - { - // get previous executor in sentinel list - address previous; - - (address[] memory array,) = - IAccountModulesPaginated(instance.account).getExecutorsPaginated(address(0x1), 100); - - if (array.length == 1) { - previous = address(0x1); - } else if (array[0] == module) { - previous = address(0x1); - } else { - for (uint256 i = 1; i < array.length; i++) { - if (array[i] == module) previous = array[i - 1]; - } - } - data = abi.encode(previous, initData); - } - - /// @notice Gets the data to install a fallback on an account instance - /// @param initData the data to pass to the module - /// @return data the data to install the fallback - function getInstallFallbackData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - pure - virtual - override - returns (bytes memory data) - { - (bytes4 selector, CallType callType, bytes memory _initData) = - abi.decode(initData, (bytes4, CallType, bytes)); - data = abi.encodePacked(selector, callType, _initData); - } - - /// @notice Gets the data to uninstall a fallback on an account instance - /// @param initData the data to pass to the module - /// @return data the data to uninstall the fallback - function getUninstallFallbackData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - pure - virtual - override - returns (bytes memory data) - { - (bytes4 selector,, bytes memory _initData) = abi.decode(initData, (bytes4, CallType, bytes)); - data = abi.encodePacked(selector, _initData); - } - - /*////////////////////////////////////////////////////////////////////////// - SIGNATURE UTILS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Checks if a signature is valid for an account instance - /// @param instance AccountInstance the account instance to check the signature on - /// @param validator address the address of the validator - /// @param hash bytes32 the hash of the data that is signed - /// @param signature bytes the signature to check - /// @return isValid bool whether the signature is valid, return true if isValidSignature return - /// EIP1271_MAGIC_VALUE - function isValidSignature( - AccountInstance memory instance, - address validator, - bytes32 hash, - bytes memory signature - ) - public - virtual - override - deployAccountForAction(instance) - returns (bool isValid) - { - isValid = IERC1271(instance.account).isValidSignature( - hash, abi.encodePacked(validator, signature) - ) == EIP1271_MAGIC_VALUE; - } - - /// @notice Formats an ERC1271 signature for an account instance - /// @param validator address the address of the validator - /// @param signature bytes the signature to format - /// @return bytes the formatted signature - function formatERC1271Signature( - AccountInstance memory, // instance - address validator, - bytes memory signature - ) - public - virtual - override - returns (bytes memory) - { - return abi.encodePacked(validator, signature); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/SafeHelpers.sol b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/SafeHelpers.sol deleted file mode 100644 index d2bf3be..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/SafeHelpers.sol +++ /dev/null @@ -1,535 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { AccountInstance } from "../RhinestoneModuleKit.sol"; -import { PackedUserOperation } from "../../external/ERC4337.sol"; -import { - MODULE_TYPE_HOOK, - MODULE_TYPE_VALIDATOR, - MODULE_TYPE_EXECUTOR, - MODULE_TYPE_FALLBACK, - MODULE_TYPE_PREVALIDATION_HOOK_ERC1271, - MODULE_TYPE_PREVALIDATION_HOOK_ERC4337 -} from "../../accounts/common/interfaces/IERC7579Module.sol"; -import { HookType } from "../../accounts/safe/types/DataTypes.sol"; -import { CALLTYPE_STATIC } from "../../accounts/common/lib/ModeLib.sol"; -import { CallType } from "../../accounts/common/lib/ModeLib.sol"; - -// Dependencies -import { HelperBase } from "./HelperBase.sol"; -import { SafeFactory } from "../../accounts/safe/SafeFactory.sol"; - -// Interfaces -import { ISafe7579Launchpad } from "../../accounts/safe/interfaces/ISafe7579Launchpad.sol"; -import { IERC7579Account } from "../../accounts/common/interfaces/IERC7579Account.sol"; -import { IAccountFactory } from "../../accounts/factory/interface/IAccountFactory.sol"; -import { IAccountModulesPaginated } from "./interfaces/IAccountModulesPaginated.sol"; -import { IERC1271, EIP1271_MAGIC_VALUE, IERC712 } from "../../Interfaces.sol"; - -// Libraries -import { LibBytes } from "solady/utils/LibBytes.sol"; - -// Utils -import { startPrank, stopPrank } from "../utils/Vm.sol"; - -/// @notice Helper functions for the Safe7579 implementation -contract SafeHelpers is HelperBase { - /*////////////////////////////////////////////////////////////////////////// - CONSTANTS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice The typehash for EIP712 Safe messages - bytes32 constant SAFE_MSG_TYPEHASH = - 0x60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca; - - /*////////////////////////////////////////////////////////////////////////// - EXECUTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Gets userOp and userOpHash for an executing calldata on an account instance - /// @param instance AccountInstance the account instance to execute the callData on - /// @param callData bytes the calldata to execute - /// @param txValidator address the address of the validator - /// @return userOp PackedUserOperation the user operation - /// @return userOpHash bytes32 the hash of the user operation - function execUserOp( - AccountInstance memory instance, - bytes memory callData, - address txValidator - ) - public - virtual - override - returns (PackedUserOperation memory userOp, bytes32 userOpHash) - { - bytes memory initCode; - bool notDeployedYet = instance.account.code.length == 0; - if (notDeployedYet) { - initCode = instance.initCode; - } - - if (initCode.length != 0) { - (initCode, callData) = _getInitCallData(instance.salt, initCode, callData); - } - - userOp = PackedUserOperation({ - sender: instance.account, - nonce: getNonce(instance, callData, txValidator), - initCode: initCode, - callData: callData, - accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), - preVerificationGas: 2e6, - gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), - paymasterAndData: bytes(""), - signature: bytes("") - }); - - userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); - } - - /*////////////////////////////////////////////////////////////////////////// - MODULE CONFIG - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Configures a userop for an account instance to install or uninstall a module - /// @param instance AccountInstance the account instance to configure the userop for - /// @param moduleType uint256 the type of the module - /// @param module address the address of the module - /// @param initData bytes the data to pass to the module - /// @param isInstall bool whether to install or uninstall the module - /// @param txValidator address the address of the validator - /// @return userOp PackedUserOperation the packed user operation - /// @return userOpHash bytes32 the hash of the user operation - function configModuleUserOp( - AccountInstance memory instance, - uint256 moduleType, - address module, - bytes memory initData, - bool isInstall, - address txValidator - ) - public - virtual - override - returns (PackedUserOperation memory userOp, bytes32 userOpHash) - { - bytes memory initCode; - if (instance.account.code.length == 0) { - initCode = instance.initCode; - } - - bytes memory callData; - if (isInstall) { - initData = getInstallModuleData({ - instance: instance, - moduleType: moduleType, - module: module, - initData: initData - }); - callData = abi.encodeCall(IERC7579Account.installModule, (moduleType, module, initData)); - } else { - initData = getUninstallModuleData({ - instance: instance, - moduleType: moduleType, - module: module, - initData: initData - }); - callData = - abi.encodeCall(IERC7579Account.uninstallModule, (moduleType, module, initData)); - } - - if (initCode.length != 0) { - (initCode, callData) = _getInitCallData(instance.salt, initCode, callData); - } - - userOp = PackedUserOperation({ - sender: instance.account, - nonce: getNonce(instance, callData, txValidator), - initCode: initCode, - callData: callData, - accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), - preVerificationGas: 2e6, - gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), - paymasterAndData: bytes(""), - signature: bytes("") - }); - - userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); - } - - /// @notice Gets the data to install a validator on an account instance - /// @param instance AccountInstance the account instance to install the validator on - /// @param initData the data to pass to the validator - /// @return data the data to install the validator - function getUninstallValidatorData( - AccountInstance memory instance, - address module, - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory data) - { - // get previous validator in sentinel list - address previous; - - (address[] memory array,) = - IAccountModulesPaginated(instance.account).getValidatorsPaginated(address(0x1), 100); - - if (array.length == 1) { - previous = address(0x1); - } else if (array[0] == module) { - previous = address(0x1); - } else { - for (uint256 i = 1; i < array.length; i++) { - if (array[i] == module) previous = array[i - 1]; - } - } - data = abi.encode(previous, initData); - } - - /// @notice Gets the data to install an executor on an account instance - /// @param instance AccountInstance the account instance to install the executor on - /// @param initData the data to pass to the executor - /// @return data the data to install the executor - function getUninstallExecutorData( - AccountInstance memory instance, - address module, - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory data) - { - // get previous executor in sentinel list - address previous; - - (address[] memory array,) = - IAccountModulesPaginated(instance.account).getExecutorsPaginated(address(0x1), 100); - - if (array.length == 1) { - previous = address(0x1); - } else if (array[0] == module) { - previous = address(0x1); - } else { - for (uint256 i = 1; i < array.length; i++) { - if (array[i] == module) previous = array[i - 1]; - } - } - data = abi.encode(previous, initData); - } - - /// @notice Gets the data to install a hook on an account instance - /// @param initData the data to pass to the hook - /// @return data the data to install the hook - function getInstallHookData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory data) - { - data = abi.encode(HookType.GLOBAL, bytes4(0x0), initData); - } - - /// @notice Gets the data to uninstall a hook on an account instance - /// @param initData the data to pass to the hook - /// @return data the data to uninstall the hook - function getUninstallHookData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - pure - virtual - override - returns (bytes memory data) - { - data = abi.encode(HookType.GLOBAL, bytes4(0x0), initData); - } - - /// @notice Gets the data to install a fallback on an account instance - /// @param initData the data to pass to the fallback - /// @return data the data to install the fallback - function getUninstallFallbackData( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - pure - virtual - override - returns (bytes memory data) - { - (bytes4 selector,, bytes memory _initData) = abi.decode(initData, (bytes4, CallType, bytes)); - data = abi.encode(selector, _initData); - } - - /// @notice get callData to install an ERC1271 prevalidation hook - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to install the prevalidation hook ERC1271 - function getInstallPrevalidationHookERC1271Data( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory data) - { - data = abi.encode(MODULE_TYPE_PREVALIDATION_HOOK_ERC1271, initData); - } - - /// @notice get callData to install an ERC4337 prevalidation hook ERC4337 - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to install the prevalidation hook ERC4337 - function getInstallPrevalidationHookERC4337Data( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory data) - { - data = abi.encode(MODULE_TYPE_PREVALIDATION_HOOK_ERC4337, initData); - } - - /// @notice get callData to uninstall an ERC1271 prevalidation hook - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to uninstall the prevalidation hook ERC1271 - function getUninstallPrevalidationHookERC1271Data( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory data) - { - data = abi.encode(MODULE_TYPE_PREVALIDATION_HOOK_ERC1271, initData); - } - - /// @notice get callData to uninstall an ERC4337 prevalidation hook - /// @param initData bytes the data to pass to the module - /// @return data bytes the callData to uninstall the prevalidation hook ERC4337 - function getUninstallPrevalidationHookERC4337Data( - AccountInstance memory, // instance - address, // module - bytes memory initData - ) - public - view - virtual - override - returns (bytes memory data) - { - data = abi.encode(MODULE_TYPE_PREVALIDATION_HOOK_ERC4337, initData); - } - - /// @notice Checks if a module is installed on an account instance - /// @param instance AccountInstance the account instance to check - /// @param moduleTypeId uint256 the type of the module - /// @param module address the address of the module - /// @param data bytes the data to pass to the module - /// @return bool whether the module is installed - function isModuleInstalled( - AccountInstance memory instance, - uint256 moduleTypeId, - address module, - bytes memory data - ) - public - virtual - override - deployAccountForAction(instance) - returns (bool) - { - if (moduleTypeId == MODULE_TYPE_HOOK) { - data = abi.encode(HookType.GLOBAL, bytes4(0x0), data); - } - - if ( - moduleTypeId == MODULE_TYPE_PREVALIDATION_HOOK_ERC4337 - || moduleTypeId == MODULE_TYPE_PREVALIDATION_HOOK_ERC1271 - ) { - data = abi.encode(moduleTypeId, data); - } - - return IERC7579Account(instance.account).isModuleInstalled(moduleTypeId, module, data); - } - - /*////////////////////////////////////////////////////////////////////////// - SIGNATURE UTILS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Checks if a signature is valid for an account instance - /// @param instance AccountInstance the account instance to check the signature on - /// @param validator address the address of the validator - /// @param hash bytes32 the hash to check the signature against - /// @param signature bytes the signature to check - /// @return isValid bool whether the signature is valid, returns true if isValidSignature - /// returns EIP1271_MAGIC_VALUE - function isValidSignature( - AccountInstance memory instance, - address validator, - bytes32 hash, - bytes memory signature - ) - public - virtual - override - deployAccountForAction(instance) - returns (bool isValid) - { - isValid = IERC1271(instance.account).isValidSignature( - hash, abi.encodePacked(validator, signature) - ) == EIP1271_MAGIC_VALUE; - } - - /// @notice Format a Safe compatible hash for an account instance - /// @param instance AccountInstance the account instance to format the hash for - /// @param hash bytes32 the hash to format - /// @return bytes32 the formatted hash - function formatERC1271Hash( - AccountInstance memory instance, - address validator, - bytes32 hash - ) - public - virtual - override - deployAccountForAction(instance) - returns (bytes32) - { - // Revert if validator is installed - if (isModuleInstalled(instance, MODULE_TYPE_VALIDATOR, validator, "")) { - revert("formatERC1271Hash: validator is installed"); - } - bytes memory messageData = abi.encodePacked( - bytes1(0x19), - bytes1(0x01), - IERC712(instance.account).domainSeparator(), - keccak256(abi.encodePacked(SAFE_MSG_TYPEHASH, abi.encode(keccak256(abi.encode(hash))))) - ); - return keccak256(messageData); - } - - /// @notice Format a ERC1271 signature for an account - /// @param validator address the address of the validator - /// @param signature bytes the signature to format - /// @return bytes the formatted signature - function formatERC1271Signature( - AccountInstance memory, // instance - address validator, - bytes memory signature - ) - public - virtual - override - returns (bytes memory) - { - return abi.encodePacked(validator, signature); - } - - /*////////////////////////////////////////////////////////////////////////// - ACCOUNT UTILS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Deploys an account instance if it has not been deployed yet - /// reverts if no initCode is provided - /// @param instance AccountInstance the account instance to deploy - function deployAccount(AccountInstance memory instance) public virtual override { - if (instance.account.code.length == 0) { - if (instance.initCode.length == 0) { - revert("deployAccount: no initCode provided"); - } else { - (bytes memory initCode, bytes memory callData) = _getInitCallData( - instance.salt, - instance.initCode, - encode({ target: address(0), value: 0 wei, callData: "" }) - ); - assembly { - let factory := mload(add(initCode, 20)) - let success := call(gas(), factory, 0, add(initCode, 52), mload(initCode), 0, 0) - if iszero(success) { revert(0, 0) } - } - PackedUserOperation memory userOp = PackedUserOperation({ - sender: instance.account, - nonce: getNonce(instance, callData, address(instance.defaultValidator)), - initCode: "", - callData: callData, - accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), - preVerificationGas: 2e6, - gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))), - paymasterAndData: bytes(""), - signature: bytes("") - }); - bytes32 userOpHash = instance.aux.entrypoint.getUserOpHash(userOp); - bytes memory userOpValidationCallData = - abi.encodeCall(ISafe7579Launchpad.validateUserOp, (userOp, userOpHash, 0)); - startPrank(address(instance.aux.entrypoint)); - (bool success,) = instance.account.call(userOpValidationCallData); - if (!success) { - revert("deployAccount: failed to call account"); - } - - (success,) = instance.account.call(callData); - - if (!success) { - revert("deployAccount: failed to call account"); - } - stopPrank(); - } - } - } - - /*////////////////////////////////////////////////////////////////////////// - INTERNAL - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Gets the initCode and callData for a new account instance - /// @param salt bytes32 the salt for the account instance - /// @param originalInitCode bytes the original initCode for the account instance - /// @param erc4337CallData bytes the callData for the ERC4337 call - function _getInitCallData( - bytes32 salt, - bytes memory originalInitCode, - bytes memory erc4337CallData - ) - public - pure - returns (bytes memory initCode, bytes memory callData) - { - // TODO: refactor this to decode the initcode - address factory; - assembly { - factory := mload(add(originalInitCode, 20)) - } - bytes memory initData2 = LibBytes.slice(originalInitCode, 120, originalInitCode.length); - ISafe7579Launchpad.InitData memory initData = - abi.decode(initData2, (ISafe7579Launchpad.InitData)); - initData.callData = erc4337CallData; - initCode = abi.encodePacked( - factory, abi.encodeCall(SafeFactory.createAccount, (salt, abi.encode(initData))) - ); - callData = abi.encodeCall(ISafe7579Launchpad.setupSafe, (initData)); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/SmartSessionHelpers.sol b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/SmartSessionHelpers.sol deleted file mode 100644 index d1cf72e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/SmartSessionHelpers.sol +++ /dev/null @@ -1,393 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -/// @dev A collection of smart session related libraries, vendored from -/// https://github.com/erc7579/smartsessions - -// Interfaces -import { - SmartSessionMode, - PermissionId, - EnableSession, - ChainDigest, - Session, - PolicyData, - ActionData, - ERC7739Data -} from "../../integrations/interfaces/ISmartSession.sol"; - -// Libraries -import { LibZip } from "solady/utils/LibZip.sol"; -import { EfficientHashLib } from "solady/utils/EfficientHashLib.sol"; -import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; - -// Types -import { ModeCode as ExecutionMode } from "../../accounts/common/lib/ModeLib.sol"; - -library SmartSessionModeLib { - function isUseMode(SmartSessionMode mode) internal pure returns (bool) { - return mode == SmartSessionMode.USE; - } - - function isEnableMode(SmartSessionMode mode) internal pure returns (bool) { - return (mode == SmartSessionMode.ENABLE || mode == SmartSessionMode.UNSAFE_ENABLE); - } - - function useRegistry(SmartSessionMode mode) internal pure returns (bool) { - return (mode == SmartSessionMode.ENABLE); - } -} - -library EncodeLib { - using LibZip for bytes; - using EncodeLib for *; - using SmartSessionModeLib for SmartSessionMode; - - error ChainIdAndHashesLengthMismatch(uint256 chainIdsLength, uint256 hashesLength); - - function unpackMode(bytes calldata packed) - internal - pure - returns (SmartSessionMode mode, PermissionId permissionId, bytes calldata data) - { - mode = SmartSessionMode(uint8(bytes1(packed[:1]))); - if (mode.isEnableMode()) { - data = packed[1:]; - } else { - permissionId = PermissionId.wrap(bytes32(packed[1:33])); - data = packed[33:]; - } - } - - function encodeUse( - PermissionId permissionId, - bytes memory sig - ) - internal - pure - returns (bytes memory userOpSig) - { - userOpSig = - abi.encodePacked(SmartSessionMode.USE, permissionId, abi.encode(sig).flzCompress()); - } - - function decodeUse(bytes memory packedSig) internal pure returns (bytes memory signature) { - (signature) = abi.decode(packedSig.flzDecompress(), (bytes)); - } - - function encodeUnsafeEnable( - bytes memory sig, - EnableSession memory enableData - ) - internal - pure - returns (bytes memory packedSig) - { - packedSig = abi.encodePacked( - SmartSessionMode.UNSAFE_ENABLE, abi.encode(enableData, sig).flzCompress() - ); - } - - function encodeEnable( - bytes memory sig, - EnableSession memory enableData - ) - internal - pure - returns (bytes memory packedSig) - { - packedSig = - abi.encodePacked(SmartSessionMode.ENABLE, abi.encode(enableData, sig).flzCompress()); - } - - function decodeEnable(bytes calldata packedSig) - internal - pure - returns (EnableSession memory enableData, bytes memory signature) - { - (enableData, signature) = abi.decode(packedSig.flzDecompress(), (EnableSession, bytes)); - } -} - -// Typehashes -string constant POLICY_DATA_NOTATION = "PolicyData(address policy,bytes initData)"; -string constant ACTION_DATA_NOTATION = - "ActionData(address actionTarget, bytes4 actionTargetSelector,PolicyData[] actionPolicies)"; -string constant ERC7739_DATA_NOTATION = - "ERC7739Data(string[] allowedERC7739Content,PolicyData[] erc1271Policies)"; - -bytes32 constant POLICY_DATA_TYPEHASH = keccak256(bytes(POLICY_DATA_NOTATION)); -bytes32 constant ACTION_DATA_TYPEHASH = keccak256(bytes(ACTION_DATA_NOTATION)); -bytes32 constant ERC7739_DATA_TYPEHASH = keccak256(bytes(ERC7739_DATA_NOTATION)); - -string constant SESSION_NOTATION = - "Session(address account,address smartSession,uint8 mode,address sessionValidator,bytes32 salt,bytes sessionValidatorInitData,PolicyData[] userOpPolicies,ERC7739Data erc7739Policies,ActionData[] actions)"; -string constant CHAIN_SESSION_NOTATION = "ChainSession(uint64 chainId,Session session)"; -string constant MULTI_CHAIN_SESSION_NOTATION = - "MultiChainSession(ChainSession[] sessionsAndChainIds)"; - -bytes32 constant SESSION_TYPEHASH = keccak256( - abi.encodePacked( - bytes(SESSION_NOTATION), - bytes(POLICY_DATA_NOTATION), - bytes(ACTION_DATA_NOTATION), - bytes(ERC7739_DATA_NOTATION) - ) -); - -bytes32 constant CHAIN_SESSION_TYPEHASH = keccak256( - abi.encodePacked( - bytes(CHAIN_SESSION_NOTATION), - bytes(SESSION_NOTATION), - bytes(POLICY_DATA_NOTATION), - bytes(ACTION_DATA_NOTATION), - bytes(ERC7739_DATA_NOTATION) - ) -); - -bytes32 constant MULTICHAIN_SESSION_TYPEHASH = keccak256( - abi.encodePacked( - bytes(MULTI_CHAIN_SESSION_NOTATION), - bytes(CHAIN_SESSION_NOTATION), - bytes(SESSION_NOTATION), - bytes(POLICY_DATA_NOTATION), - bytes(ACTION_DATA_NOTATION), - bytes(ERC7739_DATA_NOTATION) - ) -); - -/// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address -/// verifyingContract)")`. -bytes32 constant _DOMAIN_TYPEHASH = - 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; - -// keccak256(abi.encode(_DOMAIN_TYPEHASH, keccak256("SmartSession"), keccak256(""), 0, address(0))); -// One should use the same domain separator where possible -// or provide the following EIP712Domain struct to the signTypedData() function -// Name: "SmartSession" (string) -// Version: "" (string) -// ChainId: 0 (uint256) -// VerifyingContract: address(0) (address) -// it is introduced for compatibility with signTypedData() -// all the critical data such as chainId and verifyingContract are included -// in session hashes -// https://docs.metamask.io/wallet/reference/eth_signtypeddata_v4 -bytes32 constant _DOMAIN_SEPARATOR = - 0xa82dd76056d04dc31e30c73f86aa4966336112e8b5e9924bb194526b08c250c1; - -library HashLib { - error ChainIdMismatch(uint64 providedChainId); - error HashMismatch(bytes32 providedHash, bytes32 computedHash); - - using EfficientHashLib for bytes32; - using HashLib for *; - - /** - * Mimics SignTypedData() behaviour - * 1. hashStruct(Session) - * 2. hashStruct(ChainSession) - * 3. abi.encodePacked hashStruct's for 2) together - * 4. Hash it together with MULTI_CHAIN_SESSION_TYPEHASH - * as it was MultiChainSession struct - * 5. Add multichain domain separator - * This method doest same, just w/o 1. as it is already provided to us as a digest - */ - function multichainDigest(ChainDigest[] memory hashesAndChainIds) - internal - pure - returns (bytes32) - { - bytes32 structHash = keccak256( - abi.encode(MULTICHAIN_SESSION_TYPEHASH, hashesAndChainIds.hashChainDigestArray()) - ); - - return MessageHashUtils.toTypedDataHash(_DOMAIN_SEPARATOR, structHash); - } - - /** - * Hash array of ChainDigest structs - */ - function hashChainDigestArray(ChainDigest[] memory chainDigestArray) - internal - pure - returns (bytes32) - { - uint256 length = chainDigestArray.length; - bytes32[] memory hashes = new bytes32[](length); - for (uint256 i; i < length; i++) { - hashes[i] = chainDigestArray[i].hashChainDigestMimicRPC(); - } - return keccak256(abi.encodePacked(hashes)); - } - - /** - * We have session digests, not full Session structs - * However to mimic signTypedData() behaviour, we need to use CHAIN_SESSION_TYPEHASH - * not CHAIN_DIGEST_TYPEHASH. We just use the ready session digest instead of rebuilding it - */ - function hashChainDigestMimicRPC(ChainDigest memory chainDigest) - internal - pure - returns (bytes32) - { - return keccak256( - abi.encode( - CHAIN_SESSION_TYPEHASH, - chainDigest.chainId, - chainDigest.sessionDigest // this is the digest obtained using sessionDigest() - // we just do not rebuild it here for all sessions, but receive it from - // off-chain - ) - ); - } - - /** - * Hashes the data from the Session struct with some security critical data - * such as nonce, account address, smart session address, and mode - */ - function sessionDigest( - Session memory session, - address account, - SmartSessionMode mode, - uint256 nonce - ) - internal - view - returns (bytes32) - { - return _sessionDigest(session, account, address(this), mode, nonce); - } - - /** - * Should never be used directly on-chain, only via sessionDigest() - * Only for external use - to be able to pass smartSession when - * testing for different chains which may have different addresses for - * the Smart Session contract - * It is exactly how signTypedData will hash such an object - * when this object is an inner struct - * It won't use eip712 domain for it as it is inner struct - */ - function _sessionDigest( - Session memory session, - address account, - address smartSession, // for testing purposes - SmartSessionMode mode, - uint256 nonce - ) - internal - pure - returns (bytes32 _hash) - { - // chainId is not needed as it is in the ChainSession - _hash = keccak256( - abi.encode( - SESSION_TYPEHASH, - account, - smartSession, - uint8(mode), // Include mode as uint8 - address(session.sessionValidator), - session.salt, - keccak256(session.sessionValidatorInitData), - session.userOpPolicies.hashPolicyDataArray(), - session.erc7739Policies.hashERC7739Data(), - session.actions.hashActionDataArray(), - nonce - ) - ); - } - - function hashPolicyData(PolicyData memory policyData) internal pure returns (bytes32) { - return keccak256( - abi.encode(POLICY_DATA_TYPEHASH, policyData.policy, keccak256(policyData.initData)) - ); - } - - function hashPolicyDataArray(PolicyData[] memory policyDataArray) - internal - pure - returns (bytes32) - { - uint256 length = policyDataArray.length; - bytes32[] memory hashes = new bytes32[](length); - for (uint256 i; i < length; i++) { - hashes[i] = policyDataArray[i].hashPolicyData(); - } - return keccak256(abi.encodePacked(hashes)); - } - - function hashActionData(ActionData memory actionData) internal pure returns (bytes32) { - return keccak256( - abi.encode( - ACTION_DATA_TYPEHASH, - actionData.actionTargetSelector, - actionData.actionTarget, - hashPolicyDataArray(actionData.actionPolicies) - ) - ); - } - - function hashActionDataArray(ActionData[] memory actionDataArray) - internal - pure - returns (bytes32) - { - uint256 length = actionDataArray.length; - bytes32[] memory hashes = new bytes32[](length); - for (uint256 i; i < length; i++) { - hashes[i] = actionDataArray[i].hashActionData(); - } - return keccak256(abi.encodePacked(hashes)); - } - - function hashERC7739Data(ERC7739Data memory erc7739Data) internal pure returns (bytes32) { - return keccak256( - abi.encode( - ERC7739_DATA_TYPEHASH, - erc7739Data.allowedERC7739Content.hashStringArray(), - erc7739Data.erc1271Policies.hashPolicyDataArray() - ) - ); - } - - function hashStringArray(string[] memory stringArray) internal pure returns (bytes32) { - uint256 length = stringArray.length; - bytes32[] memory hashes = new bytes32[](length); - for (uint256 i; i < length; i++) { - hashes[i] = keccak256(abi.encodePacked(stringArray[i])); - } - return keccak256(abi.encodePacked(hashes)); - } - - function hashERC7739Content(string memory content) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(content)); - } - - function getAndVerifyDigest( - EnableSession memory enableData, - address account, - uint256 nonce, - SmartSessionMode mode - ) - internal - view - returns (bytes32 digest) - { - bytes32 computedHash = enableData.sessionToEnable.sessionDigest(account, mode, nonce); - - uint64 providedChainId = enableData.hashesAndChainIds[enableData.chainDigestIndex].chainId; - bytes32 providedHash = - enableData.hashesAndChainIds[enableData.chainDigestIndex].sessionDigest; - - if (providedChainId != block.chainid) { - revert ChainIdMismatch(providedChainId); - } - - // ensure digest we've built from the sessionToEnable is included into - // the list of digests that were signed - if (providedHash != computedHash) { - revert HashMismatch(providedHash, computedHash); - } - - digest = enableData.hashesAndChainIds.multichainDigest(); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/interfaces/IAccountModulesPaginated.sol b/typescript/packages/account-modules/lib/modulekit/src/test/helpers/interfaces/IAccountModulesPaginated.sol deleted file mode 100644 index 1d9c50c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/helpers/interfaces/IAccountModulesPaginated.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -interface IAccountModulesPaginated { - function getValidatorsPaginated( - address, - uint256 - ) - external - view - returns (address[] memory, address); - - function getExecutorsPaginated( - address, - uint256 - ) - external - view - returns (address[] memory, address); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/ECDSA.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/ECDSA.sol deleted file mode 100644 index 28fbfad..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/utils/ECDSA.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Utils -import { sign as vmSign } from "./Vm.sol"; - -function ecdsaSign(uint256 privKey, bytes32 digest) pure returns (bytes memory signature) { - (uint8 v, bytes32 r, bytes32 s) = vmSign(privKey, digest); - return abi.encodePacked(r, s, v); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/ERC4337Helpers.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/ERC4337Helpers.sol deleted file mode 100644 index b0c76f6..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/utils/ERC4337Helpers.sol +++ /dev/null @@ -1,272 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { - PackedUserOperation, - IEntryPoint, - IEntryPointSimulations, - IStakeManager -} from "../../external/ERC4337.sol"; -import { ExecutionReturnData } from "../RhinestoneModuleKit.sol"; - -// Deployments -import { ENTRYPOINT_ADDR } from "../../deployment/predeploy/EntryPoint.sol"; - -// Utils -import "./Vm.sol"; -import "./Log.sol"; - -// Dependencies -import "./gas/GasCalculations.sol"; -import { GasParser } from "./gas/GasParser.sol"; -import { - getSimulateUserOp, - getExpectRevert, - getExpectRevertMessage, - clearExpectRevert, - getGasIdentifier, - writeGasIdentifier, - writeInstalledModule, - getInstalledModules, - removeInstalledModule, - InstalledModule -} from "./Storage.sol"; - -// External Dependencies -import { Simulator } from "erc4337-validation/Simulator.sol"; - -/// @notice A library that contains helper functions for ERC-4337 operations -library ERC4337Helpers { - using Simulator for PackedUserOperation; - - error UserOperationReverted( - bytes32 userOpHash, address sender, string senderLabel, uint256 nonce, bytes revertReason - ); - error InvalidRevertMessage(bytes4 expected, bytes4 reason); - error InvalidRevertMessageBytes(bytes expected, bytes reason); - - struct ExecutionContext { - uint256 isExpectRevert; - address payable beneficiary; - bytes userOpCalldata; - bool success; - bytes returnData; - } - - function exec4337( - PackedUserOperation[] memory userOps, - IEntryPoint onEntryPoint - ) - internal - returns (ExecutionReturnData memory executionData) - { - // Initialize execution context - ExecutionContext memory ctx = ExecutionContext({ - isExpectRevert: getExpectRevert(), - beneficiary: payable(address(0x69)), - userOpCalldata: "", - success: false, - returnData: "" - }); - - // Handle simulation - if (envOr("SIMULATE", false) || getSimulateUserOp()) { - bool simulationSuccess = userOps[0].simulateUserOp(address(onEntryPoint)); - if (ctx.isExpectRevert == 0) { - require(simulationSuccess, "UserOperation simulation failed"); - } - } - - // Record logs for revert detection - recordLogs(); - - // Prepare and execute userOps - ctx.userOpCalldata = abi.encodeCall(IEntryPoint.handleOps, (userOps, ctx.beneficiary)); - (ctx.success, ctx.returnData) = address(onEntryPoint).call(ctx.userOpCalldata); - - if (ctx.isExpectRevert == 0) { - require(ctx.success, "UserOperation execution failed"); - } else if (ctx.isExpectRevert == 2 && !ctx.success) { - checkRevertMessage(ctx.returnData); - } - - // Process logs - VmSafe.Log[] memory logs = getRecordedLogs(); - executionData = ExecutionReturnData(logs); - uint256 totalUserOpGas = 0; - - for (uint256 i; i < logs.length; i++) { - if ( - logs[i].topics[0] - == 0x49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f - ) { - (uint256 nonce, bool userOpSuccess,, uint256 actualGasUsed) = - abi.decode(logs[i].data, (uint256, bool, uint256, uint256)); - totalUserOpGas = actualGasUsed; - - if (!userOpSuccess) { - bytes32 userOpHash = logs[i].topics[1]; - if (ctx.isExpectRevert == 0) { - bytes memory revertReason = getUserOpRevertReason(logs, userOpHash); - address account = address(bytes20(logs[i].topics[2])); - revert UserOperationReverted( - userOpHash, account, getLabel(account), nonce, revertReason - ); - } else { - if (ctx.isExpectRevert == 2) { - checkRevertMessage(getUserOpRevertReason(logs, userOpHash)); - } - clearExpectRevert(); - } - } - } - // Handle module events - else if ( - logs[i].topics[0] - == 0xd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123 - ) { - (uint256 moduleType, address module) = abi.decode(logs[i].data, (uint256, address)); - writeInstalledModule(InstalledModule(moduleType, module), logs[i].emitter); - } else if ( - logs[i].topics[0] - == 0x341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e - ) { - (uint256 moduleType, address module) = abi.decode(logs[i].data, (uint256, address)); - InstalledModule[] memory installedModules = getInstalledModules(logs[i].emitter); - for (uint256 j; j < installedModules.length; j++) { - if ( - installedModules[j].moduleAddress == module - && installedModules[j].moduleType == moduleType - ) { - removeInstalledModule(j, logs[i].emitter); - break; - } - } - } - } - - // Handle gas calculations - string memory gasIdentifier = getGasIdentifier(); - if ( - envOr("GAS", false) && bytes(gasIdentifier).length > 0 - && bytes(gasIdentifier).length < 50 - ) { - calculateGas(userOps, onEntryPoint, ctx.beneficiary, gasIdentifier, totalUserOpGas); - } - - // Emit events - for (uint256 i; i < userOps.length; i++) { - emit ModuleKitLogs.ModuleKit_Exec4337(userOps[i].sender); - } - } - - // Original helper functions unchanged - function exec4337( - PackedUserOperation memory userOp, - IEntryPoint onEntryPoint - ) - internal - returns (ExecutionReturnData memory logs) - { - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = userOp; - return exec4337(userOps, onEntryPoint); - } - - function getUserOpRevertReason( - VmSafe.Log[] memory logs, - bytes32 userOpHash - ) - internal - pure - returns (bytes memory revertReason) - { - for (uint256 i; i < logs.length; i++) { - if ( - logs[i].topics[0] - == 0x1c4fada7374c0a9ee8841fc38afe82932dc0f8e69012e927f061a8bae611a201 - && logs[i].topics[1] == userOpHash - ) { - (, revertReason) = abi.decode(logs[i].data, (uint256, bytes)); - } - } - } - - function checkRevertMessage(bytes memory actualReason) internal view { - bytes memory revertMessage = getExpectRevertMessage(); - if (actualReason.length >= 4) { - bytes4 actual = bytes4(actualReason); - bytes4 expected = bytes4(revertMessage); - if (actual == bytes4(0x65c8fd4d)) { - return parseFailedOpWithRevert(actualReason, revertMessage); - } else if (actual != expected) { - revert InvalidRevertMessageBytes(revertMessage, actualReason); - } - return; - } - if (revertMessage.length != actualReason.length) { - revert InvalidRevertMessageBytes(revertMessage, actualReason); - } - } - - function parseFailedOpWithRevert( - bytes memory actualReason, - bytes memory revertMessage - ) - internal - pure - { - uint256 bytesOffset; - assembly { - let ptr := add(actualReason, 0x20) - ptr := add(ptr, 0x04) - ptr := add(ptr, 0x40) - bytesOffset := mload(ptr) - } - - bytes memory actual; - assembly { - let ptr := add(actualReason, 0x20) - ptr := add(ptr, 0x04) - ptr := add(ptr, bytesOffset) - let innerLength := mload(ptr) - - actual := mload(0x40) - mstore(actual, innerLength) - - let srcPtr := add(ptr, 0x20) - let destPtr := add(actual, 0x20) - mstore(destPtr, mload(srcPtr)) - - mstore(0x40, add(add(actual, 0x20), innerLength)) - } - - if (revertMessage.length == 4) { - bytes4 expected = bytes4(revertMessage); - if (expected != bytes4(actual)) { - revert InvalidRevertMessage(expected, bytes4(actual)); - } - } else { - if (keccak256(actual) != keccak256(revertMessage)) { - revert InvalidRevertMessageBytes(revertMessage, actual); - } - } - } - - function calculateGas( - PackedUserOperation[] memory userOps, - IEntryPoint onEntryPoint, - address beneficiary, - string memory gasIdentifier, - uint256 totalUserOpGas - ) - internal - { - bytes memory userOpCalldata = - abi.encodeWithSelector(onEntryPoint.handleOps.selector, userOps, beneficiary); - GasParser.parseAndWriteGas( - userOpCalldata, address(onEntryPoint), gasIdentifier, userOps[0].sender, totalUserOpGas - ); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/Log.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/Log.sol deleted file mode 100644 index 080e769..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/utils/Log.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -library ModuleKitLogs { - /* solhint-disable event-name-camelcase */ - event ModuleKit_NewAccount(address account, string accountType); - event ModuleKit_Exec4337(address sender); - - event ModuleKit_AddExecutor(address account, address executor); - event ModuleKit_RemoveExecutor(address account, address executor); - - event ModuleKit_AddValidator(address account, address validator); - event ModuleKit_RemoveValidator(address account, address validator); - - event ModuleKit_SetFallback(address account, bytes4 functionSig, address handler); - - event ModuleKit_SetCondition(address account, address executor); - /* solhint-enable event-name-camelcase */ -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/Storage.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/Storage.sol deleted file mode 100644 index 945caaa..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/utils/Storage.sol +++ /dev/null @@ -1,413 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/*////////////////////////////////////////////////////////////// - EXPECT REVERT -//////////////////////////////////////////////////////////////*/ - -function writeExpectRevert(bytes memory message) { - uint256 value = 1; - bytes32 slot = keccak256("ModuleKit.ExpectMessageSlot"); - - if (message.length > 0) { - value = 2; - assembly { - sstore(slot, message) - } - } - - slot = keccak256("ModuleKit.ExpectSlot"); - assembly { - sstore(slot, value) - } -} - -function getExpectRevert() view returns (uint256 value) { - bytes32 slot = keccak256("ModuleKit.ExpectSlot"); - assembly { - value := sload(slot) - } -} - -function getExpectRevertMessage() view returns (bytes memory data) { - bytes32 slot = keccak256("ModuleKit.ExpectMessageSlot"); - assembly { - data := sload(slot) - } -} - -function clearExpectRevert() { - bytes32 slot = keccak256("ModuleKit.ExpectSlot"); - assembly { - sstore(slot, 0) - } - - slot = keccak256("ModuleKit.ExpectMessageSlot"); - assembly { - sstore(slot, 0) - } -} - -/*////////////////////////////////////////////////////////////// - GAS IDENTIFIER -//////////////////////////////////////////////////////////////*/ - -function writeGasIdentifier(string memory id) { - bytes32 slot = keccak256("ModuleKit.GasIdentifierSlot"); - writeString(slot, id); -} - -function getGasIdentifier() view returns (string memory id) { - bytes32 slot = keccak256("ModuleKit.GasIdentifierSlot"); - id = readString(slot); -} - -/*////////////////////////////////////////////////////////////// - SIMULATE OP -//////////////////////////////////////////////////////////////*/ - -function writeSimulateUserOp(bool value) { - bytes32 slot = keccak256("ModuleKit.SimulateUserOp"); - assembly { - sstore(slot, value) - } -} - -function getSimulateUserOp() view returns (bool value) { - bytes32 slot = keccak256("ModuleKit.SimulateUserOp"); - assembly { - value := sload(slot) - } -} - -/*////////////////////////////////////////////////////////////// - STORAGE COMPLIANCE -//////////////////////////////////////////////////////////////*/ - -function writeStorageCompliance(bool value) { - bytes32 slot = keccak256("ModuleKit.StorageCompliance"); - assembly { - sstore(slot, value) - } -} - -function getStorageCompliance() view returns (bool value) { - bytes32 slot = keccak256("ModuleKit.StorageCompliance"); - assembly { - value := sload(slot) - } -} - -/*////////////////////////////////////////////////////////////// - ACCOUNT ENV -//////////////////////////////////////////////////////////////*/ - -function writeAccountEnv(string memory env, address factory, address helper) { - bytes32 envSlot = keccak256("ModuleKit.AccountTypeSlot"); - bytes32 factorySlot = keccak256("ModuleKit.AccountFactorySlot"); - bytes32 helperSlot = keccak256("ModuleKit.HelperSlot"); - bytes32 envHash = keccak256(abi.encodePacked(env)); - assembly { - sstore(envSlot, envHash) - sstore(factorySlot, factory) - sstore(helperSlot, helper) - } -} - -function getAccountEnv() view returns (bytes32 env, address factory, address helper) { - bytes32 envSlot = keccak256("ModuleKit.AccountTypeSlot"); - bytes32 factorySlot = keccak256("ModuleKit.AccountFactorySlot"); - bytes32 helperSlot = keccak256("ModuleKit.HelperSlot"); - assembly { - env := sload(envSlot) - factory := sload(factorySlot) - helper := sload(helperSlot) - } -} - -/*////////////////////////////////////////////////////////////// - ACCOUNT TYPE -//////////////////////////////////////////////////////////////*/ - -function writeAccountType(string memory accountType) { - bytes32 slot = keccak256("ModuleKit.AccountTypeSlot"); - bytes32 accountTypeHash = keccak256(abi.encodePacked(accountType)); - assembly { - sstore(slot, accountTypeHash) - } -} - -function getAccountType() view returns (bytes32 accountType) { - bytes32 slot = keccak256("ModuleKit.AccountTypeSlot"); - assembly { - accountType := sload(slot) - } -} - -/*////////////////////////////////////////////////////////////// - FACTORY -//////////////////////////////////////////////////////////////*/ - -function writeFactory(address factory, string memory factoryType) { - bytes32 slot = keccak256(abi.encode("ModuleKit.", factoryType, "FactorySlot")); - assembly { - sstore(slot, factory) - } -} - -function getFactory(string memory factoryType) view returns (address factory) { - bytes32 slot = keccak256(abi.encode("ModuleKit.", factoryType, "FactorySlot")); - assembly { - factory := sload(slot) - } -} - -/*////////////////////////////////////////////////////////////// - HELPER -//////////////////////////////////////////////////////////////*/ - -function writeHelper(address helper, string memory helperType) { - bytes32 slot = keccak256(abi.encode("ModuleKit.", helperType, "HelperSlot")); - assembly { - sstore(slot, helper) - } -} - -function getHelper(string memory helperType) view returns (address helper) { - bytes32 slot = keccak256(abi.encode("ModuleKit.", helperType, "HelperSlot")); - assembly { - helper := sload(slot) - } -} - -/*////////////////////////////////////////////////////////////// - INSTALLED MODULE -//////////////////////////////////////////////////////////////*/ - -struct InstalledModule { - uint256 moduleType; - address moduleAddress; -} - -// Adds new address to the installed module linked list for the given account -// The list is stored in storage as a linked list in the following format: -// --------------------------------------------------------------------- -// | Slot | Value | -// |----------------------------------------------------------|--------| -// | keccak256(abi.encode("ModuleKit.InstalledModuleSlot.")); | length | -// | keccak256(abi.encode("ModuleKit.InstalledModuleHead.")); | head | -// | keccak256(abi.encode("ModuleKit.InstalledModuleTail.")); | tail | -// | keccak256(abi.encode(lengthSlot)) - initially X | element| -// --------------------------------------------------------------------- -// -// The elements are stored in the following way: -// -------------------------- -// | Slot | Value | -// |------------------------| -// | X | moduleType | -// | X + 0x20 | moduleAddr | -// | X + 0x40 | prev | -// | X + 0x60 | next | -// -------------------------- -function writeInstalledModule(InstalledModule memory module, address account) { - bytes32 lengthSlot = keccak256( - abi.encode("ModuleKit.InstalledModuleSlot.", keccak256(abi.encodePacked(account))) - ); - bytes32 headSlot = keccak256( - abi.encode("ModuleKit.InstalledModuleHead.", keccak256(abi.encodePacked(account))) - ); - bytes32 tailSlot = - keccak256(abi.encode("ModuleKit.InstalledModuleTail", keccak256(abi.encodePacked(account)))); - bytes32 elementSlot = keccak256(abi.encode(lengthSlot)); - uint256 moduleType = module.moduleType; - address moduleAddress = module.moduleAddress; - assembly { - // Get the length of the array - let length := sload(lengthSlot) - let nextSlot - let oldTail - switch iszero(length) - case 1 { - // If length is zero, set element slot to head and tail - sstore(headSlot, elementSlot) - sstore(tailSlot, elementSlot) - oldTail := elementSlot - nextSlot := elementSlot - } - default { - oldTail := sload(tailSlot) - // Set the new elemeont slot to the old tail + 0x80 - elementSlot := add(oldTail, 0x80) - // Set the old tail next slot to the new element slot - sstore(add(oldTail, 0x60), elementSlot) - // Update tailSlot to point to the new element slot - sstore(tailSlot, elementSlot) - // Set nextSlot to the head slot - nextSlot := sload(headSlot) - } - // Update the length of the list - sstore(lengthSlot, add(length, 1)) - // Store the module type and address in the new slot - sstore(elementSlot, moduleType) - sstore(add(elementSlot, 0x20), moduleAddress) - // Store the old tail as the prev slot - sstore(add(elementSlot, 0x40), oldTail) - // Store the head as the next slot - sstore(add(elementSlot, 0x60), nextSlot) - } -} - -// Removes a specific installed module -function removeInstalledModule(uint256 index, address account) { - bytes32 lengthSlot = keccak256( - abi.encode("ModuleKit.InstalledModuleSlot.", keccak256(abi.encodePacked(account))) - ); - bytes32 headSlot = keccak256( - abi.encode("ModuleKit.InstalledModuleHead.", keccak256(abi.encodePacked(account))) - ); - bytes32 tailSlot = keccak256( - abi.encode("ModuleKit.InstalledModuleTail.", keccak256(abi.encodePacked(account))) - ); - assembly { - // Get the length of the list - let length := sload(lengthSlot) - // Get the initial element slot - let elementSlot := sload(headSlot) - // Ensure the index is within bounds - if lt(index, length) { - // Traverse to the node to remove - for { let i := 0 } lt(i, index) { i := add(i, 1) } { - elementSlot := sload(add(elementSlot, 0x60)) - } - - // Get the previous and next slots - let prevSlot := sload(add(elementSlot, 0x40)) - let nextSlot := sload(add(elementSlot, 0x60)) - - // Update the previous slot's next pointer - sstore(add(prevSlot, 0x60), nextSlot) - // Update the next slot's previous pointer - sstore(add(nextSlot, 0x40), prevSlot) - - // Handle removing the head - if eq(elementSlot, sload(headSlot)) { sstore(headSlot, nextSlot) } - - // Handle removing the tail - if eq(elementSlot, sload(tailSlot)) { sstore(tailSlot, prevSlot) } - - // Clear the removed node - sstore(elementSlot, 0) - sstore(add(elementSlot, 0x20), 0) - sstore(add(elementSlot, 0x40), 0) - sstore(add(elementSlot, 0x60), 0) - - // Update the length of the list - sstore(lengthSlot, sub(length, 1)) - } - } -} - -// Returns all installed modules for the given account -function getInstalledModules(address account) view returns (InstalledModule[] memory modules) { - bytes32 lengthSlot = keccak256( - abi.encode("ModuleKit.InstalledModuleSlot.", keccak256(abi.encodePacked(account))) - ); - bytes32 headSlot = keccak256( - abi.encode("ModuleKit.InstalledModuleHead.", keccak256(abi.encodePacked(account))) - ); - assembly { - // Get the length of the array from storage - let length := sload(lengthSlot) - - // Each struct is 64 bytes (32 bytes for moduleType and 32 bytes for moduleAddress) - let structSize := 0x40 // 64 bytes - let size := mul(length, structSize) // Total size for structs - let totalSize := add(add(size, 0x40), mul(0x20, length)) - - // Allocate memory for the array - let freeMemoryPtr := mload(0x40) - modules := freeMemoryPtr - - // Store the length of the array in the first 32 bytes of memory - mstore(modules, length) - - // Update the free memory pointer to the end of the allocated memory - mstore(0x40, add(freeMemoryPtr, totalSize)) - - // Get the head of the linked list - let storageLocation := sload(headSlot) - - // Copy the structs from storage to memory - for { let i := 0 } lt(i, length) { i := add(i, 1) } { - // Calculate memory location for this struct - let structLocation := - add(add(freeMemoryPtr, add(0x40, mul(i, structSize))), mul(0x20, length)) - - // Load the moduleType and moduleAddress from storage - let moduleType := sload(storageLocation) - let moduleAddress := sload(add(storageLocation, 0x20)) - - // Store the structLocation into memory - mstore(add(freeMemoryPtr, add(0x20, mul(i, 0x20))), structLocation) - - // Store the moduleType and moduleAddress into memory - mstore(structLocation, moduleType) - mstore(add(structLocation, 0x20), moduleAddress) - - // Move to the next element in the linked list - storageLocation := sload(add(storageLocation, 0x60)) - } - } -} - -/*////////////////////////////////////////////////////////////// - STRING STORAGE -//////////////////////////////////////////////////////////////*/ - -function writeString(bytes32 slot, string memory value) { - bytes memory strBytes = bytes(value); - uint256 length = strBytes.length; - - // Store the length of the string at the initial slot - assembly { - sstore(slot, length) - } - - // Store the actual string bytes in packed form - for (uint256 i = 0; i < length; i += 32) { - bytes32 data; - for (uint256 j = 0; j < 32 && i + j < length; j++) { - data |= bytes32(uint256(uint8(strBytes[i + j])) << (248 - j * 8)); - } - bytes32 charSlot = keccak256(abi.encodePacked(slot, i / 32)); - assembly { - sstore(charSlot, data) - } - } -} - -function readString(bytes32 slot) view returns (string memory) { - uint256 length; - - // Load the length of the string from the initial slot - assembly { - length := sload(slot) - } - - // Allocate memory for the string bytes - bytes memory strBytes = new bytes(length); - - // Load the actual string bytes from storage in packed form - for (uint256 i = 0; i < length; i += 32) { - bytes32 charSlot = keccak256(abi.encodePacked(slot, i / 32)); - bytes32 data; - assembly { - data := sload(charSlot) - } - for (uint256 j = 0; j < 32 && i + j < length; j++) { - strBytes[i + j] = bytes1(uint8(uint256(data >> (248 - j * 8)))); - } - } - - return string(strBytes); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/Vm.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/Vm.sol deleted file mode 100644 index ac2251c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/utils/Vm.sol +++ /dev/null @@ -1,206 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -import { Vm, VmSafe } from "forge-std/Vm.sol"; - -address constant VM_ADDR = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D; - -function makeAddrAndKey(string memory name) returns (address addr, uint256 privateKey) { - privateKey = uint256(keccak256(abi.encodePacked(name))); - addr = Vm(VM_ADDR).addr(privateKey); - Vm(VM_ADDR).label(addr, name); -} - -function makeAddr(string memory name) pure returns (address addr) { - uint256 privateKey = uint256(keccak256(abi.encodePacked(name))); - addr = Vm(VM_ADDR).addr(privateKey); - // Vm(VM_ADDR).label(addr, name); -} - -function getAddr(uint256 pk) pure returns (address) { - return Vm(VM_ADDR).addr(pk); -} - -function sign(uint256 pk, bytes32 msgHash) pure returns (uint8 v, bytes32 r, bytes32 s) { - return Vm(VM_ADDR).sign(pk, msgHash); -} - -function etch(address target, bytes memory runtimeBytecode) { - Vm(VM_ADDR).etch(target, runtimeBytecode); -} - -function label(address _addr, string memory _label) { - Vm(VM_ADDR).label(_addr, _label); -} - -function getLabel(address addr) view returns (string memory) { - return Vm(VM_ADDR).getLabel(addr); -} - -function deal(address _addr, uint256 amount) { - Vm(VM_ADDR).deal(_addr, amount); -} - -function expectEmit() { - Vm(VM_ADDR).expectEmit(); -} - -function expectRevert() { - Vm(VM_ADDR).expectRevert(); -} - -function expectRevert(bytes4 message) { - Vm(VM_ADDR).expectRevert(message); -} - -function recordLogs() { - Vm(VM_ADDR).recordLogs(); -} - -function getRecordedLogs() returns (VmSafe.Log[] memory) { - return Vm(VM_ADDR).getRecordedLogs(); -} - -function prank(address _addr) { - Vm(VM_ADDR).prank(_addr); -} - -function startPrank(address _addr) { - Vm(VM_ADDR).startPrank(_addr); -} - -function stopPrank() { - Vm(VM_ADDR).stopPrank(); -} - -function accesses(address _addr) returns (bytes32[] memory, bytes32[] memory) { - return Vm(VM_ADDR).accesses(_addr); -} - -function store(address account, bytes32 key, bytes32 entry) { - Vm(VM_ADDR).store(account, key, entry); -} - -function record() { - Vm(VM_ADDR).record(); -} - -function load(address account, bytes32 key) view returns (bytes32) { - return Vm(VM_ADDR).load(account, key); -} - -function snapshot() returns (uint256) { - return Vm(VM_ADDR).snapshotState(); -} - -function revertTo(uint256 id) returns (bool) { - return Vm(VM_ADDR).revertToState(id); -} - -function startStateDiffRecording() { - Vm(VM_ADDR).startStateDiffRecording(); -} - -function stopAndReturnStateDiff() returns (VmSafe.AccountAccess[] memory) { - return Vm(VM_ADDR).stopAndReturnStateDiff(); -} - -function envOr(string memory name, string memory defaultValue) view returns (string memory value) { - return Vm(VM_ADDR).envOr(name, defaultValue); -} - -function envOr(string memory name, bool defaultValue) view returns (bool value) { - return Vm(VM_ADDR).envOr(name, defaultValue); -} - -function setEnv(string memory key, string memory value) { - Vm(VM_ADDR).setEnv(key, value); -} - -function envBool(string memory key) view returns (bool value) { - return Vm(VM_ADDR).envBool(key); -} - -function serializeUint( - string memory objectKey, - string memory valueKey, - uint256 value -) - returns (string memory json) -{ - return Vm(VM_ADDR).serializeUint(objectKey, valueKey, value); -} - -function serializeString( - string memory objectKey, - string memory valueKey, - string memory value -) - returns (string memory json) -{ - return Vm(VM_ADDR).serializeString(objectKey, valueKey, value); -} - -function writeJson(string memory json, string memory path) { - Vm(VM_ADDR).writeJson(json, path); -} - -function readFile(string memory path) view returns (string memory) { - return Vm(VM_ADDR).readFile(path); -} - -function exists(string memory path) view returns (bool) { - return Vm(VM_ADDR).exists(path); -} - -function toString(uint256 input) pure returns (string memory) { - return Vm(VM_ADDR).toString(input); -} - -function toString(int256 input) pure returns (string memory) { - return Vm(VM_ADDR).toString(input); -} - -function toString(bytes memory input) pure returns (string memory) { - return Vm(VM_ADDR).toString(input); -} - -function toString(bytes32 input) pure returns (string memory) { - bytes memory _bytes = new bytes(32); - for (uint256 i = 0; i < 32; i++) { - _bytes[i] = input[i]; - } - return string(_bytes); -} - -function parseJson(string memory json, string memory key) pure returns (bytes memory) { - return Vm(VM_ADDR).parseJson(json, key); -} - -function parseJson(string memory json) pure returns (bytes memory) { - return Vm(VM_ADDR).parseJson(json); -} - -function parseJsonKeys(string memory json, string memory key) pure returns (string[] memory keys) { - return Vm(VM_ADDR).parseJsonKeys(json, key); -} - -function parseUint(string memory stringifiedValue) pure returns (uint256 parsedValue) { - return Vm(VM_ADDR).parseUint(stringifiedValue); -} - -function startMappingRecording() { - Vm(VM_ADDR).startMappingRecording(); -} - -function stopMappingRecording() { - Vm(VM_ADDR).stopMappingRecording(); -} - -function getMappingKeyAndParentOf(address target, bytes32 slot) returns (bool, bytes32, bytes32) { - return Vm(VM_ADDR).getMappingKeyAndParentOf(target, slot); -} - -function getMappingSlotAt(address target, bytes32 slot, uint256 idx) returns (bytes32) { - return Vm(VM_ADDR).getMappingSlotAt(target, slot, idx); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasCalculations.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasCalculations.sol deleted file mode 100644 index f5a0bf1..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasCalculations.sol +++ /dev/null @@ -1,140 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// External Dependencies -import { UD60x18, ud, intoUint256 } from "@prb/math/UD60x18.sol"; -import { PRBMathCastingUint256 } from "@prb/math/casting/Uint256.sol"; -import { LibZip } from "solady/utils/LibZip.sol"; - -// Utils -import { parseJson, toString } from "../Vm.sol"; - -/// @title GasCalculations -/// @dev This contract is used for calculating gas consumption in different phases of a transaction. -struct GasCalculations { - uint256 creation; - uint256 validation; - uint256 execution; - uint256 total; - uint256 arbitrum; - uint256 opStack; -} - -/// @notice Calculate the gas cost of calldata. -/// @param data The calldata to be sent. -/// @return calldataGas The gas cost of the calldata. -function getCallDataGas(bytes memory data) pure returns (uint256 calldataGas) { - for (uint256 i = 0; i < data.length; i++) { - if (data[i] == 0x00) { - calldataGas += 4; - } else { - calldataGas += 16; - } - } -} - -/// @notice Calculate the gas cost of calldata on Arbitrum L1. -/// @param data The calldata to be sent. -/// @return calldataGas The gas cost of the calldata on Arbitrum L1. -function getArbitrumL1Gas(bytes memory data) pure returns (uint256 calldataGas) { - bytes memory compressed = LibZip.flzCompress(data); - calldataGas = getCallDataGas(compressed); -} - -/// @notice Calculate the gas cost of calldata on OpStack L1. -/// @param data The calldata to be sent. -/// @return calldataGas The gas cost of the calldata on OpStack L1. -function getOpStackL1Gas(bytes memory data) pure returns (uint256 calldataGas) { - uint256 opStackConstant = 2028; - UD60x18 opStackScalar = ud(0.684e18); - - calldataGas = intoUint256( - PRBMathCastingUint256.intoUD60x18(getCallDataGas(data)).mul(opStackScalar) - ) + opStackConstant; -} - -/// @notice Parse the previous gas report from a file. -/// @param fileContent The content of the file. -/// @return prevGasCalculations The previous gas calculations. -function parsePrevGasReport(string memory fileContent) - pure - returns (GasCalculations memory prevGasCalculations) -{ - prevGasCalculations.total = parseUintFromASCII(parseJson(fileContent, ".Total")); - prevGasCalculations.creation = parseUintFromASCII(parseJson(fileContent, ".Phases.Creation")); - prevGasCalculations.validation = - parseUintFromASCII(parseJson(fileContent, ".Phases.Validation")); - prevGasCalculations.execution = parseUintFromASCII(parseJson(fileContent, ".Phases.Execution")); - prevGasCalculations.arbitrum = parseUintFromASCII(parseJson(fileContent, ".Calldata.Arbitrum")); - prevGasCalculations.opStack = parseUintFromASCII(parseJson(fileContent, ".Calldata.OP-Stack")); -} - -/// @notice Parse a uint256 from ASCII. -/// @param ascii The ASCII to be parsed. -/// @return _ret The parsed uint256. -function parseUintFromASCII(bytes memory ascii) pure returns (uint256 _ret) { - bytes memory prevTotal; - uint256 offset = ascii.length > 32 ? 32 : 0; - for (uint256 i; i < ascii.length; i++) { - if (ascii[i] == 0x28) { - break; - } else { - if (i >= offset) { - prevTotal = abi.encodePacked(prevTotal, ascii[i]); - } - } - } - uint256 j = 1; - for (uint256 i = prevTotal.length - 1; i > 0; i--) { - if (uint8(prevTotal[i]) >= 48 && uint8(prevTotal[i]) <= 57) { - _ret += (uint8(prevTotal[i]) - 48) * j; - j *= 10; - } - } -} - -/// @notice Format the gas value. -/// @param prevValue The previous gas value. -/// @param newValue The new gas value. -/// @return formattedValue The formatted gas value. -function formatGasValue( - uint256 prevValue, - uint256 newValue -) - pure - returns (string memory formattedValue) -{ - if (prevValue == 0) { - formattedValue = string.concat(formatGas(int256(newValue)), " gas"); - } else { - formattedValue = string.concat( - formatGas(int256(newValue)), - " gas (diff: ", - formatGas(int256(newValue) - int256(prevValue)), - ")" - ); - } -} - -/// @notice Format the gas value with underscores for readability. -/// @param value The gas value to be formatted. -/// @return The formatted gas value. -function formatGas(int256 value) pure returns (string memory) { - string memory str = toString(value); - bytes memory bStr = bytes(str); - bytes memory result = new bytes(bStr.length + (bStr.length - 1) / 3); - - uint256 j = result.length; - for (uint256 i = 0; i < bStr.length; i++) { - if (i > 0 && i % 3 == 0) { - result[--j] = "_"; - } - result[--j] = bStr[bStr.length - i - 1]; - } - - return string(result); -} - -interface GasDebug { - function getGasConsumed(address account, uint256 phase) external view returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasParser.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasParser.sol deleted file mode 100644 index 5f5b6b1..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/GasParser.sol +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Utils -import "../Vm.sol"; -import "../Log.sol"; - -// Dependencies -import "./GasCalculations.sol"; -import { writeGasIdentifier } from "../Storage.sol"; - -library GasParser { - function parseAndWriteGas( - bytes memory userOpCalldata, - address entrypoint, - string memory gasIdentifier, - address sender, - uint256 totalUserOpGas - ) - internal - { - string memory fileName = string.concat("./gas_calculations/", gasIdentifier, ".json"); - - GasCalculations memory gasCalculations = GasCalculations({ - creation: GasDebug(entrypoint).getGasConsumed(sender, 0), - validation: GasDebug(entrypoint).getGasConsumed(sender, 1), - execution: GasDebug(entrypoint).getGasConsumed(sender, 2), - total: totalUserOpGas, - arbitrum: getArbitrumL1Gas(userOpCalldata), - opStack: getOpStackL1Gas(userOpCalldata) - }); - - GasCalculations memory prevGasCalculations; - - if (exists(fileName)) { - string memory fileContent = readFile(fileName); - prevGasCalculations = parsePrevGasReport(fileContent); - } - - string memory finalJson = - formatGasToWrite(gasIdentifier, prevGasCalculations, gasCalculations); - - writeJson(finalJson, fileName); - writeGasIdentifier(""); - } - - function formatGasToWrite( - string memory gasIdentifier, - GasCalculations memory prevGasCalculations, - GasCalculations memory gasCalculations - ) - internal - returns (string memory finalJson) - { - string memory jsonObj = string(abi.encodePacked(gasIdentifier)); - - // total gas used - serializeString( - jsonObj, - "Total", - formatGasValue({ prevValue: prevGasCalculations.total, newValue: gasCalculations.total }) - ); - - // ERC-4337 phases gas used - string memory phasesObj = "phases"; - serializeString( - phasesObj, - "Creation", - formatGasValue({ - prevValue: prevGasCalculations.creation, - newValue: gasCalculations.creation - }) - ); - serializeString( - phasesObj, - "Validation", - formatGasValue({ - prevValue: prevGasCalculations.validation, - newValue: gasCalculations.validation - }) - ); - string memory phasesOutput = serializeString( - phasesObj, - "Execution", - formatGasValue({ - prevValue: prevGasCalculations.execution, - newValue: gasCalculations.execution - }) - ); - - // L2-L1 calldata gas used - string memory l2sObj = "l2s"; - serializeString( - l2sObj, - "OP-Stack", - formatGasValue({ - prevValue: prevGasCalculations.opStack, - newValue: gasCalculations.opStack - }) - ); - string memory l2sOutput = serializeString( - l2sObj, - "Arbitrum", - formatGasValue({ - prevValue: prevGasCalculations.arbitrum, - newValue: gasCalculations.arbitrum - }) - ); - - serializeString(jsonObj, "Phases", phasesOutput); - finalJson = serializeString(jsonObj, "Calldata", l2sOutput); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/UserOpGasLog.sol b/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/UserOpGasLog.sol deleted file mode 100644 index 7da0b60..0000000 --- a/typescript/packages/account-modules/lib/modulekit/src/test/utils/gas/UserOpGasLog.sol +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Types -import { - PackedUserOperation, - EntryPointSimulations, - IEntryPointSimulations -} from "src/external/ERC4337.sol"; - -// Utils -import "../Log.sol"; - -contract UserOpGasLog { - EntryPointSimulations public immutable simulation = new EntryPointSimulations(); - - struct GasLog { - uint256 gasValidation; - uint256 gasExecution; - } - - mapping(bytes32 userOpHash => GasLog log) internal _log; - - function getLog(bytes32 userOpHash) - external - view - returns (uint256 gasValidation, uint256 gasExecution) - { - GasLog memory log = _log[userOpHash]; - return (log.gasValidation, log.gasExecution); - } - - function calcValidationGas( - PackedUserOperation memory userOp, - bytes32 userOpHash, - address, /* sender */ - bytes memory /* initCode */ - ) - external - returns (uint256 gasValidation) - { - IEntryPointSimulations.ValidationResult memory validationResult = - simulation.simulateValidation(userOp); - - gasValidation = validationResult.returnInfo.preOpGas; - - _log[userOpHash].gasValidation = gasValidation; - } - - function calcExecutionGas( - PackedUserOperation memory userOp, - bytes32 userOpHash, - address sender, - bytes memory initCode - ) - external - returns (uint256 gasExecution) - { - IEntryPointSimulations.ExecutionResult memory executionResult = - simulation.simulateHandleOp(userOp, sender, initCode); - - gasExecution = executionResult.paid; - // gasValidation = executionResult.gasUsedInValidation; - - // _log[userOpHash].gasValidation = executionResult.gasUsedInValidation; - _log[userOpHash].gasExecution = gasExecution; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/test/BaseTest.t.sol b/typescript/packages/account-modules/lib/modulekit/test/BaseTest.t.sol deleted file mode 100644 index fdb307d..0000000 --- a/typescript/packages/account-modules/lib/modulekit/test/BaseTest.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -import "forge-std/Test.sol"; -import "src/ModuleKit.sol"; -import "src/Accounts.sol"; -import "src/Mocks.sol"; -import { Execution } from "src/accounts/erc7579/lib/ExecutionLib.sol"; - -contract BaseTest is RhinestoneModuleKit, Test { - using ModuleKitHelpers for AccountInstance; - - AccountInstance internal instance; - AccountInstance internal instanceSafe; - - address recipient; - - function setUp() public virtual { - instance = makeAccountInstance("account1"); - - // MockValidator defaultValidator = new MockValidator(); - // MockExecutor defaultExecutor = new MockExecutor(); - vm.deal(instanceSafe.account, 1000 ether); - vm.deal(instance.account, 2 ether); - - recipient = makeAddr("recipient"); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/test/Diff.t.sol b/typescript/packages/account-modules/lib/modulekit/test/Diff.t.sol deleted file mode 100644 index f66e88a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/test/Diff.t.sol +++ /dev/null @@ -1,910 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -import "src/ModuleKit.sol"; -import "./BaseTest.t.sol"; -import "src/Mocks.sol"; -import { ExecutionReturnData } from "src/test/RhinestoneModuleKit.sol"; -import { - MODULE_TYPE_VALIDATOR, - MODULE_TYPE_EXECUTOR, - MODULE_TYPE_HOOK, - MODULE_TYPE_FALLBACK, - VALIDATION_SUCCESS, - VALIDATION_FAILED -} from "src/accounts/common/interfaces/IERC7579Module.sol"; -import { CALLTYPE_SINGLE } from "src/accounts/common/lib/ModeLib.sol"; -import { getAccountType, InstalledModule } from "src/test/utils/Storage.sol"; -import { toString } from "src/test/utils/Vm.sol"; -import { MockValidatorFalse } from "test/mocks/MockValidatorFalse.sol"; -import { MockK1Validator, VALIDATION_SUCCESS } from "test/mocks/MockK1Validator.sol"; -import { MockK1ValidatorUncompliantUninstall } from - "test/mocks/MockK1ValidatorUncompliantUninstall.sol"; -import { VmSafe } from "src/test/utils/Vm.sol"; -import { IAccountFactory } from "src/accounts/factory/interface/IAccountFactory.sol"; - -contract ERC7579DifferentialModuleKitLibTest is BaseTest { - using ModuleKitHelpers for *; - - MockValidator internal validator; - MockValidatorFalse internal validatorFalse; - MockExecutor internal executor; - MockFallback internal fallbackHandler; - MockHook internal hook; - MockTarget internal mockTarget; - - MockERC20 internal token; - address module; - - function setUp() public override { - super.setUp(); - // Setup account - instance = makeAccountInstance("account1"); - - // Setup modules - validator = new MockValidator(); - validatorFalse = new MockValidatorFalse(); - hook = new MockHook(); - executor = new MockExecutor(); - fallbackHandler = new MockFallback(); - mockTarget = new MockTarget(); - - // Setup aux - token = new MockERC20(); - token.initialize("Mock Token", "MTK", 18); - deal(address(token), instance.account, 100 ether); - vm.deal(instance.account, 1000 ether); - instance.simulateUserOp(false); - } - - function test_transfer() public { - UserOpData memory data = instance.exec({ target: recipient, value: 1 ether, callData: "" }); - assertTrue(data.userOpHash != ""); - assertTrue(recipient.balance == 1 ether); - assertTrue(data.userOp.sender == instance.account); - } - - /*////////////////////////////////////////////////////////////////////////// - make instance - //////////////////////////////////////////////////////////////////////////*/ - - function test_makeAccountInstance() public { - AccountInstance memory newInstance = makeAccountInstance("newSalt"); - assertTrue(newInstance.account.code.length == 0); - newInstance.deployAccount(); - assertTrue(newInstance.account.code.length > 0); - } - - function test_makeAccountInstance_withModules() public { - AccountType env = ModuleKitHelpers.getAccountType(); - // AccountInstance memory newInstance = makeAccountInstance("newSalt"); - // assertTrue(newInstance.account.code.length == 0); - // newInstance.deployAccount(); - // assertTrue(newInstance.account.code.length > 0); - // Deploy executors, validators, hooks and fallbacks and setup ModuleInit data - IAccountFactory.ModuleInitData[] memory validators = new IAccountFactory.ModuleInitData[](1); - validators[0] = - IAccountFactory.ModuleInitData({ module: address(validator), data: abi.encode(0x123) }); - IAccountFactory.ModuleInitData[] memory executors = new IAccountFactory.ModuleInitData[](1); - executors[0] = IAccountFactory.ModuleInitData({ - module: address(executor), - data: env == AccountType.KERNEL ? abi.encodePacked(bytes20(0)) : abi.encodePacked("") - }); - IAccountFactory.ModuleInitData memory _hook = IAccountFactory.ModuleInitData({ - module: address(hook), - data: env == AccountType.SAFE - ? abi.encode(bytes1(0), bytes4(0), abi.encode(0x123)) - : abi.encode(0x123) - }); - IAccountFactory.ModuleInitData[] memory fallbacks = new IAccountFactory.ModuleInitData[](1); - fallbacks[0] = IAccountFactory.ModuleInitData({ - module: address(fallbackHandler), - data: env == AccountType.KERNEL - ? abi.encodePacked( - bytes4(0), - bytes20(0), - abi.encode(abi.encodePacked(hex"00", "fallbackData"), abi.encodePacked("")) - ) - : env == AccountType.SAFE || env == AccountType.NEXUS - ? abi.encode(bytes4(0x12345678), bytes1(0), abi.encode(0x123)) - : abi.encode(0x123) - }); - // Create account instance - AccountInstance memory newInstance2 = makeAccountInstance({ - salt: "newSalt2", - validators: validators, - executors: executors, - hook: _hook, - fallbacks: fallbacks - }); - assertTrue(newInstance2.account.code.length == 0); - newInstance2.deployAccount(); - assertTrue(newInstance2.account.code.length > 0); - } - - /*////////////////////////////////////////////////////////////////////////// - exec - //////////////////////////////////////////////////////////////////////////*/ - - function testexec__Given__TwoInputs() public { - // Create userOperation fields - address receiver = makeAddr("receiver"); - uint256 value = 10 gwei; - bytes memory callData = - abi.encodeWithSignature("transfer(address,uint256)", receiver, value); - - // Create userOperation - instance.exec({ target: address(token), callData: callData }); - - // Validate userOperation - assertEq(token.balanceOf(receiver), value, "Receiver should have 10 gwei in tokens"); - } - - function testexec__Given__ThreeInputs() public { - // Create userOperation fields - address receiver = makeAddr("receiver"); - uint256 value = 10 gwei; - bytes memory callData = ""; - - // Create userOperation - instance.exec({ target: receiver, value: value, callData: callData }); - - // Validate userOperation - assertEq(receiver.balance, value, "Receiver should have 10 gwei"); - } - - function testexec__Given__FourInputs() public { - // Create userOperation fields - address receiver = makeAddr("receiver"); - uint256 value = 10 gwei; - bytes memory callData = ""; - // bytes memory signature = ""; - - // Create userOperation - ExecutionReturnData memory executionData = instance.getExecOps({ - target: receiver, - value: value, - callData: callData, - txValidator: address(instance.defaultValidator) - }).execUserOps(); - - // Validate Logs - assertTrue(executionData.logs.length >= 5); - - // Validate userOperation - assertEq(receiver.balance, value, "Receiver should have 10 gwei"); - } - - function testexec__RevertWhen__ValidationFails() public { - // No revert reason - _revertWhen__ValidationFails(""); - - // Revert selector - _revertWhen__ValidationFails(abi.encodePacked(bytes4(0x220266b6))); - - // Revert message - _revertWhen__ValidationFails( - abi.encodeWithSignature("FailedOp(uint256,string)", 0, "AA24 signature error") - ); - } - - function testexec__RevertWhen__ValidationReverts() public { - // No revert reason - _revertWhen__ValidationReverts(""); - - // Revert message - bytes memory revertMessage; - - AccountType env = ModuleKitHelpers.getAccountType(); - - // Revert selector - _revertWhen__ValidationReverts( - abi.encodePacked(bytes4(env == AccountType.SAFE ? 0xacfdb444 : 0x0)) - ); - - if (env == AccountType.SAFE) { - revertMessage = abi.encodePacked(bytes4(0xacfdb444)); - } else { - revertMessage = abi.encodePacked(bytes4(0x0)); - } - - _revertWhen__ValidationReverts(revertMessage); - } - - function testexec__RevertWhen__UserOperationFails() public { - // Deploy the account first - testexec__Given__TwoInputs(); - - // No revert reason - _revertWhen__UserOperationFails(""); - - bytes memory revertSelector; - bytes memory revertMessage; - - AccountType env = ModuleKitHelpers.getAccountType(); - if (env == AccountType.SAFE) { - revertSelector = abi.encodePacked(bytes4(0xacfdb444)); - revertMessage = abi.encodePacked(bytes4(0xacfdb444)); - } else if (env == AccountType.KERNEL) { - revertSelector = abi.encodePacked(bytes4(0xf21e646b)); - revertMessage = abi.encodePacked(bytes4(0xf21e646b)); - } else { - revertSelector = abi.encodePacked(bytes4(0x82b42900)); - revertMessage = abi.encodePacked(bytes4(0x82b42900)); - } - - // Revert selector - _revertWhen__UserOperationFails(revertSelector); - - // Revert message - _revertWhen__UserOperationFails(revertMessage); - } - - /*////////////////////////////////////////////////////////////////////////// - MODULES - //////////////////////////////////////////////////////////////////////////*/ - - function testAddValidator() public { - address newValidator = address(new MockValidator()); - address newValidator1 = address(new MockValidator()); - vm.label(newValidator, "2nd validator"); - - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: newValidator, - data: "" - }); - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: newValidator1, - data: "" - }); - - bool validatorEnabled = instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, newValidator); - assertTrue(validatorEnabled); - bool validator1Enabled = instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, newValidator1); - assertTrue(validator1Enabled); - } - - function test_getInstalledModules() public whenEnvIsNotKernel { - address newValidator = address(new MockValidator()); - address newValidator1 = address(new MockValidator()); - vm.label(newValidator, "2nd validator"); - - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: newValidator, - data: "" - }); - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: newValidator1, - data: "" - }); - - // Assert installed modules - this._getModulesAndAssert( - abi.encode( - 2, [newValidator, newValidator1], [MODULE_TYPE_VALIDATOR, MODULE_TYPE_VALIDATOR] - ), - instance - ); - - address newExecutor = address(new MockExecutor()); - instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: newExecutor, data: "" }); - - // Assert installed modules - this._getModulesAndAssert( - abi.encode( - 3, - [newValidator, newValidator1, newExecutor], - [MODULE_TYPE_VALIDATOR, MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR] - ), - instance - ); - } - - function test_getInstalledModules_DifferentInstances() public whenEnvIsNotKernel { - address newValidator = address(new MockValidator()); - address newValidator1 = address(new MockValidator()); - vm.label(newValidator, "2nd validator"); - - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: newValidator, - data: "" - }); - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: newValidator1, - data: "" - }); - - // Assert installed modules - this._getModulesAndAssert( - abi.encode( - 2, [newValidator, newValidator1], [MODULE_TYPE_VALIDATOR, MODULE_TYPE_VALIDATOR] - ), - instance - ); - - address newExecutor = address(new MockExecutor()); - instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: newExecutor, data: "" }); - - // Assert installed modules - this._getModulesAndAssert( - abi.encode( - 3, - [newValidator, newValidator1, newExecutor], - [MODULE_TYPE_VALIDATOR, MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR] - ), - instance - ); - - // Deploy new instance using current env - AccountInstance memory newInstance = makeAccountInstance("newSalt"); - assertTrue(newInstance.account.code.length == 0); - newInstance.deployAccount(); - assertTrue(newInstance.account.code.length > 0); - - // Install modules on new instance - newInstance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: newValidator, - data: "" - }); - newInstance.installModule({ - moduleTypeId: MODULE_TYPE_EXECUTOR, - module: newExecutor, - data: "" - }); - - // Assert installed modules on new instance - this._getModulesAndAssert( - abi.encode( - 2, [newValidator, newExecutor], [MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR] - ), - newInstance - ); - - // Old instance modules should still be the same - this._getModulesAndAssert( - abi.encode( - 3, - [newValidator, newValidator1, newExecutor], - [MODULE_TYPE_VALIDATOR, MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR] - ), - instance - ); - } - - function test_getInstalledModules_AfterUninstall() public whenEnvIsNotKernel { - address newValidator = address(new MockValidator()); - address newValidator1 = address(new MockValidator()); - vm.label(newValidator, "2nd validator"); - - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: newValidator, - data: "" - }); - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: newValidator1, - data: "" - }); - - // Assert installed modules - this._getModulesAndAssert( - abi.encode( - 2, [newValidator, newValidator1], [MODULE_TYPE_VALIDATOR, MODULE_TYPE_VALIDATOR] - ), - instance - ); - - address newExecutor = address(new MockExecutor()); - instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: newExecutor, data: "" }); - - // Assert installed modules - this._getModulesAndAssert( - abi.encode( - 3, // length - [newValidator, newValidator1, newExecutor], // expectedAddresses - [MODULE_TYPE_VALIDATOR, MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR] // expectedTypes - ), - instance - ); - - // Uninstall module - instance.uninstallModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: newValidator, - data: "" - }); - - // Assert installed modules - this._getModulesAndAssert( - abi.encode( - 2, [newValidator1, newExecutor], [MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR] - ), - instance - ); - } - - function testRemoveValidator() public { - address newValidator = address(new MockValidator()); - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: newValidator, - data: "" - }); - bool validatorEnabled = instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, newValidator); - assertTrue(validatorEnabled); - - instance.uninstallModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: newValidator, - data: "" - }); - validatorEnabled = instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, newValidator); - assertFalse(validatorEnabled); - } - - function testAddExecutor() public { - address newExecutor = address(new MockExecutor()); - - instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: newExecutor, data: "" }); - bool executorEnabled = instance.isModuleInstalled(MODULE_TYPE_EXECUTOR, newExecutor); - assertTrue(executorEnabled); - } - - function testRemoveExecutor() public { - address newExecutor = address(new MockExecutor()); - - instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: newExecutor, data: "" }); - bool executorEnabled = instance.isModuleInstalled(MODULE_TYPE_EXECUTOR, newExecutor); - assertTrue(executorEnabled); - - instance.uninstallModule({ - moduleTypeId: MODULE_TYPE_EXECUTOR, - module: newExecutor, - data: "" - }); - executorEnabled = instance.isModuleInstalled(MODULE_TYPE_EXECUTOR, newExecutor); - assertFalse(executorEnabled); - } - - function testAddHook() public { - instance.installModule({ moduleTypeId: MODULE_TYPE_HOOK, module: address(hook), data: "" }); - - bool hookEnabled = instance.isModuleInstalled(MODULE_TYPE_HOOK, address(hook)); - assertTrue(hookEnabled); - } - - function testRemoveHook() public { - instance.installModule({ moduleTypeId: MODULE_TYPE_HOOK, module: address(hook), data: "" }); - - bool hookEnabled = instance.isModuleInstalled(MODULE_TYPE_HOOK, address(hook)); - assertTrue(hookEnabled); - - instance.uninstallModule({ moduleTypeId: MODULE_TYPE_HOOK, module: address(hook), data: "" }); - hookEnabled = instance.isModuleInstalled(MODULE_TYPE_HOOK, address(hook)); - assertFalse(hookEnabled); - } - - function testAddFallback() public { - bytes memory fallbackData = abi.encode(bytes4(keccak256("foo()")), CALLTYPE_SINGLE, ""); - - instance.installModule({ - moduleTypeId: MODULE_TYPE_FALLBACK, - module: address(fallbackHandler), - data: fallbackData - }); - - bool fallbackEnabled = - instance.isModuleInstalled(MODULE_TYPE_FALLBACK, address(fallbackHandler), fallbackData); - assertTrue(fallbackEnabled); - } - - function testRemoveFallback() public { - bytes memory fallbackData = abi.encode(bytes4(keccak256("foo()")), CALLTYPE_SINGLE, ""); - - instance.installModule({ - moduleTypeId: MODULE_TYPE_FALLBACK, - module: address(fallbackHandler), - data: fallbackData - }); - - bool fallbackEnabled = - instance.isModuleInstalled(MODULE_TYPE_FALLBACK, address(fallbackHandler), fallbackData); - assertTrue(fallbackEnabled); - - instance.uninstallModule({ - moduleTypeId: MODULE_TYPE_FALLBACK, - module: address(fallbackHandler), - data: fallbackData - }); - fallbackEnabled = - instance.isModuleInstalled(MODULE_TYPE_FALLBACK, address(fallbackHandler), fallbackData); - assertFalse(fallbackEnabled); - } - - /*////////////////////////////////////////////////////////////////////////// - UTILS - //////////////////////////////////////////////////////////////////////////*/ - - function testGetUserOpHash() public { - // Create userOperation fields - address receiver = makeAddr("receiver"); - uint256 value = 10 gwei; - bytes memory callData = abi.encode(true); - - // Create userOperation hash using lib - UserOpData memory userOpData = instance.getExecOps({ - target: receiver, - value: value, - callData: callData, - txValidator: address(instance.defaultValidator) - }); - bytes32 entryPointUserOpHash = instance.aux.entrypoint.getUserOpHash(userOpData.userOp); - - // Validate userOperation - assertEq(userOpData.userOpHash, entryPointUserOpHash); - } - - function testDeployAccount() public { - AccountInstance memory newInstance = makeAccountInstance("new"); - assertTrue(newInstance.account.code.length == 0); - - newInstance.deployAccount(); - - assertTrue(newInstance.account.code.length > 0); - } - - function testWriteGas() public { - string memory gasIdentifier = "testWriteGas"; - string memory rootDir = "gas_calculations"; - string memory fileName = string.concat(rootDir, "/", gasIdentifier, ".json"); - assertTrue(vm.isDir("gas_calculations")); - if (vm.isFile(fileName)) { - vm.removeFile(fileName); - } - assertFalse(vm.isFile(fileName)); - - vm.setEnv("GAS", "true"); - - instance.log4337Gas("testWriteGas"); - testexec__Given__TwoInputs(); - assertTrue(vm.isFile(fileName)); - } - - function testSimulateUserOp() public { - instance.simulateUserOp(true); - testexec__Given__TwoInputs(); - } - - function testERC1271() public { - bytes32 unformattedHash = keccak256("test"); - - bool isValid = instance.isValidSignature({ - validator: address(instance.defaultValidator), - hash: unformattedHash, - signature: bytes("test") - }); - assertTrue(isValid); - } - - function testUsingAccountEnv() public { - string[] memory envs = new string[](6); - envs[0] = "DEFAULT"; - envs[1] = "SAFE"; - envs[2] = "KERNEL"; - envs[3] = "NEXUS"; - envs[4] = "CUSTOM"; - envs[5] = "INVALID"; - - for (uint256 i = 0; i < envs.length; i++) { - string memory env = envs[i]; - if (keccak256(abi.encodePacked(env)) == keccak256(abi.encodePacked("INVALID"))) { - vm.expectRevert(ModuleKitHelpers.InvalidAccountType.selector); - this._usingAccountEnv(env); - } else { - _usingAccountEnv(env); - } - } - } - - function testUsingAccountEnv_ModuleKitUninitialized() public { - isInit[block.chainid] = false; - _usingAccountEnv("DEFAULT"); - } - - function testSetAccountEnv() public { - // Deploy using current env - AccountInstance memory oldEnvInstance = makeAccountInstance("sameSalt"); - assertTrue(oldEnvInstance.account.code.length == 0); - oldEnvInstance.deployAccount(); - assertTrue(oldEnvInstance.account.code.length > 0); - - // Load env - (bytes32 envHash) = getAccountType(); - - // Switch env - string memory newEnv = envHash == keccak256(abi.encodePacked("KERNEL")) ? "SAFE" : "KERNEL"; - instance.setAccountEnv(newEnv); - - // Deploy using new env - AccountInstance memory newEnvInstance = makeAccountInstance("sameSalt"); - assertTrue(newEnvInstance.account.code.length == 0); - newEnvInstance.deployAccount(); - assertTrue(newEnvInstance.account.code.length > 0); - } - - function testSetAccountEnv_RevertsWhen_InvalidAccountType() public { - vm.expectRevert(ModuleKitHelpers.InvalidAccountType.selector); - this.callSetAccountENVInvalid(); - } - - /*////////////////////////////////////////////////////////////// - HELPERS - //////////////////////////////////////////////////////////////*/ - - function callSetAccountENVInvalid() public { - instance.setAccountEnv("INVALID"); - } - - function _usingAccountEnv(string memory env) public usingAccountEnv(env.toAccountType()) { - AccountInstance memory newInstance = makeAccountInstance(keccak256(abi.encode(env))); - assertTrue(newInstance.account.code.length == 0); - - newInstance.deployAccount(); - - assertTrue(newInstance.account.code.length > 0); - } - - function _getModulesAndAssert( - bytes calldata expectedResultBytes, - AccountInstance memory _instance - ) - public - view - { - InstalledModule[] memory modules = _instance.getInstalledModules(); - // Parse length - uint256 length = abi.decode(expectedResultBytes[0:32], (uint256)); - // Parse addresses and types - address[] memory expectedAddresses = new address[](length); - uint256[] memory expectedTypes = new uint256[](length); - for (uint256 i = 0; i < length; i++) { - expectedAddresses[i] = - abi.decode(expectedResultBytes[32 + i * 32:64 + i * 32], (address)); - expectedTypes[i] = abi.decode( - expectedResultBytes[32 + length * 32 + i * 32:64 + length * 32 + i * 32], (uint256) - ); - } - // Assert expected modules length - assertTrue( - modules.length == length + (instance.getAccountType() == AccountType.SAFE ? 1 : 0) - ); - // AccountType.SAFE has 1 extra module added during setup, skip it - uint256 index = instance.getAccountType() == AccountType.SAFE ? 1 : 0; - for (uint256 i = 0; i < length; i++) { - assertTrue(modules[index + i].moduleAddress == expectedAddresses[i]); - assertTrue(modules[index + i].moduleType == expectedTypes[i]); - } - } - - function test_verifyModuleStorageWasCleared() public { - // Set simulate mode to false - instance.simulateUserOp(false); - // Install a module - module = address(new MockK1Validator()); - // Start state diff recording - instance.startStateDiffRecording(); - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: module, - data: abi.encode(instance.account) - }); - // Uninstall the module - instance.uninstallModule({ moduleTypeId: MODULE_TYPE_VALIDATOR, module: module, data: "" }); - // Stop state diff recording - VmSafe.AccountAccess[] memory accountAccesses = instance.stopAndReturnStateDiff(); - // Assert that the module storage was cleared - instance.verifyModuleStorageWasCleared(accountAccesses, module); - } - - function test_verifyModuleStorageWasCleared_RevertsWhen_NotCleared_UsingComplianceFlag() - public - { - // Set simulate mode to false - instance.simulateUserOp(false); - // Set compliance flag - instance.storageCompliance(true); - - // Install a module - module = address(new MockK1ValidatorUncompliantUninstall()); - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: module, - data: abi.encode(0xffffffffffffffffffff) - }); - // Assert module storage - assertEq( - address(0xffffffffffffffffffff), - MockK1Validator(module).smartAccountOwners(address(instance.account)) - ); - // Expect revert - vm.expectRevert(); - this.__revertWhen_verifyModuleStorageWasCleared_NotCleared(); - } - - function test_verifyModuleStorageWasCleared_RevertsWhen_NotCleared() public { - // Set simulate mode to false - instance.simulateUserOp(false); - // Install a module - module = address(new MockK1ValidatorUncompliantUninstall()); - // Start state diff recording - instance.startStateDiffRecording(); - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: module, - data: abi.encode(0xffffffffffffffffffff) - }); - // Assert module storage - assertEq( - address(0xffffffffffffffffffff), - MockK1Validator(module).smartAccountOwners(address(instance.account)) - ); - // Uninstall the module - instance.uninstallModule({ moduleTypeId: MODULE_TYPE_VALIDATOR, module: module, data: "" }); - // Stop state diff recording - VmSafe.AccountAccess[] memory accountAccesses = instance.stopAndReturnStateDiff(); - // Expect revert - vm.expectRevert(); - // Assert that the module storage was cleared - this.callVerifyStorageWasNotCleared(instance, module, accountAccesses); - } - - function __revertWhen_verifyModuleStorageWasCleared_NotCleared() public { - // Uninstall - instance.uninstallModule({ moduleTypeId: MODULE_TYPE_VALIDATOR, module: module, data: "" }); - } - - function test_withModuleStorageClearValidation() - public - withModuleStorageClearValidation(instance, module) - { - // Set simulate mode to false - instance.simulateUserOp(false); - // Install a module - module = address(new MockK1Validator()); - // Install the module - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: module, - data: abi.encode(VALIDATION_FAILED) - }); - // Uninstall the module - instance.uninstallModule({ moduleTypeId: MODULE_TYPE_VALIDATOR, module: module, data: "" }); - } - - /*////////////////////////////////////////////////////////////// - EXPECT REVERT - //////////////////////////////////////////////////////////////*/ - - function _revertWhen__ValidationFails(bytes memory revertReason) public { - // Create userOperation fields - address receiver = makeAddr("receiver"); - uint256 value = 10 gwei; - bytes memory callData = ""; - - if (!instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, address(validatorFalse))) { - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: address(validatorFalse), - data: "" - }); - } - - // Expect the revert - if (revertReason.length == 0) { - instance.expect4337Revert(); - } else if (revertReason.length == 4) { - instance.expect4337Revert(bytes4(revertReason)); - } else { - instance.expect4337Revert(revertReason); - } - - // Create userOperation - instance.getExecOps({ - target: receiver, - value: value, - callData: callData, - txValidator: address(validatorFalse) - }).execUserOps(); - } - - function _revertWhen__ValidationReverts(bytes memory revertReason) public { - address revertingValidator = makeAddr("revertingValidator"); - - if (!instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, revertingValidator)) { - vm.etch(revertingValidator, address(validator).code); - - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: revertingValidator, - data: "" - }); - - vm.etch(revertingValidator, hex"fd"); - } - - // Create userOperation fields - address receiver = makeAddr("receiver"); - uint256 value = 10 gwei; - bytes memory callData = ""; - - // Expect the revert - if (revertReason.length == 0) { - instance.expect4337Revert(); - } else if (revertReason.length == 4) { - instance.expect4337Revert(bytes4(revertReason)); - } else { - instance.expect4337Revert(revertReason); - } - - // Create userOperation - instance.getExecOps({ - target: receiver, - value: value, - callData: callData, - txValidator: revertingValidator - }).execUserOps(); - } - - function _revertWhen__UserOperationFails(bytes memory revertReason) public { - // Create userOperation fields - bytes memory callData = abi.encodeWithSelector(MockTarget.setAccessControl.selector, 2); - - // Expect the revert - if (revertReason.length == 0) { - instance.expect4337Revert(); - } else if (revertReason.length == 4) { - instance.expect4337Revert(bytes4(revertReason)); - } else { - instance.expect4337Revert(revertReason); - } - - // Create userOperation - instance.exec({ target: address(mockTarget), callData: callData, value: 0 }); - } - - /*////////////////////////////////////////////////////////////// - MODIFIERS - //////////////////////////////////////////////////////////////*/ - - // Used to skip tests when env is kernel as they don't emit events on module installation - modifier whenEnvIsNotKernel() { - AccountType env = ModuleKitHelpers.getAccountType(); - if (env == AccountType.KERNEL) { - return; - } - _; - } - - /*////////////////////////////////////////////////////////////// - HELPERS - //////////////////////////////////////////////////////////////*/ - - function callVerifyStorageWasNotCleared( - AccountInstance memory _instance, - address _module, - VmSafe.AccountAccess[] memory _accountAccesses - ) - public - view - { - _instance.verifyModuleStorageWasCleared(_accountAccesses, _module); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/test/GasCalculationsTest.sol b/typescript/packages/account-modules/lib/modulekit/test/GasCalculationsTest.sol deleted file mode 100644 index 9984ce7..0000000 --- a/typescript/packages/account-modules/lib/modulekit/test/GasCalculationsTest.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "ds-test/test.sol"; -import "src/test/utils/gas/GasCalculations.sol"; - -contract GasCalculationsTest is DSTest { - function test_formatGasValue() public { - uint256 prevValue = 37_054; - uint256 newValue = 187_170; - - string memory result = formatGasValue(prevValue, newValue); - - // Log the result - emit log_named_string("Result", result); - } - - function test_formatGas() public { - int256 value = 2_550_948; - - string memory result = formatGas(value); - - // Log the result - emit log_named_string("Result", result); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/test/RegistryDeployer.t.sol b/typescript/packages/account-modules/lib/modulekit/test/RegistryDeployer.t.sol deleted file mode 100644 index cc3c506..0000000 --- a/typescript/packages/account-modules/lib/modulekit/test/RegistryDeployer.t.sol +++ /dev/null @@ -1,203 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -import "./BaseTest.t.sol"; -import { - RegistryDeployer, - REGISTRY_ADDR, - ResolverUID, - SchemaUID, - ModuleRecord, - ModuleType -} from "src/deployment/registry/RegistryDeployer.sol"; -import { MockValidator } from "src/Mocks.sol"; - -contract RegistryDeployerTest is RegistryDeployer, BaseTest { - uint256 internal mainnetFork; - uint256 internal testnetFork; - - function setUp() public override { - super.setUp(); - - string memory MAINNET_RPC_URL = vm.envString("MAINNET_RPC_URL"); - mainnetFork = vm.createFork(MAINNET_RPC_URL); - - string memory TESTNET_RPC_URL = vm.envString("TESTNET_RPC_URL"); - testnetFork = vm.createFork(TESTNET_RPC_URL); - } - - function testDeployModule() public onMainnet { - // Setup module bytecode, deploy params, and data - bytes memory initCode = type(MockValidator).creationCode; - bytes32 salt = bytes32(0); - bytes memory metadata = hex"41414141414141"; - bytes memory resolverContext = ""; - - // Deploy module - address module = deployModule({ - initCode: initCode, - salt: salt, - metadata: metadata, - resolverContext: resolverContext - }); - - assertEq(module, predictModuleAddress({ salt: salt, initCode: initCode })); - assertGt(module.code.length, 0); - - ModuleRecord memory moduleRecord = findModule(module); - assertEq(ResolverUID.unwrap(moduleRecord.resolverUID), ResolverUID.unwrap(resolverUID)); - assertEq(moduleRecord.metadata, metadata); - } - - function testDeployModuleViaFactory() public onMainnet { - bytes32 salt = bytes32(0); - address factory = address(this); - bytes memory callOnFactory = abi.encodeCall(this.deploy, (salt)); - bytes memory metadata = hex"41414141414141"; - bytes memory resolverContext = ""; - - address module = deployModuleViaFactory({ - factory: factory, - callOnFactory: callOnFactory, - metadata: metadata, - resolverContext: resolverContext - }); - - assertEq(module, predictAddress(salt)); - assertGt(module.code.length, 0); - - ModuleRecord memory moduleRecord = findModule(module); - assertEq(ResolverUID.unwrap(moduleRecord.resolverUID), ResolverUID.unwrap(resolverUID)); - assertEq(moduleRecord.metadata, metadata); - } - - function testRegisterModule() public onMainnet { - address module = address(new MockValidator()); - - ModuleRecord memory moduleRecord = findModule(module); - assertEq(ResolverUID.unwrap(moduleRecord.resolverUID), bytes32(0)); - assertEq(moduleRecord.metadata, ""); - - bytes memory metadata = hex"41414141414141"; - bytes memory resolverContext = ""; - - registerModule({ module: module, metadata: metadata, resolverContext: resolverContext }); - - moduleRecord = findModule(module); - assertEq(ResolverUID.unwrap(moduleRecord.resolverUID), ResolverUID.unwrap(resolverUID)); - assertEq(moduleRecord.metadata, metadata); - } - - function testMockAttestModule() public onTestnet { - deployModule(); - - bytes memory initCode = type(MockValidator).creationCode; - bytes32 salt = bytes32(0); - - address module = predictModuleAddress({ salt: salt, initCode: initCode }); - - bytes memory attestationData = hex"41414141414141"; - ModuleType[] memory moduleTypes = new ModuleType[](1); - moduleTypes[0] = ModuleType.wrap(1); - - mockAttestToModule({ - module: module, - attestationData: attestationData, - moduleTypes: moduleTypes - }); - - assertTrue(isModuleAttestedMock(module)); - } - - function testFindResolver() public onMainnet { - ResolverUID _resolverUID = findResolver(); - assertEq(ResolverUID.unwrap(_resolverUID), ResolverUID.unwrap(resolverUID)); - } - - function testRegisterResolver() public onMainnet { - ResolverUID _resolverUID = registerResolver(address(this)); - setResolverUID(_resolverUID); - findResolver(); - } - - function testFindSchema() public onMainnet { - SchemaUID _schemaUID = findSchema(); - assertEq(SchemaUID.unwrap(_schemaUID), SchemaUID.unwrap(schemaUID)); - } - - function testRegisterSchema() public onMainnet { - SchemaUID _schemaUID = registerSchema({ schema: "schema", validator: address(this) }); - setSchemaUID(_schemaUID); - findSchema(); - } - - /*////////////////////////////////////////////////////////////////////////// - INTERNAL - //////////////////////////////////////////////////////////////////////////*/ - - function deployModule() internal { - // Setup module bytecode, deploy params, and data - bytes memory initCode = type(MockValidator).creationCode; - bytes32 salt = bytes32(0); - bytes memory metadata = hex"41414141414141"; - bytes memory resolverContext = ""; - - // Deploy module - address module = deployModule({ - initCode: initCode, - salt: salt, - metadata: metadata, - resolverContext: resolverContext - }); - - assertEq(module, predictModuleAddress({ salt: salt, initCode: initCode })); - assertGt(module.code.length, 0); - - ModuleRecord memory moduleRecord = findModule(module); - assertEq(ResolverUID.unwrap(moduleRecord.resolverUID), ResolverUID.unwrap(resolverUID)); - assertEq(moduleRecord.metadata, metadata); - } - - /*////////////////////////////////////////////////////////////////////////// - MODIFIERS - //////////////////////////////////////////////////////////////////////////*/ - - modifier onMainnet() { - vm.selectFork(mainnetFork); - vm.rollFork(20_626_383); - _; - } - - modifier onTestnet() { - vm.selectFork(testnetFork); - vm.rollFork(6_586_870); - _; - } - - /*////////////////////////////////////////////////////////////////////////// - CALLBACKS - //////////////////////////////////////////////////////////////////////////*/ - - function deploy(bytes32 salt) external returns (address) { - return address(new MockValidator{ salt: salt }()); - } - - function predictAddress(bytes32 salt) public view returns (address) { - bytes32 hash = keccak256( - abi.encodePacked( - bytes1(0xff), address(this), salt, keccak256(type(MockValidator).creationCode) - ) - ); - return address(uint160(uint256(hash))); - } - - function supportsInterface( - bytes4 // interfaceID - ) - external - pure - returns (bool) - { - return true; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/test/integrations/ExampleFactory.t.sol b/typescript/packages/account-modules/lib/modulekit/test/integrations/ExampleFactory.t.sol deleted file mode 100644 index f61374a..0000000 --- a/typescript/packages/account-modules/lib/modulekit/test/integrations/ExampleFactory.t.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -import { BaseTest } from "test/BaseTest.t.sol"; -import { IERC7579Account } from "src/accounts/common/interfaces/IERC7579Account.sol"; -import { IERC7579Bootstrap } from "src/accounts/erc7579/interfaces/IERC7579Bootstrap.sol"; -import { ExampleFactory } from "src/integrations/registry/ExampleFactory.sol"; -import { ModuleKitHelpers } from "src/ModuleKit.sol"; -import { IStakeManager } from "src/external/ERC4337.sol"; -import { ENTRYPOINT_ADDR } from "src/deployment/predeploy/EntryPoint.sol"; -import { getHelper } from "src/test/utils/Storage.sol"; -import { AccountType } from "src/test/RhinestoneModuleKit.sol"; -import { ERC7579Precompiles } from "src/deployment/precompiles/ERC7579Precompiles.sol"; - -contract ExampleFactoryTest is BaseTest, ERC7579Precompiles { - using ModuleKitHelpers for *; - - IERC7579Account implementation; - IERC7579Bootstrap bootstrap; - ExampleFactory factory; - - function setUp() public override { - super.setUp(); - - implementation = deployERC7579Account(); - vm.label(address(implementation), "AccountSingleton"); - bootstrap = deployERC7579Bootstrap(); - vm.label(address(bootstrap), "Bootstrap"); - address[] memory trustedAttesters = new address[](2); - trustedAttesters[0] = makeAddr("attester1"); - trustedAttesters[1] = makeAddr("attester2"); - uint8 threshold = 2; - - factory = new ExampleFactory( - address(implementation), - address(bootstrap), - address(instance.aux.registry), - trustedAttesters, - threshold - ); - vm.label(address(factory), "ExampleFactory"); - - vm.deal(address(factory), 10 ether); - vm.prank(address(factory)); - IStakeManager(ENTRYPOINT_ADDR).addStake{ value: 10 ether }(100_000); - } - - function test_createAccount() public { - address account = - factory.createAccount(keccak256("1"), address(instance.defaultValidator), ""); - assertTrue(account != address(0)); - assertEq(IERC7579Account(payable(account)).accountId(), "uMSA.advanced/withHook.v0.1"); - } - - function test_userOpFlow() public { - bytes32 salt = bytes32(bytes("newAccount")); - address account = factory.getAddress(salt, address(instance.defaultValidator), ""); - bytes memory initCode = factory.getInitCode(salt, address(instance.defaultValidator), ""); - address erc7579Helper = ModuleKitHelpers.getHelper(AccountType.DEFAULT); - - instance = makeAccountInstance({ - salt: salt, - helper: erc7579Helper, - account: account, - initCode: initCode - }); - - address target = makeAddr("target"); - uint256 value = 1 ether; - - instance.exec({ target: target, value: value, callData: "" }); - - assertTrue(target.balance == value); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/test/integrations/SmartSession.t.sol b/typescript/packages/account-modules/lib/modulekit/test/integrations/SmartSession.t.sol deleted file mode 100644 index 5131bdd..0000000 --- a/typescript/packages/account-modules/lib/modulekit/test/integrations/SmartSession.t.sol +++ /dev/null @@ -1,405 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -// Constants -import { MODULE_TYPE_VALIDATOR } from "src/accounts/common/interfaces/IERC7579Module.sol"; - -// Libraries -import { ModuleKitHelpers, AccountInstance } from "src/ModuleKit.sol"; -import { ecdsaSign } from "src/Helpers.sol"; - -// Mocks -import { MockPolicy, MockTarget } from "src/Mocks.sol"; -import { MockK1Validator } from "test/mocks/MockK1Validator.sol"; - -// Tests -import { BaseTest } from "../BaseTest.t.sol"; - -// Types -import { - PermissionId, - PolicyData, - ActionData, - ERC7739Data, - Session, - ISessionValidator -} from "src/integrations/interfaces/ISmartSession.sol"; -import { Execution } from "src/accounts/erc7579/lib/ExecutionLib.sol"; -import { UserOpData, PackedUserOperation } from "src/test/RhinestoneModuleKit.sol"; - -/// @dev Tests for smart session integration within the RhinestoneModuleKit -contract SmartSessionTest is BaseTest { - /*////////////////////////////////////////////////////////////// - LIBRARIES - //////////////////////////////////////////////////////////////*/ - - using ModuleKitHelpers for AccountInstance; - using ModuleKitHelpers for UserOpData; - - /*////////////////////////////////////////////////////////////// - VARIABLES - //////////////////////////////////////////////////////////////*/ - - // @dev A policy contract that allows any action - MockPolicy mockPolicy; - // @@dev A mock target contract - MockTarget target; - // @dev Owner account - Account owner; - - /*////////////////////////////////////////////////////////////// - SETUP - //////////////////////////////////////////////////////////////*/ - - function setUp() public override { - super.setUp(); - // Deploy mock policy - mockPolicy = new MockPolicy(); - // Set the policy to allow any action - mockPolicy.setValidationData(address(instance.account), 0); - // Deploy mock target - target = new MockTarget(); - } - - /*////////////////////////////////////////////////////////////// - TESTS - //////////////////////////////////////////////////////////////*/ - - function test_isModuleType() public view { - // Check if the module type is correct - assertTrue( - auxiliary.smartSession.isModuleType(1) // ERC7579_MODULE_TYPE_VALIDATOR; - ); - } - - function test_installModule() public { - // Check if the module is not installed - assertFalse( - instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, address(auxiliary.smartSession)) - ); - // Install a module - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: address(auxiliary.smartSession), - data: "" - }); - // Check if the module is installed - assertTrue( - instance.isModuleInstalled(MODULE_TYPE_VALIDATOR, address(auxiliary.smartSession)) - ); - } - - function test_addSession() public { - // Add a session - PermissionId permissionIds = instance.addSession({ - salt: bytes32("salt1"), - userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), - erc7739Policy: _getEmptyERC7739Data( - "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) - ), - actionDatas: _getEmptyActionDatas( - address(target), MockTarget.set.selector, address(mockPolicy) - ) - }); - // Check if the session is enabled - assertTrue(instance.isPermissionEnabled(permissionIds)); - } - - function test_addSession_preInstalled() public { - // Install smart session - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: address(auxiliary.smartSession), - data: "" - }); - // Add a session - PermissionId permissionIds = instance.addSession({ - salt: bytes32("salt1"), - userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), - erc7739Policy: _getEmptyERC7739Data( - "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) - ), - actionDatas: _getEmptyActionDatas( - address(target), MockTarget.set.selector, address(mockPolicy) - ) - }); - // Check if the session is enabled - assertTrue(instance.isPermissionEnabled(permissionIds)); - } - - function test_removeSession() public { - // Add a session - PermissionId permissionIds = instance.addSession({ - salt: bytes32("salt1"), - userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), - erc7739Policy: _getEmptyERC7739Data( - "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) - ), - actionDatas: _getEmptyActionDatas( - address(target), MockTarget.set.selector, address(mockPolicy) - ) - }); - // Check if the session is enabled - assertTrue(instance.isPermissionEnabled(permissionIds)); - // Remove the session - instance.removeSession(permissionIds); - // Check if the session is disabled - assertFalse(instance.isPermissionEnabled(permissionIds)); - } - - function test_getPermissionId() public { - // Setup session data - Session memory session = Session({ - sessionValidator: ISessionValidator(address(instance.defaultSessionValidator)), - salt: "mockSalt", - sessionValidatorInitData: "mockInitData", - userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), - erc7739Policies: _getEmptyERC7739Data( - "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) - ), - actions: _getEmptyActionDatas(address(target), MockTarget.set.selector, address(mockPolicy)) - }); - - // Add a session - PermissionId permissionIds = instance.addSession({ session: session }); - // Get the permission id - PermissionId permissionId = instance.getPermissionId(session); - - // Check if the permission id is correct - assertTrue(permissionIds == permissionId); - } - - function test_useSession() public { - // Setup calldata to execute - bytes memory callData = abi.encodeWithSelector(MockTarget.set.selector, (1337)); - - // Setup session data - Session memory session = Session({ - sessionValidator: ISessionValidator(address(instance.defaultSessionValidator)), - salt: "mockSalt", - sessionValidatorInitData: "mockInitData", - userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), - erc7739Policies: _getEmptyERC7739Data( - "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) - ), - actions: _getEmptyActionDatas(address(target), MockTarget.set.selector, address(mockPolicy)) - }); - - // Use the session - instance.useSession(session, address(target), 0, /* value */ callData); - - // Check if the value was set - assertTrue(target.value() == 1337); - } - - function test_useSession_batchExecutions() public { - // Setup calldata to execute multiple operations - bytes memory callData1 = abi.encodeWithSelector(MockTarget.set.selector, (1337)); - bytes memory callData2 = abi.encodeWithSelector(MockTarget.set.selector, (7331)); - - // Create executions array - Execution[] memory executions = new Execution[](2); - executions[0] = Execution({ target: address(target), value: 0, callData: callData1 }); - executions[1] = Execution({ target: address(target), value: 0, callData: callData2 }); - - // Setup session data - Session memory session = Session({ - sessionValidator: ISessionValidator(address(instance.defaultSessionValidator)), - salt: "mockSalt", - sessionValidatorInitData: "mockInitData", - userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), - erc7739Policies: _getEmptyERC7739Data( - "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) - ), - actions: _getEmptyActionDatas(address(target), MockTarget.set.selector, address(mockPolicy)) - }); - - // Use the session with multiple executions - instance.useSession(session, executions); - - // Check if the second execution's value was set (since it was the last one) - assertEq(target.value(), 7331, "Target value should be set to last execution value"); - } - - function test_encodeSignatureEnableMode() public { - // Deploy MockK1Validator - MockK1Validator mockK1Validator = new MockK1Validator(); - - // Make an owner - owner = makeAccount("owner"); - - // Install validator - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: address(mockK1Validator), - data: abi.encode(owner.addr) - }); - - // Install smart session - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: address(auxiliary.smartSession), - data: "" - }); - - // Setup calldata to execute - bytes memory callData = abi.encodeWithSelector(MockTarget.set.selector, (1337)); - - // Get exec user ops - UserOpData memory userOpData = instance.getExecOps({ - target: address(target), - value: 0, - callData: callData, - txValidator: address(instance.defaultValidator) - }); - - // Setup session data - Session memory session = Session({ - sessionValidator: ISessionValidator(address(instance.defaultSessionValidator)), - salt: "mockSalt", - sessionValidatorInitData: "mockInitData", - userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), - erc7739Policies: _getEmptyERC7739Data( - "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) - ), - actions: _getEmptyActionDatas(address(target), MockTarget.set.selector, address(mockPolicy)) - }); - - // Get enable mode signature - bytes memory signature = instance.encodeSignatureEnableMode( - userOpData.userOp, session, _signWithOwner, address(mockK1Validator) - ); - - // Update the user op signature - userOpData.userOp.signature = signature; - - // Execute user ops - userOpData.execUserOps(); - } - - function test_encodeSignatureUnsafeEnableMode() public { - // Deploy MockK1Validator - MockK1Validator mockK1Validator = new MockK1Validator(); - - // Make an owner - owner = makeAccount("owner"); - - // Install validator - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: address(mockK1Validator), - data: abi.encode(owner.addr) - }); - - // Install smart session - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: address(auxiliary.smartSession), - data: "" - }); - - // Setup calldata to execute - bytes memory callData = abi.encodeWithSelector(MockTarget.set.selector, (1337)); - - // Get exec user ops - UserOpData memory userOpData = instance.getExecOps({ - target: address(target), - value: 0, - callData: callData, - txValidator: address(instance.defaultValidator) - }); - - // Setup session data - Session memory session = Session({ - sessionValidator: ISessionValidator(address(instance.defaultSessionValidator)), - salt: "mockSalt", - sessionValidatorInitData: "mockInitData", - userOpPolicies: _getEmptyPolicyDatas(address(mockPolicy)), - erc7739Policies: _getEmptyERC7739Data( - "mockContent", _getEmptyPolicyDatas(address(mockPolicy)) - ), - actions: _getEmptyActionDatas(address(target), MockTarget.set.selector, address(mockPolicy)) - }); - - // Get enable mode signature - bytes memory signature = instance.encodeSignatureUnsafeEnableMode( - userOpData.userOp, session, _signWithOwner, address(mockK1Validator) - ); - - // Update the user op signature - userOpData.userOp.signature = signature; - - // Execute user ops - userOpData.execUserOps(); - } - - /*////////////////////////////////////////////////////////////// - HELPERS - //////////////////////////////////////////////////////////////*/ - - function _signWithOwner(bytes32 hash) internal view returns (bytes memory) { - // Sign the hash with the owner - bytes memory signature = ecdsaSign(owner.key, hash); - // Return the signature - return signature; - } - - function _getEmptyPolicyDatas(address policyContract) - internal - pure - returns (PolicyData[] memory policyDatas) - { - policyDatas = new PolicyData[](1); - policyDatas[0] = _getEmptyPolicyData(policyContract); - } - - function _getEmptyPolicyData(address policyContract) - internal - pure - returns (PolicyData memory) - { - return PolicyData({ policy: policyContract, initData: "" }); - } - - function _getEmptyActionData( - address actionTarget, - bytes4 actionSelector, - address policyContract - ) - internal - pure - returns (ActionData memory) - { - return ActionData({ - actionTargetSelector: actionSelector, - actionTarget: actionTarget, - actionPolicies: _getEmptyPolicyDatas(policyContract) - }); - } - - function _getEmptyActionDatas( - address actionTarget, - bytes4 actionSelector, - address policyContract - ) - internal - pure - returns (ActionData[] memory actionDatas) - { - actionDatas = new ActionData[](1); - actionDatas[0] = _getEmptyActionData(actionTarget, actionSelector, policyContract); - } - - function _getEmptyERC7739Data( - string memory content, - PolicyData[] memory erc1271Policies - ) - internal - pure - returns (ERC7739Data memory) - { - string[] memory contents = new string[](1); - contents[0] = content; - return ERC7739Data({ allowedERC7739Content: contents, erc1271Policies: erc1271Policies }); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/test/integrations/SwapTest.t.sol b/typescript/packages/account-modules/lib/modulekit/test/integrations/SwapTest.t.sol deleted file mode 100644 index 8b20338..0000000 --- a/typescript/packages/account-modules/lib/modulekit/test/integrations/SwapTest.t.sol +++ /dev/null @@ -1,103 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -import "test/BaseTest.t.sol"; -import "src/ModuleKit.sol"; -import { ERC7579ExecutorBase } from "src/Modules.sol"; -import { IERC20 } from "forge-std/interfaces/IERC20.sol"; -import { UniswapV3Integration } from "src/integrations/uniswap/v3/Uniswap.sol"; - -contract TestUniswap is BaseTest { - using ModuleKitHelpers for AccountInstance; - using UniswapV3Integration for *; - - IERC20 tokenA; - IERC20 tokenB; - MockERC20 mockTokenA; - MockERC20 mockTokenB; - - uint256 amountIn = 100_000_000; // Example: 100 tokens of tokenA - uint32 slippage = 1; // 0.1% slippage - - address internal constant USDC_HOLDER = 0x4B16c5dE96EB2117bBE5fd171E4d203624B014aa; // account - // with USDC holdings - address internal constant WETH_HOLDER = 0x57757E3D981446D585Af0D9Ae4d7DF6D64647806; // account - // with WETH holdings - - address constant USDC_ADDRESS = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; - address constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; - - function setUp() public override { - string memory MAINNET_RPC_URL = vm.envString("MAINNET_RPC_URL"); - vm.createSelectFork(MAINNET_RPC_URL); - vm.rollFork(20_426_591); - instance = makeAccountInstance("account1"); - assertTrue(instance.account != address(0)); - - tokenA = IERC20(USDC_ADDRESS); - tokenB = IERC20(WETH_ADDRESS); - - _fundAccountWithTokenA(amountIn); - vm.deal(instance.account, 1 ether); - assertTrue(instance.account.balance == 1 ether); - instance.simulateUserOp(false); - } - - function _fundAccountWithTokenA(uint256 amount) internal { - vm.startPrank(USDC_HOLDER); - bool success = tokenA.transfer(instance.account, amount); - require(success, "Failed to transfer tokenA to account"); - vm.stopPrank(); - } - - function testApproveAndSwap() public { - address poolAddress = UniswapV3Integration.getPoolAddress(address(tokenA), address(tokenB)); - uint160 sqrtPriceX96 = UniswapV3Integration.getSqrtPriceX96(poolAddress); - - uint256 priceRatio = UniswapV3Integration.sqrtPriceX96toPriceRatio(sqrtPriceX96); - - UniswapV3Integration.priceRatioToPrice(priceRatio, poolAddress, address(tokenA)); - - bool swapToken0to1 = UniswapV3Integration.checkTokenOrder(address(tokenA), poolAddress); - - uint256 priceRatioLimit; - if (swapToken0to1) { - priceRatioLimit = (priceRatio * (1000 - slippage)) / 1000; - } else { - priceRatioLimit = (priceRatio * (1000 + slippage)) / 1000; - } - - UniswapV3Integration.priceRatioToPrice(priceRatioLimit, poolAddress, address(tokenA)); - - uint160 sqrtPriceLimitX96 = UniswapV3Integration.priceRatioToSqrtPriceX96(priceRatioLimit); - - uint256 initialAccountBalanceA = tokenA.balanceOf(instance.account); - uint256 initialAccountBalanceB = tokenB.balanceOf(instance.account); - - Execution[] memory swap = UniswapV3Integration.approveAndSwap( - instance.account, tokenA, tokenB, amountIn, sqrtPriceLimitX96 - ); - - for (uint256 i = 0; i < swap.length; i++) { - instance.exec({ - target: swap[i].target, - value: swap[i].value, - callData: swap[i].callData - }); - } - - uint256 finalAccountBalanceA = tokenA.balanceOf(instance.account); - uint256 finalAccountBalanceB = tokenB.balanceOf(instance.account); - - sqrtPriceX96 = UniswapV3Integration.getSqrtPriceX96(poolAddress); - - require( - finalAccountBalanceA < initialAccountBalanceA, - "Token A balance in account did not decrease" - ); - require( - finalAccountBalanceB > initialAccountBalanceB, - "Token B balance in account did not increase" - ); - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1Validator.sol b/typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1Validator.sol deleted file mode 100644 index 07c2e5e..0000000 --- a/typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1Validator.sol +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -import { - IValidator, - VALIDATION_SUCCESS, - VALIDATION_FAILED, - MODULE_TYPE_VALIDATOR -} from "src/accounts/common/interfaces/IERC7579Module.sol"; -import { PackedUserOperation } from "src/external/ERC4337.sol"; -import { ECDSA } from "solady/utils/ECDSA.sol"; -import { SignatureCheckerLib } from "solady/utils/SignatureCheckerLib.sol"; -import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; -import { EIP1271_MAGIC_VALUE, IERC1271 } from "src/module-bases/interfaces/IERC1271.sol"; - -contract MockK1Validator is IValidator { - bytes4 constant ERC1271_INVALID = 0xffffffff; - mapping(address => address) public smartAccountOwners; - - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) - external - payable - returns (uint256 validation) - { - return ECDSA.recover(MessageHashUtils.toEthSignedMessageHash(userOpHash), userOp.signature) - == smartAccountOwners[msg.sender] ? VALIDATION_SUCCESS : VALIDATION_FAILED; - } - - function isValidSignatureWithSender( - address, - bytes32 hash, - bytes calldata signature - ) - external - view - returns (bytes4) - { - return ECDSA.recover(MessageHashUtils.toEthSignedMessageHash(hash), signature) - == smartAccountOwners[msg.sender] ? EIP1271_MAGIC_VALUE : ERC1271_INVALID; - } - - function onInstall(bytes calldata data) external { - address owner = abi.decode(data, (address)); - smartAccountOwners[msg.sender] = owner; - } - - function onUninstall(bytes calldata data) external { - data; - delete smartAccountOwners[msg.sender]; - } - - function isModuleType(uint256 moduleTypeId) external pure returns (bool) { - return moduleTypeId == MODULE_TYPE_VALIDATOR; - } - - function isOwner(address account, address owner) external view returns (bool) { - return smartAccountOwners[account] == owner; - } - - function isInitialized(address) external pure returns (bool) { - return false; - } - - function getOwner(address account) external view returns (address) { - return smartAccountOwners[account]; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1ValidatorUncompliantUninstall.sol b/typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1ValidatorUncompliantUninstall.sol deleted file mode 100644 index 5c0f16c..0000000 --- a/typescript/packages/account-modules/lib/modulekit/test/mocks/MockK1ValidatorUncompliantUninstall.sol +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -import { - IValidator, - VALIDATION_SUCCESS, - VALIDATION_FAILED, - MODULE_TYPE_VALIDATOR -} from "src/accounts/common/interfaces/IERC7579Module.sol"; -import { PackedUserOperation } from "src/external/ERC4337.sol"; -import { ECDSA } from "solady/utils/ECDSA.sol"; -import { SignatureCheckerLib } from "solady/utils/SignatureCheckerLib.sol"; -import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; -import { EIP1271_MAGIC_VALUE, IERC1271 } from "src/module-bases/interfaces/IERC1271.sol"; - -contract MockK1ValidatorUncompliantUninstall is IValidator { - bytes4 constant ERC1271_INVALID = 0xffffffff; - mapping(address => address) public smartAccountOwners; - - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) - external - payable - returns (uint256 validation) - { - return ECDSA.recover(MessageHashUtils.toEthSignedMessageHash(userOpHash), userOp.signature) - == smartAccountOwners[msg.sender] ? VALIDATION_SUCCESS : VALIDATION_FAILED; - } - - function isValidSignatureWithSender( - address, - bytes32 hash, - bytes calldata signature - ) - external - view - returns (bytes4) - { - return ECDSA.recover(MessageHashUtils.toEthSignedMessageHash(hash), signature) - == smartAccountOwners[msg.sender] ? EIP1271_MAGIC_VALUE : ERC1271_INVALID; - } - - function onInstall(bytes calldata data) external { - address owner = abi.decode(data, (address)); - smartAccountOwners[msg.sender] = owner; - } - - function onUninstall(bytes calldata data) external pure { - data; - } - - function isModuleType(uint256 moduleTypeId) external pure returns (bool) { - return moduleTypeId == MODULE_TYPE_VALIDATOR; - } - - function isOwner(address account, address owner) external view returns (bool) { - return smartAccountOwners[account] == owner; - } - - function isInitialized(address) external pure returns (bool) { - return false; - } - - function getOwner(address account) external view returns (address) { - return smartAccountOwners[account]; - } -} diff --git a/typescript/packages/account-modules/lib/modulekit/test/mocks/MockValidatorFalse.sol b/typescript/packages/account-modules/lib/modulekit/test/mocks/MockValidatorFalse.sol deleted file mode 100644 index e255952..0000000 --- a/typescript/packages/account-modules/lib/modulekit/test/mocks/MockValidatorFalse.sol +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.23 <0.9.0; - -/* solhint-disable no-unused-vars */ -import { ERC7579StatelessValidatorBase } from "src/Modules.sol"; -import { ERC7579ValidatorBase } from "src/Modules.sol"; -import { PackedUserOperation } from "src/external/ERC4337.sol"; - -contract MockValidatorFalse is ERC7579StatelessValidatorBase, ERC7579ValidatorBase { - function onInstall(bytes calldata data) external virtual override { } - - function onUninstall(bytes calldata data) external virtual override { } - - function validateUserOp( - PackedUserOperation calldata, // userOp - bytes32 // userOpHash - ) - external - virtual - override - returns (ValidationData) - { - return _packValidationData({ sigFailed: true, validUntil: type(uint48).max, validAfter: 0 }); - } - - function isValidSignatureWithSender( - address, // sender - bytes32, // hash - bytes calldata // signature - ) - external - view - virtual - override - returns (bytes4) - { - return EIP1271_FAILED; - } - - function isModuleType(uint256 typeID) external pure override returns (bool) { - return typeID == TYPE_VALIDATOR; - } - - function isInitialized( - address // smartAccount - ) - external - pure - returns (bool) - { - return false; - } - - function validateSignatureWithData( - bytes32, - bytes calldata, - bytes calldata - ) - external - pure - override - returns (bool validSig) - { - return false; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.changeset/config.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/.changeset/config.json deleted file mode 100644 index 66794fa..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.changeset/config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$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/typescript/packages/account-modules/lib/openzeppelin-contracts/.codecov.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.codecov.yml deleted file mode 100644 index 4cec4ef..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.codecov.yml +++ /dev/null @@ -1,16 +0,0 @@ -comment: off -github_checks: - annotations: false -coverage: - status: - patch: - default: - target: 95% - only_pulls: true - project: - default: - threshold: 1% -ignore: - - "test" - - "contracts/mocks" - - "contracts/vendor" diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.editorconfig b/typescript/packages/account-modules/lib/openzeppelin-contracts/.editorconfig deleted file mode 100644 index f162e8d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.editorconfig +++ /dev/null @@ -1,21 +0,0 @@ -# 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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/bug_report.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 35ad097..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 4018cef..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,4 +0,0 @@ -contact_links: - - name: Questions & Support Requests - url: https://forum.openzeppelin.com/c/support/contracts/18 - about: Ask in the OpenZeppelin Forum diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/feature_request.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index ff596b0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 2394518..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,20 +0,0 @@ - - - - - -Fixes #???? - - - - - -#### PR Checklist - - - - - -- [ ] Tests -- [ ] Documentation -- [ ] Changeset entry (run `npx changeset add`) diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml deleted file mode 100644 index 78c286c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Compare gas costs -description: Compare gas costs between branches -inputs: - token: - description: GitHub token, required to access GitHub API - required: true - report: - description: Path to the report to compare - required: false - default: gasReporterOutput.json - out_report: - description: Path to save the output report - required: false - default: ${{ github.ref_name }}.gasreport.json - ref_report: - description: Path to the reference report for comparison - 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@v4 - with: - name: gasreport - overwrite: true - path: ${{ inputs.out_report }} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/setup/action.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/setup/action.yml deleted file mode 100644 index 3c5fc60..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/setup/action.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Setup -description: Common environment setup - -runs: - using: composite - steps: - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - 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: stable diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/storage-layout/action.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/storage-layout/action.yml deleted file mode 100644 index fb68d5f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/actions/storage-layout/action.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Compare storage layouts -description: Compare storage layouts between branches -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@v4 - with: - name: layout - overwrite: true - path: ${{ inputs.out_layout }} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/actionlint.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/actionlint.yml deleted file mode 100644 index 3e42c8a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/actionlint.yml +++ /dev/null @@ -1,18 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/changeset.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/changeset.yml deleted file mode 100644 index efc5c53..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/changeset.yml +++ /dev/null @@ -1,28 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/checks.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/checks.yml deleted file mode 100644 index 6aca7f3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/checks.yml +++ /dev/null @@ -1,132 +0,0 @@ -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=8192 - -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 - # Needed for "eth-gas-reporter" to produce a "gasReporterOutput.json" as documented in - # https://github.com/cgewecke/eth-gas-reporter/blob/v0.2.27/docs/gasReporterOutput.md - CI: true - 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 pragma consistency between files - run: npm run test:pragma - - name: Check procedurally 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@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 pragma consistency between files - run: npm run test:pragma - - name: Check storage layout - uses: ./.github/actions/storage-layout - 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 -vvv - - coverage: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up environment - uses: ./.github/actions/setup - - name: Run coverage - run: npm run coverage - - uses: codecov/codecov-action@v5 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - - harnesses: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up environment - uses: ./.github/actions/setup - - name: Compile harnesses - run: | - make -C certora apply - npm run compile:harnesses - - slither: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up environment - uses: ./.github/actions/setup - - uses: crytic/slither-action@v0.4.1 - - codespell: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Run CodeSpell - uses: codespell-project/actions-codespell@v2.1 - with: - check_hidden: true - check_filenames: true - skip: package-lock.json,*.pdf,vendor diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/docs.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/docs.yml deleted file mode 100644 index 04b8131..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/docs.yml +++ /dev/null @@ -1,19 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/formal-verification.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/formal-verification.yml deleted file mode 100644 index 86acca7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/formal-verification.yml +++ /dev/null @@ -1,86 +0,0 @@ -name: formal verification - -on: - pull_request: - types: - - opened - - reopened - - synchronize - - labeled - workflow_dispatch: {} - -env: - PIP_VERSION: '3.11' - 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@v5 - with: - python-version: ${{ env.PIP_VERSION }} - cache: 'pip' - cache-dependency-path: 'fv-requirements.txt' - - name: Install python packages - run: pip install -r fv-requirements.txt - - name: Install java - uses: actions/setup-java@v4 - 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 }} - - halmos: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up environment - uses: ./.github/actions/setup - - name: Install python - uses: actions/setup-python@v5 - with: - python-version: ${{ env.PIP_VERSION }} - cache: 'pip' - cache-dependency-path: 'fv-requirements.txt' - - name: Install python packages - run: pip install -r fv-requirements.txt - - name: Run Halmos - run: halmos --match-test '^symbolic|^testSymbolic' -vv diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/release-cycle.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/release-cycle.yml deleted file mode 100644 index 02d5478..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/release-cycle.yml +++ /dev/null @@ -1,214 +0,0 @@ -# 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@v7 - 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@v7 - 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@v7 - 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@v7 - 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 - id-token: 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@v4 - 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 }} - NPM_CONFIG_PROVENANCE: true - - name: Create Github Release - uses: actions/github-script@v7 - 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 - uses: actions/download-artifact@v4 - 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@v7 - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/upgradeable.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/upgradeable.yml deleted file mode 100644 index 46bf15a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.github/workflows/upgradeable.yml +++ /dev/null @@ -1,34 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/.gitignore b/typescript/packages/account-modules/lib/openzeppelin-contracts/.gitignore deleted file mode 100644 index 50f1bf5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.gitignore +++ /dev/null @@ -1,67 +0,0 @@ -*.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 - -# macOS -.DS_Store - -# IntelliJ IDE -.idea - -# docs artifacts -docs/modules/api -build/site - -# 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/typescript/packages/account-modules/lib/openzeppelin-contracts/.gitmodules b/typescript/packages/account-modules/lib/openzeppelin-contracts/.gitmodules deleted file mode 100644 index 4939cd2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.gitmodules +++ /dev/null @@ -1,10 +0,0 @@ -[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 -[submodule "lib/halmos-cheatcodes"] - path = lib/halmos-cheatcodes - url = https://github.com/a16z/halmos-cheatcodes diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.husky/pre-commit b/typescript/packages/account-modules/lib/openzeppelin-contracts/.husky/pre-commit deleted file mode 100755 index 4738b05..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.husky/pre-commit +++ /dev/null @@ -1,2 +0,0 @@ -npm run test:generation -npx lint-staged diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.mocharc.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/.mocharc.js deleted file mode 100644 index 920662d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.mocharc.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - require: 'hardhat/register', - timeout: 4000, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.prettierrc b/typescript/packages/account-modules/lib/openzeppelin-contracts/.prettierrc deleted file mode 100644 index 39c004c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.prettierrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "printWidth": 120, - "singleQuote": true, - "trailingComma": "all", - "arrowParens": "avoid", - "overrides": [ - { - "files": "*.sol", - "options": { - "singleQuote": false - } - } - ], - "plugins": ["prettier-plugin-solidity"] -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/.solcover.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/.solcover.js deleted file mode 100644 index f079998..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/.solcover.js +++ /dev/null @@ -1,21 +0,0 @@ -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, - }, - // Work around stack too deep for coverage - configureYulOptimizer: true, - solcOptimizerDetails: { - yul: true, - yulDetails: { - optimizerSteps: '', - }, - }, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/CHANGELOG.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/CHANGELOG.md deleted file mode 100644 index c608394..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/CHANGELOG.md +++ /dev/null @@ -1,1278 +0,0 @@ -# Changelog - - -## 5.4.0 (2025-07-17) - -### Breaking changes - -- Update minimum pragma to 0.8.24 in `SignatureChecker`, `Governor` and Governor's extensions. ([#5716](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5716)). - -### Pragma changes - -- Reduced pragma requirement of interface files - -### Changes by category - -#### Account - -- `Account`: Added a simple ERC-4337 account implementation with minimal logic to process user operations. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657)) -- `AccountERC7579`: Extension of `Account` that implements support for ERC-7579 modules of type executor, validator, and fallback handler. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657)) -- `AccountERC7579Hooked`: Extension of `AccountERC7579` that implements support for ERC-7579 hook modules. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657)) -- `EIP7702Utils`: Add a library for checking if an address has an EIP-7702 delegation in place. ([#5587](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5587)) -- `IERC7821`, `ERC7821`: Interface and logic for minimal batch execution. No support for additional `opData` is included. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657)) - -#### Governance - -- `GovernorNoncesKeyed`: Extension of `Governor` that adds support for keyed nonces when voting by sig. ([#5574](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5574)) - -#### Tokens - -- `ERC20Bridgeable`: Implementation of ERC-7802 that makes an ERC-20 compatible with crosschain bridges. ([#5739](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5739)) - -#### Cryptography - -##### Signers - -- `AbstractSigner`, `SignerECDSA`, `SignerP256`, and `SignerRSA`: Add an abstract contract and various implementations for contracts that deal with signature verification. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657)) -- `SignerERC7702`: Implementation of `AbstractSigner` for Externally Owned Accounts (EOAs). Useful with ERC-7702. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657)) -- `SignerERC7913`: Abstract signer that verifies signatures using the ERC-7913 workflow. ([#5659](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5659)) -- `MultiSignerERC7913`: Implementation of `AbstractSigner` that supports multiple ERC-7913 signers with a threshold-based signature verification system. ([#5659](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5659)) -- `MultiSignerERC7913Weighted`: Extension of `MultiSignerERC7913` that supports assigning different weights to each signer, enabling more flexible governance schemes. ([#5741](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5741)) - -##### Verifiers - -- `ERC7913P256Verifier` and `ERC7913RSAVerifier`: Ready to use ERC-7913 verifiers that implement key verification for P256 (secp256r1) and RSA keys. ([#5659](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5659)) - -##### Other - -- `SignatureChecker`: Add support for ERC-7913 signatures alongside existing ECDSA and ERC-1271 signature verification. ([#5659](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5659)) -- `ERC7739`: An abstract contract to validate signatures following the rehashing scheme from `ERC7739Utils`. ([#5664](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5664)) -- `ERC7739Utils`: Add a library that implements a defensive rehashing mechanism to prevent replayability of smart contract signatures based on the ERC-7739. ([#5664](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5664)) - -#### Structures - -- `EnumerableMap`: Add support for `BytesToBytesMap` type. ([#5658](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5658)) -- `EnumerableMap`: Add `keys(uint256,uint256)` that returns a subset (slice) of the keys in the map. ([#5713](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5713)) -- `EnumerableSet`: Add support for `StringSet` and `BytesSet` types. ([#5658](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5658)) -- `EnumerableSet`: Add `values(uint256,uint256)` that returns a subset (slice) of the values in the set. ([#5713](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5713)) - -#### Utils - -- `Arrays`: Add `unsafeAccess`, `unsafeMemoryAccess` and `unsafeSetLength` for `bytes[]` and `string[]`. ([#5568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5568)) -- `Blockhash`: Add a library that provides access to historical block hashes using EIP-2935's history storage, extending the standard 256-block limit to 8191 blocks. ([#5642](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5642)) -- `Bytes`: Fix `lastIndexOf(bytes,byte,uint256)` with empty buffers and finite position to correctly return `type(uint256).max` instead of accessing uninitialized memory sections. ([#5797](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5797)) - -## 5.3.0 (2025-04-09) - -### Breaking Changes - -- Replace `GovernorCountingOverridable.VoteReceipt` struct parameter member names `hasOverriden` and `overridenWeight` for `hasOverridden` and `overriddenWeight` respectively. - -#### Custom error changes - -- Replace `GovernorAlreadyOverridenVote` with `GovernorAlreadyOverriddenVote`. -- Replace `GovernorOnlyProposer` with `GovernorUnableToCancel`. - -### Changes by category - -#### Account - -- `ERC4337Utils`: Update the `hash` function to call `getUserOpHash` on the specified entrypoint and add an `ENTRYPOINT_V08` constant. ([#5614](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5614)) -- `ERC7579Utils`: Add ABI decoding checks on calldata bounds within `decodeBatch`. ([#5371](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5371)) -- `ERC7579Utils`: Replace `address(0)` with `address(this)` during execution for calldata compression efficiency. ([#5614](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5614)) - -#### Governance - -- `IGovernor`: Add the `getProposalId` function to the governor interface. ([#5290](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5290)) -- `GovernorProposalGuardian`: Add a governance extension that defines a proposal guardian who can cancel proposals at any stage in their lifecycle. ([#5303](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5303)) -- `GovernorSequentialProposalId`: Adds a `Governor` extension that sequentially numbers proposal ids instead of using the hash. ([#5290](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5290)) -- `GovernorSuperQuorum`: Add a governance extension to support a super quorum. Proposals that meet the super quorum (and have a majority of for votes) advance to the `Succeeded` state before the proposal deadline. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) -- `GovernorVotesSuperQuorumFraction`: Add a variant of the `GovernorSuperQuorum` extensions where the super quorum is expressed as a fraction of the total supply. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) -- `TimelockController`: Receive function is now virtual. ([#5509](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5509)) - -#### Structures - -- `EnumerableSet`: Add `clear` function to EnumerableSets which deletes all values in the set. ([#5486](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5486)) -- `EnumerableMap`: Add `clear` function to EnumerableMaps which deletes all entries in the map. ([#5486](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5486)) -- `MerkleTree`: Add an update function that replaces a previously inserted leaf with a new value, updating the tree root along the way. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) - -#### Tokens - -- `ERC4626`: Use the `asset` getter in `totalAssets`, `_deposit` and `_withdraw`. ([#5322](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5322)) -- `IERC6909`: Add the interface for ERC-6909. ([#5343](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5343)) -- `ERC6909`: Add a standard implementation of ERC6909. ([#5394](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5394)) -- `ERC6909TokenSupply`: Add an extension of ERC6909 which tracks total supply for each token id. ([#5394](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5394)) -- `ERC6909Metadata`: Add an extension of ERC6909 which adds metadata functionality. ([#5394](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5394)) -- `ERC6909ContentURI`: Add an extension of ERC6909 which adds content URI functionality. ([#5394](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5394)) -- `SafeERC20`: Add `trySafeTransfer` and `trySafeTransferFrom` that do not revert and return false if the transfer is not successful. ([#5483](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5483)) - -#### Other - -- `Address`: bubble up revert data on `sendValue` failed call. ([#5379](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5379)) -- `Calldata`: Library with `emptyBytes` and `emptyString` functions to generate empty `bytes` and `string` calldata types. ([#5422](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5422)) -- `ERC2771Forwarder`: Expose the `_isTrustedByTarget` internal function to check whether a target trusts the forwarder. ([#5416](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5416)) -- `Hashes`: Expose `efficientKeccak256` for hashing non-commutative pairs of bytes32 without allocating extra memory. ([#5442](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5442)) -- `Initializable`: Add `_initializableStorageSlot` function that returns a pointer to the storage struct. The function allows customizing with a custom storage slot with an `override`. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) -- `Math`: Add `add512`, `mul512` and `mulShr`. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) -- `Math`: Add saturating arithmetic operations `saturatingAdd`, `saturatingSub` and `saturatingMul`. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) -- `MessageHashUtils`: Add `toDataWithIntendedValidatorHash(address, bytes32)`. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) -- `P256`: Adjust precompile detection in `verifyNative` to consider empty `returndata` on invalid verification. Previously, invalid signatures would've reverted with a `MissingPrecompile` error in chains with RIP-7212 support. ([#5620](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5620)) -- `Pausable`: Stop explicitly setting `paused` to `false` during construction. ([#5448](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5448)) -- `Strings`: Add `espaceJSON` that escapes special characters in JSON strings. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526)) - -## 5.2.0 (2025-01-08) - -### Breaking Changes - -#### Custom error changes - -This version comes with changes to the custom error identifiers. Contracts previously depending on the following errors should be replaced accordingly: - -- Replace `Errors.FailedCall` with a bubbled-up revert reason in `Address.sendValue`. - -### Changes by category - -#### General - -- Update some pragma directives to ensure that all file requirements match that of the files they import. ([#5273](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5273)) - -#### Account - -- `ERC4337Utils`: Add a reusable library to manipulate user operations and interact with ERC-4337 contracts ([#5274](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5274)) -- `ERC7579Utils`: Add a reusable library to interact with ERC-7579 modular accounts ([#5274](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5274)) - -#### Governance - -- `GovernorCountingOverridable`: Add a governor counting module that enables token holders to override the vote of their delegate. ([#5192](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5192)) -- `VotesExtended`: Create an extension of `Votes` which checkpoints balances and delegates. ([#5192](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5192)) - -### Proxy - -- `Clones`: Add `cloneWithImmutableArgs` and `cloneDeterministicWithImmutableArgs` variants that create clones with per-instance immutable arguments. The immutable arguments can be retrieved using `fetchCloneArgs`. The corresponding `predictDeterministicWithImmutableArgs` function is also included. ([#5109](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5109)) - -### Tokens - -- `ERC1363Utils`: Add helper similar to the existing `ERC721Utils` and `ERC1155Utils` ([#5133](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5133)) - -### Utils - -- `Address`: bubble up revert data on `sendValue` failed call ([#5418](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5418)) -- `Bytes`: Add a library of common operations that operate on `bytes` objects. ([#5252](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5252)) -- `CAIP2` and `CAIP10`: Add libraries for formatting and parsing CAIP-2 and CAIP-10 identifiers. ([#5252](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5252)) -- `NoncesKeyed`: Add a variant of `Nonces` that implements the ERC-4337 entrypoint nonce system. ([#5272](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5272)) -- `Packing`: Add variants for packing `bytes10` and `bytes22` ([#5274](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5274)) -- `Strings`: Add `parseUint`, `parseInt`, `parseHexUint` and `parseAddress` to parse strings into numbers and addresses. Also provide variants of these functions that parse substrings, and `tryXxx` variants that do not revert on invalid input. ([#5166](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5166)) - -## 5.1.0 (2024-10-17) - -### Breaking changes - -- `ERC1967Utils`: Removed duplicate declaration of the `Upgraded`, `AdminChanged` and `BeaconUpgraded` events. These events are still available through the `IERC1967` interface located under the `contracts/interfaces/` directory. Minimum pragma version is now 0.8.21. -- `Governor`, `GovernorCountingSimple`: The `_countVote` virtual function now returns an `uint256` with the total votes cast. This change allows for more flexibility for partial and fractional voting. Upgrading users may get a compilation error that can be fixed by adding a return statement to the `_countVote` function. - -#### Custom error changes - -This version comes with changes to the custom error identifiers. Contracts previously depending on the following errors should be replaced accordingly: - -- Replace `Address.FailedInnerCall` with `Errors.FailedCall` -- Replace `Address.AddressInsufficientBalance` with `Errors.InsufficientBalance` -- Replace `Clones.Create2InsufficientBalance` with `Errors.InsufficientBalance` -- Replace `Clones.ERC1167FailedCreateClone` with `Errors.FailedDeployment` -- Replace `Clones.Create2FailedDeployment` with `Errors.FailedDeployment` -- `SafeERC20`: Replace `Address.AddressEmptyCode` with `SafeERC20FailedOperation` if there is no code at the token's address. -- `SafeERC20`: Replace generic `Error(string)` with `SafeERC20FailedOperation` if the returned data can't be decoded as `bool`. -- `SafeERC20`: Replace generic `SafeERC20FailedOperation` with the revert message from the contract call if it fails. - -### Changes by category - -#### General - -- `AccessManager`, `VestingWallet`, `TimelockController` and `ERC2771Forwarder`: Added a public `initializer` function in their corresponding upgradeable variants. ([#5008](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5008)) - -#### Access - -- `AccessControlEnumerable`: Add a `getRoleMembers` method to return all accounts that have `role`. ([#4546](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4546)) -- `AccessManager`: Allow the `onlyAuthorized` modifier to restrict functions added to the manager. ([#5014](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5014)) - -#### Finance - -- `VestingWalletCliff`: Add an extension of the `VestingWallet` contract with an added cliff. ([#4870](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4870)) - -#### Governance - -- `GovernorCountingFractional`: Add a governor counting module that allows distributing voting power amongst 3 options (For, Against, Abstain). ([#5045](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5045)) -- `Votes`: Set `_moveDelegateVotes` visibility to internal instead of private. ([#5007](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5007)) - -#### Proxy - -- `Clones`: Add version of `clone` and `cloneDeterministic` that support sending value at creation. ([#4936](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4936)) -- `TransparentUpgradeableProxy`: Make internal `_proxyAdmin()` getter have `view` visibility. ([#4688](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4688)) -- `ProxyAdmin`: Fixed documentation for `UPGRADE_INTERFACE_VERSION` getter. ([#5031](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5031)) - -#### Tokens - -- `ERC1363`: Add implementation of the token payable standard allowing execution of contract code after transfers and approvals. ([#4631](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4631)) -- `ERC20TemporaryApproval`: Add an ERC-20 extension that implements temporary approval using transient storage, based on ERC7674 (draft). ([#5071](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5071)) -- `SafeERC20`: Add "relaxed" function for interacting with ERC-1363 functions in a way that is compatible with EOAs. ([#4631](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4631)) -- `SafeERC20`: Document risks of `safeIncreaseAllowance` and `safeDecreaseAllowance` when associated with ERC-7674. ([#5262](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5262)) -- `ERC721Utils` and `ERC1155Utils`: Add reusable libraries with functions to perform acceptance checks on `IERC721Receiver` and `IERC1155Receiver` implementers. ([#4845](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4845)) -- `ERC1363Utils`: Add helper similar to the existing ERC721Utils and ERC1155Utils. ([#5133](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5133)) - -#### Utils - -- `Arrays`: add a `sort` functions for `address[]`, `bytes32[]` and `uint256[]` memory arrays. ([#4846](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4846)) -- `Arrays`: add new functions `lowerBound`, `upperBound`, `lowerBoundMemory` and `upperBoundMemory` for lookups in sorted arrays with potential duplicates. ([#4842](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4842)) -- `Arrays`: deprecate `findUpperBound` in favor of the new `lowerBound`. ([#4842](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4842)) -- `Base64`: Add `encodeURL` following section 5 of RFC4648 for URL encoding ([#4822](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4822)) -- `Comparator`: A library of comparator functions, useful for customizing the behavior of the Heap structure. ([#5084](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5084)) -- `Create2`: Bubbles up returndata from a deployed contract that reverted during construction. ([#5052](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5052)) -- `Create2`, `Clones`: Mask `computeAddress` and `cloneDeterministic` outputs to produce a clean value for an `address` type (i.e. only use 20 bytes) ([#4941](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4941)) -- `Errors`: New library of common custom errors. ([#4936](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4936)) -- `Hashes`: A library with commonly used hash functions. ([#3617](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3617)) -- `Packing`: Added a new utility for packing, extracting and replacing bytesXX values. ([#4992](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4992)) -- `Panic`: Add a library for reverting with panic codes. ([#3298](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3298)) -- `ReentrancyGuardTransient`: Added a variant of `ReentrancyGuard` that uses transient storage. ([#4988](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4988)) -- `Strings`: Added a utility function for converting an address to checksummed string. ([#5067](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5067)) -- `SlotDerivation`: Add a library of methods for derivating common storage slots. ([#4975](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4975)) -- `TransientSlot`: Add primitives for operating on the transient storage space using a typed-slot representation. ([#4980](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4980)) - -##### Cryptography - -- `SignatureChecker`: refactor `isValidSignatureNow` to avoid validating ECDSA signatures if there is code deployed at the signer's address. ([#4951](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4951)) -- `MerkleProof`: Add variations of `verify`, `processProof`, `multiProofVerify` and `processMultiProof` (and equivalent calldata version) with support for custom hashing functions. ([#4887](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4887)) -- `P256`: Library for verification and public key recovery of P256 (aka secp256r1) signatures. ([#4881](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4881)) -- `RSA`: Library to verify signatures according to RFC 8017 Signature Verification Operation ([#4952](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4952)) - -#### Math - -- `Math`: add an `invMod` function to get the modular multiplicative inverse of a number in Z/nZ. ([#4839](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4839)) -- `Math`: Add `modExp` function that exposes the `EIP-198` precompile. Includes `uint256` and `bytes memory` versions. ([#3298](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3298)) -- `Math`: Custom errors replaced with native panic codes. ([#3298](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3298)) -- `Math`, `SignedMath`: Add a branchless `ternary` function that computes`cond ? a : b` in constant gas cost. ([#4976](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4976)) -- `SafeCast`: Add `toUint(bool)` for operating on `bool` values as `uint256`. ([#4878](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4878)) - -#### Structures - -- `CircularBuffer`: Add a data structure that stores the last `N` values pushed to it. ([#4913](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4913)) -- `DoubleEndedQueue`: Custom errors replaced with native panic codes. ([#4872](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4872)) -- `EnumerableMap`: add `UintToBytes32Map`, `AddressToAddressMap`, `AddressToBytes32Map` and `Bytes32ToAddressMap`. ([#4843](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4843)) -- `Heap`: A data structure that implements a heap-based priority queue. ([#5084](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5084)) -- `MerkleTree`: A data structure that allows inserting elements into a merkle tree and updating its root hash. ([#3617](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3617)) - -## 5.0.2 (2024-02-29) - -- `Base64`: Fix issue where dirty memory located just after the input buffer is affecting the result. ([#4926](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4926)) - -## 5.0.1 (2023-12-07) - -- `ERC2771Context` and `Context`: Introduce a `_contextPrefixLength()` getter, used to trim extra information appended to `msg.data`. -- `Multicall`: Make aware of non-canonical context (i.e. `msg.sender` is not `_msgSender()`), allowing compatibility with `ERC2771Context`. - -## 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), [#4489](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4489)) -- 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)`. - -#### More about ERC1155 - -Batch transfers will now emit `TransferSingle` if the batch consists of a single token, while in previous versions the `TransferBatch` event would be used for all transfers initiated through `safeBatchTransferFrom`. Both behaviors are compliant with the ERC-1155 specification. - -#### ERC165Storage - -Users that were registering EIP-165 interfaces with `_registerInterface` from `ERC165Storage` should instead do 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); -} -``` - -#### SafeMath - -Methods in SafeMath superseded by native overflow checks in Solidity 0.8.0 were removed along with operations providing an interface for revert strings. The remaining methods were moved to `utils/Math.sol`. - -```diff -- import "@openzeppelin/contracts/utils/math/SafeMath.sol"; -+ import "@openzeppelin/contracts/utils/math/Math.sol"; - - function tryOperations(uint256 x, uint256 y) external view { -- (bool overflowsAdd, uint256 resultAdd) = SafeMath.tryAdd(x, y); -+ (bool overflowsAdd, uint256 resultAdd) = Math.tryAdd(x, y); -- (bool overflowsSub, uint256 resultSub) = SafeMath.trySub(x, y); -+ (bool overflowsSub, uint256 resultSub) = Math.trySub(x, y); -- (bool overflowsMul, uint256 resultMul) = SafeMath.tryMul(x, y); -+ (bool overflowsMul, uint256 resultMul) = Math.tryMul(x, y); -- (bool overflowsDiv, uint256 resultDiv) = SafeMath.tryDiv(x, y); -+ (bool overflowsDiv, uint256 resultDiv) = Math.tryDiv(x, y); - // ... - } -``` - -#### 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 was changed. This is the case for `Initializable` and all the upgradeable contracts since they now use namespaced storage locations. Any system relying on storage locations for retrieving data or detecting capabilities should be updated to support these new locations. - -## 4.9.6 (2024-02-29) - -- `Base64`: Fix issue where dirty memory located just after the input buffer is affecting the result. ([#4929](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4929)) - -## 4.9.5 (2023-12-08) - -- `Multicall`: Make aware of non-canonical context (i.e. `msg.sender` is not `_msgSender()`), allowing compatibility with `ERC2771Context`. Patch duplicated `Address.functionDelegateCall` in v4.9.4 (removed). - -## 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 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/typescript/packages/account-modules/lib/openzeppelin-contracts/CODE_OF_CONDUCT.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/CODE_OF_CONDUCT.md deleted file mode 100644 index f7cdce9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,73 +0,0 @@ -# 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, socioeconomic 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/typescript/packages/account-modules/lib/openzeppelin-contracts/CONTRIBUTING.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/CONTRIBUTING.md deleted file mode 100644 index 1a44cc2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/CONTRIBUTING.md +++ /dev/null @@ -1,36 +0,0 @@ -# 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/typescript/packages/account-modules/lib/openzeppelin-contracts/FUNDING.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/FUNDING.json deleted file mode 100644 index 0a362ba..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/FUNDING.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "drips": { - "ethereum": { - "ownedBy": "0xAeb37910f93486C85A1F8F994b67E8187554d664" - } - }, - "opRetro": { - "projectId": "0x939241afa4c4b9e1dda6b8250baa8f04fa8b0debce738cfd324c0b18f9926d25" - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/GUIDELINES.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/GUIDELINES.md deleted file mode 100644 index deafed0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/GUIDELINES.md +++ /dev/null @@ -1,155 +0,0 @@ -# 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 is just as important (if not more so) than the code itself, and should be written to 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 workflows](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. ERC-20) 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 ..., { - ``` - -* Return values are generally not named, unless they are not immediately clear or there are multiple return values. - - ```solidity - function expiration() public view returns (uint256) { // Good - function hasRole() public view returns (bool isMember, uint32 currentDelay) { // Good - ``` - -* 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/typescript/packages/account-modules/lib/openzeppelin-contracts/LICENSE b/typescript/packages/account-modules/lib/openzeppelin-contracts/LICENSE deleted file mode 100644 index 367f411..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016-2025 Zeppelin Group Ltd - -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/typescript/packages/account-modules/lib/openzeppelin-contracts/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/README.md deleted file mode 100644 index 2f92281..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/README.md +++ /dev/null @@ -1,108 +0,0 @@ -# OpenZeppelin - -[![Github Release](https://img.shields.io/github/v/tag/OpenZeppelin/openzeppelin-contracts.svg?filter=v*&sort=semver&label=github)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/latest) -[![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://forum.openzeppelin.com/) - -**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 mission-critical developer security platform to code, audit, deploy, monitor, and operate with confidence. - -> [!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 (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' 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/typescript/packages/account-modules/lib/openzeppelin-contracts/RELEASING.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/RELEASING.md deleted file mode 100644 index 6820d40..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/RELEASING.md +++ /dev/null @@ -1,45 +0,0 @@ -# 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 consistent and reliable. - -## Changesets - -[Changesets](https://github.com/changesets/changesets/) are 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/typescript/packages/account-modules/lib/openzeppelin-contracts/SECURITY.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/SECURITY.md deleted file mode 100644 index 0d09b3e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/SECURITY.md +++ /dev/null @@ -1,43 +0,0 @@ -# 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. Learn more about release candidates at [`RELEASING.md`](./RELEASING.md). - -## 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 | -| ------- | ----------------------- | -------------------- | -| 5.x | :white_check_mark: | :white_check_mark: | -| 4.9 | :white_check_mark: | :x: | -| 3.4 | :white_check_mark: | :x: | -| 2.5 | :x: | :x: | -| < 2.0 | :x: | :x: | - -Note as well that the Solidity language itself only guarantees security updates for the latest release. - -## Legal - -Blockchain is a nascent technology and carries a high level of risk and uncertainty. OpenZeppelin makes certain software available under open source licenses, which disclaim all warranties in relation to the project and which limits the liability of OpenZeppelin. Subject to any particular licensing terms, your use of the project is governed by the terms found at [www.openzeppelin.com/tos](https://www.openzeppelin.com/tos) (the "Terms"). As set out in the Terms, you are solely responsible for any use of the project and you assume all risks associated with any such use. This Security Policy in no way evidences or represents an ongoing duty by any contributor, including OpenZeppelin, to correct any issues or vulnerabilities or alert you to all or any of the risks of utilizing the project. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2017-03.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2017-03.md deleted file mode 100644 index d54174e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2017-03.md +++ /dev/null @@ -1,292 +0,0 @@ -# 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 warranties 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 bug free 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 executed 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 prime time. 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 recommend 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 is 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/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2018-10.pdf b/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2018-10.pdf deleted file mode 100644 index d5bf12741c8a6d44ed597de7204fde72d91dec35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1000527 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
      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!) zyc?;>b>R)v>hA%lp7W>xp#6BbHcYs>ISr+%jMuupor1MxwS_c^pDX?|EuVP;JXbv* z0bmIOc&OrMM@wrvOiS@Sx9S+n)~eL1cyqit*&GdE-rvx_%E>(6Je6O$n+KSC zn_W!9OhZjxramT5Q*V>I$-TZd*a=RJ|WJbek zguVER^o$dl!if#x5l$m{xq)Wz)^LLp_F<^LQ-!!`*p}W#b+7jz8_Ysv*>o@2(>L>Ro^6IYsT;RG;*JwD)SN`HNoS z?Eh&%U=KvVO5zLg@DNr(3`E0DH~@RW9-=tX?_eYR48OoS*aDG=V1nnc3l74s@B&^! zG8~4hkOxO#I?RArmH2I`QZ4cbCI?!cY63wL88CSfyFqlk8xjCD>R3LT&t?qF+d zgXb^{9kDI0#q*er7w{rp!prD{?cf+3$M)C(uV4;##7?L|E#_h#yoP_lUATu5%BVv< z=Hpeoh6PxNMOcg_=!`C?paDy<49l?sEAcvHVrT4vuGkgs!vnm*qF6Lr%hs_Nww}eZ zIJSXpWSiJ#7SFb@t<;4jux+rPZD%{!PPU8fW{E6`C9^$jFWblVvlLZ;Dv+hJ1MDC> z#169~>?k|Nj*%_9`(pd&O%QD$Hmc`DqY<7WNWS7`wc7^4zT$ac3 z*;RIp6|h3~Z<^~nIIAj+}W) z*%x^jDUFmx$}vENfEpu+XwV`dW9Ua+uGw!6n1kk!Ic$!YJag0>Gsn#dlW$I%Q>MV2 zHfPLPQ)tea^X7v8)-RdM=8Cy$uBk)nusWjh)KPUzVr`7AWMgfdt!%5p{L%LRAW-E&3mzI)(`U5R_>N?n;N zj|Nc{1zX3~wW&7ErrQi#&(^n@m?~8z-o9tY+X;4}on$B5_w5ur)lRb?*bnV=JHyVj zv+Qg;$L83%cAlLd912d_1;G)!&@Qrz{q42X-(t({3cJ#NWdCmeVgG4A4)TJd!LcAe zI2@d?tL!KCQ@h%(v7gzscAZ^sKerp~7j~ol(r&Vw?G{OpM5!j#rH0g$BuSQ9Qd?4_ zj?|S@Nt1NRh~z}(QtQY&^enZZw$zT=M@CTx>PVfaGj*Y^)Q!4R59&$1s5kYYzSNKU z(*PPsgJ>`fq37s%8cM?=^QE5DmrQ9O4W*GZmMpm_m*lcsk*m@~no2X8K{II<&89h& zLvv{!&8G#lkQUKmT0%={8Lf=!Xe5e3lDe*LsGI7zx}|QbJL;Y)QuoyZRje{qiF&9? zRheqww^aasXo7|aAQ-Sfz!0j2AmAVh6`&%-KqZKUIH;@|K^3T~8mlabhXhE3YET_& zKut)3WWUj-`@NB(ny98wM>T`GkP2y#4jE7n>O-bvOLI9U$K`}vlk0LrZqg2D01crL zG=?l_0!^VAWJ7a!1X|F~v=iQezrefjR~QF>gZE%OOn`|n2`1Ao@IFkTUuhTZraiQm z_E9eFrvvmG9i&5an2t~$9i?M*oK8?aoupG#K&R;pouxuLN9XARU82i$g|5;yx=uIf zCf%ajbcgQJJu0I6^ni+CDon!|tVAXB5MwcpN~sJhV->85@l?(MD+Wx!MAjT(WW$z; znL`$KSPiRV4XlYtn9NbGz!fym1a}}=2@tnYkT#c)94X(*aoXoYj zHm7i%sNqyj<8;p8dR(6~xdGP2RBp(PxG`sO6K=}QIGdaEBiw>p@}vA1reQii&QI`@ z{1iXUt@s&k&ChZhZp-cDmfYs{+#zbC6y<0bm8j#6+=)AL7w*d4xI6dYp4^Ljb06-@ z{kT65h(@Coq7|btJdg+RU>?HH@$)>Chw%&iBEQ7L`DK2E|G*>oRk_0>`H%b>|B3(1 zuk#!HCcnjR^C%w8V_*i%gjp~f=0Fb2g?TU^7RX#a7bEPq`B6Imsn%4%67pUGNThs~rIuEBLZUQg7M^%Ol#&(O2be*2}#CR_Qf*tzNG; z=#6@d{#t*px9V+rr``=Wbgn+A^YjT_pbPayeN|uAH{mASg4=Kh?!rANg8SGKAH~OH zy?ibkq(mM{sgy~%3*Z41LkT>DQYeFR9cZONYaM|r8ZiSK;NxDYPhl(nc57^d?XZKF zXg9CcemF=cd!4?Bui!|p&$n=lPWS2@=XcQroaD_p)thrV&h*;M!Fjj<7vU0IrZaH` zeuN+6YFvk3;AZ>^zrkg)S)S2N@Vpo4b+6MREWvW`9_u%J zMK9Ah6R$6uL~qk%Q_C;<6z|P6uh9D5oQ+JDZf=^IY}3*U=_$YVTbnkTOk2~=v^O10 zN7Ko4HeF0t)6H}@Jxov2%k(yVOkdN_^fv>{Kr_fc87v!R)Bn#$hg!7z{d~+2Gt3M( zBh0I^#ep*}bQN5ztLmz`B$wjST!yRf8n`T%?OM7gTr1bcb#Pr=57);Ha6{ZMH{6YI zBi(C~A5DlRsuL<-om8h(fjZ6QVGybiLLEjz3{7Z53ONiz30)WsD})upn6Oe98^(o| z)fsg*axYR8xgU8DDUOuL9@#7VBv?cWICfBqa$}Kt(}v1H*15ppI5^fa!GL*#i_8sD9iq`^9G^X)IcfLOe(=ONldKW7by zs((vwvM#bC$U{KEyOc!5v=edgR%#}dW}#(0m7^$V-^x;~RvLu}S>Wk_?7fJT4^tvb zwmwJHyheP0UTY|hM$kl>iCB9Rn`SMcYC0uX(>R)j2z(J+X$7s#))wm};Np;Y*Sb#q zDHXB(JnFD6D<4^ZB@cQ$2ke|;TlyU!FJ@T@$sZwV-yvp8X3e+0h6XOg?j0nllsZ^D zcVqNAI>(Y(lkj1bU6yIR1*u^)8=1fkM73ktWbRU`tx~Il5;4b8jJlon;|v^xO^(pV zELQ2VUb4CDCXEMYA^ip!$T39EZ}5dmtda}Q_?Yz} z4W%5ag0{QS^Ka}c+~v5<#XB-!O`-v?%d@t%>1{;wsfa3OuzL_IEaWeU2PpJlZaJ6;XXbGH_TbF zRlX{ZJ8H1%`;hT$qP@sJ2D3a?#=gtySrco<`P+`j{}?;ZC-O?Z0C!EjSS*gnNhlTa zA-NhD-=Ln41S4-n{t)@f%C*)~8StYzpt)E2J{cdU5+BhOh=hx zHe&pPjt^tPwvUFV{uSNyW2X@z_{9O*%*V(Sc*mo_^Bk%br5s4*d)PX@g0=G7l%;9` zFJRNDOJ=~<@9-B92NZ}>R>CT%k>_-erVf>_;ZrDoN0;R5SldyIyi|>4kMk>PEbV8+ z$79a7#c1gk@6pHN6m!U*&|jnzx#uOmTg(Isj>sYhKVY?TK5eEktclLiD>xOI$^-C$3GDa0 zK^lArYb7pU#p=c*XBEm&dWy{!JJc)u1TCRX>7xbLBKc^clWN#sfwzE8lbRKuqo#OXc^KQK|0q9qx~nFd@`!9(moc^-a3 z0znNp*alDE-(WdMWMA(HP!%4wGM3T?OM(*xEP^1vT7TTK{o4}C^Y(;l`a zvYZyttvER+*)%1pewf)^2M!b5gx^Kh2=m>1BsPH4ZoS*ks4C z-sM!s%dLk+U8Dhacp6sl!dgqIGEXW_9H*V~mV{&swj~eO8c4uYY zaeGGkZTbk8HvHCGhNY#ZBqt>%3>`9fQ2f9Fak2fK{bC%dA_ZrZ?bicg&CCd!GDDv- z#bej?8Z^}0)DSi`GzI#~m|8e0ruCKdLh^h6CF$*!^!7@!c&(5MJ=vOH*UXM$U29{r z%7UOb73(3*ycDHNqx3UTIu5kUg$|lOxxQF4Sy=O%fk)~Mf4CUKwe)xTbYGp*lT9to z{vi8sMG2nd&u`%r69=WtRK3`5rs&1C2Bt{&*VLLb%Yy#mG?y#n$u^m9 zo<7$keUdrQ9Tg#8bQ)9jnU3f*T7$hB+Mu;$w;LPV;%RQ!9b2o{)>H>gQ4_M~805yh z#b(lDpC*4>#o&W|!RDK}X~OU)H)wX%Fq$><$7R8rxi0%13SkWN<>`U25x~?NVZ@RO z4YTnzp`gjuU`owiiM^`s_0{QqyCvMHnf>%hdcDyY#@3`7CY3L9?N3eh9d3g}SFT~Kxti_HrnEiZVBR=15xBHt)dc3X~R|yEv zFJ0{0Qq$9-rpI3;o3wG#3pMa>(5BmMW@XtBarm&O(6K05AM43}q>bzPqIeA-n2%<{ zwl$&rQ82&DWpD6?HZRRZ#avky?5=AxH*G(8N4Y~L58Isf8=QnHo3ru;r?-1p2a;Qf z!D%FzF&Vx8f$@n${Pp=JOZ*?~x^8|+gzs+jTv!76! z>4nLBwgB+g-PBXB$bj(HTZS*8;|W=&thMCayF7-dpX;T3suzc2}|_ zYu7@O?X@k*x?O=c=I9XOn$uShF)%bB(n-K}JzNvJ5bQX_5NZ=b!jVa)9cTbYK)An2 zV$2~-I$$Kd+x zOz#Gd$an@Xqig8e;4_OmzCAeEnei7K?<_gchJCde)?rd0&@k$O11m-qIIya{^)ds1 zIIz0)9D-vz#BP@=7Rjhg)lT!SKD0dNLqXnQ|~PLrbQAPh|A zCP97f(|X6KvtadMD*_a)zfI`s$b=>Z68JeHg^&m#yp8+aKI!$NHd+1wGo4N~GE>YX ze#Inn57gH;GPzHet!f=3H2^{;#iZKWLP3_Wge?RS4RfEx{}OrQ1Nao7gNyT59(ZWojETE-0nN&w8 z2xXa7w}<;gRUWFHsQx%K5hTW-@cHNYzt2i_pWMu6nl|zdZ~!+9DgEWHgbV33Iu~j& zUt%vgZ?U(W_gxf39MEY9E6|aY1>nrf0G(dTIB0{Gu^G);Mlcmq7Qw_4R>8z0PB7UK zXET-{&Oti~tAlnCR-3Vuve=An%Hp7Dhr@x?%iY?7Rz> zq=9Vta?9D<%OIcs zUCWW?{LPkbShp;H!w%1kz^xiQ1eIABKL_bryn4Rk4m3K)VFEvT^jx&lr=DNBI2rUQzFr^U z%c7Nvxsn$Iw_6kwiQ3wV3jFJzDm=iT%5o^A*VA+mSB1Uc_n7!uWKeWuP3P0hvkYR! z;Siu;LNV8qP2{uWK~h87lebW!4%nhwvjIgC3}RkmtngjJYYxm2zcYAJ%}JhG{Zd zgZyz`;024%@AE|?@mL(wR$b8ge0~crlp@YbX*q(TI4du(u~;0R^%F8WyJ z>8|GVz~f_?<7Qv&dj#r+}CBSH*_=Z#~WYk+|UzH19Z>K`_xGs zC-gwTvBHnLC#^ysvL7lzn~O>ujx0K+m~D2e&1SbbIJ3PZBp1JnP68cnS`6rB5d&|{zH(swnC(n8H&UeuZqNK3n|?IGUvr@GlABhvB{t5ZEyAWS+7y7z;k7Ze zB;4*sjeLUx1xu1{jvny&U$FfdY4T1V&|`(2)O z9qcpgDV7MZ3X9l}TnBB?mPPG~)4rf|yXbuSW|A5+R`<39zO}#sQlrQaG{KWT{ zuJ?FgWB%gd9}fLw#o4nPHy+*n%D{)KwhuMz`*pVO55xJ<)~@oayZ1kSa0&6;;?4ET zo>;f2Y*}S43SVg%S=x4W6Q)HwPUikXh2c{;KoXF=hXBzh!b1?j45iizsz)$c;A~AW zTM!J?6v}|&FTTj%!*AK0Ux7OCd11hOh4z~vV2ZW>X1i*DqPni|z4!g?zMtLu_6K&C zby=h?QdCqxS+kaBQl}{+)udv?N@%JzMpBhvtrCqtF>0()l2nZuEttkutj3C<{3Y7f z(UBRNwpeFsXA;{%>o`K34s}coOV4==X3{CkyZ7#UZ|^zx{Cwv-4$j+X!5Pxva=>hv zN`vcJB5)xp2*L^T@NRqKq5GJOP&`W#Xhj-hCc;*MtiZ?5DgAWcAIcVWZCRf)GaK?H z`BWEuKwSgZhaUd1V%Pr850jb6=vUTN z%3<-K#qG8ieJzGzFYa1yRb}OFS0+$_6P^(rF+=}HPj5Cc3v&Qva|!@n{hSRU3Xh$c zQ@5pSQQ61Ir|1p(_pbK+yB7WV;n4MgWIX4-5pHyCwN~XLGlNID-BMW zJkA6f1gse7kI87VhVDI1_a08HeK9*bwa*iiIp|6r2qLS~lszCUE4JMdp#cV20 zRhl3w6W|MxikImjLCg>$jnwr?7v@x-1k84EZW9aupa?FPOyTj*=m86(J~O3O;|`;4KD=6)of;AmFV7e63SCNv1A1SYH{6i6}TFTAG;w+Xuq@!tf( z#WQsQWDigQQ?ZQfv~pt#!SeF_SZkWC@ZS7T`TX@a45O$Jrr(2MX z_F}*aYMP8&a=b&huH%UJ9&P#Mo-J}T$itA{%`B>YG<<`k!R3L=4ZQUSqP&Cc)ONbB zxFn~d1=wuw9Dix>iH!N)#s0;?r!%URYHf-4MSpeh`x)!mPvo^)oqLD;j!l){d7|n}a`<{Onf(39ch1qn$pfF=qs!@vffu%8tb7U%d>gxW37@C_R!VR6SYZHI|x8S-uVaqk-tWK`5PNDKloO66`m~tv8=$^BJ}b|EICbX1iW6k+`v#WO?xq5IXQ<_ z#3w~CMAPwwNCclo!Y+6c(NXhA8|$=mrlzMyGr7rFG!xJu|7s78JtV&$H7&vM;#3S? z_DG=a@i1GU<#d~DRL%`c^LSZ##E18A?`GHSTq*$LhXMO5yPIU;SivOBNP^l2!}T9%v_V2Z8Xq|Cm^;t+?45RZF(M?*ebS(iL8Tt4OsZz)2U!bW}S!df^{bW{5sVd(b4`0$x{kx z$!G=?6X;xCs;C&}&x%b4kB^ce1mP6v1tK6TqVmObmOkzm?|ydd;LBSN(RS~HKlR>! z@>jomZ*k=0$ytdd7hbt|b6NG$t-B+tn(L2*#Yk>g$~CeLJrD#M5#<>CQ6+|6#Mfi_h(0~} z_#vKnNeL8@e(+!aC4R{h=NI#);)VVjFBxgZY-772&NiPh*JcP$r@hEm_?D*q*jVq| zZtU{Co^jMrrKn)XjiwteQK2B0qFXFDKqn25Tw>6o7G3v?fe!XQ39{u@4rnQXnue#g zD!MAlq5+KL=w_uhW@A%~k{FLM(0K41K8e*&47AbW=3p=Fpv6!~E?C-^Xf>gYzIA#O zuxu|PW)0?5rf_Sh4}-Hm)#|3)38@MWglwfX6+k0KIugLF>5rD9K13%fI1=bz7PMsU ztKM|#y^RHPd>*Z~ZTpHBcKceg?tHMWyL#Eut@X*<*M2)pUkx1G@tdt1j`)7g)@@v} zb=$UR>*eR0msTB`6!~z^h2+0)fzlzs01nJm1>?l5X`Y4pa{XPsNxz~?bA&m@&qTok zF-~+@P$X3o6rw}2cMGCV5JbTsOgDf}b+S(4AdEIzDiK9^g>~CH)dGc0nq0+6jg88F(NXcBv7+KkPxM(A=UJ z3ICVwYJrO4I>Yzgnc4Tw&g`P#s&cy6c|A#<6Z~*T;TnF@}A@$ zxsJKsv3+FwILTyosp3>GXU-LJt>=KpI6#Nwvbdct*Dpm!g6K*R9d>|-?xKO{;$aZ% zqC)Bb(8D;-!xWq+Cbxz@7?R$NS27%t2E(+H57Z~(xklYRH*v03?Od$Yb1RK2 zO?A$d+6L3cDLYI%r+j4kK#`3a-Qvt~Oc<5~7~#GlY=BE#28fCeiK%7bV zY7H$Uke)dnGw9hu-HA@8H%qLL;PoUxDP-~48LCL6j%gNJIUg?4mD!#e&w9^h5ARXv zGmk=-^YoLnp6qdv21txd6fwqljOif9Sj8xODBD$G@JLLWfoXzbIq853q#{`=pj3ww zCY6-?qDP%pQeW}Nk`?5U^J{v?p7~ANpQFP+-u<_(n_~rK&o69x{phnTC-_BTU2bXa z!~gulTsYAS_Ryhn^dTi>F8(cUqJ6nEw~cWCBNr#rUFvB zr)XY!(zG0UdO*vd@bLvT8}g~h24NhYjwkJO^93_D_mefcl-=ymHNcJoBZuT5j(&Wg zZ-(0ZQx0?RygRMgJz;6wx|_H=9-Oc=cL4i$#wjln%Pq{3qeCl(7{+tqrbg6QRfRJ$ z@@B^5TwDntxZ_HggqF$B!F3I5Z(X=}yMEoSebJHY*P|l`R_v^QV#n^)Yo04E=~%S2 zvuoStV_Z`3VBO&xpB!HOVsP5vbLYQA7+>6f2`_%4ZF|k*yV^#-EbS?tjg1}tyw;Ym?D;moG2!s za*Uabv`gSBFr751R7BHV8O#pPU?ehwZ46YKwx2{<^ya%0PGV9J_hzR)l?_jsb@BgM z_5QW~XQ`aY3+Xe9y^kq+V5w3WSk0|f)_KWo{LCf-$i8XY{PN7TUtL5XA+)INC0Un=+>w2Gvf8Ar6q!6bcHUO%6rJo!EttIXo#yC8X7$|Gz7nWBKk+Xo&C0m zcIY|H*6r3GT7P2w%qqZMW>^X=^DGsXRhHA1Pc25PMKsbijUj_U5P9oK5TE6GKnU?H zjI9U>24je~6k3ag9DX)WG#>Lu9PyAscZNY-N+HJW(%4u;Vt_c{|+*sYTdS<+aeH7FmNU!43KKL$&u=A zq8rZPauC<$x*MIuCpDgUO?(K`?b>LptY!@mqH_l&=6FjZ@KU|8sHnj}Fn6#UV|N30 zWi-kWvb7T*>WL0UFZIycG~pwBF>heCnXhLG2Fx4HD4oOU95JTzydfP%;%nsBgpdmY z@|tm?iLSX&8kTOMoYDwXita&(Em#EOjxv`&k7{H;Up!jKy-yErS?AcxonOg#3)#TOLTE4-_cNWHCAB-OUXBFPu$ ziXQDa*(nOu#-s>?u9qPxXgVEGePXR4wH9`_MAqQ|YpOC>+K>?FIP-6rA@wA5VKoBu3gz_!{;p52g(izWz+} zA@ywH-7CMxsCxT%^1Y;g2tS$TtSc>^mHozw;wNA0cu5($ar@2XM>j0|*7CK{7a300 zN55_SQ1}qdN0sQVUdj6-ErvH!oMS8Z?;#~Hre z`_}2>^kG?+t@Fu}C9nd<$Obz=d>IGQ0;Y!YWk3`|!H|>&8`4bDHZchlC}c39&;~lj z0Yad}#RS9HE**l)w39*#Z3jX__-G3xFm*zJBrd_{zPl%!^yU+VP z&*GO1ms<4*6ZJH^qC?arU_(369wr+%wUw6^MB#aviQpzf)=N-H*7RxXEYDTh-AgtP zsqWjoP@JHnh27mLVDifVhw{{ANOanN0Vq=Wg!YJtdWec<4o|Wc-whw;DJjO$NFIkX zd>$^TM~5c`fs5otqj9n>9ws~#Y;T52cNFm$@}+qcmdc5_HIKeFv3mES9XIQzHI?NZ zXw(LVN~YGY+-tVHd)@r;>CJ3$q_-Zs2SE&n?R`r(smgAOF=Ioq^d`FWG7W|C%KCp z+Xxihj*y{L+20l~+Sx`svXgt&C7u-V3u1$a#f`2r?^zU{1t)w0fR1363ThcB9~lI+ z(DLkF#Scy-V2`;pd`)kYH9xFE7P`DZ-+{NCQJul)^u`s$dxoFw0QXAC-QK89zY z%^lCYyq38B&A?69V5Qu2=jrWWI9QX%6-AiBabqG=BMTx+S`9$q8wYw_HtgGg2TX*ooB_+WW2=Nn(!#53xpqKr$~#lJ*>^Ab8o!}yaJY^3)6w-96K05iHu}ojOL!O1soi@72R!1P68-|U% zmq{f?%(6C%4Mso>!&pwU1x4Yqn4MB9XIC1Ci5IxJUdn~}q{s*8LA?B|K z=iw(p7+IStI=_#M?~tC(40X%{jawFKU{-`0nJxTY_H{=G+vfO#;}ml_bSva`dP43{ zh%FEXxC?Uh+{YbLebX|gW-a8O4E@lv*0Y6u)wv~SH`n;Fw3B-u$cQkFJv7UjtV5G5oUuD7kN zh9y3*0;xJkXad!vOiFl=I8PLmCsT|O9U^>43?bLnHOl7v%1W zQK;vl3dusJTh&~Q1R={P*Pwe=3M$z~5G4ob2!$S{q+o7HePHN)(GR_ze&}iULoeM= z{TFgYLn@v%hOybABuKo(Nt}=s2nMjA*q{zq2tqUcnSM`(4+B2)!$XHz0F47Go6x`a&Un6h+0qHmZFqO3xgV8nc)e(J z<jf&oxgTd&4yM)C_GIRy6wBuB%@ZXfW&TzziQj9u;Pjksw_J65;p4r~iLIQjo5SNn*W7J$-8tE2^+s=R$Uaeti_4S`u_ zgwyACE_%0#P24@ruHZXc%PUFoE1kn1jr`Y$WI$)`R@_PXng#OC9S9#zEx) z;x-f-xIJBj=Kq9m8!_vi@b8KLGFW&k^wj;a?`F^6y@FeNt4Q1rxAZQ67#2hAcR=mu zBd-z6_GM?_IdL>w@*)o#jWS_RCeCLxOp8+|F(4#lYECw+2{J;lczzT-EX*rD2eVMf zm+4HX`jVMI=Y6^YRDH9_?{R%Y9K}O1-G*!`8L(x==FR-7lq=QL=jr)C@Ia1*w5Xv? zjHLI3FX1G{2LSyT7s<{E=49otf<30@XT)-2Qa%@pIJ;1V+iDm2kF$aX{9C-i%_7)nr?Odk@*Uvv`2C~*MK`;pQR6epSRY++FfyexS9oH$5o2lEj1fznaMv`rRU?Vur6J7A#IM)IvTq*-ksNL!=8 zp%&|WBfpOatb$ov&oncw3|Gh)OcisHxxw%r9R?d2mOf51$pq5b`B#5-KJL%X=Z0!I zJ(`{E+?nco$hTtF^tT$o&ZVmB>PPmb`cncqC?}X)_9t~Xp<4cPgYDx z>0YFJ4R4iqj+gVI7}4{7O1$2`s2`*`Wt`_w|4h2oRGl>=;vS&{yA$PPr{Nv$C!#s5 z1SaC6dyWzRp}bmPqd3m+&g{kY|IHH zN|Yvbi(LsNr73ROV$xEi5QRbul&X#5l%_lkj%Cu;ptd}sJXG;aC_xd>Hj)vdZi<3^ z?mu&P;1*RPXWz^}v!~si|Np-K|Neu@hIP$P)|_lR@!W~G(0;r3+mC(oJK~+u*udE* zud=)ds*fyZh(=kjR4i|Fsc&|*I#X^?zo4!Zw}=--WutmoybMK%WeHvyYsfa~hve7N zN0g`%nkik7u#bV-7fjWQNj89J=<~Zlw%Z45nx7>$m+*P0FBoC_SG~D0cxF}AT4eU&bC_kMCPts8CiaCa$b`Jk zgggNyFM**@vxzo=Y_~zSCqT9{Refnz+hG|$_GP}f-RHNMzixX`Fl1A=>Zz%l^*&~) zCU8T@J-3bPCjJ2wdzP;p{5Cn}O6*&naDg0G`y*gRT$#C53%ayC>`GqPWo|xJ1!j?( ze(-5yH%6UZnY6$f2Znx>Lh!FxJ5S9e%;ai*j-sg|c)h;>P5=2CJYtt1 z$OgQLiLW2VIj2&{0X#!eJz(+b2FU>o@X#%538EYxohT$ z`$<11t_d%9^JxAgcMB&O&7EW_yyIJZfD|$`WWM|EkOd7xI-QG_kjO>aD^qwrlKCj| zQQ{-vBV}l-U>4@00tzOp#yXduygyR;sIWI+ZlcU#Wz2F2@+Z|`y}<|K7X_q)B%`3s z*umM|xWR979JdHT@KuW!$g3B*;C_Bv0kN};Oa-j-ve1+}Oy&Xh(m6OLyv+hOXc#A` zw9&uCe;QorZ}vAE;v}gmFj;RE+og?xr}dry)i9xMpg~`X7mA-(Ji0jWIbGd_cZ)lf zowQecMUjKp(Di8q1KTn62LjUw1(W)h8_SW0Fs9U}YLNGJ-DGiE8|)6^;2`c50%-aX zlB5G@x~KYmYSQy>){r&`ht!bM0Z>DtZ9wXx($n<4Q0i$OR2epFEpte7PSBR{WOfidMsKN?`bW5=!iqt1z>{F;D zCS{ov>Mgl1X-JMqAVR!2hjS*Wp`^A?`44pjeN$vHt662e(;S=>NjGaODt6A4K&rLY#&64I;D ze*Mq77>(KqoGkIIrJn>5igIBc+KL+9MDq_E&G!G{o$O%mX;gCY zeUy0SA1}O}y@=1E4z%}V_T?)dWcMFCjaL0W`|s>Ks2(NykoIEs2Ka0rRHQLLcR;X( zBi`io)>C1;&|Da9H`~LK<}ZZ|BSh_7uNQQv%Fa#AeD2M6KQx|Vkk~9TL`4GwA2tWtt?f1aVKQ6NQ4T=4HXn~h(VaeB2+*wGrTGmmCynlPu6zV z;@Xr0*-7KQm&Vbn#U}kPdKc$)9!KwIhpnia?`fm1V9hYkm}hd;Fq09wSWfQjs)DxD zsg@`7p$y}&+mHvh#gN|UR7?Nr>2mk&{pFudW#2e>2+cdg0RQ!|o4p+e0OyypAELyS zCswzw-x2uR8Z4Vu%UQW+2gdMO!AprE$~s{Vs~V$Rr-SB1<5aItBX5|yL?aU&lo>Y zw;DeQylM;>f7kzJn4oZymJzlr!!rE7U;?M&5mgRaX24HupDz-P$4aBDe8gDLqER7L z&N*xY4s=@T=zC-a0R{@WKu?+VBIWEHvdm5_XOfj0D!VJi%5wWrc`g6n8dSlWfhC1* z0EoSq6(P>^*mWCF!$m@#-)Xqk%?|qGLr=7Wk{FXHNa>a z2m%&f7Hp956oo;cP%%+$&?e9lO)G7sJ%o^^Z4y%EQ?y$+EpqO6iqN~Vm#Vq zVg*$z#Ag4wwt;G~?m2&sukCaH^ZnodeL7q|rz)p{v{!4U!1bufP;D^Xvdn<6D*zFvbtZQX+ zRnM?RnOYS3hX@YC$Ww?IuwPl9eD;3F<0At$P%un@d5m5~L~t z-28|HUlxM{)qwcr2z$49^1&!6=l`_(%~avkW(lD)h4 zKlthU#k+5#%j)LW`o6KPd)C_8;I|vvkM_Ut`!(x7c-eR0^_Q2=&t^B)&pfqb;G=EZ zZ&Rc;fgU&utmtJ19fij+NH_y|=Q&{%ZyRx~Dne&GHo}c8Vj(_-Txy^~SaRusl)2&a zidFqbg(M~`q);rGCi;!!^xIFmR!Ao(((CyflnhGkzPTx`#arWMT*F4Onj0!cdF9x# z`*-PXkAUKEDM05ajVAG6d(NM z&&B&&#^xN`bLljHcJlbu;^fiSk#d`zKY8MJr@k|W0yIYg^tsuPBN2W5ICjfc=Mh6( zMJF=6KzM}t#;YHyS3lIUS;%=80JXU(>LeO@G?l4mlVYRXB(IVO$)GSSpOf#%k}dbj zn8OmmB_=o{AX#Dvd}UV`ZTdO*v?vHR;RA&53_t|)0gQP8e(JU@f*b88s2>xWN~u2A zOVD02OyGZn90fb|xs@0l!av6t(-qC;dwJXh4s@75$KT<3aG|e`NUMHXa-mzVLp9MW zq(T)!BZ-73LS3EIYeLhYUK1u%a+(2flP4HIoWy@l2s)w@3BZy6yTkpXrn4SyYjaH} z^YC29(xt8t2dTLTl|m|?s- zsJ1|Vby8_2rKR;$D95yEIlV13mzkr@)#rqkFn!t*y)UG`Mc(q46X|4C6bUz&EqsgI z&3DVsnTz;E@^W(xzee6@Zs)hlFPVPclvxJp1WFCN=h)Tdo?6glPn!G~%kez+cp>>B zAW=|!e!msk5jn2+86D%jgV+_7CfDjYn35l7ZfN6$wSrB5T z4xz5ee!s110aev>K_(%S_iHND6>N!TL#p2|2!vqRQ%Kh}jUka>Frq#!paqQ0$S|64 zISh{$oVIO*P&hn_4jeBDgM1|1Q;38Lg-Ey%nm4Pz`^F(>Xk-Gpj_o%&8=KR4tZ65rrP$r=4U?gF{YeL}AI zF6lS9TjZAShW<5>k)Jx6tU(jD=qM37LaF_Cga&1tOEO~y)R3rosP4Sw_-Leh7_0y* zVSqFoJ3V7)k0nUw0nLJdpcAnyG#bP2Qxv4Cil!Te1UbWs#L9*!A&-g;K{O1T5rF>$ z7AuM^vjJIVfst4iV?%*f&yYqFnSf4Pc4RD%qLpWCaacSjvf?NjJ+-n-KBJE4Iq9gq z>PIT8!cC57GvRk(Kg zl`Xo;+89COLLT{lY*&43Q`Z%L_r5Rtefc@D{cPtY4=0ZEVZiyY6U#=8$c_ViUzr-%c&wlmQ^}A5d=!x7f zNtUXBH6Ei`QjQmB1a>af9dAZ+9L-Kva>&jH<4sc-O+|8v0+XpkfHKdensVnSN<4aq zgFQxwb4r{;k|M>Sc%_8y0p*&6IG9PCR4JQrL{22bC*YSOnJy$(;Ss(>6tFCnKygbS zqCW78gY7S3#2SYUWf~KFSc(eUrnDF9o=LEWYST(m$)>PME($|yD$0zNnA?z6O?5FH8c|Lio}q&3Xill zkN%kpj(*b4zSqkhT0ZZ{kx_BQ5%6z-{#IW~&0&I?gSEC7^=!cmSdhf1JG zfgXt42;n~LczY#b&S}6(E|pDDzC7V~ZB3y&)1!gaWv2 zOEj*-&b>?F{n`H)3<@Rc-DQao>dmho7(j34JNF0`G@1tdKDz^=5twCkSleER$Mz&6 zxC(?Kh9c#WkOKYpf^A?v#W5))2rPC?kJzEd%hEd$=9%DAV^UYgM&O1 z;ATEb05%Ba8(T13Tf+hnEbc(QbMt26dpma!ea3$T&ve)_JIx5hvF&olVNcGTfIlp$ zqM$DjZ$+&vw%Jw&L;qorjxgE=Mn7KsKHAFmK@wnhG+t1H^haaIo@Z;KR!Efs2)Y@m{NRJnlm!{bN}m z0U&w`3dosP$T>l{NE@*%!}3QbSI3iFa`IfRdGb?^_UMa_&gceZoAQZrPrVm)H^w!@ z>9KI!s0(@g&sMFi!c}HWYtnXV?`UHh|Blw9jcBZf8nQ}oWD~%-L4GoR-lZaPD%1Q;X;t^b5=kpmpuh-)<$|9^FY8Xrqt8f#WT7J5# z=gge-&52c4R-pP>+c&;ae9XV*(i__kw(3r!^o(gdcYf^;>t5us|SZF%Cg zCp?-O43|r5rp##1_%l0N>}B(&{^ZVox6GJ^u2q_P<$_pq$I}aE{1_0u6%cJfx6zqm zw8`F!c*Paw6Z|ZmZ?cYA*s@B^dh;=JowdsnrWdAsso;Fy{9xLVR)641`<@AQIaaGH zU2A-6g6FIO<%)47aHH_HaXau;@pWs=3QXc-u9&BWZ*tlEd{-;~B7dd$8}7cY=w6M3 zIaXu>$C13ICi}yeWTeZs+#zq0Im;&5k|{=IKed4b(4h~;9f~2DfQf(yjO!FUt3Pon|? z6-1#zxOgu?7`@d;mPUTEF7l8iP@rT^Bkd&*iCsF=om!yh;L4z$dw6k}00_Qrf|qe} zk?CeKAs9XGhWfe^?A4jF(hAmN5FjMt1S)9C?|ZwCKi8A7^Z)t7nN>L6wtK_j-@Uxy zF#kdBo1F`H{%L)FB!BsB^sBRNJ1%^B>EjE~D_h5IvBS`>f@tY+Oo>EX+vq|r8QDxL zvkrPFS76Gb-{fSZc|`|_UZl~B3W;9SN%SH`_=V3uCSDKg=hJoMsI4io=QtH)nKKJ# z8jA}T8y$rm#$LRaeM{Z1?++>tH6V52PPU7GSy`uUQr}hjoF}C|Me!+Hm9H?Xl|JiQ z>)PmIT?kr?{Yni(oaz9#$V9!)+yO!7a>>j?A5CyQtT||ZDlLNe!gADt35*c3X@YE; zoo1SoAkE2K(;L1hB1>!%v8a)oM2Xxa()KFW7RApKHZY!*@#0T+w=6Dep*j{39Xs5e zjShFy*rC|n$(WuVgfB@OVeRe6Ahpf7;{}j9pCLv_w#G}CO&u>DIeI1kZTCOlIC9nM z32a=t{owweb^QWuF-~1X#Yj4g@M}H4DO$DqkAJ=V(PlDZW<$=tgo<=SMYh@dCCsVi zYFvF>YI)eY73sF&i2eTmq<^kE7T$3rtdz=YX9T9T4STQ&gi`}cOG|U*E6%8 zo$=ahuh(X6!)_B`7eDAK9ztxCfNe|y#VMPb@(=~J!3YR}I5A2Bv?Y~=ls2?!ZAyzs z+BC+oQsScGDu^Eym7xliN)n)o6+v1Pl(sG}+x_kxn^=+Mxihmn9^dbL=X~dwI4tJr zrU8u96$=3+MZF-6QNl73rg`4NrsY}fR+k0TWIf>%)Cw`?SbS(Ps#-GZAd3?g?tTGZ zg^F8wtm1HegR>M)Zg~$gbgb>6S*Mj@<%%+?5C&0;A}S@k<+x5OC4MV%*!Wmd`1DaC zC7IqOGAdkrmOkq3;&1jqZ|ng~tF^K&iiku>uo0*a*7ra;M$d>WEI%=r(&z!8A!x zR8!EP@FwfnX*C-HHbC7?V8^TZz#i9wVEfSkD`}8n!CoC?^PiQJXI@%4C({?i!NM3b zQ;CWUTfIeW%*JrcNt?42Z`Pd5G*YEAkcx7oe1b(eMh?ddkeaE9xn$G$NV5sHaIAw} zH!&p~hY2~t$(75FcVv00VQ}FbAECHo+cd>Yl%9_)TZuaiFC4GnLsWcfFm>a->l2@2 z`=g6E58u0{^}oFC;P@q>HBh_i`_H|BSGh+Aa16vgfU71hPuw<3-yYnAU){HO(=kwy ze1NbE+^~y-UWrYy5qU5&H{wOMMt&A}J@`gYEeuu#`yxXT5@GeIDvV`{)u0$Kq8bhh zNjsm2GSYf%Y)|HU#7z(+3Wq?JSP|#da%bu#qp?gk!V!=MjVuy zinl-Nyq5Ar4 zmPLcnItyyM_*u_3Etx8^3J%Gnp(13-MiEZp{&;(?SsaiM< z@u$ndcE(}NvbGL7E|{akBo|MtOq8-WoIPqd1k0V7J#9Q?G` zuIrMW(i8SFy}_1gailnuKUBG_vOCqA zQmW(Cv+GlhdSkp{_7m|ZW`9Rn7hgBKJ=K-ERCz6aqx|zq%XQ@NN#VpmRWx7Wlf*1V zbNL+ULPO|01gVokr#D}UMh&f@EE>?9a5|CJ5(Ne4U2M9Z+wOL`Bn2fGR;IYDxm?!V z`?BV8S#ur!8KB|I8vB;au6W$iqAPKD_z83$L8oeQd*ry?^}d@UhP4 zj=!~g*YVYbt%>>TpRDQoA$y$m?97w%lti8!D8fM%c!_|R$-M|j zjgx8LB|1*nDz`X{a@g8G@chuu-z^>3v1R!yS+Im(9LoLb_3>{BNA~Y|{70SRe*jJ% z0HEL_aD58;i}w_*W;9Q9dHrFKhX29m)I!>97b@IWRCVK>j&Ad^b!g?p^{}pZw)S zD_+R=96}ep1|lV-uamU2Pm)|!k`zJ&BIP3-)CJKF5KGb(wnJT3qL$GOitf6=%3wm% zx^*1W>-830)Y*<|*p76QClekNbe<{o5}r%~Y*V_*GYRLm9?7@giZ7YTYR+QF2H9q_ zVZ$SzcA)wumI+{2p}PC~v(oAPrkeFTLN$#F)zpeG%~Ohy-w`;+_Ks^frJ(}00uROY`Fy6~fs&p~?(pAr01$#Bap; z4euqmBNHMKxrQzQDCDnctF>pu9oi-F6InSX<8rw|NvL&lEv*l>1lvfPyjp3ao#a{R zFg+{(mHbT}k*_QNlW(ixkfuqZNCa6{C{^Kts%k=!ZAFnqLK2c@OOmER!x9xkTS~H` z0%MUzPGZBO5@Fa#Wh%Rhm-2LAa@$ha4F*V0ARz%+5#f5&0?dK-^yYEybHoux9Pv&@ zA+7*CP9PplP$UriM|{b~nOJkEVGe`!8B69s&N<~x_47BaG|#|Vkj#S< z1z=aRB0rvxd3Fmfr8q`k5(Qciv@)Ot9c|G6i`T67G@2@|qiS(+767~4Ut9;v2mPgd zIT5ep|3Vu$U+}*unS>|aL-OQMf4mMr9O`%2a=G8Ell_HX1^9A8_a9ESL9?+3z0k)5 ztF{Agv+XQDz*A%W1?=H}ohb6Zj&p6?y0Nnku2(pXaXD6iq4>?~6Pxkr%M(XlkOuFa z!hI7v$JYz7-4owrefc6BYB*m%c~{~BB{3USQ=8#yW`V!Xo#(G*3BGy>7&nF#lX|2p z(*N16{@5n2JAUu(?DPGw{my5f?{fZe_-C*~fM7rbR^KSUN=j%;TNSWNL}6P3tT+Tl z#i+tMnr)qE#)hb-{Rj}jMmIqrL$n%Nw82pMp=JWQRTT(R2=Y2lk&xc)#4mTZ4)Unag?HG5kNX-SBu>~H_M1($ooXu}3Fom}GG3Wi1|09)Sy1Vr z&J^-Yad7r+%8h7-r+1yK6o^6pvX+SMT#_AONBEC|pO}s-j@u?3beVBpGfbXg;*pRu zfGq_Fobfsx3PVZIo9s){Nu*<*WUmZlmLxWfq&3`4MUvS3_(#f^(Lww}Wt!wRB4fxF zdP!!vb1%JBQVb|sl9uc>fI+4+?oDTq>CpKXmW-z}NS8DOJe`5LM4Gc9;fc}tT{5wO z=Tj+qT09AcD8#)!ijGp4e+=PY_-p(lic6`L4t%%jk#AXk(u!>;JT@g0$&+B~@rMLcV9k}$n&wCt+)4FQ)bMG8EQBKppUcah& zPk(tYeQfL2Cw}>}@&{GVbsg;&6>PT@2jf)e-@%jcW9Hw=P3E@ZWU=JVK^x{J2;P80 z+BI!lV@;Re<5zvia{;I77Tg}mlhBCI(un60iQ5v1+Y;}&Es>BwjFCI=3KO>_61RoU z|7!y(61OE{H%8=8B!*4|=q0vlm~?g6d1*H_dZX5-9n}UkR%7UC0hMs`_JAzg%=`a_ zOL)j|$u)+HtuS%W@;z+eT7&R*v2-6(#KK#|ggtN-{f#0u#y$-7;Cn7ib;`Wp5;%cz z!j$av7{Dv|Dj;WeV7raB5J4IHvETy`_w3(%wQb)MP#DOpTeRsAo7#J1{>CLu+sm8i zSHHXAo4YTR|BM_8HE;Y=HjPkpQ#x38BB0@4q97&`l6f&DH{nVrANV*ymliq~xt?_{ zcYWL0?sDZ|v#(j5uFZ!nz7}=9R&W&fr(n@nRG-o|I5zNW;0E6Yb&d8t5a68-_e$nz z$J4?}X+5*nu~t|w3BeG{$w)H%34>%GgKPs1ryP=fI1OLrVCCw~0lfaCAf5pi7za|2 z28uyY63N^Y4p1EAOpf8E4kL}g*B^_-b5l_5Nl=mp$6g5qv!aUz@c=e<+n8 zY@sQ!9MII%y4*}GuEqPv!BVz(yI8Ej5+$SjD3V%~V@tSg@yi^`_|=ZpJd1l1zD0pE z5olC^gd(ao6wT}Z@tF^Sy6whm!(*dwAM1Jb*zuh`$7ltlcWoK_sC@Cp4?qOCFPy*d zk2B}bp$F<2YiB1Q1btKlthRPZa1#6mY=LavJZjQWbD|UvHwBu)bHf|WUenbaY&I4L z7aPl6E2ToPV05_FN$qe$aGfz|Uh-enuGU?OjQB?)*UWKKjk8&p4NPa7;R1FsTme53 zZ-mF7D0>(+6v8U6hCCwW(Gx=gfPy8o3Ecu~5(rHKC-QCAEfE7LXqEFjRYUg$!IC&T z455JcS{yI7&;^uf^fX_Rq6U!*0)5~pxCz)O$b+ST0l3c*H3meD0a0T>b_kI0lmL?% zV@GZ!!3aorVkD6WSD;51&eTA*6+R@yuzYLee#|YF5Q=%?iHX)yMcg>4l2R2_HQ=Xl zpiRq64SGHO&AY$zqoIz?!`oK8-Y6g3vh~eFU7Ow-Yj>Rb$&*k1bo`A2V_&`YcyswH zrvKvU^Hzb+(l9;ZLVBH)6aX;c!zAuoVl%iHGd_OcO6M9Uc==y`ou3B6cx2^qakyzE|; zd`226UV5*J*BVO&VIa9ZPt>DJPW**?j~nL3IW~$+?ovd?1YvR=9>~QAw^iHt5^WvqK&y@C; zC;VaSrh`YeY(6m7PP=Bef=0mgjlFVk*PTb1KVH1}x3ibuKZ`ruP6W;05h^nEt~GnI z0w4?GY>s`DUB-Tk?P8t0?BZR#TakG;#khb-C_xE)eXk3+Vx|HVIwsr3&w>v(h8nN; zr6t!i8YdB=2OI_2!<4he_wWhu+-j(Q1{9O2zw7Y(9!=5Sq z!tbR6>HhlTsWU0HzUo9{)goRk64j#KPKT9ya1pN-iE0r>xx(^AX033glaj#JnW+FP zHiqj?(ub{>-hdZBs^|5k`YQd1{+{mi>QVhgeOPCs`s+HapF-FK(7rfK0fed_-wuHV zXb6T-&;tJqx8 zXt^dld@`n;uGvS-7G1@AL^ttB-Nd7G5*&4vbm^1y%41w2gNFVoG;1gWGWc8YhzzDD zo+eY}DJnicfd^&k$X88BXL4;#gH3e4sk@18f&hR7rP+R$Y&p|jWhCvmzz={6OUDmk zCcH#|z2xz{WeIa7%(4a*g<}mmy>MFzMoclcIzV9x3H=6`D2^&I|A?R)hOM|&c zI{_l3JfwuO4n7)&76DsFzy?Z3rlBtsJ5#{NP}>K8UHckS&s;p&zI;jj zu?+`a+2Zw>5AEo>KNf2!Km3d1n|540@a8*sS;Yen-goD+nt1Bds~%n3y1#Btdga60 zp)NjIgF-lub?KO*(YNfe;BhY^Dstf|dXp4sIvIaG!bHZ6uF z6mx0XVL;uI;kebP8e4wK#M7F77rkqnwnsapeMgfKD5vMN9&JRsq^TMwYmQY~k*vk! zqkfKATG5Y{CIZ!q3c9GtIQPR$ElIPYs?^St`%xS(?(O^^lM3`Z0s7dz&Jlj11*RO~ zy-db^joa3AIu-Ev)i!!HfbUI!WHnxthn~2J&ozH(=YqqB`vwLg>AKlJI^}-mzURr8 zpTgSC!qZPpJ+o#(g2(7vfMw%yEj+z_7$qP!bXJfh$w(~g@VCwQ(QG<`=jxG|i6b!s zz}$l{p-e0l54fF32(J_6rCXsiV;oHOLUyd^fqzO8RDSg$&~S@QhtBI z7gTr?O8B$s+A{7vXQB+Jy`{Ox9HNO5vTIw8MN~~!bwvjwBAeyN(!FxT zZAg9nqrks#ZB?U4%{)j>#)E?A4Y8QdrIxNMUwEP2HTn&2*Sd8_@96(Q|H`knH$FtZ zJJt8}r&`x-`1TQ!yEO*cffPwMAUh1d-%H4fjhn+j(Gk;CtTLofUBN_|%gaw`NM9Ru zuZ==!aJJ*GT0YpQU{vkp7{_7Rc(86^7A0YD%=xH}*0LOGWGhiC+k`if4t+E2#GPb^zJu;Vd+}bfU*AXfvToc> z9+Mu|j_6O&AEFcV7<&ml&t5@;S}%JI{fdpDE9?XGCw2=>vIVdl7Dq8whiX|9YeylY zO6bS33Y1E=R~2igupYj2#3gd*@H8?cFqFrFpA&MHM@5_^ieeg&wuWnIhz)F`>CrT5 zXlW6tEDxKQrt2xnqLeZu5dy*_iZQ$h1IeQ6gkV);R6az$ zq|@MtK5lwZzM~3fBC%j`QzV1&PYOGKemylOp8jCCuuHC;I=p@N#&3`#P#jPlDniO2 zREIBD7OP_z`COR_^ic&-sU?qbx!<$|#ohpk3NtTh7JnG&w_WiAP%EE#p*Uuqgpmnq z2&)c6!!lLgP^O28%w&)81MfD_dB8fOqwdvF_i}oaS04{BXPgo(@Mb874vgY@c|Ien zy?ec*p5!G({)VQ<1q8~sCmx3#I;Se@R#eX8aQ$I8IA?BFR!tgF%W0Xf$VgTVYS_B( zqKFjLD)e%r5*%zwtJl+Z7By;1^*ii4rB*f6*63}<3a8au?ceLH_aD%{qHp*2tKZbV zt`Do{opb)*)myaA@aj;VHP5bd=J^fLC8){Yt3RfnkdB+D@r&d|7Pr1~#fVW|9#O)b2YP<{2nt64Z2QJLY@vb48RUeC6AJH0ON36FV9hFaw5C?@8=q0S3g+mN1wFF$s# z^G}ie;aeU?B}D z;nN{Ywlln&J;DeZBA*XwyN7psk9fr6M~185ZOR^KE(x0J^Z>pYx!EZsQQ4Zwd_E4k z2EM$>^6~d(I?FA6VClHjb)Fcz*L=L;KDmRc?6%ztn(a38jnDbk)-z|r=6)+_CdtpH z$3fGMBYXN%KU(A@eW+2qr1aO()|1@;9j8xU>eUuuaiVHNTTf=)7IAjGS4$Sp`fzr( zI14vA2T~C34QO@gthR{X@hnJKXauV?$05SK%&-ppD z05)jw-bfBs)KMa{2RW2*tq4|70E)nqNWej*Mw%z#w!+Kj&$P&yGsCAEm!11*q5tJG z^WOr1`Tlk9b+T*f#2cfe^VS&Y8u<5{fHV&9(BA-QT>OU;56yD0p~{4+M75wI9ihmb zhO{V3FA)6W_}Hl~%c-1y?k>x1ah{c*)lb^rb4HXAbwqo^p-vdfC8P+QWhLB3ywrFU zA2sv_{~ozR>o7Lk$MFev!Wbk&=Bvi*_OIPB=?eX=^?UbS=HG5E!$iL4#4QjODn~b) z&m0vI3o%BZM>z08B>)WZU3u84s*Kj2xw^?s46-B=tugn=d-bQ84tPXM#Z2b6aRnFxY&t~Otbybdr6}j7t(~FhYSB~UG&+^t%5oA8@#%s zkcV|u71l|Ag&IlVf0SyZl0_ZKkSfX?Up3T7=sQUx{14mJ8r;Nnh3~zq=W4aPTCHTs zTCBB%WZ42NjASEO*w^6^JB+buZNNz#LU0oUpOn#7|gwS_89lOLB zOdyjfbf%AKI-LoHA1NuFl7?wVK&Nh}A!DiMu4LIEv8CO++CAUi^PO|Qdyb%&a>ZXC zue@35`=HV zQFs+DBmu-Q;^0+>gLf;6AUG@x0BN#D>b3VZqK%W*F$uV!>Nx44j#h;#WUcbPLX>g* z$ax8e(9!_UZW(M*T}TLB0@p1R1R}r_qxBMSLt4)T^gSSqK;GmKw2P2LFwFVniQ9hp zcK=YW(kJJP5%RIdVJf3+kV$a%#l=!ey=vqSsGbOF;{&z1goMH!sCX)woUUf4YQ$tqSVkeQNWZY=7^mw&Epc4E(}Wd7No%CXsjP0}n=Z1T+)Ufi>TZ2J5+BaifbomDw8(4K3MS0Wyv zPGy|@)}TYc+hy;G4k+AiLkCMtX@z0<<7AcZaA z>QuD{TN@Wtdt&4V&#%dMaRZaT+_G~c{^#qQ&GP!UC!gGHKgr^p&aWhU%pamUw3~K5 zD&d$Sxsrq(tUiaBj3{vM)_75EU7Zk&=xz{V7ie!#9}Xz4h}oYBM50{AJX}|ki4ND* ztwqNWK^x**2Mw{!!pdNuN%+7x3#75mE(hH~E{$0~P;}beLX@T!($u(MfhQcYcw~sJ z)$8>b4IKNaW*#BX)ulVv>BMZG-@Y)qYGH72i9=c4|E={VTie>;!l&oZ9zW67b&>(n zbqKFW^*pmk=1(nuDgR*UrtNd*y?5hkWJ%*Gx#HQk@Zh0t!o0tnUy1v`dk!^RL>%5r zeb9)UA>=eS!Vzu!Nd5smy4R8a1Ot zEH#AkYhos*y=j0Kf6y`9^=Y8HIBNAd2iPaJgr$8N2$)?7}rf4*k ztcgaApDL<|;`Nek4-smYpIY<$lV3Q}zH1{|u_cyuV`Tut9WI{%;o5cTO-5b8!L$s?g!rqCub=uny+OWwT(@vP$*17=hkQWD~Y1n z5PT~-id%3MY8Znilq24ENi~FI-~fu_;+`~yBrhgy&_(eoRn(*^479TamP(beCdybJ z;Z`{MsmzfAR3!o$j00#DsRg+BP$~uQN6+M+Fz+yb2sTl}=Fj*IP^b{~W0cSnT?wu} zu`h8f!6i(nJ&tkEW*GMm!TZqn5Hj7d&H>w)VS5Dk;EgCoWhfKzAEo;esh5t!W=+QP z+&N|~U1a_k07ZoF!i)%dtPLCwkbr4Czso@P&tQwaUlv$){Z3MTJ(OA!rD&t)(;~h2dYN(GRS<3U4 z-mTgF+51^8t3BP$@~U-uK40+uXJv#N2EsyGMLMX{Y3c1SU^=M3GTA{L&g8z1V;!VJ zgNEoFbMVm_fbcgxr(7BFBXkoGt5}9hZNWCurWJF%Z3d&vt~bF@npE>fWUC*F(Zg1Yjrm8D-2-q@UIa(!)FtQJq}|*cP8T@2h2mqXt5lsvHSXhlBKvgm8!-Fd`cHQbgZFh|DwI z|0l4vpd(=1Z~KS1M{qzzRMct-<_0GA;a!m z#G1vkn&dnJ*6<6g;c*|2`TTT#F>4mj{}g==^F3fU1X2QiBw!@C5d(bje1k9dW`3|R z^N2h%B&nf|NEVB7or^p{p$1~;Qf!w=bC2>Qhzo0+URdL|@*3rmm5PQFVd}f#xiFOs zkA?I9h85Ylzsl(!y!RUO-C|_!HvPH$9uLh&?-s1&m5Q(+>5bKHAqlREjm!CZuK?tE zzj$sF>OPoZWY6eP&I7bDNRv=-7a#_ZV6mgGCey)`~qSmTJi zh7!T|*RL+w4im(U*`GbxBneR%jWvRpGXbev5 z@I`|XD@SxNlGGk}g)_FJL$cb=&7^W524{#`Dyk-0i8B+CRA;ux8jy&k;mMtk9iJT7 zIoaFY(%jwM+|sRhZ{Yaxfq}{6kF|7nx4;fh@yP5pg{I&#@}LmjE4|3^W`U~3DaAv^ zv>|Ovdv_TIghA)Q;3@A-eA{rF|H^a6`&9|sYHxS8dD8Z@GaXX4t5&n>Q2++UaCRc|-z_4Y!&-c)E89gI@1DRkH^OqMz=)hm@cn;m(p zN(2jIV{}?t&}j8~rH^rxiawLFu#j43(&%*XZ6?*&ZAzFZlRbR%GA>6pEIci1en_p3 z+_#MX>VVLK&`u;~rV`-vqEqk%9}K%G7Gq_$yR_gX2yh8f>?0N6M->9g4yl-IOg~2}$`K12sece6WTaLFq zrU%AWNK5G_XDIcNVe_R=^s|E=e54NJ_s`7@tMG_t_KEQGy?kGW-f->7eeae6!T7l; zMFVg$hQ5^Ad+Qz#?+?=!FE%p`wl*6bTq61u#i1CY>4JKSrhPuYD}bR>g4J+ED#eWz zJ1VG(S*Zrs1S41@Ig6_`L{4k6c;b8%DruI=g2Fbs*f;eqv(}xZ9)8!Qt?a6(H)ipe zRO(^NS&DTm#ng%7F4Cwv>btImejWN-hz{*^2mGR|@h#}$_J&i3^DfQaF=d1Fn@-J4 zr*hMAz%JD>HJy`f(o7D{=fdGcu74&)AdJqZu6)3G;H==HaH=1rFeEF_O`loT{&+*@mda3=|JW6cwoW!R zZ`#jZf5mHhKX=rx*BL&yH=`0U5exc8!7qOzKfP`b6qcl$*qNy#^w>r7`YVWnrsjBw2>Y6hLo7OZ(BCqamaXghtw^W5!p5CzS(5g*8 zbl*R)eE90QQ$@Qsb;qkq?|*4iS$ue9|LRC|*`d`B9bJ13PX)G=#}bL2Z`VdT>l3lq z#w6)8z4!)|rhfr--F*qsc&(&YD}U)hLHHbK%mmh)%0ft5hM1 zuBuR$E2F5aRP+Y~-f3cuT1^!Q`AVSx11Yt&ND~!QuW=zCw1+ZD$MHW0$t4Ii#Xc@O zH!a&-GLZDd<|1wr*T)TW3h1uO-bFRFxYm!db6;OD8sXyI`(g0q1>&J#@J~rYCX%-M zLR}WuzEdYF0OFZ)avgyogfN;S43|kBCuN77C-_~Gla`>5g!NAtuSab1!5BZFH(t-T zgzEBYi1RHYM_GnG6v4fun;LF$;? zJ@(>M6)X1%Ad{ZDn=W}`iTARLY&F%5R9+u&?91zKJazUXU#HE&ZGNUq`uNzB??r!5 zxw&rDqaJRzKmM@q?9Qr3UrpFNZqM@dwH=w!j}G*-rdt2Yc(uSb zb)DgJ&b`;y_VwfXmBdcsx38Tze#LnbL(Hqtj4Tx-Re6mp0SQ`dA#G7byDrfP1vRVa zq@WGT23u&8GLTRbf&=Me4HU|>ZWP*y!RU%uMb)J+DaxiUzS)1SLjko@ccpXw|5!)Y z_W8f_f8V$Hp_-6m!IQPMso*2WAM-BQ&~t6ZgIL7Oe!<-Wj2Mv%RiQNAk*?Zr?#t_Q z>~~%@U(UPixaw5DRW=qOQm`aa5)UT^m_gxn{b=~z@JC_oCUra!+ZcN~Mq=PvhowkG zEJNDTu4tJx8ZC>Ig-c7gXgpEQRK*jaBwedxB_)-x=R|e2+mo)RyNf)?yT?nseJC1> zRW-S>(cR(ha^H5d?!E%pFr*el8W2-QgVY>5McPml=Z&)I>dGol)f=#M;|8QdMWk(* zbu6;dFVNW+=I+$goK}F+Lmg7ULX&gMGqt`mMG*pWF`J^qldX*@eNRCIh=*_|#R0C( zVW1(k00;bm`I0$ckO(kpo}>+^Bu8L@udWQ6j8+eF;UW*t*Fa|HAxj17%dkZ+dT=oV zlT9e_ph6BN1sRH@xc{N}pcGfmnr&9X`n-NXfZ3n#WdSN?Hd*dBS5^=|$kuYDxAGJ{ z`96vkpU-5<2}(%G^qctc3+Lp0XU@p`&i@`i{^mjX(vbmN*58lIUVB~sK+ebcd%9P2 zZ3#OP%i0euZ>jJvZ9Mqos?f65z1*boz_sbU#_sbs+4B&A8 zVI1rK&u2_oWNZEE9<|vX?>yN3bE!xk!0#=o@z)k1<^fF2!^yO}4-oZ=;}z#?fSp18 zSo|^|>nb4Y!{kR*hOKIMhWvKev&$c&F&@Ry)1(!JQ4L^2Z1Q8Hzr)|M)K_0SeRmAIKW)5FLRw&4VXP)niWPD_wq0zbJkWydHQyizNvJ%J>)){!IQi*)LDyP3PY~ zcjiYQJa?7!lF{wkvkgovyN&eDTqH-c&15v&Ksog~dxSJ`?*Pg-jUhaHemLJ=K{B&% z)5t(fOOSNoZt^i^I+!lh#V{SH1Cu8F2q6eDB14#6n8g{=Iz(PzGGx^WWM{AB6j@_- zDvRo~>!~$e4-dcrekXH%=RdBoM{t3Bi=Os;cAET#}Wo3 zKE)nnQX5bQ+Jjz3hY*J{#6PUwI;X@Nv(s5IC$Q;Zi8*m$sZ83EFy@bsjkD8#fCv8T zcfn)i!GE=&i|L=7)SnayVl7z5uofbyI5QD=wUK}dFc3knF<_mjHe#KLGh-d-9$ZfZ zDzM zGLj5{0tUYQ&h82MQ@rt6*-L_FUYNiR`M`GkSNv;vF@9qZ+XnHtykt=Re2~@w>=gg9 zqWCOWOdD~5-lS?Vh!&$k)FDe|_Manq6KR2DI_;!Z)?ze*M6m*hEJn=e0QF8$G?@^F z<~5KGsa2el?^5qk6SW#K7AJx8&^UF1QHRv5#;wztb)raG%QY_;*tOoP^8Lw0NH+Jdkhq-O#2!YRdnebtQU z0V+2NBGsZ)o6^hmY0jl(bM6d?5?B&i8GKsHr&8fWJc*Tic6Tt?WAb70J9aqhBFD0; z$jr>b?1l5#fp7kdJ9SK+e^fRe!vpeavWlDnWUrb%%T023P$7~~9QUWYOHe5e7#Wdx zk(a44&MRChJseybTB%v*St&I~w-|PyZn$(in4ZF&MW+jA(3eu4P{d0@keSEMk2l~3 z_Tl2C?&ZPnMAo9U%<7^R_iE4D;L4IUktgsL@@%}9>Mo41W>A@bOV??&surVL4KouA0j>!uk^siIG$aMs;-X-j^~UbyWiBF$aTB(}4p)Yp z9J;$yp`2GeXM=$(JLvRy>uww21VRv_K2VJKW{C+;j>H zNW_VBzE`rT=vJFb(ZM!svnSfu<*s`;+&Gy9np;1et7zjK&t<9Bg{mRb-5yB;FB)k3 zoD0BEa8(wsdu$AaX0MN0Ym2U^dkhmkJp?o;LYPS(Uq#cO)aFR(tucw%@NN z;B>Q-ilVsdFyM^AUMM`IP!R}<@^H-QHRo|!jTFv{xR94~yKu}5nNtf{nXS}?Ju06I zM=f#Jf4Qy};3lps`rg}JNxLhpKGw%t8C$k~mj77zBU#`j7;p(Tg48sob#W#(iH*Ym z1=9c}Wa8l1PGTIG4wSYDnGk54mhXUS%9Kpa)NM+e8QM&nnM|41L!8cd(vRcDAgz1f zO0=0uyL$KSNP73(`|dgCq5{K`0)+mj7M{c^q>KrY`wOaF_*L_JG zkc&MHiT0jrO-I+aCmMQQI@vuo)_wB!*P1J$>!0drU0NEOPjr^WS`yK2rfi@jcH&3< zgPWqI1LG%m?*fJ#tS;QSt#@Z$=y+FjQ}fz3ih`{Ou}=0j5&;KWl?t917_@^dFgwf~ z=FHN9(ZrbqqhW_mSm3Y;?`R}P$s2?rZ59pD=R2kWpVRRiYwQ|G{&7Szk;a&e?X0_s&vQmm5KIzarpY9m5bvIGI#~yYXV@e;e~nu(7z%9Imc*Tk*J`y`1c66L$aT5w z_MCbvVHllGU(Z|OUMsdHF;YZ_L-rvdUddyg&dnT$EM~K=4Ou7-q9k@-_E3#)nWr2^ z6@5B0%w=T3Tvq-xW~Uv%W$LVE&uWz#9i)xl*X+Mn6`cz^}vIruI(ZqNN^J1GasrZijgn{yyBRM@Em6U#3%!KT@*;KS)Q9kB+F< zK}Woy_AvL^Aadi)%JO2im@9VHv-Lt$Y-XE7u>;+obN28??TpQswcAj&yZFo5xiB2vYGJQ59Jaxtwj z4x$`HDFsm_k*9@L?(`h?kPDuh9`b?bu7`Nc#(>ErQIev|fboUqfo9P4z({H9X;0{S zV0@+t6fpjIg{BRRwBn>I-Ief7=>v%%$tzuu7|AUsaqY!Krv5ZRoY5sMkWe7Cj)%0C zeVU$zoX$d8qfwBxnjX>8X7$zR^cj={)gQ6iofIHzYpl%u)5{`jIv!K1VwWy0+q*t- zXc-%P@X?_}ez?%RF0FDm)D@qPef9B?IeZJss($ek<~DS;9uz`-%7%TU-|_AIBMz1~ z@&Pf}WbBf^mH%wuKya801Pt)T{iDP~?(}`-%YkdIhAe8C!oKA;@GAsanU2UL(0J39=Xy9H~Ys2ph zu9^Ji`U3@(#JLjm(yNnzq*m@h24ti6~)U6phFp!W4xkZ7e#^P zScdcRf}Q6D!sLrd^7d7X2&h;9t+y3PZ;&u4*XcKUP1wXvkQfrkE=A;#Sk8M5*s$4{ z#F2~N$o6nhgR=nr8V|(pQLzahRJI$S3}MXG43tS|4pbYaWd~R_!u}!UCtK6|Sjz(o z=}VvC?!1*+Nd5Zsb;i!HbQh;#7yp7?=+O$Lh+>IeVu71{h_DkFGZUnb2Mj~H34OnT zGC6nxC}5%8B+Ub0LStOxqa4t%&^r1~bDMsis(6pP^Ti?E?-$DG8t`Jf*bqc&rIN4H z6R{K{oq-de!C~0fuxtV_7x>qZ+c^JI@?DgX3v+RLhUc|W>tWJyx;x-IUuGezkL`N% zhPwG@ud|^aruH#I^rovV`bm|3Eh7^y% zV3NG4c>R8#P~mdP{7+mVcPM8(9Ks>gU*z_dSNx{%6yRiOWh?kIHQY9w` zluA~r&>Ga_h|A`%L+koq(UMUtA@VCLANFi5uYR;96u8jKaOME3ysoNG;rT?w|>FHHXHRZKRUSUZqZh(5NB!45nh1~l< z{f#IR$`^zF5;15iFDxYG6XYP!e!*3@Bh=``&IytP*AFT+ZY(|LU*eysTF9?2TJRR) z!k(iMd^mD5LOLTmBSeWLA|&FNp+5?hgt?yTQ!i&~7YK%y>wE{4F&rF-VtTG)+L8ul zp$%&`jwzLoK!_I=A&?ECxj zBh|&YOmYIO2E(z|sGTafaxzVBXjSe)t1ef%vF!!~Mu&8`02v`3GSb-*c7&Op&)j&Y z`>>n1&0)SLHw##><9Vo)Mi3O1S&COUn`gQ|S5|mZEsFP!T}zIRC9jQbe6o8(qN|&` zGj-wo)a3aqQ!nm*{?OjNFYMn#Yw0wu$SGa<10=!NNyuq|6hcB+q5Q3*6hbHvrn$6~rqI$Mls0VzqvMY@ z0a?`*S}Jv+5E+n`QAMo$6Vk+_QEg@F+^o`Kw6PN72K_bRo>JHU>&~Ckj$xG-?k6(f4z~vIRDgfaAk8RzveH| zIj9~rqBi`pR^OCtn%`d4nOs%XmFzbN5pB9!7iu@OSiTpUJAXA@W?5!k651fFx2&`F z1YZ=N4-bg;itOa%h#6Mct~4>WVT%pHueG?DQBITCM4Fmht+SN9@u4`0$7iOL{Vv6y zQYtI`LaSn$sURdm`e(@wP2xCH@vM-&wkZ@(Xz?O8R-C=2a`wXFPDUni9W8Ihu`k{n z-xKHJSv+<+T3>-`quI$X_1i}o1u<}f;0qm`Ab6lz*o9(rdQ^+TD3mF@%nrs26MCj}e8)0H z{~dnH>A7+T1nCYtLUDrh)T9f0_(!xrvzS>&aE|{aM+Msmz+E|qFgbGR$_-*I1iXZ4 z5f12vQurTz;xEj+cK|y;#J}>@(T-<-_wq-hYllBQ(2F_!!d2|kCt!Ugq0)vhQ3oPZE8*X6VE*NR2_oMdTnwT z`tW+>MgbHhpK6n3oYSD9>XMMV6)ko5xQ$LXE*II$iUhDoC4(X=HpT8#Te$@#?P9xa zo@ZfrmE7y>@%E~N@=o=d?6AwxYA!0*s13+qM#Y3$Wk3hpxAb55zLhrFW`~!0&Jubv zb_?Am-*9w=>1kV6cu=Lg(O}7-I9N_^;oI^<^pMa?fzQ$B+&3z{gf5YPQtqhjr-2W- z69Kxt{H4H4>WLuT7}yZ(FX-nw04;(3pIKj9Y1k zxy8M}+geHc)vdvwi2GIAW7_Q8?0r^!Q#IH*HK-*@ECADTK(u0PweGMG3BCt{vPvU9 z65}x9B7(JAEU|Dt2`R3UP_fkla)7gB^(jSh2^I)OLV*5}3V}%98rtOEp(v{J_Qg2+(+ns8INE8G*PAjhCcKe0RO*iox55$pEGhGO?(9E$m4J7a%} z(U`A7LhMG8F3FOC-9oak@g>Rzm!Qrx8ynmw-IVT1@a$M}SD(eTH|yy#P_G1 zLkB~;9DHnyX9^$85Qjxm`vFTl3bZL$8etPe{Q#Y<<>?h?fW5vrX-)>9z(SqX?q1Mcus!l?f2;dJ#cI3Xd@gKplCsYgiO*APrc|nQI;pLy%&O8X`B)1Of*Uzr>T>q^D{uvBBr5Gv zU$=Dm%W?VE;E_WNy%{+{qZ4(efIfG>k@=vSoXs`mh1iCj!FmT!1}M;D^D`^qni4VS zVF~ibtLL$|bVkLw#CtD3_p`FB`yZEnKe=+(%2{qg!&k575305wbfg-h@2yE~JhJzY z^YR~VzyHk8^PO$oeT<2|&iCQp=(9GVt;0NNS-N6a&}UK1=73UsBbO3zO^zAPiSe2l z)60hy{d^G43mjj38KvlKgK0LGGBz3ve4}5$!sVjk*8(^GUdHkf<~EVbiMbp=VvRU4 zK4bdAB`ZFm29pu97Qb?(K1T#mn-R+N8S z3}Gs_CS1GvyQ zi12B!p&*i`KnQWtmdXu5f{0X5)HFhY5U?X0S_zO41dtmNP#Y;tO(O!d)fUnqh-*ZsXE#2DphwZIAmUFOP zs1-(%Fv&uh-CU`p{F!iNMMYI6TU{*^8t{{duOd(tq;Y>V5R62ViHdktG@Yc$NF5z5 z)L!zh{T}K`CAz7;qcW9J zdCy1OP~YkEF00P)u0f*s(kL(2c@K*|)E@yL%SP?`C5O-)>|C*U3b}%vD=N}3e&(Y{i)3WZoYVa{BS*W4L#sga~KF6)1^hwLO6XB`{q? zU?K_>&oMd51VpET2$T^)V&Zh%t49z-reNqt<$u7}K%WJGh$MfR-1oF|%367JMmW?X z?zL)?M~lgv3=aZy*VEGxa9wGuDrk$9fBb}SIgOYgXC?7MA$Fz?c`yZcq)@|M9h+;8c&!*EFlGu)0{iZ z0k*Ap0vfh&0N2jqX&ASYs>QMJ0eny#TWYy=x8feY7~I1qTag%bhgrxifXw$$E-IdT zo8T*!?9%E77s^{ZHMogh+{8891RqCiXY~O#lu@?d_v`nejr^bG7gSvTt-x+7;pZ^WgMYUkmK3tQl%ORaBUDvzeuifz3AG@93z`#I1A>tGA zLo|(NkAO@j!ctgHl830uO`s^jyy_)WGZfULG)YFlQ!f$DC+o=Fxl-S~xqpVa@ICUa z4lD_Y2S%5w=zAm(BWyw@W|sv_7%;)K%ZKDmTT$~S%$mv}TI=d3xL(pca8>-w(OWyH z_Z;fYalM)Mx!wnq#)mUUsi!*Ikfn>VkYz~94xzrLCe((J@WQ}V`IvYC(?=!jv>Ww^ zo`{*TNjTo2spwmTj8wG2y={WlrZ+a5t1YD5h#T?CgvmTQ5+*1HAbUBO=Gb^ zjjD9noZxqBh)rlCSxl%&T6nhEn1*ybje-4d2gxp-$Q^pU1h5~#*S9c<&bWCQ^G#Dzb>{954=rLNERdLe_~lSfJkFMbyfO7= zxN}Ol_%5)k!swKe=CE{7B}vn$OO_>r{DKOJmZ_m!Z78Tx`PiMkFBfkYFYI~+;*bZ| zE3Bb^9i7*|um9+h<4<1Q^P4ZO9yoBZaIG6A!nfgY)Ndw!g>T(eV)(u+pU z&MtL5?O$BEGQDzSb5>heJ10+Pg%?CDBt3p)E?Zw)o0o}iI4RSse090%_^ z_`C)h&wF^*wJy5Rwv&~T>y=BxsNxlc*FK zogec*Jd8(5f975%lPO$wUSX>2chXd$sh}2kt8%#CbRSKPyNmltQxz}4B$y95Wtk%- z!jjYHtZ~T_Pz#TX%tfC7ro)UHd>IjXBCf4VO(DB?|xJasJAmCsa(}J)D z&c6C8$F2m^LWgb6mukLdk6Q6`hZHOuYjlIWL8E=HKAo;~t<>p!*L2(al{m3!MyttTIx~ucREu%<5=obd!}Ql z8?GBV1sC#_OY$X+o|n&S^tgOnqwmV^YILu>SEJkHZ5rJyZ`Npw+@jGXt|dC1?V3Gk zseo5uM1Nc3w(`Y)W7gz0>M#74^>Po6s=DL&`JMYXcXyNB?0YxK=H|gJA)6O$ z9xPdsi#!x1NF-8G(-sS*0UF$(Q)vZBl|ToErwkzsCh-qSJGP@F&;+%%TBNoO^d-}& zGo98Vwe5sfWv~c)x4(0DlPr>PI!=?>dw=Ji-E+_Ro!|NWKHu^CtR1H5=URNvpVcZb^gAQtFnQ^D*OUoxM9*5h6kD$efs;yexx0Kxq z%~l}6;7{ydjK0b)FnW~zkkJR(21XTz!Gh}q1QJkYZ-l2{F9=4oxEYRRED>X(kjF&U zvCWe)fve+-YlBOKFFD4;fUjzNO?)|-yFG8JJ;pa|5dIExjh%f=3;mA$mC={j8;pLa zz(Hj|p_`O%EA)P4jY27^Hr%iD_7uRxw8_L?7@Kj+G}C*Knqb=dWIRZDlx8~o$*FwH z>&jAS5T7>X$?*o)zDnnrZVTVM^t|S;eV~PCsChhpl9h@ zs}enlBXlhiW0Bq>T#?>DVtm*j#y#XT3dA|5C;+9!BeeJyX3Q(LIFT7gh>D173s=|J zR8{@ADyX(ckQ?LSm9@1vri^sENd60s8B2``%b3t{VG&Eazg(9WaGIFX%G7y z(J;Zgj~f`C9Q>dd4-h7IRwTP!Uc7mD>8^LnC51w0dP#jGglPb8jv$tKFAE8t6P*j{ zXPfEw^Af9YJDA{rpyN0T7%&6CZaGcVrcrhK) z&qBi?YSW`|4&F+?vB-F1%_$~$1xon~yrOhn;}{)o;wJ&f*D5@UCEIUS{9An_J6{1O4GZ}Whux0S zQO6tJy}rO}fn-1k zj)ZuWxYV5H=MjQWW~XR6mc5HhX$Ua@ri+_!Z?ibF3rq` z7W@TIE;I65T0~$vPH9-4j?ui-wlwEjiX)BZ&8b2XGg3>=_*Z!lI#M!Y{$|Z;waLuN za`K2x&dvioq+MMRdr57iwk8!^NQrKD#9dTj&C*!WDI+_zRUPxQ_TK(++K9M%UeI~aOun^i#Vw)){l$D(sAM>Jz7h))hbDH zA!At>>PWC(`>QebZqFgLSj-BDdn*a%4C^R4G%LF z8eNZKW#tGkzU0YxnlP{OMUyHXiQF1rb*h-oq`-cqU!k4KGYZyV_$`AW&PJ_lHIiG3g^+>_9`Ydz;Tsg8%RnJ8 z6iWsPAqb5bENX!J1P4Ki)Z+2TR2-B^LCE0x2Xv`1H!r!EW^keq7k!t#dmDcDvwkPt z&-SPBdlTE_Oac39Wwnd8Dy>s6xW!=b>{u37DBdnlF&?gJ0>QI5erHYMH|*u>%n&OR z06s~6V?2o@rlN0>sZ>ZOv_<}B{GJlN83`tT!QL@g!A1&58HtjGq!qSmmL51P&_M;L zAPm!9&Bob`ARNvLW2(<_zC!y*HmD?z_GuQxvN;R{LP}ePY2V4YbL(Ek?qcjNC5!RF z{P~sme5lm2qP_VQ+DkMzO%~DKlXKS1;>{p7!`M_eczM%|%^cc0D7N3fVi?8-i;jNH z7Y<(=ON@DP*SW472;Taf9Ig5KMx}!3@V+&G@4>Q4Tsdahq-q1b4*}ta_7RuDp@iQFVVs}6(ZB{QeIZ6l9?gA6i9h0_)K`Q+ng%#Snxu^8GjI->aPph zID7%mQy#ZVE-4PxyEvZI)z(bMw8iAl=#oC;R~lXUbmD}*>R8vd{@n+*^*?*>yoSPX zd2y_cY}>Yh$)^>?4g9HcAYzQ`t_fkJ9D;YT}A9@Pg7N8 z)6Guf*_$J053jG7+k2$3s+|sJI&zQi=e?eqG~p}(cWjL#O?w* zkAgdsZ98iT67lndi0>P}EKUD%J^r#xbNrX>YJqL?y2AI~|7rgZzwO^n9NTelpau-F zlQgM`|1@R5z@ZOd3vJd-gE1wH@z{_GZ9}S1rb)D=Vp=;IXxeVoqOLTr&d^muFtJsj zu4*^Lq%o+JLPzVhnz9T5j(6_0(*%Yi|G9~M&bi;c=bZ05ST(D{DWo1%NkV;8B`V1k zilZQrvGW-9LS1xji`U;F`hJ`NACVyfiuQ!5IQ=Q73gVhz+wA!9nfOeR&n+wR&7jDa z4HK+WW5#H@X;h}zpYC8drJFWK>Sg^4oxH5Sr4t<#oj%5-yKDBw;8lM|gl)JNb~o3w z<0INpjr>sS(TJ&G4e;Gy__SGWw$Z6!KOF*?hxsLZ#iQUMK7=LM(}>TXqQ6bOdQK`K zVF|CNPNW$pC8Whm&_X+Ac{x}7BY3GBfx*f;{pIOtMzp|v#Vbr3ZzfYI-VBCPJpRsd z3aW$dhzDQw?9@uWo&jG~$e?qKOiFW%^3?{|$)$BU16vA47V?=6K!^~7m-?BZjKLe&A0*EUCy|I&m~KJDh}a1s`_KlSLqb|y!qdxe zSkx510d3%VaGLm~UjyIxft`(P!9Qsf3UPRX7D?v|o#`}{SW?uLbVczux4nP<#K&ia zHG|lg`jp}o`BUUIVG#7j&rQcZ9hX1cO>ad5n>aZ8X!>Y-3jBTKCQHG?%(hJn$iZxRG3(Nq5K?Is8k%Ldd%}pIG z-S2K=HpZ@Mm#~Xl|OUvAlNSC$H)^x4ryrR$XbwqpbJdZ&iC+y zmt+|s`5jOW610mWrp?6f@}Gw#zi#L8p;jXfL%>A9pDh#u2AxQ$_)m0}#!?0)R-5!v zV1(?pz1XwoMcZ!up|3sgkdS-g>Ag?h*Van+{s}*b{~-Jn_Fie~1T;$;gEBkA|Ls3C znPAK;_2gXCZ9~i3l*c5K3i6V%O68o_HQsVCgGj$fOxm_HqbU5QC{g@@%65* z6)U?|W#aKn%lvpoXkO9Py(-()y*go<3l^9eimH3+VNwaZ^PtvI#iBM_a%5~we`z&* zlq2hbRh&bY?Mm3FmOji1!<%z1t`96XS4}g>94h2@2iUn3TMwt<*M_6+|p{ zKJ|2D?Yidb9;;t=yshm=Cyv&Pq3&R5MiD4X8E_uCUdNNYM8= zJB&B`L}Jm&una|Pax{PNag_&LOcaCRaOYIveR2fK8(TxTv zY$P<@I{?5EZn|}F&^q`YKe{~oX^=#;rUq;1vqXeYD}w4x?b;0nhpw*Y@nChuXZ zVl87ulDw3mH2I652HLd-$`4Aec#UxgEUueDU56D<8AP$NkKL3s6xnVU={KfEDPCCI zFdd9jl(6!F!YS?QvioO2r|3JU;m^iCgB&_)345bQazyt&_0-6|eIul0%i%5LABE#P z`gauO0gFCTyuyDb#ehW{7>i!SbMXe`H&y)QV!YVvr0kiRVNb^0nc}D1kZ=-g)|G6~ zK}Zs6vlVPS%%=VrsV-|2W-|}6=q(m!NjZ)i;($iM$Y~R$R*dbpXcSPG++SFX&T@<# z#F$4_mg_imUDCeOGSBS*AMpyd&|9ghf|~!`)C0JKO^^~={VpQpO(fxsNQ5CW$|1`D z;s^rKCLH09LX+PqN>Z3$G9b&AzeWaL0KS8A>4X!eRc|l-{0n%mP`C`I>xepB@Wvhe z{r$p6H?MNu8$Y}GPtJ!3Q}OE|i(D{2a^}J|Im#`nAq0gZRiZ#V?kX3OYieS(6)|lt zD+Qg^fxBD;*Oh&J7> zJ9JL;2aJF(z=MTAuwV531BmZN( z%44HAulV=Anc0~=yfd@s9DCwpy*9)SV6VMivl9XVL`*>tj+9kI+c-d=lqB4tGznK) zS}cnyDQ!t;qoxN{DGm{FXcHmlXx%o+9|e^b1yv-XX-uWavV`!C`@Y$=p;1-U-ktg8 z+u7s2-|xNm`+YwgzyC}2dqY?4-}EQdU$(c-zy9*6KRwxM2lgZ4i;&G}%zTVALcg_H z){}aU%O_THrI?Gye%vI~X(b}elqko6rbS#XQP&02BnF2Y>}>EcJZaIeiwg1Da3G~c zU6d!fY3Mu$M64C0xM>I+Zlz+WKx=>oj_N#iNuBlF8dlx9*bwu2<8>0#j0_xU5*%Fo z-N961Dw5SbF8<+Eyt5F${_36 z**RxkO~JWj5@%eK;z+R>2NbCmx4sN-7R@{)RYdbmO5a^O(Ye5Ok zrvGal44vKo^v{3w%r^#v!S>eP-sN_my|Zlp^}@a@AV5s3U9_xg-y@qJ9RJaq!^0n3 z72rHhHhkEXcQ8@+wPn}mji0xQ4?2}SB$x5a(DkrO(%|vI7R49(JtI-ig zg3gL5!P-naFa;)GB^;pqF1C_-D$MOF~u(he%M9IT3Rh z6Gbg1dx_ty!*TbSk>8g&<&zy4cGC#&bWOv-2lzwM;8q+8j454#l zhAhe|ktj~86emwg)vS%Z!tQo%s$~U70#5dPPOtQ_Z%L9O`2tQ2J-r}zM-D4#EEH}R zmQz_+S|dfZT1FKs6w~99-(6qR5SPq2=zcuJJc&3MKFz6#J4zym*>7jYhY4HixSov4 z-J!D&y|O5`aP8suH*WiI_wohp3)P=&-}#G|pLqP&_6BiTdAvuTc4XrDm+bLxrH#eq zTii>392)-f@b51%mG~Il$LF~WMq*e#T2F`}fX=Uau;PNom|G}z#k={##0#mj86N8R>X5ZmuZL4nBQD||;Ci_OoXC-u(yUhV^plI1uePEI)#LI~ zx9IY663# zw4b=~)qW!2%rn1ssTbdUT}$$8B!QW)1d0>}I7PKn@@ZAOf6(F8l4>kcZBl_PdbZZNF{51>b`%X9=CV z?01}(?YA6PM6bZ#gg;=IODzSa1v)u=iV^{ybCYwB9FVx{{5kq#OBO{5BzGI25#+Xc zR=ox-PPm0Jq$2Z~=uXOoDef_Dp%Q9qZ_lCTUEI5S&hsss=oQ+uEVU=JvAe9|ck6h4 z7{5D4p0-Sm_i1#S_EGdBZJgsh0vNi+i8Y!YFb3&55`*NcYE7o-2mc^FM?7?$6;i>B z<;8614N{Z!XNVsE+4?D?R32e!v^-k6rj*NSXJxQdHJYZzIMu+B!%77c2wO{JYY@3# zm#b1;%(Pd$ricnbOow$>wg@S+{=Rv0?+HH_KYH-FZ+Fdjad|B~O|NuzuKXa8ZEl^@ za<8&w!}bSOEbe%`yKWc8m!`w?Aja2Bwp(hgqy%e~9$AhEkZHwN&tn(@MwW%7<%{c? zhm0)-EgE33_#zme9tZiwU^bPJvJD>+J!@njOZ4fJL5@_SERQ;2KE~q2Xqj{x?*t4D zK?vqh=SE6YsbVJ6gAfGy$;; zmkMJlv`n9sE;h_duSlP2Jm2_fBNIO7=y5AeAcRD0%*u+&nSR0n<)=4$eY_xvG0haO zOUS-6UcLs&XenM_o&qGz7PDw_W{>s;CNK#}(uik2$zs;LO-;xJ!nyq!bC7-+i4(Vi z;q0`0Q&V=sbbrf#y}~8HL9R$XqPSF-GF@$Tf$}j(=e(Efy+Ms$Ag< zIHzdk*?H)$=Do^Ll~)bPCN-J8gICy9w?<(WaJMVrf3fTu-}A#;1MSsX>2@{EVVs*k z-{D-}0miu(Rv_m(UA~*6T;z5wmHCd&RqrQ}gxxK3<*!vp_(XT@E*$?39^a|rp%D|n zN<~yiL5gP8W;3tm&6T8=95mgg*=ue$QCbp)OPr%2j-v>K14%q)ssYV!r~y;>PfWr- zpO<>`0Fh`^kxe}u3h7^w&(YIo{J{XbVTPt5tQo)8XbYM*RrMhSlpFrGV5BFdfp#kH zt7#J$Bq<(vJ@z`BB_Jc}lHpomgt;F?g`jRw9Lz?`RXc=_;7_gVXs+=M+}HDQ4j~6)%d%@Z$ynQLpWg2K4ZJV_{A8kd>f0O zIN=(BH0%C2KqHw*bhgi%7hTY~B^J%F^KZ1o+i(+{9UUzKIohIlGc0D+lr8wGwKX>0 zF+Uk^AB?xm=~(#?V5C-^6KkZ68P;fNV)Y!O);34~!hM+yqyOC=+#5QJw*Eh9-M@E;pWHJ=CVRZ?Yk17o zm-``o;pu^a!GBEc>-8e92@j^VyQlBlY~XKri5e(OFZr!iYBz1LkEUXAk!X3nC>2?& zm2{aZ$a7+G`FF(Q6`7Z~v{z->*&|7|Z6$VxqPjf+Q6OGM_j(P~*xpQjoNH_^s!fda zqF6-j2#vekxA9vj6ru6CC8Kck4(X>(BcBx{A%Y~ubz*9Y+wcu4(UY2p0L|q_LAG;EiJfY)f1;5A#7zG3TW)V6 z-jeEu%}J+s@f>W0Oz!1wFjR1ZBe0&9i!^9?yon$LStTXD#E#&NAd3cRP$f98U~#Qr z^db=)XLbITFvdON(t<~PA95MP9hr88#p#)*qTuv2VxBbF0h5{vj0!`|no($aMmOj= zx`mX3KP7bmhkGHVwbM_3(35ZQC-eS+8oLYn`=|FX3Br15{+74{aN{Elbg#8{ow2(9 zXjte1aifJQo6JtFy|Uey->^bkQn9ppc|)((Te`mNiApzUr1Cn@6J{hqt_cn&Hk{Y& zebRP``K74TCG|-|l1&=4u|8qD!2Ci~=o0#bA;BgL+C(BNa*g3q>Wp$bqZ#&XtJNWh z4Yoj>_*A7qwr_IKlMZ^$@h1m!9J5KzFvoJ3BUjcDmvSaQVR;dlvV^8iuH^T)Wkk0o zbN44BdJ&n>_|jU0$n?mTd{7qTJyrF(iKFV32xi^Hc%3^vUB!-i6$bkCE`620Nf&ir zD6yK8Z@TF6vNIMi0=S+?@7#sln*u`4VuNrKi1Z7V!-JP>1pbet_-V+^!mczrtz^6m zXwzGlL>>(#6FPEh1)b&hgt@t2(%#|0!PEU$4t(^~wrfAybUd2<@b#zmzIx{A@0}8V ze|Y!q!*?D!a^k0Vem+EnXV)yuZN2*b@7}$B^$HY1{_m10J}V8uY1m+CEG7svMuaLG z@rjq{kLhz{%KLqS-jB18kPMdj#a~J0p+mr~<7_|ujj#fu-EXoKfj5bc(J1sQftinw zvi+l@faZLb5ZeaMMDQC8~2E3}4gLis)Yf)n{;?bXdO5nn1+;tt=xVmgmc(;UrOT_uxbqJ{!Kqg=|c z#a4n?RInJMq`HcPy36f`A_ux%iaZE&6PQI?tE-K=xZc^p$6&k+$0tm7tl9g2Io^k}O9!Kas%GVnol4Z$`rNs#&$R>$SYiBqTOmgUIBF8;uvl$V0Z;bCne?Oa2giS`6%=Akt;MvV*!CA*cULFQAkur3R1#YUJk$!L= zn!JWHhpa#evVKZ+O;efMWqK5cyGqww0adBT@>Ed1VtGO%hfD!25h;ZK*04GQ3RQgG z1y9bxe5wcQ@)Ib<9;`(Ka}hXPR6=ul2|~MOrWrAw$W;| z$B8AB;!^zr6_)St9Q3du&kYY-1rAqJ2@t8~YETu#YhlromKRA=5fO-r%-sT}0-0_q z6-b|oqmYWb7Z9D$_{wr~#3})WDJ$K}wjx+(=r4r_KW437s6V-r5fP4fyqIzeoQ&p*Ur;E|=1SqD{9$~ughLZ5XOi;yDc-5x{a3)Zhq zC#1M&N1#10|ltnPRm(2VOk^UM*&#i196i%E6z9_+Fmy+$*q_=L%#OTb3>L zTyzweGS2dSPDvN9hkQ3_{z?~U{^E^$CsVjE{x3>#JQcORcBxY$K#0B44QWK;Bsk$K zXPLY$>f3$LK5wzg`%bBn{swodIFB2nI7+Xj1dOOq7$0DT8=b7e44VO_pKA#J7|s=; zYS-(=!lH+dSMr6ml$rfqbT*P>dE(;DZcfE_;6v9|H{C^mEWD5(zSrzzJ>* z=mL(UrtnIZu3ZegGJ|1#x40Jl6|mCpazvw5Ez|Tm1d5-}u=Ni}CYNFB--P>}X4u)1 z-y?us0SYc{x_w64^aqSI=#podE=f<(C3N*(i1h~yy@|#ey%<1rEk2_TsYHc3H&n=+ zpD@p=4?LTDfSjI09>O}X>P%B6jVXLLHJ&0HQioC`1>jqzftTj9hH2S}FjzVD-8i7kHb9-EYq^&@{ zVOC&ZO~izytpKcqQ z;ok6gm3FZ`cOH4pdWMM4f3NqDEK7O$WIJexlaXCvrgYGp8^7$Qh zvTv3u>pq+e*Z^Ol9rg@#Sm>383~aD&n!=*R2|Iu`<33@h$(45a4V*^n#;YJ*Yz1o* zTc%u~$11TkTgQ;a(MjY1Tn)%&-S`TKY=HBzbGWt_kSM{OLR5Cl|F()V9X z==*>CpS~YsH3P<%tY%8@Fk`fbl}tpee-9rl4pfsWVx`RVRSq>Wg*B(z5AxfWI>G&X z?2$g{Vc z#=w^FtKyKORw^KrZ4l)Z6ZLbKJ`%d}OI4Ux{sp$LB$QY+#J zY8)qP4o9rjA8D2RX^~O@y*n76vnzu!!mbR)*Gxl!G0JW#QmvI{I#TQsNtcGjs3xV6 zNZ&#t`vKe?DQ{U{l2XI)EHTHhe2c2g;l^PQnA>v0Y}l#7VOOQk?oVQ`Q%WM02P;It zQfzV(dED>_2*D%{V|dVA*dwzWCQYD}oL@%C1oFXCuOPJnR5O=;Na@I*O{#fd00U?7 zK5K{d(V%ti@QnJD*;&ZhTA@lgs#r_^6e$eruhw@`Jef%IDj9zgnhj?7Zip>%AfHeYPxH>s_m*4QR(2ftI?DeaK=^ZNsPLwjTUHU9z*C;WC- zG@`i*xXw&F{hHE2x(Fd}AYqNR^SGrm__%YbX`9swk>~V5o);t?3lG+6S>*X1!tE?z4uh zw~t`u<3IiVtM~doy7QN7!mVz<_4~WlsCC)d-|xbWU;hf*Uv-`o`!8MoGbax86+WZg zcR8rIC-{XZ08tE>kBbgbk@Z@#jI1GR_#KWPDbG8cb{k$1S{hkez9QZnS{+$k-W+dp zw7H)4?sVLXNnt;(ET0|EmeR7+34YaRGo~X87@wQV=+7@{IIfLoMEjP|g-&BEo)&8LuqoMT z7nfpg2!`aQTqG&=^0{DCq7xJnHvnvtJG;6YUa`~aIY7Z)-SC;mkB;$eRXN{-#_d$ZTIcqJ@>t!vPEonwz%_hORzoM9?Soa>uL>d;=00ncUQa8 zT8~}ySj%495_%B~mTk$BjZL*QI046Rhwzkbz&6I11{2E55HR2=&oS?YkOZcWnL-B& zwxJ#a2{F)23?=+wrZc4z+8Bm3At8lOplIp2*O0g!kL0sgx_7nTIp;gym;ScZP{-8? zmBvc3(ovT@OQ}rPbBvwIlolCVM4gqU(r~VH5--s*P97uy{;45~YG<}F*pX&SszlG0 z7D?-*E{WAidb0}jMw!7|sBRTEg~PpIZPIxn74-+KFY@gf z%^hdliE9nlKiscW&)C@Yng*(rfKo&^CIbev@UJeT$=;?Y3NC2Q23G ze&lx-q(nyloL?pO>Q1{a>i*<5q#I=i2F+|Rh8+$Y6@$7$OcKtMVTti0BW*M~8Js*1 zZ^Mh3&ZKlsF&bqBQ4X0?U24kcu*;>0IB%5flI!L5GAkeTORCcM?2(#`^P`9uTE#)2 zRVox(3Hyej#i-^6+W^c=fDitF&9JI{F~#m;m_zvEkOa6=q>Ffr8|j&-{l}0<-n?)W zUXf5PGqIz6(Tu8<%Pbz3*!AX;vK{Rmhrc<~cVf@+-mA><=6G%7l{o0epB2A4cjMxt zAHIF6v}X5;bI?QBi(UXkEmSJTi2#vjcn zgKP9n`X0@z^kMo0%}^uOI0Hqa5;|BLuU*>qBQFfa#UUVrL{W^80FpeC8dHGn)ik31$hKW$3dTgKJ$R>O9=SNCr^soK=U zF3`<0El7Pw{+;}ZX>in_JeZuMggC|ONU|e^8m%Pp6ptv}#&&}_4E9N}aTRuC_t`j% zg$-kY$gj`M_5ik&}ADJd+8RWZ}p2By{8 z5NynzSGk;Rx2~#bpT2r_C);K2vhHwnW^5^3U%9<@N8J%qpXs7$&~wojNHJE;aNE3n z^dC>Xs*EY0P}Ya6s&$M_G3qDq`RUfAibSZyY zZFh2sw>|EI&B>XW*jbTs@-${yfP8UBh`ik_QrE-WqZWNClMf1}E!>+hI<97T|JS!t@?g=(f(W<|Z; z(yGm`bzUv0*{Ii-k87eoS+?KpNF3E!68CafKeq-{>LW%$SGbivXHn*Zj+tfDN} z*x6}WE6dAbxIZeW_xTe{D<#532p*FtE)P6YUL=CPE-fr9;|d>NYOXEs=$}7*fN5P` zSKrwB>CS!G<9+Yo{Rgxfrdd~r_gf>8XvpD^?fw9C0i1PU*Drlp!F@YFZEdWtTh4sY zIq=5({*JQR1y6pW8z?O*{Qvvoy|B#_i30D#PvERS?09^MD})_PD;zmKn;bc}cKQF_ zU(SOAKn6vk5F!UM;{;U1j(`=iEmgKynGYk${0@T~bJRm?eNDEg)d2g()py zqb*TmTa-s5uOP5D7Q$mFaTJnFa9W`1bc#daVxdVpr4xvgD#JjlBmqV1)M`6`j8$hk zWOwgf|8vg0cNZFz4vxEf?%s3Gf4=jd?|lD%?yZr|PMi>K%bj0YHDB$D-M6e}0j}jM zU2^sVIQ!Fhk^u3h_Lo03f^>{2!6oU(YTCChoNLBDH0Lhd+Fm1T>Tpq`BgdESZFzb3 z?w4EkmX0sm)5>pK_aOQ{X9-)Tb_jHj7~i>)3UpS}In7saRLkL}ro%0J$~cy|-K%!g zbl@}%u@4&NJhZi=25S$^X;2FqaMBJu1^3x4F8Zkdf{%N8n>n06&~tX=KhAVxe=Wk3 z|3DW(>twiM*ks z4I{T81VyB1G#y@iV57*WJkN`?&jTA~R8>{Yxc>P`vp3G17A#~rpDi3&NHvA2Ok+Az zv>`cza|Y#P=O|i!@H0WGjmQ{P4a2hn)ufOWRFhy1UP?>xHx55rwiJbo+^P4mNO>X6 zmr1!~0t*!np*o&+;hp-RIjxtY8!o;uH(S}EWmVK2dHnGcYbWT8t|IDO^QX_(E`8y| z&dG7RnXY?(#+se=^A|Qg|LrO7;GqL+pi7yq{6(B`*|2p_w&1y#2@o*|F~UW7-A~Su z^NDua?=(8w=q9S${q~NBsZI_%OK|^IlS9fE6b<)x{0SDOl)Oe>pE(3*fv%`wJO?$; z*#$fce}KodQE! zk#aHV(qf79xltpBPLN32nH$$7Qf}6~L3&^`A|x&Pwo8hGU97^lWh#Lk2meP-m=l4*SZ{MP*&Q z3FQ33PgSfeByt^p6$#KfOCgD)Bx=#^0^Qk`s8rTj9{a8@xT*?Y2ed_KfmEX_v0T^k zs_RLfFyo$d5@)PJxGT6~vS$!ESOd}URGRH^$j=ocLhINg z@gyxJefDNcpBL-2#01JZp(Ii*RGH3;t8bwa!3*nlqu^@FQhLL##*?HEOXRH%NBy{RWu^Uq*k_oA# zRw5|#IKxR@h4_Bv`NT;@3F`dtcm4For1>eeWw_cxUE7;UpDQjIaY!TUMoLj)R7Spt zWYH#e}YaP7p@jDFql6FS7VMhhWInl zr#Y1tTV!v-q5gE-M>%CGkLIPvh%Zq;i?}&e`P?5K;WD};_c9Z*Ya-fh#$B@!|-r=6iypQ&#_0hkjPVGKF8hN%dXrJF%2v0c~E~YMaEf3eq zpQ1xh0;Mn!A}|#yVFt{G`{6-+M_2@p!ej7t_!caK6;KCjVFSMHL;|6(Thz3B{SMmm z@525m(ul^6%-VEP|M%W3v;fK%+ZSWi%grC7na2PB&4ju3Ybiyy;S8x{Ih6`{J zF2kSTefSWr!QX-6Ln`t%b%3J&AKJsWw0ZknGCXOBc~6@1@Y9X>z-Jdw>baq}`R&1K0zt@MC=E`U$)UKZhgm3wRY? zhd1Fgbi)}q2fu+{_#ONa-h;ow6}S%n;Q1&Nh@=;uWGh0qlt^Hp5(GEq`Dg@KoP+zeT%-O z?vAbJZ#tus?`db%UA!-olF{nn*b;S@U1pc@aoBfKT`BvtllF9by1Fv99+7SuM+~B! z<-=mtvA_7gO6$?l~6wZhRgNUFN#FbIp5J$z0BDmpHK&$Q8Q%5~g zi;fG{IV$Z;u}AF8=$RR1I_fO6o-??h2_?g5iP=^yKUqPsaJdnDt>J!H*atgIpM` z2IOvF&%Vih@NfT*ZhT|$yry_tR&#Uqn{>B~At(Ivw~(9zNn$ogU0TsJHg7n_CYfBW z00qbuas_sxtO!KFvLb9j^?Cys07q;}6B4Xo1z{ZX9H_0CrLD6;XXbm;gY_iL;LmXD zASjXlM{(og%%#mU_`48}6GC^?eu@6!|Xw8L?ME>El6c6W@sLuBw z%x#Dk>ZhMiXS|ue6M@+A5HQ@83+=Q{?@mqAP)SkavX|1pH@qc@H^cACp6=QCVtd`d z4*o%3)q@SdeRU1E4G-WC{E{R-9llJ0#?7yG)xF%YbD-`!{yVB?O>gxzz7M!-)xB%b zekK2s*~aD)N800>HqHGf#Jhf1Fs)AKH6x$ADlOO!u;8!$RjH zW#||RY_8N)`M${^*``zw#`ots=171&Z$btE-crq-1-9a(1E5*KEs z^9$ZOq6^cRZdOWz*DXIkWkQS*Qh;(BF(5eUnP0oVAmi6{Gu1IUt5t^= zv{upG2TtBB%esHA!JN9fHSFq&J1vM3;krlNV`kyI5>}zW4D$tdcQfLIg~|NK#1J0p zKeuKlN1Nv-PEOC)*gq<$*m!VlRuMDH*FQ0;xwOnU)e#svcxlbHoV6v3KAa@vL7uCI ziD!OtqeqNIlPhG*ICN4@X>11^6}5+|C#0l0PrinypTBtZ`MM1=*UvB6;~PZwoFBZn zX4{Ol^92ho7jeb)h*`~CzqcuK0ICi+6w0nEIh5PNE zUaTMt+GS!fN`5{*IC@GX?yGn0a;cQf%cdQ4D}9CTq#2sppJpV84%f4GDI%iqvR&-s z7Jh0M=A!W5c0nD50lTj^!c`K&A}7C+W&~rQQTSMf|M6o+-gSHqrF8Sobn|`>{))Vh z*(DUIv5UoIp2qI!MdooGt`}}&D0I3#Kw;2rl@oXf)KU1>uJlG%inyg58N$VKm0SbY z#@**wPSgPt+mQu9k08+_0PZWpUca>a3$zJZN{7-L=?~Fsb=_<779_uHn7qY;?8~vf zzh}B|mCGTXAb*xPhwT0AzWB_;o}?K7lwm}g!Dz(u8tN?6qo)ip#U4iKR9Z9X9w>sL zX<&Y&NP--oH^pFo6UZK3s5E9t`wQQ5_7S$^K9Kn-660cxMvk+ZL{yE~{Hd82s#u($*tU0dF{mdnELoyi-#sC$fi>J zt5oVB)ntR|B6%4bvjv!Sm+f+cr$(*zlK6)BlD<_~l~T-rHia;S#wjwK;^jqY9;@4e zW23@5$V+xvR8;U1B4|MM8^SlrXA1J}fLyz`f0PYb2PQ20bR-u2ef@ob(tc&1w7<_e zBoVegr}KwGDSnfs$#{bIlD9FFjO(Spi;IOqq7W2g%T1&o-R3DU0hmXZLF-5thBL_W zwf>)0A3T5IV0CjqwJhJ}_{EBXjQQ6oUE|;bxYha5p|7qS{?*k@>*vm0FZ`(gNNXBy zTb#n$&SkHmyaN@UJU8k>i-Mm;|U*EW+zFycLC9cQhR*ba@^M1WO zBzpn`s#M))GKeJ1fX#dtScm3i@?FBJ zJKDv+(ZiFAmyCAp<9l_1=~DQNET!7qJ)@xcx}{c(>C|EI!ltH$3!54jrI(harIn$A za4P&V%hJ+IOViWJTrQUr_q=@eGN~uR-Rs+*AOjqP-mbtT0IB4bgbbC$O7O%_EdCh@ zlJle%t4~;PmMs@nm<-%IHH-uGrw-{8PqDI9b{}%-WFRIdktAwOK2Kg7))I6|aWAM6 z=~3r@j8}bZ6XzL!-`Dqj_MOk?oO5yPI7uA>1{|;*KzPe#g^iLDpujYinz1Qtf)zEO zF%7B}m;|)YKNzYiDz>V0-Bx81uo1wan}{N{`(Ej~Qb;Stv_PR9s6#Z{ptkos=Z}Q$ zpIOP>`@Z+w@45H+`aN%(`_2V=g7y>3Q7DPEN_sb(eQIh@eg!b-O@0*QKVOz7cR`0M zABl+?$VY}*%cOi6zoCXd2KWa_og>qz+7HE&MknD(4S#pylr?>&w^lT_Sft zUmfV9aSJGb(UzJGC--xwrf=;3+Ry$P{#eyVQ};8)N1MS%!(ubY&nWwpX%Khre%e31 zpZ0{N;eOgQQrpkxfR{gTV`6C~CVo@ZH>*PrfxcP)t53L5(>LbobNACWUBUgd-M61I z{{9;N7#Vl%C9}lznM)FkCMMzWdo~yQ_+kF7Dn7l%B#>86Qj|#b|OQz zbG=7@)6 zl4l*ipp@m=>LEMQD1`HD=g{m%TU7IG(DBEV4rRSEpzKmcl=F(HwMrJ(WOZ4~Estf-Ne@$nl-ae?*DM2y^%rVg4*atI!kv$^E`=;e z-Wdl<83#_ujpIG*FT&&O#LWuTV#nM$4_a^RmgnN+3EHK(%dcivpO zt~2K^_8vF>zWqSkwqx(zzWv_W9Y1;W>X8c;}c89k(vz#OAF-?m`!8$3VXdhU~{=G{)vjS3t9iTKQ~bwXZ<(9;n}V%ct2an8s%%sNKv?i@DClI zFk3UJOscLK{!?|WMk~;As|nMW_v{&EcSqq`5Jq9d^*sA7{GPpcik&Ph<9a^)5LjA3 z`-44g`t?(0i$9bO!`4sMh0+?{WhGsgFI{%jke!aJ8D+8JQQ+)y8m3CU$k0l2qlq;8 ziv$&uBf&(m6Dg-hgtjI#JF&J&3ud zqrFtLm#*OPz%`b4hgD%`Vq(i7dElP6xq53{BL$Ro84_=VySw{MZv4t^0QG9-@yIzrW-4r^ko> z_QVf|xZ`{G?Aco^96DUQSNIA$O4-q06<&obD~&)ZtP_K*dft4ebheshoZsayb842A z{tWU1{2<7`?Vgj~`2+d1^dy^ z=}E4KoF}YTlxpagN^e%tRo<1C?n4KrWe>UBUPixEMW2+O!h}7=N9YUuS=Q;ITjX+u zr|LQ4>8`Mu4Kk0pG7pz!{)94&G)kOUm6=z1pIhzLrCF7_G+MQAFeIsP$ zl`O`OLOum)+(~efClHfjMl7&UOi6Q%CF)*D5lu-`NI%Evo+c0T>|?wjAltP#swOCn zrp{-D&u|!d&9XPm^^<a{2WXm;!*D1Bi?ed59G zj#mw+0biJU4F!(1u-)B8Dm8_(AP<%mvb~EpEV{PEPUaG@T)(VfPt+F*3Ao}Jv8yYK z)vS<%iUw2`Sm2(0#8xw9w$gbnAsI+etu5EK{PE(*mERYawWOQ7W)E$9?je5lAgwQ6 z|IgXywN+1XkKTLnwG-%{=b$5b1bo;=W|un>3SmJaKc^O2Mw9!6H8G14%OHHWMv~B* zm;L%wvCs2w_r2cAd(Cd=TUZ{@~TpLko-!KtM*N4!OPy@>Y;EC(b z!#E0g=pqjl1Wsn65EqhSQrhJ^!@tgt_^t|9cPImugHET2%@aWlETZ9gryKjMOY)nMIk7Pf`{Ycyb|PjWrIQ$ z8Rt~sIYE^qQTdqwOA<^yVocm6o)bMHQ{x0c++s-Ff``FD1pIO$U|3Wh3phYd6v``J zpF613La+ykk@L{ZbEMZhwH6k#;QG*lEuy{jJEn5)-IL)9bN?WOD>>Z+mH;S9+xy!|)JGr*v3VNdW?Lt3m+EMJQ zc%GZ#dN5h>;A-%o>8KPP?pMKoQpJCG0xb5?W3KdatRD2%A*ddw>2i)XaWr2VAL2Md zy79n=)#C>cRZXt+oC@}}Ds~VOUk7Y&4V&zPSh~i27Nl2}rQK73c7~GXM(XXhQ8EKI z`!RIqIsPpYA)h$w7K&-L%j#A)nvYpec(w^!#ckFB&k>K8_wfH^yINzTxUTTMcOE;t zUhm94W?vqUXKk;SWL-A0cO4!sjAbY;U~t($><|~!q!Oj1GNvT$kB9{f0uqCx(ndr@ zKnnfQg0N#_n+UapM^!+mq@pS`NpTRVLIN#9R@4XH?YVb$*ET`&?A%?SIcM&<=X~e; zLO#wHs^+S_3I9g2jr^P(B}chIGR&PN*N7s!Tu#{)&;<@7BD>tW)2@|Ea>9jOYK^^` zo-Nelbw)#A@nDFaD=h8}(f+p6%JR`7LUwFlRe?35+{ja5i^G%`I7~U6o3u12OJ=oD zPHTaBp*F*e5qIj!#3XI`s&o42OC;zg3_e8p3QWIFX!v@yfsQGV5xVbkr`Pkpv4`{?5>KYe~}Q|q>+*&pt>wDf}T{&3Hdce8)WKFq$F-O_R(xfR)*sBGrs_7K^|i;U6RY6fv|e4d&Oq5v>B*K+0;x zLE1@sa6#^KKE~L@3hO!aC3IDEkPsX$5QzbiG(XpV3YBT#Azn5VCXSYPydzbNYpX2A zy$NyGqloDvZB=Wlx~ei&eN{pgK~&}%Q$nL+?9pQEn=Cd=eS#uo>}B<7Y~u*v#R-NN zsp)t@jF}kCoB@I-I*AuMva87-7+$QjuqcWU-|s^S_}`1bH@>vh!2cTZd}Aqo+2R}Z z4SqlHjk;;NX@2f=Za_E(_Ny#=^gDzK_Nr>x7v2<#@fis9KJa`Q4Vg8_t+)+0=fuyH z5F(3`pxZ zpaT|fBCB62|Et0>&`GR4?3U zh2lsm;)V-YGrg*aH#>|MXUq9L*)rUc9X&@j_YmKS6BGA(Cf=Z^;LJTFUf}@JL2n`f zq)b&!Ql!1J8Wss7V-N+$WkSMEAzmVi{!3vl7!C-kl%x=8XP=T?bh}C&yq&5_8!zc{ zeaT_cPbeDmgoq{1%0Ok%?ukmloGuCr^@85ei+V%nosbos=?z_^Szt!At6}lT0ur6c z8l3?&P1#BP_c}rPHJ#|oDgwbpr?CSC<4C!Lr?Rd%Wa>VZAa}+=6ecz*cibKjg>V7p z*2m+FXhEBU$z&ca{o$t9vu>&u;Zl9j^UnsL`)g`aZ|&I8(=#+Qbo_YKG!o%&e{=n& z3PO6Y?@esmknMdld#~p&E9cn`DJ`3K(V9L2-BxLHK^@Mrln6drs9QKEH`Jjzt!}qN z-HtIO(r($Kdr-HA>B0XB;gFerE{Q@>_FSk~zi~F3StRj%G13hdDLRO!gec&G8YsaO z7gQM)alwkbrWpAKi_G3Mq&Wgs#Pd^no9#?1#=D983Om#M;GWrkZD*rJ|2LWc8T9?i z3tK6?pAm+D@v;G_uRT|C7agF^^||EyVj;_R0;XhsG-_ zoG$eHZcvG!!3<&Yv&C`-5wZXMU9 z2o6m^$YHY~$&k9FjKoW&t|(T_{Jj6l3@}Py5dnq$D&=SYBeRBbNEB z>^bOI{`~)b!Wb=NwnK8l`M<=@zZa*;V)XqHK1S2e#{lF8fgiAYWwmwJ4R#+^Jjs(W z9772Py;eR=JBleWau|N6rVAHZkJKjE{k=da38tOh9jSa}EruDX*?Qole#B0y7t8n@ zx}10RG>_WSbLTd31kIYKX-zyzx1}GXxkS1vok??Pju=guCX#8wO(?OkJC#ZR^9IkU zc&f~-<=Ym(9=@}pEuC4iJefAvu7!_Tvyv#iHoY%>EzR!(UnHHGH9wiAU~aFSnM`M% zO0aK(u^IH98LX(tEQbxhU!}498ONUr}kTO1N_U(|B<|XL&1M-xla8jCjGCA21iZse1MFRj%Xe)h8fFGuZ?07Ca54 z_SYk2A%F@@iP)6gKaLg6cpbc5{t49!;DE7j8gF_$MlXv2`^O;(3Sb(vJ_(I_Sp;hD zwK03|6tYwBFMe9|zZcL?NAXhxV?siY;~%Ifihl!I0BDSb##5r6FGk(VFfa)04*OYH zLj03)Q%^v>X57m5<-ph_hFfBAD{c%u0ri^E2t?3K8Pr*+OI)eRVY)kQauiZ7w}-on zR|}Vr9W5H>u!OkZ@}s!T4B9bjwA&@b|A4!QkbSFdzJ#Ta<6!Z~I~!Z!z{l@^L{nff z0Rqi48(o63ukr)()TC1Nc*%FkhT6`S5BPuovUbtad$%8h7t4LhUm=%;HBe7s(}`1v zgaxRj=5^HT9R=#B6>y9LdR9U1@>llnr!`oXyTi``L~g(d^I}Q0mwzfa$CIA>3T)nsIRMwMAjI$46@I_vQc3qj6=prL-;@E z{zj5yFI<2(7jRakSX~YwFH;Q1z3|U?%)mC z#tB_Eud|G$>vFO)X{)QE647*7;RboT;il7AW~7X^YLC|oObl2zIB84=%QjqeU2%Ql zqFr4Ur^8{l+b*Y1oONJ})%WsHatW=$a7L6As-$X#nl+OAV+C|t!EiJJ^;Zqq5L8}~ zScH$lt}_-2lUg>^nY=HS*a_r7*WE|T%b*SG>V#rf%HcG`4dx3oH@JevUFCzit-wu& zN^c&tWkfS#7or93NXM_>^!Pt=`h)74ZD*F(KIuQczG37?b*DyZ-*R5P%H*FuXu;Y` zKmW{j&M?~EJ(P*R8~?qH+B!P&{dB8beJW5~8k*XDb=1*4+8TW8y^C+!JCD7v-v9LI zcCc2|I`=-apQ%S?h^>=q%WDj-wX`xTjqCVUX{Du|Y15=Q?S7__c|>TCSTkx$Q><64 zl+~&=aobruNl$2XqCaCYeZr(+Cx*E(?ksnayTV=P;3uX{Qi7Mdr4;!%D^HltA z5Z0)D?l)XN@Ju5E%0VSiqlHzY;_nsqN`t}?i3K)^=`3CEC3{tHf6Ge;5Eda8GBWaw z#;R%RaaHHYSMme-bbfwT(FN*pl!n2?vRKVz%D9d(Ok>A+o&E-ee~Aykd&=MjL)Hz1 zXl<^{yGv!~G|p19Y>VV{w@0?w{D{UBe4Ku-?etE8H>r=k*(w$V~@PVU8k3RR(>BECR zd!^3fd8EF|r)K`}+bye?*EQ8}`Y)n%I#u|nvsZXxNlb_zSN61Yw6ES%A`kC4*tdD~ zQia!BQtI=^kM-47`j^*&9=V{$p@bf}s0uAbLHwv{afsJNN@?C+u(hzaU~l1I!PAAB zuL&dFB}`^!PDV+I-{opdisM)O0YB~cSE#=NaTehjRDq0e#%M6)WU!Z=Oc_Hln>FNQ z4tAgnBvNPKrII2AB)U(+8>J43N(|C5Gd%KK#)6o&@ED;YA*RtV#{1-a_cFPX2x?cB z$VKjYS+O-I1Z`fy%eLH9xhxxJPg9Fj3uAN}HnXD4OMiw3=dvgG3(bJYUEFam7vj?Y64aRRX2M#}b@VTQyr_b~coCHY9 z8|tg70FwF@s}>-6*R;E_ri0$Kb?sJ5NAsKe+(pN?{2+c(+0(kEef91#dH9Lm-Zp}Z zr!^f&_o~IcuD$L-*Ae$6``h-L_S;g5+3K_^P32aGl~_9^O43eV z5P4p>PjnX+`kc=CBtSmJ7x2+OpR$BRcRoaSnj%RCfp>2-b(s20!zRWwVIbFLnk=fN z#X?&wSps{xpTPt!m1$uZ0F2z61<6226U`#wNN~?{w3H+TCBczb&ULGD1z{++*e@?~ z*UH7VrUXMxjgpB^Gnug&Kti@M8)YLXiHs-;g2`m!G4CcEHLh9UC{&?TC>|w2QfRSo zzqAoacouNfnasNLME$QkGGK%mo205U6uO(Lgt4W8eQA;q5rF;=q(*E#P3s?9T30vJ zjIYH9bDP(8zWB!BCx5~`|6ruvHgA6{;9sR$aZk^SmCx_o_d;jf^B|yD=!53{Ko6Z> zG4dt+pymL-S3Jre5%1>*7E7MNP?;nqPst19(Rq29g+z2So_RG>4_W+;*E!9kHf2F} zg~*xl3dRkzKaBWyxJ3TWvK7*=wpfEu(d&;?w~>@q(5kz_9N8OeN}*_~T4ZI@7inlm>J6P$T=P}q6`q954FDhN3$ZSz(MDPFtFaRC47}TzdZG41>kHsF^mG6-f8(w$e zx7~R0)Ku)+)D-(c{Now;k*}G9l)H|-0N-K+s3%^-MiWo1qNeBmb^gxe-{*OrBa_+l z218=R;WMmVgB9@8UQrfhe#AoO+(}?&x_Sf8u_^GH*Vb|i-REyZA`-ON* zf6H*osAcqwfico1WaiD3`CXpUrD|CQDkEbGr_tzPp2F#q)xhVfNw23?(N0D$!WGa? zkYf@#hMXF`NG{K2*_3RK=BBCLsuAfwf`#H&3M7z)A-nv8 zqq?d%e(!zvy?wubY&Oa6W_Q_5LZDg7B1wfnI=pFx6d0Pgr8N9l!#Fs@=m=76hw%>^ z$67>3n~GK~jzp?0Q(*`um2G6E6p^-e7|_uvMpMvX3aPBp8A@wl-+Io?lEmpI@4kEX zZC>_$&N<(6j%~+zK5UV7r8V5Ias9BH+syIp^K(8U{Vup%L$ze zu_r?PAr{(KGfMZI^8TOymA?Oz)pHVU<^O#1+TZ2T$yM}3 z@F}*5K6`4%cfa!-jRsd?TBy7T-hUgsZxDz4%U@~|$90%9W-&!hsVan^#8bdi*HQ*i zt-PHd0D=>aImhfa&zToZ+4OC%-9)~YX0#swV*bKy?PdtyS>T4-L+hnAX+3Q*J???v zQL@;Ds3N-Kz#6wKSX+cQi`1WUa9|zb2k)>t1gzejVnr9cLOgiFg*CP9Gt9V@(gyYOn6RqMn4!)PGkvFuDG8WN z@fh7^pE+nsJtlPlo2;foA*EOu_mfCSF_DmxLPCm;gp@FHflmZ}JF-zcWP{g~hqo$E zD@=*^c>Nypm;snofjJ>CFBF)Il}W!|pk5>Z#{}S(D&R>!A^`j1n~^^9D(KU=TLj7* zMNOJb*)7c2$TT+Qq@Ne@&1szrZ$4u42RG zbye7cHERXdsF7#<#g3NK7HRz&Cm|P-a7>XQD2XcPmHa@6h9-EO36IF5_~kjG=7_ov zPhnsK7b{ofKgoZF4kbzw)b=;Xj_&ETa(#`H^pdqT z^L)^r;3m(R{lLAqOMrEj#&pg7tw(IfhYh9 zO7Ie-qQp~H3*<5abqyOKYC5dOEO4vwzdO*%=fIf@lgMn#tbi&#IGw@kO1W8KRDz!> zxf+*b(!_(cv6(H2khaBWG&K^Gyk7ck+D`AGdxFP2#tuY8^i^FxMPmZs8Ot3@&!*r_|Yh`nBS`F znkGpMQovB4Z6bEw$q&G&Fk!{eVOy;)SO-H_^=nTt(W{3QxEu@5tKR4iW=wneIRVjwFpIAf+v~d5HUSHE1V;w3SkooT%i*>+v*f^b&AUkceuKtrt;3RTTI#zz` z8qGZH-}f1s_-Fa}t#%BPFG}lzRo{5*%LDZ2?cwsi8Rf?+`Ae7}k|aY%{FMj10}ZT~ zK4N_}{8;>{=+P!+i`=8_l(%V*Yw}!eZFp^DRdi)sHe{|P<%rfQ%VsUBUmll8#?7$I zSb7etE3yatrjTS?gx=lI;N5Md95GHdve6I#O6akjA7^29JQJK`KENj2c3aiznqM`J!PrS+bBQ6HL?sagES;pu!;PbK?^J6wQ(j>1DHUefo#KtG zo9!$?1eGwds$~a5stl78{B}-j2Mn==0x2xXG<)sg=C;K=T+yddLB*>KpDEPKlCP~J&0wIEgCiq zZo=6&d+e>i*yeMfq7|W!idE~h0H z0clj>20Tq@1ZF{*r-({HX_=%Fl~W=!X_Ubg7V#|@H2~K+m8z;~#5`giXI+1coZl+u*u10p$Q_77O*Ryo1xf|GtrITIws|U-*sgg+Ogsv zk?ue7m2V9or-Q)hs^BzVaJviaAz|Mu>|X%4Mqy`#{VF`l*M+^{4re(p?1cm;UIXk0 zfU{1n`0+lO5)%RMH2EXa7QR82bX62;%sCHtk}R_j;3E{qFGyP`3IJ4QvdXaG7GcDo zVTwR45ZC96>;I#@{DY%7%Q*hN@4mZx@9u4G@5f#?x#V&oxr59B3FH!5NXb@|NjeVH z5g`#zAXxcP7zr&UVWtg31!16qV=dNF%plOBsnP~&66}a{tiNWI5vD_(BGG0_Wnhej zqBZ2=^SntQw%VzGILYnpyZ65DzVG*aetaH4Tc01JgD)YBh!6%$AbdVXeFkAZLl8#$ z=rSTk{vqRlz=k?<1CtCGs9FUtP$wvz9+$cf|KREEY>>W_4$>c%dn1TVX_*unz7(6? zbuRb#%vkBP+{3T2dn8>=+4Deq+t3BI57hcLWcPqnt4gYO0Msgx?HQn+Le_)&uZ zN#=T!)i^lfLVcOuq3_i>ltNGg`BAZmhn~a2BGr{ky#Q-i3DkE{Jr8S`DNk_h#9;+py&xcDZm2KN zX4N=lVA&X3G04KryIujRtJruZN_MNDLQ9Z@J$k}7WjA><&i*IHs;u|CJUl!g2RIIJ z5O{R@Wq1wA`UJ8@SUwjtA?_E;#RkFW0OA7RLS`RFHo$-U!X4M+Ss>jb+aKnS0o0@N zs`bz7u)l+#>9EweTJG;jXdjXl)Ei#idxF*~wSqbPTl@%ropGI+BFYLyicJ%<*leX< zG%Cg#Wvysa+C-1iD{iv)g-_uMgB(97;{e`xLEIUS`$WX&6ADwfj1ILjPDlo2aYF!B z2?KuSoN*`~;wDq$x{ot>0(CB=O`W`zfOy+OXLMWoU;Osl5HbfOrqltl;9h}d>JVR~ zfllBRd5fIdx{Aqu^hVCF)D68$FXc+%?1!%opLpTdtdizlMJohb zlpT_@WD+KsY3M=IC>R$K)NMycTdUO=J0-RJRzqA}n_Ja@Uf!QJO} zx`Ma~x61Wg?j!&n0(dD?%8ZPXF%B66#!W-_saZQ51~_LLBP`_8g9$CvGcq)47NJno zOjtA#wWP#gL>6XtRM}PvS=_UbH1}DZ)`+D6lw>{I-Rhop&$>#d+wTs# ziVN1&ErOY74@3ZIolzf77PS!sqBbV2sH{8_Q5x-KS(0xLjM-VX)qY!6R+yB)voLv$ zMr3HfJ;Gl)4Jkfc9gIZtA!pUr2H|R}V2$M@*m36dOJ{!n)~mxi&*Watom2aAoBsB* zkh1XBi`H)`r4Qv=hP#d29Qtz&$_EqGT>)x8gPcbxqtr(8)-EfdCI1I(3*ezGFQ%k8QOt_F;@~c= z{|;^0+tl^}X!{VXeOypm@llZW(SQcN#3A9=Xn$fU%%4;zUmy7ejgu)S83i^lds!)D z;52A{rdOyq%^GrsACUk>&B7Hay{nB=r zDqT~9KHMz_fnd?Jp$LZJGVx;g8i90;Vq6QXvD^)(a4?dIR8rMbzb%_ggcEq zv7L~*Ztx3zyx*7-j;>23dWjCcoL`X9u_Q4kB{P)(s`T@qP8J1%Id{UE0S#f!GF$^4 zByYkRtP=oUO8(fia0p~iZVkT&{47GI0^v5_6={ep39JgNEm&LpK&su`Qn00Xm$|!O zzhzDF(}s%XmpNtq#$rS-Uu{v#a*FJ!r>C;1u_C>^D6G@4$?`16p>BD- zu@Gxpw#XBc%cn=sOKgm2CYY~{>yMNtGgUSv;5rFgv1d##p-GuHg6J1aLldZOl@uT%%~I5^e9}x>ccZ@Yci>_Nt)(Bgo{?oW~!`=)^{)c!(N!(!(?dac zg)Wmf%B{4p&UX->u+9ivPN6(;~-{raHJJ)Is0n}d$Ts4|utTaA5&3Las=VZ7uN zX40)FY9)Ypdc4{xum|h`cnJTa_WTmlbZ9ga7kLxoQ2j*cyu+N3UN+)UQphh9pdJpW z;1yayt9o(|{g|h2ol-tE^oQIUx*v6H$bCk61oCnTx#}f+1#ZDQzFFI$9p%Sdy-=B_ zEK-zN%9i5Y#R`i1=i7*gX`9=`37=)e>^+;lY^I0^@SxK=O?g9Y;=HwQ(>40{?}8jMqVc&TOe?%48-p91-Fe&WZNX>qy7G<%JDpQ` z$DPy8`QTZn-x+c2L5FI(2uAfJui^9g8+O0)*Pt*1#0V6rI-^=J5H>-qq~oDi3#qL@ z8H2J+ksdFKY{6m; z^O@KoZK{xvkl?L=x6x2&o3YYTU|3|d9fejSDO(2=*0dB-Kx!ut48qn?tt-(wbx4T_ zVH1OvpF-COsnR-H4Wc13HZ^oV6ez>?-uJT;m}Oh<-TCf(&-;AO^Sn~ffoFFl+3+Ws zZYN13gD6J?_DrCTv4h2MFAJ3Rf<6OMqCjwpG2bo~2pSV`p>#7!Sb%vKH>y!``S^2-$ET;RWFnPDnM?9!-Q2-V%DAp3hIrPdqH$Z|+;4|GP9jcZkyp zS}FZSx|TC@T%JMG!?^{yzd`G_fQU>79hS+1nGlebm`b}O1DA>n0?8H64@Eu`zT@u$ zWh8PRn>|EL600lm1Gq8*UIPIc=n&j8z-s>c3EX2djJXB42d9gNh*G#LVxE4eQ~;?j zXJ%j(mFO&q&a@WGi`WWz1?#qUD}Bl!JIRh(my}ETuys@ZLJ25Jl^oM+^=bM-_@Ope zLHD?t@fmtRQgp*$x~Ad6c^EO*QmO(1p+FE2VO7>Jse)Y?U>C-dFum%E#AKo}Sv56H zHQ!cXm!`n5rv=n`YNy(*{#^aNs;bmXaadp?zH+gq{2-59EMG1Rnu*4SiQNQ{^m+PC9#qGvak2En*37wMt*i~2faEyKL=d{lA1gMuA!07 zhoCo~Wisf1B<2UY5UFTxRoj#W%2V=wwqH?onHVv-!RRn{6VxA__&7YJ z!VvJAnQ{y{nlBK%4Lb%fY|b=+x;P}K2rLwt!QYUn!icJYNScgA*emjieGVSlEV?Dqj}c ziwI)31RS>$RI8TyGL1&UsA;no*c)v{F#5#bbCUnbr>|hk)u;JN zcdc)&t0sW#{a}+|qh~XT310I=-Ps2uG$z!>oTwdeCYX{_OJmV!B(5Y=hYF(uHV`U> z#KYB>LNKdvMXpM{kdjiVc$E_|k&=;!(78i}OX3VH2Jwt|Num;P*GQyWr@Bts@3xY0 z;l^=YxN-coxD+3f9wB#$l{^}_Hf1u}aCXdwMVds=$DJ4(kV}L5LkiD!(JU=P&5tCS z$}lyKIkVQ<0?s@MW~r9enwqK2Elo1p@#YR%x8vpGKkGWYrgQEmL-mi(e>>kc`0A@K zUiwt|XyPR$*bL~( z!vvH4Mo9MefoEH!0{Zd$ z)Oqq!WvMaGURtK415-n-<>}a*KwGG-d`@hE{Ft)PSmb-kx5l^CXZuXzk2ogxJ4_1( zt!PqABPQs#=0``-aFE3{k3}YiOQAvQ(7H95XaUXBWUcW+6|E8{p<6(0rBGip+#e8L zUD8{K!6>j}-d&Q7|8wceaoHF}qbT_V_NmyNU|P5`PPSd)U?9{q1+o&Uo;WE;u}7sm zzwye&zfwD&`{=}KTD|f0pKk8?)j{C?CR$G?=KpZ*dj5kAd8TAee|qBh2k)IfhTLBO z+&>8@Pb60|4@}bUinr)#uT7upshhps@jj(5KIonD{>;wB^%}3$o9#X4ZDxw$RKdVx z%T7WIheDPMj}l8-IPG3Nojx--^GZ~bEo0q zZ)|v>?{z&(;8PqW!S~?ZaGWM-{mJ|~+WTStME>2=bPoVLAU&A7Cl{5T%#>(J2PKzP_KxH7P1xS#u*Aq@{_s-XyZ$(rWhRi3Go)`r$rNQN3ww?}!o->+&a zQT4LlN)3=P$_x2Hq+fZtkk+dr0u3)`9 zbzOhM-d6@T_D=18=pTO^*!2FkdcgMTj^5>(y#LlBZP}hZk}r4j?3tfv`4{O6Y}U>< z2a(H<6)yje@M?{X;=023-kF`9o!R%!K4u@|S+708U63(`B?%yggc1ju76nK{g3ZGy zN{Q3}Y9Tx7sI6KaqN1%zAz%^%RYFbE232aBG(ky<1OXR^f{9b8p@yC9 zId^v!#GhL7`rProXYBLc^L^j(fXg6Fbe{b%u|^rDb)V5;*w!4+f@o)MPQy~qGtqD7 z7B{R)t<8P6VQtgK)TXBW){vDT7By5U(vg)qOlSpFHAw=Bp9Pnh!1^Z%Wn=9aNhWm- ztW3c`8fCKsGyquGQHAq>q7*b+=SD(D98^R^SCB$=x2Ob3xxn)+Csf#4E7 ztYf@iAJV1j!qyk*9=+|1MXkEzK`ht>o*okyJP0tXZ`wJ`Uq~VI7r47AaIP*)EwDmc zbDgVQs$RL`4ul3*ti+yZ#qaQ7c#y-z?Fp_RfF@W8fU)=;9FwTBx6mGqgc-0oa1NUg z{?G4TTicU z8E|em*PY8>d_fy;Qn^y8ybo4{c}_5kfop_eYRjvHj5^FHWlTN78c7Q&($^*S;M~U# z6OTgKv|^@5W~8H7oIha#xEihk{CokIZ`({x!zuM3rS1!G7r&W&msQ&a<{tvqe5kHqcgWaR5{{!u!2Js()zuSL=<#}34##IKSpTGo? zqbd6C<7e%2_*8QTC40Q%)`XwWo%&?q6SVoQ*eqU&2FsKQvm%Vf-qglYWf9pZ& zfZ*Rfc$pv=<{SXQIqn=FxNQ6JO8F)>WXyD0ILclEM}L-cFF31fJxD_koZ_h<_!l2Y zAsFE~`IDLr8|FD{n|bi%8{DVOHNwNLu)zoicW$_LSGh;-M;|e@43kOgV7QEr@IpSg z#!f{OUNx#}C7STUM@)&7NL)^qD9}r>xM2h7jOF9`NQrwlc8B38G$PaF$B933QsrY8 zY4+l0Pk+DRYmaXK*`eR>zR>5SJV*CA_jWrM{&LVcmEY5R;D=j|b(J6Y1OS^|fXzJb zXuxtx4e^_F8Hw9IDhYc#U^tR$2mzGHN=qvPo>egGq{(~s#$P9Tq$3F-BNe4dQm6i` z{(}Cx&)Xuj_*&En!X#;eZ&KnRVV3k&->k%A!d%~D>fG2eb+xcYdQN>&*yR6J;;{6t zobsMGoqg(ddhf^mw7vA!9OuNTtA1hDzU$6; z`kgi>P2Z*uy-R0)c<$sl+U_`~v11lg2Egh<$ut%hc?xnQLt>Cx2i1%`0_IQiTv2c2Obc9 zOn#d>P1hkvk;R#gm_N^ zCK_p=)9u!x>~DxsqoG07A}nqMRapZZ;${d+6qm3>aTD1m?nfNr=-D|AajuH6K4&+g zO2)%jx_CU4wj>Uml)z(>9~q0og6AdVMLaGc&jnnd(su!sj|9z-i727_>Z#eXVa|sk zq`{go8{xS^ZmtmeUhdIgaC?K>v`+Ij4RW(zAFoiOT}07LO&*+zY*^-g3J^7foNT24 z&8(I5rAss?z=!Tllt{*7)aZ}{co%*J(D8gERtK&i-cM(|e{t*flgG>Nm9O;mv1lKC z=6mZpAKm-uWdv--UpH<2cskovUWhBUa^zCen(ldP#{kc@5h6VYSS9IwcHk*-HL8&= z$3Ts+W&DwdpCv(xG{4LhDDF3v-pYs7QA^>YmZD+J;OPed8%CU@V10>K41%+~h7g>x zqX>~=gFme(^teKmuX9VKk1vfs02Ydc_2v3b{eWHp3l%pt?QZ4z)D^5Nu3$M;OGSM6 zR#;!>@Idg1D_7U-Fjp`>u_3pgPlbnFt6NhpFt@kuFPAVJ)2ia->Q>krmYYLX*c&L( zpf3UdAwI5L0gVDgfDIzj=s}@s6JK+ZG_q&MTy*vAv~@QsiNA;G+SX_Q*1)OU|JgBtp$O@ zk%Qott>YWSFv2DV@g26fRb&fAD&p}F<(xnb=EtK9`xzfVFvQIXa}5u3+mm5e;va~= zvJ?CQu-R-UJHUpRXEvkT7-g+63%ZaO%P!bJul47Md3dmO>SV5z*k^g(Y3&hV;yx$Q z$8Mc)zD2itj*eXQ1V(0n>n#)Fna|aziL23G!0-mtI!IEa-;R%xMI)683eZ3yBPcUQ zVrbyL>`|*O?FLSP5Q%tqeRVzYQMk=M(J1xiOijYijPJXN}`8fy!v39yL~ z*hAVXZR*6PO)E%6U0XHKN9ZKLVdr;jhrvIKWBc55eXo7K=lA>mKEJ_z`<5R(J6VAE z&n|jz$A+_;j|>c~*qnse-%EA-gy|ULAVV3gQ5^-Y-|}J-L>v}mmk{wKx?ckFsB`g~g#}Mxs@}=6;i7AhMKrLk3)Q@Nzm3^Q$ACW$QlIM5-rv!%@qq%fS1B3O1?jM^k(zX-goe+Ni@F` zzXmx}D4<6s-^2vjN$vE-rwe_5Dfdt;5|S(uB+3#igwxzy^tyFqmv7MjQhaNYug@W8 zu0Chw`tb^5EdmvW9|buyaKTB=*3E$M~nwSl$McGTJyY746uMmKsl zPJgCWOc*V#t!8anudPkT;&C&P)DwxMK!~Ypx~^*hzuz=`x?%WQTZq8RS^80ppE;vy zMmClV`1o)vX(j@GA2Eoa=~X0TPuI>Mtu1CF$_BG^pGLyrxpBWK&peI4!Ofx0TWM9z zk^AT31C6M$F5w6BYESG=;KV5EeK)knj_h>?>>MLe%NQ`QLC;tYlM8jtH60L4W-(^i zpco@&v0D?_j8y@f{<(>|%}XXW>r4Jdxq}*9>T*xH48Sz)6bg6K|Wycw6~ z&15nz7-TXWeW!0Q2hZ(7I#v0sdVYIl+E*M1` zi6o$96D3iUs=PD^s4vjCh=`IzqNu4k9#7CmRGQNSrPE9QUA$-a`iJMXzx?RqUZuvA z@^$HZtX0eQY)9$OuXS$Q^!twCPRF$`PgtxY*}FP+Ey*oiw}+C=bL+`PzMt`?mOapD*S|A2x6nw}c}c=Z`rkOC7h_Vs83=%ujegD?O&z z?Orurqrw)}sF1xiv|d`3VAKa{-m1Yhi=}v^j5-mh$Sz2BGlC*3lis+m6UDicXeO6X zC&nknSsOS$k!SgNR|l9cwSchQd9K7W)zN8zYL_O6T0m_=!ZfJ~xvHtni&4IbV-Ej3 z{o{J*w)VK2t5~}*o6_c-B6mh3qUcFz)cifV1OSobTF|NL^Y1MP2Ee_?<3rrkdeZF#U`Xv0X|4D|lhgYWf(&b;vJTP5cg zOzN)+YPD?jb|m>6)kQnBbQm?`7U>bZOj;*x#G51u1Kvfzwxn-@Zc-M!U1|eOiA2E$ z6CGoM!IEK48ol)=OK0#P$pm3pl!+_?u#DdNtc)sGpe)mo#yEu%3%e8;hN27ICSHbI z<1w2YKX}5F^^mKc-+;2fNZB*5-|OS?)Mu;btoY6v`l(buNSJ>@lYtN zLMnuneh&Ksfv_B?Hi%#3y&g9)nJfD1qR2GEP~t)5a9QPWS>{i^ zt{6p?BaTj+06Yo8RoE0F6BCP|4Go6Rie!M}jF-i`LE=-(V398~RAxbp^8-54MN^~v z&lJ{xO4(gB40q9FxQoWx1GtUGikCKuTP>wxkwXNb9cBE60TbHM>1IM-p13=LP3?TbU)450$cekw(`|<2aJLQ+@bT?0hp*g7uYD36&eMysI(# z2}Wx%`Y9SF7^@hm)Ge9Yx>)oCRZdqiQ8`kaHH)(XuL~FnJXQrFbN0M#k<1f9@x21# zRh1PLaRTA7X+ySQ`u%7n{pyv+G1goLlqlc$xS?LoL*9W0`e2HgC?cm*DFHH3 zhMX*pARSR}p6jKyhtMp^6QntO#)H=iS0Z~WlG zVD$C66^Chkrimtu3BTi9v}X$;$y#WJks59fcZdHRz7!T>o|HEgh}G~~zo9tX{h?rk z18s0@abU-=-3W3yg1QMJ!wB2u>bO&b@OSENZ=-|pVN+3$JZ_j#VT$m02g!B3muA%=dQutiL;*;+QtM%h^=GyXtm=nYz< zE^vz0a#ZIm7wS-6x&{$+sI3MZarDjlq%H>ffWBK7_3rWp^nvREMlgfx$xZ7$I3Z=|6GmRX#e80MA9iDr}O(292^Muhw$V z1jZ6M1vn2u;x;0Q4R{*yhDF#4Xer2GfwDyzSKd%0<+Fwm=&0y=+`oFPHF~TyxPbqu z#|hM9t-(Cl5L0L9&AEy#NuoEa>wN8`!X4So8LAr_8l)RWC>)};ObK(p+4#!!F_@O1 ztt$uVvmB={@y^|YsxTAk>x4&z9|)qS3TP{J({wa}styeZ&~nY2oU6h>ay4fX#m=NQ zml9@FeaT$d1usuf7xX~YAb^^JhgAcUehjIUV$LNx&eH3?DF3__|>HRd$6 z+z_N_kQz*_O%11R;j~-Dp>iiL$UC_NR~@P;8?0c+dWj?zvs6_EQf|vTQog-d?B^(@ zc%R?yESC06Mb{5Ke_>#1eB{XcQ^LS~n@;_bjz{-jes+!UcFk9^*Pym&dpKYjp)qWX z8gCer#wA0+3X>#i^VD}@>P^f$!=xkM>l*A=&tk4E;B0RG2K2}DO}xeS(XYSClt9~e z<0Rs(#j2qJ&=7<#E+gVvRX1?)cdQ)vap*$CLGHaY8fwGZs3vMWXvnohv>~Dx*P;k= zgAyVtfV&802g2ZujLyS^;$~3@#9?u(I4NEdWpUV`7!C<a~!>PfUgO(2@B3G*TA<9oL-i54c&!X#RlL<^H>nGn`m zh(xVHsUlHZ5Yw{g0Ftz5{crs7MMWT@S_aOCIZOeo!cQ-8!4m`VVa&lLk%`@P%quq$ zui?L;ehPemQ~+FHe>f4y2yrsLx9eJJUOKA8Km^XB=zd6&c;t6su3Z&!o~I?bmoajh z>J(WDcEgf&28B0f(55XNg}z0M5@xf2iL58caC$caEmKR_Z0KXg5Kb+Hxyr_g0uF(+ zU~=F*0kfDkO^6TLJIT`m@3L%Me{N*s zns4O^SNa_sod-EO8cC51?F(JNCzaCDT)T4_O|?LfFYKx5%&Aysejn@1`{4qVXc4kK z$S6QH$&P|RhYUn#oJovnnZSdm0XPrFO?1=VMWP4Y3_MK4?e#Rkthr-~ewp6$-udXw$~#j$4`W|> zaep)?EuDfP=c(wWoj1ltzCZNMcCnF@2d~sIu3@vN^=a~E=oNS-(rKLtNlwLfQSoXH zy2=WC@oy|ubjf)rRfQ78Rsuy-dP0BH-|Ub3l24O?9(-84XJhTY7Hc;*4ppW87viLs zy<2daSE2O+%}Nb&!7Z8zyF?o#ey~)dL>!iik*Pw{>v3#^`PhtcT&|p2dpBOTz!Kg0d`kbI1;6uRX}LMBN_NK2R?hOq#)WN^!} z7j|L{HGdA?*Xaiwx83+a*(D$2ULZ#gh9#Cx_=zUgl1?}IO-<>Rf>PAGjAFXe@8lkK zdFt-WitJsv!Sot`sA*-(i1|bFr&8908PRrxRk$$B+5);;if>8rEm(v-I8o;85N_Ea zT(?8G21mBawq4SkVd4Ni8a2;VM>J8YG4%P+fp{X$tRix~2$5PKrifx5h>wYz zL{a<`bpjV_$Bk>pjcdn^YsZBigOYLM7lT`SA+B3)wQstZd3JAx+nYKAVo@z!It`-^ zp7$)O-l$T&OWFeB*l-m2P)BXDxYu=TA>S@+o1)n?9i}#IrH@8WM1PKEqZe8u?sc|M za`Z%W?ZkW6c~yObew02EJrr$^o{PT5$+1-VuJCSjAv!|)Xd89u9nr6$*0S7r7v%$V zCFz%cTdTDv_7jVnSe?-%5sf0%jbj5_*Q%cGm)ULH#_0Q?=@9M%{I4?CzpWu_hG6Ge;hMzB!Pm^Y{kT!&$ zUZV9EmMmDIEic@?V70m0S(RSX`uW1pg5<|DG!YaNd7mt%o8;y!37V5ivAIDfPtzZ_ zbaaOB-kn&f7QCf{MnOZPprKI!r9*#ZN%60cc`Qu5g^S711`4t$v1}{gUZJNGE`BPP z?_1PKJ4ZWdzQa$NJgDzNP(KL){bmU0yRd)X0|xTZiTEK8*6J_y1;6LEd4s}q*#;Sbb(a^hzb?+nuxx^Q2w@WQ5NUVioQjX#%93lDxF^Tmm09(W-7 z>y-l+zq5;)bbyZ0j^y0n_Ty(?-+$v2*;?7MBulnY8w0|CWn*oP0rL}Z z(qL$*0u5=%G-9KCPM>lLQOMvQp&XOke9+k+~TIV?zE5r&oFeRo=K-Or4Q!8 zlj$_^gtmsJU_{Tok`gmht+abqyR$#%JLmhp!_p6NT_hC{7uh|L(kiap;#DnQnfwFm znii3NF;n<7<8$+c2aL*R83#Sc;&>=UQjKX-v0W6#u!`0+xF}9xWywKTP#m$=MfE<{ z6=GV#MN~Dq;CfwUwP1n)Jzo|KS%Eb`77qbLOgECrAVjN}fFzHh(%rk)hJw5@V?rO*~fbBkqtYtJHpUlfDrx= z5R!x^J)Hm+l7hC;dac=fSypo=9J z#mh4Q{IX^UEAb$*@$7RW3%?uL{rewTuj5WJz3|Oa9(}&_KDvZ3x_j^LC-@$)>1JTh z2F|8^z^3T_U10w`fXHfe!Ru(25WI3KWJXg)t}U0(?a2-1-pOe~E|y!G+m?GdH1$fA8w_E9gDc0hP1OoHWF;Z#`Xo=;^~5$S{>B_@Q6`X zRSf)SS&Dd2RxJqr!wEjhj6n^++!2Itc_XlCjxDgA>oR5;!f+x#+EG3Uen+K;GX58h z%do922Yv_^MLdKuC>9Gs0R@2{V993f=7b_EK>bcQlqA3yP#+0dA<59nRq1pyEXjn@ zo&}--7_vb^2iC96FJJad&$2$t&b0LQ9o#=Pb*XdbnhRY!J1wLv5C@e(8edbOE&s&&DU5w5liiOdsR&h8m)U| z=x4p?8Y7A2_y10w5W9sm(!9c-DKc8N*ALMnzE|ocwGMTvrhp>Dg4^%zaR=QoSDJQ_ z>oy4ba6o%m!4;$$XEnNCh#ty+4ul(D;p4yR%33SO-796E0kZDE3#3E z16Jf4&izYbO`)(qAS=nV;+I?$3&&m56pFh<4yZ0_bQ)YCVWnIYGCAd!#{>8PY=t6f z@5YSc6H2oQ^lw`Vmw;p=S>-T^=3_$w9XRmCO<#TZCu`32qvdBWz0}`7Jy{yf{UUsP z*RJnu87NY8<2W+bdTMZAfA?3yEdNI<`b^QIUa*c> zDjvZ5@FC?0KCVcZ@v2Ti1Qds@`F;n5wq^UkcZ#ZJFtIQuSWyX*RasL~y2r;W?x4gb zJ{Xw(@>DR#Y&ArjRmBKDgX_E~GY%A)s4!X-nW%6VBzoDEEAER3zT#G{?co(GSB&X5 zbv&pK>1XsY{h}`EI7OKOuS^ejJe}Q;%DS(*&*uWMGB8~9Ot|VziUit7r|AtU(ybbR zT&!wUfw`*UBIeD^{ZhtjAKQ7Js0s#&~MuUKZHtV7Ut1ud}%~ zh>}Og(ZAmtFV(yU{QDQOs2`a1mIPVy1mWaQeMt0y;5&@BrMm+ZQ|#oHn}afMSfiVuJW4lrmSri zH_NBQQ}Q|SoIEK`%GbnevKEWwV~4~;@~}88%VJOt)P}>X{9SH1Q&4KmYlsvF1EMVY z?AmAuGsay4{EB>ilp;AA4m+AChk^k~ueHM@s-G1cWF9!?f?N^q zJ5{&8FkbQhH@SogSLb0w+VVK7UlxNXp_Z0ZsJBvYo*#%yQsQ>lIt9 zIWQldShBEIIsc<^=1(E`=eW*n46`FHOB)th&cM|`!Z7a?jPO>ArLK;(iFMP$p0&ps zw9Z&#)tWyZgamm zXwI0DIqCCRq3=x~O{mQ<2HHfEV?0lqW?L4~SmBNd>gi-L;Z6*wmz zJ{*d3L&L|F=5}s=XGrh)QnL2hr}B?(TfNi})6h;ozW4FO^E=fy!^?jND7-ER;ym+{ z=-9hTR4Zq7)_Y!q_wwUkYgaU4VpqW;@)4r?=z6q?tW!790rkuD2pT4b)nPh~X2`TU zLvN{fsHM_6?9vzT3-lNrL8r)wdWyb{&XI96N#0d2qibYJH6>M}7K#u@b?GQNiGNB) z)t^%xF}Q4`QL1Z@MVi3~7!xt_WGQCG{pO(kcfd22{l0RPD`UT93MiFkGr|P@4GY0TCwqumfXiX$IkA& z&-?tI=XpU@B`wNjp~lomi-MgHf0RrhtEXvTN_eWE@Vy3nH-%OyC1-(HE1mu3Hgmv~ z%?^{t^cFgr9Cxm@!1|I&YJ8>r$Rv z^y|B&paUZ~e2Gp2&rB_z8RMKG^%+}@ZN`A17+nAOCUjlZ+)u1Ta%OQ><|IHDi)o|X> zyGIdET0H|8<+&xlu~gQLk=5wJ{yj0%wv(c!f%>3QKf} zZDK$O21Sq93Kvjr6_S`j%VE$hBvRG^`yVl-!J!88@-qL$9sY|-{+W^0@{`z4ga0-8 zjFN|bmO?)=`-*>$`em_)jfY?{jo#igRtJh;rES)H3i%aCC#=_+M%;MbQ#>M%C zH-CNd!uD12Dq}_R+nH6l-p1bicP6d8dBxUv{ca$V*Tb+fT4*)*Y*vx#kO z88I%>&~{5ERui*KfG`2g@5DVT(ZVb=du$tu3!aW`TbA4097TY100@dx*>{V{6CdlngjjE`srSqlRe)QG7C(pb(^MM7W z>5ts;yQ}ZM*7b1Pj*ZKEpL?S3f%T(z|Ge-1`ySk|`Z2M`7hZ?I@9Y)-U~`vm@C!3% z@)mBt$7ghSe%HC*yz$oq`w#7TXaBx^Z@zgDr=EaOpQouWAr?RCA5rc?MdhkjyUgIA zr4gwR(=}5LCz?kJ_&esIuB=NM%EEs|?8`JyilVIRBaQVYRppL%nt+D63)z zoR^MSRoY7G`e=!NSi0}&k^SIBz4B8dy?zJ31yP#=DE=ByORjVAGFeAit;G)X8hm_x96r0=>2Pd!sC*~O;GK-(7pk4tOnO+0 zCxF#aJg%eOGk9~B%>z@OR8yfTc6YJLJIFd_1dC|WO3FgX+bzP9#xpsoj;{o(Hq7~L zw-%{?;A%cUZB8k>Zt==rl}f+evVQj$l>F-t-@j-&e+P`_rS=WmzYAzQ&X_n!9QwZ3 z!VJskGvu7nYRofw40O!_A?G&HY^<tO~>ni zoqovI%O2?s(}>6dNu6MP9@3TvgsljAVR-cV)##e43*ar%)*|AD%%$(gOZ?dqe{RQB zj8Uu6(c~wu9miSuN7Mx{s|3tyvSss}Jrua;(IVAoYs zvZ|+aeMZ$28tx{82o>grvm&Jl=k>j3t{w`-rXo0SvSD}GiMtDP7*Ho=@pOu(lRT|( zryxms93qEN&~>|+Bsdi5QlQR0B?}UA>_NpqOrckG2VL$`%tcppxn#8HaZ)aelxx@6 z@lqgO9}wbth&U7jJJNTw<8M!o8SPtiuE*nyyr7(Uhe|jQD2{}*KY$?!Di3aCwbt7N z(k$!kP_;&9aj@6m@3;(hpu<8;TMPdns)21fHEL6X-M|C8Y?{PR{Nuvkjvn?u?;qnQ z_P(@b!wW|t3V(C&=AZ3=4Uo@Yx?m}!o1cP4O$G#IW-^!Oyi_)-7F<^rOidI_Q`S?> zI_(XZM=FASoF1J1Vlj?vGs0*%jBD92EM+sMjFJn~Mjbnzs^?A=ek5a7J*&}b>%j-$>xYnBn&3Oc zyBMOaJXk7?*rij0=U+eR&o1r#{ZseuK8m3kA%FQ7oAy4vVDX%Lfw3FGAx{I|I!j@) z$VR0?Dy7321C}P5Rg=;KrucxF=R;;fP9|oOWUAP05tE(DK}6LY#Db|=r^8w1{J?qM zdBu6n8FZovhbNpT=;|+Ueb$LMJl4W0STZHpWkE}$5gS6Xri9m3j8o5@p@*7WQb|%26%4#1eDbA zfO(9~c$JwH!LT_~McSF6B0}MNw2qmCplKE}oz^9r9(Edo$!s2bU%af$hU}8%4|#X% z3U5z;G5w9`vUry{-%;r&rhaW_K%ZD94mzi4)GT+7s!c^+&S* zRNhNmQLc%P5?7q7>3`K<$Tms^+fK2Xj2dBTN*|XoVzSlj;#PxC=_32_RJiB@Bm%BQ ziF?=BM_wI{rPUpCrRUwl?vQ)VRsPL)wZKMkUD5a6{D14&o&AjM-Sv8R$7|RMLv8aD z#X}2(HpL`rXiKO|rKB_}C_qz0KCKc+`L-nxLR(O&pg*Yz6cSuMZipO`C=w(RML+~a z1yP`g$kY{-B8u0&_lYSnb>!|DHn{-9>WHEK!W7mA zLqcCP=xDTS2^Iv-2gzi@h5><<3Lv_?oT$zMYrD_5eTR1RJahZh`~5X%x`ju7wCR-} zJhyEPRLRtf{VOiMUFoY_r0V6$Na1%!_y6^SL&rb-5EyO%?HvW}#YjDLx+YP}sBPv{ zbFTV`dBRklF=$aWnJ%j;?@+3222<5deS+L7K%&1!T+<8yLlaE1zAOkVUXIC{ zsxsY>RY7yuaB;^50mWZb6i5sb_2MbTy@p?+i_N1WAbuFP_zc6$uO2HXB4&rXx*jA}AAfZ(_y7!5B zU30dbJ3Qy>TQ|RRkWLsRJG$2X@qO%g^jBk6UZL3+qlxaN>vnE_{0sBufL&ZEovkHD(V0k`H?atG@{?Lpv6PS09<;e)l-d*MPcFYu{^0074>LDH- z?`MUYc#UVY8`BMGY;2nIY{QQmKo-elT{>Q)Fy0xnp-`-Pkd;FB~e}SmHP)i;qUd}t_orf(t zo9uy5OOqfl*>H7_y2^bmT`etLtxyC(czEvqUs8k)7u4BcBig-s%Bo(|B zjlf3KBQ{Ddq9d&l)GQwwBN1*5J~YdQNJoT4#?-eRq&jiSo%W4zf-KJ*m;~0*HM8#q zZ(3m-E8|ty#o!ZBr-??K8l99Z7i2chCV+cNL8ukBys|dBarwm&d(t1jb>Wsw*||5) zy1PH~m#4Qx*>_*rwTr5$-KQ*278Pjoq0Q;judhdpI|i=^uZxqJOukBnFsGBG9=QH8 zzt(_*iCkwVIS1=MAf&;MGOFgV&QwNblqp~qN(>b?I5_z0%ENRb-)AO4H*^MX%eSCc z){;E*%7%oPknN&C%lW)!lxyX>vgVXyF%A5L)ZvhGBj|dXiCqt`xvOayAnpSRY5+xE2F@iMaT#**T zxDIR6b5%^NZVZp%;`#Czc3h5vo5qdZIG$scJI_7m3hr;6tp)q$&8k7!khgCP*;SAh z!&VC;3nWH6%;3QDumBFSLS3~7x(egCIQ7!m>+fEuOs-g^MNecFJ<#0IEX+N$^W_CS zr!d^?-15Rz2O0Qlisde>D(iSVs)cgbn;CeznQ-q$%PiCPozeX0y7RS&a*3*y2n|%$#}5 zJP*%wrtb@rB^PO3beE!?$GLR3@W$J0xj|pbn^wf5Bx+*;zTNh(uJs$hB z;4Jkgq`ErDQchY|YFu5+)zf<0%WzZ4a8t3ksaV`ptk6^}-t{eRDpqJJ7B>|uiO5*o zR4m$SQL8f(no6cW!xm?@XZBvKh`NM`u$W5urNY+ayICT3usGFi^3a0cXocQN{0YEA%vaAzt=*T=J z2s%G<+zcw?9~@d(T=#iI$O)9cf+tr=l0$A}&W+5ukr_WI78`B=i|hOFd3oA>N3Yrr z9=>DP;g@Z$jP4ej;P5B!EP|4T(@&vClwLNM2qf-nG)vfP5_wIuFWZ+1x{=e~n3$qG zPmgTeNMH)vPKfHmTWcgi8X-SV^xYC|mRm~e=qmYD<2R946RP5BNj4jj^A+F2)i^ev zEoCd&ONumJr2tM3qj3h&S&;?G8b(?N=zPDqcBC`2kZ&(~OI1}?smxR+DT#=r zq$87H*XMm3A(13iFTQ7c?18;i5cjj334wnx}Z;h&C2kQo)feO zitpbLT%j$bReIN_P9FhZ)!D>$iqSZe6;$cmMagd%9jP?e3)*FG7ghL>UZS)qPI8 zYA4Y9i9Dn#XR*Zu6eA#?ZX2~Dm;`1FJ~m1Q289`|HKiLOM=%Z!QVWAKpKtuo1NWg2H8=!zmPbpYa=8G~5w*flQ{$s>8%-r2u($T1 zX=MfzZYKL4v2ds90d*5gzF1YoPi$?9!!Vjkmfs6!lXb8vfp?qFy|LiDICvU@GhxVv zVU&v2C2z)?qNzDgmHHqA30NovQTh%Z*G;E;(vRGW_AwB^zcGlr= zZWO!>4WGSwvw&X($*=pXGJ+a!-${dVH%)sfz!E+M15VRPa4N?^>Qn+$@iRwajfq5K zUD8)yuES5B04EZS;E$&voehVxsVI28GoRlA=7zIiEj*fMt%9Oxt1d+ptSHqEPlqhe zwc1Njtp-ftM__O`B5ZU!I~|>#PSxG&CT=~lAmi2-sc>msk#SQ3+EFSMWQy*r6Qxn0 zrX3G>g0oRt2Hx2J^ycsm{N#4*e3V1wd%gL5Z+fmz7^>y~R82GFsdACl4B}~xAPF)| zeYh;<*1@$opwmuccliKGz)lhhq1w}S8ju0SBGX%7n>YfSGHRg=+k%%y!p_UWIWNgw zugO7<(Y#yOn1Ht!eq5{MP$jJ@4ge~<0hNS-N(d@#x%p;YP%2aetj0!0 ze8?ht1{BP=|6kLr^W*VIOJA5n5RWo?9#de{Q@%`UrWb)H&LP}^;H*?Nb@n*!!H3G1 z^Lb<4dRVswlt=9l(_taU!OyW_jLK=pg1#ax1|R)5&NG?3T+Z;lG-d!!QvO^Ad;Vl4*cE4{p1K_SMUO| zfTf7m^iWt-;ZQY#Wyb1$#^8-LIiud<B83c?r zHUOy81XSZtZ&W1I=JQ(l`}8dDV!FwX*%PO{155;skarO)PnJLhY9N38AXTm( zP&n_sj}T^T>@nsHw~DgfMP!|c020-?zE=o}+1wO&H-w_89JeYP@zn)W(WV5#(=2;z z`d9P!5Y6&4_F!NS2Qjxe*_gmSqhjb5#sLCb0KY)c@Lte03{*f+mrx7lT3E)4tSzis zXpviBC$nfYF9V;E@$qqH)A;z*TjS&4`3oRu*FYq_=%4y`tN40pG5#!B$}bg`NK3t6 z!0X6rex0ydTIb!!vm2#R zS-(x>BBEu4Tthy2GF?zLd9t8E0lM7&C7Mf1yEG7`po8E8-&FLd)zQ+j&moVsoVJh^ z8=f8_0m+q-K$s1{9kl1BR1&r0_Sz`6SedBD-OOk>muqg;K#yD5HFwI}pLNBr#A^or z{Sn^qc*;?AB_MC^B+Im)mVbm_!ssjbnR2Y@`Iq1S+Yg6U(Y#4R^qSZda-)~^1Sk9C z4f5CJzsnqAi;O50?eK3Gi%u&Sfz=9Ce>g~`AEwQ&jcPy4Q{4yt|7j4O+rik;Av+jt zXGh2%kq3NN<1XMZL!ze*KGrCpAOfiZjA>pFfUZnENM&n7PK&T!W>5c=Kn^Vb_3-ER z%lnSv8jSn;`tY{i!%sVo`TjFS?S=z_+y=X=&^5h{3Ah8%fErpXW&&%)P2x6jm)LDN z$o1Ro49lL!M8TMFR%?_O6`mJ4R^+jC8w!IZEbHT~gb_VO#j3c9J}W0myyvo_Sb6H9 zi|1J>f|=vw6!{%tfR3TH(;Y?}MB0F=z#}8%DhkPy&<>=#)Ihr?m(rTLSku%Av-K!w z(7pl8uh5n*P|#dU+y>r`E_n>@fjHbvG3<#l3&70gTu!?m5uiY_cgs7gcdcJ~X~Wtp ztE<{pElWC9Jh%T~hWw^{zI+t3hhI8z=&RV@wkanb^=&9bNKg`@>rD1N;Bk9K+TllDp=8d_zEid2xOBEs5l^>exQfbOon}ed4g?Y+SskE)lo!lt4nl9MMR*rgC6jX zZlmwz3>#qnFQY@DI$3eCQa&Y zi&KzCp$5>zEKE~H9;twt)E4Yipq3&y;Uz^11Um>yiD*ftJcK|gsI9fdaq6RWD&QE< ziHQtDvu$$Y@0`0E@E^ySWar%7lg;n(ec$iFa2&>I%4AZ*jHX#Eu$yv5VI7FD>Q z2QI)>4rdT)e0W-_F2-~$69ia=LlCrA(;%F7cfW$?xIMGFJ6||*riZsm?zqDjiQMu1 zxntbk;iF^`)bJ$$+G3{B$u1&uA`?~Qa3@FHF1iiTgBJ^D(;&H=+S0A_Z-^~8bgfx@ zk)QC%`|v#&EdkVCgHsUAPZ#SUCj=6MZkSn11fOZrZI^R2&C-Jywu9fKm5^nt@b!*` zAz23-A82-~gcdt0QZPU#a&98p&`#Hb8ad^*-cWIAE9*5Okg#1q& z8u#Fk)*1$XiVpr!AP&DzCeS)ga+h%%7*iK_SID(8;ZBbXARg)zlr$i!h}0~R7zG(q zZ>1wtIs}>i8zId2>M-t7^)qrcF)0Icf;aUu)wtT@9&e6vZ_?gx<0&}Y({OTa%Pzhs zeBJFIs^DJk-0_eNQOzG20I5i#2wIb_nkCHgHwjJt2D8ByrwI4?YlT`rk2^rwI>L(D z0fVVSm#_*mS4{PU}Ch@TS|h;8CVQIKUD3K}B76(5ZaDAJqf%3sq=c@@PDI!u>oL*a0vOZ5bL zklnUgn0mxZd14VPHEmInM5Y#C zA1F>s&G^S;&Xmf;qdoDdb@vqvcc0@YxPz;=%$WJaw~n^2-;kP9-8iG2RDsUtRl^6m zu{v!{7wg5PB4=i?tYvvgc6_6%;nQeb@O+D@hR;(C!y$F_Q^HikJKXjlOqgnr|5A-R zdDUQ@DlN@v1(z2OzGkSI>4m2qo?5t%;0~%D!(|lj^C9BTLd1pWQaUX2lFt{K%qK#P ze50^jSYi2*!BLTzt*Uwi#=L_Ocm@=TL@e5|h!aJ2Gz$Fx|JIm0IgPn@)_pu(IP0;2)UnCZ zk}l(QTOY5-f|a^J03|Y%&Ij{FAw)J5tSCGkH2rCl4H}6J8jb!l_O42+7BhRycTCQt z#S1bnd*zGYLuC&g_qs`1A5!Nc{9xh2QP*^k`0`Ha1-gGUj$8$7JcI(^CO=G1i4`TI zGotmRL1^&TtMx{c)fBFe9`XM;(2H-1x=Gufd-H)T!y>>f-f7|(OW;t(;iNH=t%Qz~(s!4X8T#f&v<6uMqwV8f6c-zoAo?Kf+6 zj544i4%<@!SRfPy#>6tiW{t;|P1-ZeMrTlF0v8X0rUm1i#___$1g<;z>-|R;$rof_ zaN!~MqWkBf6YIG{LoZJMFsDbL zW3Lh;H5j8G)-d8G3DoU6JQZ#31U8EXEs$oU2W?SkxL4z$8Ubds&A;#F8OPhKr$P<|cDjhd5ISN-Pbhi*| zJI~(4)$V!s+Ql`WZhrBVk6wRy!55$!_Wg4=?BGe2`!9FM9dX~CaUgZ^jbm4Wudjoe zeDAvy!_e!;0K)-v_!QzmuOFl!^>g@({4%nXTgpF0p5$+GS7^e!r^FM8difQ;4DGACpHhxPK0 zjpDfC_{{9y?(KTLyZ3AF2R{4GzB^+s^_jCTjyW4IAtg8s#!Ukx77&DJemGF!0I5)F z0g)n#k`|%>N|TDDDQXdQio*~8fGQ>-KU5S%35t?J2%(^el)yg)5(nR2-^||GMv(t< z(w+Ct^XARWd-LAs8$onC^vWjdQ$SjjxbCW_p@rS#*j3%w^B#uyHld~_XlHD1$s`t4 zB6@sKzS$NtjohQMBign4e2yo+T>rmu_0LS1j}Jex<~K8~9o?^U&sjB%J*)a?1>X)k z{|&zh=Y&5C1EwgKMmYGj$MT7dV}|Y`3TadD#WHHT8q+<$-hB&MmFU zWF8oeny_MyGH^y0h1HL==_Vm6TPi_O0 zAGwh`LgW{>E~F&CEPviH1tJoK?l4Q#oE}3f^8`c5id5B9Eu*)1T0&FHXM1M{A9gHs zcUC+O4Axb#rsOGQwf=NyZN&?YP34;^%2bYvx<<-M3^6J=>CFnzWg4vbMA@e^B8pKX z;)k|*pi1RXBud+0rG7P+PD2XPA_ALXxkta$(+FU{+n+9U2hm{EPcM`}c&H}C#o+`m zxVm=x4hMwL&-ZK%_CNPb--BxMaLl*dx_0tVu1DqLz1Fvnc5TIBYwx^=mbNL&pItNb zH~gXX>oeA={sXuJ2XLImDE}S*62zz+y<*m4zS4Z>sh7esiaZ z?U#)EZ9hPMG`Fc+-BOp#Ek>PWC*H)o22F*791%z}UdHvJ)Mcprtx$ib)_EYcJC`2o zhoKv+b&Pk(PBL0pYn>TFJa+KBqhR_7EfzwvW0}~?!z{Tpv>$sey;-M+57R~AjgP^c zmUnDoHaRL>pKPB^h2fRLbr z@P#8M_PKObABJa*oIoP{mElxCE#zQEb!AQ$u;0AMjRfCcoJqG$fj)erpE)`<$7hU3`4o=t^=d_ip>$oG|+J zD%b+a_rhT=cHD~;q@(sB_~qn)*sE)@F35xAal6F&rQ zxymFGoFb?s-GUqEN*fHn6A7sQbm28gBN2$Frs54p9QS4-frNq6(RiKp1x>Jg9!-Ys z29=&9$ZlAbNPdT$_&N%k8o`@2j6iyj8JG}lh@3(-D2bDcG8uFmyKT(w4pYG$+7^v$ z(fRrk-EYBfA-6=FpoYAFyT^%>*y*xirRqcYP_Bqbmsc{83ZQ= z$>;lO#ywCMu&!h>Lp$J4z|%V{*Pb;aDJ?5alh+DsrM2<~B2FPwgelS#xtU}IL6DqI zDx_*v7j%q+qTq%8D@fBEBRtQ^3S3o*mz;uA6iazvxK!zI>G4volu8f4GQcldKPSo# znt2xrs-qw}FhNzoE>w8X8#myxZv5AJ8hhXR=Nnf_<##y6nrwXp&@#GqCjJz!pz&cn z(lHC-Gi0AE*8?XOGE4E?S}fPr8U`G0d0&vktZz1+ zL)x5kq&8)aPYgN}%3XLG$vU%AlOneIHb|R&e^E~P98OZ>ne1x;{0=CP63Sry;(q#2 z33uDPqc4O*Awl*jK!!w;p*oe69F(zFma$L45-$r5gk_fwL|je{qR5CC>x@0du;HjM zQU);$ho-xEhbR%n$GZePNR|w&r-fAqnMjWISC`0+h%8Vgl+drIFQ@7Y^zU-}n;_59 zu6o+BY0aP-0N(I>ft*FPxp||izt@ZcE+!6=$*FY+5^xc`qE%QBxhjvlkz+ccu^tj# z#0_^sXE*G!Q<+Hc_kCkMxyYUTAX&cm+e`St>FLto2Lade$E-K~2|v^ys7L;UL0alx zwO$16f;#a+D_*l=*g3haVVRxdKUH*CAlW}(Su2%E9>F%pS&#J0rxVuxc66brj(R)mJg zmj!c{r}X|`V0rXs+rAyye%-n|;_h?v$X(*#!O%HGKA+%sJFM4aes{9`dl@VFw^6z2 zB4&7HxG&7n^*SNVVZG;yc94hg!hNi7y3v9mq(D#LiOdOH1T?@Evy2vfB$v{XX3o5) z0hukC*ASkI@?d)i+MO3UAzP#rG(=N(HE5}1H^_wUrzn`^pgS8SY`iFO;vB0t71((uAWsn)nlsu2F+99A)Z0< z(Y~1b{lE}8i6W`oSNd0rl1#EP;!Iw4*^GIi6>^i|cBSC+`VFRcs$oZsRN_s@M%W{l z{llA5=>Ke23vd(18Q$Hy)7|N$(@8o#PL|Qjl4V4Yg@px;!Pm4?pbTj!&=!J|jE6EE zN*i!WA24aBWCC$WN-{8QQl<%0!jxDE;bCm^Na}_*=}h{fnW2P|v{0Kz2T~?ujGe)! z{=1TGIf>;t?VkR<+x`C6_x0=Ic58?{HfEHM3rB0@UU+R+?edS-?mD>c!k2UVH}18% z$|r~46FC}vPnG@y-n<*Ud7$D=eY~2aW3{w|PMZij=0!5@MGdVz4)o$()4}rybRL;- zWxUFjX(|Ih+o2vHDAb`&?4%BLGKUV89ZEe489jI0sUqw8RW6Op&LzqYrDSe6(~!u` zNW;NC-MJyMJ$;q>=uss&k!vC_X*}Ooy2*WwFMxHiY<=rbD18{mK@ylcWhN;8P<%t2 zL-87?2&;pWX~@>MOzH5jJ~9^-4&xZ@)HEXKpqI966r(qRFVIdM3(-zZOZ$a!zCimj z-4Eo~e75_86_2!*PL=ncoaR$uQO%@B%I_yF%>Gc>zSLg&3(6hFVY&kvnK0<@g_mmK zXTqef^xxjFk8owOGI0{h2{^Q>bP?Wt4{!nlrLkegveQ?4R{NI)epN zDd6lwrlM(Nh3Ej@w4yv$RT$ZwPBtGl6^8>x&^y@ta+%}zm2Qr+{*Rb~gTV+x8Hn*) zrhU4aLUso{646K0(#1$+K2+&4N{Dw32P1Tfj1W8)=QGJ!J|^oI7Q(PHVBGiMmld> zQ43z`N$M1fBt(a)I{>PrnMmc6rV-93p)69GKGIE783uPuozZl*LQ7Ccvl`Z@Uh_{! zQN=@JPLb%Z3ZwE0?bKz20o}H7VA;2o831&fvaPi4!8hO=n1cgz+Q1CE^`=>c0AT5M zH#bH7J|SE7kb%)Al)vRZpI?uz$ zXgr70>EQa>S|TZZj?_Gk?QHIc8GpF9EeJyRMmqZG}IL~+QNu|z&Y zG0kNBT1sFyh4BccgI)?vx5{Mo3^~R!gVdD#yj#qhZA_#%xKNw-3+2GiLZfpN*I`^z?p)L5y9c zXrqWlG3Jj3pgJCFR5=ul(Q22~hR0^j0@6$w@EBk~Ya3(Bt@Kutdu}CM*dGpf0uU)6 z%T!ME)2L}Kz{Ey)h!W!F@OW>gA%j!A&AqP6*B`WnmcF*z=y`n0q2+3(zs|Sby7lhK zu}4)-gOI87B}0vT@)hg$+I72et#xF@H`*6D)^FW(yolene(=6^zULUe4+nA5BDq8& z=dBNwV<=r3;de1lov3ujZKZuEY`XB?hC>YmHN=A+@KaF=7ZYI`~jnX4BC%8gVeK5~0MvL*+jfbTtrL94GSq(yixN6?bbfKZSTxAIerO}0; zUm!yxGOscPsEn$*&*yTfHosSAYR}MkUzOU^qdri3rmM!TI9!`l)fsg-gea4JAtw07 zTC@SJW!6;j2l5XBS)-pDRnqTKty=nJsp`XRs7mqGC+ONq)yJ=yRC(J@z45~;omZvo zPC@DW_N2H2yh<0W8>mi@A=aGTghNFRLM5BcHF_aX>J|#}=zuLu?UG>kPvLQ-Vr+VX zLO>x)$P$%c$Dq^64?_6$AC=WS*GJBoPQgAX+XiLPggd}=&h-eA+1i?ysPppvKwgpr zMNoc&15W}AZL+M`oMH$ zn(~UG774uHHYn0P^ni(r!yGjcD^n;cu)bG_gSj9O=r);wHu|q!htJro>M6=*npk53 zhq&oT8_TpXv&{7t?KngM)QQP{AcUNIE!-qD+di-PR#vNLV}k26uVs zDk#Xl(g#QB#;7ZuY;&Y&r%$jSC+`7ay_NaQjo#44KC#gZfEWYt0K!;efi?Vp!mBkl zj;jjanVpCCF|#|fvpcgd?_+j%)*gFbGv4(iPCVIl?AUI|J86?xMkzrltx8G@0Ypn_ zYE^APMM6N4LR6%viiCn>JC4^Tphha9Lj0pNRN@D!R4G#GrY(s}X&#(AW2d1i!uIYR z&3N~o^L^hr=ey6>-iCMy2#r4dOzo}9wP$cO{~CJgisy$&KE_$SuLk!1_~D-(Z*FQfN@I;i6?*Y2M3i`k`UgaiLR0@81DJjs1lF4;aglrQZ zNFhJG5Q~+{kWUA43$nHtHd*#*@X(=LuCz?9pfZu4!KTe{a#^t|f;(|=Z4J9t4>PV4 z61$d=d-{k-a#V&<#A;@gMJq@=EpPBacm`xo9}{gi)$)-nnbC<}aBA zc9T{;HdL8@k&K-wRvHI{vX)DnA;wzuGzc2|tEdVe0|KknfeyK92YPUI^z@`TMG^4h zG*rKwFw?jT@S>RpWdng0&I60xl|KHnEYWfb06SD*+<7WErSDJ-X+|C8L%J%k>z-^F z)*%`{z?Vgrd$_^k$1dx{yU{2wvir*$#txLIfE1QQR$~29Iaj1u&(>if6xZ~DL~%@! zq9WbRG4aBdoKNN|J?%z!zU57T%~O2pXu8?zjYLvGsS*-WnM%bh?vsm2QDPEd2ix1L z#3^(L7!IPXOQ;Kw^Z5c8IUeS!H)!%ag*q`)x|0*WyVwQAum#p?{42QkCW z`=Lsox~s30+gRyWck8_>ROu*v1TtkH@RwY&g!_0c8X{NaiTb)15~MP9v-H z-Q9T*^y-|~>*yd4{Ku1K9_t_+aaTSBE0LPP{=ung1GA2Oo`AJrxKc1&9juGM;U5d2 zdAIvTur}nVw%#Iv@^g%5PhFg-j}MI5*>p(S-XHJvOCiBOSrmQ#SYH?Yq>vZuO>tXn z(9pt>c)E3TuoUiT@|=GvQRdmGl9TW}9li5cVD-!wVEV7mV|ou`YnYy?_Nh>MIs83< z=qwWhJfE`@tU?uv*B%|Njj6bVsOvKUf|Qt%dj^7}t zFTll|D5jRlPf!vdjL2pZL&=5AB*2K7tvfKfRRwWb4z5$~7!@qH*hI_aABKj5r!za6 zO$pCXqYl_M0Z)7}(2Pcj*?7tjyTcJNqxSalT!a!uJsuDvU34H>jEWJ8rT;KlZ3MWy zn6c{dddAz84@A|$_#{*Fr|Tu130Ky;&n|{Tex#uOCFF%vgTd%UNYz7Lhksa|3j_e% ze^j_TG8~Bv6)ra~KFXWtomjW*lILSb^*{q-~LuN&2WO6`+ zy5ohX;e;eBiYVK@lqt&selFtES-=#XX}d<(lwbe``ig7S;74$Qn8J5%xjw`ds>U$t z8V0~BsojHt5yh(kR`vDi2d%wQ?$~%CluG-R(%^`Ba@-th@7`DK31zwl&4;8cO+WbL zv-!fHHLi`l^4Rbd6R$?cL4$pON||0jI{L=^vuVPawSK|O zz`E#zmE(}|d$1`o0D)Y)asm7oxUgJ@ygAQtC1@)*!K$&#=j8}Ah56Q}2sWn`*DY7`vn$qd_N@0lW)FLB zdzW1=_OjyxFJ2!Q2iy3Hfr2o&m~KcZ0V*XDF0Cpe(vUz%MAcBK7X=k#XPuIks!E$S3sEx zMpDB087MYE0s%z91aRl=5X>OSN>Fean1W98HgJ*VMXffe5#Uh>tc8eE*accj(L6;3 zj8LgDVMwRw^YW7y>a@Zy&Us(nxjm;03=c{!E`4}v>G7p^Z~`Cw2F}jCdu{2TnEUN} zq@pvpo_-6soTK<7w;Rf-+F0?kvw!9crV5km@Nsk?$o z!m#iM7_0Q`e<|#dx)$IGjk8c0Q(E3L3&p|v)l2_bpPvfwQZWay0AFK5lo9$Z@5$fS z%R;VTb8h;?@L+>6k!$K}rS>nq`4WD6@xv!h9XRq;?3j7~I&S;q?8)g7GF3OBcRi9{ zAqxtiJqySJVNU~arS)J{tWJqf1gTCeQBL^R=fh6IFl+^|Dr)hP$73avCZQJR%5iT6 zs<+9+0Za*_h*_6?1gH=!M6F+qa9lMhBU#CD;uQ8|cepI=?e4wLIQ&BYzQ;nmN>=63 zT`)QOn!m8U!!d~Oy`MdC07q)HBb(QaKA9gK>iGKLcmFV6M=3{R!bl((RU^o6Gw3{h zS=tDWM2D=XPf+M6oi!=dU{IA$W)%vZnYjp;&HD%C4lNcV0` ztto8C-}{Q>(7k`8y1P@UjlBecKSObRgYuv%lvyAeH3v;G$fTqjYHd;~HK0PA z`QDnEa7Ma~nQ{hoGN$P07--tcOywO{Kx$byiezFm$zpLc5#Ky@f6h6Dr>1&KFe_#y zdB_+!DaR&Y6VRsWZIfNr>0GJ&<$m(z4!Fqq!+i;yNOa^k59nBjQ$8)*x^1#4I31Rf z$8MwUzcwi-)yc`p4Ef?P9Mf2siQT#d8*}Rx$T@Mw8OR?Eu_CdAfK2g|M65{eNF*6w zT})C69Aq*3@M4x+S1fBFAS3!muEdB^y#j#rs_hm6oi4YJwdUw()b1VVj4E5)%^^Oxbe%J>9LKUI=0&^LY;mlOrEG!gQo7yK z9Cp+OoRR5-Ldf;`?Wrh})@w~l1MhHpeFnY3W{;%owSC=5xuR`Ty(1KKM)o!+4@oxF z+Sf$9oTo-r#k&j~XVBM}fOnv`NCGdIOfcqd*3J6hgh9GLbE-!qN0+HP&Lu~8=dhq?{e$1bNs=f=~ybFuw~+nN2%`P z`Dwd5+cDO=k@?<)dGmMtIjf~!9pDq0+-Il|qq8_de_Qf%6h^NRR`_5Z+<{7MX2@Kq zz+Es#y~XUZn}H?-r9un2fYa+`;QsH-Ar6DFfH8xL1DL3A0QN$uR;i3$i{FKe5D_jj zj2{6J-WT*1i^~tH6+nX84&?7A0U{p20r0>pHrbGAfS^FE@$GWf6xoM(l3c|qm+c8F z4hrldVSXb-15>Juc$w(9U|h)lrA?w51j;s&7wy>Du8~4sJ29HAkJQU0?)vC>(VpmZ z_CK-CWPABg)B4(=T9M!bp7s=T?Juux4W4_>VQp4})b4&#uWRg*KYym$zO|)c>e)Zt zy!_2)iv%O5aR+@&@_kVDFgh%lc^BAcCpnqi9E~jMpaK!Qg06smW7s4MwR}mT2ogDm zR3+$5YBv{zgEF3n0L(E#z&MjT#&5LBKZ)h99pMMO40>d77fk(326UGdA6 z5FsMVkT!~Yv8IBo6>Q-Pt?%s~Ybi|G;YIIBPi?$qsPA}PTnN;+XG3}B z`ptKLJ%8%p?k{OgK1VV=QN;F-7Jp-MB?5(GN6v=YhWmFFgn|ulbPaHHSn>wq(NlAf zuDGNU5Ht^E>GY(eJM%W1*=SUYiOXz8>et0Q@n@l$7IgX~EvPg}+Q#d3I=jurgJS*_ zB$6l0i?FBcwqX|%um@1Gm?X;}iIv|fI{@XD88Ri3q0Ik)-o#7+FT5qc>4g)$T}=lf zYxZ|3JA3NC{KDra29F<(Y=3;Ry{8ICegGLJw=VYFaG`&2LTT2wHKdw7jX(8l*>>#o z<^K)O{9jknsDrtIeeFMUhj(sfmHLDlPY7Vv5dGb~;;7IHo_UXaXY!JTw;WaU&knoOsKY*rAGGQQ2>fb?EKe)7Q_ zG8%Q}a^)8}6JR#G)2X-+ZOE3%59c~M(xE6EW&|NUPkx9};D8-2C54@^*$R;m&VY{v z^owl`>WA7B(v976x*PRs#;FZw05*Zut9YByl0}W0Wq}UsvKy8UT8TUwq8;{Xmf)kd z*uaM4BwmrX|E6i<+dkJ*5dP{7$e^O##zzy4Mt!|Q$8n8b6X#%bCV$MyIdn9=CDkad zYm}m^TU>VaaB;My-E4~3_|8^ufD?>H!Q_l)JtK50%eN((4Yt-#O`d#O?j$PngsArs zH{ee9n}~!Njn@i9-k;VJY3prB9mtAsCam}U`+|NKAzu5W|6?8MS~{;UQEwqX;*o$P z^tX~=64pcs$AX-<*?p&%S`rXxIYizj%V zsN}&fYWAJg<RsjB6hv^I&m?=C+H0?wKR7e zQ!g#5mln0Ijn~icvJG;n6ADT&oKa$`Cvp&Uyu$|XIK1_x{}kT(>{Qay8FV@VUp#V! zTHBrfFS+ zr3)`_etB|g(@UsQd8oXT3IQ%%Wq#>A@qoIlGGmb&{j@}55`;#8g_vXEz+nP9gB}y0 zX~I~?U;-=)*fD{+BNTCqA}Gpi!@I2=q_2l)2I=**4ohz^7zqkt=}D4d>#+1jquFk^ z*(`5@x+c)wi_BPK>%#w(_Q|@6E0hx<;jss(N_u;xTHjv$74Z+hZDf3y^JQ1+^WfTv z)s5>fZI{PpDwT)IIH@rDq$}qCsjc>sMqBaoav>%dJx;rRd0X-|uz~29Em08{c~8+4JxIk|>l7?{)oY>gv`#YrBs} zNn%A_k!6F)$Q_Fm{pR}Dh19_AQ4JI};lKxlwOJGR}^9&3Ay^s=paBHoVJid=Z)j%nO@<(2Gp znX@PN)#>P~TVC6Gqz3n!A+9mgPl3 z6hYIaAkGc9mKza>C5XO&AJ=Oz=njQ>oCcAI$K}R9dA$TnTJZY8Fivt_1MLs`Fz7(Q z!$-o^Iq3GfFldX%L$NGDO+bxP6oG+G3)ny4B2zslW>r&*i`{K1HMx4_v386tM=Y)` zsLMqNFL~v7)AfAx9F^Wz*fP9+qpSqd1N-;AIQYuR#_pvvHELd4+tlIl)5Yfep0=+) z!z}H6Y^ps{i%Q_BhKiK}bw~eORk;|<^E){-BgXxLCk&%ru!zWx{(VEn6Q{M_+^NeoRwP+jH9u(@*sk zwIr5pg<1^Q{u`>v55rIO_U)O6laRs<4&F4psXI?^IQ6-a!F4^GhKCyZrn+8u@%fpQ z*x$J!-gIm1wIZ>9{NhM{^kR_^51-gSGHkc-KA&XvZ5Vm~skK`Q#aBm1Hy@z31BRu4 zy|j7i#{dO8jAiYeR3oq;kev_>r}ejB9?f4zPM9J#YlFh@@UcpNP){;EV^We>cld=X zSN<|PNbFn2zDV)exM&k64zo*UbplM>%KcB=T%roZn!lr|?L5y$b( zmx&t(Ufmv=R02QTJvn^%M}NJ^?BY zqQ&bdS-FYT3gcz~YNfGy5Sz5vf}^~533Pu90cL=zWBoC)!+3ec`TYbu z>Pwa#T1mv>P#{s_k2NH&TsZWlR?qN5WLFET0NK`|o=kX6y1A$M%g=6@Y+B#SdgLQt zxJ!t&a1yQC`cv-M3X)yXAcslz=d<17WM@piHj(%*`(+#3#$Ctp|2_EpboS+ZK0CJS z^Vw&glQ{Mz_QemG8()_;N#iJKTCZW%%+_h$24w@*3Z|APfmYxR9YO+a6GAW{s02() z+BIoKsl=O&At8`PDez)1c#wcdAhksmZO89_cTUoWv`yQWtEzjxNdA1kzwh^dA8Yue z!TG25+uv(c7PO3`?=PWoT!P9irwT19ee zZflWzNZv1h-Akphx4W^o^Y*)Wn_S+EdmxAM1ecIfd574u#SPH1fX{(MIATx`07{8y z3Ip_Vc_N>W277v#DA;*{t-TT%?G?k`!hXt7=}xXC-@D0p z&wSzrn_8?*o09vkx7p8bc4Y^@=}JUexy<|Erwi=(7#&AWBBpcC60?mSzTT zK!*p=0a(c?rI{Ktl^iF=$5Z!F35I)IX*T0`Q4BlpsTgc+>+6fVQWFoZDORPwpVA9f1$;!Rz%I;g8kt_W$#*uF#gtV(mc9@@J~{x*f=(AI#p$kGy!Eu$?&Y~k%; zVhbK59Ec4WK-Dl|18=m&4OEwM`|8@agk4 zz3?f>_>)-~n#hS5U|WNV%EBH#U=|>;LT4x+^27N6`A<}$Si|k{^rxu+Lj8;6)#K1( zo0F%_h?A{|ljZa&ibYYPwi0ppBQLsKf}z0hmr-N6kz0n1d2YoS5oDaIs-!SFz+4Q4 zL;$?fPjqyD_UuU!!Ys%y*tzVhO>=69ZbVeWC})BLA?**tV; zp!bECz>W-#9{7A~-ww<${Xv30K{{YcUS5J<`o7_2c|AH5i3~9~eLQZD&M-uOKan~G zta!}Mr}JkhKN_;~1gR9e;PWAEkz$Vch7zCt48?A z9yL?@(xLZ`K6gY?Vg~|^^7i_^sn#1rrmH(iyBRl^IsHg``}E5PzpT9)++sXGcG%b) zifKGgIg`oH%@~O=&XoT`S|j=xl28^sZ?H5)Box`9x_Ok-TkeV^lG>ksG;sg^lDMF{)3PB z8m7@E%mHN>^Ou$@s`YzAp|I6?1l)3lfCz<-PE>j$(qp9que|?b(iavI9?>sFf{EnO zYp)A)Po>1_V4cVue(amokwo|I-%h)>x>9|q^vJ=HpL}EMvjqQKVzlD+Ad)}`V#$FJ zg`5Z_`6Qo#4S{HMMW)VPF&qdKrq7}epZxI22lga|2IzCdZ=9b+d9)inNyH5|wb!G# z-ARA$6nPQtfk5$c`kp;|7s-onDM~OLPR8JHJ{U~G&ItMa&7ra4uGY+CvoY3e8m*RL zjLqODip4Sf7i#1M!|!JHdghdNHYxE8gHDl`&>T)Gk3KioUL-FWY}Rmh>DjF04~Kbt z!6QjS&B;-tQD`lamyhq-)vPz*VBRpAr^w4_5`s|->ywa~3%)Mc6X}<kP zbLn7E5Cc)CH&{riPS-X=b_X(rVqBG?@lrq%f`Y8{_4$1w9SG#2Y(R85*iC9EAkxm> zFe|VDhvajLVNGF0A3QKxmeTc1JfwE_k4u%&K3+)%3o_ds)AAL9P_G?q4wPA6N|39? zXff$>rP+{DjZ86v-bAstpAiO$bhpa0fgls(v3JJ6J8wESL%0sYm*=ky!5N{|Y$`4V zB9bIzvw{#wVJpyd1e?X}g}T$d-hn=RvA=)7yjU>Y-Fl%=E#iy1Ud5&f zud=RsPI%G@_rvy{coVdNi4%fY8<)c`(!7w1`gqYzcf{fJN8ib{&XxASmihbCz>tqk z35n`pBpyg(?BQfJwjHp`#ooNLyZ`rver0EWZ%Wbf>DgSb0uyerXO>{T2hmTL;L62$ zl4LN^7;U&W=`U=e7E7AoSvH9o3*?1)glN3%VEuwlb81G4MO_+( zTqvlaD25!1sTgv`f}F7-XV!&W(r%b5JUF~PSLX8;+77V0LrnYtc;$Eg%>rwg-UNG- z>zSoOLD|vQn|ckbjG(i&F zTL`&Y7;K#5T-dBGm)V>e1ZnszGB=6V4N$GOQGSSyaMQI9pxIKJzr3gSi^IN%|6|z4|`9MCf@q;VvHARin zb@DeLotDaS$2W5Rz>_z$ar`FpCr}nIAWB$Fso`3foT?Rv^#vVPM|w>#b}SJ|;2~`fK0^QeMFDdQp9yOpe;JP@*vw%A<_tz^ zHp;_sz)R|Q@iZOa=AUtEMc{??_YgIb=eLQp)m1N==MG5eupfCXQeOV=^Jkvj`h0&b)CF(yC6btwl2d zJ@uE$Wae*edKsz4#@9%^%^69IjU_f6Ja|wWXU&5jeKa_@ckd6-BNpc(haxbPM}}Op zfiszDE;h??-3Rga!R~k}p7w#y>Hr`33Nl_uB(Np%&tWL|wb${PY~UWTnME@$Qpf}bfrF=Fmi8sJQ>PxU1h{ZM-le_z$Se+(C}x&p z2+I-Ro0lTo?jxUf8?J%=oUHu} zWPA?C6f%Uus=5o_PfpE3s&2RBj9lWS&#L&Bj%3%-ElyWHW+-Ol6ii5_U(^RR>r803 zLA^T+%K+;)qFam|NTwJ`=&~|XuD}M-A`}vYZGu%aVoD0_A{H-^pCc=Yp#l;cD67bi z;q4b#gO^~U5AZNRNlYnpRj@{{P$ekB0f7;g&aJR4H7(5nWuX>|0CS}TrEjE;^&2Q`V~8OcPZh0@en zKY*t?Kx=9~6eaA`{z#<1`_S&5-ra|~4>vR%hJJ5P&#q&~VEh(35C2YDXKCxMd@0U$=c7`Gxy}n{>GG1^0XI58Zd&%=g`W?$_MZ=MK4B-Lzx* z%;n{twoVlX)n;{rN>x=_+ft6@@?d#$IW3oSn!`AZ7y9^ODjQ}qzWjo%V(t1C2@6uQ zv_YaLB|Jx}k`#$btIhRuo11D@%vrstv8?Gk-wQk!cqKrUKucg_fR+VtKx(U6kJpz; zzm-TC%9_dMaDp4O9RRIA0I;g6k95IqAa`{o1LC`J5h_tvRlDF(RjfYzz<=!U11qqw!C_zqJOeVa z22#-veO+ev`}`oa!`MQ|*+T390C^nMW5&iNyG_w99yyyR7|10>`}XX5cQZ^q-=SsZ%M8-?XY=&X)+KKSm9 zNt~=bXh_EyN~o zo;O*m5sp!Az>=FABlia^7OXc2@o$kylqbV|_3v<8L9#FCgTqN>WhLh4N$|DmH`7Hm zHn^u2%&@_=lvK^%=Gz)*Z2Z<1f7H8caqZmMi)U-kd3si!`1L4e@83LoqIIwPld*fZ z@4WM~pRPcYlSl>YEMQ$5-A7(VD2|l>bE->A?G-U{cR&>F&?rSVTgQRkzCc@@66)>kYiMX`>F((0 z>uU?`jFC?V{Qfq*sjCac$gKgE1=rjgL@3|o%=JR|yvO4zDuK>GX{i&Mi;BzD5qNs* zh8U$vUPniF%hs(`YYrT!Z|Ln&m^Dv=c%Y?aO>8oLPPA6*tzt5os@JTk_wTNH21Wk+w$GAGdcqWUskd89iZ)*)n#q_AU7?6aF^P=H zo(i~ZW*Ji#Ni|&xIE8z^>z2Vx~qsE1DF<7N0%Y|tq%lU#;!ur7DHupxhSx|W zg94;Ovj_rg1{s?zF-tlxNK!Z$2#9l}6NQzgucDN|WL_{)2~6k3K1AMH?F$ZjLxxCb zf?;IcNB9Ir(e;+_u7s8#7O-Q$6D0P7)Cc<&1NIRJ%Zmc>VKCI4FXo;!*}M+M$A~G* zQ^jbnx<2G6@+1`%?VP(LItzB*^n8T#I-)eqCM@oVQ@rz&EgRE2tf4V>KXLTx^vl`3 zxg+k(D9*!-MiNyjECKC?JaJm@4U;+W#6`;Zb z6%3g${8Qs|IWZ>2;&Gd1;Z&QAWlggrKf`fo&Ttbc&fBokfKbt^$fXs0nzid4=wLJ{ zsRu*A-gaTXm&o?ah-)Vwh3K-HSPw5q(~{F_9fGLf5y|343r#9A_HK2Ld& zNQWp2vxDcTP)NLNxQ!g72PMEhjEClVKSF+rVrEHd#_!KzALaAuWFirn2Op)0fmiRd zQUym6hjT@#R8Xyky(KF+bHGzCDP9@ORmdZ#7d=DN@=_MSuEFCr(U_7)&l^`;PaO<< zGV@P`ou1x-oI7M=!U;icL{+^j?Ei8~!GPq=?DAlO5EkheKh^3HEN`3pI* zzjS(i=-oLmoZh5a%q+LWESGD;?8*|eK6o$+=6Zme#sau3_E|QY%cZc-3Wdl#_^coB z-ETGi0f5cb1g~R$YvOC`MIzmS-|yO+@gWfZbG3~jq05VlPm)KChfxG&(AUxL=YZQ^ zGz%U_G&qppL(RePDvx1k@=$R!{|Ihq&(P4Q1~5lQ^O_|D#tbrUYY?|`G8x7A-O$Wd zt9_odA|q+m7_GQ&-H0rYhDLC0KmrmZsUE60`<5CsqJ(Ut_{8v2k& zkH0=Mw7#^pUg!F!3&)??zFppYVt6dyKeZ#(RTIJiDcHSpQwO<-$3Hl8!NCMXA6eN&@++-Z;5Mjo3cMLOW<1Id0-a-+^uwbA&nOV8 zMWrQ31J@9U(0D)zBvb!aa*T99DX&V7az}86eI0@W2)cmaH6SQJa-5w*z9oWLv8PK7 zrZ7Rar$@yERrOSm2x5p9yBZ7`H}yHaiP7W9ps5e*E2NN{a9Ezs8|{Mza072z2M+u} z0NNB?iW+@8){>%(ZJvtj(|1`PE`;P7;u$};8RCx@ckJFN_ih;-+5M;A+&eq-jlD5{ z4_VFBhR?qD!s*xl=nMWs9x7M2@7*^vcK1geWF;e!VS7&9( zy{mut?g>qNBArTBUOxWW51)ChD;{{3uk~%H?iri>`0h_TE?1{FYP6Uvj^w57jSb_c zp8KBiw!5w!TtBU?69Njyk#scr;$|%@6304=YFM0yY3dfW3)xT>y*Y;*diQgxNd-Y; zY{H%4gIG{oB9YN}ubRp5JdMN93=7q;ELzMR4ofU6@w^vAyC_M7*-X>qFIo+cdJuti zaoz?EApN}DssXCmR)A=4R9y-^&zgC6YvEJk%b;uH_$VLvR!3?-e|}J&IP+L((~RNW z&R7-~zv3d0Z$SGJ=q;Gpar?SaX@)Yg7=aV|z(_iv7n~QIPBUdRBD`xe-`AH&->JdB z)3)!nuIjb_@?Ng7O`T^PKks?Z@$vDoeQY25_>%a79XmI2AvSRm<>G{JDQQ9nA#^}s zFcz_{T-MTRz`9lHx~}ay6LzUkJC)1SLfKT2#Kc5HtJ)8nw0_vMsoRH1L#Un9Y0=OG z+9pV{=Y7xdEyM)av_#6WohW*r-~0dnpXXt#%5^WqC}i%X-K+B#jCoN%GA+3wd5Rkj z?J(swpmObE$+keUpkv_-pTX}lmEghgD~t{7EkWF?L^u9mAdA^dD1=N75u%-A+;B_} zJRRC`CjudV7NhB4koS1pZl%`*N=Z?zgc%d{wW#@86k(ji43FxHe0|eb5YntJpdOmk zb9z3byS)kvnl2?IR44h&optX&m9CT91FFma^+WICO|89yE5-h~4~NcfMA0?FlcReg zdzHq<^=;4gc2pdGt>s+OdidkHx$)tXppSh0Do&H>Y++{M47!Qm1|Qj&(P?TQ*`Fca+kn7$nQG?51jAxD?i50tL4X%2S%%?}R|6r7J>d*QRWj(iTv3wTW+(w+ z21=M>SzZ9ip_G~9!U3PlX;am(kIeZ-V=ct|9PDc~FVX~__0q^~CpYCGR~6T)gJS;% zACn{=oz*{uLZLE&RHqO0^fqbH0;%30!U-AG?K zo9c_WjpoVGJ;-37&8amR(-5kv+pSq1ekG6<5Bt zlA;MXcAzMq;SH2%6*F~(@#skrAQoASR?^Xi96mb@jv#;x!PB=i&}ojdghIh!g`OZr zz!-y+AqisF62xv-NrG5P6697H^Usv?n~E+aG0se|51WaQFhBqb{A;K$KM6wEGM&WHpKn!zlXR$Fy2c1uEpt~yoNFr}!RTP96Z5LEJ+8w)y~ z6zr~P4smK2H0V~<7D@6GvDFhGP%=~+kHe&FZy#;fNx)!0vL9a9;k&6`AACkN5;#m3 zQ-N-qWKU_0!#iDCE8=c}b_RWA!G^6r9(>OEsFHdtvArfTaH;R3-D~}aE2F>r!Jm$w zy7nPjmo;4P_+$Fw{A>)XfCsKIP>d^NnW(qg?()!4uH*xP@2a+ma0P4g2+ ze|i4fV>>Ey%vR$sGu=!d^HItgAj~Y3SrFN>3ug(l-kua;)(6aFNlEneA*Icj=&Fr6 z6#~fx;F{y%L<0dAjmC+-5?Elm^g$}s*Gt6I)5BTY;zm#yPTAVq(_s{jD=w?knTW@k zEPG?JzqXbRl9f7A+ozPNBM%j5I@F1tjSO2u|90 z;flD`FCQH`GldlxmUwnSw7Vmam5V2=(Y&dEZ-sMGu)V8_OKL3}KTTg0} z>d(0@{1u3QAG349>-G@$`g}-Yi8?1mQDtXzx*ngK$W!)uu_Pfp42vPghycA*iGU$d z9+1h6sdJqzlv~c2;KLX}0wi=L!nam^*X`$U)7ZLg8$P!sp71yI?;m@0?VCsIJLmDh zxgnTeH?2&1D}{{>z580edqA8&dV)^fg|p+g=vJ0<K+0yWD908ai6o;cx5WGYs)pr|jk>_$kco3tZPwv}f zY<78np(1~sUcz0_5ABHu@Y3Wx4U}5mKubF3f8&^kcguqt1;~>0*FDlXaknp0=EZLC z6uBYqgR%}NtNy!$ug^@n=Fb&65$~s+==)_m5oyzx5t9Eu9Vp+5AEp7ZKN&nT;J4hhspKGRJu5olG%|>dQuC8*I`*fmU)5rOb~dE zb{&5CuA@(YOZbl6MV8zb%9u|tuABqm>?(eTcAecQ%1&}mKspSj#4+WF!U}@LL6l;* zTl9>`I2?An(L(N?VQ)-$IO7caZ${8$V7oO7r-vz*@$}5m(>KAvM_~;cxY>L-sFGw?$+2B7`y%)zmUT(0>T;Rwqy!F1s5F{M3DTkxJVd|RMQD}e zFJe@?iY0487luwhg5F!IF#hWJ$oOqX`Rbq=6x0?bn>NvQ)rJL+Id z;j#uYwL#f_P%t-^RIqm zqA|LreRK6n6g~Lt{(%inIaE)>Rs!`%zk0r)tw~>ZT!0YFQEjiD^6dfz(PM@oUni z?N>EvQWvd1hPIYV_P*!X4k<|)v?{gFXIr4}xxLT3`S0UfclHndV#}5tlX%a@y=?Tm z5{uGVa!-()6ZCexsSR(ct=~{ne^)nd>Rz_3d0CSO@9c#;n>sCcXC19wN->Yu>+v`n zOov(1^4qf=4mqM47%X39$Kusl25PCp4Krefm?`rd8ff>uoHLVZTX2|ew*khx8%9cX*H6;n-`J`g zI2gK33uUfUzE{d{(s!&J84~y~5@HB_sL22tu28hAVL(VcEYTpJ;DCt;!(r(g^|`Ix zPi2yU%&wDbO2>cvw~r>jlMLGm@&5GGZ?C@ne#DdCmgAf!_r^mSP26OQBsSZfK6|t; zqq9+wKsajP#&;gAZ0oQ7YR4bO3P-p%f4AY~SNpd8WMbDw@#aW*>}MV)@97G4@7teR z>#^lZ$>iaxyZk+5wZWo|o+6F*Ri^W#i~L@&=aE*WfnyWNU>oOh6_QC1Rm`8S1&V0KA9}o+wkm?_|)<6x3I-xL1;1Zg+i_dqyc49 zJ#5Bw8{khp2tU3`vlw{*7LW*;1bmg5kc_ZI16n{0@A)R!HVN(3u~(L>!gw?j>KGGw zKA2nktzFly4Tn0_+Ju|)N85$I&EdFKleD^G!A@5op-GB~RzN-EkF;q9J-RLcJj9 z^(M~BtMG-ITl`F5;9(0AkVIdZz*lMXRStdC3>Uppt%0YDDwS5J$1-JN7`|E^>KDXy zLqp)dj+(S-Fw>D#7+u#7gtfG+L)Tfsbt!mv(QG}9W}#E5G_Z(J7u9M;ufu@SY6q;Q zYL9>%igizlV%5s?tsTA&1r#duL2DF|8EsBbH|RF2BVFCR=zIX2;cO}*HC11?s5zxwMz>e-=pHjB`8 zs6Rikr&R~e?KpS;zi;k%*9$rNK(ROso8)sv>!wEXGt%4cb-_Fz8E29?3gfae90q=>2$Ncv|5drA>DHJe<-(Y z$PuWoG<&%#M@dy?j#gcwfxq|lNJLBGCXYQ|JO76P{NB6zu84(A^ezd;) z&dHHYW95AVo2Z*lAEP3-o_%$77e)gc51DzJbL+ql71^TSo{L6fbq`8N+vs^x-^kS0 z>0S~cYspiWIkQT~n9Tus-%TUhc6g*HT}>`W7t^X}D=ax*%$Us#*y64Ap7l3f!NT@law0-r;RHd>N>UxBtP1X~$q(@HHBgffLkA_F+(NS7q;4C~C81mxvwdASJKtj;H zPpVPn1h)C-A6uvmohmUQK0uyi-Xxw9geNDaWl{t^MMZ3O#%QqHBXUG!ksKF1s#HdN zG&D2+5+PY8X||zy?RG;F)eHDf6%5PN+XQyGgqz69>+Iu+Svi0>`X5Wtb?_c7>xQZ& zwEoy|weq}rjHF44ygpBSFiH)rEFaNii>%4vN_am2WGuu%>q$cKuZ!7iv8brYAu5<6 zfucr7xg1`Lg=HNM(;UrBd%Xd8o6+g0_J--ZD1;4ATj;<)4P8nT3?txPH$qnKz(ujN zRFDJtq6Cwyz-TN6H6ACHTCIVD&1S{svyvE<=kJ(*y1r}u4$fw2^_tpxH7Yls2ji7qV|np6=`U<+t|_>>U~vH&8SGq$2N8oHf7Znap#q?s=uM*Vlc7&$L-J zht?%1MtS@{+c)m?iO<;kw{AM6=*auq+JmY3d_w$e^ff{rb(YmBooSe0J!E#Cgcd)W zZEZw{V4$dULZ9!lTHL;L5V3ayQJn0*q8lpmqcwO@~? z>tEt!g)^Z@^8S$0uk0s9a(?CqDar%;%nW3Gc5d;;3?%(p+;13oF!R%6YWb~IU@z zszf6I^GBb&2d58bHX|N(+eECKD8EY40N;C;5dr_oM6AfN96K_cS>!ZHXr)HWaWETq z#T13cwOS^Y(;LW*Ylv{_YP$>F$lhI%#mLB;zl_G)EP#W8DlZN02Tlt@Dn;E`_144D zvk&f9`riNEOTFGc%c_yaV?TIi{f|E)vzP0-&&T%G?-^^dKh0Sz&GDN3F?$T2B*{jufwC);?Xlclga0^^-2dNQj!oJb{N@U*n*(N zb(sDYk7ePH$MaNIbaA-qlE$^wf6a=Nvx*Vi_%{m77|uG+h-jMjZk^}c#tmUP?Z=5-imIs?x$G%Y(Z%nSy0KFkVX zeGbv!foy52SrTrfyZfEBWXGa}Q+qO#Sp;*r`W3bQDs-%Hmq6K)H7K%Gv>-^LDCLPK zNmWzov1r8lGR#(tHyazYT7yAHukWCb^!aEks3>xPphVFS%j>AXKJ)C6GLL|B?v%%6 zA@LDth4{~705KodmZTzu6u3uvm{E8qLk$-uSqUV;Vttzw+zRW5FOA$DG;^iy{>6f?C9#07ec_pdjBqZ3F zqZ`g_B({CF^LO9)ZqGo%Zw^MBghZstKkcqt(bDn6Ggba=79r;Kgj`JJ8$+k2#~tpj z^+$&H_63E(C;f+Cmcq+Bvpe?getOa{7^@HYYwYGnkBU9CQMU>=2I*sNLQn0;k9LjE zE)?G3V&!t25#Uaf@k@F6{F6e5kOQwB)}i5GQ%ra~j0RH*Uk^(0dYHQ)aI;iV&C!&n z){|5<SgqSJu5_aEAk;JR~HU{ig;_ zO%I$OUe9Ut{&3H?w(Yw9!`lSy^T(^*z2!Y&oTGENX?D0EU3 zwSq9OR?vt`OA7{Erpv_$g)-%0ncS>_pvH!TT4`?jDsL@NV|>ouh-o%Ze;~W1x zGe!)y3?_b_7_Dm=ezrEeN#H|iXRyb~bf4IAeEQ|{tkG_Z@7tc;erW4)x>xD0a;))M^4iz2@o1c$<H$OpWuv7pq9&gb^h24ZnRGS1Y&6QBG z!#GLM@%3lATi3!#`RJGLKD_hsi-!YpYq-)X>Ww4MesFv2iiQoWQ-a^cc&3I1?eEY)5{*%*x`1Q7I@8G+84(;1#?ntevZCi1urJ}Fd0^#WEi{4Tdr_; z$Blcv3Vz`@?bYI1TQC`ydSSYBJXWdS&+4#BVJsIT>;g098$QpGk&><#8vcL1Nz#SB z{%lEqzEx=A8;g3B&U^H?YIhvKq$A)`6Hz(q(o*HxuwC7512}e(wp^xZuVI;J#vSo` zS+UR&g6>K5~LyN+25b;i<2t0s9ij2!N8P<^0Xi^p6<_s%kSSvPF?JcWB5C46{Sg0P_7I6);KRp6{;j{yd7UIiTB|M4s$YJiQHb0AoeNWeF_T&j(z zS?ppN+15XFNf!_UB+3rM(A0#cW-_ZPP^B)eUJbwk2(%h6PG@yFNMJ_P#cf0hJ#y&q zPzpRGSOvjarco@^Q>P9$uc;p7D!e_G(Vut)hoQqRU)W+<uUKqy4QC`ZshQ!1 z=F>x8b@yA>_XnP@@=(3@Rr?!s>B?aAYm(`+`#_As^lj815fCJw20w<+v4x)zfjW_a zE{Esq(AX6SkDp8!)l>2Q1c2I(j}-&FaY_)6d~&qL6vxU?0#S%WI>aFpNW%frC_@U2 zSQ`lVd~!`Z8inJ}G#-z;uEQ7+jJE-CFkVxR>?V`C0=0y{bi5_gy@M)Zr9;eNJc9B4 zU$Uz;wyE`KLZ7^~nfdX1PsoQ>RT7PU(*Hv^{t4*7tQK{3awQ=@--?2lqDYnl| ziq8AI&-=X3^H@q2NqAMk!=Z#i%%(XG#|_dCa;7x&mrv{)dwcJw(-z}1LeS|mTPH4! zoqvOO_v&CRgVhk-7`aX;Z#*jr6M(lsVa?K(~(KRcB zC8LF6SZZp_l%cRv*DDP5;xQvZ;d}!k~rs=IDonA^ysMVp8z| zilQ@jkQx}`;l=uy`OhV*#VMY(o^>b$H!o=%BG20cP?)4~OHLOkggyEIYO})^SEr}z zChT^^&nW&gAqXloqj+??S+8d_8WlDJW`<(Oh&y2{9p;a*BZe<3LX;xQMV@XshC+@Y zeTTqMS09pnF-f9WO@R~PY8Zt-#pJVBpL@L}p)u8L7L&c#& zA)RrhsURO-)_w66DO5-e4!*JGdDrtV`do~pZ(_~ihW?i2@z4_AD%|B78XWy+R7;y- zdKt1qvN$5?yn@~!y79R9u!Dl56{L3D;}HOvNr;yk;)fBcEuCqPV6{3_8c1Xx-L}|3 zKsAoLH2&9*ZUt+L1`5ZpfVequ!oqupY?*32kW3yI23hj*9PZd;!F z+URR9Z|u#sEpbClQ}Br_2+xDH{yZPa4Bcrv-V)GJ=dN{>3z0T zxKLly4ycu*|AJo-^~^t|%qWk*z73$OcTgP^3}RuQng4@i1~=gnbQY1vKMNjNC~2W= zAE*X{EMOHKaHS?zQE`{1K%jmu>9j@>A)C)92%f4t#BnNw7~&2svW8eJHXNt){~xEE zKpzZQHBWUEXBSyPIZ7?qz_yx_FDOVj3#3xK-Tzvj!g}(h%DcbXI~omeZB0vCZe6*5 zVan@D4rZE^fpbG=zr6Wy&w-^YFAe={L)(7l{MDZ4zEvLl-p=8H+;7%gKMPE$p~KOi z)R;njrs4oCGuk+<74?g7(LErZS&8Zvk^{CP(_lsPdY!KRKGcd)V2}z|Z2s5dLaW~Q zah0{eAXfuCpss+w`fTo9>Qj%kf1rC+U?m#rp+SNNuwjF~J2Pgn6x2d*7<**|ZxO1zx2D zv8zlACL3k5`O$qSB7*$173nDJsl=@L6DQO#;+nH}5O%v{QwbkpE6Kbs@LS% z?FHU3^xlAaiMlb`7$}Sue)63qyD7`ld^xMplC+0tR=FQMR0fsNHOZ6{U@zuc@=VIu z(9q(a0doU4{Qi~}yb&kWYNMfqd#D7ZGs4jTUWv`;)Tu}V?`H(?NlcRS`y<>8jV6*w zLxfnS9Clr~oS_ZhMX1LxL-D5)INe&Rwq_R3JwOqYwOv+#VodJY!(g$pPKU+J z{nYPPCs=mSlg*D_IP`;4F{d{liYMFZGmz*U+na&((Y|G}BJll%dz(VU-tp`ID4EiusEJ%u0YrIEmkrD>l0hly3X?^!VR#^DL zvKepIX@S)fKu9fNVJr>1hfomb8fU^$tcJbn(y4KcNM?2KEKYg#wP?f9hmV~Z?_Qez zN~vUNKi+!m>2>R3t4^0!B-@A9hrC6OcZWTZVQSltFW)xl+;+}yXehLfB=*Ky_wO3s zxntE!s;xmG=xI%3U8+^i(X&XtzNUPi9*64;xemJjXq2i9k>{PL2$TH# zJ1A7$P7x7)q9P#IRVd3mFT)Dy3Xhe3*d6=i6nP`G>75HVT5!dcaJuZ zF;4=n`C=DNjfFy~+zlrak`zcoWP~)NZ4S^t?Pj3hq{J{izPHE<6XX>p2mx$^T~x=y z3bUjg;OB_9!_2fS&X%*q7z}=qJSr~Em$(<;f$c?gT0Wq+4w$hYF}N^+Nh$T7j*QWYs&woSCtStb<|2i>7NPMIG?- zHe}4YI;t6;#uH+5Gu4PKr~aQ7%3>*GJ1*s@+zic5x3_oZFBPc5U7$*rOl#;;-Gs~O z%-oe7>3DlCiyPO`(N)OfWt;4zIy)0y5EA`_!GIEQoRpMGFM0sdAwkZ;&2!4lb2`1a zdA3E(lT9m0q(oRo9`_C=rvutILTh|9>F?CTOS+0w?)0g8+Z^u%7(n?-4}UXGi@ zrG)&r*|ip?7dkj~^OaXeBFQyLrs4R1*{}N8CeAzj-kp8t#9w#*Iy;FIJC2~IHwfm!6yFXa>q3%m00i28i)23A& zDrjY>nkKbKTenGDR-iy9H6Q!E=OZL20nE(WNr`iJ?|b)qKkmKfeSXigZ|=;yPwyA` ztyLa(=<82hIQW%)rLN*f4dFoN+To4KU(9VyKhi&t+Lb2UtktO~pbPZwUv{TE;nVBIGtZhh-LiD?|U{3Cg8}j^-kg{^+TiqHDf|g9jCFL;fw~n zlT0SP7E}Rw46y{u63j_SXh?yU#_LSMY@U^uf-Rr z9I0S5N{559>YWUuttc=#SRU}ziLNNl0={@)y>6m?5)#YBaS)WIO!jI94>gXH6uv@= zs=}050EJY^^IozX*WB>Uy)^)*nkbyAlW?lS=n8jrV~}=tC%R%AqB2OM(e()o(hVEB zFi5TI*E5A;Atw|T8i2kVD6zmQP*j`YBp|T?kk|y*O7fF2kEac@r43-I?d}do!{KNw z#(+Y`Qo-uLqT{rvE!0C}))A~zHxLaOiXCfes>7FH(3&AHjrV#yY=*G!1-Z&z!?*)< zO=BowZR_k&>W94@73H8bwVpw(&%VUgcP^g-BJQ2~Cnu^zS*0xl4y!?}02Z`^sCYxHB zhhlw)56n#v+Gj89*lV*mOWw->h1J?RYg`^yRD-F+{M6nT1y}8w_!q*d;r&0D z?M>}?pA9f`*M@d^93`7u2A_QC%+}ZYk`I(0`q87$9v<2gs8D?W77zi7JeZ~6Yhaez zL5P!RGvJ~YP$IF_U9!*wLg84wlv?dVeSI>VA+H=uY#ZqrO(yYOgH1?|j*eu=Yexq~ z@G*lYD6_;?n5)#=dLDjwdm^ztne5L{N>L|n-<}uRdL&C*ExFJZ_KqBW>XY>nc1T{I z#8hG23%4SXVbb#Eo3(IXjF7cpvRwd(W;HQ5gnZGLP-d=~+E&Jz{VjDSyGC7BVezJ& z7GwVSi?x}wda>RG*fy6nw-sA-c0-9l1G^rhFod}bP>8u~kcdyBb--cjTe!;rg}tVI z=6#koO^TZ&=39Zp7)K!?6O_zNhBk+zt>MH{ZaR_WCS(9M;_ZS#Vk2m7FtjJbJ&}R- zb{WC#0|Px6!Eub>c!n~I>SSc|=Du*auf07A$UWNEmn*G3B+**S?P+ZZBo_lxLbXhF z3oHk~TtsW>Jh0jwFnI6uHuKC1u)9}&dvRruQK)O)uFxsZEM+?V4W`?cz-%=LA6V3n zjEsu#!AD2MdO7@thubj{9_oj$4N5ZmZC|X*ims=l6-} zsQ(SqefNG7-Q1?zVK539Jga<9=DE}Y&sj1#Yq!!BXfI1zaSY_bo}K{=7)ydEu;0xq8Yw`N;d=8S}(BdE*xRJ)>AD$qaJsUOZpjN^&Vj zIvCG&>x*}^a4Yz>{F=0T-?{g=LE)AOkQ6IXNfih7*AlXvRUEo)MMk6XZ~w z&LMJs9z~Q}iC5?ckcGU8q`Kl=sJBA>GP*Bg<~BQ+&1PB)v-$VJ?2gbjsDFHaW(Q+* zz!*QH55O4L7RLO5?uYu7&&Y}#p<&BXoi|s6>4mys(F&c1dTh~i_?}dUR2LP0gnB*H zqf)&Ao}XhLhx&$G-VXOXe}Q-fy$0)YJv-9eb*QJH{?VtsPOFitk*krbk*krbk*krb zk@=29zay-~Tgv0efJ#x@Bx1=c#~BeU5yO<6ApZpt=%0utFHbOx(S|bQ^q5v_oFu1_ z4ck)5cuu1*m{e~VTnVN6bXhp=?10PEJ z`p14<@~!9gyu9Yvp1Ribz)TPxG&V&+))DAUnBO_F9I27zBr1RzQ7|I}GobOv(|FWH zL!3(l0~gMih@)yUPz|2mSGpCa4@ zBF;mk^$kRlA0mSM2lR01h?4NJA7r`8>4&y+Q$&Pt|6FdPx{Ed{^zoExQ5*Iy+OX)u zDK^`NL__m`qkpRW1Ja{ff;d{tYIQ{eo4W2ee$Kh}y}pn5aqZYnn#3`FK^!o_*MXFPFC?_3Py!^t zLgE0c8t8yQ!W3zOlqjgQ6hdIDHa4|9w3feMY)v8(7z=b_)h1;F4LVhnmLViSTSllD zVOTYQ+g|ZowmjjXN^erPY=!}S6H`j+SU#yscgOWv{WD#g!Ov)fA zun9^*Krj>(%Hs%%naER_;HsR%1ouekWeqJ-hzk>N(s9o!ziYGm60RYDnKa?1#Q46I?d&Dm6wN-^>usp)Yh-8d#kIq zo|}6vSk^hxw)@8GyWZP%{>tuG^Q&iKVn4s3xq0KS2iG^hvf=v_&GHw_meiit=XAe~ zO*pi-t$X9Kl9kJ7&v68zrPFu{1#qCxLiJZztbh@8W3M3OqXJAk#7^@2$!WdZECvF^ zEP_TPh*e1<%WyT-0Gp^DxQJ?ltEo=7n(BseQLxz5pZ-%XB?QKwb(tz`vQmZN^LbsS z&zo3CnJ6{t!Zb#W8oHT!GUW!a}H;~( z4O^B6L=cKl8W|k6Z2X`{NPIEcxYC9^gCshwygZgAVrV?)Z#;8k+vUWM7F*?B*>}9Q z>)GDz@d9oc<#E`NGQZRN{5NaLTgi8lJ>8K5b$j0=6)CrK4P%k~lAcq zvrWStV1E@6@>q9N`AYYD6N#iR3V9kLM53<#E1H^mOOV>wMQi@G=_VyOIa~ zb1xXYBoAcW;L)SJoGKE0;H9=NiO7I@tLcw&pnlh(NZ^On9viuA~Fe z<#XwKJ)){{bPBSw27L}mpKb%QZG^}75ynx$m%4KOW~UHldi_MM5KeJUq;M`>vHptV?4m=G>?_zkBJBtqn;pafWd#zHT4AGyxAwSu zxcw5VAuX-$tKlJAMJ6iHbXv}7F$tAJ*??am*B46-TVog(mNa7!#UU5y^4ExIAH>Qukz8t7y09j!PC1SBA=SYIh=Fsi>wzo99zH}K3 z3l_pqIU9yxxn{Lvdx!8d+>LSop#>hZINh4%0mrG5U6$2-_Q?3^!)*EapJt*ye+UXB ztp2AwsjB;0uT2;8G!(A?%4T@F8$)(4gK8PZ&xGnsm8$IjI_8bsu>^nAAUku!93wZ! zi1Es}**TrYuFZHW^~?VgM#;G&!-L!(_kkzR6 z0HUQ8j6?V$sIse5!qZ;B~;O|7QrRr6p7Pu4am z+ZAGg#dlcgJ!?45BHj^+M~sLy;wrIQJS6fKFgA(XVH+bNFY3EvqW+Byny9YEdE@5?kWrp$#QR0@L{(8LZYM-wHO` zhV!px3T{5!!<0!pL79j5Gs;xYQr0kKsz8}-OB+hv&mAi*Tu5_xD=(+5{1>3imdD6h z|B)OG5zQOa9zz%r<02OU2?)a|>gBVa%5ofL_^C8Uw>*KS{5Z|jW#c7Wz&9g1nl*r= z^hl4>qZyzH>V>P!YK7f55h~G$fQ1e#r*yzcpo7b(86R%RzZyPUHWh`#Trd=MW}0`H zKhvy_7TFfLXX;mq`Ke)kw4UWmZcE8;F}(G`Gg%OF8<=e3Eow; zbt}SYk~*FKZTd~9fD?5)s$7is;R~2U7-Ozdhpv+4H%WuC)&i^JL@ zqM6MT_B&Zpg%3`rfq0NCONdFTNKTCqL!J-_7@!;3t4qdW2}@E*Fqk($_GaEz$U2G2 zWMwo`NzX{(%s~mop$DXWIXy*H(99HOM<}=vFeDP#7mLCcqPf0I4+tHg#!gJwL7Tvs zMiUeE#=PWcQ&W3$^S7SgHMnBZ+b=eDzL?s&si9&0##N2$$hxG9+&1PkE?LqzdOWe| z^orJdtIPh*eANa;b)DgJ?zwlD{b1R>z%Ji+WffR13c_7<7i15hX3;f}fNfZ%YGz_d zOcfk!tx9E_c4{(7V9eCC9b24arawqJLZph4sa85^n*NA0&2-Xqtc;WCm?l)4!FD3- zZr^k71=sRrr%sFG+j%vIq%1Fz8<@I{Kv0;=cUu9qV?N=ojvj27)}Ylhc7EC zLxVIO&Mb&<8bnq8vSm_svdt!Xvxm7|=d!Xy=^btt+^i%da=WOh^d>kv+T@#l>#FUS7rH(0-%AWp9M3HOom7ov{n`zckfye(_@lD%Ae>u%Sc z=8;21#Xs0py8!`znZV>rDwBn%4qZ!RGBYE?De{6~a*K>fhr{G#Oy&TSCScN1z?f7j zD#~gpv)6&W4D8NIjn53XRfHBOWOy?(1uxI|OwLd9=H*#|;PnJiR-nWbheB5s)dg00 z1DA^`yh>qF=>+5S6Ch0X&q=aFCpoGa7A1PcL-30$S?g41z@JzxQ!g_H8ZO`+{d&}zVA5~RGwr=tr z3>1Ew)yDIDKUyVRg>$Jp_apqEf=*EtbPv>$MHF+Vu9peuZb98}3F75$HEvGv`RN?mQz#O|0;WB8YufXutNakt)WFBP|69!efnc5!G^n`u3=Of}s>SKVES!a!Y>LHt&|*OcT}(rzx)k<4pKMe1xv-1rQw^%zHV4u*I#i|;b+ASQld1uK zE5qx~Hy$V7Xkm!+)18e<+s}{2LQ4eqRPjD{2D|#CtuylcClWsY}ER)w`BUAmFW$I7roL|A5SM)iT)j2;Z}FQbNv*W zi@~CHuGn{Bw<&eEmRUVlQhTn1OEJeDJ-83^XYpmwP>b~7ncdV5e;1mt(W7?wtNbY1 zxkOGoI{IInc63K3;^R4C||Ws;=@p ztm4;Kc}}%F1(p@M#mp+MneogTF_oy5e$8j4jm?Uc)^C7^yi(a`J!a)npdfeKVb0rxm@W|) zGQ%en;ETkmUBt#wSFj?ZbUf>NTPJWVXMs(nyA3O|%I;KZ2dld4*I9R|RhK@&8IC@= ztt4aPTP3++hE{~mJFpZw#8m2H9b)nnFsuAun4Lo?yr#jOp|<|<2dHIe8vyMRV0Ien z{LG>g@TlespcWmYv{C34&Ikj-72$?(M=&Bm5;}x#p-(rB330(J2^brI!4-nrV&S$T zgVhR8v-&+8{~V6R3}0y$i-C=&hOEiz$KOD4+Tjbi(HLyTs)zay6lM_cx9#t&a8x)> z4Dkh%A47Jz7JF7*$YK6Vu7F`PLIb?Sj`C7(-FCIsm zVk3MGUjx5fulI_f#~2K`zWhwI~|4vJaYV0~dS4xFg&h=9 zBx6>mRh;_nvbH-aE$ozvl}r(ZWDYsf02b$m+B%k>4YJ5Uzr2y_Sd z-oTl_KwvCzCm;mqs&WMd*5%~Xa#Brc4R@yo@2J5w)MQm^v}WUD=>ab}k;~cM>?MP2 zOtZ)hCr)uo|FHVw`Fm9zANRSp(C_(DVQ-alx$_d$r{yicRy!a;h5XP$q ziI>rrn=2^;UX0lPA~Cgg+8sM{$9~@(Il-TjS^gX#As9bR&7`{-H#Q$@=9<~!HDb1c znxCwyu6;Cz)49;;^a<50)@VM|&s?|Sq-ie2?!?IHX8z25N_v*58S%v|uMYFjhfxcy zB`DY!MmNwD}%(t(AU-}>`gQLzPJZ_ zoT+NQWHan;nz>SOPh;;)IEjRO`6IfkXFZFrHPlLWhB`tV3T+E&nMy;G;sATPf;6b@pzn0U|W&^F`)Ei(`@3QYyFCc zdRM~(Iw1Az^W5;<_V6CiymzT-#zW03+1I*&Unj|S7#Ck4DGf~xTtoeE{0nNE-C;kSjsuY8{c~pcG|~eq(mIHqrpV4n zZ{$pbM-h9ZEYcC_jtB@IS0dM#t(67MeE1=L7C4JOp$Wz%R3aa!l#)``x>nAMIiXV| zWbZWM!~AI&%Y$Si^FQ5eRnW$!pnqO)dev03a`!B3Gg-M@&&uVAS-E_LmX$h4^8>^t zWaaQIlv-96P$!Wd!|1UP%gO~#AH5Fi+)}kfk&bJ-*5|Q18KYzyvP}2+%`h`h)ea$j zr;lM~+Ap{!X{Q9S`q7Z&=K1N_uOr0YQqR3eKW`RImh(_Q|3!P%hPHK`;d9Q_m1Iel zEK9a5SzlN7wd~&L!}gUMWlnQMl9DYQcCr;x)?m}@$7u86WXqq?k&;l{4Yrzw4F-Xv z-3Ft}4?Atwq=ga|$S7-=H%gKpb!-Y-@~bgpgTWSS?|bgK(v@R}rEJ8xSGL~szR&w{ zp7Wff&<-Mty-@44&<=Z~cEH<0f=3t`=@?;iBUeWjM-(zL?DL`H<4w;|+cUXEU#2gT zZa_=|J?NSSt}xBYvSP@H{-OuW%KXlX|dhSanB4@m1h8&rkRPG7I z!3KolNM_CX0ZQ;k4|UWw%fm5o!e?t9mg3k4Y&TIoRlQ$Ts_46nf}^@s%hmoL9kKYS zpZBo&2qlqJFuV!)<`fBDYDI3TirsuvA^L>Qh+fL}eL1)iEi!`85v^z~WpR?2rwh*eJ6|Kb@)%TRif$0Hc4W1gv18r;!nD#da%YpC^A*@IAaEsMDwhedm z0u5r%eBv$@j0%yX9YW2k$ylgOBPezM6p@yWw83HuzE&XeP1w4h_&$}$4t1sk~W{q1LnsCog+~Pq{UciHWnLf7MSMOsX5R}gZ$A`W_R~^_-x~8qW)>wo2#wfv`N?NOJhFs2*K)&T6436F`^mC%ws}4*w}@F=UNe3yHOzQ*I}bItLk%9wPNp3!Evn!t(`i=;|j_3p@((g zXx71Ml}5+i7qL687llgsG5tNLnhfk?Ql`hst7TT!<1kIM&=5D)O$6(t5=7y8$y!PN z4$(E#P-Qw%o+`gyR?7OYT$^iIyFThpdJUq&*}y_YS})R~e!2enyAOrkAnH!M6^f`+ z#bZU5EtZR{sFO!T-EBt|oD~rqPYLn$n6&W1KnrozCso3oH;c!db^R)E$rrc`&`o==Er>zSzKme%}oc|BZZby zDI|P3Cn|CA2KFYCODj>8H^C|=PLZwB-;7k^6DT-iVYlt?%-V;_ifaHY4@iH%MkUUJ zbTToWm`Nxk(HrQpmH3;m6LVtUZO)lbX)#%c>3h@9-ZfTtJooEV%NWP|Z>T&Fj>Volfj z$UEt)5Lx4$^wbbNHbl=4(V+zDU7B~y^ob24T2me80lESwTs$CgJ}RE9FLt9;exs068_@+tp;Rvp4R?(U-QVqjvWpMV zF6#pih2S!iDb1AFTUiohan zq|eK)d}J{VCB69oq(^(5OjCz@r}~^nV`HQr>| zvdgk3{{a7K-od7~)0OR%Y~Pkl!m9Dcy;tnn`sbjlza`>qvDVc;fH(=>PO~Us-KeOk zx4CI>%{;6b!dOCEca!DUWF}4XYYxs7ssJO5$V`4`XQHJ+ql%-km6OE@J0`R$X7Xp7 zlQT)YHPCd6e~atT|5oXL&hk%5BIc)nC%%4vC@aGM0qOrUyA$bNUkvP18~7i!{i^}? zh2V#Fg~5tAM1T)5QmRx?Bvfop0apE!#j2nZeu6Qe>$k~g^aSY8Ea;g2couS*iBl5K zgu^xEszyWF4vlG)FTBQeWkrn%3Lf z0!G9A&>jkdsPzR*gcP?S8HNpsY=9}~#H4jun6&>6)3T_}7|+42c71iG^;dMJbAQ0p zTfjW3KB1QSbUjvmc9I)_WgCww9h#O-w_wTH#mQlDa+?%KSzA+YQ|1{Z3h@v>In4Jm zpI7myUayPy>86W!b(=1K$W7gZ@z;K6GCuKLcs#Wm9>r03^beUOMj20}%~gDNM$J?B zZfiFgYFqe+d}J6)cMgs(8OAs*-B}v%SQ;NLQ>~(f`zoU<{HN@}znN=xcJ0jUtox&r zYri^s_G|;4DbbyKN1=>BV($Pdd~-bzHHk;%{;0V_r7Gk8qzMUlRRpghc-7~jXj%1z zO-e8Yf+-M8f$-usGeqFe{kmDgH)erv%mUw#1!-h)LZo5blxf_!ZrnL&EL}H@aJ4#I zj(GZ>jL2*r+&w*e*Gk4?Ub?jQ%k|m#NRa&HQk&0<$&^hK-sj#2v|hLB@*vzK;P-HU zx9Ms3`}nYF`o0Zc`>du2r4oR~D3phyCguL1xr0*b$1mdWg+D;ikYWL7P~pZFQ)yH2 z+ih)OQ+0W<4qmK-7wg~^b?{QJr~|&S4*148;2Y}TZLI?op?cGhrNBZMOE(SUhGBHz z8!B=GpU`9|2i!~Zqp>Fy(dXIO^jkkV_tSk7pUlpxx6gjOu<*hQP$2S9w|~Y1s>kK# zkdNEv6-lR|y_ht%8}jwGInwki>VNny|JWwZGmhVTKkYl;`OZGa_ChY_*msU|PMpLf z!AXOiEC~yRtc6AtiU%s7HcW*MZLELLZbAqs-56}ZDs|H~gf{+QOru^G*rcWzP5+q6 zGQm1&5<;4$F^y#!<3~|iJA2;OcA5}aEc@QOb58H`{eC~s`?~5gC*b-7T%UmJ6G(jm z5=edci0i{gTpvC{eZu2>hT6bt6^tf6lY*e0YBi_!-~8)VQcCawsRQA4ksakOQ8KkD zr!fpic@bwyZoyPldKB!vTkv|x;C?}t$zT@z^uQ>uh_u1FTmmv=T5wU>?2ML4O%x}P zdLPf~3Jlc=xPy0#DCW{$FFz{UskRuK>@qr=!r9(hRx*tGCVgNi z*&melGsEK4jGK!heWXC%EZKUaU$yjUmy_0Oa>p+YcpC9fBJ$M-~s-M6W6ZK zT!veRROeOoGSYl743)k;=rz&!p#ARuGMZLDO2zzbbG6Gfd}a3yZrg3!^K zZV%RwmzLJryE^d;E(IFwDE>Nr)dc-%;kk2zck?Zq_I-KE91wjvU?I9qY_) z-Y_EV7|$nGu8j@6`N63nYt71d{_QP6IW51CG1HyV?(N?`^1CmW#?bfC(KlN*71z<{ z+naw*`%1geKW@Ym&!i9ka2-vbrH?%E-9qD9n%-Z0?Tbwpj`w^EuC21ac__W!iQg!_ zkBRuCbd`Gw64;O0ay>#6y~ralmw01)yedCxTfwj%42HwOx`bC%y&jn#RV~e@Yhb&s zCB!;SY)!##_iiqTzn`*tGI~!>rYDo^psoHsh{E{XZD@Y*e~i_a)%&v9mC3%O+Y%LT zIRW>fO+v&)7iJF5|C{T6441|+m={+tp4J!fb*Y}#@N%qd7Szr z=M7rubsf3<=ye_u&+g_@k_4W46mWqt?U-)cu@_>% zCrN{fCu9J8eD3ds3gh>yjFhZB z(xax0>_*vT5h*Kj&*n4&6i+nf2~1dE{C#2q0Sg{oAVQDNeVS__;)~b|N;E}U9EsQ0 zxxx;pAM!-42H7dA&szYQTYOmk>Ce>9JI(?F^3EcvK69XKz@xNZN(r;~L}(%v?HDc; zwzsO?je4@%ffzqoFUGB9_F7&C`bK?BXAZ`Y9y5Gg6Jn4L-$y3Zq*GKALnSy-0%^!-`^KJw0TbmWPDOCZGssKn;0Hi7aQWXHH3V?(GXv4mk5|Z*sJLZlUHA=1A zgc5GuuQHk@D~4NO8OF`SOO$DftbU~7Wl||nSjC%wAox<|;vr**EmL@#;7okzv}?qi zL$6*&q}}Dq_Tck;TWbW{1Ln*-1RtG`L4-Yh`(AhImGt1`{Qq1I!C^+@gYXg z(JfDurqItqWkS5@d!@hh?b_e;Y_f47Czul0cpd{v8qxB1#sa7&8i``DSIZhd8nwz! zy&FNdBIrkv8xdNM)cLtMSmnaBAd8BFRdI&0IhE%ng;?{8x_9g7xAe3BIyQOhBWWnO_({*=yw=zK%1a7AMMWNQ)4iV2`Y& zxwGefP~;~k>DkGHxTVu?7uP~se@btfy#sX~E?s3eKr+3sZYCwhQfN!d;mA-ro*?BR zV-K!`Qb^?@t_{~eThKI8@4s>qE>F>M?8v!B^bm<24fqLg^#%!`f=kEGfx&|uc@|d4 zB9ds8p9zJET9qU(`n@ndcPD2OeaaINOo0|gRLLPy@m^=CR12ELwfTmAy?l7IXzYd) zCrWamfbJB&O1kl%O9{x!5W4i~uIg{EmmnP;>e5BZJ@?Oo3=?+aZr6>QtJ|ZJPdD!| zDFo~yH_!X9CcF#R&YK*obL?&oaV&*Qmi-^u)dJhpd4=z}_xJUE+4te=M-s=m&ck6d zG%QX?SSj&VAcS>8S_w2FhL%vVLeoww&vje(NYj={+mKjQ_7LqNDy^%=5S~VnhN7&c z?KCDfD%K$~QC6)$YeuIHbt1m(oZmJiYoa*k`ud*a|IT;L`93-?de3(`I~e8RjAFcn z@p^_s#<+u`)J!mB%$Z?}n8=tEkVT1X938meEGEHNm4(^zDQmj$R7E6En<=!pvO+eC zhXy<_KkS+^LR!10-5Qx->BBiD3R3eUpNenXDZlS^Gj%?BZlG`{M1VtNjhy#ok zNEMTh@-_#B{|%<8Y88-B1rR^qzyVR25fEe){H%*DW82vn=F>!>qpvX8H#v#G)Bxd# z%mU;#BC{}w5GE0+8lfgjN*4EFk43?QfCpu8ejSo8*(d=E*mEV?~9 z7L^8ch=o878+bYt)&D9|5asifB3+@^$}atl=*8n&T>?LLDIeABE;&IjdemZ?A!$m) z5QV-aeM?BoX0zNEc9a_O3uV=njHv3yLY5YZg>)?<86nA#yjaMM#X`6YV{SxsRZok! z8valr)97agT}v|<1vmnuy39~P7$Gs1k~CETf|TYmLQ2MUI(yPOl|?Z?S|DMaoi0^k zEU`J1tqv)&HK=fLKtrZo4nhmmxR}EzF!1s+|NC|AU5@{Q%VLjjya(Ev<^}!Gex_W8 zUw)l$JiT@4+Jq0{jCjI-de>b88{o50Re{NamwN%W+%EuoXug z8hpDE#n?O&Yk2*3z7n~&iN^w#q}Tz=K~G^iYEU*MMN%D=N@CJLP}>yARTN2V6OP?1 z=Nl{5gdWA!iYym?=)gh;9Lo$?0eUJ$PX*d!)0Jg&qxGnD(2^`eeqI5^#&uZJ4;19< zxpgwYFz^=sE2g5#PF9iw+W!NNi!hhVO&1XMLQR7q?u7y^!&3DfLchvqPUiw}TL~Qb zI3eFd$V(sYAMii$FQ0=k|G+yFpY&SpIQkcVAGB`a3vLz9UN=H--rVfMa(B=b7rBsNahadoE)YRCzHOV&ad6TNVXdqJ*Wv^ zAnT)3cSDLY;I+@C6%h5~)Ip$8DsU(OWI&t04=98_eJH22~De40ck4>WW6mY-1U$ zQfDV>;f^^rvouSgWJ{CW*zmzKjVc9ek#4c&AkG%KrMVrwW;cozH`bHmP6lO5aq4G# zcgM`V+rK$~-qevj`tE%{o)T9tiTjs9gQY9>JbDBU`y>B605IkEyGzA4u`0{an@nI2 zq_784G+)FAqfp1fTzZ6cJRM8OnrZQ(T<4I=e3H^FIn0Y9+sRZLg82u627&f?9h7Pv zt`{|(2Okyb86dD4IQ;x+;F6{ZKmY*GZbM~wp^_(@QFZ#}-#N1G@glt3Y@9vabLXa^Z4i5Ndv;An zT7jtlzV-=thbH|C*bzQ7@RSFa@uRp*xhNQO^YYBlWFCsNa>i9>vRG?4<35SKjgpo(m}Sv*zvWu{ombt zqWAd&=ifLu@x}hvX715v&YYPMOa9TnUbygQShL~$H^%%^ou|LNZPQ5cNB-Zg`xhaF zSPkC1#OAT3LR|2KKjs(oHmz(zRq$X`+#7*C5g3j<91&NA(B$@p#D`^AFT;oggAye4 zRy_YdY8YMN1mQsytgD<^0uA1NoiGYE+pSJrt7e2rOSuMVsU+QL()zU3nxu85>#_&+ z!@B6$rrl&8v=7@%w{^SGOuE6wB-7`BSg3il(%F*bSGd$U2S{*(eBgC=^>7rMgY8bb zlOq_90!$$AgXTEdqYB72Jz@dp} zuUXzt?jJoDhjq{G^Pd~P`%Cw&LCOjDBhStS-V$tNS_}4K?@%+;H$yD7HYJWFU`GPh zBp{Ypkr3C$VXq5&To`s?z=e7jhAh}^z>o+H4w3CrWsM0+70;_RJg@PF!{Fb%&jd1a z9h`>4ZS~2FCR6-B#;Y{Asp|^gbKfdGEzjCFTQasJ<3%!(Y+0U;{cIc-V`B(rv8gZw zf>}C%DHuu!5E8cFvSw&QJFyEX9ug*Q?3mchBzQW3Hf;>FCA3pQx(sb+nxRmdcIYIw zd#^Siz%*d?Yg^IUBo_ z-il)*Pe?BgGSOZ#UCGh%T#wZvB-!HyF3lYG`{AFCzkjv&t)}|^i_i#9jlBDjadX$r z-yZ2SGk^NhrQfpu_RYOJ@XhhzUwzWP=0e|DXukgETfe@4^Ti(?-+K4l)q_39_Y(%| zi2D3QeR^a=xnNN0zUldv2hVdYci|Nlm~VloWx53~Hmo(^83u?MV6_ew>0qTAR`M{P zhgQ4>W7(dcr%<}`l$7@FCmVK@I3^)E_4QtQ*ZwU{<%6_F|DNJBnrCz5iy~F1=%JHE z8>L@#(IrF!oiDoRWRcdDVme!7Y2Fk)biP}x7Mnyyj7*Y?jyQT8*x|@Aximt~L-7VP zx=lqO6N|6S1T+{44a>>>|70jw|Gmv!_xC*a`hiQI?cH@TtF~qDzLwf7yk_jEIJ5cq z@p&`wr17pjHQlc~0RN%R9~}SQ3-!-FTmQl_)8^{~r&!BJ*^*vmD2ZDD(_F&v`N51B;ja|u#*@F-Lh1}#;Est7xfv06MoLd(0 z`J=QFaD!h?8`*fcP#?>&n6tO9e}ic%uW2k+)q!_v^FVxA-ZREPV0uMoO{H_gcSEP6 zx(zoFOk4mje9oLf8dR$ox_Ee=2!>z7V^MSqATZPwqyyn1!6_2F%wu>7TKU@8m5phT zKn`Z4MkVpU=VO=QpDyF9*)t4I@V?bqRW$eX;&5X>!qh6xXBU&|oQoQU5jp=Tx-JW> zwLE9R7A`v*6T_MTl!vp1@ZAB2gL9LyU!`I$B<&O9q2QeuxhMiEnOH0yCv`H3fX^hg zgdogJLJ@?paHt&TkDb6~bHo+Mn;9qzRkUuajh@!I3w_SKMb-$x*)lsz(0B`*4zAjC z@wJbE&G&{%+;a>m)DGrf$bhm@-QZU9elu1RobNasm^UT>yRnV{Ra921!~<_MK880I z52x_P2w+;&DcVqZ)b|Kfe;TUQf*oT$u&`=j_+0qg(W;h}WreL)^W;ibL6eKXRO#)O z(AL%Q)w|of*g5`L#W@WQ6|L;kCfeCv<}fNjmFNQ{e9#UJcBr(&WINdG@RAui%|QCl z1!h<%x64~(W{(~gszKzT8CJk1V7x{%}2Li{^PcqMomjF({88{CNFqmRO zNK}g|f@x5afaNJVMcpm*30M#w;~-3OdMuU|4n71Mk7uPuIdM-hlm=ed*i#RyW}li> z({QT3{MdqH;}4E3INV3vAh>1X!R?F(yA|yv2~J37r1KIZsZt*NLV#C=v%;{ze60r= zR>dUlK|z3|FSI**6g$l{{||H{x%_F)ch#S6oRs2yyqmyprQ~C@cKjUdOChi7Pa+%O zlVB8;j6E3RWSHN1g2Ds<%HyXQK~bB~LhM~5_7b-Gi7muV{C9jVe34;Dk46-2r3O?Q zyJoV6(P^{^j`U>`@RCLHJwjWV0K7nIXofa3p-t3R0x)`TLl77Pm*Gy&vjXLg<5UDI z1r4Cp>*#|c0y@z^ zCKfQoZm5Pf*a_Xh!4S=K!T7C_Pm4xLCoX@oB>oX?$P>{c=e&4$G!!ZVn|$Mvq zE%8|~`5N)wHkznl$;?I*nV+0#NG&Bvk33q;BoPXULylR9Bs!dM2>Zu+XI4))szt4! z%@&QK$K=5}R>%7U%+GbqDBaPpw0f!Eesu%un^zntnW9Xo$O-Cd3T;}EaVumW?_A(1 z(&h#=llDU>WRi(S_1sP96LOJ}^z7S|xq{Vd^;?<0TK{9kHcCKHW<*)m?lc`XVUr%Y z5tfi7Xf4P9b>!M$0K*Omnxr;qJrNcs-?KxTeZ9TU&h*(Y+Od5IB9x$x_{gox@p!Of z%A_J)b9f`9^-Xxmq1(M&xVd8kg?{EnEN+UCR-58*>!PdFy=~hp4 z{?o1edu7F?C7f2nPl?oaFZVq|`kQ}q4`7{;gM8>8!{qgk%JZ@*a?<*S6|-Q158yhm zUMPd7fXU8v8qH28(&QquZ2lkfRU6w@b%xJ-&b@XVf8CGRP8=t``EWk!w)fh;PMQ$N zvF4&SgLI&%B`9tfu!#z(Z7MObsvG&Ushc{OgtiH7k{O%I&?*IJyOnOJ`Bin(qM`{E z&{ol3-O!4bA1zzO7Vkax-ndDF5Trp`q}p+v=RME+oagVgg}R8_Exf_S$P|+kz5!u z7tZHZZD=n_CVZ6z6bk!lMMyTYfZw2v@D&FD{$Ez8C)Ob6nGTf`^U|A==%XH2S5$KU z-usIFfHD+Rlfl0BCQFZN<>Fmia*1?zshDf-@Ez{!NUAi^6}~qf?&?l&yC;|ENww=O z3Do45(mQZXev|mf9zJ}DUZo#VCee8YMFtXUV%?0f_uvD#i4((jk-#v4AZaC8Y)f1w zSJ)z>Y*wbkTu5H7%tMQrTtMzv@ZKAigTJe{kQjt(N4Fi_bN~JFn^&(MJGSOz`KtVp z%$PhcK~VxpYLdDoCcWqTz<1Nfe6adtO8FIeQKs@Nk%&2uCnp#1=rt#I_4>O83vdmO z-E(xC^vF+27h$Fd4sX&Jp@DznW9xU5E>2B27lv0KYY~>mY@5-A{sF& z^w;x;4jsaKS1zAdMZ^44rIL59x-#Sb;Me#MZo6_g&L154MqD?7TMO!UHWh98&pWM1 zxMU?nF1zK+SRIXc{GKZv=$q;^TZi? zP`*FUd$%CJbd9%a(EWJUZ zPJjM1((-yqH-8%E+C`~{^Nd(?Z6c(lXbyOV~Ra?&`ZYBrX)SQ1ZlNTr1BoFBJBnA_nbKFY0Yia2;`z}Tp@FE!hIYKf#i4Gm?36~%`VNO&h*aX+& z_5=?`?Fm7qvV04}kdaUOUPQP9lb)?5vagd6lP-TOVWEj`h)3Oi!{UgDb z{+mAZ@jlYbgIJr{OuQ9~(mq4~K}KE3dJwgv1PL{;kMCE>iW&WeWFW0Gjfg7EXQfRyhR`rqKNR91KMhv&1`6dHSF^a`(B=q z5UKP6=@l7>57C}<5AAVNaC^oEMOc$X-pQiCI|S(c1ZE;kC_cnFZU<)kK%9=ot8p49 zZomHGqG3Hgu&N&OG=;U{Wp^tzgR3#y#5KaL4o~2XiGbDl0DQcnI`b>=$>n4e2d{v# z;dnBzG%gv=6#Th6!{CQF1=BnZB)`S4;S3uy$EL>)j?Io$$9!Y%%2h`e9pp>5Bg>=x z1w>AnQ`1uir)H9&$4x^Sm8M3h%H4md$M%wM~24K44dE+2)#V z+hPU7@ozgbbVdZ**jTO>!d;#gIoOQu>K2og6mlpADw#L(G%wI$)y_NHz;c&y^l;EG ztw3kQ)Fj)#go02giy;$0q*6A@w0v8i7MVDBHfcVWkf%vvow^OH#)NG2SL<%X7 zM9N($>fLc8qPR-1r|L>mE2sp=r@a+2)P2GB)pgiP7Rf1c7jOG1 z{WYc7DYnmTr&aMnwvR?648_ZyGX9`l<{`x{*V%}MR&ms+-6!46o~-A!6{PwcYfCtJ zk(836DKX4as~Fu0c8wA_ID+U5Z=p~v%oW}*{Iehxc%ac<)+O(5M$6mU?P}zp8TIJl z8lG8l(;qFLD_<0cW@hyp+i{oqZIr*G@j`P`RQ_ntbOyh!Sn+?`Zt(9m@V%m_J zRhu>>v}F?GG9figlVE_9RsvP~fl8Nc%2tVjV4{UeodCg*rWM4WP9w^s@nbMn^SZA9G;);X7IWuw zmvc(aYRTD}u=344k)d5M={~~lMtGI&++|kT=s5iF_L|F8>aK>X^VMV3jjBqjGhi9~ zZ}XL7m6eK2Dn{je<#OdpMRixgm2_pJQm?2LX3m%uHWV?1ydEyE*n)U&4K{RS?TYUzgV;!OKA@9Xt_yFDR3sC%7CuA5?;<{&7sSX4SP% zD$YD%(yH=cBM!`{Z;2U|zdQwB-pJM&^%fBIQ>_SfoO}mV4>3O_eF&g*`Ll+&7;qF z<$1yCfd`@T7%VE$bcltPLUQ9$i-RjzfPGManbXzMhpqn6My7go%e~*h6>4+?<$rdA zZDDx^mzr3E+;3xK_bOC`5UBg2!voXU6=n~Ge7vb(C1zbXBtc!4BFy0u6+`D0qp{oE z9@d@Lv8G89SPj1K4Gs zd8fyp>ZRE)nh`cPM)gXT6AwC?`P|K<#%i+f%m7P#?oc*ikO4L;U4sgAaVNP zG7i9HY?*`GgIE1ce2y;H?;%6XPIrdG{rx2x1@tR!zv+(BD2Iya|CVvrK9t{)7aKU~ z1L?VcC*Y>N{JdCh=$RP(MU2L<7km9C|J~^@W7hJqdGa*J z4=)DE%SkDT#)FcT+&ap&jipfkitSnDJg}Sojan=j9nCzQ@qr+c36{E6H zS*j=%Vr-c}w}r01Mu%;$bM(0uACEE@qIYL~96ik^IvmfZjcI9GOmuDMP)^(K1&&_| z4(Tv(OfU~}l<9ZN(w5F zr-o+CKH)EaDjRXMq#P2QaDpk3uq!Zbpadm@rH;ZZ~0fY6mb2{;(A;? ziB3SSWUSMRT!vQE7PKWz(Qb5ttnrgvYGev0F_{a|ljDI1qBCptrB%1r%Y&8oaYzn_drg*EXUAe>35K(XKT&c>8)QIMh?6+rryo91>0LVZG%2nZ zCyVReT}F)>>zO{IR_kB)ywM;0=(?+zBtT~mN3fOEt-AXiS zeV)t&dV4fe8;Qr@`#`Vlz<(b4!&5&vaL?qhFR2gG2%VPx_UKfxu=k5!N)12Y4;ZoN z=nx(54_Eeofd+@PG?|ZrHkg;=gc%sjTKGN!^P!B1mz9y!2 zM&hynfiq zqpJLfOtL|lOc()RAme%m)Xy|?_{{XpQZTFmirg+%p^f@Yp$*Alj>uX6wMxj{Y)VeD zPH26}q{~&Z^peBch9;fRRy4_gx3;3m8iSPsmL!*{-AqirAs*);H)HnmnEDMdXV|Em z;4u@4&Q6FK8R~?XD{&fUuyz5x!;IfddW^CeL%dO}7nX+%r3&>T`7)HoH?nlC{uAcO zW&;5%l|^>ry>|Q8Q|ydTpBltB#bgEnB_=hWeW}h2&QOffvGhJ6$G8jZof0+`6G3 z)E9IG%)P|y9ofX6~b8DYWS6#du;(K!5Qs6t)tazwH9JjV{iS-%4t;v z=9GBzQdxO|gqUAS@1{e$caM&iBzNA(FXrVuYJdW4A9taNGo&>1{b3e_V?R_Z0u0Yz zHp;BLP+lyn0MHsT+bMjp11$F?tyMkjZ2x#N0&T*TAxVM?he>Qpy6v% zN;ES3U-GLhwvDU|pEJi9H}`34Cux&7c5Y6Zczhct&bYS6UJ~0GZ|$g-vzu%bONn3+ zqUlXV(4t026dri!1LCqmt32?)LxrQJv|&+YOI#!**c8MA`>?9TL%R>Gx+|f!EQ`&5 z&Wv5>QZ3bTksylZn~Tpk|M&fK{_~#+pES@9mu&5ym^AZ7SmwRfL9ge~)4ONOOXb1x zXMgtIyFBi}=SY}qyf$;~R>9U11J&hsI<3_7nL==xwDdWg%8=@zz%`L~RRFjRWL0#wsXfk)T zx3splZ*z}sHi~Y5ErOdHx0$$mp7%Y%euZxf_x|v{*ZEseInZzC|4E@{ld;3=Z49a3 z75L@@C4b}NEBhrcc7;?t^d>PpUw7)wSM3P1oxn$+-HxI^MeT(A1dSR;dTo&=LQn_l z0mZ#&0FEX!3}O$P4!s2zEQ^1y$pdY_s?VRzM>S18Ulsq+-Am;+%GvT4%HPA6xeom0 z^Y1)I2~D2pn)z%qT5w5}KJA7@)j~a3Y@|xkNF+B^Yb7l-R?n?@lPI zQ)9(ffYq^Zi9yW zm&%FR+3xNLI*z)9<3hKAYgezTd9|QEQX5po=9E;}ThYT|N!6Ag-x9pz9ILngfp=(b z^M$J0(0!(PKMLHzB?}fT*h2O94M-G~W3b8aSS)RA5iInD`%-;Z`wV@`M2PjAOKgX+ z^lxO<{4gG>`QgN`^H_K2Z0Ow(Q z3bq{uyTM-HZliw%19FtVzw7&R;p?c@H)c+WY`sq@Ek~u4ULsO^`o>SqKs(p^YS7?9 z-_jT$a;S>Og=+$nPP^^=yfS`VD&U|!0O#y zJqcGB-5KRZS)`+*P(6WhJUpHsC%N(BIBT0J*5@k_Fqa!1f zb2>bopC-BK;xsp{b50+ioxf_dRUPHONY3(i(HW%?_G%%#5yBxl(*2sm@Q9hAa6qVyccGw^}VJ<%yerSI@{KRe`VKF6goLGxY+!TuP1425>78lAQ_=mFNUZ>wfskMElhU!3l2fIZGq(`}K2INpe36i>%D!aoXsV8lN6mD8#^~6X zJ~p;H?(&UYs@*T9x_o1oYB&DPi>NN&*rnS2VyeqGcByuw7f`*YZk!=;V*>qp3s#XR z{TwGNQj`w#OlUYfrlD<6!y_h!iqHy0FpAlK6za*ucI7>#<4BKWbbm?WfbD(+FGtoQ zr3i`8-#4}iQbak@AIZ%Xv*Cy6iat3F6okp5xC%6 zf~m!pd%Xm~4O$Ge8~UodwKYem^B43j>QWgFJ2V8T6hVziLW{XY4lOE+ z=|zGT7olvWsL);zdMJU7v#T#(eECj__9^!l@bbdiLTQ04RP`=Uy$ibD1zqn#Rqq1m zU7+QS>5b`n0ZX?)FM_oB_Gvx0TkHYV?@Z-G(E2y3)k~@6isYr#&^R%)PiY7uDJqAl zNN?Jk^AhCsLJb_*uH2&z*>xO#cKvj#*G{pd41<1?ebCMw>&JZmg@Fr$7ls}TKOW|( z5gxqkS@V=U#8WlGLyhq0MtF21JXIq+V1$QOQ)UFMs#_;kD3-Q*M=AdC*0CN5^=XFe zb>uv|09)$5fPFQWxq`7`g80%&jFL(+oxGmhNNy(iBzY7?oiCQ&B zrRJ!*IjU}sS~W)nb5vT$nK^#l9KUXkziN*EKy#|zjE(7SF`XST)MjWkTEUxlS?!s? zf59s#uQX#cB}{EhZB7}c=)&0qZ8n;kf(_jWed`eW1lB1I>v&?j^1)VPMHRyil1l?$+EG|Gsl zuk5Kvd~MYq^Ns0$tOxp^QbNC1{3E91zNVz|15i@BjZvr2$#v4#jkJP@&ZCCIkuGH< zDw*lQL=Ro-FI6NnJ(%dBjg|e1)T(2Pj?FqY>DWl6cUGiBIvStd2kfBti?;x=ncjG5 zS~BbNgW}DAkAl(%ttm3Q%rcb{zX9bsWEEH_r2O<7c~e;`qM)ho)Vdmaf$n zlBr!s*+kN+E!!AM5Nu2vs0E2h8y`}{hRUa;32j3+lzf=B38)s(geHV&J}^-gMa?Gu zkJ_C3>^Nz~`k{XW5{r^|{9b&1@7~`z=XcJ11^wY7M)`^Sd>+oXzopK6J`&M$R6nGx zXP3LmU&#tuCOc(_lz(A<1#_@_58ma$9tPE! z(3qWq7QtGJ*W^t6^?`oM}pDhfFpr%B%n{CrP`(7A^Mb^+p}|P<(R)j zk}%s?r#XUq8Sa)eGt-HrX4q(F#d@0zJ7sYLVb{+0_Ch;c%VrmUkQIz!qg5-fJiqgT zYc>iFbEK?eyrAP<`j9@NFX_B7`9E5&oB;M8sMsyrZaxuMVXCQ|7ye^m!89|FzL}%S zm=nKg%K4O~+p=_PrNNy1CY&CwQVY-&3gWpS4l>wGw`SO;7Q;^2T)@sp=Yzredi|aj zS?fxX!3qY&VR1p^c8Npch`1#3VwDoHN{LvdM66OG8ubK}h>Q{ut+0^3S%c%%0r^t~ zSf!K(c$+y@tCV5fSw4=Qya=yHz0O`TQ~nK=dwVTN=SYEWO&4g7t`+FIjD}|m?-s5U zxcLGu(Efg{z?gwA7>m)3+v%=M#jfo%ENxg50cRMV3N^VKIA$Dl)2uiCZ?33(sq`{_ z!&ni^5}zsgK0*?0f(5m;craTBMt-NC_-Uh8^8*g^!?h~A8*j9^)X%5+li>Y9r5oa& z(m7P59)hA$Bd-&g?%1ixw7Z)r${cO((zGiw9+xNNvdke_m5cJId`dRS%QGp%zOTsT zOXVNnKbw4j{6}NQ3PLDE?F4yTCct%5t5ZZojCSUDr+x^d&E+TfH1{A1p|g}e z9eg239uMNr1P=sBEVw>Mp7-GnU*1Q);lU?8_)!nu=fTf8@R#A&icb){ha4ni6TvMl zNEH1u95+o-*giu(rj4OC8%8##jo551-Oh2S9*N{SYT+7?9oe`#B)}cdxp2p`sJK{6 z6&JC(*ww5K32m+HMEg?n%e6bmhp=Ejz~dO&-XMxKICR^D|%D zxaWI^_wUSK-hK8(7TF3P#AkLOw0v*gMKbIjBAvo}%acf<7J`SuBjL#~7iIx=H8g6D zaGT4o!;~COhDjI#%TkeLoYag5@UFQ_Xm4~m^<>JY~><-byAT&l0AMTfIP?ch2LR#$ZM?h!JjoqWjD0;`Tz6~WKH zgw{|WkGgYpZk>1L)%;L?JU10bVec)>m-s2UH|7aCrNg@PNcC=NR!3{uO`g_mPBn1 zxV1KFgVMVaaY$4;C0&K| z>DZYVH&gzQ(pb#v)yXLZI}}wZDuc?fGNz0xbqd{>R%kk_DKw$Nr6aB>Y*`9zZHJ57 z3m0opQ&yiXjBvxNPyl_03y^Unpsh6Yobx3odD;GBJ9*KL5Ab+Bzl|qParg@yM!rT{ z{p+A}4&))%r)-VL$lSNOZu}0^?y_^Prf#@BEQ5T>?cq9eUDTcGYVxI0TwvRV0lMB4 zYTI~tYa#LWuX1}I-q?es^wwTe%c(Bar`ZQg4uffG7dV1AsCf zm#IBWeeljx>=W7q)RN9I^7Ah#VBz+<5`MC5o2V47o9# zN?FuP&@5$+`w7ZeEuAxvH|y4^V5lg2yb(2Agsu=4gUzTFFSIVTlGawc)gnV;O<64V z*EtI`)%r?Pg>LFEx^wQFdi2=kuCAOqkh8LlenvA!cCu%ow3dZCR~TR_qyS-07)VgL(OQ3WuxqjdGi}LQx_>tFsc)`&aaJ04u9lh%3 z8oA~+yKQ@0bG_95%g6Q~F3p-=(+{nRtj`=l%aMMDpIDBxDT7a!K0?|#5;t0s+pnQ` z96`Q9%NnC@r%R*Cs6red07J^G!YfQp3?)h57qka5DEw~f!;qn+UYRYObQ)BFg^OmP*swgy)fjw4CN zbuvkl#F;E6A4rZQ$C9RG1SO^d2zLsA7%*eC_sBHHGmDu{;$ zwF2@`8cLeW21NbPMhLpF0#T_I36XdJxGxlbS#2ZESdS=ed`S;BCf9L!E z54?mkXd=UafG{GPC6k%dFwdC8yl8Rvx^T!B@#dMhQRx}7Q`U@zpV^lycI2Or`v;EO{ z>=M|EB>DRV6p#an01Yfq53YkEw!mjB*1>In>S5zITp(va@NW6*E#GL^7zM|%&Irqv zE`l1iS~K@dhvhr0@*M0N_spIDBA-{4i>|+X=T0e7o=V4?!}opZtGi|`)Z@ZAA_D5aV*TMVwwG~5 z$4@8l{=|_4*`2@}64>FxbmV8$jVQ`eH}kp#7p5-iildqmh+1Z?Pfe+WsFk%AL!ckSN@JHNAie#i*KF3vA6JawA+hp*#gP93Sge&o!HPkd8y=uS#=Ztl01o~y? z5Q?z?Mh&?^P-7ys270W?nMpF)ZPBeB6{UE7=q${utjxQ68oK)+K3V;Kb*V~g)v95@ z%zC3v>YtbinLUi}2>*ha|Lo0lEZ5KoOHmXIaydDu%qzrDu%yJ5hBBiF3X}b&!ZLYN zS!qyKoWiFUtEYEw-qVmFyi3TV+5#fbZbya+xm=T!imdozks8HD@p$oC@pe%xa(Qur zf)u$17JKsXiJJ52M(li>Ytc%!Y=>}hSw^+<1h*%bCJCP@O)}LF4ed{w?dDRGHo34t z({CN2xHfsbxt_t}c?6dR`)nnT5Rr9$ht@JLIKn!7*9JWhY@E;Dvdy%PY@>BNKU6W7 z#^DzAf&dk|CA&4&b8xTYJM@R7B69Z?5=Rh1DJBz~lzf=C+kWN_ntp3dYfS%Y!T;ap z0zRkz1D`p(3;3}1Ecn|gZr7Y)5c-?UJv9Ls!C<_JEns}19zfDPfL02?f5B)DFuIEB zJSv~XLTkJxYE}U$7#U}q$9_Bhr*UFo<@A_cfC`5Tt1-c8ZCGBk&6AH%4qaf(B}F9? zq{t<^h$f}Da2dO{jeAoF0Cv|$VkpRjrfTj^-+^QRk&?2`AyhVm2 zA~h^;=c)#mGjpxEIk0mDEVs+Pdc^9dyUjFw({|lzq$|~XAFF)ys!8_)a;Mwo?|yXf zNTeT=v4QZ{_w4!1{wX1@=OZE4x^sWE|<7;U2O*{y6 zIOmF*OM~Fm=2&QOFc4_sgTtqW$uJ8l<}h!4hgX`-xvnNzZ%e-i(VE?8^sgVEL}{jC zq$Ndf6U&;R&1h6(u*Ee7Y}4+ws~oKyPUGW%7Dd_u7>xFLXT(GzrkA<}4FJK0e7P`E z!uptwk9SVvhj980aD1IXA%j1(htLQbM>iHwe)%@b=_#{MhAq--ZbG%P+g;A*(p1Xg z49zB)KA=X!@i^ZTaeKgw53n$^`^~U25K1O}N1??KZeU zVC8#CU4F0rj>Y3exCZ)if*XtPUjZKTK_D>@-d~6FtMEX%ya?PjeBcuK2H;$xJz)#@XNj1%I*TRXES<~Z_Co@>e#4|*q znRpda@0KQviTfvJCWMN}CQ|u44;zLhuGZKnt}A@+Jof#V@pyOk;oX_>zP-!LvODauSrQKp3pNG|VraqG zSfU6_5OtwJMWxAFX;rBrQKbmAYWl-brAqzPA4O>$8l_cbSu$k_R2wS_HsnWCRjPPI zl~5GnanIc`E~I#U?#!IM_h{$bbH4ApnW`NOKflV#dd6m3mw*IUp%^VZr90A)2ubWu z?oGtO@K&qb`cAzit53>J{g2D9a<6npiZwZ6{$y;|K!LjadmASRvA%%qek0o$1zWBA z{6oe!OHWL(-T}3={mAeuQ>CKr#jkUMsP+IdtQDCwy2bV(9}>~`4Y!M{4d@&fOX|V7 zwSO3~n5OdqKWK7Szz7(2UJnFpeq;-X9^T-|b_Kx417JH?3H75%)I_t0MX*ITSK55- zhP5LEpxcmf%}QX6C%LoICL}r?x`im^YA^uEO_(Mq-rBr>X!DWXLwkxZ?Hj3jk^$c9 z$qg{+ZQDj0hlL;1-4%`HJ%NG)-XR9>@P+NyfNnMPPovwLi{&VlNjO7NNyzr`-UzcO@c-P}=f)ECko0v!smX09t&$O1W2 zYhAD__ieudbW6joh`k(uKT66;s*82Vfgat?!H}E-Dtaxh=n4k|{S=hJ?0!(KKovAa z#a+HoucrG#;C1;TKFZ}2;;btz#f5~6LVgUZEJ*R`G%cl~VqEa?5|jE^!ZQ-)q(3x_oV*;N%piCAL z-io*D*x)_6Bd)SIV9{U)YanRVJ4$zGbNT0*T*jY$7 z$zm+4)2z$kmYn_0NoUhJ>tvmftCd=9X&qw$U0WnU@YYMMiL>z7K4)D!V<#!NlaCCT z2sWMClkkDP1jhUlpsE1&J23bO<{Q9-Z`v4C#=`q+WIq z5jX9RND(bUhgnTSs+unJ^hD*T(G}LCVZ$cNMkJ=ohOH^esHfAO z0x}ShRmjeXT!y20&VzU?(7a%HI`cL=yt=CO06sv$zbRTem5$Ez;2wql3->X1m!lEK zaTJ%P6%dn>tKT*0YPx1!tm{dCxBt3QyE8vAQR3z&K#p(=+&m8i1C+C}07>GZfY#BE z)EFr5PEQl9k|%;3M9)H}zQS6k$jD8n(a)0FvM`c#dWS%&B4G~b<#pu}D0eiB7z~!5 zh?xL>GhNOnx7Vk3O)aL~VWIk)@xjBjtmyRA_uB=BJ(my*a*%a1Un$CTJ^Rkk(Wve` z`|<@jv+Ll_V`-^xcPW&JX?ZQ&w^>j6q#AO-d93NU2709oNWTN^L*GR|1iZh5=8cnw zU&tBi`BUzT(`OjlLA}_oVpYX{RRTS{AH6-+NbQhkru;wp>G5Fq(cySe#)^!Q%*m8| zEOPM0;kR3eetF_8K3@!*MbXPDEcF8<8VUvN8}-ivQ|k+yOJQdVx= zEVa0m6;OLO!M@>amEi_}wbh=0{UA@J)-o8k3=iDWbKO8j-Gp}n-2^{viVO+wC0(3e z?`0TCA6FDvge!qv$THT`9c@Xvo3Oau{*(jjgv=nC(g_Kz&tVcmAp?45sRCo_DTm|Q z)bT6yNHwcGH1C-Y9xB=D2z}-F)P@%enBVZ4BdRQGsv@gP?FV1BYnm*ps;sE&?eRmi zvBcKQ<7{SYA~t(y9FLMm`cv|VN6in(EHZoP@rCx64^{;dgT$i#{%CpWU7x?YH`r_j z_g4MBcbAqQJzDGqi)JZFVT0V0|uzrL3_;0rtKDxx^a@?hl7H*sU=BMNyXU*eQ zaMgEa#`=L8@<2^3IxgA;>c6Y2>SLUhIh zry#t@;l&8XNUC$Mu92dL(!G$R}=pn_bWIJ!W(yJGk0g<_2H zB$#ajvfqJu+TpY*Mu5-d47*p)RR$8A2YbA(q!H@Qpp2Y>r5Uoc3`;Y$O-Oby{f(HP zfu#&f#f@-RK2MhB%cy~O$_>mlaIx`TyLM~TJ+WHE&6-rYpb`+ z^Y{{_;kU4Oef8hXv9Xz%v9adxfqH#(v|c|z-G3%tXC$80U7eVBvGVm*5`P#%{@F6K z4_`9Ruihkqaj0dUXjw6vV^+um2(P^l{5Q;e2;3JjK#)2mx}Tn;oAfNr(gcs8{Wlkd zr`~k9AV~#c%vtMNfGB^2D7%@fz@iWZ6odqa(@EUKvzW#IivsF&_vOn>`Z6%pJz%OX zb{kad$qx{}_L-3mCv`gX!gd&v85oGl;ko~EU#+omTvhl!=CQNm-Pzgo?#%42J-gnQ z?X|s*ch-*cu&=RG;BFf& zu|$Ge!G@}&7HZk{2SEf-1Of?FZN1C6GwV>Q{y~*MV)n0W^8WeS^ zC=HkL1ewo3W-o1E_uKY9w*td4X2_w^D7C)*D%PdaNEK36mC<-cyD$}54n&Cu@#rPUU4mmM9 zj2Y%%38lr^jX#4A<0bqe81+uzYCU#6Qt(`Ia`@%6+CpL-`rhuDcGKRQ4S>2`$P+=sMhke`iDIQ~U|u%pEaV3Wov z@Z*B;F{n^?v83oH0YTOflYw|>8q4i+v;gtRe$gYhM((U5iz3Sv9nmJEWS-ndP7#rC zq}gPno_V2~M@#`BSXbiaZ>=jjXOa<~uua3@P7W>D`PR`EH7LeRbu?^Q!eqvfB->Dd zyCDR*cvSoYvLMDkVyb3F41maOfTI^1%NNX~J2D#rbDW-`=PCUb`98ToC;;pbNfD}u zk#^S3j~!{XoOY(DPCL@$$gdblmgMv8fryigTfp^LOVH5;zY?&8QDI)VPdFur!YcTw zT?t+GLi=*lKwK(cb7#G9x=?2R;6WEDyEq1VBS$PQ?Q=m*c_1q1d7Salb!Qb5yuTG% zk$eeNV^H@s9quoKEmV#jx2dPqCse8?-g$#p9dQ{fbp3GE4eqd8jz>HumY6w6#9l-eu(yEkTZ`?}yyD=l{|l*!a)=K^h^r#ebEK@=A}M=4|N(n@)B( za!R+HNX$$)F`t!iOw)){tP$Kt2}3Ag7%XalFF5TWO5E3i0zel6nvWm~b&sh*2b+PG z7RiX4rhAcqfSPeZx1~{OUb;^@C5h54icqV%Uf}q?9J)oMpaL#~(bdp3zzRQalFYbA zE_IIwV1930a@m@G4+aor*{zv+{f{r?0O${%*>T&hfzBT36Tq$N`(8SJ$1Xtj2R0pQ zFHFvFSQ!62LJ}H)+VQA#1Tei0n9D|a)Qf)2?nxC2XE6yax&PJX-s8VD{poZ>rx*jl!`RT}bU`1I0T~q(YQW&V4;cm7(962; z=v&{uew{d^a{WZzs>feCO+R&d?}>W(1pX3s>c6a4@5TFav-P)TUwQ1YA8vUDi{uVW z$=a3Y>nkfy(P{jrdhF)PL(e`-4&8kG?N@02as1`_16=aR+kd0MBMU1gxv}v2>*vmG zUl|}*8;!^|E^>o0HI^WY1@3;n@q1aJBgc9ksEi{xCX;egYkJyW3G)nI9>< zr5;wW;&#=!Vx`eQBaQviaq)RFNS{Oq4T-(N6HvAcu|#hGx*BC!ffBT1I)lbAn*5-G z#^5_NQ<~X5b9hFW!JC;HaW;c77Zks<83Amll;$dx3NBW_Qx){z(9n3U@jYSG)o{Vn zKxRD+_}ITRY?+924I4HL4!Rm9OOv}N4^Ik{cq7-av8iF>|3(A%lJ5oKB53%jyK}F& z0GhH)r{CO!(WY@x7^4$RjXD#}Z6@4paB;5kex26|K1F{gw!zw~&9w}5 zqBT#F^?c)G%Hbo61$8I19;5Zc18c{~?sa$_*S!vO9^{4=i>r~OKXdo`RdcT%@5BUU zvx+cAGF&RtJaOjVZKVZQ@i}l}-8?=nFaOxiP z3zkz9?k&L=a74;}}28sGrN8JJ+2zo*ch%Jt`1j^-rMf06td$G(b2Ys1TP zOSPrYO+fm*%xt|GdhKSIe|T6pz7_r{bHck^ZMH%v>cb^o&tW!ReGRHQP+k`f6aXL$ zHTi%?1Z0;MNSrJfgH+Gx<+7e3H~PPG*TFeE5Q|u!D|hyfY}epv4-bR<5|(V3drGrqH^^gUpSg~5)ld|StO{VVmm@gw!S5%@M! zpCV6@S5Y_WgKm1Bg}-iMr4@fo#>fD^WEcos_9jzODG@pS18ji1H4F|y1GwX#WLJG` zQ`Z&0_r6a*=i}K)>^LEDoDXA~#CGgwCt1_@J`%E&0RD&v9?T(YDNBns5;WMRLhDXz zt4c_9r3#f+D`-?`)3k07hC+)5e@v)SA!O1twUd^z4ON=9Y%sNdR3q`uz0Wa}S~|X8 z@7{aP@0@$@?+B5eAPrJ?8+RME*=$D8R#jz_7Rc%a-HDx5a8puSPhX@Pw|U*2fat~A zW^XfTc3&p{L63l7@=uglSzVr6(HA57^3~<52^`9=SgF*aMZ5p9Sh=`$coRe0R~#Hg zhF~5uPSsHFf~-nrurVCtmBh*dx14Wc0MZ9SF8tu^(VzB)>@`iEu)FiX!Q8n-ZPf6! zHns;_{fV8!!_in%bnW(D?AeREyc-|ieBw>&AC62;zMU>K6<+Z*IcZg(UfNR|KL*2xVacA?ZasPm?`M7K9IPQA)aH1!5 zW>0kc`PHyL(jOXn?a7Xv0~>lR?Y~8eh3X#3?bcC9_p~Yjx+xIg4|lc0Kmk2)D{v|A$U@;yEDinR zb;dmxE%FW3DJw9_DVo1u?&yd`BXtZ0H;ahqL(q_7U?!5Nb7&jA&6235-rBu;=_zB# zMIzf?3!HlZs?Ok4`oQizyMph$i#^U?zcDwo-Q0WcuMeSyLZ$EHYj7hohGS5VBFQ2U zAVPrV%t}}~1+G>Y`9>k2&XLgEjYEtAr9muoDFYUyBz9MnDFh?s@uU5O!)G zUHcHB}BSc4yAexg|h^`(X*+W3_Z`oa>xAg#mEHu&Q>HsCJ{vTeF^`WqleK^QL1 zwSVB-=!X_AcqbjQ+cZ_95N@w(r!?}MhLhS}?V!dm_>uC8a#9hVQShMhxbjU!ctpWM zt>RUPQ>x&@rcyB_l0Fe5Q5V}p!DV3usTRQW5+Q}{3@aXf~1VxbFIIs(QEiwKw? z{tAu2B1Lo>krxn7p=mUWn733>u7yZY6nsKGtCGX&iz*pYcdGkUA*N!N>Q{-T*4n@~ zWlzwCzJAD6+q=LGu(ALng7sj{L$(IUTQKv4E3ytcZ?StJ501EzF9#VkEpYd;jFk^I zhAOx}Jjl8$omONr?!1w?%Rb8uJ#0i&;#yi!OKd;$wC`b5!C==NPaxaP;ltsv8zI}8?K1)(UM2ENY%ZH`46 zODXSLibK|OI~ZZP=Ytx%nYMlHQ=LaZf@6(iKLKGe^WD-cejW9fW2T0>teA0o42}AG zjR#K4JoNFXsD^%Kgu3oxHo{%)fe{253k{AKgnGN-&*?G1*(&?WKVqnymNa+_aK9o+ z)Z1aKpQm8dGPR?r!>CoTAwX!bV`yU^u^6B*jkz8REd99vy&MM4IR=>nISy8nIg}lt z2m3HTT-F)0oZWr@*fp&;9_YW19QXC>?fctDLEIosV=ZGZfYgJqH?JOd$>_dU3pSg)QTqAXU6^gds74{!#N2rfCwJbwW;etNxkPyFWAX1e zAbpCek?%6RvZvtbQOK!z6{+@1(1LGQm#^Z`%JK@Nj8Pe04gbcd%N32pfAwtb$>$3v zYoD!|97|71pB{VZ#pgyxOoU-sFS(3ghM3ZSD@cg!Lny@F?5llYN6gm%W8Rq=raATs zySU~&?~spxEpRL@Av-7vd|YGk&;*r~nz9jH)on$!XcGytX)-p64Tdk;fr~*-3Yc({ z@^JM6+x{H=Osr8_0nz`#$}R~^MH7%$^a?>CRM%SJ)3F56il`VVw`Y=t1L`fPB1vao@hWI+M&W&pBNNl!f!&7;B#Y z8ZT&_x!IsII5o30L&7t3=FW^TgM#_FLrl+dwzL&?Sd^B_nz9}C!46}PE!9p;`28ly zmDkT%>*uWXbCvaTIF(zdF>$1tnka=eKOyUd`$P~4?j441WmWL#a zZ5qq7nBU5<=R4jj?|2J#{PxALYIhifr>R{5D_w1Cw@P<2FR5m)GiFB%qs39UM()z8 z(L_VoJkfBrfgtWMyB!=xc2L{6v4d@F?LEiM?M7v5Hz;itYvUx0pF~fbBT0T!YgI-n zIh`am$s|H1Nwd92wivv8Y?znlAC0ksdTn+CrNik$`gB^<)3Z=1rf;UDX{cUF3uy@I z3eI`UlRW0yDt23Yf9D+8%$C(^jfK+RXwBwCIBE)gLPUrP#4IadmK8891%_$Zw)K7Ofvpe>y!hWD-3yn>n5N zP3CGwLYZl32%$_Oa}auNW$t9;4AUSN<3)xS^IInjUXFg9m*-7ubjTXrQ!+B(3hM_N z@w=;n#{UVg))*(QD}3)A&y3$QV|&J9uRXTeT^rUSUe;c~$!h&V$#eP(GuNjV~E&Q=$hO$ zw`*4yOC=ZT>H=lJ_j7=g{;AAli=*pPZC0?44OFR^@o07Z+C$Z~t=(F6M<|k;szb3( zMVVVDtaebU^@F=u0VFd3$%4c1LZJwLsZS3T$AUm803f2@U?y9{TsLe+4S-PtVAKE@ zH2}sf00sqM+yek*!u-YH{ft|JKN~oYVh7=UR)u&4Dc9Vocal||oi5iHOWHN$@Z_L< zid#ZXz>`DXh9{2>oY%dDf~r#36LqNaiL^LxwLy%!aU=5)dl)sKza3WN;5yg~8QoH40OT*Uh^*noMnVrmmQ@PjiCJh%MSch;?ggrK+3W##~I96<|pmq+vl za$Zr2<>aFS*K`r0CNfsQ<2u|qn^HCuCb>dXx<+&3TpG_f&ZTQ=)?x?BT_m8FbZ$C6?k|^H3AH08H;F>MQ9!EixLZ|dK ztm+bS0eWa`b_=;YDH4)biVA73>!>5l()wrXiBKP_Cob0KaOhe(=eVc~Znw_6bF1B3 z++?-;q?@?6dXVOiL}Y#l*ATJ6R4Yk7wc&lRTacV#aZd0xBB$siywiQvj*&fXC&(_^ zo9&F(I@pBAr_x`FZxDiq2sE!7V=CnWZU)s8Y$B`>*N zs&CD=(ivSo+x3UkA<0~h{&^!|x2z4*wO z+_bIRI&@P1m!3mA*4ciwcKPzP<|kXs^EY2#xMA($9Ve%4+PDP#VgMm_H}DpMIv#=c z=_~9ac25Z4TmYwnqk^jPHs`K(wIa@M1)6Kr;s@# zUYcDhUo4ej5};kM(u)e^0+0vi^s6$A2i=xtts${gnq8tSB@$AV4?fu{CKB-=)v66s zo)S_5DDvMv9W|2Oz5O}!v&y+*xXt^rAGebvZtKpU!2$DM-z)4g|A^b4&2MY(DQ-63 z!i!3&b*)kSlRtFNV?9o#BQ|o_xFU8Pp0(iIf+@KBwRFH7FAX^=8vPrVF1_>+qq=;OtR&<~aivHW$;FlL{Hb!`tMtSk-)6pW zx0oPWCq#b(q7_gWJ*5}7W6XPk9%BEE^iPR6rLaU8AruP{FYC~BS!OsMcCSD%XXA;Y zF?KNt;n`7yXB|qM-NoQeW(%{EVVF#*)K}@1^5PYc2$e;3!j$qbM|PB}r89>rqJ%*M zQmPeaA>lzKsPMP5Z@W>sT)FTHZcE_V#}@9;o6qg*eAm2*zqxzz<9M$*o%!<{2`pAN zCq_I!|A}{p`b^u1b{bPHgFZ9_ZPMp*B8*2?8U=cY-%g{nQX-3#XB4tWJED=iR@8{g z;YJ~EFe36%E@q|Ce=CU%T%Ft7=)89t&sJJ$i5!&1Gxgg2*KVY((Fk-kj%&hd5+A;J@P)86y=TbG5L40Z5#gvPwYJA zW!~n~LX1huaS~5^?7sfx>&@L$PCf9$o=@?P$XrsujXbhmCL7TH%Dp#Dg^XnRR|Rh)J+~Ptb(zAq^hEXcb5=I ztLAQGi6;rm<;Wt4Deeza!xLv2m3Fl{R=Zjq*0GY% zVL*0eY=f~G>`e(ICR{1RTs64UVuLBzN(mSzU=kZ2q#a@|hjO_k1Oo9uhBW19!AT7y znNms#ByGr;OiB&IFfhYp+JYtb?Mf!3J6^vXS+<}4@B9A$-`CmEnW}4@3@@p=L&J&7 z@Q;)8+Lz|9^DLHzq|=!p$bAHmx>c zgC)y?TP(2J0)MhXiv({;@TL=37p(Jq<-uQgpv?;gFECU91S&xE^(qvjf}>JO=rkYz z5};c+CfpY&L6GYVO@_?|0;~?BS7vyx!w7+hA)scQs2Q zYM;;4ZoE>^;wz&(QJaWOBu*>*_)a7eh?H}pa#(MbxB`MTn4eafpygO=kp`3Mclxwv zyc`e8NAr70-H!ZMNY4!j(5+{&`^?O{Q@VN|O!n_m>Wpfp&kjR#7+OQ1_c%QGmmX*c!4B8k zF5K?=j|)HJf_WlLp`Z&N#JB@PKxSCP!wvpEk7w~!Jm&qZY{P*7&%~KBhFZ)FF_>rS zn4=8EFedkK;73hDCh*f?Pkb(&^y#q5Tu4(Y23C!>zaR9PyHnPP=I()_aeDLXt9olT zChrYLJ3KnHaQ*y&k5kDRJ*huKF`$|)_-3l_!|r(2lX-6UP3ue5!~UPikGgBNsJcug zDYlE~LcANzR>tU@c4x#%QM}D>i`yu(j+HGI#K}f%mJ!Qwh+@qFB(W<&;CXfdYPkX4;4Du^RFtyx|R zQyhY&xB=q{7(zHm;tM!YM4TP0k(p>8I*QIBnn!W6TtfXw$D?})vt-r^$2mC5UE=yV z%FmT?Gr7ea&1t8so;V@9zCPhG3zK73mrT2)qnunC7A1ptz@>lJ( z2fFLpHY_6wKAZYEokN$B$svlaD~<0&PDVb7Q1ipf!uW&W`5>+cRtND1zVkj@;j8xH zU-+7RxXH8GgXepedGKNPDfg#ts=?9jz^lbp5m#Ga8io!E)>0kRZHh95ytLO#vf2=1 zEu*+%4zHoxXiRf{q$if7*CUp-y240N?f!UpbfISZ4uho-jr51Did7-6`K@KvnO4dg zA0AeT&u5;9ki>9^XvEel6QtA#EX3~?kjzZH2#K`cRH{akP=SGQIPFBjs3xiA;Tc34 z@f|eetZcYe`QO2QocGgfzn?O9L)-n^t?N(BoY%GX59M=q@2q$ZkGS5skA15DwJl4w zH7#lCd$9G_ySLuiv-0IXe!748E9+LMF20iV(EFq=jVM=f>1CY`3^IqY3@owXD)I(0 zLqMEB&b34u^fL_-B)bzbH~s#jQ&h{~RVp^Pmk#&9gLmP>9`dWRhX&|2LMFNBs?s?( zRufwj8;H>rKB#3I*-b39oO_wu#U0^jxB0Lc-;!W_7PMyV$ihpqU&`K?P0d18sGiI| zi06gHLY>eg>=Seh@qWzn2C(T2emNM#PMN1h$qF_YTxPz|VD$SvVpPc0985tJgW{ej zGUgc-BgIq3NK~)r6@#fzKivJFku%W>o}>dgA+h*z7Hh){`Kj6j>Ove)GrdIG^D2QP zuX;S=iqdBkurY-pSu7jH!KI&{a17|0nnm%zxef`WAmThaP zd}C4lvdY$$B~@#=_Cg)b3DirrZZ5&ASc!bOtyGmvRD1E=@`^T zIJKE$5Yz^ZG^-YAJ02?p>5YRo@v-Erf=Te7`! zdL|;!YVBaPZq&+2(}Vs@n$wP!b}y(;Zrl#+tDUtC>!+oj$174_r+Tj(IrY2Ql}8SJ z3A%0&pTM=-c~_o}Zat8?n_APXjLMk=!n=^XadX~csQTi{vA!QKX!=Rs9^#=qshNA) z+?NG5<$@02a|bWS4GA-%7MjibyX=S0&oW zNKWa3MA-~tmWU^mi)+PCM5;sFDdO8A2{5;aM~fvQR-Z%itWcmLVTfVkE{-M?9i128m`YB)t# zM4h<)Et!Z7PfVhB)1T07lyN$V66He*?Gz?bpcDd>28qQC?u#Tn4*qSj03ql|r5%wRw^!OG*g5@hvEaa*YryMd7tTRO0UxU)oM%$ zxN0R-idQrWGIEi#HnQVu{162``=*rnq`&9R$Gn| zhDZt;M$Dv!>5vu6k(C!tx?#Nq4_PqA0*pYG zo1f?O80vQwwx$Do%AcEPLzoZ2E!=qycfrCJ#u^iN=inAbMIbGqJI`S~1ho()hy%U; zUiO*Rjx9TLNJk^^+=tmFQu0XlUbf?zUj-a#$^0AkXIBfPO+4*(x^Hx{SaVgP&7g`z zRcyT&mv0IfY)XcjFO^Eal}W#uYrZe_9_(J$u?&y@?Y$6kc~PhnlqWHm=4p~k1v$^7 zNs8C4cvT>Ta?Vsx<-EKuvNc)cRSd6JQ3Y`t5~tzc$53Jz<6Lx;FOU$|wH5LF+I*Q_JeWO|J#`R% zI`+M8?{X9)zn(Lxala9_{U}ar_AP(=`kiav_}zg&{bl2XJ9=IP zxo6u8-Q5SDWe*PgJv)$U*g`)Z=R zQug6TP|$8bfCTL-6ZYZgJZ4fepV)4Z^vH6(RVTK-Ur#%!Z)I~Y)`D8=udBl%aPQZR z|ENu`Y-8`xUmf@{Yenw1 zWS7t@>}&Yc_a`UC0;2~uvLPK^}=2cd{ecz}=W5cge-5YOS;%E2?$uAX3Ww_VAvnSLU zB72NZgG?o`k-`HW*zAQVI=GFg262VzLxiKSM@B~$Mpi}Ggb1jmc-&svRQgCMQ^TcD z81aQm!sEj;!{@@>OT%GiMe?W}VeSB?yqw`TWHlkh3d7|qRIpWW!i9l z)TcY&46b_Y?5VA*P5O_)ufZNTxclvYzI*)Rvm18){D)Vc zf9tXKCpM!3+@D?InvOUH(BZ64-fM-SK0G%}%rICXs1MBztqyGru>+w$hlm-1F3(X9 z(f!mfDvv~5ZpaJTy3Sx0Yh;9hz0JSdPyDZ=pOV($>e0gTFQOp!XR0QZIhk5nle2`G zc(1?C(F+HGmCm4cmDv^Leo=Z&ehjxLZURg&ju&)I@9F8dmVM(;&+iYyjNaGaXOT?z z_a4q>);G6q{?`U9X6wMJws(&Im+q>MZQ?$|zmN0X+0NN#UlKd#i|va)LK1>qY=@B& zatRPh3Q2$g0hDH_EQJIJ=~BwarlAP}l(tIS42IZBfR2_@+Dv>1^2h4XkoAwTX41qq zO>F;EEnAhXf=+8GarXYs4j+@2Se9cYk>B@u-sc0?uyH#&?){USle{vRxpU{ucj5Ca z1h$LH78dtYFKfyHnZ7c+&{AB#K70M^wk|rP4`z)?AhCO?%l0> zA)q4gAEN)Yi5xA= z$G7 zE;@?CIf3v)97ux_&T@JpLga5EMq*GTNR-96NJWvE5||OoUp={1F$T>xAFvQJc(E{? zO;=1QfJl#pS!Rw^iJ)Tc<{_)*RB?e%x9@tt^WywPr_I#W8Z7Sp71p{_SLQwa`anzF zyvCzHTUtYWnUk+J^i6)t&pOe#5`tJ+c>O<4W&XYQ=-}3a{V$w2)w%z0H`~>lnGt9! z!$?7X^nua4*}uzAHhFe>NS_-=UHE{6qj{KF8&N`}f@=uzcug&b6Hm4dNCD2IaiQD;!pxFE8~&=$*KfW0lWrMbTvNBm<6tbpsB7wT?jEox zfqrNFDE=KtHc#2H-Hum#@Zu7DNW>e}UUi>J`9NWyFF=LWTQ&M5P94htww> zkt~uw%0~;MgpXE5&qOar$D$UoGrBuUDxx^bc?T_JYD-jt4Mn9gchso| zbfQo_F>OgMW=Sb;w5Tkr#n@EhKTJHh#hc8B%+N3~3iN|#_gpjP%M)!Z0x`n4J{6Pj9|vytCaSk>>b?5|Uww5f(Y$kRMdot{_H-pj zH+27gTdX{;*1vMJP7hZ!H*AA_H&5NBBcSSK=o_Q9bH?r&)f1^8e-e!+!z=i#-&X5r5QwF^E0R86DAN)g5`i+E+~OT%!ulA@;nRR5)ZNvBc0 zN?)zhBl;PAOsB2-PW_-xbrNu6x2$;tR3?|fUze3?#4hR~N7!fh*xDUX{E!b9QD52g z?H34g5>>dvN+|5)10a*_JSXr#;z!XKYiDw2zRY0)Z@_aK1EmKrsmRJewt_wQ!bA^d zVVPsX0*7B(Wop9zfL=Yi0P>)D#*(h&yE&CWX*6km;|> z$$emc5sIQtqi!*WtL^LTo%Y>!u3B0rbxOM>F6CO~B35T85Q>GGLtLoXi9H%*#2N00 zfK*uxs)ou5RAph^EK*7`FJ^A!7Gvu8GT0SMP`7Tj-N<<=&bq0~Oy{g>78YdV!W^6g z353Z_Hj?`bmmH~2L>gMYziH`#W41!Dfy_(Q@pv_uvtP?>R5mt!#HAx!nwvJCJN|7= zXLy-|FP>F9zcOa%es4E`DH?a)S!k}OFC&SZKhPBlp+T*eEy^peFCA02H_tn zRtL)hP&F~Av^VyU@@P5*)S5K_Gt&<}>iXPp#&_-764f;M`E-*-x_8$inNTuEx0@(U z-61=Gg(38YQSS*_t!G`6a9G4B56J*(iP!J~n9@>ru(GVI(q8*x@tKXG&jk~yNH3zwW;kjNBsF9A@$?g}*lY&~nvTNa;(&$M zS}4ghps1=+1fv7AA7!J<_76i-ORjrfC(!+|zb4D_on`;=e(rg`KQ_dOr&sGF6__5_ z9iX>3MEPXCozoWbLqaNS2&YmJ;-)lE)>S-HL97a>P?DKC3JQe)tqg@rhltoM0j< z&mW8e_hQ}-?|JWl#|OPnyuWxf25b>@0NKfK0=i;Ek3o!K8S!GVH2xoA0u+JQj7J&c zTo+*mG1M847&`V+8i+AZfz|vez7q$9gJjadd--wBxiBG(T~1*TV604vQNpZ4DH3w5 z3)oAf%c3ZWCfP`anv241vhgKjBqqpx0ne(HQBoNXoKnCrBozvn9wyn4DMjuvM6MHe zv$H@=jlOrz-&^BM$jsf`dS-9S+=m`Lv3!2ZYAEMt@0}U_DcMTqHan@7&fT+Ww)p?v z{p_wTI4Mb0`pa=YhEc~(RCTzZ zxe#!XMt(e1<1Ca~?1;R><33>FeVweWeSv{MDPNDt8>l5qnsPq{&Vq(98l_CakF3}} z|Iu21&bKG$f8Lmj&Y8BQ-p(+c`diQaVfuu04a}&XK6k@5zJA{$+rON5a^BnV|b${?7`1BRB;i9#%bWiHN$mC8Xtvq;FWZ7KT+&1tk9+0xMI z0*sKH=`}{k1VTuiET=_JnwHFPo;5rqWNu4*cXUuDx6$I-v5Bf%moFAkV2VY_Z{Mzg zeFKPXpaiW@SveC>S>!tgl`*_vr@rif7yKP?7k+Z@5=;2o;Kb-{e;a-4mvE~S{?Xs> zi%wt2IjL3@I?OVt-k;`rHikh9yJ4b*QU4$qwna#kP~d0P7>Y<(<+VA>rV6td5eUP8 zP}(hTycU85A<#opL&rnE3o-1lAx$sGHakq9n#?Az5W0x85;BKCg47Uln|whCC0Nlw zB^h#z3=u}6s6hAwutVhy_B}9kkuFHUHUG5X0inf(p%zWR!|%Ag$Gn3}Lk$u$vHAp)ghk z8gQQ4+Dg^7Z4kSy#B`rezMx3uE=XBgo3E0VHE}Yg!f~e>qZb40yXXy)$&<;zKVU>)Uey`cA@ioVBR4`H-YHV?19ZA(;D> z&XFG5&w3ec1;{2AB)Sp@6D%8t76+IEcN}PP_B*`}UF<+h8T`V67Gt$R)*GG1%LYBG zpVvu1hk#|6M%uQbwk1-AVp}#zqhZ@&`o4M1Byn`SE)1AfDom1IisEwH>+EiuJY~aF z)MjGXaKXN2e{NITj3m=aE`pIlHafYbN`)ECXt{_sLBp@KoEdG@uukB(l>+AgOhB{0 zfOYBX8{FLgi#1o-B(lga>eS=ad^V>G09vGigDDVel_R2#BVy$a%3a(rs8CIK#I$Nd zYGp+^jR?az?3{4O9A~jZ3@7Q301mT595YfmSti7K1)GeF`ot`o+^j9t)@f9$%VU1R z*dU1&&^O!0t7`M;himhLB`=l4tTAK?{-V^=+A#h~RujjYYKhgvDG(cv_+xItEXViH zU4Q9Ed)nXiyK$eFW)Hx!{NX2_T=sbP&c*W`t9aw^p&OU>c7&k4y+`$r_N{2`dwFBw zvBkTPTJt!yI#6=cHt8KWVnHuLdt>b%1L`R~1Z_W|tPC;NikWiN1HQ*ybaXL|nnHrzfR4bD)q_%Z*rk1AD>1ZE`I?hg#v27kLOV59IwYJ>3 zyIlDHbMF70bH4K(KMeT~`{^@I_?r`YoP$of&pGO(PQRnY0XH4s@MTMK5T^*yS6U*I z((FRH#@J$PGjc|Tt2B{dvUDPWnWqEG_!9FC)rd+w*jEyXYBnLUj>2*=@i8uJR*9a$ zrBVD_3x)((+ZIw?I0ZId@feaonm&;RTsSwf>k;Jh_jG@9Zqxn)v2R{|?CInH)FY)f zVF>!)nZJB%)73rBl}mrHVr$E4^O|=T&C?dXx4+gmGcQ|?FFObojAc(qB{N>#URPCK zU{n{>6$VSIT3IGPj$K+rB~t_i+V9W$LGZi$w8&HKp&J}M4!RjBmi|EiCeh9d9Ll*r z^7r_E@!Z?|F`gFju$hNY)C8s*;Wi@}jnL)lcTuY===#FNi7vb91tk}Z7tC-$gg$Yv zNX^*(#`7lf=yv@0Jnx@*{G7bQd1v#+^Z4z-p&$+BDHg@As0#O-vO_th{9O69A{;gaXA&m_OZ#1F-5v0)Yg;#e-qAkC^}noHe`#lL_mY=4WY#~$;?y{Gn-3$qhe^Ly zX9&4NouTa^UOej8yM2oR(f>8)lO!|XPwH<5#V<3Vv zmCD%9(xVr{By5W?3b8R%`0)B&_dn`-&2iB&YyQT8#q|x1yOVb>a=nw^^jvvmD||Kn znba{Kgr}?ySL9EW#;%oD9?1Nf;Q%n!|+`QMNx($*T5-AZ| z#kJx#k#~q7nghJWmroqmkzpM!Pga^@HNumiOUySgSddmP{}+ztb_B$h8c#aXRgQSE zd}%>=*pS+;gA?K&w0ee2B#jIL!#)4fs&|uv(?;EWOB-j*Z25lA=}|5t*)XwuFO(m8 zwjQ38TRUS_jayYe>>eCUepkML<${cu3<>*4Avv#g2?`RUo5DWJsD-X5g!P5ph18ZW z3o?8r|3jumxk`RYULyZe{!}&`kzua9QSOzw&GPFqHOU|zkbf#unGa^G0l&|KzyK#Y z^oDFgL;|_Ne9h~2Yfe|p?KWgSY&=CI8?r^2!J@Ytgn<>A&r>^jb&SD-NOaVcmyfZW zVWq~3twTzrstF770Wc46VOKmJiI>|dZCFE$`Pjt`?btM$+&KMY@b9fpEUXQ#KJmm0 z-QB0ooGH&)^y%Z>Q1z4MdT0#%NiJUUv?BS7qqQTu-UM+~a_5_y=jXfK(;^E9CB4ZP z_%J_%NSH^vwERsueK~X@8#bc^q6RC>;b0Dh2>@R}vl_lIP?0lO&Q0AqVi)M^mM+ZTRPt0diNECa85iBC_c4KP|a(IQb$BvU?bYk}F{d4kcUQ&{1$5g{#T(qse<@YKnY-uiP(u zNZnZb?D+s8=8a+jslbXOq>@Y*KEV~)fR%7f``;iHEhnjd;V@+Z?yaAnLxP>hGl zkP=In@sQf8_NyZ*uL2oCh&d=dPxJoQxNdvS)E#4$ZhLOZHoq)ooBs@-XK9ad!Lph% zN*-Dcsx@khdQIioR~I@tt_tWxvSP#de<$ti2+YgS)NSz=_NNLwDYIV8ccJytvnIC} z$w^|b?-b*8Qj63kZIec%G3k~hN(As9C&f7SXceug@n(kiP_n_0^N6il{;y~&U$asO z*)f|(>|ffcUEg~~jE_L7#p`bqXZv4EHgHybe_d)n{0{f$Xc-iu=>E9Gr5zg|I8N<* zXX>^|(f5_6&cLETY?=w`oVQRWV(pZ$#roQ0g9wkTt<~2$G&3I79d%>wq!;U}dy@^q z0ey8t`a~E564YE2NTepBMYw3BEz%!39^oVDjqEI#GmTSscm0pgK7ny22=>Jf+sM9$;ktpTT)gWT`2q>JpVk~i52 zCZMV*IHW6Ms9D@~QYnKGem8Y!WEJAC0Mu z!Ak(eT3T9geT#WUj{(vl@lRmW!Rq8Ny3fw)3c8QCqNnvb9_j7zWE)2Y;zRL~_|5pe zxPaozLZLQ3tz(y-)H6DzsU(G}Y67h4AP6S@Btk!tFD4_A8E@lp9HL-u$0Zr7aTj3!o znuv%_^!*1kqNldOW7%?eG&IAbstz8(GI)4=@US|xdj!V_-c2x}8-dx+{Gu9W>fQX? zB{jz!wI#wqf5v3`A>l9X+b3SwVVr*H^Jt5g3Gf*z((M4Y&kJC4P&+Xb z>i>oG2Y~d_SxAF~|57rZXd`jfWZgau#S;KCmri0Aw9-tHOOgcR+~qCl1XdGzqAM|w z7)oRkHxrU8kxXn(>}J2-OGt?v)+W^T6lvH4aI!QY4#OS>%v0tvxC<3S{mMR{$J0iz zFVEGCMLV*$#XktWuztu~Pre9yFVhvSw{vsn#ZC@&u4-*)<8bGB@}_CFr3IpF%KlA^ zKC(Q^{!-D;SCy6NKEIX) z?T_4HHQX5Hj)YH!hr?Vr9Eg;aSEMRPMFsD2mOE3(H7VLsaFGj1Fi5oUjWiDO5>t^FY#vGu`v4PhA*32bP z$8KoKu#O7BdTi1Gn;+nJTv^0N)Y=-wjUp;Y&xk6CirZftp@T16x)#>M#mIW&LnC9H zedjHF5Puop?i=ngUNb&D^uqqbnBVyAT`P^%c-UA?Hm%1EU;k+G67I%5c*t1Uh+EGN z8lM^e8hp8~zGKg!Ul_jwUJV+n`5NHWO6V~U&m$2;UO5P9Yt4xo;@}tg77<4@93@V^ zOsokn2o%8`^r!s2e(s|G zkNz9}te;mwY_nUO8_O=6sBhWY)H9J|-ie9kX804JAERgo15@a#@jH?$aNrX;s&6IcPP+Oa4W~xR(j>AaH*qVhHCo-|$>*|bv`u6Xay zOQ$jCvEZE}Q{UaTb=UPboCRgpZ-aw1GH%|C8-cq8Bm6l5rrSi-ae-&gurgxGrQT6^SU1) z?o;Mn#20X-?m~w_38uWL7$8ySpZ4S6AwW-C$|+j(HpB)F$Ec>dGz2C!g;NF&&z=Hy zh|u+R7pyNvH~Q(_z`p$5fM(@%ft7FG-C+8kskd4dhv|P*swGS&L)rdp>~Oexmtq5mh#3u1hxnidwS=@1OI8%$K{%(AJO)7j?N%pvq^6Gc+e zVAe{*42rPZSF*RI4D7HJ4eA^A5xj$7ix?0Wh{wgVqF{-NI3!}J$X`@j#C=wTtpV&R zv)LSSP*fbm54uvexGgG`rHvp=`@Dja^LpiyYS5Z`ZM}xjJwzlFcG*=VH_9V&MxK-f ziwr~GG%(uN@@>b|nA3Fpy9=OMmdmukhH_@9h5mH>W_}tQ20KK10_1=fU9>Y1~epr8@j)#&i4$;WCmz ziT_+*wBCug%X?(vmuuxO$lOtax$Phs%JdkYSoKu(&l2k`k<1 zXKpvO$wjUxL{5#n3$;6i z5PzFxxFDC|28dHar&OfK5C{{Z%tT`ObV95$md~T}^NCbKmC<}E=H`=&Q&EVMB5&mR zz{A2|&zyYB7-NMPDW-H;{#7gluA0ND2cbMVSsn|`J)t|`KQv14SoU4rYURyTtg})9 zD_}KJ%`$mEXEgy)OskLQSXIneAs(!rV7ZvFQg~rL7aOy{w%NI4|4VlHz&3GTar}P2 zJNsfXj33{$pGMj4g^?%FGV{7P96%&7E&O>KrDT%t+CrAeKc~nUWs6HkbxfYXT zXfYZo6EY?7K+MKUO$LLp#Z=Dfu$!TwzBAf-UUFzKXDh&()B{W_97-Gd%eMeN-s?z zfj7Cm4n$K%yE_SNc&96-IATsGr647V&&GnZcfZ4>IGiy>L9A#jwV3qwJesqJ1@)qj z^1X`?5~M;NO|piC#)T|2v3^1Y7WeuI810VPtS#>M^MbZ`)X#C+;=f?5CyTo=hs6Rb zOo*`p!9}qib{|W#=Wzw)LpARY0kr#BXmH&h6H|anjE{}o7NaogY2b+Tft%CtQsfVA zN)hrCWetVIkBA^B%mqOd06|m$Q{5bp1O--`9R!iaRZqZTQCSjQ-CDMNd*7KeIigV@&e-aQisUMN%2;bgLIgKy!icG%)3(2(Pxj@;DWVrI%I zIv_5Bd z4%RtkC$3kK(TGZnsN0BCV{QkJcsIu}Hpv~3k(^8G+>FJ@+Et`d=75V0P?Sh{D4L}_ zqU@2e%urkfhYcLarorL3cx`1o^>NA?id#bjTqu#MB9bv7MI!M;TfDMDQ;vxQe1O0L z9kmj~lTNP-`>oYQ*{?u>4={PFa_x|ac6vO0WiY)NA8Y7Kzk-j&>ek;}+jRnkFK*h} z-Hq0yN3L~mJ#`6ncQtkGf$z;58^{K1XZR)R8y@63F$?r1yvr^Mx;HxQ*-(GFUKeV^ox7%rZ zuC7r)LJ){m#S`LiR%sG$KqN~pRTa;wO@+wth{lQlYy;7mh?f@H2sSvT;S4yk$bj=$ z3AWkkiC?Av^mXf{=eMN~BfMhtvwaPJSO?Xur?s{ByWcEZdE}XSKRdp$cFF1^b+gwT z|LWv|$#l=*juxngN1@YXxQ{KhiWT6Rh^0Y%xJ8|*$Ht3>|y3}PR)FK zolZ=2fb+3-Bu$Jun*NCnK}O5ei?N#J2DDQ+BpefHgP?a?XbzhU$gGoOsZeT>)=D~7 zG9u4=)L)?N^H`=$B6~P-s&#h>G<-4Hn{Bu8;zi|C)eWc2-oV>$y!khW2YHBpLpA8{> z5dA2)E{M;1hrRfW{Gp83ggQg`$E6*mcui4f5#H%X{pyg4i`4I__#MX|9oS@^XU0D@ zuQ&h8{Lsuqc+|_E;IH#v@(*}jmk|}1O58S^ixF2@UbkRNP^ncK6569W;*`DIk;wJO*S4##2{P+Ht!=s!)WKr^_U9ZX~WHMzuLD63I?#xee*3eFJkdu9Z&2#o_c-$ybaGa zpWgDG%MwX{+*7|`L4D7`mztVhnj&2cq`g!*bvbt65Jqq7QJo1jo6y@P)NB6I{J=~* z#a{7*I3P0iyhC}%^3LWlhupW_<8Jyb?;S4=_|Y%?-G02TcxN$QTe_nZuP@(Sjy-%J z&u(`yl45nCvOI?St#netB~Y{R0p*B-14@m870F@q@RY&fSA8&wc&G|e-GVm1WtJa6 z=WDG0A9h3o3cLqz3_eLaK1CaLAHge0QMY47N6uSdOb|>wk>00 zTeiKhXvCqk)ATnXg17tmy1K<(>A#ZmRWhkEr$MX8)Vf#$%OQh^c&ljjaJ-GBQ1qn}#YYs6;|Xq=c4R-Y_Bp1ChGUoX+VrHx{%$`i9>1=rZ#^wyOoU zsp|~ibI$dB_}acVzJA1xeQ&N~#~3ShYCA6|_=W-_r4UMaENmeW9jr`c#Jno9$Ho>dDT7YiKw~YfGPI?UnpR^QE0x&Ft0hv^4pqvC5TdFUC;QK}!xo0D{P&>~ z`<(Cp|L_04;6xYBytRDCnwEu;dVQHsJj=G7KK<{3coRLttf?@$#8xu_X2@Lkn&X56 zA5(v&;x&Oyfn5ROP~B>*c$|%HR3r<+xNF^A?jASGyB)5isc;NdFb1n&m&%jrtSsqL zN+Nz%QoTvjZinxX+?1*`hd1lCnZ+4*kzqx`RLGJ9;w7s~NJ_!TDp%m#z{SA}BS|{= zo0#%ka9QE~5qOtm$`yLGUR+oYaNL6ewcm#YS7o75pP|G=E*0@8T*N1SR6p5DzEfEF z`hxC1F3#VBUxzJwI`!YU4}&Us$5lT6{!ML)5@p7U;hIzRT=QO zzJ1$Rz6@UH^7q3G0fFkE%7ao`5(v%kSrfsJZ4bb|Iu0b)P)}=`uP!nh&uVDmrug`p zqkmq0?#apb)EPO6pWE5H=fL=v`?`l5jca=Mt!fpqSE=ml+;Y`F`4>GmBTEO|dk!Of z_t?o_9DVWNqfdWx^?vH!o&qoV37>)5PSe`9IY=ec_B=BQc8iG`gfz3{R&*+gqdg0z zvQabE48dLo0fY&*Vw6cG>!|c^ucI!n=usC!&&0Wp;ColX_cbstF}JPWxy;-~+nCj+ z#xjvu&}fEV2^uWh%yveQ9LYt7BP2qwVe!eLI>x9qIt@~3n8pg@urXi^8>0qq!VUCi z3Mc}84ldTuTK;mfV7rVU#|#11zWugKv3s+&!Ku-+d?3qshlmdtm_?Kr9mMyhvjn97eQ#41L2_zglGanP=nz1K;WI(ag0*RgZYJm@u*^s*`(@${R6vS*Q zo{M+H2@|h`vLHZrDVp&1AGNbGi1FQvQ9eFNKWU{t?7<* zfBLuS;WVGd36pnZ^+YOx&BWmZ?nv|}aH5p$QnI1cruS>{c)G;nf1T#>kPchKC^Un| ztsPoCzOuyQ*I}pD`d}D#gHiAviP!x<9^56XH*`}axXVC{QG~&uJz&rtpkO>0i>rV| z(>*LU{*Gw0z$1L!s5Y))Ml*up=F%oer-5W62bE3?9Hz^ni|RVVs4{GZSA-9T2g1YQ z(J(KEbK$Mwz1HJ+m=E8NPtw{42a|3wHw625q?ilzH0mgN5vPJA@D$D&2pQn_{$=Zc z_1`Y#Zm5V5Vk$IAh4mG`$M2Qa1KY2Kb0#ddpUYe`ckDz5p!o>Y3;#h?VE!7TyQ z7T6s4IzYrgAdm>053u6pYQ!h}iFks%F&hbu<&Co%iKMuZ+s|g9HL{_&&;WB#@C(>= zUbsT%B61T!@IM@*q#fa0A;08~smW=R7!jeFpr_}>giK7UibV!Abf$=GrFKyp)mV+f z^N%s5Fq~07$d@eRr7_Cl)baq2Lt6n+=g0EO2%V4?XHyYE$EPJli=Syp-{9wp>J;>; z#oig8zsTIvn$!#Kl784k&zvQhE!Q@o%%Vek9x=5usdqOYDzqnL5s9fkgoJlK>f5ko z_|c|yH=YP@7+Dwnh8`fU{J`&TzE{n?Ty z`c~Ie|9W2cf>|M_QCl;7{sF9rsK`} z*E$v}(A^63l^=;dw9U8AhlwbnUE)CzJMD;H!yV*~a$j&P=G+{1u`=fxgjv2?lC!GI z8vqxR;#Z{J-a0SM5G174uYyz^EAy=%G>1U|fWMw7=mk+_#+GOSyg9RoMh`uX) zDBKW;F64w(fq+HGTLvM&tuQjoluT%nfs{~r2v5L%IY>$|NA39zY7_DnEgDsIB|l~j zP8izvc`q`0cEj0gJ=?Ere(wGJ@#DGWKRMdclw1DeSC-Dp_rBHt8ESjJ`HhzfqbGN~ z^1?GGj&JS#;rA$#2cfdH5|Ss(AK1#_;0_wJT0pT4qusa{qgKY}NZlIVHFc@rXLI|b4Q4B5wD9sNX2%SKivD27z z$P97XP$(%A_|XR3hCpUg(ohinRx1x7nQ2GTuB3n8v*$hUIf+!9%oaL`WLt7(2!+m~ zLZ9QY5XVZWx3T#eW^uUTJje}`&qluA-CbESy=-sy+!B=fw?n7e8>q}zj>Y4fe|25m8xkxlH1E=#bm^7ta_-?DTdwWtZ9T6dEhtyVXw=$QXEeiZSS z`jM#EA>HLu#xt3wK;pn0=TfvG0`x=Ym^9b_JamH|u?$5RpX9L*O7}Lt@zI^Prp)QuH+M#O(caFAD9RW;_-5Y@s{3Hs z04Pa%+#HDBzgSrtG0%X!fG&)bi2^w~o zJI%;sm8|F`>n@GWc*$%b#COewMRdbyjIY(R~qF;;f2N6sXFymd23=t_L&pW6@ zDVT2K!v>KkJCCLN*#Y*h4u?un9E=5%v|)%J5;q7EgJem<&1wv<2~iS3Fm^c*%LmBB1N1!I-ARHD*A?X;duq34B^Q;}`YPiEGxty5`SMeWtuI z;Zq32KNu=FIRjR{x@KK*1aV*P>%Vl$75@r)pzDeU=0#_1-l{8S-lHD!8fKMBWD?iT z5|&3dqMdd=T!Vn6WD2dI)>CLF)59P)6J(IdCfU$E8_c#>*;m-fTA@imbEG9wokUvP z9d7jZR5+RnMX69DK&b?hpm2;iUGphsvr+J$930c+1EjKeFymyGo$TvsO>w&WwjSc+JNMdUS{apE6jzx{h~Hmp2xcwOd< zru6bPH(zXrmFw#}_Rpz}wV=;ESK@VBmwy<4xolS1lw~yqKic;R)Hg>ToUeYfxC~RB z9iLCVi@T+l$R$S3kUqs94(k41j0bUNPEXFQ9I`d5D+{$v=$?R(CTgfXtvBsz+GyI> zX>^t(el3rKL2iV*&XFot!c}rhIf~QKC7pfv;m|Nqaxvju zu~^9yroPl@NcvQR;pUUZcB^6QLZM*HF?@Th-?rMy6h>Yx!;6X^T{$ z7RC2ZEkDqWoxY;;=X0jVf9PnOe`@Gp>Gw8n`6a|Up7|L{xi75Bn43bHUSG3&XWh~M z`nKj;oh|md``GJJi5%j}84qt2!dW`o5}j?RCv+=Bwg$Qas7>qE5XulUP`j_!chxuQ z``Sle@LctbddN2JCWmOw$?1rBjM!|E#}NDEbVXt!A*iuzu%M|H2w8%P%}OfZwa6GT zdx$;B4zd)-=CQ_>q&fBui?AzZYI!0IiX-B6kyOPJu~J+rQsNVchyOofopI7Ag^X`u zo)pH{?;yU9?Q(IN_jvX2W5^u`%Hw_CBuu~4X9;La{3W*v zX-0R+NsJ}DmT6`X!Kw@I2Y-MHcm-Zn@jaVY$ML*6n}@YjGtPNb zCUu$ml%kj>s+~dso>D1i2#efO>8f`j&ZWAR;xClTskoVtVzCM?zjjA`q$1TzQ9P07 z(&T`q^1vqm@=*USOZ3QQ4n1bJy*xt`0Tb#!)?K-iX(T- zumLG)r8>$92F2tunyfD*%sGwL?>>5Tef7Cqv~kB5|J=47&;zols_Xr^=VGw_U#&CL z11>w~nwY!!;o*n<%+nQnp%@NC?xp&^>N$F(^9$bB=~%e>V;3y$DgA-Ez04Dw-q`i* z3VqX;;!WR#iHC^4L^n|~mYR)ct>KQ~{vdizgxzAFh+c&4fMx@{2f(_O0Tomg4GJRy z$`gRVyT_rVFuoA*Azx^1XedN+A-t?Z0VRs8EX!EK6)dn8k4GYe3w-DTk;t1b5NnBM zqMu;QB#|p=mZ(J+s?(bhwrJX*X~cBhM5?9|Q>BSC>Ct&Ox$ODNSdbV!UQ&5tq(L8k zoSujE(QnWnK;j9+ZbuRs3KtvQ3Q(HC*O05vp<4qUeT>!RG-Ug@@{mna;+@CqHui6> zU(p2x^Io6cQ@(s=L9oGRUZKngX3m^ewfvcx5@g5UF01N4Q&q8T-{Sf4KP#sfm4&M; zEbIo_UYPsTf^hz{$THkE3ozg1)Kf@8%Ltt}{!QC4?_#i=C2}9#I*nmlbmM#;qbCEB zI~*V(VlTC$^*l%ccqj130BQ(q4WJ+MEj-GnLPZFLY$jEC)zj}m9*>R7f|FT;S%}C2 zbCzETF>5&>xOvf) z9oxf|Ld6wAF=-$+sY97?gn>W;O*{s|UCgwF6q-UCmEaz!re&O_Eo1)3xIo&0PNyj} zcu0qT($<#yy_MX+kWQsH)-fy3e#h^^7$aCNkAJ4m#Yr?-z+##_x!9VYzquUNmP2`@ z(bQ&IVd6}le8N2HN^38=u-jHMj?PJ9#UGLqxr7F}66r&yj!!k}{IBm~lQ1B_%-2U< zjFG=&E^I7}xzlrT833uRHT*?acNZIwfdtONr?J53#h67^G>wNUBVyvG$FX5{^gR21 zlz*vz%lfmaL$U9B_O4n|KVx=f@g`gDdUZ~bwyO0=!})foIJYX2-Jih-om30zOY;{0 zq^OUAQGLt8cLPuwpIV=5AcgVLY@FgCPE8>t`g9{*f#z#q6IpD!H9msE6U==cdo z5D7Zr5Cczy^Ld@uMQ5~;hafVw%NOu?Ou>M_7b2%m(DO(wl*PLr#zObVM@T=|^9*0Z za^}@0f&+1-Rgbk6(^96J>0W*j9|yNQclIx-k?+3to5O22Z0k>qdkeNlzq-2R^n#|Z z#9v=hKNE^suYw>#;Tt_2OAhR8UHrozVZYS8uQe~)@%8h+e|CK&N??2-)j_QXz1Njo1TlFR1B$Jv!6RQ zx|U6FW~#$%M$c19>d5c_DIdS4ccI<69)o9UHr3GUQ=ztaUU6qJ*XjGFk8*($QeD_o zxVVs;S{Mmv{IuBI*wZm?oqw~R#{BdBOZ{BTKP`}Bk0`qGg0e&DRjw(w6<+ZMoD#7< zQRvqsYa2QnPD1kItPQG$7cz7y-_ti{37SB^A?z0DJSTKIVS)UNOsnN4nJ!e;DAa~m6(eYQC$+BSy+gQ@+1QJ_h!%-tLy=x{LjbGb6X<2(bAfK*U*~BPznD*F z#~$;mW_kuL!7zLRCWH`Bo|6E5x05Z^!J=u=kDYML3Dr(`8}0ygQiojv>TnZP5#2;k zM7!jmRKpL7B1(3<<|b~pn~W+j>ITK_qjn3C9HPaCNOcpBB2psT#WJ)y9*-z#C&&-T zDB*69y9DO|5geW0p=}Z$h_p#OBYq-sEZJTX2St-r6JebQB5pF{BJ3`UkBq$r<3_qP z{;)PDlS#~)c)GgwnB~%~@|8V4<3+*;GfZ79cBV}zDurq7P39A ztl;jZdS=vpe4}ngs^<#iL;iz2Ny@8;m^zClBcduo4ANT6mQhMg!0e@RK+~#j( z%#e+4eHb?|h`TkcNBAHt&4H4fSk7;AxJB8ZWrNiVcC$OnO=a#)^C>fxkO`@33HuPc ze&(|?ulkbQ!l>?V_tV4vvwj+uEq;?)1Q&2weViJY?6VXF1mUpdEbg8Kc$=IpQyDMf zY>sfj?`$C1z?OT(0T@{oM?ryy?JkXxQV%lY@;H+GRou$qt8t@?-rD8pG2=!X$CC1& z;z`4HGV0F|<_hBi>{&d`4BQuu;|wijWZm2*>mv8)a4U>p_?~DeJ5b~kcPI~XWkq#0 zzTxgAwk7}BUXZxm{;m2%s*}3l6DOH{#{2-bafZ zyMpV<*fd=y`aQyGH9sQb|F7=KnQzUTomU-f_1M3(1F>H}wMISad@6rE9sZxaK$K%c z&Y6FT>LHOXJto;p%{H6J!!}Ap3vXX3fg}Z`GKu3QC$VTcVsXZH8*EH3Vy=zjIU7!# z=W%H-p_Ar$m(0`x-O9D3Pab4|>s}t8gj<+ob{7k8G~^`7))LUGs9`KI<5{3Sk=U>y zv2kN!gXzrz-R`oCQO)b{Qu<<+?q;g zNF+=JsH~aaQ4e2dC@Vhbx3S`E64&c|zDQMcnscsmuam2WCKQsv|FB;5u}z$3{C(d$ zzjywKefHVsvwiVLY{yAVArKqL(3%^hqA7yFQVmh&hI9}{VP)w^TiTUI<*R8~Ss|1G zT2o-9tE!5sbwxq#aJz(UmFO~&MPd_6rLG-xbIG)-f(bi&-aDJF(z-vUoz9onmne6? z=Xu`W2S|yzt1BeDyX(#;u>U2I5_q-IH%ctPS_H9WAt9dWiA zlC--JCvi~@4jK7nVb*!+91v!%P%wNXgK()JP28PhFP&!g*ysk3VT;j_ST{$U{-FdD1jPHZyQvCgHOM3UCBW5)Wx$0vSk*o$mGY5iKjc1`&G3Z%~JLbb+Yx&M6 zfApvFrbYRt>w8x&@A>xO9A184Zh0b~Czr~5-*|AKXY$}-JX?CDZ~f5lsym1A-SoyL z%bD_~2g`#sTeq`b?wGzzf9vFe+Wdi6&YZ#P$i>ok-e{@Kt$2!TC@q`%>C$IN%D`OS@IPaA z{$DT`z8Z5yxc?jG{N}=czzljm`!e!z|Q%b5n#ibx#sBP+5byB^mTH4fZb+5`H z6|3qkGYrH4a!zi%+T_xx;nb?AO~C)Agn$mlJjDV9Q$jPy!L%DX2wB5T>#IsQZ=TgX zZ|1G#8z%P36yVz{O1NYn`Q7T&qIhljSHQBbu^N;v^7U*i%102MK4B&>n1C(%3PJJ* zGbc2BPMgp^);Non)Up~U4DyHgmw0ZF!z$H+f6XL8bokxOzl zyExIsfR(DSM!vuWB;LnxrK?!->kVe7@1d}usyi|ad2yue9y@)Xu%*+cX8&&(yDW)Wecx;>! z-^@?(yvQ@_e1B;)XS%e}95bUViS0JI7yUw_-$CkD#TMYje=5; zc(`DY_i7Fy4DMbEB#@4n(@8XB*iSuRt;wLc8cc|~s3&G*B4V4^DRzszI4f6C(^2VM zy1HarjO9$w66QBq7GMYbUJ}giNQOUA1h&&)iwTyPVzLaMn(E*4*^Y;QHaPm%-H)Ah zFI=^2_o{_%a&PGwv7>8ff7k7#uDoaGH-?9<;ndR)9NG7ifhFtKEg2X(vgW?cYna1? zicl9+L_;&Mpf9wh18Kr8*V9~G!<+^}8 zEQ*XhZ%+SOU!nvv#N+YQc{nHUQPMJvX}VJ&^VxkBG@69c*w&~~d#wj2b$>L}9QuCf z)leZc7NP?%#vvODV1WzxkWtWDt1|=Rp>SwsGHKIoMp12TwoY5Ojki^cS~UD@8mrRC z2rLZ#E*RF}e)m^j5Q{_hdT6q~Rmbw>rJ$JP0w%fXn9{Xnd4;I$P zp%K@Hh8ybVZaPr@V1M}(-f?2nwtqd+zz$$l9(8@8B%XzH{N!@jV}Yxaatc)-98- zH?}^ur8SNJGXBKzt5=UdF^*$L4;(mJ9{=>A_3Iz{bXU&+zOTRk>D=~#9%KKOH}G}f zC4DH2Qjmxi8_w~&R^SVT^b#%@)jTdC6w!FW06Rd$zb+x_R1(i4EFlash&&-nlDZ;L zhm&@!+cC0Z!5#&wp^XiO^o_#^^cCGLEmCRDobf(W?%PI7qwHf!AA>Hi)L@RrzgVx< z*eK2``aNcMb{@MkJ3F%v@7TNEmmdo?vB$=C3Z6O^4#f_{DFj0dDZ(URQdkox4NXFX zf=i1iY7+!WTo;!@e^nH_QLL(!iNKKp7Dz!fRa8Q&ic+n}66Ng5`pAH8HRZ*VPhkxFl)*SS3Dr2-e>syHgiQ8_D92`gzk#^xwAOb8q%Ls7uv zjZ3OU*u_gEXge&bZfDo4t%WfYu2HW;9{_#m7B)%YsBx}8$HLsarMHfxhaanY{OR=@ zmbSJYs4g2l*}bZtRG)Bh9H(TyElJW;5!T70^@)nzwAk0 z74RJaBOxx_6sS<+SgktIlbbsPpaG;d0ujt-<|RHdQA9kvW&e7PbCBL&;`;5$u>#Jg z9h_10nw=E25{-PJ;YaaCRM^QL!W(9IvkY&TI-yQB{mLBTQY8$K4Sa`%xwvr?vU>sY zg#zZOM?m*HfL#zgG`r0{Ou^AS;he-nWTtY) z5xGh}A#)xkupmB=*OQ(v?Nm|NqU}E{sAD_~O~>oi;n97Yhk6-?SK8j0zDD-m-M!JN zVfgK|^V=!gaC?K^jQ5zA^SDikXQ>zY1t`F&x$iG#*aTnUc$z`dqv7h;J6e}+=pEX; zk1Tkn?Ujl%%^P>$Wj^$Mgt!Li4;__aGKR>^?UAx_3$sHh-0#=}TF^Rf{=y{DU^ciS zNIwhyJ$Nrj2Xwqw$6M4}DydiT@4bKZlB8TG6XsT5r|T&91;rM@8Hj=y=|l&hx{i?k z8|{)t1TCU9X;h13ksAVl+YJsTxDob<@9J36v50h4C#p-w5GIk4vVDbw5Q2n&Vi7)l z)-&$8>Y>OJ_uTYQ2weTJx=pZ9a2K9{;+pBr$gSrwfhaJ{NtV6i_} zhy(roxqe7ukpC+(nPd_UrkqK~Y#2gek5j$7)~q_Tw!0}m zgFgDf6I*W&)Z{mDnf9*1fz>Mm{sZ{(nf%FU)k6w1FS|U33{Z4iAZ#r&4jRXd(+20( z8}!pU?bh&h;g&#>LY+XixUg;@tYae$SEzwedVvxbHE2DhG@4Zu5KU3MrYVca@Vei{ zSi&G0RxyZ%4V{`On6mkYM2nlg^jUdazA95B$K{(cmH%(im}0psrc4}1B&Ls}(Bj2T zLSXW74Ig%|J+x}guHI95edNU*ixZuL=GNB3A7PZ|GWkCr@CR0|9vJLuhlfqo(cJCn z;O?rD{7KerEikoz1r^_j{$;n-ha;v%GFpb5PGgePl3hvqav9zi!4t-HgX}l3*I()< zLZ{lJk}4Ngs$v-5KTUu3h}8_vzbzC#V#$kY82RGP%Y+bado=T z_)Y4Kp6T%m8+z1<+-z38F?9`;ZGxCJ#nLKVA+a(6)v01mg-_uFCwR`7c6oV zQ%D`;uMnFYEO~@xl}}U{^X6O2XzcFutzGr0w}uvf`fA@0c7JoB|7_&St@V+E??*qo zy!pFh-Lq2<_C37B{9|h2+9kuUpW)XItti zn1-+gvS~C7^L@4J6I6n>+Yu>rDMWlk)WihzJx9$5R!v({oVp9Zid#&e5=DI4_Ubx& z@8>1U>2F)V1A{>~qb!%@`khG64Bv_E#S9O+I7R8qOg7Bt`F~-2u8ua=KHIWj$?)>F zL_@4ID7Lk~*Wo%pD0Z&9*K)2a7dYYTOl{*PhgYm*490-LFfd4><73D-^KW}8RE8A4 z1WO_DX}*LHn0QLFQi({-1U5`tRWuv8C|XRb(Ws=Ank8u@r~=WcAUQjstktBHe zetF80q;!h0gC%b~>=0vhF$sTkPEWE@nIp<#_$=A%oI}(ZNn;-6`ec1wk@hg7U0yac z6lnfK$8&{;D_5QKJ}UX#kd4q$^ixDb6d4Ba8%bm=!#QXpZ0$7m8%GVw zZp1K3O($yiXPq;3mal0>_K{)= z=V{8&+93Sqk{kvaZ@ncMbP zDi>M?FVKL?F>~1z%OH2)04h_<;$>8zWn$8&h_YaqY2J3yR47$pot3d$4$7odRs~3qSVJ+fuoVR(xXLgk1asZ`xF_{WQfSr%@x?0-pG{I9p+Fse)d^!K8x4ymf zYpf0OhufQB1KVC~hvn@b?peI=9QN%wT*9q_dic-yqUP$IFmsieyTovvKq0hY3gf!AzrGuIX;bS91PmAgcT1i3X=Unc#4FBd=_&Yg}ervTaDuzP|DaTfE=s) zlJF$N;>ionl!G@(KkQbliszkq-G8aB+SsP9Gko52&h@!piI460-Z*ibq>e*KR+5mf z1&zhxI}FNK%ZE0@hA06<3pQJzRV%73B~Vfob(FRU${4hzXlT<2CBVia6f)Y4wLb=o zkI^4nX{s)2w`okJn)>v@?W8`tnHoc3{?R_d2}O`dHTK7Vc? z3rHkSCWsC$)01YdUk{D-E3D>LKub~p5mKnWaUp7#r!tDIV~5WUYrnj_JT*w#8XB;; zEPqvTIrge*TGXt5&D`p-0#rfy;i<8D?+5DeocDlO@4eXb)xRDot`^FFMMj7CLUad( z$l0yQMYA2ZwI%i?R}EY3?YGO>b4g18@0@Y7OC z1+5GfCF=5%xWn>@1R|xZlT4RbOZvl$>9GRR{evh_M49DOTU)wepI8Gu}1Nvf{@UOrKp6g^#`BeZ5;- z9%;@j=z`yRQ`Ni6eyR4g@zt}YVdth{y|b|17&)Ju`-BTC!!R?vBuve~qySy3K~$2w znv#5gHs_Zu|lz zyKJew#ioV!1)JJs2t!hCl)sW%Qo?-seZ2pf`sJ4(WL~i1BNIx^Hj|plsSge)gPv(k zrSEI_pkgjQTRxUF5U@*Qh~W$3D8nSng2tA3Q+e2zqd;?$9M@FNXMJ+R`}pe3T|GBG zfit(~EZ+adW3&GYr`g`VJJ-GIdwzQ5PG3(~r}u}Suin(T<}lQ6>QemPK03s%q5p}H zZON2RabgMWpftqdj4sLR$fJggNP1O*Dfh~w@_orMP=Td|qJ;u^ALW+gn1KqCB*}5r zjU?$t8#fTNE49eDVl%5@!F@MbWe6wqwD|NJK5{q&aAygcZ_V_nOsa)p22mEwG|P< zhL8a!xqOP4=*u>sdKeNvI()E(LMexNd<8$i8D$)N8W$Y6!1Q3E5jJr+6S`5L>v(um zB?h6J%M2(qsthU&Zi1$dBhW#*$*bgT@_V9{AqbTDNhuc3ghpv2%WsnTJMzFmJ! zKcZjIHJ|S2l{yo8ts;Qh)q}bEaT}*n$`bdhfk7`kw+4N1ccHA&pOt^^&L0?1Z`{}E z4CV=yAsDV{!Q#-shEDyXrm!^e_p`A32;JWK=#y(ky0CU2K0>sUcxMAip6|dgX+^Ad zYnk<_^`+%&#oMPW_O5lyqCUehW*Cc&)ff(L8=@J1bQ-MB7&7R1-p-eCwu3__he|es zEoN*RgGuIW^R&rq6ZUJzG`dp*uEBnKjMAMHI0d1Z7^-kV>Ifg>K4Es+@UT4@qnll1 zQ~fdXN9OY;TdPAzkL#!j35_mf8TMnwifA>Zx`sG2YT1VBO4j(IIS{qO@^Wf8sK8P$ zWo5IVDcJh^@%cS-o86tMudg)X#nc52p-_W%@|XXu%t_PZz5n^)fb zfYl>zg~*;;+G!$ie{6FF;Pp)keOQ$slwu@d6!266xgvawCAe0=xwZtih=3+BUC^+& zBT2B@t<+$f_O3Rlu_GEB(1778(tJK%M<9Ub zFfMZtd^4vySA@Y4N@aPXlF>b`WPhj9Dn8{HgI}^+AJ7$DQW;2P%HsfvDD2i*?}~Tj zEUh^E1}nOYC3;KMCWv5q^edi_mB}d=EWnE43NU>OYzO)j-@$3v0B!(dwuS;>K%$?2 z$muSe8Lrt0Jng*>5e>B3jOtQ)IBU*^(Rs9~&ZJel>g!Sf7<{n}j@#T4;(l*wuebWW z3lm!>%oyO6Bm2B>!#TRjdw*`n{Pi$FovzATzz^Z+ipiejsvZ1w{tjn-ChRs3n{=iL zdjm%UxY=bOVVDJmVMb7#AD5uXuuMosa4~O`&q*$rH0@|I-xmlOg*6i!EdxF?zA~s0 zis~ks4p~r=M~pIj5XFEsC~po943oBz0UT3OD9@vz965h6yQ15M71rI)W>YG@QaOQc zDsRHOa$L{Q+)$p|(ELzVq(=lj{7SPokF6S6cyJ1Q_JCfmdztCJmp9-2o8kR4E7+7& zjiz`NR$N5NfhLddiM$n|&$vDAK9}utf8o+XY7W0H*Sj8%%v;|qPIFViXpp&>iX#ugMRc0~k zA%rlE7$RI4MbV^5-1+#Wh83-WB5daWVO8YF$V;gQuvIKq%uXc=5LO=wLCb>(Hv}6d zIzlN#!$e;7{08qY6DoEFioJ{Xk)Ax|;ep?6{K=vDi+(t`VED?|a{S zt{eOyIAYAQS8J~V zl)D^|oCru3GmoH)M|@FHPTREAbOWMOf~eB0GaJq2W}De=@~!4iP26b0c}mPdCedui z?r)R(F{H13^DQFh?|k9a1RC z3AN0$jS6F=vCi0Hu#BM?QG=W|J~i$dBoh=3lw*YDh#dizBWh7$rjW91Q*+p)XJ3kDQ4{=!QZJh|)%UJcPeRCRhuI`bJJmO6NDB$N zlWmMtX6(eL^PgJ#&rS97>n1cGd*A*)MUD8bduq$em7_;i4q4}(Z?>kd8a%Rf+0aK{ z95UkT`Z~M*g<<{YmnSOXVXvRTmOj8;gnqWVoyqOKof&3E(>gB3cmsKpV9}5KB@p;W zt3(JHA-q*XtQOL6K(bgikCy{h9^!MnjinNfQ+z#xcNF41lP^08WQ~(OumW0u1?+>W zu9LKK(%{;V4IoVbJ&YBUO_e5AB?gH#F9v1P(8+;@XHOh1>yMJ|*^a*ZhoU*_7c3cA zNp_#xyf5Ic#L--|6>Yv8M%9@St6zW0u|mj~ljE!hm-Z>B=;0zZILB716s&-0JY2An^4 z{?8IAc78~SL;|M zx-QCJB_J#niQhy(*U74{;NOsK4cR(b(bI^40Voh2{x_Gjwk>Fi!fDTXS*LT?r?mnyPjukWQ}?ZO>Gv%t{lt>Fqie;ICoWkwH+8ny(TxNDy3945v5GV^pnQAyF% zqIpHE7ImUE(OFSevmC3&nq{%ntEZatOm=PvwaRVs@8zp93we&L|mqv=G`=9gUs2|CG z+mHR_AW^{NVQ-|&)8g18ho)W~!^fM!tPVU8XD3ilz?`B2-xJ0LIEDTDan~k1`R-dE zp8myKwUgfa5Iu1UZfZ_-E`H7JTC=FR^)LTgx7=NL<_!MBCvES4@5$*i-+T90sOI9I z8fF}L=NekHdDO9;?&p91`QC#&ThB1v-OLYRX8*<(V;xUp7#O`#-M7idprAaaggKa* z98g4GdRuBw>UfF_N=;48OOa{%d>yxIs8U09D!S@N?}#XeE8t4F(;O>a&A*e6rHIAY zij8fX7?vy~EaH=G*a)`m3-;!Ns05p%Oi}>6aj+B$ihPBRB1DBg0;v+l3s|7x`(kIm zY|ZRJQ1yW8#jw7!k_PgI`fSdkexNWt=H6@YI-v%iHFHCQJFN#x^0E8ZKfnFVik+($ z%-(XUbyxf26Wu}Kh+`Tbo^3EfZ$F12=J7MXM-K%@&x73W8 z6Az+S(7{RRKJ#XIQ`dc)z0clY63o_i#sLqR=~L5-;%nls#eW@V2kJU_gya4kN0Ltlxu_)dKM~6)4(o zePm(Vs*Pimm&%XI zV`P#LDuj^&(bQ6Iyov6a-6mGd17?RwOtcy^Oi&48fdqNGRFaXA=VTa8)2OTp%KN4d zXdT*ljWC*`?Sy5cX#qVRb^_FoRhk>9PC7aY%yC^E9TYT>R8=P(RtWdmkt~G|f?*35 z_F5HHQ$O(Ke%!-kfZsTLxV2T7(y(iLP4yFFR$V#V>Yliedi;^nK^xgS7aoN6&YnMh z^s1GQ4JRM`XZZFZC6#dt)FQf#WEo^kA9Ek9LkSk7N%UK>^m2l#2nvvI6C7mmvF16;*_OQp0r=3 zc;^6LPWSMC=`R1^D9$pD@AJO9w|jfZ-Ci#DGn>6!?lzZX$>x3%LX5Y83Iw4ER4P#~ zX*+01N*hC=G#wRMDB*_=pp+k#8nHla)xjAe5d9<9nSe4Qf+H}Z4r$A1txSf_=(I2- zhwrJ=G7<(`s*oFKo}JYAa4R0tu2I|5C%v>gENU=9Lhib5$wyiT!XHSL!>qf^X;$$9h!XqB{)jm zMS2O{Aob#yv=Je1tASWw0EHOoC!SSva1qeQ01Q;Xdw_xRB^^a;skZT0C`4onp&OHL z48d`>YND5<+@gFpdx!fIQ^sh_O~dAwh+!3})SHT)zWY0)m8?zH+Jm)k*WRvWi?>$o zt3m^n`zsL&m4whi<*M?La$8}~`DxbS10^tE-*5lWjyb#APBv1;4lb*m@qo|bIZeV~ zxy_MMJQcE0$~$Vo#)%SX{U#A=#cH|8h65mr9+hbm28H9oh`>68dh&Ha7!x>$a8p2n zP#1}eNEf6r2~#L)ldx3qK3$&9l692HoX?CW5?PHQ_4SdJlw3^xHYab_Gy#*a(6oC| zK!~Z(+6DWkQ{)rOu;eY%A<5n;#KF*0Lx0`${MGL7{JLl7p(Xjj%%cbPwKirR-M{CH z&D^_hh&7R~-2MOw+fNK$hmL`kZSNoc;Y9N2x;;DA9QjG__RT#rc{j+sJIr`UVV)tR zWkKISFCcs!{~Mzn{@4BQ`0>;71{tyCtIF4vW8ThbHbZC^o)9o2kO?9PqEluK)+q6% zSc8Oyg9Vlihz>9CWNi(AC|WEGXBSmr3XFaCCXSVYS;(vUit6t}v)puq5@P8r$*)4nbZUNz86kX1oFxHn+ie6X> zk9)u>c8mQYw%WVx{dUZAPPbEaVu#FYV6g4%6D(#}QX!VbepxUCS|P!#kN~_ONZ93; zCBP!b;UXES{B8^w7m?z`N`NV;C_yDbuNo}MnA~Dgcg~!#Gb`gX*RF>Y#w?AdPL(8m zkH%g9WAqUITmIxw{uH!MV|mLxQisKRNjaXKMspMLD6i*l5tlEx`%iwSN$CosgEGw2 z5}Q6xY%0{PtV6fzz)}OB)Bvx-rz$)ZSsQsJf~}#}P)Ddc#NH0U%Yi+C!vXwd9zNw^ zJ^w0?ek;H(Wl%Y;;DE>NQI$Zcq67ptxC650vd}#@qqHeq3Wpg5c#GokX$FWAHFO&> zbVv%zcD|+#7NM1BHNqN#I;4?}z{!yRQ(USP3_=DF0}>zr(Vg>yKNgMDi!dTy5XVFu z6frk>7bGp3uVttT(%%#AiPdFITFWw(zGtiA#O z(NhbB(lbbsSexdb8)hd%bjx+(&v=~QdFK~jAKm=S(~V7+dN%*2=LG)la;tnwA{ePrSbLwY`g*xBjSg;Y%A2Lw3g(zK`trH5(?bThU$1L>~Hn_T2Zj^&I_i z@4%*R%8?85%PbQ_u@v(Nv<@@zyYCsRs_RqU3i5Go{?++tp0V6ORmN-soy}ayptDU^ zn$Wzt%jY70LrnuZ*KoA~rIRa?my>@_vfbW;UQ}%dZ#))PJ>F8{uu|D*j{_42(Gfo$ zABp249FJpv?DXA_jbh%Jig^Q?p<8A#8kKAbX_W@8QLeG@e32|#%l+lZKEJ$04%&)j z?1+1Bc);&z_4IqN!vhYFCsrn?e0f?^^|CV65evrZW4Hvzr0Fbiip42rL31RiX4E#d zOJ!Aa{h7*?QKAzO^Wx;_=%w+3Y5Mx8rsGsiGA7BbX?sxetCc^ z$O{Es%|p}FQj>3^Nl!t$G}SVkHgyd@P<8U4`WeBAT-U~azGMowZ_$_OcvwHDU)AyF!muX%tuPY9?}Yyn{#TeS@&;jV@JMhdhzFz( zCB#W?3E6ok8OO+vkVS=ZM1*m*^d zX|kn8Hkb&AI8vD~Jib&%qC0{56EK{BjS0X^f@DJ?s8wnP!74v(we=(&(*6e7%Qv>b zO51ANi#FV3gBDvxF17`jj!Ljrf>6m=U(i5{vZ~c)EhG3JC2y3FRezG^!UYi<;%*U% zqARLSy_HhITL(~FlG{H3G`Eqru#!^7ey zS&~e6_!McyWCA}hiN;>-&Hq`C>~xmptL}@W=6Q9aBj4QoX8U97&Mq6iFPg@m+xS>} z^Q^fKiYPEP_AYz#0YQZ*m2j)LgG`v21CkLt24Epu3+mvz`FQMEY8gxDbt-ZG`7Sa+Ht4is)<6qfxvyx-WVq`j6-*QLZNni=r!|FGg{c zbNEOf`2w^U9Gfy;t9*V~1X^XY@9GOuwmHigZ2B z_#)m&gqbVFRmKKhTQMU-gCPPVR)~g}6EBJ!FOrxc44ymRnVrl@*T(Nf4{3=;4ah|! z(L9+nRj(&eRER06-dbr~E9l!bEiXMN=7h}^k)%t~Nd`EX=Y(%4K~mA^$)~8)rrfE9 zu#-v|N^q-o_Wg45KgVWQZ`pDJ4z&H3?W%!o;ylCOkMGXDvwe5I^VzY_vE!eRI3`Zw z3n8#92ZWyx0tGG5zyfrPKxw7aNQDrlhAxE;jfzT?A}YE9Vr5hUx)FXtD-l&88Iu^5 zNQcUVK<&inrYx1%(AMB&-`yo4*{ZXBzO$XY-}`*;^V0K#MyXd{=$K!Mb2=s zT)uo>W5a^niRHnhfgH({IpX1q36~tv7Zmyl3<rpPP0}sWNW+Ksk%k*Se8@Zu$CSws>dsnTn^`jr!q0p$J=#_iT8f%w#!?WG)#Bn+L7Adt;$MA-Hq{W zRs7nTb7+&*z3j<`72ge_$GJl*0!c%S<71DgV`P_?gSjxHUpZV3>2jsKupGCSLYjxO z_(l9`{vrQ_r)D^-oQs`zoVJBr6StYei)^cHtu}0Uro#+QGLE8Zsa|T9a8K2ZDkN2T zD^-W1EDa%fw82hzkOVN|yVWwLS{1o)z8VXbL{z#+^>R0oUnajvVkzlLZLWe=CNKNTD@31kq~w+#L1rse6ggbYnKtZo65NEx7+A8r?`)8-efZy4e` z&Tr84u(HpfGsSD6IUPmsIDA#(t`}x~ zi!OPtwq?HQgm)~Mb>z%*`&+uuKMd!)YstB}^It#EP`AHxZQbb!U=QRDHLA&F+bJzWrC-I^r$0$LPTV6;zw`-L6>y%^mU-5? zXPV7nD^m3sOkWv$aG|(TOB>>~-51i*9<`kDt0gl-v_rM=N`Ni(CKO%K<4KKI!V3C9 zt+GLBGn`UbSwY^OSMDpr%9vtzVnqRd+La(CNiQtcNN51}!7vyD6i;Fw;>kN?2h}tA z1PLk$e?rd>2904WF4c^)E{6&<5R3%%;KxB569j5RMQXam%p4}HjX8s}dIgfv$RL_# zE7vDlK_qKnZ`}d4y%xH)xxNz1JP#2xH<+?TG>w`zkD?(%5s?g_c~p*1q{(tboJhzs zVJE;-hpe%zj4b!ECEA|RN8PtBeDHxZ=gVb3Hm0^9A7)>@*Vf!xpw8)D)n-g)^kwwv zFBYsEJ(>FyzxT8izjq+}lJ>smeYPmR_9sWqmueeV{>nhGYwVG2gm|NJ@Kn!G$cxZv z2&pn}SyLI_k%YSvaG>B$0eYhVvY|jI8N!Y^>QWV9o)7a#ph^uP`Wa!sQdQn7AC`YD zV?{2M7s;#Thw>Ad-Y35+Uy|_>d8^zmW7)==o~BR@Gn`B1=`fw9v6G^0oCDa|QdumD z6A*NU)xyDBL3A)U97Mq&;NtO^7zY`eOAOm##QvNe0lQ!?vtzs6^te-Whgbs33|nEQ zHbc5URPju7vRPAeps6_%f@3L8bOxEGj5z6VC*|e;)yJpUM$UH)KK-n_`wx#h*R)s0 z-!XM%SL<)4O3tO=YZWDM_9spHE6-C`N7fw;mu#qs`4g6=y#4&rXL3`{me&8!;LI)n zY+n;ZSipl{>g)c^!9ngX9D0+3cbUI2sEL6bLo*4UlX;%w=?!!zeUQFJ-=~LZM#41d zt8SxtUG`~V9`cMsg)9Ob!_z#QW|5s0ZF~a22#JSjQ?J*z^jodUUGK||C%)^~NqZ)v z9yD82P%u5u*}fh*-aS3DQCFu#Gh;3J0N_5d7AMGqn%?frgKo}`c-Dsnhhh`$UdqGB zOr9?fedxdB@Au;Y{~bSKd|Q0zwC}PHE%vVQq9b0o)zj`l?~3p!54X5?x=*_=y9eCV zfcuUc$sVsLC_dip&*LP}>bYhP&9=iG?{D^_YArYfBNw({iuZGjR#i#0q8nLchrd6(YHxoiMW57Sh`9IY{eq z43kGjk}^T`?7bx6zTdun;`p8mdv|~M!bh*}nR-E8%`JqvQH(yx4I#;V!vDQPu-Qbg z`GR1>kbO2=4?{-+7(<2ZqRpA0A};8H6fU6wSK@ZKjMd#EdUdat?3!M~eHgE#zL-c7 z;Ik+GqC5Ab8*jH>@ohL~v>*QUyG7QS@Xb%*U38ZGR|&k-14M$0>=HBw&cn!u0WHud zMsvVL0PBv=(OkA`I0Sf{M}ElS0DxH49j_20g#hbxTrsXzup3wuVIfNfpOiJ&GGvml z88gPG+~DV!sF|cH8Ut>rDLUJ6*ruIT+rVVC zH-HM>=m7yzt&ddOi4T%pL)X!WcZQv5Cl)Br6&$*tyMQuYxMCLWpH{d?{@~ljHQ)sv zF}(Nt7SOl8g{&bvWf7ASlAXQ`ZCojcP)uLX@3k7wjDoqziDmVh%WB8LLFYCmQ*+o_ z8yfo~xCFkUdWb2Nz>*%ojD344QLI4(Jl9CwPEx-e2LT}?Ql-Q~UWE6>F%b!3L`0(K zl})m3+1}fi>oq)0?M+f)G*+*B}CxT5EN*oTCHeFn{6YJrX|!%zdP#^S$(bLnYpvOch5a@zjMw< zYhw&pKtF>(H5NUMxlJXS;gf{=W%+K^PG~$&15J`TVIixiZ&xp2OskyH{<3sNp4k$T zLikf@`4={3hxR@B@cIVc*B;&Eu1P&lFYnqf5fZov2l#-8&We|fe2|B zuc@aUwepuayoC=w;B5gv;+lgX$#G=}rJA)VAoqHO!c-+D+u5rvGCcen!h-5qM8W|H ztziZx+}O2$zK0T?_7IZOG#?R0$)OQTBD5qz$yv;5u&Bpdu?U~V2kR1w!PZj4*lnoY zfkOe>9e{v#1_5WXh^rG~5t>gN)s~FT&2S)r|ITq^$oQ$j+6*9uWmFhUHD=IzonM;e zOD*lQ_bo1@D4khnuO=9hS2RDisBJ+`#nuOB*0r~&XimX|e|2Ktx9%@*I`EZBP5Ozf z$0=N+gB5vwjA-|64f}&}ZS>yX-K^Ys@i4#!0n2?*t-;@HxHAVLSeS0KkwJoi!m?N~ zW9jJ9fZmwlkG_R$n7C{QpHaj$i$c{Qx*)VTL_>~TdUOZu0a^sr@HV^;H$g0h0T{(r z11lZh&LJvvtB2H&RkmC0R)3;SseG*p4JxQ+Ac~(D$ulcVYI;U{RSJDa@>-=l;=wC% zFR)Z0he#HB1g4XAxib|tYbNhY)0KoJ5-eU&;8a!8sb}l!znrLB^ToE*@ZJ@xio;c{ znZG>nqaX5tbIqoisN2+!S_6HeVN7rZ2}wISa8u#^fo^nEtNEAYm4xCK@IBBv39!S#*S$x~3|l z$ew}57>-lReJIYcT!(SsopG$n^40K$X4TZib$K@@PoAfSXU6Wm`iJ7CoPYz0P~sDS z5WvguD$rs81x~?vxCZ=FfR_MtXoY>i)JD3I?xbUs@1%R_8+h>!72l(Sl>UlBC+(%w zq;QnM%luVNIfo2|*LZCu_8<{Xvvg4>XrfenCa5l=;-a`A_)+mDj@bqAfw(2uO3^Gv z1$$0_BDM>vo>Jj86`uAz@1q-hJA735AVbq48eJxjZ=jE9CE8x?8ydf*!7CbU*E{v! z>!0epQ}5MJ>8xLeNA+zw{jLt3Mz2AejmHhD8#syS=0Kfhg6b1oV>&g!G%B!An^2$E zDxkz#CNNo`JftIQx;<=958FFr6?S-MuOI2~ZhE)>b-(QX3u|*+zT^?pi5EwlqEJ}_NL7fgRZFHirR)=poer8BzIhkGkbJ{lpJ5LO&~ ztZqqRNnAKk_r7z}`K!Zvo$olWIgB{KGMro|<}e?JfaUO@o)#p*<_?pv9rQL**mA;g z$1(zOTWZ)w96=tAB4G%HK?!GtX+*K1ZoR$T?zB(Y=k05@60t$EBQ~wIWKd(ZfyThb zz&nBKfe!=9VR#*=9d@h$D8cYb(oAR`Lbu0QHVMX(S6f;xrGpx>=5g5ZIa5-}f*wzg zwYTGYGxCg^(zChwo}S?!RApw(sYztgzSLh9&S_{XDEF6Sugo_iLP>r6?6-5Btn8ym zVDaA4uV!=@@yrzgi%zDtZdlv=CHTR;dt?(E229X23ljpt@fJ2r_jqGLWDR$-+ptc& zhwoOqI<4;#2gPy0#3(emnPgB$Nmum6gw+%D73!0|GJWkPnlzg8CoNKo6}8GKkljoI z*6kEq&gGSE7B7__yVC#M(xwvm3s0~QVJW5^oh)*7G1$ht_(9IN`~}NbuM<_*_+p{g zr;Rl^dv+8nb$(3({U4U*mTfM7T-kC?6!tDzSF)n?`&V%G7jX8?-t35<40gdmIF3r{ z;rG=m1XTnU6ZOC2S7kF+jcdq)&E=cRa?fp1c*Tm6bxV5tuXw%eUET#lB1!z@i810w zO(|6ExE9VWjEnFCg>k*da1B@WdyYMc?!^q=p zfKB`_U@#AR*P1E^BO+QY46WYLx~gnxeL3&iwWhJP(JfoJOya6UPdy?oq6MBAF~hbK z4@gi8iWkOny+h-s<_h>BVhNX{kHVrlG&sefIBu+&qhe{xQN)zABLi8b%IE0<{6U%D>6~rvHrp zqF)^01Dx*R2RM2Sl-RX4ol!WC2-6H1k_dE4BqBu85#KeNFa($u{3jyNM6*vL5w01E zTe1JY+VpZ|b`4snJh*0A7Fg974UTlqduH-N;RE}68r@gcwA|)@u=`SfPJN`M`asp5 z+V7{rS}$DT zW@g0&@F4&=OE;l>6KEQtc_%QHr^g(t+OG_XLHs_bl=@WMuMw>2Xfin+4JTWo5z9N1 z*m&&zro~lv6cqpzKows;oI0197>1(*Nk;#XV(-pI_N1GeA#%l}_{~2_uNv4Wt|R>B z&D(wVf9v(ycjq6xXJZayk~7>H2Qcyq2?SLur>RH-iETn19H^9FB0}PbmMY~}K@Bam zX=4?lHWejmO#veZ6mg0GDYVB=l)97_sH#GcDhjPC8pZhBd3$GL5{N+Y`Sy12c6Pou z^JczpwCkD{)(Dx7sBody%=?HjZv)fp-2z1Z8Wk{jhZ8Ujq^5lVuxkX&$mCJEm;l85 z+|zq<%MU;^w1|OQjre;)#>ol9#dENk=2~RcjxWrsc#@;!Kn2`SsueWh)+=ktwzp9t zY2<*-U0r1JRa(_Wv6r`M?~`r2V@7c@K0+cDp_JA`>XsVR(*1;7RY)*Ylx7G&_aMtzx zgcFQl0-F$->swW3!M$U0hdbn(Zwv!mhY{eeb1y5ng)z6oZJ+l_Vgk-?|M=hJD(c26 zw*oeg^pnr#e!7&jl95cmH;{%9ciXTxnC95Y$mvoQMV^mdI~7Axk#arj7#~G?nu=m& zZjf&qSxHZg(GaK+x%9zNic%w|R1z}d1ewGe<9yrj>wHyiaEDqw*`6Kw9@(sX@YM(N ztM?+U-%(3A=q`b^6!x?xh;+gAa*&pUo?S#Qi9P`&9+W2T=u3b*CyAL-zEYs-WTCs^ESE z!QC*`-a`;{-k}G6#rAWA9Ob{maireK8KvM+T#AB1E_o+7!kO}LS~ykl^igqIToRZR zEuvMREkMPItHTWytPHSZ*&o{7S)@LXWHOC>r8wq(@k-Y#`@1e* z{;Yq-JGJrtnbxU7LjHBvKSkw|j!C^mZ`IM(f$4_M)!_z3OV8lF{GS>=r5Xt7;Tq}) zNZz3hescM8*Z2td*|(kf%tsL9cnm(->3|R(^e7x27l-Gx=aL7Lo)%B52W<~9kKy6! zaKnSrkx*G)fHh62SyS>hL^L-q7 zBiyaKL6ExJ$lu{xya;0~#1c+vpEyctOa?fk)r{_DEqQ@*VH{)0>_=JEQfZ<=nP`fX zM$}lti(Y)@_{6W5{WB5>MAHv{2YP1$^S+Vz{=C@qITWdpA=G&vv7Vo;b5gp`9-v5xLSQ=vgjO=ZVA)Rb1Q_?hN5RqzQyO}LvPlJ_nB^wXt7L+%lmkDk$y zQGZj@>JFM#!z>0XosK^NOoACOA5MVK0M2PwwNErc2p>z>BjKDMp71~G=XL&>{)PSz z{9=~*6?2J+jn+JCk%f=@VR~q8=&=w24_Yk5gTAoe7Y>-k77Lg`&RzLu1}xJIgnd4B zWm?R#=xzGA2w)Usl*DrR0TvDh1~BHl<}=I8DdtME$J}b3H07+V=FiN-bavj<7Mm-~ zm(6$056nNC`kUrE<`Hwq6w-{C+^bn7R;~4nwZ__D9k=AH4c1PppU(bhX^&gWtrx9B z)(LCS(hpkywYbkR$$40*P;N6AWLFsfDf=~hm*E21YQey{z*Q2gWksnrBl}UCQk_`} zGi_fLb@zj{WHK2gW+)+>G^2i76%ok&P(LnK;v-I z+HW*PqfJIyRcI%iXBS|0- zC;3Lwj}MV5j75oDD+h=S8YaZk65xL%)1U-u0srEGx{{eCJQl5sa(@hlVxUbenaYD0 zE{3R9H!yPMfb^&9R6>)+B;%&R2aPKRf7|FcjvM%r0YY$-Zuju)WJB zlD4bg!%8Caaw*YR~k!Ofzq#iR*NoeGK|N`<+PK?7axrf|?$@hDLOvA4QYXA|kph!atF`ln7$w?tYa9TAKq+X|F9 zcukcOb)~}GagBP@Of_=kzb!Co{)&E5Tfw+iPx)1fqC;&4>S=V$Phd56qDl1)V!gzq z{3}11P(M)<^uU2t!C{md4F6huI`wf|7oa7~-H~NYjD70NowPd`w!5$smSMU4})_5>&_3$#e!N z2C(cvC@6JRogslBgFcOiy&}Zi_)n$`GGVs*O>| zqlThnm!s*FN-AGQ^fpx)eXV}eI=77IqfkaF%&O=}Ghz*3iefjTsVRkg_s%2l{Rs5` zyzyKtX4byE{S!D3<+;nS1{Uv0Oes(A&Ha`pyTV+{OXYTVvimW$z#gg_jYSO$r`rg z*5az%T6)4{nhM^csX%9IogzIfszg$t2gN3>Gq3UgPk8mmRCS)=^SofIM??`tw^k7exUJHHIOJvn3$|#sHOrTC zNO9#j_}h(kc27U98`i^Uam8%%01wXmBIxk^}NJ$z+)@XJImSM{g)& z*%M>#j*{c=Df+MI=y6`?(Vtqw{)tbC8&;N;XFYAt%odj)c%Gl(KjP#<*kmutniZ+a z&9WZM%YC3CJGaWpgGgRfWkq>~$g1j!f*l=*VpNa*iNDjZ%ATN$$NWS#OO9p#Cr00i z0Szj(cx5@QS|a@;KK1b9JC`=dUDup9Q$LA<_Enn;Yl?pO`{C3Nu7cP#Qc%>|U@vcy zZ4y_?YKi1_RM8n`0p_J@o!Y9JRGaD{1ezofQfb6fY4$tgG)X~ zBgHzSum_4rvZO#~0*b5^d#$bDo%N5S0?i*VYd(R7qhQ%xOP z5u>Lq(dhb@sT!diz{B6W1#0M7MV50DPQ~e4X^=(KT4B$*#GuX)(M=Vcz-8d^#tFoO zNUJBG5c1s;&pT}{1j&a0X#52}Us-GHMS6B}c12H5`C9?q0-6Nu5l}7a1eOaBgeC)0 z@e1=m-HOUxttJ<2G4mO3#*=5TF;vMK`%%9J0_$h+igXLZE2gC+j)+AtgrYw`$JJrF zHotfN<5Ba@e?$VoGrF|roCny!@EfkNAM+$a1tRncs27I?Zqv#EQ?crj;7XeNa#~2AwyWJJ(Z#XQ{9aSV!JSkt6*d$@GE7fCKs(>mi z)Obj$RCnB)09FiQ8H)Wkmef0EZUy>=z_7(cC~u(?Pp9rR>V$V#>mjSSGc=Y|^Z9(zLz`%c*nDsHQalHY^PB zdcuAr!Jvh8GQ22ZyQ~k8`9GeT>MDcx9e7Y{ozNO-B?)3ZV^$$g z`vHBpEB$xq6&D%tcZmUk2SlsDuT32zVGCHXpb0kDn@vyG@<)7Jqdn%k;E4U?s}c$o zbn+37huA5G4Gh*ZSjnJ>HgYzbk(N9wwD3O4AffaUf+w`nQZAT}Fe6}uScp|gMi6Qn zWcr}C(e=T;d$)O2`Mulh(IC&Lb=3X>@f=ccR#WXGvg`&!%+BkYRV#eTBu1K5m7U)#+a*%a z_puR%9V{~iJ-3W!fW}-j?bnh3TJK$Qh=wX;x5Ap*W|uXYFd7!HT>vF+AA{2jE+Zrm zP9rqn5yVRTywFQA-E~dajU$+$~DG3zshghn>x+Fd6U68Q(u#-LtMfjPg@6S zB)$4&j`Z$FIb?Gk7R+}O7pPt~$~-Q+XrIRc$oK5dn1unGT2?$_)>*76 zUnZW!8fgq43ww*0S`lKpRg<+0+3DGuQEm7_EFR*TlWy^|u$26jY}8!4@SDg&T)$$M z_sWYB&k0DmpBmIEUy>IjYcwo7r(x&unx2*4zA0>4-~{B5G@Vh+W-Sex(EuA|mD&$A z^LF0L*+nDI5dh#QRaB>zB)b%kr;=$r$9K8!ac91U82opFKK+xwiUsax8+S>o+Acf- zz!bm`ZBM+LBa*c{u@8|Wm}s;}GL()c35zp5=5^UiL+!JwCfKB*CjY_ zE=$;<-;eAP<$^lr<;=KlS*QXtr4~cJ?$N08i_P#Hf>_|Z{&i>xernYEqP?tJL55hIOF6hKlsNwv}ZfwQ$^Vof!#p&mHZ6ox%i)X2Glh9L_NSeV$ zd&wK>Errbr>J_*oGLfm9JR=aM#SfzoJ7cv5of3babDPkU*YLAp^sV;tB@*UJm?7bJ z3f?dbM%evGxWVwhD8LjNFF1d8n?M)mS?3d?aqkaoS%5{v+GSUE2q+XVLr^YuB3586 zZFcNm65b_V5-xK1F+x9SNpPJMCMPH^Qdu#*W73`h;nO+c{KKWg-~O1mOuo47cvj{s#I7m9?ga&99trA~u;jCB;M#4Yc2#JKqb$+SE23BwIYI<7rDLgNs zLqdy$3Rx?04n?0E1k`DQh@>FKp*T=Z+Wq-u`R=rzaQfXN*K#Hj=KkyrT!jS{td`+R z>Vm>O>X5DnBZGyvY6VOgh9IWy;+@wgZ&OY>sstbgzQ zueJWqxFoa6X*h94f8IN~&5~JaAPyeKcsR*$aJpL^ffw4?jnnQTA$iXi!<=%i`0~;bJHU@oJWd4;5y5x z)$ArGQ!^b}3kzehobT;807VV|y4hq;RAR?BD2Emr` zIL8WF0{#>06g$MBV_B#6XW6<+h?>eV`y#f4d_+4U6juvdC2W&$gQ^n)USn*X7Z43Y z4Ty&VZwdIog!sJ(+wmOYlXU>(ZiK2B^>meCKvq$f+Qzo|Rfa>2YEFwuu`OO2oaoBC zDFy_d74W9+%?n0Yx+nA&qj1QPIioM1lo@Hc#6j+)x+F%-S813}OWTZ{_k!A1s!|db zXHd#27&>FAS%Q&8yVcKp0YxJosVFDyk)91O)zF^S6M;FnHlU|aeWmwt`ZL&_ra&8f zNiXjOvr_pE;dy@9tRg4O5sCBa4eFf~&?TV7v}%cf0S-4fbn{-0+c+FVXwT}RtnL|d zR(jnVpg)p#@(Zo5qAdBhFS6(_s*3)@;Sc;XQ=I1IJ^{N0+~jbUwD2?w{+1*RuaD9% zkio(jEHTCBl1X0)+{_yF9rCE|A$-ZhL5t;65o6T2Y?XS0{FE*v(>*5Cj&OM@kTiTS z1+}@mrV(b69K(Kjlalj!Y0#OQRK)3;-;0c{>1>{-O9P6tLHh;#m{OzHJm~-!3VWC` z)N6tFR9U^#2=h$u5as1Pot(*T?G7s3uAV<@6!r-XdgW{@!x9E*eJ3SobzPE0Wu3%h zcnL`)?DDnL2%NdxsJS9P9L3+Ea0p3n?I9L zT&AAhD|_V6C99F^C7$8X%Jujh4(7$ON$;19uo7pBF{#bp#Q}evaHvUD+>j8FP-<}E z5X~hE4!Z1joxx=W?=slSdKm6vP{Y-{q5@v(iV5&9@U6Al)n zjx53fgM)sRakb!q?toT#U9xfs(|z%OYsF!} zYSxzXVe79N;j#mc#i^Tgm8qLp9ME}Kz5Ka^>t?l)*J~t{$cRMJ`Z?2bX))6q_FB+o zk@RK@zi&ac1(WH@wfI(nQ2`ej?9}(Y{z+joD@6=G$tnAWa}t`-)u{)SI6#S_z;_ap zc&-W9E8s^0)(Kdyw^l^pBmvh=x}kti$(pRwMTg}FIUdJfAksfxdqNuZ)>uYnxBWZE z82oj6R5=bj{HMbo&t!UUwkl}jZ*hE=iguC&`~mKw5U9yCMC~^SPJMf;HbAG;A$LxB+(}n~yNV2fnBeRyb`C_PXEIL3(o(?-GfoIvepf0ZJ%R zUt2GCNY9{@drT)~(WiG?nVuf$F1EfXyax3eMc!WvI}GW1-(R7MsgVuhR#?z4q0Kn5 zK>{tY^9*_re5EbYq1Sxa@2%@YSu49O`lHa}kV=JpV>$fH?#G=$CVEj7-XijS--2ID z=$6pI;3Z1X+ZoF^T-%#O(6w?LMh>mbQgOz<<)|QP>C`HYr4pbYjHsccQ3C!U z;ZG87OE@K=PBszHu(6W5@U*~;eRUGk*D~VKISjJB+iCwL3JEjRw3<7~7Ty?SnHg%# zzd3x!p^cq&$i?-nQ*?;Lm9dwzK*$3LUE)p^?13`+es|`yGu7B`*30m`?$;i~SG_<* z7fq*f%}YTy7^FZ~VB?F&8w=mFYl(3y6TIEF5)OrSXWn(T8W*vk)Pk_3heBAJil^UG zpCTLx)LGZ252DMY*FcXcM5pObKs`(fRGOv6(%3v?0o9vs5nQDM1kJ{PbMqcmhy1F) zo-oDik4;kWZmmoeGzsXyBXn^^oo6i5u))uJ~fOw>#50fTEg#O!q$V4_PZyU7t*K~8XEO#b5n}zxyns21ztA1$2QJS9pIaSiML(VT%!#nVVR6eoG8Ij zONmiyjWb4S^L5aMIOQ~X!ezfYS``8g2xuh;1>aq2ijFYZv-Xm&zymgL$YGnubh zNO%#%3qfdpItS7)zC2GtW2F>gs!x{=p=Yc&w15%NFc7nd2{HtL=FNa3d6#ePbjP2%K z`~+uPIMh)y(=Tgc&CGOinhkxu9Lw3uy3@!Ev$tU~kX+oS|LhmT^C7L`z z=(5y;63c1fCebYL5`&`*IyG~_Lbif!pjhXDS2zuc;o*^svqwjM(+gAg?Vo6UIvdO2=?oXjo z&1L~M96+IBKrd|Q)mRbA))$;BYvH2i!ov6)*mMHJJjG8OYJVZlDm?M!qr&Wg{bU)CM!5TO*#%53Kh< z=RXY7r`Csl;H-+m1)an1JGbH$Kfz0|B3MtFHA9VTlh7bxv)m)`2!};1%KE~Wo@9VA z?>IYLQ61ps;y(>zCKX>-g)d7e((OhaMzHCo<$Bh_aF02CH^d~e(}ec~NfLVa@^j~u zTZ_ibc*S&<;rtpaLiLoWG1a=!X>b2Zg5KH(WPbs(M^m`snl9rNc`O<)W!u7jn4^AJ zCz~beK#h$8aE;h54hXiKe(f7kmX&sc$wuc!6xs|->XRSun$2gs+Frh!sYV~>O&n<# zoWeH5eF$&jW_)6*OmfmFiX+DNBxvMjux-B~trGv7Woptvd0OfwkID@uvKLA{r)Z}y zX3&OkLKA1dZ69>~LuXA1Y@<-5=~MTj!pl~m8rzznGCB;mEY#Obr{#}Gw1Jbl=X5i3 zMG5}hobxTbNyr)acA7O#4c#T74;>Wl9x_b{yaTTp*oeY5+#mY-e3e^m!$KQo*+6%> zK>{7b^iDr5o65B%aL`Tc5vTp`JD|r+x!ETa;J-5 z3aaZZnUxSWl0FwDqF=8F0^P~2-C3~!o`Xt5Zd&v|{I#mEYDB#-ORMU8ZQ*c?L*I2% zat|rz!%{(k*snls8=yJd9rM&5C6eY|R99j@I;xWV} z2%}M(*zguh1ze$p7X&Uc4jn`v!uWNVe}XA0yH&z&Sub(1_H7++=D30HAJ9m%-c~b{AkfSxy1@q?W)<7mB;bgi%S2ifE%&h# z47aclx7c)}X^A4f_vke3<>@e8-F3F>!gR{J+c}9!b8f+KD^%Ya714C{v1G|IDc()D zAKgZR#S=bf8mHwh1F`2 zOI5oySiw-K3uS`-X0To}U@^l=8**&;z74j0*2YBH9#xfUs_NIBf`7T;s{iD)x>ZwX ze9-wJRo(ShHa1Z80BgINPZ+gFTodTB6eErrs!<9)M%aZ=g?c#7k}yO9JHw%lLk))p znv}YW@mx@8V@O=8S||StpT#$ZEEQonveXgL8o>N!yy1 zLgGKc>B?!lp;u1KP zqv1-*)s#)N1GJS2B*kM1O*ZYLMmp?vT^Z%~CV@Kz^sA&Y{mx}Q3j3RLtdcA>)qs;O z>_L1cD+#^(&(tJZO!)$a2w=_TW)4x7->xSf7^+#vt2x#Md@ksH0!~kD17q|aDD|mx zrV_40zWZL{*{~mD$Md?$+3{q>mEc^!tXtyk#7WPQCgGK zh|?U7a5#^kC2$ME5?n>ZrrRmpOWk*tX(j_NQM@1HXF8Y86RQJXPqRu@QJsXH-kVm5 zT7l;o>}3rMm#|fA6JxtE`OcELS@H?3=l9oOFTzIQf@uJ!BVI8N&p|5;4OKHkjXWpe zq=dZ^7E7QpMiV(2*kCqekLfpGG{9DOoE=eUf>%xQnTIzGTO}2jsmVKRD7RsO4F}{e zCF;i0Vb;Y|b0I5P|D2wx|NiUzA_{+j7Yu1pK`hfb!POt0MynaAnrGRWP282BU8hgCyjW~pHEDCK2NqmO%=KA+QR6~)!PUB`&;&BGMSRV&`aK8WBc{Kt@ z;Kwmu6#uT%u?6z@Kr5h^X3bI~J;Y!w3>UMNfi>S3=O| z4C>lefqJ%BlnZR;aFoMp?>19iWh$mM?H$1{%_VNZ8w6{iQ{}0Q7P>{&95_ucZ4~aH zTh0d&s5g^Y*T0g0Huy>3!l(`A>&2hfcNQImqn6q5=hYyhEBMiHi$)=n%TZzb z!^`R^`>A|fF5cx+m}2yg-)3g#o1X&*=d+C5oE#XIK4{MEjC<*~-CyHnua^$Xh!0D@ zZB4rzFTFi}9Au5Mv!0#+lRtgC;>K5(d24Gcq*FD2MXAq5=~1O(N;l0PC&EjBxtY%Z4~h%?UW|d&;;$;LN%?X zsyb~j0i$6}StQIzH>xcm43?pZ3O0!)oo1D7C?HL~-Z|G!7Fwnr~d;OmKoR8-@ z=afkgp@-Qqb{gm(q5y`pCSf0$fWzofW9l&bhWO1Z5UbQr)e82s8i!NmGKWysU{W8o zDA(Xv6>05^Bp1%Hr~kD@{6wvI0nXXi#aUXTj6#gNWOb9eLEWPAU#ovmXH>pce?s4? z^Go`5eOBi`)<<<_jI#L1X-Ex3CN2vU!zV1kOo3mggb>;}7AMTXc`eeHpjPS{x*F;0 z@9U?ms*(pv0&ALRjnBSs-}4}H;JqrG5IwNgv&-i0LnOl4pC>Q?D72My`Y2^vQ6 zAP3W}$$(XxS}F}=&}{d#XK$vK%*~Z1p8=3Xs=seb8`*RhErq1QQwQOLj)GWnD|5noIMh zp`^3_IJXy`!wnR3%Ke3YxaiKyM+Wv?J-lD}r9Dea@q)@52X9;ES*KzJwF)kVl_;BM zoeHd@z&aWQZ|7MD&j)x|NRefo^PN)=6raVqB=`aK!2LYnZK5rIN?f1p+nqsl{5VwK zq}WYDpf<=Lm&tt0f&~O)QhkO*p_)kR1iDq|&kuxRF|nJ%OwQ8J!l}4(N+YWQ;KD(H zC#9i8u{SsdrX$Gx4?7VCTH$cTW3k_5jM*b#@WC2rd)LVj>F1-o6iN|HtmnRmUGiM_Fd!Q>a!?4Sz%w0%V5w>N43J}B zY>rR2bY|-KbxIey8x=uaP=qNUb7urqA-~z0R|cfEcR?Mx#>Or^pbrxh^9r#@t)7(? zTSQFk6MRP86KpH%X3sG`%kDFFiCt%yHvkAqrThW`fGEXfiL`Xus()E$mvu_?Je_I! z^Vyh9mEGu!0GcvXn?<7K2NG-kf~rbdb71L_gXIT&)S$XJJ3LIG>Cp5M{!h}aTqQ2( ztS%PbqYNmApm&VY%^<@kT!eAewU+QO2+Q>C{DNkP!(FsqsA_>?e<;}0*wo#lbY7@j zyqPYyQR&j+5sH+F;7HO(h z)7S(d?eW!auj^JjFDT1~9`9JSVf7nV5b^6^xp&?&IkAThz>vsk*0M?rnE2Nc?bC?0 z6*VhDAwXTyTerQ|ccD`i4I5T7s0t|71By4(XF(eVWhIxzr9m`oVL0+Q!`V8jP$ep1zN6^tJF7n*#BcdnMOE-L zP0%UID`^7+f?Jg0h`{h8jdMc6r&3d;UFsfnK!thPLN1 z`fHt@3|R{W-i*!7#q6HFv3|hV1sKO1jKeV7!n-Q~CJI?4;U@7x#{skeQ;kYWVQ9|6 zWD77^f=w}A$r>P5++q}UkKsoebv5BrsHxB{1*yiBM}t`mQd=Atn~TNf>>GROM!;zg zi*t0p`W>Q>3Yp6Zjq_9dJm)+lGGoUz9JM|iNAb+ZX>0$hskhia;863c;N{==$5hR1 zA!mhN=*2MKm$`1Jg=`BjIm6mF)UecvqH9>JKR4V#u7@=%`Kwxr94KuCtakw?&SucR z@~T2>Fs4+s|MD*IpxFN7lc%r1`+j71kZtMnpwVA@kLc;ycPf?zJ)`ManFoJpgOIp9 zuI3D8YtRSvMaVHH*153y$mJ`87<-FwjqpL2l^n-rotFRr@bYXKTJUGm!BLnQVu~~K z%eMAd?~}DH;X1nmN0v5OTfYvgu>&%F(#iCl%z_(QqzP+XI#$;TSJP;ijNs*`|x&BZ>B+BOTB_>me$qXej+=b`?N(|qP zy+B}O#s~H^ZBF-s)_HLQiPKZ`JamWeqZ!u^d-@gdtsJUzg#3V*WQp`Na++&Y z2-94y=33)8d0B9x&kH*5udZpr9^VLkWF)ZewYK%ujlT90*T@$xZi*JZp1aB4i;7Q( z-9e8!_R6KXiZ_F{k(_d75@R{ErExIXiY6%lB6sjq?xFr4ey}|Cu?hWWE@DTTgZ6Ixft(+d> zbbue?aefm@HY>!qHyD_~GQ$kU4QhA>pC^aO)Vu}~+%=NdVCF~?t3OM?YhBI^0W2cSZGeDJgODG|IM{K zA6%Yi7QeEjWOb}#)~jRRh|bM_LcKraw!=>!^9e6DSPzn;gb<&Y^gj17J5hYPjUTh; zyGSBBzBmDq==t%*ixx(CHq7M(XlMb&_?I_SCKkl}3w`$`q7Ou8tga3=#^>Gb$ZHGU z5v`tMw#NlIU}wj%vlSBV%K!@ou}{hjDu=!!MwJGN2q9w{CR-dU zw_b;P(@&E^vUvcD_EXcQyJL18FHT%jCufz#ykcG5jyK%nE;Na!&0*%ZdE8w0xlC1W zD|F|RNHQ7tAQ?y{J(bw>fe!*h0Rt~s4RS|>!z`1JOcO?Zm=$?}dlxL)SQn3P-neK% zP4foca|&&AV$y2r>5;n6x`_UT z(mRoRo-#`{zL7WbC%HPtKjBo@H|aa{R$aZKf2z}S`bC}Ea_plDI17l=P>tC{kZC5? z$5qvaTL=I9wP^*Z7(^|}9I9nmh}}Xo2u%XC=l(%wQ@m6&e5Oi1)3b!8PD5xMZ%${O zRD{O`=2VEZDLOEg^^!R=Q7e)@N~Jf&%g-S;t0_xt)=BhoU3x9fr1k-9-is%(E3jcN zn#IMzSe}8uw<;GA+C^_eBMj=z~`Tv1X>pMiMA z*5!{a4KB++@lnO>tzS>9TvEJ|e3=bB(Q7r)4c0aM3+E|?(gfg>w;rS${W!K9f^Un8B#QcC#eA!BoO# zvW3{JA2Oz)J{L+P)$;ALS(!N`(uV3hCHfI<3vEr;3;W{zmjl+Bc9|veJ6H$jFiVgB z*IDvT%F=!va)~5t&5GJwzZnk)Pef=>7Ws2cczjsXZ1J)}IZ zpm4)_QRknQAu~~Uas(Gy7dd@VNw-C#D+Z|*5eN28 zIFG=aNAN3JM@O+o(<||uZ=hNbJ(@5bnhUl9^(pvOnVsa*9I-a~ETvRe(fSFTvKrP` z3cr>ZXS0o%%3!A#TTqDy3*N8}L2KP0>X26J_k)Az^Utgw!75Y{1!VgGDM0mR)7&wa zffrSf=e!xE7+bu6xm%2Jln~A~4>vVW-hS<{)~zX;(FRT>&u553B~eQl=UarB2n?gadE7cFhHThCh6Lvk1QI+V5Euw)2xKTGoG* zRpE`tj|0G~g|tw4sN7%f*HVwPx948!uP6P2){daH?R*!qNn`-K<%a3?6vUhcUI?>m z)S(fVj+?cVB!-5EATm5;45!Y@Lwbd}EbwV@Q7iFS`Su-;p2ZjU@wn%iC0&j>wcOva z=sBC5!t7(ZUYjQ~++cnM)5kw&3KM>V(;FPPi-C|WYuHwHn02$anbysYvtO`F>^fs@ z499px&;=I3bh8-#Wft?F$YBiDA+?7Pb_RXfWIFsxNGVsaO`%Y^C3E`eHq(Q(XFA<6 z+TjAY4rve@{vp#wB(5r*AY&qi;Y58)Rtn({sfFv^D9pOX{-kE~4k38cnziT=Bd!98 zN?J6t=3dLrdM8>W9T44F?s9$tssnII?k1ew?P#x5L?6YL7|sCTl#+_v2?C(D)FIu-P|FpG>5BETmzSca^Rd@wa(IV>ir)6S@y@LY`%eU=_GAd^|3d}Q z^rIM)Zb_CJsXUEDn4`a} zDi3brI^*x{+e0hX((0DhvLxGB2Ak+y+u_s(2q8F711WJ_WN1d6io6qk`kcD+mamWfSfc*xTNi7Y@D%vjDYgkO z5~%KRp<;CTEaK?NY$``jRt4uV%g}SWADX5flh4bSWWpG%hB5;X5GtO56~!(}E>_dE zOC21RrH5sUkc7h$enmPcF%mPQ0k6bNL2n?VYz!EQoftKX%ca2zE&xGueeAgG$T*0j zD8g%e15bEm2J&E!4oot8we8|y^4~P4xvEf`T?MmI`z2dj2k(G1b?Ve`dSN!L^O{a< zV9>bh0pv!hV8w+CBYBEj%yiwQxaTfh;A{K8F7Vte--_JB{fNo4Gk*lwxe~hz{A|nH z-<0QPn`)&fIr{Rq=vAwOTYh>gr~@dSmo7=9z~ILM=L44lgmGKlWp04eGm(>7udPx; zb~{D08ql;;H0@%Eq0@`aUcdLGmzceXrydUo@>-G2MiHc3uT9KYMl53%Vi9$o5SU7& z$Vxzg2NkWfvXVYnNgpiwxZ-j}rh-(IASZU_0sbz!GQbNX3-1}Cd2SL2gMuxm7589X zwost+Q2(zu@*w!fW6O7d?|Q%(f8?$m{&Tkp@RQtHlpXs65>c(@Gl=-M2vHB;<}qeT zO3=hko=O%2*GYtMTIs)<25Fm2D}!0ed6WZO0;tZ)I!C-F+jX<6>*n@swGVK^l0dw9NL?>0RXx zppv?i9W5OvPTaf+nXNnP2THxheFAJJLWbZ#C8z>Dglf=C^eC!Fi_z2QhiDCIMH|s} zv=hCG-azl5L+B`O)Q$_i{DEF53+Ekv^OujmePsTd8#Zl?b@i-W_uBqtKmB>_v}v&= z%ho~J5NmESt$s#vIzv{|>{(?#6O>>m7Hg|ojEvGk(txF4Roe#RThcpkL7Crhr1wXu z-Mi*$FYVaT{`%gP%lGbrvbjAl@!9q3UwE=nwl})H56@_XqQ1~RWm0>4X9Uj|>RE9f zLOH*h0H|$vPtrrp$-yD|)qC<#8dxnn(675`I4t)=Gv5nC zlQJF*-W|~I52f?NX*rFs$1Xd-eWnsTA?i73sRE47)XxN~K1( z;yL@_kudyne}j24bb?<%V;PKOJD?&A?DgA3D#QFW8mi4c21ENI5tRuPp3Vu-xK987 zr5aH~(Ab3MjBZWAUNck^EM-6Cy16mn+3$ZSN{~`wzK=PmO(-(k{I;--2sZgVa}dIn zNE54X%(#jBockB|EytQU(RKlDA!LMF3}^LNnoOd^)!{1;F{lzuLgWNKnh3cbBzZtb zY&=$5$90!|{Zdc%o1KgHxVy_UJGV2{TcF8}?Rfv#>IL1Wq0)DDhU?*D;Js7MA_997 z%?7`L5e%679dIbtm*%17=+ZQ`YfkFwlPL|5a%*XT>*+X`E6#b(b=+X8n91xJ%;a)- zi+<|dTJi<38IOXRy})Bs5$P<}$#86#k{B=z5SUIdoKOSrM-BO+Ym_CUz+EjJKrgv7 z_;Xy(_MyqB7X9&z5Gaz>(!Q~4+9b)Mo+`y*FP`gp(v$KKv(ay4oLtyoaj1Wi@Ry-~ zhM3n?T-`@XG>Nx3EkOt*7S50Rh;q7y#Ltlu#1ZAgj54Ayij#Kz#B-WhtNMsngZw2Z z2O~kUGPpk28$1;p2wn^FK~XtRyr3$g@JLZYJSZ~T#Edv15)mkK_{y++1(Lz+XK~01 zE+!Mhu~>pSHU*8w6q+fu(%6E_gOz#^fuyxoFLf%7DESmZk0~yv!(n$hNevH!kmo{- zsm1l3R(|uYHM8rVniMIm-!l)Fhn6p$JjMQ#!1hO*k0rcD0Jm#)cl8tMtNZKh_^S$a zO|)*+v(t-zqNu1&Ez)E+NB>%kZ8SL_TiOMdCHl#y7o?3XXg8JRUAa*7NP;@|`tR5f_9@cx`9}PWE4TffK1p&t!3P1dc~A6jhI*yB!r*I{ZteeG%)D*#BgF5%s|mk zC$l=&CR-ut!MgHHu7KR78kain3GUP`)C!KuAhioG;04+1ygF^w&YCTW(IY=twzTQ+ zfyRbTLvUL1>F0P-wr2L@d(78cp856B)$7--dUtM9XkL30%{V^AU!j@YIX&Yj{jGpt zyQg`~or7cY@VbGBM2Y@H0#cW(o>|nyEkKnsH^GMs?HUa*f1zG*0_^fVu!|Y_(R*iX zlfWjrDuZh=Rb^3Vl+e*eAAa8SqUl`|;Z46XF&m9LjlVGx5h}*WzsEBKF}(~UarQ_4 zOLnyeH*sCzd+y!U)x*15X(icfNwz`A59C-RJ?zu7c*W%H(AJ~e+`<+SCU)$w?B zXJ>TWJt6apgL!E4vppjb2|zhs9^z7gd%Tl zk_5B>ox%bE7gJ5{O1jlTHKo?8Qh=$Nb!-GYAKn>)RS}s&0{7~85`W?LKP5Nb>xtyTLfSN*7OwMr(Tvz?45SM9j6wvQ0g?adxic294zm+ZUQJh|d0C;x^ zb!a22$Zm20>ue(iKJLG12SHR6<&6U#cLl*E#Y+Y@DQWx?`ejVo@n#M@!f=(_LMwJw~!>gl?L z^XCwYuU8<78laQ5LE^#U`;f8@W-yw|#OOmKHWyJ4__0Y}Nh;Dih|O)$R)`@WJV%zh z&KyUUy`w|eXhtmhegTFkBKp3h6|+zgPgcVq+WXr2a$j%nyyp)*Y+x*B4lju}X4bH4 znK#B_3-IX;WNsn((ICkmyVZ{Y7Kk>Rhl~GkIG_%yXI1u^d!L*Bv;ak0$1d6* z4A>M)N5Uk};-P^kbeVa-|5kNj;(nj)NGf!n$C`Y!THVsT2xe zB9R&rHnyufTM&;`0fFT{C_jP<nCg5BkvUlYNjCvb94@;6fOagcp#);&!{@qNnybbSP%NhN;s>HVJGs1~ zDdg+z{6=F++TNAFzsbPcET@OkJf(Pnpv3CL$cuQNz7#}>a3Ie#;oC{T}e_7 zf90QW`V;!am@`f&cXG)os_!7+!(Zf*WVLHX zeT-4gfC?HBr^E)BVV2awPB;LAAkCt$(!KNql_VzxF8`1~PqrOl7a}a4#`cnH`QV|U zp%e~4eX{$984a}974glDjlTt^1GPj7So%@O4&5V z+zbMYnTjXL258$|kD#cYB-uP?e-&#M)QnB|h5xe{skd2VCsC{g3CYFo66Q zqc~(mQ7(G;kQu-q!Z1K36wO)`mmENrgo(sy2nU#y)jA`30uCK3U4&mpG?ctFc3qk- z{{;oHoZK*{%hXS)LpJ0s@=jUW>U`Zv9ZthZW!0~~sWKk$L0PaSNNWl}D)p68g}Gy( z+VuR8VHzUe!iH}!wi%QdMMkC3U`X6BSWzek%0eb{>6$w~l}|O6pC5{b#21o@>Ldwi zp`s9L2(^Xi?hu6D(V$*y)umJ?LHlex5a8N`$kd{#cN^+mcO^|9`{Re*J65i~ zdT@2`&fb0Lw=>V?LtEYKC3|a%leGiu>Sn>N-+kKtJj{TPK3@OAcfPm3_mE$^cm(FW z@L9*q8QqT_&9whv=_~W+V#Z&@jMvJ;SfV&NZ>}vU^%(#~K)S!lj*8P2mn!~VA#JXJ zvVxj|+5%P<91NZfUJgozADaA2{WRc#Mo))__BggUXmK=T2$M}6gcRBoTUn?O^pMR} z9$gjQ5T+!og@?iy!qSYF!@I&X99D~s=p;7){^2k~rl?WHR7Co9yDLc)(D2^|<(48{ zQ$UH|_siPpOV&6tIwXb>TxA_}DoZPC7J#gTS;GkmH~+FZeOS0tA@AA*k!OEm!c+}M z72#H-+LcRJ4gX+qXT0QpbXRLo6jvJUd%LF}^g#E#8ipBWdfww84#Lc^Lt^MCK5!KS zDw0a!BML51O0)pQCly5`W)0#>!S2SOrAbyzf}$I#eMl)%x=W1vh#QT%iM3m542io{ zyQx$;&EDGsCVzIOYHoK|_uP9=pYJ>8oGnncmu$~WA6+~jn9meA8`Qf?v!n79cuD=w zr!6~U&(v2Qf=!8iyUJHCDSoyAP&F@I1F!Z~-tX%J^LI3CDqMhT6E!#5fw0XW_9~0# zS%66tWtK6sVk*m|qGMif=6Ss-y_N@a`DHxhSrK)9(veQ4>R}4&XMmrHG0n^khFZ&j z5(Y3Pf=$(ntc)HbGWB6`#1IdU#f@mYP#&t*rW1nM~p)LJTxoT7zr5CNiADLxOcKqwNKvfU^!behd+rNkl+Es3r>Y@rJ+d6G?oyGrl$mxc{e{FIW1J)iM%|`J6=v)F4BH5({NB@ z5Rm?){VhNolag^QU_hYi40O^4Q{grBSI%CoUsH{Sq4l+ck!Kn<7Urqz8{>I-ap-<< z@J+kA73|6C?Yw)pv&R8;sXOe4-uV0L)s6C#hjPnWl{C4Us`u}&ZbB8iZ2W=l0p&+X z+8bHfRol78z7$HD$GBk=-WHlLmUYcR9G50Uf&Ubg+#)L>?!} zW*X2e;T65ePuU z#WgWhgzy^xmqM@BOi6NkxV3 zKt;uel}~(*AKQ^!{ zjZ(xcqcgLJjwC;@nt>nRY4Mva7Qf^(1u4J9W|x_OpEg@ka_nh5XQ${iUl`p`5SSZS z79ayA--Y1EK_~Zh>PTA*|y!Py`6$1~{aZy=HGTUjsI5z+qI}-cAh< zi|xb1Ny%AWrAxk!0uAkG6f-x9R5%$Km_Sl|EFhnpcq7!l{F&V)#qOAMp_H;Yp05@@ z{6~tk&>3?Vmvqm}2P4|)w35P0rE5&RX{DYzSzl3l>CcHj0V_CB?=4O1HLXGCFs$BJ zE6}+GF?h9FtGlE1#UOD~SrrNt2I>M^0+i1a^;CPBJe1EFbyho@oK(nGXsferu~D1T z!JrZJ7(lNc{Dub|JTepKD9CIg+etVD#SH;EAxx#&G@pa!xGaZ>q-Bm1to{iaTbPtc zD`G{+*Wr_=`w(8msJ{gelZ}L%IDSr6^a75V z*9Xv;aen*?3OhnX!dD^g1Jlt?d4tUWyScYH*usLJ!D9#-m<3@PA}j8Ne7ap=C?CV{ zCT|j-0dFv(;grFpMhLIX%PYL%of>iSMf@Uu1yAv)M^B1y_W#2xS@M{!;`g0VOj;Ud z(#A}>n84#jm1jrmR~_rP{Af?>;N0@Jjx3%%r~Js#@?z*#UvHb5rfvakj>DZdL12IL zFAjeDPW_J7`jaQtweDJn)wM<~(^Vm_7$Qz73+99>LNy^WIsThG)2;_4znOh zUYj4;^#(K}GJlXErgDDS3j{ClhO3gsZ^PIPj0I7Y7@4qmMPs-dB4J*x5l9@v=6!-h z40K@y)__RIR_|#=Vy71fc##hjeF!s3S9RfK_158yEz_qpuK)HA-|cJs^pgG%On4$P|(7`YqaG=1!>SW9gL^+m7g{&-deOx~`#8F(hDlvrL{|)R6G?PCz zf>!J@xC}_=5dB?L+mnC7{)?*dB6&xbsurqSKTXu2IRLR&t%Z+}iu1%8#iL{FDCYos z3eBa_zK^xpWFnU!ITBCl;}lM-&0uzf;6U+p4t&l5f)lx1?lDKP91a&)Cp0YanpXU9 zQHk#t<-v=BkJK`-{p{7Va5Z^AeW;!pe6m~jJIwF#$JDr%1^!2Mxd1nDU1507y{ldA zOWKvRl59z96etO*O9-?>VFE)-%LGb0DWP?trIW!0FTGbX(9CF7tB0+7|9j4VzW=l2T2Uk} z8Zsr(BZYzzc_oyYVUKBsgP~BFtaxNunJ594z}{eh5)2t(QI-T#EYu7g7aEv!$slvM ziBFo4FdNL3X0OS%hgXKtcw?6F3P}`7LTOO&X$1x;!%l_T)&HRLTR=^*;jMF8dNP^kV!2@Nh$sdr(a^ai9kY zi^t%@qzg%--PcPag{61cp?#cxA={Z~@C^tTl=ZUp=&o-8+gbbeyEZQR?{EnIXt^l+c0ms;~&Et|h)j7k#jATp7o@!e~8TeJ&B{X3A5{#dY{TvUF zkeNt)Qw4J7WUxnS$SjYrqVwRAEbYDj|u)@0NAcWn1($1Z+jWM(!3Y`Ves9(`<>i9h!PUtX7hc4yE3Q7~FSeb|Oh6hdtE(Y*` zz>|SD1KR>@!0Y#WHBXR{Dy0?)+a*a8y+ITBAnO!7c^=g3fqYM?XO3r)hxJH;7IUhN z>NFLLSXG0JHjxu9nFH-57ZN>)I%Vp zMN`IPAt*)1Q>4gSWop%!Ix*=AHO9oq6Gs>*S0HYeEpv8{HFd(eHaMJGlc+uf&6Z`| z+`svq39YNP@4t2_v#<>k)})_w?UkYTEcj6UkhNA3T!v*euwCr?H4?_3TEDg_eQLk; z7wca{>8A;iris#S=1OwCUxG~v2rAeYxmURn>-M+{-SuwvqVT1F;=*uYqkvx$ffs!u zQv71Eh&G8}6Lm2rVy7UN$S9eXSIVeF?v)Ymc-4V+I)33mUI%dG;q*F@hIo;nfy0hn zgpVAGU}tTNOLdtp?8GjHm^yi=952dFRJ_76f zd;N$(V7JMtq*j+W5)M@2O1O~Z3b;^1v?+=>!{(5j1$l;|2{A)QVUvKM6Y);Ni0e|! zd@T-4T#Z-8u@W!#njE8>IvQr`mHKmfi@r`jr{B`~=k)3NUUJLQPm_9v++Ni=UhntX zOm_08`aY$FR`mik+f0T=p{lAnI_+t-<&dZ>MyoAS6Cu!3)SrdoH1nug2B+bN6rxte zEpD1;eRCK&eKbO^Rpwr`fca1+U{e(cdxasw{O@zz47Evj~@MGC;Pp- zm#n*~v8(azyC-hJV!V$kwwx#yB~zt@%=aJeD1e=QXmEYyLS?R67uqa9S^zIvfI87e z#D3IZg5AWq8K5dn+&MrS0b@u z=M&D6PAoZrcd7;?jp@cM12e`tW3Pb?qpY+)yAWYgJr`P2t$m-W7YHY1XonJ!d{smk zB3QOJvlIURM5@V&L^XK;)H#)MH(a!7zIFXx5}!UWGV${H8$>4S@JC}G8`4o1Ol?~S67!c zovNOJWLIS0k*LP@4qd<; zKIq8wbgi!Jh*CcV;(PLs8+W*B^ftToCsB@>;YjiEy!JlhGUM93FP1%$#ujw93? z)S!R?(e2KUKsh5Dj;vGtql?WyWF$Ov`6?6@Rr)*ddJB71h- z^gQs51I6Q;=C(|pRS+tF>U|OnYs_bLv8;L-_zxgoeQEh))icI#fq@^5YawxPOu;t`E~e$Hdslamtu20z*??~>6dd5Vm72~Z*=gtX8uus4MN3W!DZXgQ+U z#pYBDkJqcYkY>-ecAO4ILPtCkaI2(!wMuQTmeI~>HoHdln8{IDHk#BuJdxZ8XoW|0 zrV)yyA*D(q^yu^2VE>2KpR5A-{PXsu)|PF*@9zG?LD0L};2CSf@%_73tN}aRYVI3s zJKDEz#%BZ<5hLEePI!6^Q$&_?Ci!N*pLo>dVwf0*1#!p=m4q5XO`)$sy&-ODKHPCb zvumzvu?sJfSIJxC2T!ZHtt6))X!k*+I9d_+73Kw}SAequ_=*a)G#KU`!8*Q?pT=We z(1NTah`xBBa7Qr|N1|J!5G^m%3!M~C2fkMh-Ajxr4 z>!vkJ*@@0cGAI)X`u^jUZT%8uuVs*pCFJ<^Xtoq`ZCFkFvcI4Q4fb)oH%7jag(!Tv z{q-wjKK2gXRFjyII9|PG%&@YL4_kkqH}k^}eh?qpUhwVt)+eLVQy0Cw4Ees^^#07z zGoBhc^R@ZAUjNQH>#b4sqrWv{_P}}XEO}z|lP{85nS1|l?0-nQt786|e2YU~L;xwD zTgBm#0!RW()Pa%*8ezhu5@;$_~BOUAPEV@87Q zI7^NtA`MWs@w)+ITYw#Z9bKUbxwNH)&@BtlTnlSyHeehq^x(!4);qRByN;z@NOy2K zV3$!^u7fddl+JlGQnMtUNcTTrpGf=+s; zdpo^7-aaqujanWnXwe=kXC1U&vqmiTIcv8?e*-)m;|rmt5DJw>HB6=D^y6t5YSPQn zJJS2pLun6>)2S#USl)6uX;dc*O)?0|sEgVT6;K;WmX#+>9{F580MKv9BW;DYIY!W> z@|LCz2GT(Zyz&iDCD17gmXNr@(z{AEm&mzD6JWV`jv}>5OyV8SSV%-&kookDUpt?? z-2Zt4l0VAUcP#2Tbhz{l5l#FAP21dbcJa}(Ed$R!^8A7ITPg-~=>rELF31{&D;*CRNa(KWSPSz?K8KV`%DZz ziuTKT2vd5cT`4P}Y-PDldrdAbS(Hyhyq5A?rE$w-kdHx30ZUlOBLx)GDau6^fOLgO z0Y|j7)m0sC;U+vWQ@IaA>pl$4I_CW`=fwD-F9WZyb1Tx$MC;J8>v_~3%cJ)1dqDfy zv^twG0Sn#aA~1B6iczoFKl&<-g0?=6FGkai&omSGgDu~iD5y9tN#Fq&6abTeU7`o^3ky3$mN&wfxwt$s zDV>?B?M3NZe@E%P+SE*1X;}W`{^7>?bEk~#cdnklz?QX7$fO&czVV8|LHYt()0kFT z+TZMd_uc-_-$UaL25eNoW`JoV*r4gJQ?c70+bxw7vxW>i4zPKG|2cn%XVqY3us(=` z(PT6i#T5oh#?UGrRhj4k&>hDUY~e0^BuYI1!b_##qX0%d65p>B$Oe8014{w)0C_SBU0T<4Ut zYTGun8|CJvm4%SIUAy{kwH`YLnOl1M8ruUMI|%OZZ+52FLftXc9YMV+q65u=7X$qP zW-m9$(R0{+>~C3cy3O>9bU)2-bV*4G9b^<>%cJqhSu)yD)yOJZl=91dNQd9g6h%ck z4(uw03dH(*;8m&|F1}E>>FiN*&+*$I+6H{}l7hA>XoG@gD2tTU3RaAy=|Mh^;h{Z* zFVe2;26W2qI+tPB6DoO^m`SAoML0rB?h-H21EwO^0qko471r%rEr_SsFRPa#YTJ3FAyWlw!JxYB#X=DZV4q}2bjVXuR;*-mQ8YtFE94HD z&K04D+3&El2L(|Q;gEhwN1OE>I<4!pp!1vp+^MR5pWx5;{+Q1)m?mZpvy@>NB1}o= zA68tcmq!2qDo8!(?*s(`giI!%$YlZ(TyBIgPn%pVFlZ>qR5_v}(|exY_N~EB*Zl-$ zpKEQ|)x2@)p(|@QpbgGix)I&f*aNJ0_V>q}bhc-cO$PnfqD=2{A>wI8a-pf=d^ zg)&4W-{P|Wl`&71A&-G_#&lz$@tMJN8i@7w z&M^F)3YeP#b5p1;+wcj5KQM;{V*xdB&7P zZAOW6aV4g(0oY^1x#C<~xo1TZC6KxjMe*)it5#It;+@DuJ6BXVH}6zpFH~Zjx@nhC z0Xaa2S)JoGUKNF~5C(cY8jWRP{Mi0(NifTs5b-h`1;a??Q5ddF2w@=Ku&8o66Bc}W zDW`=!ydcJ)HmNW#)M+!cMH<$)#GmvtI@rr~dY6tRtm_F&C{YulEfRi6R%PAMnBb0f z7=DBjQR9$!R=g}?TSTTt8YZ&wm|1hg5X&zZ-x0MZGnmio=>lniXPxJb!X zXHakdzl$YUS2dm!YEd5=Z~w-Et@p5YJF4B-bJmc*}D$Dye`$4$#8Y(x^A<_iN=lN zxJ)Lq+js^>@F($mjrpCMj;!?wf0<~)e$K3Pyh^KB99e93V(g29VA&v;?3(3ja?vZ| z*CJ^Z;a^#SyMt131p#-!>jg)^Cins%dputIfZvoj-R&)?Mh{z(%zDi9eR##$0@rC- z2el{?!NRg~G{7o2c_I;7W!&mZ&7*Y5>Ru3xyK8I4D$r!KhJb;yqowa|TgT4&r`K*Z z&YJtK!+npm_T88mbJcgtM>hIkifguOxr@$`V5I~bDSSnMCmYB%LPdK(mU%Vc5rhCQ z%d+aQ6=Zjw;27>*P)n>$_y7N{r)4z>lA(qN9;t|gy*QWx11CIVT1Drj`ixuP1Qs${ zp-CBAv(~r^LhtG&#M{@>u@fHKy7uY%ogHnM{oSbc{wWS7!%U0>Klf8u3v;>rgbz5U z+ZlE)bgpsoiqi??2>|B_5fX5ILUt`>{|+mY*OHIzjUPD{d3!x7Um#GX~=R zf^mU_0&DDPI|)9#+k+@Pm6tO&aMHpQyIR+>{fwUp)znL1?q5X$HJa-YlH zmit~VFKC)JNqbW}s_{iGI3Yuk3`YsX3B>Y)(WoL-cv?N%J;YNsC|Eg6RTVnC5DLTL z;y{p15S~X(BiV+<-72Wzf`XEGe!ecC(+oS%h2p6ai5scM!wyg!;4rz}JX-5St8g$e z(Vb4Z5e>^sibSSMR^wnUlgNAcbAOg2vjux!2o;*2xa#I2VI;|DSQJ#ZUyEQ{4_C1m zd=XW%+|w}CT^Ns;co_+E@{{K;7~RIbd-sfcM)!sD&<6FO?RX`1+W79ZbuF(0d#Pzv z4T506c&27m(@Vf!Z&~-6@!jdvD?3o#)I%G&V!VCvQdifdi|{NYp=)#V%A zJw?T1Ks|WSxHG1>Xiq1WpxD_xvw5>I-RuxI*4j7NAvzpR)NvX(1e(YRlwYN{==T)M z7D{L}t))1$(_NI>X&x=6$b&AZQ0^(jr$D{}lvBXX`Jsp@)a7Tqu1W&oWiSmw1&T5b zV3Y`xfrtPygF!$TKmdT&Ycn;n&kv9If%w7BG(S*JOf?C=H?bJ^LFpE{hrUbMw-n43 z*+>6Kzov8?ZKNr>k+K%@H$tY8732h=V+kBr;7w(pLKKRSukKQRr}n6?3{`+ zU&MSpq)fbwZN=Z|zt;Z|K1SOaXv1mRiFvk z=ki3i%~32UitG+3dbM7w)8Pt^?fM6LM(3;bW}P(aJ-DW69dwz?K{9c_$}R$=noc5uppYzQkK2;?NP@A0>^^RFo73h6l*@9C%8F z@d`XeTPgW10~>>PAPrx!StO!} zB01=#GKmF=%_fDz5l)Z$3*%f-FcNn*3+=)#ftt>=TBsEogl3^fxFci)n@k0V6t*R7 zrr^yBmYefYx34^G16xUQK-Bi9ub6`NZ2ws-t}C~*CJxhAZ7t36vgWf{2Xyu!j$0of zCWcef?jYh1d!W=ra$kv9815Bon~gkU-+^B`{&eQdMP>N2yMKNDv+cVoPfs-7|9Dl( zL2~-9%kx)%4AZ8qJ+Rb7jADbN^51&#*TvV5p4SYFUl zK$T#z6p1+OoI4hd)y1aA*2K~=Ar|v8e@HLE%52w}uCv^LS9A!`0JGa=B^(M9k%q&u zV5C4wD3X+LdCEglwbUbBm+naXbp$null20BtRRG&EOg1SUORC1u>FReeqaZ?S(GT} zK2Hv$I*Bq_EwfPf)tB1IQI%zQTQmORcXz@c8g?LU;4 ze{2)y8OPt}eeZ|gOYVI3-NnB1Vc$U<3ZY9z0w{&ZW+NeN(n6;O0aKQ21IiDfkRT|u z>Jq^qZJ9)?qEhIzWzrNDwl2{K3??=r1{wcQn3#h4M@KXv3RAPP3AD9c%$~CoAQV7Z=uz6tP zT1h_GeKj{*D9bGwd1?2GZ~fGL|9dO;9?11V2dY^Q39%>wKZ^xDUMA|4yhqklZ$CsVj)qXz{QZP6;pxmFq70GrKptwVLGeCm34rP zGU+LnRwRi-S(xl6`9ww{p)y{9QKPv4chwl$bS{dK|BKa-%+OEf0#l(gyw_Y9m;Xj9I?S+PSe?36o?#*d%`{?*O^x0PUC};f{ zpVYyeb`z(3@T7mw?&7j7(|;+@r(k;uo|yF(!P25YfU8Bq*XU|WkJ3*mT_&%R=`Uoc zQ{k}+NT`4^Re=Ep5-Y(jpH@W4lBgU!erXnyI0XVl44=QWz;4$4a&IQIZJw&vP-Y0vaL}S?;)G}qlzUh(KaZhr+spL(0At%!_glXnj3AK zG#={s3Np3>orgNYoa~kLCiKa0l)_>8s7yby;2jH=S@8T92`dG{Dvt+DnuXhVv6(=8YUUiLfS|t`3bp48YyoXaPM_N~J2ikk;sLIrep!bagxh&8eUE4n4R5W2=*1(MaM*-T~ zgUr+1{-6xTlro4rCj5IWcWrPGR`osNVi+m(J2?H2n|BZ*%|bWFNdgvR|FXh?Ugv~E zPudr3d;uc{dt)GBryYsihzTPlaMgmDkp&SNiol2h^ObsKg~Bc<@EkwDf5zD?p+?vs zuo_{RKwlFM3r7X!7^dMR95dnAC02=-u+2om7DLHIiD8(s?IbO%u&jmfUA#4skUUw| zz%#8`*NnY|{H zH<&w3YA)BdXw=gntU*Yt2tsyM5HC^8peF748nhQyJFEk)cUXt2s?0e7qi6mbI)c*T!JjctFPn*_z!7Cxc!9A1d=Mh|BF*~4U$30KwPyX8;cgMe3Gk!~WcKoxTIxiw4fQ;D0 zCI2|C>vBl_x(UZJ zt+eZyuIq>)ci4qG7s_35t!UJcokY25NFb{U-iDuXT`4WgDx_oPOq37jl7}6-6;oRe zxlAOIEKVOmo^&RMeE4E*VNS*r`OV!*P%H$*trb^JHSyN)%j9?e~1@8vFzu4>A?oogJaAKsVS00;LC z*Vo_Oyj6$Ka-zO<^Ii6h+-sBl`z|_u8u8%8?7bB!=uMqS(Ss>CnY@ssCzD{fu-662 zEpdC@5%-2GjwC=zz*Ps72sn}1k-tSgjR>nF@Vm&x$OjSDe;);kAp8J9ppRleS93_k z?YQTqOfQv8I0?^7n)r_#c!@~z_4rVn#^bh}OeHPHrZSjJLqr_>kmpSj;gmXbiSwLu z$6;HY-3~qNfTJT4(~$+c&Tg{z*upgXX`4zmNOqb1md$qBV28B|Eu(d6`?Y>eYSh~D zr)RW}HA#zQOAK$h*=lYv88LOU#~d(+Oi?xwl|u6h2r0mlUt1rkXAJ8(8JWi(Lknqt zzzf>qJ~NMlW}=x*k|W=pBo`blo$6sdrPGAuz`||r9+!UTL7m^^Q^7a=QlELTcr5LE zrthU3+e!N=)Av)z(+wZi`tWu9*^XWwi^b)XS8kheNd|+d3f_w!^!*8_KCxkez0{_5 zhBV@gVU77QbBPEoxh2swF<{gHV(7+ggM}^`&}Qt%WPv0G6MuYY7-K+tM-aV(ywow7o$@uAi;>`o zMICzrruQigzV7p&&bVL730kG?6SOY-&)^{a$`gUTzB#u6XOuVvT1wXCo)vb#~aWu;my7RU_Nh*>cRUTL|w8o#QOEy^wzS_MjkN+BzB39kzS z!jK>L5S~PYluDVn z5~|fnt~pXe8Q{xYWd&tq8E$3#Vw^wk0~UV5Hjeu@fm<2J87iX$yJ6fbtCFU=Y?eiF z>o=Bo+VkN@HtUql5+`uVicetY_dwL@isK(y%Hvb9(d53C{G`He43Hi&WG(`{l4~=K zp`fVbtxQkYlSO&5awJ8KLoOklBY8ZLAXesRM7dVNm^w2DhcW!J5t&Tnn|~ht{6bed zI5zcKbIt1GGSC;d&W;St;}SPxudHZ)dGiS{*tud~tS8)B99{aIuD1F|U5?XL;Ov=Q zKN{P<7v&|c0n1x&{rl-er6sF!b8BtIs=C#4YX)DhivoRrb?Gt2Fu#0pdqr6&x^nrf zJn+f-&XMsh_Xn6Y&ctG}Pc?>FQww&Sc$c2arcRvC?4gNI< zn|#1(C^6I;$n6=sGlnwAYZ-Sk;2YY9nUW>XskV18fT1hwIxgb2pKy#ipu@V< zX)Y<`QQsp^P@#;JayyA z!3AZ3U}JQZUJHHzNXF-#v+%KD?2Q^8-~ZgA#*>E{>t=|xrEW)8Z3W(BORyKaj(vlf zI3TZx7^)2Luntt|Kr;gS0qDc0*8zzD5cCeHQc)(3ffP;hE~=gb9LJbk1!h2)c^q8K zRyDhhJc>x2rW; zTCdK?rkw()7g~f4VXr_50&B^>iN$h8w;rhVQGKI+ou1O`vb*slX`|Xk?K&-`-Nynp zfMbx7Kx64R8tY0e4WIGy@WK?Yj>%_K6h+B9S>!_tLo>WR+s5CSu6%#^l(hAo#BAFz zbiLQu`{+WHcoy^k3n@+h^HuW5WV8Ng-OnJ4LqqHI-&B`X6NEsxhyZb1UbQ;_Y_k^3 zS~iQ!%&W>uqjh(eoJ>STb60UYCGAQMpBR8Ud$ zRHp@H>rKhCGL4twg$1#sD6hDu$vjfKl@3cv#BjUJCM2ab7f%O;2L#WHi0@6xz!XJQ zmq*4D?|pRS7xfF?J_G7O_2|1F8lD=s^4Y#^nZ0`(K<&yMvE|RKO#HH8u$SxJ{nh3E zo$yLxq_6t`?vqSdSG4EK=s8vhX!9DFpibe*Qgw7F2P}6 zl}~&lH){M=KMeTFebAL#kPFv)yS)&3&0fe(m~We5lL-)+d?w@!P6Pad@Gk+9oZhL2 zgpSw26KcSzoT?txUKPawCpZg8z1nS`DbG}}3(!J%rp-=>yjUR0VuRQz_KN$&QBh+g zMUgVvS(Im|w04igJH<5KF3}t22qys%NdzpCNXxV=`om7ToUW%^Xo?QpRka|0;l9K@ z+=6i*k$jHH*pg~OOYCk#Qr$?38DEstrU!drO7%jz-wP_|=2HW=cYXJb7tY=2?>Q^X zZ+^bNdA`t46FL`Zsg~D9&V?2(rfZiR*uSI(W+eu`H}BwqJ0RzW+g=(R>aAP5wyrn0 zW>w*u&`YiD9j$muHQ3k2Fq1QgS56UXyj3hS*usc6n8RKKj`3gfkaP$n4L7kn*gY)C zBAQi8PE?Ly0Ck{)h(w4!jD<;}dMI#}0(j3cQjnsyQnx7*aTLg)D4H;8B#fQ16KQyR z_z}8^hWD}K&kH3jiUaJzMv{-ml0zKF2#$A^mn)zt;t!Al0`Pzkwt_gnVQ|#3=8a{I z{zU$-r+)K$@Jztr3V_;$N1s+T?yBkhwo!HZ+t2!*+`N1g7K zGhbypExtE%3d+{ClNb6cwoYEBq^VsS+Lv^L^G_7aot{oH0Oi3beU%`9nO+1}gAIiD zBm^hS!2GM}QGzBS(_do1%rrF*KxjS%-9#>-c-&Ydf-5AkRgK{aU!*F4F@hihvKE2@ zD{xtRaZpj}AYA7!vc_sn)v=v|S$FGfjzknaSe;nR`~$PmLqxDcFOpx|pavzbS{Ho0 zctbI?75|6w@{eueJmdJi_nz;3jvd=c?rd!5a&a6xImdD0v-8uLFD6O1L4Gg>>jGXf zsnC#6HA#U|L6xW?MWHQ4g3_g%N2kH8iYwNMC<7S{c-PNGcJq@_OyrR{#S zT`qg>?C|4{ZQXmi_g=rc^B>Rid7tO|m1@WzHN4tD8XCBU;s(6F@o*z)Xyh7;8?o`b zEswU4rWRKV$!76xp0xD4husI<*x^QQhu>Z0hFSqj+U<7of|W}h?9kjvi zbQU}KJcol9yaqR>c@y?{fe+g1FcwOU>?8Hc4qhJsNWUdT*| z8MrU%K1y>;&)P2RH9BoU11z)>ve$S4fw<~Q5t_uRtoTU^>9}M@h6-A*D*?T1z*YSa zBzg~si2=V|YXKbe0Bj5RVTYmZnoi>2Bhy^~si{o8vC^CRWmL(lFYBwY`zaQyPrP}v zyr3ZX^OADl>YKyU7uC1bw=YhgnMQ4>ZTigR{^wK}&-D+De){R?P#U~Ho>6|qpRld= z^qO2os$_9&=;_@%&uygz~((+0$IsjBzqIS(L;$o*OTUV{@&iwyYM%UBff%Adx!)?(u4pXkWJv?0XEW2WZ|LZf8iv} z2mqofzm(1hl#&0B5luM9mUT9#^(M`m#g?_S#t3Wvc8px!wdad3_Uzg{a`*1Y?z7En zj~-pyoSy#|9gF+^dFaS0=wg}2slMS=!+obtZH32HaAzBrM(H+MCUSv{3rbrK=_N^h z$~T6LFrj>N$V}=}PL4MxJz2PCIg)e_x=A9xKcC!Fh%80V7LgXpsW7&vlXnSL#cm-* zEtLZ7h+aW3V8-O-?HFT1a9N=7nevu}nN1UB#UB5IqU`oPNv7w}o=&7Zw|EisfHNVx z=2{mcbHTJI(8oafLN>ynWyMF>ZA7uA2`B>FinT4uZZl{bKDrG~+=mr|+bYz*sFzU{ z@>Fc!R)O+S-DR~Wx_OJNZbb)UkM~5;tK>~}R(+d|4??G3ZUbK=y(A-wF3Q+N0a&?X$d%itn$5~c1nLV97myHi)Ba3O$G;NwQQHM;(!sIg{22+MS0~sMv zlKcS);~4n{`6daC(xbp>@j%c$IZB?5_AMVEpWo~0pbZ-IV1NLnJZI`y&9NJD5b*#JRiZu9?bhW4Zr?7fzP`c97eRe*wVPoW@`ABL*WS-3Z z{R@Xnd$*Jx-uDM>)z=5B_fYk!*43-ktLp5kw$@gN`V&ikWnD}VqTY;NQfAru74@a{ zTk0vT-}TmDE>axX6v1?u5BtNL!xUDm)&eVO#8xZEa*ELsJ;0#^_iK>FTmhHh+PN<7 z7I%kR;*3_zu}V&H)XIk01l!J1R<;0^=h=7JJM0q6)P&hCc8GnMJ;L5%X%;7fdxD38 z$AdW75E2w=k90^nE@3HIf=#iy*!N?dF)CIq3yNojP%4ZHXN6h8U>4%SYGI@B3&Fr( zL1c3@>zPBC6GqL{LyRwb+?lrDv`VMTHJB<;--*gqhhmS&_s zOOzxzV}jtT^%G8;Q*>g+`ADT7TC5eitbVq@$U>IwdXB;6=F~dFx&U8Zx#sl4cQc)K z?S##^S{G;J6qv%4UA`TOz?>L_tiuaoU6u!l`yZzj7O+4U74lr3rom&;D!EXfBYeg| z(M8J*G~$4Is`XA=VWgUuMZ4Bay-c7=hR#ao*3_tDs74>?aeaZA(^Kl?$8VhZSe=|Y zeeOJ3GjU*3YP$!~x637X$IqJF(SwdueFT66v!ebJX>IA1d9%RIlitxjCJ z{@7#JFQG?K_q7}A_BTw7sefPm&Hnx5YGfLlXxP8*#xn2=j8t%8w{{%&zUN+KZE~=Le4T}3nq=A59Ld_)00f=OIc`{iJKxhjzvwe8s z<0i!)OXtIHuMcG4DT?ElqZ=i?ZeFTUmL$XINs7S ze(=k$UO8Gd5>R{9p6+h+GjupGQg!qd0;$#1K{RVvPh=766dQ&N5Mar&AP-rLLTSOv zcjiaIyLC}df{S~Xx<%cgXo{hXO4cw*n}7f!F*BouVg`lh1_tj(&vrAV1&1jL6lHES z+vyE|5Z3Qb!}_;2!FUTi0@OIuBa96^!d2ZPd}QcA=LlXgAtISD1DdG$o~_V4g$+E# zf?++pe=Yq!xfMJ`6WDgX*4zXM87q5#{zc?HUx}~`G_g;8A50SQ7N*kCI+je zMJ)(B5+Ma4)Top{O4}$EX+^0)RJa64)db-R;!wg_NN?i_evK58P4PvF+i}wl4P-f2eqLq^=}Jns*|5_OVb~1^fB{A; z^A`GCmTnaLe0fmXhIW)g`h61l_^=QpQs{@J0HT$GwW~RJFH4?W4Dk2JLG%u&e~k)%NfX_F5gZcUEoD-n=jFq zC2&!wr`zb?=zS_3fMak{e9?4UQKow|x9$mw46xh9vYki-2>go6Wx_0y&u0~xjV3k2 zQ%Mxh%oE=T-93{j@^M^ezi%?ybJ?wvks%SZwH2q{+qMbA`0ef8^z&&SicMW-nEgDdIwLy(;)8VKN1v+SYfxcYdpx@LvT205pFLBLHKsQv?XMv)+ zt-(ik;&YGz{@#Ma7RY+8PTyDIgnC+~Zi(v#sEXy&G=f20jD%4lel2WXPFPNT22TV8 z4K)t=oD5aZ0AN6$zw(etHX`UrH!}N`8EP-(Whs8PGbVrH`~?}uE07bceyr0I>$AJ0&K(g~$=;Pf_K^nftIq3sf#{WnR5;;Q*G;p3_ z*UV$f7zN_uhF+wHb*AbXxU%q+ypAsb;p_P5?hph-oibAn1Y*&MC}fr`Dh|w>`FU$k z&-}mCk4PWXmsR#3+Ke%nep@;VYvl-0$h5eN3^5rb8CYh|WD++VN)~*GUsK`_SW$lo ztWDk6vxk=RSReHE3H@KAe#ewP8zP*_oWe8ufmjLtMWJI)>IN;}Bc1Kr(?`^aQ2Jf= z5&sQwVf8WtIrm($fHaXday#C>cv1e+=JI)U(MWmAiaAvkQeMS&GdpKC2CHCn^1RAa4m)1A1#pg`be02dTghg24- z0$y>x>S`4wRjaC~QZ+y3^Tz7jX0(okhlYpDkzoY)Q9+wAh^9`hK=&e?EM8Je7kDJjCYyI5sRgHTQ5#2=F54 zv6l1}c1o6r2Tw=|nS=gnChepPJn=UdEnd>Fx?}yCu1=O%9gWSatzIxcyt>V+o4!!x z>`=wbS!KbB5LaAGl?ljdsGYQ$t+chRkd&Auw4^w{r7c!FKRlN$sGd<+l3y*W3U?C* zF0NEBCQW7&ZCcVmY}2NSZR);;bsZbluTHG#>{`*%x~i)xRKY4|&k9z~?g}H3+R?xo zNH{S%k{r2WA-0&K!u-idef>z}O2izwn7q=JFq6r|Wn2;wbI5+DRyp+}7`vB;g&1>u za&&lVm*kgMqF{2vj80}!01}=)#Zk&c^^_AR4fw@DbaL?+)YR7bWq%a8Qdw=RrVN+h zv?5Yuog@2gr;cSRuV`*G7R^**vDz3a2SrXTs}m`;td12nI{6iIYPWuKb7a|yYhTk| z`SHN=1&tF&kFIH2(L&!WXtXlI=7+u8H%E0ND8>=7#1d=i8|9VFD_V}GwU=s|S{6?3 zCH*d|^%5$if+#Mpq#FmG>k}#u&O}3xAKA=)wEYRiRDWi-iBG1s?|%Hqt;oKQBlozW zSa`x6ax>nf$Q|;_@@um6nf!%JRdv0(Rqa)!JL)}^{z<)|(mZdumvS2n+iw?}hHaXL zt5Ir`Xjl^6RY{VRv-B9Dv?Q*h*zcoGp>C=k9f9!JsbN9x@FrekavRVx?2S_U*g>R_Yuak@h~^#m_!`P1^rp9Idu5eNFlq9~4%D zz4488@=~-Ldtd%o{!C``)MaQlCd_q5WxrGhReDr|=e;0%bG>xE7hW~tvAI`r9mH?BDV@7wEd!pI5`9$IFr#KzyRF^Tn3it`Nya;jSRnjWZQZpb^{NF{ zxEo1A57s%D@2n_d@DNT5=yAmtM&|$)h=%7%x8cJP9$ruSwxif@6k+oNj2?08m zPkFWn5*fOO%~yJuz4(NO;q36CLx$KrxWVm~JVq$Q zN+fKsl4fBFk(ijr(d_DT^}ASC*u?lVz(O?R ze%gGg_#aqttYsCPDlXz`b^u?zz2lQu&9=u^U#cuAay1QDn~!1GPwm>m%scr$Oymv{ zB!>vgdo}ONUe-~mPu7>{tM$z~UlE3iaD8}jcvZMJ{I{?m$PSlloDzu!+5>%o{=l`s zhXFyx!-oM@4m9JlYXQ!~1fZM^jAMe4JU`BpwN>Y>-N%EQ4_++3|Hn(v05eZKI*04qapJ^|ky|q#K6|!!l)=vY zkYRWoJEJl&n3Dgt!w4G0;S2i4`>y)l^YLy8V8Lp570AyCZc-o%1SWrhN0;A4Bryt0 z{~d+OCbb z-JUB~6#4_1iVwQ!)gJo?W1n&Vs;~i3M>(tcL^eZ5=qPb^U@%BrLPU=cT`<8f z#i8lF_$P7F6bJT90#XTJ5=tVU*q`7$gBG+{9o9z{`y1xCSheLL(ZE<^;^=?f*9PI8H;#gSf+$p;M8l zRYuyG788sFjATlLkrXK(!;f=4(w+;Hf+?*MInX}JFV0DOH?IRCQ^lH zF%_HS*LgU3r1+0Z#ov1`t8_sb89hrfUGGJ9ZT(x2W0ZFdhe6<_-GTR+)6AwCh3 z;DOJVkJR%QUn{nC{_0iiz@B0&7vL<+{5$efMAL8fn!8O-465L8<9Ey;Pgp=h^G(=o%D5T5rvC91pcZMl1M=t2%qOCAf#II6Ov;NPnkZGj6szw3ijy-%y>CcL|^`D>3YIrPXg=g5j;YftaZ z7x#Dm^}ylg*6n@WPke7+$s^(7w>azN;@+}tyC~WZ;b_~&UuPO&@&!i3{F8O7nZ?sr zP4At~E}FJ-8abH*A@@p-+^U5w6ZTFZ71c1e5|%~QMxKhWh`vJ5FFmx@*+HC2rya81 zqIGCp2<_(@uW9w(hK9J&Q4Zzh_1=t}ZO?AVZq4>*c`=*yPBQA*kdf!S4%rDV)+q?| zMLNDnIGtxO0G+|W%89J1GFrp=J45*Ze!5%(G)yfo&s16RRFK)J#$B3eqASD9&@C-v zwPZobn%PvA&0?#EZ+zKkI~3v2E6EiwLzUzLwC||bY6vJ-YzWeHK2iwU3U)5;9?k`m z_RYdC8i%XzQL(#Ve^uM73ks8hltqXrLUFd<=H?h&<=I-g9*seV>y1`XLj4@otn1vi zmo^+XdY@RiY59T~&A#G_XD);~pWMEyu%@eRe_?B;V{+Z24|T6;UT7K@o8axYc6{gZ zmVNM}OItev8|OZ;rJ;AyqM3CK1l~;Te5_;Uyyy4KnR0TRcV=Vj`dJO>y3Xa3s^I#n zuJiA9$KIic*A^GCkE7R5f#nyN?47^AAvrT5Cf_%(wd6d8;w%nErw?xXAnI%Mk(}>> zJ+V2#f80-wC!sajnIw=@lZbr|O4%BvI-AkX-?^1{R;4nm-%B&E&4{UEjL2D${bd7X zq^!&@cBuR)6>>DFPr;A5 zD+jrH95{(Yim8rot?#SvuV?E^F$JN?OiNv5YLprhWoz`S=r?)Un|V$fz(J6_>)|&j z8SIGkhwfo}2P(;R{~uahL7Q$IzS7-8uMX#IHZaumt6?-xb$3%U$DsYcNHN9<%O*m$ zZj=@D{3RjS$5+qWc#jWS@yEH7`kv0k(`L+0kN<|lTMio&42Z71kdU@?2YV<#jXqjO|Cik0Nk^E~hS zJ->bT{Gt`=_N{*MnS+pgxjpCk&YV&f>YD|a8DF_6lU>~KXt@o346HS6%$&dYohnGT zF59zhK^x5hZRKxpzh-KfPjWN&Rzq3(VtORa3Tust{VhEVQR4F*3=N- zgMO((H&i~IuHfy?GLOemaf0Ogc-|qZCrC@~KFL9_vWx3#0BZ1d;0)jlpF!I7b^5D1 zo76{iBI+;bU+Qe54tmh=TLgv497M=*dIZJZg_o^0lj){y^)%w?5Z7(RE4_v3W7vGB9iWh2BWvS@6Hg92oIh6DZm#8mR8cph3 z!1BgFzgS+~v3YR+{=q|scFor2HdZz~*wVg%cVr!Fo0RE|v8L58?Sz+Jxoi2@qH#F5 zwkZAfw$!p}gB&3bB(}a-`*1RGiE51xb{F2MDPVHR%Ai-uwuh+1Evn{KRShN9m=sE! zN)cWR`Xd#pCL0wez@B@snFpR1<(3HVDRVmQAh7nF1OKLIb-QIj4F)3FqiVlO%2c?l z!V-10ils`EwTy;uAabf^_=B7bDS|vI)2WL2Ls?nDQ&l@F1kL_=vF;3u>?PEmu_{(# z&Ezu}P zs0CaekEX=DiV`#9ohP6>umqiPtnoG3GW=qA_0>utscV(03#N5*TzX23o8> zM#_}$DLa&Y#WF{MpaO<+L?KHRP&_f0CFBqkr}#3hmN~IUWCc-78X;;$(wcEy$Pc;A zTc>-p&P=_zOWfnJA1&qn|H=F0xJT6|Ud z+jyFA$xOG@FOf0{E=#aPS}kF^Wm(S1_=f40NW8&u` zOIy4mp2K`|pJBd5jmoW~+-LGMu2gK-?GlbP9z}0Hhg;uOYG-$jcIV`5PZfPisx9rM zR2MG7$9GILyL)e;{%rNwFt!;Iz*K~X2qB_pDSL2w0)Y;Ny!6Wqx^8;-oY_`aFARl zJ)GnE74pv50`BD4o1}v_W}Gc6dhcM`bKkJ0&4Z-vBF_p|8>_7#K+iIb!oo_j0S`1l z&Ji9DMNg!i6@U>GVOU_t&qGhp-97n0|8*YDTDaI(aP;-T75JFl{qHXLV0eVxR9W5)Li+1D+{dlm8m1F`p*Zi0>A$<_{I8 zZeh)-G0ULkhj-u_^a_3Y6-ApO+wi^Ul*$~)%@tyS*!CEUWRrB065Avltlf`tR4GbT z7|Di$O(e?Vz?uM2g7CTwR=HA6$-T1W zCo!!fP^>S;i4EEsZIkxAW@*sdbds$D)>#K$u9o)cwsLp&uny;I|6Kb;En6E- zS6X!tbP}~N5hERGjY2f)u8dg9L?_ss?nt?vC1J^0TUkq-daaRhmY1tyCeBDMiFjB^ z5{+bB&8bD=v1Zk*Pj3}hiW@{$5y6Q&E|Z@ez=6{8qVi6so2xVLZfe3lJ6hM7H*=UD z&5V{lz}MPolxd2HLyObIBhAGVys9L0x2v%M%c@}BBR&_#HP)!tXK~RfZZDx1x6Ay* z8))Eq3m49`EHC`>_~GO4!K}~rZ(VofT2I&d?_c%Idt&}0A42~1-LLIAe)y?$c+HKE z+$YK}y$@|L|NRf2`_ZFszdBa9@w0yJ)L(};?kwDOxbTmKs|fivRImNkj**`}$)JO+ zH}7FDAEI+zynDe+|2=>@~89^>sWxA6Uj1^ zx{xA)lutLcl_ZP1$}TWfs;|mo8zDdfAuS4ARKsn4fAoBmE03mB!|5ysjDEQ+hK!t% z^Z2v73~(BCW>otWoZWB&R4Xnsn=dze^FF1Khj=9x{j!R)JkTU>% zVWyLaq_^B>Ok^I?JZKGrV)XTf95H+`b^3mLMy^Yze~EkgooF^^IzlPx_N> zNtTcM<85)a>^%iWl`)0PROTzhu7IsblnYBl`8x`D-~k3^{D<#qfsNw2qVK*pvoo{5 znf0!Byx!f}wY?vkS+9R<0}jSRDU^@|o0J$RUE>f6p(ODq#)MP^ml6ll5TG?AL;*}` zB85^x6$qGCU=fN+Bz_{I3Bur3QA%1_p&y~D#^b)3T?0|0YONW)-8Y{5?z!jQbN-HC z2ilMD7YJ$)%tk%vE+XfZ&y+6}^0snN!BM4J!K^|bP}~KIpQsA;nZiRp^SEg4=1f#sXLW2{<=Qp6dV!v&^(Gnp55vt4z2Uw$_@;TJvn+&%MP z{{AzcL2}yZW%~8K9qTHR!!P#0_vgcvuhu{9ZF?+h6l>}%&~f4lTpw6;<5DS9&TZJy zyF+j7nFVVo-i>+_8KK;YLxWaO6`VeHo zg**j;02d8tjK}s6(pubv`YRV`)NmRoN0fL(L?MJZR8kbVly@r+*XKc=N!OdSYi8i3 ztN(?zEN#%#REqSQEUe90SWQsrwIeg#+f8T<9gtqy{!RFrl$HzzyC*2^CL_VM^PUOa zM;4ECcm1Wa7go+VTsde^`HLvLaD3&=yfsf`5uGxvzwe*W+O6qF{C_mLEKnrN^;OJC zs)lT6x%M5bupAG9V#O9hoetH;<3`;*&1c4~`AeNDL7}qsXOK8dDWlcxd!p-OKFMWqj|W z9(|RWsb7!w8v+hxGRDrO857atMpUZZVlkppX;e{-fov?QXp7PT#X0wh5Ej9Vj=C-5B2<8nE`s}SDfz#bCzVnxhuQYA9n6MlNP`qbalLq%`1VOywA>rYACn zqj|7eT8E=&w{&(ViqF8L3x7UiCK)$8J$?4N*5ANk{TY4T5_~?B?OFO&MyA>Jqi!u_ zWBd$W;qG$dnw%9mT{&c{ut&fSzLej}@8KDqvCPTMC3y}@z6!)DlW4w{Z?>ywB9#xS zU-KI)hc`dv4?3eEM}u*yhi1ry%-uN8#f(3=f1WgIHxFdFe;_*8O^09}ijn*J-rN3s z^YTc+Q6Z;(+M*S|$Y2JCQj;H9ws`Ck^|N&2a`FVEKP!#1in0}C2=xo zpQIEJN-u$n?c)#gr+FgsA-CgjC;4UHZaS+;~*@71xNOs zw|2ZTJp4+B6}Jto-vm{aS6WvuTmHeCx54)4w@Ye5kI8lb->KnSAL|DiZojd2?;E#K z1{r3Y&f7wy0ylt4sB?JKE~YF|Z!{Jq>!Q6;d@cy~Ak;d+>imxrbAr?7EO8S4DccWh zc%f~jZLN*0WnW|8WC_R0Y@8)F!n#@7P6Z>2t7#V7gl^ithXqCuIB5gfM)nax0;(t1 zFRCH6L0zi0s;sDvtC%CI8sY+WTRafrgow2$f=X2qku<*~X%*EeNt;wkFQPkj$DsWk z3G=NIG)T83EXg@#LuU;xwi{%1RhjTqN;gM7xet%w|1Mwqy)@QtlzW;^Ph&trRu?s! zNVTir;R-UvE>qECz*9W|PgRYnf4$rUI?OoSyDdE4wCm$}C)4_t+dUfveTYI+l|Mai z^_Cld-MIFYeM(dB#sv)m&XvONv^;-Z*57}9^Ot|CpI2B~JXf}#da>`ouGf2JKD+3t zO=x@^S@kCkuHYKMMO%W5Zjuy2$o3&dTBY4S1Jvs5E(15ZD<`uHKbPHASN34nY5Lob z*^}6d63AF{2ysieLR^D2<0&D67r_saSF-~8*7Q0w13(+V1*n7;gIYa4K0b;N+rplp z`&%;m;aU0?bAR2`DaQUs25@0^KkZ-p_4$m>{uWiDVQs1hM=%zgi=Egy>Vhs8Fcoyl zNfnJ1EfsAQtc_6ufoL+}NhTA?fRbQJ%6vX8M^5=p;Ix+V&}^3|MKb0%uU%n8FE1o~ ziGc)h^d^Czq?Bw-63LQKk^v?f%@rqD8{}*$l;Xo82lUCj+%WQ%dyjYry_f$>c$L6L zah>6J%)EKKJF_!8JA3$E+q<^$V%C6A4NjoN zmg3N$95@L<&~QmM$Q*4QHv&RMV-*A;tqT%TKyBU7LnJDA-T%$(f&;DUUCq3;cHg}J z|G)qHzb`EFun-N9EnI=}Cr=|41chi6QW%~EQfxz4qZKtk0 zzV3JFBLf4SvlH{{bL+l4ciDQT)o5#{#3s+L$K{y2JKVFWYh?L!`pFdvHC)C3h$b1+k#{?X)pH#@Rq@B=x+A-}Djn31SY0Vn_ zO2dB){55bVKyL+ba{#X$hgns)iipdGsx4Kws^o&ayt$PXR%K;HK}ls^1x+NQ`6xIT zyc(nm4F_o=o~9N6txnAA$&80Q79H7pN6i4NGJtO*?PBHE%(YL zx;Qc=nUTN^P_Mz^jIA9J^$I}6j7+_R2XcuwVP)ucvgmA3zh$MR_tk51sJzT67Ie52 zexdyjzj*e!K=1f-KU+BG&^v>@y{oH@sTJ1vsmYb`N#7~*mRHuEeRpf-^HjRyfUAl}v@jxjw=M2FSk$@VC=lXMeTm(dQ?WjRRe!;TK09f#%;smW%Vhl3qlwL50Go z$)2_b#1jc7{eB}9faWy3-h4^7)P#;OyhlYrc|tLQdIE`=32(!whS4c;1L)9gF|eJ^ zYRuuCv%5{>^h|8bsp+-#n=bFY3cYa*`_o!)FaBrm6W2T5eCOp3{3E^3*aWzf$w>XVb!hMC^Y>*MgxaJ{xA(%koSD^&}_h1ci)(uK1;8S8T-pvp5evrE< z!Q6nDp<%<(;L!B(4XXctpvM5{{jfirK7sfkzsf1%7;ytE?@fqMuofm6fBO( zpUA|}SLy5ZHeC|8t2(`@<6?cHK0~JqbZqK+HIpr-t4vm5t#C_GxL3}V&&t%ZoP&%4 zR1!nxvQ8CKC03!t6fd+RbRx2BX4g%tQA7qCVWBfTa}s-4G;WxcF{&X2&wN`sppa%| zlk%!URfXv$>=iStHmlR3wzbe&56f=gNM?n3Y?l{zc=0L_kKUNK+G~5SdT)B+fhk9S z4;x~9@CQrK`7N^6}gMcwy;^ zPI|{-jGv~@%ew)Q2KxIkq>g^w;}3{(+_ZNFb89wH%-9-6dKva8{d^3rVKzX;rKBwMIUpkDVID+dibtmqUJNszcoi?fL&Oy4^ zowpODBV@DOhdgMdT~g2HuqBM1W|!D?MjzsH`BF~L@Xz=SPWSRYPCR{NSMOo?nFI^l zls!dKN+P->ZiggEQjU{dh=A{C7zW7n-1Me&*g9X zd7j*t9>KJ|9X!nlc$#HOF{wlGjHh`FHw#ZgP*BHY2El=`9th1Jy&>fb4}@m9-$!R$ z4@A)PhoU9${i*jn(B1v3viqa$u>U%gW2=-PGbkQFiFxk{j!$!+@tf>3(01n;?r)|| z7Z0IijMH*{16-zbI^M3+@piLDZ?LoA2*aq``TQRG58YKB8^w9Wzhh?hnDJg-?=gGM zu4i|>>&4d^SP}35`^@{i9ry|oJCD5LNmwXXukDA!MBpLJ(b5H zF;7gNs>Y-z;4I1AVO~*jW@<5&MVxrT<)bn23Hj9K?&4=uoHbfL-!J0C6TC%>8O0&2 zQJlkM_WNP!DTk}Xn)1*Q(jBQtU5B4S^bv+PjF2-qOvqq!+fYf`v%rJad7#b%ozno3 zJhZ?dY=d2JALK;d0lh)7P3#ge5U+@zh&bSZ09K10yXbNI6=)U%BAUdCqR#+=l~pNn z2`Mf9hoM1XEr=QjT#x_fS5BEb!Q)tnbV!EXr+fBPVgXqL31KLqWx6UA*lD}PvRf`g@Ru83mi8(ydcryFqI|pu$G>$gA;xhE=>`DbXPe0T&*a|+pXL=Z_Wdym zQNOQt)GV!|==XhOgM|BNjFrY9GzyZ*cU2zeLJ?<=ij(iEF+t?Jqs_G--aTpAuF`{71py>a@VWZ=5 zNKB|guf~KX;4CCKtJK;(rQxhDsL|*rR)p4IVm^u7U+^E*y1l63kV%-Yce5V?e;^;` zFG6YcHs(HO&1xSk*7`spSYE{ptF4L^0jpgl*E)tL5+xB2_66+*uuAKOlZ9^Z`1w*2 z;2GBqDvFxXVl5+z68ROmZ>Z=jHc#rFmDmPXo?v?st(~M-#Jf<$+XK!PvQyOTDCXGg z+Q($4t1RN)Qs-Jyu^@QPe%XG{jh68LC#MG z*uZIrKh@^x@}U0Q=Ze7-5^VG&;B})CXWn0Q#E5qw7n=Lym*u}P9*4gIIc>2(c z8j{ysa#szi`@%e+o;P<_mnP>GK^%Oj9MBtF2J|%lZ65XThk0ZW+yaW);kU@Yv&H$6 z6R!=v5JYR`7i2WGVtxg3cp2Vp_Itg03+mjeF2B28%xKQc znx;1hv1+z-hE&H&@0oU5qhaDbwOy510J5w?_4bHzqeZjQV%1u$b+CR+^~lYlOSfb{ z8hP;C!I3Wtb&RL?KRogHXrY?RjvZRp0{d@l?L6J9)%B}~d*(I6*>Km$%eM>lUDQY_ zN-E5Ckcx&tEvz{MCgpywv`4As`stw81Q`2^vMx{kc_$p0k@w1q>_NHkJ!A=K463*1d6TR?ps zOBaFAD1BT_z3pzySiN|NBE&Ab`3(^gX5B^}` zblCs#OP!}qEtt2h^KF>fJ?8*2ef8j#<;~yx+7sDdwjST~dQa<5j%K^NT1X?VC&~!2 zSHUDGo&nL^zm>UUOXH9Op`T*Nv&UJa)3a33c&i<5c0+>*KNI1Tl%X6J1g|X;<|1veuGrBSj>UYHbS(ze z-iYFZzQ*MJBnl+=CXqSWn?%{Fe{cW?z%~v)9M!d_E?yRql~d z3;DJz_!SMsx$b0_v|S@HLXY!r1G{=L7Motd4T z-I>|hukLhrXTRE&YIcQ|Z|oSQM(#+_;|Lm-!YTENNU1^(4a%2%h^I9wT+h=`?t^#; zmW!AJ?mQ~#CC4A2Ik*~=Gmu=Om`laP3pr1Adhc&`OQ{~owav`@rcK-Td7tNbpI0Qe z#m)@Xfm#Pr9kz#cWx3my9&Fr&o>85(FgU9Rh2#cpZ0az!2;VMeoh{ZRhRC=A>#6n) zBX+fEs4urwEz_%AV@;cASXEnk%QS(YxGt}4@0r`T+L&L+uUyza@2y2JwSU#xX9lL+ z@l)0=)YP*pwy#X-F90Vu73O|_@jLaZR zL0BIJZwx+lPD3aDJkSwU4Y+9D%T0@$%8X?(OunR0K z&BqOe6reCA-e8+x#*1dF*==q%2ThM^cDRrGO^;}rTw-H(cb0ZBbmgS&1+N#U5^z!| znQ-NBj_Kjsa&VPUn>=UH;>Oj$;GCofgch=T_Ww{pc$!B#{Q8EKFW-#*JDo208N9J; z{_LA@fB2cJjP=fWZUkAMCU2i0bx5?i$ohi@+-IybC>XjyH6b2}(-1`m;lhm532(h5 zacU@qW`sly1?!_CSWPx3C)nm$M5cD)51TJBbV8Pzs{+WGe7?g1i;}dJUXkX~+0dDz zVF*`U;_N4rs8}Q7x$8_Eoi$EC_Su62VjQQN&@McU8+rAWwX^npmu%~u^Kcs!pUfNI zrP-2q_aZ96vCqVLIC=Br=XTG6%<9ZjnLQbvU0%y@y{Vlkx-+#eMMu<6)vGEuU4SXV zY~he_QsC<-&f|j=BrAm&Bz)Pb0vmnSVEhzrx<)DYVUBj^U~_IPN85AzbEk4wa(qrs znlzHsz3F=1>)LATXw5_~Oz5?Y!GtN#mEU#k>1jR0_<@HR)%}*esU;L~9{S|fN0wB+ z@P_Yi>#`qAmojBj;r6+?#5KsRkAA`}tN8zN*TJ^AvBRMs7oX*&Z~pb-{0^2$m@~%E z8QYo_F8=N9C+SPncEY_N7%G;g(7^R2&GxP9rGZt0xg6RkJo3=RpU$*va) zt_K!CEwmQe(HZg9T^KBUP`FqaD~M7-&KHxAO!^!1q{*LeclE}ZnyK~-k zq3LrTUGggYqjKfV;A73VO8ZK6d*~l4&u^~{c!tWaajFj?M@(|So*B^+spd7YO)%x7vqZzcw8FOHHHYMPt*ULp2Q2Fm4%*@m4o!bZ?3-B#zN`={D*cUAGRVNQe>yS{2qW_ zx|33`SSLOyJ}2_`N)Jd~(#O*0l4n&ER>xs!9FlsIq67?8h+*vkIh^jhSZt0A3<;fC(F+)&^|&$rfk z-st#`9fPlqz5Js|tzO!9t8)wA;IzTX%C7w{S6d9^v9ZrQCveWxlN0ua*WeJ)9RU42 z^h$8Ij9-i8hh?r;g$AutJE(Cj+6L{<8rKl&3>^${&7t)n+8c&9qDP|i7qPcubY=`p z+;6C=q?C50PuZ^wDuNP7dbvoFdQCGJ&l4r*t7he7utBf|Mh`h*HCqCxxc3yxJ(vc%KjIV|-+Ai;ag3x+K~erSW>x zq%Zjg{8aU){M74L>t!)qPkr&YUgys%F85XBSdokoKEjcNo58*s3vz2hJ((Bwj zs7RKjE>fwg$(C%(i)8+i3^GdKLb)q!L zzsE7Z<^4yFTsu&;d#3J&vCI5fRChhuYd`$F1UcGFk5MjU3>%b2gHambP3GuD6I3&0 zGQZ~8ZL@jGyl7rA1yfU+{6ZKji|6ecn^oHgH>)c6In|ffY>ge;HP9|9fMzyaYh{HE z`zDCF9YvRC&8!R+Yw?q%B$y=j8;h(eoj-fs-4Agc&Y}Nh>U;M()^#I?vAdjQ>gq@c9%V5{Qxl$GIFXwd)A1AnV8$ z?BW(*?NtC)1l9$%pp9)2PjERR6-VQL?|D34aj!VgaH26QYa-fEJa%@x#-=7C+tQrP zgu{57(K0O@3BR|jW7UIw%le#UrGbIcL;d-3Ip0q>=M4W2%<-Hd3aP`aV&54cgq|k? zmnVL_8^pqE98U&`(DTPME#b}n0bik*Xoj>7RoGu2h2qswt#Xx_M+lKciAGsUTQ?}$0*!QxfTZ{+TL+18dj9t}-5^`beC;U6)IbkL7 zVX}$<=ks_)L6TAGX#`H-sU(WW$1d6T%6jvlcuM>L$s=l_C32$oxBq3nYGc~E&hYuT z$Jh57<7@2ei!bHFKyZATheGPrU`P$hfB7lVd+#6qDq^VX1G!(t&>Rl zFIhDyk@jaokw}0vkgBaKMcJQuiPY?)T4>fynzA1$`8B0l!F$iK0Ym7d?bnRB_xN%y z=RNQHJkR?a5AFa381PUJo6E=PBLj1AopEe7WmAN+R_t;pQLK3Z(kp}EX|8Nyf7ec4DFU6;w4xKABcSI^1R*1uK#3kZ41sc?sGVcJhLyA&K2m9)lI* zOj|e_>*{FPw{rKOtxk-8b%0kE6#F#-R{cvA%2gZpS zOV$vENfFe;kr8%(UuW~yI$y`~zeM37>LL7ssBi}OG+F!{qWsQPY&67NO`HlsHKw~? z8_|e{+cEhPW0X_g2Tm~L1G0p;gGLd#h3+9zQVc}_s?F3ixe5Y))Eal>83{B2J4^O& z0ZZZxkO(ye-JYaJo-rqvFDXOH^E=0u596#+Taz5^dq%|bI%MsP#{$srnTI6idBA$Y zMbx0Aiqa-T2rM)Uj|iS4&D=LE+8V*63Dc;Pw+q=q7A$A9AW0e(AV~;>#Cy(6OiZv> zrl+S7Uj8HSu$_GlGJa_umb^a`v|Kz_{1fj~4VQWCde<*5!CH78d=j2n-cZE-gZg)s zd}{y0CiM*(57C^zI!Z+lTQxua(vL^j4;lFxJI{!p)p;85KO6A<2K=gtziX%67*esGW1{W|X|(lfK*y>swv1ADUKT8Q zAZrWp0XtgYP$$lJO{KEpLFLcovK|!P13{giD&7DDP0RxwAMq3%JQap1!BrGt%&j^% zfE%%c;gE_6XM~7HpDqbbT-m`OKJ`H}RB-O*&Vi z5*a1r7P&_VB0wdgX=N&D8>r-nEl5p}q_U0QCCZj+wG&xJtXo(lH=bPU0agUKHn#J5 zsLQkv_Ri*gyO)1;@R`2RWKHb>p$5%em`E)EBuuU#K`$eLNF)$Y08Q)$GB1$e!>UiM zK*G`r5<<Fwj*uwpGqtP9dvx6|ZCfFV3VKKWg?1WQcnhp<#FN7Dv zO4te5j-9g8_NYB&7j4x`?Iy$prMO+!;NC`mK@Ww&HP8UMh~U4YHeDQV?(?J;a8)lX z;bk6G(d)Y`ZgF_!p0#KdEgG;Itzm1*f>*3>)bn61OgBWPHF%}5CTJ-2j+HFows1qT zQVxxqR@dWCkpttxjqFK@`$94)sT)itCAUixH~gjSisGR7EB;4~ubCk;tZs2ZKcPIr zgjSBpu^%5!cT6}FiJu%g_{P$=oQaO~p;M<1WZy`Tul8=+ksj#V-v8C#`cvEX_HXYS zU|$?Qoq*Y${fADUUjBuA?ZEh{Y=7tYw!!`#eFHCTPrW#}ZTm|DNHj^PY*1FV4qf8k zL@L&pSBLsOKdp|BUA$_fny{Ek26Py0vxQ~shKisd){bFm`jVpXp% z)~1>N+8jeBVYo4yYGuZPl^J_sB}eNrbEupQP?uLhUCw#ZD2R564sf4`b<6cDiq{Be zDJ`uHYl^CQuLH|~`PZbO_XfPcz$?1yq)zg}S`~n*LVtGIXHW6~andMriAMd>mt(1LGokv5=UX z;22`v$?oJ^%a5kPA7z%|?c?zFx&Ood6_WkyTt)lZ#M7}=Psc{ss;67+PxQZQMC&|V zWy@LZGi&`ts4#T?K^cvO&Q-*tK|Fr(EhxSZPg>Ks*+Q#o6tZX1#Qg2qVi^}nuYQr`j+nlksP00E< zWc|(J9mwZvyvd-LirPa^M(J{dTqb$KAVROoRl(k1Vyhca9hF#ARX`6UCV1e9nA?Fa zqdd9|0Hw@EsKOPg zaEha(6q;6sl?%$Eq9~z&?&v8!t&i$cdQk_3(<6{0*;mv>wW!j7+NchzQ!1#NYWO)8 zeFd%b6(AQ<{Qrx(1vm7Dc!j!E=znZQ^p(F>>inv{RN!GGKxJ83V;>jUJxoOOgQ%3}}6#+oAxt7c1g8)%~$mJ<2F*~4cKzH;Qy z&(CkkX1ARGUdP3Y9byN^r8?IE65cK8TXluLfo_SoO%SvbG)Lc|^xxE1eQX>@6`z^i znZ4b!eS4R)@9bRe_I!36=aQW9?ZpjM<8j)Aq;2YiHWF>+1X2V_)DYa3FQLdsX)!?* zM+8+!Epe~_Mf^eH*!gM@DMdm=O6o{}RjNjgA|P(1C`Ekyfyf>2&F+da;I9?C!}7aYA-{re6y_U6Cmq;U-DSBR+@8KX@1(A6ChIbJqJClB)bWlA~Sfj zgXj=l_cceqNh`0;YbABUZciRd!=^kciC!vvO-WGN z(3p-dBspkF=R4BK2Y005f6&(+yuhz8G{8hxp@ohW!j;{53I%1y>y>LXNTQH0GSrLyM!$>F%z~qg*U+ zuJ2A~y5Jlv@ynDMc}Q!6{7oJa5=AX%Oc^r#L37XRX_n!Gk{d9LaLFzdaS{QO%IxSX~JlBRRPh^03g6g1Z719tOm;i3tm;A zO3p(inQU=fCZlnG3$%Xnv(OKiIJvv$#D#I|jyh?1IJT!4P{{|0M8qYxi+42q& zq+Voips(gZ2@R6SqaX^PFd4T8)dqACDW%4d?18qmpIF)5zxb7GuaV!ockJ*Zk8H_h zH*6qU6~hKpP=m)JwzUAyrAu%qH+$to475P?fRlFICC!McB}u>zH~}qyQZ6kd5A1Yq zTO1x4R*oF4uHj)GPj)qfwu~sLx+?j=w1I7cE8^iP}*o3j9TjG4%CiXs*)SBMyxYX%LPWPQ7G!BtQm_F3;45`5XhjA8=r*>Fes2gfeZ>{ zP#}W>85D{^K~o|pa2x1Df{I&k2qpdJuR>@#Y+%@RkN*TXK%TRrKohj@ZJYQ4-ZM@S2!h;A?NWX=+`KS%%Y9#JWl`Z(g z^uYPS8)XiUfkHk8$??GO@E*tpKyUQuQ9#WB)PAo}v)~K}bDI6303ZVlYb^PF z_@Z0$@Ic>m*CKBP0tjy4e+|(^gy_wiHflJs3UR_;r#w3R)WNah z*#7>0!0O=m`1b9f64muYkerj>R>D9f3BGRO?!vZ`TTm7uJSM_pB0Nwf0X!xRnJKf^ z>^FzZ5%Y{$HUlH(sCn3&GG|Qa1_2(Ef?j0WT^;e)ea6qB_E3coeE2?no5 z!wqtw<>G~w^O%Ev0%EN&mvVbly>M{<{{3(emdoYqrOo_t{u*0J+Mo!J1-7#v5kl%u zXpA(5h}K85g#sy;$%CcMdO}|fb`N-V^pbCvU44%>Z}&1G`n%#UVAqaz2v+>4bOLfdY*BT6tDasVLTZqsZUEdmMYHKb=UXh3I26c?#-8 zH3UbzTsp14t464K^gWsbBO)-*GMMM=1v;W&#(tw9ks@n=&OLty%TIx4@CS|nds@MgBeJd)79Ul<+_HtM!K{vovhC?+H;bnk9AU- z3IG5I+F${kBi@@zyS1zQ4e-9s^G<#NCk}Wg(AJTMagBdI?z%w;CxMyY5{-&2sYEWp z>;%1*DC4~=F_h2}!IS0hPU2)PRQ@~4iMB*$42eFp=D zg~>Ey9$7xWYTUZ=tTv+%`-smk>=TldVP+>cB|o0jx|3<6p@w9I-GS0+{)8IW;j{cv z7}q$?QaGO(2)Z=oghG8d4WhBGbh>&TVEU(EA3V;YDaYHSM0uUA_6qy~Bc%B_vz_-H z=78%HMu9l#a2OpA_@1Y$J;RtFj7i8Sb7azSN1Z8$jXD%Ysd)wlJ-kZy)y(u1oAlx# zol8~NzVG{Ld_Tn&c~(uGORJ;aQR8c;THAtgmcf7n1vArDgT#&+pF3H=+oKs7uw2-0 zlbJTL~v+CBuiniTJW?RvH2-XecgoZe6V zK$nomj%yhiYj!cHiH5Mc9}So=<9o6#lS!ug7)hort4~X1XezTUvoCWnb0otv(yVhc z^BW+S9eAbyD@Sp=RfJzs5!RnzbJ2PFbGztXQqlFwthTRxrkyQnZ?6uem8M#^weD*@ z*m|Uuw_+%*w+O}C31g)l`m92BiI41A#TEn-A;Ah;4}n!u>E(LgYJ<;wrcKu?RyX?E zvM{<4aHs~#DkR*nA!&}J2t{RThhKMD4! zaT>?mtqXih6&MT zmHj^{uin_Et}A};ef}RmJAdpXwqw5}b4(omB$)S-KpA=N7~4uk0s}@{Sm?&KCS5z2 zHneqZhqP8@ok*?i%O;@()b7J7A#m%?9ZXuJNmcuWbsf+S6%jU#B6aEjbrXDOymQaJ z_xU-5O8fE>CFh>=JO6)Yvy}INJnSf1d#f7nWI=clZ+P(%Os`(d?s7T3_RH+*5#m>Q zdk$unsDaILX8l>!Kqm<)DMagE>7bpVN5Fc*4nqTk+nBdV;oz)W7n(U@d?OIgkT>}* zE;HCSAK1Zo7Y#yKSf}e5y!r*~t2*j-@;;PiN15upk^LK?k>+A$)_x9BLnw8>kRq4Gle7dpeg_}$2$uDmN~c$+y?i^^x(1=v15oMki%teD ziw^}6X&<~9!8hkYc9_h(g)^sij((SXgY$>$b~GGD8bdrGt|F|OAZ&-iCS;NG@>f1@ zAw4(X@5D3Y+3V4|J+^1UQ}P`1%z5VF^nqWPhpa-{XIX>r;UJbP?&aNvOk-ZdGL;>(mGW8HjMHr zS?wDj7D-V#6~8s7L)pDk(IZU(zDtBPsQp{`W{a$SU>GDX-q=a7c1%B|vk85#eqGl} z`Z1mDlf{RmMA*IHwhNn?cfVmrsU4x+k)cQ_G8cI}0_Wj;B@z|J58%tgu+v@E;bj-R z>@L#?w;u9`%%O-K*&ESbuibQ>I_z@*Uk*y#w`AS<1H`Lp`00f+bTdkg3n}^}NHxQR z8TV4+^nS^NFM8J0&~ z<3blbAavC@-!y=8kw6ol*8%~f0hb09QMY#xmr3beAn15k`^~}y7O#63cpSJV?<(q( zUFGu=tyr&)sRo_XY@gKG6t3%h5jwTYrE?lPl}iOfPCt`h65@+ujSk5=zYU)Cm1&IU ztp(UeDK-~l!B~tz%4kcy#+R$P=*uBzo)GU@Ok5kZ_Hi|vO{K)HbnQO0h_hc1#j4z6Q56RxSCjD-0i|DRR;maWpn2=J}rBq)o znNU(kVG0=ob&JIf=X3rhbMDD&#a`!9p zvX~c_g~2ZiLtYk!`?4^MWSXN*^XM7|HH=B4WE?Y28D4|ad4tj9T`r5o=zjQrqC0}< z@UrN++{4m6J#Hu&YGfuerOdI+sf;(np=6eTA}$NqeV$KnuC0-C%_|rttCg!=T`=_- zO*Hl{Ow}HoWM5X>T1+xlyH@S(MZ(eB(7k8_r^6aK9U@{nu%=J3@VsL|Ooz;Cj2O)Z zd%bqGYAiOhhrc@xQ|JWRv7{Ya`SQ1FE{B#r(_raY;81U%r5(s4FYXglsI4_l`Gjq4 z@Z&g4p%d8cmYhOQ@U35FS-t~;0joPZku7Cmb)T zpZ@Pu+S*!LiY^PdM=h~OxdpsNhQX5!Wo;QRz-TKJVC8qq2H;{?!gdvHYjl}=2Z_4- zD&RPaSIZ8$^MmO3dqqNes*JQJxZ6OPstAhF_Idz>C&yuWx?%ux@gqLDtE{_ksL$>L z`&TM`IpI6En1hY&@;vZ3-2?KiuhQli*!fE(7AFBEySw&*=R?fju*~0mYKyEk+uI=@ zs~fU6R=cK^F?%~@og7vhZ?zeZ3wc-mb_3)2(EC@VAEIljEZnXX){wl+!Wit4GGg8- zvvo+x-QaQqQV#KA7o)!5lk5-J#Xz`+hdEx^#fTIA+KEj4$N_=&Ja~8SYi!IKw|G_C zS<5OEinL@>VsiZOpF`HHb<&!%yp|n|m{#2*Xk&|q%@sKplBd{<3dzXbk&FP-IV>ah zYrwJ|F1ztjN=EOo%p$dTVRZthvJgvjbZqp{=+wjMihXa>{iGgfa)H;|A&&C@z&{)B$|Pa~g4s$U5p$bp$LF*0P&^ zf_%1ilMSH!SA=}+6u()4&6CblSTFkY?K-1W-K=}Wt0D0AGtfp|CH##?E7CLUg z`zxgznDNJ|mi|>qB>l9gv|Vs(gTDH{VmM8XwptCk={t38&`rZi+u2Go<jiTJc$a1i{Qk@~@RM$^{=gfO@Ah%1( znAE+7o|;EKwo9^`_nj+t zJK1O7&xlFqO&T}NL?0AwqA%1@WF}{0CTC+NXJaO^F>}yl{PTjTnY16-PXAy(v-?Z^ zY_fm0pY`9BjV(s|G`k|$mGpW52}oMW^#_>@>U<3ET#trKWHU*mJnPSAwC=Ud$HhQ)@_ z9NL0-RMFE1Wjyv{4TR`;jFMQqm2YLN7M__ep||%)R8wj~#yS`Tg~l2(6NSv&KrbGW z`{HHgMN3Qzid)p38Lr>I($PPI`V+8Uz(9&WV9aF!GazjI$+0nmHpH7&1ch&U-EVkw zH=!Tvr5}$dKlEnwLvQe-XJM=M5&E%P`td5*$l0AR$(mC`DQzzGc4|JQkyNIs4PK|} z1QX+yhs|;d+45)c{RJ42)1=#OgM)7{GL)N@Uyd)>U z^2##(AMNEA+tyXb@pI0#<2e3zT_?5^dybQ9yLO$%?s}azP1l^NWh&!g7LztW3aPdt zfdn)jJng070XEp$MuJHo5Q)Yk($=(1(y>WJoiyI)XacO;RNDwf)u}WR@PLFdzw_tX z*Vm4lZfRBZs?zWKIX|EC`|Iaz*5TBBeoXyy{(1j`-v+nJAZNV`4$i`DSx_HL?C=WTX(^S#&XcN^LC zA zLi+^lVo|O=&a{qm=%&a4f~F2eqcAK_wdBALVYhgi#U}ovjJ2;AvFY1ox3`1{vp)g+ zr+VO?@i?>Zdk3oVDb9~%M^qK~$rirVzJ`7y?a}Tuw;%0le}nTMp+1GsJdWl084Agm zb}D}7R$bYo%i?fW>QeX9t>ZD!r7kK&<8RgH*5@^RLetvL758n`SGwy{9rcb!8u|_H z_b~Md~ z*K<6g^D@JKATk!C{60;CijZl^SgU;v{n)V2j&b``7kh|+Q>RdrPv2GQ)RRm>$X-(m z?Vu?)G#^lBPHOga(?DjUS44ggtka>m-rIhbdWz0AZFkPN?TOJd0s@8=n!Qa%Wbp$ztt84a5VS6$osD z<)DH^z9eq_E`qtyNpReqcT+cT&aJxL2Ita1MCUxeqYrp_Oz|9E#7nq`bF)UQv~$Z3 ziM#%gxE0_Yr(S}uy05#*r-hd|{bktR?y$HaVVOC9F*0E|&NqW_OD0(DYv`_FKNR8i z16}P!Zxng(33Y1y*x5Qybo8ohQvHoOV^THPUA2xU8mf=stbuKvRpF}9Rf12)&cvYl zl;OYu>wz;(E$e4eyTNZyOxF8#p&7GG)>ciG-=NTp=Y%F>(XhO_!($-ZlA{NgahR3r z-aaVR&(jf+p+2nQH?We!PeN9m#^>QbSMhaR$4>V6rGnUL+L<+j8E7!SMn^=ZZky?N zK`>1@d#EJ`UZEo*PE`oXB5-U7vj}BahOFRTiEPGyE3^C%nClOLS^2EY`ac0UI+X#NC=TZHjV3;gt%fMezwJzGG6Xzkdpi%N^*_u0fqA zMxRILMIm6f9xL{lHcCZOyprPO6cO|>Kyr9mH0=`eIlBc> zRF$a}eARW`1wr)$^}AdTfSob8%1yyFRhA5|?WI+ltuak_9R(JoEJPQvU5*rmEg0n; zV65)|qw=5(mchzRp21_L%5aFicFs0yBa5~-Y;f5xm~nnbA&#*@ToS}m)?5`V%<5-l zqT{gf?Pj@vz9{F5TVh@yD4DX^juISesR>s5TGKv0!tEnn?Tz_D0Y^8fGc&|A3K?zf z`Bqigq=HEyAyvcORqHqms>GT?${DCy2Wpg@q_S9mTIo zEL=b#ho&XGf;M3+N4W9(OEX*YD?7@62{yeCcz4lcM*X=tu_IU8#BQ~(p&MWyW)=S4 z+E9cm2D&OlPQ@=1Jg-5J|C^2NOlIytGaY>^H{cHsgsOAc=C8^3^g-r?Lk~H2J!tYV%cutTqmMMYt zlAh;zFF6dqubI8c6^#0e{ZP*qslUIUkfRV_KEED^2qQ>zl168B{8A81UGYiqMCBe7 z*ymE8s;m3~qMH7mieWIgQvVelQq=|-(cZ!|Dx-TyIb+0aR>W=;+1 zx+-q)GsJwRCz*hdy_WgRswtZ^IjPxmAI&<{P1f7kbn!NI>Z$glI;bip)fMW@rP>cO zR6L4>YJ>ZifEPXfR{giA7ZvI?>OB5AA%3hGydBk5euv`BkEnB+3fZC7Guhr+x38lK z;xTo=FjcX0&mKiNil|al%8H`!aOtEF88Whhi^-Eo2($lEZ!+1YEH$#@JZKLPkEx>_ zHmXP2c(y>#999+;0!TI#m6};=p_X@unw8XMXFJxQ4oE7< z^D!EmizzRfsJ`9;QdEWAfsHCyF*3xIy%u_9=je>@$g*s1&^P`gZsZ7~`*!I^jEH(` z^~jO?apexxPOVDnq@+$7)Yn%hC$~pMCt#9$%6^SZ;BgkW=otDPT+R^nki}7qMn_c@ z##Gb%*GY30{RA|8u1zGkAkk7So`wGK9JkNQGtPnio@Jb3{`I+iI!dXjr4+b(cP*9D zw3d1^(}590XTOb54Dtk}@n#zSO>EKlAPo?<2#hv@B2guoI+%dK z5Yr?i67!t%`tsV2lNQ=VY3tX0pWpvExBq#bS%PPn?BZ^^+Wv7nwY9g)sJ7ZDdE?70 z6D74f!iBDYUtF_Tg%pY(EcpF(Gn}qg3%b}@tgEy&u{X?U#aZS1Nlgn1nwHo-SIu@+ ztVJ?uchu~fboKtw#m>Sq#wK}4?3)Xz%c;fGD)t!0R4OIo>-W!*&69>>;wBM0oeW`p ziZvhvE#IVA=aK~Xv3v$^ue~Y9-5 z)a0{=w;J-IRO>?$qdW_dY)qh-uGX3?_c!&dm2FvR2&GG`1Nc`N2Vs5QN>MNqAu5ryN8Dj`EelQPfO|qKgVf=k7>AElacFaYunO> z&kfVa@Ij3>*gz|8Y@Re8m#484qX%ubeoQ0_O@Qp>Rz}))5r$h$jMZs(t4cT;rupzi zal$j#!(o6iS>nrDp@Fucqh+hKfV?FFZR$h-qJeB+B9IRl3dQ*KK%j<4yqhOYFUgv> zQ`F~3yh9|B&Er#!+YBTYMIxhaVRjCWdfAO;H_AP3w;*BZdl5@tEMKu?)dnqAMegiI z_R14v-_@}P>eyGE9(7yrHr&<6!u^8a%5I>{U7o0N`?$+M_GKk^)P2#7OaG&7W??{E zyGG{P|IL)QrL40hQmEYr-cmlRPpW36WOouOd7gfy;@r!~;DDr&epQ3?Y?+acu~xHIHH^I( zjj_9)LC}%@B2P?O-ugpY$0PUQ8~FS*w^Gv9O3Y&r5=X{j!y|Ks$3h|8iNp;Gyag-+ z&%qR&f>-e2=kOaSf)%jKnGq+biONPZ6>ml5t32lQKB9{G8=4CJlIDi%Qp0!m{?{P5w0W|}LlJsBnPMcmOJNjFGprv`qZ zojn$nu41P|tAw0m=qnow*?oytbj#f}rRWx%4R~`K&L0=jJ(82$iF2nep8z96K!yg9 zgLa^H2@0jXdOO&Xv$8EGQ{wE|k#iS5(Q)?RR?=|_#hcu!CLcDZ)$LgYZp|dO%}aWw z##*i!Umtfeau~?rXC&*;yTwIfAp^w?Zawrl4f&L=p=rWgt64*tUzLfA$gQJXgB@td zPdH`Kc$W-P=L@xN{AJN&@gOBVX=Wb->z+M~jS{*$9uE zjHYv_zwRUXOTYZvx#iGy?9$3*^{&!VR&Lba{dLu&5-J*_^ zxB0vCBO^O0mFIB_owX)9xspz*pXy{va!eB%Xv!3i2sX zQqk1u6zfaHoq%Fp)lzHbOf`P05`Ry|cXB_?#2_C7C3ZSS`(m9kI@S;^x=GQoY273l zC%@FrlI$kCd64CkfQ27+lQbU(5|4{k65_go4}VFSWEd&uQ6ebZrp3jO0J;uVr#VZ0 zpo>UwpH7o>c1pp{nhSwc#ywXV_wVJnBU};VJ{5z$Sg#y%wwkJL#B&vO8COwH^EQ@0 z0OUYUsBc5kvM6p4Vmxk+YaOpxJ$N2oBmo>X2`E4@%6o&xN|~46H~p&e{yq47`F(eb zeBa&pzL+cdet?YsRLqcza`%LL8vCZp?nSq$P&~3ATPKR`%g6xebF0J#$!sx>BW!z{ za?i8}eQ|8T;}JnhIY`8yw;ngXQ;xw|`3}a|=P6O#*sNhv_%->^z~L6wRStA)h1kGs zvl$I`YIPVL=k1yG_gZpf^mZv_JdCA|MF!9-=aQan!>iQgcA2S>3wR004lLcvT)7i8865=SS~2u*nV;mY;Y3m6o7 zQW=>Hx9DreIpQUkL`L_nS-dLVZ})gtB%#_Bi$`@R_^Bn-JFFTFenXdm`53W7yUE0z zUQy_C*YK$75bhuSJ6Z<`DZgu5!jVj!n8e?-_yJQQ-knUugNfwOV1HjQ z(BC&iUo-t|^lRfC&(fD*VE@#}*M}1a9LBi^`#Yz;GJ0qvGKI5kGJJ}!-M~=>Nti4> zzL8${VAn&%|LrncRT}n(4hF(BcrcJ}I~WcV>;EzXo|atZ==!JYWOQ+3QTer)h}&(C zHYZ+ObR+)Ra&Dfxd2{o-H*cD5RHtb3simc*ayKeYlh%!*Q+}+S5ZR4(a6EdgA?!wh z_Hn9iwF^@drPM?OCIRnRz)YN=>)~h*@CSq2`a%0LA-44 zEd+y7+E;a|Qtzly=gQjXdPo(%1H=~vE5;DIq5T~eP#RE)N_M~=2JTqEF*$tQcS z6!cWQYws0sVBS~lEoz}S$9-C3g2z0AeeXrQ9l<5tsMPmv!72M#A9q01m348~wCl9X zSSViNK9{SW=B&~t%d}^;j!>6Xwv?64iCMkQ16o$Vaa(rCR!NsvT9=oeRL)Di0xo2| zjjSmb9-^P{fR+t*TCtksLF^!UgzCr7G&Lw z5f_+UR+q(1K!GSQ3%pF-6mMS=CHMv@&|_Dz_Y)h&he;>^I7epq7UhINfQdTgn$x4Q z0-fdo$|-mGRH`@?t8(7W-Q3|(-5GfXj|wMM-Yb1hi?b#_otQjR`VPM#qwnJvO2uwx zAi?^Ldefz^e*e$^+`M0LUc(%O&g#s!cAS^^ZVUS_?NuAw)OCi>Irq!H_RY14?OcCe z-#Brc4=si`1V+1DT0uo8Mt-zv*=CYTfRui$1daY$1&kJ|N}=A?s#~Wu`LQ1z8w-pr zK=%U|(haQwLFq_3J`}C1fVS46Ns}f`vG<;H{c)WH1hk8idvEObzUMjbIq&m4N8?gU z&eP;nqOwVt%S1%xL}H0qEV`! z;*B32I9bz{)5V($=P1G)E#{4*&%Qd|H6QRg=Lq(YI3YwwF)YP`v66;WZ9*drnogqe zV0!mkShtCn8=7)GL&YS!IpX0~*JU`1zCOi-x0fFtLCx-4$Mz8Gna9d2HrJn+(Z6^^| znln|mTNM9qFqqH$3Dj{p(+aDO)0L|89#+T3x;nCGDY5|bG^^uq1+ymFN*89wD8Lq` zn8(66e2=iZE3mV6+z7@e!_2!|{QYt13(Je!_lwPo{~O}BG4F20&y;2=@wFXOi>C@f z4l{-5vT04`IF18YlLyuvo#c5Y4RjhF$&u;CyFs^(VE9zD3B*#_syg@w92e6f7_I%2 zqIg%?7V&FUM-(h6yduap9g*)-NBk<$32ESnBJ-}jvME!FmCF=64}@`1T1%=$rFwR;n7?AHA#~I$rJLN}m|7&P{zq3T zo;d7BF6d{i&J$blgVp#MbhYZCn^?SWaXe$^1oO}bX*|^obk)*~NLe!?Rn3S*f;aw?#F|P*qeT z5(xxqKq3_&5eg(iux0_#sz9`~Hl%TJ&C~|8oHnlIwOLIv;Q`JMOR5IiR~+WoiAlg= z(DCInaGu&qt4UC6lILOYSY0(2#?RN{;|7ZlFR@yOs;f0^Tdg=-t;7L%%wM5F`49wLuBFz`UL8FG#}91y9zxa9n4yeREG8xBCk)moxV*tfDh8!LTX#jvCph66l$q@150}>u&pmyFJsy3=Q zWmLa8yKCPRL-ly^a|;(nn?X=7GVOfQRH!%T1La(#@ypmb%9|nkRgC|MOPDZmbRw10 zIl>))|C&*MA&a}`vm*t&5H3$=nWSF?6{p%w*Zqm&uy9j24IP+d9r!RlL08}LLk?CN zb(?O2Ixy;JmzA|RNjHMzf{ie9JehR4VS6X5?OfeSEF+(^GFCHrXip^Jx0PnH+||Od zNAX9tH+sxw+t?_DbEzY#d}=l|ml9H`6dS&^I(&AdI)3RUWIa?FA5CL$>?mX^c%l`f z*5&NQOzp)Ql0#J_?42r-l-UG38>4SLNRiwoOF0uN-H@EZN04KM&3{HuB2v0V8J@Kd zZRR;xX4=SQW`_5~wea3bv|?+mi&vTrB(0lz4i1g8`kXGFD4jQ(;N-}f&;+}wBAqth z5Nw}H=T)4m_-Ek~>LZE`M+SWl#|I8UQk+=f)OawOQCC4ny{-OMB_L>_V62m<#%soyF=6nM zVc=-zVCeY}35BpXA`8u(SXNsb8WLixxittU3_XkzoorN>{3Ov2^Xu^%e#83Xx6i+F zeczrJ_x>c*<8yYq@3^#DA z72Lt$N9AwJPs`i}9f#wFAcjP(rQIO~r9iSxcKKb69cjhwOSZ(hSbJNV>o5XZn2R}N zg=-XOP0YkVVkjZFlvp%IJc*dm5eoW!9kE8v?UF#oq}b^7A_ZPt*>3qo}>2>wiB<>L&`aC6ZrDlAL`#&xR%f7``HzOSJRbY-@<@sIccgY*M19c;lSNfIe>CLt z#a%2Q#RFW8D;zL`WCo)O%d-!Q5is^E91w^p1Bp}n(Y5_3K)d@VoNU1IQa+Ws56M1! zRv2#VGkPB?Rl}cJAQCnlsisVBk*Gz4y5+QDptguvC0IJ)O8w2lyAL0O)=@}IJMk6$ zkN4KCoU>%_&fay)R!nbedp1@9O>^OQH@@@i)w8e!=AOOyr}H(C+P8gdbZBoKIlkja zmu`DzEH5ZH8 zMGSVagX|QeTNyCf?+s;rkn@4h2B8HUoae?7af0en!zxv6A-g2E$S35h^2ajYBKOEI z$dr>omSfQZ*>(5j@~Q4iD2EshhBt7lfW~tMxbV)qd%FABIaF-9%ej`83#m&vHg7DK za;MSEp4o^9V;fCHpcO!-YH}umsQ|B?%33|upgvP@fvgo>QkoVU(g9frAF#+%64P5! zTMu5`58r)ff0O^Dp&|g92AH z(Ui1Wueu?kK)n`&IHw;}kR2j`157z#FgOI=F}7jqD>lQ3%-$(7ABwLh_9{Q2)@( zhsdlM&^rSLvaq=p7RO;A469W*?f-+HtoMV}>+=#zqo>nDJT@?yfl(}MWPaxSim6kZ z=2c{;k=iD6%&2hRLsb(iXG84A>=2`2*1(pqUS|3}`w1Iiw2KY0?=i|ul>rD;m6wT} z$i#)>qoT<|MN4_sWUEakJtE6&Paa8*CT}M1CHXx`NCr9%b^N`9Z0Z1a2Yl249qW+x z5-dS>CtxT6386F0+5_$D+9}u0+KJfS-sGO&7+BB*Tocl0Q;d}agYK+5>sK?iZg7jC zM}>95kA$3Hl7vd3R_GB{3a<+%gsTEpNL(OTSrX(HA@5y6q+v+pNBWBL3*(^H;I;|* zVVKy6L2oI8;jl!)b8?#VwD{)bPvNkBaNt-Aj$6gOo?IQ zG-#4eaivpJ8tM!1G@gR62^57*fiw#bmO{k?8U~iE8q&w5Fy1iI3~C}3zr_M)AA4GV zs`=-YpZ2tUu|D|HuGG3@_3GYX5WZX^zvVrDeVK2=;j(Y1;-A0y>AS7*`I(x@74!f6 zF4_Fkt_?Gr^{>v4e5tclAJLPr5b)&JE3v zd-iRb6SM~Ftci~4`ZuAjxA6(pZxzSB#UJ%W`X5`Z@0}Xf7Oo<%{8cY|vYEr$)r-Rb zMyR2x!pI0UTpgDoN;YRs!tBK33DOXT>tUE0gfqdLL2@Mkf)Z8+6gr|n)Csd4U_m`a zTmmc+z)Rr~)Y}AJ4nZo^79w|};PY1i@e+4Hi$pyxwW>O*L`|`HFhu#9$>ER?Doxa- zGEPTrGM$k#(j=Q1!!i>MQ6~D_u3)&-A=&)_H9k2}JE^3ERcKYQn!2P7=_gWc;!|m} zA+{;9kL*-DUY-#F^}A?R-X6bkpgfXM3}AQ=7)}qaoD64T0B54HCm1On7lLufjvLf4 zQR5IPnuuXqjvJl~Y|p^b49v=aCt4ky9laYhZHvO`uUk9vlz!(gEpH4Aocj1J3yghy;yTuX7eBBOaJ51uqAwnDug_Aj1=BSC8 z2%r#`o&O@c>SLR_uJ}Fo-uL_!+s}@j_u|+|NMa{hOrF1Dry(UTDTI#&2mzcA5@0P2 z3^4*|8wf^8yD_$Es;DSTbW%z8$Cgzq-GB;+#F|oskcOM6&01Q)s5T+-PpVFuREaH* zook1+P5pfC$Ghj9cm4d%@Ao@|c-$^mC0Bf$E4w+|;qV5Z;Pfn?;nY&s z{JZ4EYT*f_VxcSxN)j(QE+MlXQLZ1?6w%>}VlC7Sh^2)JumNj8sJ0Xs)|2N~P_gcl zdL9uoaq`Ty0|%~U=?h?)J5x=UnHl=>DU;Ke$LaHPN72sd<3c6Iu@&t0^E<7TmY9WFT%%5KI{gkS z_{&Quw^$it1UxP$GrWNRIF)1@hst8bUBrp6(iig?K5p^({Df4JZnBN+C1d1IWSUqV zh>-ph{z?C|pSR#!W%#@ORLrPf&p#vO2I_CYMrv|aO$eo^CIvmINzyhq*(PeX+}%R) zHY5f@3Fhu4pnHXRV%P+#VVz9qfr@YX&Q_rQb6u zLOlbKbXPpugYbCC9!m8@B1V^h%7`bFigabWXjdfqy9f~cMq|-!(GyW_VUcJgx^-p5 zZ}^3ntaW-)ev1Vw5#;@h3>kTcd_X=fbNQ?RMqd#WIh)Dw)MnZDOrKXfPmCkrG=?u5jro-usDqA?DY70dZDgq%G#Jm;@Ek-RR;!JTG za2=P$qUC|yw{L#^-H~sn);eWJ7KSz7(vx}KF?@S!<2Yu;IrZaRN??XJile+3&(UH*a6-MSOj zoDOyz3;*Zou9lAWC0(nY?0Bk`j{W<{xGQ_>ka^Yo_@yeN8PreA@#xaU+n0L@)=RNR zjqHQ@8sbCa1&zaP4m-S;y!3J@Xd$>Af)YX5s;e|qUgXrAfnbHhUSv4b76P)*+5rzUc0LiuP&P0WvpeqA5BfmxTkn=8mg9ORSlG0iF8q`ZCm5$5)T z05Fk*mZnVJlAbVH#&7XtBwS!0+{~J>wlL069u- z8qe(9-Mw++VBf)?G`H^kVO@0F_L{DhMb>2oCssUyl{Kx=nwn@U>kFo0K1I=jYghkx z|Nf_kJ3F2`luqo~25iJ*sUAR5*|T`0TIXoqnGK~^GqVxT`;6koK}&xz@5M>=rgnN z7-Cl?tM)FUyUpOl;V)>tbjdW~$ij%FQoV#Kyq@+`1|lM1EFY1N!nY$<(?v~{bob#2 zGf3oYOW9ouayxGFvdm0VH=g^gCqj8i9#5tLEu9;MckC=i23Qk zwI{V>)%Sk67Zyq7n}$~(JHLr6jOxIsM3SxfsFGup6{6lseic=$J zcM}<$Om>D5zl>CKiWq(^<;Fy(>&PQQD{yaYTB%?Xu8+GgAE)(ujDjOI&F z+(1jRx&ZJ)`}P@9K|j;=bbFANRw~IriB(`!05DUmQC>oR|yo znKU6ZHyA&%!3d*;4mE_WYd5l%k%)psL}4WmT0%h;UDxghX}i&hZ32~KgKiRTMNwOk zl};V%rWLwMW8I{Pi9fnFnw`Dxozo_TVp+a>wsr6O-sgSZ`@D!LX!y8xLHkIf$2Huo z;fJ+-+EW@WQ*oL4raGn4u)0Bg8E*fo^3AHHcB`~j#m7~wRz+af3y?7SZw&K>m{DQ@ zJt=3fFB8vz8qUnGPeS^c%5du~CJH1)OSCOXHjjx|%!Up5!i;7p>4`%AGE>2mCArW8 zA51c{6=;CT-~qOOg;z}iOc(663jXbEZ2gVHJUpOrc-Q%14g@k^63WbW!PNz}4_+{3 zdYLTmb@Vb*9b!c&=-{1Wc$=U>Xq{Mt)e2ghD+v+NWFkXRD;99x?&`sFuTZddC48CS62M8?r~5w zf7?^Me&sb1dl#pO6mH)8)n#i}@9yaSL8hYk_B7&P5kmZ8nC>x@LQQBsnzHT?C>Da) z9guXmhEqPd?qqv#A|CK)`k$K2$YzB zHTZJ~M>Lc*(kUwHE^nFaaT(d{mApL3Mt}ZdOG~4p>ugk8S~fCd8X0N~wt&6lG$Q*) zFdC6Rn+0Q{rN#LP#C$djmc7wH69gSsUG4ON9P0(u0EG&RE(0u^ss-g&9pueASaBAJ z@X^9A{%*8&NAZo~fmaW~i!?m3=HILDTZZY1;@PGp&HIXvkw23{hWv?k7W(kuMY?`z z$D@T`)Ad6ehA{RvygB4kDq~l2f%3b4Qz>r?*l}t0gZON;ViVCcTZPV znbp7{cFmlbe%*Qq@_eBA!)CI-2@ls}QWvNrk0t+-{8#dmBqs*dAQ|>!-XHY;!%w}i z2;rDOwd$lvH6Y=B@rUAZk*`@y_#!CG z7S?T&&rF7Et29w+#%-Q15Ak`h)a;p8WqBnc1O%dpNs%BCmve&X;bgbR-(rC0pX+c2QQA9=5kxm*4KBv5;TvcdX=~PxLy$YwWhB+x; z-dNhEz{(cR=UbTM&)RE%!%rLdo=&(r&`;#;C4mVQ#@2oqag9!)l+?dXMqUQ3FMzZM zg`Z=51b}n0O+c6ea0%Tk_L&K{d|&bJ7u(}o9?Z;JYTbWk@Atmbw(y<4y}$1}y{vu5 z(ZbscSN`PbuC~rqPaXZrB0SR8)UjOHvhBIzjhAW;Z|_*Ne&N{9x|Z+U{T%LjeCdP2ff|WN$IL|UE+`=OS(j* z3LWi%2^0m@JppKBKf}S{AI#G)O#R$^ml7<_B$T`|E1_dcI(8g=p{;4*a^a!bS>r#P z8i|Z-cXES$Q_MTM960e)FFWhE-lobO5_v7moO5Y2}ocF?`gkA6hY>r~ebCDjcZ4{3(99)YEYLxx(Bx~^cP$V#(9T?#BQJ%!gG z-~A2)`ZqETOwMJ1O@Ujcex~eU>t%iMa~QDd*8R}$vO#<5sG;CoRQRp4Q0dKe6|apw z|L}X4zELlit!TX^L}cvMcD?v~;SXHx(kU>4aK7E5+-A)ys}sKQqk)TqLf&Z+M3#vx|E`+Owb8IK0gz~ zEd{SP!7*{<)|_D(Z~R&az4<;b|=uU6tjx%`r1zWh4ykTc; zn*feDE>pQwP*m{;PCUhXo$$~cuS+a1eBt5+L?Nabx8MMC7Eck6*l`fyS^hBO4?+Is zx`q7lxz@TI&m6I+u8-R>LN7z3Fq>V|=V0Sh(IzVv9O|U_FvYv+VS0>Sr5vI%1+`3l zLvG8>JV)I=^OzgEJwvS91BvVvQAB|uL8#OiktW}P)-Z{Tfs$tZKkL;V+thW3&+m60 z_g+6@$0j6!5XW&s(wNK%ad;;9HY2p*rAcT|CJaoA79MJwWQDdvD6oY@6-;H)R;pHm zYU|pe{Q*m%Jk+A7$|gXIpekbRBw(7#pxdl6RboZp>;2BPVWiNlnuhSTuXBCQ_j`Tc zcP_Y8(N7I2Cs7AZZ%y9g0`er(bFbW&0R}3Jl@_oV?ldkWBcbzH$S<&Yt!Z> zjdp5AV~4GCvYL&+`*4=#_M5i9l-KduoHGuS-J-wcFHZ8~xZVz-jhZoWC;;#&FkfakhhW*TKiy}?ah#_Op- zv_nGiQm%Bg71EYE2>}_AXviU92MkJ-VN;e2oux@O6G4H7z<`@UyO6$-!tt|&e(XkU zu%UvWm2#cP5lXLqATq6cxjx;A}(*2}alo>I7RzrOeP zd`;58W8oOR@b6W^T1q${#+C$B!1LY|G^(+tNdfU|u3|N)uplNuK(6_im$6vsh+P#mg6pHowIJi=J~O9-{Ftv z)U5kNPRl2Sx;3qId{#e(w-Y#LH4VVn-x=G7aZ4%lLiPjSt$m`T-c2v_9Nh`fz zXq^6u%=qm;j#EAkil;txEEIGjPef5e)_1!gdFz;cH2kHES!Q z$-{hh7)J#GnKG{JTVH>?FyAh!?3g}@#x*Vy`zWfLJ&=|w zuEJ6_0o9L=U^n%q+hPwv<|49vR1?}xae@d1h;R=gjKX=~RnSCS$P)kohydzK4!8k% zh`)ab#60)9F!Qx@lNf6yust^+EuOmC<6@5W6)z(G3&fHGc(o5rhE3 zI(!-jkkgb9&i|6oDEX%rRL(DYZaN!b>D37s_tXA%w2!0vL@*}PUp!f z^uZWZwz3U>Qp?0SMWd|zgT#Wgaab{C*VZSsjwcv57$5Wy!D${2j%ozUGWujtC^_Xe z9uMb5yd_5zh*7P5e`! ziBI4Ld=ABR{2cK#eu(IA^Z6vD;=qyfn%C*Wv4VP$E*-EZMa%^0sHxu$QSCtb+Ps9H zrLyNoFOZl6F=O^Znix4jDBV7Vm^QkxP_&9`rmWjGb>HraZ4t1*JowH#@(07iz@4UX zU8R__h+Sfge9$aAsywDwqF|;0RUEiQx-QZ5T88i>G&Yf-9Y>2x=Q8&Lm4@nK)ERZN z>t>hEE;TN#*}3!Xf9L1--RPbAoi%K?>+Ed1{60VV)lK9*{}|5u$K7ABkN5BK|8S3` z`Ig%~(LADajV5cqyNjRg__zBGyY8FLp{6wa9`3Vfy7c!^Jy>4fLu@%620VVtN8LJl zgnsPv-wjcN`J!K+0PX?%ZWNsE{=AF-B#$|7=HGnCtbF$b^XG2ZHAX0Dl|^cjvW%w1 zGw8Lw?zDI#-g91>7Oxm2X~OCej}SVR01b>bP*s8(f(;sp%so@F!I+T)8i$$874T+-1Px4SkGsukj>98xoBVrG!}C^WzEsD%d@Qlsm4#spnu zB6~p}^vGyyCxF!7E!5;;IdmiYhwQ~0+fKsAaP_2`>HHA3I}Y)qUR_r3JMw4bGK!8c zz$Wd3sh3>Vj`BOVSBZnN!tKx%&P9GFx2o_YG~t6!Iv01cT#oH0JXv`XC$qmXeLw7M z6jAs7?@T+Ja>n=-F`d}oLrRrK(*o|Xgk?2($)H=+)`<0C{FOlxoF1kNMok22?W~tGX zYd*;?QDaj7X*x2ycSaVY}#-lt2En(8fEAMV`_HTI?UVf>0`*!GXPKoK+5$JPX zEJPp=Q3L^Um~Y$P4|6h-p19wyAQ+D000(WAkY-j|p}0~-al&06f?tJTW9XyMtq{Kz zf^UVOCX@^v3GtAy)FY}(y`T=NGm0*sDEvs>QaG7H#OZW-ThUUUqS_!3!I_1#Rf(vT ziA?bF+Vt2Mg`@*&N%s-O<=@i%EOkDUa>God)A@Mmc{f~&HCn7=jh4{6enD}J%R|}4 z&d!(5V2JlRAvojAM$9h$&V_vVuR4Eu)%h*VhojCC>Vk#2>*}mnz>;hsTLMx0y@LW? zvSIj9Sk$qy0~HP-{xl5TkHE_Lu;sB`kKr?^!4#${_8D&)_`LCgfy_8e$0MV;R8oogpT&`V@7 zOGHaDPu7REws1%f=~7wJ5sHT}ABs=dj4OHh!ua8z^W%D^e`B_A9vC0+CY`^O&vmA= zg0O`03@u4cHU8HM0fs+s%fnI-MH%qp~Y_}EOp`)Jdzd$u0xn^C*< zPsZ4~M=^eYy@B?59apFQ4leoXXCM9Nt(6QmcSE$#9<7Jj~7n^BlvI8})(+ZN0x zWlv`!(F%8!D!Mk3>ty+JRr zvp$NJL6@3z)COvCoy8{wG)B-gTa{MEHE1?L4SRIB==Sl7VA8x;k->TTWM9xn?8L`- zqT!+m&=pq@SSt}|h=_K^Cflai2ydfy=t3bYUr3aS_{T=mjulr>zjPjo)YzC$B%nz2 z6n&!rp`jW`J1tF!8Yw4K!t3*T6l-II)}qE~)~?yz94#%_`hKp7<@$Qg7@-Xt(C90( zR?KQ@8Z|!YXxcoM?FzKiRX>7S`v$M&f0XJ#m#uTZm-+TQbUB00%IbIKbgy_U(-U$V zS1eLP#8{nd_Zq+V)BtKOd~loO*;#;^Z6<1tK$a&#mU+g>tk$El9IQ!(5&D!z0U<76 zha8aOG7&8jI8M993bydLq4if6WgI|;+a3W?Oety#OZbZ{V&f1rAmoLK&Np*Y%n9_a zh7<-85ehO^IW!*bB;#hm*n-w0JE}Zwymso$;qDb!ePG;VqsG1a=(&R2y|Rdr=JQH$ zv_nso)8~yLbW1{NSzQ^nm8<1-<-}>#6pmwM&Bl4)p&jmkJMJbTal1YCQUHO60aQ9Y z5sv?VF%;`P5r)$o*;1ha{LERT0m)3MvZbIr6M@|_j4kWeKMd{Oz471}5L2{bW`M@W z8RJ8U5z(5EQHW7w;(7(A*=)$7VNTGHz_W~<6Cw->f`p5A!n0k^ z2H|)^AAB@PwICTLyGfSZAa|)587BK-aS4{(G`fWuf>x3Y`IL|_L5B$127&>LASneK z$1y;^zZDS@v5jQ`Tm(E%=n%dE6)N}z+#sO01SBv_5Hf7%35bWFsT`naS31X_Y5F&U zdZ5xF3;%G~-%s}d@U;;OG@JIKoEs^ZH5NW)KF0&QGE|Z;?+n!-tCOZ1H6rr$b>rQk z6DQF7pBc~MzzfFHFfR+yF=K${M~3p=f&AE+Q@Y4oSQ{&1A`q5lKyvw$LXf_}_9?tu zUrGdp5P`8F$!6mm1bIQQfFP1I9SJr;pstk>&?NymgrfrH1wo_^1p=G`t>fUu2>2M1 z#g{O?ixGo^_y#5zIBVnIvog$zJO(6IWVDCsHC<#ubALqEMqbP@8Wm4$E+>zSD++5< z3W7~}tj-X=Q+Q`^@Wh!j=qTFN`$jM3jn_xt7&V@weZ32?;Y&6Oece}7h|nE(&2^8t z25rH{Ozc}^uH7&P$LQJ`Gv}a%sb=@G7KWn2klynH%XZ6$ma7(afQpXI!m9!vuy3>D zd9DuEYS(8VxGZhnW!^sTP48D;OIyXVioOamud1VJbrn&1N;KMizj@%(-c~H(7ceQd=X6OA5)xyV2l!Yb7Sx!WqTB#$@A>q(Vu=}{PiaT z`!ad7>6O`;t?P~)SUWVl=J4UQ!&v#^iIh(!}p%w`HMv@k1u}b-Nmh~i)c@@ zFssZcea!nO9kS|A!f@Z#zXb>F=oy5kyXL!a(%a(22hd4`2Uw(njKnHm$75?atsq7T zD!S6Gup&{27?yNwnkjv1FP2zylN<^<6^k|cFfHs}<5=ZijAxBi$mTn~YR&%4 z7ihz^>HJz!TP;)_qpCOWGjemz^0W7DGrB!YkP-VyJcUUsS4t3Iz1;_wIjasN^OS-*v;m1~2wz@-jeawG@w2*!?JNCjw= z!ZjGkq0C_iT0^+bG0lOaxEW)tN)FZyq9Gh)>#M>;Zlt@r-NWwvZq{8N=D=*J^d`xH zRn{kjgEb*GTH$y20zPc@#iRa!ut4Y%h)~M5(>KitNCVSkzQ+4*e7Cc+v=8%Fmdnuz zG(S+MHcs7LW_N0gscM#+3mE2zHO5VJYb@mhAwyLrs2fu3TGR~2YNB(`we9$BOV5aL zc~}3!k-0x^X<4`9{+ox|r*2vI%RRmLiMAt!)9InLN9NCH*wwv8_Xd8o{STx6W4!8P zn>f$-z4xAdw$DDFbLWrPPR^;nNF9iqILQJTIYJ5HBP4{B5)wBb>srEBoTviA(#8r6 zAN``G(2@>H*akF02($#cFgh|CKoiS?R*J+_$SR?!LsSH9)mjakJ?}Y$Y3(1ge7?K) zY~MY<=Xrk5@3*z}x%G3>XKd>E=ezHtjQ$nnkz`5zA@uuYEk|k>8ucWvplsNA;2dNs zm--PhD4%XY=rs;KFQN1Har=ZF57<$keZWq?nvS+)qNsO+_hm1x_BZ)seq0zh8aNZU z6kuvXEuoGOj?UaL^W~X%Q$D&;gzAb~i#m&Nmjx}d)LB|B_?{JYTX$P0tk`OGm_tGs z#lms0uHmcUzlJBnOgQ|y4mouWgHLq39c+%9DR3LOe>suP8J^(_3ua_C^B&(RYJ|E< zVQ`o%HQVa5J>@&epXbMUZ02+MDjw^2LYBle+#-9T|1W|BDNZ?s(vBVpPRz^9ls?FKw4H-P_#TKrkI)B!v1?v_2BYhuN3eD@$8qp^UiR_^_? zGPD}CA?vojf85*NJ-o2t-2=~5RMZ~4uq^Q4v&3nxymDJl%~INve50oOc9>eaP`d4Y*RqCiLHQ88t4HeF1EelOP4 zY49B$-EpHMGtrT!kj$M7qTt(BWVPaSL7VHwoXiR7ey7(r#V`?zUkLeRwv?@68(D^h z!oQX({cC_7K)5A;3J5p=$!@iMpMCN3H$MLDy0!Bv zVhv?;hja4l>+^Gl=ax0JRg|5Ll)UglNhELf+O@Ou(ALv8H?AAr{9?P6lh!mf*OygQ zmDM*lt&upX7nA*9o?1{35ym!fr))uQ!}vlA>$u^yI&)VC9TtUjNrk5!qf z%JmL-tB>jh8AYrZ8zJ)5gYWir{_ge=x-hu0_iXahPd-O}`u54%vSc$8D6c(sBKZqY z4Kh6O6;)Mqs;Xh?oU&4x)Ny6ANe~^8MW$V*KGT4S(euUp0FSqr(Mkc`z<KYeNC@|~;dE=(L;>MPo~W^nNG>+@Ta6*UL8KT|DQwxP_g zVy+PS@If1DbUyjgF+e8(X!NS+tXDPGPU!5vsOMfPr9SGI9(;y!Q0>aBVj3A~H=RS{ zqsHq-+AjLrq;ZKhOXsBt>7m51SOR|_*iCN5MyaOF=Ff@5QvhJfsfaAAzzREMNQ6HT z;SfR&VHBigULKimWF>J??R98$GN-Z%vPfk@j|9lE)oWvVD%LG8>_}{+D|hGa4?ekP zN8&OQI531ppZis%g&X3$CqP4$3?1%*IRg=BK2RfYgY>m18--I@}J_a8tbky$sL3}jC*utjypu3=Y8mAed zcebZ+`uFBBc%jj;hM=ILwS0k!R^GY9_&GJ}5389T<{sd+W0=Z(IH}~NStA8#0s01E zge)ivVHUgWeuvr5Gkyj0vH)&V=3SDE(>S-{%=jKEn0i97^B9x-W5~ZHKmTz72qO-N zI5A>}kn=;7L%0s{3yJHb5L6)(@(Wq1IE#p^B!?v6sdz!TKusino(R$h>x1*X8Oh6u z_vv3x9;|#Paf1o$J8|~x{^V~4^_HSpa}hIi?&O?|p~G#T-6?woD&7el@D-_es!r_y zEk$WQR?kt z=xlT1L(cQgap#1SaZ2`(Lu+s=0wGI^ZDM0=oIS;kuv$H48O|j+MUg-*+g%Y+)H-=z zigjZ4xSh7M{x)s5cDEL5fnY90RhlJ(74ksFtfO?4B!c+6#Knt{5ek+ar1m;4I>+D& z&`~8Zd*ErK9f&Y;M+dk<)%4&ZTWWTYgcOKsL0S>;6K>hM_E>V?>;c=(=4VUhZ7ABG z+*g?VBYi*l<=(~fPyC1}2{X;W^bcB?P#O*B)xXLItj(6Ag(E(MfxV76vcUk_91 zP=Pki9MLoB%paH=3|JW|T}Y?xT8@PLCg5cTWl_rEhrqj(EXZM5k(=b09GCm$Q?i~c zdE`kMekdChj{-jkdlXN#C+3NJG#)aT=|)4Ffi@WEQmIioB%Opd*GOq@I~&ff&VD<) zKYKD;lO1%^ob2Z~t=Z?wo|>_k3Q2ye&!<(i3it#qV5+*JtHAF7AnXBWGIK|xWFr*c zJ_ZQGmu?c!p`oYbI=n-Oo~HQ%71Js0m(u5;ZdA4>c;lS8$#Z=zvH45i>Ynp#)3Rf; zj?YC;lZ7R3#b>V~3rI|U{&dyern1G{&m7*C(#kxOgi5zzw}CM;rA#-on_>P#ce%hebzX7&d)&8kZQtwb#CA;V*s+}#4PetGymEmi zyaL@2p(HGftRaZUfB*ruif(IwQ1K|;G^QervK4i#8`YWsNq9(1i_(>eN4E$l6BJcr z+SWyAoy0`9Tz0lcl5>t;5?Y&Oz$pc;%Zkc+G| zB(kua;Q_bJnfif1rKs zoZ}m-6YY&ZJYPO;`P{iJMdjx=ADVOUM(eKK%}bUn+q0|n#=$v}j@R$d*R zR1bMYwtvF?75@7gexKtdlJ8o?tH(E?y3|7TC`Mg_C?BfF{8%D$D~#udTf(G1zbT&# z)9aKJ2Evl6Dp8jY&VJ0O_We7$`ZoD01esm13EsT-_-x4 zQ&pX(HmmfZiucHe<+o)Tl*{CKa$;%HR`=B2Cygfq<_Tsdd#&Oz5VfvFPJ$87D)3$y;-g%&Xb;f5Ee;wb# zw}0lUWzOxa!s0kk*aJ*{_Kc4Tl3;@4$upv4iK65KSx!+Zi5gs-)^!Q1CS3JOhzZt< z1(AuAmawRqYfZA&{EPXyNe4_^W6m}Anp80ZW~n(~3LeSCQ{k&npGm!f=4NWBUW`R0 z5BY^bCITpMXJ{y!bIez^Wg#awcW#F41R<_Lhq=fSb(9|%=0aQXa_5T;=6taq&g_eg zI2Ff@ZFgSTdl28I;~h7?>P#f!*!Hj8109N-Pw3q)=W3Vp3tWV6I;FsRlOWe3poAL* zfo!|&Xam9Zc};mF-;K+SDF!JE)&_|h#%f8hg!pwo%NXbmI7lNA(aNe4ovG3k5@`tO z$OAsPP>3e`P^mu({`QNuXq#3>%$0dIvcRl5iA}1k(6fpUlPX@(`gmAngl6RGcYccX zNElt9wEO;Z2?J`RW7%nE58iscF}3g9dta$s`~Hol(p6>aCa(PBKckDVm zyD!x}cc8xd;f8T;XC$x4>E9mrIzJP=vlECu`VhQt0q^}#O2?yj2T}CVO}iM#txLo$ zfwckB99qSr*laO$H~;S@^*O|$b9g=wSY@cv3xohu`wP|qs>>*^R__-3ZT`4xTk(m~twAD&V(WXI$is5LSahNEah$ykSsX%=70>&Z87j zFC`ui!TBP~pI!y!p9igEPzute7Zove`ej>YTF8%a0EFN^B6^ptXnw=wf>BgBC=BM_yFL-v#ha)E&szO0}_4+I8qXxa}sT^9}ef0P^|CrWL z^?V~^RPZPtJaVDNK_u}US0TEpibb|!g0!=+VoXD)6#?mz#ukii%odEFO6;Mbr_(yS zLm%%>nm-mMm&eYK#Mtji8`y)rcx|im?tfWd_}ID#)y;68vcu$ya3+xFHsQ~M%JY60_JsS2<>=t9Nu)cVl@PZJ?vklv8W;{m3xN3ZC z+&4sx8hNOQiAHGXR4f(^8Rwuhcu|x^JQ-pFG5`b*q^BZ2!mAwfg7GzHzJ(kIb7M_5 z2`U)JU?Axn_;GG2kXar8?MZ$w=a)~I1Z1xdi(OZX&Bl7ol$Sn*1i4lkf!Ch(uP|4i#8QhqlNE zBSU8WN@D$LMQaw%J6r1*CUtgpW(ONzb#|^X(q!>YyV?1hxJ}u&rbzFm1%IfI<8tqC zQ{n~kPEOMfuIU|HbGZ;9m@2Bu`=drJO`{~s4&#x_LdZp3J{Ph46pM5>{XV@%1(7zv ziN=96T!N^nFoj~?m#5}ycv!* zbrF%mzXm0U9ep}>0}M}|#P1@+&nT$FY=bn9v4?@Ky+L_9{aP z2NW#xFyl0)9VeYP-|FthqwhIT0PusO&It&$h5zbo$ZA54f+ix5wU8?~{Y-rNZ^o-V zD5~oYpWiw6v3K{vy?fa=3(K;)JPQH~h?H{2LDEEgWOS^LZgi%`)7)`F-E_BeL)S$(hjK#{=$J zpyR&J#=*FEfxqH@?1VSW_hV)Z7X}4ND1280 zW{9{H@vN#ynV|8;5M)kBnCt%*)`xEj5uA`t2|`d*G(kmyqqY&EZSo0|7~)JLm_Yy* znqH(hNOJIbE7`lX$+d0x;MuTO#1GjtIFJVs7X;t6yA7G(L}dB=HMLn)?4wR=ti$?S z=kTWizdn1S4}to|6=ywmnKD|Mrny8cqEBK@U~zIyk=qM zr5nc5Qo1pm){VMeJN)4s$5S%4da5Kq1!?S^y3^T99i4bw*W~9&|L4p#ef|df{0IN% z`5meA^Q*up9@HTsiJU@JcK99iisL%QdYiHtrLYKVWJ?&9!sP#>lytgxKcE<-$ZizY zuzl**uI*Ik%B4+yhQ<7ox$WF>k&TOgApFaBo6W7cKggw8ZX}nk4{Zxk64FC-gRjF! zsn5W1(s;_C8Ac91NQRz4Gh8_?8h6$>sU}85>Y;!a*DKf=RwdzSz0v$_B0ty_0&BB`qBhsa=%M9E>Z@?!Ka(NCl7 zOk_0jafIy;oDEzKFsB<{cE9c(a^G}+;TB)U1wDXc*;R@896Yb~>pC@DBrk2q{Re#D zbGQs{$yq$Dn@*ch2O}}{9XrD3&Y*G{fYAw?M0~}&XzPw`W_3Kjzh51qSpSNH(N_9df&hF#}QU*?S)OdTbfIq z6_Y#aTBar|oTbezy`Wj2SyLpPI|~pA9G=MIX08Zcm<=aEV9qRO%z483p7T#m$;C7; zctt+Moj|8fPj2E+%F9j=f7XAqXl|M_!UpFU%ZXu&O(#t|Xhthpf%W{oZsVtrt3W@FCalMRb|B8v4|`oyo=+~t#h4dP&M%dB-~Ch`iie2HK-T+N1Y z4~)A((BWhK-#X3GV|ta&2H9Okx4|yh3!@-xLp4dcA&zP2h8VHIg*E2d!mTSym30b6 zRaXw5TUBg&7w_5N(IE5$ZwF~8SRBOQ76e5M66%Cdign-@-6T9e$ZCSj%C$qS%XD#A zTr-?6P5xyb&D^%$w(%w&IcTZrN5rR} zCF}r?jq&O)x;M_v3;U`Lbi+Vqd2`zOr=GIt!s+R)yf&rK7XFl4w1|#*FNi z1&`i{hx|2*;k_f)z>-3)aTSPi6QV2=^Vg}sE)m9cSH#O6H?s+MAd@X+>zFuW$(Z8c znJL+JW(tFQLMkWjOti+)Ayq9+9 zJvuFx=gE)A*W{bBcv%=1=xkQa7BCiYku0t)5+28YztK=Rvoko}PSeTpc7CNXYg6f} z@wDAkh-686;Nj|m`sm>(rehXs2*n;-`4j6Oi{sszf5E)vhwCf4S!eH(*819a*1Sf) zJ~iB0y`mucXwxxT&ygZeyl~7^xeHN^IKeA19w%j20$)eWOjS=X(-**ifHtA> zxS-(9;5&ow%DjPu(+C-Kxw>AZdsT3%A(g5)7|e?>zv}dovwaE8fPFnR>h^ zp$*)-VV=T83?KmTd$U3kU($`Ce`gWKJNK9ZckP-63jde~-r17Bc3wBKq=|AoI>QbGdg zg;iDQ7}L(j++@2QWKyZc9((~}Op;j)cy__)l1ebbm)5OkZ)uqy^jLR$UkvG`zdg9S z#&1MWZ6@>B_sqnUib1BMebw9apyhn`$m&k|!<2?zpyz}EQbcOV^^G*_s) z6Ma!A4?|OMd2oFYC%uT1`owaF+nYGA!qu`*%IHf8C>dZmW`^YUx#Mo8xZPp|l__+* znpF+493rB(JR5o;L_ED^DUsC107*DB^Q=YPiZCMj9t7D;s$` zWB*jl;Zq`q5Ao(Q6fcls`P0)P{??}LSuU8K9(`VJ)vQ|Lz2^1s2BYV?4C$HYHqKx8 zt-?9cg+FbESlPFi6_t9n=ly8GV{bHuof1ep=l{5*C9!9Jtp~2nPHe2GeSA}Wc7~!D zfyg6~qHykFeP4O7CBGtP+0UNOSPiT+J4*`WHneXop7!>0!XPO?Hm(ekI1-VQ;Ys-O zkd0G*$TMJ}wnl5!7y%uSjl=-zj)9C^t{ktVFP1=WKAdGx&Ph=fN6=B^U=GJDZ)5FJB+O#L{tavG>Ez_tuao@#&+~u&56JK=eGPu@8Ty)i!56RP zf!f&$bF&gQ7m`Ue9I1hNW)kqK7MPrQg@FEa>g|p_fkRDQ8g$96>9T45;zNx4{KNB< zYNwTcGaY1S$84lv7P+4M@XbNdC#Py2@Fr`h3MD@kNJ;?@~NEIrlOet5~Y zZ9jcs>Gq0b@47@ezQ1JEzAfke(KU0&nx`jD9{}sHDDt#5AcRsPK?!Gy`x|^+0&|;v!=lQXb zF?pDkhUSrlN5kyx?BGp!1u8}RFnGoW4x2*VEM?>hLy8^L%Baw^PKQ=3|83bqNrm#c zt^^DeifdZ`LI-Q@s}E@>b?0AA9qwJ!ykc+EZr)wCH`|$8RPO0`N)Oxj-2&i59j-M(g1|K*=Ahz2wy<`Mtlocp#G4u(oz)Y2DiO$rxSo*5>`2yXffCw_m>V{`RI-oh=&=)vfMs zne@nafS`+P6Jgv#EDhB&KdyR|EFgwfV}5tzWOMT8Gzv#N2&mX=j3n+g-< z7C2-PD#nf>+Pae0a!>haLAEu!xxgrn{yGKuHeBcjX7NPDFHoj!^2<^UTbw zm1!06c$9z46P_2bQp}9ZQ-$i`7gXa6Zo~apXTbqX1d6ff&6)tC4FK!my9gD>gN+EV zZTKb^yo^tBsgGItoj^CxW2BoL`T|7~E@ptsq>KdBt?rQer2%O~8kO`&s+Ne`BH`3s z>5()cQK?D`s5>V&!<+J_n%hhn6kA%x@@|v6(LH`6Z&Xt;w!250N}>GrqD&W{$eA}2 zjwiRqzv9%?hNH;?_5XgiYsHJ5zj?c(?Vu1&b-%Qgqa_>XH=nY6)wlL{mwI<>+i-DV zXJx}rI-lVlz;b4RNe1Y}F1Q>m##cS~6YdL+=$%gIP3PxM9YsVYH^>Oli563pi3Ig> z2AEr9{79aFm?Yapm%^C4f-Hj?>cv*EN2ExUMIbJUI!PPwb|CJX>~jUUPto>%FKvT- zT}xgrhMa|6hTPC^7%+?&Mh$u`^13YsKyG+sm|%%_I&wAyrZXSE`2)y%v>;G021r|> zX`WrgPfAfsZY}G)cwuE5aZRDW)Y<;?r`t8`bCR_2Qr~u<9o(2*%;>-TEnrXAv3-(p z?*#44-HEY{0bB2lY7Zx<4$cadQWFVq9M`kd~Ak=fk?Uvat=DQ+_h_k}Y zpe%C{R?B{7_Em_c*<8Hnwau7@KmCRB5D6cRlU zWP8Tgz13{YGQ8T%9jk*2%et!zX3VComUzJ`*%;OG7c6eLP}_z2<^ejh7R5O^A@epv zIwMbVP0O~lw=`_HQ@g9YZ+EM2iMP=j^Lu8Nr;dflZ|~RCZQY+zJJzLV-?s1D(r(e? z9x9XuD(XsuC!gi73?X6S@gOMRgGn_AB9yQx7Xl%63rB=A0_8k7sPj2|Wj>moL6U^< zVQdUL@t(Ady`Z7@)8=*!GQ4mRs8eE(b15#;mV_}-& zRb@y^%R_-wf=Y;rrb4Jzl(wR%)a#ymXN^hWkE)h-_Rg*?&pqe6-}gHPV?J$Ew8cWR zL~9~u%+8GDn=q0CFydIi)78T-3q14Am?PgQPo7}WP!YffG5atz^C>)LZQPj{nghR+ z6-tJ9+J<=AY9Txeg>X5%_JnXqpeIL=OyZ8~kB9EV%;hUrc|7Astvm!Et${nu%od2r zk4kAE<3zLndt%ANvMy}uxHs}bRp;*NM!G|ZEm(CpkKx*#Z`VKf*0L90S-quu{-XA_ z#N4r$6LZK@->rOUVS({EDqz;Iy{Eau`_3h8HB6&4viURJB_9KeaOIWsJhV z;&-*k=0!G%K1=NYlE zd`4zT%*#mm0rqD`7z?vzMlrM6h)i`l4)8IgwVQvR`TBKv)!g0s*y}-kt_1J8I;M_+d}35_@tWcU zCc_8E8+vrzJa%_PT!`tCNAKa>3hhmu~ZCaFoLd+pfETg7+~({$y>=FEdHtB zW6lxhZ=LiV?E{S*$OU}zoTlNSEWgE3X@#Sb1KAuxUU>Ncsj`8JJQ#U&PpyZl9;;}M z9ax?ZZN!SQMDLbrEW+Z9uF&9G0jMBpj5EWextL_shgg!4+s-C5x2>#TmWX1%X|-%TjiSYOP0E!~Pg8Q8S2E&T?$)c&n!o_^&EQ8)0e6QXYK zo7`Fi^?IK45Ry+85z?$})PATP*Uo6rd{@*3fgN!XH_FztNiNF4g%;l#C|Y3h&M#&z zHUhdJq!4^!6}}{aUwI)cEJ=kKW;R&2fN%)%`k?{Y!!19 zqC_S~e#zE(6&}`rn~9H{$SLe9jtBCBC7R`(v%Q@)2Ujlns^5c$`bw)E8?1(ZCBB{- zPxp{Z>vu$Am8Baq6nPbDz*Fm!4?P9Ik3K&B!Fv|GCyQZ`!#{mK7jJWZ+d1H*7UxkX z>1F%aF-EO$AEmidmE4FX1YG|s; zFvx&l@4t*7ZSv00oVcNJ_Q;=EU^rALmo*s6H!RdoNudRoxmUQ!95=X>SN9UXtnyk! zA*_(9tE8B!sz=h3ip}8jQH5TkOMa?5MIkwHvrHlF(}lG0KSnqoOgzKaD%3AqNh-;b zC47`x&dH@np*2dYa#9&pBt^v7G*$EBJyN=f^ZXvc!3=V=ewbhIGhN4gAwHM>kRr%H zO~a3S`aM0NL%+GaH*e>>zh7IGPnRD3M#q~y`VjVF_gn7UKW*R@qm@EuF7$RXbir}M zao0i5X`gDJY4o%UgFRpvGvtq8r<{ZF^iBgHnJ4H)xKI=3tGnZ69i3(I-F3|aN1E$s<<_dkhN^9YZJRpU zGYYs$D>M6%Z^(CLdX9cdKcnza=Y zG}pndIy=hZwDM?s2Z(!HRYPOdR+9?IHRz9yqUhcTa)OqNf#M>$@m!*1A{0=ELh zW%FivNmMJ+h$cs5a6_0Y3Bo!iUfIg+&<5raU1r#T$YInA7{unb5w{eu`Al4MKp^`q z!DzW*(cMAguH|1AqGn-tmL=zGrdldECsZsM(a=dm@<8WF#Aizr-mZX$T9C>@0;V;j z?os!v{puA}jzZCen{qo9g@UqhL|e;6JVj|--P88U0Zl+!%am74d+K9maqUp`>K)7b zHb3{;ud8S7E=aVsEt*@9Xy0HI(q(^L7jI4v&_A_we%RRFv2xA2nvSmJ&1YijD4JW(9+R zGOB3)h(GS9E{o=O_~3DKrq1vp-EZiy?&ss3o*67;XoXuAP8jS>zDI3c+Wg zQz3vr=o#oRd@9#x=V#i%4_eZW(SMjP_t>V+GmL-l_nmXTW1qy=lQ<@^j~A0TB!Hb8 ziIa3TZOEEXNXdmZlq})WlyDg}+n^K}6wv~rY`{cUIx*i^E9gIm? zQCF=)qoP76W0!6dqBwiMV+Y7+rS%WCoj=a8W6L>y{Jih;dommu4`(nn!vlU(xHJ=T zk9byR*9|?aBNO5|rg!O*9WTxLaO%OZj!dY>b!0+)uTCR65Ius=8Q1kMAi{EFLBU0W z3(*z>!nY}Bi~wP!nMioLf+9XoxEegDY4B>Yv{DYxnod834IXO{)A$$jwBG^@S zpi)+HCLZN+HM4?p_#^)-r#tvh`C-mVcrBmG*&@D*Z{f_w{ha=V!zn(RxoJBj)VS5V7o|oqMe;W64b;M-6%Uo+JlN$k>Do&2r@#kAPD7dMC2+r-I4rr zB6)4yOWrJ7V2`x_W*I$~Y-yMp>40Oz{Pyp$fb=E_fpU@nZtr$8q8+H%08lJF+ic_9U`Eg6alVNKV<-5E?(doLKzaR`f~KXB z#wlH0_1}mromw!azMM9$&C~BIExk|ATRUw|qS~sgBw!J$tC!N5TPG~A{x8ar>z|iGHEmp+J?oweSXa_{j4h;@DqhVJx6}7RU)F2Nz9Z6bpYpwl`iW)B5L|;!+!tb3e6~9Ik9B9xi9L}V z0yjN(^F2C=q#NU)+=rPOBA*{EsK&ArJTZJmG)CWv;q&ovqB=(K^nx2&GUsMuRfI#< z0V}PwLahQH$uP)Z5(OJ(ukUp`(evI)7sjzER*3s|+2BpvS=;Yz%$DPGO>ogn7g(qZ zJd(?)il#Uc#CfCp){qpX|W;V5Kt2;>j$!913a8;ysOv|Scm$I6D^LrQ0-?MY>BBglOqx0_XX`k}Q#wCqy?M;gpHnp`qD0C-hSgX`W z{G^2ZG9FR`DDmGZ+)!baWsBv8g%xGOhqf!W>o)d*ep#m<6kjf;j>$F@)lPzV&P9of zaK1&jbDVqyC*N*&DMhkC%xp!`3?W%oK#Yh3hyM@`zKj_U4q|eWVb=_eM*Fp4jW%mt z+ET4wlZfWfA{x7>fhPDyME9Vnomd38W<{{$Y8bfrHa3)@(g-eCQ^XY7px@F8dQyUU zMi#^^6`hl+Cb8D7Q=fWj=i^;Xts8QludZ2GUGVk8Gm6*c6*PtIyr;U1bsvAGeoQh6 zbj|V~ZC>zQ)*C*(bXtoC-r7{?-PhjM7HgZB6H6{~b+wLcfPUNn8rdHY9arB`>8sjt zjqaCE$W%k}BPu5rNd`r-P*9kag92uf6ON;+P~$u7dAoGFnRXvUp<$+{to;kITt=dsQET*O?t$X&L3V)K4!CV zWpGmeb56wVW-E3ufIip{zXs}n08jvnD)%u1z2H9vd+9|=5m5pp)_FD-1M$;|9~6JZ z(uf-?f~ZCxKaB@H|NQ3xdQQ;g@M^e9XQ9PB&v>+>$lKyu-!xAZ_~6j$))cieYvX|5xlN z@_*b>HhfV<5ndc#O?Tk^-Bao`($wky-%=-S8cm(((_}Bb#FpG+>gh8RCU6+Jr_bab z<2bkd7pSM;9#YTFuK+#hGSpePOa<+pGf&)~h929O0gsUe9{>Lz@Cb|E0X&$y$yRy+ zH(Wj@@XdJB*2wM%?U(=^vks2lvpkU)SW4o(`jd#VKR)9wD6+@(YvxJls26{{&h#vu69P+ z@1F0R@0=TXVU1Adu&Vl$rbWv>>TEDNSJm$rTOHWpkIDgPVPsQJS>O*Zuj?I}4Ci5$ znA>Qk@UFfa$6NL;UwrhzU7MD6HPvkxXlP$vo9;<3)q+>1v(V4~{Vb%pCkxr{$wH1Z zjQ0N}2?6|PNr=papOLwsMkD`A5;EPFgtYT9$Q~E(k3rkfFv95|G^p6C!2eAYf`1W( zQoZ+QAwYGhHu^2}8>B@AagB;%DWX6Ue0b_zJV&Bn;MRCD0RjDNA~7Yz$TM7FSDMil zGMJS?`mMjbs;I~@)Gzz8F$b=s+D_D+S{ht=q^Y=KYv$j{%G@Z5dg4}0Av&NbDbCF{ zmtzWl0E7;BwyQov) zD8jeTrrMZ&Xfv{r>D?O7+ogvsdT7i2SmZ|JYIROwEM2RL z6i!nhcZGCge1cRi#2}EACiOE3vO$#fOBC#qTR;dSr#^zU;STm$%23+bT@thJ^CcZU z4f|8WFz}$bNb75Sd*F$_4NvZQ|Hz)^zV2?=GMs9wtURH$)Q0QIQy+G>cXX$6*HtZA zgya=~o35f(r*SQdoA%mZs||W=&~5`|j>9A%-9LqRGMJQR6L)LOpd7guW#(@vS7lH> zSKg38`OmB=TD7u>g73s7JGkdjZp_8=FmJSHS1WLb-rxg^j zFy^c*E&MStl_|nuxfBrdDUTr-gsb%<&-h>bZ8^A8-_0YINZ2E!mQgnqbtD5;pt*SH z+vRW|3L{|{E`--bI3U7PA`GcvupA7|sXqW(oPLs*rXApwR#mBHY+BuBqnv)6<){Lt%MAVV_Cf$*QY_j=EMcNF?BBWdL zrNNc91kp*Q4VJn&Hgx9JQ$a^IUme+zUBAlR+}X1~-Y7M!?Mc12W!2-8mx?ZTq}COD z458tc&h}4JbJK%2j`XbMKO1a+r>jlle`C!PR}MKJC=r(quJ0Kr%#QKi-inCdxGD7g z7T+)C+G}8>WyQr0QWtlBsY+%fPhUaTl`dpN+2~vGiZ?8$EqJfx1q&XqK%1q((p<>n&Q%n9Z8e3)mD`xQSJxJWLQyexII*-#T+ys*^bD5wgT zT3yUzUYFNMDvvC$WmfZIfg`%4)KZvhH(80x;nWlz1HaNt*j<25#UJf7!Z8+x*n=$I z#=?3QI$5Y^!NRaJ z_o-h}Q);B;AjQG2xDUBGj^eNasdU;ro5`Z%)Gn<~AU6V26Vpj4tpF(@BaxVrCP;o1 zV*UO4ndF2aMz%;KPRcu^{<{a5=t56sikh=LN`+D^i{#73mWh@!+rgi@%BefQ^04GB zK4?fC3OVd2SU2lmVH65l3s;od>42V5j~j}7c2C1Y<*Ta)HnuqC&b3m8upp`#8Y4yO zjN%s5lWtQ;Ag)~uruf)(ANSP0w-pRMIv>KKg*xzsYm%C z{vc0v^1VE+=OM-e$(c4DR6HEzMmc<*gGcDyG+s?Z3k@|iNHjQU09v5&Mf&&jXEc?Q zYqvS_iwe){U`z+cbnp`4kRqjpIW1_lj7p*Tkzw3`4TTh7RH)SzU=pVayms=N+#EBb zvLUnH++_Zyd8hfXnauA|C?@pl?h4LM-BC+&IuVQMrwR6#<%?v$+yQw)5#-6CpG~I8 znQ4ODhyK4i(#leLBKLLVi?wDhSSrHKyPX;NBJJI%_130N-rFAgKd3SFOZqu7&@U0s zJ{jMBBnu9h;D`neXyC9K_N!sH8hX@&YWzL!bq+tw4RCuns*Qsh4%}Rr!)6YY9NggG zBMv6GX%3&^;7tx*nSYw5))DA|M&d1|=$E0|u2AstKkEXA5mi&gSrBYNWs-E+h z6i012^LuMKR-H#k7HTTPi87Ih@;)b^f~7%PNtsO3wx38KxQXiOE0|{Wj5=hsb>3Li zDMa=Bxbja_!+)c3k_5eg&-H6bbuqAxfBy!Q=N&)OQV=| zwFXSM(aB5d6h3ryP1=e0Q3H;~GJ@&RR|y@jnvn_NcHGWn=(>O%npnKN97Q)8df?^G z&j(9uP?Z&_nu|$K*Lar1zLWEqqu6gqdmA^-t*?(SEG`HYeu*nCpXM!zE#$4%pg+6V z=Lp1Xd;duEkrh%7=GG_7`GcPG9!k8L{HkZ1u7L&X;+xy z5kMAfN0@xbS0`c_N9~%;JY^4i;|e3cVVOi-87K664VQSnxzc>0sLgi2*xU*!J~LyD z3uO?N4v~OZZQUbeW`;ZmrS!D;D_YBrAY8v#*GNdfD@le>_%4NZXwgpNNsH}x0yAV zx)EV>yC=*;1+@J(~`EeLR(c{66 zf+InqAST6SkA2nci5o%u*-l}*YoF_oi}_u(F51VTheMyyZ=5g~qb_a;8mc3=L_or1 z=%U<^+)fPPbIBg^Ln1oKHA3afn|c0&X=sKOS(GyLY>P z;1*)>P&P;AX{y_6U)U%l!XZ#(E<&m zX=DUHnm5q!T;?K2BD+PL7}?!B3XzD~yPJ=Ws`d{SCAcmW0!e0J-HzB0g4#O0nn|+Q zWBo04`VBoY7U7FpHd%iFPHT6l_?S0LS9ct?UWJWYR<4ahW9oFrUf5{8dixv5_B>=; zMYd&9YPwh!h|`iJ1cCgL{*E|_NPkNl>P_{|WRf(cMw;xZNDFINKZ@$$xqJJB8*Jyj zm)Ooj7|jmge_Ah85f4U#cC(bBZ5ZL3I8{VJRrNR~xH$rN9n(%}+9iXQg_awl7X}Qc z8pLAoZQ@h!B**ZJgfu1pn2g%NEn*+oK66;Z5-?PZxgrz{_%(!4Ev_H_{x)mk)}PcH zpu^Um4&VLz@G#A~+3|(^!$qsQtsAMg=yKbm+Gjozb_jLEAZ_NH8i0rswkUfP8d0Fe zfVl=}{a#PMPZs+Hxu3dRWkFmtM8^gLLX#J~(Zq;)CxNgKl>J2#GIjzLE7iJ8j6!r_ z8(no!*pXtt-kjU{_T6tCJ^sDh7ZSN&AE7DgO-&UZD_s2S)$!+-V#mgX!A0m6&myiW z(^yVdQ|hJKv`><=96?d^dTf5iPY3j%H=0CVw1y~xXiC~vNPth4CBq1(3ozWjCZtts zA)&jocG<9QG&U~2x91%DCM!7K+q%B@Xy3Z#C2e1PW=9{bv0g-59YkBLLR&ddQ-03O zf7T7F)6Qw_2XAy|Hyd{NC(v{x+g0F0{t|HcMV8Q~n0PkX%X-L8bIt}s$X_{_OSP(D`rADfwcGYW_y=|#jY!sp?D~Xh;S5i|WDMTmwkR#L`D7>`?-GE=jyDL8!cxamb zpzDW=RpD?|Wl2Y-nV+LrAFWw)d3MnHWVZ9|Oj}a9D_m6-E~&JxX4*2}M%earrr+_O zuPV{;tkuZRfq(N;M3!Z^F?pJtf`a^<{FOzyPJ1YenapN_F&{n-<`51tpXFgR8ABG* z6uf&S3DHZjsQSMg9}NcwKJ|dsNofDHvvjR_1a+9KH90AQyniuYwZTmsXL#SeJ;^6o z;v}CwY)iI;BpXNmz}Cqi!1k#m7(@67ABiEO*aL)uX)vY*TBanPK(R?ett6O2fZ&W1 z2x-$2>{1d^;u%Z`WQNi}Xq!oanKmhO#)VN-#xh`L!0(besm?>v%9*FecpX{ z?|FpcVyoY?Eb!mQtC{`leCxdHJf3`=>!41xN*}I#t}2CTbvL8b5GEXMzyE_x0QaH5 zS29}losO@dv}4B#t|D*4S=LS;Mu%IZje#hk1tQ;p^Vz^gcX+n^$AtVTshWlBUx@l0 zjC~uRRfYFd*dM?mGdtXJ+GdwXl5|zsq*mh^+@Sjasx=o!V!)X`xLPi^&uRquyb> zX{1d?BV%#Gv^O#?{jkCxqapf^v+^voKhU(x4g&*9VQ!}cA9~6GD;>iP2MzxG$ z?kJi^(KL$Eu}tTHE2HL&qVbD#(#nbM& z>JjF8T0Lt#H$BY5Pkl6_>e##}i_@lOaY~(znw0NRJ(}IAdj1uIL`O9GWEckT4HxEc0D{lR^Mw9B+aviE$_Zv~}8lt)vbAZV}4L(vU zJi%iqY-fjY9hbhrlKi@SYo6*$u1O}7eaWGucs_YENlzz}#E*5XWRH_&c<0yk_7u&;gw_`DwLpt_3|v~_rcHC^#F;>rwARV7f`PilX6l^&TDgjR|KyW zL3a^M!b-tM1+=>WCKbSkPI%b~T~1J)aLEp@*rCe~Q9JCm!gOo1mA+tt>855A?KQwO z!-EFeOQDfIL}~SLx&);Pqf0dDDkd8BOsohWqf3qwpX{T)T&xb>P(a~*nyIp~mXyoo zwA_u&BRS?;ezl*-bjcg|CTU1r9%)FOOK{PQ8}Z2H1is`xM&!cvKNqNBc85Y)U~G^^ zReR7imQjadXOWtqJ*v_m*!(q4r$a&M7qHnPH7NQ^N&*4;w-eBI_H=sp@Njzfd+$Tr ziT&vduN{Q){(dMwa47vjdOo;%I`3cIyXg7-Yv+$^Z0!{pF@336btu0t=hOikHN>D1nQWLZbAec?&5-KQEpg#UawYK7GNis<#B2z?>?J>c6 z6U;QNGEpCDU^J`(Gl`UnCdQ0riGneQd$A#Ord3#mplYOw2dYcft!ct7UrMC9vi0im zB%#|P6v+?(G>H*_h+)j}^sK$<*~e3G0^UintEuqg->6Pp=R)XVy zT3fu&3}t30Fhi~x@=frZ1P@6YB&tY3iHZ{JVc=%4L(mz7vkW-FuugCrCqP5QDx#MK zqex8xlgtLAl?h-%7DEj>51tArP;Ie6-65W<#cP=&N8|_v^BIdbSd;{ zNVJUgj-^76f4`sZ@PgS}=%rh%FoqV>9x7mxR2R5VZe1G)+@tE~_UfoDH;+-PU4e*4 z^EixdVvx$}BpFYVWIUs+E>_o6Cp1edBpQ|`OEV>*P6|)8^aRWN4{rCb>fW+?-#ZJR-qzmpJ&ng2FEnz;5*HFU7>~!XR12Tg!lo*as=QSvsxDS>HPJ_+cwgjLRw;vq-fFBR~;Gha$m$%7-GI>Zrs8(~k3lz8u6qsXr zDWjm)J+;oCE^&&~E=ZBoBn3KqLei~jq9WCl`dW&lq{?PfeveT4P=2wzSS+LUp@3tq z41hWN zceS-(Uv7BUjP2PkFzq{gHw= zb$u_cVL9S{_WoXevA`o4xsir^(4XF@YJqU#<6@8xJjokbVXm+5i(drB3Ff<_zwe!TNQ@~g9=4X zSBX#cX@s+JZm*BGTG`16iKG|sR%Rqti9Mqu$%T+a1y#^R>Jmj-;!-`>UMzw@C5y}< zk-f!3In!B@jD#(1R}(fg#lg4oOL?h0Gu@z&9a%#F;bnzyYelxWKAiMl!l zfb#Bmv~bNpYBC=%_eonWSlWZZKE{uYDZP`s-5mJ*=wQnvPHdZGia}=56*YpyfM7!q z;!bBAMAIKc5;wx47$p4STR+Mj$(>i(A5Z$8FsFtY9#m-FG``Ia_E=k~=9#yOMmm0pH_67nG zK@lKm{yTy_Xc*x;2{s9tWCI|U}A+RKq*T1u~P)`yv-;K})yGd+j8HchK( z@K?a~k6(Ck?(ioIw~btfKU`e&_~y5tK33hH`ts4Q!g~DImdEDq>DzPhyEEgA8dq)= znP5plM`75QUfrwwPQf23uqX@*%YlZp5PmTP_d>8Dv_6ER0eC$Ci~O*<1R9Fr2W<1e zw=qcAi}5QMig6e>U~L!bLiH$K4{ zR(FXTf6l1zhBQ57Hda_f6{{$$q&Mgt`YGiO(<>Cyve0kj_hsDr5Q@%;ai))Qdr5{t zF>ZQ5SD^@?)``{$(_K{4VY;G7GZXy3fiU|&k&yS6&ZV7s81j3U`O}>l^pFJ-bTSsy zNpEq+$paSZOcr#OAjyQkd*iw1p8V;+ZPC;7QFmXe>D0hjf7vNdGIzCQ-kq}Ro|4?# z_3+JetDlMF+TkC9wi_f^w zi_O9AIYgUIc%ZC^SEMagLIhhWPysU+H9wz~QHYI>vz{;C0#2(n3^kZ!7OEO8hY+C`ZehisQw>%mb}WGPjwSP(6;9g!lPLy|7lN@?k| z#EX)|zDq~*&@yxcokrJ~yD&$z^jk(P*DPE!vOwB0&w|Y>Y$?djrnNG@#QY*Q@7c#) z`!(B;nHxr1|2V4L9xcpqM`2;2<{KIFXe13bdE=BxoeCJpz%+vX~Ll7pr|LcB+~^6q}LUp2QpKVMRUECpn%In_24`Q(}6I#8PD; zD(V_&n^cIX;8cV06_wB(friM;2(FA+{9-&`O)0hblW}X%uLle;{361&&CuN3=*JF5 zd|fP4)YSS`rf#A&K6zo1&S0J#SVJ^k$I57?E*57~gxyzItJIWvCvTsb$@b_$2M8wS z%<~%Zu_&1^vvfXBCm8d3u?c)|YQEs*SNCM@&W9*+cvZ(x$H1&T>(1<3`sjjWXz=^- zEwzzNE02S)yjuMy*<~Kw)OCgNd+vRUo+L}Mo}M-&S({}ORhBKwb_xb71RG3QlbYQF z31JNsi!8ttf-^P7v`oQFLJCRhhLV;rEn$MoK&HfQYO)Q6G*B2a5VuVOO&L%5r!Rxm3Js<8Pgwj&xnac>U7$gMVH%Z`VuF z#QX^ncj;J1)y#)x?3q7p`-D~QqdUJBHAbt970nYDA6h({_D-3PH&Tu_az}^}ANfz_ zEt3eQ6%q)NL!yf0k*LQbkCo|n<^A%9GBcQ0nW;}OJIvImdQ}>f9Pr=@$FmN)LwjGl ztg$;znBs&k*J0O57xTDafeUuH-gjMgvE}Y(-1G}K7~F0*t#gA}wX3Bjv%_REd$H`x z?I7AUd#Rlfd!@b2-fkCUW;a`W8JlEs$5UyO32vJ1ny5+j8I5)y30R3Kh+q0`pS8Yc zdoOj4H01hQvs|Gt<(?Tt^~r8%7#{6l>|9hH?qytq3UI3<7}AodnKuTecp>eDHHD(o(k42WGA-(qilRY$vQSznf#lTOvf>j2 zso3WR$;j0QhjTb(JDb9;%UwhF{%p9avh_Zr$vBPoJFDQHW%dxZmC&?d%k|!|lU`oB zdiAnjZ&@@i_QqQ127C8T_WI}DFFW;i>NPA|_raO9%OB3H{|+qN-%S9ha2yVc3y6uh z-XVluATlxHD$p=a1tjq=k8mM&FA6psjyXJ`RAuB*QA&7Ln^jp;um8wi78P%QU8Rd8&TzLFlMRl6=Taw;E&L(aiO1x)Vvp7m| zmo$suiysNP*F{pTelHv}r>#6|KY$z2Di@W+ zJ6MAZyJgrW@0NSyAsG|9O{OxFi#(+r8MUa0TXvOVP4}RaidJ9P+0l;3_Ay}v?O1^MINk%k1XQc?nwp5$u~iG_IOHzpifKv{g?wEv^+TwM{cuPOGm-Oqh_U zsMr5?Z}-*oC!3qs&1_yXRkYNsnNiU&F_DkxjRxs#x|Ft2v7PqQk13@yQOsHb#t=#3@rCUFI06sv$zZ?DzU%Z{t ze*{}~9VlLuQC}@Iq9-{?l$^~}cSXPuaYtw(3{fBK^g_Z5ZVwndZVxpZwE5as8ry8& zZ-2vn$}T7rEJX^B4VBh{xA>T0j4z|gk_~z8Q|X@)l|mTWh}mWinwgQAEsA1tMMpz= zNhFrGVNqj#*;HyN8Y+g}#XyRK#k8;#CwXM*AIS9&*v@Sj4el67NCUn&bgI@7y&L8e zgDo?XzYCeWkiJL8wM@g5qD5+WVzGr#*kmpiJYE%~Luh>Z`M;id3L5l3^lsh^f4aG2 z+o^|U9n^>Fr@iv(?8(&ej{`@xp4)Zs;4V6k&i>`k?i^jaU0;0oiLKAA$>+(O{0;Fj z@d9;9d+<6qlid)X6)zA*!Z0CoqT@q%L)00F1y%%@(-ZTo@G!rY(1ta(R@NgSJgJw%H8jrUy;5QGtch8i}5uQ09g} z?3f??eupJS!iJdah$XcKZHdOTV9e?-@o)3*_P^;L@=GQDS^hrU{L3%;{iis({9HS# z(PnL@MqiX)m#IMp#3jKV@GxUQP`)W2f8!W}R>VOCt&md*mXKuc#VuY+u!-38(Xu)| z^|duN-s`N43uaJtiq%>~d`v%f@ZBr=Cs-+nLCbPpDE-i!cX=V7pHyKP^{x}yLGJIbp=z`sM<}E;qY{%CWHczZ8bt^wlm=u&;U74=>>zTdS#$N2P_cq3e`mC`_YHn$8L)&y?l2Tff2V-bTrAjdh ziiA=thN`8|8>S>B4+yt*No@qOmC{S3x+GEs<$)?vRZ1FBcmNcq#oPbPt_`SpNn##m z&pET_|IYmX`7ht^&7@&CKl+u?FMn;@Q!gK>FBa>Me6?+CtWDG)N%~po6kCU?koP>Y z03SgnE1^1o!{yVo-&ak_h4J+jE3v;mm~6|jbvZ3qA81cBtrQri7DiEj$$;K3cn(>G zwBR?B7lCu>LuH&AZ@IccS?zC6B-;CvZ3}--w6`bv#aE!iAaGb}hd!>GCz%Fysb(JA z9rJd(bKYvP*VH&vI|gQ|Y513T7E?S;{(!u2Pd74pF_Y0DWy1_E53Vc)?IZAiv+K2( zw9NV))zgT= zg;m*{St{?tY`e^5af4NEUsi?>eqMs>(=)mP9SqXTmGRzeSoss&KtT9QA{Tq>m2V!z z-#fDKFYNyYl+x1Kg*zn7PJ(fKC*Zk0#uinuf+Q%L(}LZ@)OQ<@&uby!Bg8oXYGm zKJ%p=x#oYIKKJp}-u`K1D}6BO1QIe;9x;sE1`~=MHVc~~?{g0##4drgx#G>rcB|D{ zWvWt6{Bv$otGP>8F9}_M&I)D3V-e#kdtTgw8{p@s@Q}Umvv3rC4#6YX7W1MDYzusg zdjd)FG`Wi;@J*}(RE=zj$MQz{g3@hUc*kw@vn@^jlozC)k}jhY>^zduR^EAuTqAc0 zmB=i`If^CfrAbQZ75pBa2d9)TBHW3v1DcW)D9ssqm)@d;?qdY$bK$GSSsVfu4v7>x z*~$QCTM~_#fN|nL$APUIH?s5Bu8oX{s2YHiPcEIzuCcp}QZ_5$oP;IGD=pw`Csdq;lf!dx^#7flXtX4Z%t<(Q>wymG^2o?FIQNCp>u5h3ha0Ou z2Vr>wK7f*cPuRFk^b{6**0$*J<*vo>E)i${{*8vww?1!dY&O=fH;hf25Gj2h^q7}l zMq%*zA5EiR={mOod2_~DNUoV8cP64dDq_p-aAu>?xGbZ%cpD0#DRP@v$u?Jr#i+D` zkqhKpPO#ap5hqrwS#ThK3EI5Py2~oLtRx3zC;n=0+nu5iXbgz21?&@mc__Itf%WXO*H=FCJD9TfdRO!& zI$Bz{=U3>vVJ`Z@pOpIW4pgk5yb5MhhYsMsDZSrg(f=o5K#7jyt$j z#$t^rDzBk45^Ly?aN??uzY|VB&d#uDlBc6$C)4pQ)&fi^AW>46s;>?dVA9O()!E_Z@n+JD^rDb7 z#nGpiFP$wN$G2r0$p0AR{UD2w_J$PZ4qrAbJkMdXXTuVTgq-F_L&iwuKDiv~TsZom zwV6(UHlQ{hGOevOKHf+RjWIAftQ!PagUD5Y)nFosFE3Usw_He2&yV8UOSk1`I^e9} z9*}bc+#w_Y`~tvV0q`#YEQ@?u6DET#fAFv-Orl8F^v88t(3|{`0<2pFP-_LK^&@Sv z97tuI*pqibwNs&o0lHM^-%8v)mY{ z6W6md(w!w;^7zeC2U^8b7-^bDkY*}0s1B<{SFuY~)h=~FJ*YC3E1s;%8=AAKaK+-# zZu4p%5oYNuuE)1c%(AX|WChH2p2W!MM4;=SYuH6}7k0T+SC?zRCAkEcOMtoVgDp1} z$}en^G`1Z)@wkcAiuC%TSF$ zgQ~_cW85ei5;EFD9+CgmJVyEP{7n90UK-8c%9Ff+-JM$mzHdFcbIE!-u7)UE%i9G& zp;RD)g_*)dm`Ixo#|q;G8Y*;EONAY7EJ|Lt(oJ~x!S1nc+FkzU+z?Kc4?*ROEUlr> zE!jc;AM@1~+sIXh&s;p2-0ZQlu_uY^*co54JGRG3W^Bh<$H&>trP*$6Dj^E1Di*DH zK<%z6?9w8nxJZ?_2omi>rF}qIkcxyrayAJ~v^+QxAQoC_vpgXvB&bDD)G86}OQFR4 z=gipaWGjT&t>}ZtGl~Ci{`39UkCE^0B!K}2o?diZ15`U3FFAJSerhMqz% zfW-*91<%i6C(jkgoQue%99C+t0Rh$Rl}JkKl7b6Y1-07v-DmKI-Gz*ThWcPq_|+ zk&P2KBuRAp2!_X}>x@tII^-^g{&g^NiG6*t?B3$I4KE6`i(5?pi`tm9y#tbNyiaq2 zj8z$saO3nUYbe)${$G7>%DH!(MDA(Zf7k|X2ik?m7gbe5iqHmXH4;g=$3{Ws1&ly4 zl{9pC?ggbc#=SNB$?sgAzr42Od=6DXUaP&EodjkrR#()sQj2#GX%_ z8zvb8wO`bVrQ%AlTC5d?BJF9`I%7OI9NNut6ldMUVU__WwLvUrASKtjo%&Y&ZS0xB z0~X%2HeH%tnXXRPriJMy9tA`n1tK~{I;7ACh`%yBF1lpM%p@tAwC{|*Jh?Z? zqRF(g4=OK?$^-c$eup-pI z*DS1y;NO`I7(E)my}qfP^!Nb{*6<4UJDs{Co`{#?mH1BFCdG5{0z8!CEAeW)78m19 z>?c}zeyz!K0{H}t%IgrKDMGX~ct-criLf)ZH+3*2Y}Ie#>=Yp#ev+>|@;NrTijH8QuZUWf(a7d0XCUYidI*SaZOP!>wi<66krzp@*>p z-Xl#g%M+^;+Y<*9{8s(%xP4;0XMi}6AwKp(c0q_1Nr=jsN@fKDWXqVZIWis1xCqf^ zToP!;b{(DCB(DfA1fg~P4okryhz|TEr<5QvG#p1%4UNaGW;_yT6#PuA(IVW(?OIIs z6LTVqa5uO{=&u0%JR!eTpB(3Y1dRgsk3wWilYsRm9-BOECHHxf+{RhB0K-|zFeLTu zESJbGXIYZqWk~UTE5V;t8!7&w%#KiIHJXi^o0Lk6Nhi1~(G)jX6f&mEO^tDkzY+8q z;4l0N%M?udR1jMwUdw%Y=X?-#8I_#AGSneu|fU<*q$;q)@g)-RPB9$T|+~raYTx+ z5n>#yP%Pt&@{SjusZJS z)uG95ufw*XBTa41wEIRN`y8vboLoEIux|^8O?#EttCqd`VfHPjziaQLyunR`*heh; z$gvZgU_!#8P=m~g(G$eDvXDj^?qE<%iuq$pF=!0`z`e0pXJ?)<``#jy98ON^aY|=H zi2+jE6^ax;jx;09_-B@8Or)8aKmd?tbF+on#aVuqAkDTSnb}N{G!qFG0cm2B+4C`y zkMWVC3@WsLyA&10+bh0th{RkU$PvkYs=~XQ_{(CR$J@!N0u}Bc=Q)He~^) zn!u@4I1Iq)T)L26O!H|1oNfhfGI*!Kpm33UMtC2M;UM&?6ow^qJGGPAPaULqIhAT_ zqa83=NLD~_@X2NmRIT}JvUsP#;t{kWMJw(U_lpNbUM?0NdWfPG3WZ9cR^SWA(JUtK zG?)}FqG3Rb;65|Y3TK)FXxAcPLbBZ{HNNXTFgfg z5@zi^hmdN{t5s}Ir5p|dfe8e*AaE-LVMIB6l-=O7fbl0QD-rh!%Hwt>hV8xjVhq6E z!@*e0@6R()SdF5UPGc~di!MaDr6}WoyF#=Ytwn9ohOA-KFQ^|iwwYNxsirq9>;pcH zMqs;>f=nq`4zeg1?CHs~p-N|$z7%2{p}|lgv=FL>Y$0=5Vp=NmL1CF^W`EyuW}+#z z8w_cnn;qSHS*@rrSH6#(bSN<>Dn;2SiBYuCgwzL%1QY6eT!eeL^?ZO7T!&*p1U`kG z!64YPC?tj05U~$6+u{9Mqv^xPc!R$J)_(8$WoQ+2MGq#`hilTjXzxyW+mciPri{MS!I@ z(Et1GWHVsiv$^5ze=#?M#y)~P&OY)+W@D8#FG#4d*a4qiB?kU88OY1{1`cJ$ew_Aw)cD?dK|G=40&{sed-o z=7k;Rr0H4xZSDhLeGGjSZGc}cDwuj@-R~;7SmbhIsJ3pBK<>{%0{s(@cXx|oep$TQ zu`O~O8^CAh^#GnS0yv(5o5)GHbPni+z@-3N4b%d=f&D-|U<)vIf;=*B*l`X%S@?`k z=yvSt)$Nr|r@mmnWZ$*#+j)mwvlr}TJ70w-)_zxMsbeQivz2~_E#$Nto)1+DUJ$L8lx#zjh_xJXg z+kyf%JRBdh|DW$PZb8(Q+ulsIqDYhi(+(3U91+n3M(Rr`6cIl$;;96IVv=IyvaF&i zhO$Aiu*xIKlS)6TGDej#g;DMV?(~28*;ots8NF=6o6)nYr@`ys!NY_HM;t}Xm~9|z zwnxxhc$!8JkEapPG!bEgFenTQ7FJM&sz9!d~G`p(Kn7V}eZ>$7hy>|C>1h z1hat4QbTJ%1;05CVDjMEk9FmiErAUk&iACji zNC$8LJ81(vF=p5;4fQ~&4T_;yk@&)}N2B3zD5=PDs7P|h6b1PGtXL$S18LCgKs}Dw z4Lf>~w``7#-OipMoq&dk&1$(tO+&xL%`bCjN@YH$@|s%KRCf-wTCIA8cjt2W2PCze z&*e1@_2JR2oLc&QskzB~GssbNJj!SER^3N4wCIVo=&jj|l2l?@O;Iws=JonKjNUJFL+PU!zj-R*bdYz9UkA|kg2hg=2 zym%b=tJe)K7|PUIybMFyth~ohikNJTlRt^blEfH*#3zQU)(b=nLs}_G0%DEH*6Fm_ ztR9i)t%&UrQ6zB#g0P4Qa%al_f=p7?JK*x=acXyC18Eq`#>lvd2T}9*5FnaSFdzXQ zsJLP8ywCp>%}5g4*`jfdrof!`g)niDNOXNzJ7ZnW(H8P}TGj@+x4UkAI$_HP%s2l! zz$Ch=Gs$bz2gtVHFm1aT{(-s=1P|lF_mtsC#B2SX1Vpu)Y;FMHc=WiJQQkYFa`5Ad z6GX9nzlutq2pR-gS(OQtV>mO%;L_*bMs`%cLBC|K^zisf$zy1xb;k&(&Nb$uAoN$m zF?VhzgO@uG&YM_nA$yNw&AnFM96K;UXbBpdHf(4x+EaBKB(B$a!>F&v!#f}8?CC6Z zS~~y!5b&RQ3LvU4SFc(k)CrIPS#bI-nnOFiP_cT!Xtqijjzb4Zaty1I`e*BjSDTMD6S?L&%|z`xL_Y`v7f}QbqTi4Msypu{-0rvt8e)@zai)oG z30fRhdr~d|$f7W&2aBkqEkHMVV+qmf!dLE^Q7fwcqE-S}IcpQD`K;=a!kWV6GFQ4) z8XCG(<}Mf3ltDgUZfP-p?wq=I=+@1VG72N8W1(PXG~^l{hK|=MVw_LL>wNK~-m10u zvYP1CT6E3)2i%!I zpB*cc{KejFUh`F%6^1GWqTDfi0s=mPo zzSFxJQ3f*+|aEge!@G6Ci+qONbn6q}WI#LQEnf5upx<#p+cfgj7q5 zlY;`2)8XUHQw%YcfjW~7+8ne!VAA*3Gj(DjP62$Sr4~~C)FEn+vapnjnqg{`qF8E- zBCJ$fv#hdkkR4`6Su(=r*@bL3YhiJ2Ds$(NNNX=mh;(^EA0!5D(m=v0buTFl`R7k4 zwWKid!GRyE!N;?>Nh--KXG-;NWP|@K)+zd3LD>Jbp^Yn-<))6T*!c4mVSYk4Z)8Al zwmU1IO`Z3{U2}5z`8&Sf)lNP3k>!hLw(OZR>*)>qVBxtLFG1OfrL!(QKrOo2|I=09 z-L~QqEqRrXfnc=)vM?&$TJd0H@P#Un2L0QJdLVZI9 zw?=I!mU&Z#K#s~U$a`hWb{sMjQMCJ03u>W&ia027BM7S>rQH%DUwZ#`5*`{t3ZOgr zGD;rmZTCQ3F>YoYqKL8tf5#j6fAABehL+9XQ=%s@rDahpJUkq5n{MC@58UM({ry7Q z#d*{(`s^wB!AGC3yn;NyT6q|LI_?oL_WYWanLa>P&jCPRv~(a3Xa$|%hB2u(2e(az z@5|?9!XkTQStcDWoBMMO>RLxu^tt^~hs6ex*_0a*I%;&Jda@XmEDhSA&E{#1&5RMD z`(n+OrnX=_!USl##$yk42#J74!W~(k;ejO&^k|dlL}J{&Rb=0An5t3)MaR6cWQ=sg zw1kV*^ZKAZs*mYZUhmeo>m<;ju1}wa;S~yNO4yc13TsA8`{vNud3-kX9>|wUCTE{k zz+H#R{!1f%%>3?eu7D3XJfROnr455%BjyRz$Vdu&#l%~6Uc({D*Q!N%u@!kKE`5@y zA`&fHOCp=WqA{ogeX;IIjvw%{n<`h2RxWIG*^fqCn^Vv2TYdK9Y3qLtXGdKh+IYRO zqjD3b*Sl`*IC*HQNIQKSh;MCLT;r%b4QCSh%Cqoi(;=!5z87!U{V@FVjyF!6sQlod z+;Hf(4=K~*p~|lwn!fUx>wQzc3UQWr8vsiYsTTna;M#GJM%it);LXfRFG?>#3peG z&XultgYcqJ63V<#DX_qRU}%BR6|$8;TUg(C=|F55lolqfO(-u7bXr{$GO40!CUrqt zDewpDCZV*`wCd^c>8?cUmgQ~66=&YT&t6-YJC2$REerXah%Q&QUu#3Ze`Dym`u5naS1OnM z`u!`9D6Nm4GB&pX_1ALiSU*rNVdf$OWHW4a7MjgTNDa?}*&L_YoW!jdCqu0vJU`MN z!9y`sC4u$TzHb=FC7#v!F zPo(L{&>s(?maldm> zg%qdsAHnXwv-#O~*1K(*i4}OyyDYON<~sFs7WsM;BMl1=9bEcoL)(#Ki{|5^+=-W) z_U0xH5b51#4b;v!cF#*EbKms8@ym@by!y=G$@K&KdudLbf)N=5ox)7^5@Q8{f)Ei! zG$%^9xm*)B#<470z=l{tn4m4F1c`~0s1(JF8KmIx;6>Ff2u_6?nZA7vN@@U(ss~QE z0EB{G(K-2HC`^n3+)D!vSSJQAn)Qyb;&f|61HcNELQ**HM1OT6#;G`OJBgDfa~}IR zOu<##7(CRCS}+4gZN0ch86bD1QRcpI_+P=G4FDcXEm-h;#20pJG>gm5^V|$gi{a$j z{#7h{x^!>X*2O}{9ZT*kI*utmgxM399^`c-&&xNfhRiWQSuSfBoDB?>!rP%mn$@&sZy8Vazr~E|l%YHo1 zjy_M_O<^G=r(Q`BE0;5^m` zCr7`v33}>CrnjUs8GCJQI&GVThq;!zL_T4=(zD$XEF9i4@Kr5zC6R6f3aQilAfK-E zrPEZcE73$%z}u<#)Hd=j_%g|nxlWJ!TKA7~+vmS0|GjI$cN3vQSC*Q@NE8jAM~W0z z-`X=s_f&;_*!}63t2_hE%`0jwruk;vzqP)=nrQm?$vNl=?-!wp&iTQ@aIAzgv31cO zG!_f-d9QZ14b1N;eD}qLAwJ}ExQlQHeL5~p{|$F=N1=Oul;0PedTRRcW-Bw=;+?i0 z8;<5T02d5~2ylxkyk5oVwVKM5XgCz~>q>{sS@XD=n5(E57c1CsSyu;y?G!C*& zq@i=x)@r45cB(*;%xuA*F=Ch2@)L=N%BG!0Yrc-+4%oF6tN55N=2_HmE+*M#o!Tny z*>mo~1+NHTU%F%b$>O4je$bYwJu$}R+otOP(r?K9^g!-Sz5}eGjA6)UYzY%WflG`R z7|sKHJZ0ENP`%J1bP6K^yWNix{>S}K_=zMde$j7*iXp%;jD-S>1(_6clGRMHT`aEB zH|nweG63g*;yh2U8JW$&H6r3fQ4EWO5v#?`V!z1hi742;s#E6=;=*W6{BwL4{}U4& z^djCbh}c6_;DsW@lOi!xqNm$|K{aUgzap+3-HLWp%@DZ;2ZI%iaTsQ0B1@6xC*DMN~W$-eKK3LQaY7O!yqNKD!PxeMfW{7x(`BlpLLWQ9i}?;TO?82h>CN^pns2wH!4jW|yp*-H6%RnOj1-bDt(%nhRDR_*HM;dUW@7 zv`O2nicyK~_3gQ1=8ikTv1g6&xW1TM#>T++f=n&*mHKWvwlRk5V=Xa!y%LpGqU#a# zz0wV(xHHfbz$=Q@7Gb^9<;2D$X(jj%zCZb}KH`d$Mo68n*@row=nMNu#8>7WR*PAG7z$N0 zOPSRS$@iOtVU90+i$@Hv@R;Fkd^JxDyw+u=fZk2mdPncI7|2xM4SDiOS6W*dGIV92 zmXt>K{3x9cg9GXFoy87rqk)$6TFr;Japf-`E-tZHazoF{zuEb=ui}MGgO@k;vqPqu z$DY1hV@2DB|F~=GrG|yak1a|qSbF$iySnYQo%>sxe%4QpjIBP{*3iE4tY=xc=C_IW z_P=@ft1~@6-qrKgFE;GnwGO7E8{NRC*)xoZS$x)rMu=B6shgSGaO+&wz|w2;60VEG z3fB+&l3|1tpC^Pz+y}(N=op^3X_L;v%}ye?->Iy}b|dYX%EAK`wEH11YvH{XpYF>I z_4T1;edq>C<*wjsxd{}3|Iw0L&d!0^ECz@BKz)8CUWaiBkFI-Ar?Lg*K(|B{OY;K(6M&!_2`T4x##@OIVj{S4w$-4_=0K7gjFI$ z#%Yf^bmczAYICkKWx!jOSdit0cu&NlXiqq6fe*CPNiDIr*|FWOmm*Z6Boffq>KE&2 zeFCDvH8Q$dNH-wsXf~O(5&J3hg_dmUPNBvTXVD&VrP@SG7d&JJkeZi*~aBZ4y{^^+3|Ls@z9o45A8)ts? zrLX^VMkHFjZO!JN^tEm1YU}S=m(8}p4Mry3V&7mdQ)$$$*13ZAinL3B*TE#>lI|ov zn?xg3<5ifcDyqVVU1$s4PamP_Ei~$<&(V0A$?O*6VyrY;?5U`L-4I=>Zu3+Wc`8It zvD+Lq8MxAzp~A!QjBi>chj?SWqKxubeMNkU6bpysfR01POdLHPUl|{Y)26sDjtz01 zij^A`Q)yX%M*%*;ck`!s#>y||Tlp@Y5qLXNtWYGei>g-a;i$Ppp(L;&Ne%ivLld`u zW^krGet*G_{8N792S4&7$}jkXe$~%#{wY7QrHCg@T2fOknH(Mmd9Eh6Nk-ssGMO7r zf+&d$VVN?i6l{ROsXL_nxodjkVB zU>)OPHZy$;Q*1zPaPk!ry)LjZfR_Z&Q=u0^I1@r*2)P{sLAe5X&1PHBr{kSAU9nT4 z&}rAO>vvF0N-SoFR}n6l$IO^A2hG^5KoZRYBZN_5JUjfG+%T~zGS(m9mYo{j6eJ(A z&1O;9S(xJ_n@+MwCQM>sm}|2e%$k|o(Y}8C#b-Jb(M)C#eR!rL|3Th4L*3fAwb+er z#^3*1clE4}mHX2g;mC8cB)#K_wq^CR2~tKtYC9n1qZCA`fzB{mBcld+g^a6XbIfJYg?tR(;Ca@AInV1JtoI}!;^6Df zyUqzGO+rsX3q2D~or!je4nN_bcanoDaPS^*FuKz8ya|h@OJI>fp;AzV^}=a^RRy#} zXoLN6@}E^eoM5&~5xwy`hXPvi1*1=m-bs#t_CSXpl?B89Tg5yQGmL7Mi@ZWallkq!@yZ?imKb|QU2DItN9Pm+~(McTj>17D9$Kv zqjR@T#FpL9^)gM%4;^iui*8=cUqhj*y(f3>>21C8$ClnbJ5Tn$vbJM$8$rGg5@&!t zM@iH)>UA|<6a=k%iQp?LLGUyE^ZoeIP*Vugo6393F<omY zMFGT`D)gN2ynts3s7grq?7VC>>MTk~4hxd9SUx77k}t@NRZhS%CSR9Xt9)0+dO017 zBt&#U922jLbU>^X7mKYTBLdkr+!4kJ4++kHBIu6RPR4PvKt-yBhD3r~tCq}LwHeBO z7Toak2h%{9?5M<5K96zTLl7^2W@Jalvo*8EGds>_&aBJ-d)C5N4mQ@*Htm0T{-ZOe zK(6jP+SstA`vhv~pZgNFeEeth+>bl=?#le|c-PJzlFA+VrML$&U6k6Y#v?(4C2ds# zN?$NgqhUmsHb@hNxZ2f?(sg7 zTp>$iV_$j*ji-(sbIkn1LiWu8V`*g7+C4e+?xzsYNA_ep(gQ@9|6#l8W1Bed@cZ6- zb`odgKJEMP*}lZSOX4`OlbDdu1Yc7r3X}}kM)_(Qwm%@FYf+e>v=Sff2m#S)nHIvj z2@RqS*wn2l%@828MpX#YBu1nGUH_;^wXS2+Eai`GLXbH7z2~I3p|WCMPEK_1^Lw7> z_dM;n4W41x$SLIDZ(Ko5^Ha_+FzZ4FH?}_0%3Nr~EuqyRW|Oc}U~0YIL?B@&NMmBT z5icq+SXSbSGis(PLz>M_lku6l88=DBY%?m723O&us&ka}%68?9GO83Qh9PnF3DZh? zf5PDmcaLKbhY`nfCPzv+&R%9^5b)iEF+f5%gGLd{5!9|)@LwpZ5hI>fT4J_iJ2iD_ zo2G>i>|6Fdd){UvHnxF!H4Bw+u^RGssU!A5#-z&c+XMT30tlJC*`2wa<@2nh4w-cs znptcYHP#Zqp*EHSA6F;~&RCf*9eHxXx+-5vPS0?`I36&mmvSFmdHMAv)$yb6zX`n( zzccqv`?_IhkI*FF>RPqx@u>dsz3Hy4qmL`(r+D2Uw9DBnUUp{Jp@Y4rp;8{|rFrid zcmxKI2;${`&{VlR&4J3_7t7NMbWOpXXc!e;_u;f-Mh%smotkAUw9*c4I%vt2kW z3|7L}+P);U$t zc&~uG%Ph(P289BGH6wv8O=(&pwK$*Ikp}wayb}uOJiF2mu5{Q}tOe5{;i;l%lRR;lE5E{Mx1t7doBCM!em75*A z_U==mv9r7X`tSCGf5x3Xg;P4ct@4>@D0gG-6mxOrbk|SkK4$Hczq@)h_sh8t0kIRH zqfS7~La$vx5m=P#MSuF3fRBrBiA+Zrp9|yR2o6N-2t#2C%0{S2^Ts%p?o5lbxY)fI zGZn*AvFR8Ss|+d@QZZ6_HKk6gGpeUprA9P&or16@>rR-0KnsT3bm{8}GEx-s803!* zCgc|y+0MeF_bgwX`+RIarL@cOWxfiMd21kxYK6vQ)0 z4b`PtDeTw1hHZq4lsd!lmuh9DPLVHNDq5_=I$A8vR>Y8lTra0}3{AmvG#bF8dm2<$ zQ)7_EYblLDs9p?elZzDkGOaBph%*I$kP>2tiAyVp*45y6q0G{uc@@a$OS_>B* zg8-Vkw^;Ly=GP*F%6Zi)F^a7z4bS9Zo7RX%bJyH;Dz8bJ{#{NrJVpk9>FLIOi?QNs zB85vWW^z?~`;X$`tpy-#9ocbs8_S-rJlgZa-0p%P!P;l9P?yQ%Hjww=ge!5e)3!f| z_cvirv%h&`^POgPUju%%7T>7;sG2!ajeVAGF(q4LyJ8IC%!tX9aS9f^Wp%upO`9&y z&p1tGLb}N?`i+yuuMH9aI&~P&8SGJG*tlenPNUb@51{Z|Vt3+Dg7`=Rs8(4dQBpO- zpCY;}cxhA`m)H^_`3=6b$w+C5SdA822^wA5nuH9tuU(H`h1(-e<^sdq2{sL zH?F`NjZb2=o7Uce)%)sJuX-M)Ha`NqdlVT?V5i8kC5f^miL{L>5*B?( zmnCnBU^xtf|Az4ZK96r;vPHzISS2#Ds9@bARU*6-4WLu#Ji38ACRicJ0E{7tNRbB_ zE{FBXc)Ci$z0xu1=h6k~Pm;$g1teP{MG|037plrnx@zw36Olp-TM^}m^;$@@^|(z$EXuE^gJ(8N_`K@gVR!*} z74nA#L-mKnpdu|0lcbW1G0oIPTx? z9Q)1}=kDUzcX7@aC${4lH#s|JCvjeg2_zzf5Yj;i>H;C+rDQ9_u)=^1QeXtAI$pX3 zP`f29l&)hFNUR-ne}rj)l}S~K#+b?k*^9K&wH8Q|co~V=^E;dHQrpU%PbWowKKFcI zet1y>s5gku;<5HA*5U+~NdYH;i^}_5*VRlzxb_Ir` z@s-uWT%k)iCm1(NC@M8cizP~sM9Iesc|0$WpR`IuS)yI^iIhPMiT&b$Xf#uz05)Pb zNlso0Rzz4HeZ@cIG4GT)izJ9V3|1^~>Q{}BZ(KksKH{uHX)CEmXyUDAGWIC~vHc75@ClhdUA|3AFrB{;#>@i9g z$f&0zQzgL-((h;{lbHRLRgc3S*n^hIC@2bDl)R^#W@t{!P@`5Y(;r=Vt9RXNwawZq ze_M^TroG$h;>sCybj|+Mw*wqQudq1U3M*5Ey<h$_7>&oh9yzo8gMw72UJTJKI&XtZU-|@8N;A@SgvXvFplF*_u|1awa z!@0mv28M2E84u#Dhj+Rn9w|?Zym0Q(C-K=3BN=t6ir1M@$LYP_nZG zQw)zb@q2h|6_B~py2mkv34}e(rdB{?k*qKS0M2n%&bnAgV7@X!AO`q^OyQn5i zb9*joX309XuHN5Ve{JLEYqwuayxWxqG^b&~(V>=D!-6A+TI(}>68p}M{1Yu5oOSZY zldtM1DCWeghxUK>#JlVF?dl^Onjy~@~U_qi1B~vETKav*5Rx?x4UmmtoCZ(uHW@FHvfEn>Swj{-#!9p+J5?z zdG%SphiKtl`mmAUI7Tr2`t_FPZ9CpU-TRvke?8K=a58ji-5Y!R-WypzIIxy5Y6V7< zuq!2C`F}odD1%|n0X%7GqqYS01u)H_B`mVAP8ORtI|rRdoRrxqI{i+H-Qq%&)8+&q zUa}dSxzLPxqgi1TqEIc+wEC3+A>;?zefHmj;2 z%M2To1vBi5;w|)h?O|2&7Frvu?N-VPLRP`wgb17*(~}zr*|P2p$pqvKKmkhkn1)^} z5D~Ry`X)?o!L+0i{eqBDbKdx?{|*jp`_Y~M?A(kdZ!z;bhyJwS z)Y^yJ+oi#TD%*4v;}6| z4KuDa+>Y-6R6wi0XWcLr8&9(lOV}C4pXVcMzAGQ|6vrZm$?UclM$8%$1M}dDV$I;PEIC>9VL@hH)Aq ze8e5;iS$PXA|nwqLq+NpuMigqB0HFf5cG~($E_1q>dCkh$+5@fgLq1EEP0I-3pF?P zbn_rKG6sKjr-6_McLblTL3i*Q)6Y~4TV^NnNWZY_=hF}UG!kRCPNL_~`+ZwSwy$43 zgen%Esz2JMRy0-wHn^FWoeeKG)^+waH99^>lhJuB)>;?8^I>P(&Nr8Ir2ZnG4Fu;$ zIxRGM17&6R#J?2@)z+-=riKY3k`F5&^MyjA<9>d>*neZR?#89m2j1T#IAw$r+qv}A_a1~YM z@^VlM40WN)hA3n5>M!bY7N2WQZw-~(nA-BZz8b&GE94}xfQa8nSk zb!~BBvkTENCmIqF!{jqxGL$9HnMd5j$vbgm%1Bydgo2Z3((-QDIMTZX_lQ>~H`y12EyTvrz$DHyrSxUuE=UebPNtrOqu3{o(v5YqAUvu##9~ z!`&PsO^7ZJ4i4gJ=7#cvdGn`pH-~S(VI~tc4_+D9w+Hmy4-AQ;qS48d{ek*w zKOobDuMx!Uf6Graf5uOKqMg*pBn{g%zeb#uLHuU$FF}&lFX_M6DV?F?u_*S&um~@U zRrf}-Q>_?;ZmM1kg+sL=>Y|}ggj3iSTOIB!Qrt?NVkjMor5E%*rcg!U0)Ysx1~_|F zdx#ADMPX$H~IdAfTr*)-a~P zI$!o*_*<6Gm-xa61N8ZPCCd%Er@G6|^ z&Jpondwbj0-c#vOU-94g0Dk#*8ty0-pF#M}>%fNvko#ijIU`|NddhVOTlw_aDF znv)~0nPcXv#AE;Kc)jCE=TmIoGka2NU2|ir=`Zkuz_Mq-hpM@1ltf*|9H$%f&ud^a z&^q3BzVH0VNvolshh(cRRLs;K(>gV(*;MciA(+siLq~>nEb3vM@Os*tKoUlhTdI?& zAk{7%p9D&S05a1j=wqlnz;)f9^I28L#oyG_I6*X)YO|v4-?{eA5(wji_SjG7wa%J4 z`1pkGIrZS+*5-$sy2;+c!0y@usq_zak=(ePFq#8NMumN5(0@)tp>GekJ=ru1;5(C< ztS#n`9gDpm`zZEl%&LZxArecc(uruy8;!;`Tb{QNyG65PEL603sTc`Ih#Uz-#WYsZ zX;;je!e2@yGBsAO8tA3{6b7-tdKY%PbXT2=y2MyIx-WVpO0v-zQNl&NQ6g-N?tu2{ z5mVt5k!dOrM~2BHkKL7J+MitQje8uHM2iP|YV)iwUIg1M>xuD2%CSb*E#-2kCEryT zfz;Dd`0djC1v6h>7==6J9Ne+P;?C^Ya-IPWPL=R-0JQR%INw}$*+v%OV~tRgNMocD zbDUbd^{1noiEvL*zw}Ih?)mc$Z*TNy5%tA=MJs?-Ir1v)?0GDi>pCi>6H#^!KB;mkR zw1sU%v6z;x%RbZc$rSK;J9QagTcRuMYH_u@IEA|0(;R@F9iaEZnF4|?8bD5@(7?}2 z+&u~3a2bA<%+M1NZ}6m@U&iL*uvURbl@$fpZ4f0kb?eq6jYz`l-zp5V65KvLX)S7Tk^jKuj6? z0)Sr}&LXWk8RbJ3Nl`;*0Y^K+cX2da9?%79L1Z1E>9sI8WuzJ^=~r>Px=ihZnTk_u z!9YhF&gbueD(6@r&V3HHtik4F^Xk(46o}_0N1?ZNGgDw#oA7#lfOKVvtyaFKsXX)4 z(=4#H#MJ#80P*0qXU~46b@iGKchfv6H|y1o#s6rZoqwXfEt`3OUSkz_bovV?R@SE) z)Ol_Gc`IJNy>L?DN^4KG*U#$0czelm8U@fKJo`<(4k{5n1$u^a63)igVUbS4VP^*K z3*c`AdIE&6@>LPr6CS+KgO7^%xE*h**i~_?g4*CfDy(l<2}Pur5Qi(`H?$6otXDCo z!qn3ut&_G&yQN|21BrKgR85krct<6QuzEP49;uQm7>*A-nDana_Egd!1Kp2|AFH@d zGqhfc~bPo0d0e%k}LL6JLERw+N|PKZ$g_KO0ZdQKP? zJ`wH++##V)I44ly6jry_=DXRvGQrlnpq!Gg!CaXi`syK8o2jWq_T^a78l)UZ#Z*dH zz7&+Y%qo_BW?V7VHGEBTbxnifYxcoNbHC?YTDbV&iRCRb=kJ>_yC!!!^x8wMdnebt z7<%&h(^GPts~a=5&7Gaiwf|?mYGa!?@A&gPcfPZIc6{;K=bRnKj_thRU}y0;GzrW{ z%S&F?g>_BJcuD9IpbapfbU<7|(}GaZs0wNah-w2B2`E(sBq=1>0DnNNAVQ;+?gP?L zrF|Hh8a3UAuG6ry|MMKL{|KAJOe00tFU0uKZuy1qq5~FKT>-=OS zx^Uq$KNRl$s`bTXty?xOdSPk%eKuMK+g62rW5_x)JseNyrLb7Tv+8Mk?;7QR##ZYd z>p?3g_;Hvo^_0d+x#kLz24h=^rAiN7B4yJ3wR;*ui<@@^&jcai1OpctrH7$cA~jT% zH98Vyald#>JS$q9A_xNO;CYXytWt~7-i?%%Awh$S;aE&?(tZS8CL1{nOSP4%{xJPJ0P4<|CxdNX3cRN zEq>Gv@S0FG^_%$kI%n1U`aE}4xmh^*XW>XowBOM$>T~gmZroKk%{UBQAg5v4%TW@S z8*Kp@JcwEX2U`LUB=#oA;W$1NKN%-tH9lB%qKa5!czf)f82NVqHwLiX=l3=F#(md) z7TXc|v^*|z9OAIU0+N(FFUh*y?sZ*eV-G)@jecn6?q{H|u~4PyaDw1)oQV>+rO-n{ zsikY+g?=iLFr%+Ja5Ti6bJO6QMWTa4nnV@Hj%LAk0-B*2`aE4T93I`J;R>YTM)(YB zSWD7Dr>@3ir(59VDJ|u%m`?tY^`RFm!!;%!iZ~;s*QmZg(qWTta?>2&eYaWlI8~)n z59vu}wZdwJYy!c6!|pU`S!;RTK3S+T2B`Cv#)pCoPPYLLgSfN zl3jQ&JY9pk)s|6UCl~4(<^?CBjr3!i)j_QUX}OHQz(mGjOfW8%i=dj|h{b9Z9n=$x z(0dFGhloY%fkDS?6JTd2Cnx0m>|@TZ`f`Z0u{5bx7PSa>`RUXZ}+Gnt34o1*Vw&j!$MqW|-=7)ty}FimYk z$c`yQB^KUg4O!uNAhSfahQY2|oesN50fH#QS;raY`O(wROyqMD(6z@f!PO=rT;vfP zR54)ZBdj}K(2_UCK#isiyR%p?3OhZz2c{%AY*dG_a54^pe<3q{Ke&D zPd@uED%8`mYtMs2p2dfA}R$B z;mp&h8LxOW{cPRw_GI1a+0m@%O8KH!oeR>tc*}og7HetPE@Xo@2ia!!oD+&DIVmij zX)ZY=la@2`WtkvZmcue<=VaOIfvSQ-ya6^oH!Rw9{tp1Gn|kVVGA(8z6Gx1)SW!Sn zw5&U^WUwzRe=#@)I1n+M#1L8C0F{t`G1 zO262g)FI0tPcd=~;{BL}F$OWlR4AwX6HtmDrWcpPYsv{O^k#7s9&{srm^~AX@=5*z znuY!`hAO}(0VCBwATa`P@h=5`>>u-A^K*v+Cj(@6%?CB)gBonR$ed09#4^PBhbtp) zZN3d|RYR!Im`aqxq(S;JLKubQ(2@{m4S7uiQBF1*heP%Uf;1}nqmAoV0;pl zp-CfTkpWm+7!E(U@d@p`c2(mJ`%n4Fhc+w_dKkrkLU=#eOAI2fD~Mv^Qo zkvOZQ;^6%rP*5268!yW~RO#pfr)JFck(q54Y@bvEh>g?Qj2XHUKryP!_+B-RF4Q zuXpbJ4u4aa_eMnd5+5rh0kKv1b(qJQYiN{w0`nL`LlDituj_!+Qfa$HDy0SqtbIR! zgg?!X^A=7P!y<8sA(6OIsa#rDdbX4=LqS|4_$XxB%-xY#ldcK#scj3u9XFhvfG=Gd z2)c%Zz>g4_Luv_Q7?%nd!zQ~rR2){ZYG$L&S4`_cX9~7>idoJnW;aZm!O-eqPA~dk zmYy6ibDUH!`6O#Z>o3J>SEpg36x}6m=s0*iCW4ZT?5^^DQ~23ibJ#Tb7nA>zUGA|_ zTvr&Md++Sb&c0@LcV>2W*ZcDN0W7W^@2npL>TxJI4p3W^670&dl~Myv1lSS}TLL+% zcmzcXp(ZMA5Ge!%h!z4yjnhQ9tsyZIV2O$*qAL8AkV=-Ls!Bk_rsvG=(kQjOd*{yV zu5`{l=R3b|rg!@vO4sB&lr6I}a(s-_p4`U{)xgnMRq>ShBEN&D^Z7=ec1nHHZ=|!* z2a+S?sq|2%$MDdApb-cUQlel=0{N5#+|3?Hg$j3KdHF=ug25s{5~Qu+`(YZE{XUy9 zWRjGLT*w5bplf>K|1yA})!${;LqTz$wp20nf&#N;8MAj`8nZC8x$Q8-F34uEa>BDT z_e*lu&cRN4!w!9}yw%9Lin@0ebWh@rSPN@J!i!}hR3SV#vI06ZJGk@-RgC*; zMEOToe`NM5Le_Yov2mZ0*|!U%oa@5C;RTwC(Gmcxv%_2!A=C1T+)o^n**VqDi$ZxJcsNbxE>3*_))TC7VjPW_9LdoDsovB%PMi@+c;_ov`dAix6&RoKKwmG3R;b z6(@7r6BiIYPw2Hbkk1E-JA?;h@@|`xohw5I)D1ACtKgq(UA3!6LTGo+Q#+k8=he+9(OK$dHv~6y4yGYd_!mb;>Goy z>o+#9Ska6*=l)7>I!1w&O1L!lvDH|SCd*4nU1Dv5J|86uBBUX-E<{B&q*kiT={3Cb zyv!*X(maXnx0#%YG(>3-&CEr&EwY!maKM3?sfx)n0!a!r0+j_w45CSo09C{Z1QBIe zVCMxQ2<2r8XTQhJdTke2U zHO#Uku;x6h*5^QgL_)qHgeNK~BkXR7e3&BhQ;jKlBt^pM`RUd)^OTWq%g9LGyLF>= z%u%P+Q7@B|#Bc~Y@BYZ97zI*bKAE~Cx=j=FS{McMdE;fYWG0Y1b!7g|QfgAgRiJ+rc0-8_2FKApfY)Y+C8?zVI znoXr`rQM~hw7S>_cR($tC%)SYf18HGZG?s>+$~tw{0<&rYbeu&yRd(z2A-h4+AT9s zkl13+xEe7@tR)%a99@0*nED!f? zH{M*+viZH{xMzp|_1`X$yLM_L^!NLh#22>#8oM^4HqQnR56n0Gk+{^bdqYEY$Aaa` z_O7fUgpQjd2oCBvLzaaWrMGqe{@^L_AvEE2{|=FkZc-QbkRw zR8=Ek@A$;c9}>I2tT1UzCZ@-&`c4c9{^s;M4>kFQ@8(n zJ^~LOy<@Ik%WCPO<=Gv}XGPEXg!YKs(J?qQB>8?2NR!dQ`jwa(y*1%kl75A}-F>n3 zarazTE>Pm&D1g)?eF)U5b4l))l@yU%KM_9_ABwEEga~mxP6JF%BoZ_YX9BbkyX>|| z$nD0MC8yhTyX6GWu0Xa>>;zbYD1H|MEcCujU)olB9|pC{Z`f1U<7;z~q>H#<;*Q@$ z>gh&CiwE0(xL~Ab6#7g+_o3pwqFfXsXa8b@bt?SJoVwEOWNB z43Ra1tFFzR6OC=JW`Zm=H@0c$Lgfqf9i(dRHoiKXFU2=(szLIog&aJ99K=Y=7#9S| z+u+yC&m3Pm9yyrcAa}&i#jiysiNrHsX;fO3P0FD1nj*NBs6t-|^@WB)2SPmKh(ah~ zQQ4hvQ?KBbs$@o$DL0qjIe5XbxoIEa1$&8Z~`M&&>48JUUB*~uTQc|js zSmPDxmPF4>M2gD9W1F}VsBElt`@{f$3bmKbf}b3~A#W(xiu#q8HG7w_A3Rkv*g{#u zCCVD;7#tEJA|kS`sc=%LQR!St6N)DU+LcSu2X7y~@~e@*ymgdhPGuMMz1&!PiY(xt z-*tNA+O?6>ySh8ur#3HJ)xLbo%~hQ?8BWsUa6TIM?qx+$L#7w!QU)&m?)}0`C81U5 z5FQD&`VFP3gh(hCs7Qq>j8ADq)|#|?+Kk4_S^_THv@O~j z+A&QGYc4F*h%AvfCy{5TB*IBO(y(+;;*+pYsk&gErqM8=Re;>twiCDCp`D^vvdsZK z-m>E0_;Zn=^30n4N_mj6L#x*we)bpS%-oCX8k#p$t|af+v0jH*-{(TyxiOAC`P53o zA@2>5PG6so9`F(NA2(@pbUP?m8k(eEQC@QRZSvD0MiE}#g0}sa?P`sU;=023HIF+p zyF0Tp-q+yg8XM!JHul)Y$ccwQC}0vEQcz24;{@8KF(P(arwwX?6;V+7qlu7$N@?p& zrO+Z_fgm^-O1!1U1tF9Dfvu7R6{!+R)vQ4M)AWbeJ$H5ur0uR|_MXw&ch5cNe2{idIs5MYK?|5_(C2L>1h1S^>SBQ%IFEq7Y><$wgKZ$}X7A z0Gq%Y6eqJ6Yyl)4Fn)&AK-dC zUf8&E`6~RYHBH>zNJG~r5QE>=p@zH=!+AE($gkNLyToWM^VnKOce5X| z1B_y3F;ZaoI{TFUgHgs+2Ce}I$s)}`NMlMsN1DnVRpm_8zyT)DBCNm}r2OU$+EI|! z6B=8`kMQGsoWoypjY$U(eyu2#VLH)UD*lm*H>(&V@X*i{TyY?Az^iQF5)MgbgSH2@8cmr{-bfwRJn zdsX6KGboF4=suE6U^D{qo`8xaACr4zfw0YFC)rOY4f3Z1?=^6_IdYi-gR_)ooZ#SHq0s_SR~0a{eH``b<~hGqSO;V(WU`gFktJ80>{D z^LOQdmp`PPkfn>Vkfr5VwHDPiS8Eg|$1(-TjdRW6TuWXkde$?hW?Ts9IC+L!wpgk( zbYJPkPukShwgQrg}5uOz;-L_}Z7zXWr%v+42Isw49Sd~H`<;Zt!I17E|N0z&?y zwkf@5{ewgKu*AbHcn`S?7?%RixOoD^*5_xfxR(Ok=r4iA(Kzm~ajlJY!!;TW=m98X zN@A5li^O~$11Ipc=@N2=${u z@RXv@h6x7tL3Ra&B;A1S;ONM2j1-Y=HB+sXAgFeeLc^$bvC%mcM+ZK5|#VQ_MVQt zCGT_@Dp!G@6{`4iKMaU%m}Z%0ny_*NS3SAB#dA%#9VJ*MSm$z5ZjfnAF>p0^l1_s| zzs}*_>1=RVd-=NZ?d5cb{gS=UrjDC}vo7~7+i`5$SsulaXl0ae8il84ecN>d7u49| z^}9KjRJqOWJ8s5hl8aqeb5b!eG6^U;Qn9XTMNj1VDaW-VcBS29)3pmWw(Yb{Y{g9B zR9IBDB0%J3fDNjmNW3ZD9p4#$J1+e-elJeqfDOF0dvPJ1vq?~f6NE!L*-XXz? z`KckRQ`FNcTA{w)?)fWMgw%(EpoDn^#!Hmv!APN30{$$%L0CL+Ky{1C*Q-mX+d7Kn zQ-ssG{O$fD2gX7poqlgT`eC32u^$}4iGKzI# zKJ!7cBbH$#5@9f2>>eYd>=c^>Mto$fN<7{oEXPnV6~#DkVLbyk>0dH^X-?92*;xzMn0;kH1xTKl{J?uJ+3m6*jGx zIwV3eSW+{-zPKqG1qlTk4@>O9rgQ&q(|Ve=mC~j^zdQWi;juAxBYRBjn#}@W|DdoH zZCm&qsziS}N6e*-#mSF8*5M&nPE>%B_Z8El+!Cb)H{@A7QRW-60PdKT^b#uEj53~( zU0R`r5%#fY22gO~)At_pyitss;qf3I!SCQK&fz;)MK}W=_d)nj91h#Q?L!|62U-Qb z^E__)DQfBsP;;icq}hYOigyYz-;|oUd3#D2(x4w^%$v8TA>+nITLJAZhAz05)EsE~ zGA9VaVtQzR5?73lK6=1AUtM z3`&BV@&Fg0zd(DWYgj`i(zcxqbuz zolO9!9h4?YT@gW7{bM>q)ac?8rYK~Fh!P4}ChkJSCxZkiHbcl0CInkVFbLsk!VqZ= zp5%yR5UC5vzC0*XBxhv!E(BXdFbLsknIXA3c#@MPL*`vb^R+>ZA}ynlC&Y3@1kDiU zv^$#Atn~-am=^8|X^`+-K!Zc`bAA7{$P2=2>g$cS=Ho3wWVW?hk6ifROzFkGn3?|% z;Z+~o#CgW=eed2o-^IQ=f5mp}yR)6d2}y_(?BI|HeCa|dP?m^LXfjN;@-=87d^0Ah zvH?X@W3)@z$|fxt6q1xNGEmx3n8+W2uyq^RXc^VSV1H}_O%YW!X`9;Ed){+MVbU}w z_MKlRit;?a&!bb{G-c#o!q;&JGlQAU{B1}GgK|WMbN9@0yE8c$LGci34lE0-39yP} zNVt&1ZBB3Umv;1V^@D2sRuWZGC3Eo3LTAhgNOlqf(zbEFj!jTsA*}K4D@8|(aNcwb zRzJ_WDyU2a7$&C1%vft|OKe}PH#Qg>kBJH!6N@gfAxML@@H2)8S+0I=Qnd68dMj?e zA>I{nj}_Ed(bBO;vh^V-1Hk#(lBwC& zS1MT+14LVi08s4%Gx5^o#@6w02;ioEgRk#%@q53s;i<(d%4;HvyPrnI)hpX(RC#uX zzcqi=nRH0v5&!L{4pu&!eB=8m&wS1dV6$N-m)0o9xvdr$@_eA&bq^OFQ-30-Lbr_<3!Jj)_t~EL#BNb zKf1ALVYhOB{R{o4*KgUp_GEKM_0u~#n5ntngt;rA)W08cm&44x!@1iR;0jUdwpj}| z8a;hpN89E7@=2NH<=uKcx?L;%O3Ln06Ry$O=~mWbEm27Qr}M z@?EkOM#?eyQVHYq(_w~frp>ei-fd7(Y~bFu8@7kGoQ>4Od-U-!T0_i_ ztkW{qA%YwBOzoQlU&n>VMbCqC<_ zdU5r@*jHOOtnSF1|8|k3nq`0}nIj&8T~H+(iNrYs_&{J~ zNVlv^cmxNCNAw?*7{S9Zf`gS=`c~l_9?l^t1ar^_A)v6v1=%6+!>n$~9E${pM6e=q za=yZrXc4HeCX8+$a}UtSGgMYbc$V+vUg2;H*U4cHkaKO@XvQjTE*~umBO~+)_lL+5 z8ZQs|t(2+21Cl1p3(=X9VwNpNYy$WXnvh^|@3Bk2=tlgfZ*BJIuF^ek{ObS;X8(eA zqV|405lp_5{TcHFZw;iHU$WDXulwQUu#Vm>LLcyd-c{#v{ibudJI7zX` z?Kn(S6F94==%JcZv8uWyzmIa(AEt^Yrll6ClbV7m0b?bJlba*}mHRPp`GB|6@CyD< zwu&m1RwqP%pe&VEN?Ea292CdJdm^y}HlT<=S@EHmqx$+dWr3qlaCY+Q|DkMWzG_XQ zuP$QI)QSxN!YL}x#$!v{-v*juKc8$^Yf-nauRNaIAbzQ*L@P?*El)Yd3 z2hg^$9;Uu2H8=PenN=^ zSQFea=|m=zP~m*mtPJ=S9FJz;oH95cw;|D#a>QF)7o!q4=$VrqfWMa_ zC)kuzC57Z-_S5V~8?PLHyRD-wbLP$WH=?p53uEWz^)@eE{lcEPLumVC=GLxb$hPj+ ze{fv7>}X$g;@s_UK&sV-#bF*0!KHFp~tDTLUKSh&gx$nvQPh}^vyZ0v` zN#`aRhP0FS0d+bPMc**b2K`1^@=gFPh#=9JV;naI4DJV7pN8v$$QI}iU~z#D*;M3C zDGL)r0J0;%LTbH1^K|HbC`!LV2DjQ~5fxQG(ivvL}J;jts|OHN9wGpU#{|fdY7lDm&?r3Q(NXmf zdGap*Ngfib==WB5Fqz6oF&lyY0og7Usf)N1?ua+yOL&VBz=9V9R2C6P`<*kBKl;gU z&-CA4lKlYfy!5*<^xf=xOaFNxyQW}4M4RPCor|+)7o*GBW^}p#dO!MWwg@iRAG*Aw z`(QHr`t|En>6P4{xi#ePOd2JI8vK$Y85+*rzW`To$NOeVQj*6T1{!cxBicn?CHR}- zYa;%-h>kf;#kI87qj4@)(_+FfsynYZVsN=&#>qU&ykd1(QZwPD zFrbCGs0Yofuj3MIieXH_o@DIN?TLb6RR11hSMAu|Q~~# z7J>`ZlRTASag@BUJ7`n?l|H>50X7MYCcF^g)_mS4&Ts8Lvb5Pbq-Os;zW!H@yGi<$ zxjO?xS;Xq@|4?84v2C1X9DkqpUdMLqG?%lTbL@+gvzyqBonF(O8@XDYH>`A3#b^+y zh0@g3fNshkYvM_Tezz8F`;^C*JbO_DltSELUc?(e{Bt@Lz^Zb zpdo>*=6K)t&Pmp#$pi@~iTpmNT|C%+Uu_Sm_Z@#DU){G!)< z$VQzV_=j*i*~UAyZ44x&FhWp?Y)tBuX|E%;Ca!j z_b&8nvFq+($G25k{)!~QZ_=5M6@ z1%h?(jZ$x3?h)O)ov2>i)3z}LZA5B{$ZEUi*p6qcpO4KQ{oW_xQ{Ox__8PPoUO8YR z$n2i$ox6Ep^Gpd||LYUwz{QtUC{4c(*I(Qd96#Fp=1=<})?WWo3ii%Tl9Tbd_rLYz z+|h3o*e(vEZ{soPDe-3eAk7h29rk-WqYCC^b0_TUsWr94s!c~e&i5Dzlm z9KFL%d-eg=+T^!buCpPDWwIyV)5bn{?9T7;CjP;1&ptnU=MQW_wvBe%?~qS>`|vi{ zj1U?`R}pU?YV&W)u*2UbyT7j&e*71lwuH&ux z#ugYp*kA9*L^9d^bM#{-k2D(VG)?OBnaBjo1ZrAl)vTGsoR(A?z+Jkb59uYH=+iif zh9=lN!AF*CHlL4+SaXnO;D;tXFkuM4#1hV$DRC zmsRahzO{(5Q8F+!MvTM8xIq%e3Y7cmeN3?73N{*o4I$V7%K&OvM%Abp#8^GbGlKF- z+QlAi3>lb<{*ECnDf`~A*Fd`iyS%jeYv{6lbv~!B(k!E0EEO>=)`~b$G`M6V1E({9 zGIFLnGoGnrJXvl%I|ju2#*Vc_ikEqC`7#-LCtU|N7g zVZnb$4w;Q4fK_sC3g>3sWX=l>=LO-s09FBL!75Y>wE`)uk#lGFovMA8vKQH*0xV(v zTwlK=00lhk%Ht+KabwVp0XKTw zA|P%Ix-rlwikK)0HeoYIdZQ?G;Y0^Z2dZ1_=&Z3*j~4|XpHmdRMp5{{w?a`&aNx|_ z#k+Vr-kdD_9rbf>Fsp+oU&Sfosb&X%iyjjA*NbJgpIP1n?zy8*w!cc*8xYbOJ8A{0 zfm%RXC6}sjsn%8IQfs)>gi8%94X9>mRjsBG?LT!ny8O;MmGs*w=ke#14pS3b8em&` zjfOR`rR&afKI_&hI&QxsT^FuXADB;_39rohY9-D3>OZKOj-tRY%tio3+S%2??s_*9 zn0EU|y3s$pe9&v)5Bo?o-tc=c)dH zY>tZuPTOx^NOy3V5i#zw8z=%+r>5MeGM?h8fk2Bno~$IX#g)EwA-Mw4)fc`j z(QD|&qIZyAJttwFo}B|pt`f!NcqLwqlf&`x_-tH4@d*2K#4WwB8#On^-57C8FziOn zjqyfF_KA|@Z(9-`Xq4oDFgO6#0MG$zpgK?+AOlWGMxBz3HcB!I(T~)Ima52xUnl$j zH03DZyEQPM{XzuGei|Q0Entw=BZL+A-KnG-FG#qQgDW{vOsU+5ci&@S}MPR;&(%F)2HKxmP9Vdmr<9?w;B*vg4y z=*lfhhFXKlY@Dn!B4sBd#H<_l=G+r{5S_3m?J?fZ>=Wn|sOSNE62{O!pCd9?+SOz7 zNQ<&&cFD5eKP+_zw*+ZWLcvzjJdD{O+|17Fw#pZ6Q|3z>O?<(W`O-$2J(({X_*ZSS z%@+Put?Z(eM%bCn7b0fnRz5s0%*^LvUBoD#chB>c3HhG3 zzt0H0`ywLtEZwdsO-=WJq6i**Q5+s@Q8Th>V0Rc2Nrv6lz(73k6XN3ZXEm1S>6- zP=%jtPO*gC*s^HaqbXiRl>@dJ<4c^zK4-@G66bJZd?8}+^EU=RjRWkEWE#_*v}~0P z8K0KV%2;-gP3_JLa@!Y?YZK%snIY0$>;$~BVD~|C6J>|p1kb4QN8!hEit}rw9YmwM z9%6dwPBy4s(ynMyx3)!_(InoB`ZSFvn;nAHA*aog)8@%(f?Q{VTqh^j`9CJdz=>>J z=;68f9)1GdbgGffUn29+O{ZUVyJ^=w->?2nef7sSaozFveRt>cIX1p?&c6~TIs5FK z6JNO4XU7~6azFz~G)g)MKU!SaMnel7CHxw+g{A_UQL&Y2f}u%Jgr>4}sz8Hn5t}-X zA&Oe4=vu+5iK^Q_rJ@-V;t$4Vv-d6uLz6Z%O`0@6y&w19o$c@E`}us{J4J~`XFK@W zF$Tq&PF1PUCQenU&?ZhJQ)tsTA7Wnkwv9K^>Q7 zj7T%)NHexDwlelojO`-b>#-BDUy)S0PQ)OFK^~W;OutONFHL!sjQ7i6%OL-!e)TYf z+=m^6CjBar2!;LyC^c zlzRl%qbl?hH1Q;w8|42IQ2joj`h7rk2hg@jK-(ywZU0L^hb9pnKYfuc04+kt*bw&~ zvQZDrwCBo?!11|orv>(?ut|l*>S`5ts8A=vUu0MpfHx%A!oqO|USZ&_1V5Kxt|W)+ zxu#$@xVoX+Uo(4@VeC47dfWnJi59jx3;BG`@K1%QQ=787F-i^$3+%2L(Al{w1#?nR zNWs-KY)ylihEy8Zw4BCEn4dA2Wq?Vim?pu`H}MO3hVP3vN$GBVF4GORVay22-Szcx zq2?F(Ci0_heB*RBSC~Fy6yH2$S^2^ld<(@%?dmd3V=O0GR+l-J3s^?LG9}9>Un4VR zQo%6A^QD{=wo3OuIm0x~^J6*klu;7T=Zs6@#Zt)zXX;_qo zHPSbv5s4}0t(&rC?dXIjI!# zfp1uYjT(GSgT)$XsaU9}8~N-RlFuBzWy`5VG8uBcCct`Or+{hk+rK1>A$$Y*oy?8} zEXyDUY)YnKUh1k`D_<)ItbmhAFiNH&mUG6%%KJ2>B-JG;V9|_9X4Hs`mBt zQg-hCZeCq`tm}!VM&76_gC9zDLEjF0!|ct?O00k8yRiO+nf|^^>+zjC`<{8}w}GRD zBmuS-A*P?5g`#Ms-RX+JW)b%K-~|De3(p96n$RO)4Ub^#!XPCBu9~Dm9%56-1uixg zka$vD{#b~2c_^q71ywS~2!fSsr7`i7u}QL*C_XM;QYAvvLf)abMhHz|V*1xCd*Sr9 zvB^AN#lA?`? zq|olt{E4On-mgJIOK9mxqX(xOIXCJWn+T><63dmcI7Y;Ni44l(m5&H@N+MY`X!_xS z=;CpS3Aol72Az_l5@$dE-pke7l@Ipp!Obvp$hrh__3lX5(dzG^ zbJ#l2d8GH-)wf`6^&ot`r0pp*z>lsDeFdJ|&Aju|6@woPJ_bX_GIF(BYO6+1<|9AZ zeU^`W)p6yPd!KQK2sROvLaXfQ+mm~f_!R}VC}4S@M}X-96kO235@S{(VFduR`dUTw z`@*8!?t}XJL{MT9jc$QLKont=Y1HGvi&skJOO^5iDOIUy5t~w&=0btSPNFB(M7~CF&-5vp9I0Gw@aPQ7(pAQcR^n$y0+xFGexCRi{PJV#% z)iN3l@XOj^k72sbs8aqke%WymNpF$9S?%g7Y*9Ie@QAZL~m+6bTm zwGGlSBA)hPbyu!F-d5dw9(QtQ?#^S=`<~jq?XSNhm@w$ry#wrZ7e}-lMs?^#yOxcF zW!}xWAs|ihc?37{zfmS_XBfB4Fm6HcinTGOE)-R`Dd9#b5()U^M&2!Wcw84~WHAFQ zQ2;SSu~MGsC=n`z29@&VbK;frWM3N*Gb20BiRYY;IO25K_IR9Ei>eeanmn;KhR_{I zk>Y$@Vz2-0*TuudwahB*u%-=P|2y4P0^G!Th5z^Ou1;%rbsxLBtP79<;~N?W*?@y_ z5xBuzsVE`bE?_5MLK3cGa3IIvabrkH3gswQIO~=`Cmq!Vnl_lymZTGEIxQV~#!P0K zhISgQ`*tmkW*Uul*OKPqkPuf%w1?`IH8PxOR=!? zwFeG5X;7B10n9T*qNIovqpnPPY&a~9!JHT@3Bjx&to3*J>0I}6Hy!7KXT=vq+F^n= z6Fi}B*3+5nVwQ@$2 z24@UqN6%<>L67LW+-v}psk_R?|2%ymqwJX9_=B!r6h^l{zxCr8^=G^K5}}SCS?Zp& z6^;4EjA=$N)&9yfgF3~Ka@=vltsM0#i{ZLEz7y!DuOD(lmoi2!>^#s}e*+@??56f_ z9?PinSUUJ;<}TJmA`4RE*NL!Hgte9q3pECP@+;H*7ZS**}m*mtY{xnAz&c(h}EHawaTI3 ztoh(zTu)C+OKEL){lvnG;8d4s#fqL5_OHMEESdYmPtptRuk-21aw@gMJIVx=yPr}T zbrN?S7l+|wWvZ?z0d)yzivt&*6mN<%+hWjG2wWjd5#|ciV_s^ec85#v4-wgwjK&3Y zMS)PjX}2=|VFA6-DEk703PcNCyRri%7(L>v2Cvzd2TeBQTFMb*>@KmgB3$CGEJcH^ zW(3xFB&633ebPx2>krhHbstxb^`3v{U6{51z2=a~H8ohFyzuQ^%0FLO|4QfI&M6D+ zEwfI}EWdUcro!Xz->Rzm_ub}5nuibBNZH#5l~4b*_W))*S!rZ1qWh3>vY$*Dlxbz#|V)eo2TMzidbA4*hxt3|>* zb2wF3OYW!nAW8KhY9myBKgl6aqH_*?tY9xrtUvfjazW2;H$C&=vJID7_YWoc#`yH^ z?)tIg)4Mtwsxi%{zjE^A_V4ZeBh2Zj`R=R#IizOE7!R%P-0}5;`&Vt>vRth!zPNMP zbwM(WEK5}{4?~-Oo1ZTBL5B<4To3>TLL}fI0f~u{P~1BLjh0p9qt-wGJC!$^Es=nY zS`Z7BnKh?1I$Mf0%-z@Kfe+BIbf|=Kk3qr_M%yGXu?QM3&6{Yh)G2bR=VZ#lL-vF_ z_epO}GF>*ZD3CtYd-EopeSG%TN!7|z>BOulHOggW0j#>)kbp6Z$2EujCVg%Ved!48 z@FkvJxK24XHXfP&4Bc}_kyckDHwc*UWvr=#Jdz3$5Otg(##@LP%m#Ck=QtBEvX$8N zg3hFRMvXG9_eM)irLXh~)(rGm4l9aCKJrp0mWy6~w6^xW6DNAw+V(%*^#scvPAIqA z6$x(R5Pj!7BCSKD>kw%xI-qZ*njH25v(srdhfJJ9hk9->aW0Oc;PGxZ&xZu+08yY; zBD4rpprMT%aJ*m=3yhXx8`78y*1BMk3!H8jO1s_8noU&IM$H*%YhPCLM_KWj8hx%m zlUDYb`@$4j}ew&8Jg%0HBgy~Vb3kbDf|<-IW<O>0mM1hIp^$l()jn)Z3bhw&LAenzM9YC@aH%1S2k5MB`tFXqnKTeXqQ zp|X_YOGVAa*0}h)?{C@C`vQD*W6$Qz%A2{8QNhp%TAw>~y5=p{QSr<2@*>*M4s(>l z>eaquwvbWsBW`0Nz_gojo+%^%|rBBTk*=@we=)Yh%2Y96nQ0#yO(W<3YgPt zHr+Y9{*46FQxi9ACWC`yI$|}z zK1wS{9hw0*xk37K2I5T#K%{_^)WBW|Hc226WZ`m1maAv-_|ggslRxt;o*AB!V5b*~ zy&!slsBhU&fakri$qU~6d9@X^|FH#6R&p1pi%dg8g~1%EM-$GvAC){pg1q1g={c5$ zB%ep3#hk~ZgMdtR0k=W0%6vgyAqIxXGf$j-*?zPiqN?P`g-+aFod2Wc<$2y@n{qsK zDyuRN$$9g^gG>)+QEcrBdH=qkSI|9ZHdL1cN+bO{PNbhamWpff#nkv>l8<-*LriKR zCS{#2={9{qh?&pFs50Ug#Q0yrt2MZZ>k8kycOTl7*4mY1J=TgPA!N&zY}wMT9lH=M zChw0jNFhV9-82Q4hr&2GVPJrXOOrAIGIUBIown1CXF7cZhZ3imRE17} zrk&EH{o`h^+VZ2BPK%bFE7`RnNo#r5)?J-@&v%aY`@X~6v<9Z97iO5-y_@+wIcEK1 z)Ou-QhRi5FO*0g&fihca=%~4Nn+w}q_q!Os;?q3UURCqBysBGvDn7UDReVZV^?Fp* z>+@;6AUNcJ<^hWE$Zk2Tc|4j2X+gIeZhPE}rpT&I5Q98Br^=HVN(?v!4)}Vy%mGS; z0kE3M_)|ddvjc?_e#(zOHxIGR(Cg_ugfrz|FW0?d)iXUS7PZBiA6#nf^_I?jiz*Z_uLXgRFm@6!&09aEF)Dyk_}5(1Un*m5Rw!HxkZuXdAKdATuT*jl_WBRtvHb@ zliAtXP^rLG%ZUFw9RjffVE-J}u}e-^q5X|SX-6YQq|#J)^0<|MxB6%=9o7ZhZY`_y z(@Nq->s@9$bn)US^HjNwhelDwXOLUaMT)HdV`0Vafd$hJl42tEh$04Dl=bJJNq{Xu zv57o|CRL!#BAZ+QEjNd4?31u9K<2I>Be!l?GqiCVtczH;epPAS1-#699iOpsxHyU@ z%025Dg`C#hnP$hhcTf|$W*%Fgcp~xD#B_pPcOTwn8?haF?A8kT|FyA1jQ{AZUQ1_{)R8AnO$~c`Oc5`B=HWFccwNBDd zYr@3lmz}z34~1%6b!t-`LJBew5m2h84%u7mrkyy6Jyyq?yeT?#eolg}g3^G)hRb!z zRj!T%@@KW)iX0U?;4XCm^be?0`GFpyJdQw$=onjP=xyzA0S_K_3wqt0_x5^$-xj#= zc6Mx!wdr@?ID2I0#bcwd;R_G_q<87+!NI<@TgOLpM?W{XHFse2@l6^&X|3F``!{>u zhzu2eJotpw)VTUgqWyv8+k5wi&vkY`_e@XMrVR(6x+_74c7e_((Yxjz)-Oo9L$TTQ zgN@&8WFB?l!>*TI%u{$2Gu;?ZVQkZaKM3Jah`FF%R+*HFk&0D!uu2Fgv62iY2a}UY z)|mvUPR4^KW4GA^yWVTVHmRn@i`2K2-d~?5T!kt9%I-b3@tUCAd=gFLuxp4-G?+6N$M3 z&({}MscY0!7@BSCo4_McNKU&+PuY+gmFy`b;^8;)2mL(mVp}sEA!^xx4W14zw7y8Y7|^MWao$MqQDtp z)M5r8yBJy&P-3;tM2Oddey{y5%_>$>`+u1kbBRUM^TKOI89CdwCHqLAu#rn~-ku z!}p=quJ5CwdSVB$bkRg#EOAQYKQVJHpmGDE*NKA}Qw zW!nZL?2%A7(&edov_G9q^{#O*Yx>kKJlwZ|`q?kD`_Li&KA2%mGr(a`CetSAJZ6B0 zSdPJjz#Rm$CXeoqxd@GU_+uk}TTgJmwhK+eDKrA+jt9#37otNxQkjfgKKx$@45qO=^XX zOe&`pv_ER}JgSHV?GNSuHJEVesT_%tjIW*JjP`ni!zU}JT34;<^XGA3MJ1WDbZvM7 zu}He}rm!8jq8=qs2DRZX^NpQp>}$XcK3vb>RGX1*F

      %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 z299bkUuyCSkt&y6pO1G1A@&eod__0#2u^#5ZlPjSZsAK4`4kWqNz?lrjZ{<%%GJRa zDQukr=;Rvo

      ^CJE9mFB0a-Fbn4;Bxwv*As7xDygo?RFOfXCDXJVs>x90tPYh^NB zE07bJI(d2N5BY{Hh_@n{0=c-o<;3btBwvavHyy4_D&foV`*5ra+Q80X9$h;Khq+gBbOkuB@s#;?d9#+|7fz7)s z3)knH4V&RKE)I<)v%1648-mA^-eZ^U7md}GvQ>4k#GA{VDi<&CQa~etZOYzsw<%L_%(|`K?VBB@!Vh;1?p@>c=MOl0 zP4&gBa{!CUVs4Www|EB+XgZG6ifUHq>1rgB;l`dqkMm1^ha1?^tXI|-_u7V z+pnLjS;$Jc6ySJ~XxPZGd-|ee2*18R+m~PrNKC!=*SFIu$#(k+(vO%ORv54bt$n0Z z8LwB^cPZkWY$ooIpPTE<@Nnt%_9#{f8JPi+U1vm8KgZYHxC-{fpUg~3MNU5X3iG_v zZw(}!BwL=!+1a?)lRTDQAkzBM?0GXlF|O^~Tqgx2#qRG*`cq8tE089}ztS`IoumGd zq<_zy8T1T4z=>atG%@~_4zcgl^ydQp4Mj}( z|8{*Uk1jCdMBK(jSqg@5hmU1pWmD{^5P=pC(P;-OK-{+Vu2{|CJ;) zAC6Iv;GSN-*T00jQ_+Bk1~yJVR){Bq|dn4vfuSDo`BsTdbZ;*OKE zz3JrwbcNINQ!y_Z#XHbEz%q%C=Vn)ApQUmtqOhM|53X~>I(%PtHTLJjlsB{JEbmI{ z2&HCxO*-5~Ra2aelP^5A6KX9o=*@0-*`Dw<@ zkZr7)-*9xbi#){pFENz!Amg=zt;IR|9`ZF0!u1;hX@8E$C6LUo$R4T7@F!cV&xy_m z1V5Ydd*-xmm8y%Ip}Xo*h)e(v8jRAGlbd13Ma(ugu=WCW03s2u8IdB%74rd}*J{Ek zpp#kuJW)%4$fV7g^C@^-wj-4XfJ<#re~_Ar_K4HfTH|Rz+fWZ!ZIV4;SRSpWJd&qc zB_297kr|GfY(7^dukf>VOa#icC=h>hnT>=JO9&)6lxw$lWKp`~O(Xd*le%m`zC(;H z?ewRNT|AQW#3gKwi3PfdK7-rc;3d+`Qll8hL^%fOcl=t3n91j%S#CEBE&!RWC=`_X z14V1_d1{dW_!V!wDnH)glHd*Wx}>V)Y&e5EIN=;N}88&)Ckb;e$CWlURY-*mcj>%CQ^W>h}hRtKL-xqW+L?FZoLHgR>AAMgXFp&-B6s zW16seRYU>monfMli5Ygg0eO~V{oACD3Qui;QjO;IHUg5wG$3&`z4D->C6SCXYMgaM zK54osu+^KHcg%+y=er}1CPMfo^2s()dm6R6_(p+!;G7RXSqLp1a%^(RubXZLr*e}O zNjex)V4u#AEFj$ENP!n~Et-@OnQ=^|0g76F0V%oVtVWE4o5qrhEFgrx+mQSkWuqqc zrK@SOk&0-Yd1q{8KPm&g=mR%q+D>4l=@r=t2ezx|3dAi@{eftjLhsP(A}Wa2w4*=;i*dmV1m-&R zhtLJMg?DSZ2W$Ct(Psm7BXuX6V)8gF2swwkTY?87BI68dg z_>}Fpo@F%=sI2BS2q1z?tqPixeW#=`%`tcVK)PXAqTPzQuv7U}A;fkOO05CR5#bE< z@p>p|Df%-zcZ+0Ox%6Pk1i#>?jPJ!RDPZ^XLPr?hAB5Hpjug2(o~TtWSj0Qg5tkVf zhs(`Ta%CrDWS4v;#-B* zWND!DP5>-dZEA=x8Cf6>LIKXRD1oHKWcPzNXL-9xASE)2Zq&jsW6#1by*ZU*E=?eX zF=3Bt&o*}kyreZ&BNS@U=M9|$&5&?>mp%T}lTCsG$=-YXu+FLd!}JUMlz|0{d=Alx z8I!JbVQu8fNrDIxUzWR!$d40Qmh!d6Ky%YZD7!o#Mr<@(S2!lDSBX^EXy-*W<&IZ! z06!{Ter)SW6GbZn;`%5z>=J}i6y1WtGX{WDI3yp-a_`KE>2VE)V-*-A(|7^1ICoQ) z+kh1>R~Lg+G}%Q#mF1$i_{rMUO?KIQQ+n@M)~VCC0xi3H%4KS|^T36Iy~5hSt13QU zGZ}{5UA>Zd3{tHAVa^JTg8ZFE){3i!xNGK}JsD(hVGzEer1`coS$1kx(n<)t$z5Rk$Y?#D6D>fqY98`|w+$ zSW$t>zY@i$5dWPhMlCI+n%kRaYC!|M7d=-3VSw_rC&5*>m!BdjWq94)(=LHewaUy* z_)>{77sr4tuGV_xGn*JsTT5kMQzg>v|0IfmlS}??iDmkeuBPu7?*D8~|AC2rJDAAy zCtXe7OWQvJ|9Y&6>4&+rKZ1$hk0bvG{0j>F!z=Ya4HKDuI6D8_q)1Q8@?W+!Wy?iD zIFH-%x&Augf>ziLTHFbRWNhIOFw*f1QcP7kHNvV*Qox5(4p(bOXJrv_a&K{)@_UD! z{Q828c(}C%bou75;OM`@47VsG&}g(tvkF%xNswBZ0q=`^{N{ zPAq5loYsJtR(Q(n!#ZeDeLQ-*z($QIe2YcBvl7-G2!sU~V&~nkqLJmC?}4T1NB5#P z!!e-b)5*J#mY{qDPG(1|o72hLBwsK4%x=X8!tj9_SoTA0BbzD6wgjothTImE!JwIg zdZi}GRGq}GmGJBF&D^~{tI#78VM5$R#g6pTrAd4@ua-el;T)Ej1(sRtQMoK~^|* zao>ovX4Osloc?WR8lb>ET?UNkv-&j-#~>Z&I(r zMt<&6;F#=0s_-u00nSvXv%vC&@x!*uQ1p$!YQr5<3k&osocnHi)xoW5I^Sv%QSgBN z5;Rz~HFmxOR8iD8RtUs39-7q4@{0E~*T*-d(W@%%kE+nIehw*l=ij&jyDJP350u>j z=T}eTEnP=u5;;1OU>cQ@l1sK0^0tHOc9!?`@IE%=qC|Tpw(4Ex$mQovbkOLY=BVn} zBI*+G3q@6z8*u@b8~596mqIi|VFOCGP-77MvRCZ1kMC#RGwxDWGw?Z>RtbgL*lW4; zV`?fyet@+}WccES4sD~tba`mxa!SQu+aZ@^qoTA!A3NWD5@oM zD)kcLLy>hHVhG5It4ah+whhI1GXFK+!nKz!a65}&tSoAzL$j33rNLR;V;4zv(z_|p zo=`g-bYs0m2a0?Xo9FCR8rQ?sqC-+!IbY{0W5XuV@1aCw-`5#)%mlqXnR+LeL93_+ z0n1|K=p*ec;h|CDRc_Pxk6UV{DSzS-&_508#5t+s-6#>ZV7>+a=5BUsP6?m zwss08d7%-9Q3FZO?g8&3gkpfSR3UUeA#ioacC>AQ(n})?>mIRQj`~AbtKFaRE~nVZ z4xgD)Io7(Wd8F;=sHc}Zav~e!yoX)NFN?2KA8=FA5tI`Li!3}qilLW?h{{&0H17r0 z+s~`|G!JPUCip?FX2_P5Y#&gc5Nq!Qj4T8snU0Jzh>F@ys_sb2Paor;II42=+y8_0 zAxcUbR{$W-)*NMbye)hib(>RV)z~gDwZef;uAx07qTd>Bm~XRLnV8pht{Mt-W5#*D zy@JN}d_%OK;YmnEA+RBleK@>xqR7e7J-O(p8-;|E_LC1|)|evSb~0kN(x6$MiH_Q2=bgv+0irpTkxlpcXUczHllPwqEYb!Ll|KnzS1d@?axPfOkikM z7SW>JMcfVX6L(j_!0Tfj_r<1D99SHgqAF5P>-Q7#^&{UtsCb+>iBpImjS4%Icu_jp zR3lR?V%);K^{e%IWM0pgWiXM=Nd7D!w6dcoQJf4*H4&UoTq~07QsrRu5l~#zh_9Bc zmNpW7t^hqjm@~r80wC`VN22masGB@V=nsS(v{)%hev?eJ!-~;`N29~ja$4JfIr%w( zRlogr>H>L#_Ef(45G?trG<%O@fSsfud=C5L+^%;4Yd~FS z0iaUh7>@s@lu=@guhN*#Qfcdb@ElfiqyoU8ZUZFRVH!J!OqQ&r;iKX_`c%&|Zz({Y zXmMR+UJy%mxL}xgng!EIO&!#`?UnNnP!o*G_<8<)CY;8tx&r8osrkNIVL^P)v^bf? zK=WBG_jL5s@-{Y$pMl^G2Ht6z*g%th@XtY%XTmblstUmq(+r(c;x~9pB>dLKK0LI@ z7#~r1^VtM%L9cMu<*4!2VfQ)nWA*vheaJL9e=zN?cia8yyu$oY^_Nar$xzNsTwpTF z*4c$uY(uvApVgKSx!skE1JDKRHjP3-=zXcX*yejvymHFGW;uoIkz~*u61c$ZYgx0$ ze24J74)D6qGvQ4P8|f-0Qa9pzff_3MsWe*p_nu&Usp4QC7wh8{UF}?&3Qip!k1bx| z-ES{En)yA=PfzPlEgbh4N@-O*n%b5<+nuiWM_<|>sZ^e7T3c4QGkW{npFNyyo12$b zSB}T$=MP#0=LNv3T1yMSybyYpK`RjQGwgwF&M}VAc`grcE^n|Nw$WWGn~T~2_}=g^ z6^DW}iLizGa)xhhPrrP7@0YW+`GT(GWwiAQ|03VOx`xmlXym`=`7MsRlVOeF_nXI` z!kk}$&wX1;|JRL`(*BDK{qkd_-(&9o-6i}d-1!yw9P?l4-~7J(;OBVfZ#!1X`~%YY zPYM72X=2QOrCam+>VuyP_+Na^SobeT6YCBBKhwl=|KG&_Z6(q3|KW20 z7wr3m`=`7A^}2iJKj{VgUfTW<_!kuT2QSzk@wxBEk$(jK1qJ>Awf$*6$Na<5`R9C& zj+O1d(!>@mFj(N+XTOh?24k)Oc6(9Io4fF;eBkj$5m;vpUdNBb5&|D@KRv4x6K$^A za8j(TT-dhv?`AMG;1*}qzI$D24+XNh_SjfV;x}3;CvNu?nn4r{gFu|>x5d=+peK2G zeQ}|GenBRf#j$2G6lKt9gwgZ}sc&tq6!L;EJggrKXeGCXI5@18`2;!TBuF!oIZhJO zTY%^v)9$BMfkK2~7{rf!WMqTvC_;^DBHnr4fwDE{6Z?insj`x)l(Vj6LW;%_wAUvS zYz&=brA^9RkVyDmHFd(NQ48C>Z#l?t*x+#=^QF)It#aG44BWVS?aYhqy@yQ~8e;yi zC-Ls^M2;tv4zlcE<&Ejc z0(fq;4+(Z{npUgj2CC*A{eAa~w#_?!Y~*#howxX9u_1G)ZHDF?Bl?Bz8mEIhca)N^ zDle>A%Y?fz=)_g$l4xig+)lNa9rjNzDy&bnD5BvmXhQ&u1n8I=h#FxVcQ>=nkqaST z6$)Y30l+|G*Wfbr5kBZ~fU>b&y=B$H>9*`(>1Rp5?{>ZZP@KjBar?~MYZb2Ys>PJj zy`egih5LFOd%j8!el-VqSG~_eJUUhQr6-^5%uEeCasV&Eaqs{HWCNiQ6|iI-0X+YU zHSs2MC6AeaWJ0`du%d32ilcPx&bD}ML7&+)y*GRv?K)bxYizuwikn?Gz8V?QD!GiJ zf8Yq5H8_3|8bzh6bQk`rD2_rsl-hixqC?H+8r}G3Q;wmbK7-FKqSb;fp_qo-XvvPt zAZP-q%&-~(j_#HU2?3X%50rxer(tFZ^>7BuV~{7xKW`{cH-W&bU%>GC9t#1ZFvb94 zZe?^9+Szf~CAV|p`Uz0TQYi!1AkQ6XG?Pj@b_jn-)xfm&-g3V380+6=`2V5evP5XG@)srxGLaC@OHy?5GUF zeU!*BK7*6(DThQ7Q!o~`>!tZBGfCxfikZWwM>!AK1Fl+_uC`ru)}g`fmp{H+3Xk!^ z@>i8a_C%}auuBipiwiAPN$T&h)O%ttN~lEk3HQ+|IODLimbWfh*_iL?^vXkI#hG-A zC0J@Hb9+j2+bST=$ph&?62ctlFe&#=G@(}Np1Z&j(6G`a&AdhDRY}c(O#Y~YAQJ_2 z(Hj??S8x;=XIq1rsH^?8Q%{+8d&UzO$;u5cx#nGs-9)iXe-`z|5fVwkgo#i}dahr$ zrm6Rm=6gaYTx zS)lf`&xMh7F=7-HwH=`;Z(W+f^7qDpSIYrT@Iy@~J5n(d)p84vwD4ymq06xa)iSW& z0+p?lGSn^z@+leBqnt=Ea?Dpqu5{?9l^1i=3Y$+GG-l{7f$gT{7FCY;n^WoxC2W8r zQzH~EfX4K`N)ox#UMRa1gc}G9rHl2esZ_CJz2jQ!IV;C1+i%E*Pwmx}-=9%UR{9c^ zIK+|uZKHwqC};TNONU!YL55Q@2`On2*)-QnLlIaJMBj0ty%Q60ad2U?V3mAWkE1E! z2Ps8)U>|zCflhgNnov18K8eA-RHFnrYbklXf@@{Lx6#>aa(gq<^zmDqj0v=;kxjI^ z^v1fPkr#@0>2e?5@e>IKKG*>zI(iQ1mz5~qG?kfH%v_9~U z@alLV)H42f(V7N&`f~ek^x<{`Zk1KC2`-e1B9z9QmGZG+SwH5aXR<;X?GI85DE>0WIK^z+7^_wfNY$)&vq z5YhpnfVCBb8G_taLqO~SqKLg47rx4#yx(9pgU{cd=6gW3U~xZBi|nO>Sfr5DbrTf8 zp^-L??>Q&6U~gVsYH4j*h=`8fe{yJ5E@idZ-cFw8N~GpLoE<()zTV#1agdOd`hsFBgXxQC2bD=Gl#2wr%d76( z@Hxco;G)I*Agx8yYtUdUgSdpK8I%ZZ<~B{Ve5Ei|)**KkUp6$A zA8crUezE2M&(Qqmf6uhq-;#^}eu@3TrNn1!XZum#hTqcM%F;sL!VZ^}hTqc6(ni)w zTUVdvgT8~YuD*;AAIq;yR5b?s;rjrD%}7UK_l)|^s~lb*uA#?)=V&PB>&>*G=?4o6+Z8BnMEw!ORS@_>Jm>2dAl9Hisr zG{JB}14lWza(BWjj>XfI(FqNYB{qqjJx&49u(<=>JUiQsv7pZ^SI~|RQ*(z= z^Ci=voH_iO-Zt@T^H|;HpGlwW&#+K_EULRzKXa_=+7zG-K+gH1jD;*g`%Nrij)58m!_NkY*B%R&<4R@YqJM~Ni%Kc)s zAG9*oK@3`30NvDVIXcKVHsAvU9l3uH^mtWo;kosKenQsyB2cB~qinf`wghu>ud;+| z4#=mWbQ<15&zCXcXhOi)f*C$q@Wf#*>MtCZkhWy{45G?E#~i7$c={O`;Q6)Fe7H zqm@jB37pHas$jmE{YLEYPzbt2OSGkVz-ZcbU2&<$S(bQk>Pdpt3zw8iW9=>nL2($S zxVR2%uu`38MXScb%!~>nJRw1L@g3FP2Twd*n;kjl3;`EHW|k;*qb`qce_og;iP^6p zJ%k{h;ea{@9h*Ri6FL!EVm%o==ab;aIu*C^? zf+en4YSr0;5ssgo1#^Vb-nFp$bdN82mb?NxNefswE7I)$xwCS}_nly4%eqLVQaU#ok6nNp09KvUUlhjAzPnAS`Kr z)$?-NwPrQgG)e1BTa{vhU>kj~dCjH@Av6JVXn9pj@9C!F>)<9kSvF1JG=b(Q7s2ps z1+K9WN2_7fJDh+{@RJ2R^F;{Hf+*kXiMACTE}tDckB4`0^Iry9_@%aQ`bA22XX+#aiOaRj%bU&go5IcJypanwmv7bY@nkX zG=II3CPGWJE_gb}q|k0fI?P*|3ZpykRJH9MC|f12K}g2nUy&3B>8X{d8^K@Pb_>u4 zY;5ml|8Qct4HN%364brT-Mnqp_=SgE?WDTr+ehMU-P>)88&-{{foy6g&2is88msEQ z)?9ghMU`w|KK%XK`vZagGqqR9M%($%6<;Psn*Vt!{n=VOI@bx^feQuPd9@lNX6p;r zrS;OR*eOh?rAZup=Yl(g_(>TXZETV*BUf8^IEGlx6!Y7M?5SU;~f|N}?n> zf$DlA68K}2EG&hZ#SnH_X;i|4fe*{;#j?+UQ*MHTzklWar1kRqwGO%;;+YFE4B=TcpzqxsjF- zoBhh{dIaRf4fo;Iy2?~cuSwr! z-#+Alzkc<@0#vAXu5BT4KyjiGhwLsdG8M%0>b`PtY4I|81yi1oSa(Fy&Cak;eOiFq zNnrfcB}>7M6GwDRf@uTOIPu_LT|G^nsEvz1L)im&PNn*!3W_))fcZrLBAgae9vkzW zI#D-0=LRz)>iUGsdi2J2HtWae1N!(XijUR^W!aqvO|(b&wI}`;rL&)YxJM-fC86fx zDqrd4q;>V$r;x{O{;)f1UlXg84~`wVdW2haq|E>>p5IDoE_4ll4me;r#TR{;AI>(s z+jc3V3+x42C3DkeTYa=?H~4;`q^nOWlAckNQe|40Omi8Rf5{`$C!yDlb;(0{3l-{d zdVja;vbm~i9UgL3eDLZkUul*ed{t;C578fHDUYXjrm8Es+ zyG3D-8G))E-^})N!Yr(~i$6w1aK*n#!kx1|+|i#0(=2{imoH33<)ms@x@MtJrj3;p zLg$?IU5b+!QBCHlNhwKni0`&cRddm1)Hx8eYtO^sQSaI#VMWb+KyHbCSo$t{7E zkwY>X2%zrIrt|C!hj$j^{$gmehJhD+H;X^1Yo@Cs94sf}`*Jabae;h#+Hg@zN4m7x z%YjJe6`Hgt!9x%^uoKEA*EsdD(qRdy!h^<_Uy<;{%&(n)hzI_-p`TjjizUx!f-c4# zRTVy0vi;?)>ON2wWwPdM%f0h^OY7W?Zx1|te zx4@w^V%o%7%iQCt!F}7CNBkp>x%1r+^tB0D?D+O5;$tH#%}=2uzJ6{rg$Vx!V9}?R zEeFm+s02o)7shki{#bducR(zK7q1A-g~^<;2C&aBl;V;Zi%)M@l8b~k3e9h6uGclQ z&*74W1aK(dlqo|V!IjEP2~VLvqE0DKO>vLr-MU6TsRK`YsH{4@KZHQEa1<_s4~P$% zx{&RfbRN1TWaJO3LN~xPvC9j@Bqe8_2*o;is{~k{q~Ct%nhJ)9*`5xE@C?%`uN0&Y zFNo)YCPU*?K&Zl1avC(9$=K}1?-%926fTh46U{TLT zq{buCAzR|F=oKgt+XxGzBPJ9!BdyrVbf&1W%u~=Gr-+9+j~W%zwQ*{Y=+hzH-_1Ce zb>~u7LSMkFc4#@E)f&U4J2Uk~CoMv2pD5{TM31-XdY}kfpm#G)Pi~LDVH9jars#|t zfSj?@jG(l2sK}3axL|C$b5Ju@WXYl*&>`qgM_B2o3V6WQFlwS^I1{2Sx6i|aVs6_` zAFHjrZD^#@V{#ibh%WzDT6m|aGC;)gQFqHk;TiyF(`~Kp? z+kksJ+2Z`ZrF%i~8TAI;FEyGIj77%@>5wZqmh)>)0l}$)fKX8T54E(^Fjns(7|ABp zKDQ}I)7J2-I(OYen!`K2^?bjiA-4hW@AV$cU8~w%oy{x3X5*3QY{#SK9S`q2U0*0p!l%^4Z?uDpuly=K?npW>~=^!G`}mBkz)NG|>qAqu5)m&eNHpyFW}{ z*nfs@f;O&N^tANvY1rSs{1xQ89KYPz|6LHA{Wqfi_iRF8{lb z{uS0W*ngRg|Jy?P+s^(xr2nDzdiI~7!e4D&gZw*z9>HA4uUuBsI?dG&g#{Zw~|hL;0@LDW%jO53&EE`0v+-`)_{v z7tAkz694^EfbbJ&`16$Vzx5OT}!T&qq^%ESXo$Cz1$ zqW|NiR7Qy(V zN!HX_L-d%KN}Z#OJf2z_0Q|}!GDwPvy8Aq$HORO^@TW72#bqo$U0tj30yc2t{Y6`h~H`jTNb#0z&b0*f5Rkz6yqqFi- z7Yqp1S>sF+{df~#NI1`|RMSivDdDbm{h2)}9ceZ|cJ+Wbcw1uEvFed`Fsxp* zQBJ$TZ>wz#quE5{aP{-O_T2H(A_PU6N@6CoyZO*G>j3#nmfB>6k35x9UWM98RJ(hRdTnQq_k@a5;vy7k-*sK| zvHRsgj#Git?Y3PbYmBwIl6>J8BaE_7+;+^tcHXNP^@K=PYLdh;e&MIf3nw}$X4mU) zrVZWJhL1%JF({eqdiNJS{MWt>tz}JrfLXZ0?wkMl)D^AZ|sgq(G!Riz|yr zjhWAo36PdCAL1yNZNWTXW1_X`Hph2?rO^kvYcKuBWgnU0j!ZpQq6U3S&FC1kw#y*{&s-TUVXq3<*T5F^TJr;SY%qBgQDq~^b!+Iz)z)5@JW7r-54o37=gj+-8(q2G7bm?@X?)mBu# z&q2pFczF%Kzct*e&l$g##oSD079)aTapCIIYQ&yFK8UAqtBO>R=6n3DoVhKm&DZF% z3~b-xoM~}@=ok%=X`ggF*IKej!tNN$xI^Krn~ia~eBI0d=q!!H7eZ6bSlLIDS_%&< zs)`t*8Rt@?3axluBa$)>9WSeXt?I!Rm4|>zO^pW6$Gw@vDr;N8 zeeLOa#n@MJKy{Ts#+l&S&6NA@0=8WD;Ikz4geqI1TzCS%L#Sd$o)G#9xr?ic z_K`T-;C;Is)W_`BEg*cB8BXxi?oWl5DB)!Wyh`aMCG1MQuFL##w5ynMCGFODdgNlNkJFGppSv47Y8>62BiM1%({70@(cvjFT~W) z1P*KhC@`M`pE1!VLC8k4Ypy{1O9Q02nIQ$g8#MCJYF{&v)*ErSE`_ooGHW=4@^%t4 z`$|95Ddzeg6>s%C1%7anC%39K6+h^iv(pUA@&9l)wX)XNHQEha=;SZC6>XKct0sAP z#Y!c4bfpQ@&QS&aC3TS|TVg2K(JGaiyMdu`l-6|B&dMrTP6-`&N4l2Awb`mmsSTys zYVneT@>JtoQCwu!z1+GmJxjztSygldrgC7Ru|elMU91=C@?THXpZU4j^~8V-MQ|+i zbTS5x_5fEchBvtP3+4Oe^QWJ6=;Q$=MkW&0rZ(K%bOOSHB6`2d@0_fSf04(%{Z81% zNXf*}5nyfR@TR0=qW@*m^v_AnKTbp59^h=?XhJ7$Vqk1y&-?a4r)c6}<797S^0qS; zHn#tX)ci$6#lMQ9|CR#$p4|N3!nc34<=@vHnVA3WA^o3q;{P~}|0$$@6P^DVyZMh5 z75^%R{=*Rd=X>Wl{++7uU)Rn5W$*m|6H)PVUB;B$+xmvnE~Vrj53&EEdgs@M`)}(0 z7fjuMf@=SS%`nmbGPM0Sz<;>_GtvK~-ub5i{)yrIIga@+UHwm^t4#F&8b@Pf`NwLk zYr0PKSMwfvxWF@S7`$bnnzSBSLU~RI4of_lJD|vl{J=ieP=|qKHD@76l!f;{evo-f zWiH>%wSirx`5n@K-DoFC?-7K^`8MfhSN?@FuCa2(bV@-yu+2%9y}=tQw-R_KVU}YO zrY-Ir&uKt=w1~a;=hg9+?M^Mj=RRmJ5Ry~~YIyELrEhdRgadwfn!~M9$DdO8zF9>; zsT@X)Gn1;P=dp?}MUk8L&GNr|orSu-&FWNm(LYVCeX1~QQY2GZS@zhw{GppOBG~IT zge)12`_;|!gd#Ax#1miC$mS30z%czgz=k`2H@yM@iz4~12{O^yO9eR+ZdWqyeYJ8 zZ7of#elgm-xn6$RgR+g7gs_Z(E#2QYq7znoPfz#DA%#sGjO+onjyCqcW&yu<1HNtg z%isKxF);pStNHaT)wJlfSQr>}IM}rq+1Pb-czJ)hTmNz`za$brt#%4H82xef^YXCKv%h(MetU<8k(rrJ)Y9NB2YLJccBo%x*)$BStnXpKJ z8Qf*X@0=1Z8aw#~-ievz7{jp>L3kK*rr}Y_Ipv@b;Z^}P2&xds?fRMCfpsltviQEJN# z3hi}ri6F72_qekc5C>ZjX@;BCXUhRF_Nf+atCyG1b8HWOh*R$?KIj>PhHeXs1P;V0 z79Oi2`<~i=*zqNFS7vtakhCIvt-!4q{+jX|lKE7p03=}+&j;}Y0IOGWki{DB%`h>GQ)yJld9J)D66juA*%nwEWabh0Pk_`ZujkR1J8LuTE zR|IfeD*9IlaCPVdihDo!Hn0ab4h&mILvQ|7e|woY=U_^GGhtZT_6=9@1)b*dceL$5 z59oW@qaRFHxHh}8LPlN@aGYs*g()FW9E&4(P8tA-%pLum=tzwCLf~ z&qMRD2Hp_lYOYZAVJ~QY>QFX_5IX--1>f9q;Nb}3^2z^8;?A00AnsiE6>?euakV>k zGZb=i2OKmvtc1SBcH6m>z9;CZoPQ?J3+6S5F_~?bw(rY35FZgLV_H>e!ksOXL&7Dp zs|2F9z)*>unrH}PukdG9;wxJFOrjlLxexPnLIXBo#Q_Dx#{v`CIz)6*Ur9c<0s(RZ z-&_)Fflu4nHh#3e-tZ};=I^dQmo~v`Woh#FJ_7jXbQxv`k}G8*4$>-WWvxo%ZdyP4 zUPa^v!b;3F<2?<>6}u^%aUeTYiF@F3tU!6Zzm5J*5g>pMDIm8XT+z%|c;J_tg%%w< z$(e@kZHVGTSqfGG!Sbn{os4X@r9o$}PBqg8GUiMTcIcu!V~Ip(2qh#A>rU5gFQjgY zcf0qYQ4e+^`T&q_lt$te#rb}{+-cY$8`hEkD%*#rnt`A87DC@(3K$V`b{Y~x7DiCd z610UM2aj&*$j{*t-H8AUPvuU4qAf{P!X4tli&RgK&D^Tm3&B%67ysLQ$+&`q)prc` zuH!-daoT6ewg6Uhgq}H|RnkmwbqA`C8MnZTVei-rdc~wU_$~UFKrIs`ai=k(ay}#> zK{myn>W^9y9GkdQH(AJ9W!+ZalAN?fx^SL4aBsL)pXzod+H5(se`32(T^nnA2zn^G zH`BJzepgAF)Ffa*Zlyk3-D;rIQyAD9xEGiiSObxF5u-=*tf{3Q%~1Y1>yC+z>r3R< z9thWa5N^-5FFn|upKSKD-Pzystc(+=Z{1F>C_moxcUi-QwM(d3=-`mH7A*aplz3GIJixDe~VGYu; z*F6zX2unq$%+0I!+CSC$?C?M=Rn1n705pLt-y#!6P@$}qqcX|D``s#A#F9+CB;qQm2By=z<^Il76e10VHx+PZ}D&co77p{)XPMI#T9|C3vT8@xj zL8tlOF81!gUUgG&|a;mZ3GkdZ0#WOQY8MHQZ z>6~(^a$Kd-x%;u|geNAKf%`5T4&fdA^}6HMeN88hhezb2*Q!p27$-bI>*mJI3FPhB za+{f%MVL#_eyf#Cgx2c2%ExyW7Nu$`73JzR?d|1`8X-bPJDcb@R~nI`y4&-syiIF$ zJw0AHA6B`zd7FGjwm6$?sQ~tO*Wxi+P4}2hskYOwy+*2#%so=fT$ZDe?WARUkcZi} zn|pI=ZL6M{8MsisU2V%eLltHuKH8TgGWONTph>V)#>yWwPwSqiW6Evd7;0NW(cT32 zMt$%IqZP$KTEJtiV;RXt^LU1_la*Hu;{fGO#pXU)FZY2X0;v1e4BGhvc)2Q--P1&+ z84?-I0v**9=0O=G&WwGBOvpN$jH<$mn!TZDuKac6YFy4aQ@l>gTN+iFx`x$NE32*- zNStbip3CMoFV(v0CAQ?d>868NjbZGvRqiKT1FlmuA5H4Xg#7xNM-Jrj0w)bi`VC}) zA_8@@I&Zc+vv0MJ&)ti5Y*o%?`;=65&;%QWuRzixbe>1;)0bUNGo|=p)wc=_PCxXs z8ca8ozf57jaOVp7@dd3`zR0S{=obAjp9WJ0f=Ao~>3`)(N1|0 z5cA%pLFJ}>dUvd{auZThw4gFLm(AGTLIdSXcWF0xF+mNn77e7z_;Qn3hV6uMT`GZX zPk8mV!&CoE*5LpI<_1uE(IRc|rtj?JyFwwgl&jH(M*RTZz}}Qq#uC*qE`tgum%Tdb zuM9yT_92?46(_YHsf$%LXm}U(d~M2?;RP1#5x`E18Uw-{+FGu*t?JW6+XC#ZFiI;1 zliq#qR((lk`uqxeYoQ9HhU{}o ztmry2)2Z(?tG{6V5YDh0zXPXej`};`JAXSD{N5&&Id%9_hz&(bnC7eZ2pjan03tXG zt~;z%NxAT_a9R|T+1a={Rm#BX>Dg_^h}Q4p@KJ$)N?aq67N7<)wt#IIl-=U#N_+}r zb!)`FaZu|Xo})K3Dw#jUo=nVwjkkITY23+gWGflI)syDgKQRm{D~Y;!=W=>J0w{MF8y$N$ z;#BP*LFMHjp0FS_8YTzRmH}}Nf`L5gaqNjJ zcx-49nId|7gPVwgYJ3nAe4j;2)r!kJHj?vvn~q)2aNKdHUg|wnlZjb@wD+DkvDA0L z>&-x@*zj+mQ9;6=+P#@$@o>;&L>qh|eUkfDf`F2qCUB=EsVdN{^QKE}U0@yz2>C3B zr2^XF3I@%w5;6ASD+buS22(1$RrxtWdx*7Ot|KG07RYpjZUX{`=0 z_y~Cs?BFc3hQ~J~M3z&Uusx<7dk|{&;}VfrMaHPWJEP`~T8+glH98ToSk8(&EtkgJ zRT!43GR%n*nOQ6{vW}mo;NY8EpQh1iePQTo{}JCerV$~u)n>Gjui`$I8xvOq;t<|p zbuHtvE|a14SgunXTSJrQr79jDra$Iavc{+;m611EB3*Z%f2ns#^a`TUCY*5pid#{r zb6=@_Y5hnej_m63n&KJM8ULiaK;79OR(xIXDFCDD#`$U4Ylg}Jp<#RU91IV{1#}JE zBmerEYX0q|_EqJ>k|5EEg1tOeOK}VYSLO1OdQC_|yrt&yKoW};)pUK~EeQl0;?O~cIMgo*?JW|O$VSmP#PAvywus_KB)OIRn_fMq6WH;?a5a9p(YnyillE4XZ^e1@g+be!+lYQ(O( zN?lMWGAAX&E%DD@9fdF8mt;Fa>2fsFaag;;=cYOOk`&*0&n|gldE;n?(iJ6quii?U zrgWCRpu$!99=}EP(Q6O`O%M9jZ%eKAFm@kJPh@SXc&iLxa_E7kC$w8Yp#01^z*l;& zNlE3!|4d^xXdnKe0D%I(&SW%nzL;{H>tpqI-z}*DC1>4>;Q_5%iMIm^El!8h89D8m zyd6+x7zeE@{V0(@^*MCvjJiwZ0&S;at>|9zJa9|RoUg(=XshfXk;R3wGnKW%P5XjH zxnqx`uPRT*B8j3iv2g-ra>x1((a!_Juk(Pa6IGWXT0S9UpRpJxA7- z1d$1GQAG6JKs^#u-17qcnOy(f_f7u`3Le$^$`0{>eaEHEoRc9XHk`qDtf-5OwK>(b z6ox#)&bo$%Syf(ExLG_!xe8XL`-F7aBSIrdIoV6sW_IgdPJ_ZJ(J3f9rv7Op|0vg> z_I5ovoEqkNBSPMEJx?WeONe(A=~HG8%{9hO6XJzVE8FyOJ4H+qOlXY$0O7PtbT=Mk z$yE37r?`}Q4g=yOIJW`u6cmPqkrUuHo@$@2pksskt-8QW>5vTJYXB4LC)aF3KkZ`NGlKC@z-Y@)Sx2>bS2FkF=8%`>{MTH2EV_ zzUx#q#(wwb3jHbmEc6h$_xM;D(Kli-UFxQxE`50lLe9Btv9e@KTAHS&rtM0lWF24c zXH{lq%s$1l=Rz!)Mt6Mu*uVHO+q4#c0SzZnnsUf)v_pA{=c3rCWOgXGCbwOr`} zE(AYmF;g5n@FO8WEmJesT^~dyk$Ez?IQ_k>^93FX+R>)cMKqRZuSBtcpLjUt7E8WR z00jI%agGrsc`2$&@_M?jZq(@Iys0g2NSs`Hj5{MS>$Cay-YD=AXI-GC>Lg_KCjBC= zorBOiQ)*lrfz_i)bRv{ljE1WFcnV~AY!vmF{5M@y(Kxj(wRCDWR6)qJSGLZKB-e#x z_aQs8VK#F;vN6AXeBno2KCSkRD0x&2I`ynrB2X95JAh|UHb?Lim`Qe-kh@dbNj3Rg zuRb000|R!y3*SBasfVrILa2~dkZfCM-HD5)Q(ZVUxDFEdH+Q=7dcR}g&!mQM5`eOH z7#i5N##ub@+fc7GWMI7be)Xgu+zccxJkT2H-SfRO{nmn-62t88up%gkWIzpac>IEc zh+ki-(-YUGr!1t+5%j)Z$(-W`W@Oh#PorMdHAhJuHh4l75Wn;Cz*UA?Tgs9qrD;eC$PVlSxKaZ8=lCN*d$-Pgj5;B1XB;jN9|vR}P~Ax0f2 zOqwt*0k#cjF&Er4S{@*biG^BLRkG(L;SdtVN?fdQ!R)t`uSCQ;N}#gz2tW^@^EZ8; z2256s>STd#up48CHIzr;0*LClkKA*hy`_(=;TIauqx%p_CoohwQhaShB;TC2ML9fM zrJ+CBKNOT=*TAVJ;hmBduDuuo-HnB@$i{OMzBkiDX|uR3EX9lZruNDf^(4_8{BMW(ixa=3#Up}C9kH0%!X5C zRh_lm@JRt)pbIx_fe5@tO!-!cl2m6iF08WIUHF=b(LwtIn~HBjNjbHulAyb^9^q4f z+eIl8EzM+<1n!A8_2^o{7;_sVhv(u`#88~jbsnCM<{q{9d>Pb9CNfpg>>{D5(?h$s z#7XnDZg>!_)iQDpUkT^j9C`V8@JO^o)9_27N`%`b&!jIEZ5Qkb#+gXc6B53#7Z6)-oLUY9wWQ?;PeB6AJD$()CO1adGpckj1XHV)JZ|*X5A8?b&-PZ!EyP7#|rjAyI2TCJ`P`KuG z@@kjj)I9wbkU||C+Mz(TXz5dFUF!ySo*Jtu-z}q<*WG4EboCtr;q8aH~nf|esA|BHFW?Eli{pE>Y6Th0)T|oms@w8jHzo#+G z<`2uYO_$mDP?KSd@@85W3XLDokDP!{X;3a%Zx#T|RwfE?Iykr20v}N?)oIIoD;jfu3M~ zqOA!VG6G0oV4<5XhLRc+2@8MfqKD$#=pD>F>40t(eFTayCNk-SAEP^zR^~0%iZ$Ip zAq{?xTqWvanvLm|p^sneU8qYZloMffH|rrtlHd#zaGwIPU1^3cYed}cs(F{*D>zA7 zNvaI6Gv=`RYi|%MMas%j&<~}uXDb@R+LN90Eujgg2!$>6 zgbJ!cZ9^*1T4>0%Z=QBPm^j=Yg8V2PASoSg(u#f_g^J@lyzCjo+Sg9kdv&n4<4AEd znCOb6(P6A;1I9dEVA!?z7DcgoUSlICeTGu$I?N4VCjoziejGhqo{H~JtCLy0zGK;z=UXUx~)Eu=` zgAZ$QFOG3SSfU)Lp*LoVfiJaeIG}`z=RCt-K&}{xS2PG0IIx;TZdiUF2jqL%&R&Ex zG>ngECk1x;zz{28G~_TK0?+CIGW8gk_6i`PBRcEWpp0}mVY>0yD4=n}>jY@hY(G9! zK3CSgq}mn|==HK-jwhSAwlTaqJ#2qQC&Zg(=MXhYyucN@4YUntyn%^OYAY}TDKVmu z$DLql$CWW*F-uGhF4y*0&}ac55!y)r+X>I}ZW@(K*RYQwb$t%L3UjZ}3$lya&qy_4 zSaYyfsR9mWz&&P=J!=l-J!)s=)}7tD(FEbcrw5Si)Y zRf$FqYti^YA$h0NWfu#4lqWyZ^3qJ_gdnHVZ?=5tkoJvYgA_mLAwVt`L^YM1xJ5$kAT_c@ zxN@HhJ&*%|S4H2C9oZPJcb%2;QxwYdc`8X0tKH6+BJ%?I*zadQh467y_&`&X-0$Z~ zv7zikGEOO=#M^p0zPrB70S4k=m$(DKa?_lrYbxR+gOG)0hZI1I%4vzp*?VUc$Hi36 z2RhZQwjiEPcbZ%exvdx(4aS{pmV8#Q+U+LYgnb)(gf* zl4CkOYl4He<$R&4m;RU?&Te7 zzXC=cI91JG(A$dw8;FQG?UJH1mBk@eewetw=pgwefw?yT*wNwEb?nM~TMqBII2k^d>8(dU9QauX%tY^!Z=WM*PI6nA z9LYA{{;{E@fxd>TVucoV<(JM*>RB+{q;%XJum{kCtO83v5BdX~F_v`Wi#}3ClV=%l z3vR+_5;WLC0QwVT;YmD%ja(zNzoj1MaX})Vl2I>cL*Y1mn|?J_#x)NWuG+plU(-K}z73`+(c)><70O zrbF$6Y&r&x; z-EfmWAaFqO3dzKOJQ?{(Wc7Ph>t8{r{I_RxOB*;i%GekKOaUgwiW!&#W z_DXZS_*^=~r|{N_aXvjG0SN5neEYReU%phbp5EwApflKh0S^*NwFDu+CbMe{u2YD}GsH0IKfaAIql z8i~feBz!o(0%s0?&1|8ws&Tv8?B=23|KZxzbw96{+6Fske#q8OF#b8wn~C}K?DeH@ z_l{2E>J>IaHNC9g*W6cPm$)6rWAGU#GWDAppPpwXGn8ihx@BCtR?^0SlSbcINoYgj zG3gIBC8`9OP#pTOl3jA~3g)*G9*_K06dWg1*FxHJG`aP#7jp7Yruo zX^qLUS=&UuWx>yMtNv_kXAq(-=Q)k1`=dc&`{4}UPFG!F7;O9Vw3?-6MG)Cl+*UIP zsw24sqBlxyBiBqT^jkjR&;sk!p3gRqz+7f&C_zPAn)IhZNq`zO$z(x#e@E99j9G{D z*LmaKL|#%}A?DCE2a$E|a%i-<)u!I>AoZg0y=QmFtd+y4=U)q8JluY~qR~LP-GuAX z`%&;nC~-SoK(C<8_hIi@Y>9M|N>W6h#UCBjx6Ai8Z@>Gq1CTG$&#?8=qLe;~kFwU=2ite~1xzL??Z zK7t|DuydgvgVq_CLCGYy$uE^d^NLk_0Vz^V%4FY@J@K|&F$2}JDMf?%wsq9Vvfp6Od^0)>Dv ze!M`JUsriXU_TMH;(o-?iJ$@5I}!BkVwqhD^z_1cP2eLM;GmT-C}*$SD0XAtK4Ouz zG>q<0U%?`MJD~2*z+o&Iyrgt|XFa&odi>oe=Q8IzNX5BmcjsnFUCIQjNLBzSsVYcWlkigtuLt3+frcoI{P`D39Lm}qv~Pwl(Yw)Th% zp-_3WU)~4cs~|w8)au^Va_1{1EL_`*_{9$2k3ty}=+`lJyNchyXk^mR>CoV|=ToM) zOGZoRm!q$1Hn-IZqSgw-6^#j2P(F#Ex60^^^f>{P;8SLx+P%5JQv!rWl!w9RQ^Mw< zs`I}pn7$Jzgi}o!j)ToRj`4QDV#HXn9UivCW(D^(IqPGoPsdWxwkF;0&UZj_>GlI& z>BTPbc+W-m)mnbraP*S8FELYYqoQ#jzYBcZ+f@$gQL&bp_*$V!!A|N2w*TnM)8Xsd@*W090_*BWejq{8}yRoXAum&Ayq5Nsw&0XDQ((U9WB#grZ3bS#&@HY z^15xcTnYKY5~a&YG^Ynf*ao8@eH-4@?bT3|BI| zu_|c|2a$Wf{d3d>eV~gsLfYVSO{j6TNq_1qwu76z3@O+FnwT&nP(^0PdnH82;fG*g zO%g`PDHM!3Npx}?C+bRE)fKL(d+ux9bqg0@y*JVI(iu~li1cCe_|3ryV$m)KmPcoj zLd>xpwnt|b*x};gQlG=JQd;EfhxX}DkvE)pa_1hl_**PT9)sB|OADyJ98v?y_avgv zZk%Viq>>1a2N7a+8dW)cbL5(bCz<1R?)52zEu{J7-34KZB&25VnKr{!w&Ra@TO)y` zR>j3`N8LpuDOKUad3c=3zMbNE+5M7g^xl6k%ahw~u-N z@ns7XamS(>{=oMm&U+t3C!nt+3*e=L9~4~P^|!$p#`tc`wvjn1^yNxr=aq6JWOKUCFKFU@6uoHR3PX0NunIK!@?S|&Ez&$A zuAseEn@z;Do@LXk-J_ENoO8l5%%8o#kus{xpjo82(swjc)-DV-XE4Nl5I+2)c;u}rI~vBsC>jM+zJvL+m^Q>oSNt{HNTob40!Sxpkq z<7BHLc7_)6QoD-N`TkLnuaGvrSz2i^M*cv)wBuDd)#_Px7e}cnJWd@0u#DmaN`35L zZ6zg)3;S&x)s+d$HS!9c2xW;zh00`~4VV-U$Q8~vP1ZzEtAA3Tjo+OWKs-Yr5lDuH zc1;0CX*4Lf(`kc2K-HYsB(JP32ORN<%?|<{pJrd8gSRYz2bT8=clz8w%S7 ztBT!p(cJuDJ06r0TjdMhv@TEWO7OT?gtdygR8f0y^=OtT-N9uLLiwT>F-ua~Q_o4; zybb*5)qc|Ix3-?w)ANFd>8Pw*m(i}fEZ!5Jjt&d&Z;32v>uYQHubvN=O?vP?o=a>= zKC4~cZCy6BHqX;?RqN|(9lR^v?G}}ljct{Kl|T{wfy3wnAE3Ybp6U6yj5;yy^zj{z z1hc#qOz8a4@bKg^ir`|iM3y{(;~UsCC%>csB}(%ti00v9baR_7A9-_llgpm3#`iqy zg|hDRWCdEkIfDVZsp*T}o1@n(kiz2+6J^Ff1y_Fs7RmTO8?^s{U;ZbDJhZ-9u~>^TLp$cLs|c+MH849f5KP4XOZl0#e`Yj0!+*P=FDUM#g_-L zbTqO5#lz=lB5Y!0V{AhAueII(rjacFZW_t>3!C|O(MZ;Rj+6gS8p*&z8T>vpsUrl^ zs-YfA@c-Mh*jWC&W~tO+kVa$ybAW@<*j5akO?ge9dg70dMb{|$K+*`5gnvB7{$$Dh zXDH*>cKa`k{OiF;#-AYLKMn9tOzV&O?Qc)m`!9_Ak7HGgKS9QS8sMLp)_(*17lM(D zKXJu>8AdYwG3@ciBWhMQxJ^i}m3m*JWRR3_J5dn9Rx0vY0b$Goz~I9@NkA`mc=m&DR^YWv!zb6t&3ZA~L98*RtMknuSbY#ax~(4YLEVmyU@KTg zmaImMACF8P?T9NW%=AB8bNtZk=&SGDTDzK`hY|c%eR>x~-M@0HLv$}Rcc%$uctyp^ z?pB`B@ltbwX{V0g4yG?9+OsZ(3Uy{veD${veuzD%c6rrb85(TXVm#j(TXQ7?`Xd*!i1H?Fh5W}`6yQ~Y<~6u7J?BflX1qRD8`4*a za?E4m<@SzdWWnO&Q6D;MHodj_y}45@u^w44>oH?qD||cN5+`YkZ?icQS_BwEklw-w zUpCcrVXZ%#O%g@O0`rFRzxMCztedH}(6QQ_A3H4HS@|~@8S|-bFC>rGRII*YZeOx9 zy~-Yca}v515xDLvzv5aSmvK0FYFDi_Id(D0JSBCouJl>*T&CZFAZ~&O33*D09?JrD z<;kvm@rAe#Hw>*DMq=I_^Ji((sNx&==*e2 z%j%8SVB(<_6w8vV(Wp3r`zk9vHuZdVPUKj~#-!9aCf)Y9;`QYtIDCJooN%#yS&@j) zIzVo{M80EM+)0Aa#sgNtLfz>Hj;?=!Mtx4AAA{VS@Jdb% zWHpR?7$8O9tGt+^zMyUoC%ziiNW7vv-WURYHK~KCx;)bCZfuyb*fJ7!h7$JJUWl{k zq;Ec1m2RD&PI#;B|Fiyb`l4q*Vr+Ce0Ta~vJ$qjY=tZ~6*NJ!gJfJhCq|z*54sAB zMo!9yOPCHv6hidc1ApGEFr6sEP3@yv1_*6da^7)#eMvI zKZuoQH&|uGt<&{5NY{kXYab*LAi*rc&CB~iN754{GUx^g@|?+nJ(Ek}vVY$pU0o|ztR%B@xLe!|&m$F? zr<|jPozOS)Q-MK3Ker027N2tfCUF<3RjE{+b~Z9$rGj;609p`^VGHMi=5nEDOGOoB zpK7Y!94)elS>uUmC6nKZB#wiAyJ~h7bFUdN=J#m**%MkJDAF>FSs$fhH6rHdZ-d-s z&Gyv%PH;zrJc6BzM@H$WPd5ucjFv`jV88Q2YFMVMT-Fq@SmlTp5LvM>D%1G5%G4B| z3A?;Z?=2@Dg1P#9@$Ue+#)T&F&kI+8VvnkbKJ=oTPm#6cvYmb%ZpKn?irCZP6#My^+LudhSnIt(gJD*$ z8q0Uo%$fCBu#ESk4w5hv{sDq&V>cz?OKnL@40u@?&hdCUM#X5Q&O4iw3ueH}_x9@X zl7o*CL&XAQ>>wl+yfHlbs%nw!$nl3Y`OcdI+0`jt>iSC1EjVR$fBn??7Zy9KCx zlt%l40$hv%{28%AEG3T$$lIzH9(#WTGC9(a?2!2#(p1}9g&p=Qb5@&Mg#vGpyKgtu25E5YFO+J8M z-fQp2t;C@w>tbaMsyTE|AkI#%>uCzXt%wB!qUFG9wZIlbn$_p59$?iSqLT>`;^1P#GIlFrPer#kcYzpCG= z$@lgRRB_MY?6dD)oRz(w-&$+;s&Q@<22$8sX^)Dx>h?61Zc)D#mavDsfi>e@>PKP7 z49Rf_NZU0k7KU`>AK%lj*vMew>=*?@JRMH7iy zxd(~j>Cc-R{dsT^ERNFs+ocfL@GY{DaS6j3_6kNam_a`bWAOaGCh83Y!NHlB@$3(; zviM-hRJ2*iMJQ5&b{E0TvR}~de6bk>qAJ8808cwDg9oC>SGv(N@`;~s+}LKf25WH* z+M!o@*%HM5Oy_7}cGl?X*tWrQ#naIH=J@_|%)R^V!~N%^AhFMBAAHNaJnt)SKb{5Y zc(2`mx=+-4aJ)Uc{2ZcXC4cbd*(U;gon!npp6Y{x%NP9v%7n*CSdo$xnBrW5)W~TdTmL(0s&kFF+&R&sIxTTi#6O`bV`? zAc3^rUwA*ntxT<*zV)!g!dxoHQ004&;OR{n5V%KTGK^edo0=HF=DpJN^W6Z&KM z{|WkI{wX*570@5^*HzYE#f_edSAA{lmqUNdKft125B)L!m64=hIp=>c;lHClGw#0t z{l%t$!7=WPsoGAYlJCB9StkHeFcnLTI5)!&%lmD+q94)Ujd!iW4HN@F8l0N&kA3W) z3{(3yZhxb{Ul08;|A6%V6B+vE+x|B2FKFN&klueZ@DBv(=P>ARw)GOJ97Hu=%h#ohLLo`BQ+HpIyNvHe`Y<5FV2FzR@UEK0Qb{*c4c$7Osr1g990M%Je9S|{=mm}B z^Q!RYa8Rg?!L;3IU_d&ei4L$|n4YujX`MAWerc4#mhu9w3BseE971+;dPKOYUST+2 znNL+Ln94?@Y0S6{T|6nA?Of1yN%6vB5llg1~zj^wZ z^O<*iD=Js({`)vZ(@84tsrReBXuFzP1YS*zJhbFmk_S4wiSQ9~y8!X!z!qcUQ{G2d z9c_&yrI$*93wZZbH_KBEc@z;qQ*j+WTbi_?6Z{5H%3uoETri*#V0yw5>JI3!Z*oW$ zBLi4H$SX@STSBtRzd^(lX*&_!KHKhrcxt(?oogc_wF}S z*~N{fK!CeGc=m|$`8XY(VqTaamIa&0j#=#v>~7@qKxk=(9bM~b)|q!@zTg7KYj*VpS7ClhwfC};phL*3!;DX7o{SHXKqt}s$&(bLG&y8BpQ@A-I%Xiz$Dr!&o_)9!B6-xR+@N&waJ zI<;(y{UpfvnSJ6Kd~EWGSK?|zBm{6A?%x!P!w(8vHZce9AyRu$h(SZa+GX#h=SoXc z#VjV%%AYOuwNW#t&|?nWw_IjKLwZQ@RwI-qDDZ!vjLu~WuzUeE8d!W@InJ7(-oLq) znN~7HXJom*9a|o`_hqFn9a5iuDUtIq1{Y(+jB5j0sZC?yqK7LZu6pi{IzNf&R=ZuZ z;a*eO-2^=@N2TjE4ZnuW^LKAXp2y#~%i+xljr+HG`dO)FDl`)8X}){gK`^H`#1x`j zngESz&7xX3dK&()v2D7&*IpOP)9UH#XTuqbGeD@n^(YTD;RpqpN0g2R3O@%a?MQ^w za}hZyc}uKz(ON3SG^juk+$Sr4@NpbP+?-HFX;m#X=%c6<^+bZ&oH*`K@nI2}$xGbY z50`iiEB*Ymqe^oj*%(DPq16z<0%3!6L&8YrVhiS>sWUnFt2e3@z?qisU%||SFigCb z=P4`i6iZN^tl%a{K-)cRG}s8zrA}-rQO(CmubJhQvt4n5FRt(;v)0io`XIsM1zjwe ziT$AuWZ)xnmGMsXb9-jnb|}NP+eM;xbONln_}k0NUWmE*FEG+oF+NC{WUeULX+elX z&cqwon)&*}HDy!Z*_LrbObpw{mACvp@|GaLO3NDOfr&N^msY>oc#J2`ikwy_Qo@%v=FWcqxn@?qmwi2v z=9<3HYA{lsg)pEb!zrOKCc1kL2iH;{-);6wX%|Lrxs+l3E-u+>RE8mOEK$>HW&_y! zkpb9dVJc?7J$3(uYRD=E7}@Me<;z<3xa*PJYYyYbNjoz@q-3U3*xO2lSJCJ-c<~YG z(}qzn+IA>yQ1;VUQyIHm$htTziB=viS|A_LPV%@!@?3--LINJxv)fVa_Z~NoK_o4A%ct81TOcjm{uSPB9`4SMXAV~n znOZv5)=s63!MdVM0TG0XC6LC81@7w)ai7EAULSwCJyrP}WxddFRgp@;KL8+Q zBru`s8Mw<4@7WT6=k4hB$Q%;CIlYgwj;lKNko?RSY>oxKl$ilY3cd0HQ5PWd;P?3t zm%c1NWl_HZUi^-a{vy2iKe4D^V>>2hmY=ezUjZ+&{FT9?-xdJBAYNqo0Z9FNc#-9= z3=aL~pnh(`{{p=DkH|u)duoC|_OX95@a)^T{Y{^KJ^IA*Cj-yE`L@3e{0kcR2W?P)Lc zYKyvkpW5Kpz;M1@w(%Vz#9WccUn>tD+a%54Ct8{*;lw(*j$Dp<;Cf~9cb+_L&B_>w zq4I|OK??+-!ntJd4IkH{$4AI+O*)NYR2yy#S6{@H2VUE$?TIva4bi{u~ zUb}*;W*}}vV!7!5aQ;?6*6z|UZ6?dnmd=m9U{OE`DsU+MwXb{sA+KZA6qG{ldWiP6 zz`0w-a?Mg=7`9^GP&FeDs%Eyj5p;uf9UTH$G>}Z9uQ6J{qhtpJ}K*G{HogOCPq7byaw*=P(;DORQ_@z?ks)e5nc+a5W05m zn^VQedhZ;u3PfhJ(z!D#Pp-MvmDfut9r&(>jBNPLyL;UjU!MmDQ(8%y zHJa&i%BzdhN@?!~tVF(ic}J4w;<2s9nsh`m0>Yb`xsTgo(q8mADjY&yu?TER5hbb{ zh!}cL52{Fd1U&y*Ab!{@Q80f8or&c0qG~oa9j=$g@~f}~L}$q?b3gxV3pLs88ySdT zIMej^%sO9=A^4IVIkei`=h9q*S|w)-FCqnTpK5GlsuPUBzN=+(%Y&VMGfqQ&G0uh6 zUN{#x6>{-m52MgRJU?B@JkJ8&J#f2chvk?W%ST(y-I8RNuxJj3`g1SY>-SjI?$ULu z%rMf2Nrq?-m}i*etkzxVx>F9#Ba{w_UG%B41t)XvL~2(6(*wtF-Q3Ho&XuN5!8Xi6 zBWwP*n7T0YC#l)dd|-1EJtJo6#md?f+8Uj>b15IAVJaO5U~Yqf^szy|kVd4DCNxv0 z>cXG&`8lQ$X-eA?T%p)~Vd!7x#}{8GJb?|#G4!pfI^>e9>{C&3MNZAGNe2h6F?TD7 zg=a#9%w)1i6{{gf*bJ$Zvhw!~S@SB!W{*u)$eW%cea{V@JTy00tH6o#(TJ<-nfqI* zeskm5QvkudNmkX%nuX&0NCL_eH-?ji5xiO@yoqB;S}A82lo4IPM0oQvvMvNQVyYS& z*s+GOt=!qL9t9IM!lOtp=3@HJo1kd0*L;8!xEBb^=1#ly<>(Cxd6W^#c+|^f_myyX zb}V%VflCgYc5)ISNd)B2fti`o7@dTVR;q>Etzqch<7xKEI1vJ_m5Fmtx9gq#UJFB9cT-d3NmHDhN~c6Vc&|Z zsGplz}uQ5P(kl}oJfVz*0V)P^>b_B~^ScX?wR$m&Y(9$fRzw9l1Vz6cpo z8fDInz&!N%fw`7_mD1sUv=fq~BTC7RNc@rIB#98+TLLcPN;i*_jPv}iwwPPLjS&mR>zI)80NQ)ltSXsro zFsPZ}^SC5jS7fMgPeVA9`x=?Oi@ zQDo0pwJcxP(Y6eYi`&05Zc{5`*9rZky;eTgt5dSPJllWZcp8yZn(XQ6+;;7C^YLJL zw7sE3|7QB*+3LsgWcu#qPe}yj^GRt3X^ysTZce<(T`D`siM$17B&JoxQR@M_01@QtcXuNrg0JhY3Hg(+UK0OD7x)ggYhb+xEL&}esV zD2|O3SNM=QUV@$8#v=2W;t(0?~Krz zhE$CR5@Xfot1U{8zUHhgsPiX{c(8n^{WADsAm?uNy<9*AZ9MN&%}vKuQsh5=Dt{m) zzaIBu{VO9QzeO1S+=TxH+^hL}Se?`bHU1x4^G`-yeH*vGSIxiRs`*bwU48Rye;fGM zGw`>{4Brj+pSahz`N-b}{sj&E1H$^#+>7mpx%1Dt7ZU^L?=xzXmaU$+SKy~hRQE;n z!O#yUkf1;oWLAFl;$fJS6KVefU)DOAPOb}DA+b$W$OEyW+#a`acP3w4eQm}dUg0%)4*PV)xg~c6(mc%!rtn;Yk#a%eYgW>C3v^D26`}td=5_1 zHwyWwz;{6OHRMSaAI2MJ;P;7@5X@CgyTsy4O{ik51%hSz6FuHJW}JJjV6)@>ILEU+ znoWd=D-cD3-HFntdK0h`tn0esD7dgG4Yfi$0?ed2B=O`Nm`v7YK_h;~;`Co^{&kY( z9TNMEQnJ#qJESBy<8t}?t^iPCS4!YL_a#*}b<=rgyc9w=(W%Q?MrL*VG~j(9fnNM> zf2Qhpv(dyRy{4LPxs8{MvdM`0QzO}^43``YfrCnf41nSEQ3#7nsh0dBQBbi;mX}C? zjTo2d(dghr3QUCG(k41RHT(Rnkk8oysyMNFAY0ZJs7Rk=04@e)*rHRBso6l2>hq=C zXtVhksC2oH6UqFp7SN#wRyBt5Xek@~M;leFx^$I0Djebh+13h1c$%N)GkT&xhY7YnKo3x$V2y zU-Q!RW0_sL48Xfzo1MZEiC!E?w=)PTess>)(e&n>uSj@+9e?(y)!KR&8Lj>fokm(g zwiX8zMGrrM1KJaE#tN1hV?IKbhAhOIn5*%1u6Rd=alAWTM4(`M;k?{|^H@eEZjO_=k$Jj+Cff;yPo>BQCO9D-eQevhmn-( zCP)X(7l63MS|c(KlnYS`pTv$ZgA(bQW;`lO-h_zINRt?&WI$f9YGJ9~rv+Y;r0i%v zHLzSq%W?%=rd6)s@%wPxrt)Lwbr=%kKGk3N=p?hz~aAei}$5l4o_%glD)u>a=L{Vqy z6y#m?L=%MEitAw8uA&E*|JdPP3A!!*jDlOx+IJ>?FxG%tiH}cX9g~4 zdfVaFU4{J-)NgSsXFsQi)1^x#Q8*SvjUt57eOo_1kW{b>eRT_|Mo-RHBT^MwIgtf9 zxmW^ZPe8)&H3zjBgIX$!CYn5t86j$D8cD3EV==E;kFF8^mgk?S_q!(NWi!D~`67&<1Vgk7J@fm|Xx5dUl zFO=HOns^O$cp*jv3Bu)G-4G^hCmzzhfSx{;r2sW#GfKhmU9PNai)Olr25#n6+6{nG zjlpnBbZukk1pXu<4Nj1o-BaTGD7Ulh>h0j=3>{Ts4O#ZqAGa2DjXc&$2tZE|yI{#FfGVRn3jfgPlvr_-uWxF`wgxtNw1l9#xa%A4Y=YRuA+Vcg+x=YIb| zRL32beUgf2RySbBHFQISD~ZqTYmA+bN2QzN<{w47sA}{3(of}(&_eU!B*S{_w$hYv z0BsMNI@&L7C;6cfW@zT~(D$VdOwpvFtKYm-Fw0(rLb6PFUj!W|%ysB1FLgma66t$2qBsK#s}d*LDfxV z`r5P6O4q~%a2kOVZciYEI?pi3Zr^k{X^RTJtjDJ@Z~E@?JE5P|}Tvy|lDu#FW+oOs2~&o3`G zxJml9TfEtO5oEOWP?b|zh+38{57i73Can4h!vKhT2e|yh1tr^03D2(p?byFgoBpcA z$?tm!{5)~;7YSBl`zi7H6`&paZ@G_u4Yd1KEdS@k=fAcL9@`I?=huUFY=32j`u8nb ze)d%U8?45cFZEv;88|#sF*9^9C1hk`_*dk_Q-ReD0HUO*geU+A2mkil(XsK!2(WQTaM95TX$eWl zDX6Haun6cF=qMS;D5)sFHUb0z0RasOjRFmgLWzxzP5J-)dh7roK>{cNE+9a}0AM5_ z5G0_-9st%;SHHdh|9U<36a@I`6eA)42m}Ne!gi7*XZ)d}4?N zCsAYddAB1QpZIZ)e} ztg6Q)0PNGHPsfk|e1OW}uzq}1Vq!pOUG*@TXZDu%VrripK(mWUEB)d^UX1y5QTJ1w z>EXm!>&mdwFwtbH?8GaFy!z*Ii6RuWcP`-pfscUvSC%Z3O4X+3l%yP%!W1ODG)5kt z6520t@B?#8YXw9MWEVcvII&|batLea}`Fu1_675RAq6jrcI>g#Mwiz9Ei9+wTz zyF{3Wyx46qJTNj^MYg>$VIDCcNaScO3L;b@9q77t`5?28UyJ z--65RH?dps5-jY+8fmpQak)9ivXEc0R)Y&kJ4DAdwGKHW)m5DrL%Rr_OHaW%U)Sy? zNC2)=7#9Ndb6uUNh*j^A>vA6JcPnq4TNLNTR|8E9**TX09az_ZO8OV>Duw&D^OM76 zua4?EghdMH{xRyH!u-Gc5$JL8j~&UMgu~w)@Zaq4*JFp@c7^*BaQNFK>2Cx7f(HHp z4*w_m|7~IOw}F2_1OKp|77`$2q-XeT7AE52Ag18(RI2)!f!^1nyu4pM{8tMzvN5y& zuwwfU^q-UChq;@0$cV~vo&{XLa#uI&Kd*NatijIkYzwXc0zL91KQQB|Ly zHva>!Vay?Y^&(fgR=pGHVOe0(bV2i2(M@d*i0$K>Yl5Zf_oKHNj~a5|-d^t(@9#!! zT1avdD;XZnXv_2b9v`odjyG>r3|($}E%SwoJ7v+lY$5LI(Mb{COP^!jm|g8_b2}KG zRYia3Q;{3ope_;bPa7~LBRFw(DA@!tnrSRh@C#LxHxi0wehwBuHk>e3Y&1bINT!Cr z?-xcgoM2;!bs+}bohWv*u{mHzhN}jC9}@~4Y!(=KA>eHY-4(Mf$x#h^LsD02v+oBJ z|NUJ=+0(o4m;1B#v;*%c9O?9$1tq*f@^kc?BFcrL5rXWfMbYmyJ8w2K-v+)2r#5ZQ!LPppFi$dOocjGSZ+-4{4K9h+G?71{jnW z&MG@;^v&+T);@w35P_ZB&fO+bHW4SOid==Sv)%~-wVkD>o=&5SN z*av6{}5FFmV}dtybl)zlW-tSJ-w%O=ul)D ztwj9@aaEP*!~kIB=701Ni2m#00aijzGl$=Lh^i_irb$#7+}WI7%k7_f{4@l#>rY+0 zyp-}CTELDDuLWL$j-sK2E*+u0ED*_9l^{Tvf6viN`!YbXfWPpIY>+p*8`JMM9_nle(fSKO~ThkpbqS& z&JcC!WHiW_zTSA_MmFMiABFQ``gl6Bi|}UTaUv1UdhJtsjw#zKPSdS+=J)L_mwevL zE6RyF+Mnp(d5Z)#=s00Od?r}ehn=_TxNOlKx@;F`Yd(j>b-(wzN=GbO#UK%Gbgg6@%5x3;V2Q&_1tE- z156Y}**Bv*Ui&ypG$n<8IfCjb*cTP)nmch_5ed04(Y!m!gkATvVJ{tmG=eSsL~A8! z=WXF4PsxhbK82GV38m?6*cT~kn&D?I-x%DB(Ll3AcR|F_nP>a$G~R@@{xj888&<~Jf}oF!E7abIzNd`CeM$R&WTPSqom=3}HkG259wb#Yel zKxhJzrdz+L0-jgmed|s^QZ=&$n7=>24^O1Lo z#L71onN_k+B(nAe03?|X4AEe-sxmf=U&S*-bDMz+1vM-E61LeP(l|$GfPbo80$~dl z%$)89ca^KDP}mI?{^movtxA)xgni;*e7W-w_4`a2!?PSkyxTsgSIhmnGxu-H;ZJK= zni0xZGLK2h_Br@2gE+4dz?b&;F{NKZ#OBXJ=fq$>L?eYFP44lAPtu7}Qh{M-;UDqd z%gG$a5m_RaLK;hTb|rI!WK_Y@14A1jxd(MnmQGGaV1DeQ`&c<^H_GA;#iFw4QVxZs z!4aQwB^kG}H`uf_bU(41s_5(h@V^Z*i=46-rH{ezc`PVOAmAdi16r+$Mn2j6?VI@_9Hjj+4Mgz}-M#QDhcCbRss(ZspL-sgH zF2y)oP(_!>O@T%deFGU^^pg3KyzU;@4hQAS0UcI}2qhOaWRN*7UXc4?=5@SYs zKHOiO0_Sisc%8PBXD?lPfVty3n7yKOet8jHhu0L()V;d*yiwo1IkK{T%VLIL=K~j} zY0kMW15bunvNB9Kxc-8WF^P;z&cR7#MZ*CkmHU|J(-@V19ixJ$F|zGSP9EA#Hbd_k z8sD)4$tP1!iiaEJC}Iw3mol+?s{X+two~kC>}I#tXk-1Z`ivWe+O!x9i3yAti<#v` zKB_Cv&`ms8z@qmVgh6>2xg^wugJopAlD&#pY;GFCB?RYfj72(54vvv*b2E}Pd!H$7 zI*%dzrY>|uWbPrleKaBRsDRrXPa(ZcZVvqnUW&c5MA2AhotbjSrc?{ippX$v_Ze@z zM|Vk_3)ax^GJv@%tp0pgK4&}!;(Z8MV};9547W#KzX|W~OnPD}Dc%>J{bFl>hr`C( z?sT+BmX}l#TMWsW*!`9z3!+8Pif@W-d@DsgQD&?rZS8~ncx2XZNThBOeaxpCo}R?U z4;%v~ih|yjA3fdYR{FsBqSl>7qsqpZ*Es{^<%$*whe~iM zvn1hkp$gZn+gtT;NsWvxs{=Hq(W6Bg8;KT2=z9T~j4s%kvX=vI9ga|h-G`Cs)_J-? zjERWM&S^ zD+yQlc+N>IJj)%;>A~=jWXY(&b{$cA125)dkxYt}a{+w$3W4+17d)aPd>?SG5O1&X z5R=Z`?cF|AdRk>fV@V-}n8d3(OZ2bl*$)&s57@AOhFA4-{|rC!et(Y30fO@qo_VBi z4M=Ezk&7Wm<_Is`L;MqAh{Z8puDcKW9$qp-p)<#aIWlcti515YK7>pWzJw=9de zMg|iZCPWRobltE~Sj*tC?t4473zlMu>nGz;6*L?^DK0d*`Zh0(t3$ppwm=uKkCLqd zla#y=r$ghMBJT{-tv{M$R+S#nPZ*HKV~0!$4|HHnlQ)xAMU4{>Fd=Ah6ps|_yKKz$ zBr9&Dk&$HOqKc5StxhVAVo(Pcp%;!7VH+qi6_#n zZ&aw+p6tb9hRz}1dfV;MWm?Po>+`Vgpyigd<(6mNI$n1!_FQ+jJ6ru}>+7rV-qkU% zw|rin&R6qcD&BW?SM5>k-M#Bp+K+DMu8oa>?GKkXM=i_q&YyT!;Gb!0dO2fGfJ}6@ zMQc9ytWuVDfrp3#W>@(n0XRE*V>J$)>b-L3dVYIyWgSFdwH{8vpA5v%EoQ!=Q84oy z*$sCv%KDi1ZnNC*VtBP7(&JU&$xCj?L*f?pI*e$uZmlFppEPwLLBy=vi)B{ zapU;9RQZb(H#UynqI-YF_J5f$dG;Rxzo4~?1_M0Gr4MTEbC;>Ph8il}THztx)f zxk>*^!{ph2K&!u=;>Ph8il%HF|G6ggzbS5J27f{I+1}9qvHEP@KR2G*Rz?4Z;Opv;E>-%H=rlU4FHY= z_EmEeK$Ux97PdZF5a_H9zA;tR7)&gVos%a|7vg-?=6>JkSLF>1;;Z&Xi}a+t0f7L6 zfq;G2=Dz+m5)mjeBZ?dtDzU&*lT}Q5`gSoVzgOXWnRfca6F`&FrS!z=Wth(^ z1jz#uw%%f3LqjX)pV#Cr9rf8R!VQ{jQ*lMdvK8uX+;(0o&N)U=@Aw|pZ?j_Ma(2mF z#I0&B0XD45@kwIAHT(kS z7=$d%mUeyCzMEZceD1dfCg=FmIXj6Gd078&7#2R*y(t`Z@iC7IYBH zp5TjNKbhbnI0K@o5MA_q#~@l|P_t9~K&yW3-rS#ZP^4 z$|p~1OC|t+XC9D|r!!i=8kTMLJT{j|d`4L|9yC1%0{8ACOofo$>KsNv^O?4~Y{Dn; zjvcCHE?g(S^!rMsXH&yCQY$Oaw_yZ(iWeoT%B#*Vr&vM`q5}%#K=Xh|Q4R1sZe}C4 z3?=LJn5hQo2F0rDNW2I zsYkCEr^xclPsv;&N`T-C5o8$eFc?UA1|Vin&G?FW;40J`bMCOEM=DuQOW|53bfq36 zxXDh%m!MH8qdx+cm#o*+@4HG4a$d%4?DoYqc!SL}HE@hUa*TH+Y%cM?M1pgnXue#I zpwLQjHpN^gi$vWE`6vNLNQn@AC)z@{$&wZ%SieNVNJMvydHnJ8#{LU+>%l=>$U7z5 zIt=4GFwxCjss&`xLwDw>RISYqQbWq`F0`MouW@i|wFq>8I3e%@_B9o<(h91p>JP4! zo)uV!?)R)}jNLTz<=EQr`KxoHSDSq>du;Ztgb_5?US z!|1^}<#Iag9GAK7by&u*up|*l$$v40QYaR?=P2;f0=LR1qM%uz@UkUHBqN^(AFjFw z3ud`qP=}hb6ZCB9`D?MhIx*Dnl)eZQ7ve_Tu)09CjX3GPAhvFEI>*&GKgBZMc<GeoE6hEq&kM%l ztd^EYK3@0nS3xDlixMhisFWMmZf}n38sJ$y?KT^535$hAKlDM=6cX&tegV4h69~;)SFwRpwd4 z_X*x>OXX-y24?pFXVS&rkem+#Q$m0rr)rsVU#+O(OG;FGgEd<3Gb{V>^vzl`T@O2q zRy(k}MT)bkFM;J$*+_jh^Vkoy69{vmzVUh1n*MoIg2?fCkdpH8L{yTp|MoWEC)zK^ z57m1AlXCQJD)6^*^y?`{9Dh<8{5Dw<^GgB1 zQcGbLgx+tcV@EZd#~sG)SkBy7R#^>CPbyuCKTcyELEhb>x7Ql2w%js%sKhtTk2jb+ z-Y8tzh`Q0Oc6>Ww<{-oR-0?H94~( zJqr#~-Bzv&#jPB0+1Q3F9bxS^(j(l*D$S&Gd1v%Ugs0FZzdCvgombg*h)USp#OE#o z*+MM*@ubQh^59Jfp})P$8fY5yxXSzcv(24$lL~8@W(?@H5K{7^AhT)2BvM%PSky;` z`dIzElf|0DWK?=F~{+1Sb&)$hYtZ`M{@hSSiu!a*nAicwel8~hmXy=zJ#bak0a$P zpJwj0H6N#B^lgkkcfKhhRAI| zo~64VrBB<$n|~dF_2qLD5R0YZ)=Z>@;9ks&uIjqc_noZMQRwH>4BChqX)A@1IM$Q? zDv7lY>4Et}3b<&y5uODRy=JDx+`V!Jpp&ttVbc?euAw=7klAFJ66s)xLs7+4SX@qN z+jgsB>+1t}=W0{ZTsVDI4n#k~zS^bLN=dUsTaSXKgc4K+%;5?dCd0uGrlmgt~(+W(rsWhZT*-j`WlaH2ifG4;VU3DP)-xhm=Dd zC+f2@GP;(n58@oYt>t<>W*YXS+WJzWAE<0VQ?$B+ryF;~TW6G2c2PNeSIYH3*U^kl zBvsJ19hA+nP6WC)LwO!I1x1N?rp`)1W_LU`0V|`rq?L~(FEz9H86dVQQg z9;3e#!BBgk91&w<_Z~}WZjmErlAIPRB2GENVnfD$OS*D?58iUmsxqs^4Y#?(a%0St z$u6jVNs9-5b(U?ts_S?Y4+$G=1#>P_aw(mDURXX%CKAYh#RE}M8_!#q~=<>T_a~R*~P|8 zeGqk&CykX1o6h=2iv@PNDZ05|?~WcnfjmWOIX$d`n2{cdRV2*;tvn!3O)F8_AFi0M zzqa5k2}UCNYMRB@G{n_dSi&qt^PNAWn&-D>(P9+U5%ssto_1_lTVT%?9tI^zFasCB zmq7d0%?iS5Gf`@kNMCXylA=nEV2jk4A;l4#TPMmzQj$6|Y=K%rAdA@8DW)cm>X8dv zn_IdS?X4w=w$|1y`|S)x)wi}nC&Tkju)}k7@u{+5&?u7Xw5}-)gGa~j3OPlg^O~oW zlNhd8MB>dTKOjM&mn1J*r+jk##nc6M$l^3hwh&%4tP22RP- z^IVZUnBjG1_VlfXr<8ApN8m0Qqw#nU9AjYb^gR%u=`PG{py4@KYl+N#Sv~{&oYs4M!vL_6S-4-yk!`+23<*SZ`xg*C81@i_yXNs>`I-@ zh)^WW%TDyHNE+H%#kZedJmh0m8zR<_(arYj4W1+qYgOE0-CBAmJX`MR$_&HACh{F} z{GrnWMg6`Np>AB9vsf1(MH^x_{ZiK$F=6qk_yx37TVvb9l2YWtVqk6_#<2o|%;4 zYdDJDt5OPQnq%e+{9Njx1o|R3Mu>rMNhM$?HJWrkOe>#3>Ixf}f-zCpgpE1&rm^{h zLyyX0zf(gF=QQg6tTS=;Q!vCHtP2+DRNuUSOHuPI{2{od$~n^r#sqAsgja>kOr+UL z5uJyjZWM|z>J=3XrG4x=dX+qAfw`NIXy6JgG#A6>4Hem@k&v4+;wgUWq)zz#NVi%3 zL2zhYj>Y)d_}f}LvM&~@?d?+8Kh(Zx4yfY|4RJiv+}q7a#Tg5?*4J6_fl8P~Cz|gG z9S1#rR$z}*F&2qckqmo?`fguV#7g0a;R7eT7_5oID{2l#ZABQ~M5C;oBrd}&RBD|! z0jUPzYNodQLA3ECW{ZbR5{b$PL(?2{Eio+P7KRl&c`9f z0gS^)9iBJVT`MoKr@E`<=LIl=iCJ7))s)@$@3}4O|+9u&Y3@j#q3Uw4sKm zUGEuA?x}xbF+xklf* z9v0Op%QqmrmcV15zv=;Ty?0J#_S>;;XkUL=y1z_29_?=N0`mubjkTr$B3CfOjoeHy zc=ah0-#d^D>;CKlF8bw*-N!A6PGr$5Wz3RZcvV`zOK%`>Kw|Odsy`G3zDZNxXWGA) zczy-pmGd`Y?JvoTV`KlHidp?4sgB>Isy{U8uOPf~eqAsARa*M@RM=lmc;)S|7m|2fcfw)qhBJ1bRw!6#bg&__6T$Z>f%D$lp^PqYDelru0#kmSOO3 zNZCsM-?sf+`bT}TMQWTs^s$^@h3J1gkpGLRj+_kt2XxmzN_7MW1qOK%Na+y)0PrV) z6cqFysg3|3;HOMSkSEm@92JdGK<-I(orEAJVT$QI{ie45Cb#}Gl@R~{eiB%pG9{l* zQh!%lL7@I|`kUH{3`)d^BB19}1%}EbXB+cXw*6hkQl)M_W4<^QIBp@Y zF2wly>xIov*JZ8r=g-H);tg}H8rD6-!b`i59OCSwAAWemB;$pfD$x+yJ(8Yiki7GfzFkdju4jtf{qSWap0nP|}%BW-Ta3RpX0SOO$@A5|x8k$OaBt^{eAVp6R{9 zM*F*VNKJS}E^t((`AWt{``Ud}gVak}f;A7QbG&-(kt3{2Ol zVoEPl;~fmWC*32d)T|zOIm^e^jr~N+oXZEAinj({+_bR>+;dCNf%t`Rsx5r+n9%^O zpd0I`Sy4s1RToLOy-+L&AnUTVB2m87`uH*dmZNx1Lm%ve)mZs^!?sb!{O~rKH_vP- zW#>O)@k!U$TOxu1EK1Z(GthOf_+GyTaDE&D0EmC~^%KR6^9MoYe>Dh%_5Xr1`hy^l zrzCL*kgqw}+`k2Z0E2@;!u;k!z6F7NO}r*zgg|+U*U&?Iav?tKg7S_}iPN3vBxG#% z4!+sd-IL#Z(^G86Q?B(7FOaX!><8Zj3V4bH`F{SNkstynPZ`}=V5qjlF`e&EfA5=e z^QevTSE-L|jN#g{FOnh=eY)4|HyE{SU^=wBcENpjv4Mp09GE9ZjNeF8x#iD|PQ2$y z%0%@t;{+uLP*!E(x{{a=9$z6Axlje$m27B;s3Z*_FaFjy4NldP7# zCXifOVSy>ElYC>+vRppWD{~cxHFkqC&T$3o`bCkWS-7R(NX7Y>ajWkQP4#x?>-n-Z zxiQ9-+mGB7ev0L+H_q%f&W`J>9`;?s^37a4*kW!tQ;V}~3B87|w+5AEeO(QAK{AxP zCW_t^c_LZ2btZCA#TqiM^LN!BZn&QDVaI{=>e00;PBjlW<8Exd*Dq38dMPzNbGGsd zQV`1!jQh3#(!%xngq!-avTtaioo3xDbIog{G?KS`J8j z-R?D?!p_Ti=8zK%3XWc`KVzhuw84vRYYEe6RR<~TZVI$9CLR60-?1%Nw7$k9iiU1H>S40EL zYb}aYmM{w3i#g_$luv*P(IUtqy460(2QbG0dGeF=lbkPWZWb&YPaP()nJoW*?Y(1= zWnsE3T((_Zwr$(CZQHi3E*o8TRhMm}%eIX!-kLLW?(Oq^Gjq?6`{PW+>{zj5?bukz z9q(Fi=9BrXpYAie8yh3;LfnAWAot^9tLiwzEm&+Jdk_e@x0a@sMn)A2S61YBJ00l| z6#!zYX6uqs3=GiQ-)0V7$5h)=Ovf@s-l(?M@sVqjoIq6T07B7{+#(eF5N5X?T}*eC z=UbU!=oV@HdQ@&72TjBzC~8P9Gls$0Y)SR$u&7+Y>Tl6|u08##0stbm8Q-2 z$Rr!Og+G0e;>;B-?LJ`DCxZ7zmx+bWVitk<$#`wW82wdDBYS15-Joiu}qq?0#=QizEvYXU zv@C}#z&F<>w5d8Ah;i-O(%qjSYRM6TyaC*_TvVDBOOD}=dYBzy1IChwVf$FV7Cl5gDz9Va zjHi(+X;8P0$0ffB;6EdAxc^oHNw~OvsYywAkWuQ08RHx z@(rijO{;>mB>-M(s9wAA)r}OxMYiZCnfbaz?@<2;d8~_2x$UpDirGc0`X);$3jzz9 zjn~nA4;aHV+9d#iW12PsW;t)W=vk+j<#IBdt-iuy3UTcW#pHZQNyT6i3Q2_IVsgR% z&&z*w@%keW@}G&t|1kmizsiUI7K{JKiNzd$sQmvF;6Fs=f9wtZH^Be%0RF=i@J|8$ zqw@UU01v{sfI=mvT1wn0)GR&s4mboTr;u4%loPH0&ja|6BJ=-lxd$`-A9UA0Mw^k9 zh5gTRk1RDSJM9+4cV9nHzEu(DG`m}%(11lr$$8drU^|37K}7bsRRx18Ym4mW&o1wY zc%jYqMC-2xSED-<_PAzneDGNgrXj|*iRZp-Z)1=BM+Oh?T2s8-Fcnc+Q&X3rx&5Eh za*>foQDf9E9thNtp<9IqLk#(gWu#=wix;(?cbE3d8&@lfz*?O<=R1~oD&b{>xNSJe zm>c^mkZZSK2tepAtGl&vY%d?_KAYax z>~XDauDZ0}Z^lcvn%h5dr)uor&WG8u(NFj^Q%7$_MaQ`_QYE7$DNL)rRXJIE@pSBJ zb4)#0Jl}A8dvw0L!OWSvbi~5TZunsk#@?{Kv%VL{e*3decrB6+`xO)j~Vt7O>Lzy5ci;F`@pTyn)OtNTycQa zsmey3Vf2QwvhY%*E`}7hb4;jk0$0zs|L!W=HJmCTOeroGnXq-PT6HE7 z;U+txZdR&9Xq-~fBiKSp)IK0QM&4oj&B7pBMq_>*yM}^1AvBv%GGk|M zB^HqsG-DN$SNd+TKZkDS6f2tyr9#DgVXql7$|JQfz6uTmtv9w1;}hB67OXGZgdE8# zp-J}DlBRQcHm|$Nc4n&p@<(9f+47tZ1S#4^6dCj{2mXcThh1S5dc;gtVRe|{kZJrx z%b7!|@cDH~!pq^S%r~|iP8c*dz#ypC$n zLPbBl0>^)Z)u4N+kHGX#3#y8|lw-}5fuFS!cSR3~TFL;3&npWqATwKnB2KRpjWb1-^=VpL^Oke&;rbE31*LRq;$SXK8*|diQP^^VbhhcR#B_6tY9d4OjUG91(X(6%oD)-5 zhv^aWECn-3s>HBq(I)<3WGVjL>bv@}Q+&EWtQhI%cN-+On96x14ZVOl_g$(0+HQ5b zUP+s)Sepo1PRorfrKltXtsWP)oOx0x8JugX;{e;*is3DYZ=A|YVC3^dDY4uPKC=KN zPbu0tay|VXlR>?tGmC8jqjmC!-`;f9)G6?DWKFwoen$v*OXUSfCoB5po)HqR>hXRhT8(3Rj zOm(-btY=f&>}rNmFC}7ATPCqa1S5|T(Um^zJ&zMkBV#^6l0Ns`Ne^X{Rztzuhqr^j zOsE1uR94OrsXY2KN*2RuHe*G;)ZURNmpS=&hu5V3z`#q;?1 zte*7CO~DpEz1FPMXQmwJ;sEE^91_;Z$D_grf?vByUdoi$&JKM`LiYe8iuGxFIK^bb zH=dmBd~WQK6bska&x%rANtzLJ6g^C?eFI%S@l0Z~?}C7i94pa}<%lOl!!U~++SbuU z++mQ|_F>>8!B5vlCFA9QjRr)ndm8ugt@zrZQ`6qBuJdU z4KMld%5vnYv;_8Mz|5c{9s?e!NFgacHcMLxpaVgS>$%m$W$5&41$*R$p*xdz#gNC_ zY0S*}Is+pnR1Qeyt-HN*Tw`$s_lG%%?=3<;`BBM3S4N*0)F`Yk}{w`#kW^R z&=EJQaDDXs)9Srx3RWLh93T?&p~1p=a@$i<_^$R@!(3hEd`XM9z|O#5;+BW|hNDz9 zX}KcRi6c3bh z6NBQh;1^|djDMK?Uh)uc6f6(GsHTnxCzYre*5P2W5Jj1cBq&KsN5m0yS<=r#sXClj z(yA=jmH&Y>)xtkAcQW>LCc||a{XK|HstMW71x%mz`o_J8U%t!(i2yOOly?1$%}>`<<9+nf&PN1#WB;=MTU&}xDI>4`E2%bCT4wsO%T_u@EN+B^1Z zl4JELwXHWbR%z3ogZH4!(uAHGRsAzgu;Wi7HW}fhO7*~zba;z!93LaWL&*sa6ltbf z1uDdh7k5SfSfEpmRz)8r)Q-4rq@--YSQG@a4KOlWc1<8qM~I^`YDu~}@kX{O7w6zvp>@<*@ zlzRY8`O9Od@g>phPGFcxIah%gLQ91h=Nfipa5$TksLW@p81up`C;PN zQFSe42g0-~jja8|0x{%rb|hfQ`U`~`F8p>k`m*~>wGkXdN~`dlc_uUvAY>KjYpINc zQ@k@UdM(l?MrK2|_f9}dK;|e{pjhmT6D~)D_fYYgSXFMtD-sC(=k48SdwxiLw>tn0 zB{5n!heWd~crJf4Z>nIksv}X~Q=pV)JeKjw3F4{)bJ5W_DS3- znr>`*dd2|Aj=upCjcjCTg6zbXWXZA%TYUMjzx&u&4CwT1T3x?@Z-3tj=zKnzx1Ij@ z`Fd~hbYnXGkxXQEMz_QkmR8ZC=gaqYH6L5`(dOmW*=|;0^YVDO5tjMh-aomK)9LHu z*=*2%M1V$S7RWJ5NS9GE3Nc!3D+I<1Q*pIL`M6`CuCq?*>dN-Uo%M+!i*s{?*UsmL zx3bl3#CKjZWalXOBG1Mf+`Bs5IVqfFTqUzrzG-U zApIApmtdy#-%Fw_6PjF0$_w9J2;?#(SV4%J7G&~c?Up&+nV{h##`>jOc}nwlU4 zG!VX>SV6QC=iC^gz(cCDl&~1U(ED>(6|4D1^nyS_HTgy1p)qpzWt{F|G^gi zW8&}MJpTVQnwOd3561RyG_Rbz3_io(&vm7S0V_A7+Wo=w(&|TRQSsUeOd#pt5p(M(9?V3JHv&Mp|S{~qWb`b6Vk_M2~;`)tDL za_;2#JDtF1ThcbkrIP-I@bUu}xx>?4ws5;#zc@D8$zZ}+VjuE6ax!AXSYzdWB{!hj zAwX&;U@D2(7)pI5j7R~aNXJ0P~=_?$AX?o;M{W`Slo6LgK8at^&C z^dn>jKOiRhG&EFmAzE#t<8(_Cmp({3Ou$dY9+98%g3+gV$Gx01BuxLCPi*?aBs z4*FEJ_Xb^m-_5^o6&9O8o%C{i?$jio-^C9LBaFW@nj`y|FXcijQ($xtNc&8xV;Dx- zTmZ2dK2GT8K;Q!j+Ey+=OjAJ3yctkJ%5M1)p-}|ZBuP>@>>2B- z=K2$3WGqE24Nqe+1gK-iH?b@KHU0C(tYehY5~v;J2LVWk|KXv3U02dO8!CE}_#JIf zUjnprpu7O~OZErvP8;&J^pPSy`n`H- zTIKN7kaR?X28%(y@1u0q4_G62bM%URPgo>H1K6PgoTX3>>l}#Yln$@A2>x89v^YTT z^Q4#vz!sd-^J*^XEZN9=nzNf5uDq`s2c>NwZydgie!QL%zHaplPD|2xiF#qG%x@%Z zCT(^tWP`ois>R#c!a@{iC5uy7y8oPeg5s4?m{gc#*u3uC$gN#o=yi?O)_xHQkS%COVAw-=JFvvqPhU=IUpAjbsuZ>f#TtpW1 z2ddN00Y*V0BG?+qKZ4j@hBr8IBmjjKl0O+i)b`5`48__%&Zd)la?Ey#=?vm^L)95S zU2Zek(d!z{Qz=3XP`)npZOfas-N|r_tx$cn9+8zCGi72M_GO66-*b6-u6Vj`*2}v= zS8&TzUh!gk`UdO^ZwEOzDQlDCm->2H~j10;@Oottx`U}|g{?8cD(+elT;ln!baxZ_Pc1D-nIN4P6C^3|(Lg)neP z&a`-*yMoAYZ|rT#7g4;MHiI z9KpPEwMz6xD$~(gFp)Ifcqx!ZP5WNw;uIaXuYFFSB11}LF;-?nVQox&G-fBYM2u~7 z)uBAA^`0Yzw^VkS4TG*e?jxe^ikt3#o3i09si3rt4DI%4Sl2%a!RkcMA( z>ytQ>82X9r@Zt5x#T6O12+0IGBb|dGieG0aA}7IdDAlB zmlvTgx_MEkPcbUEH@^8PPCybm;hQ`?6xba6ewtr-nWX`q{OFBBMzM5HE*^*M>%M`7z3olz5+R0YwJdpE5Cmx zq}*qckD9MEH`Y6g=Fb$D*q`nfJS6Zkp-*&+%yK64LD<3f6t20y(le_IZ%6+UcgmnW z)I(yt-R70vdj_(!1yuO3=;I{_b~+e=br`t{;d{=qG@UpVTEtpG zzE*z8dpg|v^%%HriH3tZhnI;r4I+Hcb9j6Kv{%a|nCFlW6Baw{rYU!*E`&CSmdnGu{;5O8fuc3Ir)12pJvjdpboz8Rr4(z z%Mc4s?&;Pmwc*-ChKuD%u}GD$x}OmZ3fDc5-Fi}sEIuApDPA7aYRwevGdg)ybvK+F z6x35{*YuL?jTDwaau|)M5SX<(CG}@9<8#7;&BYj}Y`=HwjYidwIEaOIV@Bo)#y-G5 z-*%%qvcPaz_Dt2Z2e;I@hPX_3@a^i$S4T= zD4NwK-zJ1B9;`;O!5-?U8ut9?m28~mABsNC*o-*jY>d+#QhY{o!rCob?zq5ijh$U54l{#B=mq(+`hV* zknEwP?rX{Xz6V3(0&s*TH$(GOCgnQp{3`SW63U(QEryk7m}{3#7pV3w3wh9oDP{o7b^ zu}-xr^iNd0B~5jDPXg#BxlHxUF{3?T*&MhINiPOnH;yxFV&XNH-Krus&XC_D;S-!$ zm=SK8sUjOW7B|80IvaKDb5T2LjAGi8iWIR)d#z&e1xzQaQd-xk)G~9UE|78Zk!Q@1 z?bz;s;t@BFg?IbE9i!9Ma*U=}Uj^H&AWov@oDAy=9S_`v4%6>eohAXFv5!3F8NkDx z9-|0fwa$Er6R@j$ZATELM*F=~ew^SLQ`n2A>RPy6y51SYea14@OhCKS+cMb~dyz=HJn05q%J!;H`f#N+>kU$L^2Fgn^ zN(dpS->sB9y`-~1ei<|r206A!2z!YTFzqAWA}!PQ?Jsg3j=RNA3~M2oYub4U)s?6L zyWRNlGpXs*U$Pi}Z-sFLzkOC97;DoP{E+Pxhvx8{Q%RE^o>~p)? zMab7*!t(vc2$}f)3V%AAvylYq9o3?&FzB{!6UeJ--f%7c4-M{;gZu0{)xItW>#$k3_x?x-QK#Aa4~ z4ART@-b}~LyDFHRka-}v0(sf5wcG@ds?r0UkgrFRp+#>p3v*qZ8HY2)P>``J^)SHG zX7>$h9P@(U#Bkd(883;V}r@?=S@#!wWR+D>ie5-{frOX}C9pCuTfuI?BNZUb(|`w_)_vKZ32B}2j*qt^o)MXpq54k1o z8#pP0z??=SuFd*(fLDgbb*PG;UE7-mi=HE{NWLyZWgQoTu0dy9?&cMC_KW9d&c+Tw zPT)Q|h(Kj?joYTN_ud1Wwyf2~HyZM$CQYORD~bp_7hlW4%E3ad9!p_Xdz{tYE!K*{}7tA>=P$kD zZ-!k9Pm?d(Au}V#-+KEgnwZk5X))k4;WO&|pXs~#=6NQxv&v%n@N}04SzbN}Wn7t& z$AU630tG=GOEfBll-5b0A|8!$Ni#iKn1ZmGbzQYatn$o3!(wV=+^S~XYO#tyRXz=a zvpXb|`d~SNG$?1j2rkgm{rY?NQkKjk&ry!klZ0(w?%U#?f z6=@|f9%n7}ETK~8RwBhwZunr;&_!xYa!Oz=?rYLOTuI|mW0l5PR#r1hRUhI|WvJ2( zb&j~V^*PVkF~bmV^Y1eOIO{Vinl`heofT;McRDz1BfpccxoyZ%i+D&xX?w`Hn)uFd z6Ysdtm5kqEG3bI-tPH)(m5dj+YkkWYPDc9fmTs7PwJd1)!Y?v$lsN? z8mge-(uN?l5>J(YtXQa-=={&ogl~+&-3q~a0oO|ivLdGrB;(8wcv6r_Jj9y}sZ#NG z3L-vW!BVI@(hzCneGxr(xGWB!_m^t-hy3oPgjvu#7Z-vnsGx0z!veRrN%hDvx#wuC znJ*)6V*V9r2Z+;ZmoNVU)`S_KoSli7qZ8+{N4D+%pa?Q64W;hYV?kD*@ zEF8XzoLLATW0b*bLL-V<;ygP=S>8s;zRkEijPMi&AVS_HNSKNeua%$oHottqJCho; zA`GqhXFPtOszxSIPD|^kzb4+TnCGdwhUzxNuR>>OQe$5F?8;0}4YyHDx)Br3P$ z!midhq3seTA5&-$2B7CwbvzIFnU`RCDX6Iid=HC%Axu4c!?GoSV%-`&kw(YDS1yej zQ2c5p0v_MG{TMvs%aP+chsY#pQhuxmK_(vZS~6y~^&2)g2;W+?wG;8uIoCeqJI`R1 z?-kAm>TUe4L48e_-`477?{7b<$Xgi4W7J{Zhi8(#SpJb^>vLJszdX2z0!H1my_9pnblgYAsnqmPec#Ww(O z=*4p^;wQ!`LLukLLxh;Qn`Pre1mcIs%co&eE`UP(=f3~#2%rwo$Lu11n;<~JK60Oa z9H(>BoO@Api5yy?xPDU4(=lqjeVs%BD+XnnO#kDgZSF#zb>(S$#E&vU+oi^q zN32hz$!sEp19=9|I=vVWE_{*8ziSVr^|#sPKFJA-pOBy8C}JI6ZGLPz>b35L3aGXD z!Ol8Xtc~Sa8N7sXkA7|87>%yr?B=qYfAjwiBAAQc)D+!!Z8qCYwn6G zak)<6PV3SrI%a^iV5VQv>E%hmBwKlF6XnuG$s^Vaxxwh?kir4_&d$#=Ju}M(m@WX@ z+(WI#hH~u?wbDiSs2ZcMXb`)o5FHH*qn#C)uV07jkm%6;hAF*(D0`jWJd+j=y$hyAmCBRCr{VxOo#3%#(#1hu!-WXu=BbSYpd{{RMeZhJ^AFp

      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 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2022-10-Checkpoints.pdf b/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2022-10-Checkpoints.pdf deleted file mode 100644 index 7e0d08387ad3be0a3e74201566eca3167aead1c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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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 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2022-10-ERC4626.pdf b/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2022-10-ERC4626.pdf deleted file mode 100644 index 154fe75212e317a87cfa249b9101a04e789281bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 204184 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 P3ADOAJw3B!^LYOO&o2YP diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2023-05-v4.9.pdf b/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2023-05-v4.9.pdf deleted file mode 100644 index 21cd7f59307483e93957a3b2c94aa11c0efe40ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 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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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

      >u|qF z&JT-u>?G2{ZOCkxbbq-T2qk?>3Z4s7*;<>nFMDNIs-W~JzOO)`sj0N z?^Z?$72pitwfM5NO*-{`t-{G$Ze*_#{~CVP9$FCVA}%)i)cxaQKP4O6+v+oGSnKK2 z#eF{-17$(wnpCn{L$I9w*5EWYzIZIB$nl5MZ>N$fCY2i&>NLY-KYe;DadU#@k6d*z z4VBjPpdglH8ua-!^wel#Ajy`=X_LE&Z+*=NKRyPrQ6e35y3)$9=RpkwwP%0z# z2jN(ys@&^LD|qwOcM5d|5Be%R4qM2~zDL+dX!Yt&JfHMxVl^Ddqj9y3s<*TEYmP|F z%zYz~3(vqaT1m`npA&S^?7P@&ZRe=O(d=l>y=zT_najNWHXnFvW`T~#3lFPWIj@jR z_P4wZzP9}9=jx7U_&nWinrq`A-9>}gr2{T~cu3=49xxYTwkC&80AGMT#*l8K!%0^- ze9!U7j-ebXP2dGSAKq_JpF1ZcH5w@T5&9MPUd>x6n#oNGoz#lc+Q&z8n|idI*?^D8 z-hcKVui$(!>!~(Ux-t^uA;n9mY^sjxKApJc95EwebcbiD_{O7kST(~Tcs0Q?0K81H zwz(wD0uTEMfa9zl^toJ=A$)N}igsgk{{l<-`fqz>4c-^egPq@Y4v&y)<;1@bRMx%F2mE6ReSr+mTBiy*FcBe$!f`OiD8aU83P$GvV%}4 z$4HRy(Q$5!HL7QxpDx3Xf$pj>B6oskJaQETGVRgkWmp*7^Ng`_1Ikjx{{?sgo-?u3 zaMZ-x1PPdNy%DfM&s1%D_2<0~)!Bzk@M|G}R?NvVrF}L&p)>JPKvh4>OeD#APb)_q!y7&;)5^7ANK6A)ISbw9D$O>3iNW-vy z4)7l&sW@|haY7S%Lrs}M5sRkAkU+SL!>mL7%3`W&5;Z_N5t?c~t&`iLz2RLT+2W)O zP`e-K1_G};ij0zMP_hATf~*K=8?lW{TAK0)37t?jE)cS|Ns>Z*_ zbW%5x%f!(+Z8$9xc7mq07{n=tl^x5%qmfu3TV24Q*iSo3W0P)aLX<@!1#U1IR`^i_ zJ31N<+iQt(iAW?n9GA;crKU{0Od)CWLp7Wdxs}JcE1*8OcT+&F05TzKt&C)UJgE1qVc~Qo$0>k4tK0Pv47_ zhnCv~Ini}4__ApOrFqZxiws%maWg?@OQMJB)VIIc6JZAJ=1*MMlL~_H@qcLt#1J3c zR-^NgWTFiwlk1+-u%gbVScNQWEMrW@GQdG|G6=}OFlrZ$&MMx~sSl0_vIB*izDZna z6=d?hzOpha9)R`iNjQL9B-mG4;w}IW1IGHs^bjbabpag+9<#FtGszqy!V)vFHaLRsL>oWFMgOfv#3eA)7ETtZO;URBoG+PaMdO z6X+hVu3IE{Y7Qs5aY2~EekkU^H^6@zRUx?hY<$ng{kAWy5;)Jd$0$scCN@Xy|{ zy9I;)c=d|2>~kkeemD-pzgl|kdb782)6cp^bD?!}3Ks<4cX+n%cQFdx0Zcl&@5b(& z`|qR$Tzg{u-A@bn%VGR4#GmhN8+LEE&CA-Feby=!J?P2JR_~`(f~+5THSc9MX+6C= z74OKij>qg;KQv-29)ZVg%`b2?+#>z4-Mp>w3}s;abF2Mqg$&=ZOtW zVN?EfuEdzBsW_`%S7}zJUxtkXM@QYfkTn1BbG~?;@8+g_YyfIWWtX4ld*p0t(#0SI zV_)}8bET>6nMBGc-%nfhjyx+cF51a#YjutX(z3&#Md7EZRj-TgUeLrts zr?rn-1uKcK#jG=y&2xxZL2{w|Q`#teVlYTU~c;zeaokDTl7 z-L5p_#y(Df@Z#t0UeDhncn-tV_x)OSBs~9oxxfB;xtC9rckKJF0MP4ZN!Q-Ef=R0# z-$gp&ndk1-jx~NA*t2IP68n;4Oqey+{P^r=u{w81ekCAx&#!ccchCX*uTJ8ihL6L8o!t9o>Ko3?G~lGs@CJzbbS0vGu%8SxwlY{fcGVeL*p2d z_(nvnlkyqAJ#T{XYV}apv5mHGNwCXfn{DtbcxomZL^s7Oa2q^=^L>1_!$qEcFE)Ge z4#xvpAfk~15D{HbYU}-J?82JQD0j>ub7E}IZ)JXYghHGYjozAqaD&TT8ZV#Kfp?1j zr8b?Yn;OWnOuj*X0vZA#O6uN#)>MM+R0yeXMS0ad$)h5*#E|`-fV( zsilt6GLZDlYja*e+O^syd|$*Y@lzQhfe9-BYds zoUq;dr(0w&n(u`s_}8jF%aDYD0ScV`6B1nsx=}7fpBQFw1I0^hcJjTpTH0g$xVzaw ze8KQZs_0KGyA%puwTcnh#rY>AlP+p%f$52cQ=1{hVm-_O6i12lI?8n=?>TFHHgGvx zCna~56d5PZS=zBJ?&{$LwGwDbvLk2dgtsn(k&bl=7Gd(}UZ>S2ytV$Y90Z&MuT7Pf zJm@Fc3@50^2DSc_t5EM0)+3NkkFZT~u@y;v%e1Z~lita5e;Mx9+Vu>R>Gvh0bziy} z$BUqY7E!u%CubPF4?v$azJ!!^l#;=`x^rKKX-A?}gb*vdgC#`GL2aS+rsdX>Y7TTR zvwyrRY?bI;r}4rj9vb~ndBzw3^s?9(p*9qFk7g8`tvpw90yn^p3^Z4=ys=8%GN!qpE%WVXbtxUhT{;q4P=UR!OZHJDXy zqPTGN{QR1$rNOsHJ#@pFkL~_qh%}?7eB=BPDebKQU7p)DO?C5c+Lo8+fH!Mjg4MUp z6{tyiE$;etuDovmLbo{FQ7Rs5_ zcKN3H!tl&#L`m&Xo99_2|JZ--h@QR$7D? zhk>F^mP3P$r7F=3@V{#wsBqmiKV7GMG8{t-E0c?aG}L*{LpZs|{=NN9+Yn_Zvyh>h#d-F=CQ*hRiSC~$98f&v^l)MqNnE+0SrBAO^2bKw_^ z%B}yL;gJ7e-;cckG;>xi*()axlD=^T<^UdY);<#VgKS^4XOkGVgH5S|6%`# zf9zkoj6dcx?->@WF{$X;3$!PeYmF(uywCx9%Y z%ce`o9UNok$IcB$4ANrxNnw!&agHT{e^FY7RESU55Q50{Db3xL;a9^0|KypOm2k@- zQIW{}Aw-ISmOKZD35@M zP}-o6&3q7*b0$RO5~p`VH2y??AonDFEtmL9uZ=K8an=ODTS(Imo?0f%RRuf1$*b-? zMMl1y$K~Dz{sm z4wCrMaL_tQf~jsJI)#2He(rcQB&aTYK}td}QjFphqSP6HoS<;&&cHY-t~ts?Z1Lz8 zo%j+)>J!krGB0|X>RpdZ3J%CL{n`?OU?C|TF{(cFd^CpOUY-cKq@D<^-h^$aHuFFD zX6!Bo!b7HYFl5U=b(@rCU|1}m^@v1nV47;7^$FnQx7%MZ$C^+xI-`V+yRL%@w8`_P z3Winw1VL#4gC%1sVvm0}AMre1g;=YQ6rgdic+x0sV~s_5*VzUpL$}V|N2AcEfrI51 zY+>>W;LMy%1F@Md%c&9ROz`?pldOp%&9hYNgX7~P5Q(Y7@EX$gb%o9H$(5I8OVVZZ!Z zEfg(Wrrlbh|3sw4YSLkjEXTi67^k)7z7_+Eb%Fdc?@Ws5=*+mac1rFGV_<;G+lq8V zm)2wIW*3r+;Pe)yG|V9bqsF>@5epsjLXjQ$fr70AbruVhx2ob`S2gIpzo8|eDF=j4 zFg)m2ca6`H$o2;1xq`~l_ zfR&Abins87*f30eOHVQ%p)j1`Qomxc` z#;cvmKK?Tzm6cCZ$j~?Jw#g$YreVBaiR)0S4 zSm!*>Iox{BRhb)(kqvaYAqYc^W3kfcEq;WP{K3cfBbzvsycCwX(~<*9KN`$Wd~P^M zv_lMC9#kK# z==cUw7(+J`_zP-KMU{S0*iMoOlfcZI!&$GajgMj_XG051PH@s%Ui#(w78~#<%1r*6 zRD?cInDp{0=ha+Rwq!mL;kDKJfvnQhBzjUUE^hhWlpn8;W@TD?Agyp))=wpUHqlEAJ_^Sg;A<8#ktRH+8~(B zH?j8_^orGau3)gGqc$+HMNXPUt}s2Zc;Wi;BWz7HPi z*9$uAmoiAMlUt#&LUn<57D}|!eo=Ulc@g5E{~*yuC#?@ONBSE6m^$ce*xV+(L5_z~`x*x2jym<81!WTR0qyD@@OMV% zibm4mKwXt9@eY?INoA+T>EM`qf;#chhiR6RO8LQMJh~l)-ZvuEw~el`VgnTq36t{! zd^U_nd??IIUDQW)wMpr?DxRH8%%ff0qy5^3bXHX45x@GJ8K5`Moy3umru?|Ou(bQP zKzSTyKB8hA1{YP;q&TKxoTc`kEQ_fznW^I&!`ob@yRlbQDv1RH6G>WCWZW;QzUX8{ zZSO07>olmUrJ%9%-;pv?Z5xMabWUHbeltUF%R-&PtifCjMvZyTLI#+Toq%w12~WX^ zb2yD~b|&EJj=gfpcGt*#!Hxgw(#wMwC~wVXKg!beDNXIElVvD?wnapZj~1* zd@VL&7H{ta($P2CxT(n8+6w#p|dirL}K=h zo{-^%ZPYR|JqK}g3gKkWVja=kg|E&M`*o_rscfl^77tREb5v6?L$&M;unnHr6{ z1p*R)c}N@TcL@ep1`k54;Hj+tj?p>f*CcCL<&U&gC+3GjKv965?w4@o;)1w?VHE0T z=7NJ5ws<0ICMFwYm(ovVnD6&42rX;i zH`;1xlt7SOw0`Uj;um<_*oxV&C@>c^$jcQ@@M#4+@C)g9CD<1g9=!Fe5=@}LT$Vssc`*r9FPESC58YpNj3?j>VET|Iqdy!4;!pwrLON_x!g}!zi4442 z5k*nEbkLT*{W}`tzhip&cW61JW?#wkD??6nG}*_QE@=Fm&HSq%U<^T43E0wx8VRi^ zcCCq|O)O}#P3mO&H|uF4qm5Rrcrtq<(jrkCf2&DJbVe*H&pbDZMK~w!P&Xk*1yH>} zk>z*I_|H7E8I;8lkU%>IyZ3(vwO&Jx1i3=#$wOX4>A`G6ZvP(EMXV00*%Zk%M+X_a zGR#{MmO(iVe~!E#f*6E=(!nS4(jlQk!zXjnq3#i+Fk5 z^N{N`;`rn^2@Ew0$e1Z2R2$trh(ZTPqek1~yCtECfsh>}?i2#;<{wl-sgf z>wWIw+9dXr=&QV-ylS(7yrCB8t)U+#lTQRsKUYb6E%B&Jck+sFrUJacE|NI`XeAK+O zzEio$GS$=bBQ$N|VuzuL=C6jpElK+IRBBJ%)w+Kfe)h~Lb9HCd^AQqH?6DC&UX0D(8q|oQrF|wfLv<<>j%3#% zyw15P3z~-4xK(6dK)VBD_VcbHFLR)C4&?|<4$j56Wj#8bAhljVUmI%mq{SVaR-=SD zNzJgC`5R``*CY#nfvleNal8ZecUnmNhVjMJvOAV7Q2$@f^B6>*TJP)F7SuX{u?H2G z!VaO&|C>Sg$bQnsq8`Z1V-s#RLH0l%;*&Ewc%yW04wV>Qp?7ay;I_&P*puuTr@aqK zMApF&_23#klZe_IQX$gPMiHc=syEWZw~6@r^*QtMs(zr=Gd<82|1K(S$M0FWCx5au zB`7II-4Ka_p|#^~(|XT(AnY?0l}JYcv1M0M!ga^Q+H%SD`C)4uG2x}8c+_J#*W<#kTKl=sW@9#`X^8|S zJ<9vCd)oClBEJw5jvdF$Hf93|ACVBbNoHQT1>?T79r@^NusWZ~68`=aoZLlt>e1zS z)#Mf%HP1nJi+OIkbDL_zM>sa1utOg9Y__mWkYUsD3=6%bg-OngYG~Ckc~4d2je(Fz z#XF8IY#W{eIoNY|Hz{8l%;L4>w|d^Fmmbd9T?r?@GpDl)M%Yo5VCQ>kymfgAcHdU^ z{1XF+z0Bb@?q*R%I>s&d;@49yI>JHIt%<}U(tci&X_itw|qg< zGaQa$rYM-a(i|E{Y6>1-Yv*L0RkMMEJ_vOGSR}Y`@o=47L%*a}I{fJ#)3#fquBT_b z@9!|0nENoGan2NrpROievY2RrJla&RJCDaJ^+!Lu)AxKT|&SGx@Nn>ew*)j*nU5Ybahor`t0&{(&?(d>C$2T@xkv{7zRIB z&ydGd$}38y^%T;go;)a2@nxXy@5fcB6L4c~X@8MpSt(Y>Z0xFi+P29v=BDl_HaRb_ z(ASES*iAv*vDQofKBnVMJ*&tR`Oz{tFmt=iQsW$0cME<-T#ozwQ(a81447`JMRH9w zrppe@U@9*w8}C-&>lH?sH`Gz6-q7f(%=aOT{Q#}|4RTesRpG3Upz8u^hsST!6g&x+%A{TTxE2Wezl#|zCU^n!PXbghb;&|Bd> zbfgB?&7&roim`Vky2&e}L^cB!sv_L^K-XBqvysb}@qa4H&cBoYX*Aq-7@o0U=n_i} zB|BJCf);%fGMVh8^t@`g+u`OkAGzbEGukQjbg3=GC2-tdKPt)^j=juXV(WbNksT(` z0>0Rfu_4FKM(dIIYX1EOSvP>iq$fX?qsvpK%>BdYM!_e3^z?P`d40)|ix2;{;rm%x z`R8m&HJQgk*cUTcR8e-r_;526Hm2@AUE^6;@4MknbG7BRxKdZk@Obmk&txRjXgkF- z;dvx5CAV(g&RuCS!`g*L6#I2rENoTzw7Tth(qWx!#^*aqood6*3Y4lP<@|B%^=RL- zvb9rW$yi_B+V&P;BC~r?WlyU0yngfJv6f1kgAvkOt9F(u%dl^ksl?-p?iM2*ejn@- z3-u;oun_7@%_s_N|M2>@s7bpUC@;0p_amAEAh)ZBWG(+8RWQ+Ax+OWwHM_;D^OP0r zkTQWm%PX2S`x`#R9lB-+L!0o{-+|;>HV-Sjs~LXyrj%s`@uy*37o6v-jGY?$s(t)i zQ?ti)_cHWp9gPxG399LQ4CEjcj2Pk(#Kgba{Ea{R-57;wrnn7m8!OTHdW5w)uX8Dj zY_KmPZ%)@afybZqIxDT6vC+?w`$YMqA*0-EU0Zd&!uDHD>B*w1Y&Mt_!KO#0p>LUZ z!=DIgjC;~3bpwkAxewm)OdPO%Q&=xDJDazwqR`hQ)X48#^5R4_kE1GC_$&QfVSkhDNl9 za;!q115;1ASs=vm8h%P{p8(Xd{`1k6gZn)Jl;^}WZ{yM7<&tpbJ((QMc&RA+Wzi-! z(LMacREWNOr3Dxs352WQBlm@1x!g!=A)edLtT@_QDv!VSE&XqN(t8yjxeBT_UxyZc zgkcx&y2zt*d$8K;_14Siw-D=?i(4>vO_%wiYuYq|eW7Wj@P-ZxW7kQdp$8T`BAxdy zJ1pC84=bH3u6JmY_qQ|N>$k#oh&SHIkRp@nO=^~Sr)hyMU;qDIWb?md&Lo+jUj^XB^ z2fg@n<_orM?N)b3>*z`kubM^%cC*ULVVk|&>%;6xigAcr&P&*Io71k2m(@BROLis}58~P_cks9NeVDZ}D@kVZX-up}ar_8^`;Zq-4>ysuSB=&*1^>*n zr9dscj@GJ&uT|yBi$-*b=WeFwVz@8trK(Lst%WSxDJQF~F6YIJv(!t_2f;az`3dy) zYNtY{J8i~RuSs<+zC4(j@HfD1VSlesu%J9u)E8N7fh!K`<-{=W!&F{BL1x6$CPC_! zstN{8UV%3mKp8eUD@_foye&FiE2$Oy6@BY%mo|OdB)MsRS+V;AG^s0OHM}NZh z3Kwd}RsuPCRS))hzW3g1U^4~Yn=jUP)#kHMZsyxP!HN7mAAGpb*!8I|b)eOUaJm(` zMsRS??!+SBM>FufPv^VR&9r4#_K)>8N)Nf@_ibwqGTH|xzd7HG1VjvO3Sy=j zE*e-f`KW%n?!-0HPM29MKl7d%a!#u3Q~=~!IY{n-*OaQbq&gwq3555@2dUarpq3C{ zDo6Me^es(93d@W!!OQvd`ePM#3#v+A3Y2$YFOAFnkUB-gS7*$@+FaMVktWyn5(#=t9)zM-MZWvd=_JhP0^-CK zM;PFRzt$$I(^efLyjw3^pi9`;LKHp(p+$+n)iE9;m~i0AW7K5#;V=5IISc`bmG)hf z?~##+!vqB_#2Yyd;;}fbl`Q&I^p@tKA*2g+N!VP$)wAc=PdUEhb3;lqHoB>h*TFjd z+b4dS1r%Ut;S?f;)HU%0#d-MP(nQdVYQOg42e+fr+t6WdKvQ-#JN=?pqSS|)1Kp6x z?ZJ<4Sf>i(`zaF&PJTBivY!chQ$#nMh+zq`$463?#gxqAvV`L0jhItb7cDl$x6Ht= ziQCS;J7rAGsXOI-(G_p|)0<+u?t{u53T90Xw1tf{1nOKIj`2jB-SP6o;_s5Xaek-k z?eyHBZH?L9{q>6A-|e}3-YC;ZdXge9j+~P{&3{nwptg`oNhn33+DBErrBIdXV$w;^ z-zWwu;;EofPb9OBgPT+~NOR(&rKnw~TP`#~ht6N$m%M88)dF&^?9?C@oJxfyPD#7{ z22NGF`~{CZ;zl`tVIJ`mrl%q;OhcX_uvx2lZr(zLhX-Z`H$>om(Uh)VSJk8)D4vI~ zFo%FPhk`aYYKh1o^CmjV_&NYx!6iW)ML3s9j$7h9Nln~z+=~}=QwQ{PcI{Ol?gCQo zWye0y#)=M*$Si`CY3)5ll)}QH%9%)vAEqb}#bE&drrN-ZrhbL_V8MT<6z0>WwsN#d zb79X{Fg0hR%Ns17oQ54*RY--`{O$u|-mju{W>jxMI^zE#5PIU6dR?LNd4JbZXxzL|%QSTo7&_4A^d zI<#y{x?#;nh(lc5pWjkm&09Mit?f@`i5V|rr`_X}C7s^duE%Ya7vZ;1IY7u zIJ3XOG6`s*>8YEd?C|SQ(?B>AZ#h8aW}s7AL@NEP^UO3ekgL^-R1N+LS)vvpS}V+C z)*+L)xcKXauyFk*smFeRWpGVWDpI7Vm32@7lYsxN~n6dODs7H+>#!QbJ$aeV| z8s;J#>pf-FhIC3{9HHVGr0+W56FJ^^osl1fki* z4VH^@Lc)OnrGtk^`SmJNiUF1v>xUqKkBo<649Zm~F)#uZ%%`p(@=zQw8#JF+3)bx4 z?f*dbw&WN7fNO_9(04tP(QQi&hxU7&+^_V5tQLg)VrNq)2soe*jUNt_3S~6N-~~(d>q~?H zCB67fU@0Kf{zC$=yGjBIH*f)({vLIt+8)(SI{wT7yaZ4>;548qKlZ^?v3NC+j%kSS z=;*C!{r*O$MInx?g^%Fc5q^=_5liiCind{-<~2H9)7_lYYU^)6N&@l^$|MM;&3~2|k^1eE1|X9F;h_SQ3-ZQ~VA~E-%93Fc$`A=m z1*XQx;$R>dD&l*WBt6bZX_f6^N_N#=o6_ihxP&ZR;9U&yb;f*h5P*3o#EF_kl+Za* z4nYprDXVux(Uod+2;B@PFJ#vg${E*xC&!Tf94P!WVHv*yXRJ;wA3)lcPqrOO#| zoiOX?^`hS%aeVQ~p>{Lnqu+se5%dYeN3&{-!#^BxL*l2SFk|E&lXj!zACkXk>f@ny zBjq2ce9`ogyP5u@J1`9c4VXB85!Ic>21T$wNOeQ*0cO6U_K9h^W7{69zp`!-a#)~W zA9{aqT_1ydfa4zsdui0oBl$$e-mQB@Z6o14;`L0Ayn^uck%K9FkCwg?e`(Y$Vtyq} z-B zs{w8%%fcO`fa`p%2R4r^yi!UJY}&0Qt8;@(=XzB4qnY;P792}80&k%|O+I~o$QdRn z)r79es((8|O&5_LYdq3)t_w%LWo@g6Mox&Ev-kQsmBo9)zMeK|x+b;P={pyCW(%f5 z#jCYH4k8YlBfFBDo0GeTSSPG=dP2o7Z8Vb1J}2K7$$e%mTA#8WC)8toQ5#)a=RLd? zcTX~{nR}qtMrYB+(AK(pjt$;U?u}dk(^DsZKQm5hK4B96 z`Cl*7&}zt?r!ZCLD&==G2AKa9N_qnMv#Lc!*t;zKTB_%_tOu$!QR#8&EZ&=SwH|cW zSYJI>t1AN%6b#nF*l&0%40YdnTEOA!*l?20eSOWa>nCQsEgyz2twk0b^I}clhq5)_y@pp{o&`ZgMxhO zx*ufYVY{$R!oGAzHIDY2)*<#4WSBCX!tKc8x0ii-)23b`<(G51UKh*3_m+`hBU}?o z!*wKV*c<(U8fM;$86%e2SM4GHv~a_ZBL14~l+v0WV!Z^0OMDx8gSr0+>HkZy`TvCU z|9Ml&_}@%l)#d7iviQu$cbd87x&EN*V#>Bkk&=Xo0!q0G2`L2mvw+ZFM#ofCM3Dha zM3e@Sg2<-8@Vd)j2%O3VR75}kATa)Qm2JlU_UYwwn2X|IoTkTE4M}yJ*TZ)${ArWP{uS}cP&`qG6lw8PBQ@Ic?K9XiM2rM-7FYCd1AbB zoL>jAo+^shBQVK&rTC^#(w6zYLsIIcG02=)UpozK%-*Y#UQ#W?zOdTQjuNm95{axu z_{D1a+wYA(CB=bUhS!`S_1%oMI=Qyx#U&tf5=d+Fe6{y)7N2-`?u-LLMZoK1<7+?& z=_R&cj#l~)K(fIX*S*2g!wS+!AW`5`0yogi$k!`ld>iH(d!P598VZ1!B+CcD_~yTp zn~~mvCZjf|clTj1FSa=4|E4LL+{cinRRjUqg4O5?LcCPI!$*!|rqMjYze|IHDripI z83KM=95zUg=uT+^HRK_FS230FosgPh?^hyY{C;7y=t=Gr=Ngb9EW}5|nPTV*K45qRKiv=Lti{pWsTmg! zYznVWdp;9^@(=Fh@f8;B8Q}!q%?Za%(T%{4Ceq8J^``9XK`PO-L(4IqyQ;v2(#z8a zO)GNwHA&l!N$%g}yqPOA!0tKjMsM#dd8t2=glH%4j-$M*p_^ytt5)+qrK1#Rzx5)JR=0!it#4&p|Ws=Qv<=C?#y*k%2Cg&p;>D<_#>m^fed%JPCsxxXp-9-Smo;_y7l^Q)}&NR6YdA`q~}fpK|w6Ge>e#zhr z%!v}IrinuY%;1i^j?9kSjtKVz_mKMrIi|XXTgH6)d`8^{KKd?9zD%L%gh$!}5&|j$ zh5}*&x&jsgvI082U_WVp7J`t0%D|@~F_7nx3qaXHY#`c6_h$dB1X%*Nf^{R>Y4=kH z*@AkZ*opMB1@VDj!L=jUG4JK~|LLF7yV85m3+(;qZRlO=ed~n*3GSWvMGh_pWrdK1 zy@Fi^u8Zwvr0=^k-uwP*8O#P22iA-2Cb_p2q!rW#ZUgT{d8elL(_j3TJQ$;(fgq#c zn4qR0soONZtTc|CpPTrT&9i6`Sz*x{+Xak{sAw!`A;RYdS zp>bg=!kD;7p}{yt!fHbG5FqR+bUJ=PFb%XOmV@P}4&ifX6~ZdYoysT-VQpw9`kmyc zI^p)e%CbB0(Z0BSLNlR2A!4C@;dvoP;Yi_1q1Tyv;Y=ZVI9zlO(G%7D?EKAqrIY@d zbK%tBEu;=AC)tybf2#pzLVEDt)DHtQ)55L6Ul?zmC*3nW!tx;=1407@0}1_119t=C z{eK3|2Iyds`{`gZG1y3}c&%(SY}2q@tXHB9J`Jb`u3)s#pEOny4W>i8(4K5oMhx^q zywRVeS90ol`eTB#TR;K*wDu_~(lN!ON*22`$C_CGgy3|oO`0W|rkXYN51QI3Ln)cG zty)+0Jm&6$d-Xil?qhc)haeMXDYi8H8ZLmZCY%;n&8gtfAn{=G5VN4;;M9=ipygma z#I4_aTwX#i2RE3zj{Tnf$#$+UaJ#KR+nC*4Ue+(eH{|`fFutrG**CHMJ&@mQAICSF zyAb`cA>YVIhz8+d(GuaKF%(f{Vfw^aM07D2n2c=wn2f9i#CvC9U`QT=&PeQ{8)){f zgCIx<;yifuoO?rI>_l6!FD!fKVYo;=q8HH|DE35qR>pS5#>PU%9!0DTBn@11c$`EH zoDM1nFQbz2^TcN2Q;|u;(W9jC6U6EwTiCA(2Ziy0@zY}6zh7MrQbw!e*NJ^2Hc;F7 z?<5Y&Dafd3sK}@|si-RmDtN}x4#PSqq@u8p52G^BoSjwll8~B7&Qi)$70(OVM0rsk z#TFnGb49(8AB7jD%J>W6#oe-^kg_~M0M1m;dG>RR2Rw9-Ac=fMSY`TZTMxR^AKH3 z7w6N{il-rdlsCx|^1IW8biM7c58}J#1$#aJ;8oNo^ON0$!bN*qTw7V&U|UpMXWLv` zMq5W4%pPD*Y(zFJ6NjDHMowEk>-TZYU&5=DHtv13k?QDmjAxOJNPFACF8pVUjb(f8 zJ)g*RY*&gak&V@totM#uB};+UOp} zZhjw=5AWOaJ^V;trmxqR<-P6bZ;r2tm+L*>@NML8^^f|Oc_@FVT_}5~awtwHQmAGq zI4D`DLSz7P2`NzSM0N(bM!t=7cPi)|8BY>J#*J?`ItT%|TjGV!z^wl($Oy^|Ss2*} zdH(nP?+N7gL8Ne@y_G@g-)1B(q)((+;p}8vDQ#5t)_Wy`rO0}cUhKE?gVy2vO?$=wYUe7IT%S>GHb~< zCJXVoYsvS77_w|hc*z(^IoTGnRMN(=WAav#SVfoTFSLD+39P^T>PriI!PTYk4p=Gm9FJ=ayuv=PZv^^ zwq-sE9vc^Im3$>O)8EX_b{Fy&94!bf6fMFnFfH6IiY-_zoGs9cnv0_4GUM1dt;N=| znsQi3C$n9I*Jv$VORD9xGFuog!<&xhbY(rsFAJOK=UR#{CEiJ`)z@+@Am(FAvSqk4 z@zU^8@RIRza}sjWZDi@C=;doAkLR)H=w)o>dPuxw-hv*e=SoXjOQ+>}$h>_z61o{a zJ07s-Q%kpVeAM609-2?F=W``|={^@9T<7?uzKK59A9CkiOYtT6Grr`-1VTuO*@#Jr zxeFNzi2^6hN831zjE7fX&4w4EVxlUU(Tq zg(=mTZdyCu-S$X0J=PT7lrQsD>S#S(i>cMrX8MEDQT^x(NSt2UkXBV!l~#37RaF&G zbw{I>LVR98!)Pg^X1SEC$=uk{aAano8QG9xx|!juzVxYi-pFRcoBSxWbgp@A;+^oQ zy7a8sWBM8I%y90ulzx$S5q9x%(R8tKv3F5n#rOVkQF0;OIAWp~@2%=$=Hl9t)Wz`r zc44yWYFs<6o7hF@N${S2k=nRD{>AWqe__4KZ~C3nMgM+%k+`~*HIsFcRg?wH`p9a? zTFZLNf^iJWns6XHk{Pp@PS2drEIiWAbTpFlof^-2cUU^)Nx3(ky63Dt?99BkpGxK2 zKKw{%BtNdrGU6oRbaaSxpmuEExOc#Iq#x_zX{B`qTvcsYI=nmRv`0GH zPId7<=WIYY;*UKZ@MXU%U1hf8ANZua%U&V0b31+md9%2aJg2Y>qZ`No%vJ77N|w>h zQy%`!LtJZIeO#+t16(6(Mygdd=Wt6}RjvSatz`f^Ah(Xs%zN=I=8^aueaW_(U&~bs zK_eFMJq9z{crbKSd|+~ndZc<#?+)jVejE+N&O8QYW-Q0MI&TH=@LqRxX5QIM{N=v( z?+m@in_ka)Hr&E?zdrWPcy`{3>D<11I>H_2j(26_=iq1JC*9TSIjeJx6av#m!>3 zt)CjYmg<7$f-VUf9ZgrSt?DMGUp3egnjHlmg-`j#VOJ{{AI(R%t@>u9e;ei*^-IUC zVMYrDfTEM6lBAiWr=q5!rK0C#5U=2*IXhTDDS9dD80itYP+%EpLvuzC&~(z9?I;+D z$f5D*K4~s+jpUd{NZ|`QWZU4t!&R)^pgi+l~*WT!sbSM?Q z6;+-(N7YN#Ua!8=&Hi?Bs1^65OG%_?| zIyopwB$*_|IO!lcDPXKHZM?hoL!kscrhtrib%6+~S_(D_UL^kAep) zO*>6vO(9K>^yaFfst%woTR~O3mCEW%gQUs)glXy|b>c)+1F6Zxgj&+3)|0|&p-G_0 zbV`@flgnyKL$%5Jgb&raYD>?B#A>-i2~QPI2~RsuWoKSz=Z4x9MNgSF4ZiXgz{lhj zcvo}xdI)$exGO$vP1#oU@qK-}lRcDA?os&ic=bHYP4ZR!@_wy7^i9I2;n(#kAu1y( zAnGQnCTcBcE2s#l<>)CW-6c;nKFcmZXZK!J~NT{|d>uhr{K3tJ9J6sr#8Ly;9 zS2;^wR^3u@*E-xxMo{6?esw!M8b_zzF7xWSn;);Gc2)UOYj3?%I1C?eRP9rZSA|kN zRb8q`s5qnYTnwu?s!&wjuOw5It$+=$i_PyKWQ3kr@R+)Rx(R@a&rOU#H zT4U>x!en?xV{>0~d^1$@Y4g%r!rB?Y^D=DhXic$s-;#V$t~OhTyH>4+^-t;oU9FCy zr|qS1bLEchDqb_(T26D9q33$bP|IS==2N0|s&&t0*d@wDoq-i> zCeXAV%!<>}2=_wt|D)|Kfa+Shv|$JYNpKR}-QC^Y3GVLhatIRK-QAtQ!5xCT2Pe4e zIS~Bk-goXdcjkR(=9{nTuUfVG*-v*@@2=Xrd$p~u8jdm2S*BfnTlVM8UHB<}s&cD- z%W&)G&fgvmhyVltvH`Kr-<~6$bDoo*gZPIDET$ZVb)hk*ik(_@nKcHk*6wxDJ*YWj z+5_7oPIlY4!*z!Brs#Lhx73|%S`gPD?hx)+?lA6%@3@?+HHg zH4(gfHklE`_&X0p084}RKM(#B zI6Dl(hq91FJ{78i>P3R)ML9)8pD2-fd#Yf~`I$}vv@N-vPvbF> zY|3D6kkUMQYM|Wl>vn~F@GZ-r5Z&_fkr0BR)Nu@pA){@3P7n`$q1sjp`Ch z&syxm2_c6;IL>}e)+qMBRNL}tLwK*XghS@cq&cwRy(fK-4W$0ZOKtz9cO4j8jS#i} zOesR-K=46&zPp6pg6~21r-b-t0y+nd57m?8Qfw={2OW~^ofLE&91*GziN6>`I0TwJ z5r$K)_?iXk-Lf`PU}&A_yzsmz7ZDB-4sixi2C+5~G~5>Pbwk(_9f@G%@D$0vL7P9m z0FHkZ6InM&Qq=%=Lf6OhuVCmPXnM-wWF_|5U)r7e^#$z%f}QwYQq z$sf;j@AxABgwagVTvKmRZ%IgPIgH_OjM`Ao#4asRpR}OAV)W+Py%Rx4$?%7eFzkh+ z!wPs$T4xB|^yZNU=1s}>*u2w6zZAlulL~roRY!z~QPdmAra2A$F~d+8oz61wy?k9B zJO*2DAjQ8X|13fL-wXTSLsZW#2n@WQKqyT|h>u8yy^wTV{_kPy3b;yZ_0CSyIMKtO zJJRv>0QjRF%j?-Z_e36UQw5v{jUFKIElP0LkA;;H`#xVQF6;tt4GV+Pd2+-h>%7&E z*H$&Ntfifb=}YT1)86=Juj~tNtxsC#K@SQZRv?t9qahp;LT>;u7ZWsW$ku;F-ooJh zU38XaxGO8$+p~d$t0-S3d&uz8zCk5A8loY|^#w?CF~P%9{Q8UhN$L0x(e0dHU1yh# zZ}ail2UTPP*3TFOd4@xvmK}+3kxcsoY`NkPL-nABpz!DW1H8GEkYSI13Gw5Vg+hTH z^9Yds2ePhot49bAD+~(C$&d&M;YUCK7ZVCB%=X_%9|WX-2=GTh3fD9mtoF8$ES_aJ z6ur|=6GubJ8YE95Y9z5A0byK@NU)Q?dbshpLZJ>Ew>~3v^chw51n6^3e}wh^CB%q# z80_*}AC}G?0q;#TLu`aNg*ov4y)Nt!kXijk4!v*Hux0-Hd;C$88dRY_-;kY$A$N(p z6rf;0>3)jW5(b6ov_*oX`y(Kd%MlfpVY^5CeQDAYlg+%cz!}>RZ z-vo-jR~#Cw%C?XU9tn4-)Fg3&OW5wehFOQKb}={xI;#Thm1F9%^|HCf z&G(-dYY_yupCi_5=kJrfySFcC5e14Tks&X(ZFHV;0T3J;4wL)M#y2|O@2l(j5y8!| zf5_XdXsbrg6UNUlTHV5n4skcQyH7CO-NKWbMw1TdH#+-IDcs#=|A5aaUfpIJ4(WF~ z`_Cz%kCTt|H-2Lsn=FESNiU;re-rSF`TXO|$@3xD59Hn5`!^8|-OTIXWDMP`?{`@K z)qHxX59VKpnHcqkz}hb(S^ylMGZ*@MOv084qf z1x=9E6ZGD*4k8u+hs?4i48u36)<+_ZM0d`L{=cnVi33{tL*9Oz&&QN6wmdLrHMC0k0M}Vo~Z4q z`O9cv4HgaZAN_hi7P85{KwOwPT-v@-MyQnwp%k>Xon+-%PXp8x5+Cp7>EFRH5)rTe zvA+`RHy)yS$oxO8IVcf)lw-p-q>_{A;eXh^e;Kr)jzVlgzoXcN*+hXta46<3?{P2dilFJJA!TKH z63}dW`bW{~>Y=OXAZcZLM&F(rAdyexdU(+5CZYd>jr)h~`%eUtC*CF3mQ&A;{}5#C zn-$FWPXvJ{-=*hPZ!0ucD#QWWmhQVOS$`LJM+V4A@}B<<$$PnF^3GSzKNjAtC#VwM zksY#zqGtiRB?CeOearftu6!930iS~Z5d0+W2d@cD( z$Q|BqTrGj8qjElhC%C5)R-ga!IN$&x2g(y^i`)Od0ZR}aFk9>pwUC~OJvI>fP?tFV z|4vCsLKl&~n?;2@3iEdr6XGEu!bgpZf%}WjpRqs({1f|MB>p>%V*LJ_CM2=?Kk}kD zzK7O@gwzn~`TQsB#dM7S_d@=j?{8)Q|3v>~X0zVC<3JrJ4{Q}1;>(wPmlZAE( zH)MDt7aywFMA-iN>?+0oa|&JZz)CU4WVjl%UNw>y8ED>cLrTDIOF{C7{Q`46#w^NCVBp{@=+Cl0Xfy%Lq7q)LvQ=PjTql zu&vLieQRL`NQNb#m&5)A`F~aE|5O!}2sjZ`VJZ?hap?RoqED#bNCK6_{#%kt3_3V0 z4+V9NIFMJ&G4yZ;3AMy2izI@Hz7Oa%_+v2xB=QY0FnEi|6OLC5UyT17Q~_iGY5{x! zcES5TSh9>h7(U#~KU%F`7-(D+TPAaK3!3%yY-h0U>nqMe$3#ImUB+-9L?ovcFj{<7 z6Br%LjbUdp!||s=ir${4LW09X;UaRhB>8j5F6Y8D(aQ!qhbMP)$bk$^0LO>o`Hx1N zpu`IlAW7&6aRsscc8opjk5QOA#PXlRF}?5qqFw*9r9bx9fbDo|iy&)})Q=5||6LKN z9~%`DoK;Ekp3F>o0~`JU1C-vzV?^^%`2=v_KSpAZ(6B2J-0?b3Dw+vjT_-XfV zswCuCcBn~rh0FZ``hZI~P2g%a-sA}C$vJy~aY^ef_^an;6H246TON1tJhuI<_3mC5 zIY7odVtD&*N9^bLMMHie0Uw4SB4xqI-JA)AAe_Y&x+6ySq4`y${US_meQ&AlB{gnr z({&e(B|hH(j6=^wZMe|qDyOHKjDd>^t+$}jD0;PS@QT(3qr2Yxe-0?#u0Mf!>dP2l ztkU|Y0B)<7)AkY(*S8;Lv+my@lwhm*6{!u$@B1@=vxd)IRn2mP4o|z8i+vdE#KlQ= zvFq?YrA~Fxc;*s=2l#fY0ly%>7Jv~xv98D8(C*!4s-Y3P#$8(5*$xo!(z(#h1A5$n zMoUi5lgL!l=a!ZkJZ{r@8UuH%QzUJN?g;3*?uY_|FZpdkn0Wm!#58?Bia;YPBmeSe z3hh02biHFZJxv$=DmS&59xi~o-@qfM#A@D--LM|DY(HqrY0{L*ygHF~WMTrzMPCY2HU)643mL@Asfb4gZ9$>eLbXpx* z-qETin9%BklqxM}^JPQ3i*)fMnCq*0hWZ@68{Tl1hT6_4Gkk7`ee%T(0h?4htyPPu z^W$@pNS{T=&Wg94H|^EOIZx* zzr)8?mgi=8BeBw#Hkg|$OB27?<}L^{w9nCiCsP`4yA)1r1L0mzkJC+(M^>w$ZQXq& zOHI$tkKd-khEJSp7Zxft+sSMcYt7Y3YRBJJzVsG1mKWd3H+OTNIz7#tTeh$}Qst>h zUt&o2Z|9T{&AJ1{Mg>g8|@2ay{)A79(^O)p=T zKJgp^+2=FJE$p%uWVLx`$Vako$WDq)Z6EjVZfCUmY~^}vPzw+%A_!Vm`q%!p>uHTbfP+os_?i8-k7~yq5yXR@;h>vV~<#+CsKkiiA z#c^I2tx+6q44!|E8jhXlCLc`uI=1iP3=prWE_!h%>87}5Cg~<$Lf(Cd>9`?{=N)cL z(e;Qw;dFkMJ3b@3HhQp_l=9JFY8=lN>zeq%)STc$8~*Zs<_K$D9%PUvwNGF0Dh7I% zW4VFMhNcL+k6T+6e2t zos$LaA)w#FSxFXNI8;*a-bj$N4;RPFlIL0(?6X1|Wx}Pr?G+?r$3(m5Lm$)?J?~Z! z@Q9ltjMM6jP5aJ_$?_w_OrVuF7QSwNw%Zq74nvm8t5+mN1{z(yP3;FA0s-Nb(kc3P z#-ZxiO_W#5r?<;O(Dy0I;5kdjWtQXPGoAsr+$V#5OA(97&1%p3ZZ)Gi6JJWzOVvs> zEWU6qO+c1krK6Bz0@z2H;?|} z(laVipJ)f9uT%n)sK}*9R3egSilvWKLXxP>q?c7sG|k6w{PzSHxSBXa11M`XTFHu27MRrxN6v9Og^PVN<&7q*lJd7*3~Lxo?#-1 zr$|esluajtbRxN}sIu6m$lfYPtS^tvK${3Goj@iVQ6!U5B+FoxZz^Sfq-_=Nnhn%! z)7K_hCt9bXPqt66Pf3v;E7mFUJ5oR5IC4KivI=%B1*){kw&}DkoeZ7Coz$J=o%EfgowS{los0k?0F_<5K!QMuK)gV*K%ziulZ=6s zfsBE)f$XN#YSGzj^Q_10-7L}(?2+UV<&nh^=8?t`r&TGa9Voj(e-{4|cPsN%=CSB` z7V?PkD9=@jhwhmkKR!lgsAy*v-b#vxIy>PdUP0EPs9~0SgqGFWACC%lq}MqNk0x{k zgIhNyj&zTTTRSG+WRHtmUm*^CkBnPOAzpQljazRrj&+ZYTW2!f1s->I5UZ=W8;rdOqJF(c1${aLM#gxDIESRvQO*(0v9aB~YkKEy-%8(1-*(^74v{WZedFhD?GVayx*6um%+FiTf>)i9+`*?*u1w9o$B|bGgMLtzNWp=2(=xvZ+q}&aE z9roE1+yh+u-TObK`YH*K5vIJR#12dDnOr;Ff8!&|O;Q|r9WLEtz1F(VI#t6W7lQv1 zm}E#U2CvrlDH5$lj4J+Z#k~3l)pwaJv|2K%aG8XJsv@d#nT&)QQ>yg0b9~jiRIL$e zBdXWQ?~0YERU(qnioZ~+jwXL7Rw-AhNX98v|4v=iN8Mqpah&8mkk3YSKz%?ak>iNJ&ry1JtVVW=hAwW zR@qjaR!ObmwaO~>bJcSV0wsbki&V(eHpy=q+s97urSBTmv zO{q?4NS0xiVOC(4V^&66C$3aAl?BpNkS@s1%PuG%TY_2saI@5@i(eX}L0N{rpuSMv zRIX8$I6rdy2`uAQ!6V-(lU*~Zw7QUP9m*qn_Qj&oWxmxq)w|I{j@Y)+PMqTDMa7mu{7A^={?n^3?^0g^T%%1^i>=TWXumdf`j{x!UWOyYj~csAGd;VQ`$c=Ccle0fAa<`OpITah$gbfALFU zj`~!Y#ez$Ph6xaYUg_g(U?U3smydIF+ASFQ;?~OAK#alxYbWiFlss~4Y3=%yf?{hc z?Y5MBGixpFrj)`xYjt|Xv84|{k!mU0MH!$wGqiKWwCr>ao^IVk>Skx45wNrvlMLE zx#DXVuvjXcQAM3mVUw+XlPw-L7$w;8u>w;{JBw<)(x zw=uUhw>h_6w*j~LP2!JIkD8BSk6#|;9(7kM0QrD&Krx^iP-r*TWV30#X|-v?3nT;* zHs%6z8x4SOr)GiKD;FyacFj$akD{xU&*f)xw>GfAZeY*~@mbw%v%45?1^!%&4JDBH ztjJyFQIfYhduG!5fUS1&5Yju3pa}Ma*t?9NL52X(l4+jtG&mW& z`G^v%`XKmr7%R$8U9i+gFN(J3^Wg{Q_w6FO`878{Gjqjhh~^&D zEgWlEX&F4^*vICVsAb;NGz4KM5aUMV<7DLHGMMBWVcG9!o5VY1fB)ICp=rEkxMoSm zZqH)Rk%B!ItrO+9qrStjA8QUh> zZP0tiXb06K=&J1djOX}IQ$BmoC`glO&pyvt&(WW@e0F>$d^UU*d=4Fk9hM!Y9kw0D z9o8M@9rhhY9abG?9d;ci9X1^n9S**RzLvJk0xSX?0?Y#J0;~d@O*jTv1~>-T2DqD8 zt5Iiz&4V6;cY{bfusf1FlsgtXm^&IfoF=7L?cc|K+MP1LFx}#O#d(Z+9)#Rs+{tqq z=CXaV!()!Y8H(B&gf|)HvdUt4VOGGkh-w(*?msbKgFF}Vh~xc0C%R94k z=JW68W9vI>JL~9c=xpZL>#A!SZKZ9ct+mdI9#f9Z?G|mkYYl7J=ga5Z z=dI@qcMIn>YwPD;=L8lr#8?Q0*`Lsrka7CVOl**@PNz3?|Olo8@O97K<%u!ou91 zsMGUF$f&5oSgB9KSaS{>Ibp=ZV>8lwumg_uYeDycD{uKPjkjMvmhOboA@~$q3vb26 zyF`j$f)9Vmp@NuMG(ePpM4zH(c^~X|*3ma6=3oQ%{t80yOh@o`XnwmPX^{Ss#cK~r z|AIJnXe^0^SpS0BBGb%LKCQMsc z$hC@*QM}}n)P>od*4jHp=EX&C{8F ziVb3c|A9iimSWVHEO3?P_U61oIpN%vbYJA?hHk3IE@f(?mF(1RC3g{%ZMHv`KZvSR zE@Fr^IttEi`*BiTRsuk$v5PY836e-Pq!JCt;Pcd7r^PsqSosYWhvlC?z zni^i*f34VR5xvB_>y)VA?V%jqfvtFgS2z)SecMAyswIQ#5p}6geH^&@;bc!5!k1&C%8#k3dUn;wZK(&^>+? zUV)d~+4+L&#tKuFUvv+&awL2tcD->zwt@-;kK`OYk;l&H47zbzI9ua_Y?!e39TtE< zL7iD`lUa?W8%Ps;M{s@4&WzBYYZ=oqW?NM3X6bRw{>eY;ieW{IC${LqlnQAYd^VR7 z4+}cF*b6ev>ALfi84YsPdq3O$bxtC5Izy8G)w=zhMAiSC=Sb$LaAohys&rPU_m(sd z2Qz|JWN8QCW^)okKr6)fqzZ1SG?a;g1akIQXL09l2X5w1mrU;wE)nS1WM_pbA`!Ch ze=K`bmLF*ur4*%@F}tkO)ZTq-KqQAO0xM+h$So0I|7!C4AisiU%b==Fy_QvFG+{hR zLO)&}kuS<$m2g+q_|vYsIepUqT74GYqS7jTB{rY*6ufZbJ;l9Bz$U9Q=EIo|aT9Lg zNZt55MJqvDG&0=>Gm&E2BX&+8(G{F!20{J!V%lv(cX;JT@>kQpTD-$;C3^YB)<>(^@~5 zg^XlVZQ4qydJub^Cdwn#2$_pvAwmD3pI~8_+%3nc0S}-Y$_mhRF;1WGC;I5$k#6ek zcmmVC|I~-42u%N>?|i{{5sjhhb{}}#Wmiqxu_4G8L?zuY0ioX&?rNDDTC>J)3hcBf zA3J4^FH0BXdn@lEeujnKi!ajBQp+lZF-|!@WteB_Fs+7^bV^L=jP^QVj%{8>bfVuh zqLX(x>eMulI%8QeqG^-6R}%j*TjK#J>bf|7=sC}Ak4V2N6lg@b2r4v9Hnp7c<)bPg0e^h(IL{Xq^zi@Qsj^mS6X zmI`DgFol)(QWy0AaK*@e$8vn>8Ue)!N5vcXgnEZ^huDoB9iD@|!sbA6kjKQXQGP|NtSR0j6m8$6 zn?+aF<~d7L7_Ex6SG)B^uyZDZ6m=vzP0_QzaU2uw>XRipSeKOA;@l<)WRr2au> zkS6E6Aq5EPTK4WKz3=!&!nNtFjBG^??G-1Tr!UgFWJ`2It9MZ;uZWFx`ziK_8j3B$ zR!b;#gW{N)jY<);0D74l>~9Y%MaakzDI2t5=UxV-Kz28CWv>|9ecu#4tj;b%FY)+t z8?+SefuNL21^)iS@4z_MeR$cM5F9R3uPZ0uG`lC-tC05Vo5H2wB-JswYnAGV411<* zh^?WgLQNflmLd|x>&n;t@P?4=-7wlv0$y&OdjgpkyRKbYTdrB1G@XL2f7Lfabjzr+u(J2*=>Y7q- z;}=&KC9sztW6a8Sn zXc5X6{HJU@X3Ni zS1GsY2{J^;c_}l^Ry)bCl6}sxf=-IlnwV@n9cyh?%vUH)3OTy7r1F{b1W#bNM9*E>M4O|P zAnQCc^7MW#C@XYj|ABmkb}8|_kV|->!rbk1iV+yfAc{{#z;YTUu9sJi1Y>5SFfwFN zt?JawwehSGfjqbA-W^RYK0VQ!FBAUbrv$v0q3Jy!eeFy>*~OE1ruX8wlN2!cmeWK_ zq8G;ZjQ<#qwQ5EzCg#JsTe=mL)sLR9jjEgR~2Ewp;><;3+7z_J#jh`K99G8?Sf#1=5YRL zq&tyebkHs=$`m5UX)eLsFsYO@4w@^T8#NWM#!@8^o}KSunTfqZ9dn1UFvw6$TVjV@ zJXda-ugQ;l#F0qx(Y#9L&i1xd`k}5rZ8Cm$wSnK7SO;YCvhFpGZEiVuG%|vgO(w$l zXz3DhSVoxl5g6x5x$ay{tZ6n@H-bDR2OAeUKVssV`SnKBuFbN_-VojI8BEj+vg zu|10;(0(x8iR^2^3bJXlcy5$)Q`eE1w$$Ri)nT&!g^QdzCN+N$*{1i#5z`n43#nov z+=>t^sBDRM82WdJJ*%BfLPJoOQNp%ZMZEgK3^Aqr6$?9=&6R-c9lAvtc~K?^$;*n( zPL`mWr){ml{ZV@s<$@dSY$#=}!^!3JrL` z2Mk3uZO;D0+^;$(q8(wKR=`zf$*!s^o#-Uci^#P4p4rvCd|$gL5givh)vHM8yd1d(|PI3?5qH22K!uDx)K4x%V^k;6(jSc#`tFZUsZ~KA(fi1~e z4@S}91>F);UiqnamcQ9pn?+42-%TLYNLoP%>^~35H)njeCp;k(3lfV?xnZBq^APOx z8En^Sq*JvL%qjwT!zd*T$>E$eqz?eoDc{r5H|bbbobo?YS*2PSlJX0sUt`hhP=g8c zhp0fN<5u>}wRxn!BN)9V^XvoSBm^ax0%F&0!lXxkDplq0iK$S`kz<*3iIAjS_>c2- z7HZeD${fv!)E@!Uo_1E<_8*R*V1xH-SWP^a(mN))PonP5c;qL{ID|VT+d`3?i8G{B z_~=mEu74XZ`;MF3E-(I|@(-1z~EA+fFU>D+tQflZ zdonL!nyWrp4ve7dkkUm*+qt&Gt3L+e@W_7CLz}q5e}L^dZjc~U_dR!dae5@FEs<8i zpotxXidL*T(IUK4lz#R8SIb;2c{(>UK&F1eXFS34!xbq-ia~_4&L$YxP-l9^|l)GW|l-o?1gXNW;cFt1M4fCJn*}2NF^P^$RQt z6=g|z<&S4Ua=&FZIhZoXae#cKuVSgwj)LsJiKrW>PNu(vj+h#!*y@USccy6p-HEjZ z!#DIk0zzdT9T!^$nwuj)u8$sCAaJ&;70Y<=emGOMV#Z4*@3x+~ifxWRiegcQ*fu1f z-htWVkZkNRQo4`0<}PpK>oBwiqRquUN1$nQ;q({JSn+(=ai|Ds`B4&*SQeuq9=#8e zjwEsogx&;)b0rT6rTu$Qk>iO`;veIaeURzQ?bYch(<7%`zhyXWd!3f11={V0)1*h( zW-(^2K*anWW>{`Df6f4RO$fi)+h)SC7|$!uuI%2vrFB+6r#d8}JQZiF@B6z<2l)2o zulPhy_$3?FzK}`--q{INX~jVrZ>O<+M4a`pa_;JvjNiBZP*_?IPc}!UjkaJfDG+7? z2+!nSuio5nlm7oaa6|*Q(gOu3C{Z~+I(j|s9>?v(u&D`7ioTLx9 zr*Xd}|0C+IG1GFl*;wP7Don`Y+k8N9i|y1%y(zTU_Mly}YRTm^Iyzd!#gV}rVSULa z=VZV>Cj4a6XLD)YxKn@Bg^6tMq!HJg#C~l;>ch6us4yC4kpFV&x(r}}PqAc(5T_5i3I1MMbTF)h6X zkzzbSq+M~}lQdfm$JernP#T*$)m(;nKKtW1E9+ zr^L01Fz8Tx;8P_U-%aFaixV2F#8DBg}#`CR2S zF0J8dr6fXsf2VVXDHUQ$5a127G?RA|rzK#r-`wzMmBG|RxY^;Qs61`Z%#Ar=z_yv{ z{nVPKtQ#@Lmw8S9BYS`UBl#YgE#%h{3tE>;^4SkJw%Y_>TSM(3##O)KR7;T&U@h`> zU7*d59^D(ISWMGVf1cU1VV6wBATz6bvYs@lyl2PRliZ zMgBH^80+AANF00*2=Lm%jBw%cros|Mek9?~d9=Le>Y5@RTbFh*$ALUN?+>hnS9t8Q zlw#wg9GRp}c>!}K#zv;&5|G`xx)yYZI7%5o zoR~31reGo#d3>2P9(z3(QGG3|5Lk(S{(0jr%X%1)^W=1Kv*wfNQ|h^YBI@C$2G-d0 z=yKV($x(gqvAep~FcIp6IbxUUk>h?Jj+K@@K_n}16!X=+kB&76`9X2$IkDk7sD8`T ze+VoO4v8Rv6_$w1&vwiSX0l9W88dlJS5biviwUW7GGQgNa%Pub=pjPuN z>*7SwI#f}-@8^E34eTx+DrBlQU@)ZAkT54eelFk_jJRiHoi{#sU)URIwlcyO&6Uv~ z61b$(30-aRX_LWwhY&5Bqh$F`oxoXo5uV!J~GKwJj>F=q4s^A zhvzei-7g51il9o=1(!6fy@>V#rWDmSp_RSu)74G-FLG)%q>o4Ez)x zQ1T6{?7+_lG8BpSI_mG((k|8IwjHyJf^JRw=IZvD4ZpA8JUXAFPtP-jPtc#5eL{vR zz^goL)OO%2Y9~7LKY_%TA0NOreBfO(`Ra0RFdO}Z6E$}-d$MhQ?ke)TU41JdLW-7a zhlE$CB zafvoIcoWy{^X?*(JgibK>cP4Ur&OsZaePq6fuw+-GXW*if>pVbe2$mzid0$JB&pG~ zQOd91L!HZoGwLz>cZ0up_t5Vr!V8G{*)qCa=zUkQ-?>eNF+J>|mzl-1SQBw4Aw{4| zk@W>JN5$R3GdIDWd{7s8j>7lB+Jh6k|19)M?F!+I5_+aki_0L%=zz}_c@M&&5lA~R z=(!e^+WyG4bY+FS^I~EaTpn}b=7JN>XzbSGqj%Za(x8k8@?^Pj0n^r+wESqB8xO_p zSSUHE-B0?F><-oke4_tNrXGK_{~7~s{T|2ku-x093nZtev&*9zC z9RdsWJFUoa*A<YwJlS-{kpkh=TT5dFEdux5hJb;LVETN%lkovc|y`HR*1=u)FT?dU7MMp)XOMM z_UxcC$)f_H#TsF1V#wA=cI*`xRdr9Q7G%f;d%b|DRL>K2AwB+%1S-^|vKDBt0xv~? zGZ!bcCjU)SFJ#bO#DtrK3S)Fsv-%gz*KD{E&ujXGK}*IEZOGLTYemw@Hgvh#hhT~7 zv_=H$$u#(BE&E_iQn-uARk!dja_vjfHCPUXm{qG2Rr#u?YKCgAwoNwV*fqtKTiVn9(6-9v0>>9s^mS{3vtEqylK&4fluwB|MRL@}j-HyW0lU3!l$sfY zOd`ZDGBV+Y)%#Wa0cXMWa3WTH2qU<2mQy7*totEbLmtv)8DU51M&(vMcqiu zpq!K2O14J2ZHOOr!oz8x1^uujVk{YKwTM8wX$dU;UXlHY6D%1QGD;q45pJ2qy(F~b ztGoY|G!QvTL9-;!n)j+TQ45}^f=(mDIqnmJ^gR4nG$_;1+~6%KA;KgIhrMa=s; zI1~yuOM5{{mo7taR_N4HMJhZnQOW+9i{!qFjS7@yX2%&wldb`tQS&a`S$Vw4)GE-? zs$|Ty1Z@&=wsXRVJaeSszabg&zH5Bf`X0o9=awxs+2g@u?lvi2&i~cVcn9ZQ_$|%= zdbsQv15^!2;5q6pob}iGnJdswboI(gEGy>MI=k8=a{nbe<;db%-sZ1$MYM9pjP(to z_aOW!pMa+^dF7Ai`QNAc_S$?A>DHrO+qr69C7B>@%U4y%lCm?I_a#LiuvBFAs)cM%Yp;_nGG&MF)k;tl1IcpK+XVLLu{y^XT%C7C_Dyx z2Ua#rFC?{i?#+4gKukz?I&+F^DDxmj(2AexJ~a%jd9u@|DoxEtGRk{sxwA*g{7xte z&F}RzExJwblxOcSu<6fB+l+sOkJpmGvrGY(S}H9)s-tWfUO2QeW!w-xV;x9Qh(JCR zF;yB2FGP9~rWUdTmT^*3D7$>hZ@uF0C<+Gstawn7uYGSAF?P++mbr9|ejOS-KJOeY zZ%&TK6k9y@Z>KL`lvwNp^|`$uKN$=?W7|)UZ}N`W@wqxYMV*u$hq}3S?+cx_B%?RkkWMXOwr7YZ+G8BrwU8*QiQVcYE z8c4(_phO>(Y^&456RBjD_~Aq(&|2J(oR!7970RMsoh7yluN|$h+?%I4mF@IZnvTSo z#S&MYJURN4vw&{WXq5%Kl54=1v?{TO8f;ibraV%5)OhS|DgQ=0KOJXY1`i0HXNBUr zM%SK&K*3qGU-?0Xzm{8uJ4GB<2}5}M@i|CZwLi7}e$&J$4h z?i3S*3PxO_j(?I_C^9j&TMJH8b>wsZ0ebi{cake96-ZOx@YBdOcVe#8em%`7HB~65f*{yenC7@&=fy0oALu6+$QQkb9A3cc zHx-Qk@l1g@D(F~TDxin9pR9#@rD+Kc#i|W`njyQV?ubn@vewL~ZEWNtg(u~u>XEor zqwyUGN(bG~hMXHIh+McoLZdgu>H@*YXUO;A)uj$@-HtHaNlx$aklr6TL3HND@ld`* zV-eMA_1upAto?~Ou)Fh142Rjuy5}8BNHeq`l^R`XBxwVLeS9JDD5GJq%1G1>Puh8B zho#-Q-JY>s7Xjx-U4%-^@RNGJ=O}_I5qPqnx+9-|Qm;q3Uz!`jBdM^Dx5Lw|+tpc! zbbKKNZ|n7z0;I0bCKb;1g_vC-PX>UUx$kzN7|{Dy)#25G5ZldDt;65$ahB@bmGecg zD;#2D0ZNK&;u6+<^tk8D@N&~b;ITjr#~&Rh3CJf`&%(QC+_UWb?4nUYxfo5dRPw$g}%)?OeKla#5^~$D2}`a1x`-Z z__6HTdk;rGe9JAH?!pOi;R0{?b0gv7y`)Rf-rm#Vy-&tslX`I^qa2lrPPpiMf&Grs z&G?H$Mo`rXRv6Cr2GJo~`R$6UVAU68PP!bw3WpLKCXVb)&P2kNqjLc3oJsKJ0VVR? z1RLVuL;C|vdtf$ybo&Nz_68wgIQ#^5Ocb{3A}k;N#$!*5ElvDEY-D*~8}`fcs`1KQ zOV3z4w!+yX8%%vCUy-@a4(6{id=7_mR$x?l<-`!qpqoR~+kjU!0$ySckceK|Z0)8XghRX^#4gCIhWLX zo{E)o?4Y*+M$)GSQ!;F4&PDxexAbNs`W^_GQpfe800LM#p$R`-x~dP+qpJM)1<6r6 z;olGtcZoH9l3Z9Nl!|EuI23K$>Lh0E`Z}?Sl8~4r;Scy=TFzCU^yyG=y0=KK z!ZGR5cp2kq77}05*0R2SW7lQSPhMl2`-m#gj{A!^Sw*IMQ`VqAl8cB2l9U;yrWIZ! z1R7anIId+CtLEt2-3KntX}ixi+{LM4cD#XpeJN#{)iU41yxi2b|3Av^DMoZC%met? zw(i(-$F^F8e0n1v z86L0T8YJ$XXXv)>_s|RvbZwP(JD+J|qQ+cNs`gB8AbgiIFkX*E)r) zo!=9^1^343NR56%`)t_mgY`nUq{DrC$nAkee!b_Z$DM-BJ~54OxK`0hp+8S!5RK(_ zFMjUQx_spt#k?6Vj7FWUz;~`VFM^x2_amnRv!ekQd*2nJ7+up7s8nD0S9hnhifqxhu37UQI7TF+SN(ifbi|M^S5iNUj zN4avc3yv=8V8-&NDfP5I#x`xQV>Z~HLp61)ngNN_Emx5euN%BAoxosWAv{*CjpcyVpiJ~p0 zSIm{61z0YS$lK8$wN5+91GtytqJmRxKNOo+o{s;*`j<9%JTr9PR4-j74t_p?yt`73 zdjaMRQq60S>GJyaPCsUB9)g+FKBPYmHy~&RD5o8-Q;Gd6Nl;z58Q}bn7jV+v9d-U< z*Dzy`V2pu)E6K~4m}^B7mBbHoDQ1+9Qj%g3(ZViJj51W0-V;b&8kmVQGfGRlsixJT z(m&L{xhrgK9H=CK;Tpk-yH_tfXnjPVM2!u(o>s) zS=1W8Z-$(2_}8{qHGF>rgXLvx3n6`x7&4*@UFA*d%yhwR+hiP`yDMkZq(Wx zNbxw|6bofD(QIWJLUa36WpE+k2FGZ;QO-ILivQXhv8K?2L;fi%RDs#CL<2m;Fr|uF zNzOm^Q$(Q*G9@-~tP1g>oLmFfa0ehAEC3~%-S$=An$Y3Td&mUq2<=H7P6|nv{vye@;E3x9~oaok#>WV zyih)328R4c&}ogUZb;)1@#w+@c4f;hS;9tUl3CNABv40#;L8QY1;>L3TAf>`6LOJ_ zL6Q2~>XwyMifU#Xrc(%-_dfxdqg8M;;M;#s_IU=)E*K|(=~^uao4cD7+5VN>pU5oB zDdsJSpm)pZ6Uj&dJb|baGUMbi3*b9BnT^aJUTsAptraDRO{XCS=BA3_TwTOkJiiKu z=awKBZ44xwym$p+Zb-NLkqehA5!1Q+0C7^;Aj=T(A@J?&XtZcP-oGHSY#&?e830z# zF<5>cLTD#*!HGdMh0kW`9Gc(7pzH7i(EnmTVwD&wU>1+a^EG(t^nZQBm$=O4IdeoU zr3C)^?bXKH+xu%g+e>5e9JpUDgIyE<#gw4<8sAPg@=ZQm%iSOQK(H*CcIG>9p~z1b zQb0LoYAy9b>YINT$I9ZQT6)aiD8Fv@T&0S9W8k1hI-svy#c|*{rF>wFEpHK!cS)jH z9@?}r9hRPq<49bXQ<5Z&cOPWl8HBlFTaI3~?XHxM>tL{4HqyB^3T_`O&Wm*<7Vso8 zPx26cQ%2-M8jRb$?dHhkw{crJ5~?Nz&=cG$7+dqv&xu>@;kPsC*C0RDf4)RY>FmWc^(%+az=~G=2_^*o~ z8W0mgWfeLloMYD)hER9x&@tMq1Mp%0V=%|dkZhMPPsV+m)gRmQJCLY1-X(6etwGqH zBpwr-fLfy%%(qVG!I*ZR(<#74&D%$RtkvEahnGixq7y0+N!EWF1ag+={sVb zm4|Gif5MmjDAq^Bv&gLY+49d!IWG-aCmFso%&()-OBlX6mDROD#3R~C8E80ehfmcX z1vI9|E#t#*1n*CkJya5xt|ShkfC91+mk*h4dl5Hi~&whbJfDq+lvb?Gv0(Zv;Uc{+dkh>V|r7=G@#|0pe!d z*m4@^z68zoiLr^puFqBzI0;D9sti%EcM~HqDPPsEXa&o>{L4@AUDFulvQTA}63w8M zgautX<|w+x@6J;VixK~*p9kv*`na2v++tCVo?w?@dam}?#h1AcHS3x4ob<!+OTp-LciU!JUs(P&DMFzFfSp9&fy}9 z)|5n)sQ7dZfHMHoNFN0*(tPW0km?&XH78|0K&vmUteA93 zEQZj^veMl{de0k9fk#Z|5Dm`1n14T z8*npdH;^(rh~o35@+O5uDx-^t50V%g)?K>MgbFMYm9AbHbgt+v2~7`Ss6=_hQKwmi zVS-IOQ9)4&Uv*RkE;EGASu%#qZ%RNi!Z>~tWJbr}EB1TcyWo*Jo7=`KPE`hV;g;t> z$idU&73Eu18Ay=lve6)_GSjWcBopfW2xajBnlr@-AQu%l(`&Z=D1o+5;l+}l$6AD< zy=6)O22IX7xy@#@Rm<`NO%oXinC8tZ#&)heDk7NjAPZxegz%r_RhuPs5pecH;o^cv z2a^}&iUzY7(3!`2BKjUDf)z@{-%Um{FQFfu0qGBe1U)eT)rD_vr`g!~7wCc>5DP5& z^&z22VIfvkO$dlNh3w3^awMDi5#)H%MJWcWQwwClY!qK=N5vCjk>r|W$*gKVQz_^R zjmbs}q?&hS(X84ejTyZF$!mcX7U4ChO9V~K*oBnQYdO~OQ<+qcLa_v|`7P>HwJ(;3 z7O<`*&09Lx_H9|9aV^zGwlqL29y7~qjGifSEAIQmoEx2#?o1-26&?73X9Y*1{Sx9s z@z}%*EXpe2VsRgTrHF{05mKoh*Yd5VD+cM}l{%m;a|f3_Ah})uOI-W@u^}d3BzX4DH(@t^$dVGDcL7%s%y3tMpd%{MFq1#ezqFQh}O`#o{*`g|Fm-j%kB1}2s;(_cN~ju?5?dUY_Y&PH5R7IA=}MNYv}u!@R=F0HyNmKT9) z3|r^7pBhBQrK?#yHtcTb^6|YbAw%>OEosEE!$*mDUYa>4V363@pk|CKBfQI6s5dMM zv|*ts@62P{abkJ|N`T+@Zwf{{2$&rieHC2rkZecR6n>fVqPS38<#5to+&KgM#xFo7t6bR?5r57hm zw!0;j_*@Hepq`w~RgFjrKOp%PrKc`=?*xS_vH_P0J;W7BW_!z?;cx|6s6PqZ$to0A zH!qU(2e{?-&O}HLm}lkQeG-Y;rn;~}Uekr~7Em>6Zb{Sd0v8T2CLE_Ct%TS0#2UZ( zjW$G*QY|^(b(KPdH%L$8pU)&8(e!i$8BoN~Jsa=e!bJLAk)H(2UtZq5OE|DfXKZz#-%7Cv;c_U zz<8m>i;2owb*h3TA9KRwV7BG-^>~@SuduuQ4QT> zKA5YNL;XUP2wx&IRXtk2y~b`1>xxV(gv0?(60oR$!kO7{g!lReYSP$|Y1C0HlPV9w zP=p6lC3mJNGi5QboJlpa{oQa`F~uT32S-6#)--8l)+nOn*pGp{xM|olhUWQaYU-Jr zg@^{SgIC()96yw|ff0Y~2=}dUxhYAHnrM5LnG&;Xk0`lrzzUK`Yt?zLQ?hJ7P|q8Li{+Za#{7j%-Bt;R5!EhOC4ENdx$rISiqAy3wwxCRB7Xa}a}+Ua1^j^_54DRe>)X^-3XO z8m{YNG}Hq!l^AV|E3Wt(yxXt-o>&7tM|8Rd3X0HT^{6rVaQlvu*GCIR0JM$*OHepl zO4sTGg>f$qOM=rvZ^NFIw+WJEgl2Gnk(m^ij3t_WT%==XGOod*bMp+2>=v6;5K`jZ zga+G9*6b@+;}YN8&w<-g^iQBSOo|Yux$fFUd^?HT$PHe$aeDo>br>De8m$t9ocfyl z?(7~byd_Q{4z61<#w4WzKsf-*ry`{+Df<+D+b8sj$Rbd~1jrWW{>>);^H8ai5->Um zhkL>r_XQeKS^e@1FHpL~izqw_dx#ZOqY5!@Fg@r~PDW*8$*KX$I3<4Wx)TK^L~V(3 zgLXL20C4I-Xf1-#>M#}2dXtwv@~8LivdRNvhCjH)l{U6H$+D9Bh$Z4<4za_A21_cY ziObJ-EnmRH=mXp_jehwZ#%7^^2PIMpr#21m7B(c%l!Kp9qi-iMvkbymD`?5<7(EN1 z&kKiG{*0RVgXi^UPgDhGbS26bP7D>>QsW@m6?2pnMb{<&w=@caD9PgRoeO zu(`NA=Z>Y#Wq&gWYh^av9#ykOI4L7lT@sB}T}po*8hQ*FaCd7V0X;hWl!KS<(#2dM zdY)?o_i>-dQ^+cbW*<{^Q1plyB@oV0W=(mvoWT}0XeiGXg zT%_=tSp&EnJZOa5zUU9m#o_8vpvFX&Eo8M&nVRLjtq`U10f=>mEYq(TNMnvL8MZ3><&!fo2|p;|gS{IR4m`VJy^xSVe6 zZIIfd-dhp>0Zg6JB`Qe~8@|zPamIyzEU29wz;19+R5oz^@<5w1KBx2O( zDlqhyCYj36y{nr6ZJC)StYUVd3Q@xbhQ&s)TogsWDP>qnbynuKY=-uCTmn-lv7MrQ z7=5K@ZKK854iV7~}@qwpBe`Aa>F91p=C{(T|{a3^niYr@eP*dV zL4dRNbX16Z^t%Fk3lRSkZ->ZV~O&vhi*V!R*wDR}JEeZ8g(r zY=#9%*Fj$=Ji(UJv`5}QP&b^@v$dYk-+9MbwyU1sy#*}axrC`(lg2xdLu{rN zc!ENFjP-&iyB9F)XhxhdK4)N{P3`XTqr=z}I1nL$wC!Mp6afcMIlj1I8(jYx}-XJ2k*3R3!Z4N?kl7*bkzVHr~To;IL_4SVVZ zHOR(9x;?D5@T>Z<^xwI zkQ2l9sxvRx_TzVO28puA5v+?x=1w0xF~BrIlUd1_F%{2}GOcfLauLc(-3WCRmi^QR z1vkP-X!PV?%M(rbX4YfWnBR&3JL^n9n~hZcTTuReVzetDIcqK4gHw%%Oj zRi|=EhSmraq!Jaa^eXu-2gLYhk|%6a;7t3VNQ8~e+OX1Dtwot3wk(9SD!#=pj2s^W z)Ezs&(a-2F_ZTO;)v@QDSM%qMVtSZ?KZ9edlL-$A^;`W9My42gP7ng4hf>-S{aR1c zC$_S%tlI>m2g-t@1|~=8REAI|;4rr(a=9t}>xGGavPk_GqkKdh=7sB2-9HCfA9FnA zAZLby-bhY=4X81+XL?fxc@Px@>ZK^ea2KV+vY@8+QTVdpIg}HU;*; zjR&gsJN&z&?P--jxyqwT@l7v><4RWxF=W%eFw2}_ZaBa~cR|j5AZ_=UX06k6 zD4rhUx$|?cNo@B%8Q8hOPY=FazD$kuqYHE?E&~%37+W(apuCr9#Dx0QN)t3NEg!9z z&8myF#AOlfvh_J{Oe*xg8o9pCxV>z#W}YnToPqqc3oIn2tE$NrneGH!;OCpOgkT5c zLrYt4`IbLbyVmrtiqdykNNA>`tg`H_hwSh(bEiyz)%A02U^GY6I%N=!jaCF@0^WY9 zReTCa6|jv{8~frGowYxEia!|_p94Z z%ZKxV$VP-2&Z!_12Mm@rZvt|?F91cod1bDQ;Zj#}E)M)I^TxvwDrfy_NBO#h$L7jH z6nfSl$;(Lb}tAUFPLaF%VCM$l6g zGa0t7;O;X@oRJB*Lq|fnn9ZUZJl6nayor4rnGKsQdWNxr*rB*@LPRf-23M)$2K<~#%T@1Ar(|sRu;YuNH6V7Yj@b%Ub8zLi`2o|k^MXgR zkoS!Y2a2@-{XPVk5{u`E=Ry&eVel|QeLz&-917Le0iO9uzdFzX-rN>_?Q26@6zeh$ zDLgg7`!;MTcj{P9C4?`vr$iJ#8hl`fjV6X>@`xfP+2F0Z?ic;8lQ|I{H$cc*k!K_e z5B)Lnz4rJy{dNaR(q^8rLo>n1#qmHHUXCn4v5rqW92yl;W<1iM_AkdKo{!Z{vC1jj zIW%j@D_??#3+qkHhe!XH(Enko^|lpa52^J$#d@bZ{xz| zjoobX7`;wV^Y;b@*GV;Zt3Y(MGMBE~_=~rOBcXbnI1&P4i8og8_3r)*@Ja z-^6(9gZ1J!#gFU=Z1+ab$iy_ep|;A>Ue-gC^B>(_^cH&b_BHzt+7H@j7p4!W$hFPXiynY_E7Kej5qj?Rst?l4}yCCl4hw5wh&nd~9Ssx;h|JG0C`v@E0TsH;{w$E{iO53Q{d4&WNB z=a!HdZ@3ZTg|}#JMGNzo`h# z6t`*fM6|kel+~${=CI0tb;bYgk^g6--Jp#n_>uYn)7bOC>#f(CZ;RdX)7$z(Pr6LYtQbB_m1xE`rG3R zaaQDUiX-Ay*+Bz?;j`yxt7FzT-Dq_MB~_zTLsdI{^5IQy%wgO2p@hU_!A|rB^uJ7e zo?fqaW_HJFR&gA3lb~1YWapNUvtIJSJTJU3US;c6Ws>fH8Q6QQ`_r{xLQc13zJOkE zJN?VfH^Qv&u`|K%JbP_JfzB<$u<>t-_!KacqRX2XSDsU}+d%)05w;ihtemK7?b+pc zS4@uv@L^6P4xUNydYU`$z|pboap<;06XCP_Z{Y)5WfW-0+YwiT@B+$k?;F4;gg?RG z+3^c77iNXD1eu*Z2p`yOpn|o8UaRUHvtlA)dTG5#hivtB>onW4=)~Y-qa$EO$r6^a z-AHB9v}UwNF}?K>Ybl7@;0bjOdsgm)E(cx&f1+_xB2G+zp9TpH*<@J3HHq1xF5&6H zLLKcpiYamW)tz3-?TAzJKSY9^wFHuMf(zUB<;Up&uul)R<{}a^q4P5JL+Mrm<6?D z#qEwU^Mx_9@Jpvz>Xh=RBxohWd+)XeAl0v;`U?BjDiR|4L5mhCRfflGR$?cms; zd>#WO9mgI6GsSB-3FxfE#AAaSW(-E3G63p``F3r5@X_RKR0P(>QxR`qa5it0E#xEW zpg$se_AjbcEa$Kw6>rP6Mmty#&52BltnnRh3%Rl|{y5rN$CXS&rs%Ur$JI%M{bx0eXen)W^}~87HMQ(_laF?5n7;@&x^fj zB`r#41$o=t&6Y-=z522$6dCuYDyRF+GTH{w{D6XPx~ z?2(pp-vo8$G|#g6*)nhBqBct@b*7&@1gt1-!@gHRDs5bEemhqcwm#TeeHD#5#t>aq z_|ck+$u`pgBA8KwO*X%3+PNq$*3S<~9zYBMXbBmU8> zfwEiV!b;8bD6by$&NS#=MH+_AH(dyj2>)s|kf${nLKkVIjmBsAjqVJ#>T1kht)wDH5#urm;pVwtBd{xG z^XIzLYL~%5FrO^A&SFw8S~}!wL_jGJ^$J=Mg;|v4m^|3U)(>Yf4BUbZ{Y0*(^Ido9 zY>vA3svP!eqU1i9!(h8* z8&_H;A%;7<>9I{9J+u8}TPHhwYtH5r_XPL&_*Udr<<@T7OS^1);8yEa?3VZqR}*I@SnT)0h~7Urw+I`n}Z2v6QC zxiwdP-r#IlMLydw*jwBk#x7eojn}a|`h5d8`(FiDeP4N>dB5gPcwcgmdtY=savP{(Y=ytZ8gYO!4R`enm{Ph|z)n zC}FIVP*wET8q_`dink_~O?bgn(uS-oEDF8z>uNx!MPNxM!rQ zf_z8$EpukaU5i(p`gr)H_{jM5@Cf}#^^`6zp)yU<(xllqPPh4@wLp(|x1WhJE` zB{7wkW@#`oq=nANGlJx38O3=LllEc2GQ@@b;4)=OKiXlx4YMucGI>eroVh%`etl!J z*~z_neQg8YksT8qbB&sbNHruA(LB6^+sWXfScUUpa)thj*ycoBhed`-Mo30uBc|f1 zqNw7!I&O8fZ64l)b<)}xZW-EF+t-eCqyIX!`)#?uPHk-1EqX4hE(R~NkIZMo>&Id1 z5bvKKg-_lC-UwcdAH&b{*U4XTmKzz27)EkTmRyWnCN0BGGJr^5exM?#8B!D3g`_L~ zZZ{|w$!q(tv($C=lBee*dfT#-_Ohqu19@Bb=G*6`w&N!SBV~<~o~oYCUc*57AYjN7 zxs{}a^qc!vnZ-k*eGa>f-!N2)Ex=v$T=V>URbMhn#I51kwS2gUE9&W%*g;ZE5-r|A zP|h%(-Na!oxzH$XOYEKWXuWWrgUFre33uymJzLIA<;n8YReHLT<1owW>9h49Hp|#e z=z-}0dux2b+@4y!8lYq8$vuDhr1Nw0)o9d<5!02v#Ut+}mhBpqLC`+n)v)%bpwu9_3d*0pj(y~+g_+9ie&Li)w z@Nx7)ajUp(s+{}Bd*|vwIhXgH^!d+xYuRm853D!0x9gL4=Pj#uH$^x_pdysQNa+jR%Qm*1`iH;PsWTZ4>QE>^Z zBz7_jOEsOfKnBV6O4FOUw0Y&iN~yJsC)2N23vKTEpN8#VQ%h5!x#=PeW?^)9^k9_w zZ;>i99Mdd=EaNJs6-;!DRLoTjJO&=~&&Yq&hrLnYQM_2P*tD=wm}VGjwtId4MBpc| zOz>HBb{l=z;4^q@Tz1QS;9xemZH{?dceKE}xUc7ZM8LAJP}ob3bAJ4TV9{7iE^`0! z!~=h)N~~uw{FY$WIFD<2=wM&obKm^dfiZ9#oM!|0B-*(I z@BNM7vv^$|cgTUdSf9^(E&Ze5xqrOe#irtP1V!K|uo%q8rU)EE+d}_hHh7Gs5ZuRc z3qHfS+m4|N#=x@kGMSU}Dq(TBmsyv2o?YZ?hTPy#!hcQ9v4;9^J&w)ohT0Dzg<^(6 z4w}GK;V)3}Secxe+?6PdpZ!v$?>}Q7D;(ov1!H4=X zer|=?5WUCliK4`&u^*%$Did9Z{Kc@p4YMY~#jCd*+Clsf^L=P@FRxohesIudim-LN|r6+cWw7M(?Z-xB{sq#C8geg7T5DaylrpB#T1 z%|&;AG&Y$op8gw2XJBM}U?`qyn4(B;WTaxWWI#8n8S7$w=%14Q#eI3Q-?UCD(?1w~ zlHbfv@~7|^eJ8ncQBzP;ml>%@EcMWGnOP(!D5o>BjHf#&Dj6zCE9ouGS1zi+8*#@I z8g-^Ts4oYrh}28p?0U#-j~LwWJ&x7Y{10E3vk&^pr6G zpsBKNw@gTQc6TnoqpEJ?tw=ygl2<9{r!Jn<6x1a#Tbt%8SZvDZm-pg!;!zrJ*Eh;i zESr?tY2{Hp0PV3=nBxW?el|}%2p&>qJ3F(WZbIVXl@)LR#N-+}Di3n@Uzb%kaFS>B zaop(TLM|l)4nS5V!ab+&**Xq9#k{S8Q)c4<*q$u~X2{UVsJPew>N3t4x2~>kTvXyD zBb(D$P-Lx9*jkgh5z3dO41~}5P6+yo* zetN)A8```)O>T_mTrbTExhbma>L~ZgnO;^>wX}5LYRLt-kEOV(pi4vH>hIgxh*4raEBilWH6DjZpAUSwBb=rpolKCowsaJNcVn7vT{ zi35bRd=LyShS4vTbtkF{umH*iL?~r6T_W$P8(L>7UEzrlk!iEqaRH?XrFB}Ot?T5w zN1KPjx1zDV1met~?Jn@bwe1B;olSL-_kgjz1=8%3Z7cXx+p!0&iOZc6J}2Cn2W?5C z?Je+vyzK%~ok(?+?|@mEL0!9&|7@DOUtjOKgwlfJt&Uu1@2Z5pGTZsh)p7NlLuv8Y zUKc!K^iV)>b|+q0!mKMeG(fMHnsM2iF$V|xq#Ht8byg@fSMJ{L8Slfyq$Cn6Cvx;3 zf4^t>kozrGK*h`&2kxE>g=w-L}r7g>tO7G*G z0(sUq+Q89Bid}Y5>v6KE5K$?B5#7m>p%F6G!71V_LBbHD@FUlF_;QhqxZk`0B@gVRp-?%kOQILuzs9SQU5jjpHotrd_4Q6AF7suZ*v z{)Ek6mw1KLj=}_yBeJ5p(X+yY!7q}KbA$>+T*tQwplA0Ih5#!=4ZxgE4br=Rg(Sd; zlgh7-1=L540(_!N^IONS!da}vkYbsr){{ci)xeITIFY;zpeNDW2Q%a&gAqykrx@^& z1nhMTHDdHo9NnLWvxB5Snc50QBq5<`n5-N(em_v_$n z+2O`rNtmam!fr~^k%rbnAtt%^Y2}yA=XWK6R~SN^9vwgQ15aQNvWDtGz0PHf-Z$r$ z3H0!wD1#&-F@U-cdr6zMAnnW#=SjYmP_47VSH;dP$K?*nf+x36s*lZ*ICoq&3HYce z(s7;)f`sOc9Nihix!y5Fj~}1v_+wAYs%c%@v4-U7bG!P3RePjRyP1KKcsW8qF`d~j zyI2Bah4e$Ne|FU%JJf+VdV-Q28HCp$nXOXRvj&8#p*HC7_v&~pHvz3})Fd#W4J|4s z*r|3(C?JZJR1*8^=v`LalE@W7bDdqVu0`}QRoa87f>d})uR^ld*}81AoxMI+l0@G$ zZSHW;1kv_GKtN1uo(7ko4WM}@TksR=QbVHPVbo32*K(vO^VQm3FaSP!TA~vJP4|>j zIl)<#X|uvo`aUfu+}nfqN??WWR~Dh_wbyjeqd_|-%Ry-Hg*Aau<<}$E^s8J}Rn^oh zyUYMT1K6>pMxCl$+57szOqXDS<$hCG} zOkuyf;-WWpidj3;Jmb8y|%~lGD?3yfE!0{O%c1Qy$baWS0 zHABc!EeAI`RaUrvyRR&Y+Rs)Mr`Vf}w4zDvro?~^(NZ;2Gt+iPOHoHZV^A~FZq)$0 zyrQIF&uDCllOYXUa9}PqM>j7tuXk>t5KTRvC%o*)23iWPT?wx*o7YMgt9fTXyJ>jK zC+sDo-%}LAA(@%?E6@<_&d&dotG~!IjG3H?NAi_c_9+vptdIbf_+(aoBRKPMp-^)r z8Lr|$n?0#qaue@+7?lVaT26#_SX<}p-w20zp4ow2!U=?hP%wuX5>=L5D=|h@FyQL2eHj30(%#?zL;7d{6UK%C$QlOPWzljWUXItBrAK5 z0)>TcZTAC=muVWlJ-}{>I~7a{nzWOOjboZuClxQ_rnY(>UV1fx*#dy`0?z37;ihDj z-%ERCy)Ahu0rY6RM{oo3G_7E2pWQAW1d?M??Scp2hRURx0R}65_hwLjD{)vE0+ujz ze2M@{v1iTinE{2UN%nxjs2g@@W_>URQNbuPc^ha7Y=Trha=<39<;Z#4Fx45sSagfI zEo1Q0OBHHGfQ_H#(>`V{dR38}+Q4&^I#qy;Uyr(1p%uW5hqtUY^wSt979`eKdP#Zh-6r%0-VbK70~?^6HLs9yo2e}^FLyIwz6x%o8DOmL8xC|>g1HY@$ak(oQV^Nf_l}T!u^*~s@ zr>A^orebOacd+v+Sw=M(+EZxsjrn;4G{!?>n&QCv>EVvYIJg39%W4zE{BF`W$Rz323i$B*w+7z-dN&>S6!Add7il@_tzeB%_w3zl7?eEvlGlg+3L#alf=5@s8ZgRVZ z>WPK6xl-rCneEWctwi?h|4fDzOUyE{ge z!;wU3-leDWY@Ar)_4TV7+O0**X2!x`->H`M%x(OhRLpIKK7qhh_RW}7IIuI! z)%l&=jv)+Z%H-Qe{(c@|lX3WM$xX1;*v!029S#ITziFTbvu3*)>RVUGL$M0bVqMeB zt+^5XtrH>2vFe+SKcos=$d( zZk`c2BaWK92C4x?JPJ4y0Kd=7#Hy#Y@UvmU;NPy3}b!NVqSZ6 z<3#9miP>hJyKpu!?4KeHt0CPoKM<*eDTEOQCCThC_&9lTvG+DREy`B|<~A z$SFir$2+OtQG;A+?sxS`oScWKgg{p<2r!DueTH3RAb6(}GLV0#d=Ylj^?xBbTh!g}MDN+$ z`{3xZ?f(EvdgJu^0lT$v!}EL5cKZQ*`-a>V-S@`W@g4jCJom3!F6UD?bmji{(Z| z@MBOz+ltzQ-Tv1G-D~$G;U8Ij{M#5DVjsf1oHER6bma2z#evhm4iIfu?Sh(68u3-d zRY}u1>N(Ym%14(ktuHR`=AHc9+S>Wmi_6C+kJ27~-_CFPufuw91Nf1g$lon?GK?zh zH%3KPLw|GL_GSMgla@fo{7+f1T0dC7SU-86W^g-XIm8p@1#1Q4hS3e?1shjvJ??(a zuixAk@6qIaa!>_cmsJaQhoQ^*6`m-O;jot8v^Vj~#^ydP6*?w{+ts?(a#Xu>tZDVJ z;+%O=SGqQHhpyZFJ@cG;aaa07>W8k|+GF&w<~+CLMd~(_hwf{#Y4_1~F|;IB3NQ29 z@O|j9{G4&oS2{OyLrOOdE)6cDhsoQR!-&J`ed96uTyqg|(Y54Onl~*b!-we)&$i1oA*I z1cAaFq`W{=9=bu0jX)Iw*$_0OfGdIg838dQcd$+XzZjYaw0BUCK*XHv87&NgLNHT5 zISdLI2n6PU7=hv#lG{F(eo`Fu5k&id8G-B=`UnK*fZD!BKQTlA zxmbXDn+!QhM36zg5IO2Zko|z0et=!KT_Bx&8nG1GL@>pGl70rAb{&LDzCaqm6p9IC zV=#7bW>99ZW{_s^CP*foXcKu7nFsZ(O zotzpm6Le%SXAoyF$$)}>dYzUUK^2M$q${K=bY-w-kY_OSfOmjso30z58Wk6L74ix+ zc2HafW1%>MMuSF!vj>m|5(g9q76*Rg%=)c&Rrt`<0+n}J zcU^Y@b)s(aZsMjcO`eM`_%il13de91DgY!1DylB!7o8C z!SF%8kRQRm(0EXIka*BPh&+fqs65EuR9-Yqkh&1yL4gCQ1F8cA`*nBCchPs%c0#W* zuR5>%Y?PnmILJOoG0?owWI>4ov;(yRwgVLVuKP`PB5YJy$lnMv&^r0rZTMO!UIL+Z z;%$G)3CTjj_YHzDC@zM`={1%j=?z%vRicm&he7H))5xC@5{GgOXy@@sBfE!r40P#* zugIR!!NbZ8GR#oGBLat+^WrxK;=M2i*>|z=cjP%pjOXG!CsFL?1{WOdn7mR3BIuNM{kLL?{<%XHm@{R|-igs>`-*8`EF@N&cD4WHMR%U>&Tpo$Q@; z=YFp1sz}xrZOb^hT}YRT0VR8Qcpra1cOS*6qFqjxp%zIas%offsB3s>pMSq+ALmYB zj&z$*fT$Lo5N##$Viwty)806Vq;ix7=Pbn|6pI?4*E{|j{45Z zDg8C3UB^c~Wf-GD%}2pU-$!_pw3n)v>|5MN%SU{ZwwI=t;#{P0gienfs$e&i3jAm+vp;}Gb+@SW@( z?OlSW=BM_j#HTtRi65mO<2Mljx<6Wcq+sOeaQ-mrzVsdDoyHyKUCL{hr#2sH9{NnA zf5eG+-714V5@VD=gJ?IIJ_dSZ@<53rwMbNot4azQ{aGniMfU$x87}I{qyVI(RTL}I zO%swzw^ax$>QYFalHX-POH`@lS!6&6%)mfy2$YhdC(`u9dTZ3qo!=|4_q{p~LB%eYdom}c{6~(5O zMIoO~m!wviU@pa4sx@zWCUHh_W`2h89|hq!#Z=-yZ{j$^RO+$xQj%yEmU*sx}3Ey1Eo?soK2W{MNkn8Nr#pRjh0N zVd8(xh08LCG8ZLJ^AKmmR>hC?&C=_1c8RSr8zqwe6obY8^n%Q1PXDBWA&(`GDUZ#~ zvH*#7dVbn*mFPv9|I!#Cw-IrM`d`Gs-LQ#{7v&;I>Rq{fb4r$v*LUBW9wtw zW9_5j8ULB@8R(h8yx-Z*eE7WN{OG)YiDHRj=}gIwOunq$Jmx=HVZmeRW9ol&g}(H@ zq`tKHiM`3a>3#`uGJ^lqh57&Fg){TeXC;r(|J+2`t}^d>JoLGV(=sO|f+Y`08rJCy zQkdlVi^O_K46;#~tl^o1Q^?0sP1AU0aU2&@%*Xb}nl3rq+c}2U_6lq-Oq7}4S>BoO z$EGe0E`%-yE>Ru%9erK_+)Fv;99fWAkeLfp!Be7>|AYaPgHxoF*vE;-axQ6^oCYQY zX44!e87@=BQ(nhD4_GdNUe#~fP2+SK;!UO;*>$X#S<#cj$0#lp9g}?1eA|3~e0ts> z9>gBV9!y<2yrR4+y|TPI*Nj`UXeU`GS*MyNo2EFk99VX2dxw3h-Z+}3_(pZDYFRd> zT&5l-m(0VxdOJpRZE9IpvU86i9zL};>R5KndN;b)ed6ErA8;Og&Ewzv9zc&ykZG< zfNokkCDCf@+_DCS=}*vV^EVrn_f$HdLKkS^XJ~X)C1{7twDw4tHo#YcF` zMWya+gc%LCPJw*km91x3A%%h`*W|%4qSQt|0^>lQnj*6dF8YLfs{lW;un8@j3pSvQISScq zl!5hc(Kd4Y+rfL?4GQrOHkQ()x!V@AoEqgkk0ZU88?`Tb>Ey+!dSC3UiI~50v<#Ub zkOrB~*Dki_syT;!shqM2(qd=;qQr*sO!q7q-|iBzP!Nk`J|;zc!D0*l{sXBnGTsUk z@dLst{RE;KI2%68dpUU{gmMZ-_W9eVShC)Xxj8WP8)k|6g!zmtjXS@S;Ub=!pj;E4Xtb~G~7!{rbA=UR5p*j|#{BHffel@#~tXOOtb=q(2g z0p%|LKw8mLFR6ZF<=b#w@Pzrmgl?JK4%pS)g$y6$V4z1_=fzSu2{gCYOKut4m`CnF z(DPwWD-Mx_4@A6mptQ9zN72HKp&Cvghdo2Uu3=H4HMB0Bu#Oc2rvtzf6==dp6F5UL z-i09it>`fRYt~kmaEOh?nR$=r(f`TMcs25e?8HO8Z$2)XgCP8_t5hb~P)Jqb&5Zj* z_}cb~E|3_dYR}L&;{q>^0!XibxJ667Mz_V8T-ghJ(Z0rzSQ&+gjO@;km(H7NXchg} zIvuW-g7$1KF%crBC~H7*#Gg%?#i(RjLAb4cPtJ3kV3fixsq9s_6d)&E=#ZY&m4GNN zWPYbvXfdq|_Ylht4StyM4CDURK(Y6b{-(OGdg2Xly-^v5c-UXBmfDxI-5%U4-6GFUW8nLKzYCPyI#E_cpwb zuN{Q*DJElLLW%lzi@Ats3|fAeh3X*%Q&Og>y<^Y1{tSPDHL}3?H_5#@muBAQVCLf%%RwYNDnv*BC$@~`@rcCbw|7* zT8#DI8w?yD#YP30*VhQF{@fmIqH-BlO%Nq6L)&r^TTMa{4i4{`FLfr0tTygfr`aJ% zD=`RXgs@^nz9k)<@T=CGFdJ&&xp|-nNNK>Y$84?FFvK@GR}l!K3?)d15Ag?&BkLkK z=52PSiGcrDk(bbQT^iwr6d5|I`oWKU|I!Jixl^RFfYPqdSmsJB)q?exz~B$Pzoevq zr$OqJ4vjN$tc-24ni0Ze~vuaJ{CH!b+IPWGT5sy8EMmH>53-`t-)kaPzEuU`~yJvXw=HGy}F|wA2Jzf`wK@jN|9;p0;r$nLdz6lC%lNm9}xppmXpvx`5SDh7F#3GW8~%2f9RRK8shdoJ5^ToTz*l8WC})RSrsSg}Mz{!y7IQ`*1GdeL?=TRxgb`6P z!b=;}7S`)Q*0B~Js}vbuBv<1fvDZcd5nkI;fkkgl9D#TX6Gd1ReQ6Tvu1ni!7r72X=lm-!^ZAH87LusFcfyZ7ly32=zCSP5oD{*zlRAZy* z;)2jm)8#7rQLJA(c-rF4tMKpMe{|*Bqw5+pHs8(Poex0FdBz9wA=^jYe%FApKh7kX5@7Td?+!DZQOyGzE^%hBcZ>%dN=>&g@0bg^TM44fKg9# zg-S3Wy8%V~F60qcA|x|J$=(&`We$;Mp*m68D6)fpa=7@#wdW1o_$Ulz&IM8yq0+$w zOo7%qn9EdZmqw{l}fi+z7Acox;Fqu^(&O5KGndH zcdz|OZjbZ}ta9K<)LPKe)T7aHm}N8cFct6|h%Udu1OdE(&_?Ptg)(c4qW#r$+v#D< zmSxPs!A39^YQ~drE-go$a}cid^k>l}i&`oPz2E}5Qe?tXgej>D{-x9j(U=R>wv2GS znu@P_fnUnVwt5QWSOV+JL^B#jOZt{keFbTi8{i;=21BLBA7Tbcb~fm$xNcDGR~~eX zq0Vv&Tj!aljOpM|^~9iBIaa?KG>b~)n!wt5!16tKPhqXfScqb41jB<{K(JxR%e#yh zK$ZGCTqfj?j2{u;3$z4Tu-%M*jC9f3ZNj1)wg^rLB1W=?Lth{wLBA#2xwM>zUV@XXk+8F4|f~cPMZuXdmiWm0jdPW3Ly)F4v^nQ$$UtsQzogPyaI& z4slT|f%MAO-vVbt`tM1!REh8_KFaNIf z5UGuC=sQAH-e}n-l(2E%-HKeo(+K=BP=+@|v9NcfKlaQU1N8gNVz2N)EA;0wB*+V3bqEl z@0eCWtuf6?O{|up92_W{V(5Az2R}2q8+0?rBNTyuin$T)e6Kz06i~>P6ugCm(q9M+ zd%bYp1~>W&c$+q6d~EVk$%XWJH35M69BZ^{>ZMNWEsg!McVsEoDq)zWWTJF1FSqMS zvl;UAUM|(`wip%4Qr=eOnTy<7-0x+3%&;^-R^(gd(mVaCIvh{T1v|=vKe+>Nn&3bo z>?u?n?iI)p6g1MLSI8M-jl!a>`@wIc(zC@Xz`H|pkg`ht*s3q(yNobOlH+?1N z9o+d4=8>{2GheIf67NhRoZ7YyFdFyhlO&@7nTt78WmU=EBgn5PlcY!Q zN#Yz^9_SM&H;bj?Pyg757B|cuG=mYk^?4fmDZ<7dxiiO(BkU#WrD$+^+w@bgQX*d= zQLDRz`TamAYA%H&&GgJ-*TkMKXl;xBUBr2s;{-j3$ zL>)D}QLf$gb3kO0&6m=}m$gg=`cf8^vxkzqZW-BPv6OVtW!fE0$zP={5?xbGJlan+ zHl(;NO!o9PRSb=>*jNm-S=~OmsLvDvXSrH(e77D9{pke4XWONZqV8b$x4ArXSDqq3 zRLP6A>QVte75+G@wK#X_E0L|FK3DK+^eUBC60gwPazXl>znL<2B)3z_11(=UtJY1~ zIpOSp3yn!KtW9p7K>Lxt%CJ3}JB;s6Jw@J&DAhxP{gx%o0Tr2tC6`^!Un9GMjjRD@ zb?9G?k78OW0W_w*p7;!^Qc*%;)ozUt%5IuWanXK4GaNw28<#d}ii%haIWZOxsa6E+ z_x=kcZR>x6ENAY&jfIGVNGi?H*B2Wr%U;Y?P77eZ!nzeN-9+AUH0^;yW62nC#77uWG)t(Z;I%Bad3!g5?xI-E4rM5e{>b?4Oj4^?)e{V zb?}Bb5lm?egG6mN0Qry?L!GxlpPk(?uZx?i|@d#7PO=~(WYL~x< zF%$sU@D!!cY9m~;`0z9k$@U!Svg5=wh&LnC_0-#S&DDUvqJ;6@6B;oa>JA4;U9P<^ z*&{u9&Y^`Q)!L|K++9<@#YlMr^#S--pp&2mbJ#rcz2`@UIz?5P18Hi!>d71md!`v$ zmq~#`fqwv~6`lnMh$gnA#Y4gs=ArP_h`hK|8pMVz_@{JnB(fH?VfHGo%}v56Ai4q~ z8_Ud3aZZ4s&)?zA(I5p(S3q{B!UCa3-qfSW>(K;+un)N+g4>~MD${4E6B`Edy^hh0 z6K%foY&B0cwz)1&*!L=Kvlbl!-+LP66x%oV5PjeZ;jA?t<>!Q#;x=EzzXOLl2M-?0 z!TMGqAV9T+(XJiH2rof49r{)nElK=ql0!m8Vb6q)f#m1P*u)LAE&B63%Hd-Kk8m$s zVQBm9KYFL`Gb)K5hkU~edfR2cL}&=F70VhVE68dRvd&gZ-S?SBJS8k8)xqz8Y=$xD z5t14YVod1l7A21Ur zeY%EK{s_e;C(0{V2wL>S-Z8M*Z3XIe2)F1nYF8m=h3Sp-WI<;d%$=ZBC|b@u_1fHC z%}z4_NW@9kt36o|Y#f3CtEi%37`(C$MljWc>k|rVLgMwt?iV5Or${!+q3(1JUkBAgBnV(|s@{h_d`3tsfwT3d9lvG7iMLc!`)#y`zowy6Q zt4QVc=UKZbacLzu;#jm3CnhU&%@m?Wy;xI-@$!rO1Osmgw}Ry0FCDK@cV}=R&#@Z- zcR_7}));2NoS$8(FKWrBM>8@|I7kWp$F~#@PK!}Xdj`$rz;|$FxE!+qETeH=-I>@K zQnOM8%#W!01;tZFH}3QgCl`mxm|wvGxk`s}0nXu8Y^5bh6MgJ-s}v3kfAQ z>QAf1qkyJ>p-QPCrA1{Mm_mXm1m=oW$&z$)mBQZ{W4lx5=nI<7&h-=7SkA1Vf_(ASb{B!}su!L+n4$DJEZl|C`{H@~R_%t}eWz5;v^q%~qmHDAatl&oFe z0XlC!nbH#*C3-%&vVNBZ>nHPxwk(Qqw0uvzPekl{gcXF9WK*syb&t$%Ptf2iPAQ&s z2MI%s4z?q>5YTlR0ui;_7D=Wd7h6ykKNf5rPm~P<`#C|Pgck~MHNL9#Ifu251s#$asgoe5;L5-7*=R<0uR5_aEw?3(;^RYq58cO$yI<;9k|w0>2{l6 zU*IyWCP*}){^xBH{a?bsK)2CgKG)J&`+n_<&~JG3tjgAns#t2LCcblJ?uyqE@C0B( zqBf%7YqJw?+w3A68vb@+0J>bs1n-L*seNqSd=SB~=c-?nEAi=>_Vk-arpj z>s#7VJEUCc?TFf`A&7f`nIH1NFI}!=yMiW-`V9ov`Z{56Rb~J(w%h~%87j-RML31> zwto?nY!YV;xtk@w{qDzd)kgbvU#!Q2!vRjS_|{0*0>?JKLoM(f+XgJ>?MZ~CVj(KR zr3Y5~1+v@gP})wiR%{PnfW$!hEGFagk+vKd{*#&;IO6Ownoy7G6%DZDt3Y-dN_c0L zpJW#Z4`X~IuH*$$Rs}&;{-UbF5!-s*sIZylfiD|PVX>v4OOm)(how@71vXD>kn0Xk zZo;nYTAi|$%A>!){qZZo<8Ln?w{6kwwQVbb;!(~~i2gAZXVboI!G z9~(9gO__vg0X?!=jq(|8sCt;hSxr0PwwO0)*K+8r`BR=k_huu(pdAv0Y4g6G$lE`I zwWqF`JRh!@j3~pZPr|wm)8^kr^CL^#NaK12AISoP8!>PF(#m{N*;nbTF3S8hxfgss zUVdAK%pck~21DkX42Zediia%45G#FU3?8$0&80@E&QP`4FjuUC`{HP2D_b*2KfE#< zL&?$Jwn9Nn$7AxvEI&!%#K^T?(Y?f=vUwV?b`Dz>g6z-qC6Vw~Nv8R@Kg^v(e>UT5 z&hZEH&Afmau&~<{l6v#2@Sb3kqEa@BCol`3KgY=J#BIR00FsCFo~RLe?W9W|D%nQ} zk3-Fk32Qk80axl@%*{QO339b5skDn%yL>!j-?s*qe3BbAZXn~3Up+suK`rG@e}5pC zi^|e2bty4y+*nMKuYv`eii(Zk>?xS@H#JQQo@NDfYln_y`h@8+ zZ0-(w-Z%I&bLbUz(!1Uxmju$W8DY}PYubq}{8TjL|6%B3D1NGs!7ibyODh-n7W~}y z3&{GE=)IhyOu2zHavR8@a#=#Ye zFMr7w?%s^vJ9uGH9*l_>^Qt=$SESX8@H5|F-8i*9W$qNZOCb=9^gL5Bnw)tWm5$t# znbin>L5(d*HQ@)fdV>#I^KoK-gVLBKG1<#?U9;NzWeG$k5b8lQ*B9mcilBj2p}f=Z z(Nv#FNKu1nb`8vtNO+o=U9a9lcn?Z&QwZFFmaZIK`JSV~uynTKgLAZXv0-~VgVaT% zFZ|ENvvheFi$C*;;@C@sKT{~Cq;QY}EXuZ!!{(8dxp9WjbosB6cowkF`SZ2EGkZ!2 zC9mz?>$=SIgv@WXR{rE(j!RuRy542bER%RS9S{HQ}Xh~&{DS5S(pYKt+c zNxLd9>ytG~1n|=Yb*xwXeIUFqUw5f*fxEi}x1KO#TS@ubC3(@a=lMO4QelmYc{Yz` zuY#GXM>9PtO(TYbYEk-8+wu*|Z}dKVIfBYN)Mc0%F+0_6yIJWHgmH&`L1u`wi96j7 zM&<8VL35HrZU^@pq_QXfYagiKMOA=*(6tIzRU3jU1!};l2BIsENr_7)n&GCNjTNP4 zU8wIOsKAl|j^d~h&S_tF*n4GQw-=JV=enri^xf`ddXr7srB9%)g=e~QFhzsT_c}Wq zPe{iaqS~y}%}D6s$nRT*PT8PFbyh>tBgIqGLw>LaWGi7rp!3&uY%ynhG|Jf%C^N)| zXvf6IVpL1q%8rQHSg0D+6+^bKYcP6a{_=1jc9Ldg^!Nt#PTYHb0+7eM@^>$=u0Iog z98JPKCHSR2V;PB89AX1dZxP#w6P3n?B=Lt?wEA>ebay~s+@6O^OE;^{MTsJ*qOC$qHpT>kumCX2sbUqJ!EI!jA4v!%2c zMeD+tWVcR9(@wli=i^uKC~gwL|*I&X!F`q&ZoJjRm$z$yhbx_Z}I3KlJETMl2Z?AoH|e; ziNjER=pd4w8CKz)mwLINDNtg&IxOS-@sxdx_8Hr^RrlMeNuOMi!E?V{cSMrWjBjPQ zva)~R(OUJ(wSbFh{R@sk%1zd3NX)bR_>~UuHm1Dwga{iE?V`ceTi%y`ORx{u2UyDj zI#L$d=NT4O5-pRDAGQ2DzN@CtUS8;8pTu(&gS(Ba@IQp8`(;r_ck--9xk%Sp3}hW? zIIwb4HS6QHVxdELG5^8sJ{8-$GDL1)1%u2#mpl^M_=p#G=!1$#=tr?xa2wBB9lW8* z+Fw6Apjim?B7=v=0o8@tlOt=lsDuNh_YO&!z^=l%RhKuf{vU45D5nZhk@R!0r6n zMvHGN^XP1AbLjL480Flc^_K0f^6}*p$Yop^^>Xp8AfQUtFK;I>_QjN4v=FxtQyV5tZ5^8Yz90FX>~70YOWE4m=lMrqwzE`HqjHZBYXn) zd%4qg{Kz~$RcdgzGrb85h8W{7oiVv%SB7ql;A6*Xyrz1OVRwb)5S?bJGt43SXs@Q? zDJ7d%ddn&D?U7P3i*5(?67lCc*#2=mreHIm<(R+QmRO<`&(>`G;p*a~Bfputs(Upy zvQJp=^^>|5%>U2&VHCK627d7v71^o&`N4MpypY*2{5<>iFdX6tDTF({<`)6FXzo6a z(7wMXfNDkf|7K^MlyF^5z2t~ zH_~NDhcrU|4E?hV;15CVs6bLUDF_|w9^)&|hRq*83L$sV6WDth@cZ_E4Y6?cxb0JgKdx8`&Bp!#|ivCwtE7^=!8m|)o}qV7?-NH@GQLEvnfPX_G8eN zKRyDp^LQ)cxrb}MZ(LC8YN@!Z;9@Rw18WdKdh86cPwdNdSk_#>K}0ZxJxJjMkcmDv zCh2s#Q=&lGg}RPLN`W^kzkQU#fXF>;)+>9w+9R%QP zk0~yn)tju?*ow&P_PQDUxa)m+;$G}=bI5f$U#$35roavlMH&K8%r->qPneJ13%=5q z8#@c*;>mlS>*eslHNyS7|AEU>L9=nw?fy3=cs$a8@GTw^0cKWxtAHt!NSxKJZm$3v zGjJww(UG<%L9+k{Hw*7$E1`(~AX4K)yf!8dv3&d&ZSxn{Fh7hwTo%72^jK5iiIcKZ zb{oO{ZFTs`0n|9d=ty|@GGV2gkmaXXNHx#CNE?Nwt*HL20Q%__XV^#$?$gj0lE~kp z-L2!0*P*E%&N=JT{P8wPTU#>Cg%6*~ul1EOL2;AS`htg4hg!3jR;SS3o?Ns$k4dy! z%Q&cc(A&)6xjCpi`JUXK+)sRA6~X$|$?bkO929JBKhO+^0dLK!F?m&}c!$%QO?EWt zYN47yW7z2&%8(V8>=)*D$zJ@x?!+G3l-02HU6LlQ&F4nQUTAS_>O%YW1GBGfY5nB} zoCzFH4H)vVTLusrUOq{Y@ql^oBcK$zLEh9oUyc-4stSl+pWx4e^u}2!Dwg0++u#^& zDv7tt4g{H;LO*z!fIyCMp={IBzG~ zoOLrsX~7i>87T|yTKTqq2pro%BJ1p=(6%Kx05kNt?9A@Nw;R8Fbmt9XqYn}n*aUo1 zB)OfhS)Hcei&8u|HH17!MY8E6cH+E*Z5ON>zmzo-`Mjm78iaxf+5J zBEEXa{dHY|;KfL1aZlwB$G`L3$~R0s-q0Y=G#l2?Jle)Zufh;oT99Q&c?>0ODL?A6 zBh7>J9po;J``~4!6mG;Y)5p~&CQ)5`Q`)i$S~lv3I60PAI3+5S0hHXlik0gXi@REW zbIiTH4Rf+7sSX|O_IatwZYc3kf5Jtt>DGYYndkgwcQ13;ye�R0pl!Gh|V83jf>^ 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

      Sve@6z;dti&qM@hjdwzFR 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 #Y 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 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2025-04-v5.3.pdf b/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/2025-04-v5.3.pdf deleted file mode 100644 index 8bf812ff58399b33262c251e00a3209a424becd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 154227 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

      `xU97POli2)8@K8~oE=v*$x$kp+UxvCFT}>lH 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⩔`B>BA9Z-U8vxzY|EBK5G$+e^28MB@HS{vO%&j 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 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/README.md deleted file mode 100644 index cba0f2f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/audits/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Audits - -| Date | Version | Commit | Auditor | Scope | Links | -| ------------- | ------- | -------------------------------------------------------------------------------- | ------------ | -------------------- | ----------------------------------------------------------- | -| April 2025 | v5.3.0 | [`d4b2e98`](https://github.com/openzeppelin/openzeppelin-contracts/tree/d4b2e98) | OpenZeppelin | v5.3 Changes | [🔗](./2025-04-v5.3.pdf) | -| December 2024 | v5.2.0 | [`98d28f9`](https://github.com/openzeppelin/openzeppelin-contracts/tree/98d28f9) | OpenZeppelin | v5.2 Changes | [🔗](./2024-12-v5.2.pdf) | -| October 2024 | v5.1.0 | [`aba9ff6`](https://github.com/openzeppelin/openzeppelin-contracts/tree/aba9ff6) | OpenZeppelin | v5.1 Changes | [🔗](./2024-10-v5.1.pdf) | -| October 2023 | v5.0.0 | [`b5a3e69`](https://github.com/openzeppelin/openzeppelin-contracts/tree/b5a3e69) | OpenZeppelin | v5.0 Changes | [🔗](./2023-10-v5.0.pdf) | -| May 2023 | v4.9.0 | [`91df66c`](https://github.com/openzeppelin/openzeppelin-contracts/tree/91df66c) | OpenZeppelin | v4.9 Changes | [🔗](./2023-05-v4.9.pdf) | -| October 2022 | v4.8.0 | [`14f98db`](https://github.com/openzeppelin/openzeppelin-contracts/tree/14f98db) | OpenZeppelin | ERC4626, Checkpoints | [🔗](./2022-10-ERC4626.pdf) [🔗](./2022-10-Checkpoints.pdf) | -| October 2018 | v2.0.0 | [`dac5bcc`](https://github.com/openzeppelin/openzeppelin-contracts/tree/dac5bcc) | LevelK | Everything | [🔗](./2018-10.pdf) | -| March 2017 | v1.0.4 | [`9c5975a`](https://github.com/openzeppelin/openzeppelin-contracts/tree/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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/.gitignore b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/.gitignore deleted file mode 100644 index 893adcd..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/.gitignore +++ /dev/null @@ -1 +0,0 @@ -patched diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/Makefile b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/Makefile deleted file mode 100644 index d57d2ff..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -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 | $(DST) - @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 | $(DIFF) - @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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/README.md deleted file mode 100644 index ff2ccdf..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# 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 is 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/diff/access_manager_AccessManager.sol.patch b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/diff/access_manager_AccessManager.sol.patch deleted file mode 100644 index cfb6cdf..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/diff/access_manager_AccessManager.sol.patch +++ /dev/null @@ -1,97 +0,0 @@ ---- 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 adminRestricted, uint64 roleAdminId, uint32 executionDelay) { -+ ) internal view returns (bool adminRestricted, 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol deleted file mode 100644 index e96883f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol +++ /dev/null @@ -1,46 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessControlHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessControlHarness.sol deleted file mode 100644 index e862d3e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessControlHarness.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {AccessControl} from "../patched/access/AccessControl.sol"; - -contract AccessControlHarness is AccessControl {} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagedHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagedHarness.sol deleted file mode 100644 index 50be23a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagedHarness.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import "../patched/access/manager/IAccessManager.sol"; -import "../patched/access/manager/AccessManaged.sol"; - -contract AccessManagedHarness is AccessManaged { - bytes internal SOME_FUNCTION_CALLDATA = abi.encodeCall(this.someFunction, ()); - - constructor(address initialAuthority) AccessManaged(initialAuthority) {} - - function someFunction() public restricted() { - // Sanity for FV: the msg.data when calling this function should be the same as the data used when checking - // the schedule. This is a reformulation of `msg.data == SOME_FUNCTION_CALLDATA` that focuses on the operation - // hash for this call. - require( - IAccessManager(authority()).hashOperation(_msgSender(), address(this), msg.data) - == - IAccessManager(authority()).hashOperation(_msgSender(), address(this), SOME_FUNCTION_CALLDATA) - ); - } - - function authority_canCall_immediate(address caller) public view returns (bool result) { - (result,) = AuthorityUtils.canCallWithDelay(authority(), caller, address(this), this.someFunction.selector); - } - - function authority_canCall_delay(address caller) public view returns (uint32 result) { - (,result) = AuthorityUtils.canCallWithDelay(authority(), caller, address(this), this.someFunction.selector); - } - - function authority_getSchedule(address caller) public view returns (uint48) { - IAccessManager manager = IAccessManager(authority()); - return manager.getSchedule(manager.hashOperation(caller, address(this), SOME_FUNCTION_CALLDATA)); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagerHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagerHarness.sol deleted file mode 100644 index 69295d4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/AccessManagerHarness.sol +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import "../patched/access/manager/AccessManager.sol"; - -contract AccessManagerHarness is AccessManager { - // override with a storage slot that can basically take any value. - uint32 private _minSetback; - - constructor(address initialAdmin) AccessManager(initialAdmin) {} - - // FV - function minSetback() public view override returns (uint32) { - return _minSetback; - } - - function canCall_immediate(address caller, address target, bytes4 selector) external view returns (bool result) { - (result,) = canCall(caller, target, selector); - } - - function canCall_delay(address caller, address target, bytes4 selector) external view returns (uint32 result) { - (,result) = canCall(caller, target, selector); - } - - function canCallExtended(address caller, address target, bytes calldata data) external view returns (bool, uint32) { - return _canCallExtended(caller, target, data); - } - - function canCallExtended_immediate(address caller, address target, bytes calldata data) external view returns (bool result) { - (result,) = _canCallExtended(caller, target, data); - } - - function canCallExtended_delay(address caller, address target, bytes calldata data) external view returns (uint32 result) { - (,result) = _canCallExtended(caller, target, data); - } - - function getAdminRestrictions_restricted(bytes calldata data) external view returns (bool result) { - (result,,) = _getAdminRestrictions(data); - } - - function getAdminRestrictions_roleAdminId(bytes calldata data) external view returns (uint64 result) { - (,result,) = _getAdminRestrictions(data); - } - - function getAdminRestrictions_executionDelay(bytes calldata data) external view returns (uint32 result) { - (,,result) = _getAdminRestrictions(data); - } - - function hasRole_isMember(uint64 roleId, address account) external view returns (bool result) { - (result,) = hasRole(roleId, account); - } - - function hasRole_executionDelay(uint64 roleId, address account) external view returns (uint32 result) { - (,result) = hasRole(roleId, account); - } - - function getAccess_since(uint64 roleId, address account) external view returns (uint48 result) { - (result,,,) = getAccess(roleId, account); - } - - function getAccess_currentDelay(uint64 roleId, address account) external view returns (uint32 result) { - (,result,,) = getAccess(roleId, account); - } - - function getAccess_pendingDelay(uint64 roleId, address account) external view returns (uint32 result) { - (,,result,) = getAccess(roleId, account); - } - - function getAccess_effect(uint64 roleId, address account) external view returns (uint48 result) { - (,,,result) = getAccess(roleId, account); - } - - function getTargetAdminDelay_after(address target) public view virtual returns (uint32 result) { - (,result,) = _getTargetAdminDelayFull(target); - } - - function getTargetAdminDelay_effect(address target) public view virtual returns (uint48 result) { - (,,result) = _getTargetAdminDelayFull(target); - } - - function getRoleGrantDelay_after(uint64 roleId) public view virtual returns (uint32 result) { - (,result,) = _getRoleGrantDelayFull(roleId); - } - - function getRoleGrantDelay_effect(uint64 roleId) public view virtual returns (uint48 result) { - (,,result) = _getRoleGrantDelayFull(roleId); - } - - function hashExecutionId(address target, bytes4 selector) external pure returns (bytes32) { - return _hashExecutionId(target, selector); - } - - function executionId() external view returns (bytes32) { - return _executionId; - } - - // Pad with zeros (and don't revert) if data is too short. - function getSelector(bytes calldata data) external pure returns (bytes4) { - return bytes4(data); - } - - function getFirstArgumentAsAddress(bytes calldata data) external pure returns (address) { - return abi.decode(data[0x04:0x24], (address)); - } - - function getFirstArgumentAsUint64(bytes calldata data) external pure returns (uint64) { - return abi.decode(data[0x04:0x24], (uint64)); - } - - function _checkAuthorized() internal override { - // We need this hack otherwise certora will assume _checkSelector(_msgData()) can return anything :/ - require(msg.sig == _checkSelector(_msgData())); - super._checkAuthorized(); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/DoubleEndedQueueHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/DoubleEndedQueueHarness.sol deleted file mode 100644 index d684c73..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/DoubleEndedQueueHarness.sol +++ /dev/null @@ -1,58 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20FlashMintHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20FlashMintHarness.sol deleted file mode 100644 index 2f989b2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20FlashMintHarness.sol +++ /dev/null @@ -1,36 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20PermitHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20PermitHarness.sol deleted file mode 100644 index 08113f4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20PermitHarness.sol +++ /dev/null @@ -1,16 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20WrapperHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20WrapperHarness.sol deleted file mode 100644 index ca183ad..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC20WrapperHarness.sol +++ /dev/null @@ -1,34 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC3156FlashBorrowerHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC3156FlashBorrowerHarness.sol deleted file mode 100644 index 1c76da2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC3156FlashBorrowerHarness.sol +++ /dev/null @@ -1,13 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC721Harness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC721Harness.sol deleted file mode 100644 index 69c4c20..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC721Harness.sol +++ /dev/null @@ -1,33 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC721ReceiverHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC721ReceiverHarness.sol deleted file mode 100644 index 3843ef4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/ERC721ReceiverHarness.sol +++ /dev/null @@ -1,11 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/EnumerableMapHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/EnumerableMapHarness.sol deleted file mode 100644 index 6155193..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/EnumerableMapHarness.sol +++ /dev/null @@ -1,55 +0,0 @@ -// 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 _positionOf(bytes32 key) public view returns (uint256) { - return _map._keys._inner._positions[key]; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/EnumerableSetHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/EnumerableSetHarness.sol deleted file mode 100644 index 09246de..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/EnumerableSetHarness.sol +++ /dev/null @@ -1,35 +0,0 @@ -// 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 _positionOf(bytes32 value) public view returns (uint256) { - return _set._inner._positions[value]; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/InitializableHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/InitializableHarness.sol deleted file mode 100644 index 743d677..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/InitializableHarness.sol +++ /dev/null @@ -1,23 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/NoncesHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/NoncesHarness.sol deleted file mode 100644 index beea5fd..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/NoncesHarness.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {Nonces} from "../patched/utils/Nonces.sol"; - -contract NoncesHarness is Nonces { - function useNonce(address account) external returns (uint256) { - return _useNonce(account); - } - - function useCheckedNonce(address account, uint256 nonce) external { - _useCheckedNonce(account, nonce); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/Ownable2StepHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/Ownable2StepHarness.sol deleted file mode 100644 index 09a5faa..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/Ownable2StepHarness.sol +++ /dev/null @@ -1,10 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/OwnableHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/OwnableHarness.sol deleted file mode 100644 index 79b4b1b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/OwnableHarness.sol +++ /dev/null @@ -1,10 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/PausableHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/PausableHarness.sol deleted file mode 100644 index 5977b92..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/PausableHarness.sol +++ /dev/null @@ -1,18 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/TimelockControllerHarness.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/TimelockControllerHarness.sol deleted file mode 100644 index 95ae406..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/harnesses/TimelockControllerHarness.sol +++ /dev/null @@ -1,13 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2021-10.pdf b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2021-10.pdf deleted file mode 100644 index 22df9c61e6a9f74b29f90b6e36bd3d04f99756f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 92882 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 aXJ@ZxYwu)>@+&A9#pUoWT@sTO$NL{da>MEX diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2022-03.pdf b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2022-03.pdf deleted file mode 100644 index b6ff81d1812c808e2f683c1e5fe10abf71ba5438..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199401 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

      E02esqZ$^2gTs{2 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 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2022-05.pdf b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/reports/2022-05.pdf deleted file mode 100644 index f24a44910c4fba449300987456b5f440e7f99511..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 132223 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%0D7|ieYKPVYBX59b!U}f9eB5UvK%HwkWL{dR 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 UVZ$VVhf9Eu51oMlq$-2{KaJIBBLDyZ diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/run.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/run.js deleted file mode 100755 index 91f4a6a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/run.js +++ /dev/null @@ -1,168 +0,0 @@ -#!/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 - -import { spawn } from 'child_process'; -import { PassThrough } from 'stream'; -import { once } from 'events'; -import path from 'path'; -import yargs from 'yargs'; -import { hideBin } from 'yargs/helpers'; -import pLimit from 'p-limit'; -import fs from 'fs/promises'; - -const argv = yargs(hideBin(process.argv)) - .env('') - .options({ - all: { - alias: 'a', - type: 'boolean', - }, - spec: { - alias: 's', - type: 'string', - default: path.resolve(import.meta.dirname, 'specs.json'), - }, - parallel: { - alias: 'p', - type: 'number', - default: 4, - }, - verbose: { - alias: 'v', - type: 'count', - default: 0, - }, - options: { - alias: 'o', - type: 'array', - default: [], - }, - }) - .parse(); - -function match(entry, request) { - const [reqSpec, reqContract] = request.split(':').reverse(); - return entry.spec == reqSpec && (!reqContract || entry.contract == reqContract); -} - -const specs = JSON.parse(fs.readFileSync(argv.spec, 'utf8')).filter(s => argv.all || argv._.some(r => match(s, r))); - -const limit = pLimit(argv.parallel); - -if (argv._.length == 0 && !argv.all) { - console.error(`Warning: No specs requested. Did you forget 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 = 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 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 ? ':heavy_check_mark:' : ':x:', - url ? `[link](${url?.replace('/output/', '/jobStatus/')})` : 'error', - url ? `[link](${url})` : 'error', - ), - ); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs.json deleted file mode 100644 index a894190..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs.json +++ /dev/null @@ -1,110 +0,0 @@ -[ - { - "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": "AccessManager", - "contract": "AccessManagerHarness", - "files": ["certora/harnesses/AccessManagerHarness.sol"], - "options": ["--optimistic_hashing", "--optimistic_loop"] - }, - { - "spec": "AccessManaged", - "contract": "AccessManagedHarness", - "files": [ - "certora/harnesses/AccessManagedHarness.sol", - "certora/harnesses/AccessManagerHarness.sol" - ], - "options": [ - "--optimistic_hashing", - "--optimistic_loop", - "--link AccessManagedHarness:_authority=AccessManagerHarness" - ] - }, - { - "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"] - }, - { - "spec": "Nonces", - "contract": "NoncesHarness", - "files": ["certora/harnesses/NoncesHarness.sol"] - } -] diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessControl.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessControl.spec deleted file mode 100644 index 70b0672..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessControl.spec +++ /dev/null @@ -1,119 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessControlDefaultAdminRules.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessControlDefaultAdminRules.spec deleted file mode 100644 index 5860fd5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessControlDefaultAdminRules.spec +++ /dev/null @@ -1,464 +0,0 @@ -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 renouncing │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -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 renouncing"; -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ 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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManaged.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManaged.spec deleted file mode 100644 index adcb859..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManaged.spec +++ /dev/null @@ -1,34 +0,0 @@ -import "helpers/helpers.spec"; -import "methods/IAccessManaged.spec"; - -methods { - // FV - function someFunction() external; - function authority_canCall_immediate(address) external returns (bool); - function authority_canCall_delay(address) external returns (uint32); - function authority_getSchedule(address) external returns (uint48); -} - -invariant isConsumingScheduledOpClean() - isConsumingScheduledOp() == to_bytes4(0); - -rule callRestrictedFunction(env e) { - bool immediate = authority_canCall_immediate(e, e.msg.sender); - uint32 delay = authority_canCall_delay(e, e.msg.sender); - uint48 scheduleBefore = authority_getSchedule(e, e.msg.sender); - - someFunction@withrevert(e); - bool success = !lastReverted; - - uint48 scheduleAfter = authority_getSchedule(e, e.msg.sender); - - // can only call if immediate, or (with delay) by consuming a scheduled op - assert success => ( - immediate || - ( - delay > 0 && - isSetAndPast(e, scheduleBefore) && - scheduleAfter == 0 - ) - ); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManager.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManager.spec deleted file mode 100644 index cc4b013..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/AccessManager.spec +++ /dev/null @@ -1,826 +0,0 @@ -import "helpers/helpers.spec"; -import "methods/IAccessManager.spec"; - -methods { - // FV - function canCall_immediate(address,address,bytes4) external returns (bool); - function canCall_delay(address,address,bytes4) external returns (uint32); - function canCallExtended(address,address,bytes) external returns (bool,uint32); - function canCallExtended_immediate(address,address,bytes) external returns (bool); - function canCallExtended_delay(address,address,bytes) external returns (uint32); - function getAdminRestrictions_restricted(bytes) external returns (bool); - function getAdminRestrictions_roleAdminId(bytes) external returns (uint64); - function getAdminRestrictions_executionDelay(bytes) external returns (uint32); - function hasRole_isMember(uint64,address) external returns (bool); - function hasRole_executionDelay(uint64,address) external returns (uint32); - function getAccess_since(uint64,address) external returns (uint48); - function getAccess_currentDelay(uint64,address) external returns (uint32); - function getAccess_pendingDelay(uint64,address) external returns (uint32); - function getAccess_effect(uint64,address) external returns (uint48); - function getTargetAdminDelay_after(address target) external returns (uint32); - function getTargetAdminDelay_effect(address target) external returns (uint48); - function getRoleGrantDelay_after(uint64 roleId) external returns (uint32); - function getRoleGrantDelay_effect(uint64 roleId) external returns (uint48); - function hashExecutionId(address,bytes4) external returns (bytes32) envfree; - function executionId() external returns (bytes32) envfree; - function getSelector(bytes) external returns (bytes4) envfree; - function getFirstArgumentAsAddress(bytes) external returns (address) envfree; - function getFirstArgumentAsUint64(bytes) external returns (uint64) envfree; -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Helpers │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -definition isOnlyAuthorized(bytes4 selector) returns bool = - selector == to_bytes4(sig:labelRole(uint64,string).selector ) || - selector == to_bytes4(sig:setRoleAdmin(uint64,uint64).selector ) || - selector == to_bytes4(sig:setRoleGuardian(uint64,uint64).selector ) || - selector == to_bytes4(sig:setGrantDelay(uint64,uint32).selector ) || - selector == to_bytes4(sig:setTargetAdminDelay(address,uint32).selector ) || - selector == to_bytes4(sig:updateAuthority(address,address).selector ) || - selector == to_bytes4(sig:setTargetClosed(address,bool).selector ) || - selector == to_bytes4(sig:setTargetFunctionRole(address,bytes4[],uint64).selector) || - selector == to_bytes4(sig:grantRole(uint64,address,uint32).selector ) || - selector == to_bytes4(sig:revokeRole(uint64,address).selector ); - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Invariant: executionId must be clean when not in the middle of a call │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -invariant cleanExecutionId() - executionId() == to_bytes32(0); - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Invariant: public role │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -invariant publicRole(env e, address account) - hasRole_isMember(e, PUBLIC_ROLE(), account) && - hasRole_executionDelay(e, PUBLIC_ROLE(), account) == 0 && - getAccess_since(e, PUBLIC_ROLE(), account) == 0 && - getAccess_currentDelay(e, PUBLIC_ROLE(), account) == 0 && - getAccess_pendingDelay(e, PUBLIC_ROLE(), account) == 0 && - getAccess_effect(e, PUBLIC_ROLE(), account) == 0; - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Invariant: hasRole is consistent with getAccess │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -invariant hasRoleGetAccessConsistency(env e, uint64 roleId, address account) - hasRole_isMember(e, roleId, account) == (roleId == PUBLIC_ROLE() || isSetAndPast(e, getAccess_since(e, roleId, account))) && - hasRole_executionDelay(e, roleId, account) == getAccess_currentDelay(e, roleId, account); - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Functions: canCall, canCallExtended, getAccess, hasRole, isTargetClosed and getTargetFunctionRole do NOT revert │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule noRevert(env e) { - require nonpayable(e); - require sanity(e); - - address caller; - address target; - bytes data; - bytes4 selector; - uint64 roleId; - - canCall@withrevert(e, caller, target, selector); - assert !lastReverted; - - // require data.length <= max_uint64; - // - // canCallExtended@withrevert(e, caller, target, data); - // assert !lastReverted; - - getAccess@withrevert(e, roleId, caller); - assert !lastReverted; - - hasRole@withrevert(e, roleId, caller); - assert !lastReverted; - - isTargetClosed@withrevert(target); - assert !lastReverted; - - getTargetFunctionRole@withrevert(target, selector); - assert !lastReverted; - - // Not covered: - // - getAdminRestrictions (_1, _2 & _3) - // - getSelector -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Functions: admin restrictions are correct │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule getAdminRestrictions(env e, bytes data) { - bool restricted = getAdminRestrictions_restricted(e, data); - uint64 roleId = getAdminRestrictions_roleAdminId(e, data); - uint32 delay = getAdminRestrictions_executionDelay(e, data); - bytes4 selector = getSelector(data); - - if (data.length < 4) { - assert restricted == false; - assert roleId == 0; - assert delay == 0; - } else { - assert restricted == - isOnlyAuthorized(selector); - - assert roleId == ( - (restricted && selector == to_bytes4(sig:grantRole(uint64,address,uint32).selector)) || - (restricted && selector == to_bytes4(sig:revokeRole(uint64,address).selector )) - ? getRoleAdmin(getFirstArgumentAsUint64(data)) - : ADMIN_ROLE() - ); - - assert delay == ( - (restricted && selector == to_bytes4(sig:updateAuthority(address,address).selector )) || - (restricted && selector == to_bytes4(sig:setTargetClosed(address,bool).selector )) || - (restricted && selector == to_bytes4(sig:setTargetFunctionRole(address,bytes4[],uint64).selector)) - ? getTargetAdminDelay(e, getFirstArgumentAsAddress(data)) - : 0 - ); - } -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Functions: canCall │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule canCall(env e) { - address caller; - address target; - bytes4 selector; - - // Get relevant values - bool immediate = canCall_immediate(e, caller, target, selector); - uint32 delay = canCall_delay(e, caller, target, selector); - bool closed = isTargetClosed(target); - uint64 roleId = getTargetFunctionRole(target, selector); - bool isMember = hasRole_isMember(e, roleId, caller); - uint32 currentDelay = hasRole_executionDelay(e, roleId, caller); - - // Can only execute without delay in specific cases: - // - target not closed - // - if self-execution: `executionId` must match - // - if third party execution: must be member with no delay - assert immediate <=> ( - !closed && - ( - (caller == currentContract && executionId() == hashExecutionId(target, selector)) - || - (caller != currentContract && isMember && currentDelay == 0) - ) - ); - - // Can only execute with delay in specific cases: - // - target not closed - // - third party execution - // - caller is a member and has an execution delay - assert delay > 0 <=> ( - !closed && - caller != currentContract && - isMember && - currentDelay > 0 - ); - - // If there is a delay, then it must be the caller's execution delay - assert delay > 0 => delay == currentDelay; - - // Immediate execute means no delayed execution - assert immediate => delay == 0; -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Functions: canCallExtended │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule canCallExtended(env e) { - address caller; - address target; - bytes data; - bytes4 selector = getSelector(data); - - bool immediate = canCallExtended_immediate(e, caller, target, data); - uint32 delay = canCallExtended_delay(e, caller, target, data); - bool enabled = getAdminRestrictions_restricted(e, data); - uint64 roleId = getAdminRestrictions_roleAdminId(e, data); - uint32 operationDelay = getAdminRestrictions_executionDelay(e, data); - bool inRole = hasRole_isMember(e, roleId, caller); - uint32 executionDelay = hasRole_executionDelay(e, roleId, caller); - - if (target == currentContract) { - // Can only execute without delay in the specific cases: - // - caller is the AccessManager and the executionId is set - // or - // - data matches an admin restricted function - // - caller has the necessary role - // - operation delay is not set - // - execution delay is not set - assert immediate <=> ( - ( - caller == currentContract && - data.length >= 4 && - executionId() == hashExecutionId(target, selector) - ) || ( - caller != currentContract && - enabled && - inRole && - operationDelay == 0 && - executionDelay == 0 - ) - ); - - // Immediate execute means no delayed execution - // This is equivalent to "delay > 0 => !immediate" - assert immediate => delay == 0; - - // Can only execute with delay in specific cases: - // - caller is a third party - // - data matches an admin restricted function - // - caller has the necessary role - // -operation delay or execution delay is set - assert delay > 0 <=> ( - caller != currentContract && - enabled && - inRole && - (operationDelay > 0 || executionDelay > 0) - ); - - // If there is a delay, then it must be the maximum of caller's execution delay and the operation delay - assert delay > 0 => to_mathint(delay) == max(operationDelay, executionDelay); - } else if (data.length < 4) { - assert immediate == false; - assert delay == 0; - } else { - // results are equivalent when targeting third party contracts - assert immediate == canCall_immediate(e, caller, target, selector); - assert delay == canCall_delay(e, caller, target, selector); - } -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ State transitions: getAccess │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule getAccessChangeTime(uint64 roleId, address account) { - env e1; - env e2; - - // values before - mathint getAccess1Before = getAccess_since(e1, roleId, account); - mathint getAccess2Before = getAccess_currentDelay(e1, roleId, account); - mathint getAccess3Before = getAccess_pendingDelay(e1, roleId, account); - mathint getAccess4Before = getAccess_effect(e1, roleId, account); - - // time pass: e1 → e2 - require clock(e1) <= clock(e2); - - // values after - mathint getAccess1After = getAccess_since(e2, roleId, account); - mathint getAccess2After = getAccess_currentDelay(e2, roleId, account); - mathint getAccess3After = getAccess_pendingDelay(e2, roleId, account); - mathint getAccess4After = getAccess_effect(e2, roleId, account); - - // member "since" cannot change as a consequence of time passing - assert getAccess1Before == getAccess1After; - - // any change of any other value should be a consequence of the effect timepoint being reached - assert ( - getAccess2Before != getAccess2After || - getAccess3Before != getAccess3After || - getAccess4Before != getAccess4After - ) => ( - getAccess4Before != 0 && - getAccess4Before > clock(e1) && - getAccess4Before <= clock(e2) && - getAccess2After == getAccess3Before && - getAccess3After == 0 && - getAccess4After == 0 - ); -} - -rule getAccessChangeCall(uint64 roleId, address account) { - env e; - - // sanity - require sanity(e); - - // values before - mathint getAccess1Before = getAccess_since(e, roleId, account); - mathint getAccess2Before = getAccess_currentDelay(e, roleId, account); - mathint getAccess3Before = getAccess_pendingDelay(e, roleId, account); - mathint getAccess4Before = getAccess_effect(e, roleId, account); - - // arbitrary function call - method f; calldataarg args; f(e, args); - - // values before - mathint getAccess1After = getAccess_since(e, roleId, account); - mathint getAccess2After = getAccess_currentDelay(e, roleId, account); - mathint getAccess3After = getAccess_pendingDelay(e, roleId, account); - mathint getAccess4After = getAccess_effect(e, roleId, account); - - // transitions - assert ( - getAccess1Before != getAccess1After || - getAccess2Before != getAccess2After || - getAccess3Before != getAccess3After || - getAccess4Before != getAccess4After - ) => ( - ( - f.selector == sig:grantRole(uint64,address,uint32).selector && - getAccess1After > 0 - ) || ( - ( - f.selector == sig:revokeRole(uint64,address).selector || - f.selector == sig:renounceRole(uint64,address).selector - ) && - getAccess1After == 0 && - getAccess2After == 0 && - getAccess3After == 0 && - getAccess4After == 0 - ) - ); -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ State transitions: isTargetClosed │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule isTargetClosedChangeTime(address target) { - env e1; - env e2; - - // values before - bool isClosedBefore = isTargetClosed(e1, target); - - // time pass: e1 → e2 - require clock(e1) <= clock(e2); - - // values after - bool isClosedAfter = isTargetClosed(e2, target); - - // transitions - assert isClosedBefore == isClosedAfter; -} - -rule isTargetClosedChangeCall(address target) { - env e; - - // values before - bool isClosedBefore = isTargetClosed(e, target); - - // arbitrary function call - method f; calldataarg args; f(e, args); - - // values after - bool isClosedAfter = isTargetClosed(e, target); - - // transitions - assert isClosedBefore != isClosedAfter => ( - f.selector == sig:setTargetClosed(address,bool).selector - ); -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ State transitions: getTargetFunctionRole │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule getTargetFunctionRoleChangeTime(address target, bytes4 selector) { - env e1; - env e2; - - // values before - mathint roleIdBefore = getTargetFunctionRole(e1, target, selector); - - // time pass: e1 → e2 - require clock(e1) <= clock(e2); - - // values after - mathint roleIdAfter = getTargetFunctionRole(e2, target, selector); - - // transitions - assert roleIdBefore == roleIdAfter; -} - -rule getTargetFunctionRoleChangeCall(address target, bytes4 selector) { - env e; - - // values before - mathint roleIdBefore = getTargetFunctionRole(e, target, selector); - - // arbitrary function call - method f; calldataarg args; f(e, args); - - // values after - mathint roleIdAfter = getTargetFunctionRole(e, target, selector); - - // transitions - assert roleIdBefore != roleIdAfter => ( - f.selector == sig:setTargetFunctionRole(address,bytes4[],uint64).selector - ); -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ State transitions: getTargetAdminDelay │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule getTargetAdminDelayChangeTime(address target) { - env e1; - env e2; - - // values before - mathint delayBefore = getTargetAdminDelay(e1, target); - mathint delayPendingBefore = getTargetAdminDelay_after(e1, target); - mathint delayEffectBefore = getTargetAdminDelay_effect(e1, target); - - // time pass: e1 → e2 - require clock(e1) <= clock(e2); - - // values after - mathint delayAfter = getTargetAdminDelay(e2, target); - mathint delayPendingAfter = getTargetAdminDelay_after(e2, target); - mathint delayEffectAfter = getTargetAdminDelay_effect(e2, target); - - assert ( - delayBefore != delayAfter || - delayPendingBefore != delayPendingAfter || - delayEffectBefore != delayEffectAfter - ) => ( - delayEffectBefore > clock(e1) && - delayEffectBefore <= clock(e2) && - delayAfter == delayPendingBefore && - delayPendingAfter == 0 && - delayEffectAfter == 0 - ); -} - -rule getTargetAdminDelayChangeCall(address target) { - env e; - - // values before - mathint delayBefore = getTargetAdminDelay(e, target); - mathint delayPendingBefore = getTargetAdminDelay_after(e, target); - mathint delayEffectBefore = getTargetAdminDelay_effect(e, target); - - // arbitrary function call - method f; calldataarg args; f(e, args); - - // values after - mathint delayAfter = getTargetAdminDelay(e, target); - mathint delayPendingAfter = getTargetAdminDelay_after(e, target); - mathint delayEffectAfter = getTargetAdminDelay_effect(e, target); - - // if anything changed ... - assert ( - delayBefore != delayAfter || - delayPendingBefore != delayPendingAfter || - delayEffectBefore != delayEffectAfter - ) => ( - ( - // ... it was the consequence of a call to setTargetAdminDelay - f.selector == sig:setTargetAdminDelay(address,uint32).selector - ) && ( - // ... delay cannot decrease instantly - delayAfter >= delayBefore - ) && ( - // ... if setback is not 0, value cannot change instantly - minSetback() > 0 => ( - delayBefore == delayAfter - ) - ) && ( - // ... if the value did not change and there is a minSetback, there must be something scheduled in the future - delayAfter == delayBefore && minSetback() > 0 => ( - delayEffectAfter >= clock(e) + minSetback() - ) - // note: if there is no minSetback, and if the caller "confirms" the current value, - // then this as immediate effect and nothing is scheduled - ) && ( - // ... if the value changed, then no further change should be scheduled - delayAfter != delayBefore => ( - delayPendingAfter == 0 && - delayEffectAfter == 0 - ) - ) - ); -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ State transitions: getRoleGrantDelay │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule getRoleGrantDelayChangeTime(uint64 roleId) { - env e1; - env e2; - - // values before - mathint delayBefore = getRoleGrantDelay(e1, roleId); - mathint delayPendingBefore = getRoleGrantDelay_after(e1, roleId); - mathint delayEffectBefore = getRoleGrantDelay_effect(e1, roleId); - - // time pass: e1 → e2 - require clock(e1) <= clock(e2); - - // values after - mathint delayAfter = getRoleGrantDelay(e2, roleId); - mathint delayPendingAfter = getRoleGrantDelay_after(e2, roleId); - mathint delayEffectAfter = getRoleGrantDelay_effect(e2, roleId); - - assert ( - delayBefore != delayAfter || - delayPendingBefore != delayPendingAfter || - delayEffectBefore != delayEffectAfter - ) => ( - delayEffectBefore > clock(e1) && - delayEffectBefore <= clock(e2) && - delayAfter == delayPendingBefore && - delayPendingAfter == 0 && - delayEffectAfter == 0 - ); -} - -rule getRoleGrantDelayChangeCall(uint64 roleId) { - env e; - - // values before - mathint delayBefore = getRoleGrantDelay(e, roleId); - mathint delayPendingBefore = getRoleGrantDelay_after(e, roleId); - mathint delayEffectBefore = getRoleGrantDelay_effect(e, roleId); - - // arbitrary function call - method f; calldataarg args; f(e, args); - - // values after - mathint delayAfter = getRoleGrantDelay(e, roleId); - mathint delayPendingAfter = getRoleGrantDelay_after(e, roleId); - mathint delayEffectAfter = getRoleGrantDelay_effect(e, roleId); - - // if anything changed ... - assert ( - delayBefore != delayAfter || - delayPendingBefore != delayPendingAfter || - delayEffectBefore != delayEffectAfter - ) => ( - ( - // ... it was the consequence of a call to setTargetAdminDelay - f.selector == sig:setGrantDelay(uint64,uint32).selector - ) && ( - // ... delay cannot decrease instantly - delayAfter >= delayBefore - ) && ( - // ... if setback is not 0, value cannot change instantly - minSetback() > 0 => ( - delayBefore == delayAfter - ) - ) && ( - // ... if the value did not change and there is a minSetback, there must be something scheduled in the future - delayAfter == delayBefore && minSetback() > 0 => ( - delayEffectAfter >= clock(e) + minSetback() - ) - // note: if there is no minSetback, and if the caller "confirms" the current value, - // then this as immediate effect and nothing is scheduled - ) && ( - // ... if the value changed, then no further change should be scheduled - delayAfter != delayBefore => ( - delayPendingAfter == 0 && - delayEffectAfter == 0 - ) - ) - ); -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ State transitions: getRoleAdmin & getRoleGuardian │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule getRoleAdminChangeCall(uint64 roleId) { - // values before - mathint adminIdBefore = getRoleAdmin(roleId); - - // arbitrary function call - env e; method f; calldataarg args; f(e, args); - - // values after - mathint adminIdAfter = getRoleAdmin(roleId); - - // transitions - assert adminIdBefore != adminIdAfter => f.selector == sig:setRoleAdmin(uint64,uint64).selector; -} - -rule getRoleGuardianChangeCall(uint64 roleId) { - // values before - mathint guardianIdBefore = getRoleGuardian(roleId); - - // arbitrary function call - env e; method f; calldataarg args; f(e, args); - - // values after - mathint guardianIdAfter = getRoleGuardian(roleId); - - // transitions - assert guardianIdBefore != guardianIdAfter => ( - f.selector == sig:setRoleGuardian(uint64,uint64).selector - ); -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ State transitions: getNonce │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule getNonceChangeCall(bytes32 operationId) { - // values before - mathint nonceBefore = getNonce(operationId); - - // reasonable assumption - require nonceBefore < max_uint32; - - // arbitrary function call - env e; method f; calldataarg args; f(e, args); - - // values after - mathint nonceAfter = getNonce(operationId); - - // transitions - assert nonceBefore != nonceAfter => ( - f.selector == sig:schedule(address,bytes,uint48).selector && - nonceAfter == nonceBefore + 1 - ); -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ State transitions: getSchedule │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule getScheduleChangeTime(bytes32 operationId) { - env e1; - env e2; - - // values before - mathint scheduleBefore = getSchedule(e1, operationId); - - // time pass: e1 → e2 - require clock(e1) <= clock(e2); - - // values after - mathint scheduleAfter = getSchedule(e2, operationId); - - // transition - assert scheduleBefore != scheduleAfter => ( - scheduleBefore + expiration() > clock(e1) && - scheduleBefore + expiration() <= clock(e2) && - scheduleAfter == 0 - ); -} - -rule getScheduleChangeCall(bytes32 operationId) { - env e; - - // values before - mathint scheduleBefore = getSchedule(e, operationId); - - // arbitrary function call - method f; calldataarg args; f(e, args); - - // values after - mathint scheduleAfter = getSchedule(e, operationId); - - // transitions - assert scheduleBefore != scheduleAfter => ( - (f.selector == sig:schedule(address,bytes,uint48).selector && scheduleAfter >= clock(e)) || - (f.selector == sig:execute(address,bytes).selector && scheduleAfter == 0 ) || - (f.selector == sig:cancel(address,address,bytes).selector && scheduleAfter == 0 ) || - (f.selector == sig:consumeScheduledOp(address,bytes).selector && scheduleAfter == 0 ) || - (isOnlyAuthorized(to_bytes4(f.selector)) && scheduleAfter == 0 ) - ); -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Functions: restricted functions can only be called by owner │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule restrictedFunctions(env e) { - require nonpayable(e); - require sanity(e); - - method f; - calldataarg args; - - f(e,args); - - assert ( - f.selector == sig:labelRole(uint64,string).selector || - f.selector == sig:setRoleAdmin(uint64,uint64).selector || - f.selector == sig:setRoleGuardian(uint64,uint64).selector || - f.selector == sig:setGrantDelay(uint64,uint32).selector || - f.selector == sig:setTargetAdminDelay(address,uint32).selector || - f.selector == sig:updateAuthority(address,address).selector || - f.selector == sig:setTargetClosed(address,bool).selector || - f.selector == sig:setTargetFunctionRole(address,bytes4[],uint64).selector - ) => ( - hasRole_isMember(e, ADMIN_ROLE(), e.msg.sender) || e.msg.sender == currentContract - ); -} - -rule restrictedFunctionsGrantRole(env e) { - require nonpayable(e); - require sanity(e); - - uint64 roleId; - address account; - uint32 executionDelay; - - // We want to check that the caller has the admin role before we possibly grant it. - bool hasAdminRoleBefore = hasRole_isMember(e, getRoleAdmin(roleId), e.msg.sender); - - grantRole(e, roleId, account, executionDelay); - - assert hasAdminRoleBefore || e.msg.sender == currentContract; -} - -rule restrictedFunctionsRevokeRole(env e) { - require nonpayable(e); - require sanity(e); - - uint64 roleId; - address account; - - // This is needed if roleId is self-administered, the `revokeRole` call could target - // e.msg.sender and remove the very role that is necessary for authorizing the call. - bool hasAdminRoleBefore = hasRole_isMember(e, getRoleAdmin(roleId), e.msg.sender); - - revokeRole(e, roleId, account); - - assert hasAdminRoleBefore || e.msg.sender == currentContract; -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Functions: canCall delay is enforced for calls to execute (only for others target) │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -// getScheduleChangeCall proves that only {schedule} can set an operation schedule to a non 0 value -rule callDelayEnforce_scheduleInTheFuture(env e) { - address target; - bytes data; - uint48 when; - - // Condition: calling a third party with a delay - mathint delay = canCallExtended_delay(e, e.msg.sender, target, data); - require delay > 0; - - // Schedule - schedule(e, target, data, when); - - // Get operation schedule - mathint timepoint = getSchedule(e, hashOperation(e.msg.sender, target, data)); - - // Schedule is far enough in the future - assert timepoint == max(clock(e) + delay, when); -} - -rule callDelayEnforce_executeAfterDelay(env e) { - address target; - bytes data; - - // Condition: calling a third party with a delay - mathint delay = canCallExtended_delay(e, e.msg.sender, target, data); - - // Get operation schedule before - mathint scheduleBefore = getSchedule(e, hashOperation(e.msg.sender, target, data)); - - // Do call - execute@withrevert(e, target, data); - bool success = !lastReverted; - - // Get operation schedule after - mathint scheduleAfter = getSchedule(e, hashOperation(e.msg.sender, target, data)); - - // Can only execute if delay is set and has passed - assert success => ( - delay > 0 => ( - scheduleBefore != 0 && - scheduleBefore <= clock(e) - ) && - scheduleAfter == 0 - ); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/DoubleEndedQueue.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/DoubleEndedQueue.spec deleted file mode 100644 index 3b71bb4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/DoubleEndedQueue.spec +++ /dev/null @@ -1,300 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20.spec deleted file mode 100644 index 21a0335..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20.spec +++ /dev/null @@ -1,352 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20FlashMint.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20FlashMint.spec deleted file mode 100644 index 6942495..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20FlashMint.spec +++ /dev/null @@ -1,55 +0,0 @@ -import "helpers/helpers.spec"; -import "methods/IERC20.spec"; -import "methods/IERC3156FlashLender.spec"; -import "methods/IERC3156FlashBorrower.spec"; - -methods { - // non standard ERC-3156 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)) trackedTransferredAmount; - -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 { - trackedTransferredAmount[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) => trackedTransferredAmount[receiver][recipient] == to_mathint(fees); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20Wrapper.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20Wrapper.spec deleted file mode 100644 index 04e6704..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC20Wrapper.spec +++ /dev/null @@ -1,198 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC721.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC721.spec deleted file mode 100644 index bad4c47..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/ERC721.spec +++ /dev/null @@ -1,679 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/EnumerableMap.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/EnumerableMap.spec deleted file mode 100644 index 1801d99..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/EnumerableMap.spec +++ /dev/null @@ -1,333 +0,0 @@ -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 _positionOf(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 _positionOf are inverse of one │ -│ another. This proves that we have a bijection between indices (the enumerability part) and keys (the entries that │ -│ are set and removed from the EnumerableMap). │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -invariant consistencyIndex(uint256 index) - index < length() => to_mathint(_positionOf(key_at(index))) == index + 1 - { - preserved remove(bytes32 key) { - requireInvariant consistencyIndex(require_uint256(length() - 1)); - } - } - -invariant consistencyKey(bytes32 key) - contains(key) => ( - _positionOf(key) > 0 && - _positionOf(key) <= length() && - key_at(require_uint256(_positionOf(key) - 1)) == key - ) - { - preserved remove(bytes32 otherKey) { - requireInvariant consistencyKey(otherKey); - requireInvariant atUniqueness( - require_uint256(_positionOf(key) - 1), - require_uint256(_positionOf(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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/EnumerableSet.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/EnumerableSet.spec deleted file mode 100644 index 94d0a91..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/EnumerableSet.spec +++ /dev/null @@ -1,246 +0,0 @@ -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 _positionOf(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 _positionOf 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() => _positionOf(at_(index)) == require_uint256(index + 1) - { - preserved remove(bytes32 key) { - requireInvariant consistencyIndex(require_uint256(length() - 1)); - } - } - -invariant consistencyKey(bytes32 key) - contains(key) => ( - _positionOf(key) > 0 && - _positionOf(key) <= length() && - at_(require_uint256(_positionOf(key) - 1)) == key - ) - { - preserved remove(bytes32 otherKey) { - requireInvariant consistencyKey(otherKey); - requireInvariant atUniqueness( - require_uint256(_positionOf(key) - 1), - require_uint256(_positionOf(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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Initializable.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Initializable.spec deleted file mode 100644 index 07c2930..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Initializable.spec +++ /dev/null @@ -1,165 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Nonces.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Nonces.spec deleted file mode 100644 index 4647c5c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Nonces.spec +++ /dev/null @@ -1,92 +0,0 @@ -import "helpers/helpers.spec"; - -methods { - function nonces(address) external returns (uint256) envfree; - function useNonce(address) external returns (uint256) envfree; - function useCheckedNonce(address,uint256) external envfree; -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Helpers │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -function nonceSanity(address account) returns bool { - return nonces(account) < max_uint256; -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Function correctness: useNonce uses nonce │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule useNonce(address account) { - require nonceSanity(account); - - address other; - - mathint nonceBefore = nonces(account); - mathint otherNonceBefore = nonces(other); - - mathint nonceUsed = useNonce@withrevert(account); - bool success = !lastReverted; - - mathint nonceAfter = nonces(account); - mathint otherNonceAfter = nonces(other); - - // liveness - assert success, "doesn't revert"; - - // effect - assert nonceAfter == nonceBefore + 1 && nonceBefore == nonceUsed, "nonce is used"; - - // no side effect - assert otherNonceBefore != otherNonceAfter => other == account, "no other nonce is used"; -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Function correctness: useCheckedNonce uses only the current nonce │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule useCheckedNonce(address account, uint256 currentNonce) { - require nonceSanity(account); - - address other; - - mathint nonceBefore = nonces(account); - mathint otherNonceBefore = nonces(other); - - useCheckedNonce@withrevert(account, currentNonce); - bool success = !lastReverted; - - mathint nonceAfter = nonces(account); - mathint otherNonceAfter = nonces(other); - - // liveness - assert success <=> to_mathint(currentNonce) == nonceBefore, "works iff current nonce is correct"; - - // effect - assert success => nonceAfter == nonceBefore + 1, "nonce is used"; - - // no side effect - assert otherNonceBefore != otherNonceAfter => other == account, "no other nonce is used"; -} - -/* -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Rule: nonce only increments │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -*/ -rule nonceOnlyIncrements(address account) { - require nonceSanity(account); - - mathint nonceBefore = nonces(account); - - env e; method f; calldataarg args; - f(e, args); - - mathint nonceAfter = nonces(account); - - assert nonceAfter == nonceBefore || nonceAfter == nonceBefore + 1, "nonce only increments"; -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Ownable.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Ownable.spec deleted file mode 100644 index 0d50813..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Ownable.spec +++ /dev/null @@ -1,77 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Ownable2Step.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Ownable2Step.spec deleted file mode 100644 index d13c6d3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Ownable2Step.spec +++ /dev/null @@ -1,108 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Pausable.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Pausable.spec deleted file mode 100644 index a7aff9c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/Pausable.spec +++ /dev/null @@ -1,96 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/TimelockController.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/TimelockController.spec deleted file mode 100644 index 5123768..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/TimelockController.spec +++ /dev/null @@ -1,274 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/helpers/helpers.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/helpers/helpers.spec deleted file mode 100644 index 7125ce2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/helpers/helpers.spec +++ /dev/null @@ -1,12 +0,0 @@ -// environment -definition nonpayable(env e) returns bool = e.msg.value == 0; -definition nonzerosender(env e) returns bool = e.msg.sender != 0; -definition sanity(env e) returns bool = clock(e) > 0 && clock(e) <= max_uint48; - -// 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; - -// time -definition clock(env e) returns mathint = to_mathint(e.block.timestamp); -definition isSetAndPast(env e, uint48 timepoint) returns bool = timepoint != 0 && to_mathint(timepoint) <= clock(e); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessControl.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessControl.spec deleted file mode 100644 index 5c395b0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessControl.spec +++ /dev/null @@ -1,8 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessControlDefaultAdminRules.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessControlDefaultAdminRules.spec deleted file mode 100644 index d02db18..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessControlDefaultAdminRules.spec +++ /dev/null @@ -1,36 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManaged.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManaged.spec deleted file mode 100644 index 886d917..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManaged.spec +++ /dev/null @@ -1,5 +0,0 @@ -methods { - function authority() external returns (address) envfree; - function isConsumingScheduledOp() external returns (bytes4) envfree; - function setAuthority(address) external; -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManager.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManager.spec deleted file mode 100644 index 5d305f7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IAccessManager.spec +++ /dev/null @@ -1,33 +0,0 @@ -methods { - function ADMIN_ROLE() external returns (uint64) envfree; - function PUBLIC_ROLE() external returns (uint64) envfree; - function canCall(address,address,bytes4) external returns (bool,uint32); - function expiration() external returns (uint32) envfree; - function minSetback() external returns (uint32) envfree; - function isTargetClosed(address) external returns (bool) envfree; - function getTargetFunctionRole(address,bytes4) external returns (uint64) envfree; - function getTargetAdminDelay(address) external returns (uint32); - function getRoleAdmin(uint64) external returns (uint64) envfree; - function getRoleGuardian(uint64) external returns (uint64) envfree; - function getRoleGrantDelay(uint64) external returns (uint32); - function getAccess(uint64,address) external returns (uint48,uint32,uint32,uint48); - function hasRole(uint64,address) external returns (bool,uint32); - function labelRole(uint64,string) external; - function grantRole(uint64,address,uint32) external; - function revokeRole(uint64,address) external; - function renounceRole(uint64,address) external; - function setRoleAdmin(uint64,uint64) external; - function setRoleGuardian(uint64,uint64) external; - function setGrantDelay(uint64,uint32) external; - function setTargetFunctionRole(address,bytes4[],uint64) external; - function setTargetAdminDelay(address,uint32) external; - function setTargetClosed(address,bool) external; - function hashOperation(address,address,bytes) external returns (bytes32) envfree; - function getNonce(bytes32) external returns (uint32) envfree; - function getSchedule(bytes32) external returns (uint48); - function schedule(address,bytes,uint48) external returns (bytes32,uint32); - function execute(address,bytes) external returns (uint32); - function cancel(address,address,bytes) external returns (uint32); - function consumeScheduledOp(address,bytes) external; - function updateAuthority(address,address) external; -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC20.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC20.spec deleted file mode 100644 index 100901a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC20.spec +++ /dev/null @@ -1,11 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC2612.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC2612.spec deleted file mode 100644 index 4ecc17b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC2612.spec +++ /dev/null @@ -1,5 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashBorrower.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashBorrower.spec deleted file mode 100644 index 733c168..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashBorrower.spec +++ /dev/null @@ -1,3 +0,0 @@ -methods { - function _.onFlashLoan(address,address,uint256,uint256,bytes) external => DISPATCHER(true); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashLender.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashLender.spec deleted file mode 100644 index 66ed14c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashLender.spec +++ /dev/null @@ -1,5 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC5313.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC5313.spec deleted file mode 100644 index f1d469f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC5313.spec +++ /dev/null @@ -1,3 +0,0 @@ -methods { - function owner() external returns (address) envfree; -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC721.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC721.spec deleted file mode 100644 index 34ff50b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC721.spec +++ /dev/null @@ -1,17 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC721Receiver.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC721Receiver.spec deleted file mode 100644 index e6bdf42..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IERC721Receiver.spec +++ /dev/null @@ -1,3 +0,0 @@ -methods { - function _.onERC721Received(address,address,uint256,bytes) external => DISPATCHER(true); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IOwnable.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IOwnable.spec deleted file mode 100644 index 4d7c925..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IOwnable.spec +++ /dev/null @@ -1,5 +0,0 @@ -methods { - function owner() external returns (address) envfree; - function transferOwnership(address) external; - function renounceOwnership() external; -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IOwnable2Step.spec b/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IOwnable2Step.spec deleted file mode 100644 index e6a9957..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/certora/specs/methods/IOwnable2Step.spec +++ /dev/null @@ -1,7 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/AccessControl.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/AccessControl.sol deleted file mode 100644 index 0c7ec60..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/AccessControl.sol +++ /dev/null @@ -1,207 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (access/AccessControl.sol) - -pragma solidity ^0.8.20; - -import {IAccessControl} from "./IAccessControl.sol"; -import {Context} from "../utils/Context.sol"; -import {IERC165, 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); - _; - } - - /// @inheritdoc IERC165 - 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` from `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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol deleted file mode 100644 index 23f0770..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (access/IAccessControl.sol) - -pragma solidity >=0.8.4; - -/** - * @dev External interface of AccessControl declared to support ERC-165 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 to signal 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. This account bears the admin role (for the granted role). - * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}. - */ - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable.sol deleted file mode 100644 index bd96f66..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable.sol +++ /dev/null @@ -1,100 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol deleted file mode 100644 index 3a0747c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.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. - * - * This extension of the {Ownable} contract includes a two-step mechanism to transfer - * ownership, where the new owner must call {acceptOwnership} in order to replace the - * old one. This can help prevent common mistakes, such as transfers of ownership to - * incorrect accounts, or to contracts that are unable to interact with the - * permission system. - * - * 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. - * - * Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer. - */ - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/README.adoc deleted file mode 100644 index b89865b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/README.adoc +++ /dev/null @@ -1,45 +0,0 @@ -= 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. - -- {AccessManager} is a full-fledged access control solution for smart contract systems. Allows creating and assigning multiple hierarchical roles with execution delays for each account across various contracts. -- {AccessManaged} delegates its access control to an authority that dictates the permissions of the managed contract. It's compatible with an AccessManager as an authority. -- {AccessControl} provides a per-contract role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts within the same instance. -- {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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sol deleted file mode 100644 index 77a7e45..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sol +++ /dev/null @@ -1,372 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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"; -import {IERC165} from "../../utils/introspection/ERC165.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}. - * * Role transfers must wait at least one block after scheduling before it can be accepted. - * * 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); - } - - /// @inheritdoc IERC165 - function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { - return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId); - } - - /// @inheritdoc IERC5313 - 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); - } - - /// @inheritdoc AccessControl - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlEnumerable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlEnumerable.sol deleted file mode 100644 index f2d79fd..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlEnumerable.sol +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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"; -import {IERC165} from "../../utils/introspection/ERC165.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; - - /// @inheritdoc IERC165 - 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 Return all accounts that have `role` - * - * 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 getRoleMembers(bytes32 role) public view virtual returns (address[] memory) { - return _roleMembers[role].values(); - } - - /** - * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlDefaultAdminRules.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlDefaultAdminRules.sol deleted file mode 100644 index 616b4d8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlDefaultAdminRules.sol +++ /dev/null @@ -1,192 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (access/extensions/IAccessControlDefaultAdminRules.sol) - -pragma solidity >=0.8.4; - -import {IAccessControl} from "../IAccessControl.sol"; - -/** - * @dev External interface of AccessControlDefaultAdminRules declared to support ERC-165 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlEnumerable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlEnumerable.sol deleted file mode 100644 index 90371fa..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlEnumerable.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (access/extensions/IAccessControlEnumerable.sol) - -pragma solidity >=0.8.4; - -import {IAccessControl} from "../IAccessControl.sol"; - -/** - * @dev External interface of AccessControlEnumerable declared to support ERC-165 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManaged.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManaged.sol deleted file mode 100644 index 382a308..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManaged.sol +++ /dev/null @@ -1,112 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (access/manager/AccessManaged.sol) - -pragma solidity ^0.8.20; - -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 unambiguously 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManager.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManager.sol deleted file mode 100644 index 0510805..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AccessManager.sol +++ /dev/null @@ -1,740 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.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; - } - - /** - * @dev The identifier of the admin role. Required to perform most configuration operations including - * other roles' management and target restrictions. - */ - uint64 public constant ADMIN_ROLE = type(uint64).min; // 0 - - /** - * @dev The identifier of the public role. Automatically granted to all addresses with no delay. - */ - 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. - * See {AccessManager} description for a detailed breakdown of the authorization logic. - */ - 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 { - _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, revert - 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 call is not authorized, 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 and roles logic. - * - * WARNING: Carefully review the considerations of {AccessManaged-restricted} since they apply to this modifier. - */ - 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 adminRestricted, 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, getTargetFunctionRole(address(this), selector), 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 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 adminRestricted, uint64 roleId, uint32 operationDelay) = _getAdminRestrictions(data); - - // isTargetClosed apply to non-admin-restricted function - if (!adminRestricted && isTargetClosed(address(this))) { - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sol deleted file mode 100644 index 8b04709..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.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) { - bytes memory data = abi.encodeCall(IAuthority.canCall, (caller, target, selector)); - - assembly ("memory-safe") { - mstore(0x00, 0x00) - mstore(0x20, 0x00) - - if staticcall(gas(), authority, add(data, 0x20), mload(data), 0x00, 0x40) { - immediate := mload(0x00) - delay := mload(0x20) - - // If delay does not fit in a uint32, return 0 (no delay) - // equivalent to: if gt(delay, 0xFFFFFFFF) { delay := 0 } - delay := mul(delay, iszero(shr(32, delay))) - } - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol deleted file mode 100644 index c93c711..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (access/manager/IAccessManaged.sol) - -pragma solidity >=0.8.4; - -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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sol deleted file mode 100644 index 925be90..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sol +++ /dev/null @@ -1,399 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (access/manager/IAccessManager.sol) - -pragma solidity >=0.8.4; - -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 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 `allowed` 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 the admin functions in the manager itself. These are defined by the - * {AccessManager} documentation. - */ - 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. - * - * NOTE: When the manager itself is closed, admin functions are still accessible to avoid locking the contract. - */ - 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 since, uint32 currentDelay, uint32 pendingDelay, uint48 effect); - - /** - * @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 isMember, uint32 executionDelay); - - /** - * @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. - * - * Closing the manager itself won't disable access to admin methods to avoid locking the 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 operationId, uint32 nonce); - - /** - * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAuthority.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAuthority.sol deleted file mode 100644 index 6ad902c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/access/manager/IAuthority.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (access/manager/IAuthority.sol) - -pragma solidity >=0.4.16; - -/** - * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/Account.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/Account.sol deleted file mode 100644 index 19c64d7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/Account.sol +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (account/Account.sol) - -pragma solidity ^0.8.20; - -import {PackedUserOperation, IAccount, IEntryPoint} from "../interfaces/draft-IERC4337.sol"; -import {ERC4337Utils} from "./utils/draft-ERC4337Utils.sol"; -import {AbstractSigner} from "../utils/cryptography/signers/AbstractSigner.sol"; - -/** - * @dev A simple ERC4337 account implementation. This base implementation only includes the minimal logic to process - * user operations. - * - * Developers must implement the {AbstractSigner-_rawSignatureValidation} function to define the account's validation logic. - * - * NOTE: This core account doesn't include any mechanism for performing arbitrary external calls. This is an essential - * feature that all Account should have. We leave it up to the developers to implement the mechanism of their choice. - * Common choices include ERC-6900, ERC-7579 and ERC-7821 (among others). - * - * IMPORTANT: Implementing a mechanism to validate signatures is a security-sensitive operation as it may allow an - * attacker to bypass the account's security measures. Check out {SignerECDSA}, {SignerP256}, or {SignerRSA} for - * digital signature validation implementations. - * - * @custom:stateless - */ -abstract contract Account is AbstractSigner, IAccount { - /** - * @dev Unauthorized call to the account. - */ - error AccountUnauthorized(address sender); - - /** - * @dev Revert if the caller is not the entry point or the account itself. - */ - modifier onlyEntryPointOrSelf() { - _checkEntryPointOrSelf(); - _; - } - - /** - * @dev Revert if the caller is not the entry point. - */ - modifier onlyEntryPoint() { - _checkEntryPoint(); - _; - } - - /** - * @dev Canonical entry point for the account that forwards and validates user operations. - */ - function entryPoint() public view virtual returns (IEntryPoint) { - return ERC4337Utils.ENTRYPOINT_V08; - } - - /** - * @dev Return the account nonce for the canonical sequence. - */ - function getNonce() public view virtual returns (uint256) { - return getNonce(0); - } - - /** - * @dev Return the account nonce for a given sequence (key). - */ - function getNonce(uint192 key) public view virtual returns (uint256) { - return entryPoint().getNonce(address(this), key); - } - - /** - * @inheritdoc IAccount - */ - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash, - uint256 missingAccountFunds - ) public virtual onlyEntryPoint returns (uint256) { - uint256 validationData = _validateUserOp(userOp, userOpHash); - _payPrefund(missingAccountFunds); - return validationData; - } - - /** - * @dev Returns the validationData for a given user operation. By default, this checks the signature of the - * signable hash (produced by {_signableUserOpHash}) using the abstract signer ({AbstractSigner-_rawSignatureValidation}). - * - * NOTE: The userOpHash is assumed to be correct. Calling this function with a userOpHash that does not match the - * userOp will result in undefined behavior. - */ - function _validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) internal virtual returns (uint256) { - return - _rawSignatureValidation(_signableUserOpHash(userOp, userOpHash), userOp.signature) - ? ERC4337Utils.SIG_VALIDATION_SUCCESS - : ERC4337Utils.SIG_VALIDATION_FAILED; - } - - /** - * @dev Virtual function that returns the signable hash for a user operations. Since v0.8.0 of the entrypoint, - * `userOpHash` is an EIP-712 hash that can be signed directly. - */ - function _signableUserOpHash( - PackedUserOperation calldata /*userOp*/, - bytes32 userOpHash - ) internal view virtual returns (bytes32) { - return userOpHash; - } - - /** - * @dev Sends the missing funds for executing the user operation to the {entrypoint}. - * The `missingAccountFunds` must be defined by the entrypoint when calling {validateUserOp}. - */ - function _payPrefund(uint256 missingAccountFunds) internal virtual { - if (missingAccountFunds > 0) { - (bool success, ) = payable(msg.sender).call{value: missingAccountFunds}(""); - success; // Silence warning. The entrypoint should validate the result. - } - } - - /** - * @dev Ensures the caller is the {entrypoint}. - */ - function _checkEntryPoint() internal view virtual { - address sender = msg.sender; - if (sender != address(entryPoint())) { - revert AccountUnauthorized(sender); - } - } - - /** - * @dev Ensures the caller is the {entrypoint} or the account itself. - */ - function _checkEntryPointOrSelf() internal view virtual { - address sender = msg.sender; - if (sender != address(this) && sender != address(entryPoint())) { - revert AccountUnauthorized(sender); - } - } - - /** - * @dev Receive Ether. - */ - receive() external payable virtual {} -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/README.adoc deleted file mode 100644 index dc3c9a0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/README.adoc +++ /dev/null @@ -1,30 +0,0 @@ -= Account -[.readme-notice] -NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/account - -This directory includes contracts to build accounts for ERC-4337. These include: - - * {Account}: An ERC-4337 smart account implementation that includes the core logic to process user operations. - * {AccountERC7579}: An extension of `Account` that implements support for ERC-7579 modules. - * {AccountERC7579Hooked}: An extension of `AccountERC7579` with support for a single hook module (type 4). - * {ERC7821}: Minimal batch executor implementation contracts. Useful to enable easy batch execution for smart contracts. - * {ERC4337Utils}: Utility functions for working with ERC-4337 user operations. - * {ERC7579Utils}: Utility functions for working with ERC-7579 modules and account modularity. - -== Core - -{{Account}} - -== Extensions - -{{AccountERC7579}} - -{{AccountERC7579Hooked}} - -{{ERC7821}} - -== Utilities - -{{ERC4337Utils}} - -{{ERC7579Utils}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579.sol deleted file mode 100644 index 40ea71e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579.sol +++ /dev/null @@ -1,405 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (account/extensions/draft-AccountERC7579.sol) - -pragma solidity ^0.8.26; - -import {PackedUserOperation} from "../../interfaces/draft-IERC4337.sol"; -import {IERC1271} from "../../interfaces/IERC1271.sol"; -import {IERC7579Module, IERC7579Validator, IERC7579Execution, IERC7579AccountConfig, IERC7579ModuleConfig, MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR, MODULE_TYPE_FALLBACK} from "../../interfaces/draft-IERC7579.sol"; -import {ERC7579Utils, Mode, CallType, ExecType} from "../../account/utils/draft-ERC7579Utils.sol"; -import {EnumerableSet} from "../../utils/structs/EnumerableSet.sol"; -import {Bytes} from "../../utils/Bytes.sol"; -import {Packing} from "../../utils/Packing.sol"; -import {Address} from "../../utils/Address.sol"; -import {Calldata} from "../../utils/Calldata.sol"; -import {Account} from "../Account.sol"; - -/** - * @dev Extension of {Account} that implements support for ERC-7579 modules. - * - * To comply with the ERC-1271 support requirement, this contract defers signature validation to - * installed validator modules by calling {IERC7579Validator-isValidSignatureWithSender}. - * - * This contract does not implement validation logic for user operations since this functionality - * is often delegated to self-contained validation modules. Developers must install a validator module - * upon initialization (or any other mechanism to enable execution from the account): - * - * ```solidity - * contract MyAccountERC7579 is AccountERC7579, Initializable { - * function initializeAccount(address validator, bytes calldata validatorData) public initializer { - * _installModule(MODULE_TYPE_VALIDATOR, validator, validatorData); - * } - * } - * ``` - * - * [NOTE] - * ==== - * * Hook support is not included. See {AccountERC7579Hooked} for a version that hooks to execution. - * * Validator selection, when verifying either ERC-1271 signature or ERC-4337 UserOperation is implemented in - * internal virtual functions {_extractUserOpValidator} and {_extractSignatureValidator}. Both are implemented - * following common practices. However, this part is not standardized in ERC-7579 (or in any follow-up ERC). Some - * accounts may want to override these internal functions. - * * When combined with {ERC7739}, resolution ordering of {isValidSignature} may have an impact ({ERC7739} does not - * call super). Manual resolution might be necessary. - * * Static calls (using callType `0xfe`) are currently NOT supported. - * ==== - * - * WARNING: Removing all validator modules will render the account inoperable, as no user operations can be validated thereafter. - */ -abstract contract AccountERC7579 is Account, IERC1271, IERC7579Execution, IERC7579AccountConfig, IERC7579ModuleConfig { - using Bytes for *; - using ERC7579Utils for *; - using EnumerableSet for *; - using Packing for bytes32; - - EnumerableSet.AddressSet private _validators; - EnumerableSet.AddressSet private _executors; - mapping(bytes4 selector => address) private _fallbacks; - - /// @dev The account's {fallback} was called with a selector that doesn't have an installed handler. - error ERC7579MissingFallbackHandler(bytes4 selector); - - /// @dev Modifier that checks if the caller is an installed module of the given type. - modifier onlyModule(uint256 moduleTypeId, bytes calldata additionalContext) { - _checkModule(moduleTypeId, msg.sender, additionalContext); - _; - } - - /// @dev See {_fallback}. - fallback(bytes calldata) external payable virtual returns (bytes memory) { - return _fallback(); - } - - /// @inheritdoc IERC7579AccountConfig - function accountId() public view virtual returns (string memory) { - // vendorname.accountname.semver - return "@openzeppelin/community-contracts.AccountERC7579.v0.0.0"; - } - - /** - * @inheritdoc IERC7579AccountConfig - * - * @dev Supported call types: - * * Single (`0x00`): A single transaction execution. - * * Batch (`0x01`): A batch of transactions execution. - * * Delegate (`0xff`): A delegate call execution. - * - * Supported exec types: - * * Default (`0x00`): Default execution type (revert on failure). - * * Try (`0x01`): Try execution type (emits ERC7579TryExecuteFail on failure). - */ - function supportsExecutionMode(bytes32 encodedMode) public view virtual returns (bool) { - (CallType callType, ExecType execType, , ) = Mode.wrap(encodedMode).decodeMode(); - return - (callType == ERC7579Utils.CALLTYPE_SINGLE || - callType == ERC7579Utils.CALLTYPE_BATCH || - callType == ERC7579Utils.CALLTYPE_DELEGATECALL) && - (execType == ERC7579Utils.EXECTYPE_DEFAULT || execType == ERC7579Utils.EXECTYPE_TRY); - } - - /** - * @inheritdoc IERC7579AccountConfig - * - * @dev Supported module types: - * - * * Validator: A module used during the validation phase to determine if a transaction is valid and - * should be executed on the account. - * * Executor: A module that can execute transactions on behalf of the smart account via a callback. - * * Fallback Handler: A module that can extend the fallback functionality of a smart account. - */ - function supportsModule(uint256 moduleTypeId) public view virtual returns (bool) { - return - moduleTypeId == MODULE_TYPE_VALIDATOR || - moduleTypeId == MODULE_TYPE_EXECUTOR || - moduleTypeId == MODULE_TYPE_FALLBACK; - } - - /// @inheritdoc IERC7579ModuleConfig - function installModule( - uint256 moduleTypeId, - address module, - bytes calldata initData - ) public virtual onlyEntryPointOrSelf { - _installModule(moduleTypeId, module, initData); - } - - /// @inheritdoc IERC7579ModuleConfig - function uninstallModule( - uint256 moduleTypeId, - address module, - bytes calldata deInitData - ) public virtual onlyEntryPointOrSelf { - _uninstallModule(moduleTypeId, module, deInitData); - } - - /// @inheritdoc IERC7579ModuleConfig - function isModuleInstalled( - uint256 moduleTypeId, - address module, - bytes calldata additionalContext - ) public view virtual returns (bool) { - if (moduleTypeId == MODULE_TYPE_VALIDATOR) return _validators.contains(module); - if (moduleTypeId == MODULE_TYPE_EXECUTOR) return _executors.contains(module); - if (moduleTypeId == MODULE_TYPE_FALLBACK) return _fallbacks[bytes4(additionalContext[0:4])] == module; - return false; - } - - /// @inheritdoc IERC7579Execution - function execute(bytes32 mode, bytes calldata executionCalldata) public payable virtual onlyEntryPointOrSelf { - _execute(Mode.wrap(mode), executionCalldata); - } - - /// @inheritdoc IERC7579Execution - function executeFromExecutor( - bytes32 mode, - bytes calldata executionCalldata - ) - public - payable - virtual - onlyModule(MODULE_TYPE_EXECUTOR, Calldata.emptyBytes()) - returns (bytes[] memory returnData) - { - return _execute(Mode.wrap(mode), executionCalldata); - } - - /** - * @dev Implement ERC-1271 through IERC7579Validator modules. If module based validation fails, fallback to - * "native" validation by the abstract signer. - * - * NOTE: when combined with {ERC7739}, resolution ordering may have an impact ({ERC7739} does not call super). - * Manual resolution might be necessary. - */ - function isValidSignature(bytes32 hash, bytes calldata signature) public view virtual returns (bytes4) { - // check signature length is enough for extraction - if (signature.length >= 20) { - (address module, bytes calldata innerSignature) = _extractSignatureValidator(signature); - // if module is not installed, skip - if (isModuleInstalled(MODULE_TYPE_VALIDATOR, module, Calldata.emptyBytes())) { - // try validation, skip any revert - try IERC7579Validator(module).isValidSignatureWithSender(msg.sender, hash, innerSignature) returns ( - bytes4 magic - ) { - return magic; - } catch {} - } - } - return bytes4(0xffffffff); - } - - /** - * @dev Validates a user operation with {_signableUserOpHash} and returns the validation data - * if the module specified by the first 20 bytes of the nonce key is installed. Falls back to - * {Account-_validateUserOp} otherwise. - * - * See {_extractUserOpValidator} for the module extraction logic. - */ - function _validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) internal virtual override returns (uint256) { - address module = _extractUserOpValidator(userOp); - return - isModuleInstalled(MODULE_TYPE_VALIDATOR, module, Calldata.emptyBytes()) - ? IERC7579Validator(module).validateUserOp(userOp, _signableUserOpHash(userOp, userOpHash)) - : super._validateUserOp(userOp, userOpHash); - } - - /** - * @dev ERC-7579 execution logic. See {supportsExecutionMode} for supported modes. - * - * Reverts if the call type is not supported. - */ - function _execute( - Mode mode, - bytes calldata executionCalldata - ) internal virtual returns (bytes[] memory returnData) { - (CallType callType, ExecType execType, , ) = mode.decodeMode(); - if (callType == ERC7579Utils.CALLTYPE_SINGLE) return executionCalldata.execSingle(execType); - if (callType == ERC7579Utils.CALLTYPE_BATCH) return executionCalldata.execBatch(execType); - if (callType == ERC7579Utils.CALLTYPE_DELEGATECALL) return executionCalldata.execDelegateCall(execType); - revert ERC7579Utils.ERC7579UnsupportedCallType(callType); - } - - /** - * @dev Installs a module of the given type with the given initialization data. - * - * For the fallback module type, the `initData` is expected to be the (packed) concatenation of a 4-byte - * selector and the rest of the data to be sent to the handler when calling {IERC7579Module-onInstall}. - * - * Requirements: - * - * * Module type must be supported. See {supportsModule}. Reverts with {ERC7579Utils-ERC7579UnsupportedModuleType}. - * * Module must be of the given type. Reverts with {ERC7579Utils-ERC7579MismatchedModuleTypeId}. - * * Module must not be already installed. Reverts with {ERC7579Utils-ERC7579AlreadyInstalledModule}. - * - * Emits a {IERC7579ModuleConfig-ModuleInstalled} event. - */ - function _installModule(uint256 moduleTypeId, address module, bytes memory initData) internal virtual { - require(supportsModule(moduleTypeId), ERC7579Utils.ERC7579UnsupportedModuleType(moduleTypeId)); - require( - IERC7579Module(module).isModuleType(moduleTypeId), - ERC7579Utils.ERC7579MismatchedModuleTypeId(moduleTypeId, module) - ); - - if (moduleTypeId == MODULE_TYPE_VALIDATOR) { - require(_validators.add(module), ERC7579Utils.ERC7579AlreadyInstalledModule(moduleTypeId, module)); - } else if (moduleTypeId == MODULE_TYPE_EXECUTOR) { - require(_executors.add(module), ERC7579Utils.ERC7579AlreadyInstalledModule(moduleTypeId, module)); - } else if (moduleTypeId == MODULE_TYPE_FALLBACK) { - bytes4 selector; - (selector, initData) = _decodeFallbackData(initData); - require( - _fallbacks[selector] == address(0), - ERC7579Utils.ERC7579AlreadyInstalledModule(moduleTypeId, module) - ); - _fallbacks[selector] = module; - } - - IERC7579Module(module).onInstall(initData); - emit ModuleInstalled(moduleTypeId, module); - } - - /** - * @dev Uninstalls a module of the given type with the given de-initialization data. - * - * For the fallback module type, the `deInitData` is expected to be the (packed) concatenation of a 4-byte - * selector and the rest of the data to be sent to the handler when calling {IERC7579Module-onUninstall}. - * - * Requirements: - * - * * Module must be already installed. Reverts with {ERC7579Utils-ERC7579UninstalledModule} otherwise. - */ - function _uninstallModule(uint256 moduleTypeId, address module, bytes memory deInitData) internal virtual { - require(supportsModule(moduleTypeId), ERC7579Utils.ERC7579UnsupportedModuleType(moduleTypeId)); - - if (moduleTypeId == MODULE_TYPE_VALIDATOR) { - require(_validators.remove(module), ERC7579Utils.ERC7579UninstalledModule(moduleTypeId, module)); - } else if (moduleTypeId == MODULE_TYPE_EXECUTOR) { - require(_executors.remove(module), ERC7579Utils.ERC7579UninstalledModule(moduleTypeId, module)); - } else if (moduleTypeId == MODULE_TYPE_FALLBACK) { - bytes4 selector; - (selector, deInitData) = _decodeFallbackData(deInitData); - require( - _fallbackHandler(selector) == module && module != address(0), - ERC7579Utils.ERC7579UninstalledModule(moduleTypeId, module) - ); - delete _fallbacks[selector]; - } - - IERC7579Module(module).onUninstall(deInitData); - emit ModuleUninstalled(moduleTypeId, module); - } - - /** - * @dev Fallback function that delegates the call to the installed handler for the given selector. - * - * Reverts with {ERC7579MissingFallbackHandler} if the handler is not installed. - * - * Calls the handler with the original `msg.sender` appended at the end of the calldata following - * the ERC-2771 format. - */ - function _fallback() internal virtual returns (bytes memory) { - address handler = _fallbackHandler(msg.sig); - require(handler != address(0), ERC7579MissingFallbackHandler(msg.sig)); - - // From https://eips.ethereum.org/EIPS/eip-7579#fallback[ERC-7579 specifications]: - // - MUST utilize ERC-2771 to add the original msg.sender to the calldata sent to the fallback handler - // - MUST use call to invoke the fallback handler - (bool success, bytes memory returndata) = handler.call{value: msg.value}( - abi.encodePacked(msg.data, msg.sender) - ); - - if (success) return returndata; - - assembly ("memory-safe") { - revert(add(returndata, 0x20), mload(returndata)) - } - } - - /// @dev Returns the fallback handler for the given selector. Returns `address(0)` if not installed. - function _fallbackHandler(bytes4 selector) internal view virtual returns (address) { - return _fallbacks[selector]; - } - - /// @dev Checks if the module is installed. Reverts if the module is not installed. - function _checkModule( - uint256 moduleTypeId, - address module, - bytes calldata additionalContext - ) internal view virtual { - require( - isModuleInstalled(moduleTypeId, module, additionalContext), - ERC7579Utils.ERC7579UninstalledModule(moduleTypeId, module) - ); - } - - /** - * @dev Extracts the nonce validator from the user operation. - * - * To construct a nonce key, set nonce as follows: - * - * ``` - * | | - * ``` - * NOTE: The default behavior of this function replicates the behavior of - * https://github.com/rhinestonewtf/safe7579/blob/bb29e8b1a66658790c4169e72608e27d220f79be/src/Safe7579.sol#L266[Safe adapter], - * https://github.com/etherspot/etherspot-prime-contracts/blob/cfcdb48c4172cea0d66038324c0bae3288aa8caa/src/modular-etherspot-wallet/wallet/ModularEtherspotWallet.sol#L227[Etherspot's Prime Account], and - * https://github.com/erc7579/erc7579-implementation/blob/16138d1afd4e9711f6c1425133538837bd7787b5/src/MSAAdvanced.sol#L247[ERC7579 reference implementation]. - * - * This is not standardized in ERC-7579 (or in any follow-up ERC). Some accounts may want to override these internal functions. - * - * For example, https://github.com/bcnmy/nexus/blob/54f4e19baaff96081a8843672977caf712ef19f4/contracts/lib/NonceLib.sol#L17[Biconomy's Nexus] - * uses a similar yet incompatible approach (the validator address is also part of the nonce, but not at the same location) - */ - function _extractUserOpValidator(PackedUserOperation calldata userOp) internal pure virtual returns (address) { - return address(bytes32(userOp.nonce).extract_32_20(0)); - } - - /** - * @dev Extracts the signature validator from the signature. - * - * To construct a signature, set the first 20 bytes as the module address and the remaining bytes as the - * signature data: - * - * ``` - * | - * ``` - * - * NOTE: The default behavior of this function replicates the behavior of - * https://github.com/rhinestonewtf/safe7579/blob/bb29e8b1a66658790c4169e72608e27d220f79be/src/Safe7579.sol#L350[Safe adapter], - * https://github.com/bcnmy/nexus/blob/54f4e19baaff96081a8843672977caf712ef19f4/contracts/Nexus.sol#L239[Biconomy's Nexus], - * https://github.com/etherspot/etherspot-prime-contracts/blob/cfcdb48c4172cea0d66038324c0bae3288aa8caa/src/modular-etherspot-wallet/wallet/ModularEtherspotWallet.sol#L252[Etherspot's Prime Account], and - * https://github.com/erc7579/erc7579-implementation/blob/16138d1afd4e9711f6c1425133538837bd7787b5/src/MSAAdvanced.sol#L296[ERC7579 reference implementation]. - * - * This is not standardized in ERC-7579 (or in any follow-up ERC). Some accounts may want to override these internal functions. - */ - function _extractSignatureValidator( - bytes calldata signature - ) internal pure virtual returns (address module, bytes calldata innerSignature) { - return (address(bytes20(signature[0:20])), signature[20:]); - } - - /** - * @dev Extract the function selector from initData/deInitData for MODULE_TYPE_FALLBACK - * - * NOTE: If we had calldata here, we could use calldata slice which are cheaper to manipulate and don't require - * actual copy. However, this would require `_installModule` to get a calldata bytes object instead of a memory - * bytes object. This would prevent calling `_installModule` from a contract constructor and would force the use - * of external initializers. That may change in the future, as most accounts will probably be deployed as - * clones/proxy/ERC-7702 delegates and therefore rely on initializers anyway. - */ - function _decodeFallbackData( - bytes memory data - ) internal pure virtual returns (bytes4 selector, bytes memory remaining) { - return (bytes4(data), data.slice(4)); - } - - /// @dev By default, only use the modules for validation of userOp and signature. Disable raw signatures. - function _rawSignatureValidation( - bytes32 /*hash*/, - bytes calldata /*signature*/ - ) internal view virtual override returns (bool) { - return false; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579Hooked.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579Hooked.sol deleted file mode 100644 index c83f38f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579Hooked.sol +++ /dev/null @@ -1,107 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (account/extensions/draft-AccountERC7579Hooked.sol) - -pragma solidity ^0.8.26; - -import {IERC7579Hook, MODULE_TYPE_HOOK} from "../../interfaces/draft-IERC7579.sol"; -import {ERC7579Utils, Mode} from "../../account/utils/draft-ERC7579Utils.sol"; -import {AccountERC7579} from "./draft-AccountERC7579.sol"; - -/** - * @dev Extension of {AccountERC7579} with support for a single hook module (type 4). - * - * If installed, this extension will call the hook module's {IERC7579Hook-preCheck} before executing any operation - * with {_execute} (including {execute} and {executeFromExecutor} by default) and {IERC7579Hook-postCheck} thereafter. - * - * NOTE: Hook modules break the check-effect-interaction pattern. In particular, the {IERC7579Hook-preCheck} hook can - * lead to potentially dangerous reentrancy. Using the `withHook()` modifier is safe if no effect is performed - * before the preHook or after the postHook. That is the case on all functions here, but it may not be the case if - * functions that have this modifier are overridden. Developers should be extremely careful when implementing hook - * modules or further overriding functions that involve hooks. - */ -abstract contract AccountERC7579Hooked is AccountERC7579 { - address private _hook; - - /// @dev A hook module is already present. This contract only supports one hook module. - error ERC7579HookModuleAlreadyPresent(address hook); - - /** - * @dev Calls {IERC7579Hook-preCheck} before executing the modified function and {IERC7579Hook-postCheck} - * thereafter. - */ - modifier withHook() { - address hook_ = hook(); - bytes memory hookData; - - // slither-disable-next-line reentrancy-no-eth - if (hook_ != address(0)) hookData = IERC7579Hook(hook_).preCheck(msg.sender, msg.value, msg.data); - _; - if (hook_ != address(0)) IERC7579Hook(hook_).postCheck(hookData); - } - - /// @inheritdoc AccountERC7579 - function accountId() public view virtual override returns (string memory) { - // vendorname.accountname.semver - return "@openzeppelin/community-contracts.AccountERC7579Hooked.v0.0.0"; - } - - /// @dev Returns the hook module address if installed, or `address(0)` otherwise. - function hook() public view virtual returns (address) { - return _hook; - } - - /// @dev Supports hook modules. See {AccountERC7579-supportsModule} - function supportsModule(uint256 moduleTypeId) public view virtual override returns (bool) { - return moduleTypeId == MODULE_TYPE_HOOK || super.supportsModule(moduleTypeId); - } - - /// @inheritdoc AccountERC7579 - function isModuleInstalled( - uint256 moduleTypeId, - address module, - bytes calldata data - ) public view virtual override returns (bool) { - return - (moduleTypeId == MODULE_TYPE_HOOK && module == hook()) || - super.isModuleInstalled(moduleTypeId, module, data); - } - - /// @dev Installs a module with support for hook modules. See {AccountERC7579-_installModule} - function _installModule( - uint256 moduleTypeId, - address module, - bytes memory initData - ) internal virtual override withHook { - if (moduleTypeId == MODULE_TYPE_HOOK) { - require(_hook == address(0), ERC7579HookModuleAlreadyPresent(_hook)); - _hook = module; - } - super._installModule(moduleTypeId, module, initData); - } - - /// @dev Uninstalls a module with support for hook modules. See {AccountERC7579-_uninstallModule} - function _uninstallModule( - uint256 moduleTypeId, - address module, - bytes memory deInitData - ) internal virtual override withHook { - if (moduleTypeId == MODULE_TYPE_HOOK) { - require(_hook == module, ERC7579Utils.ERC7579UninstalledModule(moduleTypeId, module)); - _hook = address(0); - } - super._uninstallModule(moduleTypeId, module, deInitData); - } - - /// @dev Hooked version of {AccountERC7579-_execute}. - function _execute( - Mode mode, - bytes calldata executionCalldata - ) internal virtual override withHook returns (bytes[] memory) { - return super._execute(mode, executionCalldata); - } - - /// @dev Hooked version of {AccountERC7579-_fallback}. - function _fallback() internal virtual override withHook returns (bytes memory) { - return super._fallback(); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-ERC7821.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-ERC7821.sol deleted file mode 100644 index a8f2236..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/extensions/draft-ERC7821.sol +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (account/extensions/draft-ERC7821.sol) - -pragma solidity ^0.8.20; - -import {ERC7579Utils, Mode, CallType, ExecType, ModeSelector} from "../utils/draft-ERC7579Utils.sol"; -import {IERC7821} from "../../interfaces/draft-IERC7821.sol"; -import {Account} from "../Account.sol"; - -/** - * @dev Minimal batch executor following ERC-7821. - * - * Only supports supports single batch mode (`0x01000000000000000000`). Does not support optional "opData". - * - * @custom:stateless - */ -abstract contract ERC7821 is IERC7821 { - using ERC7579Utils for *; - - error UnsupportedExecutionMode(); - - /** - * @dev Executes the calls in `executionData` with no optional `opData` support. - * - * NOTE: Access to this function is controlled by {_erc7821AuthorizedExecutor}. Changing access permissions, for - * example to approve calls by the ERC-4337 entrypoint, should be implemented by overriding it. - * - * Reverts and bubbles up error if any call fails. - */ - function execute(bytes32 mode, bytes calldata executionData) public payable virtual { - if (!_erc7821AuthorizedExecutor(msg.sender, mode, executionData)) - revert Account.AccountUnauthorized(msg.sender); - if (!supportsExecutionMode(mode)) revert UnsupportedExecutionMode(); - executionData.execBatch(ERC7579Utils.EXECTYPE_DEFAULT); - } - - /// @inheritdoc IERC7821 - function supportsExecutionMode(bytes32 mode) public view virtual returns (bool result) { - (CallType callType, ExecType execType, ModeSelector modeSelector, ) = Mode.wrap(mode).decodeMode(); - return - callType == ERC7579Utils.CALLTYPE_BATCH && - execType == ERC7579Utils.EXECTYPE_DEFAULT && - modeSelector == ModeSelector.wrap(0x00000000); - } - - /** - * @dev Access control mechanism for the {execute} function. - * By default, only the contract itself is allowed to execute. - * - * Override this function to implement custom access control, for example to allow the - * ERC-4337 entrypoint to execute. - * - * ```solidity - * function _erc7821AuthorizedExecutor( - * address caller, - * bytes32 mode, - * bytes calldata executionData - * ) internal view virtual override returns (bool) { - * return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); - * } - * ``` - */ - function _erc7821AuthorizedExecutor( - address caller, - bytes32 /* mode */, - bytes calldata /* executionData */ - ) internal view virtual returns (bool) { - return caller == address(this); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/EIP7702Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/EIP7702Utils.sol deleted file mode 100644 index 804d6c2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/EIP7702Utils.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (account/utils/EIP7702Utils.sol) - -pragma solidity ^0.8.20; - -/** - * @dev Library with common EIP-7702 utility functions. - * - * See https://eips.ethereum.org/EIPS/eip-7702[ERC-7702]. - */ -library EIP7702Utils { - bytes3 internal constant EIP7702_PREFIX = 0xef0100; - - /** - * @dev Returns the address of the delegate if `account` as an EIP-7702 delegation setup, or address(0) otherwise. - */ - function fetchDelegate(address account) internal view returns (address) { - bytes23 delegation = bytes23(account.code); - return bytes3(delegation) == EIP7702_PREFIX ? address(bytes20(delegation << 24)) : address(0); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC4337Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC4337Utils.sol deleted file mode 100644 index 6d2c8cc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC4337Utils.sol +++ /dev/null @@ -1,159 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (account/utils/draft-ERC4337Utils.sol) - -pragma solidity ^0.8.20; - -import {IEntryPoint, PackedUserOperation} from "../../interfaces/draft-IERC4337.sol"; -import {Math} from "../../utils/math/Math.sol"; -import {Calldata} from "../../utils/Calldata.sol"; -import {Packing} from "../../utils/Packing.sol"; - -/// @dev This is available on all entrypoint since v0.4.0, but is not formally part of the ERC. -interface IEntryPointExtra { - function getUserOpHash(PackedUserOperation calldata userOp) external view returns (bytes32); -} - -/** - * @dev Library with common ERC-4337 utility functions. - * - * See https://eips.ethereum.org/EIPS/eip-4337[ERC-4337]. - */ -library ERC4337Utils { - using Packing for *; - - /// @dev Address of the entrypoint v0.7.0 - IEntryPoint internal constant ENTRYPOINT_V07 = IEntryPoint(0x0000000071727De22E5E9d8BAf0edAc6f37da032); - - /// @dev Address of the entrypoint v0.8.0 - IEntryPoint internal constant ENTRYPOINT_V08 = IEntryPoint(0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108); - - /// @dev For simulation purposes, validateUserOp (and validatePaymasterUserOp) return this value on success. - uint256 internal constant SIG_VALIDATION_SUCCESS = 0; - - /// @dev For simulation purposes, validateUserOp (and validatePaymasterUserOp) must return this value in case of signature failure, instead of revert. - uint256 internal constant SIG_VALIDATION_FAILED = 1; - - /// @dev Parses the validation data into its components. See {packValidationData}. - function parseValidationData( - uint256 validationData - ) internal pure returns (address aggregator, uint48 validAfter, uint48 validUntil) { - validAfter = uint48(bytes32(validationData).extract_32_6(0)); - validUntil = uint48(bytes32(validationData).extract_32_6(6)); - aggregator = address(bytes32(validationData).extract_32_20(12)); - if (validUntil == 0) validUntil = type(uint48).max; - } - - /// @dev Packs the validation data into a single uint256. See {parseValidationData}. - function packValidationData( - address aggregator, - uint48 validAfter, - uint48 validUntil - ) internal pure returns (uint256) { - return uint256(bytes6(validAfter).pack_6_6(bytes6(validUntil)).pack_12_20(bytes20(aggregator))); - } - - /// @dev Same as {packValidationData}, but with a boolean signature success flag. - function packValidationData(bool sigSuccess, uint48 validAfter, uint48 validUntil) internal pure returns (uint256) { - return - packValidationData( - address(uint160(Math.ternary(sigSuccess, SIG_VALIDATION_SUCCESS, SIG_VALIDATION_FAILED))), - validAfter, - validUntil - ); - } - - /** - * @dev Combines two validation data into a single one. - * - * The `aggregator` is set to {SIG_VALIDATION_SUCCESS} if both are successful, while - * the `validAfter` is the maximum and the `validUntil` is the minimum of both. - */ - function combineValidationData(uint256 validationData1, uint256 validationData2) internal pure returns (uint256) { - (address aggregator1, uint48 validAfter1, uint48 validUntil1) = parseValidationData(validationData1); - (address aggregator2, uint48 validAfter2, uint48 validUntil2) = parseValidationData(validationData2); - - bool success = aggregator1 == address(uint160(SIG_VALIDATION_SUCCESS)) && - aggregator2 == address(uint160(SIG_VALIDATION_SUCCESS)); - uint48 validAfter = uint48(Math.max(validAfter1, validAfter2)); - uint48 validUntil = uint48(Math.min(validUntil1, validUntil2)); - return packValidationData(success, validAfter, validUntil); - } - - /// @dev Returns the aggregator of the `validationData` and whether it is out of time range. - function getValidationData(uint256 validationData) internal view returns (address aggregator, bool outOfTimeRange) { - (address aggregator_, uint48 validAfter, uint48 validUntil) = parseValidationData(validationData); - return (aggregator_, block.timestamp < validAfter || validUntil < block.timestamp); - } - - /// @dev Get the hash of a user operation for a given entrypoint - function hash(PackedUserOperation calldata self, address entrypoint) internal view returns (bytes32) { - // NOTE: getUserOpHash is available since v0.4.0 - // - // Prior to v0.8.0, this was easy to replicate for any entrypoint and chainId. Since v0.8.0 of the - // entrypoint, this depends on the Entrypoint's domain separator, which cannot be hardcoded and is complex - // to recompute. Domain separator could be fetch using the `getDomainSeparatorV4` getter, or recomputed from - // the ERC-5267 getter, but both operation would require doing a view call to the entrypoint. Overall it feels - // simpler and less error prone to get that functionality from the entrypoint directly. - return IEntryPointExtra(entrypoint).getUserOpHash(self); - } - - /// @dev Returns `factory` from the {PackedUserOperation}, or address(0) if the initCode is empty or not properly formatted. - function factory(PackedUserOperation calldata self) internal pure returns (address) { - return self.initCode.length < 20 ? address(0) : address(bytes20(self.initCode[0:20])); - } - - /// @dev Returns `factoryData` from the {PackedUserOperation}, or empty bytes if the initCode is empty or not properly formatted. - function factoryData(PackedUserOperation calldata self) internal pure returns (bytes calldata) { - return self.initCode.length < 20 ? Calldata.emptyBytes() : self.initCode[20:]; - } - - /// @dev Returns `verificationGasLimit` from the {PackedUserOperation}. - function verificationGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) { - return uint128(self.accountGasLimits.extract_32_16(0)); - } - - /// @dev Returns `callGasLimit` from the {PackedUserOperation}. - function callGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) { - return uint128(self.accountGasLimits.extract_32_16(16)); - } - - /// @dev Returns the first section of `gasFees` from the {PackedUserOperation}. - function maxPriorityFeePerGas(PackedUserOperation calldata self) internal pure returns (uint256) { - return uint128(self.gasFees.extract_32_16(0)); - } - - /// @dev Returns the second section of `gasFees` from the {PackedUserOperation}. - function maxFeePerGas(PackedUserOperation calldata self) internal pure returns (uint256) { - return uint128(self.gasFees.extract_32_16(16)); - } - - /// @dev Returns the total gas price for the {PackedUserOperation} (ie. `maxFeePerGas` or `maxPriorityFeePerGas + basefee`). - function gasPrice(PackedUserOperation calldata self) internal view returns (uint256) { - unchecked { - // Following values are "per gas" - uint256 maxPriorityFee = maxPriorityFeePerGas(self); - uint256 maxFee = maxFeePerGas(self); - return Math.min(maxFee, maxPriorityFee + block.basefee); - } - } - - /// @dev Returns the first section of `paymasterAndData` from the {PackedUserOperation}. - function paymaster(PackedUserOperation calldata self) internal pure returns (address) { - return self.paymasterAndData.length < 52 ? address(0) : address(bytes20(self.paymasterAndData[0:20])); - } - - /// @dev Returns the second section of `paymasterAndData` from the {PackedUserOperation}. - function paymasterVerificationGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) { - return self.paymasterAndData.length < 52 ? 0 : uint128(bytes16(self.paymasterAndData[20:36])); - } - - /// @dev Returns the third section of `paymasterAndData` from the {PackedUserOperation}. - function paymasterPostOpGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) { - return self.paymasterAndData.length < 52 ? 0 : uint128(bytes16(self.paymasterAndData[36:52])); - } - - /// @dev Returns the fourth section of `paymasterAndData` from the {PackedUserOperation}. - function paymasterData(PackedUserOperation calldata self) internal pure returns (bytes calldata) { - return self.paymasterAndData.length < 52 ? Calldata.emptyBytes() : self.paymasterAndData[52:]; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC7579Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC7579Utils.sol deleted file mode 100644 index 3e6544e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/account/utils/draft-ERC7579Utils.sol +++ /dev/null @@ -1,280 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (account/utils/draft-ERC7579Utils.sol) - -pragma solidity ^0.8.20; - -import {Execution} from "../../interfaces/draft-IERC7579.sol"; -import {Packing} from "../../utils/Packing.sol"; -import {Address} from "../../utils/Address.sol"; - -type Mode is bytes32; -type CallType is bytes1; -type ExecType is bytes1; -type ModeSelector is bytes4; -type ModePayload is bytes22; - -/** - * @dev Library with common ERC-7579 utility functions. - * - * See https://eips.ethereum.org/EIPS/eip-7579[ERC-7579]. - */ -// slither-disable-next-line unused-state -library ERC7579Utils { - using Packing for *; - - /// @dev A single `call` execution. - CallType internal constant CALLTYPE_SINGLE = CallType.wrap(0x00); - - /// @dev A batch of `call` executions. - CallType internal constant CALLTYPE_BATCH = CallType.wrap(0x01); - - /// @dev A `delegatecall` execution. - CallType internal constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF); - - /// @dev Default execution type that reverts on failure. - ExecType internal constant EXECTYPE_DEFAULT = ExecType.wrap(0x00); - - /// @dev Execution type that does not revert on failure. - ExecType internal constant EXECTYPE_TRY = ExecType.wrap(0x01); - - /** - * @dev Emits when an {EXECTYPE_TRY} execution fails. - * @param batchExecutionIndex The index of the failed call in the execution batch. - * @param returndata The returned data from the failed call. - */ - event ERC7579TryExecuteFail(uint256 batchExecutionIndex, bytes returndata); - - /// @dev The provided {CallType} is not supported. - error ERC7579UnsupportedCallType(CallType callType); - - /// @dev The provided {ExecType} is not supported. - error ERC7579UnsupportedExecType(ExecType execType); - - /// @dev The provided module doesn't match the provided module type. - error ERC7579MismatchedModuleTypeId(uint256 moduleTypeId, address module); - - /// @dev The module is not installed. - error ERC7579UninstalledModule(uint256 moduleTypeId, address module); - - /// @dev The module is already installed. - error ERC7579AlreadyInstalledModule(uint256 moduleTypeId, address module); - - /// @dev The module type is not supported. - error ERC7579UnsupportedModuleType(uint256 moduleTypeId); - - /// @dev Input calldata not properly formatted and possibly malicious. - error ERC7579DecodingError(); - - /// @dev Executes a single call. - function execSingle( - bytes calldata executionCalldata, - ExecType execType - ) internal returns (bytes[] memory returnData) { - (address target, uint256 value, bytes calldata callData) = decodeSingle(executionCalldata); - returnData = new bytes[](1); - returnData[0] = _call(0, execType, target, value, callData); - } - - /// @dev Executes a batch of calls. - function execBatch( - bytes calldata executionCalldata, - ExecType execType - ) internal returns (bytes[] memory returnData) { - Execution[] calldata executionBatch = decodeBatch(executionCalldata); - returnData = new bytes[](executionBatch.length); - for (uint256 i = 0; i < executionBatch.length; ++i) { - returnData[i] = _call( - i, - execType, - executionBatch[i].target, - executionBatch[i].value, - executionBatch[i].callData - ); - } - } - - /// @dev Executes a delegate call. - function execDelegateCall( - bytes calldata executionCalldata, - ExecType execType - ) internal returns (bytes[] memory returnData) { - (address target, bytes calldata callData) = decodeDelegate(executionCalldata); - returnData = new bytes[](1); - returnData[0] = _delegatecall(0, execType, target, callData); - } - - /// @dev Encodes the mode with the provided parameters. See {decodeMode}. - function encodeMode( - CallType callType, - ExecType execType, - ModeSelector selector, - ModePayload payload - ) internal pure returns (Mode mode) { - return - Mode.wrap( - CallType - .unwrap(callType) - .pack_1_1(ExecType.unwrap(execType)) - .pack_2_4(bytes4(0)) - .pack_6_4(ModeSelector.unwrap(selector)) - .pack_10_22(ModePayload.unwrap(payload)) - ); - } - - /// @dev Decodes the mode into its parameters. See {encodeMode}. - function decodeMode( - Mode mode - ) internal pure returns (CallType callType, ExecType execType, ModeSelector selector, ModePayload payload) { - return ( - CallType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 0)), - ExecType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 1)), - ModeSelector.wrap(Packing.extract_32_4(Mode.unwrap(mode), 6)), - ModePayload.wrap(Packing.extract_32_22(Mode.unwrap(mode), 10)) - ); - } - - /// @dev Encodes a single call execution. See {decodeSingle}. - function encodeSingle( - address target, - uint256 value, - bytes calldata callData - ) internal pure returns (bytes memory executionCalldata) { - return abi.encodePacked(target, value, callData); - } - - /// @dev Decodes a single call execution. See {encodeSingle}. - function decodeSingle( - bytes calldata executionCalldata - ) internal pure returns (address target, uint256 value, bytes calldata callData) { - target = address(bytes20(executionCalldata[0:20])); - value = uint256(bytes32(executionCalldata[20:52])); - callData = executionCalldata[52:]; - } - - /// @dev Encodes a delegate call execution. See {decodeDelegate}. - function encodeDelegate( - address target, - bytes calldata callData - ) internal pure returns (bytes memory executionCalldata) { - return abi.encodePacked(target, callData); - } - - /// @dev Decodes a delegate call execution. See {encodeDelegate}. - function decodeDelegate( - bytes calldata executionCalldata - ) internal pure returns (address target, bytes calldata callData) { - target = address(bytes20(executionCalldata[0:20])); - callData = executionCalldata[20:]; - } - - /// @dev Encodes a batch of executions. See {decodeBatch}. - function encodeBatch(Execution[] memory executionBatch) internal pure returns (bytes memory executionCalldata) { - return abi.encode(executionBatch); - } - - /// @dev Decodes a batch of executions. See {encodeBatch}. - /// - /// NOTE: This function runs some checks and will throw a {ERC7579DecodingError} if the input is not properly formatted. - function decodeBatch(bytes calldata executionCalldata) internal pure returns (Execution[] calldata executionBatch) { - unchecked { - uint256 bufferLength = executionCalldata.length; - - // Check executionCalldata is not empty. - if (bufferLength < 32) revert ERC7579DecodingError(); - - // Get the offset of the array (pointer to the array length). - uint256 arrayLengthOffset = uint256(bytes32(executionCalldata[0:32])); - - // The array length (at arrayLengthOffset) should be 32 bytes long. We check that this is within the - // buffer bounds. Since we know bufferLength is at least 32, we can subtract with no overflow risk. - if (arrayLengthOffset > bufferLength - 32) revert ERC7579DecodingError(); - - // Get the array length. arrayLengthOffset + 32 is bounded by bufferLength so it does not overflow. - uint256 arrayLength = uint256(bytes32(executionCalldata[arrayLengthOffset:arrayLengthOffset + 32])); - - // Check that the buffer is long enough to store the array elements as "offset pointer": - // - each element of the array is an "offset pointer" to the data. - // - each "offset pointer" (to an array element) takes 32 bytes. - // - validity of the calldata at that location is checked when the array element is accessed, so we only - // need to check that the buffer is large enough to hold the pointers. - // - // Since we know bufferLength is at least arrayLengthOffset + 32, we can subtract with no overflow risk. - // Solidity limits length of such arrays to 2**64-1, this guarantees `arrayLength * 32` does not overflow. - if (arrayLength > type(uint64).max || bufferLength - arrayLengthOffset - 32 < arrayLength * 32) - revert ERC7579DecodingError(); - - assembly ("memory-safe") { - executionBatch.offset := add(add(executionCalldata.offset, arrayLengthOffset), 0x20) - executionBatch.length := arrayLength - } - } - } - - /// @dev Executes a `call` to the target with the provided {ExecType}. - function _call( - uint256 index, - ExecType execType, - address target, - uint256 value, - bytes calldata data - ) private returns (bytes memory) { - (bool success, bytes memory returndata) = (target == address(0) ? address(this) : target).call{value: value}( - data - ); - return _validateExecutionMode(index, execType, success, returndata); - } - - /// @dev Executes a `delegatecall` to the target with the provided {ExecType}. - function _delegatecall( - uint256 index, - ExecType execType, - address target, - bytes calldata data - ) private returns (bytes memory) { - (bool success, bytes memory returndata) = (target == address(0) ? address(this) : target).delegatecall(data); - return _validateExecutionMode(index, execType, success, returndata); - } - - /// @dev Validates the execution mode and returns the returndata. - function _validateExecutionMode( - uint256 index, - ExecType execType, - bool success, - bytes memory returndata - ) private returns (bytes memory) { - if (execType == ERC7579Utils.EXECTYPE_DEFAULT) { - Address.verifyCallResult(success, returndata); - } else if (execType == ERC7579Utils.EXECTYPE_TRY) { - if (!success) emit ERC7579TryExecuteFail(index, returndata); - } else { - revert ERC7579UnsupportedExecType(execType); - } - return returndata; - } -} - -// Operators -using {eqCallType as ==} for CallType global; -using {eqExecType as ==} for ExecType global; -using {eqModeSelector as ==} for ModeSelector global; -using {eqModePayload as ==} for ModePayload global; - -/// @dev Compares two `CallType` values for equality. -function eqCallType(CallType a, CallType b) pure returns (bool) { - return CallType.unwrap(a) == CallType.unwrap(b); -} - -/// @dev Compares two `ExecType` values for equality. -function eqExecType(ExecType a, ExecType b) pure returns (bool) { - return ExecType.unwrap(a) == ExecType.unwrap(b); -} - -/// @dev Compares two `ModeSelector` values for equality. -function eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) { - return ModeSelector.unwrap(a) == ModeSelector.unwrap(b); -} - -/// @dev Compares two `ModePayload` values for equality. -function eqModePayload(ModePayload a, ModePayload b) pure returns (bool) { - return ModePayload.unwrap(a) == ModePayload.unwrap(b); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/README.adoc deleted file mode 100644 index c855cbb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/README.adoc +++ /dev/null @@ -1,14 +0,0 @@ -= 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 ERC-20 tokens for a given beneficiary. Custody of multiple tokens can - be given to this contract, which will release the token to the beneficiary following a given, customizable, vesting - schedule. - -== Contracts - -{{VestingWallet}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol deleted file mode 100644 index 03024fa..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol +++ /dev/null @@ -1,159 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.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 ERC-20 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 holds 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. - * - * NOTE: Chains with support for native ERC20s may allow the vesting wallet to withdraw the underlying asset as both an - * ERC20 and as native currency. For example, if chain C supports token A and the wallet gets deposited 100 A, then - * at 50% of the vesting period, the beneficiary can withdraw 50 A as ERC20 and 25 A as native currency (totaling 75 A). - * Consider disabling one of the withdrawal methods. - */ -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 beneficiary (owner), the start timestamp and the vesting duration (in seconds) 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWalletCliff.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWalletCliff.sol deleted file mode 100644 index dd1da65..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/finance/VestingWalletCliff.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (finance/VestingWalletCliff.sol) - -pragma solidity ^0.8.20; - -import {SafeCast} from "../utils/math/SafeCast.sol"; -import {VestingWallet} from "./VestingWallet.sol"; - -/** - * @dev Extension of {VestingWallet} that adds a cliff to the vesting schedule. - * - * _Available since v5.1._ - */ -abstract contract VestingWalletCliff is VestingWallet { - using SafeCast for *; - - uint64 private immutable _cliff; - - /// @dev The specified cliff duration is larger than the vesting duration. - error InvalidCliffDuration(uint64 cliffSeconds, uint64 durationSeconds); - - /** - * @dev Set the duration of the cliff, in seconds. The cliff starts vesting schedule (see {VestingWallet}'s - * constructor) and ends `cliffSeconds` later. - */ - constructor(uint64 cliffSeconds) { - if (cliffSeconds > duration()) { - revert InvalidCliffDuration(cliffSeconds, duration().toUint64()); - } - _cliff = start().toUint64() + cliffSeconds; - } - - /** - * @dev Getter for the cliff timestamp. - */ - function cliff() public view virtual returns (uint256) { - return _cliff; - } - - /** - * @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. Returns 0 if the {cliff} timestamp is not met. - * - * IMPORTANT: The cliff not only makes the schedule return 0, but it also ignores every possible side - * effect from calling the inherited implementation (i.e. `super._vestingSchedule`). Carefully consider - * this caveat if the overridden implementation of this function has any (e.g. writing to memory or reverting). - */ - function _vestingSchedule( - uint256 totalAllocation, - uint64 timestamp - ) internal view virtual override returns (uint256) { - return timestamp < cliff() ? 0 : super._vestingSchedule(totalAllocation, timestamp); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/Governor.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/Governor.sol deleted file mode 100644 index 05564b8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/Governor.sol +++ /dev/null @@ -1,818 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/Governor.sol) - -pragma solidity ^0.8.24; - -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 {Strings} from "../utils/Strings.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 {_quorumReached}, {_voteSucceeded} and {_countVote} - * - A voting module must implement {_getVotes} - * - Additionally, {votingPeriod}, {votingDelay}, and {quorum} 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(); - } - } - - /// @inheritdoc IERC165 - function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { - return - interfaceId == type(IGovernor).interfaceId || - interfaceId == type(IGovernor).interfaceId ^ IGovernor.getProposalId.selector || - interfaceId == type(IERC1155Receiver).interfaceId || - super.supportsInterface(interfaceId); - } - - /// @inheritdoc IGovernor - function name() public view virtual returns (string memory) { - return _name; - } - - /// @inheritdoc IGovernor - 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))); - } - - /// @inheritdoc IGovernor - function getProposalId( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) public view virtual returns (uint256) { - return hashProposal(targets, values, calldatas, descriptionHash); - } - - /// @inheritdoc IGovernor - 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; - } - } - - /// @inheritdoc IGovernor - function proposalThreshold() public view virtual returns (uint256) { - return 0; - } - - /// @inheritdoc IGovernor - function proposalSnapshot(uint256 proposalId) public view virtual returns (uint256) { - return _proposals[proposalId].voteStart; - } - - /// @inheritdoc IGovernor - function proposalDeadline(uint256 proposalId) public view virtual returns (uint256) { - return _proposals[proposalId].voteStart + _proposals[proposalId].voteDuration; - } - - /// @inheritdoc IGovernor - function proposalProposer(uint256 proposalId) public view virtual returns (address) { - return _proposals[proposalId].proposer; - } - - /// @inheritdoc IGovernor - function proposalEta(uint256 proposalId) public view virtual returns (uint256) { - return _proposals[proposalId].etaSeconds; - } - - /// @inheritdoc IGovernor - 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 totalWeight, - bytes memory params - ) internal virtual returns (uint256); - - /** - * @dev Hook that should be called every time the tally for a proposal is updated. - * - * Note: This function must run successfully. Reverts will result in the bricking of governance - */ - function _tallyUpdated(uint256 proposalId) 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 votesThreshold = proposalThreshold(); - if (votesThreshold > 0) { - uint256 proposerVotes = getVotes(proposer, clock() - 1); - 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 = getProposalId(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 - } - - /// @inheritdoc IGovernor - function queue( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) public virtual returns (uint256) { - uint256 proposalId = getProposalId(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; - } - - /// @inheritdoc IGovernor - function execute( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) public payable virtual returns (uint256) { - uint256 proposalId = getProposalId(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}. - */ - 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); - } - } - - /// @inheritdoc IGovernor - 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 `getProposalId` duplication has a cost that is limited, and that we accept. - uint256 proposalId = getProposalId(targets, values, calldatas, descriptionHash); - - address caller = _msgSender(); - if (!_validateCancel(proposalId, caller)) revert GovernorUnableToCancel(proposalId, caller); - - 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 = getProposalId(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; - } - - /// @inheritdoc IGovernor - function getVotes(address account, uint256 timepoint) public view virtual returns (uint256) { - return _getVotes(account, timepoint, _defaultParams()); - } - - /// @inheritdoc IGovernor - function getVotesWithParams( - address account, - uint256 timepoint, - bytes memory params - ) public view virtual returns (uint256) { - return _getVotes(account, timepoint, params); - } - - /// @inheritdoc IGovernor - function castVote(uint256 proposalId, uint8 support) public virtual returns (uint256) { - address voter = _msgSender(); - return _castVote(proposalId, voter, support, ""); - } - - /// @inheritdoc IGovernor - function castVoteWithReason( - uint256 proposalId, - uint8 support, - string calldata reason - ) public virtual returns (uint256) { - address voter = _msgSender(); - return _castVote(proposalId, voter, support, reason); - } - - /// @inheritdoc IGovernor - 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); - } - - /// @inheritdoc IGovernor - function castVoteBySig( - uint256 proposalId, - uint8 support, - address voter, - bytes memory signature - ) public virtual returns (uint256) { - if (!_validateVoteSig(proposalId, support, voter, signature)) { - revert GovernorInvalidSignature(voter); - } - return _castVote(proposalId, voter, support, ""); - } - - /// @inheritdoc IGovernor - function castVoteWithReasonAndParamsBySig( - uint256 proposalId, - uint8 support, - address voter, - string calldata reason, - bytes memory params, - bytes memory signature - ) public virtual returns (uint256) { - if (!_validateExtendedVoteSig(proposalId, support, voter, reason, params, signature)) { - revert GovernorInvalidSignature(voter); - } - return _castVote(proposalId, voter, support, reason, params); - } - - /// @dev Validate the `signature` used in {castVoteBySig} function. - function _validateVoteSig( - uint256 proposalId, - uint8 support, - address voter, - bytes memory signature - ) internal virtual returns (bool) { - return - SignatureChecker.isValidSignatureNow( - voter, - _hashTypedDataV4(keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support, voter, _useNonce(voter)))), - signature - ); - } - - /// @dev Validate the `signature` used in {castVoteWithReasonAndParamsBySig} function. - function _validateExtendedVoteSig( - uint256 proposalId, - uint8 support, - address voter, - string memory reason, - bytes memory params, - bytes memory signature - ) internal virtual returns (bool) { - return - SignatureChecker.isValidSignatureNow( - voter, - _hashTypedDataV4( - keccak256( - abi.encode( - EXTENDED_BALLOT_TYPEHASH, - proposalId, - support, - voter, - _useNonce(voter), - keccak256(bytes(reason)), - keccak256(params) - ) - ) - ), - signature - ); - } - - /** - * @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 totalWeight = _getVotes(account, proposalSnapshot(proposalId), params); - uint256 votedWeight = _countVote(proposalId, account, support, totalWeight, params); - - if (params.length == 0) { - emit VoteCast(account, proposalId, support, votedWeight, reason); - } else { - emit VoteCastWithParams(account, proposalId, support, votedWeight, reason, params); - } - - _tallyUpdated(proposalId); - - return votedWeight; - } - - /** - * @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) internal 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) { - unchecked { - uint256 length = bytes(description).length; - - // Length is too short to contain a valid proposer suffix - if (length < 52) { - return true; - } - - // Extract what would be the `#proposer=` marker beginning the suffix - bytes10 marker = bytes10(_unsafeReadBytesOffset(bytes(description), length - 52)); - - // If the marker is not found, there is no proposer suffix to check - if (marker != bytes10("#proposer=")) { - return true; - } - - // Check that the last 42 characters (after the marker) are a properly formatted address. - (bool success, address recovered) = Strings.tryParseAddress(description, length - 42, length); - return !success || recovered == proposer; - } - } - - /** - * @dev Check if the `caller` can cancel the proposal with the given `proposalId`. - * - * The default implementation allows the proposal proposer to cancel the proposal during the pending state. - */ - function _validateCancel(uint256 proposalId, address caller) internal view virtual returns (bool) { - return (state(proposalId) == ProposalState.Pending) && caller == proposalProposer(proposalId); - } - - /// @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); - - /** - * @dev Reads a bytes32 from a bytes array without bounds checking. - * - * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the - * assembly block as such would prevent some optimizations. - */ - function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) { - // This is not memory safe in the general case, but all calls to this private function are within bounds. - assembly ("memory-safe") { - value := mload(add(add(buffer, 0x20), offset)) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol deleted file mode 100644 index b3f0feb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol +++ /dev/null @@ -1,454 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/IGovernor.sol) - -pragma solidity >=0.8.4; - -import {IERC165} from "../interfaces/IERC165.sol"; -import {IERC6372} from "../interfaces/IERC6372.sol"; - -/** - * @dev Interface of the {Governor} core. - * - * NOTE: Event parameters lack the `indexed` keyword for compatibility with GovernorBravo events. - * Making event parameters `indexed` affects how events are decoded, potentially breaking existing indexers. - */ -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 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 The provided params buffer is not supported by the counting module. - */ - error GovernorInvalidVoteParams(); - - /** - * @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 The given `account` is unable to cancel the proposal with given `proposalId`. - */ - error GovernorUnableToCancel(uint256 proposalId, address account); - - /** - * @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 interpretation 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 EIP-712 domain separator). - */ - function name() external view returns (string memory); - - /** - * @notice module:core - * @dev Version of the governor instance (used in building the EIP-712 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. - * - * NOTE: For all off-chain and external calls, use {getProposalId}. - */ - function hashProposal( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) external pure returns (uint256); - - /** - * @notice module:core - * @dev Function used to get the proposal id from the proposal details. - */ - function getProposalId( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) external view 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 ERC-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 ERC-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. - * - * NOTE: The state of the Governor and `targets` may change between the proposal creation and its execution. - * This may be the result of third party actions on the targeted contracts, or other governor proposals. - * For example, the balance of this contract could be updated or its access control permissions may be modified, - * possibly compromising the proposal's ability to execute successfully (e.g. the governor doesn't have enough - * value to cover a proposal with multiple transfers). - */ - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/README.adoc deleted file mode 100644 index 3131a0b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/README.adoc +++ /dev/null @@ -1,197 +0,0 @@ -= 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 {IVotes} contract. - -* {GovernorVotesQuorumFraction}: Combines with `GovernorVotes` to set the quorum as a fraction of the total token supply. - -* {GovernorVotesSuperQuorumFraction}: Combines `GovernorSuperQuorum` with `GovernorVotesQuorumFraction` to set the super 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. - -* {GovernorCountingFractional}: A more modular voting system that allows a user to vote with only part of its voting power, and to split that weight arbitrarily between the 3 different options (Against, For and Abstain). - -* {GovernorCountingOverridable}: An extended version of `GovernorCountingSimple` which allows delegatees to override their delegates while the vote is live. Must be used in conjunction with {VotesExtended}. - -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. - -* {GovernorTimelockAccess}: Connects with an instance of an {AccessManager}. This allows restrictions (and delays) enforced by the manager to be considered by the Governor and integrated into the AccessManager's "schedule + execute" workflow. - -* {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. - -* {GovernorProposalGuardian}: Adds a proposal guardian that can cancel proposals at any stage in their lifecycle--this permission is passed on to the proposers if the guardian is not set. - -* {GovernorSuperQuorum}: Extension of {Governor} with a super quorum. Proposals that meet the super quorum (and have a majority of for votes) advance to the `Succeeded` state before the proposal deadline. - -* {GovernorNoncesKeyed}: An extension of {Governor} with support for keyed nonces in addition to traditional nonces when voting by signature. - -In addition to modules and extensions, the core contract requires a few virtual functions to be implemented to your particular specifications: - -* <>: Delay (in ERC-6372 clock) since the proposal is submitted until voting power is fixed and voting starts. This can be used to enforce a delay after a proposal is published for users to buy tokens, or delegate their votes. -* <>: Delay (in ERC-6372 clock) since the proposal starts until voting ends. -* <>: Quorum required for a proposal to be successful. This function includes a `timepoint` argument (see ERC-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}} - -{{GovernorCountingFractional}} - -{{GovernorCountingOverridable}} - -{{GovernorVotes}} - -{{GovernorVotesQuorumFraction}} - -{{GovernorVotesSuperQuorumFraction}} - -=== Extensions - -{{GovernorTimelockAccess}} - -{{GovernorTimelockControl}} - -{{GovernorTimelockCompound}} - -{{GovernorSettings}} - -{{GovernorPreventLateQuorum}} - -{{GovernorStorage}} - -{{GovernorProposalGuardian}} - -{{GovernorSuperQuorum}} - -{{GovernorNoncesKeyed}} - -== Utils - -{{Votes}} - -{{VotesExtended}} - -== 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. 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 rescheduled. - -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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol deleted file mode 100644 index 17fef92..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol +++ /dev/null @@ -1,471 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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"; -import {IERC165} from "../utils/introspection/ERC165.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 virtual {} - - /// @inheritdoc IERC165 - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingFractional.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingFractional.sol deleted file mode 100644 index 1460d2d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingFractional.sol +++ /dev/null @@ -1,190 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorCountingFractional.sol) - -pragma solidity ^0.8.24; - -import {IGovernor, Governor} from "../Governor.sol"; -import {GovernorCountingSimple} from "./GovernorCountingSimple.sol"; -import {Math} from "../../utils/math/Math.sol"; - -/** - * @dev Extension of {Governor} for fractional voting. - * - * Similar to {GovernorCountingSimple}, this contract is a votes counting module for {Governor} that supports 3 options: - * Against, For, Abstain. Additionally, it includes a fourth option: Fractional, which allows voters to split their voting - * power amongst the other 3 options. - * - * Votes cast with the Fractional support must be accompanied by a `params` argument that is three packed `uint128` values - * representing the weight the delegate assigns to Against, For, and Abstain respectively. For those votes cast for the other - * 3 options, the `params` argument must be empty. - * - * This is mostly useful when the delegate is a contract that implements its own rules for voting. These delegate-contracts - * can cast fractional votes according to the preferences of multiple entities delegating their voting power. - * - * Some example use cases include: - * - * * Voting from tokens that are held by a DeFi pool - * * Voting from an L2 with tokens held by a bridge - * * Voting privately from a shielded pool using zero knowledge proofs. - * - * Based on ScopeLift's https://github.com/ScopeLift/flexible-voting/blob/e5de2efd1368387b840931f19f3c184c85842761/src/GovernorCountingFractional.sol[`GovernorCountingFractional`] - * - * _Available since v5.1._ - */ -abstract contract GovernorCountingFractional is Governor { - using Math for *; - - uint8 internal constant VOTE_TYPE_FRACTIONAL = 255; - - struct ProposalVote { - uint256 againstVotes; - uint256 forVotes; - uint256 abstainVotes; - mapping(address voter => uint256) usedVotes; - } - - /** - * @dev Mapping from proposal ID to vote tallies for that proposal. - */ - mapping(uint256 proposalId => ProposalVote) private _proposalVotes; - - /** - * @dev A fractional vote params uses more votes than are available for that user. - */ - error GovernorExceedRemainingWeight(address voter, uint256 usedVotes, uint256 remainingWeight); - - /// @inheritdoc IGovernor - // solhint-disable-next-line func-name-mixedcase - function COUNTING_MODE() public pure virtual override returns (string memory) { - return "support=bravo,fractional&quorum=for,abstain¶ms=fractional"; - } - - /// @inheritdoc IGovernor - function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) { - return usedVotes(proposalId, account) > 0; - } - - /** - * @dev Get the number of votes already cast by `account` for a proposal with `proposalId`. Useful for - * integrations that allow delegates to cast rolling, partial votes. - */ - function usedVotes(uint256 proposalId, address account) public view virtual returns (uint256) { - return _proposalVotes[proposalId].usedVotes[account]; - } - - /** - * @dev Get current distribution of votes for a given proposal. - */ - 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); - } - - /// @inheritdoc Governor - 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, forVotes must be > 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}. Function that records the delegate's votes. - * - * Executing this function consumes (part of) the delegate's weight on the proposal. This weight can be - * distributed amongst the 3 options (Against, For, Abstain) by specifying a fractional `support`. - * - * This counting module supports two vote casting modes: nominal and fractional. - * - * - Nominal: A nominal vote is cast by setting `support` to one of the 3 bravo options (Against, For, Abstain). - * - Fractional: A fractional vote is cast by setting `support` to `type(uint8).max` (255). - * - * Casting a nominal vote requires `params` to be empty and consumes the delegate's full remaining weight on the - * proposal for the specified `support` option. This is similar to the {GovernorCountingSimple} module and follows - * the `VoteType` enum from Governor Bravo. As a consequence, no vote weight remains unspent so no further voting - * is possible (for this `proposalId` and this `account`). - * - * Casting a fractional vote consumes a fraction of the delegate's remaining weight on the proposal according to the - * weights the delegate assigns to each support option (Against, For, Abstain respectively). The sum total of the - * three decoded vote weights _must_ be less than or equal to the delegate's remaining weight on the proposal (i.e. - * their checkpointed total weight minus votes already cast on the proposal). This format can be produced using: - * - * `abi.encodePacked(uint128(againstVotes), uint128(forVotes), uint128(abstainVotes))` - * - * NOTE: Consider that fractional voting restricts the number of casted votes (in each category) to 128 bits. - * Depending on how many decimals the underlying token has, a single voter may require to split their vote into - * multiple vote operations. For precision higher than ~30 decimals, large token holders may require a - * potentially large number of calls to cast all their votes. The voter has the possibility to cast all the - * remaining votes in a single operation using the traditional "bravo" vote. - */ - // slither-disable-next-line cyclomatic-complexity - function _countVote( - uint256 proposalId, - address account, - uint8 support, - uint256 totalWeight, - bytes memory params - ) internal virtual override returns (uint256) { - // Compute number of remaining votes. Returns 0 on overflow. - (, uint256 remainingWeight) = totalWeight.trySub(usedVotes(proposalId, account)); - if (remainingWeight == 0) { - revert GovernorAlreadyCastVote(account); - } - - uint256 againstVotes = 0; - uint256 forVotes = 0; - uint256 abstainVotes = 0; - uint256 usedWeight = 0; - - // For clarity of event indexing, fractional voting must be clearly advertised in the "support" field. - // - // Supported `support` value must be: - // - "Full" voting: `support = 0` (Against), `1` (For) or `2` (Abstain), with empty params. - // - "Fractional" voting: `support = 255`, with 48 bytes params. - if (support == uint8(GovernorCountingSimple.VoteType.Against)) { - if (params.length != 0) revert GovernorInvalidVoteParams(); - usedWeight = againstVotes = remainingWeight; - } else if (support == uint8(GovernorCountingSimple.VoteType.For)) { - if (params.length != 0) revert GovernorInvalidVoteParams(); - usedWeight = forVotes = remainingWeight; - } else if (support == uint8(GovernorCountingSimple.VoteType.Abstain)) { - if (params.length != 0) revert GovernorInvalidVoteParams(); - usedWeight = abstainVotes = remainingWeight; - } else if (support == VOTE_TYPE_FRACTIONAL) { - // The `params` argument is expected to be three packed `uint128`: - // `abi.encodePacked(uint128(againstVotes), uint128(forVotes), uint128(abstainVotes))` - if (params.length != 0x30) revert GovernorInvalidVoteParams(); - - assembly ("memory-safe") { - againstVotes := shr(128, mload(add(params, 0x20))) - forVotes := shr(128, mload(add(params, 0x30))) - abstainVotes := shr(128, mload(add(params, 0x40))) - usedWeight := add(add(againstVotes, forVotes), abstainVotes) // inputs are uint128: cannot overflow - } - - // check parsed arguments are valid - if (usedWeight > remainingWeight) { - revert GovernorExceedRemainingWeight(account, usedWeight, remainingWeight); - } - } else { - revert GovernorInvalidVoteType(); - } - - // update votes tracking - ProposalVote storage details = _proposalVotes[proposalId]; - if (againstVotes > 0) details.againstVotes += againstVotes; - if (forVotes > 0) details.forVotes += forVotes; - if (abstainVotes > 0) details.abstainVotes += abstainVotes; - details.usedVotes[account] += usedWeight; - - return usedWeight; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingOverridable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingOverridable.sol deleted file mode 100644 index 45a72ea..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingOverridable.sol +++ /dev/null @@ -1,222 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorCountingOverridable.sol) - -pragma solidity ^0.8.24; - -import {SignatureChecker} from "../../utils/cryptography/SignatureChecker.sol"; -import {SafeCast} from "../../utils/math/SafeCast.sol"; -import {VotesExtended} from "../utils/VotesExtended.sol"; -import {GovernorVotes} from "./GovernorVotes.sol"; -import {IGovernor, Governor} from "../Governor.sol"; - -/** - * @dev Extension of {Governor} which enables delegators to override the vote of their delegates. This module requires a - * token that inherits {VotesExtended}. - */ -abstract contract GovernorCountingOverridable is GovernorVotes { - bytes32 public constant OVERRIDE_BALLOT_TYPEHASH = - keccak256("OverrideBallot(uint256 proposalId,uint8 support,address voter,uint256 nonce,string reason)"); - - /** - * @dev Supported vote types. Matches Governor Bravo ordering. - */ - enum VoteType { - Against, - For, - Abstain - } - - struct VoteReceipt { - uint8 casted; // 0 if vote was not casted. Otherwise: support + 1 - bool hasOverridden; - uint208 overriddenWeight; - } - - struct ProposalVote { - uint256[3] votes; - mapping(address voter => VoteReceipt) voteReceipt; - } - - /// @dev The votes casted by `delegate` were reduced by `weight` after an override vote was casted by the original token holder - event VoteReduced(address indexed delegate, uint256 proposalId, uint8 support, uint256 weight); - - /// @dev A delegated vote on `proposalId` was overridden by `weight` - event OverrideVoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason); - - error GovernorAlreadyOverriddenVote(address account); - - mapping(uint256 proposalId => ProposalVote) private _proposalVotes; - - /// @inheritdoc IGovernor - // solhint-disable-next-line func-name-mixedcase - function COUNTING_MODE() public pure virtual override returns (string memory) { - return "support=bravo,override&quorum=for,abstain&overridable=true"; - } - - /** - * @dev See {IGovernor-hasVoted}. - * - * NOTE: Calling {castVote} (or similar) casts a vote using the voting power that is delegated to the voter. - * Conversely, calling {castOverrideVote} (or similar) uses the voting power of the account itself, from its asset - * balances. Casting an "override vote" does not count as voting and won't be reflected by this getter. Consider - * using {hasVotedOverride} to check if an account has casted an "override vote" for a given proposal id. - */ - function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) { - return _proposalVotes[proposalId].voteReceipt[account].casted != 0; - } - - /** - * @dev Check if an `account` has overridden their delegate for a proposal. - */ - function hasVotedOverride(uint256 proposalId, address account) public view virtual returns (bool) { - return _proposalVotes[proposalId].voteReceipt[account].hasOverridden; - } - - /** - * @dev Accessor to the internal vote counts. - */ - function proposalVotes( - uint256 proposalId - ) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) { - uint256[3] storage votes = _proposalVotes[proposalId].votes; - return (votes[uint8(VoteType.Against)], votes[uint8(VoteType.For)], votes[uint8(VoteType.Abstain)]); - } - - /// @inheritdoc Governor - function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) { - uint256[3] storage votes = _proposalVotes[proposalId].votes; - return quorum(proposalSnapshot(proposalId)) <= votes[uint8(VoteType.For)] + votes[uint8(VoteType.Abstain)]; - } - - /** - * @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) { - uint256[3] storage votes = _proposalVotes[proposalId].votes; - return votes[uint8(VoteType.For)] > votes[uint8(VoteType.Against)]; - } - - /** - * @dev See {Governor-_countVote}. In this module, the support follows the `VoteType` enum (from Governor Bravo). - * - * NOTE: called by {Governor-_castVote} which emits the {IGovernor-VoteCast} (or {IGovernor-VoteCastWithParams}) - * event. - */ - function _countVote( - uint256 proposalId, - address account, - uint8 support, - uint256 totalWeight, - bytes memory /*params*/ - ) internal virtual override returns (uint256) { - ProposalVote storage proposalVote = _proposalVotes[proposalId]; - - if (support > uint8(VoteType.Abstain)) { - revert GovernorInvalidVoteType(); - } - - if (proposalVote.voteReceipt[account].casted != 0) { - revert GovernorAlreadyCastVote(account); - } - - totalWeight -= proposalVote.voteReceipt[account].overriddenWeight; - proposalVote.votes[support] += totalWeight; - proposalVote.voteReceipt[account].casted = support + 1; - - return totalWeight; - } - - /** - * @dev Variant of {Governor-_countVote} that deals with vote overrides. - * - * NOTE: See {hasVoted} for more details about the difference between {castVote} and {castOverrideVote}. - */ - function _countOverride(uint256 proposalId, address account, uint8 support) internal virtual returns (uint256) { - ProposalVote storage proposalVote = _proposalVotes[proposalId]; - - if (support > uint8(VoteType.Abstain)) { - revert GovernorInvalidVoteType(); - } - - if (proposalVote.voteReceipt[account].hasOverridden) { - revert GovernorAlreadyOverriddenVote(account); - } - - uint256 snapshot = proposalSnapshot(proposalId); - uint256 overriddenWeight = VotesExtended(address(token())).getPastBalanceOf(account, snapshot); - address delegate = VotesExtended(address(token())).getPastDelegate(account, snapshot); - uint8 delegateCasted = proposalVote.voteReceipt[delegate].casted; - - proposalVote.voteReceipt[account].hasOverridden = true; - proposalVote.votes[support] += overriddenWeight; - if (delegateCasted == 0) { - proposalVote.voteReceipt[delegate].overriddenWeight += SafeCast.toUint208(overriddenWeight); - } else { - uint8 delegateSupport = delegateCasted - 1; - proposalVote.votes[delegateSupport] -= overriddenWeight; - emit VoteReduced(delegate, proposalId, delegateSupport, overriddenWeight); - } - - return overriddenWeight; - } - - /// @dev Variant of {Governor-_castVote} that deals with vote overrides. Returns the overridden weight. - function _castOverride( - uint256 proposalId, - address account, - uint8 support, - string calldata reason - ) internal virtual returns (uint256) { - _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Active)); - - uint256 overriddenWeight = _countOverride(proposalId, account, support); - - emit OverrideVoteCast(account, proposalId, support, overriddenWeight, reason); - - _tallyUpdated(proposalId); - - return overriddenWeight; - } - - /// @dev Public function for casting an override vote. Returns the overridden weight. - function castOverrideVote( - uint256 proposalId, - uint8 support, - string calldata reason - ) public virtual returns (uint256) { - address voter = _msgSender(); - return _castOverride(proposalId, voter, support, reason); - } - - /// @dev Public function for casting an override vote using a voter's signature. Returns the overridden weight. - function castOverrideVoteBySig( - uint256 proposalId, - uint8 support, - address voter, - string calldata reason, - bytes calldata signature - ) public virtual returns (uint256) { - bool valid = SignatureChecker.isValidSignatureNow( - voter, - _hashTypedDataV4( - keccak256( - abi.encode( - OVERRIDE_BALLOT_TYPEHASH, - proposalId, - support, - voter, - _useNonce(voter), - keccak256(bytes(reason)) - ) - ) - ), - signature - ); - - if (!valid) { - revert GovernorInvalidSignature(voter); - } - - return _castOverride(proposalId, voter, support, reason); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol deleted file mode 100644 index 3f24a65..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorCountingSimple.sol) - -pragma solidity ^0.8.24; - -import {IGovernor, 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; - - /// @inheritdoc IGovernor - // solhint-disable-next-line func-name-mixedcase - function COUNTING_MODE() public pure virtual override returns (string memory) { - return "support=bravo&quorum=for,abstain"; - } - - /// @inheritdoc IGovernor - 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); - } - - /// @inheritdoc Governor - 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 totalWeight, - bytes memory // params - ) internal virtual override returns (uint256) { - ProposalVote storage proposalVote = _proposalVotes[proposalId]; - - if (proposalVote.hasVoted[account]) { - revert GovernorAlreadyCastVote(account); - } - proposalVote.hasVoted[account] = true; - - if (support == uint8(VoteType.Against)) { - proposalVote.againstVotes += totalWeight; - } else if (support == uint8(VoteType.For)) { - proposalVote.forVotes += totalWeight; - } else if (support == uint8(VoteType.Abstain)) { - proposalVote.abstainVotes += totalWeight; - } else { - revert GovernorInvalidVoteType(); - } - - return totalWeight; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorNoncesKeyed.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorNoncesKeyed.sol deleted file mode 100644 index c506b7e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorNoncesKeyed.sol +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorNoncesKeyed.sol) - -pragma solidity ^0.8.24; - -import {Governor} from "../Governor.sol"; -import {Nonces} from "../../utils/Nonces.sol"; -import {NoncesKeyed} from "../../utils/NoncesKeyed.sol"; -import {SignatureChecker} from "../../utils/cryptography/SignatureChecker.sol"; - -/** - * @dev An extension of {Governor} that extends existing nonce management to use {NoncesKeyed}, where the key is the low-order 192 bits of the `proposalId`. - * This is useful for voting by signature while maintaining separate sequences of nonces for each proposal. - * - * NOTE: Traditional (un-keyed) nonces are still supported and can continue to be used as if this extension was not present. - */ -abstract contract GovernorNoncesKeyed is Governor, NoncesKeyed { - function _useCheckedNonce(address owner, uint256 nonce) internal virtual override(Nonces, NoncesKeyed) { - super._useCheckedNonce(owner, nonce); - } - - /** - * @dev Check the signature against keyed nonce and falls back to the traditional nonce. - * - * NOTE: This function won't call `super._validateVoteSig` if the keyed nonce is valid. - * Side effects may be skipped depending on the linearization of the function. - */ - function _validateVoteSig( - uint256 proposalId, - uint8 support, - address voter, - bytes memory signature - ) internal virtual override returns (bool) { - if ( - SignatureChecker.isValidSignatureNow( - voter, - _hashTypedDataV4( - keccak256( - abi.encode(BALLOT_TYPEHASH, proposalId, support, voter, nonces(voter, uint192(proposalId))) - ) - ), - signature - ) - ) { - _useNonce(voter, uint192(proposalId)); - return true; - } else { - return super._validateVoteSig(proposalId, support, voter, signature); - } - } - - /** - * @dev Check the signature against keyed nonce and falls back to the traditional nonce. - * - * NOTE: This function won't call `super._validateExtendedVoteSig` if the keyed nonce is valid. - * Side effects may be skipped depending on the linearization of the function. - */ - function _validateExtendedVoteSig( - uint256 proposalId, - uint8 support, - address voter, - string memory reason, - bytes memory params, - bytes memory signature - ) internal virtual override returns (bool) { - if ( - SignatureChecker.isValidSignatureNow( - voter, - _hashTypedDataV4( - keccak256( - abi.encode( - EXTENDED_BALLOT_TYPEHASH, - proposalId, - support, - voter, - nonces(voter, uint192(proposalId)), - keccak256(bytes(reason)), - keccak256(params) - ) - ) - ), - signature - ) - ) { - _useNonce(voter, uint192(proposalId)); - return true; - } else { - return super._validateExtendedVoteSig(proposalId, support, voter, reason, params, signature); - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol deleted file mode 100644 index 581f96e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorPreventLateQuorum.sol) - -pragma solidity ^0.8.24; - -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 Vote tally updated and detects if it caused quorum to be reached, potentially extending the voting period. - * - * May emit a {ProposalExtended} event. - */ - function _tallyUpdated(uint256 proposalId) internal virtual override { - super._tallyUpdated(proposalId); - if (_extendedDeadlines[proposalId] == 0 && _quorumReached(proposalId)) { - uint48 extendedDeadline = clock() + lateQuorumVoteExtension(); - - if (extendedDeadline > proposalDeadline(proposalId)) { - emit ProposalExtended(proposalId, extendedDeadline); - } - - _extendedDeadlines[proposalId] = extendedDeadline; - } - } - - /** - * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorProposalGuardian.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorProposalGuardian.sol deleted file mode 100644 index 5ff0c18..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorProposalGuardian.sol +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorProposalGuardian.sol) -pragma solidity ^0.8.24; - -import {Governor} from "../Governor.sol"; - -/** - * @dev Extension of {Governor} which adds a proposal guardian that can cancel proposals at any stage in the proposal's lifecycle. - * - * NOTE: if the proposal guardian is not configured, then proposers take this role for their proposals. - */ -abstract contract GovernorProposalGuardian is Governor { - address private _proposalGuardian; - - event ProposalGuardianSet(address oldProposalGuardian, address newProposalGuardian); - - /** - * @dev Getter that returns the address of the proposal guardian. - */ - function proposalGuardian() public view virtual returns (address) { - return _proposalGuardian; - } - - /** - * @dev Update the proposal guardian's address. This operation can only be performed through a governance proposal. - * - * Emits a {ProposalGuardianSet} event. - */ - function setProposalGuardian(address newProposalGuardian) public virtual onlyGovernance { - _setProposalGuardian(newProposalGuardian); - } - - /** - * @dev Internal setter for the proposal guardian. - * - * Emits a {ProposalGuardianSet} event. - */ - function _setProposalGuardian(address newProposalGuardian) internal virtual { - emit ProposalGuardianSet(_proposalGuardian, newProposalGuardian); - _proposalGuardian = newProposalGuardian; - } - - /** - * @dev Override {Governor-_validateCancel} to implement the extended cancellation logic. - * - * * The {proposalGuardian} can cancel any proposal at any point. - * * If no proposal guardian is set, the {IGovernor-proposalProposer} can cancel their proposals at any point. - * * In any case, permissions defined in {Governor-_validateCancel} (or another override) remains valid. - */ - function _validateCancel(uint256 proposalId, address caller) internal view virtual override returns (bool) { - address guardian = proposalGuardian(); - - return - guardian == caller || - (guardian == address(0) && caller == proposalProposer(proposalId)) || - super._validateCancel(proposalId, caller); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSequentialProposalId.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSequentialProposalId.sol deleted file mode 100644 index d6869bb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSequentialProposalId.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorSequentialProposalId.sol) - -pragma solidity ^0.8.24; - -import {IGovernor, Governor} from "../Governor.sol"; - -/** - * @dev Extension of {Governor} that changes the numbering of proposal ids from the default hash-based approach to - * sequential ids. - */ -abstract contract GovernorSequentialProposalId is Governor { - uint256 private _latestProposalId; - mapping(uint256 proposalHash => uint256 proposalId) private _proposalIds; - - /** - * @dev The {latestProposalId} may only be initialized if it hasn't been set yet - * (through initialization or the creation of a proposal). - */ - error GovernorAlreadyInitializedLatestProposalId(); - - /// @inheritdoc IGovernor - function getProposalId( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) public view virtual override returns (uint256) { - uint256 proposalHash = hashProposal(targets, values, calldatas, descriptionHash); - uint256 storedProposalId = _proposalIds[proposalHash]; - if (storedProposalId == 0) { - revert GovernorNonexistentProposal(0); - } - return storedProposalId; - } - - /** - * @dev Returns the latest proposal id. A return value of 0 means no proposals have been created yet. - */ - function latestProposalId() public view virtual returns (uint256) { - return _latestProposalId; - } - - /** - * @dev See {IGovernor-_propose}. - * Hook into the proposing mechanism to increment proposal count. - */ - function _propose( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - string memory description, - address proposer - ) internal virtual override returns (uint256) { - uint256 proposalHash = hashProposal(targets, values, calldatas, keccak256(bytes(description))); - uint256 storedProposalId = _proposalIds[proposalHash]; - if (storedProposalId == 0) { - _proposalIds[proposalHash] = ++_latestProposalId; - } - return super._propose(targets, values, calldatas, description, proposer); - } - - /** - * @dev Internal function to set the {latestProposalId}. This function is helpful when transitioning - * from another governance system. The next proposal id will be `newLatestProposalId` + 1. - * - * May only call this function if the current value of {latestProposalId} is 0. - */ - function _initializeLatestProposalId(uint256 newLatestProposalId) internal virtual { - if (_latestProposalId != 0) { - revert GovernorAlreadyInitializedLatestProposalId(); - } - _latestProposalId = newLatestProposalId; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol deleted file mode 100644 index 5f3cef7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorSettings.sol) - -pragma solidity ^0.8.24; - -import {IGovernor, 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); - } - - /// @inheritdoc IGovernor - function votingDelay() public view virtual override returns (uint256) { - return _votingDelay; - } - - /// @inheritdoc IGovernor - function votingPeriod() public view virtual override returns (uint256) { - return _votingPeriod; - } - - /// @inheritdoc Governor - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorStorage.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorStorage.sol deleted file mode 100644 index 1c00678..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorStorage.sol +++ /dev/null @@ -1,125 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorStorage.sol) - -pragma solidity ^0.8.24; - -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 {IGovernor-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 targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash) - { - // 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 proposalId, - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) - { - proposalId = _proposalIds[index]; - (targets, values, calldatas, descriptionHash) = proposalDetails(proposalId); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSuperQuorum.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSuperQuorum.sol deleted file mode 100644 index 04602fd..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSuperQuorum.sol +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorSuperQuorum.sol) -pragma solidity ^0.8.24; - -import {Governor} from "../Governor.sol"; - -/** - * @dev Extension of {Governor} with a super quorum. Proposals that meet the super quorum (and have a majority of for - * votes) advance to the `Succeeded` state before the proposal deadline. Counting modules that want to use this - * extension must implement {proposalVotes}. - */ -abstract contract GovernorSuperQuorum is Governor { - /** - * @dev Minimum number of cast votes required for a proposal to reach super quorum. Only FOR votes are counted - * towards the super quorum. Once the super quorum is reached, an active proposal can proceed to the next state - * without waiting for the proposal deadline. - * - * NOTE: The `timepoint` parameter corresponds to the snapshot used for counting the vote. This enables scaling of the - * quorum depending on values such as the `totalSupply` of a token at this timepoint (see {ERC20Votes}). - * - * NOTE: Make sure the value specified for the super quorum is greater than {quorum}, otherwise, it may be - * possible to pass a proposal with less votes than the default quorum. - */ - function superQuorum(uint256 timepoint) public view virtual returns (uint256); - - /** - * @dev Accessor to the internal vote counts. This must be implemented by the counting module. Counting modules - * that don't implement this function are incompatible with this module - */ - function proposalVotes( - uint256 proposalId - ) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes); - - /** - * @dev Overridden version of the {Governor-state} function that checks if the proposal has reached the super - * quorum. - * - * NOTE: If the proposal reaches super quorum but {_voteSucceeded} returns false, eg, assuming the super quorum - * has been set low enough that both FOR and AGAINST votes have exceeded it and AGAINST votes exceed FOR votes, - * the proposal continues to be active until {_voteSucceeded} returns true or the proposal deadline is reached. - * This means that with a low super quorum it is also possible that a vote can succeed prematurely before enough - * AGAINST voters have a chance to vote. Hence, it is recommended to set a high enough super quorum to avoid these - * types of scenarios. - */ - function state(uint256 proposalId) public view virtual override returns (ProposalState) { - ProposalState currentState = super.state(proposalId); - if (currentState != ProposalState.Active) return currentState; - - (, uint256 forVotes, ) = proposalVotes(proposalId); - if (forVotes < superQuorum(proposalSnapshot(proposalId)) || !_voteSucceeded(proposalId)) { - return ProposalState.Active; - } else if (proposalEta(proposalId) == 0) { - return ProposalState.Succeeded; - } else { - return ProposalState.Queued; - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockAccess.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockAccess.sol deleted file mode 100644 index 14823d9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockAccess.sol +++ /dev/null @@ -1,346 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorTimelockAccess.sol) - -pragma solidity ^0.8.24; - -import {IGovernor, 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. - * - * 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 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); - } - - /// @inheritdoc IGovernor - function proposalNeedsQueuing(uint256 proposalId) public view virtual override returns (bool) { - return _executionPlan[proposalId].delay > 0; - } - - /// @inheritdoc IGovernor - 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) { - // This function can reenter when calling `_manager.schedule` before performing state updates in `_setManagerData`. - // However, the `manager` is a trusted contract in the current context's security model (e.g. an `AccessManager`). - // slither-disable-next-line reentrancy-no-eth - (, 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); - } - } - } - - /// @inheritdoc Governor - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol deleted file mode 100644 index dce13f1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol +++ /dev/null @@ -1,165 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorTimelockCompound.sol) - -pragma solidity ^0.8.24; - -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 proposals (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 from a proposal, unless executed via {Governor-relay}. - */ -abstract contract GovernorTimelockCompound is Governor { - ICompoundTimelock private _timelock; - - /** - * @dev Emitted when the timelock controller used for proposal execution is modified. - */ - 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); - } - - /// @inheritdoc IGovernor - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol deleted file mode 100644 index b3f3b26..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol +++ /dev/null @@ -1,167 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorTimelockControl.sol) - -pragma solidity ^0.8.24; - -import {IGovernor, Governor} from "../Governor.sol"; -import {TimelockController} from "../TimelockController.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 and canceller) 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 cancelers 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. - */ -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); - } - - /// @inheritdoc IGovernor - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol deleted file mode 100644 index 4ad5870..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorVotes.sol) - -pragma solidity ^0.8.24; - -import {Governor} from "../Governor.sol"; -import {IVotes} from "../utils/IVotes.sol"; -import {IERC5805} from "../../interfaces/IERC5805.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 ERC-6372) is set to match the token's clock. Fallback to block numbers if the token - * does not implement ERC-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 ERC-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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol deleted file mode 100644 index 2f6034d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorVotesQuorumFraction.sol) - -pragma solidity ^0.8.24; - -import {GovernorVotes} from "./GovernorVotes.sol"; -import {Math} from "../../utils/math/Math.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) { - return _optimisticUpperLookupRecent(_quorumNumeratorHistory, 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 Math.mulDiv(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); - } - - /** - * @dev Returns the numerator at a specific timepoint. - */ - function _optimisticUpperLookupRecent( - Checkpoints.Trace208 storage ckpts, - uint256 timepoint - ) internal view returns (uint256) { - // If trace is empty, key and value are both equal to 0. - // In that case `key <= timepoint` is true, and it is ok to return 0. - (, uint48 key, uint208 value) = ckpts.latestCheckpoint(); - return key <= timepoint ? value : ckpts.upperLookupRecent(SafeCast.toUint48(timepoint)); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol deleted file mode 100644 index 1c47840..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol +++ /dev/null @@ -1,134 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/extensions/GovernorVotesSuperQuorumFraction.sol) -pragma solidity ^0.8.24; - -import {Governor} from "../Governor.sol"; -import {GovernorSuperQuorum} from "./GovernorSuperQuorum.sol"; -import {GovernorVotesQuorumFraction} from "./GovernorVotesQuorumFraction.sol"; -import {Math} from "../../utils/math/Math.sol"; -import {SafeCast} from "../../utils/math/SafeCast.sol"; -import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; - -/** - * @dev Extension of {GovernorVotesQuorumFraction} with a super quorum expressed as a - * fraction of the total supply. Proposals that meet the super quorum (and have a majority of for votes) advance to - * the `Succeeded` state before the proposal deadline. - */ -abstract contract GovernorVotesSuperQuorumFraction is GovernorVotesQuorumFraction, GovernorSuperQuorum { - using Checkpoints for Checkpoints.Trace208; - - Checkpoints.Trace208 private _superQuorumNumeratorHistory; - - event SuperQuorumNumeratorUpdated(uint256 oldSuperQuorumNumerator, uint256 newSuperQuorumNumerator); - - /** - * @dev The super quorum set is not valid as it exceeds the quorum denominator. - */ - error GovernorInvalidSuperQuorumFraction(uint256 superQuorumNumerator, uint256 denominator); - - /** - * @dev The super quorum set is not valid as it is smaller or equal to the quorum. - */ - error GovernorInvalidSuperQuorumTooSmall(uint256 superQuorumNumerator, uint256 quorumNumerator); - - /** - * @dev The quorum set is not valid as it exceeds the super quorum. - */ - error GovernorInvalidQuorumTooLarge(uint256 quorumNumerator, uint256 superQuorumNumerator); - - /** - * @dev Initialize super quorum as a fraction of the token's total supply. - * - * The super quorum is specified as a fraction of the token's total supply and has to - * be greater than the quorum. - */ - constructor(uint256 superQuorumNumeratorValue) { - _updateSuperQuorumNumerator(superQuorumNumeratorValue); - } - - /** - * @dev Returns the current super quorum numerator. - */ - function superQuorumNumerator() public view virtual returns (uint256) { - return _superQuorumNumeratorHistory.latest(); - } - - /** - * @dev Returns the super quorum numerator at a specific `timepoint`. - */ - function superQuorumNumerator(uint256 timepoint) public view virtual returns (uint256) { - return _optimisticUpperLookupRecent(_superQuorumNumeratorHistory, timepoint); - } - - /** - * @dev Returns the super quorum for a `timepoint`, in terms of number of votes: `supply * numerator / denominator`. - * See {GovernorSuperQuorum-superQuorum} for more details. - */ - function superQuorum(uint256 timepoint) public view virtual override returns (uint256) { - return Math.mulDiv(token().getPastTotalSupply(timepoint), superQuorumNumerator(timepoint), quorumDenominator()); - } - - /** - * @dev Changes the super quorum numerator. - * - * Emits a {SuperQuorumNumeratorUpdated} event. - * - * Requirements: - * - * - Must be called through a governance proposal. - * - New super quorum numerator must be smaller or equal to the denominator. - * - New super quorum numerator must be greater than or equal to the quorum numerator. - */ - function updateSuperQuorumNumerator(uint256 newSuperQuorumNumerator) public virtual onlyGovernance { - _updateSuperQuorumNumerator(newSuperQuorumNumerator); - } - - /** - * @dev Changes the super quorum numerator. - * - * Emits a {SuperQuorumNumeratorUpdated} event. - * - * Requirements: - * - * - New super quorum numerator must be smaller or equal to the denominator. - * - New super quorum numerator must be greater than or equal to the quorum numerator. - */ - function _updateSuperQuorumNumerator(uint256 newSuperQuorumNumerator) internal virtual { - uint256 denominator = quorumDenominator(); - if (newSuperQuorumNumerator > denominator) { - revert GovernorInvalidSuperQuorumFraction(newSuperQuorumNumerator, denominator); - } - - uint256 quorumNumerator = quorumNumerator(); - if (newSuperQuorumNumerator < quorumNumerator) { - revert GovernorInvalidSuperQuorumTooSmall(newSuperQuorumNumerator, quorumNumerator); - } - - uint256 oldSuperQuorumNumerator = _superQuorumNumeratorHistory.latest(); - _superQuorumNumeratorHistory.push(clock(), SafeCast.toUint208(newSuperQuorumNumerator)); - - emit SuperQuorumNumeratorUpdated(oldSuperQuorumNumerator, newSuperQuorumNumerator); - } - - /** - * @dev Overrides {GovernorVotesQuorumFraction-_updateQuorumNumerator} to ensure the super - * quorum numerator is greater than or equal to the quorum numerator. - */ - function _updateQuorumNumerator(uint256 newQuorumNumerator) internal virtual override { - // Ignoring check when the superQuorum was never set (construction sets quorum before superQuorum) - if (_superQuorumNumeratorHistory.length() > 0) { - uint256 superQuorumNumerator_ = superQuorumNumerator(); - if (newQuorumNumerator > superQuorumNumerator_) { - revert GovernorInvalidQuorumTooLarge(newQuorumNumerator, superQuorumNumerator_); - } - } - super._updateQuorumNumerator(newQuorumNumerator); - } - - /// @inheritdoc GovernorSuperQuorum - function state( - uint256 proposalId - ) public view virtual override(Governor, GovernorSuperQuorum) returns (ProposalState) { - return super.state(proposalId); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol deleted file mode 100644 index a007f3a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (governance/utils/IVotes.sol) -pragma solidity >=0.8.4; - -/** - * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol deleted file mode 100644 index f5994f2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol +++ /dev/null @@ -1,252 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.2.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 ERC-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 Validate that a timepoint is in the past, and return it as a uint48. - */ - function _validateTimepoint(uint256 timepoint) internal view returns (uint48) { - uint48 currentTimepoint = clock(); - if (timepoint >= currentTimepoint) revert ERC5805FutureLookup(timepoint, currentTimepoint); - return SafeCast.toUint48(timepoint); - } - - /** - * @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) { - return _delegateCheckpoints[account].upperLookupRecent(_validateTimepoint(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) { - return _totalCheckpoints.upperLookupRecent(_validateTimepoint(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) internal virtual { - 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 oldValue, uint208 newValue) { - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/VotesExtended.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/VotesExtended.sol deleted file mode 100644 index 5b67320..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/governance/utils/VotesExtended.sol +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.2.0) (governance/utils/VotesExtended.sol) -pragma solidity ^0.8.20; - -import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; -import {Votes} from "./Votes.sol"; -import {SafeCast} from "../../utils/math/SafeCast.sol"; - -/** - * @dev Extension of {Votes} that adds checkpoints for delegations and balances. - * - * WARNING: While this contract extends {Votes}, valid uses of {Votes} may not be compatible with - * {VotesExtended} without additional considerations. This implementation of {_transferVotingUnits} must - * run AFTER the voting weight movement is registered, such that it is reflected on {_getVotingUnits}. - * - * Said differently, {VotesExtended} MUST be integrated in a way that calls {_transferVotingUnits} AFTER the - * asset transfer is registered and balances are updated: - * - * ```solidity - * contract VotingToken is Token, VotesExtended { - * function transfer(address from, address to, uint256 tokenId) public override { - * super.transfer(from, to, tokenId); // <- Perform the transfer first ... - * _transferVotingUnits(from, to, 1); // <- ... then call _transferVotingUnits. - * } - * - * function _getVotingUnits(address account) internal view override returns (uint256) { - * return balanceOf(account); - * } - * } - * ``` - * - * {ERC20Votes} and {ERC721Votes} follow this pattern and are thus safe to use with {VotesExtended}. - */ -abstract contract VotesExtended is Votes { - using Checkpoints for Checkpoints.Trace160; - using Checkpoints for Checkpoints.Trace208; - - mapping(address delegator => Checkpoints.Trace160) private _userDelegationCheckpoints; - mapping(address account => Checkpoints.Trace208) private _userVotingUnitsCheckpoints; - - /** - * @dev Returns the delegate of an `account` 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 getPastDelegate(address account, uint256 timepoint) public view virtual returns (address) { - return address(_userDelegationCheckpoints[account].upperLookupRecent(_validateTimepoint(timepoint))); - } - - /** - * @dev Returns the `balanceOf` of an `account` 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 getPastBalanceOf(address account, uint256 timepoint) public view virtual returns (uint256) { - return _userVotingUnitsCheckpoints[account].upperLookupRecent(_validateTimepoint(timepoint)); - } - - /// @inheritdoc Votes - function _delegate(address account, address delegatee) internal virtual override { - super._delegate(account, delegatee); - - _userDelegationCheckpoints[account].push(clock(), uint160(delegatee)); - } - - /// @inheritdoc Votes - function _transferVotingUnits(address from, address to, uint256 amount) internal virtual override { - super._transferVotingUnits(from, to, amount); - if (from != to) { - if (from != address(0)) { - _userVotingUnitsCheckpoints[from].push(clock(), SafeCast.toUint208(_getVotingUnits(from))); - } - if (to != address(0)) { - _userVotingUnitsCheckpoints[to].push(clock(), SafeCast.toUint208(_getVotingUnits(to))); - } - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol deleted file mode 100644 index 6c10b87..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1155.sol) - -pragma solidity >=0.6.2; - -import {IERC1155} from "../token/ERC1155/IERC1155.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol deleted file mode 100644 index 95f815f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1155MetadataURI.sol) - -pragma solidity >=0.6.2; - -import {IERC1155MetadataURI} from "../token/ERC1155/extensions/IERC1155MetadataURI.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol deleted file mode 100644 index b56bdfe..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1155Receiver.sol) - -pragma solidity >=0.6.2; - -import {IERC1155Receiver} from "../token/ERC1155/IERC1155Receiver.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol deleted file mode 100644 index 4382286..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1271.sol) - -pragma solidity >=0.5.0; - -/** - * @dev Interface of the ERC-1271 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 `hash` - */ - function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4 magicValue); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol deleted file mode 100644 index 7bf3e1f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol) - -pragma solidity >=0.6.2; - -import {IERC20} from "./IERC20.sol"; -import {IERC165} from "./IERC165.sol"; - -/** - * @title IERC1363 - * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. - * - * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract - * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction. - */ -interface IERC1363 is IERC20, IERC165 { - /* - * 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 Moves a `value` amount of tokens from the caller's account to `to` - * and then calls {IERC1363Receiver-onTransferReceived} on `to`. - * @param to The address which you want to transfer to. - * @param value The amount of tokens to be transferred. - * @return A boolean value indicating whether the operation succeeded unless throwing. - */ - function transferAndCall(address to, uint256 value) external returns (bool); - - /** - * @dev Moves a `value` amount of tokens from the caller's account to `to` - * and then calls {IERC1363Receiver-onTransferReceived} on `to`. - * @param to The address which you want to transfer to. - * @param value The amount of tokens to be transferred. - * @param data Additional data with no specified format, sent in call to `to`. - * @return A boolean value indicating whether the operation succeeded unless throwing. - */ - function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); - - /** - * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism - * and then calls {IERC1363Receiver-onTransferReceived} on `to`. - * @param from The address which you want to send tokens from. - * @param to The address which you want to transfer to. - * @param value The amount of tokens to be transferred. - * @return A boolean value indicating whether the operation succeeded unless throwing. - */ - function transferFromAndCall(address from, address to, uint256 value) external returns (bool); - - /** - * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism - * and then calls {IERC1363Receiver-onTransferReceived} on `to`. - * @param from The address which you want to send tokens from. - * @param to The address which you want to transfer to. - * @param value The amount of tokens to be transferred. - * @param data Additional data with no specified format, sent in call to `to`. - * @return A boolean value indicating whether the operation succeeded unless throwing. - */ - function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool); - - /** - * @dev Sets a `value` amount of tokens as the allowance of `spender` over the - * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. - * @param spender The address which will spend the funds. - * @param value The amount of tokens to be spent. - * @return A boolean value indicating whether the operation succeeded unless throwing. - */ - function approveAndCall(address spender, uint256 value) external returns (bool); - - /** - * @dev Sets a `value` amount of tokens as the allowance of `spender` over the - * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. - * @param spender The address which will spend the funds. - * @param value The amount of tokens to be spent. - * @param data Additional data with no specified format, sent in call to `spender`. - * @return A boolean value indicating whether the operation succeeded unless throwing. - */ - function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol deleted file mode 100644 index 43efc9b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363Receiver.sol) - -pragma solidity >=0.5.0; - -/** - * @title IERC1363Receiver - * @dev Interface for any contract that wants to support `transferAndCall` or `transferFromAndCall` - * from ERC-1363 token contracts. - */ -interface IERC1363Receiver { - /** - * @dev Whenever ERC-1363 tokens are transferred to this contract via `transferAndCall` or `transferFromAndCall` - * by `operator` from `from`, this function is called. - * - * NOTE: To accept the transfer, this must return - * `bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))` - * (i.e. 0x88a7ca5c, or its own function selector). - * - * @param operator The address which called `transferAndCall` or `transferFromAndCall` function. - * @param from The address which the tokens are transferred from. - * @param value The amount of tokens transferred. - * @param data Additional data with no specified format. - * @return `bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))` if transfer is allowed unless throwing. - */ - function onTransferReceived( - address operator, - address from, - uint256 value, - bytes calldata data - ) external returns (bytes4); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol deleted file mode 100644 index 46efa88..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363Spender.sol) - -pragma solidity >=0.5.0; - -/** - * @title IERC1363Spender - * @dev Interface for any contract that wants to support `approveAndCall` - * from ERC-1363 token contracts. - */ -interface IERC1363Spender { - /** - * @dev Whenever an ERC-1363 token `owner` approves this contract via `approveAndCall` - * to spend their tokens, this function is called. - * - * NOTE: To accept the approval, this must return - * `bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))` - * (i.e. 0x7b04a2d0, or its own function selector). - * - * @param owner The address which called `approveAndCall` function and previously owned the tokens. - * @param value The amount of tokens to be spent. - * @param data Additional data with no specified format. - * @return `bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))` if approval is allowed unless throwing. - */ - function onApprovalReceived(address owner, uint256 value, bytes calldata data) external returns (bytes4); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol deleted file mode 100644 index d2c99a5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol) - -pragma solidity >=0.4.16; - -import {IERC165} from "../utils/introspection/IERC165.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol deleted file mode 100644 index 8c04719..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1820Implementer.sol) - -pragma solidity >=0.4.16; - -/** - * @dev Interface for an ERC-1820 implementer, as defined in the - * https://eips.ethereum.org/EIPS/eip-1820#interface-implementation-erc1820implementerinterface[ERC]. - * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol deleted file mode 100644 index 03efa03..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol +++ /dev/null @@ -1,112 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1820Registry.sol) - -pragma solidity >=0.5.0; - -/** - * @dev Interface of the global ERC-1820 Registry, as defined in the - * https://eips.ethereum.org/EIPS/eip-1820[ERC]. 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 ERC 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 ERC]. - */ - function interfaceHash(string calldata interfaceName) external pure returns (bytes32); - - /** - * @notice Updates the cache with whether the contract implements an ERC-165 interface or not. - * @param account Address of the contract for which to update the cache. - * @param interfaceId ERC-165 interface for which to update the cache. - */ - function updateERC165Cache(address account, bytes4 interfaceId) external; - - /** - * @notice Checks whether a contract implements an ERC-165 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 ERC-165 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 ERC-165 interface or not without using or updating the cache. - * @param account Address of the contract to check. - * @param interfaceId ERC-165 interface to check. - * @return True if `account` implements `interfaceId`, false otherwise. - */ - function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol deleted file mode 100644 index 95d222e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1967.sol) - -pragma solidity >=0.4.11; - -/** - * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol deleted file mode 100644 index 078e9ec..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol) - -pragma solidity >=0.4.16; - -import {IERC20} from "../token/ERC20/IERC20.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol deleted file mode 100644 index adffeb5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20Metadata.sol) - -pragma solidity >=0.6.2; - -import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol deleted file mode 100644 index bc0fb64..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC2309.sol) - -pragma solidity >=0.4.11; - -/** - * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol deleted file mode 100644 index 330c064..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC2612.sol) - -pragma solidity >=0.6.2; - -import {IERC20Permit} from "../token/ERC20/extensions/IERC20Permit.sol"; - -interface IERC2612 is IERC20Permit {} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol deleted file mode 100644 index 858713b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC2981.sol) - -pragma solidity >=0.6.2; - -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. - * - * NOTE: ERC-2981 allows setting the royalty to 100% of the price. In that case all the price would be sent to the - * royalty receiver and 0 tokens to the seller. Contracts dealing with royalty should consider empty transfers. - */ - function royaltyInfo( - uint256 tokenId, - uint256 salePrice - ) external view returns (address receiver, uint256 royaltyAmount); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol deleted file mode 100644 index 95b4b2d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC3156.sol) - -pragma solidity >=0.5.0; - -import {IERC3156FlashBorrower} from "./IERC3156FlashBorrower.sol"; -import {IERC3156FlashLender} from "./IERC3156FlashLender.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol deleted file mode 100644 index 5028df8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC3156FlashBorrower.sol) - -pragma solidity >=0.5.0; - -/** - * @dev Interface of the ERC-3156 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol deleted file mode 100644 index 77ca98a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC3156FlashLender.sol) - -pragma solidity >=0.5.0; - -import {IERC3156FlashBorrower} from "./IERC3156FlashBorrower.sol"; - -/** - * @dev Interface of the ERC-3156 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol deleted file mode 100644 index 5f785c3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol +++ /dev/null @@ -1,230 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC4626.sol) - -pragma solidity >=0.6.2; - -import {IERC20} from "../token/ERC20/IERC20.sol"; -import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; - -/** - * @dev Interface of the ERC-4626 "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 redemption 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol deleted file mode 100644 index 09f13b2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC4906.sol) - -pragma solidity >=0.6.2; - -import {IERC165} from "./IERC165.sol"; -import {IERC721} from "./IERC721.sol"; - -/// @title ERC-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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol deleted file mode 100644 index 96cd325..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC5267.sol) - -pragma solidity >=0.4.16; - -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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol deleted file mode 100644 index 9c94692..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC5313.sol) - -pragma solidity >=0.4.16; - -/** - * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol deleted file mode 100644 index 5d73abb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC5805.sol) - -pragma solidity >=0.8.4; - -import {IVotes} from "../governance/utils/IVotes.sol"; -import {IERC6372} from "./IERC6372.sol"; - -interface IERC5805 is IERC6372, IVotes {} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol deleted file mode 100644 index 447a8ea..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC6372.sol) - -pragma solidity >=0.4.16; - -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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol deleted file mode 100644 index 6ec5136..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC721.sol) - -pragma solidity >=0.6.2; - -import {IERC721} from "../token/ERC721/IERC721.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol deleted file mode 100644 index e713bc2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC721Enumerable.sol) - -pragma solidity >=0.6.2; - -import {IERC721Enumerable} from "../token/ERC721/extensions/IERC721Enumerable.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol deleted file mode 100644 index 932afaa..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC721Metadata.sol) - -pragma solidity >=0.6.2; - -import {IERC721Metadata} from "../token/ERC721/extensions/IERC721Metadata.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol deleted file mode 100644 index 7b5fd47..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC721Receiver.sol) - -pragma solidity >=0.5.0; - -import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol deleted file mode 100644 index d65b9c7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol +++ /dev/null @@ -1,200 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC777.sol) - -pragma solidity >=0.5.0; - -/** - * @dev Interface of the ERC-777 Token standard as defined in the ERC. - * - * This contract uses the - * https://eips.ethereum.org/EIPS/eip-1820[ERC-1820 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol deleted file mode 100644 index 4277333..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC777Recipient.sol) - -pragma solidity >=0.5.0; - -/** - * @dev Interface of the ERC-777 Tokens Recipient standard as defined in the ERC. - * - * 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[ERC-1820 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol deleted file mode 100644 index 46d1b4a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC777Sender.sol) - -pragma solidity >=0.5.0; - -/** - * @dev Interface of the ERC-777 Tokens Sender standard as defined in the ERC. - * - * {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[ERC-1820 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC7913.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC7913.sol deleted file mode 100644 index 4f887fb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/IERC7913.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC7913.sol) - -pragma solidity >=0.5.0; - -/** - * @dev Signature verifier interface. - */ -interface IERC7913SignatureVerifier { - /** - * @dev Verifies `signature` as a valid signature of `hash` by `key`. - * - * MUST return the bytes4 magic value IERC7913SignatureVerifier.verify.selector if the signature is valid. - * SHOULD return 0xffffffff or revert if the signature is not valid. - * SHOULD return 0xffffffff or revert if the key is empty - */ - function verify(bytes calldata key, bytes32 hash, bytes calldata signature) external view returns (bytes4); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/README.adoc deleted file mode 100644 index 9cb4d9a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/README.adoc +++ /dev/null @@ -1,102 +0,0 @@ -= 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} -- {IERC6909} -- {IERC6909ContentURI} -- {IERC6909Metadata} -- {IERC6909TokenSupply} -- {IERC7674} -- {IERC7802} - -== Detailed ABI - -{{IERC20Errors}} - -{{IERC721Errors}} - -{{IERC1155Errors}} - -{{IERC1271}} - -{{IERC1363}} - -{{IERC1363Receiver}} - -{{IERC1363Spender}} - -{{IERC1820Implementer}} - -{{IERC1820Registry}} - -{{IERC1822Proxiable}} - -{{IERC2612}} - -{{IERC2981}} - -{{IERC3156FlashLender}} - -{{IERC3156FlashBorrower}} - -{{IERC4626}} - -{{IERC4906}} - -{{IERC5267}} - -{{IERC5313}} - -{{IERC5805}} - -{{IERC6372}} - -{{IERC6909}} - -{{IERC6909ContentURI}} - -{{IERC6909Metadata}} - -{{IERC6909TokenSupply}} - -{{IERC7674}} - -{{IERC7802}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol deleted file mode 100644 index 2edb85d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC1822.sol) - -pragma solidity >=0.4.16; - -/** - * @dev ERC-1822: 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC4337.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC4337.sol deleted file mode 100644 index 752e4e4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC4337.sol +++ /dev/null @@ -1,253 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC4337.sol) - -pragma solidity >=0.8.4; - -/** - * @dev A https://github.com/ethereum/ercs/blob/master/ERCS/erc-4337.md#useroperation[user operation] is composed of the following elements: - * - `sender` (`address`): The account making the operation - * - `nonce` (`uint256`): Anti-replay parameter (see “Semi-abstracted Nonce Support” ) - * - `factory` (`address`): account factory, only for new accounts - * - `factoryData` (`bytes`): data for account factory (only if account factory exists) - * - `callData` (`bytes`): The data to pass to the sender during the main execution call - * - `callGasLimit` (`uint256`): The amount of gas to allocate the main execution call - * - `verificationGasLimit` (`uint256`): The amount of gas to allocate for the verification step - * - `preVerificationGas` (`uint256`): Extra gas to pay the bundler - * - `maxFeePerGas` (`uint256`): Maximum fee per gas (similar to EIP-1559 max_fee_per_gas) - * - `maxPriorityFeePerGas` (`uint256`): Maximum priority fee per gas (similar to EIP-1559 max_priority_fee_per_gas) - * - `paymaster` (`address`): Address of paymaster contract, (or empty, if account pays for itself) - * - `paymasterVerificationGasLimit` (`uint256`): The amount of gas to allocate for the paymaster validation code - * - `paymasterPostOpGasLimit` (`uint256`): The amount of gas to allocate for the paymaster post-operation code - * - `paymasterData` (`bytes`): Data for paymaster (only if paymaster exists) - * - `signature` (`bytes`): Data passed into the account to verify authorization - * - * When passed to on-chain contracts, the following packed version is used. - * - `sender` (`address`) - * - `nonce` (`uint256`) - * - `initCode` (`bytes`): concatenation of factory address and factoryData (or empty) - * - `callData` (`bytes`) - * - `accountGasLimits` (`bytes32`): concatenation of verificationGas (16 bytes) and callGas (16 bytes) - * - `preVerificationGas` (`uint256`) - * - `gasFees` (`bytes32`): concatenation of maxPriorityFeePerGas (16 bytes) and maxFeePerGas (16 bytes) - * - `paymasterAndData` (`bytes`): concatenation of paymaster fields (or empty) - * - `signature` (`bytes`) - */ -struct PackedUserOperation { - address sender; - uint256 nonce; - bytes initCode; // `abi.encodePacked(factory, factoryData)` - bytes callData; - bytes32 accountGasLimits; // `abi.encodePacked(verificationGasLimit, callGasLimit)` 16 bytes each - uint256 preVerificationGas; - bytes32 gasFees; // `abi.encodePacked(maxPriorityFeePerGas, maxFeePerGas)` 16 bytes each - bytes paymasterAndData; // `abi.encodePacked(paymaster, paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymasterData)` (20 bytes, 16 bytes, 16 bytes, dynamic) - bytes signature; -} - -/** - * @dev Aggregates and validates multiple signatures for a batch of user operations. - * - * A contract could implement this interface with custom validation schemes that allow signature aggregation, - * enabling significant optimizations and gas savings for execution and transaction data cost. - * - * Bundlers and clients whitelist supported aggregators. - * - * See https://eips.ethereum.org/EIPS/eip-7766[ERC-7766] - */ -interface IAggregator { - /** - * @dev Validates the signature for a user operation. - * Returns an alternative signature that should be used during bundling. - */ - function validateUserOpSignature( - PackedUserOperation calldata userOp - ) external view returns (bytes memory sigForUserOp); - - /** - * @dev Returns an aggregated signature for a batch of user operation's signatures. - */ - function aggregateSignatures( - PackedUserOperation[] calldata userOps - ) external view returns (bytes memory aggregatesSignature); - - /** - * @dev Validates that the aggregated signature is valid for the user operations. - * - * Requirements: - * - * - The aggregated signature MUST match the given list of operations. - */ - function validateSignatures(PackedUserOperation[] calldata userOps, bytes calldata signature) external view; -} - -/** - * @dev Handle nonce management for accounts. - * - * Nonces are used in accounts as a replay protection mechanism and to ensure the order of user operations. - * To avoid limiting the number of operations an account can perform, the interface allows using parallel - * nonces by using a `key` parameter. - * - * See https://eips.ethereum.org/EIPS/eip-4337#semi-abstracted-nonce-support[ERC-4337 semi-abstracted nonce support]. - */ -interface IEntryPointNonces { - /** - * @dev Returns the nonce for a `sender` account and a `key`. - * - * Nonces for a certain `key` are always increasing. - */ - function getNonce(address sender, uint192 key) external view returns (uint256 nonce); -} - -/** - * @dev Handle stake management for entities (i.e. accounts, paymasters, factories). - * - * The EntryPoint must implement the following API to let entities like paymasters have a stake, - * and thus have more flexibility in their storage access - * (see https://eips.ethereum.org/EIPS/eip-4337#reputation-scoring-and-throttlingbanning-for-global-entities[reputation, throttling and banning.]) - */ -interface IEntryPointStake { - /** - * @dev Returns the balance of the account. - */ - function balanceOf(address account) external view returns (uint256); - - /** - * @dev Deposits `msg.value` to the account. - */ - function depositTo(address account) external payable; - - /** - * @dev Withdraws `withdrawAmount` from the account to `withdrawAddress`. - */ - function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external; - - /** - * @dev Adds stake to the account with an unstake delay of `unstakeDelaySec`. - */ - function addStake(uint32 unstakeDelaySec) external payable; - - /** - * @dev Unlocks the stake of the account. - */ - function unlockStake() external; - - /** - * @dev Withdraws the stake of the account to `withdrawAddress`. - */ - function withdrawStake(address payable withdrawAddress) external; -} - -/** - * @dev Entry point for user operations. - * - * User operations are validated and executed by this contract. - */ -interface IEntryPoint is IEntryPointNonces, IEntryPointStake { - /** - * @dev A user operation at `opIndex` failed with `reason`. - */ - error FailedOp(uint256 opIndex, string reason); - - /** - * @dev A user operation at `opIndex` failed with `reason` and `inner` returned data. - */ - error FailedOpWithRevert(uint256 opIndex, string reason, bytes inner); - - /** - * @dev Batch of aggregated user operations per aggregator. - */ - struct UserOpsPerAggregator { - PackedUserOperation[] userOps; - IAggregator aggregator; - bytes signature; - } - - /** - * @dev Executes a batch of user operations. - * @param beneficiary Address to which gas is refunded upon completing the execution. - */ - function handleOps(PackedUserOperation[] calldata ops, address payable beneficiary) external; - - /** - * @dev Executes a batch of aggregated user operations per aggregator. - * @param beneficiary Address to which gas is refunded upon completing the execution. - */ - function handleAggregatedOps( - UserOpsPerAggregator[] calldata opsPerAggregator, - address payable beneficiary - ) external; -} - -/** - * @dev Base interface for an ERC-4337 account. - */ -interface IAccount { - /** - * @dev Validates a user operation. - * - * * MUST validate the caller is a trusted EntryPoint - * * MUST validate that the signature is a valid signature of the userOpHash, and SHOULD - * return SIG_VALIDATION_FAILED (and not revert) on signature mismatch. Any other error MUST revert. - * * MUST pay the entryPoint (caller) at least the “missingAccountFunds” (which might - * be zero, in case the current account’s deposit is high enough) - * - * Returns an encoded packed validation data that is composed of the following elements: - * - * - `authorizer` (`address`): 0 for success, 1 for failure, otherwise the address of an authorizer contract - * - `validUntil` (`uint48`): The UserOp is valid only up to this time. Zero for “infinite”. - * - `validAfter` (`uint48`): The UserOp is valid only after this time. - */ - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash, - uint256 missingAccountFunds - ) external returns (uint256 validationData); -} - -/** - * @dev Support for executing user operations by prepending the {executeUserOp} function selector - * to the UserOperation's `callData`. - */ -interface IAccountExecute { - /** - * @dev Executes a user operation. - */ - function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external; -} - -/** - * @dev Interface for a paymaster contract that agrees to pay for the gas costs of a user operation. - * - * NOTE: A paymaster must hold a stake to cover the required entrypoint stake and also the gas for the transaction. - */ -interface IPaymaster { - enum PostOpMode { - opSucceeded, - opReverted, - postOpReverted - } - - /** - * @dev Validates whether the paymaster is willing to pay for the user operation. See - * {IAccount-validateUserOp} for additional information on the return value. - * - * NOTE: Bundlers will reject this method if it modifies the state, unless it's whitelisted. - */ - function validatePaymasterUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash, - uint256 maxCost - ) external returns (bytes memory context, uint256 validationData); - - /** - * @dev Verifies the sender is the entrypoint. - * @param actualGasCost the actual amount paid (by account or paymaster) for this UserOperation - * @param actualUserOpFeePerGas total gas used by this UserOperation (including preVerification, creation, validation and execution) - */ - function postOp( - PostOpMode mode, - bytes calldata context, - uint256 actualGasCost, - uint256 actualUserOpFeePerGas - ) external; -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol deleted file mode 100644 index aef2b0a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol +++ /dev/null @@ -1,161 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC6093.sol) -pragma solidity >=0.8.4; - -/** - * @dev Standard ERC-20 Errors - * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 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 ERC-721 Errors - * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens. - */ -interface IERC721Errors { - /** - * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-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 ERC-1155 Errors - * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6909.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6909.sol deleted file mode 100644 index df15761..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6909.sol +++ /dev/null @@ -1,125 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC6909.sol) - -pragma solidity >=0.6.2; - -import {IERC165} from "../utils/introspection/IERC165.sol"; - -/** - * @dev Required interface of an ERC-6909 compliant contract, as defined in the - * https://eips.ethereum.org/EIPS/eip-6909[ERC]. - */ -interface IERC6909 is IERC165 { - /** - * @dev Emitted when the allowance of a `spender` for an `owner` is set for a token of type `id`. - * The new allowance is `amount`. - */ - event Approval(address indexed owner, address indexed spender, uint256 indexed id, uint256 amount); - - /** - * @dev Emitted when `owner` grants or revokes operator status for a `spender`. - */ - event OperatorSet(address indexed owner, address indexed spender, bool approved); - - /** - * @dev Emitted when `amount` tokens of type `id` are moved from `sender` to `receiver` initiated by `caller`. - */ - event Transfer( - address caller, - address indexed sender, - address indexed receiver, - uint256 indexed id, - uint256 amount - ); - - /** - * @dev Returns the amount of tokens of type `id` owned by `owner`. - */ - function balanceOf(address owner, uint256 id) external view returns (uint256); - - /** - * @dev Returns the amount of tokens of type `id` that `spender` is allowed to spend on behalf of `owner`. - * - * NOTE: Does not include operator allowances. - */ - function allowance(address owner, address spender, uint256 id) external view returns (uint256); - - /** - * @dev Returns true if `spender` is set as an operator for `owner`. - */ - function isOperator(address owner, address spender) external view returns (bool); - - /** - * @dev Sets an approval to `spender` for `amount` of tokens of type `id` from the caller's tokens. An `amount` of - * `type(uint256).max` signifies an unlimited approval. - * - * Must return true. - */ - function approve(address spender, uint256 id, uint256 amount) external returns (bool); - - /** - * @dev Grants or revokes unlimited transfer permission of any token id to `spender` for the caller's tokens. - * - * Must return true. - */ - function setOperator(address spender, bool approved) external returns (bool); - - /** - * @dev Transfers `amount` of token type `id` from the caller's account to `receiver`. - * - * Must return true. - */ - function transfer(address receiver, uint256 id, uint256 amount) external returns (bool); - - /** - * @dev Transfers `amount` of token type `id` from `sender` to `receiver`. - * - * Must return true. - */ - function transferFrom(address sender, address receiver, uint256 id, uint256 amount) external returns (bool); -} - -/** - * @dev Optional extension of {IERC6909} that adds metadata functions. - */ -interface IERC6909Metadata is IERC6909 { - /** - * @dev Returns the name of the token of type `id`. - */ - function name(uint256 id) external view returns (string memory); - - /** - * @dev Returns the ticker symbol of the token of type `id`. - */ - function symbol(uint256 id) external view returns (string memory); - - /** - * @dev Returns the number of decimals for the token of type `id`. - */ - function decimals(uint256 id) external view returns (uint8); -} - -/** - * @dev Optional extension of {IERC6909} that adds content URI functions. - */ -interface IERC6909ContentURI is IERC6909 { - /** - * @dev Returns URI for the contract. - */ - function contractURI() external view returns (string memory); - - /** - * @dev Returns the URI for the token of type `id`. - */ - function tokenURI(uint256 id) external view returns (string memory); -} - -/** - * @dev Optional extension of {IERC6909} that adds a token supply function. - */ -interface IERC6909TokenSupply is IERC6909 { - /** - * @dev Returns the total supply of the token of type `id`. - */ - function totalSupply(uint256 id) external view returns (uint256); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7579.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7579.sol deleted file mode 100644 index 99a79c1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7579.sol +++ /dev/null @@ -1,226 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC7579.sol) -pragma solidity >=0.8.4; - -import {PackedUserOperation} from "./draft-IERC4337.sol"; - -uint256 constant VALIDATION_SUCCESS = 0; -uint256 constant VALIDATION_FAILED = 1; -uint256 constant MODULE_TYPE_VALIDATOR = 1; -uint256 constant MODULE_TYPE_EXECUTOR = 2; -uint256 constant MODULE_TYPE_FALLBACK = 3; -uint256 constant MODULE_TYPE_HOOK = 4; - -/// @dev Minimal configuration interface for ERC-7579 modules -interface IERC7579Module { - /** - * @dev This function is called by the smart account during installation of the module - * @param data arbitrary data that may be passed to the module during `onInstall` initialization - * - * MUST revert on error (e.g. if module is already enabled) - */ - function onInstall(bytes calldata data) external; - - /** - * @dev This function is called by the smart account during uninstallation of the module - * @param data arbitrary data that may be passed to the module during `onUninstall` de-initialization - * - * MUST revert on error - */ - function onUninstall(bytes calldata data) external; - - /** - * @dev Returns boolean value if module is a certain type - * @param moduleTypeId the module type ID according the ERC-7579 spec - * - * MUST return true if the module is of the given type and false otherwise - */ - function isModuleType(uint256 moduleTypeId) external view returns (bool); -} - -/** - * @dev ERC-7579 Validation module (type 1). - * - * A module that implements logic to validate user operations and signatures. - */ -interface IERC7579Validator is IERC7579Module { - /** - * @dev Validates a UserOperation - * @param userOp the ERC-4337 PackedUserOperation - * @param userOpHash the hash of the ERC-4337 PackedUserOperation - * - * MUST validate that the signature is a valid signature of the userOpHash - * SHOULD return ERC-4337's SIG_VALIDATION_FAILED (and not revert) on signature mismatch - * See {IAccount-validateUserOp} for additional information on the return value - */ - function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external returns (uint256); - - /** - * @dev Validates a signature using ERC-1271 - * @param sender the address that sent the ERC-1271 request to the smart account - * @param hash the hash of the ERC-1271 request - * @param signature the signature of the ERC-1271 request - * - * MUST return the ERC-1271 `MAGIC_VALUE` if the signature is valid - * MUST NOT modify state - */ - function isValidSignatureWithSender( - address sender, - bytes32 hash, - bytes calldata signature - ) external view returns (bytes4); -} - -/** - * @dev ERC-7579 Hooks module (type 4). - * - * A module that implements logic to execute before and after the account executes a user operation, - * either individually or batched. - */ -interface IERC7579Hook is IERC7579Module { - /** - * @dev Called by the smart account before execution - * @param msgSender the address that called the smart account - * @param value the value that was sent to the smart account - * @param msgData the data that was sent to the smart account - * - * MAY return arbitrary data in the `hookData` return value - */ - function preCheck( - address msgSender, - uint256 value, - bytes calldata msgData - ) external returns (bytes memory hookData); - - /** - * @dev Called by the smart account after execution - * @param hookData the data that was returned by the `preCheck` function - * - * MAY validate the `hookData` to validate transaction context of the `preCheck` function - */ - function postCheck(bytes calldata hookData) external; -} - -struct Execution { - address target; - uint256 value; - bytes callData; -} - -/** - * @dev ERC-7579 Execution. - * - * Accounts should implement this interface so that the Entrypoint and ERC-7579 modules can execute operations. - */ -interface IERC7579Execution { - /** - * @dev Executes a transaction on behalf of the account. - * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details - * @param executionCalldata The encoded execution call data - * - * MUST ensure adequate authorization control: e.g. onlyEntryPointOrSelf if used with ERC-4337 - * If a mode is requested that is not supported by the Account, it MUST revert - */ - function execute(bytes32 mode, bytes calldata executionCalldata) external payable; - - /** - * @dev Executes a transaction on behalf of the account. - * This function is intended to be called by Executor Modules - * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details - * @param executionCalldata The encoded execution call data - * @return returnData An array with the returned data of each executed subcall - * - * MUST ensure adequate authorization control: i.e. onlyExecutorModule - * If a mode is requested that is not supported by the Account, it MUST revert - */ - function executeFromExecutor( - bytes32 mode, - bytes calldata executionCalldata - ) external payable returns (bytes[] memory returnData); -} - -/** - * @dev ERC-7579 Account Config. - * - * Accounts should implement this interface to expose information that identifies the account, supported modules and capabilities. - */ -interface IERC7579AccountConfig { - /** - * @dev Returns the account id of the smart account - * @return accountImplementationId the account id of the smart account - * - * MUST return a non-empty string - * The accountId SHOULD be structured like so: - * "vendorname.accountname.semver" - * The id SHOULD be unique across all smart accounts - */ - function accountId() external view returns (string memory accountImplementationId); - - /** - * @dev Function to check if the account supports a certain execution mode (see above) - * @param encodedMode the encoded mode - * - * MUST return true if the account supports the mode and false otherwise - */ - function supportsExecutionMode(bytes32 encodedMode) external view returns (bool); - - /** - * @dev Function to check if the account supports a certain module typeId - * @param moduleTypeId the module type ID according to the ERC-7579 spec - * - * MUST return true if the account supports the module type and false otherwise - */ - function supportsModule(uint256 moduleTypeId) external view returns (bool); -} - -/** - * @dev ERC-7579 Module Config. - * - * Accounts should implement this interface to allow installing and uninstalling modules. - */ -interface IERC7579ModuleConfig { - event ModuleInstalled(uint256 moduleTypeId, address module); - event ModuleUninstalled(uint256 moduleTypeId, address module); - - /** - * @dev Installs a Module of a certain type on the smart account - * @param moduleTypeId the module type ID according to the ERC-7579 spec - * @param module the module address - * @param initData arbitrary data that may be passed to the module during `onInstall` - * initialization. - * - * MUST implement authorization control - * MUST call `onInstall` on the module with the `initData` parameter if provided - * MUST emit ModuleInstalled event - * MUST revert if the module is already installed or the initialization on the module failed - */ - function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external; - - /** - * @dev Uninstalls a Module of a certain type on the smart account - * @param moduleTypeId the module type ID according the ERC-7579 spec - * @param module the module address - * @param deInitData arbitrary data that may be passed to the module during `onUninstall` - * deinitialization. - * - * MUST implement authorization control - * MUST call `onUninstall` on the module with the `deInitData` parameter if provided - * MUST emit ModuleUninstalled event - * MUST revert if the module is not installed or the deInitialization on the module failed - */ - function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external; - - /** - * @dev Returns whether a module is installed on the smart account - * @param moduleTypeId the module type ID according the ERC-7579 spec - * @param module the module address - * @param additionalContext arbitrary data that may be passed to determine if the module is installed - * - * MUST return true if the module is installed and false otherwise - */ - function isModuleInstalled( - uint256 moduleTypeId, - address module, - bytes calldata additionalContext - ) external view returns (bool); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7674.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7674.sol deleted file mode 100644 index 240c0e9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7674.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC7674.sol) - -pragma solidity >=0.6.2; - -import {IERC20} from "./IERC20.sol"; - -/** - * @dev Temporary Approval Extension for ERC-20 (https://github.com/ethereum/ERCs/pull/358[ERC-7674]) - */ -interface IERC7674 is IERC20 { - /** - * @dev Set the temporary allowance, allowing `spender` to withdraw (within the same transaction) assets - * held by the caller. - */ - function temporaryApprove(address spender, uint256 value) external returns (bool success); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7802.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7802.sol deleted file mode 100644 index 940eddd..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7802.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC7802.sol) -pragma solidity >=0.6.2; - -import {IERC165} from "./IERC165.sol"; - -/// @title IERC7802 -/// @notice Defines the interface for crosschain ERC20 transfers. -interface IERC7802 is IERC165 { - /// @notice Emitted when a crosschain transfer mints tokens. - /// @param to Address of the account tokens are being minted for. - /// @param amount Amount of tokens minted. - /// @param sender Address of the caller (msg.sender) who invoked crosschainMint. - event CrosschainMint(address indexed to, uint256 amount, address indexed sender); - - /// @notice Emitted when a crosschain transfer burns tokens. - /// @param from Address of the account tokens are being burned from. - /// @param amount Amount of tokens burned. - /// @param sender Address of the caller (msg.sender) who invoked crosschainBurn. - event CrosschainBurn(address indexed from, uint256 amount, address indexed sender); - - /// @notice Mint tokens through a crosschain transfer. - /// @param _to Address to mint tokens to. - /// @param _amount Amount of tokens to mint. - function crosschainMint(address _to, uint256 _amount) external; - - /// @notice Burn tokens through a crosschain transfer. - /// @param _from Address to burn tokens from. - /// @param _amount Amount of tokens to burn. - function crosschainBurn(address _from, uint256 _amount) external; -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7821.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7821.sol deleted file mode 100644 index 8a11a6e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC7821.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC7821.sol) - -pragma solidity >=0.5.0; - -/** - * @dev Interface for minimal batch executor. - */ -interface IERC7821 { - /** - * @dev Executes the calls in `executionData`. - * Reverts and bubbles up error if any call fails. - * - * `executionData` encoding: - * - If `opData` is empty, `executionData` is simply `abi.encode(calls)`. - * - Else, `executionData` is `abi.encode(calls, opData)`. - * See: https://eips.ethereum.org/EIPS/eip-7579 - * - * Supported modes: - * - `bytes32(0x01000000000000000000...)`: does not support optional `opData`. - * - `bytes32(0x01000000000078210001...)`: supports optional `opData`. - * - * Authorization checks: - * - If `opData` is empty, the implementation SHOULD require that - * `msg.sender == address(this)`. - * - If `opData` is not empty, the implementation SHOULD use the signature - * encoded in `opData` to determine if the caller can perform the execution. - * - * `opData` may be used to store additional data for authentication, - * paymaster data, gas limits, etc. - * - * For calldata compression efficiency, if a Call.to is `address(0)`, - * it will be replaced with `address(this)`. - */ - function execute(bytes32 mode, bytes calldata executionData) external payable; - - /** - * @dev This function is provided for frontends to detect support. - * Only returns true for: - * - `bytes32(0x01000000000000000000...)`: does not support optional `opData`. - * - `bytes32(0x01000000000078210001...)`: supports optional `opData`. - */ - function supportsExecutionMode(bytes32 mode) external view returns (bool); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol deleted file mode 100644 index cdff6f7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (metatx/ERC2771Context.sol) - -pragma solidity ^0.8.20; - -import {Context} from "../utils/Context.sol"; - -/** - * @dev Context variant with ERC-2771 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 ERC-2771 - * 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`. - * - * WARNING: The usage of `delegatecall` in this contract is dangerous and may result in context corruption. - * Any forwarded request to this contract triggering a `delegatecall` to itself will result in an invalid {_msgSender} - * recovery. - */ -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) { - uint256 calldataLength = msg.data.length; - uint256 contextSuffixLength = _contextSuffixLength(); - if (calldataLength >= contextSuffixLength && isTrustedForwarder(msg.sender)) { - unchecked { - return address(bytes20(msg.data[calldataLength - contextSuffixLength:])); - } - } 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) { - uint256 calldataLength = msg.data.length; - uint256 contextSuffixLength = _contextSuffixLength(); - if (calldataLength >= contextSuffixLength && isTrustedForwarder(msg.sender)) { - unchecked { - return msg.data[:calldataLength - contextSuffixLength]; - } - } else { - return super._msgData(); - } - } - - /** - * @dev ERC-2771 specifies the context as being a single address (20 bytes). - */ - function _contextSuffixLength() internal view virtual override returns (uint256) { - return 20; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Forwarder.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Forwarder.sol deleted file mode 100644 index a463e70..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/ERC2771Forwarder.sol +++ /dev/null @@ -1,372 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.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"; -import {Errors} from "../utils/Errors.sol"; - -/** - * @dev A forwarder compatible with ERC-2771 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 Errors.FailedCall(); - } - } - - /** - * @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 isValid, address signer) { - (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 ("memory-safe") { - 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. - * - * NOTE: Consider the execution of this forwarder is permissionless. Without this check, anyone may transfer assets - * that are owned by, or are approved to this forwarder. - */ - function _isTrustedByTarget(address target) internal view virtual returns (bool) { - bytes memory encodedParams = abi.encodeCall(ERC2771Context.isTrustedForwarder, (address(this))); - - bool success; - uint256 returnSize; - uint256 returnValue; - assembly ("memory-safe") { - // Perform the staticcall 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 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 - assembly ("memory-safe") { - invalid() - } - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/README.adoc deleted file mode 100644 index c02fb10..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/metatx/README.adoc +++ /dev/null @@ -1,17 +0,0 @@ -= Meta Transactions - -[.readme-notice] -NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/metatx - -This directory includes contracts for adding meta-transaction capabilities (i.e. abstracting the execution context from the transaction origin) following the https://eips.ethereum.org/EIPS/eip-2771[ERC-2771 specification]. - -- {ERC2771Context}: Provides a mechanism to override the sender and calldata of the execution context (`msg.sender` and `msg.data`) with a custom value specified by a trusted forwarder. -- {ERC2771Forwarder}: A production-ready forwarder that relays operation requests signed off-chain by an EOA. - -== Core - -{{ERC2771Context}} - -== Utils - -{{ERC2771Forwarder}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagedTarget.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagedTarget.sol deleted file mode 100644 index 673feed..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagedTarget.sol +++ /dev/null @@ -1,34 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagerMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagerMock.sol deleted file mode 100644 index 4b5be35..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AccessManagerMock.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {AccessManager} from "../access/manager/AccessManager.sol"; - -contract AccessManagerMock is AccessManager { - event CalledRestricted(address caller); - event CalledUnrestricted(address caller); - - constructor(address initialAdmin) AccessManager(initialAdmin) {} - - function fnRestricted() public onlyAuthorized { - emit CalledRestricted(msg.sender); - } - - function fnUnrestricted() public { - emit CalledUnrestricted(msg.sender); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol deleted file mode 100644 index 68f7d1d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol +++ /dev/null @@ -1,171 +0,0 @@ -// 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 value) external view returns (uint256) { - return _array.findUpperBound(value); - } - - function lowerBound(uint256 value) external view returns (uint256) { - return _array.lowerBound(value); - } - - function upperBound(uint256 value) external view returns (uint256) { - return _array.upperBound(value); - } - - function lowerBoundMemory(uint256[] memory array, uint256 value) external pure returns (uint256) { - return array.lowerBoundMemory(value); - } - - function upperBoundMemory(uint256[] memory array, uint256 value) external pure returns (uint256) { - return array.upperBoundMemory(value); - } - - function unsafeAccess(uint256 pos) external view returns (uint256) { - return _array.unsafeAccess(pos).value; - } - - function sort(uint256[] memory array) external pure returns (uint256[] memory) { - return array.sort(); - } - - function sortReverse(uint256[] memory array) external pure returns (uint256[] memory) { - return array.sort(_reverse); - } - - function _reverse(uint256 a, uint256 b) private pure returns (bool) { - return a > b; - } - - function unsafeSetLength(uint256 newLength) external { - _array.unsafeSetLength(newLength); - } - - function length() external view returns (uint256) { - return _array.length; - } -} - -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; - } - - function sort(address[] memory array) external pure returns (address[] memory) { - return array.sort(); - } - - function sortReverse(address[] memory array) external pure returns (address[] memory) { - return array.sort(_reverse); - } - - function _reverse(address a, address b) private pure returns (bool) { - return uint160(a) > uint160(b); - } - - function unsafeSetLength(uint256 newLength) external { - _array.unsafeSetLength(newLength); - } - - function length() external view returns (uint256) { - return _array.length; - } -} - -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; - } - - function sort(bytes32[] memory array) external pure returns (bytes32[] memory) { - return array.sort(); - } - - function sortReverse(bytes32[] memory array) external pure returns (bytes32[] memory) { - return array.sort(_reverse); - } - - function _reverse(bytes32 a, bytes32 b) private pure returns (bool) { - return uint256(a) > uint256(b); - } - - function unsafeSetLength(uint256 newLength) external { - _array.unsafeSetLength(newLength); - } - - function length() external view returns (uint256) { - return _array.length; - } -} - -contract BytesArraysMock { - using Arrays for bytes[]; - - bytes[] private _array; - - constructor(bytes[] memory array) { - _array = array; - } - - function unsafeAccess(uint256 pos) external view returns (bytes memory) { - return _array.unsafeAccess(pos).value; - } - - function unsafeSetLength(uint256 newLength) external { - _array.unsafeSetLength(newLength); - } - - function length() external view returns (uint256) { - return _array.length; - } -} - -contract StringArraysMock { - using Arrays for string[]; - - string[] private _array; - - constructor(string[] memory array) { - _array = array; - } - - function unsafeAccess(uint256 pos) external view returns (string memory) { - return _array.unsafeAccess(pos).value; - } - - function unsafeSetLength(uint256 newLength) external { - _array.unsafeSetLength(newLength); - } - - function length() external view returns (uint256) { - return _array.length; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AuthorityMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AuthorityMock.sol deleted file mode 100644 index cd2356e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/AuthorityMock.sol +++ /dev/null @@ -1,69 +0,0 @@ -// 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 private _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 private _immediate; - uint256 private _delay; - - function canCall( - address /* caller */, - address /* target */, - bytes4 /* selector */ - ) external view returns (bool immediate, uint256 delay) { - return (_immediate, _delay); - } - - function _setImmediate(bool immediate) external { - _immediate = immediate; - } - - function _setDelay(uint256 delay) external { - _delay = delay; - } -} - -contract AuthorityNoResponse { - function canCall(address /* caller */, address /* target */, bytes4 /* selector */) external view {} -} - -contract AuthorityObserveIsConsuming { - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Base64Dirty.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Base64Dirty.sol deleted file mode 100644 index 238bd26..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Base64Dirty.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {Base64} from "../utils/Base64.sol"; - -contract Base64Dirty { - struct A { - uint256 value; - } - - function encode(bytes memory input) public pure returns (string memory) { - A memory unused = A({value: type(uint256).max}); - // To silence warning - unused; - - return Base64.encode(input); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/BatchCaller.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/BatchCaller.sol deleted file mode 100644 index 740691b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/BatchCaller.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {Address} from "../utils/Address.sol"; - -contract BatchCaller { - struct Call { - address target; - uint256 value; - bytes data; - } - - function execute(Call[] calldata calls) external returns (bytes[] memory) { - bytes[] memory returndata = new bytes[](calls.length); - for (uint256 i = 0; i < calls.length; ++i) { - returndata[i] = Address.functionCallWithValue(calls[i].target, calls[i].data, calls[i].value); - } - return returndata; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol deleted file mode 100644 index 8b5ec7a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -contract CallReceiverMock { - event MockFunctionCalled(); - event MockFunctionCalledWithArgs(uint256 a, uint256 b); - event MockFunctionCalledExtra(address caller, uint256 value); - - 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"; - } - - function mockFunctionExtra() public payable { - emit MockFunctionCalledExtra(msg.sender, msg.value); - } -} - -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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ConstructorMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ConstructorMock.sol deleted file mode 100644 index 50e671b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ConstructorMock.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -contract ConstructorMock { - bool foo; - - enum RevertType { - None, - RevertWithoutMessage, - RevertWithMessage, - RevertWithCustomError, - Panic - } - - error CustomError(); - - constructor(RevertType error) { - // After transpilation to upgradeable contract, the constructor will become an initializer - // To silence the `... can be restricted to view` warning, we write to state - foo = true; - - if (error == RevertType.RevertWithoutMessage) { - revert(); - } else if (error == RevertType.RevertWithMessage) { - revert("ConstructorMock: reverting"); - } else if (error == RevertType.RevertWithCustomError) { - revert CustomError(); - } else if (error == RevertType.Panic) { - uint256 a = uint256(0) / uint256(0); - a; - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol deleted file mode 100644 index 199b2a9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol +++ /dev/null @@ -1,35 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol deleted file mode 100644 index 0f11474..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.22; - -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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol deleted file mode 100644 index fe32a21..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol +++ /dev/null @@ -1,16 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol deleted file mode 100644 index cba7d47..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol +++ /dev/null @@ -1,24 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165InterfacesSupported.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165InterfacesSupported.sol deleted file mode 100644 index dffd6a2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165InterfacesSupported.sol +++ /dev/null @@ -1,58 +0,0 @@ -// 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 ERC-165 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol deleted file mode 100644 index 3542756..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol +++ /dev/null @@ -1,12 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol deleted file mode 100644 index fec4339..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -contract ERC165MissingData { - function supportsInterface(bytes4 interfaceId) public view {} // missing return -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol deleted file mode 100644 index 78ef9c8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -contract ERC165NotSupported {} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol deleted file mode 100644 index 4bfacfd..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol +++ /dev/null @@ -1,18 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol deleted file mode 100644 index 33887cf..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {ContextMock} from "./ContextMock.sol"; -import {Context} from "../utils/Context.sol"; -import {Multicall} from "../utils/Multicall.sol"; -import {ERC2771Context} from "../metatx/ERC2771Context.sol"; - -// By inheriting from ERC2771Context, Context's internal functions are overridden automatically -contract ERC2771ContextMock is ContextMock, ERC2771Context, Multicall { - /// @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(); - } - - function _contextSuffixLength() internal view override(Context, ERC2771Context) returns (uint256) { - return ERC2771Context._contextSuffixLength(); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol deleted file mode 100644 index 261fea1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol +++ /dev/null @@ -1,53 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol deleted file mode 100644 index 1b1c936..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol +++ /dev/null @@ -1,17 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol deleted file mode 100644 index 7f76caa..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol +++ /dev/null @@ -1,130 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleProofCustomHashMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleProofCustomHashMock.sol deleted file mode 100644 index 1039af3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleProofCustomHashMock.sol +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {MerkleProof} from "../utils/cryptography/MerkleProof.sol"; - -// This could be a library, but then we would have to add it to the Stateless.sol mock for upgradeable tests -abstract contract MerkleProofCustomHashMock { - function customHash(bytes32 a, bytes32 b) internal pure returns (bytes32) { - return a < b ? sha256(abi.encode(a, b)) : sha256(abi.encode(b, a)); - } - - function verify(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal view returns (bool) { - return MerkleProof.verify(proof, root, leaf, customHash); - } - - function processProof(bytes32[] calldata proof, bytes32 leaf) internal view returns (bytes32) { - return MerkleProof.processProof(proof, leaf, customHash); - } - - function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal view returns (bool) { - return MerkleProof.verifyCalldata(proof, root, leaf, customHash); - } - - function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal view returns (bytes32) { - return MerkleProof.processProofCalldata(proof, leaf, customHash); - } - - function multiProofVerify( - bytes32[] calldata proof, - bool[] calldata proofFlags, - bytes32 root, - bytes32[] calldata leaves - ) internal view returns (bool) { - return MerkleProof.multiProofVerify(proof, proofFlags, root, leaves, customHash); - } - - function processMultiProof( - bytes32[] calldata proof, - bool[] calldata proofFlags, - bytes32[] calldata leaves - ) internal view returns (bytes32) { - return MerkleProof.processMultiProof(proof, proofFlags, leaves, customHash); - } - - function multiProofVerifyCalldata( - bytes32[] calldata proof, - bool[] calldata proofFlags, - bytes32 root, - bytes32[] calldata leaves - ) internal view returns (bool) { - return MerkleProof.multiProofVerifyCalldata(proof, proofFlags, root, leaves, customHash); - } - - function processMultiProofCalldata( - bytes32[] calldata proof, - bool[] calldata proofFlags, - bytes32[] calldata leaves - ) internal view returns (bytes32) { - return MerkleProof.processMultiProofCalldata(proof, proofFlags, leaves, customHash); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleTreeMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleTreeMock.sol deleted file mode 100644 index 48ee1a6..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MerkleTreeMock.sol +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {MerkleTree} from "../utils/structs/MerkleTree.sol"; - -contract MerkleTreeMock { - using MerkleTree for MerkleTree.Bytes32PushTree; - - MerkleTree.Bytes32PushTree private _tree; - - // This mock only stored the latest root. - // Production contract may want to store historical values. - bytes32 public root; - - event LeafInserted(bytes32 leaf, uint256 index, bytes32 root); - event LeafUpdated(bytes32 oldLeaf, bytes32 newLeaf, uint256 index, bytes32 root); - - function setup(uint8 _depth, bytes32 _zero) public { - root = _tree.setup(_depth, _zero); - } - - function push(bytes32 leaf) public { - (uint256 leafIndex, bytes32 currentRoot) = _tree.push(leaf); - emit LeafInserted(leaf, leafIndex, currentRoot); - root = currentRoot; - } - - function update(uint256 index, bytes32 oldValue, bytes32 newValue, bytes32[] memory proof) public { - (bytes32 oldRoot, bytes32 newRoot) = _tree.update(index, oldValue, newValue, proof); - if (oldRoot != root) revert MerkleTree.MerkleTreeUpdateInvalidProof(); - emit LeafUpdated(oldValue, newValue, index, newRoot); - root = newRoot; - } - - function depth() public view returns (uint256) { - return _tree.depth(); - } - - // internal state - function nextLeafIndex() public view returns (uint256) { - return _tree._nextLeafIndex; - } - - function sides(uint256 i) public view returns (bytes32) { - return _tree._sides[i]; - } - - function zeros(uint256 i) public view returns (bytes32) { - return _tree._zeros[i]; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MulticallHelper.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MulticallHelper.sol deleted file mode 100644 index d70f3bf..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MulticallHelper.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {ERC20MulticallMock} from "./token/ERC20MulticallMock.sol"; - -contract MulticallHelper { - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol deleted file mode 100644 index 51030ac..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol +++ /dev/null @@ -1,131 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol deleted file mode 100644 index fa701e2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol +++ /dev/null @@ -1,31 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol deleted file mode 100644 index 3df2d1c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol +++ /dev/null @@ -1,12 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol deleted file mode 100644 index 39e2d5e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol +++ /dev/null @@ -1,50 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyTransientMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyTransientMock.sol deleted file mode 100644 index f0e61ea..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/ReentrancyTransientMock.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -import {ReentrancyGuardTransient} from "../utils/ReentrancyGuardTransient.sol"; -import {ReentrancyAttack} from "./ReentrancyAttack.sol"; - -contract ReentrancyTransientMock is ReentrancyGuardTransient { - 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, "ReentrancyTransientMock: 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol deleted file mode 100644 index 19b9706..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol +++ /dev/null @@ -1,61 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol deleted file mode 100644 index 0bd3c61..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol +++ /dev/null @@ -1,49 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Stateless.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Stateless.sol deleted file mode 100644 index 8977f87..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/Stateless.sol +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -// 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 {Blockhash} from "../utils/Blockhash.sol"; -import {Bytes} from "../utils/Bytes.sol"; -import {CAIP2} from "../utils/CAIP2.sol"; -import {CAIP10} from "../utils/CAIP10.sol"; -import {Checkpoints} from "../utils/structs/Checkpoints.sol"; -import {CircularBuffer} from "../utils/structs/CircularBuffer.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 {EIP7702Utils} from "../account/utils/EIP7702Utils.sol"; -import {EnumerableMap} from "../utils/structs/EnumerableMap.sol"; -import {EnumerableSet} from "../utils/structs/EnumerableSet.sol"; -import {ERC165} from "../utils/introspection/ERC165.sol"; -import {ERC165Checker} from "../utils/introspection/ERC165Checker.sol"; -import {ERC721Holder} from "../token/ERC721/utils/ERC721Holder.sol"; -import {ERC1155Holder} from "../token/ERC1155/utils/ERC1155Holder.sol"; -import {ERC1967Utils} from "../proxy/ERC1967/ERC1967Utils.sol"; -import {ERC4337Utils} from "../account/utils/draft-ERC4337Utils.sol"; -import {ERC7579Utils} from "../account/utils/draft-ERC7579Utils.sol"; -import {ERC7913P256Verifier} from "../utils/cryptography/verifiers/ERC7913P256Verifier.sol"; -import {ERC7913RSAVerifier} from "../utils/cryptography/verifiers/ERC7913RSAVerifier.sol"; -import {Heap} from "../utils/structs/Heap.sol"; -import {Math} from "../utils/math/Math.sol"; -import {MerkleProof} from "../utils/cryptography/MerkleProof.sol"; -import {MessageHashUtils} from "../utils/cryptography/MessageHashUtils.sol"; -import {Nonces} from "../utils/Nonces.sol"; -import {NoncesKeyed} from "../utils/NoncesKeyed.sol"; -import {P256} from "../utils/cryptography/P256.sol"; -import {Packing} from "../utils/Packing.sol"; -import {Panic} from "../utils/Panic.sol"; -import {RSA} from "../utils/cryptography/RSA.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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol deleted file mode 100644 index ec176e2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: MIT -// This file was procedurally generated from scripts/generate/templates/StorageSlotMock.js. - -pragma solidity ^0.8.20; - -import {Multicall} from "../utils/Multicall.sol"; -import {StorageSlot} from "../utils/StorageSlot.sol"; - -contract StorageSlotMock is Multicall { - using StorageSlot for *; - - function setAddressSlot(bytes32 slot, address value) public { - slot.getAddressSlot().value = value; - } - - function setBooleanSlot(bytes32 slot, bool value) public { - slot.getBooleanSlot().value = value; - } - - function setBytes32Slot(bytes32 slot, bytes32 value) public { - slot.getBytes32Slot().value = value; - } - - function setUint256Slot(bytes32 slot, uint256 value) public { - slot.getUint256Slot().value = value; - } - - function setInt256Slot(bytes32 slot, int256 value) public { - slot.getInt256Slot().value = value; - } - - function getAddressSlot(bytes32 slot) public view returns (address) { - return slot.getAddressSlot().value; - } - - function getBooleanSlot(bytes32 slot) public view returns (bool) { - return slot.getBooleanSlot().value; - } - - function getBytes32Slot(bytes32 slot) public view returns (bytes32) { - return slot.getBytes32Slot().value; - } - - function getUint256Slot(bytes32 slot) public view returns (uint256) { - return slot.getUint256Slot().value; - } - - function getInt256Slot(bytes32 slot) public view returns (int256) { - return slot.getInt256Slot().value; - } - - mapping(uint256 key => string) public stringMap; - - function setStringSlot(bytes32 slot, string calldata value) public { - slot.getStringSlot().value = value; - } - - function setStringStorage(uint256 key, string calldata value) public { - stringMap[key].getStringSlot().value = value; - } - - function getStringSlot(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 setBytesSlot(bytes32 slot, bytes calldata value) public { - slot.getBytesSlot().value = value; - } - - function setBytesStorage(uint256 key, bytes calldata value) public { - bytesMap[key].getBytesSlot().value = value; - } - - function getBytesSlot(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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TimelockReentrant.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TimelockReentrant.sol deleted file mode 100644 index aab676a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TimelockReentrant.sol +++ /dev/null @@ -1,26 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TransientSlotMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TransientSlotMock.sol deleted file mode 100644 index 6b18fa5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/TransientSlotMock.sol +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: MIT -// This file was procedurally generated from scripts/generate/templates/TransientSlotMock.js. - -pragma solidity ^0.8.24; - -import {Multicall} from "../utils/Multicall.sol"; -import {TransientSlot} from "../utils/TransientSlot.sol"; - -contract TransientSlotMock is Multicall { - using TransientSlot for *; - - event AddressValue(bytes32 slot, address value); - - function tloadAddress(bytes32 slot) public { - emit AddressValue(slot, slot.asAddress().tload()); - } - - function tstore(bytes32 slot, address value) public { - slot.asAddress().tstore(value); - } - - event BooleanValue(bytes32 slot, bool value); - - function tloadBoolean(bytes32 slot) public { - emit BooleanValue(slot, slot.asBoolean().tload()); - } - - function tstore(bytes32 slot, bool value) public { - slot.asBoolean().tstore(value); - } - - event Bytes32Value(bytes32 slot, bytes32 value); - - function tloadBytes32(bytes32 slot) public { - emit Bytes32Value(slot, slot.asBytes32().tload()); - } - - function tstore(bytes32 slot, bytes32 value) public { - slot.asBytes32().tstore(value); - } - - event Uint256Value(bytes32 slot, uint256 value); - - function tloadUint256(bytes32 slot) public { - emit Uint256Value(slot, slot.asUint256().tload()); - } - - function tstore(bytes32 slot, uint256 value) public { - slot.asUint256().tstore(value); - } - - event Int256Value(bytes32 slot, int256 value); - - function tloadInt256(bytes32 slot) public { - emit Int256Value(slot, slot.asInt256().tload()); - } - - function tstore(bytes32 slot, int256 value) public { - slot.asInt256().tstore(value); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/UpgradeableBeaconMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/UpgradeableBeaconMock.sol deleted file mode 100644 index 354ac02..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/UpgradeableBeaconMock.sol +++ /dev/null @@ -1,27 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesExtendedMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesExtendedMock.sol deleted file mode 100644 index 9c45619..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesExtendedMock.sol +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {VotesExtended} from "../governance/utils/VotesExtended.sol"; - -abstract contract VotesExtendedMock is VotesExtended { - 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 VotesExtendedTimestampMock is VotesExtendedMock { - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol deleted file mode 100644 index e28d6b5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol +++ /dev/null @@ -1,42 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/AccountMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/AccountMock.sol deleted file mode 100644 index a870156..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/AccountMock.sol +++ /dev/null @@ -1,169 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.27; - -import {Account} from "../../account/Account.sol"; -import {AccountERC7579} from "../../account/extensions/draft-AccountERC7579.sol"; -import {AccountERC7579Hooked} from "../../account/extensions/draft-AccountERC7579Hooked.sol"; -import {ERC721Holder} from "../../token/ERC721/utils/ERC721Holder.sol"; -import {ERC1155Holder} from "../../token/ERC1155/utils/ERC1155Holder.sol"; -import {ERC4337Utils} from "../../account/utils/draft-ERC4337Utils.sol"; -import {ERC7739} from "../../utils/cryptography/signers/draft-ERC7739.sol"; -import {ERC7821} from "../../account/extensions/draft-ERC7821.sol"; -import {MODULE_TYPE_VALIDATOR} from "../../interfaces/draft-IERC7579.sol"; -import {PackedUserOperation} from "../../interfaces/draft-IERC4337.sol"; -import {AbstractSigner} from "../../utils/cryptography/signers/AbstractSigner.sol"; -import {SignerECDSA} from "../../utils/cryptography/signers/SignerECDSA.sol"; -import {SignerP256} from "../../utils/cryptography/signers/SignerP256.sol"; -import {SignerRSA} from "../../utils/cryptography/signers/SignerRSA.sol"; -import {SignerERC7702} from "../../utils/cryptography/signers/SignerERC7702.sol"; -import {SignerERC7913} from "../../utils/cryptography/signers/SignerERC7913.sol"; -import {MultiSignerERC7913} from "../../utils/cryptography/signers/MultiSignerERC7913.sol"; -import {MultiSignerERC7913Weighted} from "../../utils/cryptography/signers/MultiSignerERC7913Weighted.sol"; - -abstract contract AccountMock is Account, ERC7739, ERC7821, ERC721Holder, ERC1155Holder { - /// Validates a user operation with a boolean signature. - function _rawSignatureValidation(bytes32 hash, bytes calldata signature) internal pure override returns (bool) { - return signature.length >= 32 && bytes32(signature) == hash; - } - - /// @inheritdoc ERC7821 - function _erc7821AuthorizedExecutor( - address caller, - bytes32 mode, - bytes calldata executionData - ) internal view virtual override returns (bool) { - return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); - } -} - -abstract contract AccountECDSAMock is Account, SignerECDSA, ERC7739, ERC7821, ERC721Holder, ERC1155Holder { - /// @inheritdoc ERC7821 - function _erc7821AuthorizedExecutor( - address caller, - bytes32 mode, - bytes calldata executionData - ) internal view virtual override returns (bool) { - return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); - } -} - -abstract contract AccountP256Mock is Account, SignerP256, ERC7739, ERC7821, ERC721Holder, ERC1155Holder { - /// @inheritdoc ERC7821 - function _erc7821AuthorizedExecutor( - address caller, - bytes32 mode, - bytes calldata executionData - ) internal view virtual override returns (bool) { - return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); - } -} - -abstract contract AccountRSAMock is Account, SignerRSA, ERC7739, ERC7821, ERC721Holder, ERC1155Holder { - /// @inheritdoc ERC7821 - function _erc7821AuthorizedExecutor( - address caller, - bytes32 mode, - bytes calldata executionData - ) internal view virtual override returns (bool) { - return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); - } -} - -abstract contract AccountERC7702Mock is Account, SignerERC7702, ERC7739, ERC7821, ERC721Holder, ERC1155Holder { - /// @inheritdoc ERC7821 - function _erc7821AuthorizedExecutor( - address caller, - bytes32 mode, - bytes calldata executionData - ) internal view virtual override returns (bool) { - return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); - } -} - -abstract contract AccountERC7702WithModulesMock is - Account, - AccountERC7579, - SignerERC7702, - ERC7739, - ERC721Holder, - ERC1155Holder -{ - function _validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) internal virtual override(Account, AccountERC7579) returns (uint256) { - return super._validateUserOp(userOp, userOpHash); - } - - /// @dev Resolve implementation of ERC-1271 by both ERC7739 and AccountERC7579 to support both schemes. - function isValidSignature( - bytes32 hash, - bytes calldata signature - ) public view virtual override(ERC7739, AccountERC7579) returns (bytes4) { - // ERC-7739 can return the fn selector (success), 0xffffffff (invalid) or 0x77390001 (detection). - // If the return is 0xffffffff, we fallback to validation using ERC-7579 modules. - bytes4 erc7739magic = ERC7739.isValidSignature(hash, signature); - return erc7739magic == bytes4(0xffffffff) ? AccountERC7579.isValidSignature(hash, signature) : erc7739magic; - } - - /// @dev Enable signature using the ERC-7702 signer. - function _rawSignatureValidation( - bytes32 hash, - bytes calldata signature - ) internal view virtual override(AbstractSigner, AccountERC7579, SignerERC7702) returns (bool) { - return SignerERC7702._rawSignatureValidation(hash, signature); - } -} - -abstract contract AccountERC7579Mock is AccountERC7579 { - constructor(address validator, bytes memory initData) { - _installModule(MODULE_TYPE_VALIDATOR, validator, initData); - } -} - -abstract contract AccountERC7579HookedMock is AccountERC7579Hooked { - constructor(address validator, bytes memory initData) { - _installModule(MODULE_TYPE_VALIDATOR, validator, initData); - } -} - -abstract contract AccountERC7913Mock is Account, SignerERC7913, ERC7739, ERC7821, ERC721Holder, ERC1155Holder { - /// @inheritdoc ERC7821 - function _erc7821AuthorizedExecutor( - address caller, - bytes32 mode, - bytes calldata executionData - ) internal view virtual override returns (bool) { - return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); - } -} - -abstract contract AccountMultiSignerMock is Account, MultiSignerERC7913, ERC7739, ERC7821, ERC721Holder, ERC1155Holder { - /// @inheritdoc ERC7821 - function _erc7821AuthorizedExecutor( - address caller, - bytes32 mode, - bytes calldata executionData - ) internal view virtual override returns (bool) { - return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); - } -} - -abstract contract AccountMultiSignerWeightedMock is - Account, - MultiSignerERC7913Weighted, - ERC7739, - ERC7821, - ERC721Holder, - ERC1155Holder -{ - /// @inheritdoc ERC7821 - function _erc7821AuthorizedExecutor( - address caller, - bytes32 mode, - bytes calldata executionData - ) internal view virtual override returns (bool) { - return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/modules/ERC7579Mock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/modules/ERC7579Mock.sol deleted file mode 100644 index 4cb559e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/modules/ERC7579Mock.sol +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -import {MODULE_TYPE_HOOK, MODULE_TYPE_FALLBACK, MODULE_TYPE_VALIDATOR, IERC7579Hook, IERC7579Module, IERC7579Validator} from "../../../interfaces/draft-IERC7579.sol"; -import {SignatureChecker} from "../../../utils/cryptography/SignatureChecker.sol"; -import {PackedUserOperation} from "../../../interfaces/draft-IERC4337.sol"; -import {IERC1271} from "../../../interfaces/IERC1271.sol"; -import {ERC4337Utils} from "../../../account/utils/draft-ERC4337Utils.sol"; - -abstract contract ERC7579ModuleMock is IERC7579Module { - uint256 private _moduleTypeId; - - event ModuleInstalledReceived(address account, bytes data); - event ModuleUninstalledReceived(address account, bytes data); - - constructor(uint256 moduleTypeId) { - _moduleTypeId = moduleTypeId; - } - - function onInstall(bytes calldata data) public virtual { - emit ModuleInstalledReceived(msg.sender, data); - } - - function onUninstall(bytes calldata data) public virtual { - emit ModuleUninstalledReceived(msg.sender, data); - } - - function isModuleType(uint256 moduleTypeId) external view returns (bool) { - return moduleTypeId == _moduleTypeId; - } -} - -abstract contract ERC7579HookMock is ERC7579ModuleMock(MODULE_TYPE_HOOK), IERC7579Hook { - event PreCheck(address sender, uint256 value, bytes data); - event PostCheck(bytes hookData); - - function preCheck( - address msgSender, - uint256 value, - bytes calldata msgData - ) external returns (bytes memory hookData) { - emit PreCheck(msgSender, value, msgData); - return msgData; - } - - function postCheck(bytes calldata hookData) external { - emit PostCheck(hookData); - } -} - -abstract contract ERC7579FallbackHandlerMock is ERC7579ModuleMock(MODULE_TYPE_FALLBACK) { - event ERC7579FallbackHandlerMockCalled(address account, address sender, uint256 value, bytes data); - - error ERC7579FallbackHandlerMockRevert(); - - function _msgAccount() internal view returns (address) { - return msg.sender; - } - - function _msgSender() internal pure returns (address) { - return address(bytes20(msg.data[msg.data.length - 20:])); - } - - function _msgData() internal pure returns (bytes calldata) { - return msg.data[:msg.data.length - 20]; - } - - function callPayable() public payable { - emit ERC7579FallbackHandlerMockCalled(_msgAccount(), _msgSender(), msg.value, _msgData()); - } - - function callView() public view returns (address, address) { - return (_msgAccount(), _msgSender()); - } - - function callRevert() public pure { - revert ERC7579FallbackHandlerMockRevert(); - } -} - -abstract contract ERC7579ValidatorMock is ERC7579ModuleMock(MODULE_TYPE_VALIDATOR), IERC7579Validator { - mapping(address sender => address signer) private _associatedSigners; - - function onInstall(bytes calldata data) public virtual override(IERC7579Module, ERC7579ModuleMock) { - _associatedSigners[msg.sender] = address(bytes20(data[0:20])); - super.onInstall(data); - } - - function onUninstall(bytes calldata data) public virtual override(IERC7579Module, ERC7579ModuleMock) { - delete _associatedSigners[msg.sender]; - super.onUninstall(data); - } - - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) public view virtual returns (uint256) { - return - SignatureChecker.isValidSignatureNow(_associatedSigners[msg.sender], userOpHash, userOp.signature) - ? ERC4337Utils.SIG_VALIDATION_SUCCESS - : ERC4337Utils.SIG_VALIDATION_FAILED; - } - - function isValidSignatureWithSender( - address /*sender*/, - bytes32 hash, - bytes calldata signature - ) public view virtual returns (bytes4) { - return - SignatureChecker.isValidSignatureNow(_associatedSigners[msg.sender], hash, signature) - ? IERC1271.isValidSignature.selector - : bytes4(0xffffffff); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/utils/ERC7579UtilsMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/utils/ERC7579UtilsMock.sol deleted file mode 100644 index e0a1e1a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/account/utils/ERC7579UtilsMock.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {CallType, ExecType, ModeSelector, ModePayload} from "../../../account/utils/draft-ERC7579Utils.sol"; - -contract ERC7579UtilsGlobalMock { - function eqCallTypeGlobal(CallType callType1, CallType callType2) internal pure returns (bool) { - return callType1 == callType2; - } - - function eqExecTypeGlobal(ExecType execType1, ExecType execType2) internal pure returns (bool) { - return execType1 == execType2; - } - - function eqModeSelectorGlobal(ModeSelector modeSelector1, ModeSelector modeSelector2) internal pure returns (bool) { - return modeSelector1 == modeSelector2; - } - - function eqModePayloadGlobal(ModePayload modePayload1, ModePayload modePayload2) internal pure returns (bool) { - return modePayload1 == modePayload2; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol deleted file mode 100644 index c72ed08..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol +++ /dev/null @@ -1,174 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC20WithAutoMinerReward.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC20WithAutoMinerReward.sol deleted file mode 100644 index 46be532..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC20WithAutoMinerReward.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {ERC20} from "../../token/ERC20/ERC20.sol"; - -contract ERC20WithAutoMinerReward is ERC20 { - constructor() ERC20("Reward", "RWD") { - _mintMinerReward(); - } - - function _mintMinerReward() internal { - _mint(block.coinbase, 1000); - } - - function _update(address from, address to, uint256 value) internal virtual override { - if (!(from == address(0) && to == block.coinbase)) { - _mintMinerReward(); - } - super._update(from, to, value); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC4626Fees.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC4626Fees.sol deleted file mode 100644 index dd49933..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/ERC4626Fees.sol +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {IERC20} from "../../token/ERC20/IERC20.sol"; -import {ERC4626} from "../../token/ERC20/extensions/ERC4626.sol"; -import {SafeERC20} from "../../token/ERC20/utils/SafeERC20.sol"; -import {Math} from "../../utils/math/Math.sol"; - -/// @dev ERC-4626 vault with entry/exit fees expressed in https://en.wikipedia.org/wiki/Basis_point[basis point (bp)]. -/// -/// NOTE: The contract charges fees in terms of assets, not shares. This means that the fees are calculated based on the -/// amount of assets that are being deposited or withdrawn, and not based on the amount of shares that are being minted or -/// redeemed. This is an opinionated design decision that should be taken into account when integrating this contract. -/// -/// WARNING: This contract has not been audited and shouldn't be considered production ready. Consider using it with caution. -abstract contract ERC4626Fees is ERC4626 { - using Math for uint256; - - uint256 private constant _BASIS_POINT_SCALE = 1e4; - - // === Overrides === - - /// @dev Preview taking an entry fee on deposit. See {IERC4626-previewDeposit}. - function previewDeposit(uint256 assets) public view virtual override returns (uint256) { - uint256 fee = _feeOnTotal(assets, _entryFeeBasisPoints()); - return super.previewDeposit(assets - fee); - } - - /// @dev Preview adding an entry fee on mint. See {IERC4626-previewMint}. - function previewMint(uint256 shares) public view virtual override returns (uint256) { - uint256 assets = super.previewMint(shares); - return assets + _feeOnRaw(assets, _entryFeeBasisPoints()); - } - - /// @dev Preview adding an exit fee on withdraw. See {IERC4626-previewWithdraw}. - function previewWithdraw(uint256 assets) public view virtual override returns (uint256) { - uint256 fee = _feeOnRaw(assets, _exitFeeBasisPoints()); - return super.previewWithdraw(assets + fee); - } - - /// @dev Preview taking an exit fee on redeem. See {IERC4626-previewRedeem}. - function previewRedeem(uint256 shares) public view virtual override returns (uint256) { - uint256 assets = super.previewRedeem(shares); - return assets - _feeOnTotal(assets, _exitFeeBasisPoints()); - } - - /// @dev Send entry fee to {_entryFeeRecipient}. See {IERC4626-_deposit}. - function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual override { - uint256 fee = _feeOnTotal(assets, _entryFeeBasisPoints()); - address recipient = _entryFeeRecipient(); - - super._deposit(caller, receiver, assets, shares); - - if (fee > 0 && recipient != address(this)) { - SafeERC20.safeTransfer(IERC20(asset()), recipient, fee); - } - } - - /// @dev Send exit fee to {_exitFeeRecipient}. See {IERC4626-_deposit}. - function _withdraw( - address caller, - address receiver, - address owner, - uint256 assets, - uint256 shares - ) internal virtual override { - uint256 fee = _feeOnRaw(assets, _exitFeeBasisPoints()); - address recipient = _exitFeeRecipient(); - - super._withdraw(caller, receiver, owner, assets, shares); - - if (fee > 0 && recipient != address(this)) { - SafeERC20.safeTransfer(IERC20(asset()), recipient, fee); - } - } - - // === Fee configuration === - - function _entryFeeBasisPoints() internal view virtual returns (uint256) { - return 0; // replace with e.g. 100 for 1% - } - - function _exitFeeBasisPoints() internal view virtual returns (uint256) { - return 0; // replace with e.g. 100 for 1% - } - - function _entryFeeRecipient() internal view virtual returns (address) { - return address(0); // replace with e.g. a treasury address - } - - function _exitFeeRecipient() internal view virtual returns (address) { - return address(0); // replace with e.g. a treasury address - } - - // === Fee operations === - - /// @dev Calculates the fees that should be added to an amount `assets` that does not already include fees. - /// Used in {IERC4626-mint} and {IERC4626-withdraw} operations. - function _feeOnRaw(uint256 assets, uint256 feeBasisPoints) private pure returns (uint256) { - return assets.mulDiv(feeBasisPoints, _BASIS_POINT_SCALE, Math.Rounding.Ceil); - } - - /// @dev Calculates the fee part of an amount `assets` that already includes fees. - /// Used in {IERC4626-deposit} and {IERC4626-redeem} operations. - function _feeOnTotal(uint256 assets, uint256 feeBasisPoints) private pure returns (uint256) { - return assets.mulDiv(feeBasisPoints, feeBasisPoints + _BASIS_POINT_SCALE, Math.Rounding.Ceil); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/MyNFT.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/MyNFT.sol deleted file mode 100644 index 1a442fa..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/MyNFT.sol +++ /dev/null @@ -1,9 +0,0 @@ -// contracts/MyNFT.sol -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {ERC721} from "../../token/ERC721/ERC721.sol"; - -contract MyNFT is ERC721 { - constructor() ERC721("MyNFT", "MNFT") {} -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintBase.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintBase.sol deleted file mode 100644 index 25139cb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintBase.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {AccessControl} from "../../../access/AccessControl.sol"; -import {ERC20} from "../../../token/ERC20/ERC20.sol"; - -contract AccessControlERC20MintBase is ERC20, AccessControl { - // Create a new role identifier for the minter role - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - - error CallerNotMinter(address caller); - - constructor(address minter) ERC20("MyToken", "TKN") { - // Grant the minter role to a specified account - _grantRole(MINTER_ROLE, minter); - } - - function mint(address to, uint256 amount) public { - // Check that the calling account has the minter role - if (!hasRole(MINTER_ROLE, msg.sender)) { - revert CallerNotMinter(msg.sender); - } - _mint(to, amount); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintMissing.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintMissing.sol deleted file mode 100644 index 46002fd..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintMissing.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {AccessControl} from "../../../access/AccessControl.sol"; -import {ERC20} from "../../../token/ERC20/ERC20.sol"; - -contract AccessControlERC20MintMissing is ERC20, AccessControl { - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); - - constructor() ERC20("MyToken", "TKN") { - // Grant the contract deployer the default admin role: it will be able - // to grant and revoke any roles - _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); - } - - function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { - _mint(to, amount); - } - - function burn(address from, uint256 amount) public onlyRole(BURNER_ROLE) { - _burn(from, amount); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintOnlyRole.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintOnlyRole.sol deleted file mode 100644 index a71060a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintOnlyRole.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {AccessControl} from "../../../access/AccessControl.sol"; -import {ERC20} from "../../../token/ERC20/ERC20.sol"; - -contract AccessControlERC20Mint is ERC20, AccessControl { - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); - - constructor(address minter, address burner) ERC20("MyToken", "TKN") { - _grantRole(MINTER_ROLE, minter); - _grantRole(BURNER_ROLE, burner); - } - - function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { - _mint(to, amount); - } - - function burn(address from, uint256 amount) public onlyRole(BURNER_ROLE) { - _burn(from, amount); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlModified.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlModified.sol deleted file mode 100644 index 479fa20..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlModified.sol +++ /dev/null @@ -1,14 +0,0 @@ -// contracts/AccessControlModified.sol -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {AccessControl} from "../../../access/AccessControl.sol"; - -contract AccessControlModified is AccessControl { - error AccessControlNonRevocable(); - - // Override the revokeRole function - function revokeRole(bytes32, address) public pure override { - revert AccessControlNonRevocable(); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessManagedERC20MintBase.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessManagedERC20MintBase.sol deleted file mode 100644 index 02ae00a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessManagedERC20MintBase.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {AccessManaged} from "../../../access/manager/AccessManaged.sol"; -import {ERC20} from "../../../token/ERC20/ERC20.sol"; - -contract AccessManagedERC20Mint is ERC20, AccessManaged { - constructor(address manager) ERC20("MyToken", "TKN") AccessManaged(manager) {} - - // Minting is restricted according to the manager rules for this function. - // The function is identified by its selector: 0x40c10f19. - // Calculated with bytes4(keccak256('mint(address,uint256)')) - function mint(address to, uint256 amount) public restricted { - _mint(to, amount); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/MyContractOwnable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/MyContractOwnable.sol deleted file mode 100644 index 0dfc804..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/access-control/MyContractOwnable.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {Ownable} from "../../../access/Ownable.sol"; - -contract MyContract is Ownable { - constructor(address initialOwner) Ownable(initialOwner) {} - - function normalThing() public { - // anyone can call this normalThing() - } - - function specialThing() public onlyOwner { - // only the owner can call specialThing()! - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyAccountERC7702.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyAccountERC7702.sol deleted file mode 100644 index a2f2ca4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyAccountERC7702.sol +++ /dev/null @@ -1,20 +0,0 @@ -// contracts/MyAccountERC7702.sol -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {Account} from "../../../account/Account.sol"; -import {ERC721Holder} from "../../../token/ERC721/utils/ERC721Holder.sol"; -import {ERC1155Holder} from "../../../token/ERC1155/utils/ERC1155Holder.sol"; -import {ERC7821} from "../../../account/extensions/draft-ERC7821.sol"; -import {SignerERC7702} from "../../../utils/cryptography/signers/SignerERC7702.sol"; - -contract MyAccountERC7702 is Account, SignerERC7702, ERC7821, ERC721Holder, ERC1155Holder { - /// @dev Allows the entry point as an authorized executor. - function _erc7821AuthorizedExecutor( - address caller, - bytes32 mode, - bytes calldata executionData - ) internal view virtual override returns (bool) { - return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyFactoryAccount.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyFactoryAccount.sol deleted file mode 100644 index 3db3a25..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/account/MyFactoryAccount.sol +++ /dev/null @@ -1,37 +0,0 @@ -// contracts/MyFactoryAccount.sol -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {Clones} from "../../../proxy/Clones.sol"; -import {Address} from "../../../utils/Address.sol"; - -/** - * @dev A factory contract to create accounts on demand. - */ -contract MyFactoryAccount { - using Clones for address; - using Address for address; - - address private immutable _impl; - - constructor(address impl_) { - require(impl_.code.length > 0); - _impl = impl_; - } - - /// @dev Predict the address of the account - function predictAddress(bytes calldata callData) public view returns (address) { - return _impl.predictDeterministicAddress(keccak256(callData), address(this)); - } - - /// @dev Create clone accounts on demand - function cloneAndInitialize(bytes calldata callData) public returns (address) { - address predicted = predictAddress(callData); - if (predicted.code.length == 0) { - _impl.cloneDeterministic(keccak256(callData)); - predicted.functionCall(callData); - } - return predicted; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyGovernor.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyGovernor.sol deleted file mode 100644 index 4d38d0f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyGovernor.sol +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.24; - -import {Governor} from "../../../governance/Governor.sol"; -import {GovernorCountingSimple} from "../../../governance/extensions/GovernorCountingSimple.sol"; -import {GovernorVotes} from "../../../governance/extensions/GovernorVotes.sol"; -import {GovernorVotesQuorumFraction} from "../../../governance/extensions/GovernorVotesQuorumFraction.sol"; -import {GovernorTimelockControl} from "../../../governance/extensions/GovernorTimelockControl.sol"; -import {TimelockController} from "../../../governance/TimelockController.sol"; -import {IVotes} from "../../../governance/utils/IVotes.sol"; - -contract MyGovernor is - Governor, - GovernorCountingSimple, - GovernorVotes, - GovernorVotesQuorumFraction, - GovernorTimelockControl -{ - constructor( - IVotes _token, - TimelockController _timelock - ) Governor("MyGovernor") GovernorVotes(_token) GovernorVotesQuorumFraction(4) GovernorTimelockControl(_timelock) {} - - function votingDelay() public pure override returns (uint256) { - return 7200; // 1 day - } - - function votingPeriod() public pure override returns (uint256) { - return 50400; // 1 week - } - - function proposalThreshold() public pure override returns (uint256) { - return 0; - } - - // The functions below are overrides required by Solidity. - - function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) { - return super.state(proposalId); - } - - 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(); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyToken.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyToken.sol deleted file mode 100644 index cfb1675..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyToken.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {ERC20} from "../../../token/ERC20/ERC20.sol"; -import {ERC20Permit} from "../../../token/ERC20/extensions/ERC20Permit.sol"; -import {ERC20Votes} from "../../../token/ERC20/extensions/ERC20Votes.sol"; -import {Nonces} from "../../../utils/Nonces.sol"; - -contract MyToken is ERC20, ERC20Permit, ERC20Votes { - constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {} - - // The functions below are overrides required by Solidity. - - function _update(address from, address to, uint256 amount) internal override(ERC20, ERC20Votes) { - super._update(from, to, amount); - } - - function nonces(address owner) public view virtual override(ERC20Permit, Nonces) returns (uint256) { - return super.nonces(owner); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenTimestampBased.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenTimestampBased.sol deleted file mode 100644 index 7c0d329..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenTimestampBased.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {ERC20} from "../../../token/ERC20/ERC20.sol"; -import {ERC20Permit} from "../../../token/ERC20/extensions/ERC20Permit.sol"; -import {ERC20Votes} from "../../../token/ERC20/extensions/ERC20Votes.sol"; -import {Nonces} from "../../../utils/Nonces.sol"; - -contract MyTokenTimestampBased is ERC20, ERC20Permit, ERC20Votes { - constructor() ERC20("MyTokenTimestampBased", "MTK") ERC20Permit("MyTokenTimestampBased") {} - - // Overrides IERC6372 functions to make the token & governor timestamp-based - - function clock() public view override returns (uint48) { - return uint48(block.timestamp); - } - - // solhint-disable-next-line func-name-mixedcase - function CLOCK_MODE() public pure override returns (string memory) { - return "mode=timestamp"; - } - - // The functions below are overrides required by Solidity. - - function _update(address from, address to, uint256 amount) internal override(ERC20, ERC20Votes) { - super._update(from, to, amount); - } - - function nonces(address owner) public view virtual override(ERC20Permit, Nonces) returns (uint256) { - return super.nonces(owner); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenWrapped.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenWrapped.sol deleted file mode 100644 index c9d567d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenWrapped.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {IERC20, ERC20} from "../../../token/ERC20/ERC20.sol"; -import {ERC20Permit} from "../../../token/ERC20/extensions/ERC20Permit.sol"; -import {ERC20Votes} from "../../../token/ERC20/extensions/ERC20Votes.sol"; -import {ERC20Wrapper} from "../../../token/ERC20/extensions/ERC20Wrapper.sol"; -import {Nonces} from "../../../utils/Nonces.sol"; - -contract MyTokenWrapped is ERC20, ERC20Permit, ERC20Votes, ERC20Wrapper { - constructor( - IERC20 wrappedToken - ) ERC20("MyTokenWrapped", "MTK") ERC20Permit("MyTokenWrapped") ERC20Wrapper(wrappedToken) {} - - // The functions below are overrides required by Solidity. - - function decimals() public view override(ERC20, ERC20Wrapper) returns (uint8) { - return super.decimals(); - } - - function _update(address from, address to, uint256 amount) internal override(ERC20, ERC20Votes) { - super._update(from, to, amount); - } - - function nonces(address owner) public view virtual override(ERC20Permit, Nonces) returns (uint256) { - return super.nonces(owner); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/GameItems.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/GameItems.sol deleted file mode 100644 index e84fc0b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/GameItems.sol +++ /dev/null @@ -1,21 +0,0 @@ -// contracts/GameItems.sol -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {ERC1155} from "../../../../token/ERC1155/ERC1155.sol"; - -contract GameItems is ERC1155 { - uint256 public constant GOLD = 0; - uint256 public constant SILVER = 1; - uint256 public constant THORS_HAMMER = 2; - uint256 public constant SWORD = 3; - uint256 public constant SHIELD = 4; - - constructor() ERC1155("https://game.example/api/item/{id}.json") { - _mint(msg.sender, GOLD, 10 ** 18, ""); - _mint(msg.sender, SILVER, 10 ** 27, ""); - _mint(msg.sender, THORS_HAMMER, 1, ""); - _mint(msg.sender, SWORD, 10 ** 9, ""); - _mint(msg.sender, SHIELD, 10 ** 9, ""); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/MyERC115HolderContract.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/MyERC115HolderContract.sol deleted file mode 100644 index 742a53b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/MyERC115HolderContract.sol +++ /dev/null @@ -1,7 +0,0 @@ -// contracts/MyERC115HolderContract.sol -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {ERC1155Holder} from "../../../../token/ERC1155/utils/ERC1155Holder.sol"; - -contract MyERC115HolderContract is ERC1155Holder {} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC20/GLDToken.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC20/GLDToken.sol deleted file mode 100644 index b6c5454..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC20/GLDToken.sol +++ /dev/null @@ -1,11 +0,0 @@ -// contracts/GLDToken.sol -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {ERC20} from "../../../../token/ERC20/ERC20.sol"; - -contract GLDToken is ERC20 { - constructor(uint256 initialSupply) ERC20("Gold", "GLD") { - _mint(msg.sender, initialSupply); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC6909/ERC6909GameItems.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC6909/ERC6909GameItems.sol deleted file mode 100644 index 611e1dd..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC6909/ERC6909GameItems.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {ERC6909Metadata} from "../../../../token/ERC6909/extensions/draft-ERC6909Metadata.sol"; - -contract ERC6909GameItems is ERC6909Metadata { - uint256 public constant GOLD = 0; - uint256 public constant SILVER = 1; - uint256 public constant THORS_HAMMER = 2; - uint256 public constant SWORD = 3; - uint256 public constant SHIELD = 4; - - constructor() { - _setDecimals(GOLD, 18); - _setDecimals(SILVER, 18); - // Default decimals is 0 - _setDecimals(SWORD, 9); - _setDecimals(SHIELD, 9); - - _mint(msg.sender, GOLD, 10 ** 18); - _mint(msg.sender, SILVER, 10_000 ** 18); - _mint(msg.sender, THORS_HAMMER, 1); - _mint(msg.sender, SWORD, 10 ** 9); - _mint(msg.sender, SHIELD, 10 ** 9); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC721/GameItem.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC721/GameItem.sol deleted file mode 100644 index b7f576f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/token/ERC721/GameItem.sol +++ /dev/null @@ -1,19 +0,0 @@ -// contracts/GameItem.sol -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {ERC721URIStorage, ERC721} from "../../../../token/ERC721/extensions/ERC721URIStorage.sol"; - -contract GameItem is ERC721URIStorage { - uint256 private _nextTokenId; - - constructor() ERC721("GameItem", "ITM") {} - - function awardItem(address player, string memory tokenURI) public returns (uint256) { - uint256 tokenId = _nextTokenId++; - _mint(player, tokenId); - _setTokenURI(tokenId, tokenURI); - - return tokenId; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Base64NFT.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Base64NFT.sol deleted file mode 100644 index 1fb6623..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Base64NFT.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {ERC721} from "../../../token/ERC721/ERC721.sol"; -import {Strings} from "../../../utils/Strings.sol"; -import {Base64} from "../../../utils/Base64.sol"; - -contract Base64NFT is ERC721 { - using Strings for uint256; - - constructor() ERC721("Base64NFT", "MTK") {} - - // ... - - function tokenURI(uint256 tokenId) public pure override returns (string memory) { - // Equivalent to: - // { - // "name": "Base64NFT #1", - // // Replace with extra ERC-721 Metadata properties - // } - // prettier-ignore - string memory dataURI = string.concat("{\"name\": \"Base64NFT #", tokenId.toString(), "\"}"); - - return string.concat("data:application/json;base64,", Base64.encode(bytes(dataURI))); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Multicall.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Multicall.sol deleted file mode 100644 index 6faac6a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/docs/utilities/Multicall.sol +++ /dev/null @@ -1,15 +0,0 @@ -// contracts/Box.sol -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {Multicall} from "../../../utils/Multicall.sol"; - -contract Box is Multicall { - function foo() public { - // ... - } - - function bar() public { - // ... - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCountingOverridableMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCountingOverridableMock.sol deleted file mode 100644 index 063cc36..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCountingOverridableMock.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -import {Governor} from "../../governance/Governor.sol"; -import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; -import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; -import {GovernorCountingOverridable} from "../../governance/extensions/GovernorCountingOverridable.sol"; - -abstract contract GovernorCountingOverridableMock is - GovernorSettings, - GovernorVotesQuorumFraction, - GovernorCountingOverridable -{ - function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { - return super.proposalThreshold(); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorFractionalMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorFractionalMock.sol deleted file mode 100644 index ae8a2c1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorFractionalMock.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -import {Governor} from "../../governance/Governor.sol"; -import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; -import {GovernorCountingFractional} from "../../governance/extensions/GovernorCountingFractional.sol"; -import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; - -abstract contract GovernorFractionalMock is GovernorSettings, GovernorVotesQuorumFraction, GovernorCountingFractional { - function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { - return super.proposalThreshold(); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol deleted file mode 100644 index 867eccf..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorNoncesKeyedMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorNoncesKeyedMock.sol deleted file mode 100644 index 91021cc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorNoncesKeyedMock.sol +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -import {Governor, Nonces} 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"; -import {GovernorProposalGuardian} from "../../governance/extensions/GovernorProposalGuardian.sol"; -import {GovernorNoncesKeyed} from "../../governance/extensions/GovernorNoncesKeyed.sol"; - -abstract contract GovernorNoncesKeyedMock is - GovernorSettings, - GovernorVotesQuorumFraction, - GovernorCountingSimple, - GovernorNoncesKeyed -{ - function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { - return super.proposalThreshold(); - } - - function _validateVoteSig( - uint256 proposalId, - uint8 support, - address voter, - bytes memory signature - ) internal virtual override(Governor, GovernorNoncesKeyed) returns (bool) { - return super._validateVoteSig(proposalId, support, voter, signature); - } - - function _validateExtendedVoteSig( - uint256 proposalId, - uint8 support, - address voter, - string memory reason, - bytes memory params, - bytes memory signature - ) internal virtual override(Governor, GovernorNoncesKeyed) returns (bool) { - return super._validateExtendedVoteSig(proposalId, support, voter, reason, params, signature); - } - - function _useCheckedNonce(address owner, uint256 nonce) internal virtual override(Nonces, GovernorNoncesKeyed) { - super._useCheckedNonce(owner, nonce); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol deleted file mode 100644 index e403d17..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -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 _tallyUpdated(uint256 proposalId) internal override(Governor, GovernorPreventLateQuorum) { - super._tallyUpdated(proposalId); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorProposalGuardianMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorProposalGuardianMock.sol deleted file mode 100644 index 01e2f0a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorProposalGuardianMock.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -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"; -import {GovernorProposalGuardian} from "../../governance/extensions/GovernorProposalGuardian.sol"; - -abstract contract GovernorProposalGuardianMock is - GovernorSettings, - GovernorVotesQuorumFraction, - GovernorCountingSimple, - GovernorProposalGuardian -{ - function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { - return super.proposalThreshold(); - } - - function _validateCancel( - uint256 proposalId, - address caller - ) internal view override(Governor, GovernorProposalGuardian) returns (bool) { - return super._validateCancel(proposalId, caller); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSequentialProposalIdMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSequentialProposalIdMock.sol deleted file mode 100644 index 0bd86dc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSequentialProposalIdMock.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -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"; -import {GovernorSequentialProposalId} from "../../governance/extensions/GovernorSequentialProposalId.sol"; - -abstract contract GovernorSequentialProposalIdMock is - GovernorSettings, - GovernorVotesQuorumFraction, - GovernorCountingSimple, - GovernorSequentialProposalId -{ - function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { - return super.proposalThreshold(); - } - - function getProposalId( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) public view virtual override(Governor, GovernorSequentialProposalId) returns (uint256) { - return super.getProposalId(targets, values, calldatas, descriptionHash); - } - - function _propose( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - string memory description, - address proposer - ) internal virtual override(Governor, GovernorSequentialProposalId) returns (uint256 proposalId) { - return super._propose(targets, values, calldatas, description, proposer); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorStorageMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorStorageMock.sol deleted file mode 100644 index 9b2178e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorStorageMock.sol +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -import {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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSuperQuorumMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSuperQuorumMock.sol deleted file mode 100644 index 72e8f16..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorSuperQuorumMock.sol +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -import {Governor} from "../../governance/Governor.sol"; -import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; -import {GovernorVotes} from "../../governance/extensions/GovernorVotes.sol"; -import {GovernorSuperQuorum} from "../../governance/extensions/GovernorSuperQuorum.sol"; -import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; -import {GovernorTimelockControl} from "../../governance/extensions/GovernorTimelockControl.sol"; - -abstract contract GovernorSuperQuorumMock is - GovernorSettings, - GovernorVotes, - GovernorTimelockControl, - GovernorSuperQuorum, - GovernorCountingSimple -{ - uint256 private _quorum; - uint256 private _superQuorum; - - constructor(uint256 quorum_, uint256 superQuorum_) { - _quorum = quorum_; - _superQuorum = superQuorum_; - } - - function quorum(uint256) public view override returns (uint256) { - return _quorum; - } - - function superQuorum(uint256) public view override returns (uint256) { - return _superQuorum; - } - - function state( - uint256 proposalId - ) public view override(Governor, GovernorSuperQuorum, GovernorTimelockControl) returns (ProposalState) { - return super.state(proposalId); - } - - function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { - return super.proposalThreshold(); - } - - function proposalVotes( - uint256 proposalId - ) - public - view - virtual - override(GovernorCountingSimple, GovernorSuperQuorum) - returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) - { - return super.proposalVotes(proposalId); - } - - 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 _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 _executor() internal view override(Governor, GovernorTimelockControl) returns (address) { - return super._executor(); - } - - 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 proposalNeedsQueuing( - uint256 proposalId - ) public view override(Governor, GovernorTimelockControl) returns (bool) { - return super.proposalNeedsQueuing(proposalId); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockAccessMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockAccessMock.sol deleted file mode 100644 index 64ad64b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockAccessMock.sol +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -import {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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol deleted file mode 100644 index 71508cd..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -import {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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol deleted file mode 100644 index 0ff6fdf..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -import {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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol deleted file mode 100644 index ea699a3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVotesSuperQuorumFractionMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVotesSuperQuorumFractionMock.sol deleted file mode 100644 index 1f4282e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVotesSuperQuorumFractionMock.sol +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -import {Governor} from "../../governance/Governor.sol"; -import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; -import {GovernorSuperQuorum} from "../../governance/extensions/GovernorSuperQuorum.sol"; -import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; -import {GovernorVotesSuperQuorumFraction} from "../../governance/extensions/GovernorVotesSuperQuorumFraction.sol"; - -abstract contract GovernorVotesSuperQuorumFractionMock is - GovernorSettings, - GovernorVotesSuperQuorumFraction, - GovernorCountingSimple -{ - function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { - return super.proposalThreshold(); - } - - function proposalVotes( - uint256 proposalId - ) - public - view - virtual - override(GovernorCountingSimple, GovernorSuperQuorum) - returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) - { - return super.proposalVotes(proposalId); - } - - function state( - uint256 proposalId - ) public view override(Governor, GovernorVotesSuperQuorumFraction) returns (ProposalState) { - return super.state(proposalId); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol deleted file mode 100644 index 6c31c99..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -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) returns (uint256) { - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol deleted file mode 100644 index f3153a8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol +++ /dev/null @@ -1,11 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol deleted file mode 100644 index 43d5a34..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol +++ /dev/null @@ -1,19 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol deleted file mode 100644 index 8c5641e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.22; - -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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol deleted file mode 100644 index 2a85d1d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol +++ /dev/null @@ -1,74 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ForceApproveMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ForceApproveMock.sol deleted file mode 100644 index 6bd957e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ForceApproveMock.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {ERC1363} from "../../token/ERC20/extensions/ERC1363.sol"; - -// contract that replicate USDT approval behavior in approveAndCall -abstract contract ERC1363ForceApproveMock is ERC1363 { - function approveAndCall(address spender, uint256 amount, bytes memory data) public virtual override returns (bool) { - require(amount == 0 || allowance(msg.sender, spender) == 0, "USDT approval failure"); - return super.approveAndCall(spender, amount, data); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363NoReturnMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363NoReturnMock.sol deleted file mode 100644 index 45136ed..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363NoReturnMock.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {ERC1363} from "../../token/ERC20/extensions/ERC1363.sol"; - -abstract contract ERC1363NoReturnMock is ERC1363 { - function transferAndCall(address to, uint256 value, bytes memory data) public override returns (bool) { - super.transferAndCall(to, value, data); - assembly { - return(0, 0) - } - } - - function transferFromAndCall( - address from, - address to, - uint256 value, - bytes memory data - ) public override returns (bool) { - super.transferFromAndCall(from, to, value, data); - assembly { - return(0, 0) - } - } - - function approveAndCall(address spender, uint256 value, bytes memory data) public override returns (bool) { - super.approveAndCall(spender, value, data); - assembly { - return(0, 0) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReceiverMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReceiverMock.sol deleted file mode 100644 index d33e05e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReceiverMock.sol +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {IERC1363Receiver} from "../../interfaces/IERC1363Receiver.sol"; - -contract ERC1363ReceiverMock is IERC1363Receiver { - enum RevertType { - None, - RevertWithoutMessage, - RevertWithMessage, - RevertWithCustomError, - Panic - } - - bytes4 private _retval; - RevertType private _error; - - event Received(address operator, address from, uint256 value, bytes data); - error CustomError(bytes4); - - constructor() { - _retval = IERC1363Receiver.onTransferReceived.selector; - _error = RevertType.None; - } - - function setUp(bytes4 retval, RevertType error) public { - _retval = retval; - _error = error; - } - - function onTransferReceived( - address operator, - address from, - uint256 value, - bytes calldata data - ) external override returns (bytes4) { - if (_error == RevertType.RevertWithoutMessage) { - revert(); - } else if (_error == RevertType.RevertWithMessage) { - revert("ERC1363ReceiverMock: 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, value, data); - return _retval; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReturnFalseMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReturnFalseMock.sol deleted file mode 100644 index afdd01f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReturnFalseMock.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {IERC20, ERC20} from "../../token/ERC20/ERC20.sol"; -import {ERC1363} from "../../token/ERC20/extensions/ERC1363.sol"; - -abstract contract ERC1363ReturnFalseOnERC20Mock is ERC1363 { - function transfer(address, uint256) public pure override(IERC20, ERC20) returns (bool) { - return false; - } - - function transferFrom(address, address, uint256) public pure override(IERC20, ERC20) returns (bool) { - return false; - } - - function approve(address, uint256) public pure override(IERC20, ERC20) returns (bool) { - return false; - } -} - -abstract contract ERC1363ReturnFalseMock is ERC1363 { - function transferAndCall(address, uint256, bytes memory) public pure override returns (bool) { - return false; - } - - function transferFromAndCall(address, address, uint256, bytes memory) public pure override returns (bool) { - return false; - } - - function approveAndCall(address, uint256, bytes memory) public pure override returns (bool) { - return false; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363SpenderMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363SpenderMock.sol deleted file mode 100644 index b12c4c1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC1363SpenderMock.sol +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {IERC1363Spender} from "../../interfaces/IERC1363Spender.sol"; - -contract ERC1363SpenderMock is IERC1363Spender { - enum RevertType { - None, - RevertWithoutMessage, - RevertWithMessage, - RevertWithCustomError, - Panic - } - - bytes4 private _retval; - RevertType private _error; - - event Approved(address owner, uint256 value, bytes data); - error CustomError(bytes4); - - constructor() { - _retval = IERC1363Spender.onApprovalReceived.selector; - _error = RevertType.None; - } - - function setUp(bytes4 retval, RevertType error) public { - _retval = retval; - _error = error; - } - - function onApprovalReceived(address owner, uint256 value, bytes calldata data) external override returns (bytes4) { - if (_error == RevertType.RevertWithoutMessage) { - revert(); - } else if (_error == RevertType.RevertWithMessage) { - revert("ERC1363SpenderMock: reverting"); - } else if (_error == RevertType.RevertWithCustomError) { - revert CustomError(_retval); - } else if (_error == RevertType.Panic) { - uint256 a = uint256(0) / uint256(0); - a; - } - - emit Approved(owner, value, data); - return _retval; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ApprovalMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ApprovalMock.sol deleted file mode 100644 index ff33a36..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ApprovalMock.sol +++ /dev/null @@ -1,10 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20BridgeableMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20BridgeableMock.sol deleted file mode 100644 index 6249cb6..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20BridgeableMock.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {ERC20, ERC20Bridgeable} from "../../token/ERC20/extensions/draft-ERC20Bridgeable.sol"; - -abstract contract ERC20BridgeableMock is ERC20Bridgeable { - address private _bridge; - - error OnlyTokenBridge(); - event OnlyTokenBridgeFnCalled(address caller); - - constructor(address bridge) { - _bridge = bridge; - } - - function onlyTokenBridgeFn() external onlyTokenBridge { - emit OnlyTokenBridgeFnCalled(msg.sender); - } - - function _checkTokenBridge(address sender) internal view override { - if (sender != _bridge) { - revert OnlyTokenBridge(); - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol deleted file mode 100644 index a26e1f5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol +++ /dev/null @@ -1,17 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ExcessDecimalsMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ExcessDecimalsMock.sol deleted file mode 100644 index 4627efd..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ExcessDecimalsMock.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -contract ERC20ExcessDecimalsMock { - function decimals() public pure returns (uint256) { - return type(uint256).max; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol deleted file mode 100644 index 508573c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol +++ /dev/null @@ -1,26 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ForceApproveMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ForceApproveMock.sol deleted file mode 100644 index aecfb9e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ForceApproveMock.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {ERC20} from "../../token/ERC20/ERC20.sol"; - -// contract that replicates 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20GetterHelper.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20GetterHelper.sol deleted file mode 100644 index acdcced..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20GetterHelper.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {IERC20} from "../../token/ERC20/IERC20.sol"; -import {IERC20Metadata} from "../../token/ERC20/extensions/IERC20Metadata.sol"; - -contract ERC20GetterHelper { - event ERC20TotalSupply(IERC20 token, uint256 totalSupply); - event ERC20BalanceOf(IERC20 token, address account, uint256 balanceOf); - event ERC20Allowance(IERC20 token, address owner, address spender, uint256 allowance); - event ERC20Name(IERC20Metadata token, string name); - event ERC20Symbol(IERC20Metadata token, string symbol); - event ERC20Decimals(IERC20Metadata token, uint8 decimals); - - function totalSupply(IERC20 token) external { - emit ERC20TotalSupply(token, token.totalSupply()); - } - - function balanceOf(IERC20 token, address account) external { - emit ERC20BalanceOf(token, account, token.balanceOf(account)); - } - - function allowance(IERC20 token, address owner, address spender) external { - emit ERC20Allowance(token, owner, spender, token.allowance(owner, spender)); - } - - function name(IERC20Metadata token) external { - emit ERC20Name(token, token.name()); - } - - function symbol(IERC20Metadata token) external { - emit ERC20Symbol(token, token.symbol()); - } - - function decimals(IERC20Metadata token) external { - emit ERC20Decimals(token, token.decimals()); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol deleted file mode 100644 index 39ab129..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol +++ /dev/null @@ -1,16 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol deleted file mode 100644 index dce3e70..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol +++ /dev/null @@ -1,8 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol deleted file mode 100644 index 2129537..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol +++ /dev/null @@ -1,28 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Reentrant.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Reentrant.sol deleted file mode 100644 index 813913f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Reentrant.sol +++ /dev/null @@ -1,39 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol deleted file mode 100644 index 94bff32..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol +++ /dev/null @@ -1,19 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesAdditionalCheckpointsMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesAdditionalCheckpointsMock.sol deleted file mode 100644 index 39b3c65..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesAdditionalCheckpointsMock.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {ERC20Votes} from "../../token/ERC20/extensions/ERC20Votes.sol"; -import {VotesExtended, Votes} from "../../governance/utils/VotesExtended.sol"; -import {SafeCast} from "../../utils/math/SafeCast.sol"; - -abstract contract ERC20VotesExtendedMock is ERC20Votes, VotesExtended { - function _delegate(address account, address delegatee) internal virtual override(Votes, VotesExtended) { - return super._delegate(account, delegatee); - } - - function _transferVotingUnits( - address from, - address to, - uint256 amount - ) internal virtual override(Votes, VotesExtended) { - return super._transferVotingUnits(from, to, amount); - } -} - -abstract contract ERC20VotesExtendedTimestampMock is ERC20VotesExtendedMock { - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sol deleted file mode 100644 index 3246fd4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sol +++ /dev/null @@ -1,253 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesTimestampMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesTimestampMock.sol deleted file mode 100644 index 78fdfae..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesTimestampMock.sol +++ /dev/null @@ -1,29 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626LimitsMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626LimitsMock.sol deleted file mode 100644 index a845365..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626LimitsMock.sol +++ /dev/null @@ -1,23 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626Mock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626Mock.sol deleted file mode 100644 index 22ac5e8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626Mock.sol +++ /dev/null @@ -1,17 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sol deleted file mode 100644 index 3dde095..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sol +++ /dev/null @@ -1,17 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4646FeesMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4646FeesMock.sol deleted file mode 100644 index 368b078..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC4646FeesMock.sol +++ /dev/null @@ -1,40 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol deleted file mode 100644 index 7732ae4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol +++ /dev/null @@ -1,42 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol deleted file mode 100644 index 1098647..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol +++ /dev/null @@ -1,61 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol deleted file mode 100644 index 14120f5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol +++ /dev/null @@ -1,47 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol deleted file mode 100644 index 254435e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol +++ /dev/null @@ -1,17 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/utils/cryptography/ERC7739Mock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/utils/cryptography/ERC7739Mock.sol deleted file mode 100644 index c803a40..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/mocks/utils/cryptography/ERC7739Mock.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {ECDSA} from "../../../utils/cryptography/ECDSA.sol"; -import {ERC7739} from "../../../utils/cryptography/signers/draft-ERC7739.sol"; -import {SignerECDSA} from "../../../utils/cryptography/signers/SignerECDSA.sol"; -import {SignerP256} from "../../../utils/cryptography/signers/SignerP256.sol"; -import {SignerRSA} from "../../../utils/cryptography/signers/SignerRSA.sol"; - -abstract contract ERC7739ECDSAMock is ERC7739, SignerECDSA {} -abstract contract ERC7739P256Mock is ERC7739, SignerP256 {} -abstract contract ERC7739RSAMock is ERC7739, SignerRSA {} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/package.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/package.json deleted file mode 100644 index 8ccb946..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "@openzeppelin/contracts", - "description": "Secure Smart Contract library for Solidity", - "version": "5.4.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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Clones.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Clones.sol deleted file mode 100644 index 1eb71b7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Clones.sol +++ /dev/null @@ -1,294 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (proxy/Clones.sol) - -pragma solidity ^0.8.20; - -import {Create2} from "../utils/Create2.sol"; -import {Errors} from "../utils/Errors.sol"; - -/** - * @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-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 { - error CloneArgumentsTooLong(); - - /** - * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation`. - * - * This function uses the create opcode, which should never revert. - * - * WARNING: This function does not check if `implementation` has code. A clone that points to an address - * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they - * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. - */ - function clone(address implementation) internal returns (address instance) { - return clone(implementation, 0); - } - - /** - * @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency - * to the new contract. - * - * WARNING: This function does not check if `implementation` has code. A clone that points to an address - * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they - * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. - * - * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory) - * to always have enough balance for new deployments. Consider exposing this function under a payable method. - */ - function clone(address implementation, uint256 value) internal returns (address instance) { - if (address(this).balance < value) { - revert Errors.InsufficientBalance(address(this).balance, value); - } - assembly ("memory-safe") { - // 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(value, 0x09, 0x37) - } - if (instance == address(0)) { - revert Errors.FailedDeployment(); - } - } - - /** - * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation`. - * - * This function uses the create2 opcode and a `salt` to deterministically deploy - * the clone. Using the same `implementation` and `salt` multiple times will revert, since - * the clones cannot be deployed twice at the same address. - * - * WARNING: This function does not check if `implementation` has code. A clone that points to an address - * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they - * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. - */ - function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { - return cloneDeterministic(implementation, salt, 0); - } - - /** - * @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with - * a `value` parameter to send native currency to the new contract. - * - * WARNING: This function does not check if `implementation` has code. A clone that points to an address - * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they - * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. - * - * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory) - * to always have enough balance for new deployments. Consider exposing this function under a payable method. - */ - function cloneDeterministic( - address implementation, - bytes32 salt, - uint256 value - ) internal returns (address instance) { - if (address(this).balance < value) { - revert Errors.InsufficientBalance(address(this).balance, value); - } - assembly ("memory-safe") { - // 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(value, 0x09, 0x37, salt) - } - if (instance == address(0)) { - revert Errors.FailedDeployment(); - } - } - - /** - * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. - */ - function predictDeterministicAddress( - address implementation, - bytes32 salt, - address deployer - ) internal pure returns (address predicted) { - assembly ("memory-safe") { - 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 := and(keccak256(add(ptr, 0x43), 0x55), 0xffffffffffffffffffffffffffffffffffffffff) - } - } - - /** - * @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)); - } - - /** - * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom - * immutable arguments. These are provided through `args` and cannot be changed after deployment. To - * access the arguments within the implementation, use {fetchCloneArgs}. - * - * This function uses the create opcode, which should never revert. - * - * WARNING: This function does not check if `implementation` has code. A clone that points to an address - * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they - * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. - */ - function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance) { - return cloneWithImmutableArgs(implementation, args, 0); - } - - /** - * @dev Same as {xref-Clones-cloneWithImmutableArgs-address-bytes-}[cloneWithImmutableArgs], but with a `value` - * parameter to send native currency to the new contract. - * - * WARNING: This function does not check if `implementation` has code. A clone that points to an address - * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they - * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. - * - * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory) - * to always have enough balance for new deployments. Consider exposing this function under a payable method. - */ - function cloneWithImmutableArgs( - address implementation, - bytes memory args, - uint256 value - ) internal returns (address instance) { - if (address(this).balance < value) { - revert Errors.InsufficientBalance(address(this).balance, value); - } - bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args); - assembly ("memory-safe") { - instance := create(value, add(bytecode, 0x20), mload(bytecode)) - } - if (instance == address(0)) { - revert Errors.FailedDeployment(); - } - } - - /** - * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom - * immutable arguments. These are provided through `args` and cannot be changed after deployment. To - * access the arguments within the implementation, use {fetchCloneArgs}. - * - * This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same - * `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice - * at the same address. - * - * WARNING: This function does not check if `implementation` has code. A clone that points to an address - * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they - * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. - */ - function cloneDeterministicWithImmutableArgs( - address implementation, - bytes memory args, - bytes32 salt - ) internal returns (address instance) { - return cloneDeterministicWithImmutableArgs(implementation, args, salt, 0); - } - - /** - * @dev Same as {xref-Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-}[cloneDeterministicWithImmutableArgs], - * but with a `value` parameter to send native currency to the new contract. - * - * WARNING: This function does not check if `implementation` has code. A clone that points to an address - * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they - * have no effect and leave the clone uninitialized, allowing a third party to initialize it later. - * - * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory) - * to always have enough balance for new deployments. Consider exposing this function under a payable method. - */ - function cloneDeterministicWithImmutableArgs( - address implementation, - bytes memory args, - bytes32 salt, - uint256 value - ) internal returns (address instance) { - bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args); - return Create2.deploy(value, salt, bytecode); - } - - /** - * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}. - */ - function predictDeterministicAddressWithImmutableArgs( - address implementation, - bytes memory args, - bytes32 salt, - address deployer - ) internal pure returns (address predicted) { - bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args); - return Create2.computeAddress(salt, keccak256(bytecode), deployer); - } - - /** - * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}. - */ - function predictDeterministicAddressWithImmutableArgs( - address implementation, - bytes memory args, - bytes32 salt - ) internal view returns (address predicted) { - return predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this)); - } - - /** - * @dev Get the immutable args attached to a clone. - * - * - If `instance` is a clone that was deployed using `clone` or `cloneDeterministic`, this - * function will return an empty array. - * - If `instance` is a clone that was deployed using `cloneWithImmutableArgs` or - * `cloneDeterministicWithImmutableArgs`, this function will return the args array used at - * creation. - * - If `instance` is NOT a clone deployed using this library, the behavior is undefined. This - * function should only be used to check addresses that are known to be clones. - */ - function fetchCloneArgs(address instance) internal view returns (bytes memory) { - bytes memory result = new bytes(instance.code.length - 45); // revert if length is too short - assembly ("memory-safe") { - extcodecopy(instance, add(result, 32), 45, mload(result)) - } - return result; - } - - /** - * @dev Helper that prepares the initcode of the proxy with immutable args. - * - * An assembly variant of this function requires copying the `args` array, which can be efficiently done using - * `mcopy`. Unfortunately, that opcode is not available before cancun. A pure solidity implementation using - * abi.encodePacked is more expensive but also more portable and easier to review. - * - * NOTE: https://eips.ethereum.org/EIPS/eip-170[EIP-170] limits the length of the contract code to 24576 bytes. - * With the proxy code taking 45 bytes, that limits the length of the immutable args to 24531 bytes. - */ - function _cloneCodeWithImmutableArgs( - address implementation, - bytes memory args - ) private pure returns (bytes memory) { - if (args.length > 24531) revert CloneArgumentsTooLong(); - return - abi.encodePacked( - hex"61", - uint16(args.length + 45), - hex"3d81600a3d39f3363d3d373d3d3d363d73", - implementation, - hex"5af43d82803e903d91602b57fd5bf3", - args - ); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol deleted file mode 100644 index eb482f6..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Proxy.sol) - -pragma solidity ^0.8.22; - -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[ERC-1967], 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 ERC-1967) 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol deleted file mode 100644 index ffa77cc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (proxy/ERC1967/ERC1967Utils.sol) - -pragma solidity ^0.8.21; - -import {IBeacon} from "../beacon/IBeacon.sol"; -import {IERC1967} from "../../interfaces/IERC1967.sol"; -import {Address} from "../../utils/Address.sol"; -import {StorageSlot} from "../../utils/StorageSlot.sol"; - -/** - * @dev This library provides getters and event emitting update functions for - * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots. - */ -library ERC1967Utils { - /** - * @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 ERC-1967 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 IERC1967.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 ERC-1967) 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 ERC-1967 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 IERC1967.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 ERC-1967 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 IERC1967.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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol deleted file mode 100644 index 0e73651..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol +++ /dev/null @@ -1,69 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/README.adoc deleted file mode 100644 index 1c4d010..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/README.adoc +++ /dev/null @@ -1,87 +0,0 @@ -= 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[ERC-1967] storage slots. - -- {ERC1967Utils}: Internal functions to get and set the storage slots defined in ERC-1967. -- {ERC1967Proxy}: A proxy using ERC-1967 storage slots. Not upgradeable by default. - -There are two alternative ways to add upgradeability to an ERC-1967 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 Hardhat and Foundry. - -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 ERC-1967 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[ERC-1822], 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[ERC-1822] 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 ERC-1822 interface. - -== Core - -{{Proxy}} - -== ERC-1967 - -{{IERC1967}} - -{{ERC1967Proxy}} - -{{ERC1967Utils}} - -== Transparent Proxy - -{{TransparentUpgradeableProxy}} - -{{ProxyAdmin}} - -== Beacon - -{{BeaconProxy}} - -{{IBeacon}} - -{{UpgradeableBeacon}} - -== Minimal Clones - -{{Clones}} - -== Utils - -{{Initializable}} - -{{UUPSUpgradeable}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol deleted file mode 100644 index 36558d6..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.2.0) (proxy/beacon/BeaconProxy.sol) - -pragma solidity ^0.8.22; - -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[ERC-1967] 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol deleted file mode 100644 index f911b15..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (proxy/beacon/IBeacon.sol) - -pragma solidity >=0.4.16; - -/** - * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol deleted file mode 100644 index 8db9bd2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol +++ /dev/null @@ -1,70 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol deleted file mode 100644 index eefd49a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.2.0) (proxy/transparent/ProxyAdmin.sol) - -pragma solidity ^0.8.22; - -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,address)` - * and `upgradeAndCall(address,address,bytes)` are present, and `upgrade` must be used if no function should be called, - * while `upgradeAndCall` will invoke the `receive` function if the third argument is the empty byte string. - * If the getter returns `"5.0.0"`, only `upgradeAndCall(address,address,bytes)` is present, and the third 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol deleted file mode 100644 index 21af0e3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.2.0) (proxy/transparent/TransparentUpgradeableProxy.sol) - -pragma solidity ^0.8.22; - -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 { - /// @dev See {UUPSUpgradeable-upgradeToAndCall} - function upgradeToAndCall(address newImplementation, bytes calldata data) 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. Relying on the value of the admin slot - * is generally fine if the implementation is trusted. - * - * 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 view 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol deleted file mode 100644 index 0d05fdb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol +++ /dev/null @@ -1,238 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.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 reinitialization) 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 Pointer to storage slot. Allows integrators to override it with a custom storage location. - * - * NOTE: Consider following the ERC-7201 formula to derive storage locations. - */ - function _initializableStorageSlot() internal pure virtual returns (bytes32) { - return INITIALIZABLE_STORAGE; - } - - /** - * @dev Returns a pointer to the storage namespace. - */ - // solhint-disable-next-line var-name-mixedcase - function _getInitializableStorage() private pure returns (InitializableStorage storage $) { - bytes32 slot = _initializableStorageSlot(); - assembly { - $.slot := slot - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol deleted file mode 100644 index d0f5842..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol +++ /dev/null @@ -1,146 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/UUPSUpgradeable.sol) - -pragma solidity ^0.8.22; - -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 ERC-1967) 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 ERC-1167 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 ERC-1822 {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 ERC-1967 compliant implementation pointing to self. - */ - 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 ERC-1967. - * - * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol deleted file mode 100644 index 8582e0c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol +++ /dev/null @@ -1,389 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/ERC1155.sol) - -pragma solidity ^0.8.20; - -import {IERC1155} from "./IERC1155.sol"; -import {IERC1155MetadataURI} from "./extensions/IERC1155MetadataURI.sol"; -import {ERC1155Utils} from "./utils/ERC1155Utils.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_); - } - - /// @inheritdoc IERC165 - 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 ERC]. - * - * 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; - } - - /// @inheritdoc IERC1155 - 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; - } - - /// @inheritdoc IERC1155 - function setApprovalForAll(address operator, bool approved) public virtual { - _setApprovalForAll(_msgSender(), operator, approved); - } - - /// @inheritdoc IERC1155 - function isApprovedForAll(address account, address operator) public view virtual returns (bool) { - return _operatorApprovals[account][operator]; - } - - /// @inheritdoc IERC1155 - 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); - } - - /// @inheritdoc IERC1155 - 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); - ERC1155Utils.checkOnERC1155Received(operator, from, to, id, value, data); - } else { - ERC1155Utils.checkOnERC1155BatchReceived(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 ERC]. - * - * 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 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) { - assembly ("memory-safe") { - // 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol deleted file mode 100644 index f017084..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol +++ /dev/null @@ -1,123 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/IERC1155.sol) - -pragma solidity >=0.6.2; - -import {IERC165} from "../../utils/introspection/IERC165.sol"; - -/** - * @dev Required interface of an ERC-1155 compliant contract, as defined in the - * https://eips.ethereum.org/EIPS/eip-1155[ERC]. - */ -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`. - */ - 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 zero address. - */ - 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 {IERC1155Receiver-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 {IERC1155Receiver-onERC1155BatchReceived} on the receiver. - * Ensure to follow the checks-effects-interactions pattern and consider employing - * reentrancy guards when interacting with untrusted contracts. - * - * Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments. - * - * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol deleted file mode 100644 index f27b897..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/IERC1155Receiver.sol) - -pragma solidity >=0.6.2; - -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 ERC-1155 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 ERC-1155 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc deleted file mode 100644 index f8bf958..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc +++ /dev/null @@ -1,43 +0,0 @@ -= 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[ERC-1155 Multi Token Standard]. - -The ERC 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 ERC-1155 (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}} - -{{ERC1155Utils}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol deleted file mode 100644 index fd6ad61..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol +++ /dev/null @@ -1,28 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol deleted file mode 100644 index a0de999..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/extensions/ERC1155Pausable.sol) - -pragma solidity ^0.8.20; - -import {ERC1155} from "../ERC1155.sol"; -import {Pausable} from "../../../utils/Pausable.sol"; - -/** - * @dev ERC-1155 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol deleted file mode 100644 index 96d5e60..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/extensions/ERC1155Supply.sol) - -pragma solidity ^0.8.20; - -import {ERC1155} from "../ERC1155.sol"; -import {Arrays} from "../../../utils/Arrays.sol"; - -/** - * @dev Extension of ERC-1155 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 { - using Arrays for uint256[]; - - 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; - } - - /// @inheritdoc ERC1155 - 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.unsafeMemoryAccess(i); - // Overflow check required: The rest of the code assumes that totalSupply never overflows - _totalSupply[ids.unsafeMemoryAccess(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.unsafeMemoryAccess(i); - - unchecked { - // Overflow not possible: values[i] <= balanceOf(from, ids[i]) <= totalSupply(ids[i]) - _totalSupply[ids.unsafeMemoryAccess(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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol deleted file mode 100644 index 5abf319..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/extensions/ERC1155URIStorage.sol) - -pragma solidity ^0.8.20; - -import {Strings} from "../../../utils/Strings.sol"; -import {ERC1155} from "../ERC1155.sol"; - -/** - * @dev ERC-1155 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol deleted file mode 100644 index 501d855..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/extensions/IERC1155MetadataURI.sol) - -pragma solidity >=0.6.2; - -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[ERC]. - */ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol deleted file mode 100644 index 19d7963..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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 ERC-1155 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 { - /// @inheritdoc IERC165 - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Utils.sol deleted file mode 100644 index 03cb0f0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Utils.sol +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/utils/ERC1155Utils.sol) - -pragma solidity ^0.8.20; - -import {IERC1155Receiver} from "../IERC1155Receiver.sol"; -import {IERC1155Errors} from "../../../interfaces/draft-IERC6093.sol"; - -/** - * @dev Library that provide common ERC-1155 utility functions. - * - * See https://eips.ethereum.org/EIPS/eip-1155[ERC-1155]. - * - * _Available since v5.1._ - */ -library ERC1155Utils { - /** - * @dev Performs an acceptance check for the provided `operator` by calling {IERC1155Receiver-onERC1155Received} - * on the `to` address. The `operator` is generally the address that initiated the token transfer (i.e. `msg.sender`). - * - * The acceptance call is not executed and treated as a no-op if the target address doesn't contain code (i.e. an EOA). - * Otherwise, the recipient must implement {IERC1155Receiver-onERC1155Received} and return the acceptance magic value to accept - * the transfer. - */ - function checkOnERC1155Received( - address operator, - address from, - address to, - uint256 id, - uint256 value, - bytes memory data - ) internal { - 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 IERC1155Errors.ERC1155InvalidReceiver(to); - } - } catch (bytes memory reason) { - if (reason.length == 0) { - // non-IERC1155Receiver implementer - revert IERC1155Errors.ERC1155InvalidReceiver(to); - } else { - assembly ("memory-safe") { - revert(add(reason, 0x20), mload(reason)) - } - } - } - } - } - - /** - * @dev Performs a batch acceptance check for the provided `operator` by calling {IERC1155Receiver-onERC1155BatchReceived} - * on the `to` address. The `operator` is generally the address that initiated the token transfer (i.e. `msg.sender`). - * - * The acceptance call is not executed and treated as a no-op if the target address doesn't contain code (i.e. an EOA). - * Otherwise, the recipient must implement {IERC1155Receiver-onERC1155Received} and return the acceptance magic value to accept - * the transfer. - */ - function checkOnERC1155BatchReceived( - address operator, - address from, - address to, - uint256[] memory ids, - uint256[] memory values, - bytes memory data - ) internal { - 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 IERC1155Errors.ERC1155InvalidReceiver(to); - } - } catch (bytes memory reason) { - if (reason.length == 0) { - // non-IERC1155Receiver implementer - revert IERC1155Errors.ERC1155InvalidReceiver(to); - } else { - assembly ("memory-safe") { - revert(add(reason, 0x20), mload(reason)) - } - } - } - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol deleted file mode 100644 index 886febc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol +++ /dev/null @@ -1,305 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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 ERC-20 - * applications. - */ -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}. - * - * Both 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; - } - - /// @inheritdoc IERC20 - function totalSupply() public view virtual returns (uint256) { - return _totalSupply; - } - - /// @inheritdoc IERC20 - 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; - } - - /// @inheritdoc IERC20 - 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}. - * - * Skips emitting an {Approval} event indicating an allowance update. This is not - * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve]. - * - * 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: - * - * ```solidity - * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol deleted file mode 100644 index b493743..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol) - -pragma solidity >=0.4.16; - -/** - * @dev Interface of the ERC-20 standard as defined in the ERC. - */ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc deleted file mode 100644 index e7c981e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc +++ /dev/null @@ -1,78 +0,0 @@ -= 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[ERC-20 Token Standard]. - -TIP: For an overview of ERC-20 tokens and a walk through on how to create a token contract read our xref:ROOT:erc20.adoc[ERC-20 guide]. - -There are a few core contracts that implement the behavior specified in the ERC-20 standard: - -* {IERC20}: the interface all ERC-20 implementations should conform to. -* {IERC20Metadata}: the extended ERC-20 interface including the <>, <> and <> functions. -* {ERC20}: the implementation of the ERC-20 interface, including the <>, <> and <> optional extensions to the standard interface. - -Additionally there are multiple custom extensions, including: - -* {ERC20Permit}: gasless approval of tokens (standardized as ERC-2612). -* {ERC20Bridgeable}: compatibility with crosschain bridges through ERC-7802. -* {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 ERC-3156). -* {ERC20Votes}: support for voting and vote delegation. -* {ERC20Wrapper}: wrapper to create an ERC-20 backed by another ERC-20, with deposit and withdraw methods. Useful in conjunction with {ERC20Votes}. -* {ERC20TemporaryApproval}: support for approvals lasting for only one transaction, as defined in ERC-7674. -* {ERC1363}: support for calling the target of a transfer or approval, enabling code execution on the receiver within a single transaction. -* {ERC4626}: tokenized vault that manages shares (represented as ERC-20) that are backed by assets (another ERC-20). - -Finally, there are some utilities to interact with ERC-20 contracts in various ways: - -* {SafeERC20}: a wrapper around the interface that eliminates the need to handle boolean return values. - -Other utilities that support ERC-20 assets can be found in the codebase: - -* ERC-20 tokens can be timelocked (held 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 ERC-20 (such as <>) and expose them as external functions in the way they prefer. - -== Core - -{{IERC20}} - -{{IERC20Metadata}} - -{{ERC20}} - -== Extensions - -{{IERC20Permit}} - -{{ERC20Permit}} - -{{ERC20Bridgeable}} - -{{ERC20Burnable}} - -{{ERC20Capped}} - -{{ERC20Pausable}} - -{{ERC20Votes}} - -{{ERC20Wrapper}} - -{{ERC20FlashMint}} - -{{ERC20TemporaryApproval}} - -{{ERC1363}} - -{{ERC4626}} - -== Utilities - -{{SafeERC20}} - -{{ERC1363Utils}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC1363.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC1363.sol deleted file mode 100644 index 3b3dbba..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC1363.sol +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/ERC1363.sol) - -pragma solidity ^0.8.20; - -import {ERC20} from "../ERC20.sol"; -import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol"; -import {IERC1363} from "../../../interfaces/IERC1363.sol"; -import {ERC1363Utils} from "../utils/ERC1363Utils.sol"; - -/** - * @title ERC1363 - * @dev Extension of {ERC20} tokens that adds support for code execution after transfers and approvals - * on recipient contracts. Calls after transfers are enabled through the {ERC1363-transferAndCall} and - * {ERC1363-transferFromAndCall} methods while calls after approvals can be made with {ERC1363-approveAndCall} - * - * _Available since v5.1._ - */ -abstract contract ERC1363 is ERC20, ERC165, IERC1363 { - /** - * @dev Indicates a failure within the {transfer} part of a transferAndCall operation. - * @param receiver Address to which tokens are being transferred. - * @param value Amount of tokens to be transferred. - */ - error ERC1363TransferFailed(address receiver, uint256 value); - - /** - * @dev Indicates a failure within the {transferFrom} part of a transferFromAndCall operation. - * @param sender Address from which to send tokens. - * @param receiver Address to which tokens are being transferred. - * @param value Amount of tokens to be transferred. - */ - error ERC1363TransferFromFailed(address sender, address receiver, uint256 value); - - /** - * @dev Indicates a failure within the {approve} part of a approveAndCall operation. - * @param spender Address which will spend the funds. - * @param value Amount of tokens to be spent. - */ - error ERC1363ApproveFailed(address spender, uint256 value); - - /// @inheritdoc IERC165 - function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { - return interfaceId == type(IERC1363).interfaceId || super.supportsInterface(interfaceId); - } - - /** - * @dev Moves a `value` amount of tokens from the caller's account to `to` - * and then calls {IERC1363Receiver-onTransferReceived} on `to`. Returns a flag that indicates - * if the call succeeded. - * - * Requirements: - * - * - The target has code (i.e. is a contract). - * - The target `to` must implement the {IERC1363Receiver} interface. - * - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer. - * - The internal {transfer} must succeed (returned `true`). - */ - function transferAndCall(address to, uint256 value) public returns (bool) { - return transferAndCall(to, value, ""); - } - - /** - * @dev Variant of {transferAndCall} that accepts an additional `data` parameter with - * no specified format. - */ - function transferAndCall(address to, uint256 value, bytes memory data) public virtual returns (bool) { - if (!transfer(to, value)) { - revert ERC1363TransferFailed(to, value); - } - ERC1363Utils.checkOnERC1363TransferReceived(_msgSender(), _msgSender(), to, value, data); - return true; - } - - /** - * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism - * and then calls {IERC1363Receiver-onTransferReceived} on `to`. Returns a flag that indicates - * if the call succeeded. - * - * Requirements: - * - * - The target has code (i.e. is a contract). - * - The target `to` must implement the {IERC1363Receiver} interface. - * - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer. - * - The internal {transferFrom} must succeed (returned `true`). - */ - function transferFromAndCall(address from, address to, uint256 value) public returns (bool) { - return transferFromAndCall(from, to, value, ""); - } - - /** - * @dev Variant of {transferFromAndCall} that accepts an additional `data` parameter with - * no specified format. - */ - function transferFromAndCall( - address from, - address to, - uint256 value, - bytes memory data - ) public virtual returns (bool) { - if (!transferFrom(from, to, value)) { - revert ERC1363TransferFromFailed(from, to, value); - } - ERC1363Utils.checkOnERC1363TransferReceived(_msgSender(), from, to, value, data); - return true; - } - - /** - * @dev Sets a `value` amount of tokens as the allowance of `spender` over the - * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. - * Returns a flag that indicates if the call succeeded. - * - * Requirements: - * - * - The target has code (i.e. is a contract). - * - The target `spender` must implement the {IERC1363Spender} interface. - * - The target must return the {IERC1363Spender-onApprovalReceived} selector to accept the approval. - * - The internal {approve} must succeed (returned `true`). - */ - function approveAndCall(address spender, uint256 value) public returns (bool) { - return approveAndCall(spender, value, ""); - } - - /** - * @dev Variant of {approveAndCall} that accepts an additional `data` parameter with - * no specified format. - */ - function approveAndCall(address spender, uint256 value, bytes memory data) public virtual returns (bool) { - if (!approve(spender, value)) { - revert ERC1363ApproveFailed(spender, value); - } - ERC1363Utils.checkOnERC1363ApprovalReceived(_msgSender(), spender, value, data); - return true; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol deleted file mode 100644 index 4d482d8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol +++ /dev/null @@ -1,39 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol deleted file mode 100644 index c6d0900..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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; - } - - /// @inheritdoc ERC20 - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol deleted file mode 100644 index 4d3a31f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol +++ /dev/null @@ -1,134 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.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 ERC-3156 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 {IERC3156FlashBorrower-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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol deleted file mode 100644 index 2f6d86c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/ERC20Pausable.sol) - -pragma solidity ^0.8.20; - -import {ERC20} from "../ERC20.sol"; -import {Pausable} from "../../../utils/Pausable.sol"; - -/** - * @dev ERC-20 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol deleted file mode 100644 index 7efa9ed..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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 ERC-20 Permit extension allowing approvals to be made via signatures, as defined in - * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612]. - * - * Adds the {permit} method, which can be used to change an account's ERC-20 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 ERC-20 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol deleted file mode 100644 index c15e7f5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.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 ERC-20 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 {Votes-delegate} function directly, or by providing a signature to be used with {Votes-delegateBySig}. Voting - * power can be queried through the public accessors {Votes-getVotes} and {Votes-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 - * {Votes-_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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol deleted file mode 100644 index 8916d1a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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 ERC-20 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" ERC-20 into a governance token. - * - * WARNING: Any mechanism in which the underlying token changes the {balanceOf} of an account without an explicit transfer - * may desynchronize this contract's supply and its underlying balance. Please exercise caution when wrapping tokens that - * may undercollateralize the wrapper (i.e. wrapper's total supply is higher than its underlying balance). See {_recover} - * for recovering value accrued to the wrapper. - */ -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; - } - - /// @inheritdoc IERC20Metadata - 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 or acquired from - * rebasing mechanisms. 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol deleted file mode 100644 index fd8231a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol +++ /dev/null @@ -1,282 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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 ERC-4626 "Tokenized Vault Standard" as defined in - * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. - * - * This extension allows the minting and burning of "shares" (represented using the ERC-20 inheritance) in exchange for - * underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends - * the ERC-20 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 introduces configurable virtual assets and shares to help developers 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 even if an attacker is able to capture value from multiple user deposits, 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:ROOT: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 (ERC-20 or ERC-777). - */ - 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 ok, uint8 assetDecimals) { - (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(); - } - - /// @inheritdoc IERC4626 - function asset() public view virtual returns (address) { - return address(_asset); - } - - /// @inheritdoc IERC4626 - function totalAssets() public view virtual returns (uint256) { - return IERC20(asset()).balanceOf(address(this)); - } - - /// @inheritdoc IERC4626 - function convertToShares(uint256 assets) public view virtual returns (uint256) { - return _convertToShares(assets, Math.Rounding.Floor); - } - - /// @inheritdoc IERC4626 - function convertToAssets(uint256 shares) public view virtual returns (uint256) { - return _convertToAssets(shares, Math.Rounding.Floor); - } - - /// @inheritdoc IERC4626 - function maxDeposit(address) public view virtual returns (uint256) { - return type(uint256).max; - } - - /// @inheritdoc IERC4626 - function maxMint(address) public view virtual returns (uint256) { - return type(uint256).max; - } - - /// @inheritdoc IERC4626 - function maxWithdraw(address owner) public view virtual returns (uint256) { - return _convertToAssets(balanceOf(owner), Math.Rounding.Floor); - } - - /// @inheritdoc IERC4626 - function maxRedeem(address owner) public view virtual returns (uint256) { - return balanceOf(owner); - } - - /// @inheritdoc IERC4626 - function previewDeposit(uint256 assets) public view virtual returns (uint256) { - return _convertToShares(assets, Math.Rounding.Floor); - } - - /// @inheritdoc IERC4626 - function previewMint(uint256 shares) public view virtual returns (uint256) { - return _convertToAssets(shares, Math.Rounding.Ceil); - } - - /// @inheritdoc IERC4626 - function previewWithdraw(uint256 assets) public view virtual returns (uint256) { - return _convertToShares(assets, Math.Rounding.Ceil); - } - - /// @inheritdoc IERC4626 - function previewRedeem(uint256 shares) public view virtual returns (uint256) { - return _convertToAssets(shares, Math.Rounding.Floor); - } - - /// @inheritdoc IERC4626 - 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; - } - - /// @inheritdoc IERC4626 - 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; - } - - /// @inheritdoc IERC4626 - 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; - } - - /// @inheritdoc IERC4626 - 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 ERC-777, `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(IERC20(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 ERC-777, `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(IERC20(asset()), receiver, assets); - - emit Withdraw(caller, receiver, owner, assets, shares); - } - - function _decimalsOffset() internal view virtual returns (uint8) { - return 0; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol deleted file mode 100644 index 87bbafa..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Metadata.sol) - -pragma solidity >=0.6.2; - -import {IERC20} from "../IERC20.sol"; - -/** - * @dev Interface for the optional metadata functions from the ERC-20 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol deleted file mode 100644 index 65488ba..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Permit.sol) - -pragma solidity >=0.4.16; - -/** - * @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in - * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612]. - * - * Adds the {permit} method, which can be used to change an account's ERC-20 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20Bridgeable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20Bridgeable.sol deleted file mode 100644 index 3473013..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20Bridgeable.sol +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/draft-ERC20Bridgeable.sol) - -pragma solidity ^0.8.20; - -import {ERC20} from "../ERC20.sol"; -import {ERC165, IERC165} from "../../../utils/introspection/ERC165.sol"; -import {IERC7802} from "../../../interfaces/draft-IERC7802.sol"; - -/** - * @dev ERC20 extension that implements the standard token interface according to - * https://eips.ethereum.org/EIPS/eip-7802[ERC-7802]. - */ -abstract contract ERC20Bridgeable is ERC20, ERC165, IERC7802 { - /// @dev Modifier to restrict access to the token bridge. - modifier onlyTokenBridge() { - // Token bridge should never be impersonated using a relayer/forwarder. Using msg.sender is preferable to - // _msgSender() for security reasons. - _checkTokenBridge(msg.sender); - _; - } - - /// @inheritdoc ERC165 - function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { - return interfaceId == type(IERC7802).interfaceId || super.supportsInterface(interfaceId); - } - - /** - * @dev See {IERC7802-crosschainMint}. Emits a {IERC7802-CrosschainMint} event. - */ - function crosschainMint(address to, uint256 value) public virtual override onlyTokenBridge { - _mint(to, value); - emit CrosschainMint(to, value, _msgSender()); - } - - /** - * @dev See {IERC7802-crosschainBurn}. Emits a {IERC7802-CrosschainBurn} event. - */ - function crosschainBurn(address from, uint256 value) public virtual override onlyTokenBridge { - _burn(from, value); - emit CrosschainBurn(from, value, _msgSender()); - } - - /** - * @dev Checks if the caller is a trusted token bridge. MUST revert otherwise. - * - * Developers should implement this function using an access control mechanism that allows - * customizing the list of allowed senders. Consider using {AccessControl} or {AccessManaged}. - */ - function _checkTokenBridge(address caller) internal virtual; -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20TemporaryApproval.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20TemporaryApproval.sol deleted file mode 100644 index 357daa9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20TemporaryApproval.sol +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/extensions/draft-ERC20TemporaryApproval.sol) - -pragma solidity ^0.8.24; - -import {IERC20, ERC20} from "../ERC20.sol"; -import {IERC7674} from "../../../interfaces/draft-IERC7674.sol"; -import {Math} from "../../../utils/math/Math.sol"; -import {SlotDerivation} from "../../../utils/SlotDerivation.sol"; -import {TransientSlot} from "../../../utils/TransientSlot.sol"; - -/** - * @dev Extension of {ERC20} that adds support for temporary allowances following ERC-7674. - * - * WARNING: This is a draft contract. The corresponding ERC is still subject to changes. - * - * _Available since v5.1._ - */ -abstract contract ERC20TemporaryApproval is ERC20, IERC7674 { - using SlotDerivation for bytes32; - using TransientSlot for bytes32; - using TransientSlot for TransientSlot.Uint256Slot; - - // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20_TEMPORARY_APPROVAL_STORAGE")) - 1)) & ~bytes32(uint256(0xff)) - bytes32 private constant ERC20_TEMPORARY_APPROVAL_STORAGE = - 0xea2d0e77a01400d0111492b1321103eed560d8fe44b9a7c2410407714583c400; - - /** - * @dev {allowance} override that includes the temporary allowance when looking up the current allowance. If - * adding up the persistent and the temporary allowances result in an overflow, type(uint256).max is returned. - */ - function allowance(address owner, address spender) public view virtual override(IERC20, ERC20) returns (uint256) { - (bool success, uint256 amount) = Math.tryAdd( - super.allowance(owner, spender), - _temporaryAllowance(owner, spender) - ); - return success ? amount : type(uint256).max; - } - - /** - * @dev Internal getter for the current temporary allowance that `spender` has over `owner` tokens. - */ - function _temporaryAllowance(address owner, address spender) internal view virtual returns (uint256) { - return _temporaryAllowanceSlot(owner, spender).tload(); - } - - /** - * @dev Alternative to {approve} that sets a `value` amount of tokens as the temporary allowance of `spender` over - * the caller's tokens. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Requirements: - * - `spender` cannot be the zero address. - * - * Does NOT emit an {Approval} event. - */ - function temporaryApprove(address spender, uint256 value) public virtual returns (bool) { - _temporaryApprove(_msgSender(), spender, value); - return true; - } - - /** - * @dev Sets `value` as the temporary allowance of `spender` over the `owner`'s tokens. - * - * This internal function is equivalent to `temporaryApprove`, and can be used to e.g. set automatic allowances - * for certain subsystems, etc. - * - * Requirements: - * - `owner` cannot be the zero address. - * - `spender` cannot be the zero address. - * - * Does NOT emit an {Approval} event. - */ - function _temporaryApprove(address owner, address spender, uint256 value) internal virtual { - if (owner == address(0)) { - revert ERC20InvalidApprover(address(0)); - } - if (spender == address(0)) { - revert ERC20InvalidSpender(address(0)); - } - _temporaryAllowanceSlot(owner, spender).tstore(value); - } - - /** - * @dev {_spendAllowance} override that consumes the temporary allowance (if any) before eventually falling back - * to consuming the persistent allowance. - * NOTE: This function skips calling `super._spendAllowance` if the temporary allowance - * is enough to cover the spending. - */ - function _spendAllowance(address owner, address spender, uint256 value) internal virtual override { - // load transient allowance - uint256 currentTemporaryAllowance = _temporaryAllowance(owner, spender); - - // Check and update (if needed) the temporary allowance + set remaining value - if (currentTemporaryAllowance > 0) { - // All value is covered by the infinite allowance. nothing left to spend, we can return early - if (currentTemporaryAllowance == type(uint256).max) { - return; - } - // check how much of the value is covered by the transient allowance - uint256 spendTemporaryAllowance = Math.min(currentTemporaryAllowance, value); - unchecked { - // decrease transient allowance accordingly - _temporaryApprove(owner, spender, currentTemporaryAllowance - spendTemporaryAllowance); - // update value necessary - value -= spendTemporaryAllowance; - } - } - // reduce any remaining value from the persistent allowance - if (value > 0) { - super._spendAllowance(owner, spender, value); - } - } - - function _temporaryAllowanceSlot(address owner, address spender) private pure returns (TransientSlot.Uint256Slot) { - return ERC20_TEMPORARY_APPROVAL_STORAGE.deriveMapping(owner).deriveMapping(spender).asUint256(); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/ERC1363Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/ERC1363Utils.sol deleted file mode 100644 index 25577bc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/ERC1363Utils.sol +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/utils/ERC1363Utils.sol) - -pragma solidity ^0.8.20; - -import {IERC1363Receiver} from "../../../interfaces/IERC1363Receiver.sol"; -import {IERC1363Spender} from "../../../interfaces/IERC1363Spender.sol"; - -/** - * @dev Library that provides common ERC-1363 utility functions. - * - * See https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. - */ -library ERC1363Utils { - /** - * @dev Indicates a failure with the token `receiver`. Used in transfers. - * @param receiver Address to which tokens are being transferred. - */ - error ERC1363InvalidReceiver(address receiver); - - /** - * @dev Indicates a failure with the token `spender`. Used in approvals. - * @param spender Address that may be allowed to operate on tokens without being their owner. - */ - error ERC1363InvalidSpender(address spender); - - /** - * @dev Performs a call to {IERC1363Receiver-onTransferReceived} on a target address. - * - * Requirements: - * - * - The target has code (i.e. is a contract). - * - The target `to` must implement the {IERC1363Receiver} interface. - * - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer. - */ - function checkOnERC1363TransferReceived( - address operator, - address from, - address to, - uint256 value, - bytes memory data - ) internal { - if (to.code.length == 0) { - revert ERC1363InvalidReceiver(to); - } - - try IERC1363Receiver(to).onTransferReceived(operator, from, value, data) returns (bytes4 retval) { - if (retval != IERC1363Receiver.onTransferReceived.selector) { - revert ERC1363InvalidReceiver(to); - } - } catch (bytes memory reason) { - if (reason.length == 0) { - revert ERC1363InvalidReceiver(to); - } else { - assembly ("memory-safe") { - revert(add(reason, 0x20), mload(reason)) - } - } - } - } - - /** - * @dev Performs a call to {IERC1363Spender-onApprovalReceived} on a target address. - * - * Requirements: - * - * - The target has code (i.e. is a contract). - * - The target `spender` must implement the {IERC1363Spender} interface. - * - The target must return the {IERC1363Spender-onApprovalReceived} selector to accept the approval. - */ - function checkOnERC1363ApprovalReceived( - address operator, - address spender, - uint256 value, - bytes memory data - ) internal { - if (spender.code.length == 0) { - revert ERC1363InvalidSpender(spender); - } - - try IERC1363Spender(spender).onApprovalReceived(operator, value, data) returns (bytes4 retval) { - if (retval != IERC1363Spender.onApprovalReceived.selector) { - revert ERC1363InvalidSpender(spender); - } - } catch (bytes memory reason) { - if (reason.length == 0) { - revert ERC1363InvalidSpender(spender); - } else { - assembly ("memory-safe") { - revert(add(reason, 0x20), mload(reason)) - } - } - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol deleted file mode 100644 index 883e8d3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol +++ /dev/null @@ -1,212 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol) - -pragma solidity ^0.8.20; - -import {IERC20} from "../IERC20.sol"; -import {IERC1363} from "../../../interfaces/IERC1363.sol"; - -/** - * @title SafeERC20 - * @dev Wrappers around ERC-20 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 { - /** - * @dev An operation with an ERC-20 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 Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful. - */ - function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) { - return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value))); - } - - /** - * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful. - */ - function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) { - return _callOptionalReturnBool(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. - * - * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" - * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using - * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract - * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. - */ - 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. - * - * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" - * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using - * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract - * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. - */ - 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. - * - * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function - * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being - * set here. - */ - 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 Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no - * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when - * targeting contracts. - * - * Reverts if the returned value is other than `true`. - */ - function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { - if (to.code.length == 0) { - safeTransfer(token, to, value); - } else if (!token.transferAndCall(to, value, data)) { - revert SafeERC20FailedOperation(address(token)); - } - } - - /** - * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target - * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when - * targeting contracts. - * - * Reverts if the returned value is other than `true`. - */ - function transferFromAndCallRelaxed( - IERC1363 token, - address from, - address to, - uint256 value, - bytes memory data - ) internal { - if (to.code.length == 0) { - safeTransferFrom(token, from, to, value); - } else if (!token.transferFromAndCall(from, to, value, data)) { - revert SafeERC20FailedOperation(address(token)); - } - } - - /** - * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no - * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when - * targeting contracts. - * - * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}. - * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall} - * once without retrying, and relies on the returned value to be true. - * - * Reverts if the returned value is other than `true`. - */ - function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { - if (to.code.length == 0) { - forceApprove(token, to, value); - } else if (!token.approveAndCall(to, value, data)) { - 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 {_callOptionalReturnBool} that reverts if call fails to meet the requirements. - */ - function _callOptionalReturn(IERC20 token, bytes memory data) private { - uint256 returnSize; - uint256 returnValue; - assembly ("memory-safe") { - let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) - // bubble errors - if iszero(success) { - let ptr := mload(0x40) - returndatacopy(ptr, 0, returndatasize()) - revert(ptr, returndatasize()) - } - returnSize := returndatasize() - returnValue := mload(0) - } - - if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) { - 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 silently catches all reverts and returns a bool instead. - */ - function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { - bool success; - uint256 returnSize; - uint256 returnValue; - assembly ("memory-safe") { - success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) - returnSize := returndatasize() - returnValue := mload(0) - } - return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/README.adoc deleted file mode 100644 index 17d116c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/README.adoc +++ /dev/null @@ -1,27 +0,0 @@ -= ERC-6909 - -[.readme-notice] -NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc6909 - -This set of interfaces and contracts are all related to the https://eips.ethereum.org/EIPS/eip-6909[ERC-6909 Minimal Multi-Token Interface]. - -The ERC consists of four interfaces which fulfill different roles--the interfaces are as follows: - -. {IERC6909}: Base interface for a vanilla ERC6909 token. -. {IERC6909ContentURI}: Extends the base interface and adds content URI (contract and token level) functionality. -. {IERC6909Metadata}: Extends the base interface and adds metadata functionality, which exposes a name, symbol, and decimals for each token id. -. {IERC6909TokenSupply}: Extends the base interface and adds total supply functionality for each token id. - -Implementations are provided for each of the 4 interfaces defined in the ERC. - -== Core - -{{ERC6909}} - -== Extensions - -{{ERC6909ContentURI}} - -{{ERC6909Metadata}} - -{{ERC6909TokenSupply}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/draft-ERC6909.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/draft-ERC6909.sol deleted file mode 100644 index 6f5cdd6..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/draft-ERC6909.sol +++ /dev/null @@ -1,224 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC6909/draft-ERC6909.sol) - -pragma solidity ^0.8.20; - -import {IERC6909} from "../../interfaces/draft-IERC6909.sol"; -import {Context} from "../../utils/Context.sol"; -import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol"; - -/** - * @dev Implementation of ERC-6909. - * See https://eips.ethereum.org/EIPS/eip-6909 - */ -contract ERC6909 is Context, ERC165, IERC6909 { - mapping(address owner => mapping(uint256 id => uint256)) private _balances; - - mapping(address owner => mapping(address operator => bool)) private _operatorApprovals; - - mapping(address owner => mapping(address spender => mapping(uint256 id => uint256))) private _allowances; - - error ERC6909InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 id); - error ERC6909InsufficientAllowance(address spender, uint256 allowance, uint256 needed, uint256 id); - error ERC6909InvalidApprover(address approver); - error ERC6909InvalidReceiver(address receiver); - error ERC6909InvalidSender(address sender); - error ERC6909InvalidSpender(address spender); - - /// @inheritdoc IERC165 - function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { - return interfaceId == type(IERC6909).interfaceId || super.supportsInterface(interfaceId); - } - - /// @inheritdoc IERC6909 - function balanceOf(address owner, uint256 id) public view virtual override returns (uint256) { - return _balances[owner][id]; - } - - /// @inheritdoc IERC6909 - function allowance(address owner, address spender, uint256 id) public view virtual override returns (uint256) { - return _allowances[owner][spender][id]; - } - - /// @inheritdoc IERC6909 - function isOperator(address owner, address spender) public view virtual override returns (bool) { - return _operatorApprovals[owner][spender]; - } - - /// @inheritdoc IERC6909 - function approve(address spender, uint256 id, uint256 amount) public virtual override returns (bool) { - _approve(_msgSender(), spender, id, amount); - return true; - } - - /// @inheritdoc IERC6909 - function setOperator(address spender, bool approved) public virtual override returns (bool) { - _setOperator(_msgSender(), spender, approved); - return true; - } - - /// @inheritdoc IERC6909 - function transfer(address receiver, uint256 id, uint256 amount) public virtual override returns (bool) { - _transfer(_msgSender(), receiver, id, amount); - return true; - } - - /// @inheritdoc IERC6909 - function transferFrom( - address sender, - address receiver, - uint256 id, - uint256 amount - ) public virtual override returns (bool) { - address caller = _msgSender(); - if (sender != caller && !isOperator(sender, caller)) { - _spendAllowance(sender, caller, id, amount); - } - _transfer(sender, receiver, id, amount); - return true; - } - - /** - * @dev Creates `amount` of token `id` 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 to, uint256 id, uint256 amount) internal { - if (to == address(0)) { - revert ERC6909InvalidReceiver(address(0)); - } - _update(address(0), to, id, amount); - } - - /** - * @dev Moves `amount` of token `id` from `from` to `to` without checking for approvals. This function verifies - * that neither the sender nor the receiver are address(0), which means it cannot mint or burn tokens. - * Relies on the `_update` mechanism. - * - * Emits a {Transfer} event. - * - * NOTE: This function is not virtual, {_update} should be overridden instead. - */ - function _transfer(address from, address to, uint256 id, uint256 amount) internal { - if (from == address(0)) { - revert ERC6909InvalidSender(address(0)); - } - if (to == address(0)) { - revert ERC6909InvalidReceiver(address(0)); - } - _update(from, to, id, amount); - } - - /** - * @dev Destroys a `amount` of token `id` from `account`. - * 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 from, uint256 id, uint256 amount) internal { - if (from == address(0)) { - revert ERC6909InvalidSender(address(0)); - } - _update(from, address(0), id, amount); - } - - /** - * @dev Transfers `amount` of token `id` 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 id, uint256 amount) internal virtual { - address caller = _msgSender(); - - if (from != address(0)) { - uint256 fromBalance = _balances[from][id]; - if (fromBalance < amount) { - revert ERC6909InsufficientBalance(from, fromBalance, amount, id); - } - unchecked { - // Overflow not possible: amount <= fromBalance. - _balances[from][id] = fromBalance - amount; - } - } - if (to != address(0)) { - _balances[to][id] += amount; - } - - emit Transfer(caller, from, to, id, amount); - } - - /** - * @dev Sets `amount` as the allowance of `spender` over the `owner`'s `id` 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 id, uint256 amount) internal virtual { - if (owner == address(0)) { - revert ERC6909InvalidApprover(address(0)); - } - if (spender == address(0)) { - revert ERC6909InvalidSpender(address(0)); - } - _allowances[owner][spender][id] = amount; - emit Approval(owner, spender, id, amount); - } - - /** - * @dev Approve `spender` to operate on all of `owner`'s tokens - * - * This internal function is equivalent to `setOperator`, and can be used to e.g. set automatic allowances for - * certain subsystems, etc. - * - * Emits an {OperatorSet} event. - * - * Requirements: - * - * - `owner` cannot be the zero address. - * - `spender` cannot be the zero address. - */ - function _setOperator(address owner, address spender, bool approved) internal virtual { - if (owner == address(0)) { - revert ERC6909InvalidApprover(address(0)); - } - if (spender == address(0)) { - revert ERC6909InvalidSpender(address(0)); - } - _operatorApprovals[owner][spender] = approved; - emit OperatorSet(owner, spender, approved); - } - - /** - * @dev Updates `owner`'s allowance for `spender` based on spent `amount`. - * - * 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 id, uint256 amount) internal virtual { - uint256 currentAllowance = allowance(owner, spender, id); - if (currentAllowance < type(uint256).max) { - if (currentAllowance < amount) { - revert ERC6909InsufficientAllowance(spender, currentAllowance, amount, id); - } - unchecked { - _allowances[owner][spender][id] = currentAllowance - amount; - } - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909ContentURI.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909ContentURI.sol deleted file mode 100644 index 9d082c0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909ContentURI.sol +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC6909/extensions/draft-ERC6909ContentURI.sol) - -pragma solidity ^0.8.20; - -import {ERC6909} from "../draft-ERC6909.sol"; -import {IERC6909ContentURI} from "../../../interfaces/draft-IERC6909.sol"; - -/** - * @dev Implementation of the Content URI extension defined in ERC6909. - */ -contract ERC6909ContentURI is ERC6909, IERC6909ContentURI { - string private _contractURI; - mapping(uint256 id => string) private _tokenURIs; - - /// @dev Event emitted when the contract URI is changed. See https://eips.ethereum.org/EIPS/eip-7572[ERC-7572] for details. - event ContractURIUpdated(); - - /// @dev See {IERC1155-URI} - event URI(string value, uint256 indexed id); - - /// @inheritdoc IERC6909ContentURI - function contractURI() public view virtual override returns (string memory) { - return _contractURI; - } - - /// @inheritdoc IERC6909ContentURI - function tokenURI(uint256 id) public view virtual override returns (string memory) { - return _tokenURIs[id]; - } - - /** - * @dev Sets the {contractURI} for the contract. - * - * Emits a {ContractURIUpdated} event. - */ - function _setContractURI(string memory newContractURI) internal virtual { - _contractURI = newContractURI; - - emit ContractURIUpdated(); - } - - /** - * @dev Sets the {tokenURI} for a given token of type `id`. - * - * Emits a {URI} event. - */ - function _setTokenURI(uint256 id, string memory newTokenURI) internal virtual { - _tokenURIs[id] = newTokenURI; - - emit URI(newTokenURI, id); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909Metadata.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909Metadata.sol deleted file mode 100644 index 31efebe..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909Metadata.sol +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC6909/extensions/draft-ERC6909Metadata.sol) - -pragma solidity ^0.8.20; - -import {ERC6909} from "../draft-ERC6909.sol"; -import {IERC6909Metadata} from "../../../interfaces/draft-IERC6909.sol"; - -/** - * @dev Implementation of the Metadata extension defined in ERC6909. Exposes the name, symbol, and decimals of each token id. - */ -contract ERC6909Metadata is ERC6909, IERC6909Metadata { - struct TokenMetadata { - string name; - string symbol; - uint8 decimals; - } - - mapping(uint256 id => TokenMetadata) private _tokenMetadata; - - /// @dev The name of the token of type `id` was updated to `newName`. - event ERC6909NameUpdated(uint256 indexed id, string newName); - - /// @dev The symbol for the token of type `id` was updated to `newSymbol`. - event ERC6909SymbolUpdated(uint256 indexed id, string newSymbol); - - /// @dev The decimals value for token of type `id` was updated to `newDecimals`. - event ERC6909DecimalsUpdated(uint256 indexed id, uint8 newDecimals); - - /// @inheritdoc IERC6909Metadata - function name(uint256 id) public view virtual override returns (string memory) { - return _tokenMetadata[id].name; - } - - /// @inheritdoc IERC6909Metadata - function symbol(uint256 id) public view virtual override returns (string memory) { - return _tokenMetadata[id].symbol; - } - - /// @inheritdoc IERC6909Metadata - function decimals(uint256 id) public view virtual override returns (uint8) { - return _tokenMetadata[id].decimals; - } - - /** - * @dev Sets the `name` for a given token of type `id`. - * - * Emits an {ERC6909NameUpdated} event. - */ - function _setName(uint256 id, string memory newName) internal virtual { - _tokenMetadata[id].name = newName; - - emit ERC6909NameUpdated(id, newName); - } - - /** - * @dev Sets the `symbol` for a given token of type `id`. - * - * Emits an {ERC6909SymbolUpdated} event. - */ - function _setSymbol(uint256 id, string memory newSymbol) internal virtual { - _tokenMetadata[id].symbol = newSymbol; - - emit ERC6909SymbolUpdated(id, newSymbol); - } - - /** - * @dev Sets the `decimals` for a given token of type `id`. - * - * Emits an {ERC6909DecimalsUpdated} event. - */ - function _setDecimals(uint256 id, uint8 newDecimals) internal virtual { - _tokenMetadata[id].decimals = newDecimals; - - emit ERC6909DecimalsUpdated(id, newDecimals); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909TokenSupply.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909TokenSupply.sol deleted file mode 100644 index 0fd4c22..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC6909/extensions/draft-ERC6909TokenSupply.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC6909/extensions/draft-ERC6909TokenSupply.sol) - -pragma solidity ^0.8.20; - -import {ERC6909} from "../draft-ERC6909.sol"; -import {IERC6909TokenSupply} from "../../../interfaces/draft-IERC6909.sol"; - -/** - * @dev Implementation of the Token Supply extension defined in ERC6909. - * Tracks the total supply of each token id individually. - */ -contract ERC6909TokenSupply is ERC6909, IERC6909TokenSupply { - mapping(uint256 id => uint256) private _totalSupplies; - - /// @inheritdoc IERC6909TokenSupply - function totalSupply(uint256 id) public view virtual override returns (uint256) { - return _totalSupplies[id]; - } - - /// @dev Override the `_update` function to update the total supply of each token id as necessary. - function _update(address from, address to, uint256 id, uint256 amount) internal virtual override { - super._update(from, to, id, amount); - - if (from == address(0)) { - _totalSupplies[id] += amount; - } - if (to == address(0)) { - unchecked { - // amount <= _balances[from][id] <= _totalSupplies[id] - _totalSupplies[id] -= amount; - } - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol deleted file mode 100644 index 2867cd1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol +++ /dev/null @@ -1,430 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/ERC721.sol) - -pragma solidity ^0.8.20; - -import {IERC721} from "./IERC721.sol"; -import {IERC721Metadata} from "./extensions/IERC721Metadata.sol"; -import {ERC721Utils} from "./utils/ERC721Utils.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[ERC-721] 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_; - } - - /// @inheritdoc IERC165 - function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { - return - interfaceId == type(IERC721).interfaceId || - interfaceId == type(IERC721Metadata).interfaceId || - super.supportsInterface(interfaceId); - } - - /// @inheritdoc IERC721 - function balanceOf(address owner) public view virtual returns (uint256) { - if (owner == address(0)) { - revert ERC721InvalidOwner(address(0)); - } - return _balances[owner]; - } - - /// @inheritdoc IERC721 - function ownerOf(uint256 tokenId) public view virtual returns (address) { - return _requireOwned(tokenId); - } - - /// @inheritdoc IERC721Metadata - function name() public view virtual returns (string memory) { - return _name; - } - - /// @inheritdoc IERC721Metadata - function symbol() public view virtual returns (string memory) { - return _symbol; - } - - /// @inheritdoc IERC721Metadata - 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 ""; - } - - /// @inheritdoc IERC721 - function approve(address to, uint256 tokenId) public virtual { - _approve(to, tokenId, _msgSender()); - } - - /// @inheritdoc IERC721 - function getApproved(uint256 tokenId) public view virtual returns (address) { - _requireOwned(tokenId); - - return _getApproved(tokenId); - } - - /// @inheritdoc IERC721 - function setApprovalForAll(address operator, bool approved) public virtual { - _setApprovalForAll(_msgSender(), operator, approved); - } - - /// @inheritdoc IERC721 - function isApprovedForAll(address owner, address operator) public view virtual returns (bool) { - return _operatorApprovals[owner][operator]; - } - - /// @inheritdoc IERC721 - 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); - } - } - - /// @inheritdoc IERC721 - function safeTransferFrom(address from, address to, uint256 tokenId) public { - safeTransferFrom(from, to, tokenId, ""); - } - - /// @inheritdoc IERC721 - function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual { - transferFrom(from, to, tokenId); - ERC721Utils.checkOnERC721Received(_msgSender(), 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 ERC-721 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 `owner` for `tokenId`. - * - `spender` does not have approval to manage all of `owner`'s assets. - * - * 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); - ERC721Utils.checkOnERC721Received(_msgSender(), 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 ERC-721 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); - ERC721Utils.checkOnERC721Received(_msgSender(), 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; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol deleted file mode 100644 index 7498203..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/IERC721.sol) - -pragma solidity >=0.6.2; - -import {IERC165} from "../../utils/introspection/IERC165.sol"; - -/** - * @dev Required interface of an ERC-721 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 ERC-721 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 ERC-721 - * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol deleted file mode 100644 index 6110f0c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/IERC721Receiver.sol) - -pragma solidity >=0.5.0; - -/** - * @title ERC-721 token receiver interface - * @dev Interface for any contract that wants to support safeTransfers - * from ERC-721 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc deleted file mode 100644 index 22a3062..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc +++ /dev/null @@ -1,69 +0,0 @@ -= 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 is all related to the https://eips.ethereum.org/EIPS/eip-721[ERC-721 Non-Fungible Token Standard]. - -TIP: For a walk through on how to create an ERC-721 token read our xref:ROOT:erc721.adoc[ERC-721 guide]. - -The ERC 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[ERC-2309] for minting batches of tokens during construction, in accordance with ERC-721. -* {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 ERC-2981. -* {ERC721Pausable}: A primitive to pause contract operation. -* {ERC721Burnable}: A way for token holders to burn their own tokens. -* {ERC721Wrapper}: Wrapper to create an ERC-721 backed by another ERC-721, 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 ERC-721 (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}} - -{{ERC721Utils}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol deleted file mode 100644 index c6d2245..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/extensions/ERC721Burnable.sol) - -pragma solidity ^0.8.20; - -import {ERC721} from "../ERC721.sol"; -import {Context} from "../../../utils/Context.sol"; - -/** - * @title ERC-721 Burnable Token - * @dev ERC-721 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol deleted file mode 100644 index 0f32673..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol +++ /dev/null @@ -1,176 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.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 ERC-2309 "Consecutive Transfer Extension" as defined in - * https://eips.ethereum.org/EIPS/eip-2309[ERC-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 ERC-721 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 ERC-721 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol deleted file mode 100644 index 1231ffc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol +++ /dev/null @@ -1,164 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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 ERC 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(); - - /// @inheritdoc IERC165 - function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { - return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); - } - - /// @inheritdoc IERC721Enumerable - function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) { - if (index >= balanceOf(owner)) { - revert ERC721OutOfBoundsIndex(owner, index); - } - return _ownedTokens[owner][index]; - } - - /// @inheritdoc IERC721Enumerable - function totalSupply() public view virtual returns (uint256) { - return _allTokens.length; - } - - /// @inheritdoc IERC721Enumerable - function tokenByIndex(uint256 index) public view virtual returns (uint256) { - if (index >= totalSupply()) { - revert ERC721OutOfBoundsIndex(address(0), index); - } - return _allTokens[index]; - } - - /// @inheritdoc ERC721 - 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]; - - mapping(uint256 index => uint256) storage _ownedTokensByOwner = _ownedTokens[from]; - - // When the token to delete is the last token, the swap operation is unnecessary - if (tokenIndex != lastTokenIndex) { - uint256 lastTokenId = _ownedTokensByOwner[lastTokenIndex]; - - _ownedTokensByOwner[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 _ownedTokensByOwner[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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol deleted file mode 100644 index 9a75623..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/extensions/ERC721Pausable.sol) - -pragma solidity ^0.8.20; - -import {ERC721} from "../ERC721.sol"; -import {Pausable} from "../../../utils/Pausable.sol"; - -/** - * @dev ERC-721 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol deleted file mode 100644 index cb51fdb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/extensions/ERC721Royalty.sol) - -pragma solidity ^0.8.20; - -import {ERC721} from "../ERC721.sol"; -import {IERC165} from "../../../utils/introspection/ERC165.sol"; -import {ERC2981} from "../../common/ERC2981.sol"; - -/** - * @dev Extension of ERC-721 with the ERC-2981 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 ERC. 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 { - /// @inheritdoc IERC165 - function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC2981) returns (bool) { - return super.supportsInterface(interfaceId); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol deleted file mode 100644 index 99630df..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/extensions/ERC721URIStorage.sol) - -pragma solidity ^0.8.20; - -import {ERC721} from "../ERC721.sol"; -import {IERC721Metadata} from "./IERC721Metadata.sol"; -import {Strings} from "../../../utils/Strings.sol"; -import {IERC4906} from "../../../interfaces/IERC4906.sol"; -import {IERC165} from "../../../interfaces/IERC165.sol"; - -/** - * @dev ERC-721 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; - - /// @inheritdoc IERC165 - function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, IERC165) returns (bool) { - return interfaceId == ERC4906_INTERFACE_ID || super.supportsInterface(interfaceId); - } - - /// @inheritdoc IERC721Metadata - 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 {IERC4906-MetadataUpdate}. - */ - function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { - _tokenURIs[tokenId] = _tokenURI; - emit MetadataUpdate(tokenId); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol deleted file mode 100644 index f71195c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.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 ERC-721 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol deleted file mode 100644 index 111136b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.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 ERC-721 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" ERC-721 into a governance token. - */ -abstract contract ERC721Wrapper is ERC721, IERC721Receiver { - IERC721 private immutable _underlying; - - /** - * @dev The received ERC-721 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 ERC-721 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol deleted file mode 100644 index 1fe5885..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/extensions/IERC721Enumerable.sol) - -pragma solidity >=0.6.2; - -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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol deleted file mode 100644 index b4da16d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/extensions/IERC721Metadata.sol) - -pragma solidity >=0.6.2; - -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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol deleted file mode 100644 index 6bb23ac..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol +++ /dev/null @@ -1,24 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Utils.sol deleted file mode 100644 index 575ee8b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Utils.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/utils/ERC721Utils.sol) - -pragma solidity ^0.8.20; - -import {IERC721Receiver} from "../IERC721Receiver.sol"; -import {IERC721Errors} from "../../../interfaces/draft-IERC6093.sol"; - -/** - * @dev Library that provide common ERC-721 utility functions. - * - * See https://eips.ethereum.org/EIPS/eip-721[ERC-721]. - * - * _Available since v5.1._ - */ -library ERC721Utils { - /** - * @dev Performs an acceptance check for the provided `operator` by calling {IERC721Receiver-onERC721Received} - * on the `to` address. The `operator` is generally the address that initiated the token transfer (i.e. `msg.sender`). - * - * The acceptance call is not executed and treated as a no-op if the target address doesn't contain code (i.e. an EOA). - * Otherwise, the recipient must implement {IERC721Receiver-onERC721Received} and return the acceptance magic value to accept - * the transfer. - */ - function checkOnERC721Received( - address operator, - address from, - address to, - uint256 tokenId, - bytes memory data - ) internal { - if (to.code.length > 0) { - try IERC721Receiver(to).onERC721Received(operator, from, tokenId, data) returns (bytes4 retval) { - if (retval != IERC721Receiver.onERC721Received.selector) { - // Token rejected - revert IERC721Errors.ERC721InvalidReceiver(to); - } - } catch (bytes memory reason) { - if (reason.length == 0) { - // non-IERC721Receiver implementer - revert IERC721Errors.ERC721InvalidReceiver(to); - } else { - assembly ("memory-safe") { - revert(add(reason, 0x20), mload(reason)) - } - } - } - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol deleted file mode 100644 index 5d75e3a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol +++ /dev/null @@ -1,139 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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 ERC. 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 a 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); - - /// @inheritdoc IERC165 - 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 receiver, uint256 amount) { - RoyaltyInfo storage _royaltyInfo = _tokenRoyaltyInfo[tokenId]; - address royaltyReceiver = _royaltyInfo.receiver; - uint96 royaltyFraction = _royaltyInfo.royaltyFraction; - - if (royaltyReceiver == address(0)) { - royaltyReceiver = _defaultRoyaltyInfo.receiver; - royaltyFraction = _defaultRoyaltyInfo.royaltyFraction; - } - - uint256 royaltyAmount = (salePrice * royaltyFraction) / _feeDenominator(); - - return (royaltyReceiver, 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/README.adoc deleted file mode 100644 index a70d90d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/token/common/README.adoc +++ /dev/null @@ -1,10 +0,0 @@ -= Common (Tokens) - -Functionality that is common to multiple token standards. - -* {ERC2981}: NFT Royalties compatible with both ERC-721 and ERC-1155. -** For ERC-721 consider {ERC721Royalty} which clears the royalty information from storage on burn. - -== Contracts - -{{ERC2981}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Address.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Address.sol deleted file mode 100644 index cb90227..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Address.sol +++ /dev/null @@ -1,149 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/Address.sol) - -pragma solidity ^0.8.20; - -import {Errors} from "./Errors.sol"; - -/** - * @dev Collection of functions related to the address type - */ -library Address { - /** - * @dev There's no code at `target` (it is not a contract). - */ - error AddressEmptyCode(address target); - - /** - * @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 Errors.InsufficientBalance(address(this).balance, amount); - } - - (bool success, bytes memory returndata) = recipient.call{value: amount}(""); - if (!success) { - _revert(returndata); - } - } - - /** - * @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 - * {Errors.FailedCall} 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 Errors.InsufficientBalance(address(this).balance, value); - } - (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 {Errors.FailedCall}) 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 {Errors.FailedCall} 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 {Errors.FailedCall}. - */ - 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 - assembly ("memory-safe") { - revert(add(returndata, 0x20), mload(returndata)) - } - } else { - revert Errors.FailedCall(); - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Arrays.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Arrays.sol deleted file mode 100644 index 511354a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Arrays.sol +++ /dev/null @@ -1,552 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/Arrays.sol) -// This file was procedurally generated from scripts/generate/templates/Arrays.js. - -pragma solidity ^0.8.20; - -import {Comparators} from "./Comparators.sol"; -import {SlotDerivation} from "./SlotDerivation.sol"; -import {StorageSlot} from "./StorageSlot.sol"; -import {Math} from "./math/Math.sol"; - -/** - * @dev Collection of functions related to array types. - */ -library Arrays { - using SlotDerivation for bytes32; - using StorageSlot for bytes32; - - /** - * @dev Sort an array of uint256 (in memory) following the provided comparator function. - * - * This function does the sorting "in place", meaning that it overrides the input. The object is returned for - * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array. - * - * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the - * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful - * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may - * consume more gas than is available in a block, leading to potential DoS. - * - * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way. - */ - function sort( - uint256[] memory array, - function(uint256, uint256) pure returns (bool) comp - ) internal pure returns (uint256[] memory) { - _quickSort(_begin(array), _end(array), comp); - return array; - } - - /** - * @dev Variant of {sort} that sorts an array of uint256 in increasing order. - */ - function sort(uint256[] memory array) internal pure returns (uint256[] memory) { - sort(array, Comparators.lt); - return array; - } - - /** - * @dev Sort an array of address (in memory) following the provided comparator function. - * - * This function does the sorting "in place", meaning that it overrides the input. The object is returned for - * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array. - * - * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the - * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful - * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may - * consume more gas than is available in a block, leading to potential DoS. - * - * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way. - */ - function sort( - address[] memory array, - function(address, address) pure returns (bool) comp - ) internal pure returns (address[] memory) { - sort(_castToUint256Array(array), _castToUint256Comp(comp)); - return array; - } - - /** - * @dev Variant of {sort} that sorts an array of address in increasing order. - */ - function sort(address[] memory array) internal pure returns (address[] memory) { - sort(_castToUint256Array(array), Comparators.lt); - return array; - } - - /** - * @dev Sort an array of bytes32 (in memory) following the provided comparator function. - * - * This function does the sorting "in place", meaning that it overrides the input. The object is returned for - * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array. - * - * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the - * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful - * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may - * consume more gas than is available in a block, leading to potential DoS. - * - * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way. - */ - function sort( - bytes32[] memory array, - function(bytes32, bytes32) pure returns (bool) comp - ) internal pure returns (bytes32[] memory) { - sort(_castToUint256Array(array), _castToUint256Comp(comp)); - return array; - } - - /** - * @dev Variant of {sort} that sorts an array of bytes32 in increasing order. - */ - function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) { - sort(_castToUint256Array(array), Comparators.lt); - return array; - } - - /** - * @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops - * at end (exclusive). Sorting follows the `comp` comparator. - * - * Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls. - * - * IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should - * be used only if the limits are within a memory array. - */ - function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure { - unchecked { - if (end - begin < 0x40) return; - - // Use first element as pivot - uint256 pivot = _mload(begin); - // Position where the pivot should be at the end of the loop - uint256 pos = begin; - - for (uint256 it = begin + 0x20; it < end; it += 0x20) { - if (comp(_mload(it), pivot)) { - // If the value stored at the iterator's position comes before the pivot, we increment the - // position of the pivot and move the value there. - pos += 0x20; - _swap(pos, it); - } - } - - _swap(begin, pos); // Swap pivot into place - _quickSort(begin, pos, comp); // Sort the left side of the pivot - _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot - } - } - - /** - * @dev Pointer to the memory location of the first element of `array`. - */ - function _begin(uint256[] memory array) private pure returns (uint256 ptr) { - assembly ("memory-safe") { - ptr := add(array, 0x20) - } - } - - /** - * @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word - * that comes just after the last element of the array. - */ - function _end(uint256[] memory array) private pure returns (uint256 ptr) { - unchecked { - return _begin(array) + array.length * 0x20; - } - } - - /** - * @dev Load memory word (as a uint256) at location `ptr`. - */ - function _mload(uint256 ptr) private pure returns (uint256 value) { - assembly { - value := mload(ptr) - } - } - - /** - * @dev Swaps the elements memory location `ptr1` and `ptr2`. - */ - function _swap(uint256 ptr1, uint256 ptr2) private pure { - assembly { - let value1 := mload(ptr1) - let value2 := mload(ptr2) - mstore(ptr1, value2) - mstore(ptr2, value1) - } - } - - /// @dev Helper: low level cast address memory array to uint256 memory array - function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) { - assembly { - output := input - } - } - - /// @dev Helper: low level cast bytes32 memory array to uint256 memory array - function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) { - assembly { - output := input - } - } - - /// @dev Helper: low level cast address comp function to uint256 comp function - function _castToUint256Comp( - function(address, address) pure returns (bool) input - ) private pure returns (function(uint256, uint256) pure returns (bool) output) { - assembly { - output := input - } - } - - /// @dev Helper: low level cast bytes32 comp function to uint256 comp function - function _castToUint256Comp( - function(bytes32, bytes32) pure returns (bool) input - ) private pure returns (function(uint256, uint256) pure returns (bool) output) { - assembly { - output := input - } - } - - /** - * @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). - * - * NOTE: The `array` is expected to be sorted in ascending order, and to - * contain no repeated elements. - * - * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks - * support for repeated elements in the array. The {lowerBound} function should - * be used instead. - */ - 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 Searches an `array` sorted in ascending order and returns the first - * index that contains a value greater or equal than `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). - * - * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound]. - */ - function lowerBound(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) { - // this cannot overflow because mid < high - unchecked { - low = mid + 1; - } - } else { - high = mid; - } - } - - return low; - } - - /** - * @dev Searches an `array` sorted in ascending order and returns the first - * index that contains a value strictly greater than `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). - * - * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound]. - */ - function upperBound(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 { - // this cannot overflow because mid < high - unchecked { - low = mid + 1; - } - } - } - - return low; - } - - /** - * @dev Same as {lowerBound}, but with an array in memory. - */ - function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure 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 (unsafeMemoryAccess(array, mid) < element) { - // this cannot overflow because mid < high - unchecked { - low = mid + 1; - } - } else { - high = mid; - } - } - - return low; - } - - /** - * @dev Same as {upperBound}, but with an array in memory. - */ - function upperBoundMemory(uint256[] memory array, uint256 element) internal pure 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 (unsafeMemoryAccess(array, mid) > element) { - high = mid; - } else { - // this cannot overflow because mid < high - unchecked { - low = mid + 1; - } - } - } - - 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; - assembly ("memory-safe") { - slot := arr.slot - } - return slot.deriveArray().offset(pos).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; - assembly ("memory-safe") { - slot := arr.slot - } - return slot.deriveArray().offset(pos).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; - assembly ("memory-safe") { - slot := arr.slot - } - return slot.deriveArray().offset(pos).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 unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) { - bytes32 slot; - assembly ("memory-safe") { - slot := arr.slot - } - return slot.deriveArray().offset(pos).getBytesSlot(); - } - - /** - * @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(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) { - bytes32 slot; - assembly ("memory-safe") { - slot := arr.slot - } - return slot.deriveArray().offset(pos).getStringSlot(); - } - - /** - * @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))) - } - } - - /** - * @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(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 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(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(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory 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(string[] memory arr, uint256 pos) internal pure returns (string memory res) { - assembly { - res := mload(add(add(arr, 0x20), mul(pos, 0x20))) - } - } - - /** - * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. - * - * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. - */ - function unsafeSetLength(address[] storage array, uint256 len) internal { - assembly ("memory-safe") { - sstore(array.slot, len) - } - } - - /** - * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. - * - * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. - */ - function unsafeSetLength(bytes32[] storage array, uint256 len) internal { - assembly ("memory-safe") { - sstore(array.slot, len) - } - } - - /** - * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. - * - * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. - */ - function unsafeSetLength(uint256[] storage array, uint256 len) internal { - assembly ("memory-safe") { - sstore(array.slot, len) - } - } - - /** - * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. - * - * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. - */ - function unsafeSetLength(bytes[] storage array, uint256 len) internal { - assembly ("memory-safe") { - sstore(array.slot, len) - } - } - - /** - * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. - * - * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. - */ - function unsafeSetLength(string[] storage array, uint256 len) internal { - assembly ("memory-safe") { - sstore(array.slot, len) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Base64.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Base64.sol deleted file mode 100644 index d9b09ec..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Base64.sol +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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 - * See sections 4 and 5 of https://datatracker.ietf.org/doc/html/rfc4648 - */ - string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - string internal constant _TABLE_URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; - - /** - * @dev Converts a `bytes` to its Bytes64 `string` representation. - */ - function encode(bytes memory data) internal pure returns (string memory) { - return _encode(data, _TABLE, true); - } - - /** - * @dev Converts a `bytes` to its Bytes64Url `string` representation. - * Output is not padded with `=` as specified in https://www.rfc-editor.org/rfc/rfc4648[rfc4648]. - */ - function encodeURL(bytes memory data) internal pure returns (string memory) { - return _encode(data, _TABLE_URL, false); - } - - /** - * @dev Internal table-agnostic conversion - */ - function _encode(bytes memory data, string memory table, bool withPadding) private 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 ""; - - // If padding is enabled, the final length should be `bytes` data length divided by 3 rounded up and then - // multiplied by 4 so that it leaves room for padding the last chunk - // - `data.length + 2` -> Prepare for division rounding up - // - `/ 3` -> Number of 3-bytes chunks (rounded up) - // - `4 *` -> 4 characters for each chunk - // This is equivalent to: 4 * Math.ceil(data.length / 3) - // - // If padding is disabled, the final length should be `bytes` data length multiplied by 4/3 rounded up as - // opposed to when padding is required to fill the last chunk. - // - `4 * data.length` -> 4 characters for each chunk - // - ` + 2` -> Prepare for division rounding up - // - `/ 3` -> Number of 3-bytes chunks (rounded up) - // This is equivalent to: Math.ceil((4 * data.length) / 3) - uint256 resultLength = withPadding ? 4 * ((data.length + 2) / 3) : (4 * data.length + 2) / 3; - - string memory result = new string(resultLength); - - assembly ("memory-safe") { - // Prepare the lookup table (skip the first "length" byte) - let tablePtr := add(table, 1) - - // Prepare result pointer, jump over length - let resultPtr := add(result, 0x20) - let dataPtr := data - let endPtr := add(data, mload(data)) - - // In some cases, the last iteration will read bytes after the end of the data. We cache the value, and - // set it to zero to make sure no dirty bytes are read in that section. - let afterPtr := add(endPtr, 0x20) - let afterCache := mload(afterPtr) - mstore(afterPtr, 0x00) - - // Run over the input, 3 bytes at a time - for {} lt(dataPtr, endPtr) {} { - // Advance 3 bytes - dataPtr := add(dataPtr, 3) - let input := mload(dataPtr) - - // To write each character, shift the 3 byte (24 bits) chunk - // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) - // and apply logical AND with 0x3F to bitmask the least significant 6 bits. - // Use this as an index into the lookup table, mload an entire word - // so the desired character is in the least significant byte, and - // mstore8 this least significant byte into the result and continue. - - 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 - } - - // Reset the value that was cached - mstore(afterPtr, afterCache) - - if withPadding { - // 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Blockhash.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Blockhash.sol deleted file mode 100644 index d420b8e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Blockhash.sol +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/Blockhash.sol) -pragma solidity ^0.8.20; - -/** - * @dev Library for accessing historical block hashes beyond the standard 256 block limit. - * Uses EIP-2935's history storage contract which maintains a ring buffer of the last - * 8191 block hashes in state. - * - * For blocks within the last 256 blocks, it uses the native `BLOCKHASH` opcode. - * For blocks between 257 and 8191 blocks ago, it queries the EIP-2935 history storage. - * For blocks older than 8191 or future blocks, it returns zero, matching the `BLOCKHASH` behavior. - * - * NOTE: After EIP-2935 activation, it takes 8191 blocks to completely fill the history. - * Before that, only block hashes since the fork block will be available. - */ -library Blockhash { - /// @dev Address of the EIP-2935 history storage contract. - address internal constant HISTORY_STORAGE_ADDRESS = 0x0000F90827F1C53a10cb7A02335B175320002935; - - /** - * @dev Retrieves the block hash for any historical block within the supported range. - * - * NOTE: The function gracefully handles future blocks and blocks beyond the history window - * by returning zero, consistent with the EVM's native `BLOCKHASH` behavior. - */ - function blockHash(uint256 blockNumber) internal view returns (bytes32) { - uint256 current = block.number; - uint256 distance; - - unchecked { - // Can only wrap around to `current + 1` given `block.number - (2**256 - 1) = block.number + 1` - distance = current - blockNumber; - } - - return distance < 257 ? blockhash(blockNumber) : _historyStorageCall(blockNumber); - } - - /// @dev Internal function to query the EIP-2935 history storage contract. - function _historyStorageCall(uint256 blockNumber) private view returns (bytes32 hash) { - assembly ("memory-safe") { - // Store the blockNumber in scratch space - mstore(0x00, blockNumber) - mstore(0x20, 0) - - // call history storage address - pop(staticcall(gas(), HISTORY_STORAGE_ADDRESS, 0x00, 0x20, 0x20, 0x20)) - - // load result - hash := mload(0x20) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Bytes.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Bytes.sol deleted file mode 100644 index 15084ec..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Bytes.sol +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/Bytes.sol) - -pragma solidity ^0.8.24; - -import {Math} from "./math/Math.sol"; - -/** - * @dev Bytes operations. - */ -library Bytes { - /** - * @dev Forward search for `s` in `buffer` - * * If `s` is present in the buffer, returns the index of the first instance - * * If `s` is not present in the buffer, returns type(uint256).max - * - * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf[Javascript's `Array.indexOf`] - */ - function indexOf(bytes memory buffer, bytes1 s) internal pure returns (uint256) { - return indexOf(buffer, s, 0); - } - - /** - * @dev Forward search for `s` in `buffer` starting at position `pos` - * * If `s` is present in the buffer (at or after `pos`), returns the index of the next instance - * * If `s` is not present in the buffer (at or after `pos`), returns type(uint256).max - * - * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf[Javascript's `Array.indexOf`] - */ - function indexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) { - uint256 length = buffer.length; - for (uint256 i = pos; i < length; ++i) { - if (bytes1(_unsafeReadBytesOffset(buffer, i)) == s) { - return i; - } - } - return type(uint256).max; - } - - /** - * @dev Backward search for `s` in `buffer` - * * If `s` is present in the buffer, returns the index of the last instance - * * If `s` is not present in the buffer, returns type(uint256).max - * - * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf[Javascript's `Array.lastIndexOf`] - */ - function lastIndexOf(bytes memory buffer, bytes1 s) internal pure returns (uint256) { - return lastIndexOf(buffer, s, type(uint256).max); - } - - /** - * @dev Backward search for `s` in `buffer` starting at position `pos` - * * If `s` is present in the buffer (at or before `pos`), returns the index of the previous instance - * * If `s` is not present in the buffer (at or before `pos`), returns type(uint256).max - * - * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf[Javascript's `Array.lastIndexOf`] - */ - function lastIndexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) { - unchecked { - uint256 length = buffer.length; - for (uint256 i = Math.min(Math.saturatingAdd(pos, 1), length); i > 0; --i) { - if (bytes1(_unsafeReadBytesOffset(buffer, i - 1)) == s) { - return i - 1; - } - } - return type(uint256).max; - } - } - - /** - * @dev Copies the content of `buffer`, from `start` (included) to the end of `buffer` into a new bytes object in - * memory. - * - * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`] - */ - function slice(bytes memory buffer, uint256 start) internal pure returns (bytes memory) { - return slice(buffer, start, buffer.length); - } - - /** - * @dev Copies the content of `buffer`, from `start` (included) to `end` (excluded) into a new bytes object in - * memory. - * - * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`] - */ - function slice(bytes memory buffer, uint256 start, uint256 end) internal pure returns (bytes memory) { - // sanitize - uint256 length = buffer.length; - end = Math.min(end, length); - start = Math.min(start, end); - - // allocate and copy - bytes memory result = new bytes(end - start); - assembly ("memory-safe") { - mcopy(add(result, 0x20), add(add(buffer, 0x20), start), sub(end, start)) - } - - return result; - } - - /** - * @dev Reads a bytes32 from a bytes array without bounds checking. - * - * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the - * assembly block as such would prevent some optimizations. - */ - function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) { - // This is not memory safe in the general case, but all calls to this private function are within bounds. - assembly ("memory-safe") { - value := mload(add(add(buffer, 0x20), offset)) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP10.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP10.sol deleted file mode 100644 index 84b35da..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP10.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.2.0) (utils/CAIP10.sol) - -pragma solidity ^0.8.24; - -import {Bytes} from "./Bytes.sol"; -import {Strings} from "./Strings.sol"; -import {CAIP2} from "./CAIP2.sol"; - -/** - * @dev Helper library to format and parse CAIP-10 identifiers - * - * https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md[CAIP-10] defines account identifiers as: - * account_id: chain_id + ":" + account_address - * chain_id: [-a-z0-9]{3,8}:[-_a-zA-Z0-9]{1,32} (See {CAIP2}) - * account_address: [-.%a-zA-Z0-9]{1,128} - * - * WARNING: According to [CAIP-10's canonicalization section](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md#canonicalization), - * the implementation remains at the developer's discretion. Please note that case variations may introduce ambiguity. - * For example, when building hashes to identify accounts or data associated to them, multiple representations of the - * same account would derive to different hashes. For EVM chains, we recommend using checksummed addresses for the - * "account_address" part. They can be generated onchain using {Strings-toChecksumHexString}. - */ -library CAIP10 { - using Strings for address; - using Bytes for bytes; - - /// @dev Return the CAIP-10 identifier for an account on the current (local) chain. - function local(address account) internal view returns (string memory) { - return format(CAIP2.local(), account.toChecksumHexString()); - } - - /** - * @dev Return the CAIP-10 identifier for a given caip2 chain and account. - * - * NOTE: This function does not verify that the inputs are properly formatted. - */ - function format(string memory caip2, string memory account) internal pure returns (string memory) { - return string.concat(caip2, ":", account); - } - - /** - * @dev Parse a CAIP-10 identifier into its components. - * - * NOTE: This function does not verify that the CAIP-10 input is properly formatted. The `caip2` return can be - * parsed using the {CAIP2} library. - */ - function parse(string memory caip10) internal pure returns (string memory caip2, string memory account) { - bytes memory buffer = bytes(caip10); - - uint256 pos = buffer.lastIndexOf(":"); - return (string(buffer.slice(0, pos)), string(buffer.slice(pos + 1))); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP2.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP2.sol deleted file mode 100644 index d06dd6d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/CAIP2.sol +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.2.0) (utils/CAIP2.sol) - -pragma solidity ^0.8.24; - -import {Bytes} from "./Bytes.sol"; -import {Strings} from "./Strings.sol"; - -/** - * @dev Helper library to format and parse CAIP-2 identifiers - * - * https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md[CAIP-2] defines chain identifiers as: - * chain_id: namespace + ":" + reference - * namespace: [-a-z0-9]{3,8} - * reference: [-_a-zA-Z0-9]{1,32} - * - * WARNING: In some cases, multiple CAIP-2 identifiers may all be valid representation of a single chain. - * For EVM chains, it is recommended to use `eip155:xxx` as the canonical representation (where `xxx` is - * the EIP-155 chain id). Consider the possible ambiguity when processing CAIP-2 identifiers or when using them - * in the context of hashes. - */ -library CAIP2 { - using Strings for uint256; - using Bytes for bytes; - - /// @dev Return the CAIP-2 identifier for the current (local) chain. - function local() internal view returns (string memory) { - return format("eip155", block.chainid.toString()); - } - - /** - * @dev Return the CAIP-2 identifier for a given namespace and reference. - * - * NOTE: This function does not verify that the inputs are properly formatted. - */ - function format(string memory namespace, string memory ref) internal pure returns (string memory) { - return string.concat(namespace, ":", ref); - } - - /** - * @dev Parse a CAIP-2 identifier into its components. - * - * NOTE: This function does not verify that the CAIP-2 input is properly formatted. - */ - function parse(string memory caip2) internal pure returns (string memory namespace, string memory ref) { - bytes memory buffer = bytes(caip2); - - uint256 pos = buffer.indexOf(":"); - return (string(buffer.slice(0, pos)), string(buffer.slice(pos + 1))); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Calldata.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Calldata.sol deleted file mode 100644 index 41860b2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Calldata.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (utils/Calldata.sol) - -pragma solidity ^0.8.20; - -/** - * @dev Helper library for manipulating objects in calldata. - */ -library Calldata { - // slither-disable-next-line write-after-write - function emptyBytes() internal pure returns (bytes calldata result) { - assembly ("memory-safe") { - result.offset := 0 - result.length := 0 - } - } - - // slither-disable-next-line write-after-write - function emptyString() internal pure returns (string calldata result) { - assembly ("memory-safe") { - result.offset := 0 - result.length := 0 - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Comparators.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Comparators.sol deleted file mode 100644 index a8c5e73..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Comparators.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol) - -pragma solidity ^0.8.20; - -/** - * @dev Provides a set of functions to compare values. - * - * _Available since v5.1._ - */ -library Comparators { - function lt(uint256 a, uint256 b) internal pure returns (bool) { - return a < b; - } - - function gt(uint256 a, uint256 b) internal pure returns (bool) { - return a > b; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Context.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Context.sol deleted file mode 100644 index 4e535fe..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Context.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.0.1) (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; - } - - function _contextSuffixLength() internal view virtual returns (uint256) { - return 0; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Create2.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Create2.sol deleted file mode 100644 index ffd39d9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Create2.sol +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (utils/Create2.sol) - -pragma solidity ^0.8.20; - -import {Errors} from "./Errors.sol"; - -/** - * @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 There's no code to deploy. - */ - error Create2EmptyBytecode(); - - /** - * @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 Errors.InsufficientBalance(address(this).balance, amount); - } - if (bytecode.length == 0) { - revert Create2EmptyBytecode(); - } - assembly ("memory-safe") { - addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt) - // if no address was created, and returndata is not empty, bubble revert - if and(iszero(addr), not(iszero(returndatasize()))) { - let p := mload(0x40) - returndatacopy(p, 0, returndatasize()) - revert(p, returndatasize()) - } - } - if (addr == address(0)) { - revert Errors.FailedDeployment(); - } - } - - /** - * @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) { - assembly ("memory-safe") { - 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 := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Errors.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Errors.sol deleted file mode 100644 index 442fc18..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Errors.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol) - -pragma solidity ^0.8.20; - -/** - * @dev Collection of common custom errors used in multiple contracts - * - * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. - * It is recommended to avoid relying on the error API for critical functionality. - * - * _Available since v5.1._ - */ -library Errors { - /** - * @dev The ETH balance of the account is not enough to perform the operation. - */ - error InsufficientBalance(uint256 balance, uint256 needed); - - /** - * @dev A call to an address target failed. The target may have reverted. - */ - error FailedCall(); - - /** - * @dev The deployment failed. - */ - error FailedDeployment(); - - /** - * @dev A necessary precompile is missing. - */ - error MissingPrecompile(address); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Multicall.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Multicall.sol deleted file mode 100644 index 94222fe..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Multicall.sol +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (utils/Multicall.sol) - -pragma solidity ^0.8.20; - -import {Address} from "./Address.sol"; -import {Context} from "./Context.sol"; - -/** - * @dev Provides a function to batch together multiple calls in a single external call. - * - * Consider any assumption about calldata validation performed by the sender may be violated if it's not especially - * careful about sending transactions invoking {multicall}. For example, a relay address that filters function - * selectors won't filter calls nested within a {multicall} operation. - * - * NOTE: Since 5.0.1 and 4.9.4, this contract identifies non-canonical contexts (i.e. `msg.sender` is not {Context-_msgSender}). - * If a non-canonical context is identified, the following self `delegatecall` appends the last bytes of `msg.data` - * to the subcall. This makes it safe to use with {ERC2771Context}. Contexts that don't affect the resolution of - * {Context-_msgSender} are not propagated to subcalls. - */ -abstract contract Multicall is Context { - /** - * @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) { - bytes memory context = msg.sender == _msgSender() - ? new bytes(0) - : msg.data[msg.data.length - _contextSuffixLength():]; - - results = new bytes[](data.length); - for (uint256 i = 0; i < data.length; i++) { - results[i] = Address.functionDelegateCall(address(this), bytes.concat(data[i], context)); - } - return results; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Nonces.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Nonces.sol deleted file mode 100644 index 37451ff..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Nonces.sol +++ /dev/null @@ -1,46 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/NoncesKeyed.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/NoncesKeyed.sol deleted file mode 100644 index df9c570..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/NoncesKeyed.sol +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.2.0) (utils/NoncesKeyed.sol) -pragma solidity ^0.8.20; - -import {Nonces} from "./Nonces.sol"; - -/** - * @dev Alternative to {Nonces}, that supports key-ed nonces. - * - * Follows the https://eips.ethereum.org/EIPS/eip-4337#semi-abstracted-nonce-support[ERC-4337's semi-abstracted nonce system]. - * - * NOTE: This contract inherits from {Nonces} and reuses its storage for the first nonce key (i.e. `0`). This - * makes upgrading from {Nonces} to {NoncesKeyed} safe when using their upgradeable versions (e.g. `NoncesKeyedUpgradeable`). - * Doing so will NOT reset the current state of nonces, avoiding replay attacks where a nonce is reused after the upgrade. - */ -abstract contract NoncesKeyed is Nonces { - mapping(address owner => mapping(uint192 key => uint64)) private _nonces; - - /// @dev Returns the next unused nonce for an address and key. Result contains the key prefix. - function nonces(address owner, uint192 key) public view virtual returns (uint256) { - return key == 0 ? nonces(owner) : _pack(key, _nonces[owner][key]); - } - - /** - * @dev Consumes the next unused nonce for an address and key. - * - * Returns the current value without the key prefix. Consumed nonce is increased, so calling this function twice - * with the same arguments will return different (sequential) results. - */ - function _useNonce(address owner, uint192 key) 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 key == 0 ? _useNonce(owner) : _pack(key, _nonces[owner][key]++); - } - } - - /** - * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`. - * - * This version takes the key and the nonce in a single uint256 parameter: - * - use the first 24 bytes for the key - * - use the last 8 bytes for the nonce - */ - function _useCheckedNonce(address owner, uint256 keyNonce) internal virtual override { - (uint192 key, ) = _unpack(keyNonce); - if (key == 0) { - super._useCheckedNonce(owner, keyNonce); - } else { - uint256 current = _useNonce(owner, key); - if (keyNonce != current) revert InvalidAccountNonce(owner, current); - } - } - - /** - * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`. - * - * This version takes the key and the nonce as two different parameters. - */ - function _useCheckedNonce(address owner, uint192 key, uint64 nonce) internal virtual { - _useCheckedNonce(owner, _pack(key, nonce)); - } - - /// @dev Pack key and nonce into a keyNonce - function _pack(uint192 key, uint64 nonce) private pure returns (uint256) { - return (uint256(key) << 64) | nonce; - } - - /// @dev Unpack a keyNonce into its key and nonce components - function _unpack(uint256 keyNonce) private pure returns (uint192 key, uint64 nonce) { - return (uint192(keyNonce >> 64), uint64(keyNonce)); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Packing.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Packing.sol deleted file mode 100644 index f7c5d6f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Packing.sol +++ /dev/null @@ -1,1656 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.2.0) (utils/Packing.sol) -// This file was procedurally generated from scripts/generate/templates/Packing.js. - -pragma solidity ^0.8.20; - -/** - * @dev Helper library packing and unpacking multiple values into bytesXX. - * - * Example usage: - * - * ```solidity - * library MyPacker { - * type MyType is bytes32; - * - * function _pack(address account, bytes4 selector, uint64 period) external pure returns (MyType) { - * bytes12 subpack = Packing.pack_4_8(selector, bytes8(period)); - * bytes32 pack = Packing.pack_20_12(bytes20(account), subpack); - * return MyType.wrap(pack); - * } - * - * function _unpack(MyType self) external pure returns (address, bytes4, uint64) { - * bytes32 pack = MyType.unwrap(self); - * return ( - * address(Packing.extract_32_20(pack, 0)), - * Packing.extract_32_4(pack, 20), - * uint64(Packing.extract_32_8(pack, 24)) - * ); - * } - * } - * ``` - * - * _Available since v5.1._ - */ -// solhint-disable func-name-mixedcase -library Packing { - error OutOfRangeAccess(); - - function pack_1_1(bytes1 left, bytes1 right) internal pure returns (bytes2 result) { - assembly ("memory-safe") { - left := and(left, shl(248, not(0))) - right := and(right, shl(248, not(0))) - result := or(left, shr(8, right)) - } - } - - function pack_2_2(bytes2 left, bytes2 right) internal pure returns (bytes4 result) { - assembly ("memory-safe") { - left := and(left, shl(240, not(0))) - right := and(right, shl(240, not(0))) - result := or(left, shr(16, right)) - } - } - - function pack_2_4(bytes2 left, bytes4 right) internal pure returns (bytes6 result) { - assembly ("memory-safe") { - left := and(left, shl(240, not(0))) - right := and(right, shl(224, not(0))) - result := or(left, shr(16, right)) - } - } - - function pack_2_6(bytes2 left, bytes6 right) internal pure returns (bytes8 result) { - assembly ("memory-safe") { - left := and(left, shl(240, not(0))) - right := and(right, shl(208, not(0))) - result := or(left, shr(16, right)) - } - } - - function pack_2_8(bytes2 left, bytes8 right) internal pure returns (bytes10 result) { - assembly ("memory-safe") { - left := and(left, shl(240, not(0))) - right := and(right, shl(192, not(0))) - result := or(left, shr(16, right)) - } - } - - function pack_2_10(bytes2 left, bytes10 right) internal pure returns (bytes12 result) { - assembly ("memory-safe") { - left := and(left, shl(240, not(0))) - right := and(right, shl(176, not(0))) - result := or(left, shr(16, right)) - } - } - - function pack_2_20(bytes2 left, bytes20 right) internal pure returns (bytes22 result) { - assembly ("memory-safe") { - left := and(left, shl(240, not(0))) - right := and(right, shl(96, not(0))) - result := or(left, shr(16, right)) - } - } - - function pack_2_22(bytes2 left, bytes22 right) internal pure returns (bytes24 result) { - assembly ("memory-safe") { - left := and(left, shl(240, not(0))) - right := and(right, shl(80, not(0))) - result := or(left, shr(16, right)) - } - } - - function pack_4_2(bytes4 left, bytes2 right) internal pure returns (bytes6 result) { - assembly ("memory-safe") { - left := and(left, shl(224, not(0))) - right := and(right, shl(240, not(0))) - result := or(left, shr(32, right)) - } - } - - function pack_4_4(bytes4 left, bytes4 right) internal pure returns (bytes8 result) { - assembly ("memory-safe") { - left := and(left, shl(224, not(0))) - right := and(right, shl(224, not(0))) - result := or(left, shr(32, right)) - } - } - - function pack_4_6(bytes4 left, bytes6 right) internal pure returns (bytes10 result) { - assembly ("memory-safe") { - left := and(left, shl(224, not(0))) - right := and(right, shl(208, not(0))) - result := or(left, shr(32, right)) - } - } - - function pack_4_8(bytes4 left, bytes8 right) internal pure returns (bytes12 result) { - assembly ("memory-safe") { - left := and(left, shl(224, not(0))) - right := and(right, shl(192, not(0))) - result := or(left, shr(32, right)) - } - } - - function pack_4_12(bytes4 left, bytes12 right) internal pure returns (bytes16 result) { - assembly ("memory-safe") { - left := and(left, shl(224, not(0))) - right := and(right, shl(160, not(0))) - result := or(left, shr(32, right)) - } - } - - function pack_4_16(bytes4 left, bytes16 right) internal pure returns (bytes20 result) { - assembly ("memory-safe") { - left := and(left, shl(224, not(0))) - right := and(right, shl(128, not(0))) - result := or(left, shr(32, right)) - } - } - - function pack_4_20(bytes4 left, bytes20 right) internal pure returns (bytes24 result) { - assembly ("memory-safe") { - left := and(left, shl(224, not(0))) - right := and(right, shl(96, not(0))) - result := or(left, shr(32, right)) - } - } - - function pack_4_24(bytes4 left, bytes24 right) internal pure returns (bytes28 result) { - assembly ("memory-safe") { - left := and(left, shl(224, not(0))) - right := and(right, shl(64, not(0))) - result := or(left, shr(32, right)) - } - } - - function pack_4_28(bytes4 left, bytes28 right) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - left := and(left, shl(224, not(0))) - right := and(right, shl(32, not(0))) - result := or(left, shr(32, right)) - } - } - - function pack_6_2(bytes6 left, bytes2 right) internal pure returns (bytes8 result) { - assembly ("memory-safe") { - left := and(left, shl(208, not(0))) - right := and(right, shl(240, not(0))) - result := or(left, shr(48, right)) - } - } - - function pack_6_4(bytes6 left, bytes4 right) internal pure returns (bytes10 result) { - assembly ("memory-safe") { - left := and(left, shl(208, not(0))) - right := and(right, shl(224, not(0))) - result := or(left, shr(48, right)) - } - } - - function pack_6_6(bytes6 left, bytes6 right) internal pure returns (bytes12 result) { - assembly ("memory-safe") { - left := and(left, shl(208, not(0))) - right := and(right, shl(208, not(0))) - result := or(left, shr(48, right)) - } - } - - function pack_6_10(bytes6 left, bytes10 right) internal pure returns (bytes16 result) { - assembly ("memory-safe") { - left := and(left, shl(208, not(0))) - right := and(right, shl(176, not(0))) - result := or(left, shr(48, right)) - } - } - - function pack_6_16(bytes6 left, bytes16 right) internal pure returns (bytes22 result) { - assembly ("memory-safe") { - left := and(left, shl(208, not(0))) - right := and(right, shl(128, not(0))) - result := or(left, shr(48, right)) - } - } - - function pack_6_22(bytes6 left, bytes22 right) internal pure returns (bytes28 result) { - assembly ("memory-safe") { - left := and(left, shl(208, not(0))) - right := and(right, shl(80, not(0))) - result := or(left, shr(48, right)) - } - } - - function pack_8_2(bytes8 left, bytes2 right) internal pure returns (bytes10 result) { - assembly ("memory-safe") { - left := and(left, shl(192, not(0))) - right := and(right, shl(240, not(0))) - result := or(left, shr(64, right)) - } - } - - function pack_8_4(bytes8 left, bytes4 right) internal pure returns (bytes12 result) { - assembly ("memory-safe") { - left := and(left, shl(192, not(0))) - right := and(right, shl(224, not(0))) - result := or(left, shr(64, right)) - } - } - - function pack_8_8(bytes8 left, bytes8 right) internal pure returns (bytes16 result) { - assembly ("memory-safe") { - left := and(left, shl(192, not(0))) - right := and(right, shl(192, not(0))) - result := or(left, shr(64, right)) - } - } - - function pack_8_12(bytes8 left, bytes12 right) internal pure returns (bytes20 result) { - assembly ("memory-safe") { - left := and(left, shl(192, not(0))) - right := and(right, shl(160, not(0))) - result := or(left, shr(64, right)) - } - } - - function pack_8_16(bytes8 left, bytes16 right) internal pure returns (bytes24 result) { - assembly ("memory-safe") { - left := and(left, shl(192, not(0))) - right := and(right, shl(128, not(0))) - result := or(left, shr(64, right)) - } - } - - function pack_8_20(bytes8 left, bytes20 right) internal pure returns (bytes28 result) { - assembly ("memory-safe") { - left := and(left, shl(192, not(0))) - right := and(right, shl(96, not(0))) - result := or(left, shr(64, right)) - } - } - - function pack_8_24(bytes8 left, bytes24 right) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - left := and(left, shl(192, not(0))) - right := and(right, shl(64, not(0))) - result := or(left, shr(64, right)) - } - } - - function pack_10_2(bytes10 left, bytes2 right) internal pure returns (bytes12 result) { - assembly ("memory-safe") { - left := and(left, shl(176, not(0))) - right := and(right, shl(240, not(0))) - result := or(left, shr(80, right)) - } - } - - function pack_10_6(bytes10 left, bytes6 right) internal pure returns (bytes16 result) { - assembly ("memory-safe") { - left := and(left, shl(176, not(0))) - right := and(right, shl(208, not(0))) - result := or(left, shr(80, right)) - } - } - - function pack_10_10(bytes10 left, bytes10 right) internal pure returns (bytes20 result) { - assembly ("memory-safe") { - left := and(left, shl(176, not(0))) - right := and(right, shl(176, not(0))) - result := or(left, shr(80, right)) - } - } - - function pack_10_12(bytes10 left, bytes12 right) internal pure returns (bytes22 result) { - assembly ("memory-safe") { - left := and(left, shl(176, not(0))) - right := and(right, shl(160, not(0))) - result := or(left, shr(80, right)) - } - } - - function pack_10_22(bytes10 left, bytes22 right) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - left := and(left, shl(176, not(0))) - right := and(right, shl(80, not(0))) - result := or(left, shr(80, right)) - } - } - - function pack_12_4(bytes12 left, bytes4 right) internal pure returns (bytes16 result) { - assembly ("memory-safe") { - left := and(left, shl(160, not(0))) - right := and(right, shl(224, not(0))) - result := or(left, shr(96, right)) - } - } - - function pack_12_8(bytes12 left, bytes8 right) internal pure returns (bytes20 result) { - assembly ("memory-safe") { - left := and(left, shl(160, not(0))) - right := and(right, shl(192, not(0))) - result := or(left, shr(96, right)) - } - } - - function pack_12_10(bytes12 left, bytes10 right) internal pure returns (bytes22 result) { - assembly ("memory-safe") { - left := and(left, shl(160, not(0))) - right := and(right, shl(176, not(0))) - result := or(left, shr(96, right)) - } - } - - function pack_12_12(bytes12 left, bytes12 right) internal pure returns (bytes24 result) { - assembly ("memory-safe") { - left := and(left, shl(160, not(0))) - right := and(right, shl(160, not(0))) - result := or(left, shr(96, right)) - } - } - - function pack_12_16(bytes12 left, bytes16 right) internal pure returns (bytes28 result) { - assembly ("memory-safe") { - left := and(left, shl(160, not(0))) - right := and(right, shl(128, not(0))) - result := or(left, shr(96, right)) - } - } - - function pack_12_20(bytes12 left, bytes20 right) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - left := and(left, shl(160, not(0))) - right := and(right, shl(96, not(0))) - result := or(left, shr(96, right)) - } - } - - function pack_16_4(bytes16 left, bytes4 right) internal pure returns (bytes20 result) { - assembly ("memory-safe") { - left := and(left, shl(128, not(0))) - right := and(right, shl(224, not(0))) - result := or(left, shr(128, right)) - } - } - - function pack_16_6(bytes16 left, bytes6 right) internal pure returns (bytes22 result) { - assembly ("memory-safe") { - left := and(left, shl(128, not(0))) - right := and(right, shl(208, not(0))) - result := or(left, shr(128, right)) - } - } - - function pack_16_8(bytes16 left, bytes8 right) internal pure returns (bytes24 result) { - assembly ("memory-safe") { - left := and(left, shl(128, not(0))) - right := and(right, shl(192, not(0))) - result := or(left, shr(128, right)) - } - } - - function pack_16_12(bytes16 left, bytes12 right) internal pure returns (bytes28 result) { - assembly ("memory-safe") { - left := and(left, shl(128, not(0))) - right := and(right, shl(160, not(0))) - result := or(left, shr(128, right)) - } - } - - function pack_16_16(bytes16 left, bytes16 right) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - left := and(left, shl(128, not(0))) - right := and(right, shl(128, not(0))) - result := or(left, shr(128, right)) - } - } - - function pack_20_2(bytes20 left, bytes2 right) internal pure returns (bytes22 result) { - assembly ("memory-safe") { - left := and(left, shl(96, not(0))) - right := and(right, shl(240, not(0))) - result := or(left, shr(160, right)) - } - } - - function pack_20_4(bytes20 left, bytes4 right) internal pure returns (bytes24 result) { - assembly ("memory-safe") { - left := and(left, shl(96, not(0))) - right := and(right, shl(224, not(0))) - result := or(left, shr(160, right)) - } - } - - function pack_20_8(bytes20 left, bytes8 right) internal pure returns (bytes28 result) { - assembly ("memory-safe") { - left := and(left, shl(96, not(0))) - right := and(right, shl(192, not(0))) - result := or(left, shr(160, right)) - } - } - - function pack_20_12(bytes20 left, bytes12 right) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - left := and(left, shl(96, not(0))) - right := and(right, shl(160, not(0))) - result := or(left, shr(160, right)) - } - } - - function pack_22_2(bytes22 left, bytes2 right) internal pure returns (bytes24 result) { - assembly ("memory-safe") { - left := and(left, shl(80, not(0))) - right := and(right, shl(240, not(0))) - result := or(left, shr(176, right)) - } - } - - function pack_22_6(bytes22 left, bytes6 right) internal pure returns (bytes28 result) { - assembly ("memory-safe") { - left := and(left, shl(80, not(0))) - right := and(right, shl(208, not(0))) - result := or(left, shr(176, right)) - } - } - - function pack_22_10(bytes22 left, bytes10 right) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - left := and(left, shl(80, not(0))) - right := and(right, shl(176, not(0))) - result := or(left, shr(176, right)) - } - } - - function pack_24_4(bytes24 left, bytes4 right) internal pure returns (bytes28 result) { - assembly ("memory-safe") { - left := and(left, shl(64, not(0))) - right := and(right, shl(224, not(0))) - result := or(left, shr(192, right)) - } - } - - function pack_24_8(bytes24 left, bytes8 right) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - left := and(left, shl(64, not(0))) - right := and(right, shl(192, not(0))) - result := or(left, shr(192, right)) - } - } - - function pack_28_4(bytes28 left, bytes4 right) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - left := and(left, shl(32, not(0))) - right := and(right, shl(224, not(0))) - result := or(left, shr(224, right)) - } - } - - function extract_2_1(bytes2 self, uint8 offset) internal pure returns (bytes1 result) { - if (offset > 1) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(248, not(0))) - } - } - - function replace_2_1(bytes2 self, bytes1 value, uint8 offset) internal pure returns (bytes2 result) { - bytes1 oldValue = extract_2_1(self, offset); - assembly ("memory-safe") { - value := and(value, shl(248, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_4_1(bytes4 self, uint8 offset) internal pure returns (bytes1 result) { - if (offset > 3) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(248, not(0))) - } - } - - function replace_4_1(bytes4 self, bytes1 value, uint8 offset) internal pure returns (bytes4 result) { - bytes1 oldValue = extract_4_1(self, offset); - assembly ("memory-safe") { - value := and(value, shl(248, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_4_2(bytes4 self, uint8 offset) internal pure returns (bytes2 result) { - if (offset > 2) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(240, not(0))) - } - } - - function replace_4_2(bytes4 self, bytes2 value, uint8 offset) internal pure returns (bytes4 result) { - bytes2 oldValue = extract_4_2(self, offset); - assembly ("memory-safe") { - value := and(value, shl(240, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_6_1(bytes6 self, uint8 offset) internal pure returns (bytes1 result) { - if (offset > 5) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(248, not(0))) - } - } - - function replace_6_1(bytes6 self, bytes1 value, uint8 offset) internal pure returns (bytes6 result) { - bytes1 oldValue = extract_6_1(self, offset); - assembly ("memory-safe") { - value := and(value, shl(248, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_6_2(bytes6 self, uint8 offset) internal pure returns (bytes2 result) { - if (offset > 4) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(240, not(0))) - } - } - - function replace_6_2(bytes6 self, bytes2 value, uint8 offset) internal pure returns (bytes6 result) { - bytes2 oldValue = extract_6_2(self, offset); - assembly ("memory-safe") { - value := and(value, shl(240, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_6_4(bytes6 self, uint8 offset) internal pure returns (bytes4 result) { - if (offset > 2) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(224, not(0))) - } - } - - function replace_6_4(bytes6 self, bytes4 value, uint8 offset) internal pure returns (bytes6 result) { - bytes4 oldValue = extract_6_4(self, offset); - assembly ("memory-safe") { - value := and(value, shl(224, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_8_1(bytes8 self, uint8 offset) internal pure returns (bytes1 result) { - if (offset > 7) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(248, not(0))) - } - } - - function replace_8_1(bytes8 self, bytes1 value, uint8 offset) internal pure returns (bytes8 result) { - bytes1 oldValue = extract_8_1(self, offset); - assembly ("memory-safe") { - value := and(value, shl(248, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_8_2(bytes8 self, uint8 offset) internal pure returns (bytes2 result) { - if (offset > 6) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(240, not(0))) - } - } - - function replace_8_2(bytes8 self, bytes2 value, uint8 offset) internal pure returns (bytes8 result) { - bytes2 oldValue = extract_8_2(self, offset); - assembly ("memory-safe") { - value := and(value, shl(240, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_8_4(bytes8 self, uint8 offset) internal pure returns (bytes4 result) { - if (offset > 4) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(224, not(0))) - } - } - - function replace_8_4(bytes8 self, bytes4 value, uint8 offset) internal pure returns (bytes8 result) { - bytes4 oldValue = extract_8_4(self, offset); - assembly ("memory-safe") { - value := and(value, shl(224, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_8_6(bytes8 self, uint8 offset) internal pure returns (bytes6 result) { - if (offset > 2) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(208, not(0))) - } - } - - function replace_8_6(bytes8 self, bytes6 value, uint8 offset) internal pure returns (bytes8 result) { - bytes6 oldValue = extract_8_6(self, offset); - assembly ("memory-safe") { - value := and(value, shl(208, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_10_1(bytes10 self, uint8 offset) internal pure returns (bytes1 result) { - if (offset > 9) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(248, not(0))) - } - } - - function replace_10_1(bytes10 self, bytes1 value, uint8 offset) internal pure returns (bytes10 result) { - bytes1 oldValue = extract_10_1(self, offset); - assembly ("memory-safe") { - value := and(value, shl(248, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_10_2(bytes10 self, uint8 offset) internal pure returns (bytes2 result) { - if (offset > 8) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(240, not(0))) - } - } - - function replace_10_2(bytes10 self, bytes2 value, uint8 offset) internal pure returns (bytes10 result) { - bytes2 oldValue = extract_10_2(self, offset); - assembly ("memory-safe") { - value := and(value, shl(240, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_10_4(bytes10 self, uint8 offset) internal pure returns (bytes4 result) { - if (offset > 6) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(224, not(0))) - } - } - - function replace_10_4(bytes10 self, bytes4 value, uint8 offset) internal pure returns (bytes10 result) { - bytes4 oldValue = extract_10_4(self, offset); - assembly ("memory-safe") { - value := and(value, shl(224, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_10_6(bytes10 self, uint8 offset) internal pure returns (bytes6 result) { - if (offset > 4) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(208, not(0))) - } - } - - function replace_10_6(bytes10 self, bytes6 value, uint8 offset) internal pure returns (bytes10 result) { - bytes6 oldValue = extract_10_6(self, offset); - assembly ("memory-safe") { - value := and(value, shl(208, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_10_8(bytes10 self, uint8 offset) internal pure returns (bytes8 result) { - if (offset > 2) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(192, not(0))) - } - } - - function replace_10_8(bytes10 self, bytes8 value, uint8 offset) internal pure returns (bytes10 result) { - bytes8 oldValue = extract_10_8(self, offset); - assembly ("memory-safe") { - value := and(value, shl(192, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_12_1(bytes12 self, uint8 offset) internal pure returns (bytes1 result) { - if (offset > 11) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(248, not(0))) - } - } - - function replace_12_1(bytes12 self, bytes1 value, uint8 offset) internal pure returns (bytes12 result) { - bytes1 oldValue = extract_12_1(self, offset); - assembly ("memory-safe") { - value := and(value, shl(248, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_12_2(bytes12 self, uint8 offset) internal pure returns (bytes2 result) { - if (offset > 10) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(240, not(0))) - } - } - - function replace_12_2(bytes12 self, bytes2 value, uint8 offset) internal pure returns (bytes12 result) { - bytes2 oldValue = extract_12_2(self, offset); - assembly ("memory-safe") { - value := and(value, shl(240, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_12_4(bytes12 self, uint8 offset) internal pure returns (bytes4 result) { - if (offset > 8) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(224, not(0))) - } - } - - function replace_12_4(bytes12 self, bytes4 value, uint8 offset) internal pure returns (bytes12 result) { - bytes4 oldValue = extract_12_4(self, offset); - assembly ("memory-safe") { - value := and(value, shl(224, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_12_6(bytes12 self, uint8 offset) internal pure returns (bytes6 result) { - if (offset > 6) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(208, not(0))) - } - } - - function replace_12_6(bytes12 self, bytes6 value, uint8 offset) internal pure returns (bytes12 result) { - bytes6 oldValue = extract_12_6(self, offset); - assembly ("memory-safe") { - value := and(value, shl(208, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_12_8(bytes12 self, uint8 offset) internal pure returns (bytes8 result) { - if (offset > 4) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(192, not(0))) - } - } - - function replace_12_8(bytes12 self, bytes8 value, uint8 offset) internal pure returns (bytes12 result) { - bytes8 oldValue = extract_12_8(self, offset); - assembly ("memory-safe") { - value := and(value, shl(192, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_12_10(bytes12 self, uint8 offset) internal pure returns (bytes10 result) { - if (offset > 2) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(176, not(0))) - } - } - - function replace_12_10(bytes12 self, bytes10 value, uint8 offset) internal pure returns (bytes12 result) { - bytes10 oldValue = extract_12_10(self, offset); - assembly ("memory-safe") { - value := and(value, shl(176, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_16_1(bytes16 self, uint8 offset) internal pure returns (bytes1 result) { - if (offset > 15) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(248, not(0))) - } - } - - function replace_16_1(bytes16 self, bytes1 value, uint8 offset) internal pure returns (bytes16 result) { - bytes1 oldValue = extract_16_1(self, offset); - assembly ("memory-safe") { - value := and(value, shl(248, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_16_2(bytes16 self, uint8 offset) internal pure returns (bytes2 result) { - if (offset > 14) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(240, not(0))) - } - } - - function replace_16_2(bytes16 self, bytes2 value, uint8 offset) internal pure returns (bytes16 result) { - bytes2 oldValue = extract_16_2(self, offset); - assembly ("memory-safe") { - value := and(value, shl(240, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_16_4(bytes16 self, uint8 offset) internal pure returns (bytes4 result) { - if (offset > 12) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(224, not(0))) - } - } - - function replace_16_4(bytes16 self, bytes4 value, uint8 offset) internal pure returns (bytes16 result) { - bytes4 oldValue = extract_16_4(self, offset); - assembly ("memory-safe") { - value := and(value, shl(224, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_16_6(bytes16 self, uint8 offset) internal pure returns (bytes6 result) { - if (offset > 10) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(208, not(0))) - } - } - - function replace_16_6(bytes16 self, bytes6 value, uint8 offset) internal pure returns (bytes16 result) { - bytes6 oldValue = extract_16_6(self, offset); - assembly ("memory-safe") { - value := and(value, shl(208, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_16_8(bytes16 self, uint8 offset) internal pure returns (bytes8 result) { - if (offset > 8) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(192, not(0))) - } - } - - function replace_16_8(bytes16 self, bytes8 value, uint8 offset) internal pure returns (bytes16 result) { - bytes8 oldValue = extract_16_8(self, offset); - assembly ("memory-safe") { - value := and(value, shl(192, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_16_10(bytes16 self, uint8 offset) internal pure returns (bytes10 result) { - if (offset > 6) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(176, not(0))) - } - } - - function replace_16_10(bytes16 self, bytes10 value, uint8 offset) internal pure returns (bytes16 result) { - bytes10 oldValue = extract_16_10(self, offset); - assembly ("memory-safe") { - value := and(value, shl(176, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_16_12(bytes16 self, uint8 offset) internal pure returns (bytes12 result) { - if (offset > 4) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(160, not(0))) - } - } - - function replace_16_12(bytes16 self, bytes12 value, uint8 offset) internal pure returns (bytes16 result) { - bytes12 oldValue = extract_16_12(self, offset); - assembly ("memory-safe") { - value := and(value, shl(160, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_20_1(bytes20 self, uint8 offset) internal pure returns (bytes1 result) { - if (offset > 19) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(248, not(0))) - } - } - - function replace_20_1(bytes20 self, bytes1 value, uint8 offset) internal pure returns (bytes20 result) { - bytes1 oldValue = extract_20_1(self, offset); - assembly ("memory-safe") { - value := and(value, shl(248, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_20_2(bytes20 self, uint8 offset) internal pure returns (bytes2 result) { - if (offset > 18) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(240, not(0))) - } - } - - function replace_20_2(bytes20 self, bytes2 value, uint8 offset) internal pure returns (bytes20 result) { - bytes2 oldValue = extract_20_2(self, offset); - assembly ("memory-safe") { - value := and(value, shl(240, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_20_4(bytes20 self, uint8 offset) internal pure returns (bytes4 result) { - if (offset > 16) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(224, not(0))) - } - } - - function replace_20_4(bytes20 self, bytes4 value, uint8 offset) internal pure returns (bytes20 result) { - bytes4 oldValue = extract_20_4(self, offset); - assembly ("memory-safe") { - value := and(value, shl(224, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_20_6(bytes20 self, uint8 offset) internal pure returns (bytes6 result) { - if (offset > 14) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(208, not(0))) - } - } - - function replace_20_6(bytes20 self, bytes6 value, uint8 offset) internal pure returns (bytes20 result) { - bytes6 oldValue = extract_20_6(self, offset); - assembly ("memory-safe") { - value := and(value, shl(208, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_20_8(bytes20 self, uint8 offset) internal pure returns (bytes8 result) { - if (offset > 12) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(192, not(0))) - } - } - - function replace_20_8(bytes20 self, bytes8 value, uint8 offset) internal pure returns (bytes20 result) { - bytes8 oldValue = extract_20_8(self, offset); - assembly ("memory-safe") { - value := and(value, shl(192, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_20_10(bytes20 self, uint8 offset) internal pure returns (bytes10 result) { - if (offset > 10) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(176, not(0))) - } - } - - function replace_20_10(bytes20 self, bytes10 value, uint8 offset) internal pure returns (bytes20 result) { - bytes10 oldValue = extract_20_10(self, offset); - assembly ("memory-safe") { - value := and(value, shl(176, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_20_12(bytes20 self, uint8 offset) internal pure returns (bytes12 result) { - if (offset > 8) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(160, not(0))) - } - } - - function replace_20_12(bytes20 self, bytes12 value, uint8 offset) internal pure returns (bytes20 result) { - bytes12 oldValue = extract_20_12(self, offset); - assembly ("memory-safe") { - value := and(value, shl(160, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_20_16(bytes20 self, uint8 offset) internal pure returns (bytes16 result) { - if (offset > 4) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(128, not(0))) - } - } - - function replace_20_16(bytes20 self, bytes16 value, uint8 offset) internal pure returns (bytes20 result) { - bytes16 oldValue = extract_20_16(self, offset); - assembly ("memory-safe") { - value := and(value, shl(128, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_22_1(bytes22 self, uint8 offset) internal pure returns (bytes1 result) { - if (offset > 21) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(248, not(0))) - } - } - - function replace_22_1(bytes22 self, bytes1 value, uint8 offset) internal pure returns (bytes22 result) { - bytes1 oldValue = extract_22_1(self, offset); - assembly ("memory-safe") { - value := and(value, shl(248, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_22_2(bytes22 self, uint8 offset) internal pure returns (bytes2 result) { - if (offset > 20) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(240, not(0))) - } - } - - function replace_22_2(bytes22 self, bytes2 value, uint8 offset) internal pure returns (bytes22 result) { - bytes2 oldValue = extract_22_2(self, offset); - assembly ("memory-safe") { - value := and(value, shl(240, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_22_4(bytes22 self, uint8 offset) internal pure returns (bytes4 result) { - if (offset > 18) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(224, not(0))) - } - } - - function replace_22_4(bytes22 self, bytes4 value, uint8 offset) internal pure returns (bytes22 result) { - bytes4 oldValue = extract_22_4(self, offset); - assembly ("memory-safe") { - value := and(value, shl(224, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_22_6(bytes22 self, uint8 offset) internal pure returns (bytes6 result) { - if (offset > 16) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(208, not(0))) - } - } - - function replace_22_6(bytes22 self, bytes6 value, uint8 offset) internal pure returns (bytes22 result) { - bytes6 oldValue = extract_22_6(self, offset); - assembly ("memory-safe") { - value := and(value, shl(208, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_22_8(bytes22 self, uint8 offset) internal pure returns (bytes8 result) { - if (offset > 14) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(192, not(0))) - } - } - - function replace_22_8(bytes22 self, bytes8 value, uint8 offset) internal pure returns (bytes22 result) { - bytes8 oldValue = extract_22_8(self, offset); - assembly ("memory-safe") { - value := and(value, shl(192, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_22_10(bytes22 self, uint8 offset) internal pure returns (bytes10 result) { - if (offset > 12) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(176, not(0))) - } - } - - function replace_22_10(bytes22 self, bytes10 value, uint8 offset) internal pure returns (bytes22 result) { - bytes10 oldValue = extract_22_10(self, offset); - assembly ("memory-safe") { - value := and(value, shl(176, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_22_12(bytes22 self, uint8 offset) internal pure returns (bytes12 result) { - if (offset > 10) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(160, not(0))) - } - } - - function replace_22_12(bytes22 self, bytes12 value, uint8 offset) internal pure returns (bytes22 result) { - bytes12 oldValue = extract_22_12(self, offset); - assembly ("memory-safe") { - value := and(value, shl(160, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_22_16(bytes22 self, uint8 offset) internal pure returns (bytes16 result) { - if (offset > 6) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(128, not(0))) - } - } - - function replace_22_16(bytes22 self, bytes16 value, uint8 offset) internal pure returns (bytes22 result) { - bytes16 oldValue = extract_22_16(self, offset); - assembly ("memory-safe") { - value := and(value, shl(128, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_22_20(bytes22 self, uint8 offset) internal pure returns (bytes20 result) { - if (offset > 2) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(96, not(0))) - } - } - - function replace_22_20(bytes22 self, bytes20 value, uint8 offset) internal pure returns (bytes22 result) { - bytes20 oldValue = extract_22_20(self, offset); - assembly ("memory-safe") { - value := and(value, shl(96, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_24_1(bytes24 self, uint8 offset) internal pure returns (bytes1 result) { - if (offset > 23) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(248, not(0))) - } - } - - function replace_24_1(bytes24 self, bytes1 value, uint8 offset) internal pure returns (bytes24 result) { - bytes1 oldValue = extract_24_1(self, offset); - assembly ("memory-safe") { - value := and(value, shl(248, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_24_2(bytes24 self, uint8 offset) internal pure returns (bytes2 result) { - if (offset > 22) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(240, not(0))) - } - } - - function replace_24_2(bytes24 self, bytes2 value, uint8 offset) internal pure returns (bytes24 result) { - bytes2 oldValue = extract_24_2(self, offset); - assembly ("memory-safe") { - value := and(value, shl(240, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_24_4(bytes24 self, uint8 offset) internal pure returns (bytes4 result) { - if (offset > 20) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(224, not(0))) - } - } - - function replace_24_4(bytes24 self, bytes4 value, uint8 offset) internal pure returns (bytes24 result) { - bytes4 oldValue = extract_24_4(self, offset); - assembly ("memory-safe") { - value := and(value, shl(224, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_24_6(bytes24 self, uint8 offset) internal pure returns (bytes6 result) { - if (offset > 18) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(208, not(0))) - } - } - - function replace_24_6(bytes24 self, bytes6 value, uint8 offset) internal pure returns (bytes24 result) { - bytes6 oldValue = extract_24_6(self, offset); - assembly ("memory-safe") { - value := and(value, shl(208, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_24_8(bytes24 self, uint8 offset) internal pure returns (bytes8 result) { - if (offset > 16) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(192, not(0))) - } - } - - function replace_24_8(bytes24 self, bytes8 value, uint8 offset) internal pure returns (bytes24 result) { - bytes8 oldValue = extract_24_8(self, offset); - assembly ("memory-safe") { - value := and(value, shl(192, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_24_10(bytes24 self, uint8 offset) internal pure returns (bytes10 result) { - if (offset > 14) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(176, not(0))) - } - } - - function replace_24_10(bytes24 self, bytes10 value, uint8 offset) internal pure returns (bytes24 result) { - bytes10 oldValue = extract_24_10(self, offset); - assembly ("memory-safe") { - value := and(value, shl(176, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_24_12(bytes24 self, uint8 offset) internal pure returns (bytes12 result) { - if (offset > 12) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(160, not(0))) - } - } - - function replace_24_12(bytes24 self, bytes12 value, uint8 offset) internal pure returns (bytes24 result) { - bytes12 oldValue = extract_24_12(self, offset); - assembly ("memory-safe") { - value := and(value, shl(160, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_24_16(bytes24 self, uint8 offset) internal pure returns (bytes16 result) { - if (offset > 8) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(128, not(0))) - } - } - - function replace_24_16(bytes24 self, bytes16 value, uint8 offset) internal pure returns (bytes24 result) { - bytes16 oldValue = extract_24_16(self, offset); - assembly ("memory-safe") { - value := and(value, shl(128, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_24_20(bytes24 self, uint8 offset) internal pure returns (bytes20 result) { - if (offset > 4) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(96, not(0))) - } - } - - function replace_24_20(bytes24 self, bytes20 value, uint8 offset) internal pure returns (bytes24 result) { - bytes20 oldValue = extract_24_20(self, offset); - assembly ("memory-safe") { - value := and(value, shl(96, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_24_22(bytes24 self, uint8 offset) internal pure returns (bytes22 result) { - if (offset > 2) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(80, not(0))) - } - } - - function replace_24_22(bytes24 self, bytes22 value, uint8 offset) internal pure returns (bytes24 result) { - bytes22 oldValue = extract_24_22(self, offset); - assembly ("memory-safe") { - value := and(value, shl(80, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_28_1(bytes28 self, uint8 offset) internal pure returns (bytes1 result) { - if (offset > 27) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(248, not(0))) - } - } - - function replace_28_1(bytes28 self, bytes1 value, uint8 offset) internal pure returns (bytes28 result) { - bytes1 oldValue = extract_28_1(self, offset); - assembly ("memory-safe") { - value := and(value, shl(248, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_28_2(bytes28 self, uint8 offset) internal pure returns (bytes2 result) { - if (offset > 26) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(240, not(0))) - } - } - - function replace_28_2(bytes28 self, bytes2 value, uint8 offset) internal pure returns (bytes28 result) { - bytes2 oldValue = extract_28_2(self, offset); - assembly ("memory-safe") { - value := and(value, shl(240, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_28_4(bytes28 self, uint8 offset) internal pure returns (bytes4 result) { - if (offset > 24) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(224, not(0))) - } - } - - function replace_28_4(bytes28 self, bytes4 value, uint8 offset) internal pure returns (bytes28 result) { - bytes4 oldValue = extract_28_4(self, offset); - assembly ("memory-safe") { - value := and(value, shl(224, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_28_6(bytes28 self, uint8 offset) internal pure returns (bytes6 result) { - if (offset > 22) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(208, not(0))) - } - } - - function replace_28_6(bytes28 self, bytes6 value, uint8 offset) internal pure returns (bytes28 result) { - bytes6 oldValue = extract_28_6(self, offset); - assembly ("memory-safe") { - value := and(value, shl(208, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_28_8(bytes28 self, uint8 offset) internal pure returns (bytes8 result) { - if (offset > 20) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(192, not(0))) - } - } - - function replace_28_8(bytes28 self, bytes8 value, uint8 offset) internal pure returns (bytes28 result) { - bytes8 oldValue = extract_28_8(self, offset); - assembly ("memory-safe") { - value := and(value, shl(192, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_28_10(bytes28 self, uint8 offset) internal pure returns (bytes10 result) { - if (offset > 18) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(176, not(0))) - } - } - - function replace_28_10(bytes28 self, bytes10 value, uint8 offset) internal pure returns (bytes28 result) { - bytes10 oldValue = extract_28_10(self, offset); - assembly ("memory-safe") { - value := and(value, shl(176, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_28_12(bytes28 self, uint8 offset) internal pure returns (bytes12 result) { - if (offset > 16) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(160, not(0))) - } - } - - function replace_28_12(bytes28 self, bytes12 value, uint8 offset) internal pure returns (bytes28 result) { - bytes12 oldValue = extract_28_12(self, offset); - assembly ("memory-safe") { - value := and(value, shl(160, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_28_16(bytes28 self, uint8 offset) internal pure returns (bytes16 result) { - if (offset > 12) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(128, not(0))) - } - } - - function replace_28_16(bytes28 self, bytes16 value, uint8 offset) internal pure returns (bytes28 result) { - bytes16 oldValue = extract_28_16(self, offset); - assembly ("memory-safe") { - value := and(value, shl(128, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_28_20(bytes28 self, uint8 offset) internal pure returns (bytes20 result) { - if (offset > 8) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(96, not(0))) - } - } - - function replace_28_20(bytes28 self, bytes20 value, uint8 offset) internal pure returns (bytes28 result) { - bytes20 oldValue = extract_28_20(self, offset); - assembly ("memory-safe") { - value := and(value, shl(96, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_28_22(bytes28 self, uint8 offset) internal pure returns (bytes22 result) { - if (offset > 6) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(80, not(0))) - } - } - - function replace_28_22(bytes28 self, bytes22 value, uint8 offset) internal pure returns (bytes28 result) { - bytes22 oldValue = extract_28_22(self, offset); - assembly ("memory-safe") { - value := and(value, shl(80, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_28_24(bytes28 self, uint8 offset) internal pure returns (bytes24 result) { - if (offset > 4) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(64, not(0))) - } - } - - function replace_28_24(bytes28 self, bytes24 value, uint8 offset) internal pure returns (bytes28 result) { - bytes24 oldValue = extract_28_24(self, offset); - assembly ("memory-safe") { - value := and(value, shl(64, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_32_1(bytes32 self, uint8 offset) internal pure returns (bytes1 result) { - if (offset > 31) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(248, not(0))) - } - } - - function replace_32_1(bytes32 self, bytes1 value, uint8 offset) internal pure returns (bytes32 result) { - bytes1 oldValue = extract_32_1(self, offset); - assembly ("memory-safe") { - value := and(value, shl(248, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_32_2(bytes32 self, uint8 offset) internal pure returns (bytes2 result) { - if (offset > 30) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(240, not(0))) - } - } - - function replace_32_2(bytes32 self, bytes2 value, uint8 offset) internal pure returns (bytes32 result) { - bytes2 oldValue = extract_32_2(self, offset); - assembly ("memory-safe") { - value := and(value, shl(240, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_32_4(bytes32 self, uint8 offset) internal pure returns (bytes4 result) { - if (offset > 28) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(224, not(0))) - } - } - - function replace_32_4(bytes32 self, bytes4 value, uint8 offset) internal pure returns (bytes32 result) { - bytes4 oldValue = extract_32_4(self, offset); - assembly ("memory-safe") { - value := and(value, shl(224, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_32_6(bytes32 self, uint8 offset) internal pure returns (bytes6 result) { - if (offset > 26) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(208, not(0))) - } - } - - function replace_32_6(bytes32 self, bytes6 value, uint8 offset) internal pure returns (bytes32 result) { - bytes6 oldValue = extract_32_6(self, offset); - assembly ("memory-safe") { - value := and(value, shl(208, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_32_8(bytes32 self, uint8 offset) internal pure returns (bytes8 result) { - if (offset > 24) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(192, not(0))) - } - } - - function replace_32_8(bytes32 self, bytes8 value, uint8 offset) internal pure returns (bytes32 result) { - bytes8 oldValue = extract_32_8(self, offset); - assembly ("memory-safe") { - value := and(value, shl(192, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_32_10(bytes32 self, uint8 offset) internal pure returns (bytes10 result) { - if (offset > 22) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(176, not(0))) - } - } - - function replace_32_10(bytes32 self, bytes10 value, uint8 offset) internal pure returns (bytes32 result) { - bytes10 oldValue = extract_32_10(self, offset); - assembly ("memory-safe") { - value := and(value, shl(176, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_32_12(bytes32 self, uint8 offset) internal pure returns (bytes12 result) { - if (offset > 20) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(160, not(0))) - } - } - - function replace_32_12(bytes32 self, bytes12 value, uint8 offset) internal pure returns (bytes32 result) { - bytes12 oldValue = extract_32_12(self, offset); - assembly ("memory-safe") { - value := and(value, shl(160, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_32_16(bytes32 self, uint8 offset) internal pure returns (bytes16 result) { - if (offset > 16) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(128, not(0))) - } - } - - function replace_32_16(bytes32 self, bytes16 value, uint8 offset) internal pure returns (bytes32 result) { - bytes16 oldValue = extract_32_16(self, offset); - assembly ("memory-safe") { - value := and(value, shl(128, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_32_20(bytes32 self, uint8 offset) internal pure returns (bytes20 result) { - if (offset > 12) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(96, not(0))) - } - } - - function replace_32_20(bytes32 self, bytes20 value, uint8 offset) internal pure returns (bytes32 result) { - bytes20 oldValue = extract_32_20(self, offset); - assembly ("memory-safe") { - value := and(value, shl(96, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_32_22(bytes32 self, uint8 offset) internal pure returns (bytes22 result) { - if (offset > 10) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(80, not(0))) - } - } - - function replace_32_22(bytes32 self, bytes22 value, uint8 offset) internal pure returns (bytes32 result) { - bytes22 oldValue = extract_32_22(self, offset); - assembly ("memory-safe") { - value := and(value, shl(80, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_32_24(bytes32 self, uint8 offset) internal pure returns (bytes24 result) { - if (offset > 8) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(64, not(0))) - } - } - - function replace_32_24(bytes32 self, bytes24 value, uint8 offset) internal pure returns (bytes32 result) { - bytes24 oldValue = extract_32_24(self, offset); - assembly ("memory-safe") { - value := and(value, shl(64, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } - - function extract_32_28(bytes32 self, uint8 offset) internal pure returns (bytes28 result) { - if (offset > 4) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := and(shl(mul(8, offset), self), shl(32, not(0))) - } - } - - function replace_32_28(bytes32 self, bytes28 value, uint8 offset) internal pure returns (bytes32 result) { - bytes28 oldValue = extract_32_28(self, offset); - assembly ("memory-safe") { - value := and(value, shl(32, not(0))) - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Panic.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Panic.sol deleted file mode 100644 index e168824..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Panic.sol +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol) - -pragma solidity ^0.8.20; - -/** - * @dev Helper library for emitting standardized panic codes. - * - * ```solidity - * contract Example { - * using Panic for uint256; - * - * // Use any of the declared internal constants - * function foo() { Panic.GENERIC.panic(); } - * - * // Alternatively - * function foo() { Panic.panic(Panic.GENERIC); } - * } - * ``` - * - * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil]. - * - * _Available since v5.1._ - */ -// slither-disable-next-line unused-state -library Panic { - /// @dev generic / unspecified error - uint256 internal constant GENERIC = 0x00; - /// @dev used by the assert() builtin - uint256 internal constant ASSERT = 0x01; - /// @dev arithmetic underflow or overflow - uint256 internal constant UNDER_OVERFLOW = 0x11; - /// @dev division or modulo by zero - uint256 internal constant DIVISION_BY_ZERO = 0x12; - /// @dev enum conversion error - uint256 internal constant ENUM_CONVERSION_ERROR = 0x21; - /// @dev invalid encoding in storage - uint256 internal constant STORAGE_ENCODING_ERROR = 0x22; - /// @dev empty array pop - uint256 internal constant EMPTY_ARRAY_POP = 0x31; - /// @dev array out of bounds access - uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32; - /// @dev resource error (too large allocation or too large array) - uint256 internal constant RESOURCE_ERROR = 0x41; - /// @dev calling invalid internal function - uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51; - - /// @dev Reverts with a panic code. Recommended to use with - /// the internal constants with predefined codes. - function panic(uint256 code) internal pure { - assembly ("memory-safe") { - mstore(0x00, 0x4e487b71) - mstore(0x20, code) - revert(0x1c, 0x24) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Pausable.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Pausable.sol deleted file mode 100644 index 68e7d26..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Pausable.sol +++ /dev/null @@ -1,112 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.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 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/README.adoc deleted file mode 100644 index 231bccd..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/README.adoc +++ /dev/null @@ -1,139 +0,0 @@ -= 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. - - * {Math}, {SignedMath}: Implementation of various arithmetic functions. - * {SafeCast}: Checked downcasting functions to avoid silent truncation. - * {ReentrancyGuard}: A modifier that can prevent reentrancy during certain functions. - * {ReentrancyGuardTransient}: Variant of {ReentrancyGuard} that uses transient storage (https://eips.ethereum.org/EIPS/eip-1153[EIP-1153]). - * {Pausable}: A common emergency response mechanism that can pause functionality while a remediation is pending. - * {Nonces}: Utility for tracking and verifying address nonces that only increment. - * {NoncesKeyed}: Alternative to {Nonces}, that support keyed nonces following https://eips.ethereum.org/EIPS/eip-4337#semi-abstracted-nonce-support[ERC-4337 specifications]. - * {ERC165}, {ERC165Checker}: Utilities for inspecting interfaces supported by contracts. - * {BitMaps}: A simple library to manage boolean value mapped to a numerical index in an efficient way. - * {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. - * {DoubleEndedQueue}: An implementation of a https://en.wikipedia.org/wiki/Double-ended_queue[double ended queue] whose values can be added or removed from both sides. Useful for FIFO and LIFO structures. - * {CircularBuffer}: A data structure to store the last N values pushed to it. - * {Checkpoints}: A data structure to store values mapped to a strictly increasing key. Can be used for storing and accessing values over time. - * {Heap}: A library that implements a https://en.wikipedia.org/wiki/Binary_heap[binary heap] in storage. - * {MerkleTree}: A library with https://wikipedia.org/wiki/Merkle_Tree[Merkle Tree] data structures and helper functions. - * {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. - * {Address}: Collection of functions for overloading Solidity's https://docs.soliditylang.org/en/latest/types.html#address[`address`] type. - * {Arrays}: Collection of functions that operate on https://docs.soliditylang.org/en/latest/types.html#arrays[`arrays`]. - * {Base64}: On-chain base64 and base64URL encoding according to https://datatracker.ietf.org/doc/html/rfc4648[RFC-4648]. - * {Bytes}: Common operations on bytes objects. - * {Calldata}: Helpers for manipulating calldata. - * {Strings}: Common operations for strings formatting. - * {ShortStrings}: Library to encode (and decode) short strings into (or from) a single bytes32 slot for optimizing costs. Short strings are limited to 31 characters. - * {SlotDerivation}: Methods for deriving storage slot from ERC-7201 namespaces as well as from constructions such as mapping and arrays. - * {StorageSlot}: Methods for accessing specific storage slots formatted as common primitive types. - * {TransientSlot}: Primitives for reading from and writing to transient storage (only value types are currently supported). - * {Multicall}: Abstract contract with a utility to allow batching together multiple calls in a single transaction. Useful for allowing EOAs to perform multiple operations at once. - * {Context}: A utility for abstracting the sender and calldata in the current execution context. - * {Packing}: A library for packing and unpacking multiple values into bytes32 - * {Panic}: A library to revert with https://docs.soliditylang.org/en/v0.8.20/control-structures.html#panic-via-assert-and-error-via-require[Solidity panic codes]. - * {Comparators}: A library that contains comparator functions to use with the {Heap} library. - * {CAIP2}, {CAIP10}: Libraries for formatting and parsing CAIP-2 and CAIP-10 identifiers. - * {Blockhash}: A library for accessing historical block hashes beyond the standard 256 block limit utilizing EIP-2935's historical blockhash functionality. - * {Time}: A library that provides helpers for manipulating time-related objects, including a `Delay` type. - -[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}} - -== Security - -{{ReentrancyGuard}} - -{{ReentrancyGuardTransient}} - -{{Pausable}} - -{{Nonces}} - -{{NoncesKeyed}} - -== 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. ERC-20 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}} - -{{CircularBuffer}} - -{{Checkpoints}} - -{{Heap}} - -{{MerkleTree}} - -== Libraries - -{{Create2}} - -{{Address}} - -{{Arrays}} - -{{Base64}} - -{{Bytes}} - -{{Calldata}} - -{{Strings}} - -{{ShortStrings}} - -{{SlotDerivation}} - -{{StorageSlot}} - -{{TransientSlot}} - -{{Multicall}} - -{{Context}} - -{{Packing}} - -{{Panic}} - -{{Comparators}} - -{{CAIP2}} - -{{CAIP10}} - -{{Blockhash}} - -{{Time}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol deleted file mode 100644 index a95fb51..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.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 EIP-1153 (transient storage) is available on the chain you're deploying at, - * consider using {ReentrancyGuardTransient} instead. - * - * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuardTransient.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuardTransient.sol deleted file mode 100644 index a1318c8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuardTransient.sol +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (utils/ReentrancyGuardTransient.sol) - -pragma solidity ^0.8.24; - -import {TransientSlot} from "./TransientSlot.sol"; - -/** - * @dev Variant of {ReentrancyGuard} that uses transient storage. - * - * NOTE: This variant only works on networks where EIP-1153 is available. - * - * _Available since v5.1._ - */ -abstract contract ReentrancyGuardTransient { - using TransientSlot for *; - - // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) - bytes32 private constant REENTRANCY_GUARD_STORAGE = - 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; - - /** - * @dev Unauthorized reentrant call. - */ - error ReentrancyGuardReentrantCall(); - - /** - * @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, REENTRANCY_GUARD_STORAGE.asBoolean().tload() will be false - if (_reentrancyGuardEntered()) { - revert ReentrancyGuardReentrantCall(); - } - - // Any calls to nonReentrant after this point will fail - REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true); - } - - function _nonReentrantAfter() private { - REENTRANCY_GUARD_STORAGE.asBoolean().tstore(false); - } - - /** - * @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 REENTRANCY_GUARD_STORAGE.asBoolean().tload(); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol deleted file mode 100644 index 81d713d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.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); - assembly ("memory-safe") { - 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 {toShortStringWithFallback}. - */ - 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 - * {toShortStringWithFallback}. - * - * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/SlotDerivation.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/SlotDerivation.sol deleted file mode 100644 index df23efa..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/SlotDerivation.sol +++ /dev/null @@ -1,155 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol) -// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js. - -pragma solidity ^0.8.20; - -/** - * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots - * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by - * the solidity language / compiler. - * - * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.]. - * - * Example usage: - * ```solidity - * contract Example { - * // Add the library methods - * using StorageSlot for bytes32; - * using SlotDerivation for bytes32; - * - * // Declare a namespace - * string private constant _NAMESPACE = ""; // eg. OpenZeppelin.Slot - * - * function setValueInNamespace(uint256 key, address newValue) internal { - * _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue; - * } - * - * function getValueInNamespace(uint256 key) internal view returns (address) { - * return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value; - * } - * } - * ``` - * - * TIP: Consider using this library along with {StorageSlot}. - * - * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking - * upgrade safety will ignore the slots accessed through this library. - * - * _Available since v5.1._ - */ -library SlotDerivation { - /** - * @dev Derive an ERC-7201 slot from a string (namespace). - */ - function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) { - assembly ("memory-safe") { - mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1)) - slot := and(keccak256(0x00, 0x20), not(0xff)) - } - } - - /** - * @dev Add an offset to a slot to get the n-th element of a structure or an array. - */ - function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) { - unchecked { - return bytes32(uint256(slot) + pos); - } - } - - /** - * @dev Derive the location of the first element in an array from the slot where the length is stored. - */ - function deriveArray(bytes32 slot) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - mstore(0x00, slot) - result := keccak256(0x00, 0x20) - } - } - - /** - * @dev Derive the location of a mapping element from the key. - */ - function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - mstore(0x00, and(key, shr(96, not(0)))) - mstore(0x20, slot) - result := keccak256(0x00, 0x40) - } - } - - /** - * @dev Derive the location of a mapping element from the key. - */ - function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - mstore(0x00, iszero(iszero(key))) - mstore(0x20, slot) - result := keccak256(0x00, 0x40) - } - } - - /** - * @dev Derive the location of a mapping element from the key. - */ - function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - mstore(0x00, key) - mstore(0x20, slot) - result := keccak256(0x00, 0x40) - } - } - - /** - * @dev Derive the location of a mapping element from the key. - */ - function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - mstore(0x00, key) - mstore(0x20, slot) - result := keccak256(0x00, 0x40) - } - } - - /** - * @dev Derive the location of a mapping element from the key. - */ - function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - mstore(0x00, key) - mstore(0x20, slot) - result := keccak256(0x00, 0x40) - } - } - - /** - * @dev Derive the location of a mapping element from the key. - */ - function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - let length := mload(key) - let begin := add(key, 0x20) - let end := add(begin, length) - let cache := mload(end) - mstore(end, slot) - result := keccak256(begin, add(length, 0x20)) - mstore(end, cache) - } - } - - /** - * @dev Derive the location of a mapping element from the key. - */ - function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - let length := mload(key) - let begin := add(key, 0x20) - let end := add(begin, length) - let cache := mload(end) - mstore(end, slot) - result := keccak256(begin, add(length, 0x20)) - mstore(end, cache) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol deleted file mode 100644 index aebb105..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.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 ERC-1967 implementation slot: - * ```solidity - * contract ERC1967 { - * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. - * 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; - * } - * } - * ``` - * - * TIP: Consider using this library along with {SlotDerivation}. - */ -library StorageSlot { - struct AddressSlot { - address value; - } - - struct BooleanSlot { - bool value; - } - - struct Bytes32Slot { - bytes32 value; - } - - struct Uint256Slot { - uint256 value; - } - - struct Int256Slot { - int256 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) { - assembly ("memory-safe") { - r.slot := slot - } - } - - /** - * @dev Returns a `BooleanSlot` with member `value` located at `slot`. - */ - function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { - assembly ("memory-safe") { - r.slot := slot - } - } - - /** - * @dev Returns a `Bytes32Slot` with member `value` located at `slot`. - */ - function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { - assembly ("memory-safe") { - r.slot := slot - } - } - - /** - * @dev Returns a `Uint256Slot` with member `value` located at `slot`. - */ - function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { - assembly ("memory-safe") { - r.slot := slot - } - } - - /** - * @dev Returns a `Int256Slot` with member `value` located at `slot`. - */ - function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) { - assembly ("memory-safe") { - r.slot := slot - } - } - - /** - * @dev Returns a `StringSlot` with member `value` located at `slot`. - */ - function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { - assembly ("memory-safe") { - 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) { - assembly ("memory-safe") { - r.slot := store.slot - } - } - - /** - * @dev Returns a `BytesSlot` with member `value` located at `slot`. - */ - function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { - assembly ("memory-safe") { - 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) { - assembly ("memory-safe") { - r.slot := store.slot - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Strings.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Strings.sol deleted file mode 100644 index a2d934d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/Strings.sol +++ /dev/null @@ -1,490 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/Strings.sol) - -pragma solidity ^0.8.20; - -import {Math} from "./math/Math.sol"; -import {SafeCast} from "./math/SafeCast.sol"; -import {SignedMath} from "./math/SignedMath.sol"; - -/** - * @dev String operations. - */ -library Strings { - using SafeCast for *; - - bytes16 private constant HEX_DIGITS = "0123456789abcdef"; - uint8 private constant ADDRESS_LENGTH = 20; - uint256 private constant SPECIAL_CHARS_LOOKUP = - (1 << 0x08) | // backspace - (1 << 0x09) | // tab - (1 << 0x0a) | // newline - (1 << 0x0c) | // form feed - (1 << 0x0d) | // carriage return - (1 << 0x22) | // double quote - (1 << 0x5c); // backslash - - /** - * @dev The `value` string doesn't fit in the specified `length`. - */ - error StringsInsufficientHexLength(uint256 value, uint256 length); - - /** - * @dev The string being parsed contains characters that are not in scope of the given base. - */ - error StringsInvalidChar(); - - /** - * @dev The string being parsed is not a properly formatted address. - */ - error StringsInvalidAddressFormat(); - - /** - * @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; - assembly ("memory-safe") { - ptr := add(add(buffer, 0x20), length) - } - while (true) { - ptr--; - assembly ("memory-safe") { - 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 Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal - * representation, according to EIP-55. - */ - function toChecksumHexString(address addr) internal pure returns (string memory) { - bytes memory buffer = bytes(toHexString(addr)); - - // hash the hex part of buffer (skip length + 2 bytes, length 40) - uint256 hashValue; - assembly ("memory-safe") { - hashValue := shr(96, keccak256(add(buffer, 0x22), 40)) - } - - for (uint256 i = 41; i > 1; --i) { - // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f) - if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) { - // case shift by xoring with 0x20 - buffer[i] ^= 0x20; - } - hashValue >>= 4; - } - return string(buffer); - } - - /** - * @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)); - } - - /** - * @dev Parse a decimal string and returns the value as a `uint256`. - * - * Requirements: - * - The string must be formatted as `[0-9]*` - * - The result must fit into an `uint256` type - */ - function parseUint(string memory input) internal pure returns (uint256) { - return parseUint(input, 0, bytes(input).length); - } - - /** - * @dev Variant of {parseUint-string} that parses a substring of `input` located between position `begin` (included) and - * `end` (excluded). - * - * Requirements: - * - The substring must be formatted as `[0-9]*` - * - The result must fit into an `uint256` type - */ - function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) { - (bool success, uint256 value) = tryParseUint(input, begin, end); - if (!success) revert StringsInvalidChar(); - return value; - } - - /** - * @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character. - * - * NOTE: This function will revert if the result does not fit in a `uint256`. - */ - function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) { - return _tryParseUintUncheckedBounds(input, 0, bytes(input).length); - } - - /** - * @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid - * character. - * - * NOTE: This function will revert if the result does not fit in a `uint256`. - */ - function tryParseUint( - string memory input, - uint256 begin, - uint256 end - ) internal pure returns (bool success, uint256 value) { - if (end > bytes(input).length || begin > end) return (false, 0); - return _tryParseUintUncheckedBounds(input, begin, end); - } - - /** - * @dev Implementation of {tryParseUint-string-uint256-uint256} that does not check bounds. Caller should make sure that - * `begin <= end <= input.length`. Other inputs would result in undefined behavior. - */ - function _tryParseUintUncheckedBounds( - string memory input, - uint256 begin, - uint256 end - ) private pure returns (bool success, uint256 value) { - bytes memory buffer = bytes(input); - - uint256 result = 0; - for (uint256 i = begin; i < end; ++i) { - uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i))); - if (chr > 9) return (false, 0); - result *= 10; - result += chr; - } - return (true, result); - } - - /** - * @dev Parse a decimal string and returns the value as a `int256`. - * - * Requirements: - * - The string must be formatted as `[-+]?[0-9]*` - * - The result must fit in an `int256` type. - */ - function parseInt(string memory input) internal pure returns (int256) { - return parseInt(input, 0, bytes(input).length); - } - - /** - * @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and - * `end` (excluded). - * - * Requirements: - * - The substring must be formatted as `[-+]?[0-9]*` - * - The result must fit in an `int256` type. - */ - function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) { - (bool success, int256 value) = tryParseInt(input, begin, end); - if (!success) revert StringsInvalidChar(); - return value; - } - - /** - * @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if - * the result does not fit in a `int256`. - * - * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`. - */ - function tryParseInt(string memory input) internal pure returns (bool success, int256 value) { - return _tryParseIntUncheckedBounds(input, 0, bytes(input).length); - } - - uint256 private constant ABS_MIN_INT256 = 2 ** 255; - - /** - * @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid - * character or if the result does not fit in a `int256`. - * - * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`. - */ - function tryParseInt( - string memory input, - uint256 begin, - uint256 end - ) internal pure returns (bool success, int256 value) { - if (end > bytes(input).length || begin > end) return (false, 0); - return _tryParseIntUncheckedBounds(input, begin, end); - } - - /** - * @dev Implementation of {tryParseInt-string-uint256-uint256} that does not check bounds. Caller should make sure that - * `begin <= end <= input.length`. Other inputs would result in undefined behavior. - */ - function _tryParseIntUncheckedBounds( - string memory input, - uint256 begin, - uint256 end - ) private pure returns (bool success, int256 value) { - bytes memory buffer = bytes(input); - - // Check presence of a negative sign. - bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty - bool positiveSign = sign == bytes1("+"); - bool negativeSign = sign == bytes1("-"); - uint256 offset = (positiveSign || negativeSign).toUint(); - - (bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end); - - if (absSuccess && absValue < ABS_MIN_INT256) { - return (true, negativeSign ? -int256(absValue) : int256(absValue)); - } else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) { - return (true, type(int256).min); - } else return (false, 0); - } - - /** - * @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as a `uint256`. - * - * Requirements: - * - The string must be formatted as `(0x)?[0-9a-fA-F]*` - * - The result must fit in an `uint256` type. - */ - function parseHexUint(string memory input) internal pure returns (uint256) { - return parseHexUint(input, 0, bytes(input).length); - } - - /** - * @dev Variant of {parseHexUint-string} that parses a substring of `input` located between position `begin` (included) and - * `end` (excluded). - * - * Requirements: - * - The substring must be formatted as `(0x)?[0-9a-fA-F]*` - * - The result must fit in an `uint256` type. - */ - function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) { - (bool success, uint256 value) = tryParseHexUint(input, begin, end); - if (!success) revert StringsInvalidChar(); - return value; - } - - /** - * @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character. - * - * NOTE: This function will revert if the result does not fit in a `uint256`. - */ - function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) { - return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length); - } - - /** - * @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an - * invalid character. - * - * NOTE: This function will revert if the result does not fit in a `uint256`. - */ - function tryParseHexUint( - string memory input, - uint256 begin, - uint256 end - ) internal pure returns (bool success, uint256 value) { - if (end > bytes(input).length || begin > end) return (false, 0); - return _tryParseHexUintUncheckedBounds(input, begin, end); - } - - /** - * @dev Implementation of {tryParseHexUint-string-uint256-uint256} that does not check bounds. Caller should make sure that - * `begin <= end <= input.length`. Other inputs would result in undefined behavior. - */ - function _tryParseHexUintUncheckedBounds( - string memory input, - uint256 begin, - uint256 end - ) private pure returns (bool success, uint256 value) { - bytes memory buffer = bytes(input); - - // skip 0x prefix if present - bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty - uint256 offset = hasPrefix.toUint() * 2; - - uint256 result = 0; - for (uint256 i = begin + offset; i < end; ++i) { - uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i))); - if (chr > 15) return (false, 0); - result *= 16; - unchecked { - // Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check). - // This guarantees that adding a value < 16 will not cause an overflow, hence the unchecked. - result += chr; - } - } - return (true, result); - } - - /** - * @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as an `address`. - * - * Requirements: - * - The string must be formatted as `(0x)?[0-9a-fA-F]{40}` - */ - function parseAddress(string memory input) internal pure returns (address) { - return parseAddress(input, 0, bytes(input).length); - } - - /** - * @dev Variant of {parseAddress-string} that parses a substring of `input` located between position `begin` (included) and - * `end` (excluded). - * - * Requirements: - * - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}` - */ - function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) { - (bool success, address value) = tryParseAddress(input, begin, end); - if (!success) revert StringsInvalidAddressFormat(); - return value; - } - - /** - * @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly - * formatted address. See {parseAddress-string} requirements. - */ - function tryParseAddress(string memory input) internal pure returns (bool success, address value) { - return tryParseAddress(input, 0, bytes(input).length); - } - - /** - * @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly - * formatted address. See {parseAddress-string-uint256-uint256} requirements. - */ - function tryParseAddress( - string memory input, - uint256 begin, - uint256 end - ) internal pure returns (bool success, address value) { - if (end > bytes(input).length || begin > end) return (false, address(0)); - - bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty - uint256 expectedLength = 40 + hasPrefix.toUint() * 2; - - // check that input is the correct length - if (end - begin == expectedLength) { - // length guarantees that this does not overflow, and value is at most type(uint160).max - (bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end); - return (s, address(uint160(v))); - } else { - return (false, address(0)); - } - } - - function _tryParseChr(bytes1 chr) private pure returns (uint8) { - uint8 value = uint8(chr); - - // Try to parse `chr`: - // - Case 1: [0-9] - // - Case 2: [a-f] - // - Case 3: [A-F] - // - otherwise not supported - unchecked { - if (value > 47 && value < 58) value -= 48; - else if (value > 96 && value < 103) value -= 87; - else if (value > 64 && value < 71) value -= 55; - else return type(uint8).max; - } - - return value; - } - - /** - * @dev Escape special characters in JSON strings. This can be useful to prevent JSON injection in NFT metadata. - * - * WARNING: This function should only be used in double quoted JSON strings. Single quotes are not escaped. - * - * NOTE: This function escapes all unicode characters, and not just the ones in ranges defined in section 2.5 of - * RFC-4627 (U+0000 to U+001F, U+0022 and U+005C). ECMAScript's `JSON.parse` does recover escaped unicode - * characters that are not in this range, but other tooling may provide different results. - */ - function escapeJSON(string memory input) internal pure returns (string memory) { - bytes memory buffer = bytes(input); - bytes memory output = new bytes(2 * buffer.length); // worst case scenario - uint256 outputLength = 0; - - for (uint256 i; i < buffer.length; ++i) { - bytes1 char = bytes1(_unsafeReadBytesOffset(buffer, i)); - if (((SPECIAL_CHARS_LOOKUP & (1 << uint8(char))) != 0)) { - output[outputLength++] = "\\"; - if (char == 0x08) output[outputLength++] = "b"; - else if (char == 0x09) output[outputLength++] = "t"; - else if (char == 0x0a) output[outputLength++] = "n"; - else if (char == 0x0c) output[outputLength++] = "f"; - else if (char == 0x0d) output[outputLength++] = "r"; - else if (char == 0x5c) output[outputLength++] = "\\"; - else if (char == 0x22) { - // solhint-disable-next-line quotes - output[outputLength++] = '"'; - } - } else { - output[outputLength++] = char; - } - } - // write the actual length and deallocate unused memory - assembly ("memory-safe") { - mstore(output, outputLength) - mstore(0x40, add(output, shl(5, shr(5, add(outputLength, 63))))) - } - - return string(output); - } - - /** - * @dev Reads a bytes32 from a bytes array without bounds checking. - * - * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the - * assembly block as such would prevent some optimizations. - */ - function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) { - // This is not memory safe in the general case, but all calls to this private function are within bounds. - assembly ("memory-safe") { - value := mload(add(add(buffer, 0x20), offset)) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/TransientSlot.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/TransientSlot.sol deleted file mode 100644 index f0caea1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/TransientSlot.sol +++ /dev/null @@ -1,183 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (utils/TransientSlot.sol) -// This file was procedurally generated from scripts/generate/templates/TransientSlot.js. - -pragma solidity ^0.8.24; - -/** - * @dev Library for reading and writing value-types to specific transient storage slots. - * - * Transient slots are often used to store temporary values that are removed after the current transaction. - * This library helps with reading and writing to such slots without the need for inline assembly. - * - * * Example reading and writing values using transient storage: - * ```solidity - * contract Lock { - * using TransientSlot for *; - * - * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. - * bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542; - * - * modifier locked() { - * require(!_LOCK_SLOT.asBoolean().tload()); - * - * _LOCK_SLOT.asBoolean().tstore(true); - * _; - * _LOCK_SLOT.asBoolean().tstore(false); - * } - * } - * ``` - * - * TIP: Consider using this library along with {SlotDerivation}. - */ -library TransientSlot { - /** - * @dev UDVT that represents a slot holding an address. - */ - type AddressSlot is bytes32; - - /** - * @dev Cast an arbitrary slot to a AddressSlot. - */ - function asAddress(bytes32 slot) internal pure returns (AddressSlot) { - return AddressSlot.wrap(slot); - } - - /** - * @dev UDVT that represents a slot holding a bool. - */ - type BooleanSlot is bytes32; - - /** - * @dev Cast an arbitrary slot to a BooleanSlot. - */ - function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) { - return BooleanSlot.wrap(slot); - } - - /** - * @dev UDVT that represents a slot holding a bytes32. - */ - type Bytes32Slot is bytes32; - - /** - * @dev Cast an arbitrary slot to a Bytes32Slot. - */ - function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) { - return Bytes32Slot.wrap(slot); - } - - /** - * @dev UDVT that represents a slot holding a uint256. - */ - type Uint256Slot is bytes32; - - /** - * @dev Cast an arbitrary slot to a Uint256Slot. - */ - function asUint256(bytes32 slot) internal pure returns (Uint256Slot) { - return Uint256Slot.wrap(slot); - } - - /** - * @dev UDVT that represents a slot holding a int256. - */ - type Int256Slot is bytes32; - - /** - * @dev Cast an arbitrary slot to a Int256Slot. - */ - function asInt256(bytes32 slot) internal pure returns (Int256Slot) { - return Int256Slot.wrap(slot); - } - - /** - * @dev Load the value held at location `slot` in transient storage. - */ - function tload(AddressSlot slot) internal view returns (address value) { - assembly ("memory-safe") { - value := tload(slot) - } - } - - /** - * @dev Store `value` at location `slot` in transient storage. - */ - function tstore(AddressSlot slot, address value) internal { - assembly ("memory-safe") { - tstore(slot, value) - } - } - - /** - * @dev Load the value held at location `slot` in transient storage. - */ - function tload(BooleanSlot slot) internal view returns (bool value) { - assembly ("memory-safe") { - value := tload(slot) - } - } - - /** - * @dev Store `value` at location `slot` in transient storage. - */ - function tstore(BooleanSlot slot, bool value) internal { - assembly ("memory-safe") { - tstore(slot, value) - } - } - - /** - * @dev Load the value held at location `slot` in transient storage. - */ - function tload(Bytes32Slot slot) internal view returns (bytes32 value) { - assembly ("memory-safe") { - value := tload(slot) - } - } - - /** - * @dev Store `value` at location `slot` in transient storage. - */ - function tstore(Bytes32Slot slot, bytes32 value) internal { - assembly ("memory-safe") { - tstore(slot, value) - } - } - - /** - * @dev Load the value held at location `slot` in transient storage. - */ - function tload(Uint256Slot slot) internal view returns (uint256 value) { - assembly ("memory-safe") { - value := tload(slot) - } - } - - /** - * @dev Store `value` at location `slot` in transient storage. - */ - function tstore(Uint256Slot slot, uint256 value) internal { - assembly ("memory-safe") { - tstore(slot, value) - } - } - - /** - * @dev Load the value held at location `slot` in transient storage. - */ - function tload(Int256Slot slot) internal view returns (int256 value) { - assembly ("memory-safe") { - value := tload(slot) - } - } - - /** - * @dev Store `value` at location `slot` in transient storage. - */ - function tstore(Int256Slot slot, int256 value) internal { - assembly ("memory-safe") { - tstore(slot, value) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol deleted file mode 100644 index 6493f56..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol +++ /dev/null @@ -1,180 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.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 recovered, RecoverError err, bytes32 errArg) { - 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. - assembly ("memory-safe") { - 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[ERC-2098 short signatures] - */ - function tryRecover( - bytes32 hash, - bytes32 r, - bytes32 vs - ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) { - 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 recovered, RecoverError err, bytes32 errArg) { - // 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol deleted file mode 100644 index 6400cbc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol +++ /dev/null @@ -1,160 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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; - // slither-disable-next-line constable-states - string private _nameFallback; - // slither-disable-next-line constable-states - 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); - } - - /// @inheritdoc IERC5267 - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/Hashes.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/Hashes.sol deleted file mode 100644 index 48c9bbe..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/Hashes.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/Hashes.sol) - -pragma solidity ^0.8.20; - -/** - * @dev Library of standard hash functions. - * - * _Available since v5.1._ - */ -library Hashes { - /** - * @dev Commutative Keccak256 hash of a sorted pair of bytes32. Frequently used when working with merkle proofs. - * - * NOTE: Equivalent to the `standardNodeHash` in our https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. - */ - function commutativeKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32) { - return a < b ? efficientKeccak256(a, b) : efficientKeccak256(b, a); - } - - /** - * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory. - */ - function efficientKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32 value) { - assembly ("memory-safe") { - mstore(0x00, a) - mstore(0x20, b) - value := keccak256(0x00, 0x40) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol deleted file mode 100644 index 19b09e2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol +++ /dev/null @@ -1,514 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/MerkleProof.sol) -// This file was procedurally generated from scripts/generate/templates/MerkleProof.js. - -pragma solidity ^0.8.20; - -import {Hashes} from "./Hashes.sol"; - -/** - * @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. - * - * IMPORTANT: Consider memory side-effects when using custom hashing functions - * that access memory in an unsafe way. - * - * NOTE: This library supports proof verification for merkle trees built using - * custom _commutative_ hashing functions (i.e. `H(a, b) == H(b, a)`). Proving - * leaf inclusion in trees built using non-commutative hashing functions requires - * additional logic that is not supported by this library. - */ -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. - * - * This version handles proofs in memory with the default hashing function. - */ - function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { - return processProof(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 leaves & pre-images are assumed to be sorted. - * - * This version handles proofs in memory with the default hashing function. - */ - function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { - bytes32 computedHash = leaf; - for (uint256 i = 0; i < proof.length; i++) { - computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]); - } - return computedHash; - } - - /** - * @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. - * - * This version handles proofs in memory with a custom hashing function. - */ - function verify( - bytes32[] memory proof, - bytes32 root, - bytes32 leaf, - function(bytes32, bytes32) view returns (bytes32) hasher - ) internal view returns (bool) { - return processProof(proof, leaf, hasher) == 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 leaves & pre-images are assumed to be sorted. - * - * This version handles proofs in memory with a custom hashing function. - */ - function processProof( - bytes32[] memory proof, - bytes32 leaf, - function(bytes32, bytes32) view returns (bytes32) hasher - ) internal view returns (bytes32) { - bytes32 computedHash = leaf; - for (uint256 i = 0; i < proof.length; i++) { - computedHash = hasher(computedHash, proof[i]); - } - return computedHash; - } - - /** - * @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. - * - * This version handles proofs in calldata with the default hashing function. - */ - 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 leaves & pre-images are assumed to be sorted. - * - * This version handles proofs in calldata with the default hashing function. - */ - function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { - bytes32 computedHash = leaf; - for (uint256 i = 0; i < proof.length; i++) { - computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]); - } - return computedHash; - } - - /** - * @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. - * - * This version handles proofs in calldata with a custom hashing function. - */ - function verifyCalldata( - bytes32[] calldata proof, - bytes32 root, - bytes32 leaf, - function(bytes32, bytes32) view returns (bytes32) hasher - ) internal view returns (bool) { - return processProofCalldata(proof, leaf, hasher) == 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 leaves & pre-images are assumed to be sorted. - * - * This version handles proofs in calldata with a custom hashing function. - */ - function processProofCalldata( - bytes32[] calldata proof, - bytes32 leaf, - function(bytes32, bytes32) view returns (bytes32) hasher - ) internal view returns (bytes32) { - bytes32 computedHash = leaf; - for (uint256 i = 0; i < proof.length; i++) { - computedHash = hasher(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}. - * - * This version handles multiproofs in memory with the default hashing function. - * - * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. - * - * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`. - * The `leaves` must be validated independently. See {processMultiProof}. - */ - function multiProofVerify( - bytes32[] memory proof, - bool[] memory proofFlags, - bytes32 root, - bytes32[] memory leaves - ) internal pure returns (bool) { - return processMultiProof(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. - * - * This version handles multiproofs in memory with the default hashing function. - * - * 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). - * - * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op, - * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not - * validating the leaves elsewhere. - */ - 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 proofFlagsLen = proofFlags.length; - - // Check proof validity. - if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen); - 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 < proofFlagsLen; i++) { - bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; - bytes32 b = proofFlags[i] - ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) - : proof[proofPos++]; - hashes[i] = Hashes.commutativeKeccak256(a, b); - } - - if (proofFlagsLen > 0) { - if (proofPos != proof.length) { - revert MerkleProofInvalidMultiproof(); - } - unchecked { - return hashes[proofFlagsLen - 1]; - } - } else if (leavesLen > 0) { - return leaves[0]; - } else { - return proof[0]; - } - } - - /** - * @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}. - * - * This version handles multiproofs in memory with a custom hashing function. - * - * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. - * - * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`. - * The `leaves` must be validated independently. See {processMultiProof}. - */ - function multiProofVerify( - bytes32[] memory proof, - bool[] memory proofFlags, - bytes32 root, - bytes32[] memory leaves, - function(bytes32, bytes32) view returns (bytes32) hasher - ) internal view returns (bool) { - return processMultiProof(proof, proofFlags, leaves, hasher) == 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. - * - * This version handles multiproofs in memory with a custom hashing function. - * - * 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). - * - * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op, - * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not - * validating the leaves elsewhere. - */ - function processMultiProof( - bytes32[] memory proof, - bool[] memory proofFlags, - bytes32[] memory leaves, - function(bytes32, bytes32) view returns (bytes32) hasher - ) internal view 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 proofFlagsLen = proofFlags.length; - - // Check proof validity. - if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen); - 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 < proofFlagsLen; i++) { - bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; - bytes32 b = proofFlags[i] - ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) - : proof[proofPos++]; - hashes[i] = hasher(a, b); - } - - if (proofFlagsLen > 0) { - if (proofPos != proof.length) { - revert MerkleProofInvalidMultiproof(); - } - unchecked { - return hashes[proofFlagsLen - 1]; - } - } else if (leavesLen > 0) { - return leaves[0]; - } else { - return proof[0]; - } - } - - /** - * @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}. - * - * This version handles multiproofs in calldata with the default hashing function. - * - * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. - * - * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`. - * The `leaves` must be validated independently. See {processMultiProofCalldata}. - */ - 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. - * - * This version handles multiproofs in calldata with the default hashing function. - * - * 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). - * - * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op, - * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not - * validating the leaves elsewhere. - */ - 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 proofFlagsLen = proofFlags.length; - - // Check proof validity. - if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen); - 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 < proofFlagsLen; i++) { - bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; - bytes32 b = proofFlags[i] - ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) - : proof[proofPos++]; - hashes[i] = Hashes.commutativeKeccak256(a, b); - } - - if (proofFlagsLen > 0) { - if (proofPos != proof.length) { - revert MerkleProofInvalidMultiproof(); - } - unchecked { - return hashes[proofFlagsLen - 1]; - } - } else if (leavesLen > 0) { - return leaves[0]; - } else { - return proof[0]; - } - } - - /** - * @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}. - * - * This version handles multiproofs in calldata with a custom hashing function. - * - * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. - * - * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`. - * The `leaves` must be validated independently. See {processMultiProofCalldata}. - */ - function multiProofVerifyCalldata( - bytes32[] calldata proof, - bool[] calldata proofFlags, - bytes32 root, - bytes32[] memory leaves, - function(bytes32, bytes32) view returns (bytes32) hasher - ) internal view returns (bool) { - return processMultiProofCalldata(proof, proofFlags, leaves, hasher) == 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. - * - * This version handles multiproofs in calldata with a custom hashing function. - * - * 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). - * - * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op, - * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not - * validating the leaves elsewhere. - */ - function processMultiProofCalldata( - bytes32[] calldata proof, - bool[] calldata proofFlags, - bytes32[] memory leaves, - function(bytes32, bytes32) view returns (bytes32) hasher - ) internal view 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 proofFlagsLen = proofFlags.length; - - // Check proof validity. - if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen); - 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 < proofFlagsLen; i++) { - bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; - bytes32 b = proofFlags[i] - ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) - : proof[proofPos++]; - hashes[i] = hasher(a, b); - } - - if (proofFlagsLen > 0) { - if (proofPos != proof.length) { - revert MerkleProofInvalidMultiproof(); - } - unchecked { - return hashes[proofFlagsLen - 1]; - } - } else if (leavesLen > 0) { - return leaves[0]; - } else { - return proof[0]; - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol deleted file mode 100644 index 37e9239..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.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[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] - * specifications. - */ -library MessageHashUtils { - /** - * @dev Returns the keccak256 digest of an ERC-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://ethereum.org/en/developers/docs/apis/json-rpc/#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) { - assembly ("memory-safe") { - 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 ERC-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://ethereum.org/en/developers/docs/apis/json-rpc/#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 ERC-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 Variant of {toDataWithIntendedValidatorHash-address-bytes} optimized for cases where `data` is a bytes32. - */ - function toDataWithIntendedValidatorHash( - address validator, - bytes32 messageHash - ) internal pure returns (bytes32 digest) { - assembly ("memory-safe") { - mstore(0x00, hex"19_00") - mstore(0x02, shl(96, validator)) - mstore(0x16, messageHash) - digest := keccak256(0x00, 0x36) - } - } - - /** - * @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-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) { - assembly ("memory-safe") { - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/P256.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/P256.sol deleted file mode 100644 index 81d79ad..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/P256.sol +++ /dev/null @@ -1,408 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/P256.sol) -pragma solidity ^0.8.20; - -import {Math} from "../math/Math.sol"; -import {Errors} from "../Errors.sol"; - -/** - * @dev Implementation of secp256r1 verification and recovery functions. - * - * The secp256r1 curve (also known as P256) is a NIST standard curve with wide support in modern devices - * and cryptographic standards. Some notable examples include Apple's Secure Enclave and Android's Keystore - * as well as authentication protocols like FIDO2. - * - * Based on the original https://github.com/itsobvioustech/aa-passkeys-wallet/blob/d3d423f28a4d8dfcb203c7fa0c47f42592a7378e/src/Secp256r1.sol[implementation of itsobvioustech] (GNU General Public License v3.0). - * Heavily inspired in https://github.com/maxrobot/elliptic-solidity/blob/c4bb1b6e8ae89534d8db3a6b3a6b52219100520f/contracts/Secp256r1.sol[maxrobot] and - * https://github.com/tdrerup/elliptic-curve-solidity/blob/59a9c25957d4d190eff53b6610731d81a077a15e/contracts/curves/EllipticCurve.sol[tdrerup] implementations. - * - * _Available since v5.1._ - */ -library P256 { - struct JPoint { - uint256 x; - uint256 y; - uint256 z; - } - - /// @dev Generator (x component) - uint256 internal constant GX = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296; - /// @dev Generator (y component) - uint256 internal constant GY = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5; - /// @dev P (size of the field) - uint256 internal constant P = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF; - /// @dev N (order of G) - uint256 internal constant N = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551; - /// @dev A parameter of the weierstrass equation - uint256 internal constant A = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC; - /// @dev B parameter of the weierstrass equation - uint256 internal constant B = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B; - - /// @dev (P + 1) / 4. Useful to compute sqrt - uint256 private constant P1DIV4 = 0x3fffffffc0000000400000000000000000000000400000000000000000000000; - - /// @dev N/2 for excluding higher order `s` values - uint256 private constant HALF_N = 0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8; - - /** - * @dev Verifies a secp256r1 signature using the RIP-7212 precompile and falls back to the Solidity implementation - * if the precompile is not available. This version should work on all chains, but requires the deployment of more - * bytecode. - * - * @param h - hashed message - * @param r - signature half R - * @param s - signature half S - * @param qx - public key coordinate X - * @param qy - public key coordinate Y - * - * IMPORTANT: This function disallows signatures where the `s` value is above `N/2` to prevent malleability. - * To flip the `s` value, compute `s = N - s`. - */ - function verify(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) internal view returns (bool) { - (bool valid, bool supported) = _tryVerifyNative(h, r, s, qx, qy); - return supported ? valid : verifySolidity(h, r, s, qx, qy); - } - - /** - * @dev Same as {verify}, but it will revert if the required precompile is not available. - * - * Make sure any logic (code or precompile) deployed at that address is the expected one, - * otherwise the returned value may be misinterpreted as a positive boolean. - */ - function verifyNative(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) internal view returns (bool) { - (bool valid, bool supported) = _tryVerifyNative(h, r, s, qx, qy); - if (supported) { - return valid; - } else { - revert Errors.MissingPrecompile(address(0x100)); - } - } - - /** - * @dev Same as {verify}, but it will return false if the required precompile is not available. - */ - function _tryVerifyNative( - bytes32 h, - bytes32 r, - bytes32 s, - bytes32 qx, - bytes32 qy - ) private view returns (bool valid, bool supported) { - if (!_isProperSignature(r, s) || !isValidPublicKey(qx, qy)) { - return (false, true); // signature is invalid, and its not because the precompile is missing - } else if (_rip7212(h, r, s, qx, qy)) { - return (true, true); // precompile is present, signature is valid - } else if ( - // Given precompiles have no bytecode (i.e. `address(0x100).code.length == 0`), we use - // a valid signature with small `r` and `s` values to check if the precompile is present. Taken from - // https://github.com/C2SP/wycheproof/blob/4672ff74d68766e7785c2cac4c597effccef2c5c/testvectors/ecdsa_secp256r1_sha256_p1363_test.json#L1173-L1204 - _rip7212( - 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023, // sha256("123400") - 0x0000000000000000000000000000000000000000000000000000000000000005, - 0x0000000000000000000000000000000000000000000000000000000000000001, - 0xa71af64de5126a4a4e02b7922d66ce9415ce88a4c9d25514d91082c8725ac957, - 0x5d47723c8fbe580bb369fec9c2665d8e30a435b9932645482e7c9f11e872296b - ) - ) { - return (false, true); // precompile is present, signature is invalid - } else { - return (false, false); // precompile is absent - } - } - - /** - * @dev Low level helper for {_tryVerifyNative}. Calls the precompile and checks if there is a return value. - */ - function _rip7212(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) private view returns (bool isValid) { - assembly ("memory-safe") { - // Use the free memory pointer without updating it at the end of the function - let ptr := mload(0x40) - mstore(ptr, h) - mstore(add(ptr, 0x20), r) - mstore(add(ptr, 0x40), s) - mstore(add(ptr, 0x60), qx) - mstore(add(ptr, 0x80), qy) - // RIP-7212 precompiles return empty bytes when an invalid signature is passed, making it impossible - // to distinguish the presence of the precompile. Custom precompile implementations may decide to - // return `bytes32(0)` (i.e. false) without developers noticing, so we decide to evaluate the return value - // without expanding memory using scratch space. - mstore(0x00, 0) // zero out scratch space in case the precompile doesn't return anything - if iszero(staticcall(gas(), 0x100, ptr, 0xa0, 0x00, 0x20)) { - invalid() - } - isValid := mload(0x00) - } - } - - /** - * @dev Same as {verify}, but only the Solidity implementation is used. - */ - function verifySolidity(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) internal view returns (bool) { - if (!_isProperSignature(r, s) || !isValidPublicKey(qx, qy)) { - return false; - } - - JPoint[16] memory points = _preComputeJacobianPoints(uint256(qx), uint256(qy)); - uint256 w = Math.invModPrime(uint256(s), N); - uint256 u1 = mulmod(uint256(h), w, N); - uint256 u2 = mulmod(uint256(r), w, N); - (uint256 x, ) = _jMultShamir(points, u1, u2); - return ((x % N) == uint256(r)); - } - - /** - * @dev Public key recovery - * - * @param h - hashed message - * @param v - signature recovery param - * @param r - signature half R - * @param s - signature half S - * - * IMPORTANT: This function disallows signatures where the `s` value is above `N/2` to prevent malleability. - * To flip the `s` value, compute `s = N - s` and `v = 1 - v` if (`v = 0 | 1`). - */ - function recovery(bytes32 h, uint8 v, bytes32 r, bytes32 s) internal view returns (bytes32 x, bytes32 y) { - if (!_isProperSignature(r, s) || v > 1) { - return (0, 0); - } - - uint256 p = P; // cache P on the stack - uint256 rx = uint256(r); - uint256 ry2 = addmod(mulmod(addmod(mulmod(rx, rx, p), A, p), rx, p), B, p); // weierstrass equation y² = x³ + a.x + b - uint256 ry = Math.modExp(ry2, P1DIV4, p); // This formula for sqrt work because P ≡ 3 (mod 4) - if (mulmod(ry, ry, p) != ry2) return (0, 0); // Sanity check - if (ry % 2 != v) ry = p - ry; - - JPoint[16] memory points = _preComputeJacobianPoints(rx, ry); - uint256 w = Math.invModPrime(uint256(r), N); - uint256 u1 = mulmod(N - (uint256(h) % N), w, N); - uint256 u2 = mulmod(uint256(s), w, N); - (uint256 xU, uint256 yU) = _jMultShamir(points, u1, u2); - return (bytes32(xU), bytes32(yU)); - } - - /** - * @dev Checks if (x, y) are valid coordinates of a point on the curve. - * In particular this function checks that x < P and y < P. - */ - function isValidPublicKey(bytes32 x, bytes32 y) internal pure returns (bool result) { - assembly ("memory-safe") { - let p := P - let lhs := mulmod(y, y, p) // y^2 - let rhs := addmod(mulmod(addmod(mulmod(x, x, p), A, p), x, p), B, p) // ((x^2 + a) * x) + b = x^3 + ax + b - result := and(and(lt(x, p), lt(y, p)), eq(lhs, rhs)) // Should conform with the Weierstrass equation - } - } - - /** - * @dev Checks if (r, s) is a proper signature. - * In particular, this checks that `s` is in the "lower-range", making the signature non-malleable. - */ - function _isProperSignature(bytes32 r, bytes32 s) private pure returns (bool) { - return uint256(r) > 0 && uint256(r) < N && uint256(s) > 0 && uint256(s) <= HALF_N; - } - - /** - * @dev Reduce from jacobian to affine coordinates - * @param jx - jacobian coordinate x - * @param jy - jacobian coordinate y - * @param jz - jacobian coordinate z - * @return ax - affine coordinate x - * @return ay - affine coordinate y - */ - function _affineFromJacobian(uint256 jx, uint256 jy, uint256 jz) private view returns (uint256 ax, uint256 ay) { - if (jz == 0) return (0, 0); - uint256 p = P; // cache P on the stack - uint256 zinv = Math.invModPrime(jz, p); - assembly ("memory-safe") { - let zzinv := mulmod(zinv, zinv, p) - ax := mulmod(jx, zzinv, p) - ay := mulmod(jy, mulmod(zzinv, zinv, p), p) - } - } - - /** - * @dev Point addition on the jacobian coordinates - * Reference: https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-1998-cmo-2 - * - * Note that: - * - * - `addition-add-1998-cmo-2` doesn't support identical input points. This version is modified to use - * the `h` and `r` values computed by `addition-add-1998-cmo-2` to detect identical inputs, and fallback to - * `doubling-dbl-1998-cmo-2` if needed. - * - if one of the points is at infinity (i.e. `z=0`), the result is undefined. - */ - function _jAdd( - JPoint memory p1, - uint256 x2, - uint256 y2, - uint256 z2 - ) private pure returns (uint256 rx, uint256 ry, uint256 rz) { - assembly ("memory-safe") { - let p := P - let z1 := mload(add(p1, 0x40)) - let zz1 := mulmod(z1, z1, p) // zz1 = z1² - let s1 := mulmod(mload(add(p1, 0x20)), mulmod(mulmod(z2, z2, p), z2, p), p) // s1 = y1*z2³ - let r := addmod(mulmod(y2, mulmod(zz1, z1, p), p), sub(p, s1), p) // r = s2-s1 = y2*z1³-s1 = y2*z1³-y1*z2³ - let u1 := mulmod(mload(p1), mulmod(z2, z2, p), p) // u1 = x1*z2² - let h := addmod(mulmod(x2, zz1, p), sub(p, u1), p) // h = u2-u1 = x2*z1²-u1 = x2*z1²-x1*z2² - - // detect edge cases where inputs are identical - switch and(iszero(r), iszero(h)) - // case 0: points are different - case 0 { - let hh := mulmod(h, h, p) // h² - - // x' = r²-h³-2*u1*h² - rx := addmod( - addmod(mulmod(r, r, p), sub(p, mulmod(h, hh, p)), p), - sub(p, mulmod(2, mulmod(u1, hh, p), p)), - p - ) - // y' = r*(u1*h²-x')-s1*h³ - ry := addmod( - mulmod(r, addmod(mulmod(u1, hh, p), sub(p, rx), p), p), - sub(p, mulmod(s1, mulmod(h, hh, p), p)), - p - ) - // z' = h*z1*z2 - rz := mulmod(h, mulmod(z1, z2, p), p) - } - // case 1: points are equal - case 1 { - let x := x2 - let y := y2 - let z := z2 - let yy := mulmod(y, y, p) - let zz := mulmod(z, z, p) - let m := addmod(mulmod(3, mulmod(x, x, p), p), mulmod(A, mulmod(zz, zz, p), p), p) // m = 3*x²+a*z⁴ - let s := mulmod(4, mulmod(x, yy, p), p) // s = 4*x*y² - - // x' = t = m²-2*s - rx := addmod(mulmod(m, m, p), sub(p, mulmod(2, s, p)), p) - - // y' = m*(s-t)-8*y⁴ = m*(s-x')-8*y⁴ - // cut the computation to avoid stack too deep - let rytmp1 := sub(p, mulmod(8, mulmod(yy, yy, p), p)) // -8*y⁴ - let rytmp2 := addmod(s, sub(p, rx), p) // s-x' - ry := addmod(mulmod(m, rytmp2, p), rytmp1, p) // m*(s-x')-8*y⁴ - - // z' = 2*y*z - rz := mulmod(2, mulmod(y, z, p), p) - } - } - } - - /** - * @dev Point doubling on the jacobian coordinates - * Reference: https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2 - */ - function _jDouble(uint256 x, uint256 y, uint256 z) private pure returns (uint256 rx, uint256 ry, uint256 rz) { - assembly ("memory-safe") { - let p := P - let yy := mulmod(y, y, p) - let zz := mulmod(z, z, p) - let m := addmod(mulmod(3, mulmod(x, x, p), p), mulmod(A, mulmod(zz, zz, p), p), p) // m = 3*x²+a*z⁴ - let s := mulmod(4, mulmod(x, yy, p), p) // s = 4*x*y² - - // x' = t = m²-2*s - rx := addmod(mulmod(m, m, p), sub(p, mulmod(2, s, p)), p) - // y' = m*(s-t)-8*y⁴ = m*(s-x')-8*y⁴ - ry := addmod(mulmod(m, addmod(s, sub(p, rx), p), p), sub(p, mulmod(8, mulmod(yy, yy, p), p)), p) - // z' = 2*y*z - rz := mulmod(2, mulmod(y, z, p), p) - } - } - - /** - * @dev Compute G·u1 + P·u2 using the precomputed points for G and P (see {_preComputeJacobianPoints}). - * - * Uses Strauss Shamir trick for EC multiplication - * https://stackoverflow.com/questions/50993471/ec-scalar-multiplication-with-strauss-shamir-method - * - * We optimize this for 2 bits at a time rather than a single bit. The individual points for a single pass are - * precomputed. Overall this reduces the number of additions while keeping the same number of - * doublings - */ - function _jMultShamir( - JPoint[16] memory points, - uint256 u1, - uint256 u2 - ) private view returns (uint256 rx, uint256 ry) { - uint256 x = 0; - uint256 y = 0; - uint256 z = 0; - unchecked { - for (uint256 i = 0; i < 128; ++i) { - if (z > 0) { - (x, y, z) = _jDouble(x, y, z); - (x, y, z) = _jDouble(x, y, z); - } - // Read 2 bits of u1, and 2 bits of u2. Combining the two gives the lookup index in the table. - uint256 pos = ((u1 >> 252) & 0xc) | ((u2 >> 254) & 0x3); - // Points that have z = 0 are points at infinity. They are the additive 0 of the group - // - if the lookup point is a 0, we can skip it - // - otherwise: - // - if the current point (x, y, z) is 0, we use the lookup point as our new value (0+P=P) - // - if the current point (x, y, z) is not 0, both points are valid and we can use `_jAdd` - if (points[pos].z != 0) { - if (z == 0) { - (x, y, z) = (points[pos].x, points[pos].y, points[pos].z); - } else { - (x, y, z) = _jAdd(points[pos], x, y, z); - } - } - u1 <<= 2; - u2 <<= 2; - } - } - return _affineFromJacobian(x, y, z); - } - - /** - * @dev Precompute a matrice of useful jacobian points associated with a given P. This can be seen as a 4x4 matrix - * that contains combination of P and G (generator) up to 3 times each. See the table below: - * - * ┌────┬─────────────────────┐ - * │ i │ 0 1 2 3 │ - * ├────┼─────────────────────┤ - * │ 0 │ 0 p 2p 3p │ - * │ 4 │ g g+p g+2p g+3p │ - * │ 8 │ 2g 2g+p 2g+2p 2g+3p │ - * │ 12 │ 3g 3g+p 3g+2p 3g+3p │ - * └────┴─────────────────────┘ - * - * Note that `_jAdd` (and thus `_jAddPoint`) does not handle the case where one of the inputs is a point at - * infinity (z = 0). However, we know that since `N ≡ 1 mod 2` and `N ≡ 1 mod 3`, there is no point P such that - * 2P = 0 or 3P = 0. This guarantees that g, 2g, 3g, p, 2p, 3p are all non-zero, and that all `_jAddPoint` calls - * have valid inputs. - */ - function _preComputeJacobianPoints(uint256 px, uint256 py) private pure returns (JPoint[16] memory points) { - points[0x00] = JPoint(0, 0, 0); // 0,0 - points[0x01] = JPoint(px, py, 1); // 1,0 (p) - points[0x04] = JPoint(GX, GY, 1); // 0,1 (g) - points[0x02] = _jDoublePoint(points[0x01]); // 2,0 (2p) - points[0x08] = _jDoublePoint(points[0x04]); // 0,2 (2g) - points[0x03] = _jAddPoint(points[0x01], points[0x02]); // 3,0 (p+2p = 3p) - points[0x05] = _jAddPoint(points[0x01], points[0x04]); // 1,1 (p+g) - points[0x06] = _jAddPoint(points[0x02], points[0x04]); // 2,1 (2p+g) - points[0x07] = _jAddPoint(points[0x03], points[0x04]); // 3,1 (3p+g) - points[0x09] = _jAddPoint(points[0x01], points[0x08]); // 1,2 (p+2g) - points[0x0a] = _jAddPoint(points[0x02], points[0x08]); // 2,2 (2p+2g) - points[0x0b] = _jAddPoint(points[0x03], points[0x08]); // 3,2 (3p+2g) - points[0x0c] = _jAddPoint(points[0x04], points[0x08]); // 0,3 (g+2g = 3g) - points[0x0d] = _jAddPoint(points[0x01], points[0x0c]); // 1,3 (p+3g) - points[0x0e] = _jAddPoint(points[0x02], points[0x0c]); // 2,3 (2p+3g) - points[0x0f] = _jAddPoint(points[0x03], points[0x0c]); // 3,3 (3p+3g) - } - - function _jAddPoint(JPoint memory p1, JPoint memory p2) private pure returns (JPoint memory) { - (uint256 x, uint256 y, uint256 z) = _jAdd(p1, p2.x, p2.y, p2.z); - return JPoint(x, y, z); - } - - function _jDoublePoint(JPoint memory p) private pure returns (JPoint memory) { - (uint256 x, uint256 y, uint256 z) = _jDouble(p.x, p.y, p.z); - return JPoint(x, y, z); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/README.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/README.adoc deleted file mode 100644 index 37a9824..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/README.adoc +++ /dev/null @@ -1,67 +0,0 @@ -= Cryptography - -[.readme-notice] -NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/utils/cryptography - -A collection of contracts and libraries that implement various signature validation schemes and cryptographic primitives. These utilities enable secure authentication, multisignature operations, and advanced cryptographic operations in smart contracts. - - * {ECDSA}, {MessageHashUtils}: Libraries for interacting with ECDSA signatures. - * {P256}: Library for verifying and recovering public keys from secp256r1 signatures. - * {RSA}: Library with RSA PKCS#1 v1.5 signature verification utilities. - * {SignatureChecker}: A library helper to support regular ECDSA from EOAs as well as ERC-1271 signatures for smart contracts. - * {Hashes}: Commonly used hash functions. - * {MerkleProof}: Functions for verifying https://en.wikipedia.org/wiki/Merkle_tree[Merkle Tree] proofs. - * {EIP712}: Contract with functions to allow processing signed typed structure data according to https://eips.ethereum.org/EIPS/eip-712[EIP-712]. - * {ERC7739Utils}: Utilities library that implements a defensive rehashing mechanism to prevent replayability of smart contract signatures based on ERC-7739. - * {AbstractSigner}: Abstract contract for internal signature validation in smart contracts. - * {ERC7739}: An abstract contract to validate signatures following the rehashing scheme from {ERC7739Utils}. - * {SignerECDSA}, {SignerP256}, {SignerRSA}: Implementations of an {AbstractSigner} with specific signature validation algorithms. - * {SignerERC7702}: Implementation of {AbstractSigner} that validates signatures using the contract's own address as the signer, useful for delegated accounts following EIP-7702. - * {SignerERC7913}, {MultiSignerERC7913}, {MultiSignerERC7913Weighted}: Implementations of {AbstractSigner} that validate signatures based on ERC-7913. Including a simple and weighted multisignature scheme. - * {ERC7913P256Verifier}, {ERC7913RSAVerifier}: Ready to use ERC-7913 signature verifiers for P256 and RSA keys. - -== Utils - -{{ECDSA}} - -{{MessageHashUtils}} - -{{P256}} - -{{RSA}} - -{{SignatureChecker}} - -{{Hashes}} - -{{MerkleProof}} - -{{EIP712}} - -{{ERC7739Utils}} - -== Abstract Signers - -{{AbstractSigner}} - -{{ERC7739}} - -{{SignerECDSA}} - -{{SignerP256}} - -{{SignerRSA}} - -{{SignerERC7702}} - -{{SignerERC7913}} - -{{MultiSignerERC7913}} - -{{MultiSignerERC7913Weighted}} - -== Verifiers - -{{ERC7913P256Verifier}} - -{{ERC7913RSAVerifier}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/RSA.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/RSA.sol deleted file mode 100644 index 4e04ce5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/RSA.sol +++ /dev/null @@ -1,154 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/RSA.sol) -pragma solidity ^0.8.20; - -import {Math} from "../math/Math.sol"; - -/** - * @dev RSA PKCS#1 v1.5 signature verification implementation according to https://datatracker.ietf.org/doc/html/rfc8017[RFC8017]. - * - * This library supports PKCS#1 v1.5 padding to avoid malleability via chosen plaintext attacks in practical implementations. - * The padding follows the EMSA-PKCS1-v1_5-ENCODE encoding definition as per section 9.2 of the RFC. This padding makes - * RSA semantically secure for signing messages. - * - * Inspired by https://github.com/adria0/SolRsaVerify/blob/79c6182cabb9102ea69d4a2e996816091d5f1cd1[Adrià Massanet's work] (GNU General Public License v3.0). - * - * _Available since v5.1._ - */ -library RSA { - /** - * @dev Same as {pkcs1Sha256} but using SHA256 to calculate the digest of `data`. - */ - function pkcs1Sha256( - bytes memory data, - bytes memory s, - bytes memory e, - bytes memory n - ) internal view returns (bool) { - return pkcs1Sha256(sha256(data), s, e, n); - } - - /** - * @dev Verifies a PKCSv1.5 signature given a digest according to the verification - * method described in https://datatracker.ietf.org/doc/html/rfc8017#section-8.2.2[section 8.2.2 of RFC8017] with - * support for explicit or implicit NULL parameters in the DigestInfo (no other optional parameters are supported). - * - * IMPORTANT: For security reason, this function requires the signature and modulus to have a length of at least - * 2048 bits. If you use a smaller key, consider replacing it with a larger, more secure, one. - * - * WARNING: This verification algorithm doesn't prevent replayability. If called multiple times with the same - * digest, public key and (valid signature), it will return true every time. Consider including an onchain nonce - * or unique identifier in the message to prevent replay attacks. - * - * WARNING: This verification algorithm supports any exponent. NIST recommends using `65537` (or higher). - * That is the default value many libraries use, such as OpenSSL. Developers may choose to reject public keys - * using a low exponent out of security concerns. - * - * @param digest the digest to verify - * @param s is a buffer containing the signature - * @param e is the exponent of the public key - * @param n is the modulus of the public key - */ - function pkcs1Sha256(bytes32 digest, bytes memory s, bytes memory e, bytes memory n) internal view returns (bool) { - unchecked { - // cache and check length - uint256 length = n.length; - if ( - length < 0x100 || // Enforce 2048 bits minimum - length != s.length // signature must have the same length as the finite field - ) { - return false; - } - - // Verify that s < n to ensure there's only one valid signature for a given message - for (uint256 i = 0; i < length; i += 0x20) { - uint256 p = Math.min(i, length - 0x20); - bytes32 sp = _unsafeReadBytes32(s, p); - bytes32 np = _unsafeReadBytes32(n, p); - if (sp < np) { - // s < n in the upper bits (everything before is equal) → s < n globally: ok - break; - } else if (sp > np || p == length - 0x20) { - // s > n in the upper bits (everything before is equal) → s > n globally: fail - // or - // s = n and we are looking at the lower bits → s = n globally: fail - return false; - } - } - - // RSAVP1 https://datatracker.ietf.org/doc/html/rfc8017#section-5.2.2 - // The previous check guarantees that n > 0. Therefore modExp cannot revert. - bytes memory buffer = Math.modExp(s, e, n); - - // Check that buffer is well encoded: - // buffer ::= 0x00 | 0x01 | PS | 0x00 | DigestInfo - // - // With - // - PS is padding filled with 0xFF - // - DigestInfo ::= SEQUENCE { - // digestAlgorithm AlgorithmIdentifier, - // [optional algorithm parameters] -- not currently supported - // digest OCTET STRING - // } - - // Get AlgorithmIdentifier from the DigestInfo, and set the config accordingly - // - params: includes 00 + first part of DigestInfo - // - mask: filter to check the params - // - offset: length of the suffix (including digest) - bytes32 params; // 0x00 | DigestInfo - bytes32 mask; - uint256 offset; - - // Digest is expected at the end of the buffer. Therefore if NULL param is present, - // it should be at 32 (digest) + 2 bytes from the end. To those 34 bytes, we add the - // OID (9 bytes) and its length (2 bytes) to get the position of the DigestInfo sequence, - // which is expected to have a length of 0x31 when the NULL param is present or 0x2f if not. - if (bytes1(_unsafeReadBytes32(buffer, length - 0x32)) == 0x31) { - offset = 0x34; - // 00 (1 byte) | SEQUENCE length (0x31) = 3031 (2 bytes) | SEQUENCE length (0x0d) = 300d (2 bytes) | OBJECT_IDENTIFIER length (0x09) = 0609 (2 bytes) - // SHA256 OID = 608648016503040201 (9 bytes) | NULL = 0500 (2 bytes) (explicit) | OCTET_STRING length (0x20) = 0420 (2 bytes) - params = 0x003031300d060960864801650304020105000420000000000000000000000000; - mask = 0xffffffffffffffffffffffffffffffffffffffff000000000000000000000000; // (20 bytes) - } else if (bytes1(_unsafeReadBytes32(buffer, length - 0x30)) == 0x2F) { - offset = 0x32; - // 00 (1 byte) | SEQUENCE length (0x2f) = 302f (2 bytes) | SEQUENCE length (0x0b) = 300b (2 bytes) | OBJECT_IDENTIFIER length (0x09) = 0609 (2 bytes) - // SHA256 OID = 608648016503040201 (9 bytes) | NULL = | OCTET_STRING length (0x20) = 0420 (2 bytes) - params = 0x00302f300b060960864801650304020104200000000000000000000000000000; - mask = 0xffffffffffffffffffffffffffffffffffff0000000000000000000000000000; // (18 bytes) - } else { - // unknown - return false; - } - - // Length is at least 0x100 and offset is at most 0x34, so this is safe. There is always some padding. - uint256 paddingEnd = length - offset; - - // The padding has variable (arbitrary) length, so we check it byte per byte in a loop. - // This is required to ensure non-malleability. Not checking would allow an attacker to - // use the padding to manipulate the message in order to create a valid signature out of - // multiple valid signatures. - for (uint256 i = 2; i < paddingEnd; ++i) { - if (bytes1(_unsafeReadBytes32(buffer, i)) != 0xFF) { - return false; - } - } - - // All the other parameters are small enough to fit in a bytes32, so we can check them directly. - return - bytes2(0x0001) == bytes2(_unsafeReadBytes32(buffer, 0x00)) && // 00 | 01 - // PS was checked in the loop - params == _unsafeReadBytes32(buffer, paddingEnd) & mask && // DigestInfo - // Optional parameters are not checked - digest == _unsafeReadBytes32(buffer, length - 0x20); // Digest - } - } - - /// @dev Reads a bytes32 from a bytes array without bounds checking. - function _unsafeReadBytes32(bytes memory array, uint256 offset) private pure returns (bytes32 result) { - // Memory safeness is guaranteed as long as the provided `array` is a Solidity-allocated bytes array - // and `offset` is within bounds. This is the case for all calls to this private function from {pkcs1Sha256}. - assembly ("memory-safe") { - result := mload(add(add(array, 0x20), offset)) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol deleted file mode 100644 index f85b24c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/SignatureChecker.sol) - -pragma solidity ^0.8.24; - -import {ECDSA} from "./ECDSA.sol"; -import {IERC1271} from "../../interfaces/IERC1271.sol"; -import {IERC7913SignatureVerifier} from "../../interfaces/IERC7913.sol"; -import {Bytes} from "../../utils/Bytes.sol"; - -/** - * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support: - * - * * ECDSA signatures from externally owned accounts (EOAs) - * * ERC-1271 signatures from smart contract wallets like Argent and Safe Wallet (previously Gnosis Safe) - * * ERC-7913 signatures from keys that do not have an Ethereum address of their own - * - * See https://eips.ethereum.org/EIPS/eip-1271[ERC-1271] and https://eips.ethereum.org/EIPS/eip-7913[ERC-7913]. - */ -library SignatureChecker { - using Bytes for bytes; - - /** - * @dev Checks if a signature is valid for a given signer and data hash. If the signer has code, the - * signature is validated against it using ERC-1271, 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). - * - * NOTE: For an extended version of this function that supports ERC-7913 signatures, see {isValidSignatureNow-bytes-bytes32-bytes-}. - */ - function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { - if (signer.code.length == 0) { - (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature); - return err == ECDSA.RecoverError.NoError && recovered == signer; - } else { - return 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 ERC-1271. - * - * 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)); - } - - /** - * @dev Verifies a signature for a given ERC-7913 signer and hash. - * - * The signer is a `bytes` object that is the concatenation of an address and optionally a key: - * `verifier || key`. A signer must be at least 20 bytes long. - * - * Verification is done as follows: - * - * * If `signer.length < 20`: verification fails - * * If `signer.length == 20`: verification is done using {isValidSignatureNow} - * * Otherwise: verification is done using {IERC7913SignatureVerifier} - * - * 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( - bytes memory signer, - bytes32 hash, - bytes memory signature - ) internal view returns (bool) { - if (signer.length < 20) { - return false; - } else if (signer.length == 20) { - return isValidSignatureNow(address(bytes20(signer)), hash, signature); - } else { - (bool success, bytes memory result) = address(bytes20(signer)).staticcall( - abi.encodeCall(IERC7913SignatureVerifier.verify, (signer.slice(20), hash, signature)) - ); - return (success && - result.length >= 32 && - abi.decode(result, (bytes32)) == bytes32(IERC7913SignatureVerifier.verify.selector)); - } - } - - /** - * @dev Verifies multiple ERC-7913 `signatures` for a given `hash` using a set of `signers`. - * Returns `false` if the number of signers and signatures is not the same. - * - * The signers should be ordered by their `keccak256` hash to ensure efficient duplication check. Unordered - * signers are supported, but the uniqueness check will be more expensive. - * - * 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 areValidSignaturesNow( - bytes32 hash, - bytes[] memory signers, - bytes[] memory signatures - ) internal view returns (bool) { - if (signers.length != signatures.length) return false; - - bytes32 lastId = bytes32(0); - - for (uint256 i = 0; i < signers.length; ++i) { - bytes memory signer = signers[i]; - - // If one of the signatures is invalid, reject the batch - if (!isValidSignatureNow(signer, hash, signatures[i])) return false; - - bytes32 id = keccak256(signer); - // If the current signer ID is greater than all previous IDs, then this is a new signer. - if (lastId < id) { - lastId = id; - } else { - // If this signer id is not greater than all the previous ones, verify that it is not a duplicate of a previous one - // This loop is never executed if the signers are ordered by id. - for (uint256 j = 0; j < i; ++j) { - if (id == keccak256(signers[j])) return false; - } - } - } - - return true; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/draft-ERC7739Utils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/draft-ERC7739Utils.sol deleted file mode 100644 index e47f20b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/draft-ERC7739Utils.sol +++ /dev/null @@ -1,207 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/draft-ERC7739Utils.sol) - -pragma solidity ^0.8.20; - -import {Calldata} from "../Calldata.sol"; - -/** - * @dev Utilities to process https://ercs.ethereum.org/ERCS/erc-7739[ERC-7739] typed data signatures - * that are specific to an EIP-712 domain. - * - * This library provides methods to wrap, unwrap and operate over typed data signatures with a defensive - * rehashing mechanism that includes the app's xref:api:utils/cryptography#EIP712-_domainSeparatorV4[EIP-712] - * and preserves readability of the signed content using an EIP-712 nested approach. - * - * A smart contract domain can validate a signature for a typed data structure in two ways: - * - * - As an application validating a typed data signature. See {typedDataSignStructHash}. - * - As a smart contract validating a raw message signature. See {personalSignStructHash}. - * - * NOTE: A provider for a smart contract wallet would need to return this signature as the - * result of a call to `personal_sign` or `eth_signTypedData`, and this may be unsupported by - * API clients that expect a return value of 129 bytes, or specifically the `r,s,v` parameters - * of an xref:api:utils/cryptography#ECDSA[ECDSA] signature, as is for example specified for - * xref:api:utils/cryptography#EIP712[EIP-712]. - */ -library ERC7739Utils { - /** - * @dev An EIP-712 type to represent "personal" signatures - * (i.e. mimic of `personal_sign` for smart contracts). - */ - bytes32 private constant PERSONAL_SIGN_TYPEHASH = keccak256("PersonalSign(bytes prefixed)"); - - /** - * @dev Nest a signature for a given EIP-712 type into a nested signature for the domain of the app. - * - * Counterpart of {decodeTypedDataSig} to extract the original signature and the nested components. - */ - function encodeTypedDataSig( - bytes memory signature, - bytes32 appSeparator, - bytes32 contentsHash, - string memory contentsDescr - ) internal pure returns (bytes memory) { - return - abi.encodePacked(signature, appSeparator, contentsHash, contentsDescr, uint16(bytes(contentsDescr).length)); - } - - /** - * @dev Parses a nested signature into its components. - * - * Constructed as follows: - * - * `signature ‖ APP_DOMAIN_SEPARATOR ‖ contentsHash ‖ contentsDescr ‖ uint16(contentsDescr.length)` - * - * - `signature` is the signature for the (ERC-7739) nested struct hash. This signature indirectly signs over the - * original "contents" hash (from the app) and the account's domain separator. - * - `APP_DOMAIN_SEPARATOR` is the EIP-712 {EIP712-_domainSeparatorV4} of the application smart contract that is - * requesting the signature verification (though ERC-1271). - * - `contentsHash` is the hash of the underlying data structure or message. - * - `contentsDescr` is a descriptor of the "contents" part of the the EIP-712 type of the nested signature. - * - * NOTE: This function returns empty if the input format is invalid instead of reverting. - * data instead. - */ - function decodeTypedDataSig( - bytes calldata encodedSignature - ) - internal - pure - returns (bytes calldata signature, bytes32 appSeparator, bytes32 contentsHash, string calldata contentsDescr) - { - unchecked { - uint256 sigLength = encodedSignature.length; - - // 66 bytes = contentsDescrLength (2 bytes) + contentsHash (32 bytes) + APP_DOMAIN_SEPARATOR (32 bytes). - if (sigLength < 66) return (Calldata.emptyBytes(), 0, 0, Calldata.emptyString()); - - uint256 contentsDescrEnd = sigLength - 2; // Last 2 bytes - uint256 contentsDescrLength = uint16(bytes2(encodedSignature[contentsDescrEnd:])); - - // Check for space for `contentsDescr` in addition to the 66 bytes documented above - if (sigLength < 66 + contentsDescrLength) return (Calldata.emptyBytes(), 0, 0, Calldata.emptyString()); - - uint256 contentsHashEnd = contentsDescrEnd - contentsDescrLength; - uint256 separatorEnd = contentsHashEnd - 32; - uint256 signatureEnd = separatorEnd - 32; - - signature = encodedSignature[:signatureEnd]; - appSeparator = bytes32(encodedSignature[signatureEnd:separatorEnd]); - contentsHash = bytes32(encodedSignature[separatorEnd:contentsHashEnd]); - contentsDescr = string(encodedSignature[contentsHashEnd:contentsDescrEnd]); - } - } - - /** - * @dev Nests an `ERC-191` digest into a `PersonalSign` EIP-712 struct, and returns the corresponding struct hash. - * This struct hash must be combined with a domain separator, using {MessageHashUtils-toTypedDataHash} before - * being verified/recovered. - * - * This is used to simulates the `personal_sign` RPC method in the context of smart contracts. - */ - function personalSignStructHash(bytes32 contents) internal pure returns (bytes32) { - return keccak256(abi.encode(PERSONAL_SIGN_TYPEHASH, contents)); - } - - /** - * @dev Nests an `EIP-712` hash (`contents`) into a `TypedDataSign` EIP-712 struct, and returns the corresponding - * struct hash. This struct hash must be combined with a domain separator, using {MessageHashUtils-toTypedDataHash} - * before being verified/recovered. - */ - function typedDataSignStructHash( - string calldata contentsName, - string calldata contentsType, - bytes32 contentsHash, - bytes memory domainBytes - ) internal pure returns (bytes32 result) { - return - bytes(contentsName).length == 0 - ? bytes32(0) - : keccak256( - abi.encodePacked(typedDataSignTypehash(contentsName, contentsType), contentsHash, domainBytes) - ); - } - - /** - * @dev Variant of {typedDataSignStructHash-string-string-bytes32-bytes} that takes a content descriptor - * and decodes the `contentsName` and `contentsType` out of it. - */ - function typedDataSignStructHash( - string calldata contentsDescr, - bytes32 contentsHash, - bytes memory domainBytes - ) internal pure returns (bytes32 result) { - (string calldata contentsName, string calldata contentsType) = decodeContentsDescr(contentsDescr); - - return typedDataSignStructHash(contentsName, contentsType, contentsHash, domainBytes); - } - - /** - * @dev Compute the EIP-712 typehash of the `TypedDataSign` structure for a given type (and typename). - */ - function typedDataSignTypehash( - string calldata contentsName, - string calldata contentsType - ) internal pure returns (bytes32) { - return - keccak256( - abi.encodePacked( - "TypedDataSign(", - contentsName, - " contents,string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)", - contentsType - ) - ); - } - - /** - * @dev Parse the type name out of the ERC-7739 contents type description. Supports both the implicit and explicit - * modes. - * - * Following ERC-7739 specifications, a `contentsName` is considered invalid if it's empty or it contains - * any of the following bytes , )\x00 - * - * If the `contentsType` is invalid, this returns an empty string. Otherwise, the return string has non-zero - * length. - */ - function decodeContentsDescr( - string calldata contentsDescr - ) internal pure returns (string calldata contentsName, string calldata contentsType) { - bytes calldata buffer = bytes(contentsDescr); - if (buffer.length == 0) { - // pass through (fail) - } else if (buffer[buffer.length - 1] == bytes1(")")) { - // Implicit mode: read contentsName from the beginning, and keep the complete descr - for (uint256 i = 0; i < buffer.length; ++i) { - bytes1 current = buffer[i]; - if (current == bytes1("(")) { - // if name is empty - passthrough (fail) - if (i == 0) break; - // we found the end of the contentsName - return (string(buffer[:i]), contentsDescr); - } else if (_isForbiddenChar(current)) { - // we found an invalid character (forbidden) - passthrough (fail) - break; - } - } - } else { - // Explicit mode: read contentsName from the end, and remove it from the descr - for (uint256 i = buffer.length; i > 0; --i) { - bytes1 current = buffer[i - 1]; - if (current == bytes1(")")) { - // we found the end of the contentsName - return (string(buffer[i:]), string(buffer[:i])); - } else if (_isForbiddenChar(current)) { - // we found an invalid character (forbidden) - passthrough (fail) - break; - } - } - } - return (Calldata.emptyString(), Calldata.emptyString()); - } - - function _isForbiddenChar(bytes1 char) private pure returns (bool) { - return char == 0x00 || char == bytes1(" ") || char == bytes1(",") || char == bytes1("(") || char == bytes1(")"); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/AbstractSigner.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/AbstractSigner.sol deleted file mode 100644 index 942ec2a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/AbstractSigner.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/AbstractSigner.sol) - -pragma solidity ^0.8.20; - -/** - * @dev Abstract contract for signature validation. - * - * Developers must implement {_rawSignatureValidation} and use it as the lowest-level signature validation mechanism. - * - * @custom:stateless - */ -abstract contract AbstractSigner { - /** - * @dev Signature validation algorithm. - * - * WARNING: Implementing a signature validation algorithm is a security-sensitive operation as it involves - * cryptographic verification. It is important to review and test thoroughly before deployment. Consider - * using one of the signature verification libraries (xref:api:utils/cryptography#ECDSA[ECDSA], - * xref:api:utils/cryptography#P256[P256] or xref:api:utils/cryptography#RSA[RSA]). - */ - function _rawSignatureValidation(bytes32 hash, bytes calldata signature) internal view virtual returns (bool); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913.sol deleted file mode 100644 index f485409..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913.sol +++ /dev/null @@ -1,252 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/MultiSignerERC7913.sol) - -pragma solidity ^0.8.26; - -import {AbstractSigner} from "./AbstractSigner.sol"; -import {SignatureChecker} from "../SignatureChecker.sol"; -import {EnumerableSet} from "../../structs/EnumerableSet.sol"; - -/** - * @dev Implementation of {AbstractSigner} using multiple ERC-7913 signers with a threshold-based - * signature verification system. - * - * This contract allows managing a set of authorized signers and requires a minimum number of - * signatures (threshold) to approve operations. It uses ERC-7913 formatted signers, which - * makes it natively compatible with ECDSA and ERC-1271 signers. - * - * Example of usage: - * - * ```solidity - * contract MyMultiSignerAccount is Account, MultiSignerERC7913, Initializable { - * function initialize(bytes[] memory signers, uint64 threshold) public initializer { - * _addSigners(signers); - * _setThreshold(threshold); - * } - * - * function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf { - * _addSigners(signers); - * } - * - * function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf { - * _removeSigners(signers); - * } - * - * function setThreshold(uint64 threshold) public onlyEntryPointOrSelf { - * _setThreshold(threshold); - * } - * } - * ``` - * - * IMPORTANT: Failing to properly initialize the signers and threshold either during construction - * (if used standalone) or during initialization (if used as a clone) may leave the contract - * either front-runnable or unusable. - */ -abstract contract MultiSignerERC7913 is AbstractSigner { - using EnumerableSet for EnumerableSet.BytesSet; - using SignatureChecker for *; - - EnumerableSet.BytesSet private _signers; - uint64 private _threshold; - - /// @dev Emitted when a signer is added. - event ERC7913SignerAdded(bytes indexed signers); - - /// @dev Emitted when a signers is removed. - event ERC7913SignerRemoved(bytes indexed signers); - - /// @dev Emitted when the threshold is updated. - event ERC7913ThresholdSet(uint64 threshold); - - /// @dev The `signer` already exists. - error MultiSignerERC7913AlreadyExists(bytes signer); - - /// @dev The `signer` does not exist. - error MultiSignerERC7913NonexistentSigner(bytes signer); - - /// @dev The `signer` is less than 20 bytes long. - error MultiSignerERC7913InvalidSigner(bytes signer); - - /// @dev The `threshold` is zero. - error MultiSignerERC7913ZeroThreshold(); - - /// @dev The `threshold` is unreachable given the number of `signers`. - error MultiSignerERC7913UnreachableThreshold(uint64 signers, uint64 threshold); - - constructor(bytes[] memory signers_, uint64 threshold_) { - _addSigners(signers_); - _setThreshold(threshold_); - } - - /** - * @dev Returns a slice of the set of authorized signers. - * - * Using `start = 0` and `end = type(uint64).max` will return the entire set of signers. - * - * WARNING: Depending on the `start` and `end`, this operation can copy a large amount of data to memory, which - * can be expensive. This is designed for view accessors queried without gas fees. Using it in state-changing - * functions may become uncallable if the slice grows too large. - */ - function getSigners(uint64 start, uint64 end) public view virtual returns (bytes[] memory) { - return _signers.values(start, end); - } - - /// @dev Returns the number of authorized signers - function getSignerCount() public view virtual returns (uint256) { - return _signers.length(); - } - - /// @dev Returns whether the `signer` is an authorized signer. - function isSigner(bytes memory signer) public view virtual returns (bool) { - return _signers.contains(signer); - } - - /// @dev Returns the minimum number of signers required to approve a multisignature operation. - function threshold() public view virtual returns (uint64) { - return _threshold; - } - - /** - * @dev Adds the `newSigners` to those allowed to sign on behalf of this contract. - * Internal version without access control. - * - * Requirements: - * - * * Each of `newSigners` must be at least 20 bytes long. Reverts with {MultiSignerERC7913InvalidSigner} if not. - * * Each of `newSigners` must not be authorized. See {isSigner}. Reverts with {MultiSignerERC7913AlreadyExists} if so. - */ - function _addSigners(bytes[] memory newSigners) internal virtual { - for (uint256 i = 0; i < newSigners.length; ++i) { - bytes memory signer = newSigners[i]; - require(signer.length >= 20, MultiSignerERC7913InvalidSigner(signer)); - require(_signers.add(signer), MultiSignerERC7913AlreadyExists(signer)); - emit ERC7913SignerAdded(signer); - } - } - - /** - * @dev Removes the `oldSigners` from the authorized signers. Internal version without access control. - * - * Requirements: - * - * * Each of `oldSigners` must be authorized. See {isSigner}. Otherwise {MultiSignerERC7913NonexistentSigner} is thrown. - * * See {_validateReachableThreshold} for the threshold validation. - */ - function _removeSigners(bytes[] memory oldSigners) internal virtual { - for (uint256 i = 0; i < oldSigners.length; ++i) { - bytes memory signer = oldSigners[i]; - require(_signers.remove(signer), MultiSignerERC7913NonexistentSigner(signer)); - emit ERC7913SignerRemoved(signer); - } - _validateReachableThreshold(); - } - - /** - * @dev Sets the signatures `threshold` required to approve a multisignature operation. - * Internal version without access control. - * - * Requirements: - * - * * See {_validateReachableThreshold} for the threshold validation. - */ - function _setThreshold(uint64 newThreshold) internal virtual { - require(newThreshold > 0, MultiSignerERC7913ZeroThreshold()); - _threshold = newThreshold; - _validateReachableThreshold(); - emit ERC7913ThresholdSet(newThreshold); - } - - /** - * @dev Validates the current threshold is reachable. - * - * Requirements: - * - * * The {getSignerCount} must be greater or equal than to the {threshold}. Throws - * {MultiSignerERC7913UnreachableThreshold} if not. - */ - function _validateReachableThreshold() internal view virtual { - uint256 signersLength = _signers.length(); - uint64 currentThreshold = threshold(); - require( - signersLength >= currentThreshold, - MultiSignerERC7913UnreachableThreshold( - uint64(signersLength), // Safe cast. Economically impossible to overflow. - currentThreshold - ) - ); - } - - /** - * @dev Decodes, validates the signature and checks the signers are authorized. - * See {_validateSignatures} and {_validateThreshold} for more details. - * - * Example of signature encoding: - * - * ```solidity - * // Encode signers (verifier || key) - * bytes memory signer1 = abi.encodePacked(verifier1, key1); - * bytes memory signer2 = abi.encodePacked(verifier2, key2); - * - * // Order signers by their id - * if (keccak256(signer1) > keccak256(signer2)) { - * (signer1, signer2) = (signer2, signer1); - * (signature1, signature2) = (signature2, signature1); - * } - * - * // Assign ordered signers and signatures - * bytes[] memory signers = new bytes[](2); - * bytes[] memory signatures = new bytes[](2); - * signers[0] = signer1; - * signatures[0] = signature1; - * signers[1] = signer2; - * signatures[1] = signature2; - * - * // Encode the multi signature - * bytes memory signature = abi.encode(signers, signatures); - * ``` - * - * Requirements: - * - * * The `signature` must be encoded as `abi.encode(signers, signatures)`. - */ - function _rawSignatureValidation( - bytes32 hash, - bytes calldata signature - ) internal view virtual override returns (bool) { - if (signature.length == 0) return false; // For ERC-7739 compatibility - (bytes[] memory signers, bytes[] memory signatures) = abi.decode(signature, (bytes[], bytes[])); - return _validateThreshold(signers) && _validateSignatures(hash, signers, signatures); - } - - /** - * @dev Validates the signatures using the signers and their corresponding signatures. - * Returns whether the signers are authorized and the signatures are valid for the given hash. - * - * IMPORTANT: Sorting the signers by their `keccak256` hash will improve the gas efficiency of this function. - * See {SignatureChecker-areValidSignaturesNow-bytes32-bytes[]-bytes[]} for more details. - * - * Requirements: - * - * * The `signatures` and `signers` arrays must be equal in length. Returns false otherwise. - */ - function _validateSignatures( - bytes32 hash, - bytes[] memory signers, - bytes[] memory signatures - ) internal view virtual returns (bool valid) { - for (uint256 i = 0; i < signers.length; ++i) { - if (!isSigner(signers[i])) { - return false; - } - } - return hash.areValidSignaturesNow(signers, signatures); - } - - /** - * @dev Validates that the number of signers meets the {threshold} requirement. - * Assumes the signers were already validated. See {_validateSignatures} for more details. - */ - function _validateThreshold(bytes[] memory validatingSigners) internal view virtual returns (bool) { - return validatingSigners.length >= threshold(); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol deleted file mode 100644 index 653272f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol +++ /dev/null @@ -1,208 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/MultiSignerERC7913Weighted.sol) - -pragma solidity ^0.8.26; - -import {SafeCast} from "../../math/SafeCast.sol"; -import {MultiSignerERC7913} from "./MultiSignerERC7913.sol"; - -/** - * @dev Extension of {MultiSignerERC7913} that supports weighted signatures. - * - * This contract allows assigning different weights to each signer, enabling more - * flexible governance schemes. For example, some signers could have higher weight - * than others, allowing for weighted voting or prioritized authorization. - * - * Example of usage: - * - * ```solidity - * contract MyWeightedMultiSignerAccount is Account, MultiSignerERC7913Weighted, Initializable { - * function initialize(bytes[] memory signers, uint64[] memory weights, uint64 threshold) public initializer { - * _addSigners(signers); - * _setSignerWeights(signers, weights); - * _setThreshold(threshold); - * } - * - * function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf { - * _addSigners(signers); - * } - * - * function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf { - * _removeSigners(signers); - * } - * - * function setThreshold(uint64 threshold) public onlyEntryPointOrSelf { - * _setThreshold(threshold); - * } - * - * function setSignerWeights(bytes[] memory signers, uint64[] memory weights) public onlyEntryPointOrSelf { - * _setSignerWeights(signers, weights); - * } - * } - * ``` - * - * IMPORTANT: When setting a threshold value, ensure it matches the scale used for signer weights. - * For example, if signers have weights like 1, 2, or 3, then a threshold of 4 would require at - * least two signers (e.g., one with weight 1 and one with weight 3). See {signerWeight}. - */ -abstract contract MultiSignerERC7913Weighted is MultiSignerERC7913 { - using SafeCast for *; - - // Sum of all the extra weights of all signers. Storage packed with `MultiSignerERC7913._threshold` - uint64 private _totalExtraWeight; - - // Mapping from signer to extraWeight (in addition to all authorized signers having weight 1) - mapping(bytes signer => uint64) private _extraWeights; - - /** - * @dev Emitted when a signer's weight is changed. - * - * NOTE: Not emitted in {_addSigners} or {_removeSigners}. Indexers must rely on {ERC7913SignerAdded} - * and {ERC7913SignerRemoved} to index a default weight of 1. See {signerWeight}. - */ - event ERC7913SignerWeightChanged(bytes indexed signer, uint64 weight); - - /// @dev Thrown when a signer's weight is invalid. - error MultiSignerERC7913WeightedInvalidWeight(bytes signer, uint64 weight); - - /// @dev Thrown when the arrays lengths don't match. See {_setSignerWeights}. - error MultiSignerERC7913WeightedMismatchedLength(); - - constructor(bytes[] memory signers_, uint64[] memory weights_, uint64 threshold_) MultiSignerERC7913(signers_, 1) { - _setSignerWeights(signers_, weights_); - _setThreshold(threshold_); - } - - /// @dev Gets the weight of a signer. Returns 0 if the signer is not authorized. - function signerWeight(bytes memory signer) public view virtual returns (uint64) { - unchecked { - // Safe cast, _setSignerWeights guarantees 1+_extraWeights is a uint64 - return uint64(isSigner(signer).toUint() * (1 + _extraWeights[signer])); - } - } - - /// @dev Gets the total weight of all signers. - function totalWeight() public view virtual returns (uint64) { - return (getSignerCount() + _totalExtraWeight).toUint64(); - } - - /** - * @dev Sets weights for multiple signers at once. Internal version without access control. - * - * Requirements: - * - * * `signers` and `weights` arrays must have the same length. Reverts with {MultiSignerERC7913WeightedMismatchedLength} on mismatch. - * * Each signer must exist in the set of authorized signers. Otherwise reverts with {MultiSignerERC7913NonexistentSigner} - * * Each weight must be greater than 0. Otherwise reverts with {MultiSignerERC7913WeightedInvalidWeight} - * * See {_validateReachableThreshold} for the threshold validation. - * - * Emits {ERC7913SignerWeightChanged} for each signer. - */ - function _setSignerWeights(bytes[] memory signers, uint64[] memory weights) internal virtual { - require(signers.length == weights.length, MultiSignerERC7913WeightedMismatchedLength()); - - uint256 extraWeightAdded = 0; - uint256 extraWeightRemoved = 0; - for (uint256 i = 0; i < signers.length; ++i) { - bytes memory signer = signers[i]; - require(isSigner(signer), MultiSignerERC7913NonexistentSigner(signer)); - - uint64 weight = weights[i]; - require(weight > 0, MultiSignerERC7913WeightedInvalidWeight(signer, weight)); - - unchecked { - uint64 oldExtraWeight = _extraWeights[signer]; - uint64 newExtraWeight = weight - 1; - - if (oldExtraWeight != newExtraWeight) { - // Overflow impossible: weight values are bounded by uint64 and economic constraints - extraWeightRemoved += oldExtraWeight; - extraWeightAdded += _extraWeights[signer] = newExtraWeight; - emit ERC7913SignerWeightChanged(signer, weight); - } - } - } - unchecked { - // Safe from underflow: `extraWeightRemoved` is bounded by `_totalExtraWeight` by construction - // and weight values are bounded by uint64 and economic constraints - _totalExtraWeight = (uint256(_totalExtraWeight) + extraWeightAdded - extraWeightRemoved).toUint64(); - } - _validateReachableThreshold(); - } - - /** - * @dev See {MultiSignerERC7913-_addSigners}. - * - * In cases where {totalWeight} is almost `type(uint64).max` (due to a large `_totalExtraWeight`), adding new - * signers could cause the {totalWeight} computation to overflow. Adding a {totalWeight} calls after the new - * signers are added ensures no such overflow happens. - */ - function _addSigners(bytes[] memory newSigners) internal virtual override { - super._addSigners(newSigners); - - // This will revert if the new signers cause an overflow - _validateReachableThreshold(); - } - - /** - * @dev See {MultiSignerERC7913-_removeSigners}. - * - * Just like {_addSigners}, this function does not emit {ERC7913SignerWeightChanged} events. The - * {ERC7913SignerRemoved} event emitted by {MultiSignerERC7913-_removeSigners} is enough to track weights here. - */ - function _removeSigners(bytes[] memory signers) internal virtual override { - // Clean up weights for removed signers - // - // The `extraWeightRemoved` is bounded by `_totalExtraWeight`. The `super._removeSigners` function will revert - // if the signers array contains any duplicates, ensuring each signer's weight is only counted once. Since - // `_totalExtraWeight` is stored as a `uint64`, the final subtraction operation is also safe. - unchecked { - uint64 extraWeightRemoved = 0; - for (uint256 i = 0; i < signers.length; ++i) { - bytes memory signer = signers[i]; - - extraWeightRemoved += _extraWeights[signer]; - delete _extraWeights[signer]; - } - _totalExtraWeight -= extraWeightRemoved; - } - super._removeSigners(signers); - } - - /** - * @dev Sets the threshold for the multisignature operation. Internal version without access control. - * - * Requirements: - * - * * The {totalWeight} must be `>=` the {threshold}. Otherwise reverts with {MultiSignerERC7913UnreachableThreshold} - * - * NOTE: This function intentionally does not call `super._validateReachableThreshold` because the base implementation - * assumes each signer has a weight of 1, which is a subset of this weighted implementation. Consider that multiple - * implementations of this function may exist in the contract, so important side effects may be missed - * depending on the linearization order. - */ - function _validateReachableThreshold() internal view virtual override { - uint64 weight = totalWeight(); - uint64 currentThreshold = threshold(); - require(weight >= currentThreshold, MultiSignerERC7913UnreachableThreshold(weight, currentThreshold)); - } - - /** - * @dev Validates that the total weight of signers meets the threshold requirement. - * - * NOTE: This function intentionally does not call `super._validateThreshold` because the base implementation - * assumes each signer has a weight of 1, which is a subset of this weighted implementation. Consider that multiple - * implementations of this function may exist in the contract, so important side effects may be missed - * depending on the linearization order. - */ - function _validateThreshold(bytes[] memory signers) internal view virtual override returns (bool) { - unchecked { - uint64 weight = 0; - for (uint256 i = 0; i < signers.length; ++i) { - // Overflow impossible: weight values are bounded by uint64 and economic constraints - weight += signerWeight(signers[i]); - } - return weight >= threshold(); - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerECDSA.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerECDSA.sol deleted file mode 100644 index 517cd7e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerECDSA.sol +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerECDSA.sol) - -pragma solidity ^0.8.20; - -import {AbstractSigner} from "./AbstractSigner.sol"; -import {ECDSA} from "../ECDSA.sol"; - -/** - * @dev Implementation of {AbstractSigner} using xref:api:utils/cryptography#ECDSA[ECDSA] signatures. - * - * For {Account} usage, a {_setSigner} function is provided to set the {signer} address. - * Doing so is easier for a factory, who is likely to use initializable clones of this contract. - * - * Example of usage: - * - * ```solidity - * contract MyAccountECDSA is Account, SignerECDSA, Initializable { - * function initialize(address signerAddr) public initializer { - * _setSigner(signerAddr); - * } - * } - * ``` - * - * IMPORTANT: Failing to call {_setSigner} either during construction (if used standalone) - * or during initialization (if used as a clone) may leave the signer either front-runnable or unusable. - */ -abstract contract SignerECDSA is AbstractSigner { - address private _signer; - - constructor(address signerAddr) { - _setSigner(signerAddr); - } - - /** - * @dev Sets the signer with the address of the native signer. This function should be called during construction - * or through an initializer. - */ - function _setSigner(address signerAddr) internal { - _signer = signerAddr; - } - - /// @dev Return the signer's address. - function signer() public view virtual returns (address) { - return _signer; - } - - /// @inheritdoc AbstractSigner - function _rawSignatureValidation( - bytes32 hash, - bytes calldata signature - ) internal view virtual override returns (bool) { - (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature); - return signer() == recovered && err == ECDSA.RecoverError.NoError; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7702.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7702.sol deleted file mode 100644 index b02190e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7702.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerERC7702.sol) - -pragma solidity ^0.8.20; - -import {AbstractSigner} from "./AbstractSigner.sol"; -import {ECDSA} from "../ECDSA.sol"; - -/** - * @dev Implementation of {AbstractSigner} for implementation for an EOA. Useful for ERC-7702 accounts. - * - * @custom:stateless - */ -abstract contract SignerERC7702 is AbstractSigner { - /** - * @dev Validates the signature using the EOA's address (i.e. `address(this)`). - */ - function _rawSignatureValidation( - bytes32 hash, - bytes calldata signature - ) internal view virtual override returns (bool) { - (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature); - return address(this) == recovered && err == ECDSA.RecoverError.NoError; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7913.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7913.sol deleted file mode 100644 index d0f567a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7913.sol +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerERC7913.sol) - -pragma solidity ^0.8.24; - -import {AbstractSigner} from "./AbstractSigner.sol"; -import {SignatureChecker} from "../SignatureChecker.sol"; - -/** - * @dev Implementation of {AbstractSigner} using - * https://eips.ethereum.org/EIPS/eip-7913[ERC-7913] signature verification. - * - * For {Account} usage, a {_setSigner} function is provided to set the ERC-7913 formatted {signer}. - * Doing so is easier for a factory, who is likely to use initializable clones of this contract. - * - * The signer is a `bytes` object that concatenates a verifier address and a key: `verifier || key`. - * - * Example of usage: - * - * ```solidity - * contract MyAccountERC7913 is Account, SignerERC7913, Initializable { - * function initialize(bytes memory signer_) public initializer { - * _setSigner(signer_); - * } - * - * function setSigner(bytes memory signer_) public onlyEntryPointOrSelf { - * _setSigner(signer_); - * } - * } - * ``` - * - * IMPORTANT: Failing to call {_setSigner} either during construction (if used standalone) - * or during initialization (if used as a clone) may leave the signer either front-runnable or unusable. - */ - -abstract contract SignerERC7913 is AbstractSigner { - bytes private _signer; - - constructor(bytes memory signer_) { - _setSigner(signer_); - } - - /// @dev Return the ERC-7913 signer (i.e. `verifier || key`). - function signer() public view virtual returns (bytes memory) { - return _signer; - } - - /// @dev Sets the signer (i.e. `verifier || key`) with an ERC-7913 formatted signer. - function _setSigner(bytes memory signer_) internal { - _signer = signer_; - } - - /** - * @dev Verifies a signature using {SignatureChecker-isValidSignatureNow-bytes-bytes32-bytes-} - * with {signer}, `hash` and `signature`. - */ - function _rawSignatureValidation( - bytes32 hash, - bytes calldata signature - ) internal view virtual override returns (bool) { - return SignatureChecker.isValidSignatureNow(signer(), hash, signature); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerP256.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerP256.sol deleted file mode 100644 index 131b5c1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerP256.sol +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerP256.sol) - -pragma solidity ^0.8.20; - -import {AbstractSigner} from "./AbstractSigner.sol"; -import {P256} from "../P256.sol"; - -/** - * @dev Implementation of {AbstractSigner} using xref:api:utils/cryptography#P256[P256] signatures. - * - * For {Account} usage, a {_setSigner} function is provided to set the {signer} public key. - * Doing so is easier for a factory, who is likely to use initializable clones of this contract. - * - * Example of usage: - * - * ```solidity - * contract MyAccountP256 is Account, SignerP256, Initializable { - * function initialize(bytes32 qx, bytes32 qy) public initializer { - * _setSigner(qx, qy); - * } - * } - * ``` - * - * IMPORTANT: Failing to call {_setSigner} either during construction (if used standalone) - * or during initialization (if used as a clone) may leave the signer either front-runnable or unusable. - */ -abstract contract SignerP256 is AbstractSigner { - bytes32 private _qx; - bytes32 private _qy; - - error SignerP256InvalidPublicKey(bytes32 qx, bytes32 qy); - - constructor(bytes32 qx, bytes32 qy) { - _setSigner(qx, qy); - } - - /** - * @dev Sets the signer with a P256 public key. This function should be called during construction - * or through an initializer. - */ - function _setSigner(bytes32 qx, bytes32 qy) internal { - if (!P256.isValidPublicKey(qx, qy)) revert SignerP256InvalidPublicKey(qx, qy); - _qx = qx; - _qy = qy; - } - - /// @dev Return the signer's P256 public key. - function signer() public view virtual returns (bytes32 qx, bytes32 qy) { - return (_qx, _qy); - } - - /// @inheritdoc AbstractSigner - function _rawSignatureValidation( - bytes32 hash, - bytes calldata signature - ) internal view virtual override returns (bool) { - if (signature.length < 0x40) return false; - bytes32 r = bytes32(signature[0x00:0x20]); - bytes32 s = bytes32(signature[0x20:0x40]); - (bytes32 qx, bytes32 qy) = signer(); - return P256.verify(hash, r, s, qx, qy); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerRSA.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerRSA.sol deleted file mode 100644 index 7ca18ea..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerRSA.sol +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerRSA.sol) - -pragma solidity ^0.8.20; - -import {AbstractSigner} from "./AbstractSigner.sol"; -import {RSA} from "../RSA.sol"; - -/** - * @dev Implementation of {AbstractSigner} using xref:api:utils/cryptography#RSA[RSA] signatures. - * - * For {Account} usage, a {_setSigner} function is provided to set the {signer} public key. - * Doing so is easier for a factory, who is likely to use initializable clones of this contract. - * - * Example of usage: - * - * ```solidity - * contract MyAccountRSA is Account, SignerRSA, Initializable { - * function initialize(bytes memory e, bytes memory n) public initializer { - * _setSigner(e, n); - * } - * } - * ``` - * - * IMPORTANT: Failing to call {_setSigner} either during construction (if used standalone) - * or during initialization (if used as a clone) may leave the signer either front-runnable or unusable. - */ -abstract contract SignerRSA is AbstractSigner { - bytes private _e; - bytes private _n; - - constructor(bytes memory e, bytes memory n) { - _setSigner(e, n); - } - - /** - * @dev Sets the signer with a RSA public key. This function should be called during construction - * or through an initializer. - */ - function _setSigner(bytes memory e, bytes memory n) internal { - _e = e; - _n = n; - } - - /// @dev Return the signer's RSA public key. - function signer() public view virtual returns (bytes memory e, bytes memory n) { - return (_e, _n); - } - - /** - * @dev See {AbstractSigner-_rawSignatureValidation}. Verifies a PKCSv1.5 signature by calling - * xref:api:utils/cryptography.adoc#RSA-pkcs1Sha256-bytes-bytes-bytes-bytes-[RSA.pkcs1Sha256]. - * - * IMPORTANT: Following the RSASSA-PKCS1-V1_5-VERIFY procedure outlined in RFC8017 (section 8.2.2), the - * provided `hash` is used as the `M` (message) and rehashed using SHA256 according to EMSA-PKCS1-v1_5 - * encoding as per section 9.2 (step 1) of the RFC. - */ - function _rawSignatureValidation( - bytes32 hash, - bytes calldata signature - ) internal view virtual override returns (bool) { - (bytes memory e, bytes memory n) = signer(); - return RSA.pkcs1Sha256(abi.encodePacked(hash), signature, e, n); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/draft-ERC7739.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/draft-ERC7739.sol deleted file mode 100644 index 003b915..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/signers/draft-ERC7739.sol +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/draft-ERC7739.sol) - -pragma solidity ^0.8.20; - -import {AbstractSigner} from "./AbstractSigner.sol"; -import {EIP712} from "../EIP712.sol"; -import {ERC7739Utils} from "../draft-ERC7739Utils.sol"; -import {IERC1271} from "../../../interfaces/IERC1271.sol"; -import {MessageHashUtils} from "../MessageHashUtils.sol"; -import {ShortStrings} from "../../ShortStrings.sol"; - -/** - * @dev Validates signatures wrapping the message hash in a nested EIP712 type. See {ERC7739Utils}. - * - * Linking the signature to the EIP-712 domain separator is a security measure to prevent signature replay across different - * EIP-712 domains (e.g. a single offchain owner of multiple contracts). - * - * This contract requires implementing the {_rawSignatureValidation} function, which passes the wrapped message hash, - * which may be either an typed data or a personal sign nested type. - * - * NOTE: xref:api:utils/cryptography#EIP712[EIP-712] uses xref:api:utils/cryptography#ShortStrings[ShortStrings] to - * optimize gas costs for short strings (up to 31 characters). Consider that strings longer than that will use storage, - * which may limit the ability of the signer to be used within the ERC-4337 validation phase (due to - * https://eips.ethereum.org/EIPS/eip-7562#storage-rules[ERC-7562 storage access rules]). - */ -abstract contract ERC7739 is AbstractSigner, EIP712, IERC1271 { - using ERC7739Utils for *; - using MessageHashUtils for bytes32; - - /** - * @dev Attempts validating the signature in a nested EIP-712 type. - * - * A nested EIP-712 type might be presented in 2 different ways: - * - * - As a nested EIP-712 typed data - * - As a _personal_ signature (an EIP-712 mimic of the `eth_personalSign` for a smart contract) - */ - function isValidSignature(bytes32 hash, bytes calldata signature) public view virtual returns (bytes4 result) { - // For the hash `0x7739773977397739773977397739773977397739773977397739773977397739` and an empty signature, - // we return the magic value `0x77390001` as it's assumed impossible to find a preimage for it that can be used - // maliciously. Useful for simulation purposes and to validate whether the contract supports ERC-7739. - return - (_isValidNestedTypedDataSignature(hash, signature) || _isValidNestedPersonalSignSignature(hash, signature)) - ? IERC1271.isValidSignature.selector - : (hash == 0x7739773977397739773977397739773977397739773977397739773977397739 && signature.length == 0) - ? bytes4(0x77390001) - : bytes4(0xffffffff); - } - - /** - * @dev Nested personal signature verification. - */ - function _isValidNestedPersonalSignSignature(bytes32 hash, bytes calldata signature) private view returns (bool) { - return _rawSignatureValidation(_domainSeparatorV4().toTypedDataHash(hash.personalSignStructHash()), signature); - } - - /** - * @dev Nested EIP-712 typed data verification. - */ - function _isValidNestedTypedDataSignature( - bytes32 hash, - bytes calldata encodedSignature - ) private view returns (bool) { - // decode signature - ( - bytes calldata signature, - bytes32 appSeparator, - bytes32 contentsHash, - string calldata contentsDescr - ) = encodedSignature.decodeTypedDataSig(); - - ( - , - string memory name, - string memory version, - uint256 chainId, - address verifyingContract, - bytes32 salt, - - ) = eip712Domain(); - - // Check that contentHash and separator are correct - // Rebuild nested hash - return - hash == appSeparator.toTypedDataHash(contentsHash) && - bytes(contentsDescr).length != 0 && - _rawSignatureValidation( - appSeparator.toTypedDataHash( - ERC7739Utils.typedDataSignStructHash( - contentsDescr, - contentsHash, - abi.encode(keccak256(bytes(name)), keccak256(bytes(version)), chainId, verifyingContract, salt) - ) - ), - signature - ); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913P256Verifier.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913P256Verifier.sol deleted file mode 100644 index 60091c9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913P256Verifier.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/verifiers/ERC7913P256Verifier.sol) - -pragma solidity ^0.8.20; - -import {P256} from "../../../utils/cryptography/P256.sol"; -import {IERC7913SignatureVerifier} from "../../../interfaces/IERC7913.sol"; - -/** - * @dev ERC-7913 signature verifier that support P256 (secp256r1) keys. - * - * @custom:stateless - */ -contract ERC7913P256Verifier is IERC7913SignatureVerifier { - /// @inheritdoc IERC7913SignatureVerifier - function verify(bytes calldata key, bytes32 hash, bytes calldata signature) public view virtual returns (bytes4) { - // Signature length may be 0x40 or 0x41. - if (key.length == 0x40 && signature.length >= 0x40) { - bytes32 qx = bytes32(key[0x00:0x20]); - bytes32 qy = bytes32(key[0x20:0x40]); - bytes32 r = bytes32(signature[0x00:0x20]); - bytes32 s = bytes32(signature[0x20:0x40]); - if (P256.verify(hash, r, s, qx, qy)) { - return IERC7913SignatureVerifier.verify.selector; - } - } - return 0xFFFFFFFF; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913RSAVerifier.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913RSAVerifier.sol deleted file mode 100644 index 07f58c8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913RSAVerifier.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/verifiers/ERC7913RSAVerifier.sol) - -pragma solidity ^0.8.20; - -import {RSA} from "../../../utils/cryptography/RSA.sol"; -import {IERC7913SignatureVerifier} from "../../../interfaces/IERC7913.sol"; - -/** - * @dev ERC-7913 signature verifier that support RSA keys. - * - * @custom:stateless - */ -contract ERC7913RSAVerifier is IERC7913SignatureVerifier { - /// @inheritdoc IERC7913SignatureVerifier - function verify(bytes calldata key, bytes32 hash, bytes calldata signature) public view virtual returns (bytes4) { - (bytes memory e, bytes memory n) = abi.decode(key, (bytes, bytes)); - return - RSA.pkcs1Sha256(abi.encodePacked(hash), signature, e, n) - ? IERC7913SignatureVerifier.verify.selector - : bytes4(0xFFFFFFFF); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol deleted file mode 100644 index be4cc5a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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 ERC-165 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 { - /// @inheritdoc IERC165 - function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { - return interfaceId == type(IERC165).interfaceId; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol deleted file mode 100644 index 8650f55..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.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 ERC-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 ERC-165 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 ERC-165 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 ERC-165 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 ERC-165 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 ERC-165 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 ERC-165, 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 ("memory-safe") { - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol deleted file mode 100644 index be1932f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol) - -pragma solidity >=0.4.16; - -/** - * @dev Interface of the ERC-165 standard, as defined in the - * https://eips.ethereum.org/EIPS/eip-165[ERC]. - * - * 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[ERC 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/Math.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/Math.sol deleted file mode 100644 index f0d608a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/Math.sol +++ /dev/null @@ -1,749 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol) - -pragma solidity ^0.8.20; - -import {Panic} from "../Panic.sol"; -import {SafeCast} from "./SafeCast.sol"; - -/** - * @dev Standard math utilities missing in the Solidity language. - */ -library Math { - enum Rounding { - Floor, // Toward negative infinity - Ceil, // Toward positive infinity - Trunc, // Toward zero - Expand // Away from zero - } - - /** - * @dev Return the 512-bit addition of two uint256. - * - * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low. - */ - function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) { - assembly ("memory-safe") { - low := add(a, b) - high := lt(low, a) - } - } - - /** - * @dev Return the 512-bit multiplication of two uint256. - * - * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low. - */ - function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) { - // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use - // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 - // variables such that product = high * 2²⁵⁶ + low. - assembly ("memory-safe") { - let mm := mulmod(a, b, not(0)) - low := mul(a, b) - high := sub(sub(mm, low), lt(mm, low)) - } - } - - /** - * @dev Returns the addition of two unsigned integers, with a success flag (no overflow). - */ - function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { - unchecked { - uint256 c = a + b; - success = c >= a; - result = c * SafeCast.toUint(success); - } - } - - /** - * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow). - */ - function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { - unchecked { - uint256 c = a - b; - success = c <= a; - result = c * SafeCast.toUint(success); - } - } - - /** - * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow). - */ - function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { - unchecked { - uint256 c = a * b; - assembly ("memory-safe") { - // Only true when the multiplication doesn't overflow - // (c / a == b) || (a == 0) - success := or(eq(div(c, a), b), iszero(a)) - } - // equivalent to: success ? c : 0 - result = c * SafeCast.toUint(success); - } - } - - /** - * @dev Returns the division of two unsigned integers, with a success flag (no division by zero). - */ - function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { - unchecked { - success = b > 0; - assembly ("memory-safe") { - // The `DIV` opcode returns zero when the denominator is 0. - result := div(a, b) - } - } - } - - /** - * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero). - */ - function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { - unchecked { - success = b > 0; - assembly ("memory-safe") { - // The `MOD` opcode returns zero when the denominator is 0. - result := mod(a, b) - } - } - } - - /** - * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing. - */ - function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) { - (bool success, uint256 result) = tryAdd(a, b); - return ternary(success, result, type(uint256).max); - } - - /** - * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing. - */ - function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) { - (, uint256 result) = trySub(a, b); - return result; - } - - /** - * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing. - */ - function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) { - (bool success, uint256 result) = tryMul(a, b); - return ternary(success, result, type(uint256).max); - } - - /** - * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. - * - * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. - * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute - * one branch when needed, making this function more expensive. - */ - function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) { - unchecked { - // branchless ternary works because: - // b ^ (a ^ b) == a - // b ^ 0 == b - return b ^ ((a ^ b) * SafeCast.toUint(condition)); - } - } - - /** - * @dev Returns the largest of two numbers. - */ - function max(uint256 a, uint256 b) internal pure returns (uint256) { - return ternary(a > b, a, b); - } - - /** - * @dev Returns the smallest of two numbers. - */ - function min(uint256 a, uint256 b) internal pure returns (uint256) { - return ternary(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. - Panic.panic(Panic.DIVISION_BY_ZERO); - } - - // The following calculation ensures accurate ceiling division without overflow. - // Since a is non-zero, (a - 1) / b will not overflow. - // The largest possible result occurs when (a - 1) / b is type(uint256).max, - // but the largest value we can obtain is type(uint256).max - 1, which happens - // when a = type(uint256).max and b = 1. - unchecked { - return SafeCast.toUint(a > 0) * ((a - 1) / b + 1); - } - } - - /** - * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or - * denominator == 0. - * - * 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 { - (uint256 high, uint256 low) = mul512(x, y); - - // Handle non-overflow cases, 256 by 256 division. - if (high == 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 low / denominator; - } - - // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0. - if (denominator <= high) { - Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW)); - } - - /////////////////////////////////////////////// - // 512 by 256 division. - /////////////////////////////////////////////// - - // Make division exact by subtracting the remainder from [high low]. - uint256 remainder; - assembly ("memory-safe") { - // Compute remainder using mulmod. - remainder := mulmod(x, y, denominator) - - // Subtract 256 bit number from 512 bit number. - high := sub(high, gt(remainder, low)) - low := sub(low, 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 ("memory-safe") { - // Divide denominator by twos. - denominator := div(denominator, twos) - - // Divide [high low] by twos. - low := div(low, twos) - - // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one. - twos := add(div(sub(0, twos), twos), 1) - } - - // Shift in bits from high into low. - low |= high * twos; - - // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such - // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for - // four bits. That is, denominator * inv ≡ 1 mod 2⁴. - 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⁸ - inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶ - inverse *= 2 - denominator * inverse; // inverse mod 2³² - inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴ - inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸ - inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶ - - // 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²⁵⁶. Since the preconditions guarantee that the outcome is - // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high - // is no longer required. - result = low * inverse; - return result; - } - } - - /** - * @dev 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) { - return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0); - } - - /** - * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256. - */ - function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) { - unchecked { - (uint256 high, uint256 low) = mul512(x, y); - if (high >= 1 << n) { - Panic.panic(Panic.UNDER_OVERFLOW); - } - return (high << (256 - n)) | (low >> n); - } - } - - /** - * @dev Calculates x * y >> n with full precision, following the selected rounding direction. - */ - function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) { - return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0); - } - - /** - * @dev Calculate the modular multiplicative inverse of a number in Z/nZ. - * - * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0. - * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible. - * - * If the input value is not inversible, 0 is returned. - * - * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the - * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}. - */ - function invMod(uint256 a, uint256 n) internal pure returns (uint256) { - unchecked { - if (n == 0) return 0; - - // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version) - // Used to compute integers x and y such that: ax + ny = gcd(a, n). - // When the gcd is 1, then the inverse of a modulo n exists and it's x. - // ax + ny = 1 - // ax = 1 + (-y)n - // ax ≡ 1 (mod n) # x is the inverse of a modulo n - - // If the remainder is 0 the gcd is n right away. - uint256 remainder = a % n; - uint256 gcd = n; - - // Therefore the initial coefficients are: - // ax + ny = gcd(a, n) = n - // 0a + 1n = n - int256 x = 0; - int256 y = 1; - - while (remainder != 0) { - uint256 quotient = gcd / remainder; - - (gcd, remainder) = ( - // The old remainder is the next gcd to try. - remainder, - // Compute the next remainder. - // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd - // where gcd is at most n (capped to type(uint256).max) - gcd - remainder * quotient - ); - - (x, y) = ( - // Increment the coefficient of a. - y, - // Decrement the coefficient of n. - // Can overflow, but the result is casted to uint256 so that the - // next value of y is "wrapped around" to a value between 0 and n - 1. - x - y * int256(quotient) - ); - } - - if (gcd != 1) return 0; // No inverse exists. - return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative. - } - } - - /** - * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`. - * - * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is - * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that - * `a**(p-2)` is the modular multiplicative inverse of a in Fp. - * - * NOTE: this function does NOT check that `p` is a prime greater than `2`. - */ - function invModPrime(uint256 a, uint256 p) internal view returns (uint256) { - unchecked { - return Math.modExp(a, p - 2, p); - } - } - - /** - * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m) - * - * Requirements: - * - modulus can't be zero - * - underlying staticcall to precompile must succeed - * - * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make - * sure the chain you're using it on supports the precompiled contract for modular exponentiation - * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, - * the underlying function will succeed given the lack of a revert, but the result may be incorrectly - * interpreted as 0. - */ - function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) { - (bool success, uint256 result) = tryModExp(b, e, m); - if (!success) { - Panic.panic(Panic.DIVISION_BY_ZERO); - } - return result; - } - - /** - * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m). - * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying - * to operate modulo 0 or if the underlying precompile reverted. - * - * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain - * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in - * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack - * of a revert, but the result may be incorrectly interpreted as 0. - */ - function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) { - if (m == 0) return (false, 0); - assembly ("memory-safe") { - let ptr := mload(0x40) - // | Offset | Content | Content (Hex) | - // |-----------|------------|--------------------------------------------------------------------| - // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 | - // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 | - // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 | - // | 0x60:0x7f | value of b | 0x<.............................................................b> | - // | 0x80:0x9f | value of e | 0x<.............................................................e> | - // | 0xa0:0xbf | value of m | 0x<.............................................................m> | - mstore(ptr, 0x20) - mstore(add(ptr, 0x20), 0x20) - mstore(add(ptr, 0x40), 0x20) - mstore(add(ptr, 0x60), b) - mstore(add(ptr, 0x80), e) - mstore(add(ptr, 0xa0), m) - - // Given the result < m, it's guaranteed to fit in 32 bytes, - // so we can use the memory scratch space located at offset 0. - success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20) - result := mload(0x00) - } - } - - /** - * @dev Variant of {modExp} that supports inputs of arbitrary length. - */ - function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) { - (bool success, bytes memory result) = tryModExp(b, e, m); - if (!success) { - Panic.panic(Panic.DIVISION_BY_ZERO); - } - return result; - } - - /** - * @dev Variant of {tryModExp} that supports inputs of arbitrary length. - */ - function tryModExp( - bytes memory b, - bytes memory e, - bytes memory m - ) internal view returns (bool success, bytes memory result) { - if (_zeroBytes(m)) return (false, new bytes(0)); - - uint256 mLen = m.length; - - // Encode call args in result and move the free memory pointer - result = abi.encodePacked(b.length, e.length, mLen, b, e, m); - - assembly ("memory-safe") { - let dataPtr := add(result, 0x20) - // Write result on top of args to avoid allocating extra memory. - success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen) - // Overwrite the length. - // result.length > returndatasize() is guaranteed because returndatasize() == m.length - mstore(result, mLen) - // Set the memory pointer after the returned data. - mstore(0x40, add(dataPtr, mLen)) - } - } - - /** - * @dev Returns whether the provided byte array is zero. - */ - function _zeroBytes(bytes memory byteArray) private pure returns (bool) { - for (uint256 i = 0; i < byteArray.length; ++i) { - if (byteArray[i] != 0) { - return false; - } - } - return true; - } - - /** - * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded - * towards zero. - * - * This method is based on Newton's method for computing square roots; the algorithm is restricted to only - * using integer operations. - */ - function sqrt(uint256 a) internal pure returns (uint256) { - unchecked { - // Take care of easy edge cases when a == 0 or a == 1 - if (a <= 1) { - return a; - } - - // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a - // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between - // the current value as `ε_n = | x_n - sqrt(a) |`. - // - // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root - // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is - // bigger than any uint256. - // - // By noticing that - // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)` - // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar - // to the msb function. - uint256 aa = a; - uint256 xn = 1; - - if (aa >= (1 << 128)) { - aa >>= 128; - xn <<= 64; - } - if (aa >= (1 << 64)) { - aa >>= 64; - xn <<= 32; - } - if (aa >= (1 << 32)) { - aa >>= 32; - xn <<= 16; - } - if (aa >= (1 << 16)) { - aa >>= 16; - xn <<= 8; - } - if (aa >= (1 << 8)) { - aa >>= 8; - xn <<= 4; - } - if (aa >= (1 << 4)) { - aa >>= 4; - xn <<= 2; - } - if (aa >= (1 << 2)) { - xn <<= 1; - } - - // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1). - // - // We can refine our estimation by noticing that the middle of that interval minimizes the error. - // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2). - // This is going to be our x_0 (and ε_0) - xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2) - - // From here, Newton's method give us: - // x_{n+1} = (x_n + a / x_n) / 2 - // - // One should note that: - // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a - // = ((x_n² + a) / (2 * x_n))² - a - // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a - // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²) - // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²) - // = (x_n² - a)² / (2 * x_n)² - // = ((x_n² - a) / (2 * x_n))² - // ≥ 0 - // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n - // - // This gives us the proof of quadratic convergence of the sequence: - // ε_{n+1} = | x_{n+1} - sqrt(a) | - // = | (x_n + a / x_n) / 2 - sqrt(a) | - // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) | - // = | (x_n - sqrt(a))² / (2 * x_n) | - // = | ε_n² / (2 * x_n) | - // = ε_n² / | (2 * x_n) | - // - // For the first iteration, we have a special case where x_0 is known: - // ε_1 = ε_0² / | (2 * x_0) | - // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2))) - // ≤ 2**(2*e-4) / (3 * 2**(e-1)) - // ≤ 2**(e-3) / 3 - // ≤ 2**(e-3-log2(3)) - // ≤ 2**(e-4.5) - // - // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n: - // ε_{n+1} = ε_n² / | (2 * x_n) | - // ≤ (2**(e-k))² / (2 * 2**(e-1)) - // ≤ 2**(2*e-2*k) / 2**e - // ≤ 2**(e-2*k) - xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above - xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5 - xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9 - xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18 - xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36 - xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72 - - // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision - // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either - // sqrt(a) or sqrt(a) + 1. - return xn - SafeCast.toUint(xn > a / xn); - } - } - - /** - * @dev 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a); - } - } - - /** - * @dev Return the log in base 2 of a positive value rounded towards zero. - * Returns 0 if given 0. - */ - function log2(uint256 x) internal pure returns (uint256 r) { - // If value has upper 128 bits set, log2 result is at least 128 - r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7; - // If upper 64 bits of 128-bit half set, add 64 to result - r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6; - // If upper 32 bits of 64-bit half set, add 32 to result - r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5; - // If upper 16 bits of 32-bit half set, add 16 to result - r |= SafeCast.toUint((x >> r) > 0xffff) << 4; - // If upper 8 bits of 16-bit half set, add 8 to result - r |= SafeCast.toUint((x >> r) > 0xff) << 3; - // If upper 4 bits of 8-bit half set, add 4 to result - r |= SafeCast.toUint((x >> r) > 0xf) << 2; - - // Shifts value right by the current result and use it as an index into this lookup table: - // - // | x (4 bits) | index | table[index] = MSB position | - // |------------|---------|-----------------------------| - // | 0000 | 0 | table[0] = 0 | - // | 0001 | 1 | table[1] = 0 | - // | 0010 | 2 | table[2] = 1 | - // | 0011 | 3 | table[3] = 1 | - // | 0100 | 4 | table[4] = 2 | - // | 0101 | 5 | table[5] = 2 | - // | 0110 | 6 | table[6] = 2 | - // | 0111 | 7 | table[7] = 2 | - // | 1000 | 8 | table[8] = 3 | - // | 1001 | 9 | table[9] = 3 | - // | 1010 | 10 | table[10] = 3 | - // | 1011 | 11 | table[11] = 3 | - // | 1100 | 12 | table[12] = 3 | - // | 1101 | 13 | table[13] = 3 | - // | 1110 | 14 | table[14] = 3 | - // | 1111 | 15 | table[15] = 3 | - // - // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes. - assembly ("memory-safe") { - r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000)) - } - } - - /** - * @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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value); - } - } - - /** - * @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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value); - } - } - - /** - * @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 x) internal pure returns (uint256 r) { - // If value has upper 128 bits set, log2 result is at least 128 - r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7; - // If upper 64 bits of 128-bit half set, add 64 to result - r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6; - // If upper 32 bits of 64-bit half set, add 32 to result - r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5; - // If upper 16 bits of 32-bit half set, add 16 to result - r |= SafeCast.toUint((x >> r) > 0xffff) << 4; - // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8 - return (r >> 3) | SafeCast.toUint((x >> r) > 0xff); - } - - /** - * @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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value); - } - } - - /** - * @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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol deleted file mode 100644 index b345ede..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol +++ /dev/null @@ -1,1162 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.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/bool 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); - } - - /** - * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. - */ - function toUint(bool b) internal pure returns (uint256 u) { - assembly ("memory-safe") { - u := iszero(iszero(b)) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol deleted file mode 100644 index 7c97aa4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol) - -pragma solidity ^0.8.20; - -import {SafeCast} from "./SafeCast.sol"; - -/** - * @dev Standard signed math utilities missing in the Solidity language. - */ -library SignedMath { - /** - * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. - * - * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. - * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute - * one branch when needed, making this function more expensive. - */ - function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) { - unchecked { - // branchless ternary works because: - // b ^ (a ^ b) == a - // b ^ 0 == b - return b ^ ((a ^ b) * int256(SafeCast.toUint(condition))); - } - } - - /** - * @dev Returns the largest of two signed numbers. - */ - function max(int256 a, int256 b) internal pure returns (int256) { - return ternary(a > b, a, b); - } - - /** - * @dev Returns the smallest of two signed numbers. - */ - function min(int256 a, int256 b) internal pure returns (int256) { - return ternary(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 { - // Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson. - // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift, - // taking advantage of the most significant (or "sign" bit) in two's complement representation. - // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result, - // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative). - int256 mask = n >> 255; - - // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it. - return uint256((n + mask) ^ mask); - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol deleted file mode 100644 index 40cceb9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol +++ /dev/null @@ -1,60 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol deleted file mode 100644 index ce88f51..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol +++ /dev/null @@ -1,630 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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 oldValue, uint224 newValue) { - 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 optimized 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 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1); - return (true, ckpt._key, ckpt._value); - } - } - - /** - * @dev Returns the number of checkpoints. - */ - 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 oldValue, uint224 newValue) { - uint256 pos = self.length; - - if (pos > 0) { - Checkpoint224 storage last = _unsafeAccess(self, pos - 1); - uint32 lastKey = last._key; - uint224 lastValue = last._value; - - // Checkpoint keys must be non-decreasing. - if (lastKey > key) { - revert CheckpointUnorderedInsertion(); - } - - // Update or push new checkpoint - if (lastKey == key) { - last._value = value; - } else { - self.push(Checkpoint224({_key: key, _value: value})); - } - return (lastValue, value); - } else { - self.push(Checkpoint224({_key: key, _value: value})); - return (0, value); - } - } - - /** - * @dev Return the index of the first (oldest) checkpoint with key strictly bigger 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 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 oldValue, uint208 newValue) { - 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 optimized 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 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1); - return (true, ckpt._key, ckpt._value); - } - } - - /** - * @dev Returns the number of checkpoints. - */ - 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 oldValue, uint208 newValue) { - uint256 pos = self.length; - - if (pos > 0) { - Checkpoint208 storage last = _unsafeAccess(self, pos - 1); - uint48 lastKey = last._key; - uint208 lastValue = last._value; - - // Checkpoint keys must be non-decreasing. - if (lastKey > key) { - revert CheckpointUnorderedInsertion(); - } - - // Update or push new checkpoint - if (lastKey == key) { - last._value = value; - } else { - self.push(Checkpoint208({_key: key, _value: value})); - } - return (lastValue, value); - } else { - self.push(Checkpoint208({_key: key, _value: value})); - return (0, value); - } - } - - /** - * @dev Return the index of the first (oldest) checkpoint with key strictly bigger 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 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 oldValue, uint160 newValue) { - 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 optimized 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 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1); - return (true, ckpt._key, ckpt._value); - } - } - - /** - * @dev Returns the number of checkpoints. - */ - 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 oldValue, uint160 newValue) { - uint256 pos = self.length; - - if (pos > 0) { - Checkpoint160 storage last = _unsafeAccess(self, pos - 1); - uint96 lastKey = last._key; - uint160 lastValue = last._value; - - // Checkpoint keys must be non-decreasing. - if (lastKey > key) { - revert CheckpointUnorderedInsertion(); - } - - // Update or push new checkpoint - if (lastKey == key) { - last._value = value; - } else { - self.push(Checkpoint160({_key: key, _value: value})); - } - return (lastValue, value); - } else { - self.push(Checkpoint160({_key: key, _value: value})); - return (0, value); - } - } - - /** - * @dev Return the index of the first (oldest) checkpoint with key strictly bigger 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 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/CircularBuffer.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/CircularBuffer.sol deleted file mode 100644 index 43ce89b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/CircularBuffer.sol +++ /dev/null @@ -1,140 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/CircularBuffer.sol) -pragma solidity ^0.8.20; - -import {Math} from "../math/Math.sol"; -import {Arrays} from "../Arrays.sol"; -import {Panic} from "../Panic.sol"; - -/** - * @dev A fixed-size buffer for keeping `bytes32` items in storage. - * - * This data structure allows for pushing elements to it, and when its length exceeds the specified fixed size, - * new items take the place of the oldest element in the buffer, keeping at most `N` elements in the - * structure. - * - * Elements can't be removed but the data structure can be cleared. See {clear}. - * - * Complexity: - * - insertion ({push}): O(1) - * - lookup ({last}): O(1) - * - inclusion ({includes}): O(N) (worst case) - * - reset ({clear}): O(1) - * - * * The struct is called `Bytes32CircularBuffer`. Other types can be cast to and from `bytes32`. This data structure - * can only be used in storage, and not in memory. - * - * Example usage: - * - * ```solidity - * contract Example { - * // Add the library methods - * using CircularBuffer for CircularBuffer.Bytes32CircularBuffer; - * - * // Declare a buffer storage variable - * CircularBuffer.Bytes32CircularBuffer private myBuffer; - * } - * ``` - * - * _Available since v5.1._ - */ -library CircularBuffer { - /** - * @dev Error emitted when trying to setup a buffer with a size of 0. - */ - error InvalidBufferSize(); - - /** - * @dev Counts the number of items that have been pushed to the buffer. The residuo modulo _data.length indicates - * where the next value should be stored. - * - * 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. - * - * In a full buffer: - * - The most recently pushed item (last) is at data[(index - 1) % data.length] - * - The oldest item (first) is at data[index % data.length] - */ - struct Bytes32CircularBuffer { - uint256 _count; - bytes32[] _data; - } - - /** - * @dev Initialize a new CircularBuffer of a given size. - * - * If the CircularBuffer was already setup and used, calling that function again will reset it to a blank state. - * - * NOTE: The size of the buffer will affect the execution of {includes} function, as it has a complexity of O(N). - * Consider a large buffer size may render the function unusable. - */ - function setup(Bytes32CircularBuffer storage self, uint256 size) internal { - if (size == 0) revert InvalidBufferSize(); - clear(self); - Arrays.unsafeSetLength(self._data, size); - } - - /** - * @dev Clear all data in the buffer without resetting memory, keeping the existing size. - */ - function clear(Bytes32CircularBuffer storage self) internal { - self._count = 0; - } - - /** - * @dev Push a new value to the buffer. If the buffer is already full, the new value replaces the oldest value in - * the buffer. - */ - function push(Bytes32CircularBuffer storage self, bytes32 value) internal { - uint256 index = self._count++; - uint256 modulus = self._data.length; - Arrays.unsafeAccess(self._data, index % modulus).value = value; - } - - /** - * @dev Number of values currently in the buffer. This value is 0 for an empty buffer, and cannot exceed the size of - * the buffer. - */ - function count(Bytes32CircularBuffer storage self) internal view returns (uint256) { - return Math.min(self._count, self._data.length); - } - - /** - * @dev Length of the buffer. This is the maximum number of elements kept in the buffer. - */ - function length(Bytes32CircularBuffer storage self) internal view returns (uint256) { - return self._data.length; - } - - /** - * @dev Getter for the i-th value in the buffer, from the end. - * - * Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if trying to access an element that was not pushed, or that was - * dropped to make room for newer elements. - */ - function last(Bytes32CircularBuffer storage self, uint256 i) internal view returns (bytes32) { - uint256 index = self._count; - uint256 modulus = self._data.length; - uint256 total = Math.min(index, modulus); // count(self) - if (i >= total) { - Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS); - } - return Arrays.unsafeAccess(self._data, (index - i - 1) % modulus).value; - } - - /** - * @dev Check if a given value is in the buffer. - */ - function includes(Bytes32CircularBuffer storage self, bytes32 value) internal view returns (bool) { - uint256 index = self._count; - uint256 modulus = self._data.length; - uint256 total = Math.min(index, modulus); // count(self) - for (uint256 i = 0; i < total; ++i) { - if (Arrays.unsafeAccess(self._data, (index - i - 1) % modulus).value == value) { - return true; - } - } - return false; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol deleted file mode 100644 index f243243..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol +++ /dev/null @@ -1,156 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/DoubleEndedQueue.sol) -pragma solidity ^0.8.20; - -import {Panic} from "../Panic.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; - * ``` - */ -library DoubleEndedQueue { - /** - * @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 {Panic-RESOURCE_ERROR} if the queue is full. - */ - function pushBack(Bytes32Deque storage deque, bytes32 value) internal { - unchecked { - uint128 backIndex = deque._end; - if (backIndex + 1 == deque._begin) Panic.panic(Panic.RESOURCE_ERROR); - deque._data[backIndex] = value; - deque._end = backIndex + 1; - } - } - - /** - * @dev Removes the item at the end of the queue and returns it. - * - * Reverts with {Panic-EMPTY_ARRAY_POP} if the queue is empty. - */ - function popBack(Bytes32Deque storage deque) internal returns (bytes32 value) { - unchecked { - uint128 backIndex = deque._end; - if (backIndex == deque._begin) Panic.panic(Panic.EMPTY_ARRAY_POP); - --backIndex; - value = deque._data[backIndex]; - delete deque._data[backIndex]; - deque._end = backIndex; - } - } - - /** - * @dev Inserts an item at the beginning of the queue. - * - * Reverts with {Panic-RESOURCE_ERROR} if the queue is full. - */ - function pushFront(Bytes32Deque storage deque, bytes32 value) internal { - unchecked { - uint128 frontIndex = deque._begin - 1; - if (frontIndex == deque._end) Panic.panic(Panic.RESOURCE_ERROR); - deque._data[frontIndex] = value; - deque._begin = frontIndex; - } - } - - /** - * @dev Removes the item at the beginning of the queue and returns it. - * - * Reverts with {Panic-EMPTY_ARRAY_POP} if the queue is empty. - */ - function popFront(Bytes32Deque storage deque) internal returns (bytes32 value) { - unchecked { - uint128 frontIndex = deque._begin; - if (frontIndex == deque._end) Panic.panic(Panic.EMPTY_ARRAY_POP); - value = deque._data[frontIndex]; - delete deque._data[frontIndex]; - deque._begin = frontIndex + 1; - } - } - - /** - * @dev Returns the item at the beginning of the queue. - * - * Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the queue is empty. - */ - function front(Bytes32Deque storage deque) internal view returns (bytes32 value) { - if (empty(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS); - return deque._data[deque._begin]; - } - - /** - * @dev Returns the item at the end of the queue. - * - * Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the queue is empty. - */ - function back(Bytes32Deque storage deque) internal view returns (bytes32 value) { - if (empty(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS); - 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 {Panic-ARRAY_OUT_OF_BOUNDS} if the index is out of bounds. - */ - function at(Bytes32Deque storage deque, uint256 index) internal view returns (bytes32 value) { - if (index >= length(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS); - // 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol deleted file mode 100644 index 68ce322..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol +++ /dev/null @@ -1,1319 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.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. - * - Map can be cleared (all entries removed) in O(n). - * - * ```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 - * - `uint256 -> bytes32` (`UintToBytes32Map`) since v5.1.0 - * - `address -> address` (`AddressToAddressMap`) since v5.1.0 - * - `address -> bytes32` (`AddressToBytes32Map`) since v5.1.0 - * - `bytes32 -> address` (`Bytes32ToAddressMap`) since v5.1.0 - * - `bytes -> bytes` (`BytesToBytesMap`) since v5.4.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 *; - - // 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 Removes all the entries from a map. O(n). - * - * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the - * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block. - */ - function clear(Bytes32ToBytes32Map storage map) internal { - uint256 len = length(map); - for (uint256 i = 0; i < len; ++i) { - delete map._values[map._keys.at(i)]; - } - map._keys.clear(); - } - - /** - * @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 key, bytes32 value) { - bytes32 atKey = map._keys.at(index); - return (atKey, map._values[atKey]); - } - - /** - * @dev Tries to return the value associated with `key`. O(1). - * Does not revert if `key` is not in the map. - */ - function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool exists, bytes32 value) { - bytes32 val = map._values[key]; - if (val == bytes32(0)) { - return (contains(map, key), bytes32(0)); - } else { - return (true, val); - } - } - - /** - * @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 Returns an array containing all the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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(); - } - - /** - * @dev Returns an array containing a slice of the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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, - uint256 start, - uint256 end - ) internal view returns (bytes32[] memory) { - return map._keys.values(start, end); - } - - // 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 Removes all the entries from a map. O(n). - * - * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that - * using it may render the function uncallable if the map grows to the point where clearing it consumes too much - * gas to fit in a block. - */ - function clear(UintToUintMap storage map) internal { - clear(map._inner); - } - - /** - * @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 key, uint256 value) { - (bytes32 atKey, bytes32 val) = at(map._inner, index); - return (uint256(atKey), uint256(val)); - } - - /** - * @dev Tries to return the value associated with `key`. O(1). - * Does not revert if `key` is not in the map. - */ - function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool exists, uint256 value) { - (bool success, bytes32 val) = tryGet(map._inner, bytes32(key)); - return (success, uint256(val)); - } - - /** - * @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 Returns an array containing all the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - /** - * @dev Returns an array containing a slice of the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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, uint256 start, uint256 end) internal view returns (uint256[] memory) { - bytes32[] memory store = keys(map._inner, start, end); - uint256[] memory result; - - assembly ("memory-safe") { - 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 Removes all the entries from a map. O(n). - * - * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that - * using it may render the function uncallable if the map grows to the point where clearing it consumes too much - * gas to fit in a block. - */ - function clear(UintToAddressMap storage map) internal { - clear(map._inner); - } - - /** - * @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 key, address value) { - (bytes32 atKey, bytes32 val) = at(map._inner, index); - return (uint256(atKey), address(uint160(uint256(val)))); - } - - /** - * @dev Tries to return the value associated with `key`. O(1). - * Does not revert if `key` is not in the map. - */ - function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool exists, address value) { - (bool success, bytes32 val) = tryGet(map._inner, bytes32(key)); - return (success, address(uint160(uint256(val)))); - } - - /** - * @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 Returns an array containing all the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - /** - * @dev Returns an array containing a slice of the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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, uint256 start, uint256 end) internal view returns (uint256[] memory) { - bytes32[] memory store = keys(map._inner, start, end); - uint256[] memory result; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - // UintToBytes32Map - - struct UintToBytes32Map { - 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(UintToBytes32Map storage map, uint256 key, bytes32 value) internal returns (bool) { - return set(map._inner, bytes32(key), 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(UintToBytes32Map storage map, uint256 key) internal returns (bool) { - return remove(map._inner, bytes32(key)); - } - - /** - * @dev Removes all the entries from a map. O(n). - * - * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that - * using it may render the function uncallable if the map grows to the point where clearing it consumes too much - * gas to fit in a block. - */ - function clear(UintToBytes32Map storage map) internal { - clear(map._inner); - } - - /** - * @dev Returns true if the key is in the map. O(1). - */ - function contains(UintToBytes32Map 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(UintToBytes32Map 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(UintToBytes32Map storage map, uint256 index) internal view returns (uint256 key, bytes32 value) { - (bytes32 atKey, bytes32 val) = at(map._inner, index); - return (uint256(atKey), val); - } - - /** - * @dev Tries to return the value associated with `key`. O(1). - * Does not revert if `key` is not in the map. - */ - function tryGet(UintToBytes32Map storage map, uint256 key) internal view returns (bool exists, bytes32 value) { - (bool success, bytes32 val) = tryGet(map._inner, bytes32(key)); - return (success, val); - } - - /** - * @dev Returns the value associated with `key`. O(1). - * - * Requirements: - * - * - `key` must be in the map. - */ - function get(UintToBytes32Map storage map, uint256 key) internal view returns (bytes32) { - return get(map._inner, bytes32(key)); - } - - /** - * @dev Returns an array containing all the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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(UintToBytes32Map storage map) internal view returns (uint256[] memory) { - bytes32[] memory store = keys(map._inner); - uint256[] memory result; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - /** - * @dev Returns an array containing a slice of the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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(UintToBytes32Map storage map, uint256 start, uint256 end) internal view returns (uint256[] memory) { - bytes32[] memory store = keys(map._inner, start, end); - uint256[] memory result; - - assembly ("memory-safe") { - 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 Removes all the entries from a map. O(n). - * - * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that - * using it may render the function uncallable if the map grows to the point where clearing it consumes too much - * gas to fit in a block. - */ - function clear(AddressToUintMap storage map) internal { - clear(map._inner); - } - - /** - * @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 key, uint256 value) { - (bytes32 atKey, bytes32 val) = at(map._inner, index); - return (address(uint160(uint256(atKey))), uint256(val)); - } - - /** - * @dev Tries to return the value associated with `key`. O(1). - * Does not revert if `key` is not in the map. - */ - function tryGet(AddressToUintMap storage map, address key) internal view returns (bool exists, uint256 value) { - (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key)))); - return (success, uint256(val)); - } - - /** - * @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 Returns an array containing all the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - /** - * @dev Returns an array containing a slice of the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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, uint256 start, uint256 end) internal view returns (address[] memory) { - bytes32[] memory store = keys(map._inner, start, end); - address[] memory result; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - // AddressToAddressMap - - struct AddressToAddressMap { - 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(AddressToAddressMap storage map, address key, address value) internal returns (bool) { - return set(map._inner, bytes32(uint256(uint160(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(AddressToAddressMap storage map, address key) internal returns (bool) { - return remove(map._inner, bytes32(uint256(uint160(key)))); - } - - /** - * @dev Removes all the entries from a map. O(n). - * - * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that - * using it may render the function uncallable if the map grows to the point where clearing it consumes too much - * gas to fit in a block. - */ - function clear(AddressToAddressMap storage map) internal { - clear(map._inner); - } - - /** - * @dev Returns true if the key is in the map. O(1). - */ - function contains(AddressToAddressMap 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(AddressToAddressMap 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(AddressToAddressMap storage map, uint256 index) internal view returns (address key, address value) { - (bytes32 atKey, bytes32 val) = at(map._inner, index); - return (address(uint160(uint256(atKey))), address(uint160(uint256(val)))); - } - - /** - * @dev Tries to return the value associated with `key`. O(1). - * Does not revert if `key` is not in the map. - */ - function tryGet(AddressToAddressMap storage map, address key) internal view returns (bool exists, address value) { - (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key)))); - return (success, address(uint160(uint256(val)))); - } - - /** - * @dev Returns the value associated with `key`. O(1). - * - * Requirements: - * - * - `key` must be in the map. - */ - function get(AddressToAddressMap storage map, address key) internal view returns (address) { - return address(uint160(uint256(get(map._inner, bytes32(uint256(uint160(key))))))); - } - - /** - * @dev Returns an array containing all the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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(AddressToAddressMap storage map) internal view returns (address[] memory) { - bytes32[] memory store = keys(map._inner); - address[] memory result; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - /** - * @dev Returns an array containing a slice of the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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( - AddressToAddressMap storage map, - uint256 start, - uint256 end - ) internal view returns (address[] memory) { - bytes32[] memory store = keys(map._inner, start, end); - address[] memory result; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - // AddressToBytes32Map - - struct AddressToBytes32Map { - 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(AddressToBytes32Map storage map, address key, bytes32 value) internal returns (bool) { - return set(map._inner, bytes32(uint256(uint160(key))), 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(AddressToBytes32Map storage map, address key) internal returns (bool) { - return remove(map._inner, bytes32(uint256(uint160(key)))); - } - - /** - * @dev Removes all the entries from a map. O(n). - * - * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that - * using it may render the function uncallable if the map grows to the point where clearing it consumes too much - * gas to fit in a block. - */ - function clear(AddressToBytes32Map storage map) internal { - clear(map._inner); - } - - /** - * @dev Returns true if the key is in the map. O(1). - */ - function contains(AddressToBytes32Map 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(AddressToBytes32Map 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(AddressToBytes32Map storage map, uint256 index) internal view returns (address key, bytes32 value) { - (bytes32 atKey, bytes32 val) = at(map._inner, index); - return (address(uint160(uint256(atKey))), val); - } - - /** - * @dev Tries to return the value associated with `key`. O(1). - * Does not revert if `key` is not in the map. - */ - function tryGet(AddressToBytes32Map storage map, address key) internal view returns (bool exists, bytes32 value) { - (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key)))); - return (success, val); - } - - /** - * @dev Returns the value associated with `key`. O(1). - * - * Requirements: - * - * - `key` must be in the map. - */ - function get(AddressToBytes32Map storage map, address key) internal view returns (bytes32) { - return get(map._inner, bytes32(uint256(uint160(key)))); - } - - /** - * @dev Returns an array containing all the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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(AddressToBytes32Map storage map) internal view returns (address[] memory) { - bytes32[] memory store = keys(map._inner); - address[] memory result; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - /** - * @dev Returns an array containing a slice of the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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( - AddressToBytes32Map storage map, - uint256 start, - uint256 end - ) internal view returns (address[] memory) { - bytes32[] memory store = keys(map._inner, start, end); - address[] memory result; - - assembly ("memory-safe") { - 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 Removes all the entries from a map. O(n). - * - * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that - * using it may render the function uncallable if the map grows to the point where clearing it consumes too much - * gas to fit in a block. - */ - function clear(Bytes32ToUintMap storage map) internal { - clear(map._inner); - } - - /** - * @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 key, uint256 value) { - (bytes32 atKey, bytes32 val) = at(map._inner, index); - return (atKey, uint256(val)); - } - - /** - * @dev Tries to return the value associated with `key`. O(1). - * Does not revert if `key` is not in the map. - */ - function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool exists, uint256 value) { - (bool success, bytes32 val) = tryGet(map._inner, key); - return (success, uint256(val)); - } - - /** - * @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 Returns an array containing all the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - /** - * @dev Returns an array containing a slice of the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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, uint256 start, uint256 end) internal view returns (bytes32[] memory) { - bytes32[] memory store = keys(map._inner, start, end); - bytes32[] memory result; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - // Bytes32ToAddressMap - - struct Bytes32ToAddressMap { - 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(Bytes32ToAddressMap storage map, bytes32 key, address value) internal returns (bool) { - return set(map._inner, 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(Bytes32ToAddressMap storage map, bytes32 key) internal returns (bool) { - return remove(map._inner, key); - } - - /** - * @dev Removes all the entries from a map. O(n). - * - * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that - * using it may render the function uncallable if the map grows to the point where clearing it consumes too much - * gas to fit in a block. - */ - function clear(Bytes32ToAddressMap storage map) internal { - clear(map._inner); - } - - /** - * @dev Returns true if the key is in the map. O(1). - */ - function contains(Bytes32ToAddressMap 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(Bytes32ToAddressMap 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(Bytes32ToAddressMap storage map, uint256 index) internal view returns (bytes32 key, address value) { - (bytes32 atKey, bytes32 val) = at(map._inner, index); - return (atKey, address(uint160(uint256(val)))); - } - - /** - * @dev Tries to return the value associated with `key`. O(1). - * Does not revert if `key` is not in the map. - */ - function tryGet(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (bool exists, address value) { - (bool success, bytes32 val) = tryGet(map._inner, key); - return (success, address(uint160(uint256(val)))); - } - - /** - * @dev Returns the value associated with `key`. O(1). - * - * Requirements: - * - * - `key` must be in the map. - */ - function get(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (address) { - return address(uint160(uint256(get(map._inner, key)))); - } - - /** - * @dev Returns an array containing all the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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(Bytes32ToAddressMap storage map) internal view returns (bytes32[] memory) { - bytes32[] memory store = keys(map._inner); - bytes32[] memory result; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - /** - * @dev Returns an array containing a slice of the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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( - Bytes32ToAddressMap storage map, - uint256 start, - uint256 end - ) internal view returns (bytes32[] memory) { - bytes32[] memory store = keys(map._inner, start, end); - bytes32[] memory result; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - /** - * @dev Query for a nonexistent map key. - */ - error EnumerableMapNonexistentBytesKey(bytes key); - - struct BytesToBytesMap { - // Storage of keys - EnumerableSet.BytesSet _keys; - mapping(bytes key => bytes) _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(BytesToBytesMap storage map, bytes memory key, bytes memory 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(BytesToBytesMap storage map, bytes memory key) internal returns (bool) { - delete map._values[key]; - return map._keys.remove(key); - } - - /** - * @dev Removes all the entries from a map. O(n). - * - * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the - * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block. - */ - function clear(BytesToBytesMap storage map) internal { - uint256 len = length(map); - for (uint256 i = 0; i < len; ++i) { - delete map._values[map._keys.at(i)]; - } - map._keys.clear(); - } - - /** - * @dev Returns true if the key is in the map. O(1). - */ - function contains(BytesToBytesMap storage map, bytes memory 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(BytesToBytesMap 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( - BytesToBytesMap storage map, - uint256 index - ) internal view returns (bytes memory key, bytes memory value) { - key = map._keys.at(index); - value = map._values[key]; - } - - /** - * @dev Tries to return the value associated with `key`. O(1). - * Does not revert if `key` is not in the map. - */ - function tryGet( - BytesToBytesMap storage map, - bytes memory key - ) internal view returns (bool exists, bytes memory value) { - value = map._values[key]; - exists = bytes(value).length != 0 || contains(map, key); - } - - /** - * @dev Returns the value associated with `key`. O(1). - * - * Requirements: - * - * - `key` must be in the map. - */ - function get(BytesToBytesMap storage map, bytes memory key) internal view returns (bytes memory value) { - bool exists; - (exists, value) = tryGet(map, key); - if (!exists) { - revert EnumerableMapNonexistentBytesKey(key); - } - } - - /** - * @dev Returns an array containing all the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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(BytesToBytesMap storage map) internal view returns (bytes[] memory) { - return map._keys.values(); - } - - /** - * @dev Returns an array containing a slice of the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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(BytesToBytesMap storage map, uint256 start, uint256 end) internal view returns (bytes[] memory) { - return map._keys.values(start, end); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol deleted file mode 100644 index fbf742a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol +++ /dev/null @@ -1,792 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (utils/structs/EnumerableSet.sol) -// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. - -pragma solidity ^0.8.20; - -import {Arrays} from "../Arrays.sol"; -import {Math} from "../math/Math.sol"; - -/** - * @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. - * - Set can be cleared (all elements removed) in O(n). - * - * ```solidity - * contract Example { - * // Add the library methods - * using EnumerableSet for EnumerableSet.AddressSet; - * - * // Declare a set state variable - * EnumerableSet.AddressSet private mySet; - * } - * ``` - * - * The following types are supported: - * - * - `bytes32` (`Bytes32Set`) since v3.3.0 - * - `address` (`AddressSet`) since v3.3.0 - * - `uint256` (`UintSet`) since v3.3.0 - * - `string` (`StringSet`) since v5.4.0 - * - `bytes` (`BytesSet`) since v5.4.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 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 Removes all the values from a set. O(n). - * - * WARNING: This function has an unbounded cost that scales with set size. Developers should keep in mind that - * using it may render the function uncallable if the set grows to the point where clearing it consumes too much - * gas to fit in a block. - */ - function _clear(Set storage set) private { - uint256 len = _length(set); - for (uint256 i = 0; i < len; ++i) { - delete set._positions[set._values[i]]; - } - Arrays.unsafeSetLength(set._values, 0); - } - - /** - * @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; - } - - /** - * @dev Return a slice of the 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, uint256 start, uint256 end) private view returns (bytes32[] memory) { - unchecked { - end = Math.min(end, _length(set)); - start = Math.min(start, end); - - uint256 len = end - start; - bytes32[] memory result = new bytes32[](len); - for (uint256 i = 0; i < len; ++i) { - result[i] = Arrays.unsafeAccess(set._values, start + i).value; - } - return result; - } - } - - // 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 Removes all the values from a set. O(n). - * - * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the - * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. - */ - function clear(Bytes32Set storage set) internal { - _clear(set._inner); - } - - /** - * @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; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - /** - * @dev Return a slice of the 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, uint256 start, uint256 end) internal view returns (bytes32[] memory) { - bytes32[] memory store = _values(set._inner, start, end); - bytes32[] memory result; - - assembly ("memory-safe") { - 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 Removes all the values from a set. O(n). - * - * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the - * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. - */ - function clear(AddressSet storage set) internal { - _clear(set._inner); - } - - /** - * @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; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - /** - * @dev Return a slice of the 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, uint256 start, uint256 end) internal view returns (address[] memory) { - bytes32[] memory store = _values(set._inner, start, end); - address[] memory result; - - assembly ("memory-safe") { - 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 Removes all the values from a set. O(n). - * - * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the - * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. - */ - function clear(UintSet storage set) internal { - _clear(set._inner); - } - - /** - * @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; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - /** - * @dev Return a slice of the 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, uint256 start, uint256 end) internal view returns (uint256[] memory) { - bytes32[] memory store = _values(set._inner, start, end); - uint256[] memory result; - - assembly ("memory-safe") { - result := store - } - - return result; - } - - struct StringSet { - // Storage of set values - string[] _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(string 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(StringSet storage set, string memory value) internal returns (bool) { - if (!contains(set, value)) { - set._values.push(value); - // The value is stored at length-1, but we add 1 to all indexes - // and use 0 as a sentinel value - 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(StringSet storage set, string memory value) internal returns (bool) { - // We cache the value's position to prevent multiple reads from the same storage slot - uint256 position = 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) { - string memory 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 Removes all the values from a set. O(n). - * - * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the - * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. - */ - function clear(StringSet storage set) internal { - uint256 len = length(set); - for (uint256 i = 0; i < len; ++i) { - delete set._positions[set._values[i]]; - } - Arrays.unsafeSetLength(set._values, 0); - } - - /** - * @dev Returns true if the value is in the set. O(1). - */ - function contains(StringSet storage set, string memory value) internal view returns (bool) { - return set._positions[value] != 0; - } - - /** - * @dev Returns the number of values on the set. O(1). - */ - function length(StringSet storage set) internal 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(StringSet storage set, uint256 index) internal view returns (string memory) { - 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(StringSet storage set) internal view returns (string[] memory) { - return set._values; - } - - /** - * @dev Return a slice of the 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(StringSet storage set, uint256 start, uint256 end) internal view returns (string[] memory) { - unchecked { - end = Math.min(end, length(set)); - start = Math.min(start, end); - - uint256 len = end - start; - string[] memory result = new string[](len); - for (uint256 i = 0; i < len; ++i) { - result[i] = Arrays.unsafeAccess(set._values, start + i).value; - } - return result; - } - } - - struct BytesSet { - // Storage of set values - bytes[] _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(bytes 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(BytesSet storage set, bytes memory value) internal returns (bool) { - if (!contains(set, value)) { - set._values.push(value); - // The value is stored at length-1, but we add 1 to all indexes - // and use 0 as a sentinel value - 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(BytesSet storage set, bytes memory value) internal returns (bool) { - // We cache the value's position to prevent multiple reads from the same storage slot - uint256 position = 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) { - bytes memory 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 Removes all the values from a set. O(n). - * - * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the - * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. - */ - function clear(BytesSet storage set) internal { - uint256 len = length(set); - for (uint256 i = 0; i < len; ++i) { - delete set._positions[set._values[i]]; - } - Arrays.unsafeSetLength(set._values, 0); - } - - /** - * @dev Returns true if the value is in the set. O(1). - */ - function contains(BytesSet storage set, bytes memory value) internal view returns (bool) { - return set._positions[value] != 0; - } - - /** - * @dev Returns the number of values on the set. O(1). - */ - function length(BytesSet storage set) internal 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(BytesSet storage set, uint256 index) internal view returns (bytes memory) { - 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(BytesSet storage set) internal view returns (bytes[] memory) { - return set._values; - } - - /** - * @dev Return a slice of the 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(BytesSet storage set, uint256 start, uint256 end) internal view returns (bytes[] memory) { - unchecked { - end = Math.min(end, length(set)); - start = Math.min(start, end); - - uint256 len = end - start; - bytes[] memory result = new bytes[](len); - for (uint256 i = 0; i < len; ++i) { - result[i] = Arrays.unsafeAccess(set._values, start + i).value; - } - return result; - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Heap.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Heap.sol deleted file mode 100644 index c97bb43..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/Heap.sol +++ /dev/null @@ -1,256 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/Heap.sol) - -pragma solidity ^0.8.20; - -import {Math} from "../math/Math.sol"; -import {SafeCast} from "../math/SafeCast.sol"; -import {Comparators} from "../Comparators.sol"; -import {Arrays} from "../Arrays.sol"; -import {Panic} from "../Panic.sol"; -import {StorageSlot} from "../StorageSlot.sol"; - -/** - * @dev Library for managing https://en.wikipedia.org/wiki/Binary_heap[binary heap] that can be used as - * https://en.wikipedia.org/wiki/Priority_queue[priority queue]. - * - * Heaps are represented as a tree of values where the first element (index 0) is the root, and where the node at - * index i is the child of the node at index (i-1)/2 and the parent of nodes at index 2*i+1 and 2*i+2. Each node - * stores an element of the heap. - * - * The structure is ordered so that each node is bigger than its parent. An immediate consequence is that the - * highest priority value is the one at the root. This value can be looked up in constant time (O(1)) at - * `heap.tree[0]` - * - * The structure is designed to perform the following operations with the corresponding complexities: - * - * * peek (get the highest priority value): O(1) - * * insert (insert a value): O(log(n)) - * * pop (remove the highest priority value): O(log(n)) - * * replace (replace the highest priority value with a new value): O(log(n)) - * * length (get the number of elements): O(1) - * * clear (remove all elements): O(1) - * - * IMPORTANT: This library allows for the use of custom comparator functions. Given that manipulating - * memory can lead to unexpected behavior. Consider verifying that the comparator does not manipulate - * the Heap's state directly and that it follows the Solidity memory safety rules. - * - * _Available since v5.1._ - */ -library Heap { - using Arrays for *; - using Math for *; - using SafeCast for *; - - /** - * @dev Binary heap that supports values of type uint256. - * - * Each element of that structure uses one storage slot. - */ - struct Uint256Heap { - uint256[] tree; - } - - /** - * @dev Lookup the root element of the heap. - */ - function peek(Uint256Heap storage self) internal view returns (uint256) { - // self.tree[0] will `ARRAY_ACCESS_OUT_OF_BOUNDS` panic if heap is empty. - return self.tree[0]; - } - - /** - * @dev Remove (and return) the root element for the heap using the default comparator. - * - * NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator - * during the lifecycle of a heap will result in undefined behavior. - */ - function pop(Uint256Heap storage self) internal returns (uint256) { - return pop(self, Comparators.lt); - } - - /** - * @dev Remove (and return) the root element for the heap using the provided comparator. - * - * NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator - * during the lifecycle of a heap will result in undefined behavior. - */ - function pop( - Uint256Heap storage self, - function(uint256, uint256) view returns (bool) comp - ) internal returns (uint256) { - unchecked { - uint256 size = length(self); - if (size == 0) Panic.panic(Panic.EMPTY_ARRAY_POP); - - // cache - uint256 rootValue = self.tree.unsafeAccess(0).value; - uint256 lastValue = self.tree.unsafeAccess(size - 1).value; - - // swap last leaf with root, shrink tree and re-heapify - self.tree.pop(); - self.tree.unsafeAccess(0).value = lastValue; - _siftDown(self, size - 1, 0, lastValue, comp); - - return rootValue; - } - } - - /** - * @dev Insert a new element in the heap using the default comparator. - * - * NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator - * during the lifecycle of a heap will result in undefined behavior. - */ - function insert(Uint256Heap storage self, uint256 value) internal { - insert(self, value, Comparators.lt); - } - - /** - * @dev Insert a new element in the heap using the provided comparator. - * - * NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator - * during the lifecycle of a heap will result in undefined behavior. - */ - function insert( - Uint256Heap storage self, - uint256 value, - function(uint256, uint256) view returns (bool) comp - ) internal { - uint256 size = length(self); - - // push new item and re-heapify - self.tree.push(value); - _siftUp(self, size, value, comp); - } - - /** - * @dev Return the root element for the heap, and replace it with a new value, using the default comparator. - * This is equivalent to using {pop} and {insert}, but requires only one rebalancing operation. - * - * NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator - * during the lifecycle of a heap will result in undefined behavior. - */ - function replace(Uint256Heap storage self, uint256 newValue) internal returns (uint256) { - return replace(self, newValue, Comparators.lt); - } - - /** - * @dev Return the root element for the heap, and replace it with a new value, using the provided comparator. - * This is equivalent to using {pop} and {insert}, but requires only one rebalancing operation. - * - * NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator - * during the lifecycle of a heap will result in undefined behavior. - */ - function replace( - Uint256Heap storage self, - uint256 newValue, - function(uint256, uint256) view returns (bool) comp - ) internal returns (uint256) { - uint256 size = length(self); - if (size == 0) Panic.panic(Panic.EMPTY_ARRAY_POP); - - // cache - uint256 oldValue = self.tree.unsafeAccess(0).value; - - // replace and re-heapify - self.tree.unsafeAccess(0).value = newValue; - _siftDown(self, size, 0, newValue, comp); - - return oldValue; - } - - /** - * @dev Returns the number of elements in the heap. - */ - function length(Uint256Heap storage self) internal view returns (uint256) { - return self.tree.length; - } - - /** - * @dev Removes all elements in the heap. - */ - function clear(Uint256Heap storage self) internal { - self.tree.unsafeSetLength(0); - } - - /** - * @dev Swap node `i` and `j` in the tree. - */ - function _swap(Uint256Heap storage self, uint256 i, uint256 j) private { - StorageSlot.Uint256Slot storage ni = self.tree.unsafeAccess(i); - StorageSlot.Uint256Slot storage nj = self.tree.unsafeAccess(j); - (ni.value, nj.value) = (nj.value, ni.value); - } - - /** - * @dev Perform heap maintenance on `self`, starting at `index` (with the `value`), using `comp` as a - * comparator, and moving toward the leaves of the underlying tree. - * - * NOTE: This is a private function that is called in a trusted context with already cached parameters. `size` - * and `value` could be extracted from `self` and `index`, but that would require redundant storage read. These - * parameters are not verified. It is the caller role to make sure the parameters are correct. - */ - function _siftDown( - Uint256Heap storage self, - uint256 size, - uint256 index, - uint256 value, - function(uint256, uint256) view returns (bool) comp - ) private { - unchecked { - // Check if there is a risk of overflow when computing the indices of the child nodes. If that is the case, - // there cannot be child nodes in the tree, so sifting is done. - if (index >= type(uint256).max / 2) return; - - // Compute the indices of the potential child nodes - uint256 lIndex = 2 * index + 1; - uint256 rIndex = 2 * index + 2; - - // Three cases: - // 1. Both children exist: sifting may continue on one of the branch (selection required) - // 2. Only left child exist: sifting may continue on the left branch (no selection required) - // 3. Neither child exist: sifting is done - if (rIndex < size) { - uint256 lValue = self.tree.unsafeAccess(lIndex).value; - uint256 rValue = self.tree.unsafeAccess(rIndex).value; - if (comp(lValue, value) || comp(rValue, value)) { - uint256 cIndex = comp(lValue, rValue).ternary(lIndex, rIndex); - _swap(self, index, cIndex); - _siftDown(self, size, cIndex, value, comp); - } - } else if (lIndex < size) { - uint256 lValue = self.tree.unsafeAccess(lIndex).value; - if (comp(lValue, value)) { - _swap(self, index, lIndex); - _siftDown(self, size, lIndex, value, comp); - } - } - } - } - - /** - * @dev Perform heap maintenance on `self`, starting at `index` (with the `value`), using `comp` as a - * comparator, and moving toward the root of the underlying tree. - * - * NOTE: This is a private function that is called in a trusted context with already cached parameters. `value` - * could be extracted from `self` and `index`, but that would require redundant storage read. These parameters are not - * verified. It is the caller role to make sure the parameters are correct. - */ - function _siftUp( - Uint256Heap storage self, - uint256 index, - uint256 value, - function(uint256, uint256) view returns (bool) comp - ) private { - unchecked { - while (index > 0) { - uint256 parentIndex = (index - 1) / 2; - uint256 parentValue = self.tree.unsafeAccess(parentIndex).value; - if (comp(parentValue, value)) break; - _swap(self, index, parentIndex); - index = parentIndex; - } - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/MerkleTree.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/MerkleTree.sol deleted file mode 100644 index 010ccfe..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/structs/MerkleTree.sol +++ /dev/null @@ -1,267 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/MerkleTree.sol) - -pragma solidity ^0.8.20; - -import {Hashes} from "../cryptography/Hashes.sol"; -import {Arrays} from "../Arrays.sol"; -import {Panic} from "../Panic.sol"; -import {StorageSlot} from "../StorageSlot.sol"; - -/** - * @dev Library for managing https://wikipedia.org/wiki/Merkle_Tree[Merkle Tree] data structures. - * - * Each tree is a complete binary tree with the ability to sequentially insert leaves, changing them from a zero to a - * non-zero value and updating its root. This structure allows inserting commitments (or other entries) that are not - * stored, but can be proven to be part of the tree at a later time if the root is kept. See {MerkleProof}. - * - * A tree is defined by the following parameters: - * - * * Depth: The number of levels in the tree, it also defines the maximum number of leaves as 2**depth. - * * Zero value: The value that represents an empty leaf. Used to avoid regular zero values to be part of the tree. - * * Hashing function: A cryptographic hash function used to produce internal nodes. Defaults to {Hashes-commutativeKeccak256}. - * - * NOTE: Building trees using non-commutative hashing functions (i.e. `H(a, b) != H(b, a)`) is supported. However, - * proving the inclusion of a leaf in such trees is not possible with the {MerkleProof} library since it only supports - * _commutative_ hashing functions. - * - * _Available since v5.1._ - */ -library MerkleTree { - /// @dev Error emitted when trying to update a leaf that was not previously pushed. - error MerkleTreeUpdateInvalidIndex(uint256 index, uint256 length); - - /// @dev Error emitted when the proof used during an update is invalid (could not reproduce the side). - error MerkleTreeUpdateInvalidProof(); - - /** - * @dev A complete `bytes32` Merkle tree. - * - * The `sides` and `zero` arrays are set to have a length equal to the depth of the tree during setup. - * - * 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. - * - * NOTE: The `root` and the updates history is not stored within the tree. Consider using a secondary structure to - * store a list of historical roots from the values returned from {setup} and {push} (e.g. a mapping, {BitMaps} or - * {Checkpoints}). - * - * WARNING: Updating any of the tree's parameters after the first insertion will result in a corrupted tree. - */ - struct Bytes32PushTree { - uint256 _nextLeafIndex; - bytes32[] _sides; - bytes32[] _zeros; - } - - /** - * @dev Initialize a {Bytes32PushTree} using {Hashes-commutativeKeccak256} to hash internal nodes. - * The capacity of the tree (i.e. number of leaves) is set to `2**treeDepth`. - * - * Calling this function on MerkleTree that was already setup and used will reset it to a blank state. - * - * Once a tree is setup, any push to it must use the same hashing function. This means that values - * should be pushed to it using the default {xref-MerkleTree-push-struct-MerkleTree-Bytes32PushTree-bytes32-}[push] function. - * - * IMPORTANT: The zero value should be carefully chosen since it will be stored in the tree representing - * empty leaves. It should be a value that is not expected to be part of the tree. - */ - function setup(Bytes32PushTree storage self, uint8 treeDepth, bytes32 zero) internal returns (bytes32 initialRoot) { - return setup(self, treeDepth, zero, Hashes.commutativeKeccak256); - } - - /** - * @dev Same as {xref-MerkleTree-setup-struct-MerkleTree-Bytes32PushTree-uint8-bytes32-}[setup], but allows to specify a custom hashing function. - * - * Once a tree is setup, any push to it must use the same hashing function. This means that values - * should be pushed to it using the custom push function, which should be the same one as used during the setup. - * - * IMPORTANT: Providing a custom hashing function is a security-sensitive operation since it may - * compromise the soundness of the tree. - * - * NOTE: Consider verifying that the hashing function does not manipulate the memory state directly and that it - * follows the Solidity memory safety rules. Otherwise, it may lead to unexpected behavior. - */ - function setup( - Bytes32PushTree storage self, - uint8 treeDepth, - bytes32 zero, - function(bytes32, bytes32) view returns (bytes32) fnHash - ) internal returns (bytes32 initialRoot) { - // Store depth in the dynamic array - Arrays.unsafeSetLength(self._sides, treeDepth); - Arrays.unsafeSetLength(self._zeros, treeDepth); - - // Build each root of zero-filled subtrees - bytes32 currentZero = zero; - for (uint256 i = 0; i < treeDepth; ++i) { - Arrays.unsafeAccess(self._zeros, i).value = currentZero; - currentZero = fnHash(currentZero, currentZero); - } - - // Set the first root - self._nextLeafIndex = 0; - - return currentZero; - } - - /** - * @dev Insert a new leaf in the tree, and compute the new root. Returns the position of the inserted leaf in the - * tree, and the resulting root. - * - * Hashing the leaf before calling this function is recommended as a protection against - * second pre-image attacks. - * - * This variant uses {Hashes-commutativeKeccak256} to hash internal nodes. It should only be used on merkle trees - * that were setup using the same (default) hashing function (i.e. by calling - * {xref-MerkleTree-setup-struct-MerkleTree-Bytes32PushTree-uint8-bytes32-}[the default setup] function). - */ - function push(Bytes32PushTree storage self, bytes32 leaf) internal returns (uint256 index, bytes32 newRoot) { - return push(self, leaf, Hashes.commutativeKeccak256); - } - - /** - * @dev Insert a new leaf in the tree, and compute the new root. Returns the position of the inserted leaf in the - * tree, and the resulting root. - * - * Hashing the leaf before calling this function is recommended as a protection against - * second pre-image attacks. - * - * This variant uses a custom hashing function to hash internal nodes. It should only be called with the same - * function as the one used during the initial setup of the merkle tree. - */ - function push( - Bytes32PushTree storage self, - bytes32 leaf, - function(bytes32, bytes32) view returns (bytes32) fnHash - ) internal returns (uint256 index, bytes32 newRoot) { - // Cache read - uint256 treeDepth = depth(self); - - // Get leaf index - index = self._nextLeafIndex++; - - // Check if tree is full. - if (index >= 1 << treeDepth) { - Panic.panic(Panic.RESOURCE_ERROR); - } - - // Rebuild branch from leaf to root - uint256 currentIndex = index; - bytes32 currentLevelHash = leaf; - for (uint256 i = 0; i < treeDepth; i++) { - // Reaching the parent node, is currentLevelHash the left child? - bool isLeft = currentIndex % 2 == 0; - - // If so, next time we will come from the right, so we need to save it - if (isLeft) { - Arrays.unsafeAccess(self._sides, i).value = currentLevelHash; - } - - // Compute the current node hash by using the hash function - // with either its sibling (side) or the zero value for that level. - currentLevelHash = fnHash( - isLeft ? currentLevelHash : Arrays.unsafeAccess(self._sides, i).value, - isLeft ? Arrays.unsafeAccess(self._zeros, i).value : currentLevelHash - ); - - // Update node index - currentIndex >>= 1; - } - - return (index, currentLevelHash); - } - - /** - * @dev Change the value of the leaf at position `index` from `oldValue` to `newValue`. Returns the recomputed "old" - * root (before the update) and "new" root (after the update). The caller must verify that the reconstructed old - * root is the last known one. - * - * The `proof` must be an up-to-date inclusion proof for the leaf being updated. This means that this function is - * vulnerable to front-running. Any {push} or {update} operation (that changes the root of the tree) would render - * all "in flight" updates invalid. - * - * This variant uses {Hashes-commutativeKeccak256} to hash internal nodes. It should only be used on merkle trees - * that were setup using the same (default) hashing function (i.e. by calling - * {xref-MerkleTree-setup-struct-MerkleTree-Bytes32PushTree-uint8-bytes32-}[the default setup] function). - */ - function update( - Bytes32PushTree storage self, - uint256 index, - bytes32 oldValue, - bytes32 newValue, - bytes32[] memory proof - ) internal returns (bytes32 oldRoot, bytes32 newRoot) { - return update(self, index, oldValue, newValue, proof, Hashes.commutativeKeccak256); - } - - /** - * @dev Change the value of the leaf at position `index` from `oldValue` to `newValue`. Returns the recomputed "old" - * root (before the update) and "new" root (after the update). The caller must verify that the reconstructed old - * root is the last known one. - * - * The `proof` must be an up-to-date inclusion proof for the leaf being update. This means that this function is - * vulnerable to front-running. Any {push} or {update} operation (that changes the root of the tree) would render - * all "in flight" updates invalid. - * - * This variant uses a custom hashing function to hash internal nodes. It should only be called with the same - * function as the one used during the initial setup of the merkle tree. - */ - function update( - Bytes32PushTree storage self, - uint256 index, - bytes32 oldValue, - bytes32 newValue, - bytes32[] memory proof, - function(bytes32, bytes32) view returns (bytes32) fnHash - ) internal returns (bytes32 oldRoot, bytes32 newRoot) { - unchecked { - // Check index range - uint256 length = self._nextLeafIndex; - if (index >= length) revert MerkleTreeUpdateInvalidIndex(index, length); - - // Cache read - uint256 treeDepth = depth(self); - - // Workaround stack too deep - bytes32[] storage sides = self._sides; - - // This cannot overflow because: 0 <= index < length - uint256 lastIndex = length - 1; - uint256 currentIndex = index; - bytes32 currentLevelHashOld = oldValue; - bytes32 currentLevelHashNew = newValue; - for (uint32 i = 0; i < treeDepth; i++) { - bool isLeft = currentIndex % 2 == 0; - - lastIndex >>= 1; - currentIndex >>= 1; - - if (isLeft && currentIndex == lastIndex) { - StorageSlot.Bytes32Slot storage side = Arrays.unsafeAccess(sides, i); - if (side.value != currentLevelHashOld) revert MerkleTreeUpdateInvalidProof(); - side.value = currentLevelHashNew; - } - - bytes32 sibling = proof[i]; - currentLevelHashOld = fnHash( - isLeft ? currentLevelHashOld : sibling, - isLeft ? sibling : currentLevelHashOld - ); - currentLevelHashNew = fnHash( - isLeft ? currentLevelHashNew : sibling, - isLeft ? sibling : currentLevelHashNew - ); - } - return (currentLevelHashOld, currentLevelHashNew); - } - } - - /** - * @dev Tree's depth (set at initialization) - */ - function depth(Bytes32PushTree storage self) internal view returns (uint256) { - return self._zeros.length; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/types/Time.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/types/Time.sol deleted file mode 100644 index a495932..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/utils/types/Time.sol +++ /dev/null @@ -1,133 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.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 valueBefore, uint32 valueAfter, uint48 effect) { - (valueBefore, valueAfter, 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 valueBefore, uint32 valueAfter, uint48 effect) { - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol deleted file mode 100644 index 84cd62e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.4.0) (vendor/compound/ICompoundTimelock.sol) - -pragma solidity >=0.6.9; - -/** - * 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/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE b/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE deleted file mode 100644 index 7da2324..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE +++ /dev/null @@ -1,11 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/README.md deleted file mode 100644 index ca39e51..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/README.md +++ /dev/null @@ -1,16 +0,0 @@ -Documentation is hosted at https://docs.openzeppelin.com/contracts. - -All of the content for the site is in this repository. The guides are in the -[docs](/docs) directory, and the API Reference is extracted from comments in -the source code. If you want to help improve the content, this is the -repository you should be contributing to. - -[`solidity-docgen`](https://github.com/OpenZeppelin/solidity-docgen) is the -program that extracts the API Reference from source code. - -The [`docs.openzeppelin.com`](https://github.com/OpenZeppelin/docs.openzeppelin.com) -repository hosts the configuration for the entire site, which includes -documentation for all of the OpenZeppelin projects. - -To run the docs locally you should run `npm run docs:watch` on this -repository. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/antora.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/antora.yml deleted file mode 100644 index 4bc06b3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/antora.yml +++ /dev/null @@ -1,7 +0,0 @@ -name: contracts -title: Contracts -version: 5.x -prerelease: false -nav: - - modules/ROOT/nav.adoc - - modules/api/nav.adoc diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/config.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/config.js deleted file mode 100644 index f0af663..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/config.js +++ /dev/null @@ -1,21 +0,0 @@ -const path = require('path'); -const fs = require('fs'); - -/** @type import('solidity-docgen/dist/config').UserConfig */ -module.exports = { - outputDir: 'docs/modules/api/pages', - templates: 'docs/templates', - exclude: ['mocks'], - pageExtension: '.adoc', - pages: (_, file, config) => { - // For each contract file, find the closest README.adoc and return its location as the output page path. - const sourcesDir = path.resolve(config.root, config.sourcesDir); - let dir = path.resolve(config.root, file.absolutePath); - while (dir.startsWith(sourcesDir)) { - dir = path.dirname(dir); - if (fs.existsSync(path.join(dir, 'README.adoc'))) { - return path.relative(sourcesDir, dir) + config.pageExtension; - } - } - }, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-control-multiple.svg b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-control-multiple.svg deleted file mode 100644 index 0314e09..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-control-multiple.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager-functions.svg b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager-functions.svg deleted file mode 100644 index dbbf041..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager-functions.svg +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager.svg b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager.svg deleted file mode 100644 index 12f91ba..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/access-manager.svg +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack-3a.png b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack-3a.png deleted file mode 100644 index 4cb52237d635f634085d87337322ac5e0741ff01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60433 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¨> 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 W72fFO~av*&4wv-#`&9xxJ7DPz*Q3{XF6KYttW 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 ZvU7})GO|xKx>5WWyCiin@%)Vk{~s{kR%ZYJ diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack-6.png b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack-6.png deleted file mode 100644 index 1587fb5c1360e59243297ebca9f097ed116dcdc4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56290 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 O?BA=lCt1P7>wf@z+Op{Y diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack.png b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-attack.png deleted file mode 100644 index dc059b228bf86b49a55f9afac01baf1188b51904..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58886 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

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

      XRhnQ}H08>D;q7lu(1A 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 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-rate-loglogext.png b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/erc4626-rate-loglogext.png deleted file mode 100644 index 127bc7f2fddc37bcfd0863238db2c7874f4e210f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 109923 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�S;#YCJ>3E4Gp0$=R%K*`_zT?& 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 NxuSVFSK-!^{{fq-$;AKw diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/tally-exec.png b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/tally-exec.png deleted file mode 100644 index e24a145d09abc70ab36c6f036bce726e8410534a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 231859 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


      >t>*+2Sz_Kd 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∈YQ8Q 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 VZVAzj{5LR4@tvC7A6e6o{|B=b*sA~l diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/tally-vote.png b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/images/tally-vote.png deleted file mode 100644 index 7d270fce091298627d9c181c315415c7710de784..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40507 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 dynamically, it is not always possible to determine which accounts hold a particular role. This is important as it allows proving certain properties about a system, such as that an administrative account is a multisig or a DAO, or that a certain role has been removed from all users, effectively disabling any associated functionality. - -Under the hood, `AccessControl` uses `EnumerableSet`, a more powerful variant of Solidity's `mapping` type, which allows for key enumeration. `getRoleMemberCount` can be used to retrieve the number of accounts that have a particular role, and `getRoleMember` can then be called to get the address of each of these accounts. - -```javascript -const minterCount = await myToken.getRoleMemberCount(MINTER_ROLE); - -const members = []; -for (let i = 0; i < minterCount; ++i) { - members.push(await myToken.getRoleMember(MINTER_ROLE, i)); -} -``` - -== Delayed operation - -Access control is essential to prevent unauthorized access to critical functions. These functions may be used to mint tokens, freeze transfers or perform an upgrade that completely changes the smart contract logic. While xref:api:access.adoc#Ownable[`Ownable`] and xref:api:access.adoc#AccessControl[`AccessControl`] can prevent unauthorized access, they do not address the issue of a misbehaving administrator attacking their own system to the prejudice of their users. - -This is the issue the xref:api:governance.adoc#TimelockController[`TimelockController`] is addressing. - -The xref:api:governance.adoc#TimelockController[`TimelockController`] is a proxy that is governed by proposers and executors. When set as the owner/admin/controller of a smart contract, it ensures that whichever maintenance operation is ordered by the proposers is subject to a delay. This delay protects the users of the smart contract by giving them time to review the maintenance operation and exit the system if they consider it is in their best interest to do so. - -=== Using `TimelockController` - -By default, the address that deployed the xref:api:governance.adoc#TimelockController[`TimelockController`] gets administration privileges over the timelock. This role grants the right to assign proposers, executors, and other administrators. - -The first step in configuring the xref:api:governance.adoc#TimelockController[`TimelockController`] is to assign at least one proposer and one executor. These can be assigned during construction or later by anyone with the administrator role. These roles are not exclusive, meaning an account can have both roles. - -Roles are managed using the xref:api:access.adoc#AccessControl[`AccessControl`] interface and the `bytes32` values for each role are accessible through the `ADMIN_ROLE`, `PROPOSER_ROLE` and `EXECUTOR_ROLE` constants. - -There is an additional feature built on top of `AccessControl`: giving the executor role to `address(0)` opens access to anyone to execute a proposal once the timelock has expired. This feature, while useful, should be used with caution. - -At this point, with both a proposer and an executor assigned, the timelock can perform operations. - -An optional next step is for the deployer to renounce its administrative privileges and leave the timelock self-administered. If the deployer decides to do so, all further maintenance, including assigning new proposers/schedulers or changing the timelock duration will have to follow the timelock workflow. This links the governance of the timelock to the governance of contracts attached to the timelock, and enforce a delay on timelock maintenance operations. - -WARNING: If the deployer renounces administrative rights in favour of timelock itself, assigning new proposers or executors will require a timelocked operation. This means that if the accounts in charge of any of these two roles become unavailable, then the entire contract (and any contract it controls) becomes locked indefinitely. - -With both the proposer and executor roles assigned and the timelock in charge of its own administration, you can now transfer the ownership/control of any contract to the timelock. - -TIP: A recommended configuration is to grant both roles to a secure governance contract such as a DAO or a multisig, and to additionally grant the executor role to a few EOAs held by people in charge of helping with the maintenance operations. These wallets cannot take over control of the timelock but they can help smoothen the workflow. - -=== Minimum delay - -Operations executed by the xref:api:governance.adoc#TimelockController[`TimelockController`] are not subject to a fixed delay but rather a minimum delay. Some major updates might call for a longer delay. For example, if a delay of just a few days might be sufficient for users to audit a minting operation, it makes sense to use a delay of a few weeks, or even a few months, when scheduling a smart contract upgrade. - -The minimum delay (accessible through the xref:api:governance.adoc#TimelockController-getMinDelay--[`getMinDelay`] method) can be updated by calling the xref:api:governance.adoc#TimelockController-updateDelay-uint256-[`updateDelay`] function. Bear in mind that access to this function is only accessible by the timelock itself, meaning this maintenance operation has to go through the timelock itself. - -[[access-management]] -== Access Management - -For a system of contracts, better integrated role management can be achieved with an xref:api:access.adoc#AccessManager[`AccessManager`] instance. Instead of managing each contract's permission separately, AccessManager stores all the permissions in a single contract, making your protocol easier to audit and maintain. - -Although xref:api:access.adoc#AccessControl[`AccessControl`] offers a more dynamic solution for adding permissions to your contracts than Ownable, decentralized protocols tend to become more complex after integrating new contract instances and requires you to keep track of permissions separately in each contract. This increases the complexity of permissions management and monitoring across the system. - -image::access-control-multiple.svg[Access Control multiple] - -Protocols managing permissions in production systems often require more integrated alternatives to fragmented permissions through multiple `AccessControl` instances. - -image::access-manager.svg[AccessManager] - -The AccessManager is designed around the concept of role and target functions: - -* Roles are granted to accounts (addresses) following a many-to-many approach for flexibility. This means that each user can have one or multiple roles and multiple users can have the same role. -* Access to a restricted target function is limited to one role. A target function is defined by one https://docs.soliditylang.org/en/v0.8.20/abi-spec.html#function-selector[function selector] on one contract (called target). - -For a call to be authorized, the caller must bear the role that is assigned to the current target function (contract address + function selector). - -image::access-manager-functions.svg[AccessManager functions] - -=== Using `AccessManager` - -OpenZeppelin Contracts provides xref:api:access.adoc#AccessManager[`AccessManager`] for managing roles across any number of contracts. The `AccessManager` itself is a contract that can be deployed and used out of the box. It sets an initial admin in the constructor who will be allowed to perform management operations. - -In order to restrict access to some functions of your contract, you should inherit from the xref:api:access.adoc#AccessManaged[`AccessManaged`] contract provided along with the manager. This provides the `restricted` modifier that can be used to protect any externally facing function. Note that you will have to specify the address of the AccessManager instance (xref:api:access.adoc#AccessManaged-constructor-address-[`initialAuthority`]) in the constructor so the `restricted` modifier knows which manager to use for checking permissions. - -Here's a simple example of an xref:tokens.adoc#ERC20[ERC-20 token] that defines a `mint` function that is restricted by an xref:api:access.adoc#AccessManager[`AccessManager`]: - -```solidity -include::api:example$access-control/AccessManagedERC20MintBase.sol[] -``` - -NOTE: Make sure you fully understand how xref:api:access.adoc#AccessManager[`AccessManager`] works before using it or copy-pasting the examples from this guide. - -Once the managed contract has been deployed, it is now under the manager's control. The initial admin can then assign the minter role to an address and also allow the role to call the `mint` function. For example, this is demonstrated in the following Javascript code using Ethers.js: - -```javascript -// const target = ...; -// const user = ...; -const MINTER = 42n; // Roles are uint64 (0 is reserved for the ADMIN_ROLE) - -// Grant the minter role with no execution delay -await manager.grantRole(MINTER, user, 0); - -// Allow the minter role to call the function selector -// corresponding to the mint function -await manager.setTargetFunctionRole( - target, - ['0x40c10f19'], // bytes4(keccak256('mint(address,uint256)')) - MINTER -); -``` - -Even though each role has its own list of function permissions, each role member (`address`) has an execution delay that will dictate how long the account should wait to execute a function that requires its role. Delayed operations must have the xref:api:access.adoc#AccessManager-schedule-address-bytes-uint48-[`schedule`] function called on them first in the AccessManager before they can be executed, either by calling to the target function or using the AccessManager's xref:api:access.adoc#AccessManager-execute-address-bytes-[`execute`] function. - -Additionally, roles can have a granting delay that prevents adding members immediately. The AccessManager admins can set this grant delay as follows: - -```javascript -const HOUR = 60 * 60; - -const GRANT_DELAY = 24 * HOUR; -const EXECUTION_DELAY = 5 * HOUR; -const ACCOUNT = "0x..."; - -await manager.connect(initialAdmin).setGrantDelay(MINTER, GRANT_DELAY); - -// The role will go into effect after the GRANT_DELAY passes -await manager.connect(initialAdmin).grantRole(MINTER, ACCOUNT, EXECUTION_DELAY); -``` - -Note that roles do not define a name. As opposed to the xref:api:access.adoc#AccessControl[`AccessControl`] case, roles are identified as numeric values instead of being hardcoded in the contract as `bytes32` values. It is still possible to allow for tooling discovery (e.g. for role exploration) using role labeling with the xref:api:access.adoc#AccessManager-labelRole-uint64-string-[`labelRole`] function. - -```javascript -await manager.labelRole(MINTER, "MINTER"); -``` - -Given the admins of the `AccessManaged` can modify all of its permissions, it's recommended to keep only a single admin address secured under a multisig or governance layer. To achieve this, it is possible for the initial admin to set up all the required permissions, targets, and functions, assign a new admin, and finally renounce its admin role. - -For improved incident response coordination, the manager includes a mode where administrators can completely close a target contract. When closed, all calls to restricted target functions in a target contract will revert. - -Closing and opening contracts don't alter any of their settings, neither permissions nor delays. Particularly, the roles required for calling specific target functions are not modified. - -This mode is useful for incident response operations that require temporarily shutting down a contract in order to evaluate emergencies and reconfigure permissions. - -```javascript -const target = await myToken.getAddress(); - -// Token's `restricted` functions closed -await manager.setTargetClosed(target, true); - -// Token's `restricted` functions open -await manager.setTargetClosed(target, false); -``` - -WARNING: Even if an `AccessManager` defines permissions for a target function, these won't be applied if the managed contract instance is not using the xref:api:access.adoc#AccessManaged-restricted--[`restricted`] modifier for that function, or if its manager is a different one. - -=== Role Admins and Guardians - -An important aspect of the AccessControl contract is that roles aren't granted nor revoked by role members. Instead, it relies on the concept of a role admin for granting and revoking. - -In the case of the `AccessManager`, the same rule applies and only the role's admins are able to call xref:api:access.adoc#AccessManager-grantRole-uint64-address-uint32-[grant] and xref:api:access.adoc#AccessManager-revokeRole-uint64-address-[revoke] functions. Note that calling these functions will be subject to the execution delay that the executing role admin has. - -Additionally, the `AccessManager` stores a _guardian_ as an extra protection for each role. This guardian has the ability to cancel operations that have been scheduled by any role member with an execution delay. Consider that a role will have its initial admin and guardian default to the `ADMIN_ROLE` (`0`). - -IMPORTANT: Be careful with the members of `ADMIN_ROLE`, since it acts as the default admin and guardian for every role. A misbehaved guardian can cancel operations at will, affecting the AccessManager's operation. - -=== Manager configuration - -The `AccessManager` provides a built-in interface for configuring permission settings that can be accessed by its `ADMIN_ROLE` members. - -This configuration interface includes the following functions: - -* Add a label to a role using the xref:api:access.adoc#AccessManager-labelRole-uint64-string-[`labelRole`] function. -* Assign the admin and guardian of a role with xref:api:access.adoc#AccessManager-setRoleAdmin-uint64-uint64-[`setRoleAdmin`] and xref:api:access.adoc#AccessManager-setRoleGuardian-uint64-uint64-[`setRoleGuardian`]. -* Set each role's grant delay via xref:api:access.adoc#AccessManager-setGrantDelay-uint64-uint32-[`setGrantDelay`]. - -As an admin, some actions will require a delay. Similar to each member's execution delay, some admin operations require waiting for execution and should follow the xref:api:access.adoc#AccessManager-schedule-address-bytes-uint48-[`schedule`] and xref:api:access.adoc#AccessManager-execute-address-bytes-[`execute`] workflow. - -More specifically, these delayed functions are those for configuring the settings of a specific target contract. The delay applied to these functions can be adjusted by the manager admins with xref:api:access.adoc#AccessManager-setTargetAdminDelay-address-uint32-[`setTargetAdminDelay`]. - -The delayed admin actions are: - -* Updating an `AccessManaged` contract xref:api:access.adoc#AccessManaged-authority--[authority] using xref:api:access.adoc#AccessManager-updateAuthority-address-address-[`updateAuthority`]. -* Closing or opening a target via xref:api:access.adoc#AccessManager-setTargetClosed-address-bool-[`setTargetClosed`]. -* Changing permissions of whether a role can call a target function with xref:api:access.adoc#AccessManager-setTargetFunctionRole-address-bytes4---uint64-[`setTargetFunctionRole`]. - -=== Using with Ownable - -Contracts already inheriting from xref:api:access.adoc#Ownable[`Ownable`] can migrate to AccessManager by transferring ownership to the manager. After that, all calls to functions with the `onlyOwner` modifier should be called through the manager's xref:api:access.adoc#AccessManager-execute-address-bytes-[`execute`] function, even if the caller doesn't require a delay. - -```javascript -await ownable.connect(owner).transferOwnership(accessManager); -``` - -=== Using with AccessControl - -For systems already using xref:api:access.adoc#AccessControl[`AccessControl`], the `DEFAULT_ADMIN_ROLE` can be granted to the `AccessManager` after revoking every other role. Subsequent calls should be made through the manager's xref:api:access.adoc#AccessManager-execute-address-bytes-[`execute`] method, similar to the Ownable case. - -```javascript -// Revoke old roles -await accessControl.connect(admin).revokeRole(MINTER_ROLE, account); - -// Grant the admin role to the access manager -await accessControl.connect(admin).grantRole(DEFAULT_ADMIN_ROLE, accessManager); - -await accessControl.connect(admin).renounceRole(DEFAULT_ADMIN_ROLE, admin); -``` diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/account-abstraction.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/account-abstraction.adoc deleted file mode 100644 index 82fc65e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/account-abstraction.adoc +++ /dev/null @@ -1,100 +0,0 @@ -= Account Abstraction - -Unlike Externally Owned Accounts (EOAs), smart contracts may contain arbitrary verification logic based on authentication mechanisms different to Ethereum's native xref:api:utils.adoc#ECDSA[ECDSA] and have execution advantages such as batching or gas sponsorship. To leverage these properties of smart contracts, the community has widely adopted https://eips.ethereum.org/EIPS/eip-4337[ERC-4337], a standard to process user operations through an alternative mempool. - -The library provides multiple contracts for Account Abstraction following this standard as it enables more flexible and user-friendly interactions with applications. Account Abstraction use cases include wallets in novel contexts (e.g. embedded wallets), more granular configuration of accounts, and recovery mechanisms. - -== ERC-4337 Overview - -The ERC-4337 is a detailed specification of how to implement the necessary logic to handle operations without making changes to the protocol level (i.e. the rules of the blockchain itself). This specification defines the following components: - -=== UserOperation - -A `UserOperation` is a higher-layer pseudo-transaction object that represents the intent of the account. This shares some similarities with regular EVM transactions like the concept of `gasFees` or `callData` but includes fields that enable new capabilities. - -```solidity -struct PackedUserOperation { - address sender; - uint256 nonce; - bytes initCode; // concatenation of factory address and factoryData (or empty) - bytes callData; - bytes32 accountGasLimits; // concatenation of verificationGas (16 bytes) and callGas (16 bytes) - uint256 preVerificationGas; - bytes32 gasFees; // concatenation of maxPriorityFee (16 bytes) and maxFeePerGas (16 bytes) - bytes paymasterAndData; // concatenation of paymaster fields (or empty) - bytes signature; -} -``` - -This process of bundling user operations involves several costs that the bundler must cover, including base transaction fees, calldata serialization, entrypoint execution, and paymaster context costs. To compensate for these expenses, bundlers use the `preVerificationGas` and `gasFees` fields to charge users appropriately. - -NOTE: Estimating `preVerificationGas` is not standardized as it varies based on network conditions such as gas prices and the size of the operation bundle. - -TIP: Use xref:api:account.adoc#ERC4337Utils[`ERC4337Utils`] to manipulate the `UserOperation` struct and other ERC-4337 related values. - -=== Entrypoint - -Each `UserOperation` is executed through a contract known as the https://etherscan.io/address/0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108#code[`EntryPoint`]. This contract is a singleton deployed across multiple networks at the same address although other custom implementations may be used. - -The Entrypoint contracts is considered a trusted entity by the account. - -=== Bundlers - -The bundler is a piece of _offchain_ infrastructure that is in charge of processing an alternative mempool of user operations. Bundlers themselves call the Entrypoint contract's `handleOps` function with an array of UserOperations that are executed and included in a block. - -During the process, the bundler pays for the gas of executing the transaction and gets refunded during the execution phase of the Entrypoint contract. - -```solidity -/// @dev Process `userOps` and `beneficiary` receives all -/// the gas fees collected during the bundle execution. -function handleOps( - PackedUserOperation[] calldata ops, - address payable beneficiary -) external { ... } -``` - -=== Account Contract - -The Account Contract is a smart contract that implements the logic required to validate a `UserOperation` in the context of ERC-4337. Any smart contract account should conform with the `IAccount` interface to validate operations. - -```solidity -interface IAccount { - function validateUserOp(PackedUserOperation calldata, bytes32, uint256) external returns (uint256 validationData); -} -``` - -Similarly, an Account should have a way to execute these operations by either handling arbitrary calldata on its `fallback` or implementing the `IAccountExecute` interface: - -```solidity -interface IAccountExecute { - function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external; -} -``` - -NOTE: The `IAccountExecute` interface is optional. Developers might want to use xref:api:account.adoc#ERC7821[`ERC-7821`] for a minimal batched execution interface or rely on ERC-7579 or any other execution logic. - -To build your own account, see xref:accounts.adoc[accounts]. - -=== Factory Contract - -The smart contract accounts are created by a Factory contract defined by the Account developer. This factory receives arbitrary bytes as `initData` and returns an `address` where the logic of the account is deployed. - -To build your own factory, see xref:accounts.adoc#accounts_factory[account factories]. - -=== Paymaster Contract - -A Paymaster is an optional entity that can sponsor gas fees for Accounts, or allow them to pay for those fees in ERC-20 instead of native currency. This abstracts gas away of the user experience in the same way that computational costs of cloud servers are abstracted away from end-users. - -To build your own paymaster, see https://docs.openzeppelin.com/community-contracts/0.0.1/paymasters[paymasters]. - -== Further notes - -=== ERC-7562 Validation Rules - -To process a bundle of `UserOperations`, bundlers call xref:api:account.adoc#Account-validateUserOp-struct-PackedUserOperation-bytes32-uint256-[`validateUserOp`] on each operation sender to check whether the operation can be executed. However, the bundler has no guarantee that the state of the blockchain will remain the same after the validation phase. To overcome this problem, https://eips.ethereum.org/EIPS/eip-7562[ERC-7562] proposes a set of limitations to EVM code so that bundlers (or node operators) are protected from unexpected state changes. - -These rules outline the requirements for operations to be processed by the canonical mempool. - -Accounts can access its own storage during the validation phase, they might easily violate ERC-7562 storage access rules in undirect ways. For example, most accounts access their public keys from storage when validating a signature, limiting the ability of having accounts that validate operations for other accounts (e.g. via ERC-1271) - -TIP: Although any Account that breaks such rules may still be processed by a private bundler, developers should keep in mind the centralization tradeoffs of relying on private infrastructure instead of _permissionless_ execution. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/accounts.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/accounts.adoc deleted file mode 100644 index c2f8996..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/accounts.adoc +++ /dev/null @@ -1,354 +0,0 @@ -= Smart Accounts - -OpenZeppelin provides a simple xref:api:account.adoc#Account[`Account`] implementation including only the basic logic to handle user operations in compliance with ERC-4337. Developers who want to build their own account can leverage it to bootstrap custom implementations. - -User operations are validated using an xref:api:utils.adoc#AbstractSigner[`AbstractSigner`], which requires to implement the internal xref:api:utils.adoc#AbstractSigner-_rawSignatureValidation-bytes32-bytes-[`_rawSignatureValidation`] function, of which we offer a set of implementations to cover a wide customization range. This is the lowest-level signature validation layer and is used to wrap other validation methods like the Account's xref:api:account.adoc#Account-validateUserOp-struct-PackedUserOperation-bytes32-uint256-[`validateUserOp`]. - -== Setting up an account - -To setup an account, you can either start configuring it using our Wizard and selecting a predefined validation scheme, or bring your own logic and start by inheriting xref:api:account.adoc#Account[`Account`] from scratch. - -++++ - - - -++++ - -NOTE: Accounts don't support xref:erc721.adoc[ERC-721] and xref:erc1155.adoc[ERC-1155] tokens natively since these require the receiving address to implement an acceptance check. It is recommended to inherit xref:api:token/ERC721.adoc#ERC721Holder[ERC721Holder], xref:api:token/ERC1155.adoc#ERC1155Holder[ERC1155Holder] to include these checks in your account. - -=== Selecting a signer - -Since the minimum requirement of xref:api:account.adoc#Account[`Account`] is to provide an implementation of xref:api:utils/cryptography.adoc#AbstractSigner-_rawSignatureValidation-bytes32-bytes-[`_rawSignatureValidation`], the library includes specializations of the `AbstractSigner` contract that use custom digital signature verification algorithms. Some examples that you can select from include: - -* xref:api:utils/cryptography.adoc#SignerECDSA[`SignerECDSA`]: Verifies signatures produced by regular EVM Externally Owned Accounts (EOAs). -* xref:api:utils/cryptography.adoc#SignerP256[`SignerP256`]: Validates signatures using the secp256r1 curve, common for World Wide Web Consortium (W3C) standards such as FIDO keys, passkeys or secure enclaves. -* xref:api:utils/cryptography.adoc#SignerRSA[`SignerRSA`]: Verifies signatures of traditional PKI systems and X.509 certificates. -* xref:api:utils/cryptography.adoc#SignerERC7702[`SignerERC7702`]: Checks EOA signatures delegated to this signer using https://eips.ethereum.org/EIPS/eip-7702#set-code-transaction[EIP-7702 authorizations] -* xref:api:utils/cryptography.adoc#SignerERC7913[`SignerERC7913`]: Verifies generalized signatures following https://eips.ethereum.org/EIPS/eip-7913[ERC-7913]. -* https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#SignerZKEmail[`SignerZKEmail`]: Enables email-based authentication for smart contracts using zero knowledge proofs of email authority signatures. -* xref:api:utils/cryptography.adoc#MultiSignerERC7913[`MultiSignerERC7913`]: Allows using multiple ERC-7913 signers with a threshold-based signature verification system. -* xref:api:utils/cryptography.adoc#MultiSignerERC7913Weighted[`MultiSignerERC7913Weighted`]: Overrides the threshold mechanism of xref:api:utils/cryptography.adoc#MultiSignerERC7913[`MultiSignerERC7913`], offering different weights per signer. - -TIP: Given xref:api:utils/cryptography.adoc#SignerERC7913[`SignerERC7913`] provides a generalized standard for signature validation, you don't need to implement your own xref:api:utils/cryptography.adoc#AbstractSigner[`AbstractSigner`] for different signature schemes, consider bringing your own ERC-7913 verifier instead. - -==== Accounts factory - -The first time you send an user operation, your account will be created deterministically (i.e. its code and address can be predicted) using the the `initCode` field in the UserOperation. This field contains both the address of a smart contract (the factory) and the data required to call it and create your smart account. - -Suggestively, you can create your own account factory using the xref:api:proxy.adoc#Clones[Clones library], taking advantage of decreased deployment costs and account address predictability. - -[source,solidity] ----- -include::api:example$account/MyFactoryAccount.sol[] ----- - -Account factories should be carefully implemented to ensure the account address is deterministically tied to the initial owners. This prevents frontrunning attacks where a malicious actor could deploy the account with their own owners before the intended owner does. The factory should include the owner's address in the salt used for address calculation. - -==== Handling initialization - -Most smart accounts are deployed by a factory, the best practice is to create xref:api:proxy.adoc#minimal_clones[minimal clones] of initializable contracts. These signer implementations provide an initializable design by default so that the factory can interact with the account to set it up right after deployment in a single transaction. - -[source,solidity] ----- -import {Account} from "@openzeppelin/community-contracts/account/Account.sol"; -import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; -import {SignerECDSA} from "@openzeppelin/community-contracts/utils/cryptography/SignerECDSA.sol"; - -contract MyAccount is Initializable, Account, SignerECDSA, ... { - // ... - - function initializeECDSA(address signer) public initializer { - _setSigner(signer); - } -} ----- - -Note that some account implementations may be deployed directly and therefore, won't require a factory. - -WARNING: Leaving an account uninitialized may leave it unusable since no public key was associated with it. - -=== Signature validation - -Regularly, accounts implement https://eips.ethereum.org/EIPS/eip-1271[ERC-1271] to enable smart contract signature verification given its wide adoption. To be compliant means that smart contract exposes an xref:api:interfaces.adoc#IERC1271-isValidSignature-bytes32-bytes-[`isValidSignature(bytes32 hash, bytes memory signature)`] method that returns `0x1626ba7e` to identify whether the signature is valid. - -The benefit of this standard is that it allows to receive any format of `signature` for a given `hash`. This generalized mechanism fits very well with the account abstraction principle of _bringing your own validation mechanism_. - -This is how you enable ERC-1271 using an xref:api:utils/cryptography.adoc#AbstractSigner[`AbstractSigner`]: - -[source,solidity] ----- -function isValidSignature(bytes32 hash, bytes calldata signature) public view override returns (bytes4) { - return _rawSignatureValidation(hash, signature) ? IERC1271.isValidSignature.selector : bytes4(0xffffffff); -} ----- - -IMPORTANT: We recommend using xref:api:utils/cryptography.adoc#ERC7739[ERC7739] to avoid replayability across accounts. This defensive rehashing mechanism that prevents signatures for this account to be replayed in another account controlled by the same signer. See xref:accounts.adoc#erc_7739_signatures[ERC-7739 signatures]. - -=== Batched execution - -Batched execution allows accounts to execute multiple calls in a single transaction, which is particularly useful for bundling operations that need to be atomic. This is especially valuable in the context of account abstraction where you want to minimize the number of user operations and associated gas costs. xref:api:account.adoc#ERC7821[`ERC-7821`] standard provides a minimal interface for batched execution. - -The library implementation supports a single batch mode (`0x01000000000000000000`) and allows accounts to execute multiple calls atomically. The standard includes access control through the xref:api:account.adoc#ERC7821-_erc7821AuthorizedExecutor-address-bytes32-bytes-[`_erc7821AuthorizedExecutor`] function, which by default only allows the contract itself to execute batches. - -Here's an example of how to use batched execution using EIP-7702: - -[source,solidity] ----- -import {Account} from "@openzeppelin/community-contracts/account/Account.sol"; -import {ERC7821} from "@openzeppelin/community-contracts/account/extensions/draft-ERC7821.sol"; -import {SignerERC7702} from "@openzeppelin/community-contracts/utils/cryptography/SignerERC7702.sol"; - -contract MyAccount is Account, SignerERC7702, ERC7821 { - // Override to allow the entrypoint to execute batches - function _erc7821AuthorizedExecutor( - address caller, - bytes32 mode, - bytes calldata executionData - ) internal view virtual override returns (bool) { - return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); - } -} ----- - -The batched execution data follows a specific format that includes the calls to be executed. This format follows the same format as https://eips.ethereum.org/EIPS/eip-7579#execution-behavior[ERC-7579 execution] but only supports `0x01` call type (i.e. batched `call`) and default execution type (i.e. reverts if at least one subcall does). - -To encode an ERC-7821 batch, you can use https://viem.sh/[viem]'s utilities: - -[source,typescript] ----- -// CALL_TYPE_BATCH, EXEC_TYPE_DEFAULT, ..., selector, payload -const mode = encodePacked( - ["bytes1", "bytes1", "bytes4", "bytes4", "bytes22"], - ["0x01", "0x00", "0x00000000", "0x00000000", "0x00000000000000000000000000000000000000000000"] -); - -const entries = [ - { - target: "0x000...0001", - value: 0n, - data: "0x000...000", - }, - { - target: "0x000...0002", - value: 0n, - data: "0x000...000", - } -]; - -const batch = encodeAbiParameters( - [parseAbiParameter("(address,uint256,bytes)[]")], - [ - entries.map<[Address, bigint, Hex]>((entry) => - [entry.target, entry.value ?? 0n, entry.data ?? "0x"] - ), - ] -); - -const userOpData = encodeFunctionData({ - abi: account.abi, - functionName: "execute", - args: [mode, batch] -}); ----- - -== Bundle a `UserOperation` - -xref:account-abstraction.adoc#useroperation[UserOperations] are a powerful abstraction layer that enable more sophisticated transaction capabilities compared to traditional Ethereum transactions. To get started, you'll need to an account, which you can get by xref:accounts.adoc#accounts_factory[deploying a factory] for your implementation. - -=== Preparing a UserOp - -A UserOperation is a struct that contains all the necessary information for the EntryPoint to execute your transaction. You'll need the `sender`, `nonce`, `accountGasLimits` and `callData` fields to construct a `PackedUserOperation` that can be signed later (to populate the `signature` field). - -TIP: Specify `paymasterAndData` with the address of a paymaster contract concatenated to `data` that will be passed to the paymaster's validatePaymasterUserOp function to support sponsorship as part of your user operation. - -Here's how to prepare one using https://viem.sh/[viem]: - -[source,typescript] ----- -import { getContract, createWalletClient, http, Hex } from 'viem'; - -const walletClient = createWalletClient({ - account, // See Viem's `privateKeyToAccount` - chain, // import { ... } from 'viem/chains'; - transport: http(), -}) - -const entrypoint = getContract({ - abi: [/* ENTRYPOINT ABI */], - address: '0x', - client: walletClient, -}); - -const userOp = { - sender: '0x', - nonce: await entrypoint.read.getNonce([sender, 0n]), - initCode: "0x" as Hex, - callData: '0x', - accountGasLimits: encodePacked( - ["uint128", "uint128"], - [ - 100_000n, // verificationGasLimit - 300_000n, // callGasLimit - ] - ), - preVerificationGas: 50_000n, - gasFees: encodePacked( - ["uint128", "uint128"], - [ - 0n, // maxPriorityFeePerGas - 0n, // maxFeePerGas - ] - ), - paymasterAndData: "0x" as Hex, - signature: "0x" as Hex, -}; ----- - -In case your account hasn't been deployed yet, make sure to provide the `initCode` field as `abi.encodePacked(factory, factoryData)` to deploy the account within the same UserOp: - -[source,typescript] ----- -const deployed = await publicClient.getCode({ address: predictedAddress }); - -if (!deployed) { - userOp.initCode = encodePacked( - ["address", "bytes"], - [ - '0x', - encodeFunctionData({ - abi: [/* ACCOUNT ABI */], - functionName: "", - args: [...], - }), - ] - ); -} ----- - -==== Estimating gas - -To calculate gas parameters of a `UserOperation`, developers should carefully consider the following fields: - -* `verificationGasLimit`: This covers the gas costs for signature verification, paymaster validation (if used), and account validation logic. While a typical value is around 100,000 gas units, this can vary significantly based on the complexity of your signature validation scheme in both the account and paymaster contracts. - -* `callGasLimit`: This parameter accounts for the actual execution of your account's logic. It's recommended to use `eth_estimateGas` for each subcall and add additional buffer for computational overhead. - -* `preVerificationGas`: This compensates for the EntryPoint's execution overhead. While 50,000 gas is a reasonable starting point, you may need to increase this value based on your UserOperation's size and specific bundler requirements. - -NOTE: The `maxFeePerGas` and `maxPriorityFeePerGas` values are typically provided by your bundler service, either through their SDK or a custom RPC method. - -IMPORTANT: A penalty of 10% (`UNUSED_GAS_PENALTY_PERCENT`) is applied on the amounts of `callGasLimit` and `paymasterPostOpGasLimit` gas that remains unused if the amount of remaining unused gas is greater than or equal to 40,000 (`PENALTY_GAS_THRESHOLD`). - -=== Signing the UserOp - -To sign a UserOperation, you'll need to first calculate its hash as an EIP-712 typed data structure using the EntryPoint's domain, then sign this hash using your account's signature scheme, and finally encode the resulting signature in the format that your account contract expects for verification. - -[source,typescript] ----- -import { signTypedData } from 'viem/actions'; - -// EntryPoint v0.8 EIP-712 domain -const domain = { - name: 'ERC4337', - version: '1', - chainId: 1, // Your target chain ID - verifyingContract: '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108', // v08 -}; - -// EIP-712 types for PackedUserOperation -const types = { - PackedUserOperation: [ - { name: 'sender', type: 'address' }, - { name: 'nonce', type: 'uint256' }, - { name: 'initCode', type: 'bytes' }, - { name: 'callData', type: 'bytes' }, - { name: 'accountGasLimits', type: 'bytes32' }, - { name: 'preVerificationGas', type: 'uint256' }, - { name: 'gasFees', type: 'bytes32' }, - { name: 'paymasterAndData', type: 'bytes' }, - ], -} as const; - -// Sign the UserOperation using EIP-712 -userOp.signature = await eoa.signTypedData({ - domain, - types, - primaryType: 'PackedUserOperation', - message: { - sender: userOp.sender, - nonce: userOp.nonce, - initCode: userOp.initCode, - callData: userOp.callData, - accountGasLimits: userOp.accountGasLimits, - preVerificationGas: userOp.preVerificationGas, - gasFees: userOp.gasFees, - paymasterAndData: userOp.paymasterAndData, - }, -}); ----- - -Alternatively, developers can get the raw user operation hash by using the Entrypoint's `getUserOpHash` function: - -[source,typescript] ----- -const userOpHash = await entrypoint.read.getUserOpHash([userOp]); -userOp.signature = await eoa.sign({ hash: userOpHash }); ----- - -IMPORTANT: Using `getUserOpHash` directly may provide a poorer user experience as users see an opaque hash rather than structured transaction data. In many cases, offchain signers won't have an option to sign a raw hash. - -=== Sending the UserOp - -Finally, to send the user operation you can call `handleOps` on the Entrypoint contract and set yourself as the `beneficiary`. - -[source,typescript] ----- -// Send the UserOperation -const userOpReceipt = await walletClient - .writeContract({ - abi: [/* ENTRYPOINT ABI */], - address: '0x', - functionName: "handleOps", - args: [[userOp], eoa.address], - }) - .then((txHash) => - publicClient.waitForTransactionReceipt({ - hash: txHash, - }) - ); - -// Print receipt -console.log(userOpReceipt); ----- - -TIP: Since you're bundling your user operations yourself, you can safely specify `preVerificationGas` and `maxFeePerGas` in 0. - -=== Using a Bundler - -For better reliability, consider using a bundler service. Bundlers provide several key benefits: they automatically handle gas estimation, manage transaction ordering, support bundling multiple operations together, and generally offer higher transaction success rates compared to self-bundling. - -== Further notes - -=== ERC-7739 Signatures - -A common security practice to prevent user operation https://mirror.xyz/curiousapple.eth/pFqAdW2LiJ-6S4sg_u1z08k4vK6BCJ33LcyXpnNb8yU[replayability across smart contract accounts controlled by the same private key] (i.e. multiple accounts for the same signer) is to link the signature to the `address` and `chainId` of the account. This can be done by asking the user to sign a hash that includes these values. - -The problem with this approach is that the user might be prompted by the wallet provider to sign an https://x.com/howydev/status/1780353754333634738[obfuscated message], which is a phishing vector that may lead to a user losing its assets. - -To prevent this, developers may use xref:api:account#ERC7739Signer[`ERC7739Signer`], a utility that implements xref:api:interfaces#IERC1271[`IERC1271`] for smart contract signatures with a defensive rehashing mechanism based on a https://github.com/frangio/eip712-wrapper-for-eip1271[nested EIP-712 approach] to wrap the signature request in a context where there's clearer information for the end user. - -=== EIP-7702 Delegation - -https://eips.ethereum.org/EIPS/eip-7702[EIP-7702] lets EOAs delegate to smart contracts while keeping their original signing key. This creates a hybrid account that works like an EOA for signing but has smart contract features. Protocols don't need major changes to support EIP-7702 since they already handle both EOAs and smart contracts (see xref:api:utils/cryptography.adoc#SignatureChecker[SignatureChecker]). - -The signature verification stays compatible: delegated EOAs are treated as contracts using ERC-1271, making it easy to redelegate to a contract with ERC-1271 support with little overhead by reusing the validation mechanism of the account. - -TIP: Learn more about delegating to an ERC-7702 account in our xref:eoa-delegation.adoc[EOA Delegation] section. - -=== ERC-7579 Modules - -Smart accounts have evolved to embrace modularity as a design principle, with popular implementations like https://erc7579.com/#supporters[Safe, Pimlico, Rhinestone, Etherspot and many others] agreeing on ERC-7579 as the standard for module interoperability. This standardization enables accounts to extend their functionality through external contracts while maintaining compatibility across different implementations. - -OpenZeppelin Contracts provides both the building blocks for creating ERC-7579-compliant modules and an xref:api:account.adoc#AccountERC7579[`AccountERC7579`] implementation that supports installing and managing these modules. - -TIP: Learn more in our https://docs.openzeppelin.com/community-contracts/0.0.1/account-modules[account modules] section. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/backwards-compatibility.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/backwards-compatibility.adoc deleted file mode 100644 index 5d0e29b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/backwards-compatibility.adoc +++ /dev/null @@ -1,50 +0,0 @@ -= Backwards Compatibility -:page-aliases: releases-stability.adoc - -OpenZeppelin Contracts uses semantic versioning to communicate backwards compatibility of its API and storage layout. Patch and minor updates will generally be backwards compatible, with rare exceptions as detailed below. Major updates should be assumed incompatible with previous releases. On this page, we provide details about these guarantees. - -== API - -In backwards compatible releases, all changes should be either additions or modifications to internal implementation details. Most code should continue to compile and behave as expected. The exceptions to this rule are listed below. - -=== Security - -Infrequently a patch or minor update will remove or change an API in a breaking way, but only if the previous API is considered insecure. These breaking changes will be noted in the changelog and release notes, and published along with a security advisory. - -=== Draft or Pre-Final ERCs - -ERCs that are not Final can change in incompatible ways. For this reason, we avoid shipping implementations of ERCs before they are Final. Some exceptions are made for ERCs that have been published for a long time and seem unlikely to change. Implementations for ERCs that may have breaking changes are published in files named `draft-*.sol` to make that condition explicit. There is no backwards compatibility guarantee for content in files prefixed with `draft`. - -Standards that have achieved widespread adoption with strong backwards compatibility expectations from the community may be treated as de-facto finalized and published without the `draft-` prefix, as extensive ecosystem reliance makes breaking changes highly unlikely. - -=== Virtual & Overrides - -Almost all functions in this library are virtual with some exceptions, but this does not mean that overrides are encouraged. There is a subset of functions that are designed to be overridden. By defining overrides outside of this subset you are potentially relying on internal implementation details. We make efforts to preserve backwards compatibility even in these cases but it is extremely difficult and easy to accidentally break. Caution is advised. - -Additionally, some minor updates may result in new compilation errors of the kind "two or more base classes define function with same name and parameter types" or "need to specify overridden contract", due to what Solidity considers ambiguity in inherited functions. This should be resolved by adding an override that invokes the function via `super`. - -See xref:extending-contracts.adoc[Extending Contracts] for more about virtual and overrides. - -=== Structs - -Struct members with an underscore prefix should be considered "private" and may break in minor versions. Struct data should only be accessed and modified through library functions. - -=== Errors - -The specific error format and data that is included with reverts should not be assumed stable unless otherwise specified. - -=== Major Releases - -Major releases should be assumed incompatible. Nevertheless, the external interfaces of contracts will remain compatible if they are standardized, or if the maintainers judge that changing them would cause significant strain on the ecosystem. - -An important aspect that major releases may break is "upgrade compatibility", in particular storage layout compatibility. It will never be safe for a live contract to upgrade from one major release to another. - -== Storage Layout - -Minor and patch updates always preserve storage layout compatibility. This means that a live contract can be upgraded from one minor to another without corrupting the storage layout. In some cases it may be necessary to initialize new state variables when upgrading, although we expect this to be infrequent. - -We recommend using xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins or CLI] to ensure storage layout safety of upgrades. - -== Solidity Version - -The minimum Solidity version required to compile the contracts will remain unchanged in minor and patch updates. New contracts introduced in minor releases may make use of newer Solidity features and require a more recent version of the compiler. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/eoa-delegation.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/eoa-delegation.adoc deleted file mode 100644 index 935852f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/eoa-delegation.adoc +++ /dev/null @@ -1,143 +0,0 @@ -= EOA Delegation - -https://eips.ethereum.org/EIPS/eip-7702[EIP-7702] introduces a new transaction type (`0x4`) that grants https://ethereum.org/en/developers/docs/accounts/[Externally Owned Accounts (EOAs)] the ability to delegate execution to an smart contract. This is particularly useful to enable traditional EVM accounts to: - -* Batch multiple operations in a single transaction (e.g. xref:api:token/ERC20.adoc#IERC20-approve-address-uint256-[`approve`] + xref:api:token/ERC20.adoc#IERC20-transfer-address-uint256-[`transfer`], yey!) -* Sponsoring transactions for other users. -* Implementing privilege de-escalation (e.g., sub-keys with limited permissions) - -This section walks you through the process of delegating an EOA to a contract following https://eips.ethereum.org/EIPS/eip-7702[ERC-7702]. This allows you to use your EOA's private key to sign and execute operations with custom execution logic. Combined with https://eips.ethereum.org/EIPS/eip-4337[ERC-4337] infrastructure, users can achieve gas sponsoring through https://docs.openzeppelin.com/community-contracts/paymasters[paymasters]. - -== Delegating execution - -EIP-7702 enables EOAs to delegate their execution capabilities to smart contracts, effectively bridging the gap between traditional and xref:accounts.adoc[Smart Accounts]. The xref:api:utils/cryptography.adoc#[`SignerERC7702`] utility facilitates this delegation by verifying signatures against the EOA's address (`address(this)`), making it easier to implement EIP-7702 in smart contract accounts. - -[source,solidity] ----- -include::api:example$account/MyAccountERC7702.sol[] ----- - -TIP: Users can delegate to an instance of xref:api:account.adoc#ERC7821[`ERC-7821`] for a minimal batch executor that does not use ERC-4337 related code. - -=== Signing Authorization - -To authorize delegation, the EOA owner signs a message containing the chain ID, nonce, delegation address, and signature components (i.e. `[chain_id, address, nonce, y_parity, r, s]`). This signed authorization serves two purposes: it restricts execution to only the delegate contract and prevents replay attacks. - -The EOA maintains a delegation designator for each authorized address on each chain, which points to the contract whose code will be executed in the EOA's context to handle delegated operations. - -Here's how to construct an authorization with https://viem.sh/[viem]: - -[source, typescript] ----- -// Remember not to hardcode your private key! -const eoa = privateKeyToAccount(''); -const eoaClient = createWalletClient({ - account: eoa, - chain: publicClient.chain, - transport: http(), -}); - -const walletClient = createWalletClient({ - account, // See Viem's `privateKeyToAccount` - chain, // import { ... } from 'viem/chains'; - transport: http(), -}) - -const authorization = await eoaClient.signAuthorization({ - account: walletClient.account.address, - contractAddress: '0x', - // Use instead of `account` if your - // walletClient's account is the one sending the transaction - // executor: "self", -}); ----- - -NOTE: When implementing delegate contracts, ensure they require signatures that avoid replayability (e.g. a domain separator, nonce). -A poorly implemented delegate can allow a malicious actor to take near complete control over a signer's EOA. - -=== Send a Set Code Transaction - -After signing the authorization, you need to send a `SET_CODE_TX_TYPE` (0x04) transaction to write the delegation designator (i.e. `0xef0100 || address`) to your EOA's code, which tells the EVM to load and execute code from the specified address when operations are performed on your EOA. - -[source, typescript] ----- -// Send the `authorization` along with `data` -const receipt = await walletClient - .sendTransaction({ - authorizationList: [authorization], - data: '0x', - to: eoa.address, - }) - .then((txHash) => - publicClient.waitForTransactionReceipt({ - hash: txHash, - }) - ); - -// Print receipt -console.log(userOpReceipt); ----- - -To remove the delegation and restore your EOA to its original state, you can send a `SET_CODE_TX_TYPE` transaction with an authorization tuple that points to the zero address (`0x0000000000000000000000000000000000000000`). This will clear the account's code and reset its code hash to the empty hash, however, be aware that it will not automatically clean the EOA storage. - -When changing an account's delegation, ensure the newly delegated code is purposely designed and tested as an upgrade to the old one. To ensure safe migration between delegate contracts, namespaced storage that avoid accidental collisions following ERC-7201. - -WARNING: Updating the delegation designator may render your EOA unusable due to potential storage collisions. We recommend following similar practices to those of https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable[writing upgradeable smart contracts]. - -== Using with ERC-4337 - -The ability to set code to execute logic on an EOA allows users to leverage ERC-4337 infrastructure to process user operations. Developers only need to combine an xref:api:account.adoc#Account[`Account`] contract with an xref:api:utils/cryptography.adoc#SignerERC7702[`SignerERC7702`] to accomplish ERC-4337 compliance out of the box. - -=== Sending a UserOp - -Once your EOA is delegated to an ERC-4337 compatible account, you can send user operations through the entry point contract. The user operation includes all the necessary fields for execution, including gas limits, fees, and the actual call data to execute. The entry point will validate the operation and execute it in the context of your delegated account. - -Similar to how xref:accounts.adoc#bundle_a_useroperation[sending a UserOp] is achieved for factory accounts, here's how you can construct a UserOp for an EOA who's delegated to an xref:api:account.adoc#Account[`Account`] contract. - -[source, typescript] ----- -const userOp = { - sender: eoa.address, - nonce: await entrypoint.read.getNonce([eoa.address, 0n]), - initCode: "0x" as Hex, - callData: '0x', - accountGasLimits: encodePacked( - ["uint128", "uint128"], - [ - 100_000n, // verificationGas - 300_000n, // callGas - ] - ), - preVerificationGas: 50_000n, - gasFees: encodePacked( - ["uint128", "uint128"], - [ - 0n, // maxPriorityFeePerGas - 0n, // maxFeePerGas - ] - ), - paymasterAndData: "0x" as Hex, - signature: "0x" as Hex, -}; - -const userOpHash = await entrypoint.read.getUserOpHash([userOp]); -userOp.signature = await eoa.sign({ hash: userOpHash }); - -const userOpReceipt = await eoaClient - .writeContract({ - abi: EntrypointV08Abi, - address: entrypoint.address, - authorizationList: [authorization], - functionName: "handleOps", - args: [[userOp], eoa.address], - }) - .then((txHash) => - publicClient.waitForTransactionReceipt({ - hash: txHash, - }) - ); - -console.log(userOpReceipt); ----- - -NOTE: When using sponsored transaction relayers, be aware that the authorized account can cause relayers to spend gas without being reimbursed by either invalidating the authorization (increasing the account's nonce) or by sweeping the relevant assets out of the account. Relayers may implement safeguards like requiring a bond or using a reputation system. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc1155.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc1155.adoc deleted file mode 100644 index 2c31db8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc1155.adoc +++ /dev/null @@ -1,118 +0,0 @@ -= ERC-1155 - -ERC-1155 is a novel token standard that aims to take the best from previous standards to create a xref:tokens.adoc#different-kinds-of-tokens[*fungibility-agnostic*] and *gas-efficient* xref:tokens.adoc#but_first_coffee_a_primer_on_token_contracts[token contract]. - -TIP: ERC-1155 draws ideas from all of xref:erc20.adoc[ERC-20], xref:erc721.adoc[ERC-721], and https://eips.ethereum.org/EIPS/eip-777[ERC-777]. If you're unfamiliar with those standards, head to their guides before moving on. - -[[multi-token-standard]] -== Multi Token Standard - -The distinctive feature of ERC-1155 is that it uses a single smart contract to represent multiple tokens at once. This is why its xref:api:token/ERC1155.adoc#IERC1155-balanceOf-address-uint256-[`balanceOf`] function differs from ERC-20's and ERC-777's: it has an additional `id` argument for the identifier of the token that you want to query the balance of. - -This is similar to how ERC-721 does things, but in that standard a token `id` has no concept of balance: each token is non-fungible and exists or doesn't. The ERC-721 xref:api:token/ERC721.adoc#IERC721-balanceOf-address-[`balanceOf`] function refers to _how many different tokens_ an account has, not how many of each. On the other hand, in ERC-1155 accounts have a distinct balance for each token `id`, and non-fungible tokens are implemented by simply minting a single one of them. - -This approach leads to massive gas savings for projects that require multiple tokens. Instead of deploying a new contract for each token type, a single ERC-1155 token contract can hold the entire system state, reducing deployment costs and complexity. - -[[batch-operations]] -== Batch Operations - -Because all state is held in a single contract, it is possible to operate over multiple tokens in a single transaction very efficiently. The standard provides two functions, xref:api:token/ERC1155.adoc#IERC1155-balanceOfBatch-address---uint256---[`balanceOfBatch`] and xref:api:token/ERC1155.adoc#IERC1155-safeBatchTransferFrom-address-address-uint256---uint256---bytes-[`safeBatchTransferFrom`], that make querying multiple balances and transferring multiple tokens simpler and less gas-intensive. - -In the spirit of the standard, we've also included batch operations in the non-standard functions, such as xref:api:token/ERC1155.adoc#ERC1155-_mintBatch-address-uint256---uint256---bytes-[`_mintBatch`]. - -== Constructing an ERC-1155 Token Contract - -We'll use ERC-1155 to track multiple items in our game, which will each have their own unique attributes. We mint all items to the deployer of the contract, which we can later transfer to players. Players are free to keep their tokens or trade them with other people as they see fit, as they would any other asset on the blockchain! - -For simplicity, we will mint all items in the constructor, but you could add minting functionality to the contract to mint on demand to players. - -TIP: For an overview of minting mechanisms, check out xref:erc20-supply.adoc[Creating ERC-20 Supply]. - -Here's what a contract for tokenized items might look like: - -[source,solidity] ----- -include::api:example$token/ERC1155/GameItems.sol[] ----- - -Note that for our Game Items, Gold is a fungible token whilst Thor's Hammer is a non-fungible token as we minted only one. - -The xref:api:token/ERC1155.adoc#ERC1155[`ERC1155`] contract includes the optional extension xref:api:token/ERC1155.adoc#IERC1155MetadataURI[`IERC1155MetadataURI`]. That's where the xref:api:token/ERC1155.adoc#IERC1155MetadataURI-uri-uint256-[`uri`] function comes from: we use it to retrieve the metadata uri. - -Also note that, unlike ERC-20, ERC-1155 lacks a `decimals` field, since each token is distinct and cannot be partitioned. - -Once deployed, we will be able to query the deployer’s balance: -[source,javascript] ----- -> gameItems.balanceOf(deployerAddress,3) -1000000000 ----- - -We can transfer items to player accounts: -[source,javascript] ----- -> gameItems.safeTransferFrom(deployerAddress, playerAddress, 2, 1, "0x0") -> gameItems.balanceOf(playerAddress, 2) -1 -> gameItems.balanceOf(deployerAddress, 2) -0 ----- - -We can also batch transfer items to player accounts and get the balance of batches: -[source,javascript] ----- -> gameItems.safeBatchTransferFrom(deployerAddress, playerAddress, [0,1,3,4], [50,100,1,1], "0x0") -> gameItems.balanceOfBatch([playerAddress,playerAddress,playerAddress,playerAddress,playerAddress], [0,1,2,3,4]) -[50,100,1,1,1] ----- - -The metadata uri can be obtained: - -[source,javascript] ----- -> gameItems.uri(2) -"https://game.example/api/item/{id}.json" ----- - -The `uri` can include the string `++{id}++` which clients must replace with the actual token ID, in lowercase hexadecimal (with no 0x prefix) and leading zero padded to 64 hex characters. - -For token ID `2` and uri `++https://game.example/api/item/{id}.json++` clients would replace `++{id}++` with `0000000000000000000000000000000000000000000000000000000000000002` to retrieve JSON at `https://game.example/api/item/0000000000000000000000000000000000000000000000000000000000000002.json`. - -The JSON document for token ID 2 might look something like: - -[source,json] ----- -{ - "name": "Thor's hammer", - "description": "Mjölnir, the legendary hammer of the Norse god of thunder.", - "image": "https://game.example/item-id-8u5h2m.png", - "strength": 20 -} ----- - -For more information about the metadata JSON Schema, check out the https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md#erc-1155-metadata-uri-json-schema[ERC-1155 Metadata URI JSON Schema]. - -NOTE: You'll notice that the item's information is included in the metadata, but that information isn't on-chain! So a game developer could change the underlying metadata, changing the rules of the game! - -TIP: If you'd like to put all item information on-chain, you can extend ERC-721 to do so (though it will be rather costly) by providing a xref:utilities.adoc#base64[`Base64`] Data URI with the JSON schema encoded. You could also leverage IPFS to store the URI information, but these techniques are out of the scope of this overview guide - -[[sending-to-contracts]] -== Sending Tokens to Contracts - -A key difference when using xref:api:token/ERC1155.adoc#IERC1155-safeTransferFrom-address-address-uint256-uint256-bytes-[`safeTransferFrom`] is that token transfers to other contracts may revert with the following custom error: - -[source,text] ----- -ERC1155InvalidReceiver("

      ") ----- - -This is a good thing! It means that the recipient contract has not registered itself as aware of the ERC-1155 protocol, so transfers to it are disabled to *prevent tokens from being locked forever*. As an example, https://etherscan.io/token/0xa74476443119A942dE498590Fe1f2454d7D4aC0d?a=0xa74476443119A942dE498590Fe1f2454d7D4aC0d[the Golem contract currently holds over 350k `GNT` tokens], and lacks methods to get them out of there. This has happened to virtually every ERC20-backed project, usually due to user error. - -In order for our contract to receive ERC-1155 tokens we can inherit from the convenience contract xref:api:token/ERC1155.adoc#ERC1155Holder[`ERC1155Holder`] which handles the registering for us. However, we need to remember to implement functionality to allow tokens to be transferred out of our contract: - -[source,solidity] ----- -include::api:example$token/ERC1155/MyERC115HolderContract.sol[] ----- - -We can also implement more complex scenarios using the xref:api:token/ERC1155.adoc#IERC1155Receiver-onERC1155Received-address-address-uint256-uint256-bytes-[`onERC1155Received`] and xref:api:token/ERC1155.adoc#IERC1155Receiver-onERC1155BatchReceived-address-address-uint256---uint256---bytes-[`onERC1155BatchReceived`] functions. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20-supply.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20-supply.adoc deleted file mode 100644 index 273cb32..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20-supply.adoc +++ /dev/null @@ -1,71 +0,0 @@ -= Creating ERC-20 Supply - -In this guide, you will learn how to create an ERC-20 token with a custom supply mechanism. We will showcase two idiomatic ways to use OpenZeppelin Contracts for this purpose that you will be able to apply to your smart contract development practice. - -The standard interface implemented by tokens built on Ethereum is called ERC-20, and Contracts includes a widely used implementation of it: the aptly named xref:api:token/ERC20.adoc[`ERC20`] contract. This contract, like the standard itself, is quite simple and bare-bones. In fact, if you try to deploy an instance of `ERC20` as-is it will be quite literally useless... it will have no supply! What use is a token with no supply? - -The way that supply is created is not defined in the ERC-20 document. Every token is free to experiment with its own mechanisms, ranging from the most decentralized to the most centralized, from the most naive to the most researched, and more. - -[[fixed-supply]] -== Fixed Supply - -Let's say we want a token with a fixed supply of 1000, initially allocated to the account that deploys the contract. If you've used Contracts v1, you may have written code like the following: - -[source,solidity] ----- -contract ERC20FixedSupply is ERC20 { - constructor() { - totalSupply += 1000; - balances[msg.sender] += 1000; - } -} ----- - -Starting with Contracts v2, this pattern is not only discouraged, but disallowed. The variables `totalSupply` and `balances` are now private implementation details of `ERC20`, and you can't directly write to them. Instead, there is an internal xref:api:token/ERC20.adoc#ERC20-_mint-address-uint256-[`_mint`] function that will do exactly this: - -[source,solidity] ----- -contract ERC20FixedSupply is ERC20 { - constructor() ERC20("Fixed", "FIX") { - _mint(msg.sender, 1000); - } -} ----- - -Encapsulating state like this makes it safer to extend contracts. For instance, in the first example we had to manually keep the `totalSupply` in sync with the modified balances, which is easy to forget. In fact, we omitted something else that is also easily forgotten: the `Transfer` event that is required by the standard, and which is relied on by some clients. The second example does not have this bug, because the internal `_mint` function takes care of it. - -[[rewarding-miners]] -== Rewarding Miners - -The internal xref:api:token/ERC20.adoc#ERC20-_mint-address-uint256-[`_mint`] function is the key building block that allows us to write ERC-20 extensions that implement a supply mechanism. - -The mechanism we will implement is a token reward for the miners that produce Ethereum blocks. In Solidity, we can access the address of the current block's miner in the global variable `block.coinbase`. We will mint a token reward to this address whenever someone calls the function `mintMinerReward()` on our token. The mechanism may sound silly, but you never know what kind of dynamic this might result in, and it's worth analyzing and experimenting with! - -[source,solidity] ----- -contract ERC20WithMinerReward is ERC20 { - constructor() ERC20("Reward", "RWD") {} - - function mintMinerReward() public { - _mint(block.coinbase, 1000); - } -} ----- - -As we can see, `_mint` makes it super easy to do this correctly. - -[[automating-the-reward]] -== Automating the Reward - -So far our supply mechanism was triggered manually, but `ERC20` also allows us to extend the core functionality of the token through the xref:api:token/ERC20.adoc#ERC20-_update-address-address-uint256-[`_update`] function. - -Adding to the supply mechanism from the previous section, we can use this function to mint a miner reward for every token transfer that is included in the blockchain. - -```solidity -include::api:example$ERC20WithAutoMinerReward.sol[] -``` - -[[wrapping-up]] -== Wrapping Up - -We've seen how to implement an ERC-20 supply mechanism: internally through `_mint`. Hopefully this has helped you understand how to use OpenZeppelin Contracts and some of the design principles behind it, and you can apply them to your own smart contracts. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20.adoc deleted file mode 100644 index 104b4ef..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc20.adoc +++ /dev/null @@ -1,67 +0,0 @@ -= ERC-20 - -An ERC-20 token contract keeps track of xref:tokens.adoc#different-kinds-of-tokens[_fungible_ tokens]: any one token is exactly equal to any other token; no tokens have special rights or behavior associated with them. This makes ERC-20 tokens useful for things like a *medium of exchange currency*, *voting rights*, *staking*, and more. - -OpenZeppelin Contracts provides many ERC20-related contracts. On the xref:api:token/ERC20.adoc[`API reference`] you'll find detailed information on their properties and usage. - -[[constructing-an-erc20-token-contract]] -== Constructing an ERC-20 Token Contract - -Using Contracts, we can easily create our own ERC-20 token contract, which will be used to track _Gold_ (GLD), an internal currency in a hypothetical game. - -Here's what our GLD token might look like. - -[source,solidity] ----- -include::api:example$token/ERC20/GLDToken.sol[] ----- - -Our contracts are often used via https://solidity.readthedocs.io/en/latest/contracts.html#inheritance[inheritance], and here we're reusing xref:api:token/ERC20.adoc#erc20[`ERC20`] for both the basic standard implementation and the xref:api:token/ERC20.adoc#ERC20-name--[`name`], xref:api:token/ERC20.adoc#ERC20-symbol--[`symbol`], and xref:api:token/ERC20.adoc#ERC20-decimals--[`decimals`] optional extensions. Additionally, we're creating an `initialSupply` of tokens, which will be assigned to the address that deploys the contract. - -TIP: For a more complete discussion of ERC-20 supply mechanisms, see xref:erc20-supply.adoc[Creating ERC-20 Supply]. - -That's it! Once deployed, we will be able to query the deployer's balance: - -[source,javascript] ----- -> GLDToken.balanceOf(deployerAddress) -1000000000000000000000 ----- - -We can also xref:api:token/ERC20.adoc#IERC20-transfer-address-uint256-[transfer] these tokens to other accounts: - -[source,javascript] ----- -> GLDToken.transfer(otherAddress, 300000000000000000000) -> GLDToken.balanceOf(otherAddress) -300000000000000000000 -> GLDToken.balanceOf(deployerAddress) -700000000000000000000 ----- - -[[a-note-on-decimals]] -== A Note on `decimals` - -Often, you'll want to be able to divide your tokens into arbitrary amounts: say, if you own `5 GLD`, you may want to send `1.5 GLD` to a friend, and keep `3.5 GLD` to yourself. Unfortunately, Solidity and the EVM do not support this behavior: only integer (whole) numbers can be used, which poses an issue. You may send `1` or `2` tokens, but not `1.5`. - -To work around this, xref:api:token/ERC20.adoc#ERC20[`ERC20`] provides a xref:api:token/ERC20.adoc#ERC20-decimals--[`decimals`] field, which is used to specify how many decimal places a token has. To be able to transfer `1.5 GLD`, `decimals` must be at least `1`, since that number has a single decimal place. - -How can this be achieved? It's actually very simple: a token contract can use larger integer values, so that a balance of `50` will represent `5 GLD`, a transfer of `15` will correspond to `1.5 GLD` being sent, and so on. - -It is important to understand that `decimals` is _only used for display purposes_. All arithmetic inside the contract is still performed on integers, and it is the different user interfaces (wallets, exchanges, etc.) that must adjust the displayed values according to `decimals`. The total token supply and balance of each account are not specified in `GLD`: you need to divide by `10 ** decimals` to get the actual `GLD` amount. - -You'll probably want to use a `decimals` value of `18`, just like Ether and most ERC-20 token contracts in use, unless you have a very special reason not to. When minting tokens or transferring them around, you will be actually sending the number `num GLD * (10 ** decimals)`. - -NOTE: By default, `ERC20` uses a value of `18` for `decimals`. To use a different value, you will need to override the `decimals()` function in your contract. - -```solidity -function decimals() public view virtual override returns (uint8) { - return 16; -} -``` - -So if you want to send `5` tokens using a token contract with 18 decimals, the method to call will actually be: - -```solidity -transfer(recipient, 5 * (10 ** 18)); -``` diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc4626.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc4626.adoc deleted file mode 100644 index c219595..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc4626.adoc +++ /dev/null @@ -1,214 +0,0 @@ -= ERC-4626 -:stem: latexmath - -https://eips.ethereum.org/EIPS/eip-4626[ERC-4626] is an extension of xref:erc20.adoc[ERC-20] that proposes a standard interface for token vaults. This standard interface can be used by widely different contracts (including lending markets, aggregators, and intrinsically interest bearing tokens), which brings a number of subtleties. Navigating these potential issues is essential to implementing a compliant and composable token vault. - -We provide a base implementation of ERC-4626 that includes a simple vault. This contract is designed in a way that allows developers to easily re-configure the vault's behavior, with minimal overrides, while staying compliant. In this guide, we will discuss some security considerations that affect ERC-4626. We will also discuss common customizations of the vault. - -[[inflation-attack]] -== Security concern: Inflation attack - -=== Visualizing the vault - -In exchange for the assets deposited into an ERC-4626 vault, a user receives shares. These shares can later be burned to redeem the corresponding underlying assets. The number of shares a user gets depends on the amount of assets they put in and on the exchange rate of the vault. This exchange rate is defined by the current liquidity held by the vault. - -- If a vault has 100 tokens to back 200 shares, then each share is worth 0.5 assets. -- If a vault has 200 tokens to back 100 shares, then each share is worth 2.0 assets. - -In other words, the exchange rate can be defined as the slope of the line that passes through the origin and the current number of assets and shares in the vault. Deposits and withdrawals move the vault in this line. - -image::erc4626-rate-linear.png[Exchange rates in linear scale] - -When plotted in log-log scale, the rate is defined similarly, but appears differently (because the point (0,0) is infinitely far away). Rates are represented by "diagonal" lines with different offsets. - -image::erc4626-rate-loglog.png[Exchange rates in logarithmic scale] - -In such a representation, widely different rates can be clearly visible in the same graph. This wouldn't be the case in linear scale. - -image::erc4626-rate-loglogext.png[More exchange rates in logarithmic scale] - -=== The attack - -When depositing tokens, the number of shares a user gets is rounded towards zero. This rounding takes away value from the user in favor of the vault (i.e. in favor of all the current shareholders). This rounding is often negligible because of the amount at stake. If you deposit 1e9 shares worth of tokens, the rounding will have you lose at most 0.0000001% of your deposit. However if you deposit 10 shares worth of tokens, you could lose 10% of your deposit. Even worse, if you deposit <1 share worth of tokens, then you get 0 shares, and you basically made a donation. - -For a given amount of assets, the more shares you receive the safer you are. If you want to limit your losses to at most 1%, you need to receive at least 100 shares. - -image::erc4626-deposit.png[Depositing assets] - -In the figure we can see that for a given deposit of 500 assets, the number of shares we get and the corresponding rounding losses depend on the exchange rate. If the exchange rate is that of the orange curve, we are getting less than a share, so we lose 100% of our deposit. However, if the exchange rate is that of the green curve, we get 5000 shares, which limits our rounding losses to at most 0.02%. - -image::erc4626-mint.png[Minting shares] - -Symmetrically, if we focus on limiting our losses to a maximum of 0.5%, we need to get at least 200 shares. With the green exchange rate that requires just 20 tokens, but with the orange rate that requires 200000 tokens. - -We can clearly see that the blue and green curves correspond to vaults that are safer than the yellow and orange curves. - -The idea of an inflation attack is that an attacker can donate assets to the vault to move the rate curve to the right, and make the vault unsafe. - -image::erc4626-attack.png[Inflation attack without protection] - -Figure 6 shows how an attacker can manipulate the rate of an empty vault. First the attacker must deposit a small amount of tokens (1 token) and follow up with a donation of 1e5 tokens directly to the vault to move the exchange rate "right". This puts the vault in a state where any deposit smaller than 1e5 would be completely lost to the vault. Given that the attacker is the only shareholder (from their donation), the attacker would steal all the tokens deposited. - -An attacker would typically wait for a user to do the first deposit into the vault, and would frontrun that operation with the attack described above. The risk is low, and the size of the "donation" required to manipulate the vault is equivalent to the size of the deposit that is being attacked. - -In math that gives: - -- stem:[a_0] the attacker deposit -- stem:[a_1] the attacker donation -- stem:[u] the user deposit - -[%header,cols=4*] -|=== -| -| Assets -| Shares -| Rate - -| initial -| stem:[0] -| stem:[0] -| - - -| after attacker's deposit -| stem:[a_0] -| stem:[a_0] -| stem:[1] - -| after attacker's donation -| stem:[a_0+a_1] -| stem:[a_0] -| stem:[\frac{a_0}{a_0+a_1}] -|=== - -This means a deposit of stem:[u] will give stem:[\frac{u \times a_0}{a_0 + a_1}] shares. - -For the attacker to dilute that deposit to 0 shares, causing the user to lose all its deposit, it must ensure that - -[stem] -++++ -\frac{u \times a_0}{a_0+a_1} < 1 \iff u < 1 + \frac{a_1}{a_0} -++++ - -Using stem:[a_0 = 1] and stem:[a_1 = u] is enough. So the attacker only needs stem:[u+1] assets to perform a successful attack. - -It is easy to generalize the above results to scenarios where the attacker is going after a smaller fraction of the user's deposit. In order to target stem:[\frac{u}{n}], the user needs to suffer rounding of a similar fraction, which means the user must receive at most stem:[n] shares. This results in: - -[stem] -++++ -\frac{u \times a_0}{a_0+a_1} < n \iff \frac{u}{n} < 1 + \frac{a_1}{a_0} -++++ - -In this scenario, the attack is stem:[n] times less powerful (in how much it is stealing) and costs stem:[n] times less to execute. In both cases, the amount of funds the attacker needs to commit is equivalent to its potential earnings. - -=== Defending with a virtual offset - -The defense we propose is based on the approach used in link:https://github.com/boringcrypto/YieldBox[YieldBox]. It consists of two parts: - -- Use an offset between the "precision" of the representation of shares and assets. Said otherwise, we use more decimal places to represent the shares than the underlying token does to represent the assets. -- Include virtual shares and virtual assets in the exchange rate computation. These virtual assets enforce the conversion rate when the vault is empty. - -These two parts work together in enforcing the security of the vault. First, the increased precision corresponds to a high rate, which we saw is safer as it reduces the rounding error when computing the amount of shares. Second, the virtual assets and shares (in addition to simplifying a lot of the computations) capture part of the donation, making it unprofitable for a developer to perform an attack. - -Following the previous math definitions, we have: - -- stem:[\delta] the vault offset -- stem:[a_0] the attacker deposit -- stem:[a_1] the attacker donation -- stem:[u] the user deposit - -[%header,cols=4*] -|=== -| -| Assets -| Shares -| Rate - -| initial -| stem:[1] -| stem:[10^\delta] -| stem:[10^\delta] - -| after attacker's deposit -| stem:[1+a_0] -| stem:[10^\delta \times (1+a_0)] -| stem:[10^\delta] - -| after attacker's donation -| stem:[1+a_0+a_1] -| stem:[10^\delta \times (1+a_0)] -| stem:[10^\delta \times \frac{1+a_0}{1+a_0+a_1}] -|=== - -One important thing to note is that the attacker only owns a fraction stem:[\frac{a_0}{1 + a_0}] of the shares, so when doing the donation, he will only be able to recover that fraction stem:[\frac{a_1 \times a_0}{1 + a_0}] of the donation. The remaining stem:[\frac{a_1}{1+a_0}] are captured by the vault. - -[stem] -++++ -\mathit{loss} = \frac{a_1}{1+a_0} -++++ - -When the user deposits stem:[u], he receives - -[stem] -++++ -10^\delta \times u \times \frac{1+a_0}{1+a_0+a_1} -++++ - -For the attacker to dilute that deposit to 0 shares, causing the user to lose all its deposit, it must ensure that - -[stem] -++++ -10^\delta \times u \times \frac{1+a_0}{1+a_0+a_1} < 1 -++++ - -[stem] -++++ -\iff 10^\delta \times u < \frac{1+a_0+a_1}{1+a_0} -++++ - -[stem] -++++ -\iff 10^\delta \times u < 1 + \frac{a_1}{1+a_0} -++++ - -[stem] -++++ -\iff 10^\delta \times u \le \mathit{loss} -++++ - -- If the offset is 0, the attacker loss is at least equal to the user's deposit. -- If the offset is greater than 0, the attacker will have to suffer losses that are orders of magnitude bigger than the amount of value that can hypothetically be stolen from the user. - -This shows that even with an offset of 0, the virtual shares and assets make this attack non profitable for the attacker. Bigger offsets increase the security even further by making any attack on the user extremely wasteful. - -The following figure shows how the offset impacts the initial rate and limits the ability of an attacker with limited funds to inflate it effectively. - -image::erc4626-attack-3a.png[Inflation attack without offset=3] -stem:[\delta = 3], stem:[a_0 = 1], stem:[a_1 = 10^5] - -image::erc4626-attack-3b.png[Inflation attack without offset=3 and an attacker deposit that limits its losses] -stem:[\delta = 3], stem:[a_0 = 100], stem:[a_1 = 10^5] - -image::erc4626-attack-6.png[Inflation attack without offset=6] -stem:[\delta = 6], stem:[a_0 = 1], stem:[a_1 = 10^5] - - -[[fees]] -== Custom behavior: Adding fees to the vault - -In an ERC-4626 vaults, fees can be captured during the deposit/mint and/or during the withdraw/redeem steps. In both cases it is essential to remain compliant with the ERC-4626 requirements with regard to the preview functions. - -For example, if calling `deposit(100, receiver)`, the caller should deposit exactly 100 underlying tokens, including fees, and the receiver should receive a number of shares that matches the value returned by `previewDeposit(100)`. Similarly, `previewMint` should account for the fees that the user will have to pay on top of share's cost. - -As for the `Deposit` event, while this is less clear in the EIP spec itself, there seems to be consensus that it should include the number of assets paid for by the user, including the fees. - -On the other hand, when withdrawing assets, the number given by the user should correspond to what he receives. Any fees should be added to the quote (in shares) performed by `previewWithdraw`. - -The `Withdraw` event should include the number of shares the user burns (including fees) and the number of assets the user actually receives (after fees are deducted). - -The consequence of this design is that both the `Deposit` and `Withdraw` events will describe two exchange rates. The spread between the "Buy-in" and the "Exit" prices correspond to the fees taken by the vault. - -The following example describes how fees proportional to the deposited/withdrawn amount can be implemented: - -```solidity -include::api:example$ERC4626Fees.sol[] -``` diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc6909.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc6909.adoc deleted file mode 100644 index 164ded8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc6909.adoc +++ /dev/null @@ -1,47 +0,0 @@ -= ERC-6909 - -ERC-6909 is a draft EIP that draws on ERC-1155 learnings since it was published in 2018. The main goals of ERC-6909 is to decrease gas costs and complexity--this is mainly accomplished by removing batching and callbacks. - -TIP: To understand the inspiration for a multi token standard, see the xref:erc1155.adoc#multi-token-standard[multi token standard] section within the EIP-1155 docs. - -== Changes from ERC-1155 - -There are three main changes from ERC-1155 which are as follows: - -. The removal of batch operations. -. The removal of transfer callbacks. -. Granularization in approvals--approvals can be set globally (as operators) or as amounts per token (inspired by ERC20). - -== Constructing an ERC-6909 Token Contract - -We'll use ERC-6909 to track multiple items in a game, each having their own unique attributes. All item types will by minted to the deployer of the contract, which we can later transfer to players. We'll also use the xref:api:token/ERC6909.adoc#ERC6909Metadata[`ERC6909Metadata`] extension to add decimals to our fungible items (the vanilla ERC-6909 implementation does not have decimals). - -For simplicity, we will mint all items in the constructor--however, minting functionality could be added to the contract to mint on demand to players. - -TIP: For an overview of minting mechanisms, check out xref:erc20-supply.adoc[Creating ERC-20 Supply]. - -Here's what a contract for tokenized items might look like: - -[source,solidity] ----- -include::api:example$token/ERC6909/ERC6909GameItems.sol[] ----- - -Note that there is no content URI functionality in the base implementation, but the xref:api:token/ERC6909.adoc#ERC6909ContentURI[`ERC6909ContentURI`] extension adds it. Additionally, the base implementation does not track total supplies, but the xref:api:token/ERC6909.adoc#ERC6909TokenSupply[`ERC6909TokenSupply`] extension tracks the total supply of each token id. - -Once the contract is deployed, we will be able to query the deployer’s balance: -[source,javascript] ----- -> gameItems.balanceOf(deployerAddress, 3) -1000000000 ----- - -We can transfer items to player accounts: -[source,javascript] ----- -> gameItems.transfer(playerAddress, 2, 1) -> gameItems.balanceOf(playerAddress, 2) -1 -> gameItems.balanceOf(deployerAddress, 2) -0 ----- diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc721.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc721.adoc deleted file mode 100644 index 4b784db..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/erc721.adoc +++ /dev/null @@ -1,58 +0,0 @@ -= ERC-721 - -We've discussed how you can make a _fungible_ token using xref:erc20.adoc[ERC-20], but what if not all tokens are alike? This comes up in situations like *real estate*, *voting rights*, or *collectibles*, where some items are valued more than others, due to their usefulness, rarity, etc. ERC-721 is a standard for representing ownership of xref:tokens.adoc#different-kinds-of-tokens[_non-fungible_ tokens], that is, where each token is unique. - -ERC-721 is a more complex standard than ERC-20, with multiple optional extensions, and is split across a number of contracts. The OpenZeppelin Contracts provide flexibility regarding how these are combined, along with custom useful extensions. Check out the xref:api:token/ERC721.adoc[API Reference] to learn more about these. - -== Constructing an ERC-721 Token Contract - -We'll use ERC-721 to track items in our game, which will each have their own unique attributes. Whenever one is to be awarded to a player, it will be minted and sent to them. Players are free to keep their token or trade it with other people as they see fit, as they would any other asset on the blockchain! Please note any account can call `awardItem` to mint items. To restrict what accounts can mint items we can add xref:access-control.adoc[Access Control]. - -Here's what a contract for tokenized items might look like: - -[source,solidity] ----- -include::api:example$token/ERC721/GameItem.sol[] ----- - -The xref:api:token/ERC721.adoc#ERC721URIStorage[`ERC721URIStorage`] contract is an implementation of ERC-721 that includes the metadata standard extensions (xref:api:token/ERC721.adoc#IERC721Metadata[`IERC721Metadata`]) as well as a mechanism for per-token metadata. That's where the xref:api:token/ERC721.adoc#ERC721-_setTokenURI-uint256-string-[`_setTokenURI`] method comes from: we use it to store an item's metadata. - -Also note that, unlike ERC-20, ERC-721 lacks a `decimals` field, since each token is distinct and cannot be partitioned. - -New items can be created: - -[source,javascript] ----- -> gameItem.awardItem(playerAddress, "https://game.example/item-id-8u5h2m.json") -Transaction successful. Transaction hash: 0x... -Events emitted: - - Transfer(0x0000000000000000000000000000000000000000, playerAddress, 7) ----- - -And the owner and metadata of each item queried: - -[source,javascript] ----- -> gameItem.ownerOf(7) -playerAddress -> gameItem.tokenURI(7) -"https://game.example/item-id-8u5h2m.json" ----- - -This `tokenURI` should resolve to a JSON document that might look something like: - -[source,json] ----- -{ - "name": "Thor's hammer", - "description": "Mjölnir, the legendary hammer of the Norse god of thunder.", - "image": "https://game.example/item-id-8u5h2m.png", - "strength": 20 -} ----- - -For more information about the `tokenURI` metadata JSON Schema, check out the https://eips.ethereum.org/EIPS/eip-721[ERC-721 specification]. - -NOTE: You'll notice that the item's information is included in the metadata, but that information isn't on-chain! So a game developer could change the underlying metadata, changing the rules of the game! - -TIP: If you'd like to put all item information on-chain, you can extend ERC-721 to do so (though it will be rather costly) by providing a xref:utilities.adoc#base64[`Base64`] Data URI with the JSON schema encoded. You could also leverage IPFS to store the tokenURI information, but these techniques are out of the scope of this overview guide. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/extending-contracts.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/extending-contracts.adoc deleted file mode 100644 index 8ff4101..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/extending-contracts.adoc +++ /dev/null @@ -1,51 +0,0 @@ -= Extending Contracts - -Most of the OpenZeppelin Contracts are expected to be used via https://solidity.readthedocs.io/en/latest/contracts.html#inheritance[inheritance]: you will _inherit_ from them when writing your own contracts. - -This is the commonly found `is` syntax, like in `contract MyToken is ERC20`. - -[NOTE] -==== -Unlike ``contract``s, Solidity ``library``s are not inherited from and instead rely on the https://solidity.readthedocs.io/en/latest/contracts.html#using-for[`using for`] syntax. - -OpenZeppelin Contracts has some ``library``s: most are in the xref:api:utils.adoc[Utils] directory. -==== - -== Overriding - -Inheritance is often used to add the parent contract's functionality to your own contract, but that's not all it can do. You can also _change_ how some parts of the parent behave using _overrides_. - -For example, imagine you want to change xref:api:access.adoc#AccessControl[`AccessControl`] so that xref:api:access.adoc#AccessControl-revokeRole-bytes32-address-[`revokeRole`] can no longer be called. This can be achieved using overrides: - -```solidity -include::api:example$access-control/AccessControlModified.sol[] -``` - -The old `revokeRole` is then replaced by our override, and any calls to it will immediately revert. We cannot _remove_ the function from the contract, but reverting on all calls is good enough. - -=== Calling `super` - -Sometimes you want to _extend_ a parent's behavior, instead of outright changing it to something else. This is where `super` comes in. - -The `super` keyword will let you call functions defined in a parent contract, even if they are overridden. This mechanism can be used to add additional checks to a function, emit events, or otherwise add functionality as you see fit. - -TIP: For more information on how overrides work, head over to the https://solidity.readthedocs.io/en/latest/contracts.html#index-17[official Solidity documentation]. - -Here is a modified version of xref:api:access.adoc#AccessControl[`AccessControl`] where xref:api:access.adoc#AccessControl-revokeRole-bytes32-address-[`revokeRole`] cannot be used to revoke the `DEFAULT_ADMIN_ROLE`: - - -```solidity -include::api:example$access-control/AccessControlNonRevokableAdmin.sol[] -``` - -The `super.revokeRole` statement at the end will invoke ``AccessControl``'s original version of `revokeRole`, the same code that would've run if there were no overrides in place. - -NOTE: The same rule is implemented and extended in xref:api:access.adoc#AccessControlDefaultAdminRules[`AccessControlDefaultAdminRules`], an extension that also adds enforced security measures for the `DEFAULT_ADMIN_ROLE`. - -== Security - -The maintainers of OpenZeppelin Contracts are mainly concerned with the correctness and security of the code as published in the library, and the combinations of base contracts with the official extensions from the library. - -Custom overrides, especially to hooks, can disrupt important assumptions and may introduce security risks in the code that was previously secure. While we try to ensure the contracts remain secure in the face of a wide range of potential customizations, this is done in a best-effort manner. While we try to document all important assumptions, this should not be relied upon. Custom overrides should be carefully reviewed and checked against the source code of the contract they are customizing to fully understand their impact and guarantee their security. - -The way functions interact internally should not be assumed to stay stable across releases of the library. For example, a function that is used in one context in a particular release may not be used in the same context in the next release. Contracts that override functions should revalidate their assumptions when updating the version of OpenZeppelin Contracts they are built on. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/faq.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/faq.adoc deleted file mode 100644 index 81c34bb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/faq.adoc +++ /dev/null @@ -1,13 +0,0 @@ -= Frequently Asked Questions - -== Can I restrict a function to EOAs only? - -When calling external addresses from your contract it is unsafe to assume that an address is an externally-owned account (EOA) and not a contract. Attempting to prevent 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. - -Although checking that the address has code, `address.code.length > 0`, may seem to differentiate contracts from EOAs, it can only say that an address is currently a contract, and its negation (that an address is not currently a contract) does not imply that the address is an EOA. Some counterexamples are: - - - address of a contract in construction - - address where a contract will be created - - address where a contract lived, but was destroyed - -Furthermore, an address will be considered a contract within the same transaction where it is scheduled for destruction by `SELFDESTRUCT`, which only has an effect at the end of the entire transaction. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/governance.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/governance.adoc deleted file mode 100644 index c2b8218..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/governance.adoc +++ /dev/null @@ -1,239 +0,0 @@ -= How to set up on-chain governance - -In this guide we will learn how OpenZeppelin’s Governor contract works, how to set it up, and how to use it to create proposals, vote for them, and execute them, using tools provided by Ethers.js and Tally. - -NOTE: Find detailed contract documentation at xref:api:governance.adoc[Governance API]. - -== Introduction - -Decentralized protocols are in constant evolution from the moment they are publicly released. Often, the initial team retains control of this evolution in the first stages, but eventually delegates it to a community of stakeholders. The process by which this community makes decisions is called on-chain governance, and it has become a central component of decentralized protocols, fueling varied decisions such as parameter tweaking, smart contract upgrades, integrations with other protocols, treasury management, grants, etc. - -This governance protocol is generally implemented in a special-purpose contract called “Governor”. The GovernorAlpha and GovernorBravo contracts designed by Compound have been very successful and popular so far, with the downside that projects with different requirements have had to fork the code to customize it for their needs, which can pose a high risk of introducing security issues. For OpenZeppelin Contracts, we set out to build a modular system of Governor contracts so that forking is not needed, and different requirements can be accommodated by writing small modules using Solidity inheritance. You will find the most common requirements out of the box in OpenZeppelin Contracts, but writing additional ones is simple, and we will be adding new features as requested by the community in future releases. Additionally, the design of OpenZeppelin Governor requires minimal use of storage and results in more gas efficient operation. - -== Compatibility - -OpenZeppelin’s Governor system was designed with a concern for compatibility with existing systems that were based on Compound’s GovernorAlpha and GovernorBravo. Because of this, you will find that many modules are presented in two variants, one of which is built for compatibility with those systems. - -=== ERC20Votes & ERC20VotesComp - -The ERC-20 extension to keep track of votes and vote delegation is one such case. The shorter one is the more generic version because it can support token supplies greater than 2^96, while the “Comp” variant is limited in that regard, but exactly fits the interface of the COMP token that is used by GovernorAlpha and Bravo. Both contract variants share the same events, so they are fully compatible when looking at events only. - -=== Governor & GovernorStorage - -An OpenZeppelin Governor contract is not interface-compatible with Compound's GovernorAlpha or Bravo. Even though events are fully compatible, proposal lifecycle functions (creation, execution, etc.) have different signatures that are meant to optimize storage use. Other functions from GovernorAlpha and Bravo are likewise not available. It’s possible to opt in some Bravo-like behavior by inheriting from the GovernorStorage module. This module provides proposal enumerability and alternate versions of the `queue`, `execute` and `cancel` function that only take the proposal id. This module reduces the calldata needed by some operations in exchange for an increased storage footprint. This might be a good trade-off for some L2 chains. It also provides primitives for indexer-free frontends. - -Note that even with the use of this module, one important difference with Compound's GovernorBravo is the way that `proposalId`s are calculated. Governor uses the hash of the proposal parameters with the purpose of keeping its data off-chain by event indexing, while the original Bravo implementation uses sequential `proposalId`s. - -=== GovernorTimelockControl & GovernorTimelockCompound - -When using a timelock with your Governor contract, you can use either OpenZeppelin’s TimelockController or Compound’s Timelock. Based on the choice of timelock, you should choose the corresponding Governor module: GovernorTimelockControl or GovernorTimelockCompound respectively. This allows you to migrate an existing GovernorAlpha instance to an OpenZeppelin-based Governor without changing the timelock in use. - -=== Tally - -https://www.tally.xyz[Tally] is a full-fledged application for user owned on-chain governance. It comprises a voting dashboard, proposal creation wizard, real time research and analysis, and educational content. - -For all of these options, the Governor will be compatible with Tally: users will be able to create proposals, see voting periods and delays following xref:api:interfaces.adoc#IERC6372[IERC6372], visualize voting power and advocates, navigate proposals, and cast votes. For proposal creation in particular, projects can also use https://docs.openzeppelin.com/defender/module/actions#transaction-proposals-reference[Defender Transaction Proposals] as an alternative interface. - -In the rest of this guide, we will focus on a fresh deploy of the vanilla OpenZeppelin Governor features without concern for compatibility with GovernorAlpha or Bravo. - -== Setup - -=== Token - -The voting power of each account in our governance setup will be determined by an ERC-20 token. The token has to implement the ERC20Votes extension. This extension will keep track of historical balances so that voting power is retrieved from past snapshots rather than current balance, which is an important protection that prevents double voting. - -```solidity -include::api:example$governance/MyToken.sol[] -``` - -If your project already has a live token that does not include ERC20Votes and is not upgradeable, you can wrap it in a governance token by using ERC20Wrapper. This will allow token holders to participate in governance by wrapping their tokens 1-to-1. - -```solidity -include::api:example$governance/MyTokenWrapped.sol[] -``` - -NOTE: The only other source of voting power available in OpenZeppelin Contracts currently is xref:api:token/ERC721.adoc#ERC721Votes[`ERC721Votes`]. ERC-721 tokens that don't provide this functionality can be wrapped into a voting tokens using a combination of xref:api:token/ERC721.adoc#ERC721Votes[`ERC721Votes`] and xref:api:token/ERC721.adoc#ERC721Wrapper[`ERC721Wrapper`]. - -NOTE: The internal clock used by the token to store voting balances will dictate the operating mode of the Governor contract attached to it. By default, block numbers are used. Since v4.9, developers can override the xref:api:interfaces.adoc#IERC6372[IERC6372] clock to use timestamps instead of block numbers. - -=== Governor - -Initially, we will build a Governor without a timelock. The core logic is given by the Governor contract, but we still need to choose: 1) how voting power is determined, 2) how many votes are needed for quorum, 3) what options people have when casting a vote and how those votes are counted, and 4) what type of token should be used to vote. Each of these aspects is customizable by writing your own module, or more easily choosing one from OpenZeppelin Contracts. - -For 1) we will use the GovernorVotes module, which hooks to an IVotes instance to determine the voting power of an account based on the token balance they hold when a proposal becomes active. This module requires as a constructor parameter the address of the token. This module also discovers the clock mode (ERC-6372) used by the token and applies it to the Governor. - -For 2) we will use GovernorVotesQuorumFraction which works together with ERC20Votes to define quorum as a percentage of the total supply at the block a proposal’s voting power is retrieved. This requires a constructor parameter to set the percentage. Most Governors nowadays use 4%, so we will initialize the module with parameter 4 (this indicates the percentage, resulting in 4%). - -For 3) we will use GovernorCountingSimple, a module that offers 3 options to voters: For, Against, and Abstain, and where only For and Abstain votes are counted towards quorum. - -Besides these modules, Governor itself has some parameters we must set. - -votingDelay: How long after a proposal is created should voting power be fixed. A large voting delay gives users time to unstake tokens if necessary. - -votingPeriod: How long does a proposal remain open to votes. - -These parameters are specified in the unit defined in the token's clock. Assuming the token uses block numbers, and assuming block time of around 12 seconds, we will have set votingDelay = 1 day = 7200 blocks, and votingPeriod = 1 week = 50400 blocks. - -We can optionally set a proposal threshold as well. This restricts proposal creation to accounts that have enough voting power. - -```solidity -include::api:example$governance/MyGovernor.sol[] -``` - -=== Timelock - -It is good practice to add a timelock to governance decisions. This allows users to exit the system if they disagree with a decision before it is executed. We will use OpenZeppelin’s TimelockController in combination with the GovernorTimelockControl module. - -IMPORTANT: When using a timelock, it is the timelock that will execute proposals and thus the timelock that should hold any funds, ownership, and access control roles. Before version 4.5 there was no way to recover funds in the Governor contract when using a timelock! Before version 4.3, when using the Compound Timelock, ETH in the timelock was not easily accessible. - -TimelockController uses an AccessControl setup that we need to understand in order to set up roles. - -- The Proposer role is in charge of queueing operations: this is the role the Governor instance should be granted, and it should likely be the only proposer in the system. -- The Executor role is in charge of executing already available operations: we can assign this role to the special zero address to allow anyone to execute (if operations can be particularly time sensitive, the Governor should be made Executor instead). -- Lastly, there is the Admin role, which can grant and revoke the two previous roles: this is a very sensitive role that will be granted automatically to the timelock itself, and optionally to a second account, which can be used for ease of setup but should promptly renounce the role. - -== Proposal Lifecycle - -Let’s walk through how to create and execute a proposal on our newly deployed Governor. - -A proposal is a sequence of actions that the Governor contract will perform if it passes. Each action consists of a target address, calldata encoding a function call, and an amount of ETH to include. Additionally, a proposal includes a human-readable description. - -=== Create a Proposal - -Let’s say we want to create a proposal to give a team a grant, in the form of ERC-20 tokens from the governance treasury. This proposal will consist of a single action where the target is the ERC-20 token, calldata is the encoded function call `transfer(, )`, and with 0 ETH attached. - -Generally a proposal will be created with the help of an interface such as Tally or https://docs.openzeppelin.com/defender/module/actions#transaction-proposals-reference[Defender Proposals]. Here we will show how to create the proposal using Ethers.js. - -First we get all the parameters necessary for the proposal action. - -```javascript -const tokenAddress = ...; -const token = await ethers.getContractAt(‘ERC20’, tokenAddress); - -const teamAddress = ...; -const grantAmount = ...; -const transferCalldata = token.interface.encodeFunctionData(‘transfer’, [teamAddress, grantAmount]); -``` - -Now we are ready to call the propose function of the Governor. Note that we don’t pass in one array of actions, but instead three arrays corresponding to the list of targets, the list of values, and the list of calldatas. In this case it’s a single action, so it’s simple: - -```javascript -await governor.propose( - [tokenAddress], - [0], - [transferCalldata], - “Proposal #1: Give grant to team”, -); -``` - -This will create a new proposal, with a proposal id that is obtained by hashing together the proposal data, and which will also be found in an event in the logs of the transaction. - -=== Cast a Vote - -Once a proposal is active, delegates can cast their vote. Note that it is delegates who carry voting power: if a token holder wants to participate, they can set a trusted representative as their delegate, or they can become a delegate themselves by self-delegating their voting power. - -Votes are cast by interacting with the Governor contract through the `castVote` family of functions. Voters would generally invoke this from a governance UI such as Tally. - -image::tally-vote.png[Voting in Tally] - -=== Execute the Proposal - -Once the voting period is over, if quorum was reached (enough voting power participated) and the majority voted in favor, the proposal is considered successful and can proceed to be executed. Once a proposal passes, it can be queued and executed from the same place you voted. - -image::tally-exec.png[Administration Panel in Tally] - -We will see now how to do this manually using Ethers.js. - -If a timelock was set up, the first step to execution is queueing. You will notice that both the queue and execute functions require passing in the entire proposal parameters, as opposed to just the proposal id. This is necessary because this data is not stored on chain, as a measure to save gas. Note that these parameters can always be found in the events emitted by the contract. The only parameter that is not sent in its entirety is the description, since this is only needed in its hashed form to compute the proposal id. - -To queue, we call the queue function: - -```javascript -const descriptionHash = ethers.utils.id(“Proposal #1: Give grant to team”); - -await governor.queue( - [tokenAddress], - [0], - [transferCalldata], - descriptionHash, -); -``` - -This will cause the Governor to interact with the timelock contract and queue the actions for execution after the required delay. - -After enough time has passed (according to the timelock parameters), the proposal can be executed. If there was no timelock to begin with, this step can be ran immediately after the proposal succeeds. - -```javascript -await governor.execute( - [tokenAddress], - [0], - [transferCalldata], - descriptionHash, -); -``` - -Executing the proposal will transfer the ERC-20 tokens to the chosen recipient. To wrap up: we set up a system where a treasury is controlled by the collective decision of the token holders of a project, and all actions are executed via proposals enforced by on-chain votes. - -== Timestamp based governance - -=== Motivation - -It is sometimes difficult to deal with durations expressed in number of blocks because of inconsistent or unpredictable time between blocks. This is particularly true of some L2 networks where blocks are produced based on blockchain usage. Using number of blocks can also lead to the governance rules being affected by network upgrades that modify the expected time between blocks. - -The difficulty of replacing block numbers with timestamps is that the Governor and the token must both use the same format when querying past votes. If a token is designed around block numbers, it is not possible for a Governor to reliably do timestamp based lookups. - -Therefore, designing a timestamp based voting system starts with the token. - -=== Token - -Since v4.9, all voting contracts (including xref:api:token/ERC20.adoc#ERC20Votes[`ERC20Votes`] and xref:api:token/ERC721.adoc#ERC721Votes[`ERC721Votes`]) rely on xref:api:interfaces.adoc#IERC6372[IERC6372] for clock management. In order to change from operating with block numbers to operating with timestamps, all that is required is to override the `clock()` and `CLOCK_MODE()` functions. - -```solidity -include::api:example$governance/MyTokenTimestampBased.sol[] -``` - -=== Governor - -The Governor will automatically detect the clock mode used by the token and adapt to it. There is no need to override anything in the Governor contract. However, the clock mode does affect how some values are interpreted. It is therefore necessary to set the `votingDelay()` and `votingPeriod()` accordingly. - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {Governor} from "@openzeppelin/contracts/governance/Governor.sol"; -import {GovernorCountingSimple} from "@openzeppelin/contracts/governance/compatibility/GovernorCountingSimple.sol"; -import {GovernorVotes} from "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol"; -import {GovernorVotesQuorumFraction} from "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol"; -import {GovernorTimelockControl} from "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol"; -import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol"; -import {IVotes} from "@openzeppelin/contracts/governance/utils/IVotes.sol"; - -contract MyGovernor is Governor, GovernorCountingSimple, GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl { - constructor(IVotes _token, TimelockController _timelock) - Governor("MyGovernor") - GovernorVotes(_token) - GovernorVotesQuorumFraction(4) - GovernorTimelockControl(_timelock) - {} - - function votingDelay() public pure virtual override returns (uint256) { - return 1 days; - } - - function votingPeriod() public pure virtual override returns (uint256) { - return 1 weeks; - } - - function proposalThreshold() public pure virtual override returns (uint256) { - return 0; - } - - // ... -} -``` - -=== Disclaimer - -Timestamp based voting is a recent feature that was formalized in ERC-6372 and ERC-5805, and introduced in v4.9. At the time this feature is released, some governance tooling may not support it yet. Users can expect invalid reporting of deadlines & durations if the tool is not able to interpret the ERC6372 clock. This invalid reporting by offchain tools does not affect the onchain security and functionality of the governance contract. - -Governors with timestamp support (v4.9 and above) are compatible with old tokens (before v4.9) and will operate in "block number" mode (which is the mode all old tokens operate on). On the other hand, old Governor instances (before v4.9) are not compatible with new tokens operating using timestamps. If you update your token code to use timestamps, make sure to also update your Governor code. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/index.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/index.adoc deleted file mode 100644 index 3c8e57e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/index.adoc +++ /dev/null @@ -1,70 +0,0 @@ -= Contracts - -*A library for secure smart contract development.* Build on a solid foundation of community-vetted code. - - * Implementations of standards like xref:erc20.adoc[ERC20] and xref:erc721.adoc[ERC721]. - * Flexible xref:access-control.adoc[role-based permissioning] scheme. - * Reusable xref:utilities.adoc[Solidity components] to build custom contracts and complex decentralized systems. - -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 xref:backwards-compatibility.adoc[Backwards Compatibility]. - -== Overview - -[[install]] -=== Installation - -==== Hardhat (npm) - -```console -$ 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. - -```console -$ forge install OpenZeppelin/openzeppelin-contracts -``` - -Add `@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/` in `remappings.txt.` - -[[usage]] -=== Usage - -Once installed, you can use the contracts in the library by importing them: - -[source,solidity] ----- -include::api:example$MyNFT.sol[] ----- - -TIP: If you're new to smart contract development, head to xref:learn::developing-smart-contracts.adoc[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. - -[[security]] -== Security - -Please report any security issues you find via our https://www.immunefi.com/bounty/openzeppelin[bug bounty program on Immunefi] or directly to security@openzeppelin.org. - -The https://contracts.openzeppelin.com/security[Security Center] contains more details about the secure development process. - -[[next-steps]] -== Learn More - -The guides in the sidebar will teach about different concepts, and how to use the related contracts that OpenZeppelin Contracts provides: - -* xref:access-control.adoc[Access Control]: decide who can perform each of the actions on your system. -* xref:tokens.adoc[Tokens]: create tradable assets or collectibles, like the well known xref:erc20.adoc[ERC20] and xref:erc721.adoc[ERC721] standards. -* xref:utilities.adoc[Utilities]: generic useful tools, including non-overflowing math, signature verification, and trustless paying systems. - -The xref:api:token/ERC20.adoc[full API] 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' development in the https://forum.openzeppelin.com[community forum]. - -The following articles provide great background reading, though please note, some of the referenced tools have changed as the tooling in the ecosystem continues to rapidly evolve. - -* https://blog.openzeppelin.com/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05[The Hitchhiker’s Guide to Smart Contracts in Ethereum] will help you get an overview of the various tools available for smart contract development, and help you set up your environment. -* https://blog.openzeppelin.com/a-gentle-introduction-to-ethereum-programming-part-1-783cc7796094[A Gentle Introduction to Ethereum Programming, Part 1] 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 https://blog.openzeppelin.com/designing-the-architecture-for-your-ethereum-application-9cec086f8317[Designing the architecture for your Ethereum application], which discusses how to better structure your application and its relationship to the real world. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/multisig.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/multisig.adoc deleted file mode 100644 index b44406b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/multisig.adoc +++ /dev/null @@ -1,306 +0,0 @@ -= Multisig Account - -A multi-signature (multisig) account is a smart account that requires multiple authorized signers to approve operations before execution. Unlike traditional accounts controlled by a single private key, multisigs distribute control among multiple parties, eliminating single points of failure. For example, a 2-of-3 multisig requires signatures from at least 2 out of 3 possible signers. - -Popular implementations like https://safe.global/[Safe] (formerly Gnosis Safe) have become the standard for securing valuable assets. Multisigs provide enhanced security through collective authorization, customizable controls for ownership and thresholds, and the ability to rotate signers without changing the account address. - -== Beyond Standard Signature Verification - -As discussed in the xref:accounts.adoc#signature_validation[accounts section], the standard approach for smart contracts to verify signatures is https://eips.ethereum.org/EIPS/eip-1271[ERC-1271], which defines an `isValidSignature(hash, signature)`. However, it is limited in two important ways: - -1. It assumes the signer has an EVM address -2. It treats the signer as a single identity - -This becomes problematic when implementing multisig accounts where: - -* You may want to use signers that don't have EVM addresses (like keys from hardware devices) -* Each signer needs to be individually verified rather than treated as a collective identity -* You need a threshold system to determine when enough valid signatures are present - -The https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol[SignatureChecker] library is useful for verifying EOA and ERC-1271 signatures, but it's not designed for more complex arrangements like threshold-based multisigs. - -== ERC-7913 Signers - -https://eips.ethereum.org/EIPS/eip-7913[ERC-7913] extends the concept of signer representation to include keys that don't have EVM addresses, addressing this limitation. OpenZeppelin implements this standard through three contracts: - -=== SignerERC7913 - -The xref:api:utils.adoc#SignerERC7913[`SignerERC7913`] contract allows a single ERC-7913 formatted signer to control an account. The signer is represented as a `bytes` object that concatenates a verifier address and a key: `verifier || key`. - -[source,solidity] ----- -// contracts/MyAccountERC7913.sol -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -import {Account} from "@openzeppelin/community-contracts/account/Account.sol"; -import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; -import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; -import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; -import {ERC7739} from "@openzeppelin/community-contracts/utils/cryptography/signers/ERC7739.sol"; -import {ERC7821} from "@openzeppelin/community-contracts/account/extensions/ERC7821.sol"; -import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; -import {SignerERC7913} from "@openzeppelin/community-contracts/utils/cryptography/signers/SignerERC7913.sol"; - -contract MyAccountERC7913 is Account, SignerERC7913, ERC7739, ERC7821, ERC721Holder, ERC1155Holder, Initializable { - constructor() EIP712("MyAccount7913", "1") {} - - function initialize(bytes memory signer) public initializer { - _setSigner(signer); - } - - function setSigner(bytes memory signer) public onlyEntryPointOrSelf { - _setSigner(signer); - } - - /// @dev Allows the entry point as an authorized executor. - function _erc7821AuthorizedExecutor( - address caller, - bytes32 mode, - bytes calldata executionData - ) internal view virtual override returns (bool) { - return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); - } -} ----- - -WARNING: Leaving an account uninitialized may leave it unusable since no public key was associated with it. - -=== MultiSignerERC7913 - -The xref:api:utils/cryptography.adoc#MultiSignerERC7913[`MultiSignerERC7913`] contract extends this concept to support multiple signers with a threshold-based signature verification system. - -[source,solidity] ----- -// contracts/MyAccountMultiSigner.sol -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.27; - -import {Account} from "@openzeppelin/community-contracts/account/Account.sol"; -import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; -import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; -import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; -import {ERC7739} from "@openzeppelin/community-contracts/utils/cryptography/signers/ERC7739.sol"; -import {ERC7821} from "@openzeppelin/community-contracts/account/extensions/ERC7821.sol"; -import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; -import {MultiSignerERC7913} from "@openzeppelin/community-contracts/utils/cryptography/signers/MultiSignerERC7913.sol"; - -contract MyAccountMultiSigner is - Account, - MultiSignerERC7913, - ERC7739, - ERC7821, - ERC721Holder, - ERC1155Holder, - Initializable -{ - constructor() EIP712("MyAccountMultiSigner", "1") {} - - function initialize(bytes[] memory signers, uint256 threshold) public initializer { - _addSigners(signers); - _setThreshold(threshold); - } - - function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf { - _addSigners(signers); - } - - function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf { - _removeSigners(signers); - } - - function setThreshold(uint256 threshold) public onlyEntryPointOrSelf { - _setThreshold(threshold); - } - - /// @dev Allows the entry point as an authorized executor. - function _erc7821AuthorizedExecutor( - address caller, - bytes32 mode, - bytes calldata executionData - ) internal view virtual override returns (bool) { - return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); - } -} ----- - -This implementation is ideal for standard multisig setups where each signer has equal authority, and a fixed number of approvals is required. - -The `MultiSignerERC7913` contract provides several key features for managing multi-signature accounts. It maintains a set of authorized signers and implements a threshold-based system that requires a minimum number of signatures to approve operations. The contract includes an internal interface for managing signers, allowing for the addition and removal of authorized parties. - -NOTE: `MultiSignerERC7913` safeguards to ensure that the threshold remains achievable based on the current number of active signers, preventing situations where operations could become impossible to execute. - -The contract also provides public functions for querying signer information: xref:api:utils/cryptography.adoc#MultiSignerERC7913-isSigner-bytes-[`isSigner(bytes memory signer)`] to check if a given signer is authorized, xref:api:utils/cryptography.adoc#MultiSignerERC7913-getSigners-uint64-uint64-[`getSigners(uint64 start, uint64 end)`] to retrieve a paginated list of authorized signers, and xref:api:utils/cryptography.adoc#MultiSignerERC7913-getSignerCount[`getSignerCount()`] to get the total number of signers. These functions are useful when validating signatures, implementing customized access control logic, or building user interfaces that need to display signer information. - -=== MultiSignerERC7913Weighted - -For more sophisticated governance structures, the xref:api:utils/cryptography.adoc#MultiSignerERC7913Weighted[`MultiSignerERC7913Weighted`] contract extends `MultiSignerERC7913` by assigning different weights to each signer. - -[source,solidity] ----- -// contracts/MyAccountMultiSignerWeighted.sol -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.27; - -import {Account} from "@openzeppelin/community-contracts/account/Account.sol"; -import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; -import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; -import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; -import {ERC7739} from "@openzeppelin/community-contracts/utils/cryptography/signers/ERC7739.sol"; -import {ERC7821} from "@openzeppelin/community-contracts/account/extensions/ERC7821.sol"; -import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; -import {MultiSignerERC7913Weighted} from "@openzeppelin/community-contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol"; - -contract MyAccountMultiSignerWeighted is - Account, - MultiSignerERC7913Weighted, - ERC7739, - ERC7821, - ERC721Holder, - ERC1155Holder, - Initializable -{ - constructor() EIP712("MyAccountMultiSignerWeighted", "1") {} - - function initialize(bytes[] memory signers, uint256[] memory weights, uint256 threshold) public initializer { - _addSigners(signers); - _setSignerWeights(signers, weights); - _setThreshold(threshold); - } - - function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf { - _addSigners(signers); - } - - function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf { - _removeSigners(signers); - } - - function setThreshold(uint256 threshold) public onlyEntryPointOrSelf { - _setThreshold(threshold); - } - - function setSignerWeights(bytes[] memory signers, uint256[] memory weights) public onlyEntryPointOrSelf { - _setSignerWeights(signers, weights); - } - - /// @dev Allows the entry point as an authorized executor. - function _erc7821AuthorizedExecutor( - address caller, - bytes32 mode, - bytes calldata executionData - ) internal view virtual override returns (bool) { - return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); - } -} ----- - -This implementation is perfect for scenarios where different signers should have varying levels of authority, such as: - -* Board members with different voting powers -* Organizational structures with hierarchical decision-making -* Hybrid governance systems combining core team and community members -* Execution setups like "social recovery" where you trust particular guardians more than others - -The `MultiSignerERC7913Weighted` contract extends `MultiSignerERC7913` with a weighting system. Each signer can have a custom weight, and operations require the total weight of signing participants to meet or exceed the threshold. Signers without explicit weights default to a weight of 1. - -NOTE: When setting up a weighted multisig, ensure the threshold value matches the scale used for signer weights. For example, if signers have weights like 1, 2, or 3, then a threshold of 4 would require at least two signers (e.g., one with weight 1 and one with weight 3). - -== Setting Up a Multisig Account - -To create a multisig account, you need to: - -1. Define your signers -2. Determine your threshold -3. Initialize your account with these parameters - -The example below demonstrates setting up a 2-of-3 multisig account with different types of signers: - -[source,solidity] ----- -// Example setup code -function setupMultisigAccount() external { - // Create signers using different types of keys - bytes memory ecdsaSigner = alice; // EOA address (20 bytes) - - // P256 signer with format: verifier || pubKey - bytes memory p256Signer = abi.encodePacked( - p256Verifier, - bobP256PublicKeyX, - bobP256PublicKeyY - ); - - // RSA signer with format: verifier || pubKey - bytes memory rsaSigner = abi.encodePacked( - rsaVerifier, - abi.encode(charlieRSAPublicKeyE, charlieRSAPublicKeyN) - ); - - // Create array of signers - bytes[] memory signers = new bytes[](3); - signers[0] = ecdsaSigner; - signers[1] = p256Signer; - signers[2] = rsaSigner; - - // Set threshold to 2 (2-of-3 multisig) - uint256 threshold = 2; - - // Initialize the account - myMultisigAccount.initialize(signers, threshold); -} ----- - -For a weighted multisig, you would also specify weights: - -[source,solidity] ----- -// Example setup for weighted multisig -function setupWeightedMultisigAccount() external { - // Create array of signers (same as above) - bytes[] memory signers = new bytes[](3); - signers[0] = ecdsaSigner; - signers[1] = p256Signer; - signers[2] = rsaSigner; - - // Assign weights to signers (Alice:1, Bob:2, Charlie:3) - uint256[] memory weights = new uint256[](3); - weights[0] = 1; - weights[1] = 2; - weights[2] = 3; - - // Set threshold to 4 (requires at least Bob+Charlie or all three) - uint256 threshold = 4; - - // Initialize the weighted account - myWeightedMultisigAccount.initialize(signers, weights, threshold); -} ----- - -IMPORTANT: The xref:api:utils/cryptography.adoc#MultiSignerERC7913-_validateReachableThreshold--[`_validateReachableThreshold`] function ensures that the sum of weights for all active signers meets or exceeds the threshold. Any customization built on top of the multisigner contracts must ensure the threshold is always reachable. - -For multisig accounts, the signature is a complex structure that contains both the signers and their individual signatures. The format follows ERC-7913's specification and must be properly encoded. - -=== Signature Format - -The multisig signature is encoded as: - -[source,solidity] ----- -abi.encode( - bytes[] signers, // Array of signers sorted by `keccak256` - bytes[] signatures // Array of signatures corresponding to each signer -) ----- - -Where: - -* `signers` is an array of the signers participating in this particular signature -* `signatures` is an array of the individual signatures corresponding to each signer - -[NOTE] -==== -To avoid duplicate signers, the contract uses `keccak256` to generate a unique id for each signer. When providing a multisignature, the `signers` array should be sorted in ascending order by `keccak256`, and the `signatures` array must match the order of their corresponding signers. -==== diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/tokens.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/tokens.adoc deleted file mode 100644 index 217c5e0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/tokens.adoc +++ /dev/null @@ -1,31 +0,0 @@ -= Tokens - -Ah, the "token": blockchain's most powerful and most misunderstood tool. - -A token is a _representation of something in the blockchain_. This something can be money, time, services, shares in a company, a virtual pet, anything. By representing things as tokens, we can allow smart contracts to interact with them, exchange them, create or destroy them. - -[[but_first_coffee_a_primer_on_token_contracts]] -== But First, [strikethrough]#Coffee# a Primer on Token Contracts - -Much of the confusion surrounding tokens comes from two concepts getting mixed up: _token contracts_ and the actual _tokens_. - -A _token contract_ is simply an Ethereum smart contract. "Sending tokens" actually means "calling a method on a smart contract that someone wrote and deployed". At the end of the day, a token contract is not much more than a mapping of addresses to balances, plus some methods to add and subtract from those balances. - -It is these balances that represent the _tokens_ themselves. Someone "has tokens" when their balance in the token contract is non-zero. That's it! These balances could be considered money, experience points in a game, deeds of ownership, or voting rights, and each of these tokens would be stored in different token contracts. - -[[different-kinds-of-tokens]] -== Different Kinds of Tokens - -Note that there's a big difference between having two voting rights and two deeds of ownership: each vote is equal to all others, but houses usually are not! This is called https://en.wikipedia.org/wiki/Fungibility[fungibility]. _Fungible goods_ are equivalent and interchangeable, like Ether, fiat currencies, and voting rights. _Non-fungible_ goods are unique and distinct, like deeds of ownership, or collectibles. - -In a nutshell, when dealing with non-fungibles (like your house) you care about _which ones_ you have, while in fungible assets (like your bank account statement) what matters is _how much_ you have. - -== Standards - -Even though the concept of a token is simple, they have a variety of complexities in the implementation. Because everything in Ethereum is just a smart contract, and there are no rules about what smart contracts have to do, the community has developed a variety of *standards* (called EIPs or ERCs) for documenting how a contract can interoperate with other contracts. - -You've probably heard of the ERC-20 or ERC-721 token standards, and that's why you're here. Head to our specialized guides to learn more about these: - - * xref:erc20.adoc[ERC-20]: the most widespread token standard for fungible assets, albeit somewhat limited by its simplicity. - * xref:erc721.adoc[ERC-721]: the de-facto solution for non-fungible tokens, often used for collectibles and games. - * xref:erc1155.adoc[ERC-1155]: a novel standard for multi-tokens, allowing for a single contract to represent multiple fungible and non-fungible tokens, along with batched operations for increased gas efficiency. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/upgradeable.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/upgradeable.adoc deleted file mode 100644 index 6d252d8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/upgradeable.adoc +++ /dev/null @@ -1,77 +0,0 @@ -= Using with Upgrades - -If your contract is going to be deployed with upgradeability, such as using the xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins], you will need to use the Upgradeable variant of OpenZeppelin Contracts. - -This variant is available as a separate package called `@openzeppelin/contracts-upgradeable`, which is hosted in the repository https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable[OpenZeppelin/openzeppelin-contracts-upgradeable]. It uses `@openzeppelin/contracts` as a peer dependency. - -It follows all of the rules for xref:upgrades-plugins::writing-upgradeable.adoc[Writing Upgradeable Contracts]: constructors are replaced by initializer functions, state variables are initialized in initializer functions, and we additionally check for storage incompatibilities across minor versions. - -TIP: OpenZeppelin provides a full suite of tools for deploying and securing upgradeable smart contracts. xref:openzeppelin::upgrades.adoc[Check out the full list of resources]. - -== Overview - -=== Installation - -```console -$ npm install @openzeppelin/contracts-upgradeable @openzeppelin/contracts -``` - -=== Usage - -The Upgradeable package replicates the structure of the main OpenZeppelin Contracts package, but every file and contract has the suffix `Upgradeable`. - -```diff --import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -+import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; - --contract MyCollectible is ERC721 { -+contract MyCollectible is ERC721Upgradeable { -``` - -NOTE: Interfaces and libraries are not included in the Upgradeable package, but are instead imported from the main OpenZeppelin Contracts package. - -Constructors are replaced by internal initializer functions following the naming convention `+__{ContractName}_init+`. Since these are internal, you must always define your own public initializer function and call the parent initializer of the contract you extend. - -```diff -- constructor() ERC721("MyCollectible", "MCO") public { -+ function initialize() initializer public { -+ __ERC721_init("MyCollectible", "MCO"); - } -``` - -CAUTION: Use with multiple inheritance requires special attention. See the section below titled <>. - -Once this contract is set up and compiled, you can deploy it using the xref:upgrades-plugins::index.adoc[Upgrades Plugins]. The following snippet shows an example deployment script using Hardhat. - -```js -// scripts/deploy-my-collectible.js -const { ethers, upgrades } = require("hardhat"); - -async function main() { - const MyCollectible = await ethers.getContractFactory("MyCollectible"); - - const mc = await upgrades.deployProxy(MyCollectible); - - await mc.waitForDeployment(); - console.log("MyCollectible deployed to:", await mc.getAddress()); -} - -main(); -``` - -== Further Notes - -[[multiple-inheritance]] -=== Multiple Inheritance - -Initializer functions are not linearized by the compiler like constructors. Because of this, each `+__{ContractName}_init+` function embeds the linearized calls to all parent initializers. As a consequence, calling two of these `init` functions can potentially initialize the same contract twice. - -The function `+__{ContractName}_init_unchained+` found in every contract is the initializer function minus the calls to parent initializers, and can be used to avoid the double initialization problem, but doing this manually is not recommended. We hope to be able to implement safety checks for this in future versions of the Upgrades Plugins. - -=== Namespaced Storage - -You may notice that contracts use a struct with the `@custom:storage-location erc7201:` annotation to store the contract's state variables. This follows the https://eips.ethereum.org/EIPS/eip-7201[ERC-7201: Namespaced Storage Layout] pattern, where each contract has its own storage layout in a namespace that is separate from other contracts in the inheritance chain. - -Without namespaced storage, it isn't safe to simply add a state variable because it "shifts down" all of the state variables below in the inheritance chain. This makes the storage layouts incompatible, as explained in xref:upgrades-plugins::writing-upgradeable.adoc#modifying-your-contracts[Writing Upgradeable Contracts]. - -The namespaced storage pattern used in the Upgradeable package allows us to freely add new state variables in the future without compromising the storage compatibility with existing deployments. It also allows changing the inheritance order with no impact on the resulting storage layout, as long as all inherited contracts use namespaced storage. \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/utilities.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/utilities.adoc deleted file mode 100644 index a248a0a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/utilities.adoc +++ /dev/null @@ -1,559 +0,0 @@ -= Utilities - -The OpenZeppelin Contracts provide a ton of useful utilities that you can use in your project. For a complete list, check out the xref:api:utils.adoc[API Reference]. -Here are some of the more popular ones. - -[[cryptography]] -== Cryptography - -=== Checking Signatures On-Chain - -At a high level, signatures are a set of cryptographic algorithms that allow for a _signer_ to prove himself owner of a _private key_ used to authorize a piece of information (generally a transaction or `UserOperation`). Natively, the EVM supports the Elliptic Curve Digital Signature Algorithm (https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm[ECDSA]) using the secp256k1 curve, however other signature algorithms such as P256 and RSA are supported. - -==== Ethereum Signatures (secp256k1) - -xref:api:utils/cryptography.adoc#ECDSA[`ECDSA`] provides functions for recovering and managing Ethereum account ECDSA signatures. These are often generated via https://web3js.readthedocs.io/en/v1.7.3/web3-eth.html#sign[`web3.eth.sign`], and form a 65-byte array (of type `bytes` in Solidity) arranged the following way: `[[v (1)], [r (32)], [s (32)]]`. - -The data signer can be recovered with xref:api:utils/cryptography.adoc#ECDSA-recover-bytes32-bytes-[`ECDSA.recover`], and its address compared to verify the signature. Most wallets will hash the data to sign and add the prefix `\x19Ethereum Signed Message:\n`, so when attempting to recover the signer of an Ethereum signed message hash, you'll want to use xref:api:utils/cryptography.adoc#MessageHashUtils-toEthSignedMessageHash-bytes32-[`toEthSignedMessageHash`]. - -[source,solidity] ----- -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; -} ----- - -WARNING: Getting signature verification right is not trivial: make sure you fully read and understand xref:api:utils/cryptography.adoc#MessageHashUtils[`MessageHashUtils`]'s and xref:api:utils/cryptography.adoc#ECDSA[`ECDSA`]'s documentation. - -==== P256 Signatures (secp256r1) - -P256, also known as secp256r1, is one of the most used signature schemes. P256 signatures are standardized by the National Institute of Standards and Technology (NIST) and they are widely available in consumer hardware and software. - -These signatures are different from regular Ethereum Signatures (secp256k1) in that they use a different elliptic curve to perform operations but have similar security guarantees. - -[source,solidity] ----- -using P256 for bytes32; - -function _verify( - bytes32 data, - bytes32 r, - bytes32 s, - bytes32 qx, - bytes32 qy -) internal pure returns (bool) { - return data.verify(data, r, s, qx, qy); -} ----- - -By default, the `verify` function will try calling the https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md[RIP-7212] precompile at address `0x100` and will fallback to an implementation in Solidity if not available. We encourage you to use `verifyNative` if you know the precompile is available on the chain you're working on and on any other chain on which you intend to use the same bytecode in the future. In case of any doubts regarding the implementation roadmap of the native precompile `P256` of potential future target chains, please consider using `verifySolidity`. - -[source,solidity] ----- -using P256 for bytes32; - -function _verify( - bytes32 data, - bytes32 r, - bytes32 s, - bytes32 qx, - bytes32 qy -) internal pure returns (bool) { - // Will only call the precompile at address(0x100) - return data.verifyNative(data, r, s, qx, qy); -} ----- - -IMPORTANT: The P256 library only allows for `s` values in the lower order of the curve (i.e. `s <= N/2`) to prevent malleability. In case your tooling produces signatures in both sides of the curve, consider flipping the `s` value to keep compatibility. - -==== RSA - -RSA is a public-key cryptosystem that was popularized by corporate and governmental public key infrastructures (https://en.wikipedia.org/wiki/Public_key_infrastructure[PKIs]) and https://en.wikipedia.org/wiki/Domain_Name_System_Security_Extensions[DNSSEC]. - -This cryptosystem consists of using a private key that's the product of 2 large prime numbers. The message is signed by applying a modular exponentiation to its hash (commonly SHA256), where both the exponent and modulus compose the public key of the signer. - -RSA signatures are known for being less efficient than elliptic curve signatures given the size of the keys, which are big compared to ECDSA keys with the same security level. Using plain RSA is considered unsafe, this is why the implementation uses the `EMSA-PKCS1-v1_5` encoding method from https://datatracker.ietf.org/doc/html/rfc8017[RFC8017] to include padding to the signature. - -To verify a signature using RSA, you can leverage the xref:api:utils/cryptography.adoc#RSA[`RSA`] library that exposes a method for verifying RSA with the PKCS 1.5 standard: - -[source,solidity] ----- -using RSA for bytes32; - -function _verify( - bytes32 data, - bytes memory signature, - bytes memory e, - bytes memory n -) internal pure returns (bool) { - return data.pkcs1Sha256(signature, e, n); -} ----- - -IMPORTANT: Always use keys of at least 2048 bits. Additionally, be aware that PKCS#1 v1.5 allows for replayability due to the possibility of arbitrary optional parameters. To prevent replay attacks, consider including an onchain nonce or unique identifier in the message. - -=== Signature Verification - -The xref:api:utils/cryptography.adoc#SignatureChecker[`SignatureChecker`] library provides a unified interface for verifying signatures from different sources. It seamlessly supports: - -* ECDSA signatures from externally owned accounts (EOAs) -* ERC-1271 signatures from smart contract wallets like Argent and Safe Wallet -* ERC-7913 signatures from keys that don't have their own Ethereum address - -This allows developers to write signature verification code once and have it work across all these different signature types. - -==== Basic Signature Verification - -For standard signature verification that supports both EOAs and ERC-1271 contracts: - -[source,solidity] ----- -using SignatureChecker for address; - -function _verifySignature(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { - return SignatureChecker.isValidSignatureNow(signer, hash, signature); -} ----- - -The library automatically detects whether the signer is an EOA or a contract and uses the appropriate verification method. - -==== ERC-1271 Contract Signatures - -For smart contract wallets that implement ERC-1271, you can explicitly use: - -[source,solidity] ----- -function _verifyContractSignature(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { - return SignatureChecker.isValidERC1271SignatureNow(signer, hash, signature); -} ----- - -==== ERC-7913 Extended Signatures - -ERC-7913 extends signature verification to support keys that don't have their own Ethereum address. This is useful for integrating non-Ethereum cryptographic curves, hardware devices, or other identity systems. - -A signer is represented as a `bytes` object that concatenates a verifier address and a key: `verifier || key`. - -[source,solidity] ----- -function _verifyERC7913Signature(bytes memory signer, bytes32 hash, bytes memory signature) internal view returns (bool) { - return SignatureChecker.isValidSignatureNow(signer, hash, signature); -} ----- - -The verification process works as follows: - -* If `signer.length < 20`: verification fails -* If `signer.length == 20`: verification is done using standard signature checking -* Otherwise: verification is done using an ERC-7913 verifier - -==== Batch Verification - -For verifying multiple ERC-7913 signatures at once: - -[source,solidity] ----- -function _verifyMultipleSignatures( - bytes32 hash, - bytes[] memory signers, - bytes[] memory signatures -) internal view returns (bool) { - return SignatureChecker.areValidSignaturesNow(hash, signers, signatures); -} ----- - -This function will reject inputs that contain duplicated signers. Sorting the signers by their `keccak256` hash is recommended to minimize the gas cost. - -This unified approach allows smart contracts to accept signatures from any supported source without needing to implement different verification logic for each type. - -=== Verifying Merkle Proofs - -Developers can build a Merkle Tree off-chain, which allows for verifying that an element (leaf) is part of a set by using a Merkle Proof. This technique is widely used for creating whitelists (e.g., for airdrops) and other advanced use cases. - -TIP: OpenZeppelin Contracts provides a https://github.com/OpenZeppelin/merkle-tree[JavaScript library] for building trees off-chain and generating proofs. - -xref:api:utils/cryptography.adoc#MerkleProof[`MerkleProof`] provides: - -* xref:api:utils/cryptography.adoc#MerkleProof-verify-bytes32---bytes32-bytes32-[`verify`] - can prove that some value is part of a https://en.wikipedia.org/wiki/Merkle_tree[Merkle tree]. - -* xref:api:utils/cryptography.adoc#MerkleProof-multiProofVerify-bytes32-bytes32---bytes32---bool---[`multiProofVerify`] - can prove multiple values are part of a Merkle tree. - -For an on-chain Merkle Tree, see the xref:api:utils.adoc#MerkleTree[`MerkleTree`] library. - -[[introspection]] -== Introspection - -In Solidity, it's frequently helpful to know whether or not a contract supports an interface you'd like to use. ERC-165 is a standard that helps do runtime interface detection. Contracts provide helpers both for implementing ERC-165 in your contracts and querying other contracts: - -* xref:api:utils.adoc#IERC165[`IERC165`] — this is the ERC-165 interface that defines xref:api:utils.adoc#IERC165-supportsInterface-bytes4-[`supportsInterface`]. When implementing ERC-165, you'll conform to this interface. -* xref:api:utils.adoc#ERC165[`ERC165`] — inherit this contract if you'd like to support interface detection using a lookup table in contract storage. You can register interfaces using xref:api:utils.adoc#ERC165-_registerInterface-bytes4-[`_registerInterface(bytes4)`]: check out example usage as part of the ERC-721 implementation. -* xref:api:utils.adoc#ERC165Checker[`ERC165Checker`] — ERC165Checker simplifies the process of checking whether or not a contract supports an interface you care about. -* include with `using ERC165Checker for address;` -* xref:api:utils.adoc#ERC165Checker-_supportsInterface-address-bytes4-[`myAddress._supportsInterface(bytes4)`] -* xref:api:utils.adoc#ERC165Checker-_supportsAllInterfaces-address-bytes4---[`myAddress._supportsAllInterfaces(bytes4[\])`] - -[source,solidity] ----- -contract MyContract { - using ERC165Checker for address; - - bytes4 private InterfaceId_ERC721 = 0x80ac58cd; - - /** - * @dev transfer an ERC-721 token from this contract to someone else - */ - function transferERC721( - address token, - address to, - uint256 tokenId - ) - public - { - require(token.supportsInterface(InterfaceId_ERC721), "IS_NOT_721_TOKEN"); - IERC721(token).transferFrom(address(this), to, tokenId); - } -} ----- - -[[math]] -== Math - -Although Solidity already provides math operators (i.e. `+`, `-`, etc.), Contracts includes xref:api:utils.adoc#Math[`Math`]; a set of utilities for dealing with mathematical operators, with support for extra operations (e.g., xref:api:utils.adoc#Math-average-uint256-uint256-[`average`]) and xref:api:utils.adoc#SignedMath[`SignedMath`]; a library specialized in signed math operations. - -Include these contracts with `using Math for uint256` or `using SignedMath for int256` and then use their functions in your code: - -[source,solidity] ----- -contract MyContract { - using Math for uint256; - using SignedMath for int256; - - function tryOperations(uint256 a, uint256 b) internal pure { - (bool succeededAdd, uint256 resultAdd) = x.tryAdd(y); - (bool succeededSub, uint256 resultSub) = x.trySub(y); - (bool succeededMul, uint256 resultMul) = x.tryMul(y); - (bool succeededDiv, uint256 resultDiv) = x.tryDiv(y); - // ... - } - - function unsignedAverage(int256 a, int256 b) { - int256 avg = a.average(b); - // ... - } -} ----- - -Easy! - -TIP: While working with different data types that might require casting, you can use xref:api:utils.adoc#SafeCast[`SafeCast`] for type casting with added overflow checks. - -[[structures]] -== Structures - -Some use cases require more powerful data structures than arrays and mappings offered natively in Solidity. Contracts provides these libraries for enhanced data structure management: - -- xref:api:utils.adoc#BitMaps[`BitMaps`]: Store packed booleans in storage. -- xref:api:utils.adoc#Checkpoints[`Checkpoints`]: Checkpoint values with built-in lookups. -- xref:api:utils.adoc#DoubleEndedQueue[`DoubleEndedQueue`]: Store items in a queue with `pop()` and `queue()` constant time operations. -- xref:api:utils.adoc#EnumerableSet[`EnumerableSet`]: A https://en.wikipedia.org/wiki/Set_(abstract_data_type)[set] with enumeration capabilities. -- xref:api:utils.adoc#EnumerableMap[`EnumerableMap`]: A `mapping` variant with enumeration capabilities. -- xref:api:utils.adoc#MerkleTree[`MerkleTree`]: An on-chain https://wikipedia.org/wiki/Merkle_Tree[Merkle Tree] with helper functions. -- xref:api:utils.adoc#Heap.sol[`Heap`]: A - -The `Enumerable*` structures are similar to mappings in that they store and remove elements in constant time and don't allow for repeated entries, but they also support _enumeration_, which means you can easily query all stored entries both on and off-chain. - -=== Building a Merkle Tree - -Building an on-chain Merkle Tree allows developers to keep track of the history of roots in a decentralized manner. For these cases, the xref:api:utils.adoc#MerkleTree[`MerkleTree`] includes a predefined structure with functions to manipulate the tree (e.g. pushing values or resetting the tree). - -The Merkle Tree does not keep track of the roots intentionally, so that developers can choose their tracking mechanism. Setting up and using a Merkle Tree in Solidity is as simple as follows: - -NOTE: Functions are exposed without access control for demonstration purposes - -[source,solidity] ----- -using MerkleTree for MerkleTree.Bytes32PushTree; -MerkleTree.Bytes32PushTree private _tree; - -function setup(uint8 _depth, bytes32 _zero) public /* onlyOwner */ { - root = _tree.setup(_depth, _zero); -} - -function push(bytes32 leaf) public /* onlyOwner */ { - (uint256 leafIndex, bytes32 currentRoot) = _tree.push(leaf); - // Store the new root. -} ----- - -The library also supports custom hashing functions, which can be passed as an extra parameter to the xref:api:utils.adoc#MerkleTree-push-struct-MerkleTree-Bytes32PushTree-bytes32-[`push`] and xref:api:utils.adoc#MerkleTree-setup-struct-MerkleTree-Bytes32PushTree-uint8-bytes32-[`setup`] functions. - -Using custom hashing functions is a sensitive operation. After setup, it requires to keep using the same hashing function for every new value pushed to the tree to avoid corrupting the tree. For this reason, it's a good practice to keep your hashing function static in your implementation contract as follows: - -[source,solidity] ----- -using MerkleTree for MerkleTree.Bytes32PushTree; -MerkleTree.Bytes32PushTree private _tree; - -function setup(uint8 _depth, bytes32 _zero) public /* onlyOwner */ { - root = _tree.setup(_depth, _zero, _hashFn); -} - -function push(bytes32 leaf) public /* onlyOwner */ { - (uint256 leafIndex, bytes32 currentRoot) = _tree.push(leaf, _hashFn); - // Store the new root. -} - -function _hashFn(bytes32 a, bytes32 b) internal view returns(bytes32) { - // Custom hash function implementation - // Kept as an internal implementation detail to - // guarantee the same function is always used -} ----- - -=== Using a Heap - -A https://en.wikipedia.org/wiki/Binary_heap[binary heap] is a data structure that always stores the most important element at its peak and it can be used as a priority queue. - -To define what is most important in a heap, these frequently take comparator functions that tell the binary heap whether a value has more relevance than another. - -OpenZeppelin Contracts implements a Heap data structure with the properties of a binary heap. The heap uses the xref:api:utils.adoc#Comparators-lt-uint256-uint256-[`lt`] function by default but allows to customize its comparator. - -When using a custom comparator, it's recommended to wrap your function to avoid the possibility of mistakenly using a different comparator function: - -[source,solidity] ----- -function pop(Uint256Heap storage self) internal returns (uint256) { - return pop(self, Comparators.gt); -} - -function insert(Uint256Heap storage self, uint256 value) internal { - insert(self, value, Comparators.gt); -} - -function replace(Uint256Heap storage self, uint256 newValue) internal returns (uint256) { - return replace(self, newValue, Comparators.gt); -} ----- - - -[[misc]] -== Misc - -=== Packing - -The storage in the EVM is shaped in chunks of 32 bytes, each of this chunks is known as a _slot_, and can hold multiple values together as long as these values don't exceed its size. These properties of the storage allow for a technique known as _packing_, that consists of placing values together on a single storage slot to reduce the costs associated to reading and writing to multiple slots instead of just one. - -Commonly, developers pack values using structs that place values together so they fit better in storage. However, this approach requires to load such struct from either calldata or memory. Although sometimes necessary, it may be useful to pack values in a single slot and treat it as a packed value without involving calldata or memory. - -The xref:api:utils.adoc#Packing[`Packing`] library is a set of utilities for packing values that fit in 32 bytes. The library includes 3 main functionalities: - -* Packing 2 `bytesXX` values -* Extracting a packed `bytesXX` value from a `bytesYY` -* Replacing a packed `bytesXX` value from a `bytesYY` - -With these primitives, one can build custom functions to create custom packed types. For example, suppose you need to pack an `address` of 20 bytes with a `bytes4` selector and an `uint64` time period: - -[source,solidity] ----- -function _pack(address account, bytes4 selector, uint64 period) external pure returns (bytes32) { - bytes12 subpack = Packing.pack_4_8(selector, bytes8(period)); - return Packing.pack_20_12(bytes20(account), subpack); -} - -function _unpack(bytes32 pack) external pure returns (address, bytes4, uint64) { - return ( - address(Packing.extract_32_20(pack, 0)), - Packing.extract_32_4(pack, 20), - uint64(Packing.extract_32_8(pack, 24)) - ); -} ----- - -=== Storage Slots - -Solidity allocates a storage pointer for each variable declared in a contract. However, there are cases when it's required to access storage pointers that can't be derived by using regular Solidity. -For those cases, the xref:api:utils.adoc#StorageSlot[`StorageSlot`] library allows for manipulating storage slots directly. - -[source,solidity] ----- -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; -} ----- - -The xref:api:utils.adoc#TransientSlot[`TransientSlot`] library supports transient storage through user defined value types (https://docs.soliditylang.org/en/latest/types.html#user-defined-value-types[UDVTs]), which enables the same value types as in Solidity. - -[source,solidity] ----- -bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542; - -function _getTransientLock() internal view returns (bool) { - return _LOCK_SLOT.asBoolean().tload(); -} - -function _setTransientLock(bool lock) internal { - _LOCK_SLOT.asBoolean().tstore(lock); -} ----- - -WARNING: Manipulating storage slots directly is an advanced practice. Developers MUST make sure that the storage pointer is not colliding with other variables. - -One of the most common use cases for writing directly to storage slots is ERC-7201 for namespaced storage, which is guaranteed to not collide with other storage slots derived by Solidity. - -Users can leverage this standard using the xref:api:utils.adoc#SlotDerivation[`SlotDerivation`] library. - -[source,solidity] ----- -using SlotDerivation for bytes32; -string private constant _NAMESPACE = "" // eg. example.main - -function erc7201Pointer() internal view returns (bytes32) { - return _NAMESPACE.erc7201Slot(); -} ----- - -=== Base64 - -xref:api:utils.adoc#Base64[`Base64`] util allows you to transform `bytes32` data into its Base64 `string` representation. - -This is especially useful for building URL-safe tokenURIs for both xref:api:token/ERC721.adoc#IERC721Metadata-tokenURI-uint256-[`ERC-721`] or xref:api:token/ERC1155.adoc#IERC1155MetadataURI-uri-uint256-[`ERC-1155`]. This library provides a clever way to serve URL-safe https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs/[Data URI] compliant strings to serve on-chain data structures. - -Here is an example to send JSON Metadata through a Base64 Data URI using an ERC-721: - -[source,solidity] ----- -include::api:example$utilities/Base64NFT.sol[] ----- - -=== Multicall - -The `Multicall` abstract contract comes with a `multicall` function that bundles together multiple calls in a single external call. With it, external accounts may perform atomic operations comprising several function calls. This is not only useful for EOAs to make multiple calls in a single transaction, it's also a way to revert a previous call if a later one fails. - -Consider this dummy contract: - -[source,solidity] ----- -include::api:example$utilities/Multicall.sol[] ----- - -This is how to call the `multicall` function using Ethers.js, allowing `foo` and `bar` to be called in a single transaction: -[source,javascript] ----- -// scripts/foobar.js - -const instance = await ethers.deployContract("Box"); - -await instance.multicall([ - instance.interface.encodeFunctionData("foo"), - instance.interface.encodeFunctionData("bar") -]); ----- - -=== Historical Block Hashes - -xref:api:utils.adoc#Blockhash[`Blockhash`] provides L2 protocol developers with extended access to historical block hashes beyond Ethereum's native 256-block limit. By leveraging https://eips.ethereum.org/EIPS/eip-2935[EIP-2935]'s history storage contract, the library enables access to block hashes up to 8,191 blocks in the past, making it invaluable for L2 fraud proofs and state verification systems. - -The library seamlessly combines native `BLOCKHASH` opcode access for recent blocks (≤256) with EIP-2935 history storage queries for older blocks (257-8,191). It handles edge cases gracefully by returning zero for future blocks or those beyond the history window, matching the EVM's behavior. The implementation uses gas-efficient assembly for static calls to the history storage contract. - -[source,solidity] ----- -contract L1Inbox { - using Blockhash for uint256; - - function verifyBlockHash(uint256 blockNumber, bytes32 expectedHash) public view returns (bool) { - return blockNumber.blockHash() == expectedHash; - } -} ----- - -IMPORTANT: After EIP-2935 activation, it takes 8,191 blocks to completely fill the history storage. Before that, only block hashes since the fork block will be available. - -=== Time - -The xref:api:utils.adoc#Time[`Time`] library provides helpers for manipulating time-related objects in a type-safe manner. It uses `uint48` for timepoints and `uint32` for durations, helping to reduce gas costs while providing adequate precision. - -One of its key features is the `Delay` type, which represents a duration that can automatically change its value at a specified point in the future while maintaining delay guarantees. For example, when reducing a delay value (e.g., from 7 days to 1 day), the change only takes effect after the difference between the old and new delay (i.e. a 6 days) or a minimum setback period, preventing an attacker who gains admin access from immediately reducing security timeouts and executing sensitive operations. This is particularly useful for governance and security mechanisms where timelock periods need to be enforced. - -Consider this example for using and safely updating Delays: -[source,solidity] ----- -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.27; - -import {Time} from "contracts/utils/types/Time.sol"; - -contract MyDelayedContract { - using Time for *; - - Time.Delay private _delay; - - constructor() { - _delay = Time.toDelay(3 days); - } - - function schedule(bytes32 operationId) external { - // Get the current `_delay` value, respecting any pending delay changes if they've taken effect - uint32 currentDelay = _delay.get(); - uint48 executionTime = Time.timestamp() + currentDelay; - - // ... schedule the operation at `executionTime` - } - - function execute(bytes32 operationId) external { - uint48 executionTime = getExecutionTime(operationId); - require(executionTime > 0, "Operation not scheduled"); - require(Time.timestamp() >= executionTime, "Delay not elapsed yet"); - - // ... execute the operation - } - - // Update the delay with `Time`'s safety mechanism - function updateDelay(uint32 newDelay) external { - (Time.Delay updatedDelay, uint48 effect) = _delay.withUpdate( - newDelay, // The new delay value - 5 days // Minimum setback if reducing the delay - ); - - _delay = updatedDelay; - - // ... emit events - } - - // Get complete delay details including pending changes - function getDelayDetails() external view returns ( - uint32 currentValue, // The current delay value - uint32 pendingValue, // The pending delay value - uint48 effectTime // The timepoint when the pending delay change takes effect - ) { - return _delay.getFull(); - } -} ----- - -This pattern is used extensively in OpenZeppelin's xref:api:access.adoc#AccessManager[AccessManager] for implementing secure time-based access control. For example, when changing an admin delay: - -[source,solidity] ----- -// From AccessManager.sol -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); -} ----- diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/wizard.adoc b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/wizard.adoc deleted file mode 100644 index ed416e2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/modules/ROOT/pages/wizard.adoc +++ /dev/null @@ -1,15 +0,0 @@ -= Contracts Wizard -:page-notoc: - -Not sure where to start? Use the interactive generator below to bootstrap your -contract and learn about the components offered in OpenZeppelin Contracts. - -TIP: Place the resulting contract in your `contracts` or `src` directory in order to compile it with a tool like Hardhat or Foundry. Consider reading our guide on xref:learn::developing-smart-contracts.adoc[Developing Smart Contracts] for more guidance! - -++++ - - - -++++ - - diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/contract.hbs b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/contract.hbs deleted file mode 100644 index 458b511..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/contract.hbs +++ /dev/null @@ -1,141 +0,0 @@ -{{#each items}} -:{{name}}: pass:normal[xref:#{{anchor}}[`++{{name}}++`]] -{{/each}} - -{{#each functions}} -:{{fullname}}: pass:normal[xref:#{{anchor}}[`++{{name}}++`]] -{{/each}} - -[.contract] -[[{{anchor}}]] -=== `++{{name}}++` link:https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v{{oz-version}}/{{__item_context.file.absolutePath}}[{github-icon},role=heading-link] - -[.hljs-theme-light.nopadding] -```solidity -import "@openzeppelin/{{__item_context.file.absolutePath}}"; -``` - -{{{natspec.dev}}} - -{{#if modifiers}} -[.contract-index] -.Modifiers --- -{{#each modifiers}} -* {xref-{{anchor~}} }[`++{{name}}({{names params}})++`] -{{/each}} --- -{{/if}} - -{{#if has-functions}} -[.contract-index] -.Functions --- -{{#each inherited-functions}} -{{#unless @first}} -[.contract-subindex-inherited] -.{{contract.name}} -{{/unless}} -{{#each functions}} -* {xref-{{anchor~}} }[`++{{name}}({{names params}})++`] -{{/each}} - -{{/each}} --- -{{/if}} - -{{#if has-events}} -[.contract-index] -.Events --- -{{#each inheritance}} -{{#unless @first}} -[.contract-subindex-inherited] -.{{name}} -{{/unless}} -{{#each events}} -* {xref-{{anchor~}} }[`++{{name}}({{names params}})++`] -{{/each}} - -{{/each}} --- -{{/if}} - -{{#if has-errors}} -[.contract-index] -.Errors --- -{{#each inheritance}} -{{#unless @first}} -[.contract-subindex-inherited] -.{{name}} -{{/unless}} -{{#each errors}} -* {xref-{{anchor~}} }[`++{{name}}({{names params}})++`] -{{/each}} - -{{/each}} --- -{{/if}} - -{{#if has-internal-variables}} -[.contract-index] -.Internal Variables --- -{{#each inheritance}} -{{#unless @first}} -[.contract-subindex-inherited] -.{{name}} -{{/unless}} -{{#each internal-variables}} -* {xref-{{anchor~}} }[`++{{typeDescriptions.typeString}} {{#if constant}}constant{{/if}} {{name}}++`] -{{/each}} - -{{/each}} --- -{{/if}} - -{{#each modifiers}} -[.contract-item] -[[{{anchor}}]] -==== `[.contract-item-name]#++{{name}}++#++({{typed-params params}})++` [.item-kind]#modifier# - -{{{natspec.dev}}} - -{{/each}} - -{{#each functions}} -[.contract-item] -[[{{anchor}}]] -==== `[.contract-item-name]#++{{name}}++#++({{typed-params params}}){{#if returns2}} → {{typed-params returns2}}{{/if}}++` [.item-kind]#{{visibility}}# - -{{{natspec.dev}}} - -{{/each}} - -{{#each events}} -[.contract-item] -[[{{anchor}}]] -==== `[.contract-item-name]#++{{name}}++#++({{typed-params params}})++` [.item-kind]#event# - -{{{natspec.dev}}} - -{{/each}} - -{{#each errors}} -[.contract-item] -[[{{anchor}}]] -==== `[.contract-item-name]#++{{name}}++#++({{typed-params params}})++` [.item-kind]#error# - -{{{natspec.dev}}} - -{{/each}} - -{{#each internal-variables}} -[.contract-item] -[[{{anchor}}]] -==== `{{typeDescriptions.typeString}} [.contract-item-name]#++{{name}}++#` [.item-kind]#internal{{#if constant}} constant{{/if}}# - -{{{natspec.dev}}} - -{{/each}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/helpers.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/helpers.js deleted file mode 100644 index 1b63835..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/helpers.js +++ /dev/null @@ -1,46 +0,0 @@ -const { version } = require('../../package.json'); - -module.exports['oz-version'] = () => version; - -module.exports['readme-path'] = opts => { - return 'contracts/' + opts.data.root.id.replace(/\.adoc$/, '') + '/README.adoc'; -}; - -module.exports.names = params => params?.map(p => p.name).join(', '); - -module.exports['typed-params'] = params => { - return params?.map(p => `${p.type}${p.indexed ? ' indexed' : ''}${p.name ? ' ' + p.name : ''}`).join(', '); -}; - -const slug = (module.exports.slug = str => { - if (str === undefined) { - throw new Error('Missing argument'); - } - return str.replace(/\W/g, '-'); -}); - -const linksCache = new WeakMap(); - -function getAllLinks(items) { - if (linksCache.has(items)) { - return linksCache.get(items); - } - const res = {}; - linksCache.set(items, res); - for (const item of items) { - res[`xref-${item.anchor}`] = `xref:${item.__item_context.page}#${item.anchor}`; - res[slug(item.fullName)] = `pass:normal[xref:${item.__item_context.page}#${item.anchor}[\`${item.fullName}\`]]`; - } - return res; -} - -module.exports['with-prelude'] = opts => { - const links = getAllLinks(opts.data.site.items); - const contents = opts.fn(); - const neededLinks = contents - .match(/\{[-._a-z0-9]+\}/gi) - .map(m => m.replace(/^\{(.+)\}$/, '$1')) - .filter(k => k in links); - const prelude = neededLinks.map(k => `:${k}: ${links[k]}`).join('\n'); - return prelude + '\n' + contents; -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/page.hbs b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/page.hbs deleted file mode 100644 index cab050a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/page.hbs +++ /dev/null @@ -1,4 +0,0 @@ -:github-icon: pass:[] -{{#with-prelude}} -{{readme (readme-path)}} -{{/with-prelude}} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/properties.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/properties.js deleted file mode 100644 index 8d6b286..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/docs/templates/properties.js +++ /dev/null @@ -1,88 +0,0 @@ -const { isNodeType, findAll } = require('solidity-ast/utils'); -const { slug } = require('./helpers'); - -module.exports.anchor = function anchor({ item, contract }) { - let res = ''; - if (contract) { - res += contract.name + '-'; - } - res += item.name; - if ('parameters' in item) { - const signature = item.parameters.parameters.map(v => v.typeName.typeDescriptions.typeString).join(','); - res += slug('(' + signature + ')'); - } - if (isNodeType('VariableDeclaration', item)) { - res += '-' + slug(item.typeName.typeDescriptions.typeString); - } - return res; -}; - -module.exports.fullname = function fullname({ item }) { - let res = ''; - res += item.name; - if ('parameters' in item) { - const signature = item.parameters.parameters.map(v => v.typeName.typeDescriptions.typeString).join(','); - res += slug('(' + signature + ')'); - } - if (isNodeType('VariableDeclaration', item)) { - res += '-' + slug(item.typeName.typeDescriptions.typeString); - } - if (res.charAt(res.length - 1) === '-') { - return res.slice(0, -1); - } - return res; -}; - -module.exports.inheritance = function ({ item, build }) { - if (!isNodeType('ContractDefinition', item)) { - throw new Error('used inherited-items on non-contract'); - } - - return item.linearizedBaseContracts - .map(id => build.deref('ContractDefinition', id)) - .filter((c, i) => c.name !== 'Context' || i === 0); -}; - -module.exports['has-functions'] = function ({ item }) { - return item.inheritance.some(c => c.functions.length > 0); -}; - -module.exports['has-events'] = function ({ item }) { - return item.inheritance.some(c => c.events.length > 0); -}; - -module.exports['has-errors'] = function ({ item }) { - return item.inheritance.some(c => c.errors.length > 0); -}; - -module.exports['internal-variables'] = function ({ item }) { - return item.variables.filter(({ visibility }) => visibility === 'internal'); -}; - -module.exports['has-internal-variables'] = function ({ item }) { - return module.exports['internal-variables']({ item }).length > 0; -}; - -module.exports.functions = function ({ item }) { - return [ - ...[...findAll('FunctionDefinition', item)].filter(f => f.visibility !== 'private'), - ...[...findAll('VariableDeclaration', item)].filter(f => f.visibility === 'public'), - ]; -}; - -module.exports.returns2 = function ({ item }) { - if (isNodeType('VariableDeclaration', item)) { - return [{ type: item.typeDescriptions.typeString }]; - } else { - return item.returns; - } -}; - -module.exports['inherited-functions'] = function ({ item }) { - const { inheritance } = item; - const baseFunctions = new Set(inheritance.flatMap(c => c.functions.flatMap(f => f.baseFunctions ?? []))); - return inheritance.map((contract, i) => ({ - contract, - functions: contract.functions.filter(f => !baseFunctions.has(f.id) && (f.name !== 'constructor' || i === 0)), - })); -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/eslint.config.mjs b/typescript/packages/account-modules/lib/openzeppelin-contracts/eslint.config.mjs deleted file mode 100644 index 00fcc95..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/eslint.config.mjs +++ /dev/null @@ -1,26 +0,0 @@ -import js from '@eslint/js'; -import { includeIgnoreFile } from '@eslint/compat'; -import prettier from 'eslint-config-prettier'; -import globals from 'globals'; -import path from 'path'; - -export default [ - js.configs.recommended, - prettier, - { - languageOptions: { - ecmaVersion: 2022, - globals: { - ...globals.browser, - ...globals.mocha, - ...globals.node, - artifacts: 'readonly', - contract: 'readonly', - web3: 'readonly', - extendEnvironment: 'readonly', - expect: 'readonly', - }, - }, - }, - includeIgnoreFile(path.resolve(import.meta.dirname, '.gitignore')), -]; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/foundry.toml b/typescript/packages/account-modules/lib/openzeppelin-contracts/foundry.toml deleted file mode 100644 index ea8b1fa..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/foundry.toml +++ /dev/null @@ -1,15 +0,0 @@ -[profile.default] -solc_version = '0.8.27' -evm_version = 'prague' -optimizer = true -optimizer-runs = 200 -src = 'contracts' -out = 'out' -libs = ['node_modules', 'lib'] -test = 'test' -cache_path = 'cache_forge' -fs_permissions = [{ access = "read", path = "./test/bin" }] - -[fuzz] -runs = 5000 -max_test_rejects = 150000 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/fv-requirements.txt b/typescript/packages/account-modules/lib/openzeppelin-contracts/fv-requirements.txt deleted file mode 100644 index 0c2ef0e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/fv-requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -certora-cli==4.13.1 -# File uses a custom name (fv-requirements.txt) so that it isn't picked by Netlify's build -# whose latest Python version is 0.3.8, incompatible with most recent versions of Halmos -halmos==0.2.6 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat.config.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat.config.js deleted file mode 100644 index 8f326b5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat.config.js +++ /dev/null @@ -1,124 +0,0 @@ -/// ENVVAR -// - COMPILER: compiler version (default: 0.8.27) -// - SRC: contracts folder to compile (default: contracts) -// - RUNS: number of optimization runs (default: 200) -// - IR: enable IR compilation (default: false) -// - COVERAGE: enable coverage report (default: false) -// - GAS: enable gas report (default: false) -// - COINMARKETCAP: coinmarketcap api key for USD value in gas report -// - CI: output gas report to file instead of stdout - -const fs = require('fs'); -const path = require('path'); - -const { argv } = require('yargs/yargs')() - .env('') - .options({ - // Compilation settings - compiler: { - alias: 'compileVersion', - type: 'string', - default: '0.8.27', - }, - src: { - alias: 'source', - type: 'string', - default: 'contracts', - }, - runs: { - alias: 'optimizationRuns', - type: 'number', - default: 200, - }, - ir: { - alias: 'enableIR', - type: 'boolean', - default: false, - }, - evm: { - alias: 'evmVersion', - type: 'string', - default: 'prague', - }, - // Extra modules - coverage: { - type: 'boolean', - default: false, - }, - gas: { - alias: 'enableGasReport', - type: 'boolean', - default: false, - }, - coinmarketcap: { - alias: 'coinmarketcapApiKey', - type: 'string', - }, - }); - -require('@nomicfoundation/hardhat-chai-matchers'); -require('@nomicfoundation/hardhat-ethers'); -require('hardhat-exposed'); -require('hardhat-gas-reporter'); -require('hardhat-ignore-warnings'); -require('solidity-coverage'); -require('solidity-docgen'); - -for (const f of fs.readdirSync(path.join(__dirname, 'hardhat'))) { - require(path.join(__dirname, 'hardhat', f)); -} - -/** - * @type import('hardhat/config').HardhatUserConfig - */ -module.exports = { - solidity: { - version: argv.compiler, - settings: { - optimizer: { - enabled: true, - runs: argv.runs, - }, - evmVersion: argv.evm, - viaIR: argv.ir, - outputSelection: { '*': { '*': ['storageLayout'] } }, - }, - }, - warnings: { - 'contracts-exposed/**/*': { - 'code-size': 'off', - 'initcode-size': 'off', - }, - '*': { - 'unused-param': !argv.coverage, // coverage causes unused-param warnings - 'transient-storage': false, - default: 'error', - }, - }, - networks: { - hardhat: { - hardfork: argv.evm, - // Exposed contracts often exceed the maximum contract size. For normal contract, - // we rely on the `code-size` compiler warning, that will cause a compilation error. - allowUnlimitedContractSize: true, - initialBaseFeePerGas: argv.coverage ? 0 : undefined, - enableRip7212: true, - }, - }, - exposed: { - imports: true, - initializers: true, - exclude: ['vendor/**/*', '**/*WithInit.sol'], - }, - gasReporter: { - enabled: argv.gas, - showMethodSig: true, - includeBytecodeInJSON: true, - currency: 'USD', - coinmarketcap: argv.coinmarketcap, - }, - paths: { - sources: argv.src, - }, - docgen: require('./docs/config'), -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/async-test-sanity.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/async-test-sanity.js deleted file mode 100644 index 8e60f70..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/async-test-sanity.js +++ /dev/null @@ -1,10 +0,0 @@ -process.on('unhandledRejection', reason => { - // If the reason is already an Error object, throw it directly to preserve the stack trace. - if (reason instanceof Error) { - throw reason; - } else { - // If the reason is not an Error (e.g., a string, number, or other primitive), - // create a new Error object with the reason as its message. - throw new Error(`Unhandled rejection: ${reason}`); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/common-contracts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/common-contracts.js deleted file mode 100644 index 67e44be..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/common-contracts.js +++ /dev/null @@ -1,69 +0,0 @@ -const { task } = require('hardhat/config'); -const { TASK_TEST_SETUP_TEST_ENVIRONMENT } = require('hardhat/builtin-tasks/task-names'); -const { setCode } = require('@nomicfoundation/hardhat-network-helpers'); - -const fs = require('fs'); -const path = require('path'); - -const INSTANCES = { - // ERC-4337 Entrypoints - entrypoint: { - v07: { - address: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', - abi: JSON.parse(fs.readFileSync(path.resolve(__dirname, '../test/bin/EntryPoint070.abi'), 'utf-8')), - bytecode: fs.readFileSync(path.resolve(__dirname, '../test/bin/EntryPoint070.bytecode'), 'hex'), - }, - v08: { - address: '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108', - abi: JSON.parse(fs.readFileSync(path.resolve(__dirname, '../test/bin/EntryPoint080.abi'), 'utf-8')), - bytecode: fs.readFileSync(path.resolve(__dirname, '../test/bin/EntryPoint080.bytecode'), 'hex'), - }, - }, - senderCreator: { - v07: { - address: '0xEFC2c1444eBCC4Db75e7613d20C6a62fF67A167C', - abi: JSON.parse(fs.readFileSync(path.resolve(__dirname, '../test/bin/SenderCreator070.abi'), 'utf-8')), - bytecode: fs.readFileSync(path.resolve(__dirname, '../test/bin/SenderCreator070.bytecode'), 'hex'), - }, - v08: { - address: '0x449ED7C3e6Fee6a97311d4b55475DF59C44AdD33', - abi: JSON.parse(fs.readFileSync(path.resolve(__dirname, '../test/bin/SenderCreator080.abi'), 'utf-8')), - bytecode: fs.readFileSync(path.resolve(__dirname, '../test/bin/SenderCreator080.bytecode'), 'hex'), - }, - }, - deployer: { - // Arachnid's deterministic deployment proxy - // See: https://github.com/Arachnid/deterministic-deployment-proxy/tree/master - arachnid: { - address: '0x4e59b44847b379578588920cA78FbF26c0B4956C', - abi: [], - bytecode: - '0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3', - }, - // Micah's deployer - micah: { - address: '0x7A0D94F55792C434d74a40883C6ed8545E406D12', - abi: [], - bytecode: '0x60003681823780368234f58015156014578182fd5b80825250506014600cf3', - }, - }, - eip2935: { - address: '0x0000F90827F1C53a10cb7A02335B175320002935', - abi: [], - bytecode: - '0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500', - }, -}; - -const setup = (input, ethers) => - input.address && input.abi && input.bytecode - ? setCode(input.address, '0x' + input.bytecode.replace(/0x/, '')).then(() => - ethers.getContractAt(input.abi, input.address), - ) - : Promise.all( - Object.entries(input).map(([name, entry]) => setup(entry, ethers).then(result => [name, result])), - ).then(Object.fromEntries); - -task(TASK_TEST_SETUP_TEST_ENVIRONMENT).setAction((_, env, runSuper) => - runSuper().then(() => setup(INSTANCES, env.ethers).then(result => Object.assign(env, result))), -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/env-artifacts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/env-artifacts.js deleted file mode 100644 index e97ae64..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/env-artifacts.js +++ /dev/null @@ -1,29 +0,0 @@ -const { HardhatError } = require('hardhat/internal/core/errors'); - -function isExpectedError(e, suffix) { - // HH700: Artifact not found - from https://hardhat.org/hardhat-runner/docs/errors#HH700 - return HardhatError.isHardhatError(e) && e.number === 700 && suffix !== ''; -} - -// Modifies the artifact require functions 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(hre => { - const suffixes = ['UpgradeableWithInit', 'Upgradeable', '']; - - // Ethers - const originalReadArtifact = hre.artifacts.readArtifact; - hre.artifacts.readArtifact = async function (name) { - for (const suffix of suffixes) { - try { - return await originalReadArtifact.call(this, name + suffix); - } catch (e) { - if (isExpectedError(e, suffix)) { - continue; - } else { - throw e; - } - } - } - throw new Error('Unreachable'); - }; -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js deleted file mode 100644 index eeacf0a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js +++ /dev/null @@ -1,45 +0,0 @@ -// 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 coming 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/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/remappings.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/remappings.js deleted file mode 100644 index cd9984d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/remappings.js +++ /dev/null @@ -1,18 +0,0 @@ -const fs = require('fs'); -const { task } = require('hardhat/config'); -const { TASK_COMPILE_GET_REMAPPINGS } = require('hardhat/builtin-tasks/task-names'); - -task(TASK_COMPILE_GET_REMAPPINGS).setAction((taskArgs, env, runSuper) => - runSuper().then(remappings => - Object.assign( - remappings, - Object.fromEntries( - fs - .readFileSync('remappings.txt', 'utf-8') - .split('\n') - .filter(Boolean) - .map(line => line.trim().split('=')), - ), - ), - ), -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js deleted file mode 100644 index 965ba37..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js +++ /dev/null @@ -1,6 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/task-test-get-files.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/task-test-get-files.js deleted file mode 100644 index 108f40a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/hardhat/task-test-get-files.js +++ /dev/null @@ -1,25 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol deleted file mode 100644 index c34512b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol +++ /dev/null @@ -1,404 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol deleted file mode 100644 index a26ad0d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol +++ /dev/null @@ -1,356 +0,0 @@ -// 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 test_withdraw_zero_allowance(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); - (bool success,) = _vault_.call( - abi.encodeWithSelector(IERC4626.withdraw.selector, assets, receiver, owner) - ); - assertFalse(success); - } - - // - // 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 test_redeem_zero_allowance(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); - (bool success,) = _vault_.call( - abi.encodeWithSelector(IERC4626.redeem.selector, shares, receiver, owner) - ); - assertFalse(success); - } - - // - // 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE deleted file mode 100644 index 0ad25db..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE +++ /dev/null @@ -1,661 +0,0 @@ - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/README.md deleted file mode 100644 index 651e443..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/erc4626-tests/README.md +++ /dev/null @@ -1,116 +0,0 @@ -# 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitattributes b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitattributes deleted file mode 100644 index 27042d4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -src/Vm.sol linguist-generated diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml deleted file mode 100644 index 2d68e91..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml +++ /dev/null @@ -1,128 +0,0 @@ -name: CI - -on: - workflow_dispatch: - pull_request: - push: - branches: - - master - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Install Foundry - uses: foundry-rs/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@v4 - - - name: Install Foundry - uses: foundry-rs/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@v4 - - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: nightly - - - name: Print forge version - run: forge --version - - - name: Check formatting - run: forge fmt --check diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/sync.yml b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/sync.yml deleted file mode 100644 index 9b170f0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/sync.yml +++ /dev/null @@ -1,31 +0,0 @@ -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@v4 - with: - fetch-depth: 0 - ref: v1 - - # The email is derived from the bots user id, - # found here: https://api.github.com/users/github-actions%5Bbot%5D - - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitignore b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitignore deleted file mode 100644 index 756106d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -cache/ -out/ -.vscode -.idea diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/CONTRIBUTING.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/CONTRIBUTING.md deleted file mode 100644 index 89b75f3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/CONTRIBUTING.md +++ /dev/null @@ -1,193 +0,0 @@ -## Contributing to Foundry - -Thanks for your interest in improving Foundry! - -There are multiple opportunities to contribute at any level. It doesn't matter if you are just getting started with Rust or are the most weathered expert, we can use your help. - -This document will help you get started. **Do not let the document intimidate you**. -It should be considered as a guide to help you navigate the process. - -The [dev Telegram][dev-tg] is available for any concerns you may have that are not covered in this guide. - -### Code of Conduct - -The Foundry project adheres to the [Rust Code of Conduct][rust-coc]. This code of conduct describes the _minimum_ behavior expected from all contributors. - -Instances of violations of the Code of Conduct can be reported by contacting the team at [me@gakonst.com](mailto:me@gakonst.com). - -### Ways to contribute - -There are fundamentally four ways an individual can contribute: - -1. **By opening an issue:** For example, if you believe that you have uncovered a bug - in Foundry, creating a new issue in the issue tracker is the way to report it. -2. **By adding context:** Providing additional context to existing issues, - such as screenshots and code snippets, which help resolve issues. -3. **By resolving issues:** Typically this is done in the form of either - demonstrating that the issue reported is not a problem after all, or more often, - by opening a pull request that fixes the underlying problem, in a concrete and - reviewable manner. - -**Anybody can participate in any stage of contribution**. We urge you to participate in the discussion -around bugs and participate in reviewing PRs. - -### Contributions Related to Spelling and Grammar - -At this time, we will not be accepting contributions that only fix spelling or grammatical errors in documentation, code or -elsewhere. - -### Asking for help - -If you have reviewed existing documentation and still have questions, or you are having problems, you can get help in the following ways: - -- **Asking in the support Telegram:** The [Foundry Support Telegram][support-tg] is a fast and easy way to ask questions. -- **Opening a discussion:** This repository comes with a discussions board where you can also ask for help. Click the "Discussions" tab at the top. - -As Foundry is still in heavy development, the documentation can be a bit scattered. -The [Foundry Book][foundry-book] is our current best-effort attempt at keeping up-to-date information. - -### Submitting a bug report - -When filing a new bug report in the issue tracker, you will be presented with a basic form to fill out. - -If you believe that you have uncovered a bug, please fill out the form to the best of your ability. Do not worry if you cannot answer every detail; just fill in what you can. Contributors will ask follow-up questions if something is unclear. - -The most important pieces of information we need in a bug report are: - -- The Foundry version you are on (and that it is up to date) -- The platform you are on (Windows, macOS, an M1 Mac or Linux) -- Code snippets if this is happening in relation to testing or building code -- Concrete steps to reproduce the bug - -In order to rule out the possibility of the bug being in your project, the code snippets should be as minimal -as possible. It is better if you can reproduce the bug with a small snippet as opposed to an entire project! - -See [this guide][mcve] on how to create a minimal, complete, and verifiable example. - -### Submitting a feature request - -When adding a feature request in the issue tracker, you will be presented with a basic form to fill out. - -Please include as detailed of an explanation as possible of the feature you would like, adding additional context if necessary. - -If you have examples of other tools that have the feature you are requesting, please include them as well. - -### Resolving an issue - -Pull requests are the way concrete changes are made to the code, documentation, and dependencies of Foundry. - -Even minor pull requests, such as those fixing wording, are greatly appreciated. Before making a large change, it is usually -a good idea to first open an issue describing the change to solicit feedback and guidance. This will increase -the likelihood of the PR getting merged. - -Please make sure that the following commands pass if you have changed the code: - -```sh -forge fmt --check -forge test -vvv -``` - -To make sure your changes are compatible with all compiler version targets, run the following commands: - -```sh -forge build --skip test --use solc:0.6.2 -forge build --skip test --use solc:0.6.12 -forge build --skip test --use solc:0.7.0 -forge build --skip test --use solc:0.7.6 -forge build --skip test --use solc:0.8.0 -``` - -The CI will also ensure that the code is formatted correctly and that the tests are passing across all compiler version targets. - -#### Adding cheatcodes - -Please follow the guide outlined in the [cheatcodes](https://github.com/foundry-rs/foundry/blob/master/docs/dev/cheatcodes.md#adding-a-new-cheatcode) documentation of Foundry. - -When making modifications to the native cheatcodes or adding new ones, please make sure to run [`./scripts/vm.py`](./scripts/vm.py) to update the cheatcodes in the [`src/Vm.sol`](./src/Vm.sol) file. - -By default the script will automatically generate the cheatcodes from the [`cheatcodes.json`](https://raw.githubusercontent.com/foundry-rs/foundry/master/crates/cheatcodes/assets/cheatcodes.json) file but alternatively you can provide a path to a JSON file containing the Vm interface, as generated by Foundry, with the `--from` flag. - -```sh -./scripts/vm.py --from path/to/cheatcodes.json -``` - -It is possible that the resulting [`src/Vm.sol`](./src/Vm.sol) file will have some changes that are not directly related to your changes, this is not a problem. - -#### Commits - -It is a recommended best practice to keep your changes as logically grouped as possible within individual commits. There is no limit to the number of commits any single pull request may have, and many contributors find it easier to review changes that are split across multiple commits. - -That said, if you have a number of commits that are "checkpoints" and don't represent a single logical change, please squash those together. - -#### Opening the pull request - -From within GitHub, opening a new pull request will present you with a template that should be filled out. Please try your best at filling out the details, but feel free to skip parts if you're not sure what to put. - -#### Discuss and update - -You will probably get feedback or requests for changes to your pull request. -This is a big part of the submission process, so don't be discouraged! Some contributors may sign off on the pull request right away, others may have more detailed comments or feedback. -This is a necessary part of the process in order to evaluate whether the changes are correct and necessary. - -**Any community member can review a PR, so you might get conflicting feedback**. -Keep an eye out for comments from code owners to provide guidance on conflicting feedback. - -#### Reviewing pull requests - -**Any Foundry community member is welcome to review any pull request**. - -All contributors who choose to review and provide feedback on pull requests have a responsibility to both the project and individual making the contribution. Reviews and feedback must be helpful, insightful, and geared towards improving the contribution as opposed to simply blocking it. If there are reasons why you feel the PR should not be merged, explain what those are. Do not expect to be able to block a PR from advancing simply because you say "no" without giving an explanation. Be open to having your mind changed. Be open to working _with_ the contributor to make the pull request better. - -Reviews that are dismissive or disrespectful of the contributor or any other reviewers are strictly counter to the Code of Conduct. - -When reviewing a pull request, the primary goals are for the codebase to improve and for the person submitting the request to succeed. **Even if a pull request is not merged, the submitter should come away from the experience feeling like their effort was not unappreciated**. Every PR from a new contributor is an opportunity to grow the community. - -##### Review a bit at a time - -Do not overwhelm new contributors. - -It is tempting to micro-optimize and make everything about relative performance, perfect grammar, or exact style matches. Do not succumb to that temptation.. - -Focus first on the most significant aspects of the change: - -1. Does this change make sense for Foundry? -2. Does this change make Foundry better, even if only incrementally? -3. Are there clear bugs or larger scale issues that need attending? -4. Are the commit messages readable and correct? If it contains a breaking change, is it clear enough? - -Note that only **incremental** improvement is needed to land a PR. This means that the PR does not need to be perfect, only better than the status quo. Follow-up PRs may be opened to continue iterating. - -When changes are necessary, _request_ them, do not _demand_ them, and **do not assume that the submitter already knows how to add a test or run a benchmark**. - -Specific performance optimization techniques, coding styles and conventions change over time. The first impression you give to a new contributor never does. - -Nits (requests for small changes that are not essential) are fine, but try to avoid stalling the pull request. Most nits can typically be fixed by the Foundry maintainers merging the pull request, but they can also be an opportunity for the contributor to learn a bit more about the project. - -It is always good to clearly indicate nits when you comment, e.g.: `Nit: change foo() to bar(). But this is not blocking`. - -If your comments were addressed but were not folded after new commits, or if they proved to be mistaken, please, [hide them][hiding-a-comment] with the appropriate reason to keep the conversation flow concise and relevant. - -##### Be aware of the person behind the code - -Be aware that _how_ you communicate requests and reviews in your feedback can have a significant impact on the success of the pull request. Yes, we may merge a particular change that makes Foundry better, but the individual might just not want to have anything to do with Foundry ever again. The goal is not just having good code. - -##### Abandoned or stale pull requests - -If a pull request appears to be abandoned or stalled, it is polite to first check with the contributor to see if they intend to continue the work before checking if they would mind if you took it over (especially if it just has nits left). When doing so, it is courteous to give the original contributor credit for the work they started, either by preserving their name and e-mail address in the commit log, or by using the `Author: ` or `Co-authored-by: ` metadata tag in the commits. - -_Adapted from the [ethers-rs contributing guide](https://github.com/gakonst/ethers-rs/blob/master/CONTRIBUTING.md)_. - -### Releasing - -Releases are automatically done by the release workflow when a tag is pushed, however, these steps still need to be taken: - -1. Ensure that the versions in the relevant `Cargo.toml` files are up-to-date. -2. Update documentation links -3. Perform a final audit for breaking changes. - -[rust-coc]: https://github.com/rust-lang/rust/blob/master/CODE_OF_CONDUCT.md -[dev-tg]: https://t.me/foundry_rs -[foundry-book]: https://github.com/foundry-rs/foundry-book -[support-tg]: https://t.me/foundry_support -[mcve]: https://stackoverflow.com/help/mcve -[hiding-a-comment]: https://help.github.com/articles/managing-disruptive-comments/#hiding-a-comment \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE deleted file mode 100644 index cf01a49..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE +++ /dev/null @@ -1,203 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT deleted file mode 100644 index 28f9830..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/README.md deleted file mode 100644 index 2674dec..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/README.md +++ /dev/null @@ -1,266 +0,0 @@ -# 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 { - 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 addresses 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 - -Contains various assertions. - -### `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); -``` - -## Contributing - -See our [contributing guidelines](./CONTRIBUTING.md). - -## Getting Help - -First, see if the answer to your question can be found in [book](https://book.getfoundry.sh). - -If the answer is not there: - -- Join the [support Telegram](https://t.me/foundry_support) to get help, or -- Open a [discussion](https://github.com/foundry-rs/foundry/discussions/new/choose) with your question, or -- Open an issue with [the bug](https://github.com/foundry-rs/foundry/issues/new/choose) - -If you want to contribute, or follow along with contributor discussion, you can use our [main telegram](https://t.me/foundry_rs) to chat with us about the development of Foundry! - -## License - -Forge Standard Library is offered under either [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE) license. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/foundry.toml b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/foundry.toml deleted file mode 100644 index f09a028..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/foundry.toml +++ /dev/null @@ -1,23 +0,0 @@ -[profile.default] -fs_permissions = [{ access = "read-write", path = "./"}] -optimizer = true -optimizer_runs = 200 - -[rpc_endpoints] -# The RPC URLs are modified versions of the default for testing initialization. -mainnet = "https://eth-mainnet.alchemyapi.io/v2/WV407BEiBmjNJfKo9Uo_55u0z0ITyCOX" # Different API key. -optimism_sepolia = "https://sepolia.optimism.io/" # Adds a trailing slash. -arbitrum_one_sepolia = "https://sepolia-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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/package.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/package.json deleted file mode 100644 index 6011817..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "forge-std", - "version": "1.9.6", - "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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/scripts/vm.py b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/scripts/vm.py deleted file mode 100755 index 3cd047d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/scripts/vm.py +++ /dev/null @@ -1,646 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import copy -import json -import re -import subprocess -from enum import Enum as PyEnum -from pathlib import Path -from typing import Callable -from urllib import request - -VoidFn = Callable[[], None] - -CHEATCODES_JSON_URL = "https://raw.githubusercontent.com/foundry-rs/foundry/master/crates/cheatcodes/assets/cheatcodes.json" -OUT_PATH = "src/Vm.sol" - -VM_SAFE_DOC = """\ -/// 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. -""" - -VM_DOC = """\ -/// 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. -""" - - -def main(): - parser = argparse.ArgumentParser( - description="Generate Vm.sol based on the cheatcodes json created by Foundry") - parser.add_argument( - "--from", - metavar="PATH", - dest="path", - required=False, - help="path to a json file containing the Vm interface, as generated by Foundry") - args = parser.parse_args() - json_str = request.urlopen(CHEATCODES_JSON_URL).read().decode("utf-8") if args.path is None else Path(args.path).read_text() - contract = Cheatcodes.from_json(json_str) - - ccs = contract.cheatcodes - ccs = list(filter(lambda cc: cc.status not in ["experimental", "internal"], ccs)) - ccs.sort(key=lambda cc: cc.func.id) - - safe = list(filter(lambda cc: cc.safety == "safe", ccs)) - safe.sort(key=CmpCheatcode) - unsafe = list(filter(lambda cc: cc.safety == "unsafe", ccs)) - unsafe.sort(key=CmpCheatcode) - assert len(safe) + len(unsafe) == len(ccs) - - prefix_with_group_headers(safe) - prefix_with_group_headers(unsafe) - - out = "" - - out += "// Automatically @generated by scripts/vm.py. Do not modify manually.\n\n" - - pp = CheatcodesPrinter( - spdx_identifier="MIT OR Apache-2.0", - solidity_requirement=">=0.6.2 <0.9.0", - abicoder_pragma=True, - ) - pp.p_prelude() - pp.prelude = False - out += pp.finish() - - out += "\n\n" - out += VM_SAFE_DOC - vm_safe = Cheatcodes( - # TODO: Custom errors were introduced in 0.8.4 - errors=[], # contract.errors - events=contract.events, - enums=contract.enums, - structs=contract.structs, - cheatcodes=safe, - ) - pp.p_contract(vm_safe, "VmSafe") - out += pp.finish() - - out += "\n\n" - out += VM_DOC - vm_unsafe = Cheatcodes( - errors=[], - events=[], - enums=[], - structs=[], - cheatcodes=unsafe, - ) - pp.p_contract(vm_unsafe, "Vm", "VmSafe") - out += pp.finish() - - # Compatibility with <0.8.0 - def memory_to_calldata(m: re.Match) -> str: - return " calldata " + m.group(1) - - out = re.sub(r" memory (.*returns)", memory_to_calldata, out) - - with open(OUT_PATH, "w") as f: - f.write(out) - - forge_fmt = ["forge", "fmt", OUT_PATH] - res = subprocess.run(forge_fmt) - assert res.returncode == 0, f"command failed: {forge_fmt}" - - print(f"Wrote to {OUT_PATH}") - - -class CmpCheatcode: - cheatcode: "Cheatcode" - - def __init__(self, cheatcode: "Cheatcode"): - self.cheatcode = cheatcode - - def __lt__(self, other: "CmpCheatcode") -> bool: - return cmp_cheatcode(self.cheatcode, other.cheatcode) < 0 - - def __eq__(self, other: "CmpCheatcode") -> bool: - return cmp_cheatcode(self.cheatcode, other.cheatcode) == 0 - - def __gt__(self, other: "CmpCheatcode") -> bool: - return cmp_cheatcode(self.cheatcode, other.cheatcode) > 0 - - -def cmp_cheatcode(a: "Cheatcode", b: "Cheatcode") -> int: - if a.group != b.group: - return -1 if a.group < b.group else 1 - if a.status != b.status: - return -1 if a.status < b.status else 1 - if a.safety != b.safety: - return -1 if a.safety < b.safety else 1 - if a.func.id != b.func.id: - return -1 if a.func.id < b.func.id else 1 - return 0 - - -# HACK: A way to add group header comments without having to modify printer code -def prefix_with_group_headers(cheats: list["Cheatcode"]): - s = set() - for i, cheat in enumerate(cheats): - if cheat.group in s: - continue - - s.add(cheat.group) - - c = copy.deepcopy(cheat) - c.func.description = "" - c.func.declaration = f"// ======== {group(c.group)} ========" - cheats.insert(i, c) - return cheats - - -def group(s: str) -> str: - if s == "evm": - return "EVM" - if s == "json": - return "JSON" - return s[0].upper() + s[1:] - - -class Visibility(PyEnum): - EXTERNAL: str = "external" - PUBLIC: str = "public" - INTERNAL: str = "internal" - PRIVATE: str = "private" - - def __str__(self): - return self.value - - -class Mutability(PyEnum): - PURE: str = "pure" - VIEW: str = "view" - NONE: str = "" - - def __str__(self): - return self.value - - -class Function: - id: str - description: str - declaration: str - visibility: Visibility - mutability: Mutability - signature: str - selector: str - selector_bytes: bytes - - def __init__( - self, - id: str, - description: str, - declaration: str, - visibility: Visibility, - mutability: Mutability, - signature: str, - selector: str, - selector_bytes: bytes, - ): - self.id = id - self.description = description - self.declaration = declaration - self.visibility = visibility - self.mutability = mutability - self.signature = signature - self.selector = selector - self.selector_bytes = selector_bytes - - @staticmethod - def from_dict(d: dict) -> "Function": - return Function( - d["id"], - d["description"], - d["declaration"], - Visibility(d["visibility"]), - Mutability(d["mutability"]), - d["signature"], - d["selector"], - bytes(d["selectorBytes"]), - ) - - -class Cheatcode: - func: Function - group: str - status: str - safety: str - - def __init__(self, func: Function, group: str, status: str, safety: str): - self.func = func - self.group = group - self.status = status - self.safety = safety - - @staticmethod - def from_dict(d: dict) -> "Cheatcode": - return Cheatcode( - Function.from_dict(d["func"]), - str(d["group"]), - str(d["status"]), - str(d["safety"]), - ) - - -class Error: - name: str - description: str - declaration: str - - def __init__(self, name: str, description: str, declaration: str): - self.name = name - self.description = description - self.declaration = declaration - - @staticmethod - def from_dict(d: dict) -> "Error": - return Error(**d) - - -class Event: - name: str - description: str - declaration: str - - def __init__(self, name: str, description: str, declaration: str): - self.name = name - self.description = description - self.declaration = declaration - - @staticmethod - def from_dict(d: dict) -> "Event": - return Event(**d) - - -class EnumVariant: - name: str - description: str - - def __init__(self, name: str, description: str): - self.name = name - self.description = description - - -class Enum: - name: str - description: str - variants: list[EnumVariant] - - def __init__(self, name: str, description: str, variants: list[EnumVariant]): - self.name = name - self.description = description - self.variants = variants - - @staticmethod - def from_dict(d: dict) -> "Enum": - return Enum( - d["name"], - d["description"], - list(map(lambda v: EnumVariant(**v), d["variants"])), - ) - - -class StructField: - name: str - ty: str - description: str - - def __init__(self, name: str, ty: str, description: str): - self.name = name - self.ty = ty - self.description = description - - -class Struct: - name: str - description: str - fields: list[StructField] - - def __init__(self, name: str, description: str, fields: list[StructField]): - self.name = name - self.description = description - self.fields = fields - - @staticmethod - def from_dict(d: dict) -> "Struct": - return Struct( - d["name"], - d["description"], - list(map(lambda f: StructField(**f), d["fields"])), - ) - - -class Cheatcodes: - errors: list[Error] - events: list[Event] - enums: list[Enum] - structs: list[Struct] - cheatcodes: list[Cheatcode] - - def __init__( - self, - errors: list[Error], - events: list[Event], - enums: list[Enum], - structs: list[Struct], - cheatcodes: list[Cheatcode], - ): - self.errors = errors - self.events = events - self.enums = enums - self.structs = structs - self.cheatcodes = cheatcodes - - @staticmethod - def from_dict(d: dict) -> "Cheatcodes": - return Cheatcodes( - errors=[Error.from_dict(e) for e in d["errors"]], - events=[Event.from_dict(e) for e in d["events"]], - enums=[Enum.from_dict(e) for e in d["enums"]], - structs=[Struct.from_dict(e) for e in d["structs"]], - cheatcodes=[Cheatcode.from_dict(e) for e in d["cheatcodes"]], - ) - - @staticmethod - def from_json(s) -> "Cheatcodes": - return Cheatcodes.from_dict(json.loads(s)) - - @staticmethod - def from_json_file(file_path: str) -> "Cheatcodes": - with open(file_path, "r") as f: - return Cheatcodes.from_dict(json.load(f)) - - -class Item(PyEnum): - ERROR: str = "error" - EVENT: str = "event" - ENUM: str = "enum" - STRUCT: str = "struct" - FUNCTION: str = "function" - - -class ItemOrder: - _list: list[Item] - - def __init__(self, list: list[Item]) -> None: - assert len(list) <= len(Item), "list must not contain more items than Item" - assert len(list) == len(set(list)), "list must not contain duplicates" - self._list = list - pass - - def get_list(self) -> list[Item]: - return self._list - - @staticmethod - def default() -> "ItemOrder": - return ItemOrder( - [ - Item.ERROR, - Item.EVENT, - Item.ENUM, - Item.STRUCT, - Item.FUNCTION, - ] - ) - - -class CheatcodesPrinter: - buffer: str - - prelude: bool - spdx_identifier: str - solidity_requirement: str - abicoder_v2: bool - - block_doc_style: bool - - indent_level: int - _indent_str: str - - nl_str: str - - items_order: ItemOrder - - def __init__( - self, - buffer: str = "", - prelude: bool = True, - spdx_identifier: str = "UNLICENSED", - solidity_requirement: str = "", - abicoder_pragma: bool = False, - block_doc_style: bool = False, - indent_level: int = 0, - indent_with: int | str = 4, - nl_str: str = "\n", - items_order: ItemOrder = ItemOrder.default(), - ): - self.prelude = prelude - self.spdx_identifier = spdx_identifier - self.solidity_requirement = solidity_requirement - self.abicoder_v2 = abicoder_pragma - self.block_doc_style = block_doc_style - self.buffer = buffer - self.indent_level = indent_level - self.nl_str = nl_str - - if isinstance(indent_with, int): - assert indent_with >= 0 - self._indent_str = " " * indent_with - elif isinstance(indent_with, str): - self._indent_str = indent_with - else: - assert False, "indent_with must be int or str" - - self.items_order = items_order - - def finish(self) -> str: - ret = self.buffer.rstrip() - self.buffer = "" - return ret - - def p_contract(self, contract: Cheatcodes, name: str, inherits: str = ""): - if self.prelude: - self.p_prelude(contract) - - self._p_str("interface ") - name = name.strip() - if name != "": - self._p_str(name) - self._p_str(" ") - if inherits != "": - self._p_str("is ") - self._p_str(inherits) - self._p_str(" ") - self._p_str("{") - self._p_nl() - self._with_indent(lambda: self._p_items(contract)) - self._p_str("}") - self._p_nl() - - def _p_items(self, contract: Cheatcodes): - for item in self.items_order.get_list(): - if item == Item.ERROR: - self.p_errors(contract.errors) - elif item == Item.EVENT: - self.p_events(contract.events) - elif item == Item.ENUM: - self.p_enums(contract.enums) - elif item == Item.STRUCT: - self.p_structs(contract.structs) - elif item == Item.FUNCTION: - self.p_functions(contract.cheatcodes) - else: - assert False, f"unknown item {item}" - - def p_prelude(self, contract: Cheatcodes | None = None): - self._p_str(f"// SPDX-License-Identifier: {self.spdx_identifier}") - self._p_nl() - - if self.solidity_requirement != "": - req = self.solidity_requirement - elif contract and len(contract.errors) > 0: - req = ">=0.8.4 <0.9.0" - else: - req = ">=0.6.0 <0.9.0" - self._p_str(f"pragma solidity {req};") - self._p_nl() - - if self.abicoder_v2: - self._p_str("pragma experimental ABIEncoderV2;") - self._p_nl() - - self._p_nl() - - def p_errors(self, errors: list[Error]): - for error in errors: - self._p_line(lambda: self.p_error(error)) - - def p_error(self, error: Error): - self._p_comment(error.description, doc=True) - self._p_line(lambda: self._p_str(error.declaration)) - - def p_events(self, events: list[Event]): - for event in events: - self._p_line(lambda: self.p_event(event)) - - def p_event(self, event: Event): - self._p_comment(event.description, doc=True) - self._p_line(lambda: self._p_str(event.declaration)) - - def p_enums(self, enums: list[Enum]): - for enum in enums: - self._p_line(lambda: self.p_enum(enum)) - - def p_enum(self, enum: Enum): - self._p_comment(enum.description, doc=True) - self._p_line(lambda: self._p_str(f"enum {enum.name} {{")) - self._with_indent(lambda: self.p_enum_variants(enum.variants)) - self._p_line(lambda: self._p_str("}")) - - def p_enum_variants(self, variants: list[EnumVariant]): - for i, variant in enumerate(variants): - self._p_indent() - self._p_comment(variant.description) - - self._p_indent() - self._p_str(variant.name) - if i < len(variants) - 1: - self._p_str(",") - self._p_nl() - - def p_structs(self, structs: list[Struct]): - for struct in structs: - self._p_line(lambda: self.p_struct(struct)) - - def p_struct(self, struct: Struct): - self._p_comment(struct.description, doc=True) - self._p_line(lambda: self._p_str(f"struct {struct.name} {{")) - self._with_indent(lambda: self.p_struct_fields(struct.fields)) - self._p_line(lambda: self._p_str("}")) - - def p_struct_fields(self, fields: list[StructField]): - for field in fields: - self._p_line(lambda: self.p_struct_field(field)) - - def p_struct_field(self, field: StructField): - self._p_comment(field.description) - self._p_indented(lambda: self._p_str(f"{field.ty} {field.name};")) - - def p_functions(self, cheatcodes: list[Cheatcode]): - for cheatcode in cheatcodes: - self._p_line(lambda: self.p_function(cheatcode.func)) - - def p_function(self, func: Function): - self._p_comment(func.description, doc=True) - self._p_line(lambda: self._p_str(func.declaration)) - - def _p_comment(self, s: str, doc: bool = False): - s = s.strip() - if s == "": - return - - s = map(lambda line: line.lstrip(), s.split("\n")) - if self.block_doc_style: - self._p_str("/*") - if doc: - self._p_str("*") - self._p_nl() - for line in s: - self._p_indent() - self._p_str(" ") - if doc: - self._p_str("* ") - self._p_str(line) - self._p_nl() - self._p_indent() - self._p_str(" */") - self._p_nl() - else: - first_line = True - for line in s: - if not first_line: - self._p_indent() - first_line = False - - if doc: - self._p_str("/// ") - else: - self._p_str("// ") - self._p_str(line) - self._p_nl() - - def _with_indent(self, f: VoidFn): - self._inc_indent() - f() - self._dec_indent() - - def _p_line(self, f: VoidFn): - self._p_indent() - f() - self._p_nl() - - def _p_indented(self, f: VoidFn): - self._p_indent() - f() - - def _p_indent(self): - for _ in range(self.indent_level): - self._p_str(self._indent_str) - - def _p_nl(self): - self._p_str(self.nl_str) - - def _p_str(self, txt: str): - self.buffer += txt - - def _inc_indent(self): - self.indent_level += 1 - - def _dec_indent(self): - self.indent_level -= 1 - - -if __name__ == "__main__": - main() diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Base.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Base.sol deleted file mode 100644 index 851ac0c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Base.sol +++ /dev/null @@ -1,35 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Script.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Script.sol deleted file mode 100644 index 94e75f6..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Script.sol +++ /dev/null @@ -1,27 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol deleted file mode 100644 index 857ecd5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol +++ /dev/null @@ -1,669 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2 <0.9.0; -pragma experimental ABIEncoderV2; - -import {Vm} from "./Vm.sol"; - -abstract contract StdAssertions { - Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); - - event log(string); - event logs(bytes); - - event log_address(address); - event log_bytes32(bytes32); - event log_int(int256); - event log_uint(uint256); - 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, int256 val, uint256 decimals); - event log_named_decimal_uint(string key, uint256 val, uint256 decimals); - event log_named_int(string key, int256 val); - event log_named_uint(string key, uint256 val); - event log_named_bytes(string key, bytes val); - event log_named_string(string key, string val); - - 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); - - bool private _failed; - - function failed() public view returns (bool) { - if (_failed) { - return _failed; - } else { - return vm.load(address(vm), bytes32("failed")) != bytes32(0); - } - } - - function fail() internal virtual { - vm.store(address(vm), bytes32("failed"), bytes32(uint256(1))); - _failed = true; - } - - function assertTrue(bool data) internal pure virtual { - vm.assertTrue(data); - } - - function assertTrue(bool data, string memory err) internal pure virtual { - vm.assertTrue(data, err); - } - - function assertFalse(bool data) internal pure virtual { - vm.assertFalse(data); - } - - function assertFalse(bool data, string memory err) internal pure virtual { - vm.assertFalse(data, err); - } - - function assertEq(bool left, bool right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bool left, bool right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(uint256 left, uint256 right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(uint256 left, uint256 right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertEqDecimal(left, right, decimals); - } - - function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertEqDecimal(left, right, decimals, err); - } - - function assertEq(int256 left, int256 right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(int256 left, int256 right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEqDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertEqDecimal(left, right, decimals); - } - - function assertEqDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertEqDecimal(left, right, decimals, err); - } - - function assertEq(address left, address right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(address left, address right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(bytes32 left, bytes32 right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bytes32 left, bytes32 right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq32(bytes32 left, bytes32 right) internal pure virtual { - assertEq(left, right); - } - - function assertEq32(bytes32 left, bytes32 right, string memory err) internal pure virtual { - assertEq(left, right, err); - } - - function assertEq(string memory left, string memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(string memory left, string memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(bytes memory left, bytes memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bytes memory left, bytes memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(bool[] memory left, bool[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bool[] memory left, bool[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(uint256[] memory left, uint256[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(uint256[] memory left, uint256[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(int256[] memory left, int256[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(int256[] memory left, int256[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(address[] memory left, address[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(address[] memory left, address[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(bytes32[] memory left, bytes32[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bytes32[] memory left, bytes32[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(string[] memory left, string[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(string[] memory left, string[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(bytes[] memory left, bytes[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bytes[] memory left, bytes[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - // Legacy helper - function assertEqUint(uint256 left, uint256 right) internal pure virtual { - assertEq(left, right); - } - - function assertNotEq(bool left, bool right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bool left, bool right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(uint256 left, uint256 right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(uint256 left, uint256 right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertNotEqDecimal(left, right, decimals); - } - - function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) - internal - pure - virtual - { - vm.assertNotEqDecimal(left, right, decimals, err); - } - - function assertNotEq(int256 left, int256 right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(int256 left, int256 right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertNotEqDecimal(left, right, decimals); - } - - function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertNotEqDecimal(left, right, decimals, err); - } - - function assertNotEq(address left, address right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(address left, address right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(bytes32 left, bytes32 right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bytes32 left, bytes32 right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq32(bytes32 left, bytes32 right) internal pure virtual { - assertNotEq(left, right); - } - - function assertNotEq32(bytes32 left, bytes32 right, string memory err) internal pure virtual { - assertNotEq(left, right, err); - } - - function assertNotEq(string memory left, string memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(string memory left, string memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(bytes memory left, bytes memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bytes memory left, bytes memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(bool[] memory left, bool[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bool[] memory left, bool[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(uint256[] memory left, uint256[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(uint256[] memory left, uint256[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(int256[] memory left, int256[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(int256[] memory left, int256[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(address[] memory left, address[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(address[] memory left, address[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(bytes32[] memory left, bytes32[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bytes32[] memory left, bytes32[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(string[] memory left, string[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(string[] memory left, string[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(bytes[] memory left, bytes[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bytes[] memory left, bytes[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertLt(uint256 left, uint256 right) internal pure virtual { - vm.assertLt(left, right); - } - - function assertLt(uint256 left, uint256 right, string memory err) internal pure virtual { - vm.assertLt(left, right, err); - } - - function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertLtDecimal(left, right, decimals); - } - - function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertLtDecimal(left, right, decimals, err); - } - - function assertLt(int256 left, int256 right) internal pure virtual { - vm.assertLt(left, right); - } - - function assertLt(int256 left, int256 right, string memory err) internal pure virtual { - vm.assertLt(left, right, err); - } - - function assertLtDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertLtDecimal(left, right, decimals); - } - - function assertLtDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertLtDecimal(left, right, decimals, err); - } - - function assertGt(uint256 left, uint256 right) internal pure virtual { - vm.assertGt(left, right); - } - - function assertGt(uint256 left, uint256 right, string memory err) internal pure virtual { - vm.assertGt(left, right, err); - } - - function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertGtDecimal(left, right, decimals); - } - - function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertGtDecimal(left, right, decimals, err); - } - - function assertGt(int256 left, int256 right) internal pure virtual { - vm.assertGt(left, right); - } - - function assertGt(int256 left, int256 right, string memory err) internal pure virtual { - vm.assertGt(left, right, err); - } - - function assertGtDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertGtDecimal(left, right, decimals); - } - - function assertGtDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertGtDecimal(left, right, decimals, err); - } - - function assertLe(uint256 left, uint256 right) internal pure virtual { - vm.assertLe(left, right); - } - - function assertLe(uint256 left, uint256 right, string memory err) internal pure virtual { - vm.assertLe(left, right, err); - } - - function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertLeDecimal(left, right, decimals); - } - - function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertLeDecimal(left, right, decimals, err); - } - - function assertLe(int256 left, int256 right) internal pure virtual { - vm.assertLe(left, right); - } - - function assertLe(int256 left, int256 right, string memory err) internal pure virtual { - vm.assertLe(left, right, err); - } - - function assertLeDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertLeDecimal(left, right, decimals); - } - - function assertLeDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertLeDecimal(left, right, decimals, err); - } - - function assertGe(uint256 left, uint256 right) internal pure virtual { - vm.assertGe(left, right); - } - - function assertGe(uint256 left, uint256 right, string memory err) internal pure virtual { - vm.assertGe(left, right, err); - } - - function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertGeDecimal(left, right, decimals); - } - - function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertGeDecimal(left, right, decimals, err); - } - - function assertGe(int256 left, int256 right) internal pure virtual { - vm.assertGe(left, right); - } - - function assertGe(int256 left, int256 right, string memory err) internal pure virtual { - vm.assertGe(left, right, err); - } - - function assertGeDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertGeDecimal(left, right, decimals); - } - - function assertGeDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertGeDecimal(left, right, decimals, err); - } - - function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) internal pure virtual { - vm.assertApproxEqAbs(left, right, maxDelta); - } - - function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string memory err) - internal - pure - virtual - { - vm.assertApproxEqAbs(left, right, maxDelta, err); - } - - function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) - internal - pure - virtual - { - vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals); - } - - function assertApproxEqAbsDecimal( - uint256 left, - uint256 right, - uint256 maxDelta, - uint256 decimals, - string memory err - ) internal pure virtual { - vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals, err); - } - - function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) internal pure virtual { - vm.assertApproxEqAbs(left, right, maxDelta); - } - - function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string memory err) internal pure virtual { - vm.assertApproxEqAbs(left, right, maxDelta, err); - } - - function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) - internal - pure - virtual - { - vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals); - } - - function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals, string memory err) - internal - pure - virtual - { - vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals, err); - } - - function assertApproxEqRel( - uint256 left, - uint256 right, - uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% - ) internal pure virtual { - vm.assertApproxEqRel(left, right, maxPercentDelta); - } - - function assertApproxEqRel( - uint256 left, - uint256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - string memory err - ) internal pure virtual { - vm.assertApproxEqRel(left, right, maxPercentDelta, err); - } - - function assertApproxEqRelDecimal( - uint256 left, - uint256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - uint256 decimals - ) internal pure virtual { - vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals); - } - - function assertApproxEqRelDecimal( - uint256 left, - uint256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - uint256 decimals, - string memory err - ) internal pure virtual { - vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals, err); - } - - function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) internal pure virtual { - vm.assertApproxEqRel(left, right, maxPercentDelta); - } - - function assertApproxEqRel( - int256 left, - int256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - string memory err - ) internal pure virtual { - vm.assertApproxEqRel(left, right, maxPercentDelta, err); - } - - function assertApproxEqRelDecimal( - int256 left, - int256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - uint256 decimals - ) internal pure virtual { - vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals); - } - - function assertApproxEqRelDecimal( - int256 left, - int256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - uint256 decimals, - string memory err - ) internal pure virtual { - vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals, err); - } - - // Inherited from DSTest, not used but kept for backwards-compatibility - function checkEq0(bytes memory left, bytes memory right) internal pure returns (bool) { - return keccak256(left) == keccak256(right); - } - - function assertEq0(bytes memory left, bytes memory right) internal pure virtual { - assertEq(left, right); - } - - function assertEq0(bytes memory left, bytes memory right, string memory err) internal pure virtual { - assertEq(left, right, err); - } - - function assertNotEq0(bytes memory left, bytes memory right) internal pure virtual { - assertNotEq(left, right); - } - - function assertNotEq0(bytes memory left, bytes memory right, string memory err) internal pure virtual { - assertNotEq(left, right, err); - } - - 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); - revert("assertion failed"); - } - - 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); - revert("assertion failed"); - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol deleted file mode 100644 index 964cdbe..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol +++ /dev/null @@ -1,287 +0,0 @@ -// 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 - 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) { - 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' - // The upstream error thrown by forge for failing cheats changed so we check both the old and new versions - bytes memory oldNotFoundError = - abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias))); - bytes memory newNotFoundError = abi.encodeWithSignature( - "CheatcodeError(string)", string(abi.encodePacked("invalid rpc url: ", chainAlias)) - ); - bytes32 errHash = keccak256(err); - if ( - (errHash != keccak256(oldNotFoundError) && errHash != keccak256(newNotFoundError)) - || 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 `test_Rpcs` in `StdChains.t.sol` - setChainWithDefaultRpcUrl("anvil", ChainData("Anvil", 31337, "http://127.0.0.1:8545")); - setChainWithDefaultRpcUrl( - "mainnet", ChainData("Mainnet", 1, "https://eth-mainnet.alchemyapi.io/v2/pwc5rmJhrdoaSEfimoKEmsvOjKSmPDrP") - ); - setChainWithDefaultRpcUrl( - "sepolia", ChainData("Sepolia", 11155111, "https://sepolia.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001") - ); - setChainWithDefaultRpcUrl("holesky", ChainData("Holesky", 17000, "https://rpc.holesky.ethpandaops.io")); - setChainWithDefaultRpcUrl("optimism", ChainData("Optimism", 10, "https://mainnet.optimism.io")); - setChainWithDefaultRpcUrl( - "optimism_sepolia", ChainData("Optimism Sepolia", 11155420, "https://sepolia.optimism.io") - ); - setChainWithDefaultRpcUrl("arbitrum_one", ChainData("Arbitrum One", 42161, "https://arb1.arbitrum.io/rpc")); - setChainWithDefaultRpcUrl( - "arbitrum_one_sepolia", ChainData("Arbitrum One Sepolia", 421614, "https://sepolia-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_amoy", ChainData("Polygon Amoy", 80002, "https://rpc-amoy.polygon.technology") - ); - 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_sepolia", ChainData("Base Sepolia", 84532, "https://sepolia.base.org")); - setChainWithDefaultRpcUrl("base", ChainData("Base", 8453, "https://mainnet.base.org")); - setChainWithDefaultRpcUrl("blast_sepolia", ChainData("Blast Sepolia", 168587773, "https://sepolia.blast.io")); - setChainWithDefaultRpcUrl("blast", ChainData("Blast", 81457, "https://rpc.blast.io")); - setChainWithDefaultRpcUrl("fantom_opera", ChainData("Fantom Opera", 250, "https://rpc.ankr.com/fantom/")); - setChainWithDefaultRpcUrl( - "fantom_opera_testnet", ChainData("Fantom Opera Testnet", 4002, "https://rpc.ankr.com/fantom_testnet/") - ); - setChainWithDefaultRpcUrl("fraxtal", ChainData("Fraxtal", 252, "https://rpc.frax.com")); - setChainWithDefaultRpcUrl("fraxtal_testnet", ChainData("Fraxtal Testnet", 2522, "https://rpc.testnet.frax.com")); - setChainWithDefaultRpcUrl( - "berachain_bartio_testnet", ChainData("Berachain bArtio Testnet", 80084, "https://bartio.rpc.berachain.com") - ); - setChainWithDefaultRpcUrl("flare", ChainData("Flare", 14, "https://flare-api.flare.network/ext/C/rpc")); - setChainWithDefaultRpcUrl( - "flare_coston2", ChainData("Flare Coston2", 114, "https://coston2-api.flare.network/ext/C/rpc") - ); - - setChainWithDefaultRpcUrl("mode", ChainData("Mode", 34443, "https://mode.drpc.org")); - setChainWithDefaultRpcUrl("mode_sepolia", ChainData("Mode Sepolia", 919, "https://sepolia.mode.network")); - - setChainWithDefaultRpcUrl("zora", ChainData("Zora", 7777777, "https://zora.drpc.org")); - setChainWithDefaultRpcUrl( - "zora_sepolia", ChainData("Zora Sepolia", 999999999, "https://sepolia.rpc.zora.energy") - ); - - setChainWithDefaultRpcUrl("race", ChainData("Race", 6805, "https://racemainnet.io")); - setChainWithDefaultRpcUrl("race_sepolia", ChainData("Race Sepolia", 6806, "https://racemainnet.io")); - - setChainWithDefaultRpcUrl("metal", ChainData("Metal", 1750, "https://metall2.drpc.org")); - setChainWithDefaultRpcUrl("metal_sepolia", ChainData("Metal Sepolia", 1740, "https://testnet.rpc.metall2.com")); - - setChainWithDefaultRpcUrl("binary", ChainData("Binary", 624, "https://rpc.zero.thebinaryholdings.com")); - setChainWithDefaultRpcUrl( - "binary_sepolia", ChainData("Binary Sepolia", 625, "https://rpc.zero.thebinaryholdings.com") - ); - - setChainWithDefaultRpcUrl("orderly", ChainData("Orderly", 291, "https://rpc.orderly.network")); - setChainWithDefaultRpcUrl( - "orderly_sepolia", ChainData("Orderly Sepolia", 4460, "https://testnet-rpc.orderly.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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol deleted file mode 100644 index 9f360de..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol +++ /dev/null @@ -1,829 +0,0 @@ -// 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 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 are reserved by Ethereum and may be on all EVM-compatible chains. - vm.assume(addr < address(0x1) || addr > address(0xff)); - - // 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 assumeUnusedAddress(address addr) internal view virtual { - uint256 size; - assembly { - size := extcodesize(addr) - } - vm.assume(size == 0); - - assumeNotPrecompile(addr); - assumeNotZeroAddress(addr); - assumeNotForgeAddress(addr); - } - - 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(vm.getBlockTimestamp() + time); - } - - function rewind(uint256 time) internal virtual { - vm.warp(vm.getBlockTimestamp() - 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_StdCheats("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_StdCheats(string memory p0) private view { - (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string)", p0)); - status; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol deleted file mode 100644 index a302191..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol +++ /dev/null @@ -1,15 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdInvariant.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdInvariant.sol deleted file mode 100644 index 056db98..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdInvariant.sol +++ /dev/null @@ -1,122 +0,0 @@ -// 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 FuzzArtifactSelector { - string artifact; - 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; - - FuzzArtifactSelector[] private _targetedArtifactSelectors; - - FuzzSelector[] private _excludedSelectors; - 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 excludeSelector(FuzzSelector memory newExcludedSelector_) internal { - _excludedSelectors.push(newExcludedSelector_); - } - - 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(FuzzArtifactSelector 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 excludeSelectors() public view returns (FuzzSelector[] memory excludedSelectors_) { - excludedSelectors_ = _excludedSelectors; - } - - 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 (FuzzArtifactSelector[] 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol deleted file mode 100644 index 2a033c0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol +++ /dev/null @@ -1,283 +0,0 @@ -// 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(""); -// json.readUint(""); -// ``` -// To write: -// ``` -// using stdJson for string; -// string memory json = "json"; -// json.serialize("a", uint256(123)); -// string memory semiFinal = json.serialize("b", string("test")); -// string memory finalJson = json.serialize("c", semiFinal); -// finalJson.write(""); -// ``` - -library stdJson { - VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); - - function keyExists(string memory json, string memory key) internal view returns (bool) { - return vm.keyExistsJson(json, key); - } - - 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 readUintOr(string memory json, string memory key, uint256 defaultValue) internal view returns (uint256) { - return keyExists(json, key) ? readUint(json, key) : defaultValue; - } - - function readUintArrayOr(string memory json, string memory key, uint256[] memory defaultValue) - internal - view - returns (uint256[] memory) - { - return keyExists(json, key) ? readUintArray(json, key) : defaultValue; - } - - function readIntOr(string memory json, string memory key, int256 defaultValue) internal view returns (int256) { - return keyExists(json, key) ? readInt(json, key) : defaultValue; - } - - function readIntArrayOr(string memory json, string memory key, int256[] memory defaultValue) - internal - view - returns (int256[] memory) - { - return keyExists(json, key) ? readIntArray(json, key) : defaultValue; - } - - function readBytes32Or(string memory json, string memory key, bytes32 defaultValue) - internal - view - returns (bytes32) - { - return keyExists(json, key) ? readBytes32(json, key) : defaultValue; - } - - function readBytes32ArrayOr(string memory json, string memory key, bytes32[] memory defaultValue) - internal - view - returns (bytes32[] memory) - { - return keyExists(json, key) ? readBytes32Array(json, key) : defaultValue; - } - - function readStringOr(string memory json, string memory key, string memory defaultValue) - internal - view - returns (string memory) - { - return keyExists(json, key) ? readString(json, key) : defaultValue; - } - - function readStringArrayOr(string memory json, string memory key, string[] memory defaultValue) - internal - view - returns (string[] memory) - { - return keyExists(json, key) ? readStringArray(json, key) : defaultValue; - } - - function readAddressOr(string memory json, string memory key, address defaultValue) - internal - view - returns (address) - { - return keyExists(json, key) ? readAddress(json, key) : defaultValue; - } - - function readAddressArrayOr(string memory json, string memory key, address[] memory defaultValue) - internal - view - returns (address[] memory) - { - return keyExists(json, key) ? readAddressArray(json, key) : defaultValue; - } - - function readBoolOr(string memory json, string memory key, bool defaultValue) internal view returns (bool) { - return keyExists(json, key) ? readBool(json, key) : defaultValue; - } - - function readBoolArrayOr(string memory json, string memory key, bool[] memory defaultValue) - internal - view - returns (bool[] memory) - { - return keyExists(json, key) ? readBoolArray(json, key) : defaultValue; - } - - function readBytesOr(string memory json, string memory key, bytes memory defaultValue) - internal - view - returns (bytes memory) - { - return keyExists(json, key) ? readBytes(json, key) : defaultValue; - } - - function readBytesArrayOr(string memory json, string memory key, bytes[] memory defaultValue) - internal - view - returns (bytes[] memory) - { - return keyExists(json, key) ? readBytesArray(json, key) : defaultValue; - } - - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol deleted file mode 100644 index 459523b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol +++ /dev/null @@ -1,43 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol deleted file mode 100644 index bf3223d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol +++ /dev/null @@ -1,473 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2 <0.9.0; - -import {Vm} from "./Vm.sol"; - -struct FindData { - uint256 slot; - uint256 offsetLeft; - uint256 offsetRight; - bool found; -} - -struct StdStorage { - mapping(address => mapping(bytes4 => mapping(bytes32 => FindData))) finds; - bytes32[] _keys; - bytes4 _sig; - uint256 _depth; - address _target; - bytes32 _set; - bool _enable_packed_slots; - bytes _calldata; -} - -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"))))); - uint256 constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935; - - function sigs(string memory sigStr) internal pure returns (bytes4) { - return bytes4(keccak256(bytes(sigStr))); - } - - function getCallParams(StdStorage storage self) internal view returns (bytes memory) { - if (self._calldata.length == 0) { - return flatten(self._keys); - } else { - return self._calldata; - } - } - - // Calls target contract with configured parameters - function callTarget(StdStorage storage self) internal view returns (bool, bytes32) { - bytes memory cald = abi.encodePacked(self._sig, getCallParams(self)); - (bool success, bytes memory rdat) = self._target.staticcall(cald); - bytes32 result = bytesToBytes32(rdat, 32 * self._depth); - - return (success, result); - } - - // Tries mutating slot value to determine if the targeted value is stored in it. - // If current value is 0, then we are setting slot value to type(uint256).max - // Otherwise, we set it to 0. That way, return value should always be affected. - function checkSlotMutatesCall(StdStorage storage self, bytes32 slot) internal returns (bool) { - bytes32 prevSlotValue = vm.load(self._target, slot); - (bool success, bytes32 prevReturnValue) = callTarget(self); - - bytes32 testVal = prevReturnValue == bytes32(0) ? bytes32(UINT256_MAX) : bytes32(0); - vm.store(self._target, slot, testVal); - - (, bytes32 newReturnValue) = callTarget(self); - - vm.store(self._target, slot, prevSlotValue); - - return (success && (prevReturnValue != newReturnValue)); - } - - // Tries setting one of the bits in slot to 1 until return value changes. - // Index of resulted bit is an offset packed slot has from left/right side - function findOffset(StdStorage storage self, bytes32 slot, bool left) internal returns (bool, uint256) { - for (uint256 offset = 0; offset < 256; offset++) { - uint256 valueToPut = left ? (1 << (255 - offset)) : (1 << offset); - vm.store(self._target, slot, bytes32(valueToPut)); - - (bool success, bytes32 data) = callTarget(self); - - if (success && (uint256(data) > 0)) { - return (true, offset); - } - } - return (false, 0); - } - - function findOffsets(StdStorage storage self, bytes32 slot) internal returns (bool, uint256, uint256) { - bytes32 prevSlotValue = vm.load(self._target, slot); - - (bool foundLeft, uint256 offsetLeft) = findOffset(self, slot, true); - (bool foundRight, uint256 offsetRight) = findOffset(self, slot, false); - - // `findOffset` may mutate slot value, so we are setting it to initial value - vm.store(self._target, slot, prevSlotValue); - return (foundLeft && foundRight, offsetLeft, offsetRight); - } - - function find(StdStorage storage self) internal returns (FindData storage) { - return find(self, true); - } - - /// @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, bool _clear) internal returns (FindData storage) { - address who = self._target; - bytes4 fsig = self._sig; - uint256 field_depth = self._depth; - bytes memory params = getCallParams(self); - - // calldata to test against - if (self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found) { - if (_clear) { - clear(self); - } - return self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))]; - } - vm.record(); - (, bytes32 callResult) = callTarget(self); - (bytes32[] memory reads,) = vm.accesses(address(who)); - - if (reads.length == 0) { - revert("stdStorage find(StdStorage): No storage use detected for target."); - } else { - for (uint256 i = reads.length; --i >= 0;) { - bytes32 prev = vm.load(who, reads[i]); - if (prev == bytes32(0)) { - emit WARNING_UninitedSlot(who, uint256(reads[i])); - } - - if (!checkSlotMutatesCall(self, reads[i])) { - continue; - } - - (uint256 offsetLeft, uint256 offsetRight) = (0, 0); - - if (self._enable_packed_slots) { - bool found; - (found, offsetLeft, offsetRight) = findOffsets(self, reads[i]); - if (!found) { - continue; - } - } - - // Check that value between found offsets is equal to the current call result - uint256 curVal = (uint256(prev) & getMaskByOffsets(offsetLeft, offsetRight)) >> offsetRight; - - if (uint256(callResult) != curVal) { - continue; - } - - emit SlotFound(who, fsig, keccak256(abi.encodePacked(params, field_depth)), uint256(reads[i])); - self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))] = - FindData(uint256(reads[i]), offsetLeft, offsetRight, true); - break; - } - } - - require( - self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found, - "stdStorage find(StdStorage): Slot(s) not found." - ); - - if (_clear) { - clear(self); - } - return self.finds[who][fsig][keccak256(abi.encodePacked(params, 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_calldata(StdStorage storage self, bytes memory _calldata) internal returns (StdStorage storage) { - self._calldata = _calldata; - 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 enable_packed_slots(StdStorage storage self) internal returns (StdStorage storage) { - self._enable_packed_slots = true; - 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) { - FindData storage data = find(self, false); - uint256 mask = getMaskByOffsets(data.offsetLeft, data.offsetRight); - uint256 value = (uint256(vm.load(self._target, bytes32(data.slot))) & mask) >> data.offsetRight; - clear(self); - return abi.encode(value); - } - - 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, true).slot - 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, true).slot - 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; - } - - function clear(StdStorage storage self) internal { - delete self._target; - delete self._sig; - delete self._keys; - delete self._depth; - delete self._enable_packed_slots; - delete self._calldata; - } - - // Returns mask which contains non-zero bits for values between `offsetLeft` and `offsetRight` - // (slotValue & mask) >> offsetRight will be the value of the given packed variable - function getMaskByOffsets(uint256 offsetLeft, uint256 offsetRight) internal pure returns (uint256 mask) { - // mask = ((1 << (256 - (offsetRight + offsetLeft))) - 1) << offsetRight; - // using assembly because (1 << 256) causes overflow - assembly { - mask := shl(offsetRight, sub(shl(sub(256, add(offsetRight, offsetLeft)), 1), 1)) - } - } - - // Returns slot value with updated packed variable. - function getUpdatedSlotValue(bytes32 curValue, uint256 varValue, uint256 offsetLeft, uint256 offsetRight) - internal - pure - returns (bytes32 newValue) - { - return bytes32((uint256(curValue) & ~getMaskByOffsets(offsetLeft, offsetRight)) | (varValue << offsetRight)); - } -} - -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 find(self, true); - } - - function find(StdStorage storage self, bool _clear) internal returns (uint256) { - return stdStorageSafe.find(self, _clear).slot; - } - - 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 with_calldata(StdStorage storage self, bytes memory _calldata) internal returns (StdStorage storage) { - return stdStorageSafe.with_calldata(self, _calldata); - } - - function enable_packed_slots(StdStorage storage self) internal returns (StdStorage storage) { - return stdStorageSafe.enable_packed_slots(self); - } - - function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { - return stdStorageSafe.depth(self, _depth); - } - - function clear(StdStorage storage self) internal { - stdStorageSafe.clear(self); - } - - 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; - bytes memory params = stdStorageSafe.getCallParams(self); - - if (!self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found) { - find(self, false); - } - FindData storage data = self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))]; - if ((data.offsetLeft + data.offsetRight) > 0) { - uint256 maxVal = 2 ** (256 - (data.offsetLeft + data.offsetRight)); - require( - uint256(set) < maxVal, - string( - abi.encodePacked( - "stdStorage find(StdStorage): Packed slot. We can't fit value greater than ", - vm.toString(maxVal) - ) - ) - ); - } - bytes32 curVal = vm.load(who, bytes32(data.slot)); - bytes32 valToSet = stdStorageSafe.getUpdatedSlotValue(curVal, uint256(set), data.offsetLeft, data.offsetRight); - - vm.store(who, bytes32(data.slot), valToSet); - - (bool success, bytes32 callResult) = stdStorageSafe.callTarget(self); - - if (!success || callResult != set) { - vm.store(who, bytes32(data.slot), curVal); - revert("stdStorage find(StdStorage): Failed to write value."); - } - clear(self); - } - - 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); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStyle.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStyle.sol deleted file mode 100644 index d371e0c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdStyle.sol +++ /dev/null @@ -1,333 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdToml.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdToml.sol deleted file mode 100644 index 7ad3be2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdToml.sol +++ /dev/null @@ -1,283 +0,0 @@ -// 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 TOML files -// To parse: -// ``` -// using stdToml for string; -// string memory toml = vm.readFile(""); -// toml.readUint(""); -// ``` -// To write: -// ``` -// using stdToml for string; -// string memory json = "json"; -// json.serialize("a", uint256(123)); -// string memory semiFinal = json.serialize("b", string("test")); -// string memory finalJson = json.serialize("c", semiFinal); -// finalJson.write(""); -// ``` - -library stdToml { - VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); - - function keyExists(string memory toml, string memory key) internal view returns (bool) { - return vm.keyExistsToml(toml, key); - } - - function parseRaw(string memory toml, string memory key) internal pure returns (bytes memory) { - return vm.parseToml(toml, key); - } - - function readUint(string memory toml, string memory key) internal pure returns (uint256) { - return vm.parseTomlUint(toml, key); - } - - function readUintArray(string memory toml, string memory key) internal pure returns (uint256[] memory) { - return vm.parseTomlUintArray(toml, key); - } - - function readInt(string memory toml, string memory key) internal pure returns (int256) { - return vm.parseTomlInt(toml, key); - } - - function readIntArray(string memory toml, string memory key) internal pure returns (int256[] memory) { - return vm.parseTomlIntArray(toml, key); - } - - function readBytes32(string memory toml, string memory key) internal pure returns (bytes32) { - return vm.parseTomlBytes32(toml, key); - } - - function readBytes32Array(string memory toml, string memory key) internal pure returns (bytes32[] memory) { - return vm.parseTomlBytes32Array(toml, key); - } - - function readString(string memory toml, string memory key) internal pure returns (string memory) { - return vm.parseTomlString(toml, key); - } - - function readStringArray(string memory toml, string memory key) internal pure returns (string[] memory) { - return vm.parseTomlStringArray(toml, key); - } - - function readAddress(string memory toml, string memory key) internal pure returns (address) { - return vm.parseTomlAddress(toml, key); - } - - function readAddressArray(string memory toml, string memory key) internal pure returns (address[] memory) { - return vm.parseTomlAddressArray(toml, key); - } - - function readBool(string memory toml, string memory key) internal pure returns (bool) { - return vm.parseTomlBool(toml, key); - } - - function readBoolArray(string memory toml, string memory key) internal pure returns (bool[] memory) { - return vm.parseTomlBoolArray(toml, key); - } - - function readBytes(string memory toml, string memory key) internal pure returns (bytes memory) { - return vm.parseTomlBytes(toml, key); - } - - function readBytesArray(string memory toml, string memory key) internal pure returns (bytes[] memory) { - return vm.parseTomlBytesArray(toml, key); - } - - function readUintOr(string memory toml, string memory key, uint256 defaultValue) internal view returns (uint256) { - return keyExists(toml, key) ? readUint(toml, key) : defaultValue; - } - - function readUintArrayOr(string memory toml, string memory key, uint256[] memory defaultValue) - internal - view - returns (uint256[] memory) - { - return keyExists(toml, key) ? readUintArray(toml, key) : defaultValue; - } - - function readIntOr(string memory toml, string memory key, int256 defaultValue) internal view returns (int256) { - return keyExists(toml, key) ? readInt(toml, key) : defaultValue; - } - - function readIntArrayOr(string memory toml, string memory key, int256[] memory defaultValue) - internal - view - returns (int256[] memory) - { - return keyExists(toml, key) ? readIntArray(toml, key) : defaultValue; - } - - function readBytes32Or(string memory toml, string memory key, bytes32 defaultValue) - internal - view - returns (bytes32) - { - return keyExists(toml, key) ? readBytes32(toml, key) : defaultValue; - } - - function readBytes32ArrayOr(string memory toml, string memory key, bytes32[] memory defaultValue) - internal - view - returns (bytes32[] memory) - { - return keyExists(toml, key) ? readBytes32Array(toml, key) : defaultValue; - } - - function readStringOr(string memory toml, string memory key, string memory defaultValue) - internal - view - returns (string memory) - { - return keyExists(toml, key) ? readString(toml, key) : defaultValue; - } - - function readStringArrayOr(string memory toml, string memory key, string[] memory defaultValue) - internal - view - returns (string[] memory) - { - return keyExists(toml, key) ? readStringArray(toml, key) : defaultValue; - } - - function readAddressOr(string memory toml, string memory key, address defaultValue) - internal - view - returns (address) - { - return keyExists(toml, key) ? readAddress(toml, key) : defaultValue; - } - - function readAddressArrayOr(string memory toml, string memory key, address[] memory defaultValue) - internal - view - returns (address[] memory) - { - return keyExists(toml, key) ? readAddressArray(toml, key) : defaultValue; - } - - function readBoolOr(string memory toml, string memory key, bool defaultValue) internal view returns (bool) { - return keyExists(toml, key) ? readBool(toml, key) : defaultValue; - } - - function readBoolArrayOr(string memory toml, string memory key, bool[] memory defaultValue) - internal - view - returns (bool[] memory) - { - return keyExists(toml, key) ? readBoolArray(toml, key) : defaultValue; - } - - function readBytesOr(string memory toml, string memory key, bytes memory defaultValue) - internal - view - returns (bytes memory) - { - return keyExists(toml, key) ? readBytes(toml, key) : defaultValue; - } - - function readBytesArrayOr(string memory toml, string memory key, bytes[] memory defaultValue) - internal - view - returns (bytes[] memory) - { - return keyExists(toml, key) ? readBytesArray(toml, key) : defaultValue; - } - - 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.writeToml(jsonKey, path); - } - - function write(string memory jsonKey, string memory path, string memory valueKey) internal { - vm.writeToml(jsonKey, path, valueKey); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol deleted file mode 100644 index 7106960..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol +++ /dev/null @@ -1,209 +0,0 @@ -// 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 pure virtual returns (uint256 result) { - result = _bound(x, min, max); - console2_log_StdUtils("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 pure virtual returns (int256 result) { - result = _bound(x, min, max); - console2_log_StdUtils("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) { - console2_log_StdUtils("computeCreateAddress is deprecated. Please use vm.computeCreateAddress instead."); - return vm.computeCreateAddress(deployer, nonce); - } - - function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) - internal - pure - virtual - returns (address) - { - console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead."); - return vm.computeCreate2Address(salt, initcodeHash, deployer); - } - - /// @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) { - console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead."); - return vm.computeCreate2Address(salt, initCodeHash); - } - - /// @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))); - } - - // This section is used to prevent the compilation of console, which shortens the compilation time when console is - // not used elsewhere. We also trick the compiler into letting us make the console log methods as `pure` to avoid - // any breaking changes to function signatures. - 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 = CONSOLE2_ADDRESS; - /// @solidity memory-safe-assembly - assembly { - let payloadStart := add(payload, 32) - let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) - } - } - - function console2_log_StdUtils(string memory p0) private pure { - _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); - } - - function console2_log_StdUtils(string memory p0, uint256 p1) private pure { - _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); - } - - function console2_log_StdUtils(string memory p0, string memory p1) private pure { - _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Test.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Test.sol deleted file mode 100644 index 5ff60ea..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Test.sol +++ /dev/null @@ -1,33 +0,0 @@ -// 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 {stdToml} from "./StdToml.sol"; -import {StdUtils} from "./StdUtils.sol"; -import {Vm} from "./Vm.sol"; - -// 📦 BOILERPLATE -import {TestBase} from "./Base.sol"; - -// ⭐️ TEST -abstract contract Test is TestBase, StdAssertions, StdChains, StdCheats, StdInvariant, StdUtils { - // Note: IS_TEST() must return true. - bool public IS_TEST = true; -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol deleted file mode 100644 index 2f69997..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol +++ /dev/null @@ -1,2263 +0,0 @@ -// Automatically @generated by scripts/vm.py. Do not modify manually. - -// SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity >=0.6.2 <0.9.0; -pragma experimental ABIEncoderV2; - -/// 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 { - /// A modification applied to either `msg.sender` or `tx.origin`. Returned by `readCallers`. - enum CallerMode { - // No caller modification is currently active. - None, - // A one time broadcast triggered by a `vm.broadcast()` call is currently active. - Broadcast, - // A recurrent broadcast triggered by a `vm.startBroadcast()` call is currently active. - RecurrentBroadcast, - // A one time prank triggered by a `vm.prank()` call is currently active. - Prank, - // A recurrent prank triggered by a `vm.startPrank()` call is currently active. - RecurrentPrank - } - - /// The kind of account access that occurred. - enum AccountAccessKind { - // The account was called. - Call, - // The account was called via delegatecall. - DelegateCall, - // The account was called via callcode. - CallCode, - // The account was called via staticcall. - StaticCall, - // The account was created. - Create, - // The account was selfdestructed. - SelfDestruct, - // Synthetic access indicating the current context has resumed after a previous sub-context (AccountAccess). - Resume, - // The account's balance was read. - Balance, - // The account's codesize was read. - Extcodesize, - // The account's codehash was read. - Extcodehash, - // The account's code was copied. - Extcodecopy - } - - /// Forge execution contexts. - enum ForgeContext { - // Test group execution context (test, coverage or snapshot). - TestGroup, - // `forge test` execution context. - Test, - // `forge coverage` execution context. - Coverage, - // `forge snapshot` execution context. - Snapshot, - // Script group execution context (dry run, broadcast or resume). - ScriptGroup, - // `forge script` execution context. - ScriptDryRun, - // `forge script --broadcast` execution context. - ScriptBroadcast, - // `forge script --resume` execution context. - ScriptResume, - // Unknown `forge` execution context. - Unknown - } - - /// The transaction type (`txType`) of the broadcast. - enum BroadcastTxType { - // Represents a CALL broadcast tx. - Call, - // Represents a CREATE broadcast tx. - Create, - // Represents a CREATE2 broadcast tx. - Create2 - } - - /// An Ethereum log. Returned by `getRecordedLogs`. - struct Log { - // The topics of the log, including the signature, if any. - bytes32[] topics; - // The raw data of the log. - bytes data; - // The address of the log's emitter. - address emitter; - } - - /// An RPC URL and its alias. Returned by `rpcUrlStructs`. - struct Rpc { - // The alias of the RPC URL. - string key; - // The RPC URL. - string url; - } - - /// An RPC log object. Returned by `eth_getLogs`. - struct EthGetLogs { - // The address of the log's emitter. - address emitter; - // The topics of the log, including the signature, if any. - bytes32[] topics; - // The raw data of the log. - bytes data; - // The block hash. - bytes32 blockHash; - // The block number. - uint64 blockNumber; - // The transaction hash. - bytes32 transactionHash; - // The transaction index in the block. - uint64 transactionIndex; - // The log index. - uint256 logIndex; - // Whether the log was removed. - bool removed; - } - - /// A single entry in a directory listing. Returned by `readDir`. - struct DirEntry { - // The error message, if any. - string errorMessage; - // The path of the entry. - string path; - // The depth of the entry. - uint64 depth; - // Whether the entry is a directory. - bool isDir; - // Whether the entry is a symlink. - bool isSymlink; - } - - /// Metadata information about a file. - /// This structure is returned from the `fsMetadata` function and represents known - /// metadata about a file such as its permissions, size, modification - /// times, etc. - struct FsMetadata { - // True if this metadata is for a directory. - bool isDir; - // True if this metadata is for a symlink. - bool isSymlink; - // The size of the file, in bytes, this metadata is for. - uint256 length; - // True if this metadata is for a readonly (unwritable) file. - bool readOnly; - // The last modification time listed in this metadata. - uint256 modified; - // The last access time of this metadata. - uint256 accessed; - // The creation time listed in this metadata. - uint256 created; - } - - /// A wallet with a public and private key. - struct Wallet { - // The wallet's address. - address addr; - // The wallet's public key `X`. - uint256 publicKeyX; - // The wallet's public key `Y`. - uint256 publicKeyY; - // The wallet's private key. - uint256 privateKey; - } - - /// The result of a `tryFfi` call. - struct FfiResult { - // The exit code of the call. - int32 exitCode; - // The optionally hex-decoded `stdout` data. - bytes stdout; - // The `stderr` data. - bytes stderr; - } - - /// Information on the chain and fork. - struct ChainInfo { - // The fork identifier. Set to zero if no fork is active. - uint256 forkId; - // The chain ID of the current fork. - uint256 chainId; - } - - /// The result of a `stopAndReturnStateDiff` call. - struct AccountAccess { - // The chain and fork the access occurred. - ChainInfo chainInfo; - // The kind of account access that determines what the account is. - // If kind is Call, DelegateCall, StaticCall or CallCode, then the account is the callee. - // If kind is Create, then the account is the newly created account. - // If kind is SelfDestruct, then the account is the selfdestruct recipient. - // If kind is a Resume, then account represents a account context that has resumed. - AccountAccessKind kind; - // The account that was accessed. - // It's either the account created, callee or a selfdestruct recipient for CREATE, CALL or SELFDESTRUCT. - address account; - // What accessed the account. - address accessor; - // If the account was initialized or empty prior to the access. - // An account is considered initialized if it has code, a - // non-zero nonce, or a non-zero balance. - bool initialized; - // The previous balance of the accessed account. - uint256 oldBalance; - // The potential new balance of the accessed account. - // That is, all balance changes are recorded here, even if reverts occurred. - uint256 newBalance; - // Code of the account deployed by CREATE. - bytes deployedCode; - // Value passed along with the account access - uint256 value; - // Input data provided to the CREATE or CALL - bytes data; - // If this access reverted in either the current or parent context. - bool reverted; - // An ordered list of storage accesses made during an account access operation. - StorageAccess[] storageAccesses; - // Call depth traversed during the recording of state differences - uint64 depth; - } - - /// The storage accessed during an `AccountAccess`. - struct StorageAccess { - // The account whose storage was accessed. - address account; - // The slot that was accessed. - bytes32 slot; - // If the access was a write. - bool isWrite; - // The previous value of the slot. - bytes32 previousValue; - // The new value of the slot. - bytes32 newValue; - // If the access was reverted. - bool reverted; - } - - /// Gas used. Returned by `lastCallGas`. - struct Gas { - // The gas limit of the call. - uint64 gasLimit; - // The total gas used. - uint64 gasTotalUsed; - // DEPRECATED: The amount of gas used for memory expansion. Ref: - uint64 gasMemoryUsed; - // The amount of gas refunded. - int64 gasRefunded; - // The amount of gas remaining. - uint64 gasRemaining; - } - - /// The result of the `stopDebugTraceRecording` call - struct DebugStep { - // The stack before executing the step of the run. - // stack\[0\] represents the top of the stack. - // and only stack data relevant to the opcode execution is contained. - uint256[] stack; - // The memory input data before executing the step of the run. - // only input data relevant to the opcode execution is contained. - // e.g. for MLOAD, it will have memory\[offset:offset+32\] copied here. - // the offset value can be get by the stack data. - bytes memoryInput; - // The opcode that was accessed. - uint8 opcode; - // The call depth of the step. - uint64 depth; - // Whether the call end up with out of gas error. - bool isOutOfGas; - // The contract address where the opcode is running - address contractAddr; - } - - /// Represents a transaction's broadcast details. - struct BroadcastTxSummary { - // The hash of the transaction that was broadcasted - bytes32 txHash; - // Represent the type of transaction among CALL, CREATE, CREATE2 - BroadcastTxType txType; - // The address of the contract that was called or created. - // This is address of the contract that is created if the txType is CREATE or CREATE2. - address contractAddress; - // The block number the transaction landed in. - uint64 blockNumber; - // Status of the transaction, retrieved from the transaction receipt. - bool success; - } - - /// Holds a signed EIP-7702 authorization for an authority account to delegate to an implementation. - struct SignedDelegation { - // The y-parity of the recovered secp256k1 signature (0 or 1). - uint8 v; - // First 32 bytes of the signature. - bytes32 r; - // Second 32 bytes of the signature. - bytes32 s; - // The current nonce of the authority account at signing time. - // Used to ensure signature can't be replayed after account nonce changes. - uint64 nonce; - // Address of the contract implementation that will be delegated to. - // Gets encoded into delegation code: 0xef0100 || implementation. - address implementation; - } - - /// Represents a "potential" revert reason from a single subsequent call when using `vm.assumeNoReverts`. - /// Reverts that match will result in a FOUNDRY::ASSUME rejection, whereas unmatched reverts will be surfaced - /// as normal. - struct PotentialRevert { - // The allowed origin of the revert opcode; address(0) allows reverts from any address - address reverter; - // When true, only matches on the beginning of the revert data, otherwise, matches on entire revert data - bool partialMatch; - // The data to use to match encountered reverts - bytes revertData; - } - - // ======== Crypto ======== - - /// 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); - - /// 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); - - /// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language - /// at the derivation path `m/44'/60'/0'/0/{index}`. - function deriveKey(string calldata mnemonic, uint32 index, string calldata language) - external - pure - returns (uint256 privateKey); - - /// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language - /// at `{derivationPath}{index}`. - function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index, string calldata language) - external - pure - returns (uint256 privateKey); - - /// Derives secp256r1 public key from the provided `privateKey`. - function publicKeyP256(uint256 privateKey) external pure returns (uint256 publicKeyX, uint256 publicKeyY); - - /// Adds a private key to the local forge wallet and returns the address. - function rememberKey(uint256 privateKey) external returns (address keyAddr); - - /// Derive a set number of wallets from a mnemonic at the derivation path `m/44'/60'/0'/0/{0..count}`. - /// The respective private keys are saved to the local forge wallet for later use and their addresses are returned. - function rememberKeys(string calldata mnemonic, string calldata derivationPath, uint32 count) - external - returns (address[] memory keyAddrs); - - /// Derive a set number of wallets from a mnemonic in the specified language at the derivation path `m/44'/60'/0'/0/{0..count}`. - /// The respective private keys are saved to the local forge wallet for later use and their addresses are returned. - function rememberKeys( - string calldata mnemonic, - string calldata derivationPath, - string calldata language, - uint32 count - ) external returns (address[] memory keyAddrs); - - /// Signs data with a `Wallet`. - /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the - /// signature's `s` value, and the recovery id `v` in a single bytes32. - /// This format reduces the signature size from 65 to 64 bytes. - function signCompact(Wallet calldata wallet, bytes32 digest) external returns (bytes32 r, bytes32 vs); - - /// Signs `digest` with `privateKey` using the secp256k1 curve. - /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the - /// signature's `s` value, and the recovery id `v` in a single bytes32. - /// This format reduces the signature size from 65 to 64 bytes. - function signCompact(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 vs); - - /// Signs `digest` with signer provided to script using the secp256k1 curve. - /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the - /// signature's `s` value, and the recovery id `v` in a single bytes32. - /// This format reduces the signature size from 65 to 64 bytes. - /// If `--sender` is provided, the signer with provided address is used, otherwise, - /// if exactly one signer is provided to the script, that signer is used. - /// Raises error if signer passed through `--sender` does not match any unlocked signers or - /// if `--sender` is not provided and not exactly one signer is passed to the script. - function signCompact(bytes32 digest) external pure returns (bytes32 r, bytes32 vs); - - /// Signs `digest` with signer provided to script using the secp256k1 curve. - /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the - /// signature's `s` value, and the recovery id `v` in a single bytes32. - /// This format reduces the signature size from 65 to 64 bytes. - /// Raises error if none of the signers passed into the script have provided address. - function signCompact(address signer, bytes32 digest) external pure returns (bytes32 r, bytes32 vs); - - /// Signs `digest` with `privateKey` using the secp256r1 curve. - function signP256(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 s); - - /// Signs data with a `Wallet`. - function sign(Wallet calldata wallet, bytes32 digest) external returns (uint8 v, bytes32 r, bytes32 s); - - /// Signs `digest` with `privateKey` using the secp256k1 curve. - function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); - - /// Signs `digest` with signer provided to script using the secp256k1 curve. - /// If `--sender` is provided, the signer with provided address is used, otherwise, - /// if exactly one signer is provided to the script, that signer is used. - /// Raises error if signer passed through `--sender` does not match any unlocked signers or - /// if `--sender` is not provided and not exactly one signer is passed to the script. - function sign(bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); - - /// Signs `digest` with signer provided to script using the secp256k1 curve. - /// Raises error if none of the signers passed into the script have provided address. - function sign(address signer, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); - - // ======== Environment ======== - - /// Gets the environment variable `name` and parses it as `address`. - /// Reverts if the variable was not found or could not be parsed. - function envAddress(string calldata name) external view returns (address value); - - /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value); - - /// Gets the environment variable `name` and parses it as `bool`. - /// Reverts if the variable was not found or could not be parsed. - function envBool(string calldata name) external view returns (bool value); - - /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value); - - /// Gets the environment variable `name` and parses it as `bytes32`. - /// Reverts if the variable was not found or could not be parsed. - function envBytes32(string calldata name) external view returns (bytes32 value); - - /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value); - - /// Gets the environment variable `name` and parses it as `bytes`. - /// Reverts if the variable was not found or could not be parsed. - function envBytes(string calldata name) external view returns (bytes memory value); - - /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value); - - /// Gets the environment variable `name` and returns true if it exists, else returns false. - function envExists(string calldata name) external view returns (bool result); - - /// Gets the environment variable `name` and parses it as `int256`. - /// Reverts if the variable was not found or could not be parsed. - function envInt(string calldata name) external view returns (int256 value); - - /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value); - - /// Gets the environment variable `name` and parses it as `bool`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, bool defaultValue) external view returns (bool value); - - /// Gets the environment variable `name` and parses it as `uint256`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, uint256 defaultValue) external view returns (uint256 value); - - /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, address[] calldata defaultValue) - external - view - returns (address[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue) - external - view - returns (bytes32[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, string[] calldata defaultValue) - external - view - returns (string[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue) - external - view - returns (bytes[] memory value); - - /// Gets the environment variable `name` and parses it as `int256`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, int256 defaultValue) external view returns (int256 value); - - /// Gets the environment variable `name` and parses it as `address`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, address defaultValue) external view returns (address value); - - /// Gets the environment variable `name` and parses it as `bytes32`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, bytes32 defaultValue) external view returns (bytes32 value); - - /// Gets the environment variable `name` and parses it as `string`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata defaultValue) external view returns (string memory value); - - /// Gets the environment variable `name` and parses it as `bytes`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, bytes calldata defaultValue) external view returns (bytes memory value); - - /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue) - external - view - returns (bool[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue) - external - view - returns (uint256[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue) - external - view - returns (int256[] memory value); - - /// Gets the environment variable `name` and parses it as `string`. - /// Reverts if the variable was not found or could not be parsed. - function envString(string calldata name) external view returns (string memory value); - - /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envString(string calldata name, string calldata delim) external view returns (string[] memory value); - - /// Gets the environment variable `name` and parses it as `uint256`. - /// Reverts if the variable was not found or could not be parsed. - function envUint(string calldata name) external view returns (uint256 value); - - /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value); - - /// Returns true if `forge` command was executed in given context. - function isContext(ForgeContext context) external view returns (bool result); - - /// Sets environment variables. - function setEnv(string calldata name, string calldata value) external; - - // ======== EVM ======== - - /// 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); - - /// Gets the address for a given private key. - function addr(uint256 privateKey) external pure returns (address keyAddr); - - /// Gets all the logs according to specified filter. - function eth_getLogs(uint256 fromBlock, uint256 toBlock, address target, bytes32[] calldata topics) - external - returns (EthGetLogs[] memory logs); - - /// Gets the current `block.blobbasefee`. - /// You should use this instead of `block.blobbasefee` if you use `vm.blobBaseFee`, as `block.blobbasefee` is assumed to be constant across a transaction, - /// and as a result will get optimized out by the compiler. - /// See https://github.com/foundry-rs/foundry/issues/6180 - function getBlobBaseFee() external view returns (uint256 blobBaseFee); - - /// Gets the current `block.number`. - /// You should use this instead of `block.number` if you use `vm.roll`, as `block.number` is assumed to be constant across a transaction, - /// and as a result will get optimized out by the compiler. - /// See https://github.com/foundry-rs/foundry/issues/6180 - function getBlockNumber() external view returns (uint256 height); - - /// Gets the current `block.timestamp`. - /// You should use this instead of `block.timestamp` if you use `vm.warp`, as `block.timestamp` is assumed to be constant across a transaction, - /// and as a result will get optimized out by the compiler. - /// See https://github.com/foundry-rs/foundry/issues/6180 - function getBlockTimestamp() external view returns (uint256 timestamp); - - /// 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); - - /// 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 nonce of an account. - function getNonce(address account) external view returns (uint64 nonce); - - /// Get the nonce of a `Wallet`. - function getNonce(Wallet calldata wallet) external returns (uint64 nonce); - - /// Gets all the recorded logs. - function getRecordedLogs() external returns (Log[] memory logs); - - /// Returns state diffs from current `vm.startStateDiffRecording` session. - function getStateDiff() external view returns (string memory diff); - - /// Returns state diffs from current `vm.startStateDiffRecording` session, in json format. - function getStateDiffJson() external view returns (string memory diff); - - /// Gets the gas used in the last call from the callee perspective. - function lastCallGas() external view returns (Gas memory gas); - - /// Loads a storage slot from an address. - function load(address target, bytes32 slot) external view returns (bytes32 data); - - /// Pauses gas metering (i.e. gas usage is not counted). Noop if already paused. - function pauseGasMetering() external; - - /// Records all storage reads and writes. - function record() external; - - /// Record all the transaction logs. - function recordLogs() external; - - /// Reset gas metering (i.e. gas usage is set to gas limit). - function resetGasMetering() external; - - /// Resumes gas metering (i.e. gas usage is counted again). Noop if already on. - function resumeGasMetering() external; - - /// Performs an Ethereum JSON-RPC request to the current fork URL. - function rpc(string calldata method, string calldata params) external returns (bytes memory data); - - /// Performs an Ethereum JSON-RPC request to the given endpoint. - function rpc(string calldata urlOrAlias, string calldata method, string calldata params) - external - returns (bytes memory data); - - /// Records the debug trace during the run. - function startDebugTraceRecording() external; - - /// Starts recording all map SSTOREs for later retrieval. - function startMappingRecording() external; - - /// Record all account accesses as part of CREATE, CALL or SELFDESTRUCT opcodes in order, - /// along with the context of the calls - function startStateDiffRecording() external; - - /// Stop debug trace recording and returns the recorded debug trace. - function stopAndReturnDebugTraceRecording() external returns (DebugStep[] memory step); - - /// Returns an ordered array of all account accesses from a `vm.startStateDiffRecording` session. - function stopAndReturnStateDiff() external returns (AccountAccess[] memory accountAccesses); - - /// Stops recording all map SSTOREs for later retrieval and clears the recorded data. - function stopMappingRecording() external; - - // ======== Filesystem ======== - - /// 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; - - /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the - /// artifact in the form of :: where and parts are optional. - function deployCode(string calldata artifactPath) external returns (address deployedAddress); - - /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the - /// artifact in the form of :: where and parts are optional. - /// Additionally accepts abi-encoded constructor arguments. - function deployCode(string calldata artifactPath, bytes calldata constructorArgs) - external - returns (address deployedAddress); - - /// Returns true if the given path points to an existing entity, else returns false. - function exists(string calldata path) external view returns (bool result); - - /// Performs a foreign function call via the terminal. - function ffi(string[] calldata commandInput) external returns (bytes memory 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); - - /// Gets the artifact path from code (aka. creation code). - function getArtifactPathByCode(bytes calldata code) external view returns (string memory path); - - /// Gets the artifact path from deployed code (aka. runtime code). - function getArtifactPathByDeployedCode(bytes calldata deployedCode) external view returns (string memory path); - - /// Returns the most recent broadcast for the given contract on `chainId` matching `txType`. - /// For example: - /// The most recent deployment can be fetched by passing `txType` as `CREATE` or `CREATE2`. - /// The most recent call can be fetched by passing `txType` as `CALL`. - function getBroadcast(string calldata contractName, uint64 chainId, BroadcastTxType txType) - external - view - returns (BroadcastTxSummary memory); - - /// Returns all broadcasts for the given contract on `chainId` with the specified `txType`. - /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. - function getBroadcasts(string calldata contractName, uint64 chainId, BroadcastTxType txType) - external - view - returns (BroadcastTxSummary[] memory); - - /// Returns all broadcasts for the given contract on `chainId`. - /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. - function getBroadcasts(string calldata contractName, uint64 chainId) - external - view - returns (BroadcastTxSummary[] memory); - - /// Gets the creation bytecode from an artifact file. Takes in the relative path to the json file or the path to the - /// artifact in the form of :: where and parts are optional. - 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 or the path to the - /// artifact in the form of :: where and parts are optional. - function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); - - /// Returns the most recent deployment for the current `chainId`. - function getDeployment(string calldata contractName) external view returns (address deployedAddress); - - /// Returns the most recent deployment for the given contract on `chainId` - function getDeployment(string calldata contractName, uint64 chainId) - external - view - returns (address deployedAddress); - - /// Returns all deployments for the given contract on `chainId` - /// Sorted in descending order of deployment time i.e descending order of BroadcastTxSummary.blockNumber. - /// The most recent deployment is the first element, and the oldest is the last. - function getDeployments(string calldata contractName, uint64 chainId) - external - view - returns (address[] memory deployedAddresses); - - /// Returns true if the path exists on disk and is pointing at a directory, else returns false. - function isDir(string calldata path) external view 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 view returns (bool result); - - /// Get the path of the current project root. - function projectRoot() external view returns (string memory path); - - /// Prompts the user for a string value in the terminal. - function prompt(string calldata promptText) external returns (string memory input); - - /// Prompts the user for an address in the terminal. - function promptAddress(string calldata promptText) external returns (address); - - /// Prompts the user for a hidden string value in the terminal. - function promptSecret(string calldata promptText) external returns (string memory input); - - /// Prompts the user for hidden uint256 in the terminal (usually pk). - function promptSecretUint(string calldata promptText) external returns (uint256); - - /// Prompts the user for uint256 in the terminal. - function promptUint(string calldata promptText) external returns (uint256); - - /// Reads the directory at the given path recursively, up to `maxDepth`. - /// `maxDepth` defaults to 1, meaning only the direct children of the given directory will be returned. - /// Follows symbolic links if `followLinks` is true. - function readDir(string calldata path) external view returns (DirEntry[] memory entries); - - /// See `readDir(string)`. - function readDir(string calldata path, uint64 maxDepth) external view returns (DirEntry[] memory entries); - - /// See `readDir(string)`. - 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; - - /// 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); - - /// Returns the time since unix epoch in milliseconds. - function unixTime() external view returns (uint256 milliseconds); - - /// 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; - - // ======== JSON ======== - - /// Checks if `key` exists in a JSON object. - function keyExistsJson(string calldata json, string calldata key) external view returns (bool); - - /// Parses a string of JSON data at `key` and coerces it to `address`. - function parseJsonAddress(string calldata json, string calldata key) external pure returns (address); - - /// Parses a string of JSON data at `key` and coerces it to `address[]`. - function parseJsonAddressArray(string calldata json, string calldata key) - external - pure - returns (address[] memory); - - /// Parses a string of JSON data at `key` and coerces it to `bool`. - function parseJsonBool(string calldata json, string calldata key) external pure returns (bool); - - /// Parses a string of JSON data at `key` and coerces it to `bool[]`. - function parseJsonBoolArray(string calldata json, string calldata key) external pure returns (bool[] memory); - - /// Parses a string of JSON data at `key` and coerces it to `bytes`. - function parseJsonBytes(string calldata json, string calldata key) external pure returns (bytes memory); - - /// Parses a string of JSON data at `key` and coerces it to `bytes32`. - function parseJsonBytes32(string calldata json, string calldata key) external pure returns (bytes32); - - /// Parses a string of JSON data at `key` and coerces it to `bytes32[]`. - function parseJsonBytes32Array(string calldata json, string calldata key) - external - pure - returns (bytes32[] memory); - - /// Parses a string of JSON data at `key` and coerces it to `bytes[]`. - function parseJsonBytesArray(string calldata json, string calldata key) external pure returns (bytes[] memory); - - /// Parses a string of JSON data at `key` and coerces it to `int256`. - function parseJsonInt(string calldata json, string calldata key) external pure returns (int256); - - /// Parses a string of JSON data at `key` and coerces it to `int256[]`. - function parseJsonIntArray(string calldata json, string calldata key) external pure returns (int256[] memory); - - /// Returns an array of all the keys in a JSON object. - function parseJsonKeys(string calldata json, string calldata key) external pure returns (string[] memory keys); - - /// Parses a string of JSON data at `key` and coerces it to `string`. - function parseJsonString(string calldata json, string calldata key) external pure returns (string memory); - - /// Parses a string of JSON data at `key` and coerces it to `string[]`. - function parseJsonStringArray(string calldata json, string calldata key) external pure returns (string[] memory); - - /// Parses a string of JSON data at `key` and coerces it to type array corresponding to `typeDescription`. - function parseJsonTypeArray(string calldata json, string calldata key, string calldata typeDescription) - external - pure - returns (bytes memory); - - /// Parses a string of JSON data and coerces it to type corresponding to `typeDescription`. - function parseJsonType(string calldata json, string calldata typeDescription) - external - pure - returns (bytes memory); - - /// Parses a string of JSON data at `key` and coerces it to type corresponding to `typeDescription`. - function parseJsonType(string calldata json, string calldata key, string calldata typeDescription) - external - pure - returns (bytes memory); - - /// Parses a string of JSON data at `key` and coerces it to `uint256`. - function parseJsonUint(string calldata json, string calldata key) external pure returns (uint256); - - /// Parses a string of JSON data at `key` and coerces it to `uint256[]`. - function parseJsonUintArray(string calldata json, string calldata key) external pure returns (uint256[] memory); - - /// ABI-encodes a JSON object. - function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData); - - /// ABI-encodes a JSON object at `key`. - function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData); - - /// See `serializeJson`. - function serializeAddress(string calldata objectKey, string calldata valueKey, address value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBool(string calldata objectKey, string calldata valueKey, bool value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeInt(string calldata objectKey, string calldata valueKey, int256 value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values) - external - returns (string memory json); - - /// Serializes a key and value to a JSON object stored in-memory that can be later written to a file. - /// 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); - - /// See `serializeJson`. - function serializeJsonType(string calldata typeDescription, bytes calldata value) - external - pure - returns (string memory json); - - /// See `serializeJson`. - function serializeJsonType( - string calldata objectKey, - string calldata valueKey, - string calldata typeDescription, - bytes calldata value - ) external returns (string memory json); - - /// See `serializeJson`. - function serializeString(string calldata objectKey, string calldata valueKey, string calldata value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeUintToHex(string calldata objectKey, string calldata valueKey, uint256 value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) - external - returns (string memory json); - - /// 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; - - /// Checks if `key` exists in a JSON object - /// `keyExists` is being deprecated in favor of `keyExistsJson`. It will be removed in future versions. - function keyExists(string calldata json, string calldata key) external view returns (bool); - - // ======== Scripting ======== - - /// Designate the next call as an EIP-7702 transaction - function attachDelegation(SignedDelegation calldata signedDelegation) external; - - /// Takes a signed transaction and broadcasts it to the network. - function broadcastRawTransaction(bytes calldata data) external; - - /// Has the next call (at this call depth only) create transactions that can later be signed and sent onchain. - /// Broadcasting address is determined by checking the following in order: - /// 1. If `--sender` argument was provided, that address is used. - /// 2. If exactly one signer (e.g. private key, hw wallet, keystore) is set when `forge broadcast` is invoked, that signer is used. - /// 3. Otherwise, default foundry sender (1804c8AB1F12E6bbf3894d4083f33e07309d1f38) is used. - 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; - - /// Returns addresses of available unlocked wallets in the script environment. - function getWallets() external returns (address[] memory wallets); - - /// Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction - function signAndAttachDelegation(address implementation, uint256 privateKey) - external - returns (SignedDelegation memory signedDelegation); - - /// Sign an EIP-7702 authorization for delegation - function signDelegation(address implementation, uint256 privateKey) - external - returns (SignedDelegation memory signedDelegation); - - /// Has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain. - /// Broadcasting address is determined by checking the following in order: - /// 1. If `--sender` argument was provided, that address is used. - /// 2. If exactly one signer (e.g. private key, hw wallet, keystore) is set when `forge broadcast` is invoked, that signer is used. - /// 3. Otherwise, default foundry sender (1804c8AB1F12E6bbf3894d4083f33e07309d1f38) is used. - 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; - - // ======== String ======== - - /// Returns true if `search` is found in `subject`, false otherwise. - function contains(string calldata subject, string calldata search) external returns (bool result); - - /// Returns the index of the first occurrence of a `key` in an `input` string. - /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `key` is not found. - /// Returns 0 in case of an empty `key`. - function indexOf(string calldata input, string calldata key) external pure returns (uint256); - - /// Parses the given `string` into an `address`. - function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue); - - /// Parses the given `string` into a `bool`. - function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue); - - /// Parses the given `string` into `bytes`. - function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue); - - /// Parses the given `string` into a `bytes32`. - function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue); - - /// Parses the given `string` into a `int256`. - function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue); - - /// Parses the given `string` into a `uint256`. - function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue); - - /// Replaces occurrences of `from` in the given `string` with `to`. - function replace(string calldata input, string calldata from, string calldata to) - external - pure - returns (string memory output); - - /// Splits the given `string` into an array of strings divided by the `delimiter`. - function split(string calldata input, string calldata delimiter) external pure returns (string[] memory outputs); - - /// Converts the given `string` value to Lowercase. - function toLowercase(string calldata input) external pure returns (string memory output); - - /// Converts the given value to a `string`. - function toString(address value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(bytes calldata value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(bytes32 value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(bool value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(uint256 value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(int256 value) external pure returns (string memory stringifiedValue); - - /// Converts the given `string` value to Uppercase. - function toUppercase(string calldata input) external pure returns (string memory output); - - /// Trims leading and trailing whitespace from the given `string` value. - function trim(string calldata input) external pure returns (string memory output); - - // ======== Testing ======== - - /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. - /// Formats values with decimals in failure message. - function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertApproxEqAbsDecimal( - uint256 left, - uint256 right, - uint256 maxDelta, - uint256 decimals, - string calldata error - ) external pure; - - /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. - /// Formats values with decimals in failure message. - function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertApproxEqAbsDecimal( - int256 left, - int256 right, - uint256 maxDelta, - uint256 decimals, - string calldata error - ) external pure; - - /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. - function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) external pure; - - /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. - /// Includes error message into revert string on failure. - function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string calldata error) external pure; - - /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. - function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) external pure; - - /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. - /// Includes error message into revert string on failure. - function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string calldata error) external pure; - - /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Formats values with decimals in failure message. - function assertApproxEqRelDecimal(uint256 left, uint256 right, uint256 maxPercentDelta, uint256 decimals) - external - pure; - - /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertApproxEqRelDecimal( - uint256 left, - uint256 right, - uint256 maxPercentDelta, - uint256 decimals, - string calldata error - ) external pure; - - /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Formats values with decimals in failure message. - function assertApproxEqRelDecimal(int256 left, int256 right, uint256 maxPercentDelta, uint256 decimals) - external - pure; - - /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertApproxEqRelDecimal( - int256 left, - int256 right, - uint256 maxPercentDelta, - uint256 decimals, - string calldata error - ) external pure; - - /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta) external pure; - - /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Includes error message into revert string on failure. - function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta, string calldata error) - external - pure; - - /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) external pure; - - /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Includes error message into revert string on failure. - function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta, string calldata error) - external - pure; - - /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message. - function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message. - /// Includes error message into revert string on failure. - function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Asserts that two `int256` values are equal, formatting them with decimals in failure message. - function assertEqDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Asserts that two `int256` values are equal, formatting them with decimals in failure message. - /// Includes error message into revert string on failure. - function assertEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Asserts that two `bool` values are equal. - function assertEq(bool left, bool right) external pure; - - /// Asserts that two `bool` values are equal and includes error message into revert string on failure. - function assertEq(bool left, bool right, string calldata error) external pure; - - /// Asserts that two `string` values are equal. - function assertEq(string calldata left, string calldata right) external pure; - - /// Asserts that two `string` values are equal and includes error message into revert string on failure. - function assertEq(string calldata left, string calldata right, string calldata error) external pure; - - /// Asserts that two `bytes` values are equal. - function assertEq(bytes calldata left, bytes calldata right) external pure; - - /// Asserts that two `bytes` values are equal and includes error message into revert string on failure. - function assertEq(bytes calldata left, bytes calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bool` values are equal. - function assertEq(bool[] calldata left, bool[] calldata right) external pure; - - /// Asserts that two arrays of `bool` values are equal and includes error message into revert string on failure. - function assertEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `uint256 values are equal. - function assertEq(uint256[] calldata left, uint256[] calldata right) external pure; - - /// Asserts that two arrays of `uint256` values are equal and includes error message into revert string on failure. - function assertEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `int256` values are equal. - function assertEq(int256[] calldata left, int256[] calldata right) external pure; - - /// Asserts that two arrays of `int256` values are equal and includes error message into revert string on failure. - function assertEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure; - - /// Asserts that two `uint256` values are equal. - function assertEq(uint256 left, uint256 right) external pure; - - /// Asserts that two arrays of `address` values are equal. - function assertEq(address[] calldata left, address[] calldata right) external pure; - - /// Asserts that two arrays of `address` values are equal and includes error message into revert string on failure. - function assertEq(address[] calldata left, address[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bytes32` values are equal. - function assertEq(bytes32[] calldata left, bytes32[] calldata right) external pure; - - /// Asserts that two arrays of `bytes32` values are equal and includes error message into revert string on failure. - function assertEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `string` values are equal. - function assertEq(string[] calldata left, string[] calldata right) external pure; - - /// Asserts that two arrays of `string` values are equal and includes error message into revert string on failure. - function assertEq(string[] calldata left, string[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bytes` values are equal. - function assertEq(bytes[] calldata left, bytes[] calldata right) external pure; - - /// Asserts that two arrays of `bytes` values are equal and includes error message into revert string on failure. - function assertEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure; - - /// Asserts that two `uint256` values are equal and includes error message into revert string on failure. - function assertEq(uint256 left, uint256 right, string calldata error) external pure; - - /// Asserts that two `int256` values are equal. - function assertEq(int256 left, int256 right) external pure; - - /// Asserts that two `int256` values are equal and includes error message into revert string on failure. - function assertEq(int256 left, int256 right, string calldata error) external pure; - - /// Asserts that two `address` values are equal. - function assertEq(address left, address right) external pure; - - /// Asserts that two `address` values are equal and includes error message into revert string on failure. - function assertEq(address left, address right, string calldata error) external pure; - - /// Asserts that two `bytes32` values are equal. - function assertEq(bytes32 left, bytes32 right) external pure; - - /// Asserts that two `bytes32` values are equal and includes error message into revert string on failure. - function assertEq(bytes32 left, bytes32 right, string calldata error) external pure; - - /// Asserts that the given condition is false. - function assertFalse(bool condition) external pure; - - /// Asserts that the given condition is false and includes error message into revert string on failure. - function assertFalse(bool condition, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than or equal to second. - /// Formats values with decimals in failure message. - function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than or equal to second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be greater than or equal to second. - /// Formats values with decimals in failure message. - function assertGeDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects first value to be greater than or equal to second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertGeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than or equal to second. - function assertGe(uint256 left, uint256 right) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than or equal to second. - /// Includes error message into revert string on failure. - function assertGe(uint256 left, uint256 right, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be greater than or equal to second. - function assertGe(int256 left, int256 right) external pure; - - /// Compares two `int256` values. Expects first value to be greater than or equal to second. - /// Includes error message into revert string on failure. - function assertGe(int256 left, int256 right, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than second. - /// Formats values with decimals in failure message. - function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be greater than second. - /// Formats values with decimals in failure message. - function assertGtDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects first value to be greater than second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertGtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than second. - function assertGt(uint256 left, uint256 right) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than second. - /// Includes error message into revert string on failure. - function assertGt(uint256 left, uint256 right, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be greater than second. - function assertGt(int256 left, int256 right) external pure; - - /// Compares two `int256` values. Expects first value to be greater than second. - /// Includes error message into revert string on failure. - function assertGt(int256 left, int256 right, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be less than or equal to second. - /// Formats values with decimals in failure message. - function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects first value to be less than or equal to second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be less than or equal to second. - /// Formats values with decimals in failure message. - function assertLeDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects first value to be less than or equal to second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertLeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be less than or equal to second. - function assertLe(uint256 left, uint256 right) external pure; - - /// Compares two `uint256` values. Expects first value to be less than or equal to second. - /// Includes error message into revert string on failure. - function assertLe(uint256 left, uint256 right, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be less than or equal to second. - function assertLe(int256 left, int256 right) external pure; - - /// Compares two `int256` values. Expects first value to be less than or equal to second. - /// Includes error message into revert string on failure. - function assertLe(int256 left, int256 right, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be less than second. - /// Formats values with decimals in failure message. - function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects first value to be less than second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be less than second. - /// Formats values with decimals in failure message. - function assertLtDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects first value to be less than second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertLtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be less than second. - function assertLt(uint256 left, uint256 right) external pure; - - /// Compares two `uint256` values. Expects first value to be less than second. - /// Includes error message into revert string on failure. - function assertLt(uint256 left, uint256 right, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be less than second. - function assertLt(int256 left, int256 right) external pure; - - /// Compares two `int256` values. Expects first value to be less than second. - /// Includes error message into revert string on failure. - function assertLt(int256 left, int256 right, string calldata error) external pure; - - /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message. - function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message. - /// Includes error message into revert string on failure. - function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message. - function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message. - /// Includes error message into revert string on failure. - function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Asserts that two `bool` values are not equal. - function assertNotEq(bool left, bool right) external pure; - - /// Asserts that two `bool` values are not equal and includes error message into revert string on failure. - function assertNotEq(bool left, bool right, string calldata error) external pure; - - /// Asserts that two `string` values are not equal. - function assertNotEq(string calldata left, string calldata right) external pure; - - /// Asserts that two `string` values are not equal and includes error message into revert string on failure. - function assertNotEq(string calldata left, string calldata right, string calldata error) external pure; - - /// Asserts that two `bytes` values are not equal. - function assertNotEq(bytes calldata left, bytes calldata right) external pure; - - /// Asserts that two `bytes` values are not equal and includes error message into revert string on failure. - function assertNotEq(bytes calldata left, bytes calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bool` values are not equal. - function assertNotEq(bool[] calldata left, bool[] calldata right) external pure; - - /// Asserts that two arrays of `bool` values are not equal and includes error message into revert string on failure. - function assertNotEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `uint256` values are not equal. - function assertNotEq(uint256[] calldata left, uint256[] calldata right) external pure; - - /// Asserts that two arrays of `uint256` values are not equal and includes error message into revert string on failure. - function assertNotEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `int256` values are not equal. - function assertNotEq(int256[] calldata left, int256[] calldata right) external pure; - - /// Asserts that two arrays of `int256` values are not equal and includes error message into revert string on failure. - function assertNotEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure; - - /// Asserts that two `uint256` values are not equal. - function assertNotEq(uint256 left, uint256 right) external pure; - - /// Asserts that two arrays of `address` values are not equal. - function assertNotEq(address[] calldata left, address[] calldata right) external pure; - - /// Asserts that two arrays of `address` values are not equal and includes error message into revert string on failure. - function assertNotEq(address[] calldata left, address[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bytes32` values are not equal. - function assertNotEq(bytes32[] calldata left, bytes32[] calldata right) external pure; - - /// Asserts that two arrays of `bytes32` values are not equal and includes error message into revert string on failure. - function assertNotEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `string` values are not equal. - function assertNotEq(string[] calldata left, string[] calldata right) external pure; - - /// Asserts that two arrays of `string` values are not equal and includes error message into revert string on failure. - function assertNotEq(string[] calldata left, string[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bytes` values are not equal. - function assertNotEq(bytes[] calldata left, bytes[] calldata right) external pure; - - /// Asserts that two arrays of `bytes` values are not equal and includes error message into revert string on failure. - function assertNotEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure; - - /// Asserts that two `uint256` values are not equal and includes error message into revert string on failure. - function assertNotEq(uint256 left, uint256 right, string calldata error) external pure; - - /// Asserts that two `int256` values are not equal. - function assertNotEq(int256 left, int256 right) external pure; - - /// Asserts that two `int256` values are not equal and includes error message into revert string on failure. - function assertNotEq(int256 left, int256 right, string calldata error) external pure; - - /// Asserts that two `address` values are not equal. - function assertNotEq(address left, address right) external pure; - - /// Asserts that two `address` values are not equal and includes error message into revert string on failure. - function assertNotEq(address left, address right, string calldata error) external pure; - - /// Asserts that two `bytes32` values are not equal. - function assertNotEq(bytes32 left, bytes32 right) external pure; - - /// Asserts that two `bytes32` values are not equal and includes error message into revert string on failure. - function assertNotEq(bytes32 left, bytes32 right, string calldata error) external pure; - - /// Asserts that the given condition is true. - function assertTrue(bool condition) external pure; - - /// Asserts that the given condition is true and includes error message into revert string on failure. - function assertTrue(bool condition, string calldata error) external pure; - - /// If the condition is false, discard this run's fuzz inputs and generate new ones. - function assume(bool condition) external pure; - - /// Discard this run's fuzz inputs and generate new ones if next call reverted. - function assumeNoRevert() external pure; - - /// Discard this run's fuzz inputs and generate new ones if next call reverts with the potential revert parameters. - function assumeNoRevert(PotentialRevert calldata potentialRevert) external pure; - - /// Discard this run's fuzz inputs and generate new ones if next call reverts with the any of the potential revert parameters. - function assumeNoRevert(PotentialRevert[] calldata potentialReverts) external pure; - - /// Writes a breakpoint to jump to in the debugger. - function breakpoint(string calldata char) external pure; - - /// Writes a conditional breakpoint to jump to in the debugger. - function breakpoint(string calldata char, bool value) external pure; - - /// Returns the Foundry version. - /// Format: -+.. - /// Sample output: 0.3.0-nightly+3cb96bde9b.1737036656.debug - /// Note: Build timestamps may vary slightly across platforms due to separate CI jobs. - /// For reliable version comparisons, use UNIX format (e.g., >= 1700000000) - /// to compare timestamps while ignoring minor time differences. - function getFoundryVersion() external view returns (string memory version); - - /// 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 as structs. - function rpcUrlStructs() external view returns (Rpc[] memory urls); - - /// Returns all rpc urls and their aliases `[alias, url][]`. - function rpcUrls() external view returns (string[2][] memory urls); - - /// Suspends execution of the main thread for `duration` milliseconds. - function sleep(uint256 duration) external; - - // ======== Toml ======== - - /// Checks if `key` exists in a TOML table. - function keyExistsToml(string calldata toml, string calldata key) external view returns (bool); - - /// Parses a string of TOML data at `key` and coerces it to `address`. - function parseTomlAddress(string calldata toml, string calldata key) external pure returns (address); - - /// Parses a string of TOML data at `key` and coerces it to `address[]`. - function parseTomlAddressArray(string calldata toml, string calldata key) - external - pure - returns (address[] memory); - - /// Parses a string of TOML data at `key` and coerces it to `bool`. - function parseTomlBool(string calldata toml, string calldata key) external pure returns (bool); - - /// Parses a string of TOML data at `key` and coerces it to `bool[]`. - function parseTomlBoolArray(string calldata toml, string calldata key) external pure returns (bool[] memory); - - /// Parses a string of TOML data at `key` and coerces it to `bytes`. - function parseTomlBytes(string calldata toml, string calldata key) external pure returns (bytes memory); - - /// Parses a string of TOML data at `key` and coerces it to `bytes32`. - function parseTomlBytes32(string calldata toml, string calldata key) external pure returns (bytes32); - - /// Parses a string of TOML data at `key` and coerces it to `bytes32[]`. - function parseTomlBytes32Array(string calldata toml, string calldata key) - external - pure - returns (bytes32[] memory); - - /// Parses a string of TOML data at `key` and coerces it to `bytes[]`. - function parseTomlBytesArray(string calldata toml, string calldata key) external pure returns (bytes[] memory); - - /// Parses a string of TOML data at `key` and coerces it to `int256`. - function parseTomlInt(string calldata toml, string calldata key) external pure returns (int256); - - /// Parses a string of TOML data at `key` and coerces it to `int256[]`. - function parseTomlIntArray(string calldata toml, string calldata key) external pure returns (int256[] memory); - - /// Returns an array of all the keys in a TOML table. - function parseTomlKeys(string calldata toml, string calldata key) external pure returns (string[] memory keys); - - /// Parses a string of TOML data at `key` and coerces it to `string`. - function parseTomlString(string calldata toml, string calldata key) external pure returns (string memory); - - /// Parses a string of TOML data at `key` and coerces it to `string[]`. - function parseTomlStringArray(string calldata toml, string calldata key) external pure returns (string[] memory); - - /// Parses a string of TOML data at `key` and coerces it to type array corresponding to `typeDescription`. - function parseTomlTypeArray(string calldata toml, string calldata key, string calldata typeDescription) - external - pure - returns (bytes memory); - - /// Parses a string of TOML data and coerces it to type corresponding to `typeDescription`. - function parseTomlType(string calldata toml, string calldata typeDescription) - external - pure - returns (bytes memory); - - /// Parses a string of TOML data at `key` and coerces it to type corresponding to `typeDescription`. - function parseTomlType(string calldata toml, string calldata key, string calldata typeDescription) - external - pure - returns (bytes memory); - - /// Parses a string of TOML data at `key` and coerces it to `uint256`. - function parseTomlUint(string calldata toml, string calldata key) external pure returns (uint256); - - /// Parses a string of TOML data at `key` and coerces it to `uint256[]`. - function parseTomlUintArray(string calldata toml, string calldata key) external pure returns (uint256[] memory); - - /// ABI-encodes a TOML table. - function parseToml(string calldata toml) external pure returns (bytes memory abiEncodedData); - - /// ABI-encodes a TOML table at `key`. - function parseToml(string calldata toml, string calldata key) external pure returns (bytes memory abiEncodedData); - - /// Takes serialized JSON, converts to TOML and write a serialized TOML to a file. - function writeToml(string calldata json, string calldata path) external; - - /// Takes serialized JSON, converts to TOML and write a serialized TOML table to an **existing** TOML file, replacing a value with key = - /// This is useful to replace a specific value of a TOML file, without having to parse the entire thing. - function writeToml(string calldata json, string calldata path, string calldata valueKey) external; - - // ======== Utilities ======== - - /// Compute the address of a contract created with CREATE2 using the given CREATE2 deployer. - function computeCreate2Address(bytes32 salt, bytes32 initCodeHash, address deployer) - external - pure - returns (address); - - /// Compute the address of a contract created with CREATE2 using the default CREATE2 deployer. - function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) external pure returns (address); - - /// Compute the address a contract will be deployed at for a given deployer address and nonce. - function computeCreateAddress(address deployer, uint256 nonce) external pure returns (address); - - /// Utility cheatcode to copy storage of `from` contract to another `to` contract. - function copyStorage(address from, address to) external; - - /// Returns ENS namehash for provided string. - function ensNamehash(string calldata name) external pure returns (bytes32); - - /// Gets the label for the specified address. - function getLabel(address account) external view returns (string memory currentLabel); - - /// Labels an address in call traces. - function label(address account, string calldata newLabel) external; - - /// Pauses collection of call traces. Useful in cases when you want to skip tracing of - /// complex calls which are not useful for debugging. - function pauseTracing() external view; - - /// Returns a random `address`. - function randomAddress() external returns (address); - - /// Returns a random `bool`. - function randomBool() external view returns (bool); - - /// Returns a random byte array value of the given length. - function randomBytes(uint256 len) external view returns (bytes memory); - - /// Returns a random fixed-size byte array of length 4. - function randomBytes4() external view returns (bytes4); - - /// Returns a random fixed-size byte array of length 8. - function randomBytes8() external view returns (bytes8); - - /// Returns a random `int256` value. - function randomInt() external view returns (int256); - - /// Returns a random `int256` value of given bits. - function randomInt(uint256 bits) external view returns (int256); - - /// Returns a random uint256 value. - function randomUint() external returns (uint256); - - /// Returns random uint256 value between the provided range (=min..=max). - function randomUint(uint256 min, uint256 max) external returns (uint256); - - /// Returns a random `uint256` value of given bits. - function randomUint(uint256 bits) external view returns (uint256); - - /// Unpauses collection of call traces. - function resumeTracing() external view; - - /// Utility cheatcode to set arbitrary storage for given target address. - function setArbitraryStorage(address target) external; - - /// Encodes a `bytes` value to a base64url string. - function toBase64URL(bytes calldata data) external pure returns (string memory); - - /// Encodes a `string` value to a base64url string. - function toBase64URL(string calldata data) external pure returns (string memory); - - /// Encodes a `bytes` value to a base64 string. - function toBase64(bytes calldata data) external pure returns (string memory); - - /// Encodes a `string` value to a base64 string. - function toBase64(string calldata data) external pure returns (string memory); -} - -/// 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 ======== - - /// Returns the identifier of the currently active fork. Reverts if no fork is currently active. - function activeFork() external view returns (uint256 forkId); - - /// In forking mode, explicitly grant the given address cheatcode access. - function allowCheatcodes(address account) external; - - /// Sets `block.blobbasefee` - function blobBaseFee(uint256 newBlobBaseFee) external; - - /// Sets the blobhashes in the transaction. - /// Not available on EVM versions before Cancun. - /// If used on unsupported EVM versions it will revert. - function blobhashes(bytes32[] calldata hashes) external; - - /// Sets `block.chainid`. - function chainId(uint256 newChainId) external; - - /// Clears all mocked calls. - function clearMockedCalls() external; - - /// Clones a source account code, state, balance and nonce to a target account and updates in-memory EVM state. - function cloneAccount(address source, address target) external; - - /// Sets `block.coinbase`. - function coinbase(address newCoinbase) external; - - /// 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 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 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 the latest block and returns the identifier of the fork. - function createSelectFork(string calldata urlOrAlias) 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); - - /// Sets an address' balance. - function deal(address account, uint256 newBalance) external; - - /// Removes the snapshot with the given ID created by `snapshot`. - /// Takes the snapshot ID to delete. - /// Returns `true` if the snapshot was successfully deleted. - /// Returns `false` if the snapshot does not exist. - function deleteStateSnapshot(uint256 snapshotId) external returns (bool success); - - /// Removes _all_ snapshots previously created by `snapshot`. - function deleteStateSnapshots() external; - - /// Sets `block.difficulty`. - /// Not available on EVM versions from Paris onwards. Use `prevrandao` instead. - /// Reverts if used on unsupported EVM versions. - function difficulty(uint256 newDifficulty) external; - - /// Dump a genesis JSON file's `allocs` to disk. - function dumpState(string calldata pathToStateJson) external; - - /// Sets an address' code. - function etch(address target, bytes calldata newRuntimeBytecode) external; - - /// Sets `block.basefee`. - function fee(uint256 newBasefee) external; - - /// Gets the blockhashes from the current transaction. - /// Not available on EVM versions before Cancun. - /// If used on unsupported EVM versions it will revert. - function getBlobhashes() external view returns (bytes32[] memory hashes); - - /// Returns true if the account is marked as persistent. - function isPersistent(address account) external view returns (bool persistent); - - /// Load a genesis JSON file's `allocs` into the in-memory EVM state. - function loadAllocs(string calldata pathToAllocsJson) 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; - - /// See `makePersistent(address)`. - function makePersistent(address account0, address account1) external; - - /// See `makePersistent(address)`. - function makePersistent(address account0, address account1, address account2) external; - - /// See `makePersistent(address)`. - function makePersistent(address[] calldata accounts) 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; - - /// Reverts a call to an address with specified revert data. - /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. - function mockCallRevert(address callee, bytes4 data, bytes calldata revertData) external; - - /// Reverts a call to an address with a specific `msg.value`, with specified revert data. - /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. - function mockCallRevert(address callee, uint256 msgValue, bytes4 data, bytes calldata revertData) 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; - - /// 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. - /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. - function mockCall(address callee, bytes4 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. - /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`. - function mockCall(address callee, uint256 msgValue, bytes4 data, bytes calldata returnData) external; - - /// Mocks multiple calls to an address, returning specified data for each call. - function mockCalls(address callee, bytes calldata data, bytes[] calldata returnData) external; - - /// Mocks multiple calls to an address with a specific `msg.value`, returning specified data for each call. - function mockCalls(address callee, uint256 msgValue, bytes calldata data, bytes[] calldata returnData) external; - - /// Whenever a call is made to `callee` with calldata `data`, this cheatcode instead calls - /// `target` with the same calldata. This functionality is similar to a delegate call made to - /// `target` contract from `callee`. - /// Can be used to substitute a call to a function with another implementation that captures - /// the primary logic of the original function but is easier to reason about. - /// If calldata is not a strict match then partial match by selector is attempted. - function mockFunction(address callee, address target, bytes calldata data) external; - - /// Sets the *next* call's `msg.sender` to be the input address. - function prank(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 the *next* delegate call's `msg.sender` to be the input address. - function prank(address msgSender, bool delegateCall) external; - - /// Sets the *next* delegate call's `msg.sender` to be the input address, and the `tx.origin` to be the second input. - function prank(address msgSender, address txOrigin, bool delegateCall) 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.prevrandao`. - /// Not available on EVM versions before Paris. Use `difficulty` instead. - /// If used on unsupported EVM versions it will revert. - function prevrandao(uint256 newPrevrandao) 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); - - /// Resets the nonce of an account to 0 for EOAs and 1 for contract accounts. - function resetNonce(address account) external; - - /// Revert the state of the EVM to a previous snapshot - /// Takes the snapshot ID to revert to. - /// Returns `true` if the snapshot was successfully reverted. - /// Returns `false` if the snapshot does not exist. - /// **Note:** This does not automatically delete the snapshot. To delete the snapshot use `deleteStateSnapshot`. - function revertToState(uint256 snapshotId) external returns (bool success); - - /// Revert the state of the EVM to a previous snapshot and automatically deletes the snapshots - /// Takes the snapshot ID to revert to. - /// Returns `true` if the snapshot was successfully reverted and deleted. - /// Returns `false` if the snapshot does not exist. - function revertToStateAndDelete(uint256 snapshotId) external returns (bool success); - - /// Revokes persistent status from the address, previously added via `makePersistent`. - function revokePersistent(address account) external; - - /// See `revokePersistent(address)`. - function revokePersistent(address[] calldata accounts) external; - - /// Sets `block.height`. - function roll(uint256 newHeight) external; - - /// 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; - - /// Set blockhash for the current block. - /// It only sets the blockhash for blocks where `block.number - 256 <= number < block.number`. - function setBlockhash(uint256 blockNumber, bytes32 blockHash) 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; - - /// Snapshot capture the gas usage of the last call by name from the callee perspective. - function snapshotGasLastCall(string calldata name) external returns (uint256 gasUsed); - - /// Snapshot capture the gas usage of the last call by name in a group from the callee perspective. - function snapshotGasLastCall(string calldata group, string calldata name) external returns (uint256 gasUsed); - - /// Snapshot the current state of the evm. - /// Returns the ID of the snapshot that was created. - /// To revert a snapshot use `revertToState`. - function snapshotState() external returns (uint256 snapshotId); - - /// Snapshot capture an arbitrary numerical value by name. - /// The group name is derived from the contract name. - function snapshotValue(string calldata name, uint256 value) external; - - /// Snapshot capture an arbitrary numerical value by name in a group. - function snapshotValue(string calldata group, string calldata name, uint256 value) external; - - /// Sets all subsequent calls' `msg.sender` to be the input address until `stopPrank` is called. - function startPrank(address msgSender) 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; - - /// Sets all subsequent delegate calls' `msg.sender` to be the input address until `stopPrank` is called. - function startPrank(address msgSender, bool delegateCall) external; - - /// Sets all subsequent delegate 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, bool delegateCall) external; - - /// Start a snapshot capture of the current gas usage by name. - /// The group name is derived from the contract name. - function startSnapshotGas(string calldata name) external; - - /// Start a snapshot capture of the current gas usage by name in a group. - function startSnapshotGas(string calldata group, string calldata name) external; - - /// Resets subsequent calls' `msg.sender` to be `address(this)`. - function stopPrank() external; - - /// Stop the snapshot capture of the current gas by latest snapshot name, capturing the gas used since the start. - function stopSnapshotGas() external returns (uint256 gasUsed); - - /// Stop the snapshot capture of the current gas usage by name, capturing the gas used since the start. - /// The group name is derived from the contract name. - function stopSnapshotGas(string calldata name) external returns (uint256 gasUsed); - - /// Stop the snapshot capture of the current gas usage by name in a group, capturing the gas used since the start. - function stopSnapshotGas(string calldata group, string calldata name) external returns (uint256 gasUsed); - - /// Stores a value to an address' storage slot. - function store(address target, bytes32 slot, bytes32 value) 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; - - /// Sets `tx.gasprice`. - function txGasPrice(uint256 newGasPrice) external; - - /// Sets `block.timestamp`. - function warp(uint256 newTimestamp) external; - - /// `deleteSnapshot` is being deprecated in favor of `deleteStateSnapshot`. It will be removed in future versions. - function deleteSnapshot(uint256 snapshotId) external returns (bool success); - - /// `deleteSnapshots` is being deprecated in favor of `deleteStateSnapshots`. It will be removed in future versions. - function deleteSnapshots() external; - - /// `revertToAndDelete` is being deprecated in favor of `revertToStateAndDelete`. It will be removed in future versions. - function revertToAndDelete(uint256 snapshotId) external returns (bool success); - - /// `revertTo` is being deprecated in favor of `revertToState`. It will be removed in future versions. - function revertTo(uint256 snapshotId) external returns (bool success); - - /// `snapshot` is being deprecated in favor of `snapshotState`. It will be removed in future versions. - function snapshot() external returns (uint256 snapshotId); - - // ======== Testing ======== - - /// 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; - - /// 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; - - /// Prepare an expected anonymous log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData.). - /// Call this function, then emit an anonymous 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 expectEmitAnonymous(bool checkTopic0, bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) - external; - - /// Same as the previous method, but also checks supplied address against emitting contract. - function expectEmitAnonymous( - bool checkTopic0, - bool checkTopic1, - bool checkTopic2, - bool checkTopic3, - bool checkData, - address emitter - ) external; - - /// Prepare an expected anonymous log with all topic and data checks enabled. - /// Call this function, then emit an anonymous 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 expectEmitAnonymous() external; - - /// Same as the previous method, but also checks supplied address against emitting contract. - function expectEmitAnonymous(address emitter) 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; - - /// Expect a given number of logs with the provided topics. - function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, uint64 count) external; - - /// Expect a given number of logs from a specific emitter with the provided topics. - function expectEmit( - bool checkTopic1, - bool checkTopic2, - bool checkTopic3, - bool checkData, - address emitter, - uint64 count - ) external; - - /// Expect a given number of logs with all topic and data checks enabled. - function expectEmit(uint64 count) external; - - /// Expect a given number of logs from a specific emitter with all topic and data checks enabled. - function expectEmit(address emitter, uint64 count) external; - - /// Expects an error on next call that starts with the revert data. - function expectPartialRevert(bytes4 revertData) external; - - /// Expects an error on next call to reverter address, that starts with the revert data. - function expectPartialRevert(bytes4 revertData, address reverter) external; - - /// Expects an error on next call with any revert data. - function expectRevert() external; - - /// Expects an error on next call that exactly matches the revert data. - function expectRevert(bytes4 revertData) external; - - /// Expects a `count` number of reverts from the upcoming calls from the reverter address that match the revert data. - function expectRevert(bytes4 revertData, address reverter, uint64 count) external; - - /// Expects a `count` number of reverts from the upcoming calls from the reverter address that exactly match the revert data. - function expectRevert(bytes calldata revertData, address reverter, uint64 count) external; - - /// Expects an error on next call that exactly matches the revert data. - function expectRevert(bytes calldata revertData) external; - - /// Expects an error with any revert data on next call to reverter address. - function expectRevert(address reverter) external; - - /// Expects an error from reverter address on next call, with any revert data. - function expectRevert(bytes4 revertData, address reverter) external; - - /// Expects an error from reverter address on next call, that exactly matches the revert data. - function expectRevert(bytes calldata revertData, address reverter) external; - - /// Expects a `count` number of reverts from the upcoming calls with any revert data or reverter. - function expectRevert(uint64 count) external; - - /// Expects a `count` number of reverts from the upcoming calls that match the revert data. - function expectRevert(bytes4 revertData, uint64 count) external; - - /// Expects a `count` number of reverts from the upcoming calls that exactly match the revert data. - function expectRevert(bytes calldata revertData, uint64 count) external; - - /// Expects a `count` number of reverts from the upcoming calls from the reverter address. - function expectRevert(address reverter, uint64 count) 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 level of a test. - function skip(bool skipTest) external; - - /// Marks a test as skipped with a reason. Must be called at the top level of a test. - function skip(bool skipTest, string calldata reason) external; - - /// Stops all safe memory expectation in the current subcontext. - function stopExpectSafeMemory() external; -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console.sol deleted file mode 100644 index 4fdb667..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console.sol +++ /dev/null @@ -1,1560 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.4.22 <0.9.0; - -library console { - address constant CONSOLE_ADDRESS = - 0x000000000000000000636F6e736F6c652e6c6f67; - - function _sendLogPayloadImplementation(bytes memory payload) internal view { - address consoleAddress = CONSOLE_ADDRESS; - /// @solidity memory-safe-assembly - assembly { - pop( - staticcall( - gas(), - consoleAddress, - add(payload, 32), - mload(payload), - 0, - 0 - ) - ) - } - } - - function _castToPure( - function(bytes memory) internal view fnIn - ) internal pure returns (function(bytes memory) pure fnOut) { - assembly { - fnOut := fnIn - } - } - - function _sendLogPayload(bytes memory payload) internal pure { - _castToPure(_sendLogPayloadImplementation)(payload); - } - - 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)); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol deleted file mode 100644 index 03531d9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol +++ /dev/null @@ -1,4 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.4.22 <0.9.0; - -import {console as console2} from "./console.sol"; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol deleted file mode 100644 index f7dd2b4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol +++ /dev/null @@ -1,105 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol deleted file mode 100644 index 9af4bf8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol +++ /dev/null @@ -1,12 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol deleted file mode 100644 index ba40806..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol +++ /dev/null @@ -1,43 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol deleted file mode 100644 index 391eeb4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol +++ /dev/null @@ -1,190 +0,0 @@ -// 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 withdrawal 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 withdrawal. - /// - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol deleted file mode 100644 index 0a16f45..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol +++ /dev/null @@ -1,164 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IMulticall3.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IMulticall3.sol deleted file mode 100644 index 0d031b7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IMulticall3.sol +++ /dev/null @@ -1,73 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/safeconsole.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/safeconsole.sol deleted file mode 100644 index 87c475a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/src/safeconsole.sol +++ /dev/null @@ -1,13937 +0,0 @@ -// 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; - /// @solidity memory-safe-assembly - assembly { - pureSendLogPayload := fnIn - } - pureSendLogPayload(offset, size); - } - - function _sendLogPayloadView(uint256 offset, uint256 size) private view { - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - assembly { - pureMemcopy := fnIn - } - pureMemcopy(fromOffset, toOffset, length); - } - - function _memcopyView(uint256 fromOffset, uint256 toOffset, uint256 length) private view { - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - assembly { - m0 := mload(sub(offset, 0x60)) - m1 := mload(sub(offset, 0x40)) - m2 := mload(sub(offset, 0x20)) - // Selector of `log(bytes)`. - mstore(sub(offset, 0x60), 0x0be77f56) - mstore(sub(offset, 0x40), 0x20) - mstore(sub(offset, 0x20), length) - } - _sendLogPayload(offset - 0x44, length + 0x44); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - assembly { - m0 := mload(add(endOffset, 0x00)) - m1 := mload(add(endOffset, 0x20)) - m2 := mload(add(endOffset, 0x40)) - } - _memcopy(offset, offset + 0x60, length); - /// @solidity memory-safe-assembly - assembly { - // Selector of `log(bytes)`. - mstore(add(offset, 0x00), 0x0be77f56) - mstore(add(offset, 0x20), 0x20) - mstore(add(offset, 0x40), length) - } - _sendLogPayload(offset + 0x1c, length + 0x44); - _memcopy(offset + 0x60, offset, length); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - assembly { - m0 := mload(0x00) - m1 := mload(0x20) - // Selector of `log(address)`. - mstore(0x00, 0x2c2ecbc2) - mstore(0x20, p0) - } - _sendLogPayload(0x1c, 0x24); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - } - } - - function log(bool p0) internal pure { - bytes32 m0; - bytes32 m1; - /// @solidity memory-safe-assembly - assembly { - m0 := mload(0x00) - m1 := mload(0x20) - // Selector of `log(bool)`. - mstore(0x00, 0x32458eed) - mstore(0x20, p0) - } - _sendLogPayload(0x1c, 0x24); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - } - } - - function log(uint256 p0) internal pure { - bytes32 m0; - bytes32 m1; - /// @solidity memory-safe-assembly - assembly { - m0 := mload(0x00) - m1 := mload(0x20) - // Selector of `log(uint256)`. - mstore(0x00, 0xf82c50f1) - mstore(0x20, p0) - } - _sendLogPayload(0x1c, 0x24); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - } - } - - function log(bytes32 p0) internal pure { - bytes32 m0; - bytes32 m1; - bytes32 m2; - bytes32 m3; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - mstore(0x40, m2) - } - } - - function log(address p0, bool p1) internal pure { - bytes32 m0; - bytes32 m1; - bytes32 m2; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - mstore(0x40, m2) - } - } - - function log(address p0, uint256 p1) internal pure { - bytes32 m0; - bytes32 m1; - bytes32 m2; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - mstore(0x40, m2) - } - } - - function log(bool p0, bool p1) internal pure { - bytes32 m0; - bytes32 m1; - bytes32 m2; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - mstore(0x40, m2) - } - } - - function log(bool p0, uint256 p1) internal pure { - bytes32 m0; - bytes32 m1; - bytes32 m2; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - mstore(0x40, m2) - } - } - - function log(uint256 p0, bool p1) internal pure { - bytes32 m0; - bytes32 m1; - bytes32 m2; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, m0) - mstore(0x20, m1) - mstore(0x40, m2) - } - } - - function log(uint256 p0, uint256 p1) internal pure { - bytes32 m0; - bytes32 m1; - bytes32 m2; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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; - /// @solidity memory-safe-assembly - 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); - /// @solidity memory-safe-assembly - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol deleted file mode 100644 index acc0c1e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {StdAssertions} from "../src/StdAssertions.sol"; -import {Vm} from "../src/Vm.sol"; - -interface VmInternal is Vm { - function _expectCheatcodeRevert(bytes memory message) external; -} - -contract StdAssertionsTest is StdAssertions { - string constant errorMessage = "User provided message"; - uint256 constant maxDecimals = 77; - - bool constant SHOULD_REVERT = true; - bool constant SHOULD_RETURN = false; - - bool constant STRICT_REVERT_DATA = true; - bool constant NON_STRICT_REVERT_DATA = false; - - VmInternal constant vm = VmInternal(address(uint160(uint256(keccak256("hevm cheat code"))))); - - 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)); - - assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); - } - - 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._expectCheatcodeRevert( - bytes( - string.concat( - "Call return data does not match: ", vm.toString(returnDataA), " != ", vm.toString(returnDataB) - ) - ) - ); - assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); - } - - 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)); - - assertEqCall(targetA, callDataA, targetB, callDataB, NON_STRICT_REVERT_DATA); - } - - 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._expectCheatcodeRevert( - bytes( - string.concat( - "Call revert data does not match: ", vm.toString(revertDataA), " != ", vm.toString(revertDataB) - ) - ) - ); - assertEqCall(targetA, callDataA, targetB, callDataB, STRICT_REVERT_DATA); - } - - 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.expectRevert(bytes("assertion failed")); - this.assertEqCallExternal(targetA, callDataA, targetB, callDataB, strictRevertData); - - vm.expectRevert(bytes("assertion failed")); - this.assertEqCallExternal(targetB, callDataB, targetA, callDataA, strictRevertData); - } - - // Helper function to test outcome of assertEqCall via `expect` cheatcodes - function assertEqCallExternal( - address targetA, - bytes memory callDataA, - address targetB, - bytes memory callDataB, - bool strictRevertData - ) public { - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol deleted file mode 100644 index 3ecaa2e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol +++ /dev/null @@ -1,227 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {Test} from "../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://eth-mainnet.alchemyapi.io/v2/WV407BEiBmjNJfKo9Uo_55u0z0ITyCOX"); - assertEq(getChain("optimism_sepolia").rpcUrl, "https://sepolia.optimism.io/"); - assertEq(getChain("arbitrum_one_sepolia").rpcUrl, "https://sepolia-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://eth-mainnet.alchemyapi.io/v2/WV407BEiBmjNJfKo9Uo_55u0z0ITyCOX"); - - // 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"); - } - - // Named with a leading underscore to clarify this is not intended to be run as a normal test, - // and is intended to be used in the below `test_Rpcs` test. - 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. - // Currently commented out since this is slow and public RPCs are flaky, often resulting in failing CI. - // function test_Rpcs() public { - // _testRpc("mainnet"); - // _testRpc("sepolia"); - // _testRpc("holesky"); - // _testRpc("optimism"); - // _testRpc("optimism_sepolia"); - // _testRpc("arbitrum_one"); - // _testRpc("arbitrum_one_sepolia"); - // _testRpc("arbitrum_nova"); - // _testRpc("polygon"); - // _testRpc("polygon_amoy"); - // _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_sepolia"); - // _testRpc("base"); - // _testRpc("blast_sepolia"); - // _testRpc("blast"); - // _testRpc("fantom_opera"); - // _testRpc("fantom_opera_testnet"); - // _testRpc("fraxtal"); - // _testRpc("fraxtal_testnet"); - // _testRpc("berachain_bartio_testnet"); - // _testRpc("flare"); - // _testRpc("flare_coston2"); - // } - - function test_RevertIf_ChainNotFound() 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_RevertIf_SetChain_ChainIdExist_FirstTest() 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_RevertIf_ChainBubbleUp() public { - // We deploy a mock to properly test the revert. - StdChainsMock stdChainsMock = new StdChainsMock(); - - stdChainsMock.exposed_setChain("needs_undefined_env_var", ChainData("", 123456789, "")); - // Forge environment variable error. - vm.expectRevert(); - stdChainsMock.exposed_getChain("needs_undefined_env_var"); - } - - function test_RevertIf_SetChain_ChainIdExists_SecondTest() 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_RevertIf_SetEmptyAlias() 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_RevertIf_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_RevertIf_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_RevertIf_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_RevertIf_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_RevertIf_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", 9999999999999999999, "https://modified.chain/")); - vm.expectRevert("StdChains getChain(uint256): Chain with ID 123456789 not found."); - stdChainsMock.exposed_getChain(123456789); - - Chain memory modifiedChain = getChain(9999999999999999999); - assertEq(modifiedChain.name, "Modified Chain"); - assertEq(modifiedChain.chainId, 9999999999999999999); - assertEq(modifiedChain.rpcUrl, "https://modified.chain/"); - } - - function test_RevertIf_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(); - stdChainsMock.exposed_getChain(31337); - vm.expectRevert(); - stdChainsMock.exposed_getChain("sepolia"); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol deleted file mode 100644 index 0a5a832..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol +++ /dev/null @@ -1,618 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {StdCheats} from "../src/StdCheats.sol"; -import {Test} from "../src/Test.sol"; -import {stdJson} from "../src/StdJson.sol"; -import {stdToml} from "../src/StdToml.sol"; -import {IERC20} from "../src/interfaces/IERC20.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 test_DealToken() 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_RevertIf_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 pure { - 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 view { - 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 view { - 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(); - - 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_sepolia").chainId); - assertTrue( - addr < address(1) || (addr > address(9) && addr < address(0x4200000000000000000000000000000000000000)) - || addr > address(0x4200000000000000000000000000000000000800) - ); - } - - function testFuzz_AssumeNotForgeAddress(address addr) external pure { - assumeNotForgeAddress(addr); - assertTrue( - addr != address(vm) && addr != 0x000000000000000000636F6e736F6c652e6c6f67 - && addr != 0x4e59b44847b379578588920cA78FbF26c0B4956C - ); - } - - function test_RevertIf_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_RevertIf_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 view { - assumeNotBlacklisted(SHIB, addr); - assertTrue(true); - } - - function test_RevertIf_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 view { - assumeNotBlacklisted(USDC, addr); - assertFalse(USDCLike(USDC).isBlacklisted(addr)); - } - - function test_RevertIf_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 view { - assumeNotBlacklisted(USDT, addr); - assertFalse(USDTLike(USDT).isBlackListed(addr)); - } - - function test_dealUSDC() external { - // roll fork to the point when USDC contract updated to store balance in packed slots - vm.rollFork(19279215); - - uint256 balance = 100e6; - deal(USDC, address(this), balance); - assertEq(IERC20(USDC).balanceOf(address(this)), balance); - } -} - -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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol deleted file mode 100644 index 29803d5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -import {stdError} from "../src/StdError.sol"; -import {Test} from "../src/Test.sol"; - -contract StdErrorsTest is Test { - ErrorsTest test; - - function setUp() public { - test = new ErrorsTest(); - } - - function test_RevertIf_AssertionError() public { - vm.expectRevert(stdError.assertionError); - test.assertionError(); - } - - function test_RevertIf_ArithmeticError() public { - vm.expectRevert(stdError.arithmeticError); - test.arithmeticError(10); - } - - function test_RevertIf_DivisionError() public { - vm.expectRevert(stdError.divisionError); - test.divError(0); - } - - function test_RevertIf_ModError() public { - vm.expectRevert(stdError.divisionError); - test.modError(0); - } - - function test_RevertIf_EnumConversionError() public { - vm.expectRevert(stdError.enumConversionError); - test.enumConversion(1); - } - - function test_RevertIf_EncodeStgError() public { - vm.expectRevert(stdError.encodeStorageError); - test.encodeStgError(); - } - - function test_RevertIf_PopError() public { - vm.expectRevert(stdError.popError); - test.pop(); - } - - function test_RevertIf_IndexOOBError() public { - vm.expectRevert(stdError.indexOOBError); - test.indexOOBError(1); - } - - function test_RevertIf_MemOverflowError() public { - vm.expectRevert(stdError.memOverflowError); - test.mem(); - } - - function test_RevertIf_InternError() 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdJson.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdJson.t.sol deleted file mode 100644 index 6bedfcc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdJson.t.sol +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {Test, stdJson} from "../src/Test.sol"; - -contract StdJsonTest is Test { - using stdJson for string; - - string root; - string path; - - function setUp() public { - root = vm.projectRoot(); - path = string.concat(root, "/test/fixtures/test.json"); - } - - struct SimpleJson { - uint256 a; - string b; - } - - struct NestedJson { - uint256 a; - string b; - SimpleJson c; - } - - function test_readJson() public view { - string memory json = vm.readFile(path); - assertEq(json.readUint(".a"), 123); - } - - function test_writeJson() public { - string memory json = "json"; - json.serialize("a", uint256(123)); - string memory semiFinal = json.serialize("b", string("test")); - string memory finalJson = json.serialize("c", semiFinal); - finalJson.write(path); - - string memory json_ = vm.readFile(path); - bytes memory data = json_.parseRaw("$"); - NestedJson memory decodedData = abi.decode(data, (NestedJson)); - - assertEq(decodedData.a, 123); - assertEq(decodedData.b, "test"); - assertEq(decodedData.c.a, 123); - assertEq(decodedData.c.b, "test"); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol deleted file mode 100644 index d1269a0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol +++ /dev/null @@ -1,202 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -import {stdMath} from "../src/StdMath.sol"; -import {Test, stdError} from "../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 pure { - 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 pure { - uint256 manualAbs = getAbs(a); - - uint256 abs = stdMath.abs(a); - - assertEq(abs, manualAbs); - } - - function test_GetDelta_Uint() external pure { - 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 pure { - uint256 manualDelta = a > b ? a - b : b - a; - - uint256 delta = stdMath.delta(a, b); - - assertEq(delta, manualDelta); - } - - function test_GetDelta_Int() external pure { - 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 pure { - 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 pure { - vm.assume(b != 0); - uint256 manualDelta = a > b ? a - b : 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 pure { - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol deleted file mode 100644 index 46604f8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol +++ /dev/null @@ -1,488 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {stdStorage, StdStorage} from "../src/StdStorage.sol"; -import {Test} from "../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 testFuzz_StorageCheckedWriteMapPacked(address addr, uint128 value) public { - stdstore.enable_packed_slots().target(address(test)).sig(test.read_struct_lower.selector).with_key(addr) - .checked_write(value); - assertEq(test.read_struct_lower(addr), value); - - stdstore.enable_packed_slots().target(address(test)).sig(test.read_struct_upper.selector).with_key(addr) - .checked_write(value); - assertEq(test.read_struct_upper(addr), value); - } - - function test_StorageCheckedWriteMapPackedFullSuccess() 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 test_RevertStorageConst() public { - StorageTestTarget target = new StorageTestTarget(test); - - vm.expectRevert("stdStorage find(StdStorage): No storage use detected for target."); - target.expectRevertStorageConst(); - } - - function testFuzz_StorageNativePack(uint248 val1, uint248 val2, bool boolVal1, bool boolVal2) public { - stdstore.enable_packed_slots().target(address(test)).sig(test.tA.selector).checked_write(val1); - stdstore.enable_packed_slots().target(address(test)).sig(test.tB.selector).checked_write(boolVal1); - stdstore.enable_packed_slots().target(address(test)).sig(test.tC.selector).checked_write(boolVal2); - stdstore.enable_packed_slots().target(address(test)).sig(test.tD.selector).checked_write(val2); - - assertEq(test.tA(), val1); - assertEq(test.tB(), boolVal1); - assertEq(test.tC(), boolVal2); - assertEq(test.tD(), val2); - } - - 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_RevertIf_ReadingNonBoolValue() 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); - } - - function testFuzz_Packed(uint256 val, uint8 elemToGet) public { - // This function tries an assortment of packed slots, shifts meaning number of elements - // that are packed. Shiftsizes are the size of each element, i.e. 8 means a data type that is 8 bits, 16 == 16 bits, etc. - // Combined, these determine how a slot is packed. Making it random is too hard to avoid global rejection limit - // and make it performant. - - // change the number of shifts - for (uint256 i = 1; i < 5; i++) { - uint256 shifts = i; - - elemToGet = uint8(bound(elemToGet, 0, shifts - 1)); - - uint256[] memory shiftSizes = new uint256[](shifts); - for (uint256 j; j < shifts; j++) { - shiftSizes[j] = 8 * (j + 1); - } - - test.setRandomPacking(val); - - uint256 leftBits; - uint256 rightBits; - for (uint256 j; j < shiftSizes.length; j++) { - if (j < elemToGet) { - leftBits += shiftSizes[j]; - } else if (elemToGet != j) { - rightBits += shiftSizes[j]; - } - } - - // we may have some right bits unaccounted for - leftBits += 256 - (leftBits + shiftSizes[elemToGet] + rightBits); - // clear left bits, then clear right bits and realign - uint256 expectedValToRead = (val << leftBits) >> (leftBits + rightBits); - - uint256 readVal = stdstore.target(address(test)).enable_packed_slots().sig( - "getRandomPacked(uint8,uint8[],uint8)" - ).with_calldata(abi.encode(shifts, shiftSizes, elemToGet)).read_uint(); - - assertEq(readVal, expectedValToRead); - } - } - - function testFuzz_Packed2(uint256 nvars, uint256 seed) public { - // Number of random variables to generate. - nvars = bound(nvars, 1, 20); - - // This will decrease as we generate values in the below loop. - uint256 bitsRemaining = 256; - - // Generate a random value and size for each variable. - uint256[] memory vals = new uint256[](nvars); - uint256[] memory sizes = new uint256[](nvars); - uint256[] memory offsets = new uint256[](nvars); - - for (uint256 i = 0; i < nvars; i++) { - // Generate a random value and size. - offsets[i] = i == 0 ? 0 : offsets[i - 1] + sizes[i - 1]; - - uint256 nvarsRemaining = nvars - i; - uint256 maxVarSize = bitsRemaining - nvarsRemaining + 1; - sizes[i] = bound(uint256(keccak256(abi.encodePacked(seed, i + 256))), 1, maxVarSize); - bitsRemaining -= sizes[i]; - - uint256 maxVal; - uint256 varSize = sizes[i]; - assembly { - // mask = (1 << varSize) - 1 - maxVal := sub(shl(varSize, 1), 1) - } - vals[i] = bound(uint256(keccak256(abi.encodePacked(seed, i))), 0, maxVal); - } - - // Pack all values into the slot. - for (uint256 i = 0; i < nvars; i++) { - stdstore.enable_packed_slots().target(address(test)).sig("getRandomPacked(uint256,uint256)").with_key( - sizes[i] - ).with_key(offsets[i]).checked_write(vals[i]); - } - - // Verify the read data matches. - for (uint256 i = 0; i < nvars; i++) { - uint256 readVal = stdstore.enable_packed_slots().target(address(test)).sig( - "getRandomPacked(uint256,uint256)" - ).with_key(sizes[i]).with_key(offsets[i]).read_uint(); - - uint256 retVal = test.getRandomPacked(sizes[i], offsets[i]); - - assertEq(readVal, vals[i]); - assertEq(retVal, vals[i]); - } - } - - function testEdgeCaseArray() public { - stdstore.target(address(test)).sig("edgeCaseArray(uint256)").with_key(uint256(0)).checked_write(1); - assertEq(test.edgeCaseArray(0), 1); - } -} - -contract StorageTestTarget { - using stdStorage for StdStorage; - - StdStorage internal stdstore; - StorageTest internal test; - - constructor(StorageTest test_) { - test = test_; - } - - function expectRevertStorageConst() public { - stdstore.target(address(test)).sig("const()").find(); - } -} - -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"); - - uint256 randomPacking; - - // Array with length matching values of elements. - uint256[] public edgeCaseArray = [3, 3, 3]; - - 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; - } - - function setRandomPacking(uint256 val) public { - randomPacking = val; - } - - function _getMask(uint256 size) internal pure returns (uint256 mask) { - assembly { - // mask = (1 << size) - 1 - mask := sub(shl(size, 1), 1) - } - } - - function setRandomPacking(uint256 val, uint256 size, uint256 offset) public { - // Generate mask based on the size of the value - uint256 mask = _getMask(size); - // Zero out all bits for the word we're about to set - uint256 cleanedWord = randomPacking & ~(mask << offset); - // Place val in the correct spot of the cleaned word - randomPacking = cleanedWord | val << offset; - } - - function getRandomPacked(uint256 size, uint256 offset) public view returns (uint256) { - // Generate mask based on the size of the value - uint256 mask = _getMask(size); - // Shift to place the bits in the correct position, and use mask to zero out remaining bits - return (randomPacking >> offset) & mask; - } - - function getRandomPacked(uint8 shifts, uint8[] memory shiftSizes, uint8 elem) public view returns (uint256) { - require(elem < shifts, "!elem"); - uint256 leftBits; - uint256 rightBits; - - for (uint256 i; i < shiftSizes.length; i++) { - if (i < elem) { - leftBits += shiftSizes[i]; - } else if (elem != i) { - rightBits += shiftSizes[i]; - } - } - - // we may have some right bits unaccounted for - leftBits += 256 - (leftBits + shiftSizes[elem] + rightBits); - - // clear left bits, then clear right bits and realign - return (randomPacking << leftBits) >> (leftBits + rightBits); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStyle.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStyle.t.sol deleted file mode 100644 index 974e756..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdStyle.t.sol +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {Test, console2, StdStyle} from "../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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdToml.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdToml.t.sol deleted file mode 100644 index 5a45f4f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdToml.t.sol +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {Test, stdToml} from "../src/Test.sol"; - -contract StdTomlTest is Test { - using stdToml for string; - - string root; - string path; - - function setUp() public { - root = vm.projectRoot(); - path = string.concat(root, "/test/fixtures/test.toml"); - } - - struct SimpleToml { - uint256 a; - string b; - } - - struct NestedToml { - uint256 a; - string b; - SimpleToml c; - } - - function test_readToml() public view { - string memory json = vm.readFile(path); - assertEq(json.readUint(".a"), 123); - } - - function test_writeToml() public { - string memory json = "json"; - json.serialize("a", uint256(123)); - string memory semiFinal = json.serialize("b", string("test")); - string memory finalJson = json.serialize("c", semiFinal); - finalJson.write(path); - - string memory toml = vm.readFile(path); - bytes memory data = toml.parseRaw("$"); - NestedToml memory decodedData = abi.decode(data, (NestedToml)); - - assertEq(decodedData.a, 123); - assertEq(decodedData.b, "test"); - assertEq(decodedData.c.a, 123); - assertEq(decodedData.c.b, "test"); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol deleted file mode 100644 index aee801b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol +++ /dev/null @@ -1,342 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {Test, StdUtils} from "../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 pure returns (int256) { - return bound(num, min, max); - } - - function exposed_bound(uint256 num, uint256 min, uint256 max) external pure 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 pure { - 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 pure { - 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 pure { - 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 testFuzz_Bound_DistributionIsEven(uint256 min, uint256 size) public pure { - 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 testFuzz_Bound(uint256 num, uint256 min, uint256 max) public pure { - 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 pure { - 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_RevertIf_BoundMaxLessThanMin() 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 testFuzz_RevertIf_BoundMaxLessThanMin(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 pure { - 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 pure { - 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 pure { - 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 testFuzz_BoundInt_DistributionIsEven(int256 min, uint256 size) public pure { - 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 testFuzz_BoundInt(int256 num, int256 min, int256 max) public pure { - 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 pure { - 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 pure { - 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_RevertIf_BoundIntMaxLessThanMin() 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 testFuzz_RevertIf_BoundIntMaxLessThanMin(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 pure { - 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 pure { - 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_RevertIf_BytesLengthExceeds32() 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 pure { - address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; - uint256 nonce = 14; - address createAddress = computeCreateAddress(deployer, nonce); - assertEq(createAddress, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); - } - - /*////////////////////////////////////////////////////////////////////////// - COMPUTE CREATE2 ADDRESS - //////////////////////////////////////////////////////////////////////////*/ - - function test_ComputeCreate2Address() external pure { - 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 pure { - 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_RevertIf_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_RevertIf_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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/Vm.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/Vm.t.sol deleted file mode 100644 index 7c766b1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/Vm.t.sol +++ /dev/null @@ -1,18 +0,0 @@ -// 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"; - -// These tests ensure that functions are never accidentally removed from a Vm interface, or -// inadvertently moved between Vm and VmSafe. These tests must be updated each time a function is -// added to or removed from Vm or VmSafe. -contract VmTest is Test { - function test_VmInterfaceId() public pure { - assertEq(type(Vm).interfaceId, bytes4(0xdb28dd7b), "Vm"); - } - - function test_VmSafeInterfaceId() public pure { - assertEq(type(VmSafe).interfaceId, bytes4(0xb572f44f), "VmSafe"); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol deleted file mode 100644 index e205cff..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol +++ /dev/null @@ -1,10 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol deleted file mode 100644 index ce8e0e9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol +++ /dev/null @@ -1,10 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol deleted file mode 100644 index 9beeafe..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol +++ /dev/null @@ -1,10 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol deleted file mode 100644 index e993535..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol +++ /dev/null @@ -1,10 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/broadcast.log.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/broadcast.log.json deleted file mode 100644 index 0a0200b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/broadcast.log.json +++ /dev/null @@ -1,187 +0,0 @@ -{ - "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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.json deleted file mode 100644 index caebf6d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "a": 123, - "b": "test", - "c": { - "a": 123, - "b": "test" - } -} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.toml b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.toml deleted file mode 100644 index 60692bc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/test.toml +++ /dev/null @@ -1,6 +0,0 @@ -a = 123 -b = "test" - -[c] -a = 123 -b = "test" diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/LICENSE b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/LICENSE deleted file mode 100644 index 0ad25db..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/LICENSE +++ /dev/null @@ -1,661 +0,0 @@ - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/README.md deleted file mode 100644 index 209c2cf..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/README.md +++ /dev/null @@ -1,97 +0,0 @@ -# Halmos Cheat Codes - -Halmos cheatcodes are abstract functions designed to facilitate writing symbolic tests, such as the creation of new symbolic values at runtime. While these cheatcodes are currently exclusive to [Halmos][halmos], they are not limited to it and could potentially be supported by other symbolic testing tools in the future. - -Please refer to [the list of currently available cheatcodes][list]. More cheatcodes will be added in the future. - -Join the [Halmos Telegram Group][chat] for any inquiries or further discussions. - -[halmos]: -[list]: -[chat]: - -## Installation - -To install using Foundry: -``` -forge install a16z/halmos-cheatcodes -``` -Alternatively, you can directly add it as a submodule: -``` -git submodule add https://github.com/a16z/halmos-cheatcodes -``` - -## Example usage - -Below is an example of a symbolic test that checks for potential unauthorized access to others' tokens. The approach involves setting up an initial symbolic state of the token contract, executing an arbitrary function call to the token contract, and checking if there is an execution path that increases the caller's balance and/or decreases the balance of others. This example illustrates how to utilize cheatcodes to set up initial symbolic states and execute arbitrary function calls. - -```solidity -// import Halmos cheatcodes -import {SymTest} from "halmos-cheatcodes/SymTest.sol"; - -import {Test} from "forge-std/Test.sol"; - -import {Token} from "/path/to/Token.sol"; - -contract TokenTest is SymTest, Test { - Token token; - - function setUp() public { - token = new Token(); - - // set the balances of three arbitrary accounts to arbitrary symbolic values - for (uint256 i = 0; i < 3; i++) { - address receiver = svm.createAddress('receiver'); // create a new symbolic address - uint256 amount = svm.createUint256('amount'); // create a new symbolic uint256 value - token.transfer(receiver, amount); - } - } - - function checkBalanceUpdate() public { - // consider two arbitrary distinct accounts - address caller = svm.createAddress('caller'); // create a symbolic address - address others = svm.createAddress('others'); // create another symbolic address - vm.assume(others != caller); // assume the two addresses are different - - // record their current balances - uint256 oldBalanceCaller = token.balanceOf(caller); - uint256 oldBalanceOthers = token.balanceOf(others); - - // execute an arbitrary function call to the token from the caller - vm.prank(caller); - uint256 dataSize = 100; // the max calldata size for the public functions in the token - bytes memory data = svm.createBytes(dataSize, 'data'); // create a symbolic calldata - address(token).call(data); - - // ensure that the caller cannot spend others' tokens - assert(token.balanceOf(caller) <= oldBalanceCaller); // cannot increase their own balance - assert(token.balanceOf(others) >= oldBalanceOthers); // cannot decrease others' balance - } -} -``` - -When running the above test against the following buggy token contract, Halmos will provide a counterexample that may be overlooked during manual reviews. - -```solidity -/// @notice This is a buggy token contract. DO NOT use it in production. -contract Token { - mapping(address => uint) public balanceOf; - - constructor() public { - balanceOf[msg.sender] = 1e27; - } - - function transfer(address to, uint amount) public { - _transfer(msg.sender, to, amount); - } - - function _transfer(address from, address to, uint amount) public { - balanceOf[from] -= amount; - balanceOf[to] += amount; - } -} -``` - -## Disclaimer - -_These smart contracts and code 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 and code. 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 AND CODE 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 and code 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 and code 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/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SVM.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SVM.sol deleted file mode 100644 index b42c25c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SVM.sol +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0 -pragma solidity >=0.8.0 <0.9.0; - -/// @notice Symbolic Virtual Machine -interface SVM { - // Create a new symbolic uint value ranging over [0, 2**bitSize - 1] (inclusive) - function createUint(uint256 bitSize, string memory name) external pure returns (uint256 value); - - // Create a new symbolic uint256 value - function createUint256(string memory name) external pure returns (uint256 value); - - // Create a new symbolic signed int value - function createInt(uint256 bitSize, string memory name) external pure returns (int256 value); - - // Create a new symbolic int256 value - function createInt256(string memory name) external pure returns (int256 value); - - // Create a new symbolic byte array with the given byte size - function createBytes(uint256 byteSize, string memory name) external pure returns (bytes memory value); - - // Create a new symbolic string backed by a symbolic array with the given byte size - function createString(uint256 byteSize, string memory name) external pure returns (string memory value); - - // Create a new symbolic bytes32 value - function createBytes32(string memory name) external pure returns (bytes32 value); - - // Create a new symbolic bytes4 value - function createBytes4(string memory name) external pure returns (bytes4 value); - - // Create a new symbolic address value - function createAddress(string memory name) external pure returns (address value); - - // Create a new symbolic boolean value - function createBool(string memory name) external pure returns (bool value); - - // Create arbitrary symbolic calldata for the given contract or interface name. - // An exception is thrown if the contract name exists in multiple files. An optional filename (with .sol extension) can be provided to avoid ambiguity. - // By default, view and pure functions are excluded. An optional boolean flag can be set to include view and pure functions. - function createCalldata(string memory contractOrInterfaceName) external pure returns (bytes memory data); - function createCalldata(string memory contractOrInterfaceName, bool includeViewAndPureFunctions) external pure returns (bytes memory data); - function createCalldata(string memory filename, string memory contractOrInterfaceName) external pure returns (bytes memory data); - function createCalldata(string memory filename, string memory contractOrInterfaceName, bool includeViewAndPureFunctions) external pure returns (bytes memory data); - - // Assign symbolic values to uninitialized storage slots - function enableSymbolicStorage(address) external; - - // Snapshot the current storage of the given account and return a snapshot ID - function snapshotStorage(address) external returns (uint256 id); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SymTest.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SymTest.sol deleted file mode 100644 index 96684ed..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/SymTest.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0 -pragma solidity >=0.8.0 <0.9.0; - -import {SVM} from "./SVM.sol"; - -abstract contract SymTest { - // SVM cheat code address: 0xf3993a62377bcd56ae39d773740a5390411e8bc9 - address internal constant SVM_ADDRESS = address(uint160(uint256(keccak256("svm cheat code")))); - - SVM internal constant svm = SVM(SVM_ADDRESS); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/logo.svg b/typescript/packages/account-modules/lib/openzeppelin-contracts/logo.svg deleted file mode 100644 index f1e14c2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/logo.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/netlify.toml b/typescript/packages/account-modules/lib/openzeppelin-contracts/netlify.toml deleted file mode 100644 index 0447f41..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/netlify.toml +++ /dev/null @@ -1,3 +0,0 @@ -[build] -command = "npm run docs" -publish = "build/site" diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/package-lock.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/package-lock.json deleted file mode 100644 index acbc992..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/package-lock.json +++ /dev/null @@ -1,10552 +0,0 @@ -{ - "name": "openzeppelin-solidity", - "version": "5.3.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "openzeppelin-solidity", - "version": "5.3.0", - "license": "MIT", - "devDependencies": { - "@changesets/changelog-github": "^0.5.0", - "@changesets/cli": "^2.26.0", - "@changesets/pre": "^2.0.0", - "@changesets/read": "^0.6.0", - "@eslint/compat": "^1.2.1", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.6", - "@nomicfoundation/hardhat-ethers": "^3.0.4", - "@nomicfoundation/hardhat-network-helpers": "^1.0.3", - "@openzeppelin/docs-utils": "^0.1.5", - "@openzeppelin/merkle-tree": "^1.0.7", - "@openzeppelin/upgrade-safe-transpiler": "^0.3.32", - "@openzeppelin/upgrades-core": "^1.20.6", - "chai": "^4.2.0", - "eslint": "^9.0.0", - "eslint-config-prettier": "^10.0.0", - "ethers": "^6.14.0", - "glob": "^11.0.0", - "globals": "^16.0.0", - "graphlib": "^2.1.8", - "hardhat": "^2.24.0", - "hardhat-exposed": "^0.3.15", - "hardhat-gas-reporter": "^2.1.0", - "hardhat-ignore-warnings": "^0.2.11", - "husky": "^9.1.7", - "lint-staged": "^16.0.0", - "lodash.startcase": "^4.4.0", - "micromatch": "^4.0.2", - "p-limit": "^6.0.0", - "prettier": "^3.0.0", - "prettier-plugin-solidity": "^1.1.0", - "rimraf": "^6.0.0", - "semver": "^7.3.5", - "solhint": "^5.0.0", - "solhint-plugin-openzeppelin": "file:scripts/solhint-custom", - "solidity-ast": "^0.4.50", - "solidity-coverage": "^0.8.14", - "solidity-docgen": "^0.6.0-beta.29", - "undici": "^7.4.0", - "yargs": "^17.0.0" - } - }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", - "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", - "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bytecodealliance/preview2-shim": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.0.tgz", - "integrity": "sha512-JorcEwe4ud0x5BS/Ar2aQWOQoFzjq/7jcnxYXCvSMh0oRm0dQXzOA+hqLDBnOMks1LLBA7dmiLLsEBl09Yd6iQ==", - "dev": true, - "license": "(Apache-2.0 WITH LLVM-exception)" - }, - "node_modules/@changesets/apply-release-plan": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-7.0.12.tgz", - "integrity": "sha512-EaET7As5CeuhTzvXTQCRZeBUcisoYPDDcXvgTE/2jmmypKp0RC7LxKj/yzqeh/1qFTZI7oDGFcL1PHRuQuketQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/config": "^3.1.1", - "@changesets/get-version-range-type": "^0.4.0", - "@changesets/git": "^3.0.4", - "@changesets/should-skip-package": "^0.1.2", - "@changesets/types": "^6.1.0", - "@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, - "license": "MIT", - "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": "6.0.6", - "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-6.0.6.tgz", - "integrity": "sha512-Frkj8hWJ1FRZiY3kzVCKzS0N5mMwWKwmv9vpam7vt8rZjLL1JMthdh6pSDVSPumHPshTTkKZ0VtNbE0cJHZZUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/errors": "^0.2.0", - "@changesets/get-dependents-graph": "^2.1.3", - "@changesets/should-skip-package": "^0.1.2", - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3", - "semver": "^7.5.3" - } - }, - "node_modules/@changesets/changelog-git": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.1.tgz", - "integrity": "sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0" - } - }, - "node_modules/@changesets/changelog-github": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@changesets/changelog-github/-/changelog-github-0.5.1.tgz", - "integrity": "sha512-BVuHtF+hrhUScSoHnJwTELB4/INQxVFc+P/Qdt20BLiBFIHFJDDUaGsZw+8fQeJTRP5hJZrzpt3oZWh0G19rAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/get-github-info": "^0.6.0", - "@changesets/types": "^6.1.0", - "dotenv": "^8.1.0" - } - }, - "node_modules/@changesets/cli": { - "version": "2.29.2", - "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.29.2.tgz", - "integrity": "sha512-vwDemKjGYMOc0l6WUUTGqyAWH3AmueeyoJa1KmFRtCYiCoY5K3B68ErYpDB6H48T4lLI4czum4IEjh6ildxUeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/apply-release-plan": "^7.0.12", - "@changesets/assemble-release-plan": "^6.0.6", - "@changesets/changelog-git": "^0.2.1", - "@changesets/config": "^3.1.1", - "@changesets/errors": "^0.2.0", - "@changesets/get-dependents-graph": "^2.1.3", - "@changesets/get-release-plan": "^4.0.10", - "@changesets/git": "^3.0.4", - "@changesets/logger": "^0.1.1", - "@changesets/pre": "^2.0.2", - "@changesets/read": "^0.6.5", - "@changesets/should-skip-package": "^0.1.2", - "@changesets/types": "^6.1.0", - "@changesets/write": "^0.4.0", - "@manypkg/get-packages": "^1.1.3", - "ansi-colors": "^4.1.3", - "ci-info": "^3.7.0", - "enquirer": "^2.4.1", - "external-editor": "^3.1.0", - "fs-extra": "^7.0.1", - "mri": "^1.2.0", - "p-limit": "^2.2.0", - "package-manager-detector": "^0.2.0", - "picocolors": "^1.1.0", - "resolve-from": "^5.0.0", - "semver": "^7.5.3", - "spawndamnit": "^3.0.1", - "term-size": "^2.1.0" - }, - "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, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@changesets/config": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@changesets/config/-/config-3.1.1.tgz", - "integrity": "sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/errors": "^0.2.0", - "@changesets/get-dependents-graph": "^2.1.3", - "@changesets/logger": "^0.1.1", - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3", - "fs-extra": "^7.0.1", - "micromatch": "^4.0.8" - } - }, - "node_modules/@changesets/errors": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.2.0.tgz", - "integrity": "sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==", - "dev": true, - "license": "MIT", - "dependencies": { - "extendable-error": "^0.1.5" - } - }, - "node_modules/@changesets/get-dependents-graph": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-2.1.3.tgz", - "integrity": "sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3", - "picocolors": "^1.1.0", - "semver": "^7.5.3" - } - }, - "node_modules/@changesets/get-github-info": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@changesets/get-github-info/-/get-github-info-0.6.0.tgz", - "integrity": "sha512-v/TSnFVXI8vzX9/w3DU2Ol+UlTZcu3m0kXTjTT4KlAdwSvwutcByYwyYn9hwerPWfPkT2JfpoX0KgvCEi8Q/SA==", - "dev": true, - "license": "MIT", - "dependencies": { - "dataloader": "^1.4.0", - "node-fetch": "^2.5.0" - } - }, - "node_modules/@changesets/get-release-plan": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-4.0.10.tgz", - "integrity": "sha512-CCJ/f3edYaA3MqoEnWvGGuZm0uMEMzNJ97z9hdUR34AOvajSwySwsIzC/bBu3+kuGDsB+cny4FljG8UBWAa7jg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/assemble-release-plan": "^6.0.6", - "@changesets/config": "^3.1.1", - "@changesets/pre": "^2.0.2", - "@changesets/read": "^0.6.5", - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3" - } - }, - "node_modules/@changesets/get-version-range-type": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.4.0.tgz", - "integrity": "sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@changesets/git": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@changesets/git/-/git-3.0.4.tgz", - "integrity": "sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/errors": "^0.2.0", - "@manypkg/get-packages": "^1.1.3", - "is-subdir": "^1.1.1", - "micromatch": "^4.0.8", - "spawndamnit": "^3.0.1" - } - }, - "node_modules/@changesets/logger": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.1.1.tgz", - "integrity": "sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "picocolors": "^1.1.0" - } - }, - "node_modules/@changesets/parse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.4.1.tgz", - "integrity": "sha512-iwksMs5Bf/wUItfcg+OXrEpravm5rEd9Bf4oyIPL4kVTmJQ7PNDSd6MDYkpSJR1pn7tz/k8Zf2DhTCqX08Ou+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0", - "js-yaml": "^3.13.1" - } - }, - "node_modules/@changesets/pre": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-2.0.2.tgz", - "integrity": "sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/errors": "^0.2.0", - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3", - "fs-extra": "^7.0.1" - } - }, - "node_modules/@changesets/read": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.6.5.tgz", - "integrity": "sha512-UPzNGhsSjHD3Veb0xO/MwvasGe8eMyNrR/sT9gR8Q3DhOQZirgKhhXv/8hVsI0QpPjR004Z9iFxoJU6in3uGMg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/git": "^3.0.4", - "@changesets/logger": "^0.1.1", - "@changesets/parse": "^0.4.1", - "@changesets/types": "^6.1.0", - "fs-extra": "^7.0.1", - "p-filter": "^2.1.0", - "picocolors": "^1.1.0" - } - }, - "node_modules/@changesets/should-skip-package": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.2.tgz", - "integrity": "sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3" - } - }, - "node_modules/@changesets/types": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", - "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@changesets/write": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.4.0.tgz", - "integrity": "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0", - "fs-extra": "^7.0.1", - "human-id": "^4.1.1", - "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, - "license": "MIT", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", - "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/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, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/compat": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.9.tgz", - "integrity": "sha512-gCdSY54n7k+driCadyMNv8JSPzYLeDVM/ikZRtvtROBpRdFSkS8W9A82MqsaY7lZuwL0wiapgD0NT1xT0hyJsA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": "^9.10.0" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/@eslint/config-array": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", - "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.6", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/config-array/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz", - "integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.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": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/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, - "license": "MIT", - "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/@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, - "license": "Python-2.0" - }, - "node_modules/@eslint/eslintrc/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@eslint/eslintrc/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, - "license": "MIT" - }, - "node_modules/@eslint/eslintrc/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "9.25.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz", - "integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.13.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@ethereumjs/common": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-3.2.0.tgz", - "integrity": "sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ethereumjs/util": "^8.1.0", - "crc-32": "^1.2.0" - } - }, - "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, - "license": "MPL-2.0", - "bin": { - "rlp": "bin/rlp" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@ethereumjs/tx": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-4.2.0.tgz", - "integrity": "sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@ethereumjs/common": "^3.2.0", - "@ethereumjs/rlp": "^4.0.1", - "@ethereumjs/util": "^8.1.0", - "ethereum-cryptography": "^2.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@ethereumjs/tx/node_modules/@noble/curves": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.4.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/tx/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/tx/node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/tx/node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/tx/node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/tx/node_modules/ethereum-cryptography": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "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, - "license": "MPL-2.0", - "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/@noble/curves": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.4.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/util/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/util/node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/util/node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/util/node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "node_modules/@ethersproject/abi": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.8.0.tgz", - "integrity": "sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/address": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/hash": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@ethersproject/abstract-provider": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz", - "integrity": "sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/networks": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/transactions": "^5.8.0", - "@ethersproject/web": "^5.8.0" - } - }, - "node_modules/@ethersproject/abstract-signer": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz", - "integrity": "sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abstract-provider": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0" - } - }, - "node_modules/@ethersproject/address": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.8.0.tgz", - "integrity": "sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/rlp": "^5.8.0" - } - }, - "node_modules/@ethersproject/base64": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.8.0.tgz", - "integrity": "sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0" - } - }, - "node_modules/@ethersproject/bignumber": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz", - "integrity": "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "bn.js": "^5.2.1" - } - }, - "node_modules/@ethersproject/bytes": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", - "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/constants": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", - "integrity": "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.8.0" - } - }, - "node_modules/@ethersproject/hash": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.8.0.tgz", - "integrity": "sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abstract-signer": "^5.8.0", - "@ethersproject/address": "^5.8.0", - "@ethersproject/base64": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@ethersproject/keccak256": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz", - "integrity": "sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "js-sha3": "0.8.0" - } - }, - "node_modules/@ethersproject/logger": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", - "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", - "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" - } - ], - "license": "MIT" - }, - "node_modules/@ethersproject/networks": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", - "integrity": "sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/properties": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", - "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/rlp": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.8.0.tgz", - "integrity": "sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/signing-key": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", - "integrity": "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "bn.js": "^5.2.1", - "elliptic": "6.6.1", - "hash.js": "1.1.7" - } - }, - "node_modules/@ethersproject/strings": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz", - "integrity": "sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/transactions": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz", - "integrity": "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/address": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/rlp": "^5.8.0", - "@ethersproject/signing-key": "^5.8.0" - } - }, - "node_modules/@ethersproject/units": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.8.0.tgz", - "integrity": "sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/web": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.8.0.tgz", - "integrity": "sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==", - "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" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/base64": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "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, - "license": "MIT", - "engines": { - "node": ">=12.x", - "pnpm": "7.5.1" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "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, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", - "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "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, - "license": "ISC", - "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.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/@metamask/abi-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@metamask/abi-utils/-/abi-utils-2.0.4.tgz", - "integrity": "sha512-StnIgUB75x7a7AgUhiaUZDpCsqGp7VkNnZh2XivXkJ6mPkE83U8ARGQj5MbRis7VJY8BC5V1AbB1fjdh0hupPQ==", - "dev": true, - "license": "(Apache-2.0 AND MIT)", - "dependencies": { - "@metamask/superstruct": "^3.1.0", - "@metamask/utils": "^9.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/superstruct": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@metamask/superstruct/-/superstruct-3.2.1.tgz", - "integrity": "sha512-fLgJnDOXFmuVlB38rUN5SmU7hAFQcCjrg3Vrxz67KTY7YHFnSNEKvX4avmEBdOI0yTCxZjwMCFEqsC8k2+Wd3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/utils": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-9.3.0.tgz", - "integrity": "sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==", - "dev": true, - "license": "ISC", - "dependencies": { - "@ethereumjs/tx": "^4.2.0", - "@metamask/superstruct": "^3.1.0", - "@noble/hashes": "^1.3.1", - "@scure/base": "^1.1.3", - "@types/debug": "^4.1.7", - "debug": "^4.3.4", - "pony-cause": "^2.1.10", - "semver": "^7.5.4", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@noble/ciphers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", - "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.0.tgz", - "integrity": "sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.8.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@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/" - } - ], - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nomicfoundation/edr": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.11.0.tgz", - "integrity": "sha512-36WERf8ldvyHR6UAbcYsa+vpbW7tCrJGBwF4gXSsb8+STj1n66Hz85Y/O7B9+8AauX3PhglvV5dKl91tk43mWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nomicfoundation/edr-darwin-arm64": "0.11.0", - "@nomicfoundation/edr-darwin-x64": "0.11.0", - "@nomicfoundation/edr-linux-arm64-gnu": "0.11.0", - "@nomicfoundation/edr-linux-arm64-musl": "0.11.0", - "@nomicfoundation/edr-linux-x64-gnu": "0.11.0", - "@nomicfoundation/edr-linux-x64-musl": "0.11.0", - "@nomicfoundation/edr-win32-x64-msvc": "0.11.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-darwin-arm64": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.11.0.tgz", - "integrity": "sha512-aYTVdcSs27XG7ayTzvZ4Yn9z/ABSaUwicrtrYK2NR8IH0ik4N4bWzo/qH8rax6rewVLbHUkGyGYnsy5ZN4iiMw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-darwin-x64": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.11.0.tgz", - "integrity": "sha512-RxX7UYgvJrfcyT/uHUn44Nsy1XaoW+Q1khKMdHKxeW7BrgIi+Lz+siz3bX5vhSoAnKilDPhIVLrnC8zxQhjR2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.11.0.tgz", - "integrity": "sha512-J0j+rs0s11FuSipt/ymqrFmpJ7c0FSz1/+FohCIlUXDxFv//+1R/8lkGPjEYFmy8DPpk/iO8mcpqHTGckREbqA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-linux-arm64-musl": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.11.0.tgz", - "integrity": "sha512-4r32zkGMN7WT/CMEuW0VjbuEdIeCskHNDMW4SSgQSJOE/N9L1KSLJCSsAbPD3aYE+e4WRDTyOwmuLjeUTcLZKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-linux-x64-gnu": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.11.0.tgz", - "integrity": "sha512-SmdncQHLYtVNWLIMyGaY6LpAfamzTDe3fxjkirmJv3CWR5tcEyC6LMui/GsIVnJzXeNJBXAzwl8hTUAxHTM6kQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-linux-x64-musl": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.11.0.tgz", - "integrity": "sha512-w6hUqpn/trwiH6SRuRGysj37LsQVCX5XDCA3Xi81sbOaLhbHrNvK9TXWyZmcuzbdTKQQW6VNywcSxDdOiChcJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-win32-x64-msvc": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.11.0.tgz", - "integrity": "sha512-BLmULjRKoH9BsX+c4Na2ypV7NGeJ+M6Zpqj/faPOwleVscDdSr/IhriyPaXCe8dyfwbge7lWsbekiADtPSnB2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/hardhat-chai-matchers": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.8.tgz", - "integrity": "sha512-Z5PiCXH4xhNLASROlSUOADfhfpfhYO6D7Hn9xp8PddmHey0jq704cr6kfU8TRrQ4PUZbpfsZadPj+pCfZdjPIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/chai-as-promised": "^7.1.3", - "chai-as-promised": "^7.1.1", - "deep-eql": "^4.0.1", - "ordinal": "^1.0.3" - }, - "peerDependencies": { - "@nomicfoundation/hardhat-ethers": "^3.0.0", - "chai": "^4.2.0", - "ethers": "^6.1.0", - "hardhat": "^2.9.4" - } - }, - "node_modules/@nomicfoundation/hardhat-ethers": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.8.tgz", - "integrity": "sha512-zhOZ4hdRORls31DTOqg+GmEZM0ujly8GGIuRY7t7szEk2zW/arY1qDug/py8AEktT00v5K+b6RvbVog+va51IA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.1", - "lodash.isequal": "^4.5.0" - }, - "peerDependencies": { - "ethers": "^6.1.0", - "hardhat": "^2.0.0" - } - }, - "node_modules/@nomicfoundation/hardhat-network-helpers": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.12.tgz", - "integrity": "sha512-xTNQNI/9xkHvjmCJnJOTyqDSl8uq1rKb2WOVmixQxFtRd7Oa3ecO8zM0cyC2YmOK+jHB9WPZ+F/ijkHg1CoORA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ethereumjs-util": "^7.1.4" - }, - "peerDependencies": { - "hardhat": "^2.9.5" - } - }, - "node_modules/@nomicfoundation/slang": { - "version": "0.18.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/slang/-/slang-0.18.3.tgz", - "integrity": "sha512-YqAWgckqbHM0/CZxi9Nlf4hjk9wUNLC9ngWCWBiqMxPIZmzsVKYuChdlrfeBPQyvQQBoOhbx+7C1005kLVQDZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bytecodealliance/preview2-shim": "0.17.0" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz", - "integrity": "sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - }, - "optionalDependencies": { - "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.2", - "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.2", - "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.2" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz", - "integrity": "sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz", - "integrity": "sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz", - "integrity": "sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz", - "integrity": "sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz", - "integrity": "sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz", - "integrity": "sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz", - "integrity": "sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "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, - "license": "MIT", - "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/merkle-tree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@openzeppelin/merkle-tree/-/merkle-tree-1.0.8.tgz", - "integrity": "sha512-E2c9/Y3vjZXwVvPZKqCKUn7upnvam1P1ZhowJyZVQSkzZm5WhumtaRr+wkUXrZVfkIc7Gfrl7xzabElqDL09ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@metamask/abi-utils": "^2.0.4", - "ethereum-cryptography": "^3.0.0" - } - }, - "node_modules/@openzeppelin/upgrade-safe-transpiler": { - "version": "0.3.33", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrade-safe-transpiler/-/upgrade-safe-transpiler-0.3.33.tgz", - "integrity": "sha512-yKdnfZtfDw0ivonZmDx1YgFJXLNHz/5+XPN7bx/9ObQYKUawmTiOcGC6BKezpphL+witvHQbMhmQbwGIyEoR8g==", - "dev": true, - "license": "MIT", - "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/@noble/curves": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.4.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/ethereum-cryptography": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "node_modules/@openzeppelin/upgrades-core": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.44.0.tgz", - "integrity": "sha512-AUnQW7cbh2ntFuQdHi5C0vKB+QfkTQtzXgCmzazXLJDX7slFTF676lw+x97ZKfzwQw5unO1+ALZMx+s+2yQUew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nomicfoundation/slang": "^0.18.3", - "bignumber.js": "^9.1.2", - "cbor": "^10.0.0", - "chalk": "^4.1.0", - "compare-versions": "^6.0.0", - "debug": "^4.1.1", - "ethereumjs-util": "^7.0.3", - "minimatch": "^9.0.5", - "minimist": "^1.2.7", - "proper-lockfile": "^4.1.1", - "solidity-ast": "^0.4.60" - }, - "bin": { - "openzeppelin-upgrades-core": "dist/cli/cli.js" - } - }, - "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, - "license": "MIT", - "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/@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, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@pnpm/config.env-replace": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", - "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.22.0" - } - }, - "node_modules/@pnpm/network.ca-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", - "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "4.2.10" - }, - "engines": { - "node": ">=12.22.0" - } - }, - "node_modules/@pnpm/network.ca-file/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, - "license": "ISC" - }, - "node_modules/@pnpm/npm-conf": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", - "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@pnpm/config.env-replace": "^1.1.0", - "@pnpm/network.ca-file": "^1.0.1", - "config-chain": "^1.1.11" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@scure/base": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.5.tgz", - "integrity": "sha512-9rE6EOVeIQzt5TSu4v+K523F8u6DhBsoZWPGKlnCshhlDhy0kJzUX4V+tr2dWmzF1GdekvThABoEQBGBQI7xZw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", - "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.9.0", - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", - "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "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, - "license": "BSD-3-Clause", - "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/core/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, - "license": "0BSD" - }, - "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, - "license": "BSD-3-Clause", - "dependencies": { - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/hub/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, - "license": "0BSD" - }, - "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, - "license": "BSD-3-Clause", - "dependencies": { - "@sentry/hub": "5.30.0", - "@sentry/types": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/minimal/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, - "license": "0BSD" - }, - "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, - "license": "BSD-3-Clause", - "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/node/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, - "license": "0BSD" - }, - "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, - "license": "MIT", - "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/tracing/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, - "license": "0BSD" - }, - "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, - "license": "BSD-3-Clause", - "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, - "license": "BSD-3-Clause", - "dependencies": { - "@sentry/types": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/utils/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, - "license": "0BSD" - }, - "node_modules/@sindresorhus/is": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", - "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@solidity-parser/parser": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.19.0.tgz", - "integrity": "sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT", - "dependencies": { - "defer-to-connect": "^2.0.1" - }, - "engines": { - "node": ">=14.16" - } - }, - "node_modules/@types/bn.js": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.6.tgz", - "integrity": "sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/chai": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.1.tgz", - "integrity": "sha512-iu1JLYmGmITRzUgNiLMZD3WCoFzpYtueuyAgHTXqgwSRAMIlFTnZqG6/xenkpUGRJEzSfklUTI4GNSzks/dc0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*" - } - }, - "node_modules/@types/chai-as-promised": { - "version": "7.1.8", - "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", - "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/chai": "*" - } - }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT", - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "node_modules/@types/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/secp256k1": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz", - "integrity": "sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "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, - "license": "ISC" - }, - "node_modules/abitype": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.8.tgz", - "integrity": "sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "typescript": ">=5.0.4", - "zod": "^3 >=3.22.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, - "license": "MIT", - "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, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.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, - "license": "MIT", - "engines": { - "node": ">=0.3.0" - } - }, - "node_modules/aes-js": { - "version": "4.0.0-beta.5", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", - "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.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, - "license": "BSD-3-Clause OR MIT", - "optional": true, - "engines": { - "node": ">=0.4.2" - } - }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.1.0" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/antlr4": { - "version": "4.13.2", - "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.2.tgz", - "integrity": "sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=16" - } - }, - "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, - "license": "ISC", - "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, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "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, - "license": "MIT", - "engines": { - "node": ">=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, - "license": "MIT", - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "node_modules/axios": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", - "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", - "dev": true, - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.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, - "license": "MIT" - }, - "node_modules/base-x": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", - "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "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, - "license": "MIT", - "dependencies": { - "is-windows": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/bignumber.js": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz", - "integrity": "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "MIT" - }, - "node_modules/bn.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", - "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", - "dev": true, - "license": "MIT" - }, - "node_modules/boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/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, - "license": "MIT", - "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/boxen/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, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.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, - "license": "MIT" - }, - "node_modules/brotli-wasm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brotli-wasm/-/brotli-wasm-2.0.1.tgz", - "integrity": "sha512-+3USgYsC7bzb5yU0/p2HnnynZl0ak0E6uoIm4UW4Aby/8s8HFCq6NCfrrf1E9c3O8OCSzq3oYO1tUVqIi61Nww==", - "dev": true, - "license": "Apache-2.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, - "license": "ISC" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacheable-lookup": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", - "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.16" - } - }, - "node_modules/cacheable-request": { - "version": "10.2.14", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", - "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-cache-semantics": "^4.0.2", - "get-stream": "^6.0.1", - "http-cache-semantics": "^4.1.1", - "keyv": "^4.5.3", - "mimic-response": "^4.0.0", - "normalize-url": "^8.0.0", - "responselike": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - } - }, - "node_modules/cacheable-request/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, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.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, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cbor": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-10.0.3.tgz", - "integrity": "sha512-72Jnj81xMsqepqdcSdf2+fflz/UDsThOHy5hj2MW5F5xzHL8Oa0KQ6I6V9CwVUPxg5pf+W9xp6W2KilaRXWWtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "nofilter": "^3.0.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/chai": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", - "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chai-as-promised": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", - "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", - "dev": true, - "license": "WTFPL", - "dependencies": { - "check-error": "^1.0.2" - }, - "peerDependencies": { - "chai": ">= 2.1.2 < 6" - } - }, - "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, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "BSD-3-Clause", - "engines": { - "node": "*" - } - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "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" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cipher-base": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", - "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "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, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-table3": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", - "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, - "node_modules/cli-truncate": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", - "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", - "dev": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/cli-truncate/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true, - "license": "MIT" - }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/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, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "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, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT" - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "MIT" - }, - "node_modules/commander": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/compare-versions": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", - "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "node_modules/config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "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, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "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, - "license": "MIT", - "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, - "license": "Python-2.0" - }, - "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, - "license": "MIT", - "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, - "license": "Apache-2.0", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "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, - "license": "BSD-3-Clause", - "engines": { - "node": "*" - } - }, - "node_modules/dataloader": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", - "integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "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.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "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, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "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, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true, - "license": "BSD-3-Clause", - "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, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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, - "license": "BSD-2-Clause", - "engines": { - "node": ">=10" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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, - "license": "MIT" - }, - "node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "dev": true, - "license": "MIT", - "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.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.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, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "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, - "license": "MIT", - "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, - "license": "BSD-2-Clause", - "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, - "license": "BSD-2-Clause", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint": { - "version": "9.25.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz", - "integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.20.0", - "@eslint/config-helpers": "^0.2.1", - "@eslint/core": "^0.13.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.25.1", - "@eslint/plugin-kit": "^0.2.8", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.3.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-config-prettier": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.2.tgz", - "integrity": "sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA==", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", - "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/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, - "license": "MIT", - "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/eslint/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/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, - "license": "MIT" - }, - "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, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/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, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.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, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "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, - "license": "BSD-2-Clause", - "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, - "license": "BSD-2-Clause", - "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, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ethereum-bloom-filters": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.2.0.tgz", - "integrity": "sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "^1.4.0" - } - }, - "node_modules/ethereum-cryptography": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-3.2.0.tgz", - "integrity": "sha512-Urr5YVsalH+Jo0sYkTkv1MyI9bLYZwW8BENZCeE1QYaTHETEYx0Nv/SVsWkSqpYrzweg6d8KMY1wTjH/1m/BIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/ciphers": "1.3.0", - "@noble/curves": "1.9.0", - "@noble/hashes": "1.8.0", - "@scure/bip32": "1.7.0", - "@scure/bip39": "1.6.0" - }, - "engines": { - "node": "^14.21.3 || >=16", - "npm": ">=9" - } - }, - "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, - "license": "MPL-2.0", - "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/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, - "license": "MIT", - "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/ethers": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.14.0.tgz", - "integrity": "sha512-KgHwltNSMdbrGWEyKkM0Rt2s+u1nDH/5BVDQakLinzGEJi4bWindBzZSCC4gKsbZjwDTI6ex/8suR9Ihbmz4IQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "1.10.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "22.7.5", - "aes-js": "4.0.0-beta.5", - "tslib": "2.7.0", - "ws": "8.17.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/ethers/node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethers/node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethers/node_modules/@types/node": { - "version": "22.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT" - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "Apache-2.0" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "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.8" - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/form-data-encoder": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", - "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.17" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "ISC" - }, - "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, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "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, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", - "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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, - "license": "ISC", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/glob": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.2.tgz", - "integrity": "sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^4.0.1", - "minimatch": "^10.0.0", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "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, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/globals": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", - "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "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.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/got": { - "version": "12.6.1", - "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", - "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sindresorhus/is": "^5.2.0", - "@szmarczak/http-timer": "^5.0.1", - "cacheable-lookup": "^7.0.0", - "cacheable-request": "^10.2.8", - "decompress-response": "^6.0.0", - "form-data-encoder": "^2.1.2", - "get-stream": "^6.0.1", - "http2-wrapper": "^2.1.10", - "lowercase-keys": "^3.0.0", - "p-cancelable": "^3.0.0", - "responselike": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/got/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, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "ISC" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hardhat": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.24.0.tgz", - "integrity": "sha512-wDkD5GPmttYv21MR7tGDkyQ22tO2V86OEV8pA7NcXWYUpibe8XZ2EanXCeRHO61vwEx0f7/M+NqrhJwasaNMJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ethereumjs/util": "^9.1.0", - "@ethersproject/abi": "^5.1.2", - "@nomicfoundation/edr": "^0.11.0", - "@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", - "boxen": "^5.1.2", - "chokidar": "^4.0.0", - "ci-info": "^2.0.0", - "debug": "^4.1.1", - "enquirer": "^2.3.0", - "env-paths": "^2.2.0", - "ethereum-cryptography": "^1.0.3", - "find-up": "^5.0.0", - "fp-ts": "1.19.3", - "fs-extra": "^7.0.1", - "immutable": "^4.0.0-rc.12", - "io-ts": "1.10.4", - "json-stream-stringify": "^3.1.4", - "keccak": "^3.0.2", - "lodash": "^4.17.11", - "micro-eth-signer": "^0.14.0", - "mnemonist": "^0.38.0", - "mocha": "^10.0.0", - "p-map": "^4.0.0", - "picocolors": "^1.1.0", - "raw-body": "^2.4.1", - "resolve": "1.17.0", - "semver": "^6.3.0", - "solc": "0.8.26", - "source-map-support": "^0.5.13", - "stacktrace-parser": "^0.1.10", - "tinyglobby": "^0.2.6", - "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.19", - "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.19.tgz", - "integrity": "sha512-vVye5TurJu8dWeo4ma+EfLAOQaJyica4uncd0/BGPO2tmexuDwZUmE1vYx81PlP4Iak3wqkNTEPxWQaE2ZnKnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "micromatch": "^4.0.8", - "solidity-ast": "^0.4.59" - }, - "peerDependencies": { - "hardhat": "^2.3.0" - } - }, - "node_modules/hardhat-gas-reporter": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-2.2.3.tgz", - "integrity": "sha512-/52fDR0WOgPTjImmx4j179SAgxPv/499TD0o0qnMhaRr24i2cqlcmCW92FJi0QAKu7HcnxdBGZWQP/5aPjQqUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ethersproject/abi": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/units": "^5.7.0", - "@solidity-parser/parser": "^0.19.0", - "axios": "^1.6.7", - "brotli-wasm": "^2.0.1", - "chalk": "4.1.2", - "cli-table3": "^0.6.3", - "ethereum-cryptography": "^2.1.3", - "glob": "^10.3.10", - "jsonschema": "^1.4.1", - "lodash": "^4.17.21", - "markdown-table": "2.0.0", - "sha1": "^1.1.1", - "viem": "^2.27.0" - }, - "peerDependencies": { - "hardhat": "^2.16.0" - } - }, - "node_modules/hardhat-gas-reporter/node_modules/@noble/curves": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.4.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/hardhat-gas-reporter/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/hardhat-gas-reporter/node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/hardhat-gas-reporter/node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/hardhat-gas-reporter/node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/hardhat-gas-reporter/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, - "license": "MIT", - "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/hardhat-gas-reporter/node_modules/ethereum-cryptography": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "node_modules/hardhat-gas-reporter/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/hardhat-gas-reporter/node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/hardhat-gas-reporter/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/hardhat-gas-reporter/node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/hardhat-ignore-warnings": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/hardhat-ignore-warnings/-/hardhat-ignore-warnings-0.2.12.tgz", - "integrity": "sha512-SaxCLKzYBMk3Rd1275TnanUmmxwgU+bu4Ekf2MKcqXxxt6xTGcPTtTaM+USrLgmejZHC4Itg/PaWITlOp4RL3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimatch": "^5.1.0", - "node-interval-tree": "^2.0.1", - "solidity-comments": "^0.0.2" - } - }, - "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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hardhat/node_modules/@ethereumjs/rlp": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-5.0.2.tgz", - "integrity": "sha512-DziebCdg4JpGlEqEdGgXmjqcFoJi+JGulUXwEjsZGAscAQ7MyD/7LE/GVCP29vEQxKc7AAwjT3A2ywHp2xfoCA==", - "dev": true, - "license": "MPL-2.0", - "bin": { - "rlp": "bin/rlp.cjs" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/hardhat/node_modules/@ethereumjs/util": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-9.1.0.tgz", - "integrity": "sha512-XBEKsYqLGXLah9PNJbgdkigthkG7TAGvlD/sH12beMXEyHDyigfcbdvHhmLyDWgDyOJn4QwiQUaF7yeuhnjdog==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@ethereumjs/rlp": "^5.0.2", - "ethereum-cryptography": "^2.2.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/hardhat/node_modules/@ethereumjs/util/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/hardhat/node_modules/@ethereumjs/util/node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/hardhat/node_modules/@ethereumjs/util/node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/hardhat/node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "node_modules/hardhat/node_modules/@noble/curves": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.4.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/hardhat/node_modules/@noble/curves/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "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/" - } - ], - "license": "MIT" - }, - "node_modules/hardhat/node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", - "dev": true, - "license": "MIT", - "funding": { - "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/" - } - ], - "license": "MIT", - "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/" - } - ], - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.2.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/hardhat/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "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": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hardhat/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, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hardhat/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, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hardhat/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, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hardhat/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "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, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/hardhat/node_modules/undici": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", - "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, - "engines": { - "node": ">=14.0" - } - }, - "node_modules/hardhat/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, - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/hardhat/node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "dev": true, - "license": "MIT", - "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/hardhat/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, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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, - "license": "MIT", - "bin": { - "he": "bin/he" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "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, - "license": "BSD-2-Clause" - }, - "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, - "license": "MIT", - "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/http2-wrapper": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", - "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", - "dev": true, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-id": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.1.1.tgz", - "integrity": "sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg==", - "dev": true, - "license": "MIT", - "bin": { - "human-id": "dist/cli.js" - } - }, - "node_modules/husky": { - "version": "9.1.7", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", - "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", - "dev": true, - "license": "MIT", - "bin": { - "husky": "bin.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, - "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, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/immutable": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", - "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", - "dev": true, - "license": "MIT" - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "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, - "license": "ISC" - }, - "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, - "license": "ISC" - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "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, - "license": "MIT", - "dependencies": { - "fp-ts": "^1.0.0" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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, - "license": "MIT", - "dependencies": { - "better-path-resolve": "1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "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, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/isows": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.6.tgz", - "integrity": "sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "peerDependencies": { - "ws": "*" - } - }, - "node_modules/jackspeak": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz", - "integrity": "sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "node_modules/json-stream-stringify": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz", - "integrity": "sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=7.10.1" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonschema": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz", - "integrity": "sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "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, - "license": "MIT", - "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/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "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, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/latest-version": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", - "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "package-json": "^8.1.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "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, - "license": "MIT" - }, - "node_modules/lint-staged": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.0.0.tgz", - "integrity": "sha512-sUCprePs6/rbx4vKC60Hez6X10HPkpDJaGcy3D1NdwR7g1RcNkWL8q9mJMreOqmHBTs+1sNFp+wOiX9fr+hoOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^5.4.1", - "commander": "^13.1.0", - "debug": "^4.4.0", - "lilconfig": "^3.1.3", - "listr2": "^8.3.3", - "micromatch": "^4.0.8", - "nano-spawn": "^1.0.0", - "pidtree": "^0.6.0", - "string-argv": "^0.3.2", - "yaml": "^2.7.1" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, - "engines": { - "node": ">=20.18" - }, - "funding": { - "url": "https://opencollective.com/lint-staged" - } - }, - "node_modules/lint-staged/node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/listr2": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", - "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "cli-truncate": "^4.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/listr2/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/listr2/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, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/listr2/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true, - "license": "MIT" - }, - "node_modules/listr2/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/listr2/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, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/listr2/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT" - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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-update": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", - "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^7.0.0", - "cli-cursor": "^5.0.0", - "slice-ansi": "^7.1.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-escapes": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", - "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/log-update/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, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-update/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true, - "license": "MIT" - }, - "node_modules/log-update/node_modules/is-fullwidth-code-point": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", - "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", - "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/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, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", - "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", - "dev": true, - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/markdown-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", - "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", - "dev": true, - "license": "MIT", - "dependencies": { - "repeat-string": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "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, - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "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/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micro-eth-signer": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.14.0.tgz", - "integrity": "sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.8.1", - "@noble/hashes": "~1.7.1", - "micro-packed": "~0.7.2" - } - }, - "node_modules/micro-eth-signer/node_modules/@noble/curves": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", - "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.7.2" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/micro-eth-signer/node_modules/@noble/hashes": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", - "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "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, - "license": "MIT" - }, - "node_modules/micro-packed": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.7.3.tgz", - "integrity": "sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mimic-response": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", - "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "ISC" - }, - "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, - "license": "MIT" - }, - "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "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, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "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, - "license": "MIT", - "dependencies": { - "obliterator": "^2.0.0" - } - }, - "node_modules/mocha": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", - "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.3", - "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", - "debug": "^4.3.5", - "diff": "^5.2.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^8.1.0", - "he": "^1.2.0", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", - "ms": "^2.1.3", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9", - "yargs-unparser": "^2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "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, - "license": "Python-2.0" - }, - "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, - "license": "ISC", - "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, - "license": "MIT", - "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": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "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/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, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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/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, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "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, - "license": "MIT" - }, - "node_modules/nano-spawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-1.0.1.tgz", - "integrity": "sha512-BfcvzBlUTxSDWfT+oH7vd6CbUV+rThLLHCIym/QO6GGLBsyVXleZs00fto2i2jzC/wPiBYk5jyOmpXWg4YopiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18" - }, - "funding": { - "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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.8.4", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", - "dev": true, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "ISC", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.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, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", - "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT" - }, - "node_modules/obliterator": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", - "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "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.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ordinal": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ordinal/-/ordinal-1.0.3.tgz", - "integrity": "sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "MIT" - }, - "node_modules/ox": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", - "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "^1.10.1", - "@noble/curves": "^1.6.0", - "@noble/hashes": "^1.5.0", - "@scure/bip32": "^1.5.0", - "@scure/bip39": "^1.4.0", - "abitype": "^1.0.6", - "eventemitter3": "5.0.1" - }, - "peerDependencies": { - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": 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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/p-limit": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", - "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.1.1" - }, - "engines": { - "node": ">=18" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", - "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", - "dev": true, - "license": "MIT", - "dependencies": { - "got": "^12.1.0", - "registry-auth-token": "^5.0.1", - "registry-url": "^6.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/package-manager-detector": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.11.tgz", - "integrity": "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "quansync": "^0.2.7" - } - }, - "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, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "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, - "license": "MIT", - "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/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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", - "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", - "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "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, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/pony-cause": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.11.tgz", - "integrity": "sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==", - "dev": true, - "license": "0BSD", - "engines": { - "node": ">=12.0.0" - } - }, - "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, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-plugin-solidity": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.4.3.tgz", - "integrity": "sha512-Mrr/iiR9f9IaeGRMZY2ApumXcn/C5Gs3S7B7hWB3gigBFML06C0yEyW86oLp0eqiA0qg+46FaChgLPJCj/pIlg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@solidity-parser/parser": "^0.20.1", - "semver": "^7.7.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "prettier": ">=2.3.0" - } - }, - "node_modules/prettier-plugin-solidity/node_modules/@solidity-parser/parser": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.20.1.tgz", - "integrity": "sha512-58I2sRpzaQUN+jJmWbHfbWf9AKfzqCI8JAdFB0vbyY+u8tBRcuTt9LxzasvR0LGQpcRv97eyV7l61FQ3Ib7zVw==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "retry": "^0.12.0", - "signal-exit": "^3.0.2" - } - }, - "node_modules/proper-lockfile/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, - "license": "ISC" - }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true, - "license": "ISC" - }, - "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, - "license": "MIT" - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/quansync": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.10.tgz", - "integrity": "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/antfu" - }, - { - "type": "individual", - "url": "https://github.com/sponsors/sxzz" - } - ], - "license": "MIT" - }, - "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" - } - ], - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "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, - "license": "MIT", - "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/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/recursive-readdir/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/recursive-readdir/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/registry-auth-token": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.0.tgz", - "integrity": "sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@pnpm/npm-conf": "^2.1.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/registry-url": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", - "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "rc": "1.2.8" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/responselike": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", - "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", - "dev": true, - "license": "MIT", - "dependencies": { - "lowercase-keys": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/rimraf": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", - "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^11.0.0", - "package-json-from-dist": "^1.0.0" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "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, - "license": "MIT", - "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, - "license": "MPL-2.0", - "dependencies": { - "bn.js": "^5.2.0" - }, - "bin": { - "rlp": "bin/rlp" - } - }, - "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" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "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" - } - ], - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "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, - "license": "BSD-3-Clause", - "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/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "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, - "license": "BSD-2-Clause", - "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==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "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, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sc-istanbul/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "ISC", - "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, - "license": "MIT" - }, - "node_modules/secp256k1": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.4.tgz", - "integrity": "sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "elliptic": "^6.5.7", - "node-addon-api": "^5.0.0", - "node-gyp-build": "^4.2.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/secp256k1/node_modules/node-addon-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", - "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", - "dev": true, - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "license": "BSD-3-Clause", - "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, - "license": "MIT" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC" - }, - "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, - "license": "(MIT AND BSD-3-Clause)", - "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, - "license": "BSD-3-Clause", - "dependencies": { - "charenc": ">= 0.0.1", - "crypt": ">= 0.0.1" - }, - "engines": { - "node": "*" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "BSD-3-Clause", - "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/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "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==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "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/shelljs/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "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, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/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, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/solc": { - "version": "0.8.26", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.26.tgz", - "integrity": "sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "command-exists": "^1.2.8", - "commander": "^8.1.0", - "follow-redirects": "^1.12.1", - "js-sha3": "0.8.0", - "memorystream": "^0.3.1", - "semver": "^5.5.0", - "tmp": "0.0.33" - }, - "bin": { - "solcjs": "solc.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/solc/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "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, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/solhint": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.5.tgz", - "integrity": "sha512-WrnG6T+/UduuzSWsSOAbfq1ywLUDwNea3Gd5hg6PS+pLUm8lz2ECNr0beX609clBxmDeZ3676AiA9nPDljmbJQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@solidity-parser/parser": "^0.19.0", - "ajv": "^6.12.6", - "antlr4": "^4.13.1-patch-1", - "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", - "latest-version": "^7.0.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/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "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/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, - "license": "Python-2.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, - "license": "MIT", - "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/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "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==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "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/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, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/solhint/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, - "license": "MIT" - }, - "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, - "license": "ISC", - "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, - "license": "MIT", - "optional": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/solidity-ast": { - "version": "0.4.60", - "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.60.tgz", - "integrity": "sha512-UwhasmQ37ji1ul8cIp0XlrQ/+SVQhy09gGqJH4jnwdo2TgI6YIByzi0PI5QvIGcIdFOs1pbSmJW1pnWB7AVh2w==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/solidity-coverage": { - "version": "0.8.15", - "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.15.tgz", - "integrity": "sha512-qH7290NKww4/t/qFvnSEePEzON0k025IGVlwc8wo8Q6p+h1Tt6fV2M0k3yfsps3TomZYTROsfPXjx7MSnwD5uA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@ethersproject/abi": "^5.0.9", - "@solidity-parser/parser": "^0.19.0", - "chalk": "^2.4.2", - "death": "^1.1.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.21", - "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/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, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/solidity-coverage/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "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, - "license": "MIT", - "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/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, - "license": "MIT", - "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, - "license": "MIT" - }, - "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, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "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, - "license": "MIT", - "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==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "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, - "license": "MIT", - "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/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, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/solidity-coverage/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "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, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spawndamnit": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-3.0.1.tgz", - "integrity": "sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==", - "dev": true, - "license": "SEE LICENSE IN LICENSE", - "dependencies": { - "cross-spawn": "^7.0.5", - "signal-exit": "^4.0.1" - } - }, - "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, - "license": "BSD-3-Clause" - }, - "node_modules/stacktrace-parser": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", - "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", - "dev": true, - "license": "MIT", - "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, - "license": "(MIT OR CC0-1.0)", - "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, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "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, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-argv": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.19" - } - }, - "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, - "license": "MIT", - "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": { - "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, - "license": "MIT", - "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/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, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/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, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/table": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", - "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", - "dev": true, - "license": "BSD-3-Clause", - "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/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, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/table/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, - "license": "MIT", - "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/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, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", - "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.4.4", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.4", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", - "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "license": "MIT", - "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, - "license": "MIT", - "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, - "license": "MIT", - "engines": { - "node": ">=0.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, - "license": "MIT" - }, - "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "dev": true, - "license": "0BSD" - }, - "node_modules/tsort": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", - "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "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, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/undici": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.8.0.tgz", - "integrity": "sha512-vFv1GA99b7eKO1HG/4RPu2Is3FBTWBrmzqzO0mz+rLxN3yXkE4mqRcb8g8fHxzX4blEysrNZLqg5RbJLqX5buA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18.1" - } - }, - "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "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, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "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" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/viem": { - "version": "2.28.3", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.28.3.tgz", - "integrity": "sha512-kGYmSHNmzXqg7uZlaV6OEL1p68Z45BYTRPsUM0jYLmOn2zWy6DRA+YxntKnt6jBiCPjiWbVrbFm5QS6TWnfAXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@noble/curves": "1.8.2", - "@noble/hashes": "1.7.2", - "@scure/bip32": "1.6.2", - "@scure/bip39": "1.5.4", - "abitype": "1.0.8", - "isows": "1.0.6", - "ox": "0.6.9", - "ws": "8.18.1" - }, - "peerDependencies": { - "typescript": ">=5.0.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/viem/node_modules/@noble/curves": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", - "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.7.2" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/@noble/hashes": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", - "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/@scure/bip32": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.2.tgz", - "integrity": "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.8.1", - "@noble/hashes": "~1.7.1", - "@scure/base": "~1.2.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/@scure/bip39": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.4.tgz", - "integrity": "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.7.1", - "@scure/base": "~1.2.4" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/web3-utils": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.4.tgz", - "integrity": "sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==", - "dev": true, - "license": "LGPL-3.0", - "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/@noble/curves": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.4.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/web3-utils/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/web3-utils/node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/web3-utils/node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/web3-utils/node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/web3-utils/node_modules/ethereum-cryptography": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "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, - "license": "BSD-2-Clause" - }, - "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, - "license": "MIT", - "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, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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, - "license": "MIT", - "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, - "license": "MIT" - }, - "node_modules/workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", - "dev": true, - "license": "Apache-2.0" - }, - "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, - "license": "MIT", - "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, - "license": "MIT", - "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/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, - "license": "ISC" - }, - "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.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, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yaml": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", - "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, - "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, - "license": "MIT", - "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.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "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, - "license": "MIT", - "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/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, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", - "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "scripts/solhint-custom": { - "name": "solhint-plugin-openzeppelin", - "version": "0.0.0", - "dev": true, - "dependencies": { - "minimatch": "^3.1.2" - } - }, - "scripts/solhint-custom/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "scripts/solhint-custom/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/package.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/package.json deleted file mode 100644 index 6cd1daa..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/package.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "name": "openzeppelin-solidity", - "description": "Secure Smart Contract library for Solidity", - "version": "5.4.0", - "private": true, - "files": [ - "/contracts/**/*.sol", - "!/contracts/mocks/**/*" - ], - "scripts": { - "compile": "hardhat compile", - "compile:harnesses": "env SRC=./certora/harnesses hardhat compile", - "coverage": "scripts/checks/coverage.sh", - "docs": "npm run prepare-docs && oz-docs", - "docs:watch": "oz-docs watch contracts docs/templates docs/config.js", - "prepare": "husky", - "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 .", - "lint:js:fix": "prettier --log-level warn --ignore-path .gitignore '**/*.{js,ts}' --write && eslint . --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", - "version": "scripts/release/version.sh", - "test": ". scripts/set-max-old-space-size.sh && hardhat test", - "test:generation": "scripts/checks/generation.sh", - "test:inheritance": "scripts/checks/inheritance-ordering.js artifacts/build-info/*", - "test:pragma": "scripts/checks/pragma-consistency.js artifacts/build-info/*", - "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.5.0", - "@changesets/cli": "^2.26.0", - "@changesets/pre": "^2.0.0", - "@changesets/read": "^0.6.0", - "@eslint/compat": "^1.2.1", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.6", - "@nomicfoundation/hardhat-ethers": "^3.0.4", - "@nomicfoundation/hardhat-network-helpers": "^1.0.3", - "@openzeppelin/docs-utils": "^0.1.5", - "@openzeppelin/merkle-tree": "^1.0.7", - "@openzeppelin/upgrade-safe-transpiler": "^0.3.32", - "@openzeppelin/upgrades-core": "^1.20.6", - "chai": "^4.2.0", - "eslint": "^9.0.0", - "eslint-config-prettier": "^10.0.0", - "ethers": "^6.14.0", - "glob": "^11.0.0", - "globals": "^16.0.0", - "graphlib": "^2.1.8", - "hardhat": "^2.24.0", - "hardhat-exposed": "^0.3.15", - "hardhat-gas-reporter": "^2.1.0", - "hardhat-ignore-warnings": "^0.2.11", - "husky": "^9.1.7", - "lint-staged": "^16.0.0", - "lodash.startcase": "^4.4.0", - "micromatch": "^4.0.2", - "p-limit": "^6.0.0", - "prettier": "^3.0.0", - "prettier-plugin-solidity": "^1.1.0", - "rimraf": "^6.0.0", - "semver": "^7.3.5", - "solhint": "^5.0.0", - "solhint-plugin-openzeppelin": "file:scripts/solhint-custom", - "solidity-ast": "^0.4.50", - "solidity-coverage": "^0.8.14", - "solidity-docgen": "^0.6.0-beta.29", - "undici": "^7.4.0", - "yargs": "^17.0.0" - }, - "lint-staged": { - "*.{js,ts}": [ - "prettier --log-level warn --ignore-path .gitignore --check", - "eslint" - ], - "*.sol": [ - "prettier --log-level warn --ignore-path .gitignore --check", - "solhint" - ] - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/remappings.txt b/typescript/packages/account-modules/lib/openzeppelin-contracts/remappings.txt deleted file mode 100644 index 304d138..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/remappings.txt +++ /dev/null @@ -1 +0,0 @@ -@openzeppelin/contracts/=contracts/ diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/renovate.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/renovate.json deleted file mode 100644 index c0b97d8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/renovate.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": ["github>OpenZeppelin/configs"], - "labels": ["ignore-changeset"] -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compare-layout.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compare-layout.js deleted file mode 100644 index 64ff439..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compare-layout.js +++ /dev/null @@ -1,20 +0,0 @@ -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 incompatibility found in ${name}:`); - console.log(report.explain()); - process.exitCode = 1; - } - } else { - console.log(`WARNING: ${name} is missing from the current branch`); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js deleted file mode 100755 index 2c7b4dc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js +++ /dev/null @@ -1,247 +0,0 @@ -#!/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.options?.solcInfo) !== JSON.stringify(ref.options?.solcInfo)) { - console.warn('WARNING: Reports produced with non matching metadata'); - } - - // gasReporter 1.0.0 uses ".info", but 2.0.0 uses ".data" - const updateInfo = update.info ?? update.data; - const refInfo = ref.info ?? ref.data; - - const deployments = updateInfo.deployments - .map(contract => - Object.assign(contract, { previousVersion: refInfo.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(updateInfo.methods) - .filter(key => refInfo.methods[key]) - .filter(key => updateInfo.methods[key].numberOfCalls > 0) - .filter( - key => !opts.strictTesting || updateInfo.methods[key].numberOfCalls === refInfo.methods[key].numberOfCalls, - ) - .map(key => ({ - contract: refInfo.methods[key].contract, - method: refInfo.methods[key].fnSig, - min: variation(...[updateInfo, refInfo].map(x => Math.min(...x.methods[key].gasData)), BASE_TX_COST), - max: variation(...[updateInfo, refInfo].map(x => Math.max(...x.methods[key].gasData)), BASE_TX_COST), - avg: variation(...[updateInfo, refInfo].map(x => Math.round(average(...x.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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/coverage.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/coverage.sh deleted file mode 100755 index fd8b9e8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/coverage.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -export COVERAGE=true -export FOUNDRY_FUZZ_RUNS=10 - -. scripts/set-max-old-space-size.sh - -# Hardhat coverage -hardhat coverage - -if [ "${CI:-"false"}" == "true" ]; then - # Foundry coverage - forge coverage --report lcov --ir-minimum - # Remove zero hits - if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' '/,0/d' lcov.info - else - sed -i '/,0/d' lcov.info - fi -fi - -# Reports are then uploaded to Codecov automatically by workflow, and merged. diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/extract-layout.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/extract-layout.js deleted file mode 100644 index d0b9965..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/extract-layout.js +++ /dev/null @@ -1,38 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/generation.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/generation.sh deleted file mode 100755 index 00d609f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/generation.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -npm run generate -git diff -R --exit-code diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js deleted file mode 100755 index fbeac9e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env node - -const path = require('path'); -const graphlib = require('graphlib'); -const match = require('micromatch'); -const { findAll } = require('solidity-ast/utils'); -const { _: artifacts } = require('yargs').argv; - -// files to skip -const skipPatterns = ['contracts-exposed/**', 'contracts/mocks/**']; - -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 (match.any(source, skipPatterns)) 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 in 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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/pragma-consistency.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/pragma-consistency.js deleted file mode 100755 index cf74cd2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/checks/pragma-consistency.js +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env node - -const path = require('path'); -const semver = require('semver'); -const match = require('micromatch'); -const { findAll } = require('solidity-ast/utils'); -const { _: artifacts } = require('yargs').argv; - -// files to skip -const skipPatterns = ['contracts-exposed/**', 'contracts/mocks/WithInit.sol']; - -for (const artifact of artifacts) { - const { output: solcOutput } = require(path.resolve(__dirname, '../..', artifact)); - - const pragma = {}; - - // Extract pragma directive for all files - for (const source in solcOutput.contracts) { - if (match.any(source, skipPatterns)) continue; - for (const { literals } of findAll('PragmaDirective', solcOutput.sources[source].ast)) { - // There should only be one. - const [first, ...rest] = literals; - if (first === 'solidity') pragma[source] = rest.join(''); - } - } - - // Compare the pragma directive of the file, to that of the files it imports - for (const source in solcOutput.contracts) { - if (match.any(source, skipPatterns)) continue; - // minimum version of the compiler that matches source's pragma - const minVersion = semver.minVersion(pragma[source]); - // loop over all imports in source - for (const { absolutePath } of findAll('ImportDirective', solcOutput.sources[source].ast)) { - // So files that only import without declaring anything cause issues, because they don't shop in "pragma" - if (!pragma[absolutePath]) continue; - // Check that the minVersion for source satisfies the requirements of the imported files - if (!semver.satisfies(minVersion, pragma[absolutePath])) { - console.log( - `- ${source} uses ${pragma[source]} but depends on ${absolutePath} that requires ${pragma[absolutePath]}`, - ); - process.exitCode = 1; - } - } - } -} - -if (!process.exitCode) { - console.log('Pragma directives are consistent.'); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/fetch-common-contracts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/fetch-common-contracts.js deleted file mode 100755 index af90424..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/fetch-common-contracts.js +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env node - -// This script snapshots the bytecode and ABI for the `hardhat/common-contracts.js` script. -// - Bytecode is fetched directly from the blockchain by querying the provided client endpoint. If no endpoint is -// provided, ethers default provider is used instead. -// - ABI is fetched from etherscan's API using the provided etherscan API key. If no API key is provided, ABI will not -// be fetched and saved. -// -// The produced artifacts are stored in the `output` folder ('test/bin' by default). For each contract, two files are -// produced: -// - `.bytecode` containing the contract bytecode (in binary encoding) -// - `.abi` containing the ABI (in utf-8 encoding) - -const fs = require('fs'); -const path = require('path'); -const { ethers } = require('ethers'); -const { request } = require('undici'); -const { hideBin } = require('yargs/helpers'); -const { argv } = require('yargs/yargs')(hideBin(process.argv)) - .env('') - .options({ - output: { type: 'string', default: 'test/bin/' }, - client: { type: 'string' }, - etherscan: { type: 'string' }, - }); - -// List of contract names and addresses to fetch -const config = { - EntryPoint070: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', - SenderCreator070: '0xEFC2c1444eBCC4Db75e7613d20C6a62fF67A167C', - EntryPoint080: '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108', - SenderCreator080: '0x449ED7C3e6Fee6a97311d4b55475DF59C44AdD33', -}; - -Promise.all( - Object.entries(config).flatMap(([name, addr]) => - Promise.all([ - argv.etherscan && - request(`https://api.etherscan.io/api?module=contract&action=getabi&address=${addr}&apikey=${argv.etherscan}`) - .then(({ body }) => body.json()) - .then(({ result: abi }) => fs.writeFile(path.join(argv.output, `${name}.abi`), abi, 'utf-8', () => {})), - ethers - .getDefaultProvider(argv.client) - .getCode(addr) - .then(bytecode => - fs.writeFile(path.join(argv.output, `${name}.bytecode`), ethers.getBytes(bytecode), 'binary', () => {}), - ), - ]), - ), -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/gen-nav.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/gen-nav.js deleted file mode 100644 index 06444f9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/gen-nav.js +++ /dev/null @@ -1,81 +0,0 @@ -#!/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'; - default: - return startCase(directory); - } -} - -const menuItems = files.reduce( - (acc, file) => { - let current = acc; - const doc = file.replace(baseDir, ''); - - const keys = doc - .split('/') - .filter(Boolean) - .map(k => k.replace('.adoc', '')); - - for (let i = 0; i < keys.length; i++) { - current = current.items[keys[i]] ??= { - name: startCase(keys[i]), - dir: keys[i], - items: {}, - doc, - }; - } - - return acc; - }, - { - items: { - token: { - name: 'tokens', - dir: '', - items: {}, - }, - }, - }, -); - -const arrayifyItems = items => - Object.entries(items).map(([k, v]) => { - if (Object.keys(v.items ?? {}).length > 0) return [v, arrayifyItems(v.items)]; - return [k, v]; - }); - -const isString = v => typeof v === 'string'; - -const sortItems = items => - items.sort(([a], [b]) => - (isString(a) ? a : a.name).toLowerCase().localeCompare(isString(b) ? b : b.name, undefined, { numeric: true }), - ); - -const print = (items, level = 1) => { - items.forEach(([k, v]) => { - if (v.doc || k?.doc) - console.log(`${'*'.repeat(level)} xref:${v.doc || k.doc}[${getPageTitle(isString(k) ? k : k.name)}]`); - else console.log(`${'*'.repeat(level)} ${getPageTitle(isString(k) ? k : k.name)}`); - if (Array.isArray(v)) print(v, level + 1); - }); -}; - -print( - sortItems(arrayifyItems(menuItems.items)).map(([k, v]) => { - if (v?.length > 0) return [k, sortItems(v)]; - return [k, v]; - }), -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/format-lines.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/format-lines.js deleted file mode 100644 index fa3d6b1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/format-lines.js +++ /dev/null @@ -1,16 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/helpers/sanitize.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/helpers/sanitize.js deleted file mode 100644 index e680ec1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/helpers/sanitize.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - address: expr => `and(${expr}, shr(96, not(0)))`, - bool: expr => `iszero(iszero(${expr}))`, - bytes: (expr, size) => `and(${expr}, shl(${256 - 8 * size}, not(0)))`, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/run.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/run.js deleted file mode 100755 index 394bb39..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/run.js +++ /dev/null @@ -1,61 +0,0 @@ -#!/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 { - return null; - } -} - -function generateFromTemplate(file, template, outputPrefix = '', lint = false) { - 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).trimEnd(), - ); - - fs.writeFileSync(output, content); - lint && cp.execFileSync('prettier', ['--write', output]); -} - -// Some templates needs to go through the linter after generation -const needsLinter = ['utils/structs/EnumerableMap.sol']; - -// Contracts -for (const [file, template] of Object.entries({ - 'utils/cryptography/MerkleProof.sol': './templates/MerkleProof.js', - 'utils/math/SafeCast.sol': './templates/SafeCast.js', - 'utils/structs/Checkpoints.sol': './templates/Checkpoints.js', - 'utils/structs/EnumerableSet.sol': './templates/EnumerableSet.js', - 'utils/structs/EnumerableMap.sol': './templates/EnumerableMap.js', - 'utils/SlotDerivation.sol': './templates/SlotDerivation.js', - 'utils/StorageSlot.sol': './templates/StorageSlot.js', - 'utils/TransientSlot.sol': './templates/TransientSlot.js', - 'utils/Arrays.sol': './templates/Arrays.js', - 'utils/Packing.sol': './templates/Packing.js', - 'mocks/StorageSlotMock.sol': './templates/StorageSlotMock.js', - 'mocks/TransientSlotMock.sol': './templates/TransientSlotMock.js', -})) { - generateFromTemplate(file, template, './contracts/', needsLinter.includes(file)); -} - -// Tests -for (const [file, template] of Object.entries({ - 'utils/structs/Checkpoints.t.sol': './templates/Checkpoints.t.js', - 'utils/Packing.t.sol': './templates/Packing.t.js', - 'utils/SlotDerivation.t.sol': './templates/SlotDerivation.t.js', -})) { - generateFromTemplate(file, template, './test/', needsLinter.includes(file)); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.js deleted file mode 100644 index 6f9380a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.js +++ /dev/null @@ -1,386 +0,0 @@ -const format = require('../format-lines'); -const { capitalize } = require('../../helpers'); -const { TYPES } = require('./Arrays.opts'); - -const header = `\ -pragma solidity ^0.8.20; - -import {Comparators} from "./Comparators.sol"; -import {SlotDerivation} from "./SlotDerivation.sol"; -import {StorageSlot} from "./StorageSlot.sol"; -import {Math} from "./math/Math.sol"; - -/** - * @dev Collection of functions related to array types. - */ -`; - -const sort = type => `\ -/** - * @dev Sort an array of ${type.name} (in memory) following the provided comparator function. - * - * This function does the sorting "in place", meaning that it overrides the input. The object is returned for - * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array. - * - * NOTE: this function's cost is \`O(n · log(n))\` in average and \`O(n²)\` in the worst case, with n the length of the - * array. Using it in view functions that are executed through \`eth_call\` is safe, but one should be very careful - * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may - * consume more gas than is available in a block, leading to potential DoS. - * - * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way. - */ -function sort( - ${type.name}[] memory array, - function(${type.name}, ${type.name}) pure returns (bool) comp -) internal pure returns (${type.name}[] memory) { - ${ - type.name === 'uint256' - ? '_quickSort(_begin(array), _end(array), comp);' - : 'sort(_castToUint256Array(array), _castToUint256Comp(comp));' - } - return array; -} - -/** - * @dev Variant of {sort} that sorts an array of ${type.name} in increasing order. - */ -function sort(${type.name}[] memory array) internal pure returns (${type.name}[] memory) { - ${type.name === 'uint256' ? 'sort(array, Comparators.lt);' : 'sort(_castToUint256Array(array), Comparators.lt);'} - return array; -} -`; - -const quickSort = `\ -/** - * @dev Performs a quick sort of a segment of memory. The segment sorted starts at \`begin\` (inclusive), and stops - * at end (exclusive). Sorting follows the \`comp\` comparator. - * - * Invariant: \`begin <= end\`. This is the case when initially called by {sort} and is preserved in subcalls. - * - * IMPORTANT: Memory locations between \`begin\` and \`end\` are not validated/zeroed. This function should - * be used only if the limits are within a memory array. - */ -function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure { - unchecked { - if (end - begin < 0x40) return; - - // Use first element as pivot - uint256 pivot = _mload(begin); - // Position where the pivot should be at the end of the loop - uint256 pos = begin; - - for (uint256 it = begin + 0x20; it < end; it += 0x20) { - if (comp(_mload(it), pivot)) { - // If the value stored at the iterator's position comes before the pivot, we increment the - // position of the pivot and move the value there. - pos += 0x20; - _swap(pos, it); - } - } - - _swap(begin, pos); // Swap pivot into place - _quickSort(begin, pos, comp); // Sort the left side of the pivot - _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot - } -} - -/** - * @dev Pointer to the memory location of the first element of \`array\`. - */ -function _begin(uint256[] memory array) private pure returns (uint256 ptr) { - assembly ("memory-safe") { - ptr := add(array, 0x20) - } -} - -/** - * @dev Pointer to the memory location of the first memory word (32bytes) after \`array\`. This is the memory word - * that comes just after the last element of the array. - */ -function _end(uint256[] memory array) private pure returns (uint256 ptr) { - unchecked { - return _begin(array) + array.length * 0x20; - } -} - -/** - * @dev Load memory word (as a uint256) at location \`ptr\`. - */ -function _mload(uint256 ptr) private pure returns (uint256 value) { - assembly { - value := mload(ptr) - } -} - -/** - * @dev Swaps the elements memory location \`ptr1\` and \`ptr2\`. - */ -function _swap(uint256 ptr1, uint256 ptr2) private pure { - assembly { - let value1 := mload(ptr1) - let value2 := mload(ptr2) - mstore(ptr1, value2) - mstore(ptr2, value1) - } -} -`; - -const castArray = type => `\ -/// @dev Helper: low level cast ${type.name} memory array to uint256 memory array -function _castToUint256Array(${type.name}[] memory input) private pure returns (uint256[] memory output) { - assembly { - output := input - } -} -`; - -const castComparator = type => `\ -/// @dev Helper: low level cast ${type.name} comp function to uint256 comp function -function _castToUint256Comp( - function(${type.name}, ${type.name}) pure returns (bool) input -) private pure returns (function(uint256, uint256) pure returns (bool) output) { - assembly { - output := input - } -} -`; - -const search = `\ -/** - * @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). - * - * NOTE: The \`array\` is expected to be sorted in ascending order, and to - * contain no repeated elements. - * - * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks - * support for repeated elements in the array. The {lowerBound} function should - * be used instead. - */ -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 Searches an \`array\` sorted in ascending order and returns the first - * index that contains a value greater or equal than \`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). - * - * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound]. - */ -function lowerBound(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) { - // this cannot overflow because mid < high - unchecked { - low = mid + 1; - } - } else { - high = mid; - } - } - - return low; -} - -/** - * @dev Searches an \`array\` sorted in ascending order and returns the first - * index that contains a value strictly greater than \`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). - * - * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound]. - */ -function upperBound(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 { - // this cannot overflow because mid < high - unchecked { - low = mid + 1; - } - } - } - - return low; -} - -/** - * @dev Same as {lowerBound}, but with an array in memory. - */ -function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure 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 (unsafeMemoryAccess(array, mid) < element) { - // this cannot overflow because mid < high - unchecked { - low = mid + 1; - } - } else { - high = mid; - } - } - - return low; -} - -/** - * @dev Same as {upperBound}, but with an array in memory. - */ -function upperBoundMemory(uint256[] memory array, uint256 element) internal pure 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 (unsafeMemoryAccess(array, mid) > element) { - high = mid; - } else { - // this cannot overflow because mid < high - unchecked { - low = mid + 1; - } - } - } - - return low; -} -`; - -const unsafeAccessStorage = type => `\ -/** - * @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(${type.name}[] storage arr, uint256 pos) internal pure returns (StorageSlot.${capitalize( - type.name, -)}Slot storage) { - bytes32 slot; - assembly ("memory-safe") { - slot := arr.slot - } - return slot.deriveArray().offset(pos).get${capitalize(type.name)}Slot(); -} -`; - -const unsafeAccessMemory = type => `\ -/** - * @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(${type.name}[] memory arr, uint256 pos) internal pure returns (${type.name}${ - type.isValueType ? '' : ' memory' -} res) { - assembly { - res := mload(add(add(arr, 0x20), mul(pos, 0x20))) - } -} -`; - -const unsafeSetLength = type => `\ -/** - * @dev Helper to set the length of a dynamic array. Directly writing to \`.length\` is forbidden. - * - * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. - */ -function unsafeSetLength(${type.name}[] storage array, uint256 len) internal { - assembly ("memory-safe") { - sstore(array.slot, len) - } -} -`; - -// GENERATE -module.exports = format( - header.trimEnd(), - 'library Arrays {', - format( - [].concat( - 'using SlotDerivation for bytes32;', - 'using StorageSlot for bytes32;', - '', - // sorting, comparator, helpers and internal - sort({ name: 'uint256' }), - TYPES.filter(type => type.isValueType && type.name !== 'uint256').map(sort), - quickSort, - TYPES.filter(type => type.isValueType && type.name !== 'uint256').map(castArray), - TYPES.filter(type => type.isValueType && type.name !== 'uint256').map(castComparator), - // lookup - search, - // unsafe (direct) storage and memory access - TYPES.map(unsafeAccessStorage), - TYPES.map(unsafeAccessMemory), - TYPES.map(unsafeSetLength), - ), - ).trimEnd(), - '}', -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.opts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.opts.js deleted file mode 100644 index 80efc80..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Arrays.opts.js +++ /dev/null @@ -1,9 +0,0 @@ -const TYPES = [ - { name: 'address', isValueType: true }, - { name: 'bytes32', isValueType: true }, - { name: 'uint256', isValueType: true }, - { name: 'bytes', isValueType: false }, - { name: 'string', isValueType: false }, -]; - -module.exports = { TYPES }; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js deleted file mode 100644 index 0aaa181..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js +++ /dev/null @@ -1,242 +0,0 @@ -const format = require('../format-lines'); -const { OPTS } = require('./Checkpoints.opts'); - -// 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} oldValue, ${opts.valueTypeName} newValue) { - 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 optimized 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} storage ckpt = _unsafeAccess(self.${opts.checkpointFieldName}, pos - 1); - return (true, ckpt.${opts.keyFieldName}, ckpt.${opts.valueFieldName}); - } -} - -/** - * @dev Returns the number of checkpoints. - */ -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} oldValue, ${opts.valueTypeName} newValue) { - uint256 pos = self.length; - - if (pos > 0) { - ${opts.checkpointTypeName} storage last = _unsafeAccess(self, pos - 1); - ${opts.keyTypeName} lastKey = last.${opts.keyFieldName}; - ${opts.valueTypeName} lastValue = last.${opts.valueFieldName}; - - // Checkpoint keys must be non-decreasing. - if (lastKey > key) { - revert CheckpointUnorderedInsertion(); - } - - // Update or push new checkpoint - if (lastKey == key) { - last.${opts.valueFieldName} = value; - } else { - self.push(${opts.checkpointTypeName}({${opts.keyFieldName}: key, ${opts.valueFieldName}: value})); - } - return (lastValue, value); - } else { - self.push(${opts.checkpointTypeName}({${opts.keyFieldName}: key, ${opts.valueFieldName}: value})); - return (0, value); - } -} - -/** - * @dev Return the index of the first (oldest) checkpoint with key strictly bigger 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 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) - } -} -`; - -// GENERATE -module.exports = format( - header.trimEnd(), - 'library Checkpoints {', - format( - [].concat( - errors, - OPTS.map(opts => template(opts)), - ), - ).trimEnd(), - '}', -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.opts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.opts.js deleted file mode 100644 index 08b7b91..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.opts.js +++ /dev/null @@ -1,17 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.t.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.t.js deleted file mode 100644 index 77a9cd3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.t.js +++ /dev/null @@ -1,137 +0,0 @@ -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 "@openzeppelin/contracts/utils/math/SafeCast.sol"; -import {Checkpoints} from "@openzeppelin/contracts/utils/structs/Checkpoints.sol"; -`; - -const template = opts => `\ -using Checkpoints for Checkpoints.${opts.historyTypeName}; - -// Maximum gap between keys used during the fuzzing tests: the \`_prepareKeys\` function will 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 pure 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 pure { - ${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 view { - (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).trimEnd()], - '}', - '', - ]), -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Enumerable.opts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Enumerable.opts.js deleted file mode 100644 index 50c7349..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Enumerable.opts.js +++ /dev/null @@ -1,53 +0,0 @@ -const { capitalize, mapValues } = require('../../helpers'); - -const typeDescr = ({ type, size = 0, memory = false }) => { - memory |= size > 0; - - const name = [type == 'uint256' ? 'Uint' : capitalize(type), size].filter(Boolean).join('x'); - const base = size ? type : undefined; - const typeFull = size ? `${type}[${size}]` : type; - const typeLoc = memory ? `${typeFull} memory` : typeFull; - return { name, type: typeFull, typeLoc, base, size, memory }; -}; - -const toSetTypeDescr = value => ({ - name: value.name + 'Set', - value, -}); - -const toMapTypeDescr = ({ key, value }) => ({ - name: `${key.name}To${value.name}Map`, - keySet: toSetTypeDescr(key), - key, - value, -}); - -const SET_TYPES = [ - { type: 'bytes32' }, - { type: 'address' }, - { type: 'uint256' }, - { type: 'string', memory: true }, - { type: 'bytes', memory: true }, -] - .map(typeDescr) - .map(toSetTypeDescr); - -const MAP_TYPES = [] - .concat( - // value type maps - ['uint256', 'address', 'bytes32'] - .flatMap((keyType, _, array) => array.map(valueType => ({ key: { type: keyType }, value: { type: valueType } }))) - .slice(0, -1), // remove bytes32 → bytes32 (last one) that is already defined - // non-value type maps - { key: { type: 'bytes', memory: true }, value: { type: 'bytes', memory: true } }, - ) - .map(entry => mapValues(entry, typeDescr)) - .map(toMapTypeDescr); - -module.exports = { - SET_TYPES, - MAP_TYPES, - typeDescr, - toSetTypeDescr, - toMapTypeDescr, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js deleted file mode 100644 index f8deb88..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js +++ /dev/null @@ -1,463 +0,0 @@ -const format = require('../format-lines'); -const { fromBytes32, toBytes32 } = require('./conversion'); -const { MAP_TYPES } = require('./Enumerable.opts'); - -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. - * - Map can be cleared (all entries removed) in O(n). - * - * \`\`\`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 - * - \`uint256 -> bytes32\` (\`UintToBytes32Map\`) since v5.1.0 - * - \`address -> address\` (\`AddressToAddressMap\`) since v5.1.0 - * - \`address -> bytes32\` (\`AddressToBytes32Map\`) since v5.1.0 - * - \`bytes32 -> address\` (\`Bytes32ToAddressMap\`) since v5.1.0 - * - \`bytes -> bytes\` (\`BytesToBytesMap\`) since v5.4.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. - * ==== - */ -`; - -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 Removes all the entries from a map. O(n). - * - * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the - * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block. - */ -function clear(Bytes32ToBytes32Map storage map) internal { - uint256 len = length(map); - for (uint256 i = 0; i < len; ++i) { - delete map._values[map._keys.at(i)]; - } - map._keys.clear(); -} - -/** - * @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 key, bytes32 value) { - bytes32 atKey = map._keys.at(index); - return (atKey, map._values[atKey]); -} - -/** - * @dev Tries to return the value associated with \`key\`. O(1). - * Does not revert if \`key\` is not in the map. - */ -function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool exists, bytes32 value) { - bytes32 val = map._values[key]; - if (val == bytes32(0)) { - return (contains(map, key), bytes32(0)); - } else { - return (true, val); - } -} - -/** - * @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 Returns an array containing all the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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(); -} - -/** - * @dev Returns an array containing a slice of the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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, uint256 start, uint256 end) internal view returns (bytes32[] memory) { - return map._keys.values(start, end); -} -`; - -const customMap = ({ name, key, value }) => `\ -// ${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, ${key.type} key, ${value.type} value) internal returns (bool) { - return set(map._inner, ${toBytes32(key.type, 'key')}, ${toBytes32(value.type, '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, ${key.type} key) internal returns (bool) { - return remove(map._inner, ${toBytes32(key.type, 'key')}); -} - -/** - * @dev Removes all the entries from a map. O(n). - * - * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that - * using it may render the function uncallable if the map grows to the point where clearing it consumes too much - * gas to fit in a block. - */ -function clear(${name} storage map) internal { - clear(map._inner); -} - -/** - * @dev Returns true if the key is in the map. O(1). - */ -function contains(${name} storage map, ${key.type} key) internal view returns (bool) { - return contains(map._inner, ${toBytes32(key.type, '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 (${key.type} key, ${value.type} value) { - (bytes32 atKey, bytes32 val) = at(map._inner, index); - return (${fromBytes32(key.type, 'atKey')}, ${fromBytes32(value.type, 'val')}); -} - -/** - * @dev Tries to return the value associated with \`key\`. O(1). - * Does not revert if \`key\` is not in the map. - */ -function tryGet(${name} storage map, ${key.type} key) internal view returns (bool exists, ${value.type} value) { - (bool success, bytes32 val) = tryGet(map._inner, ${toBytes32(key.type, 'key')}); - return (success, ${fromBytes32(value.type, 'val')}); -} - -/** - * @dev Returns the value associated with \`key\`. O(1). - * - * Requirements: - * - * - \`key\` must be in the map. - */ -function get(${name} storage map, ${key.type} key) internal view returns (${value.type}) { - return ${fromBytes32(value.type, `get(map._inner, ${toBytes32(key.type, 'key')})`)}; -} - -/** - * @dev Returns an array containing all the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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 (${key.type}[] memory) { - bytes32[] memory store = keys(map._inner); - ${key.type}[] memory result; - - assembly ("memory-safe") { - result := store - } - - return result; -} - -/** - * @dev Returns an array containing a slice of the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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, uint256 start, uint256 end) internal view returns (${key.type}[] memory) { - bytes32[] memory store = keys(map._inner, start, end); - ${key.type}[] memory result; - - assembly ("memory-safe") { - result := store - } - - return result; -} -`; - -const memoryMap = ({ name, keySet, key, value }) => `\ -/** - * @dev Query for a nonexistent map key. - */ -error EnumerableMapNonexistent${key.name}Key(${key.type} key); - -struct ${name} { - // Storage of keys - EnumerableSet.${keySet.name} _keys; - mapping(${key.type} key => ${value.type}) _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(${name} storage map, ${key.typeLoc} key, ${value.typeLoc} 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(${name} storage map, ${key.typeLoc} key) internal returns (bool) { - delete map._values[key]; - return map._keys.remove(key); -} - -/** - * @dev Removes all the entries from a map. O(n). - * - * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the - * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block. - */ -function clear(${name} storage map) internal { - uint256 len = length(map); - for (uint256 i = 0; i < len; ++i) { - delete map._values[map._keys.at(i)]; - } - map._keys.clear(); -} - -/** - * @dev Returns true if the key is in the map. O(1). - */ -function contains(${name} storage map, ${key.typeLoc} 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(${name} 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( - ${name} storage map, - uint256 index -) internal view returns (${key.typeLoc} key, ${value.typeLoc} value) { - key = map._keys.at(index); - value = map._values[key]; -} - -/** - * @dev Tries to return the value associated with \`key\`. O(1). - * Does not revert if \`key\` is not in the map. - */ -function tryGet( - ${name} storage map, - ${key.typeLoc} key -) internal view returns (bool exists, ${value.typeLoc} value) { - value = map._values[key]; - exists = ${value.memory ? 'bytes(value).length != 0' : `value != ${value.type}(0)`} || contains(map, key); -} - -/** - * @dev Returns the value associated with \`key\`. O(1). - * - * Requirements: - * - * - \`key\` must be in the map. - */ -function get(${name} storage map, ${key.typeLoc} key) internal view returns (${value.typeLoc} value) { - bool exists; - (exists, value) = tryGet(map, key); - if (!exists) { - revert EnumerableMapNonexistent${key.name}Key(key); - } -} - -/** - * @dev Returns an array containing all the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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 (${key.type}[] memory) { - return map._keys.values(); -} - -/** - * @dev Returns an array containing a slice of the keys - * - * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - * 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, uint256 start, uint256 end) internal view returns (${key.type}[] memory) { - return map._keys.values(start, end); -} -`; - -// GENERATE -module.exports = format( - header.trimEnd(), - 'library EnumerableMap {', - format( - [].concat( - 'using EnumerableSet for *;', - '', - defaultMap, - MAP_TYPES.filter(({ key, value }) => !(key.memory || value.memory)).map(customMap), - MAP_TYPES.filter(({ key, value }) => key.memory || value.memory).map(memoryMap), - ), - ).trimEnd(), - '}', -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js deleted file mode 100644 index eb6a0a2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js +++ /dev/null @@ -1,469 +0,0 @@ -const format = require('../format-lines'); -const { fromBytes32, toBytes32 } = require('./conversion'); -const { SET_TYPES } = require('./Enumerable.opts'); - -const header = `\ -pragma solidity ^0.8.20; - -import {Arrays} from "../Arrays.sol"; -import {Math} from "../math/Math.sol"; - -/** - * @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. - * - Set can be cleared (all elements removed) in O(n). - * - * \`\`\`solidity - * contract Example { - * // Add the library methods - * using EnumerableSet for EnumerableSet.AddressSet; - * - * // Declare a set state variable - * EnumerableSet.AddressSet private mySet; - * } - * \`\`\` - * - * The following types are supported: - * - * - \`bytes32\` (\`Bytes32Set\`) since v3.3.0 - * - \`address\` (\`AddressSet\`) since v3.3.0 - * - \`uint256\` (\`UintSet\`) since v3.3.0 - * - \`string\` (\`StringSet\`) since v5.4.0 - * - \`bytes\` (\`BytesSet\`) since v5.4.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 EnumerableSet, you can either remove all elements one by one or create a fresh instance using an - * array of EnumerableSet. - * ==== - */ -`; - -// NOTE: this should be deprecated in favor of a more native construction in v6.0 -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 Removes all the values from a set. O(n). - * - * WARNING: This function has an unbounded cost that scales with set size. Developers should keep in mind that - * using it may render the function uncallable if the set grows to the point where clearing it consumes too much - * gas to fit in a block. - */ -function _clear(Set storage set) private { - uint256 len = _length(set); - for (uint256 i = 0; i < len; ++i) { - delete set._positions[set._values[i]]; - } - Arrays.unsafeSetLength(set._values, 0); -} - -/** - * @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; -} - -/** - * @dev Return a slice of the 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, uint256 start, uint256 end) private view returns (bytes32[] memory) { - unchecked { - end = Math.min(end, _length(set)); - start = Math.min(start, end); - - uint256 len = end - start; - bytes32[] memory result = new bytes32[](len); - for (uint256 i = 0; i < len; ++i) { - result[i] = Arrays.unsafeAccess(set._values, start + i).value; - } - return result; - } -} -`; - -// NOTE: this should be deprecated in favor of a more native construction in v6.0 -const customSet = ({ name, value: { 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 Removes all the values from a set. O(n). - * - * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the - * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. - */ -function clear(${name} storage set) internal { - _clear(set._inner); -} - -/** - * @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; - - assembly ("memory-safe") { - result := store - } - - return result; -} - -/** - * @dev Return a slice of the 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, uint256 start, uint256 end) internal view returns (${type}[] memory) { - bytes32[] memory store = _values(set._inner, start, end); - ${type}[] memory result; - - assembly ("memory-safe") { - result := store - } - - return result; -} -`; - -const memorySet = ({ name, value }) => `\ -struct ${name} { - // Storage of set values - ${value.type}[] _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(${value.type} 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(${name} storage set, ${value.type} memory value) internal returns (bool) { - if (!contains(set, value)) { - set._values.push(value); - // The value is stored at length-1, but we add 1 to all indexes - // and use 0 as a sentinel value - 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(${name} storage set, ${value.type} memory value) internal returns (bool) { - // We cache the value's position to prevent multiple reads from the same storage slot - uint256 position = 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) { - ${value.type} memory 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 Removes all the values from a set. O(n). - * - * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the - * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. - */ -function clear(${name} storage set) internal { - uint256 len = length(set); - for (uint256 i = 0; i < len; ++i) { - delete set._positions[set._values[i]]; - } - Arrays.unsafeSetLength(set._values, 0); -} - -/** - * @dev Returns true if the value is in the set. O(1). - */ -function contains(${name} storage set, ${value.type} memory value) internal view returns (bool) { - return set._positions[value] != 0; -} - -/** - * @dev Returns the number of values on the set. O(1). - */ -function length(${name} storage set) internal 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(${name} storage set, uint256 index) internal view returns (${value.type} memory) { - 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(${name} storage set) internal view returns (${value.type}[] memory) { - return set._values; -} - -/** - * @dev Return a slice of the 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, uint256 start, uint256 end) internal view returns (${value.type}[] memory) { - unchecked { - end = Math.min(end, length(set)); - start = Math.min(start, end); - - uint256 len = end - start; - ${value.type}[] memory result = new ${value.type}[](len); - for (uint256 i = 0; i < len; ++i) { - result[i] = Arrays.unsafeAccess(set._values, start + i).value; - } - return result; - } -} -`; - -// GENERATE -module.exports = format( - header.trimEnd(), - 'library EnumerableSet {', - format( - [].concat( - defaultSet, - SET_TYPES.filter(({ value }) => !value.memory).map(customSet), - SET_TYPES.filter(({ value }) => value.memory).map(memorySet), - ), - ).trimEnd(), - '}', -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.js deleted file mode 100644 index 890b2fe..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.js +++ /dev/null @@ -1,187 +0,0 @@ -const format = require('../format-lines'); -const { OPTS } = require('./MerkleProof.opts'); - -const DEFAULT_HASH = 'Hashes.commutativeKeccak256'; - -const formatArgsSingleLine = (...args) => args.filter(Boolean).join(', '); -const formatArgsMultiline = (...args) => '\n' + format(args.filter(Boolean).join(',\0').split('\0')); - -// TEMPLATE -const header = `\ -pragma solidity ^0.8.20; - -import {Hashes} from "./Hashes.sol"; - -/** - * @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. - * - * IMPORTANT: Consider memory side-effects when using custom hashing functions - * that access memory in an unsafe way. - * - * NOTE: This library supports proof verification for merkle trees built using - * custom _commutative_ hashing functions (i.e. \`H(a, b) == H(b, a)\`). Proving - * leaf inclusion in trees built using non-commutative hashing functions requires - * additional logic that is not supported by this library. - */ -`; - -const errors = `\ -/** - *@dev The multiproof provided is not valid. - */ -error MerkleProofInvalidMultiproof(); -`; - -const templateProof = ({ suffix, location, visibility, hash }) => `\ -/** - * @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. - * - * This version handles proofs in ${location} with ${hash ? 'a custom' : 'the default'} hashing function. - */ -function verify${suffix}(${(hash ? formatArgsMultiline : formatArgsSingleLine)( - `bytes32[] ${location} proof`, - 'bytes32 root', - 'bytes32 leaf', - hash && `function(bytes32, bytes32) view returns (bytes32) ${hash}`, -)}) internal ${visibility} returns (bool) { - return processProof${suffix}(proof, leaf${hash ? `, ${hash}` : ''}) == 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 leaves & pre-images are assumed to be sorted. - * - * This version handles proofs in ${location} with ${hash ? 'a custom' : 'the default'} hashing function. - */ -function processProof${suffix}(${(hash ? formatArgsMultiline : formatArgsSingleLine)( - `bytes32[] ${location} proof`, - 'bytes32 leaf', - hash && `function(bytes32, bytes32) view returns (bytes32) ${hash}`, -)}) internal ${visibility} returns (bytes32) { - bytes32 computedHash = leaf; - for (uint256 i = 0; i < proof.length; i++) { - computedHash = ${hash ?? DEFAULT_HASH}(computedHash, proof[i]); - } - return computedHash; -} -`; - -const templateMultiProof = ({ suffix, location, visibility, hash }) => `\ -/** - * @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}. - * - * This version handles multiproofs in ${location} with ${hash ? 'a custom' : 'the default'} hashing function. - * - * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. - * - * NOTE: Consider the case where \`root == proof[0] && leaves.length == 0\` as it will return \`true\`. - * The \`leaves\` must be validated independently. See {processMultiProof${suffix}}. - */ -function multiProofVerify${suffix}(${formatArgsMultiline( - `bytes32[] ${location} proof`, - `bool[] ${location} proofFlags`, - 'bytes32 root', - `bytes32[] memory leaves`, - hash && `function(bytes32, bytes32) view returns (bytes32) ${hash}`, -)}) internal ${visibility} returns (bool) { - return processMultiProof${suffix}(proof, proofFlags, leaves${hash ? `, ${hash}` : ''}) == 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. - * - * This version handles multiproofs in ${location} with ${hash ? 'a custom' : 'the default'} hashing function. - * - * 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). - * - * NOTE: The _empty set_ (i.e. the case where \`proof.length == 1 && leaves.length == 0\`) is considered a no-op, - * and therefore a valid multiproof (i.e. it returns \`proof[0]\`). Consider disallowing this case if you're not - * validating the leaves elsewhere. - */ -function processMultiProof${suffix}(${formatArgsMultiline( - `bytes32[] ${location} proof`, - `bool[] ${location} proofFlags`, - `bytes32[] memory leaves`, - hash && `function(bytes32, bytes32) view returns (bytes32) ${hash}`, -)}) internal ${visibility} 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 proofFlagsLen = proofFlags.length; - - // Check proof validity. - if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen); - 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 < proofFlagsLen; i++) { - bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; - bytes32 b = proofFlags[i] - ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) - : proof[proofPos++]; - hashes[i] = ${hash ?? DEFAULT_HASH}(a, b); - } - - if (proofFlagsLen > 0) { - if (proofPos != proof.length) { - revert MerkleProofInvalidMultiproof(); - } - unchecked { - return hashes[proofFlagsLen - 1]; - } - } else if (leavesLen > 0) { - return leaves[0]; - } else { - return proof[0]; - } -} -`; - -// GENERATE -module.exports = format( - header.trimEnd(), - 'library MerkleProof {', - format( - [].concat( - errors, - OPTS.flatMap(opts => templateProof(opts)), - OPTS.flatMap(opts => templateMultiProof(opts)), - ), - ).trimEnd(), - '}', -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.opts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.opts.js deleted file mode 100644 index 911f239..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/MerkleProof.opts.js +++ /dev/null @@ -1,11 +0,0 @@ -const { product } = require('../../helpers'); - -const OPTS = product( - [ - { suffix: '', location: 'memory' }, - { suffix: 'Calldata', location: 'calldata' }, - ], - [{ visibility: 'pure' }, { visibility: 'view', hash: 'hasher' }], -).map(objs => Object.assign({}, ...objs)); - -module.exports = { OPTS }; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.js deleted file mode 100644 index 9f3b771..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.js +++ /dev/null @@ -1,92 +0,0 @@ -const format = require('../format-lines'); -const sanitize = require('../helpers/sanitize'); -const { product } = require('../../helpers'); -const { SIZES } = require('./Packing.opts'); - -// TEMPLATE -const header = `\ -pragma solidity ^0.8.20; - -/** - * @dev Helper library packing and unpacking multiple values into bytesXX. - * - * Example usage: - * - * \`\`\`solidity - * library MyPacker { - * type MyType is bytes32; - * - * function _pack(address account, bytes4 selector, uint64 period) external pure returns (MyType) { - * bytes12 subpack = Packing.pack_4_8(selector, bytes8(period)); - * bytes32 pack = Packing.pack_20_12(bytes20(account), subpack); - * return MyType.wrap(pack); - * } - * - * function _unpack(MyType self) external pure returns (address, bytes4, uint64) { - * bytes32 pack = MyType.unwrap(self); - * return ( - * address(Packing.extract_32_20(pack, 0)), - * Packing.extract_32_4(pack, 20), - * uint64(Packing.extract_32_8(pack, 24)) - * ); - * } - * } - * \`\`\` - * - * _Available since v5.1._ - */ -// solhint-disable func-name-mixedcase -`; - -const errors = `\ -error OutOfRangeAccess(); -`; - -const pack = (left, right) => `\ -function pack_${left}_${right}(bytes${left} left, bytes${right} right) internal pure returns (bytes${ - left + right -} result) { - assembly ("memory-safe") { - left := ${sanitize.bytes('left', left)} - right := ${sanitize.bytes('right', right)} - result := or(left, shr(${8 * left}, right)) - } -} -`; - -const extract = (outer, inner) => `\ -function extract_${outer}_${inner}(bytes${outer} self, uint8 offset) internal pure returns (bytes${inner} result) { - if (offset > ${outer - inner}) revert OutOfRangeAccess(); - assembly ("memory-safe") { - result := ${sanitize.bytes('shl(mul(8, offset), self)', inner)} - } -} -`; - -const replace = (outer, inner) => `\ -function replace_${outer}_${inner}(bytes${outer} self, bytes${inner} value, uint8 offset) internal pure returns (bytes${outer} result) { - bytes${inner} oldValue = extract_${outer}_${inner}(self, offset); - assembly ("memory-safe") { - value := ${sanitize.bytes('value', inner)} - result := xor(self, shr(mul(8, offset), xor(oldValue, value))) - } -} -`; - -// GENERATE -module.exports = format( - header.trimEnd(), - 'library Packing {', - format( - [].concat( - errors, - product(SIZES, SIZES) - .filter(([left, right]) => SIZES.includes(left + right)) - .map(([left, right]) => pack(left, right)), - product(SIZES, SIZES) - .filter(([outer, inner]) => outer > inner) - .flatMap(([outer, inner]) => [extract(outer, inner), replace(outer, inner)]), - ), - ).trimEnd(), - '}', -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.opts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.opts.js deleted file mode 100644 index 893ad62..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.opts.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - SIZES: [1, 2, 4, 6, 8, 10, 12, 16, 20, 22, 24, 28, 32], -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.t.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.t.js deleted file mode 100644 index 1feec28..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Packing.t.js +++ /dev/null @@ -1,48 +0,0 @@ -const format = require('../format-lines'); -const { product } = require('../../helpers'); -const { SIZES } = require('./Packing.opts'); - -// TEMPLATE -const header = `\ -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; -import {Packing} from "@openzeppelin/contracts/utils/Packing.sol"; -`; - -const testPack = (left, right) => `\ -function testPack(bytes${left} left, bytes${right} right) external pure { - assertEq(left, Packing.pack_${left}_${right}(left, right).extract_${left + right}_${left}(0)); - assertEq(right, Packing.pack_${left}_${right}(left, right).extract_${left + right}_${right}(${left})); -} -`; - -const testReplace = (outer, inner) => `\ -function testReplace(bytes${outer} container, bytes${inner} newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, ${outer - inner})); - - bytes${inner} oldValue = container.extract_${outer}_${inner}(offset); - - assertEq(newValue, container.replace_${outer}_${inner}(newValue, offset).extract_${outer}_${inner}(offset)); - assertEq(container, container.replace_${outer}_${inner}(newValue, offset).replace_${outer}_${inner}(oldValue, offset)); -} -`; - -// GENERATE -module.exports = format( - header, - 'contract PackingTest is Test {', - format( - [].concat( - 'using Packing for *;', - '', - product(SIZES, SIZES) - .filter(([left, right]) => SIZES.includes(left + right)) - .map(([left, right]) => testPack(left, right)), - product(SIZES, SIZES) - .filter(([outer, inner]) => outer > inner) - .map(([outer, inner]) => testReplace(outer, inner)), - ), - ).trimEnd(), - '}', -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js deleted file mode 100644 index 21000cf..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js +++ /dev/null @@ -1,136 +0,0 @@ -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/bool 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); -} -`; - -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); - } -} -`; - -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); -} -`; - -const boolToUint = `\ -/** - * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. - */ -function toUint(bool b) internal pure returns (uint256 u) { - assembly ("memory-safe") { - u := iszero(iszero(b)) - } -} -`; - -// GENERATE -module.exports = format( - header.trimEnd(), - 'library SafeCast {', - format( - [].concat(errors, LENGTHS.map(toUintDownCast), toUint(256), LENGTHS.map(toIntDownCast), toInt(256), boolToUint), - ).trimEnd(), - '}', -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Slot.opts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Slot.opts.js deleted file mode 100644 index 3eca2bc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/Slot.opts.js +++ /dev/null @@ -1,15 +0,0 @@ -const { capitalize } = require('../../helpers'); - -const TYPES = [ - { type: 'address', isValueType: true }, - { type: 'bool', isValueType: true, name: 'Boolean' }, - { type: 'bytes32', isValueType: true, variants: ['bytes4'] }, - { type: 'uint256', isValueType: true, variants: ['uint32'] }, - { type: 'int256', isValueType: true, variants: ['int32'] }, - { type: 'string', isValueType: false }, - { type: 'bytes', isValueType: false }, -].map(type => Object.assign(type, { name: type.name ?? capitalize(type.type) })); - -Object.assign(TYPES, Object.fromEntries(TYPES.map(entry => [entry.type, entry]))); - -module.exports = { TYPES }; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.js deleted file mode 100644 index a00e981..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.js +++ /dev/null @@ -1,119 +0,0 @@ -const format = require('../format-lines'); -const sanitize = require('../helpers/sanitize'); -const { TYPES } = require('./Slot.opts'); - -const header = `\ -pragma solidity ^0.8.20; - -/** - * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots - * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by - * the solidity language / compiler. - * - * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.]. - * - * Example usage: - * \`\`\`solidity - * contract Example { - * // Add the library methods - * using StorageSlot for bytes32; - * using SlotDerivation for bytes32; - * - * // Declare a namespace - * string private constant _NAMESPACE = ""; // eg. OpenZeppelin.Slot - * - * function setValueInNamespace(uint256 key, address newValue) internal { - * _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue; - * } - * - * function getValueInNamespace(uint256 key) internal view returns (address) { - * return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value; - * } - * } - * \`\`\` - * - * TIP: Consider using this library along with {StorageSlot}. - * - * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking - * upgrade safety will ignore the slots accessed through this library. - * - * _Available since v5.1._ - */ -`; - -const namespace = `\ -/** - * @dev Derive an ERC-7201 slot from a string (namespace). - */ -function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) { - assembly ("memory-safe") { - mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1)) - slot := and(keccak256(0x00, 0x20), not(0xff)) - } -} -`; - -const array = `\ -/** - * @dev Add an offset to a slot to get the n-th element of a structure or an array. - */ -function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) { - unchecked { - return bytes32(uint256(slot) + pos); - } -} - -/** - * @dev Derive the location of the first element in an array from the slot where the length is stored. - */ -function deriveArray(bytes32 slot) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - mstore(0x00, slot) - result := keccak256(0x00, 0x20) - } -} -`; - -const mapping = ({ type }) => `\ -/** - * @dev Derive the location of a mapping element from the key. - */ -function deriveMapping(bytes32 slot, ${type} key) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - mstore(0x00, ${(sanitize[type] ?? (x => x))('key')}) - mstore(0x20, slot) - result := keccak256(0x00, 0x40) - } -} -`; - -const mapping2 = ({ type }) => `\ -/** - * @dev Derive the location of a mapping element from the key. - */ -function deriveMapping(bytes32 slot, ${type} memory key) internal pure returns (bytes32 result) { - assembly ("memory-safe") { - let length := mload(key) - let begin := add(key, 0x20) - let end := add(begin, length) - let cache := mload(end) - mstore(end, slot) - result := keccak256(begin, add(length, 0x20)) - mstore(end, cache) - } -} -`; - -// GENERATE -module.exports = format( - header.trimEnd(), - 'library SlotDerivation {', - format( - [].concat( - namespace, - array, - TYPES.map(type => (type.isValueType ? mapping(type) : mapping2(type))), - ), - ).trimEnd(), - '}', -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.t.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.t.js deleted file mode 100644 index 824af07..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/SlotDerivation.t.js +++ /dev/null @@ -1,127 +0,0 @@ -const format = require('../format-lines'); -const { capitalize } = require('../../helpers'); -const { TYPES } = require('./Slot.opts'); - -const header = `\ -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; -import {SymTest} from "halmos-cheatcodes/SymTest.sol"; -import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; -`; - -const array = `\ -bytes[] private _array; - -function symbolicDeriveArray(uint256 length, uint256 offset) public { - vm.assume(length > 0); - vm.assume(offset < length); - _assertDeriveArray(length, offset); -} - -function testDeriveArray(uint256 length, uint256 offset) public { - length = bound(length, 1, type(uint256).max); - offset = bound(offset, 0, length - 1); - _assertDeriveArray(length, offset); -} - -function _assertDeriveArray(uint256 length, uint256 offset) public { - bytes32 baseSlot; - assembly { - baseSlot := _array.slot - sstore(baseSlot, length) // store length so solidity access does not revert - } - - bytes storage derived = _array[offset]; - bytes32 derivedSlot; - assembly { - derivedSlot := derived.slot - } - - assertEq(baseSlot.deriveArray().offset(offset), derivedSlot); -} -`; - -const mapping = ({ type, name }) => `\ -mapping(${type} => bytes) private _${type}Mapping; - -function testSymbolicDeriveMapping${name}(${type} key) public view { - bytes32 baseSlot; - assembly { - baseSlot := _${type}Mapping.slot - } - - bytes storage derived = _${type}Mapping[key]; - bytes32 derivedSlot; - assembly { - derivedSlot := derived.slot - } - - assertEq(baseSlot.deriveMapping(key), derivedSlot); -} -`; - -const mappingDirty = ({ type, name }) => `\ -function testSymbolicDeriveMapping${name}Dirty(bytes32 dirtyKey) public { - ${type} key; - assembly { - key := dirtyKey - } - - // run the "normal" test using a potentially dirty value - testSymbolicDeriveMapping${name}(key); -} -`; - -const boundedMapping = ({ type, name }) => `\ -mapping(${type} => bytes) private _${type}Mapping; - -function testDeriveMapping${name}(${type} memory key) public view { - _assertDeriveMapping${name}(key); -} - -function symbolicDeriveMapping${name}() public view { - _assertDeriveMapping${name}(svm.create${name}(256, "DeriveMapping${name}Input")); -} - -function _assertDeriveMapping${name}(${type} memory key) internal view { - bytes32 baseSlot; - assembly { - baseSlot := _${type}Mapping.slot - } - - bytes storage derived = _${type}Mapping[key]; - bytes32 derivedSlot; - assembly { - derivedSlot := derived.slot - } - - assertEq(baseSlot.deriveMapping(key), derivedSlot); -} -`; - -// GENERATE -module.exports = format( - header, - 'contract SlotDerivationTest is Test, SymTest {', - format( - [].concat( - 'using SlotDerivation for bytes32;', - '', - array, - TYPES.flatMap(type => - [].concat( - type, - (type.variants ?? []).map(variant => ({ - type: variant, - name: capitalize(variant), - isValueType: type.isValueType, - })), - ), - ).map(type => (type.isValueType ? mapping(type) : boundedMapping(type))), - mappingDirty(TYPES.bool), - mappingDirty(TYPES.address), - ), - ).trimEnd(), - '}', -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js deleted file mode 100644 index 53287b8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js +++ /dev/null @@ -1,77 +0,0 @@ -const format = require('../format-lines'); -const { TYPES } = require('./Slot.opts'); - -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 ERC-1967 implementation slot: - * \`\`\`solidity - * contract ERC1967 { - * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. - * 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; - * } - * } - * \`\`\` - * - * TIP: Consider using this library along with {SlotDerivation}. - */ -`; - -const struct = ({ type, name }) => `\ -struct ${name}Slot { - ${type} value; -} -`; - -const get = ({ name }) => `\ -/** - * @dev Returns ${ - name.toLowerCase().startsWith('a') ? 'an' : 'a' - } \`${name}Slot\` with member \`value\` located at \`slot\`. - */ -function get${name}Slot(bytes32 slot) internal pure returns (${name}Slot storage r) { - assembly ("memory-safe") { - r.slot := slot - } -} -`; - -const getStorage = ({ type, name }) => `\ -/** - * @dev Returns an \`${name}Slot\` representation of the ${type} storage pointer \`store\`. - */ -function get${name}Slot(${type} storage store) internal pure returns (${name}Slot storage r) { - assembly ("memory-safe") { - r.slot := store.slot - } -} -`; - -// GENERATE -module.exports = format( - header.trimEnd(), - 'library StorageSlot {', - format( - [].concat( - TYPES.map(type => struct(type)), - TYPES.flatMap(type => [get(type), !type.isValueType && getStorage(type)].filter(Boolean)), - ), - ).trimEnd(), - '}', -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlotMock.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlotMock.js deleted file mode 100644 index c6d326a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlotMock.js +++ /dev/null @@ -1,57 +0,0 @@ -const format = require('../format-lines'); -const { TYPES } = require('./Slot.opts'); - -const header = `\ -pragma solidity ^0.8.20; - -import {Multicall} from "../utils/Multicall.sol"; -import {StorageSlot} from "../utils/StorageSlot.sol"; -`; - -const storageSetValueType = ({ type, name }) => `\ -function set${name}Slot(bytes32 slot, ${type} value) public { - slot.get${name}Slot().value = value; -} -`; - -const storageGetValueType = ({ type, name }) => `\ -function get${name}Slot(bytes32 slot) public view returns (${type}) { - return slot.get${name}Slot().value; -} -`; - -const storageSetNonValueType = ({ type, name }) => `\ -mapping(uint256 key => ${type}) public ${type}Map; - -function set${name}Slot(bytes32 slot, ${type} calldata value) public { - slot.get${name}Slot().value = value; -} - -function set${name}Storage(uint256 key, ${type} calldata value) public { - ${type}Map[key].get${name}Slot().value = value; -} - -function get${name}Slot(bytes32 slot) public view returns (${type} memory) { - return slot.get${name}Slot().value; -} - -function get${name}Storage(uint256 key) public view returns (${type} memory) { - return ${type}Map[key].get${name}Slot().value; -} -`; - -// GENERATE -module.exports = format( - header, - 'contract StorageSlotMock is Multicall {', - format( - [].concat( - 'using StorageSlot for *;', - '', - TYPES.filter(type => type.isValueType).map(type => storageSetValueType(type)), - TYPES.filter(type => type.isValueType).map(type => storageGetValueType(type)), - TYPES.filter(type => !type.isValueType).map(type => storageSetNonValueType(type)), - ), - ).trimEnd(), - '}', -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlot.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlot.js deleted file mode 100644 index 9ede32f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlot.js +++ /dev/null @@ -1,80 +0,0 @@ -const format = require('../format-lines'); -const { TYPES } = require('./Slot.opts'); - -const header = `\ -pragma solidity ^0.8.24; - -/** - * @dev Library for reading and writing value-types to specific transient storage slots. - * - * Transient slots are often used to store temporary values that are removed after the current transaction. - * This library helps with reading and writing to such slots without the need for inline assembly. - * - * * Example reading and writing values using transient storage: - * \`\`\`solidity - * contract Lock { - * using TransientSlot for *; - * - * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. - * bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542; - * - * modifier locked() { - * require(!_LOCK_SLOT.asBoolean().tload()); - * - * _LOCK_SLOT.asBoolean().tstore(true); - * _; - * _LOCK_SLOT.asBoolean().tstore(false); - * } - * } - * \`\`\` - * - * TIP: Consider using this library along with {SlotDerivation}. - */ -`; - -const udvt = ({ type, name }) => `\ -/** - * @dev UDVT that represents a slot holding ${type == 'address' ? 'an' : 'a'} ${type}. - */ -type ${name}Slot is bytes32; - -/** - * @dev Cast an arbitrary slot to a ${name}Slot. - */ -function as${name}(bytes32 slot) internal pure returns (${name}Slot) { - return ${name}Slot.wrap(slot); -} -`; - -const transient = ({ type, name }) => `\ -/** - * @dev Load the value held at location \`slot\` in transient storage. - */ -function tload(${name}Slot slot) internal view returns (${type} value) { - assembly ("memory-safe") { - value := tload(slot) - } -} - -/** - * @dev Store \`value\` at location \`slot\` in transient storage. - */ -function tstore(${name}Slot slot, ${type} value) internal { - assembly ("memory-safe") { - tstore(slot, value) - } -} -`; - -// GENERATE -module.exports = format( - header.trimEnd(), - 'library TransientSlot {', - format( - [].concat( - TYPES.filter(type => type.isValueType).map(type => udvt(type)), - TYPES.filter(type => type.isValueType).map(type => transient(type)), - ), - ).trimEnd(), - '}', -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlotMock.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlotMock.js deleted file mode 100644 index 4807b0c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/TransientSlotMock.js +++ /dev/null @@ -1,35 +0,0 @@ -const format = require('../format-lines'); -const { TYPES } = require('./Slot.opts'); - -const header = `\ -pragma solidity ^0.8.24; - -import {Multicall} from "../utils/Multicall.sol"; -import {TransientSlot} from "../utils/TransientSlot.sol"; -`; - -const transient = ({ type, name }) => `\ -event ${name}Value(bytes32 slot, ${type} value); - -function tload${name}(bytes32 slot) public { - emit ${name}Value(slot, slot.as${name}().tload()); -} - -function tstore(bytes32 slot, ${type} value) public { - slot.as${name}().tstore(value); -} -`; - -// GENERATE -module.exports = format( - header, - 'contract TransientSlotMock is Multicall {', - format( - [].concat( - 'using TransientSlot for *;', - '', - TYPES.filter(type => type.isValueType).map(type => transient(type)), - ), - ).trimEnd(), - '}', -); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/conversion.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/conversion.js deleted file mode 100644 index 9221f7c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/generate/templates/conversion.js +++ /dev/null @@ -1,30 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/git-user-config.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/git-user-config.sh deleted file mode 100644 index e7b81c3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/git-user-config.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/helpers.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/helpers.js deleted file mode 100644 index d28c086..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/helpers.js +++ /dev/null @@ -1,7 +0,0 @@ -const iterate = require('../test/helpers/iterate'); -const strings = require('../test/helpers/strings'); - -module.exports = { - ...iterate, - ...strings, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/prepack.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/prepack.sh deleted file mode 100755 index 6af1032..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/prepack.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/prepare-docs.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/prepare-docs.sh deleted file mode 100755 index 0ff5b94..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/prepare-docs.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/format-changelog.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/format-changelog.js deleted file mode 100755 index c96dc92..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/format-changelog.js +++ /dev/null @@ -1,33 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/synchronize-versions.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/synchronize-versions.js deleted file mode 100755 index 15aa259..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/synchronize-versions.js +++ /dev/null @@ -1,15 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/update-comment.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/update-comment.js deleted file mode 100755 index 9d6df26..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/update-comment.js +++ /dev/null @@ -1,34 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/version.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/version.sh deleted file mode 100755 index 7b0ddea..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/version.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh deleted file mode 100644 index bcf9b9a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/github-release.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/github-release.js deleted file mode 100644 index f213106..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/github-release.js +++ /dev/null @@ -1,48 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/integrity-check.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/integrity-check.sh deleted file mode 100644 index 86e99f9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/integrity-check.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/pack.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/pack.sh deleted file mode 100644 index ce30712..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/pack.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/publish.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/publish.sh deleted file mode 100644 index e490e5d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/publish.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/rerun.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/rerun.js deleted file mode 100644 index f48ce6e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/rerun.js +++ /dev/null @@ -1,7 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js deleted file mode 100644 index 59b03b2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js +++ /dev/null @@ -1,17 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/start.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/start.sh deleted file mode 100644 index 7683ec5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/start.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/state.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/state.js deleted file mode 100644 index 002f777..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/release/workflow/state.js +++ /dev/null @@ -1,112 +0,0 @@ -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(packageName, version) { - const res = await fetch(`https://registry.npmjs.com/${packageName}/${version}`); - return res.ok; -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js deleted file mode 100644 index e156032..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js +++ /dev/null @@ -1,45 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/set-max-old-space-size.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/set-max-old-space-size.sh deleted file mode 100755 index f56b11d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/set-max-old-space-size.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env sh - -# This script sets the node `--max-old-space-size` to 8192 if it is not set already. -# All existing `NODE_OPTIONS` are retained as is. - -export NODE_OPTIONS="${NODE_OPTIONS:-}" - -if [ "${NODE_OPTIONS##*--max-old-space-size*}" = "$NODE_OPTIONS" ]; then - export NODE_OPTIONS="${NODE_OPTIONS} --max-old-space-size=8192" -fi diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/index.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/index.js deleted file mode 100644 index 9625027..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/index.js +++ /dev/null @@ -1,84 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/package.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/package.json deleted file mode 100644 index ce9690d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/solhint-custom/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "solhint-plugin-openzeppelin", - "version": "0.0.0", - "private": true, - "dependencies": { - "minimatch": "^3.1.2" - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/update-docs-branch.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/update-docs-branch.js deleted file mode 100644 index cf61daa..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/update-docs-branch.js +++ /dev/null @@ -1,65 +0,0 @@ -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 { - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/README.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/README.md deleted file mode 100644 index 2309f9e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/README.md +++ /dev/null @@ -1,21 +0,0 @@ -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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/patch-apply.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/patch-apply.sh deleted file mode 100755 index d9e1758..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/patch-apply.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/patch-save.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/patch-save.sh deleted file mode 100755 index 111e6f1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/patch-save.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/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/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile-onto.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile-onto.sh deleted file mode 100644 index ae14da4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile-onto.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/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" --no-verify - -# return to original branch -git checkout "$start_branch" diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile.sh b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile.sh deleted file mode 100644 index f7c848c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/transpile.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/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/access/manager/AccessManager.sol' \ - -p 'contracts/finance/VestingWallet.sol' \ - -p 'contracts/governance/TimelockController.sol' \ - -p 'contracts/metatx/ERC2771Forwarder.sol' \ - -n \ - -N 'contracts/mocks/**/*' \ - -q '@openzeppelin/' - -# delete compilation artifacts of vanilla code -npm run clean diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/upgradeable.patch b/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/upgradeable.patch deleted file mode 100644 index 0fd5caa..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/scripts/upgradeable/upgradeable.patch +++ /dev/null @@ -1,398 +0,0 @@ -diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md -deleted file mode 100644 -index 35ad097ff..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 60d0a430a..0e4f91a6d 100644 ---- a/README.md -+++ b/README.md -@@ -19,6 +19,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 -@@ -26,7 +29,7 @@ - #### Hardhat (npm) - - ``` --$ npm install @openzeppelin/contracts -+$ npm install @openzeppelin/contracts-upgradeable - ``` - - #### Foundry (git) -@@ -38,10 +41,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 - -@@ -50,10 +53,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 70ae73bc2..ef659873f 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": "5.3.0", - "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 c39954e35..fe681f87a 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"; - - /** -@@ -25,33 +24,20 @@ import {IERC5267} from "../../interfaces/IERC5267.sol"; - * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method - * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. - * -- * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain -- * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the -- * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. -- * -- * @custom:oz-upgrades-unsafe-allow state-variable-immutable -+ * NOTE: The upgradeable version of this contract does not use an immutable cache and recomputes the domain separator -+ * each time {_domainSeparatorV4} is called. That is cheaper than accessing a cached version in cold storage. - */ - 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; -- // slither-disable-next-line constable-states -- string private _nameFallback; -- // slither-disable-next-line constable-states -- string private _versionFallback; -+ string private _name; -+ string private _version; - - /** - * @dev Initializes the domain separator and parameter caches. -@@ -66,29 +52,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 +105,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 +123,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 eeeaf0bcd..65581c544 100644 ---- a/package.json -+++ b/package.json -@@ -34,7 +34,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/account/AccountERC7702.test.js b/test/account/AccountERC7702.test.js -index d08a52209..7a44bccfe 100644 ---- a/test/account/AccountERC7702.test.js -+++ b/test/account/AccountERC7702.test.js -@@ -26,8 +26,8 @@ async function fixture() { - - // domain cannot be fetched using getDomain(mock) before the mock is deployed - const domain = { -- name: 'AccountERC7702Mock', -- version: '1', -+ name: '', // Not initialized in the context of signer -+ version: '', // Not initialized in the context of signer - chainId: entrypointDomain.chainId, - verifyingContract: mock.address, - }; -diff --git a/test/account/examples/AccountERC7702WithModulesMock.test.js b/test/account/examples/AccountERC7702WithModulesMock.test.js -index 9ee5f9177..f6106bcc7 100644 ---- a/test/account/examples/AccountERC7702WithModulesMock.test.js -+++ b/test/account/examples/AccountERC7702WithModulesMock.test.js -@@ -36,8 +36,8 @@ async function fixture() { - - // domain cannot be fetched using getDomain(mock) before the mock is deployed - const domain = { -- name: 'AccountERC7702WithModulesMock', -- version: '1', -+ name: '', // Not initialized in the context of signer -+ version: '', // Not initialized in the context of signer - chainId: entrypointDomain.chainId, - verifyingContract: mock.address, - }; -diff --git a/test/utils/cryptography/EIP712.test.js b/test/utils/cryptography/EIP712.test.js -index 2b6e7fa97..268e0d29d 100644 ---- a/test/utils/cryptography/EIP712.test.js -+++ b/test/utils/cryptography/EIP712.test.js -@@ -47,27 +47,6 @@ describe('EIP712', function () { - const rebuildDomain = await getDomain(this.eip712); - expect(rebuildDomain).to.be.deep.equal(this.domain); - }); -- -- 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 ethers.deployContract('$Clones'); -- -- const clone = await factory -- .$clone(this.eip712) -- .then(tx => tx.wait()) -- .then(receipt => receipt.logs.find(ev => ev.fragment.name == 'return$clone_address').args.instance) -- .then(address => ethers.getContractAt('$EIP712Verifier', address)); -- -- const expectedDomain = { ...this.domain, verifyingContract: clone.target }; -- expect(await getDomain(clone)).to.be.deep.equal(expectedDomain); -- -- const expectedSeparator = await domainSeparator(expectedDomain); -- expect(await clone.$_domainSeparatorV4()).to.equal(expectedSeparator); -- }); -- } - }); - - it('hash digest', async function () { diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/slither.config.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/slither.config.json deleted file mode 100644 index 47892af..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/slither.config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "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/vendor,contracts-exposed" -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/solhint.config.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/solhint.config.js deleted file mode 100644 index 07e7526..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/solhint.config.js +++ /dev/null @@ -1,29 +0,0 @@ -const customRules = require('solhint-plugin-openzeppelin'); - -const rules = [ - 'avoid-tx-origin', - 'const-name-snakecase', - 'contract-name-capwords', - 'event-name-capwords', - 'max-states-count', - 'explicit-types', - 'func-name-mixedcase', - 'func-param-name-mixedcase', - 'imports-on-top', - 'modifier-name-mixedcase', - 'no-console', - 'no-global-import', - 'no-unused-vars', - 'quotes', - 'use-forbidden-name', - 'var-name-mixedcase', - 'visibility-modifier-order', - 'interface-starts-with-i', - 'duplicated-imports', - ...customRules.map(r => `openzeppelin/${r.ruleId}`), -]; - -module.exports = { - plugins: ['openzeppelin'], - rules: Object.fromEntries(rules.map(r => [r, 'error'])), -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/TESTING.md b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/TESTING.md deleted file mode 100644 index 321c7e5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/TESTING.md +++ /dev/null @@ -1,3 +0,0 @@ -## Testing - -Unit tests 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/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js deleted file mode 100644 index c596e6a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js +++ /dev/null @@ -1,874 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); - -const time = require('../helpers/time'); - -const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); - -const DEFAULT_ADMIN_ROLE = ethers.ZeroHash; -const ROLE = ethers.id('ROLE'); -const OTHER_ROLE = ethers.id('OTHER_ROLE'); - -function shouldBehaveLikeAccessControl() { - beforeEach(async function () { - [this.authorized, this.other, this.otherAdmin] = this.accounts; - }); - - shouldSupportInterfaces(['AccessControl']); - - describe('default admin', function () { - it('deployer has default admin role', async function () { - expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)).to.be.true; - }); - - it("other role's admin is the default admin role", async function () { - expect(await this.mock.getRoleAdmin(ROLE)).to.equal(DEFAULT_ADMIN_ROLE); - }); - - it("default admin role's admin is itself", async function () { - expect(await this.mock.getRoleAdmin(DEFAULT_ADMIN_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); - }); - }); - - describe('granting', function () { - beforeEach(async function () { - await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized); - }); - - it('non-admin cannot grant role to other accounts', async function () { - await expect(this.mock.connect(this.other).grantRole(ROLE, this.authorized)) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.other, DEFAULT_ADMIN_ROLE); - }); - - it('accounts can be granted a role multiple times', async function () { - await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized); - await expect(this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized)).to.not.emit( - this.mock, - 'RoleGranted', - ); - }); - }); - - describe('revoking', function () { - it('roles that are not had can be revoked', async function () { - expect(await this.mock.hasRole(ROLE, this.authorized)).to.be.false; - - await expect(this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.authorized)).to.not.emit( - this.mock, - 'RoleRevoked', - ); - }); - - describe('with granted role', function () { - beforeEach(async function () { - await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized); - }); - - it('admin can revoke role', async function () { - await expect(this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.authorized)) - .to.emit(this.mock, 'RoleRevoked') - .withArgs(ROLE, this.authorized, this.defaultAdmin); - - expect(await this.mock.hasRole(ROLE, this.authorized)).to.be.false; - }); - - it('non-admin cannot revoke role', async function () { - await expect(this.mock.connect(this.other).revokeRole(ROLE, this.authorized)) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.other, DEFAULT_ADMIN_ROLE); - }); - - it('a role can be revoked multiple times', async function () { - await this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.authorized); - - await expect(this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.authorized)).to.not.emit( - this.mock, - 'RoleRevoked', - ); - }); - }); - }); - - describe('renouncing', function () { - it('roles that are not had can be renounced', async function () { - await expect(this.mock.connect(this.authorized).renounceRole(ROLE, this.authorized)).to.not.emit( - this.mock, - 'RoleRevoked', - ); - }); - - describe('with granted role', function () { - beforeEach(async function () { - await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized); - }); - - it('bearer can renounce role', async function () { - await expect(this.mock.connect(this.authorized).renounceRole(ROLE, this.authorized)) - .to.emit(this.mock, 'RoleRevoked') - .withArgs(ROLE, this.authorized, this.authorized); - - expect(await this.mock.hasRole(ROLE, this.authorized)).to.be.false; - }); - - it('only the sender can renounce their roles', async function () { - await expect( - this.mock.connect(this.defaultAdmin).renounceRole(ROLE, this.authorized), - ).to.be.revertedWithCustomError(this.mock, 'AccessControlBadConfirmation'); - }); - - it('a role can be renounced multiple times', async function () { - await this.mock.connect(this.authorized).renounceRole(ROLE, this.authorized); - - await expect(this.mock.connect(this.authorized).renounceRole(ROLE, this.authorized)).not.to.emit( - this.mock, - 'RoleRevoked', - ); - }); - }); - }); - - describe('setting role admin', function () { - beforeEach(async function () { - await expect(this.mock.$_setRoleAdmin(ROLE, OTHER_ROLE)) - .to.emit(this.mock, 'RoleAdminChanged') - .withArgs(ROLE, DEFAULT_ADMIN_ROLE, OTHER_ROLE); - - await this.mock.connect(this.defaultAdmin).grantRole(OTHER_ROLE, this.otherAdmin); - }); - - it("a role's admin role can be changed", async function () { - expect(await this.mock.getRoleAdmin(ROLE)).to.equal(OTHER_ROLE); - }); - - it('the new admin can grant roles', async function () { - await expect(this.mock.connect(this.otherAdmin).grantRole(ROLE, this.authorized)) - .to.emit(this.mock, 'RoleGranted') - .withArgs(ROLE, this.authorized, this.otherAdmin); - }); - - it('the new admin can revoke roles', async function () { - await this.mock.connect(this.otherAdmin).grantRole(ROLE, this.authorized); - await expect(this.mock.connect(this.otherAdmin).revokeRole(ROLE, this.authorized)) - .to.emit(this.mock, 'RoleRevoked') - .withArgs(ROLE, this.authorized, this.otherAdmin); - }); - - it("a role's previous admins no longer grant roles", async function () { - await expect(this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized)) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.defaultAdmin, OTHER_ROLE); - }); - - it("a role's previous admins no longer revoke roles", async function () { - await expect(this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.authorized)) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.defaultAdmin, OTHER_ROLE); - }); - }); - - describe('onlyRole modifier', function () { - beforeEach(async function () { - await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized); - }); - - it('do not revert if sender has role', async function () { - await this.mock.connect(this.authorized).$_checkRole(ROLE); - }); - - it("revert if sender doesn't have role #1", async function () { - await expect(this.mock.connect(this.other).$_checkRole(ROLE)) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.other, ROLE); - }); - - it("revert if sender doesn't have role #2", async function () { - await expect(this.mock.connect(this.authorized).$_checkRole(OTHER_ROLE)) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.authorized, OTHER_ROLE); - }); - }); - - describe('internal functions', function () { - describe('_grantRole', function () { - it('return true if the account does not have the role', async function () { - await expect(this.mock.$_grantRole(ROLE, this.authorized)) - .to.emit(this.mock, 'return$_grantRole') - .withArgs(true); - }); - - it('return false if the account has the role', async function () { - await this.mock.$_grantRole(ROLE, this.authorized); - - await expect(this.mock.$_grantRole(ROLE, this.authorized)) - .to.emit(this.mock, 'return$_grantRole') - .withArgs(false); - }); - }); - - describe('_revokeRole', function () { - it('return true if the account has the role', async function () { - await this.mock.$_grantRole(ROLE, this.authorized); - - await expect(this.mock.$_revokeRole(ROLE, this.authorized)) - .to.emit(this.mock, 'return$_revokeRole') - .withArgs(true); - }); - - it('return false if the account does not have the role', async function () { - await expect(this.mock.$_revokeRole(ROLE, this.authorized)) - .to.emit(this.mock, 'return$_revokeRole') - .withArgs(false); - }); - }); - }); -} - -function shouldBehaveLikeAccessControlEnumerable() { - beforeEach(async function () { - [this.authorized, this.other, this.otherAdmin, this.otherAuthorized] = this.accounts; - }); - - shouldSupportInterfaces(['AccessControlEnumerable']); - - describe('enumerating', function () { - it('role bearers can be enumerated', async function () { - await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized); - await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.other); - await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.otherAuthorized); - await this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.other); - - const expectedMembers = [this.authorized.address, this.otherAuthorized.address]; - - const memberCount = await this.mock.getRoleMemberCount(ROLE); - const members = []; - for (let i = 0; i < memberCount; ++i) { - members.push(await this.mock.getRoleMember(ROLE, i)); - } - - expect(memberCount).to.equal(expectedMembers.length); - expect(members).to.deep.equal(expectedMembers); - expect(await this.mock.getRoleMembers(ROLE)).to.deep.equal(expectedMembers); - }); - - it('role enumeration should be in sync after renounceRole call', async function () { - expect(await this.mock.getRoleMemberCount(ROLE)).to.equal(0); - await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.defaultAdmin); - expect(await this.mock.getRoleMemberCount(ROLE)).to.equal(1); - await this.mock.connect(this.defaultAdmin).renounceRole(ROLE, this.defaultAdmin); - expect(await this.mock.getRoleMemberCount(ROLE)).to.equal(0); - }); - }); -} - -function shouldBehaveLikeAccessControlDefaultAdminRules() { - shouldSupportInterfaces(['AccessControlDefaultAdminRules']); - - beforeEach(async function () { - [this.newDefaultAdmin, this.other] = this.accounts; - }); - - 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.mock[getter](); - expect(value).to.equal(this.defaultAdmin); - expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, value)).to.be.true; - }); - - it('changes if the default admin changes', async function () { - // Starts an admin transfer - await this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin); - - // Wait for acceptance - await time.increaseBy.timestamp(this.delay + 1n, false); - await this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer(); - - const value = await this.mock[getter](); - expect(value).to.equal(this.newDefaultAdmin); - }); - }); - } - - describe('pendingDefaultAdmin()', function () { - it('returns 0 if no pending default admin transfer', async function () { - const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); - expect(newAdmin).to.equal(ethers.ZeroAddress); - expect(schedule).to.equal(0); - }); - - describe('when there is a scheduled default admin transfer', function () { - beforeEach('begins admin transfer', async function () { - await this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin); - }); - - for (const [fromSchedule, tag] of [ - [-1n, 'before'], - [0n, 'exactly when'], - [1n, 'after'], - ]) { - it(`returns pending admin and schedule ${tag} it passes if not accepted`, async function () { - // Wait until schedule + fromSchedule - const { schedule: firstSchedule } = await this.mock.pendingDefaultAdmin(); - await time.increaseTo.timestamp(firstSchedule + fromSchedule); - - const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); - expect(newAdmin).to.equal(this.newDefaultAdmin); - expect(schedule).to.equal(firstSchedule); - }); - } - - it('returns 0 after schedule passes and the transfer was accepted', async function () { - // Wait after schedule - const { schedule: firstSchedule } = await this.mock.pendingDefaultAdmin(); - await time.increaseTo.timestamp(firstSchedule + 1n, false); - - // Accepts - await this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer(); - - const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); - expect(newAdmin).to.equal(ethers.ZeroAddress); - expect(schedule).to.equal(0); - }); - }); - }); - - describe('defaultAdminDelay()', function () { - it('returns the current delay', async function () { - expect(await this.mock.defaultAdminDelay()).to.equal(this.delay); - }); - - describe('when there is a scheduled delay change', function () { - const newDelay = 0x1337n; // Any change - - beforeEach('begins delay change', async function () { - await this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(newDelay); - }); - - for (const [fromSchedule, tag, expectNew, delayTag] of [ - [-1n, 'before', false, 'old'], - [0n, 'exactly when', false, 'old'], - [1n, 'after', true, 'new'], - ]) { - it(`returns ${delayTag} delay ${tag} delay schedule passes`, async function () { - // Wait until schedule + fromSchedule - const { schedule } = await this.mock.pendingDefaultAdminDelay(); - await time.increaseTo.timestamp(schedule + fromSchedule); - - const currentDelay = await this.mock.defaultAdminDelay(); - expect(currentDelay).to.equal(expectNew ? newDelay : this.delay); - }); - } - }); - }); - - describe('pendingDefaultAdminDelay()', function () { - it('returns 0 if not set', async function () { - const { newDelay, schedule } = await this.mock.pendingDefaultAdminDelay(); - expect(newDelay).to.equal(0); - expect(schedule).to.equal(0); - }); - - describe('when there is a scheduled delay change', function () { - const newDelay = 0x1337n; // Any change - - beforeEach('begins admin transfer', async function () { - await this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(newDelay); - }); - - for (const [fromSchedule, tag, expectedDelay, delayTag, expectZeroSchedule] of [ - [-1n, 'before', newDelay, 'new'], - [0n, 'exactly when', newDelay, 'new'], - [1n, 'after', 0, 'zero', true], - ]) { - it(`returns ${delayTag} delay ${tag} delay schedule passes`, async function () { - // Wait until schedule + fromSchedule - const { schedule: firstSchedule } = await this.mock.pendingDefaultAdminDelay(); - await time.increaseTo.timestamp(firstSchedule + fromSchedule); - - const { newDelay, schedule } = await this.mock.pendingDefaultAdminDelay(); - expect(newDelay).to.equal(expectedDelay); - expect(schedule).to.equal(expectZeroSchedule ? 0 : firstSchedule); - }); - } - }); - }); - - describe('defaultAdminDelayIncreaseWait()', function () { - it('should return 5 days (default)', async function () { - expect(await this.mock.defaultAdminDelayIncreaseWait()).to.equal(time.duration.days(5)); - }); - }); - - it('should revert if granting default admin role', async function () { - await expect( - this.mock.connect(this.defaultAdmin).grantRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin), - ).to.be.revertedWithCustomError(this.mock, 'AccessControlEnforcedDefaultAdminRules'); - }); - - it('should revert if revoking default admin role', async function () { - await expect( - this.mock.connect(this.defaultAdmin).revokeRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin), - ).to.be.revertedWithCustomError(this.mock, 'AccessControlEnforcedDefaultAdminRules'); - }); - - it("should revert if defaultAdmin's admin is changed", async function () { - await expect(this.mock.$_setRoleAdmin(DEFAULT_ADMIN_ROLE, OTHER_ROLE)).to.be.revertedWithCustomError( - this.mock, - 'AccessControlEnforcedDefaultAdminRules', - ); - }); - - it('should not grant the default admin role twice', async function () { - await expect(this.mock.$_grantRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)).to.be.revertedWithCustomError( - this.mock, - 'AccessControlEnforcedDefaultAdminRules', - ); - }); - - describe('begins a default admin transfer', function () { - it('reverts if called by non default admin accounts', async function () { - await expect(this.mock.connect(this.other).beginDefaultAdminTransfer(this.newDefaultAdmin)) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.other, DEFAULT_ADMIN_ROLE); - }); - - describe('when there is no pending delay nor pending admin transfer', function () { - it('should set pending default admin and schedule', async function () { - const nextBlockTimestamp = (await time.clock.timestamp()) + 1n; - const acceptSchedule = nextBlockTimestamp + this.delay; - - await time.increaseTo.timestamp(nextBlockTimestamp, false); // set timestamp but don't mine the block yet - await expect(this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin)) - .to.emit(this.mock, 'DefaultAdminTransferScheduled') - .withArgs(this.newDefaultAdmin, acceptSchedule); - - const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); - expect(newAdmin).to.equal(this.newDefaultAdmin); - expect(schedule).to.equal(acceptSchedule); - }); - }); - - describe('when there is a pending admin transfer', function () { - beforeEach('sets a pending default admin transfer', async function () { - await this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin); - this.acceptSchedule = (await time.clock.timestamp()) + this.delay; - }); - - for (const [fromSchedule, tag] of [ - [-1n, 'before'], - [0n, 'exactly when'], - [1n, 'after'], - ]) { - it(`should be able to begin a transfer again ${tag} acceptSchedule passes`, async function () { - // Wait until schedule + fromSchedule - await time.increaseTo.timestamp(this.acceptSchedule + fromSchedule, false); - - // defaultAdmin changes its mind and begin again to another address - await expect(this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.other)).to.emit( - this.mock, - 'DefaultAdminTransferCanceled', // Cancellation is always emitted since it was never accepted - ); - const newSchedule = (await time.clock.timestamp()) + this.delay; - const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); - expect(newAdmin).to.equal(this.other); - expect(schedule).to.equal(newSchedule); - }); - } - - it('should not emit a cancellation event if the new default admin accepted', async function () { - // Wait until the acceptSchedule has passed - await time.increaseTo.timestamp(this.acceptSchedule + 1n, false); - - // Accept and restart - await this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer(); - await expect(this.mock.connect(this.newDefaultAdmin).beginDefaultAdminTransfer(this.other)).to.not.emit( - this.mock, - 'DefaultAdminTransferCanceled', - ); - }); - }); - - describe('when there is a pending delay', function () { - const newDelay = time.duration.hours(3); - - beforeEach('schedule a delay change', async function () { - await this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(newDelay); - ({ schedule: this.effectSchedule } = await this.mock.pendingDefaultAdminDelay()); - }); - - for (const [fromSchedule, schedulePassed, expectNewDelay] of [ - [-1n, 'before', false], - [0n, 'exactly when', false], - [1n, 'after', true], - ]) { - it(`should set the ${ - expectNewDelay ? 'new' : 'old' - } delay and apply it to next default admin transfer schedule ${schedulePassed} effectSchedule passed`, async function () { - // Wait until the expected fromSchedule time - const nextBlockTimestamp = this.effectSchedule + fromSchedule; - await time.increaseTo.timestamp(nextBlockTimestamp, false); - - // Start the new default admin transfer and get its schedule - const expectedDelay = expectNewDelay ? newDelay : this.delay; - const expectedAcceptSchedule = nextBlockTimestamp + expectedDelay; - await expect(this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin)) - .to.emit(this.mock, 'DefaultAdminTransferScheduled') - .withArgs(this.newDefaultAdmin, expectedAcceptSchedule); - - // Check that the schedule corresponds with the new delay - const { newAdmin, schedule: transferSchedule } = await this.mock.pendingDefaultAdmin(); - expect(newAdmin).to.equal(this.newDefaultAdmin); - expect(transferSchedule).to.equal(expectedAcceptSchedule); - }); - } - }); - }); - - describe('accepts transfer admin', function () { - beforeEach(async function () { - await this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin); - this.acceptSchedule = (await time.clock.timestamp()) + this.delay; - }); - - it('should revert if caller is not pending default admin', async function () { - await time.increaseTo.timestamp(this.acceptSchedule + 1n, false); - await expect(this.mock.connect(this.other).acceptDefaultAdminTransfer()) - .to.be.revertedWithCustomError(this.mock, 'AccessControlInvalidDefaultAdmin') - .withArgs(this.other); - }); - - describe('when caller is pending default admin and delay has passed', function () { - beforeEach(async function () { - await time.increaseTo.timestamp(this.acceptSchedule + 1n, false); - }); - - it('accepts a transfer and changes default admin', async function () { - // Emit events - await expect(this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer()) - .to.emit(this.mock, 'RoleRevoked') - .withArgs(DEFAULT_ADMIN_ROLE, this.defaultAdmin, this.newDefaultAdmin) - .to.emit(this.mock, 'RoleGranted') - .withArgs(DEFAULT_ADMIN_ROLE, this.newDefaultAdmin, this.newDefaultAdmin); - - // Storage changes - expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)).to.be.false; - expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, this.newDefaultAdmin)).to.be.true; - expect(await this.mock.owner()).to.equal(this.newDefaultAdmin); - - // Resets pending default admin and schedule - const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); - expect(newAdmin).to.equal(ethers.ZeroAddress); - expect(schedule).to.equal(0); - }); - }); - - describe('schedule not passed', function () { - for (const [fromSchedule, tag] of [ - [-1n, 'less'], - [0n, 'equal'], - ]) { - it(`should revert if block.timestamp is ${tag} to schedule`, async function () { - await time.increaseTo.timestamp(this.acceptSchedule + fromSchedule, false); - await expect(this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer()) - .to.be.revertedWithCustomError(this.mock, 'AccessControlEnforcedDefaultAdminDelay') - .withArgs(this.acceptSchedule); - }); - } - }); - }); - - describe('cancels a default admin transfer', function () { - it('reverts if called by non default admin accounts', async function () { - await expect(this.mock.connect(this.other).cancelDefaultAdminTransfer()) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.other, DEFAULT_ADMIN_ROLE); - }); - - describe('when there is a pending default admin transfer', function () { - beforeEach(async function () { - await this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin); - this.acceptSchedule = (await time.clock.timestamp()) + this.delay; - }); - - for (const [fromSchedule, tag] of [ - [-1n, 'before'], - [0n, 'exactly when'], - [1n, 'after'], - ]) { - it(`resets pending default admin and schedule ${tag} transfer schedule passes`, async function () { - // Advance until passed delay - await time.increaseTo.timestamp(this.acceptSchedule + fromSchedule, false); - - await expect(this.mock.connect(this.defaultAdmin).cancelDefaultAdminTransfer()).to.emit( - this.mock, - 'DefaultAdminTransferCanceled', - ); - - const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); - expect(newAdmin).to.equal(ethers.ZeroAddress); - expect(schedule).to.equal(0); - }); - } - - it('should revert if the previous default admin tries to accept', async function () { - await this.mock.connect(this.defaultAdmin).cancelDefaultAdminTransfer(); - - // Advance until passed delay - await time.increaseTo.timestamp(this.acceptSchedule + 1n, false); - - // Previous pending default admin should not be able to accept after cancellation. - await expect(this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer()) - .to.be.revertedWithCustomError(this.mock, 'AccessControlInvalidDefaultAdmin') - .withArgs(this.newDefaultAdmin); - }); - }); - - describe('when there is no pending default admin transfer', function () { - it('should succeed without changes', async function () { - await expect(this.mock.connect(this.defaultAdmin).cancelDefaultAdminTransfer()).to.not.emit( - this.mock, - 'DefaultAdminTransferCanceled', - ); - - const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); - expect(newAdmin).to.equal(ethers.ZeroAddress); - expect(schedule).to.equal(0); - }); - }); - }); - - describe('renounces admin', function () { - beforeEach(async function () { - await this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(ethers.ZeroAddress); - this.expectedSchedule = (await time.clock.timestamp()) + this.delay; - }); - - it('reverts if caller is not default admin', async function () { - await time.increaseBy.timestamp(this.delay + 1n, false); - await expect( - this.mock.connect(this.defaultAdmin).renounceRole(DEFAULT_ADMIN_ROLE, this.other), - ).to.be.revertedWithCustomError(this.mock, 'AccessControlBadConfirmation'); - }); - - it("renouncing the admin role when not an admin doesn't affect the schedule", async function () { - await time.increaseBy.timestamp(this.delay + 1n, false); - await this.mock.connect(this.other).renounceRole(DEFAULT_ADMIN_ROLE, this.other); - - const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); - expect(newAdmin).to.equal(ethers.ZeroAddress); - expect(schedule).to.equal(this.expectedSchedule); - }); - - it('keeps defaultAdmin consistent with hasRole if another non-defaultAdmin user renounces the DEFAULT_ADMIN_ROLE', async function () { - await time.increaseBy.timestamp(this.delay + 1n, false); - - // This passes because it's a noop - await this.mock.connect(this.other).renounceRole(DEFAULT_ADMIN_ROLE, this.other); - - expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)).to.be.true; - expect(await this.mock.defaultAdmin()).to.equal(this.defaultAdmin); - }); - - it('renounces role', async function () { - await time.increaseBy.timestamp(this.delay + 1n, false); - await expect(this.mock.connect(this.defaultAdmin).renounceRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)) - .to.emit(this.mock, 'RoleRevoked') - .withArgs(DEFAULT_ADMIN_ROLE, this.defaultAdmin, this.defaultAdmin); - - expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)).to.be.false; - expect(await this.mock.defaultAdmin()).to.equal(ethers.ZeroAddress); - expect(await this.mock.owner()).to.equal(ethers.ZeroAddress); - - const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin(); - expect(newAdmin).to.equal(ethers.ZeroAddress); - expect(schedule).to.equal(0); - }); - - it('allows to recover access using the internal _grantRole', async function () { - await time.increaseBy.timestamp(this.delay + 1n, false); - await this.mock.connect(this.defaultAdmin).renounceRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin); - - await expect(this.mock.connect(this.defaultAdmin).$_grantRole(DEFAULT_ADMIN_ROLE, this.other)) - .to.emit(this.mock, 'RoleGranted') - .withArgs(DEFAULT_ADMIN_ROLE, this.other, this.defaultAdmin); - }); - - describe('schedule not passed', function () { - for (const [fromSchedule, tag] of [ - [-1n, 'less'], - [0n, 'equal'], - ]) { - it(`reverts if block.timestamp is ${tag} to schedule`, async function () { - await time.increaseBy.timestamp(this.delay + fromSchedule, false); - await expect(this.mock.connect(this.defaultAdmin).renounceRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)) - .to.be.revertedWithCustomError(this.mock, 'AccessControlEnforcedDefaultAdminDelay') - .withArgs(this.expectedSchedule); - }); - } - }); - }); - - describe('changes delay', function () { - it('reverts if called by non default admin accounts', async function () { - await expect(this.mock.connect(this.other).changeDefaultAdminDelay(time.duration.hours(4))) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.other, DEFAULT_ADMIN_ROLE); - }); - - for (const [delayDifference, delayChangeType] of [ - [time.duration.hours(-1), 'decreased'], - [time.duration.hours(1), 'increased'], - [time.duration.days(5), 'increased to more than 5 days'], - ]) { - describe(`when the delay is ${delayChangeType}`, function () { - beforeEach(function () { - this.newDefaultAdminDelay = this.delay + delayDifference; - }); - - it('begins the delay change to the new delay', async function () { - // Calculate expected values - const capWait = await this.mock.defaultAdminDelayIncreaseWait(); - const minWait = capWait < this.newDefaultAdminDelay ? capWait : this.newDefaultAdminDelay; - const changeDelay = - this.newDefaultAdminDelay <= this.delay ? this.delay - this.newDefaultAdminDelay : minWait; - const nextBlockTimestamp = (await time.clock.timestamp()) + 1n; - const effectSchedule = nextBlockTimestamp + changeDelay; - - await time.increaseTo.timestamp(nextBlockTimestamp, false); - - // Begins the change - await expect(this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(this.newDefaultAdminDelay)) - .to.emit(this.mock, 'DefaultAdminDelayChangeScheduled') - .withArgs(this.newDefaultAdminDelay, effectSchedule); - - // Assert - const { newDelay, schedule } = await this.mock.pendingDefaultAdminDelay(); - expect(newDelay).to.equal(this.newDefaultAdminDelay); - expect(schedule).to.equal(effectSchedule); - }); - - describe('scheduling again', function () { - beforeEach('schedule once', async function () { - await this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(this.newDefaultAdminDelay); - }); - - for (const [fromSchedule, tag] of [ - [-1n, 'before'], - [0n, 'exactly when'], - [1n, 'after'], - ]) { - const passed = fromSchedule > 0; - - it(`succeeds ${tag} the delay schedule passes`, async function () { - // Wait until schedule + fromSchedule - const { schedule: firstSchedule } = await this.mock.pendingDefaultAdminDelay(); - const nextBlockTimestamp = firstSchedule + fromSchedule; - await time.increaseTo.timestamp(nextBlockTimestamp, false); - - // Calculate expected values - const anotherNewDefaultAdminDelay = this.newDefaultAdminDelay + time.duration.hours(2); - const capWait = await this.mock.defaultAdminDelayIncreaseWait(); - const minWait = capWait < anotherNewDefaultAdminDelay ? capWait : anotherNewDefaultAdminDelay; - const effectSchedule = nextBlockTimestamp + minWait; - - // Default admin changes its mind and begins another delay change - await expect(this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(anotherNewDefaultAdminDelay)) - .to.emit(this.mock, 'DefaultAdminDelayChangeScheduled') - .withArgs(anotherNewDefaultAdminDelay, effectSchedule); - - // Assert - const { newDelay, schedule } = await this.mock.pendingDefaultAdminDelay(); - expect(newDelay).to.equal(anotherNewDefaultAdminDelay); - expect(schedule).to.equal(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.mock.pendingDefaultAdminDelay(); - await time.increaseTo.timestamp(firstSchedule + fromSchedule, false); - - // Default admin changes its mind and begins another delay change - const anotherNewDefaultAdminDelay = this.newDefaultAdminDelay + time.duration.hours(2); - - const expected = expect( - this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(anotherNewDefaultAdminDelay), - ); - if (passed) { - await expected.to.not.emit(this.mock, 'DefaultAdminDelayChangeCanceled'); - } else { - await expected.to.emit(this.mock, 'DefaultAdminDelayChangeCanceled'); - } - }); - } - }); - }); - } - }); - - describe('rollbacks a delay change', function () { - it('reverts if called by non default admin accounts', async function () { - await expect(this.mock.connect(this.other).rollbackDefaultAdminDelay()) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.other, DEFAULT_ADMIN_ROLE); - }); - - describe('when there is a pending delay', function () { - beforeEach('set pending delay', async function () { - await this.mock.connect(this.defaultAdmin).changeDefaultAdminDelay(time.duration.hours(12)); - }); - - for (const [fromSchedule, tag] of [ - [-1n, 'before'], - [0n, 'exactly when'], - [1n, '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.mock.pendingDefaultAdminDelay(); - await time.increaseTo.timestamp(firstSchedule + fromSchedule, false); - - await this.mock.connect(this.defaultAdmin).rollbackDefaultAdminDelay(); - - const { newDelay, schedule } = await this.mock.pendingDefaultAdminDelay(); - expect(newDelay).to.equal(0); - expect(schedule).to.equal(0); - }); - - 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.mock.pendingDefaultAdminDelay(); - await time.increaseTo.timestamp(firstSchedule + fromSchedule, false); - - const expected = expect(this.mock.connect(this.defaultAdmin).rollbackDefaultAdminDelay()); - if (passed) { - await expected.to.not.emit(this.mock, 'DefaultAdminDelayChangeCanceled'); - } else { - await expected.to.emit(this.mock, 'DefaultAdminDelayChangeCanceled'); - } - }); - } - }); - - describe('when there is no pending delay', function () { - it('succeeds without changes', async function () { - await this.mock.connect(this.defaultAdmin).rollbackDefaultAdminDelay(); - - const { newDelay, schedule } = await this.mock.pendingDefaultAdminDelay(); - expect(newDelay).to.equal(0); - expect(schedule).to.equal(0); - }); - }); - }); -} - -module.exports = { - DEFAULT_ADMIN_ROLE, - shouldBehaveLikeAccessControl, - shouldBehaveLikeAccessControlEnumerable, - shouldBehaveLikeAccessControlDefaultAdminRules, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.test.js deleted file mode 100644 index 5c70cdc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/AccessControl.test.js +++ /dev/null @@ -1,19 +0,0 @@ -const { ethers } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl } = require('./AccessControl.behavior'); - -async function fixture() { - const [defaultAdmin, ...accounts] = await ethers.getSigners(); - const mock = await ethers.deployContract('$AccessControl'); - await mock.$_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); - return { mock, defaultAdmin, accounts }; -} - -describe('AccessControl', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeAccessControl(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable.test.js deleted file mode 100644 index 2d9b561..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable.test.js +++ /dev/null @@ -1,79 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -async function fixture() { - const [owner, other] = await ethers.getSigners(); - const ownable = await ethers.deployContract('$Ownable', [owner]); - return { owner, other, ownable }; -} - -describe('Ownable', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('emits ownership transfer events during construction', async function () { - await expect(this.ownable.deploymentTransaction()) - .to.emit(this.ownable, 'OwnershipTransferred') - .withArgs(ethers.ZeroAddress, this.owner); - }); - - it('rejects zero address for initialOwner', async function () { - await expect(ethers.deployContract('$Ownable', [ethers.ZeroAddress])) - .to.be.revertedWithCustomError({ interface: this.ownable.interface }, 'OwnableInvalidOwner') - .withArgs(ethers.ZeroAddress); - }); - - it('has an owner', async function () { - expect(await this.ownable.owner()).to.equal(this.owner); - }); - - describe('transfer ownership', function () { - it('changes owner after transfer', async function () { - await expect(this.ownable.connect(this.owner).transferOwnership(this.other)) - .to.emit(this.ownable, 'OwnershipTransferred') - .withArgs(this.owner, this.other); - - expect(await this.ownable.owner()).to.equal(this.other); - }); - - it('prevents non-owners from transferring', async function () { - await expect(this.ownable.connect(this.other).transferOwnership(this.other)) - .to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount') - .withArgs(this.other); - }); - - it('guards ownership against stuck state', async function () { - await expect(this.ownable.connect(this.owner).transferOwnership(ethers.ZeroAddress)) - .to.be.revertedWithCustomError(this.ownable, 'OwnableInvalidOwner') - .withArgs(ethers.ZeroAddress); - }); - }); - - describe('renounce ownership', function () { - it('loses ownership after renouncement', async function () { - await expect(this.ownable.connect(this.owner).renounceOwnership()) - .to.emit(this.ownable, 'OwnershipTransferred') - .withArgs(this.owner, ethers.ZeroAddress); - - expect(await this.ownable.owner()).to.equal(ethers.ZeroAddress); - }); - - it('prevents non-owners from renouncement', async function () { - await expect(this.ownable.connect(this.other).renounceOwnership()) - .to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount') - .withArgs(this.other); - }); - - it('allows to recover access using the internal _transferOwnership', async function () { - await this.ownable.connect(this.owner).renounceOwnership(); - - await expect(this.ownable.$_transferOwnership(this.other)) - .to.emit(this.ownable, 'OwnershipTransferred') - .withArgs(ethers.ZeroAddress, this.other); - - expect(await this.ownable.owner()).to.equal(this.other); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js deleted file mode 100644 index 5620a24..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js +++ /dev/null @@ -1,102 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -async function fixture() { - const [owner, accountA, accountB] = await ethers.getSigners(); - const ownable2Step = await ethers.deployContract('$Ownable2Step', [owner]); - return { - ownable2Step, - owner, - accountA, - accountB, - }; -} - -describe('Ownable2Step', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('transfer ownership', function () { - it('starting a transfer does not change owner', async function () { - await expect(this.ownable2Step.connect(this.owner).transferOwnership(this.accountA)) - .to.emit(this.ownable2Step, 'OwnershipTransferStarted') - .withArgs(this.owner, this.accountA); - - expect(await this.ownable2Step.owner()).to.equal(this.owner); - expect(await this.ownable2Step.pendingOwner()).to.equal(this.accountA); - }); - - it('changes owner after transfer', async function () { - await this.ownable2Step.connect(this.owner).transferOwnership(this.accountA); - - await expect(this.ownable2Step.connect(this.accountA).acceptOwnership()) - .to.emit(this.ownable2Step, 'OwnershipTransferred') - .withArgs(this.owner, this.accountA); - - expect(await this.ownable2Step.owner()).to.equal(this.accountA); - expect(await this.ownable2Step.pendingOwner()).to.equal(ethers.ZeroAddress); - }); - - it('guards transfer against invalid user', async function () { - await this.ownable2Step.connect(this.owner).transferOwnership(this.accountA); - - await expect(this.ownable2Step.connect(this.accountB).acceptOwnership()) - .to.be.revertedWithCustomError(this.ownable2Step, 'OwnableUnauthorizedAccount') - .withArgs(this.accountB); - }); - }); - - describe('renouncing ownership', function () { - it('changes owner after renouncing ownership', async function () { - await expect(this.ownable2Step.connect(this.owner).renounceOwnership()) - .to.emit(this.ownable2Step, 'OwnershipTransferred') - .withArgs(this.owner, ethers.ZeroAddress); - - // 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(ethers.ZeroAddress); - }); - - it('pending owner resets after renouncing ownership', async function () { - await this.ownable2Step.connect(this.owner).transferOwnership(this.accountA); - expect(await this.ownable2Step.pendingOwner()).to.equal(this.accountA); - - await this.ownable2Step.connect(this.owner).renounceOwnership(); - expect(await this.ownable2Step.pendingOwner()).to.equal(ethers.ZeroAddress); - - await expect(this.ownable2Step.connect(this.accountA).acceptOwnership()) - .to.be.revertedWithCustomError(this.ownable2Step, 'OwnableUnauthorizedAccount') - .withArgs(this.accountA); - }); - - it('allows to recover access using the internal _transferOwnership', async function () { - await this.ownable2Step.connect(this.owner).renounceOwnership(); - - await expect(this.ownable2Step.$_transferOwnership(this.accountA)) - .to.emit(this.ownable2Step, 'OwnershipTransferred') - .withArgs(ethers.ZeroAddress, this.accountA); - - expect(await this.ownable2Step.owner()).to.equal(this.accountA); - }); - - it('allows the owner to cancel an initiated ownership transfer by setting newOwner to zero address', async function () { - // initiate ownership transfer to accountA - await this.ownable2Step.connect(this.owner).transferOwnership(this.accountA); - expect(await this.ownable2Step.pendingOwner()).to.equal(this.accountA); - - // cancel the ownership transfer by setting newOwner to zero address - await expect(this.ownable2Step.connect(this.owner).transferOwnership(ethers.ZeroAddress)) - .to.emit(this.ownable2Step, 'OwnershipTransferStarted') - .withArgs(this.owner, ethers.ZeroAddress); - expect(await this.ownable2Step.pendingOwner()).to.equal(ethers.ZeroAddress); - - // verify that accountA cannot accept ownership anymore - await expect(this.ownable2Step.connect(this.accountA).acceptOwnership()) - .to.be.revertedWithCustomError(this.ownable2Step, 'OwnableUnauthorizedAccount') - .withArgs(this.accountA); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlDefaultAdminRules.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlDefaultAdminRules.test.js deleted file mode 100644 index 48036fd..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlDefaultAdminRules.test.js +++ /dev/null @@ -1,32 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const time = require('../../helpers/time'); - -const { - shouldBehaveLikeAccessControl, - shouldBehaveLikeAccessControlDefaultAdminRules, -} = require('../AccessControl.behavior'); - -async function fixture() { - const delay = time.duration.hours(10); - const [defaultAdmin, ...accounts] = await ethers.getSigners(); - const mock = await ethers.deployContract('$AccessControlDefaultAdminRules', [delay, defaultAdmin]); - return { mock, defaultAdmin, delay, accounts }; -} - -describe('AccessControlDefaultAdminRules', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('initial admin not zero', async function () { - await expect(ethers.deployContract('$AccessControlDefaultAdminRules', [this.delay, ethers.ZeroAddress])) - .to.be.revertedWithCustomError(this.mock, 'AccessControlInvalidDefaultAdmin') - .withArgs(ethers.ZeroAddress); - }); - - shouldBehaveLikeAccessControl(); - shouldBehaveLikeAccessControlDefaultAdminRules(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlEnumerable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlEnumerable.test.js deleted file mode 100644 index ea1a8c4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/extensions/AccessControlEnumerable.test.js +++ /dev/null @@ -1,24 +0,0 @@ -const { ethers } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { - DEFAULT_ADMIN_ROLE, - shouldBehaveLikeAccessControl, - shouldBehaveLikeAccessControlEnumerable, -} = require('../AccessControl.behavior'); - -async function fixture() { - const [defaultAdmin, ...accounts] = await ethers.getSigners(); - const mock = await ethers.deployContract('$AccessControlEnumerable'); - await mock.$_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); - return { mock, defaultAdmin, accounts }; -} - -describe('AccessControlEnumerable', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeAccessControl(); - shouldBehaveLikeAccessControlEnumerable(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManaged.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManaged.test.js deleted file mode 100644 index d666b5e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManaged.test.js +++ /dev/null @@ -1,146 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { impersonate } = require('../../helpers/account'); -const time = require('../../helpers/time'); - -async function fixture() { - const [admin, roleMember, other] = await ethers.getSigners(); - - const authority = await ethers.deployContract('$AccessManager', [admin]); - const managed = await ethers.deployContract('$AccessManagedTarget', [authority]); - - const anotherAuthority = await ethers.deployContract('$AccessManager', [admin]); - const authorityObserveIsConsuming = await ethers.deployContract('$AuthorityObserveIsConsuming'); - - await impersonate(authority.target); - const authorityAsSigner = await ethers.getSigner(authority.target); - - return { - roleMember, - other, - authorityAsSigner, - authority, - managed, - authorityObserveIsConsuming, - anotherAuthority, - }; -} - -describe('AccessManaged', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('sets authority and emits AuthorityUpdated event during construction', async function () { - await expect(this.managed.deploymentTransaction()) - .to.emit(this.managed, 'AuthorityUpdated') - .withArgs(this.authority); - }); - - describe('restricted modifier', function () { - beforeEach(async function () { - this.selector = this.managed.fnRestricted.getFragment().selector; - this.role = 42n; - await this.authority.$_setTargetFunctionRole(this.managed, this.selector, this.role); - await this.authority.$_grantRole(this.role, this.roleMember, 0, 0); - }); - - it('succeeds when role is granted without execution delay', async function () { - await this.managed.connect(this.roleMember)[this.selector](); - }); - - it('reverts when role is not granted', async function () { - await expect(this.managed.connect(this.other)[this.selector]()) - .to.be.revertedWithCustomError(this.managed, 'AccessManagedUnauthorized') - .withArgs(this.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 expect(this.managed.$_checkCanCall(this.roleMember, '0x1234')).to.be.reverted; - }); - - describe('when role is granted with execution delay', function () { - beforeEach(async function () { - const executionDelay = 911n; - await this.authority.$_grantRole(this.role, this.roleMember, 0, executionDelay); - }); - - it('reverts if the operation is not scheduled', async function () { - const fn = this.managed.interface.getFunction(this.selector); - const calldata = this.managed.interface.encodeFunctionData(fn, []); - const opId = await this.authority.hashOperation(this.roleMember, this.managed, calldata); - - await expect(this.managed.connect(this.roleMember)[this.selector]()) - .to.be.revertedWithCustomError(this.authority, 'AccessManagerNotScheduled') - .withArgs(opId); - }); - - it('succeeds if the operation is scheduled', async function () { - // Arguments - const delay = time.duration.hours(12); - const fn = this.managed.interface.getFunction(this.selector); - const calldata = this.managed.interface.encodeFunctionData(fn, []); - - // Schedule - const scheduledAt = (await time.clock.timestamp()) + 1n; - const when = scheduledAt + delay; - await time.increaseTo.timestamp(scheduledAt, false); - await this.authority.connect(this.roleMember).schedule(this.managed, calldata, when); - - // Set execution date - await time.increaseTo.timestamp(when, false); - - // Shouldn't revert - await this.managed.connect(this.roleMember)[this.selector](); - }); - }); - }); - - describe('setAuthority', function () { - it('reverts if the caller is not the authority', async function () { - await expect(this.managed.connect(this.other).setAuthority(this.other)) - .to.be.revertedWithCustomError(this.managed, 'AccessManagedUnauthorized') - .withArgs(this.other); - }); - - it('reverts if the new authority is not a valid authority', async function () { - await expect(this.managed.connect(this.authorityAsSigner).setAuthority(this.other)) - .to.be.revertedWithCustomError(this.managed, 'AccessManagedInvalidAuthority') - .withArgs(this.other); - }); - - it('sets authority and emits AuthorityUpdated event', async function () { - await expect(this.managed.connect(this.authorityAsSigner).setAuthority(this.anotherAuthority)) - .to.emit(this.managed, 'AuthorityUpdated') - .withArgs(this.anotherAuthority); - - expect(await this.managed.authority()).to.equal(this.anotherAuthority); - }); - }); - - describe('isConsumingScheduledOp', function () { - beforeEach(async function () { - await this.managed.connect(this.authorityAsSigner).setAuthority(this.authorityObserveIsConsuming); - }); - - it('returns bytes4(0) when not consuming operation', async function () { - expect(await this.managed.isConsumingScheduledOp()).to.equal('0x00000000'); - }); - - it('returns isConsumingScheduledOp selector when consuming operation', async function () { - const isConsumingScheduledOp = this.managed.interface.getFunction('isConsumingScheduledOp()'); - const fnRestricted = this.managed.fnRestricted.getFragment(); - await expect(this.managed.connect(this.other).fnRestricted()) - .to.emit(this.authorityObserveIsConsuming, 'ConsumeScheduledOpCalled') - .withArgs( - this.other, - this.managed.interface.encodeFunctionData(fnRestricted, []), - isConsumingScheduledOp.selector, - ); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.behavior.js deleted file mode 100644 index 385da57..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.behavior.js +++ /dev/null @@ -1,257 +0,0 @@ -const { expect } = require('chai'); - -const { - LIKE_COMMON_IS_EXECUTING, - LIKE_COMMON_GET_ACCESS, - LIKE_COMMON_SCHEDULABLE, - testAsSchedulableOperation, - testAsRestrictedOperation, - testAsDelayedOperation, - testAsCanCall, - testAsHasRole, -} = require('./AccessManager.predicate'); - -// ============ ADMIN OPERATION ============ - -/** - * @requires this.{manager,roles,calldata,role} - */ -function shouldBehaveLikeDelayedAdminOperation() { - const getAccessPath = LIKE_COMMON_GET_ACCESS; - testAsDelayedOperation.mineDelay = true; - getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = - testAsDelayedOperation; - getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = function () { - beforeEach('set execution delay', async function () { - this.scheduleIn = this.executionDelay; // For testAsDelayedOperation - }); - testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); - }; - - beforeEach('set target as manager', function () { - this.target = this.manager; - }); - - testAsRestrictedOperation({ - callerIsTheManager: LIKE_COMMON_IS_EXECUTING, - callerIsNotTheManager() { - testAsHasRole({ - publicRoleIsRequired() { - it('reverts as AccessManagerUnauthorizedAccount', async function () { - await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) - .to.be.revertedWithCustomError(this.target, 'AccessManagerUnauthorizedAccount') - .withArgs( - 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 = LIKE_COMMON_GET_ACCESS; - - function testScheduleOperation(mineDelay) { - return function self() { - self.mineDelay = mineDelay; - beforeEach('set execution delay', async function () { - this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation - }); - testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); - }; - } - - getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = - testScheduleOperation(true); - getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = testScheduleOperation(false); - - beforeEach('set target as manager', function () { - this.target = this.manager; - }); - - testAsRestrictedOperation({ - callerIsTheManager: LIKE_COMMON_IS_EXECUTING, - callerIsNotTheManager() { - testAsHasRole({ - publicRoleIsRequired() { - it('reverts as AccessManagerUnauthorizedAccount', async function () { - await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) - .to.be.revertedWithCustomError(this.target, 'AccessManagerUnauthorizedAccount') - .withArgs( - 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 = LIKE_COMMON_GET_ACCESS; - - function afterGrantDelay() { - afterGrantDelay.mineDelay = true; - beforeEach('set execution delay', async function () { - this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation - }); - testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); - } - - getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = afterGrantDelay; - getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = afterGrantDelay; - - beforeEach('set target as manager', function () { - this.target = this.manager; - }); - - testAsRestrictedOperation({ - callerIsTheManager: LIKE_COMMON_IS_EXECUTING, - callerIsNotTheManager() { - testAsHasRole({ - publicRoleIsRequired() { - it('reverts as AccessManagerUnauthorizedAccount', async function () { - await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) - .to.be.revertedWithCustomError(this.target, 'AccessManagerUnauthorizedAccount') - .withArgs(this.caller, roleAdmin); - }); - }, - specificRoleIsRequired: getAccessPath, - }); - }, - }); -} - -// ============ RESTRICTED OPERATION ============ - -/** - * @requires this.{manager,roles,calldata,role} - */ -function shouldBehaveLikeAManagedRestrictedOperation() { - function revertUnauthorized() { - it('reverts as AccessManagedUnauthorized', async function () { - await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) - .to.be.revertedWithCustomError(this.target, 'AccessManagedUnauthorized') - .withArgs(this.caller); - }); - } - - const getAccessPath = LIKE_COMMON_GET_ACCESS; - - getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.beforeGrantDelay = - revertUnauthorized; - getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasNoExecutionDelay.beforeGrantDelay = - revertUnauthorized; - getAccessPath.requiredRoleIsNotGranted = revertUnauthorized; - - function testScheduleOperation(mineDelay) { - return function self() { - self.mineDelay = mineDelay; - beforeEach('sets execution delay', async function () { - this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation - }); - testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); - }; - } - - getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = - testScheduleOperation(true); - getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = testScheduleOperation(false); - - const isExecutingPath = LIKE_COMMON_IS_EXECUTING; - isExecutingPath.notExecuting = revertUnauthorized; - - testAsCanCall({ - closed: revertUnauthorized, - open: { - callerIsTheManager: isExecutingPath, - callerIsNotTheManager: { - publicRoleIsRequired() { - it('succeeds called directly', async function () { - await this.caller.sendTransaction({ to: this.target, data: this.calldata }); - }); - - it('succeeds via execute', async function () { - await this.manager.connect(this.caller).execute(this.target, this.calldata); - }); - }, - specificRoleIsRequired: getAccessPath, - }, - }, - }); -} - -/** - * @requires this.{target,manager,roles,calldata,role} - */ -function shouldBehaveLikeASelfRestrictedOperation() { - function revertUnauthorized() { - it('reverts as AccessManagerUnauthorizedAccount', async function () { - await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedAccount') - .withArgs(this.caller, this.role?.id ?? 0n); - }); - } - - const getAccessPath = LIKE_COMMON_GET_ACCESS; - - function testScheduleOperation(mineDelay) { - return function self() { - self.mineDelay = mineDelay; - beforeEach('sets execution delay', async function () { - this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation - }); - testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); - }; - } - - getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = - testScheduleOperation(true); - getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = testScheduleOperation(false); - - beforeEach('set target as manager', function () { - this.target = this.manager; - }); - - const isExecutingPath = LIKE_COMMON_IS_EXECUTING; - isExecutingPath.notExecuting = revertUnauthorized; - - testAsCanCall({ - closed: revertUnauthorized, - open: { - callerIsTheManager: isExecutingPath, - callerIsNotTheManager: { - publicRoleIsRequired() { - it('succeeds called directly', async function () { - await this.caller.sendTransaction({ to: this.target, data: this.calldata }); - }); - - it('succeeds via execute', async function () { - await this.manager.connect(this.caller).execute(this.target, this.calldata); - }); - }, - specificRoleIsRequired: getAccessPath, - }, - }, - }); -} - -module.exports = { - shouldBehaveLikeDelayedAdminOperation, - shouldBehaveLikeNotDelayedAdminOperation, - shouldBehaveLikeRoleAdminOperation, - shouldBehaveLikeAManagedRestrictedOperation, - shouldBehaveLikeASelfRestrictedOperation, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.predicate.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.predicate.js deleted file mode 100644 index 8b4c5f4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.predicate.js +++ /dev/null @@ -1,456 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { setStorageAt } = require('@nomicfoundation/hardhat-network-helpers'); - -const { EXECUTION_ID_STORAGE_SLOT, EXPIRATION, prepareOperation } = require('../../helpers/access-manager'); -const { impersonate } = require('../../helpers/account'); -const time = require('../../helpers/time'); - -// ============ COMMON PREDICATES ============ - -const LIKE_COMMON_IS_EXECUTING = { - executing() { - it('succeeds', async function () { - await this.caller.sendTransaction({ to: this.target, data: this.calldata }); - }); - }, - notExecuting() { - it('reverts as AccessManagerUnauthorizedAccount', async function () { - await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedAccount') - .withArgs(this.caller, this.role.id); - }); - }, -}; - -const LIKE_COMMON_GET_ACCESS = { - requiredRoleIsGranted: { - roleGrantingIsDelayed: { - callerHasAnExecutionDelay: { - beforeGrantDelay() { - it('reverts as AccessManagerUnauthorizedAccount', async function () { - await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedAccount') - .withArgs(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 expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedAccount') - .withArgs(this.caller, this.role.id); - }); - }, - afterGrantDelay() { - it('succeeds called directly', async function () { - await this.caller.sendTransaction({ to: this.target, data: this.calldata }); - }); - - it('succeeds via execute', async function () { - await this.manager.connect(this.caller).execute(this.target, this.calldata); - }); - }, - }, - }, - roleGrantingIsNotDelayed: { - callerHasAnExecutionDelay: undefined, // Diverges if there's an operation to schedule or not - callerHasNoExecutionDelay() { - it('succeeds called directly', async function () { - await this.caller.sendTransaction({ to: this.target, data: this.calldata }); - }); - - it('succeeds via execute', async function () { - await this.manager.connect(this.caller).execute(this.target, this.calldata); - }); - }, - }, - }, - requiredRoleIsNotGranted() { - it('reverts as AccessManagerUnauthorizedAccount', async function () { - await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedAccount') - .withArgs(this.caller, this.role.id); - }); - }, -}; - -const LIKE_COMMON_SCHEDULABLE = { - scheduled: { - before() { - it('reverts as AccessManagerNotReady', async function () { - await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerNotReady') - .withArgs(this.operationId); - }); - }, - after() { - it('succeeds called directly', async function () { - await this.caller.sendTransaction({ to: this.target, data: this.calldata }); - }); - - it('succeeds via execute', async function () { - await this.manager.connect(this.caller).execute(this.target, this.calldata); - }); - }, - expired() { - it('reverts as AccessManagerExpired', async function () { - await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerExpired') - .withArgs(this.operationId); - }); - }, - }, - notScheduled() { - it('reverts as AccessManagerNotScheduled', async function () { - await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata })) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerNotScheduled') - .withArgs(this.operationId); - }); - }, -}; - -// ============ MODE ============ - -/** - * @requires this.{manager,target} - */ -function testAsClosable({ closed, open }) { - describe('when the manager is closed', function () { - beforeEach('close', async function () { - await this.manager.$_setTargetClosed(this.target, true); - }); - - closed(); - }); - - describe('when the manager is open', function () { - beforeEach('open', async function () { - await this.manager.$_setTargetClosed(this.target, false); - }); - - open(); - }); -} - -// ============ DELAY ============ - -/** - * @requires this.{delay} - */ -function testAsDelay(type, { before, after }) { - beforeEach('define timestamp when delay takes effect', async function () { - const timestamp = await time.clock.timestamp(); - this.delayEffect = timestamp + this.delay; - }); - - describe(`when ${type} delay has not taken effect yet`, function () { - beforeEach(`set next block timestamp before ${type} takes effect`, async function () { - await time.increaseTo.timestamp(this.delayEffect - 1n, !!before.mineDelay); - }); - - before(); - }); - - describe(`when ${type} delay has taken effect`, function () { - beforeEach(`set next block timestamp when ${type} takes effect`, async function () { - await time.increaseTo.timestamp(this.delayEffect, !!after.mineDelay); - }); - - after(); - }); -} - -// ============ OPERATION ============ - -/** - * @requires this.{manager,scheduleIn,caller,target,calldata} - */ -function testAsSchedulableOperation({ scheduled: { before, after, expired }, notScheduled }) { - describe('when operation is scheduled', function () { - beforeEach('schedule operation', async function () { - if (this.caller.target) { - await impersonate(this.caller.target); - this.caller = await ethers.getSigner(this.caller.target); - } - const { operationId, schedule } = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay: this.scheduleIn, - }); - await schedule(); - 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.clock.timestamp(); - const schedule = await this.manager.getSchedule(this.operationId); - await time.increaseTo.timestamp(schedule - 1n, !!before.mineDelay); - }); - - 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.clock.timestamp(); - const schedule = await this.manager.getSchedule(this.operationId); - await time.increaseTo.timestamp(schedule, !!after.mineDelay); - }); - - after(); - }); - - describe('when operation has expired', function () { - beforeEach('set next block time when operation expired', async function () { - this.scheduledAt = await time.clock.timestamp(); - const schedule = await this.manager.getSchedule(this.operationId); - await time.increaseTo.timestamp(schedule + EXPIRATION, !!expired.mineDelay); - }); - - expired(); - }); - }); - - describe('when operation is not scheduled', function () { - beforeEach('set expected operationId', async function () { - this.operationId = await this.manager.hashOperation(this.caller, this.target, this.calldata); - - // Assert operation is not scheduled - expect(await this.manager.getSchedule(this.operationId)).to.equal(0n); - }); - - notScheduled(); - }); -} - -/** - * @requires this.{manager,roles,target,calldata} - */ -function testAsRestrictedOperation({ callerIsTheManager: { executing, notExecuting }, callerIsNotTheManager }) { - describe('when the call comes from the manager (msg.sender == manager)', function () { - beforeEach('define caller as manager', async function () { - this.caller = this.manager; - if (this.caller.target) { - await impersonate(this.caller.target); - this.caller = await ethers.getSigner(this.caller.target); - } - }); - - describe('when _executionId is in storage for target and selector', function () { - beforeEach('set _executionId flag from calldata and target', async function () { - const executionId = ethers.keccak256( - ethers.AbiCoder.defaultAbiCoder().encode( - ['address', 'bytes4'], - [this.target.target, this.calldata.substring(0, 10)], - ), - ); - await setStorageAt(this.manager.target, EXECUTION_ID_STORAGE_SLOT, executionId); - }); - - executing(); - }); - - describe('when _executionId does not match target and selector', notExecuting); - }); - - 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,scheduleIn,caller,target,calldata,executionDelay} - */ -function testAsDelayedOperation() { - 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 + time.duration.hours(1); - await this.manager.$_setTargetAdminDelay(this.target, this.operationDelay); - this.scheduleIn = this.operationDelay; // For testAsSchedulableOperation - }); - - testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); - }); - - describe('when operation delay is shorter than execution delay', function () { - beforeEach('set operation delay', async function () { - this.operationDelay = this.executionDelay - time.duration.hours(1); - await this.manager.$_setTargetAdminDelay(this.target, this.operationDelay); - this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation - }); - - testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); - }); - }); - - describe('without operation delay', function () { - beforeEach('set operation delay', async function () { - this.operationDelay = 0n; - await this.manager.$_setTargetAdminDelay(this.target, this.operationDelay); - this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation - }); - - testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); - }); -} - -// ============ METHOD ============ - -/** - * @requires this.{manager,roles,role,target,calldata} - */ -function testAsCanCall({ - closed, - open: { - callerIsTheManager, - callerIsNotTheManager: { publicRoleIsRequired, specificRoleIsRequired }, - }, -}) { - testAsClosable({ - closed, - open() { - testAsRestrictedOperation({ - callerIsTheManager, - callerIsNotTheManager() { - testAsHasRole({ - publicRoleIsRequired, - specificRoleIsRequired, - }); - }, - }); - }, - }); -} - -/** - * @requires this.{target,calldata,roles,role} - */ -function testAsHasRole({ 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 - .connect(this.roles.ADMIN.members[0]) - .$_setTargetFunctionRole(this.target, this.calldata.substring(0, 10), this.role.id); - }); - - 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 - .connect(this.roles.ADMIN.members[0]) - .$_setTargetFunctionRole(this.target, this.calldata.substring(0, 10), this.role.id); - }); - - testAsGetAccess(specificRoleIsRequired); - }); -} - -/** - * @requires this.{manager,role,caller} - */ -function testAsGetAccess({ - 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 testAsDelay 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 testAsDelay - }); - - 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); - }); - - testAsDelay('grant', { before: case1, after: case2 }); - }); - - describe('when caller has no execution delay', function () { - beforeEach('set role and delay', async function () { - this.executionDelay = 0n; - await this.manager.$_grantRole(this.role.id, this.caller, this.grantDelay, this.executionDelay); - }); - - testAsDelay('grant', { before: case3, after: case4 }); - }); - }); - - describe('when role granting is not delayed', function () { - beforeEach('define delay', function () { - this.grantDelay = 0n; - }); - - 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 = 0n; - 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.equal(0n); - }); - - requiredRoleIsNotGranted(); - }); -} - -module.exports = { - LIKE_COMMON_IS_EXECUTING, - LIKE_COMMON_GET_ACCESS, - LIKE_COMMON_SCHEDULABLE, - testAsClosable, - testAsDelay, - testAsSchedulableOperation, - testAsRestrictedOperation, - testAsDelayedOperation, - testAsCanCall, - testAsHasRole, - testAsGetAccess, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.test.js deleted file mode 100644 index 7726831..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AccessManager.test.js +++ /dev/null @@ -1,2489 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { impersonate } = require('../../helpers/account'); -const { MAX_UINT48 } = require('../../helpers/constants'); -const { selector } = require('../../helpers/methods'); -const time = require('../../helpers/time'); - -const { - buildBaseRoles, - formatAccess, - EXPIRATION, - MINSETBACK, - EXECUTION_ID_STORAGE_SLOT, - CONSUMING_SCHEDULE_STORAGE_SLOT, - prepareOperation, - hashOperation, -} = require('../../helpers/access-manager'); - -const { - shouldBehaveLikeDelayedAdminOperation, - shouldBehaveLikeNotDelayedAdminOperation, - shouldBehaveLikeRoleAdminOperation, - shouldBehaveLikeAManagedRestrictedOperation, - shouldBehaveLikeASelfRestrictedOperation, -} = require('./AccessManager.behavior'); - -const { - LIKE_COMMON_SCHEDULABLE, - testAsClosable, - testAsDelay, - testAsSchedulableOperation, - testAsCanCall, - testAsHasRole, - testAsGetAccess, -} = require('./AccessManager.predicate'); - -async function fixture() { - const [admin, roleAdmin, roleGuardian, member, user, other] = await ethers.getSigners(); - - // Build roles - const roles = buildBaseRoles(); - - // Add members - roles.ADMIN.members = [admin]; - roles.SOME_ADMIN.members = [roleAdmin]; - roles.SOME_GUARDIAN.members = [roleGuardian]; - roles.SOME.members = [member]; - roles.PUBLIC.members = [admin, roleAdmin, roleGuardian, member, user, other]; - - const manager = await ethers.deployContract('$AccessManagerMock', [admin]); - const target = await ethers.deployContract('$AccessManagedTarget', [manager]); - - for (const { id: roleId, admin, guardian, members } of Object.values(roles)) { - if (roleId === roles.PUBLIC.id) continue; // Every address belong to public and is locked - if (roleId === roles.ADMIN.id) continue; // Admin set during construction and is locked - - // Set admin role avoiding default - if (admin.id !== roles.ADMIN.id) { - await manager.$_setRoleAdmin(roleId, admin.id); - } - - // Set guardian role avoiding default - if (guardian.id !== roles.ADMIN.id) { - await manager.$_setRoleGuardian(roleId, guardian.id); - } - - // Grant role to members - for (const member of members) { - await manager.$_grantRole(roleId, member, 0, 0); - } - } - - return { - admin, - roleAdmin, - user, - other, - roles, - manager, - target, - }; -} - -// This test suite is made using the following tools: -// -// * Predicates: Functions with common conditional setups without assertions. -// * Behaviors: Functions with common assertions. -// -// The behavioral tests are built by composing predicates and are used as templates -// for testing access to restricted functions. -// -// Similarly, unit tests in this suite will use predicates to test subsets of these -// behaviors and are helped by common assertions provided for some of the predicates. -// -// The predicates can be identified by the `testAs*` prefix while the behaviors -// are prefixed with `shouldBehave*`. The common assertions for predicates are -// defined as constants. -describe('AccessManager', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('during construction', function () { - it('grants admin role to initialAdmin', async function () { - const manager = await ethers.deployContract('$AccessManager', [this.other]); - expect(await manager.hasRole(this.roles.ADMIN.id, this.other).then(formatAccess)).to.be.deep.equal([true, '0']); - }); - - it('rejects zero address for initialAdmin', async function () { - await expect(ethers.deployContract('$AccessManager', [ethers.ZeroAddress])) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerInvalidInitialAdmin') - .withArgs(ethers.ZeroAddress); - }); - - 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.equal(admin.id); - expect(await this.manager.getRoleGuardian(roleId)).to.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: 379204n }; - }); - - testAsCanCall({ - closed() { - it('should return false and no delay', async function () { - const { immediate, delay } = await this.manager.canCall( - this.other, - this.target, - this.calldata.substring(0, 10), - ); - expect(immediate).to.be.false; - expect(delay).to.equal(0n); - }); - }, - open: { - callerIsTheManager: { - executing() { - it('should return true and no delay', async function () { - const { immediate, delay } = await this.manager.canCall( - this.caller, - this.target, - this.calldata.substring(0, 10), - ); - expect(immediate).to.be.true; - expect(delay).to.equal(0n); - }); - }, - notExecuting() { - it('should return false and no delay', async function () { - const { immediate, delay } = await this.manager.canCall( - this.caller, - this.target, - this.calldata.substring(0, 10), - ); - expect(immediate).to.be.false; - expect(delay).to.equal(0n); - }); - }, - }, - callerIsNotTheManager: { - publicRoleIsRequired() { - it('should return true and no delay', async function () { - const { immediate, delay } = await this.manager.canCall( - this.caller, - this.target, - this.calldata.substring(0, 10), - ); - expect(immediate).to.be.true; - expect(delay).to.equal(0n); - }); - }, - specificRoleIsRequired: { - requiredRoleIsGranted: { - roleGrantingIsDelayed: { - callerHasAnExecutionDelay: { - beforeGrantDelay: function self() { - self.mineDelay = true; - - it('should return false and no execution delay', async function () { - const { immediate, delay } = await this.manager.canCall( - this.caller, - this.target, - this.calldata.substring(0, 10), - ); - expect(immediate).to.be.false; - expect(delay).to.equal(0n); - }); - }, - afterGrantDelay: function self() { - self.mineDelay = true; - - beforeEach('sets execution delay', function () { - this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation - }); - - testAsSchedulableOperation({ - scheduled: { - before: function self() { - self.mineDelay = true; - - it('should return false and execution delay', async function () { - const { immediate, delay } = await this.manager.canCall( - this.caller, - this.target, - this.calldata.substring(0, 10), - ); - expect(immediate).to.be.false; - expect(delay).to.equal(this.executionDelay); - }); - }, - after: function self() { - self.mineDelay = true; - - it('should return false and execution delay', async function () { - const { immediate, delay } = await this.manager.canCall( - this.caller, - this.target, - this.calldata.substring(0, 10), - ); - expect(immediate).to.be.false; - expect(delay).to.equal(this.executionDelay); - }); - }, - expired: function self() { - self.mineDelay = true; - - it('should return false and execution delay', async function () { - const { immediate, delay } = await this.manager.canCall( - this.caller, - this.target, - this.calldata.substring(0, 10), - ); - expect(immediate).to.be.false; - expect(delay).to.equal(this.executionDelay); - }); - }, - }, - notScheduled() { - it('should return false and execution delay', async function () { - const { immediate, delay } = await this.manager.canCall( - this.caller, - this.target, - this.calldata.substring(0, 10), - ); - expect(immediate).to.be.false; - expect(delay).to.equal(this.executionDelay); - }); - }, - }); - }, - }, - callerHasNoExecutionDelay: { - beforeGrantDelay: function self() { - self.mineDelay = true; - - it('should return false and no execution delay', async function () { - const { immediate, delay } = await this.manager.canCall( - this.caller, - this.target, - this.calldata.substring(0, 10), - ); - expect(immediate).to.be.false; - expect(delay).to.equal(0n); - }); - }, - afterGrantDelay: function self() { - self.mineDelay = true; - - it('should return true and no execution delay', async function () { - const { immediate, delay } = await this.manager.canCall( - this.caller, - this.target, - this.calldata.substring(0, 10), - ); - expect(immediate).to.be.true; - expect(delay).to.equal(0n); - }); - }, - }, - }, - roleGrantingIsNotDelayed: { - callerHasAnExecutionDelay() { - it('should return false and execution delay', async function () { - const { immediate, delay } = await this.manager.canCall( - this.caller, - this.target, - this.calldata.substring(0, 10), - ); - expect(immediate).to.be.false; - expect(delay).to.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, - this.calldata.substring(0, 10), - ); - expect(immediate).to.be.true; - expect(delay).to.equal(0n); - }); - }, - }, - }, - requiredRoleIsNotGranted() { - it('should return false and no execution delay', async function () { - const { immediate, delay } = await this.manager.canCall( - this.caller, - this.target, - this.calldata.substring(0, 10), - ); - expect(immediate).to.be.false; - expect(delay).to.equal(0n); - }); - }, - }, - }, - }, - }); - }); - - describe('#expiration', function () { - it('has a 7 days default expiration', async function () { - expect(await this.manager.expiration()).to.equal(EXPIRATION); - }); - }); - - describe('#minSetback', function () { - it('has a 5 days default minimum setback', async function () { - expect(await this.manager.minSetback()).to.equal(MINSETBACK); - }); - }); - - describe('#isTargetClosed', function () { - testAsClosable({ - closed() { - it('returns true', async function () { - expect(await this.manager.isTargetClosed(this.target)).to.be.true; - }); - }, - open() { - it('returns false', async function () { - expect(await this.manager.isTargetClosed(this.target)).to.be.false; - }); - }, - }); - }); - - describe('#getTargetFunctionRole', function () { - const methodSelector = selector('something(address,bytes)'); - - it('returns the target function role', async function () { - const roleId = 21498n; - await this.manager.$_setTargetFunctionRole(this.target, methodSelector, roleId); - - expect(await this.manager.getTargetFunctionRole(this.target, methodSelector)).to.equal(roleId); - }); - - it('returns the ADMIN role if not set', async function () { - expect(await this.manager.getTargetFunctionRole(this.target, methodSelector)).to.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); - this.newDelay = time.duration.days(10); - - await this.manager.$_setTargetAdminDelay(this.target, this.newDelay); - this.delay = MINSETBACK; // For testAsDelay - }); - - testAsDelay('effect', { - before: function self() { - self.mineDelay = true; - - it('returns the old target admin delay', async function () { - expect(await this.manager.getTargetAdminDelay(this.target)).to.equal(this.oldDelay); - }); - }, - after: function self() { - self.mineDelay = true; - - it('returns the new target admin delay', async function () { - expect(await this.manager.getTargetAdminDelay(this.target)).to.equal(this.newDelay); - }); - }, - }); - }); - - it('returns the 0 if not set', async function () { - expect(await this.manager.getTargetAdminDelay(this.target)).to.equal(0n); - }); - }); - - describe('#getRoleAdmin', function () { - const roleId = 5234907n; - - it('returns the role admin', async function () { - const adminId = 789433n; - - await this.manager.$_setRoleAdmin(roleId, adminId); - - expect(await this.manager.getRoleAdmin(roleId)).to.equal(adminId); - }); - - it('returns the ADMIN role if not set', async function () { - expect(await this.manager.getRoleAdmin(roleId)).to.equal(this.roles.ADMIN.id); - }); - }); - - describe('#getRoleGuardian', function () { - const roleId = 5234907n; - - it('returns the role guardian', async function () { - const guardianId = 789433n; - - await this.manager.$_setRoleGuardian(roleId, guardianId); - - expect(await this.manager.getRoleGuardian(roleId)).to.equal(guardianId); - }); - - it('returns the ADMIN role if not set', async function () { - expect(await this.manager.getRoleGuardian(roleId)).to.equal(this.roles.ADMIN.id); - }); - }); - - describe('#getRoleGrantDelay', function () { - const roleId = 9248439n; - - 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 testAsDelay - }); - - testAsDelay('grant', { - before: function self() { - self.mineDelay = true; - - it('returns the old role grant delay', async function () { - expect(await this.manager.getRoleGrantDelay(roleId)).to.equal(this.oldDelay); - }); - }, - after: function self() { - self.mineDelay = true; - - it('returns the new role grant delay', async function () { - expect(await this.manager.getRoleGrantDelay(roleId)).to.equal(this.newDelay); - }); - }, - }); - }); - - it('returns 0 if delay is not set', async function () { - expect(await this.manager.getTargetAdminDelay(this.target)).to.equal(0n); - }); - }); - - describe('#getAccess', function () { - beforeEach('set role', function () { - this.role = { id: 9452n }; - this.caller = this.user; - }); - - testAsGetAccess({ - requiredRoleIsGranted: { - roleGrantingIsDelayed: { - callerHasAnExecutionDelay: { - beforeGrantDelay: function self() { - self.mineDelay = true; - - 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.equal(this.delayEffect); // inEffectSince - expect(access[1]).to.equal(this.executionDelay); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // pendingDelayEffect - - // Not in effect yet - expect(await time.clock.timestamp()).to.lt(access[0]); - }); - }, - afterGrantDelay: function self() { - self.mineDelay = true; - - 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.equal(this.delayEffect); // inEffectSince - expect(access[1]).to.equal(this.executionDelay); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // pendingDelayEffect - - // Already in effect - expect(await time.clock.timestamp()).to.equal(access[0]); - }); - }, - }, - callerHasNoExecutionDelay: { - beforeGrantDelay: function self() { - self.mineDelay = true; - - 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.equal(this.delayEffect); // inEffectSince - expect(access[1]).to.equal(0n); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // pendingDelayEffect - - // Not in effect yet - expect(await time.clock.timestamp()).to.lt(access[0]); - }); - }, - afterGrantDelay: function self() { - self.mineDelay = true; - - 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.equal(this.delayEffect); // inEffectSince - expect(access[1]).to.equal(0n); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // pendingDelayEffect - - // Already in effect - expect(await time.clock.timestamp()).to.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.equal(await time.clock.timestamp()); // inEffectSince - expect(access[1]).to.equal(this.executionDelay); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // pendingDelayEffect - - // Already in effect - expect(await time.clock.timestamp()).to.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.equal(await time.clock.timestamp()); // inEffectSince - expect(access[1]).to.equal(0n); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // pendingDelayEffect - - // Already in effect - expect(await time.clock.timestamp()).to.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.equal(0n); // inEffectSince - expect(access[1]).to.equal(0n); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // pendingDelayEffect - }); - }, - }); - }); - - describe('#hasRole', function () { - beforeEach('setup testAsHasRole', function () { - this.role = { id: 49832n }; - this.calldata = '0x12345678'; - this.caller = this.user; - }); - - testAsHasRole({ - 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.equal('0'); - }); - }, - specificRoleIsRequired: { - requiredRoleIsGranted: { - roleGrantingIsDelayed: { - callerHasAnExecutionDelay: { - beforeGrantDelay: function self() { - self.mineDelay = true; - - 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.equal(this.executionDelay); - }); - }, - afterGrantDelay: function self() { - self.mineDelay = true; - - 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.equal(this.executionDelay); - }); - }, - }, - callerHasNoExecutionDelay: { - beforeGrantDelay: function self() { - self.mineDelay = true; - - 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.equal('0'); - }); - }, - afterGrantDelay: function self() { - self.mineDelay = true; - - 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.equal('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.equal(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.equal('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.equal('0'); - }); - }, - }, - }); - }); - - describe('#getSchedule', function () { - beforeEach('set role and calldata', async function () { - const fnRestricted = this.target.fnRestricted.getFragment().selector; - this.caller = this.user; - this.role = { id: 493590n }; - await this.manager.$_setTargetFunctionRole(this.target, fnRestricted, this.role.id); - await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay - - this.calldata = this.target.interface.encodeFunctionData(fnRestricted, []); - this.scheduleIn = time.duration.days(10); // For testAsSchedulableOperation - }); - - testAsSchedulableOperation({ - scheduled: { - before: function self() { - self.mineDelay = true; - - it('returns schedule in the future', async function () { - const schedule = await this.manager.getSchedule(this.operationId); - expect(schedule).to.equal(this.scheduledAt + this.scheduleIn); - expect(schedule).to.gt(await time.clock.timestamp()); - }); - }, - after: function self() { - self.mineDelay = true; - - it('returns schedule', async function () { - const schedule = await this.manager.getSchedule(this.operationId); - expect(schedule).to.equal(this.scheduledAt + this.scheduleIn); - expect(schedule).to.equal(await time.clock.timestamp()); - }); - }, - expired: function self() { - self.mineDelay = true; - - it('returns 0', async function () { - expect(await this.manager.getSchedule(this.operationId)).to.equal(0n); - }); - }, - }, - notScheduled() { - it('defaults to 0', async function () { - expect(await this.manager.getSchedule(this.operationId)).to.equal(0n); - }); - }, - }); - }); - - describe('#getNonce', function () { - describe('when operation is scheduled', function () { - beforeEach('schedule operation', async function () { - const fnRestricted = this.target.fnRestricted.getFragment().selector; - this.caller = this.user; - this.role = { id: 4209043n }; - await this.manager.$_setTargetFunctionRole(this.target, fnRestricted, this.role.id); - await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay - - this.calldata = this.target.interface.encodeFunctionData(fnRestricted, []); - this.delay = time.duration.days(10); - - const { operationId, schedule } = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay: this.delay, - }); - await schedule(); - this.operationId = operationId; - }); - - it('returns nonce', async function () { - expect(await this.manager.getNonce(this.operationId)).to.equal(1n); - }); - }); - - describe('when is not scheduled', function () { - it('returns default 0', async function () { - expect(await this.manager.getNonce(ethers.id('operation'))).to.equal(0n); - }); - }); - }); - - describe('#hashOperation', function () { - it('returns an operationId', async function () { - const args = [this.user, this.other, '0x123543']; - expect(await this.manager.hashOperation(...args)).to.equal(hashOperation(...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 args = [123443, 'TEST']; - const method = this.manager.interface.getFunction('labelRole(uint64,string)'); - this.calldata = this.manager.interface.encodeFunctionData(method, args); - }); - - shouldBehaveLikeDelayedAdminOperation(); - }); - - it('emits an event with the label', async function () { - await expect(this.manager.connect(this.admin).labelRole(this.roles.SOME.id, 'Some label')) - .to.emit(this.manager, 'RoleLabel') - .withArgs(this.roles.SOME.id, 'Some label'); - }); - - it('updates label on a second call', async function () { - await this.manager.connect(this.admin).labelRole(this.roles.SOME.id, 'Some label'); - - await expect(this.manager.connect(this.admin).labelRole(this.roles.SOME.id, 'Updated label')) - .to.emit(this.manager, 'RoleLabel') - .withArgs(this.roles.SOME.id, 'Updated label'); - }); - - it('reverts labeling PUBLIC_ROLE', async function () { - await expect(this.manager.connect(this.admin).labelRole(this.roles.PUBLIC.id, 'Some label')) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') - .withArgs(this.roles.PUBLIC.id); - }); - - it('reverts labeling ADMIN_ROLE', async function () { - await expect(this.manager.connect(this.admin).labelRole(this.roles.ADMIN.id, 'Some label')) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') - .withArgs(this.roles.ADMIN.id); - }); - }); - - describe('#setRoleAdmin', function () { - describe('restrictions', function () { - beforeEach('set method and args', function () { - const args = [93445, 84532]; - const method = this.manager.interface.getFunction('setRoleAdmin(uint64,uint64)'); - this.calldata = this.manager.interface.encodeFunctionData(method, args); - }); - - shouldBehaveLikeDelayedAdminOperation(); - }); - - it("sets any role's admin if called by an admin", async function () { - expect(await this.manager.getRoleAdmin(this.roles.SOME.id)).to.equal(this.roles.SOME_ADMIN.id); - - await expect(this.manager.connect(this.admin).setRoleAdmin(this.roles.SOME.id, this.roles.ADMIN.id)) - .to.emit(this.manager, 'RoleAdminChanged') - .withArgs(this.roles.SOME.id, this.roles.ADMIN.id); - - expect(await this.manager.getRoleAdmin(this.roles.SOME.id)).to.equal(this.roles.ADMIN.id); - }); - - it('reverts setting PUBLIC_ROLE admin', async function () { - await expect(this.manager.connect(this.admin).setRoleAdmin(this.roles.PUBLIC.id, this.roles.ADMIN.id)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') - .withArgs(this.roles.PUBLIC.id); - }); - - it('reverts setting ADMIN_ROLE admin', async function () { - await expect(this.manager.connect(this.admin).setRoleAdmin(this.roles.ADMIN.id, this.roles.ADMIN.id)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') - .withArgs(this.roles.ADMIN.id); - }); - }); - - describe('#setRoleGuardian', function () { - describe('restrictions', function () { - beforeEach('set method and args', function () { - const args = [93445, 84532]; - const method = this.manager.interface.getFunction('setRoleGuardian(uint64,uint64)'); - this.calldata = this.manager.interface.encodeFunctionData(method, args); - }); - - shouldBehaveLikeDelayedAdminOperation(); - }); - - it("sets any role's guardian if called by an admin", async function () { - expect(await this.manager.getRoleGuardian(this.roles.SOME.id)).to.equal(this.roles.SOME_GUARDIAN.id); - - await expect(this.manager.connect(this.admin).setRoleGuardian(this.roles.SOME.id, this.roles.ADMIN.id)) - .to.emit(this.manager, 'RoleGuardianChanged') - .withArgs(this.roles.SOME.id, this.roles.ADMIN.id); - - expect(await this.manager.getRoleGuardian(this.roles.SOME.id)).to.equal(this.roles.ADMIN.id); - }); - - it('reverts setting PUBLIC_ROLE admin', async function () { - await expect(this.manager.connect(this.admin).setRoleGuardian(this.roles.PUBLIC.id, this.roles.ADMIN.id)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') - .withArgs(this.roles.PUBLIC.id); - }); - - it('reverts setting ADMIN_ROLE admin', async function () { - await expect(this.manager.connect(this.admin).setRoleGuardian(this.roles.ADMIN.id, this.roles.ADMIN.id)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') - .withArgs(this.roles.ADMIN.id); - }); - }); - - describe('#setGrantDelay', function () { - describe('restrictions', function () { - beforeEach('set method and args', function () { - const args = [984910, time.duration.days(2)]; - const method = this.manager.interface.getFunction('setGrantDelay(uint64,uint32)'); - this.calldata = this.manager.interface.encodeFunctionData(method, args); - }); - - shouldBehaveLikeDelayedAdminOperation(); - }); - - it('reverts setting grant delay for the PUBLIC_ROLE', async function () { - await expect(this.manager.connect(this.admin).setGrantDelay(this.roles.PUBLIC.id, 69n)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') - .withArgs(this.roles.PUBLIC.id); - }); - - describe('when increasing the delay', function () { - const oldDelay = 10n; - const newDelay = 100n; - - beforeEach('sets old delay', async function () { - this.role = this.roles.SOME; - await this.manager.$_setGrantDelay(this.role.id, oldDelay); - await time.increaseBy.timestamp(MINSETBACK); - expect(await this.manager.getRoleGrantDelay(this.role.id)).to.equal(oldDelay); - }); - - it('increases the delay after minsetback', async function () { - const txResponse = await this.manager.connect(this.admin).setGrantDelay(this.role.id, newDelay); - const setGrantDelayAt = await time.clockFromReceipt.timestamp(txResponse); - await expect(txResponse) - .to.emit(this.manager, 'RoleGrantDelayChanged') - .withArgs(this.role.id, newDelay, setGrantDelayAt + MINSETBACK); - - expect(await this.manager.getRoleGrantDelay(this.role.id)).to.equal(oldDelay); - await time.increaseBy.timestamp(MINSETBACK); - expect(await this.manager.getRoleGrantDelay(this.role.id)).to.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.increaseBy.timestamp(MINSETBACK); - expect(await this.manager.getRoleGrantDelay(this.role.id)).to.equal(oldDelay); - }); - - describe('when the delay difference is shorter than minimum setback', function () { - const newDelay = oldDelay - 1n; - - it('increases the delay after minsetback', async function () { - const txResponse = await this.manager.connect(this.admin).setGrantDelay(this.role.id, newDelay); - const setGrantDelayAt = await time.clockFromReceipt.timestamp(txResponse); - await expect(txResponse) - .to.emit(this.manager, 'RoleGrantDelayChanged') - .withArgs(this.role.id, newDelay, setGrantDelayAt + MINSETBACK); - - expect(await this.manager.getRoleGrantDelay(this.role.id)).to.equal(oldDelay); - await time.increaseBy.timestamp(MINSETBACK); - expect(await this.manager.getRoleGrantDelay(this.role.id)).to.equal(newDelay); - }); - }); - - describe('when the delay difference is longer than minimum setback', function () { - const newDelay = 1n; - - beforeEach('assert delay difference is higher than minsetback', function () { - expect(oldDelay - newDelay).to.gt(MINSETBACK); - }); - - it('increases the delay after delay difference', async function () { - const setback = oldDelay - newDelay; - - const txResponse = await this.manager.connect(this.admin).setGrantDelay(this.role.id, newDelay); - const setGrantDelayAt = await time.clockFromReceipt.timestamp(txResponse); - - await expect(txResponse) - .to.emit(this.manager, 'RoleGrantDelayChanged') - .withArgs(this.role.id, newDelay, setGrantDelayAt + setback); - - expect(await this.manager.getRoleGrantDelay(this.role.id)).to.equal(oldDelay); - await time.increaseBy.timestamp(setback); - expect(await this.manager.getRoleGrantDelay(this.role.id)).to.equal(newDelay); - }); - }); - }); - }); - - describe('#setTargetAdminDelay', function () { - describe('restrictions', function () { - beforeEach('set method and args', function () { - const args = [this.other.address, time.duration.days(3)]; - const method = this.manager.interface.getFunction('setTargetAdminDelay(address,uint32)'); - this.calldata = this.manager.interface.encodeFunctionData(method, args); - }); - - shouldBehaveLikeDelayedAdminOperation(); - }); - - describe('when increasing the delay', function () { - const oldDelay = time.duration.days(10); - const newDelay = time.duration.days(11); - - beforeEach('sets old delay', async function () { - await this.manager.$_setTargetAdminDelay(this.other, oldDelay); - await time.increaseBy.timestamp(MINSETBACK); - expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay); - }); - - it('increases the delay after minsetback', async function () { - const txResponse = await this.manager.connect(this.admin).setTargetAdminDelay(this.other, newDelay); - const setTargetAdminDelayAt = await time.clockFromReceipt.timestamp(txResponse); - await expect(txResponse) - .to.emit(this.manager, 'TargetAdminDelayUpdated') - .withArgs(this.other, newDelay, setTargetAdminDelayAt + MINSETBACK); - - expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay); - await time.increaseBy.timestamp(MINSETBACK); - expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(newDelay); - }); - }); - - describe('when reducing the delay', function () { - const oldDelay = time.duration.days(10); - - beforeEach('sets old delay', async function () { - await this.manager.$_setTargetAdminDelay(this.other, oldDelay); - await time.increaseBy.timestamp(MINSETBACK); - expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay); - }); - - describe('when the delay difference is shorter than minimum setback', function () { - const newDelay = oldDelay - 1n; - - it('increases the delay after minsetback', async function () { - const txResponse = await this.manager.connect(this.admin).setTargetAdminDelay(this.other, newDelay); - const setTargetAdminDelayAt = await time.clockFromReceipt.timestamp(txResponse); - await expect(txResponse) - .to.emit(this.manager, 'TargetAdminDelayUpdated') - .withArgs(this.other, newDelay, setTargetAdminDelayAt + MINSETBACK); - - expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay); - await time.increaseBy.timestamp(MINSETBACK); - expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(newDelay); - }); - }); - - describe('when the delay difference is longer than minimum setback', function () { - const newDelay = 1n; - - beforeEach('assert delay difference is higher than minsetback', function () { - expect(oldDelay - newDelay).to.gt(MINSETBACK); - }); - - it('increases the delay after delay difference', async function () { - const setback = oldDelay - newDelay; - - const txResponse = await this.manager.connect(this.admin).setTargetAdminDelay(this.other, newDelay); - const setTargetAdminDelayAt = await time.clockFromReceipt.timestamp(txResponse); - - await expect(txResponse) - .to.emit(this.manager, 'TargetAdminDelayUpdated') - .withArgs(this.other, newDelay, setTargetAdminDelayAt + setback); - - expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay); - await time.increaseBy.timestamp(setback); - expect(await this.manager.getTargetAdminDelay(this.other)).to.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 ethers.deployContract('$AccessManager', [this.admin]); - this.newManagedTarget = await ethers.deployContract('$AccessManagedTarget', [this.manager]); - }); - - describe('restrictions', function () { - beforeEach('set method and args', function () { - this.calldata = this.manager.interface.encodeFunctionData('updateAuthority(address,address)', [ - this.newManagedTarget.target, - this.newAuthority.target, - ]); - }); - - shouldBehaveLikeNotDelayedAdminOperation(); - }); - - it('changes the authority', async function () { - expect(await this.newManagedTarget.authority()).to.equal(this.manager); - - await expect(this.manager.connect(this.admin).updateAuthority(this.newManagedTarget, this.newAuthority)) - .to.emit(this.newManagedTarget, 'AuthorityUpdated') // Managed contract is responsible of notifying the change through an event - .withArgs(this.newAuthority); - - expect(await this.newManagedTarget.authority()).to.equal(this.newAuthority); - }); - }); - - describe('#setTargetClosed', function () { - describe('restrictions', function () { - beforeEach('set method and args', function () { - const args = [this.other.address, true]; - const method = this.manager.interface.getFunction('setTargetClosed(address,bool)'); - this.calldata = this.manager.interface.encodeFunctionData(method, args); - }); - - shouldBehaveLikeNotDelayedAdminOperation(); - }); - - it('closes and opens a target', async function () { - await expect(this.manager.connect(this.admin).setTargetClosed(this.target, true)) - .to.emit(this.manager, 'TargetClosed') - .withArgs(this.target, true); - expect(await this.manager.isTargetClosed(this.target)).to.be.true; - - await expect(this.manager.connect(this.admin).setTargetClosed(this.target, false)) - .to.emit(this.manager, 'TargetClosed') - .withArgs(this.target, false); - expect(await this.manager.isTargetClosed(this.target)).to.be.false; - }); - - describe('when the target is the manager', async function () { - it('closes and opens the manager', async function () { - await expect(this.manager.connect(this.admin).setTargetClosed(this.manager, true)) - .to.emit(this.manager, 'TargetClosed') - .withArgs(this.manager, true); - expect(await this.manager.isTargetClosed(this.manager)).to.be.true; - - await expect(this.manager.connect(this.admin).setTargetClosed(this.manager, false)) - .to.emit(this.manager, 'TargetClosed') - .withArgs(this.manager, false); - expect(await this.manager.isTargetClosed(this.manager)).to.be.false; - }); - }); - }); - - describe('#setTargetFunctionRole', function () { - describe('restrictions', function () { - beforeEach('set method and args', function () { - const args = [this.other.address, ['0x12345678'], 443342]; - const method = this.manager.interface.getFunction('setTargetFunctionRole(address,bytes4[],uint64)'); - this.calldata = this.manager.interface.encodeFunctionData(method, args); - }); - - 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, sig)).to.equal(this.roles.ADMIN.id); - } - - const allowRole = await this.manager - .connect(this.admin) - .setTargetFunctionRole(this.target, sigs, this.roles.SOME.id); - - for (const sig of sigs) { - await expect(allowRole) - .to.emit(this.manager, 'TargetFunctionRoleUpdated') - .withArgs(this.target, sig, this.roles.SOME.id); - expect(await this.manager.getTargetFunctionRole(this.target, sig)).to.equal(this.roles.SOME.id); - } - - await expect( - this.manager.connect(this.admin).setTargetFunctionRole(this.target, [sigs[1]], this.roles.SOME_ADMIN.id), - ) - .to.emit(this.manager, 'TargetFunctionRoleUpdated') - .withArgs(this.target, sigs[1], this.roles.SOME_ADMIN.id); - - for (const sig of sigs) { - expect(await this.manager.getTargetFunctionRole(this.target, sig)).to.equal( - sig == sigs[1] ? this.roles.SOME_ADMIN.id : this.roles.SOME.id, - ); - } - }); - }); - - describe('role admin operations', function () { - const ANOTHER_ADMIN = 0xdeadc0de1n; - const ANOTHER_ROLE = 0xdeadc0de2n; - - beforeEach('set required role', async function () { - // Make admin a member of ANOTHER_ADMIN - await this.manager.$_grantRole(ANOTHER_ADMIN, this.admin, 0, 0); - await this.manager.$_setRoleAdmin(ANOTHER_ROLE, ANOTHER_ADMIN); - - this.role = { id: ANOTHER_ADMIN }; - await this.manager.$_grantRole(this.role.id, this.user, 0, 0); - }); - - describe('#grantRole', function () { - describe('restrictions', function () { - beforeEach('set method and args', function () { - const args = [ANOTHER_ROLE, this.other.address, 0]; - const method = this.manager.interface.getFunction('grantRole(uint64,address,uint32)'); - this.calldata = this.manager.interface.encodeFunctionData(method, args); - }); - - shouldBehaveLikeRoleAdminOperation(ANOTHER_ADMIN); - }); - - it('reverts when granting PUBLIC_ROLE', async function () { - await expect(this.manager.connect(this.admin).grantRole(this.roles.PUBLIC.id, this.user, 0)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') - .withArgs(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.increaseBy.timestamp(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', - ]); - - this.txResponse = await this.manager - .connect(this.admin) - .grantRole(ANOTHER_ROLE, this.user, this.executionDelay); - this.delay = this.grantDelay; // For testAsDelay - }); - - testAsDelay('grant', { - before: function self() { - self.mineDelay = true; - - it('does not grant role to the user yet', async function () { - const timestamp = await time.clockFromReceipt.timestamp(this.txResponse); - await expect(this.txResponse) - .to.emit(this.manager, 'RoleGranted') - .withArgs(ANOTHER_ROLE, this.user, this.executionDelay, timestamp + this.grantDelay, true); - - // Access is correctly stored - const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); - expect(access[0]).to.equal(timestamp + this.grantDelay); // inEffectSince - expect(access[1]).to.equal(this.executionDelay); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // pendingDelayEffect - - // Not in effect yet - const currentTimestamp = await time.clock.timestamp(); - expect(currentTimestamp).to.be.lt(access[0]); - expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ - false, - this.executionDelay.toString(), - ]); - }); - }, - after: function self() { - self.mineDelay = true; - - it('grants role to the user', async function () { - const timestamp = await time.clockFromReceipt.timestamp(this.txResponse); - await expect(this.txResponse) - .to.emit(this.manager, 'RoleGranted') - .withArgs(ANOTHER_ROLE, this.user, this.executionDelay, timestamp + this.grantDelay, true); - - // Access is correctly stored - const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); - expect(access[0]).to.equal(timestamp + this.grantDelay); // inEffectSince - expect(access[1]).to.equal(this.executionDelay); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // pendingDelayEffect - - // Already in effect - const currentTimestamp = await time.clock.timestamp(); - expect(currentTimestamp).to.equal(access[0]); - expect(await this.manager.hasRole(ANOTHER_ROLE, this.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.increaseBy.timestamp(MINSETBACK); - }); - - it('immediately grants the role to the user', async function () { - const executionDelay = time.duration.days(6); - expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ - false, - '0', - ]); - const txResponse = await this.manager - .connect(this.admin) - .grantRole(ANOTHER_ROLE, this.user, executionDelay); - const grantedAt = await time.clockFromReceipt.timestamp(txResponse); - await expect(txResponse) - .to.emit(this.manager, 'RoleGranted') - .withArgs(ANOTHER_ROLE, this.user, executionDelay, grantedAt, true); - - // Access is correctly stored - const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); - expect(access[0]).to.equal(grantedAt); // inEffectSince - expect(access[1]).to.equal(executionDelay); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // pendingDelayEffect - - // Already in effect - const currentTimestamp = await time.clock.timestamp(); - expect(currentTimestamp).to.equal(access[0]); - expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ - true, - 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, this.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.increaseBy.timestamp(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 + 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 txResponse = await this.manager - .connect(this.admin) - .grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay); - const timestamp = await time.clockFromReceipt.timestamp(txResponse); - - await expect(txResponse) - .to.emit(this.manager, 'RoleGranted') - .withArgs(ANOTHER_ROLE, this.user, this.newExecutionDelay, timestamp, false); - - // Access is correctly stored - const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); - expect(access[0]).to.equal(this.oldAccess[0]); // inEffectSince - expect(access[1]).to.equal(this.newExecutionDelay); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // pendingDelayEffect - - // Already in effect - expect(await this.manager.hasRole(ANOTHER_ROLE, this.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 - time.duration.days(4); - this.txResponse = await this.manager - .connect(this.admin) - .grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay); - this.grantTimestamp = await time.clockFromReceipt.timestamp(this.txResponse); - - this.delay = this.previousExecutionDelay - this.newExecutionDelay; // For testAsDelay - }); - - it('emits event', async function () { - await expect(this.txResponse) - .to.emit(this.manager, 'RoleGranted') - .withArgs(ANOTHER_ROLE, this.user, this.newExecutionDelay, this.grantTimestamp + this.delay, false); - }); - - testAsDelay('execution delay effect', { - before: function self() { - self.mineDelay = true; - - it('does not change the execution delay yet', async function () { - // Access is correctly stored - const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); - expect(access[0]).to.equal(this.oldAccess[0]); // inEffectSince - expect(access[1]).to.equal(this.previousExecutionDelay); // currentDelay - expect(access[2]).to.equal(this.newExecutionDelay); // pendingDelay - expect(access[3]).to.equal(this.grantTimestamp + this.delay); // pendingDelayEffect - - // Not in effect yet - expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ - true, - this.previousExecutionDelay.toString(), - ]); - }); - }, - after: function self() { - self.mineDelay = true; - - it('changes the execution delay', async function () { - // Access is correctly stored - const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); - - expect(access[0]).to.equal(this.oldAccess[0]); // inEffectSince - expect(access[1]).to.equal(this.newExecutionDelay); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // pendingDelayEffect - - // Already in effect - expect(await this.manager.hasRole(ANOTHER_ROLE, this.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.increaseBy.timestamp(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 + 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 txResponse = await this.manager - .connect(this.admin) - .grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay); - const timestamp = await time.clockFromReceipt.timestamp(txResponse); - - await expect(txResponse) - .to.emit(this.manager, 'RoleGranted') - .withArgs(ANOTHER_ROLE, this.user, this.newExecutionDelay, timestamp, false); - - // Access is correctly stored - const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); - expect(access[0]).to.equal(this.oldAccess[0]); // inEffectSince - expect(access[1]).to.equal(this.newExecutionDelay); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // pendingDelayEffect - - // Already in effect - expect(await this.manager.hasRole(ANOTHER_ROLE, this.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 - time.duration.days(4); - this.txResponse = await this.manager - .connect(this.admin) - .grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay); - this.grantTimestamp = await time.clockFromReceipt.timestamp(this.txResponse); - - this.delay = this.previousExecutionDelay - this.newExecutionDelay; // For testAsDelay - }); - - it('emits event', async function () { - await expect(this.txResponse) - .to.emit(this.manager, 'RoleGranted') - .withArgs(ANOTHER_ROLE, this.user, this.newExecutionDelay, this.grantTimestamp + this.delay, false); - }); - - testAsDelay('execution delay effect', { - before: function self() { - self.mineDelay = true; - - it('does not change the execution delay yet', async function () { - // Access is correctly stored - const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); - expect(access[0]).to.equal(this.oldAccess[0]); // inEffectSince - expect(access[1]).to.equal(this.previousExecutionDelay); // currentDelay - expect(access[2]).to.equal(this.newExecutionDelay); // pendingDelay - expect(access[3]).to.equal(this.grantTimestamp + this.delay); // pendingDelayEffect - - // Not in effect yet - expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ - true, - this.previousExecutionDelay.toString(), - ]); - }); - }, - after: function self() { - self.mineDelay = true; - - it('changes the execution delay', async function () { - // Access is correctly stored - const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); - - expect(access[0]).to.equal(this.oldAccess[0]); // inEffectSince - expect(access[1]).to.equal(this.newExecutionDelay); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // pendingDelayEffect - - // Already in effect - expect(await this.manager.hasRole(ANOTHER_ROLE, this.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 args = [ANOTHER_ROLE, this.other.address]; - const method = this.manager.interface.getFunction('revokeRole(uint64,address)'); - this.calldata = this.manager.interface.encodeFunctionData(method, args); - - // 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, this.user, this.grantDelay, 0); - - this.delay = this.grantDelay; // For testAsDelay - }); - - testAsDelay('grant', { - before: function self() { - self.mineDelay = true; - - it('revokes a granted role that will take effect in the future', async function () { - expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ - false, - '0', - ]); - - await expect(this.manager.connect(this.admin).revokeRole(ANOTHER_ROLE, this.user)) - .to.emit(this.manager, 'RoleRevoked') - .withArgs(ANOTHER_ROLE, this.user); - - expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ - false, - '0', - ]); - - const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); - expect(access[0]).to.equal(0n); // inRoleSince - expect(access[1]).to.equal(0n); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // effect - }); - }, - after: function self() { - self.mineDelay = true; - - it('revokes a granted role that already took effect', async function () { - expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ - true, - '0', - ]); - - await expect(this.manager.connect(this.admin).revokeRole(ANOTHER_ROLE, this.user)) - .to.emit(this.manager, 'RoleRevoked') - .withArgs(ANOTHER_ROLE, this.user); - - expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ - false, - '0', - ]); - - const access = await this.manager.getAccess(ANOTHER_ROLE, this.user); - expect(access[0]).to.equal(0n); // inRoleSince - expect(access[1]).to.equal(0n); // currentDelay - expect(access[2]).to.equal(0n); // pendingDelay - expect(access[3]).to.equal(0n); // effect - }); - }, - }); - }); - - describe('when role has not been granted', function () { - it('has no effect', async function () { - expect(await this.manager.hasRole(this.roles.SOME.id, this.user).then(formatAccess)).to.be.deep.equal([ - false, - '0', - ]); - await expect(this.manager.connect(this.roleAdmin).revokeRole(this.roles.SOME.id, this.user)).to.not.emit( - this.manager, - 'RoleRevoked', - ); - expect(await this.manager.hasRole(this.roles.SOME.id, this.user).then(formatAccess)).to.be.deep.equal([ - false, - '0', - ]); - }); - }); - - it('reverts revoking PUBLIC_ROLE', async function () { - await expect(this.manager.connect(this.admin).revokeRole(this.roles.PUBLIC.id, this.user)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') - .withArgs(this.roles.PUBLIC.id); - }); - }); - }); - - describe('self role operations', function () { - describe('#renounceRole', function () { - beforeEach('grant role', async function () { - this.role = { id: 783164n }; - this.caller = this.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', - ]); - await expect(this.manager.connect(this.caller).renounceRole(this.role.id, this.caller)) - .to.emit(this.manager, 'RoleRevoked') - .withArgs(this.role.id, 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 expect(this.manager.connect(this.caller).renounceRole(this.roles.PUBLIC.id, this.caller)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedRole') - .withArgs(this.roles.PUBLIC.id); - }); - - it('reverts if renouncing with bad caller confirmation', async function () { - await expect( - this.manager.connect(this.caller).renounceRole(this.role.id, this.other), - ).to.be.revertedWithCustomError(this.manager, 'AccessManagerBadConfirmation'); - }); - }); - }); - }); - }); - - describe('access managed self operations', function () { - describe('when calling a restricted target function', function () { - const method = 'fnRestricted()'; - - beforeEach('set required role', async function () { - this.role = { id: 785913n }; - await this.manager.$_setTargetFunctionRole( - this.manager, - this.manager[method].getFragment().selector, - this.role.id, - ); - }); - - describe('restrictions', function () { - beforeEach('set method and args', function () { - this.caller = this.user; - this.calldata = this.manager.interface.encodeFunctionData(method, []); - }); - - shouldBehaveLikeASelfRestrictedOperation(); - }); - - it('succeeds called by a role member', async function () { - await this.manager.$_grantRole(this.role.id, this.user, 0, 0); - - await expect(this.manager.connect(this.user)[method]()) - .to.emit(this.manager, 'CalledRestricted') - .withArgs(this.user); - }); - }); - - describe('when calling a non-restricted target function', function () { - const method = 'fnUnrestricted()'; - - beforeEach('set required role', async function () { - this.role = { id: 879435n }; - await this.manager.$_setTargetFunctionRole( - this.manager, - this.manager[method].getFragment().selector, - this.role.id, - ); - }); - - it('succeeds called by anyone', async function () { - await expect(this.manager.connect(this.user)[method]()) - .to.emit(this.manager, 'CalledUnrestricted') - .withArgs(this.user); - }); - }); - }); - - describe('access managed target operations', function () { - describe('when calling a restricted target function', function () { - const method = 'fnRestricted()'; - - beforeEach('set required role', async function () { - this.role = { id: 3597243n }; - await this.manager.$_setTargetFunctionRole( - this.target, - this.target[method].getFragment().selector, - this.role.id, - ); - }); - - describe('restrictions', function () { - beforeEach('set method and args', function () { - this.caller = this.user; - this.calldata = this.target.interface.encodeFunctionData(method, []); - }); - - shouldBehaveLikeAManagedRestrictedOperation(); - }); - - it('succeeds called by a role member', async function () { - await this.manager.$_grantRole(this.role.id, this.user, 0, 0); - - await expect(this.target.connect(this.user)[method]()) - .to.emit(this.target, 'CalledRestricted') - .withArgs(this.user); - }); - }); - - describe('when calling a non-restricted target function', function () { - const method = 'fnUnrestricted()'; - - beforeEach('set required role', async function () { - this.role = { id: 879435n }; - await this.manager.$_setTargetFunctionRole( - this.target, - this.target[method].getFragment().selector, - this.role.id, - ); - }); - - it('succeeds called by anyone', async function () { - await expect(this.target.connect(this.user)[method]()) - .to.emit(this.target, 'CalledUnrestricted') - .withArgs(this.user); - }); - }); - }); - - describe('#schedule', function () { - beforeEach('set target function role', async function () { - this.method = this.target.fnRestricted.getFragment(); - this.role = { id: 498305n }; - this.caller = this.user; - - await this.manager.$_setTargetFunctionRole(this.target, this.method.selector, this.role.id); - await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay - - this.calldata = this.target.interface.encodeFunctionData(this.method, []); - this.delay = time.duration.weeks(2); - }); - - describe('restrictions', function () { - testAsCanCall({ - closed() { - it('reverts as AccessManagerUnauthorizedCall', async function () { - const { schedule } = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay: this.delay, - }); - await expect(schedule()) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.target, 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 () { - const { schedule } = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay: this.delay, - }); - await expect(schedule()) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); - }); - }, - }, - callerIsNotTheManager: { - publicRoleIsRequired() { - it('reverts as AccessManagerUnauthorizedCall', async function () { - // prepareOperation is not used here because it alters the next block timestamp - await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); - }); - }, - specificRoleIsRequired: { - requiredRoleIsGranted: { - roleGrantingIsDelayed: { - callerHasAnExecutionDelay: { - beforeGrantDelay() { - it('reverts as AccessManagerUnauthorizedCall', async function () { - // prepareOperation is not used here because it alters the next block timestamp - await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); - }); - }, - afterGrantDelay() { - it('succeeds', async function () { - // prepareOperation is not used here because it alters the next block timestamp - await this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48); - }); - }, - }, - callerHasNoExecutionDelay: { - beforeGrantDelay() { - it('reverts as AccessManagerUnauthorizedCall', async function () { - // prepareOperation is not used here because it alters the next block timestamp - await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); - }); - }, - afterGrantDelay() { - it('reverts as AccessManagerUnauthorizedCall', async function () { - // prepareOperation is not used here because it alters the next block timestamp - await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); - }); - }, - }, - }, - roleGrantingIsNotDelayed: { - callerHasAnExecutionDelay() { - it('succeeds', async function () { - const { schedule } = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay: this.delay, - }); - - await schedule(); - }); - }, - callerHasNoExecutionDelay() { - it('reverts as AccessManagerUnauthorizedCall', async function () { - // prepareOperation is not used here because it alters the next block timestamp - await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); - }); - }, - }, - }, - requiredRoleIsNotGranted() { - it('reverts as AccessManagerUnauthorizedCall', async function () { - const { schedule } = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay: this.delay, - }); - await expect(schedule()) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.target, 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, schedule } = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay: this.delay, - }); - - const txResponse = await schedule(); - - expect(await this.manager.getSchedule(operationId)).to.equal(scheduledAt + this.delay); - await expect(txResponse) - .to.emit(this.manager, 'OperationScheduled') - .withArgs(operationId, '1', scheduledAt + this.delay, this.caller, this.target, 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 txResponse = await this.manager.connect(this.caller).schedule(this.target, this.calldata, 0); - const scheduledAt = await time.clockFromReceipt.timestamp(txResponse); - - const operationId = await this.manager.hashOperation(this.caller, this.target, this.calldata); - - expect(await this.manager.getSchedule(operationId)).to.equal(scheduledAt + executionDelay); - await expect(txResponse) - .to.emit(this.manager, 'OperationScheduled') - .withArgs(operationId, '1', scheduledAt + executionDelay, this.caller, this.target, this.calldata); - }); - - it('increases the nonce of an operation scheduled more than once', async function () { - // Setup and check initial nonce - const expectedOperationId = hashOperation(this.caller, this.target, this.calldata); - expect(await this.manager.getNonce(expectedOperationId)).to.equal('0'); - - // Schedule - const op1 = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay: this.delay, - }); - await expect(op1.schedule()) - .to.emit(this.manager, 'OperationScheduled') - .withArgs(op1.operationId, 1n, op1.scheduledAt + this.delay, this.caller, this.target, this.calldata); - expect(expectedOperationId).to.equal(op1.operationId); - - // Consume - await time.increaseBy.timestamp(this.delay); - await this.manager.$_consumeScheduledOp(expectedOperationId); - - // Check nonce - expect(await this.manager.getNonce(expectedOperationId)).to.equal('1'); - - // Schedule again - const op2 = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay: this.delay, - }); - await expect(op2.schedule()) - .to.emit(this.manager, 'OperationScheduled') - .withArgs(op2.operationId, 2n, op2.scheduledAt + this.delay, this.caller, this.target, this.calldata); - expect(expectedOperationId).to.equal(op2.operationId); - - // Check final nonce - expect(await this.manager.getNonce(expectedOperationId)).to.equal('2'); - }); - - it('reverts if the specified execution date is before the current timestamp + caller execution delay', async function () { - const executionDelay = time.duration.weeks(1) + this.delay; - await this.manager.$_grantRole(this.role.id, this.caller, 0, executionDelay); - - const { schedule } = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay: this.delay, - }); - - await expect(schedule()) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); - }); - - it('reverts if an operation is already schedule', async function () { - const op1 = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay: this.delay, - }); - - await op1.schedule(); - - const op2 = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay: this.delay, - }); - - await expect(op2.schedule()) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerAlreadyScheduled') - .withArgs(op1.operationId); - }); - - it('panics scheduling calldata with less than 4 bytes', async function () { - const calldata = '0x1234'; // 2 bytes - - // Managed contract - const op1 = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: calldata, - delay: this.delay, - }); - await expect(op1.schedule()).to.be.revertedWithoutReason(); - - // Manager contract - const op2 = await prepareOperation(this.manager, { - caller: this.caller, - target: this.manager, - calldata: calldata, - delay: this.delay, - }); - await expect(op2.schedule()).to.be.revertedWithoutReason(); - }); - - it('reverts scheduling an unknown operation to the manager', async function () { - const calldata = '0x12345678'; - - const { schedule } = await prepareOperation(this.manager, { - caller: this.caller, - target: this.manager, - calldata, - delay: this.delay, - }); - - await expect(schedule()) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.manager, calldata); - }); - }); - - describe('#execute', function () { - beforeEach('set target function role', async function () { - this.method = this.target.fnRestricted.getFragment(); - this.role = { id: 9825430n }; - this.caller = this.user; - - await this.manager.$_setTargetFunctionRole(this.target, this.method.selector, this.role.id); - await this.manager.$_grantRole(this.role.id, this.caller, 0, 0); - - this.calldata = this.target.interface.encodeFunctionData(this.method, []); - }); - - describe('restrictions', function () { - testAsCanCall({ - closed() { - it('reverts as AccessManagerUnauthorizedCall', async function () { - await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); - }); - }, - open: { - callerIsTheManager: { - executing() { - it('succeeds', async function () { - await this.manager.connect(this.caller).execute(this.target, this.calldata); - }); - }, - notExecuting() { - it('reverts as AccessManagerUnauthorizedCall', async function () { - await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); - }); - }, - }, - callerIsNotTheManager: { - publicRoleIsRequired() { - it('succeeds', async function () { - await this.manager.connect(this.caller).execute(this.target, this.calldata); - }); - }, - specificRoleIsRequired: { - requiredRoleIsGranted: { - roleGrantingIsDelayed: { - callerHasAnExecutionDelay: { - beforeGrantDelay() { - it('reverts as AccessManagerUnauthorizedCall', async function () { - await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); - }); - }, - afterGrantDelay: function self() { - self.mineDelay = true; - - beforeEach('define schedule delay', function () { - this.scheduleIn = time.duration.days(21); // For testAsSchedulableOperation - }); - - testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); - }, - }, - callerHasNoExecutionDelay: { - beforeGrantDelay() { - it('reverts as AccessManagerUnauthorizedCall', async function () { - await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.target, this.calldata.substring(0, 10)); - }); - }, - afterGrantDelay: function self() { - self.mineDelay = true; - - it('succeeds', async function () { - await this.manager.connect(this.caller).execute(this.target, this.calldata); - }); - }, - }, - }, - roleGrantingIsNotDelayed: { - callerHasAnExecutionDelay() { - beforeEach('define schedule delay', function () { - this.scheduleIn = time.duration.days(15); // For testAsSchedulableOperation - }); - - testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE); - }, - callerHasNoExecutionDelay() { - it('succeeds', async function () { - await this.manager.connect(this.caller).execute(this.target, this.calldata); - }); - }, - }, - }, - requiredRoleIsNotGranted() { - it('reverts as AccessManagerUnauthorizedCall', async function () { - await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.caller, this.target, 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, schedule } = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay, - }); - await schedule(); - await time.increaseBy.timestamp(delay); - await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) - .to.emit(this.manager, 'OperationExecuted') - .withArgs(operationId, 1n); - - expect(await this.manager.getSchedule(operationId)).to.equal(0n); - }); - - 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, schedule } = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay, - }); - await schedule(); - - // remove the execution delay - await this.manager.$_grantRole(this.role.id, this.caller, 0, 0); - - await time.increaseBy.timestamp(delay); - await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) - .to.emit(this.manager, 'OperationExecuted') - .withArgs(operationId, 1n); - - expect(await this.manager.getSchedule(operationId)).to.equal(0n); - }); - - it('keeps the original _executionId after finishing the call', async function () { - const executionIdBefore = await ethers.provider.getStorage(this.manager, EXECUTION_ID_STORAGE_SLOT); - await this.manager.connect(this.caller).execute(this.target, this.calldata); - const executionIdAfter = await ethers.provider.getStorage(this.manager, EXECUTION_ID_STORAGE_SLOT); - expect(executionIdBefore).to.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, schedule } = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay, - }); - await schedule(); - await time.increaseBy.timestamp(delay); - await this.manager.connect(this.caller).execute(this.target, this.calldata); - await expect(this.manager.connect(this.caller).execute(this.target, this.calldata)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerNotScheduled') - .withArgs(operationId); - }); - }); - - describe('#consumeScheduledOp', function () { - beforeEach('define scheduling parameters', async function () { - const method = this.target.fnRestricted.getFragment(); - this.caller = await ethers.getSigner(this.target.target); - await impersonate(this.caller.address); - this.calldata = this.target.interface.encodeFunctionData(method, []); - this.role = { id: 9834983n }; - - await this.manager.$_setTargetFunctionRole(this.target, method.selector, this.role.id); - await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay - - this.scheduleIn = time.duration.hours(10); // For testAsSchedulableOperation - }); - - describe('when caller is not consuming scheduled operation', function () { - beforeEach('set consuming false', async function () { - await this.target.setIsConsumingScheduledOp(false, ethers.toBeHex(CONSUMING_SCHEDULE_STORAGE_SLOT, 32)); - }); - - it('reverts as AccessManagerUnauthorizedConsume', async function () { - await expect(this.manager.connect(this.caller).consumeScheduledOp(this.caller, this.calldata)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedConsume') - .withArgs(this.caller); - }); - }); - - describe('when caller is consuming scheduled operation', function () { - beforeEach('set consuming true', async function () { - await this.target.setIsConsumingScheduledOp(true, ethers.toBeHex(CONSUMING_SCHEDULE_STORAGE_SLOT, 32)); - }); - - testAsSchedulableOperation({ - scheduled: { - before() { - it('reverts as AccessManagerNotReady', async function () { - await expect(this.manager.connect(this.caller).consumeScheduledOp(this.caller, this.calldata)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerNotReady') - .withArgs(this.operationId); - }); - }, - after() { - it('consumes the scheduled operation and resets timepoint', async function () { - expect(await this.manager.getSchedule(this.operationId)).to.equal(this.scheduledAt + this.scheduleIn); - - await expect(this.manager.connect(this.caller).consumeScheduledOp(this.caller, this.calldata)) - .to.emit(this.manager, 'OperationExecuted') - .withArgs(this.operationId, 1n); - expect(await this.manager.getSchedule(this.operationId)).to.equal(0n); - }); - }, - expired() { - it('reverts as AccessManagerExpired', async function () { - await expect(this.manager.connect(this.caller).consumeScheduledOp(this.caller, this.calldata)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerExpired') - .withArgs(this.operationId); - }); - }, - }, - notScheduled() { - it('reverts as AccessManagerNotScheduled', async function () { - await expect(this.manager.connect(this.caller).consumeScheduledOp(this.caller, this.calldata)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerNotScheduled') - .withArgs(this.operationId); - }); - }, - }); - }); - }); - - describe('#cancelScheduledOp', function () { - beforeEach('setup scheduling', async function () { - this.method = this.target.fnRestricted.getFragment(); - this.caller = this.roles.SOME.members[0]; - await this.manager.$_setTargetFunctionRole(this.target, this.method.selector, this.roles.SOME.id); - await this.manager.$_grantRole(this.roles.SOME.id, this.caller, 0, 1); // nonzero execution delay - - this.calldata = this.target.interface.encodeFunctionData(this.method, []); - this.scheduleIn = time.duration.days(10); // For testAsSchedulableOperation - }); - - testAsSchedulableOperation({ - scheduled: { - before() { - describe('when caller is the scheduler', function () { - it('succeeds', async function () { - await this.manager.connect(this.caller).cancel(this.caller, this.target, this.calldata); - }); - }); - - describe('when caller is an admin', function () { - it('succeeds', async function () { - await this.manager.connect(this.roles.ADMIN.members[0]).cancel(this.caller, this.target, this.calldata); - }); - }); - - describe('when caller is the role guardian', function () { - it('succeeds', async function () { - await this.manager - .connect(this.roles.SOME_GUARDIAN.members[0]) - .cancel(this.caller, this.target, this.calldata); - }); - }); - - describe('when caller is any other account', function () { - it('reverts as AccessManagerUnauthorizedCancel', async function () { - await expect(this.manager.connect(this.other).cancel(this.caller, this.target, this.calldata)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCancel') - .withArgs(this.other, this.caller, this.target, this.method.selector); - }); - }); - }, - after() { - it('succeeds', async function () { - await this.manager.connect(this.caller).cancel(this.caller, this.target, this.calldata); - }); - }, - expired() { - it('succeeds', async function () { - await this.manager.connect(this.caller).cancel(this.caller, this.target, this.calldata); - }); - }, - }, - notScheduled() { - it('reverts as AccessManagerNotScheduled', async function () { - await expect(this.manager.cancel(this.caller, this.target, this.calldata)) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerNotScheduled') - .withArgs(this.operationId); - }); - }, - }); - - it('cancels an operation and resets schedule', async function () { - const { operationId, schedule } = await prepareOperation(this.manager, { - caller: this.caller, - target: this.target, - calldata: this.calldata, - delay: this.scheduleIn, - }); - await schedule(); - await expect(this.manager.connect(this.caller).cancel(this.caller, this.target, this.calldata)) - .to.emit(this.manager, 'OperationCanceled') - .withArgs(operationId, 1n); - expect(await this.manager.getSchedule(operationId)).to.equal('0'); - }); - }); - - describe('with Ownable target contract', function () { - const roleId = 1n; - - beforeEach(async function () { - this.ownable = await ethers.deployContract('$Ownable', [this.manager]); - - // add user to role - await this.manager.$_grantRole(roleId, this.user, 0, 0); - }); - - it('initial state', async function () { - expect(await this.ownable.owner()).to.equal(this.manager); - }); - - describe('Contract is closed', function () { - beforeEach(async function () { - await this.manager.$_setTargetClosed(this.ownable, true); - }); - - it('directly call: reverts', async function () { - await expect(this.ownable.connect(this.user).$_checkOwner()) - .to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount') - .withArgs(this.user); - }); - - it('relayed call (with role): reverts', async function () { - await expect( - this.manager.connect(this.user).execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector), - ) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.user, this.ownable, this.ownable.$_checkOwner.getFragment().selector); - }); - - it('relayed call (without role): reverts', async function () { - await expect( - this.manager.connect(this.other).execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector), - ) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.other, this.ownable, this.ownable.$_checkOwner.getFragment().selector); - }); - }); - - describe('Contract is managed', function () { - describe('function is open to specific role', function () { - beforeEach(async function () { - await this.manager.$_setTargetFunctionRole( - this.ownable, - this.ownable.$_checkOwner.getFragment().selector, - roleId, - ); - }); - - it('directly call: reverts', async function () { - await expect(this.ownable.connect(this.user).$_checkOwner()) - .to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount') - .withArgs(this.user); - }); - - it('relayed call (with role): success', async function () { - await this.manager.connect(this.user).execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector); - }); - - it('relayed call (without role): reverts', async function () { - await expect( - this.manager.connect(this.other).execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector), - ) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall') - .withArgs(this.other, this.ownable, this.ownable.$_checkOwner.getFragment().selector); - }); - }); - - describe('function is open to public role', function () { - beforeEach(async function () { - await this.manager.$_setTargetFunctionRole( - this.ownable, - this.ownable.$_checkOwner.getFragment().selector, - this.roles.PUBLIC.id, - ); - }); - - it('directly call: reverts', async function () { - await expect(this.ownable.connect(this.user).$_checkOwner()) - .to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount') - .withArgs(this.user); - }); - - it('relayed call (with role): success', async function () { - await this.manager.connect(this.user).execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector); - }); - - it('relayed call (without role): success', async function () { - await this.manager - .connect(this.other) - .execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector); - }); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AuthorityUtils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AuthorityUtils.test.js deleted file mode 100644 index 465f617..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/access/manager/AuthorityUtils.test.js +++ /dev/null @@ -1,112 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { MAX_UINT32, MAX_UINT64 } = require('../../helpers/constants'); - -async function fixture() { - const [user, other] = await ethers.getSigners(); - - const mock = await ethers.deployContract('$AuthorityUtils'); - const notAuthorityMock = await ethers.deployContract('NotAuthorityMock'); - const authorityNoDelayMock = await ethers.deployContract('AuthorityNoDelayMock'); - const authorityDelayMock = await ethers.deployContract('AuthorityDelayMock'); - const authorityNoResponse = await ethers.deployContract('AuthorityNoResponse'); - - return { - user, - other, - mock, - notAuthorityMock, - authorityNoDelayMock, - authorityDelayMock, - authorityNoResponse, - }; -} - -describe('AuthorityUtils', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('canCallWithDelay', function () { - describe('when authority does not have a canCall function', function () { - beforeEach(async function () { - this.authority = this.notAuthorityMock; - }); - - it('returns (immediate = 0, delay = 0)', async function () { - const { immediate, delay } = await this.mock.$canCallWithDelay( - this.authority, - this.user, - this.other, - '0x12345678', - ); - expect(immediate).to.be.false; - expect(delay).to.equal(0n); - }); - }); - - describe('when authority has no delay', function () { - beforeEach(async function () { - this.authority = this.authorityNoDelayMock; - 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, - this.user, - this.other, - '0x12345678', - ); - expect(immediate).to.equal(this.immediate); - expect(delay).to.equal(0n); - }); - }); - - describe('when authority replies with a delay', function () { - beforeEach(async function () { - this.authority = this.authorityDelayMock; - }); - - for (const immediate of [true, false]) { - for (const delay of [0n, 42n, MAX_UINT32]) { - it(`returns (immediate=${immediate}, delay=${delay})`, async function () { - await this.authority._setImmediate(immediate); - await this.authority._setDelay(delay); - const result = await this.mock.$canCallWithDelay(this.authority, this.user, this.other, '0x12345678'); - expect(result.immediate).to.equal(immediate); - expect(result.delay).to.equal(delay); - }); - } - } - - it('out of bound delay', async function () { - await this.authority._setImmediate(false); - await this.authority._setDelay(MAX_UINT64); // bigger than the expected uint32 - const result = await this.mock.$canCallWithDelay(this.authority, this.user, this.other, '0x12345678'); - expect(result.immediate).to.equal(false); - expect(result.delay).to.equal(0n); - }); - }); - - describe('when authority replies with empty data', function () { - beforeEach(async function () { - this.authority = this.authorityNoResponse; - }); - - it('returns (immediate = 0, delay = 0)', async function () { - const { immediate, delay } = await this.mock.$canCallWithDelay( - this.authority, - this.user, - this.other, - '0x12345678', - ); - expect(immediate).to.be.false; - expect(delay).to.equal(0n); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.behavior.js deleted file mode 100644 index eb10fbb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.behavior.js +++ /dev/null @@ -1,144 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { expect } = require('chai'); -const { impersonate } = require('../helpers/account'); -const { SIG_VALIDATION_SUCCESS, SIG_VALIDATION_FAILURE } = require('../helpers/erc4337'); -const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); - -function shouldBehaveLikeAccountCore() { - describe('entryPoint', function () { - it('should return the canonical entrypoint', async function () { - await this.mock.deploy(); - await expect(this.mock.entryPoint()).to.eventually.equal(entrypoint.v08); - }); - }); - - describe('validateUserOp', function () { - beforeEach(async function () { - await this.other.sendTransaction({ to: this.mock.target, value: ethers.parseEther('1') }); - await this.mock.deploy(); - this.userOp ??= {}; - }); - - it('should revert if the caller is not the canonical entrypoint', async function () { - // empty operation (does nothing) - const operation = await this.mock.createUserOp(this.userOp).then(op => this.signUserOp(op)); - - await expect(this.mock.connect(this.other).validateUserOp(operation.packed, operation.hash(), 0)) - .to.be.revertedWithCustomError(this.mock, 'AccountUnauthorized') - .withArgs(this.other); - }); - - describe('when the caller is the canonical entrypoint', function () { - beforeEach(async function () { - this.mockFromEntrypoint = this.mock.connect(await impersonate(entrypoint.v08.target)); - }); - - it('should return SIG_VALIDATION_SUCCESS if the signature is valid', async function () { - // empty operation (does nothing) - const operation = await this.mock.createUserOp(this.userOp).then(op => this.signUserOp(op)); - - expect(await this.mockFromEntrypoint.validateUserOp.staticCall(operation.packed, operation.hash(), 0)).to.eq( - SIG_VALIDATION_SUCCESS, - ); - }); - - it('should return SIG_VALIDATION_FAILURE if the signature is invalid', async function () { - // empty operation (does nothing) - const operation = await this.mock.createUserOp(this.userOp); - operation.signature = (await this.invalidSig?.()) ?? '0x00'; - - expect(await this.mockFromEntrypoint.validateUserOp.staticCall(operation.packed, operation.hash(), 0)).to.eq( - SIG_VALIDATION_FAILURE, - ); - }); - - it('should pay missing account funds for execution', async function () { - // empty operation (does nothing) - const operation = await this.mock.createUserOp(this.userOp).then(op => this.signUserOp(op)); - const value = 42n; - - await expect( - this.mockFromEntrypoint.validateUserOp(operation.packed, operation.hash(), value), - ).to.changeEtherBalances([this.mock, entrypoint.v08], [-value, value]); - }); - }); - }); - - describe('fallback', function () { - it('should receive ether', async function () { - await this.mock.deploy(); - const value = 42n; - - await expect(this.other.sendTransaction({ to: this.mock, value })).to.changeEtherBalances( - [this.other, this.mock], - [-value, value], - ); - }); - }); -} - -function shouldBehaveLikeAccountHolder() { - describe('onReceived', function () { - beforeEach(async function () { - await this.mock.deploy(); - }); - - shouldSupportInterfaces(['ERC1155Receiver']); - - describe('onERC1155Received', function () { - const ids = [1n, 2n, 3n]; - const values = [1000n, 2000n, 3000n]; - const data = '0x12345678'; - - beforeEach(async function () { - this.token = await ethers.deployContract('$ERC1155', ['https://somedomain.com/{id}.json']); - await this.token.$_mintBatch(this.other, ids, values, '0x'); - }); - - it('receives ERC1155 tokens from a single ID', async function () { - await this.token.connect(this.other).safeTransferFrom(this.other, this.mock, ids[0], values[0], data); - - await expect( - this.token.balanceOfBatch( - ids.map(() => this.mock), - ids, - ), - ).to.eventually.deep.equal(values.map((v, i) => (i == 0 ? v : 0n))); - }); - - it('receives ERC1155 tokens from a multiple IDs', async function () { - await expect( - this.token.balanceOfBatch( - ids.map(() => this.mock), - ids, - ), - ).to.eventually.deep.equal(ids.map(() => 0n)); - - await this.token.connect(this.other).safeBatchTransferFrom(this.other, this.mock, ids, values, data); - await expect( - this.token.balanceOfBatch( - ids.map(() => this.mock), - ids, - ), - ).to.eventually.deep.equal(values); - }); - }); - - describe('onERC721Received', function () { - const tokenId = 1n; - - beforeEach(async function () { - this.token = await ethers.deployContract('$ERC721', ['Some NFT', 'SNFT']); - await this.token.$_mint(this.other, tokenId); - }); - - it('receives an ERC721 token', async function () { - await this.token.connect(this.other).safeTransferFrom(this.other, this.mock, tokenId); - - await expect(this.token.ownerOf(tokenId)).to.eventually.equal(this.mock); - }); - }); - }); -} - -module.exports = { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder }; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.test.js deleted file mode 100644 index 2ccb81f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/Account.test.js +++ /dev/null @@ -1,48 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain } = require('../helpers/eip712'); -const { ERC4337Helper } = require('../helpers/erc4337'); -const { PackedUserOperation } = require('../helpers/eip712-types'); -const { NonNativeSigner } = require('../helpers/signers'); - -const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); -const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); -const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); - -async function fixture() { - // EOAs and environment - const [beneficiary, other] = await ethers.getSigners(); - const target = await ethers.deployContract('CallReceiverMock'); - - // ERC-4337 signer - const signer = new NonNativeSigner({ sign: hash => ({ serialized: hash }) }); - - // ERC-4337 account - const helper = new ERC4337Helper(); - const mock = await helper.newAccount('$AccountMock', ['Account', '1']); - - // ERC-4337 Entrypoint domain - const entrypointDomain = await getDomain(entrypoint.v08); - - // domain cannot be fetched using getDomain(mock) before the mock is deployed - const domain = { name: 'Account', version: '1', chainId: entrypointDomain.chainId, verifyingContract: mock.address }; - - const signUserOp = async userOp => - signer - .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) - .then(signature => Object.assign(userOp, { signature })); - - return { helper, mock, domain, signer, target, beneficiary, other, signUserOp }; -} - -describe('Account', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC1271({ erc7739: true }); - shouldBehaveLikeERC7821(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountECDSA.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountECDSA.test.js deleted file mode 100644 index e6bf27a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountECDSA.test.js +++ /dev/null @@ -1,52 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain } = require('../helpers/eip712'); -const { ERC4337Helper } = require('../helpers/erc4337'); -const { PackedUserOperation } = require('../helpers/eip712-types'); - -const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); -const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); -const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); - -async function fixture() { - // EOAs and environment - const [beneficiary, other] = await ethers.getSigners(); - const target = await ethers.deployContract('CallReceiverMock'); - - // ERC-4337 signer - const signer = ethers.Wallet.createRandom(); - - // ERC-4337 account - const helper = new ERC4337Helper(); - const mock = await helper.newAccount('$AccountECDSAMock', [signer, 'AccountECDSA', '1']); - - // ERC-4337 Entrypoint domain - const entrypointDomain = await getDomain(entrypoint.v08); - - // domain cannot be fetched using getDomain(mock) before the mock is deployed - const domain = { - name: 'AccountECDSA', - version: '1', - chainId: entrypointDomain.chainId, - verifyingContract: mock.address, - }; - - const signUserOp = userOp => - signer - .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) - .then(signature => Object.assign(userOp, { signature })); - - return { helper, mock, domain, signer, target, beneficiary, other, signUserOp }; -} - -describe('AccountECDSA', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC1271({ erc7739: true }); - shouldBehaveLikeERC7821(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.t.sol deleted file mode 100644 index f08193f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.t.sol +++ /dev/null @@ -1,97 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; -import {AccountERC7702Mock} from "@openzeppelin/contracts/mocks/account/AccountMock.sol"; -import {CallReceiverMock} from "@openzeppelin/contracts/mocks/CallReceiverMock.sol"; -import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; -import {ERC7579Utils, Execution, Mode, ModeSelector, ModePayload} from "@openzeppelin/contracts/account/utils/draft-ERC7579Utils.sol"; -import {ERC4337Utils, IEntryPointExtra} from "@openzeppelin/contracts/account/utils/draft-ERC4337Utils.sol"; -import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; -import {PackedUserOperation} from "@openzeppelin/contracts/interfaces/draft-IERC4337.sol"; -import {ERC7821} from "@openzeppelin/contracts/account/extensions/draft-ERC7821.sol"; - -contract AccountERC7702MockConstructor is AccountERC7702Mock { - constructor() EIP712("MyAccount", "1") {} -} - -contract AccountERC7702Test is Test { - using ERC7579Utils for *; - using ERC4337Utils for PackedUserOperation; - using Strings for *; - - uint256 private constant MAX_ETH = type(uint128).max; - - // Test accounts - CallReceiverMock private _target; - - // ERC-4337 signer - uint256 private _signerPrivateKey; - AccountERC7702MockConstructor private _signer; - - function setUp() public { - // Deploy target contract - _target = new CallReceiverMock(); - - // Setup signer - _signerPrivateKey = 0x1234; - _signer = AccountERC7702MockConstructor(payable(vm.addr(_signerPrivateKey))); - vm.deal(address(_signer), MAX_ETH); - - // Sign and attach delegation - vm.signAndAttachDelegation(address(new AccountERC7702MockConstructor()), _signerPrivateKey); - - // Setup entrypoint - vm.deal(address(ERC4337Utils.ENTRYPOINT_V08), MAX_ETH); - vm.etch(address(ERC4337Utils.ENTRYPOINT_V08), vm.readFileBinary("test/bin/EntryPoint070.bytecode")); - } - - function testExecuteBatch(uint256 argA, uint256 argB) public { - // Create the mode for batch execution - Mode mode = ERC7579Utils.CALLTYPE_BATCH.encodeMode( - ERC7579Utils.EXECTYPE_DEFAULT, - ModeSelector.wrap(0x00000000), - ModePayload.wrap(0x00000000) - ); - - Execution[] memory execution = new Execution[](2); - execution[0] = Execution({ - target: address(_target), - value: 1 ether, - callData: abi.encodeCall(CallReceiverMock.mockFunctionExtra, ()) - }); - execution[1] = Execution({ - target: address(_target), - value: 0, - callData: abi.encodeCall(CallReceiverMock.mockFunctionWithArgs, (argA, argB)) - }); - - // Pack the batch within a PackedUserOperation - PackedUserOperation[] memory ops = new PackedUserOperation[](1); - ops[0] = PackedUserOperation({ - sender: address(_signer), - nonce: 0, - initCode: bytes(""), - callData: abi.encodeCall(ERC7821.execute, (Mode.unwrap(mode), execution.encodeBatch())), - preVerificationGas: 100000, - accountGasLimits: bytes32(abi.encodePacked(uint128(100000), uint128(100000))), - gasFees: bytes32(abi.encodePacked(uint128(1000000), uint128(1000000))), - paymasterAndData: bytes(""), - signature: bytes("") - }); - (uint8 v, bytes32 r, bytes32 s) = vm.sign( - _signerPrivateKey, - IEntryPointExtra(address(ERC4337Utils.ENTRYPOINT_V08)).getUserOpHash(ops[0]) - ); - ops[0].signature = abi.encodePacked(r, s, v); - - // Expect the events to be emitted - vm.expectEmit(true, true, true, true); - emit CallReceiverMock.MockFunctionCalledExtra(address(_signer), 1 ether); - vm.expectEmit(true, true, true, true); - emit CallReceiverMock.MockFunctionCalledWithArgs(argA, argB); - - // Execute the batch - _signer.entryPoint().handleOps(ops, payable(makeAddr("beneficiary"))); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.test.js deleted file mode 100644 index d08a522..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7702.test.js +++ /dev/null @@ -1,52 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain } = require('../helpers/eip712'); -const { ERC4337Helper } = require('../helpers/erc4337'); -const { PackedUserOperation } = require('../helpers/eip712-types'); - -const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); -const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); -const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); - -async function fixture() { - // EOAs and environment - const [beneficiary, other] = await ethers.getSigners(); - const target = await ethers.deployContract('CallReceiverMock'); - - // ERC-4337 signer - const signer = ethers.Wallet.createRandom(ethers.provider); - - // ERC-4337 account - const helper = new ERC4337Helper(); - const mock = await helper.newAccount('$AccountERC7702Mock', ['AccountERC7702Mock', '1'], { erc7702signer: signer }); - - // ERC-4337 Entrypoint domain - const entrypointDomain = await getDomain(entrypoint.v08); - - // domain cannot be fetched using getDomain(mock) before the mock is deployed - const domain = { - name: 'AccountERC7702Mock', - version: '1', - chainId: entrypointDomain.chainId, - verifyingContract: mock.address, - }; - - const signUserOp = userOp => - signer - .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) - .then(signature => Object.assign(userOp, { signature })); - - return { helper, mock, domain, signer, target, beneficiary, other, signUserOp }; -} - -describe('AccountERC7702', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC1271({ erc7739: true }); - shouldBehaveLikeERC7821({ deployable: false }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7913.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7913.test.js deleted file mode 100644 index 297a5eb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountERC7913.test.js +++ /dev/null @@ -1,116 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain } = require('../helpers/eip712'); -const { ERC4337Helper } = require('../helpers/erc4337'); -const { NonNativeSigner, P256SigningKey, RSASHA256SigningKey } = require('../helpers/signers'); -const { PackedUserOperation } = require('../helpers/eip712-types'); - -const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); -const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); -const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); - -// Prepare signer in advance (RSA are long to initialize) -const signerECDSA = ethers.Wallet.createRandom(); -const signerP256 = new NonNativeSigner(P256SigningKey.random()); -const signerRSA = new NonNativeSigner(RSASHA256SigningKey.random()); - -// Minimal fixture common to the different signer verifiers -async function fixture() { - // EOAs and environment - const [beneficiary, other] = await ethers.getSigners(); - const target = await ethers.deployContract('CallReceiverMock'); - - // ERC-7913 verifiers - const verifierP256 = await ethers.deployContract('ERC7913P256Verifier'); - const verifierRSA = await ethers.deployContract('ERC7913RSAVerifier'); - - // ERC-4337 env - const helper = new ERC4337Helper(); - await helper.wait(); - const entrypointDomain = await getDomain(entrypoint.v08); - const domain = { name: 'AccountERC7913', version: '1', chainId: entrypointDomain.chainId }; // Missing verifyingContract, - - const makeMock = signer => - helper.newAccount('$AccountERC7913Mock', [signer, 'AccountERC7913', '1']).then(mock => { - domain.verifyingContract = mock.address; - return mock; - }); - - const signUserOp = function (userOp) { - return this.signer - .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) - .then(signature => Object.assign(userOp, { signature })); - }; - - return { - helper, - verifierP256, - verifierRSA, - domain, - target, - beneficiary, - other, - makeMock, - signUserOp, - }; -} - -describe('AccountERC7913', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - // Using ECDSA key as verifier - describe('ECDSA key', function () { - beforeEach(async function () { - this.signer = signerECDSA; - this.mock = await this.makeMock(this.signer.address); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC1271({ erc7739: true }); - shouldBehaveLikeERC7821(); - }); - - // Using P256 key with an ERC-7913 verifier - describe('P256 key', function () { - beforeEach(async function () { - this.signer = signerP256; - this.mock = await this.makeMock( - ethers.concat([ - this.verifierP256.target, - this.signer.signingKey.publicKey.qx, - this.signer.signingKey.publicKey.qy, - ]), - ); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC1271({ erc7739: true }); - shouldBehaveLikeERC7821(); - }); - - // Using RSA key with an ERC-7913 verifier - describe('RSA key', function () { - beforeEach(async function () { - this.signer = signerRSA; - this.mock = await this.makeMock( - ethers.concat([ - this.verifierRSA.target, - ethers.AbiCoder.defaultAbiCoder().encode( - ['bytes', 'bytes'], - [this.signer.signingKey.publicKey.e, this.signer.signingKey.publicKey.n], - ), - ]), - ); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC1271({ erc7739: true }); - shouldBehaveLikeERC7821(); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSigner.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSigner.test.js deleted file mode 100644 index 78011a3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSigner.test.js +++ /dev/null @@ -1,326 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain } = require('../helpers/eip712'); -const { ERC4337Helper } = require('../helpers/erc4337'); -const { NonNativeSigner, P256SigningKey, RSASHA256SigningKey, MultiERC7913SigningKey } = require('../helpers/signers'); -const { MAX_UINT64 } = require('../helpers/constants'); - -const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); -const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); -const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); -const { PackedUserOperation } = require('../helpers/eip712-types'); - -// Prepare signers in advance (RSA are long to initialize) -const signerECDSA1 = ethers.Wallet.createRandom(); -const signerECDSA2 = ethers.Wallet.createRandom(); -const signerECDSA3 = ethers.Wallet.createRandom(); -const signerECDSA4 = ethers.Wallet.createRandom(); // Unauthorized signer -const signerP256 = new NonNativeSigner(P256SigningKey.random()); -const signerRSA = new NonNativeSigner(RSASHA256SigningKey.random()); - -// Minimal fixture common to the different signer verifiers -async function fixture() { - // EOAs and environment - const [beneficiary, other] = await ethers.getSigners(); - const target = await ethers.deployContract('CallReceiverMock'); - - // ERC-7913 verifiers - const verifierP256 = await ethers.deployContract('ERC7913P256Verifier'); - const verifierRSA = await ethers.deployContract('ERC7913RSAVerifier'); - - // ERC-4337 env - const helper = new ERC4337Helper(); - await helper.wait(); - const entrypointDomain = await getDomain(entrypoint.v08); - const domain = { name: 'AccountMultiSigner', version: '1', chainId: entrypointDomain.chainId }; // Missing verifyingContract - - const makeMock = (signers, threshold) => - helper.newAccount('$AccountMultiSignerMock', [signers, threshold, 'AccountMultiSigner', '1']).then(mock => { - domain.verifyingContract = mock.address; - return mock; - }); - - // Sign user operations using MultiERC7913SigningKey - const signUserOp = function (userOp) { - return this.signer - .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) - .then(signature => Object.assign(userOp, { signature })); - }; - - const invalidSig = function () { - return this.signer.signMessage('invalid'); - }; - - return { - helper, - verifierP256, - verifierRSA, - domain, - target, - beneficiary, - other, - makeMock, - signUserOp, - invalidSig, - }; -} - -describe('AccountMultiSigner', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('Multi ECDSA signers with threshold=1', function () { - beforeEach(async function () { - this.signer = new NonNativeSigner(new MultiERC7913SigningKey([signerECDSA1])); - this.mock = await this.makeMock([signerECDSA1.address], 1); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC1271({ erc7739: true }); - shouldBehaveLikeERC7821(); - }); - - describe('Multi ECDSA signers with threshold=2', function () { - beforeEach(async function () { - this.signer = new NonNativeSigner(new MultiERC7913SigningKey([signerECDSA1, signerECDSA2])); - this.mock = await this.makeMock([signerECDSA1.address, signerECDSA2.address], 2); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC1271({ erc7739: true }); - shouldBehaveLikeERC7821(); - }); - - describe('Mixed signers with threshold=2', function () { - beforeEach(async function () { - // Create signers array with all three types - signerP256.bytes = ethers.concat([ - this.verifierP256.target, - signerP256.signingKey.publicKey.qx, - signerP256.signingKey.publicKey.qy, - ]); - - signerRSA.bytes = ethers.concat([ - this.verifierRSA.target, - ethers.AbiCoder.defaultAbiCoder().encode( - ['bytes', 'bytes'], - [signerRSA.signingKey.publicKey.e, signerRSA.signingKey.publicKey.n], - ), - ]); - - this.signer = new NonNativeSigner(new MultiERC7913SigningKey([signerECDSA1, signerP256, signerRSA])); - this.mock = await this.makeMock([signerECDSA1.address, signerP256.bytes, signerRSA.bytes], 2); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC1271({ erc7739: true }); - shouldBehaveLikeERC7821(); - }); - - describe('Signer management', function () { - beforeEach(async function () { - this.signer = new NonNativeSigner(new MultiERC7913SigningKey([signerECDSA1, signerECDSA2])); - this.mock = await this.makeMock([signerECDSA1.address, signerECDSA2.address], 1); - await this.mock.deploy(); - }); - - it('can add signers', async function () { - const signers = [signerECDSA3.address]; - - // Successfully adds a signer - const signersArrayBefore = await this.mock.getSigners(0, MAX_UINT64).then(s => s.map(ethers.getAddress)); - await expect(this.mock.$_addSigners(signers)) - .to.emit(this.mock, 'ERC7913SignerAdded') - .withArgs(signerECDSA3.address); - const signersArrayAfter = await this.mock.getSigners(0, MAX_UINT64).then(s => s.map(ethers.getAddress)); - expect(signersArrayAfter.length).to.equal(signersArrayBefore.length + 1); - expect(signersArrayAfter).to.include(ethers.getAddress(signerECDSA3.address)); - - // Reverts if the signer was already added - await expect(this.mock.$_addSigners(signers)) - .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913AlreadyExists') - .withArgs(...signers.map(s => s.toLowerCase())); - }); - - it('can remove signers', async function () { - const signers = [signerECDSA2.address]; - - // Successfully removes an already added signer - const signersArrayBefore = await this.mock.getSigners(0, MAX_UINT64).then(s => s.map(ethers.getAddress)); - await expect(this.mock.$_removeSigners(signers)) - .to.emit(this.mock, 'ERC7913SignerRemoved') - .withArgs(signerECDSA2.address); - const signersArrayAfter = await this.mock.getSigners(0, MAX_UINT64).then(s => s.map(ethers.getAddress)); - expect(signersArrayAfter.length).to.equal(signersArrayBefore.length - 1); - expect(signersArrayAfter).to.not.include(ethers.getAddress(signerECDSA2.address)); - - // Reverts removing a signer if it doesn't exist - await expect(this.mock.$_removeSigners(signers)) - .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913NonexistentSigner') - .withArgs(...signers.map(s => s.toLowerCase())); - - // Reverts if removing a signer makes the threshold unreachable - await expect(this.mock.$_removeSigners([signerECDSA1.address])) - .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913UnreachableThreshold') - .withArgs(0, 1); - }); - - it('can change threshold', async function () { - // Reachable threshold is set - await expect(this.mock.$_setThreshold(2)).to.emit(this.mock, 'ERC7913ThresholdSet'); - - // Unreachable threshold reverts - await expect(this.mock.$_setThreshold(3)) - .to.revertedWithCustomError(this.mock, 'MultiSignerERC7913UnreachableThreshold') - .withArgs(2, 3); - - // Zero threshold reverts - await expect(this.mock.$_setThreshold(0)).to.revertedWithCustomError( - this.mock, - 'MultiSignerERC7913ZeroThreshold', - ); - }); - - it('rejects invalid signer format', async function () { - const invalidSigner = '0x123456'; // Too short - - await expect(this.mock.$_addSigners([invalidSigner])) - .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913InvalidSigner') - .withArgs(invalidSigner); - }); - - it('can read signers and threshold', async function () { - await expect( - this.mock.getSigners(0, MAX_UINT64).then(s => s.map(ethers.getAddress)), - ).to.eventually.have.deep.members([signerECDSA1.address, signerECDSA2.address]); - - await expect(this.mock.threshold()).to.eventually.equal(1); - }); - - it('checks if an address is a signer', async function () { - // Should return true for authorized signers - await expect(this.mock.isSigner(signerECDSA1.address)).to.eventually.be.true; - await expect(this.mock.isSigner(signerECDSA2.address)).to.eventually.be.true; - - // Should return false for unauthorized signers - await expect(this.mock.isSigner(signerECDSA3.address)).to.eventually.be.false; - await expect(this.mock.isSigner(signerECDSA4.address)).to.eventually.be.false; - }); - }); - - describe('Signature validation', function () { - const TEST_MESSAGE = ethers.keccak256(ethers.toUtf8Bytes('Test message')); - - beforeEach(async function () { - // Set up mock with authorized signers - this.mock = await this.makeMock([signerECDSA1.address, signerECDSA2.address], 1); - await this.mock.deploy(); - }); - - it('rejects signatures from unauthorized signers', async function () { - // Create signatures including an unauthorized signer - const authorizedSignature = await signerECDSA1.signMessage(ethers.getBytes(TEST_MESSAGE)); - const unauthorizedSignature = await signerECDSA4.signMessage(ethers.getBytes(TEST_MESSAGE)); - - // Prepare signers and signatures arrays - const signers = [ - signerECDSA1.address, - signerECDSA4.address, // Unauthorized signer - ].sort((a, b) => (ethers.toBigInt(ethers.keccak256(a)) < ethers.toBigInt(ethers.keccak256(b)) ? -1 : 1)); - - const signatures = signers.map(signer => { - if (signer === signerECDSA1.address) return authorizedSignature; - return unauthorizedSignature; - }); - - // Encode the multi-signature - const multiSignature = ethers.AbiCoder.defaultAbiCoder().encode(['bytes[]', 'bytes[]'], [signers, signatures]); - - // Should fail because one signer is not authorized - await expect(this.mock.$_rawSignatureValidation(TEST_MESSAGE, multiSignature)).to.eventually.be.false; - }); - - it('rejects invalid signatures from authorized signers', async function () { - // Create a valid signature and an invalid one from authorized signers - const validSignature = await signerECDSA1.signMessage(ethers.getBytes(TEST_MESSAGE)); - const invalidSignature = await signerECDSA2.signMessage(ethers.toUtf8Bytes('Different message')); // Wrong message - - // Prepare signers and signatures arrays - const signers = [signerECDSA1.address, signerECDSA2.address].sort((a, b) => - ethers.toBigInt(ethers.keccak256(a)) < ethers.toBigInt(ethers.keccak256(b)) ? -1 : 1, - ); - - const signatures = signers.map(signer => { - if (signer === signerECDSA1.address) return validSignature; - return invalidSignature; - }); - - // Encode the multi-signature - const multiSignature = ethers.AbiCoder.defaultAbiCoder().encode(['bytes[]', 'bytes[]'], [signers, signatures]); - - // Should fail because one signature is invalid - await expect(this.mock.$_rawSignatureValidation(TEST_MESSAGE, multiSignature)).to.eventually.be.false; - }); - - it('rejects signatures from unsorted signers', async function () { - // Create a valid signature and an invalid one from authorized signers - const validSignature1 = await signerECDSA1.signMessage(ethers.getBytes(TEST_MESSAGE)); - const validSignature2 = await signerECDSA2.signMessage(ethers.getBytes(TEST_MESSAGE)); - - // Prepare signers and signatures arrays - const signers = [signerECDSA1.address, signerECDSA2.address].sort((a, b) => - ethers.toBigInt(ethers.keccak256(a)) < ethers.toBigInt(ethers.keccak256(b)) ? -1 : 1, - ); - const unsortedSigners = signers.reverse(); - const signatures = unsortedSigners.map(signer => { - if (signer === signerECDSA1.address) return validSignature1; - return validSignature2; - }); - - // Encode the multi-signature - const multiSignature = ethers.AbiCoder.defaultAbiCoder().encode( - ['bytes[]', 'bytes[]'], - [unsortedSigners, signatures], - ); - - // Should fail because signers are not sorted - await expect(this.mock.$_rawSignatureValidation(TEST_MESSAGE, multiSignature)).to.eventually.be.false; - }); - - it('rejects signatures when signers.length != signatures.length', async function () { - // Create a valid signature and an invalid one from authorized signers - const validSignature1 = await signerECDSA1.signMessage(ethers.getBytes(TEST_MESSAGE)); - - // Prepare signers and signatures arrays - const signers = [signerECDSA1.address, signerECDSA2.address]; - const signatures = [validSignature1]; - - // Encode the multi-signature - const multiSignature = ethers.AbiCoder.defaultAbiCoder().encode(['bytes[]', 'bytes[]'], [signers, signatures]); - - // Should fail because signers and signatures arrays have different lengths - await expect(this.mock.$_rawSignatureValidation(TEST_MESSAGE, multiSignature)).to.eventually.be.false; - }); - - it('rejects duplicated signers', async function () { - // Create a valid signature - const validSignature = await signerECDSA1.signMessage(ethers.getBytes(TEST_MESSAGE)); - - // Prepare signers and signatures arrays - const signers = [signerECDSA1.address, signerECDSA1.address]; - const signatures = [validSignature, validSignature]; - - // Encode the multi-signature - const multiSignature = ethers.AbiCoder.defaultAbiCoder().encode(['bytes[]', 'bytes[]'], [signers, signatures]); - - // Should fail because of duplicated signers - await expect(this.mock.$_rawSignatureValidation(TEST_MESSAGE, multiSignature)).to.eventually.be.false; - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSignerWeighted.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSignerWeighted.test.js deleted file mode 100644 index 5519d8a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountMultiSignerWeighted.test.js +++ /dev/null @@ -1,312 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain } = require('../helpers/eip712'); -const { ERC4337Helper } = require('../helpers/erc4337'); -const { NonNativeSigner, P256SigningKey, RSASHA256SigningKey, MultiERC7913SigningKey } = require('../helpers/signers'); -const { PackedUserOperation } = require('../helpers/eip712-types'); -const { MAX_UINT64 } = require('../helpers/constants'); - -const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); -const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); -const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); - -// Prepare signers in advance (RSA are long to initialize) -const signerECDSA1 = ethers.Wallet.createRandom(); -const signerECDSA2 = ethers.Wallet.createRandom(); -const signerECDSA3 = ethers.Wallet.createRandom(); -const signerECDSA4 = ethers.Wallet.createRandom(); -const signerP256 = new NonNativeSigner(P256SigningKey.random()); -const signerRSA = new NonNativeSigner(RSASHA256SigningKey.random()); - -// Minimal fixture common to the different signer verifiers -async function fixture() { - // EOAs and environment - const [beneficiary, other] = await ethers.getSigners(); - const target = await ethers.deployContract('CallReceiverMock'); - - // ERC-7913 verifiers - const verifierP256 = await ethers.deployContract('ERC7913P256Verifier'); - const verifierRSA = await ethers.deployContract('ERC7913RSAVerifier'); - - // ERC-4337 env - const helper = new ERC4337Helper(); - await helper.wait(); - const entrypointDomain = await getDomain(entrypoint.v08); - const domain = { name: 'AccountMultiSignerWeighted', version: '1', chainId: entrypointDomain.chainId }; // Missing verifyingContract - - const makeMock = (signers, weights, threshold) => - helper - .newAccount('$AccountMultiSignerWeightedMock', [signers, weights, threshold, 'AccountMultiSignerWeighted', '1']) - .then(mock => { - domain.verifyingContract = mock.address; - return mock; - }); - - // Sign user operations using NonNativeSigner with MultiERC7913SigningKey - const signUserOp = function (userOp) { - return this.signer - .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) - .then(signature => Object.assign(userOp, { signature })); - }; - - const invalidSig = function () { - return this.signer.signMessage('invalid'); - }; - - return { - helper, - verifierP256, - verifierRSA, - domain, - target, - beneficiary, - other, - makeMock, - signUserOp, - invalidSig, - }; -} - -describe('AccountMultiSignerWeighted', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('Weighted signers with equal weights (1, 1, 1) and threshold=2', function () { - beforeEach(async function () { - this.signer = new NonNativeSigner(new MultiERC7913SigningKey([signerECDSA1, signerECDSA3])); // 2 accounts, weight 1+1=2 - this.mock = await this.makeMock([signerECDSA1.address, signerECDSA2.address, signerECDSA3.address], [1, 1, 1], 2); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC1271({ erc7739: true }); - shouldBehaveLikeERC7821(); - }); - - describe('Weighted signers with varying weights (1, 2, 3) and threshold=3', function () { - beforeEach(async function () { - this.signer = new NonNativeSigner(new MultiERC7913SigningKey([signerECDSA1, signerECDSA2])); // 2 accounts, weight 1+2=3 - this.mock = await this.makeMock([signerECDSA1.address, signerECDSA2.address, signerECDSA3.address], [1, 2, 3], 3); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC1271({ erc7739: true }); - shouldBehaveLikeERC7821(); - }); - - describe('Mixed weighted signers with threshold=4', function () { - beforeEach(async function () { - // Create signers array with all three types - signerP256.bytes = ethers.concat([ - this.verifierP256.target, - signerP256.signingKey.publicKey.qx, - signerP256.signingKey.publicKey.qy, - ]); - - signerRSA.bytes = ethers.concat([ - this.verifierRSA.target, - ethers.AbiCoder.defaultAbiCoder().encode( - ['bytes', 'bytes'], - [signerRSA.signingKey.publicKey.e, signerRSA.signingKey.publicKey.n], - ), - ]); - - this.signer = new NonNativeSigner(new MultiERC7913SigningKey([signerP256, signerRSA])); // 2 accounts, weight 2+3=5 - this.mock = await this.makeMock( - [signerECDSA1.address, signerP256.bytes, signerRSA.bytes], - [1, 2, 3], - 4, // Requires at least signer2 + signer3, or all three signers - ); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC1271({ erc7739: true }); - shouldBehaveLikeERC7821(); - }); - - describe('Weight management', function () { - const signer1 = signerECDSA1.address; - const signer2 = signerECDSA2.address; - const signer3 = signerECDSA3.address; - const signer4 = signerECDSA4.address; - - beforeEach(async function () { - this.mock = await this.makeMock([signer1, signer2, signer3], [1, 2, 3], 4); - await this.mock.deploy(); - }); - - it('can get signer weights', async function () { - await expect(this.mock.signerWeight(signer1)).to.eventually.equal(1); - await expect(this.mock.signerWeight(signer2)).to.eventually.equal(2); - await expect(this.mock.signerWeight(signer3)).to.eventually.equal(3); - }); - - it('can update signer weights', async function () { - // Successfully updates weights and emits event - await expect(this.mock.$_setSignerWeights([signer1, signer2], [5, 6])) - .to.emit(this.mock, 'ERC7913SignerWeightChanged') - .withArgs(signer1, 5) - .to.emit(this.mock, 'ERC7913SignerWeightChanged') - .withArgs(signer2, 6); - - await expect(this.mock.signerWeight(signer1)).to.eventually.equal(5); - await expect(this.mock.signerWeight(signer2)).to.eventually.equal(6); - await expect(this.mock.signerWeight(signer3)).to.eventually.equal(3); // unchanged - }); - - it("no-op doesn't emit an event", async function () { - await expect(this.mock.$_setSignerWeights([signer1], [1])).to.not.emit(this.mock, 'ERC7913SignerWeightChanged'); - }); - - it('cannot set weight to non-existent signer', async function () { - // Reverts when setting weight for non-existent signer - await expect(this.mock.$_setSignerWeights([signer4], [1])) - .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913NonexistentSigner') - .withArgs(signer4.toLowerCase()); - }); - - it('cannot set weight to 0', async function () { - // Reverts when setting weight to 0 - await expect(this.mock.$_setSignerWeights([signer1], [0])) - .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913WeightedInvalidWeight') - .withArgs(signer1.toLowerCase(), 0); - }); - - it('requires signers and weights arrays to have same length', async function () { - // Reverts when arrays have different lengths - await expect(this.mock.$_setSignerWeights([signer1, signer2], [1])).to.be.revertedWithCustomError( - this.mock, - 'MultiSignerERC7913WeightedMismatchedLength', - ); - - await expect(this.mock.$_setSignerWeights([signer1], [1, 2])).to.be.revertedWithCustomError( - this.mock, - 'MultiSignerERC7913WeightedMismatchedLength', - ); - }); - - it('validates threshold is reachable when updating weights', async function () { - // First, lower the weights so the sum is exactly 9 (just enough for threshold=9) - await expect(this.mock.$_setSignerWeights([signer1, signer2, signer3], [2, 3, 4])) - .to.emit(this.mock, 'ERC7913SignerWeightChanged') - .withArgs(signer1, 2) - .to.emit(this.mock, 'ERC7913SignerWeightChanged') - .withArgs(signer2, 3) - .to.emit(this.mock, 'ERC7913SignerWeightChanged') - .withArgs(signer3, 4); - - // Increase threshold to 9 - await expect(this.mock.$_setThreshold(9)).to.emit(this.mock, 'ERC7913ThresholdSet').withArgs(9); - - // Now try to lower weights so their sum is less than the threshold - await expect(this.mock.$_setSignerWeights([signer1, signer2, signer3], [2, 2, 2])).to.be.revertedWithCustomError( - this.mock, - 'MultiSignerERC7913UnreachableThreshold', - ); - - // Try to increase threshold to be larger than the total weight - await expect(this.mock.$_setThreshold(10)) - .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913UnreachableThreshold') - .withArgs(9, 10); - }); - - it('reports default weight of 1 for signers without explicit weight', async function () { - // Add a new signer without setting weight - await this.mock.$_addSigners([signer4]); - - // Should have default weight of 1 - await expect(this.mock.signerWeight(signer4)).to.eventually.equal(1); - }); - - it('reports weight of 0 for invalid signers', async function () { - // not authorized - await expect(this.mock.signerWeight(signer4)).to.eventually.equal(0); - }); - - it('can get total weight of all signers', async function () { - await expect(this.mock.totalWeight()).to.eventually.equal(6); // 1+2+3=6 - }); - - it('totalWeight returns correct value when all signers have default weight of 1', async function () { - // Deploy a new mock with all signers having default weight (1) - const signers = [signerECDSA1.address, signerECDSA2.address, signerECDSA3.address]; - const defaultWeights = [1, 1, 1]; // All weights are 1 (default) - const newMock = await this.makeMock(signers, defaultWeights, 2); - await newMock.deploy(); - - // totalWeight should return max(3, 3) = 3 when all weights are default - await expect(newMock.totalWeight()).to.eventually.equal(3); - - // Clear custom weights to ensure we're using default weights - await newMock.$_setSignerWeights(signers, [1, 1, 1]); - - // totalWeight should still be max(3, 3) = 3 - await expect(newMock.totalWeight()).to.eventually.equal(3); - }); - - it('_setSignerWeights correctly handles default weights when updating', async function () { - await expect(this.mock.totalWeight()).to.eventually.equal(6); // 1+2+3=6 - - // Set weight for signer1 from 1 (default) to 5 - await this.mock.$_setSignerWeights([signer1], [5]); - await expect(this.mock.totalWeight()).to.eventually.equal(10); // 5+2+3=10 - - // Reset signer1 to default weight (1) - await this.mock.$_setSignerWeights([signer1], [1]); - await expect(this.mock.totalWeight()).to.eventually.equal(6); // 1+2+3=6 - }); - - it('updates total weight when adding and removing signers', async function () { - await expect(this.mock.totalWeight()).to.eventually.equal(6); // 1+2+3=6 - - // Add a new signer - should increase total weight by default weight (1) - await this.mock.$_addSigners([signer4]); - await expect(this.mock.totalWeight()).to.eventually.equal(7); // 1+2+3+1=7 - - // Set weight to 5 - should increase total weight by 4 - await this.mock.$_setSignerWeights([signer4], [5]); - await expect(this.mock.totalWeight()).to.eventually.equal(11); // 1+2+3+5=11 - - // Remove signer - should decrease total weight by current weight (5) - await this.mock.$_removeSigners([signer4]); - await expect(this.mock.totalWeight()).to.eventually.equal(6); // 1+2+3=6 - }); - - it('removing signers should not make threshold unreachable', async function () { - // current threshold = 4, totalWeight = 1+2+3 = 6 - - // After removing signer3, the threshold is unreachable because totalWeight = 1+2 = 3 but threshold = 4 - // [reverts] - await expect(this.mock.$_removeSigners([signer3])) - .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913UnreachableThreshold') - .withArgs(3, 4); - - // After removing signer1, the threshold is still reachable because totalWeight = 2+3 = 5 and threshold = 4 - // [does not revert] - await expect(this.mock.$_removeSigners([signer1])) - .to.emit(this.mock, 'ERC7913SignerRemoved') - .withArgs(signer1) - .to.not.emit(this.mock, 'ERC7913SignerWeightChanged'); - }); - - it('should revert if total weight to overflow (_setSignerWeights)', async function () { - await expect(this.mock.$_setSignerWeights([signer1, signer2, signer3], [1n, 1n, MAX_UINT64 - 1n])) - .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintDowncast') - .withArgs(64, MAX_UINT64 + 1n); - }); - - it('should revert if total weight to overflow (_addSigner)', async function () { - await this.mock.$_setSignerWeights([signer1, signer2, signer3], [1n, 1n, MAX_UINT64 - 2n]); - await expect(this.mock.totalWeight()).to.eventually.equal(MAX_UINT64); - - await expect(this.mock.$_addSigners([signer4])) - .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintDowncast') - .withArgs(64, MAX_UINT64 + 1n); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountP256.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountP256.test.js deleted file mode 100644 index 33aadbb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountP256.test.js +++ /dev/null @@ -1,58 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain } = require('../helpers/eip712'); -const { ERC4337Helper } = require('../helpers/erc4337'); -const { NonNativeSigner, P256SigningKey } = require('../helpers/signers'); -const { PackedUserOperation } = require('../helpers/eip712-types'); - -const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); -const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); -const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); - -async function fixture() { - // EOAs and environment - const [beneficiary, other] = await ethers.getSigners(); - const target = await ethers.deployContract('CallReceiverMock'); - - // ERC-4337 signer - const signer = new NonNativeSigner(P256SigningKey.random()); - - // ERC-4337 account - const helper = new ERC4337Helper(); - const mock = await helper.newAccount('$AccountP256Mock', [ - signer.signingKey.publicKey.qx, - signer.signingKey.publicKey.qy, - 'AccountP256', - '1', - ]); - - // ERC-4337 Entrypoint domain - const entrypointDomain = await getDomain(entrypoint.v08); - - // domain cannot be fetched using getDomain(mock) before the mock is deployed - const domain = { - name: 'AccountP256', - version: '1', - chainId: entrypointDomain.chainId, - verifyingContract: mock.address, - }; - - const signUserOp = userOp => - signer - .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) - .then(signature => Object.assign(userOp, { signature })); - - return { helper, mock, domain, signer, target, beneficiary, other, signUserOp }; -} - -describe('AccountP256', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC1271({ erc7739: true }); - shouldBehaveLikeERC7821(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountRSA.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountRSA.test.js deleted file mode 100644 index 707469f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/AccountRSA.test.js +++ /dev/null @@ -1,58 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain } = require('../helpers/eip712'); -const { ERC4337Helper } = require('../helpers/erc4337'); -const { NonNativeSigner, RSASHA256SigningKey } = require('../helpers/signers'); -const { PackedUserOperation } = require('../helpers/eip712-types'); - -const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior'); -const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior'); -const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior'); - -async function fixture() { - // EOAs and environment - const [beneficiary, other] = await ethers.getSigners(); - const target = await ethers.deployContract('CallReceiverMock'); - - // ERC-4337 signer - const signer = new NonNativeSigner(RSASHA256SigningKey.random()); - - // ERC-4337 account - const helper = new ERC4337Helper(); - const mock = await helper.newAccount('$AccountRSAMock', [ - signer.signingKey.publicKey.e, - signer.signingKey.publicKey.n, - 'AccountRSA', - '1', - ]); - - // ERC-4337 Entrypoint domain - const entrypointDomain = await getDomain(entrypoint.v08); - - // domain cannot be fetched using getDomain(mock) before the mock is deployed - const domain = { - name: 'AccountRSA', - version: '1', - chainId: entrypointDomain.chainId, - verifyingContract: mock.address, - }; - - const signUserOp = userOp => - signer - .signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed) - .then(signature => Object.assign(userOp, { signature })); - - return { helper, mock, domain, signer, target, beneficiary, other, signUserOp }; -} - -describe('AccountRSA', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC1271({ erc7739: true }); - shouldBehaveLikeERC7821(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/examples/AccountERC7702WithModulesMock.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/examples/AccountERC7702WithModulesMock.test.js deleted file mode 100644 index 9ee5f91..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/examples/AccountERC7702WithModulesMock.test.js +++ /dev/null @@ -1,99 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { loadFixture, setBalance } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain } = require('../../helpers/eip712'); -const { ERC4337Helper } = require('../../helpers/erc4337'); -const { PackedUserOperation } = require('../../helpers/eip712-types'); - -const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('../Account.behavior'); -const { shouldBehaveLikeAccountERC7579 } = require('../extensions/AccountERC7579.behavior'); -const { shouldBehaveLikeERC1271 } = require('../../utils/cryptography/ERC1271.behavior'); -const { shouldBehaveLikeERC7821 } = require('../extensions/ERC7821.behavior'); - -const { MODULE_TYPE_VALIDATOR } = require('../../helpers/erc7579'); - -async function fixture() { - // EOAs and environment - const [beneficiary, other] = await ethers.getSigners(); - const target = await ethers.deployContract('CallReceiverMock'); - const anotherTarget = await ethers.deployContract('CallReceiverMock'); - - // Signer with EIP-7702 support + funding - const eoa = ethers.Wallet.createRandom(ethers.provider); - await setBalance(eoa.address, ethers.WeiPerEther); - - // ERC-7579 validator module - const validator = await ethers.deployContract('$ERC7579ValidatorMock'); - - // ERC-4337 account - const helper = new ERC4337Helper(); - const mock = await helper.newAccount('$AccountERC7702WithModulesMock', ['AccountERC7702WithModulesMock', '1'], { - erc7702signer: eoa, - }); - - // ERC-4337 Entrypoint domain - const entrypointDomain = await getDomain(entrypoint.v08); - - // domain cannot be fetched using getDomain(mock) before the mock is deployed - const domain = { - name: 'AccountERC7702WithModulesMock', - version: '1', - chainId: entrypointDomain.chainId, - verifyingContract: mock.address, - }; - - return { helper, validator, mock, domain, entrypointDomain, eoa, target, anotherTarget, beneficiary, other }; -} - -describe('AccountERC7702WithModules: ERC-7702 account with ERC-7579 modules supports', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('using ERC-7702 signer', function () { - beforeEach(async function () { - this.signer = this.eoa; - this.signUserOp = userOp => - this.signer - .signTypedData(this.entrypointDomain, { PackedUserOperation }, userOp.packed) - .then(signature => Object.assign(userOp, { signature })); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeERC7821({ deployable: false }); - shouldBehaveLikeERC1271({ erc7739: true }); - }); - - describe('using ERC-7579 validator', function () { - beforeEach(async function () { - // signer that adds a prefix to all signatures (except the userOp ones) - this.signer = ethers.Wallet.createRandom(); - this.signer.signMessage = message => - ethers.Wallet.prototype.signMessage - .bind(this.signer)(message) - .then(sign => ethers.concat([this.validator.target, sign])); - this.signer.signTypedData = (domain, types, values) => - ethers.Wallet.prototype.signTypedData - .bind(this.signer)(domain, types, values) - .then(sign => ethers.concat([this.validator.target, sign])); - - this.signUserOp = userOp => - ethers.Wallet.prototype.signTypedData - .bind(this.signer)(this.entrypointDomain, { PackedUserOperation }, userOp.packed) - .then(signature => Object.assign(userOp, { signature })); - - // Use the first 20 bytes from the nonce key (24 bytes) to identify the validator module - this.userOp = { nonce: ethers.zeroPadBytes(ethers.hexlify(this.validator.target), 32) }; - - // Deploy (using ERC-7702) and add the validator module using EOA - await this.mock.deploy(); - await this.mock.connect(this.eoa).installModule(MODULE_TYPE_VALIDATOR, this.validator, this.signer.address); - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountHolder(); - shouldBehaveLikeAccountERC7579(); - shouldBehaveLikeERC1271({ erc7739: false }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.behavior.js deleted file mode 100644 index 1b702fc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.behavior.js +++ /dev/null @@ -1,563 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { expect } = require('chai'); -const { impersonate } = require('../../helpers/account'); -const { selector } = require('../../helpers/methods'); -const { zip } = require('../../helpers/iterate'); -const { - encodeMode, - encodeBatch, - encodeSingle, - encodeDelegate, - MODULE_TYPE_VALIDATOR, - MODULE_TYPE_EXECUTOR, - MODULE_TYPE_FALLBACK, - MODULE_TYPE_HOOK, - CALL_TYPE_CALL, - CALL_TYPE_BATCH, - CALL_TYPE_DELEGATE, - EXEC_TYPE_DEFAULT, - EXEC_TYPE_TRY, -} = require('../../helpers/erc7579'); - -const CALL_TYPE_INVALID = '0x42'; -const EXEC_TYPE_INVALID = '0x17'; -const MODULE_TYPE_INVALID = 999n; - -const coder = ethers.AbiCoder.defaultAbiCoder(); - -function shouldBehaveLikeAccountERC7579({ withHooks = false } = {}) { - describe('AccountERC7579', function () { - beforeEach(async function () { - await this.mock.deploy(); - await this.other.sendTransaction({ to: this.mock.target, value: ethers.parseEther('1') }); - - this.modules = {}; - this.modules[MODULE_TYPE_VALIDATOR] = await ethers.deployContract('$ERC7579ModuleMock', [MODULE_TYPE_VALIDATOR]); - this.modules[MODULE_TYPE_EXECUTOR] = await ethers.deployContract('$ERC7579ModuleMock', [MODULE_TYPE_EXECUTOR]); - this.modules[MODULE_TYPE_FALLBACK] = await ethers.deployContract('$ERC7579ModuleMock', [MODULE_TYPE_FALLBACK]); - this.modules[MODULE_TYPE_HOOK] = await ethers.deployContract('$ERC7579HookMock'); - - this.mockFromEntrypoint = this.mock.connect(await impersonate(entrypoint.v08.target)); - this.mockFromExecutor = this.mock.connect(await impersonate(this.modules[MODULE_TYPE_EXECUTOR].target)); - }); - - describe('accountId', function () { - it('should return the account ID', async function () { - await expect(this.mock.accountId()).to.eventually.equal( - withHooks - ? '@openzeppelin/community-contracts.AccountERC7579Hooked.v0.0.0' - : '@openzeppelin/community-contracts.AccountERC7579.v0.0.0', - ); - }); - }); - - describe('supportsExecutionMode', function () { - for (const [callType, execType] of zip( - [CALL_TYPE_CALL, CALL_TYPE_BATCH, CALL_TYPE_DELEGATE, CALL_TYPE_INVALID], - [EXEC_TYPE_DEFAULT, EXEC_TYPE_TRY, EXEC_TYPE_INVALID], - )) { - const result = callType != CALL_TYPE_INVALID && execType != EXEC_TYPE_INVALID; - - it(`${ - result ? 'does not support' : 'supports' - } CALL_TYPE=${callType} and EXEC_TYPE=${execType} execution mode`, async function () { - await expect(this.mock.supportsExecutionMode(encodeMode({ callType, execType }))).to.eventually.equal(result); - }); - } - }); - - describe('supportsModule', function () { - it('supports MODULE_TYPE_VALIDATOR module type', async function () { - await expect(this.mock.supportsModule(MODULE_TYPE_VALIDATOR)).to.eventually.equal(true); - }); - - it('supports MODULE_TYPE_EXECUTOR module type', async function () { - await expect(this.mock.supportsModule(MODULE_TYPE_EXECUTOR)).to.eventually.equal(true); - }); - - it('supports MODULE_TYPE_FALLBACK module type', async function () { - await expect(this.mock.supportsModule(MODULE_TYPE_FALLBACK)).to.eventually.equal(true); - }); - - it( - withHooks ? 'supports MODULE_TYPE_HOOK module type' : 'does not support MODULE_TYPE_HOOK module type', - async function () { - await expect(this.mock.supportsModule(MODULE_TYPE_HOOK)).to.eventually.equal(withHooks); - }, - ); - - it('does not support invalid module type', async function () { - await expect(this.mock.supportsModule(MODULE_TYPE_INVALID)).to.eventually.equal(false); - }); - }); - - describe('module installation', function () { - it('should revert if the caller is not the canonical entrypoint or the account itself', async function () { - await expect(this.mock.connect(this.other).installModule(MODULE_TYPE_VALIDATOR, this.mock, '0x')) - .to.be.revertedWithCustomError(this.mock, 'AccountUnauthorized') - .withArgs(this.other); - }); - - it('should revert if the module type is not supported', async function () { - await expect(this.mockFromEntrypoint.installModule(MODULE_TYPE_INVALID, this.mock, '0x')) - .to.be.revertedWithCustomError(this.mock, 'ERC7579UnsupportedModuleType') - .withArgs(MODULE_TYPE_INVALID); - }); - - it('should revert if the module is not the provided type', async function () { - const instance = this.modules[MODULE_TYPE_EXECUTOR]; - await expect(this.mockFromEntrypoint.installModule(MODULE_TYPE_VALIDATOR, instance, '0x')) - .to.be.revertedWithCustomError(this.mock, 'ERC7579MismatchedModuleTypeId') - .withArgs(MODULE_TYPE_VALIDATOR, instance); - }); - - for (const moduleTypeId of [ - MODULE_TYPE_VALIDATOR, - MODULE_TYPE_EXECUTOR, - MODULE_TYPE_FALLBACK, - withHooks && MODULE_TYPE_HOOK, - ].filter(Boolean)) { - const prefix = moduleTypeId == MODULE_TYPE_FALLBACK ? '0x12345678' : '0x'; - const initData = ethers.hexlify(ethers.randomBytes(256)); - const fullData = ethers.concat([prefix, initData]); - - it(`should install a module of type ${moduleTypeId}`, async function () { - const instance = this.modules[moduleTypeId]; - - await expect(this.mock.isModuleInstalled(moduleTypeId, instance, fullData)).to.eventually.equal(false); - - await expect(this.mockFromEntrypoint.installModule(moduleTypeId, instance, fullData)) - .to.emit(this.mock, 'ModuleInstalled') - .withArgs(moduleTypeId, instance) - .to.emit(instance, 'ModuleInstalledReceived') - .withArgs(this.mock, initData); // After decoding MODULE_TYPE_FALLBACK, it should remove the fnSig - - await expect(this.mock.isModuleInstalled(moduleTypeId, instance, fullData)).to.eventually.equal(true); - }); - - it(`does not allow to install a module of ${moduleTypeId} id twice`, async function () { - const instance = this.modules[moduleTypeId]; - - await this.mockFromEntrypoint.installModule(moduleTypeId, instance, fullData); - - await expect(this.mock.isModuleInstalled(moduleTypeId, instance, fullData)).to.eventually.equal(true); - - await expect(this.mockFromEntrypoint.installModule(moduleTypeId, instance, fullData)) - .to.be.revertedWithCustomError( - this.mock, - moduleTypeId == MODULE_TYPE_HOOK ? 'ERC7579HookModuleAlreadyPresent' : 'ERC7579AlreadyInstalledModule', - ) - .withArgs(...[moduleTypeId != MODULE_TYPE_HOOK && moduleTypeId, instance].filter(Boolean)); - }); - } - - withHooks && - describe('with hook', function () { - beforeEach(async function () { - await this.mockFromEntrypoint.$_installModule(MODULE_TYPE_HOOK, this.modules[MODULE_TYPE_HOOK], '0x'); - }); - - it('should call the hook of the installed module when performing an module install', async function () { - const instance = this.modules[MODULE_TYPE_EXECUTOR]; - const initData = ethers.hexlify(ethers.randomBytes(256)); - - const precheckData = this.mock.interface.encodeFunctionData('installModule', [ - MODULE_TYPE_EXECUTOR, - instance.target, - initData, - ]); - - await expect(this.mockFromEntrypoint.installModule(MODULE_TYPE_EXECUTOR, instance, initData)) - .to.emit(this.modules[MODULE_TYPE_HOOK], 'PreCheck') - .withArgs(entrypoint.v08, 0n, precheckData) - .to.emit(this.modules[MODULE_TYPE_HOOK], 'PostCheck') - .withArgs(precheckData); - }); - }); - }); - - describe('module uninstallation', function () { - it('should revert if the caller is not the canonical entrypoint or the account itself', async function () { - await expect(this.mock.connect(this.other).uninstallModule(MODULE_TYPE_VALIDATOR, this.mock, '0x')) - .to.be.revertedWithCustomError(this.mock, 'AccountUnauthorized') - .withArgs(this.other); - }); - - it('should revert if the module type is not supported', async function () { - await expect(this.mockFromEntrypoint.uninstallModule(MODULE_TYPE_INVALID, this.mock, '0x')) - .to.be.revertedWithCustomError(this.mock, 'ERC7579UnsupportedModuleType') - .withArgs(MODULE_TYPE_INVALID); - }); - - for (const moduleTypeId of [ - MODULE_TYPE_VALIDATOR, - MODULE_TYPE_EXECUTOR, - MODULE_TYPE_FALLBACK, - withHooks && MODULE_TYPE_HOOK, - ].filter(Boolean)) { - const prefix = moduleTypeId == MODULE_TYPE_FALLBACK ? '0x12345678' : '0x'; - const initData = ethers.hexlify(ethers.randomBytes(256)); - const fullData = ethers.concat([prefix, initData]); - - it(`should uninstall a module of type ${moduleTypeId}`, async function () { - const instance = this.modules[moduleTypeId]; - - await this.mock.$_installModule(moduleTypeId, instance, fullData); - - await expect(this.mock.isModuleInstalled(moduleTypeId, instance, fullData)).to.eventually.equal(true); - - await expect(this.mockFromEntrypoint.uninstallModule(moduleTypeId, instance, fullData)) - .to.emit(this.mock, 'ModuleUninstalled') - .withArgs(moduleTypeId, instance) - .to.emit(instance, 'ModuleUninstalledReceived') - .withArgs(this.mock, initData); // After decoding MODULE_TYPE_FALLBACK, it should remove the fnSig - - await expect(this.mock.isModuleInstalled(moduleTypeId, instance, fullData)).to.eventually.equal(false); - }); - - it(`should revert uninstalling a module of type ${moduleTypeId} if it was not installed`, async function () { - const instance = this.modules[moduleTypeId]; - - await expect(this.mockFromEntrypoint.uninstallModule(moduleTypeId, instance, fullData)) - .to.be.revertedWithCustomError(this.mock, 'ERC7579UninstalledModule') - .withArgs(moduleTypeId, instance); - }); - } - - it('should revert uninstalling a module of type MODULE_TYPE_FALLBACK if a different module was installed for the provided selector', async function () { - const instance = this.modules[MODULE_TYPE_FALLBACK]; - const anotherInstance = await ethers.deployContract('$ERC7579ModuleMock', [MODULE_TYPE_FALLBACK]); - const initData = '0x12345678abcdef'; - - await this.mockFromEntrypoint.$_installModule(MODULE_TYPE_FALLBACK, instance, initData); - await expect(this.mockFromEntrypoint.uninstallModule(MODULE_TYPE_FALLBACK, anotherInstance, initData)) - .to.be.revertedWithCustomError(this.mock, 'ERC7579UninstalledModule') - .withArgs(MODULE_TYPE_FALLBACK, anotherInstance); - }); - - withHooks && - describe('with hook', function () { - beforeEach(async function () { - await this.mockFromEntrypoint.$_installModule(MODULE_TYPE_HOOK, this.modules[MODULE_TYPE_HOOK], '0x'); - }); - - it('should call the hook of the installed module when performing a module uninstall', async function () { - const instance = this.modules[MODULE_TYPE_EXECUTOR]; - const initData = ethers.hexlify(ethers.randomBytes(256)); - - const precheckData = this.mock.interface.encodeFunctionData('uninstallModule', [ - MODULE_TYPE_EXECUTOR, - instance.target, - initData, - ]); - - await this.mock.$_installModule(MODULE_TYPE_EXECUTOR, instance, initData); - await expect(this.mockFromEntrypoint.uninstallModule(MODULE_TYPE_EXECUTOR, instance, initData)) - .to.emit(this.modules[MODULE_TYPE_HOOK], 'PreCheck') - .withArgs(entrypoint.v08, 0n, precheckData) - .to.emit(this.modules[MODULE_TYPE_HOOK], 'PostCheck') - .withArgs(precheckData); - }); - }); - }); - - describe('execution', function () { - beforeEach(async function () { - await this.mock.$_installModule(MODULE_TYPE_EXECUTOR, this.modules[MODULE_TYPE_EXECUTOR], '0x'); - }); - - for (const [execFn, mock] of [ - ['execute', 'mockFromEntrypoint'], - ['executeFromExecutor', 'mockFromExecutor'], - ]) { - describe(`executing with ${execFn}`, function () { - it('should revert if the call type is not supported', async function () { - await expect( - this[mock][execFn](encodeMode({ callType: CALL_TYPE_INVALID }), encodeSingle(this.other, 0, '0x')), - ) - .to.be.revertedWithCustomError(this.mock, 'ERC7579UnsupportedCallType') - .withArgs(ethers.solidityPacked(['bytes1'], [CALL_TYPE_INVALID])); - }); - - it('should revert if the caller is not authorized / installed', async function () { - const error = execFn == 'execute' ? 'AccountUnauthorized' : 'ERC7579UninstalledModule'; - const args = execFn == 'execute' ? [this.other] : [MODULE_TYPE_EXECUTOR, this.other]; - - await expect( - this[mock] - .connect(this.other) - [execFn](encodeMode({ callType: CALL_TYPE_CALL }), encodeSingle(this.other, 0, '0x')), - ) - .to.be.revertedWithCustomError(this.mock, error) - .withArgs(...args); - }); - - describe('single execution', function () { - it('calls the target with value and args', async function () { - const value = 0x432; - const data = encodeSingle( - this.target, - value, - this.target.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234']), - ); - - const tx = this[mock][execFn](encodeMode({ callType: CALL_TYPE_CALL }), data); - - await expect(tx).to.emit(this.target, 'MockFunctionCalledWithArgs').withArgs(42, '0x1234'); - await expect(tx).to.changeEtherBalances([this.mock, this.target], [-value, value]); - }); - - it('reverts when target reverts in default ExecType', async function () { - const value = 0x012; - const data = encodeSingle( - this.target, - value, - this.target.interface.encodeFunctionData('mockFunctionRevertsReason'), - ); - - await expect(this[mock][execFn](encodeMode({ callType: CALL_TYPE_CALL }), data)).to.be.revertedWith( - 'CallReceiverMock: reverting', - ); - }); - - it('emits ERC7579TryExecuteFail event when target reverts in try ExecType', async function () { - const value = 0x012; - const data = encodeSingle( - this.target, - value, - this.target.interface.encodeFunctionData('mockFunctionRevertsReason'), - ); - - await expect(this[mock][execFn](encodeMode({ callType: CALL_TYPE_CALL, execType: EXEC_TYPE_TRY }), data)) - .to.emit(this.mock, 'ERC7579TryExecuteFail') - .withArgs( - CALL_TYPE_CALL, - ethers.solidityPacked( - ['bytes4', 'bytes'], - [selector('Error(string)'), coder.encode(['string'], ['CallReceiverMock: reverting'])], - ), - ); - }); - }); - - describe('batch execution', function () { - it('calls the targets with value and args', async function () { - const value1 = 0x012; - const value2 = 0x234; - const data = encodeBatch( - [this.target, value1, this.target.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234'])], - [ - this.anotherTarget, - value2, - this.anotherTarget.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234']), - ], - ); - - const tx = this[mock][execFn](encodeMode({ callType: CALL_TYPE_BATCH }), data); - await expect(tx) - .to.emit(this.target, 'MockFunctionCalledWithArgs') - .to.emit(this.anotherTarget, 'MockFunctionCalledWithArgs'); - await expect(tx).to.changeEtherBalances( - [this.mock, this.target, this.anotherTarget], - [-value1 - value2, value1, value2], - ); - }); - - it('reverts when any target reverts in default ExecType', async function () { - const value1 = 0x012; - const value2 = 0x234; - const data = encodeBatch( - [this.target, value1, this.target.interface.encodeFunctionData('mockFunction')], - [ - this.anotherTarget, - value2, - this.anotherTarget.interface.encodeFunctionData('mockFunctionRevertsReason'), - ], - ); - - await expect(this[mock][execFn](encodeMode({ callType: CALL_TYPE_BATCH }), data)).to.be.revertedWith( - 'CallReceiverMock: reverting', - ); - }); - - it('emits ERC7579TryExecuteFail event when any target reverts in try ExecType', async function () { - const value1 = 0x012; - const value2 = 0x234; - const data = encodeBatch( - [this.target, value1, this.target.interface.encodeFunctionData('mockFunction')], - [ - this.anotherTarget, - value2, - this.anotherTarget.interface.encodeFunctionData('mockFunctionRevertsReason'), - ], - ); - - const tx = this[mock][execFn](encodeMode({ callType: CALL_TYPE_BATCH, execType: EXEC_TYPE_TRY }), data); - - await expect(tx) - .to.emit(this.mock, 'ERC7579TryExecuteFail') - .withArgs( - CALL_TYPE_BATCH, - ethers.solidityPacked( - ['bytes4', 'bytes'], - [selector('Error(string)'), coder.encode(['string'], ['CallReceiverMock: reverting'])], - ), - ); - - await expect(tx).to.changeEtherBalances( - [this.mock, this.target, this.anotherTarget], - [-value1, value1, 0], - ); - }); - }); - - describe('delegate call execution', function () { - it('delegate calls the target', async function () { - const slot = ethers.hexlify(ethers.randomBytes(32)); - const value = ethers.hexlify(ethers.randomBytes(32)); - const data = encodeDelegate( - this.target, - this.target.interface.encodeFunctionData('mockFunctionWritesStorage', [slot, value]), - ); - - await expect(ethers.provider.getStorage(this.mock.target, slot)).to.eventually.equal(ethers.ZeroHash); - await this[mock][execFn](encodeMode({ callType: CALL_TYPE_DELEGATE }), data); - await expect(ethers.provider.getStorage(this.mock.target, slot)).to.eventually.equal(value); - }); - - it('reverts when target reverts in default ExecType', async function () { - const data = encodeDelegate( - this.target, - this.target.interface.encodeFunctionData('mockFunctionRevertsReason'), - ); - await expect(this[mock][execFn](encodeMode({ callType: CALL_TYPE_DELEGATE }), data)).to.be.revertedWith( - 'CallReceiverMock: reverting', - ); - }); - - it('emits ERC7579TryExecuteFail event when target reverts in try ExecType', async function () { - const data = encodeDelegate( - this.target, - this.target.interface.encodeFunctionData('mockFunctionRevertsReason'), - ); - await expect( - this[mock][execFn](encodeMode({ callType: CALL_TYPE_DELEGATE, execType: EXEC_TYPE_TRY }), data), - ) - .to.emit(this.mock, 'ERC7579TryExecuteFail') - .withArgs( - CALL_TYPE_CALL, - ethers.solidityPacked( - ['bytes4', 'bytes'], - [selector('Error(string)'), coder.encode(['string'], ['CallReceiverMock: reverting'])], - ), - ); - }); - }); - - withHooks && - describe('with hook', function () { - beforeEach(async function () { - await this.mockFromEntrypoint.$_installModule(MODULE_TYPE_HOOK, this.modules[MODULE_TYPE_HOOK], '0x'); - }); - - it(`should call the hook of the installed module when executing ${execFn}`, async function () { - const caller = execFn === 'execute' ? entrypoint.v08 : this.modules[MODULE_TYPE_EXECUTOR]; - const value = 17; - const data = this.target.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234']); - - const mode = encodeMode({ callType: CALL_TYPE_CALL }); - const call = encodeSingle(this.target, value, data); - const precheckData = this[mock].interface.encodeFunctionData(execFn, [mode, call]); - - const tx = this[mock][execFn](mode, call, { value }); - - await expect(tx) - .to.emit(this.modules[MODULE_TYPE_HOOK], 'PreCheck') - .withArgs(caller, value, precheckData) - .to.emit(this.modules[MODULE_TYPE_HOOK], 'PostCheck') - .withArgs(precheckData); - await expect(tx).to.changeEtherBalances([caller, this.mock, this.target], [-value, 0n, value]); - }); - }); - }); - } - }); - - describe('fallback', function () { - beforeEach(async function () { - this.fallbackHandler = await ethers.deployContract('$ERC7579FallbackHandlerMock'); - }); - - it('reverts if there is no fallback module installed', async function () { - const { selector } = this.fallbackHandler.callPayable.getFragment(); - - await expect(this.fallbackHandler.attach(this.mock).callPayable()) - .to.be.revertedWithCustomError(this.mock, 'ERC7579MissingFallbackHandler') - .withArgs(selector); - }); - - describe('with a fallback module installed', function () { - beforeEach(async function () { - await Promise.all( - [ - this.fallbackHandler.callPayable.getFragment().selector, - this.fallbackHandler.callView.getFragment().selector, - this.fallbackHandler.callRevert.getFragment().selector, - ].map(selector => - this.mock.$_installModule( - MODULE_TYPE_FALLBACK, - this.fallbackHandler, - coder.encode(['bytes4', 'bytes'], [selector, '0x']), - ), - ), - ); - }); - - it('forwards the call to the fallback handler', async function () { - const calldata = this.fallbackHandler.interface.encodeFunctionData('callPayable'); - const value = 17n; - - await expect(this.fallbackHandler.attach(this.mock).connect(this.other).callPayable({ value })) - .to.emit(this.fallbackHandler, 'ERC7579FallbackHandlerMockCalled') - .withArgs(this.mock, this.other, value, calldata); - }); - - it('returns answer from the fallback handler', async function () { - await expect(this.fallbackHandler.attach(this.mock).connect(this.other).callView()).to.eventually.deep.equal([ - this.mock.target, - this.other.address, - ]); - }); - - it('bubble up reverts from the fallback handler', async function () { - await expect( - this.fallbackHandler.attach(this.mock).connect(this.other).callRevert(), - ).to.be.revertedWithCustomError(this.fallbackHandler, 'ERC7579FallbackHandlerMockRevert'); - }); - - withHooks && - describe('with hook', function () { - beforeEach(async function () { - await this.mockFromEntrypoint.$_installModule(MODULE_TYPE_HOOK, this.modules[MODULE_TYPE_HOOK], '0x'); - }); - - it('should call the hook of the installed module when performing a callback', async function () { - const precheckData = this.fallbackHandler.interface.encodeFunctionData('callPayable'); - const value = 17n; - - // call with interface: decode returned data - await expect(this.fallbackHandler.attach(this.mock).connect(this.other).callPayable({ value })) - .to.emit(this.modules[MODULE_TYPE_HOOK], 'PreCheck') - .withArgs(this.other, value, precheckData) - .to.emit(this.modules[MODULE_TYPE_HOOK], 'PostCheck') - .withArgs(precheckData); - }); - }); - }); - }); - }); -} - -module.exports = { - shouldBehaveLikeAccountERC7579, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.test.js deleted file mode 100644 index 7903c91..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579.test.js +++ /dev/null @@ -1,60 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain } = require('../../helpers/eip712'); -const { ERC4337Helper } = require('../../helpers/erc4337'); -const { PackedUserOperation } = require('../../helpers/eip712-types'); - -const { shouldBehaveLikeAccountCore } = require('../Account.behavior'); -const { shouldBehaveLikeAccountERC7579 } = require('./AccountERC7579.behavior'); -const { shouldBehaveLikeERC1271 } = require('../../utils/cryptography/ERC1271.behavior'); - -async function fixture() { - // EOAs and environment - const [other] = await ethers.getSigners(); - const target = await ethers.deployContract('CallReceiverMock'); - const anotherTarget = await ethers.deployContract('CallReceiverMock'); - - // ERC-7579 validator - const validator = await ethers.deployContract('$ERC7579ValidatorMock'); - - // ERC-4337 signer - const signer = ethers.Wallet.createRandom(); - - // ERC-4337 account - const helper = new ERC4337Helper(); - const mock = await helper.newAccount('$AccountERC7579Mock', [ - validator, - ethers.solidityPacked(['address'], [signer.address]), - ]); - - // ERC-4337 Entrypoint domain - const entrypointDomain = await getDomain(entrypoint.v08); - - return { helper, validator, mock, entrypointDomain, signer, target, anotherTarget, other }; -} - -describe('AccountERC7579', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - - this.signer.signMessage = message => - ethers.Wallet.prototype.signMessage - .bind(this.signer)(message) - .then(sign => ethers.concat([this.validator.target, sign])); - this.signer.signTypedData = (domain, types, values) => - ethers.Wallet.prototype.signTypedData - .bind(this.signer)(domain, types, values) - .then(sign => ethers.concat([this.validator.target, sign])); - this.signUserOp = userOp => - ethers.Wallet.prototype.signTypedData - .bind(this.signer)(this.entrypointDomain, { PackedUserOperation }, userOp.packed) - .then(signature => Object.assign(userOp, { signature })); - - this.userOp = { nonce: ethers.zeroPadBytes(ethers.hexlify(this.validator.target), 32) }; - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountERC7579(); - shouldBehaveLikeERC1271(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579Hooked.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579Hooked.test.js deleted file mode 100644 index 6db8fe9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/AccountERC7579Hooked.test.js +++ /dev/null @@ -1,60 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain } = require('../../helpers/eip712'); -const { ERC4337Helper } = require('../../helpers/erc4337'); -const { PackedUserOperation } = require('../../helpers/eip712-types'); - -const { shouldBehaveLikeAccountCore } = require('../Account.behavior'); -const { shouldBehaveLikeAccountERC7579 } = require('./AccountERC7579.behavior'); -const { shouldBehaveLikeERC1271 } = require('../../utils/cryptography/ERC1271.behavior'); - -async function fixture() { - // EOAs and environment - const [other] = await ethers.getSigners(); - const target = await ethers.deployContract('CallReceiverMock'); - const anotherTarget = await ethers.deployContract('CallReceiverMock'); - - // ERC-7579 validator - const validator = await ethers.deployContract('$ERC7579ValidatorMock'); - - // ERC-4337 signer - const signer = ethers.Wallet.createRandom(); - - // ERC-4337 account - const helper = new ERC4337Helper(); - const mock = await helper.newAccount('$AccountERC7579HookedMock', [ - validator, - ethers.solidityPacked(['address'], [signer.address]), - ]); - - // ERC-4337 Entrypoint domain - const entrypointDomain = await getDomain(entrypoint.v08); - - return { helper, validator, mock, entrypointDomain, signer, target, anotherTarget, other }; -} - -describe('AccountERC7579Hooked', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - - this.signer.signMessage = message => - ethers.Wallet.prototype.signMessage - .bind(this.signer)(message) - .then(sign => ethers.concat([this.validator.target, sign])); - this.signer.signTypedData = (domain, types, values) => - ethers.Wallet.prototype.signTypedData - .bind(this.signer)(domain, types, values) - .then(sign => ethers.concat([this.validator.target, sign])); - this.signUserOp = userOp => - ethers.Wallet.prototype.signTypedData - .bind(this.signer)(this.entrypointDomain, { PackedUserOperation }, userOp.packed) - .then(signature => Object.assign(userOp, { signature })); - - this.userOp = { nonce: ethers.zeroPadBytes(ethers.hexlify(this.validator.target), 32) }; - }); - - shouldBehaveLikeAccountCore(); - shouldBehaveLikeAccountERC7579({ withHooks: true }); - shouldBehaveLikeERC1271(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/ERC7821.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/ERC7821.behavior.js deleted file mode 100644 index d6bff8b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/extensions/ERC7821.behavior.js +++ /dev/null @@ -1,145 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { expect } = require('chai'); - -const { CALL_TYPE_BATCH, encodeMode, encodeBatch } = require('../../helpers/erc7579'); - -function shouldBehaveLikeERC7821({ deployable = true } = {}) { - describe('supports ERC-7821', function () { - beforeEach(async function () { - // give eth to the account (before deployment) - await this.other.sendTransaction({ to: this.mock.target, value: ethers.parseEther('1') }); - - // account is not initially deployed - await expect(ethers.provider.getCode(this.mock)).to.eventually.equal('0x'); - - this.encodeUserOpCalldata = (...calls) => - this.mock.interface.encodeFunctionData('execute', [ - encodeMode({ callType: CALL_TYPE_BATCH }), - encodeBatch(...calls), - ]); - }); - - it('should revert if the caller is not the canonical entrypoint or the account itself', async function () { - await this.mock.deploy(); - - await expect( - this.mock.connect(this.other).execute( - encodeMode({ callType: CALL_TYPE_BATCH }), - encodeBatch({ - target: this.target, - data: this.target.interface.encodeFunctionData('mockFunctionExtra'), - }), - ), - ) - .to.be.revertedWithCustomError(this.mock, 'AccountUnauthorized') - .withArgs(this.other); - }); - - if (deployable) { - describe('when not deployed', function () { - it('should be created with handleOps and increase nonce', async function () { - const operation = await this.mock - .createUserOp({ - callData: this.encodeUserOpCalldata({ - target: this.target, - value: 17, - data: this.target.interface.encodeFunctionData('mockFunctionExtra'), - }), - }) - .then(op => op.addInitCode()) - .then(op => this.signUserOp(op)); - - // Can't call the account to get its nonce before it's deployed - await expect(entrypoint.v08.getNonce(this.mock.target, 0)).to.eventually.equal(0); - await expect(entrypoint.v08.handleOps([operation.packed], this.beneficiary)) - .to.emit(entrypoint.v08, 'AccountDeployed') - .withArgs(operation.hash(), this.mock, this.helper.factory, ethers.ZeroAddress) - .to.emit(this.target, 'MockFunctionCalledExtra') - .withArgs(this.mock, 17); - await expect(this.mock.getNonce()).to.eventually.equal(1); - }); - - it('should revert if the signature is invalid', async function () { - const operation = await this.mock - .createUserOp({ - callData: this.encodeUserOpCalldata({ - target: this.target, - value: 17, - data: this.target.interface.encodeFunctionData('mockFunctionExtra'), - }), - }) - .then(op => op.addInitCode()); - - operation.signature = '0x00'; - - await expect(entrypoint.v08.handleOps([operation.packed], this.beneficiary)).to.be.reverted; - }); - }); - } - - describe('when deployed', function () { - beforeEach(async function () { - await this.mock.deploy(); - }); - - it('should increase nonce and call target', async function () { - const operation = await this.mock - .createUserOp({ - callData: this.encodeUserOpCalldata({ - target: this.target, - value: 42, - data: this.target.interface.encodeFunctionData('mockFunctionExtra'), - }), - }) - .then(op => this.signUserOp(op)); - - await expect(this.mock.getNonce()).to.eventually.equal(0); - await expect(entrypoint.v08.handleOps([operation.packed], this.beneficiary)) - .to.emit(this.target, 'MockFunctionCalledExtra') - .withArgs(this.mock, 42); - await expect(this.mock.getNonce()).to.eventually.equal(1); - }); - - it('should support sending eth to an EOA', async function () { - const operation = await this.mock - .createUserOp({ callData: this.encodeUserOpCalldata({ target: this.other, value: 42 }) }) - .then(op => this.signUserOp(op)); - - await expect(this.mock.getNonce()).to.eventually.equal(0); - await expect(entrypoint.v08.handleOps([operation.packed], this.beneficiary)).to.changeEtherBalance( - this.other, - 42, - ); - await expect(this.mock.getNonce()).to.eventually.equal(1); - }); - - it('should support batch execution', async function () { - const value1 = 43374337n; - const value2 = 69420n; - - const operation = await this.mock - .createUserOp({ - callData: this.encodeUserOpCalldata( - { target: this.other, value: value1 }, - { - target: this.target, - value: value2, - data: this.target.interface.encodeFunctionData('mockFunctionExtra'), - }, - ), - }) - .then(op => this.signUserOp(op)); - - await expect(this.mock.getNonce()).to.eventually.equal(0); - const tx = entrypoint.v08.handleOps([operation.packed], this.beneficiary); - await expect(tx).to.changeEtherBalances([this.other, this.target], [value1, value2]); - await expect(tx).to.emit(this.target, 'MockFunctionCalledExtra').withArgs(this.mock, value2); - await expect(this.mock.getNonce()).to.eventually.equal(1); - }); - }); - }); -} - -module.exports = { - shouldBehaveLikeERC7821, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/EIP7702Utils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/EIP7702Utils.test.js deleted file mode 100644 index fb045f7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/EIP7702Utils.test.js +++ /dev/null @@ -1,53 +0,0 @@ -const { ethers, config } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -// [NOTE] -// -// ethers.getSigners() returns object than cannot currently send type-4 transaction, or sign authorization. Therefore, -// we have to instantiate the eoa AND the relayer manually using ethers 6.14.0 wallets. This can be improved when -// @nomicfoundation/hardhat-ethers starts instantiating signers with 7702 support. -const relayAuthorization = authorization => - ethers.Wallet.fromPhrase(config.networks.hardhat.accounts.mnemonic, ethers.provider).sendTransaction({ - to: ethers.ZeroAddress, - authorizationList: [authorization], - gasLimit: 46_000n, - }); - -const fixture = async () => { - const eoa = ethers.Wallet.createRandom(ethers.provider); - const mock = await ethers.deployContract('$EIP7702Utils'); - return { eoa, mock }; -}; - -describe('EIP7702Utils', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('fetchDelegate', function () { - it('EOA without delegation', async function () { - await expect(this.mock.$fetchDelegate(this.eoa)).to.eventually.equal(ethers.ZeroAddress); - }); - - it('EOA with delegation', async function () { - // set delegation - await this.eoa.authorize({ address: this.mock }).then(relayAuthorization); - - await expect(this.mock.$fetchDelegate(this.eoa)).to.eventually.equal(this.mock); - }); - - it('EOA with revoked delegation', async function () { - // set delegation - await this.eoa.authorize({ address: this.mock }).then(relayAuthorization); - // reset delegation - await this.eoa.authorize({ address: ethers.ZeroAddress }).then(relayAuthorization); - - await expect(this.mock.$fetchDelegate(this.eoa)).to.eventually.equal(ethers.ZeroAddress); - }); - - it('other smart contract', async function () { - await expect(this.mock.$fetchDelegate(this.mock)).to.eventually.equal(ethers.ZeroAddress); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC4337Utils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC4337Utils.test.js deleted file mode 100644 index ab4f345..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC4337Utils.test.js +++ /dev/null @@ -1,289 +0,0 @@ -const { ethers, entrypoint } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { packValidationData, UserOperation } = require('../../helpers/erc4337'); -const { MAX_UINT48 } = require('../../helpers/constants'); -const ADDRESS_ONE = '0x0000000000000000000000000000000000000001'; - -const fixture = async () => { - const [authorizer, sender, factory, paymaster] = await ethers.getSigners(); - const utils = await ethers.deployContract('$ERC4337Utils'); - const SIG_VALIDATION_SUCCESS = await utils.$SIG_VALIDATION_SUCCESS(); - const SIG_VALIDATION_FAILED = await utils.$SIG_VALIDATION_FAILED(); - - return { utils, authorizer, sender, factory, paymaster, SIG_VALIDATION_SUCCESS, SIG_VALIDATION_FAILED }; -}; - -describe('ERC4337Utils', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('entrypoint', function () { - it('v0.7.0', async function () { - await expect(this.utils.$ENTRYPOINT_V07()).to.eventually.equal(entrypoint.v07); - }); - - it('v0.8.0', async function () { - await expect(this.utils.$ENTRYPOINT_V08()).to.eventually.equal(entrypoint.v08); - }); - }); - - describe('parseValidationData', function () { - it('parses the validation data', async function () { - const authorizer = this.authorizer; - const validUntil = 0x12345678n; - const validAfter = 0x9abcdef0n; - const validationData = packValidationData(validAfter, validUntil, authorizer); - - await expect(this.utils.$parseValidationData(validationData)).to.eventually.deep.equal([ - authorizer.address, - validAfter, - validUntil, - ]); - }); - - it('returns an type(uint48).max if until is 0', async function () { - const authorizer = this.authorizer; - const validAfter = 0x12345678n; - const validationData = packValidationData(validAfter, 0, authorizer); - - await expect(this.utils.$parseValidationData(validationData)).to.eventually.deep.equal([ - authorizer.address, - validAfter, - MAX_UINT48, - ]); - }); - - it('parse canonical values', async function () { - await expect(this.utils.$parseValidationData(this.SIG_VALIDATION_SUCCESS)).to.eventually.deep.equal([ - ethers.ZeroAddress, - 0n, - MAX_UINT48, - ]); - - await expect(this.utils.$parseValidationData(this.SIG_VALIDATION_FAILED)).to.eventually.deep.equal([ - ADDRESS_ONE, - 0n, - MAX_UINT48, - ]); - }); - }); - - describe('packValidationData', function () { - it('packs the validation data', async function () { - const authorizer = this.authorizer; - const validUntil = 0x12345678n; - const validAfter = 0x9abcdef0n; - const validationData = packValidationData(validAfter, validUntil, authorizer); - - await expect( - this.utils.$packValidationData(ethers.Typed.address(authorizer), validAfter, validUntil), - ).to.eventually.equal(validationData); - }); - - it('packs the validation data (bool)', async function () { - const success = false; - const validUntil = 0x12345678n; - const validAfter = 0x9abcdef0n; - const validationData = packValidationData(validAfter, validUntil, false); - - await expect( - this.utils.$packValidationData(ethers.Typed.bool(success), validAfter, validUntil), - ).to.eventually.equal(validationData); - }); - - it('packing reproduced canonical values', async function () { - await expect( - this.utils.$packValidationData(ethers.Typed.address(ethers.ZeroAddress), 0n, 0n), - ).to.eventually.equal(this.SIG_VALIDATION_SUCCESS); - await expect(this.utils.$packValidationData(ethers.Typed.bool(true), 0n, 0n)).to.eventually.equal( - this.SIG_VALIDATION_SUCCESS, - ); - await expect(this.utils.$packValidationData(ethers.Typed.address(ADDRESS_ONE), 0n, 0n)).to.eventually.equal( - this.SIG_VALIDATION_FAILED, - ); - await expect(this.utils.$packValidationData(ethers.Typed.bool(false), 0n, 0n)).to.eventually.equal( - this.SIG_VALIDATION_FAILED, - ); - }); - }); - - describe('combineValidationData', function () { - const validUntil1 = 0x12345678n; - const validAfter1 = 0x9abcdef0n; - const validUntil2 = 0x87654321n; - const validAfter2 = 0xabcdef90n; - - it('combines the validation data', async function () { - const validationData1 = packValidationData(validAfter1, validUntil1, ethers.ZeroAddress); - const validationData2 = packValidationData(validAfter2, validUntil2, ethers.ZeroAddress); - const expected = packValidationData(validAfter2, validUntil1, true); - - // check symmetry - await expect(this.utils.$combineValidationData(validationData1, validationData2)).to.eventually.equal(expected); - await expect(this.utils.$combineValidationData(validationData2, validationData1)).to.eventually.equal(expected); - }); - - for (const [authorizer1, authorizer2] of [ - [ethers.ZeroAddress, '0xbf023313b891fd6000544b79e353323aa94a4f29'], - ['0xbf023313b891fd6000544b79e353323aa94a4f29', ethers.ZeroAddress], - ]) { - it('returns SIG_VALIDATION_FAILURE if one of the authorizers is not address(0)', async function () { - const validationData1 = packValidationData(validAfter1, validUntil1, authorizer1); - const validationData2 = packValidationData(validAfter2, validUntil2, authorizer2); - const expected = packValidationData(validAfter2, validUntil1, false); - - // check symmetry - await expect(this.utils.$combineValidationData(validationData1, validationData2)).to.eventually.equal(expected); - await expect(this.utils.$combineValidationData(validationData2, validationData1)).to.eventually.equal(expected); - }); - } - }); - - describe('getValidationData', function () { - it('returns the validation data with valid validity range', async function () { - const aggregator = this.authorizer; - const validAfter = 0; - const validUntil = MAX_UINT48; - const validationData = packValidationData(validAfter, validUntil, aggregator); - - await expect(this.utils.$getValidationData(validationData)).to.eventually.deep.equal([aggregator.address, false]); - }); - - it('returns the validation data with invalid validity range (expired)', async function () { - const aggregator = this.authorizer; - const validAfter = 0; - const validUntil = 1; - const validationData = packValidationData(validAfter, validUntil, aggregator); - - await expect(this.utils.$getValidationData(validationData)).to.eventually.deep.equal([aggregator.address, true]); - }); - - it('returns the validation data with invalid validity range (not yet valid)', async function () { - const aggregator = this.authorizer; - const validAfter = MAX_UINT48; - const validUntil = MAX_UINT48; - const validationData = packValidationData(validAfter, validUntil, aggregator); - - await expect(this.utils.$getValidationData(validationData)).to.eventually.deep.equal([aggregator.address, true]); - }); - - it('returns address(0) and false for validationData = 0', async function () { - await expect(this.utils.$getValidationData(0n)).to.eventually.deep.equal([ethers.ZeroAddress, false]); - }); - }); - - describe('hash', function () { - for (const [version, instance] of Object.entries(entrypoint)) { - it(`returns the operation hash for entrypoint ${version}`, async function () { - const userOp = new UserOperation({ sender: this.sender, nonce: 1 }); - const expected = await userOp.hash(instance); - - await expect(this.utils.$hash(userOp.packed, instance)).to.eventually.equal(expected); - }); - } - }); - - describe('userOp values', function () { - describe('intiCode', function () { - beforeEach(async function () { - this.userOp = new UserOperation({ - sender: this.sender, - nonce: 1, - verificationGas: 0x12345678n, - factory: this.factory, - factoryData: '0x123456', - }); - - this.emptyUserOp = new UserOperation({ - sender: this.sender, - nonce: 1, - }); - }); - - it('returns factory', async function () { - await expect(this.utils.$factory(this.userOp.packed)).to.eventually.equal(this.factory); - await expect(this.utils.$factory(this.emptyUserOp.packed)).to.eventually.equal(ethers.ZeroAddress); - }); - - it('returns factoryData', async function () { - await expect(this.utils.$factoryData(this.userOp.packed)).to.eventually.equal('0x123456'); - await expect(this.utils.$factoryData(this.emptyUserOp.packed)).to.eventually.equal('0x'); - }); - }); - - it('returns verificationGasLimit', async function () { - const userOp = new UserOperation({ sender: this.sender, nonce: 1, verificationGas: 0x12345678n }); - await expect(this.utils.$verificationGasLimit(userOp.packed)).to.eventually.equal(userOp.verificationGas); - }); - - it('returns callGasLimit', async function () { - const userOp = new UserOperation({ sender: this.sender, nonce: 1, callGas: 0x12345678n }); - await expect(this.utils.$callGasLimit(userOp.packed)).to.eventually.equal(userOp.callGas); - }); - - it('returns maxPriorityFeePerGas', async function () { - const userOp = new UserOperation({ sender: this.sender, nonce: 1, maxPriorityFee: 0x12345678n }); - await expect(this.utils.$maxPriorityFeePerGas(userOp.packed)).to.eventually.equal(userOp.maxPriorityFee); - }); - - it('returns maxFeePerGas', async function () { - const userOp = new UserOperation({ sender: this.sender, nonce: 1, maxFeePerGas: 0x12345678n }); - await expect(this.utils.$maxFeePerGas(userOp.packed)).to.eventually.equal(userOp.maxFeePerGas); - }); - - it('returns gasPrice', async function () { - const userOp = new UserOperation({ - sender: this.sender, - nonce: 1, - maxPriorityFee: 0x12345678n, - maxFeePerGas: 0x87654321n, - }); - await expect(this.utils.$gasPrice(userOp.packed)).to.eventually.equal(userOp.maxPriorityFee); - }); - - describe('paymasterAndData', function () { - beforeEach(async function () { - this.userOp = new UserOperation({ - sender: this.sender, - nonce: 1, - paymaster: this.paymaster, - paymasterVerificationGasLimit: 0x12345678n, - paymasterPostOpGasLimit: 0x87654321n, - paymasterData: '0xbeefcafe', - }); - - this.emptyUserOp = new UserOperation({ - sender: this.sender, - nonce: 1, - }); - }); - - it('returns paymaster', async function () { - await expect(this.utils.$paymaster(this.userOp.packed)).to.eventually.equal(this.userOp.paymaster); - await expect(this.utils.$paymaster(this.emptyUserOp.packed)).to.eventually.equal(ethers.ZeroAddress); - }); - - it('returns verificationGasLimit', async function () { - await expect(this.utils.$paymasterVerificationGasLimit(this.userOp.packed)).to.eventually.equal( - this.userOp.paymasterVerificationGasLimit, - ); - await expect(this.utils.$paymasterVerificationGasLimit(this.emptyUserOp.packed)).to.eventually.equal(0n); - }); - - it('returns postOpGasLimit', async function () { - await expect(this.utils.$paymasterPostOpGasLimit(this.userOp.packed)).to.eventually.equal( - this.userOp.paymasterPostOpGasLimit, - ); - await expect(this.utils.$paymasterPostOpGasLimit(this.emptyUserOp.packed)).to.eventually.equal(0n); - }); - - it('returns data', async function () { - await expect(this.utils.$paymasterData(this.userOp.packed)).to.eventually.equal(this.userOp.paymasterData); - await expect(this.utils.$paymasterData(this.emptyUserOp.packed)).to.eventually.equal('0x'); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.t.sol deleted file mode 100644 index bc69e4c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.t.sol +++ /dev/null @@ -1,418 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.24; - -// Parts of this test file are adapted from Adam Egyed (@adamegyed) proof of concept available at: -// https://github.com/adamegyed/erc7579-execute-vulnerability/tree/4589a30ff139e143d6c57183ac62b5c029217a90 -// -// solhint-disable no-console - -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; -import {PackedUserOperation, IAccount, IEntryPoint} from "@openzeppelin/contracts/interfaces/draft-IERC4337.sol"; -import {ERC4337Utils} from "@openzeppelin/contracts/account/utils/draft-ERC4337Utils.sol"; -import {ERC7579Utils, Mode, CallType, ExecType, ModeSelector, ModePayload, Execution} from "@openzeppelin/contracts/account/utils/draft-ERC7579Utils.sol"; -import {Test, Vm, console} from "forge-std/Test.sol"; - -contract SampleAccount is IAccount, Ownable { - using ECDSA for *; - using MessageHashUtils for *; - using ERC4337Utils for *; - using ERC7579Utils for *; - - event Log(bool duringValidation, Execution[] calls); - - error UnsupportedCallType(CallType callType); - - constructor(address initialOwner) Ownable(initialOwner) {} - - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash, - uint256 missingAccountFunds - ) external override returns (uint256 validationData) { - require(msg.sender == address(ERC4337Utils.ENTRYPOINT_V07), "only from EP"); - // Check signature - if (userOpHash.toEthSignedMessageHash().recover(userOp.signature) != owner()) { - revert OwnableUnauthorizedAccount(_msgSender()); - } - - // If this is an execute call with a batch operation, log the call details from the calldata - if (bytes4(userOp.callData[0x00:0x04]) == this.execute.selector) { - (CallType callType, , , ) = Mode.wrap(bytes32(userOp.callData[0x04:0x24])).decodeMode(); - - if (callType == ERC7579Utils.CALLTYPE_BATCH) { - // Remove the selector - bytes calldata params = userOp.callData[0x04:]; - - // Use the same vulnerable assignment technique here, but assert afterwards that the checks aren't - // broken here by comparing to the result of `abi.decode(...)`. - bytes calldata executionCalldata; - assembly ("memory-safe") { - let dataptr := add(params.offset, calldataload(add(params.offset, 0x20))) - executionCalldata.offset := add(dataptr, 32) - executionCalldata.length := calldataload(dataptr) - } - // Check that this decoding step is done correctly. - (, bytes memory executionCalldataMemory) = abi.decode(params, (bytes32, bytes)); - - require( - keccak256(executionCalldata) == keccak256(executionCalldataMemory), - "decoding during validation failed" - ); - // Now, we know that we have `bytes calldata executionCalldata` as would be decoded by the solidity - // builtin decoder for the `execute` function. - - // This is where the vulnerability from ExecutionLib results in a different result between validation - // and execution. - - emit Log(true, executionCalldata.decodeBatch()); - } - } - - if (missingAccountFunds > 0) { - (bool success, ) = payable(msg.sender).call{value: missingAccountFunds}(""); - success; // Silence warning. The entrypoint should validate the result. - } - - return ERC4337Utils.SIG_VALIDATION_SUCCESS; - } - - function execute(Mode mode, bytes calldata executionCalldata) external payable { - require(msg.sender == address(this) || msg.sender == address(ERC4337Utils.ENTRYPOINT_V07), "not auth"); - - (CallType callType, ExecType execType, , ) = mode.decodeMode(); - - // check if calltype is batch or single - if (callType == ERC7579Utils.CALLTYPE_SINGLE) { - executionCalldata.execSingle(execType); - } else if (callType == ERC7579Utils.CALLTYPE_BATCH) { - executionCalldata.execBatch(execType); - - emit Log(false, executionCalldata.decodeBatch()); - } else if (callType == ERC7579Utils.CALLTYPE_DELEGATECALL) { - executionCalldata.execDelegateCall(execType); - } else { - revert UnsupportedCallType(callType); - } - } -} - -contract ERC7579UtilsTest is Test { - using MessageHashUtils for *; - using ERC4337Utils for *; - using ERC7579Utils for *; - - address private _owner; - uint256 private _ownerKey; - address private _account; - address private _beneficiary; - address private _recipient1; - address private _recipient2; - - constructor() { - vm.etch(0x0000000071727De22E5E9d8BAf0edAc6f37da032, vm.readFileBinary("test/bin/EntryPoint070.bytecode")); - vm.etch(0xEFC2c1444eBCC4Db75e7613d20C6a62fF67A167C, vm.readFileBinary("test/bin/SenderCreator070.bytecode")); - - // signing key - (_owner, _ownerKey) = makeAddrAndKey("owner"); - - // ERC-4337 account - _account = address(new SampleAccount(_owner)); - vm.deal(_account, 1 ether); - - // other - _beneficiary = makeAddr("beneficiary"); - _recipient1 = makeAddr("recipient1"); - _recipient2 = makeAddr("recipient2"); - } - - function testExecuteBatchDecodeCorrectly() public { - Execution[] memory calls = new Execution[](2); - calls[0] = Execution({target: _recipient1, value: 1 wei, callData: ""}); - calls[1] = Execution({target: _recipient2, value: 1 wei, callData: ""}); - - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = PackedUserOperation({ - sender: _account, - nonce: 0, - initCode: "", - callData: abi.encodeCall( - SampleAccount.execute, - ( - ERC7579Utils.encodeMode( - ERC7579Utils.CALLTYPE_BATCH, - ERC7579Utils.EXECTYPE_DEFAULT, - ModeSelector.wrap(0x00), - ModePayload.wrap(0x00) - ), - ERC7579Utils.encodeBatch(calls) - ) - ), - accountGasLimits: _packGas(500_000, 500_000), - preVerificationGas: 0, - gasFees: _packGas(1, 1), - paymasterAndData: "", - signature: "" - }); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign( - _ownerKey, - this.hashUserOperation(userOps[0]).toEthSignedMessageHash() - ); - userOps[0].signature = abi.encodePacked(r, s, v); - - vm.recordLogs(); - ERC4337Utils.ENTRYPOINT_V07.handleOps(userOps, payable(_beneficiary)); - - assertEq(_recipient1.balance, 1 wei); - assertEq(_recipient2.balance, 1 wei); - - _collectAndPrintLogs(false); - } - - function testExecuteBatchDecodeEmpty() public { - bytes memory fakeCalls = abi.encodePacked( - uint256(1), // Length of execution[] - uint256(0x20), // offset - uint256(uint160(_recipient1)), // target - uint256(1), // value: 1 wei - uint256(0x60), // offset of data - uint256(0) // length of - ); - - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = PackedUserOperation({ - sender: _account, - nonce: 0, - initCode: "", - callData: abi.encodeCall( - SampleAccount.execute, - ( - ERC7579Utils.encodeMode( - ERC7579Utils.CALLTYPE_BATCH, - ERC7579Utils.EXECTYPE_DEFAULT, - ModeSelector.wrap(0x00), - ModePayload.wrap(0x00) - ), - abi.encodePacked( - uint256(0x70) // fake offset pointing to paymasterAndData - ) - ) - ), - accountGasLimits: _packGas(500_000, 500_000), - preVerificationGas: 0, - gasFees: _packGas(1, 1), - paymasterAndData: abi.encodePacked(address(0), fakeCalls), - signature: "" - }); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign( - _ownerKey, - this.hashUserOperation(userOps[0]).toEthSignedMessageHash() - ); - userOps[0].signature = abi.encodePacked(r, s, v); - - vm.expectRevert( - abi.encodeWithSelector( - IEntryPoint.FailedOpWithRevert.selector, - 0, - "AA23 reverted", - abi.encodeWithSelector(ERC7579Utils.ERC7579DecodingError.selector) - ) - ); - ERC4337Utils.ENTRYPOINT_V07.handleOps(userOps, payable(_beneficiary)); - - _collectAndPrintLogs(false); - } - - function testExecuteBatchDecodeDifferent() public { - bytes memory execCallData = abi.encodePacked( - uint256(0x20), // offset pointing to the next segment - uint256(5), // Length of execution[] - uint256(0), // offset of calls[0], and target (!!) - uint256(0x20), // offset of calls[1], and value (!!) - uint256(0), // offset of calls[2], and rel offset of data (!!) - uint256(0) // offset of calls[3]. - // There is one more to read by the array length, but it's not present here. This will be - // paymasterAndData.length during validation, pointing to an all-zero call. - // During execution, the offset will be 0, pointing to a call with value. - ); - - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = PackedUserOperation({ - sender: _account, - nonce: 0, - initCode: "", - callData: abi.encodePacked( - SampleAccount.execute.selector, - ERC7579Utils.encodeMode( - ERC7579Utils.CALLTYPE_BATCH, - ERC7579Utils.EXECTYPE_DEFAULT, - ModeSelector.wrap(0x00), - ModePayload.wrap(0x00) - ), - uint256(0x5c), // offset pointing to the next segment - uint224(type(uint224).max), // Padding to align the `bytes` types - // type(uint256).max, // unknown padding - uint256(execCallData.length), // Length of the data - execCallData - ), - accountGasLimits: _packGas(500_000, 500_000), - preVerificationGas: 0, - gasFees: _packGas(1, 1), - paymasterAndData: abi.encodePacked(uint256(0), uint256(0)), // padding length to create an offset - signature: "" - }); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign( - _ownerKey, - this.hashUserOperation(userOps[0]).toEthSignedMessageHash() - ); - userOps[0].signature = abi.encodePacked(r, s, v); - - vm.expectRevert( - abi.encodeWithSelector( - IEntryPoint.FailedOpWithRevert.selector, - 0, - "AA23 reverted", - abi.encodeWithSelector(ERC7579Utils.ERC7579DecodingError.selector) - ) - ); - ERC4337Utils.ENTRYPOINT_V07.handleOps(userOps, payable(_beneficiary)); - - _collectAndPrintLogs(true); - } - - function testDecodeBatch() public { - // BAD: buffer empty - vm.expectRevert(ERC7579Utils.ERC7579DecodingError.selector); - this.callDecodeBatch(""); - - // BAD: buffer too short - vm.expectRevert(ERC7579Utils.ERC7579DecodingError.selector); - this.callDecodeBatch(abi.encodePacked(uint128(0))); - - // GOOD - this.callDecodeBatch(abi.encode(0)); - // Note: Solidity also supports this even though it's odd. Offset 0 means array is at the same location, which - // is interpreted as an array of length 0, which doesn't require any more data - // solhint-disable-next-line var-name-mixedcase - uint256[] memory _1 = abi.decode(abi.encode(0), (uint256[])); - _1; - - // BAD: offset is out of bounds - vm.expectRevert(ERC7579Utils.ERC7579DecodingError.selector); - this.callDecodeBatch(abi.encode(1)); - - // GOOD - this.callDecodeBatch(abi.encode(32, 0)); - - // BAD: reported array length extends beyond bounds - vm.expectRevert(ERC7579Utils.ERC7579DecodingError.selector); - this.callDecodeBatch(abi.encode(32, 1)); - - // GOOD - this.callDecodeBatch(abi.encode(32, 1, 0)); - - // GOOD - // - // 0000000000000000000000000000000000000000000000000000000000000020 (32) offset - // 0000000000000000000000000000000000000000000000000000000000000001 ( 1) array length - // 0000000000000000000000000000000000000000000000000000000000000020 (32) element 0 offset - // 000000000000000000000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (recipient) target for element #0 - // 000000000000000000000000000000000000000000000000000000000000002a (42) value for element #0 - // 0000000000000000000000000000000000000000000000000000000000000060 (96) offset to calldata for element #0 - // 000000000000000000000000000000000000000000000000000000000000000c (12) length of the calldata for element #0 - // 48656c6c6f20576f726c64210000000000000000000000000000000000000000 (..) buffer for the calldata for element #0 - assertEq( - bytes("Hello World!"), - this.callDecodeBatchAndGetFirstBytes( - abi.encode(32, 1, 32, _recipient1, 42, 96, 12, bytes12("Hello World!")) - ) - ); - - // This is invalid, the first element of the array points is out of bounds - // but we allow it past initial validation, because solidity will validate later when the bytes field is accessed - // - // 0000000000000000000000000000000000000000000000000000000000000020 (32) offset - // 0000000000000000000000000000000000000000000000000000000000000001 ( 1) array length - // 0000000000000000000000000000000000000000000000000000000000000020 (32) element 0 offset - // - bytes memory invalid = abi.encode(32, 1, 32); - this.callDecodeBatch(invalid); - vm.expectRevert(); - this.callDecodeBatchAndGetFirst(invalid); - - // this is invalid: the bytes field of the first element of the array is out of bounds - // but we allow it past initial validation, because solidity will validate later when the bytes field is accessed - // - // 0000000000000000000000000000000000000000000000000000000000000020 (32) offset - // 0000000000000000000000000000000000000000000000000000000000000001 ( 1) array length - // 0000000000000000000000000000000000000000000000000000000000000020 (32) element 0 offset - // 000000000000000000000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (recipient) target for element #0 - // 000000000000000000000000000000000000000000000000000000000000002a (42) value for element #0 - // 0000000000000000000000000000000000000000000000000000000000000060 (96) offset to calldata for element #0 - // - bytes memory invalidDeeply = abi.encode(32, 1, 32, _recipient1, 42, 96); - this.callDecodeBatch(invalidDeeply); - // Note that this is ok because we don't return the value. Returning it would introduce a check that would fails. - this.callDecodeBatchAndGetFirst(invalidDeeply); - vm.expectRevert(); - this.callDecodeBatchAndGetFirstBytes(invalidDeeply); - } - - function callDecodeBatch(bytes calldata executionCalldata) public pure { - ERC7579Utils.decodeBatch(executionCalldata); - } - - function callDecodeBatchAndGetFirst(bytes calldata executionCalldata) public pure { - ERC7579Utils.decodeBatch(executionCalldata)[0]; - } - - function callDecodeBatchAndGetFirstBytes(bytes calldata executionCalldata) public pure returns (bytes calldata) { - return ERC7579Utils.decodeBatch(executionCalldata)[0].callData; - } - - function hashUserOperation(PackedUserOperation calldata useroperation) public view returns (bytes32) { - return useroperation.hash(address(ERC4337Utils.ENTRYPOINT_V07)); - } - - function _collectAndPrintLogs(bool includeTotalValue) internal { - Vm.Log[] memory logs = vm.getRecordedLogs(); - for (uint256 i = 0; i < logs.length; i++) { - if (logs[i].emitter == _account) { - _printDecodedCalls(logs[i].data, includeTotalValue); - } - } - } - - function _printDecodedCalls(bytes memory logData, bool includeTotalValue) internal pure { - (bool duringValidation, Execution[] memory calls) = abi.decode(logData, (bool, Execution[])); - - console.log( - string.concat( - "Batch execute contents, as read during ", - duringValidation ? "validation" : "execution", - ": " - ) - ); - console.log(" Execution[] length: %s", calls.length); - - uint256 totalValue = 0; - for (uint256 i = 0; i < calls.length; ++i) { - console.log(string.concat(" calls[", vm.toString(i), "].target = ", vm.toString(calls[i].target))); - console.log(string.concat(" calls[", vm.toString(i), "].value = ", vm.toString(calls[i].value))); - console.log(string.concat(" calls[", vm.toString(i), "].data = ", vm.toString(calls[i].callData))); - totalValue += calls[i].value; - } - - if (includeTotalValue) { - console.log(" Total value: %s", totalValue); - } - } - - function _packGas(uint256 upper, uint256 lower) internal pure returns (bytes32) { - return bytes32(uint256((upper << 128) | uint128(lower))); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.test.js deleted file mode 100644 index b0ca86c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/account/utils/draft-ERC7579Utils.test.js +++ /dev/null @@ -1,399 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { - CALL_TYPE_CALL, - CALL_TYPE_BATCH, - CALL_TYPE_DELEGATE, - EXEC_TYPE_DEFAULT, - EXEC_TYPE_TRY, - encodeSingle, - encodeBatch, - encodeDelegate, - encodeMode, -} = require('../../helpers/erc7579'); -const { selector } = require('../../helpers/methods'); - -const coder = ethers.AbiCoder.defaultAbiCoder(); - -const fixture = async () => { - const [sender] = await ethers.getSigners(); - const utils = await ethers.deployContract('$ERC7579Utils', { value: ethers.parseEther('1') }); - const utilsGlobal = await ethers.deployContract('$ERC7579UtilsGlobalMock'); - const target = await ethers.deployContract('CallReceiverMock'); - const anotherTarget = await ethers.deployContract('CallReceiverMock'); - return { utils, utilsGlobal, target, anotherTarget, sender }; -}; - -describe('ERC7579Utils', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('constants', async function () { - await expect(this.utils.$CALLTYPE_SINGLE()).to.eventually.equal(CALL_TYPE_CALL); - await expect(this.utils.$CALLTYPE_BATCH()).to.eventually.equal(CALL_TYPE_BATCH); - await expect(this.utils.$CALLTYPE_DELEGATECALL()).to.eventually.equal(CALL_TYPE_DELEGATE); - await expect(this.utils.$EXECTYPE_DEFAULT()).to.eventually.equal(EXEC_TYPE_DEFAULT); - await expect(this.utils.$EXECTYPE_TRY()).to.eventually.equal(EXEC_TYPE_TRY); - }); - - describe('execSingle', function () { - it('calls the target with value', async function () { - const value = 0x012; - const data = encodeSingle(this.target, value, this.target.interface.encodeFunctionData('mockFunction')); - - await expect(this.utils.$execSingle(data, EXEC_TYPE_DEFAULT)).to.emit(this.target, 'MockFunctionCalled'); - - await expect(ethers.provider.getBalance(this.target)).to.eventually.equal(value); - }); - - it('calls the target with value and args', async function () { - const value = 0x432; - const data = encodeSingle( - this.target, - value, - this.target.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234']), - ); - - await expect(this.utils.$execSingle(data, EXEC_TYPE_DEFAULT)) - .to.emit(this.target, 'MockFunctionCalledWithArgs') - .withArgs(42, '0x1234'); - - await expect(ethers.provider.getBalance(this.target)).to.eventually.equal(value); - }); - - it('default to calling self is target is address(0) (ERC-7821 calldata compression)', async function () { - const data = encodeSingle( - ethers.ZeroAddress, // address(0) - 0, - this.utils.interface.encodeFunctionData('$CALLTYPE_SINGLE', []), - ); - - await expect(this.utils.$execSingle(data, EXEC_TYPE_DEFAULT)) - .to.emit(this.utils, 'return$execSingle') - .withArgs([ethers.zeroPadBytes(CALL_TYPE_CALL, 32)]); - }); - - it('reverts when target reverts in default ExecType', async function () { - const value = 0x012; - const data = encodeSingle( - this.target, - value, - this.target.interface.encodeFunctionData('mockFunctionRevertsReason'), - ); - - await expect(this.utils.$execSingle(data, EXEC_TYPE_DEFAULT)).to.be.revertedWith('CallReceiverMock: reverting'); - }); - - it('emits ERC7579TryExecuteFail event when target reverts in try ExecType', async function () { - const value = 0x012; - const data = encodeSingle( - this.target, - value, - this.target.interface.encodeFunctionData('mockFunctionRevertsReason'), - ); - - await expect(this.utils.$execSingle(data, EXEC_TYPE_TRY)) - .to.emit(this.utils, 'ERC7579TryExecuteFail') - .withArgs( - CALL_TYPE_CALL, - ethers.solidityPacked( - ['bytes4', 'bytes'], - [selector('Error(string)'), coder.encode(['string'], ['CallReceiverMock: reverting'])], - ), - ); - }); - - it('reverts with an invalid exec type', async function () { - const value = 0x012; - const data = encodeSingle(this.target, value, this.target.interface.encodeFunctionData('mockFunction')); - - await expect(this.utils.$execSingle(data, '0x03')) - .to.be.revertedWithCustomError(this.utils, 'ERC7579UnsupportedExecType') - .withArgs('0x03'); - }); - }); - - describe('execBatch', function () { - it('calls the targets with value', async function () { - const value1 = 0x012; - const value2 = 0x234; - const data = encodeBatch( - [this.target, value1, this.target.interface.encodeFunctionData('mockFunction')], - [this.anotherTarget, value2, this.anotherTarget.interface.encodeFunctionData('mockFunction')], - ); - - await expect(this.utils.$execBatch(data, EXEC_TYPE_DEFAULT)) - .to.emit(this.target, 'MockFunctionCalled') - .to.emit(this.anotherTarget, 'MockFunctionCalled'); - - await expect(ethers.provider.getBalance(this.target)).to.eventually.equal(value1); - await expect(ethers.provider.getBalance(this.anotherTarget)).to.eventually.equal(value2); - }); - - it('calls the targets with value and args', async function () { - const value1 = 0x012; - const value2 = 0x234; - const data = encodeBatch( - [this.target, value1, this.target.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234'])], - [ - this.anotherTarget, - value2, - this.anotherTarget.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234']), - ], - ); - - await expect(this.utils.$execBatch(data, EXEC_TYPE_DEFAULT)) - .to.emit(this.target, 'MockFunctionCalledWithArgs') - .to.emit(this.anotherTarget, 'MockFunctionCalledWithArgs'); - - await expect(ethers.provider.getBalance(this.target)).to.eventually.equal(value1); - await expect(ethers.provider.getBalance(this.anotherTarget)).to.eventually.equal(value2); - }); - - it('default to calling self is target is address(0) (ERC-7821 calldata compression)', async function () { - const data = encodeBatch( - [ethers.ZeroAddress, 0, this.utils.interface.encodeFunctionData('$CALLTYPE_SINGLE', [])], - [ethers.ZeroAddress, 0, this.utils.interface.encodeFunctionData('$CALLTYPE_BATCH', [])], - ); - - await expect(this.utils.$execBatch(data, EXEC_TYPE_DEFAULT)) - .to.emit(this.utils, 'return$execBatch') - .withArgs([ethers.zeroPadBytes(CALL_TYPE_CALL, 32), ethers.zeroPadBytes(CALL_TYPE_BATCH, 32)]); - }); - - it('reverts when any target reverts in default ExecType', async function () { - const value1 = 0x012; - const value2 = 0x234; - const data = encodeBatch( - [this.target, value1, this.target.interface.encodeFunctionData('mockFunction')], - [this.anotherTarget, value2, this.anotherTarget.interface.encodeFunctionData('mockFunctionRevertsReason')], - ); - - await expect(this.utils.$execBatch(data, EXEC_TYPE_DEFAULT)).to.be.revertedWith('CallReceiverMock: reverting'); - }); - - it('emits ERC7579TryExecuteFail event when any target reverts in try ExecType', async function () { - const value1 = 0x012; - const value2 = 0x234; - const data = encodeBatch( - [this.target, value1, this.target.interface.encodeFunctionData('mockFunction')], - [this.anotherTarget, value2, this.anotherTarget.interface.encodeFunctionData('mockFunctionRevertsReason')], - ); - - await expect(this.utils.$execBatch(data, EXEC_TYPE_TRY)) - .to.emit(this.utils, 'ERC7579TryExecuteFail') - .withArgs( - CALL_TYPE_BATCH, - ethers.solidityPacked( - ['bytes4', 'bytes'], - [selector('Error(string)'), coder.encode(['string'], ['CallReceiverMock: reverting'])], - ), - ); - - // Check balances - await expect(ethers.provider.getBalance(this.target)).to.eventually.equal(value1); - await expect(ethers.provider.getBalance(this.anotherTarget)).to.eventually.equal(0); - }); - - it('reverts with an invalid exec type', async function () { - const value1 = 0x012; - const value2 = 0x234; - const data = encodeBatch( - [this.target, value1, this.target.interface.encodeFunctionData('mockFunction')], - [this.anotherTarget, value2, this.anotherTarget.interface.encodeFunctionData('mockFunction')], - ); - - await expect(this.utils.$execBatch(data, '0x03')) - .to.be.revertedWithCustomError(this.utils, 'ERC7579UnsupportedExecType') - .withArgs('0x03'); - }); - }); - - describe('execDelegateCall', function () { - it('delegate calls the target', async function () { - const slot = ethers.hexlify(ethers.randomBytes(32)); - const value = ethers.hexlify(ethers.randomBytes(32)); - const data = encodeDelegate( - this.target, - this.target.interface.encodeFunctionData('mockFunctionWritesStorage', [slot, value]), - ); - - await expect(ethers.provider.getStorage(this.utils.target, slot)).to.eventually.equal(ethers.ZeroHash); - await this.utils.$execDelegateCall(data, EXEC_TYPE_DEFAULT); - await expect(ethers.provider.getStorage(this.utils.target, slot)).to.eventually.equal(value); - }); - - it('default to calling self is target is address(0) (ERC-7821 calldata compression)', async function () { - const data = encodeDelegate( - ethers.ZeroAddress, - this.utils.interface.encodeFunctionData('$CALLTYPE_DELEGATECALL', []), - ); - - await expect(this.utils.$execDelegateCall(data, EXEC_TYPE_DEFAULT)) - .to.emit(this.utils, 'return$execDelegateCall') - .withArgs([ethers.zeroPadBytes(CALL_TYPE_DELEGATE, 32)]); - }); - - it('reverts when target reverts in default ExecType', async function () { - const data = encodeDelegate(this.target, this.target.interface.encodeFunctionData('mockFunctionRevertsReason')); - await expect(this.utils.$execDelegateCall(data, EXEC_TYPE_DEFAULT)).to.be.revertedWith( - 'CallReceiverMock: reverting', - ); - }); - - it('emits ERC7579TryExecuteFail event when target reverts in try ExecType', async function () { - const data = encodeDelegate(this.target, this.target.interface.encodeFunctionData('mockFunctionRevertsReason')); - await expect(this.utils.$execDelegateCall(data, EXEC_TYPE_TRY)) - .to.emit(this.utils, 'ERC7579TryExecuteFail') - .withArgs( - CALL_TYPE_CALL, - ethers.solidityPacked( - ['bytes4', 'bytes'], - [selector('Error(string)'), coder.encode(['string'], ['CallReceiverMock: reverting'])], - ), - ); - }); - - it('reverts with an invalid exec type', async function () { - const data = encodeDelegate(this.target, this.target.interface.encodeFunctionData('mockFunction')); - await expect(this.utils.$execDelegateCall(data, '0x03')) - .to.be.revertedWithCustomError(this.utils, 'ERC7579UnsupportedExecType') - .withArgs('0x03'); - }); - }); - - it('encodes Mode', async function () { - const callType = CALL_TYPE_BATCH; - const execType = EXEC_TYPE_TRY; - const selector = '0x12345678'; - const payload = ethers.toBeHex(0, 22); - - await expect(this.utils.$encodeMode(callType, execType, selector, payload)).to.eventually.equal( - encodeMode({ - callType, - execType, - selector, - payload, - }), - ); - }); - - it('decodes Mode', async function () { - const callType = CALL_TYPE_BATCH; - const execType = EXEC_TYPE_TRY; - const selector = '0x12345678'; - const payload = ethers.toBeHex(0, 22); - - await expect( - this.utils.$decodeMode( - encodeMode({ - callType, - execType, - selector, - payload, - }), - ), - ).to.eventually.deep.equal([callType, execType, selector, payload]); - }); - - it('encodes single', async function () { - const target = this.target; - const value = 0x123; - const data = '0x12345678'; - - await expect(this.utils.$encodeSingle(target, value, data)).to.eventually.equal(encodeSingle(target, value, data)); - }); - - it('decodes single', async function () { - const target = this.target; - const value = 0x123; - const data = '0x12345678'; - - await expect(this.utils.$decodeSingle(encodeSingle(target, value, data))).to.eventually.deep.equal([ - target.target, - value, - data, - ]); - }); - - it('encodes batch', async function () { - const entries = [ - [this.target, 0x123, '0x12345678'], - [this.anotherTarget, 0x456, '0x12345678'], - ]; - - await expect(this.utils.$encodeBatch(entries)).to.eventually.equal(encodeBatch(...entries)); - }); - - it('decodes batch', async function () { - const entries = [ - [this.target.target, 0x123, '0x12345678'], - [this.anotherTarget.target, 0x456, '0x12345678'], - ]; - - await expect(this.utils.$decodeBatch(encodeBatch(...entries))).to.eventually.deep.equal(entries); - }); - - it('encodes delegate', async function () { - const target = this.target; - const data = '0x12345678'; - - await expect(this.utils.$encodeDelegate(target, data)).to.eventually.equal(encodeDelegate(target, data)); - }); - - it('decodes delegate', async function () { - const target = this.target; - const data = '0x12345678'; - - await expect(this.utils.$decodeDelegate(encodeDelegate(target, data))).to.eventually.deep.equal([ - target.target, - data, - ]); - }); - - describe('global', function () { - describe('eqCallTypeGlobal', function () { - it('returns true if both call types are equal', async function () { - await expect(this.utilsGlobal.$eqCallTypeGlobal(CALL_TYPE_BATCH, CALL_TYPE_BATCH)).to.eventually.be.true; - }); - - it('returns false if both call types are different', async function () { - await expect(this.utilsGlobal.$eqCallTypeGlobal(CALL_TYPE_CALL, CALL_TYPE_BATCH)).to.eventually.be.false; - }); - }); - - describe('eqExecTypeGlobal', function () { - it('returns true if both exec types are equal', async function () { - await expect(this.utilsGlobal.$eqExecTypeGlobal(EXEC_TYPE_TRY, EXEC_TYPE_TRY)).to.eventually.be.true; - }); - - it('returns false if both exec types are different', async function () { - await expect(this.utilsGlobal.$eqExecTypeGlobal(EXEC_TYPE_DEFAULT, EXEC_TYPE_TRY)).to.eventually.be.false; - }); - }); - - describe('eqModeSelectorGlobal', function () { - it('returns true if both selectors are equal', async function () { - await expect(this.utilsGlobal.$eqModeSelectorGlobal('0x12345678', '0x12345678')).to.eventually.be.true; - }); - - it('returns false if both selectors are different', async function () { - await expect(this.utilsGlobal.$eqModeSelectorGlobal('0x12345678', '0x87654321')).to.eventually.be.false; - }); - }); - - describe('eqModePayloadGlobal', function () { - it('returns true if both payloads are equal', async function () { - await expect(this.utilsGlobal.$eqModePayloadGlobal(ethers.toBeHex(0, 22), ethers.toBeHex(0, 22))).to.eventually - .be.true; - }); - - it('returns false if both payloads are different', async function () { - await expect(this.utilsGlobal.$eqModePayloadGlobal(ethers.toBeHex(0, 22), ethers.toBeHex(1, 22))).to.eventually - .be.false; - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint070.abi b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint070.abi deleted file mode 100644 index 3f3b1d6..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint070.abi +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"ret","type":"bytes"}],"name":"DelegateAndRevert","type":"error"},{"inputs":[{"internalType":"uint256","name":"opIndex","type":"uint256"},{"internalType":"string","name":"reason","type":"string"}],"name":"FailedOp","type":"error"},{"inputs":[{"internalType":"uint256","name":"opIndex","type":"uint256"},{"internalType":"string","name":"reason","type":"string"},{"internalType":"bytes","name":"inner","type":"bytes"}],"name":"FailedOpWithRevert","type":"error"},{"inputs":[{"internalType":"bytes","name":"returnData","type":"bytes"}],"name":"PostOpReverted","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"SenderAddressResult","type":"error"},{"inputs":[{"internalType":"address","name":"aggregator","type":"address"}],"name":"SignatureValidationFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"factory","type":"address"},{"indexed":false,"internalType":"address","name":"paymaster","type":"address"}],"name":"AccountDeployed","type":"event"},{"anonymous":false,"inputs":[],"name":"BeforeExecution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalDeposit","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"revertReason","type":"bytes"}],"name":"PostOpRevertReason","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"aggregator","type":"address"}],"name":"SignatureAggregatorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalStaked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unstakeDelaySec","type":"uint256"}],"name":"StakeLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawTime","type":"uint256"}],"name":"StakeUnlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"paymaster","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint256","name":"actualGasCost","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"actualGasUsed","type":"uint256"}],"name":"UserOperationEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"UserOperationPrefundTooLow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"revertReason","type":"bytes"}],"name":"UserOperationRevertReason","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"uint32","name":"unstakeDelaySec","type":"uint32"}],"name":"addStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"delegateAndRevert","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"depositTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deposits","outputs":[{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"bool","name":"staked","type":"bool"},{"internalType":"uint112","name":"stake","type":"uint112"},{"internalType":"uint32","name":"unstakeDelaySec","type":"uint32"},{"internalType":"uint48","name":"withdrawTime","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getDepositInfo","outputs":[{"components":[{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"bool","name":"staked","type":"bool"},{"internalType":"uint112","name":"stake","type":"uint112"},{"internalType":"uint32","name":"unstakeDelaySec","type":"uint32"},{"internalType":"uint48","name":"withdrawTime","type":"uint48"}],"internalType":"struct IStakeManager.DepositInfo","name":"info","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint192","name":"key","type":"uint192"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"initCode","type":"bytes"}],"name":"getSenderAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation","name":"userOp","type":"tuple"}],"name":"getUserOpHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation[]","name":"userOps","type":"tuple[]"},{"internalType":"contract IAggregator","name":"aggregator","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IEntryPoint.UserOpsPerAggregator[]","name":"opsPerAggregator","type":"tuple[]"},{"internalType":"address payable","name":"beneficiary","type":"address"}],"name":"handleAggregatedOps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation[]","name":"ops","type":"tuple[]"},{"internalType":"address payable","name":"beneficiary","type":"address"}],"name":"handleOps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint192","name":"key","type":"uint192"}],"name":"incrementNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"callData","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"verificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"callGasLimit","type":"uint256"},{"internalType":"uint256","name":"paymasterVerificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"paymasterPostOpGasLimit","type":"uint256"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"}],"internalType":"struct EntryPoint.MemoryUserOp","name":"mUserOp","type":"tuple"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"uint256","name":"prefund","type":"uint256"},{"internalType":"uint256","name":"contextOffset","type":"uint256"},{"internalType":"uint256","name":"preOpGas","type":"uint256"}],"internalType":"struct EntryPoint.UserOpInfo","name":"opInfo","type":"tuple"},{"internalType":"bytes","name":"context","type":"bytes"}],"name":"innerHandleOp","outputs":[{"internalType":"uint256","name":"actualGasCost","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint192","name":"","type":"uint192"}],"name":"nonceSequenceNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unlockStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawAddress","type":"address"}],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawAddress","type":"address"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"withdrawTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint070.bytecode b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint070.bytecode deleted file mode 100644 index fce261af5dc93a09c7ab25cd89463d1b23c5a223..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16035 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 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint080.abi b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint080.abi deleted file mode 100644 index 22fd32c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint080.abi +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"ret","type":"bytes"}],"name":"DelegateAndRevert","type":"error"},{"inputs":[{"internalType":"uint256","name":"opIndex","type":"uint256"},{"internalType":"string","name":"reason","type":"string"}],"name":"FailedOp","type":"error"},{"inputs":[{"internalType":"uint256","name":"opIndex","type":"uint256"},{"internalType":"string","name":"reason","type":"string"},{"internalType":"bytes","name":"inner","type":"bytes"}],"name":"FailedOpWithRevert","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[{"internalType":"bytes","name":"returnData","type":"bytes"}],"name":"PostOpReverted","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"SenderAddressResult","type":"error"},{"inputs":[{"internalType":"address","name":"aggregator","type":"address"}],"name":"SignatureValidationFailed","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"factory","type":"address"},{"indexed":false,"internalType":"address","name":"paymaster","type":"address"}],"name":"AccountDeployed","type":"event"},{"anonymous":false,"inputs":[],"name":"BeforeExecution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalDeposit","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"revertReason","type":"bytes"}],"name":"PostOpRevertReason","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"aggregator","type":"address"}],"name":"SignatureAggregatorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalStaked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unstakeDelaySec","type":"uint256"}],"name":"StakeLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawTime","type":"uint256"}],"name":"StakeUnlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"paymaster","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint256","name":"actualGasCost","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"actualGasUsed","type":"uint256"}],"name":"UserOperationEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"UserOperationPrefundTooLow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"revertReason","type":"bytes"}],"name":"UserOperationRevertReason","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"uint32","name":"unstakeDelaySec","type":"uint32"}],"name":"addStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"delegateAndRevert","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"depositTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getDepositInfo","outputs":[{"components":[{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"bool","name":"staked","type":"bool"},{"internalType":"uint112","name":"stake","type":"uint112"},{"internalType":"uint32","name":"unstakeDelaySec","type":"uint32"},{"internalType":"uint48","name":"withdrawTime","type":"uint48"}],"internalType":"struct IStakeManager.DepositInfo","name":"info","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDomainSeparatorV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint192","name":"key","type":"uint192"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPackedUserOpTypeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"initCode","type":"bytes"}],"name":"getSenderAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation","name":"userOp","type":"tuple"}],"name":"getUserOpHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation[]","name":"userOps","type":"tuple[]"},{"internalType":"contract IAggregator","name":"aggregator","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IEntryPoint.UserOpsPerAggregator[]","name":"opsPerAggregator","type":"tuple[]"},{"internalType":"address payable","name":"beneficiary","type":"address"}],"name":"handleAggregatedOps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation[]","name":"ops","type":"tuple[]"},{"internalType":"address payable","name":"beneficiary","type":"address"}],"name":"handleOps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint192","name":"key","type":"uint192"}],"name":"incrementNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"callData","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"verificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"callGasLimit","type":"uint256"},{"internalType":"uint256","name":"paymasterVerificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"paymasterPostOpGasLimit","type":"uint256"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"}],"internalType":"struct EntryPoint.MemoryUserOp","name":"mUserOp","type":"tuple"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"uint256","name":"prefund","type":"uint256"},{"internalType":"uint256","name":"contextOffset","type":"uint256"},{"internalType":"uint256","name":"preOpGas","type":"uint256"}],"internalType":"struct EntryPoint.UserOpInfo","name":"opInfo","type":"tuple"},{"internalType":"bytes","name":"context","type":"bytes"}],"name":"innerHandleOp","outputs":[{"internalType":"uint256","name":"actualGasCost","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint192","name":"","type":"uint192"}],"name":"nonceSequenceNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"senderCreator","outputs":[{"internalType":"contract ISenderCreator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unlockStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawAddress","type":"address"}],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawAddress","type":"address"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"withdrawTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint080.bytecode b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/EntryPoint080.bytecode deleted file mode 100644 index f3f3bd1c1be220e99009e479c79697f0d66d18c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21738 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 diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator070.abi b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator070.abi deleted file mode 100644 index 0a1f0e4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator070.abi +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"bytes","name":"initCode","type":"bytes"}],"name":"createSender","outputs":[{"internalType":"address","name":"sender","type":"address"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator070.bytecode b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator070.bytecode deleted file mode 100644 index 8344c20281957f0aff5dd71a3650f5553f520704..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 451 zcmYdjNMJD&5KUy@4^Lod_!|u*OcNf+B!}}!nTaGas6s?d5*fR~6BO$I;|G7t7=^$p zSxhIU!<0^FY!OUkYzsF_P;O-u5(P1v6Id8cn;L<_O+aClrgla~FuNf^1WXgM=S?Hy zqy~_wq2Yv-K1i@{OyF*16k`-?W}ML6Bru^#P#mOjQcHqLOca_W~?3eV~_71&aW^K+7&892lli~-q#;|Bl$ diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator080.abi b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator080.abi deleted file mode 100644 index e169340..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator080.abi +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"opIndex","type":"uint256"},{"internalType":"string","name":"reason","type":"string"},{"internalType":"bytes","name":"inner","type":"bytes"}],"name":"FailedOpWithRevert","type":"error"},{"inputs":[{"internalType":"bytes","name":"initCode","type":"bytes"}],"name":"createSender","outputs":[{"internalType":"address","name":"sender","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"entryPoint","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"initCallData","type":"bytes"}],"name":"initEip7702Sender","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator080.bytecode b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/bin/SenderCreator080.bytecode deleted file mode 100644 index 0a8c61fb52987901cf2cbfbb119129d55d2a3c60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1217 zcmbVL&1(};5Z^I-*psv+ji7}-?CMRi)+BzQwzL%$TarCwOBdXEWK#{qq&D?X6n5Y4 zChaksRuK=Sh$lt#9}rsf;GupTRPZ3wiwE&w@FbYlx7!Z_t*!JO-VAT%&HQHOH)vtE zf?}+xl?u(OZq+qCic4))THU)p7N&cKR4e`bleZkE@Lf&MKY0H+Ooh{d;|U7iRO~ia zwm*Mj&=Pox(c)H~EW$#8U5;K`x3gydC59a~w6yxF?or`|Q;k(nW++0`0~&HuT7?QL zTLv|ShSM9D24)ZGKSyQyZtCva*)w`gigbmkcsQlmNSx#}c*8ZGr%4sGvs4oN^j}mB zUtxEW+id{eB%3Kn7*uuloVkwkA94xX`Olfsw3&HbA80_bNi8Wlie*p`QRc!%gWqOP zPiGhDzm$l_j~yq)Oy0Q2Ca#5};0?ivqmluK@M2C5K6Y#Xl8&>hYnQrQv{Z>$&b zdz8?VG^C}ps#k3+F7%tPRnprD!4jTl*zQ6EA`UpLsUgHZ8pKfS8Rja?S#6TdkW9P! zJ&1FPq%?Ez;_aK82-)zUE7*ggg0f!MTB&$MO=)OwV5anPVy?k&lj<)DiZ-VxL75BA z=TmV~yk5AKGf0}|a%5zzaD(*c$HyiTg=~Ht`?yzq`Js^=9VreSY#~O+#N_=Cl6;g6 kew^>DJ$tkGwE4oqLi>}c#jo|pS1udHLN47aNNqybUt=U#&;S4c diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js deleted file mode 100644 index b45ffee..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js +++ /dev/null @@ -1,87 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const time = require('../helpers/time'); - -async function envSetup(mock, beneficiary, token) { - return { - eth: { - checkRelease: async (tx, amount) => { - await expect(tx).to.changeEtherBalances([mock, beneficiary], [-amount, amount]); - }, - setupFailure: async () => { - const beneficiaryMock = await ethers.deployContract('EtherReceiverMock'); - await beneficiaryMock.setAcceptEther(false); - await mock.connect(beneficiary).transferOwnership(beneficiaryMock); - return { args: [], error: [mock, 'FailedCall'] }; - }, - releasedEvent: 'EtherReleased', - args: [], - }, - token: { - checkRelease: async (tx, amount) => { - await expect(tx).to.emit(token, 'Transfer').withArgs(mock, beneficiary, amount); - await expect(tx).to.changeTokenBalances(token, [mock, beneficiary], [-amount, amount]); - }, - setupFailure: async () => { - const pausableToken = await ethers.deployContract('$ERC20Pausable', ['Name', 'Symbol']); - await pausableToken.$_pause(); - return { - args: [ethers.Typed.address(pausableToken)], - error: [pausableToken, 'EnforcedPause'], - }; - }, - releasedEvent: 'ERC20Released', - args: [ethers.Typed.address(token)], - }, - }; -} - -function shouldBehaveLikeVesting() { - it('check vesting schedule', async function () { - for (const timestamp of this.schedule) { - await time.increaseTo.timestamp(timestamp); - const vesting = this.vestingFn(timestamp); - - expect(await this.mock.vestedAmount(...this.args, timestamp)).to.equal(vesting); - expect(await this.mock.releasable(...this.args)).to.equal(vesting); - } - }); - - it('execute vesting schedule', async function () { - let released = 0n; - { - const tx = await this.mock.release(...this.args); - await expect(tx) - .to.emit(this.mock, this.releasedEvent) - .withArgs(...this.args, 0); - - await this.checkRelease(tx, 0n); - } - - for (const timestamp of this.schedule) { - await time.increaseTo.timestamp(timestamp, false); - const vested = this.vestingFn(timestamp); - - const tx = await this.mock.release(...this.args); - await expect(tx).to.emit(this.mock, this.releasedEvent); - - await this.checkRelease(tx, vested - released); - released = vested; - } - }); - - it('should revert on transaction failure', async function () { - const { args, error } = await this.setupFailure(); - - for (const timestamp of this.schedule) { - await time.increaseTo.timestamp(timestamp); - - await expect(this.mock.release(...args)).to.be.revertedWithCustomError(...error); - } - }); -} - -module.exports = { - envSetup, - shouldBehaveLikeVesting, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js deleted file mode 100644 index b89258d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js +++ /dev/null @@ -1,65 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { min } = require('../helpers/math'); -const time = require('../helpers/time'); - -const { envSetup, shouldBehaveLikeVesting } = require('./VestingWallet.behavior'); - -async function fixture() { - const amount = ethers.parseEther('100'); - const duration = time.duration.years(4); - const start = (await time.clock.timestamp()) + time.duration.hours(1); - - const [sender, beneficiary] = await ethers.getSigners(); - const mock = await ethers.deployContract('VestingWallet', [beneficiary, start, duration]); - - const token = await ethers.deployContract('$ERC20', ['Name', 'Symbol']); - await token.$_mint(mock, amount); - await sender.sendTransaction({ to: mock, value: amount }); - - const env = await envSetup(mock, beneficiary, token); - - const schedule = Array.from({ length: 64 }, (_, i) => (BigInt(i) * duration) / 60n + start); - const vestingFn = timestamp => min(amount, (amount * (timestamp - start)) / duration); - - return { mock, duration, start, beneficiary, schedule, vestingFn, env }; -} - -describe('VestingWallet', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('rejects zero address for beneficiary', async function () { - await expect(ethers.deployContract('VestingWallet', [ethers.ZeroAddress, this.start, this.duration])) - .revertedWithCustomError(this.mock, 'OwnableInvalidOwner') - .withArgs(ethers.ZeroAddress); - }); - - it('check vesting contract', async function () { - expect(await this.mock.owner()).to.equal(this.beneficiary); - expect(await this.mock.start()).to.equal(this.start); - expect(await this.mock.duration()).to.equal(this.duration); - expect(await this.mock.end()).to.equal(this.start + this.duration); - }); - - describe('vesting schedule', function () { - describe('Eth vesting', function () { - beforeEach(async function () { - Object.assign(this, this.env.eth); - }); - - shouldBehaveLikeVesting(); - }); - - describe('ERC20 vesting', function () { - beforeEach(async function () { - Object.assign(this, this.env.token); - }); - - shouldBehaveLikeVesting(); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWalletCliff.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWalletCliff.test.js deleted file mode 100644 index 799b24c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/finance/VestingWalletCliff.test.js +++ /dev/null @@ -1,70 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { min } = require('../helpers/math'); -const time = require('../helpers/time'); - -const { envSetup, shouldBehaveLikeVesting } = require('./VestingWallet.behavior'); - -async function fixture() { - const amount = ethers.parseEther('100'); - const duration = time.duration.years(4); - const start = (await time.clock.timestamp()) + time.duration.hours(1); - const cliffDuration = time.duration.years(1); - const cliff = start + cliffDuration; - - const [sender, beneficiary] = await ethers.getSigners(); - const mock = await ethers.deployContract('$VestingWalletCliff', [beneficiary, start, duration, cliffDuration]); - - const token = await ethers.deployContract('$ERC20', ['Name', 'Symbol']); - await token.$_mint(mock, amount); - await sender.sendTransaction({ to: mock, value: amount }); - - const env = await envSetup(mock, beneficiary, token); - - const schedule = Array.from({ length: 64 }, (_, i) => (BigInt(i) * duration) / 60n + start); - const vestingFn = timestamp => min(amount, timestamp < cliff ? 0n : (amount * (timestamp - start)) / duration); - - return { mock, duration, start, beneficiary, cliff, schedule, vestingFn, env }; -} - -describe('VestingWalletCliff', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('rejects a larger cliff than vesting duration', async function () { - await expect( - ethers.deployContract('$VestingWalletCliff', [this.beneficiary, this.start, this.duration, this.duration + 1n]), - ) - .revertedWithCustomError(this.mock, 'InvalidCliffDuration') - .withArgs(this.duration + 1n, this.duration); - }); - - it('check vesting contract', async function () { - expect(await this.mock.owner()).to.equal(this.beneficiary); - expect(await this.mock.start()).to.equal(this.start); - expect(await this.mock.duration()).to.equal(this.duration); - expect(await this.mock.end()).to.equal(this.start + this.duration); - expect(await this.mock.cliff()).to.equal(this.cliff); - }); - - describe('vesting schedule', function () { - describe('Eth vesting', function () { - beforeEach(async function () { - Object.assign(this, this.env.eth); - }); - - shouldBehaveLikeVesting(); - }); - - describe('ERC20 vesting', function () { - beforeEach(async function () { - Object.assign(this, this.env.token); - }); - - shouldBehaveLikeVesting(); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.t.sol deleted file mode 100644 index 66b684d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.t.sol +++ /dev/null @@ -1,59 +0,0 @@ -// 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 view { - if (includeProposer) { - description = string.concat(description, "#proposer=", Strings.toHexString(proposer)); - } - assertTrue(_isValidDescriptionForProposer(proposer, description)); - } - - function testInvalidDescriptionForProposer( - string memory description, - address commitProposer, - address actualProposer - ) public view { - vm.assume(commitProposer != actualProposer); - description = string.concat(description, "#proposer=", Strings.toHexString(commitProposer)); - assertFalse(_isValidDescriptionForProposer(actualProposer, description)); - } - - // We don't need to truly 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 returns (uint256) {} -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.test.js deleted file mode 100644 index e66dd25..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/Governor.test.js +++ /dev/null @@ -1,980 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { GovernorHelper } = require('../helpers/governance'); -const { getDomain, Ballot } = require('../helpers/eip712'); -const { ProposalState, VoteType } = require('../helpers/enums'); -const time = require('../helpers/time'); - -const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); -const { shouldBehaveLikeERC6372 } = require('./utils/ERC6372.behavior'); - -const TOKENS = [ - { Token: '$ERC20Votes', mode: 'blocknumber' }, - { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, - { Token: '$ERC20VotesLegacyMock', mode: 'blocknumber' }, -]; - -const name = 'OZ-Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const votingDelay = 4n; -const votingPeriod = 16n; -const value = ethers.parseEther('1'); - -const signBallot = account => (contract, message) => - getDomain(contract).then(domain => account.signTypedData(domain, { Ballot }, message)); - -async function deployToken(contractName) { - try { - return await ethers.deployContract(contractName, [tokenName, tokenSymbol, tokenName, version]); - } catch (error) { - if (error.message == 'incorrect number of arguments to constructor') { - // ERC20VotesLegacyMock has a different construction that uses version='1' by default. - return ethers.deployContract(contractName, [tokenName, tokenSymbol, tokenName]); - } - throw error; - } -} - -describe('Governor', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [owner, proposer, voter1, voter2, voter3, voter4, userEOA] = await ethers.getSigners(); - const receiver = await ethers.deployContract('CallReceiverMock'); - - const token = await deployToken(Token, [tokenName, tokenSymbol, version]); - const mock = await ethers.deployContract('$GovernorMock', [ - name, // name - votingDelay, // initialVotingDelay - votingPeriod, // initialVotingPeriod - 0n, // initialProposalThreshold - token, // tokenAddress - 10n, // quorumNumeratorValue - ]); - - await owner.sendTransaction({ to: mock, value }); - await token.$_mint(owner, tokenSupply); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(owner).delegate({ token: token, to: voter1, value: ethers.parseEther('10') }); - await helper.connect(owner).delegate({ token: token, to: voter2, value: ethers.parseEther('7') }); - await helper.connect(owner).delegate({ token: token, to: voter3, value: ethers.parseEther('5') }); - await helper.connect(owner).delegate({ token: token, to: voter4, value: ethers.parseEther('2') }); - - return { - owner, - proposer, - voter1, - voter2, - voter3, - voter4, - userEOA, - receiver, - token, - mock, - helper, - }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - // initiate fresh proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - value, - }, - ], - '', - ); - }); - - shouldSupportInterfaces(['ERC1155Receiver', 'Governor', 'Governor_5_3']); - shouldBehaveLikeERC6372(mode); - - it('deployment check', async function () { - expect(await this.mock.name()).to.equal(name); - expect(await this.mock.token()).to.equal(this.token); - expect(await this.mock.votingDelay()).to.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.equal(votingPeriod); - expect(await this.mock.quorum(0)).to.equal(0n); - expect(await this.mock.COUNTING_MODE()).to.equal('support=bravo&quorum=for,abstain'); - }); - - it('nominal workflow', async function () { - // Before - expect(await this.mock.proposalProposer(this.proposal.id)).to.equal(ethers.ZeroAddress); - expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; - expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.false; - expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.false; - expect(await ethers.provider.getBalance(this.mock)).to.equal(value); - expect(await ethers.provider.getBalance(this.receiver)).to.equal(0n); - - expect(await this.mock.proposalEta(this.proposal.id)).to.equal(0n); - expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.false; - - // Run proposal - const txPropose = await this.helper.connect(this.proposer).propose(); - const timepoint = await time.clockFromReceipt[mode](txPropose); - - await expect(txPropose) - .to.emit(this.mock, 'ProposalCreated') - .withArgs( - this.proposal.id, - this.proposer, - this.proposal.targets, - this.proposal.values, - this.proposal.signatures, - this.proposal.data, - timepoint + votingDelay, - timepoint + votingDelay + votingPeriod, - this.proposal.description, - ); - - await this.helper.waitForSnapshot(); - - await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For, reason: 'This is nice' })) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter1, this.proposal.id, VoteType.For, ethers.parseEther('10'), 'This is nice'); - - await expect(this.helper.connect(this.voter2).vote({ support: VoteType.For })) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter2, this.proposal.id, VoteType.For, ethers.parseEther('7'), ''); - - await expect(this.helper.connect(this.voter3).vote({ support: VoteType.Against })) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter3, this.proposal.id, VoteType.Against, ethers.parseEther('5'), ''); - - await expect(this.helper.connect(this.voter4).vote({ support: VoteType.Abstain })) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter4, this.proposal.id, VoteType.Abstain, ethers.parseEther('2'), ''); - - await this.helper.waitForDeadline(); - - const txExecute = await this.helper.execute(); - - await expect(txExecute).to.emit(this.mock, 'ProposalExecuted').withArgs(this.proposal.id); - - await expect(txExecute).to.emit(this.receiver, 'MockFunctionCalled'); - - // After - expect(await this.mock.proposalProposer(this.proposal.id)).to.equal(this.proposer); - expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; - expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.true; - expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.true; - expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); - expect(await ethers.provider.getBalance(this.receiver)).to.equal(value); - - expect(await this.mock.proposalEta(this.proposal.id)).to.equal(0n); - expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.false; - }); - - it('send ethers', async function () { - this.helper.setProposal( - [ - { - target: this.userEOA.address, - value, - }, - ], - '', - ); - - // Run proposal - await expect(async () => { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - return this.helper.execute(); - }).to.changeEtherBalances([this.mock, this.userEOA], [-value, value]); - }); - - describe('vote with signature', function () { - it('votes with an EOA signature on two proposals', async function () { - await this.token.connect(this.voter1).delegate(this.userEOA); - - for (let i = 0; i < 2; i++) { - const nonce = await this.mock.nonces(this.userEOA); - - // Run proposal - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await expect( - this.helper.vote({ - support: VoteType.For, - voter: this.userEOA.address, - nonce, - signature: signBallot(this.userEOA), - }), - ) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.userEOA, this.proposal.id, VoteType.For, ethers.parseEther('10'), ''); - - // After - expect(await this.mock.hasVoted(this.proposal.id, this.userEOA)).to.be.true; - expect(await this.mock.nonces(this.userEOA)).to.equal(nonce + 1n); - - // Update proposal to allow for re-propose - this.helper.description += ' - updated'; - } - - await expect(this.mock.nonces(this.userEOA)).to.eventually.equal(2n); - }); - - it('votes with a valid EIP-1271 signature', async function () { - const wallet = await ethers.deployContract('ERC1271WalletMock', [this.userEOA]); - - await this.token.connect(this.voter1).delegate(wallet); - - const nonce = await this.mock.nonces(this.userEOA); - - // Run proposal - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await expect( - this.helper.vote({ - support: VoteType.For, - voter: wallet.target, - nonce, - signature: signBallot(this.userEOA), - }), - ) - .to.emit(this.mock, 'VoteCast') - .withArgs(wallet, this.proposal.id, VoteType.For, ethers.parseEther('10'), ''); - await this.helper.waitForDeadline(); - await this.helper.execute(); - - // After - expect(await this.mock.hasVoted(this.proposal.id, wallet)).to.be.true; - expect(await this.mock.nonces(wallet)).to.equal(nonce + 1n); - }); - - afterEach('no other votes are cast', async function () { - expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; - expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.false; - expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.false; - }); - }); - - describe('should revert', function () { - describe('on propose', function () { - it('if proposal already exists', async function () { - await this.helper.propose(); - await expect(this.helper.propose()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs(this.proposal.id, ProposalState.Pending, ethers.ZeroHash); - }); - - it('if proposer has below threshold votes', async function () { - const votes = ethers.parseEther('10'); - const threshold = ethers.parseEther('1000'); - await this.mock.$_setProposalThreshold(threshold); - await expect(this.helper.connect(this.voter1).propose()) - .to.be.revertedWithCustomError(this.mock, 'GovernorInsufficientProposerVotes') - .withArgs(this.voter1, votes, threshold); - }); - }); - - describe('on vote', function () { - it('if proposal does not exist', async function () { - await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For })) - .to.be.revertedWithCustomError(this.mock, 'GovernorNonexistentProposal') - .withArgs(this.proposal.id); - }); - - it('if voting has not started', async function () { - await this.helper.propose(); - await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For })) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Pending, - GovernorHelper.proposalStatesToBitMap([ProposalState.Active]), - ); - }); - - it('if support value is invalid', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await expect(this.helper.vote({ support: 255 })).to.be.revertedWithCustomError( - this.mock, - 'GovernorInvalidVoteType', - ); - }); - - it('if vote was already casted', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For })) - .to.be.revertedWithCustomError(this.mock, 'GovernorAlreadyCastVote') - .withArgs(this.voter1); - }); - - it('if voting is over', async function () { - await this.helper.propose(); - await this.helper.waitForDeadline(); - await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For })) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Defeated, - GovernorHelper.proposalStatesToBitMap([ProposalState.Active]), - ); - }); - }); - - describe('on vote by signature', function () { - beforeEach(async function () { - await this.token.connect(this.voter1).delegate(this.userEOA); - - // 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.userEOA); - - function tamper(str, index, mask) { - const arrayStr = ethers.getBytes(str); - arrayStr[index] ^= mask; - return ethers.hexlify(arrayStr); - } - - const voteParams = { - support: VoteType.For, - voter: this.userEOA.address, - nonce, - signature: (...args) => signBallot(this.userEOA)(...args).then(sig => tamper(sig, 42, 0xff)), - }; - - await expect(this.helper.vote(voteParams)) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') - .withArgs(voteParams.voter); - }); - - it('if vote nonce is incorrect', async function () { - const nonce = await this.mock.nonces(this.userEOA); - - const voteParams = { - support: VoteType.For, - voter: this.userEOA.address, - nonce: nonce + 1n, - signature: signBallot(this.userEOA), - }; - - await expect(this.helper.vote(voteParams)) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') - .withArgs(voteParams.voter); - }); - }); - - describe('on queue', function () { - it('always', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await expect(this.helper.queue()).to.be.revertedWithCustomError(this.mock, 'GovernorQueueNotImplemented'); - }); - }); - - describe('on execute', function () { - it('if proposal does not exist', async function () { - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorNonexistentProposal') - .withArgs(this.proposal.id); - }); - - it('if quorum is not reached', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter3).vote({ support: VoteType.For }); - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Active, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - - it('if score not reached', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.Against }); - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Active, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - - it('if voting is not over', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Active, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - - it('if receiver revert without reason', async function () { - this.helper.setProposal( - [ - { - target: this.receiver.target, - data: this.receiver.interface.encodeFunctionData('mockFunctionRevertsNoReason'), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await expect(this.helper.execute()).to.be.revertedWithCustomError(this.mock, 'FailedCall'); - }); - - it('if receiver revert with reason', async function () { - this.helper.setProposal( - [ - { - target: this.receiver.target, - data: this.receiver.interface.encodeFunctionData('mockFunctionRevertsReason'), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await expect(this.helper.execute()).to.be.revertedWith('CallReceiverMock: reverting'); - }); - - it('if proposal was already executed', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Executed, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - }); - }); - - describe('state', function () { - it('Unset', async function () { - await expect(this.mock.state(this.proposal.id)) - .to.be.revertedWithCustomError(this.mock, 'GovernorNonexistentProposal') - .withArgs(this.proposal.id); - }); - - it('Pending & Active', async function () { - await this.helper.propose(); - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Pending); - await this.helper.waitForSnapshot(); - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Pending); - await this.helper.waitForSnapshot(1n); - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active); - }); - - it('Defeated', async function () { - await this.helper.propose(); - await this.helper.waitForDeadline(); - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active); - await this.helper.waitForDeadline(1n); - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Defeated); - }); - - it('Succeeded', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active); - await this.helper.waitForDeadline(1n); - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Succeeded); - }); - - it('Executed', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Executed); - }); - }); - - describe('cancel', function () { - describe('internal', function () { - it('before proposal', async function () { - await expect(this.helper.cancel('internal')) - .to.be.revertedWithCustomError(this.mock, 'GovernorNonexistentProposal') - .withArgs(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.equal(ProposalState.Canceled); - - await this.helper.waitForSnapshot(); - await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For })) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Canceled, - GovernorHelper.proposalStatesToBitMap([ProposalState.Active]), - ); - }); - - it('after vote', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - - await this.helper.cancel('internal'); - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled); - - await this.helper.waitForDeadline(); - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Canceled, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - - it('after deadline', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await this.helper.cancel('internal'); - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Canceled, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - - it('after execution', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - - await expect(this.helper.cancel('internal')) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Executed, - GovernorHelper.proposalStatesToBitMap( - [ProposalState.Canceled, ProposalState.Expired, ProposalState.Executed], - { inverted: true }, - ), - ); - }); - }); - - describe('public', function () { - it('before proposal', async function () { - await expect(this.helper.cancel('external')) - .to.be.revertedWithCustomError(this.mock, 'GovernorNonexistentProposal') - .withArgs(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.connect(this.proposer).propose(); - - await expect(this.helper.connect(this.owner).cancel('external')) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnableToCancel') - .withArgs(this.proposal.id, this.owner); - }); - - it('after vote started', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(1n); // snapshot + 1 block - - await expect(this.helper.cancel('external')) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnableToCancel') - .withArgs(this.proposal.id, this.owner); - }); - - it('after vote', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - - await expect(this.helper.cancel('external')) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnableToCancel') - .withArgs(this.proposal.id, this.voter1); - }); - - it('after deadline', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.cancel('external')) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnableToCancel') - .withArgs(this.proposal.id, this.voter1); - }); - - it('after execution', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - - await expect(this.helper.cancel('external')) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnableToCancel') - .withArgs(this.proposal.id, this.voter1); - }); - }); - }); - - describe('proposal length', function () { - it('empty', async function () { - this.helper.setProposal([], ''); - - await expect(this.helper.propose()) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidProposalLength') - .withArgs(0, 0, 0); - }); - - it('mismatch #1', async function () { - this.helper.setProposal( - { - targets: [], - values: [0n], - data: [this.receiver.interface.encodeFunctionData('mockFunction')], - }, - '', - ); - await expect(this.helper.propose()) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidProposalLength') - .withArgs(0, 1, 1); - }); - - it('mismatch #2', async function () { - this.helper.setProposal( - { - targets: [this.receiver.target], - values: [], - data: [this.receiver.interface.encodeFunctionData('mockFunction')], - }, - '', - ); - await expect(this.helper.propose()) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidProposalLength') - .withArgs(1, 1, 0); - }); - - it('mismatch #3', async function () { - this.helper.setProposal( - { - targets: [this.receiver.target], - values: [0n], - data: [], - }, - '', - ); - await expect(this.helper.propose()) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidProposalLength') - .withArgs(1, 0, 1); - }); - }); - - describe('frontrun protection using description suffix', function () { - function shouldPropose() { - it('proposer can propose', async function () { - const txPropose = await this.helper.connect(this.proposer).propose(); - - await expect(txPropose) - .to.emit(this.mock, 'ProposalCreated') - .withArgs( - this.proposal.id, - this.proposer, - this.proposal.targets, - this.proposal.values, - this.proposal.signatures, - this.proposal.data, - (await time.clockFromReceipt[mode](txPropose)) + votingDelay, - (await time.clockFromReceipt[mode](txPropose)) + votingDelay + votingPeriod, - this.proposal.description, - ); - }); - - it('someone else can propose', async function () { - const txPropose = await this.helper.connect(this.voter1).propose(); - - await expect(txPropose) - .to.emit(this.mock, 'ProposalCreated') - .withArgs( - this.proposal.id, - this.voter1, - this.proposal.targets, - this.proposal.values, - this.proposal.signatures, - this.proposal.data, - (await time.clockFromReceipt[mode](txPropose)) + votingDelay, - (await time.clockFromReceipt[mode](txPropose)) + votingDelay + votingPeriod, - this.proposal.description, - ); - }); - } - - describe('without protection', function () { - describe('without suffix', function () { - shouldPropose(); - }); - - describe('with different suffix', function () { - beforeEach(function () { - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - value, - }, - ], - `#wrong-suffix=${this.proposer}`, - ); - }); - - shouldPropose(); - }); - - describe('with proposer suffix but bad address part', function () { - beforeEach(function () { - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - value, - }, - ], - `#proposer=0x3C44CdDdB6a900fa2b585dd299e03d12FA429XYZ`, // XYZ are not a valid hex char - ); - }); - - shouldPropose(); - }); - }); - - describe('with protection via proposer suffix', function () { - beforeEach(function () { - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - value, - }, - ], - `#proposer=${this.proposer}`, - ); - }); - - shouldPropose(); - }); - }); - - describe('onlyGovernance updates', function () { - it('setVotingDelay is protected', async function () { - await expect(this.mock.connect(this.owner).setVotingDelay(0n)) - .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') - .withArgs(this.owner); - }); - - it('setVotingPeriod is protected', async function () { - await expect(this.mock.connect(this.owner).setVotingPeriod(32n)) - .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') - .withArgs(this.owner); - }); - - it('setProposalThreshold is protected', async function () { - await expect(this.mock.connect(this.owner).setProposalThreshold(1_000_000_000_000_000_000n)) - .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') - .withArgs(this.owner); - }); - - it('can setVotingDelay through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('setVotingDelay', [0n]), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.execute()).to.emit(this.mock, 'VotingDelaySet').withArgs(4n, 0n); - - expect(await this.mock.votingDelay()).to.equal(0n); - }); - - it('can setVotingPeriod through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('setVotingPeriod', [32n]), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.execute()).to.emit(this.mock, 'VotingPeriodSet').withArgs(16n, 32n); - - expect(await this.mock.votingPeriod()).to.equal(32n); - }); - - it('cannot setVotingPeriod to 0 through governance', async function () { - const votingPeriod = 0n; - - this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('setVotingPeriod', [votingPeriod]), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidVotingPeriod') - .withArgs(votingPeriod); - }); - - it('can setProposalThreshold to 0 through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('setProposalThreshold', [1_000_000_000_000_000_000n]), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.execute()) - .to.emit(this.mock, 'ProposalThresholdSet') - .withArgs(0n, 1_000_000_000_000_000_000n); - - expect(await this.mock.proposalThreshold()).to.equal(1_000_000_000_000_000_000n); - }); - }); - - describe('safe receive', function () { - describe('ERC721', function () { - const tokenId = 1n; - - beforeEach(async function () { - this.token = await ethers.deployContract('$ERC721', ['Non Fungible Token', 'NFT']); - await this.token.$_mint(this.owner, tokenId); - }); - - it('can receive an ERC721 safeTransfer', async function () { - await this.token.connect(this.owner).safeTransferFrom(this.owner, this.mock, tokenId); - }); - }); - - describe('ERC1155', function () { - const tokenIds = { - 1: 1000n, - 2: 2000n, - 3: 3000n, - }; - - beforeEach(async function () { - this.token = await ethers.deployContract('$ERC1155', ['https://token-cdn-domain/{id}.json']); - await this.token.$_mintBatch(this.owner, Object.keys(tokenIds), Object.values(tokenIds), '0x'); - }); - - it('can receive ERC1155 safeTransfer', async function () { - await this.token.connect(this.owner).safeTransferFrom( - this.owner, - this.mock, - ...Object.entries(tokenIds)[0], // id + amount - '0x', - ); - }); - - it('can receive ERC1155 safeBatchTransfer', async function () { - await this.token - .connect(this.owner) - .safeBatchTransferFrom(this.owner, this.mock, Object.keys(tokenIds), Object.values(tokenIds), '0x'); - }); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/TimelockController.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/TimelockController.test.js deleted file mode 100644 index 08410d4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/TimelockController.test.js +++ /dev/null @@ -1,1279 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -const { GovernorHelper } = require('../helpers/governance'); -const { OperationState } = require('../helpers/enums'); -const time = require('../helpers/time'); - -const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); - -const salt = '0x025e7b0be353a74631ad648c667493c0e1cd31caa4cc2d3520fdc171ea0cc726'; // a random value - -const MINDELAY = time.duration.days(1); -const DEFAULT_ADMIN_ROLE = ethers.ZeroHash; -const PROPOSER_ROLE = ethers.id('PROPOSER_ROLE'); -const EXECUTOR_ROLE = ethers.id('EXECUTOR_ROLE'); -const CANCELLER_ROLE = ethers.id('CANCELLER_ROLE'); - -const getAddress = obj => obj.address ?? obj.target ?? obj; - -function genOperation(target, value, data, predecessor, salt) { - const id = ethers.keccak256( - ethers.AbiCoder.defaultAbiCoder().encode( - ['address', 'uint256', 'bytes', 'uint256', 'bytes32'], - [getAddress(target), value, data, predecessor, salt], - ), - ); - return { id, target, value, data, predecessor, salt }; -} - -function genOperationBatch(targets, values, payloads, predecessor, salt) { - const id = ethers.keccak256( - ethers.AbiCoder.defaultAbiCoder().encode( - ['address[]', 'uint256[]', 'bytes[]', 'uint256', 'bytes32'], - [targets.map(getAddress), values, payloads, predecessor, salt], - ), - ); - return { id, targets, values, payloads, predecessor, salt }; -} - -async function fixture() { - const [admin, proposer, canceller, executor, other] = await ethers.getSigners(); - - const mock = await ethers.deployContract('TimelockController', [MINDELAY, [proposer], [executor], admin]); - const callreceivermock = await ethers.deployContract('CallReceiverMock'); - const implementation2 = await ethers.deployContract('Implementation2'); - - expect(await mock.hasRole(CANCELLER_ROLE, proposer)).to.be.true; - await mock.connect(admin).revokeRole(CANCELLER_ROLE, proposer); - await mock.connect(admin).grantRole(CANCELLER_ROLE, canceller); - - return { - admin, - proposer, - canceller, - executor, - other, - mock, - callreceivermock, - implementation2, - }; -} - -describe('TimelockController', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldSupportInterfaces(['ERC1155Receiver']); - - it('initial state', async function () { - expect(await this.mock.getMinDelay()).to.equal(MINDELAY); - - expect(await this.mock.DEFAULT_ADMIN_ROLE()).to.equal(DEFAULT_ADMIN_ROLE); - expect(await this.mock.PROPOSER_ROLE()).to.equal(PROPOSER_ROLE); - expect(await this.mock.EXECUTOR_ROLE()).to.equal(EXECUTOR_ROLE); - expect(await this.mock.CANCELLER_ROLE()).to.equal(CANCELLER_ROLE); - - expect( - await Promise.all( - [PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, this.proposer)), - ), - ).to.deep.equal([true, false, false]); - - expect( - await Promise.all( - [PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, this.canceller)), - ), - ).to.deep.equal([false, true, false]); - - expect( - await Promise.all( - [PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, this.executor)), - ), - ).to.deep.equal([false, false, true]); - }); - - it('optional admin', async function () { - const mock = await ethers.deployContract('TimelockController', [ - MINDELAY, - [this.proposer], - [this.executor], - ethers.ZeroAddress, - ]); - expect(await mock.hasRole(DEFAULT_ADMIN_ROLE, this.admin)).to.be.false; - expect(await mock.hasRole(DEFAULT_ADMIN_ROLE, mock.target)).to.be.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.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.equal(this.operation.id); - }); - }); - describe('simple', function () { - describe('schedule', function () { - beforeEach(async function () { - this.operation = genOperation( - '0x31754f590B97fD975Eb86938f18Cc304E264D2F2', - 0n, - '0x3bf92ccc', - ethers.ZeroHash, - salt, - ); - }); - - it('proposer can schedule', async function () { - const tx = await this.mock - .connect(this.proposer) - .schedule( - this.operation.target, - this.operation.value, - this.operation.data, - this.operation.predecessor, - this.operation.salt, - MINDELAY, - ); - - await expect(tx) - .to.emit(this.mock, 'CallScheduled') - .withArgs( - this.operation.id, - 0n, - this.operation.target, - this.operation.value, - this.operation.data, - this.operation.predecessor, - MINDELAY, - ) - .to.emit(this.mock, 'CallSalt') - .withArgs(this.operation.id, this.operation.salt); - - expect(await this.mock.getTimestamp(this.operation.id)).to.equal( - (await time.clockFromReceipt.timestamp(tx)) + MINDELAY, - ); - }); - - it('prevent overwriting active operation', async function () { - await this.mock - .connect(this.proposer) - .schedule( - this.operation.target, - this.operation.value, - this.operation.data, - this.operation.predecessor, - this.operation.salt, - MINDELAY, - ); - - await expect( - this.mock - .connect(this.proposer) - .schedule( - this.operation.target, - this.operation.value, - this.operation.data, - this.operation.predecessor, - this.operation.salt, - MINDELAY, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') - .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Unset)); - }); - - it('prevent non-proposer from committing', async function () { - await expect( - this.mock - .connect(this.other) - .schedule( - this.operation.target, - this.operation.value, - this.operation.data, - this.operation.predecessor, - this.operation.salt, - MINDELAY, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.other, PROPOSER_ROLE); - }); - - it('enforce minimum delay', async function () { - await expect( - this.mock - .connect(this.proposer) - .schedule( - this.operation.target, - this.operation.value, - this.operation.data, - this.operation.predecessor, - this.operation.salt, - MINDELAY - 1n, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockInsufficientDelay') - .withArgs(MINDELAY - 1n, MINDELAY); - }); - - it('schedule operation with salt zero', async function () { - await expect( - this.mock - .connect(this.proposer) - .schedule( - this.operation.target, - this.operation.value, - this.operation.data, - this.operation.predecessor, - ethers.ZeroHash, - MINDELAY, - ), - ).to.not.emit(this.mock, 'CallSalt'); - }); - }); - - describe('execute', function () { - beforeEach(async function () { - this.operation = genOperation( - '0xAe22104DCD970750610E6FE15E623468A98b15f7', - 0n, - '0x13e414de', - ethers.ZeroHash, - '0xc1059ed2dc130227aa1d1d539ac94c641306905c020436c636e19e3fab56fc7f', - ); - }); - - it('revert if operation is not scheduled', async function () { - await expect( - this.mock - .connect(this.executor) - .execute( - this.operation.target, - this.operation.value, - this.operation.data, - this.operation.predecessor, - this.operation.salt, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') - .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); - }); - - describe('with scheduled operation', function () { - beforeEach(async function () { - await this.mock - .connect(this.proposer) - .schedule( - this.operation.target, - this.operation.value, - this.operation.data, - this.operation.predecessor, - this.operation.salt, - MINDELAY, - ); - }); - - it('revert if execution comes too early 1/2', async function () { - await expect( - this.mock - .connect(this.executor) - .execute( - this.operation.target, - this.operation.value, - this.operation.data, - this.operation.predecessor, - this.operation.salt, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') - .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); - }); - - it('revert if execution comes too early 2/2', async function () { - // -1 is too tight, test sometime fails - await this.mock.getTimestamp(this.operation.id).then(clock => time.increaseTo.timestamp(clock - 5n)); - - await expect( - this.mock - .connect(this.executor) - .execute( - this.operation.target, - this.operation.value, - this.operation.data, - this.operation.predecessor, - this.operation.salt, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') - .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); - }); - - describe('on time', function () { - beforeEach(async function () { - await this.mock.getTimestamp(this.operation.id).then(time.increaseTo.timestamp); - }); - - it('executor can reveal', async function () { - await expect( - this.mock - .connect(this.executor) - .execute( - this.operation.target, - this.operation.value, - this.operation.data, - this.operation.predecessor, - this.operation.salt, - ), - ) - .to.emit(this.mock, 'CallExecuted') - .withArgs(this.operation.id, 0n, this.operation.target, this.operation.value, this.operation.data); - }); - - it('prevent non-executor from revealing', async function () { - await expect( - this.mock - .connect(this.other) - .execute( - this.operation.target, - this.operation.value, - this.operation.data, - this.operation.predecessor, - this.operation.salt, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.other, EXECUTOR_ROLE); - }); - - it('prevents reentrancy execution', async function () { - // Create operation - const reentrant = await ethers.deployContract('$TimelockReentrant'); - const reentrantOperation = genOperation( - reentrant, - 0n, - reentrant.interface.encodeFunctionData('reenter'), - ethers.ZeroHash, - salt, - ); - - // Schedule so it can be executed - await this.mock - .connect(this.proposer) - .schedule( - reentrantOperation.target, - reentrantOperation.value, - reentrantOperation.data, - reentrantOperation.predecessor, - reentrantOperation.salt, - MINDELAY, - ); - - // Advance on time to make the operation executable - await this.mock.getTimestamp(reentrantOperation.id).then(time.increaseTo.timestamp); - - // Grant executor role to the reentrant contract - await this.mock.connect(this.admin).grantRole(EXECUTOR_ROLE, reentrant); - - // Prepare reenter - const data = this.mock.interface.encodeFunctionData('execute', [ - getAddress(reentrantOperation.target), - reentrantOperation.value, - reentrantOperation.data, - reentrantOperation.predecessor, - reentrantOperation.salt, - ]); - await reentrant.enableRentrancy(this.mock, data); - - // Expect to fail - await expect( - this.mock - .connect(this.executor) - .execute( - reentrantOperation.target, - reentrantOperation.value, - reentrantOperation.data, - reentrantOperation.predecessor, - reentrantOperation.salt, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') - .withArgs(reentrantOperation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); - - // Disable reentrancy - await reentrant.disableReentrancy(); - const nonReentrantOperation = reentrantOperation; // Not anymore - - // Try again successfully - await expect( - this.mock - .connect(this.executor) - .execute( - nonReentrantOperation.target, - nonReentrantOperation.value, - nonReentrantOperation.data, - nonReentrantOperation.predecessor, - nonReentrantOperation.salt, - ), - ) - .to.emit(this.mock, 'CallExecuted') - .withArgs( - nonReentrantOperation.id, - 0n, - getAddress(nonReentrantOperation), - nonReentrantOperation.value, - nonReentrantOperation.data, - ); - }); - }); - }); - }); - }); - - describe('batch', function () { - describe('schedule', function () { - beforeEach(async function () { - this.operation = genOperationBatch( - Array(8).fill('0xEd912250835c812D4516BBD80BdaEA1bB63a293C'), - Array(8).fill(0n), - Array(8).fill('0x2fcb7a88'), - ethers.ZeroHash, - '0x6cf9d042ade5de78bed9ffd075eb4b2a4f6b1736932c2dc8af517d6e066f51f5', - ); - }); - - it('proposer can schedule', async function () { - const tx = this.mock - .connect(this.proposer) - .scheduleBatch( - this.operation.targets, - this.operation.values, - this.operation.payloads, - this.operation.predecessor, - this.operation.salt, - MINDELAY, - ); - for (const i in this.operation.targets) { - await expect(tx) - .to.emit(this.mock, 'CallScheduled') - .withArgs( - this.operation.id, - i, - getAddress(this.operation.targets[i]), - this.operation.values[i], - this.operation.payloads[i], - this.operation.predecessor, - MINDELAY, - ) - .to.emit(this.mock, 'CallSalt') - .withArgs(this.operation.id, this.operation.salt); - } - - expect(await this.mock.getTimestamp(this.operation.id)).to.equal( - (await time.clockFromReceipt.timestamp(tx)) + MINDELAY, - ); - }); - - it('prevent overwriting active operation', async function () { - await this.mock - .connect(this.proposer) - .scheduleBatch( - this.operation.targets, - this.operation.values, - this.operation.payloads, - this.operation.predecessor, - this.operation.salt, - MINDELAY, - ); - - await expect( - this.mock - .connect(this.proposer) - .scheduleBatch( - this.operation.targets, - this.operation.values, - this.operation.payloads, - this.operation.predecessor, - this.operation.salt, - MINDELAY, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') - .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Unset)); - }); - - it('length of batch parameter must match #1', async function () { - await expect( - this.mock - .connect(this.proposer) - .scheduleBatch( - this.operation.targets, - [], - this.operation.payloads, - this.operation.predecessor, - this.operation.salt, - MINDELAY, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockInvalidOperationLength') - .withArgs(this.operation.targets.length, this.operation.payloads.length, 0n); - }); - - it('length of batch parameter must match #1', async function () { - await expect( - this.mock - .connect(this.proposer) - .scheduleBatch( - this.operation.targets, - this.operation.values, - [], - this.operation.predecessor, - this.operation.salt, - MINDELAY, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockInvalidOperationLength') - .withArgs(this.operation.targets.length, 0n, this.operation.payloads.length); - }); - - it('prevent non-proposer from committing', async function () { - await expect( - this.mock - .connect(this.other) - .scheduleBatch( - this.operation.targets, - this.operation.values, - this.operation.payloads, - this.operation.predecessor, - this.operation.salt, - MINDELAY, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.other, PROPOSER_ROLE); - }); - - it('enforce minimum delay', async function () { - await expect( - this.mock - .connect(this.proposer) - .scheduleBatch( - this.operation.targets, - this.operation.values, - this.operation.payloads, - this.operation.predecessor, - this.operation.salt, - MINDELAY - 1n, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockInsufficientDelay') - .withArgs(MINDELAY - 1n, MINDELAY); - }); - }); - - describe('execute', function () { - beforeEach(async function () { - this.operation = genOperationBatch( - Array(8).fill('0x76E53CcEb05131Ef5248553bEBDb8F70536830b1'), - Array(8).fill(0n), - Array(8).fill('0x58a60f63'), - ethers.ZeroHash, - '0x9545eeabc7a7586689191f78a5532443698538e54211b5bd4d7dc0fc0102b5c7', - ); - }); - - it('revert if operation is not scheduled', async function () { - await expect( - this.mock - .connect(this.executor) - .executeBatch( - this.operation.targets, - this.operation.values, - this.operation.payloads, - this.operation.predecessor, - this.operation.salt, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') - .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); - }); - - describe('with scheduled operation', function () { - beforeEach(async function () { - await this.mock - .connect(this.proposer) - .scheduleBatch( - this.operation.targets, - this.operation.values, - this.operation.payloads, - this.operation.predecessor, - this.operation.salt, - MINDELAY, - ); - }); - - it('revert if execution comes too early 1/2', async function () { - await expect( - this.mock - .connect(this.executor) - .executeBatch( - this.operation.targets, - this.operation.values, - this.operation.payloads, - this.operation.predecessor, - this.operation.salt, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') - .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); - }); - - it('revert if execution comes too early 2/2', async function () { - // -1 is to tight, test sometime fails - await this.mock.getTimestamp(this.operation.id).then(clock => time.increaseTo.timestamp(clock - 5n)); - - await expect( - this.mock - .connect(this.executor) - .executeBatch( - this.operation.targets, - this.operation.values, - this.operation.payloads, - this.operation.predecessor, - this.operation.salt, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') - .withArgs(this.operation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); - }); - - describe('on time', function () { - beforeEach(async function () { - await this.mock.getTimestamp(this.operation.id).then(time.increaseTo.timestamp); - }); - - it('executor can reveal', async function () { - const tx = this.mock - .connect(this.executor) - .executeBatch( - this.operation.targets, - this.operation.values, - this.operation.payloads, - this.operation.predecessor, - this.operation.salt, - ); - for (const i in this.operation.targets) { - await expect(tx) - .to.emit(this.mock, 'CallExecuted') - .withArgs( - this.operation.id, - i, - this.operation.targets[i], - this.operation.values[i], - this.operation.payloads[i], - ); - } - }); - - it('prevent non-executor from revealing', async function () { - await expect( - this.mock - .connect(this.other) - .executeBatch( - this.operation.targets, - this.operation.values, - this.operation.payloads, - this.operation.predecessor, - this.operation.salt, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.other, EXECUTOR_ROLE); - }); - - it('length mismatch #1', async function () { - await expect( - this.mock - .connect(this.executor) - .executeBatch( - [], - this.operation.values, - this.operation.payloads, - this.operation.predecessor, - this.operation.salt, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockInvalidOperationLength') - .withArgs(0, this.operation.payloads.length, this.operation.values.length); - }); - - it('length mismatch #2', async function () { - await expect( - this.mock - .connect(this.executor) - .executeBatch( - this.operation.targets, - [], - this.operation.payloads, - this.operation.predecessor, - this.operation.salt, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockInvalidOperationLength') - .withArgs(this.operation.targets.length, this.operation.payloads.length, 0n); - }); - - it('length mismatch #3', async function () { - await expect( - this.mock - .connect(this.executor) - .executeBatch( - this.operation.targets, - this.operation.values, - [], - this.operation.predecessor, - this.operation.salt, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockInvalidOperationLength') - .withArgs(this.operation.targets.length, 0n, this.operation.values.length); - }); - - it('prevents reentrancy execution', async function () { - // Create operation - const reentrant = await ethers.deployContract('$TimelockReentrant'); - const reentrantBatchOperation = genOperationBatch( - [reentrant], - [0n], - [reentrant.interface.encodeFunctionData('reenter')], - ethers.ZeroHash, - salt, - ); - - // Schedule so it can be executed - await this.mock - .connect(this.proposer) - .scheduleBatch( - reentrantBatchOperation.targets, - reentrantBatchOperation.values, - reentrantBatchOperation.payloads, - reentrantBatchOperation.predecessor, - reentrantBatchOperation.salt, - MINDELAY, - ); - - // Advance on time to make the operation executable - await this.mock.getTimestamp(reentrantBatchOperation.id).then(time.increaseTo.timestamp); - - // Grant executor role to the reentrant contract - await this.mock.connect(this.admin).grantRole(EXECUTOR_ROLE, reentrant); - - // Prepare reenter - const data = this.mock.interface.encodeFunctionData('executeBatch', [ - reentrantBatchOperation.targets.map(getAddress), - reentrantBatchOperation.values, - reentrantBatchOperation.payloads, - reentrantBatchOperation.predecessor, - reentrantBatchOperation.salt, - ]); - await reentrant.enableRentrancy(this.mock, data); - - // Expect to fail - await expect( - this.mock - .connect(this.executor) - .executeBatch( - reentrantBatchOperation.targets, - reentrantBatchOperation.values, - reentrantBatchOperation.payloads, - reentrantBatchOperation.predecessor, - reentrantBatchOperation.salt, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') - .withArgs(reentrantBatchOperation.id, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); - - // Disable reentrancy - await reentrant.disableReentrancy(); - const nonReentrantBatchOperation = reentrantBatchOperation; // Not anymore - - // Try again successfully - const tx = this.mock - .connect(this.executor) - .executeBatch( - nonReentrantBatchOperation.targets, - nonReentrantBatchOperation.values, - nonReentrantBatchOperation.payloads, - nonReentrantBatchOperation.predecessor, - nonReentrantBatchOperation.salt, - ); - for (const i in nonReentrantBatchOperation.targets) { - await expect(tx) - .to.emit(this.mock, 'CallExecuted') - .withArgs( - nonReentrantBatchOperation.id, - i, - nonReentrantBatchOperation.targets[i], - nonReentrantBatchOperation.values[i], - nonReentrantBatchOperation.payloads[i], - ); - } - }); - }); - }); - - it('partial execution', async function () { - const operation = genOperationBatch( - [this.callreceivermock, this.callreceivermock, this.callreceivermock], - [0n, 0n, 0n], - [ - this.callreceivermock.interface.encodeFunctionData('mockFunction'), - this.callreceivermock.interface.encodeFunctionData('mockFunctionRevertsNoReason'), - this.callreceivermock.interface.encodeFunctionData('mockFunction'), - ], - ethers.ZeroHash, - '0x8ac04aa0d6d66b8812fb41d39638d37af0a9ab11da507afd65c509f8ed079d3e', - ); - - await this.mock - .connect(this.proposer) - .scheduleBatch( - operation.targets, - operation.values, - operation.payloads, - operation.predecessor, - operation.salt, - MINDELAY, - ); - - await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); - - await expect( - this.mock - .connect(this.executor) - .executeBatch( - operation.targets, - operation.values, - operation.payloads, - operation.predecessor, - operation.salt, - ), - ).to.be.revertedWithCustomError(this.mock, 'FailedCall'); - }); - }); - }); - - describe('cancel', function () { - beforeEach(async function () { - this.operation = genOperation( - '0xC6837c44AA376dbe1d2709F13879E040CAb653ca', - 0n, - '0x296e58dd', - ethers.ZeroHash, - '0xa2485763600634800df9fc9646fb2c112cf98649c55f63dd1d9c7d13a64399d9', - ); - await this.mock - .connect(this.proposer) - .schedule( - this.operation.target, - this.operation.value, - this.operation.data, - this.operation.predecessor, - this.operation.salt, - MINDELAY, - ); - }); - - it('canceller can cancel', async function () { - await expect(this.mock.connect(this.canceller).cancel(this.operation.id)) - .to.emit(this.mock, 'Cancelled') - .withArgs(this.operation.id); - }); - - it('cannot cancel invalid operation', async function () { - await expect(this.mock.connect(this.canceller).cancel(ethers.ZeroHash)) - .to.be.revertedWithCustomError(this.mock, 'TimelockUnexpectedOperationState') - .withArgs( - ethers.ZeroHash, - GovernorHelper.proposalStatesToBitMap([OperationState.Waiting, OperationState.Ready]), - ); - }); - - it('prevent non-canceller from canceling', async function () { - await expect(this.mock.connect(this.other).cancel(this.operation.id)) - .to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount') - .withArgs(this.other, CANCELLER_ROLE); - }); - }); - }); - - describe('maintenance', function () { - it('prevent unauthorized maintenance', async function () { - await expect(this.mock.connect(this.other).updateDelay(0n)) - .to.be.revertedWithCustomError(this.mock, 'TimelockUnauthorizedCaller') - .withArgs(this.other); - }); - - it('timelock scheduled maintenance', async function () { - const newDelay = time.duration.hours(6); - const operation = genOperation( - this.mock, - 0n, - this.mock.interface.encodeFunctionData('updateDelay', [newDelay]), - ethers.ZeroHash, - '0xf8e775b2c5f4d66fb5c7fa800f35ef518c262b6014b3c0aee6ea21bff157f108', - ); - - await this.mock - .connect(this.proposer) - .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); - - await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); - - await expect( - this.mock - .connect(this.executor) - .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt), - ) - .to.emit(this.mock, 'MinDelayChange') - .withArgs(MINDELAY, newDelay); - - expect(await this.mock.getMinDelay()).to.equal(newDelay); - }); - }); - - describe('dependency', function () { - beforeEach(async function () { - this.operation1 = genOperation( - '0xdE66bD4c97304200A95aE0AadA32d6d01A867E39', - 0n, - '0x01dc731a', - ethers.ZeroHash, - '0x64e932133c7677402ead2926f86205e2ca4686aebecf5a8077627092b9bb2feb', - ); - this.operation2 = genOperation( - '0x3c7944a3F1ee7fc8c5A5134ba7c79D11c3A1FCa3', - 0n, - '0x8f531849', - this.operation1.id, - '0x036e1311cac523f9548e6461e29fb1f8f9196b91910a41711ea22f5de48df07d', - ); - await this.mock - .connect(this.proposer) - .schedule( - this.operation1.target, - this.operation1.value, - this.operation1.data, - this.operation1.predecessor, - this.operation1.salt, - MINDELAY, - ); - await this.mock - .connect(this.proposer) - .schedule( - this.operation2.target, - this.operation2.value, - this.operation2.data, - this.operation2.predecessor, - this.operation2.salt, - MINDELAY, - ); - - await this.mock.getTimestamp(this.operation2.id).then(time.increaseTo.timestamp); - }); - - it('cannot execute before dependency', async function () { - await expect( - this.mock - .connect(this.executor) - .execute( - this.operation2.target, - this.operation2.value, - this.operation2.data, - this.operation2.predecessor, - this.operation2.salt, - ), - ) - .to.be.revertedWithCustomError(this.mock, 'TimelockUnexecutedPredecessor') - .withArgs(this.operation1.id); - }); - - it('can execute after dependency', async function () { - await this.mock - .connect(this.executor) - .execute( - this.operation1.target, - this.operation1.value, - this.operation1.data, - this.operation1.predecessor, - this.operation1.salt, - ); - await this.mock - .connect(this.executor) - .execute( - this.operation2.target, - this.operation2.value, - this.operation2.data, - this.operation2.predecessor, - this.operation2.salt, - ); - }); - }); - - describe('usage scenario', function () { - this.timeout(10000); - - it('call', async function () { - const operation = genOperation( - this.implementation2, - 0n, - this.implementation2.interface.encodeFunctionData('setValue', [42n]), - ethers.ZeroHash, - '0x8043596363daefc89977b25f9d9b4d06c3910959ef0c4d213557a903e1b555e2', - ); - - await this.mock - .connect(this.proposer) - .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); - - await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); - - await this.mock - .connect(this.executor) - .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt); - - expect(await this.implementation2.getValue()).to.equal(42n); - }); - - it('call reverting', async function () { - const operation = genOperation( - this.callreceivermock, - 0n, - this.callreceivermock.interface.encodeFunctionData('mockFunctionRevertsNoReason'), - ethers.ZeroHash, - '0xb1b1b276fdf1a28d1e00537ea73b04d56639128b08063c1a2f70a52e38cba693', - ); - - await this.mock - .connect(this.proposer) - .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); - - await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); - - await expect( - this.mock - .connect(this.executor) - .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt), - ).to.be.revertedWithCustomError(this.mock, 'FailedCall'); - }); - - it('call throw', async function () { - const operation = genOperation( - this.callreceivermock, - 0n, - this.callreceivermock.interface.encodeFunctionData('mockFunctionThrows'), - ethers.ZeroHash, - '0xe5ca79f295fc8327ee8a765fe19afb58f4a0cbc5053642bfdd7e73bc68e0fc67', - ); - - await this.mock - .connect(this.proposer) - .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); - - await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); - - // Targeted function reverts with a panic code (0x1) + the timelock bubble the panic code - await expect( - this.mock - .connect(this.executor) - .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt), - ).to.be.revertedWithPanic(PANIC_CODES.ASSERTION_ERROR); - }); - - it('call out of gas', async function () { - const operation = genOperation( - this.callreceivermock, - 0n, - this.callreceivermock.interface.encodeFunctionData('mockFunctionOutOfGas'), - ethers.ZeroHash, - '0xf3274ce7c394c5b629d5215723563a744b817e1730cca5587c567099a14578fd', - ); - - await this.mock - .connect(this.proposer) - .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); - - await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); - - await expect( - this.mock - .connect(this.executor) - .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { - gasLimit: '100000', - }), - ).to.be.revertedWithCustomError(this.mock, 'FailedCall'); - }); - - it('call payable with eth', async function () { - const operation = genOperation( - this.callreceivermock, - 1, - this.callreceivermock.interface.encodeFunctionData('mockFunction'), - ethers.ZeroHash, - '0x5ab73cd33477dcd36c1e05e28362719d0ed59a7b9ff14939de63a43073dc1f44', - ); - - await this.mock - .connect(this.proposer) - .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); - - await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); - - expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); - expect(await ethers.provider.getBalance(this.callreceivermock)).to.equal(0n); - - await this.mock - .connect(this.executor) - .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { - value: 1, - }); - - expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); - expect(await ethers.provider.getBalance(this.callreceivermock)).to.equal(1n); - }); - - it('call nonpayable with eth', async function () { - const operation = genOperation( - this.callreceivermock, - 1, - this.callreceivermock.interface.encodeFunctionData('mockFunctionNonPayable'), - ethers.ZeroHash, - '0xb78edbd920c7867f187e5aa6294ae5a656cfbf0dea1ccdca3751b740d0f2bdf8', - ); - - await this.mock - .connect(this.proposer) - .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); - - await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); - - expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); - expect(await ethers.provider.getBalance(this.callreceivermock)).to.equal(0n); - - await expect( - this.mock - .connect(this.executor) - .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt), - ).to.be.revertedWithCustomError(this.mock, 'FailedCall'); - - expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); - expect(await ethers.provider.getBalance(this.callreceivermock)).to.equal(0n); - }); - - it('call reverting with eth', async function () { - const operation = genOperation( - this.callreceivermock, - 1, - this.callreceivermock.interface.encodeFunctionData('mockFunctionRevertsNoReason'), - ethers.ZeroHash, - '0xdedb4563ef0095db01d81d3f2decf57cf83e4a72aa792af14c43a792b56f4de6', - ); - - await this.mock - .connect(this.proposer) - .schedule(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, MINDELAY); - - await this.mock.getTimestamp(operation.id).then(time.increaseTo.timestamp); - - expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); - expect(await ethers.provider.getBalance(this.callreceivermock)).to.equal(0n); - - await expect( - this.mock - .connect(this.executor) - .execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt), - ).to.be.revertedWithCustomError(this.mock, 'FailedCall'); - - expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); - expect(await ethers.provider.getBalance(this.callreceivermock)).to.equal(0n); - }); - }); - - describe('safe receive', function () { - describe('ERC721', function () { - const tokenId = 1n; - - beforeEach(async function () { - this.token = await ethers.deployContract('$ERC721', ['Non Fungible Token', 'NFT']); - await this.token.$_mint(this.other, tokenId); - }); - - it('can receive an ERC721 safeTransfer', async function () { - await this.token.connect(this.other).safeTransferFrom(this.other, this.mock, tokenId); - }); - }); - - describe('ERC1155', function () { - const tokenIds = { - 1: 1000n, - 2: 2000n, - 3: 3000n, - }; - - beforeEach(async function () { - this.token = await ethers.deployContract('$ERC1155', ['https://token-cdn-domain/{id}.json']); - await this.token.$_mintBatch(this.other, Object.keys(tokenIds), Object.values(tokenIds), '0x'); - }); - - it('can receive ERC1155 safeTransfer', async function () { - await this.token.connect(this.other).safeTransferFrom( - this.other, - this.mock, - ...Object.entries(tokenIds)[0n], // id + amount - '0x', - ); - }); - - it('can receive ERC1155 safeBatchTransfer', async function () { - await this.token - .connect(this.other) - .safeBatchTransferFrom(this.other, this.mock, Object.keys(tokenIds), Object.values(tokenIds), '0x'); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingFractional.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingFractional.test.js deleted file mode 100644 index a46de21..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingFractional.test.js +++ /dev/null @@ -1,248 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { GovernorHelper } = require('../../helpers/governance'); -const { VoteType } = require('../../helpers/enums'); -const { zip } = require('../../helpers/iterate'); -const { sum } = require('../../helpers/math'); - -const TOKENS = [ - { Token: '$ERC20Votes', mode: 'blocknumber' }, - { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, -]; - -const name = 'OZ-Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const votingDelay = 4n; -const votingPeriod = 16n; -const value = ethers.parseEther('1'); - -describe('GovernorCountingFractional', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [owner, proposer, voter1, voter2, voter3, voter4, other] = await ethers.getSigners(); - const receiver = await ethers.deployContract('CallReceiverMock'); - - const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); - const mock = await ethers.deployContract('$GovernorFractionalMock', [ - name, // name - votingDelay, // initialVotingDelay - votingPeriod, // initialVotingPeriod - 0n, // initialProposalThreshold - token, // tokenAddress - 10n, // quorumNumeratorValue - ]); - - await owner.sendTransaction({ to: mock, value }); - await token.$_mint(owner, tokenSupply); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); - await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); - await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); - await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); - - return { owner, proposer, voter1, voter2, voter3, voter4, other, receiver, token, mock, helper }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - value, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - }, - ], - '', - ); - }); - - it('deployment check', async function () { - expect(await this.mock.name()).to.equal(name); - expect(await this.mock.token()).to.equal(this.token); - expect(await this.mock.votingDelay()).to.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.equal(votingPeriod); - expect(await this.mock.COUNTING_MODE()).to.equal( - 'support=bravo,fractional&quorum=for,abstain¶ms=fractional', - ); - }); - - it('nominal is unaffected', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For, reason: 'This is nice' }); - await this.helper.connect(this.voter2).vote({ support: VoteType.For }); - await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); - await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - - expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; - expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.true; - expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.true; - expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); - expect(await ethers.provider.getBalance(this.receiver)).to.equal(value); - }); - - describe('voting with a fraction of the weight', function () { - it('twice', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - - expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([0n, 0n, 0n]); - expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.equal(false); - expect(await this.mock.usedVotes(this.proposal.id, this.voter2)).to.equal(0n); - - const steps = [ - ['0', '2', '1'], - ['1', '0', '1'], - ].map(votes => votes.map(vote => ethers.parseEther(vote))); - - for (const votes of steps) { - const params = ethers.solidityPacked(['uint128', 'uint128', 'uint128'], votes); - await expect( - this.helper.connect(this.voter2).vote({ - support: VoteType.Parameters, - reason: 'no particular reason', - params, - }), - ) - .to.emit(this.mock, 'VoteCastWithParams') - .withArgs( - this.voter2, - this.proposal.id, - VoteType.Parameters, - sum(...votes), - 'no particular reason', - params, - ); - } - - expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal(zip(...steps).map(v => sum(...v))); - expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.equal(true); - expect(await this.mock.usedVotes(this.proposal.id, this.voter2)).to.equal(sum(...[].concat(...steps))); - }); - - it('fractional then nominal', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - - expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([0n, 0n, 0n]); - expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.equal(false); - expect(await this.mock.usedVotes(this.proposal.id, this.voter2)).to.equal(0n); - - const weight = ethers.parseEther('7'); - const fractional = ['1', '2', '1'].map(ethers.parseEther); - - const params = ethers.solidityPacked(['uint128', 'uint128', 'uint128'], fractional); - await expect( - this.helper.connect(this.voter2).vote({ - support: VoteType.Parameters, - reason: 'no particular reason', - params, - }), - ) - .to.emit(this.mock, 'VoteCastWithParams') - .withArgs( - this.voter2, - this.proposal.id, - VoteType.Parameters, - sum(...fractional), - 'no particular reason', - params, - ); - - await expect(this.helper.connect(this.voter2).vote({ support: VoteType.Against })) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter2, this.proposal.id, VoteType.Against, weight - sum(...fractional), ''); - - expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([ - weight - sum(...fractional.slice(1)), - ...fractional.slice(1), - ]); - expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.equal(true); - expect(await this.mock.usedVotes(this.proposal.id, this.voter2)).to.equal(weight); - }); - - it('revert if params spend more than available', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - - const weight = ethers.parseEther('7'); - const fractional = ['0', '1000', '0'].map(ethers.parseEther); - - await expect( - this.helper.connect(this.voter2).vote({ - support: VoteType.Parameters, - reason: 'no particular reason', - params: ethers.solidityPacked(['uint128', 'uint128', 'uint128'], fractional), - }), - ) - .to.be.revertedWithCustomError(this.mock, 'GovernorExceedRemainingWeight') - .withArgs(this.voter2, sum(...fractional), weight); - }); - - it('revert if no weight remaining', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter2).vote({ support: VoteType.For }); - - await expect( - this.helper.connect(this.voter2).vote({ - support: VoteType.Parameters, - reason: 'no particular reason', - params: ethers.solidityPacked(['uint128', 'uint128', 'uint128'], [0n, 1n, 0n]), - }), - ) - .to.be.revertedWithCustomError(this.mock, 'GovernorAlreadyCastVote') - .withArgs(this.voter2); - }); - - it('revert if params are not properly formatted #1', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - - await expect( - this.helper.connect(this.voter2).vote({ - support: VoteType.Parameters, - reason: 'no particular reason', - params: ethers.solidityPacked(['uint128', 'uint128'], [0n, 1n]), - }), - ).to.be.revertedWithCustomError(this.mock, 'GovernorInvalidVoteParams'); - }); - - it('revert if params are not properly formatted #2', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - - await expect( - this.helper.connect(this.voter2).vote({ - support: VoteType.Against, - reason: 'no particular reason', - params: ethers.solidityPacked(['uint128', 'uint128', 'uint128'], [0n, 1n, 0n]), - }), - ).to.be.revertedWithCustomError(this.mock, 'GovernorInvalidVoteParams'); - }); - - it('revert if vote type is invalid', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - - await expect(this.helper.connect(this.voter2).vote({ support: 128n })).to.be.revertedWithCustomError( - this.mock, - 'GovernorInvalidVoteType', - ); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingOverridable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingOverridable.test.js deleted file mode 100644 index fd1032b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorCountingOverridable.test.js +++ /dev/null @@ -1,346 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers'); - -const { GovernorHelper } = require('../../helpers/governance'); -const { getDomain, OverrideBallot } = require('../../helpers/eip712'); -const { VoteType } = require('../../helpers/enums'); - -const TOKENS = [ - { Token: '$ERC20VotesExtendedMock', mode: 'blocknumber' }, - { Token: '$ERC20VotesExtendedTimestampMock', mode: 'timestamp' }, -]; - -const name = 'Override Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const votingDelay = 4n; -const votingPeriod = 16n; -const value = ethers.parseEther('1'); - -const signBallot = account => (contract, message) => - getDomain(contract).then(domain => account.signTypedData(domain, { OverrideBallot }, message)); - -describe('GovernorCountingOverridable', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [owner, proposer, voter1, voter2, voter3, voter4, other] = await ethers.getSigners(); - const receiver = await ethers.deployContract('CallReceiverMock'); - - const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); - const mock = await ethers.deployContract('$GovernorCountingOverridableMock', [ - name, // name - votingDelay, // initialVotingDelay - votingPeriod, // initialVotingPeriod - 0n, // initialProposalThreshold - token, // tokenAddress - 10n, // quorumNumeratorValue - ]); - - await owner.sendTransaction({ to: mock, value }); - await token.$_mint(owner, tokenSupply); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); - await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); - await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); - await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); - - return { owner, proposer, voter1, voter2, voter3, voter4, other, receiver, token, mock, helper }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - value, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - }, - ], - '', - ); - }); - - it('deployment check', async function () { - expect(await this.mock.name()).to.equal(name); - expect(await this.mock.token()).to.equal(this.token); - expect(await this.mock.votingDelay()).to.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.equal(votingPeriod); - expect(await this.mock.COUNTING_MODE()).to.equal('support=bravo,override&quorum=for,abstain&overridable=true'); - }); - - it('nominal is unaffected', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For, reason: 'This is nice' }); - await this.helper.connect(this.voter2).vote({ support: VoteType.For }); - await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); - await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - - expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; - expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.true; - expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.true; - expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); - expect(await ethers.provider.getBalance(this.receiver)).to.equal(value); - }); - - describe('cast override vote', async function () { - beforeEach(async function () { - // user 1 -(delegate 10 tokens)-> user 2 - // user 2 -(delegate 7 tokens)-> user 2 - // user 3 -(delegate 5 tokens)-> user 1 - // user 4 -(delegate 2 tokens)-> user 2 - await this.token.connect(this.voter1).delegate(this.voter2); - await this.token.connect(this.voter3).delegate(this.voter1); - await this.token.connect(this.voter4).delegate(this.voter2); - await mine(); - - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - }); - - it('override after delegate vote', async function () { - expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.false; - expect(await this.mock.hasVoted(this.helper.id, this.voter2)).to.be.false; - expect(await this.mock.hasVoted(this.helper.id, this.voter3)).to.be.false; - expect(await this.mock.hasVoted(this.helper.id, this.voter4)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter2)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter3)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter4)).to.be.false; - - // user 2 votes - - await expect(this.helper.connect(this.voter2).vote({ support: VoteType.For })) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter2, this.helper.id, VoteType.For, ethers.parseEther('19'), ''); // 10 + 7 + 2 - - expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( - [0, 19, 0].map(x => ethers.parseEther(x.toString())), - ); - expect(await this.mock.hasVoted(this.helper.id, this.voter2)).to.be.true; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter2)).to.be.false; - - // user 1 overrides after user 2 votes - - const reason = "disagree with user 2's decision"; - await expect(this.mock.connect(this.voter1).castOverrideVote(this.helper.id, VoteType.Against, reason)) - .to.emit(this.mock, 'OverrideVoteCast') - .withArgs(this.voter1, this.helper.id, VoteType.Against, ethers.parseEther('10'), reason) - .to.emit(this.mock, 'VoteReduced') - .withArgs(this.voter2, this.helper.id, VoteType.For, ethers.parseEther('10')); - - expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( - [10, 9, 0].map(x => ethers.parseEther(x.toString())), - ); - expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.true; - }); - - it('override before delegate vote', async function () { - expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.false; - expect(await this.mock.hasVoted(this.helper.id, this.voter2)).to.be.false; - expect(await this.mock.hasVoted(this.helper.id, this.voter3)).to.be.false; - expect(await this.mock.hasVoted(this.helper.id, this.voter4)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter2)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter3)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter4)).to.be.false; - - // user 1 overrides before user 2 votes - - const reason = 'voter 2 is not voting'; - await expect(this.mock.connect(this.voter1).castOverrideVote(this.helper.id, VoteType.Against, reason)) - .to.emit(this.mock, 'OverrideVoteCast') - .withArgs(this.voter1, this.helper.id, VoteType.Against, ethers.parseEther('10'), reason) - .to.not.emit(this.mock, 'VoteReduced'); - - expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( - [10, 0, 0].map(x => ethers.parseEther(x.toString())), - ); - expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.true; - - // user 2 votes - - await expect(this.helper.connect(this.voter2).vote({ support: VoteType.For })) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter2, this.helper.id, VoteType.For, ethers.parseEther('9'), ''); // 7 + 2 - - expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( - [10, 9, 0].map(x => ethers.parseEther(x.toString())), - ); - expect(await this.mock.hasVoted(this.helper.id, this.voter2)).to.be.true; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter2)).to.be.false; - }); - - it('override before and after delegate vote', async function () { - expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.false; - expect(await this.mock.hasVoted(this.helper.id, this.voter2)).to.be.false; - expect(await this.mock.hasVoted(this.helper.id, this.voter3)).to.be.false; - expect(await this.mock.hasVoted(this.helper.id, this.voter4)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter2)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter3)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter4)).to.be.false; - - // user 1 overrides before user 2 votes - - const reason = 'voter 2 is not voting'; - await expect(this.mock.connect(this.voter1).castOverrideVote(this.helper.id, VoteType.Against, reason)) - .to.emit(this.mock, 'OverrideVoteCast') - .withArgs(this.voter1, this.helper.id, VoteType.Against, ethers.parseEther('10'), reason) - .to.not.emit(this.mock, 'VoteReduced'); - - expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( - [10, 0, 0].map(x => ethers.parseEther(x.toString())), - ); - expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.true; - - // user 2 votes - - await expect(this.helper.connect(this.voter2).vote({ support: VoteType.For })) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter2, this.helper.id, VoteType.For, ethers.parseEther('9'), ''); // 7 + 2 - - expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( - [10, 9, 0].map(x => ethers.parseEther(x.toString())), - ); - expect(await this.mock.hasVoted(this.helper.id, this.voter2)).to.be.true; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter2)).to.be.false; - - // User 4 overrides after user 2 votes - - const reason2 = "disagree with user 2's decision"; - await expect(this.mock.connect(this.voter4).castOverrideVote(this.helper.id, VoteType.Abstain, reason2)) - .to.emit(this.mock, 'OverrideVoteCast') - .withArgs(this.voter4, this.helper.id, VoteType.Abstain, ethers.parseEther('2'), reason2) - .to.emit(this.mock, 'VoteReduced') - .withArgs(this.voter2, this.helper.id, VoteType.For, ethers.parseEther('2')); - - expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( - [10, 7, 2].map(x => ethers.parseEther(x.toString())), - ); - expect(await this.mock.hasVoted(this.helper.id, this.voter4)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter4)).to.be.true; - }); - - it('vote (with delegated balance) and override (with self balance) are independent', async function () { - expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( - [0, 0, 0].map(x => ethers.parseEther(x.toString())), - ); - expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.false; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.false; - - // user 1 votes with delegated weight from user 3 - await expect(this.mock.connect(this.voter1).castVote(this.helper.id, VoteType.For)) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter1, this.helper.id, VoteType.For, ethers.parseEther('5'), ''); - - // user 1 cast an override vote with its own balance (delegated to user 2) - await expect(this.mock.connect(this.voter1).castOverrideVote(this.helper.id, VoteType.Against, '')) - .to.emit(this.mock, 'OverrideVoteCast') - .withArgs(this.voter1, this.helper.id, VoteType.Against, ethers.parseEther('10'), ''); - - expect(await this.mock.proposalVotes(this.helper.id)).to.deep.eq( - [10, 5, 0].map(x => ethers.parseEther(x.toString())), - ); - expect(await this.mock.hasVoted(this.helper.id, this.voter1)).to.be.true; - expect(await this.mock.hasVotedOverride(this.helper.id, this.voter1)).to.be.true; - }); - - it('can not override vote twice', async function () { - await expect(this.mock.connect(this.voter1).castOverrideVote(this.helper.id, VoteType.Against, '')) - .to.emit(this.mock, 'OverrideVoteCast') - .withArgs(this.voter1, this.helper.id, VoteType.Against, ethers.parseEther('10'), ''); - await expect(this.mock.connect(this.voter1).castOverrideVote(this.helper.id, VoteType.Abstain, '')) - .to.be.revertedWithCustomError(this.mock, 'GovernorAlreadyOverriddenVote') - .withArgs(this.voter1.address); - }); - - it('can not vote twice', async function () { - await expect(this.mock.connect(this.voter1).castVote(this.helper.id, VoteType.Against)) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter1, this.helper.id, VoteType.Against, ethers.parseEther('5'), ''); - await expect(this.mock.connect(this.voter1).castVote(this.helper.id, VoteType.Abstain)) - .to.be.revertedWithCustomError(this.mock, 'GovernorAlreadyCastVote') - .withArgs(this.voter1.address); - }); - - describe('invalid vote type', function () { - it('override vote', async function () { - await expect( - this.mock.connect(this.voter1).castOverrideVote(this.helper.id, 3, ''), - ).to.be.revertedWithCustomError(this.mock, 'GovernorInvalidVoteType'); - }); - - it('traditional vote', async function () { - await expect(this.mock.connect(this.voter1).castVote(this.helper.id, 3)).to.be.revertedWithCustomError( - this.mock, - 'GovernorInvalidVoteType', - ); - }); - }); - - describe('by signature', function () { - it('EOA signature', async function () { - const nonce = await this.mock.nonces(this.voter1); - - await expect( - this.helper.overrideVote({ - support: VoteType.For, - voter: this.voter1.address, - nonce, - signature: signBallot(this.voter1), - }), - ) - .to.emit(this.mock, 'OverrideVoteCast') - .withArgs(this.voter1, this.helper.id, VoteType.For, ethers.parseEther('10'), ''); - - expect(await this.mock.hasVotedOverride(this.proposal.id, this.voter1)).to.be.true; - }); - - it('revert if signature does not match signer', async function () { - const nonce = await this.mock.nonces(this.voter1); - - const voteParams = { - support: VoteType.For, - voter: this.voter2.address, - nonce, - signature: signBallot(this.voter1), - }; - - await expect(this.helper.overrideVote(voteParams)) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') - .withArgs(voteParams.voter); - }); - - it('revert if vote nonce is incorrect', async function () { - const nonce = await this.mock.nonces(this.voter1); - - const voteParams = { - support: VoteType.For, - voter: this.voter1.address, - nonce: nonce + 1n, - signature: signBallot(this.voter1), - }; - - await expect(this.helper.overrideVote(voteParams)) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') - .withArgs(voteParams.voter); - }); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js deleted file mode 100644 index 15910b8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js +++ /dev/null @@ -1,131 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { GovernorHelper } = require('../../helpers/governance'); -const { VoteType } = require('../../helpers/enums'); - -const TOKENS = [ - { Token: '$ERC721Votes', mode: 'blocknumber' }, - { Token: '$ERC721VotesTimestampMock', mode: 'timestamp' }, -]; - -const name = 'OZ-Governor'; -const version = '1'; -const tokenName = 'MockNFToken'; -const tokenSymbol = 'MTKN'; -const NFT0 = 0n; -const NFT1 = 1n; -const NFT2 = 2n; -const NFT3 = 3n; -const NFT4 = 4n; -const votingDelay = 4n; -const votingPeriod = 16n; -const value = ethers.parseEther('1'); - -describe('GovernorERC721', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [owner, voter1, voter2, voter3, voter4] = await ethers.getSigners(); - const receiver = await ethers.deployContract('CallReceiverMock'); - - const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); - const mock = await ethers.deployContract('$GovernorMock', [ - name, // name - votingDelay, // initialVotingDelay - votingPeriod, // initialVotingPeriod - 0n, // initialProposalThreshold - token, // tokenAddress - 10n, // quorumNumeratorValue - ]); - - await owner.sendTransaction({ to: mock, value }); - await Promise.all([NFT0, NFT1, NFT2, NFT3, NFT4].map(tokenId => token.$_mint(owner, tokenId))); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(owner).delegate({ token, to: voter1, tokenId: NFT0 }); - await helper.connect(owner).delegate({ token, to: voter2, tokenId: NFT1 }); - await helper.connect(owner).delegate({ token, to: voter2, tokenId: NFT2 }); - await helper.connect(owner).delegate({ token, to: voter3, tokenId: NFT3 }); - await helper.connect(owner).delegate({ token, to: voter4, tokenId: NFT4 }); - - return { - owner, - voter1, - voter2, - voter3, - voter4, - receiver, - token, - mock, - helper, - }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - // initiate fresh proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - value, - }, - ], - '', - ); - }); - - it('deployment check', async function () { - expect(await this.mock.name()).to.equal(name); - expect(await this.mock.token()).to.equal(this.token); - expect(await this.mock.votingDelay()).to.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.equal(votingPeriod); - expect(await this.mock.quorum(0n)).to.equal(0n); - - expect(await this.token.getVotes(this.voter1)).to.equal(1n); // NFT0 - expect(await this.token.getVotes(this.voter2)).to.equal(2n); // NFT1 & NFT2 - expect(await this.token.getVotes(this.voter3)).to.equal(1n); // NFT3 - expect(await this.token.getVotes(this.voter4)).to.equal(1n); // NFT4 - }); - - it('voting with ERC721 token', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - - await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For })) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter1, this.proposal.id, VoteType.For, 1n, ''); - - await expect(this.helper.connect(this.voter2).vote({ support: VoteType.For })) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter2, this.proposal.id, VoteType.For, 2n, ''); - - await expect(this.helper.connect(this.voter3).vote({ support: VoteType.Against })) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter3, this.proposal.id, VoteType.Against, 1n, ''); - - await expect(this.helper.connect(this.voter4).vote({ support: VoteType.Abstain })) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter4, this.proposal.id, VoteType.Abstain, 1n, ''); - - await this.helper.waitForDeadline(); - await this.helper.execute(); - - expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; - expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.true; - expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.true; - expect(await this.mock.hasVoted(this.proposal.id, this.voter3)).to.be.true; - expect(await this.mock.hasVoted(this.proposal.id, this.voter4)).to.be.true; - - expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([ - 1n, // againstVotes - 3n, // forVotes - 1n, // abstainVotes - ]); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorNoncesKeyed.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorNoncesKeyed.test.js deleted file mode 100644 index e2cbd8f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorNoncesKeyed.test.js +++ /dev/null @@ -1,244 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { GovernorHelper } = require('../../helpers/governance'); -const { getDomain, Ballot, ExtendedBallot } = require('../../helpers/eip712'); -const { VoteType } = require('../../helpers/enums'); -const { shouldBehaveLikeNoncesKeyed } = require('../../utils/Nonces.behavior'); - -const name = 'OZ-Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const votingDelay = 4n; -const votingPeriod = 16n; -const value = ethers.parseEther('1'); - -const signBallot = account => (contract, message) => - getDomain(contract).then(domain => account.signTypedData(domain, { Ballot }, message)); -const signExtendedBallot = account => (contract, message) => - getDomain(contract).then(domain => account.signTypedData(domain, { ExtendedBallot }, message)); - -describe('GovernorNoncesKeyed', function () { - const fixture = async () => { - const [owner, proposer, voter1, voter2, voter3, voter4, userEOA] = await ethers.getSigners(); - const receiver = await ethers.deployContract('CallReceiverMock'); - - const token = await ethers.deployContract('$ERC20Votes', [tokenName, tokenSymbol, tokenName, version]); - const mock = await ethers.deployContract('$GovernorNoncesKeyedMock', [ - name, // name - votingDelay, // initialVotingDelay - votingPeriod, // initialVotingPeriod - 0n, // initialProposalThreshold - token, // tokenAddress - 10n, // quorumNumeratorValue - ]); - - await owner.sendTransaction({ to: mock, value }); - await token.$_mint(owner, tokenSupply); - - const helper = new GovernorHelper(mock, 'blocknumber'); - await helper.connect(owner).delegate({ token: token, to: voter1, value: ethers.parseEther('10') }); - await helper.connect(owner).delegate({ token: token, to: voter2, value: ethers.parseEther('7') }); - await helper.connect(owner).delegate({ token: token, to: voter3, value: ethers.parseEther('5') }); - await helper.connect(owner).delegate({ token: token, to: voter4, value: ethers.parseEther('2') }); - - return { - owner, - proposer, - voter1, - voter2, - voter3, - voter4, - userEOA, - receiver, - token, - mock, - helper, - }; - }; - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - value, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - }, - ], - '', - ); - }); - - it('deployment check', async function () { - await expect(this.mock.name()).to.eventually.equal(name); - await expect(this.mock.token()).to.eventually.equal(this.token); - await expect(this.mock.votingDelay()).to.eventually.equal(votingDelay); - await expect(this.mock.votingPeriod()).to.eventually.equal(votingPeriod); - }); - - describe('vote with signature', function () { - for (const nonceType of ['default', 'keyed']) { - describe(`with ${nonceType} nonce`, function () { - beforeEach(async function () { - await this.helper.propose(); - - const maskedProposalId = BigInt(this.helper.id) & (2n ** 192n - 1n); - - this.getNonce = async address => { - return await (nonceType === 'default' - ? this.mock.nonces(address) - : this.mock['nonces(address,uint192)'](address, maskedProposalId)); - }; - }); - - it('votes with an EOA signature', async function () { - await this.token.connect(this.voter1).delegate(this.userEOA); - - const nonce = await this.getNonce(this.userEOA); - - await this.helper.waitForSnapshot(); - await expect( - this.helper.vote({ - support: VoteType.For, - voter: this.userEOA.address, - nonce, - signature: signBallot(this.userEOA), - }), - ) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.userEOA, this.proposal.id, VoteType.For, ethers.parseEther('10'), ''); - - await this.helper.waitForDeadline(); - await this.helper.execute(); - - // After - expect(await this.mock.hasVoted(this.proposal.id, this.userEOA)).to.be.true; - expect(await this.getNonce(this.userEOA)).to.equal(nonce + 1n); - }); - - it('votes with an EOA signature with reason', async function () { - await this.token.connect(this.voter1).delegate(this.userEOA); - - const nonce = await this.getNonce(this.userEOA); - - await this.helper.waitForSnapshot(); - await expect( - this.helper.vote({ - support: VoteType.For, - voter: this.userEOA.address, - nonce, - reason: 'This is an example reason', - signature: signExtendedBallot(this.userEOA), - }), - ) - .to.emit(this.mock, 'VoteCast') - .withArgs( - this.userEOA, - this.proposal.id, - VoteType.For, - ethers.parseEther('10'), - 'This is an example reason', - ); - - await this.helper.waitForDeadline(); - await this.helper.execute(); - - // After - expect(await this.mock.hasVoted(this.proposal.id, this.userEOA)).to.be.true; - expect(await this.getNonce(this.userEOA)).to.equal(nonce + 1n); - }); - - it('votes with a valid EIP-1271 signature', async function () { - const wallet = await ethers.deployContract('ERC1271WalletMock', [this.userEOA]); - - await this.token.connect(this.voter1).delegate(wallet); - - const nonce = await this.getNonce(wallet.target); - - await this.helper.waitForSnapshot(); - await expect( - this.helper.vote({ - support: VoteType.For, - voter: wallet.target, - nonce, - signature: signBallot(this.userEOA), - }), - ) - .to.emit(this.mock, 'VoteCast') - .withArgs(wallet, this.proposal.id, VoteType.For, ethers.parseEther('10'), ''); - await this.helper.waitForDeadline(); - await this.helper.execute(); - - // After - expect(await this.mock.hasVoted(this.proposal.id, wallet)).to.be.true; - expect(await this.getNonce(wallet)).to.equal(nonce + 1n); - }); - - afterEach('no other votes are cast', async function () { - expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; - expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.false; - expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.false; - }); - }); - } - }); - - describe('on vote by signature', function () { - beforeEach(async function () { - await this.token.connect(this.voter1).delegate(this.userEOA); - - // 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.userEOA); - - function tamper(str, index, mask) { - const arrayStr = ethers.getBytes(str); - arrayStr[index] ^= mask; - return ethers.hexlify(arrayStr); - } - - const voteParams = { - support: VoteType.For, - voter: this.userEOA.address, - nonce, - signature: (...args) => signBallot(this.userEOA)(...args).then(sig => tamper(sig, 42, 0xff)), - }; - - await expect(this.helper.vote(voteParams)) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') - .withArgs(voteParams.voter); - }); - - for (const nonceType of ['default', 'keyed']) { - it(`if vote nonce is incorrect with ${nonceType} nonce`, async function () { - const nonce = await (nonceType === 'default' - ? this.mock.nonces(this.userEOA) - : this.mock['nonces(address,uint192)'](this.userEOA, BigInt(this.helper.id) & (2n ** 192n - 1n))); - - const voteParams = { - support: VoteType.For, - voter: this.userEOA.address, - nonce: nonce + 1n, - signature: signBallot(this.userEOA), - }; - - await expect(this.helper.vote(voteParams)) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') - .withArgs(voteParams.voter); - }); - } - }); - - shouldBehaveLikeNoncesKeyed(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js deleted file mode 100644 index 761087a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js +++ /dev/null @@ -1,185 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { GovernorHelper } = require('../../helpers/governance'); -const { ProposalState, VoteType } = require('../../helpers/enums'); -const time = require('../../helpers/time'); - -const TOKENS = [ - { Token: '$ERC20Votes', mode: 'blocknumber' }, - { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, -]; - -const name = 'OZ-Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const votingDelay = 4n; -const votingPeriod = 16n; -const lateQuorumVoteExtension = 8n; -const quorum = ethers.parseEther('1'); -const value = ethers.parseEther('1'); - -describe('GovernorPreventLateQuorum', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [owner, proposer, voter1, voter2, voter3, voter4] = await ethers.getSigners(); - const receiver = await ethers.deployContract('CallReceiverMock'); - - const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); - const mock = await ethers.deployContract('$GovernorPreventLateQuorumMock', [ - name, // name - votingDelay, // initialVotingDelay - votingPeriod, // initialVotingPeriod - 0n, // initialProposalThreshold - token, // tokenAddress - lateQuorumVoteExtension, - quorum, - ]); - - await owner.sendTransaction({ to: mock, value }); - await token.$_mint(owner, tokenSupply); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); - await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); - await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); - await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); - - return { owner, proposer, voter1, voter2, voter3, voter4, receiver, token, mock, helper }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - // initiate fresh proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - value, - }, - ], - '', - ); - }); - - it('deployment check', async function () { - expect(await this.mock.name()).to.equal(name); - expect(await this.mock.token()).to.equal(this.token); - expect(await this.mock.votingDelay()).to.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.equal(votingPeriod); - expect(await this.mock.quorum(0)).to.equal(quorum); - expect(await this.mock.lateQuorumVoteExtension()).to.equal(lateQuorumVoteExtension); - }); - - it('nominal workflow unaffected', async function () { - const txPropose = await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.connect(this.voter2).vote({ support: VoteType.For }); - await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); - await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - - expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; - expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.true; - expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.true; - expect(await this.mock.hasVoted(this.proposal.id, this.voter3)).to.be.true; - expect(await this.mock.hasVoted(this.proposal.id, this.voter4)).to.be.true; - - expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([ - ethers.parseEther('5'), // againstVotes - ethers.parseEther('17'), // forVotes - ethers.parseEther('2'), // abstainVotes - ]); - - const voteStart = (await time.clockFromReceipt[mode](txPropose)) + votingDelay; - const voteEnd = (await time.clockFromReceipt[mode](txPropose)) + votingDelay + votingPeriod; - expect(await this.mock.proposalSnapshot(this.proposal.id)).to.equal(voteStart); - expect(await this.mock.proposalDeadline(this.proposal.id)).to.equal(voteEnd); - - await expect(txPropose) - .to.emit(this.mock, 'ProposalCreated') - .withArgs( - this.proposal.id, - this.proposer, - this.proposal.targets, - this.proposal.values, - this.proposal.signatures, - this.proposal.data, - voteStart, - voteEnd, - this.proposal.description, - ); - }); - - it('Delay is extended to prevent last minute take-over', async function () { - const txPropose = await this.helper.connect(this.proposer).propose(); - - // compute original schedule - const snapshotTimepoint = (await time.clockFromReceipt[mode](txPropose)) + votingDelay; - const deadlineTimepoint = (await time.clockFromReceipt[mode](txPropose)) + votingDelay + votingPeriod; - expect(await this.mock.proposalSnapshot(this.proposal.id)).to.equal(snapshotTimepoint); - expect(await this.mock.proposalDeadline(this.proposal.id)).to.equal(deadlineTimepoint); - // wait for the last minute to vote - await this.helper.waitForDeadline(-1n); - const txVote = await this.helper.connect(this.voter2).vote({ support: VoteType.For }); - - // cannot execute yet - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active); - - // compute new extended schedule - const extendedDeadline = (await time.clockFromReceipt[mode](txVote)) + lateQuorumVoteExtension; - expect(await this.mock.proposalSnapshot(this.proposal.id)).to.equal(snapshotTimepoint); - expect(await this.mock.proposalDeadline(this.proposal.id)).to.equal(extendedDeadline); - - // still possible to vote - await this.helper.connect(this.voter1).vote({ support: VoteType.Against }); - - await this.helper.waitForDeadline(); - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active); - await this.helper.waitForDeadline(1n); - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Defeated); - - // check extension event - await expect(txVote).to.emit(this.mock, 'ProposalExtended').withArgs(this.proposal.id, extendedDeadline); - }); - - describe('onlyGovernance updates', function () { - it('setLateQuorumVoteExtension is protected', async function () { - await expect(this.mock.connect(this.owner).setLateQuorumVoteExtension(0n)) - .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') - .withArgs(this.owner); - }); - - it('can setLateQuorumVoteExtension through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('setLateQuorumVoteExtension', [0n]), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.execute()) - .to.emit(this.mock, 'LateQuorumVoteExtensionSet') - .withArgs(lateQuorumVoteExtension, 0n); - - expect(await this.mock.lateQuorumVoteExtension()).to.equal(0n); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorProposalGuardian.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorProposalGuardian.test.js deleted file mode 100644 index 1741072..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorProposalGuardian.test.js +++ /dev/null @@ -1,132 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { impersonate } = require('../../helpers/account'); -const { GovernorHelper } = require('../../helpers/governance'); -const { ProposalState } = require('../../helpers/enums'); - -const TOKENS = [ - { Token: '$ERC20Votes', mode: 'blocknumber' }, - { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, -]; -const name = 'Proposal Guardian Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const votingDelay = 4n; -const votingPeriod = 16n; -const value = ethers.parseEther('1'); - -describe('GovernorProposalGuardian', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [owner, proposer, guardian, voter1, voter2, voter3, voter4, other] = await ethers.getSigners(); - const receiver = await ethers.deployContract('CallReceiverMock'); - - const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); - const mock = await ethers.deployContract('$GovernorProposalGuardianMock', [ - name, // name - votingDelay, // initialVotingDelay - votingPeriod, // initialVotingPeriod - 0n, // initialProposalThreshold - token, // tokenAddress - 10n, // quorumNumeratorValue - ]); - - await impersonate(mock.target); - await owner.sendTransaction({ to: mock, value }); - await token.$_mint(owner, tokenSupply); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); - await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); - await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); - await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); - - return { owner, proposer, guardian, voter1, voter2, voter3, voter4, other, receiver, token, mock, helper }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - value, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - }, - ], - '', - ); - }); - - it('deployment check', async function () { - await expect(this.mock.name()).to.eventually.equal(name); - await expect(this.mock.token()).to.eventually.equal(this.token); - await expect(this.mock.votingDelay()).to.eventually.equal(votingDelay); - await expect(this.mock.votingPeriod()).to.eventually.equal(votingPeriod); - }); - - describe('set proposal guardian', function () { - it('from governance', async function () { - const governorSigner = await ethers.getSigner(this.mock.target); - await expect(this.mock.connect(governorSigner).setProposalGuardian(this.guardian)) - .to.emit(this.mock, 'ProposalGuardianSet') - .withArgs(ethers.ZeroAddress, this.guardian); - await expect(this.mock.proposalGuardian()).to.eventually.equal(this.guardian); - }); - - it('from non-governance', async function () { - await expect(this.mock.connect(this.other).setProposalGuardian(this.guardian)) - .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') - .withArgs(this.other); - }); - }); - - it('cancel proposal during pending state from proposer when proposal guardian is non-zero', async function () { - await this.mock.$_setProposalGuardian(this.guardian); - await this.helper.connect(this.proposer).propose(); - await expect(this.helper.connect(this.proposer).cancel()) - .to.emit(this.mock, 'ProposalCanceled') - .withArgs(this.proposal.id); - }); - - describe('cancel proposal during active state', function () { - beforeEach(async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(1n); - await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Active); - }); - - it('from proposal guardian', async function () { - await this.mock.$_setProposalGuardian(this.guardian); - - await expect(this.helper.connect(this.guardian).cancel()) - .to.emit(this.mock, 'ProposalCanceled') - .withArgs(this.proposal.id); - }); - - it('from proposer when proposal guardian is non-zero', async function () { - await this.mock.$_setProposalGuardian(this.guardian); - - await expect(this.helper.connect(this.proposer).cancel()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnableToCancel') - .withArgs(this.proposal.id, this.proposer); - }); - - it('from proposer when proposal guardian is zero', async function () { - await this.mock.$_setProposalGuardian(ethers.ZeroAddress); - - await expect(this.helper.connect(this.proposer).cancel()) - .to.emit(this.mock, 'ProposalCanceled') - .withArgs(this.proposal.id); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSequentialProposalId.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSequentialProposalId.test.js deleted file mode 100644 index 81bc6eb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSequentialProposalId.test.js +++ /dev/null @@ -1,202 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); - -const { GovernorHelper } = require('../../helpers/governance'); -const { VoteType } = require('../../helpers/enums'); -const iterate = require('../../helpers/iterate'); - -const TOKENS = [ - { Token: '$ERC20Votes', mode: 'blocknumber' }, - { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, -]; - -const name = 'OZ-Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const votingDelay = 4n; -const votingPeriod = 16n; -const value = ethers.parseEther('1'); - -async function deployToken(contractName) { - try { - return await ethers.deployContract(contractName, [tokenName, tokenSymbol, tokenName, version]); - } catch (error) { - if (error.message == 'incorrect number of arguments to constructor') { - // ERC20VotesLegacyMock has a different construction that uses version='1' by default. - return ethers.deployContract(contractName, [tokenName, tokenSymbol, tokenName]); - } - throw error; - } -} - -describe('GovernorSequentialProposalId', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [owner, proposer, voter1, voter2, voter3, voter4, userEOA] = await ethers.getSigners(); - const receiver = await ethers.deployContract('CallReceiverMock'); - - const token = await deployToken(Token, [tokenName, tokenSymbol, version]); - const mock = await ethers.deployContract('$GovernorSequentialProposalIdMock', [ - name, // name - votingDelay, // initialVotingDelay - votingPeriod, // initialVotingPeriod - 0n, // initialProposalThreshold - token, // tokenAddress - 10n, // quorumNumeratorValue - ]); - - await owner.sendTransaction({ to: mock, value }); - await token.$_mint(owner, tokenSupply); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(owner).delegate({ token: token, to: voter1, value: ethers.parseEther('10') }); - await helper.connect(owner).delegate({ token: token, to: voter2, value: ethers.parseEther('7') }); - await helper.connect(owner).delegate({ token: token, to: voter3, value: ethers.parseEther('5') }); - await helper.connect(owner).delegate({ token: token, to: voter4, value: ethers.parseEther('2') }); - - return { - owner, - proposer, - voter1, - voter2, - voter3, - voter4, - userEOA, - receiver, - token, - mock, - helper, - }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - value, - }, - ], - '', - ); - }); - - it('sequential proposal ids', async function () { - for (const i of iterate.range(1, 10)) { - this.proposal.description = ``; - - await expect(this.mock.hashProposal(...this.proposal.shortProposal)).to.eventually.equal(this.proposal.hash); - await expect(this.mock.getProposalId(...this.proposal.shortProposal)).revertedWithCustomError( - this.mock, - 'GovernorNonexistentProposal', - ); - await expect(this.mock.latestProposalId()).to.eventually.equal(i - 1); - - await expect(this.helper.connect(this.proposer).propose()) - .to.emit(this.mock, 'ProposalCreated') - .withArgs( - i, - this.proposer, - this.proposal.targets, - this.proposal.values, - this.proposal.signatures, - this.proposal.data, - anyValue, - anyValue, - this.proposal.description, - ); - - await expect(this.mock.hashProposal(...this.proposal.shortProposal)).to.eventually.equal(this.proposal.hash); - await expect(this.mock.getProposalId(...this.proposal.shortProposal)).to.eventually.equal(i); - await expect(this.mock.latestProposalId()).to.eventually.equal(i); - } - }); - - it('sequential proposal ids with offset start', async function () { - const offset = 69420; - await this.mock.$_initializeLatestProposalId(offset); - - for (const i of iterate.range(offset + 1, offset + 10)) { - this.proposal.description = ``; - - await expect(this.mock.hashProposal(...this.proposal.shortProposal)).to.eventually.equal(this.proposal.hash); - await expect(this.mock.getProposalId(...this.proposal.shortProposal)).revertedWithCustomError( - this.mock, - 'GovernorNonexistentProposal', - ); - await expect(this.mock.latestProposalId()).to.eventually.equal(i - 1); - - await expect(this.helper.connect(this.proposer).propose()) - .to.emit(this.mock, 'ProposalCreated') - .withArgs( - i, - this.proposer, - this.proposal.targets, - this.proposal.values, - this.proposal.signatures, - this.proposal.data, - anyValue, - anyValue, - this.proposal.description, - ); - - await expect(this.mock.hashProposal(...this.proposal.shortProposal)).to.eventually.equal(this.proposal.hash); - await expect(this.mock.getProposalId(...this.proposal.shortProposal)).to.eventually.equal(i); - await expect(this.mock.latestProposalId()).to.eventually.equal(i); - } - }); - - it('can only initialize latest proposal id from 0', async function () { - await this.helper.propose(); - await expect(this.mock.latestProposalId()).to.eventually.equal(1); - await expect(this.mock.$_initializeLatestProposalId(2)).to.be.revertedWithCustomError( - this.mock, - 'GovernorAlreadyInitializedLatestProposalId', - ); - }); - - it('cannot repropose same proposal', async function () { - await this.helper.connect(this.proposer).propose(); - await expect(this.helper.connect(this.proposer).propose()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs(await this.proposal.id, 0, ethers.ZeroHash); - }); - - it('nominal workflow', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - - await expect(this.mock.connect(this.voter1).castVote(1, VoteType.For)) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter1, 1, VoteType.For, ethers.parseEther('10'), ''); - - await expect(this.mock.connect(this.voter2).castVote(1, VoteType.For)) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter2, 1, VoteType.For, ethers.parseEther('7'), ''); - - await expect(this.mock.connect(this.voter3).castVote(1, VoteType.For)) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter3, 1, VoteType.For, ethers.parseEther('5'), ''); - - await expect(this.mock.connect(this.voter4).castVote(1, VoteType.Abstain)) - .to.emit(this.mock, 'VoteCast') - .withArgs(this.voter4, 1, VoteType.Abstain, ethers.parseEther('2'), ''); - - await this.helper.waitForDeadline(); - - await expect(this.helper.execute()) - .to.eventually.emit(this.mock, 'ProposalExecuted') - .withArgs(1) - .emit(this.receiver, 'MockFunctionCalled'); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorStorage.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorStorage.test.js deleted file mode 100644 index f079405..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorStorage.test.js +++ /dev/null @@ -1,155 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -const { GovernorHelper, timelockSalt } = require('../../helpers/governance'); -const { VoteType } = require('../../helpers/enums'); - -const TOKENS = [ - { Token: '$ERC20Votes', mode: 'blocknumber' }, - { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, -]; - -const DEFAULT_ADMIN_ROLE = ethers.ZeroHash; -const PROPOSER_ROLE = ethers.id('PROPOSER_ROLE'); -const EXECUTOR_ROLE = ethers.id('EXECUTOR_ROLE'); -const CANCELLER_ROLE = ethers.id('CANCELLER_ROLE'); - -const name = 'OZ-Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const votingDelay = 4n; -const votingPeriod = 16n; -const value = ethers.parseEther('1'); -const delay = 3600n; - -describe('GovernorStorage', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [deployer, owner, proposer, voter1, voter2, voter3, voter4] = await ethers.getSigners(); - const receiver = await ethers.deployContract('CallReceiverMock'); - - const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); - const timelock = await ethers.deployContract('TimelockController', [delay, [], [], deployer]); - const mock = await ethers.deployContract('$GovernorStorageMock', [ - name, - votingDelay, - votingPeriod, - 0n, - timelock, - token, - 0n, - ]); - - await owner.sendTransaction({ to: timelock, value }); - await token.$_mint(owner, tokenSupply); - await timelock.grantRole(PROPOSER_ROLE, mock); - await timelock.grantRole(PROPOSER_ROLE, owner); - await timelock.grantRole(CANCELLER_ROLE, mock); - await timelock.grantRole(CANCELLER_ROLE, owner); - await timelock.grantRole(EXECUTOR_ROLE, ethers.ZeroAddress); - await timelock.revokeRole(DEFAULT_ADMIN_ROLE, deployer); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); - await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); - await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); - await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); - - return { deployer, owner, proposer, voter1, voter2, voter3, voter4, receiver, token, timelock, mock, helper }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - // initiate fresh proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - value, - }, - ], - '', - ); - this.proposal.timelockid = await this.timelock.hashOperationBatch( - ...this.proposal.shortProposal.slice(0, 3), - ethers.ZeroHash, - timelockSalt(this.mock.target, this.proposal.shortProposal[3]), - ); - }); - - describe('proposal indexing', function () { - it('before propose', async function () { - expect(await this.mock.proposalCount()).to.equal(0n); - - await expect(this.mock.proposalDetailsAt(0n)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); - - await expect(this.mock.proposalDetails(this.proposal.id)) - .to.be.revertedWithCustomError(this.mock, 'GovernorNonexistentProposal') - .withArgs(this.proposal.id); - }); - - it('after propose', async function () { - await this.helper.propose(); - - expect(await this.mock.proposalCount()).to.equal(1n); - - expect(await this.mock.proposalDetailsAt(0n)).to.deep.equal([ - this.proposal.id, - this.proposal.targets, - this.proposal.values, - this.proposal.data, - this.proposal.descriptionHash, - ]); - - expect(await this.mock.proposalDetails(this.proposal.id)).to.deep.equal([ - this.proposal.targets, - this.proposal.values, - this.proposal.data, - this.proposal.descriptionHash, - ]); - }); - }); - - it('queue and execute by id', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.connect(this.voter2).vote({ support: VoteType.For }); - await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); - await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }); - await this.helper.waitForDeadline(); - - await expect(this.mock.queue(this.proposal.id)) - .to.emit(this.mock, 'ProposalQueued') - .withArgs(this.proposal.id, anyValue) - .to.emit(this.timelock, 'CallScheduled') - .withArgs(this.proposal.timelockid, ...Array(6).fill(anyValue)) - .to.emit(this.timelock, 'CallSalt') - .withArgs(this.proposal.timelockid, anyValue); - - await this.helper.waitForEta(); - - await expect(this.mock.execute(this.proposal.id)) - .to.emit(this.mock, 'ProposalExecuted') - .withArgs(this.proposal.id) - .to.emit(this.timelock, 'CallExecuted') - .withArgs(this.proposal.timelockid, ...Array(4).fill(anyValue)) - .to.emit(this.receiver, 'MockFunctionCalled'); - }); - - it('cancel by id', async function () { - await this.helper.connect(this.proposer).propose(); - await expect(this.mock.connect(this.proposer).cancel(this.proposal.id)) - .to.emit(this.mock, 'ProposalCanceled') - .withArgs(this.proposal.id); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorum.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorum.test.js deleted file mode 100644 index 9a8b845..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorum.test.js +++ /dev/null @@ -1,168 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { GovernorHelper } = require('../../helpers/governance'); -const { ProposalState, VoteType } = require('../../helpers/enums'); -const time = require('../../helpers/time'); - -const TOKENS = [ - { Token: '$ERC20Votes', mode: 'blocknumber' }, - { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, -]; - -const DEFAULT_ADMIN_ROLE = ethers.ZeroHash; -const PROPOSER_ROLE = ethers.id('PROPOSER_ROLE'); -const EXECUTOR_ROLE = ethers.id('EXECUTOR_ROLE'); -const CANCELLER_ROLE = ethers.id('CANCELLER_ROLE'); - -const name = 'OZ-Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const votingDelay = 4n; -const votingPeriod = 16n; -const quorum = 10n; -const superQuorum = 40n; -const value = ethers.parseEther('1'); -const delay = time.duration.hours(1n); - -describe('GovernorSuperQuorum', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [proposer, voter1, voter2, voter3, voter4, voter5] = await ethers.getSigners(); - const receiver = await ethers.deployContract('CallReceiverMock'); - - const timelock = await ethers.deployContract('TimelockController', [delay, [], [], proposer]); - const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); - const mock = await ethers.deployContract('$GovernorSuperQuorumMock', [ - name, - votingDelay, // initialVotingDelay - votingPeriod, // initialVotingPeriod - 0n, // initialProposalThreshold - token, - timelock, - quorum, - superQuorum, - ]); - - await proposer.sendTransaction({ to: timelock, value }); - await token.$_mint(proposer, tokenSupply); - await timelock.grantRole(PROPOSER_ROLE, mock); - await timelock.grantRole(PROPOSER_ROLE, proposer); - await timelock.grantRole(CANCELLER_ROLE, mock); - await timelock.grantRole(CANCELLER_ROLE, proposer); - await timelock.grantRole(EXECUTOR_ROLE, ethers.ZeroAddress); - await timelock.revokeRole(DEFAULT_ADMIN_ROLE, proposer); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(proposer).delegate({ token, to: voter1, value: 40 }); - await helper.connect(proposer).delegate({ token, to: voter2, value: 30 }); - await helper.connect(proposer).delegate({ token, to: voter3, value: 20 }); - await helper.connect(proposer).delegate({ token, to: voter4, value: 15 }); - await helper.connect(proposer).delegate({ token, to: voter5, value: 5 }); - - return { proposer, voter1, voter2, voter3, voter4, voter5, receiver, token, mock, timelock, helper }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - value, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - }, - ], - '', - ); - }); - - it('deployment check', async function () { - await expect(this.mock.name()).to.eventually.equal(name); - await expect(this.mock.token()).to.eventually.equal(this.token); - await expect(this.mock.quorum(0)).to.eventually.equal(quorum); - await expect(this.mock.superQuorum(0)).to.eventually.equal(superQuorum); - }); - - it('proposal succeeds early when super quorum is reached', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - - // Vote with voter2 (30) - above quorum (10) but below super quorum (40) - await this.helper.connect(this.voter2).vote({ support: VoteType.For }); - await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Active); - - // Vote with voter3 (20) to reach super quorum (50 total > 40) - await this.helper.connect(this.voter3).vote({ support: VoteType.For }); - - await expect(this.mock.proposalEta(this.proposal.id)).to.eventually.equal(0); - - // Should be succeeded since we reached super quorum and no eta is set - await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Succeeded); - }); - - it('proposal remains active if super quorum is not reached', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - - // Vote with voter4 (15) - below super quorum (40) but above quorum (10) - await this.helper.connect(this.voter4).vote({ support: VoteType.For }); - await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Active); - - // Vote with voter5 (5) - still below super quorum (total 20 < 40) - await this.helper.connect(this.voter5).vote({ support: VoteType.For }); - await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Active); - - // Wait for deadline - await this.helper.waitForDeadline(1n); - - // Should succeed since deadline passed and we have enough support (20 > 10 quorum) - await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Succeeded); - }); - - it('proposal remains active if super quorum is reached but vote fails', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - - // Vote against with voter2 and voter3 (50) - await this.helper.connect(this.voter2).vote({ support: VoteType.Against }); - await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); - - // Vote for with voter1 (40) (reaching super quorum) - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - - // should be active since super quorum is reached but vote fails - await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Active); - - // wait for deadline - await this.helper.waitForDeadline(1n); - - // should be defeated since against votes are higher - await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Defeated); - }); - - it('proposal is queued if super quorum is reached and eta is set', async function () { - await this.helper.connect(this.proposer).propose(); - - await this.helper.waitForSnapshot(); - - // Vote with voter1 (40) - reaching super quorum - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - - await this.helper.queue(); - - // Queueing should set eta - await expect(this.mock.proposalEta(this.proposal.id)).to.eventually.not.equal(0); - - // Should be queued since we reached super quorum and eta is set - await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Queued); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorumGreaterThanQuorum.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorumGreaterThanQuorum.t.sol deleted file mode 100644 index eb0409c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorSuperQuorumGreaterThanQuorum.t.sol +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; -import {GovernorVotesSuperQuorumFractionMock} from "../../../contracts/mocks/governance/GovernorVotesSuperQuorumFractionMock.sol"; -import {GovernorVotesQuorumFraction} from "../../../contracts/governance/extensions/GovernorVotesQuorumFraction.sol"; -import {GovernorVotesSuperQuorumFraction} from "../../../contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol"; -import {GovernorSettings} from "../../../contracts/governance/extensions/GovernorSettings.sol"; -import {GovernorVotes} from "../../../contracts/governance/extensions/GovernorVotes.sol"; -import {Governor} from "../../../contracts/governance/Governor.sol"; -import {IVotes} from "../../../contracts/governance/utils/IVotes.sol"; -import {ERC20VotesExtendedTimestampMock} from "../../../contracts/mocks/token/ERC20VotesAdditionalCheckpointsMock.sol"; -import {EIP712} from "../../../contracts/utils/cryptography/EIP712.sol"; -import {ERC20} from "../../../contracts/token/ERC20/ERC20.sol"; - -contract TokenMock is ERC20VotesExtendedTimestampMock { - constructor() ERC20("Mock Token", "MTK") EIP712("Mock Token", "1") {} -} - -/** - * Main responsibility: expose the functions that are relevant to the simulation - */ -contract GovernorHandler is GovernorVotesSuperQuorumFractionMock { - constructor( - string memory name_, - uint48 votingDelay_, - uint32 votingPeriod_, - uint256 proposalThreshold_, - IVotes token_, - uint256 quorumNumerator_, - uint256 superQuorumNumerator_ - ) - Governor(name_) - GovernorSettings(votingDelay_, votingPeriod_, proposalThreshold_) - GovernorVotes(token_) - GovernorVotesQuorumFraction(quorumNumerator_) - GovernorVotesSuperQuorumFraction(superQuorumNumerator_) - {} - - // solhint-disable-next-line func-name-mixedcase - function $_updateSuperQuorumNumerator(uint256 newSuperQuorumNumerator) public { - _updateSuperQuorumNumerator(newSuperQuorumNumerator); - } - - // solhint-disable-next-line func-name-mixedcase - function $_updateQuorumNumerator(uint256 newQuorumNumerator) public { - _updateQuorumNumerator(newQuorumNumerator); - } -} - -contract GovernorSuperQuorumGreaterThanQuorum is Test { - GovernorHandler private _governorHandler; - - function setUp() external { - _governorHandler = new GovernorHandler( - "GovernorName", - 0, // votingDelay - 1e4, // votingPeriod - 0, // proposalThreshold - new TokenMock(), // token - 10, // quorumNumerator - 50 // superQuorumNumerator - ); - - // limit the fuzzer scope - bytes4[] memory selectors = new bytes4[](2); - selectors[0] = GovernorHandler.$_updateSuperQuorumNumerator.selector; - selectors[1] = GovernorHandler.$_updateQuorumNumerator.selector; - - targetContract(address(_governorHandler)); - targetSelector(FuzzSelector(address(_governorHandler), selectors)); - } - - // solhint-disable-next-line func-name-mixedcase - function invariant_superQuorumGreaterThanQuorum() external view { - assertGe(_governorHandler.superQuorumNumerator(), _governorHandler.quorumNumerator()); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockAccess.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockAccess.test.js deleted file mode 100644 index 5eea647..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockAccess.test.js +++ /dev/null @@ -1,864 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); - -const { GovernorHelper } = require('../../helpers/governance'); -const { hashOperation } = require('../../helpers/access-manager'); -const { max } = require('../../helpers/math'); -const { selector } = require('../../helpers/methods'); -const { ProposalState, VoteType } = require('../../helpers/enums'); -const time = require('../../helpers/time'); - -function prepareOperation({ sender, target, value = 0n, data = '0x' }) { - return { - id: hashOperation(sender, target, data), - operation: { target, value, data }, - selector: data.slice(0, 10).padEnd(10, '0'), - }; -} - -const TOKENS = [ - { Token: '$ERC20Votes', mode: 'blocknumber' }, - { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, -]; - -const name = 'OZ-Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const votingDelay = 4n; -const votingPeriod = 16n; -const value = ethers.parseEther('1'); - -describe('GovernorTimelockAccess', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [admin, voter1, voter2, voter3, voter4, other] = await ethers.getSigners(); - - const manager = await ethers.deployContract('$AccessManager', [admin]); - const receiver = await ethers.deployContract('$AccessManagedTarget', [manager]); - - const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); - const mock = await ethers.deployContract('$GovernorTimelockAccessMock', [ - name, - votingDelay, - votingPeriod, - 0n, - manager, - 0n, - token, - 0n, - ]); - - await admin.sendTransaction({ to: mock, value }); - await token.$_mint(admin, tokenSupply); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(admin).delegate({ token, to: voter1, value: ethers.parseEther('10') }); - await helper.connect(admin).delegate({ token, to: voter2, value: ethers.parseEther('7') }); - await helper.connect(admin).delegate({ token, to: voter3, value: ethers.parseEther('5') }); - await helper.connect(admin).delegate({ token, to: voter4, value: ethers.parseEther('2') }); - - return { admin, voter1, voter2, voter3, voter4, other, manager, receiver, token, mock, helper }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - - // restricted proposal - this.restricted = prepareOperation({ - sender: this.mock.target, - target: this.receiver.target, - data: this.receiver.interface.encodeFunctionData('fnRestricted'), - }); - - this.unrestricted = prepareOperation({ - sender: this.mock.target, - target: this.receiver.target, - data: this.receiver.interface.encodeFunctionData('fnUnrestricted'), - }); - - this.fallback = prepareOperation({ - sender: this.mock.target, - target: this.receiver.target, - data: '0x1234', - }); - }); - - it('accepts ether transfers', async function () { - await this.admin.sendTransaction({ to: this.mock, value: 1n }); - }); - - it('post deployment check', async function () { - expect(await this.mock.name()).to.equal(name); - expect(await this.mock.token()).to.equal(this.token); - expect(await this.mock.votingDelay()).to.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.equal(votingPeriod); - expect(await this.mock.quorum(0n)).to.equal(0n); - - expect(await this.mock.accessManager()).to.equal(this.manager); - }); - - it('sets base delay (seconds)', async function () { - const baseDelay = time.duration.hours(10n); - - // Only through governance - await expect(this.mock.connect(this.voter1).setBaseDelaySeconds(baseDelay)) - .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') - .withArgs(this.voter1); - - this.proposal = await this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('setBaseDelaySeconds', [baseDelay]), - }, - ], - 'descr', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.execute()).to.emit(this.mock, 'BaseDelaySet').withArgs(0n, baseDelay); - - expect(await this.mock.baseDelaySeconds()).to.equal(baseDelay); - }); - - it('sets access manager ignored', async function () { - const selectors = ['0x12345678', '0x87654321', '0xabcdef01']; - - // Only through governance - await expect(this.mock.connect(this.voter1).setAccessManagerIgnored(this.other, selectors, true)) - .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') - .withArgs(this.voter1); - - // Ignore - await this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('setAccessManagerIgnored', [ - this.other.address, - selectors, - true, - ]), - }, - ], - 'descr', - ); - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - const ignoreReceipt = this.helper.execute(); - for (const selector of selectors) { - await expect(ignoreReceipt) - .to.emit(this.mock, 'AccessManagerIgnoredSet') - .withArgs(this.other, selector, true); - expect(await this.mock.isAccessManagerIgnored(this.other, selector)).to.be.true; - } - - // Unignore - await this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('setAccessManagerIgnored', [ - this.other.address, - selectors, - false, - ]), - }, - ], - 'descr', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - const unignoreReceipt = this.helper.execute(); - for (const selector of selectors) { - await expect(unignoreReceipt) - .to.emit(this.mock, 'AccessManagerIgnoredSet') - .withArgs(this.other, selector, false); - expect(await this.mock.isAccessManagerIgnored(this.other, selector)).to.be.false; - } - }); - - it('sets access manager ignored when target is the governor', async function () { - const selectors = ['0x12345678', '0x87654321', '0xabcdef01']; - - await this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('setAccessManagerIgnored', [ - this.mock.target, - selectors, - true, - ]), - }, - ], - 'descr', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - const tx = this.helper.execute(); - for (const selector of selectors) { - await expect(tx).to.emit(this.mock, 'AccessManagerIgnoredSet').withArgs(this.mock, selector, true); - expect(await this.mock.isAccessManagerIgnored(this.mock, selector)).to.be.true; - } - }); - - it('does not need to queue proposals with no delay', async function () { - const roleId = 1n; - const executionDelay = 0n; - const baseDelay = 0n; - - // Set execution delay - await this.manager.connect(this.admin).setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); - await this.manager.connect(this.admin).grantRole(roleId, this.mock, executionDelay); - - // Set base delay - await this.mock.$_setBaseDelaySeconds(baseDelay); - - await this.helper.setProposal([this.restricted.operation], 'descr'); - await this.helper.propose(); - expect(await this.mock.proposalNeedsQueuing(this.helper.currentProposal.id)).to.be.false; - }); - - it('needs to queue proposals with any delay', async function () { - const roleId = 1n; - const delays = [ - [time.duration.hours(1n), time.duration.hours(2n)], - [time.duration.hours(2n), time.duration.hours(1n)], - ]; - - for (const [executionDelay, baseDelay] of delays) { - // Set execution delay - await this.manager - .connect(this.admin) - .setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); - await this.manager.connect(this.admin).grantRole(roleId, this.mock, executionDelay); - - // Set base delay - await this.mock.$_setBaseDelaySeconds(baseDelay); - - await this.helper.setProposal( - [this.restricted.operation], - `executionDelay=${executionDelay.toString()}}baseDelay=${baseDelay.toString()}}`, - ); - await this.helper.propose(); - expect(await this.mock.proposalNeedsQueuing(this.helper.currentProposal.id)).to.be.true; - } - }); - - describe('execution plan', function () { - it('returns plan for delayed operations', async function () { - const roleId = 1n; - const delays = [ - [time.duration.hours(1n), time.duration.hours(2n)], - [time.duration.hours(2n), time.duration.hours(1n)], - ]; - - for (const [executionDelay, baseDelay] of delays) { - // Set execution delay - await this.manager - .connect(this.admin) - .setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); - await this.manager.connect(this.admin).grantRole(roleId, this.mock, executionDelay); - - // Set base delay - await this.mock.$_setBaseDelaySeconds(baseDelay); - - this.proposal = await this.helper.setProposal( - [this.restricted.operation], - `executionDelay=${executionDelay.toString()}}baseDelay=${baseDelay.toString()}}`, - ); - await this.helper.propose(); - - expect(await this.mock.proposalExecutionPlan(this.proposal.id)).to.deep.equal([ - max(baseDelay, executionDelay), - [true], - [true], - ]); - } - }); - - it('returns plan for not delayed operations', async function () { - const roleId = 1n; - const executionDelay = 0n; - const baseDelay = 0n; - - // Set execution delay - await this.manager - .connect(this.admin) - .setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); - await this.manager.connect(this.admin).grantRole(roleId, this.mock, executionDelay); - - // Set base delay - await this.mock.$_setBaseDelaySeconds(baseDelay); - - this.proposal = await this.helper.setProposal([this.restricted.operation], `descr`); - await this.helper.propose(); - - expect(await this.mock.proposalExecutionPlan(this.proposal.id)).to.deep.equal([0n, [true], [false]]); - }); - - it('returns plan for an operation ignoring the manager', async function () { - await this.mock.$_setAccessManagerIgnored(this.receiver, this.restricted.selector, true); - - const roleId = 1n; - const delays = [ - [time.duration.hours(1n), time.duration.hours(2n)], - [time.duration.hours(2n), time.duration.hours(1n)], - ]; - - for (const [executionDelay, baseDelay] of delays) { - // Set execution delay - await this.manager - .connect(this.admin) - .setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); - await this.manager.connect(this.admin).grantRole(roleId, this.mock, executionDelay); - - // Set base delay - await this.mock.$_setBaseDelaySeconds(baseDelay); - - this.proposal = await this.helper.setProposal( - [this.restricted.operation], - `executionDelay=${executionDelay.toString()}}baseDelay=${baseDelay.toString()}}`, - ); - await this.helper.propose(); - - expect(await this.mock.proposalExecutionPlan(this.proposal.id)).to.deep.equal([ - baseDelay, - [false], - [false], - ]); - } - }); - }); - - 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(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - if (await this.mock.proposalNeedsQueuing(this.proposal.id)) { - expect(await this.helper.queue()) - .to.emit(this.mock, 'ProposalQueued') - .withArgs(this.proposal.id, anyValue); - } - if (delay > 0) { - await this.helper.waitForEta(); - } - await expect(this.helper.execute()) - .to.emit(this.mock, 'ProposalExecuted') - .withArgs(this.proposal.id) - .to.emit(this.receiver, 'CalledUnrestricted'); - }); - } - }); - - it('reverts when an operation is executed before eta', async function () { - const delay = time.duration.hours(2n); - await this.mock.$_setBaseDelaySeconds(delay); - - this.proposal = await this.helper.setProposal([this.unrestricted.operation], 'descr'); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnmetDelay') - .withArgs(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(2n); - const roleId = 1n; - - await this.manager.connect(this.admin).setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); - await this.manager.connect(this.admin).grantRole(roleId, this.mock, delay); - - // 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(); - await original.waitForSnapshot(); - await original.connect(this.voter1).vote({ support: VoteType.For }); - await original.waitForDeadline(); - await original.queue(); - await original.waitForEta(); - - // Suddenly cancel one of the proposed operations in the manager - await this.manager - .connect(this.admin) - .cancel(this.mock, this.restricted.operation.target, this.restricted.operation.data); - - // 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.connect(this.voter1).vote({ support: VoteType.For }); - await rescheduled.waitForDeadline(); - await rescheduled.queue(); // This will schedule it again in the manager - await rescheduled.waitForEta(); - - // Attempt to execute - await expect(original.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorMismatchedNonce') - .withArgs(original.currentProposal.id, 1, 2); - }); - - it('single operation with access manager delay', async function () { - const delay = 1000n; - const roleId = 1n; - - await this.manager.connect(this.admin).setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); - await this.manager.connect(this.admin).grantRole(roleId, this.mock, delay); - - this.proposal = await this.helper.setProposal([this.restricted.operation], 'descr'); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - const txQueue = await this.helper.queue(); - await this.helper.waitForEta(); - const txExecute = await this.helper.execute(); - - await expect(txQueue) - .to.emit(this.mock, 'ProposalQueued') - .withArgs(this.proposal.id, anyValue) - .to.emit(this.manager, 'OperationScheduled') - .withArgs( - this.restricted.id, - 1n, - (await time.clockFromReceipt.timestamp(txQueue)) + delay, - this.mock.target, - this.restricted.operation.target, - this.restricted.operation.data, - ); - - await expect(txExecute) - .to.emit(this.mock, 'ProposalExecuted') - .withArgs(this.proposal.id) - .to.emit(this.manager, 'OperationExecuted') - .withArgs(this.restricted.id, 1n) - .to.emit(this.receiver, 'CalledRestricted'); - }); - - it('bundle of varied operations', async function () { - const managerDelay = 1000n; - const roleId = 1n; - const baseDelay = managerDelay * 2n; - - await this.mock.$_setBaseDelaySeconds(baseDelay); - - await this.manager.connect(this.admin).setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); - await this.manager.connect(this.admin).grantRole(roleId, this.mock, managerDelay); - - this.proposal = await this.helper.setProposal( - [this.restricted.operation, this.unrestricted.operation, this.fallback.operation], - 'descr', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - const txQueue = await this.helper.queue(); - await this.helper.waitForEta(); - const txExecute = await this.helper.execute(); - - await expect(txQueue) - .to.emit(this.mock, 'ProposalQueued') - .withArgs(this.proposal.id, anyValue) - .to.emit(this.manager, 'OperationScheduled') - .withArgs( - this.restricted.id, - 1n, - (await time.clockFromReceipt.timestamp(txQueue)) + baseDelay, - this.mock.target, - this.restricted.operation.target, - this.restricted.operation.data, - ); - - await expect(txExecute) - .to.emit(this.mock, 'ProposalExecuted') - .withArgs(this.proposal.id) - .to.emit(this.manager, 'OperationExecuted') - .withArgs(this.restricted.id, 1n) - .to.emit(this.receiver, 'CalledRestricted') - .to.emit(this.receiver, 'CalledUnrestricted') - .to.emit(this.receiver, 'CalledFallback'); - }); - - describe('cancel', function () { - const delay = 1000n; - const roleId = 1n; - - beforeEach(async function () { - await this.manager - .connect(this.admin) - .setTargetFunctionRole(this.receiver, [this.restricted.selector], roleId); - await this.manager.connect(this.admin).grantRole(roleId, this.mock, delay); - }); - - it('cancels restricted with delay after queue (internal)', async function () { - this.proposal = await this.helper.setProposal([this.restricted.operation], 'descr'); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - - await expect(this.helper.cancel('internal')) - .to.emit(this.mock, 'ProposalCanceled') - .withArgs(this.proposal.id) - .to.emit(this.manager, 'OperationCanceled') - .withArgs(this.restricted.id, 1n); - - await this.helper.waitForEta(); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Canceled, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, 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(); - await original.waitForSnapshot(); - await original.connect(this.voter1).vote({ support: VoteType.For }); - await original.waitForDeadline(); - await original.queue(); - - // Cancel the operation in the manager - await this.manager - .connect(this.admin) - .cancel(this.mock, this.restricted.operation.target, this.restricted.operation.data); - - // 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.connect(this.voter1).vote({ support: VoteType.For }); - await rescheduled.waitForDeadline(); - await rescheduled.queue(); // This will schedule it again in the manager - - // Cancel - const eta = await this.mock.proposalEta(rescheduled.currentProposal.id); - - await expect(original.cancel('internal')) - .to.emit(this.mock, 'ProposalCanceled') - .withArgs(original.currentProposal.id); - - await time.clock.timestamp().then(clock => time.increaseTo.timestamp(max(clock + 1n, eta))); - - await expect(original.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - original.currentProposal.id, - ProposalState.Canceled, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - - it('cancels unrestricted with queueing (internal)', async function () { - this.proposal = await this.helper.setProposal([this.unrestricted.operation], 'descr'); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - - const eta = await this.mock.proposalEta(this.proposal.id); - - await expect(this.helper.cancel('internal')) - .to.emit(this.mock, 'ProposalCanceled') - .withArgs(this.proposal.id); - - await time.clock.timestamp().then(clock => time.increaseTo.timestamp(max(clock + 1n, eta))); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Canceled, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - - it('cancels unrestricted without queueing (internal)', async function () { - this.proposal = await this.helper.setProposal([this.unrestricted.operation], 'descr'); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.cancel('internal')) - .to.emit(this.mock, 'ProposalCanceled') - .withArgs(this.proposal.id); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Canceled, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - - it('cancels calls already canceled by guardian', async function () { - const operationA = { target: this.receiver.target, data: this.restricted.selector + '00' }; - const operationB = { target: this.receiver.target, data: this.restricted.selector + '01' }; - const operationC = { target: this.receiver.target, data: this.restricted.selector + '02' }; - const operationAId = hashOperation(this.mock.target, operationA.target, operationA.data); - const operationBId = hashOperation(this.mock.target, 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.connect(this.voter1).vote({ support: VoteType.For }); - await p.waitForDeadline(); - } - - // Can queue the first proposal - await proposal1.queue(); - - // Cannot queue the second proposal: operation A already scheduled with delay - await expect(proposal2.queue()) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerAlreadyScheduled') - .withArgs(operationAId); - - // Admin cancels operation B on the manager - await this.manager.connect(this.admin).cancel(this.mock, operationB.target, operationB.data); - - // Still cannot queue the second proposal: operation A already scheduled with delay - await expect(proposal2.queue()) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerAlreadyScheduled') - .withArgs(operationAId); - - await proposal1.waitForEta(); - - // Cannot execute first proposal: operation B has been canceled - await expect(proposal1.execute()) - .to.be.revertedWithCustomError(this.manager, 'AccessManagerNotScheduled') - .withArgs(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, this.restricted.selector)).to.be.false; - expect(await this.mock.isAccessManagerIgnored(this.mock, '0x12341234')).to.be.true; - }); - - it('internal setter', async function () { - await expect(this.mock.$_setAccessManagerIgnored(this.receiver, this.restricted.selector, true)) - .to.emit(this.mock, 'AccessManagerIgnoredSet') - .withArgs(this.receiver, this.restricted.selector, true); - - expect(await this.mock.isAccessManagerIgnored(this.receiver, this.restricted.selector)).to.be.true; - - await expect(this.mock.$_setAccessManagerIgnored(this.mock, '0x12341234', false)) - .to.emit(this.mock, 'AccessManagerIgnoredSet') - .withArgs(this.mock, '0x12341234', false); - - expect(await this.mock.isAccessManagerIgnored(this.mock, '0x12341234')).to.be.false; - }); - - it('external setter', async function () { - const setAccessManagerIgnored = (...args) => - this.mock.interface.encodeFunctionData('setAccessManagerIgnored', args); - - await this.helper.setProposal( - [ - { - target: this.mock.target, - data: setAccessManagerIgnored( - this.receiver.target, - [this.restricted.selector, this.unrestricted.selector], - true, - ), - }, - { - target: this.mock.target, - data: setAccessManagerIgnored(this.mock.target, ['0x12341234', '0x67896789'], false), - }, - ], - 'descr', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.execute()).to.emit(this.mock, 'AccessManagerIgnoredSet'); - - expect(await this.mock.isAccessManagerIgnored(this.receiver, this.restricted.selector)).to.be.true; - expect(await this.mock.isAccessManagerIgnored(this.receiver, this.unrestricted.selector)).to.be.true; - expect(await this.mock.isAccessManagerIgnored(this.mock, '0x12341234')).to.be.false; - expect(await this.mock.isAccessManagerIgnored(this.mock, '0x67896789')).to.be.false; - }); - - it('locked function', async function () { - const setAccessManagerIgnored = selector('setAccessManagerIgnored(address,bytes4[],bool)'); - - await expect( - this.mock.$_setAccessManagerIgnored(this.mock, setAccessManagerIgnored, true), - ).to.be.revertedWithCustomError(this.mock, 'GovernorLockedIgnore'); - - await this.mock.$_setAccessManagerIgnored(this.receiver, setAccessManagerIgnored, true); - }); - - it('ignores access manager', async function () { - const amount = 100n; - const target = this.token.target; - const data = this.token.interface.encodeFunctionData('transfer', [this.voter4.address, amount]); - const selector = data.slice(0, 10); - await this.token.$_mint(this.mock, amount); - - const roleId = 1n; - await this.manager.connect(this.admin).setTargetFunctionRole(target, [selector], roleId); - await this.manager.connect(this.admin).grantRole(roleId, this.mock, 0); - - await this.helper.setProposal([{ target, data }], 'descr #1'); - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') - .withArgs(this.manager, 0n, amount); - - await this.mock.$_setAccessManagerIgnored(target, selector, true); - - await this.helper.setProposal([{ target, data }], 'descr #2'); - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.execute()).to.emit(this.token, 'Transfer').withArgs(this.mock, this.voter4, amount); - }); - }); - - describe('operating on an Ownable contract', function () { - const method = selector('$_checkOwner()'); - - beforeEach(async function () { - this.ownable = await ethers.deployContract('$Ownable', [this.manager]); - this.operation = { - target: this.ownable.target, - data: this.ownable.interface.encodeFunctionData('$_checkOwner'), - }; - }); - - it('succeeds with delay', async function () { - const roleId = 1n; - const executionDelay = time.duration.hours(2n); - const baseDelay = time.duration.hours(1n); - - // Set execution delay - await this.manager.connect(this.admin).setTargetFunctionRole(this.ownable, [method], roleId); - await this.manager.connect(this.admin).grantRole(roleId, this.mock, executionDelay); - - // Set base delay - await this.mock.$_setBaseDelaySeconds(baseDelay); - - await this.helper.setProposal([this.operation], `descr`); - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - await this.helper.execute(); // Don't revert - }); - - it('succeeds without delay', async function () { - const roleId = 1n; - const executionDelay = 0n; - const baseDelay = 0n; - - // Set execution delay - await this.manager.connect(this.admin).setTargetFunctionRole(this.ownable, [method], roleId); - await this.manager.connect(this.admin).grantRole(roleId, this.mock, executionDelay); - - // Set base delay - await this.mock.$_setBaseDelaySeconds(baseDelay); - - await this.helper.setProposal([this.operation], `descr`); - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.execute(); // Don't revert - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js deleted file mode 100644 index cd82481..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js +++ /dev/null @@ -1,448 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); - -const { GovernorHelper } = require('../../helpers/governance'); -const { ProposalState, VoteType } = require('../../helpers/enums'); -const time = require('../../helpers/time'); - -const TOKENS = [ - { Token: '$ERC20Votes', mode: 'blocknumber' }, - { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, -]; - -const name = 'OZ-Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const votingDelay = 4n; -const votingPeriod = 16n; -const value = ethers.parseEther('1'); -const defaultDelay = time.duration.days(2n); - -describe('GovernorTimelockCompound', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [deployer, owner, voter1, voter2, voter3, voter4, other] = await ethers.getSigners(); - const receiver = await ethers.deployContract('CallReceiverMock'); - - const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); - const predictGovernor = await deployer - .getNonce() - .then(nonce => ethers.getCreateAddress({ from: deployer.address, nonce: nonce + 1 })); - const timelock = await ethers.deployContract('CompTimelock', [predictGovernor, defaultDelay]); - const mock = await ethers.deployContract('$GovernorTimelockCompoundMock', [ - name, - votingDelay, - votingPeriod, - 0n, - timelock, - token, - 0n, - ]); - - await owner.sendTransaction({ to: timelock, value }); - await token.$_mint(owner, tokenSupply); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); - await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); - await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); - await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); - - return { deployer, owner, voter1, voter2, voter3, voter4, other, receiver, token, mock, timelock, helper }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - value, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - }, - ], - '', - ); - }); - - it("doesn't accept ether transfers", async function () { - await expect(this.owner.sendTransaction({ to: this.mock, value: 1n })).to.be.revertedWithCustomError( - this.mock, - 'GovernorDisabledDeposit', - ); - }); - - it('post deployment check', async function () { - expect(await this.mock.name()).to.equal(name); - expect(await this.mock.token()).to.equal(this.token); - expect(await this.mock.votingDelay()).to.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.equal(votingPeriod); - expect(await this.mock.quorum(0n)).to.equal(0n); - - expect(await this.mock.timelock()).to.equal(this.timelock); - expect(await this.timelock.admin()).to.equal(this.mock); - }); - - it('nominal', async function () { - expect(await this.mock.proposalEta(this.proposal.id)).to.equal(0n); - expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.true; - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.connect(this.voter2).vote({ support: VoteType.For }); - await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); - await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }); - await this.helper.waitForDeadline(); - const txQueue = await this.helper.queue(); - - const eta = (await time.clockFromReceipt.timestamp(txQueue)) + defaultDelay; - expect(await this.mock.proposalEta(this.proposal.id)).to.equal(eta); - expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.true; - - await this.helper.waitForEta(); - const txExecute = await this.helper.execute(); - - await expect(txQueue) - .to.emit(this.mock, 'ProposalQueued') - .withArgs(this.proposal.id, eta) - .to.emit(this.timelock, 'QueueTransaction') - .withArgs(...Array(5).fill(anyValue), eta); - - await expect(txExecute) - .to.emit(this.mock, 'ProposalExecuted') - .withArgs(this.proposal.id) - .to.emit(this.timelock, 'ExecuteTransaction') - .withArgs(...Array(5).fill(anyValue), eta) - .to.emit(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.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await expect(this.helper.queue()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Queued, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded]), - ); - }); - - it('if proposal contains duplicate calls', async function () { - const action = { - target: this.token.target, - data: this.token.interface.encodeFunctionData('approve', [this.receiver.target, ethers.MaxUint256]), - }; - const { id } = this.helper.setProposal([action, action], ''); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await expect(this.helper.queue()) - .to.be.revertedWithCustomError(this.mock, 'GovernorAlreadyQueuedProposal') - .withArgs(id); - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorNotQueuedProposal') - .withArgs(id); - }); - }); - - describe('on execute', function () { - it('if not queued', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(1n); - - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Succeeded); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorNotQueuedProposal') - .withArgs(this.proposal.id); - }); - - it('if too early', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Queued); - - await expect(this.helper.execute()).to.be.rejectedWith( - "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.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(time.duration.days(30)); - - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Expired); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Expired, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - - it('if already executed', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - await this.helper.execute(); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Executed, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - }); - - describe('on safe receive', function () { - describe('ERC721', function () { - const tokenId = 1n; - - beforeEach(async function () { - this.token = await ethers.deployContract('$ERC721', ['Non Fungible Token', 'NFT']); - await this.token.$_mint(this.owner, tokenId); - }); - - it("can't receive an ERC721 safeTransfer", async function () { - await expect( - this.token.connect(this.owner).safeTransferFrom(this.owner, this.mock, tokenId), - ).to.be.revertedWithCustomError(this.mock, 'GovernorDisabledDeposit'); - }); - }); - - describe('ERC1155', function () { - const tokenIds = { - 1: 1000n, - 2: 2000n, - 3: 3000n, - }; - - beforeEach(async function () { - this.token = await ethers.deployContract('$ERC1155', ['https://token-cdn-domain/{id}.json']); - await this.token.$_mintBatch(this.owner, Object.keys(tokenIds), Object.values(tokenIds), '0x'); - }); - - it("can't receive ERC1155 safeTransfer", async function () { - await expect( - this.token.connect(this.owner).safeTransferFrom( - this.owner, - this.mock, - ...Object.entries(tokenIds)[0], // id + amount - '0x', - ), - ).to.be.revertedWithCustomError(this.mock, 'GovernorDisabledDeposit'); - }); - - it("can't receive ERC1155 safeBatchTransfer", async function () { - await expect( - this.token - .connect(this.owner) - .safeBatchTransferFrom(this.owner, this.mock, Object.keys(tokenIds), Object.values(tokenIds), '0x'), - ).to.be.revertedWithCustomError(this.mock, 'GovernorDisabledDeposit'); - }); - }); - }); - }); - - describe('cancel', function () { - it('cancel before queue prevents scheduling', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.cancel('internal')) - .to.emit(this.mock, 'ProposalCanceled') - .withArgs(this.proposal.id); - - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled); - - await expect(this.helper.queue()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Canceled, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded]), - ); - }); - - it('cancel after queue prevents executing', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - - await expect(this.helper.cancel('internal')) - .to.emit(this.mock, 'ProposalCanceled') - .withArgs(this.proposal.id); - - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Canceled, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - }); - - describe('onlyGovernance', function () { - describe('relay', function () { - beforeEach(async function () { - await this.token.$_mint(this.mock, 1); - }); - - it('is protected', async function () { - await expect( - this.mock - .connect(this.owner) - .relay(this.token, 0, this.token.interface.encodeFunctionData('transfer', [this.other.address, 1n])), - ) - .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') - .withArgs(this.owner); - }); - - it('can be executed through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('relay', [ - this.token.target, - 0n, - this.token.interface.encodeFunctionData('transfer', [this.other.address, 1n]), - ]), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - - const txExecute = this.helper.execute(); - - await expect(txExecute).to.changeTokenBalances(this.token, [this.mock, this.other], [-1n, 1n]); - - await expect(txExecute).to.emit(this.token, 'Transfer').withArgs(this.mock, this.other, 1n); - }); - }); - - describe('updateTimelock', function () { - beforeEach(async function () { - this.newTimelock = await ethers.deployContract('CompTimelock', [this.mock, time.duration.days(7n)]); - }); - - it('is protected', async function () { - await expect(this.mock.connect(this.owner).updateTimelock(this.newTimelock)) - .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') - .withArgs(this.owner); - }); - - it('can be executed through governance to', async function () { - this.helper.setProposal( - [ - { - target: this.timelock.target, - data: this.timelock.interface.encodeFunctionData('setPendingAdmin', [this.owner.address]), - }, - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('updateTimelock', [this.newTimelock.target]), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - - await expect(this.helper.execute()) - .to.emit(this.mock, 'TimelockChange') - .withArgs(this.timelock, this.newTimelock); - - expect(await this.mock.timelock()).to.equal(this.newTimelock); - }); - }); - - it('can transfer timelock to new governor', async function () { - const newGovernor = await ethers.deployContract('$GovernorTimelockCompoundMock', [ - name, - 8n, - 32n, - 0n, - this.timelock, - this.token, - 0n, - ]); - - this.helper.setProposal( - [ - { - target: this.timelock.target, - data: this.timelock.interface.encodeFunctionData('setPendingAdmin', [newGovernor.target]), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - - await expect(this.helper.execute()).to.emit(this.timelock, 'NewPendingAdmin').withArgs(newGovernor); - - await newGovernor.__acceptAdmin(); - expect(await this.timelock.admin()).to.equal(newGovernor); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js deleted file mode 100644 index 507c7e2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js +++ /dev/null @@ -1,504 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -const { GovernorHelper, timelockSalt } = require('../../helpers/governance'); -const { OperationState, ProposalState, VoteType } = require('../../helpers/enums'); -const time = require('../../helpers/time'); - -const TOKENS = [ - { Token: '$ERC20Votes', mode: 'blocknumber' }, - { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, -]; - -const DEFAULT_ADMIN_ROLE = ethers.ZeroHash; -const PROPOSER_ROLE = ethers.id('PROPOSER_ROLE'); -const EXECUTOR_ROLE = ethers.id('EXECUTOR_ROLE'); -const CANCELLER_ROLE = ethers.id('CANCELLER_ROLE'); - -const name = 'OZ-Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const votingDelay = 4n; -const votingPeriod = 16n; -const value = ethers.parseEther('1'); -const delay = time.duration.hours(1n); - -describe('GovernorTimelockControl', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [deployer, owner, voter1, voter2, voter3, voter4, other] = await ethers.getSigners(); - const receiver = await ethers.deployContract('CallReceiverMock'); - - const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); - const timelock = await ethers.deployContract('TimelockController', [delay, [], [], deployer]); - const mock = await ethers.deployContract('$GovernorTimelockControlMock', [ - name, - votingDelay, - votingPeriod, - 0n, - timelock, - token, - 0n, - ]); - - await owner.sendTransaction({ to: timelock, value }); - await token.$_mint(owner, tokenSupply); - await timelock.grantRole(PROPOSER_ROLE, mock); - await timelock.grantRole(PROPOSER_ROLE, owner); - await timelock.grantRole(CANCELLER_ROLE, mock); - await timelock.grantRole(CANCELLER_ROLE, owner); - await timelock.grantRole(EXECUTOR_ROLE, ethers.ZeroAddress); - await timelock.revokeRole(DEFAULT_ADMIN_ROLE, deployer); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); - await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); - await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); - await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); - - return { deployer, owner, voter1, voter2, voter3, voter4, other, receiver, token, mock, timelock, helper }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - value, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - }, - ], - '', - ); - - this.proposal.timelockid = await this.timelock.hashOperationBatch( - ...this.proposal.shortProposal.slice(0, 3), - ethers.ZeroHash, - timelockSalt(this.mock.target, this.proposal.shortProposal[3]), - ); - }); - - it("doesn't accept ether transfers", async function () { - await expect(this.owner.sendTransaction({ to: this.mock, value: 1n })).to.be.revertedWithCustomError( - this.mock, - 'GovernorDisabledDeposit', - ); - }); - - it('post deployment check', async function () { - expect(await this.mock.name()).to.equal(name); - expect(await this.mock.token()).to.equal(this.token); - expect(await this.mock.votingDelay()).to.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.equal(votingPeriod); - expect(await this.mock.quorum(0n)).to.equal(0n); - - expect(await this.mock.timelock()).to.equal(this.timelock); - }); - - it('nominal', async function () { - expect(await this.mock.proposalEta(this.proposal.id)).to.equal(0n); - expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.true; - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.connect(this.voter2).vote({ support: VoteType.For }); - await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); - await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }); - await this.helper.waitForDeadline(); - - expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.true; - const txQueue = await this.helper.queue(); - - const eta = (await time.clockFromReceipt.timestamp(txQueue)) + delay; - expect(await this.mock.proposalEta(this.proposal.id)).to.equal(eta); - await this.helper.waitForEta(); - - const txExecute = this.helper.execute(); - - await expect(txQueue) - .to.emit(this.mock, 'ProposalQueued') - .withArgs(this.proposal.id, anyValue) - .to.emit(this.timelock, 'CallScheduled') - .withArgs(this.proposal.timelockid, ...Array(6).fill(anyValue)) - .to.emit(this.timelock, 'CallSalt') - .withArgs(this.proposal.timelockid, anyValue); - - await expect(txExecute) - .to.emit(this.mock, 'ProposalExecuted') - .withArgs(this.proposal.id) - .to.emit(this.timelock, 'CallExecuted') - .withArgs(this.proposal.timelockid, ...Array(4).fill(anyValue)) - .to.emit(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.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await expect(this.helper.queue()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Queued, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded]), - ); - }); - }); - - describe('on execute', function () { - it('if not queued', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(1n); - - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Succeeded); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.timelock, 'TimelockUnexpectedOperationState') - .withArgs(this.proposal.timelockid, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); - }); - - it('if too early', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Queued); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.timelock, 'TimelockUnexpectedOperationState') - .withArgs(this.proposal.timelockid, GovernorHelper.proposalStatesToBitMap(OperationState.Ready)); - }); - - it('if already executed', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - await this.helper.execute(); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Executed, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - - it('if already executed by another proposer', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - - await this.timelock.executeBatch( - ...this.proposal.shortProposal.slice(0, 3), - ethers.ZeroHash, - timelockSalt(this.mock.target, this.proposal.shortProposal[3]), - ); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Executed, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - }); - }); - - describe('cancel', function () { - it('cancel before queue prevents scheduling', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.cancel('internal')) - .to.emit(this.mock, 'ProposalCanceled') - .withArgs(this.proposal.id); - - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled); - - await expect(this.helper.queue()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Canceled, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded]), - ); - }); - - it('cancel after queue prevents executing', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - - await expect(this.helper.cancel('internal')) - .to.emit(this.mock, 'ProposalCanceled') - .withArgs(this.proposal.id); - - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Canceled, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - - it('cancel on timelock is reflected on governor', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Queued); - - await expect(this.timelock.connect(this.owner).cancel(this.proposal.timelockid)) - .to.emit(this.timelock, 'Cancelled') - .withArgs(this.proposal.timelockid); - - expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled); - }); - }); - - describe('onlyGovernance', function () { - describe('relay', function () { - beforeEach(async function () { - await this.token.$_mint(this.mock, 1); - }); - - it('is protected', async function () { - await expect( - this.mock - .connect(this.owner) - .relay(this.token, 0n, this.token.interface.encodeFunctionData('transfer', [this.other.address, 1n])), - ) - .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') - .withArgs(this.owner); - }); - - it('can be executed through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('relay', [ - this.token.target, - 0n, - this.token.interface.encodeFunctionData('transfer', [this.other.address, 1n]), - ]), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - - const txExecute = await this.helper.execute(); - - await expect(txExecute).to.changeTokenBalances(this.token, [this.mock, this.other], [-1n, 1n]); - - await expect(txExecute).to.emit(this.token, 'Transfer').withArgs(this.mock, this.other, 1n); - }); - - it('is payable and can transfer eth to EOA', async function () { - const t2g = 128n; // timelock to governor - const g2o = 100n; // governor to eoa (other) - - this.helper.setProposal( - [ - { - target: this.mock.target, - value: t2g, - data: this.mock.interface.encodeFunctionData('relay', [this.other.address, g2o, '0x']), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - - await expect(this.helper.execute()).to.changeEtherBalances( - [this.timelock, this.mock, this.other], - [-t2g, t2g - g2o, g2o], - ); - }); - - it('protected against other proposers', async function () { - const call = [ - this.mock, - 0n, - this.mock.interface.encodeFunctionData('relay', [ethers.ZeroAddress, 0n, '0x']), - ethers.ZeroHash, - ethers.ZeroHash, - ]; - - await this.timelock.connect(this.owner).schedule(...call, delay); - - await time.increaseBy.timestamp(delay); - - // Error bubbled up from Governor - await expect(this.timelock.connect(this.owner).execute(...call)).to.be.revertedWithPanic( - PANIC_CODES.POP_ON_EMPTY_ARRAY, - ); - }); - }); - - describe('updateTimelock', function () { - beforeEach(async function () { - this.newTimelock = await ethers.deployContract('TimelockController', [ - delay, - [this.mock], - [this.mock], - ethers.ZeroAddress, - ]); - }); - - it('is protected', async function () { - await expect(this.mock.connect(this.owner).updateTimelock(this.newTimelock)) - .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') - .withArgs(this.owner); - }); - - it('can be executed through governance to', async function () { - this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('updateTimelock', [this.newTimelock.target]), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - - await expect(this.helper.execute()) - .to.emit(this.mock, 'TimelockChange') - .withArgs(this.timelock, this.newTimelock); - - expect(await this.mock.timelock()).to.equal(this.newTimelock); - }); - }); - - describe('on safe receive', function () { - describe('ERC721', function () { - const tokenId = 1n; - - beforeEach(async function () { - this.token = await ethers.deployContract('$ERC721', ['Non Fungible Token', 'NFT']); - await this.token.$_mint(this.owner, tokenId); - }); - - it("can't receive an ERC721 safeTransfer", async function () { - await expect( - this.token.connect(this.owner).safeTransferFrom(this.owner, this.mock, tokenId), - ).to.be.revertedWithCustomError(this.mock, 'GovernorDisabledDeposit'); - }); - }); - - describe('ERC1155', function () { - const tokenIds = { - 1: 1000n, - 2: 2000n, - 3: 3000n, - }; - - beforeEach(async function () { - this.token = await ethers.deployContract('$ERC1155', ['https://token-cdn-domain/{id}.json']); - await this.token.$_mintBatch(this.owner, Object.keys(tokenIds), Object.values(tokenIds), '0x'); - }); - - it("can't receive ERC1155 safeTransfer", async function () { - await expect( - this.token.connect(this.owner).safeTransferFrom( - this.owner, - this.mock, - ...Object.entries(tokenIds)[0], // id + amount - '0x', - ), - ).to.be.revertedWithCustomError(this.mock, 'GovernorDisabledDeposit'); - }); - - it("can't receive ERC1155 safeBatchTransfer", async function () { - await expect( - this.token - .connect(this.owner) - .safeBatchTransferFrom(this.owner, this.mock, Object.keys(tokenIds), Object.values(tokenIds), '0x'), - ).to.be.revertedWithCustomError(this.mock, 'GovernorDisabledDeposit'); - }); - }); - }); - }); - - it('clear queue of pending governor calls', async function () { - this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('nonGovernanceFunction'), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js deleted file mode 100644 index 99afd39..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js +++ /dev/null @@ -1,165 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers'); - -const { GovernorHelper } = require('../../helpers/governance'); -const { ProposalState, VoteType } = require('../../helpers/enums'); -const time = require('../../helpers/time'); - -const TOKENS = [ - { Token: '$ERC20Votes', mode: 'blocknumber' }, - { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, -]; - -const name = 'OZ-Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const ratio = 8n; // percents -const newRatio = 6n; // percents -const votingDelay = 4n; -const votingPeriod = 16n; -const value = ethers.parseEther('1'); - -describe('GovernorVotesQuorumFraction', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [owner, voter1, voter2, voter3, voter4] = await ethers.getSigners(); - - const receiver = await ethers.deployContract('CallReceiverMock'); - - const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); - const mock = await ethers.deployContract('$GovernorMock', [name, votingDelay, votingPeriod, 0n, token, ratio]); - - await owner.sendTransaction({ to: mock, value }); - await token.$_mint(owner, tokenSupply); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); - await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); - await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); - await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); - - return { owner, voter1, voter2, voter3, voter4, receiver, token, mock, helper }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - value, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - }, - ], - '', - ); - }); - - it('deployment check', async function () { - expect(await this.mock.name()).to.equal(name); - expect(await this.mock.token()).to.equal(this.token); - expect(await this.mock.votingDelay()).to.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.equal(votingPeriod); - expect(await this.mock.quorum(0)).to.equal(0n); - expect(await this.mock.quorumNumerator()).to.equal(ratio); - expect(await this.mock.quorumDenominator()).to.equal(100n); - expect(await time.clock[mode]().then(clock => this.mock.quorum(clock - 1n))).to.equal( - (tokenSupply * ratio) / 100n, - ); - }); - - it('quorum reached', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - }); - - it('quorum not reached', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter2).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState') - .withArgs( - this.proposal.id, - ProposalState.Defeated, - GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]), - ); - }); - - describe('onlyGovernance updates', function () { - it('updateQuorumNumerator is protected', async function () { - await expect(this.mock.connect(this.owner).updateQuorumNumerator(newRatio)) - .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') - .withArgs(this.owner); - }); - - it('can updateQuorumNumerator through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('updateQuorumNumerator', [newRatio]), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.execute()).to.emit(this.mock, 'QuorumNumeratorUpdated').withArgs(ratio, newRatio); - - expect(await this.mock.quorumNumerator()).to.equal(newRatio); - expect(await this.mock.quorumDenominator()).to.equal(100n); - - // it takes one block for the new quorum to take effect - expect(await time.clock[mode]().then(blockNumber => this.mock.quorum(blockNumber - 1n))).to.equal( - (tokenSupply * ratio) / 100n, - ); - - await mine(); - - expect(await time.clock[mode]().then(blockNumber => this.mock.quorum(blockNumber - 1n))).to.equal( - (tokenSupply * newRatio) / 100n, - ); - }); - - it('cannot updateQuorumNumerator over the maximum', async function () { - const quorumNumerator = 101n; - this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('updateQuorumNumerator', [quorumNumerator]), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - const quorumDenominator = await this.mock.quorumDenominator(); - - await expect(this.helper.execute()) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidQuorumFraction') - .withArgs(quorumNumerator, quorumDenominator); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesSuperQuorumFraction.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesSuperQuorumFraction.test.js deleted file mode 100644 index 10a4448..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesSuperQuorumFraction.test.js +++ /dev/null @@ -1,160 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { GovernorHelper } = require('../../helpers/governance'); -const { ProposalState, VoteType } = require('../../helpers/enums'); -const time = require('../../helpers/time'); - -const TOKENS = [ - { Token: '$ERC20Votes', mode: 'blocknumber' }, - { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, -]; - -const name = 'OZ-Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const quorumRatio = 8n; // percents -const superQuorumRatio = 50n; // percents -const newSuperQuorumRatio = 15n; // percents -const votingDelay = 4n; -const votingPeriod = 16n; -const value = ethers.parseEther('1'); - -describe('GovernorVotesSuperQuorumFraction', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [owner, voter1, voter2, voter3, voter4] = await ethers.getSigners(); - const receiver = await ethers.deployContract('CallReceiverMock'); - - const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); - const mock = await ethers.deployContract('$GovernorVotesSuperQuorumFractionMock', [ - name, - votingDelay, - votingPeriod, - 0n, - token, - quorumRatio, - superQuorumRatio, - ]); - - await owner.sendTransaction({ to: mock, value }); - await token.$_mint(owner, tokenSupply); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('30') }); - await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('20') }); - await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('15') }); - await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('5') }); - - return { owner, voter1, voter2, voter3, voter4, receiver, token, mock, helper }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - value, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - }, - ], - '', - ); - }); - - it('deployment check', async function () { - await expect(this.mock.name()).to.eventually.equal(name); - await expect(this.mock.token()).to.eventually.equal(this.token); - await expect(this.mock.votingDelay()).to.eventually.equal(votingDelay); - await expect(this.mock.votingPeriod()).to.eventually.equal(votingPeriod); - await expect(this.mock.quorumNumerator()).to.eventually.equal(quorumRatio); - await expect(this.mock.superQuorumNumerator()).to.eventually.equal(superQuorumRatio); - await expect(this.mock.quorumDenominator()).to.eventually.equal(100n); - await expect(time.clock[mode]().then(clock => this.mock.superQuorum(clock - 1n))).to.eventually.equal( - (tokenSupply * superQuorumRatio) / 100n, - ); - }); - - it('proposal remains active until super quorum is reached', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - - // Vote with voter1 (30%) - above quorum (8%) but below super quorum (50%) - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - - // Check proposal is still active - await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Active); - - // Vote with voter2 (20%) - now matches super quorum - await this.helper.connect(this.voter2).vote({ support: VoteType.For }); - - // Proposal should no longer be active - await expect(this.mock.state(this.proposal.id)).to.eventually.equal(ProposalState.Succeeded); - }); - - describe('super quorum updates', function () { - it('updateSuperQuorumNumerator is protected', async function () { - await expect(this.mock.connect(this.owner).updateSuperQuorumNumerator(newSuperQuorumRatio)) - .to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor') - .withArgs(this.owner); - }); - - it('can update super quorum through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.target, - data: this.mock.interface.encodeFunctionData('updateSuperQuorumNumerator', [newSuperQuorumRatio]), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For }); - await this.helper.connect(this.voter2).vote({ support: VoteType.For }); - await this.helper.waitForDeadline(); - - await expect(this.helper.execute()) - .to.emit(this.mock, 'SuperQuorumNumeratorUpdated') - .withArgs(superQuorumRatio, newSuperQuorumRatio); - - await expect(this.mock.superQuorumNumerator()).to.eventually.equal(newSuperQuorumRatio); - }); - - it('cannot set super quorum below quorum', async function () { - const invalidSuperQuorum = quorumRatio - 1n; - - await expect(this.mock.$_updateSuperQuorumNumerator(invalidSuperQuorum)) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSuperQuorumTooSmall') - .withArgs(invalidSuperQuorum, quorumRatio); - }); - - it('cannot set super quorum above denominator', async function () { - const denominator = await this.mock.quorumDenominator(); - const invalidSuperQuorum = BigInt(denominator) + 1n; - - await expect(this.mock.$_updateSuperQuorumNumerator(invalidSuperQuorum)) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSuperQuorumFraction') - .withArgs(invalidSuperQuorum, denominator); - }); - - it('cannot set quorum above super quorum', async function () { - const invalidQuorum = superQuorumRatio + 1n; - - await expect(this.mock.$_updateQuorumNumerator(invalidQuorum)) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidQuorumTooLarge') - .withArgs(invalidQuorum, superQuorumRatio); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js deleted file mode 100644 index db19bc6..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js +++ /dev/null @@ -1,245 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { GovernorHelper } = require('../../helpers/governance'); -const { VoteType } = require('../../helpers/enums'); -const { getDomain, ExtendedBallot } = require('../../helpers/eip712'); - -const TOKENS = [ - { Token: '$ERC20Votes', mode: 'blocknumber' }, - { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, -]; - -const name = 'OZ-Governor'; -const version = '1'; -const tokenName = 'MockToken'; -const tokenSymbol = 'MTKN'; -const tokenSupply = ethers.parseEther('100'); -const votingDelay = 4n; -const votingPeriod = 16n; -const value = ethers.parseEther('1'); - -const params = { - decoded: [42n, 'These are my params'], - encoded: ethers.AbiCoder.defaultAbiCoder().encode(['uint256', 'string'], [42n, 'These are my params']), -}; - -describe('GovernorWithParams', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - const [owner, proposer, voter1, voter2, voter3, voter4, other] = await ethers.getSigners(); - const receiver = await ethers.deployContract('CallReceiverMock'); - - const token = await ethers.deployContract(Token, [tokenName, tokenSymbol, tokenName, version]); - const mock = await ethers.deployContract('$GovernorWithParamsMock', [name, token]); - - await owner.sendTransaction({ to: mock, value }); - await token.$_mint(owner, tokenSupply); - - const helper = new GovernorHelper(mock, mode); - await helper.connect(owner).delegate({ token, to: voter1, value: ethers.parseEther('10') }); - await helper.connect(owner).delegate({ token, to: voter2, value: ethers.parseEther('7') }); - await helper.connect(owner).delegate({ token, to: voter3, value: ethers.parseEther('5') }); - await helper.connect(owner).delegate({ token, to: voter4, value: ethers.parseEther('2') }); - - return { owner, proposer, voter1, voter2, voter3, voter4, other, receiver, token, mock, helper }; - }; - - describe(`using ${Token}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.target, - value, - data: this.receiver.interface.encodeFunctionData('mockFunction'), - }, - ], - '', - ); - }); - - it('deployment check', async function () { - expect(await this.mock.name()).to.equal(name); - expect(await this.mock.token()).to.equal(this.token); - expect(await this.mock.votingDelay()).to.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.equal(votingPeriod); - }); - - it('nominal is unaffected', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - await this.helper.connect(this.voter1).vote({ support: VoteType.For, reason: 'This is nice' }); - await this.helper.connect(this.voter2).vote({ support: VoteType.For }); - await this.helper.connect(this.voter3).vote({ support: VoteType.Against }); - await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - - expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false; - expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.true; - expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.true; - expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); - expect(await ethers.provider.getBalance(this.receiver)).to.equal(value); - }); - - it('Voting with params is properly supported', async function () { - await this.helper.connect(this.proposer).propose(); - await this.helper.waitForSnapshot(); - - const weight = ethers.parseEther('7') - params.decoded[0]; - - await expect( - this.helper.connect(this.voter2).vote({ - support: VoteType.For, - reason: 'no particular reason', - params: params.encoded, - }), - ) - .to.emit(this.mock, 'CountParams') - .withArgs(...params.decoded) - .to.emit(this.mock, 'VoteCastWithParams') - .withArgs( - this.voter2.address, - this.proposal.id, - VoteType.For, - weight, - 'no particular reason', - params.encoded, - ); - - expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([0n, weight, 0n]); - }); - - describe('voting by signature', function () { - it('supports EOA signatures', async function () { - await this.token.connect(this.voter2).delegate(this.other); - - // Run proposal - await this.helper.propose(); - await this.helper.waitForSnapshot(); - - // Prepare vote - const weight = ethers.parseEther('7') - params.decoded[0]; - const nonce = await this.mock.nonces(this.other); - const data = { - proposalId: this.proposal.id, - support: VoteType.For, - voter: this.other.address, - nonce, - reason: 'no particular reason', - params: params.encoded, - signature: (contract, message) => - getDomain(contract).then(domain => this.other.signTypedData(domain, { ExtendedBallot }, message)), - }; - - // Vote - await expect(this.helper.vote(data)) - .to.emit(this.mock, 'CountParams') - .withArgs(...params.decoded) - .to.emit(this.mock, 'VoteCastWithParams') - .withArgs(data.voter, data.proposalId, data.support, weight, data.reason, data.params); - - expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([0n, weight, 0n]); - expect(await this.mock.nonces(this.other)).to.equal(nonce + 1n); - }); - - it('supports EIP-1271 signature signatures', async function () { - const wallet = await ethers.deployContract('ERC1271WalletMock', [this.other]); - await this.token.connect(this.voter2).delegate(wallet); - - // Run proposal - await this.helper.propose(); - await this.helper.waitForSnapshot(); - - // Prepare vote - const weight = ethers.parseEther('7') - params.decoded[0]; - const nonce = await this.mock.nonces(this.other); - const data = { - proposalId: this.proposal.id, - support: VoteType.For, - voter: wallet.target, - nonce, - reason: 'no particular reason', - params: params.encoded, - signature: (contract, message) => - getDomain(contract).then(domain => this.other.signTypedData(domain, { ExtendedBallot }, message)), - }; - - // Vote - await expect(this.helper.vote(data)) - .to.emit(this.mock, 'CountParams') - .withArgs(...params.decoded) - .to.emit(this.mock, 'VoteCastWithParams') - .withArgs(data.voter, data.proposalId, data.support, weight, data.reason, data.params); - - expect(await this.mock.proposalVotes(this.proposal.id)).to.deep.equal([0n, weight, 0n]); - expect(await this.mock.nonces(wallet)).to.equal(nonce + 1n); - }); - - it('reverts if signature does not match signer', async function () { - await this.token.connect(this.voter2).delegate(this.other); - - // Run proposal - await this.helper.propose(); - await this.helper.waitForSnapshot(); - - // Prepare vote - const nonce = await this.mock.nonces(this.other); - const data = { - proposalId: this.proposal.id, - support: VoteType.For, - voter: this.other.address, - nonce, - reason: 'no particular reason', - params: params.encoded, - // tampered signature - signature: (contract, message) => - getDomain(contract) - .then(domain => this.other.signTypedData(domain, { ExtendedBallot }, message)) - .then(signature => { - const tamperedSig = ethers.toBeArray(signature); - tamperedSig[42] ^= 0xff; - return ethers.hexlify(tamperedSig); - }), - }; - - // Vote - await expect(this.helper.vote(data)) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') - .withArgs(data.voter); - }); - - it('reverts if vote nonce is incorrect', async function () { - await this.token.connect(this.voter2).delegate(this.other); - - // Run proposal - await this.helper.propose(); - await this.helper.waitForSnapshot(); - - // Prepare vote - const nonce = await this.mock.nonces(this.other); - const data = { - proposalId: this.proposal.id, - support: VoteType.For, - voter: this.other.address, - nonce: nonce + 1n, - reason: 'no particular reason', - params: params.encoded, - signature: (contract, message) => - getDomain(contract).then(domain => this.other.signTypedData(domain, { ExtendedBallot }, message)), - }; - - // Vote - await expect(this.helper.vote(data)) - .to.be.revertedWithCustomError(this.mock, 'GovernorInvalidSignature') - .withArgs(data.voter); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/ERC6372.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/ERC6372.behavior.js deleted file mode 100644 index 32f27b5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/ERC6372.behavior.js +++ /dev/null @@ -1,28 +0,0 @@ -const { expect } = require('chai'); -const time = require('../../helpers/time'); - -function shouldBehaveLikeERC6372(mode = 'blocknumber') { - describe(`ERC-6372 behavior in ${mode} mode`, function () { - beforeEach(async function () { - this.mock = this.mock ?? this.token ?? this.votes; - }); - - it('should have a correct clock value', async function () { - const currentClock = await this.mock.clock(); - const expectedClock = await time.clock[mode](); - expect(currentClock).to.equal(expectedClock, `Clock mismatch in ${mode} mode`); - }); - - it('should have the correct CLOCK_MODE parameters', async function () { - const clockModeParams = new URLSearchParams(await this.mock.CLOCK_MODE()); - const expectedFromValue = mode === 'blocknumber' ? 'default' : null; - - expect(clockModeParams.get('mode')).to.equal(mode, `Expected mode to be ${mode}`); - expect(clockModeParams.get('from')).to.equal(expectedFromValue, `Expected 'from' to be ${expectedFromValue}`); - }); - }); -} - -module.exports = { - shouldBehaveLikeERC6372, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js deleted file mode 100644 index 0997701..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js +++ /dev/null @@ -1,325 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { mine } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain, Delegation } = require('../../helpers/eip712'); -const time = require('../../helpers/time'); - -const { shouldBehaveLikeERC6372 } = require('./ERC6372.behavior'); - -function shouldBehaveLikeVotes(tokens, { mode = 'blocknumber', fungible = true }) { - beforeEach(async function () { - [this.delegator, this.delegatee, this.alice, this.bob, this.other] = this.accounts; - this.domain = await getDomain(this.votes); - }); - - shouldBehaveLikeERC6372(mode); - - const getWeight = token => (fungible ? token : 1n); - - describe('run votes workflow', function () { - it('initial nonce is 0', async function () { - expect(await this.votes.nonces(this.alice)).to.equal(0n); - }); - - describe('delegation with signature', function () { - const token = tokens[0]; - - it('delegation without tokens', async function () { - expect(await this.votes.delegates(this.alice)).to.equal(ethers.ZeroAddress); - - await expect(this.votes.connect(this.alice).delegate(this.alice)) - .to.emit(this.votes, 'DelegateChanged') - .withArgs(this.alice, ethers.ZeroAddress, this.alice) - .to.not.emit(this.votes, 'DelegateVotesChanged'); - - expect(await this.votes.delegates(this.alice)).to.equal(this.alice); - }); - - it('delegation with tokens', async function () { - await this.votes.$_mint(this.alice, token); - const weight = getWeight(token); - - expect(await this.votes.delegates(this.alice)).to.equal(ethers.ZeroAddress); - - const tx = await this.votes.connect(this.alice).delegate(this.alice); - const timepoint = await time.clockFromReceipt[mode](tx); - - await expect(tx) - .to.emit(this.votes, 'DelegateChanged') - .withArgs(this.alice, ethers.ZeroAddress, this.alice) - .to.emit(this.votes, 'DelegateVotesChanged') - .withArgs(this.alice, 0n, weight); - - expect(await this.votes.delegates(this.alice)).to.equal(this.alice); - expect(await this.votes.getVotes(this.alice)).to.equal(weight); - expect(await this.votes.getPastVotes(this.alice, timepoint - 1n)).to.equal(0n); - await mine(); - expect(await this.votes.getPastVotes(this.alice, timepoint)).to.equal(weight); - }); - - it('delegation update', async function () { - await this.votes.connect(this.alice).delegate(this.alice); - await this.votes.$_mint(this.alice, token); - const weight = getWeight(token); - - expect(await this.votes.delegates(this.alice)).to.equal(this.alice); - expect(await this.votes.getVotes(this.alice)).to.equal(weight); - expect(await this.votes.getVotes(this.bob)).to.equal(0); - - const tx = await this.votes.connect(this.alice).delegate(this.bob); - const timepoint = await time.clockFromReceipt[mode](tx); - - await expect(tx) - .to.emit(this.votes, 'DelegateChanged') - .withArgs(this.alice, this.alice, this.bob) - .to.emit(this.votes, 'DelegateVotesChanged') - .withArgs(this.alice, weight, 0) - .to.emit(this.votes, 'DelegateVotesChanged') - .withArgs(this.bob, 0, weight); - - expect(await this.votes.delegates(this.alice)).to.equal(this.bob); - expect(await this.votes.getVotes(this.alice)).to.equal(0n); - expect(await this.votes.getVotes(this.bob)).to.equal(weight); - - expect(await this.votes.getPastVotes(this.alice, timepoint - 1n)).to.equal(weight); - expect(await this.votes.getPastVotes(this.bob, timepoint - 1n)).to.equal(0n); - await mine(); - expect(await this.votes.getPastVotes(this.alice, timepoint)).to.equal(0n); - expect(await this.votes.getPastVotes(this.bob, timepoint)).to.equal(weight); - }); - - describe('with signature', function () { - const nonce = 0n; - - it('accept signed delegation', async function () { - await this.votes.$_mint(this.delegator, token); - const weight = getWeight(token); - - const { r, s, v } = await this.delegator - .signTypedData( - this.domain, - { Delegation }, - { - delegatee: this.delegatee.address, - nonce, - expiry: ethers.MaxUint256, - }, - ) - .then(ethers.Signature.from); - - expect(await this.votes.delegates(this.delegator)).to.equal(ethers.ZeroAddress); - - const tx = await this.votes.delegateBySig(this.delegatee, nonce, ethers.MaxUint256, v, r, s); - const timepoint = await time.clockFromReceipt[mode](tx); - - await expect(tx) - .to.emit(this.votes, 'DelegateChanged') - .withArgs(this.delegator, ethers.ZeroAddress, this.delegatee) - .to.emit(this.votes, 'DelegateVotesChanged') - .withArgs(this.delegatee, 0, weight); - - expect(await this.votes.delegates(this.delegator.address)).to.equal(this.delegatee); - expect(await this.votes.getVotes(this.delegator.address)).to.equal(0n); - expect(await this.votes.getVotes(this.delegatee)).to.equal(weight); - expect(await this.votes.getPastVotes(this.delegatee, timepoint - 1n)).to.equal(0n); - await mine(); - expect(await this.votes.getPastVotes(this.delegatee, timepoint)).to.equal(weight); - }); - - it('rejects reused signature', async function () { - const { r, s, v } = await this.delegator - .signTypedData( - this.domain, - { Delegation }, - { - delegatee: this.delegatee.address, - nonce, - expiry: ethers.MaxUint256, - }, - ) - .then(ethers.Signature.from); - - await this.votes.delegateBySig(this.delegatee, nonce, ethers.MaxUint256, v, r, s); - - await expect(this.votes.delegateBySig(this.delegatee, nonce, ethers.MaxUint256, v, r, s)) - .to.be.revertedWithCustomError(this.votes, 'InvalidAccountNonce') - .withArgs(this.delegator, nonce + 1n); - }); - - it('rejects bad delegatee', async function () { - const { r, s, v } = await this.delegator - .signTypedData( - this.domain, - { Delegation }, - { - delegatee: this.delegatee.address, - nonce, - expiry: ethers.MaxUint256, - }, - ) - .then(ethers.Signature.from); - - const tx = await this.votes.delegateBySig(this.other, nonce, ethers.MaxUint256, v, r, s); - const receipt = await tx.wait(); - - const [delegateChanged] = receipt.logs.filter( - log => this.votes.interface.parseLog(log)?.name === 'DelegateChanged', - ); - const { args } = this.votes.interface.parseLog(delegateChanged); - expect(args.delegator).to.not.be.equal(this.delegator); - expect(args.fromDelegate).to.equal(ethers.ZeroAddress); - expect(args.toDelegate).to.equal(this.other); - }); - - it('rejects bad nonce', async function () { - const { r, s, v } = await this.delegator - .signTypedData( - this.domain, - { Delegation }, - { - delegatee: this.delegatee.address, - nonce: nonce + 1n, - expiry: ethers.MaxUint256, - }, - ) - .then(ethers.Signature.from); - - await expect(this.votes.delegateBySig(this.delegatee, nonce + 1n, ethers.MaxUint256, v, r, s)) - .to.be.revertedWithCustomError(this.votes, 'InvalidAccountNonce') - .withArgs(this.delegator, 0); - }); - - it('rejects expired permit', async function () { - const expiry = (await time.clock.timestamp()) - 1n; - const { r, s, v } = await this.delegator - .signTypedData( - this.domain, - { Delegation }, - { - delegatee: this.delegatee.address, - nonce, - expiry, - }, - ) - .then(ethers.Signature.from); - - await expect(this.votes.delegateBySig(this.delegatee, nonce, expiry, v, r, s)) - .to.be.revertedWithCustomError(this.votes, 'VotesExpiredSignature') - .withArgs(expiry); - }); - }); - }); - - describe('getPastTotalSupply', function () { - beforeEach(async function () { - await this.votes.connect(this.alice).delegate(this.alice); - }); - - it('reverts if block number >= current block', async function () { - const timepoint = 5e10; - const clock = await this.votes.clock(); - await expect(this.votes.getPastTotalSupply(timepoint)) - .to.be.revertedWithCustomError(this.votes, 'ERC5805FutureLookup') - .withArgs(timepoint, clock); - }); - - it('returns 0 if there are no checkpoints', async function () { - expect(await this.votes.getPastTotalSupply(0n)).to.equal(0n); - }); - - 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(this.alice, tokens[0]); - await mine(); - // t1 = mint #1 - const t1 = await this.votes.$_mint(this.alice, tokens[1]); - await mine(); - // t2 = burn #1 - const t2 = await this.votes.$_burn(...(fungible ? [this.alice] : []), tokens[1]); - await mine(); - // t3 = mint #2 - const t3 = await this.votes.$_mint(this.alice, tokens[2]); - await mine(); - // t4 = burn #0 - const t4 = await this.votes.$_burn(...(fungible ? [this.alice] : []), tokens[0]); - await mine(); - // t5 = burn #2 - const t5 = await this.votes.$_burn(...(fungible ? [this.alice] : []), tokens[2]); - await mine(); - - t0.timepoint = await time.clockFromReceipt[mode](t0); - t1.timepoint = await time.clockFromReceipt[mode](t1); - t2.timepoint = await time.clockFromReceipt[mode](t2); - t3.timepoint = await time.clockFromReceipt[mode](t3); - t4.timepoint = await time.clockFromReceipt[mode](t4); - t5.timepoint = await time.clockFromReceipt[mode](t5); - - expect(await this.votes.getPastTotalSupply(t0.timepoint - 1n)).to.equal(0); - expect(await this.votes.getPastTotalSupply(t0.timepoint)).to.equal(weight[0]); - expect(await this.votes.getPastTotalSupply(t0.timepoint + 1n)).to.equal(weight[0]); - expect(await this.votes.getPastTotalSupply(t1.timepoint)).to.equal(weight[0] + weight[1]); - expect(await this.votes.getPastTotalSupply(t1.timepoint + 1n)).to.equal(weight[0] + weight[1]); - expect(await this.votes.getPastTotalSupply(t2.timepoint)).to.equal(weight[0]); - expect(await this.votes.getPastTotalSupply(t2.timepoint + 1n)).to.equal(weight[0]); - expect(await this.votes.getPastTotalSupply(t3.timepoint)).to.equal(weight[0] + weight[2]); - expect(await this.votes.getPastTotalSupply(t3.timepoint + 1n)).to.equal(weight[0] + weight[2]); - expect(await this.votes.getPastTotalSupply(t4.timepoint)).to.equal(weight[2]); - expect(await this.votes.getPastTotalSupply(t4.timepoint + 1n)).to.equal(weight[2]); - expect(await this.votes.getPastTotalSupply(t5.timepoint)).to.equal(0); - await expect(this.votes.getPastTotalSupply(t5.timepoint + 1n)) - .to.be.revertedWithCustomError(this.votes, 'ERC5805FutureLookup') - .withArgs(t5.timepoint + 1n, t5.timepoint + 1n); - }); - }); - - // 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(this.alice, tokens[0]); - await this.votes.$_mint(this.alice, tokens[1]); - await this.votes.$_mint(this.alice, 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 expect(this.votes.getPastVotes(this.bob, timepoint)) - .to.be.revertedWithCustomError(this.votes, 'ERC5805FutureLookup') - .withArgs(timepoint, clock); - }); - - it('returns 0 if there are no checkpoints', async function () { - expect(await this.votes.getPastVotes(this.bob, 0n)).to.equal(0n); - }); - - it('returns the latest block if >= last checkpoint block', async function () { - const delegate = await this.votes.connect(this.alice).delegate(this.bob); - const timepoint = await time.clockFromReceipt[mode](delegate); - await mine(2); - - const latest = await this.votes.getVotes(this.bob); - expect(await this.votes.getPastVotes(this.bob, timepoint)).to.equal(latest); - expect(await this.votes.getPastVotes(this.bob, timepoint + 1n)).to.equal(latest); - }); - - it('returns zero if < first checkpoint block', async function () { - await mine(); - const delegate = await this.votes.connect(this.alice).delegate(this.bob); - const timepoint = await time.clockFromReceipt[mode](delegate); - await mine(2); - - expect(await this.votes.getPastVotes(this.bob, timepoint - 1n)).to.equal(0n); - }); - }); - }); - }); -} - -module.exports = { - shouldBehaveLikeVotes, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js deleted file mode 100644 index 7acacfc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js +++ /dev/null @@ -1,102 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { sum } = require('../../helpers/math'); -const { zip } = require('../../helpers/iterate'); -const time = require('../../helpers/time'); - -const { shouldBehaveLikeVotes } = require('./Votes.behavior'); - -const MODES = { - blocknumber: '$VotesMock', - timestamp: '$VotesTimestampMock', -}; - -const AMOUNTS = [ethers.parseEther('10000000'), 10n, 20n]; - -describe('Votes', function () { - for (const [mode, artifact] of Object.entries(MODES)) { - const fixture = async () => { - const accounts = await ethers.getSigners(); - - const amounts = Object.fromEntries( - zip( - accounts.slice(0, AMOUNTS.length).map(({ address }) => address), - AMOUNTS, - ), - ); - - const name = 'My Vote'; - const version = '1'; - const votes = await ethers.deployContract(artifact, [name, version]); - - return { accounts, amounts, votes, name, version }; - }; - - describe(`vote with ${mode}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeVotes(AMOUNTS, { mode, fungible: true }); - - it('starts with zero votes', async function () { - expect(await this.votes.getTotalSupply()).to.equal(0n); - }); - - describe('performs voting operations', function () { - beforeEach(async function () { - this.txs = []; - for (const [account, amount] of Object.entries(this.amounts)) { - this.txs.push(await this.votes.$_mint(account, amount)); - } - }); - - it('reverts if block number >= current block', async function () { - const lastTxTimepoint = await time.clockFromReceipt[mode](this.txs.at(-1)); - const clock = await this.votes.clock(); - await expect(this.votes.getPastTotalSupply(lastTxTimepoint)) - .to.be.revertedWithCustomError(this.votes, 'ERC5805FutureLookup') - .withArgs(lastTxTimepoint, clock); - }); - - it('delegates', async function () { - expect(await this.votes.getVotes(this.accounts[0])).to.equal(0n); - expect(await this.votes.getVotes(this.accounts[1])).to.equal(0n); - expect(await this.votes.delegates(this.accounts[0])).to.equal(ethers.ZeroAddress); - expect(await this.votes.delegates(this.accounts[1])).to.equal(ethers.ZeroAddress); - - await this.votes.delegate(this.accounts[0], ethers.Typed.address(this.accounts[0])); - - expect(await this.votes.getVotes(this.accounts[0])).to.equal(this.amounts[this.accounts[0].address]); - expect(await this.votes.getVotes(this.accounts[1])).to.equal(0n); - expect(await this.votes.delegates(this.accounts[0])).to.equal(this.accounts[0]); - expect(await this.votes.delegates(this.accounts[1])).to.equal(ethers.ZeroAddress); - - await this.votes.delegate(this.accounts[1], ethers.Typed.address(this.accounts[0])); - - expect(await this.votes.getVotes(this.accounts[0])).to.equal( - this.amounts[this.accounts[0].address] + this.amounts[this.accounts[1].address], - ); - expect(await this.votes.getVotes(this.accounts[1])).to.equal(0n); - expect(await this.votes.delegates(this.accounts[0])).to.equal(this.accounts[0]); - expect(await this.votes.delegates(this.accounts[1])).to.equal(this.accounts[0]); - }); - - it('cross delegates', async function () { - await this.votes.delegate(this.accounts[0], ethers.Typed.address(this.accounts[1])); - await this.votes.delegate(this.accounts[1], ethers.Typed.address(this.accounts[0])); - - expect(await this.votes.getVotes(this.accounts[0])).to.equal(this.amounts[this.accounts[1].address]); - expect(await this.votes.getVotes(this.accounts[1])).to.equal(this.amounts[this.accounts[0].address]); - }); - - it('returns total amount of votes', async function () { - const totalSupply = sum(...Object.values(this.amounts)); - expect(await this.votes.getTotalSupply()).to.equal(totalSupply); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/VotesExtended.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/VotesExtended.test.js deleted file mode 100644 index 4a66ef2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/governance/utils/VotesExtended.test.js +++ /dev/null @@ -1,152 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers'); - -const { sum } = require('../../helpers/math'); -const { zip } = require('../../helpers/iterate'); -const time = require('../../helpers/time'); - -const { shouldBehaveLikeVotes } = require('./Votes.behavior'); - -const MODES = { - blocknumber: '$VotesExtendedMock', - timestamp: '$VotesExtendedTimestampMock', -}; - -const AMOUNTS = [ethers.parseEther('10000000'), 10n, 20n]; - -describe('VotesExtended', function () { - for (const [mode, artifact] of Object.entries(MODES)) { - const fixture = async () => { - const accounts = await ethers.getSigners(); - - const amounts = Object.fromEntries( - zip( - accounts.slice(0, AMOUNTS.length).map(({ address }) => address), - AMOUNTS, - ), - ); - - const name = 'Override Votes'; - const version = '1'; - const votes = await ethers.deployContract(artifact, [name, version]); - - return { accounts, amounts, votes, name, version }; - }; - - describe(`vote with ${mode}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeVotes(AMOUNTS, { mode, fungible: true }); - - it('starts with zero votes', async function () { - expect(await this.votes.getTotalSupply()).to.equal(0n); - }); - - describe('performs voting operations', function () { - beforeEach(async function () { - this.txs = []; - for (const [account, amount] of Object.entries(this.amounts)) { - this.txs.push(await this.votes.$_mint(account, amount)); - } - }); - - it('reverts if block number >= current block', async function () { - const lastTxTimepoint = await time.clockFromReceipt[mode](this.txs.at(-1)); - const clock = await this.votes.clock(); - await expect(this.votes.getPastTotalSupply(lastTxTimepoint)) - .to.be.revertedWithCustomError(this.votes, 'ERC5805FutureLookup') - .withArgs(lastTxTimepoint, clock); - }); - - it('delegates', async function () { - expect(await this.votes.getVotes(this.accounts[0])).to.equal(0n); - expect(await this.votes.getVotes(this.accounts[1])).to.equal(0n); - expect(await this.votes.delegates(this.accounts[0])).to.equal(ethers.ZeroAddress); - expect(await this.votes.delegates(this.accounts[1])).to.equal(ethers.ZeroAddress); - - await this.votes.delegate(this.accounts[0], ethers.Typed.address(this.accounts[0])); - - expect(await this.votes.getVotes(this.accounts[0])).to.equal(this.amounts[this.accounts[0].address]); - expect(await this.votes.getVotes(this.accounts[1])).to.equal(0n); - expect(await this.votes.delegates(this.accounts[0])).to.equal(this.accounts[0]); - expect(await this.votes.delegates(this.accounts[1])).to.equal(ethers.ZeroAddress); - - await this.votes.delegate(this.accounts[1], ethers.Typed.address(this.accounts[0])); - - expect(await this.votes.getVotes(this.accounts[0])).to.equal( - this.amounts[this.accounts[0].address] + this.amounts[this.accounts[1].address], - ); - expect(await this.votes.getVotes(this.accounts[1])).to.equal(0n); - expect(await this.votes.delegates(this.accounts[0])).to.equal(this.accounts[0]); - expect(await this.votes.delegates(this.accounts[1])).to.equal(this.accounts[0]); - }); - - it('cross delegates', async function () { - await this.votes.delegate(this.accounts[0], ethers.Typed.address(this.accounts[1])); - await this.votes.delegate(this.accounts[1], ethers.Typed.address(this.accounts[0])); - - expect(await this.votes.getVotes(this.accounts[0])).to.equal(this.amounts[this.accounts[1].address]); - expect(await this.votes.getVotes(this.accounts[1])).to.equal(this.amounts[this.accounts[0].address]); - }); - - it('returns total amount of votes', async function () { - const totalSupply = sum(...Object.values(this.amounts)); - expect(await this.votes.getTotalSupply()).to.equal(totalSupply); - }); - }); - }); - - describe(`checkpoint delegates with ${mode}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('checkpoint delegates', async function () { - const tx = await this.votes.delegate(this.accounts[0], ethers.Typed.address(this.accounts[1])); - const timepoint = await time.clockFromReceipt[mode](tx); - await mine(2); - - expect(await this.votes.getPastDelegate(this.accounts[0], timepoint - 1n)).to.equal(ethers.ZeroAddress); - expect(await this.votes.getPastDelegate(this.accounts[0], timepoint)).to.equal(this.accounts[1].address); - expect(await this.votes.getPastDelegate(this.accounts[0], timepoint + 1n)).to.equal(this.accounts[1].address); - }); - - it('reverts if current timepoint <= timepoint', async function () { - const tx = await this.votes.delegate(this.accounts[0], ethers.Typed.address(this.accounts[1])); - const timepoint = await time.clockFromReceipt[mode](tx); - - await expect(this.votes.getPastDelegate(this.accounts[0], timepoint + 1n)) - .to.be.revertedWithCustomError(this.votes, 'ERC5805FutureLookup') - .withArgs(timepoint + 1n, timepoint); - }); - }); - - describe(`checkpoint balances with ${mode}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('checkpoint balances', async function () { - const tx = await this.votes.$_mint(this.accounts[0].address, 100n); - const timepoint = await time.clockFromReceipt[mode](tx); - await mine(2); - - expect(await this.votes.getPastBalanceOf(this.accounts[0].address, timepoint - 1n)).to.equal(0n); - expect(await this.votes.getPastBalanceOf(this.accounts[0].address, timepoint)).to.equal(100n); - expect(await this.votes.getPastBalanceOf(this.accounts[0].address, timepoint + 1n)).to.equal(100n); - }); - - it('reverts if current timepoint <= timepoint', async function () { - const tx = await this.votes.$_mint(this.accounts[0].address, 100n); - const timepoint = await time.clockFromReceipt[mode](tx); - - await expect(this.votes.getPastBalanceOf(this.accounts[0], timepoint + 1n)) - .to.be.revertedWithCustomError(this.votes, 'ERC5805FutureLookup') - .withArgs(timepoint + 1n, timepoint); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/access-manager.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/access-manager.js deleted file mode 100644 index 3b83430..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/access-manager.js +++ /dev/null @@ -1,85 +0,0 @@ -const { ethers } = require('hardhat'); - -const { MAX_UINT64 } = require('./constants'); -const time = require('./time'); -const { upgradeableSlot } = require('./storage'); - -function buildBaseRoles() { - const roles = { - ADMIN: { - id: 0n, - }, - SOME_ADMIN: { - id: 17n, - }, - SOME_GUARDIAN: { - id: 35n, - }, - SOME: { - id: 42n, - }, - 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); - -const EXECUTION_ID_STORAGE_SLOT = upgradeableSlot('AccessManager', 3n); -const CONSUMING_SCHEDULE_STORAGE_SLOT = upgradeableSlot('AccessManaged', 0n); - -/** - * @requires this.{manager, caller, target, calldata} - */ -async function prepareOperation(manager, { caller, target, calldata, delay }) { - const scheduledAt = (await time.clock.timestamp()) + 1n; - await time.increaseTo.timestamp(scheduledAt, false); // Fix next block timestamp for predictability - - return { - schedule: () => manager.connect(caller).schedule(target, calldata, scheduledAt + delay), - scheduledAt, - operationId: hashOperation(caller, target, calldata), - }; -} - -const lazyGetAddress = addressable => addressable.address ?? addressable.target ?? addressable; - -const hashOperation = (caller, target, data) => - ethers.keccak256( - ethers.AbiCoder.defaultAbiCoder().encode( - ['address', 'address', 'bytes'], - [lazyGetAddress(caller), lazyGetAddress(target), data], - ), - ); - -module.exports = { - buildBaseRoles, - formatAccess, - MINSETBACK, - EXPIRATION, - EXECUTION_ID_STORAGE_SLOT, - CONSUMING_SCHEDULE_STORAGE_SLOT, - prepareOperation, - hashOperation, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/account.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/account.js deleted file mode 100644 index 96874b1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/account.js +++ /dev/null @@ -1,14 +0,0 @@ -const { ethers } = require('hardhat'); -const { impersonateAccount, setBalance } = require('@nomicfoundation/hardhat-network-helpers'); - -// Hardhat default balance -const DEFAULT_BALANCE = 10000n * ethers.WeiPerEther; - -const impersonate = (account, balance = DEFAULT_BALANCE) => - impersonateAccount(account) - .then(() => setBalance(account, balance)) - .then(() => ethers.getSigner(account)); - -module.exports = { - impersonate, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/chains.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/chains.js deleted file mode 100644 index 3711a81..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/chains.js +++ /dev/null @@ -1,109 +0,0 @@ -// NOTE: this file defines some examples of CAIP-2 and CAIP-10 identifiers. -// The following listing does not pretend to be exhaustive or even accurate. It SHOULD NOT be used in production. - -const { ethers } = require('hardhat'); -const { mapValues } = require('./iterate'); - -// EVM (https://axelarscan.io/resources/chains?type=evm) -const ethereum = { - Ethereum: '1', - optimism: '10', - binance: '56', - Polygon: '137', - Fantom: '250', - fraxtal: '252', - filecoin: '314', - Moonbeam: '1284', - centrifuge: '2031', - kava: '2222', - mantle: '5000', - base: '8453', - immutable: '13371', - arbitrum: '42161', - celo: '42220', - Avalanche: '43114', - linea: '59144', - blast: '81457', - scroll: '534352', - aurora: '1313161554', -}; - -// Cosmos (https://axelarscan.io/resources/chains?type=cosmos) -const cosmos = { - Axelarnet: 'axelar-dojo-1', - osmosis: 'osmosis-1', - cosmoshub: 'cosmoshub-4', - juno: 'juno-1', - 'e-money': 'emoney-3', - injective: 'injective-1', - crescent: 'crescent-1', - kujira: 'kaiyo-1', - 'secret-snip': 'secret-4', - secret: 'secret-4', - sei: 'pacific-1', - stargaze: 'stargaze-1', - assetmantle: 'mantle-1', - fetch: 'fetchhub-4', - ki: 'kichain-2', - evmos: 'evmos_9001-2', - aura: 'xstaxy-1', - comdex: 'comdex-1', - persistence: 'core-1', - regen: 'regen-1', - umee: 'umee-1', - agoric: 'agoric-3', - xpla: 'dimension_37-1', - acre: 'acre_9052-1', - stride: 'stride-1', - carbon: 'carbon-1', - sommelier: 'sommelier-3', - neutron: 'neutron-1', - rebus: 'reb_1111-1', - archway: 'archway-1', - provenance: 'pio-mainnet-1', - ixo: 'ixo-5', - migaloo: 'migaloo-1', - teritori: 'teritori-1', - haqq: 'haqq_11235-1', - celestia: 'celestia', - ojo: 'agamotto', - chihuahua: 'chihuahua-1', - saga: 'ssc-1', - dymension: 'dymension_1100-1', - fxcore: 'fxcore', - c4e: 'perun-1', - bitsong: 'bitsong-2b', - nolus: 'pirin-1', - lava: 'lava-mainnet-1', - 'terra-2': 'phoenix-1', - terra: 'columbus-5', -}; - -const makeCAIP = ({ namespace, reference, account }) => ({ - namespace, - reference, - account, - caip2: `${namespace}:${reference}`, - caip10: `${namespace}:${reference}:${account}`, - toCaip10: other => `${namespace}:${reference}:${ethers.getAddress(other.target ?? other.address ?? other)}`, -}); - -module.exports = { - CHAINS: mapValues( - Object.assign( - mapValues(ethereum, reference => ({ - namespace: 'eip155', - reference, - account: ethers.Wallet.createRandom().address, - })), - mapValues(cosmos, reference => ({ - namespace: 'cosmos', - reference, - account: ethers.encodeBase58(ethers.randomBytes(32)), - })), - ), - makeCAIP, - ), - getLocalCAIP: account => - ethers.provider.getNetwork().then(({ chainId }) => makeCAIP({ namespace: 'eip155', reference: chainId, account })), -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/constants.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/constants.js deleted file mode 100644 index eb9b43e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/constants.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - MAX_UINT32: 2n ** 32n - 1n, - MAX_UINT48: 2n ** 48n - 1n, - MAX_UINT64: 2n ** 64n - 1n, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/deploy.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/deploy.js deleted file mode 100644 index 0d4b956..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/deploy.js +++ /dev/null @@ -1,14 +0,0 @@ -const { artifacts, ethers } = require('hardhat'); -const { setCode } = require('@nomicfoundation/hardhat-network-helpers'); -const { generators } = require('./random'); - -const forceDeployCode = (name, address = generators.address(), runner = ethers.provider) => - artifacts - .readArtifact(name) - .then(({ abi, deployedBytecode }) => - setCode(address, deployedBytecode).then(() => new ethers.Contract(address, abi, runner)), - ); - -module.exports = { - forceDeployCode, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712-types.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712-types.js deleted file mode 100644 index fb6fe3a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712-types.js +++ /dev/null @@ -1,61 +0,0 @@ -const { mapValues } = require('./iterate'); - -const formatType = schema => Object.entries(schema).map(([name, type]) => ({ name, type })); - -module.exports = mapValues( - { - EIP712Domain: { - name: 'string', - version: 'string', - chainId: 'uint256', - verifyingContract: 'address', - salt: 'bytes32', - }, - Permit: { owner: 'address', spender: 'address', value: 'uint256', nonce: 'uint256', deadline: 'uint256' }, - Ballot: { proposalId: 'uint256', support: 'uint8', voter: 'address', nonce: 'uint256' }, - ExtendedBallot: { - proposalId: 'uint256', - support: 'uint8', - voter: 'address', - nonce: 'uint256', - reason: 'string', - params: 'bytes', - }, - OverrideBallot: { proposalId: 'uint256', support: 'uint8', voter: 'address', nonce: 'uint256', reason: 'string' }, - Delegation: { delegatee: 'address', nonce: 'uint256', expiry: 'uint256' }, - ForwardRequest: { - from: 'address', - to: 'address', - value: 'uint256', - gas: 'uint256', - nonce: 'uint256', - deadline: 'uint48', - data: 'bytes', - }, - PackedUserOperation: { - sender: 'address', - nonce: 'uint256', - initCode: 'bytes', - callData: 'bytes', - accountGasLimits: 'bytes32', - preVerificationGas: 'uint256', - gasFees: 'bytes32', - paymasterAndData: 'bytes', - }, - UserOperationRequest: { - sender: 'address', - nonce: 'uint256', - initCode: 'bytes', - callData: 'bytes', - accountGasLimits: 'bytes32', - preVerificationGas: 'uint256', - gasFees: 'bytes32', - paymasterVerificationGasLimit: 'uint256', - paymasterPostOpGasLimit: 'uint256', - validAfter: 'uint48', - validUntil: 'uint48', - }, - }, - formatType, -); -module.exports.formatType = formatType; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712.js deleted file mode 100644 index 3843ac0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/eip712.js +++ /dev/null @@ -1,45 +0,0 @@ -const { ethers } = require('hardhat'); -const types = require('./eip712-types'); - -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 types.EIP712Domain.entries()) { - if (!(fields & (1 << i))) { - delete domain[name]; - } - } - - return domain; -} - -function domainType(domain) { - return types.EIP712Domain.filter(({ name }) => domain[name] !== undefined); -} - -function hashTypedData(domain, structHash) { - return ethers.solidityPackedKeccak256( - ['bytes', 'bytes32', 'bytes32'], - ['0x1901', ethers.TypedDataEncoder.hashDomain(domain), structHash], - ); -} - -module.exports = { - getDomain, - domainType, - domainSeparator: ethers.TypedDataEncoder.hashDomain, - hashTypedData, - ...types, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/enums.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/enums.js deleted file mode 100644 index 6adbf64..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/enums.js +++ /dev/null @@ -1,14 +0,0 @@ -const { ethers } = require('ethers'); - -const Enum = (...options) => Object.fromEntries(options.map((key, i) => [key, BigInt(i)])); -const EnumTyped = (...options) => Object.fromEntries(options.map((key, i) => [key, ethers.Typed.uint8(i)])); - -module.exports = { - Enum, - EnumTyped, - ProposalState: Enum('Pending', 'Active', 'Canceled', 'Defeated', 'Succeeded', 'Queued', 'Expired', 'Executed'), - VoteType: Object.assign(Enum('Against', 'For', 'Abstain'), { Parameters: 255n }), - Rounding: EnumTyped('Floor', 'Ceil', 'Trunc', 'Expand'), - OperationState: Enum('Unset', 'Waiting', 'Ready', 'Done'), - RevertType: EnumTyped('None', 'RevertWithoutMessage', 'RevertWithMessage', 'RevertWithCustomError', 'Panic'), -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc4337.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc4337.js deleted file mode 100644 index 0d5421b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc4337.js +++ /dev/null @@ -1,217 +0,0 @@ -const { ethers, config, entrypoint, senderCreator } = require('hardhat'); - -const SIG_VALIDATION_SUCCESS = '0x0000000000000000000000000000000000000000'; -const SIG_VALIDATION_FAILURE = '0x0000000000000000000000000000000000000001'; - -function getAddress(account) { - return account.target ?? account.address ?? account; -} - -function pack(left, right) { - return ethers.solidityPacked(['uint128', 'uint128'], [left, right]); -} - -function packValidationData(validAfter, validUntil, authorizer) { - return ethers.solidityPacked( - ['uint48', 'uint48', 'address'], - [ - validAfter, - validUntil, - typeof authorizer == 'boolean' - ? authorizer - ? SIG_VALIDATION_SUCCESS - : SIG_VALIDATION_FAILURE - : getAddress(authorizer), - ], - ); -} - -function packInitCode(factory, factoryData) { - return ethers.solidityPacked(['address', 'bytes'], [getAddress(factory), factoryData]); -} - -function packPaymasterAndData(paymaster, paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymasterData) { - return ethers.solidityPacked( - ['address', 'uint128', 'uint128', 'bytes'], - [getAddress(paymaster), paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymasterData], - ); -} - -/// Represent one user operation -class UserOperation { - constructor(params) { - this.sender = getAddress(params.sender); - this.nonce = params.nonce; - this.factory = params.factory ?? undefined; - this.factoryData = params.factoryData ?? '0x'; - this.callData = params.callData ?? '0x'; - this.verificationGas = params.verificationGas ?? 10_000_000n; - this.callGas = params.callGas ?? 100_000n; - this.preVerificationGas = params.preVerificationGas ?? 100_000n; - this.maxPriorityFee = params.maxPriorityFee ?? 100_000n; - this.maxFeePerGas = params.maxFeePerGas ?? 100_000n; - this.paymaster = params.paymaster ?? undefined; - this.paymasterVerificationGasLimit = params.paymasterVerificationGasLimit ?? 0n; - this.paymasterPostOpGasLimit = params.paymasterPostOpGasLimit ?? 0n; - this.paymasterData = params.paymasterData ?? '0x'; - this.signature = params.signature ?? '0x'; - } - - get packed() { - return { - sender: this.sender, - nonce: this.nonce, - initCode: this.factory ? packInitCode(this.factory, this.factoryData) : '0x', - callData: this.callData, - accountGasLimits: pack(this.verificationGas, this.callGas), - preVerificationGas: this.preVerificationGas, - gasFees: pack(this.maxPriorityFee, this.maxFeePerGas), - paymasterAndData: this.paymaster - ? packPaymasterAndData( - this.paymaster, - this.paymasterVerificationGasLimit, - this.paymasterPostOpGasLimit, - this.paymasterData, - ) - : '0x', - signature: this.signature, - }; - } - - hash(entrypoint) { - return entrypoint.getUserOpHash(this.packed); - } -} - -const parseInitCode = initCode => ({ - factory: '0x' + initCode.replace(/0x/, '').slice(0, 40), - factoryData: '0x' + initCode.replace(/0x/, '').slice(40), -}); - -/// Global ERC-4337 environment helper. -class ERC4337Helper { - constructor() { - this.factoryAsPromise = ethers.deployContract('$Create2'); - } - - async wait() { - this.factory = await this.factoryAsPromise; - return this; - } - - async newAccount(name, extraArgs = [], params = {}) { - const env = { - entrypoint: params.entrypoint ?? entrypoint.v08, - senderCreator: params.senderCreator ?? senderCreator.v08, - }; - - const { factory } = await this.wait(); - - const accountFactory = await ethers.getContractFactory(name); - - if (params.erc7702signer) { - const delegate = await accountFactory.deploy(...extraArgs); - const instance = await params.erc7702signer.getAddress().then(address => accountFactory.attach(address)); - const authorization = await params.erc7702signer.authorize({ address: delegate.target }); - return new ERC7702SmartAccount(instance, authorization, env); - } else { - const initCode = await accountFactory - .getDeployTransaction(...extraArgs) - .then(tx => - factory.interface.encodeFunctionData('$deploy', [0, params.salt ?? ethers.randomBytes(32), tx.data]), - ) - .then(deployCode => ethers.concat([factory.target, deployCode])); - - const instance = await ethers.provider - .call({ - from: env.entrypoint, - to: env.senderCreator, - data: env.senderCreator.interface.encodeFunctionData('createSender', [initCode]), - }) - .then(result => ethers.getAddress(ethers.hexlify(ethers.getBytes(result).slice(-20)))) - .then(address => accountFactory.attach(address)); - - return new SmartAccount(instance, initCode, env); - } - } -} - -/// Represent one ERC-4337 account contract. -class SmartAccount extends ethers.BaseContract { - constructor(instance, initCode, env) { - super(instance.target, instance.interface, instance.runner, instance.deployTx); - this.address = instance.target; - this.initCode = initCode; - this._env = env; - } - - async deploy(account = this.runner) { - const { factory: to, factoryData: data } = parseInitCode(this.initCode); - this.deployTx = await account.sendTransaction({ to, data }); - return this; - } - - async createUserOp(userOp = {}) { - userOp.sender ??= this; - userOp.nonce ??= await this._env.entrypoint.getNonce(userOp.sender, 0); - if (ethers.isAddressable(userOp.paymaster)) { - userOp.paymaster = await ethers.resolveAddress(userOp.paymaster); - userOp.paymasterVerificationGasLimit ??= 100_000n; - userOp.paymasterPostOpGasLimit ??= 100_000n; - } - return new UserOperationWithContext(userOp, this._env); - } -} - -class ERC7702SmartAccount extends SmartAccount { - constructor(instance, authorization, env) { - super(instance, undefined, env); - this.authorization = authorization; - } - - async deploy() { - // hardhat signers from @nomicfoundation/hardhat-ethers do not support type 4 txs. - // so we rebuild it using "native" ethers - await ethers.Wallet.fromPhrase(config.networks.hardhat.accounts.mnemonic, ethers.provider).sendTransaction({ - to: ethers.ZeroAddress, - authorizationList: [this.authorization], - gasLimit: 46_000n, // 21,000 base + PER_EMPTY_ACCOUNT_COST - }); - - return this; - } -} - -class UserOperationWithContext extends UserOperation { - constructor(userOp, env) { - super(userOp); - this._sender = userOp.sender; - this._env = env; - } - - addInitCode() { - if (this._sender?.initCode) { - return Object.assign(this, parseInitCode(this._sender.initCode)); - } else throw new Error('No init code available for the sender of this user operation'); - } - - getAuthorization() { - if (this._sender?.authorization) { - return this._sender.authorization; - } else throw new Error('No EIP-7702 authorization available for the sender of this user operation'); - } - - hash() { - return super.hash(this._env.entrypoint); - } -} - -module.exports = { - SIG_VALIDATION_SUCCESS, - SIG_VALIDATION_FAILURE, - packValidationData, - packInitCode, - packPaymasterAndData, - UserOperation, - ERC4337Helper, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7579.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7579.js deleted file mode 100644 index 6c3b475..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7579.js +++ /dev/null @@ -1,58 +0,0 @@ -const { ethers } = require('hardhat'); - -const MODULE_TYPE_VALIDATOR = 1; -const MODULE_TYPE_EXECUTOR = 2; -const MODULE_TYPE_FALLBACK = 3; -const MODULE_TYPE_HOOK = 4; - -const EXEC_TYPE_DEFAULT = '0x00'; -const EXEC_TYPE_TRY = '0x01'; - -const CALL_TYPE_CALL = '0x00'; -const CALL_TYPE_BATCH = '0x01'; -const CALL_TYPE_DELEGATE = '0xff'; - -const encodeMode = ({ - callType = '0x00', - execType = '0x00', - selector = '0x00000000', - payload = '0x00000000000000000000000000000000000000000000', -} = {}) => - ethers.solidityPacked( - ['bytes1', 'bytes1', 'bytes4', 'bytes4', 'bytes22'], - [callType, execType, '0x00000000', selector, payload], - ); - -const encodeSingle = (target, value = 0n, data = '0x') => - ethers.solidityPacked(['address', 'uint256', 'bytes'], [target.target ?? target.address ?? target, value, data]); - -const encodeBatch = (...entries) => - ethers.AbiCoder.defaultAbiCoder().encode( - ['(address,uint256,bytes)[]'], - [ - entries.map(entry => - Array.isArray(entry) - ? [entry[0].target ?? entry[0].address ?? entry[0], entry[1] ?? 0n, entry[2] ?? '0x'] - : [entry.target.target ?? entry.target.address ?? entry.target, entry.value ?? 0n, entry.data ?? '0x'], - ), - ], - ); - -const encodeDelegate = (target, data = '0x') => - ethers.solidityPacked(['address', 'bytes'], [target.target ?? target.address ?? target, data]); - -module.exports = { - MODULE_TYPE_VALIDATOR, - MODULE_TYPE_EXECUTOR, - MODULE_TYPE_FALLBACK, - MODULE_TYPE_HOOK, - EXEC_TYPE_DEFAULT, - EXEC_TYPE_TRY, - CALL_TYPE_CALL, - CALL_TYPE_BATCH, - CALL_TYPE_DELEGATE, - encodeMode, - encodeSingle, - encodeBatch, - encodeDelegate, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7739.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7739.js deleted file mode 100644 index 5a489de..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/erc7739.js +++ /dev/null @@ -1,118 +0,0 @@ -const { ethers } = require('hardhat'); -const { formatType } = require('./eip712'); - -const PersonalSign = formatType({ prefixed: 'bytes' }); -const TypedDataSign = contentsTypeName => - formatType({ - contents: contentsTypeName, - name: 'string', - version: 'string', - chainId: 'uint256', - verifyingContract: 'address', - salt: 'bytes32', - }); - -class ERC7739Signer extends ethers.AbstractSigner { - #signer; - #domain; - - constructor(signer, domain) { - super(signer.provider); - this.#signer = signer; - this.#domain = domain; - } - - static from(signer, domain) { - return new this(signer, domain); - } - - get signingKey() { - return this.#signer.signingKey; - } - - get privateKey() { - return this.#signer.privateKey; - } - - async getAddress() { - return this.#signer.getAddress(); - } - - connect(provider) { - this.#signer.connect(provider); - } - - async signTransaction(tx) { - return this.#signer.signTransaction(tx); - } - - async signMessage(message) { - return this.#signer.signTypedData(this.#domain, { PersonalSign }, ERC4337Utils.preparePersonalSign(message)); - } - - async signTypedData(domain, types, value) { - const { allTypes, contentsTypeName, contentsDescr } = ERC4337Utils.getContentsDetail(types); - - return Promise.resolve( - this.#signer.signTypedData(domain, allTypes, ERC4337Utils.prepareSignTypedData(value, this.#domain)), - ).then(signature => - ethers.concat([ - signature, - ethers.TypedDataEncoder.hashDomain(domain), // appDomainSeparator - ethers.TypedDataEncoder.hashStruct(contentsTypeName, types, value), // contentsHash - ethers.toUtf8Bytes(contentsDescr), - ethers.toBeHex(contentsDescr.length, 2), - ]), - ); - } -} - -class ERC4337Utils { - static preparePersonalSign(message) { - return { - prefixed: ethers.concat([ - ethers.toUtf8Bytes(ethers.MessagePrefix), - ethers.toUtf8Bytes(String(message.length)), - typeof message === 'string' ? ethers.toUtf8Bytes(message) : message, - ]), - }; - } - - static prepareSignTypedData(contents, signerDomain) { - return { - name: signerDomain.name ?? '', - version: signerDomain.version ?? '', - chainId: signerDomain.chainId ?? 0, - verifyingContract: signerDomain.verifyingContract ?? ethers.ZeroAddress, - salt: signerDomain.salt ?? ethers.ZeroHash, - contents, - }; - } - - static getContentsDetail(contentsTypes, contentsTypeName = Object.keys(contentsTypes).at(0)) { - // Examples values - // - // contentsTypeName B - // typedDataSignType TypedDataSign(B contents,...)A(uint256 v)B(Z z)Z(A a) - // contentsType A(uint256 v)B(Z z)Z(A a) - // contentsDescr A(uint256 v)B(Z z)Z(A a)B - const allTypes = { TypedDataSign: TypedDataSign(contentsTypeName), ...contentsTypes }; - const typedDataSignType = ethers.TypedDataEncoder.from(allTypes).encodeType('TypedDataSign'); - const contentsType = typedDataSignType.slice(typedDataSignType.indexOf(')') + 1); // Remove TypedDataSign (first object) - const contentsDescr = contentsType + (contentsType.startsWith(contentsTypeName) ? '' : contentsTypeName); - - return { - allTypes, - contentsTypes, - contentsTypeName, - contentsDescr, - }; - } -} - -module.exports = { - ERC7739Signer, - ERC4337Utils, - PersonalSign, - TypedDataSign, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/governance.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/governance.js deleted file mode 100644 index e068644..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/governance.js +++ /dev/null @@ -1,217 +0,0 @@ -const { ethers } = require('hardhat'); -const { ProposalState } = require('./enums'); -const { unique } = require('./iterate'); -const time = require('./time'); - -const timelockSalt = (address, descriptionHash) => - ethers.toBeHex((ethers.toBigInt(address) << 96n) ^ ethers.toBigInt(descriptionHash), 32); - -class GovernorHelper { - constructor(governor, mode = 'blocknumber') { - this.governor = governor; - this.mode = mode; - } - - connect(account) { - this.governor = this.governor.connect(account); - return this; - } - - /// Setter and getters - /** - * Specify a proposal either as - * 1) an array of objects [{ target, value, data }] - * 2) an object of arrays { targets: [], values: [], data: [] } - */ - setProposal(actions, description) { - if (Array.isArray(actions)) { - this.targets = actions.map(a => a.target); - this.values = actions.map(a => a.value || 0n); - this.data = actions.map(a => a.data || '0x'); - } else { - ({ targets: this.targets, values: this.values, data: this.data } = actions); - } - this.description = description; - return this; - } - - get hash() { - return ethers.keccak256( - ethers.AbiCoder.defaultAbiCoder().encode(['address[]', 'uint256[]', 'bytes[]', 'bytes32'], this.shortProposal), - ); - } - - get id() { - return this.governor.latestProposalId ? this.governor.getProposalId(...this.shortProposal) : this.hash; - } - - // used for checking events - get signatures() { - return this.data.map(() => ''); - } - - get descriptionHash() { - return ethers.id(this.description); - } - - // condensed version for queueing end executing - get shortProposal() { - return [this.targets, this.values, this.data, this.descriptionHash]; - } - - // full version for proposing - get fullProposal() { - return [this.targets, this.values, this.data, this.description]; - } - - get currentProposal() { - return this; - } - - /// Proposal lifecycle - delegate(delegation) { - return Promise.all([ - delegation.token.connect(delegation.to).delegate(delegation.to), - delegation.value === undefined || - delegation.token.connect(this.governor.runner).transfer(delegation.to, delegation.value), - delegation.tokenId === undefined || - delegation.token - .ownerOf(delegation.tokenId) - .then(owner => - delegation.token.connect(this.governor.runner).transferFrom(owner, delegation.to, delegation.tokenId), - ), - ]); - } - - propose() { - return this.governor.propose(...this.fullProposal); - } - - queue() { - return this.governor.queue(...this.shortProposal); - } - - execute() { - return this.governor.execute(...this.shortProposal); - } - - cancel(visibility = 'external') { - switch (visibility) { - case 'external': - return this.governor.cancel(...this.shortProposal); - - case 'internal': - return this.governor.$_cancel(...this.shortProposal); - - default: - throw new Error(`unsupported visibility "${visibility}"`); - } - } - - async vote(vote = {}) { - let method = 'castVote'; // default - let args = [await this.id, vote.support]; // base - - if (vote.signature) { - const sign = await this.forgeMessage(vote).then(msg => vote.signature(this.governor, msg)); - if (vote.params || vote.reason) { - method = 'castVoteWithReasonAndParamsBySig'; - args.push(vote.voter, vote.reason ?? '', vote.params ?? '0x', sign); - } else { - method = 'castVoteBySig'; - args.push(vote.voter, sign); - } - } else if (vote.params) { - method = 'castVoteWithReasonAndParams'; - args.push(vote.reason ?? '', vote.params); - } else if (vote.reason) { - method = 'castVoteWithReason'; - args.push(vote.reason); - } - - return await this.governor[method](...args); - } - - async overrideVote(vote = {}) { - let method = 'castOverrideVote'; - let args = [await this.id, vote.support]; - - vote.reason = vote.reason ?? ''; - - if (vote.signature) { - const sign = await this.forgeMessage(vote).then(msg => vote.signature(this.governor, { reason: '', ...msg })); - method = 'castOverrideVoteBySig'; - args.push(vote.voter, vote.reason ?? '', sign); - } - - return await this.governor[method](...args); - } - - /// Clock helpers - async waitForSnapshot(offset = 0n) { - const timepoint = await this.governor.proposalSnapshot(await this.id); - return time.increaseTo[this.mode](timepoint + offset); - } - - async waitForDeadline(offset = 0n) { - const timepoint = await this.governor.proposalDeadline(await this.id); - return time.increaseTo[this.mode](timepoint + offset); - } - - async waitForEta(offset = 0n) { - const timestamp = await this.governor.proposalEta(await this.id); - return time.increaseTo.timestamp(timestamp + offset); - } - - /// Other helpers - async forgeMessage(vote = {}) { - const message = { proposalId: await this.id, support: vote.support, voter: vote.voter, nonce: vote.nonce }; - - if (vote.params || vote.reason) { - message.reason = vote.reason ?? ''; - message.params = vote.params ?? '0x'; - } - - return message; - } - - /** - * 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 - */ - static proposalStatesToBitMap(proposalStates, options = {}) { - if (!Array.isArray(proposalStates)) { - proposalStates = [proposalStates]; - } - const statesCount = ethers.toBigInt(Object.keys(ProposalState).length); - let result = 0n; - - for (const state of unique(proposalStates)) { - if (state < 0n || state >= statesCount) { - expect.fail(`ProposalState ${state} out of possible states (0...${statesCount}-1)`); - } else { - result |= 1n << state; - } - } - - if (options.inverted) { - const mask = 2n ** statesCount - 1n; - result = result ^ mask; - } - - return ethers.toBeHex(result, 32); - } -} - -module.exports = { - GovernorHelper, - timelockSalt, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/iterate.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/iterate.js deleted file mode 100644 index 8c8e964..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/iterate.js +++ /dev/null @@ -1,41 +0,0 @@ -module.exports = { - // ================================================= Array helpers ================================================= - - // Cut an array into an array of sized-length arrays - // Example: chunk([1,2,3,4,5,6,7,8], 3) → [[1,2,3],[4,5,6],[7,8]] - chunk: (array, size = 1) => - Array.from({ length: Math.ceil(array.length / size) }, (_, i) => array.slice(i * size, i * size + size)), - - // Cartesian cross product of an array of arrays - // Example: product([1,2],[a,b,c],[true]) → [[1,a,true],[1,b,true],[1,c,true],[2,a,true],[2,b,true],[2,c,true]] - product: (...arrays) => arrays.reduce((a, b) => a.flatMap(ai => b.map(bi => [...ai, bi])), [[]]), - - // Range from start to end in increment - // Example: range(17,42,7) → [17,24,31,38] - range: (start, stop = undefined, step = 1) => { - if (stop == undefined) { - stop = start; - start = 0; - } - return start < stop ? Array.from({ length: (stop - start + step - 1) / step }, (_, i) => start + i * step) : []; - }, - - // Unique elements, with an optional getter function - // Example: unique([1,1,2,3,4,8,1,3,8,13,42]) → [1,2,3,4,8,13,42] - unique: (array, op = x => x) => array.filter((obj, i) => array.findIndex(entry => op(obj) === op(entry)) === i), - - // Zip arrays together. If some arrays are smaller, undefined is used as a filler. - // Example: zip([1,2],[a,b,c],[true]) → [[1,a,true],[2,b,undefined],[undefined,c,undefined]] - zip: (...args) => Array.from({ length: Math.max(...args.map(arg => arg.length)) }, (_, i) => args.map(arg => arg[i])), - - // ================================================ Object helpers ================================================= - - // Create a new object by mapping the values through a function, keeping the keys. Second function can be used to pre-filter entries - // Example: mapValues({a:1,b:2,c:3}, x => x**2) → {a:1,b:4,c:9} - mapValues: (obj, fn, fn2 = () => true) => - Object.fromEntries( - Object.entries(obj) - .filter(fn2) - .map(([k, v]) => [k, fn(v)]), - ), -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/math.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/math.js deleted file mode 100644 index 133254a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/math.js +++ /dev/null @@ -1,33 +0,0 @@ -// Array of number or bigint -const max = (...values) => values.slice(1).reduce((x, y) => (x > y ? x : y), values.at(0)); -const min = (...values) => values.slice(1).reduce((x, y) => (x < y ? x : y), values.at(0)); -const sum = (...values) => values.slice(1).reduce((x, y) => x + y, values.at(0)); - -// Computes modexp without BigInt overflow for large numbers -function modExp(b, e, m) { - let result = 1n; - - // If e is a power of two, modexp can be calculated as: - // for (let result = b, i = 0; i < log2(e); i++) result = modexp(result, 2, m) - // - // Given any natural number can be written in terms of powers of 2 (i.e. binary) - // then modexp can be calculated for any e, by multiplying b**i for all i where - // binary(e)[i] is 1 (i.e. a power of two). - for (let base = b % m; e > 0n; base = base ** 2n % m) { - // Least significant bit is 1 - if (e % 2n == 1n) { - result = (result * base) % m; - } - - e /= 2n; // Binary pop - } - - return result; -} - -module.exports = { - min, - max, - sum, - modExp, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/methods.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/methods.js deleted file mode 100644 index a491897..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/methods.js +++ /dev/null @@ -1,14 +0,0 @@ -const { ethers } = require('hardhat'); - -const selector = signature => ethers.FunctionFragment.from(signature).selector; - -const interfaceId = signatures => - ethers.toBeHex( - signatures.reduce((acc, signature) => acc ^ ethers.toBigInt(selector(signature)), 0n), - 4, - ); - -module.exports = { - selector, - interfaceId, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/precompiles.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/precompiles.js deleted file mode 100644 index fb6b713..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/precompiles.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - ecRecover: '0x0000000000000000000000000000000000000001', - SHA2_256: '0x0000000000000000000000000000000000000002', - RIPEMD_160: '0x0000000000000000000000000000000000000003', - identity: '0x0000000000000000000000000000000000000004', - modexp: '0x0000000000000000000000000000000000000005', - ecAdd: '0x0000000000000000000000000000000000000006', - ecMul: '0x0000000000000000000000000000000000000007', - ecPairing: '0x0000000000000000000000000000000000000008', - blake2f: '0x0000000000000000000000000000000000000009', - pointEvaluation: '0x000000000000000000000000000000000000000a', -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/random.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/random.js deleted file mode 100644 index 6d78267..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/random.js +++ /dev/null @@ -1,24 +0,0 @@ -const { ethers } = require('hardhat'); - -const generators = { - address: () => ethers.Wallet.createRandom().address, - bytes32: () => ethers.hexlify(ethers.randomBytes(32)), - uint256: () => ethers.toBigInt(ethers.randomBytes(32)), - int256: () => ethers.toBigInt(ethers.randomBytes(32)) + ethers.MinInt256, - bytes: (length = 32) => ethers.hexlify(ethers.randomBytes(length)), - string: () => ethers.uuidV4(ethers.randomBytes(32)), -}; - -generators.address.zero = ethers.ZeroAddress; -generators.bytes32.zero = ethers.ZeroHash; -generators.uint256.zero = 0n; -generators.int256.zero = 0n; -generators.bytes.zero = '0x'; -generators.string.zero = ''; - -// alias hexBytes -> bytes -generators.hexBytes = generators.bytes; - -module.exports = { - generators, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/signers.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/signers.js deleted file mode 100644 index baa8b06..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/signers.js +++ /dev/null @@ -1,184 +0,0 @@ -const { - AbiCoder, - AbstractSigner, - Signature, - TypedDataEncoder, - assert, - assertArgument, - concat, - dataLength, - decodeBase64, - getBytes, - getBytesCopy, - hashMessage, - hexlify, - sha256, - toBeHex, - keccak256, -} = require('ethers'); -const { secp256r1 } = require('@noble/curves/p256'); -const { generateKeyPairSync, privateEncrypt } = require('crypto'); - -// Lightweight version of BaseWallet -class NonNativeSigner extends AbstractSigner { - #signingKey; - - constructor(privateKey, provider) { - super(provider); - assertArgument( - privateKey && typeof privateKey.sign === 'function', - 'invalid private key', - 'privateKey', - '[ REDACTED ]', - ); - this.#signingKey = privateKey; - } - - get signingKey() { - return this.#signingKey; - } - get privateKey() { - return this.signingKey.privateKey; - } - - async getAddress() { - throw new Error("NonNativeSigner doesn't have an address"); - } - - connect(provider) { - return new NonNativeSigner(this.#signingKey, provider); - } - - async signTransaction(/*tx: TransactionRequest*/) { - throw new Error('NonNativeSigner cannot send transactions'); - } - - async signMessage(message /*: string | Uint8Array*/) /*: Promise*/ { - return this.signingKey.sign(hashMessage(message)).serialized; - } - - async signTypedData( - domain /*: TypedDataDomain*/, - types /*: Record>*/, - value /*: Record*/, - ) /*: Promise*/ { - // Populate any ENS names - const populated = await TypedDataEncoder.resolveNames(domain, types, value, async name => { - assert(this.provider != null, 'cannot resolve ENS names without a provider', 'UNSUPPORTED_OPERATION', { - operation: 'resolveName', - info: { name }, - }); - const address = await this.provider.resolveName(name); - assert(address != null, 'unconfigured ENS name', 'UNCONFIGURED_NAME', { value: name }); - return address; - }); - - return this.signingKey.sign(TypedDataEncoder.hash(populated.domain, types, populated.value)).serialized; - } -} - -class P256SigningKey { - #privateKey; - - constructor(privateKey) { - this.#privateKey = getBytes(privateKey); - } - - static random() { - return new this(secp256r1.utils.randomPrivateKey()); - } - - get privateKey() { - return hexlify(this.#privateKey); - } - - get publicKey() { - const publicKeyBytes = secp256r1.getPublicKey(this.#privateKey, false); - return { qx: hexlify(publicKeyBytes.slice(0x01, 0x21)), qy: hexlify(publicKeyBytes.slice(0x21, 0x41)) }; - } - - sign(digest /*: BytesLike*/) /*: Signature*/ { - assertArgument(dataLength(digest) === 32, 'invalid digest length', 'digest', digest); - - const sig = secp256r1.sign(getBytesCopy(digest), getBytesCopy(this.#privateKey), { lowS: true }); - - return Signature.from({ r: toBeHex(sig.r, 32), s: toBeHex(sig.s, 32), v: sig.recovery ? 0x1c : 0x1b }); - } -} - -class RSASigningKey { - #privateKey; - #publicKey; - - constructor(keyPair) { - const jwk = keyPair.publicKey.export({ format: 'jwk' }); - this.#privateKey = keyPair.privateKey; - this.#publicKey = { e: decodeBase64(jwk.e), n: decodeBase64(jwk.n) }; - } - - static random(modulusLength = 2048) { - return new this(generateKeyPairSync('rsa', { modulusLength })); - } - - get privateKey() { - return hexlify(this.#privateKey); - } - - get publicKey() { - return { e: hexlify(this.#publicKey.e), n: hexlify(this.#publicKey.n) }; - } - - sign(digest /*: BytesLike*/) /*: Signature*/ { - assertArgument(dataLength(digest) === 32, 'invalid digest length', 'digest', digest); - // SHA256 OID = 608648016503040201 (9 bytes) | NULL = 0500 (2 bytes) (explicit) | OCTET_STRING length (0x20) = 0420 (2 bytes) - return { - serialized: hexlify( - privateEncrypt(this.#privateKey, getBytes(concat(['0x3031300d060960864801650304020105000420', digest]))), - ), - }; - } -} - -class RSASHA256SigningKey extends RSASigningKey { - sign(digest /*: BytesLike*/) /*: Signature*/ { - assertArgument(dataLength(digest) === 32, 'invalid digest length', 'digest', digest); - return super.sign(sha256(getBytes(digest))); - } -} - -class MultiERC7913SigningKey { - // this is a sorted array of objects that contain {signer, weight} - #signers; - - constructor(signers) { - assertArgument( - Array.isArray(signers) && signers.length > 0, - 'signers must be a non-empty array', - 'signers', - signers.length, - ); - - // Sorting is done at construction so that it doesn't have to be done in sign() - this.#signers = signers.sort((s1, s2) => keccak256(s1.bytes ?? s1.address) - keccak256(s2.bytes ?? s2.address)); - } - - get signers() { - return this.#signers; - } - - sign(digest /*: BytesLike*/ /*: Signature*/) { - assertArgument(dataLength(digest) === 32, 'invalid digest length', 'digest', digest); - - return { - serialized: AbiCoder.defaultAbiCoder().encode( - ['bytes[]', 'bytes[]'], - [ - this.#signers.map(signer => signer.bytes ?? signer.address), - this.#signers.map(signer => signer.signingKey.sign(digest).serialized), - ], - ), - }; - } -} - -module.exports = { NonNativeSigner, P256SigningKey, RSASigningKey, RSASHA256SigningKey, MultiERC7913SigningKey }; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/storage.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/storage.js deleted file mode 100644 index 466cbb1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/storage.js +++ /dev/null @@ -1,48 +0,0 @@ -const { ethers } = require('hardhat'); -const { setStorageAt } = require('@nomicfoundation/hardhat-network-helpers'); - -const ImplementationLabel = 'eip1967.proxy.implementation'; -const AdminLabel = 'eip1967.proxy.admin'; -const BeaconLabel = 'eip1967.proxy.beacon'; - -const erc1967Slot = label => ethers.toBeHex(ethers.toBigInt(ethers.id(label)) - 1n); -const erc7201Slot = label => ethers.toBeHex(ethers.toBigInt(ethers.keccak256(erc1967Slot(label))) & ~0xffn); -const erc7201format = contractName => `openzeppelin.storage.${contractName}`; - -const getSlot = (address, slot) => - ethers.provider.getStorage(address, ethers.isBytesLike(slot) ? slot : erc1967Slot(slot)); - -const setSlot = (address, slot, value) => - Promise.all([ - ethers.isAddressable(address) ? address.getAddress() : Promise.resolve(address), - ethers.isAddressable(value) ? value.getAddress() : Promise.resolve(value), - ]).then(([address, value]) => setStorageAt(address, ethers.isBytesLike(slot) ? slot : erc1967Slot(slot), value)); - -const getAddressInSlot = (address, slot) => - getSlot(address, slot).then(slotValue => ethers.AbiCoder.defaultAbiCoder().decode(['address'], slotValue)[0]); - -const upgradeableSlot = (contractName, offset) => { - try { - // Try to get the artifact paths, will throw if it doesn't exist - artifacts._getArtifactPathSync(`${contractName}Upgradeable`); - return offset + ethers.toBigInt(erc7201Slot(erc7201format(contractName))); - } catch { - return offset; - } -}; - -module.exports = { - ImplementationLabel, - AdminLabel, - BeaconLabel, - ImplementationSlot: erc1967Slot(ImplementationLabel), - AdminSlot: erc1967Slot(AdminLabel), - BeaconSlot: erc1967Slot(BeaconLabel), - erc1967Slot, - erc7201Slot, - erc7201format, - setSlot, - getSlot, - getAddressInSlot, - upgradeableSlot, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/strings.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/strings.js deleted file mode 100644 index 4f34099..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/strings.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - // Capitalize the first char of a string - // Example: capitalize('uint256') → 'Uint256' - capitalize: str => str.charAt(0).toUpperCase() + str.slice(1), -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/time.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/time.js deleted file mode 100644 index 574170c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/time.js +++ /dev/null @@ -1,33 +0,0 @@ -const { ethers } = require('hardhat'); -const { time, mine, mineUpTo } = require('@nomicfoundation/hardhat-network-helpers'); -const { mapValues } = require('./iterate'); - -const clock = { - blocknumber: () => time.latestBlock().then(ethers.toBigInt), - timestamp: () => time.latest().then(ethers.toBigInt), -}; -const clockFromReceipt = { - blocknumber: receipt => Promise.resolve(receipt).then(({ blockNumber }) => ethers.toBigInt(blockNumber)), - timestamp: receipt => - Promise.resolve(receipt) - .then(({ blockNumber }) => ethers.provider.getBlock(blockNumber)) - .then(({ timestamp }) => ethers.toBigInt(timestamp)), -}; -const increaseBy = { - blockNumber: mine, - timestamp: (delay, mine = true) => - time.latest().then(clock => increaseTo.timestamp(clock + ethers.toNumber(delay), mine)), -}; -const increaseTo = { - blocknumber: mineUpTo, - timestamp: (to, mine = true) => (mine ? time.increaseTo(to) : time.setNextBlockTimestamp(to)), -}; -const duration = mapValues(time.duration, fn => n => ethers.toBigInt(fn(ethers.toNumber(n)))); - -module.exports = { - clock, - clockFromReceipt, - increaseBy, - increaseTo, - duration, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/txpool.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/txpool.js deleted file mode 100644 index f01327b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/helpers/txpool.js +++ /dev/null @@ -1,29 +0,0 @@ -const { network } = require('hardhat'); -const { expect } = require('chai'); -const { mine } = require('@nomicfoundation/hardhat-network-helpers'); - -const { unique } = require('./iterate'); - -async function batchInBlock(txs) { - try { - // disable auto-mining - await network.provider.send('evm_setAutomine', [false]); - // send all transactions - const responses = await Promise.all(txs.map(fn => fn())); - // mine one block - await mine(); - // fetch receipts - const receipts = await Promise.all(responses.map(response => response.wait())); - // Sanity check, all tx should be in the same block - expect(unique(receipts.map(receipt => receipt.blockNumber))).to.have.lengthOf(1); - // return responses - return receipts; - } finally { - // enable auto-mining - await network.provider.send('evm_setAutomine', [true]); - } -} - -module.exports = { - batchInBlock, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js deleted file mode 100644 index ce13996..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js +++ /dev/null @@ -1,133 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { impersonate } = require('../helpers/account'); -const { getDomain, ForwardRequest } = require('../helpers/eip712'); -const { MAX_UINT48 } = require('../helpers/constants'); - -const { shouldBehaveLikeRegularContext } = require('../utils/Context.behavior'); - -async function fixture() { - const [sender, other] = await ethers.getSigners(); - - const forwarder = await ethers.deployContract('ERC2771Forwarder', ['ERC2771Forwarder']); - const forwarderAsSigner = await impersonate(forwarder.target); - const context = await ethers.deployContract('ERC2771ContextMock', [forwarder]); - const domain = await getDomain(forwarder); - const types = { ForwardRequest }; - - return { sender, other, forwarder, forwarderAsSigner, context, domain, types }; -} - -describe('ERC2771Context', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('recognize trusted forwarder', async function () { - expect(await this.context.isTrustedForwarder(this.forwarder)).to.be.true; - }); - - it('returns the trusted forwarder', async function () { - expect(await this.context.trustedForwarder()).to.equal(this.forwarder); - }); - - describe('when called directly', function () { - shouldBehaveLikeRegularContext(); - }); - - describe('when receiving a relayed call', function () { - describe('msgSender', function () { - it('returns the relayed transaction original sender', async function () { - const nonce = await this.forwarder.nonces(this.sender); - const data = this.context.interface.encodeFunctionData('msgSender'); - - const req = { - from: await this.sender.getAddress(), - to: await this.context.getAddress(), - value: 0n, - data, - gas: 100000n, - nonce, - deadline: MAX_UINT48, - }; - - req.signature = await this.sender.signTypedData(this.domain, this.types, req); - - expect(await this.forwarder.verify(req)).to.be.true; - - await expect(this.forwarder.execute(req)).to.emit(this.context, 'Sender').withArgs(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 so `this.forwarderAsSigner` is used instead. - await expect(this.context.connect(this.forwarderAsSigner).msgSender()) - .to.emit(this.context, 'Sender') - .withArgs(this.forwarder); - }); - }); - - describe('msgData', function () { - it('returns the relayed transaction original data', async function () { - const args = [42n, 'OpenZeppelin']; - - const nonce = await this.forwarder.nonces(this.sender); - const data = this.context.interface.encodeFunctionData('msgData', args); - - const req = { - from: await this.sender.getAddress(), - to: await this.context.getAddress(), - value: 0n, - data, - gas: 100000n, - nonce, - deadline: MAX_UINT48, - }; - - req.signature = this.sender.signTypedData(this.domain, this.types, req); - - expect(await this.forwarder.verify(req)).to.be.true; - - await expect(this.forwarder.execute(req)) - .to.emit(this.context, 'Data') - .withArgs(data, ...args); - }); - }); - - it('returns the full original data when calldata length is less than 20 bytes (address length)', async function () { - const data = this.context.interface.encodeFunctionData('msgDataShort'); - - // The forwarder doesn't produce calls with calldata length less than 20 bytes so `this.forwarderAsSigner` is used instead. - await expect(await this.context.connect(this.forwarderAsSigner).msgDataShort()) - .to.emit(this.context, 'DataShort') - .withArgs(data); - }); - }); - - it('multicall poison attack', async function () { - const nonce = await this.forwarder.nonces(this.sender); - const data = this.context.interface.encodeFunctionData('multicall', [ - [ - // poisoned call to 'msgSender()' - ethers.concat([this.context.interface.encodeFunctionData('msgSender'), this.other.address]), - ], - ]); - - const req = { - from: await this.sender.getAddress(), - to: await this.context.getAddress(), - value: 0n, - data, - gas: 100000n, - nonce, - deadline: MAX_UINT48, - }; - - req.signature = await this.sender.signTypedData(this.domain, this.types, req); - - expect(await this.forwarder.verify(req)).to.be.true; - - await expect(this.forwarder.execute(req)).to.emit(this.context, 'Sender').withArgs(this.sender); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.t.sol deleted file mode 100644 index 605ae62..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.t.sol +++ /dev/null @@ -1,279 +0,0 @@ -// 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"; -import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; - -enum TamperType { - FROM, - TO, - VALUE, - DATA, - SIGNATURE -} - -contract ERC2771ForwarderMock is ERC2771Forwarder { - constructor(string memory name) ERC2771Forwarder(name) {} - - function forwardRequestStructHash( - ERC2771Forwarder.ForwardRequestData calldata request, - uint256 nonce - ) external view returns (bytes32) { - return - _hashTypedDataV4( - keccak256( - abi.encode( - _FORWARD_REQUEST_TYPEHASH, - request.from, - request.to, - request.value, - request.gas, - nonce, - request.deadline, - keccak256(request.data) - ) - ) - ); - } -} - -contract ERC2771ForwarderTest is Test { - using ECDSA for bytes32; - - ERC2771ForwarderMock internal _erc2771Forwarder; - CallReceiverMockTrustingForwarder internal _receiver; - - uint256 internal _signerPrivateKey = 0xA11CE; - address internal _signer = vm.addr(_signerPrivateKey); - - uint256 internal constant _MAX_ETHER = 10_000_000; // To avoid overflow - - function setUp() public { - _erc2771Forwarder = new ERC2771ForwarderMock("ERC2771Forwarder"); - _receiver = new CallReceiverMockTrustingForwarder(address(_erc2771Forwarder)); - } - - // Forge a new ForwardRequestData - function _forgeRequestData() private view returns (ERC2771Forwarder.ForwardRequestData memory) { - return - _forgeRequestData({ - value: 0, - deadline: uint48(block.timestamp + 1), - data: abi.encodeCall(CallReceiverMock.mockFunction, ()) - }); - } - - function _forgeRequestData( - uint256 value, - uint48 deadline, - bytes memory data - ) private view returns (ERC2771Forwarder.ForwardRequestData memory) { - return - ERC2771Forwarder.ForwardRequestData({ - from: _signer, - to: address(_receiver), - value: value, - gas: 30000, - deadline: deadline, - data: data, - signature: "" - }); - } - - // Sign a ForwardRequestData (in place) for a given nonce. Also returns it for convenience. - function _signRequestData( - ERC2771Forwarder.ForwardRequestData memory request, - uint256 nonce - ) private view returns (ERC2771Forwarder.ForwardRequestData memory) { - bytes32 digest = _erc2771Forwarder.forwardRequestStructHash(request, nonce); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_signerPrivateKey, digest); - request.signature = abi.encodePacked(r, s, v); - return request; - } - - // Tamper a ForwardRequestData (in place). Also returns it for convenience. - function _tamperRequestData( - ERC2771Forwarder.ForwardRequestData memory request, - TamperType tamper - ) private returns (ERC2771Forwarder.ForwardRequestData memory) { - if (tamper == TamperType.FROM) request.from = vm.randomAddress(); - else if (tamper == TamperType.TO) request.to = vm.randomAddress(); - else if (tamper == TamperType.VALUE) request.value = vm.randomUint(); - else if (tamper == TamperType.DATA) request.data = vm.randomBytes(4); - else if (tamper == TamperType.SIGNATURE) request.signature = vm.randomBytes(65); - - return request; - } - - // Predict the revert error for a tampered request, and expect it is emitted. - function _tamperedExpectRevert( - ERC2771Forwarder.ForwardRequestData memory request, - TamperType tamper, - uint256 nonce - ) private returns (ERC2771Forwarder.ForwardRequestData memory) { - if (tamper == TamperType.FROM) nonce = _erc2771Forwarder.nonces(request.from); - - // predict revert - if (tamper == TamperType.TO) { - vm.expectRevert( - abi.encodeWithSelector( - ERC2771Forwarder.ERC2771UntrustfulTarget.selector, - request.to, - address(_erc2771Forwarder) - ) - ); - } else { - (address recovered, , ) = _erc2771Forwarder.forwardRequestStructHash(request, nonce).tryRecover( - request.signature - ); - vm.expectRevert( - abi.encodeWithSelector(ERC2771Forwarder.ERC2771ForwarderInvalidSigner.selector, recovered, request.from) - ); - } - return request; - } - - function testExecuteAvoidsETHStuck(uint256 initialBalance, uint256 value, bool targetReverts) public { - initialBalance = bound(initialBalance, 0, _MAX_ETHER); - value = bound(value, 0, _MAX_ETHER); - - // create and sign request - ERC2771Forwarder.ForwardRequestData memory request = _forgeRequestData({ - value: value, - deadline: uint48(block.timestamp + 1), - data: targetReverts - ? abi.encodeCall(CallReceiverMock.mockFunctionRevertsNoReason, ()) - : abi.encodeCall(CallReceiverMock.mockFunction, ()) - }); - _signRequestData(request, _erc2771Forwarder.nonces(_signer)); - - vm.deal(address(_erc2771Forwarder), initialBalance); - vm.deal(address(this), request.value); - - if (targetReverts) vm.expectRevert(); - _erc2771Forwarder.execute{value: value}(request); - - assertEq(address(_erc2771Forwarder).balance, initialBalance); - } - - function testExecuteBatchAvoidsETHStuck(uint256 initialBalance, uint256 batchSize, uint256 value) public { - uint256 seed = uint256(keccak256(abi.encodePacked(initialBalance, batchSize, value))); - - batchSize = bound(batchSize, 1, 10); - initialBalance = bound(initialBalance, 0, _MAX_ETHER); - value = bound(value, 0, _MAX_ETHER); - - address refundReceiver = address(0xebe); - uint256 refundExpected = 0; - uint256 nonce = _erc2771Forwarder.nonces(_signer); - - // create an array of signed requests (that may fail) - ERC2771Forwarder.ForwardRequestData[] memory requests = new ERC2771Forwarder.ForwardRequestData[](batchSize); - for (uint256 i = 0; i < batchSize; ++i) { - bool failure = (seed >> i) & 0x1 == 0x1; - - requests[i] = _forgeRequestData({ - value: value, - deadline: uint48(block.timestamp + 1), - data: failure - ? abi.encodeCall(CallReceiverMock.mockFunctionRevertsNoReason, ()) - : abi.encodeCall(CallReceiverMock.mockFunction, ()) - }); - _signRequestData(requests[i], nonce + i); - - refundExpected += SafeCast.toUint(failure) * value; - } - - // distribute ether - vm.deal(address(_erc2771Forwarder), initialBalance); - vm.deal(address(this), value * batchSize); - - // execute batch - _erc2771Forwarder.executeBatch{value: value * batchSize}(requests, payable(refundReceiver)); - - // check balances - assertEq(address(_erc2771Forwarder).balance, initialBalance); - assertEq(refundReceiver.balance, refundExpected); - } - - function testVerifyTamperedValues(uint8 _tamper) public { - TamperType tamper = _asTamper(_tamper); - - // create request, sign, tamper - ERC2771Forwarder.ForwardRequestData memory request = _forgeRequestData(); - _signRequestData(request, 0); - _tamperRequestData(request, tamper); - - // should not pass verification - assertFalse(_erc2771Forwarder.verify(request)); - } - - function testExecuteTamperedValues(uint8 _tamper) public { - TamperType tamper = _asTamper(_tamper); - - // create request, sign, tamper, expect execution revert - ERC2771Forwarder.ForwardRequestData memory request = _forgeRequestData(); - _signRequestData(request, 0); - _tamperRequestData(request, tamper); - _tamperedExpectRevert(request, tamper, 0); - - vm.deal(address(this), request.value); - _erc2771Forwarder.execute{value: request.value}(request); - } - - function testExecuteBatchTamperedValuesZeroReceiver(uint8 _tamper) public { - TamperType tamper = _asTamper(_tamper); - uint256 nonce = _erc2771Forwarder.nonces(_signer); - - // create an array of signed requests - ERC2771Forwarder.ForwardRequestData[] memory requests = new ERC2771Forwarder.ForwardRequestData[](3); - for (uint256 i = 0; i < requests.length; ++i) { - requests[i] = _forgeRequestData({ - value: 0, - deadline: uint48(block.timestamp + 1), - data: abi.encodeCall(CallReceiverMock.mockFunction, ()) - }); - _signRequestData(requests[i], nonce + i); - } - - // tamper with request[1] and expect execution revert - _tamperRequestData(requests[1], tamper); - _tamperedExpectRevert(requests[1], tamper, nonce + 1); - - vm.deal(address(this), requests[1].value); - _erc2771Forwarder.executeBatch{value: requests[1].value}(requests, payable(address(0))); - } - - function testExecuteBatchTamperedValues(uint8 _tamper) public { - TamperType tamper = _asTamper(_tamper); - uint256 nonce = _erc2771Forwarder.nonces(_signer); - - // create an array of signed requests - ERC2771Forwarder.ForwardRequestData[] memory requests = new ERC2771Forwarder.ForwardRequestData[](3); - for (uint256 i = 0; i < requests.length; ++i) { - requests[i] = _forgeRequestData({ - value: 0, - deadline: uint48(block.timestamp + 1), - data: abi.encodeCall(CallReceiverMock.mockFunction, ()) - }); - _signRequestData(requests[i], nonce + i); - } - - // tamper with request[1] - _tamperRequestData(requests[1], tamper); - - // should not revert - vm.expectCall(address(_receiver), abi.encodeCall(CallReceiverMock.mockFunction, ()), 1); - - vm.deal(address(this), requests[1].value); - _erc2771Forwarder.executeBatch{value: requests[1].value}(requests, payable(address(0xebe))); - } - - function _asTamper(uint8 _tamper) private pure returns (TamperType) { - return TamperType(bound(_tamper, uint8(TamperType.FROM), uint8(TamperType.SIGNATURE))); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.test.js deleted file mode 100644 index 07682c1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.test.js +++ /dev/null @@ -1,384 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain, ForwardRequest } = require('../helpers/eip712'); -const { sum } = require('../helpers/math'); -const time = require('../helpers/time'); - -async function fixture() { - const [sender, refundReceiver, another, ...accounts] = await ethers.getSigners(); - - const forwarder = await ethers.deployContract('ERC2771Forwarder', ['ERC2771Forwarder']); - const receiver = await ethers.deployContract('CallReceiverMockTrustingForwarder', [forwarder]); - const domain = await getDomain(forwarder); - const types = { ForwardRequest }; - - const forgeRequest = async (override = {}, signer = sender) => { - const req = { - from: await signer.getAddress(), - to: await receiver.getAddress(), - value: 0n, - data: receiver.interface.encodeFunctionData('mockFunction'), - gas: 100000n, - deadline: (await time.clock.timestamp()) + 60n, - nonce: await forwarder.nonces(sender), - ...override, - }; - req.signature = await signer.signTypedData(domain, types, req); - return req; - }; - - const estimateRequest = request => - ethers.provider.estimateGas({ - from: forwarder, - to: request.to, - data: ethers.solidityPacked(['bytes', 'address'], [request.data, request.from]), - value: request.value, - gasLimit: request.gas, - }); - - return { - sender, - refundReceiver, - another, - accounts, - forwarder, - receiver, - forgeRequest, - estimateRequest, - domain, - types, - }; -} - -describe('ERC2771Forwarder', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('verify', function () { - describe('with valid signature', function () { - it('returns true without altering the nonce', async function () { - const request = await this.forgeRequest(); - expect(await this.forwarder.nonces(request.from)).to.equal(request.nonce); - expect(await this.forwarder.verify(request)).to.be.true; - expect(await this.forwarder.nonces(request.from)).to.equal(request.nonce); - }); - }); - - describe('with tampered values', function () { - it('returns false with valid signature for non-current nonce', async function () { - const request = await this.forgeRequest({ nonce: 1337n }); - expect(await this.forwarder.verify(request)).to.be.false; - }); - - it('returns false with valid signature for expired deadline', async function () { - const request = await this.forgeRequest({ deadline: (await time.clock.timestamp()) - 1n }); - expect(await this.forwarder.verify(request)).to.be.false; - }); - }); - }); - - describe('execute', function () { - describe('with valid requests', function () { - it('emits an event and consumes nonce for a successful request', async function () { - const request = await this.forgeRequest(); - - expect(await this.forwarder.nonces(request.from)).to.equal(request.nonce); - - await expect(this.forwarder.execute(request)) - .to.emit(this.receiver, 'MockFunctionCalled') - .to.emit(this.forwarder, 'ExecutedForwardRequest') - .withArgs(request.from, request.nonce, true); - - expect(await this.forwarder.nonces(request.from)).to.equal(request.nonce + 1n); - }); - - it('reverts with an unsuccessful request', async function () { - const request = await this.forgeRequest({ - data: this.receiver.interface.encodeFunctionData('mockFunctionRevertsNoReason'), - }); - - await expect(this.forwarder.execute(request)).to.be.revertedWithCustomError(this.forwarder, 'FailedCall'); - }); - }); - - describe('with tampered request', function () { - it('reverts with valid signature for non-current nonce', async function () { - const request = await this.forgeRequest(); - - // consume nonce - await this.forwarder.execute(request); - - // nonce has changed - await expect(this.forwarder.execute(request)) - .to.be.revertedWithCustomError(this.forwarder, 'ERC2771ForwarderInvalidSigner') - .withArgs( - ethers.verifyTypedData( - this.domain, - this.types, - { ...request, nonce: request.nonce + 1n }, - request.signature, - ), - request.from, - ); - }); - - it('reverts with valid signature for expired deadline', async function () { - const request = await this.forgeRequest({ deadline: (await time.clock.timestamp()) - 1n }); - - await expect(this.forwarder.execute(request)) - .to.be.revertedWithCustomError(this.forwarder, 'ERC2771ForwarderExpiredRequest') - .withArgs(request.deadline); - }); - - it('reverts with valid signature but mismatched value', async function () { - const request = await this.forgeRequest({ value: 100n }); - - await expect(this.forwarder.execute(request)) - .to.be.revertedWithCustomError(this.forwarder, 'ERC2771ForwarderMismatchedValue') - .withArgs(request.value, 0n); - }); - }); - - it('bubbles out of gas', async function () { - const request = await this.forgeRequest({ - data: this.receiver.interface.encodeFunctionData('mockFunctionOutOfGas'), - gas: 1_000_000n, - }); - - const gasLimit = 100_000n; - await expect(this.forwarder.execute(request, { gasLimit })).to.be.revertedWithoutReason(); - - const { gasUsed } = await ethers.provider - .getBlock('latest') - .then(block => block.getTransaction(0)) - .then(tx => ethers.provider.getTransactionReceipt(tx.hash)); - - expect(gasUsed).to.equal(gasLimit); - }); - - it('bubbles out of gas forced by the relayer', async function () { - const request = await this.forgeRequest(); - - // 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(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 gasLimit = estimate + 10_000n; - - // The subcall out of gas should be caught by the contract and then bubbled up consuming - // the available gas with an `invalid` opcode. - await expect(this.forwarder.execute(request, { gasLimit })).to.be.revertedWithoutReason(); - - const { gasUsed } = await ethers.provider - .getBlock('latest') - .then(block => block.getTransaction(0)) - .then(tx => ethers.provider.getTransactionReceipt(tx.hash)); - - // We assert that indeed the gas was totally consumed. - expect(gasUsed).to.equal(gasLimit); - }); - }); - - describe('executeBatch', function () { - const requestsValue = requests => sum(...requests.map(request => request.value)); - const requestCount = 3; - const idx = 1; // index that will be tampered with - - beforeEach(async function () { - this.forgeRequests = override => - Promise.all(this.accounts.slice(0, requestCount).map(signer => this.forgeRequest(override, signer))); - this.requests = await this.forgeRequests({ value: 10n }); - this.value = requestsValue(this.requests); - }); - - describe('with valid requests', function () { - it('sanity', async function () { - for (const request of this.requests) { - expect(await this.forwarder.verify(request)).to.be.true; - } - }); - - it('emits events', async function () { - const receipt = this.forwarder.executeBatch(this.requests, this.another, { value: this.value }); - - for (const request of this.requests) { - await expect(receipt) - .to.emit(this.receiver, 'MockFunctionCalled') - .to.emit(this.forwarder, 'ExecutedForwardRequest') - .withArgs(request.from, request.nonce, true); - } - }); - - it('increase nonces', async function () { - await this.forwarder.executeBatch(this.requests, this.another, { value: this.value }); - - for (const request of this.requests) { - expect(await this.forwarder.nonces(request.from)).to.equal(request.nonce + 1n); - } - }); - }); - - describe('with tampered requests', function () { - it('reverts with mismatched value', async function () { - // tamper value of one of the request + resign - this.requests[idx] = await this.forgeRequest({ value: 100n }, this.accounts[1]); - - await expect(this.forwarder.executeBatch(this.requests, this.another, { value: this.value })) - .to.be.revertedWithCustomError(this.forwarder, 'ERC2771ForwarderMismatchedValue') - .withArgs(requestsValue(this.requests), this.value); - }); - - describe('when the refund receiver is the zero address', function () { - beforeEach(function () { - this.refundReceiver = ethers.ZeroAddress; - }); - - it('reverts with at least one valid signature for non-current nonce', async function () { - // Execute first a request - await this.forwarder.execute(this.requests[idx], { value: this.requests[idx].value }); - - // And then fail due to an already used nonce - await expect(this.forwarder.executeBatch(this.requests, this.refundReceiver, { value: this.value })) - .to.be.revertedWithCustomError(this.forwarder, 'ERC2771ForwarderInvalidSigner') - .withArgs( - ethers.verifyTypedData( - this.domain, - this.types, - { ...this.requests[idx], nonce: this.requests[idx].nonce + 1n }, - this.requests[idx].signature, - ), - this.requests[idx].from, - ); - }); - - it('reverts with at least one valid signature for expired deadline', async function () { - this.requests[idx] = await this.forgeRequest( - { ...this.requests[idx], deadline: (await time.clock.timestamp()) - 1n }, - this.accounts[1], - ); - - await expect(this.forwarder.executeBatch(this.requests, this.refundReceiver, { value: this.amount })) - .to.be.revertedWithCustomError(this.forwarder, 'ERC2771ForwarderExpiredRequest') - .withArgs(this.requests[idx].deadline); - }); - }); - - describe('when the refund receiver is a known address', function () { - beforeEach(async function () { - this.initialRefundReceiverBalance = await ethers.provider.getBalance(this.refundReceiver); - this.initialTamperedRequestNonce = await this.forwarder.nonces(this.requests[idx].from); - }); - - it('ignores a request with a valid signature for non-current nonce', async function () { - // Execute first a request - await this.forwarder.execute(this.requests[idx], { value: this.requests[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 events = await this.forwarder - .executeBatch(this.requests, this.refundReceiver, { value: this.value }) - .then(tx => tx.wait()) - .then(receipt => - receipt.logs.filter( - log => log?.fragment?.type == 'event' && log?.fragment?.name == 'ExecutedForwardRequest', - ), - ); - - expect(events).to.have.lengthOf(this.requests.length - 1); - }); - - it('ignores a request with a valid signature for expired deadline', async function () { - this.requests[idx] = await this.forgeRequest( - { ...this.requests[idx], deadline: (await time.clock.timestamp()) - 1n }, - this.accounts[1], - ); - - const events = await this.forwarder - .executeBatch(this.requests, this.refundReceiver, { value: this.value }) - .then(tx => tx.wait()) - .then(receipt => - receipt.logs.filter( - log => log?.fragment?.type == 'event' && log?.fragment?.name == 'ExecutedForwardRequest', - ), - ); - - expect(events).to.have.lengthOf(this.requests.length - 1); - }); - - afterEach(async function () { - // The invalid request value was refunded - expect(await ethers.provider.getBalance(this.refundReceiver)).to.equal( - this.initialRefundReceiverBalance + this.requests[idx].value, - ); - - // The invalid request from's nonce was not incremented - expect(await this.forwarder.nonces(this.requests[idx].from)).to.equal(this.initialTamperedRequestNonce); - }); - }); - - it('bubbles out of gas', async function () { - this.requests[idx] = await this.forgeRequest({ - data: this.receiver.interface.encodeFunctionData('mockFunctionOutOfGas'), - gas: 1_000_000n, - }); - - const gasLimit = 300_000n; - await expect( - this.forwarder.executeBatch(this.requests, ethers.ZeroAddress, { - gasLimit, - value: requestsValue(this.requests), - }), - ).to.be.revertedWithoutReason(); - - const { gasUsed } = await ethers.provider - .getBlock('latest') - .then(block => block.getTransaction(0)) - .then(tx => ethers.provider.getTransactionReceipt(tx.hash)); - - expect(gasUsed).to.equal(gasLimit); - }); - - 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 Promise.all(this.requests.slice(0, idx + 1).map(this.estimateRequest)).then(gas => - sum(...gas), - ); - - // 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 gasLimit = estimate + 10_000n; - - // The subcall out of gas should be caught by the contract and then bubbled up consuming - // the available gas with an `invalid` opcode. - await expect( - this.forwarder.executeBatch(this.requests, ethers.ZeroAddress, { - gasLimit, - value: requestsValue(this.requests), - }), - ).to.be.revertedWithoutReason(); - - const { gasUsed } = await ethers.provider - .getBlock('latest') - .then(block => block.getTransaction(0)) - .then(tx => ethers.provider.getTransactionReceipt(tx.hash)); - - // We assert that indeed the gas was totally consumed. - expect(gasUsed).to.equal(gasLimit); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js deleted file mode 100644 index dcc6206..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js +++ /dev/null @@ -1,160 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); - -module.exports = function shouldBehaveLikeClone() { - const assertProxyInitialization = function ({ value, balance }) { - it('initializes the proxy', async function () { - const dummy = await ethers.getContractAt('DummyImplementation', this.proxy); - expect(await dummy.value()).to.equal(value); - }); - - it('has expected balance', async function () { - expect(await ethers.provider.getBalance(this.proxy)).to.equal(balance); - }); - }; - - describe('construct with value', function () { - const value = 10n; - - it('factory has enough balance', async function () { - await this.deployer.sendTransaction({ to: this.factory, value }); - - const instance = await this.createClone({ deployValue: value }); - await expect(instance.deploymentTransaction()).to.changeEtherBalances([this.factory, instance], [-value, value]); - - expect(await ethers.provider.getBalance(instance)).to.equal(value); - }); - - it('factory does not have enough balance', async function () { - await expect(this.createClone({ deployValue: value })) - .to.be.revertedWithCustomError(this.factory, 'InsufficientBalance') - .withArgs(0n, value); - }); - }); - - describe('initialization without parameters', function () { - describe('non payable', function () { - const expectedInitializedValue = 10n; - - beforeEach(async function () { - this.initializeData = await this.implementation.interface.encodeFunctionData('initializeNonPayable'); - }); - - describe('when not sending balance', function () { - beforeEach('creating proxy', async function () { - this.proxy = await this.createClone({ initData: this.initializeData }); - }); - - assertProxyInitialization({ - value: expectedInitializedValue, - balance: 0, - }); - }); - - describe('when sending some balance', function () { - const value = 10n ** 6n; - - it('reverts', async function () { - await expect(this.createClone({ initData: this.initializeData, initValue: value })).to.be.reverted; - }); - }); - }); - - describe('payable', function () { - const expectedInitializedValue = 100n; - - beforeEach(async function () { - this.initializeData = await this.implementation.interface.encodeFunctionData('initializePayable'); - }); - - describe('when not sending balance', function () { - beforeEach('creating proxy', async function () { - this.proxy = await this.createClone({ initData: this.initializeData }); - }); - - assertProxyInitialization({ - value: expectedInitializedValue, - balance: 0, - }); - }); - - describe('when sending some balance', function () { - const value = 10n ** 6n; - - beforeEach('creating proxy', async function () { - this.proxy = await this.createClone({ initData: this.initializeData, initValue: value }); - }); - - assertProxyInitialization({ - value: expectedInitializedValue, - balance: value, - }); - }); - }); - }); - - describe('initialization with parameters', function () { - describe('non payable', function () { - const expectedInitializedValue = 10n; - - beforeEach(async function () { - this.initializeData = await this.implementation.interface.encodeFunctionData('initializeNonPayableWithValue', [ - expectedInitializedValue, - ]); - }); - - describe('when not sending balance', function () { - beforeEach('creating proxy', async function () { - this.proxy = await this.createClone({ initData: this.initializeData }); - }); - - assertProxyInitialization({ - value: expectedInitializedValue, - balance: 0, - }); - }); - - describe('when sending some balance', function () { - const value = 10n ** 6n; - - it('reverts', async function () { - await expect(this.createClone({ initData: this.initializeData, initValue: value })).to.be.reverted; - }); - }); - }); - - describe('payable', function () { - const expectedInitializedValue = 42n; - - beforeEach(function () { - this.initializeData = this.implementation.interface.encodeFunctionData('initializePayableWithValue', [ - expectedInitializedValue, - ]); - }); - - describe('when not sending balance', function () { - beforeEach('creating proxy', async function () { - this.proxy = await this.createClone({ initData: this.initializeData }); - }); - - assertProxyInitialization({ - value: expectedInitializedValue, - balance: 0, - }); - }); - - describe('when sending some balance', function () { - const value = 10n ** 6n; - - beforeEach('creating proxy', async function () { - this.proxy = await this.createClone({ initData: this.initializeData, initValue: value }); - }); - - assertProxyInitialization({ - value: expectedInitializedValue, - balance: value, - }); - }); - }); - }); -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.t.sol deleted file mode 100644 index 5da6d56..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.t.sol +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; -import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; - -contract ClonesTest is Test { - function getNumber() external pure returns (uint256) { - return 42; - } - - function testSymbolicPredictDeterministicAddressSpillage(address implementation, bytes32 salt) public view { - address predicted = Clones.predictDeterministicAddress(implementation, salt); - bytes32 spillage; - assembly ("memory-safe") { - spillage := and(predicted, 0xffffffffffffffffffffffff0000000000000000000000000000000000000000) - } - assertEq(spillage, bytes32(0)); - } - - function testSymbolicPredictDeterministicAddressWithImmutableArgsSpillage( - address implementation, - bytes32 salt, - bytes memory args - ) public view { - vm.assume(args.length < 0xbfd3); - - address predicted = Clones.predictDeterministicAddressWithImmutableArgs(implementation, args, salt); - bytes32 spillage; - /// @solidity memory-safe-assembly - assembly { - spillage := and(predicted, 0xffffffffffffffffffffffff0000000000000000000000000000000000000000) - } - assertEq(spillage, bytes32(0)); - } - - function testCloneDirty() external { - address cloneClean = Clones.clone(address(this)); - address cloneDirty = Clones.clone(_dirty(address(this))); - - // both clones have the same code - assertEq(cloneClean.code, cloneDirty.code); - - // both clones behave as expected - assertEq(ClonesTest(cloneClean).getNumber(), this.getNumber()); - assertEq(ClonesTest(cloneDirty).getNumber(), this.getNumber()); - } - - function testCloneDeterministicDirty(bytes32 salt) external { - address cloneClean = Clones.cloneDeterministic(address(this), salt); - address cloneDirty = Clones.cloneDeterministic(_dirty(address(this)), ~salt); - - // both clones have the same code - assertEq(cloneClean.code, cloneDirty.code); - - // both clones behave as expected - assertEq(ClonesTest(cloneClean).getNumber(), this.getNumber()); - assertEq(ClonesTest(cloneDirty).getNumber(), this.getNumber()); - } - - function testPredictDeterministicAddressDirty(bytes32 salt) external view { - address predictClean = Clones.predictDeterministicAddress(address(this), salt); - address predictDirty = Clones.predictDeterministicAddress(_dirty(address(this)), salt); - - //prediction should be similar - assertEq(predictClean, predictDirty); - } - - function testFetchCloneArgs(bytes memory args, bytes32 salt) external { - vm.assume(args.length < 0xbfd3); - - address instance1 = Clones.cloneWithImmutableArgs(address(this), args); - address instance2 = Clones.cloneDeterministicWithImmutableArgs(address(this), args, salt); - - // both clones have the same code - assertEq(instance1.code, instance2.code); - - // both clones behave as expected and args can be fetched - assertEq(ClonesTest(instance1).getNumber(), this.getNumber()); - assertEq(ClonesTest(instance2).getNumber(), this.getNumber()); - assertEq(Clones.fetchCloneArgs(instance1), args); - assertEq(Clones.fetchCloneArgs(instance2), args); - } - - function _dirty(address input) private pure returns (address output) { - assembly ("memory-safe") { - output := or(input, shl(160, not(0))) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.test.js deleted file mode 100644 index 93bcfba..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Clones.test.js +++ /dev/null @@ -1,177 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { generators } = require('../helpers/random'); - -const shouldBehaveLikeClone = require('./Clones.behaviour'); - -const cloneInitCode = (instance, args = undefined) => - args - ? ethers.concat([ - '0x61', - ethers.toBeHex(0x2d + ethers.getBytes(args).length, 2), - '0x3d81600a3d39f3363d3d373d3d3d363d73', - instance.target ?? instance.address ?? instance, - '0x5af43d82803e903d91602b57fd5bf3', - args, - ]) - : ethers.concat([ - '0x3d602d80600a3d3981f3363d3d373d3d3d363d73', - instance.target ?? instance.address ?? instance, - '0x5af43d82803e903d91602b57fd5bf3', - ]); - -async function fixture() { - const [deployer] = await ethers.getSigners(); - - const factory = await ethers.deployContract('$Clones'); - const implementation = await ethers.deployContract('DummyImplementation'); - - const newClone = - args => - async (opts = {}) => { - const clone = await ( - args - ? factory.$cloneWithImmutableArgs.staticCall(implementation, args) - : factory.$clone.staticCall(implementation) - ).then(address => implementation.attach(address)); - const tx = await (args - ? opts.deployValue - ? factory.$cloneWithImmutableArgs(implementation, args, ethers.Typed.uint256(opts.deployValue)) - : factory.$cloneWithImmutableArgs(implementation, args) - : opts.deployValue - ? factory.$clone(implementation, ethers.Typed.uint256(opts.deployValue)) - : factory.$clone(implementation)); - if (opts.initData || opts.initValue) { - await deployer.sendTransaction({ to: clone, value: opts.initValue ?? 0n, data: opts.initData ?? '0x' }); - } - return Object.assign(clone, { deploymentTransaction: () => tx }); - }; - - const newCloneDeterministic = - args => - async (opts = {}) => { - const salt = opts.salt ?? ethers.randomBytes(32); - const clone = await ( - args - ? factory.$cloneDeterministicWithImmutableArgs.staticCall(implementation, args, salt) - : factory.$cloneDeterministic.staticCall(implementation, salt) - ).then(address => implementation.attach(address)); - const tx = await (args - ? opts.deployValue - ? factory.$cloneDeterministicWithImmutableArgs( - implementation, - args, - salt, - ethers.Typed.uint256(opts.deployValue), - ) - : factory.$cloneDeterministicWithImmutableArgs(implementation, args, salt) - : opts.deployValue - ? factory.$cloneDeterministic(implementation, salt, ethers.Typed.uint256(opts.deployValue)) - : factory.$cloneDeterministic(implementation, salt)); - if (opts.initData || opts.initValue) { - await deployer.sendTransaction({ to: clone, value: opts.initValue ?? 0n, data: opts.initData ?? '0x' }); - } - return Object.assign(clone, { deploymentTransaction: () => tx }); - }; - - return { deployer, factory, implementation, newClone, newCloneDeterministic }; -} - -describe('Clones', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - for (const args of [undefined, '0x', '0x11223344']) { - describe(args ? `with immutable args: ${args}` : 'without immutable args', function () { - describe('clone', function () { - beforeEach(async function () { - this.createClone = this.newClone(args); - }); - - shouldBehaveLikeClone(); - - it('get immutable arguments', async function () { - const instance = await this.createClone(); - expect(await this.factory.$fetchCloneArgs(instance)).to.equal(args ?? '0x'); - }); - }); - - describe('cloneDeterministic', function () { - beforeEach(async function () { - this.createClone = this.newCloneDeterministic(args); - }); - - shouldBehaveLikeClone(); - - it('get immutable arguments', async function () { - const instance = await this.createClone(); - expect(await this.factory.$fetchCloneArgs(instance)).to.equal(args ?? '0x'); - }); - - it('revert if address already used', async function () { - const salt = ethers.randomBytes(32); - - const deployClone = () => - args - ? this.factory.$cloneDeterministicWithImmutableArgs(this.implementation, args, salt) - : this.factory.$cloneDeterministic(this.implementation, salt); - - // deploy once - await expect(deployClone()).to.not.be.reverted; - - // deploy twice - await expect(deployClone()).to.be.revertedWithCustomError(this.factory, 'FailedDeployment'); - }); - - it('address prediction', async function () { - const salt = ethers.randomBytes(32); - - const expected = ethers.getCreate2Address( - this.factory.target, - salt, - ethers.keccak256(cloneInitCode(this.implementation, args)), - ); - - if (args) { - const predicted = await this.factory.$predictDeterministicAddressWithImmutableArgs( - this.implementation, - args, - salt, - ); - expect(predicted).to.equal(expected); - - await expect(this.factory.$cloneDeterministicWithImmutableArgs(this.implementation, args, salt)) - .to.emit(this.factory, 'return$cloneDeterministicWithImmutableArgs_address_bytes_bytes32') - .withArgs(predicted); - } else { - const predicted = await this.factory.$predictDeterministicAddress(this.implementation, salt); - expect(predicted).to.equal(expected); - - await expect(this.factory.$cloneDeterministic(this.implementation, salt)) - .to.emit(this.factory, 'return$cloneDeterministic_address_bytes32') - .withArgs(predicted); - } - }); - }); - }); - } - - it('EIP-170 limit on immutable args', async function () { - // EIP-170 limits the contract code size to 0x6000 - // This limits the length of immutable args to 0x5fd3 - const args = generators.hexBytes(0x5fd4); - const salt = ethers.randomBytes(32); - - await expect( - this.factory.$predictDeterministicAddressWithImmutableArgs(this.implementation, args, salt), - ).to.be.revertedWithCustomError(this.factory, 'CloneArgumentsTooLong'); - - await expect(this.factory.$cloneWithImmutableArgs(this.implementation, args)).to.be.revertedWithCustomError( - this.factory, - 'CloneArgumentsTooLong', - ); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js deleted file mode 100644 index b222800..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js +++ /dev/null @@ -1,23 +0,0 @@ -const { ethers } = require('hardhat'); - -const shouldBehaveLikeProxy = require('../Proxy.behaviour'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const fixture = async () => { - const [nonContractAddress] = await ethers.getSigners(); - - const implementation = await ethers.deployContract('DummyImplementation'); - - const createProxy = (implementation, initData, opts) => - ethers.deployContract('ERC1967Proxy', [implementation, initData], opts); - - return { nonContractAddress, implementation, createProxy }; -}; - -describe('ERC1967Proxy', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeProxy(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Utils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Utils.test.js deleted file mode 100644 index 0890324..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Utils.test.js +++ /dev/null @@ -1,162 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getAddressInSlot, setSlot, ImplementationSlot, AdminSlot, BeaconSlot } = require('../../helpers/storage'); - -async function fixture() { - const [, admin, anotherAccount] = await ethers.getSigners(); - - const utils = await ethers.deployContract('$ERC1967Utils'); - const v1 = await ethers.deployContract('DummyImplementation'); - const v2 = await ethers.deployContract('CallReceiverMock'); - - return { admin, anotherAccount, utils, v1, v2 }; -} - -describe('ERC1967Utils', function () { - beforeEach('setup', async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('IMPLEMENTATION_SLOT', function () { - beforeEach('set v1 implementation', async function () { - await setSlot(this.utils, ImplementationSlot, this.v1); - }); - - describe('getImplementation', function () { - it('returns current implementation and matches implementation slot value', async function () { - expect(await this.utils.$getImplementation()).to.equal(this.v1); - expect(await getAddressInSlot(this.utils, ImplementationSlot)).to.equal(this.v1); - }); - }); - - describe('upgradeToAndCall', function () { - it('sets implementation in storage and emits event', async function () { - const newImplementation = this.v2; - const tx = await this.utils.$upgradeToAndCall(newImplementation, '0x'); - - expect(await getAddressInSlot(this.utils, ImplementationSlot)).to.equal(newImplementation); - await expect(tx).to.emit(this.utils, 'Upgraded').withArgs(newImplementation); - }); - - it('reverts when implementation does not contain code', async function () { - await expect(this.utils.$upgradeToAndCall(this.anotherAccount, '0x')) - .to.be.revertedWithCustomError(this.utils, 'ERC1967InvalidImplementation') - .withArgs(this.anotherAccount); - }); - - describe('when data is empty', function () { - it('reverts when value is sent', async function () { - await expect(this.utils.$upgradeToAndCall(this.v2, '0x', { value: 1 })).to.be.revertedWithCustomError( - this.utils, - 'ERC1967NonPayable', - ); - }); - }); - - describe('when data is not empty', function () { - it('delegates a call to the new implementation', async function () { - const initializeData = this.v2.interface.encodeFunctionData('mockFunction'); - const tx = await this.utils.$upgradeToAndCall(this.v2, initializeData); - await expect(tx).to.emit(await ethers.getContractAt('CallReceiverMock', this.utils), 'MockFunctionCalled'); - }); - }); - }); - }); - - describe('ADMIN_SLOT', function () { - beforeEach('set admin', async function () { - await setSlot(this.utils, AdminSlot, this.admin); - }); - - describe('getAdmin', function () { - it('returns current admin and matches admin slot value', async function () { - expect(await this.utils.$getAdmin()).to.equal(this.admin); - expect(await getAddressInSlot(this.utils, AdminSlot)).to.equal(this.admin); - }); - }); - - describe('changeAdmin', function () { - it('sets admin in storage and emits event', async function () { - const newAdmin = this.anotherAccount; - const tx = await this.utils.$changeAdmin(newAdmin); - - expect(await getAddressInSlot(this.utils, AdminSlot)).to.equal(newAdmin); - await expect(tx).to.emit(this.utils, 'AdminChanged').withArgs(this.admin, newAdmin); - }); - - it('reverts when setting the address zero as admin', async function () { - await expect(this.utils.$changeAdmin(ethers.ZeroAddress)) - .to.be.revertedWithCustomError(this.utils, 'ERC1967InvalidAdmin') - .withArgs(ethers.ZeroAddress); - }); - }); - }); - - describe('BEACON_SLOT', function () { - beforeEach('set beacon', async function () { - this.beacon = await ethers.deployContract('UpgradeableBeaconMock', [this.v1]); - await setSlot(this.utils, BeaconSlot, this.beacon); - }); - - describe('getBeacon', function () { - it('returns current beacon and matches beacon slot value', async function () { - expect(await this.utils.$getBeacon()).to.equal(this.beacon); - expect(await getAddressInSlot(this.utils, BeaconSlot)).to.equal(this.beacon); - }); - }); - - describe('upgradeBeaconToAndCall', function () { - it('sets beacon in storage and emits event', async function () { - const newBeacon = await ethers.deployContract('UpgradeableBeaconMock', [this.v2]); - const tx = await this.utils.$upgradeBeaconToAndCall(newBeacon, '0x'); - - expect(await getAddressInSlot(this.utils, BeaconSlot)).to.equal(newBeacon); - await expect(tx).to.emit(this.utils, 'BeaconUpgraded').withArgs(newBeacon); - }); - - it('reverts when beacon does not contain code', async function () { - await expect(this.utils.$upgradeBeaconToAndCall(this.anotherAccount, '0x')) - .to.be.revertedWithCustomError(this.utils, 'ERC1967InvalidBeacon') - .withArgs(this.anotherAccount); - }); - - it("reverts when beacon's implementation does not contain code", async function () { - const newBeacon = await ethers.deployContract('UpgradeableBeaconMock', [this.anotherAccount]); - - await expect(this.utils.$upgradeBeaconToAndCall(newBeacon, '0x')) - .to.be.revertedWithCustomError(this.utils, 'ERC1967InvalidImplementation') - .withArgs(this.anotherAccount); - }); - - describe('when data is empty', function () { - it('reverts when value is sent', async function () { - const newBeacon = await ethers.deployContract('UpgradeableBeaconMock', [this.v2]); - await expect(this.utils.$upgradeBeaconToAndCall(newBeacon, '0x', { value: 1 })).to.be.revertedWithCustomError( - this.utils, - 'ERC1967NonPayable', - ); - }); - }); - - describe('when data is not empty', function () { - it('delegates a call to the new implementation', async function () { - const initializeData = this.v2.interface.encodeFunctionData('mockFunction'); - const newBeacon = await ethers.deployContract('UpgradeableBeaconMock', [this.v2]); - const tx = await this.utils.$upgradeBeaconToAndCall(newBeacon, initializeData); - await expect(tx).to.emit(await ethers.getContractAt('CallReceiverMock', this.utils), 'MockFunctionCalled'); - }); - }); - - describe('reentrant beacon implementation() call', function () { - it('sees the new beacon implementation', async function () { - const newBeacon = await ethers.deployContract('UpgradeableBeaconReentrantMock'); - await expect(this.utils.$upgradeBeaconToAndCall(newBeacon, '0x')) - .to.be.revertedWithCustomError(newBeacon, 'BeaconProxyBeaconSlotAddress') - .withArgs(newBeacon); - }); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js deleted file mode 100644 index f459c09..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js +++ /dev/null @@ -1,185 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); - -const { getAddressInSlot, ImplementationSlot } = require('../helpers/storage'); - -module.exports = function shouldBehaveLikeProxy() { - it('cannot be initialized with a non-contract address', async function () { - const initializeData = '0x'; - const contractFactory = await ethers.getContractFactory('ERC1967Proxy'); - await expect(this.createProxy(this.nonContractAddress, initializeData)) - .to.be.revertedWithCustomError(contractFactory, 'ERC1967InvalidImplementation') - .withArgs(this.nonContractAddress); - }); - - const assertProxyInitialization = function ({ value, balance }) { - it('sets the implementation address', async function () { - expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.implementation); - }); - - it('initializes the proxy', async function () { - const dummy = this.implementation.attach(this.proxy); - expect(await dummy.value()).to.equal(value); - }); - - it('has expected balance', async function () { - expect(await ethers.provider.getBalance(this.proxy)).to.equal(balance); - }); - }; - - describe('without initialization', function () { - const initializeData = '0x'; - - describe('when not sending balance', function () { - beforeEach('creating proxy', async function () { - this.proxy = await this.createProxy(this.implementation, initializeData); - }); - - assertProxyInitialization({ value: 0n, balance: 0n }); - }); - - describe('when sending some balance', function () { - const value = 10n ** 5n; - - it('reverts', async function () { - await expect(this.createProxy(this.implementation, initializeData, { value })).to.be.reverted; - }); - }); - }); - - describe('initialization without parameters', function () { - describe('non payable', function () { - const expectedInitializedValue = 10n; - - beforeEach(function () { - this.initializeData = this.implementation.interface.encodeFunctionData('initializeNonPayable'); - }); - - describe('when not sending balance', function () { - beforeEach('creating proxy', async function () { - this.proxy = await this.createProxy(this.implementation, this.initializeData); - }); - - assertProxyInitialization({ - value: expectedInitializedValue, - balance: 0n, - }); - }); - - describe('when sending some balance', function () { - const value = 10n ** 5n; - - it('reverts', async function () { - await expect(this.createProxy(this.implementation, this.initializeData, { value })).to.be.reverted; - }); - }); - }); - - describe('payable', function () { - const expectedInitializedValue = 100n; - - beforeEach(function () { - this.initializeData = this.implementation.interface.encodeFunctionData('initializePayable'); - }); - - describe('when not sending balance', function () { - beforeEach('creating proxy', async function () { - this.proxy = await this.createProxy(this.implementation, this.initializeData); - }); - - assertProxyInitialization({ - value: expectedInitializedValue, - balance: 0n, - }); - }); - - describe('when sending some balance', function () { - const value = 10e5; - - beforeEach('creating proxy', async function () { - this.proxy = await this.createProxy(this.implementation, this.initializeData, { value }); - }); - - assertProxyInitialization({ - value: expectedInitializedValue, - balance: value, - }); - }); - }); - }); - - describe('initialization with parameters', function () { - describe('non payable', function () { - const expectedInitializedValue = 10n; - - beforeEach(function () { - this.initializeData = this.implementation.interface.encodeFunctionData('initializeNonPayableWithValue', [ - expectedInitializedValue, - ]); - }); - - describe('when not sending balance', function () { - beforeEach('creating proxy', async function () { - this.proxy = await this.createProxy(this.implementation, this.initializeData); - }); - - assertProxyInitialization({ - value: expectedInitializedValue, - balance: 0, - }); - }); - - describe('when sending some balance', function () { - const value = 10e5; - - it('reverts', async function () { - await expect(this.createProxy(this.implementation, this.initializeData, { value })).to.be.reverted; - }); - }); - }); - - describe('payable', function () { - const expectedInitializedValue = 42n; - - beforeEach(function () { - this.initializeData = this.implementation.interface.encodeFunctionData('initializePayableWithValue', [ - expectedInitializedValue, - ]); - }); - - describe('when not sending balance', function () { - beforeEach('creating proxy', async function () { - this.proxy = await this.createProxy(this.implementation, this.initializeData); - }); - - assertProxyInitialization({ - value: expectedInitializedValue, - balance: 0n, - }); - }); - - describe('when sending some balance', function () { - const value = 10n ** 5n; - - beforeEach('creating proxy', async function () { - this.proxy = await this.createProxy(this.implementation, this.initializeData, { value }); - }); - - assertProxyInitialization({ - value: expectedInitializedValue, - balance: value, - }); - }); - }); - - describe('reverting initialization', function () { - beforeEach(function () { - this.initializeData = this.implementation.interface.encodeFunctionData('reverts'); - }); - - it('reverts', async function () { - await expect(this.createProxy(this.implementation, this.initializeData)).to.be.reverted; - }); - }); - }); -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js deleted file mode 100644 index d64023b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js +++ /dev/null @@ -1,141 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getAddressInSlot, BeaconSlot } = require('../../helpers/storage'); - -async function fixture() { - const [admin, other] = await ethers.getSigners(); - - const v1 = await ethers.deployContract('DummyImplementation'); - const v2 = await ethers.deployContract('DummyImplementationV2'); - const factory = await ethers.getContractFactory('BeaconProxy'); - const beacon = await ethers.deployContract('UpgradeableBeacon', [v1, admin]); - - const newBeaconProxy = (beacon, data, opts = {}) => factory.deploy(beacon, data, opts); - - return { admin, other, factory, beacon, v1, v2, newBeaconProxy }; -} - -describe('BeaconProxy', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('bad beacon is not accepted', function () { - it('non-contract beacon', async function () { - const notBeacon = this.other; - - await expect(this.newBeaconProxy(notBeacon, '0x')) - .to.be.revertedWithCustomError(this.factory, 'ERC1967InvalidBeacon') - .withArgs(notBeacon); - }); - - it('non-compliant beacon', async function () { - const badBeacon = await ethers.deployContract('BadBeaconNoImpl'); - - // BadBeaconNoImpl does not provide `implementation()` and has no fallback. - // This causes ERC1967Utils._setBeacon to revert. - await expect(this.newBeaconProxy(badBeacon, '0x')).to.be.revertedWithoutReason(); - }); - - it('non-contract implementation', async function () { - const badBeacon = await ethers.deployContract('BadBeaconNotContract'); - - await expect(this.newBeaconProxy(badBeacon, '0x')) - .to.be.revertedWithCustomError(this.factory, 'ERC1967InvalidImplementation') - .withArgs(await badBeacon.implementation()); - }); - }); - - describe('initialization', function () { - async function assertInitialized({ value, balance }) { - const beaconAddress = await getAddressInSlot(this.proxy, BeaconSlot); - expect(beaconAddress).to.equal(this.beacon); - - const dummy = this.v1.attach(this.proxy); - expect(await dummy.value()).to.equal(value); - - expect(await ethers.provider.getBalance(this.proxy)).to.equal(balance); - } - - it('no initialization', async function () { - this.proxy = await this.newBeaconProxy(this.beacon, '0x'); - await assertInitialized.bind(this)({ value: 0n, balance: 0n }); - }); - - it('non-payable initialization', async function () { - const value = 55n; - const data = this.v1.interface.encodeFunctionData('initializeNonPayableWithValue', [value]); - - this.proxy = await this.newBeaconProxy(this.beacon, data); - await assertInitialized.bind(this)({ value, balance: 0n }); - }); - - it('payable initialization', async function () { - const value = 55n; - const data = this.v1.interface.encodeFunctionData('initializePayableWithValue', [value]); - const balance = 100n; - - this.proxy = await this.newBeaconProxy(this.beacon, data, { value: balance }); - await assertInitialized.bind(this)({ value, balance }); - }); - - it('reverting initialization due to value', async function () { - await expect(this.newBeaconProxy(this.beacon, '0x', { value: 1n })).to.be.revertedWithCustomError( - this.factory, - 'ERC1967NonPayable', - ); - }); - - it('reverting initialization function', async function () { - const data = this.v1.interface.encodeFunctionData('reverts'); - await expect(this.newBeaconProxy(this.beacon, data)).to.be.revertedWith('DummyImplementation reverted'); - }); - }); - - describe('upgrade', function () { - it('upgrade a proxy by upgrading its beacon', async function () { - const value = 10n; - const data = this.v1.interface.encodeFunctionData('initializeNonPayableWithValue', [value]); - const proxy = await this.newBeaconProxy(this.beacon, data).then(instance => this.v1.attach(instance)); - - // test initial values - expect(await proxy.value()).to.equal(value); - - // test initial version - expect(await proxy.version()).to.equal('V1'); - - // upgrade beacon - await this.beacon.connect(this.admin).upgradeTo(this.v2); - - // test upgraded version - expect(await proxy.version()).to.equal('V2'); - }); - - it('upgrade 2 proxies by upgrading shared beacon', async function () { - const value1 = 10n; - const data1 = this.v1.interface.encodeFunctionData('initializeNonPayableWithValue', [value1]); - const proxy1 = await this.newBeaconProxy(this.beacon, data1).then(instance => this.v1.attach(instance)); - - const value2 = 42n; - const data2 = this.v1.interface.encodeFunctionData('initializeNonPayableWithValue', [value2]); - const proxy2 = await this.newBeaconProxy(this.beacon, data2).then(instance => this.v1.attach(instance)); - - // test initial values - expect(await proxy1.value()).to.equal(value1); - expect(await proxy2.value()).to.equal(value2); - - // test initial version - expect(await proxy1.version()).to.equal('V1'); - expect(await proxy2.version()).to.equal('V1'); - - // upgrade beacon - await this.beacon.connect(this.admin).upgradeTo(this.v2); - - // test upgraded version - expect(await proxy1.version()).to.equal('V2'); - expect(await proxy2.version()).to.equal('V2'); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js deleted file mode 100644 index 2da7d0a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js +++ /dev/null @@ -1,55 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -async function fixture() { - const [admin, other] = await ethers.getSigners(); - - const v1 = await ethers.deployContract('Implementation1'); - const v2 = await ethers.deployContract('Implementation2'); - const beacon = await ethers.deployContract('UpgradeableBeacon', [v1, admin]); - - return { admin, other, beacon, v1, v2 }; -} - -describe('UpgradeableBeacon', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('cannot be created with non-contract implementation', async function () { - await expect(ethers.deployContract('UpgradeableBeacon', [this.other, this.admin])) - .to.be.revertedWithCustomError(this.beacon, 'BeaconInvalidImplementation') - .withArgs(this.other); - }); - - describe('once deployed', function () { - it('emits Upgraded event to the first implementation', async function () { - await expect(this.beacon.deploymentTransaction()).to.emit(this.beacon, 'Upgraded').withArgs(this.v1); - }); - - it('returns implementation', async function () { - expect(await this.beacon.implementation()).to.equal(this.v1); - }); - - it('can be upgraded by the admin', async function () { - await expect(this.beacon.connect(this.admin).upgradeTo(this.v2)) - .to.emit(this.beacon, 'Upgraded') - .withArgs(this.v2); - - expect(await this.beacon.implementation()).to.equal(this.v2); - }); - - it('cannot be upgraded to a non-contract', async function () { - await expect(this.beacon.connect(this.admin).upgradeTo(this.other)) - .to.be.revertedWithCustomError(this.beacon, 'BeaconInvalidImplementation') - .withArgs(this.other); - }); - - it('cannot be upgraded by other account', async function () { - await expect(this.beacon.connect(this.other).upgradeTo(this.v2)) - .to.be.revertedWithCustomError(this.beacon, 'OwnableUnauthorizedAccount') - .withArgs(this.other); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js deleted file mode 100644 index df430d4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js +++ /dev/null @@ -1,82 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getAddressInSlot, ImplementationSlot } = require('../../helpers/storage'); - -async function fixture() { - const [admin, other] = await ethers.getSigners(); - - const v1 = await ethers.deployContract('DummyImplementation'); - const v2 = await ethers.deployContract('DummyImplementationV2'); - - const proxy = await ethers - .deployContract('TransparentUpgradeableProxy', [v1, admin, '0x']) - .then(instance => ethers.getContractAt('ITransparentUpgradeableProxy', instance)); - - const proxyAdmin = await ethers.getContractAt( - 'ProxyAdmin', - ethers.getCreateAddress({ from: proxy.target, nonce: 1n }), - ); - - return { admin, other, v1, v2, proxy, proxyAdmin }; -} - -describe('ProxyAdmin', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('has an owner', async function () { - expect(await this.proxyAdmin.owner()).to.equal(this.admin); - }); - - it('has an interface version', async function () { - expect(await this.proxyAdmin.UPGRADE_INTERFACE_VERSION()).to.equal('5.0.0'); - }); - - describe('without data', function () { - describe('with unauthorized account', function () { - it('fails to upgrade', async function () { - await expect(this.proxyAdmin.connect(this.other).upgradeAndCall(this.proxy, this.v2, '0x')) - .to.be.revertedWithCustomError(this.proxyAdmin, 'OwnableUnauthorizedAccount') - .withArgs(this.other); - }); - }); - - describe('with authorized account', function () { - it('upgrades implementation', async function () { - await this.proxyAdmin.connect(this.admin).upgradeAndCall(this.proxy, this.v2, '0x'); - expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.v2); - }); - }); - }); - - describe('with data', function () { - describe('with unauthorized account', function () { - it('fails to upgrade', async function () { - const data = this.v1.interface.encodeFunctionData('initializeNonPayableWithValue', [1337n]); - await expect(this.proxyAdmin.connect(this.other).upgradeAndCall(this.proxy, this.v2, data)) - .to.be.revertedWithCustomError(this.proxyAdmin, 'OwnableUnauthorizedAccount') - .withArgs(this.other); - }); - }); - - describe('with authorized account', function () { - describe('with invalid callData', function () { - it('fails to upgrade', async function () { - const data = '0x12345678'; - await expect(this.proxyAdmin.connect(this.admin).upgradeAndCall(this.proxy, this.v2, data)).to.be.reverted; - }); - }); - - describe('with valid callData', function () { - it('upgrades implementation', async function () { - const data = this.v2.interface.encodeFunctionData('initializeNonPayableWithValue', [1337n]); - await this.proxyAdmin.connect(this.admin).upgradeAndCall(this.proxy, this.v2, data); - expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.v2); - }); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js deleted file mode 100644 index 8e1d62e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js +++ /dev/null @@ -1,357 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); - -const { impersonate } = require('../../helpers/account'); -const { getAddressInSlot, ImplementationSlot, AdminSlot } = require('../../helpers/storage'); - -// createProxy, initialOwner, accounts -module.exports = function shouldBehaveLikeTransparentUpgradeableProxy() { - before(async function () { - const implementationV0 = await ethers.deployContract('DummyImplementation'); - const implementationV1 = await ethers.deployContract('DummyImplementation'); - - const createProxyWithImpersonatedProxyAdmin = async (logic, initData, opts = undefined) => { - const [proxy, tx] = await this.createProxy(logic, initData, opts).then(instance => - Promise.all([ethers.getContractAt('ITransparentUpgradeableProxy', instance), instance.deploymentTransaction()]), - ); - - const proxyAdmin = await ethers.getContractAt( - 'ProxyAdmin', - ethers.getCreateAddress({ from: proxy.target, nonce: 1n }), - ); - const proxyAdminAsSigner = await proxyAdmin.getAddress().then(impersonate); - - return { - instance: logic.attach(proxy.target), // attaching proxy directly works well for everything except for event resolution - proxy, - proxyAdmin, - proxyAdminAsSigner, - tx, - }; - }; - - Object.assign(this, { - implementationV0, - implementationV1, - createProxyWithImpersonatedProxyAdmin, - }); - }); - - beforeEach(async function () { - Object.assign(this, await this.createProxyWithImpersonatedProxyAdmin(this.implementationV0, '0x')); - }); - - describe('implementation', function () { - it('returns the current implementation address', async function () { - expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.implementationV0); - }); - - it('delegates to the implementation', async function () { - expect(await this.instance.get()).to.be.true; - }); - }); - - describe('proxy admin', function () { - it('emits AdminChanged event during construction', async function () { - await expect(this.tx).to.emit(this.proxy, 'AdminChanged').withArgs(ethers.ZeroAddress, this.proxyAdmin); - }); - - it('sets the proxy admin in storage with the correct initial owner', async function () { - expect(await getAddressInSlot(this.proxy, AdminSlot)).to.equal(this.proxyAdmin); - - expect(await this.proxyAdmin.owner()).to.equal(this.owner); - }); - - it('can overwrite the admin by the implementation', async function () { - await this.instance.unsafeOverrideAdmin(this.other); - - const ERC1967AdminSlotValue = await getAddressInSlot(this.proxy, AdminSlot); - expect(ERC1967AdminSlotValue).to.equal(this.other); - expect(ERC1967AdminSlotValue).to.not.equal(this.proxyAdmin); - - // Still allows previous admin to execute admin operations - await expect(this.proxy.connect(this.proxyAdminAsSigner).upgradeToAndCall(this.implementationV1, '0x')) - .to.emit(this.proxy, 'Upgraded') - .withArgs(this.implementationV1); - }); - }); - - describe('upgradeToAndCall', function () { - describe('without migrations', function () { - beforeEach(async function () { - this.behavior = await ethers.deployContract('InitializableMock'); - }); - - describe('when the call does not fail', function () { - beforeEach(function () { - this.initializeData = this.behavior.interface.encodeFunctionData('initializeWithX', [42n]); - }); - - describe('when the sender is the admin', function () { - const value = 10n ** 5n; - - beforeEach(async function () { - this.tx = await this.proxy - .connect(this.proxyAdminAsSigner) - .upgradeToAndCall(this.behavior, this.initializeData, { - value, - }); - }); - - it('upgrades to the requested implementation', async function () { - expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behavior); - }); - - it('emits an event', async function () { - await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behavior); - }); - - it('calls the initializer function', async function () { - expect(await this.behavior.attach(this.proxy).x()).to.equal(42n); - }); - - it('sends given value to the proxy', async function () { - expect(await ethers.provider.getBalance(this.proxy)).to.equal(value); - }); - - it('uses the storage of the proxy', async function () { - // storage layout should look as follows: - // - 0: Initializable storage ++ initializerRan ++ onlyInitializingRan - // - 1: x - expect(await ethers.provider.getStorage(this.proxy, 1n)).to.equal(42n); - }); - }); - - describe('when the sender is not the admin', function () { - it('reverts', async function () { - await expect(this.proxy.connect(this.other).upgradeToAndCall(this.behavior, this.initializeData)).to.be - .reverted; - }); - }); - }); - - describe('when the call does fail', function () { - beforeEach(function () { - this.initializeData = this.behavior.interface.encodeFunctionData('fail'); - }); - - it('reverts', async function () { - await expect(this.proxy.connect(this.proxyAdminAsSigner).upgradeToAndCall(this.behavior, this.initializeData)) - .to.be.reverted; - }); - }); - }); - - describe('with migrations', function () { - describe('when the sender is the admin', function () { - const value = 10n ** 5n; - - describe('when upgrading to V1', function () { - beforeEach(async function () { - this.behaviorV1 = await ethers.deployContract('MigratableMockV1'); - const v1MigrationData = this.behaviorV1.interface.encodeFunctionData('initialize', [42n]); - - this.balancePreviousV1 = await ethers.provider.getBalance(this.proxy); - this.tx = await this.proxy - .connect(this.proxyAdminAsSigner) - .upgradeToAndCall(this.behaviorV1, v1MigrationData, { - value, - }); - }); - - it('upgrades to the requested version and emits an event', async function () { - expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behaviorV1); - - await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behaviorV1); - }); - - it("calls the 'initialize' function and sends given value to the proxy", async function () { - expect(await this.behaviorV1.attach(this.proxy).x()).to.equal(42n); - expect(await ethers.provider.getBalance(this.proxy)).to.equal(this.balancePreviousV1 + value); - }); - - describe('when upgrading to V2', function () { - beforeEach(async function () { - this.behaviorV2 = await ethers.deployContract('MigratableMockV2'); - const v2MigrationData = this.behaviorV2.interface.encodeFunctionData('migrate', [10n, 42n]); - - this.balancePreviousV2 = await ethers.provider.getBalance(this.proxy); - this.tx = await this.proxy - .connect(this.proxyAdminAsSigner) - .upgradeToAndCall(this.behaviorV2, v2MigrationData, { - value, - }); - }); - - it('upgrades to the requested version and emits an event', async function () { - expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behaviorV2); - - await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behaviorV2); - }); - - it("calls the 'migrate' function and sends given value to the proxy", async function () { - expect(await this.behaviorV2.attach(this.proxy).x()).to.equal(10n); - expect(await this.behaviorV2.attach(this.proxy).y()).to.equal(42n); - expect(await ethers.provider.getBalance(this.proxy)).to.equal(this.balancePreviousV2 + value); - }); - - describe('when upgrading to V3', function () { - beforeEach(async function () { - this.behaviorV3 = await ethers.deployContract('MigratableMockV3'); - const v3MigrationData = this.behaviorV3.interface.encodeFunctionData('migrate()'); - - this.balancePreviousV3 = await ethers.provider.getBalance(this.proxy); - this.tx = await this.proxy - .connect(this.proxyAdminAsSigner) - .upgradeToAndCall(this.behaviorV3, v3MigrationData, { - value, - }); - }); - - it('upgrades to the requested version and emits an event', async function () { - expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behaviorV3); - - await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behaviorV3); - }); - - it("calls the 'migrate' function and sends given value to the proxy", async function () { - expect(await this.behaviorV3.attach(this.proxy).x()).to.equal(42n); - expect(await this.behaviorV3.attach(this.proxy).y()).to.equal(10n); - expect(await ethers.provider.getBalance(this.proxy)).to.equal(this.balancePreviousV3 + value); - }); - }); - }); - }); - }); - - describe('when the sender is not the admin', function () { - it('reverts', async function () { - const behaviorV1 = await ethers.deployContract('MigratableMockV1'); - const v1MigrationData = behaviorV1.interface.encodeFunctionData('initialize', [42n]); - await expect(this.proxy.connect(this.other).upgradeToAndCall(behaviorV1, v1MigrationData)).to.be.reverted; - }); - }); - }); - }); - - describe('transparent proxy', function () { - beforeEach('creating proxy', async function () { - this.clashingImplV0 = await ethers.deployContract('ClashingImplementation'); - this.clashingImplV1 = await ethers.deployContract('ClashingImplementation'); - - Object.assign(this, await this.createProxyWithImpersonatedProxyAdmin(this.clashingImplV0, '0x')); - }); - - it('proxy admin cannot call delegated functions', async function () { - const factory = await ethers.getContractFactory('TransparentUpgradeableProxy'); - - await expect(this.instance.connect(this.proxyAdminAsSigner).delegatedFunction()).to.be.revertedWithCustomError( - factory, - 'ProxyDeniedAdminAccess', - ); - }); - - describe('when function names clash', function () { - it('executes the proxy function if the sender is the admin', async function () { - await expect(this.proxy.connect(this.proxyAdminAsSigner).upgradeToAndCall(this.clashingImplV1, '0x')) - .to.emit(this.proxy, 'Upgraded') - .withArgs(this.clashingImplV1); - }); - - it('delegates the call to implementation when sender is not the admin', async function () { - await expect(this.proxy.connect(this.other).upgradeToAndCall(this.clashingImplV1, '0x')) - .to.emit(this.instance, 'ClashingImplementationCall') - .to.not.emit(this.proxy, 'Upgraded'); - }); - }); - }); - - describe('regression', function () { - const initializeData = '0x'; - - it('should add new function', async function () { - const impl1 = await ethers.deployContract('Implementation1'); - const impl2 = await ethers.deployContract('Implementation2'); - const { instance, proxy, proxyAdminAsSigner } = await this.createProxyWithImpersonatedProxyAdmin( - impl1, - initializeData, - ); - - await instance.setValue(42n); - - // `getValue` is not available in impl1 - await expect(impl2.attach(instance).getValue()).to.be.reverted; - - // do upgrade - await proxy.connect(proxyAdminAsSigner).upgradeToAndCall(impl2, '0x'); - - // `getValue` is available in impl2 - expect(await impl2.attach(instance).getValue()).to.equal(42n); - }); - - it('should remove function', async function () { - const impl1 = await ethers.deployContract('Implementation1'); - const impl2 = await ethers.deployContract('Implementation2'); - const { instance, proxy, proxyAdminAsSigner } = await this.createProxyWithImpersonatedProxyAdmin( - impl2, - initializeData, - ); - - await instance.setValue(42n); - - // `getValue` is available in impl2 - expect(await impl2.attach(instance).getValue()).to.equal(42n); - - // do downgrade - await proxy.connect(proxyAdminAsSigner).upgradeToAndCall(impl1, '0x'); - - // `getValue` is not available in impl1 - await expect(impl2.attach(instance).getValue()).to.be.reverted; - }); - - it('should change function signature', async function () { - const impl1 = await ethers.deployContract('Implementation1'); - const impl3 = await ethers.deployContract('Implementation3'); - const { instance, proxy, proxyAdminAsSigner } = await this.createProxyWithImpersonatedProxyAdmin( - impl1, - initializeData, - ); - - await instance.setValue(42n); - - await proxy.connect(proxyAdminAsSigner).upgradeToAndCall(impl3, '0x'); - - expect(await impl3.attach(instance).getValue(8n)).to.equal(50n); - }); - - it('should add fallback function', async function () { - const impl1 = await ethers.deployContract('Implementation1'); - const impl4 = await ethers.deployContract('Implementation4'); - const { instance, proxy, proxyAdminAsSigner } = await this.createProxyWithImpersonatedProxyAdmin( - impl1, - initializeData, - ); - - await proxy.connect(proxyAdminAsSigner).upgradeToAndCall(impl4, '0x'); - - await this.other.sendTransaction({ to: proxy }); - - expect(await impl4.attach(instance).getValue()).to.equal(1n); - }); - - it('should remove fallback function', async function () { - const impl2 = await ethers.deployContract('Implementation2'); - const impl4 = await ethers.deployContract('Implementation4'); - const { instance, proxy, proxyAdminAsSigner } = await this.createProxyWithImpersonatedProxyAdmin( - impl4, - initializeData, - ); - - await proxy.connect(proxyAdminAsSigner).upgradeToAndCall(impl2, '0x'); - - await expect(this.other.sendTransaction({ to: proxy })).to.be.reverted; - - expect(await impl2.attach(instance).getValue()).to.equal(0n); - }); - }); -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js deleted file mode 100644 index 61e1801..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js +++ /dev/null @@ -1,28 +0,0 @@ -const { ethers } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const shouldBehaveLikeProxy = require('../Proxy.behaviour'); -const shouldBehaveLikeTransparentUpgradeableProxy = require('./TransparentUpgradeableProxy.behaviour'); - -async function fixture() { - const [owner, other, ...accounts] = await ethers.getSigners(); - - const implementation = await ethers.deployContract('DummyImplementation'); - - const createProxy = function (logic, initData, opts = undefined) { - return ethers.deployContract('TransparentUpgradeableProxy', [logic, owner, initData], opts); - }; - - return { nonContractAddress: owner, owner, other, accounts, implementation, createProxy }; -} - -describe('TransparentUpgradeableProxy', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeProxy(); - - // createProxy, owner, otherAccounts - shouldBehaveLikeTransparentUpgradeableProxy(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js deleted file mode 100644 index 6bf213f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js +++ /dev/null @@ -1,216 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { MAX_UINT64 } = require('../../helpers/constants'); - -describe('Initializable', function () { - describe('basic testing without inheritance', function () { - beforeEach('deploying', async function () { - this.mock = await ethers.deployContract('InitializableMock'); - }); - - describe('before initialize', function () { - it('initializer has not run', async function () { - expect(await this.mock.initializerRan()).to.be.false; - }); - - it('_initializing returns false before initialization', async function () { - expect(await this.mock.isInitializing()).to.be.false; - }); - }); - - describe('after initialize', function () { - beforeEach('initializing', async function () { - await this.mock.initialize(); - }); - - it('initializer has run', async function () { - expect(await this.mock.initializerRan()).to.be.true; - }); - - it('_initializing returns false after initialization', async function () { - expect(await this.mock.isInitializing()).to.be.false; - }); - - it('initializer does not run again', async function () { - await expect(this.mock.initialize()).to.be.revertedWithCustomError(this.mock, 'InvalidInitialization'); - }); - }); - - describe('nested under an initializer', function () { - it('initializer modifier reverts', async function () { - await expect(this.mock.initializerNested()).to.be.revertedWithCustomError(this.mock, 'InvalidInitialization'); - }); - - it('onlyInitializing modifier succeeds', async function () { - await this.mock.onlyInitializingNested(); - expect(await this.mock.onlyInitializingRan()).to.be.true; - }); - }); - - it('cannot call onlyInitializable function outside the scope of an initializable function', async function () { - await expect(this.mock.initializeOnlyInitializing()).to.be.revertedWithCustomError(this.mock, 'NotInitializing'); - }); - }); - - it('nested initializer can run during construction', async function () { - const mock = await ethers.deployContract('ConstructorInitializableMock'); - expect(await mock.initializerRan()).to.be.true; - expect(await mock.onlyInitializingRan()).to.be.true; - }); - - it('multiple constructor levels can be initializers', async function () { - const mock = await ethers.deployContract('ChildConstructorInitializableMock'); - expect(await mock.initializerRan()).to.be.true; - expect(await mock.childInitializerRan()).to.be.true; - expect(await mock.onlyInitializingRan()).to.be.true; - }); - - describe('reinitialization', function () { - beforeEach('deploying', async function () { - this.mock = await ethers.deployContract('ReinitializerMock'); - }); - - it('can reinitialize', async function () { - expect(await this.mock.counter()).to.equal(0n); - await this.mock.initialize(); - expect(await this.mock.counter()).to.equal(1n); - await this.mock.reinitialize(2); - expect(await this.mock.counter()).to.equal(2n); - await this.mock.reinitialize(3); - expect(await this.mock.counter()).to.equal(3n); - }); - - it('can jump multiple steps', async function () { - expect(await this.mock.counter()).to.equal(0n); - await this.mock.initialize(); - expect(await this.mock.counter()).to.equal(1n); - await this.mock.reinitialize(128); - expect(await this.mock.counter()).to.equal(2n); - }); - - it('cannot nest reinitializers', async function () { - expect(await this.mock.counter()).to.equal(0n); - await expect(this.mock.nestedReinitialize(2, 2)).to.be.revertedWithCustomError( - this.mock, - 'InvalidInitialization', - ); - await expect(this.mock.nestedReinitialize(2, 3)).to.be.revertedWithCustomError( - this.mock, - 'InvalidInitialization', - ); - await expect(this.mock.nestedReinitialize(3, 2)).to.be.revertedWithCustomError( - this.mock, - 'InvalidInitialization', - ); - }); - - it('can chain reinitializers', async function () { - expect(await this.mock.counter()).to.equal(0n); - await this.mock.chainReinitialize(2, 3); - expect(await this.mock.counter()).to.equal(2n); - }); - - it('_getInitializedVersion returns right version', async function () { - await this.mock.initialize(); - expect(await this.mock.getInitializedVersion()).to.equal(1n); - await this.mock.reinitialize(12); - expect(await this.mock.getInitializedVersion()).to.equal(12n); - }); - - describe('contract locking', function () { - it('prevents initialization', async function () { - await this.mock.disableInitializers(); - await expect(this.mock.initialize()).to.be.revertedWithCustomError(this.mock, 'InvalidInitialization'); - }); - - it('prevents re-initialization', async function () { - await this.mock.disableInitializers(); - await expect(this.mock.reinitialize(255n)).to.be.revertedWithCustomError(this.mock, 'InvalidInitialization'); - }); - - it('can lock contract after initialization', async function () { - await this.mock.initialize(); - await this.mock.disableInitializers(); - await expect(this.mock.reinitialize(255n)).to.be.revertedWithCustomError(this.mock, 'InvalidInitialization'); - }); - }); - }); - - describe('events', function () { - it('constructor initialization emits event', async function () { - const mock = await ethers.deployContract('ConstructorInitializableMock'); - await expect(mock.deploymentTransaction()).to.emit(mock, 'Initialized').withArgs(1n); - }); - - it('initialization emits event', async function () { - const mock = await ethers.deployContract('ReinitializerMock'); - await expect(mock.initialize()).to.emit(mock, 'Initialized').withArgs(1n); - }); - - it('reinitialization emits event', async function () { - const mock = await ethers.deployContract('ReinitializerMock'); - await expect(mock.reinitialize(128)).to.emit(mock, 'Initialized').withArgs(128n); - }); - - it('chained reinitialization emits multiple events', async function () { - const mock = await ethers.deployContract('ReinitializerMock'); - - await expect(mock.chainReinitialize(2, 3)) - .to.emit(mock, 'Initialized') - .withArgs(2n) - .to.emit(mock, 'Initialized') - .withArgs(3n); - }); - }); - - describe('complex testing with inheritance', function () { - const mother = 12n; - const gramps = '56'; - const father = 34n; - const child = 78n; - - beforeEach('deploying', async function () { - this.mock = await ethers.deployContract('SampleChild'); - await this.mock.initialize(mother, gramps, father, child); - }); - - it('initializes human', async function () { - expect(await this.mock.isHuman()).to.be.true; - }); - - it('initializes mother', async function () { - expect(await this.mock.mother()).to.equal(mother); - }); - - it('initializes gramps', async function () { - expect(await this.mock.gramps()).to.equal(gramps); - }); - - it('initializes father', async function () { - expect(await this.mock.father()).to.equal(father); - }); - - it('initializes child', async function () { - expect(await this.mock.child()).to.equal(child); - }); - }); - - describe('disabling initialization', function () { - it('old and new patterns in bad sequence', async function () { - const DisableBad1 = await ethers.getContractFactory('DisableBad1'); - await expect(DisableBad1.deploy()).to.be.revertedWithCustomError(DisableBad1, 'InvalidInitialization'); - - const DisableBad2 = await ethers.getContractFactory('DisableBad2'); - await expect(DisableBad2.deploy()).to.be.revertedWithCustomError(DisableBad2, 'InvalidInitialization'); - }); - - it('old and new patterns in good sequence', async function () { - const ok = await ethers.deployContract('DisableOk'); - await expect(ok.deploymentTransaction()) - .to.emit(ok, 'Initialized') - .withArgs(1n) - .to.emit(ok, 'Initialized') - .withArgs(MAX_UINT64); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js deleted file mode 100644 index 17f8657..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js +++ /dev/null @@ -1,120 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getAddressInSlot, ImplementationSlot } = require('../../helpers/storage'); - -async function fixture() { - const implInitial = await ethers.deployContract('UUPSUpgradeableMock'); - const implUpgradeOk = await ethers.deployContract('UUPSUpgradeableMock'); - const implUpgradeUnsafe = await ethers.deployContract('UUPSUpgradeableUnsafeMock'); - const implUpgradeNonUUPS = await ethers.deployContract('NonUpgradeableMock'); - const implUnsupportedUUID = await ethers.deployContract('UUPSUnsupportedProxiableUUID'); - // Used for testing non ERC1967 compliant proxies (clones are proxies that don't use the ERC1967 implementation slot) - const cloneFactory = await ethers.deployContract('$Clones'); - - const instance = await ethers - .deployContract('ERC1967Proxy', [implInitial, '0x']) - .then(proxy => implInitial.attach(proxy.target)); - - return { - implInitial, - implUpgradeOk, - implUpgradeUnsafe, - implUpgradeNonUUPS, - implUnsupportedUUID, - cloneFactory, - instance, - }; -} - -describe('UUPSUpgradeable', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - 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 () { - await expect(this.instance.upgradeToAndCall(this.implUpgradeOk, '0x')) - .to.emit(this.instance, 'Upgraded') - .withArgs(this.implUpgradeOk); - - expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.equal(this.implUpgradeOk); - }); - - it('upgrade to upgradeable implementation with call', async function () { - expect(await this.instance.current()).to.equal(0n); - - await expect( - this.instance.upgradeToAndCall(this.implUpgradeOk, this.implUpgradeOk.interface.encodeFunctionData('increment')), - ) - .to.emit(this.instance, 'Upgraded') - .withArgs(this.implUpgradeOk); - - expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.equal(this.implUpgradeOk); - - expect(await this.instance.current()).to.equal(1n); - }); - - it('calling upgradeTo on the implementation reverts', async function () { - await expect(this.implInitial.upgradeToAndCall(this.implUpgradeOk, '0x')).to.be.revertedWithCustomError( - this.implInitial, - 'UUPSUnauthorizedCallContext', - ); - }); - - it('calling upgradeToAndCall on the implementation reverts', async function () { - await expect( - this.implInitial.upgradeToAndCall( - this.implUpgradeOk, - this.implUpgradeOk.interface.encodeFunctionData('increment'), - ), - ).to.be.revertedWithCustomError(this.implUpgradeOk, 'UUPSUnauthorizedCallContext'); - }); - - it('calling upgradeToAndCall from a contract that is not an ERC1967 proxy (with the right implementation) reverts', async function () { - const instance = await this.cloneFactory.$clone - .staticCall(this.implUpgradeOk) - .then(address => this.implInitial.attach(address)); - await this.cloneFactory.$clone(this.implUpgradeOk); - - await expect(instance.upgradeToAndCall(this.implUpgradeUnsafe, '0x')).to.be.revertedWithCustomError( - instance, - 'UUPSUnauthorizedCallContext', - ); - }); - - it('rejects upgrading to an unsupported UUID', async function () { - await expect(this.instance.upgradeToAndCall(this.implUnsupportedUUID, '0x')) - .to.be.revertedWithCustomError(this.instance, 'UUPSUnsupportedProxiableUUID') - .withArgs(ethers.id('invalid UUID')); - }); - - it('upgrade to and unsafe upgradeable implementation', async function () { - await expect(this.instance.upgradeToAndCall(this.implUpgradeUnsafe, '0x')) - .to.emit(this.instance, 'Upgraded') - .withArgs(this.implUpgradeUnsafe); - - expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.equal(this.implUpgradeUnsafe); - }); - - // delegate to a non existing upgradeTo function causes a low level revert - it('reject upgrade to non uups implementation', async function () { - await expect(this.instance.upgradeToAndCall(this.implUpgradeNonUUPS, '0x')) - .to.be.revertedWithCustomError(this.instance, 'ERC1967InvalidImplementation') - .withArgs(this.implUpgradeNonUUPS); - }); - - it('reject proxy address as implementation', async function () { - const otherInstance = await ethers - .deployContract('ERC1967Proxy', [this.implInitial, '0x']) - .then(proxy => this.implInitial.attach(proxy.target)); - - await expect(this.instance.upgradeToAndCall(otherInstance, '0x')) - .to.be.revertedWithCustomError(this.instance, 'ERC1967InvalidImplementation') - .withArgs(otherInstance); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/sanity.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/sanity.test.js deleted file mode 100644 index ea0175c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/sanity.test.js +++ /dev/null @@ -1,27 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers'); - -async function fixture() { - return {}; -} - -describe('Environment sanity', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('snapshot', function () { - let blockNumberBefore; - - it('cache and mine', async function () { - blockNumberBefore = await ethers.provider.getBlockNumber(); - await mine(); - expect(await ethers.provider.getBlockNumber()).to.equal(blockNumberBefore + 1); - }); - - it('check snapshot', async function () { - expect(await ethers.provider.getBlockNumber()).to.equal(blockNumberBefore); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js deleted file mode 100644 index d19b732..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js +++ /dev/null @@ -1,763 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); - -const { RevertType } = require('../../helpers/enums'); -const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); - -function shouldBehaveLikeERC1155() { - const firstTokenId = 1n; - const secondTokenId = 2n; - const unknownTokenId = 3n; - - const firstTokenValue = 1000n; - const secondTokenValue = 2000n; - - const RECEIVER_SINGLE_MAGIC_VALUE = '0xf23a6e61'; - const RECEIVER_BATCH_MAGIC_VALUE = '0xbc197c81'; - - beforeEach(async function () { - [this.recipient, this.proxy, this.alice, this.bruce] = this.otherAccounts; - }); - - 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(ethers.ZeroAddress, firstTokenId)).to.equal(0n); - }); - - describe("when accounts don't own tokens", function () { - it('returns zero for given addresses', async function () { - expect(await this.token.balanceOf(this.alice, firstTokenId)).to.equal(0n); - expect(await this.token.balanceOf(this.bruce, secondTokenId)).to.equal(0n); - expect(await this.token.balanceOf(this.alice, unknownTokenId)).to.equal(0n); - }); - }); - - describe('when accounts own some tokens', function () { - beforeEach(async function () { - await this.token.$_mint(this.alice, firstTokenId, firstTokenValue, '0x'); - await this.token.$_mint(this.bruce, secondTokenId, secondTokenValue, '0x'); - }); - - it('returns the amount of tokens owned by the given addresses', async function () { - expect(await this.token.balanceOf(this.alice, firstTokenId)).to.equal(firstTokenValue); - expect(await this.token.balanceOf(this.bruce, secondTokenId)).to.equal(secondTokenValue); - expect(await this.token.balanceOf(this.alice, unknownTokenId)).to.equal(0n); - }); - }); - }); - - describe('balanceOfBatch', function () { - it("reverts when input arrays don't match up", async function () { - const accounts1 = [this.alice, this.bruce, this.alice, this.bruce]; - const ids1 = [firstTokenId, secondTokenId, unknownTokenId]; - - await expect(this.token.balanceOfBatch(accounts1, ids1)) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') - .withArgs(ids1.length, accounts1.length); - - const accounts2 = [this.alice, this.bruce]; - const ids2 = [firstTokenId, secondTokenId, unknownTokenId]; - await expect(this.token.balanceOfBatch(accounts2, ids2)) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') - .withArgs(ids2.length, accounts2.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( - [this.alice, this.bruce, ethers.ZeroAddress], - [firstTokenId, secondTokenId, unknownTokenId], - ); - expect(result).to.deep.equal([0n, 0n, 0n]); - }); - - describe("when accounts don't own tokens", function () { - it('returns zeros for each account', async function () { - const result = await this.token.balanceOfBatch( - [this.alice, this.bruce, this.alice], - [firstTokenId, secondTokenId, unknownTokenId], - ); - expect(result).to.deep.equal([0n, 0n, 0n]); - }); - }); - - describe('when accounts own some tokens', function () { - beforeEach(async function () { - await this.token.$_mint(this.alice, firstTokenId, firstTokenValue, '0x'); - await this.token.$_mint(this.bruce, secondTokenId, secondTokenValue, '0x'); - }); - - it('returns amounts owned by each account in order passed', async function () { - const result = await this.token.balanceOfBatch( - [this.bruce, this.alice, this.alice], - [secondTokenId, firstTokenId, unknownTokenId], - ); - expect(result).to.deep.equal([secondTokenValue, firstTokenValue, 0n]); - }); - - it('returns multiple times the balance of the same address when asked', async function () { - const result = await this.token.balanceOfBatch( - [this.alice, this.bruce, this.alice], - [firstTokenId, secondTokenId, firstTokenId], - ); - expect(result).to.deep.equal([firstTokenValue, secondTokenValue, firstTokenValue]); - }); - }); - }); - - describe('setApprovalForAll', function () { - beforeEach(async function () { - this.tx = await this.token.connect(this.holder).setApprovalForAll(this.proxy, true); - }); - - it('sets approval status which can be queried via isApprovedForAll', async function () { - expect(await this.token.isApprovedForAll(this.holder, this.proxy)).to.be.true; - }); - - it('emits an ApprovalForAll log', async function () { - await expect(this.tx).to.emit(this.token, 'ApprovalForAll').withArgs(this.holder, this.proxy, true); - }); - - it('can unset approval for an operator', async function () { - await this.token.connect(this.holder).setApprovalForAll(this.proxy, false); - expect(await this.token.isApprovedForAll(this.holder, this.proxy)).to.be.false; - }); - - it('reverts if attempting to approve zero address as an operator', async function () { - await expect(this.token.connect(this.holder).setApprovalForAll(ethers.ZeroAddress, true)) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidOperator') - .withArgs(ethers.ZeroAddress); - }); - }); - - describe('safeTransferFrom', function () { - beforeEach(async function () { - await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); - await this.token.$_mint(this.holder, secondTokenId, secondTokenValue, '0x'); - }); - - it('reverts when transferring more than balance', async function () { - await expect( - this.token - .connect(this.holder) - .safeTransferFrom(this.holder, this.recipient, firstTokenId, firstTokenValue + 1n, '0x'), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') - .withArgs(this.holder, firstTokenValue, firstTokenValue + 1n, firstTokenId); - }); - - it('reverts when transferring to zero address', async function () { - await expect( - this.token - .connect(this.holder) - .safeTransferFrom(this.holder, ethers.ZeroAddress, firstTokenId, firstTokenValue, '0x'), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') - .withArgs(ethers.ZeroAddress); - }); - - function transferWasSuccessful() { - it('debits transferred balance from sender', async function () { - expect(await this.token.balanceOf(this.args.from, this.args.id)).to.equal(0n); - }); - - it('credits transferred balance to receiver', async function () { - expect(await this.token.balanceOf(this.args.to, this.args.id)).to.equal(this.args.value); - }); - - it('emits a TransferSingle log', async function () { - await expect(this.tx) - .to.emit(this.token, 'TransferSingle') - .withArgs(this.args.operator, this.args.from, this.args.to, this.args.id, this.args.value); - }); - } - - describe('when called by the holder', function () { - beforeEach(async function () { - this.args = { - operator: this.holder, - from: this.holder, - to: this.recipient, - id: firstTokenId, - value: firstTokenValue, - data: '0x', - }; - this.tx = await this.token - .connect(this.args.operator) - .safeTransferFrom(this.args.from, this.args.to, this.args.id, this.args.value, this.args.data); - }); - - transferWasSuccessful(); - - it('preserves existing balances which are not transferred by holder', async function () { - expect(await this.token.balanceOf(this.holder, secondTokenId)).to.equal(secondTokenValue); - expect(await this.token.balanceOf(this.recipient, secondTokenId)).to.equal(0n); - }); - }); - - describe('when called by an operator on behalf of the holder', function () { - describe('when operator is not approved by holder', function () { - beforeEach(async function () { - await this.token.connect(this.holder).setApprovalForAll(this.proxy, false); - }); - - it('reverts', async function () { - await expect( - this.token - .connect(this.proxy) - .safeTransferFrom(this.holder, this.recipient, firstTokenId, firstTokenValue, '0x'), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll') - .withArgs(this.proxy, this.holder); - }); - }); - - describe('when operator is approved by holder', function () { - beforeEach(async function () { - await this.token.connect(this.holder).setApprovalForAll(this.proxy, true); - - this.args = { - operator: this.proxy, - from: this.holder, - to: this.recipient, - id: firstTokenId, - value: firstTokenValue, - data: '0x', - }; - this.tx = await this.token - .connect(this.args.operator) - .safeTransferFrom(this.args.from, this.args.to, this.args.id, this.args.value, this.args.data); - }); - - transferWasSuccessful(); - - it("preserves operator's balances not involved in the transfer", async function () { - expect(await this.token.balanceOf(this.proxy, firstTokenId)).to.equal(0n); - expect(await this.token.balanceOf(this.proxy, secondTokenId)).to.equal(0n); - }); - }); - }); - - describe('when sending to a valid receiver', function () { - beforeEach(async function () { - this.receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ - RECEIVER_SINGLE_MAGIC_VALUE, - RECEIVER_BATCH_MAGIC_VALUE, - RevertType.None, - ]); - }); - - describe('without data', function () { - beforeEach(async function () { - this.args = { - operator: this.holder, - from: this.holder, - to: this.receiver, - id: firstTokenId, - value: firstTokenValue, - data: '0x', - }; - this.tx = await this.token - .connect(this.args.operator) - .safeTransferFrom(this.args.from, this.args.to, this.args.id, this.args.value, this.args.data); - }); - - transferWasSuccessful(); - - it('calls onERC1155Received', async function () { - await expect(this.tx) - .to.emit(this.receiver, 'Received') - .withArgs(this.args.operator, this.args.from, this.args.id, this.args.value, this.args.data, anyValue); - }); - }); - - describe('with data', function () { - beforeEach(async function () { - this.args = { - operator: this.holder, - from: this.holder, - to: this.receiver, - id: firstTokenId, - value: firstTokenValue, - data: '0xf00dd00d', - }; - this.tx = await this.token - .connect(this.args.operator) - .safeTransferFrom(this.args.from, this.args.to, this.args.id, this.args.value, this.args.data); - }); - - transferWasSuccessful(); - - it('calls onERC1155Received', async function () { - await expect(this.tx) - .to.emit(this.receiver, 'Received') - .withArgs(this.args.operator, this.args.from, this.args.id, this.args.value, this.args.data, anyValue); - }); - }); - }); - - describe('to a receiver contract returning unexpected value', function () { - it('reverts', async function () { - const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ - '0x00c0ffee', - RECEIVER_BATCH_MAGIC_VALUE, - RevertType.None, - ]); - - await expect( - this.token - .connect(this.holder) - .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') - .withArgs(receiver); - }); - }); - - describe('to a receiver contract that reverts', function () { - describe('with a revert string', function () { - it('reverts', async function () { - const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ - RECEIVER_SINGLE_MAGIC_VALUE, - RECEIVER_BATCH_MAGIC_VALUE, - RevertType.RevertWithMessage, - ]); - - await expect( - this.token - .connect(this.holder) - .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), - ).to.be.revertedWith('ERC1155ReceiverMock: reverting on receive'); - }); - }); - - describe('without a revert string', function () { - it('reverts', async function () { - const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ - RECEIVER_SINGLE_MAGIC_VALUE, - RECEIVER_BATCH_MAGIC_VALUE, - RevertType.RevertWithoutMessage, - ]); - - await expect( - this.token - .connect(this.holder) - .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') - .withArgs(receiver); - }); - }); - - describe('with a custom error', function () { - it('reverts', async function () { - const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ - RECEIVER_SINGLE_MAGIC_VALUE, - RECEIVER_BATCH_MAGIC_VALUE, - RevertType.RevertWithCustomError, - ]); - - await expect( - this.token - .connect(this.holder) - .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), - ) - .to.be.revertedWithCustomError(receiver, 'CustomError') - .withArgs(RECEIVER_SINGLE_MAGIC_VALUE); - }); - }); - - describe('with a panic', function () { - it('reverts', async function () { - const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ - RECEIVER_SINGLE_MAGIC_VALUE, - RECEIVER_BATCH_MAGIC_VALUE, - RevertType.Panic, - ]); - - await expect( - this.token - .connect(this.holder) - .safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'), - ).to.be.revertedWithPanic(); - }); - }); - }); - - describe('to a contract that does not implement the required function', function () { - it('reverts', async function () { - const invalidReceiver = this.token; - - await expect( - this.token - .connect(this.holder) - .safeTransferFrom(this.holder, invalidReceiver, firstTokenId, firstTokenValue, '0x'), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') - .withArgs(invalidReceiver); - }); - }); - }); - - describe('safeBatchTransferFrom', function () { - beforeEach(async function () { - await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); - await this.token.$_mint(this.holder, secondTokenId, secondTokenValue, '0x'); - }); - - it('reverts when transferring value more than any of balances', async function () { - await expect( - this.token - .connect(this.holder) - .safeBatchTransferFrom( - this.holder, - this.recipient, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue + 1n], - '0x', - ), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') - .withArgs(this.holder, secondTokenValue, secondTokenValue + 1n, secondTokenId); - }); - - it("reverts when ids array length doesn't match values array length", async function () { - const ids1 = [firstTokenId]; - const tokenValues1 = [firstTokenValue, secondTokenValue]; - - await expect( - this.token.connect(this.holder).safeBatchTransferFrom(this.holder, this.recipient, ids1, tokenValues1, '0x'), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') - .withArgs(ids1.length, tokenValues1.length); - - const ids2 = [firstTokenId, secondTokenId]; - const tokenValues2 = [firstTokenValue]; - - await expect( - this.token.connect(this.holder).safeBatchTransferFrom(this.holder, this.recipient, ids2, tokenValues2, '0x'), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') - .withArgs(ids2.length, tokenValues2.length); - }); - - it('reverts when transferring to zero address', async function () { - await expect( - this.token - .connect(this.holder) - .safeBatchTransferFrom( - this.holder, - ethers.ZeroAddress, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') - .withArgs(ethers.ZeroAddress); - }); - - it('reverts when transferring from zero address', async function () { - await expect( - this.token.$_safeBatchTransferFrom(ethers.ZeroAddress, this.holder, [firstTokenId], [firstTokenValue], '0x'), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidSender') - .withArgs(ethers.ZeroAddress); - }); - - function batchTransferWasSuccessful() { - it('debits transferred balances from sender', async function () { - const newBalances = await this.token.balanceOfBatch( - this.args.ids.map(() => this.args.from), - this.args.ids, - ); - expect(newBalances).to.deep.equal(this.args.ids.map(() => 0n)); - }); - - it('credits transferred balances to receiver', async function () { - const newBalances = await this.token.balanceOfBatch( - this.args.ids.map(() => this.args.to), - this.args.ids, - ); - expect(newBalances).to.deep.equal(this.args.values); - }); - - it('emits a TransferBatch log', async function () { - await expect(this.tx) - .to.emit(this.token, 'TransferBatch') - .withArgs(this.args.operator, this.args.from, this.args.to, this.args.ids, this.args.values); - }); - } - - describe('when called by the holder', function () { - beforeEach(async function () { - this.args = { - operator: this.holder, - from: this.holder, - to: this.recipient, - ids: [firstTokenId, secondTokenId], - values: [firstTokenValue, secondTokenValue], - data: '0x', - }; - this.tx = await this.token - .connect(this.args.operator) - .safeBatchTransferFrom(this.args.from, this.args.to, this.args.ids, this.args.values, this.args.data); - }); - - batchTransferWasSuccessful(); - }); - - describe('when called by an operator on behalf of the holder', function () { - describe('when operator is not approved by holder', function () { - beforeEach(async function () { - await this.token.connect(this.holder).setApprovalForAll(this.proxy, false); - }); - - it('reverts', async function () { - await expect( - this.token - .connect(this.proxy) - .safeBatchTransferFrom( - this.holder, - this.recipient, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll') - .withArgs(this.proxy, this.holder); - }); - }); - - describe('when operator is approved by holder', function () { - beforeEach(async function () { - await this.token.connect(this.holder).setApprovalForAll(this.proxy, true); - - this.args = { - operator: this.proxy, - from: this.holder, - to: this.recipient, - ids: [firstTokenId, secondTokenId], - values: [firstTokenValue, secondTokenValue], - data: '0x', - }; - this.tx = await this.token - .connect(this.args.operator) - .safeBatchTransferFrom(this.args.from, this.args.to, this.args.ids, this.args.values, this.args.data); - }); - - batchTransferWasSuccessful(); - - it("preserves operator's balances not involved in the transfer", async function () { - expect(await this.token.balanceOf(this.proxy, firstTokenId)).to.equal(0n); - expect(await this.token.balanceOf(this.proxy, secondTokenId)).to.equal(0n); - }); - }); - }); - - describe('when sending to a valid receiver', function () { - beforeEach(async function () { - this.receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ - RECEIVER_SINGLE_MAGIC_VALUE, - RECEIVER_BATCH_MAGIC_VALUE, - RevertType.None, - ]); - }); - - describe('without data', function () { - beforeEach(async function () { - this.args = { - operator: this.holder, - from: this.holder, - to: this.receiver, - ids: [firstTokenId, secondTokenId], - values: [firstTokenValue, secondTokenValue], - data: '0x', - }; - this.tx = await this.token - .connect(this.args.operator) - .safeBatchTransferFrom(this.args.from, this.args.to, this.args.ids, this.args.values, this.args.data); - }); - - batchTransferWasSuccessful(); - - it('calls onERC1155BatchReceived', async function () { - await expect(this.tx) - .to.emit(this.receiver, 'BatchReceived') - .withArgs(this.holder, this.holder, this.args.ids, this.args.values, this.args.data, anyValue); - }); - }); - - describe('with data', function () { - beforeEach(async function () { - this.args = { - operator: this.holder, - from: this.holder, - to: this.receiver, - ids: [firstTokenId, secondTokenId], - values: [firstTokenValue, secondTokenValue], - data: '0xf00dd00d', - }; - this.tx = await this.token - .connect(this.args.operator) - .safeBatchTransferFrom(this.args.from, this.args.to, this.args.ids, this.args.values, this.args.data); - }); - - batchTransferWasSuccessful(); - - it('calls onERC1155Received', async function () { - await expect(this.tx) - .to.emit(this.receiver, 'BatchReceived') - .withArgs(this.holder, this.holder, this.args.ids, this.args.values, this.args.data, anyValue); - }); - }); - }); - - describe('to a receiver contract returning unexpected value', function () { - it('reverts', async function () { - const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ - RECEIVER_SINGLE_MAGIC_VALUE, - RECEIVER_SINGLE_MAGIC_VALUE, - RevertType.None, - ]); - - await expect( - this.token - .connect(this.holder) - .safeBatchTransferFrom( - this.holder, - receiver, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') - .withArgs(receiver); - }); - }); - - describe('to a receiver contract that reverts', function () { - describe('with a revert string', function () { - it('reverts', async function () { - const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ - RECEIVER_SINGLE_MAGIC_VALUE, - RECEIVER_BATCH_MAGIC_VALUE, - RevertType.RevertWithMessage, - ]); - - await expect( - this.token - .connect(this.holder) - .safeBatchTransferFrom( - this.holder, - receiver, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ).to.be.revertedWith('ERC1155ReceiverMock: reverting on batch receive'); - }); - }); - - describe('without a revert string', function () { - it('reverts', async function () { - const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ - RECEIVER_SINGLE_MAGIC_VALUE, - RECEIVER_BATCH_MAGIC_VALUE, - RevertType.RevertWithoutMessage, - ]); - - await expect( - this.token - .connect(this.holder) - .safeBatchTransferFrom( - this.holder, - receiver, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') - .withArgs(receiver); - }); - }); - - describe('with a custom error', function () { - it('reverts', async function () { - const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ - RECEIVER_SINGLE_MAGIC_VALUE, - RECEIVER_BATCH_MAGIC_VALUE, - RevertType.RevertWithCustomError, - ]); - - await expect( - this.token - .connect(this.holder) - .safeBatchTransferFrom( - this.holder, - receiver, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ) - .to.be.revertedWithCustomError(receiver, 'CustomError') - .withArgs(RECEIVER_SINGLE_MAGIC_VALUE); - }); - }); - - describe('with a panic', function () { - it('reverts', async function () { - const receiver = await ethers.deployContract('$ERC1155ReceiverMock', [ - RECEIVER_SINGLE_MAGIC_VALUE, - RECEIVER_BATCH_MAGIC_VALUE, - RevertType.Panic, - ]); - - await expect( - this.token - .connect(this.holder) - .safeBatchTransferFrom( - this.holder, - receiver, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ).to.be.revertedWithPanic(); - }); - }); - }); - - describe('to a contract that does not implement the required function', function () { - it('reverts', async function () { - const invalidReceiver = this.token; - - await expect( - this.token - .connect(this.holder) - .safeBatchTransferFrom( - this.holder, - invalidReceiver, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') - .withArgs(invalidReceiver); - }); - }); - }); - - shouldSupportInterfaces(['ERC1155', 'ERC1155MetadataURI']); - }); -} - -module.exports = { - shouldBehaveLikeERC1155, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js deleted file mode 100644 index 8b0a672..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js +++ /dev/null @@ -1,213 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { zip } = require('../../helpers/iterate'); -const { shouldBehaveLikeERC1155 } = require('./ERC1155.behavior'); - -const initialURI = 'https://token-cdn-domain/{id}.json'; - -async function fixture() { - const [operator, holder, ...otherAccounts] = await ethers.getSigners(); - const token = await ethers.deployContract('$ERC1155', [initialURI]); - return { token, operator, holder, otherAccounts }; -} - -describe('ERC1155', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeERC1155(); - - describe('internal functions', function () { - const tokenId = 1990n; - const mintValue = 9001n; - const burnValue = 3000n; - - const tokenBatchIds = [2000n, 2010n, 2020n]; - const mintValues = [5000n, 10000n, 42195n]; - const burnValues = [5000n, 9001n, 195n]; - - const data = '0x12345678'; - - describe('_mint', function () { - it('reverts with a zero destination address', async function () { - await expect(this.token.$_mint(ethers.ZeroAddress, tokenId, mintValue, data)) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') - .withArgs(ethers.ZeroAddress); - }); - - describe('with minted tokens', function () { - beforeEach(async function () { - this.tx = await this.token.connect(this.operator).$_mint(this.holder, tokenId, mintValue, data); - }); - - it('emits a TransferSingle event', async function () { - await expect(this.tx) - .to.emit(this.token, 'TransferSingle') - .withArgs(this.operator, ethers.ZeroAddress, this.holder, tokenId, mintValue); - }); - - it('credits the minted token value', async function () { - expect(await this.token.balanceOf(this.holder, tokenId)).to.equal(mintValue); - }); - }); - }); - - describe('_mintBatch', function () { - it('reverts with a zero destination address', async function () { - await expect(this.token.$_mintBatch(ethers.ZeroAddress, tokenBatchIds, mintValues, data)) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver') - .withArgs(ethers.ZeroAddress); - }); - - it('reverts if length of inputs do not match', async function () { - await expect(this.token.$_mintBatch(this.holder, tokenBatchIds, mintValues.slice(1), data)) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') - .withArgs(tokenBatchIds.length, mintValues.length - 1); - - await expect(this.token.$_mintBatch(this.holder, tokenBatchIds.slice(1), mintValues, data)) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') - .withArgs(tokenBatchIds.length - 1, mintValues.length); - }); - - describe('with minted batch of tokens', function () { - beforeEach(async function () { - this.tx = await this.token.connect(this.operator).$_mintBatch(this.holder, tokenBatchIds, mintValues, data); - }); - - it('emits a TransferBatch event', async function () { - await expect(this.tx) - .to.emit(this.token, 'TransferBatch') - .withArgs(this.operator, ethers.ZeroAddress, this.holder, tokenBatchIds, mintValues); - }); - - it('credits the minted batch of tokens', async function () { - const holderBatchBalances = await this.token.balanceOfBatch( - tokenBatchIds.map(() => this.holder), - tokenBatchIds, - ); - - expect(holderBatchBalances).to.deep.equal(mintValues); - }); - }); - }); - - describe('_burn', function () { - it("reverts when burning the zero account's tokens", async function () { - await expect(this.token.$_burn(ethers.ZeroAddress, tokenId, mintValue)) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidSender') - .withArgs(ethers.ZeroAddress); - }); - - it('reverts when burning a non-existent token id', async function () { - await expect(this.token.$_burn(this.holder, tokenId, mintValue)) - .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') - .withArgs(this.holder, 0, mintValue, tokenId); - }); - - it('reverts when burning more than available tokens', async function () { - await this.token.connect(this.operator).$_mint(this.holder, tokenId, mintValue, data); - - await expect(this.token.$_burn(this.holder, tokenId, mintValue + 1n)) - .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') - .withArgs(this.holder, mintValue, mintValue + 1n, tokenId); - }); - - describe('with minted-then-burnt tokens', function () { - beforeEach(async function () { - await this.token.$_mint(this.holder, tokenId, mintValue, data); - this.tx = await this.token.connect(this.operator).$_burn(this.holder, tokenId, burnValue); - }); - - it('emits a TransferSingle event', async function () { - await expect(this.tx) - .to.emit(this.token, 'TransferSingle') - .withArgs(this.operator, this.holder, ethers.ZeroAddress, tokenId, burnValue); - }); - - it('accounts for both minting and burning', async function () { - expect(await this.token.balanceOf(this.holder, tokenId)).to.equal(mintValue - burnValue); - }); - }); - }); - - describe('_burnBatch', function () { - it("reverts when burning the zero account's tokens", async function () { - await expect(this.token.$_burnBatch(ethers.ZeroAddress, tokenBatchIds, burnValues)) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidSender') - .withArgs(ethers.ZeroAddress); - }); - - it('reverts if length of inputs do not match', async function () { - await expect(this.token.$_burnBatch(this.holder, tokenBatchIds, burnValues.slice(1))) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') - .withArgs(tokenBatchIds.length, burnValues.length - 1); - - await expect(this.token.$_burnBatch(this.holder, tokenBatchIds.slice(1), burnValues)) - .to.be.revertedWithCustomError(this.token, 'ERC1155InvalidArrayLength') - .withArgs(tokenBatchIds.length - 1, burnValues.length); - }); - - it('reverts when burning a non-existent token id', async function () { - await expect(this.token.$_burnBatch(this.holder, tokenBatchIds, burnValues)) - .to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance') - .withArgs(this.holder, 0, burnValues[0], tokenBatchIds[0]); - }); - - describe('with minted-then-burnt tokens', function () { - beforeEach(async function () { - await this.token.$_mintBatch(this.holder, tokenBatchIds, mintValues, data); - this.tx = await this.token.connect(this.operator).$_burnBatch(this.holder, tokenBatchIds, burnValues); - }); - - it('emits a TransferBatch event', async function () { - await expect(this.tx) - .to.emit(this.token, 'TransferBatch') - .withArgs(this.operator, this.holder, ethers.ZeroAddress, tokenBatchIds, burnValues); - }); - - it('accounts for both minting and burning', async function () { - const holderBatchBalances = await this.token.balanceOfBatch( - tokenBatchIds.map(() => this.holder), - tokenBatchIds, - ); - - expect(holderBatchBalances).to.deep.equal( - zip(mintValues, burnValues).map(([mintValue, burnValue]) => mintValue - burnValue), - ); - }); - }); - }); - }); - - describe('ERC1155MetadataURI', function () { - const firstTokenID = 42n; - const secondTokenID = 1337n; - - it('emits no URI event in constructor', async function () { - await expect(this.token.deploymentTransaction()).to.not.emit(this.token, 'URI'); - }); - - it('sets the initial URI for all token types', async function () { - expect(await this.token.uri(firstTokenID)).to.equal(initialURI); - expect(await this.token.uri(secondTokenID)).to.equal(initialURI); - }); - - describe('_setURI', function () { - const newURI = 'https://token-cdn-domain/{locale}/{id}.json'; - - it('emits no URI event', async function () { - await expect(this.token.$_setURI(newURI)).to.not.emit(this.token, 'URI'); - }); - - it('sets the new URI for all token types', async function () { - await this.token.$_setURI(newURI); - - expect(await this.token.uri(firstTokenID)).to.equal(newURI); - expect(await this.token.uri(secondTokenID)).to.equal(newURI); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js deleted file mode 100644 index 01e7ee2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js +++ /dev/null @@ -1,66 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const ids = [42n, 1137n]; -const values = [3000n, 9902n]; - -async function fixture() { - const [holder, operator, other] = await ethers.getSigners(); - - const token = await ethers.deployContract('$ERC1155Burnable', ['https://token-cdn-domain/{id}.json']); - await token.$_mint(holder, ids[0], values[0], '0x'); - await token.$_mint(holder, ids[1], values[1], '0x'); - - return { token, holder, operator, other }; -} - -describe('ERC1155Burnable', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('burn', function () { - it('holder can burn their tokens', async function () { - await this.token.connect(this.holder).burn(this.holder, ids[0], values[0] - 1n); - - expect(await this.token.balanceOf(this.holder, ids[0])).to.equal(1n); - }); - - it("approved operators can burn the holder's tokens", async function () { - await this.token.connect(this.holder).setApprovalForAll(this.operator, true); - await this.token.connect(this.operator).burn(this.holder, ids[0], values[0] - 1n); - - expect(await this.token.balanceOf(this.holder, ids[0])).to.equal(1n); - }); - - it("unapproved accounts cannot burn the holder's tokens", async function () { - await expect(this.token.connect(this.other).burn(this.holder, ids[0], values[0] - 1n)) - .to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll') - .withArgs(this.other, this.holder); - }); - }); - - describe('burnBatch', function () { - it('holder can burn their tokens', async function () { - await this.token.connect(this.holder).burnBatch(this.holder, ids, [values[0] - 1n, values[1] - 2n]); - - expect(await this.token.balanceOf(this.holder, ids[0])).to.equal(1n); - expect(await this.token.balanceOf(this.holder, ids[1])).to.equal(2n); - }); - - it("approved operators can burn the holder's tokens", async function () { - await this.token.connect(this.holder).setApprovalForAll(this.operator, true); - await this.token.connect(this.operator).burnBatch(this.holder, ids, [values[0] - 1n, values[1] - 2n]); - - expect(await this.token.balanceOf(this.holder, ids[0])).to.equal(1n); - expect(await this.token.balanceOf(this.holder, ids[1])).to.equal(2n); - }); - - it("unapproved accounts cannot burn the holder's tokens", async function () { - await expect(this.token.connect(this.other).burnBatch(this.holder, ids, [values[0] - 1n, values[1] - 2n])) - .to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll') - .withArgs(this.other, this.holder); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js deleted file mode 100644 index 81c4f69..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js +++ /dev/null @@ -1,105 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -async function fixture() { - const [holder, operator, receiver, other] = await ethers.getSigners(); - const token = await ethers.deployContract('$ERC1155Pausable', ['https://token-cdn-domain/{id}.json']); - return { token, holder, operator, receiver, other }; -} - -describe('ERC1155Pausable', function () { - const firstTokenId = 37n; - const firstTokenValue = 42n; - const secondTokenId = 19842n; - const secondTokenValue = 23n; - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('when token is paused', function () { - beforeEach(async function () { - await this.token.connect(this.holder).setApprovalForAll(this.operator, true); - await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); - await this.token.$_pause(); - }); - - it('reverts when trying to safeTransferFrom from holder', async function () { - await expect( - this.token - .connect(this.holder) - .safeTransferFrom(this.holder, this.receiver, firstTokenId, firstTokenValue, '0x'), - ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); - }); - - it('reverts when trying to safeTransferFrom from operator', async function () { - await expect( - this.token - .connect(this.operator) - .safeTransferFrom(this.holder, this.receiver, firstTokenId, firstTokenValue, '0x'), - ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); - }); - - it('reverts when trying to safeBatchTransferFrom from holder', async function () { - await expect( - this.token - .connect(this.holder) - .safeBatchTransferFrom(this.holder, this.receiver, [firstTokenId], [firstTokenValue], '0x'), - ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); - }); - - it('reverts when trying to safeBatchTransferFrom from operator', async function () { - await expect( - this.token - .connect(this.operator) - .safeBatchTransferFrom(this.holder, this.receiver, [firstTokenId], [firstTokenValue], '0x'), - ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); - }); - - it('reverts when trying to mint', async function () { - await expect(this.token.$_mint(this.holder, secondTokenId, secondTokenValue, '0x')).to.be.revertedWithCustomError( - this.token, - 'EnforcedPause', - ); - }); - - it('reverts when trying to mintBatch', async function () { - await expect( - this.token.$_mintBatch(this.holder, [secondTokenId], [secondTokenValue], '0x'), - ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); - }); - - it('reverts when trying to burn', async function () { - await expect(this.token.$_burn(this.holder, firstTokenId, firstTokenValue)).to.be.revertedWithCustomError( - this.token, - 'EnforcedPause', - ); - }); - - it('reverts when trying to burnBatch', async function () { - await expect( - this.token.$_burnBatch(this.holder, [firstTokenId], [firstTokenValue]), - ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); - }); - - describe('setApprovalForAll', function () { - it('approves an operator', async function () { - await this.token.connect(this.holder).setApprovalForAll(this.other, true); - expect(await this.token.isApprovedForAll(this.holder, this.other)).to.be.true; - }); - }); - - describe('balanceOf', function () { - it('returns the token value owned by the given address', async function () { - expect(await this.token.balanceOf(this.holder, firstTokenId)).to.equal(firstTokenValue); - }); - }); - - describe('isApprovedForAll', function () { - it('returns the approval of the operator', async function () { - expect(await this.token.isApprovedForAll(this.holder, this.operator)).to.be.true; - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js deleted file mode 100644 index cca36a0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js +++ /dev/null @@ -1,119 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -async function fixture() { - const [holder] = await ethers.getSigners(); - const token = await ethers.deployContract('$ERC1155Supply', ['https://token-cdn-domain/{id}.json']); - return { token, holder }; -} - -describe('ERC1155Supply', function () { - const firstTokenId = 37n; - const firstTokenValue = 42n; - const secondTokenId = 19842n; - const secondTokenValue = 23n; - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('before mint', function () { - it('exist', async function () { - expect(await this.token.exists(firstTokenId)).to.be.false; - }); - - it('totalSupply', async function () { - expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(0n); - expect(await this.token.totalSupply()).to.equal(0n); - }); - }); - - describe('after mint', function () { - describe('single', function () { - beforeEach(async function () { - await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); - }); - - it('exist', async function () { - expect(await this.token.exists(firstTokenId)).to.be.true; - }); - - it('totalSupply', async function () { - expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(firstTokenValue); - expect(await this.token.totalSupply()).to.equal(firstTokenValue); - }); - }); - - describe('batch', function () { - beforeEach(async function () { - await this.token.$_mintBatch( - this.holder, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ); - }); - - it('exist', async function () { - expect(await this.token.exists(firstTokenId)).to.be.true; - expect(await this.token.exists(secondTokenId)).to.be.true; - }); - - it('totalSupply', async function () { - expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(firstTokenValue); - expect(await this.token.totalSupply(ethers.Typed.uint256(secondTokenId))).to.equal(secondTokenValue); - expect(await this.token.totalSupply()).to.equal(firstTokenValue + secondTokenValue); - }); - }); - }); - - describe('after burn', function () { - describe('single', function () { - beforeEach(async function () { - await this.token.$_mint(this.holder, firstTokenId, firstTokenValue, '0x'); - await this.token.$_burn(this.holder, firstTokenId, firstTokenValue); - }); - - it('exist', async function () { - expect(await this.token.exists(firstTokenId)).to.be.false; - }); - - it('totalSupply', async function () { - expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(0n); - expect(await this.token.totalSupply()).to.equal(0n); - }); - }); - - describe('batch', function () { - beforeEach(async function () { - await this.token.$_mintBatch( - this.holder, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ); - await this.token.$_burnBatch(this.holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue]); - }); - - it('exist', async function () { - expect(await this.token.exists(firstTokenId)).to.be.false; - expect(await this.token.exists(secondTokenId)).to.be.false; - }); - - it('totalSupply', async function () { - expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(0n); - expect(await this.token.totalSupply(ethers.Typed.uint256(secondTokenId))).to.equal(0n); - expect(await this.token.totalSupply()).to.equal(0n); - }); - }); - }); - - describe('other', function () { - it('supply unaffected by no-op', async function () { - await this.token.$_update(ethers.ZeroAddress, ethers.ZeroAddress, [firstTokenId], [firstTokenValue]); - expect(await this.token.totalSupply(ethers.Typed.uint256(firstTokenId))).to.equal(0n); - expect(await this.token.totalSupply()).to.equal(0n); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js deleted file mode 100644 index a0d9b57..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js +++ /dev/null @@ -1,70 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const erc1155Uri = 'https://token.com/nfts/'; -const baseUri = 'https://token.com/'; -const tokenId = 1n; -const value = 3000n; - -describe('ERC1155URIStorage', function () { - describe('with base uri set', function () { - async function fixture() { - const [holder] = await ethers.getSigners(); - - const token = await ethers.deployContract('$ERC1155URIStorage', [erc1155Uri]); - await token.$_setBaseURI(baseUri); - await token.$_mint(holder, tokenId, value, '0x'); - - return { token, holder }; - } - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('can request the token uri, returning the erc1155 uri if no token uri was set', async function () { - expect(await this.token.uri(tokenId)).to.equal(erc1155Uri); - }); - - it('can request the token uri, returning the concatenated uri if a token uri was set', async function () { - const tokenUri = '1234/'; - const expectedUri = `${baseUri}${tokenUri}`; - - await expect(this.token.$_setURI(ethers.Typed.uint256(tokenId), tokenUri)) - .to.emit(this.token, 'URI') - .withArgs(expectedUri, tokenId); - - expect(await this.token.uri(tokenId)).to.equal(expectedUri); - }); - }); - - describe('with base uri set to the empty string', function () { - async function fixture() { - const [holder] = await ethers.getSigners(); - - const token = await ethers.deployContract('$ERC1155URIStorage', ['']); - await token.$_mint(holder, tokenId, value, '0x'); - - return { token, holder }; - } - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('can request the token uri, returning an empty string if no token uri was set', async function () { - expect(await this.token.uri(tokenId)).to.equal(''); - }); - - it('can request the token uri, returning the token uri if a token uri was set', async function () { - const tokenUri = 'ipfs://1234/'; - - await expect(this.token.$_setURI(ethers.Typed.uint256(tokenId), tokenUri)) - .to.emit(this.token, 'URI') - .withArgs(tokenUri, tokenId); - - expect(await this.token.uri(tokenId)).to.equal(tokenUri); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js deleted file mode 100644 index 9bff487..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js +++ /dev/null @@ -1,56 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); - -const ids = [1n, 2n, 3n]; -const values = [1000n, 2000n, 3000n]; -const data = '0x12345678'; - -async function fixture() { - const [owner] = await ethers.getSigners(); - - const token = await ethers.deployContract('$ERC1155', ['https://token-cdn-domain/{id}.json']); - const mock = await ethers.deployContract('$ERC1155Holder'); - - await token.$_mintBatch(owner, ids, values, '0x'); - - return { owner, token, mock }; -} - -describe('ERC1155Holder', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldSupportInterfaces(['ERC1155Receiver']); - - it('receives ERC1155 tokens from a single ID', async function () { - await this.token.connect(this.owner).safeTransferFrom(this.owner, this.mock, ids[0], values[0], data); - - expect(await this.token.balanceOf(this.mock, ids[0])).to.equal(values[0]); - - for (let i = 1; i < ids.length; i++) { - expect(await this.token.balanceOf(this.mock, ids[i])).to.equal(0n); - } - }); - - it('receives ERC1155 tokens from a multiple IDs', async function () { - expect( - await this.token.balanceOfBatch( - ids.map(() => this.mock), - ids, - ), - ).to.deep.equal(ids.map(() => 0n)); - - await this.token.connect(this.owner).safeBatchTransferFrom(this.owner, this.mock, ids, values, data); - - expect( - await this.token.balanceOfBatch( - ids.map(() => this.mock), - ids, - ), - ).to.deep.equal(values); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Utils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Utils.test.js deleted file mode 100644 index 5687568..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Utils.test.js +++ /dev/null @@ -1,299 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { RevertType } = require('../../../helpers/enums'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -const firstTokenId = 1n; -const secondTokenId = 2n; -const firstTokenValue = 1000n; -const secondTokenValue = 1000n; - -const RECEIVER_SINGLE_MAGIC_VALUE = '0xf23a6e61'; -const RECEIVER_BATCH_MAGIC_VALUE = '0xbc197c81'; - -const deployReceiver = ( - revertType, - returnValueSingle = RECEIVER_SINGLE_MAGIC_VALUE, - returnValueBatched = RECEIVER_BATCH_MAGIC_VALUE, -) => ethers.deployContract('$ERC1155ReceiverMock', [returnValueSingle, returnValueBatched, revertType]); - -const fixture = async () => { - const [eoa, operator, owner] = await ethers.getSigners(); - const utils = await ethers.deployContract('$ERC1155Utils'); - - const receivers = { - correct: await deployReceiver(RevertType.None), - invalid: await deployReceiver(RevertType.None, '0xdeadbeef', '0xdeadbeef'), - message: await deployReceiver(RevertType.RevertWithMessage), - empty: await deployReceiver(RevertType.RevertWithoutMessage), - customError: await deployReceiver(RevertType.RevertWithCustomError), - panic: await deployReceiver(RevertType.Panic), - nonReceiver: await ethers.deployContract('CallReceiverMock'), - eoa, - }; - - return { operator, owner, utils, receivers }; -}; - -describe('ERC1155Utils', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('onERC1155Received', function () { - it('succeeds when called by an EOA', async function () { - await expect( - this.utils.$checkOnERC1155Received( - this.operator, - this.owner, - this.receivers.eoa, - firstTokenId, - firstTokenValue, - '0x', - ), - ).to.not.be.reverted; - }); - - it('succeeds when data is passed', async function () { - const data = '0x12345678'; - await expect( - this.utils.$checkOnERC1155Received( - this.operator, - this.owner, - this.receivers.correct, - firstTokenId, - firstTokenValue, - data, - ), - ).to.not.be.reverted; - }); - - it('succeeds when data is empty', async function () { - await expect( - this.utils.$checkOnERC1155Received( - this.operator, - this.owner, - this.receivers.correct, - firstTokenId, - firstTokenValue, - '0x', - ), - ).to.not.be.reverted; - }); - - it('reverts when receiver returns invalid value', async function () { - await expect( - this.utils.$checkOnERC1155Received( - this.operator, - this.owner, - this.receivers.invalid, - firstTokenId, - firstTokenValue, - '0x', - ), - ) - .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver') - .withArgs(this.receivers.invalid); - }); - - it('reverts when receiver reverts with message', async function () { - await expect( - this.utils.$checkOnERC1155Received( - this.operator, - this.owner, - this.receivers.message, - firstTokenId, - firstTokenValue, - '0x', - ), - ).to.be.revertedWith('ERC1155ReceiverMock: reverting on receive'); - }); - - it('reverts when receiver reverts without message', async function () { - await expect( - this.utils.$checkOnERC1155Received( - this.operator, - this.owner, - this.receivers.empty, - firstTokenId, - firstTokenValue, - '0x', - ), - ) - .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver') - .withArgs(this.receivers.empty); - }); - - it('reverts when receiver reverts with custom error', async function () { - await expect( - this.utils.$checkOnERC1155Received( - this.operator, - this.owner, - this.receivers.customError, - firstTokenId, - firstTokenValue, - '0x', - ), - ) - .to.be.revertedWithCustomError(this.receivers.customError, 'CustomError') - .withArgs(RECEIVER_SINGLE_MAGIC_VALUE); - }); - - it('reverts when receiver panics', async function () { - await expect( - this.utils.$checkOnERC1155Received( - this.operator, - this.owner, - this.receivers.panic, - firstTokenId, - firstTokenValue, - '0x', - ), - ).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO); - }); - - it('reverts when receiver does not implement onERC1155Received', async function () { - await expect( - this.utils.$checkOnERC1155Received( - this.operator, - this.owner, - this.receivers.nonReceiver, - firstTokenId, - firstTokenValue, - '0x', - ), - ) - .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver') - .withArgs(this.receivers.nonReceiver); - }); - }); - - describe('onERC1155BatchReceived', function () { - it('succeeds when called by an EOA', async function () { - await expect( - this.utils.$checkOnERC1155BatchReceived( - this.operator, - this.owner, - this.receivers.eoa, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ).to.not.be.reverted; - }); - - it('succeeds when data is passed', async function () { - const data = '0x12345678'; - await expect( - this.utils.$checkOnERC1155BatchReceived( - this.operator, - this.owner, - this.receivers.correct, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - data, - ), - ).to.not.be.reverted; - }); - - it('succeeds when data is empty', async function () { - await expect( - this.utils.$checkOnERC1155BatchReceived( - this.operator, - this.owner, - this.receivers.correct, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ).to.not.be.reverted; - }); - - it('reverts when receiver returns invalid value', async function () { - await expect( - this.utils.$checkOnERC1155BatchReceived( - this.operator, - this.owner, - this.receivers.invalid, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ) - .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver') - .withArgs(this.receivers.invalid); - }); - - it('reverts when receiver reverts with message', async function () { - await expect( - this.utils.$checkOnERC1155BatchReceived( - this.operator, - this.owner, - this.receivers.message, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ).to.be.revertedWith('ERC1155ReceiverMock: reverting on batch receive'); - }); - - it('reverts when receiver reverts without message', async function () { - await expect( - this.utils.$checkOnERC1155BatchReceived( - this.operator, - this.owner, - this.receivers.empty, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ) - .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver') - .withArgs(this.receivers.empty); - }); - - it('reverts when receiver reverts with custom error', async function () { - await expect( - this.utils.$checkOnERC1155BatchReceived( - this.operator, - this.owner, - this.receivers.customError, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ) - .to.be.revertedWithCustomError(this.receivers.customError, 'CustomError') - .withArgs(RECEIVER_SINGLE_MAGIC_VALUE); - }); - - it('reverts when receiver panics', async function () { - await expect( - this.utils.$checkOnERC1155BatchReceived( - this.operator, - this.owner, - this.receivers.panic, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO); - }); - - it('reverts when receiver does not implement onERC1155BatchReceived', async function () { - await expect( - this.utils.$checkOnERC1155BatchReceived( - this.operator, - this.owner, - this.receivers.nonReceiver, - [firstTokenId, secondTokenId], - [firstTokenValue, secondTokenValue], - '0x', - ), - ) - .to.be.revertedWithCustomError(this.utils, 'ERC1155InvalidReceiver') - .withArgs(this.receivers.nonReceiver); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js deleted file mode 100644 index 748df4b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js +++ /dev/null @@ -1,269 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); - -function shouldBehaveLikeERC20(initialSupply, opts = {}) { - const { forcedApproval } = opts; - - beforeEach(async function () { - [this.holder, this.recipient, this.other] = this.accounts; - }); - - it('total supply: returns the total token value', async function () { - expect(await this.token.totalSupply()).to.equal(initialSupply); - }); - - describe('balanceOf', function () { - it('returns zero when the requested account has no tokens', async function () { - expect(await this.token.balanceOf(this.other)).to.equal(0n); - }); - - it('returns the total token value when the requested account has some tokens', async function () { - expect(await this.token.balanceOf(this.holder)).to.equal(initialSupply); - }); - }); - - describe('transfer', function () { - beforeEach(function () { - this.transfer = (from, to, value) => this.token.connect(from).transfer(to, value); - }); - - shouldBehaveLikeERC20Transfer(initialSupply); - }); - - describe('transfer from', function () { - describe('when the token owner is not the zero address', function () { - describe('when the recipient is not the zero address', function () { - describe('when the spender has enough allowance', function () { - beforeEach(async function () { - await this.token.connect(this.holder).approve(this.recipient, initialSupply); - }); - - describe('when the token owner has enough balance', function () { - const value = initialSupply; - - beforeEach(async function () { - this.tx = await this.token.connect(this.recipient).transferFrom(this.holder, this.other, value); - }); - - it('transfers the requested value', async function () { - await expect(this.tx).to.changeTokenBalances(this.token, [this.holder, this.other], [-value, value]); - }); - - it('decreases the spender allowance', async function () { - expect(await this.token.allowance(this.holder, this.recipient)).to.equal(0n); - }); - - it('emits a transfer event', async function () { - await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.holder, this.other, value); - }); - - if (forcedApproval) { - it('emits an approval event', async function () { - await expect(this.tx) - .to.emit(this.token, 'Approval') - .withArgs( - this.holder.address, - this.recipient.address, - await this.token.allowance(this.holder, this.recipient), - ); - }); - } else { - it('does not emit an approval event', async function () { - await expect(this.tx).to.not.emit(this.token, 'Approval'); - }); - } - }); - - it('reverts when the token owner does not have enough balance', async function () { - const value = initialSupply; - await this.token.connect(this.holder).transfer(this.other, 1n); - await expect(this.token.connect(this.recipient).transferFrom(this.holder, this.other, value)) - .to.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') - .withArgs(this.holder, value - 1n, value); - }); - }); - - describe('when the spender does not have enough allowance', function () { - const allowance = initialSupply - 1n; - - beforeEach(async function () { - await this.token.connect(this.holder).approve(this.recipient, allowance); - }); - - it('reverts when the token owner has enough balance', async function () { - const value = initialSupply; - await expect(this.token.connect(this.recipient).transferFrom(this.holder, this.other, value)) - .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientAllowance') - .withArgs(this.recipient, allowance, value); - }); - - it('reverts when the token owner does not have enough balance', async function () { - const value = allowance; - await this.token.connect(this.holder).transfer(this.other, 2); - await expect(this.token.connect(this.recipient).transferFrom(this.holder, this.other, value)) - .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') - .withArgs(this.holder, value - 1n, value); - }); - }); - - describe('when the spender has unlimited allowance', function () { - beforeEach(async function () { - await this.token.connect(this.holder).approve(this.recipient, ethers.MaxUint256); - this.tx = await this.token.connect(this.recipient).transferFrom(this.holder, this.other, 1n); - }); - - it('does not decrease the spender allowance', async function () { - expect(await this.token.allowance(this.holder, this.recipient)).to.equal(ethers.MaxUint256); - }); - - it('does not emit an approval event', async function () { - await expect(this.tx).to.not.emit(this.token, 'Approval'); - }); - }); - }); - - it('reverts when the recipient is the zero address', async function () { - const value = initialSupply; - await this.token.connect(this.holder).approve(this.recipient, value); - await expect(this.token.connect(this.recipient).transferFrom(this.holder, ethers.ZeroAddress, value)) - .to.be.revertedWithCustomError(this.token, 'ERC20InvalidReceiver') - .withArgs(ethers.ZeroAddress); - }); - }); - - it('reverts when the token owner is the zero address', async function () { - // transferFrom does a spendAllowance before moving the assets - // - default behavior (ERC20) is to always update the approval using `_approve`. This will fail because the - // approver (owner) is address(0). This happens even if the amount transferred is zero, and the approval update - // is not actually necessary. - // - in ERC20TemporaryAllowance, transfer of 0 value will not update allowance (temporary or persistent) - // therefore the spendAllowance does not revert. However, the transfer of asset will revert because the sender - // is address(0) - const errorName = this.token.temporaryApprove ? 'ERC20InvalidSender' : 'ERC20InvalidApprover'; - - const value = 0n; - await expect(this.token.connect(this.recipient).transferFrom(ethers.ZeroAddress, this.recipient, value)) - .to.be.revertedWithCustomError(this.token, errorName) - .withArgs(ethers.ZeroAddress); - }); - }); - - describe('approve', function () { - beforeEach(function () { - this.approve = (owner, spender, value) => this.token.connect(owner).approve(spender, value); - }); - - shouldBehaveLikeERC20Approve(initialSupply); - }); -} - -function shouldBehaveLikeERC20Transfer(balance) { - describe('when the recipient is not the zero address', function () { - it('reverts when the sender does not have enough balance', async function () { - const value = balance + 1n; - await expect(this.transfer(this.holder, this.recipient, value)) - .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') - .withArgs(this.holder, balance, value); - }); - - describe('when the sender transfers all balance', function () { - const value = balance; - - beforeEach(async function () { - this.tx = await this.transfer(this.holder, this.recipient, value); - }); - - it('transfers the requested value', async function () { - await expect(this.tx).to.changeTokenBalances(this.token, [this.holder, this.recipient], [-value, value]); - }); - - it('emits a transfer event', async function () { - await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.holder, this.recipient, value); - }); - }); - - describe('when the sender transfers zero tokens', function () { - const value = 0n; - - beforeEach(async function () { - this.tx = await this.transfer(this.holder, this.recipient, value); - }); - - it('transfers the requested value', async function () { - await expect(this.tx).to.changeTokenBalances(this.token, [this.holder, this.recipient], [0n, 0n]); - }); - - it('emits a transfer event', async function () { - await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.holder, this.recipient, value); - }); - }); - }); - - it('reverts when the recipient is the zero address', async function () { - await expect(this.transfer(this.holder, ethers.ZeroAddress, balance)) - .to.be.revertedWithCustomError(this.token, 'ERC20InvalidReceiver') - .withArgs(ethers.ZeroAddress); - }); -} - -function shouldBehaveLikeERC20Approve(supply) { - 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 () { - await expect(this.approve(this.holder, this.recipient, value)) - .to.emit(this.token, 'Approval') - .withArgs(this.holder, this.recipient, value); - }); - - it('approves the requested value when there was no approved value before', async function () { - await this.approve(this.holder, this.recipient, value); - - expect(await this.token.allowance(this.holder, this.recipient)).to.equal(value); - }); - - it('approves the requested value and replaces the previous one when the spender had an approved value', async function () { - await this.approve(this.holder, this.recipient, 1n); - await this.approve(this.holder, this.recipient, value); - - expect(await this.token.allowance(this.holder, this.recipient)).to.equal(value); - }); - }); - - describe('when the sender does not have enough balance', function () { - const value = supply + 1n; - - it('emits an approval event', async function () { - await expect(this.approve(this.holder, this.recipient, value)) - .to.emit(this.token, 'Approval') - .withArgs(this.holder, this.recipient, value); - }); - - it('approves the requested value when there was no approved value before', async function () { - await this.approve(this.holder, this.recipient, value); - - expect(await this.token.allowance(this.holder, this.recipient)).to.equal(value); - }); - - it('approves the requested value and replaces the previous one when the spender had an approved value', async function () { - await this.approve(this.holder, this.recipient, 1n); - await this.approve(this.holder, this.recipient, value); - - expect(await this.token.allowance(this.holder, this.recipient)).to.equal(value); - }); - }); - }); - - it('reverts when the spender is the zero address', async function () { - await expect(this.approve(this.holder, ethers.ZeroAddress, supply)) - .to.be.revertedWithCustomError(this.token, `ERC20InvalidSpender`) - .withArgs(ethers.ZeroAddress); - }); -} - -module.exports = { - shouldBehaveLikeERC20, - shouldBehaveLikeERC20Transfer, - shouldBehaveLikeERC20Approve, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js deleted file mode 100644 index 2d9eefe..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js +++ /dev/null @@ -1,199 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -const { - shouldBehaveLikeERC20, - shouldBehaveLikeERC20Transfer, - shouldBehaveLikeERC20Approve, -} = require('./ERC20.behavior'); - -const TOKENS = [{ Token: '$ERC20' }, { Token: '$ERC20ApprovalMock', forcedApproval: true }]; - -const name = 'My Token'; -const symbol = 'MTKN'; -const initialSupply = 100n; - -describe('ERC20', function () { - for (const { Token, forcedApproval } of TOKENS) { - describe(Token, function () { - const fixture = async () => { - // this.accounts is used by shouldBehaveLikeERC20 - const accounts = await ethers.getSigners(); - const [holder, recipient] = accounts; - - const token = await ethers.deployContract(Token, [name, symbol]); - await token.$_mint(holder, initialSupply); - - return { accounts, holder, recipient, token }; - }; - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeERC20(initialSupply, { 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.equal(18n); - }); - - describe('_mint', function () { - const value = 50n; - it('rejects a null account', async function () { - await expect(this.token.$_mint(ethers.ZeroAddress, value)) - .to.be.revertedWithCustomError(this.token, 'ERC20InvalidReceiver') - .withArgs(ethers.ZeroAddress); - }); - - it('rejects overflow', async function () { - await expect(this.token.$_mint(this.recipient, ethers.MaxUint256)).to.be.revertedWithPanic( - PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW, - ); - }); - - describe('for a non zero account', function () { - beforeEach('minting', async function () { - this.tx = await this.token.$_mint(this.recipient, value); - }); - - it('increments totalSupply', async function () { - await expect(await this.token.totalSupply()).to.equal(initialSupply + value); - }); - - it('increments recipient balance', async function () { - await expect(this.tx).to.changeTokenBalance(this.token, this.recipient, value); - }); - - it('emits Transfer event', async function () { - await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.recipient, value); - }); - }); - }); - - describe('_burn', function () { - it('rejects a null account', async function () { - await expect(this.token.$_burn(ethers.ZeroAddress, 1n)) - .to.be.revertedWithCustomError(this.token, 'ERC20InvalidSender') - .withArgs(ethers.ZeroAddress); - }); - - describe('for a non zero account', function () { - it('rejects burning more than balance', async function () { - await expect(this.token.$_burn(this.holder, initialSupply + 1n)) - .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') - .withArgs(this.holder, initialSupply, initialSupply + 1n); - }); - - const describeBurn = function (description, value) { - describe(description, function () { - beforeEach('burning', async function () { - this.tx = await this.token.$_burn(this.holder, value); - }); - - it('decrements totalSupply', async function () { - expect(await this.token.totalSupply()).to.equal(initialSupply - value); - }); - - it('decrements holder balance', async function () { - await expect(this.tx).to.changeTokenBalance(this.token, this.holder, -value); - }); - - it('emits Transfer event', async function () { - await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.holder, ethers.ZeroAddress, value); - }); - }); - }; - - describeBurn('for entire balance', initialSupply); - describeBurn('for less value than balance', initialSupply - 1n); - }); - }); - - describe('_update', function () { - const value = 1n; - - beforeEach(async function () { - this.totalSupply = await this.token.totalSupply(); - }); - - it('from is the zero address', async function () { - const tx = await this.token.$_update(ethers.ZeroAddress, this.holder, value); - await expect(tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.holder, value); - - expect(await this.token.totalSupply()).to.equal(this.totalSupply + value); - await expect(tx).to.changeTokenBalance(this.token, this.holder, value); - }); - - it('to is the zero address', async function () { - const tx = await this.token.$_update(this.holder, ethers.ZeroAddress, value); - await expect(tx).to.emit(this.token, 'Transfer').withArgs(this.holder, ethers.ZeroAddress, value); - - expect(await this.token.totalSupply()).to.equal(this.totalSupply - value); - await expect(tx).to.changeTokenBalance(this.token, this.holder, -value); - }); - - describe('from and to are the same address', function () { - it('zero address', async function () { - const tx = await this.token.$_update(ethers.ZeroAddress, ethers.ZeroAddress, value); - await expect(tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, ethers.ZeroAddress, value); - - expect(await this.token.totalSupply()).to.equal(this.totalSupply); - await expect(tx).to.changeTokenBalance(this.token, ethers.ZeroAddress, 0n); - }); - - describe('non zero address', function () { - it('reverts without balance', async function () { - await expect(this.token.$_update(this.recipient, this.recipient, value)) - .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') - .withArgs(this.recipient, 0n, value); - }); - - it('executes with balance', async function () { - const tx = await this.token.$_update(this.holder, this.holder, value); - await expect(tx).to.changeTokenBalance(this.token, this.holder, 0n); - await expect(tx).to.emit(this.token, 'Transfer').withArgs(this.holder, this.holder, value); - }); - }); - }); - }); - - describe('_transfer', function () { - beforeEach(function () { - this.transfer = this.token.$_transfer; - }); - - shouldBehaveLikeERC20Transfer(initialSupply); - - it('reverts when the sender is the zero address', async function () { - await expect(this.token.$_transfer(ethers.ZeroAddress, this.recipient, initialSupply)) - .to.be.revertedWithCustomError(this.token, 'ERC20InvalidSender') - .withArgs(ethers.ZeroAddress); - }); - }); - - describe('_approve', function () { - beforeEach(function () { - this.approve = this.token.$_approve; - }); - - shouldBehaveLikeERC20Approve(initialSupply); - - it('reverts when the owner is the zero address', async function () { - await expect(this.token.$_approve(ethers.ZeroAddress, this.recipient, initialSupply)) - .to.be.revertedWithCustomError(this.token, 'ERC20InvalidApprover') - .withArgs(ethers.ZeroAddress); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC1363.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC1363.test.js deleted file mode 100644 index 3d1f4e5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC1363.test.js +++ /dev/null @@ -1,370 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { - shouldBehaveLikeERC20, - shouldBehaveLikeERC20Transfer, - shouldBehaveLikeERC20Approve, -} = require('../ERC20.behavior.js'); -const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); -const { RevertType } = require('../../../helpers/enums.js'); - -const name = 'My Token'; -const symbol = 'MTKN'; -const value = 1000n; -const data = '0x123456'; - -async function fixture() { - // this.accounts is used by shouldBehaveLikeERC20 - const accounts = await ethers.getSigners(); - const [holder, other] = accounts; - - const receiver = await ethers.deployContract('ERC1363ReceiverMock'); - const spender = await ethers.deployContract('ERC1363SpenderMock'); - const token = await ethers.deployContract('$ERC1363', [name, symbol]); - - await token.$_mint(holder, value); - - return { - accounts, - holder, - other, - token, - receiver, - spender, - selectors: { - onTransferReceived: receiver.interface.getFunction('onTransferReceived(address,address,uint256,bytes)').selector, - onApprovalReceived: spender.interface.getFunction('onApprovalReceived(address,uint256,bytes)').selector, - }, - }; -} - -describe('ERC1363', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldSupportInterfaces(['ERC165', 'ERC1363']); - shouldBehaveLikeERC20(value); - - describe('transferAndCall', function () { - describe('as a transfer', function () { - beforeEach(async function () { - this.recipient = this.receiver; - this.transfer = (holder, ...rest) => - this.token.connect(holder).getFunction('transferAndCall(address,uint256)')(...rest); - }); - - shouldBehaveLikeERC20Transfer(value); - }); - - it('reverts transferring to an EOA', async function () { - await expect(this.token.connect(this.holder).getFunction('transferAndCall(address,uint256)')(this.other, value)) - .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidReceiver') - .withArgs(this.other.address); - }); - - it('succeeds without data', async function () { - await expect( - this.token.connect(this.holder).getFunction('transferAndCall(address,uint256)')(this.receiver, value), - ) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder.address, this.receiver.target, value) - .to.emit(this.receiver, 'Received') - .withArgs(this.holder.address, this.holder.address, value, '0x'); - }); - - it('succeeds with data', async function () { - await expect( - this.token.connect(this.holder).getFunction('transferAndCall(address,uint256,bytes)')( - this.receiver, - value, - data, - ), - ) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder.address, this.receiver.target, value) - .to.emit(this.receiver, 'Received') - .withArgs(this.holder.address, this.holder.address, value, data); - }); - - it('reverts with reverting hook (without reason)', async function () { - await this.receiver.setUp(this.selectors.onTransferReceived, RevertType.RevertWithoutMessage); - - await expect( - this.token.connect(this.holder).getFunction('transferAndCall(address,uint256,bytes)')( - this.receiver, - value, - data, - ), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidReceiver') - .withArgs(this.receiver.target); - }); - - it('reverts with reverting hook (with reason)', async function () { - await this.receiver.setUp(this.selectors.onTransferReceived, RevertType.RevertWithMessage); - - await expect( - this.token.connect(this.holder).getFunction('transferAndCall(address,uint256,bytes)')( - this.receiver, - value, - data, - ), - ).to.be.revertedWith('ERC1363ReceiverMock: reverting'); - }); - - it('reverts with reverting hook (with custom error)', async function () { - const reason = '0x12345678'; - await this.receiver.setUp(reason, RevertType.RevertWithCustomError); - - await expect( - this.token.connect(this.holder).getFunction('transferAndCall(address,uint256,bytes)')( - this.receiver, - value, - data, - ), - ) - .to.be.revertedWithCustomError(this.receiver, 'CustomError') - .withArgs(reason); - }); - - it('panics with reverting hook (with panic)', async function () { - await this.receiver.setUp(this.selectors.onTransferReceived, RevertType.Panic); - - await expect( - this.token.connect(this.holder).getFunction('transferAndCall(address,uint256,bytes)')( - this.receiver, - value, - data, - ), - ).to.be.revertedWithPanic(); - }); - - it('reverts with bad return value', async function () { - await this.receiver.setUp('0x12345678', RevertType.None); - - await expect( - this.token.connect(this.holder).getFunction('transferAndCall(address,uint256,bytes)')( - this.receiver, - value, - data, - ), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidReceiver') - .withArgs(this.receiver.target); - }); - }); - - describe('transferFromAndCall', function () { - beforeEach(async function () { - await this.token.connect(this.holder).approve(this.other, ethers.MaxUint256); - }); - - describe('as a transfer', function () { - beforeEach(async function () { - this.recipient = this.receiver; - this.transfer = this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256)'); - }); - - shouldBehaveLikeERC20Transfer(value); - }); - - it('reverts transferring to an EOA', async function () { - await expect( - this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256)')( - this.holder, - this.other, - value, - ), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidReceiver') - .withArgs(this.other.address); - }); - - it('succeeds without data', async function () { - await expect( - this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256)')( - this.holder, - this.receiver, - value, - ), - ) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder.address, this.receiver.target, value) - .to.emit(this.receiver, 'Received') - .withArgs(this.other.address, this.holder.address, value, '0x'); - }); - - it('succeeds with data', async function () { - await expect( - this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256,bytes)')( - this.holder, - this.receiver, - value, - data, - ), - ) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder.address, this.receiver.target, value) - .to.emit(this.receiver, 'Received') - .withArgs(this.other.address, this.holder.address, value, data); - }); - - it('reverts with reverting hook (without reason)', async function () { - await this.receiver.setUp(this.selectors.onTransferReceived, RevertType.RevertWithoutMessage); - - await expect( - this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256,bytes)')( - this.holder, - this.receiver, - value, - data, - ), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidReceiver') - .withArgs(this.receiver.target); - }); - - it('reverts with reverting hook (with reason)', async function () { - await this.receiver.setUp(this.selectors.onTransferReceived, RevertType.RevertWithMessage); - - await expect( - this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256,bytes)')( - this.holder, - this.receiver, - value, - data, - ), - ).to.be.revertedWith('ERC1363ReceiverMock: reverting'); - }); - - it('reverts with reverting hook (with custom error)', async function () { - const reason = '0x12345678'; - await this.receiver.setUp(reason, RevertType.RevertWithCustomError); - - await expect( - this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256,bytes)')( - this.holder, - this.receiver, - value, - data, - ), - ) - .to.be.revertedWithCustomError(this.receiver, 'CustomError') - .withArgs(reason); - }); - - it('panics with reverting hook (with panic)', async function () { - await this.receiver.setUp(this.selectors.onTransferReceived, RevertType.Panic); - - await expect( - this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256,bytes)')( - this.holder, - this.receiver, - value, - data, - ), - ).to.be.revertedWithPanic(); - }); - - it('reverts with bad return value', async function () { - await this.receiver.setUp('0x12345678', RevertType.None); - - await expect( - this.token.connect(this.other).getFunction('transferFromAndCall(address,address,uint256,bytes)')( - this.holder, - this.receiver, - value, - data, - ), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidReceiver') - .withArgs(this.receiver.target); - }); - }); - - describe('approveAndCall', function () { - describe('as an approval', function () { - beforeEach(async function () { - this.recipient = this.spender; - this.approve = (holder, ...rest) => - this.token.connect(holder).getFunction('approveAndCall(address,uint256)')(...rest); - }); - - shouldBehaveLikeERC20Approve(value); - }); - - it('reverts approving an EOA', async function () { - await expect(this.token.connect(this.holder).getFunction('approveAndCall(address,uint256)')(this.other, value)) - .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidSpender') - .withArgs(this.other.address); - }); - - it('succeeds without data', async function () { - await expect(this.token.connect(this.holder).getFunction('approveAndCall(address,uint256)')(this.spender, value)) - .to.emit(this.token, 'Approval') - .withArgs(this.holder.address, this.spender.target, value) - .to.emit(this.spender, 'Approved') - .withArgs(this.holder.address, value, '0x'); - }); - - it('succeeds with data', async function () { - await expect( - this.token.connect(this.holder).getFunction('approveAndCall(address,uint256,bytes)')(this.spender, value, data), - ) - .to.emit(this.token, 'Approval') - .withArgs(this.holder.address, this.spender.target, value) - .to.emit(this.spender, 'Approved') - .withArgs(this.holder.address, value, data); - }); - - it('with reverting hook (without reason)', async function () { - await this.spender.setUp(this.selectors.onApprovalReceived, RevertType.RevertWithoutMessage); - - await expect( - this.token.connect(this.holder).getFunction('approveAndCall(address,uint256,bytes)')(this.spender, value, data), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidSpender') - .withArgs(this.spender.target); - }); - - it('reverts with reverting hook (with reason)', async function () { - await this.spender.setUp(this.selectors.onApprovalReceived, RevertType.RevertWithMessage); - - await expect( - this.token.connect(this.holder).getFunction('approveAndCall(address,uint256,bytes)')(this.spender, value, data), - ).to.be.revertedWith('ERC1363SpenderMock: reverting'); - }); - - it('reverts with reverting hook (with custom error)', async function () { - const reason = '0x12345678'; - await this.spender.setUp(reason, RevertType.RevertWithCustomError); - - await expect( - this.token.connect(this.holder).getFunction('approveAndCall(address,uint256,bytes)')(this.spender, value, data), - ) - .to.be.revertedWithCustomError(this.spender, 'CustomError') - .withArgs(reason); - }); - - it('panics with reverting hook (with panic)', async function () { - await this.spender.setUp(this.selectors.onApprovalReceived, RevertType.Panic); - - await expect( - this.token.connect(this.holder).getFunction('approveAndCall(address,uint256,bytes)')(this.spender, value, data), - ).to.be.revertedWithPanic(); - }); - - it('reverts with bad return value', async function () { - await this.spender.setUp('0x12345678', RevertType.None); - - await expect( - this.token.connect(this.holder).getFunction('approveAndCall(address,uint256,bytes)')(this.spender, value, data), - ) - .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidSpender') - .withArgs(this.spender.target); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js deleted file mode 100644 index dc40c79..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js +++ /dev/null @@ -1,105 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const name = 'My Token'; -const symbol = 'MTKN'; -const initialBalance = 1000n; - -async function fixture() { - const [owner, burner] = await ethers.getSigners(); - - const token = await ethers.deployContract('$ERC20Burnable', [name, symbol], owner); - await token.$_mint(owner, initialBalance); - - return { owner, burner, token, initialBalance }; -} - -describe('ERC20Burnable', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('burn', function () { - it('reverts if not enough balance', async function () { - const value = this.initialBalance + 1n; - - await expect(this.token.connect(this.owner).burn(value)) - .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') - .withArgs(this.owner, this.initialBalance, value); - }); - - describe('on success', function () { - for (const { title, value } of [ - { title: 'for a zero value', value: 0n }, - { title: 'for a non-zero value', value: 100n }, - ]) { - describe(title, function () { - beforeEach(async function () { - this.tx = await this.token.connect(this.owner).burn(value); - }); - - it('burns the requested value', async function () { - await expect(this.tx).to.changeTokenBalance(this.token, this.owner, -value); - }); - - it('emits a transfer event', async function () { - await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.owner, ethers.ZeroAddress, value); - }); - }); - } - }); - }); - - describe('burnFrom', function () { - describe('reverts', function () { - it('if not enough balance', async function () { - const value = this.initialBalance + 1n; - - await this.token.connect(this.owner).approve(this.burner, value); - - await expect(this.token.connect(this.burner).burnFrom(this.owner, value)) - .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') - .withArgs(this.owner, this.initialBalance, value); - }); - - it('if not enough allowance', async function () { - const allowance = 100n; - - await this.token.connect(this.owner).approve(this.burner, allowance); - - await expect(this.token.connect(this.burner).burnFrom(this.owner, allowance + 1n)) - .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientAllowance') - .withArgs(this.burner, allowance, allowance + 1n); - }); - }); - - describe('on success', function () { - for (const { title, value } of [ - { title: 'for a zero value', value: 0n }, - { title: 'for a non-zero value', value: 100n }, - ]) { - describe(title, function () { - const originalAllowance = value * 3n; - - beforeEach(async function () { - await this.token.connect(this.owner).approve(this.burner, originalAllowance); - this.tx = await this.token.connect(this.burner).burnFrom(this.owner, value); - }); - - it('burns the requested value', async function () { - await expect(this.tx).to.changeTokenBalance(this.token, this.owner, -value); - }); - - it('decrements allowance', async function () { - expect(await this.token.allowance(this.owner, this.burner)).to.equal(originalAllowance - value); - }); - - it('emits a transfer event', async function () { - await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.owner, ethers.ZeroAddress, value); - }); - }); - } - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js deleted file mode 100644 index a32ec43..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js +++ /dev/null @@ -1,55 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const name = 'My Token'; -const symbol = 'MTKN'; -const cap = 1000n; - -async function fixture() { - const [user] = await ethers.getSigners(); - - const token = await ethers.deployContract('$ERC20Capped', [name, symbol, cap]); - - return { user, token, cap }; -} - -describe('ERC20Capped', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('requires a non-zero cap', async function () { - const ERC20Capped = await ethers.getContractFactory('$ERC20Capped'); - - await expect(ERC20Capped.deploy(name, symbol, 0)) - .to.be.revertedWithCustomError(ERC20Capped, 'ERC20InvalidCap') - .withArgs(0); - }); - - describe('capped token', function () { - it('starts with the correct cap', async function () { - expect(await this.token.cap()).to.equal(this.cap); - }); - - it('mints when value is less than cap', async function () { - const value = this.cap - 1n; - await this.token.$_mint(this.user, value); - expect(await this.token.totalSupply()).to.equal(value); - }); - - it('fails to mint if the value exceeds the cap', async function () { - await this.token.$_mint(this.user, this.cap - 1n); - await expect(this.token.$_mint(this.user, 2)) - .to.be.revertedWithCustomError(this.token, 'ERC20ExceededCap') - .withArgs(this.cap + 1n, this.cap); - }); - - it('fails to mint after cap is reached', async function () { - await this.token.$_mint(this.user, this.cap); - await expect(this.token.$_mint(this.user, 1)) - .to.be.revertedWithCustomError(this.token, 'ERC20ExceededCap') - .withArgs(this.cap + 1n, this.cap); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js deleted file mode 100644 index 1c751f7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js +++ /dev/null @@ -1,164 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const name = 'My Token'; -const symbol = 'MTKN'; -const initialSupply = 100n; -const loanValue = 10_000_000_000_000n; - -async function fixture() { - const [holder, other] = await ethers.getSigners(); - - const token = await ethers.deployContract('$ERC20FlashMintMock', [name, symbol]); - await token.$_mint(holder, initialSupply); - - return { holder, other, token }; -} - -describe('ERC20FlashMint', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('maxFlashLoan', function () { - it('token match', async function () { - expect(await this.token.maxFlashLoan(this.token)).to.equal(ethers.MaxUint256 - initialSupply); - }); - - it('token mismatch', async function () { - expect(await this.token.maxFlashLoan(ethers.ZeroAddress)).to.equal(0n); - }); - }); - - describe('flashFee', function () { - it('token match', async function () { - expect(await this.token.flashFee(this.token, loanValue)).to.equal(0n); - }); - - it('token mismatch', async function () { - await expect(this.token.flashFee(ethers.ZeroAddress, loanValue)) - .to.be.revertedWithCustomError(this.token, 'ERC3156UnsupportedToken') - .withArgs(ethers.ZeroAddress); - }); - }); - - describe('flashFeeReceiver', function () { - it('default receiver', async function () { - expect(await this.token.$_flashFeeReceiver()).to.equal(ethers.ZeroAddress); - }); - }); - - describe('flashLoan', function () { - it('success', async function () { - const receiver = await ethers.deployContract('ERC3156FlashBorrowerMock', [true, true]); - - const tx = await this.token.flashLoan(receiver, this.token, loanValue, '0x'); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, receiver, loanValue) - .to.emit(this.token, 'Transfer') - .withArgs(receiver, ethers.ZeroAddress, loanValue) - .to.emit(receiver, 'BalanceOf') - .withArgs(this.token, receiver, loanValue) - .to.emit(receiver, 'TotalSupply') - .withArgs(this.token, initialSupply + loanValue); - await expect(tx).to.changeTokenBalance(this.token, receiver, 0); - - expect(await this.token.totalSupply()).to.equal(initialSupply); - expect(await this.token.allowance(receiver, this.token)).to.equal(0n); - }); - - it('missing return value', async function () { - const receiver = await ethers.deployContract('ERC3156FlashBorrowerMock', [false, true]); - await expect(this.token.flashLoan(receiver, this.token, loanValue, '0x')) - .to.be.revertedWithCustomError(this.token, 'ERC3156InvalidReceiver') - .withArgs(receiver); - }); - - it('missing approval', async function () { - const receiver = await ethers.deployContract('ERC3156FlashBorrowerMock', [true, false]); - await expect(this.token.flashLoan(receiver, this.token, loanValue, '0x')) - .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientAllowance') - .withArgs(this.token, 0, loanValue); - }); - - it('unavailable funds', async function () { - const receiver = await ethers.deployContract('ERC3156FlashBorrowerMock', [true, true]); - const data = this.token.interface.encodeFunctionData('transfer', [this.other.address, 10]); - await expect(this.token.flashLoan(receiver, this.token, loanValue, data)) - .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') - .withArgs(receiver, loanValue - 10n, loanValue); - }); - - it('more than maxFlashLoan', async function () { - const receiver = await ethers.deployContract('ERC3156FlashBorrowerMock', [true, true]); - const data = this.token.interface.encodeFunctionData('transfer', [this.other.address, 10]); - await expect(this.token.flashLoan(receiver, this.token, ethers.MaxUint256, data)) - .to.be.revertedWithCustomError(this.token, 'ERC3156ExceededMaxLoan') - .withArgs(ethers.MaxUint256 - initialSupply); - }); - - describe('custom flash fee & custom fee receiver', function () { - const receiverInitialBalance = 200_000n; - const flashFee = 5_000n; - - beforeEach('init receiver balance & set flash fee', async function () { - this.receiver = await ethers.deployContract('ERC3156FlashBorrowerMock', [true, true]); - - const tx = await this.token.$_mint(this.receiver, receiverInitialBalance); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.receiver, receiverInitialBalance); - await expect(tx).to.changeTokenBalance(this.token, this.receiver, receiverInitialBalance); - - await this.token.setFlashFee(flashFee); - expect(await this.token.flashFee(this.token, loanValue)).to.equal(flashFee); - }); - - it('default flash fee receiver', async function () { - const tx = await this.token.flashLoan(this.receiver, this.token, loanValue, '0x'); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.receiver, loanValue) - .to.emit(this.token, 'Transfer') - .withArgs(this.receiver, ethers.ZeroAddress, loanValue + flashFee) - .to.emit(this.receiver, 'BalanceOf') - .withArgs(this.token, this.receiver, receiverInitialBalance + loanValue) - .to.emit(this.receiver, 'TotalSupply') - .withArgs(this.token, initialSupply + receiverInitialBalance + loanValue); - await expect(tx).to.changeTokenBalances(this.token, [this.receiver, ethers.ZeroAddress], [-flashFee, 0]); - - expect(await this.token.totalSupply()).to.equal(initialSupply + receiverInitialBalance - flashFee); - expect(await this.token.allowance(this.receiver, this.token)).to.equal(0n); - }); - - it('custom flash fee receiver', async function () { - const flashFeeReceiverAddress = this.other; - await this.token.setFlashFeeReceiver(flashFeeReceiverAddress); - expect(await this.token.$_flashFeeReceiver()).to.equal(flashFeeReceiverAddress); - - const tx = await this.token.flashLoan(this.receiver, this.token, loanValue, '0x'); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.receiver, loanValue) - .to.emit(this.token, 'Transfer') - .withArgs(this.receiver, ethers.ZeroAddress, loanValue) - .to.emit(this.token, 'Transfer') - .withArgs(this.receiver, flashFeeReceiverAddress, flashFee) - .to.emit(this.receiver, 'BalanceOf') - .withArgs(this.token, this.receiver, receiverInitialBalance + loanValue) - .to.emit(this.receiver, 'TotalSupply') - .withArgs(this.token, initialSupply + receiverInitialBalance + loanValue); - await expect(tx).to.changeTokenBalances( - this.token, - [this.receiver, flashFeeReceiverAddress], - [-flashFee, flashFee], - ); - - expect(await this.token.totalSupply()).to.equal(initialSupply + receiverInitialBalance); - expect(await this.token.allowance(this.receiver, flashFeeReceiverAddress)).to.equal(0n); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js deleted file mode 100644 index 1f1157c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js +++ /dev/null @@ -1,129 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const name = 'My Token'; -const symbol = 'MTKN'; -const initialSupply = 100n; - -async function fixture() { - const [holder, recipient, approved] = await ethers.getSigners(); - - const token = await ethers.deployContract('$ERC20Pausable', [name, symbol]); - await token.$_mint(holder, initialSupply); - - return { holder, recipient, approved, token }; -} - -describe('ERC20Pausable', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('pausable token', function () { - describe('transfer', function () { - it('allows to transfer when unpaused', async function () { - await expect(this.token.connect(this.holder).transfer(this.recipient, initialSupply)).to.changeTokenBalances( - this.token, - [this.holder, this.recipient], - [-initialSupply, initialSupply], - ); - }); - - it('allows to transfer when paused and then unpaused', async function () { - await this.token.$_pause(); - await this.token.$_unpause(); - - await expect(this.token.connect(this.holder).transfer(this.recipient, initialSupply)).to.changeTokenBalances( - this.token, - [this.holder, this.recipient], - [-initialSupply, initialSupply], - ); - }); - - it('reverts when trying to transfer when paused', async function () { - await this.token.$_pause(); - - await expect( - this.token.connect(this.holder).transfer(this.recipient, initialSupply), - ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); - }); - }); - - describe('transfer from', function () { - const allowance = 40n; - - beforeEach(async function () { - await this.token.connect(this.holder).approve(this.approved, allowance); - }); - - it('allows to transfer from when unpaused', async function () { - await expect( - this.token.connect(this.approved).transferFrom(this.holder, this.recipient, allowance), - ).to.changeTokenBalances(this.token, [this.holder, this.recipient], [-allowance, allowance]); - }); - - it('allows to transfer when paused and then unpaused', async function () { - await this.token.$_pause(); - await this.token.$_unpause(); - - await expect( - this.token.connect(this.approved).transferFrom(this.holder, this.recipient, allowance), - ).to.changeTokenBalances(this.token, [this.holder, this.recipient], [-allowance, allowance]); - }); - - it('reverts when trying to transfer from when paused', async function () { - await this.token.$_pause(); - - await expect( - this.token.connect(this.approved).transferFrom(this.holder, this.recipient, allowance), - ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); - }); - }); - - describe('mint', function () { - const value = 42n; - - it('allows to mint when unpaused', async function () { - await expect(this.token.$_mint(this.recipient, value)).to.changeTokenBalance(this.token, this.recipient, value); - }); - - it('allows to mint when paused and then unpaused', async function () { - await this.token.$_pause(); - await this.token.$_unpause(); - - await expect(this.token.$_mint(this.recipient, value)).to.changeTokenBalance(this.token, this.recipient, value); - }); - - it('reverts when trying to mint when paused', async function () { - await this.token.$_pause(); - - await expect(this.token.$_mint(this.recipient, value)).to.be.revertedWithCustomError( - this.token, - 'EnforcedPause', - ); - }); - }); - - describe('burn', function () { - const value = 42n; - - it('allows to burn when unpaused', async function () { - await expect(this.token.$_burn(this.holder, value)).to.changeTokenBalance(this.token, this.holder, -value); - }); - - it('allows to burn when paused and then unpaused', async function () { - await this.token.$_pause(); - await this.token.$_unpause(); - - await expect(this.token.$_burn(this.holder, value)).to.changeTokenBalance(this.token, this.holder, -value); - }); - - it('reverts when trying to burn when paused', async function () { - await this.token.$_pause(); - - await expect(this.token.$_burn(this.holder, value)).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Permit.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Permit.test.js deleted file mode 100644 index c3c80d7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Permit.test.js +++ /dev/null @@ -1,109 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain, domainSeparator, Permit } = require('../../../helpers/eip712'); -const time = require('../../../helpers/time'); - -const name = 'My Token'; -const symbol = 'MTKN'; -const initialSupply = 100n; - -async function fixture() { - const [holder, spender, owner, other] = await ethers.getSigners(); - - const token = await ethers.deployContract('$ERC20Permit', [name, symbol, name]); - await token.$_mint(holder, initialSupply); - - return { - holder, - spender, - owner, - other, - token, - }; -} - -describe('ERC20Permit', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('initial nonce is 0', async function () { - expect(await this.token.nonces(this.holder)).to.equal(0n); - }); - - it('domain separator', async function () { - expect(await this.token.DOMAIN_SEPARATOR()).to.equal(await getDomain(this.token).then(domainSeparator)); - }); - - describe('permit', function () { - const value = 42n; - const nonce = 0n; - const maxDeadline = ethers.MaxUint256; - - beforeEach(function () { - this.buildData = (contract, deadline = maxDeadline) => - getDomain(contract).then(domain => ({ - domain, - types: { Permit }, - message: { - owner: this.owner.address, - spender: this.spender.address, - value, - nonce, - deadline, - }, - })); - }); - - it('accepts owner signature', async function () { - const { v, r, s } = await this.buildData(this.token) - .then(({ domain, types, message }) => this.owner.signTypedData(domain, types, message)) - .then(ethers.Signature.from); - - await this.token.permit(this.owner, this.spender, value, maxDeadline, v, r, s); - - expect(await this.token.nonces(this.owner)).to.equal(1n); - expect(await this.token.allowance(this.owner, this.spender)).to.equal(value); - }); - - it('rejects reused signature', async function () { - const { v, r, s, serialized } = await this.buildData(this.token) - .then(({ domain, types, message }) => this.owner.signTypedData(domain, types, message)) - .then(ethers.Signature.from); - - await this.token.permit(this.owner, this.spender, value, maxDeadline, v, r, s); - - const recovered = await this.buildData(this.token).then(({ domain, types, message }) => - ethers.verifyTypedData(domain, types, { ...message, nonce: nonce + 1n, deadline: maxDeadline }, serialized), - ); - - await expect(this.token.permit(this.owner, this.spender, value, maxDeadline, v, r, s)) - .to.be.revertedWithCustomError(this.token, 'ERC2612InvalidSigner') - .withArgs(recovered, this.owner); - }); - - it('rejects other signature', async function () { - const { v, r, s } = await this.buildData(this.token) - .then(({ domain, types, message }) => this.other.signTypedData(domain, types, message)) - .then(ethers.Signature.from); - - await expect(this.token.permit(this.owner, this.spender, value, maxDeadline, v, r, s)) - .to.be.revertedWithCustomError(this.token, 'ERC2612InvalidSigner') - .withArgs(this.other, this.owner); - }); - - it('rejects expired permit', async function () { - const deadline = (await time.clock.timestamp()) - time.duration.weeks(1); - - const { v, r, s } = await this.buildData(this.token, deadline) - .then(({ domain, types, message }) => this.owner.signTypedData(domain, types, message)) - .then(ethers.Signature.from); - - await expect(this.token.permit(this.owner, this.spender, value, deadline, v, r, s)) - .to.be.revertedWithCustomError(this.token, 'ERC2612ExpiredSignature') - .withArgs(deadline); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js deleted file mode 100644 index 3c595c9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js +++ /dev/null @@ -1,546 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain, Delegation } = require('../../../helpers/eip712'); -const { batchInBlock } = require('../../../helpers/txpool'); -const time = require('../../../helpers/time'); - -const { shouldBehaveLikeVotes } = require('../../../governance/utils/Votes.behavior'); - -const TOKENS = [ - { Token: '$ERC20Votes', mode: 'blocknumber' }, - { Token: '$ERC20VotesTimestampMock', mode: 'timestamp' }, -]; - -const name = 'My Token'; -const symbol = 'MTKN'; -const version = '1'; -const supply = ethers.parseEther('10000000'); - -describe('ERC20Votes', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - // accounts is required by shouldBehaveLikeVotes - const accounts = await ethers.getSigners(); - const [holder, recipient, delegatee, other1, other2] = accounts; - - const token = await ethers.deployContract(Token, [name, symbol, name, version]); - const domain = await getDomain(token); - - return { accounts, holder, recipient, delegatee, other1, other2, token, domain }; - }; - - describe(`vote with ${mode}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - this.votes = this.token; - }); - - // includes ERC6372 behavior check - shouldBehaveLikeVotes([1, 17, 42], { mode, fungible: true }); - - it('initial nonce is 0', async function () { - expect(await this.token.nonces(this.holder)).to.equal(0n); - }); - - it('minting restriction', async function () { - const value = 2n ** 208n; - await expect(this.token.$_mint(this.holder, value)) - .to.be.revertedWithCustomError(this.token, 'ERC20ExceededSafeSupply') - .withArgs(value, value - 1n); - }); - - it('recent checkpoints', async function () { - await this.token.connect(this.holder).delegate(this.holder); - for (let i = 0; i < 6; i++) { - await this.token.$_mint(this.holder, 1n); - } - const timepoint = await time.clock[mode](); - expect(await this.token.numCheckpoints(this.holder)).to.equal(6n); - // recent - expect(await this.token.getPastVotes(this.holder, timepoint - 1n)).to.equal(5n); - // non-recent - expect(await this.token.getPastVotes(this.holder, timepoint - 6n)).to.equal(0n); - }); - - describe('set delegation', function () { - describe('call', function () { - it('delegation with balance', async function () { - await this.token.$_mint(this.holder, supply); - expect(await this.token.delegates(this.holder)).to.equal(ethers.ZeroAddress); - - const tx = await this.token.connect(this.holder).delegate(this.holder); - const timepoint = await time.clockFromReceipt[mode](tx); - - await expect(tx) - .to.emit(this.token, 'DelegateChanged') - .withArgs(this.holder, ethers.ZeroAddress, this.holder) - .to.emit(this.token, 'DelegateVotesChanged') - .withArgs(this.holder, 0n, supply); - - expect(await this.token.delegates(this.holder)).to.equal(this.holder); - expect(await this.token.getVotes(this.holder)).to.equal(supply); - expect(await this.token.getPastVotes(this.holder, timepoint - 1n)).to.equal(0n); - await mine(); - expect(await this.token.getPastVotes(this.holder, timepoint)).to.equal(supply); - }); - - it('delegation without balance', async function () { - expect(await this.token.delegates(this.holder)).to.equal(ethers.ZeroAddress); - - await expect(this.token.connect(this.holder).delegate(this.holder)) - .to.emit(this.token, 'DelegateChanged') - .withArgs(this.holder, ethers.ZeroAddress, this.holder) - .to.not.emit(this.token, 'DelegateVotesChanged'); - - expect(await this.token.delegates(this.holder)).to.equal(this.holder); - }); - }); - - describe('with signature', function () { - const nonce = 0n; - - beforeEach(async function () { - await this.token.$_mint(this.holder, supply); - }); - - it('accept signed delegation', async function () { - const { r, s, v } = await this.holder - .signTypedData( - this.domain, - { Delegation }, - { - delegatee: this.holder.address, - nonce, - expiry: ethers.MaxUint256, - }, - ) - .then(ethers.Signature.from); - - expect(await this.token.delegates(this.holder)).to.equal(ethers.ZeroAddress); - - const tx = await this.token.delegateBySig(this.holder, nonce, ethers.MaxUint256, v, r, s); - const timepoint = await time.clockFromReceipt[mode](tx); - - await expect(tx) - .to.emit(this.token, 'DelegateChanged') - .withArgs(this.holder, ethers.ZeroAddress, this.holder) - .to.emit(this.token, 'DelegateVotesChanged') - .withArgs(this.holder, 0n, supply); - - expect(await this.token.delegates(this.holder)).to.equal(this.holder); - - expect(await this.token.getVotes(this.holder)).to.equal(supply); - expect(await this.token.getPastVotes(this.holder, timepoint - 1n)).to.equal(0n); - await mine(); - expect(await this.token.getPastVotes(this.holder, timepoint)).to.equal(supply); - }); - - it('rejects reused signature', async function () { - const { r, s, v } = await this.holder - .signTypedData( - this.domain, - { Delegation }, - { - delegatee: this.holder.address, - nonce, - expiry: ethers.MaxUint256, - }, - ) - .then(ethers.Signature.from); - - await this.token.delegateBySig(this.holder, nonce, ethers.MaxUint256, v, r, s); - - await expect(this.token.delegateBySig(this.holder, nonce, ethers.MaxUint256, v, r, s)) - .to.be.revertedWithCustomError(this.token, 'InvalidAccountNonce') - .withArgs(this.holder, nonce + 1n); - }); - - it('rejects bad delegatee', async function () { - const { r, s, v } = await this.holder - .signTypedData( - this.domain, - { Delegation }, - { - delegatee: this.holder.address, - nonce, - expiry: ethers.MaxUint256, - }, - ) - .then(ethers.Signature.from); - - const tx = await this.token.delegateBySig(this.delegatee, nonce, ethers.MaxUint256, v, r, s); - - const { args } = await tx - .wait() - .then(receipt => receipt.logs.find(event => event.fragment.name == 'DelegateChanged')); - expect(args[0]).to.not.equal(this.holder); - expect(args[1]).to.equal(ethers.ZeroAddress); - expect(args[2]).to.equal(this.delegatee); - }); - - it('rejects bad nonce', async function () { - const { r, s, v, serialized } = await this.holder - .signTypedData( - this.domain, - { Delegation }, - { - delegatee: this.holder.address, - nonce, - expiry: ethers.MaxUint256, - }, - ) - .then(ethers.Signature.from); - - const recovered = ethers.verifyTypedData( - this.domain, - { Delegation }, - { - delegatee: this.holder.address, - nonce: nonce + 1n, - expiry: ethers.MaxUint256, - }, - serialized, - ); - - await expect(this.token.delegateBySig(this.holder, nonce + 1n, ethers.MaxUint256, v, r, s)) - .to.be.revertedWithCustomError(this.token, 'InvalidAccountNonce') - .withArgs(recovered, nonce); - }); - - it('rejects expired permit', async function () { - const expiry = (await time.clock.timestamp()) - time.duration.weeks(1); - - const { r, s, v } = await this.holder - .signTypedData( - this.domain, - { Delegation }, - { - delegatee: this.holder.address, - nonce, - expiry, - }, - ) - .then(ethers.Signature.from); - - await expect(this.token.delegateBySig(this.holder, nonce, expiry, v, r, s)) - .to.be.revertedWithCustomError(this.token, 'VotesExpiredSignature') - .withArgs(expiry); - }); - }); - }); - - describe('change delegation', function () { - beforeEach(async function () { - await this.token.$_mint(this.holder, supply); - await this.token.connect(this.holder).delegate(this.holder); - }); - - it('call', async function () { - expect(await this.token.delegates(this.holder)).to.equal(this.holder); - - const tx = await this.token.connect(this.holder).delegate(this.delegatee); - const timepoint = await time.clockFromReceipt[mode](tx); - - await expect(tx) - .to.emit(this.token, 'DelegateChanged') - .withArgs(this.holder, this.holder, this.delegatee) - .to.emit(this.token, 'DelegateVotesChanged') - .withArgs(this.holder, supply, 0n) - .to.emit(this.token, 'DelegateVotesChanged') - .withArgs(this.delegatee, 0n, supply); - - expect(await this.token.delegates(this.holder)).to.equal(this.delegatee); - - expect(await this.token.getVotes(this.holder)).to.equal(0n); - expect(await this.token.getVotes(this.delegatee)).to.equal(supply); - expect(await this.token.getPastVotes(this.holder, timepoint - 1n)).to.equal(supply); - expect(await this.token.getPastVotes(this.delegatee, timepoint - 1n)).to.equal(0n); - await mine(); - expect(await this.token.getPastVotes(this.holder, timepoint)).to.equal(0n); - expect(await this.token.getPastVotes(this.delegatee, timepoint)).to.equal(supply); - }); - }); - - describe('transfers', function () { - beforeEach(async function () { - await this.token.$_mint(this.holder, supply); - }); - - it('no delegation', async function () { - await expect(this.token.connect(this.holder).transfer(this.recipient, 1n)) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.recipient, 1n) - .to.not.emit(this.token, 'DelegateVotesChanged'); - - this.holderVotes = 0n; - this.recipientVotes = 0n; - }); - - it('sender delegation', async function () { - await this.token.connect(this.holder).delegate(this.holder); - - const tx = await this.token.connect(this.holder).transfer(this.recipient, 1n); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.recipient, 1n) - .to.emit(this.token, 'DelegateVotesChanged') - .withArgs(this.holder, supply, supply - 1n); - - const { logs } = await tx.wait(); - const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged'); - for (const event of logs.filter(event => event.fragment.name == 'Transfer')) { - expect(event.index).to.lt(index); - } - - this.holderVotes = supply - 1n; - this.recipientVotes = 0n; - }); - - it('receiver delegation', async function () { - await this.token.connect(this.recipient).delegate(this.recipient); - - const tx = await this.token.connect(this.holder).transfer(this.recipient, 1n); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.recipient, 1n) - .to.emit(this.token, 'DelegateVotesChanged') - .withArgs(this.recipient, 0n, 1n); - - const { logs } = await tx.wait(); - const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged'); - for (const event of logs.filter(event => event.fragment.name == 'Transfer')) { - expect(event.index).to.lt(index); - } - - this.holderVotes = 0n; - this.recipientVotes = 1n; - }); - - it('full delegation', async function () { - await this.token.connect(this.holder).delegate(this.holder); - await this.token.connect(this.recipient).delegate(this.recipient); - - const tx = await this.token.connect(this.holder).transfer(this.recipient, 1n); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.recipient, 1n) - .to.emit(this.token, 'DelegateVotesChanged') - .withArgs(this.holder, supply, supply - 1n) - .to.emit(this.token, 'DelegateVotesChanged') - .withArgs(this.recipient, 0n, 1n); - - const { logs } = await tx.wait(); - const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged'); - for (const event of logs.filter(event => event.fragment.name == 'Transfer')) { - expect(event.index).to.lt(index); - } - - this.holderVotes = supply - 1n; - this.recipientVotes = 1n; - }); - - afterEach(async function () { - expect(await this.token.getVotes(this.holder)).to.equal(this.holderVotes); - expect(await this.token.getVotes(this.recipient)).to.equal(this.recipientVotes); - - // need to advance 2 blocks to see the effect of a transfer on "getPastVotes" - const timepoint = await time.clock[mode](); - await mine(); - expect(await this.token.getPastVotes(this.holder, timepoint)).to.equal(this.holderVotes); - expect(await this.token.getPastVotes(this.recipient, timepoint)).to.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(this.holder, supply); - }); - - describe('balanceOf', function () { - it('grants to initial account', async function () { - expect(await this.token.balanceOf(this.holder)).to.equal(supply); - }); - }); - - describe('numCheckpoints', function () { - it('returns the number of checkpoints for a delegate', async function () { - await this.token.connect(this.holder).transfer(this.recipient, 100n); //give an account a few tokens for readability - expect(await this.token.numCheckpoints(this.other1)).to.equal(0n); - - const t1 = await this.token.connect(this.recipient).delegate(this.other1); - t1.timepoint = await time.clockFromReceipt[mode](t1); - expect(await this.token.numCheckpoints(this.other1)).to.equal(1n); - - const t2 = await this.token.connect(this.recipient).transfer(this.other2, 10); - t2.timepoint = await time.clockFromReceipt[mode](t2); - expect(await this.token.numCheckpoints(this.other1)).to.equal(2n); - - const t3 = await this.token.connect(this.recipient).transfer(this.other2, 10); - t3.timepoint = await time.clockFromReceipt[mode](t3); - expect(await this.token.numCheckpoints(this.other1)).to.equal(3n); - - const t4 = await this.token.connect(this.holder).transfer(this.recipient, 20); - t4.timepoint = await time.clockFromReceipt[mode](t4); - expect(await this.token.numCheckpoints(this.other1)).to.equal(4n); - - expect(await this.token.checkpoints(this.other1, 0n)).to.deep.equal([t1.timepoint, 100n]); - expect(await this.token.checkpoints(this.other1, 1n)).to.deep.equal([t2.timepoint, 90n]); - expect(await this.token.checkpoints(this.other1, 2n)).to.deep.equal([t3.timepoint, 80n]); - expect(await this.token.checkpoints(this.other1, 3n)).to.deep.equal([t4.timepoint, 100n]); - await mine(); - expect(await this.token.getPastVotes(this.other1, t1.timepoint)).to.equal(100n); - expect(await this.token.getPastVotes(this.other1, t2.timepoint)).to.equal(90n); - expect(await this.token.getPastVotes(this.other1, t3.timepoint)).to.equal(80n); - expect(await this.token.getPastVotes(this.other1, t4.timepoint)).to.equal(100n); - }); - - it('does not add more than one checkpoint in a block', async function () { - await this.token.connect(this.holder).transfer(this.recipient, 100n); - expect(await this.token.numCheckpoints(this.other1)).to.equal(0n); - - const [t1, t2, t3] = await batchInBlock([ - () => this.token.connect(this.recipient).delegate(this.other1, { gasLimit: 200000 }), - () => this.token.connect(this.recipient).transfer(this.other2, 10n, { gasLimit: 200000 }), - () => this.token.connect(this.recipient).transfer(this.other2, 10n, { gasLimit: 200000 }), - ]); - t1.timepoint = await time.clockFromReceipt[mode](t1); - t2.timepoint = await time.clockFromReceipt[mode](t2); - t3.timepoint = await time.clockFromReceipt[mode](t3); - - expect(await this.token.numCheckpoints(this.other1)).to.equal(1); - expect(await this.token.checkpoints(this.other1, 0n)).to.be.deep.equal([t1.timepoint, 80n]); - - const t4 = await this.token.connect(this.holder).transfer(this.recipient, 20n); - t4.timepoint = await time.clockFromReceipt[mode](t4); - - expect(await this.token.numCheckpoints(this.other1)).to.equal(2n); - expect(await this.token.checkpoints(this.other1, 1n)).to.be.deep.equal([t4.timepoint, 100n]); - }); - }); - - describe('getPastVotes', function () { - it('reverts if block number >= current block', async function () { - const clock = await this.token.clock(); - await expect(this.token.getPastVotes(this.other1, 50_000_000_000n)) - .to.be.revertedWithCustomError(this.token, 'ERC5805FutureLookup') - .withArgs(50_000_000_000n, clock); - }); - - it('returns 0 if there are no checkpoints', async function () { - expect(await this.token.getPastVotes(this.other1, 0n)).to.equal(0n); - }); - - it('returns the latest block if >= last checkpoint block', async function () { - const tx = await this.token.connect(this.holder).delegate(this.other1); - const timepoint = await time.clockFromReceipt[mode](tx); - await mine(2); - - expect(await this.token.getPastVotes(this.other1, timepoint)).to.equal(supply); - expect(await this.token.getPastVotes(this.other1, timepoint + 1n)).to.equal(supply); - }); - - it('returns zero if < first checkpoint block', async function () { - await mine(); - const tx = await this.token.connect(this.holder).delegate(this.other1); - const timepoint = await time.clockFromReceipt[mode](tx); - await mine(2); - - expect(await this.token.getPastVotes(this.other1, timepoint - 1n)).to.equal(0n); - expect(await this.token.getPastVotes(this.other1, timepoint + 1n)).to.equal(supply); - }); - - it('generally returns the voting balance at the appropriate checkpoint', async function () { - const t1 = await this.token.connect(this.holder).delegate(this.other1); - await mine(2); - const t2 = await this.token.connect(this.holder).transfer(this.other2, 10); - await mine(2); - const t3 = await this.token.connect(this.holder).transfer(this.other2, 10); - await mine(2); - const t4 = await this.token.connect(this.other2).transfer(this.holder, 20); - await mine(2); - - t1.timepoint = await time.clockFromReceipt[mode](t1); - t2.timepoint = await time.clockFromReceipt[mode](t2); - t3.timepoint = await time.clockFromReceipt[mode](t3); - t4.timepoint = await time.clockFromReceipt[mode](t4); - - expect(await this.token.getPastVotes(this.other1, t1.timepoint - 1n)).to.equal(0n); - expect(await this.token.getPastVotes(this.other1, t1.timepoint)).to.equal(supply); - expect(await this.token.getPastVotes(this.other1, t1.timepoint + 1n)).to.equal(supply); - expect(await this.token.getPastVotes(this.other1, t2.timepoint)).to.equal(supply - 10n); - expect(await this.token.getPastVotes(this.other1, t2.timepoint + 1n)).to.equal(supply - 10n); - expect(await this.token.getPastVotes(this.other1, t3.timepoint)).to.equal(supply - 20n); - expect(await this.token.getPastVotes(this.other1, t3.timepoint + 1n)).to.equal(supply - 20n); - expect(await this.token.getPastVotes(this.other1, t4.timepoint)).to.equal(supply); - expect(await this.token.getPastVotes(this.other1, t4.timepoint + 1n)).to.equal(supply); - }); - }); - }); - - describe('getPastTotalSupply', function () { - beforeEach(async function () { - await this.token.connect(this.holder).delegate(this.holder); - }); - - it('reverts if block number >= current block', async function () { - const clock = await this.token.clock(); - await expect(this.token.getPastTotalSupply(50_000_000_000n)) - .to.be.revertedWithCustomError(this.token, 'ERC5805FutureLookup') - .withArgs(50_000_000_000n, clock); - }); - - it('returns 0 if there are no checkpoints', async function () { - expect(await this.token.getPastTotalSupply(0n)).to.equal(0n); - }); - - it('returns the latest block if >= last checkpoint block', async function () { - const tx = await this.token.$_mint(this.holder, supply); - const timepoint = await time.clockFromReceipt[mode](tx); - await mine(2); - - expect(await this.token.getPastTotalSupply(timepoint)).to.equal(supply); - expect(await this.token.getPastTotalSupply(timepoint + 1n)).to.equal(supply); - }); - - it('returns zero if < first checkpoint block', async function () { - await mine(); - const tx = await this.token.$_mint(this.holder, supply); - const timepoint = await time.clockFromReceipt[mode](tx); - await mine(2); - - expect(await this.token.getPastTotalSupply(timepoint - 1n)).to.equal(0n); - expect(await this.token.getPastTotalSupply(timepoint + 1n)).to.equal(supply); - }); - - it('generally returns the voting balance at the appropriate checkpoint', async function () { - const t1 = await this.token.$_mint(this.holder, supply); - await mine(2); - const t2 = await this.token.$_burn(this.holder, 10n); - await mine(2); - const t3 = await this.token.$_burn(this.holder, 10n); - await mine(2); - const t4 = await this.token.$_mint(this.holder, 20n); - await mine(2); - - t1.timepoint = await time.clockFromReceipt[mode](t1); - t2.timepoint = await time.clockFromReceipt[mode](t2); - t3.timepoint = await time.clockFromReceipt[mode](t3); - t4.timepoint = await time.clockFromReceipt[mode](t4); - - expect(await this.token.getPastTotalSupply(t1.timepoint - 1n)).to.equal(0n); - expect(await this.token.getPastTotalSupply(t1.timepoint)).to.equal(supply); - expect(await this.token.getPastTotalSupply(t1.timepoint + 1n)).to.equal(supply); - expect(await this.token.getPastTotalSupply(t2.timepoint)).to.equal(supply - 10n); - expect(await this.token.getPastTotalSupply(t2.timepoint + 1n)).to.equal(supply - 10n); - expect(await this.token.getPastTotalSupply(t3.timepoint)).to.equal(supply - 20n); - expect(await this.token.getPastTotalSupply(t3.timepoint + 1n)).to.equal(supply - 20n); - expect(await this.token.getPastTotalSupply(t4.timepoint)).to.equal(supply); - expect(await this.token.getPastTotalSupply(t4.timepoint + 1n)).to.equal(supply); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js deleted file mode 100644 index 2f630e6..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js +++ /dev/null @@ -1,203 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { shouldBehaveLikeERC20 } = require('../ERC20.behavior'); - -const name = 'My Token'; -const symbol = 'MTKN'; -const decimals = 9n; -const initialSupply = 100n; - -async function fixture() { - // this.accounts is used by shouldBehaveLikeERC20 - const accounts = await ethers.getSigners(); - const [holder, recipient, other] = accounts; - - const underlying = await ethers.deployContract('$ERC20DecimalsMock', [name, symbol, decimals]); - await underlying.$_mint(holder, initialSupply); - - const token = await ethers.deployContract('$ERC20Wrapper', [`Wrapped ${name}`, `W${symbol}`, underlying]); - - return { accounts, holder, recipient, other, underlying, token }; -} - -describe('ERC20Wrapper', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - afterEach('Underlying balance', async function () { - expect(await this.underlying.balanceOf(this.token)).to.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.equal(decimals); - }); - - it('decimals default back to 18 if token has no metadata', async function () { - const noDecimals = await ethers.deployContract('CallReceiverMock'); - const token = await ethers.deployContract('$ERC20Wrapper', [`Wrapped ${name}`, `W${symbol}`, noDecimals]); - expect(await token.decimals()).to.equal(18n); - }); - - it('has underlying', async function () { - expect(await this.token.underlying()).to.equal(this.underlying); - }); - - describe('deposit', function () { - it('executes with approval', async function () { - await this.underlying.connect(this.holder).approve(this.token, initialSupply); - - const tx = await this.token.connect(this.holder).depositFor(this.holder, initialSupply); - await expect(tx) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.holder, this.token, initialSupply) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.holder, initialSupply); - await expect(tx).to.changeTokenBalances( - this.underlying, - [this.holder, this.token], - [-initialSupply, initialSupply], - ); - await expect(tx).to.changeTokenBalance(this.token, this.holder, initialSupply); - }); - - it('reverts when missing approval', async function () { - await expect(this.token.connect(this.holder).depositFor(this.holder, initialSupply)) - .to.be.revertedWithCustomError(this.underlying, 'ERC20InsufficientAllowance') - .withArgs(this.token, 0, initialSupply); - }); - - it('reverts when insufficient balance', async function () { - await this.underlying.connect(this.holder).approve(this.token, ethers.MaxUint256); - - await expect(this.token.connect(this.holder).depositFor(this.holder, ethers.MaxUint256)) - .to.be.revertedWithCustomError(this.underlying, 'ERC20InsufficientBalance') - .withArgs(this.holder, initialSupply, ethers.MaxUint256); - }); - - it('deposits to other account', async function () { - await this.underlying.connect(this.holder).approve(this.token, initialSupply); - - const tx = await this.token.connect(this.holder).depositFor(this.recipient, initialSupply); - await expect(tx) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.holder, this.token.target, initialSupply) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.recipient, initialSupply); - await expect(tx).to.changeTokenBalances( - this.underlying, - [this.holder, this.token], - [-initialSupply, initialSupply], - ); - await expect(tx).to.changeTokenBalances(this.token, [this.holder, this.recipient], [0, initialSupply]); - }); - - it('reverts minting to the wrapper contract', async function () { - await this.underlying.connect(this.holder).approve(this.token, ethers.MaxUint256); - - await expect(this.token.connect(this.holder).depositFor(this.token, ethers.MaxUint256)) - .to.be.revertedWithCustomError(this.token, 'ERC20InvalidReceiver') - .withArgs(this.token); - }); - }); - - describe('withdraw', function () { - beforeEach(async function () { - await this.underlying.connect(this.holder).approve(this.token, initialSupply); - await this.token.connect(this.holder).depositFor(this.holder, initialSupply); - }); - - it('reverts when insufficient balance', async function () { - await expect(this.token.connect(this.holder).withdrawTo(this.holder, ethers.MaxInt256)) - .to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance') - .withArgs(this.holder, initialSupply, ethers.MaxInt256); - }); - - it('executes when operation is valid', async function () { - const value = 42n; - - const tx = await this.token.connect(this.holder).withdrawTo(this.holder, value); - await expect(tx) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.token.target, this.holder, value) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, ethers.ZeroAddress, value); - await expect(tx).to.changeTokenBalances(this.underlying, [this.token, this.holder], [-value, value]); - await expect(tx).to.changeTokenBalance(this.token, this.holder, -value); - }); - - it('entire balance', async function () { - const tx = await this.token.connect(this.holder).withdrawTo(this.holder, initialSupply); - await expect(tx) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.token.target, this.holder, initialSupply) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, ethers.ZeroAddress, initialSupply); - await expect(tx).to.changeTokenBalances( - this.underlying, - [this.token, this.holder], - [-initialSupply, initialSupply], - ); - await expect(tx).to.changeTokenBalance(this.token, this.holder, -initialSupply); - }); - - it('to other account', async function () { - const tx = await this.token.connect(this.holder).withdrawTo(this.recipient, initialSupply); - await expect(tx) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.token, this.recipient, initialSupply) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, ethers.ZeroAddress, initialSupply); - await expect(tx).to.changeTokenBalances( - this.underlying, - [this.token, this.holder, this.recipient], - [-initialSupply, 0, initialSupply], - ); - await expect(tx).to.changeTokenBalance(this.token, this.holder, -initialSupply); - }); - - it('reverts withdrawing to the wrapper contract', async function () { - await expect(this.token.connect(this.holder).withdrawTo(this.token, initialSupply)) - .to.be.revertedWithCustomError(this.token, 'ERC20InvalidReceiver') - .withArgs(this.token); - }); - }); - - describe('recover', function () { - it('nothing to recover', async function () { - await this.underlying.connect(this.holder).approve(this.token, initialSupply); - await this.token.connect(this.holder).depositFor(this.holder, initialSupply); - - const tx = await this.token.$_recover(this.recipient); - await expect(tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.recipient, 0n); - await expect(tx).to.changeTokenBalance(this.token, this.recipient, 0); - }); - - it('something to recover', async function () { - await this.underlying.connect(this.holder).transfer(this.token, initialSupply); - - const tx = await this.token.$_recover(this.recipient); - await expect(tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.recipient, initialSupply); - await expect(tx).to.changeTokenBalance(this.token, this.recipient, initialSupply); - }); - }); - - describe('erc20 behaviour', function () { - beforeEach(async function () { - await this.underlying.connect(this.holder).approve(this.token, initialSupply); - await this.token.connect(this.holder).depositFor(this.holder, initialSupply); - }); - - shouldBehaveLikeERC20(initialSupply); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol deleted file mode 100644 index 72b0dac..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol +++ /dev/null @@ -1,41 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js deleted file mode 100644 index ad8c926..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js +++ /dev/null @@ -1,888 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -const { Enum } = require('../../../helpers/enums'); - -const name = 'My Token'; -const symbol = 'MTKN'; -const decimals = 18n; - -async function fixture() { - const [holder, recipient, spender, other, ...accounts] = await ethers.getSigners(); - return { holder, recipient, spender, other, accounts }; -} - -describe('ERC4626', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('inherit decimals if from asset', async function () { - for (const decimals of [0n, 9n, 12n, 18n, 36n]) { - const token = await ethers.deployContract('$ERC20DecimalsMock', ['', '', decimals]); - const vault = await ethers.deployContract('$ERC4626', ['', '', token]); - expect(await vault.decimals()).to.equal(decimals); - } - }); - - it('asset has not yet been created', async function () { - const vault = await ethers.deployContract('$ERC4626', ['', '', this.other.address]); - expect(await vault.decimals()).to.equal(decimals); - }); - - it('underlying excess decimals', async function () { - const token = await ethers.deployContract('$ERC20ExcessDecimalsMock'); - const vault = await ethers.deployContract('$ERC4626', ['', '', token]); - expect(await vault.decimals()).to.equal(decimals); - }); - - it('decimals overflow', async function () { - for (const offset of [243n, 250n, 255n]) { - const token = await ethers.deployContract('$ERC20DecimalsMock', ['', '', decimals]); - const vault = await ethers.deployContract('$ERC4626OffsetMock', ['', '', token, offset]); - await expect(vault.decimals()).to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW); - } - }); - - describe('reentrancy', function () { - const reenterType = Enum('No', 'Before', 'After'); - - const value = 1_000_000_000_000_000_000n; - const reenterValue = 1_000_000_000n; - - beforeEach(async function () { - // Use offset 1 so the rate is not 1:1 and we can't possibly confuse assets and shares - const token = await ethers.deployContract('$ERC20Reentrant'); - const vault = await ethers.deployContract('$ERC4626OffsetMock', ['', '', token, 1n]); - // Funds and approval for tests - await token.$_mint(this.holder, value); - await token.$_mint(this.other, value); - await token.$_approve(this.holder, vault, ethers.MaxUint256); - await token.$_approve(this.other, vault, ethers.MaxUint256); - await token.$_approve(token, vault, ethers.MaxUint256); - - Object.assign(this, { token, vault }); - }); - - // 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 this.token.$_mint(this.token, reenterValue); - - // Schedules a reentrancy from the token contract - await this.token.scheduleReenter( - reenterType.Before, - this.vault, - this.vault.interface.encodeFunctionData('deposit', [reenterValue, this.holder.address]), - ); - - // Initial share price - const sharesForDeposit = await this.vault.previewDeposit(value); - const sharesForReenter = await this.vault.previewDeposit(reenterValue); - - await expect(this.vault.connect(this.holder).deposit(value, this.holder)) - // Deposit normally, reentering before the internal `_update` - .to.emit(this.vault, 'Deposit') - .withArgs(this.holder, this.holder, value, sharesForDeposit) - // Reentrant deposit event → uses the same price - .to.emit(this.vault, 'Deposit') - .withArgs(this.token, this.holder, reenterValue, sharesForReenter); - - // Assert prices is kept - expect(await this.vault.previewDeposit(value)).to.equal(sharesForDeposit); - }); - - // 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 this.vault.connect(this.holder).deposit(value, this.holder); - await this.vault.connect(this.other).deposit(reenterValue, this.token); - - // Schedules a reentrancy from the token contract - await this.token.scheduleReenter( - reenterType.After, - this.vault, - this.vault.interface.encodeFunctionData('withdraw', [reenterValue, this.holder.address, this.token.target]), - ); - - // Initial share price - const sharesForWithdraw = await this.vault.previewWithdraw(value); - const sharesForReenter = await this.vault.previewWithdraw(reenterValue); - - // Do withdraw normally, triggering the _afterTokenTransfer hook - await expect(this.vault.connect(this.holder).withdraw(value, this.holder, this.holder)) - // Main withdraw event - .to.emit(this.vault, 'Withdraw') - .withArgs(this.holder, this.holder, this.holder, value, sharesForWithdraw) - // Reentrant withdraw event → uses the same price - .to.emit(this.vault, 'Withdraw') - .withArgs(this.token, this.holder, this.token, reenterValue, sharesForReenter); - - // Assert price is kept - expect(await this.vault.previewWithdraw(value)).to.equal(sharesForWithdraw); - }); - - // Donate newly minted tokens to the vault during the reentrancy causes the share price to increase. - // Still, the deposit that trigger the reentrancy 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 reentrancy does not affect deposit', async function () { - // Schedules a reentrancy from the token contract that mess up the share price - await this.token.scheduleReenter( - reenterType.Before, - this.token, - this.token.interface.encodeFunctionData('$_mint', [this.vault.target, reenterValue]), - ); - - // Price before - const sharesBefore = await this.vault.previewDeposit(value); - - // Deposit, reentering before the internal `_update` - await expect(this.vault.connect(this.holder).deposit(value, this.holder)) - // Price is as previewed - .to.emit(this.vault, 'Deposit') - .withArgs(this.holder, this.holder, value, sharesBefore); - - // Price was modified during reentrancy - expect(await this.vault.previewDeposit(value)).to.lt(sharesBefore); - }); - - // Burn some tokens from the vault during the reentrancy causes the share price to drop. - // Still, the withdraw that trigger the reentrancy 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 reentrancy does not affect withdraw', async function () { - await this.vault.connect(this.holder).deposit(value, this.holder); - await this.vault.connect(this.other).deposit(value, this.other); - - // Schedules a reentrancy from the token contract that mess up the share price - await this.token.scheduleReenter( - reenterType.After, - this.token, - this.token.interface.encodeFunctionData('$_burn', [this.vault.target, reenterValue]), - ); - - // Price before - const sharesBefore = await this.vault.previewWithdraw(value); - - // Withdraw, triggering the _afterTokenTransfer hook - await expect(this.vault.connect(this.holder).withdraw(value, this.holder, this.holder)) - // Price is as previewed - .to.emit(this.vault, 'Withdraw') - .withArgs(this.holder, this.holder, this.holder, value, sharesBefore); - - // Price was modified during reentrancy - expect(await this.vault.previewWithdraw(value)).to.gt(sharesBefore); - }); - }); - - describe('limits', function () { - beforeEach(async function () { - const token = await ethers.deployContract('$ERC20DecimalsMock', [name, symbol, decimals]); - const vault = await ethers.deployContract('$ERC4626LimitsMock', ['', '', token]); - - Object.assign(this, { token, vault }); - }); - - it('reverts on deposit() above max deposit', async function () { - const maxDeposit = await this.vault.maxDeposit(this.holder); - await expect(this.vault.connect(this.holder).deposit(maxDeposit + 1n, this.recipient)) - .to.be.revertedWithCustomError(this.vault, 'ERC4626ExceededMaxDeposit') - .withArgs(this.recipient, maxDeposit + 1n, maxDeposit); - }); - - it('reverts on mint() above max mint', async function () { - const maxMint = await this.vault.maxMint(this.holder); - - await expect(this.vault.connect(this.holder).mint(maxMint + 1n, this.recipient)) - .to.be.revertedWithCustomError(this.vault, 'ERC4626ExceededMaxMint') - .withArgs(this.recipient, maxMint + 1n, maxMint); - }); - - it('reverts on withdraw() above max withdraw', async function () { - const maxWithdraw = await this.vault.maxWithdraw(this.holder); - - await expect(this.vault.connect(this.holder).withdraw(maxWithdraw + 1n, this.recipient, this.holder)) - .to.be.revertedWithCustomError(this.vault, 'ERC4626ExceededMaxWithdraw') - .withArgs(this.holder, maxWithdraw + 1n, maxWithdraw); - }); - - it('reverts on redeem() above max redeem', async function () { - const maxRedeem = await this.vault.maxRedeem(this.holder); - - await expect(this.vault.connect(this.holder).redeem(maxRedeem + 1n, this.recipient, this.holder)) - .to.be.revertedWithCustomError(this.vault, 'ERC4626ExceededMaxRedeem') - .withArgs(this.holder, maxRedeem + 1n, maxRedeem); - }); - }); - - for (const offset of [0n, 6n, 18n]) { - const parseToken = token => token * 10n ** decimals; - const parseShare = share => share * 10n ** (decimals + offset); - - const virtualAssets = 1n; - const virtualShares = 10n ** offset; - - describe(`offset: ${offset}`, function () { - beforeEach(async function () { - const token = await ethers.deployContract('$ERC20DecimalsMock', [name, symbol, decimals]); - const vault = await ethers.deployContract('$ERC4626OffsetMock', [name + ' Vault', symbol + 'V', token, offset]); - - await token.$_mint(this.holder, ethers.MaxUint256 / 2n); // 50% of maximum - await token.$_approve(this.holder, vault, ethers.MaxUint256); - await vault.$_approve(this.holder, this.spender, ethers.MaxUint256); - - Object.assign(this, { token, vault }); - }); - - it('metadata', async function () { - expect(await this.vault.name()).to.equal(name + ' Vault'); - expect(await this.vault.symbol()).to.equal(symbol + 'V'); - expect(await this.vault.decimals()).to.equal(decimals + offset); - expect(await this.vault.asset()).to.equal(this.token); - }); - - describe('empty vault: no assets & no shares', function () { - it('status', async function () { - expect(await this.vault.totalAssets()).to.equal(0n); - }); - - it('deposit', async function () { - expect(await this.vault.maxDeposit(this.holder)).to.equal(ethers.MaxUint256); - expect(await this.vault.previewDeposit(parseToken(1n))).to.equal(parseShare(1n)); - - const tx = this.vault.connect(this.holder).deposit(parseToken(1n), this.recipient); - - await expect(tx).to.changeTokenBalances( - this.token, - [this.holder, this.vault], - [-parseToken(1n), parseToken(1n)], - ); - await expect(tx).to.changeTokenBalance(this.vault, this.recipient, parseShare(1n)); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.vault, parseToken(1n)) - .to.emit(this.vault, 'Transfer') - .withArgs(ethers.ZeroAddress, this.recipient, parseShare(1n)) - .to.emit(this.vault, 'Deposit') - .withArgs(this.holder, this.recipient, parseToken(1n), parseShare(1n)); - }); - - it('mint', async function () { - expect(await this.vault.maxMint(this.holder)).to.equal(ethers.MaxUint256); - expect(await this.vault.previewMint(parseShare(1n))).to.equal(parseToken(1n)); - - const tx = this.vault.connect(this.holder).mint(parseShare(1n), this.recipient); - - await expect(tx).to.changeTokenBalances( - this.token, - [this.holder, this.vault], - [-parseToken(1n), parseToken(1n)], - ); - await expect(tx).to.changeTokenBalance(this.vault, this.recipient, parseShare(1n)); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.vault, parseToken(1n)) - .to.emit(this.vault, 'Transfer') - .withArgs(ethers.ZeroAddress, this.recipient, parseShare(1n)) - .to.emit(this.vault, 'Deposit') - .withArgs(this.holder, this.recipient, parseToken(1n), parseShare(1n)); - }); - - it('withdraw', async function () { - expect(await this.vault.maxWithdraw(this.holder)).to.equal(0n); - expect(await this.vault.previewWithdraw(0n)).to.equal(0n); - - const tx = this.vault.connect(this.holder).withdraw(0n, this.recipient, this.holder); - - await expect(tx).to.changeTokenBalances(this.token, [this.vault, this.recipient], [0n, 0n]); - await expect(tx).to.changeTokenBalance(this.vault, this.holder, 0n); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.vault, this.recipient, 0n) - .to.emit(this.vault, 'Transfer') - .withArgs(this.holder, ethers.ZeroAddress, 0n) - .to.emit(this.vault, 'Withdraw') - .withArgs(this.holder, this.recipient, this.holder, 0n, 0n); - }); - - it('redeem', async function () { - expect(await this.vault.maxRedeem(this.holder)).to.equal(0n); - expect(await this.vault.previewRedeem(0n)).to.equal(0n); - - const tx = this.vault.connect(this.holder).redeem(0n, this.recipient, this.holder); - - await expect(tx).to.changeTokenBalances(this.token, [this.vault, this.recipient], [0n, 0n]); - await expect(tx).to.changeTokenBalance(this.vault, this.holder, 0n); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.vault, this.recipient, 0n) - .to.emit(this.vault, 'Transfer') - .withArgs(this.holder, ethers.ZeroAddress, 0n) - .to.emit(this.vault, 'Withdraw') - .withArgs(this.holder, this.recipient, this.holder, 0n, 0n); - }); - }); - - 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, parseToken(1n)); - }); - - it('status', async function () { - expect(await this.vault.totalSupply()).to.equal(0n); - expect(await this.vault.totalAssets()).to.equal(parseToken(1n)); - }); - - /** - * | 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()) + virtualAssets; - const effectiveShares = (await this.vault.totalSupply()) + virtualShares; - - const depositAssets = parseToken(1n); - const expectedShares = (depositAssets * effectiveShares) / effectiveAssets; - - expect(await this.vault.maxDeposit(this.holder)).to.equal(ethers.MaxUint256); - expect(await this.vault.previewDeposit(depositAssets)).to.equal(expectedShares); - - const tx = this.vault.connect(this.holder).deposit(depositAssets, this.recipient); - - await expect(tx).to.changeTokenBalances( - this.token, - [this.holder, this.vault], - [-depositAssets, depositAssets], - ); - await expect(tx).to.changeTokenBalance(this.vault, this.recipient, expectedShares); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.vault, depositAssets) - .to.emit(this.vault, 'Transfer') - .withArgs(ethers.ZeroAddress, this.recipient, expectedShares) - .to.emit(this.vault, 'Deposit') - .withArgs(this.holder, this.recipient, depositAssets, 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()) + virtualAssets; - const effectiveShares = (await this.vault.totalSupply()) + virtualShares; - - const mintShares = parseShare(1n); - const expectedAssets = (mintShares * effectiveAssets) / effectiveShares; - - expect(await this.vault.maxMint(this.holder)).to.equal(ethers.MaxUint256); - expect(await this.vault.previewMint(mintShares)).to.equal(expectedAssets); - - const tx = this.vault.connect(this.holder).mint(mintShares, this.recipient); - - await expect(tx).to.changeTokenBalances( - this.token, - [this.holder, this.vault], - [-expectedAssets, expectedAssets], - ); - await expect(tx).to.changeTokenBalance(this.vault, this.recipient, mintShares); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.vault, expectedAssets) - .to.emit(this.vault, 'Transfer') - .withArgs(ethers.ZeroAddress, this.recipient, mintShares) - .to.emit(this.vault, 'Deposit') - .withArgs(this.holder, this.recipient, expectedAssets, mintShares); - }); - - it('withdraw', async function () { - expect(await this.vault.maxWithdraw(this.holder)).to.equal(0n); - expect(await this.vault.previewWithdraw(0n)).to.equal(0n); - - const tx = this.vault.connect(this.holder).withdraw(0n, this.recipient, this.holder); - - await expect(tx).to.changeTokenBalances(this.token, [this.vault, this.recipient], [0n, 0n]); - await expect(tx).to.changeTokenBalance(this.vault, this.holder, 0n); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.vault, this.recipient, 0n) - .to.emit(this.vault, 'Transfer') - .withArgs(this.holder, ethers.ZeroAddress, 0n) - .to.emit(this.vault, 'Withdraw') - .withArgs(this.holder, this.recipient, this.holder, 0n, 0n); - }); - - it('redeem', async function () { - expect(await this.vault.maxRedeem(this.holder)).to.equal(0n); - expect(await this.vault.previewRedeem(0n)).to.equal(0n); - - const tx = this.vault.connect(this.holder).redeem(0n, this.recipient, this.holder); - - await expect(tx).to.changeTokenBalances(this.token, [this.vault, this.recipient], [0n, 0n]); - await expect(tx).to.changeTokenBalance(this.vault, this.holder, 0n); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.vault, this.recipient, 0n) - .to.emit(this.vault, 'Transfer') - .withArgs(this.holder, ethers.ZeroAddress, 0n) - .to.emit(this.vault, 'Withdraw') - .withArgs(this.holder, this.recipient, this.holder, 0n, 0n); - }); - }); - - 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, parseToken(1n)); - await this.vault.$_mint(this.holder, parseShare(100n)); - }); - - it('status', async function () { - expect(await this.vault.totalSupply()).to.equal(parseShare(100n)); - expect(await this.vault.totalAssets()).to.equal(parseToken(1n)); - }); - - /** - * | 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()) + virtualAssets; - const effectiveShares = (await this.vault.totalSupply()) + virtualShares; - - const depositAssets = parseToken(1n); - const expectedShares = (depositAssets * effectiveShares) / effectiveAssets; - - expect(await this.vault.maxDeposit(this.holder)).to.equal(ethers.MaxUint256); - expect(await this.vault.previewDeposit(depositAssets)).to.equal(expectedShares); - - const tx = this.vault.connect(this.holder).deposit(depositAssets, this.recipient); - - await expect(tx).to.changeTokenBalances( - this.token, - [this.holder, this.vault], - [-depositAssets, depositAssets], - ); - await expect(tx).to.changeTokenBalance(this.vault, this.recipient, expectedShares); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.vault, depositAssets) - .to.emit(this.vault, 'Transfer') - .withArgs(ethers.ZeroAddress, this.recipient, expectedShares) - .to.emit(this.vault, 'Deposit') - .withArgs(this.holder, this.recipient, depositAssets, 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()) + virtualAssets; - const effectiveShares = (await this.vault.totalSupply()) + virtualShares; - - const mintShares = parseShare(1n); - const expectedAssets = (mintShares * effectiveAssets) / effectiveShares + 1n; // add for the rounding - - expect(await this.vault.maxMint(this.holder)).to.equal(ethers.MaxUint256); - expect(await this.vault.previewMint(mintShares)).to.equal(expectedAssets); - - const tx = this.vault.connect(this.holder).mint(mintShares, this.recipient); - - await expect(tx).to.changeTokenBalances( - this.token, - [this.holder, this.vault], - [-expectedAssets, expectedAssets], - ); - await expect(tx).to.changeTokenBalance(this.vault, this.recipient, mintShares); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.vault, expectedAssets) - .to.emit(this.vault, 'Transfer') - .withArgs(ethers.ZeroAddress, this.recipient, mintShares) - .to.emit(this.vault, 'Deposit') - .withArgs(this.holder, this.recipient, expectedAssets, mintShares); - }); - - it('withdraw', async function () { - const effectiveAssets = (await this.vault.totalAssets()) + virtualAssets; - const effectiveShares = (await this.vault.totalSupply()) + virtualShares; - - const withdrawAssets = parseToken(1n); - const expectedShares = (withdrawAssets * effectiveShares) / effectiveAssets + 1n; // add for the rounding - - expect(await this.vault.maxWithdraw(this.holder)).to.equal(withdrawAssets); - expect(await this.vault.previewWithdraw(withdrawAssets)).to.equal(expectedShares); - - const tx = this.vault.connect(this.holder).withdraw(withdrawAssets, this.recipient, this.holder); - - await expect(tx).to.changeTokenBalances( - this.token, - [this.vault, this.recipient], - [-withdrawAssets, withdrawAssets], - ); - await expect(tx).to.changeTokenBalance(this.vault, this.holder, -expectedShares); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.vault, this.recipient, withdrawAssets) - .to.emit(this.vault, 'Transfer') - .withArgs(this.holder, ethers.ZeroAddress, expectedShares) - .to.emit(this.vault, 'Withdraw') - .withArgs(this.holder, this.recipient, this.holder, withdrawAssets, expectedShares); - }); - - it('withdraw with approval', async function () { - const assets = await this.vault.previewWithdraw(parseToken(1n)); - - await expect(this.vault.connect(this.other).withdraw(parseToken(1n), this.recipient, this.holder)) - .to.be.revertedWithCustomError(this.vault, 'ERC20InsufficientAllowance') - .withArgs(this.other, 0n, assets); - - await expect(this.vault.connect(this.spender).withdraw(parseToken(1n), this.recipient, this.holder)).to.not.be - .reverted; - }); - - it('redeem', async function () { - const effectiveAssets = (await this.vault.totalAssets()) + virtualAssets; - const effectiveShares = (await this.vault.totalSupply()) + virtualShares; - - const redeemShares = parseShare(100n); - const expectedAssets = (redeemShares * effectiveAssets) / effectiveShares; - - expect(await this.vault.maxRedeem(this.holder)).to.equal(redeemShares); - expect(await this.vault.previewRedeem(redeemShares)).to.equal(expectedAssets); - - const tx = this.vault.connect(this.holder).redeem(redeemShares, this.recipient, this.holder); - - await expect(tx).to.changeTokenBalances( - this.token, - [this.vault, this.recipient], - [-expectedAssets, expectedAssets], - ); - await expect(tx).to.changeTokenBalance(this.vault, this.holder, -redeemShares); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.vault, this.recipient, expectedAssets) - .to.emit(this.vault, 'Transfer') - .withArgs(this.holder, ethers.ZeroAddress, redeemShares) - .to.emit(this.vault, 'Withdraw') - .withArgs(this.holder, this.recipient, this.holder, expectedAssets, redeemShares); - }); - - it('redeem with approval', async function () { - await expect(this.vault.connect(this.other).redeem(parseShare(100n), this.recipient, this.holder)) - .to.be.revertedWithCustomError(this.vault, 'ERC20InsufficientAllowance') - .withArgs(this.other, 0n, parseShare(100n)); - - await expect(this.vault.connect(this.spender).redeem(parseShare(100n), this.recipient, this.holder)).to.not.be - .reverted; - }); - }); - }); - } - - describe('ERC4626Fees', function () { - const feeBasisPoints = 500n; // 5% - const valueWithoutFees = 10_000n; - const fees = (valueWithoutFees * feeBasisPoints) / 10_000n; - const valueWithFees = valueWithoutFees + fees; - - describe('input fees', function () { - beforeEach(async function () { - const token = await ethers.deployContract('$ERC20DecimalsMock', [name, symbol, 18n]); - const vault = await ethers.deployContract('$ERC4626FeesMock', [ - '', - '', - token, - feeBasisPoints, - this.other, - 0n, - ethers.ZeroAddress, - ]); - - await token.$_mint(this.holder, ethers.MaxUint256 / 2n); - await token.$_approve(this.holder, vault, ethers.MaxUint256 / 2n); - - Object.assign(this, { token, vault }); - }); - - it('deposit', async function () { - expect(await this.vault.previewDeposit(valueWithFees)).to.equal(valueWithoutFees); - this.tx = this.vault.connect(this.holder).deposit(valueWithFees, this.recipient); - }); - - it('mint', async function () { - expect(await this.vault.previewMint(valueWithoutFees)).to.equal(valueWithFees); - this.tx = this.vault.connect(this.holder).mint(valueWithoutFees, this.recipient); - }); - - afterEach(async function () { - await expect(this.tx).to.changeTokenBalances( - this.token, - [this.holder, this.vault, this.other], - [-valueWithFees, valueWithoutFees, fees], - ); - await expect(this.tx).to.changeTokenBalance(this.vault, this.recipient, valueWithoutFees); - await expect(this.tx) - // get total - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.vault, valueWithFees) - // redirect fees - .to.emit(this.token, 'Transfer') - .withArgs(this.vault, this.other, fees) - // mint shares - .to.emit(this.vault, 'Transfer') - .withArgs(ethers.ZeroAddress, this.recipient, valueWithoutFees) - // deposit event - .to.emit(this.vault, 'Deposit') - .withArgs(this.holder, this.recipient, valueWithFees, valueWithoutFees); - }); - }); - - describe('output fees', function () { - beforeEach(async function () { - const token = await ethers.deployContract('$ERC20DecimalsMock', [name, symbol, 18n]); - const vault = await ethers.deployContract('$ERC4626FeesMock', [ - '', - '', - token, - 0n, - ethers.ZeroAddress, - feeBasisPoints, - this.other, - ]); - - await token.$_mint(vault, ethers.MaxUint256 / 2n); - await vault.$_mint(this.holder, ethers.MaxUint256 / 2n); - - Object.assign(this, { token, vault }); - }); - - it('redeem', async function () { - expect(await this.vault.previewRedeem(valueWithFees)).to.equal(valueWithoutFees); - this.tx = this.vault.connect(this.holder).redeem(valueWithFees, this.recipient, this.holder); - }); - - it('withdraw', async function () { - expect(await this.vault.previewWithdraw(valueWithoutFees)).to.equal(valueWithFees); - this.tx = this.vault.connect(this.holder).withdraw(valueWithoutFees, this.recipient, this.holder); - }); - - afterEach(async function () { - await expect(this.tx).to.changeTokenBalances( - this.token, - [this.vault, this.recipient, this.other], - [-valueWithFees, valueWithoutFees, fees], - ); - await expect(this.tx).to.changeTokenBalance(this.vault, this.holder, -valueWithFees); - await expect(this.tx) - // withdraw principal - .to.emit(this.token, 'Transfer') - .withArgs(this.vault, this.recipient, valueWithoutFees) - // redirect fees - .to.emit(this.token, 'Transfer') - .withArgs(this.vault, this.other, fees) - // mint shares - .to.emit(this.vault, 'Transfer') - .withArgs(this.holder, ethers.ZeroAddress, valueWithFees) - // withdraw event - .to.emit(this.vault, 'Withdraw') - .withArgs(this.holder, this.recipient, this.holder, valueWithoutFees, 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 - const [alice, bruce] = this.accounts; - const token = await ethers.deployContract('$ERC20DecimalsMock', [name, symbol, 18n]); - const vault = await ethers.deployContract('$ERC4626', ['', '', token]); - - await token.$_mint(alice, 4000n); - await token.$_mint(bruce, 7001n); - await token.connect(alice).approve(vault, 4000n); - await token.connect(bruce).approve(vault, 7001n); - - // 1. Alice mints 2000 shares (costs 2000 tokens) - await expect(vault.connect(alice).mint(2000n, alice)) - .to.emit(token, 'Transfer') - .withArgs(alice, vault, 2000n) - .to.emit(vault, 'Transfer') - .withArgs(ethers.ZeroAddress, alice, 2000n); - - expect(await vault.previewDeposit(2000n)).to.equal(2000n); - expect(await vault.balanceOf(alice)).to.equal(2000n); - expect(await vault.balanceOf(bruce)).to.equal(0n); - expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(2000n); - expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(0n); - expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(2000n); - expect(await vault.totalSupply()).to.equal(2000n); - expect(await vault.totalAssets()).to.equal(2000n); - - // 2. Bruce deposits 4000 tokens (mints 4000 shares) - await expect(vault.connect(bruce).mint(4000n, bruce)) - .to.emit(token, 'Transfer') - .withArgs(bruce, vault, 4000n) - .to.emit(vault, 'Transfer') - .withArgs(ethers.ZeroAddress, bruce, 4000n); - - expect(await vault.previewDeposit(4000n)).to.equal(4000n); - expect(await vault.balanceOf(alice)).to.equal(2000n); - expect(await vault.balanceOf(bruce)).to.equal(4000n); - expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(2000n); - expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(4000n); - expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(6000n); - expect(await vault.totalSupply()).to.equal(6000n); - expect(await vault.totalAssets()).to.equal(6000n); - - // 3. Vault mutates by +3000 tokens (simulated yield returned from strategy) - await token.$_mint(vault, 3000n); - - expect(await vault.balanceOf(alice)).to.equal(2000n); - expect(await vault.balanceOf(bruce)).to.equal(4000n); - expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(2999n); // used to be 3000, but virtual assets/shares captures part of the yield - expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(5999n); // used to be 6000, but virtual assets/shares captures part of the yield - expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(6000n); - expect(await vault.totalSupply()).to.equal(6000n); - expect(await vault.totalAssets()).to.equal(9000n); - - // 4. Alice deposits 2000 tokens (mints 1333 shares) - await expect(vault.connect(alice).deposit(2000n, alice)) - .to.emit(token, 'Transfer') - .withArgs(alice, vault, 2000n) - .to.emit(vault, 'Transfer') - .withArgs(ethers.ZeroAddress, alice, 1333n); - - expect(await vault.balanceOf(alice)).to.equal(3333n); - expect(await vault.balanceOf(bruce)).to.equal(4000n); - expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(4999n); - expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(6000n); - expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(7333n); - expect(await vault.totalSupply()).to.equal(7333n); - expect(await vault.totalAssets()).to.equal(11000n); - - // 5. Bruce mints 2000 shares (costs 3001 assets) - // NOTE: Bruce's assets spent got rounded towards infinity - // NOTE: Alices's vault assets got rounded towards infinity - await expect(vault.connect(bruce).mint(2000n, bruce)) - .to.emit(token, 'Transfer') - .withArgs(bruce, vault, 3000n) - .to.emit(vault, 'Transfer') - .withArgs(ethers.ZeroAddress, bruce, 2000n); - - expect(await vault.balanceOf(alice)).to.equal(3333n); - expect(await vault.balanceOf(bruce)).to.equal(6000n); - expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(4999n); // used to be 5000 - expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(9000n); - expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(9333n); - expect(await vault.totalSupply()).to.equal(9333n); - expect(await vault.totalAssets()).to.equal(14000n); // used to be 14001 - - // 6. Vault mutates by +3000 tokens - // NOTE: Vault holds 17001 tokens, but sum of assetsOf() is 17000. - await token.$_mint(vault, 3000n); - - expect(await vault.balanceOf(alice)).to.equal(3333n); - expect(await vault.balanceOf(bruce)).to.equal(6000n); - expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(6070n); // used to be 6071 - expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(10928n); // used to be 10929 - expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(9333n); - expect(await vault.totalSupply()).to.equal(9333n); - expect(await vault.totalAssets()).to.equal(17000n); // used to be 17001 - - // 7. Alice redeem 1333 shares (2428 assets) - await expect(vault.connect(alice).redeem(1333n, alice, alice)) - .to.emit(vault, 'Transfer') - .withArgs(alice, ethers.ZeroAddress, 1333n) - .to.emit(token, 'Transfer') - .withArgs(vault, alice, 2427n); // used to be 2428 - - expect(await vault.balanceOf(alice)).to.equal(2000n); - expect(await vault.balanceOf(bruce)).to.equal(6000n); - expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(3643n); - expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(10929n); - expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(8000n); - expect(await vault.totalSupply()).to.equal(8000n); - expect(await vault.totalAssets()).to.equal(14573n); - - // 8. Bruce withdraws 2929 assets (1608 shares) - await expect(vault.connect(bruce).withdraw(2929n, bruce, bruce)) - .to.emit(vault, 'Transfer') - .withArgs(bruce, ethers.ZeroAddress, 1608n) - .to.emit(token, 'Transfer') - .withArgs(vault, bruce, 2929n); - - expect(await vault.balanceOf(alice)).to.equal(2000n); - expect(await vault.balanceOf(bruce)).to.equal(4392n); - expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(3643n); - expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(8000n); - expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(6392n); - expect(await vault.totalSupply()).to.equal(6392n); - expect(await vault.totalAssets()).to.equal(11644n); - - // 9. Alice withdraws 3643 assets (2000 shares) - // NOTE: Bruce's assets have been rounded back towards infinity - await expect(vault.connect(alice).withdraw(3643n, alice, alice)) - .to.emit(vault, 'Transfer') - .withArgs(alice, ethers.ZeroAddress, 2000n) - .to.emit(token, 'Transfer') - .withArgs(vault, alice, 3643n); - - expect(await vault.balanceOf(alice)).to.equal(0n); - expect(await vault.balanceOf(bruce)).to.equal(4392n); - expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(0n); - expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(8000n); // used to be 8001 - expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(4392n); - expect(await vault.totalSupply()).to.equal(4392n); - expect(await vault.totalAssets()).to.equal(8001n); - - // 10. Bruce redeem 4392 shares (8001 tokens) - await expect(vault.connect(bruce).redeem(4392n, bruce, bruce)) - .to.emit(vault, 'Transfer') - .withArgs(bruce, ethers.ZeroAddress, 4392n) - .to.emit(token, 'Transfer') - .withArgs(vault, bruce, 8000n); // used to be 8001 - - expect(await vault.balanceOf(alice)).to.equal(0n); - expect(await vault.balanceOf(bruce)).to.equal(0n); - expect(await vault.convertToAssets(await vault.balanceOf(alice))).to.equal(0n); - expect(await vault.convertToAssets(await vault.balanceOf(bruce))).to.equal(0n); - expect(await vault.convertToShares(await token.balanceOf(vault))).to.equal(0n); - expect(await vault.totalSupply()).to.equal(0n); - expect(await vault.totalAssets()).to.equal(1n); // used to be 0 - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20Bridgeable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20Bridgeable.test.js deleted file mode 100644 index 06c3bb2..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20Bridgeable.test.js +++ /dev/null @@ -1,89 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { shouldBehaveLikeERC20 } = require('../ERC20.behavior.js'); -const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); - -const name = 'My Token'; -const symbol = 'MTKN'; -const initialSupply = 100n; - -async function fixture() { - const [other, bridge, ...accounts] = await ethers.getSigners(); - - const token = await ethers.deployContract('$ERC20BridgeableMock', [name, symbol, bridge]); - await token.$_mint(accounts[0], initialSupply); - - return { bridge, other, accounts, token }; -} - -describe('ERC20Bridgeable', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('onlyTokenBridgeFn', function () { - it('reverts when called by non-bridge', async function () { - await expect(this.token.onlyTokenBridgeFn()).to.be.revertedWithCustomError(this.token, 'OnlyTokenBridge'); - }); - - it('does not revert when called by bridge', async function () { - await expect(this.token.connect(this.bridge).onlyTokenBridgeFn()) - .to.emit(this.token, 'OnlyTokenBridgeFnCalled') - .withArgs(this.bridge); - }); - }); - - describe('crosschainMint', function () { - it('reverts when called by non-bridge', async function () { - await expect(this.token.crosschainMint(this.other, 100n)).to.be.revertedWithCustomError( - this.token, - 'OnlyTokenBridge', - ); - }); - - it('mints amount provided by the bridge when calling crosschainMint', async function () { - const amount = 100n; - await expect(this.token.connect(this.bridge).crosschainMint(this.other, amount)) - .to.emit(this.token, 'CrosschainMint') - .withArgs(this.other, amount, this.bridge) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.other, amount); - - await expect(this.token.balanceOf(this.other)).to.eventually.equal(amount); - }); - }); - - describe('crosschainBurn', function () { - it('reverts when called by non-bridge', async function () { - await expect(this.token.crosschainBurn(this.other, 100n)).to.be.revertedWithCustomError( - this.token, - 'OnlyTokenBridge', - ); - }); - - it('burns amount provided by the bridge when calling crosschainBurn', async function () { - const amount = 100n; - await this.token.$_mint(this.other, amount); - - await expect(this.token.connect(this.bridge).crosschainBurn(this.other, amount)) - .to.emit(this.token, 'CrosschainBurn') - .withArgs(this.other, amount, this.bridge) - .to.emit(this.token, 'Transfer') - .withArgs(this.other, ethers.ZeroAddress, amount); - - await expect(this.token.balanceOf(this.other)).to.eventually.equal(0); - }); - }); - - describe('ERC165', function () { - shouldSupportInterfaces({ - ERC7802: ['crosschainMint(address,uint256)', 'crosschainBurn(address,uint256)'], - }); - }); - - describe('ERC20 behavior', function () { - shouldBehaveLikeERC20(initialSupply); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20TemporaryApproval.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20TemporaryApproval.test.js deleted file mode 100644 index a1f6362..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20TemporaryApproval.test.js +++ /dev/null @@ -1,142 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { max, min } = require('../../../helpers/math.js'); - -const { shouldBehaveLikeERC20 } = require('../ERC20.behavior.js'); - -const name = 'My Token'; -const symbol = 'MTKN'; -const initialSupply = 100n; - -async function fixture() { - // this.accounts is used by shouldBehaveLikeERC20 - const accounts = await ethers.getSigners(); - const [holder, recipient, other] = accounts; - - const token = await ethers.deployContract('$ERC20TemporaryApproval', [name, symbol]); - await token.$_mint(holder, initialSupply); - - const spender = await ethers.deployContract('$Address'); - const batch = await ethers.deployContract('BatchCaller'); - const getter = await ethers.deployContract('ERC20GetterHelper'); - - return { accounts, holder, recipient, other, token, spender, batch, getter }; -} - -describe('ERC20TemporaryApproval', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeERC20(initialSupply); - - describe('setting and spending temporary allowance', function () { - beforeEach(async function () { - await this.token.connect(this.holder).transfer(this.batch, initialSupply); - }); - - for (let { - description, - persistentAllowance, - temporaryAllowance, - amount, - temporaryExpected, - persistentExpected, - } of [ - { description: 'can set temporary allowance', temporaryAllowance: 42n }, - { - description: 'can set temporary allowance on top of persistent allowance', - temporaryAllowance: 42n, - persistentAllowance: 17n, - }, - { description: 'support allowance overflow', temporaryAllowance: ethers.MaxUint256, persistentAllowance: 17n }, - { description: 'consuming temporary allowance alone', temporaryAllowance: 42n, amount: 2n }, - { - description: 'fallback to persistent allowance if temporary allowance is not sufficient', - temporaryAllowance: 42n, - persistentAllowance: 17n, - amount: 50n, - }, - { - description: 'do not reduce infinite temporary allowance #1', - temporaryAllowance: ethers.MaxUint256, - amount: 50n, - temporaryExpected: ethers.MaxUint256, - }, - { - description: 'do not reduce infinite temporary allowance #2', - temporaryAllowance: 17n, - persistentAllowance: ethers.MaxUint256, - amount: 50n, - temporaryExpected: ethers.MaxUint256, - persistentExpected: ethers.MaxUint256, - }, - ]) { - persistentAllowance ??= 0n; - temporaryAllowance ??= 0n; - amount ??= 0n; - temporaryExpected ??= min(persistentAllowance + temporaryAllowance - amount, ethers.MaxUint256); - persistentExpected ??= persistentAllowance - max(amount - temporaryAllowance, 0n); - - it(description, async function () { - await expect( - this.batch.execute( - [ - persistentAllowance && { - target: this.token, - value: 0n, - data: this.token.interface.encodeFunctionData('approve', [this.spender.target, persistentAllowance]), - }, - temporaryAllowance && { - target: this.token, - value: 0n, - data: this.token.interface.encodeFunctionData('temporaryApprove', [ - this.spender.target, - temporaryAllowance, - ]), - }, - amount && { - target: this.spender, - value: 0n, - data: this.spender.interface.encodeFunctionData('$functionCall', [ - this.token.target, - this.token.interface.encodeFunctionData('transferFrom', [ - this.batch.target, - this.recipient.address, - amount, - ]), - ]), - }, - { - target: this.getter, - value: 0n, - data: this.getter.interface.encodeFunctionData('allowance', [ - this.token.target, - this.batch.target, - this.spender.target, - ]), - }, - ].filter(Boolean), - ), - ) - .to.emit(this.getter, 'ERC20Allowance') - .withArgs(this.token, this.batch, this.spender, temporaryExpected); - - expect(await this.token.allowance(this.batch, this.spender)).to.equal(persistentExpected); - }); - } - - it('reverts when the recipient is the zero address', async function () { - await expect(this.token.connect(this.holder).temporaryApprove(ethers.ZeroAddress, 1n)) - .to.be.revertedWithCustomError(this.token, 'ERC20InvalidSpender') - .withArgs(ethers.ZeroAddress); - }); - - it('reverts when the token owner is the zero address', async function () { - await expect(this.token.$_temporaryApprove(ethers.ZeroAddress, this.recipient, 1n)) - .to.be.revertedWithCustomError(this.token, 'ERC20InvalidApprover') - .withArgs(ethers.ZeroAddress); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js deleted file mode 100644 index 0ae9463..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js +++ /dev/null @@ -1,463 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const name = 'ERC20Mock'; -const symbol = 'ERC20Mock'; -const value = 100n; -const data = '0x12345678'; - -async function fixture() { - const [hasNoCode, owner, receiver, spender, other] = await ethers.getSigners(); - - const mock = await ethers.deployContract('$SafeERC20'); - const erc20ReturnFalseMock = await ethers.deployContract('$ERC20ReturnFalseMock', [name, symbol]); - const erc20ReturnTrueMock = await ethers.deployContract('$ERC20', [name, symbol]); // default implementation returns true - const erc20NoReturnMock = await ethers.deployContract('$ERC20NoReturnMock', [name, symbol]); - const erc20ForceApproveMock = await ethers.deployContract('$ERC20ForceApproveMock', [name, symbol]); - const erc1363Mock = await ethers.deployContract('$ERC1363', [name, symbol]); - const erc1363ReturnFalseOnErc20Mock = await ethers.deployContract('$ERC1363ReturnFalseOnERC20Mock', [name, symbol]); - const erc1363ReturnFalseMock = await ethers.deployContract('$ERC1363ReturnFalseMock', [name, symbol]); - const erc1363NoReturnMock = await ethers.deployContract('$ERC1363NoReturnMock', [name, symbol]); - const erc1363ForceApproveMock = await ethers.deployContract('$ERC1363ForceApproveMock', [name, symbol]); - const erc1363Receiver = await ethers.deployContract('$ERC1363ReceiverMock'); - const erc1363Spender = await ethers.deployContract('$ERC1363SpenderMock'); - - return { - hasNoCode, - owner, - receiver, - spender, - other, - mock, - erc20ReturnFalseMock, - erc20ReturnTrueMock, - erc20NoReturnMock, - erc20ForceApproveMock, - erc1363Mock, - erc1363ReturnFalseOnErc20Mock, - erc1363ReturnFalseMock, - erc1363NoReturnMock, - erc1363ForceApproveMock, - erc1363Receiver, - erc1363Spender, - }; -} - -describe('SafeERC20', function () { - before(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('with address that has no contract code', function () { - beforeEach(async function () { - this.token = this.hasNoCode; - }); - - it('reverts on transfer', async function () { - await expect(this.mock.$safeTransfer(this.token, this.receiver, 0n)) - .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') - .withArgs(this.token); - }); - - it('returns false on trySafeTransfer', async function () { - await expect(this.mock.$trySafeTransfer(this.token, this.receiver, 0n)) - .to.emit(this.mock, 'return$trySafeTransfer') - .withArgs(false); - }); - - it('reverts on transferFrom', async function () { - await expect(this.mock.$safeTransferFrom(this.token, this.mock, this.receiver, 0n)) - .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') - .withArgs(this.token); - }); - - it('returns false on trySafeTransferFrom', async function () { - await expect(this.mock.$trySafeTransferFrom(this.token, this.mock, this.receiver, 0n)) - .to.emit(this.mock, 'return$trySafeTransferFrom') - .withArgs(false); - }); - - it('reverts on increaseAllowance', async function () { - // Call to 'token.allowance' does not return any data, resulting in a decoding error (revert without reason) - await expect(this.mock.$safeIncreaseAllowance(this.token, this.spender, 0n)).to.be.revertedWithoutReason(); - }); - - it('reverts on decreaseAllowance', async function () { - // Call to 'token.allowance' does not return any data, resulting in a decoding error (revert without reason) - await expect(this.mock.$safeDecreaseAllowance(this.token, this.spender, 0n)).to.be.revertedWithoutReason(); - }); - - it('reverts on forceApprove', async function () { - await expect(this.mock.$forceApprove(this.token, this.spender, 0n)) - .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') - .withArgs(this.token); - }); - }); - - describe('with token that returns false on all calls', function () { - beforeEach(async function () { - this.token = this.erc20ReturnFalseMock; - }); - - it('reverts on transfer', async function () { - await expect(this.mock.$safeTransfer(this.token, this.receiver, 0n)) - .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') - .withArgs(this.token); - }); - - it('returns false on trySafeTransfer', async function () { - await expect(this.mock.$trySafeTransfer(this.token, this.receiver, 0n)) - .to.emit(this.mock, 'return$trySafeTransfer') - .withArgs(false); - }); - - it('reverts on transferFrom', async function () { - await expect(this.mock.$safeTransferFrom(this.token, this.mock, this.receiver, 0n)) - .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') - .withArgs(this.token); - }); - - it('returns false on trySafeTransferFrom', async function () { - await expect(this.mock.$trySafeTransferFrom(this.token, this.mock, this.receiver, 0n)) - .to.emit(this.mock, 'return$trySafeTransferFrom') - .withArgs(false); - }); - - it('reverts on increaseAllowance', async function () { - await expect(this.mock.$safeIncreaseAllowance(this.token, this.spender, 0n)) - .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') - .withArgs(this.token); - }); - - it('reverts on decreaseAllowance', async function () { - await expect(this.mock.$safeDecreaseAllowance(this.token, this.spender, 0n)) - .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') - .withArgs(this.token); - }); - - it('reverts on forceApprove', async function () { - await expect(this.mock.$forceApprove(this.token, this.spender, 0n)) - .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') - .withArgs(this.token); - }); - }); - - describe('with token that returns true on all calls', function () { - beforeEach(async function () { - this.token = this.erc20ReturnTrueMock; - }); - - shouldOnlyRevertOnErrors(); - }); - - describe('with token that returns no boolean values', function () { - beforeEach(async function () { - this.token = this.erc20NoReturnMock; - }); - - shouldOnlyRevertOnErrors(); - }); - - describe('with usdt approval behaviour', function () { - beforeEach(async function () { - this.token = this.erc20ForceApproveMock; - }); - - describe('with initial approval', function () { - beforeEach(async function () { - await this.token.$_approve(this.mock, this.spender, 100n); - }); - - it('safeIncreaseAllowance works', async function () { - await this.mock.$safeIncreaseAllowance(this.token, this.spender, 10n); - expect(await this.token.allowance(this.mock, this.spender)).to.equal(110n); - }); - - it('safeDecreaseAllowance works', async function () { - await this.mock.$safeDecreaseAllowance(this.token, this.spender, 10n); - expect(await this.token.allowance(this.mock, this.spender)).to.equal(90n); - }); - - it('forceApprove works', async function () { - await this.mock.$forceApprove(this.token, this.spender, 200n); - expect(await this.token.allowance(this.mock, this.spender)).to.equal(200n); - }); - }); - }); - - describe('with standard ERC1363', function () { - beforeEach(async function () { - this.token = this.erc1363Mock; - }); - - shouldOnlyRevertOnErrors(); - - describe('transferAndCall', function () { - it('cannot transferAndCall to an EOA directly', async function () { - await this.token.$_mint(this.owner, 100n); - - await expect(this.token.connect(this.owner).transferAndCall(this.receiver, value, ethers.Typed.bytes(data))) - .to.be.revertedWithCustomError(this.token, 'ERC1363InvalidReceiver') - .withArgs(this.receiver); - }); - - it('can transferAndCall to an EOA using helper', async function () { - await this.token.$_mint(this.mock, value); - - await expect(this.mock.$transferAndCallRelaxed(this.token, this.receiver, value, data)) - .to.emit(this.token, 'Transfer') - .withArgs(this.mock, this.receiver, value); - }); - - it('can transferAndCall to an ERC1363Receiver using helper', async function () { - await this.token.$_mint(this.mock, value); - - await expect(this.mock.$transferAndCallRelaxed(this.token, this.erc1363Receiver, value, data)) - .to.emit(this.token, 'Transfer') - .withArgs(this.mock, this.erc1363Receiver, value) - .to.emit(this.erc1363Receiver, 'Received') - .withArgs(this.mock, this.mock, value, data); - }); - }); - - describe('transferFromAndCall', function () { - it('can transferFromAndCall to an EOA using helper', async function () { - await this.token.$_mint(this.owner, value); - await this.token.$_approve(this.owner, this.mock, ethers.MaxUint256); - - await expect(this.mock.$transferFromAndCallRelaxed(this.token, this.owner, this.receiver, value, data)) - .to.emit(this.token, 'Transfer') - .withArgs(this.owner, this.receiver, value); - }); - - it('can transferFromAndCall to an ERC1363Receiver using helper', async function () { - await this.token.$_mint(this.owner, value); - await this.token.$_approve(this.owner, this.mock, ethers.MaxUint256); - - await expect(this.mock.$transferFromAndCallRelaxed(this.token, this.owner, this.erc1363Receiver, value, data)) - .to.emit(this.token, 'Transfer') - .withArgs(this.owner, this.erc1363Receiver, value) - .to.emit(this.erc1363Receiver, 'Received') - .withArgs(this.mock, this.owner, value, data); - }); - }); - - describe('approveAndCall', function () { - it('can approveAndCall to an EOA using helper', async function () { - await expect(this.mock.$approveAndCallRelaxed(this.token, this.receiver, value, data)) - .to.emit(this.token, 'Approval') - .withArgs(this.mock, this.receiver, value); - }); - - it('can approveAndCall to an ERC1363Spender using helper', async function () { - await expect(this.mock.$approveAndCallRelaxed(this.token, this.erc1363Spender, value, data)) - .to.emit(this.token, 'Approval') - .withArgs(this.mock, this.erc1363Spender, value) - .to.emit(this.erc1363Spender, 'Approved') - .withArgs(this.mock, value, data); - }); - }); - }); - - describe('with ERC1363 that returns false on all ERC20 calls', function () { - beforeEach(async function () { - this.token = this.erc1363ReturnFalseOnErc20Mock; - }); - - it('reverts on transferAndCallRelaxed', async function () { - await expect(this.mock.$transferAndCallRelaxed(this.token, this.erc1363Receiver, 0n, data)) - .to.be.revertedWithCustomError(this.token, 'ERC1363TransferFailed') - .withArgs(this.erc1363Receiver, 0n); - }); - - it('reverts on transferFromAndCallRelaxed', async function () { - await expect(this.mock.$transferFromAndCallRelaxed(this.token, this.mock, this.erc1363Receiver, 0n, data)) - .to.be.revertedWithCustomError(this.token, 'ERC1363TransferFromFailed') - .withArgs(this.mock, this.erc1363Receiver, 0n); - }); - - it('reverts on approveAndCallRelaxed', async function () { - await expect(this.mock.$approveAndCallRelaxed(this.token, this.erc1363Spender, 0n, data)) - .to.be.revertedWithCustomError(this.token, 'ERC1363ApproveFailed') - .withArgs(this.erc1363Spender, 0n); - }); - }); - - describe('with ERC1363 that returns false on all ERC1363 calls', function () { - beforeEach(async function () { - this.token = this.erc1363ReturnFalseMock; - }); - - it('reverts on transferAndCallRelaxed', async function () { - await expect(this.mock.$transferAndCallRelaxed(this.token, this.erc1363Receiver, 0n, data)) - .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') - .withArgs(this.token); - }); - - it('reverts on transferFromAndCallRelaxed', async function () { - await expect(this.mock.$transferFromAndCallRelaxed(this.token, this.mock, this.erc1363Receiver, 0n, data)) - .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') - .withArgs(this.token); - }); - - it('reverts on approveAndCallRelaxed', async function () { - await expect(this.mock.$approveAndCallRelaxed(this.token, this.erc1363Spender, 0n, data)) - .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation') - .withArgs(this.token); - }); - }); - - describe('with ERC1363 that returns no boolean values', function () { - beforeEach(async function () { - this.token = this.erc1363NoReturnMock; - }); - - it('reverts on transferAndCallRelaxed', async function () { - await expect( - this.mock.$transferAndCallRelaxed(this.token, this.erc1363Receiver, 0n, data), - ).to.be.revertedWithoutReason(); - }); - - it('reverts on transferFromAndCallRelaxed', async function () { - await expect( - this.mock.$transferFromAndCallRelaxed(this.token, this.mock, this.erc1363Receiver, 0n, data), - ).to.be.revertedWithoutReason(); - }); - - it('reverts on approveAndCallRelaxed', async function () { - await expect( - this.mock.$approveAndCallRelaxed(this.token, this.erc1363Spender, 0n, data), - ).to.be.revertedWithoutReason(); - }); - }); - - describe('with ERC1363 with usdt approval behaviour', function () { - beforeEach(async function () { - this.token = this.erc1363ForceApproveMock; - }); - - describe('without initial approval', function () { - it('approveAndCallRelaxed works when recipient is an EOA', async function () { - await this.mock.$approveAndCallRelaxed(this.token, this.spender, 10n, data); - expect(await this.token.allowance(this.mock, this.spender)).to.equal(10n); - }); - - it('approveAndCallRelaxed works when recipient is a contract', async function () { - await this.mock.$approveAndCallRelaxed(this.token, this.erc1363Spender, 10n, data); - expect(await this.token.allowance(this.mock, this.erc1363Spender)).to.equal(10n); - }); - }); - - describe('with initial approval', function () { - it('approveAndCallRelaxed works when recipient is an EOA', async function () { - await this.token.$_approve(this.mock, this.spender, 100n); - - await this.mock.$approveAndCallRelaxed(this.token, this.spender, 10n, data); - expect(await this.token.allowance(this.mock, this.spender)).to.equal(10n); - }); - - it('approveAndCallRelaxed reverts when recipient is a contract', async function () { - await this.token.$_approve(this.mock, this.erc1363Spender, 100n); - await expect(this.mock.$approveAndCallRelaxed(this.token, this.erc1363Spender, 10n, data)).to.be.revertedWith( - 'USDT approval failure', - ); - }); - }); - }); -}); - -function shouldOnlyRevertOnErrors() { - describe('transfers', function () { - beforeEach(async function () { - await this.token.$_mint(this.owner, 100n); - await this.token.$_mint(this.mock, 100n); - await this.token.$_approve(this.owner, this.mock, ethers.MaxUint256); - }); - - it("doesn't revert on transfer", async function () { - await expect(this.mock.$safeTransfer(this.token, this.receiver, 10n)) - .to.emit(this.token, 'Transfer') - .withArgs(this.mock, this.receiver, 10n); - }); - - it('returns true on trySafeTransfer', async function () { - await expect(this.mock.$trySafeTransfer(this.token, this.receiver, 10n)) - .to.emit(this.mock, 'return$trySafeTransfer') - .withArgs(true); - }); - - it("doesn't revert on transferFrom", async function () { - await expect(this.mock.$safeTransferFrom(this.token, this.owner, this.receiver, 10n)) - .to.emit(this.token, 'Transfer') - .withArgs(this.owner, this.receiver, 10n); - }); - - it('returns true on trySafeTransferFrom', async function () { - await expect(this.mock.$trySafeTransferFrom(this.token, this.owner, this.receiver, 10n)) - .to.emit(this.mock, 'return$trySafeTransferFrom') - .withArgs(true); - }); - }); - - describe('approvals', function () { - describe('with zero allowance', function () { - beforeEach(async function () { - await this.token.$_approve(this.mock, this.spender, 0n); - }); - - it("doesn't revert when force approving a non-zero allowance", async function () { - await this.mock.$forceApprove(this.token, this.spender, 100n); - expect(await this.token.allowance(this.mock, this.spender)).to.equal(100n); - }); - - it("doesn't revert when force approving a zero allowance", async function () { - await this.mock.$forceApprove(this.token, this.spender, 0n); - expect(await this.token.allowance(this.mock, this.spender)).to.equal(0n); - }); - - it("doesn't revert when increasing the allowance", async function () { - await this.mock.$safeIncreaseAllowance(this.token, this.spender, 10n); - expect(await this.token.allowance(this.mock, this.spender)).to.equal(10n); - }); - - it('reverts when decreasing the allowance', async function () { - await expect(this.mock.$safeDecreaseAllowance(this.token, this.spender, 10n)) - .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedDecreaseAllowance') - .withArgs(this.spender, 0n, 10n); - }); - }); - - describe('with non-zero allowance', function () { - beforeEach(async function () { - await this.token.$_approve(this.mock, this.spender, 100n); - }); - - it("doesn't revert when force approving a non-zero allowance", async function () { - await this.mock.$forceApprove(this.token, this.spender, 20n); - expect(await this.token.allowance(this.mock, this.spender)).to.equal(20n); - }); - - it("doesn't revert when force approving a zero allowance", async function () { - await this.mock.$forceApprove(this.token, this.spender, 0n); - expect(await this.token.allowance(this.mock, this.spender)).to.equal(0n); - }); - - it("doesn't revert when increasing the allowance", async function () { - await this.mock.$safeIncreaseAllowance(this.token, this.spender, 10n); - expect(await this.token.allowance(this.mock, this.spender)).to.equal(110n); - }); - - it("doesn't revert when decreasing the allowance to a positive value", async function () { - await this.mock.$safeDecreaseAllowance(this.token, this.spender, 50n); - expect(await this.token.allowance(this.mock, this.spender)).to.equal(50n); - }); - - it('reverts when decreasing the allowance to a negative value', async function () { - await expect(this.mock.$safeDecreaseAllowance(this.token, this.spender, 200n)) - .to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedDecreaseAllowance') - .withArgs(this.spender, 100n, 200n); - }); - }); - }); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.behavior.js deleted file mode 100644 index adfe15a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.behavior.js +++ /dev/null @@ -1,216 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); - -const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); - -function shouldBehaveLikeERC6909() { - const firstTokenId = 1n; - const secondTokenId = 2n; - const randomTokenId = 125523n; - - const firstTokenSupply = 2000n; - const secondTokenSupply = 3000n; - const amount = 100n; - - describe('like an ERC6909', function () { - describe('balanceOf', function () { - describe("when accounts don't own tokens", function () { - it('return zero', async function () { - await expect(this.token.balanceOf(this.holder, firstTokenId)).to.eventually.be.equal(0n); - await expect(this.token.balanceOf(this.holder, secondTokenId)).to.eventually.be.equal(0n); - await expect(this.token.balanceOf(this.other, randomTokenId)).to.eventually.be.equal(0n); - }); - }); - - describe('when accounts own some tokens', function () { - beforeEach(async function () { - await this.token.$_mint(this.holder, firstTokenId, firstTokenSupply); - await this.token.$_mint(this.holder, secondTokenId, secondTokenSupply); - }); - - it('returns amount owned by the given address', async function () { - await expect(this.token.balanceOf(this.holder, firstTokenId)).to.eventually.be.equal(firstTokenSupply); - await expect(this.token.balanceOf(this.holder, secondTokenId)).to.eventually.be.equal(secondTokenSupply); - await expect(this.token.balanceOf(this.other, firstTokenId)).to.eventually.be.equal(0n); - }); - }); - }); - - describe('setOperator', function () { - it('emits an OperatorSet event and updated the value', async function () { - await expect(this.token.connect(this.holder).setOperator(this.operator, true)) - .to.emit(this.token, 'OperatorSet') - .withArgs(this.holder, this.operator, true); - - // operator for holder - await expect(this.token.isOperator(this.holder, this.operator)).to.eventually.be.true; - - // not operator for other account - await expect(this.token.isOperator(this.other, this.operator)).to.eventually.be.false; - }); - - it('can unset the operator approval', async function () { - await this.token.connect(this.holder).setOperator(this.operator, true); - - // before - await expect(this.token.isOperator(this.holder, this.operator)).to.eventually.be.true; - - // unset - await expect(this.token.connect(this.holder).setOperator(this.operator, false)) - .to.emit(this.token, 'OperatorSet') - .withArgs(this.holder, this.operator, false); - - // after - await expect(this.token.isOperator(this.holder, this.operator)).to.eventually.be.false; - }); - - it('cannot set address(0) as an operator', async function () { - await expect(this.token.connect(this.holder).setOperator(ethers.ZeroAddress, true)) - .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidSpender') - .withArgs(ethers.ZeroAddress); - }); - }); - - describe('approve', function () { - it('emits an Approval event and updates allowance', async function () { - await expect(this.token.connect(this.holder).approve(this.operator, firstTokenId, firstTokenSupply)) - .to.emit(this.token, 'Approval') - .withArgs(this.holder, this.operator, firstTokenId, firstTokenSupply); - - // approved - await expect(this.token.allowance(this.holder, this.operator, firstTokenId)).to.eventually.be.equal( - firstTokenSupply, - ); - // other account is not approved - await expect(this.token.allowance(this.other, this.operator, firstTokenId)).to.eventually.be.equal(0n); - }); - - it('can unset the approval', async function () { - await expect(this.token.connect(this.holder).approve(this.operator, firstTokenId, 0n)) - .to.emit(this.token, 'Approval') - .withArgs(this.holder, this.operator, firstTokenId, 0n); - await expect(this.token.allowance(this.holder, this.operator, firstTokenId)).to.eventually.be.equal(0n); - }); - - it('cannot give allowance to address(0)', async function () { - await expect(this.token.connect(this.holder).approve(ethers.ZeroAddress, firstTokenId, firstTokenSupply)) - .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidSpender') - .withArgs(ethers.ZeroAddress); - }); - }); - - describe('transfer', function () { - beforeEach(async function () { - await this.token.$_mint(this.holder, firstTokenId, firstTokenSupply); - await this.token.$_mint(this.holder, secondTokenId, secondTokenSupply); - }); - - it('transfers to the zero address are blocked', async function () { - await expect(this.token.connect(this.holder).transfer(ethers.ZeroAddress, firstTokenId, firstTokenSupply)) - .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidReceiver') - .withArgs(ethers.ZeroAddress); - }); - - it('reverts when insufficient balance', async function () { - await expect(this.token.connect(this.holder).transfer(this.recipient, firstTokenId, firstTokenSupply + 1n)) - .to.be.revertedWithCustomError(this.token, 'ERC6909InsufficientBalance') - .withArgs(this.holder, firstTokenSupply, firstTokenSupply + 1n, firstTokenId); - }); - - it('emits event and transfers tokens', async function () { - await expect(this.token.connect(this.holder).transfer(this.recipient, firstTokenId, amount)) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.holder, this.recipient, firstTokenId, amount); - - await expect(this.token.balanceOf(this.holder, firstTokenId)).to.eventually.equal(firstTokenSupply - amount); - await expect(this.token.balanceOf(this.recipient, firstTokenId)).to.eventually.equal(amount); - }); - }); - - describe('transferFrom', function () { - beforeEach(async function () { - await this.token.$_mint(this.holder, firstTokenId, firstTokenSupply); - await this.token.$_mint(this.holder, secondTokenId, secondTokenSupply); - }); - - it('transfer from self', async function () { - await expect(this.token.connect(this.holder).transferFrom(this.holder, this.recipient, firstTokenId, amount)) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.holder, this.recipient, firstTokenId, amount); - - await expect(this.token.balanceOf(this.holder, firstTokenId)).to.eventually.equal(firstTokenSupply - amount); - await expect(this.token.balanceOf(this.recipient, firstTokenId)).to.eventually.equal(amount); - }); - - describe('with approval', async function () { - beforeEach(async function () { - await this.token.connect(this.holder).approve(this.operator, firstTokenId, amount); - }); - - it('reverts when insufficient allowance', async function () { - await expect( - this.token.connect(this.operator).transferFrom(this.holder, this.recipient, firstTokenId, amount + 1n), - ) - .to.be.revertedWithCustomError(this.token, 'ERC6909InsufficientAllowance') - .withArgs(this.operator, amount, amount + 1n, firstTokenId); - }); - - it('should emit transfer event and update approval (without an Approval event)', async function () { - await expect( - this.token.connect(this.operator).transferFrom(this.holder, this.recipient, firstTokenId, amount - 1n), - ) - .to.emit(this.token, 'Transfer') - .withArgs(this.operator, this.holder, this.recipient, firstTokenId, amount - 1n) - .to.not.emit(this.token, 'Approval'); - - await expect(this.token.allowance(this.holder, this.operator, firstTokenId)).to.eventually.equal(1n); - }); - - it("shouldn't reduce allowance when infinite", async function () { - await this.token.connect(this.holder).approve(this.operator, firstTokenId, ethers.MaxUint256); - - await this.token.connect(this.operator).transferFrom(this.holder, this.recipient, firstTokenId, amount); - - await expect(this.token.allowance(this.holder, this.operator, firstTokenId)).to.eventually.equal( - ethers.MaxUint256, - ); - }); - }); - }); - - describe('with operator approval', function () { - beforeEach(async function () { - await this.token.connect(this.holder).setOperator(this.operator, true); - await this.token.$_mint(this.holder, firstTokenId, firstTokenSupply); - }); - - it('operator can transfer', async function () { - await expect(this.token.connect(this.operator).transferFrom(this.holder, this.recipient, firstTokenId, amount)) - .to.emit(this.token, 'Transfer') - .withArgs(this.operator, this.holder, this.recipient, firstTokenId, amount); - - await expect(this.token.balanceOf(this.holder, firstTokenId)).to.eventually.equal(firstTokenSupply - amount); - await expect(this.token.balanceOf(this.recipient, firstTokenId)).to.eventually.equal(amount); - }); - - it('operator transfer does not reduce allowance', async function () { - // Also give allowance - await this.token.connect(this.holder).approve(this.operator, firstTokenId, firstTokenSupply); - - await expect(this.token.connect(this.operator).transferFrom(this.holder, this.recipient, firstTokenId, amount)) - .to.emit(this.token, 'Transfer') - .withArgs(this.operator, this.holder, this.recipient, firstTokenId, amount); - - await expect(this.token.allowance(this.holder, this.operator, firstTokenId)).to.eventually.equal( - firstTokenSupply, - ); - }); - }); - - shouldSupportInterfaces(['ERC6909']); - }); -} - -module.exports = { - shouldBehaveLikeERC6909, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.test.js deleted file mode 100644 index fa41145..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/ERC6909.test.js +++ /dev/null @@ -1,104 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { shouldBehaveLikeERC6909 } = require('./ERC6909.behavior'); - -async function fixture() { - const [holder, operator, recipient, other] = await ethers.getSigners(); - const token = await ethers.deployContract('$ERC6909'); - return { token, holder, operator, recipient, other }; -} - -describe('ERC6909', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeERC6909(); - - describe('internal functions', function () { - const tokenId = 1990n; - const mintValue = 9001n; - const burnValue = 3000n; - - describe('_mint', function () { - it('reverts with a zero destination address', async function () { - await expect(this.token.$_mint(ethers.ZeroAddress, tokenId, mintValue)) - .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidReceiver') - .withArgs(ethers.ZeroAddress); - }); - - describe('with minted tokens', function () { - beforeEach(async function () { - this.tx = await this.token.connect(this.operator).$_mint(this.holder, tokenId, mintValue); - }); - - it('emits a Transfer event from 0 address', async function () { - await expect(this.tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.operator, ethers.ZeroAddress, this.holder, tokenId, mintValue); - }); - - it('credits the minted token value', async function () { - await expect(this.token.balanceOf(this.holder, tokenId)).to.eventually.be.equal(mintValue); - }); - }); - }); - - describe('_transfer', function () { - it('reverts when transferring from the zero address', async function () { - await expect(this.token.$_transfer(ethers.ZeroAddress, this.holder, 1n, 1n)) - .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidSender') - .withArgs(ethers.ZeroAddress); - }); - - it('reverts when transferring to the zero address', async function () { - await expect(this.token.$_transfer(this.holder, ethers.ZeroAddress, 1n, 1n)) - .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidReceiver') - .withArgs(ethers.ZeroAddress); - }); - }); - - describe('_burn', function () { - it('reverts with a zero from address', async function () { - await expect(this.token.$_burn(ethers.ZeroAddress, tokenId, burnValue)) - .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidSender') - .withArgs(ethers.ZeroAddress); - }); - - describe('with burned tokens', function () { - beforeEach(async function () { - await this.token.connect(this.operator).$_mint(this.holder, tokenId, mintValue); - this.tx = await this.token.connect(this.operator).$_burn(this.holder, tokenId, burnValue); - }); - - it('emits a Transfer event to 0 address', async function () { - await expect(this.tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.operator, this.holder, ethers.ZeroAddress, tokenId, burnValue); - }); - - it('debits the burned token value', async function () { - await expect(this.token.balanceOf(this.holder, tokenId)).to.eventually.be.equal(mintValue - burnValue); - }); - }); - }); - - describe('_approve', function () { - it('reverts when the owner is the zero address', async function () { - await expect(this.token.$_approve(ethers.ZeroAddress, this.recipient, 1n, 1n)) - .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidApprover') - .withArgs(ethers.ZeroAddress); - }); - }); - - describe('_setOperator', function () { - it('reverts when the owner is the zero address', async function () { - await expect(this.token.$_setOperator(ethers.ZeroAddress, this.operator, true)) - .to.be.revertedWithCustomError(this.token, 'ERC6909InvalidApprover') - .withArgs(ethers.ZeroAddress); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909ContentURI.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909ContentURI.test.js deleted file mode 100644 index 2a54e22..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909ContentURI.test.js +++ /dev/null @@ -1,49 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -async function fixture() { - const token = await ethers.deployContract('$ERC6909ContentURI'); - return { token }; -} - -describe('ERC6909ContentURI', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('contractURI', function () { - it('is empty string by default', async function () { - await expect(this.token.contractURI()).to.eventually.equal(''); - }); - - it('is settable by internal setter', async function () { - await this.token.$_setContractURI('https://example.com'); - await expect(this.token.contractURI()).to.eventually.equal('https://example.com'); - }); - - it('emits an event when set', async function () { - await expect(this.token.$_setContractURI('https://example.com')).to.emit(this.token, 'ContractURIUpdated'); - }); - }); - - describe('tokenURI', function () { - it('is empty string by default', async function () { - await expect(this.token.tokenURI(1n)).to.eventually.equal(''); - }); - - it('can be set by dedicated setter', async function () { - await this.token.$_setTokenURI(1n, 'https://example.com/1'); - await expect(this.token.tokenURI(1n)).to.eventually.equal('https://example.com/1'); - - // Only set for the specified token ID - await expect(this.token.tokenURI(2n)).to.eventually.equal(''); - }); - - it('emits an event when set', async function () { - await expect(this.token.$_setTokenURI(1n, 'https://example.com/1')) - .to.emit(this.token, 'URI') - .withArgs('https://example.com/1', 1n); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909Metadata.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909Metadata.test.js deleted file mode 100644 index e6d3dd9..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909Metadata.test.js +++ /dev/null @@ -1,58 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -async function fixture() { - const token = await ethers.deployContract('$ERC6909Metadata'); - return { token }; -} - -describe('ERC6909Metadata', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('name', function () { - it('is empty string be default', async function () { - await expect(this.token.name(1n)).to.eventually.equal(''); - }); - - it('can be set by dedicated setter', async function () { - await expect(this.token.$_setName(1n, 'My Token')) - .to.emit(this.token, 'ERC6909NameUpdated') - .withArgs(1n, 'My Token'); - await expect(this.token.name(1n)).to.eventually.equal('My Token'); - - // Only set for the specified token ID - await expect(this.token.name(2n)).to.eventually.equal(''); - }); - }); - - describe('symbol', function () { - it('is empty string be default', async function () { - await expect(this.token.symbol(1n)).to.eventually.equal(''); - }); - - it('can be set by dedicated setter', async function () { - await expect(this.token.$_setSymbol(1n, 'MTK')).to.emit(this.token, 'ERC6909SymbolUpdated').withArgs(1n, 'MTK'); - await expect(this.token.symbol(1n)).to.eventually.equal('MTK'); - - // Only set for the specified token ID - await expect(this.token.symbol(2n)).to.eventually.equal(''); - }); - }); - - describe('decimals', function () { - it('is 0 by default', async function () { - await expect(this.token.decimals(1n)).to.eventually.equal(0); - }); - - it('can be set by dedicated setter', async function () { - await expect(this.token.$_setDecimals(1n, 18)).to.emit(this.token, 'ERC6909DecimalsUpdated').withArgs(1n, 18); - await expect(this.token.decimals(1n)).to.eventually.equal(18); - - // Only set for the specified token ID - await expect(this.token.decimals(2n)).to.eventually.equal(0); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909TokenSupply.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909TokenSupply.test.js deleted file mode 100644 index 0b8b053..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC6909/extensions/ERC6909TokenSupply.test.js +++ /dev/null @@ -1,53 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { shouldBehaveLikeERC6909 } = require('../ERC6909.behavior'); - -async function fixture() { - const [holder, operator, recipient, other] = await ethers.getSigners(); - const token = await ethers.deployContract('$ERC6909TokenSupply'); - return { token, holder, operator, recipient, other }; -} - -describe('ERC6909TokenSupply', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeERC6909(); - - describe('totalSupply', function () { - it('is zero before any mint', async function () { - await expect(this.token.totalSupply(1n)).to.eventually.be.equal(0n); - }); - - it('minting tokens increases the total supply', async function () { - await this.token.$_mint(this.holder, 1n, 17n); - await expect(this.token.totalSupply(1n)).to.eventually.be.equal(17n); - }); - - describe('with tokens minted', function () { - const supply = 1000n; - - beforeEach(async function () { - await this.token.$_mint(this.holder, 1n, supply); - }); - - it('burning tokens decreases the total supply', async function () { - await this.token.$_burn(this.holder, 1n, 17n); - await expect(this.token.totalSupply(1n)).to.eventually.be.equal(supply - 17n); - }); - - it('supply unaffected by transfers', async function () { - await this.token.$_transfer(this.holder, this.recipient, 1n, 42n); - await expect(this.token.totalSupply(1n)).to.eventually.be.equal(supply); - }); - - it('supply unaffected by no-op', async function () { - await this.token.$_update(ethers.ZeroAddress, ethers.ZeroAddress, 1n, 42n); - await expect(this.token.totalSupply(1n)).to.eventually.be.equal(supply); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js deleted file mode 100644 index 433ffe0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js +++ /dev/null @@ -1,946 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); -const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); - -const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); -const { RevertType } = require('../../helpers/enums'); - -const firstTokenId = 5042n; -const secondTokenId = 79217n; -const nonExistentTokenId = 13n; -const fourthTokenId = 4n; - -const RECEIVER_MAGIC_VALUE = '0x150b7a02'; - -function shouldBehaveLikeERC721() { - beforeEach(async function () { - const [owner, newOwner, approved, operator, other] = this.accounts; - Object.assign(this, { owner, newOwner, approved, operator, other }); - }); - - shouldSupportInterfaces(['ERC721']); - - describe('with minted tokens', function () { - beforeEach(async function () { - await this.token.$_mint(this.owner, firstTokenId); - await this.token.$_mint(this.owner, secondTokenId); - this.to = this.other; - }); - - describe('balanceOf', function () { - describe('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(this.owner)).to.equal(2n); - }); - }); - - describe('when the given address does not own any tokens', function () { - it('returns 0', async function () { - expect(await this.token.balanceOf(this.other)).to.equal(0n); - }); - }); - - describe('when querying the zero address', function () { - it('throws', async function () { - await expect(this.token.balanceOf(ethers.ZeroAddress)) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidOwner') - .withArgs(ethers.ZeroAddress); - }); - }); - }); - - describe('ownerOf', function () { - describe('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.equal(this.owner); - }); - }); - - describe('when the given token ID was not tracked by this token', function () { - const tokenId = nonExistentTokenId; - - it('reverts', async function () { - await expect(this.token.ownerOf(tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(tokenId); - }); - }); - }); - - describe('transfers', function () { - const tokenId = firstTokenId; - const data = '0x42'; - - beforeEach(async function () { - await this.token.connect(this.owner).approve(this.approved, tokenId); - await this.token.connect(this.owner).setApprovalForAll(this.operator, true); - }); - - const transferWasSuccessful = () => { - it('transfers the ownership of the given token ID to the given address', async function () { - await this.tx(); - expect(await this.token.ownerOf(tokenId)).to.equal(this.to); - }); - - it('emits a Transfer event', async function () { - await expect(this.tx()).to.emit(this.token, 'Transfer').withArgs(this.owner, this.to, tokenId); - }); - - it('clears the approval for the token ID with no event', async function () { - await expect(this.tx()).to.not.emit(this.token, 'Approval'); - - expect(await this.token.getApproved(tokenId)).to.equal(ethers.ZeroAddress); - }); - - it('adjusts owners balances', async function () { - const balanceBefore = await this.token.balanceOf(this.owner); - await this.tx(); - expect(await this.token.balanceOf(this.owner)).to.equal(balanceBefore - 1n); - }); - - it('adjusts owners tokens by index', async function () { - if (!this.token.tokenOfOwnerByIndex) return; - - await this.tx(); - expect(await this.token.tokenOfOwnerByIndex(this.to, 0n)).to.equal(tokenId); - expect(await this.token.tokenOfOwnerByIndex(this.owner, 0n)).to.not.equal(tokenId); - }); - }; - - const shouldTransferTokensByUsers = function (fragment, opts = {}) { - describe('when called by the owner', function () { - beforeEach(async function () { - this.tx = () => - this.token.connect(this.owner)[fragment](this.owner, this.to, tokenId, ...(opts.extra ?? [])); - }); - transferWasSuccessful(); - }); - - describe('when called by the approved individual', function () { - beforeEach(async function () { - this.tx = () => - this.token.connect(this.approved)[fragment](this.owner, this.to, tokenId, ...(opts.extra ?? [])); - }); - transferWasSuccessful(); - }); - - describe('when called by the operator', function () { - beforeEach(async function () { - this.tx = () => - this.token.connect(this.operator)[fragment](this.owner, this.to, tokenId, ...(opts.extra ?? [])); - }); - transferWasSuccessful(); - }); - - describe('when called by the owner without an approved user', function () { - beforeEach(async function () { - await this.token.connect(this.owner).approve(ethers.ZeroAddress, tokenId); - this.tx = () => - this.token.connect(this.operator)[fragment](this.owner, this.to, tokenId, ...(opts.extra ?? [])); - }); - transferWasSuccessful(); - }); - - describe('when sent to the owner', function () { - beforeEach(async function () { - this.tx = () => - this.token.connect(this.owner)[fragment](this.owner, this.owner, tokenId, ...(opts.extra ?? [])); - }); - - it('keeps ownership of the token', async function () { - await this.tx(); - expect(await this.token.ownerOf(tokenId)).to.equal(this.owner); - }); - - it('clears the approval for the token ID', async function () { - await this.tx(); - expect(await this.token.getApproved(tokenId)).to.equal(ethers.ZeroAddress); - }); - - it('emits only a transfer event', async function () { - await expect(this.tx()).to.emit(this.token, 'Transfer').withArgs(this.owner, this.owner, tokenId); - }); - - it('keeps the owner balance', async function () { - const balanceBefore = await this.token.balanceOf(this.owner); - await this.tx(); - expect(await this.token.balanceOf(this.owner)).to.equal(balanceBefore); - }); - - it('keeps same tokens by index', async function () { - if (!this.token.tokenOfOwnerByIndex) return; - - expect(await Promise.all([0n, 1n].map(i => this.token.tokenOfOwnerByIndex(this.owner, i)))).to.have.members( - [firstTokenId, secondTokenId], - ); - }); - }); - - describe('when the address of the previous owner is incorrect', function () { - it('reverts', async function () { - await expect( - this.token.connect(this.owner)[fragment](this.other, this.other, tokenId, ...(opts.extra ?? [])), - ) - .to.be.revertedWithCustomError(this.token, 'ERC721IncorrectOwner') - .withArgs(this.other, tokenId, this.owner); - }); - }); - - describe('when the sender is not authorized for the token id', function () { - if (opts.unrestricted) { - it('does not revert', async function () { - await this.token.connect(this.other)[fragment](this.owner, this.other, tokenId, ...(opts.extra ?? [])); - }); - } else { - it('reverts', async function () { - await expect( - this.token.connect(this.other)[fragment](this.owner, this.other, tokenId, ...(opts.extra ?? [])), - ) - .to.be.revertedWithCustomError(this.token, 'ERC721InsufficientApproval') - .withArgs(this.other, tokenId); - }); - } - }); - - describe('when the given token ID does not exist', function () { - it('reverts', async function () { - await expect( - this.token - .connect(this.owner) - [fragment](this.owner, this.other, nonExistentTokenId, ...(opts.extra ?? [])), - ) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(nonExistentTokenId); - }); - }); - - describe('when the address to transfer the token to is the zero address', function () { - it('reverts', async function () { - await expect( - this.token.connect(this.owner)[fragment](this.owner, ethers.ZeroAddress, tokenId, ...(opts.extra ?? [])), - ) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') - .withArgs(ethers.ZeroAddress); - }); - }); - }; - - const shouldTransferSafely = function (fragment, data, opts = {}) { - // sanity - it('function exists', async function () { - expect(this.token.interface.hasFunction(fragment)).to.be.true; - }); - - describe('to a user account', function () { - shouldTransferTokensByUsers(fragment, opts); - }); - - describe('to a valid receiver contract', function () { - beforeEach(async function () { - this.to = await ethers.deployContract('ERC721ReceiverMock', [RECEIVER_MAGIC_VALUE, RevertType.None]); - }); - - shouldTransferTokensByUsers(fragment, opts); - - it('calls onERC721Received', async function () { - await expect(this.token.connect(this.owner)[fragment](this.owner, this.to, tokenId, ...(opts.extra ?? []))) - .to.emit(this.to, 'Received') - .withArgs(this.owner, this.owner, tokenId, data, anyValue); - }); - - it('calls onERC721Received from approved', async function () { - await expect( - this.token.connect(this.approved)[fragment](this.owner, this.to, tokenId, ...(opts.extra ?? [])), - ) - .to.emit(this.to, 'Received') - .withArgs(this.approved, this.owner, tokenId, data, anyValue); - }); - - describe('with an invalid token id', function () { - it('reverts', async function () { - await expect( - this.token - .connect(this.approved) - [fragment](this.owner, this.to, nonExistentTokenId, ...(opts.extra ?? [])), - ) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(nonExistentTokenId); - }); - }); - }); - }; - - for (const { fnName, opts } of [ - { fnName: 'transferFrom', opts: {} }, - { fnName: '$_transfer', opts: { unrestricted: true } }, - ]) { - describe(`via ${fnName}`, function () { - shouldTransferTokensByUsers(fnName, opts); - }); - } - - for (const { fnName, opts } of [ - { fnName: 'safeTransferFrom', opts: {} }, - { fnName: '$_safeTransfer', opts: { unrestricted: true } }, - ]) { - describe(`via ${fnName}`, function () { - describe('with data', function () { - shouldTransferSafely(fnName, data, { ...opts, extra: [ethers.Typed.bytes(data)] }); - }); - - describe('without data', function () { - shouldTransferSafely(fnName, '0x', opts); - }); - - describe('to a receiver contract returning unexpected value', function () { - it('reverts', async function () { - const invalidReceiver = await ethers.deployContract('ERC721ReceiverMock', [ - '0xdeadbeef', - RevertType.None, - ]); - - await expect(this.token.connect(this.owner)[fnName](this.owner, invalidReceiver, tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') - .withArgs(invalidReceiver); - }); - }); - - describe('to a receiver contract that reverts with message', function () { - it('reverts', async function () { - const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ - RECEIVER_MAGIC_VALUE, - RevertType.RevertWithMessage, - ]); - - await expect( - this.token.connect(this.owner)[fnName](this.owner, revertingReceiver, tokenId), - ).to.be.revertedWith('ERC721ReceiverMock: reverting'); - }); - }); - - describe('to a receiver contract that reverts without message', function () { - it('reverts', async function () { - const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ - RECEIVER_MAGIC_VALUE, - RevertType.RevertWithoutMessage, - ]); - - await expect(this.token.connect(this.owner)[fnName](this.owner, revertingReceiver, tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') - .withArgs(revertingReceiver); - }); - }); - - describe('to a receiver contract that reverts with custom error', function () { - it('reverts', async function () { - const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ - RECEIVER_MAGIC_VALUE, - RevertType.RevertWithCustomError, - ]); - - await expect(this.token.connect(this.owner)[fnName](this.owner, revertingReceiver, tokenId)) - .to.be.revertedWithCustomError(revertingReceiver, 'CustomError') - .withArgs(RECEIVER_MAGIC_VALUE); - }); - }); - - describe('to a receiver contract that panics', function () { - it('reverts', async function () { - const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ - RECEIVER_MAGIC_VALUE, - RevertType.Panic, - ]); - - await expect( - this.token.connect(this.owner)[fnName](this.owner, revertingReceiver, tokenId), - ).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO); - }); - }); - - describe('to a contract that does not implement the required function', function () { - it('reverts', async function () { - const nonReceiver = await ethers.deployContract('CallReceiverMock'); - - await expect(this.token.connect(this.owner)[fnName](this.owner, nonReceiver, tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') - .withArgs(nonReceiver); - }); - }); - }); - } - }); - - 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 () { - const receiver = await ethers.deployContract('ERC721ReceiverMock', [RECEIVER_MAGIC_VALUE, RevertType.None]); - - await expect(await this.token.$_safeMint(receiver, tokenId, ethers.Typed.bytes(data))) - .to.emit(receiver, 'Received') - .withArgs(anyValue, ethers.ZeroAddress, tokenId, data, anyValue); - }); - - it('calls onERC721Received — without data', async function () { - const receiver = await ethers.deployContract('ERC721ReceiverMock', [RECEIVER_MAGIC_VALUE, RevertType.None]); - - await expect(await this.token.$_safeMint(receiver, tokenId)) - .to.emit(receiver, 'Received') - .withArgs(anyValue, ethers.ZeroAddress, tokenId, '0x', anyValue); - }); - - describe('to a receiver contract returning unexpected value', function () { - it('reverts', async function () { - const invalidReceiver = await ethers.deployContract('ERC721ReceiverMock', ['0xdeadbeef', RevertType.None]); - - await expect(this.token.$_safeMint(invalidReceiver, tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') - .withArgs(invalidReceiver); - }); - }); - - describe('to a receiver contract that reverts with message', function () { - it('reverts', async function () { - const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ - RECEIVER_MAGIC_VALUE, - RevertType.RevertWithMessage, - ]); - - await expect(this.token.$_safeMint(revertingReceiver, tokenId)).to.be.revertedWith( - 'ERC721ReceiverMock: reverting', - ); - }); - }); - - describe('to a receiver contract that reverts without message', function () { - it('reverts', async function () { - const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ - RECEIVER_MAGIC_VALUE, - RevertType.RevertWithoutMessage, - ]); - - await expect(this.token.$_safeMint(revertingReceiver, tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') - .withArgs(revertingReceiver); - }); - }); - - describe('to a receiver contract that reverts with custom error', function () { - it('reverts', async function () { - const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ - RECEIVER_MAGIC_VALUE, - RevertType.RevertWithCustomError, - ]); - - await expect(this.token.$_safeMint(revertingReceiver, tokenId)) - .to.be.revertedWithCustomError(revertingReceiver, 'CustomError') - .withArgs(RECEIVER_MAGIC_VALUE); - }); - }); - - describe('to a receiver contract that panics', function () { - it('reverts', async function () { - const revertingReceiver = await ethers.deployContract('ERC721ReceiverMock', [ - RECEIVER_MAGIC_VALUE, - RevertType.Panic, - ]); - - await expect(this.token.$_safeMint(revertingReceiver, tokenId)).to.be.revertedWithPanic( - PANIC_CODES.DIVISION_BY_ZERO, - ); - }); - }); - - describe('to a contract that does not implement the required function', function () { - it('reverts', async function () { - const nonReceiver = await ethers.deployContract('CallReceiverMock'); - - await expect(this.token.$_safeMint(nonReceiver, tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') - .withArgs(nonReceiver); - }); - }); - }); - }); - - describe('approve', function () { - const tokenId = firstTokenId; - - const itClearsApproval = function () { - it('clears approval for the token', async function () { - expect(await this.token.getApproved(tokenId)).to.equal(ethers.ZeroAddress); - }); - }; - - const itApproves = function () { - it('sets the approval for the target address', async function () { - expect(await this.token.getApproved(tokenId)).to.equal(this.approved ?? this.approved); - }); - }; - - const itEmitsApprovalEvent = function () { - it('emits an approval event', async function () { - await expect(this.tx) - .to.emit(this.token, 'Approval') - .withArgs(this.owner, this.approved ?? this.approved, tokenId); - }); - }; - - describe('when clearing approval', function () { - describe('when there was no prior approval', function () { - beforeEach(async function () { - this.approved = ethers.ZeroAddress; - this.tx = await this.token.connect(this.owner).approve(this.approved, tokenId); - }); - - itClearsApproval(); - itEmitsApprovalEvent(); - }); - - describe('when there was a prior approval', function () { - beforeEach(async function () { - await this.token.connect(this.owner).approve(this.other, tokenId); - this.approved = ethers.ZeroAddress; - this.tx = await this.token.connect(this.owner).approve(this.approved, tokenId); - }); - - itClearsApproval(); - itEmitsApprovalEvent(); - }); - }); - - describe('when approving a non-zero address', function () { - describe('when there was no prior approval', function () { - beforeEach(async function () { - this.tx = await this.token.connect(this.owner).approve(this.approved, tokenId); - }); - - itApproves(); - itEmitsApprovalEvent(); - }); - - describe('when there was a prior approval to the same address', function () { - beforeEach(async function () { - await this.token.connect(this.owner).approve(this.approved, tokenId); - this.tx = await this.token.connect(this.owner).approve(this.approved, tokenId); - }); - - itApproves(); - itEmitsApprovalEvent(); - }); - - describe('when there was a prior approval to a different address', function () { - beforeEach(async function () { - await this.token.connect(this.owner).approve(this.other, tokenId); - this.tx = await this.token.connect(this.owner).approve(this.approved, tokenId); - }); - - itApproves(); - itEmitsApprovalEvent(); - }); - }); - - describe('when the sender does not own the given token ID', function () { - it('reverts', async function () { - await expect(this.token.connect(this.other).approve(this.approved, tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidApprover') - .withArgs(this.other); - }); - }); - - describe('when the sender is approved for the given token ID', function () { - it('reverts', async function () { - await this.token.connect(this.owner).approve(this.approved, tokenId); - - await expect(this.token.connect(this.approved).approve(this.other, tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidApprover') - .withArgs(this.approved); - }); - }); - - describe('when the sender is an operator', function () { - beforeEach(async function () { - await this.token.connect(this.owner).setApprovalForAll(this.operator, true); - - this.tx = await this.token.connect(this.operator).approve(this.approved, tokenId); - }); - - itApproves(); - itEmitsApprovalEvent(); - }); - - describe('when the given token ID does not exist', function () { - it('reverts', async function () { - await expect(this.token.connect(this.operator).approve(this.approved, nonExistentTokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(nonExistentTokenId); - }); - }); - }); - - describe('setApprovalForAll', function () { - describe('when the operator willing to approve is not the owner', function () { - describe('when there is no operator approval set by the sender', function () { - it('approves the operator', async function () { - await this.token.connect(this.owner).setApprovalForAll(this.operator, true); - - expect(await this.token.isApprovedForAll(this.owner, this.operator)).to.be.true; - }); - - it('emits an approval event', async function () { - await expect(this.token.connect(this.owner).setApprovalForAll(this.operator, true)) - .to.emit(this.token, 'ApprovalForAll') - .withArgs(this.owner, this.operator, true); - }); - }); - - describe('when the operator was set as not approved', function () { - beforeEach(async function () { - await this.token.connect(this.owner).setApprovalForAll(this.operator, false); - }); - - it('approves the operator', async function () { - await this.token.connect(this.owner).setApprovalForAll(this.operator, true); - - expect(await this.token.isApprovedForAll(this.owner, this.operator)).to.be.true; - }); - - it('emits an approval event', async function () { - await expect(this.token.connect(this.owner).setApprovalForAll(this.operator, true)) - .to.emit(this.token, 'ApprovalForAll') - .withArgs(this.owner, this.operator, true); - }); - - it('can unset the operator approval', async function () { - await this.token.connect(this.owner).setApprovalForAll(this.operator, false); - - expect(await this.token.isApprovedForAll(this.owner, this.operator)).to.be.false; - }); - }); - - describe('when the operator was already approved', function () { - beforeEach(async function () { - await this.token.connect(this.owner).setApprovalForAll(this.operator, true); - }); - - it('keeps the approval to the given address', async function () { - await this.token.connect(this.owner).setApprovalForAll(this.operator, true); - - expect(await this.token.isApprovedForAll(this.owner, this.operator)).to.be.true; - }); - - it('emits an approval event', async function () { - await expect(this.token.connect(this.owner).setApprovalForAll(this.operator, true)) - .to.emit(this.token, 'ApprovalForAll') - .withArgs(this.owner, this.operator, true); - }); - }); - }); - - describe('when the operator is address zero', function () { - it('reverts', async function () { - await expect(this.token.connect(this.owner).setApprovalForAll(ethers.ZeroAddress, true)) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidOperator') - .withArgs(ethers.ZeroAddress); - }); - }); - }); - - describe('getApproved', function () { - describe('when token is not minted', function () { - it('reverts', async function () { - await expect(this.token.getApproved(nonExistentTokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(nonExistentTokenId); - }); - }); - - describe('when token has been minted ', function () { - it('should return the zero address', async function () { - expect(await this.token.getApproved(firstTokenId)).to.equal(ethers.ZeroAddress); - }); - - describe('when account has been approved', function () { - beforeEach(async function () { - await this.token.connect(this.owner).approve(this.approved, firstTokenId); - }); - - it('returns approved account', async function () { - expect(await this.token.getApproved(firstTokenId)).to.equal(this.approved); - }); - }); - }); - }); - }); - - describe('_mint(address, uint256)', function () { - it('reverts with a null destination address', async function () { - await expect(this.token.$_mint(ethers.ZeroAddress, firstTokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') - .withArgs(ethers.ZeroAddress); - }); - - describe('with minted token', function () { - beforeEach(async function () { - this.tx = await this.token.$_mint(this.owner, firstTokenId); - }); - - it('emits a Transfer event', async function () { - await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.owner, firstTokenId); - }); - - it('creates the token', async function () { - expect(await this.token.balanceOf(this.owner)).to.equal(1n); - expect(await this.token.ownerOf(firstTokenId)).to.equal(this.owner); - }); - - it('reverts when adding a token id that already exists', async function () { - await expect(this.token.$_mint(this.owner, firstTokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidSender') - .withArgs(ethers.ZeroAddress); - }); - }); - }); - - describe('_burn', function () { - it('reverts when burning a non-existent token id', async function () { - await expect(this.token.$_burn(nonExistentTokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(nonExistentTokenId); - }); - - describe('with minted tokens', function () { - beforeEach(async function () { - await this.token.$_mint(this.owner, firstTokenId); - await this.token.$_mint(this.owner, secondTokenId); - }); - - describe('with burnt token', function () { - beforeEach(async function () { - this.tx = await this.token.$_burn(firstTokenId); - }); - - it('emits a Transfer event', async function () { - await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.owner, ethers.ZeroAddress, firstTokenId); - }); - - it('deletes the token', async function () { - expect(await this.token.balanceOf(this.owner)).to.equal(1n); - await expect(this.token.ownerOf(firstTokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(firstTokenId); - }); - - it('reverts when burning a token id that has been deleted', async function () { - await expect(this.token.$_burn(firstTokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(firstTokenId); - }); - }); - }); - }); -} - -function shouldBehaveLikeERC721Enumerable() { - beforeEach(async function () { - const [owner, newOwner, approved, operator, other] = this.accounts; - Object.assign(this, { owner, newOwner, approved, operator, other }); - }); - - shouldSupportInterfaces(['ERC721Enumerable']); - - describe('with minted tokens', function () { - beforeEach(async function () { - await this.token.$_mint(this.owner, firstTokenId); - await this.token.$_mint(this.owner, secondTokenId); - this.to = this.other; - }); - - describe('totalSupply', function () { - it('returns total token supply', async function () { - expect(await this.token.totalSupply()).to.equal(2n); - }); - }); - - 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(this.owner, 0n)).to.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 expect(this.token.tokenOfOwnerByIndex(this.owner, 2n)) - .to.be.revertedWithCustomError(this.token, 'ERC721OutOfBoundsIndex') - .withArgs(this.owner, 2n); - }); - }); - - describe('when the given address does not own any token', function () { - it('reverts', async function () { - await expect(this.token.tokenOfOwnerByIndex(this.other, 0n)) - .to.be.revertedWithCustomError(this.token, 'ERC721OutOfBoundsIndex') - .withArgs(this.other, 0n); - }); - }); - - describe('after transferring all tokens to another user', function () { - beforeEach(async function () { - await this.token.connect(this.owner).transferFrom(this.owner, this.other, firstTokenId); - await this.token.connect(this.owner).transferFrom(this.owner, this.other, secondTokenId); - }); - - it('returns correct token IDs for target', async function () { - expect(await this.token.balanceOf(this.other)).to.equal(2n); - - expect(await Promise.all([0n, 1n].map(i => this.token.tokenOfOwnerByIndex(this.other, i)))).to.have.members([ - firstTokenId, - secondTokenId, - ]); - }); - - it('returns empty collection for original owner', async function () { - expect(await this.token.balanceOf(this.owner)).to.equal(0n); - await expect(this.token.tokenOfOwnerByIndex(this.owner, 0n)) - .to.be.revertedWithCustomError(this.token, 'ERC721OutOfBoundsIndex') - .withArgs(this.owner, 0n); - }); - }); - }); - - describe('tokenByIndex', function () { - it('returns all tokens', async function () { - expect(await Promise.all([0n, 1n].map(i => this.token.tokenByIndex(i)))).to.have.members([ - firstTokenId, - secondTokenId, - ]); - }); - - it('reverts if index is greater than supply', async function () { - await expect(this.token.tokenByIndex(2n)) - .to.be.revertedWithCustomError(this.token, 'ERC721OutOfBoundsIndex') - .withArgs(ethers.ZeroAddress, 2n); - }); - - for (const tokenId of [firstTokenId, secondTokenId]) { - it(`returns all tokens after burning token ${tokenId} and minting new tokens`, async function () { - const newTokenId = 300n; - const anotherNewTokenId = 400n; - - await this.token.$_burn(tokenId); - await this.token.$_mint(this.newOwner, newTokenId); - await this.token.$_mint(this.newOwner, anotherNewTokenId); - - expect(await this.token.totalSupply()).to.equal(3n); - - expect(await Promise.all([0n, 1n, 2n].map(i => this.token.tokenByIndex(i)))) - .to.have.members([firstTokenId, secondTokenId, newTokenId, anotherNewTokenId].filter(x => x !== tokenId)) - .to.not.include(tokenId); - }); - } - }); - }); - - describe('_mint(address, uint256)', function () { - it('reverts with a null destination address', async function () { - await expect(this.token.$_mint(ethers.ZeroAddress, firstTokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') - .withArgs(ethers.ZeroAddress); - }); - - describe('with minted token', function () { - beforeEach(async function () { - await this.token.$_mint(this.owner, firstTokenId); - }); - - it('adjusts owner tokens by index', async function () { - expect(await this.token.tokenOfOwnerByIndex(this.owner, 0n)).to.equal(firstTokenId); - }); - - it('adjusts all tokens list', async function () { - expect(await this.token.tokenByIndex(0n)).to.equal(firstTokenId); - }); - }); - }); - - describe('_burn', function () { - it('reverts when burning a non-existent token id', async function () { - await expect(this.token.$_burn(firstTokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(firstTokenId); - }); - - describe('with minted tokens', function () { - beforeEach(async function () { - await this.token.$_mint(this.owner, firstTokenId); - await this.token.$_mint(this.owner, secondTokenId); - }); - - describe('with burnt token', function () { - beforeEach(async function () { - await this.token.$_burn(firstTokenId); - }); - - it('removes that token from the token list of the owner', async function () { - expect(await this.token.tokenOfOwnerByIndex(this.owner, 0n)).to.equal(secondTokenId); - }); - - it('adjusts all tokens list', async function () { - expect(await this.token.tokenByIndex(0n)).to.equal(secondTokenId); - }); - - it('burns all tokens', async function () { - await this.token.$_burn(secondTokenId); - expect(await this.token.totalSupply()).to.equal(0n); - - await expect(this.token.tokenByIndex(0n)) - .to.be.revertedWithCustomError(this.token, 'ERC721OutOfBoundsIndex') - .withArgs(ethers.ZeroAddress, 0n); - }); - }); - }); - }); -} - -function shouldBehaveLikeERC721Metadata(name, symbol) { - shouldSupportInterfaces(['ERC721Metadata']); - - describe('metadata', function () { - 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); - }); - - describe('token URI', function () { - beforeEach(async function () { - await this.token.$_mint(this.owner, firstTokenId); - }); - - it('return empty string by default', async function () { - expect(await this.token.tokenURI(firstTokenId)).to.equal(''); - }); - - it('reverts when queried for non existent token id', async function () { - await expect(this.token.tokenURI(nonExistentTokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(nonExistentTokenId); - }); - }); - }); -} - -module.exports = { - shouldBehaveLikeERC721, - shouldBehaveLikeERC721Enumerable, - shouldBehaveLikeERC721Metadata, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js deleted file mode 100644 index 1454cb0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js +++ /dev/null @@ -1,23 +0,0 @@ -const { ethers } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { shouldBehaveLikeERC721, shouldBehaveLikeERC721Metadata } = require('./ERC721.behavior'); - -const name = 'Non Fungible Token'; -const symbol = 'NFT'; - -async function fixture() { - return { - accounts: await ethers.getSigners(), - token: await ethers.deployContract('$ERC721', [name, symbol]), - }; -} - -describe('ERC721', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeERC721(); - shouldBehaveLikeERC721Metadata(name, symbol); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js deleted file mode 100644 index a3bdea7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js +++ /dev/null @@ -1,28 +0,0 @@ -const { ethers } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { - shouldBehaveLikeERC721, - shouldBehaveLikeERC721Metadata, - shouldBehaveLikeERC721Enumerable, -} = require('./ERC721.behavior'); - -const name = 'Non Fungible Token'; -const symbol = 'NFT'; - -async function fixture() { - return { - accounts: await ethers.getSigners(), - token: await ethers.deployContract('$ERC721Enumerable', [name, symbol]), - }; -} - -describe('ERC721', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeERC721(); - shouldBehaveLikeERC721Metadata(name, symbol); - shouldBehaveLikeERC721Enumerable(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js deleted file mode 100644 index d6f0b80..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js +++ /dev/null @@ -1,77 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const name = 'Non Fungible Token'; -const symbol = 'NFT'; -const tokenId = 1n; -const otherTokenId = 2n; -const unknownTokenId = 3n; - -async function fixture() { - const [owner, approved, another] = await ethers.getSigners(); - const token = await ethers.deployContract('$ERC721Burnable', [name, symbol]); - return { owner, approved, another, token }; -} - -describe('ERC721Burnable', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('like a burnable ERC721', function () { - beforeEach(async function () { - await this.token.$_mint(this.owner, tokenId); - await this.token.$_mint(this.owner, otherTokenId); - }); - - describe('burn', function () { - describe('when successful', function () { - it('emits a burn event, burns the given token ID and adjusts the balance of the owner', async function () { - const balanceBefore = await this.token.balanceOf(this.owner); - - await expect(this.token.connect(this.owner).burn(tokenId)) - .to.emit(this.token, 'Transfer') - .withArgs(this.owner, ethers.ZeroAddress, tokenId); - - await expect(this.token.ownerOf(tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(tokenId); - - expect(await this.token.balanceOf(this.owner)).to.equal(balanceBefore - 1n); - }); - }); - - describe('when there is a previous approval burned', function () { - beforeEach(async function () { - await this.token.connect(this.owner).approve(this.approved, tokenId); - await this.token.connect(this.owner).burn(tokenId); - }); - - describe('getApproved', function () { - it('reverts', async function () { - await expect(this.token.getApproved(tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(tokenId); - }); - }); - }); - - describe('when there is no previous approval burned', function () { - it('reverts', async function () { - await expect(this.token.connect(this.another).burn(tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721InsufficientApproval') - .withArgs(this.another, tokenId); - }); - }); - - describe('when the given token ID was not tracked by this contract', function () { - it('reverts', async function () { - await expect(this.token.connect(this.owner).burn(unknownTokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(unknownTokenId); - }); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.t.sol deleted file mode 100644 index eca15e7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.t.sol +++ /dev/null @@ -1,181 +0,0 @@ -// 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/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js deleted file mode 100644 index 8d8a303..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js +++ /dev/null @@ -1,228 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { sum } = require('../../../helpers/math'); - -const name = 'Non Fungible Token'; -const symbol = 'NFT'; - -describe('ERC721Consecutive', function () { - for (const offset of [0n, 1n, 42n]) { - describe(`with offset ${offset}`, function () { - async function fixture() { - const accounts = await ethers.getSigners(); - const [alice, bruce, chris, receiver] = accounts; - - const batches = [ - { receiver: alice, amount: 0n }, - { receiver: alice, amount: 1n }, - { receiver: alice, amount: 2n }, - { receiver: bruce, amount: 5n }, - { receiver: chris, amount: 0n }, - { receiver: alice, amount: 7n }, - ]; - const delegates = [alice, chris]; - - const token = await ethers.deployContract('$ERC721ConsecutiveMock', [ - name, - symbol, - offset, - delegates, - batches.map(({ receiver }) => receiver), - batches.map(({ amount }) => amount), - ]); - - return { accounts, alice, bruce, chris, receiver, batches, delegates, token }; - } - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('minting during construction', function () { - it('events are emitted at construction', async function () { - let first = offset; - for (const batch of this.batches) { - if (batch.amount > 0) { - await expect(this.token.deploymentTransaction()) - .to.emit(this.token, 'ConsecutiveTransfer') - .withArgs( - first /* fromTokenId */, - first + batch.amount - 1n /* toTokenId */, - ethers.ZeroAddress /* fromAddress */, - batch.receiver /* toAddress */, - ); - } else { - // ".to.not.emit" only looks at event name, and doesn't check the parameters - } - first += batch.amount; - } - }); - - it('ownership is set', async function () { - const owners = [ - ...Array(Number(offset)).fill(ethers.ZeroAddress), - ...this.batches.flatMap(({ receiver, amount }) => Array(Number(amount)).fill(receiver.address)), - ]; - - for (const tokenId in owners) { - if (owners[tokenId] != ethers.ZeroAddress) { - expect(await this.token.ownerOf(tokenId)).to.equal(owners[tokenId]); - } - } - }); - - it('balance & voting power are set', async function () { - for (const account of this.accounts) { - const balance = - sum(...this.batches.filter(({ receiver }) => receiver === account).map(({ amount }) => amount)) ?? 0n; - - expect(await this.token.balanceOf(account)).to.equal(balance); - - // If not delegated at construction, check before + do delegation - if (!this.delegates.includes(account)) { - expect(await this.token.getVotes(account)).to.equal(0n); - - await this.token.connect(account).delegate(account); - } - - // At this point all accounts should have delegated - expect(await this.token.getVotes(account)).to.equal(balance); - } - }); - - it('reverts on consecutive minting to the zero address', async function () { - await expect( - ethers.deployContract('$ERC721ConsecutiveMock', [ - name, - symbol, - offset, - this.delegates, - [ethers.ZeroAddress], - [10], - ]), - ) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver') - .withArgs(ethers.ZeroAddress); - }); - }); - - describe('minting after construction', function () { - it('consecutive minting is not possible after construction', async function () { - await expect(this.token.$_mintConsecutive(this.alice, 10)).to.be.revertedWithCustomError( - this.token, - 'ERC721ForbiddenBatchMint', - ); - }); - - it('simple minting is possible after construction', async function () { - const tokenId = sum(...this.batches.map(b => b.amount)) + offset; - - await expect(this.token.ownerOf(tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(tokenId); - - await expect(this.token.$_mint(this.alice, tokenId)) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.alice, tokenId); - }); - - it('cannot mint a token that has been batched minted', async function () { - const tokenId = sum(...this.batches.map(b => b.amount)) + offset - 1n; - - expect(await this.token.ownerOf(tokenId)).to.not.equal(ethers.ZeroAddress); - - await expect(this.token.$_mint(this.alice, tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721InvalidSender') - .withArgs(ethers.ZeroAddress); - }); - }); - - describe('ERC721 behavior', function () { - const tokenId = offset + 1n; - - it('core takes over ownership on transfer', async function () { - await this.token.connect(this.alice).transferFrom(this.alice, this.receiver, tokenId); - - expect(await this.token.ownerOf(tokenId)).to.equal(this.receiver); - }); - - it('tokens can be burned and re-minted #1', async function () { - await expect(this.token.connect(this.alice).$_burn(tokenId)) - .to.emit(this.token, 'Transfer') - .withArgs(this.alice, ethers.ZeroAddress, tokenId); - - await expect(this.token.ownerOf(tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(tokenId); - - await expect(this.token.$_mint(this.bruce, tokenId)) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.bruce, tokenId); - - expect(await this.token.ownerOf(tokenId)).to.equal(this.bruce); - }); - - it('tokens can be burned and re-minted #2', async function () { - const tokenId = sum(...this.batches.map(({ amount }) => amount)) + offset; - - await expect(this.token.ownerOf(tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(tokenId); - - // mint - await expect(this.token.$_mint(this.alice, tokenId)) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.alice, tokenId); - - expect(await this.token.ownerOf(tokenId)).to.equal(this.alice); - - // burn - await expect(await this.token.$_burn(tokenId)) - .to.emit(this.token, 'Transfer') - .withArgs(this.alice, ethers.ZeroAddress, tokenId); - - await expect(this.token.ownerOf(tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(tokenId); - - // re-mint - await expect(this.token.$_mint(this.bruce, tokenId)) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.bruce, tokenId); - - expect(await this.token.ownerOf(tokenId)).to.equal(this.bruce); - }); - }); - }); - } - - describe('invalid use', function () { - const receiver = ethers.Wallet.createRandom(); - - it('cannot mint a batch larger than 5000', async function () { - const factory = await ethers.getContractFactory('$ERC721ConsecutiveMock'); - - await expect(ethers.deployContract('$ERC721ConsecutiveMock', [name, symbol, 0, [], [receiver], [5001n]])) - .to.be.revertedWithCustomError(factory, 'ERC721ExceededMaxBatchMint') - .withArgs(5001n, 5000n); - }); - - it('cannot use single minting during construction', async function () { - const factory = await ethers.getContractFactory('$ERC721ConsecutiveNoConstructorMintMock'); - - await expect( - ethers.deployContract('$ERC721ConsecutiveNoConstructorMintMock', [name, symbol]), - ).to.be.revertedWithCustomError(factory, 'ERC721ForbiddenMint'); - }); - - it('consecutive mint not compatible with enumerability', async function () { - const factory = await ethers.getContractFactory('$ERC721ConsecutiveEnumerableMock'); - - await expect( - ethers.deployContract('$ERC721ConsecutiveEnumerableMock', [name, symbol, [receiver], [100n]]), - ).to.be.revertedWithCustomError(factory, 'ERC721EnumerableForbiddenBatchMint'); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js deleted file mode 100644 index acf731a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js +++ /dev/null @@ -1,81 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const name = 'Non Fungible Token'; -const symbol = 'NFT'; -const tokenId = 1n; -const otherTokenId = 2n; -const data = ethers.Typed.bytes('0x42'); - -async function fixture() { - const [owner, receiver, operator] = await ethers.getSigners(); - const token = await ethers.deployContract('$ERC721Pausable', [name, symbol]); - return { owner, receiver, operator, token }; -} - -describe('ERC721Pausable', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('when token is paused', function () { - beforeEach(async function () { - await this.token.$_mint(this.owner, tokenId); - await this.token.$_pause(); - }); - - it('reverts when trying to transferFrom', async function () { - await expect( - this.token.connect(this.owner).transferFrom(this.owner, this.receiver, tokenId), - ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); - }); - - it('reverts when trying to safeTransferFrom', async function () { - await expect( - this.token.connect(this.owner).safeTransferFrom(this.owner, this.receiver, tokenId), - ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); - }); - - it('reverts when trying to safeTransferFrom with data', async function () { - await expect( - this.token.connect(this.owner).safeTransferFrom(this.owner, this.receiver, tokenId, data), - ).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); - }); - - it('reverts when trying to mint', async function () { - await expect(this.token.$_mint(this.receiver, otherTokenId)).to.be.revertedWithCustomError( - this.token, - 'EnforcedPause', - ); - }); - - it('reverts when trying to burn', async function () { - await expect(this.token.$_burn(tokenId)).to.be.revertedWithCustomError(this.token, 'EnforcedPause'); - }); - - describe('getApproved', function () { - it('returns approved address', async function () { - expect(await this.token.getApproved(tokenId)).to.equal(ethers.ZeroAddress); - }); - }); - - describe('balanceOf', function () { - it('returns the amount of tokens owned by the given address', async function () { - expect(await this.token.balanceOf(this.owner)).to.equal(1n); - }); - }); - - describe('ownerOf', function () { - it('returns the amount of tokens owned by the given address', async function () { - expect(await this.token.ownerOf(tokenId)).to.equal(this.owner); - }); - }); - - describe('isApprovedForAll', function () { - it('returns the approval of the operator', async function () { - expect(await this.token.isApprovedForAll(this.owner, this.operator)).to.be.false; - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js deleted file mode 100644 index e11954a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js +++ /dev/null @@ -1,57 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { shouldBehaveLikeERC2981 } = require('../../common/ERC2981.behavior'); - -const name = 'Non Fungible Token'; -const symbol = 'NFT'; - -const tokenId1 = 1n; -const tokenId2 = 2n; -const royalty = 200n; -const salePrice = 1000n; - -async function fixture() { - const [account1, account2, recipient] = await ethers.getSigners(); - - const token = await ethers.deployContract('$ERC721Royalty', [name, symbol]); - await token.$_mint(account1, tokenId1); - await token.$_mint(account1, tokenId2); - - return { account1, account2, recipient, token }; -} - -describe('ERC721Royalty', function () { - beforeEach(async function () { - Object.assign( - this, - await loadFixture(fixture), - { tokenId1, tokenId2, royalty, salePrice }, // set for behavior tests - ); - }); - - describe('token specific functions', function () { - beforeEach(async function () { - await this.token.$_setTokenRoyalty(tokenId1, this.recipient, royalty); - }); - - it('royalty information are kept during burn and re-mint', async function () { - await this.token.$_burn(tokenId1); - - expect(await this.token.royaltyInfo(tokenId1, salePrice)).to.deep.equal([ - this.recipient.address, - (salePrice * royalty) / 10000n, - ]); - - await this.token.$_mint(this.account2, tokenId1); - - expect(await this.token.royaltyInfo(tokenId1, salePrice)).to.deep.equal([ - this.recipient.address, - (salePrice * royalty) / 10000n, - ]); - }); - }); - - shouldBehaveLikeERC2981(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js deleted file mode 100644 index 830c13a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js +++ /dev/null @@ -1,121 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); - -const name = 'Non Fungible Token'; -const symbol = 'NFT'; -const baseURI = 'https://api.example.com/v1/'; -const otherBaseURI = 'https://api.example.com/v2/'; -const sampleUri = 'mock://mytoken'; -const tokenId = 1n; -const nonExistentTokenId = 2n; - -async function fixture() { - const [owner] = await ethers.getSigners(); - const token = await ethers.deployContract('$ERC721URIStorageMock', [name, symbol]); - return { owner, token }; -} - -describe('ERC721URIStorage', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldSupportInterfaces(['0x49064906']); - - describe('token URI', function () { - beforeEach(async function () { - await this.token.$_mint(this.owner, tokenId); - }); - - it('it is empty by default', async function () { - expect(await this.token.tokenURI(tokenId)).to.equal(''); - }); - - it('reverts when queried for non existent token id', async function () { - await expect(this.token.tokenURI(nonExistentTokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(nonExistentTokenId); - }); - - it('can be set for a token id', async function () { - await this.token.$_setTokenURI(tokenId, sampleUri); - expect(await this.token.tokenURI(tokenId)).to.equal(sampleUri); - }); - - it('setting the uri emits an event', async function () { - await expect(this.token.$_setTokenURI(tokenId, sampleUri)) - .to.emit(this.token, 'MetadataUpdate') - .withArgs(tokenId); - }); - - it('setting the uri for non existent token id is allowed', async function () { - await expect(await this.token.$_setTokenURI(nonExistentTokenId, sampleUri)) - .to.emit(this.token, 'MetadataUpdate') - .withArgs(nonExistentTokenId); - - // value will be accessible after mint - await this.token.$_mint(this.owner, nonExistentTokenId); - expect(await this.token.tokenURI(nonExistentTokenId)).to.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(tokenId, sampleUri); - - expect(await this.token.tokenURI(tokenId)).to.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(tokenId, sampleUri); - - await this.token.setBaseURI(otherBaseURI); - expect(await this.token.tokenURI(tokenId)).to.equal(otherBaseURI + 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(tokenId)).to.equal(baseURI + tokenId); - }); - - it('tokens without URI can be burnt ', async function () { - await this.token.$_burn(tokenId); - - await expect(this.token.tokenURI(tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(tokenId); - }); - - it('tokens with URI can be burnt ', async function () { - await this.token.$_setTokenURI(tokenId, sampleUri); - - await this.token.$_burn(tokenId); - - await expect(this.token.tokenURI(tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(tokenId); - }); - - it('tokens URI is kept if token is burnt and reminted ', async function () { - await this.token.$_setTokenURI(tokenId, sampleUri); - - await this.token.$_burn(tokenId); - - await expect(this.token.tokenURI(tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken') - .withArgs(tokenId); - - await this.token.$_mint(this.owner, tokenId); - expect(await this.token.tokenURI(tokenId)).to.equal(sampleUri); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js deleted file mode 100644 index dcae1b8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js +++ /dev/null @@ -1,194 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers'); - -const time = require('../../../helpers/time'); - -const { shouldBehaveLikeVotes } = require('../../../governance/utils/Votes.behavior'); - -const TOKENS = [ - { Token: '$ERC721Votes', mode: 'blocknumber' }, - // no timestamp mode for ERC721Votes yet -]; - -const name = 'My Vote'; -const symbol = 'MTKN'; -const version = '1'; -const tokens = [ethers.parseEther('10000000'), 10n, 20n, 30n]; - -describe('ERC721Votes', function () { - for (const { Token, mode } of TOKENS) { - const fixture = async () => { - // accounts is required by shouldBehaveLikeVotes - const accounts = await ethers.getSigners(); - const [holder, recipient, other1, other2] = accounts; - - const token = await ethers.deployContract(Token, [name, symbol, name, version]); - - return { accounts, holder, recipient, other1, other2, token }; - }; - - describe(`vote with ${mode}`, function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - this.votes = this.token; - }); - - // includes ERC6372 behavior check - shouldBehaveLikeVotes(tokens, { mode, fungible: false }); - - describe('balanceOf', function () { - beforeEach(async function () { - await this.votes.$_mint(this.holder, tokens[0]); - await this.votes.$_mint(this.holder, tokens[1]); - await this.votes.$_mint(this.holder, tokens[2]); - await this.votes.$_mint(this.holder, tokens[3]); - }); - - it('grants to initial account', async function () { - expect(await this.votes.balanceOf(this.holder)).to.equal(4n); - }); - }); - - describe('transfers', function () { - beforeEach(async function () { - await this.votes.$_mint(this.holder, tokens[0]); - }); - - it('no delegation', async function () { - await expect(this.votes.connect(this.holder).transferFrom(this.holder, this.recipient, tokens[0])) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.recipient, tokens[0]) - .to.not.emit(this.token, 'DelegateVotesChanged'); - - this.holderVotes = 0n; - this.recipientVotes = 0n; - }); - - it('sender delegation', async function () { - await this.votes.connect(this.holder).delegate(this.holder); - - const tx = await this.votes.connect(this.holder).transferFrom(this.holder, this.recipient, tokens[0]); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.recipient, tokens[0]) - .to.emit(this.token, 'DelegateVotesChanged') - .withArgs(this.holder, 1n, 0n); - - const { logs } = await tx.wait(); - const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged'); - for (const event of logs.filter(event => event.fragment.name == 'Transfer')) { - expect(event.index).to.lt(index); - } - - this.holderVotes = 0n; - this.recipientVotes = 0n; - }); - - it('receiver delegation', async function () { - await this.votes.connect(this.recipient).delegate(this.recipient); - - const tx = await this.votes.connect(this.holder).transferFrom(this.holder, this.recipient, tokens[0]); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.recipient, tokens[0]) - .to.emit(this.token, 'DelegateVotesChanged') - .withArgs(this.recipient, 0n, 1n); - - const { logs } = await tx.wait(); - const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged'); - for (const event of logs.filter(event => event.fragment.name == 'Transfer')) { - expect(event.index).to.lt(index); - } - - this.holderVotes = 0n; - this.recipientVotes = 1n; - }); - - it('full delegation', async function () { - await this.votes.connect(this.holder).delegate(this.holder); - await this.votes.connect(this.recipient).delegate(this.recipient); - - const tx = await this.votes.connect(this.holder).transferFrom(this.holder, this.recipient, tokens[0]); - await expect(tx) - .to.emit(this.token, 'Transfer') - .withArgs(this.holder, this.recipient, tokens[0]) - .to.emit(this.token, 'DelegateVotesChanged') - .withArgs(this.holder, 1n, 0n) - .to.emit(this.token, 'DelegateVotesChanged') - .withArgs(this.recipient, 0n, 1n); - - const { logs } = await tx.wait(); - const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged'); - for (const event of logs.filter(event => event.fragment.name == 'Transfer')) { - expect(event.index).to.lt(index); - } - - this.holderVotes = 0; - this.recipientVotes = 1n; - }); - - it('returns the same total supply on transfers', async function () { - await this.votes.connect(this.holder).delegate(this.holder); - - const tx = await this.votes.connect(this.holder).transferFrom(this.holder, this.recipient, tokens[0]); - const timepoint = await time.clockFromReceipt[mode](tx); - - await mine(2); - - expect(await this.votes.getPastTotalSupply(timepoint - 1n)).to.equal(1n); - expect(await this.votes.getPastTotalSupply(timepoint + 1n)).to.equal(1n); - - this.holderVotes = 0n; - this.recipientVotes = 0n; - }); - - it('generally returns the voting balance at the appropriate checkpoint', async function () { - await this.votes.$_mint(this.holder, tokens[1]); - await this.votes.$_mint(this.holder, tokens[2]); - await this.votes.$_mint(this.holder, tokens[3]); - - const total = await this.votes.balanceOf(this.holder); - - const t1 = await this.votes.connect(this.holder).delegate(this.other1); - await mine(2); - const t2 = await this.votes.connect(this.holder).transferFrom(this.holder, this.other2, tokens[0]); - await mine(2); - const t3 = await this.votes.connect(this.holder).transferFrom(this.holder, this.other2, tokens[2]); - await mine(2); - const t4 = await this.votes.connect(this.other2).transferFrom(this.other2, this.holder, tokens[2]); - await mine(2); - - t1.timepoint = await time.clockFromReceipt[mode](t1); - t2.timepoint = await time.clockFromReceipt[mode](t2); - t3.timepoint = await time.clockFromReceipt[mode](t3); - t4.timepoint = await time.clockFromReceipt[mode](t4); - - expect(await this.votes.getPastVotes(this.other1, t1.timepoint - 1n)).to.equal(0n); - expect(await this.votes.getPastVotes(this.other1, t1.timepoint)).to.equal(total); - expect(await this.votes.getPastVotes(this.other1, t1.timepoint + 1n)).to.equal(total); - expect(await this.votes.getPastVotes(this.other1, t2.timepoint)).to.equal(3n); - expect(await this.votes.getPastVotes(this.other1, t2.timepoint + 1n)).to.equal(3n); - expect(await this.votes.getPastVotes(this.other1, t3.timepoint)).to.equal(2n); - expect(await this.votes.getPastVotes(this.other1, t3.timepoint + 1n)).to.equal(2n); - expect(await this.votes.getPastVotes(this.other1, t4.timepoint)).to.equal('3'); - expect(await this.votes.getPastVotes(this.other1, t4.timepoint + 1n)).to.equal(3n); - - this.holderVotes = 0n; - this.recipientVotes = 0n; - }); - - afterEach(async function () { - expect(await this.votes.getVotes(this.holder)).to.equal(this.holderVotes); - expect(await this.votes.getVotes(this.recipient)).to.equal(this.recipientVotes); - - // need to advance 2 blocks to see the effect of a transfer on "getPastVotes" - const timepoint = await time.clock[mode](); - await mine(); - expect(await this.votes.getPastVotes(this.holder, timepoint)).to.equal(this.holderVotes); - expect(await this.votes.getPastVotes(this.recipient, timepoint)).to.equal(this.recipientVotes); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js deleted file mode 100644 index eeead4c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js +++ /dev/null @@ -1,201 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { shouldBehaveLikeERC721 } = require('../ERC721.behavior'); - -const name = 'Non Fungible Token'; -const symbol = 'NFT'; -const tokenId = 1n; -const otherTokenId = 2n; - -async function fixture() { - const accounts = await ethers.getSigners(); - const [owner, approved, other] = accounts; - - const underlying = await ethers.deployContract('$ERC721', [name, symbol]); - await underlying.$_safeMint(owner, tokenId); - await underlying.$_safeMint(owner, otherTokenId); - const token = await ethers.deployContract('$ERC721Wrapper', [`Wrapped ${name}`, `W${symbol}`, underlying]); - - return { accounts, owner, approved, other, underlying, token }; -} - -describe('ERC721Wrapper', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - 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.equal(this.underlying); - }); - - describe('depositFor', function () { - it('works with token approval', async function () { - await this.underlying.connect(this.owner).approve(this.token, tokenId); - - await expect(this.token.connect(this.owner).depositFor(this.owner, [tokenId])) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.owner, this.token, tokenId) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.owner, tokenId); - }); - - it('works with approval for all', async function () { - await this.underlying.connect(this.owner).setApprovalForAll(this.token, true); - - await expect(this.token.connect(this.owner).depositFor(this.owner, [tokenId])) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.owner, this.token, tokenId) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.owner, tokenId); - }); - - it('works sending to another account', async function () { - await this.underlying.connect(this.owner).approve(this.token, tokenId); - - await expect(this.token.connect(this.owner).depositFor(this.other, [tokenId])) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.owner, this.token, tokenId) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.other, tokenId); - }); - - it('works with multiple tokens', async function () { - await this.underlying.connect(this.owner).approve(this.token, tokenId); - await this.underlying.connect(this.owner).approve(this.token, otherTokenId); - - await expect(this.token.connect(this.owner).depositFor(this.owner, [tokenId, otherTokenId])) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.owner, this.token, tokenId) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.owner, tokenId) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.owner, this.token, otherTokenId) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.owner, otherTokenId); - }); - - it('reverts with missing approval', async function () { - await expect(this.token.connect(this.owner).depositFor(this.owner, [tokenId])) - .to.be.revertedWithCustomError(this.token, 'ERC721InsufficientApproval') - .withArgs(this.token, tokenId); - }); - }); - - describe('withdrawTo', function () { - beforeEach(async function () { - await this.underlying.connect(this.owner).approve(this.token, tokenId); - await this.token.connect(this.owner).depositFor(this.owner, [tokenId]); - }); - - it('works for an owner', async function () { - await expect(this.token.connect(this.owner).withdrawTo(this.owner, [tokenId])) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.token, this.owner, tokenId) - .to.emit(this.token, 'Transfer') - .withArgs(this.owner, ethers.ZeroAddress, tokenId); - }); - - it('works for an approved', async function () { - await this.token.connect(this.owner).approve(this.approved, tokenId); - - await expect(this.token.connect(this.approved).withdrawTo(this.owner, [tokenId])) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.token, this.owner, tokenId) - .to.emit(this.token, 'Transfer') - .withArgs(this.owner, ethers.ZeroAddress, tokenId); - }); - - it('works for an approved for all', async function () { - await this.token.connect(this.owner).setApprovalForAll(this.approved, true); - - await expect(this.token.connect(this.approved).withdrawTo(this.owner, [tokenId])) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.token, this.owner, tokenId) - .to.emit(this.token, 'Transfer') - .withArgs(this.owner, ethers.ZeroAddress, tokenId); - }); - - it("doesn't work for a non-owner nor approved", async function () { - await expect(this.token.connect(this.other).withdrawTo(this.owner, [tokenId])) - .to.be.revertedWithCustomError(this.token, 'ERC721InsufficientApproval') - .withArgs(this.other, tokenId); - }); - - it('works with multiple tokens', async function () { - await this.underlying.connect(this.owner).approve(this.token, otherTokenId); - await this.token.connect(this.owner).depositFor(this.owner, [otherTokenId]); - - await expect(this.token.connect(this.owner).withdrawTo(this.owner, [tokenId, otherTokenId])) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.token, this.owner, tokenId) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.token, this.owner, tokenId) - .to.emit(this.token, 'Transfer') - .withArgs(this.owner, ethers.ZeroAddress, tokenId) - .to.emit(this.token, 'Transfer') - .withArgs(this.owner, ethers.ZeroAddress, tokenId); - }); - - it('works to another account', async function () { - await expect(this.token.connect(this.owner).withdrawTo(this.other, [tokenId])) - .to.emit(this.underlying, 'Transfer') - .withArgs(this.token, this.other, tokenId) - .to.emit(this.token, 'Transfer') - .withArgs(this.owner, ethers.ZeroAddress, tokenId); - }); - }); - - describe('onERC721Received', function () { - it('only allows calls from underlying', async function () { - await expect( - this.token.connect(this.other).onERC721Received( - this.owner, - this.token, - tokenId, - this.other.address, // Correct data - ), - ) - .to.be.revertedWithCustomError(this.token, 'ERC721UnsupportedToken') - .withArgs(this.other); - }); - - it('mints a token to from', async function () { - await expect(this.underlying.connect(this.owner).safeTransferFrom(this.owner, this.token, tokenId)) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.owner, tokenId); - }); - }); - - describe('_recover', function () { - it('works if there is something to recover', async function () { - // Should use `transferFrom` to avoid `onERC721Received` minting - await this.underlying.connect(this.owner).transferFrom(this.owner, this.token, tokenId); - - await expect(this.token.$_recover(this.other, tokenId)) - .to.emit(this.token, 'Transfer') - .withArgs(ethers.ZeroAddress, this.other, tokenId); - }); - - it('reverts if there is nothing to recover', async function () { - const holder = await this.underlying.ownerOf(tokenId); - - await expect(this.token.$_recover(holder, tokenId)) - .to.be.revertedWithCustomError(this.token, 'ERC721IncorrectOwner') - .withArgs(this.token, tokenId, holder); - }); - }); - - describe('ERC712 behavior', function () { - shouldBehaveLikeERC721(); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js deleted file mode 100644 index 31dd2fd..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js +++ /dev/null @@ -1,20 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); - -const name = 'Non Fungible Token'; -const symbol = 'NFT'; -const tokenId = 1n; - -describe('ERC721Holder', function () { - it('receives an ERC721 token', async function () { - const [owner] = await ethers.getSigners(); - - const token = await ethers.deployContract('$ERC721', [name, symbol]); - await token.$_mint(owner, tokenId); - - const receiver = await ethers.deployContract('$ERC721Holder'); - await token.connect(owner).safeTransferFrom(owner, receiver, tokenId); - - expect(await token.ownerOf(tokenId)).to.equal(receiver); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Utils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Utils.test.js deleted file mode 100644 index 2327d1a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Utils.test.js +++ /dev/null @@ -1,94 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { RevertType } = require('../../../helpers/enums'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -const tokenId = 1n; - -const RECEIVER_MAGIC_VALUE = '0x150b7a02'; - -const deployReceiver = (revertType, returnValue = RECEIVER_MAGIC_VALUE) => - ethers.deployContract('$ERC721ReceiverMock', [returnValue, revertType]); - -const fixture = async () => { - const [eoa, operator, owner] = await ethers.getSigners(); - const utils = await ethers.deployContract('$ERC721Utils'); - - const receivers = { - correct: await deployReceiver(RevertType.None), - invalid: await deployReceiver(RevertType.None, '0xdeadbeef'), - message: await deployReceiver(RevertType.RevertWithMessage), - empty: await deployReceiver(RevertType.RevertWithoutMessage), - customError: await deployReceiver(RevertType.RevertWithCustomError), - panic: await deployReceiver(RevertType.Panic), - nonReceiver: await ethers.deployContract('CallReceiverMock'), - eoa, - }; - - return { operator, owner, utils, receivers }; -}; - -describe('ERC721Utils', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('onERC721Received', function () { - it('succeeds when called by an EOA', async function () { - await expect(this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.eoa, tokenId, '0x')).to - .not.be.reverted; - }); - - it('succeeds when data is passed', async function () { - const data = '0x12345678'; - await expect(this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.correct, tokenId, data)) - .to.not.be.reverted; - }); - - it('succeeds when data is empty', async function () { - await expect(this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.correct, tokenId, '0x')) - .to.not.be.reverted; - }); - - it('reverts when receiver returns invalid value', async function () { - await expect(this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.invalid, tokenId, '0x')) - .to.be.revertedWithCustomError(this.utils, 'ERC721InvalidReceiver') - .withArgs(this.receivers.invalid); - }); - - it('reverts when receiver reverts with message', async function () { - await expect( - this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.message, tokenId, '0x'), - ).to.be.revertedWith('ERC721ReceiverMock: reverting'); - }); - - it('reverts when receiver reverts without message', async function () { - await expect(this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.empty, tokenId, '0x')) - .to.be.revertedWithCustomError(this.utils, 'ERC721InvalidReceiver') - .withArgs(this.receivers.empty); - }); - - it('reverts when receiver reverts with custom error', async function () { - await expect( - this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.customError, tokenId, '0x'), - ) - .to.be.revertedWithCustomError(this.receivers.customError, 'CustomError') - .withArgs(RECEIVER_MAGIC_VALUE); - }); - - it('reverts when receiver panics', async function () { - await expect( - this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.panic, tokenId, '0x'), - ).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO); - }); - - it('reverts when receiver does not implement onERC721Received', async function () { - await expect( - this.utils.$checkOnERC721Received(this.operator, this.owner, this.receivers.nonReceiver, tokenId, '0x'), - ) - .to.be.revertedWithCustomError(this.utils, 'ERC721InvalidReceiver') - .withArgs(this.receivers.nonReceiver); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js deleted file mode 100644 index ae6abcc..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js +++ /dev/null @@ -1,152 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); - -const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); - -function shouldBehaveLikeERC2981() { - const royaltyFraction = 10n; - - shouldSupportInterfaces(['ERC2981']); - - describe('default royalty', function () { - beforeEach(async function () { - await this.token.$_setDefaultRoyalty(this.account1, royaltyFraction); - }); - - it('checks royalty is set', async function () { - expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.deep.equal([ - this.account1.address, - (this.salePrice * royaltyFraction) / 10_000n, - ]); - }); - - it('updates royalty amount', async function () { - const newFraction = 25n; - - await this.token.$_setDefaultRoyalty(this.account1, newFraction); - - expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.deep.equal([ - this.account1.address, - (this.salePrice * newFraction) / 10_000n, - ]); - }); - - it('holds same royalty value for different tokens', async function () { - const newFraction = 20n; - - await this.token.$_setDefaultRoyalty(this.account1, newFraction); - - expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.deep.equal( - await this.token.royaltyInfo(this.tokenId2, this.salePrice), - ); - }); - - it('Remove royalty information', async function () { - const newValue = 0n; - await this.token.$_deleteDefaultRoyalty(); - - expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.deep.equal([ethers.ZeroAddress, newValue]); - - expect(await this.token.royaltyInfo(this.tokenId2, this.salePrice)).to.deep.equal([ethers.ZeroAddress, newValue]); - }); - - it('reverts if invalid parameters', async function () { - const royaltyDenominator = await this.token.$_feeDenominator(); - - await expect(this.token.$_setDefaultRoyalty(ethers.ZeroAddress, royaltyFraction)) - .to.be.revertedWithCustomError(this.token, 'ERC2981InvalidDefaultRoyaltyReceiver') - .withArgs(ethers.ZeroAddress); - - const anotherRoyaltyFraction = 11000n; - - await expect(this.token.$_setDefaultRoyalty(this.account1, anotherRoyaltyFraction)) - .to.be.revertedWithCustomError(this.token, 'ERC2981InvalidDefaultRoyalty') - .withArgs(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 newFraction = 25n; - - expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.deep.equal([ - this.account1.address, - (this.salePrice * royaltyFraction) / 10_000n, - ]); - - await this.token.$_setTokenRoyalty(this.tokenId1, this.account1, newFraction); - - expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.deep.equal([ - this.account1.address, - (this.salePrice * newFraction) / 10_000n, - ]); - }); - - it('holds different values for different tokens', async function () { - const newFraction = 20n; - - await this.token.$_setTokenRoyalty(this.tokenId2, this.account1, newFraction); - - expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.not.deep.equal( - await this.token.royaltyInfo(this.tokenId2, this.salePrice), - ); - }); - - it('reverts if invalid parameters', async function () { - const royaltyDenominator = await this.token.$_feeDenominator(); - - await expect(this.token.$_setTokenRoyalty(this.tokenId1, ethers.ZeroAddress, royaltyFraction)) - .to.be.revertedWithCustomError(this.token, 'ERC2981InvalidTokenRoyaltyReceiver') - .withArgs(this.tokenId1, ethers.ZeroAddress); - - const anotherRoyaltyFraction = 11000n; - - await expect(this.token.$_setTokenRoyalty(this.tokenId1, this.account1, anotherRoyaltyFraction)) - .to.be.revertedWithCustomError(this.token, 'ERC2981InvalidTokenRoyalty') - .withArgs(this.tokenId1, anotherRoyaltyFraction, royaltyDenominator); - }); - - it('can reset token after setting royalty', async function () { - const newFraction = 30n; - - await this.token.$_setTokenRoyalty(this.tokenId1, this.account2, newFraction); - - // Tokens must have own information - expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.deep.equal([ - this.account2.address, - (this.salePrice * newFraction) / 10_000n, - ]); - - await this.token.$_setTokenRoyalty(this.tokenId2, this.account1, 0n); - - // Token must not share default information - expect(await this.token.royaltyInfo(this.tokenId2, this.salePrice)).to.deep.equal([this.account1.address, 0n]); - }); - - it('can hold default and token royalty information', async function () { - const newFraction = 30n; - - await this.token.$_setTokenRoyalty(this.tokenId2, this.account2, newFraction); - - // Tokens must not have same values - expect(await this.token.royaltyInfo(this.tokenId1, this.salePrice)).to.not.deep.equal([ - this.account2.address, - (this.salePrice * newFraction) / 10_000n, - ]); - - // Updated token must have new values - expect(await this.token.royaltyInfo(this.tokenId2, this.salePrice)).to.deep.equal([ - this.account2.address, - (this.salePrice * newFraction) / 10_000n, - ]); - }); - }); -} - -module.exports = { - shouldBehaveLikeERC2981, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Address.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Address.test.js deleted file mode 100644 index 8307a92..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Address.test.js +++ /dev/null @@ -1,281 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -const coder = ethers.AbiCoder.defaultAbiCoder(); - -async function fixture() { - const [recipient, other] = await ethers.getSigners(); - - const mock = await ethers.deployContract('$Address'); - const target = await ethers.deployContract('CallReceiverMock'); - const targetEther = await ethers.deployContract('EtherReceiverMock'); - - return { recipient, other, mock, target, targetEther }; -} - -describe('Address', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('sendValue', function () { - describe('when sender contract has no funds', function () { - it('sends 0 wei', async function () { - await expect(this.mock.$sendValue(this.other, 0n)).to.changeEtherBalance(this.recipient, 0n); - }); - - it('reverts when sending non-zero amounts', async function () { - await expect(this.mock.$sendValue(this.other, 1n)) - .to.be.revertedWithCustomError(this.mock, 'InsufficientBalance') - .withArgs(0n, 1n); - }); - }); - - describe('when sender contract has funds', function () { - const funds = ethers.parseEther('1'); - - beforeEach(async function () { - await this.other.sendTransaction({ to: this.mock, value: funds }); - }); - - describe('with EOA recipient', function () { - it('sends 0 wei', async function () { - await expect(this.mock.$sendValue(this.recipient, 0n)).to.changeEtherBalance(this.recipient, 0n); - }); - - it('sends non-zero amounts', async function () { - await expect(this.mock.$sendValue(this.recipient, funds - 1n)).to.changeEtherBalance( - this.recipient, - funds - 1n, - ); - }); - - it('sends the whole balance', async function () { - await expect(this.mock.$sendValue(this.recipient, funds)).to.changeEtherBalance(this.recipient, funds); - expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); - }); - - it('reverts when sending more than the balance', async function () { - await expect(this.mock.$sendValue(this.recipient, funds + 1n)) - .to.be.revertedWithCustomError(this.mock, 'InsufficientBalance') - .withArgs(funds, funds + 1n); - }); - }); - - describe('with contract recipient', function () { - it('sends funds', async function () { - await this.targetEther.setAcceptEther(true); - await expect(this.mock.$sendValue(this.targetEther, funds)).to.changeEtherBalance(this.targetEther, funds); - }); - - it('reverts on recipient revert', async function () { - await this.targetEther.setAcceptEther(false); - await expect(this.mock.$sendValue(this.targetEther, funds)).to.be.revertedWithCustomError( - this.mock, - 'FailedCall', - ); - }); - }); - }); - }); - - describe('functionCall', function () { - describe('with valid contract receiver', function () { - it('calls the requested function', async function () { - const call = this.target.interface.encodeFunctionData('mockFunction'); - - await expect(this.mock.$functionCall(this.target, call)) - .to.emit(this.target, 'MockFunctionCalled') - .to.emit(this.mock, 'return$functionCall') - .withArgs(coder.encode(['string'], ['0x1234'])); - }); - - it('calls the requested empty return function', async function () { - const call = this.target.interface.encodeFunctionData('mockFunctionEmptyReturn'); - - await expect(this.mock.$functionCall(this.target, call)).to.emit(this.target, 'MockFunctionCalled'); - }); - - it('reverts when the called function reverts with no reason', async function () { - const call = this.target.interface.encodeFunctionData('mockFunctionRevertsNoReason'); - - await expect(this.mock.$functionCall(this.target, call)).to.be.revertedWithCustomError(this.mock, 'FailedCall'); - }); - - it('reverts when the called function reverts, bubbling up the revert reason', async function () { - const call = this.target.interface.encodeFunctionData('mockFunctionRevertsReason'); - - await expect(this.mock.$functionCall(this.target, call)).to.be.revertedWith('CallReceiverMock: reverting'); - }); - - it('reverts when the called function runs out of gas', async function () { - const call = this.target.interface.encodeFunctionData('mockFunctionOutOfGas'); - - await expect(this.mock.$functionCall(this.target, call, { gasLimit: 120_000n })).to.be.revertedWithCustomError( - this.mock, - 'FailedCall', - ); - }); - - it('reverts when the called function throws', async function () { - const call = this.target.interface.encodeFunctionData('mockFunctionThrows'); - - await expect(this.mock.$functionCall(this.target, call)).to.be.revertedWithPanic(PANIC_CODES.ASSERTION_ERROR); - }); - - it('reverts when function does not exist', async function () { - const call = new ethers.Interface(['function mockFunctionDoesNotExist()']).encodeFunctionData( - 'mockFunctionDoesNotExist', - ); - - await expect(this.mock.$functionCall(this.target, call)).to.be.revertedWithCustomError(this.mock, 'FailedCall'); - }); - }); - - describe('with non-contract receiver', function () { - it('reverts when address is not a contract', async function () { - const call = this.target.interface.encodeFunctionData('mockFunction'); - - await expect(this.mock.$functionCall(this.recipient, call)) - .to.be.revertedWithCustomError(this.mock, 'AddressEmptyCode') - .withArgs(this.recipient); - }); - }); - }); - - describe('functionCallWithValue', function () { - describe('with zero value', function () { - it('calls the requested function', async function () { - const call = this.target.interface.encodeFunctionData('mockFunction'); - - await expect(this.mock.$functionCallWithValue(this.target, call, 0n)) - .to.emit(this.target, 'MockFunctionCalled') - .to.emit(this.mock, 'return$functionCallWithValue') - .withArgs(coder.encode(['string'], ['0x1234'])); - }); - }); - - describe('with non-zero value', function () { - const value = ethers.parseEther('1.2'); - - it('reverts if insufficient sender balance', async function () { - const call = this.target.interface.encodeFunctionData('mockFunction'); - - await expect(this.mock.$functionCallWithValue(this.target, call, value)) - .to.be.revertedWithCustomError(this.mock, 'InsufficientBalance') - .withArgs(0n, value); - }); - - it('calls the requested function with existing value', async function () { - await this.other.sendTransaction({ to: this.mock, value }); - - const call = this.target.interface.encodeFunctionData('mockFunction'); - const tx = await this.mock.$functionCallWithValue(this.target, call, value); - - await expect(tx).to.changeEtherBalance(this.target, value); - - await expect(tx) - .to.emit(this.target, 'MockFunctionCalled') - .to.emit(this.mock, 'return$functionCallWithValue') - .withArgs(coder.encode(['string'], ['0x1234'])); - }); - - it('calls the requested function with transaction funds', async function () { - expect(await ethers.provider.getBalance(this.mock)).to.equal(0n); - - const call = this.target.interface.encodeFunctionData('mockFunction'); - const tx = await this.mock.connect(this.other).$functionCallWithValue(this.target, call, value, { value }); - - await expect(tx).to.changeEtherBalance(this.target, value); - await expect(tx) - .to.emit(this.target, 'MockFunctionCalled') - .to.emit(this.mock, 'return$functionCallWithValue') - .withArgs(coder.encode(['string'], ['0x1234'])); - }); - - it('reverts when calling non-payable functions', async function () { - await this.other.sendTransaction({ to: this.mock, value }); - - const call = this.target.interface.encodeFunctionData('mockFunctionNonPayable'); - - await expect(this.mock.$functionCallWithValue(this.target, call, value)).to.be.revertedWithCustomError( - this.mock, - 'FailedCall', - ); - }); - }); - }); - - describe('functionStaticCall', function () { - it('calls the requested function', async function () { - const call = this.target.interface.encodeFunctionData('mockStaticFunction'); - - expect(await this.mock.$functionStaticCall(this.target, call)).to.equal(coder.encode(['string'], ['0x1234'])); - }); - - it('reverts on a non-static function', async function () { - const call = this.target.interface.encodeFunctionData('mockFunction'); - - await expect(this.mock.$functionStaticCall(this.target, call)).to.be.revertedWithCustomError( - this.mock, - 'FailedCall', - ); - }); - - it('bubbles up revert reason', async function () { - const call = this.target.interface.encodeFunctionData('mockFunctionRevertsReason'); - - await expect(this.mock.$functionStaticCall(this.target, call)).to.be.revertedWith('CallReceiverMock: reverting'); - }); - - it('reverts when address is not a contract', async function () { - const call = this.target.interface.encodeFunctionData('mockFunction'); - - await expect(this.mock.$functionStaticCall(this.recipient, call)) - .to.be.revertedWithCustomError(this.mock, 'AddressEmptyCode') - .withArgs(this.recipient); - }); - }); - - describe('functionDelegateCall', function () { - it('delegate calls the requested function', async function () { - const slot = ethers.hexlify(ethers.randomBytes(32)); - const value = ethers.hexlify(ethers.randomBytes(32)); - - const call = this.target.interface.encodeFunctionData('mockFunctionWritesStorage', [slot, value]); - - expect(await ethers.provider.getStorage(this.mock, slot)).to.equal(ethers.ZeroHash); - - await expect(await this.mock.$functionDelegateCall(this.target, call)) - .to.emit(this.mock, 'return$functionDelegateCall') - .withArgs(coder.encode(['string'], ['0x1234'])); - - expect(await ethers.provider.getStorage(this.mock, slot)).to.equal(value); - }); - - it('bubbles up revert reason', async function () { - const call = this.target.interface.encodeFunctionData('mockFunctionRevertsReason'); - - await expect(this.mock.$functionDelegateCall(this.target, call)).to.be.revertedWith( - 'CallReceiverMock: reverting', - ); - }); - - it('reverts when address is not a contract', async function () { - const call = this.target.interface.encodeFunctionData('mockFunction'); - - await expect(this.mock.$functionDelegateCall(this.recipient, call)) - .to.be.revertedWithCustomError(this.mock, 'AddressEmptyCode') - .withArgs(this.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/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.t.sol deleted file mode 100644 index e45d29c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.t.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; -import {SymTest} from "halmos-cheatcodes/SymTest.sol"; -import {Arrays} from "@openzeppelin/contracts/utils/Arrays.sol"; - -contract ArraysTest is Test, SymTest { - function testSort(uint256[] memory values) public pure { - Arrays.sort(values); - _assertSort(values); - } - - function symbolicSort() public pure { - uint256[] memory values = new uint256[](3); - for (uint256 i = 0; i < 3; i++) { - values[i] = svm.createUint256("arrayElement"); - } - Arrays.sort(values); - _assertSort(values); - } - - /// Asserts - - function _assertSort(uint256[] memory values) internal pure { - for (uint256 i = 1; i < values.length; ++i) { - assertLe(values[i - 1], values[i]); - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.test.js deleted file mode 100644 index a4bc9d7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Arrays.test.js +++ /dev/null @@ -1,227 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { generators } = require('../helpers/random'); -const { capitalize } = require('../../scripts/helpers'); -const { TYPES } = require('../../scripts/generate/templates/Arrays.opts'); - -// See https://en.cppreference.com/w/cpp/algorithm/lower_bound -const lowerBound = (array, value) => { - const i = array.findIndex(element => value <= element); - return i == -1 ? array.length : i; -}; - -// See https://en.cppreference.com/w/cpp/algorithm/upper_bound -const upperBound = (array, value) => { - const i = array.findIndex(element => value < element); - return i == -1 ? array.length : i; -}; - -const bigintSign = x => (x > 0n ? 1 : x < 0n ? -1 : 0); -const comparator = (a, b) => bigintSign(ethers.toBigInt(a) - ethers.toBigInt(b)); -const hasDuplicates = array => array.some((v, i) => array.indexOf(v) != i); - -describe('Arrays', function () { - const fixture = async () => { - return { mock: await ethers.deployContract('$Arrays') }; - }; - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('search', function () { - for (const [title, { array, tests }] of Object.entries({ - 'Even number of elements': { - array: [11n, 12n, 13n, 14n, 15n, 16n, 17n, 18n, 19n, 20n], - tests: { - 'basic case': 16n, - 'first element': 11n, - 'last element': 20n, - 'searched value is over the upper boundary': 32n, - 'searched value is under the lower boundary': 2n, - }, - }, - 'Odd number of elements': { - array: [11n, 12n, 13n, 14n, 15n, 16n, 17n, 18n, 19n, 20n, 21n], - tests: { - 'basic case': 16n, - 'first element': 11n, - 'last element': 21n, - 'searched value is over the upper boundary': 32n, - 'searched value is under the lower boundary': 2n, - }, - }, - 'Array with gap': { - array: [11n, 12n, 13n, 14n, 15n, 20n, 21n, 22n, 23n, 24n], - tests: { - 'search value in gap': 17n, - }, - }, - 'Array with duplicated elements': { - array: [0n, 10n, 10n, 10n, 10n, 10n, 10n, 10n, 20n], - tests: { - 'search value is duplicated': 10n, - }, - }, - 'Array with duplicated first element': { - array: [10n, 10n, 10n, 10n, 10n, 10n, 10n, 20n], - tests: { - 'search value is duplicated first element': 10n, - }, - }, - 'Array with duplicated last element': { - array: [0n, 10n, 10n, 10n, 10n, 10n, 10n, 10n], - tests: { - 'search value is duplicated last element': 10n, - }, - }, - 'Empty array': { - array: [], - tests: { - 'always returns 0 for empty array': 10n, - }, - }, - })) { - describe(title, function () { - const fixture = async () => { - return { instance: await ethers.deployContract('Uint256ArraysMock', [array]) }; - }; - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - for (const [name, input] of Object.entries(tests)) { - describe(name, function () { - it('[deprecated] findUpperBound', async function () { - // findUpperBound does not support duplicated - if (hasDuplicates(array)) { - expect(await this.instance.findUpperBound(input)).to.equal(upperBound(array, input) - 1); - } else { - expect(await this.instance.findUpperBound(input)).to.equal(lowerBound(array, input)); - } - }); - - it('lowerBound', async function () { - expect(await this.instance.lowerBound(input)).to.equal(lowerBound(array, input)); - expect(await this.instance.lowerBoundMemory(array, input)).to.equal(lowerBound(array, input)); - }); - - it('upperBound', async function () { - expect(await this.instance.upperBound(input)).to.equal(upperBound(array, input)); - expect(await this.instance.upperBoundMemory(array, input)).to.equal(upperBound(array, input)); - }); - }); - } - }); - } - }); - - for (const { name, isValueType } of TYPES) { - const elements = Array.from({ length: 10 }, generators[name]); - - describe(name, function () { - const fixture = async () => { - return { instance: await ethers.deployContract(`${capitalize(name)}ArraysMock`, [elements]) }; - }; - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - if (isValueType) { - describe('sort', function () { - for (const length of [0, 1, 2, 8, 32, 128]) { - describe(`${name}[] of length ${length}`, function () { - beforeEach(async function () { - this.array = Array.from({ length }, generators[name]); - }); - - afterEach(async function () { - const expected = Array.from(this.array).sort(comparator); - const reversed = Array.from(expected).reverse(); - expect(await this.instance.sort(this.array)).to.deep.equal(expected); - expect(await this.instance.sortReverse(this.array)).to.deep.equal(reversed); - }); - - it('sort array', async function () { - // nothing to do here, beforeEach and afterEach already take care of everything. - }); - - if (length > 1) { - it('sort array for identical elements', async function () { - // duplicate the first value to all elements - this.array.fill(this.array.at(0)); - }); - - it('sort already sorted array', async function () { - // pre-sort the elements - this.array.sort(comparator); - }); - - it('sort reversed array', async function () { - // pre-sort in reverse order - this.array.sort(comparator).reverse(); - }); - - it('sort almost sorted array', async function () { - // pre-sort + rotate (move the last element to the front) for an almost sorted effect - this.array.sort(comparator); - this.array.unshift(this.array.pop()); - }); - } - }); - } - }); - } - - describe('unsafeAccess', function () { - describe('storage', function () { - for (const i in elements) { - it(`unsafeAccess within bounds #${i}`, async function () { - expect(await this.instance.unsafeAccess(i)).to.equal(elements[i]); - }); - } - - it('unsafeAccess outside bounds', async function () { - await expect(this.instance.unsafeAccess(elements.length)).to.not.be.rejected; - }); - - it('unsafeSetLength changes the length or the array', async function () { - const newLength = generators.uint256(); - - expect(await this.instance.length()).to.equal(elements.length); - await expect(this.instance.unsafeSetLength(newLength)).to.not.be.rejected; - expect(await this.instance.length()).to.equal(newLength); - }); - }); - - describe('memory', function () { - const fragment = `$unsafeMemoryAccess(${name}[] arr, uint256 pos)`; - - for (const i in elements) { - it(`unsafeMemoryAccess within bounds #${i}`, async function () { - expect(await this.mock[fragment](elements, i)).to.equal(elements[i]); - }); - } - - it('unsafeMemoryAccess outside bounds', async function () { - await expect(this.mock[fragment](elements, elements.length)).to.not.be.rejected; - }); - - it('unsafeMemoryAccess loop around', async function () { - for (let i = 251n; i < 256n; ++i) { - expect(await this.mock[fragment](elements, 2n ** i - 1n)).to.equal( - isValueType ? BigInt(elements.length) : generators[name].zero, - ); - expect(await this.mock[fragment](elements, 2n ** i + 0n)).to.equal(elements[0]); - expect(await this.mock[fragment](elements, 2n ** i + 1n)).to.equal(elements[1]); - } - }); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.t.sol deleted file mode 100644 index b8aa7ac..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.t.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; -import {Base64} from "@openzeppelin/contracts/utils/Base64.sol"; - -contract Base64Test is Test { - function testEncode(bytes memory input) external pure { - assertEq(Base64.encode(input), vm.toBase64(input)); - } - - function testEncodeURL(bytes memory input) external pure { - assertEq(Base64.encodeURL(input), _removePadding(vm.toBase64URL(input))); - } - - function _removePadding(string memory inputStr) internal pure returns (string memory) { - bytes memory input = bytes(inputStr); - bytes memory output; - - for (uint256 i = 0; i < input.length; ++i) { - if (input[input.length - i - 1] != 0x3d) { - output = new bytes(input.length - i); - break; - } - } - - for (uint256 i = 0; i < output.length; ++i) { - output[i] = input[i]; - } - - return string(output); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.test.js deleted file mode 100644 index 5c42746..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Base64.test.js +++ /dev/null @@ -1,59 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -// Replace "+/" with "-_" in the char table, and remove the padding -// see https://datatracker.ietf.org/doc/html/rfc4648#section-5 -const base64toBase64Url = str => str.replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', ''); - -async function fixture() { - const mock = await ethers.deployContract('$Base64'); - return { mock }; -} - -describe('Strings', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('base64', function () { - for (const { title, input, expected } of [ - { title: 'converts to base64 encoded string with double padding', input: 'test', expected: 'dGVzdA==' }, - { title: 'converts to base64 encoded string with single padding', input: 'test1', expected: 'dGVzdDE=' }, - { title: 'converts to base64 encoded string without padding', input: 'test12', expected: 'dGVzdDEy' }, - { title: 'converts to base64 encoded string (/ case)', input: 'où', expected: 'b/k=' }, - { title: 'converts to base64 encoded string (+ case)', input: 'zs~1t8', expected: 'enN+MXQ4' }, - { title: 'empty bytes', input: '', expected: '' }, - ]) - it(title, async function () { - const buffer = Buffer.from(input, 'ascii'); - expect(await this.mock.$encode(buffer)).to.equal(ethers.encodeBase64(buffer)); - expect(await this.mock.$encode(buffer)).to.equal(expected); - }); - }); - - describe('base64url', function () { - for (const { title, input, expected } of [ - { title: 'converts to base64url encoded string with double padding', input: 'test', expected: 'dGVzdA' }, - { title: 'converts to base64url encoded string with single padding', input: 'test1', expected: 'dGVzdDE' }, - { title: 'converts to base64url encoded string without padding', input: 'test12', expected: 'dGVzdDEy' }, - { title: 'converts to base64url encoded string (_ case)', input: 'où', expected: 'b_k' }, - { title: 'converts to base64url encoded string (- case)', input: 'zs~1t8', expected: 'enN-MXQ4' }, - { title: 'empty bytes', input: '', expected: '' }, - ]) - it(title, async function () { - const buffer = Buffer.from(input, 'ascii'); - expect(await this.mock.$encodeURL(buffer)).to.equal(base64toBase64Url(ethers.encodeBase64(buffer))); - expect(await this.mock.$encodeURL(buffer)).to.equal(expected); - }); - }); - - it('Encode reads beyond the input buffer into dirty memory', async function () { - const mock = await ethers.deployContract('Base64Dirty'); - const buffer32 = ethers.id('example'); - const buffer31 = buffer32.slice(0, -2); - - expect(await mock.encode(buffer31)).to.equal(ethers.encodeBase64(buffer31)); - expect(await mock.encode(buffer32)).to.equal(ethers.encodeBase64(buffer32)); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.t.sol deleted file mode 100644 index eda4da6..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.t.sol +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.24; - -import {Test} from "forge-std/Test.sol"; -import {Blockhash} from "../../contracts/utils/Blockhash.sol"; - -contract BlockhashTest is Test { - uint256 internal startingBlock; - - address internal constant SYSTEM_ADDRESS = 0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE; - - // See https://eips.ethereum.org/EIPS/eip-2935#bytecode - // Generated using https://www.evm.codes/playground - bytes private constant HISTORY_STORAGE_BYTECODE = - hex"3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500"; - - function setUp() public { - vm.roll(block.number + 100); - - startingBlock = block.number; - vm.etch(Blockhash.HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_BYTECODE); - } - - function testFuzzRecentBlocks(uint8 offset, uint64 currentBlock, bytes32 expectedHash) public { - // Recent blocks (1-256 blocks old) - uint256 boundedOffset = uint256(offset) + 1; - vm.assume(currentBlock > boundedOffset); - vm.roll(currentBlock); - - uint256 targetBlock = currentBlock - boundedOffset; - vm.setBlockhash(targetBlock, expectedHash); - - bytes32 result = Blockhash.blockHash(targetBlock); - assertEq(result, blockhash(targetBlock)); - assertEq(result, expectedHash); - } - - function testFuzzHistoryBlocks(uint16 offset, uint256 currentBlock, bytes32 expectedHash) public { - // History blocks (257-8191 blocks old) - offset = uint16(bound(offset, 257, 8191)); - vm.assume(currentBlock > offset); - vm.roll(currentBlock); - - uint256 targetBlock = currentBlock - offset; - _setHistoryBlockhash(targetBlock, expectedHash); - - bytes32 result = Blockhash.blockHash(targetBlock); - (bool success, bytes memory returndata) = Blockhash.HISTORY_STORAGE_ADDRESS.staticcall( - abi.encodePacked(bytes32(targetBlock)) - ); - assertTrue(success); - assertEq(result, abi.decode(returndata, (bytes32))); - assertEq(result, expectedHash); - } - - function testFuzzVeryOldBlocks(uint256 offset, uint256 currentBlock) public { - // Very old blocks (>8191 blocks old) - offset = bound(offset, 8192, type(uint256).max); - vm.assume(currentBlock > offset); - vm.roll(currentBlock); - - uint256 targetBlock = currentBlock - offset; - bytes32 result = Blockhash.blockHash(targetBlock); - assertEq(result, bytes32(0)); - } - - function testFuzzFutureBlocks(uint256 offset, uint256 currentBlock) public { - // Future blocks - offset = bound(offset, 1, type(uint256).max); - vm.roll(currentBlock); - - unchecked { - uint256 targetBlock = currentBlock + offset; - bytes32 result = Blockhash.blockHash(targetBlock); - assertEq(result, blockhash(targetBlock)); - } - } - - function testUnsupportedChainsReturnZeroWhenOutOfRange() public { - vm.etch(Blockhash.HISTORY_STORAGE_ADDRESS, hex""); - - vm.roll(block.number + 1000); - assertEq(Blockhash.blockHash(block.number - 1000), bytes32(0)); - } - - function _setHistoryBlockhash(bytes32 blockHash) internal { - _setHistoryBlockhash(block.number, blockHash); - } - - function _setHistoryBlockhash(uint256 blockNumber, bytes32 blockHash) internal { - // Subtracting 1 due to bug encountered during coverage - uint256 currentBlock = block.number - 1; - vm.assume(blockNumber < type(uint256).max); - vm.roll(blockNumber + 1); // roll to the next block so the storage contract sets the parent's blockhash - vm.prank(SYSTEM_ADDRESS); - (bool success, ) = Blockhash.HISTORY_STORAGE_ADDRESS.call(abi.encode(blockHash)); // set parent's blockhash - assertTrue(success); - vm.roll(currentBlock + 1); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.test.js deleted file mode 100644 index a3de265..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Blockhash.test.js +++ /dev/null @@ -1,76 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture, mine, mineUpTo, setCode } = require('@nomicfoundation/hardhat-network-helpers'); -const { impersonate } = require('../helpers/account'); - -async function fixture() { - const mock = await ethers.deployContract('$Blockhash'); - return { mock }; -} - -const HISTORY_STORAGE_ADDRESS = '0x0000F90827F1C53a10cb7A02335B175320002935'; -const SYSTEM_ADDRESS = '0xfffffffffffffffffffffffffffffffffffffffe'; -const HISTORY_SERVE_WINDOW = 8191; -const BLOCKHASH_SERVE_WINDOW = 256; - -describe('Blockhash', function () { - before(async function () { - Object.assign(this, await loadFixture(fixture)); - - impersonate(SYSTEM_ADDRESS); - this.systemSigner = await ethers.getSigner(SYSTEM_ADDRESS); - }); - - it('recent block', async function () { - await mine(); - - const mostRecentBlock = (await ethers.provider.getBlock('latest')).number; - const blockToCheck = mostRecentBlock - 1; - const fetchedHash = (await ethers.provider.getBlock(blockToCheck)).hash; - await expect(this.mock.$blockHash(blockToCheck)).to.eventually.equal(fetchedHash); - }); - - it('old block', async function () { - await mine(); - - const mostRecentBlock = await ethers.provider.getBlock('latest'); - - // Call the history address with the most recent block hash - await this.systemSigner.sendTransaction({ - to: HISTORY_STORAGE_ADDRESS, - data: mostRecentBlock.hash, - }); - - await mineUpTo(mostRecentBlock.number + BLOCKHASH_SERVE_WINDOW + 10); - - // Verify blockhash after setting history - await expect(this.mock.$blockHash(mostRecentBlock.number)).to.eventually.equal(mostRecentBlock.hash); - }); - - it('very old block', async function () { - await mine(); - - const mostRecentBlock = await ethers.provider.getBlock('latest'); - await mineUpTo(mostRecentBlock.number + HISTORY_SERVE_WINDOW + 10); - - await expect(this.mock.$blockHash(mostRecentBlock.number)).to.eventually.equal(ethers.ZeroHash); - }); - - it('future block', async function () { - await mine(); - - const mostRecentBlock = await ethers.provider.getBlock('latest'); - const blockToCheck = mostRecentBlock.number + 10; - await expect(this.mock.$blockHash(blockToCheck)).to.eventually.equal(ethers.ZeroHash); - }); - - it('unsupported chain', async function () { - await setCode(HISTORY_STORAGE_ADDRESS, '0x00'); - - const mostRecentBlock = await ethers.provider.getBlock('latest'); - await mineUpTo(mostRecentBlock.number + BLOCKHASH_SERVE_WINDOW + 10); - - await expect(this.mock.$blockHash(mostRecentBlock.number)).to.eventually.equal(ethers.ZeroHash); - await expect(this.mock.$blockHash(mostRecentBlock.number + 20)).to.eventually.not.equal(ethers.ZeroHash); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.t.sol deleted file mode 100644 index 30f1421..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.t.sol +++ /dev/null @@ -1,117 +0,0 @@ -// 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"; -import {Bytes} from "@openzeppelin/contracts/utils/Bytes.sol"; - -contract BytesTest is Test { - using Bytes for bytes; - - // INDEX OF - function testIndexOf(bytes memory buffer, bytes1 s) public pure { - uint256 result = Bytes.indexOf(buffer, s); - - if (buffer.length == 0) { - // Case 0: buffer is empty - assertEq(result, type(uint256).max); - } else if (result == type(uint256).max) { - // Case 1: search value could not be found - for (uint256 i = 0; i < buffer.length; ++i) assertNotEq(buffer[i], s); - } else { - // Case 2: search value was found - assertEq(buffer[result], s); - // search value is not present anywhere before the found location - for (uint256 i = 0; i < result; ++i) assertNotEq(buffer[i], s); - } - } - - function testIndexOf(bytes memory buffer, bytes1 s, uint256 pos) public pure { - uint256 result = Bytes.indexOf(buffer, s, pos); - - if (buffer.length == 0) { - // Case 0: buffer is empty - assertEq(result, type(uint256).max); - } else if (result == type(uint256).max) { - // Case 1: search value could not be found - for (uint256 i = pos; i < buffer.length; ++i) assertNotEq(buffer[i], s); - } else { - // Case 2: search value was found - assertEq(buffer[result], s); - // search value is not present anywhere before the found location - for (uint256 i = pos; i < result; ++i) assertNotEq(buffer[i], s); - } - } - - function testLastIndexOf(bytes memory buffer, bytes1 s) public pure { - uint256 result = Bytes.lastIndexOf(buffer, s); - - if (buffer.length == 0) { - // Case 0: buffer is empty - assertEq(result, type(uint256).max); - } else if (result == type(uint256).max) { - // Case 1: search value could not be found - for (uint256 i = 0; i < buffer.length; ++i) assertNotEq(buffer[i], s); - } else { - // Case 2: search value was found - assertEq(buffer[result], s); - // search value is not present anywhere after the found location - for (uint256 i = result + 1; i < buffer.length; ++i) assertNotEq(buffer[i], s); - } - } - - function testLastIndexOf(bytes memory buffer, bytes1 s, uint256 pos) public pure { - uint256 result = Bytes.lastIndexOf(buffer, s, pos); - - if (buffer.length == 0) { - // Case 0: buffer is empty - assertEq(result, type(uint256).max); - } else if (result == type(uint256).max) { - // Case 1: search value could not be found - for (uint256 i = 0; i <= Math.min(pos, buffer.length - 1); ++i) assertNotEq(buffer[i], s); - } else { - // Case 2: search value was found - assertEq(buffer[result], s); - // search value is not present anywhere after the found location - for (uint256 i = result + 1; i <= Math.min(pos, buffer.length - 1); ++i) assertNotEq(buffer[i], s); - } - } - - // SLICES - function testSliceWithStartOnly(bytes memory buffer, uint256 start) public pure { - bytes memory originalBuffer = bytes.concat(buffer); - bytes memory result = buffer.slice(start); - - // Original buffer was not modified - assertEq(buffer, originalBuffer); - - // Should return bytes from start to end - assertEq(result.length, Math.saturatingSub(buffer.length, start)); - - // Verify content matches - for (uint256 i = 0; i < result.length; ++i) { - assertEq(result[i], buffer[start + i]); - } - } - - function testSlice(bytes memory buffer, uint256 start, uint256 end) public pure { - bytes memory originalBuffer = bytes.concat(buffer); - bytes memory result = buffer.slice(start, end); - - // Original buffer was not modified - assertEq(buffer, originalBuffer); - - // Calculate expected bounds after sanitization - uint256 sanitizedEnd = Math.min(end, buffer.length); - uint256 sanitizedStart = Math.min(start, sanitizedEnd); - uint256 expectedLength = sanitizedEnd - sanitizedStart; - - assertEq(result.length, expectedLength); - - // Verify content matches when there's content to verify - for (uint256 i = 0; i < result.length; ++i) { - assertEq(result[i], buffer[sanitizedStart + i]); - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.test.js deleted file mode 100644 index f2a1b8f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Bytes.test.js +++ /dev/null @@ -1,104 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -async function fixture() { - const mock = await ethers.deployContract('$Bytes'); - return { mock }; -} - -const lorem = ethers.toUtf8Bytes( - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', -); -const present = lorem.at(1); -const absent = 255; - -describe('Bytes', function () { - before(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('indexOf', function () { - it('first', async function () { - await expect(this.mock.$indexOf(lorem, ethers.toBeHex(present))).to.eventually.equal(lorem.indexOf(present)); - }); - - it('from index', async function () { - for (const start in Array(lorem.length + 10).fill()) { - const index = lorem.indexOf(present, start); - const result = index === -1 ? ethers.MaxUint256 : index; - await expect( - this.mock.$indexOf(lorem, ethers.toBeHex(present), ethers.Typed.uint256(start)), - ).to.eventually.equal(result); - } - }); - - it('absent', async function () { - await expect(this.mock.$indexOf(lorem, ethers.toBeHex(absent))).to.eventually.equal(ethers.MaxUint256); - }); - - it('empty buffer', async function () { - await expect(this.mock.$indexOf('0x', '0x00')).to.eventually.equal(ethers.MaxUint256); - await expect(this.mock.$indexOf('0x', '0x00', ethers.Typed.uint256(17))).to.eventually.equal(ethers.MaxUint256); - }); - }); - - describe('lastIndexOf', function () { - it('first', async function () { - await expect(this.mock.$lastIndexOf(lorem, ethers.toBeHex(present))).to.eventually.equal( - lorem.lastIndexOf(present), - ); - }); - - it('from index', async function () { - for (const start in Array(lorem.length + 10).fill()) { - const index = lorem.lastIndexOf(present, start); - const result = index === -1 ? ethers.MaxUint256 : index; - await expect( - this.mock.$lastIndexOf(lorem, ethers.toBeHex(present), ethers.Typed.uint256(start)), - ).to.eventually.equal(result); - } - }); - - it('absent', async function () { - await expect(this.mock.$lastIndexOf(lorem, ethers.toBeHex(absent))).to.eventually.equal(ethers.MaxUint256); - }); - - it('empty buffer', async function () { - await expect(this.mock.$lastIndexOf('0x', '0x00')).to.eventually.equal(ethers.MaxUint256); - await expect(this.mock.$lastIndexOf('0x', '0x00', ethers.Typed.uint256(17))).to.eventually.equal( - ethers.MaxUint256, - ); - }); - }); - - describe('slice', function () { - describe('slice(bytes, uint256)', function () { - for (const [descr, start] of Object.entries({ - 'start = 0': 0, - 'start within bound': 10, - 'start out of bound': 1000, - })) { - it(descr, async function () { - const result = ethers.hexlify(lorem.slice(start)); - await expect(this.mock.$slice(lorem, start)).to.eventually.equal(result); - }); - } - }); - - describe('slice(bytes, uint256, uint256)', function () { - for (const [descr, [start, end]] of Object.entries({ - 'start = 0': [0, 42], - 'start and end within bound': [17, 42], - 'end out of bound': [42, 1000], - 'start = end': [17, 17], - 'start > end': [42, 17], - })) { - it(descr, async function () { - const result = ethers.hexlify(lorem.slice(start, end)); - await expect(this.mock.$slice(lorem, start, ethers.Typed.uint256(end))).to.eventually.equal(result); - }); - } - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/CAIP.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/CAIP.test.js deleted file mode 100644 index cd5995c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/CAIP.test.js +++ /dev/null @@ -1,53 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { CHAINS, getLocalCAIP } = require('../helpers/chains'); - -async function fixture() { - const caip2 = await ethers.deployContract('$CAIP2'); - const caip10 = await ethers.deployContract('$CAIP10'); - return { caip2, caip10 }; -} - -describe('CAIP utilities', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('CAIP-2', function () { - it('local()', async function () { - const { caip2 } = await getLocalCAIP(); - expect(await this.caip2.$local()).to.equal(caip2); - }); - - for (const { namespace, reference, caip2 } of Object.values(CHAINS)) - it(`format(${namespace}, ${reference})`, async function () { - expect(await this.caip2.$format(namespace, reference)).to.equal(caip2); - }); - - for (const { namespace, reference, caip2 } of Object.values(CHAINS)) - it(`parse(${caip2})`, async function () { - expect(await this.caip2.$parse(caip2)).to.deep.equal([namespace, reference]); - }); - }); - - describe('CAIP-10', function () { - const { address: account } = ethers.Wallet.createRandom(); - - it(`local(${account})`, async function () { - const { caip10 } = await getLocalCAIP(account); - expect(await this.caip10.$local(ethers.Typed.address(account))).to.equal(caip10); - }); - - for (const { account, caip2, caip10 } of Object.values(CHAINS)) - it(`format(${caip2}, ${account})`, async function () { - expect(await this.caip10.$format(ethers.Typed.string(caip2), ethers.Typed.string(account))).to.equal(caip10); - }); - - for (const { account, caip2, caip10 } of Object.values(CHAINS)) - it(`parse(${caip10})`, async function () { - expect(await this.caip10.$parse(caip10)).to.deep.equal([caip2, account]); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Calldata.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Calldata.test.js deleted file mode 100644 index 7e9d3d4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Calldata.test.js +++ /dev/null @@ -1,22 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -async function fixture() { - const mock = await ethers.deployContract('$Calldata'); - return { mock }; -} - -describe('Calldata utilities', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('emptyBytes', async function () { - await expect(this.mock.$emptyBytes()).to.eventually.equal('0x'); - }); - - it('emptyString', async function () { - await expect(this.mock.$emptyString()).to.eventually.equal(''); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.behavior.js deleted file mode 100644 index adb140f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.behavior.js +++ /dev/null @@ -1,48 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -async function fixture() { - return { contextHelper: await ethers.deployContract('ContextMockCaller', []) }; -} -function shouldBehaveLikeRegularContext() { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('msgSender', function () { - it('returns the transaction sender when called from an EOA', async function () { - await expect(this.context.connect(this.sender).msgSender()).to.emit(this.context, 'Sender').withArgs(this.sender); - }); - - it('returns the transaction sender when called from another contract', async function () { - await expect(this.contextHelper.connect(this.sender).callSender(this.context)) - .to.emit(this.context, 'Sender') - .withArgs(this.contextHelper); - }); - }); - - describe('msgData', function () { - const args = [42n, 'OpenZeppelin']; - - it('returns the transaction data when called from an EOA', async function () { - const callData = this.context.interface.encodeFunctionData('msgData', args); - - await expect(this.context.msgData(...args)) - .to.emit(this.context, 'Data') - .withArgs(callData, ...args); - }); - - it('returns the transaction sender when from another contract', async function () { - const callData = this.context.interface.encodeFunctionData('msgData', args); - - await expect(this.contextHelper.callData(this.context, ...args)) - .to.emit(this.context, 'Data') - .withArgs(callData, ...args); - }); - }); -} - -module.exports = { - shouldBehaveLikeRegularContext, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.test.js deleted file mode 100644 index b766729..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Context.test.js +++ /dev/null @@ -1,18 +0,0 @@ -const { ethers } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { shouldBehaveLikeRegularContext } = require('./Context.behavior'); - -async function fixture() { - const [sender] = await ethers.getSigners(); - const context = await ethers.deployContract('ContextMock', []); - return { sender, context }; -} - -describe('Context', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeRegularContext(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.t.sol deleted file mode 100644 index b73db9f..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.t.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; -import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; - -contract Create2Test is Test { - function testSymbolicComputeAddressSpillage(bytes32 salt, bytes32 bytecodeHash, address deployer) public pure { - address predicted = Create2.computeAddress(salt, bytecodeHash, deployer); - bytes32 spillage; - assembly ("memory-safe") { - spillage := and(predicted, 0xffffffffffffffffffffffff0000000000000000000000000000000000000000) - } - assertEq(spillage, bytes32(0)); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.test.js deleted file mode 100644 index 99c47a0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Create2.test.js +++ /dev/null @@ -1,190 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -const { RevertType } = require('../helpers/enums'); - -async function fixture() { - const [deployer, other] = await ethers.getSigners(); - - const factory = await ethers.deployContract('$Create2'); - - // Bytecode for deploying a contract that includes a constructor. - // We use a vesting wallet, with 3 constructor arguments. - const constructorByteCode = await ethers - .getContractFactory('VestingWallet') - .then(factory => ethers.concat([factory.bytecode, factory.interface.encodeDeploy([other.address, 0n, 0n])])); - - // Bytecode for deploying a contract that has no constructor log. - // Here we use the Create2 helper factory. - const constructorLessBytecode = await ethers - .getContractFactory('$Create2') - .then(factory => ethers.concat([factory.bytecode, factory.interface.encodeDeploy([])])); - - const mockFactory = await ethers.getContractFactory('ConstructorMock'); - - return { deployer, other, factory, constructorByteCode, constructorLessBytecode, mockFactory }; -} - -describe('Create2', function () { - const salt = 'salt message'; - const saltHex = ethers.id(salt); - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('computeAddress', function () { - it('computes the correct contract address', async function () { - const onChainComputed = await this.factory.$computeAddress(saltHex, ethers.keccak256(this.constructorByteCode)); - const offChainComputed = ethers.getCreate2Address( - this.factory.target, - saltHex, - ethers.keccak256(this.constructorByteCode), - ); - expect(onChainComputed).to.equal(offChainComputed); - }); - - it('computes the correct contract address with deployer', async function () { - const onChainComputed = await this.factory.$computeAddress( - saltHex, - ethers.keccak256(this.constructorByteCode), - ethers.Typed.address(this.deployer), - ); - const offChainComputed = ethers.getCreate2Address( - this.deployer.address, - saltHex, - ethers.keccak256(this.constructorByteCode), - ); - expect(onChainComputed).to.equal(offChainComputed); - }); - }); - - describe('deploy', function () { - it('deploys a contract without constructor', async function () { - const offChainComputed = ethers.getCreate2Address( - this.factory.target, - saltHex, - ethers.keccak256(this.constructorLessBytecode), - ); - - await expect(this.factory.$deploy(0n, saltHex, this.constructorLessBytecode)) - .to.emit(this.factory, 'return$deploy') - .withArgs(offChainComputed); - - expect(this.constructorLessBytecode).to.include((await ethers.provider.getCode(offChainComputed)).slice(2)); - }); - - it('deploys a contract with constructor arguments', async function () { - const offChainComputed = ethers.getCreate2Address( - this.factory.target, - saltHex, - ethers.keccak256(this.constructorByteCode), - ); - - await expect(this.factory.$deploy(0n, saltHex, this.constructorByteCode)) - .to.emit(this.factory, 'return$deploy') - .withArgs(offChainComputed); - - const instance = await ethers.getContractAt('VestingWallet', offChainComputed); - - expect(await instance.owner()).to.equal(this.other); - }); - - it('deploys a contract with funds deposited in the factory', async function () { - const value = 10n; - - await this.deployer.sendTransaction({ to: this.factory, value }); - - const offChainComputed = ethers.getCreate2Address( - this.factory.target, - saltHex, - ethers.keccak256(this.constructorByteCode), - ); - - expect(await ethers.provider.getBalance(this.factory)).to.equal(value); - expect(await ethers.provider.getBalance(offChainComputed)).to.equal(0n); - - await expect(this.factory.$deploy(value, saltHex, this.constructorByteCode)) - .to.emit(this.factory, 'return$deploy') - .withArgs(offChainComputed); - - expect(await ethers.provider.getBalance(this.factory)).to.equal(0n); - expect(await ethers.provider.getBalance(offChainComputed)).to.equal(value); - }); - - it('fails deploying a contract in an existent address', async function () { - await expect(this.factory.$deploy(0n, saltHex, this.constructorByteCode)).to.emit(this.factory, 'return$deploy'); - - await expect(this.factory.$deploy(0n, saltHex, this.constructorByteCode)).to.be.revertedWithCustomError( - this.factory, - 'FailedDeployment', - ); - }); - - it('fails deploying a contract if the bytecode length is zero', async function () { - await expect(this.factory.$deploy(0n, saltHex, '0x')).to.be.revertedWithCustomError( - this.factory, - 'Create2EmptyBytecode', - ); - }); - - it('fails deploying a contract if factory contract does not have sufficient balance', async function () { - await expect(this.factory.$deploy(1n, saltHex, this.constructorByteCode)) - .to.be.revertedWithCustomError(this.factory, 'InsufficientBalance') - .withArgs(0n, 1n); - }); - - describe('reverts error thrown during contract creation', function () { - it('bubbles up without message', async function () { - await expect( - this.factory.$deploy( - 0n, - saltHex, - ethers.concat([ - this.mockFactory.bytecode, - this.mockFactory.interface.encodeDeploy([RevertType.RevertWithoutMessage]), - ]), - ), - ).to.be.revertedWithCustomError(this.factory, 'FailedDeployment'); - }); - - it('bubbles up message', async function () { - await expect( - this.factory.$deploy( - 0n, - saltHex, - ethers.concat([ - this.mockFactory.bytecode, - this.mockFactory.interface.encodeDeploy([RevertType.RevertWithMessage]), - ]), - ), - ).to.be.revertedWith('ConstructorMock: reverting'); - }); - - it('bubbles up custom error', async function () { - await expect( - this.factory.$deploy( - 0n, - saltHex, - ethers.concat([ - this.mockFactory.bytecode, - this.mockFactory.interface.encodeDeploy([RevertType.RevertWithCustomError]), - ]), - ), - ).to.be.revertedWithCustomError({ interface: this.mockFactory.interface }, 'CustomError'); - }); - - it('bubbles up panic', async function () { - await expect( - this.factory.$deploy( - 0n, - saltHex, - ethers.concat([this.mockFactory.bytecode, this.mockFactory.interface.encodeDeploy([RevertType.Panic])]), - ), - ).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Multicall.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Multicall.test.js deleted file mode 100644 index 9c84e44..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Multicall.test.js +++ /dev/null @@ -1,72 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -async function fixture() { - const [holder, alice, bruce] = await ethers.getSigners(); - - const amount = 12_000n; - const helper = await ethers.deployContract('MulticallHelper'); - const mock = await ethers.deployContract('$ERC20MulticallMock', ['name', 'symbol']); - await mock.$_mint(holder, amount); - - return { holder, alice, bruce, amount, mock, helper }; -} - -describe('Multicall', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('batches function calls', async function () { - expect(await this.mock.balanceOf(this.alice)).to.equal(0n); - expect(await this.mock.balanceOf(this.bruce)).to.equal(0n); - - await expect( - this.mock.multicall([ - this.mock.interface.encodeFunctionData('transfer', [this.alice.address, this.amount / 2n]), - this.mock.interface.encodeFunctionData('transfer', [this.bruce.address, this.amount / 3n]), - ]), - ) - .to.emit(this.mock, 'Transfer') - .withArgs(this.holder, this.alice, this.amount / 2n) - .to.emit(this.mock, 'Transfer') - .withArgs(this.holder, this.bruce, this.amount / 3n); - - expect(await this.mock.balanceOf(this.alice)).to.equal(this.amount / 2n); - expect(await this.mock.balanceOf(this.bruce)).to.equal(this.amount / 3n); - }); - - it('returns an array with the result of each call', async function () { - await this.mock.transfer(this.helper, this.amount); - expect(await this.mock.balanceOf(this.helper)).to.equal(this.amount); - - await this.helper.checkReturnValues(this.mock, [this.alice, this.bruce], [this.amount / 2n, this.amount / 3n]); - }); - - it('reverts previous calls', async function () { - expect(await this.mock.balanceOf(this.alice)).to.equal(0n); - - await expect( - this.mock.multicall([ - this.mock.interface.encodeFunctionData('transfer', [this.alice.address, this.amount]), - this.mock.interface.encodeFunctionData('transfer', [this.bruce.address, this.amount]), - ]), - ) - .to.be.revertedWithCustomError(this.mock, 'ERC20InsufficientBalance') - .withArgs(this.holder, 0, this.amount); - - expect(await this.mock.balanceOf(this.alice)).to.equal(0n); - }); - - it('bubbles up revert reasons', async function () { - await expect( - this.mock.multicall([ - this.mock.interface.encodeFunctionData('transfer', [this.alice.address, this.amount]), - this.mock.interface.encodeFunctionData('transfer', [this.bruce.address, this.amount]), - ]), - ) - .to.be.revertedWithCustomError(this.mock, 'ERC20InsufficientBalance') - .withArgs(this.holder, 0, this.amount); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.behavior.js deleted file mode 100644 index c62864e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.behavior.js +++ /dev/null @@ -1,189 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); - -function shouldBehaveLikeNonces() { - describe('should behave like Nonces', function () { - const sender = ethers.Wallet.createRandom(); - const other = ethers.Wallet.createRandom(); - - it('gets a nonce', async function () { - expect(this.mock.nonces(sender)).to.eventually.equal(0n); - }); - - describe('_useNonce', function () { - it('increments a nonce', async function () { - expect(this.mock.nonces(sender)).to.eventually.equal(0n); - - const eventName = ['return$_useNonce', 'return$_useNonce_address'].find(name => - this.mock.interface.getEvent(name), - ); - - await expect(this.mock.$_useNonce(sender)).to.emit(this.mock, eventName).withArgs(0n); - - await expect(this.mock.nonces(sender)).to.eventually.equal(1n); - }); - - it("increments only sender's nonce", async function () { - await expect(this.mock.nonces(sender)).to.eventually.equal(0n); - await expect(this.mock.nonces(other)).to.eventually.equal(0n); - - await this.mock.$_useNonce(sender); - - await expect(this.mock.nonces(sender)).to.eventually.equal(1n); - await expect(this.mock.nonces(other)).to.eventually.equal(0n); - }); - }); - - describe('_useCheckedNonce', function () { - it('increments a nonce', async function () { - // current nonce is 0n - await expect(this.mock.nonces(sender)).to.eventually.equal(0n); - - await this.mock.$_useCheckedNonce(sender, 0n); - - await expect(this.mock.nonces(sender)).to.eventually.equal(1n); - }); - - it("increments only sender's nonce", async function () { - // current nonce is 0n - await expect(this.mock.nonces(sender)).to.eventually.equal(0n); - await expect(this.mock.nonces(other)).to.eventually.equal(0n); - - await this.mock.$_useCheckedNonce(sender, 0n); - - await expect(this.mock.nonces(sender)).to.eventually.equal(1n); - await expect(this.mock.nonces(other)).to.eventually.equal(0n); - }); - - it('reverts when nonce is not the expected', async function () { - const currentNonce = await this.mock.nonces(sender); - - await expect(this.mock.$_useCheckedNonce(sender, currentNonce + 1n)) - .to.be.revertedWithCustomError(this.mock, 'InvalidAccountNonce') - .withArgs(sender, currentNonce); - }); - }); - }); -} - -function shouldBehaveLikeNoncesKeyed() { - describe('should support nonces with keys', function () { - const sender = ethers.Wallet.createRandom(); - - const keyOffset = key => key << 64n; - - it('gets a nonce', async function () { - await expect(this.mock.nonces(sender, ethers.Typed.uint192(0n))).to.eventually.equal(keyOffset(0n) + 0n); - await expect(this.mock.nonces(sender, ethers.Typed.uint192(17n))).to.eventually.equal(keyOffset(17n) + 0n); - }); - - describe('_useNonce', function () { - it('default variant uses key 0', async function () { - await expect(this.mock.nonces(sender, ethers.Typed.uint192(0n))).to.eventually.equal(keyOffset(0n) + 0n); - await expect(this.mock.nonces(sender, ethers.Typed.uint192(17n))).to.eventually.equal(keyOffset(17n) + 0n); - - await expect(this.mock.$_useNonce(sender)).to.emit(this.mock, 'return$_useNonce_address').withArgs(0n); - - await expect(this.mock.$_useNonce(sender, ethers.Typed.uint192(0n))) - .to.emit(this.mock, 'return$_useNonce_address_uint192') - .withArgs(keyOffset(0n) + 1n); - - await expect(this.mock.nonces(sender, ethers.Typed.uint192(0n))).to.eventually.equal(keyOffset(0n) + 2n); - await expect(this.mock.nonces(sender, ethers.Typed.uint192(17n))).to.eventually.equal(keyOffset(17n) + 0n); - }); - - it('use nonce at another key', async function () { - await expect(this.mock.nonces(sender, ethers.Typed.uint192(0n))).to.eventually.equal(keyOffset(0n) + 0n); - await expect(this.mock.nonces(sender, ethers.Typed.uint192(17n))).to.eventually.equal(keyOffset(17n) + 0n); - - await expect(this.mock.$_useNonce(sender, ethers.Typed.uint192(17n))) - .to.emit(this.mock, 'return$_useNonce_address_uint192') - .withArgs(keyOffset(17n) + 0n); - - await expect(this.mock.$_useNonce(sender, ethers.Typed.uint192(17n))) - .to.emit(this.mock, 'return$_useNonce_address_uint192') - .withArgs(keyOffset(17n) + 1n); - - await expect(this.mock.nonces(sender, ethers.Typed.uint192(0n))).to.eventually.equal(keyOffset(0n) + 0n); - await expect(this.mock.nonces(sender, ethers.Typed.uint192(17n))).to.eventually.equal(keyOffset(17n) + 2n); - }); - }); - - describe('_useCheckedNonce(address, uint256)', function () { - it('default variant uses key 0', async function () { - const currentNonce = await this.mock.nonces(sender, ethers.Typed.uint192(0n)); - - await this.mock.$_useCheckedNonce(sender, currentNonce); - - await expect(this.mock.nonces(sender, ethers.Typed.uint192(0n))).to.eventually.equal(currentNonce + 1n); - }); - - it('use nonce at another key', async function () { - const currentNonce = await this.mock.nonces(sender, ethers.Typed.uint192(17n)); - - await this.mock.$_useCheckedNonce(sender, currentNonce); - - await expect(this.mock.nonces(sender, ethers.Typed.uint192(17n))).to.eventually.equal(currentNonce + 1n); - }); - - it('reverts when nonce is not the expected', async function () { - const currentNonce = await this.mock.nonces(sender, ethers.Typed.uint192(42n)); - - // use and increment - await this.mock.$_useCheckedNonce(sender, currentNonce); - - // reuse same nonce - await expect(this.mock.$_useCheckedNonce(sender, currentNonce)) - .to.be.revertedWithCustomError(this.mock, 'InvalidAccountNonce') - .withArgs(sender, currentNonce + 1n); - - // use "future" nonce too early - await expect(this.mock.$_useCheckedNonce(sender, currentNonce + 10n)) - .to.be.revertedWithCustomError(this.mock, 'InvalidAccountNonce') - .withArgs(sender, currentNonce + 1n); - }); - }); - - describe('_useCheckedNonce(address, uint192, uint64)', function () { - const MASK = 0xffffffffffffffffn; - - it('default variant uses key 0', async function () { - const currentNonce = await this.mock.nonces(sender, ethers.Typed.uint192(0n)); - - await this.mock.$_useCheckedNonce(sender, ethers.Typed.uint192(0n), currentNonce); - - await expect(this.mock.nonces(sender, ethers.Typed.uint192(0n))).to.eventually.equal(currentNonce + 1n); - }); - - it('use nonce at another key', async function () { - const currentNonce = await this.mock.nonces(sender, ethers.Typed.uint192(17n)); - - await this.mock.$_useCheckedNonce(sender, ethers.Typed.uint192(17n), currentNonce & MASK); - - await expect(this.mock.nonces(sender, ethers.Typed.uint192(17n))).to.eventually.equal(currentNonce + 1n); - }); - - it('reverts when nonce is not the expected', async function () { - const currentNonce = await this.mock.nonces(sender, ethers.Typed.uint192(42n)); - - // use and increment - await this.mock.$_useCheckedNonce(sender, ethers.Typed.uint192(42n), currentNonce & MASK); - - // reuse same nonce - await expect(this.mock.$_useCheckedNonce(sender, ethers.Typed.uint192(42n), currentNonce & MASK)) - .to.be.revertedWithCustomError(this.mock, 'InvalidAccountNonce') - .withArgs(sender, currentNonce + 1n); - - // use "future" nonce too early - await expect(this.mock.$_useCheckedNonce(sender, ethers.Typed.uint192(42n), (currentNonce & MASK) + 10n)) - .to.be.revertedWithCustomError(this.mock, 'InvalidAccountNonce') - .withArgs(sender, currentNonce + 1n); - }); - }); - }); -} - -module.exports = { - shouldBehaveLikeNonces, - shouldBehaveLikeNoncesKeyed, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.test.js deleted file mode 100644 index 85aa735..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Nonces.test.js +++ /dev/null @@ -1,16 +0,0 @@ -const { ethers } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { shouldBehaveLikeNonces } = require('./Nonces.behavior'); - -async function fixture() { - const mock = await ethers.deployContract('$Nonces'); - return { mock }; -} - -describe('Nonces', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeNonces(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/NoncesKeyed.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/NoncesKeyed.test.js deleted file mode 100644 index c46948e..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/NoncesKeyed.test.js +++ /dev/null @@ -1,17 +0,0 @@ -const { ethers } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { shouldBehaveLikeNonces, shouldBehaveLikeNoncesKeyed } = require('./Nonces.behavior'); - -async function fixture() { - const mock = await ethers.deployContract('$NoncesKeyed'); - return { mock }; -} - -describe('NoncesKeyed', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldBehaveLikeNonces(); - shouldBehaveLikeNoncesKeyed(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.t.sol deleted file mode 100644 index 40f052c..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.t.sol +++ /dev/null @@ -1,993 +0,0 @@ -// SPDX-License-Identifier: MIT -// This file was procedurally generated from scripts/generate/templates/Packing.t.js. - -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; -import {Packing} from "@openzeppelin/contracts/utils/Packing.sol"; - -contract PackingTest is Test { - using Packing for *; - - function testPack(bytes1 left, bytes1 right) external pure { - assertEq(left, Packing.pack_1_1(left, right).extract_2_1(0)); - assertEq(right, Packing.pack_1_1(left, right).extract_2_1(1)); - } - - function testPack(bytes2 left, bytes2 right) external pure { - assertEq(left, Packing.pack_2_2(left, right).extract_4_2(0)); - assertEq(right, Packing.pack_2_2(left, right).extract_4_2(2)); - } - - function testPack(bytes2 left, bytes4 right) external pure { - assertEq(left, Packing.pack_2_4(left, right).extract_6_2(0)); - assertEq(right, Packing.pack_2_4(left, right).extract_6_4(2)); - } - - function testPack(bytes2 left, bytes6 right) external pure { - assertEq(left, Packing.pack_2_6(left, right).extract_8_2(0)); - assertEq(right, Packing.pack_2_6(left, right).extract_8_6(2)); - } - - function testPack(bytes2 left, bytes8 right) external pure { - assertEq(left, Packing.pack_2_8(left, right).extract_10_2(0)); - assertEq(right, Packing.pack_2_8(left, right).extract_10_8(2)); - } - - function testPack(bytes2 left, bytes10 right) external pure { - assertEq(left, Packing.pack_2_10(left, right).extract_12_2(0)); - assertEq(right, Packing.pack_2_10(left, right).extract_12_10(2)); - } - - function testPack(bytes2 left, bytes20 right) external pure { - assertEq(left, Packing.pack_2_20(left, right).extract_22_2(0)); - assertEq(right, Packing.pack_2_20(left, right).extract_22_20(2)); - } - - function testPack(bytes2 left, bytes22 right) external pure { - assertEq(left, Packing.pack_2_22(left, right).extract_24_2(0)); - assertEq(right, Packing.pack_2_22(left, right).extract_24_22(2)); - } - - function testPack(bytes4 left, bytes2 right) external pure { - assertEq(left, Packing.pack_4_2(left, right).extract_6_4(0)); - assertEq(right, Packing.pack_4_2(left, right).extract_6_2(4)); - } - - function testPack(bytes4 left, bytes4 right) external pure { - assertEq(left, Packing.pack_4_4(left, right).extract_8_4(0)); - assertEq(right, Packing.pack_4_4(left, right).extract_8_4(4)); - } - - function testPack(bytes4 left, bytes6 right) external pure { - assertEq(left, Packing.pack_4_6(left, right).extract_10_4(0)); - assertEq(right, Packing.pack_4_6(left, right).extract_10_6(4)); - } - - function testPack(bytes4 left, bytes8 right) external pure { - assertEq(left, Packing.pack_4_8(left, right).extract_12_4(0)); - assertEq(right, Packing.pack_4_8(left, right).extract_12_8(4)); - } - - function testPack(bytes4 left, bytes12 right) external pure { - assertEq(left, Packing.pack_4_12(left, right).extract_16_4(0)); - assertEq(right, Packing.pack_4_12(left, right).extract_16_12(4)); - } - - function testPack(bytes4 left, bytes16 right) external pure { - assertEq(left, Packing.pack_4_16(left, right).extract_20_4(0)); - assertEq(right, Packing.pack_4_16(left, right).extract_20_16(4)); - } - - function testPack(bytes4 left, bytes20 right) external pure { - assertEq(left, Packing.pack_4_20(left, right).extract_24_4(0)); - assertEq(right, Packing.pack_4_20(left, right).extract_24_20(4)); - } - - function testPack(bytes4 left, bytes24 right) external pure { - assertEq(left, Packing.pack_4_24(left, right).extract_28_4(0)); - assertEq(right, Packing.pack_4_24(left, right).extract_28_24(4)); - } - - function testPack(bytes4 left, bytes28 right) external pure { - assertEq(left, Packing.pack_4_28(left, right).extract_32_4(0)); - assertEq(right, Packing.pack_4_28(left, right).extract_32_28(4)); - } - - function testPack(bytes6 left, bytes2 right) external pure { - assertEq(left, Packing.pack_6_2(left, right).extract_8_6(0)); - assertEq(right, Packing.pack_6_2(left, right).extract_8_2(6)); - } - - function testPack(bytes6 left, bytes4 right) external pure { - assertEq(left, Packing.pack_6_4(left, right).extract_10_6(0)); - assertEq(right, Packing.pack_6_4(left, right).extract_10_4(6)); - } - - function testPack(bytes6 left, bytes6 right) external pure { - assertEq(left, Packing.pack_6_6(left, right).extract_12_6(0)); - assertEq(right, Packing.pack_6_6(left, right).extract_12_6(6)); - } - - function testPack(bytes6 left, bytes10 right) external pure { - assertEq(left, Packing.pack_6_10(left, right).extract_16_6(0)); - assertEq(right, Packing.pack_6_10(left, right).extract_16_10(6)); - } - - function testPack(bytes6 left, bytes16 right) external pure { - assertEq(left, Packing.pack_6_16(left, right).extract_22_6(0)); - assertEq(right, Packing.pack_6_16(left, right).extract_22_16(6)); - } - - function testPack(bytes6 left, bytes22 right) external pure { - assertEq(left, Packing.pack_6_22(left, right).extract_28_6(0)); - assertEq(right, Packing.pack_6_22(left, right).extract_28_22(6)); - } - - function testPack(bytes8 left, bytes2 right) external pure { - assertEq(left, Packing.pack_8_2(left, right).extract_10_8(0)); - assertEq(right, Packing.pack_8_2(left, right).extract_10_2(8)); - } - - function testPack(bytes8 left, bytes4 right) external pure { - assertEq(left, Packing.pack_8_4(left, right).extract_12_8(0)); - assertEq(right, Packing.pack_8_4(left, right).extract_12_4(8)); - } - - function testPack(bytes8 left, bytes8 right) external pure { - assertEq(left, Packing.pack_8_8(left, right).extract_16_8(0)); - assertEq(right, Packing.pack_8_8(left, right).extract_16_8(8)); - } - - function testPack(bytes8 left, bytes12 right) external pure { - assertEq(left, Packing.pack_8_12(left, right).extract_20_8(0)); - assertEq(right, Packing.pack_8_12(left, right).extract_20_12(8)); - } - - function testPack(bytes8 left, bytes16 right) external pure { - assertEq(left, Packing.pack_8_16(left, right).extract_24_8(0)); - assertEq(right, Packing.pack_8_16(left, right).extract_24_16(8)); - } - - function testPack(bytes8 left, bytes20 right) external pure { - assertEq(left, Packing.pack_8_20(left, right).extract_28_8(0)); - assertEq(right, Packing.pack_8_20(left, right).extract_28_20(8)); - } - - function testPack(bytes8 left, bytes24 right) external pure { - assertEq(left, Packing.pack_8_24(left, right).extract_32_8(0)); - assertEq(right, Packing.pack_8_24(left, right).extract_32_24(8)); - } - - function testPack(bytes10 left, bytes2 right) external pure { - assertEq(left, Packing.pack_10_2(left, right).extract_12_10(0)); - assertEq(right, Packing.pack_10_2(left, right).extract_12_2(10)); - } - - function testPack(bytes10 left, bytes6 right) external pure { - assertEq(left, Packing.pack_10_6(left, right).extract_16_10(0)); - assertEq(right, Packing.pack_10_6(left, right).extract_16_6(10)); - } - - function testPack(bytes10 left, bytes10 right) external pure { - assertEq(left, Packing.pack_10_10(left, right).extract_20_10(0)); - assertEq(right, Packing.pack_10_10(left, right).extract_20_10(10)); - } - - function testPack(bytes10 left, bytes12 right) external pure { - assertEq(left, Packing.pack_10_12(left, right).extract_22_10(0)); - assertEq(right, Packing.pack_10_12(left, right).extract_22_12(10)); - } - - function testPack(bytes10 left, bytes22 right) external pure { - assertEq(left, Packing.pack_10_22(left, right).extract_32_10(0)); - assertEq(right, Packing.pack_10_22(left, right).extract_32_22(10)); - } - - function testPack(bytes12 left, bytes4 right) external pure { - assertEq(left, Packing.pack_12_4(left, right).extract_16_12(0)); - assertEq(right, Packing.pack_12_4(left, right).extract_16_4(12)); - } - - function testPack(bytes12 left, bytes8 right) external pure { - assertEq(left, Packing.pack_12_8(left, right).extract_20_12(0)); - assertEq(right, Packing.pack_12_8(left, right).extract_20_8(12)); - } - - function testPack(bytes12 left, bytes10 right) external pure { - assertEq(left, Packing.pack_12_10(left, right).extract_22_12(0)); - assertEq(right, Packing.pack_12_10(left, right).extract_22_10(12)); - } - - function testPack(bytes12 left, bytes12 right) external pure { - assertEq(left, Packing.pack_12_12(left, right).extract_24_12(0)); - assertEq(right, Packing.pack_12_12(left, right).extract_24_12(12)); - } - - function testPack(bytes12 left, bytes16 right) external pure { - assertEq(left, Packing.pack_12_16(left, right).extract_28_12(0)); - assertEq(right, Packing.pack_12_16(left, right).extract_28_16(12)); - } - - function testPack(bytes12 left, bytes20 right) external pure { - assertEq(left, Packing.pack_12_20(left, right).extract_32_12(0)); - assertEq(right, Packing.pack_12_20(left, right).extract_32_20(12)); - } - - function testPack(bytes16 left, bytes4 right) external pure { - assertEq(left, Packing.pack_16_4(left, right).extract_20_16(0)); - assertEq(right, Packing.pack_16_4(left, right).extract_20_4(16)); - } - - function testPack(bytes16 left, bytes6 right) external pure { - assertEq(left, Packing.pack_16_6(left, right).extract_22_16(0)); - assertEq(right, Packing.pack_16_6(left, right).extract_22_6(16)); - } - - function testPack(bytes16 left, bytes8 right) external pure { - assertEq(left, Packing.pack_16_8(left, right).extract_24_16(0)); - assertEq(right, Packing.pack_16_8(left, right).extract_24_8(16)); - } - - function testPack(bytes16 left, bytes12 right) external pure { - assertEq(left, Packing.pack_16_12(left, right).extract_28_16(0)); - assertEq(right, Packing.pack_16_12(left, right).extract_28_12(16)); - } - - function testPack(bytes16 left, bytes16 right) external pure { - assertEq(left, Packing.pack_16_16(left, right).extract_32_16(0)); - assertEq(right, Packing.pack_16_16(left, right).extract_32_16(16)); - } - - function testPack(bytes20 left, bytes2 right) external pure { - assertEq(left, Packing.pack_20_2(left, right).extract_22_20(0)); - assertEq(right, Packing.pack_20_2(left, right).extract_22_2(20)); - } - - function testPack(bytes20 left, bytes4 right) external pure { - assertEq(left, Packing.pack_20_4(left, right).extract_24_20(0)); - assertEq(right, Packing.pack_20_4(left, right).extract_24_4(20)); - } - - function testPack(bytes20 left, bytes8 right) external pure { - assertEq(left, Packing.pack_20_8(left, right).extract_28_20(0)); - assertEq(right, Packing.pack_20_8(left, right).extract_28_8(20)); - } - - function testPack(bytes20 left, bytes12 right) external pure { - assertEq(left, Packing.pack_20_12(left, right).extract_32_20(0)); - assertEq(right, Packing.pack_20_12(left, right).extract_32_12(20)); - } - - function testPack(bytes22 left, bytes2 right) external pure { - assertEq(left, Packing.pack_22_2(left, right).extract_24_22(0)); - assertEq(right, Packing.pack_22_2(left, right).extract_24_2(22)); - } - - function testPack(bytes22 left, bytes6 right) external pure { - assertEq(left, Packing.pack_22_6(left, right).extract_28_22(0)); - assertEq(right, Packing.pack_22_6(left, right).extract_28_6(22)); - } - - function testPack(bytes22 left, bytes10 right) external pure { - assertEq(left, Packing.pack_22_10(left, right).extract_32_22(0)); - assertEq(right, Packing.pack_22_10(left, right).extract_32_10(22)); - } - - function testPack(bytes24 left, bytes4 right) external pure { - assertEq(left, Packing.pack_24_4(left, right).extract_28_24(0)); - assertEq(right, Packing.pack_24_4(left, right).extract_28_4(24)); - } - - function testPack(bytes24 left, bytes8 right) external pure { - assertEq(left, Packing.pack_24_8(left, right).extract_32_24(0)); - assertEq(right, Packing.pack_24_8(left, right).extract_32_8(24)); - } - - function testPack(bytes28 left, bytes4 right) external pure { - assertEq(left, Packing.pack_28_4(left, right).extract_32_28(0)); - assertEq(right, Packing.pack_28_4(left, right).extract_32_4(28)); - } - - function testReplace(bytes2 container, bytes1 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 1)); - - bytes1 oldValue = container.extract_2_1(offset); - - assertEq(newValue, container.replace_2_1(newValue, offset).extract_2_1(offset)); - assertEq(container, container.replace_2_1(newValue, offset).replace_2_1(oldValue, offset)); - } - - function testReplace(bytes4 container, bytes1 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 3)); - - bytes1 oldValue = container.extract_4_1(offset); - - assertEq(newValue, container.replace_4_1(newValue, offset).extract_4_1(offset)); - assertEq(container, container.replace_4_1(newValue, offset).replace_4_1(oldValue, offset)); - } - - function testReplace(bytes4 container, bytes2 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 2)); - - bytes2 oldValue = container.extract_4_2(offset); - - assertEq(newValue, container.replace_4_2(newValue, offset).extract_4_2(offset)); - assertEq(container, container.replace_4_2(newValue, offset).replace_4_2(oldValue, offset)); - } - - function testReplace(bytes6 container, bytes1 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 5)); - - bytes1 oldValue = container.extract_6_1(offset); - - assertEq(newValue, container.replace_6_1(newValue, offset).extract_6_1(offset)); - assertEq(container, container.replace_6_1(newValue, offset).replace_6_1(oldValue, offset)); - } - - function testReplace(bytes6 container, bytes2 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 4)); - - bytes2 oldValue = container.extract_6_2(offset); - - assertEq(newValue, container.replace_6_2(newValue, offset).extract_6_2(offset)); - assertEq(container, container.replace_6_2(newValue, offset).replace_6_2(oldValue, offset)); - } - - function testReplace(bytes6 container, bytes4 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 2)); - - bytes4 oldValue = container.extract_6_4(offset); - - assertEq(newValue, container.replace_6_4(newValue, offset).extract_6_4(offset)); - assertEq(container, container.replace_6_4(newValue, offset).replace_6_4(oldValue, offset)); - } - - function testReplace(bytes8 container, bytes1 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 7)); - - bytes1 oldValue = container.extract_8_1(offset); - - assertEq(newValue, container.replace_8_1(newValue, offset).extract_8_1(offset)); - assertEq(container, container.replace_8_1(newValue, offset).replace_8_1(oldValue, offset)); - } - - function testReplace(bytes8 container, bytes2 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 6)); - - bytes2 oldValue = container.extract_8_2(offset); - - assertEq(newValue, container.replace_8_2(newValue, offset).extract_8_2(offset)); - assertEq(container, container.replace_8_2(newValue, offset).replace_8_2(oldValue, offset)); - } - - function testReplace(bytes8 container, bytes4 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 4)); - - bytes4 oldValue = container.extract_8_4(offset); - - assertEq(newValue, container.replace_8_4(newValue, offset).extract_8_4(offset)); - assertEq(container, container.replace_8_4(newValue, offset).replace_8_4(oldValue, offset)); - } - - function testReplace(bytes8 container, bytes6 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 2)); - - bytes6 oldValue = container.extract_8_6(offset); - - assertEq(newValue, container.replace_8_6(newValue, offset).extract_8_6(offset)); - assertEq(container, container.replace_8_6(newValue, offset).replace_8_6(oldValue, offset)); - } - - function testReplace(bytes10 container, bytes1 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 9)); - - bytes1 oldValue = container.extract_10_1(offset); - - assertEq(newValue, container.replace_10_1(newValue, offset).extract_10_1(offset)); - assertEq(container, container.replace_10_1(newValue, offset).replace_10_1(oldValue, offset)); - } - - function testReplace(bytes10 container, bytes2 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 8)); - - bytes2 oldValue = container.extract_10_2(offset); - - assertEq(newValue, container.replace_10_2(newValue, offset).extract_10_2(offset)); - assertEq(container, container.replace_10_2(newValue, offset).replace_10_2(oldValue, offset)); - } - - function testReplace(bytes10 container, bytes4 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 6)); - - bytes4 oldValue = container.extract_10_4(offset); - - assertEq(newValue, container.replace_10_4(newValue, offset).extract_10_4(offset)); - assertEq(container, container.replace_10_4(newValue, offset).replace_10_4(oldValue, offset)); - } - - function testReplace(bytes10 container, bytes6 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 4)); - - bytes6 oldValue = container.extract_10_6(offset); - - assertEq(newValue, container.replace_10_6(newValue, offset).extract_10_6(offset)); - assertEq(container, container.replace_10_6(newValue, offset).replace_10_6(oldValue, offset)); - } - - function testReplace(bytes10 container, bytes8 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 2)); - - bytes8 oldValue = container.extract_10_8(offset); - - assertEq(newValue, container.replace_10_8(newValue, offset).extract_10_8(offset)); - assertEq(container, container.replace_10_8(newValue, offset).replace_10_8(oldValue, offset)); - } - - function testReplace(bytes12 container, bytes1 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 11)); - - bytes1 oldValue = container.extract_12_1(offset); - - assertEq(newValue, container.replace_12_1(newValue, offset).extract_12_1(offset)); - assertEq(container, container.replace_12_1(newValue, offset).replace_12_1(oldValue, offset)); - } - - function testReplace(bytes12 container, bytes2 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 10)); - - bytes2 oldValue = container.extract_12_2(offset); - - assertEq(newValue, container.replace_12_2(newValue, offset).extract_12_2(offset)); - assertEq(container, container.replace_12_2(newValue, offset).replace_12_2(oldValue, offset)); - } - - function testReplace(bytes12 container, bytes4 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 8)); - - bytes4 oldValue = container.extract_12_4(offset); - - assertEq(newValue, container.replace_12_4(newValue, offset).extract_12_4(offset)); - assertEq(container, container.replace_12_4(newValue, offset).replace_12_4(oldValue, offset)); - } - - function testReplace(bytes12 container, bytes6 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 6)); - - bytes6 oldValue = container.extract_12_6(offset); - - assertEq(newValue, container.replace_12_6(newValue, offset).extract_12_6(offset)); - assertEq(container, container.replace_12_6(newValue, offset).replace_12_6(oldValue, offset)); - } - - function testReplace(bytes12 container, bytes8 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 4)); - - bytes8 oldValue = container.extract_12_8(offset); - - assertEq(newValue, container.replace_12_8(newValue, offset).extract_12_8(offset)); - assertEq(container, container.replace_12_8(newValue, offset).replace_12_8(oldValue, offset)); - } - - function testReplace(bytes12 container, bytes10 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 2)); - - bytes10 oldValue = container.extract_12_10(offset); - - assertEq(newValue, container.replace_12_10(newValue, offset).extract_12_10(offset)); - assertEq(container, container.replace_12_10(newValue, offset).replace_12_10(oldValue, offset)); - } - - function testReplace(bytes16 container, bytes1 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 15)); - - bytes1 oldValue = container.extract_16_1(offset); - - assertEq(newValue, container.replace_16_1(newValue, offset).extract_16_1(offset)); - assertEq(container, container.replace_16_1(newValue, offset).replace_16_1(oldValue, offset)); - } - - function testReplace(bytes16 container, bytes2 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 14)); - - bytes2 oldValue = container.extract_16_2(offset); - - assertEq(newValue, container.replace_16_2(newValue, offset).extract_16_2(offset)); - assertEq(container, container.replace_16_2(newValue, offset).replace_16_2(oldValue, offset)); - } - - function testReplace(bytes16 container, bytes4 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 12)); - - bytes4 oldValue = container.extract_16_4(offset); - - assertEq(newValue, container.replace_16_4(newValue, offset).extract_16_4(offset)); - assertEq(container, container.replace_16_4(newValue, offset).replace_16_4(oldValue, offset)); - } - - function testReplace(bytes16 container, bytes6 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 10)); - - bytes6 oldValue = container.extract_16_6(offset); - - assertEq(newValue, container.replace_16_6(newValue, offset).extract_16_6(offset)); - assertEq(container, container.replace_16_6(newValue, offset).replace_16_6(oldValue, offset)); - } - - function testReplace(bytes16 container, bytes8 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 8)); - - bytes8 oldValue = container.extract_16_8(offset); - - assertEq(newValue, container.replace_16_8(newValue, offset).extract_16_8(offset)); - assertEq(container, container.replace_16_8(newValue, offset).replace_16_8(oldValue, offset)); - } - - function testReplace(bytes16 container, bytes10 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 6)); - - bytes10 oldValue = container.extract_16_10(offset); - - assertEq(newValue, container.replace_16_10(newValue, offset).extract_16_10(offset)); - assertEq(container, container.replace_16_10(newValue, offset).replace_16_10(oldValue, offset)); - } - - function testReplace(bytes16 container, bytes12 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 4)); - - bytes12 oldValue = container.extract_16_12(offset); - - assertEq(newValue, container.replace_16_12(newValue, offset).extract_16_12(offset)); - assertEq(container, container.replace_16_12(newValue, offset).replace_16_12(oldValue, offset)); - } - - function testReplace(bytes20 container, bytes1 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 19)); - - bytes1 oldValue = container.extract_20_1(offset); - - assertEq(newValue, container.replace_20_1(newValue, offset).extract_20_1(offset)); - assertEq(container, container.replace_20_1(newValue, offset).replace_20_1(oldValue, offset)); - } - - function testReplace(bytes20 container, bytes2 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 18)); - - bytes2 oldValue = container.extract_20_2(offset); - - assertEq(newValue, container.replace_20_2(newValue, offset).extract_20_2(offset)); - assertEq(container, container.replace_20_2(newValue, offset).replace_20_2(oldValue, offset)); - } - - function testReplace(bytes20 container, bytes4 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 16)); - - bytes4 oldValue = container.extract_20_4(offset); - - assertEq(newValue, container.replace_20_4(newValue, offset).extract_20_4(offset)); - assertEq(container, container.replace_20_4(newValue, offset).replace_20_4(oldValue, offset)); - } - - function testReplace(bytes20 container, bytes6 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 14)); - - bytes6 oldValue = container.extract_20_6(offset); - - assertEq(newValue, container.replace_20_6(newValue, offset).extract_20_6(offset)); - assertEq(container, container.replace_20_6(newValue, offset).replace_20_6(oldValue, offset)); - } - - function testReplace(bytes20 container, bytes8 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 12)); - - bytes8 oldValue = container.extract_20_8(offset); - - assertEq(newValue, container.replace_20_8(newValue, offset).extract_20_8(offset)); - assertEq(container, container.replace_20_8(newValue, offset).replace_20_8(oldValue, offset)); - } - - function testReplace(bytes20 container, bytes10 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 10)); - - bytes10 oldValue = container.extract_20_10(offset); - - assertEq(newValue, container.replace_20_10(newValue, offset).extract_20_10(offset)); - assertEq(container, container.replace_20_10(newValue, offset).replace_20_10(oldValue, offset)); - } - - function testReplace(bytes20 container, bytes12 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 8)); - - bytes12 oldValue = container.extract_20_12(offset); - - assertEq(newValue, container.replace_20_12(newValue, offset).extract_20_12(offset)); - assertEq(container, container.replace_20_12(newValue, offset).replace_20_12(oldValue, offset)); - } - - function testReplace(bytes20 container, bytes16 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 4)); - - bytes16 oldValue = container.extract_20_16(offset); - - assertEq(newValue, container.replace_20_16(newValue, offset).extract_20_16(offset)); - assertEq(container, container.replace_20_16(newValue, offset).replace_20_16(oldValue, offset)); - } - - function testReplace(bytes22 container, bytes1 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 21)); - - bytes1 oldValue = container.extract_22_1(offset); - - assertEq(newValue, container.replace_22_1(newValue, offset).extract_22_1(offset)); - assertEq(container, container.replace_22_1(newValue, offset).replace_22_1(oldValue, offset)); - } - - function testReplace(bytes22 container, bytes2 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 20)); - - bytes2 oldValue = container.extract_22_2(offset); - - assertEq(newValue, container.replace_22_2(newValue, offset).extract_22_2(offset)); - assertEq(container, container.replace_22_2(newValue, offset).replace_22_2(oldValue, offset)); - } - - function testReplace(bytes22 container, bytes4 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 18)); - - bytes4 oldValue = container.extract_22_4(offset); - - assertEq(newValue, container.replace_22_4(newValue, offset).extract_22_4(offset)); - assertEq(container, container.replace_22_4(newValue, offset).replace_22_4(oldValue, offset)); - } - - function testReplace(bytes22 container, bytes6 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 16)); - - bytes6 oldValue = container.extract_22_6(offset); - - assertEq(newValue, container.replace_22_6(newValue, offset).extract_22_6(offset)); - assertEq(container, container.replace_22_6(newValue, offset).replace_22_6(oldValue, offset)); - } - - function testReplace(bytes22 container, bytes8 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 14)); - - bytes8 oldValue = container.extract_22_8(offset); - - assertEq(newValue, container.replace_22_8(newValue, offset).extract_22_8(offset)); - assertEq(container, container.replace_22_8(newValue, offset).replace_22_8(oldValue, offset)); - } - - function testReplace(bytes22 container, bytes10 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 12)); - - bytes10 oldValue = container.extract_22_10(offset); - - assertEq(newValue, container.replace_22_10(newValue, offset).extract_22_10(offset)); - assertEq(container, container.replace_22_10(newValue, offset).replace_22_10(oldValue, offset)); - } - - function testReplace(bytes22 container, bytes12 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 10)); - - bytes12 oldValue = container.extract_22_12(offset); - - assertEq(newValue, container.replace_22_12(newValue, offset).extract_22_12(offset)); - assertEq(container, container.replace_22_12(newValue, offset).replace_22_12(oldValue, offset)); - } - - function testReplace(bytes22 container, bytes16 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 6)); - - bytes16 oldValue = container.extract_22_16(offset); - - assertEq(newValue, container.replace_22_16(newValue, offset).extract_22_16(offset)); - assertEq(container, container.replace_22_16(newValue, offset).replace_22_16(oldValue, offset)); - } - - function testReplace(bytes22 container, bytes20 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 2)); - - bytes20 oldValue = container.extract_22_20(offset); - - assertEq(newValue, container.replace_22_20(newValue, offset).extract_22_20(offset)); - assertEq(container, container.replace_22_20(newValue, offset).replace_22_20(oldValue, offset)); - } - - function testReplace(bytes24 container, bytes1 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 23)); - - bytes1 oldValue = container.extract_24_1(offset); - - assertEq(newValue, container.replace_24_1(newValue, offset).extract_24_1(offset)); - assertEq(container, container.replace_24_1(newValue, offset).replace_24_1(oldValue, offset)); - } - - function testReplace(bytes24 container, bytes2 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 22)); - - bytes2 oldValue = container.extract_24_2(offset); - - assertEq(newValue, container.replace_24_2(newValue, offset).extract_24_2(offset)); - assertEq(container, container.replace_24_2(newValue, offset).replace_24_2(oldValue, offset)); - } - - function testReplace(bytes24 container, bytes4 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 20)); - - bytes4 oldValue = container.extract_24_4(offset); - - assertEq(newValue, container.replace_24_4(newValue, offset).extract_24_4(offset)); - assertEq(container, container.replace_24_4(newValue, offset).replace_24_4(oldValue, offset)); - } - - function testReplace(bytes24 container, bytes6 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 18)); - - bytes6 oldValue = container.extract_24_6(offset); - - assertEq(newValue, container.replace_24_6(newValue, offset).extract_24_6(offset)); - assertEq(container, container.replace_24_6(newValue, offset).replace_24_6(oldValue, offset)); - } - - function testReplace(bytes24 container, bytes8 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 16)); - - bytes8 oldValue = container.extract_24_8(offset); - - assertEq(newValue, container.replace_24_8(newValue, offset).extract_24_8(offset)); - assertEq(container, container.replace_24_8(newValue, offset).replace_24_8(oldValue, offset)); - } - - function testReplace(bytes24 container, bytes10 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 14)); - - bytes10 oldValue = container.extract_24_10(offset); - - assertEq(newValue, container.replace_24_10(newValue, offset).extract_24_10(offset)); - assertEq(container, container.replace_24_10(newValue, offset).replace_24_10(oldValue, offset)); - } - - function testReplace(bytes24 container, bytes12 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 12)); - - bytes12 oldValue = container.extract_24_12(offset); - - assertEq(newValue, container.replace_24_12(newValue, offset).extract_24_12(offset)); - assertEq(container, container.replace_24_12(newValue, offset).replace_24_12(oldValue, offset)); - } - - function testReplace(bytes24 container, bytes16 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 8)); - - bytes16 oldValue = container.extract_24_16(offset); - - assertEq(newValue, container.replace_24_16(newValue, offset).extract_24_16(offset)); - assertEq(container, container.replace_24_16(newValue, offset).replace_24_16(oldValue, offset)); - } - - function testReplace(bytes24 container, bytes20 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 4)); - - bytes20 oldValue = container.extract_24_20(offset); - - assertEq(newValue, container.replace_24_20(newValue, offset).extract_24_20(offset)); - assertEq(container, container.replace_24_20(newValue, offset).replace_24_20(oldValue, offset)); - } - - function testReplace(bytes24 container, bytes22 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 2)); - - bytes22 oldValue = container.extract_24_22(offset); - - assertEq(newValue, container.replace_24_22(newValue, offset).extract_24_22(offset)); - assertEq(container, container.replace_24_22(newValue, offset).replace_24_22(oldValue, offset)); - } - - function testReplace(bytes28 container, bytes1 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 27)); - - bytes1 oldValue = container.extract_28_1(offset); - - assertEq(newValue, container.replace_28_1(newValue, offset).extract_28_1(offset)); - assertEq(container, container.replace_28_1(newValue, offset).replace_28_1(oldValue, offset)); - } - - function testReplace(bytes28 container, bytes2 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 26)); - - bytes2 oldValue = container.extract_28_2(offset); - - assertEq(newValue, container.replace_28_2(newValue, offset).extract_28_2(offset)); - assertEq(container, container.replace_28_2(newValue, offset).replace_28_2(oldValue, offset)); - } - - function testReplace(bytes28 container, bytes4 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 24)); - - bytes4 oldValue = container.extract_28_4(offset); - - assertEq(newValue, container.replace_28_4(newValue, offset).extract_28_4(offset)); - assertEq(container, container.replace_28_4(newValue, offset).replace_28_4(oldValue, offset)); - } - - function testReplace(bytes28 container, bytes6 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 22)); - - bytes6 oldValue = container.extract_28_6(offset); - - assertEq(newValue, container.replace_28_6(newValue, offset).extract_28_6(offset)); - assertEq(container, container.replace_28_6(newValue, offset).replace_28_6(oldValue, offset)); - } - - function testReplace(bytes28 container, bytes8 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 20)); - - bytes8 oldValue = container.extract_28_8(offset); - - assertEq(newValue, container.replace_28_8(newValue, offset).extract_28_8(offset)); - assertEq(container, container.replace_28_8(newValue, offset).replace_28_8(oldValue, offset)); - } - - function testReplace(bytes28 container, bytes10 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 18)); - - bytes10 oldValue = container.extract_28_10(offset); - - assertEq(newValue, container.replace_28_10(newValue, offset).extract_28_10(offset)); - assertEq(container, container.replace_28_10(newValue, offset).replace_28_10(oldValue, offset)); - } - - function testReplace(bytes28 container, bytes12 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 16)); - - bytes12 oldValue = container.extract_28_12(offset); - - assertEq(newValue, container.replace_28_12(newValue, offset).extract_28_12(offset)); - assertEq(container, container.replace_28_12(newValue, offset).replace_28_12(oldValue, offset)); - } - - function testReplace(bytes28 container, bytes16 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 12)); - - bytes16 oldValue = container.extract_28_16(offset); - - assertEq(newValue, container.replace_28_16(newValue, offset).extract_28_16(offset)); - assertEq(container, container.replace_28_16(newValue, offset).replace_28_16(oldValue, offset)); - } - - function testReplace(bytes28 container, bytes20 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 8)); - - bytes20 oldValue = container.extract_28_20(offset); - - assertEq(newValue, container.replace_28_20(newValue, offset).extract_28_20(offset)); - assertEq(container, container.replace_28_20(newValue, offset).replace_28_20(oldValue, offset)); - } - - function testReplace(bytes28 container, bytes22 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 6)); - - bytes22 oldValue = container.extract_28_22(offset); - - assertEq(newValue, container.replace_28_22(newValue, offset).extract_28_22(offset)); - assertEq(container, container.replace_28_22(newValue, offset).replace_28_22(oldValue, offset)); - } - - function testReplace(bytes28 container, bytes24 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 4)); - - bytes24 oldValue = container.extract_28_24(offset); - - assertEq(newValue, container.replace_28_24(newValue, offset).extract_28_24(offset)); - assertEq(container, container.replace_28_24(newValue, offset).replace_28_24(oldValue, offset)); - } - - function testReplace(bytes32 container, bytes1 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 31)); - - bytes1 oldValue = container.extract_32_1(offset); - - assertEq(newValue, container.replace_32_1(newValue, offset).extract_32_1(offset)); - assertEq(container, container.replace_32_1(newValue, offset).replace_32_1(oldValue, offset)); - } - - function testReplace(bytes32 container, bytes2 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 30)); - - bytes2 oldValue = container.extract_32_2(offset); - - assertEq(newValue, container.replace_32_2(newValue, offset).extract_32_2(offset)); - assertEq(container, container.replace_32_2(newValue, offset).replace_32_2(oldValue, offset)); - } - - function testReplace(bytes32 container, bytes4 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 28)); - - bytes4 oldValue = container.extract_32_4(offset); - - assertEq(newValue, container.replace_32_4(newValue, offset).extract_32_4(offset)); - assertEq(container, container.replace_32_4(newValue, offset).replace_32_4(oldValue, offset)); - } - - function testReplace(bytes32 container, bytes6 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 26)); - - bytes6 oldValue = container.extract_32_6(offset); - - assertEq(newValue, container.replace_32_6(newValue, offset).extract_32_6(offset)); - assertEq(container, container.replace_32_6(newValue, offset).replace_32_6(oldValue, offset)); - } - - function testReplace(bytes32 container, bytes8 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 24)); - - bytes8 oldValue = container.extract_32_8(offset); - - assertEq(newValue, container.replace_32_8(newValue, offset).extract_32_8(offset)); - assertEq(container, container.replace_32_8(newValue, offset).replace_32_8(oldValue, offset)); - } - - function testReplace(bytes32 container, bytes10 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 22)); - - bytes10 oldValue = container.extract_32_10(offset); - - assertEq(newValue, container.replace_32_10(newValue, offset).extract_32_10(offset)); - assertEq(container, container.replace_32_10(newValue, offset).replace_32_10(oldValue, offset)); - } - - function testReplace(bytes32 container, bytes12 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 20)); - - bytes12 oldValue = container.extract_32_12(offset); - - assertEq(newValue, container.replace_32_12(newValue, offset).extract_32_12(offset)); - assertEq(container, container.replace_32_12(newValue, offset).replace_32_12(oldValue, offset)); - } - - function testReplace(bytes32 container, bytes16 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 16)); - - bytes16 oldValue = container.extract_32_16(offset); - - assertEq(newValue, container.replace_32_16(newValue, offset).extract_32_16(offset)); - assertEq(container, container.replace_32_16(newValue, offset).replace_32_16(oldValue, offset)); - } - - function testReplace(bytes32 container, bytes20 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 12)); - - bytes20 oldValue = container.extract_32_20(offset); - - assertEq(newValue, container.replace_32_20(newValue, offset).extract_32_20(offset)); - assertEq(container, container.replace_32_20(newValue, offset).replace_32_20(oldValue, offset)); - } - - function testReplace(bytes32 container, bytes22 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 10)); - - bytes22 oldValue = container.extract_32_22(offset); - - assertEq(newValue, container.replace_32_22(newValue, offset).extract_32_22(offset)); - assertEq(container, container.replace_32_22(newValue, offset).replace_32_22(oldValue, offset)); - } - - function testReplace(bytes32 container, bytes24 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 8)); - - bytes24 oldValue = container.extract_32_24(offset); - - assertEq(newValue, container.replace_32_24(newValue, offset).extract_32_24(offset)); - assertEq(container, container.replace_32_24(newValue, offset).replace_32_24(oldValue, offset)); - } - - function testReplace(bytes32 container, bytes28 newValue, uint8 offset) external pure { - offset = uint8(bound(offset, 0, 4)); - - bytes28 oldValue = container.extract_32_28(offset); - - assertEq(newValue, container.replace_32_28(newValue, offset).extract_32_28(offset)); - assertEq(container, container.replace_32_28(newValue, offset).replace_32_28(oldValue, offset)); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.test.js deleted file mode 100644 index dd36f45..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Packing.test.js +++ /dev/null @@ -1,70 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { forceDeployCode } = require('../helpers/deploy'); -const { product } = require('../helpers/iterate'); -const { SIZES } = require('../../scripts/generate/templates/Packing.opts'); - -async function fixture() { - return { mock: await forceDeployCode('$Packing') }; -} - -describe('Packing', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('pack', function () { - for (const [size1, size2] of product(SIZES, SIZES).filter(([size1, size2]) => SIZES.includes(size1 + size2))) { - const value1 = ethers.hexlify(ethers.randomBytes(size1)); - const value2 = ethers.hexlify(ethers.randomBytes(size2)); - const packed = ethers.concat([value1, value2]); - - it(`pack bytes${size1} + bytes${size2} => bytes${size1 + size2}`, async function () { - expect(await this.mock[`$pack_${size1}_${size2}`](value1, value2)).to.equal(packed); - expect(await this.mock[`$extract_${size1 + size2}_${size1}`](packed, 0)).to.equal(value1); - expect(await this.mock[`$extract_${size1 + size2}_${size2}`](packed, size1)).to.equal(value2); - }); - } - }); - - describe('extract / replace', function () { - for (const [size1, size2] of product(SIZES, SIZES).filter(([size1, size2]) => size1 > size2)) { - const MAX_OFFSET = size1 - size2; - const offset = ethers.toNumber(ethers.randomBytes(1)) % (MAX_OFFSET + 1); - const outer = ethers.randomBytes(size1); - const value = ethers.randomBytes(size2); - - it(`extract bytes${size2} from bytes${size1}`, async function () { - expect(await this.mock[`$extract_${size1}_${size2}`](outer, offset)).to.equal( - ethers.hexlify(outer.slice(offset, offset + size2)), - ); - - await expect(this.mock[`$extract_${size1}_${size2}`](outer, MAX_OFFSET)).to.not.be.revertedWithCustomError( - this.mock, - 'OutOfRangeAccess', - ); - - await expect(this.mock[`$extract_${size1}_${size2}`](outer, MAX_OFFSET + 1)).to.be.revertedWithCustomError( - this.mock, - 'OutOfRangeAccess', - ); - }); - - it(`replace bytes${size2} from bytes${size1}`, async function () { - expect(await this.mock[`$replace_${size1}_${size2}`](outer, value, offset)).to.equal( - ethers.concat([outer.slice(0, offset), value, outer.slice(offset + size2)]), - ); - - await expect( - this.mock[`$replace_${size1}_${size2}`](outer, value, MAX_OFFSET), - ).to.not.be.revertedWithCustomError(this.mock, 'OutOfRangeAccess'); - - await expect( - this.mock[`$replace_${size1}_${size2}`](outer, value, MAX_OFFSET + 1), - ).to.be.revertedWithCustomError(this.mock, 'OutOfRangeAccess'); - }); - } - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Panic.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Panic.test.js deleted file mode 100644 index 49673c7..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Panic.test.js +++ /dev/null @@ -1,37 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -async function fixture() { - return { mock: await ethers.deployContract('$Panic') }; -} - -describe('Panic', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - for (const [name, code] of Object.entries({ - GENERIC: 0x0, - ASSERT: PANIC_CODES.ASSERTION_ERROR, - UNDER_OVERFLOW: PANIC_CODES.ARITHMETIC_OVERFLOW, - DIVISION_BY_ZERO: PANIC_CODES.DIVISION_BY_ZERO, - ENUM_CONVERSION_ERROR: PANIC_CODES.ENUM_CONVERSION_OUT_OF_BOUNDS, - STORAGE_ENCODING_ERROR: PANIC_CODES.INCORRECTLY_ENCODED_STORAGE_BYTE_ARRAY, - EMPTY_ARRAY_POP: PANIC_CODES.POP_ON_EMPTY_ARRAY, - ARRAY_OUT_OF_BOUNDS: PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS, - RESOURCE_ERROR: PANIC_CODES.TOO_MUCH_MEMORY_ALLOCATED, - INVALID_INTERNAL_FUNCTION: PANIC_CODES.ZERO_INITIALIZED_VARIABLE, - })) { - describe(`${name} (${ethers.toBeHex(code)})`, function () { - it('exposes panic code as constant', async function () { - expect(await this.mock.getFunction(`$${name}`)()).to.equal(code); - }); - - it('reverts with panic when called', async function () { - await expect(this.mock.$panic(code)).to.be.revertedWithPanic(code); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Pausable.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Pausable.test.js deleted file mode 100644 index 67d74a0..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Pausable.test.js +++ /dev/null @@ -1,90 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -async function fixture() { - const [pauser] = await ethers.getSigners(); - - const mock = await ethers.deployContract('PausableMock'); - - return { pauser, mock }; -} - -describe('Pausable', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('when unpaused', function () { - beforeEach(async function () { - expect(await this.mock.paused()).to.be.false; - }); - - it('can perform normal process in non-pause', async function () { - expect(await this.mock.count()).to.equal(0n); - - await this.mock.normalProcess(); - expect(await this.mock.count()).to.equal(1n); - }); - - it('cannot take drastic measure in non-pause', async function () { - await expect(this.mock.drasticMeasure()).to.be.revertedWithCustomError(this.mock, 'ExpectedPause'); - - expect(await this.mock.drasticMeasureTaken()).to.be.false; - }); - - describe('when paused', function () { - beforeEach(async function () { - this.tx = await this.mock.pause(); - }); - - it('emits a Paused event', async function () { - await expect(this.tx).to.emit(this.mock, 'Paused').withArgs(this.pauser); - }); - - it('cannot perform normal process in pause', async function () { - await expect(this.mock.normalProcess()).to.be.revertedWithCustomError(this.mock, 'EnforcedPause'); - }); - - it('can take a drastic measure in a pause', async function () { - await this.mock.drasticMeasure(); - expect(await this.mock.drasticMeasureTaken()).to.be.true; - }); - - it('reverts when re-pausing', async function () { - await expect(this.mock.pause()).to.be.revertedWithCustomError(this.mock, 'EnforcedPause'); - }); - - describe('unpausing', function () { - it('is unpausable by the pauser', async function () { - await this.mock.unpause(); - expect(await this.mock.paused()).to.be.false; - }); - - describe('when unpaused', function () { - beforeEach(async function () { - this.tx = await this.mock.unpause(); - }); - - it('emits an Unpaused event', async function () { - await expect(this.tx).to.emit(this.mock, 'Unpaused').withArgs(this.pauser); - }); - - it('should resume allowing normal process', async function () { - expect(await this.mock.count()).to.equal(0n); - await this.mock.normalProcess(); - expect(await this.mock.count()).to.equal(1n); - }); - - it('should prevent drastic measure', async function () { - await expect(this.mock.drasticMeasure()).to.be.revertedWithCustomError(this.mock, 'ExpectedPause'); - }); - - it('reverts when re-unpausing', async function () { - await expect(this.mock.unpause()).to.be.revertedWithCustomError(this.mock, 'ExpectedPause'); - }); - }); - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ReentrancyGuard.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ReentrancyGuard.test.js deleted file mode 100644 index c441856..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ReentrancyGuard.test.js +++ /dev/null @@ -1,50 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -for (const variant of ['', 'Transient']) { - describe(`Reentrancy${variant}Guard`, function () { - async function fixture() { - const name = `Reentrancy${variant}Mock`; - const mock = await ethers.deployContract(name); - return { name, mock }; - } - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('nonReentrant function can be called', async function () { - expect(await this.mock.counter()).to.equal(0n); - await this.mock.callback(); - expect(await this.mock.counter()).to.equal(1n); - }); - - it('does not allow remote callback', async function () { - const attacker = await ethers.deployContract('ReentrancyAttack'); - await expect(this.mock.countAndCall(attacker)).to.be.revertedWith('ReentrancyAttack: failed call'); - }); - - it('_reentrancyGuardEntered should be true when guarded', async function () { - await this.mock.guardedCheckEntered(); - }); - - it('_reentrancyGuardEntered should be false when unguarded', async function () { - await this.mock.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 expect(this.mock.countLocalRecursive(10n)).to.be.revertedWithCustomError( - this.mock, - 'ReentrancyGuardReentrantCall', - ); - }); - - it('does not allow indirect local recursion', async function () { - await expect(this.mock.countThisRecursive(10n)).to.be.revertedWith(`${this.name}: failed call`); - }); - }); -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.t.sol deleted file mode 100644 index 80313bf..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.t.sol +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; -import {SymTest} from "halmos-cheatcodes/SymTest.sol"; - -import {ShortStrings, ShortString} from "@openzeppelin/contracts/utils/ShortStrings.sol"; - -contract ShortStringsTest is Test, SymTest { - string _fallback; - - function testRoundtripShort(string memory input) external pure { - vm.assume(_isShort(input)); - _assertRoundtripShort(input); - } - - function symbolicRoundtripShort() external pure { - string memory input = svm.createString(31, "RoundtripShortInput"); - _assertRoundtripShort(input); - } - - function testRoundtripWithFallback(string memory input, string memory fallbackInitial) external { - _assertRoundtripWithFallback(input, fallbackInitial); - } - - function symbolicRoundtripWithFallbackLong() external { - string memory input = svm.createString(256, "RoundtripWithFallbackInput"); - string memory fallbackInitial = svm.createString(256, "RoundtripWithFallbackFallbackInitial"); - _assertRoundtripWithFallback(input, fallbackInitial); - } - - function symbolicRoundtripWithFallbackShort() external { - string memory input = svm.createString(31, "RoundtripWithFallbackInput"); - string memory fallbackInitial = svm.createString(31, "RoundtripWithFallbackFallbackInitial"); - _assertRoundtripWithFallback(input, fallbackInitial); - } - - function testRevertLong(string memory input) external { - vm.assume(!_isShort(input)); - _assertRevertLong(input); - } - - function testLengthShort(string memory input) external pure { - vm.assume(_isShort(input)); - _assertLengthShort(input); - } - - function symbolicLengthShort() external pure { - string memory input = svm.createString(31, "LengthShortInput"); - _assertLengthShort(input); - } - - function testLengthWithFallback(string memory input, string memory fallbackInitial) external { - _fallback = fallbackInitial; - _assertLengthWithFallback(input); - } - - function symbolicLengthWithFallback() external { - uint256 length = 256; - string memory input = svm.createString(length, "LengthWithFallbackInput"); - string memory fallbackInitial = svm.createString(length, "LengthWithFallbackFallbackInitial"); - _fallback = fallbackInitial; - _assertLengthWithFallback(input); - } - - /// Assertions - - function _assertRoundtripShort(string memory input) internal pure { - ShortString short = ShortStrings.toShortString(input); - string memory output = ShortStrings.toString(short); - assertEq(input, output); - } - - function _assertRoundtripWithFallback(string memory input, string memory fallbackInitial) internal { - _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 _assertRevertLong(string memory input) internal { - vm.expectRevert(abi.encodeWithSelector(ShortStrings.StringTooLong.selector, input)); - this.toShortString(input); - } - - function _assertLengthShort(string memory input) internal pure { - ShortString short = ShortStrings.toShortString(input); - uint256 shortLength = ShortStrings.byteLength(short); - uint256 inputLength = bytes(input).length; - assertEq(inputLength, shortLength); - } - - function _assertLengthWithFallback(string memory input) internal { - uint256 inputLength = bytes(input).length; - ShortString short = ShortStrings.toShortStringWithFallback(input, _fallback); - uint256 shortLength = ShortStrings.byteLengthWithFallback(short, _fallback); - assertEq(inputLength, shortLength); - } - - /// Helpers - 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/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.test.js deleted file mode 100644 index cb1a06a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/ShortStrings.test.js +++ /dev/null @@ -1,64 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const FALLBACK_SENTINEL = ethers.zeroPadValue('0xFF', 32); - -const length = sstr => parseInt(sstr.slice(64), 16); -const decode = sstr => ethers.toUtf8String(sstr).slice(0, length(sstr)); -const encode = str => - str.length < 32 - ? ethers.concat([ - ethers.encodeBytes32String(str).slice(0, -2), - ethers.zeroPadValue(ethers.toBeArray(str.length), 1), - ]) - : FALLBACK_SENTINEL; - -async function fixture() { - const mock = await ethers.deployContract('$ShortStrings'); - return { mock }; -} - -describe('ShortStrings', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - 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(encoded).to.equal(encode(str)); - expect(decode(encoded)).to.equal(str); - - expect(await this.mock.$byteLength(encoded)).to.equal(str.length); - expect(await this.mock.$toString(encoded)).to.equal(str); - } else { - await expect(this.mock.$toShortString(str)) - .to.be.revertedWithCustomError(this.mock, 'StringTooLong') - .withArgs(str); - } - }); - - it('set / get with fallback', async function () { - const short = await this.mock - .$toShortStringWithFallback(str, 0) - .then(tx => tx.wait()) - .then(receipt => receipt.logs.find(ev => ev.fragment.name == 'return$toShortStringWithFallback').args[0]); - - expect(short).to.equal(encode(str)); - - const promise = this.mock.$toString(short); - if (str.length < 32) { - expect(await promise).to.equal(str); - } else { - await expect(promise).to.be.revertedWithCustomError(this.mock, 'InvalidShortString'); - } - - expect(await this.mock.$byteLengthWithFallback(short, 0)).to.equal(str.length); - expect(await this.mock.$toStringWithFallback(short, 0)).to.equal(str); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.t.sol deleted file mode 100644 index a0846e3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.t.sol +++ /dev/null @@ -1,248 +0,0 @@ -// SPDX-License-Identifier: MIT -// This file was procedurally generated from scripts/generate/templates/SlotDerivation.t.js. - -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; -import {SymTest} from "halmos-cheatcodes/SymTest.sol"; -import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; - -contract SlotDerivationTest is Test, SymTest { - using SlotDerivation for bytes32; - - bytes[] private _array; - - function symbolicDeriveArray(uint256 length, uint256 offset) public { - vm.assume(length > 0); - vm.assume(offset < length); - _assertDeriveArray(length, offset); - } - - function testDeriveArray(uint256 length, uint256 offset) public { - length = bound(length, 1, type(uint256).max); - offset = bound(offset, 0, length - 1); - _assertDeriveArray(length, offset); - } - - function _assertDeriveArray(uint256 length, uint256 offset) public { - bytes32 baseSlot; - assembly { - baseSlot := _array.slot - sstore(baseSlot, length) // store length so solidity access does not revert - } - - bytes storage derived = _array[offset]; - bytes32 derivedSlot; - assembly { - derivedSlot := derived.slot - } - - assertEq(baseSlot.deriveArray().offset(offset), derivedSlot); - } - - mapping(address => bytes) private _addressMapping; - - function testSymbolicDeriveMappingAddress(address key) public view { - bytes32 baseSlot; - assembly { - baseSlot := _addressMapping.slot - } - - bytes storage derived = _addressMapping[key]; - bytes32 derivedSlot; - assembly { - derivedSlot := derived.slot - } - - assertEq(baseSlot.deriveMapping(key), derivedSlot); - } - - mapping(bool => bytes) private _boolMapping; - - function testSymbolicDeriveMappingBoolean(bool key) public view { - bytes32 baseSlot; - assembly { - baseSlot := _boolMapping.slot - } - - bytes storage derived = _boolMapping[key]; - bytes32 derivedSlot; - assembly { - derivedSlot := derived.slot - } - - assertEq(baseSlot.deriveMapping(key), derivedSlot); - } - - mapping(bytes32 => bytes) private _bytes32Mapping; - - function testSymbolicDeriveMappingBytes32(bytes32 key) public view { - bytes32 baseSlot; - assembly { - baseSlot := _bytes32Mapping.slot - } - - bytes storage derived = _bytes32Mapping[key]; - bytes32 derivedSlot; - assembly { - derivedSlot := derived.slot - } - - assertEq(baseSlot.deriveMapping(key), derivedSlot); - } - - mapping(bytes4 => bytes) private _bytes4Mapping; - - function testSymbolicDeriveMappingBytes4(bytes4 key) public view { - bytes32 baseSlot; - assembly { - baseSlot := _bytes4Mapping.slot - } - - bytes storage derived = _bytes4Mapping[key]; - bytes32 derivedSlot; - assembly { - derivedSlot := derived.slot - } - - assertEq(baseSlot.deriveMapping(key), derivedSlot); - } - - mapping(uint256 => bytes) private _uint256Mapping; - - function testSymbolicDeriveMappingUint256(uint256 key) public view { - bytes32 baseSlot; - assembly { - baseSlot := _uint256Mapping.slot - } - - bytes storage derived = _uint256Mapping[key]; - bytes32 derivedSlot; - assembly { - derivedSlot := derived.slot - } - - assertEq(baseSlot.deriveMapping(key), derivedSlot); - } - - mapping(uint32 => bytes) private _uint32Mapping; - - function testSymbolicDeriveMappingUint32(uint32 key) public view { - bytes32 baseSlot; - assembly { - baseSlot := _uint32Mapping.slot - } - - bytes storage derived = _uint32Mapping[key]; - bytes32 derivedSlot; - assembly { - derivedSlot := derived.slot - } - - assertEq(baseSlot.deriveMapping(key), derivedSlot); - } - - mapping(int256 => bytes) private _int256Mapping; - - function testSymbolicDeriveMappingInt256(int256 key) public view { - bytes32 baseSlot; - assembly { - baseSlot := _int256Mapping.slot - } - - bytes storage derived = _int256Mapping[key]; - bytes32 derivedSlot; - assembly { - derivedSlot := derived.slot - } - - assertEq(baseSlot.deriveMapping(key), derivedSlot); - } - - mapping(int32 => bytes) private _int32Mapping; - - function testSymbolicDeriveMappingInt32(int32 key) public view { - bytes32 baseSlot; - assembly { - baseSlot := _int32Mapping.slot - } - - bytes storage derived = _int32Mapping[key]; - bytes32 derivedSlot; - assembly { - derivedSlot := derived.slot - } - - assertEq(baseSlot.deriveMapping(key), derivedSlot); - } - - mapping(string => bytes) private _stringMapping; - - function testDeriveMappingString(string memory key) public view { - _assertDeriveMappingString(key); - } - - function symbolicDeriveMappingString() public view { - _assertDeriveMappingString(svm.createString(256, "DeriveMappingStringInput")); - } - - function _assertDeriveMappingString(string memory key) internal view { - bytes32 baseSlot; - assembly { - baseSlot := _stringMapping.slot - } - - bytes storage derived = _stringMapping[key]; - bytes32 derivedSlot; - assembly { - derivedSlot := derived.slot - } - - assertEq(baseSlot.deriveMapping(key), derivedSlot); - } - - mapping(bytes => bytes) private _bytesMapping; - - function testDeriveMappingBytes(bytes memory key) public view { - _assertDeriveMappingBytes(key); - } - - function symbolicDeriveMappingBytes() public view { - _assertDeriveMappingBytes(svm.createBytes(256, "DeriveMappingBytesInput")); - } - - function _assertDeriveMappingBytes(bytes memory key) internal view { - bytes32 baseSlot; - assembly { - baseSlot := _bytesMapping.slot - } - - bytes storage derived = _bytesMapping[key]; - bytes32 derivedSlot; - assembly { - derivedSlot := derived.slot - } - - assertEq(baseSlot.deriveMapping(key), derivedSlot); - } - - function testSymbolicDeriveMappingBooleanDirty(bytes32 dirtyKey) public { - bool key; - assembly { - key := dirtyKey - } - - // run the "normal" test using a potentially dirty value - testSymbolicDeriveMappingBoolean(key); - } - - function testSymbolicDeriveMappingAddressDirty(bytes32 dirtyKey) public { - address key; - assembly { - key := dirtyKey - } - - // run the "normal" test using a potentially dirty value - testSymbolicDeriveMappingAddress(key); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.test.js deleted file mode 100644 index 22582b3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/SlotDerivation.test.js +++ /dev/null @@ -1,58 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { erc7201Slot } = require('../helpers/storage'); -const { generators } = require('../helpers/random'); - -async function fixture() { - const [account] = await ethers.getSigners(); - const mock = await ethers.deployContract('$SlotDerivation'); - return { mock, account }; -} - -describe('SlotDerivation', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('namespaces', function () { - const namespace = 'example.main'; - - it('erc-7201', async function () { - expect(await this.mock.$erc7201Slot(namespace)).to.equal(erc7201Slot(namespace)); - }); - }); - - describe('derivation', function () { - it('offset', async function () { - const base = generators.bytes32(); - const offset = generators.uint256(); - expect(await this.mock.$offset(base, offset)).to.equal((ethers.toBigInt(base) + offset) & ethers.MaxUint256); - }); - - it('array', async function () { - const base = generators.bytes32(); - expect(await this.mock.$deriveArray(base)).to.equal(ethers.keccak256(base)); - }); - - describe('mapping', function () { - for (const { type, key, isValueType } of [ - { type: 'bool', key: true, isValueType: true }, - { type: 'address', key: generators.address(), isValueType: true }, - { type: 'bytes32', key: generators.bytes32(), isValueType: true }, - { type: 'uint256', key: generators.uint256(), isValueType: true }, - { type: 'int256', key: generators.int256(), isValueType: true }, - { type: 'bytes', key: generators.hexBytes(128), isValueType: false }, - { type: 'string', key: 'lorem ipsum', isValueType: false }, - ]) { - it(type, async function () { - const base = generators.bytes32(); - const expected = isValueType - ? ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode([type, 'bytes32'], [key, base])) - : ethers.solidityPackedKeccak256([type, 'bytes32'], [key, base]); - expect(await this.mock[`$deriveMapping(bytes32,${type})`](base, key)).to.equal(expected); - }); - } - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js deleted file mode 100644 index ddcf305..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js +++ /dev/null @@ -1,73 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { generators } = require('../helpers/random'); - -const slot = ethers.id('some.storage.slot'); -const otherSlot = ethers.id('some.other.storage.slot'); - -const TYPES = [ - { name: 'Boolean', type: 'bool', value: true, isValueType: true, zero: false }, - { name: 'Address', type: 'address', value: generators.address(), isValueType: true, zero: generators.address.zero }, - { name: 'Bytes32', type: 'bytes32', value: generators.bytes32(), isValueType: true, zero: generators.bytes32.zero }, - { name: 'Uint256', type: 'uint256', value: generators.uint256(), isValueType: true, zero: generators.uint256.zero }, - { name: 'Int256', type: 'int256', value: generators.int256(), isValueType: true, zero: generators.int256.zero }, - { name: 'Bytes', type: 'bytes', value: generators.hexBytes(128), isValueType: false, zero: generators.hexBytes.zero }, - { name: 'String', type: 'string', value: 'lorem ipsum', isValueType: false, zero: '' }, -]; - -async function fixture() { - return { mock: await ethers.deployContract('StorageSlotMock') }; -} - -describe('StorageSlot', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - for (const { name, type, value, zero } of TYPES) { - describe(`${type} storage slot`, function () { - it('set', async function () { - await this.mock.getFunction(`set${name}Slot`)(slot, value); - }); - - describe('get', function () { - beforeEach(async function () { - await this.mock.getFunction(`set${name}Slot`)(slot, value); - }); - - it('from right slot', async function () { - expect(await this.mock.getFunction(`get${name}Slot`)(slot)).to.equal(value); - }); - - it('from other slot', async function () { - expect(await this.mock.getFunction(`get${name}Slot`)(otherSlot)).to.equal(zero); - }); - }); - }); - } - - for (const { name, type, value, zero } of TYPES.filter(type => !type.isValueType)) { - describe(`${type} storage pointer`, function () { - it('set', async function () { - await this.mock.getFunction(`set${name}Storage`)(slot, value); - }); - - describe('get', function () { - beforeEach(async function () { - await this.mock.getFunction(`set${name}Storage`)(slot, value); - }); - - it('from right slot', async function () { - expect(await this.mock.getFunction(`${type}Map`)(slot)).to.equal(value); - expect(await this.mock.getFunction(`get${name}Storage`)(slot)).to.equal(value); - }); - - it('from other slot', async function () { - expect(await this.mock.getFunction(`${type}Map`)(otherSlot)).to.equal(zero); - expect(await this.mock.getFunction(`get${name}Storage`)(otherSlot)).to.equal(zero); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.t.sol deleted file mode 100644 index fe3c90b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.t.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; - -import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; - -contract StringsTest is Test { - using Strings for *; - - function testParse(uint256 value) external pure { - assertEq(value, value.toString().parseUint()); - } - - function testParseSigned(int256 value) external pure { - assertEq(value, value.toStringSigned().parseInt()); - } - - function testParseHex(uint256 value) external pure { - assertEq(value, value.toHexString().parseHexUint()); - } - - function testParseChecksumHex(address value) external pure { - assertEq(value, value.toChecksumHexString().parseAddress()); - } - - function testTryParseHexUintExtendedEnd(string memory random) external pure { - uint256 length = bytes(random).length; - assembly ("memory-safe") { - mstore(add(add(random, 0x20), length), 0x3030303030303030303030303030303030303030303030303030303030303030) - } - - (bool success, ) = random.tryParseHexUint(1, length + 1); - assertFalse(success); - } - - function testTryParseAddressExtendedEnd(address random, uint256 begin) external pure { - begin = bound(begin, 3, 43); - string memory input = random.toHexString(); - uint256 length = bytes(input).length; - - assembly ("memory-safe") { - mstore(add(add(input, 0x20), length), 0x3030303030303030303030303030303030303030303030303030303030303030) - } - - (bool success, ) = input.tryParseAddress(begin, begin + 40); - assertFalse(success); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.test.js deleted file mode 100644 index 8d5e240..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/Strings.test.js +++ /dev/null @@ -1,349 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -async function fixture() { - const mock = await ethers.deployContract('$Strings'); - return { mock }; -} - -describe('Strings', function () { - before(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('toString', function () { - const values = [ - 0n, - 7n, - 10n, - 99n, - 100n, - 101n, - 123n, - 4132n, - 12345n, - 1234567n, - 1234567890n, - 123456789012345n, - 12345678901234567890n, - 123456789012345678901234567890n, - 1234567890123456789012345678901234567890n, - 12345678901234567890123456789012345678901234567890n, - 123456789012345678901234567890123456789012345678901234567890n, - 1234567890123456789012345678901234567890123456789012345678901234567890n, - ]; - - describe('uint256', function () { - it('converts MAX_UINT256', async function () { - const value = ethers.MaxUint256; - expect(await this.mock.$toString(value)).to.equal(value.toString(10)); - expect(await this.mock.$parseUint(value.toString(10))).to.equal(value); - expect(await this.mock.$tryParseUint(value.toString(10))).to.deep.equal([true, value]); - }); - - for (const value of values) { - it(`converts ${value}`, async function () { - expect(await this.mock.$toString(value)).to.equal(value.toString(10)); - expect(await this.mock.$parseUint(value.toString(10))).to.equal(value); - expect(await this.mock.$tryParseUint(value.toString(10))).to.deep.equal([true, value]); - }); - } - }); - - describe('int256', function () { - it('converts MAX_INT256', async function () { - const value = ethers.MaxInt256; - expect(await this.mock.$toStringSigned(value)).to.equal(value.toString(10)); - expect(await this.mock.$parseInt(value.toString(10))).to.equal(value); - expect(await this.mock.$tryParseInt(value.toString(10))).to.deep.equal([true, value]); - }); - - it('converts MIN_INT256', async function () { - const value = ethers.MinInt256; - expect(await this.mock.$toStringSigned(value)).to.equal(value.toString(10)); - expect(await this.mock.$parseInt(value.toString(10))).to.equal(value); - expect(await this.mock.$tryParseInt(value.toString(10))).to.deep.equal([true, value]); - }); - - for (const value of values) { - it(`convert ${value}`, async function () { - expect(await this.mock.$toStringSigned(value)).to.equal(value.toString(10)); - expect(await this.mock.$parseInt(value.toString(10))).to.equal(value); - expect(await this.mock.$tryParseInt(value.toString(10))).to.deep.equal([true, value]); - }); - - it(`convert negative ${value}`, async function () { - const negated = -value; - expect(await this.mock.$toStringSigned(negated)).to.equal(negated.toString(10)); - expect(await this.mock.$parseInt(negated.toString(10))).to.equal(negated); - expect(await this.mock.$tryParseInt(negated.toString(10))).to.deep.equal([true, negated]); - }); - } - }); - }); - - describe('toHexString', function () { - it('converts 0', async function () { - const value = 0n; - const string = ethers.toBeHex(value); // 0x00 - - expect(await this.mock.getFunction('$toHexString(uint256)')(value)).to.equal(string); - expect(await this.mock.$parseHexUint(string)).to.equal(value); - expect(await this.mock.$parseHexUint(string.replace(/0x/, ''))).to.equal(value); - expect(await this.mock.$tryParseHexUint(string)).to.deep.equal([true, value]); - expect(await this.mock.$tryParseHexUint(string.replace(/0x/, ''))).to.deep.equal([true, value]); - }); - - it('converts a positive number', async function () { - const value = 0x4132n; - const string = ethers.toBeHex(value); - - expect(await this.mock.getFunction('$toHexString(uint256)')(value)).to.equal(string); - expect(await this.mock.$parseHexUint(string)).to.equal(value); - expect(await this.mock.$parseHexUint(string.replace(/0x/, ''))).to.equal(value); - expect(await this.mock.$tryParseHexUint(string)).to.deep.equal([true, value]); - expect(await this.mock.$tryParseHexUint(string.replace(/0x/, ''))).to.deep.equal([true, value]); - }); - - it('converts MAX_UINT256', async function () { - const value = ethers.MaxUint256; - const string = ethers.toBeHex(value); - - expect(await this.mock.getFunction('$toHexString(uint256)')(value)).to.equal(string); - expect(await this.mock.$parseHexUint(string)).to.equal(value); - expect(await this.mock.$parseHexUint(string.replace(/0x/, ''))).to.equal(value); - expect(await this.mock.$tryParseHexUint(string)).to.deep.equal([true, value]); - expect(await this.mock.$tryParseHexUint(string.replace(/0x/, ''))).to.deep.equal([true, value]); - }); - }); - - describe('toHexString fixed', function () { - it('converts a positive number (long)', async function () { - expect(await this.mock.getFunction('$toHexString(uint256,uint256)')(0x4132n, 32n)).to.equal( - '0x0000000000000000000000000000000000000000000000000000000000004132', - ); - }); - - it('converts a positive number (short)', async function () { - const length = 1n; - await expect(this.mock.getFunction('$toHexString(uint256,uint256)')(0x4132n, length)) - .to.be.revertedWithCustomError(this.mock, 'StringsInsufficientHexLength') - .withArgs(0x4132, length); - }); - - it('converts MAX_UINT256', async function () { - expect(await this.mock.getFunction('$toHexString(uint256,uint256)')(ethers.MaxUint256, 32n)).to.equal( - ethers.toBeHex(ethers.MaxUint256), - ); - }); - }); - - describe('addresses', function () { - const addresses = [ - '0xa9036907dccae6a1e0033479b12e837e5cf5a02f', // Random address - '0x0000e0ca771e21bd00057f54a68c30d400000000', // Leading and trailing zeros - // EIP-55 reference - '0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed', - '0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359', - '0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB', - '0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb', - '0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359', - '0x52908400098527886E0F7030069857D2E4169EE7', - '0x8617E340B3D01FA5F11F306F4090FD50E238070D', - '0xde709f2102306220921060314715629080e2fb77', - '0x27b1fdb04752bbc536007a920d24acb045561c26', - '0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed', - '0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359', - '0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB', - '0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb', - ]; - - describe('toHexString', function () { - for (const addr of addresses) { - it(`converts ${addr}`, async function () { - expect(await this.mock.getFunction('$toHexString(address)')(addr)).to.equal(addr.toLowerCase()); - }); - } - }); - - describe('toChecksumHexString', function () { - for (const addr of addresses) { - it(`converts ${addr}`, async function () { - expect(await this.mock.$toChecksumHexString(addr)).to.equal(ethers.getAddress(addr)); - }); - } - }); - - describe('parseAddress', function () { - for (const addr of addresses) { - it(`converts ${addr}`, async function () { - expect(await this.mock.$parseAddress(addr)).to.equal(ethers.getAddress(addr)); - expect(await this.mock.$tryParseAddress(addr)).to.deep.equal([true, ethers.getAddress(addr)]); - }); - } - }); - }); - - describe('equal', function () { - it('compares two empty strings', async function () { - expect(await this.mock.$equal('', '')).to.be.true; - }); - - it('compares two equal strings', async function () { - expect(await this.mock.$equal('a', 'a')).to.be.true; - }); - - it('compares two different strings', async function () { - expect(await this.mock.$equal('a', 'b')).to.be.false; - }); - - it('compares two different strings of different lengths', async function () { - expect(await this.mock.$equal('a', 'aa')).to.be.false; - expect(await this.mock.$equal('aa', 'a')).to.be.false; - }); - - it('compares two different large strings', async function () { - const str1 = 'a'.repeat(201); - const str2 = 'a'.repeat(200) + 'b'; - expect(await this.mock.$equal(str1, str2)).to.be.false; - }); - - it('compares two equal large strings', async function () { - const str1 = 'a'.repeat(201); - const str2 = 'a'.repeat(201); - expect(await this.mock.$equal(str1, str2)).to.be.true; - }); - }); - - describe('Edge cases: invalid parsing', function () { - it('parseUint overflow', async function () { - await expect(this.mock.$parseUint((ethers.MaxUint256 + 1n).toString(10))).to.be.revertedWithPanic( - PANIC_CODES.ARITHMETIC_OVERFLOW, - ); - await expect(this.mock.$tryParseUint((ethers.MaxUint256 + 1n).toString(10))).to.be.revertedWithPanic( - PANIC_CODES.ARITHMETIC_OVERFLOW, - ); - }); - - it('parseUint invalid character', async function () { - await expect(this.mock.$parseUint('0x1')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - await expect(this.mock.$parseUint('1f')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - await expect(this.mock.$parseUint('-10')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - await expect(this.mock.$parseUint('1.0')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - await expect(this.mock.$parseUint('1 000')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - expect(await this.mock.$tryParseUint('0x1')).to.deep.equal([false, 0n]); - expect(await this.mock.$tryParseUint('1f')).to.deep.equal([false, 0n]); - expect(await this.mock.$tryParseUint('-10')).to.deep.equal([false, 0n]); - expect(await this.mock.$tryParseUint('1.0')).deep.equal([false, 0n]); - expect(await this.mock.$tryParseUint('1 000')).deep.equal([false, 0n]); - }); - - it('parseUint invalid range', async function () { - expect(this.mock.$parseUint('12', 3, 2)).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - expect(await this.mock.$tryParseUint('12', 3, 2)).to.deep.equal([false, 0n]); - }); - - it('parseInt overflow', async function () { - await expect(this.mock.$parseInt((ethers.MaxUint256 + 1n).toString(10))).to.be.revertedWithPanic( - PANIC_CODES.ARITHMETIC_OVERFLOW, - ); - await expect(this.mock.$parseInt((-ethers.MaxUint256 - 1n).toString(10))).to.be.revertedWithPanic( - PANIC_CODES.ARITHMETIC_OVERFLOW, - ); - await expect(this.mock.$tryParseInt((ethers.MaxUint256 + 1n).toString(10))).to.be.revertedWithPanic( - PANIC_CODES.ARITHMETIC_OVERFLOW, - ); - await expect(this.mock.$tryParseInt((-ethers.MaxUint256 - 1n).toString(10))).to.be.revertedWithPanic( - PANIC_CODES.ARITHMETIC_OVERFLOW, - ); - await expect(this.mock.$parseInt((ethers.MaxInt256 + 1n).toString(10))).to.be.revertedWithCustomError( - this.mock, - 'StringsInvalidChar', - ); - await expect(this.mock.$parseInt((ethers.MinInt256 - 1n).toString(10))).to.be.revertedWithCustomError( - this.mock, - 'StringsInvalidChar', - ); - expect(await this.mock.$tryParseInt((ethers.MaxInt256 + 1n).toString(10))).to.deep.equal([false, 0n]); - expect(await this.mock.$tryParseInt((ethers.MinInt256 - 1n).toString(10))).to.deep.equal([false, 0n]); - }); - - it('parseInt invalid character', async function () { - await expect(this.mock.$parseInt('0x1')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - await expect(this.mock.$parseInt('1f')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - await expect(this.mock.$parseInt('1.0')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - await expect(this.mock.$parseInt('1 000')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - expect(await this.mock.$tryParseInt('0x1')).to.deep.equal([false, 0n]); - expect(await this.mock.$tryParseInt('1f')).to.deep.equal([false, 0n]); - expect(await this.mock.$tryParseInt('1.0')).to.deep.equal([false, 0n]); - expect(await this.mock.$tryParseInt('1 000')).to.deep.equal([false, 0n]); - }); - - it('parseInt invalid range', async function () { - expect(this.mock.$parseInt('-12', 3, 2)).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - expect(await this.mock.$tryParseInt('-12', 3, 2)).to.deep.equal([false, 0n]); - }); - - it('parseHexUint overflow', async function () { - await expect(this.mock.$parseHexUint((ethers.MaxUint256 + 1n).toString(16))).to.be.revertedWithPanic( - PANIC_CODES.ARITHMETIC_OVERFLOW, - ); - await expect(this.mock.$tryParseHexUint((ethers.MaxUint256 + 1n).toString(16))).to.be.revertedWithPanic( - PANIC_CODES.ARITHMETIC_OVERFLOW, - ); - }); - - it('parseHexUint invalid character', async function () { - await expect(this.mock.$parseHexUint('0123456789abcdefg')).to.be.revertedWithCustomError( - this.mock, - 'StringsInvalidChar', - ); - await expect(this.mock.$parseHexUint('-1')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - await expect(this.mock.$parseHexUint('-f')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - await expect(this.mock.$parseHexUint('-0xf')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - await expect(this.mock.$parseHexUint('1.0')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - await expect(this.mock.$parseHexUint('1 000')).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - expect(await this.mock.$tryParseHexUint('0123456789abcdefg')).to.deep.equal([false, 0n]); - expect(await this.mock.$tryParseHexUint('-1')).to.deep.equal([false, 0n]); - expect(await this.mock.$tryParseHexUint('-f')).to.deep.equal([false, 0n]); - expect(await this.mock.$tryParseHexUint('-0xf')).to.deep.equal([false, 0n]); - expect(await this.mock.$tryParseHexUint('1.0')).to.deep.equal([false, 0n]); - expect(await this.mock.$tryParseHexUint('1 000')).to.deep.equal([false, 0n]); - }); - - it('parseHexUint invalid begin and end', async function () { - expect(this.mock.$parseHexUint('0x', 3, 2)).to.be.revertedWithCustomError(this.mock, 'StringsInvalidChar'); - expect(await this.mock.$tryParseHexUint('0x', 3, 2)).to.deep.equal([false, 0n]); - }); - - it('parseAddress invalid format', async function () { - for (const addr of [ - '0x736a507fB2881d6bB62dcA54673CF5295dC07833', // valid - '0x736a507fB2881d6-B62dcA54673CF5295dC07833', // invalid char - '0x0736a507fB2881d6bB62dcA54673CF5295dC07833', // tooLong - '0x36a507fB2881d6bB62dcA54673CF5295dC07833', // tooShort - '736a507fB2881d6bB62dcA54673CF5295dC07833', // missingPrefix - supported - ]) { - if (ethers.isAddress(addr)) { - expect(await this.mock.$parseAddress(addr)).to.equal(ethers.getAddress(addr)); - expect(await this.mock.$tryParseAddress(addr)).to.deep.equal([true, ethers.getAddress(addr)]); - } else { - await expect(this.mock.$parseAddress(addr)).to.be.revertedWithCustomError( - this.mock, - 'StringsInvalidAddressFormat', - ); - expect(await this.mock.$tryParseAddress(addr)).to.deep.equal([false, ethers.ZeroAddress]); - } - } - }); - }); - - describe('Escape JSON string', function () { - for (const input of ['', 'a', '{"a":"b/c"}', 'a\tb\nc\\d"e\rf/g\fh\bi']) - it(`escape ${JSON.stringify(input)}`, async function () { - await expect(this.mock.$escapeJSON(input)).to.eventually.equal(JSON.stringify(input).slice(1, -1)); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/TransientSlot.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/TransientSlot.test.js deleted file mode 100644 index 7b70be3..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/TransientSlot.test.js +++ /dev/null @@ -1,59 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { generators } = require('../helpers/random'); - -const slot = ethers.id('some.storage.slot'); -const otherSlot = ethers.id('some.other.storage.slot'); - -// Non-value types are not supported by the `TransientSlot` library. -const TYPES = [ - { name: 'Boolean', type: 'bool', value: true, zero: false }, - { name: 'Address', type: 'address', value: generators.address(), zero: generators.address.zero }, - { name: 'Bytes32', type: 'bytes32', value: generators.bytes32(), zero: generators.bytes32.zero }, - { name: 'Uint256', type: 'uint256', value: generators.uint256(), zero: generators.uint256.zero }, - { name: 'Int256', type: 'int256', value: generators.int256(), zero: generators.int256.zero }, -]; - -async function fixture() { - return { mock: await ethers.deployContract('TransientSlotMock') }; -} - -describe('TransientSlot', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - for (const { name, type, value, zero } of TYPES) { - describe(`${type} transient slot`, function () { - const load = `tload${name}(bytes32)`; - const store = `tstore(bytes32,${type})`; - const event = `${name}Value`; - - it('load', async function () { - await expect(this.mock[load](slot)).to.emit(this.mock, event).withArgs(slot, zero); - }); - - it('store and load (2 txs)', async function () { - await this.mock[store](slot, value); - await expect(this.mock[load](slot)).to.emit(this.mock, event).withArgs(slot, zero); - }); - - it('store and load (batched)', async function () { - await expect( - this.mock.multicall([ - this.mock.interface.encodeFunctionData(store, [slot, value]), - this.mock.interface.encodeFunctionData(load, [slot]), - this.mock.interface.encodeFunctionData(load, [otherSlot]), - ]), - ) - .to.emit(this.mock, event) - .withArgs(slot, value) - .to.emit(this.mock, event) - .withArgs(otherSlot, zero); - - await expect(this.mock[load](slot)).to.emit(this.mock, event).withArgs(slot, zero); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js deleted file mode 100644 index 0f2879a..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js +++ /dev/null @@ -1,211 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const TEST_MESSAGE = ethers.id('OpenZeppelin'); -const WRONG_MESSAGE = ethers.id('Nope'); -const NON_HASH_MESSAGE = '0xabcd'; - -async function fixture() { - const [signer] = await ethers.getSigners(); - const mock = await ethers.deployContract('$ECDSA'); - return { signer, mock }; -} - -describe('ECDSA', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('recover with invalid signature', function () { - it('with short signature', async function () { - await expect(this.mock.$recover(TEST_MESSAGE, '0x1234')) - .to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength') - .withArgs(2); - }); - - it('with long signature', async function () { - await expect( - this.mock.$recover( - TEST_MESSAGE, - '0x01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789', - ), - ) - .to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength') - .withArgs(85); - }); - }); - - describe('recover with valid signature', function () { - describe('using .sign', function () { - it('returns signer address with correct signature', async function () { - // Create the signature - const signature = await this.signer.signMessage(TEST_MESSAGE); - - // Recover the signer address from the generated message and signature. - expect(await this.mock.$recover(ethers.hashMessage(TEST_MESSAGE), signature)).to.equal(this.signer); - }); - - it('returns signer address with correct signature for arbitrary length message', async function () { - // Create the signature - const signature = await this.signer.signMessage(NON_HASH_MESSAGE); - - // Recover the signer address from the generated message and signature. - expect(await this.mock.$recover(ethers.hashMessage(NON_HASH_MESSAGE), signature)).to.equal(this.signer); - }); - - it('returns a different address', async function () { - const signature = await this.signer.signMessage(TEST_MESSAGE); - expect(await this.mock.$recover(WRONG_MESSAGE, signature)).to.not.be.equal(this.signer); - }); - - it('reverts with invalid signature', async function () { - const signature = - '0x332ce75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e01c'; - await expect(this.mock.$recover(TEST_MESSAGE, signature)).to.be.revertedWithCustomError( - this.mock, - 'ECDSAInvalidSignature', - ); - }); - }); - - describe('with v=27 signature', function () { - const signer = '0x2cc1166f6212628A0deEf2B33BEFB2187D35b86c'; - - const signatureWithoutV = - '0x5d99b6f7f6d1f73d1a26497f2b1c89b24c0993913f86e9a2d02cd69887d9c94f3c880358579d811b21dd1b7fd9bb01c1d81d10e69f0384e675c32b39643be892'; - - it('works with correct v value', async function () { - const v = '0x1b'; // 27 = 1b. - const signature = ethers.concat([signatureWithoutV, v]); - expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.equal(signer); - - const { r, s, yParityAndS: vs } = ethers.Signature.from(signature); - expect(await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s)).to.equal( - signer, - ); - - expect(await this.mock.getFunction('$recover(bytes32,bytes32,bytes32)')(TEST_MESSAGE, r, vs)).to.equal(signer); - }); - - it('rejects incorrect v value', async function () { - const v = '0x1c'; // 28 = 1c. - const signature = ethers.concat([signatureWithoutV, v]); - expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.not.equal(signer); - - const { r, s, yParityAndS: vs } = ethers.Signature.from(signature); - expect( - await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s), - ).to.not.equal(signer); - - expect(await this.mock.getFunction('$recover(bytes32,bytes32,bytes32)')(TEST_MESSAGE, r, vs)).to.not.equal( - signer, - ); - }); - - it('reverts wrong v values', async function () { - for (const v of ['0x00', '0x01']) { - const signature = ethers.concat([signatureWithoutV, v]); - await expect(this.mock.$recover(TEST_MESSAGE, signature)).to.be.revertedWithCustomError( - this.mock, - 'ECDSAInvalidSignature', - ); - - const { r, s } = ethers.Signature.from(signature); - await expect( - this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s), - ).to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignature'); - } - }); - - it('rejects short EIP2098 format', async function () { - const v = '0x1b'; // 27 = 1b. - const signature = ethers.concat([signatureWithoutV, v]); - - const { compactSerialized } = ethers.Signature.from(signature); - await expect(this.mock.$recover(TEST_MESSAGE, compactSerialized)) - .to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength') - .withArgs(64); - }); - }); - - describe('with v=28 signature', function () { - const signer = '0x1E318623aB09Fe6de3C9b8672098464Aeda9100E'; - - const signatureWithoutV = - '0x331fe75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e0'; - - it('works with correct v value', async function () { - const v = '0x1c'; // 28 = 1c. - const signature = ethers.concat([signatureWithoutV, v]); - expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.equal(signer); - - const { r, s, yParityAndS: vs } = ethers.Signature.from(signature); - expect(await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s)).to.equal( - signer, - ); - - expect(await this.mock.getFunction('$recover(bytes32,bytes32,bytes32)')(TEST_MESSAGE, r, vs)).to.equal(signer); - }); - - it('rejects incorrect v value', async function () { - const v = '0x1b'; // 27 = 1b. - const signature = ethers.concat([signatureWithoutV, v]); - expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.not.equal(signer); - - const { r, s, yParityAndS: vs } = ethers.Signature.from(signature); - expect( - await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s), - ).to.not.equal(signer); - - expect(await this.mock.getFunction('$recover(bytes32,bytes32,bytes32)')(TEST_MESSAGE, r, vs)).to.not.equal( - signer, - ); - }); - - it('reverts invalid v values', async function () { - for (const v of ['0x00', '0x01']) { - const signature = ethers.concat([signatureWithoutV, v]); - await expect(this.mock.$recover(TEST_MESSAGE, signature)).to.be.revertedWithCustomError( - this.mock, - 'ECDSAInvalidSignature', - ); - - const { r, s } = ethers.Signature.from(signature); - await expect( - this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s), - ).to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignature'); - } - }); - - it('rejects short EIP2098 format', async function () { - const v = '0x1b'; // 28 = 1b. - const signature = ethers.concat([signatureWithoutV, v]); - - const { compactSerialized } = ethers.Signature.from(signature); - await expect(this.mock.$recover(TEST_MESSAGE, compactSerialized)) - .to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength') - .withArgs(64); - }); - }); - - it('reverts with high-s value signature', async function () { - const message = '0xb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'; - - const highSSignature = - '0xe742ff452d41413616a5bf43fe15dd88294e983d3d36206c2712f39083d638bde0a0fc89be718fbc1033e1d30d78be1c68081562ed2e97af876f286f3453231d1b'; - - const r = ethers.dataSlice(highSSignature, 0, 32); - const s = ethers.dataSlice(highSSignature, 32, 64); - const v = ethers.dataSlice(highSSignature, 64, 65); - - await expect(this.mock.$recover(message, highSSignature)) - .to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureS') - .withArgs(s); - await expect(this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s)) - .to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureS') - .withArgs(s); - expect(() => ethers.Signature.from(highSSignature)).to.throw('non-canonical s'); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js deleted file mode 100644 index 2b6e7fa..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js +++ /dev/null @@ -1,105 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { getDomain, domainSeparator, hashTypedData } = require('../../helpers/eip712'); -const { formatType } = require('../../helpers/eip712-types'); - -const LENGTHS = { - short: ['A Name', '1'], - long: ['A'.repeat(40), 'B'.repeat(40)], -}; - -const fixture = async () => { - const [from, to] = await ethers.getSigners(); - - const lengths = {}; - for (const [shortOrLong, [name, version]] of Object.entries(LENGTHS)) { - lengths[shortOrLong] = { name, version }; - lengths[shortOrLong].eip712 = await ethers.deployContract('$EIP712Verifier', [name, version]); - lengths[shortOrLong].domain = { - name, - version, - chainId: await ethers.provider.getNetwork().then(({ chainId }) => chainId), - verifyingContract: lengths[shortOrLong].eip712.target, - }; - } - - return { from, to, lengths }; -}; - -describe('EIP712', function () { - for (const [shortOrLong, [name, version]] of Object.entries(LENGTHS)) { - describe(`with ${shortOrLong} name and version`, function () { - beforeEach('deploying', async function () { - Object.assign(this, await loadFixture(fixture)); - Object.assign(this, this.lengths[shortOrLong]); - }); - - 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(rebuildDomain).to.be.deep.equal(this.domain); - }); - - 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 ethers.deployContract('$Clones'); - - const clone = await factory - .$clone(this.eip712) - .then(tx => tx.wait()) - .then(receipt => receipt.logs.find(ev => ev.fragment.name == 'return$clone_address').args.instance) - .then(address => ethers.getContractAt('$EIP712Verifier', address)); - - const expectedDomain = { ...this.domain, verifyingContract: clone.target }; - expect(await getDomain(clone)).to.be.deep.equal(expectedDomain); - - const expectedSeparator = await domainSeparator(expectedDomain); - expect(await clone.$_domainSeparatorV4()).to.equal(expectedSeparator); - }); - } - }); - - it('hash digest', async function () { - const structhash = ethers.hexlify(ethers.randomBytes(32)); - expect(await this.eip712.$_hashTypedDataV4(structhash)).to.equal(hashTypedData(this.domain, structhash)); - }); - - it('digest', async function () { - const types = { - Mail: formatType({ - to: 'address', - contents: 'string', - }), - }; - - const message = { - to: this.to.address, - contents: 'very interesting', - }; - - const signature = await this.from.signTypedData(this.domain, types, message); - - await expect(this.eip712.verify(signature, this.from.address, message.to, message.contents)).to.not.be.reverted; - }); - - it('name', async function () { - expect(await this.eip712.$_EIP712Name()).to.equal(name); - }); - - it('version', async function () { - expect(await this.eip712.$_EIP712Version()).to.equal(version); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC1271.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC1271.behavior.js deleted file mode 100644 index ef3e668..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC1271.behavior.js +++ /dev/null @@ -1,111 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { Permit, formatType, getDomain } = require('../../helpers/eip712'); -const { ERC7739Signer } = require('../../helpers/erc7739'); - -function shouldBehaveLikeERC1271({ erc7739 = false } = {}) { - const MAGIC_VALUE = '0x1626ba7e'; - - describe(`supports ERC-${erc7739 ? 7739 : 1271}`, function () { - beforeEach(async function () { - // if deploy function is present, check that code is already in place - if (this.mock.deploy) { - await ethers.provider.getCode(this.mock.address).then(code => code != '0x' || this.mock.deploy()); - } - this._signer = erc7739 - ? new ERC7739Signer(this.signer, this.domain ?? (await getDomain(this.mock))) - : this.signer; - }); - - describe('PersonalSign', function () { - it('returns true for a valid personal signature', async function () { - const text = 'Hello, world!'; - - const hash = ethers.hashMessage(text); - const signature = await this._signer.signMessage(text); - - await expect(this.mock.isValidSignature(hash, signature)).to.eventually.equal(MAGIC_VALUE); - }); - - it('returns false for an invalid personal signature', async function () { - const message = 'Message the app expects'; - const otherMessage = 'Message signed is different'; - - const hash = ethers.hashMessage(message); - const signature = await this._signer.signMessage(otherMessage); - - await expect(this.mock.isValidSignature(hash, signature)).to.eventually.not.equal(MAGIC_VALUE); - }); - }); - - describe('TypedDataSign', function () { - beforeEach(async function () { - // Dummy app domain, different from the ERC7739's domain - // Note the difference of format (signer domain doesn't include a salt, but app domain does) - this.appDomain = { - name: 'SomeApp', - version: '1', - chainId: await ethers.provider.getNetwork().then(({ chainId }) => chainId), - verifyingContract: '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', - salt: '0x02cb3d8cb5e8928c9c6de41e935e16a4e28b2d54e7e7ba47e99f16071efab785', - }; - }); - - it('returns true for a valid typed data signature', async function () { - const contents = { - owner: '0x1ab5E417d9AF00f1ca9d159007e12c401337a4bb', - spender: '0xD68E96620804446c4B1faB3103A08C98d4A8F55f', - value: 1_000_000n, - nonce: 0n, - deadline: ethers.MaxUint256, - }; - - const hash = ethers.TypedDataEncoder.hash(this.appDomain, { Permit }, contents); - const signature = await this._signer.signTypedData(this.appDomain, { Permit }, contents); - - await expect(this.mock.isValidSignature(hash, signature)).to.eventually.equal(MAGIC_VALUE); - }); - - it('returns true for valid typed data signature (nested types)', async function () { - const contentsTypes = { - B: formatType({ z: 'Z' }), - Z: formatType({ a: 'A' }), - A: formatType({ v: 'uint256' }), - }; - - const contents = { z: { a: { v: 1n } } }; - - const hash = ethers.TypedDataEncoder.hash(this.appDomain, contentsTypes, contents); - const signature = await this._signer.signTypedData(this.appDomain, contentsTypes, contents); - - await expect(this.mock.isValidSignature(hash, signature)).to.eventually.equal(MAGIC_VALUE); - }); - - it('returns false for an invalid typed data signature', async function () { - const contents = { - owner: '0x1ab5E417d9AF00f1ca9d159007e12c401337a4bb', - spender: '0xD68E96620804446c4B1faB3103A08C98d4A8F55f', - value: 1_000_000n, - nonce: 0n, - deadline: ethers.MaxUint256, - }; - - const hash = ethers.TypedDataEncoder.hash(this.appDomain, { Permit }, contents); - // message signed by the user is for a lower amount. - const signature = await this._signer.signTypedData(this.appDomain, { Permit }, { ...contents, value: 1_000n }); - - await expect(this.mock.isValidSignature(hash, signature)).to.eventually.not.equal(MAGIC_VALUE); - }); - }); - - erc7739 && - it('support ERC-7739 detection', async function () { - const hash = '0x7739773977397739773977397739773977397739773977397739773977397739'; - await expect(this.mock.isValidSignature(hash, '0x')).to.eventually.equal('0x77390001'); - }); - }); -} - -module.exports = { - shouldBehaveLikeERC1271, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739.test.js deleted file mode 100644 index 8dc6a2b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739.test.js +++ /dev/null @@ -1,42 +0,0 @@ -const { ethers } = require('hardhat'); -const { shouldBehaveLikeERC1271 } = require('./ERC1271.behavior'); -const { NonNativeSigner, P256SigningKey, RSASHA256SigningKey } = require('../../helpers/signers'); - -describe('ERC7739', function () { - describe('for an ECDSA signer', function () { - before(async function () { - this.signer = ethers.Wallet.createRandom(); - this.mock = await ethers.deployContract('$ERC7739ECDSAMock', ['ERC7739ECDSA', '1', this.signer.address]); - }); - - shouldBehaveLikeERC1271({ erc7739: true }); - }); - - describe('for a P256 signer', function () { - before(async function () { - this.signer = new NonNativeSigner(P256SigningKey.random()); - this.mock = await ethers.deployContract('$ERC7739P256Mock', [ - 'ERC7739P256', - '1', - this.signer.signingKey.publicKey.qx, - this.signer.signingKey.publicKey.qy, - ]); - }); - - shouldBehaveLikeERC1271({ erc7739: true }); - }); - - describe('for an RSA signer', function () { - before(async function () { - this.signer = new NonNativeSigner(RSASHA256SigningKey.random()); - this.mock = await ethers.deployContract('$ERC7739RSAMock', [ - 'ERC7739RSA', - '1', - this.signer.signingKey.publicKey.e, - this.signer.signingKey.publicKey.n, - ]); - }); - - shouldBehaveLikeERC1271({ erc7739: true }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739Utils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739Utils.test.js deleted file mode 100644 index 93e382d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ERC7739Utils.test.js +++ /dev/null @@ -1,203 +0,0 @@ -const { expect } = require('chai'); -const { ethers } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { Permit } = require('../../helpers/eip712'); -const { ERC4337Utils, PersonalSign } = require('../../helpers/erc7739'); - -const details = ERC4337Utils.getContentsDetail({ Permit }); - -const fixture = async () => { - const mock = await ethers.deployContract('$ERC7739Utils'); - const domain = { - name: 'SomeDomain', - version: '1', - chainId: await ethers.provider.getNetwork().then(({ chainId }) => chainId), - verifyingContract: '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', - }; - const otherDomain = { - name: 'SomeOtherDomain', - version: '2', - chainId: await ethers.provider.getNetwork().then(({ chainId }) => chainId), - verifyingContract: '0x92C32cadBc39A15212505B5530aA765c441F306f', - }; - const permit = { - owner: '0x1ab5E417d9AF00f1ca9d159007e12c401337a4bb', - spender: '0xD68E96620804446c4B1faB3103A08C98d4A8F55f', - value: 1_000_000n, - nonce: 0n, - deadline: ethers.MaxUint256, - }; - return { mock, domain, otherDomain, permit }; -}; - -describe('ERC7739Utils', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('encodeTypedDataSig', function () { - it('wraps a typed data signature', async function () { - const signature = ethers.randomBytes(65); - const appSeparator = ethers.id('SomeApp'); - const contentsHash = ethers.id('SomeData'); - const contentsDescr = 'SomeType()'; - const encoded = ethers.concat([ - signature, - appSeparator, - contentsHash, - ethers.toUtf8Bytes(contentsDescr), - ethers.toBeHex(contentsDescr.length, 2), - ]); - - await expect( - this.mock.$encodeTypedDataSig(signature, appSeparator, contentsHash, contentsDescr), - ).to.eventually.equal(encoded); - }); - }); - - describe('decodeTypedDataSig', function () { - it('unwraps a typed data signature', async function () { - const signature = ethers.randomBytes(65); - const appSeparator = ethers.id('SomeApp'); - const contentsHash = ethers.id('SomeData'); - const contentsDescr = 'SomeType()'; - const encoded = ethers.concat([ - signature, - appSeparator, - contentsHash, - ethers.toUtf8Bytes(contentsDescr), - ethers.toBeHex(contentsDescr.length, 2), - ]); - - await expect(this.mock.$decodeTypedDataSig(encoded)).to.eventually.deep.equal([ - ethers.hexlify(signature), - appSeparator, - contentsHash, - contentsDescr, - ]); - }); - - it('returns default empty values if the signature is too short', async function () { - const encoded = ethers.randomBytes(65); // DOMAIN_SEPARATOR (32 bytes) + CONTENTS (32 bytes) + CONTENTS_TYPE_LENGTH (2 bytes) - 1 - await expect(this.mock.$decodeTypedDataSig(encoded)).to.eventually.deep.equal([ - '0x', - ethers.ZeroHash, - ethers.ZeroHash, - '', - ]); - }); - - it('returns default empty values if the length is invalid', async function () { - const encoded = ethers.concat([ethers.randomBytes(64), '0x3f']); // Can't be less than 64 bytes - await expect(this.mock.$decodeTypedDataSig(encoded)).to.eventually.deep.equal([ - '0x', - ethers.ZeroHash, - ethers.ZeroHash, - '', - ]); - }); - }); - - describe('personalSignStructhash', function () { - it('should produce a personal signature EIP-712 nested type', async function () { - const text = 'Hello, world!'; - - await expect(this.mock.$personalSignStructHash(ethers.hashMessage(text))).to.eventually.equal( - ethers.TypedDataEncoder.hashStruct('PersonalSign', { PersonalSign }, ERC4337Utils.preparePersonalSign(text)), - ); - }); - }); - - describe('typedDataSignStructHash', function () { - it('should match the typed data nested struct hash', async function () { - const message = ERC4337Utils.prepareSignTypedData(this.permit, this.domain); - - const contentsHash = ethers.TypedDataEncoder.hashStruct('Permit', { Permit }, this.permit); - const hash = ethers.TypedDataEncoder.hashStruct('TypedDataSign', details.allTypes, message); - - const domainBytes = ethers.AbiCoder.defaultAbiCoder().encode( - ['bytes32', 'bytes32', 'uint256', 'address', 'bytes32'], - [ - ethers.id(this.domain.name), - ethers.id(this.domain.version), - this.domain.chainId, - this.domain.verifyingContract, - ethers.ZeroHash, - ], - ); - - await expect( - this.mock.$typedDataSignStructHash( - details.contentsTypeName, - ethers.Typed.string(details.contentsDescr), - contentsHash, - domainBytes, - ), - ).to.eventually.equal(hash); - await expect( - this.mock.$typedDataSignStructHash(details.contentsDescr, contentsHash, domainBytes), - ).to.eventually.equal(hash); - }); - }); - - describe('typedDataSignTypehash', function () { - it('should match', async function () { - const typedDataSignType = ethers.TypedDataEncoder.from(details.allTypes).encodeType('TypedDataSign'); - - await expect( - this.mock.$typedDataSignTypehash( - details.contentsTypeName, - typedDataSignType.slice(typedDataSignType.indexOf(')') + 1), - ), - ).to.eventually.equal(ethers.keccak256(ethers.toUtf8Bytes(typedDataSignType))); - }); - }); - - describe('decodeContentsDescr', function () { - const forbiddenChars = ', )\x00'; - - for (const { descr, contentsDescr, contentTypeName, contentType } of [].concat( - { - descr: 'should parse a valid descriptor (implicit)', - contentsDescr: 'SomeType(address foo,uint256 bar)', - contentTypeName: 'SomeType', - }, - { - descr: 'should parse a valid descriptor (explicit)', - contentsDescr: 'A(C c)B(A a)C(uint256 v)B', - contentTypeName: 'B', - contentType: 'A(C c)B(A a)C(uint256 v)', - }, - { descr: 'should return nothing for an empty descriptor', contentsDescr: '', contentTypeName: null }, - { descr: 'should return nothing if no [(] is present', contentsDescr: 'SomeType', contentTypeName: null }, - { - descr: 'should return nothing if starts with [(] (implicit)', - contentsDescr: '(SomeType(address foo,uint256 bar)', - contentTypeName: null, - }, - { - descr: 'should return nothing if starts with [(] (explicit)', - contentsDescr: '(SomeType(address foo,uint256 bar)(SomeType', - contentTypeName: null, - }, - forbiddenChars.split('').map(char => ({ - descr: `should return nothing if contains [${char}] (implicit)`, - contentsDescr: `SomeType${char}(address foo,uint256 bar)`, - contentTypeName: null, - })), - forbiddenChars.split('').map(char => ({ - descr: `should return nothing if contains [${char}] (explicit)`, - contentsDescr: `SomeType${char}(address foo,uint256 bar)SomeType${char}`, - contentTypeName: null, - })), - )) { - it(descr, async function () { - await expect(this.mock.$decodeContentsDescr(contentsDescr)).to.eventually.deep.equal([ - contentTypeName ?? '', - contentTypeName ? (contentType ?? contentsDescr) : '', - ]); - }); - } - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js deleted file mode 100644 index 93ee964..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js +++ /dev/null @@ -1,213 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); -const { SimpleMerkleTree } = require('@openzeppelin/merkle-tree'); - -// generate bytes32 leaves from a string -const toLeaves = (str, separator = '') => str.split(separator).map(e => ethers.keccak256(ethers.toUtf8Bytes(e))); -// internal node hashes -const concatSorted = (...elements) => Buffer.concat(elements.map(ethers.getBytes).sort(Buffer.compare)); -const defaultHash = (a, b) => ethers.keccak256(concatSorted(a, b)); -const customHash = (a, b) => ethers.sha256(concatSorted(a, b)); - -describe('MerkleProof', function () { - for (const { title, contractName, nodeHash } of [ - { title: 'default hash', contractName: '$MerkleProof', nodeHash: defaultHash }, - { title: 'custom hash', contractName: '$MerkleProofCustomHashMock', nodeHash: customHash }, - ]) { - describe(title, function () { - // stateless: no need for a fixture, just use before - before(async function () { - this.mock = await ethers.deployContract(contractName); - this.makeTree = str => SimpleMerkleTree.of(toLeaves(str), { nodeHash }); - }); - - describe('verify', function () { - it('returns true for a valid Merkle proof', async function () { - const merkleTree = this.makeTree('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='); - - const root = merkleTree.root; - const hash = merkleTree.at(0); - const proof = merkleTree.getProof(0); - - expect(await this.mock.$processProof(proof, hash)).to.equal(root); - expect(await this.mock.$processProofCalldata(proof, hash)).to.equal(root); - expect(await this.mock.$verify(proof, root, hash)).to.be.true; - expect(await this.mock.$verifyCalldata(proof, root, hash)).to.be.true; - - // For demonstration, it is also possible to create valid proofs for certain 64-byte values *not* in elements: - const noSuchLeaf = nodeHash(hash, proof.at(0)); - - expect(await this.mock.$processProof(proof.slice(1), noSuchLeaf)).to.equal(root); - expect(await this.mock.$processProofCalldata(proof.slice(1), noSuchLeaf)).to.equal(root); - expect(await this.mock.$verify(proof.slice(1), root, noSuchLeaf)).to.be.true; - expect(await this.mock.$verifyCalldata(proof.slice(1), root, noSuchLeaf)).to.be.true; - }); - - it('returns false for an invalid Merkle proof', async function () { - const correctMerkleTree = this.makeTree('abc'); - const otherMerkleTree = this.makeTree('def'); - - const root = correctMerkleTree.root; - const hash = correctMerkleTree.at(0); - const proof = otherMerkleTree.getProof(0); - - expect(await this.mock.$processProof(proof, hash)).to.not.equal(root); - expect(await this.mock.$processProofCalldata(proof, hash)).to.not.equal(root); - expect(await this.mock.$verify(proof, root, hash)).to.be.false; - expect(await this.mock.$verifyCalldata(proof, root, hash)).to.be.false; - }); - - it('returns false for a Merkle proof of invalid length', async function () { - const merkleTree = this.makeTree('abc'); - - const root = merkleTree.root; - const hash = merkleTree.at(0); - const proof = merkleTree.getProof(0); - const badProof = proof.slice(0, -1); - - expect(await this.mock.$processProof(badProof, hash)).to.not.equal(root); - expect(await this.mock.$processProofCalldata(badProof, hash)).to.not.equal(root); - expect(await this.mock.$verify(badProof, root, hash)).to.be.false; - expect(await this.mock.$verifyCalldata(badProof, root, hash)).to.be.false; - }); - }); - - describe('multiProofVerify', function () { - it('returns true for a valid Merkle multi proof', async function () { - const merkleTree = this.makeTree('abcdef'); - - const root = merkleTree.root; - const { proof, proofFlags, leaves } = merkleTree.getMultiProof(toLeaves('bdf')); - const hashes = leaves.map(e => merkleTree.leafHash(e)); - - expect(await this.mock.$processMultiProof(proof, proofFlags, hashes)).to.equal(root); - expect(await this.mock.$processMultiProofCalldata(proof, proofFlags, hashes)).to.equal(root); - expect(await this.mock.$multiProofVerify(proof, proofFlags, root, hashes)).to.be.true; - expect(await this.mock.$multiProofVerifyCalldata(proof, proofFlags, root, hashes)).to.be.true; - }); - - it('returns false for an invalid Merkle multi proof', async function () { - const merkleTree = this.makeTree('abcdef'); - const otherMerkleTree = this.makeTree('ghi'); - - const root = merkleTree.root; - const { proof, proofFlags, leaves } = otherMerkleTree.getMultiProof(toLeaves('ghi')); - const hashes = leaves.map(e => merkleTree.leafHash(e)); - - expect(await this.mock.$processMultiProof(proof, proofFlags, hashes)).to.not.equal(root); - expect(await this.mock.$processMultiProofCalldata(proof, proofFlags, hashes)).to.not.equal(root); - expect(await this.mock.$multiProofVerify(proof, proofFlags, root, hashes)).to.be.false; - expect(await this.mock.$multiProofVerifyCalldata(proof, proofFlags, root, hashes)).to.be.false; - }); - - it('revert with invalid multi proof #1', async function () { - const merkleTree = this.makeTree('abcd'); - - const root = merkleTree.root; - const hashA = merkleTree.at(0); - const hashB = merkleTree.at(1); - const hashCD = nodeHash(merkleTree.at(2), merkleTree.at(3)); - const hashE = ethers.randomBytes(32); // incorrect (not part of the tree) - const fill = ethers.randomBytes(32); - - await expect( - this.mock.$processMultiProof([hashB, fill, hashCD], [false, false, false], [hashA, hashE]), - ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); - - await expect( - this.mock.$processMultiProofCalldata([hashB, fill, hashCD], [false, false, false], [hashA, hashE]), - ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); - - await expect( - this.mock.$multiProofVerify([hashB, fill, hashCD], [false, false, false], root, [hashA, hashE]), - ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); - - await expect( - this.mock.$multiProofVerifyCalldata([hashB, fill, hashCD], [false, false, false], root, [hashA, hashE]), - ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); - }); - - it('revert with invalid multi proof #2', async function () { - const merkleTree = this.makeTree('abcd'); - - const root = merkleTree.root; - const hashA = merkleTree.at(0); - const hashB = merkleTree.at(1); - const hashCD = nodeHash(merkleTree.at(2), merkleTree.at(3)); - const hashE = ethers.randomBytes(32); // incorrect (not part of the tree) - const fill = ethers.randomBytes(32); - - await expect( - this.mock.$processMultiProof([hashB, fill, hashCD], [false, false, false, false], [hashE, hashA]), - ).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); - - await expect( - this.mock.$processMultiProofCalldata([hashB, fill, hashCD], [false, false, false, false], [hashE, hashA]), - ).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); - - await expect( - this.mock.$multiProofVerify([hashB, fill, hashCD], [false, false, false, false], root, [hashE, hashA]), - ).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); - - await expect( - this.mock.$multiProofVerifyCalldata([hashB, fill, hashCD], [false, false, false, false], root, [ - hashE, - hashA, - ]), - ).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); - }); - - it('limit case: works for tree containing a single leaf', async function () { - const merkleTree = this.makeTree('a'); - - const root = merkleTree.root; - const { proof, proofFlags, leaves } = merkleTree.getMultiProof(toLeaves('a')); - const hashes = leaves.map(e => merkleTree.leafHash(e)); - - expect(await this.mock.$processMultiProof(proof, proofFlags, hashes)).to.equal(root); - expect(await this.mock.$processMultiProofCalldata(proof, proofFlags, hashes)).to.equal(root); - expect(await this.mock.$multiProofVerify(proof, proofFlags, root, hashes)).to.be.true; - expect(await this.mock.$multiProofVerifyCalldata(proof, proofFlags, root, hashes)).to.be.true; - }); - - it('limit case: can prove empty leaves', async function () { - const merkleTree = this.makeTree('abcd'); - - const root = merkleTree.root; - expect(await this.mock.$processMultiProof([root], [], [])).to.equal(root); - expect(await this.mock.$processMultiProofCalldata([root], [], [])).to.equal(root); - expect(await this.mock.$multiProofVerify([root], [], root, [])).to.be.true; - expect(await this.mock.$multiProofVerifyCalldata([root], [], root, [])).to.be.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 leave = ethers.id('real leaf'); - const root = nodeHash(leave, ethers.ZeroHash); - - // Now we can pass any **malicious** fake leaves as valid! - const maliciousLeaves = ['malicious', 'leaves'].map(ethers.id).map(ethers.toBeArray).sort(Buffer.compare); - const maliciousProof = [leave, leave]; - const maliciousProofFlags = [true, true, false]; - - await expect( - this.mock.$processMultiProof(maliciousProof, maliciousProofFlags, maliciousLeaves), - ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); - - await expect( - this.mock.$processMultiProofCalldata(maliciousProof, maliciousProofFlags, maliciousLeaves), - ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); - - await expect( - this.mock.$multiProofVerify(maliciousProof, maliciousProofFlags, root, maliciousLeaves), - ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); - - await expect( - this.mock.$multiProofVerifyCalldata(maliciousProof, maliciousProofFlags, root, maliciousLeaves), - ).to.be.revertedWithCustomError(this.mock, 'MerkleProofInvalidMultiproof'); - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.t.sol deleted file mode 100644 index 4259c88..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.t.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; -import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; - -contract MessageHashUtilsTest is Test { - function testToDataWithIntendedValidatorHash(address validator, bytes memory data) external pure { - assertEq( - MessageHashUtils.toDataWithIntendedValidatorHash(validator, data), - MessageHashUtils.toDataWithIntendedValidatorHash(_dirty(validator), data) - ); - } - - function testToDataWithIntendedValidatorHash(address validator, bytes32 messageHash) external pure { - assertEq( - MessageHashUtils.toDataWithIntendedValidatorHash(validator, messageHash), - MessageHashUtils.toDataWithIntendedValidatorHash(_dirty(validator), messageHash) - ); - - assertEq( - MessageHashUtils.toDataWithIntendedValidatorHash(validator, messageHash), - MessageHashUtils.toDataWithIntendedValidatorHash(validator, abi.encodePacked(messageHash)) - ); - } - - function _dirty(address input) private pure returns (address output) { - assembly ("memory-safe") { - output := or(input, shl(160, not(0))) - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.test.js deleted file mode 100644 index 57e8286..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.test.js +++ /dev/null @@ -1,97 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { domainSeparator, hashTypedData } = require('../../helpers/eip712'); - -async function fixture() { - const mock = await ethers.deployContract('$MessageHashUtils'); - return { mock }; -} - -describe('MessageHashUtils', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('toEthSignedMessageHash', function () { - it('prefixes bytes32 data correctly', async function () { - const message = ethers.randomBytes(32); - const expectedHash = ethers.hashMessage(message); - - await expect(this.mock.getFunction('$toEthSignedMessageHash(bytes32)')(message)).to.eventually.equal( - expectedHash, - ); - }); - - it('prefixes dynamic length data correctly', async function () { - const message = ethers.randomBytes(128); - const expectedHash = ethers.hashMessage(message); - - await expect(this.mock.getFunction('$toEthSignedMessageHash(bytes)')(message)).to.eventually.equal(expectedHash); - }); - - it('version match for bytes32', async function () { - const message = ethers.randomBytes(32); - const fixed = await this.mock.getFunction('$toEthSignedMessageHash(bytes32)')(message); - const dynamic = await this.mock.getFunction('$toEthSignedMessageHash(bytes)')(message); - - expect(fixed).to.equal(dynamic); - }); - }); - - describe('toDataWithIntendedValidatorHash', function () { - it('returns the digest of `bytes32 messageHash` correctly', async function () { - const verifier = ethers.Wallet.createRandom().address; - const message = ethers.randomBytes(32); - const expectedHash = ethers.solidityPackedKeccak256( - ['string', 'address', 'bytes32'], - ['\x19\x00', verifier, message], - ); - - await expect( - this.mock.getFunction('$toDataWithIntendedValidatorHash(address,bytes32)')(verifier, message), - ).to.eventually.equal(expectedHash); - }); - - it('returns the digest of `bytes memory message` correctly', async function () { - const verifier = ethers.Wallet.createRandom().address; - const message = ethers.randomBytes(128); - const expectedHash = ethers.solidityPackedKeccak256( - ['string', 'address', 'bytes'], - ['\x19\x00', verifier, message], - ); - - await expect( - this.mock.getFunction('$toDataWithIntendedValidatorHash(address,bytes)')(verifier, message), - ).to.eventually.equal(expectedHash); - }); - - it('version match for bytes32', async function () { - const verifier = ethers.Wallet.createRandom().address; - const message = ethers.randomBytes(32); - const fixed = await this.mock.getFunction('$toDataWithIntendedValidatorHash(address,bytes)')(verifier, message); - const dynamic = await this.mock.getFunction('$toDataWithIntendedValidatorHash(address,bytes32)')( - verifier, - message, - ); - - expect(fixed).to.equal(dynamic); - }); - }); - - describe('toTypedDataHash', function () { - it('returns the digest correctly', async function () { - const domain = { - name: 'Test', - version: '1', - chainId: 1n, - verifyingContract: ethers.Wallet.createRandom().address, - }; - const structhash = ethers.randomBytes(32); - const expectedHash = hashTypedData(domain, structhash); - - await expect(this.mock.$toTypedDataHash(domainSeparator(domain), structhash)).to.eventually.equal(expectedHash); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.t.sol deleted file mode 100644 index ee11b43..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.t.sol +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; - -import {P256} from "@openzeppelin/contracts/utils/cryptography/P256.sol"; -import {Errors} from "@openzeppelin/contracts/utils/Errors.sol"; - -contract P256Test is Test { - /// forge-config: default.fuzz.runs = 512 - function testVerify(bytes32 digest, uint256 seed) public view { - uint256 privateKey = _asPrivateKey(seed); - - (uint256 x, uint256 y) = vm.publicKeyP256(privateKey); - (bytes32 r, bytes32 s) = vm.signP256(privateKey, digest); - s = _ensureLowerS(s); - assertTrue(P256.verify(digest, r, s, bytes32(x), bytes32(y))); - assertTrue(P256.verifySolidity(digest, r, s, bytes32(x), bytes32(y))); - } - - /// forge-config: default.fuzz.runs = 512 - function testRecover(bytes32 digest, uint256 seed) public view { - uint256 privateKey = _asPrivateKey(seed); - - (uint256 x, uint256 y) = vm.publicKeyP256(privateKey); - (bytes32 r, bytes32 s) = vm.signP256(privateKey, digest); - s = _ensureLowerS(s); - (bytes32 qx0, bytes32 qy0) = P256.recovery(digest, 0, r, s); - (bytes32 qx1, bytes32 qy1) = P256.recovery(digest, 1, r, s); - assertTrue((qx0 == bytes32(x) && qy0 == bytes32(y)) || (qx1 == bytes32(x) && qy1 == bytes32(y))); - } - - function testVerifyNativeUnsupportedRIP7212(bytes32 digest, uint256 seed) public { - // By default, the precompile at address 0x100 is not supported. - - uint256 privateKey = _asPrivateKey(seed); - - (uint256 x, uint256 y) = vm.publicKeyP256(privateKey); - (bytes32 r, bytes32 s) = vm.signP256(privateKey, digest); - s = _ensureLowerS(s); - - (bool success, bytes memory returndata) = address(this).call( - abi.encodeCall(P256Test.verifyNative, (digest, r, s, bytes32(x), bytes32(y))) - ); - assertFalse(success); - assertEq(returndata, abi.encodeWithSelector(Errors.MissingPrecompile.selector, address(0x100))); - } - - function _asPrivateKey(uint256 seed) private pure returns (uint256) { - return bound(seed, 1, P256.N - 1); - } - - function _ensureLowerS(bytes32 s) private pure returns (bytes32) { - uint256 _s = uint256(s); - unchecked { - return _s > P256.N / 2 ? bytes32(P256.N - _s) : s; - } - } - - // See https://github.com/foundry-rs/foundry/issues/10237 - function verifyNative(bytes32 digest, bytes32 r, bytes32 s, bytes32 x, bytes32 y) external view { - P256.verifyNative(digest, r, s, x, y); - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.test.js deleted file mode 100644 index a75d527..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/P256.test.js +++ /dev/null @@ -1,182 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { secp256r1 } = require('@noble/curves/p256'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const N = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551n; - -// As in ECDSA, signatures are malleable and the tooling produce both high and low S values. -// We need to ensure that the s value is in the lower half of the order of the curve. -const ensureLowerOrderS = ({ s, recovery, ...rest }) => { - if (s > N / 2n) { - s = N - s; - recovery = 1 - recovery; - } - return { s, recovery, ...rest }; -}; - -const prepareSignature = ( - privateKey = secp256r1.utils.randomPrivateKey(), - messageHash = ethers.hexlify(ethers.randomBytes(0x20)), -) => { - const publicKey = [ - secp256r1.getPublicKey(privateKey, false).slice(0x01, 0x21), - secp256r1.getPublicKey(privateKey, false).slice(0x21, 0x41), - ].map(ethers.hexlify); - const { r, s, recovery } = ensureLowerOrderS(secp256r1.sign(messageHash.replace(/0x/, ''), privateKey)); - const signature = [r, s].map(v => ethers.toBeHex(v, 0x20)); - - return { privateKey, publicKey, signature, recovery, messageHash }; -}; - -describe('P256', function () { - async function fixture() { - return { mock: await ethers.deployContract('$P256') }; - } - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('with signature', function () { - beforeEach(async function () { - Object.assign(this, prepareSignature()); - }); - - it('verify valid signature', async function () { - await expect(this.mock.$verify(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be.true; - await expect(this.mock.$verifySolidity(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be - .true; - await expect(this.mock.$verifyNative(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be - .true; - }); - - it('verify improper signature', async function () { - const signature = this.signature; - this.signature[0] = ethers.toBeHex(N, 0x20); // r = N - await expect(this.mock.$verify(this.messageHash, ...signature, ...this.publicKey)).to.eventually.be.false; - await expect(this.mock.$verifySolidity(this.messageHash, ...signature, ...this.publicKey)).to.eventually.be.false; - await expect(this.mock.$verifyNative(this.messageHash, ...signature, ...this.publicKey)).to.eventually.be.false; - }); - - it('recover public key', async function () { - await expect(this.mock.$recovery(this.messageHash, this.recovery, ...this.signature)).to.eventually.deep.equal( - this.publicKey, - ); - }); - - it('recovers (0,0) for invalid recovery bit', async function () { - await expect(this.mock.$recovery(this.messageHash, 2, ...this.signature)).to.eventually.deep.equal([ - ethers.ZeroHash, - ethers.ZeroHash, - ]); - }); - - it('recovers (0,0) for improper signature', async function () { - const signature = this.signature; - this.signature[0] = ethers.toBeHex(N, 0x20); // r = N - await expect(this.mock.$recovery(this.messageHash, this.recovery, ...signature)).to.eventually.deep.equal([ - ethers.ZeroHash, - ethers.ZeroHash, - ]); - }); - - it('reject signature with flipped public key coordinates ([x,y] >> [y,x])', async function () { - // flip public key - this.publicKey.reverse(); - - await expect(this.mock.$verify(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be.false; - await expect(this.mock.$verifySolidity(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be - .false; - await expect(this.mock.$verifyNative(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be - .false; - }); - - it('reject signature with flipped signature values ([r,s] >> [s,r])', async function () { - // Preselected signature where `r < N/2` and `s < N/2` - this.signature = [ - '0x45350225bad31e89db662fcc4fb2f79f349adbb952b3f652eed1f2aa72fb0356', - '0x513eb68424c42630012309eee4a3b43e0bdc019d179ef0e0c461800845e237ee', - ]; - - // Corresponding hash and public key - this.messageHash = '0x2ad1f900fe63745deeaedfdf396cb6f0f991c4338a9edf114d52f7d1812040a0'; - this.publicKey = [ - '0x9e30de165e521257996425d9bf12a7d366925614bf204eabbb78172b48e52e59', - '0x94bf0fe72f99654d7beae4780a520848e306d46a1275b965c4f4c2b8e9a2c08d', - ]; - - // Make sure it works - await expect(this.mock.$verify(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be.true; - - // Flip signature - this.signature.reverse(); - - await expect(this.mock.$verify(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be.false; - await expect(this.mock.$verifySolidity(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be - .false; - await expect(this.mock.$verifyNative(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be - .false; - await expect( - this.mock.$recovery(this.messageHash, this.recovery, ...this.signature), - ).to.eventually.not.deep.equal(this.publicKey); - }); - - it('reject signature with invalid message hash', async function () { - // random message hash - this.messageHash = ethers.hexlify(ethers.randomBytes(32)); - - await expect(this.mock.$verify(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be.false; - await expect(this.mock.$verifySolidity(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be - .false; - await expect(this.mock.$verifyNative(this.messageHash, ...this.signature, ...this.publicKey)).to.eventually.be - .false; - await expect( - this.mock.$recovery(this.messageHash, this.recovery, ...this.signature), - ).to.eventually.not.deep.equal(this.publicKey); - }); - - it('fail to recover signature with invalid recovery bit', async function () { - // flip recovery bit - this.recovery = 1 - this.recovery; - - await expect( - this.mock.$recovery(this.messageHash, this.recovery, ...this.signature), - ).to.eventually.not.deep.equal(this.publicKey); - }); - }); - - // test cases for https://github.com/C2SP/wycheproof/blob/4672ff74d68766e7785c2cac4c597effccef2c5c/testvectors/ecdsa_secp256r1_sha256_p1363_test.json - describe('wycheproof tests', function () { - for (const { key, tests } of require('./ecdsa_secp256r1_sha256_p1363_test.json').testGroups) { - // parse public key - let [x, y] = [key.wx, key.wy].map(v => ethers.stripZerosLeft('0x' + v, 32)); - if (x.length > 66 || y.length > 66) continue; - x = ethers.zeroPadValue(x, 32); - y = ethers.zeroPadValue(y, 32); - - // run all tests for this key - for (const { tcId, comment, msg, sig, result } of tests) { - // only keep properly formatted signatures - if (sig.length != 128) continue; - - it(`${tcId}: ${comment}`, async function () { - // split signature, and reduce modulo N - let [r, s] = Array(2) - .fill() - .map((_, i) => ethers.toBigInt('0x' + sig.substring(64 * i, 64 * (i + 1)))); - // move s to lower part of the curve if needed - if (s <= N && s > N / 2n) s = N - s; - // prepare signature - r = ethers.toBeHex(r, 32); - s = ethers.toBeHex(s, 32); - // hash - const messageHash = ethers.sha256('0x' + msg); - - // check verify - await expect(this.mock.$verify(messageHash, r, s, x, y)).to.eventually.equal(result == 'valid'); - }); - } - } - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.helper.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.helper.js deleted file mode 100644 index 48c8ee4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.helper.js +++ /dev/null @@ -1,17 +0,0 @@ -const path = require('path'); -const fs = require('fs'); - -module.exports = function* parse(file) { - const cache = {}; - const data = fs.readFileSync(path.resolve(__dirname, file), 'utf8'); - for (const line of data.split('\r\n')) { - const groups = line.match(/^(?\w+) = (?\w+)(?.*)$/)?.groups; - if (groups) { - const { key, value, extra } = groups; - cache[key] = value; - if (groups.key === 'Result') { - yield Object.assign({ extra: extra.trim() }, cache); - } - } - } -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.test.js deleted file mode 100644 index bdf3391..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/RSA.test.js +++ /dev/null @@ -1,102 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { bytes, bytes32 } = ethers.Typed; - -const parse = require('./RSA.helper'); - -async function fixture() { - return { mock: await ethers.deployContract('$RSA') }; -} - -describe('RSA', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - // Load test cases from file SigVer15_186-3.rsp from: - // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/dss/186-2rsatestvectors.zip - describe('SigVer15_186-3.rsp tests', function () { - for (const test of parse('SigVer15_186-3.rsp')) { - const { length } = Buffer.from(test.S, 'hex'); - - /// For now, RSA only supports digest that are 32bytes long. If we ever extend that, we can use these hashing functions for @noble: - // const { sha1 } = require('@noble/hashes/sha1'); - // const { sha224, sha256 } = require('@noble/hashes/sha256'); - // const { sha384, sha512 } = require('@noble/hashes/sha512'); - - if (test.SHAAlg === 'SHA256' && length >= 0x100) { - const result = test.Result === 'P'; - - it(`signature length ${length} ${test.extra} ${result ? 'works' : 'fails'}`, async function () { - const data = '0x' + test.Msg; - const sig = '0x' + test.S; - const exp = '0x' + test.e; - const mod = '0x' + test.n; - - expect(await this.mock.$pkcs1Sha256(bytes32(ethers.sha256(data)), sig, exp, mod)).to.equal(result); - expect(await this.mock.$pkcs1Sha256(bytes(data), sig, exp, mod)).to.equal(result); - }); - } - } - }); - - describe('others tests', function () { - // > openssl genrsa -out private.pem 2048 - // > openssl rsa -in private.pem -outform der -pubout -out public.pem - // > openssl asn1parse -in public.pem -inform DER -strparse 19 - // > echo -n 'hello world!' | openssl dgst -sha256 -sign private.pem | xxd -p | tr -d \\n - const openssl = { - descr: 'openssl', - data: ethers.toUtf8Bytes('hello world!'), - sig: '0x2ff4349940bf0db9bce422e316ac47e3d24b0a869acb05c9c46f74e17491177698b150f2a5996a6bf7d7c73e05af91ad78632115a7d95b823c462596486e56e8473b75a270ca4760cd83f244d5d3af81d2c7d188879abbc2992b22d51e22ffb725f0828c852ee44f81def383e0f92ebfa3c6d97ca5e52a4254f9a886680e3fb394c2a8a955849313dce2cb416f8a67974effd9a17d229146ce10a98684fb3d46a1e53ddaf831cdd2beed895532533c554ae087b2738a5c4cf0802e8062b2a599fd76d67b92eabffa8a92b24e08fbc866217502a4a3d9f6157e491bede3c1048fa8f2d804f66128e8a883018b0ec33a59e1086bf71ae5dc193d9815ca82892dbc', - exp: '0x010001', - mod: '0xDC1CE5F7B202464CD320B4F9E44FEE0A358BE7022AB155A5BDEE45B1AED3C5A19645D898E294CBA96EAD6929FD8FB4B23E9ADB4D3143A736232C32A8617A77B89F7D8399B9BE37F8349D111067F71D2F20237B9F1A7C1CF44819F9FA5AA030F563DCFB1CC59FFAA86BA2ABEE28D949FED0DF34071B7558950079E28CD9BBA4CAC2F0F86D7BBFB13363C792B5A70C9B279F0B43A264A7CB1A7C7C41FC6EC1D1C1125A6BECE3207AE582F74CE896B9AC18DB00C8985B70145217B831CC313FC06581E186BF70A2EEE2C3C065B5C91A89B2C099B4924CDBF5707D161BD83AC8D9FCA309AC75D63EACF21027C2C9C9F05994331CBDFDD24F9BC6C8B58D8F1824540B', - result: true, - }; - - // According to RFC4055, pg.5 and RFC8017, pg. 64, for SHA-1, and the SHA-2 family, - // the algorithm parameter has to be NULL and both explicit NULL parameter and implicit - // NULL parameter (ie, absent NULL parameter) are considered to be legal and equivalent. - const rfc4055 = { - descr: 'rfc8017 implicit null parameter', - data: ethers.toUtf8Bytes('hello world!'), - sig: '0xa0073057133ff3758e7e111b4d7441f1d8cbe4b2dd5ee4316a14264290dee5ed7f175716639bd9bb43a14e4f9fcb9e84dedd35e2205caac04828b2c053f68176d971ea88534dd2eeec903043c3469fc69c206b2a8694fd262488441ed8852280c3d4994e9d42bd1d575c7024095f1a20665925c2175e089c0d731471f6cc145404edf5559fd2276e45e448086f71c78d0cc6628fad394a34e51e8c10bc39bfe09ed2f5f742cc68bee899d0a41e4c75b7b80afd1c321d89ccd9fe8197c44624d91cc935dfa48de3c201099b5b417be748aef29248527e8bbb173cab76b48478d4177b338fe1f1244e64d7d23f07add560d5ad50b68d6649a49d7bc3db686daaa7', - exp: '0x03', - mod: '0xe932ac92252f585b3a80a4dd76a897c8b7652952fe788f6ec8dd640587a1ee5647670a8ad4c2be0f9fa6e49c605adf77b5174230af7bd50e5d6d6d6d28ccf0a886a514cc72e51d209cc772a52ef419f6a953f3135929588ebe9b351fca61ced78f346fe00dbb6306e5c2a4c6dfc3779af85ab417371cf34d8387b9b30ae46d7a5ff5a655b8d8455f1b94ae736989d60a6f2fd5cadbffbd504c5a756a2e6bb5cecc13bca7503f6df8b52ace5c410997e98809db4dc30d943de4e812a47553dce54844a78e36401d13f77dc650619fed88d8b3926e3d8e319c80c744779ac5d6abe252896950917476ece5e8fc27d5f053d6018d91b502c4787558a002b9283da7', - result: true, - }; - - const shortN = { - descr: 'returns false for a very short n', - data: ethers.toUtf8Bytes('hello world!'), - sig: '0x0102', - exp: '0x03', - mod: '0x0405', - result: false, - }; - - const differentLength = { - descr: 'returns false for a signature with different length to n', - data: ethers.toUtf8Bytes('hello world!'), - sig: '0x00112233', - exp: '0x03', - mod: '0xe932ac92252f585b3a80a4dd76a897c8b7652952fe788f6ec8dd640587a1ee5647670a8ad4c2be0f9fa6e49c605adf77b5174230af7bd50e5d6d6d6d28ccf0a886a514cc72e51d209cc772a52ef419f6a953f3135929588ebe9b351fca61ced78f346fe00dbb6306e5c2a4c6dfc3779af85ab417371cf34d8387b9b30ae46d7a5ff5a655b8d8455f1b94ae736989d60a6f2fd5cadbffbd504c5a756a2e6bb5cecc13bca7503f6df8b52ace5c410997e98809db4dc30d943de4e812a47553dce54844a78e36401d13f77dc650619fed88d8b3926e3d8e319c80c744779ac5d6abe252896950917476ece5e8fc27d5f053d6018d91b502c4787558a002b9283da7', - result: false, - }; - - // this is the openssl example where sig has been replaced by sig + mod - const sTooLarge = { - ...openssl, - descr: 'returns false if s >= n', - sig: ethers.toBeHex(ethers.toBigInt(openssl.sig) + ethers.toBigInt(openssl.mod)), - result: false, - }; - - for (const { descr, data, sig, exp, mod, result } of [openssl, rfc4055, shortN, differentLength, sTooLarge]) { - it(descr, async function () { - expect(await this.mock.$pkcs1Sha256(bytes(data), sig, exp, mod)).to.equal(result); - }); - } - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SigVer15_186-3.rsp b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SigVer15_186-3.rsp deleted file mode 100644 index 275be61..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SigVer15_186-3.rsp +++ /dev/null @@ -1,3850 +0,0 @@ -# CAVS 11.0 -# "SigVer PKCS#1 Ver 1.5" information -# Mod sizes selected: 1024 1536 2048 3072 4096 -# SHA Algorithm selected:SHA1 SHA224 SHA256 SHA384 SHA512 -# Generated on Wed Mar 02 00:13:02 2011 - -[mod = 1024] - -n = a8d68acd413c5e195d5ef04e1b4faaf242365cb450196755e92e1215ba59802aafbadbf2564dd550956abb54f8b1c917844e5f36195d1088c600e07cada5c080ede679f50b3de32cf4026e514542495c54b1903768791aae9e36f082cd38e941ada89baecada61ab0dd37ad536bcb0a0946271594836e92ab5517301d45176b5 - -p = c107a2fe924b76e206cb9bc4af2ab7008547c00846bf6d0680b3eac3ebcbd0c7fd7a54c2b9899b08f80cde1d3691eaaa2816b1eb11822d6be7beaf4e30977c49 -q = dfea984ce4307eafc0d140c2bb82861e5dbac4f8567cbc981d70440dd639492079031486315e305eb83e591c4a2e96064966f7c894c3ca351925b5ce82d8ef0d - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f -S = a3877b854832d6a6dec749a908e8bd3a73b24372e80321ed01c19ce066117d8efe78ef7168af8acd139e47dd262c0c92ed1701cf6c07e0c1140f82040167f55bb5180c18ad9e66a18dacf0742c1f05173129ed5ac523faeeb2119639cd30ae5a435884b55043d4fb7fa9af0dd92c365386044c2e8bcd196b3787bfede47fff37 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead -S = a5aa479d792448cc3e2ddfbe444017eea54efca7101651f4616f0260c7a48a364fe459abf98352e86b0b3d1478208687dffde1380d4462fce68cd61895401c3791186f17f159b91c02b5c0a30e894e142657b7537e84d2574837256da6940aa14cded7fbcba24b9e12ed2bb7e3f6db69b5a02807b57c9aa10ad9c0e1bde9443a -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = 9edf5246ae1d8fe800bc2ed422e6441cedde94c85a870277972a4b4a5a74f4fd76be8057ac92e6c5c36a4242dabacb79fe31052ef83c38da68cd2095185ae6398a284fc5d3c934fface4325ec734a2265fd3cbd513b957bef47f04f4dd699c6903a42757cccc5fdfe5b264f18f5bb16b394c4f855404486c63cb5f2d51aafed5 -S = 9a2e5b3ce63cb8df79f3cb25cce6964527e38592c58ba8b7b9312da25c62940985e93e62689f34b60cd019d3d472c0b72fcf2666bfcf8c13407e2150a138caaabaa409e6fd1ea55faf9180f7b41ed53d47c4dcdc3c669928d8a1c161f91918593dc3be3892c8df763d1a5ee6bcd5801866683005d89a2fd6ed3bef581833d922 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = d73829497cddbe41b705faac50e7899fdb5a38bf3a459e536357029e64f8796ba47f4fe96ba5a8b9a4396746e2164f55a25368ddd0b9a5188c7ac3da2d1f742286c3bdee697f9d546a25efcfe53191d743fcc6b47833d993d08804daeca78fb9076c3c017f53e33a90305af06220974d46bf19ed3c9b84edbae98b45a8771258 -S = 175015bda50abe0fa7d39a8353885ca01be3a7e7fcc55045744111362ee1914473a48dc537d956294b9e20a1ef661d58537acdc8de908fa050630fcc272e6d001045e6fdeed2d10531c8603334c2e8db39e73e6d9665ee1343f9e4198302d2201b44e8e8d06b3ef49cee6197582163a8490089ca654c0012fce1ba6511089750 -SaltVal = 00 -Result = P - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = a4397d9ab677aaa13a68a09de9ae0ed4045d479aa0ff3a7242dca477ab7884faf55cd06ddf19667f668b4589955bfd299dc7642c28a68bb2eba6f08c7ad9f5e96170913270c6463256a0537a72b32a04e5662416ecda74696d275a8bcfe999820ffc2ab210833201332f323828be7dac04c1f01f93a3dde1efe7483a51b1560d -S = 417aa0531b1da975066a1311a9bf2fa73f5daf90f0473a8937a27a9c6378c53012e0b4db3dcb5309b85a3e7f9db161848465f2e8102f75d171b4dc5371c3dca0bd70626dff5fad68549477fea84db9ac1b405440e178f5d9f74f3935e78a6aaf774b86d509fb25bd1a93aac9a2cdbce6a897842ea3ae07d3c8b4c43f97e0bf75 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a05000414dd1e335f65b2f5e31562a2c74ea6eab09892febcefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = e4690fb08396a8bf07377778a447dbd14c771024bd2353cbbd8446eda42795971c9eda0f2575be655c68614a7cd2fd252569c664dc291410548ec3a5eb06da2078a66c59441cbc9356e5a452f4c0386d6662a663fd6b61f254997ee6d63b5e3080e98d37e873ea737f17083713f7d5ce98ca79ca27d18199470c3d596caf66ed -S = 56b25cc46a9ef9607f4f0f553265996e22a4552fc6cb2752d0595e887afad29f7f9a390c17dc427c7d9f83f19f6986c60ec6d8f8017c3419cc2a838fe2425c7c80ceebfa1a0a3de507b5601609fe54b871efde685d23e546d69fbd14a30ebc2e67ac99446ae4978f1b3c120103294318b253aa9fcee638907b84ac72b25e18fa -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a050004148031ffbcbd668626dcc49e40128d8abdab1e8172 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f -S = 30db68c610b9086e9c6273da708ff8a89d73dfba6e2564aec908292af3a52b84ddd28bbb7c4a39df02f6e992be0d9aa8edb320a6e5a0a001ad097e7b8d09a87f50d55e1d68f47d2215a892221e7e33ddfe181b58fb12c8703e60cf0248c62af8a99111befd96b45ed4cf441a0623b013b94d3dd0976f6b5db7ae595069f21ea5 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead -S = 8ed880d91764fdadb04470e04509c6b800fe2bdb1cdb17071f855b8e38b3075c3b8a6991a34ab869127f47a753d7610c79e86a7a288b653326e31d90f4d043f52b7656b6831f6806119df6309a7846b05cb2630c28f7464a7b96e4e8ce76e9cd45502bd5e928f268763fea50271d29b7527097c51ebc2b2a3a83cf22e6b7e3fa -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = 9edf5246ae1d8fe800bc2ed422e6441cedde94c85a870277972a4b4a5a74f4fd76be8057ac92e6c5c36a4242dabacb79fe31052ef83c38da68cd2095185ae6398a284fc5d3c934fface4325ec734a2265fd3cbd513b957bef47f04f4dd699c6903a42757cccc5fdfe5b264f18f5bb16b394c4f855404486c63cb5f2d51aafed5 -S = 4a1716c989580f11bad633a8566b0f44ea689d8bc27c489bbf1a01d76bfa08ce87cace576ade53a5399addee803666fa1d99fa3739c556ae513baa10415e3db820e45f7518e15c7b1875f18f3835792e7ffaed1e7cf9c592afd660d2dda77e00f8f6cf298978929ca017cfce2675afaceca959810a4a33666be9a9a1b2f6523e -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = d73829497cddbe41b705faac50e7899fdb5a38bf3a459e536357029e64f8796ba47f4fe96ba5a8b9a4396746e2164f55a25368ddd0b9a5188c7ac3da2d1f742286c3bdee697f9d546a25efcfe53191d743fcc6b47833d993d08804daeca78fb9076c3c017f53e33a90305af06220974d46bf19ed3c9b84edbae98b45a8771258 -S = 57677b089e205486df4f56755972e3af88cabbc23efe29439b8d1e60ac226e990da487857392856d12cdcea387a269d1bbbc128549a1135ab062201cab8ac08886a313af8554506d7a93855b843086a1bf3dfbcb004ccde779c084ffa1724b41d17e10c8dd67dc0df26200376550eda14455d9b0b31f1d8c5e8bb1d3d963d0d5 -SaltVal = 00 -Result = P - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = a4397d9ab677aaa13a68a09de9ae0ed4045d479aa0ff3a7242dca477ab7884faf55cd06ddf19667f668b4589955bfd299dc7642c28a68bb2eba6f08c7ad9f5e96170913270c6463256a0537a72b32a04e5662416ecda74696d275a8bcfe999820ffc2ab210833201332f323828be7dac04c1f01f93a3dde1efe7483a51b1560d -S = 9b2222986b3f97dbdfd7aafd35fba51df5a7b76c88237e7454f2561b542289b424c76ba934e30b00e7726116ddadc359d6ad8b7ed7c16533c5661f2a61c45ec2e590e058663a740c0842e036d59f223d3c87a8127d40024ae205e46e3cd0fa323e01668da8bd723cc17e539a028a5ea69cb1fd9150db571a451ada2d81e05377 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c472fcfddd47f6ba3bb9eb166c248320d9b39fb4b2f70b65a85615244efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = e4690fb08396a8bf07377778a447dbd14c771024bd2353cbbd8446eda42795971c9eda0f2575be655c68614a7cd2fd252569c664dc291410548ec3a5eb06da2078a66c59441cbc9356e5a452f4c0386d6662a663fd6b61f254997ee6d63b5e3080e98d37e873ea737f17083713f7d5ce98ca79ca27d18199470c3d596caf66ed -S = 7016e23d4fc070a479f4a9c173de8f1dc3a54183ab44af9e3cfda7a229bed269712f5697fdd485f03ea21183f563ee0b5a91d3478c5cc94cf6fb56c0102a7098cbe06a8a5ae6a0eef7722ef9514c80e5944c8b1412b1411d56c7b674650eafca7433ac8b9266363a049f3be30885e30fee049e50ddd76816db309ed59f9b469b -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041ca73d80b7f5f188724498120a21df3683351f77de5eb916058f9769d8 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f -S = 10ecd0085694f8db6ea62dab2f239d8a93fcf449102f1368c67de329d79692b677500f55994c9722e2633063fc7d8c2c50ae8857d45c08bfaba9448dda0689c2a08605d47a7694beaacbdad1a954458a87fd78b6519393013b20996d636b755323b4b2b2b6d06a46c9221cd200462428ab5bef0f9743e144191f6928562627a7 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead -S = 488d328861653ab0a769a11a158ec7b479b62db5b253eda899beae580afb9a7c762030262b8a066f085185475e17870700504d3f78fcc4bcb95a3c1648796a323613a7b706cb64b048c68c06b396aac20b52f22f3fdce40992fb9a5ef68b5725134d83035a6f091d01aa5947175885822b2d4618c3f3fdbfd8819847fe40112b -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = 9edf5246ae1d8fe800bc2ed422e6441cedde94c85a870277972a4b4a5a74f4fd76be8057ac92e6c5c36a4242dabacb79fe31052ef83c38da68cd2095185ae6398a284fc5d3c934fface4325ec734a2265fd3cbd513b957bef47f04f4dd699c6903a42757cccc5fdfe5b264f18f5bb16b394c4f855404486c63cb5f2d51aafed5 -S = 7c547b350710337c783e7406935fb8ac7bcd1cdd4a7bcaeb63422067d1239f9f59fc29b51993a29d6ac8dcc7980871bbba1be8f0b6ce951a9e0cad64b37d7d0c3734e038efcd4e3499c8855f7c52ea3323ba4876ba9d78a98e7e5cf72b4b7444228dd0d81283e59055873450b8bc411d1cb970efda5cf5947a1d1f17e92a4639 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = d73829497cddbe41b705faac50e7899fdb5a38bf3a459e536357029e64f8796ba47f4fe96ba5a8b9a4396746e2164f55a25368ddd0b9a5188c7ac3da2d1f742286c3bdee697f9d546a25efcfe53191d743fcc6b47833d993d08804daeca78fb9076c3c017f53e33a90305af06220974d46bf19ed3c9b84edbae98b45a8771258 -S = 0b20e5093c2a926233108afbdd851b88eeb554f4beaa7b18e51519f7d0ec53b181a3b03e8484ba8de2aa7864a402e2208e84ec9914af9d776ed13c48bdeb6484254de169318a87c40f2265ff16714eae8aee2bc9c3cb4dee045e4f5d9d625210121bfcf2bed8d3ffa602ce27fff4e61cf9bb650e71a6921ae6ffa296cb11bdbb -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = a4397d9ab677aaa13a68a09de9ae0ed4045d479aa0ff3a7242dca477ab7884faf55cd06ddf19667f668b4589955bfd299dc7642c28a68bb2eba6f08c7ad9f5e96170913270c6463256a0537a72b32a04e5662416ecda74696d275a8bcfe999820ffc2ab210833201332f323828be7dac04c1f01f93a3dde1efe7483a51b1560d -S = 9313380722659eeccf8be943fbf514e90fb19657dfb410a50bdfc0cfb058a58e56bbae71ea1a30ecee08ca5d31a2d0bcd3f5a967a3794259c03635ee24cf2a15303ddb5962ae9747d72e83f630580600ba64d24bc4014c5d44640b2369b45fb09c2ba20721e0ae27d1a32546afa1bd023aa61079cea65389f55c31cfedb460b3 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420fa98b3853b928263002bcb39b454ea21f3f62bcaf6bc2b616490b7a7160120d7efefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = e4690fb08396a8bf07377778a447dbd14c771024bd2353cbbd8446eda42795971c9eda0f2575be655c68614a7cd2fd252569c664dc291410548ec3a5eb06da2078a66c59441cbc9356e5a452f4c0386d6662a663fd6b61f254997ee6d63b5e3080e98d37e873ea737f17083713f7d5ce98ca79ca27d18199470c3d596caf66ed -S = 477a7d6ff281bee7d56ac9cdc7f041b7497483f07a3cea5667ff178233219f75da7b88d9fc854a22ef541af3a5be8fb30b4e50bcb6d130e11f6c18eadec5d10f9895d654c0947aad152ba395c1039d7a8ff41b829179984a513f1abeb5a748bf248af1ea0152093d9fafb5d18e4cf91bd3b57ddd18b6984d976e6bef58cb30ec -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d06096086480165030402010500042034c9d0b0b487446c903244e640affe835096c7ada2e4295090bd9386884df006 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f -S = 5ad712eea6e12cf093b8aaa41bd972bd92ea43442dfae0671b27b80d821fdf8a83b032b870e2aa618430ab207ccb1c86bc5e74ea44a0f1ba2cfa2fca003e8547eedc4fd748e7718a9dc39c032b9bb997b4c01f49e441ddcb134d9b2c28a3dcbf126de439f07cb58aece617573797d939957083e51fe5eec00deaae17c41f59ed -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead -S = 1f00ccb2e22d0355b20b79b3d3c2416c03d281673fa3314aeec0cb41373e9a8ad5441e93545b6ceb9d3b8d660709cc2b8cff61924768fcf5b0d0ac771a395c02797123f503866d2aee5bb03c651091388486f63793bd714485ead5e03b92c9d80668c2088866b14361d2eb5eb838f903994d84471d5a352366eff2c5cbdf1ab6 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = 9edf5246ae1d8fe800bc2ed422e6441cedde94c85a870277972a4b4a5a74f4fd76be8057ac92e6c5c36a4242dabacb79fe31052ef83c38da68cd2095185ae6398a284fc5d3c934fface4325ec734a2265fd3cbd513b957bef47f04f4dd699c6903a42757cccc5fdfe5b264f18f5bb16b394c4f855404486c63cb5f2d51aafed5 -S = 52edcc1c2bd6eecfda613f0ed8cc8ed5d0f0b881b5a05eca36d9fbb3d04a9f36f0fa916008d13ae8b17b8f6d97ac4450d892b2731f14a477032cd353b8c054d53a3b2932124fd8d1bac88b44e4fd6f37b8ec3575b290fad24a262011b45f7e9b96b09324901f1d153921e13f7246ffdce405018c20975dcd28a7fe55689bdd9f -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = d73829497cddbe41b705faac50e7899fdb5a38bf3a459e536357029e64f8796ba47f4fe96ba5a8b9a4396746e2164f55a25368ddd0b9a5188c7ac3da2d1f742286c3bdee697f9d546a25efcfe53191d743fcc6b47833d993d08804daeca78fb9076c3c017f53e33a90305af06220974d46bf19ed3c9b84edbae98b45a8771258 -S = 7e3ccb6ab03b419a3e54f81337a3c3f72e8c65bbd19ddd50246a36f51f58741ec245d2d0f07677a4f88aa3b1caeecdffe5fd6edcf8b8bcfb569637ad02eb154d17b87a8f00d0e618a7f4a70ce407f20359153e5f4a4d9744f3f3ff44120c08a460500f030fd3398e97fcaef9d0a7e2acef19a81f706805be5fc003d78e5b29c0 -SaltVal = 00 -Result = P - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = a4397d9ab677aaa13a68a09de9ae0ed4045d479aa0ff3a7242dca477ab7884faf55cd06ddf19667f668b4589955bfd299dc7642c28a68bb2eba6f08c7ad9f5e96170913270c6463256a0537a72b32a04e5662416ecda74696d275a8bcfe999820ffc2ab210833201332f323828be7dac04c1f01f93a3dde1efe7483a51b1560d -S = 1077cf5852f21c7986f30bc2bb382138e93c0670315a83799047e122b7804cb8cdc892f23c8297b8315c16c351f0c6138cecb630a51b8a0980eeb59d575b3d86c52ae9270c6f444143d22ad6a1eea05a886281c9d7c93f0d3ab2528bb72e99b2afbf74f04038c3e17743e286a409304e4c19d441a68142b0d7b3c0a6da5532bd -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d0609608648016503040202050004301cdb4de69f4d84845bef51cd666020a895fbea98f2f61c9554ebdcffa525877093cbc9a4b1b8efeb77980d73ca54de17efef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = e4690fb08396a8bf07377778a447dbd14c771024bd2353cbbd8446eda42795971c9eda0f2575be655c68614a7cd2fd252569c664dc291410548ec3a5eb06da2078a66c59441cbc9356e5a452f4c0386d6662a663fd6b61f254997ee6d63b5e3080e98d37e873ea737f17083713f7d5ce98ca79ca27d18199470c3d596caf66ed -S = 63c488bdf2f7de4cd048c535b481a4cc2898e3810eda0038b2283bfe9b3f2beba2a74268639ecfc05170d1af534ced5d3b4941d1aad317875e05d6a19f734625721ed1f262faf995feb1acb44ba76beaec957aa8023429865717d0abfc553cb67474034344ceb8c5d4bddff7fa230ac620e5e665006dffb1c4cc7995c73841f9 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430cf563bb8f42149df04c9bf20652986e8888907d2ff11f086bb1b6152abd4e945ad82dda241cfbf511a88b36a5a450dcc -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f -S = 48db9934d51e8c2e234d70ff665bf2de4fef620e23f27550254a0b4b18338e299c024c4ffc5a502945e9f2e091a86ff6e7f44059f1ca58b4a18bc15931ae1176a9775247039e57d4e322f3d77fed6c6e9bec26b066fe565384c42d2ac79dd8312c8e09d3a2bf85fba0648a02f0e958d4711396e42362c5558eb7227b12aa94d7 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead -S = 125b4dddf5e18c8de2f7b72faa76f1d03dd88aac3c76ebc037b4b1aa1435eda6bef2c948e2ba51e763b8572f4ecef228ca38c10299add6f3f67c171a8fd56e33a1c287c49f844e4e98b20f0fe727b58515e5e7d3846c029afe08d25a9edf0dda6677b1cb2ca6be67763171f114932c43f53af126d0aab6dcb52d5b320b385c6d -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = 9edf5246ae1d8fe800bc2ed422e6441cedde94c85a870277972a4b4a5a74f4fd76be8057ac92e6c5c36a4242dabacb79fe31052ef83c38da68cd2095185ae6398a284fc5d3c934fface4325ec734a2265fd3cbd513b957bef47f04f4dd699c6903a42757cccc5fdfe5b264f18f5bb16b394c4f855404486c63cb5f2d51aafed5 -S = 70a4fc2afc2524ec159aaaac0cf5242e276057c3ebaee9c3c430aa862ac5758aa3a55f6f6ebbb25bc5229e51c976949314244efb35d89d4516845e41f9cb9c4db78d381eb35f257d3b9981eac9e27cd9d18a56a6dceceebb77523255684ad6ff58622889e08a616acafca687e2742074d0f7431ff5ca4324c4d25b44af9fd2aa -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = d73829497cddbe41b705faac50e7899fdb5a38bf3a459e536357029e64f8796ba47f4fe96ba5a8b9a4396746e2164f55a25368ddd0b9a5188c7ac3da2d1f742286c3bdee697f9d546a25efcfe53191d743fcc6b47833d993d08804daeca78fb9076c3c017f53e33a90305af06220974d46bf19ed3c9b84edbae98b45a8771258 -S = 8b57a6f91606ba4813b83536581eb15d72875dcbb0a514b4c03b6df8f202fa8556e4002122bedaf26eaa107ece4860752379ec8baa64f40098be92a4214b69e98b24ae1cc4d2f457cff4f405a82ef94c5f8dfaadd3078d7a9224887db86c3218bf53c9779ed09895b2cfb84f1fad2e5b1f8e4b209c5785b9ce332cd41356c171 -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = a4397d9ab677aaa13a68a09de9ae0ed4045d479aa0ff3a7242dca477ab7884faf55cd06ddf19667f668b4589955bfd299dc7642c28a68bb2eba6f08c7ad9f5e96170913270c6463256a0537a72b32a04e5662416ecda74696d275a8bcfe999820ffc2ab210833201332f323828be7dac04c1f01f93a3dde1efe7483a51b1560d -S = 8e0fecaaf7911ccadb8ca5b6ae3bb89580cbda49d3181d5aab4f03431c62aedb4affc58b87c4b3c4ee09f7908f34f52e2901891382b57cd78d3a824fe446eef4ef46b2afb0d34e6cd9a263c21db8c9c2cdcd5e60eaac571d67410c7136180ddd6195ff2a0691746e457da69bd1667a56b1980a22d5f0b3595af0e8c3bf97c2d6 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d0609608648016503040203050004406bb51b0f43cc58788c9d60f71e06fc473949ae313b3354033526cdfac71690c584f916b1a8eeb47f17f339b6cccc3fb3a53786d418295c1e454db8cb17cb7de6efefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1c23c1cce034ba598f8fd2b7af37f1d30b090f7362aee68e5187adae49b9955c729f24a863b7a38d6e3c748e2972f6d940b7ba89043a2d6c2100256a1cf0f56a8cd35fc6ee205244876642f6f9c3820a3d9d2c8921df7d82aaadcaf2d7334d398931ddbba553190b3a416099f3aa07fd5b26214645a828419e122cfb857ad73b -Msg = e4690fb08396a8bf07377778a447dbd14c771024bd2353cbbd8446eda42795971c9eda0f2575be655c68614a7cd2fd252569c664dc291410548ec3a5eb06da2078a66c59441cbc9356e5a452f4c0386d6662a663fd6b61f254997ee6d63b5e3080e98d37e873ea737f17083713f7d5ce98ca79ca27d18199470c3d596caf66ed -S = 9572ebe453e2f17dd72921b38a27c28c68f4605aedf6b4a7d54079e3ceb2811ccaa6dbc0d71d47d93cd1f18cfb028744fe3d8971b0e9712f29ccab4152e2635dff3b9a1e9cb8f462b138b00c4c0a1163739286b50ac232da5075a9ba3c02a3f604d4629a7df516b39c8d01cb5019f9630436c70415c6b16d79bb29f3a46b72d6 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d060960864801650304020305000440605b7b97abce7dee5f9b9ebf2ebe35d7e474e62b3a6e86b108cbfe3c3a8300bd11deb0210048f502b7af1c9dcb1805f1d61e8df038359729a4bb33774b9d13aa -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -n = a8d68acd413c5e195d5ef04e1b4faaf242365cb450196755e92e1215ba59802aafbadbf2564dd550956abb54f8b1c917844e5f36195d1088c600e07cada5c080ede679f50b3de32cf4026e514542495c54b1903768791aae9e36f082cd38e941ada89baecada61ab0dd37ad536bcb0a0946271594836e92ab5517301d45176b5 - -p = c107a2fe924b76e206cb9bc4af2ab7008547c00846bf6d0680b3eac3ebcbd0c7fd7a54c2b9899b08f80cde1d3691eaaa2816b1eb11822d6be7beaf4e30977c49 - -q = dfea984ce4307eafc0d140c2bb82861e5dbac4f8567cbc981d70440dd639492079031486315e305eb83e591c4a2e96064966f7c894c3ca351925b5ce82d8ef0d - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f -S = 3c9db203bbb31c7a3498b3b35ec2ea818614f3a17cad8308f834c6945305e3b94f9886c00098640cb56cefbf06a9ebb7a8c28af610c49896dae53303fb716bc3d2ebf95205944f845658732e8a7ee032472942292f82ba24a66094c7c3b417f5e678a19c04e3b54ba5f0f03610c56d31b9726ee0e39cb1708d89fa61ba9a039b -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead -S = 6592c64db5ce133e1c7d499bf7ea4d0203897186b4319fc5e29522d97b9af212fd5a10a8c15246a46d0382cc61c9bfe2b211871d7dfa4eff9a6fa15426309844fa72b1de7aba231c66076185014b9f9e9fadbc2a739ee95c48da75fbfc7d05c22e7896db47407e8d78f0d28519c7fcb6c868b05016bcf73075477a92e97625bc -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 9edf5246ae1d8fe800bc2ed422e6441cedde94c85a870277972a4b4a5a74f4fd76be8057ac92e6c5c36a4242dabacb79fe31052ef83c38da68cd2095185ae6398a284fc5d3c934fface4325ec734a2265fd3cbd513b957bef47f04f4dd699c6903a42757cccc5fdfe5b264f18f5bb16b394c4f855404486c63cb5f2d51aafed5 -S = 6c80cc0f17783b39712a994f16a461830c26ba3f3afd1a277cda564c8a8b41c4ab444bb6f79df1d109f781de3e6e81d2a0aa2b6ff566e065b3125a6bebd36039aaab46e38a3fb36f66e665372f0cbe15a696d00cd79922bce7e6771ac59fa0c4576f28eeffca9177bdfb0804d2f883b929f58d4ea948df8bb3c283fa337d5665 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 4ff6c9e7f9f03abd3e114a788fd51318feda52b6509c1b685483cb6574213f6a8ab4435cf5f34d2eeb076c0510d77b9a48889ae0ca44dfe8773b480169e8f423ce96938ef7221caeac02be42c38618bdf15eacecdf5d91da807d69f1a3229361c4a3a2c628060d05290b2776ce6d52499e647022b66e9b071a4f167c495683ec -S = 6466b9759635fbb2a3e8cb7d2a6192ea7da6033b76dd578b76ca468fcb9215f8138966f9aaa3e82246d15bb271a269eda087e63812406407ca12cb085ae82ceebcf28eb44f6608549fbf6383882c864688665a1b5a2d748496b36f8b935f676339fc61e9bc0c3a5a58141226f300cf29c4371047d530a4776809f572b88ecdfe -SaltVal = 00 -Result = P - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 85624c37ee13b3d8cb80a5961a39c5953caf10f1b4e9c00a2c78701fb8ac821f5f08bebbd8f43bc091b283a4f693f25eef6b5f7baa42ff6f9c4c8529c21c8eea2d143d56bd2022cc2da461f34fb210959981e0b1e11a00cb65553e870e047076f66e123027ff30a3a63d87aab0fee7e243d8dbb9e0da8cc79079e36225cdee6c -S = 705a07d366f2326ced17374d5f599d483ccf184d5fbbc288face464b64c058e6583b8ba664f979f3a6c1b0755b1e2cfe8154c39176d432f59af5714bcf9b0af8da122af77f0393385613393d43db7902eb1b81fc9dc6604692e0f85d30ec59fdc521cd35e5aeef006a6b919bdf47bc9a468daf3e86b3e4956ff736bbc25c9ed1 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a050004143dee53379c3e2d8c26a41c9f63be60b1993097d7efefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 263da806fe0a7a242843f295893fd891cd13c0ecc1648c90fc79322bc594bf2531839cd58c7210f4fa0307525ea112c77b11ae6d5a49c90ceb8682d6ee9931551481a7a1623fb7d6d7e6f5c54ef2bdeaa6da779f1fe91a8e0749ef6c976198e5186150d2491a74b20514435821dae2e19499a2e9dae986ff9aeb00558694fcbc -S = 727d32d7faa37ab2dac96e9f822be4dfe60459ab7aa18a26cecf6c84bfa7fac7261c86f89ca84356ee20fa9e8a8a9a2b5f5e624cc4269aa8583fb148777091ecab8929e3f8a628c8f6e1b3a48ff1f60ce1b40f279439bf8eadc6c1b977b51e8ec3c65cb8db9fdb956b514d28381260b9f6b02b2d065ef57770952d968bed65b8 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414eaf16b6fc483cd5d255ffe76f761420c4df301e6 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f -S = 64c3e9ef2af3501ed929ec204d43848d42f3393e437b4267c70d87fc5296ebd752739088529c16e2f6f0aa87e1bc6843779dac3af54f90d3334d4b65b6b0adaf91b6fa8a75826a30f50177f887e705fb64a9258f131dc958bff8134bd68206b9d3a6fa70b2c7de5308269a6c33716916c37810aa69ce3e81db88674a07fe55e1 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead -S = 6c9e4455899b0ede371ddb6fe074217d330fe0e27537b0f06ea2e24c75ed6017594ead552296da15f11e6e6923639d95fb73e98d5160e80754ec12f4a06660c6e27eb4de4fbcfbeb37176ef5281a190249e34276a2d736e622c8151f3d5b838e450383edc986cee6b00a1d4cd5a7de8fc8629b6557a3becad84cff5c6c51f2a8 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 9edf5246ae1d8fe800bc2ed422e6441cedde94c85a870277972a4b4a5a74f4fd76be8057ac92e6c5c36a4242dabacb79fe31052ef83c38da68cd2095185ae6398a284fc5d3c934fface4325ec734a2265fd3cbd513b957bef47f04f4dd699c6903a42757cccc5fdfe5b264f18f5bb16b394c4f855404486c63cb5f2d51aafed5 -S = 9b689f488edb16d4aa3192af3760977401dd066d319d4c5dacff4dbe8aab9aa5790f39bc2378d0c8f52f286fc1cabb743bf6aabffacf5ffe4186054d0b121a2e6559806886759398e7d30781380aead8af992485e2bd582208dcf69ae8e7124b1571cdfb7db87cd565f293cb8d26a8d005508a3332d4ec27d44a1423402e6d8c -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 4ff6c9e7f9f03abd3e114a788fd51318feda52b6509c1b685483cb6574213f6a8ab4435cf5f34d2eeb076c0510d77b9a48889ae0ca44dfe8773b480169e8f423ce96938ef7221caeac02be42c38618bdf15eacecdf5d91da807d69f1a3229361c4a3a2c628060d05290b2776ce6d52499e647022b66e9b071a4f167c495683ec -S = 86ff99daaee2a3c866a71f7f6fb391b9b31a3cbcf525321087a6b253e42a7b5fa386ba3907751933cd153431507b78486d5d43dd35779962fbc9babc487afc696b0140ade1456fc5b23ce5c7c97019247e827cc7032c7e101b68eb4bfb003ba107f042b92ff697789fe43018d28794c7aa8a70a5386e891e3456a5e52990853b -SaltVal = 00 -Result = P - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 85624c37ee13b3d8cb80a5961a39c5953caf10f1b4e9c00a2c78701fb8ac821f5f08bebbd8f43bc091b283a4f693f25eef6b5f7baa42ff6f9c4c8529c21c8eea2d143d56bd2022cc2da461f34fb210959981e0b1e11a00cb65553e870e047076f66e123027ff30a3a63d87aab0fee7e243d8dbb9e0da8cc79079e36225cdee6c -S = 1f4e56f13d4167951a716dc8340c006715a4b9340a1bbcfcbb7befd70e15723d81ee5152c42967ac479b3a4ceaf1527b9379daeb245c423a21bf35826dc0f6b90a4caa579d962023e12e2eda516484ddc9483b91c7853d03a1854536d1e6fdfb9217223d2d9132a56d411183fc30de2463c4d5bea4429e7599dc9c4dd2b96b89 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041cc53cbccde35eed66e504f5ae6ecf78ba8f83abd4b67822b40e121f99efefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 263da806fe0a7a242843f295893fd891cd13c0ecc1648c90fc79322bc594bf2531839cd58c7210f4fa0307525ea112c77b11ae6d5a49c90ceb8682d6ee9931551481a7a1623fb7d6d7e6f5c54ef2bdeaa6da779f1fe91a8e0749ef6c976198e5186150d2491a74b20514435821dae2e19499a2e9dae986ff9aeb00558694fcbc -S = 002e26f1d72dcaaf2935f4177601e7b55da3ba0769372a2326d4e621449deecf84c2b3b2998da662907d167a6e7dd0b63116acd7c98d3e086da986ce126568aa31ffa136efaab815ccb9e8059a1e2bf1393dfe8567b73c8191d5acb8560a69514495a33362e05b94c3e260e181603a5d5d9a589c21c5b18effbbf016cd493276 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041cd8eee327931d42ecd0654f1da8d551ebc5ca117b9a9bee9d28049ac5 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = ff23e00f819bae424e41d6b762ea6b88801e651c831c964af31de0c1d6dda4a7c8587d804ed12f526819da06650e7412fb627555979ed442f2663341e5fe57527e0ddaf453a124451674976a6a6e0a31f56a79f5b73dfac39af4f3ba4a5e8bb846cb5e333812756482d975ab1910162f96bfd7c58a02f113125189f5ac05291f -S = 8b5a3675f397841c53a9021dad71a1efab91451c71ad7060ce85d75b306d6403ba23d3370b0695be87485cf6680204c68424bc7e442ef90ac01c4df420ef574294823250a000d56a5d00947800dcb2f4947f5b4eb18fa1dbdc6ab16be4b7131102d4dff98ddeac38554473964d29cdc521ee690cde5a8cd16889aa090c32c53e -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = a6ce108ff3100b953781496c3d081fe32b8cedaf6d14aab2ef2dc37d8f8d2613d2f599efd55c51498749c0961681ae4ea7e28bf14a8f044c2d4dd4f9102ddd25f86c7795289708eb4df2d526f91b176952eb52fd0c9de2989432d6e08e13022b82f95089d20a5704f0452f26cd1f83bc956ee7da99876c1f8da3723af388bead -S = 750e59f29d2dfeedab2a3a09034904715957149126c63e6a2dc7a633a32c4c0561d54eeb1479cb65274bac37cac4751f4dffdfb7530171599b61d94862845f6cd12a5e0bd6adabc36f06d216a00b1942349710540555106aeb87f5cf3f78df918f36cf63291ef2a7064e31b84075d1c8b551225a25f59c721a3d77046078557f -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 9be28a4763c6665880c1c2a8a74494622be46de3c20e5b118cf70fee51d33b6d0b473e84a4200382004526a33eea59e13b07070e580937207ec7b2cc5fb76856fe6210a771150fa0e5da9baee4a6209ed3d4e2b3bfd2e5f6591b0ace3e657ad07c1b47d8520d5159386767f11fdfaf41fa3348fb7dd32d3c25da5d1d78433985 -S = 0ac6e41252383ee5d07f4fb08a22204f56440a8f3c8568d6e6bae46cfc9d39b65b2eae827164d716e9e465301d08fca7356ef447e0699feabbfac16ed19dc9233b457fe64d6fab38aca4464e5cd3eae3f43bab17856cdcc942e2cc848b7bf390fc53b3ed2e6f63c5d961bc83475ac200708f6e1d5be30cbe24fe4d3dad754269 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = f56379c42e3ba856585ca28f7fb768f65d273a5fc546156142857b0afb7c72d2d97ecfceec71b4260bdc58c9bb42065f53af69805d9006233ec70a591aff463bf23d78200fb8cc14a4eba286afe8924120efad9e3d3f06f7452c725e53728b8f86c9fb245fbaf7086ab0092e215213830d1091212efc1ec59ddc3a83707d4ab8 -S = 5f49d8dc4519d9520d6542eca08cafb2d99cdb97c5a8685df2476b40505a2f9e8d63d76516b83481e2d961a7e8dc5f9f46887e394776711b0f85e4303065c06d362456bc219fc6eb343ede6733f779f75853533bc9ab876188da8ad98f9ea2f335d2ceec34ef9cb2782bb0f79cad309608ddc222e00ebcff9d14f6e6ed39638b -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 399b54f756514628f32ce8f1cf391d77047af55f3d43804923e5e09a188aa27f28604f2f3cfa3d7091f3ab5c69d40d650137a597c22d531dbbdeae074f6f534a2b297e087cd7d7125e6f8eac97f5a990859d9d3555301c5076b02f9c4d3f84d62b3d090c7cb1ba1841eab668c066990079f206c15d1383eb3ba58ae17bc2dc2c -S = a62e4b688bb3c4c2e11a3a0b1ef81ff4bbaa110c9b830d02bda2d364dadb2345a8c5dca58c611515f0c09732ee6a6642d5c5c339460a9d15022f48c36e9bc2fb8b2b0ff99005273287b8c3bed87993baf52f0e9d079281bc25a8694ed9692446127c26c34f21e610a84f3617247ecfb3b5337fe59d1239dfb7fdac8694dbef0b -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420be1f73a059cec568dcdfddf1daff4201e79273653f88ef8f16be7e9ee660335aefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = b8518b80a55b365eb1850e18f88da2941c99543c2f865df3d37d114d9fc764ffc5e2ae94f2d4ab6276bfc6bda5b6976a7dcfaa56897982880410dd5542af3ad34c469990cbec828327764842ef488f767c6b0c8cd1e08caec63438f2665517d195a4d4daf64bc2a70bd11d119eec93a060960245d162844c5f11a98cd26003e1 -S = 06317d3df0fa7ae350729ae2096b050dcec8909d36681ccca09a7a527b90767f8c2318c49e09483b48df77ddb632d6ca721155165389f7795d3ede70465678649399242aed6d984ca74fc6c2eb4dd4bb2cd7bf2125ec853f2bf757d665b29487bc5b63df0d0b03b18608d3d9a7576ea0954aef3d3303f7d8fd7e7f9725c114e2 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420a51c139e5ff91509eb0bd542bebfb9a4baa9399a5535d9168942298ce69c4f5b -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = d3787e2cd5eddc154a3b29c8a5161cb0ef6fa97d6b90c9d579677d46ba22108075fd9dc13958d290c40df3ae2400224a1cf8dd74c9adc8d48522ad9c0c34c1bbde732954e432bc6e55da0beddb849ec1f2c6815d91cc006a0dabaebd3af3ac87d38327cc1ca22317c54b776b12c7197c39829c1f0c17f700d7ad88938c86594d -S = 678507d9ebb2c5254ff371d3e41b435deb1118bf0b0121c1bb8a46575df101d12d771471b956f8c229b8021a9f08faa61e0577c6a715108874bf655576954a85fb63817b58298fe3d3643a748dcc635210d2b202e3b2e663c4a212ecbc7fdf5e34e8d499a20034d98732c09be015ea728d1cc831c61965f3e32a8aae958d43d7 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 31f8dd3024b0487ae1e3a7af9032ef7c76d5420d617771814747c09b2a4ce9ba3ef8630b4e01e3fd5c6c24f588ebe44433682f5663e2df2b6978640bc2c3c1763c69d75b59efe68af8cf516a32cba1ef8380cdc72a3eb9d4d217fcdf7136e68b7173c2870e245808ff35b677587b3066af45a6c97d340563c84d107eff4d61df -S = 8d26faa1cc87606514e47b7ab3d82768868a61d237cf18e75f935e20fc5925e2c667b05cbd09da878fd623430f71ecd1f632fff4d1d049ae704004c89012008e8856f61a03001b423f4f06eadb4a72eb946a7a4dc4469e995609801498bb7471a533ee0f422adc5d41b744301efd836e5cfcc496cfc6ee646ae2218e924f76f9 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = be9b41883cfadec3960d866fe8514f9821c6c7e65af6e5c167343fb8ac227e2432760f08fbfd1c3c92e0bbcbe5266599577aa949122e215d9a81a69fa81dc0c035e46040d5ecd28d46c8ed6f490a8da3b00543c7b9d84a769aa8bdb35d2c088bee6f9df673d1e8ffdb4f8424ba05af0054f1fb27f7fa47528f31eebc74563ecb -S = 735c47985ee75db358eb0d05624be43778a37d40ad1df88cfc5b4669906e290704265fb3a133df781dfdfaa082d21d0c431b54c0c6c239fb0c0b47e675c0def6d94a726ff8267c449f1300b21a7c7f171c76e869851f9be39546e274f60924ddeedd4f69b70d97293a10ebbb3df8f9c1fec31f7d3562150a357150fbc8ae5237 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = f8a2f38109c9b6d868c5b3481cd3478c8e0845fc3e36479cb50f4158bb8d5c8ec99101cdc1ca33ddddd823ffe5b1fe75a6440a459f5df13bfdc95d2dcabac482616d86f52509359772cb3313d46083367792d9afdf27f313d9062c24b29c4f52a67ea9829b50620f10e50d0e50a77dd7eb3adac1665cf52c3210d9c5dbfba305 -S = 9ebce94bb79d82fcd236874df4c2c3d1b56481ba15fc17a345f6d45297b6adb9e07c1b582e22ce0b1830763758827a77ca675c708163cbe7a5db72d2a95939b3cef60c632a19849e6d95bf6a867604eea7f69b506bcee7d04678d4252c715edf0a928ef4c1181177bff20c3a95215782cd6b70564cf1ec2ea25e6318ef1f96b5 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430940085d291d91da907231dd6d6e10d71011dc3e0944671e632bb0d87c0b8fa1bc2f1019caa64a8f6844a8db073b0743b -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 7e3c652fb2786a379614fc8f9f01555cf029cf61cf0af6c455a4e2156996c48cef84be923cbbf883cd18f0b3392611af658688c5f79453c60d479a0a2e5943b581a8c1393cdd2c1c604b97fca41a9ed0aea43e70891fea58547ddaa83790a7709c72152b9b242f89b5759a72c6252347354b9a6b6ef4e302920d4af86c831745 -S = 995e2522f280d28f9719663178429d6ffb26cfcfbcc15812e83821db1a5e2a31a8160574e4fe4f1f09ce67690c67fe89c11015ffbf5dd5ec669561f0a2b13c416992de570a532b805b00b8003f6c70d56925ff2bb5555daf3edef1da6bcb1c94d29bbb243119da64ef352d36ddd6ac472a99a1a22da809aa235b51afc8379619 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d060960864801650304020205000430cfd23d0f765da0ba39f284a77f62552300460944a69e6fddf7aaa731f62c6d822f5eb581075a23fd540aa7a920f7c3bbefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 2bd0f6349c6f8198a10ce8e761feb6d4d72bc71addcefc628a773367be537758fbad737e77b52d1e6f80f1a1bd518af2ad17b9280d36df65838afdfd24a9dedb4169932184a3200f3c367526f64ea08d4de640b3038b3d365063b604796f3bc0a50d3d67edc1c233b2345dbf337d5e6d5ea04605e7547e9e980a48c2e82af5cd -S = 38103ad73f8bb3a9c3e01e95b8cc45e982a64f17a318026e185d523dec851ef9fbd1b9c2694a4688925580bb50709ea624417a685b39b36e988d9b7b41282cb969379c3e739c0a98151db9181dfa58c5e6ffbaaa6971dd5171d9ebcf18ce346364f7601856aa68584ee3303e8a69d0dad778e4a4ba3ed4f8a009d561652d134e -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = d3787e2cd5eddc154a3b29c8a5161cb0ef6fa97d6b90c9d579677d46ba22108075fd9dc13958d290c40df3ae2400224a1cf8dd74c9adc8d48522ad9c0c34c1bbde732954e432bc6e55da0beddb849ec1f2c6815d91cc006a0dabaebd3af3ac87d38327cc1ca22317c54b776b12c7197c39829c1f0c17f700d7ad88938c86594d -S = 22754363656ce107c1beea8999cb4a95d267d6c6d3a06b42c939f51254f822cf49bd6d51e27af51afa0d260fb4bf6fcb8b4926270851d64f2fae6f4c6562c532e3fd72db5188c51eb57b01a871004b38d6a1bb4856fdd93573735a480b4c3e444262d198d54de6db409db7432dd45beabc34991cb6868e1e1dc62f8ef509f36e -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 31f8dd3024b0487ae1e3a7af9032ef7c76d5420d617771814747c09b2a4ce9ba3ef8630b4e01e3fd5c6c24f588ebe44433682f5663e2df2b6978640bc2c3c1763c69d75b59efe68af8cf516a32cba1ef8380cdc72a3eb9d4d217fcdf7136e68b7173c2870e245808ff35b677587b3066af45a6c97d340563c84d107eff4d61df -S = 92cd8a854b4b9842c12c7f9ec2dcfad57d1f403ce8276d355f436c1d9aaa720867dc5a96b91debceedf55eea2a33d99e586a0a59d68e9289ce6f001be3d9ae9887d9f169ecd77600ef60b97851bc8ad6c5566c830a25690a13a92bd082fdc0b356a6443fcae3d29c5e9818b06c69748149a3f34793a6c7b04da345caa01d6f20 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = be9b41883cfadec3960d866fe8514f9821c6c7e65af6e5c167343fb8ac227e2432760f08fbfd1c3c92e0bbcbe5266599577aa949122e215d9a81a69fa81dc0c035e46040d5ecd28d46c8ed6f490a8da3b00543c7b9d84a769aa8bdb35d2c088bee6f9df673d1e8ffdb4f8424ba05af0054f1fb27f7fa47528f31eebc74563ecb -S = 5d8ce84e9473178a2ab5373d3154e7d649b40a144040d4a612e9ae43666d681458b5d985f5bb1bd5709455f5421dcff12307e074714b6592f0095c0a67f66f950ac8e2cc7b8ffa5d8f89d407292ac659a4e479ee2cba19d6f31673edbecb3535b85b11edfcea4df17799418fdfda145711f5f9c0540f811ac92e05bea4460c87 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = f8a2f38109c9b6d868c5b3481cd3478c8e0845fc3e36479cb50f4158bb8d5c8ec99101cdc1ca33ddddd823ffe5b1fe75a6440a459f5df13bfdc95d2dcabac482616d86f52509359772cb3313d46083367792d9afdf27f313d9062c24b29c4f52a67ea9829b50620f10e50d0e50a77dd7eb3adac1665cf52c3210d9c5dbfba305 -S = 3c42cf56c04c1ddd18a5ec523df036428d09bb44a7b12be5bf6fdb3866a122a5cd0edb2cc81930c126a9244afcf6a27c8820369f474a06f8b7022ac8b95e35791a49d71a40ecd145e8d2e334b15f6ed698b7a646248ee73f567739469960c0da5112916a12f212d198a6f6c518b4745a578d265ab1c04438d7a38263a5a8c254 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d060960864801650304020305000440174762fdf1f011f716417beb00598a33aae32c141c664908178740f19833d9109154e89f80a1ff369930cb2dbeeba511433122236e0cf6df2d7b7202de550c6a -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 7e3c652fb2786a379614fc8f9f01555cf029cf61cf0af6c455a4e2156996c48cef84be923cbbf883cd18f0b3392611af658688c5f79453c60d479a0a2e5943b581a8c1393cdd2c1c604b97fca41a9ed0aea43e70891fea58547ddaa83790a7709c72152b9b242f89b5759a72c6252347354b9a6b6ef4e302920d4af86c831745 -S = a6825908039d9165b1f1d7e85de390819b3e13fb914521bde6370db313e0c37444bc1bca1d798a73e9602b3c61a67b6c3531c25a0528f4945ac7f27ed5848b782668cad8533000a42a0435de4436e4ee7fe0f9a347750543d921a313c6872cbcf5466ae41a69f32d03acff357cf3e4f1a3e7ed4575dc61bf4fb77a04b9d3cb32 -SaltVal = 00 -EM with hash moved = 0001ffffffffffff003051300d06096086480165030402030500044062eeafda47b660f230159a79e8b20ffc84752ef5ddc420ac6478511cc199f983ea3cb8cbeb9955c175ba5afce719ae601c6303a1f6cd5e0c241b5cfb8577deb6efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 252c4956ac328ba04789bfdc5e90819981a100f3b540069ba8719b8b3ba27980cc7c96710a75ec0da83c1ddf353b45845f3db7224cdecbe5653cebb01fb66305d42e617e8a51514c6d2fb6b3cbe3ad9478ab7acb575f854ec9c9576a70c63934921c39662b32b8c93fb660f64f50e5481892a8ef4b92a64774995f2a0fbd64b9 -Msg = 2bd0f6349c6f8198a10ce8e761feb6d4d72bc71addcefc628a773367be537758fbad737e77b52d1e6f80f1a1bd518af2ad17b9280d36df65838afdfd24a9dedb4169932184a3200f3c367526f64ea08d4de640b3038b3d365063b604796f3bc0a50d3d67edc1c233b2345dbf337d5e6d5ea04605e7547e9e980a48c2e82af5cd -S = a5c713d065e204f5a3d87e4752b235fa79a703931065aaf7ae4a29d641763d7ea4350d8d9a29b29b4fc770169ba7adf1cf7ba872769265cab2d41ee7e227e7682c749fbc5836debc02485eaca9637391c3793b3f05701f80a90cfcc04c091fa37628e4eebbefe5ceec0b4dee1b41241fb883252fe18ca65ab01e4a4e3f31ba36 -SaltVal = 00 -Result = P - -n = a8d68acd413c5e195d5ef04e1b4faaf242365cb450196755e92e1215ba59802aafbadbf2564dd550956abb54f8b1c917844e5f36195d1088c600e07cada5c080ede679f50b3de32cf4026e514542495c54b1903768791aae9e36f082cd38e941ada89baecada61ab0dd37ad536bcb0a0946271594836e92ab5517301d45176b5 - -p = c107a2fe924b76e206cb9bc4af2ab7008547c00846bf6d0680b3eac3ebcbd0c7fd7a54c2b9899b08f80cde1d3691eaaa2816b1eb11822d6be7beaf4e30977c49 - -q = dfea984ce4307eafc0d140c2bb82861e5dbac4f8567cbc981d70440dd639492079031486315e305eb83e591c4a2e96064966f7c894c3ca351925b5ce82d8ef0d - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = d3787e2cd5eddc154a3b29c8a5161cb0ef6fa97d6b90c9d579677d46ba22108075fd9dc13958d290c40df3ae2400224a1cf8dd74c9adc8d48522ad9c0c34c1bbde732954e432bc6e55da0beddb849ec1f2c6815d91cc006a0dabaebd3af3ac87d38327cc1ca22317c54b776b12c7197c39829c1f0c17f700d7ad88938c86594d -S = 4bae63c2b4ed42b92d95293ba755c0f3dbae5a13369b298147e3d7d9cf8629b7df9df22f13370239ef86c91a6b15efc5611057b375e948d554a95a7119f5663b0ba6c373121f2d4f6f9a8703a78153be3472f296254db218a22925546340dd0495ec68f354ed17ed4f9d85d4b9eb1b9d1816cc1422c852410841f166e69cc212 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = 31f8dd3024b0487ae1e3a7af9032ef7c76d5420d617771814747c09b2a4ce9ba3ef8630b4e01e3fd5c6c24f588ebe44433682f5663e2df2b6978640bc2c3c1763c69d75b59efe68af8cf516a32cba1ef8380cdc72a3eb9d4d217fcdf7136e68b7173c2870e245808ff35b677587b3066af45a6c97d340563c84d107eff4d61df -S = 8a8b25a74adf17dbc6ee3dba1982f94c17ecae57a75835cc4cd476a1afb23d01c964e8532a6d0afe71ebd8d26a2e5514906caae8b18ddd860ae16303723cbd0a155cca1a4a7be32c2396b1d09544057e7f7fdf6bf1bb2861ecc0f90223269add410dd66ea54a507a31b75528bb277ee9d3d3096d2e2f0f33b0509f27bd990b9c -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = eb2a75ef219b2bec0987c2623a76a8d3c292754519c47f8d541aa8cd9b6c7b3cdd3f7825c2e9ab33e2f684eb34cbe27ac98971b1ba34364e5f15687dc15c829e520a9649dc0ee48fb8aeab8340293ffa869b5c8e4720bae91a3ce140ed7b3f1db25478625653fd8bf378e03346dae7d9638fdfe5a7d032e6ef59bc1e070fdb40 -S = 0fd7069ca1e24f81f3c67b0bcba5fa72764655739d549a59288e6eaebf4d2f52c52eaa17e495ec2b2fcb52a4673aac2e48e2078688b8e5d8a91d7c8c4bae725070425a183e95b352999ab2b49adce63b6c9d48dc29e0649d91b73fb04c45786239b0022231e5e173e2f0d94fee7905706f39ec88fce30d107e4151d010be719b -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = f1cf2ba2463023a1d329957cf3fdc044ffecf8ce0a11f9b6ce8b7ba5e5db07d03d8d08c1c61b255a6d0ece174e661593253cc04e06a69cad4fdb1442da97014e77c1c484994c93104f5b10d876a820022e26fab68ae57e258c36c9ca501106ef87b38674278b14cc61578248d48b889800f2cf8ffd9748266ce6c2c4af0fbcbc -S = 2e305057388fc454647e2c20b71c3cc3383af683126b1b802b6e74096b46655df2715e18bbd1f9f7f4484dc63ea58bd7461c58d6e7ed63e885a2524b01eeea2b9d0cbe25e6f0f780fed9fc9610ea5b7de468b0cc409da4607a367b2815d346facdb6375a7723d013f2d8726e7b40a680b82c112324ab161aab860a943d4fc84d -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a050004141bd3d18838d09a61c2b0ba9865a146b958c0ec0b -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = 8b61c39efa507e17cf4d575bd600286d56a40e84f35d6c06d3cc33b400e161220df1c86bfd0911226081008cbfd4fa0c3aafc4de70478d089ff02f8e0cecb2e6a68011abe64d4196f9de70a9217e8bad594c02df3891cfe71750b509761fc59f9c3627c77ec61759e28c2e1cc4a5e339f9a451ef12e23b8983154d8d0524a437 -S = 72c3377e5a389a176383ffb832de6eaf3b7ee9dfb38f504031af6f3d059cd9c1027e22233d1ed0908bc08ae5edb9aa491aa189610b353b31ec92eb8186c0d2bbe8fb1364c3df8393b5917f69243ccc7cf95edd413cc175793c964efc3eed10b6c2c4de4d7b75f419a68e6cf8eb1a09b0ff29c40b713ed63c4fcc08fb59ddfcf4 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a050004141c6c02fb4af79739cab2f59451c9ec6ff577051befefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = a6cc1c55dd9b8da73acc6716344503690a9db27bb439518719b41da28284c9894fdbce9de9cc032cf7af6df2d5c658e04121a61c58be6848c2f5ab07291394bdef46b09720b985cca5ff6d22bbb5a4b3a4639ff19ca49fe80f8787c30934ea92eed3694a6ba93c0dac840eacd05a0e6b9a2d430469311fee6a3158de0c2ff38f -S = 7fc3737dfc4bf283bb8f8aa2918af4fb7156703b4870f679bb76e079e561d0adb7a21bfae94e21b83edf20bd28d6c06505109bcdd000c7533a8ff9118be14cd8beeda9cdae6f0735d75fb80953bf28587fae51e024d5b415664b3ab9c26abbbb7f2461d9bf7f2520ba08a09421939fd661d5e3dd83f3e4c41f760291e1c081e8 -SaltVal = 00 -Result = P - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = d3787e2cd5eddc154a3b29c8a5161cb0ef6fa97d6b90c9d579677d46ba22108075fd9dc13958d290c40df3ae2400224a1cf8dd74c9adc8d48522ad9c0c34c1bbde732954e432bc6e55da0beddb849ec1f2c6815d91cc006a0dabaebd3af3ac87d38327cc1ca22317c54b776b12c7197c39829c1f0c17f700d7ad88938c86594d -S = 7948b018e9d0772d84bdda094957387e91179fd7ed4483091f764a2077d37b87a54f4d10069584e50314e1d866c01f1c22de215c0cd1ffff3e23b321378c1b53d0d517aa29ac262ce86dee0ba752958fab5ab69a3a0fb6824ffa8554d4b212f532611b10a28faca706391ac2bbe04a9603e4f15021ddbb1d47505bee6ba83c28 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = 31f8dd3024b0487ae1e3a7af9032ef7c76d5420d617771814747c09b2a4ce9ba3ef8630b4e01e3fd5c6c24f588ebe44433682f5663e2df2b6978640bc2c3c1763c69d75b59efe68af8cf516a32cba1ef8380cdc72a3eb9d4d217fcdf7136e68b7173c2870e245808ff35b677587b3066af45a6c97d340563c84d107eff4d61df -S = 2146e1bf9d75336d7bd76091527567c9326df14a810cf39d22eb91589584caaecd89ddc1b3ef0782e79e535b0bdce8eba2d7f40aa05720278e6c3ed8fe58974fc1ba6cde3fdb79284b64eeb5d08fb312eab503fbdcd85c240414b8a9fb726f38e2780d2506381d90eccbad3c075c7fee67e8a1da037f14fc4a6d8f06c301742b -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = eb2a75ef219b2bec0987c2623a76a8d3c292754519c47f8d541aa8cd9b6c7b3cdd3f7825c2e9ab33e2f684eb34cbe27ac98971b1ba34364e5f15687dc15c829e520a9649dc0ee48fb8aeab8340293ffa869b5c8e4720bae91a3ce140ed7b3f1db25478625653fd8bf378e03346dae7d9638fdfe5a7d032e6ef59bc1e070fdb40 -S = 885c184cf7e40453f8dcd49e1336c91adfc070ae886b23b561cf444092017a86594dbc09c484d6307201633b4476c480994c4bf0a38195d9e9065dee62f5510cb0d9b16a5a9e0ad86eee516a090809e599b4b7022333bdc1c2f9b0cd181a897108c8db6e2abec0c9c6acc426e55ceb9cb4dd565af9d0eadc24ad33bc6a0f2f9d -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = f1cf2ba2463023a1d329957cf3fdc044ffecf8ce0a11f9b6ce8b7ba5e5db07d03d8d08c1c61b255a6d0ece174e661593253cc04e06a69cad4fdb1442da97014e77c1c484994c93104f5b10d876a820022e26fab68ae57e258c36c9ca501106ef87b38674278b14cc61578248d48b889800f2cf8ffd9748266ce6c2c4af0fbcbc -S = 56c800772a63baea87e02adecbe6e7a1cbf352ec6c40d68d02035a8ef54e3c5d4e4c8d23a686d186ab783dc0115ff56138f05cd0a88a28df8304a7fe8c1f944acff2c51ba447d333e97a053aaf222bb6371c35d37a3c7345f7ba81ce99baaf2f165c3a5f0d9a1200da7017de8ab65c35cd7d082800fd13fb87c37ceff83e3dd0 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c084f86c411436b0111c733c5642186a98d5a8dd8cceb2746ccb8342c -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = 8b61c39efa507e17cf4d575bd600286d56a40e84f35d6c06d3cc33b400e161220df1c86bfd0911226081008cbfd4fa0c3aafc4de70478d089ff02f8e0cecb2e6a68011abe64d4196f9de70a9217e8bad594c02df3891cfe71750b509761fc59f9c3627c77ec61759e28c2e1cc4a5e339f9a451ef12e23b8983154d8d0524a437 -S = 1daeb428f8dcb93c16b0b96a23708a4a0b2e70ab7fcc2fb16075f901f94fc9bde149b26c83738e58dc598bf4e1c53b34adb69d93f30726a174ac87c1a1b67bf70fd83fb9b89f476fcb13cfed84c2f6d6a92294e0eae0bfdf91119cb692b096c9bc3d242a31f8a979f965fb983031b8f33f18b1713cab83c1391005a94b79ab31 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c6c72c171d3d71a0bc8488c39813a0b20e2e937a13d9484f6c5de23d1efefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = a6cc1c55dd9b8da73acc6716344503690a9db27bb439518719b41da28284c9894fdbce9de9cc032cf7af6df2d5c658e04121a61c58be6848c2f5ab07291394bdef46b09720b985cca5ff6d22bbb5a4b3a4639ff19ca49fe80f8787c30934ea92eed3694a6ba93c0dac840eacd05a0e6b9a2d430469311fee6a3158de0c2ff38f -S = 7d914ae58407a2b981e58ca575a81796a5d3d7073f6cc3b2641338fff4b963c35125e99360b8bebbd12add1919ae46f84c67b642b43d48360785d7d990bd6b23a24feb54925575a46c2e49d5ce16204ef0c921a25c31fe0b5ed623b2a35be5069b7a7fa57322a9fdcee5b391451d49e624fad211494ac3230efbad44cc5f739a -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = d3787e2cd5eddc154a3b29c8a5161cb0ef6fa97d6b90c9d579677d46ba22108075fd9dc13958d290c40df3ae2400224a1cf8dd74c9adc8d48522ad9c0c34c1bbde732954e432bc6e55da0beddb849ec1f2c6815d91cc006a0dabaebd3af3ac87d38327cc1ca22317c54b776b12c7197c39829c1f0c17f700d7ad88938c86594d -S = 73b08114f6256d434c5cdc278a9ca697ea2447895884ce05170dd41d5073ae0b6e346ae64fe886287151e0c6aab0aca3638e5b82d63aaaafc50f8070b592cd052ce7bec9306ddc4760a6f6f2166e40800715103f938698a68a10c73ddf524c6c6e55f76f7a0ab7058cace263af7061fe70fd93ca62884d232195a91acc38af2e -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = 31f8dd3024b0487ae1e3a7af9032ef7c76d5420d617771814747c09b2a4ce9ba3ef8630b4e01e3fd5c6c24f588ebe44433682f5663e2df2b6978640bc2c3c1763c69d75b59efe68af8cf516a32cba1ef8380cdc72a3eb9d4d217fcdf7136e68b7173c2870e245808ff35b677587b3066af45a6c97d340563c84d107eff4d61df -S = 6707ff06f4e6fe6cab612b8deb099ac9995511ff0f43fd42f9f1822105e6c78cf6e7bdb117f5a8d554000aeb22c69cd0beb7cf1eddaff92161117f08befcb01605e3300826c87f2fb10f6e34bde865db2c5b7124d3273a997b115f3d0022d0cded54daed0b4ddabfb9b39abec2f9b1e052a89c4d64f38a7649729ccb14f72650 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = eb2a75ef219b2bec0987c2623a76a8d3c292754519c47f8d541aa8cd9b6c7b3cdd3f7825c2e9ab33e2f684eb34cbe27ac98971b1ba34364e5f15687dc15c829e520a9649dc0ee48fb8aeab8340293ffa869b5c8e4720bae91a3ce140ed7b3f1db25478625653fd8bf378e03346dae7d9638fdfe5a7d032e6ef59bc1e070fdb40 -S = 43a9b4ac08716a3fa5e6ea8fc5957492d093b3a4293df69efae3501e938dc25f551bffc491abbc1059543280c8f48e5c97ae0fe602c911eb894804ee585f2d3b9de882856ba2bb4c86c6a14b8126cb02be2ec6303c228dfb892d3786ebd2a9eb3247581ff7f01a2d0f6d4c75a96dcb4e98fddd204eb8d191f0896506fb72d2ea -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = f1cf2ba2463023a1d329957cf3fdc044ffecf8ce0a11f9b6ce8b7ba5e5db07d03d8d08c1c61b255a6d0ece174e661593253cc04e06a69cad4fdb1442da97014e77c1c484994c93104f5b10d876a820022e26fab68ae57e258c36c9ca501106ef87b38674278b14cc61578248d48b889800f2cf8ffd9748266ce6c2c4af0fbcbc -S = 6db3e5bbdfe86efac37bc19abbd07d9209f67876d0ed8f8859b1826d98eb22fa093e161274e4a38675cb76224a70346730314f08475db6ce6fd77d840b9de3063c88e987fb244ac823e962b31ec648ca8942e378a2f7ccf7400b036aea7c5a11e694d85c3c929e43613178eaade378d3c2f6805a14d94029f4a5ce89a87651d7 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420659241b16b3fb30e5012378eac6d83b927e7fc9d0eb5a5ea9d1b75d48441a6a9 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = 8b61c39efa507e17cf4d575bd600286d56a40e84f35d6c06d3cc33b400e161220df1c86bfd0911226081008cbfd4fa0c3aafc4de70478d089ff02f8e0cecb2e6a68011abe64d4196f9de70a9217e8bad594c02df3891cfe71750b509761fc59f9c3627c77ec61759e28c2e1cc4a5e339f9a451ef12e23b8983154d8d0524a437 -S = 87ee0da9c96d9a17f63d3e9e142181c0979c381ceb769a370545b535abc6eb8981d3fd4029f529909f620d2a00f209b6ad7c8f709fca13118e00a2f21086fb3a4eb4e416a0b2a121e4f7be5b172a8ed12185948cdb75575fe53d883a354f17baae73fe464d85ca0519b980a4b6f565bc0e76060f86b4cb3e90b6c4b9902f5bc0 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004200d04ea209c27fd97098f416a6410afea38ead35d43b7a1f93d7ae04f7d62d502efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = a6cc1c55dd9b8da73acc6716344503690a9db27bb439518719b41da28284c9894fdbce9de9cc032cf7af6df2d5c658e04121a61c58be6848c2f5ab07291394bdef46b09720b985cca5ff6d22bbb5a4b3a4639ff19ca49fe80f8787c30934ea92eed3694a6ba93c0dac840eacd05a0e6b9a2d430469311fee6a3158de0c2ff38f -S = 8be4adcf1f21261f16ed5b4ce29284399e2a6b7f6339ebb94fcd8c412827911eb5e626d6c83315a59db85bea8010ccded74991f98488fc48989b1854619acccb63fff3d1e4e9a350440744e8bd16631f39ef2a1426b8ffc33418dc7a2a0bdd3330b0bbebba1f0b9fcad2347a875dd89feb43506c0d8e1476e36c9fc6a2798ec9 -SaltVal = 00 -Result = P - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = d3787e2cd5eddc154a3b29c8a5161cb0ef6fa97d6b90c9d579677d46ba22108075fd9dc13958d290c40df3ae2400224a1cf8dd74c9adc8d48522ad9c0c34c1bbde732954e432bc6e55da0beddb849ec1f2c6815d91cc006a0dabaebd3af3ac87d38327cc1ca22317c54b776b12c7197c39829c1f0c17f700d7ad88938c86594d -S = 70fa48adbbe7f5cfcc61dd844ec0948d8c20ca5bca62cafb0d7014413350c5fbbbaeff1d445a7367420b1237dd316db6c8298d5ba13a3b26cbc48a84081bb12848cd8acbd198a7250d0411ed8d0e56d0163c39853b3893655037f6b4774be21d62c604522904202d6aa0f11aa1f7f56612e85139ac0d577593586d6229422289 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = 31f8dd3024b0487ae1e3a7af9032ef7c76d5420d617771814747c09b2a4ce9ba3ef8630b4e01e3fd5c6c24f588ebe44433682f5663e2df2b6978640bc2c3c1763c69d75b59efe68af8cf516a32cba1ef8380cdc72a3eb9d4d217fcdf7136e68b7173c2870e245808ff35b677587b3066af45a6c97d340563c84d107eff4d61df -S = 1a7aa3bb07684cb72a23a570dd06eec11f1ac1e5cc02108b6bcd7145c413c743da8706a44db575b7053573e975ea2bc111821612f14aa001dea6551863e34af0e68d6f9281cccf590d1b2528085cb8e878a427d320c73806a3af8b498b7d3789b66dda4ba9d6c26d15500c71a6b663d9612076792513776921503435d6578b6b -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = eb2a75ef219b2bec0987c2623a76a8d3c292754519c47f8d541aa8cd9b6c7b3cdd3f7825c2e9ab33e2f684eb34cbe27ac98971b1ba34364e5f15687dc15c829e520a9649dc0ee48fb8aeab8340293ffa869b5c8e4720bae91a3ce140ed7b3f1db25478625653fd8bf378e03346dae7d9638fdfe5a7d032e6ef59bc1e070fdb40 -S = 706c8a70281ab07dca9ce73757279e70621358f1a5bad91bb8d0f34a4519c625ad000df75709b7fc805ee64e1a0e8b2f5c637a833b682c707eb21ad79f99d9f82aa91ca1f3ceb6da9c117c96391f547297cc8f507cc4363f9f2ff84fd9c8f430e84740f3d3d9f385e73d90c8769da2615e46552566f456f6a675d613b8a97678 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = f1cf2ba2463023a1d329957cf3fdc044ffecf8ce0a11f9b6ce8b7ba5e5db07d03d8d08c1c61b255a6d0ece174e661593253cc04e06a69cad4fdb1442da97014e77c1c484994c93104f5b10d876a820022e26fab68ae57e258c36c9ca501106ef87b38674278b14cc61578248d48b889800f2cf8ffd9748266ce6c2c4af0fbcbc -S = 5b3567d2742f596b42cd2e3951f75b8058a98d822961f5deed17ce86355fef06ce8f1b1e83da9f27ac4203d2b6a406ae2657993624344fc760a0ade6106028e2dd68646f1c6a735547aa7e4d4e6ae1d3f14610d5eebc88dfeeccf979d93f1721554c67bdbae99dcc2efcf3a98eeb6bf713dd3c5fbfa44e3b9467838744d226bd -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430582a092df1f38834b32c013209c529a91289d7e595d648c1a633680988e5c8f8153c37c9caf89c37578d4a5cccedf712 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = 8b61c39efa507e17cf4d575bd600286d56a40e84f35d6c06d3cc33b400e161220df1c86bfd0911226081008cbfd4fa0c3aafc4de70478d089ff02f8e0cecb2e6a68011abe64d4196f9de70a9217e8bad594c02df3891cfe71750b509761fc59f9c3627c77ec61759e28c2e1cc4a5e339f9a451ef12e23b8983154d8d0524a437 -S = 0a23fdb9060b70ffeb690d0e4be5201499f3623663c4a3c5b8ccd937c20523fcdf526db4279d7d7f1067e241b0d7f00de2841934691747976f3c63e68048702b69db8981d8efba63f0fabab14abf2f517b0d5caab537f187af9f46414f070fa5c1fb9d2eb6858476a5af8bc82b7c38aed298f169f1b962aa452e5f6cfbfe766d -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffff003041300d06096086480165030402020500043061ec010a79fc79f61a9051dae86a56fd57b311f7d5043f4519aae525d02bbe46a433dcc6aad89016c6298dd09ea7ffecefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = a6cc1c55dd9b8da73acc6716344503690a9db27bb439518719b41da28284c9894fdbce9de9cc032cf7af6df2d5c658e04121a61c58be6848c2f5ab07291394bdef46b09720b985cca5ff6d22bbb5a4b3a4639ff19ca49fe80f8787c30934ea92eed3694a6ba93c0dac840eacd05a0e6b9a2d430469311fee6a3158de0c2ff38f -S = 9bda2d9a6a3570737eef2c75f5fd4891d9e8acc102654decc8321b2e114ae8c2f615a1173d855e5d4261a99dc7f825fccef11199e57ba30d98502c237761217261dc31cd14de68201278ccfb46459323d192fdce1577a1a9098e5c7117bc0e52ece3403e0b35fc64969342a72ad74e0330a10a50b67536b088372514a8436de3 -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = d3787e2cd5eddc154a3b29c8a5161cb0ef6fa97d6b90c9d579677d46ba22108075fd9dc13958d290c40df3ae2400224a1cf8dd74c9adc8d48522ad9c0c34c1bbde732954e432bc6e55da0beddb849ec1f2c6815d91cc006a0dabaebd3af3ac87d38327cc1ca22317c54b776b12c7197c39829c1f0c17f700d7ad88938c86594d -S = 3892627dc93f65857a6e773202ee6d8bfed806ec2580f1f63fc7bb547d6ca2d2459efa5aa6cdc9513153ef2dc2f9acc0a3f878c4b3a149b674f246842610ec9d4f8d2038bf1126632b588b7c8376066d1b18d85e51ec221efcb5f58e6f3f4fab1fb6b232d443cb16484670b1adec3a450f9f926ceee02c6ffedebc4664a9c5bf -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = 31f8dd3024b0487ae1e3a7af9032ef7c76d5420d617771814747c09b2a4ce9ba3ef8630b4e01e3fd5c6c24f588ebe44433682f5663e2df2b6978640bc2c3c1763c69d75b59efe68af8cf516a32cba1ef8380cdc72a3eb9d4d217fcdf7136e68b7173c2870e245808ff35b677587b3066af45a6c97d340563c84d107eff4d61df -S = 6015144a01c388c92bd4913907fe075a42afea023989156b840a493f074d55164405e50a4105d5ba9810a9c761f4626e6e05bf7ec4b47b07ad459ff404db6931f4a994a1911fc65448163d369eaa61674ce2112f79a7a9f541f26a111a605b9a3aeda1db6627c59bf723d34153769d18d9ca724570484583b37ffbb11bf7d4be -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = eb2a75ef219b2bec0987c2623a76a8d3c292754519c47f8d541aa8cd9b6c7b3cdd3f7825c2e9ab33e2f684eb34cbe27ac98971b1ba34364e5f15687dc15c829e520a9649dc0ee48fb8aeab8340293ffa869b5c8e4720bae91a3ce140ed7b3f1db25478625653fd8bf378e03346dae7d9638fdfe5a7d032e6ef59bc1e070fdb40 -S = 45d7f419feda3099092973f1d61994225fec873a0467b1348776a3a6578a10b24be941000311519cf426aa8bdf45a300d7eb31766e0516988cefb14f076c0502a9f7421ff4965875bae992930322d34555cd32ec47d8e6b1ddf95cf1eb193ef3accea5db5343a80d0d36d4325361c7180de57dcd80929bcb9fa166ecf930113c -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = f1cf2ba2463023a1d329957cf3fdc044ffecf8ce0a11f9b6ce8b7ba5e5db07d03d8d08c1c61b255a6d0ece174e661593253cc04e06a69cad4fdb1442da97014e77c1c484994c93104f5b10d876a820022e26fab68ae57e258c36c9ca501106ef87b38674278b14cc61578248d48b889800f2cf8ffd9748266ce6c2c4af0fbcbc -S = 22a5c4a08adf1a8d1dc26d0a3f02af5f12062b82e10743fbc2ae74b0bb533de279bb57bb6f0a44f9b79c2621c426e9e6b5f50a5a8a2df9d46ce9fdbdd0bf6e74cbe2e55682046145a7e40622bc81ec945e8b87a8a9b9ad711e7626109772b64be7a7ad7d5f3b3aad20c03eb164716b62e0851f1041930d4e5ef4b50bff82f425 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d0609608648016503040203050004406aa75a3539ad3822952b91897813389ae2946b072578bea95a64f583bb5eb9a27a8e44c2405a9681d9a290e2cd55fbd59c381039de0e21ff120d2a3ed8889277 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = 8b61c39efa507e17cf4d575bd600286d56a40e84f35d6c06d3cc33b400e161220df1c86bfd0911226081008cbfd4fa0c3aafc4de70478d089ff02f8e0cecb2e6a68011abe64d4196f9de70a9217e8bad594c02df3891cfe71750b509761fc59f9c3627c77ec61759e28c2e1cc4a5e339f9a451ef12e23b8983154d8d0524a437 -S = 088942923512cc272b5cd0b40d4aac42ea3165c74c90970ebdc46b5fa8c0b0e153f85c446b0a2d3886c7fd468a47efeba91550c7f01167ce009a4d6a3069bb280b6755eb9716c03f64cd2788555b9f8a0e85d74879dfa9c48ba3ff2002a8b0de02cc8479ca2a59966994d36c6622f4297e2a26cfaa824e447a6badb92331829c -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffff003051300d0609608648016503040203050004409bf5087cc76d346579861f84faef10011e190ef00bfd9b708719d5b672952c0a5f5a8fea8c12b2d738e0b420d785e6a02d7352b6a0e3d20ea2c2140094278b52efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04f7405154be02c482bf07115b27fd7f988920d8207937bec317f1791c11b0f2325851c35ce42bebc828c946438cc22656b702cce2a0dad6d8a5ac3fe6fd587c36f81ff5edc977edf9c6c085efd73510ddb2532742367f8f878814c1714549dcfa17dbd5d1e17ce3dd1a9893a3785bc34c5205df3978071aa36c9e86bd33cba1 -Msg = a6cc1c55dd9b8da73acc6716344503690a9db27bb439518719b41da28284c9894fdbce9de9cc032cf7af6df2d5c658e04121a61c58be6848c2f5ab07291394bdef46b09720b985cca5ff6d22bbb5a4b3a4639ff19ca49fe80f8787c30934ea92eed3694a6ba93c0dac840eacd05a0e6b9a2d430469311fee6a3158de0c2ff38f -S = 82f547779204eefa0d857ae077b2e02e61dc76ee75e709388ce33b3f227dc96c5a98148a816a4c954516a7e44b00b080cd8b05cfa4ae9ff82d64b811f62e6752904b88c2e4a9d54088a49d2d480c267b96974c46f75a4fd9cf09acca14290d6515defc75e0807334cba3f492d42a17dec01396e39d7d8335bb4d11a1c19db3d2 -SaltVal = 00 -Result = P - -[mod = 1536] - -n = d2b6c8fd44e7eb621fa6685fb62371872b5e8408af51bd1b44c6473823402418a26963b98e6fb191cf74175e64132ae6cd101133fc002a89c10bf7739eb930b9c067b52570842395657f927434aa3acbf3369dcdc3990f77cbf22939ddd5877f09c8aab818b80aa20544b6928fe62c78795a4160aecde6ab454db0dcdf1d6c13522526c5ccf82d429791059306f02cdc18c4e580ec6c2da19b3c6de63933ebeac79010c73df95748d987e96a0f8ad523b5014b33423f55922aec2ec23b9aa22f - -p = f260d143cff1e8e0931765da8cb335c0206bf7fd19aaf8ff41e762992f2bb0a660cd65f08a80fe502c9125166a6927aa1859a874159796fada835b48522f5795ed1f8d23f05016358ff908b0dd638bb7ed12c8b80b46aa858d52c77bb7fc0ed1 -q = de8e674fac0b7ea32d518a22030fd10d4298a77974db8febe195a4240dc5373e8161baf8ce47dc4fd076f64e307ea6262c35b9819bac4f142b613973eeb6a62a15a2ff09fba9ce4db7186969af925ee3acb7d3be7a1f9c85358216640fc1e0ff - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 95e319c0df793cf1c1b424a8949b9529d6c1a0cece5f6db573a538b68b529a9810830a84d7c8a3b9747d2882585845653c3e179ec35befcc5a7153e96370467f9448ca1999fba2f801f65c0857a18f138f356233a5ce4d8d80c1243c1c2f518ce8da60696d38c21731c6ca23db9ffc99974d8777bcdf1062ad3bb198fdb64226 -S = 1b5d13124f4a0ba3b4e8f102a7044d8a633ea025729f55ac75e4a8544612f229d4f43c45574983b51efc83ab611a60b009949dd032c97358bb7ae5d3b2ce417fe11a9f6435b84bf7113b23403b010fd749838823450ec954f6e3f54c13db12606ead2eadbf209d5d31efaaa0924f256d3f64692db8a2b7fd8197df13c33b160b2f8fef0d4f2ccdd1e1a5b269b25e4efb462c000573b8584d45c2cafd248348f19cf1f7422abaa402ba54274b7611c4c9db3a7dac61ce51c396cc3c59ecbe5594 -SaltVal = 00 -Result = P - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 7271bcb91b18288e874f4c04c10a21bd35150b1813ef61a7f4dc29e4c036231fcf040abb4ece169ae5afc5d696abdbb2e943a7d0464789a4a2ecb1285e1e29d16b1716c2b3313b41b4f8be676e842f1b8006c6418ea0ec2ee57afd5f62124d6b90d3693710ea9f693e55c01f113c24e04385efd3b2a3932e07ae96f295b996d6 -S = 6b9212d017ad9f4bb7ebfa3975b514bdd22240d753fef5631e1c216bc750336349255d53b857bc944d3eee3bc82805620d770e41dcba45869f47d36343ef067cae99a941ab94948bf0c02d2a3ee403c7eab0f9d6f9423c166e62c2dd61198046944b5082db4a17843229489c46baab712416e3d0a685d2353abe010c94ddf7b47f5edf1fdfc9a5e0de27d65ab5dfc9f2e660d20d169cde3e2642393edd79fe7316ec4ebe61fb88223f6711e138d09ec3d76781e73d93e7dba9830c53cdb5b0fb -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a050004147c3d3d4d94e5e297419551f26b517d0046a98d9c -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 1484f58f6b8cff56ab4b81d17967dee7ef1eabeae57c11706fd2735ea6655145ac636df2ea1b2c409c6c3e31907e813d2ab123eaacd3089db4966bb00741c7c48ca5f8599c539d9c790cc27f1b79bc0f331c53036a872790e9cc4c851f343893be34dfec079c1c11481253e4a3bf55051048835ba50037f1165c5f0478a76b5a -S = 57b3646aae17304bcfab8b6477bbcf791ccfb4b20001b2c3cd4e6dafe129934f2c401b07eada6a4b2db9393ffed36a8ae8af85b1d433a398399fc0c2956959e99c12053ac3346710ea5d9119fa4757032fd1739b426e879214afe364a9d274d383e4d1fa64b0b07c6f6014dcbeed59ee0dbcbec90cb5f3133daeb829855d61b88777d806b5717227a8016a965f1bd2080b44ef80bdbd0bf0c494ea7baf09295aacf161c433320fa81cfca5ba44a71264a1d1db1d2f5baeb58eb9d623710ed1ba -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 957018ebbf4bc279aff3a28f87510c01666122399490a4c300680910ed6ece73e84b0e70fd2b53362a63ac6a1456ff26f999a142e65524d22aed70ef0ae115bbb6f3e09f7c88add73c507b311c29c6117c4111b92d7bc2c7dd1532ffd687054be9aeb700a4297863cc043a6c079308cad8a19926d0cb25ac032677c8ba28442d -S = 7d9edeb96e2eb21b32fc3707c42fc26cc2ddaf5283ed2853206e51594027fddbc82260dfb3e2da03dbec1069f0bdc63a7583f0ffc194ba158860fb0bd13dbe22ed34f7f77821b58ff1b6d9a6721f91914d3529d5e605b813f7de832afbc57d7ba570a4af8f9ad2b7ea8d2c1656c669e1df7d3c112bdbe212d37d61ff62d03d8b19426437a48977ea5aaf5eccdb7d90d1e8a1c652cb2333984cfac0c1432e42fb16168a3760328039d1a836a52baa9be92050e96dc86d37c8e0b0684d445be018 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = af0272c90402a9c27f9cf6c9de652cb7a3a402b4695a0c58777fea11958fc0c51f45e6b857a6e0afff42905628b7aadf457669ec83ca80af5d16544f6a5e688e7a0818aae2e48b80146be3f77344b69c650dc28aa957dc8debf22a87956c9212e9d472664dc3927ee59e5776671539382bef7657820a083b499dd57fbec12797 -S = 3cb0d524151a8e3210123ac13086c6299074f5b5a4276059cc2e741944eda31a80aada9427d0a7e49823632075093e4f779f9b84ec4f159227e650c267cf7126047f7d257dc6e41ec6113570bc231681667735d41085ea92a2b9197fac8e4ec9bfff1d2b16f65ceeed22741a872a05afd641b1444a928a948d15248b119f28b3d35e28a337096cb7bb97e7e3d73bf1cf8abdad9cbfb84481a3e124b8c345a2d1065b1713de71e0ef6b8beddb6d88e82379960bdc1cda7ebc4c4c4ea9bd1d81dd -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 3797ad7bd2b5c611a7b1a15b8337058a1e2c15cc42418d7b2fc949943fc8076cc64c6d9e3c004e489efe297711e5f2dfc92b15d029b5b9652ba541ff037419f1ff40af7db267bf005154d4695d990cef823e1b04c0599284c8df6233a9ba9b66ab1c7a007b12a3a0895cab19af7cd923130d2e504e56a241ce1fb11978c31632 -S = 0a34ff5dd8d7ef76bfd56bd4218ad50c22cee0af0532674427c7e13f8b99b86e7128316bf2084c6477180283a7b3f4f4aefe5e0dd4aa136a2920ea70eb23b0e8b8b2c2a2c530f4efa1b6bc59d2a83547cd5c4043ce497639f609f05f3d4d2099b07d9bdc0a15690b7bf2da73def963eeebe118e59ead6dd89f0fa271645fca4d9bf220080a850649f48709bcbcc1cea3fce9618bf167e2fdb13a1ed50eea093d1070c5bfb162b054317f2e41bb3099c39d8e2c7b0b771da05cb7b7bd1abfbfa8 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a0500041486d9512b229032778b2d54e07bd553ebe7f36713efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 95e319c0df793cf1c1b424a8949b9529d6c1a0cece5f6db573a538b68b529a9810830a84d7c8a3b9747d2882585845653c3e179ec35befcc5a7153e96370467f9448ca1999fba2f801f65c0857a18f138f356233a5ce4d8d80c1243c1c2f518ce8da60696d38c21731c6ca23db9ffc99974d8777bcdf1062ad3bb198fdb64226 -S = 19ca086cb98c4770fbd6b70206c3896f966c968c1e5600a2348f3457fa823f053b45b75f0da759994d5d047922efa5184fd0499f57be607a9ac63a1926f8317e6845934a37cd58c07831a970d9599dcc15fb50c629caff451c96e2e2d7f9e3842e8dcdb8011adc8f5cb1c01392218d62285442d9b651b2a0369af3f99343dc8e24fe4f93fdd490636e78ca1b7ae73af5ee2bc0ab6a0fb42ef612c3260f62a1577c3b41bcc25e8feaed1f53e0d85c8155c9c38cf72385ae28e96831f891e03ad3 -SaltVal = 00 -Result = P - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 7271bcb91b18288e874f4c04c10a21bd35150b1813ef61a7f4dc29e4c036231fcf040abb4ece169ae5afc5d696abdbb2e943a7d0464789a4a2ecb1285e1e29d16b1716c2b3313b41b4f8be676e842f1b8006c6418ea0ec2ee57afd5f62124d6b90d3693710ea9f693e55c01f113c24e04385efd3b2a3932e07ae96f295b996d6 -S = 843e9f1f0a472be4a3bdf456281eda82aaaa08a0fab173f2086bc03f8b88c0517f457bc276ad144c1b53084d736f2077b0c05f451ed6544a36bd26e902592b384c6d33587a79f2023226fc7c52b1384bc6dc83360769014fb5110245b2395baeec2b3087f6b6eb5de706d08fa7eb069c749a56b91d43d1ccc8f1631a597beaa6486a618b85a2982eb32fb5039584c65f7f07e7c31663a06f48941878f1ef4cbb657f18cc85db6e9d1c87ff81fa7b1e63c74abda333de6242a21a43789749bdbc -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041cd6266f6d4d47969031bf6bd3800efb1332f5c75ba7d91394de470bb6 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 1484f58f6b8cff56ab4b81d17967dee7ef1eabeae57c11706fd2735ea6655145ac636df2ea1b2c409c6c3e31907e813d2ab123eaacd3089db4966bb00741c7c48ca5f8599c539d9c790cc27f1b79bc0f331c53036a872790e9cc4c851f343893be34dfec079c1c11481253e4a3bf55051048835ba50037f1165c5f0478a76b5a -S = d140b01f9d0d67a4b869fa67c115919268657f97d846886f07174fe6a30be909a74f1dfc4590ea356e349bce40547539e76bc9011ea133356c6f01b7739126c8af29e307966bfe39999625ef989faf817d0ad6378fe5dfcd5974089349d977c7fec62289b760b4c7679d41e463be7e3f996cf1f66e48cc004f5823b1f7a94524abd06ff35fc4f51fe6bd16dc4b43eb360ca18b4c4e5a33440d748dc7fb1ec3a8344f4e175f52479f4d93275e03890664fb3a2941187bd023a3a277fa840986c3 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 957018ebbf4bc279aff3a28f87510c01666122399490a4c300680910ed6ece73e84b0e70fd2b53362a63ac6a1456ff26f999a142e65524d22aed70ef0ae115bbb6f3e09f7c88add73c507b311c29c6117c4111b92d7bc2c7dd1532ffd687054be9aeb700a4297863cc043a6c079308cad8a19926d0cb25ac032677c8ba28442d -S = 10699cef91c348ab96ec062c0a98bacec04aed2bc2a806d8553258ebdc999abd59651e8aa7236e50eaf0a183e278a956de7ad6c3eacf7e5a2dc1e46a5fc1ff58d09db56580d924de5c3ea9863c006cd9f1556555b024a670c316d2de697976a3ce5d3994a758220cc83cffce43f7ce42942c3caad5a477c494d9581185c4e5a69f056778c77784a7fcb246f3edb1cf93bd416057d0c2ebeb36647ba8796b50ea569930132d189cb43be8405ea210b8e2266807620487791839d0e6ee4dcf9d63 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = af0272c90402a9c27f9cf6c9de652cb7a3a402b4695a0c58777fea11958fc0c51f45e6b857a6e0afff42905628b7aadf457669ec83ca80af5d16544f6a5e688e7a0818aae2e48b80146be3f77344b69c650dc28aa957dc8debf22a87956c9212e9d472664dc3927ee59e5776671539382bef7657820a083b499dd57fbec12797 -S = 90277451b160d24cd2df6e5e84e2f90a8fb6208f3395a305e299d5005656a153d27801084f7cb76fd0e4b8d118f84214416bc65446cf41fdbb6532c07b718ed82e34a8b5b52575e39de48e65eddeced22e5556d89103960a228df0efb047ae0e1569e579b477b38198045bc3f4cfe021dc9bccc33f10d3ea30a01c7c567ab22bd2d0bbec9c57dc990bf0ef19fb5942f116ed33510ff76405ea1cd99c0b47ac687d8c66f9540685d831302c272de04b4459951ff480f99dccbe3b0c01f3330560 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 2da2547df2b14d5f28bd5cd71250f55cd840a11e7bd799470e30938124e4dcb985e7a72325aca57f5690d59a3c759e1781ad1b6f4b1bb6376b94f8a2d88b9f465beef1238b4b51e1fc371059b4f08557de41609ec3a63b2df5b172c1cdac359b1880db830ed6790d847bb41b6209d3a356c419b3cac251b2144faae8ed8fc541 -S = 8866a8d6767eb3a88cbbf6075ce1ff085e541e3dd305915cfa2ebc94ce8d6ae9b7a76d5770bd4e96b913fc41824b59f3066471b054f744efe0fda0f12fd1413b755f0c1d93fa3bfd00dbac16cd6c83a947d71645aa3828b7452aef6b68a92f83dbb48a041ccf1905e10665e186d5aa85e502b36dacfec5b1d17ce9500caef5e8eb8b51cff080368b75baaee54886e602e722d2b9d04dbf05026624ec6fa772830090c570c5b8ac7594abe3ab312d46fa3294dd96ed9c2642672154240e66b197 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c9d529ed5fc99f3b9f2d3c3abce14aa723e6ee9397db13c35a355fb87efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = df8494995c51a92e651ecc6229ec4c5ffc54b2975876ea582233a3a02f9cf73207a94fe9e92f814d0f0c3c6432a4a6cb51924304af9719121bd612437344a14e6b5aa89d8b0d9aec77ffdd1373f77220268fd7a99e2c2c61953396e8f37ae1e894fd695d4ad33a3426607618f3cbf78904b2362e301d6b6c1ab1f637b627fe28 -S = 8474bb2649667bea417d1a51fcf6cf891c29d838c7002d7189b945b53436cc0b67175e910e2cdbd3e1855326f7c0c823a8b76d06b2ae1e0bc6a835a524401b5a280d07f09acd94ee745e1a789919128c617a683d1b145b3adcc494aa701c2fc5895d14ba6a7798c3fa51a04497e78413200b284a4b50bd82f0b7a1a4b3b5b3cae15e345844b0b7f155e48bc52fddc2a83648b2714daeafbd0c8c36de1165cdaa75bc8442b681b9ecc1cae114e629b13956734aef0ad11c421ebcc27202df5899 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420351b72799b9cfe54802309d2be3fd5ffc3377302cb171d35af0d486d4e664516 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 73a012bce858e0ae42fa2893a0fb1439a73a9c101841b28ca8c8bdcb0c7b497853fefdef782dcda238a871bb218f1503ec8a52020c0d5d6887da7eab05c7c4f226c1f8321911cf966bde63251cf3e49ff8c38ba724aad027f876ddf10c2642a296f2eaccf38b4e5483a3e818bab0ebd574ed314989a27594a2a6c2e44b222b51 -S = bd0512605f506b906f012de9f50ca56881c61edc331d8b36996b4eefe75b4751b6ff980194b52e19b82dc85fb3428c86905aea1e59e9db90018ad5471e29ec170f18b9668725a562caf850ef41c7ab871448a6f428db6b2ddf85fddf029dfbbff5677bd92aceaa9372f9a579a2f7fbfa8872f8de3f7b15c5095598d39b3808f99cc672d89171302a7e7c3430a1ae675cf3d1b3341f432b4c57a372f9be3a06970f2c4ee3f557b98a8e767db450ff29a491163330bb3438432c5dad3dd8dffbd1 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = af51ab7e521b64502702bd561e40dbb41e2f80afa95bd562bcdc67b3f6e36f86fd9256311e11782f33de2918ca64f5d083d02cffba209fc2667ca4a141ca60c02a7d4559c7add9696e6db9aa4659dec2a96e20bacd1ff8b1a4a48ad20096e383fbb97fdf96190e67a05877f4da461ef158b263c62a806b973cfc222f7b6e8037 -S = 6ed6b46b522f09d6c1007dc32e593a2dec403c5f318e9ce0edbbb2ca6b9b05803ba43c1828ce2fc0e2fe8feb4f80db80e1673e111f204a6a009c115f0a797006bdfc5b5258404e259aa0f9d72957d01f92b756daa9981952dddb0bd1b1aff6caf46ccaaab62a15f52c79fd663ff64b94ab8428c04780efe11ce1a210acd89e63a26f4a48b9e4acf7c327521a9654ffcdfe03c6baec5cc8bc32731d6a9254302a69f56bf43ae8b82738e8073f073dfc8c386d9adb0f1acf16e59710e4e519cb42 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = ae4dbe3079ef09f963a3da04099f596a6eed3c979d798eff8f69af0d4eac9d5c5bd6712a4d2b2d0abcf9b4d85d2c1af26e1c1ea555a9f5e6848a4a439fe28219e1144406bcd939a1bf901069bdd5c6fc2c54248acbdf898888bfe9a9a048160a08b13eac0c22b528360df59e71c2e4ef6e3e552c4744d04e62b096279907e098 -S = c7ad03de788a43496f2ebed7df3179788360095e880785bc5f9135be256cbd7693ff1c47d7dc74e1e3f318a533ad50850336d64cecaf1b6b6a317332810d433362eff2b03b6730df4a04ac3c69e18e752577cf8ba9bb0981a2c6cfc2178fcaa3bee1957cf10a74e87541a3311e40206457a11efcf76893f59dc78cde650b0571072a9af5500dc76cfad2bce35057768b97046adb84a67efce9d9f569839e3f36541cf0b24862f8311796edb735476eed85d8290619b56237a89028c92b3eab48 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004208aeae1f557c4b574127603b7da392e75ad6df1b94d840cff18ca38033d5cd0f4efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 9245f9e8a7b4e2c8744d5bd42ebe68ca32426a5cf7c5ab78414938cc9888ef8af9dad868cb5ab9ec1444e4e6eda2543e3428f8ef805c4f545afa35a3aa96fdb76f83bf12b3f4f322bf613fc38b2c8e0678856230418b6b062fb358488d6eed7c5c0656ec48c9bbf2da6a1473eea43faa68204f27239928172a3e49c52b58e861 -S = c9e9152887b5111f721aced7cdb0e7368b0eecafaa1506ccdf35c378b633937d08544493a1e8aa84b5b7f892d89976f2ebfd55ae85189f61fb280ebfff5a01fc2c90fa4896ebdc3725ec472631e69d35fc9d5a03447941e7befe21a36ce5cad72088177d7e54cffb60dadfaf3800ca38e9751df2d4fab7738f31d82a944e0f3bf652197121c4e74ce5f170fed950f7a03906e75b7fe12469fa4d44fe8348d5459bc5f5f13aa694c12ac64912a20d694230ed95b75f3de4eb0c3c60169695e94c -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = bf15e4f37e28f61a35be4539f17d70c75d3591c19368b84c320a999cb1858114f3008faf1be1209ea1908b33a67e0ffd84670935aad46a58a7e36916844a756b579a6e0c15c11404a8d3c09f410a5287f00b6a2d726adb6a4a715c67131d81ba146aead115d0bb94710e4b466d2621acc8a91c729334f1ca433bdb5605058d48 -S = 897dd26e35a3833b069c14e173d8f90443d51f3c8867457980f0c20420568290a2e239642fd21e93778dfea2bdf3ccf72c3ee8f4334394238d52fe577d1d050dd69838626922ed9af276f888356349fd1ca8e9c17d615b9d3cdf86e86d01eebbe52dbd26c034e8a93fffe7cbca27edb1d03b13643ed4ad122400d4f980ff7b8a9864d39e9fbd5781ea4d21a06136b70a90fe2bea2ce142334403bb078095f1257df2162e9998a7268d1f05f4c483f726b9b0cfc132023c643b1b0b04b6d88745 -SaltVal = 00 -Result = P - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = df8494995c51a92e651ecc6229ec4c5ffc54b2975876ea582233a3a02f9cf73207a94fe9e92f814d0f0c3c6432a4a6cb51924304af9719121bd612437344a14e6b5aa89d8b0d9aec77ffdd1373f77220268fd7a99e2c2c61953396e8f37ae1e894fd695d4ad33a3426607618f3cbf78904b2362e301d6b6c1ab1f637b627fe28 -S = c7fab5c4083fd43b67dcc56c10b5f9a4793ae49411b828512e4930765f496e313995b506e6b2ed4ceb29eb2b9a649e18a1c9f22fa5c89f7349bd7d8e967c3169fdd120517834c0aa355b5bb85b13b0c1fbc2e915c9ac8d7801c37cfdcc45376d8915ab57a67cb39fbe3c976e49e3a47e2312dce0b27ebb2baab9214a7af25482ca1f7d9baaca22ab73deca082b271044048505257c968b131f5dea33c1d02bd4ced74b6c0cf71cba31d989c685e9291789d2a5e906c52268a270ec8206e3bddb -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430ee9e3e985b715474d343f9823ce7f3fd430e13cd9dc4d9117c1a7f1c87f40e16a1012f103c90db1b979cc17934b20756 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 73a012bce858e0ae42fa2893a0fb1439a73a9c101841b28ca8c8bdcb0c7b497853fefdef782dcda238a871bb218f1503ec8a52020c0d5d6887da7eab05c7c4f226c1f8321911cf966bde63251cf3e49ff8c38ba724aad027f876ddf10c2642a296f2eaccf38b4e5483a3e818bab0ebd574ed314989a27594a2a6c2e44b222b51 -S = 28e465b1d7e5e227ca3af797f7f4606a4d78fa8037190e52819b184bb42237b64854c317e08bf3e6ac2e544eb58e0e318682224623f8912682c9afe0e81e7d9f027105c0da1c2b5f27fb24089af422f559ba97839749bcf9e968dca0e58213a0ba53547934804a1e10db9da4464ce7800e5613c89586277beaf69edc62a3e8ca2a8935ac4d0b4d65e7ebff4358be37102a70f327245475bd6673c7d092505f321cb600f6df917c6873625e5d3539d95b94be06d39f90eccb424a9e5acb27f0d3 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = af51ab7e521b64502702bd561e40dbb41e2f80afa95bd562bcdc67b3f6e36f86fd9256311e11782f33de2918ca64f5d083d02cffba209fc2667ca4a141ca60c02a7d4559c7add9696e6db9aa4659dec2a96e20bacd1ff8b1a4a48ad20096e383fbb97fdf96190e67a05877f4da461ef158b263c62a806b973cfc222f7b6e8037 -S = 198f72795be3be9f70828fcfa6fd2eb286f4d996153953730f8195669840b685b1854ebd54f8d1ae8db487802f8c6978197822157eb45c8085ae91f11390e0d8910f2bb51d1efbd743e2e7d7e16c4757a67a666c1e6bbb90fae924550847b68e41bb9d8b58b376c70c075cbedb2875bd7789971d2281ac3a591c7361030dd46afa79ef20a32f68764d40f4f5d689f3686967e57f1b718522a61ebf35e194219f9b044aadccdf0fab455be9f86a651bd9eebab4e8c798c9156880b06f12ca6b7f -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = ae4dbe3079ef09f963a3da04099f596a6eed3c979d798eff8f69af0d4eac9d5c5bd6712a4d2b2d0abcf9b4d85d2c1af26e1c1ea555a9f5e6848a4a439fe28219e1144406bcd939a1bf901069bdd5c6fc2c54248acbdf898888bfe9a9a048160a08b13eac0c22b528360df59e71c2e4ef6e3e552c4744d04e62b096279907e098 -S = 14f03b08b6e55a8aac770701ae964a627e2c35a6e5b0a086cad74eb7cfd5f30c2b481b9a23a03e61f9a73ea131ee9e0d44ae896fd815595adc40a7f719e37d453c6c2ac99f5e76665894fbba102102e31a4fbcc172d523a0feddf5f0098949041cf5c6dd729882db4a3104062f37fd0b51f990d180fd58c2894d9c306e001878aceab5ff4376b98c65864e2216702b6afe97686498732b6259a85e60e56e184515d8326d7ea98508566fb6ff79e771a08904918f19562d28d6ae334b9f15104a -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d060960864801650304020205000430d641c0a68fa8724ce04f866e4c8d232b9643ff63669e3ba6b030d0ab734710b9d6ae8c7703bf964d4b827d2098fcb79cefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 9245f9e8a7b4e2c8744d5bd42ebe68ca32426a5cf7c5ab78414938cc9888ef8af9dad868cb5ab9ec1444e4e6eda2543e3428f8ef805c4f545afa35a3aa96fdb76f83bf12b3f4f322bf613fc38b2c8e0678856230418b6b062fb358488d6eed7c5c0656ec48c9bbf2da6a1473eea43faa68204f27239928172a3e49c52b58e861 -S = 7ea67611c9dec51c441cd3b5980e566f13e1191ab9acc5885d12e04c231b8ab7ab1bd388cdfbcbcd6a8c175d50296483edd4415ff4220b6af620e3ab5d2561c0db009e2ed7b094c8ead105d9067ce25c555cd306f52f183efe0bf3a618c5d52b9517ea948cc1a3dc43cbab21dfa74a44db4a34f8ef6aeb9e7fade424122a96f587a5ea94dc9b7399485d2bcf255826389209a89d5695891bae7bcfb22e430a3f5324fbfe79adc7f7fc5b143b86518022a96902fbba5a39275650d8028d3bf144 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = bf15e4f37e28f61a35be4539f17d70c75d3591c19368b84c320a999cb1858114f3008faf1be1209ea1908b33a67e0ffd84670935aad46a58a7e36916844a756b579a6e0c15c11404a8d3c09f410a5287f00b6a2d726adb6a4a715c67131d81ba146aead115d0bb94710e4b466d2621acc8a91c729334f1ca433bdb5605058d48 -S = a7395ce62131a5eac115ea950fe60953fc334cc244b13b159720a502b7194c9e65eb665e6475e1e19e462b735496d65fa8a5c16162d97b11656a85b43fdd4a819ae918d79e50e51ea1e9f5fa92f467410c61d50ce2e3b61f59be2c88cfadea890b71edb70fa87e38df81c38d315b33fe4ca4fdbd5779052c16eed21468a03b15fa7a235e8f6831ff55fe2eaf79eaf466a2280eccb8139dc16c8f296f0e79a1bc4784f37e6550264d7e26a8507b97b1e279f644a29c166be2c761e1ddd7cb6611 -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = df8494995c51a92e651ecc6229ec4c5ffc54b2975876ea582233a3a02f9cf73207a94fe9e92f814d0f0c3c6432a4a6cb51924304af9719121bd612437344a14e6b5aa89d8b0d9aec77ffdd1373f77220268fd7a99e2c2c61953396e8f37ae1e894fd695d4ad33a3426607618f3cbf78904b2362e301d6b6c1ab1f637b627fe28 -S = d1d6a615340ccb1504625ab056d09a95f42836bbee98bbc1ebeeef5296adc55eb8159a5dccf5fbd9bab8854bdae4f9c73379881adfaeab1bed26a544f4b56067d1c29f473ad84486a4e48c51354e4b1a9c9ba1aa019d1c75c277a2dc5df6ec4e112312c93e5652dbe107270f02805250dc77e833637c65f2248e2834b7cb62135b43730a54e0782822fbceb33073912728dbe0da834342ff7d519404c1171b347b96a4df6bf794634247e4b15b93d7929a0e1852dd20b6c88b4f30e0a18be8da -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d06096086480165030402030500044027c454d298019b1b6718f4ebbb3e2d115f3ea8a214cc95367bbe80783dbc781438847c4b1508b6010de44f47ab6e213f32e7348b8e6d6b4f85fbfbd3b4c6e05f -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 73a012bce858e0ae42fa2893a0fb1439a73a9c101841b28ca8c8bdcb0c7b497853fefdef782dcda238a871bb218f1503ec8a52020c0d5d6887da7eab05c7c4f226c1f8321911cf966bde63251cf3e49ff8c38ba724aad027f876ddf10c2642a296f2eaccf38b4e5483a3e818bab0ebd574ed314989a27594a2a6c2e44b222b51 -S = 3a24d99406cb5a02ba7a403dc0b5b2bb87984a3feec115dfd4e5531993c391294aa226761a02affab891886acc356160bc9543f2b722412392dd5dfef65688d8084268278eb04482eee60f72a34b30376a8395f5f3fd27dd56e7a8431f2093a8ae93c02674409c492b52a1b0c53923672db546c85ce5e2e160c94e78a5d66dba5c398b97585a20f3b32ac35a4216e4b93fd85c3fc5693fff06eab4b9e0495c5ab0d93bbce6b3e16bcd9bb458b2d7b4e30f9f4a52f48311a26e3c0e9ae30e4872 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = af51ab7e521b64502702bd561e40dbb41e2f80afa95bd562bcdc67b3f6e36f86fd9256311e11782f33de2918ca64f5d083d02cffba209fc2667ca4a141ca60c02a7d4559c7add9696e6db9aa4659dec2a96e20bacd1ff8b1a4a48ad20096e383fbb97fdf96190e67a05877f4da461ef158b263c62a806b973cfc222f7b6e8037 -S = ac7598c1f1f9245d59b443cf44e1eaa00f9a213ba24fffe3b6051dd0d9f430669edeab9157371eeda529bace4e66f31f272b210b5b9308d0dda403385238d758de9d2099c516e39cba18a1552059d9eba6deca27db71e766ad67b9db321011b727619bb303df82bdbf029649300b03e0ebc3208b2ea8e290b670b2796b4ea12de9f07e6185fe508548d2516ee1f8997394079cabdb6bbda455983169fee7cca71eb4c5841c27c37762b985824134fea46bd2c95d7d82abb66894c6671ddc45d4 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = ab50f6312f99e068e4a76ed88efda9b0acf416b30500e798843673b1450be4ccf05f2f5746ba4ac7f9d5993ac15ca95aacf22085b676f42c9984dc79e63f0435554e05e859251442f88679b9da474474a0553b6877f916c1ec5aef830244f47181275f2e9263a8a289c2f89f0246e2c42f264ea27013b51e24bf9416c0a01a48 -S = 6c0b09fd6b371212279378f8e3d91a4861c63c7353e5480643774821ac72cb3519cfd77e46c6edcce92b796fdd5a511199e9b870087fd9d815e7d8c8deccfc7c229b93a038e202e60df022d0a966e6616c67a447cee59b0b3ca206e9e503e928dcb33160b9b21897e24d860c7327e83f15ca41449f7aea16a3e7d83faa458dd0f27117e68bc279367925a42ec8cef69cc1bae1df16408ca60b8f1b9fe9f837a1227153b59ab2b3707c1e5cffd79d7c11a31a81f41317f012b497e34d4b3bb962 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d060960864801650304020305000440c4765be0d27a4bdb86ec440bb5259aff46c9bd89a6870bf5b87c3755ce45d780c63282898f959c929d9f144143a038c36d4d0448ef8c4663cedf5cab3d59bf0aefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = d3d03ff14b9e72bef1c6e7d29a5bb8f0ce554cf3cc867a63cdd0f1468d94d738086db0be811f82d8c9ca36d5be64426b126585074ec4726216237155ae4782eebdca24c35114758624879ada1efa61651a692527edeaf30aa4e3eaba0e7be8b67b4e63a8c26594f28965db89c0065f066fc7f5fab2e143820179251cb5194fb9 -S = 81664625093bdfe332db62e3c1f5ba000062576d95f1a82dbc5043eaa267d7602c25cb45759ae8ceb360c017f9a0c4847763e25206699792af187294514bb214a453730350673bbf2feb73033a567d4d11a6a4a13d2d1d79850bd71e4ee9b8b404d2114f505ca695a760be6b1a784be63a208edeadbd1a22c86d8ba614210d9b01b89f70243749f5be9b43385ba94ba0797219323bb1817e5e3bfbae02e2e360383e333b27c32b6685e6b9545a3a6c7742a7e0612f20bfff18907c58f3fe671e -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 076fdcedd54168af223f18c42188c7c5860c5f03517b5b00f66159dad4115297752adf60e6e8d614347f9466b83ce96b88be4ee9bd999b19f1bb26d9ea7f01b84003a907584cf232730480a6bc9692a3cf5c47d40ff051dd133ec2353e0a8c4fb6b65b5ea82aba7686f2aca7edef2b7e824b4dff3a5cdf2aec1c726d8a3dce741605abe0a0b66047ff6e3e7a1be8338af56b4cecd1e650d4fc3c52f56f29e746c7b2ec95f9dbd6dfd1f822541fb6f331faefdc00a346e86b2dd6a88076894b91 -Msg = 4ff4d6aee37bbccf415b68228612f69eddea178398c0c13d7f0a258b6719e2e0079b780a0863ff115b6d1962cf1c252ce3c7b50bd87442e40be31f1082cfacbcc570cc8fef44998e040f563d8521a40742d7f9e070644f29fbd119d41e437bc8307dba87c1a5f20ee54b07fdd0a7ddf7a322cc4c86194ed5f7ddfb2061feb8cd -S = 303e5f73eb2125488fed92692fe597994b86e4189ef71152bbe277501866f64df9de78f3d11d74c6aa48a916ce2759012ea86a862966a3cb78d8ac12d0d99d059e8cd56e83c0f5198ef7248059510687e3943fd41defcd58ad501976ec17fd1c252c13a177cb99d2ed831279d6cba8ca63ad0929eef4fcc85c985bc449030a76aff7a2b389d23b89471e21907043eb6c973ed375d85871bcc9203d6c615fa78a066e7fc5ac9f8f7099ac22d5a8b26d0608df22ae0cdbabeb81bc6f750a61f5ee -SaltVal = 00 -Result = P - -n = d2b6c8fd44e7eb621fa6685fb62371872b5e8408af51bd1b44c6473823402418a26963b98e6fb191cf74175e64132ae6cd101133fc002a89c10bf7739eb930b9c067b52570842395657f927434aa3acbf3369dcdc3990f77cbf22939ddd5877f09c8aab818b80aa20544b6928fe62c78795a4160aecde6ab454db0dcdf1d6c13522526c5ccf82d429791059306f02cdc18c4e580ec6c2da19b3c6de63933ebeac79010c73df95748d987e96a0f8ad523b5014b33423f55922aec2ec23b9aa22f - -p = f260d143cff1e8e0931765da8cb335c0206bf7fd19aaf8ff41e762992f2bb0a660cd65f08a80fe502c9125166a6927aa1859a874159796fada835b48522f5795ed1f8d23f05016358ff908b0dd638bb7ed12c8b80b46aa858d52c77bb7fc0ed1 - -q = de8e674fac0b7ea32d518a22030fd10d4298a77974db8febe195a4240dc5373e8161baf8ce47dc4fd076f64e307ea6262c35b9819bac4f142b613973eeb6a62a15a2ff09fba9ce4db7186969af925ee3acb7d3be7a1f9c85358216640fc1e0ff - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 5d7f76ed239a1a5d00c3a4f4da964ae0bc409c43ce9b147b859aeea617e8396532cc2fe1ed50c20cffa2772a2eba778f0b3de4aadda26942db9315009e96692ed5ecafbe3bb98e8ec666dcea2144b3535d72c77ee400f6a0ae5421e9b7cd3b4eb0a79f8cf41fa76abfd77a3e9a7b25b21aa5eec8cafee41c66a7bb6a4ad7d74f -S = 810510f7e41b63d4d1db17ccd919547d021c0148047ae92fa3278a1fc7d2bcea796f6ad6b927df033302d5df46b3d33af70560c01bceb46502552a8b6b67e0c754ab1bf58f5ca9f96397aebd5d852c66865c399032bac358e7a990ed6dab9aec27e664a08c505fce3dca4bae2cefd8e1b35f6d4b4216cd6572f139e4b520188e8199c9e3809938ad642123c466e0d59b172217ad290dbf74e2ada78c0b7dfe639ee88caf44535a734794406fe909922442b1bcee8fa3a8e31bfd665dd219c46d -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414fe4eed9d60746feb5599bdcf486716a6a04a0e69 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 044138280eb07cf03ec9747c7e9b89e0a37850b2fc40ba6b2ae38b1132210d13d194057510f1e62c178b45cc46188d6082b8f499cd33ad2c1a825f755f92d760eb44fa89fab8fda287cbd81661def7eb81da33ed9b700209f3a6eaf7728f3c1cf959feaef58e2919349315a1f775314948e4f7f48d801fcb5e5413de94a0a40e -S = 6af0c3b45ee0b0f5182b692d5703921e779bcc5ec5e5f71fef5c480a491acd10e61166ac2b40e4246fcb28aeb5b8feb870be4a4efa13695ec211e5f603d86d33b228a41069003d18841f48aee2f4802f1dfe95caa9a3d89e5425ce06fa4d17ac2e5fe4af0e5a2f86e5ccfa21c5d1520290b2d4d4ca5096486b6012e302b2eb3cd9f906d36719f3a19e3c124969eaad2a43c2e30bea835dcad93ed550dc3137e59fd891694274cfd6a2522600c661dc496f4e4de5a58aa51afc15834de5c97e96 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 8f662067a26e81165e23ed70b145725faf2c591491ba4d9ffe8fbfbc8a7b88f07d39d0d5d55a2fb28e7f134f20cb62084a98601f0e69d257fd2064beb47248caa79720a71d461ed07ce069ddc7ecc39b65c36a62248c3ba37d6b1dc11af69d2295e9d685831a9496b1afb9bfad8edf4288153e85db0cd0ac08d7b46dc2f0d120 -S = af16b7a53f57ef673aeaf9a17727836d00e883352e7e2109911dd839ab23d46400f140af84d4cb4a5864165c682aa85eeaf4300e74b94b4f8fdbadbec540e07056b55fffc96a627939928ce5fb61e119c94f14719a93fd5f3a3dd4a8754a8bcaba64afd5e63bea1a793d420a2b6975603f2d4597b26799da0240fdb7d8b0e6e2896f63bbb46526a2f651ed17deda3ab3b43622e749bb608c6d30d41d7346f9338bbd768209e531a17e2a92b815efd222049451785565117f39812de4c6ecc65e -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = f93d6cdebcf190ea6ab2358636af5cfe4b3a9bdc1bce160bf350aa3cd3956b897e255158cd3e2e83481ce3b6f778d418764f992d48e4f7fb6d080e6b3799d3f35949c17241a0cc5ba84597166779e6a38ce45681ad944cce7c432baf9cd8caf2b33125f2c12052bbb0b3b76f2cb97be9b4813a9ff1e5fdcd478769d0ab5b36cf -S = 1e076b3feeb281e5ded58a886f653c59a31789050df263bf06401eabf4eb79b4b516350fa63b06c4ea8339190ee9ec30c3972f0009a892bc5938e17c0ad3502f5b6ebfc6e90281cdd94ee5758a2747e05d2523ba337301d392bfc6fe57890234bb1e485ecb0c2eff55c6861100b2911fe594e6db29ed773da026bea1875f334a2de2214e656f6bb25b6f84ef5cfd4158d27642f84579c1f5e185bfbe2948c2ef26e6610355e190b4c06143f487a68ff15da2f7acc9e28bbae89e9ef0c362d63a -SaltVal = 00 -Result = P - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 6f856225ba8dd27718b7c684764f2a18c19df4dc4bb9accd71a12bec7b89a337c372dfd91afecc9e678339a9915edb699f8a94c91e71f4a7c30101885203338abea8c39a926526e68f01d49597ed4db6cad35e77ee71a09814a8431f78d0094caa4f95cfeb6ae639da5b1fb150a389e888a1da4f8364b887aabe7918b6992d67 -S = 2491418adaa343b655e7a3e762737b02ee904d6d79fb6ddb9cf2043b671de59e5165f2898bace269f0e65f3e754aee71a5fa596a5a89574afa49818c7a962c38e1577f2302b75ddf53fff93ef035be0dfe14a086a27ab5a2e64808c9abc9007cfc748fac383c9c89fad72d89044c49cca11cf761d7d8e506920aeba7e7e8f187aa287c6c8878a90fbded8489789e2742a8386d8cb21f9d0b51123a5f78de74656107e562ebf50ace92da2437ed325629e66e14b573668ed6462a8ea21e54a543 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a05000414753938c49eb8f7bc120354dd8ff2177dbe9bb916efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 9fc80458af5f2489a910779f7b9d078b249a68a276219af01ac830d0d4d0b2ba089f415b7e7079eb624a9cbb8f2eec0d0d955829d71a5bade27322255ca5eddb3178b7f1d42919ac3c606c132d612eb9b886a6d705edcb9d506e63ca32d0687b223caf403bf1cc75403a30d0dd9d94362f569bd38704b2696ba13be8deb7ec40 -S = b23c38a05b861aabb41227c23af9d3b6e1767605cdcaf1627875a7ce09f99cc4b7397a4f010a3bb2d8a9c9765b9877f936369d761a13dc3c22c0db84a3364661b5c7fd39e6965e43a728069daf89612dd8dec3dc9142d6987b8345579d9be7891d315247955f70ba789d3650947de9e92948e049696a00d0e0f6d256cfa24128be180ead9af648436c1cd21d0b396d70c27c94ad8c8625b6b3dffbb3ff78c475732203c8d08a3f99e7dcc86f1c233131571210e8135a29565761dc94e77bf484 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 5d7f76ed239a1a5d00c3a4f4da964ae0bc409c43ce9b147b859aeea617e8396532cc2fe1ed50c20cffa2772a2eba778f0b3de4aadda26942db9315009e96692ed5ecafbe3bb98e8ec666dcea2144b3535d72c77ee400f6a0ae5421e9b7cd3b4eb0a79f8cf41fa76abfd77a3e9a7b25b21aa5eec8cafee41c66a7bb6a4ad7d74f -S = d1b5a7c9880f3b076d635ce4f881de6c715d0e2ac85fd08ad5d4ca93f2b04870f7264bad5c7dc9f38046b7ce0bbb4fb4e6279571533f61cde6d540c6e6bf69e4869ab76a563f30cc6718cdef849f76c75aea4c9a3068bc579b1104474d9a4849d9c3db49fee17afa5281fa7ffb848e9b33835e942e89c04e291d123f5d2bc5869f076b550dd8c04d2c2f29ad290ae294ab3d34ef54f5148b256f50c54f14dbe4f02e2aef97e39a90431b774142b3dbaae385615323badf58f309e70a1084ee59 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c7c8aa165fbd14e4361a3bdf3f9b6bbfcbc8e14153c901f8e2104975b -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 044138280eb07cf03ec9747c7e9b89e0a37850b2fc40ba6b2ae38b1132210d13d194057510f1e62c178b45cc46188d6082b8f499cd33ad2c1a825f755f92d760eb44fa89fab8fda287cbd81661def7eb81da33ed9b700209f3a6eaf7728f3c1cf959feaef58e2919349315a1f775314948e4f7f48d801fcb5e5413de94a0a40e -S = 6883e11e659c46bbbe5a9b3470adfcfeb546bf008d1f2f272e2b3b957ffb52f6d25e0a1aa4facdde72c103566cb6b898a9f059f17b895ccca14aff8a658591998e8f106dc8624a48158e932034f9f3fd4f2692e37ab8a31d02831641d0518d4557f2588f394eac4a54510b4d4397cca2f55e7b8e08f7fbcee8a9f1c60e4f6a8fbe30b3b29bd7492aea116701187d6bcc9c91979de68b52e7c6d57e4fb9d5fd6526497be575ee861bb83e05f5b51b9cd60276d93e6fe987f4240c610d94aedb49 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 8f662067a26e81165e23ed70b145725faf2c591491ba4d9ffe8fbfbc8a7b88f07d39d0d5d55a2fb28e7f134f20cb62084a98601f0e69d257fd2064beb47248caa79720a71d461ed07ce069ddc7ecc39b65c36a62248c3ba37d6b1dc11af69d2295e9d685831a9496b1afb9bfad8edf4288153e85db0cd0ac08d7b46dc2f0d120 -S = 0e53008d7626ce138c6aff6c40eb86dece247e192bd5013880e759f96142d22d18abb6f1701b88aa28d53b0c5c13b91a316e79373a37ecfcd61df7d3c34b59ea36eebe0c6864ef63514e504a8c796780be8c2586f1a2eca3a45d45b15c4c38f94420ef563efd9fe2d8c194d01c7c34cdbd7f89923bb39bec9e8ddbb1a282e1ee18bc9cc93ab42c2dbe58ff0927036d2a66e364d88354571b75fd11f131076d6fc9c75b810b522d2c18faa4a6332cf82122dfdd17f5efa030fbb50177f97c9bf9 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = f93d6cdebcf190ea6ab2358636af5cfe4b3a9bdc1bce160bf350aa3cd3956b897e255158cd3e2e83481ce3b6f778d418764f992d48e4f7fb6d080e6b3799d3f35949c17241a0cc5ba84597166779e6a38ce45681ad944cce7c432baf9cd8caf2b33125f2c12052bbb0b3b76f2cb97be9b4813a9ff1e5fdcd478769d0ab5b36cf -S = ca58ea0da7afc7dd4a1d32ff168a03b478f296dc0f6edb2a0e859d85476f1af70d21b42f0af6fed26cf82604f8a2c5d87b50e5a5babed6d585a6a84861ae56dd2654c4884af6672ef57c63d8b03e5d7cb8ea49e6e8b53051cc64b366dab0b93fe29dfbcd7b9a0b8885711bd103844532f08ddc2edea7076e36e7ee25eb592bda6a4f862af008344117f5c51073407a8d230f2ab5aad9c981ad10842706b502f4c984f2f969dfb5090678b602b4748004984fec3a39779c2f5ee1b02c6eb77dcc -SaltVal = 00 -Result = P - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 6f856225ba8dd27718b7c684764f2a18c19df4dc4bb9accd71a12bec7b89a337c372dfd91afecc9e678339a9915edb699f8a94c91e71f4a7c30101885203338abea8c39a926526e68f01d49597ed4db6cad35e77ee71a09814a8431f78d0094caa4f95cfeb6ae639da5b1fb150a389e888a1da4f8364b887aabe7918b6992d67 -S = 1a524bd769380e63ba31ebc0adf908a5c2b657b03a534da42eae48f044ecd2bb643f2ab320b34df4ad0938e17044d9e8a40c0b50d696024e0f717f19102f82854c626642da58c430ac865d3a25299f5d8864b418a172b331734db2efec8e44d082556d7d37731e4d4a317a22a076caf9f9e9854c1eafbdd57fae1822ab268076126f55c3ca52873885f9be15c0308210465b78e34335d6fcc569c8e4ae0f65034c0d8ffc1f078983e15e4b2bd7f46a0bf41c8ad7fbae341037c2bc87c2248060 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c3634827aefd0d0bef3df495c39e6d596907496b91679e2bd96be6542efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 95d3ac5ad05aabd72a1c331b0bb6f75ddeaef4f4b0b6a6bdf92f7bbdb9ed8807c73a7ae0661dd0221adc48debabf9745c5175dc9f97f587f2262d8c831bd73308d26f996ae0eab8ee743a70383b8a7211489eb71083a74467d40735957c201b08fa010c4cdb5a2e23a5939d28f2a8eb7730d8536036f61dab2d134b753839a4e -S = 15893719e5cd0ceaac13914028cbc46bcfa00171d18041371ee945c546f10a0f212231090f4ab7f490ac852bec6ba820997d71467b797ff9a09af565794a85c15e3c10aac19b91f6a540afcfeca49f1660a788c2ae040a907146b4f6179d808f96da06f15daa18cb3be6b2ca0913fa91e966652a29360dc41e50c6c43ea5d633532d264b0ca09987ff3b0cd1542b4a6a48332d434ee3f02f9e0ee353d2acf260a3ac278de0ba65677b44911ec76071f74a5ebfeb33107a01fdfecbbc4645baf6 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 0b9c18c93a8b1b8fbbd036c2d5a6869c2c326e80e613df300d3ad74034fc28cb5e657b641bd0944ff4b4d8f209c10c86f92c5f120247ab9a6a54f8931d9b429b97ba7c67043dd4fda66e3923786e1a1711857180cab701a52398dbdd636127467f4221ba3dfa62ff99a6613e68d639b73be6adb2868c69b902ad8a044f756135 -S = 29dff9f009373438341a72589399904fab9b900a2bc65c371c989dd60e9c825dc222d982d773cea97be3a3c378956a91240b23eb59a4cd5b78d44fb948bc402db68a8efc3d9d7c48b55a826bab47ef4b605c0ff33a7019d8f1e71a17b43a6a72a57889157c15d10d65152a7581b8ccc0c09b1dd284d9da78786853bb8b88f4458bf178e05247713ed13a6bb7080827a1f4cc85de9a8b094f9c6edb71e8e3166d4907b786fc64d97359907661b6e63e6c1e415e9d31aff0e43a47e5830fcbd26e -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 5c27ae4e00a9253b8e43c744e235654a6ff72a1cd37acfe0aeb10fb5b5505b9602d4ce81aec363d9a235660aaa93286bcc9ff768d7b44de03e4f48cc27cf5a22c07942f9d2bf3bed98c273c5d115be5314c48c9c64951939048de3fd8cb661d83d20f2fb9226143d17f2d6be7e4490caf06ed100a1a499b3a772c8900c8ed781 -S = 36b438a2420cd0683b040001f926e499992d21be6d6315302123efc80d63d9182f014fc8e8cbbaa70c5875f2e7e7127e5925eb267948101ecca130bf0846f2c4aec394faedba13ec6cc19e476cb31c2cb025bb188127fe70d240fed47d674f2d5b2c3b4660b08242ebb5c005bd1e836c908121f0e73dd80a18668b79d05783c521d9913768296b057cdad7f408394d080e46b74e72c6d337b54c6ff976af2eacd7ce51f3d2432f3ccf7b55b074cc2817272816525b91264c96325f3145324cea -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420cb6adea7aa43ed6220f5f0c4dce57facddc4f77cd4e9072b0468da9bf104c1bbefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 8bbcc23dd3ea4ba9c1d1c8e052be5d49e1f358c657050a3b9e83d64a59d88761d273e6f733258d12facaf60da72bd798b723b200d601a7b1512e8ef9ca10420e2f2d3f53ed9470d76079421e8e1ffd2516fb54a063163b8625b3f8cf02327d7d8834f5d967009dffdd25d59c716177f7e4c2672e650b6bc204593d566906dfb4 -S = 3e116c20ca4dba97fd0804d5ac89cf75bf53a71c77af12c2301a1c093aa269a9074f467c57727a5c0b17f18968842f98bb11d8b4afa9a9ba193c0e8f2d2853a19293c310ad2a5e792ceafdf307959a50fc48aba8dd911b367614b26b1a19ef13e37a4e3eedd4229174d7e6184f6bdc4c5d24397545709170a72fe202bfac3695373da28abf90aa1dec9ce1ecf4afa22016c2b6b65e65a5ffe38925ebebe49e4def0133916b4c22d2225122e1d77703a716da7cacdb85d9863d53c039da1a1c44 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 676a410de221dc39a833bd94dffc5b06dc4ae2613b1ce1452ea9434115a4813a4fbf1611506e3280f4edb24513845083560a176549a81b04b1df668b1fcc3599c5ab65e6899b282a58a0fc3abdeede74b265ba5eb658278a1f9251bdb29b364f713716d5b43024fe7b5582bb03c36ca39763b495a9b46e9f21cbec1ef598ed27 -S = 34f5337351298d299f64828163e2c8edca0bbb1e80d8da4141c3aadd5827d815f32ec5ec6696679580f92d1e97ea7cb85485566f061a4eca830c22f01f9d952d33c2aea8cf7d1b49d426cfe029f2c52a2789e9031e015ad74c7105d43b9fa603869e850c6be898830ce1a921430cede5f1312de7bdd4edcde835f32102ec28628ca49b5009fdb5ac03c6ad077c77f66fae2779eace6908c4fb5051d82255e7e50920afd1692f1c08d61d233f47e8a7a1e342d39fbc8ac527d96a622a2812f177 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = ad82f5bc35d0995edf617b3b05f4ebabb0444cdb678980734541a1754f30f26804a615b735007e54167127a09603858fecd8bc0772b60f8ab7c39a15cf8c4348ee4ceec6366cf0dfcc46c66d312e08fbd0b3982dd3221f5c3b4cba803089f05395fde8b3e01ad8482966c168807f5a37845c491332d5992ffa66697d1830e1d2 -S = 8dfd4ce88f22ca5c7faee59e9c0c319ce22581108d1f333a4f53c239a840db6cbd9a18d1be3d211bb2a7dc69d1750aed173a50cce78d4b8ae804525f5e3dee05c98d9e1debef27ac43dbd8faf87607affdd97589995cf062c7f3b5c1ce7dad7c200c3124fdfce5f05e0044ea952e54ab642c47e0bff3f80cf96f0dcd08baabd11152b8741d8e700c27d805ee6edff11f95b441a24d65bccdc6949b91baebfaf249762f61593974813bec018929b51cdaa89df092b38422e2a82aa7cc8a22f971 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 75025b7ff7978e537b49fdbc59a54ce3e8313c96885ecce3e6b8a5e67b60b4df56bc19871c6d40a54d814ddcc8eabec7922f4b48d362111c2152f0b30101323fab596d0c0e1aaa0f1417c6c127a2192ef44556486fb3b28217fd499a7b09bdb6fd4120b3d68814ba5a7230147db4a63f97d923416437f73c4f227643f05f9e6c -S = 1f435cd0b2835f4a895c2a53c4a9cf8561197c90548881f3150b7f2247ce7c1f0fba20dc1b3a265566b2cacd6ac66f087ccbe11776168f382ca2cf79cf97420ea665c5cc547e250a3582febaebf9b4ec97a1cf7c8f1f75e75e67454bb2179d6fe1a66a1ca01091134871f8886eda7e72536eb05b3ab352f8e775f94a0c1c3060d3932200cc10aa07a282a2c540ead4be9c3b664da3adbc4a513e5363b41e8e867d2c348eaf50c37cab0a1ad9f7e32dc48f1ed90d2c4fd88c7588f3250e9b582a -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d0609608648016503040201050004201652a7df9a92d3bca639e5b379b1bad5728d06fe2ef755fa734a1f09be6e782c -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 0b9c18c93a8b1b8fbbd036c2d5a6869c2c326e80e613df300d3ad74034fc28cb5e657b641bd0944ff4b4d8f209c10c86f92c5f120247ab9a6a54f8931d9b429b97ba7c67043dd4fda66e3923786e1a1711857180cab701a52398dbdd636127467f4221ba3dfa62ff99a6613e68d639b73be6adb2868c69b902ad8a044f756135 -S = 49eac9a68c0786ced77b437b01a3a562a5d6e6fbc9728dd513814cbe611f3d1d4aeb4540a61853595964d370406f3a18fc6973387c99821c8e966c47bb6e636543ba7940b1c0f23a8fcf46ee4e3173dd39980088b0fb2479ee4a08b41b2dff7b3ec1d2989bae39f7abd1bffc8d33155518ea6968b6b471c90e6773c76c6fe8cbb1fcc138dbd48e9eda1090ab245dc2b98fd7c553a7bf11321ef7c77fb14f36e5b7c969abd5e8c049d2ee4fc3f08caa6d996ee0580af6cbe27c2fb1e0bf3d79fd -SaltVal = 00 -Result = P - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 5c27ae4e00a9253b8e43c744e235654a6ff72a1cd37acfe0aeb10fb5b5505b9602d4ce81aec363d9a235660aaa93286bcc9ff768d7b44de03e4f48cc27cf5a22c07942f9d2bf3bed98c273c5d115be5314c48c9c64951939048de3fd8cb661d83d20f2fb9226143d17f2d6be7e4490caf06ed100a1a499b3a772c8900c8ed781 -S = 2a7d47940bef4582f4edaaaab4b0181c76c091179465ec3c007edef88775986ac07f85b4fbbd68450ba9dc346f590cee4ec1e828978d82c5e0bbb87df6f8c548ebbe64fb4f101bb8cce618d88dfb96f3d8d5efb0d6f7dd67c8f75eb068005f47db66d87c33b833dabf7dbd02b3b327988164f436a0e313efa3cd124f87730b463962b21b5a4e3a9530db7ea0ad8d3ebaa23414aecd343ceb58e324a1deb1653e792ec5a9eae709d77b2e55b6e8b5f653a8044882d020f5fa8520afa588416d67 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d060960864801650304020205000430e1d3f55e005049c7d99593b81a02de751db47deb6bbd6cebef963164123fce991214c8be6828cd6caa14964f293e1245efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 8bbcc23dd3ea4ba9c1d1c8e052be5d49e1f358c657050a3b9e83d64a59d88761d273e6f733258d12facaf60da72bd798b723b200d601a7b1512e8ef9ca10420e2f2d3f53ed9470d76079421e8e1ffd2516fb54a063163b8625b3f8cf02327d7d8834f5d967009dffdd25d59c716177f7e4c2672e650b6bc204593d566906dfb4 -S = cc5bb97aff280fed4499d2fb96d5acdee24406fd1d80217a0b6a27f7324f4728db0a4a6f996addb55ee8fd2fff1aa109d7293f5a7954a08857e53941d1ba0a86e1c38ec61cf9d54c2ed40c281475fd68dfa1aaf0c246a05959465c89bef974df66fb1f3228e07fe03eb7b9546c6f09dabecc6f2b8f2f6be058186578d87a097aa6a0a15f98061d4d1a1ccb67a9a6ae6b35e264e591a8115b459dd392d3c1f6a6785ed3c97d319d19b562da148e7361ee261c2991ca09ea924d69d5dc59f7beae -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 676a410de221dc39a833bd94dffc5b06dc4ae2613b1ce1452ea9434115a4813a4fbf1611506e3280f4edb24513845083560a176549a81b04b1df668b1fcc3599c5ab65e6899b282a58a0fc3abdeede74b265ba5eb658278a1f9251bdb29b364f713716d5b43024fe7b5582bb03c36ca39763b495a9b46e9f21cbec1ef598ed27 -S = 4f43d98e1a988f7b64d37fb9db79b1759e1b971f90fccd542d636f04c4f8e35c3f07d941c906f8fb788cfdef25b4438a5c9322ca2230e62b17e618dcd7a4669a187506dbd2087cd25da81f351cb87430163208dd06bc3e5b7a36559969ebbde2200f8933c45cb327f5e56e1c36bd15d11ebc7bd0034cc2fec3a9382dacd61a715c1f2f5babbd549faf752d4515e4375df0aae487327b765b45e82a868dc7985e03bbf1e6c80d022562c7e4455db4463f42fca3f2bfbe9f6cabeb3bb61fe0c073 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = ad82f5bc35d0995edf617b3b05f4ebabb0444cdb678980734541a1754f30f26804a615b735007e54167127a09603858fecd8bc0772b60f8ab7c39a15cf8c4348ee4ceec6366cf0dfcc46c66d312e08fbd0b3982dd3221f5c3b4cba803089f05395fde8b3e01ad8482966c168807f5a37845c491332d5992ffa66697d1830e1d2 -S = 5028c5c1d6558214048ab00458a5b0308053d91b312c671a15a47ebc32dc85b9760202b7f1d81549fe4c76d48318655b376e7d2398be7693f530bc28611cd48a7825759641c24fef6af1376d0d7bbbf23b9753dccb810a95e4d988be0c3c694f445f47e46e2aed98223c0583fac02cd9330e5652a697b07338193efe9afe1a514786c31edea49654d90d87d7caf26978accd08aa2272e12dcb058296c032fae8c63c736bcf4837c1d0bd2deb0a9539eea5f376aa5d1593afd8a0bb48d44bd5a3 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 75025b7ff7978e537b49fdbc59a54ce3e8313c96885ecce3e6b8a5e67b60b4df56bc19871c6d40a54d814ddcc8eabec7922f4b48d362111c2152f0b30101323fab596d0c0e1aaa0f1417c6c127a2192ef44556486fb3b28217fd499a7b09bdb6fd4120b3d68814ba5a7230147db4a63f97d923416437f73c4f227643f05f9e6c -S = 068559fc0164a646aa07337ac8d98cba1da106d4fa951f408315284f4b2138037687b87c33b38d0e180ccd62bfe1baf2c42f72b9750d133502092c42a3faec6e42f3059ccb5cf1b3db1ec2c714e12aa0c5ab612a4d0c913ada82c98015ec761e7237087e2da676cc92e3340b2f31b13b157bb128b2a6afbd183dd67d5e1bf8bd041e580ac6a3fb8b4ab280d182ef906fb247c0d174076da4770eb10b13163c2e53f0a5b8a0b2352de761677a424fd5d71a4efb54b49ba6e2a96b9aa740453157 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430d7d7bfdf4dd5cfd15b04f924d4be54564e72e6a2ec5cd83b24866b42a01970acc7686ba35e3f9fc29f0fd53fc5254104 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 0b9c18c93a8b1b8fbbd036c2d5a6869c2c326e80e613df300d3ad74034fc28cb5e657b641bd0944ff4b4d8f209c10c86f92c5f120247ab9a6a54f8931d9b429b97ba7c67043dd4fda66e3923786e1a1711857180cab701a52398dbdd636127467f4221ba3dfa62ff99a6613e68d639b73be6adb2868c69b902ad8a044f756135 -S = 3583422f69bf11bb8c8c9e18c40cf2fe3d6930b174a4d8efcca214550b525f7d460077d280e714b8297378a9d228226c719f790961999f0532d7068ac8d51dacfae64819e8b7eaf618ddbc33557cd8f9a3a1e65efe8a4d02654bc725b1aa779ba54b1b9445488a084b9614d8e2c9a0d559a217c6427cb62a6cd8a255512bbdb006427db49b1a3698b643a21d65cfea8e624aefd38f0a3700687bd035028bc161f5eb005cb66aed2fe59110108140b15d6b97567b72b1c712d6fd030872d50ae4 -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 5c27ae4e00a9253b8e43c744e235654a6ff72a1cd37acfe0aeb10fb5b5505b9602d4ce81aec363d9a235660aaa93286bcc9ff768d7b44de03e4f48cc27cf5a22c07942f9d2bf3bed98c273c5d115be5314c48c9c64951939048de3fd8cb661d83d20f2fb9226143d17f2d6be7e4490caf06ed100a1a499b3a772c8900c8ed781 -S = ac97f3f6ebcaeb77a23ca3b9226f7167c7315e5687391b700f21e45a00b23d7ad5834ef313eb3163b2390ccc63f9d76274120c1f0380747b33c1c77edb3e06923482e39b5c964f8499c20e28ed3fb064990190cffd033ce3ae384c275298367baafafc5e66bb0cdbad6e2cf9b16a393610f0088c129b75b88da6207bfb8570425e38b9f2a30d24f4753184e36ce0dde7e9026fcee5cb88f70c1bfd3b9a3f0a0c6bb80a04266c2edb3ca9c06a37cbbf77c1b50c01443c9282d023309a1668fccc -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d06096086480165030402030500044068ac2dc5d380018cb50e8316dea0bd72d31a9c354b9185b1d227c6540be123d48d79581880a02e2cbb7166289ab6798fd3215b272fd171bf16f74af65de4a360efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 8bbcc23dd3ea4ba9c1d1c8e052be5d49e1f358c657050a3b9e83d64a59d88761d273e6f733258d12facaf60da72bd798b723b200d601a7b1512e8ef9ca10420e2f2d3f53ed9470d76079421e8e1ffd2516fb54a063163b8625b3f8cf02327d7d8834f5d967009dffdd25d59c716177f7e4c2672e650b6bc204593d566906dfb4 -S = 5b591910bacd2f0bb6b2052f81445397d2056d114924a306a2b24c4fac2b7698d9ad725cec3010d57b11795f7654969a86f528709655d07a336a68fd4cbbe6ffc95fbf1a6e6c17c2d627c6011e4209f406ae7f2c670ecf4081053c2283845e2c855938da5530a146a1ce4bc203d0179a19398177534c7bb37cd9837911e8b1e7988b800e8046864fbf95e8c584a3c4209f3ea5fd535ba58859ff128fed9d0fc5be8e8c2890a71e38f3acf2a1fb537cdc87f53e3376276c8cd501d21069e453c6 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 676a410de221dc39a833bd94dffc5b06dc4ae2613b1ce1452ea9434115a4813a4fbf1611506e3280f4edb24513845083560a176549a81b04b1df668b1fcc3599c5ab65e6899b282a58a0fc3abdeede74b265ba5eb658278a1f9251bdb29b364f713716d5b43024fe7b5582bb03c36ca39763b495a9b46e9f21cbec1ef598ed27 -S = 5f6b11ef4b5b0a1bcd9cdb2086c60db19544dd33aac813ff6ec628d9de0ab882bab6496b79477cd445f71686f666b9e041e2ac40959ad94d3df00b1ef8c7ac3ab68b1d2e07294b3aa54bbcc1039b90dda11bce3aaf66646d19a7224028dbe7b48dbb67dece2812a5bf82e89db0908cb26043b78ca5ba455ab680d3d6aa4bd1682b39b5ff744a65dd5cfa909d1b71218a48d88e4e112a8b959b1886d956610d915ef41b30031eb3f2acf7d42387db245d84ada17b5995711ab2e12b8ffca81905 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = b17ebdbb8027c2ef5e5de76780979c65723d73c0ff0227d95074ded158d1abf96f1d578a3c716197d996433f32d3f727ae02ba2812e91044a2c808df892fc12b7a122de5981f153f934f5d1d14bc8a835cb2814e28089123d7b1b4a6ce8e12ec1c86c7325ad9e6cfd5b1be67f0fb5c62c374519c0807b55e38566b8ef197a722 -S = 1e80b47f34629c79b612fa8d25483056d1475f5f51c50ac60e8f5eade21469dce676d13b32140760d828dece21cd9aa2381b40f42e8e20a77392713f5372d1e87fc131eb7367b98d92a76e5276bfd073d6e44f8e9cf81e175d531e6ad50dbf84bcbb636b378c3342ddf6b2d85c3d27b2afe449c40f2915515c4c417a633b4de6c30e86f49f8f5dc44427642aa0c98e499e321aebda279a7321836a3cb24ee90c08c9e88f7745c19deb0e1de72b4da5734bb137414f1d4b1c78a9c2e58f148105 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0e0c2f8859ed53f57993a08eea025ce6e0c208cd61057301d1628d4802599c01a46d6d0c5ed43f09b87f34c206abf1cb1ebccdf2662224f81defbb29d761adea4006e9f16de6ad09f5b32be59d1c6a51dd03a41ec8c5eff6eb768b481fdb0908591f902492fb603537ca6292888ae060bd38e8a9355a175113522d7993584d142998ef52f6add24f1b5e76031844d322ec03914d8c7a26e7a38e63cf99164313eafca2709f1107a6c57f5d49913d20b3bd8c2dc850db453c3a23b00f18ca724b -Msg = 212bd005a8e8e13b0bf4620ce2d3d6bbf18b3d195b05e90412b78d2e92809720cfd3bf7e6b18e08c2d4f07f1aff7cabb562edca48719de931886776605d0a6ef6503573c9c41351cd165c0dea3e59f5c17fd3739d50a7c66953407ebd44f6ae4cb03c0c9a12b88f3e07cb35c2667fba71d407760ac9f6c846f07674465c58806 -S = 6db765c50f9ac9da75eafad6652ddb99e62234397fb2c96769af84da59cd408c12b7562104d9ce9e7455e06abd53af83da43406c64bf15d37ead519d6b3a12cd5e02803c92eeeff2312cc681d53b22caafe9ed5541db754772fcfff3ae53cf67d07b8eda85202a36db8cc01fad12dc3b455bbe123f9ed7c3873c0ebf25bcd55dac7002c7ad1d00eee91c58c357276cce875ba1719b2356ad821d278e9a62ae1a6e22b145ce2c072a1faaaaa8ad2ca4ca807eba3d420af2f3d915993d1327c940 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d0609608648016503040203050004404be226f7beb9c592f2429b00af0b7dd3de42b17313c58ab7ff24fb441e6e47280fa6f5ebf3bc14dc60f8754db42c984e4bc5077fa7b559d727938c3043453166 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -n = d2b6c8fd44e7eb621fa6685fb62371872b5e8408af51bd1b44c6473823402418a26963b98e6fb191cf74175e64132ae6cd101133fc002a89c10bf7739eb930b9c067b52570842395657f927434aa3acbf3369dcdc3990f77cbf22939ddd5877f09c8aab818b80aa20544b6928fe62c78795a4160aecde6ab454db0dcdf1d6c13522526c5ccf82d429791059306f02cdc18c4e580ec6c2da19b3c6de63933ebeac79010c73df95748d987e96a0f8ad523b5014b33423f55922aec2ec23b9aa22f - -p = f260d143cff1e8e0931765da8cb335c0206bf7fd19aaf8ff41e762992f2bb0a660cd65f08a80fe502c9125166a6927aa1859a874159796fada835b48522f5795ed1f8d23f05016358ff908b0dd638bb7ed12c8b80b46aa858d52c77bb7fc0ed1 - -q = de8e674fac0b7ea32d518a22030fd10d4298a77974db8febe195a4240dc5373e8161baf8ce47dc4fd076f64e307ea6262c35b9819bac4f142b613973eeb6a62a15a2ff09fba9ce4db7186969af925ee3acb7d3be7a1f9c85358216640fc1e0ff - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 34d9afccc659c8f438830b2fbe8b6600dfabc007cb22e826ee7dcbe2c515eb0cf1d90ca08a4d30edb5d3c6f6792a1f19ce3421eef7fc3f7212f7a965ee8abff01ccdcc8b498ff11ecb9a5f667937c99bc0f51a50f3a7639ae3ac1774b0737a62de3d5755ab25f1cfa05e3d4767bd4ecfdc7711f4662b3ae688237ed9b3d703aa -S = 38fae4b9233682065387c11829b0a9747217bd7d49acbb5957b8e7d231235f4f7ec316b5a3e5f4f8f45c8b9a161f9b8d3bed9aec0a7b0d4484474150c8bdf392172592c1d0b8ee2724d08aa73a32afad3dad1a0cac3a9f21811f53c69809239c26e36c7b6f4b3a90dceab045413dc3e89fa1927cc7a622e55044a3417b44ff93b2faa3c864c6fe519fa1a8189121a4881e178979096f17519203f0d2c9313a70b2a5b670b675319ad0971a0728f0db729fb5d50280a33fa201271715b256515f -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 95e2657996a4fa69f824ca49ab5a7e6ebaf498a0dc9eaa7f4981c51fcc0935f619ec6bf862683b0025cc48724839bc1e67aa3c686d321ba66185cdca83ba9f41984fa61b826ef56b136e13f1239dadf6e03d877866ccb887908917ef0d33f117b614fd291e3e91736b15150e650db9bdcdb56317f0f5ebe97c938bd691fc9140 -S = 3ae81b95c93a702dada5637e1c4113e5c37a8a24021bb2371c788a90ce8fab1c063c7e17f7f570a25baa9adfc78035d8ecc87219df1bd30c6b8b593682f354db71902ce23faa18f4af6fb9cf925ef7916c168f7298d56c49b6c68da954b56e2164ca37bb7c06498d6ee96aa502011356fc48733b937f299616ecba6699fb8d3d64e332c0fe3f9c58c18f033f92f237940afe9101702af51d3cc220547028eeca8e2d4f46ccb400f0620339b4da7d415ea288bbd7552eef2e68e4ca7c4ea6d011 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 24b78a630dd8cde2fa183956b3edff7e0ea5bdcdc0f1f51172a3bf5218b7bafd7e9048422385fbba4b9c4a4d50958953392b18f98d96dae66a54e81fd12987284465586d9365cfe0f35ce6e250541367e46f77550973582e4b85d1efc235c8389fbb21ac0480319b19e176df5c2f850338fa43abda8f582f40bfe18a92e26573 -S = af9d6db0d610643147996ceb4e3cd539603b068b02eb31a70dd83d40d45f88ba25edda65873271099965fe67758104c2e40b93a8aa3eaf1277fe0d0db1c08de0b96b82c9b48f9a2cac852124de8ff81a7d9742365c8e7f68e94b5d3fbd3aca0e42528b0693f4c61aad95cd912a53545a785e08464b2f675a4b1a5a3c53a8acfebcb25875f7afd802f6f5d6342b1bef4c848504b40a475e56ce9b967175dd9288761599946838617dcc57ee43e1b99eb47be11773cd326029cebed368f821fd4d -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414a651b5b5a63ddcb4142c5f673fff0619b853c194 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 165c3a41385c453b38d0ce2eef3a1fd2863535b993080c84847b1d5641ea24890d9726a0ad44b37dcd0269d59f44b9e0c537ee5571566a95cb39332693adaf64070aac7307c1a37877353e09e5cc17e26b45c3d9d74c0f140a4b89799e844366cc5dd3a28cfa9e94fd1157b308fac23e4006be2d0d1282670a5c2735ab9567f7 -S = 56965ebb90a59710f86a5868573132bc39e3be28d7b5c1e588bc2c80799a0c89c17dff65d281b7aad6c0c4dedc4c134d022512b3821e057f51e27105858b2ae063f3cd0b4204b326ef8ba52310a3187a2effb3295a848de5d06d73504f71c6a91c2edfa5b6bffc5b140b031957b7bb26055f1cb2a79b89df8b1c31d9a54d96d546fa1f77e3678efcd9aa875627419d1dd38c1fe743785739c8bd0655b996f5bba23604983385ccb75640fb0c6b128c2e117e9a5fbb7b25ab1d9e7a2db644113b -SaltVal = 00 -Result = P - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = e2c50870d442d577b5fcd43778e9ac0e13f62ae7d506325ffa38fc267d697da72dfb22eb03d4c4bab3a9d904817ce78056633f93138ce773257ed88c5aa16923f2010c39fa4f38b2d529a6b61c9ac058a8e55775ec7e94df885a31bb1c68e8285a602c2260bb18a54402a515f04c1fdd3003da5709e621ec4d546f7c6cc7e2ff -S = 11875488140cf57011ffff2c42926d00a8f2cae3367360ab338c96aebdcf9cd95c091840c416039f58c8a5fc0cee32432a673714f67baa42d4ba6150054dc88644d5c133903fcf02ed83e196078041bc96f2ce785e0759f0a7ca80f41c2c2a97196d0e4763330b74355d8de3a102538e1b4174de2ae8ac71ac14f8e0a9d9d9a71a34b953c0977758c43fe96a3cbd9ba00b52a72fe464b485d306979685db3bfcdfbec66425dbd20fd59e0985458dd4afbed8dc4a0756f38c54624d86ea71e9b1 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a05000414cb9ea455374c24f698ff1b23b65a9a0e1980c32fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 2a5853c37f9428e1879034feb2d07a5c454e9970f4c1ff43b21f5918c8614d4f24866c89f4da620d7478706b040e1d5f7ee028f7c610c0f8a31cf77fcda875e4477e69e3eed3c6fe53ccab1dc6402278b3c00eb632d45f56d988884fd42733f3384733199505ba7bcb92cc5d1eeff3708cf435f55d974325fd6bf3d10767f046 -S = 616e467f569c1af563d7775df9c11116856febba4a4b7f801945b702621bad8cd599fe43ba381e02a67714244c0961c9cc65b6f842c2391a439ffab1d262ab0896e200493526f9047e3bd77e1b88ec854f8075bb54d7ebaa1143b4adf05fcd1f7873e036f464e73b4761505f7e96d6e80553260a95449dabc1e45f6e5079ea6fbfb8281c693005d3214e175ed18a9f5e70d7a59e87381611aff9cc82964bc6e68735bc11277f5c2e00be2d089511b12a32bebcb96ed91f4e158989b3869eab4c -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 34d9afccc659c8f438830b2fbe8b6600dfabc007cb22e826ee7dcbe2c515eb0cf1d90ca08a4d30edb5d3c6f6792a1f19ce3421eef7fc3f7212f7a965ee8abff01ccdcc8b498ff11ecb9a5f667937c99bc0f51a50f3a7639ae3ac1774b0737a62de3d5755ab25f1cfa05e3d4767bd4ecfdc7711f4662b3ae688237ed9b3d703aa -S = 238a420dff7b0b18fcb6684933c38a9401fb2a6f8fdbb42b786cf5acb08948a46e42197fa690a613c8c0ba530d57d4f3fcdb410edaadcf995377a4512d09e5dea6de8e8f553d7694705929b012e7de002c95cd670f47890fb2077ee5a4c819ba2438d0757d8dfd1d0a83e4203672c269ac7a0c1e9769cb86eb3c9f5d7cd81058bcce66f1e3e7f47e1e15f000a02a7c98794f383c9b8650cf512b3040d1b6ccd638f5c8aa891228ea870177add8a9e754fe1a5c97f01f945dacf851eb6eaa0219 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 95e2657996a4fa69f824ca49ab5a7e6ebaf498a0dc9eaa7f4981c51fcc0935f619ec6bf862683b0025cc48724839bc1e67aa3c686d321ba66185cdca83ba9f41984fa61b826ef56b136e13f1239dadf6e03d877866ccb887908917ef0d33f117b614fd291e3e91736b15150e650db9bdcdb56317f0f5ebe97c938bd691fc9140 -S = 5ae8f7c7b9f7002e048f47d7471f83265860a70e7da64a9ec5053f07e9d92f2af5d738c79bbc9924eae62eb723edca05a965f48946573323132b482c04810d521277676145e505b515cb4fbf2f783e3f71124300bcc96963536ce8ca83086a004e4963b8fa52c4101073d252bbc242fd6e0648b61edb394d84b01f1d7bb28f24b65e89f5acc881b6d30612105f143c0bb871193f70d4217a1e283285518cba57ee85a3bc77fc9f481ddcbd5a78144685de81a6828b0a253f17929ce14c4cdf12 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 24b78a630dd8cde2fa183956b3edff7e0ea5bdcdc0f1f51172a3bf5218b7bafd7e9048422385fbba4b9c4a4d50958953392b18f98d96dae66a54e81fd12987284465586d9365cfe0f35ce6e250541367e46f77550973582e4b85d1efc235c8389fbb21ac0480319b19e176df5c2f850338fa43abda8f582f40bfe18a92e26573 -S = 6fafddafe9df19c45011ae4914adda6bbdbb20b43106d6d81faf1121c6300f9f9f2f87991b27a79d7ab8df8466539d4974d5cd379413ff1f2ab1f826ef5a6b128966fba4000593ce924132c26e3cc2734c38536178d34d90bb141576b80fe2ef1c4be81fde648d1aa3a4f537bcf815edab3cd3b44f7db09e7d5f73a17a9af84500c87d33b9d1ec7854852400c389473c8a13f70bc37bac6f75ce407996a3fdb9489fbcfb860a8b4c7280d3795841cc325fa0c9ce025ecb3f0c2d6c18a44c8ed8 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041cdc59d2d30fcd76a4ee2fee88ea165458725b7796e06af5a9bd13f257 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 165c3a41385c453b38d0ce2eef3a1fd2863535b993080c84847b1d5641ea24890d9726a0ad44b37dcd0269d59f44b9e0c537ee5571566a95cb39332693adaf64070aac7307c1a37877353e09e5cc17e26b45c3d9d74c0f140a4b89799e844366cc5dd3a28cfa9e94fd1157b308fac23e4006be2d0d1282670a5c2735ab9567f7 -S = 00f76baa258f67d94294939b305b41eba86c36b5ec68a155281a692b0be33d01d0b4c2aee3bb503a4f26ec4688b459bdd550dfdd029bae58f744c14b2768d184f6cdb9bf1e6da750cf10883f14d49ee5d836ba34b84eee98e7feafab7ed239b4154666eb0ebf0f3be6f44926656a0b9c5f649fbe5638d563fccdeaca8665a6a7868061a7a544b69b92abae588c8461e01e47f2d83f00978a99caaa2b4478a72c83806d24ba5e41447ed7fb6f22b1750223a9b18c8a2a08f00eb58ee20559dec8 -SaltVal = 00 -Result = P - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = e2c50870d442d577b5fcd43778e9ac0e13f62ae7d506325ffa38fc267d697da72dfb22eb03d4c4bab3a9d904817ce78056633f93138ce773257ed88c5aa16923f2010c39fa4f38b2d529a6b61c9ac058a8e55775ec7e94df885a31bb1c68e8285a602c2260bb18a54402a515f04c1fdd3003da5709e621ec4d546f7c6cc7e2ff -S = 6dfff6e5d6e75fa6b9f012a13c4e62a469d915c7382f20c8b961084ab41cfbc04dbb150d5f50c7c1cc75e6e891b0950a95df3171decab5cd48dd02a62b51f50358248b1c47f1cf7949d78bf236bcf1f6803e27e37725b60a37ede16f951587290f4eb5b4af07b7a6c06bd520adfd29e56ae61efc3ca7d436a8af7c2da47bf201ba602896bcebb44adcbb54083a26b91ef32657ee52b7c69a98f985dcb37328fd703c26303c4863ee3efda288bd9565258b93298dbce897003c760168cc17a734 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041caf4c1d01bf7efc97ce8b761e6fb40139563ffeb393b5ebec6f015885efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 2a5853c37f9428e1879034feb2d07a5c454e9970f4c1ff43b21f5918c8614d4f24866c89f4da620d7478706b040e1d5f7ee028f7c610c0f8a31cf77fcda875e4477e69e3eed3c6fe53ccab1dc6402278b3c00eb632d45f56d988884fd42733f3384733199505ba7bcb92cc5d1eeff3708cf435f55d974325fd6bf3d10767f046 -S = bd10583413878f8c71938b58927ef67e7e46a56f56756ccd099e3df80dc44126566525c666f009b0bcd35ab1ed54d55a34b5e7e0c1efc1b8a54199a5d4605fd464111a40ce3c93523f6ab771d8c8b03939daf3593a020284815357958c7b69e8500d360138ab64a94237faf280a33fb257f4191b5ef385a7b9ed40e6fe77b6e85e471c3c7fa922a2044600285e2c71f5b76edfb8ac76c5b9ee0fa1856c632c9c3531763cefd999fd2f497efc4520029c6c08a8b8b2ae0cee0bc81b222dcffff4 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = e1ba864ce9f41cf4ee2ddcbeb7a05afb1f48fb88610b5da39233f3fc6f1df00f593567b29e22b0eafa3d0d035e488de0ef5d318f52244e20274932b8d32d0ae183dc04246e40b0da5a94ac3f611a80c8f511c7b722e290ec139a03fed89c488a6698a4cbdfb7e56b141801994980fa5c384d042758aceaad5e0caef604d370b3 -S = 5596571f16dbd20f8c64ee7c1fe8750910bf640837c9de5c8cf02bf1b36a4ed8e41e95e10be3038334c7ed93b80ef660b1061d3595c647a603d203d2bd9a357236679944325572748f54fb84f382a7d369899a82fdc5da17cb5a24e2811ca881fc748a6ffc4a6610a6f3ca5db07241f7bdae1d6ecfd7eea37b276d8667a536cd45c8841c5197471ea8959c253eff1588cd99355beab1bfbbcdad5c19aa507be24e826479058197313a94902d36df02770cc67a1c3f7adc1d467640ade84237c0 -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 3730776bea4bbd16ab03e8dfb6ec4b962cf4312ec6432cc1c466aad327adc9db20d16d00c8da8f201140d816fd516e3d0ed20e30fde95bd4af3b75996451cefc32403951b28944bff93ec88cc966be9a09a35432731241018d735560da8a54d951c404e60e1e85fb4843e1c783f4e4b806ad2ebd9086864f475771b2f11f0378 -S = a9a3fac88d8fa6478302de5589304fcd201792e51e7f5e2f10305311fe804dc70728623b20dcccbc996bbc7dfc2ef283521480910df1bbdf72a51151353a791319181e586868f37f17499dc31684ea8632595ecccb553f9bbd499ad291dbbac1813de8fa06a53021bb674b198c79f5c8f2f28c84c09863951501a52bc7d8076e02adb656cafb940587beb815397a9bedd3129c2beb5cef8e3771e985b4a81be0cf6d50b53af7723a0ac0973fc053004831cc3954b2356e4aaff9aafd13ead212 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = a9ba6a22549b61aca519cfec89c316889f0404eb354b5f8d7268c174d43aa6fbde87c4d20a2b9b4605754cc21bceae96f09b9ff8726598480b3785991b48d36ca5dacabe49621d4672e9bff8d0b2f9cd091dbac6abcb2e2f660391217855464a687d23f0f78a1034543fd0948fb91eb45052fc5ec9c648c7e9949014d2a7271c -S = c71119e288acfcaeca10f632f20ca3d9aab35d62f4d8ea66acb955d83c0bf0b9eeac6bb3f776efcb4bae51e47c3cd29ec5d9c8f25bb6f52956ba4ceca9e189a5dd24f1a5f314cc65c2d77b9c1450931765bca3ba701434cc9ce3c4dca806f1f1b7e11da83ce253a1c68bd306770f3d3e8be5ad242b480fab2ba73c20d3922ecfd5d3e4c66ab7a220ce1e175d19740caafc76005056a67326be67f413233810c8fabeefd00b3a3ec19178f48178c8df23a0d08e38179447e3c1f7ead1ac186298 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420669cf26386b9f299c4b53a9cc5bc93fde922383716b1bad573ef605208ad4741 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = c68bfecaa74019105206ace85d710f160907bdffbce96268b2b63680efac8a217810a053c2d0c0126b6888512802843effe1ffc8b6ff185e8bf518fa251c025fcbf26c9fd4bf8edf5e78995e43e34ab449fcbe58999888657348019e1f80dfaf27f809b6c353aa0195ff8419965c88005120a3b84ffada04d2759973c6204899 -S = b7873d5e394de2c8d17f988135da4563f12d449858e5b26e630596c325046e30f0a66ff38b97e8bd3c7b8cfeed4021ed08b025d7c8919c9c7eb29c980290faa100d4b56c1837bea27dfb862cfb216a0965a1c6a923a65e654569164ac93a3b39bc7f533a4b64e4e8a3b88d0fad6eda12e11b181c9abca3b776fc409a8f069ad40478c3f2f02b0634d5d095316813415ceaaf8ff069d85649b8f4b6ce82ba55a2a3b0e53274f10a8cc0c7863032a38ac5bbefdc735523a683bf92196be7120845 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 17c6696009d0ea40825e93872261234db051c06cb17230e339574b7802a4b0a2bb18b8a5a2caa8ff55b22b03e56cffc42d39ee346247008deb32eff072cadb4c3b173f82b49a24c74ed694498c0f52155952c8389fb5412415e0585659ccb0363ecbe63f67c9c45f15d1b8a13dd38409dea436bf91465b71626a70f2de339927 -S = 181e3c1d3f6f6ceb7465b6d232f0fbe3270bdd3e6fe05a8dbc3ca9611280b141c11b903c8c34e7a09b1124874d2ac93af9b3d8ff495d7eaf763edf281235066ac6c7c1dcc257049c732ab2288b918f1b7c43bc36f40f5fd070d362322109b51b85574b30987bbd2d460a53ddd694a972fea606ba2b3a4192dcb30490370454e147013d6c7ec15ddc72d81dd7d0601c49a00e61b57ce3cce8ce89b8048359a450a42ed1d7a424e725d75ed0ba5818b377ef809b3c32564562315f21c8d031ec0b -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004201b3650ae9361fac5158b27993f4f51b62133f7172673d0cdedc1820e3d127314efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 063c070dbba386b97c50ea8c475cb9817fb00be490184906d19a3535ae052aeb06cca546d21505b8080e8f00bf80b55993a698f14b3fcb9cb9e25acae2920bb75f92e3e1037aecbfbe8b36b0c1401c32e325c85444ecfa6e30be040f46cf1a37d935c8c696fac4356770e68498c4757339d6a4f5c3485ce2fed63cec21e5dfd4 -S = 97c48f987ae22938db183cd761956e3dde0cad8a865b70f2392b77f876c63520a12d3bd80850fa6cc20e9bf94d058f2d0a7ebc83186d0defb0ae256237a9fae92b2653284086d49b04ed9ffc3e10f6bb3f9de76396cb4fad3fcbda87bbb1df8c26e2d70f3d5dd0ae4c159ef3aca0fea506887666cd923435b0d40ae434a816b71d72b91a92b107721761adbc7b678d89ae5c8ecb0ab9078f8805dfa033e00a25b30c3c1c4ca8bb3bbdc36b7846267c2a8e5c6ccd97a454fe813c93f50eecabf8 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = e1ba864ce9f41cf4ee2ddcbeb7a05afb1f48fb88610b5da39233f3fc6f1df00f593567b29e22b0eafa3d0d035e488de0ef5d318f52244e20274932b8d32d0ae183dc04246e40b0da5a94ac3f611a80c8f511c7b722e290ec139a03fed89c488a6698a4cbdfb7e56b141801994980fa5c384d042758aceaad5e0caef604d370b3 -S = 1f01900a2786e048f388a061f173adf5247b68076effd95b5c174661b6fc3589981bbc03cbe75534af40ffe0e60c741745cd143f23c2d073e70856ea88442e56f6ebc26e8609b72a955f9377eae375913c032819afcf60cae66d893525ce0bb83e0184ff7dd85893443e10d7be59466c6b7276452501e105bd3e0a8f7553c58ed8700d8e43aad9efd827fafc1948288c12e380b82a9ba22340919a52a9453f2b14e6b7795215720cb6c2a89fa8bbeb46a416267f3126456cb6fdc9fad183059b -SaltVal = 00 -Result = P - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 3730776bea4bbd16ab03e8dfb6ec4b962cf4312ec6432cc1c466aad327adc9db20d16d00c8da8f201140d816fd516e3d0ed20e30fde95bd4af3b75996451cefc32403951b28944bff93ec88cc966be9a09a35432731241018d735560da8a54d951c404e60e1e85fb4843e1c783f4e4b806ad2ebd9086864f475771b2f11f0378 -S = c5670f7a66b167b3369df23e847a68022be3f2acf2c54b1f9c8b4559466587e80f73b6b668921af9902b72a2cbcec0f92771cfdef7bcb12d3db6032b434b8aa2e2bb2a29f16756916887a79e78552254b702cf2a14c9b9c6c7dcb84745fe27c90f0eb7760aa4f98ed241bbe65a8597aa6d26fad59874b38fb48c2a69e4a77d7414b66552dc7a9b15646acbaac71aeb4c4fe69be40137e79a05ba512d40f86af2d7ad5a1893fb589ec9aa25854083f8535da0acccd0c497dd8ae3a16d3a8b3973 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = a9ba6a22549b61aca519cfec89c316889f0404eb354b5f8d7268c174d43aa6fbde87c4d20a2b9b4605754cc21bceae96f09b9ff8726598480b3785991b48d36ca5dacabe49621d4672e9bff8d0b2f9cd091dbac6abcb2e2f660391217855464a687d23f0f78a1034543fd0948fb91eb45052fc5ec9c648c7e9949014d2a7271c -S = 29bef7b04835e0020a2cba2b9f6db73583493c3702678cc624ee60dca13ef99f58bd2466b3cc3515e3ac52cc01e53aa0b1ca13871ae90317ed90d5dc810a49b0f569cdf78cd4ac2b554f272f3aa541875478901c26d82835bf482451812460da6392f801293ce370b1dc1ca420cde9af65f191dbbb57e0868971451be9030f414c24cada0d759767b93526e39cee99933f4eccee7eabf0353fef6061ee271558144cbc8c4aaf2d2b6e9bc9dcf2fe3f1902f1ef1cbd4617b04281ffae8925fa09 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430ec65d014978f49b770a449d588ef99f8c92263e18690c237b1c0edaa8da55716adc29d56621402e375c606e7399c9a83 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = c68bfecaa74019105206ace85d710f160907bdffbce96268b2b63680efac8a217810a053c2d0c0126b6888512802843effe1ffc8b6ff185e8bf518fa251c025fcbf26c9fd4bf8edf5e78995e43e34ab449fcbe58999888657348019e1f80dfaf27f809b6c353aa0195ff8419965c88005120a3b84ffada04d2759973c6204899 -S = 80fe5722ecf6c505989f017b63fa71b2723acd378ef8c4b4de5aa611d99196584eed2b46160f4739906533fe54034db7264a19366f7719ef576d3765907f49792fdccde4b94db4b42c95a9c54b2fa67f513039329f3b3fccba4d44f69ed2c9cf3b0469556ef88d90391af612a273ada316756c36d447b4c1b36edf516e8fd0569cdc4fe2254d3165a9250a9163c9b0c629bc64fc7cf9bf96c3b51d78e378678f2309658bbb363ff462f51d145b82fcef1a0282278453b48cd8715d32dd8a2214 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 17c6696009d0ea40825e93872261234db051c06cb17230e339574b7802a4b0a2bb18b8a5a2caa8ff55b22b03e56cffc42d39ee346247008deb32eff072cadb4c3b173f82b49a24c74ed694498c0f52155952c8389fb5412415e0585659ccb0363ecbe63f67c9c45f15d1b8a13dd38409dea436bf91465b71626a70f2de339927 -S = 82af137868d165dd09c47c95c960e636513305030879d7c4e1f0b58c65fcbc10842f7794e0b80b019b4b384b3473fb452b9e04380f84232e986dddb79957845c0f69f880a51a73cd4bdd041d98576be7220992982ffbe30fe53adfd524dc5da9d8d21a2140056faef2e059a1b282914db1b83494026696601026ac038bed35ac5bc7fa317cf2302f4f211dd8bfcfa3866d8fadb498709bba9aa823c617f8c339d17d0094f31b945c1c8138c944e6ac6a601a705e47b25e9e290faa0550549989 -SaltVal = 00 -EM with hash moved = 0001ff003041300d0609608648016503040202050004305b2dc15a4a45f199a414077ae9da96fc71a00f9ecdb0c40e214da9b370763b672571e471a8d0328d5ac83d2ea45ad2a7efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 063c070dbba386b97c50ea8c475cb9817fb00be490184906d19a3535ae052aeb06cca546d21505b8080e8f00bf80b55993a698f14b3fcb9cb9e25acae2920bb75f92e3e1037aecbfbe8b36b0c1401c32e325c85444ecfa6e30be040f46cf1a37d935c8c696fac4356770e68498c4757339d6a4f5c3485ce2fed63cec21e5dfd4 -S = d216d9776d8ce35cbfa62808888f67d9a154c87184be9000322148237b8bb64bb75aa5a1773ca9d5b375ae4f643846d07dbc3cfc8246d8ff2f774ff42b184df3495cbadb81a8fad00c00f61fb59602c087d570db0ee1312a2747be0fcd9d563aa1cf14522ace1e202c76ce7849b818b04e4bf489fd723c977f1a2594d65d8595917ad0b575cea228d95d6e3a9ba6f6ca604b8650d5d4e7c182a487a20af05c15139bd46b2f2e48e5db0f184bfad5119a9c256ab601820b7671b6cc48394de6f6 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = e1ba864ce9f41cf4ee2ddcbeb7a05afb1f48fb88610b5da39233f3fc6f1df00f593567b29e22b0eafa3d0d035e488de0ef5d318f52244e20274932b8d32d0ae183dc04246e40b0da5a94ac3f611a80c8f511c7b722e290ec139a03fed89c488a6698a4cbdfb7e56b141801994980fa5c384d042758aceaad5e0caef604d370b3 -S = b4be3c1b7b85f8eff79c890661621f6f3e997ec0b957d540e12b51461fd711b1f7ef026e7f4ecd1298b2f179fd90a55cdaa8c67eeb592dc077d8157b8a04611c904808a6e8a88e83d0965b6f8673253ffaedb437e01e771fa652cbccc976bac41d5be23c5a11bc4027f38d7442e999dc4ecd4af036c201332f7bb1177ca523becf8bc98575d2c4cc4f69bfd9383e540a8eb70dae384f3f07e190f72b856139d5232c3b9037b7e05dbe596af51751da4fa33a03c1d3e847e5339f2fdbf4601272 -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 3730776bea4bbd16ab03e8dfb6ec4b962cf4312ec6432cc1c466aad327adc9db20d16d00c8da8f201140d816fd516e3d0ed20e30fde95bd4af3b75996451cefc32403951b28944bff93ec88cc966be9a09a35432731241018d735560da8a54d951c404e60e1e85fb4843e1c783f4e4b806ad2ebd9086864f475771b2f11f0378 -S = 204d6b33a90f2ce261f413b54563f97b04021d081789d8b20bae89ce2ea0de539a264a7aa47e4e4cfb9864fa271f097fe1ef632363e3ad3996e7d7d4412138419d5e17c245ded83329bf6805880397b5d9c724e4185b86fe55c88b4e8f01056747ce712b10eeed8081b928c805c4b89b6955219d9441289fd800588012b4a19a415f96096144d88c9a9de4ecaa817e36e6aa1123bcceeeaa6c779fb7fb67a61773fd1c8e9dda482be5882b4f81217bf9019753919c0c98f3d56bd60ab4e8ad9d -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = a9ba6a22549b61aca519cfec89c316889f0404eb354b5f8d7268c174d43aa6fbde87c4d20a2b9b4605754cc21bceae96f09b9ff8726598480b3785991b48d36ca5dacabe49621d4672e9bff8d0b2f9cd091dbac6abcb2e2f660391217855464a687d23f0f78a1034543fd0948fb91eb45052fc5ec9c648c7e9949014d2a7271c -S = 380e96b29f08c307d6894255bf104751d5c12892caec1f449311dea1eba85d63829c4f6f8e4c48bae11e6ce246635ffabe1f921de533867a738de08974c2685e7cb981c94ba95d50f2c663a90c281cf676655d542c5fb91818fa83b273cb7f55d88555068e9827de54abeeb597a7f66b20bcf542d9423826363716ad63fe29ef6a093f723d3a0f8926b678402fed69645b0fdebd943546fb0e0316e925eda23c755a321e23df6910e7b6c908b35dcd0b2e0e4c9dbaf51d050ad6d9d16f67891c -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d06096086480165030402030500044068a22ec35ac1e035665d558ea68f2d2867cae3935aede53c6940477d181f9630c3c8d24a06be07e006049c545aaa830a3ab849ff91d935df4edcf4e46868abc4 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = c68bfecaa74019105206ace85d710f160907bdffbce96268b2b63680efac8a217810a053c2d0c0126b6888512802843effe1ffc8b6ff185e8bf518fa251c025fcbf26c9fd4bf8edf5e78995e43e34ab449fcbe58999888657348019e1f80dfaf27f809b6c353aa0195ff8419965c88005120a3b84ffada04d2759973c6204899 -S = 7264f99a15645f551eb08662418097e48da66f7c3d5a953d7296330bfa24d02f87f554e19c20f98a848daa9de39a22b848f514826acfaebdd93db456394713547ca172439f18473f36243eb0ce85cb7357d04f011e34c139d72fc540afe0e7a5927c8466bf28a76e572c851493f23569ccb73132a650ba5af14ff2cdb20a3dca7fcc465e6ac6998fdb2df6f3d88044b4354cec5f7f6ce7f02d3dad61e764058f9a69a6c4e63d4e0ac89567fe23cd1eaa5726d567d7a647fc2ff4ab299a05a896 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 17c6696009d0ea40825e93872261234db051c06cb17230e339574b7802a4b0a2bb18b8a5a2caa8ff55b22b03e56cffc42d39ee346247008deb32eff072cadb4c3b173f82b49a24c74ed694498c0f52155952c8389fb5412415e0585659ccb0363ecbe63f67c9c45f15d1b8a13dd38409dea436bf91465b71626a70f2de339927 -S = 5d90ac2736979a5a789b927b6b142bf08cdf50a5018e9e75cb03363f255d4bf10e0873e39c7cfe7f0faaa2594b856ebaea0b3a83c6c1fbbd1201e533b2ce14e726ba43aff51445e976f9158d6b369fd121e17e34e529a9f7935f3583943fb82eb0e551e7a183254cd1d442ec87d3b853613ced92c28ad87c7884b8e57729fa36b25767be0b77108d2f1da7122c3c44f71ef1fae6399400190863764d2d28076953e579bd5380058cbc06671b76d6cc2bed1bfb1eb0a22e72308c5c294bc4d339 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffff003051300d0609608648016503040203050004409e1ae481b6e7360c34c33703717c48bf5c84b980c112931713bb8563dbbc3542dbc309570342b078e7955ded523fc9b8e992724b26452984214d8f3d04a7f0efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 0b86f0524108c0868477219f6462fffcec9e0c3f0bc83ef154f23be0c51ce72969d5e94fe758df4988bdc97b15a26ecd30b1d985794db76c6a9457cf23d021b84145eb1e94026027f6184a83268334b36c5b1a87b054cc6ea0152c81c8b2221d5994cee154433655352cbbea66651f6e0297fa432f66780fad7d1797d5d2f59cffed6125810a6db340502922acfd7d0c0103846e5041c43efc3551adfe7f08180611bcf21175160441b81bc2cc8d8e922f8e21db688e25a820453ca986bc4941 -Msg = 03403f0e704c5e28fc547e60cdba09c7bdb7e4fff89fa2a0c667f8d9a564715b9b556372caa4227545e9736122b044c1d17c9ad1ac0ccae2cedcec0029ef8dd3d3cca4c3a1c7c75ff7819f00deb29aa95726df32f00687a694590ae9a7caf79e53ace9471c3bb6aebb25e98529497349fabe9d6cec1741b2c0e53adc487e1984 -S = 5959dba95cc8fe826428883acbc57294a10e8e8ffda441b07f8fb2ad17f52589774c27c2f1cb54e96614bf7b7a89c4227168ccbea47a941540d2d71157844ae0210c6fb7abdb58db349ce1515b63303f85a6bdb38bd6ea0f9a340fe70d3aba17f4b5f2a36dcb37f354eb86533e4424c7ccd8377775a28f9beb6921c8b4d9e89811ff748bc1b026e9214c9c16227a36f803cabbd738025bd9f7cfa1c33ed4c00b5d8035389c8d6a02051576d33c8e83f2f72fdc1b35a0dde73fea1e2a93dae015 -SaltVal = 00 -Result = F (3 - Signature changed ) - -[mod = 2048] - -n = a911245a2cfb33d8ee375df9439f74e669c03a8d9acad25bd27acf3cd8bea7eb9dbe470155c7c72782c94861f7b573cd325639fb070e9ba6e621991aefa45106182e4d264be7068035595d7549052989b3e7fd04cabc94012c1278a0ef8672b1a51dd1a9e276816ba497dea24b4febe3dd8e977707bcd230ca6fb6f8a8bff9e6ba24fbadcd93f00126b19b396a38e6ef86d18fef945b9154c1963fb488c7025953511f86d05638bfe056493730bc6778446e59cd3c5c3acf07a0a3a64943793652f10e3292aa7a6d25a03181cc6f6ba0658d909e59ce2a02bacc9766fd8c4fbd4ed9c23a866844b8a794d49e505f9f944870a71aadbe5338039825c2dff81af3 - -p = bf96de108963b5113399b664765efe046e2dafdb70d6e5e29dc6ec89b789b059348d74d89129c7ade9ddb404c6dc3a3437c7fc9f23bc38dadc8ffd0ff757999f5c2d510b993056147ccdf421e03d0be2c74ec333a9677c430cc604f5550d0d86defdde71488e3db889c699a5cacb44dcdae2f3cca38695e783e6f6250827efb1 -q = e1e7e33618d1b64d6862c132e4b1cd5fabad20ce62bd97bce2a3f5ad2da67bb0a7f0b9e48335a33b7b95e77ec4c47e91416881f9f7c23f9bc1918cc644335c74260e90cd7b2e0fed802f19e78c5ed80a431b38630d82f982c74a0381b8ecf943c60810fae90574e216357b2535002316d9529cb56420f3cc82dea37cb624e1e3 - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 04d5d202ade6be1df96d263021141bd6e4e68a14c5b413df73b817df8979137377ee2df5c0e60d3f67a8ee6ea3d6f5e6da97c196cdf4437d1183d06cbe43740e6bc88a2759988919eed421ac651b870ec5ab0d190fc9f5d5bc64873e66f56147c6a90f1edec2dbb2773ae673ceaa78588b6b9527f2fbd1f15da265dbea558125 -S = 6b2703ff1a8d96808bf97eb6d297a8b8d11f479e22b8471e03d2713d124f7c8bf46225e8de2b9db432c39209c242420bc9a17196a38c1b2daa096a73e33912b353a6adf9d198d15eadb6f287c5d2379fe8c07d9e5735bc4c474c2ff9bc7ee6d3684335f7f825664d6272426b2fa20bae585f7bb306b352d916679c68c77ce0d2032cee4909fd02f4f4711ff4e771251c3a9e284f37fb1bd417d8842d030500d84bf7a774b5bbf089e2829c7e7dc27f4d88408e5b549522339e6eb98d51718a219c0fdc20e26bb32d85ef877a5fae812ece7bb04a1ac5a0dd71ae4e8d4c25aaccf8c1f5b9c0de7e0491cd754a675ab6eb8c630b8afc49e0597ea6cacc6c37fe9f -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a050004143d68a61abc2403258d48c94be567caa29e315c8befefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 3efa6c9938d6bc37f0373d0baba3697acc3bed498f9dfea7fa0af06e11c405a64aba834b4067094fabf822e390ad1bf3b58112ef580d50d120aad95c54d640a14bd9c0c824a8890db7095809caf84a338949f2a63090a9250b3e255ca00c4e682b9d4c9a4a5ee578fab20605c24c9f432edbb4f57fedb2a9a10dfff65d2fd403 -S = 343014b8db6ba664af3dc07530e444976bac0a7fd3505218500b0342c0c861d508f55383c18ee70cf47516acabd50dbc2ec18a8cc2054ab87496b9cf22e4f576d5f208d0cd3be114f65f69e0ae744e46edbe0a378942e24eb51fbe25a0caeb654b20ce9a8feda1bd02981a24ed35fd139d107611cbdecc7b1a960ec57a19eef79bac1ed277b746772b405c7c29cf8e32c1c7a49557928ec792944bbc87183fe828a3469214fd35c8ca16df57a985d610ef80db9728f3d31529a7c39da03d39a6735117dc99225921d26fcee7779d7ae191934452207bddaa60c0aadef72c1ea09d5a1d7cac615a8a5b08c5e429d801f868683a72263d80db270a413a8fd9c4d8 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 0017191f1c6b5bdf895837a17e05ca6119ea3606aedb978c5f423962ecac0811cc87471f7c2985331715cd79277a1e48bafd1a03b9b8023d7683e2208472090fcb9fbc8adb292c52817ca5ce98d307ae22fc7ace985b5e5d7e32813e392095ae25e7e128e3723685f01625687c186fd9796fbd30f2cc91359ed87d85b5bc9338 -S = 1d2db922b68b7e89cdef4a238e033500962d61cd39bcad53494663921ae6b0f7710728d9dfb8d52d7725d4f11ca058b1195b1c3c4614c32dce6a2b1b9ad1db261bfde9cc8258787fa7ac9884ffb5e69775ee76ae8af3a15254898e8497b77d7cdb161415a1615eec8ae7ba4ffb352ba459a1d84e43a04b616a13cac644b38c528047841e249ff2795ef2fd066615828545d04c82e92a027bc110c5de6a52355e02bd7888c97dfd48a925528e48890323c6a4f44e5d04ea05cf3009e838a6bf438fad103ea8ffe8d0f7d770c0034de693c7bbad16e8c6a923cc8976bda5bc08b15897075162068b39b362699149e0cd4eda9ff1bade4fb540dc27c17e4119708a -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 1577757d0f460af152dc68b6ab25deadfebba5f68351bb6e2e51ee766fc437f71c734aa3ac4b6b7da506839b5708732acb87a8b4f7eff09e33858cf5f14a866aa822459a11355e939696ad940823a51590ace407e8570a5dca42cccba96b44cea0cd8beca8cc8a3d0dd30d2a233c19753570807abe4fb2b4dbd2d68201ee1a2b -S = 5322e332949c0f15fe63f09927e2ef90a0f1eb2262fc8a7dc602facf8b5cf74dd0eaa2638a6d4393c0167be176e8e68d3b1a6dd4c7f043dc81e702b3b2620df5a4032e6319ff88e19c9cf57fc03f3ec5ca75db70b6b22a38f40a3dc214b477da2e1400eba49c35323c8d83e5159eb4ca6701b4fdb99f18505f266ccdcedbeae59b36fec2616b04da979376403a435d3aae0113d4605b9ffda0afe72923ed2644069a408c148b4e781387fe49f3103841eff840f0b39b298ab4893ba2c292af33b57f6f6f69cf5464be470f678ec07f0ae97c9ff292d896a7daec48cf9e48ecd006acbc2c8567368be62f2178d469ae958ac0b5bd66917944c4b53d1f42ea2f20 -SaltVal = 00 -Result = P - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = b72914feec0e16233c24031390fe31942537dfc03d58810915fb597b163147414f22e26b23f3c7ee3fed32ecd0dbcb36f2b3c2106b791d3499615119a93410740af4630021c3f87a3f01bdf0d0b5ae3cd52eeacc94ea0da48db6baa5b117770fcfe9be454f4650d022a9cda7f95382adb5ee827c1f71f861da43bba796a32319 -S = 2c2a5042129ef97c6235195df1da7b3d80e08176900daa562ea660258269e1a55c73bf226fb54d21f28b8cc02aab8f453405f2c0ee6682ec8ff2d1d8540aec1ed953f53847bc43f0c89608164532da10188400e9e7850114ece817aa854024e696fed5ff74a3747de548fe431d4a95c789bb377a8add64a8583dc7fb203fd66ec9e476232c25b9d454aa9ea7332672cde4ef7540b12ee28524b6c399be32805ac0f7f0db08eb07b93cd24a23baabccdbf5c8437fe2c3330586757a897242c8f2673ab8295ee88e5ec2222fd6519fc49cb1eea3d21d63f07d32bf0874dfdd5e74f511b2e06750ceafaef4238824f92c5da128042dbf64557cd6e4d7ee35d479b3 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 25d08c937abe386aa08b54cb9d7537829c478e53e67df73b0da9cbf76a153acbcaaa9e7c6510099e10172016b3562dd7fc126fef5561b5c7148e2ba6f2c07378bfd7f7ce54977e25c808fe6be71cb1bfdf936b793d1c2b6a18bdf0658c74cefd6b1f40912e99c086322695d42111edc4ad932bf885f782ab81fcc33a207b73e3 -S = 93a032b6e997c0f9ed6261cc4617d98afb80cbd6450a3d9ea2f63999dd68194c9451538975d7626d77a34734d99b5992f98ed18c7f9dc0026fe34cf6583a6a36eb6baadb8316e3aa48d9da4244544da430cb8a19953d84ad4575733d887ed3bbcb4f25389cd36b1c565bf661b1c918a14e5e00e0f0857900ed4c98beab9fe6d1f66a0df588b61afae9fa31e94464d85bc743193303259e9806231cf5cdd4d4c9da5691c08156aa72f4da7607d598d450a5c852a8b3f577194afece74e59fd4ba8c5bfa583c2fa9a6f6aca7c51f772d02fe8e0bcaf5e4c2c7cdd6a38f7264d717aa2b30daa6968a4e7e7e2dcc1de9e34604f0b80c8b793f882d35497d81ade352 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a0500041461ba8219a8f4252ba5e715540544ffde89da3072 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 04b9dc9e05391605d1101e84d4cbe1a08bc3e12a97e7e21e10bbe6cb1ba15c34bf5895b7f4c277ecfdea75d0f845bf23b438b50ec2dba209cffda7fc3168f5a4bf653f39e683704ef99599f8c9fa2d3276217080844b2dd33193a7ad062cd385adebc46d020567f26c1970446e7194977985f9c805c0eb44e087d026c5785e9f -S = 39b142d1b8340384b8eea14f948125101c3c54bb339fc06a5dfb652ff28df204b05561e7ff8e1e6630d7ee9dc7a6147f6f24ddd703bc753cd3226e35812a821e68b7a77cae8429202a74dd1361e8e568f99ee2799a92500a21c73f98024d091c5e29e9531bfde05a7959a3d8f390eb17a6292d11d361a0caa7a5cd2900df5fd2f09679c9a1e58e525721fd068061e5bf5c95d1f491da063532ef620d537a45dc74cbf249c97493bc8985cd0fafdba295fcb65b5ce134cb30d504c93a999909e0cee5aba1d6a6e1f3a3d25403d09bff303d6b89f6a81d8c570c735ffac0d0d415c7b6cb7a10f68d94cca2f1de7975a5073411529b48b2a148a9353c536369df48 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c330514ff465a496206061832aa09d4d549aec683133b10ea884bf3f9 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = ad12e61576bc1b15d5bff13ab66a496bb5f643dc8461bc858d7a15d3d938369d314fd3598305ee9087429e8fa1e70e600a61c8f82b7e34b2497f5bfc676ef15068b2936775e04da99ed45fe7c401414cb605e4919a803b718f27fa5d90149e709b60ada513f43f48649cbdaae55ee91902091e0f9a10d9aaa699795c1cd243e4 -S = 3009202b1060f77de9e25bc5bf80062a16fd8c8a7e27c4f8fa2d069c6b706bb981f0e2561d8dafd42c647c844ff30b0a226704bb85a3a58dbd5baaa8e19ebfb7635d4f502677b6575b31ca37ba4a51e747fd97ed2a1fc330f2ddfd10669aa9ea4f13c990b4cfa7e15e983459df317ff83506803db89d9f15f3b93ca0acb22d800d9a2c36770718b62a78998fd13471107afb36b700aedde93fb9019ae9aaa9ae4f33d7a18cbbd8474ffcd38a6b4dd95de015786e50811bf3de5dc7de6c3eeb721e8197a8cc537e1d076a887634cb7af055305218680b605055d7e999b90a348745d277bc36dfb38c431c9edb329d3c5c750afcca77ccf159276ff70b6e8f949a -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 3ede763590291420c8da355f5e5930447317445e61d0cee6970dbf59a4ec4e679123ea0c744373fd423aa945e51ce5308e2307684df4af5edf23b0ebc7fac138a07676dbb1936f42c2c9d0552ed7f0573abf560da512e123806d46cb4044c0a712de02e96ea171b9ef9090d76212bb811df5199792b2ccfd23f36a413852b17d -S = a3dfa3b5ce640d92f95260d559bb5c40710a2d3cb38b816fd3b790c78ede96bdc213e7e6e76f35d5e24cf1a6dc54d856be83e352f55b3caf98b6dffcc952023978a5a6900cc9b0201b99c90795c38ecf0a3dd5cfd9579378c57c0083b2584a3bf859c69a553ce7cf8c1ecb98376b4ce90e1a0271c4043654f175e90477440f7108b960d1e3e2d00743e0a2db96d179999709722b046070c4ecb6f3f3650365119004b016e62272fe9e7c06999c8b1f8e0ac56f46c668103cd23f1457f37e376b8aa5c4235db08ceb577945f3276b931f5933bda713f0c8643aac2b0ad92f7c8021da0072444ebffe55d0cf183f002ffe1e8c221508e7f65b73c05f9362214440 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c6622f8e46c8c838679d4e8af043ccdd2f9bf3a6820a5dc64a446fe67efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 250f95cfabab5de46ab2bda3cdeb3228cf7330aa1b5764ad75623c795634a9cad69424c9cf08ef3b40a29df9ef1cd4a053285289b0012efc844660a0220884369d22db87e7c8939b3a63482cb79cca5a4eb721a1dd23ce079c4f549ab8bff7193e5ec4f23b16d16c229ec6266d939cc087cba5d8eae6cd3884251f4d60808bdc -S = 580511902d07b267c4daa41b6660db0d20795afe0320a961a36b384fe3537f7a88e31e09c5e3f660d2ec4e176c2ebf7e45be1b579831c0c75509380684e5936b79097d6c3b7262583e4c2f81ba09e78e542e823e855ee97260e8fc9d53fac6d452d601d07526583d078e293c0f183d716a0f7b37de31b000ca7bb095303d4eca67393886e43ac271c119244d4c45d98212924402b37660c0f7dfcd34e4672011d1aa721337b1025bdfbce502f017a573a18850cbbe108bc9fa978078906a4c1d4023f8158cb5224b46f43f70c8029793981011d77c816749f6ca9a71c2749e0e151fc69c7f4b39fad8e96cf4dc6ae451bfb506d9faef8b377b7c5b47e19a3a59 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 8db3a4d5a7b2fa1c3cf85a9e07df0aa00eeacfe1defc527218c7c8c82c86d21065efa2c2266360797369cc02b25a24b2b35e48fdef961c450d9b2ef0ab2899bd5a132958ea82bf2ce95bf77866fc09a5fa2dedd70a52c3c246e671bf75248e1e75077fbe7d75dfdca6b72529aa2d801feb400694b7970e90ca8eda5c14e47adb -S = 9724b7c6909ae1499a06410557882d9fe49a804c68c172cd5945e40132d750d47a454f155c075c0e57003f20cef4a1edc84d427b6bd9f61617ab502ba6dc5c6b1d032a380898bacb80d5484d39783dbfac37c4f001fd8d4e1bb2310d459637be04cd5fb2cf6b32dbfd214b8f7cc0dada942cc41c9f476bf6ffa502bf7928dc8610ac0097dab03f79171046af23887c2d530463714bf7fe59933cad26266a117cd355d0402a4490472b0006f6e915c56e204eb480ab48fe9ef0dcde5660cb9ad235890713f77b5333c1314dcc741c2c8d0fed546d23696275a8d578a0d39d4f1dece330d73ff1c20c72ea82e4b714db309a0063edd35b22f12ea68f5c5723c8a2 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = d6fd570826eb30d7f3173089ffcdc2f791c60cb4bc5760e6e3e9d3557da92bc21681ff7a9646192bc6331ff5109673c487c957de276455b85db1de0eca603132447c7ea51d9e4be4a8611884fa153e81eeb81dd46c227643ea7f167d3202b56666d81db0425b8faba289625e44b4edd6ce7aa7be13f88d30923bc4cb3ff78006 -S = 4c142307690bf57792293509295ebe275716356260e0fee39e72b64fd6210f547bbc8eb84ee2fffe5bca0121735f934d1832079031d9813902269cb6a814a71a09012f08f6f8ae10907ca0755fae622328feedd8da1ca666d2b713ca0d5b6de85b9b1cbbd6874dd980f304a313ca07e6c70a44e9dda1bed3d9a2cce521473661f33b7fa96c496b8f7a9c77e9bd0ae0dd47bec92c2a4dc9f75af9280402a04014523957efa5f52985eff48e4f1bd54858a956743dd2badf858d00c83213908baf95c527afcf0e32f7c97d4dde5dbb936ffb09500a2bc0bf71839d55489a21d642ee455dfa8b525a4d4890b2283eb043b3bf77d2ed7e2885c32b004fbc89693380 -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 8457c53956849cdb39bc8e7657d62a2cda9e13e1a5c3574142f1fd041c3add70efbab5207c7b78058196e9aae89b69bc3f330dc96804f44892d5d8da68f3e2cf87d3c3ec36f8006b51178d44877a9eabc6a2badaf2301110dd060fda74a9319136e91824ebc5dc179289a2cc9b3971025632419bac0f55a20dcacb8ca92372be -S = a2a2c0264dbb8b8810aae0b9ec7408553803dd02be6247358ce39f98f0c0f0339915347ff3c4dfee0e0a49b675ba69e376f3dbba56aae846cf7f986a0a5f37fc9971a58e3217cca26dffee8655f3025bd61776683feecdde546fa88fb881d619a8ec2daf092079a850340f6af41b2dd11d9935bb06c2253bdbd32a6fb8bd5317d3c9c3be5b683e7fd6366e1816895664d8ee312eca47ecf862be009d9df699a7d2f515c69e3093fd50a3babe9ebaeab6267086a3185a908ea29af8eecf81e2be7c9c2ae33cb2380c73af264d24961b5c7711b0289e1a095f2966656ead1fed95b6c33d7082c3868f1f7b706f9442ddb76e3582f73e4839a0a110dbb78e9cfcc5 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 6918d6328ca0a8b64bbe81d91cdea519911b59fc2dbd53af76006fec4b18a320787135ce883b2b2edb26041bf86aa52c230b9620335b6e7f9ec08c7ed6b70823d819e9ab019e9929249f966fdb2069311a0ddc680ac468f514d4ed873b04a6beb0985b91a0cfd8ed51b09f9e6d06da739eaa939d5a00275901c4f8cf25076339 -S = 794d0a45bc9fc6febb586e319dfa6924c888594802b9deb9668963fdb309bf02817960a7457106fc474f91601436e8954cbb6815350b2c51b53c968d2c48cc1799550d5d03b41f6e5a8c3c264d2e2fe0b5b8ff53fdcb9dd111c985cb488d7086e6548b4077ec00721c9cb500fe07a031c2030e8ad1dd0112c34ffd9091d77a187aac8661b298eee39eb615f9715c4c48a6762ede55a466ec7f3cdb6a937cfc80188a85d8f8d3a2a80b199ce5e6375af8f02f06d706a34d9cf38318903965db54aaa7d3fa7a7ee58034cd58c8435739c8906366e2ddba293f2fb2c15f07fa4951014471e7f677d3bdacffc4c68a906e08d68b39f9010746cbacd22980cee73e8d -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 4ce993829f7b8112277cedbf8b4ec59244cd7ef79a7bad09cfdbd1109a1a7348d7f472e57cd69853cf4070c2d66e5ce20f37e2eb623547e154265f167d92a3f03caf84eca981ffe3cb45728d0c10ae43e9b44d09eee346cbe297bee73fb021ece5df72a10ec4df4a85539926137ce23c3a0b685826cdd150e1f4978bc6bc16c4 -S = 29865f133c69122e1b309b299270b5d693db89c5192eca5c829c795db460cb1dad3d1f27d200790fab035c90c00b238384bb30ee30752425f2b7f424d71bea79993046100760f3fa3c6e019d025338c13940a97778ea67e6d6138d8e8ff601d2309f02762add479d85d25fa31bd1c89af97927dac2ddf818cfe2179548db4da69c163d8cbf5f9c98ea33957022a52d6f33b19bbd3d05f40f2dfd49d999184cf5f9bc69fc1b21359c3c85ddebb6936c4f49015026539e8c4aad2dd3a3b4ba309021fb317348d12b560ec608b74f812e3b74e4c8407765f30d6d03a5c20db821adc4c844018d57fb5364d0e7c3d55816782200ddf92b13dc2e0d4665b4cf3e1059 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = c801a9270165955fa4d85fd502c0e6be0c91e1c453ef734f331300034a6f3e8a2f958f9361558e1a7e25e7eab6c76d617e256674898029f2f4c9ec0dc14fd716869b5d886698cb4841f8212b28d222b91490a731d70838cd52e9dd46e959329b34dcba0ff77875705517b59f402c2d4d34994b0325d1c865b6397db7abd578a0 -S = 290d0d444ee458777b5fdc3207d37054407c0dfa6806296869d3ec402a18209a3d06eb63d995293697e8c0a0e72489bfc9132857d6c7a17f4852e4e573a48d2a2a127fdd270092f5029d976b060a570c90d685bd2325d80c9867a3b245455545bfae8cf87cff314f4d0a968229446dbf24adcd2a52ef9abd30b4746c2e04c0fdf52655427eb03bf63fdb208c6a776a3852052ac225eb33d7246f7ba624723f9c22abaf6d2f9219181ca62e44bb53a9ce8b45e7c6d742586a234e5de66df4ffbf7bc9e7f815a7d5aadb2f727f3151afa6ff48f6090d9fe08c8b0f1505598ca4a4ccbde6ab0f87b43059065097c737e53dc17f200c3a54b00d709a5b8bdce80f2e -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420af8893e585e7d2dbf3b8d3dec0802db4ee1ae86e8bbe369d8e1eb3aa634eb2cfefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 2466a246feda6fa5cee22c2f33ed9d643c1f6824d9f327719225bc7678cfe4c85cd210ed4077701b0b5650418177a74c71b8eda3306e2ef3474f5d326990eadea84a9686e822878c932997298e01f2b16c42e019e21bdfb67b3df5478df444366c97df1bdd23dc82ce23abee44d3a61e9484e88ed642634197b52dbece451b59 -S = 79c3b93019bdb8a6d6a79e813e4d96928f730afc010657b1eb870f2891219de5fbd464fce97b2bda12a9d84a3d5c120c660ed0f70457e223809b26a996afab7c23143b411a1aae566d7e9d19d278044567b5064bc918bb101cadc7a521c31c5e1962a7437d8f799ee6a76fc2f0a6733cfcb63246b1a864bb14ae70daf848824da565892d750af7c5da6e02e4889143a746e7e58b562d19cd3cf3d97795e50e1dcfa26d43f00357c92f01b327718d6cd292498dd29d0d830408b568b2c91541a76b21b5d4efea46bc128d9c4aea4e9f60a4a601c876736bf9312a00a2bd81b4ca5d8e37ab2c79dacbe7d8e6abcc4691db64649cdff212f467a9d805b2c38cd031 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = ecb6731a006eb273f6c5404a2e2d1faa5232f7afdff5b69be1dc7927fe88af17b5077b11e84b5baf98db08d3f1c99d3b86e4fa55dd2e6b542e91858368cd51d975b5adcebf9bee6ef309caac05b276f874a70b14cfce2e237891f003a8d3f3dcb328cff98d45b3d78db5507c72cef20aa4e4f094bcbc47304543824ec480dd48 -S = 8831265bcd54bf33d8c46cbd48052e9357c31afee92276b1b744e2521da9b83968e9ca90446064d8f174b248f64e792f91f4fae15252688e0f8ad38b28a532ddc7dc59e77d81b7a51dda2df2f2cbd5195c87b66db297b74296d4058fd00a060377dc1ec286c21e4f84c17ef315d443e89912e6b5d5f7d4ade31cc2b1aaaebcf09aaca20041b5f9b799b5b532391f85fd236ff3fa794baf4b25a2a188b0746728f1cfe0816b37d8dd648c53d76b81ee42ce27bf07baa27016b82c9ef3e1f5523ded7d35622d4986a6699b261f483e9b68b9c99e17e4aeb1c7baa84be1177264894ed5aab8592dfaaa652898b37aec28c19d154df27956f604bb6a30d0964d4e97 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420e45bf84dc5abc5c28a27625b0c96d7399fa1bba8fdaf1d5b5354970b2ff9dec3 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = daf4399ffab3de496e3ec347b4ee6f4ebdbd83cf434ea81e5d2dc6d351577771a9fdbb458985ed913fd2f5ea1cc5c0df8203eddb3ff9c94d191e7e05aa7887e16f6267aa1b8c9b393143cdded1f34a02d2eab60a125eff7f0ab28f6ca6f5c60853aca79559d1d1886b1bb1ea7c80f7fed5f94624658530fd587061d0ebd51a2d -S = 38aba878044ffa4572749376a12fa96b3b8cf778e68baa7ae05b4cf0457242f3a1eb8451678e79ad73741e169efbabdb0469a53dafb627ca3d14fbe392fe311e792b8f274e0d8439de0d9a82c14082abcc4253a5a7292f846ab816419b34c57587f2fda5c6be4f4a3c4130acef535dab4f0e05f5c8b18993f57b167298ba24b0d238964e0fa87114079fec872c673cb7d961ccf7ceff7fd5ada8a6f309de2d96a40224b12b921ad987b20e0ccafad43d0220e24b82aef90151befdbaaddfcb5b35e505912438668b4f61745734879c54c1105983c83a569560f35265be0d3ebcacedbce139c489f4be3c3befba6dbd6c5c92e0441a4a789ea383516be0f4540c -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 6cd8ccf65bb3833c81961801ec68a9735fefb8a5f7e3e63c0e47fd6b60f934216c87af801e444692aa9b8737bba4fe62cdf5b485d7bbf54a2e095684a66ff765facf06f16e6c84b2b2444cae0aa05196ace9274069bdc5579042895210ba7ca2dc58d8309452c70661386e4c21842a77c47219bdf512ddccfd9b9cbbe5024b41 -S = 12eede9247a5fd5579fd51f172ce798d20f8d932326f21ab0dc698711899c68357158ba1eebe07bfc1a78a08aad655da3a26556896267afdcd5e55d2ec91fdbf79960321ad13788e33eddd06b2f25347af73db9cdf628e8ac7a57b2a03555aacfd4af01afbd049dec0be8e279ad369a3c606fb1663e4b0f95be5416c5ecfeccf73c5d829ab5041e21ad0d1792b4536033f518b411c3c82ea162cef14dd704d23a278c0d71ddc9adc4014379c920e54ef8487ab3f5f6e991e50450c609fa769b60e057e6afb511df74ba7cc6458fe493a7a23e8267a742d20600f3c9261efd554b4c0b366ec0562c94c4180f34ba40780a24e8c36e110c40b6bb28b22394177a4 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 5fa43f0df5b0d9486b1e5f80a604230cb1159cddc9681462b47ca1aa547856c97bb7ba7c0183791014215a7fd00f71dd0f8996f28351162902b0a8a920b8a2c103cd6c89736435c63109e60f8aa7542e2b04bac9378b6642974eb2db924b361e9dee3c7c74d8743469dfea76fc5634c8ad8ef0aa0e9c6e751c5da989cfb87ca7 -S = 268bf5a0977722b24a174d83dc7dbec6ca1c392ad4a48d68af1b1ce30034e471dc8ccff5e5da865f677eb85c1e3022cadc89ec82624bc8ce5c632d1863a4946f364718f3566d38dda330ed68deb56130d10126fc9dc4f501f36e6e94507d5a556c8de76efd8149276eac52d16af495679cdd4361f66b7d963b9faa5ca0f8920227071c519f3f1ddcc7c03870a9639e78ce5f1e61b5291c190a4f9ef237116ebca742a513efe5fe39b1dd8914e71b60128b0e180685008ae206a64cc51c218f45db765c1af655457af34f94789ae5527dfa840a1cc9dbaef8003d81d3f59b7a3c440a9497da1be98182cbe368f0c984710f9ec986428f5c7a38313d43bcf680df -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 40bf49cb5825523aa5aea4c0e6b08b7f857f5e8a1ae01af731c14a364d272aa12d670b534d99f93eb04a9c78dd715cd628a4c8bc328c3933b397b23c77ec0b65a7a44f994a37623c0b34e7783d3660d11c13970056563efecaf0d25f8f2ac5e138dedb4556e7d55d3fd64d670ee6e199eb3393fd8d26707ffc3470459cc89e3e -S = 825731d01b0c197e2b27c4314b256ea5bc09ce9f012ca120695ba38c0ebdfa8c8802ca5137ef675f76a17038780f94f753b1234d0531be8fbe82e557d9357b18bea2a5c1cb83dd129e31e9c2aba44640145d2ed36470ee57a9486fe04ae13d1be2ea4047ef405a53a2d4f5bbcd21c9598de98046191bb605ce7004e3250b128a0d7d075ea7bab16a30f165fda23318547481b8b6c9bea0843876934bf7c89e013c9f19a8e661ec2e78013b89aa6beed57d88cb27ac34cc18f231c6e6dfcb8cc1580fd5ea8185b927147b564d31f724466d64692a17dda68e0b8fbc1a7cfec4bfa9c9f96f73bde2d0ab8948d09e1e739d5277a4d3d4e70236e9a3dec388986684 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d060960864801650304020205000430e57e40b2774ca1517efc987400aad5a59ffe873f0532d8a092db7b4f7be006eb591eba4082d41eda449a261187bf3804efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 752fbf49ae63c7853b3ef6f52ed324e53867925bd5d4c49dc42b93f3ba9d7eae579c4169593da98f10e1a61e1214a2aa2fb511a4a75849dc9be89445c29184f85ddc877c6d1cbb45230a047a98ac5bfcbe7b69a397c454cba44fd90fa13f9b546f39ba0a52c8a8ae5c0038932962f8e3cd00c1e00be28c70c8a787d9be6f69c9 -S = 80d7286710e5f165eeb63d2936e8e313ac5999bd297d35590c2b6ffaa4b7b7ed30003f0b83c1d1996c8593a37bc5d7b501a3d126ac6124779a23718497002d9dd2ce891b83d185e333af05460c6deb65a509640f775a0d3c70e55112c2e4af19f4ccec7af9ebb34226164f1b47d50b8ecc1dc3e0fc09aa15abfce5aa3998b5c2b1fde261c35eb43220f0d64529f723801d7faff841faba8709f6ea7751f30428dfc58045c84995107ee013ca4a84f65b99adde1abdefb5428f834ac8da04dafb9beaf1813f73a4bff2ec94120e3a702aed1184c387ebda2abf1959970724299b9a05f4ad313d91beb5344fe1fe13b3fc3386c279f031c77d74bdc9bc97e22455 -SaltVal = 00 -Result = P - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 18e158ea033c33dddfc57c8d6c8f132d9b129aa64416cd971bd3119ae1564fcad726028278288f6767c0d6a8a73906840a67b50dec8a302c20760fe62bf10dddb05d171a2c97a309e41e43c51b787a9687d1ceb906e61e5f8e2136f76205a1b08ccdbe3a875017cd3c28ed6d3013186cfb990e30fcf041374b1cae57ef5ab24b -S = 3491d346ada87f5585e13c5e3ed29c35f7f8536d16b99a57e3519c6c0fff826e6e314ffab85c3d5918473cf49dfb066cf107db8398840c53a1582a2bfc792c7cc1b72d3ea0a0ee0bd9c5aba576a9c1a41836caeb61da3b019fd553ec455b5b2c66da6682595e1d2731135ea8681e3d0b262316763f0840f030e6e26c67f11c1bf93dbe71b82d593bbe869ebf8bebf831e62ef31d2851469145a1f618734baf114716c0949a28a27a83521b5c68bc5b11081f6877562ed33ad603b436b7a9f98dc0f2968350810e24477d87df566a77f6197796a835b1945418667596171868a6b14d0617a2d76fb85130d8f5fc397326ea5f43587ce1812eb86e1aa584bb936b -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430cc8f60696cd0d4217858fd042c6caa3350dca7c9e36ad539e96052393204ff21a692e6349566d013a30f59c2d6bab449 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = daf4399ffab3de496e3ec347b4ee6f4ebdbd83cf434ea81e5d2dc6d351577771a9fdbb458985ed913fd2f5ea1cc5c0df8203eddb3ff9c94d191e7e05aa7887e16f6267aa1b8c9b393143cdded1f34a02d2eab60a125eff7f0ab28f6ca6f5c60853aca79559d1d1886b1bb1ea7c80f7fed5f94624658530fd587061d0ebd51a2d -S = 091d2c61d369410e236653b2b1b068cab3fa6632220f72737520838b7febc00bfbec8e993c3c969d7d4825ebf03a5ef7f087926ef7316f97e57e515f9aaa76b3a7bb10e64d983e6c443906882028dfb7e5fd4558a3f24b2c3b863174b011e8587995eb425d52e95bb27f98413cf2a1f5999990df7f5d3835aa19b93fae1b1734ddfd2be99b9a5a071d062b707543b47aa650faf640afa43a51c4013e27d278557d4429584bdebfe5fbef4c9bce178a496c0124aadc24d9ee8af3e0e83ea72ea93751eb687875902c7348a212819097860041a9773d810dae6d3c9eb6049ffe38e2a09d976cfcd3dededb7f374577458b25124669a85de7465b8ece756633c1ad -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 6cd8ccf65bb3833c81961801ec68a9735fefb8a5f7e3e63c0e47fd6b60f934216c87af801e444692aa9b8737bba4fe62cdf5b485d7bbf54a2e095684a66ff765facf06f16e6c84b2b2444cae0aa05196ace9274069bdc5579042895210ba7ca2dc58d8309452c70661386e4c21842a77c47219bdf512ddccfd9b9cbbe5024b41 -S = 0f8e07afaddf2b88cd2ccc2f720228e612ac00459aef46f9605cc609539097e60b10c6507ffd3fc27a15d348398c573bc8d385edb18fe0246af4c0ab32165f05a0b641d2e016f562397d3080d602d9c734b4d00b27f8a016f58aff098be7d09498b8e1775f0d7a3f69c383dc1abb2f177fa53ae8c5425a82a1a9ef0b428b70e48b7bd99df60ee016c4bd02f428a19225d3cba5e640d297cd28bf96a45cfa8e4e222e245b55a5528301d71e12b70246338ae0f4754b74a45fb670477aa1b1794ca1067aa1289819290ac7fa23bcea04442fd2c5ec835bb4a2d007fc2f9530995409f1e707220ed5b845feef66537889c85a89592d2df941cb61254b7d69ade808 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 5ba7760eab59b0b7eb22f2542c627352ef1c75f931f06dfca949644e4bd79d38104078a9f91296cd52fd3ee0343f00454d5f98d2e31e156f17ab3adf671624dd77072d6b11b011676a004f5fa719d2a69f05d1a7e3a4f47afce9b8b5f346148517655dfdfa1967adbd94ed778dda329e6e76e920376b5246de6da779f651b657 -S = 8385a5fe194a10ad210c8dc069899df18ba80008a47f0f8479aa690eae5588c04401b96afa0d8bd6512b98a46d137b32b48cde633f04604f8f08f63daf4f35b836374750d08cd20d4553752d3eb5d27da8b8d12e86cb81c592d39b66ac38c04f0d5140039f165ed670b3757282816f6b607e2708e66fc699dff5e81cf2861b64a98b572a5c417056fee1335e909f3f7b9d6930f399c29a92750b486263081e6ecc2a2da06dc1883f687a9fd480f4366c3099c7fe0d56c5c7a70b5a710ba021c075b9ad46e741189bbccc4f4ac936e71121a3c62c577f8157b1919df586569e6bb52158fd0f8d08ac1114981f904b5f8b267a12e1098b2f77918ee9189dbf29b6 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = e703433ae230a79291405dfaf58386e63fb5028088dbcda5c26e8f30efbb6e7c918a272461fe5d0d43bc31a77a4f126f18ccd6b9b9b10aac7113878e03f946425403760e1f4fcba2e99c185638b020b400f8aa365e6fd35088c0a8b105aff4c719b5578184ea98586c293c90976e58bbdd82a380dddbcf9af0bd1a235ba62013 -S = 25181c5f1450e2179d3b6ee166178c674fc572507cdbb0aafca5da9b54f10a3f223670db1122140887e68b9fe8365f316981b3d611157e2d579873a2292daab5e8ec6844ec58021cd814040cefda9f7cc3bed4eb0edd3098e3d9e5546060f19df911f1f89b92e82dd7aa118623e1c707ce43a2877ad085527ccfb5d5aa2775e089e606192f785f3edcc02c59e28dc9a9eae82647e1644aaacf05c91628b1f9cc55c683ca5e349946799f456bf8f2e943a0d93966521e2c35e294ca610dd93f4d871cc80b15bf4990a0999ab392659cd81af705ef0a3d84968f85393dd6a53579c3e463ff2c08b9f68efd4a0cce43c8118fcb61fa2fc47aa9ccb6ec0453b7ba51 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d060960864801650304020305000440df5bda9e56bdbe752f0af28644291a8d0fd9925f8794a485f27fdd5b3c603ebd68742e334ece1969a14dfd84e782e5ee8c8836b93aad629c63c826c84cba848defefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 5cb7a0a74095a6f284a13d4392aac30a73a9211df0520bf2f7e9831240579fca2f7d8d24fdc8d4161306dcf8b678b13be92804598f7c7308d10c0ab3bfb1092a3adee799113498b76a500c3f64e8f8a4fa16d8012bf3354e576823daed410ff54383b7edc5007a3d5228d200e3221fac6e1ca6fc0adfd92e53a6d96f10303994 -S = 25b408187418c512e7d36eac17edc64999e94011b4d5088ab926d29e433a69e24ebac43146a1371635fc78c3d215a66ea46d0a734b1607fdb9c3848a1404545ff60582abd579d978902ed399eb5dcdfacde0ca02145480246e1a22af5ddca7080aec216895d3528a8756e0c1a2059d392f87576fe896e411ddf02bd6be81ae2a654e0a15542a6b533b776703e2057b01ad02f5430d97c691f80219e46319de527541f0bfcf0b4e1b510059fa20779eb44b1ef293b7a8318447ed25793037ddfd1877cd98514c81575613f36d946670f632779eaf629a593fe99110e781cb38101a3cbd54d7871983dbf868a00cfcb17bd330309d43b8df8d4f05eb4c43649cdf -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 290d117f97d672f3647c2b24402832b153d22a25820567688645ed95ffa6e38d116347486ab4b485c27aef4962653bb60257ef82256785a1d3d52aa0e0b94c37279dee7bb308688aaee98108de6f1373ed2c12429c9b8770756c12c03908b346b129f963bfaa38a8937190cc656f057ef1a812dd0312f51285c4f46f9241f3028ea6a61db0e9255976469f5d5542ced55ee2d6f4afe766c0a70f49871d369dd8f3a82a7141639efd4a1f4a4009821c3c2b9f5c5f5eef99a5f00fbd8bc8191a3654e8f8d8ce12d90e5ff2a4c530b76306c8c56e0549a6f277ab2af3a60cccbf4bb4b2cb47f04f211f8b86aa653bf6913f3b5ed190c51b5958e40597a2dfd30061 -Msg = 1d9589c9227a3ebe444b5fdda538adf0ae8f8fd69b30b58e3a41fb91ef229065fca3576fff758d09bcdfadd41db2904f777fd9a90f0790d4ddf30ddb90c61875d20f4edacce3c7d5ed8af51be779cfdbfb802f96774579317df17e490529a0c6254036b391ab324d5eb501590b74b2bbc1fb5b45dad1b8cda1a2168258356f80 -S = 6eaf91209e0a5f7d985231c7226732f64e2592e6be2886081f830119018ee427b3293ca3ab4156a41684824f26227401f1b10f7d993b000f3bd5d82d831bcdf772137a2982af4f1fa2b57b49833b97f448aba20458f3bd8417872f7d6b6156300d87aa87f2aee301ff53b6c367dd6907b61b6336d1ac97c4aae90e7919d94b1cb0d919a33003f05f941339f5c7de72ca94d9b65d42176deb086ec259df9e29675c087ca0d42f51be4324f8e1bff094a517083e51794dbb68aa229f7c1560945142c4e66264cf8d8fbd43dad4de21b96522f4ad7d1d121fb320204b008ccef86a22427b59b8e58d7e44fad62921b44301249fe1139ff656fedd466ffd46c27703 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d060960864801650304020305000440b1601c43923bb80b35c45d083bd748d75a3fcaff22044525ab82d705d5465863cb373e069fa40c9b8e5aa4d5ff7ad45700c7a8da342bf0b16686db87fba0abaf -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -n = a911245a2cfb33d8ee375df9439f74e669c03a8d9acad25bd27acf3cd8bea7eb9dbe470155c7c72782c94861f7b573cd325639fb070e9ba6e621991aefa45106182e4d264be7068035595d7549052989b3e7fd04cabc94012c1278a0ef8672b1a51dd1a9e276816ba497dea24b4febe3dd8e977707bcd230ca6fb6f8a8bff9e6ba24fbadcd93f00126b19b396a38e6ef86d18fef945b9154c1963fb488c7025953511f86d05638bfe056493730bc6778446e59cd3c5c3acf07a0a3a64943793652f10e3292aa7a6d25a03181cc6f6ba0658d909e59ce2a02bacc9766fd8c4fbd4ed9c23a866844b8a794d49e505f9f944870a71aadbe5338039825c2dff81af3 - -p = bf96de108963b5113399b664765efe046e2dafdb70d6e5e29dc6ec89b789b059348d74d89129c7ade9ddb404c6dc3a3437c7fc9f23bc38dadc8ffd0ff757999f5c2d510b993056147ccdf421e03d0be2c74ec333a9677c430cc604f5550d0d86defdde71488e3db889c699a5cacb44dcdae2f3cca38695e783e6f6250827efb1 - -q = e1e7e33618d1b64d6862c132e4b1cd5fabad20ce62bd97bce2a3f5ad2da67bb0a7f0b9e48335a33b7b95e77ec4c47e91416881f9f7c23f9bc1918cc644335c74260e90cd7b2e0fed802f19e78c5ed80a431b38630d82f982c74a0381b8ecf943c60810fae90574e216357b2535002316d9529cb56420f3cc82dea37cb624e1e3 - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = b756bc9af8682c9473fe98082ecb72f33f6199099baece582cc6672924e3472790a90dc330af8cd6863c7c882d4e6e726ce106ff0b6d641865b1e300bfaf067cd8f8af38c1299266efb6eaa88fe66a30191f772528649449891c1eda921539b6b5c80ac255df278bd7f44b2efd9c4f766fa455459b9a4735bf8f807e441cc81b -S = 20aad3d29d4bdf75f18d3617771723419920e688928a0c742af8b11bd2e05767afa0256c868c3538111359b7bb91dbf1b8bfc383a1573cec0bf0c62837b13fb5df21e7e07bb5d758ba8d58171d22b46147d6f7bd3b8751e97ecf13a5bc8c9b5ef7f00702c3ca400b6adacc6de96779a48881fd7c3f544f95f99ac1037f6b9f49c308aed1f6634afcbd46dd6fcecc015fccc24716cc590687fb2492c96812c9ac037f743e3b47d60420ee271331031d290fa6179178444256acb5697fbcbfbbb4fd3c6227566de99b246a8914721d5dbe58c2411df01348b63bce4e3659ae7ad09579be43acadad01ba02eb4c118b23ef64b318c7424920c5da7176ab2cdadb84 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 196c5dfa45aa9b9d8c8f0459ae650aeb45f1b05e06a6ecda44194fbdb5b5e7ec79b0656c583d7b2c4c0488253fcf77a51586e4e8ed5d81e9a44cb9779bc0938bbb90d8d9b63278a58f2f2ad85cd453534b2a2983e32918368c2965ad529911f2e6f3006ce5ef5ab05df8329a8edc659dedc7c5576f72776803989a8560aa29c8 -S = 4bfeb7f6d376548f1ada66742eb2320689db85eaca0f75845aff7cbc91faeb1efe96ddaeabf8f9bf2b3031aff3711ebf9e4bbfd46861a8bb5107aea784a78205e067779e98be0a74458c0c850903f58dd3541636c2160a8854914798310324f852c3806f0a0e59ac6b5d3ccfd2580443d09752640e27f41b1e692b3ffec67c39868f4605230b341a2b56ac68bd2fa3450df2ebf4867ac0156be6513e03bab686f435c931532632adc177e95971bfad056424230943e5757d0c5384671592b7b0bd4a454d4d73bf312f4f46f2f310e897bb657be3165d040ff0d8bf72315ae313fda1052c37307a31c2f8d4edce4644b5bfeb5ac37fdf0e2a393692dfb72bb4ea -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a0500041476e8a26a34cb08f8f58253d073c53dd76a749c5fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = c0b251836d180dbcb995b4ae6e18856be5e8bf067841b753394226efe507c7801312223eb1efa2b3b117eebe001676deb8e94cad96aa36abae6f013d5d6f18f680665514e33b164efde094cdda7b707858c38f7496ac28ebaa461b0d92e285556d78910eec45911503b84de0e48f9abf2d3e2f626090b59c95901d666baa3627 -S = 0cc0b5e4251083e72898e6d239dae55489a42675123fceb8abf34886846e5af39d109fb65d55fb019c43c3fe91b891262d8ec0aa721acd97848f455f049d6af58b5e579b92208fa48f7afcb403dd99870bb25a15b33a67b5a1ad10ccf3df04fbf5fc42a2a0dea7b6c689d18da14757b2b5ebeafc39f62b5fdbe58f44f03e148d4e5ae6ce1bdce9f316daf7722ba6622ea6eb964fc3d0d9ab54ac226a3371ef96300d9d737767cbd04963015781d14d9f0f640b1981219d391ae1d94eab184d68f1764e7dc2aa2890b08c16ac277aab85e2912975702ca0834ff7026be694f805fb2692a605635a020018342dd89b8a53f8b5fc7b5fa8b13fbd9f8b5deebbc199 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414f40c85085852eab21192fc3cd95f0ae92a42c3cd -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 9df2b3e0f8035d92193f0c980e8ce31aaf7218078171f907da982db246533dff2a8553ffa7d641cbc14fc4bbc1240ad8d7d07394046795b9372882a0b7524da3c03acad4719996f0e62a578ea175459c2ee5ea0c062125cbb59975f3385f7441a939a2c91ef464e8cefb4d7b75289b4efad905d84f47b4259a138f139222bbc1 -S = a82261947dd0f5b3f34197bb91401278dca36b759a7402ae65d8db6b6a12fb2bcf67e564d16030fd1b7e4e4df9bf0577c5dd5d6a5d8766009277003d0e7929675ccdfa04285e74ecfa1a937db117a130fe4662da0a869d7d34832165f86ad8c345cd6aa027036d818af45fcc8fb7bf55975c948af26ca363ff796c752afafc8e5afc5ce5208bacdaa98601046e69e648975a87ea34b011237bfe5f734d9470bfe71cd5053e2831d321fdb13e2a4221f992670782b7c584634761b7b96a28e33b69eba97ceb45aa1adffb29fd4705e4532e0fe1890d1575b5e43d4aa294c27936999b413a3086b000050330178b0f71248a0a92af444d8fcdaa0237b7952602a5 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 3f3544b53b09a91b7f1a27d5fed879788432e604a8b6d121fcf98ba886396b657441211c0b8d47c9e1af392c4cf127851a3c689d823811055bb5c7a28c4ad16ac43b71686ba07506d8c4098bc4cccfe3fe99329f61eff73c04d614a8b040c60297eddea1428c5b59cc233ef94eb09a189a11eb122c21a84d5d241cc1da6571b7 -S = 8caf5231442d5352259da89fbf54888cd32774b7851232b21defd3ae6d780a5387ec021f0260cd299ced9fd814208d1102620cee37b2d48b5c9ad90c061f0c2a527bbd1eabd7aa76a5f4e083483eff1a9b5d62dfe57c751d9bc49991485569142c65656a67213c37907db465dc7225c7fcdd7b9a37e3d6b887b07c3dd07dfcbdde86baccbdf6fd13676e062f9f875f912058536fbd31d4dafd9c051bb79236e6e0f90db221acfae0690b6fcba1cd7716145afabd39866e393dad2ae99b24f9d97682e6c1163f5f442c4e49c7422923625b63e82fb1a3186fcf0bb81ba38d6761156b1f723c0de7fdbb0c678effc49c128e655f36ea465d41e704ad1b449294ef -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 2726543e530ab04b06a11cbae1da53aa966dc51642d390fcfe95acbfb0ca65cb28db0f77688af52f423392d2295104594143bdbab8517c0b59ea7beb5e2fea1e86b69d77688702fb076b5543a6671722de83bc88edcfa4a651a84c539638c6af6c3c6606fc0abff77cd2cdd50124744d95b229498a58f0150e5986c0ffecdfc6 -S = 51d57b3e66fd6e271241215438be99969c40d0ea4a5b7c4918143f68f58e5cd9d52d90159e7bdc9b73ac3d3d908cdda5e402f0fd352931f9bca9dd886fed30c791efd2466dfc7c6483aa32c2865cef82a40dcf5c5bc3aad547b8e1dc9d973c8b90f529ef272a24645a6b76887925b6e19970d9f2d7d68a513f2e1638b184aa8cd20967618d06662bfe1450f03b72d19790fd1a591694043b310d982077285deafc28f95b3c6218edf59649b38e9170fb3f18483fb3788a14b161648beb4ce471c0ba4c041b87e6b38067fb934f50908b755bd126d2904b75ad7ce75a8a5d0c3540e1d9c7ad52242f2e5a5511d46ad8099f9386299f369e69e53107c6f51fb985 -SaltVal = 00 -Result = P - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = b756bc9af8682c9473fe98082ecb72f33f6199099baece582cc6672924e3472790a90dc330af8cd6863c7c882d4e6e726ce106ff0b6d641865b1e300bfaf067cd8f8af38c1299266efb6eaa88fe66a30191f772528649449891c1eda921539b6b5c80ac255df278bd7f44b2efd9c4f766fa455459b9a4735bf8f807e441cc81b -S = 3840e121a02c4d4dead5197cabbfffd00005c9474df11252853dde2cb83ef772e2a533d7e51cf524af80d1a541994018abe93fb5835989e870ec3400f171ac786678fadd6e478ddd2d6f95719c559d737dcf2e5fa0b875827ad8558c70f6b8ab725d7344ac5197270e494ceb03b89680b8bf99ee9260cf91f0611060d7ada8d2c7eb672a2957fe4eb1d3b027c4062f2d2d840304e4a7faa243b816b10bc893b2ad48e7ada998eabd1e9fca72c0820b9b4feedc3733d20087da09c26e352fd7a4962c707a7ba9e1f66b18ea89d96d0059ebd13d177bccbf2d80a502a7362e198d7bbe1199d5587c06e1192ff539ff5276ee5ee8ffe25df0a1998e5c8ab05d3097 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 196c5dfa45aa9b9d8c8f0459ae650aeb45f1b05e06a6ecda44194fbdb5b5e7ec79b0656c583d7b2c4c0488253fcf77a51586e4e8ed5d81e9a44cb9779bc0938bbb90d8d9b63278a58f2f2ad85cd453534b2a2983e32918368c2965ad529911f2e6f3006ce5ef5ab05df8329a8edc659dedc7c5576f72776803989a8560aa29c8 -S = 411e75af44716f884c084569a3500b74017141ec3f1c2768e0720d3df6cf221a155812756068bfdc74d998743647757d80e15752b0df1ed038ac316aa202a5eec1d0363e773a372d9f60c4d5c585f1111ed44b02c241280d2b6980b2cbb09128ce9b6ed38d50dd0ce10b73961b82996bc82a48f0d5a574910a691e55048136ce8f3668cec4cebe5c791d6b66b6c54617bc70d0d578080f22d9ed09030887bbeb5408155187a03657b55680c614e57c2e28e2c837eb7bdbec6985af6b596fcba378084d5f1a4fb80ec426966d9a9f914431811a06133c4e6df7a48577e16a8b6cc5af6873b70dbb5ef191ac9214866e73f0c99f33da2d21d313a6bb62cf03ea01 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041cc28faf02c47ebeac647f99f7cffeaad70df6513830d41a12b1d05b62efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = d699ca7f777828b13679a9e2ca89568233b8cf479d90462186a5ce71236ed6760053f007e807d8880418b11746c59106090f408ef1133dc1199602c16de2893054d10fe7932718eb6e24b39c0f5aff302cbdee60e5f94961eb08f516e70374841a38ae86407ef2c2bbc538dbedf1a9e9e6e961263fea73e945222dd95b7a9e5a -S = 01818ab2f8883d5b580b7d7fdd6bd15cc59f59842dd14649b27aa0aac3666562e4ee8a716d8f9a6fe19bcb5f505956457fbf200b8f0121a070788a546b86f8149f0aa98f2c6439412ed4a00114259b348d1f9e583eaa54fbc384c52c518159e460582051afee2d4163350bdba58112bf0fd9ada18346891ac14888765a68d3475f8f8f92ac9e5f4b02480859f239405d8fd14a05ef95fe9b726affaef8c8d54e6cc3a01a1399b2c2b2eba18b7e3dd7ee337c0f108dd53c460112a58f7e6b09db540ebb72fe8e3d1afa5224705f0159aed4d94d4ec0711e58873682199c90e9aa0046f81c3faa3fb21a0a05991f0752ec7e1c04d9009fcdf69d68098f9eaaea6d -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041cd8a970b5e7e41f37017b8160a04e42a8bcf502522a1ffaa739d6cee0 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = b1d87e6e67cf95799888c51383d6e6cb4fd8eecb4d2959ac7e58ce8f5598ff69bdb8d19e5e55bdd21c4e75fbe178cbbb9d93cfee8b7d387fb5a6067fbac46578cfc8d3fe04108588c9de077eb009249374f205553bba9d0218b2449ed413a142eef0ceb7e068b744a420c3c377f1b7faddddd729e5484ee0ae64cf132aee7d70 -S = 3dfbf8cf23053223500b1cc0a4e43e7754f3490f33648064bb9a806d17b8412075997148a76a152e7becbcc26783fb0519df481711648b35ead7fccb9937baf37e4b86133c15ec2ba0311ed6cbfb742daccd68bbe8f1b49766366da644302a04ec1952db9fb8e50641e3b0cf9c04066f5d49cff593581beedda78e50615c5f42f31444462f59e1e3a8331c1494867361073e5ebb8d6ecbc5b356454a4d24d87ff4dae556442384aeb0cbfadb3437074a76969b8f213a4e8a0a0538114888c95436582ecdae288c4f142612e5ca9e273da165cade52674f7668dd170cde6d7f8e6c02cd1cb013c87ab4a5c71f9f04c20a0fee617968f4862a101726368a96f3ef -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 51a9457af4abc1b75f3bdd4a383b7ad79f1bdcea045b15953b4bc15ad216f44aa2fe716fa4e91d68061db3537e48b8f0dfc3b202ea1795f966c17ecf7332a3301b1a8add2ae67a523f8730a72476d2b45bf52978f9970abcb80215f347f4a365e484f98c2dabc2be3302bc0dd1cdb16c3c39a913dae25e245898f08ef763da31 -S = 9c7b10642d88022ee6cd2816c95178a5b163ab887a3b663c0236228b72a6a92eb18d3a0fae84526f1e17442a2dbb199402693f166d31d30105b7929046db4b1812cea8d7a1c5d5d53f785130cae9816b8254de0aaaeecac2992a1df4796dd423641d685e65478850a59436aff0f0ce36f1d3111719255dd376d8315905f4b3db7439ff2b0fda6226ba64df947dec832db48905a3f2d0d9a2b46f92d91794ab98734e0a7acfa0b60216f728a0a4f6c3e188978cf745e620cb3a0fa836c1a548e1b1bd2c03926473ef6b145d6fd99eb5d512632334a2588fd7b2640e0d893e6fff31350a467543ec4a18f51853bd4566674bbc2867a18de04953b1cca246a558d7 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = ad32c2e66fa67fa97cbbc8736e36a04dfa8aff5f734c75098fe711306e9181d6d87e7aeec7535b6e25dd0da5d6032dcff9f96de76bb737bc8daa944748a94d3c4e2a50dfa2b654195a9ac0cba4e0c962077ddbacebcc3bea5c3bea260b45ccc695a0096208b7b4d3a45aab8cdeb4be2eab7e1356fa73c8b98204db74bf4c479d -S = 1c0ee89d483230cfe29503591c7d002e1930128999e06dab41d60e55ed7fb191b068b2b7c606e0b684dfbcd7b43045f10cffd72e96fdb10af7062d1e3af334b2db7d79f3ca478ba4d21f4e2d9aad635c47c15d26eb86643ff15d5366074d009bb4e213902f8c4ed53f5f3c2e1ae0771f0441f68257aa9705a4044d6846103c75f83c96f3d23a450681394e0f6f816fdc5545d96321e90a4c0a90899eac77751933f502c4b6fe72177ac1e9d3f3a67b9db66b96b78361ea7c47317b742d6f6a941a55c496cf7fcdd73ffa79274898081490049612f580a8d1e7edc95c10902dfc0826be1066e489912bbdfa2c8d6142ce9e1d3dbd8c9a9b9400f39579589f003f -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 585e2aa15bbe0f218e5119f95a252b57ce65d9474d35c1c284de1ee79f2b9a88bd1364e8a19783c3aaee6a8f05e0cc022170b1d463bdcac61c2a01e3b8bd550638c5e59ce2c04aab367b2a14257b0a157e9c6411a9f8fa94970a6992f91401efb0bdd44485ff0de11b40840e21bf8f97cc321a8785aefa33dfc67e7acbf7474c -S = 2e02460ece0246277d4517b9c00d40ee669251ce1be2d8c13bcb67b7e90635d6a68f8cf7373bb5962ff1d182f3fe706ae3e216446527cafe5e763432141f92995002f6c6c208e85ca3203de5d6602db70c2302c804abcb7b3a22edbc120a3b59b1febfc485bd787ff0053cba05d27800ab41bb431d9b7d7ccf0f1a5f52eda8432fc70d1bbc5fc766b08280124df71d7432542d5caee7d88db6654510ee81c3cd23b1501679a2fc2b050acfaf9218d7c6d4b260f9e8b986e9dd9c158820379609f11626d6b35eda024aa545286e884b6e135ac3e18d52c9be687004f0a81fabcef972cd2e82d954a43ace6f1971d7311ba9f267b262303cb51121fde66e073e10 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d0609608648016503040201050004206510c46f56c48ac0b28992c5bd0fe4047d3baf1fc7e528f67b15f3b9188af1a1 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 790ba59678e1eca8ce7e7723488b181ff1fccb3e339df4df3eede794ae30add767c006f8c4a4aa5af263d4df961a01a1b6cdf5e3d6fb004761757f414b70a5cbf5d87c5a51e7261146f7693556946be27ed6b9fc5ded8e6799fe537b7f2e62b2e9fc0fa465d3e93693df3d0ecf21dc4a10be1e71109d27a9ae30692b90926af5 -S = 91a2efacfa4e8642b683ff7c17b08743f8bd03950a35ba44372ef1814fbdec087c033d6eceeee431efdc6a3fac97f85b8248a92b601dc4ea9e02a23fb921655f084a4035b42c0e491ddee05c4d3d4024b6446caf77e917d28453640c0af50d937b5d74b535acbb3ef9b2dc87bd3cfc80f24d2aa9b1feeae7b549c197cca6888fdb617c8a5a1c91a23c6299cdd1b7d292b0227634bdfd415cb6f12723fca2edcfd1176a485b2a2cea075765785077c84de1c50da27daf89407becac9fd9664f2547c5a9f66c9ae3c14ce318317c58d4c3d3b07f07d2f8a58fc10b854b583a628054cdcb9f7729e5707d151a4ba82b1d99f339d4f8a0674f260a8a6b8665169fa0 -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 4cec86b6da42bda1aa66d9f6ee0ec6c30f4f575ca2bcdca198d2f67fb494aaba4372b5e9076f1fc2748313971f3eee2173af967da5840d74eb7246ffe9d8370a6c9f2f795b646a69ebd9e3b8116869c73d1af57e45b83b919f307f02d439aae8313a9d6ec068c51e772fef60aed45e3dd7581b69699f8d811dd249915d012bd9 -S = 89a014c41636b64663cf381dcc399355e2974e1db624e36d5fda7d3967417a3810910948813ea58caab8f7cf2dec7309d26d5cf7db0dd60a0ff42982b91f64f17cae9195f2955395e9ddc7335c441de9b65a0e252f98db17a805ffd0d0b9a68dd6be098107f1a6f7cd1292b2d6a9c23cd631c62709b72eecfb9fcaca2a3ff036984bafa785722c3fdc8398479ab77a3e1678c7af85f75f7a2f4f54a13ecddbbd4aeec7a96445c885d12aaf236a9c4058e3e669335f5fde34d6905bed45cd741d9a08f8501706d03c7f98b2c7214eecbf4759d661a32eb9c302a9c0057ab734b46dc3575ab42951298b59d3d8429339fb58bf035173a84dea90cc6354dbf68d31 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 13f936517eac73d6776695c1ff3051850e32fab734cc46c280e355dca079ef3949810e7edaf19c783c187d0e0c32d074fc3a72a276ffc405837aaf74ec5fe5659ff26961531c51b56fbecb6b28455e78ea7f7237faad131659d9f290eb69ac5bd8f54fe233561bf5daff85bf9d9182f9a2a9015e07fcb95fcaa72617e6c0ce81 -S = 2eed7fbbf583693f63e22bf78eb4d389064c21c37b66667c1b1994934bf9ace14c30279253e9195d176535e28aced6719292b064f2cf99124d55b347a14c960af52e912afb53356168d1f19727d19b65c5090c4db0e4fa9ea0ee3d3f28ce0a956f7011765bb5e58a14b8854e58e04723bc73de96278c78efbed70ebc8052d3359ba967dc91b1f982932baf770d2d2f252f37d274b9131e8c5d4607b67115bb18200a2ead70c6882ff721284d0d0876ee85e68dbefd4e3a9d5d898aa9ee6d2195c822fa02d74ec85d7a93d9688fdc5fc0c93d9c7df6c1519ce1384174e2aa5fcca3bf92e260274f2e0430ba4f008928d6ece05f0ac5a26683ce956fb7ed43f7b5 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = c81e98ab21239d9d887553bca6ecbc55a1e4593036f8e670080d44ba3793b79935075121d5bcaed3a5dce2c17ea9b0f35909fd08644283205602cafaffa2545a23ab18ae889a33f04ee0d9ce7f2d9109e7eea21b2615c81c03182ce6033c93783b13d698624392bd2a8a202bd0ffc860f29b31afa2f71c2bb85752c66ce8dbba -S = 36403d0116aa5bad635f855b1aba7ccbe7787bac4d2d0678fad33163c6a19e88fa53acd13646466ba5e11668752f52ffa3333c59d9e00bdb9cbbb9e549a47c700b1d8be5e1a778056bbb0f4d0a3266cf5b78b2c8a224f460a20b31963105236decdb49f4bd3adad75b6ef5331cf0d54c91fc0337a5ea3d1dc94e6182b11d7eb6690096242d84c174a0c01869c81b193156a730ed08acb516da3a2b1646da3fc8742191e3620d813fab2f4288768388b5c2892ebe6a42b7047401437b625b7d87368991020aa1f4831088343c51af5217334f852c49b474fdee6676cbf8d78018061bf3c398a75a73503e868468136afc187ec1deec0e2a852b454befc60d9873 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 796a46d728d7d9d6418710970f311d92f5362862f71df0d47b3fb63e51c35712f2cdb8b205f3668628f17e4dec9dcbb0211d2f1d555744d297a9423881da2473755106372685d2dd5ab51bb6efd9499f1cd8f7d5fafb990b43a262ba593665b98a5efa0d92766302613daf7b1fcddf866ed14833eff238a70792dc6ce3bd610b -S = 94c00c47cfb2eabed6ce3b04f88e797b1b2eaea162dac2e51fcfc8b9f9242c0f48f664f0b65ad4305867758811fd1cebc244f026684835b451e97e6806ad2427700f2d9c12f681b2d601fb6ead7953209a0c47db678ce0075f34705e4b1cc414f74574b4028bce76a69e160ae8180710b31d42950b66f70c6c28b15dbe38915e8c36d7df03ff5494a1265041a801c5916ff73e08bceb792c536608262d60ec34f4d3ffedd74127e9d5b237af1d300ec58bd4475f05c568978860804818fecea2781c96752821cf22164b1b917f3032c58cd47996e3ff5284004723d0c27a3d6439da0cfb725b991601a801c89a77f2ba174e3980d7d3f1b342c4b6cd16121656 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420e6689fb887124d3316d9609e412b959be86b7b02a1be76f300ebcfc82701a77cefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = ac481c957d422abb5ce8a73366bba51b4b718d83ed3c59d22a4f0464f59f3f78ace6664aa5eeb27c0b0cb0bae8eaf29e828a04d1eb88a174d4a027bea26f49e6c47e0443437cd4b29acb2738c93f12e8a5224307727b376fb38fad3141a95a7e9b17dec87d75f724b42ef4f3303f6dc15b3e326da99b818a70277c06fbd2d909 -S = 3da89b974fb03b26a5617a391b68413d62d03b7cf27daa0024e7b0085c1f542bd82adc66102c16c57c7765b1bee5ceae98ed54fd5fbddc1dc37a3a75f5695c49dc6f026213f79cbab37093a9549465370b7663f363a232c81ecb71074166bdaed7a558c5bdab0a20aa7f5c1eff0258eea42374ac3d4b386586fda7913305a602c33b6ef6dca0718fc330530e65f44d8824b4d1e137bcd3aaa9fbf0e4079cbb02a541971ce5a25d8aa91918576bdfb774ba70848db5b78331c71c26c0682b812d03197970e481689c39c56bf1bfb2d7f4c0d5c8bbbf5b3b6537f48572d5f79788362a0a7172f20308cbdc64f0dd9d0416bf09c608e915c070f4bb444e3b7ea492 -SaltVal = 00 -Result = P - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 8603abf63e1dc6a957770c225394c0223874b3ccf069c315ee26a2761519d9e3d5fb0c0197a57f945b25d9369f11284f831b26412ce6bbe36618c2318db11042ad9bb27ae881770018e5af72b66d31d8fb7ea3d7440cf528bbb12f4834fc6d70550b27c7fa5cb6d7d7e0143d6051e4a5e5c6b2f602857bca36187021d2a3f756 -S = 27d202a060e759b168e451c6bda8a290ce96aa70eaad61e65a37962a766b851ad506cd68755341f4ce2858c24c27953fc8f85788fe77f90d17e7427f6e487ee4e41bf64773c79fc1472e89ef66f6cd532a1f485adb2cc3952a15e5b93eac7cb2585f03206733a142b8ba9465653e02843eb5c70ce8d7b59fb3b8cc2ae8d0405a714fd55638aca05b0bb3b5dca25dc7230eecac2c8fac049a0891e1b986308814486dc9d076b780b30f1c2a9b8292d2e3c56ab2980c3b3cf87292a300924c30bf2633f272deb8ada1149d3e347f930cb5a4c7db035352915b031f524ff07889e1abd54ab5ce572c63d0ed3ecbb522e7a4d087763cbb712eb44ff81ced4a9ccc3e -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 44935b571d8e202a7c257defda42c57a4cf3deeefa104f7fd31e9b7c7f73ce8c959b55380ffb12a9fbb4b0b373ca3413ce86d5f518180ebac081f1f791b0bec1e3ebb42813712701305ed3e9f7ce7086024587103c4f831098630b68030d8f94974d212f113a87b985ea8e975096a15b4ffa99464efbd70bc38c90d6bdd2698d -S = 64cfae08fc369c5dac6c08609300ad79ecc260f52cd9ab810d536f776aeb9158e8745474c76ee9119ad1d3780f0175bb48e239998e0580272417f9129fc778f5679d277102551387e23ea1b0602b6617bd323deffb2c894e24d6ff5de645efc49e9165a8cb3752dc59f81e0e205eda79da7dd64baa300743919969a1a3313c2e5b211d9bb3627cf6cca4f406481b95bceca64c733ba51a04bba15c7977bfab4a776009b82d152279bca00699c91d9bff0e1f78e3a81e52e2367c982a421cdddd7dacf0b888c36d7b9ffb3254f8140fb6aca60138f196b1c65690b40476a371ac2f62899d253e730d60bf62559fd4aa3196098a0ad53c98eed2a0476a4b51f264 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d060960864801650304020205000430bbbab81643e08d7a9d84d488c6845a98389c05737c2c54103cbb497d3291a181a2ab6b4e5c376b90bae7af4405e178ddefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 69ec7262fa272d2512fe9281a0aeb2ceeb77a0692fad31618b0cff731a4cb43961f5859ee975fc952c6ffb0bb657fe19843ca07fb0e4614e501ea6e49b54011d4d60b3c84da06f588d4d61dc32086f32f6b6bf77ca8e79c1bf70ce1126793983f6d404c86fd30fd6fd3ecdde5feb8f7f088e0539c6d30124a1aa7fe206e2e3d2 -S = 3ea196268020d94c900f39ee2eca7e735e0cb478de58836b575628ef46c5e78898c2d76c7627fe36baf3eedf4d89c2572aa3afa8cb8c5ee3433e4c2ab7abe8369047d21cdcb00e1467ccd60cd2bbddbbccff5a7e0f1ed9d2d5fc4fb587d41ac538e66d9b559793e0fa8e44ea72e9c603d236f1c82c4ccf665a5337fb797b001ac0f4acfd90e54d147cb196f4169dfa0f72744bad275a748f4b402bb2cb2ca9adefb057a6400855483bb12c8e51909a7241f413ce7d84f42f8e4032acbb4a97848a0f2a3c473af3f6e218100b4d446616d55d55571c0fa9e178f502370008317456318115f8276aa1e569cf364efd5c7de9734eaa575802b0db421de6309c175f -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = ab5e706303ef34f4f855722eb521454bd886ea281c677ff935b40b3cfcf7bfebcc2a7cf62ccc95f0ae34d5081724c43cbfa126c93b02c5e63a4870b1adad446a2b802adf932fa127f3a6be93a8d770e2c79a09b4bcb8fa423142de4b3228bb528e0684068041e2028e5333b6b263d4a5b8199bd2e7b0a874e34d5ef1d28fac0a -S = 94c98efaf358dc0ac76b26f7f52b6a9c35bd8b63f9517a5b679af3cf3c48fc4ec99e5c75e7b1ef27a4dcd5443f6f4286d798cd96f746c63c290e501938196421d691faf84a5009e410545c407d920b14174e66da700b457b8a8e2e59c094e33ab1f0b3a5a954cf814da7587c95681d990ef86c4f67ef97f2ebfefa600c190a49ac88cf1c6bcc8423781117fc1686da1ed0032baa42d00fa62c38f5d3d27c355eca2f4b79b57b54b7f97c43df57b546f2391f5328ad295a16b1fb6d5eab36dcded973a7f34a0c600bf8008b96b70a3e8ce0d706d16dc2c1f298978c95d4823e406f433a48c6c98e41341704abb7860120db033591eab0674e1b2f998e58926111 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d0609608648016503040202050004306234baf47b7e2a2b38f44db0a1103dcea4fe9e2f3c6b951228d1b7bad3672f8bf772a915bc9bfc52d1e5c51165c50adc -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = d2c5b7edd8611a62e537db9331f5023e16d6ec150cc6e706d7c7fcbfff930c7281831fd5c4aff86ece57ed0db882f59a5fe403105d0592ca38a081fed84922873f538ee774f13b8cc09bd0521db4374aec69f4bae6dcb66455822c0b84c91a3474ffac2ad06f0a4423cd2c6a49d4f0d6242d6a1890937b5d9835a5f0ea5b1d01 -S = a524f38bc8b2104d55275efdcd8f1bf9d529d9565a757df8b3f8bfa067d5278721006eba463365945b81ab4a504122021f8234051847938ab3eca24f95e4aded34f9e57a7b377aa16fd9379d0b703accee4aa78a015d0986e20c4fdc950a579494c56eaef8b812e2bb0182b74da9f1c0e1e3b56142481d18e64fa797293fdbf7d8d54c44524fe6b957a06ccd292edf0e0353b96e047813662a7326c42c8bcd1d231c6a486699b756fd1c301b1891da6d51a3e5722cfa46592798e91d8df31cd98a3dd0b725391a4f9c6fa1ba312471f8d1d85519f8df7ba66244c5dc679a1348d2d415b8aa22b02a9322fd2469f9da475a8d832862e6a0cf24eee957eafc488d -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 302093a4a99ea31b8a693aac1743663b725aea8e19c1e35fb01dabb001a1fe5f413c5bfa9410add4d4272b598e617d9e4eb1203d1d890b5f4793931a62a28cfe8be8b1eaf36946249baffba95bc014c2294dc7d8982ce5899f09bdfc9c583e71988d5b1ccd90b433656b7246854672cf8a96a70a9391b9063fe5f2fcb8a95be1 -S = 2efe346135008623c56353482a684924e55455e5e75746707de371b9b14ffbaaf5b5f2ed85bd7e28ce4e1700af5014bbd315c32b872d567ea214af56e8c3276cebdb0f597a6bf2b0758ae2e5d1e2e9334a53f838c668bc9a1503010bc5cb97f6215847802827ce9f88cee4233cc80a1afca84cfcf7368e4518e157f05447586cfdb3ad9b2d79bba5a6c4f7494375472fb9075d61ff42c7816e23550f1643b758fa26f4377dff2034f5e68c5889665341d482bd4175a286022f8346ca925e925f574cc961146c4e2c3e8ba12e083a0ad31394357d099c973a9ccdd4a7a6649085fc1d4a377911be767bc9f96df50f991a9a589c5d5d19c3b3e8fcf7127b7e32ad -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 634de10919c2ebf47f5520cccd2aa37f484201b015fdab5c4ddeaabd548f8e6e6625a7d172a478ae2cc6691c5ef8bca57ea6c2a586b84ff3005d6bc360074acb97b77fa5e57a6c75ef33fdcb119c96cbf588498b656b4dbc5d1bab8d65d83bcc1d8bcf4e1a4bae92f02544a1901d1738d570fd29591c8dff8da2d3e1090b48b9 -S = 8e11eaac64a60172d6bde00aff7d654c61661c4e3213bd64b6141294b3d2491bfba0040ba09eb060a14a9c754b1b3dc74dd5e6de8185eb1cb71eae7464b1511d0b302864b34c08b041528807301c01b33a4630c74b1e6fe829518962c380de8b9094f4f90178313a7d2229a0fec1a798056b871a25778813cd70b35e713cc83816549f11717e3dd4a1412251c1082df1c03c0def3ddfdf3d7cf1b7654e5af94866392ad32330f45b7e9491a4d1cc2ad64a3b7ebaac075cb26d5115bf9a846dbc29faa8302a5f6337fa2ba07f9987ce1bc729e67fe2e8172bd44cc79ea15ced0cb49039ebc4749713343f136b7c32f5760d403568a4a6bee7fd697b82d9d44983 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = e532de1004ff3af1c5cfd5459c14e3c07acef7fd9f0d731fb0b143b90975cbeb542c1dce5a4a70121aa5cee6187d0c18f8baff7e4b76ed94a9bb4266008e84b12b2c8945c793e8ad4244ad123448515df371e99c62e29da709d15c036b8cce0693ba8a3cf1e48a0a6434db91987c99d592791b1f895a6ba0f87cf956f1789034 -S = 522fbeb9dda25bc573f9112a9f91c17edc93e2768e3500b4e2a4686c9548624900f28c878fa71336798cbe95dad6c3905ac04e4709defb972c13b6a532b0f827b86a8c809699ebcce39f38d71612ecfbd030d320d709edf5a0b7ac3f3ea49ccf8429066a679d4a9f42cf2e21bfb2616918fd80fbb7507bd301a6c650efa802cd4b139f02f65408090dde62bd825e04afc720ff8850461d5f1444bc49ef8f6f4f06e7aae64bc0f9ef3beba8298603aad62547ab8e94374cc45f7165e08c612408fe29ec242b2db649475dc2b76debb660433a2d2af7c4f82fac4b858f0b715e1048933d54bf2830f6373e6aa1ec2f460889c33b3ff78a2344f33929dac1c728b0 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d060960864801650304020305000440ed1dda6011a1309b31409ff9a5f57605f8a6d33d91249b0c1e37bdeb6a580d334c89f5332a598379bb1f37127bc39366b275962c3bb9b888d6d576fe89f6ed37efefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = fcd993a231000dacf06ffd5d90ad238d5f67c86a9f61ea10ceb2995a2b31a1f7752b69c0f6571b48c00b05b537af40cfcf738f57173d899af7e5fb4635a5887b3ecb922524b15e8ae3ef721fe8cf42a0d4020c5f7d9101dd3516a597502b7822e023d67ac3f81c98e0850c42adf57327f57c082bd845980013ab60f681abbb14 -S = a05058b41fa7d48c6be9420c6372d559d466a85e174c272f7394cf3896e1b945ab8941462cde4042d1da2a8b4ef11b5de2c720595855190bd113d566d420b31d51cc87365a2b8d7be99e2ca792b94ecc5364cf63be7a16aaed3a723754d7491480829c0cc9fdc1791998f30ef80291aa756fcab57ff5f3e7fa2d6ab001c52e76efc8dc18f5d5fa2cc762ff863e9d6d1fd921376a8f20d4dfa61f0a4c389e42db2adb07d168d438d1ecaf8e4d62006a29d944b1b5e5172d99579bf03addced9aad16038997d2721f365629cc5b065f656bd306cd76a01cba35c806a476f47c7f9b50d211b90d882201bebac5204fcff51a28d7b95c12eafde637bc50a10a0312a -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 55268a860d34f9ac8071c4048c4d6b9e5475b9a89da448e178bc475122157b3828158444ce016206b21237a7adcc4ed7fa8b5d079a5f07d8f619a5d3c7a6465a339cf4de38133a534eb6e3e1481a03dd7c4e3cf723b33ab5030d80204bdb67bdbee463be1313897a9c844e1b27df929622e5dde10248e860e5c05fa0755be547 -S = 7150a5c72d046e51f58b5d2bc60886be8b5d95edd49ee011986915138b53dc6f1c20913513418fb9a5edfcf4a3a9e4c6302c5bff2227c81d447334c3faeafda5ab5ccf2f25da8217cb3acfc8778c22bcd1559180260a8d9a3df3b2e1c7f1696bde815b4ada1e44b50b500a0aa4b880ba68176aeefcf96db028383b124f5bc7b587c6c6a726e2af4cad35b85d25fc158fc44d34a5bba69fded3b37af8cab2c53233a6e363e153966e10d6c7606a23a51b9358bb964f49ea3f19af1c038c5a1dba87b68b5802fc75f8c68a5486479391e54e743ffb64c185286140db15fdaf51aa2c6173fcb3d60f736a460623dc351f035d546f75fa07aa496f65bd8e4a66913e -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 3babb27a2dfe4e88cc8c030cae74839c9dcb5ff5be29776bb3b2dfbb1f52596237ac9188002864684c470a7cee03ce84a85aab0d4dc8eba4513908dc549458d4f979c0e057063e879a5bc6a1dd8959f45d9d2c1fcf156169d351d038cd0246990d19954b04a24bcba380e52a38b2cbb9d5b9db1af3ac0df31a458bdf4a9e1bf6812b9c2469a8e384a96d1ba29bf009b8bd0bcb098f55523ff8e220ff2aadb50cfcc2eb927e9357b51c5001123a46016c47bb7a8ade6c62b5cae190a3c89b7993d130e279f0571643f039940c5e0e6c212f39bc20d014217ee8065090eb249237873bb3d05a2ce846d58134a4ef435eed617e4435e044471f86686db1572d6531 -Msg = 587e0c53dc96138e7a0d05f8bb10e6d7d8cac64a87e538e7154e06a2b53923f01866e12d3da2643b8b90576d1da9dda35d82cbb6d44d141640a385b1e781b2172c9030dc60a9043eda985c084a207db74a40fdda36b532bf3ec0ea4bb9295c2abc845f29ecb3dadf90ac7c93eb7dad5ac88dc48056247a29362d9e38d33b0b70 -S = 40f0315cfa6e8180e68c9f409917bf35f6feee875faaca6f63d41caf57ba81f1994e4781bea5476f58feae8681229546e0b0ad4f6965e08b8c4b5915a7ae72430c18e556c9ccabf9b2adc9f4a188bed3b70982ff3561290e90cee779fe0c0a98da503f700815b9720126b1c6764103df4e05aeb81adcd11792e38ff4f072b5f403e458459e2e40e453bafe96773c489a3b55ce8f3a2dac7b5fcfbcbae53d6b27fa9acce6c3d9da72c355e11e8f56290f75fb53bd41bd0fb822662d218c6e6b8148c5a058bc2a8855e00d7d432db7ec3207be1f106cd1497a55c46607989fc295426b2f06bd7bc4da7ed40604efff01f037450abc3a1e0a657793e782f8a2389d -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d060960864801650304020305000440f7868e28e7d36a3691e196c831ce747400ae162cc2850af22ee47105eda53fe7b8826b1599e66035a13e247406b04b27b4336859fa666279991b18ae997466c0 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -n = 93397894e668653afab24bf55c15071960a81157e680444891c42ac0cebf9ff99e3739e12d0223d62ea048e77ee284582a707050fd11258f27fb6a4e2b583ab37ed0799708e3379e41b191092b2f4631c974dfe81993c740f21bbd0d828ad398893aa33101f445e5ff02ca498b8a851100e8d50aa2fe4c88ee38be966222657f943f9bed73f018a4fd371d208c362cb2aa4d1cec9c68f8416ef00ded34f4a1ee4d59a8ff4c5b3deb33c504542dfbd772ac649c8313644a32205a602cb5581819e4f4a2b8150e63e20669690429a4b5cc77577295183ff6b760a1b5fb989f158107860751c7808c54c1c511d3057b5e9537e009576b723dc9073c0b03f28955e7 - -p = cd819c9501262da3cf149709f0f56e59c2783263e399819dff248ac9e674c5d1e281e2f6471aff294b6e1db918d1d52f20bd4777b1175440c9b40da42b1c6a0cb28e404ee6446d19cdf7559304a693400d94e826eb90772fec7835cec7009be5e6b09ee7052d0b8ed413eec628d4ba9ea2dba3e53fb6fb7491eb3ce3bb16e88d - -q = b765ec141594c3a8503df7bd3e31264a88bf76ada5d529ef0969724a991787e8630cf8ee8c223fb9894c98679235139a5424e778e72309f7ff60fd5766d3edf0aa21f82d13c1ccd9d75d7799917b7abaf05c1f2dac240dd0bf3c1af0d1f5600bf46e93da91bb36a7031436e305b427af5a090b484a2c0a397d89f92c5d9c9d43 - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 16ae604b3a4e9c7f1d616e2deab96b6207705b9a8f87468503cdd20a3c02cc8da43d046da68b5ed163d926a5a714a4df1b8ef007bca408f68b9e20de86d6398ad81df5e74d5aaac40874b5d6787211ff88e128cf1676e84ca7f51aee5951efee1915dcc11502a8df74fac4c8451dda49b631a8fb87470f0ebe9b67449bbd1640 -S = 3a0751f873595e6c75cfe668304ce23e37da8f2412bef538256db7333562cd7b7457506912e176b8af543d5e01eb9742c8a42d356453a9d2ea9b78d6774144e3237e8fb3c0822c16a5550cc8dfb52af497df73d30643b4a8abe07c8e04cb165909e030faffa2429089ab6ca3d88584a0669e4955334ad5c7d41bc5efcb901f7cafe0e31552da57833d595fcf955247545cd057781d58f27c9c1a835f19f40deed90628de42de3b3efa4ad1a7311e67ee3354f6234e7aace3d39751a84611ff53d3ba70a552a78c74094c84cd401eab240aa33bf9c1492d1e173750f7505966ce83fcaae886102cd139f827386ff3898e7a1fcdde095cd96165a11b47ad5a43ca -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a050004140010617ed97007b337d2736ef686b8bc4f438f2c -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = b3d09ef22d893ef3cc09eaa9b2777e982a84341ceaa00d45956f73e484761ce6c61b31e165ccb0edeb7e0fb5255922ce27b13e4790399f8110730740276ba8032fa544919c5493d583cce5eb593a087bfe936c46f9ca85fe0646715bce93db6bf5581f2a5989ae5299ddb574d583f948b5110542adbd88657fcff95c01567cc7 -S = 859c4b66e9843f82baf341875b80215e16acedea013b10511a993b8407d72bd5dd00589d4016dde5b082f8cb0fee5f339d3e4167ba2399269e215afca6ec2c1ec3d572e214f9513086d281a4ccb5890d75bab00eb4bccc44074de6fef0e8c21237f7630557374da6779889016709aec7fe8c2999d14cfdd9a617bf858c941674737cf0723f146759e4aa691f4bad8af3296027f92fbb81476587f76759592cdc389a34d06d2bdab0bc87742e0013a11b571b58cc4990828d374268995b34d7eb8c09928efe0204cc349c83f575ff70ff3d4ffc9026561ce0601f17c8cdc945a59b44d8323a8c3dcded6158e880c7e1a214c2d3554e814a0b9c64f35724261452 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a0500041486b684bc197e2f935d2cbe5ddcc6f94830a4ce21efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = f41491a2448f0abab25b9f4958b6eb93343282e62dae1d2e5485f7c369057685a1230e2ba66c63d8e03fadeff33a612989f20ee551e784bf48b73c633791f4a47ced9ac80e7a6b26bc585cf4b588b95a4da10ccafec44094add106b52fdb78f00cdafc2183a06ccdce0f74fda7883b4d0aa645403d2d98d60e3d1d615ccc4a94 -S = 81007a0eaaab1b6205fb5579a55d50a7d7b4bb077eb0cdad18756b4bddc447cc6f1a427cfa32100cf5c0c00db6d28c371059e6341d947d843722ae8fcd0c81a4650fb96857ca5d09a270cbec62a2fcbf997b67fbae0763a5cc28f526c452b416f25fdca7bbaa82c966e7be2a5b0866da58b05e024439f15428b0815117efb9c08310e193e7e7a5f2371f7c2c2edd17616a7fb991c2e173b7fd80ae4537d38ed647c32dd16129e56600d32418575c608f360368b750faac157a3a43ff665a5ed5c545e07f413e9475e7d79d542356358f0c554cc206c3880406447308d1e0d1871d90a84ee4a43152488acbbeb7bf55fadaf3e8b32e01a363ca8e3935efda1e43 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 7cf8f94a517da2e5f856e8ddec29ab25a1a3b1faaf0eeb193326f92e7228ef8fc02d5a2aa1b67ebd2d88e245b9ba0fb8b30c94f6ce7a4dfd5f11e55d07029aed93f540bb209f8949839783f6e86562bab8dc8016c1aba24b912e7dcb228a79edbdf8b4e418614af2c22cd4d9c0542e9379bd7e42cfc8716a8f25c85e0be814f8 -S = 636d180a954780e947e916eabfcd4cfce80dc0cba1cae58342e142207fee42f3f6655ffb6c78f89fe1d2f31ed54e991d14b814583e8c84723263a22734acadfb5bf00dcd6df8bda4ebb3927a36b13bca2991094f1f92610dcaf953b33a4d1cf571085e297e3cca697e4aec953ab2134e23e62d176ade623e3e2efa562e7e0a87fb7ddc3a169325cd01fee10b2f6ed2012b9c9db99089521d2d15a15da86fcb165501eaf454bb36c8798e0476f59bf2a7d5eb395228744e266198032de0afe58cb10f81dadf57dfad47f764721e54f1248c00f98d7fd2fbbc5aa0998b8a480a73df7c2eff9940bbf644cc821ffa9bf570f2b24c43570b81c103cb4d0c39deb507 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 7ff7ba5d5e8aa7de3ffc560672a9c1b0f2eee1c39a8d7fb89553475617f81ec04a46b5b28c7d5e08d7f71f80800805c02528bb9be1545b90c1b184937c73ad115efdb92e8649cb51518b5be216118a52146eb25ca8d7428bc4cdc9fd9cfd5066a264ed57b5b695c1950132b59b8df56da708ee9059dfdab284ef3c1adf5dafc9 -S = 55fd6153dfbdd9850218c3b48a4f5e74e9aea999b7e0bf0514481f29b9491d62a4a4dbae2fbaea27cd4dea5ddfc17052d3598bc329eb3ec437d1001387510d7d0288cfe298cc5fd9f7b91c887d41d81d6685853285d67e874467c036d52be31ee49bfcaaee129a3cda168b59ffe523ef64f7e972cbda2afedf1a0fe7c6d457d79d9a73b7424fe6ec4290988dd81daa58e1fed69ddec52f8482a27da34b70114cd07f04591c5d2a38eefba0abd33d4c1f500a4073eafc5199548d7b96c772cac71cc02e18fa998f143132bcfa5e44f2dd62692c90e9a96b243ee20310fa9fff790b04a2d8811b46c5c97e66dbd5e36b03aa290cb9ae27ba94018e61430eac223f -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA1 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 3b9ffc79b59b069fb97124a6c13d51ad413638c1e8e09dab2383f90be4db64aba111b80d9feaf446703fde0fbbaded1a3b8d65a20a26c44620225d17163f43f0304768069b4206bff3ea3ec8095f0062e21c2afc032af407eb938b06e21afce4f129548b320b05b24a5b8cf633bd512d3fcccff75953f4958ebfcbffcdd45830 -S = 7f2efdaf79621804a71b9fda74328b00a65d949b26f739e1b9755ac860c5ad7bf63453a572fc54d6ec790230ac91a150ec428c252f2f8e222625b3e3e65e5abe5155b55da30fc2a89e22101f15a841058ccadfcaddb5405738d86fbbc85d82062dc988a945fb2afb9a9c4d52494f0cfad39f120577931632c31a63f06a370d1150aa4a45441bb31ccab8f7f742f5419a14a302ee0c558de496c66002a02266154ddf2b5808e33b920493e5db1719c9e6f7f43a069455024364988ad622d8d61a5b798a5f9849cf29a0d59eff8459ca65dfd0ea1a9381e8f595ff72d59bd86eb04afe1c4b61c239a746eb102effa940c011321dec7675d99ec4d03261ac254602 -SaltVal = 00 -Result = P - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 16ae604b3a4e9c7f1d616e2deab96b6207705b9a8f87468503cdd20a3c02cc8da43d046da68b5ed163d926a5a714a4df1b8ef007bca408f68b9e20de86d6398ad81df5e74d5aaac40874b5d6787211ff88e128cf1676e84ca7f51aee5951efee1915dcc11502a8df74fac4c8451dda49b631a8fb87470f0ebe9b67449bbd1640 -S = 13c5d85a48e10871542ca7b6c7f7fcc0f86da6e9cca9fb9b8f36f30fdf2f320b61b73ca1ef0b9c07af8e675f32b7a648ca109885c006971e821f09a489d1f8b79dd2d03a20b5d9c02f0117bba86ce8b419c67b90093d89f2631dbd38387a847b9490ebbfd7b6818f70e09c3ac25223ce2199030df51bb5da8242d1dd2396c72062a60f481c73a830c109e74b9fad92d7a9a414643ccb2e392afd13a8deab2b4433b0ff5eb3c01892c71a00a3e2d1173506b6340f57ad27e54a4bc5e16d50de2ed519f300f2afff9bc2a39e42c70a0fb02123db01500bb79dceda3a33b915ba095fc1269542832386a19b3ef65f56d8bf64ee4c83d5411bd0b6f097a749556917 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c35674247cb0e952ef2d28bf3e3c63c34d0ea8b3f194941d3678440aa -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = a9db46f44d85c4414d15a62541906e6ae498c06e2336191174d6bdd16993f13485b56b674e780724a310bbd850e9cd06e03343e6b39e9c535062bde4fb832e588b538637763824b62eaf20dbb09181e35996b1e1fc172ea7331881e9f28574a062bc80adec4c85bf93fcbe768810f3c9f8c7f0a5292837d6c5fef22b76222bd5 -S = 0ac7106eefb290dc2681c447fae564aad0e73028927907b323a7e1c340efa53638349d3ff6f9bd393431f085c84bd5a447a82ac98cbe6100eca7becaefb20fcbdf3c13cf883538e39a7c47c92e0a0da716bf520835156c02ad30d357115e467f9fa1b869ed1e6e1736402c2df62276cc766a0916ccebd7854f0b6f14e88de01164491ca82ed831e6e2f45b636b4ac73a3a0e0522cb47ba1758dce66ffe9e6afcd09ee6820bea67ff7351a157aade87d7243e68d3a14824b07c0a831260fd4b21020ad943ab0aceabf2fd259a038d30f786ce3a60c6fa68a5d7b1901380b19912a7eb61da8a224b9f0d2109bd161de1d3892d1001cdda4fec492bfd1fb0050039 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c062e999e48e75ccabd60ec5e67bdede1b8beb5c89c5b8455d638b0f5efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 659bd5f2edf90ba229a140bceb69036750477ef4f4ba4a646565882ad8fd2d321b669d21cb197cdfc7c9c053e4460b6de3a1396aa09134538b1510c75c5b54fb03e195ffdeda4a432fd3db59cd96fbfc1a4f385234edd06e70cbc719049036d20354e6138f041dd64a07b8580d217a1ddd98a4341a96c6bcfacfd4a736637cbe -S = 8742d7f61cd01a1cda403f08a9f367dd2f62895531634920eba3de112e3e5dc30752533851ffdba2bb48905d3532e2a55572ddeeade4dea7f80664b243f951282ca678194d6b91a9fdbaee763b01823ca4037d77cb3aef976a90bcaf195431b3856c3b598bd2c0e9000970e49d0938b3492b6c710ee898fc719b40d0b5cd98a54de06cea29584361317f4d8adcb23b982479513289c4729ad5b39fedb2ba6a6cb83fff0c2dc35d8997b9bc0d8bbe45857ffe3da67655cffac7c89e33257bb08ce3d10610b53cde7d8b31d721ea34fde8f798cf91a866bc0a52a9aa03e24454e0ab27f7cc00219072b3cebd9883ed1fe5dd02d4b59536488931d5c6059794da49 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 25c6f8cff7a49f5c0b7c1f02e3d4b8935c26cd768f33e79dfa9bfdb6dbabf3a6dd766033f62794009095dabfe718faa2b29c021205f346a47670a6497fb10fc523bc4562d44edfe5956f93c15c4ab38bba3cf8aebd2b7f60161911d477f8a7b13fc02dc459c087f16131d2700911ec36bc2f36b0818298b721bec6c18c29c254 -S = 44e33dc3011088c96cf066e4a3b93487d86779cc770c43e7a7b5d6b722cd582ce8988a28605a4961645d9bfcf60b68a83d8a5f2a85dd07f358715fdcabcea43c2816ac12771e76e54c14fe3073e1eb43312cd0e2fa0c93f07b0c215220c59379121aba72fc7e13702d9152386f6554b12b0323cb42d09ac5ad5f065fe6b045e37812a55cc6132a6a9dce1a7928a974e3e35213719b3175f96ef87dfb1cb84a67bcdd5f5b15fe2508bb6815809404e0e6b1d88da4d7202feffbfbd76010279fcd4f6fc233b27a934601c4e3701fd00eab581fde1d2aee3e27ae9b7b627e208d013fd0590c3718731c19f105258acdfd10fc8c542982e6d86b7c275372b8112fc4 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = cdb5d9071fa3a040095d41253a6a8081200ed6f4aa095b455181eaf9593c7f255412e380e9a28cbcd345be172c40f72dec3e8a10adfd8a9ab147e9022524e1aea74e934807e5ef144a64d381f5d477fe883f080e4868939f41b925988c7d31b1ce4f318701d290f077a3c88b1b8cc89cfbfb981703b23ffb0bbfe5e115af35d5 -S = 1dd48357b45763f1bea1c5a7b0f346ca8aa1ab19b163e05c78128e5f9625a22a7b3b1d8c18763349089725fe41f7431bcd42b965ae6f7dd00ae046f7fd2161d344b471dee5ff1d9fd4d5c520a6facc3bfbd8650598b34ea6c94d684b0187a2437c529e4d6408852662fe70c807c1270427b02db59f04b8df01a087f3ea9e3c80894763de195fe7f92dea8c70a3bb85864e410a4e8313a836e47fcf5050090742fbb1eb64703d5d599fab43930bf4b8a916c134f4984993e2723c4a5814265c500da5caf709143899c5a5d8eb199479aa0cf68366b7e80ff21d1352bd2bac2bb2c63a8235a379b3fb3baaa416243eed20c2c861e4924b71de1a74bfc96a85ad74 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 14690026e93115e009238306861b8968408c9f320614b61afe54c1de47fe74eedc2f4c65bc00cf3e485815c5ec04874b0109e71ef23891b99e040037fe91930e080d91f9d3436c36fb6d42f2474aa9028971acd3c6e511a497e9def2cf161b345eaad8c97623722fec0d1375e01878f3a06df738ca42c044b1ac63f802b592ca -S = 0356405c184af63e2f550081e8dd7dc7138bdcbc44d22e6225bb4babec42983f0556989ebb8bd6df4fda3b1a3d4abf2659a584ec0790379c74c7bf156d14531939aaf920fb9959d5e7cd0d2fa4f86c8029e6271522faf29499d50bfdf1b20e68de2fe4a52a84db86a39491e0e599935c3b726f6b7b876e8bbc633d05ccbb3aecbb9d1e419bd2bde528f6a7ca6ab4c9f8638a67d9aeef1491af6c5fb1c29f76a68e981bccad09d3eccdbb2fe5d44a9bb23a10f9a0fd594173b126fcf145ac2a3420e78b6b195ca4630aa2a48fd62192f21c34e8885187489eef8c79a67aa079fd8d2811a5d41b73a1cf78133424943b3414dd183d8ad242158e3c3c956185a153 -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 266a05f02ee6137da278d709b7504bf55978e432c215c5aa4cea34db831d4ac57f3eee07718504457b5be1ccc51c0279cd1cfed7fee8ba8785cedce5609f82e8b7b3334a702e16e9fe82616e7935152cf4e5e94b0b898325bbf9eef077b1499e77d1bc015469b133d2f44035fc22ead677db8bd610808a4c97745345f0db07ae -S = 598ea4dc537da91b6e9593fcb39d89f28fbda380f1b42858666b6569d40688929ced67f6df07eb58bd984fcf51a72b863649603b6e3be9f99cae28015959ba7d64fa4c0f188f849774760074d46131a5b78b712d50266feb110ab034b62bd67b38bff88eb5f04cc174c8c9e2d8f8daf6c33038a1a10088698fa09b6c397db2da169468fbe2eed851ae1265cfc05f19642d8d6ada114f4ff065e6b7b132d3cc498ed23ed4317a3d0f5c5462c9afd7dd196faede84f5f8e40b3bc8913797f1e23ebb3aebcfb23749207c95685ecf0e3f164291c1fc9087a49c88fca0b4736c7c86fe1a159b6b34dfd30cc626ef4c458f712f4a879a730e8fd6b2e075cd02b96011 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 58718b3ba6a4ddcaa7d3f7bd46cbca5591f95d87741fb852c74b004f8c0ae38a71d937909ddcddc9a8d3ec08eb490b61fb0e1f3b70e827a5eb8663ee57b5bc6f6ed760ac7f90ad9c6fc25044ffbcae8b4cae83499c60c8a15724db91540adac756524fb6d72713ea048a6c98088c797a8dc0d0d980f065ec150fae600c6f0438 -S = 29c5a0ab72d0219034ce32ed330a4b388573eb804713d98029fbc1da87a474eca1f1814dd61e26c7bed630f3a4f980734321d56fb3309c751953a4dd9110c293730829bfdc83cabf619b220818e30151c38e6bb9d304eb7204029f8af86209275b1b5fb84bdb12aeaf3013db78d6dc1bcbc23fbe3dd7eb3c3bec332c8453de3ddd2e39cadf7e062f00a682bf18ab68ed3c6bddaa9dada51c99117eceaf6f8179eb9a59e6143a56d5f26d4138a5c31e49104c5982cb1b202253a292786cdb94a2b383c9d96afaf83d52160eccbc42cf2568744999a662097b315ded7fb417a823e3e9b6c5f7a822bd58a4e5542fbdfba63f60266c0b86a363153ae0444e0ee1a5 -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 35524c5781983f729374b6342099239157485a64b9cffd112b50386849c3afcdfe3eb5965174bfb5827d189756d5d64cafa60ce75f4a41283e0b21587b2e73752f314b8f38508172444e61852c71a4f284cfa00770c8bbddb8d425371f7fc7acf1b17609dc336df1006ffac6497777cdfd497c8c91525377c130accce0bc92bc -S = 77fa540194591f2d49a7740936cc5c909e73e970fc833bd8031dbcfcf78599095bc8d185cdf681c4855c4e4527a75c5552ab3611fa7788c424c3b051d1236fb1bc3e7b65421cbb1982ae623fbd65210035c78032476df3d64c8e8136c74c47b694a881479608568368fae8d7374d32173240e55e074e4a064f6309df823269f2a2477a5bd06c819b67d9c5f0a8720af431c3edcc85a1b2cac7d2288d90b446b62cb070d1cbb87234ec41c55b89318bd852aeb60779246ffd84532d08ea27e27347c7997e7007da4680f4b7872ab89499a1b0381c4837893fd0ca055bf1f0fc4b1682044190d40e7cd4b6c077faa077d27cf5a9966e95d6acd89f1dd1a61a8a4a -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420b7cc7185c6cff2f0237380831075de8079252edb588ab3a492e600abe24dbb7eefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 31dce7cc7c03a063b9879e0343e9b6461db1992333a941bfe34a8f86bc74327b8662cacc82dc4daaf3aeaa57dc5aad810c0a23ce58c83eb828f13b9b35e7410c90078d6de7dbccbe0490c8b696aa471334f6302e9fc0f0d247471c4e116e58c958b477d63266e449f4144048f8414ca59d5e0a6b90fa1fb64a337cc8da703d5a -S = 8be14c18fba2b95cd0d0fed4b171462b07db0b5e5edf5803b595182e97ac814eb929be28d18a8f45f837ce537475fab819244788681676ef73930ac28062082b6a593072b2218862a80439a1b9e2c637ef9806463c7c3120a01473ffd9df2152d871b83d782baf6512af6979ba3a9b8d68828716539c771161b81bdd056f7535e2cc654489c90ee5c1366609c775c760cac8d084ee6d618d25a70ef64fa631c0c4caea75296d97237da8c977e711374620f232e71163d2a2515d71e30985f84a3d4839f4367a2d273f0477bc677dc830302ac423364f4628d7cba5b92d5c9f37de4268f8d957905072f2cbb7249dad4f55909e41e4edce618535c7cf62001f52 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d0609608648016503040201050004207f3ac72d5591ed16096abd35813dc29dfaa0b834e2b57e45315b3731b4d7292f -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 2656ef08c07fc1ec469aa9c73b677af225a9f5f6f8d0e150d1d65e71e6677609bd44f5859de97ad6436ecf75d5ab76a41c9f84f6ed13b311e87ab2b3661cbff3ac7378ca65d5eed14f54fc4c34e3d7681cbae5c1c1fbd3274395e2a21d6881b358ab21ddfe8b4564d215d8553e56c4c68dc1c05f5ad1691a48ef9546f495e4d2 -S = 849d23a7f9dfd0956315dc9a60c04dac1d7db660c67d2ea57db40098a84d258b111457686821134dcde66990015e769311aa53e1920bacbf59d214beb3fb79cd6482601f5ac3848f90ebe864428d0854a245c1a51f40b10899cc08fc4dcaa6b322fbedaa7b56db804009a0829fea827065ff655c1f82497c5d59998c8a577bd5e170b4734b7a24f574db4ac56fd7cf96039c594e9a109c10185e69102e27105533d826d50b5c39bd964d88ccd2e0a467a668ce15a84014c958723ce6c09230bcfdded9839ef40bb5f80ec2073081e5e6565454270937b8cff537c0b065a923d173ad04a31592fe699e2424d8bf6bb0b947ff161a33b9b03fd69892a0d9a8c711 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 1c58bd7408d1d2ecbab294bd48408178d4a95be7ca3c89e963d8bb7c6ea5cd1c4f03ee4c48c00172f78e43e720b42e4fad039e26f30c339c3790f6a371383f464f86d63c7d0c58bd24dcdc94b13fd776d7aa3d92d7ede969ffae3fe07016109325cabd6d311da0764884a7eb814a42945a848052fd4875f8c21ade5bf4a708ad -S = 60dfbc77059709311bfa31a69dc9db4703d0fc44d715598afc39331e2620d73423f2cb8026c3dd9a133a7c0a62174448128934c776616f1f9bf12c3936f52340d4f034725a759cda95a743602805f0fd7bb03a8d6fba9947d1692f6e7615ae3b89f4251542f5c902f41661f443101da8a666654c86d3cd8aa93733d677d6c4e83b527def0db12bdad93feb76e9bf986a1624834de5febd2b0a970db189c878bd99d3ae86decfd0842735361bfb1fb0cf548a9bd43411b4be4b8db8db1a585555d9fc5066bbdc081ade816777cbd29723062ca7709429331bb52a2e5967948d1d6aafe979a9e12cbd20a30937bd6965d1a04e3060f72a46fd3af1127dac637a24 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 47611125ef346ddab85ba9493e92eb1566bad85e9d17f99664bb63900b4297dabcc0a74dbcf89ae2eecf12c899002cb36a10a876bd854ad418537f93f89744d3d187449e50a940c0e344b4d97b15b8b0914224ca6794f73c90e0fabdb2c6a0ff8b9e314032b0271c9fa3d9a56e3956b5e039948323acca75d34b1a35c0397307 -S = 2fa1aed1f8b9656c8216c2ea8ba98c67a6d52cc143816c7f83b5f72e572d6953c28249593bb01332ede6b991ada2ea1004e594966f1aeb2fff14db6ae311bdcf439c8c949de248d7870b0f9f3edfa11705de95b552d3a0bd86fb52476981df2cde1df65de3ad7b957fd82b7f98d8c6bbd4b7e2b65e143c627f5e4d2cb871326ced2f904947ec2250c5ff9d330a74a480afd38277909d4d040781947302ebfa6ecd229d93b5261eeb237dc99b9060749bfeb189f99e0164ce36cb0b64935e52870fdc8cef93a0e198465f48d7ffd87c9bd1b40a127f0fca14d559ceecade77d30486cab930ba50a3358269f641ca11ccb30d3fd21becdb50efb778eb10d424b76 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = af84a31d1c08faade967cbb5a016837fb2d1c0bc5eea5b75d4e2a6449b36f2c3307b5545f0adaac437c5d81bca89587572a8f106ea06c6f9fb5593a9e6e5341302bd678ca6ead2af4917489ae85e485aa95ec6a3bd8e2ec48ad0a7db0a4a95456e71615908667c566786a199c43d5b149d1ac8fb9f299cc0c97d6842cf0c1d42 -S = 014773de1e3486a2d54c7a0a0a1a70caf61ce94868902314462c2bfd9c640de7b499578230a41734a1822cd0fde610c487c1dad10e35d70136cb162d79c403c7408cba33b72fcafbee2dffad251ecb6bd4b082aa5350b194c587b8bb1ededc902df1e2e6eb03a5744c87ee49e087759237ea133c8484d62cf142344b56cf3c5e1f72998c531129f66e0458bfd4e8b1de1866e76e3912f680bbf8a96ee4f2971e6fcf029788e0dd586db744a7f9a0010a2a27d98b3b04884cf269f19f1937e8612cfc5b144b7aaf9b2fb0464a26f4013de9fd12851c3f8c9bf1fe6926fe512e0543114cbf9bd86336d7d2aa6c2a696a3fd071467784c2cd8f64e8bcb00fcbc792 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d0609608648016503040202050004300c4887ee786dff1356756432824889c71e522ca5d478d9cba311b11a51dae49696d1f1f454ce4017e74d9f45cb17b797 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 5c95cabba94825969c306fef29fdeb104955f9e7fdc63aa29000f57d1d41b9d85210448d732ea480a2ca9c785df4492d485405a22d1c8cb4413b5ef3a9d464b23ceed55a8b6d5b041e41724601dd114c80ea8d2b2e3dba732c075303a74c9c22a39745cbf7eb924799fcb9021c9f8c977780572d08130c06d9cd9d552193aa50 -S = 019962ad704a78fce2306273ff3a649fe973dcf2dcd6d0e692a592f357c9ac459a15b0bb0ff986f104f99301c87579a321b0d4ab9e947a9de47b56c0094e4ffa6a8949594348e342f8eda30e68f5005bbf72cef70c522a124eeab1d7441cd65dff7e1ad36bca0534c09c284e8e931766406b43b62db89472c2514c3d1a6911a92e19a0dc923919daeaeec53746f487e06afedfcb679b531ede784d9d6072dad50348e1d8f01094f29cf5cc96f6c1f40ab455be6c98788e9d7615ddb6a66b893913ad0cc63a72b9dd357ce086b2df7c8a106c0c363e3e2317e37815df69b22a9d52d6e5e47d8be17ba61b2b2019a0f85fae30e1d4f2622be50086848cb405d578 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 7f88a5d6178889bcf09ab7407a01bad132cfa7456ca0fc294f88ce56214a24c5c5cb9ea581c65aaa05c017a7a93f9b5ff737539969c53a72731ffbf7c4cc5af3ca10d00674ab75f73bc3244b631ed9177e945d1233c426ee3d0778e9b6a2d19f96408422779fa44c9b8923542f063ba0d1d00dda51078946b4268d537f365170 -S = 91584aee68fc0d4e7d24afcf4eade5fea0ffedc4d49d1d75e673029bb998ad170ee5d1d28a2779c846e617b8c9783119f4af4602461434a24c1351f737ae315868a78f615019234606a12e3fdc3cbb05d2f0cfc877b344fbecec5f71f0202b507df23e4a3917cdfbd1691fc69c509598e2bd7c71ac39a71a295ae0ed1531b97dbc6666ecdb830917f04cae848f8b18b8abf191091b07632e1632ff611432b7a50c0a7654d59506ac3b4c058eb16bb66174a39f933a4c389cc86c9c124a3246402928a3e3fcc8d35a817027c2c2448b792f2009548516642d75839b61c6e2d5b63c4ee4c0cd72e559be3cf0e466a4a566681b66b71089f67c1044157d78215e0f -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 97e7bb62b6d35c8e423a4c98de8264c14eacb2b12f36cc76e54064cad6ef1d94d60f9db2e1fce4f610c2dc6ec68331e92a1962b6dbfd19afdf67b877dcb734ff8a14264f68531f83ae1a3c138345fb5871884d4c1656ed921c02efb66b259cb59c3f7dc0b1a1b63d048a960f7e906b1709419bfa480bf0258559340febfffebe -S = 6010444309201677f71890ce09e31f671208b2804c309a85a401b275eeb5d234ffe5fc6dad17fd9781cb00ccccd1d1260c2d7090652add1b635633170ef5e9eec6ab240c382a3850fe0947892870d0424bfbedd434db4084ba29cbe7c8a27b4aa858b648fb0c7096db4dfbaed09fbd7483a2e9d8c409f87c9a2a26984137000cbe451140da9bc56c4382a091bcb171c3da5f9833fd224a429353439469a39033f2e1ea20283c643eec651952ac9853ac15a8a8751ce72a443b41e17e41fb86e69ec0620660f65361035441700652619c9248b2ebe5cd83c00bd2b232c13b544b470334d7314704dde6c81150e54e9ce132a5aaa3ac03a931113160e93814e968 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d0609608648016503040202050004307c1b2374e40835303155d969bca1d02f901e2569823d83b1b8ef0221cf4af285fb3535d60dcafc85b0b856d7bb9229a5efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = f167b1c5e4e480c6d96035630415b83c9b2d137a2ecd6efa37523eaff2dbb9416e078dfae400d1e349b83c2a1f7295c790856a5fbd5c056954c29c8f605cc85766773802ad05a7b5dde10bd6cc5b10b994f0c47ce959942fa9c87738b56e69f600401ba5e5fbe982be650c2fb2d61158cef8899757cb03955fec377397168468 -S = 6e2cef82eca498f7f1bb521fca7f11b31f1e80f5d1face48609d78b2ba79b8e82c6800e92d419c4c48b7bdbc6c41cc2b9fcbd05627c1f4c567629929022baa4ea1b431f361b08afedec6eff545b682b8d9a6b18bf62f34a1596048f5455f51d5496c89eec6e7f8431ee271ae84658347df2d1a52a5acc37b0b5eb1438342da02f2dfe44e50877221a8623b1d1602339223748df48cea785f94c5ee719e95ebb2ab7d795dbf53d4055be0591e203c6ef69d6b08aff07be7e546f501e42c3192115b5f2c259c4ab2dc585cf37dd3ff54e89f0607c5e3a2f198e2875a7550bdffd0eaecb44adad438b3d0ea810668eabb123baa66843d1a136b0369332bf74d91ba -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = e946af251dd8b043a9c866cb4f5e4b65e5a983b4587203e4f16ef982d7b76891d67d13da5ef99d83cfa3eee3f3a5d995cc8ffbcb914ce6e5f3557f43a424a4571aec12fe918786104fb023352b7214fb50e072263f07684813219591090cb1e73ffa7439bc69b311b156cd69fead45c0f805b06d6a8ad232da3a04140d55d86a -S = 839d586ce12b7c22bc2e0d921d11756a9a65e8275f61307b1bf1d6e350ac126a50c52363f561e2d2f8edf3f92b9fd88af138178ee34fdc3f4d288bb142dae2e5378c50754da25eb541dd80e83f63a356c760e8efa03f07efc420109bae6c701fad5b8dc8fb266e2ce1cfa7b71f04f63c692e4b0aece6b970baa77914791e8a25e5100a2205811da238a451f5a100355b28abd39964d43dc0e2b51a8e2ddba0e94d02ef11a5cb2058acf3f98dfeb34cf939b5bb0525eebb17bb25e517fe3eb3e04e04afa892f318618cb66de38503bcf994c9d2ec20effa04d68a0df7c76dddf30e88e1fdf5afdcb2dca0e124946e7f39248633b03166027611deb276bcf2c0ed -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = c41b35fc1669b8663a14b3c37c87f27c2d1b7a539b3b1da341c74be93ab52b84fcfeeab942b854fa4a7fa168411a9196fc5cbb90e847211c4478093f8dbf08033a0d6078aa938cf95b2818b05cebb65d052a8f52e583d7c2fc49a43c2a2a0073e80e3c40364188ead4d5c1a4b5428a57b1509ea27a376520d104c5e9fa3e3a5b -S = 2ce448ee7ebf21be380247cc3f8472e440f3911128025fef0adaac37d4dc977bc5f81224dde9df193907c17fbd624ddb51c2b54c214af57520d3f69d12885e3b47cb2c005c18eac82b86d5d514cefc99794badd609cd5cb8775cf685ec1ddf6acc0272a4a58311c348381bc24c4b85626993a601ae292b13c3e8a9c0262fb8deac28320810e776c196454be73d5ad08f780ef45dfaf7704435f2b3141ef32c2d7ecb1f26398a0dd8c01c39367987f22600b07979627b391276d1c444ec87e430769fe22ec3e1d5cd4df358314282d10e2a4098b6658ffa44c4135142c2661f2a80d4d380b5ad3d2727d0ce12f1e6d67af797c3480100ea50a0fdb0bd1cb2a78e -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = c069fe30bbe18aed9d39d26f4ebcbd89a9f18f07982822e5795372bfc7176089f623af809ec15360dcaaebd8f61f8c3b3d35c0783871ce4cfe943cb6e4b893ac589c620c0d3d85d559a6a797db080628600d7699076aa968a4b4adf76374b63dae7d1ebc507daab3dad30f9445a0b5b8da21ba524f3c3aa23358ce6b8c7252a6 -S = 5e67fa94c7e19b66548220ef4e07769ff75d4e76917004492334f0fa15ffb8b14271301c170e3d325811bdfc1dc53f1b4369a2c0a99d261d9de59a73efd4ecedade05da9faccaf35d462057bb8bbbe29e3f5d4c383908c0b25006f779399064889441a84e0ce569eb474ddfb83cda6be253743693bbd551f6ac0b8cfad225d5635972d4e508ae5f7846ee3adb61958ef53146af42d0c6ce32559f661a3c3a14068b8b488f85d7e5641e250bfd9975653ad86f93ba5e5f57f5799ec135d9af7c529e6447ac43b114475060150e98ce86df3f69cabfd5a59158f0f8c4043935e0fee317901baf27aab76a2cc1561d969bb3d69de65885bfec00a522c5010fd2ae1 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = d99885b2fd968ed1385f0245a8ec086dbf33cd903c4a1c205ad0303b4789c677d74876df7a1242396c80708b2b6595dd2eb1f33fd495040e9be8577492ca9b2e1187fa92a7bea8d054c2bb78f8403d3c0c227ff890b4b1ef4405b0571b911f19ed1cb9d26ce1e51d59ec8b14f8c52714c14e1cc158ee4a4abfefe2efcb2579c0 -S = 0efe5b7647f3b6bdc7e9d161afe8591fd21c818276311c4a04a3922e7da47c9ca87bdb8d2d8b8eb267a335ada64db1f19cc35c6b9bdb06589233a834f106db34b75284f943e7426edf57b63d3c23032fcef1cc871530ed003b3a62d994caf8c4c10a90528af67824f5e5267b2eb284c4310706aefe248d3a2d98e922c859be49b71c0278f537fea1586ad9658da5c59ba11b6abaf2433500be32c862796de6aa58fe7955fa51845fb4e304adec80941f70e27ec24f1c6bafe0f2746fa102040f2483ba7e3043469c6138adaf8fe50b4274d9548b30ad0bb048af103454afad3e536c2d95ae24fb2feb08ac0f469551edcb3fa36ca078a469c001d5637cbb1bd4 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d06096086480165030402030500044065183a0ec842001ad183a8b55e9118f29757c477ffd30f57dce02a218238e0a400d6a509c69a74dd64b400c809026e9e3ad8930f550b594be664491b5732f3afefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = ae898f661a8614a533fbbae90eb5e9810ca4a205b9327845f4d3dc7f51de9ed5bb9bb1fd5e9d2f3bc4529c8c3dd86f248512ce1ba1fc9a640a3babfe0df95d6e72ef4b6c5cc35add7095fa0139d5a8eecb57b73da7a95103dfa4b9037b41d2211aaee51adda19f7380ed59afca539dc5289ae5d195e1a50abc358cf4615f07d7 -S = 0ffd86aabb2861142ad2833b1b74cbffd660755d58081f816f28639bd6cd70b6d312d6722f14e4d608b154891eee96ffab837e472286c528086fb323ade633cf1b778427b504701bca01c1a8cb18547cdc3af6afd180a65042c072c741525346be008dd2dddb53d63dc7b33458bc59fd50b35bdc291a2760ac545c4fd21a37b710050fcff970271ab9ef51fc5953fad7bbd28e9d4f84d27c36711afb3ef2e21d55a3f5cb028667c10b23a334ed7e7275b6830588f4938f2c3b9ff795029c5c9eb3965bcd784ed3bb5a119d165db4ed808d388423059ffb091fcdbb1e6e5c65291b1e5fea5bd17e2c5f16be05c3d13bc8249b7f98720b300479b0a25d680cf3f0 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d0609608648016503040203050004406c4c610edabaa9eebb437d9c62286c4f159bb471247b77f443153bea722f2a86de52a83f4c9561ae581f8b3568bf9977ad8696ca8f310ccecd598238b3edf845 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 18899418d11166347f1db7538f58d6843ac6ad8ea66ab60c184b5c7577ca9aa99a5e89a587805b4e5d1ab6d13fd06b640712bd62d4d830ed315491b7b1e409c89522beee817b33efb59d982c31dd365da1937aa6aeedf68ad3049f82406c78996c3470882afe0ba6552b21b6ec97162d8026ce2c707fb76c27b41fc3bb05bb95028eade0ba33868ecfa617b98f829957ba83934f2dd4621e111058241e3c0e08abf7222f142faa81652c625deb28d2718940679869dc51fee3e0e38830914aaf6c0b670a04815c5265836f4e9895c6a2e99111e0156c92f3c8d23b89fff18442876678c2b2c40c5a7c6f7cb1a3d314b689d48f06faed34047ea1237df9a3a2af -Msg = 0c84d0c19e69926823ae89727d7dc8f27e2dd6a8fe0c60dd2b5c2a8f219b4bcebb089a66a86264bec1f3600099cde47a56545845c0fcec24985486ae2b44feb027928ecdacab8467a6a13ac35b7048674085f8c71181fb21203a5aa6ee02afdaf82d943dd3cd5c2b7bc00101e9ed5e81e3ca9e781822f59d6c158ebd9160c415 -S = 5af917efcb50475ef7d9b555885d07cb1f38149cd8f0102760298131cb6737f5d085f2762682f98c5e5e9918d9ab5ee4eb6e94989bff59af8ea042d0225d71690bbb770ffebc0610afccadb9726c9fba0ad7c716a0712fc4ac4e14ae7c21adca56d7349e68440b3244ac4afae225e7d70b68b4bc80fa9ca6a0b5665ffd831acd05403d8050c35d95caee2d6ad1eb53523a531e87efcae11cd225a102578f8ba6fb4b907f22b9515eba4449e145b9301619d5445723537c16b8543f524f37301989026d0b4829dbc5386fff11b74e54be9f8203f2a2cb16a2181f1a8767f1f161f650f7559da91578b999a34a2eab985aa96231b7200ccc6f38c2a621ab6b190d -SaltVal = 00 -Result = F (3 - Signature changed ) - -[mod = 3072] - -n = f33d3234f13272c3b2b6821ce4805663ff2e8b0d2a47de363d97fc9cc879cc6b40f9e53aea695dc538a0d2b558498829aac327eacbcd889e172b34f90745c5d528b7e82605f1a58fd228ec7fd4b6f476f393864f48dc47097c8a780a2ecc02f748138dbd7df99c52d822a2e5154c6047fb0eeb4f49da38edcae3c32d3fde435f291f96cad1e09e1030ad7efb4944b69e074d0d7964becb3cb86238d8d293bef3030d141d14868bc21fa133e9de1115f749991cf86ef506e663ac162b2c8567ff131a6b467a6f564d6c588860becbd88970354198ecdd4f1f4baee8f8bdaf7255835385f5673625f113550b123628a0be3994d91c3a19a82e5d73448dabf684ee6794fba7a2b1afbee0287e5a11180c29ce0896795d52ac7f408fe28e8e9116fe0b61a1083f95c5227d62d5537b5040b79e21b3a8e83c225bf3efebb2f808541e97d28a2468359fc60f588e74faad611262064628a25d8d61f9d03d8b21cca515595aaf2343a759b74a6a8afeffca139a389aa281995cd18e16a9cf7b7ff0dddb - -p = f3fcc6aae575312778d9e896acfd7c1aa4c5524f20453e8bab255363164afa7124b2425587a077fa0bfaf61b12ef3f0540dc4c9e777122a60610a53d1d75b0a5859c654a8ddfc2ff4860758bf5a6f264bf8bc2baa7551eb7be23bc06978be992fc81d890e07a3abf95d20eee3f6bbbc089985cac96395b473b2741c66bd2ccbef228432f66b906c15b19694dd786c29f06cbc17b2e6400dde4e3db85819382b3d05a4c3009f092d40d05ed5b2e0428a214e15a7aca09b47120b9ea6cb4084fcd -q = ff36fcdc519fe10c69aa0dde2cf3bc72cf2ce9a54ac063d809b523f4e5d7ddaa5413d500dc21f409ce661bf33018b748fba3966d874bf96f4313eafea9decfba71d540ae0508161a3658c4762d94ebb3a4e228c45661315db30c20fbd9e20e24c044e4f0b49e6ec80949b16e0ab07f3d32b248b39f48332cc3686df05d29c170a7276acdd129259aaf018ae3afb49b6e0ddb9e404a492863daee7be71dfb11279047794e45f399a9665796d32d5e65956a13a6fbe992b36bf4c842f5f519ac47 - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 9d1f17aab0ce96c4d83405d1e3baba1dffa86ecccee7f1c1b80b1bbf859106ce2b647ae1e4a6a9b584ae1dfc0a4deebb755638f1d95dcc79b1be263177e2a05c72bde545d09ba726f41d9547117e876af81bfc672e33c71442eb05675d9552df1b313d1f9934f9ddd08955fa21d6edf23000a277f6f149591299a0a96032861e -S = cbb358cb77cb2f130b7ad636fe7ab00d1964ebd5da22bef0139a6265a15c6638b17ef3d84a588710adc06d0242085f155bf5349064dac7481ed79d62b3ed60121f010729b61bee45554bfd5d494afc55405fcc1ab8eedc9c6251d2d0512ccf2e4f370dfc523215a09553ed2b7a46e8bb0e63d1ef0b09664b42c35e303e2fc3e2142e53a0a11569f8dcd56d47542618e3f3aae3790e1f531240b52b0a89f2a24f018116e513e876c8079f3ea61210da71e481ab89934385319de3275c0d9fc9ab33ed8bed5f704ad40ceb364f21855a5f5cb1e1d2b580ee4724fdf61f308d7136160127247d4db3486170cd2183047f15c8cb54368085f595f6bcff02675d6945a1d9741768820bed442fb03d5087e793b62d3d0d37567020475268c8786a5e5385970728cebd6c027aac15240ace0f0beb6c29f656f6b3f3d458d20005e41aef294de9823722893021d9cb621b29c2730cda7b6703e3a66edac57019b8404eaf8483edf91478f294f88907e277bcff47fdce9ab7f772ec256122530ed8bc3b48 -SaltVal = 00 -Result = P - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = b33acd11fefde3f71597af02e49e821354a0bed0080b31a44a4aa1064531a8ff749bc3e65a51a56f742ed1e46c8167b18fb33e26812a34792f6cc20a0688d4eb63b2d7a04a2d13235a6e3b2c007e42aeeca071a5c134b70f11db403888dc483b67c632c63457d41db09d16620a5bbb1352ae7ed430f0616fd6dd421933f4aff7 -S = b1f3ee7bf9b57da11da3a557d311e0d00e474578d3d798ade0626105191f6db1d8d66da0a35259e40ff746d9c512478d8972cde6bf271f679ba2f8e49444002ba7f94b65ba9250bb5710587c9ea0ebf31802abb7508a785405f8ba7e0753ae1b95675d4a89227a93a96f3f273fdc3aa7fe48b94e48dec9ab2fefbbbec394a84305b0237232394c21cf31ae14e5b938e825be9ef35605d0200b9c085cab040833623e72fac9f59a2297e17cca08d3a0e11cecb5b35b3b86238a48be38c6c03f7e45d7c5495d55aab57bdf8edd871aa9caef624466b09721ac7d27a74f5ccb3645bf0690d0396fb56e424b716df6bd9e10becf9b7b10210266d0ebac4cded6510b02528ba2d3b5318b7e8f43462dda97b523b6f7355896cfd8989f8d9dac98e1f98f125d60a5d382513426565f3b1d1f305c59b2b7f659c41fb796aa6936e4e845c4ebfb14bb62b2883edb1580e68d52d62e0143410f5a5d2e8f7a2d82107b2ffcaa64dbdd32bff2d3228ae115cd86a27a3292ff43d165b174e7d77f6dd73402c6 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 7020d49c0b19cb515b193fdd410abfa3638fb66e2cf29208145e2608214e4debad45d1666bc08bfba568cbcbc78dfaab21d07d79e91fddb17fe7253bf5848c87cffd54dc07eef2ed55c56faead310e6508d82f04674973b6153121b82dd1c96a5daf27a6e98c4950f397f42ef9e045fa9f0f94b6af569d405ea4e226d11c4bbb -S = e4ce05162810343296c8c774a21000f647973dd43615237b9f753c522d32aa6ce6742fa8c9b702b0a074ef8adbd17008226e7718c4c94255b01d7870cd5cfa3aadcb309612a7b0661ce1af202f7df92885a0f70886b8edec606b1923534c75f3cda19b156a2c90f6c412d33e2e0045b6a78aaa2fa991bf61417ce8f2c74a50aff9cdbcbeabab3e404799a8091e5ae1637933272b082d8abe7305173b0ebb619e4dc1dfc77015861c073e24de4dfc28e0fd95edf45cf540d7ecca1bd30cef47fb5e398c16e7f7e41ab35c932235464a91b3eafaecb1de97708a35c39730e58a39a2af7ac71959ece442e00d42e7c1f2885c49e5b799bec3d9735e1cdc85a4c3ea58b50524a51552f230525c834c705c1f1252f85433e42043d10bd5ceb42f8213d8e9db29924cdcd127f97778e75c1626b9fb68d6f0baac56d4cc30d0c03d80ac2f92b8ce2e15a7500b0710ffadc94c54a67a9b27c5531880a60491bfec5c78a7febed2c9b3e5c45474e156ad09e966e18f9f74ad2d60710c63e6ef36ffd478b8 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414a695cf2db3cc4089154364865e1f75073a39e420 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 856d1fe7642047ed19e96d364e5a2efa2c85a1041fb33b09dd59f038a4479b12c223a07c5b16d01367c58dbffa832e8bc8c4a5b4e8d55effd8cb6b50c2badf79fd277750d7bf80049249f4b1acd9e7316446213679df0d95355ad2e5aa0dbf493c61ec8a5f831e69a25cec33edc4209506f260b25a370e73fbed6c1ee5aa042b -S = 24b57099a2e8840bdcdb4461260aecd17534f76d074c765b9944bcddf9b31572c1494b586d0da7f93e7d25fcae44804562dd13ad676b61e70d19fec98cf6dd2eb917faff448e29b951a77b1017a8650d0061bd77742e04a44c79bec6ce141bd264824b6e553a3f761bf583e231f2152cac58f71dc7198e675e364103012aae9b45a3d1a7d61cc25cadcf7d061bf36a10599a812ec279a996a486d46984ff3c10bdd6a465b93eb1796639e499d865f38b4de2b14301d01a359f36017ace359ad1e3c8c223ed74b00c6a113288e64a9c610f5f06d537edb11f520bb4eeefd055cb3560fd8b4d56311c5546b07ba1f3fd0d3e105f3da24f3bae8ed44fbeb6512fb66cf155e3e61475436b95f196f452e612aa9890cdb48938b29b624094e36f651bd305700b39176273b54ec9abb996e644be39496d8b88aa26dc5d4bafc343b9850c0201e44fac6c1ac69c4e408ad5769bf58fae1b8a88c160c0d193a2c807375a4550c4cf56c947a9afd9498fc220a469affedecda22bf44a8f6f9bafcd913948 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 590c04975accb7dda8c07afb60a7dec74d2ab36751b787c1068c6933a412f384266d871ba851d86f1417acbffd10e103cb19ae22196f2c655bc5152cc494cbe067b39c289c274460a53cb34791d511f76100001b6acd215cfa61d91c3e4655676305cb26fcf70396a45817f9e49d778c57072fb80b796d8c2b873d6bdbcf9802 -S = 8913d37eb20039be9bf34df63a3824f13f20324a3c2c2e7adc705f418c77d9be7f127e406d765501663b551e4482a177f58273483b51b3bb4614054ccca4a157eb6f4224b6c0b6e4e2b92d11b87fffb26237544c959125d2047165fc8dcc2d5766b6dd7d79abc37b79ea7bef2169e80e74237f5574494eff54b15f4ec7a5eed2e982a3b8d76b64801a37d888b079ac680b0833b51c2bb8a168c63cfb0a96a8817d8512fa4812eb457c1ed8ce0d563ea021a34e644e70689595a078ef469dea58a334207c6930a5ccd82307311ec25cc56807f2a9160b5d738acb42925acfbd4206bd92a24946e2a3fd8e04a1226e472be33eaaa5eed4c13eabca68ecef4d9c005b2f132eb827872235217622284833e339303162d866133a007e27e88af86b23c451a846eb393e05af713a59a929edd2943e6cff60aa906459c667595154747156c52c39bd369751a7a7f926bfb7e42bda447faa314a7593dfa4a06bc334ad9e52339917fc65598f06ff61ee6d7854325d40284e12505af8c57b857887f15d29 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = bbadf4bac5fa0abe2abf1e9993d33b798c5f7476dae4d6bb0e809be75a6da0b3a4ca1ad4d99e8423841adcfb9f1e0ee2a8ffb16cf888f15d513ecc0eb6e882127f4f4618ac433a137ade9a99340d37894c4b28f1aab0bc2f442bb356ef0cadd374c5e250e7f114d83495c23cfba69fb69ecc42cd98661f7810ceb686adde0a3d -S = 257d8b3a2fb7ca6d0a78adf2b6e11dc4865c63888422d0795773249865d18519033508be2811d797d564687827eed35cc4c24bddc548e7be68a14cea7e8e0a3a6ef801df2d41519dbc056fdf5cb23dc60a9b8e94581a8beda4f4e660f699ba5a649bd5724a1d48f88552c3129bd08e2ac8b0ef60ecb938d4039a2fdc648b6afadd04683b40f144e474b8a99b3a81fdc623391eaba2111dc5aa812e3fc6b9c8f8711e9986c0c2f012cc1a0120c79004eae424dc4c90f24c8f52d536dbb50a101ff04498887eab4d2bc76902c2587a3b32ef3a8a58c3cbd11a9dd14055da56e7ba011bae74875fa631a0dfa524fe396b6a5ba1b92730adf17b2e9bed78cde226ffbbbfe29d3add1c61262c0ac9624f1feec48aa73de41627514bebaf76997b0350ea4d590c6cb59252c9d693020e7887bebd7a25f1769433d39fcd3dd46625208be410d50ae16b4d8fa6554be3d94a848ffc3211a915453b45a3328b001a5b605d686129a4cf4862b5e3453ebc42c2a11fe180adf5c12d50d361128abb1555aba5 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a050004149a135a3d21fc0556fdd6fa7ab0a3b1e4ff330f9fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = cb4029c463e243b9f901855447fa2af302441ee117a3622a359fb3ae8b356675d3cc97428f6b826b922831e7c3e458a91e357d2cfba45b5093198964c0935784041cf925cdfde7eef72e83ca9310fc3be75e73f1b5615d9bc16429fd8d68224267199694a50038eb30f9c3223fe8e05065a84a55ce4430b3c66adba07a1c9059 -S = 3f5e4b911aa319cfc15e4d6f7ee82b12a7bf827dfd244a5e57a52bfeb04bdb9e29a1cebdc4ebb2139906c42a5ea92a6737495d35d43ddeea1786420e57d994d880625f0c4f56594f80a732b549c65132355d56c8e7acc857344fc736a7b3168e8e892921c12c0cf8ae7a5d66a9d95d4180b1684ce3866024eeed217fe3d386380aab1530513aba18703fed501984820d8bb050229daf0467fdf13020094be24d8fa8cafb8a6774861b4a2a0e32373989fba555141d7113804b635c0ce480818ab755c87be02aecbd69754f68c3fea89dc854996a05fbd3d5f10cc7083f893297c63dc384a6376fcffc8cfb170ac7e0363489832e0c3e9b0400d928e05411408b7b12b653a1e4aaee79ee46fe892cc64fa21afa202c763b161b7d4f1c32e7bfc75442f1a3c31aede44374939b64c264f9b1833fe04172ccf818108f74634384bcf0208492fd81a77282a27987a9001754fc74690a021880b7f2324e65a084d88c3f4486fd974d50edf6c206ed616ed9376f1855a13b51c914c48b3bb0cce759de -SaltVal = 00 -Result = P - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 58a1db581148b3b2a3f3c967d69d3feae7df5a327e122103dfb4276e640ca59b2b11cbc60c895888ce6e69589a958e51af92233658d6deb31b1aa4e53401a11d42f897e13f617634b5f22e182f57c150ee1f9c6aded527fdc96d9b30c9e3147b031ee7b2921a353fc246c0ae7f2bfe700d4f6cd8f959256a4f75b3550dfa253e -S = 3b93e9611a492f19acd725d92cddbe696e97f29c5612d7a1c57b7cfeb7c70bae57cb9c75b6c611bb1ba39e48dc99ba9ebc091d7ecb5124bee1596541ee337746c86c6280a2db0f434e13735148d39db23e594ceaacb36bc29fe005ba204bca2d90cdb083e9972b227aecc588f601427c8977ace25580481db532f580cfcd54f56169fc2f31cd00f22834cd4ee3c6d9c5f708a9d26e10e341771ce65ee4233184506a17f891cbb633fc4571d7dfcacb949523f692fd44f08cadfce02b6fc54bc156a684c9a706742d5b2d33f45b01001e777ff13f3b485c5da6778526e1f80bae0a812d80cb2bbe2fcab984754b3ae9532e24e9c930ecedf50cb554ad345655e25ad118f40e9c729efc53c67f8c9e533ed434d57c92ee71fa809aadc3c6c82aa4bfde5df4b1a32d43981b9019c04ab9b32129158d302f780c22cb47249a1f767861730c4702b8f599b594aafa691d423bab81e8de32ce7a6e988839a55a94c198c8b10e432ba10567e8a01d264a9f2964016ba1f070592abf8f1eaf25f5c06f39 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = ad65063815129120fbc5875461c916131cf2d47084800e5270475cbe620d7959fe345228c1995d9befbb2ccacd2042fe11f4257397f4b55c558abb289139c504513c32a1146a8937bf5d0fcadad398acfc549d4384168f0c8a1d6be016a68f768fc6cc2a764fbcfc54f355dcf0acbf25c65b6367b5af4569f848936e571c7eb8 -S = 2f264e0f5c24603eda9315230f23de193fe6ccece8de2d6b0ec8ead9803798b7c66b9ef0ba801b029c86bbb35a743031f5ceaf19881948cf8e2dfb52a4c7353de5844863a8a6ce407a0c88dde7f76f76b8a548930f902c974462299a9065a2a9c90b639bf017f77cb699b2c255bd18999757ab616b39cca6cdbdcf176a0057620c88bf0727133b3c5607ea13a454b45ed8d29178ea182f54329921677f7ad9b01ec3b0dac78dd82319f5b04d9e64da052fa5b193c32806a3dc6182d2bd2cfbd7741130b5d6d32ccebf48183d8b552186bbc8f6f6ddbcfeb3ac86579794bbdd51d9b231d4520b7aca40379570861f09338185e120850e989b9f708fecdae37c95507a46eef059bf7cec22a8728d03cdc7a758e85ed2c7d78b61caca723a4daa85bc6acb5e72c59fe1ab459e9d181aa2c3b0a8019f510156d76b0712678019980f2377d1ad7f126fb81762090a394a172513de39d388bc52903725f20d476724774ab0debb48e33fd03c7b48765cf91270245b42416b504c97c335400e36367c06 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c1600b15747d006f8765132be06c17817a701f2b805bf6476a1dd5582efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 0484eae59ee761e0cd361909a014b9bc1260356bdeb74440933a1503e9913d3f5630f5a0ddd882a02761f462d4b813de1324973f70cd9789ee7e447f56aad7c4ceadc840ad5541c58ea1d2f3a4c866594d7d76dce9727c5dec1bab9632b4dd459385cd8db86586992c7d1b82b64e9973e7f63a0befaedb02b598b01026b8370a -S = 74e96c2236f61bffc5830647a50f32a09b5170c586d38b83506c91f6337bed6aee942710a9288e17f8e9fa3e48ca99c23c8dec0f963f8a28c0a55db3d05fac86a67039a6c0be46d28207be9ec12e389bcea525386d4a0500d64a3d2b846cac4c5f9db7fe8a226e54e28e6524145680e8aec1b5d5f531e7cc5595e3f9973bf1b682574ba48bd42d55b240d2c9b6929b4a8fe8eb6493a2a7aea700c81dd8126c4f5cf2676adebfaf8641257d4281945ec771cdb4e45601ca20a19083e0844b8ecaba048ecfd2d76c24324f368f7c20563524271cbf5aa4239ac6259a3eef2c80e5f78ad3c7bddf786a090d7ac2f0b7e0fb5851c5017f9bb84001261038f79cad754d183662cef7676caa122fd0fb763944dd89de28f06fd40ad4721a02618b1a0e20056e265c8a2629fb57df29646df0ba56e94682bf3eba253a08fac1925d39561090d8f36c3b5068b26484e134cefaa7613898fb12c4a93122b7224771745ff115d4f70eef1e47c0a656ccec2d0afc46ed9d0fd5b29d151d23f59723d3818f1b -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 469ce940f2675abe473f931292c7fb141eb1d11ab62fcb1065aafdcb80b7fd9ae647451e871dd85c2386291154443845cfcbfe23e7b00b08535e6eda300bd59b4aeaf53e97a22cb90400655b74e83d60069264c397f345538978e909c2fa1899f7efc2472add9efc71151199fa9d518b4c6ecaa0cfdfc1188f6237003d6e10bb -S = bb0257ed939f61ba105b2381a70acae35915a625a5728e29287bf0b1928e7c8a82d6b7ca4c1d35c6dc22b2c44895202f147390da4a1d3e64f416c03ced1f2523d586cf3b36046fb221efe1375fcc2d2ec9f1c0ed979e901573b2184385098a0fe27d9263ed6054410a3230f02b6258af4f183e82a4fe13597b5c805ad22536552b222c065627d4bdb929718bbfbc21cbd8e7d688a350ca2d36ed325c737af93df4993a9cc3be1d718cb092f48efcfdf21eb419de0666e3bad14abb09ec86890dd925c54b228b8efd5f491a5d52bbf508f15bd83e912569aeebdf9b570485df348e2cbc42395674aa69f3aeaf0c9573a27098253fb36f913b332f90466b18e2e78d8c504cf0eb835b5373e2113969f935b710013ba340292be2be396256d6c6559621fe96c1fab4b92e0908f71396b8dd2096ff1f2edf1ac6a31cb3b405e0ffd7c41b8edd1de01910cce15461176e4d2706665fab3cc1c9fa4e810e15b59d64e9a46588e0629d8cb16d60bebefdcfe58cd87c37c0e8497004bc42e29f024db067 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 207fe949bf4eb76dec39e361e5153fc593b59d2d10607c306681e8bc9aa19bace993689d51eedafd53c11864f8810b281246c32cc43717f844438c0fe013797c3f3c68afeab8be870a979fb074f20c2fe2214e3b832d984fb788e87d13fc2e05ace2b0269294ad349a2540eb614f88038dac06045629465c46b9c2af3c46036e -S = 7fb366be277c3653fec8f65d741808e0e1676da31ea5388d2a87ff65d7e9dc032086be8b0f64642b937a8e0e563ab44b91e79003bd92713768b6caba087c973b351a340f3cafef865c6631da91e2eb55d9ebebd5d71c094ee8be88c43caa7c1f6a698070594d76d5b036ecdfbf0f7a9f680b56e6012230b1b91171d9fad3b8dc3c4ab88949acf036968169b9efd622cb52f485a2ed1bb6f65ed848761a67da1f67278a04891f663ce4bbab7f691b0ad1b8b4873e9bb4875d5627d581c262882f16d2c5f56e8614346934311408954b77f407272badffd3c2fadcb8a8a43441d612f6ba1d4ffbc00fdbf7fcc5ca0c9002c43f47f145ff0ffabb8c5760d4abdb6eaa01487555ff1ae4ffc632473a25831815f8e37b60cde1c85a537de9a75b5189fd5cdca65284165ee8d03082924feeea8cbeb72a1d5480fd2be13c4732f2f98ab7ffbb085c8f6c796993dc10b4c1187f32ecf2bb8bf592c3ae117be68a30e8c92d094e674a514fe9665643befd8e2c545a14e1b9f565eab37c3d913e18da9652 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c49c8f2542bf9c2bfd41d90d2ec3c717718ba9a1636f5ad048011cea9 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = dbbd09ff7b1c707c2bd52014adbb773ceb146aa72637c8724f5ac39fb5a5acc4e18bfe04be599e3ffe0f6186b870cfd2565527f5ae46a3d06f4bfcc7bf00317222e885959e03c6531da3d59e127b63f25ff9f94377d63b34bfeb6d893b4636df667da49a61427120503885450205bb05d0a9e879c70e1a0409df1dce709e4473 -S = 2e4d98c10e126e544d2b74bbcf0a4f03f081d4725a6661c0683d3612b01ddb2dd6f0391ef3679f39dc0785b37ac275f0d6841ed3a44ff7f6a407a085129a164faf63ff2aaed18ec6a5f7d27b48d017a50b24c8c4859ad2bb680ace5f3af57f2eac2d7337c0dd7403ffb2e8bac69dfdc98e62a07354b2fc93d03e499ee2d126647edaba094196b693e98cb98ad2817ba3f7f522c8f786b6ef82632ef5a00d5d4f42db6d26709909ca751aa8174037c924628852ce78e2829493d6c741d3558adcf713734697754e55e7b3bea0d8717da8aba2b2874527a0b3a8d2e1433344dd6bbaee1ebc7fa352539d94c6b45f915c6979b8e18be8934d28d770806c6ff893660dffd0e948a8cce11ac870507f88c1f86caa875ad721326dcb4f0d5ecc2d2538c4fabcc6c756ce4a59bcdafc44568787cf2bd9650486da8c85fd0b87794547e179e498cb6a5b26f71f9987d703f2d53418411c1f9a3a2e6705637b7bbda9660641c0eb037eb432b2d7515d1ffa99175cfdb8a2a4eed013b947faa4bf1c3cbd59 -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 4255d5da3223d2f6e33c43abecea1ea7926f7052eb96a203438efb73bef867723f3f77d88928a8bfa4aae8ef83ff569ae3fb4a4a769d951741e40a1d42e33d2d57188ac35bfa593892d1a13947caab78b34b19a12184269050472fc11919730851891782f1c06dcb745a75718174a4a9ca06e5413474ded6385f744789c19169 -S = 6fb009ed4d66f18ae694d6e383196b02f4d82a1c7a755ec4989af1e2f7381355a5cb0bd7b51e48de878c74c9a2b359deecc55ffe4e67c8de5666f7a23144a7a67cdfb0a62d0135d4f58c07fe467f044c1ed33afee03eec57f8a0f83b451f145f1eb598d3997b67d98b5d05a6b28d74eca249af0129ee680b9055704d803f32ce93d77fdd0455f5002fab33b30bdc0c8bccfc6834c9a260168b366ffa6f0421324b673d7e697cb266a09e03afb0ac6fe89495852a6e90d6e132b54eb0b899bfd3d9b4b84bd4ef4b4566beaf2884acd26a27c0241f820d6612fc8fe9c5f4810c6a6a32c924a7b532b63bea39c535aea33d50eb388d5efb7bdaab3864830c225c642353228cdf3e0edafe39bb7d9d9bf8143285b18ad2c941ffaa67bf4d91f94ee1abdc9e5ec6f141ea0df5a27490c51d0b75e5ba470c9e02f071063f89f7bc221170f8b67203ee6997029d53848868b8ed144651071b14eb96da6e2cdb9b9f6183f548d500270a20bb1cb2e12c4a43c5bdb3fb97b36ec02617248242e5a59dd7e7 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 3a463bbff446f2b5057c50da18fcebff0f2c5be7e91e4144e91d88e2f486ea233cdab6ab1b10d15c4130fb85121d54564ab21f98e311c59b38381d6f6ad6ea56035ca67ad9567edc36fc9d8d3504ad206fbb9b5fd7549b3de3806d0ced3fdef0d8f59194f6c0ff1b2909bd5a4959fe44c66e58a58f8fcb14321cff224469cdd8 -S = 26502431034a0f2baeaf1cb7d8fa138b32d53f808d6183270dbcb24267c71564377a6d470ec42a02a7e88711c8c1e46a8b3868d15ac81146ad6c9ce9c40a1b09c8bada5020cc52d3ac2452a1b81c4ed0052a79c6e5cc275a032a816698e5f39004a340c13e52e9d672abaf2f5e230dd9f5a40eb250e8743a46414961d347a8828d5c1eb290fbad7eff81c7204bf377b9d9f4f8a2067cba6a6b7a088491cf42eaa8b201b5d8b37033d6db81454faea89417d52dc4b50ed920ad1e863f083e1f6dba595661adfea362d0e7c8b10a55fc58a1202fd222b4354c320dfa1e466e49625bc0c80dd620ba3cc2027ada7177ce44483f5dc8caadb3ff7d812524835f402e0d691e0be9bbac2bdd0dc6881e85b0ef46962b8441c89f7eb2a2d14bde8d2ff933dcc0db390f225f2322544bb95b34c2c2e59e6823f56c048508be7a3011a3130983185b47305477b19f3c701ff3009342c19dc22bea62b4bd2ed221ae9c2213b3026a576f8e25d72f9c72468e61b6cfd9530ccc1c183e101df9aa3228e8ce3a -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420d65f865a519cd429cc9d221cdce15d51363697e694b2cd6c09987f0310b5e8d8efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 631b9db77357d87e004b61ebda972db826db2b9f03c913136d7f5e2f601395ec406fcf96785f768162e849f867dca77667ab0a195a7cd253387c44e31776d20393a59ce373c638578a70aeccdaa8c78100b188f4cc21f99a2f3a2bd25a76781c24640d86acb3a668408c99517e261641b994ad199fe1104f185e1be6713b119e -S = b3fc32b58ff28bdb60d7080dbd90e369d5b6ac8567f9953a3155e42ad86f671134b77d5f00cf1b686708da2dbcafd637b0e1c9dca59ee74b1bbdc339aac119661a2a1f3f837271a67c5788bf309f77752c4d62ddddbec71bf7b066acfd08b96d840cf4aec4c52eff42bb85038d78d668466458dc7d69621206ee831726f28e49a8a389789d39733abd67fa334c4ea1a39081bd1c086dea0a091e8eecb06d413799f88711084310c30cc824fc8f48d0a3ebdf481123a30a5535ef0c8649ff42746441bcdf3a7ffc23cc13c5aa75b2fd8a413b0cfe1388cf724cc105c182615902f91caacdc7617e349a553738d5a329445c710787cb08b87332a91ef8fa1ecc4f86a7c56d6ddbeb3397d2f92d2f325d29fefce33954a6620e3bee73411f11a152418c5cb6f37e0305530bf510589f2918204584a9126a3372fd7f915070bdba48e54c596d8693a9d18f848bd5a53982e8c8c33fcb3959ccf4a56d3b942917673aaa9246a5baff5f5aeca056287cebd950968308d535b1a62a5aed92d95d9d6c2c -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 50af2bdc908dfa76ea44c19958ba61f2deaf29e663434a30bfb98acc157a3c14635d6f2a57256695654c482f16ff193ea369e9e1c2344baec04d0999d0e81617a3c5c48438b137c2f64f1a24f818908aa8a16ecd8f1ca75d6b22082882b025be376f93b3db385745c5d79f3fa50fb01e15df207171044586e9bfed42d4d84f51 -S = 6b3f7aa014e45d369cf4cbfa86fd284af19ceaa355a00f55bf242f02094135e899529b0c64538ec409b60b6c9666f8dcc61fd6060c990954f8200cf6a477e8a114633fd8c9a62c0e8d1d171ccb5e09d360d42d868edc0bc0750338da5ab69f53ebd8f9ee99c55d9e1cf6bc9e9a8d10db7cc267adf5e525af09568c7d6ce2f59ce8c5be5562f2ba88d561f1d46dc3aa765b3a3a2f5f156177d5de5e959f2beaeacc2b265fe5f7f3638db14a97d673489faf35be8579071a09e46f48967d46e251a7bbf460fde2528e36709b5b4e13a51ee53423bd4059f38a1e3dd2720dd9c037fb6ee048ecded10e5d7c199fc3b2ea4404110e5a283b4feab8048487984c6972ced45ea31b1d262f0b071ddc146f4db71cf43b56ff887679ce39e9a6a3e449b04f3d6bab80ac393abb472dbab9ad52eea3b936ff414b9eda99d710e7c836c86a60755b65cbc0135b71f87fa96897c708cdb69d6c6d6d4ca5fa850fb6ad9b2c0eb5483b3641f211b2bee68ef6e1b32188099e7752d6776168adf7f0667f7b2017 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420e4a129a7ddccb2047e91b87062a92c5672bd3bf6238b5d2ba1175f37f458790d -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 5c78db3e64375eb7325e70272bd431c10a71e34acb58f215c987313123ac67e1633a0a4c62bd4a76666b526f8efbcacb70baa05100db08f8b40ec10fe5559abb791336a6bf660cf69ab7b17ce2905a2e07ad9dd8f755770e42eb93657cc0c9e3e42be6b342dcab1d166d18b6ee3aead418736245796f4841bd43309cb194fc40 -S = d3bf9e41c55375a032394a403ebe35dc800541f87ef67f9de42b9a386b7ed0f78403eadca167e2f49c5332cef85c2bd821511c721ff4b3bc3fcece51bb10921838384da4af0c40c1031617067656cba8eb2d2b7f1744ecdfab6874038163a97cd08439aad0b8f959364a0cb0154a9606289909a1a6a486030abd1dcbbfc113ac34bace0b84f1b7f9cccba5dbecdd1932f7993966f5ced9187692d03b8dfd99f87c2903d72bd7c0acbb942c6f1f321d43a357a21f6fb6b78f91b92346ec2e577cb8aaf9e7affd12ee3d27ec9dafe50b5cc874c374d2e2c1bdcb22f1b6105035c393e4f8f23660e2d54795757a0d1729ac12e053aeb239b7368eb991278f3a0c2f72c551cb90b96cd86905389582641d6c029c6622b2f7db133191966901d83dabdc5e634f6c8ae59aa54e6c0c2db7a1f573b825102777fc8961be82a624e5ce01244ae8279794fa5ab2fd62590ad8a00c5d0b0ad11a0154d9bbc2cf129514bf193c715e49cc75bcf8343ea017906dcab061658083ae11fe7247ec95ba18cca761 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 275a91aa97dae189c61fd1b7854d49899d9406d958a8401143718a853103f90683d088b3a71cbb13dfb2836144d662270a7acf0f05b5dcf56c701640de63ad73a240d5ff332d6b5cfc78dc57608643aefd0dd1da3283722cded7ad1b6b5eccdd0c103e3442f4398ba5d9a441e1473345ffb5d4e3e6fc4add210c17bee2dea06b -S = 270c4cf3272ae89db2b9b2be30ef1167d1b8b67307e40f97c81c3c9ced0924ac971d669e6c0b35ece58b5d4d4fcb4fda5776f81e99db9f8ea4ec5d65ec960f2feb0a4166019e5bf856246952a9a68567703e505dcee51df9827c51dfe6b13eb6038eba7cc3f3443f0ef6f28ed06fcf272255ccfb31f3a956a36744b878af8eee1eaf0e3ff1277ae602f6b3c1940697d41a5acfbe1bed9abdf73f7882c36647f2f8566d3d5eb24ff8758ca4ee72405c4f9645a2b176ee0dceeed37e8decfe2a3894d6d2118cdb7295593837e2ef96335066dc899a44dccc93ae1aa1a6d2548d074be21170e3cd6c73555bfc3a95897ac9a4766573008ea7559a08c3ad3c21bcdc32e4dbc7c5982f279b036bf790ad0beb6b129d22d834bbd74a204d5d60bf39a3fb4ae819b772dba0ada94a45a5fd7ecc79cafa31dba6762b5b51ee95c0651b63309004923b77c010d4b6b3df457aa0b0e5507c3d804fae26b0c384c1a34d1bdc998005226e81f2b9fae100776f5e3e410f53da6898e20cebdbcdbde9efa1acbb -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d0609608648016503040202050004307f87c39e3367aae5759a4d5de9ef2ce5f95692c59fe337dc4087aa11be86c01655406490b00224111fab085cb688bac2efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 88af470625e6b5be3358cf6a8698a5655ef321838f044746df83bc55b05e8529df0b120aeb1c7b3a5a1409705879f887a22a7b78a2f30186db5fb7b888cd4e8c80c6feea5d8ecb57ddf9076b8980188594947bbd0533091a19b87906e2f727fe3589138ec3652d7d86b0d0455fd78cc5fdda283a00ebe76c5e370b25060498e7 -S = 879c4df9b66227ce30e6403b620a488c72329b400ec67667a600bcfe3d0ea893f3051c8076eee81e0fece30c4153552ae2b2c774888657adb5300bedaf4940d6d6ce9310a476093b3590fca889e8ead464809be4da3370c21784e4740453df999bb9f7c290ea16e4b0e4ca666ddf23c757474fa9b0dbef769b1876e1eb553ee3a1c14c201c101164d5d1e5f628a7ebaf65c0f0f27f239ff67a4fe659d347cf50921b5859d79d86f8bfd2a25eabfcf76eb606b4151516c482c74ca3e54ede03e99086e61c0708e8ad9c94c1fe3640bf811f4e2c0e62d17d593f2e86adfd0798f04616adf9367b0f77f40de77135301debb490bfc76ba710878ddf91651a5fa025c348b6066a49853d6ece7bc79cdcd8ae709a77b96701c1ba9c4a91663e3790bad5c5c48017fcfd005a1b03d47d07dd3c511aefeb4c766dd19e377d2d82329a222b18ee0899e166cfb37c0b1b3226123f80a33c096fa4ba784719c4d9e52e60ccddb6da8575e705a36dbee7d97093f830283c71abbbb85c06daa913f96dede4ce -SaltVal = 00 -Result = P - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 78c938a5628ba2973c2b793348ae3857f599e83bb26c930c026cfcd7d3a58da90c3091f565b2a3357b2566d424db774cffbfa08c50df4f9c0b2746832f6f936955b9c3f989b353095884677d2ac4be68d3cce6756431ac86478bd79a8b7b16f47cec367a7798985bfccee3f40573f6f5964821bf966a9411dd1f17e48ecffc93 -S = 4009022b370d46f9b15af306f177d7aacf5949bb58b68c05680eed83ef5b35b29c53f781ec1910006c4a7756d1c0e67ae52e7599f691352ad5c052dd6fa7f33121841869f1df1884489b18f4fcaf4b790f6818549b26f2c764acdea5113427c0aa6f0d0c3c688f10e572adb610240ca1397a96964861a562625f1a55c2d369017585136aa6f473c368d64f8ee85eb21aea3de696e3a258890c458b1434936f48c5725b6c81de0d2f9019a4ab27724526f64f6ed1e1dc09f1d828c1d6a1cb4c593d4e554e714bf55ef5fa2915eed46497215957abfe3c92fc06dfd73add5c2046a97b50c4d2366a4ff6c03ec4ea2e916f58240744456cf57df158a7a4c3c0bfa9cee2fe72ebc2d792a99aedfcb7070841a691abaed83bd55df0408a8555e8c58c0023d2000dd7589f9e3b5e5fc9f6448f47e870ca13755408fae7eaa16e2dfd4d41b4de4099b5e224222a520b87784b2679dcd66cfa94077b9c5756190bd25d13fb40015f1bdbb73526ab6467d0eb1aaa458f38adfd539a109eed0fc253af8e8c -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = b82dc25af8993613cd5f5e6e851dad20d155f1d2831f3278971addde70a82283655b9aab7caa2db075e933990b78d9ed763ac6ca3448ff3109e708a445b84df3452fc0533c46c2b0347347444fd7356953b80eab6531cf22152818ff9b818c6460917b79c1d6bfbc0fe5e398daa38b3a6fb80fa09f416af2c2c55316fc6ba97f -S = 03ebbcc4ce14c87345290d77a652ddb0a27143e11278b4083cc33a70e4395dab1dcc8468f483e6b8fc461e31e1d5331fda53e5ea595950888d05203b06316f7e5bbec3a2a3ba3d8917e56a657d04c0a8a8aa123119facdd323114f9a1ae78ff5d9295b4bb244443a4e3ada7c00985e74de8b295dc898ecd6c891331cd458a040edf8e8d2d9aafbfbad55f111265723bf9b04636f211d853be40c9119850c2905bf665cae93968363e82794faabcb02a2f1ea1414ff05c63c3f32832e7d786809603b41776554c973560e69c3d37eb295be53c5b9a9769dad97f4a99d15e11c5268e10387b1ba13b198165f78423b61e2c203de534f9e331c004bdf85d1413896d4deb83a8bcf8a09c26f43725ae9a1f0f6ebbba092803e498a9fa5e3d15042964596817ba275fcfc89cace5b0b566afa19fc3897223b2eedb48d1d5259aa576f3248ef1647e6c3bcd5d3f88f5894be8006147a4595d416404f2de4724080bfbdc5dd58262ca15f1987b09a80a2a38c8594e1d2307fb99c1336f85e7c0cbc8ce0 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 18201d59ba48bd77abd33ec87a68c1bf5ab93b471aab100857b7e4e6f08fadcbba050da77529e0b5ffb211ffc8a0b124861f4a592aad70ae127f9a938021309a4b5ee57ed45f47653c179462d4ded03ed55b147852a8298a6ab1566ec2dd756133f14ce7bf311b0fcac872f886694594b03742ac7ae26224c813bf819e0ba5a8 -S = a07673ffcd2d28c4dc9ee2f91ab9b1f7f59aba09779102f5832409a3ce9d9193ebb54fc122018602ecf9d52a0e29c137e7a4430253faf49ce6a5f25b7eb7245e2dc01aa870f0061cd7857a6f58e765fccd06ca7f35cd796aa016bc0198583f86ab714a044e68c4827f5ecde03f9c9843f3fd5c8448bd039b5ac70a6bec0048155a11e55f60edd315a560c5410210be96baab0056f0ef9404333d068af9a814b5e8be1ebcbb1cc746080fa7b3a09e200426188b14488cfcb564a8327eea01c0c1a1681552fc23cf516f600e596ff6bf44489f07db4167c02028eb6295c769fcab30df726aec31af2cef6a26deb01a918e6dcbe6bc16fbd21092a28418598e958b99d7db0157674ac564e03ec10bd6a59d5a87435259b5d74ecafa3c0209a6c20edb7e874f6db5fb83019dfa7820584aebbf93740849b5e63985b707e891ffcebf0c45f827933808d2a7374cee25694ce9a714f433017540c996c0b169a284a5b1b2d31c954ababb6f75d7dd060408e74bb09cb9be1288a9b52127fabdc2de942f -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 6c49d5bc93d861ac46788e3c93d6e815966b90248f46ec89370c9db0553db1bd8cb81a2e77825fbbf8c39281cc11826063f131a2ef9b89ddbcfe4a1abf0447367117d289dee475c6f85fe32232072db94a6b392d66ed719063c6b8846a4aa2a0c46de416ef870993f1546767ec3f52e6f3e08f0e1cc30b6ad66bcd357d962ac3 -S = c35cc19c52d8727b0e9945942208234a2c4ba3f4d4accaf9b54fe161b5b92537838d74a94c0aed70e58e99cdafbab8d6b968f57d3af6b7a49d8592a4b381635f7ceeb25c4efa0cf8d6cd6c2e8b751143f11ec50956db690802fa0ee40640badc70ded68345255b54a97dae73b340e10af6f546dfd395d3434b775c6dfe29058d6c3b9531e968091f8e80f9f4a82439890f7435622b3fda11eda964dbc5c94f2eb7b66ac1e17b6e4bbb5a77870e8f03af62920e64ec059e6fd037574f31636800f53e506570f5352c99f04985337819cf47e8cc54ac38667e3406597f66025d05e2269a77b347f02129b510f38f898a7a79a71dc6126d3db62dc3dfe5faf7e917cff2fd6aaccec49eaa0e8a35b4bee78ca043ab2f860155ac2ecf3cb7564d8fcfc913653f6392fc03a675884062217f23543d1030704a733d077969d9181ec555c0f3808ec7d6bb7873787c296782a8c3d374039ed636037e2aea56cd230baccb692fe46cb84efcebeec031801ec10ea4fece8940ca6e4228bf5aa40206efddb8 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d0609608648016503040202050004300ba6737418933139584032033536d357a432e5e4b816eea001f2b4d47dc04550e24f47ea3060631bca744f42b3cf9675 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 08845a6647884ae71378c1ea0ebb9cac11159eb121cc08089e0a6ad0be83b8fb3a57a052473a1bb9c8d243b5c260642b10a3556b58fa096c3dc86159d61c444d5f92f25c2f7495d2ea251abff8c03eb336fcecc6eb53c6dbfd630226659477ece0fbf78ae77ee0b9e239ee10992153cbebe70acac22068dd46a2f43e5131785f -S = 06771fb5a09539491074d33f227cda5a26e630075870b00e84c0fbf47c98e60a986d5441ec0ed557c7b02db2394951b61d3ac76a94fc87b21ae77c082bfc0271c321a77ea020900fbcb7ce8ed40016279b7462df2da6e32ce0975c3a5d05cb03dd0e97b533f3bbaa352d579a2bf2d47fb72568f2a0e06a514bd1b3475db260f0fd040626fd8681914a28d49e6566855f02ee2eaa5e1e3e277e00e677c60c87083fa88785d48f7970fbf5e835e0b2bdecc61df27ea9fc7cf3f510cb234d25405c4f9078139bc85b92bd0e8905be80380188d61d699a7c7db0e087932c2cadcc6991a34dc2a6f9c2e9b659dd1527c51d6c41fdf23b5a14f5d8f0c3ed2f28c08223ce4450ca5e896a2ffd0f490cf2495956eb0257246afeece291b8ba7c373caff9eb52ab90462069d20e3b09f1e874dadeb2cbb599d2be0eea434f70f2d26ada7812f58b7edf20ca299ec53762943c628ee31891c26f69eab3242cf0d90ef1607ed56c19ff5af4d4be35334cc013b47aa087935a855dc1ff62ac5be945978d8913 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d0609608648016503040203050004404cfedf114d5b9205c1c8fa9a8d73b55d82c17feaeadcf7da87eb11bc021a4b55a0c0e4e232dbafcccc1423db05e8a917b5d86dd9854d2f9081c5cf7744d882e2efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = b2f46df8613ade16f5efaf19cd04d7ab3a99c804e0cdf66160d493b1344a9d91dac61b7a34b3a4392f5b20a0a345d37c7ac197c715c1681eebea267573eb9709450eac967c0c05ca5e26b6fa3f714c15a2720bd6a2ea7a3d90f3223fde4c92bd3bf2a6b300f009b2cb77f99069314a5efad3ae9a4ff233a697170d793b159695 -S = a411a40f0b95e8a447e09914a31ab52842583a1a90479435bea0bd20104c6423ec3ca53a42e8803d172996237e35e59952d32ad3484fcec66fb8ace07034928ed162d287125963099eec4b1f59dc835a1ca02a658771a64e20a5d4e2c83770a11438b1956bca7c586595f8cdd28f90a033b22a27f10dfd6a3de68ae283b0af9b9fb3fae6963b9177ab6bd03b7ccef9e482c3c6cfb50434212c341afadcbb8c62ec4b63758c2ff5c4ea4e6625f8ebe1b51dadfc902c572d7786ff0acc39b82a3b3dd14ecaece9db85dde3d4f13cf7cfcfecbc5de471316585541a19270c3ac94aed43087b5c03e8da4f5ce3ab7cb10567d57fc2564e2df03143cad78a797bbdbe86e9d5d64f9cc9f9e46a288bafcca13edfabd4c1914884d6984447873d033a8164346b34405c8c0c84e1ee88d480d3bfda3aa075007d7647ee8581bfdf91912df7572bb8ebc9ae22f8dfb308e983788fdf835e415e883a401cf23a426da1b21de4d904b5d52bafa91b969f36811e829d8bafe39ed4d78e2f30c2e60038d96a95 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d0609608648016503040203050004409f24b226f1c31a5ced2822ae473ff80616c976eeaf6ca63f2ffdcf92238baaf570822977f1c37aa3b53a03a0ae95c82b8de631b9bbbd0a6bb6623d9b8ef18d0e -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 68f05fb0d353897bd65d75d3b54f34199bb8e5803b8f78c5b87fb71ac282866303b169a4b95b48baa4546f4a228fd9f899efaed9155b0a2a321100423d3cdfc596c8b31b58750f203c2a0a1dbb8d88f873d0bba7cccde9eadb566f3a87c606fceadc45fbfaca671568884f35c86ec981f30213d4a90f9c6e7bf70beae8498371 -S = e7c726b4bc65c98e0468e9e20bd38fde581f0975031c56bc8a1b149724bc313442436f6b0742aa96fef392f24f4c6e78c6afcb17a9a70a686c3091a0a746f6e427023877c5080ec23d50c2c8ed063b5d435ba3cadfb0786cc0fbec7d4b834e45ba3d4ba19101beb4cd0851cd66dac7dbe6028a5a27873b81580ef817c0cec52dcc99e5d0a48400109525813c9c087b403fff944c08febb645d36d0635c817d543d319cb0625fdc8e098cbd64b67c1981da87a4550d6bbc49d074fadff82f56332679baf1861b9f09ceeb8d18351dc7565af1e4729dbfb265056baf28ddd980dbdf512e9d86faa6acaeea1744f6437e30a9ea6faafffd6a813e255215bc1ef3e3a6d2879c763dacba1af4e657a7aa19e11143da902ee567fcf6ed9bad15f952e7087d1befe7bcef6a9f14fb7d7cbe9e06ff583ea888b27a0781c1e1c46dbabd14d5688f25cab383b05c79dd4f500bd2be7c647cab0b12c123a0257cda1f0dab31d42f70b53adc07765e583a146ecde0f37fde7c0f93e72cdc56e734577be3cd1a -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 98ccc6f8347973189f124ecceb360f429f1aa6f850ce712175c2b24a7688403d06db7d26b3e187f4bbadb302220837f7017126eb2162a2cbc8d54dfed3070048057cc0ef9f43ed1d317bbd86af16e94ac7dda61d72b4d7a5ca2081231b067f563cb6779d20270c5ba884559fbbe88e0599670ed76c4d797821aa3703750e252f -S = 039f309c9e084736e33c0be61eda376c5ab9759a0ef9e47f9fe17ae52cc6bf878cc2bc6bc3dbd9986f9f1b971a5eea3377a919922aeca340d63fc414376aea9670aba138a831f75b4bc63ff3b1964a6d732988e6d801f4bffde8b36fe629e57ff3f6d6ca425a8b7d23f6f66d647aad60e60819cf00afea8003bc56ae59de98a4f0e87ce92f4a12e3641a7b4c9dc53027659f0257c3ec7e013e8396b5a006ea8b1fea2eb25132618f75f5903640bcafba9f511338fc234e1f000cfccee896194d0182347e979afa5b03402690f959329ec567bad325172c913b4575c1c46722828a99e9a304f016eb615664a43ad1bdb26e99e429c2cda4926c9005af24de69861850b6a0908347b2e72474df05c775b7cfb2360df99dfafbed216844931117462497b51e40b6b634863eb5043f001b6d3b15e61f00de1d9f012fb774933f502089a213ad2eb89cd150b46895405f087c5c93d7a9fb55bce4a2d93505d81f2966ecc6e0386c1957451d014892087d978422c612d226c9dbdad48a3aafe50bec47 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 112b7aa9fec5c7ac703a49c298c4e29586083296f79b099e6ec422d586840ed486d36e06362d6554f14d4d01fc39a9d2167e5b7350bd18161f66185db0c4127a7b3a67951bcc9e6d5de010439746e4f43b773e65ab1ab4234fcd024be621fea819e6ce1c56aa5841db7cfa4f11f67b411c7a4233b0bbc60f267f4668cfa4baa6 -S = aa3ee99d39ad0332ca48deeb68b5966962018906f1e2e97d0d711df66e600fc875faf8da141212ea9bc49b2934f19bcb26f819b3633381b23f74f0c1d486c8fed6f6c17cacaac222e55c8c534ca2cb3921ca6f0cc19d045fa5456b4ffbc496d0d3079f19d93bba5600048b783a905abc3f30fe4b33b057a203b5f9d01254bdeb02896cc11b713fdca55e3ecc67e243fddf19130e2f3c79bd984558feef0fe877e071b0a13323e700de83244e2bcc09a602eaa06bb39d832d58e30450dcd96b30052778c07d4b209d5929bb6cc80800c95963a24bea449189301b50b5f26a899739dd0a4af6eba05e7e625c96cabda3beb2e4b0d11ccf72252b2d524d76a104a6dcef635517d78f248c78837422ac900557e1671958116500c673e2fc9a08e40d4eff8d44146f43fcc5f4086d276ba026e9953425a11b7be0036ddba0648f12424c3359cd8db8a0490b1bab3b35d3550840b4937ad1986aadedab74fcab27fec7561ae2bbcbb16d28d173efdf049fa8a1daae66db51f4c03fc91d1cda85d2cddc -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 078ad6bde08572c73c5e94bdf0f1efd12da3a8fe7c035027236acd3e4ea86edd1bddd92ca601d012b7aa4e4e543caccdb49f54e35ecac7ee8b03b522a1b09957fe3ebc4d42dd96dcd4f9f2e215dba47749c9ec7369ec21571b21af638ac6f05d45980c4af0c1e6db2f70dcd738a803cb9cee7dffc3e7a735ec6c2541b270cc6b0225ef71939220f9ef35cf5c5b0dc291e237bd456333d803d12883e0694b2e891a3248ca36b838a8de27e154624fea5149857214b15ac4b4d67e0ab944ff5000552c66f833239f3d4c27a76cb14dd181d3f52a12cb4f3f9518dcb68c9db923e677d6f733febc93152c311880205a5b73ef323c07b87cd55549156b0452656f0f11a2c430924f426a22117c04dea477588fe092bbad1a4bf2a0a7b6befcffa3f91f4d308ff24515dae15897e9ab00bf755f9a366057b66f095573a9f881bc48e3711de800b3c0155c976957c40eab8834c7b7911d426fd7484e895fc8d8bb5ef7b562da7a846fd6bd013cef55ff3b11de43fe6da0c90b59dba4bb060ce4caf3cd -Msg = 7f1b83830b4da729242205b0e519b5243d32442d45f5a933d1b57bc54616613cabcdc99b02a7ddbad8cdb2a41b46c33d2cbd9f283585dee7bdda5944796a9bf06514926b14ef8a23448e5de0b682e35f3d21b03d1486ff1874d9e9f066d1dbd3d77646b9ea2c98ad92ed6c2d5fd6fdd498e5e1368b01f40c213a9291b553092b -S = c8e55b1b1ace23e606465dc81f6a349ad61d2b8a1afed31215ee6a0c8214c5366a2ce18cb649c4bcccde5ef2bf4af51f093049d1ecfa5f5b639f7ec62d5a4cbc505d0f11bae2c16d8d6a61a4f1f9613be25d66fcba03a7c405204cc816414a296787e5a1462d12fab51a829bf13dec500da689520ddddc305152021337a86b676545f8202c5f936d9cadeda41a111b65d9174488419dd19da5d3960b6f59281bb2e90b4c12891a1d5800d0b0a932bbc95639b130dc7d03402322f7cc7e06020d5124023b049c61cc6e88b345d0a395c80f1f04b7760f0c526537f4d4c515696253361a0eb03c3c5bf567cee736f63572c85db1c7e5d016ff19c0e1d38caf0f7569dc00e3c4301be9baed19d45aaa90ab7204c2c70191926ebac319caa27f55e5e68b57ba4a70dc153d750e318099c85359f1ebe70686f4bbaf9b9f6de3459cd8c4a7bcf8e559eb7c68790a67b0951554d9fed9b5c396f44860ec61cf0446cfa8061b19c72a34b62be8f34736fbf14fe556ad57aea605c60adbdee4d3fafc5af8 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -n = f33d3234f13272c3b2b6821ce4805663ff2e8b0d2a47de363d97fc9cc879cc6b40f9e53aea695dc538a0d2b558498829aac327eacbcd889e172b34f90745c5d528b7e82605f1a58fd228ec7fd4b6f476f393864f48dc47097c8a780a2ecc02f748138dbd7df99c52d822a2e5154c6047fb0eeb4f49da38edcae3c32d3fde435f291f96cad1e09e1030ad7efb4944b69e074d0d7964becb3cb86238d8d293bef3030d141d14868bc21fa133e9de1115f749991cf86ef506e663ac162b2c8567ff131a6b467a6f564d6c588860becbd88970354198ecdd4f1f4baee8f8bdaf7255835385f5673625f113550b123628a0be3994d91c3a19a82e5d73448dabf684ee6794fba7a2b1afbee0287e5a11180c29ce0896795d52ac7f408fe28e8e9116fe0b61a1083f95c5227d62d5537b5040b79e21b3a8e83c225bf3efebb2f808541e97d28a2468359fc60f588e74faad611262064628a25d8d61f9d03d8b21cca515595aaf2343a759b74a6a8afeffca139a389aa281995cd18e16a9cf7b7ff0dddb - -p = f3fcc6aae575312778d9e896acfd7c1aa4c5524f20453e8bab255363164afa7124b2425587a077fa0bfaf61b12ef3f0540dc4c9e777122a60610a53d1d75b0a5859c654a8ddfc2ff4860758bf5a6f264bf8bc2baa7551eb7be23bc06978be992fc81d890e07a3abf95d20eee3f6bbbc089985cac96395b473b2741c66bd2ccbef228432f66b906c15b19694dd786c29f06cbc17b2e6400dde4e3db85819382b3d05a4c3009f092d40d05ed5b2e0428a214e15a7aca09b47120b9ea6cb4084fcd - -q = ff36fcdc519fe10c69aa0dde2cf3bc72cf2ce9a54ac063d809b523f4e5d7ddaa5413d500dc21f409ce661bf33018b748fba3966d874bf96f4313eafea9decfba71d540ae0508161a3658c4762d94ebb3a4e228c45661315db30c20fbd9e20e24c044e4f0b49e6ec80949b16e0ab07f3d32b248b39f48332cc3686df05d29c170a7276acdd129259aaf018ae3afb49b6e0ddb9e404a492863daee7be71dfb11279047794e45f399a9665796d32d5e65956a13a6fbe992b36bf4c842f5f519ac47 - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = 3330bc3d3eda995522e8849c7e8bb5f3f6e895b3d7238156febdca74f62100f26079707698c6eb1d9530c971119a2e95ea7a8cc3c9e869f901f563eeba3d714b4ec06b18f3edcd749b00b88a188e39c0845ece31e07b265efb872920955238e2c5acb60c9877c7c2fb0057cfdb8f5fdc8a3c63e6650540efb41e24f3d188de1d -S = 5949a5007545d28832b13c6c0a453447eff95e2dcff9e403db83bba0379abed6d503394befaedefe578be085622fa73ab8f63af52eb91dded8a0456df41651cabccfd34250b813b57dcc4535edbe0901196724c0842b951ebf3ab469faaa51fb22e5574696dbb57614892d21a889224f6bb0da4b81b8fce60499b8802b36f1576780e298d87b71dd5496128b0c8fbd3f1994385c8029b720cde1317db984e02c0ee77cafca705d4be54fbca18c4f5ddf85eaeab784002c8d1fdf5e3794d94c5c6c781e9c05eee22e4c1556d9f8f6215b23d5c687ddb79af29a280a4cd6be95542709f423d918d9147c2c501d3f6121e942fbeedbe70dafaf76819842d651df018959e586e8ac4325a5e616c3e6474e1640d259c55474366761156aabd0d144a6437e7584bf33089ead0610f9ce10dbe39fa93ecc7665082d64aac474432689758cdb092757a53ee5b9b4eb3f6ec3589074248ee547c6fd203fe5bbf217974f1e2e398dd4d1909e85146d7e1dcf74ed9478ebd414268bef406228ef21c80ed1e4 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = cb67ebf8f8adde0c2b0640db1f4668ef866c27606577504abb7b777e63f3f8783b593c9286f437778ff235d990b6d767d17358f914fa150e31d04d79fe842557713fef44099dabcf69bbce2b479243278483b05f9c32fab441980bfb4354d3f2b3428c78484f43fd018c94370c81b516e7c3b6fbc5c9062533fb3a6bfb0c0a31 -S = 5e8e0eda2fd7477143e33826c1f37f1091e766874f8d9717ada2754610aee94c5bdbcf939e710a2d5bdce1329aaab8eee0a33ea8d93ac243e80a61f09fe31dad8eb291525dfda5110148a9041551c4673db5edb4d3e457e2ac8834bfe600ad9e210a9dbd238f8811552a5a6de7ac23e7ead2746cce7358e7b0fe27af32e204bf292e7be24536a1df8e10712bce78d0d94331de7095e9f56760d7e9e3534b0a8bb30357e2948e2e649c489e916abb399541067f778a21505e0ce4e43e3a64c30fcb8a22c575b2f63868b151e7c0865a52884008477d78aedec9b950bca5ffa93dee9c7b8234a054b61d2898a4fdafb1cd2008635ff56744d0419cee15477f544caf2b264dff93c2ef060fbc7e062ea29d80bec0e74287d9e2c0adba92b5592c4339776bef5cda132c83f296810833cc99119aaa31849ddcf62bf16c45f7654f04ac4eac75102e9c5b79738e7d405caa63dd917f3f199d132169192397198c67551ea78339ae376502e7e4ab23e5626c766fba9916ecd20d15fd63c75e4a927ec8 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = fc57235b4d597f5a5380a07aaf7ac6074b17d75ee4b504ffc6fcaae4d7cb7611d771cd6de6216bd047a04a5d6341c5121113fd9d14597c71e53a181ab4ba1acda9e9a0446f5a40c9f3d7ee9069532049912030f6386301fa01c4e573656abecaf9266489efee476ce08e56bac99a1fd553a7371057badcc2a101d999f4c1aa30 -S = 5b53b1a1fbbb8a28bc715cd607a699caa795fcff045e660e102b6c51e0daf25a9cc0d0639c1bbcbb9805904cf16ea3bc26c18f58a3702f39a3c1cbc5e6dac954d65d102e0c44345704844af1b8e3f15b7dad532192e35e27a335bb67dd3367c828b7eac524e1fa3a1db556c0c3180487ce197cef59ef05025d0e0c7dfb87fd9da457d15688434f5165f16205a8400849118de58b6380b807a6600c698b2553979c7e0b83ca200433c5b5a6155eb6b37ccd8d584f695a93e2b1a3f933e3a0997c18ec63c6e90c54f87bc48b8057be5eea9131d8acd848843fb3aea56882c414258478548a7806de7db039d97c5c440d8a99923cfd7c3718046fb16bfe53dfd157be94edc1ce944fd5770c38247d78927947c06d113759f4134c841323b3679b0e1b4537335d4a16aa2ddb01fb1735b8f8d0b0107ae714fbf727ac74572d355da37b997b9a424735f535232ddacd026814799d86b91b7701753fe1952651e991a1b8357f43ea06c043ca1cd57fdec28ddbe011554bc04dbbf3cecd03710d454bfd -SaltVal = 00 -Result = P - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = 6449afe8eb08b35e4411a1bdf1eab7d7cf0d5813f83b1063e714d376dde5852e84c1c054d2d3d18b31f20382dd76216e8d4a36b8554397f2cbb023106933cad532cf4c8b984143f79e94648c3af002dffdb3d35bf5c2f736d32236a349c28a4ab69bddf505fb138cd21e4b43cfff6212676db966a1613916468f9498463bcd75 -S = aa36dfbe785a437cd2c92b11941827bb4884157fdcae8331de98ab8d3294ce8425e719b3b0e54eb27d7a46e9729ce18044880a18261d28d6c10641818d7dd47c421d748c984597cfcfca821f8c3294da53d16c1af99135f750294709b92755a3f5051e033ce3f6df055a77c628ca952511a33b2a1e6ebdae047d9c7589c8689e9ab16747dd4788d023315e6c98f2f060f3bcb655d487afccef512d929da03e0e4d7ecc2b7715ca61cbad3f8fd8f4383391014f14fb414cf49347ac60c01b713b6dad9e09e60b927b261aa5877a1d5b0e76906d40bc77cfb41405b93a3c93fc2ac12aa08e44b577980e2ffdbce606aee14533c8161c85ce8e4493a8c1aa03f708c6a4f84d44f9d147082c1d6d0c8498e109d4e26406ddaeaafb9409cb2cf249a6308d3d8d7bedbb8133d542513d9c4424a3609e81066dece42a7a115279af0155e3596058a4e22f6876cd931f1e4e5ae5800ca96eca88a3c04b789ca1c843fa9730b4c050e269f9f101a48c5c1df7e5770f5a823e1e29dcb47367153a17bff1ec -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a05000414c2f234adf6d0986f254e79e3e89264f7681cdb65efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = 6d16916bed6c4e35c76fcf5ba043724e7404bb147d12534057ac512261c1b93b660242f37d3c5d8f2de5725dd5f56d314bf77915c45f0b3df41e23397674cf6e6d05f0c76c3040a8939c9424fb135f6f55947896cda31d6d35e437c95fe8dff0ca47224e81ef016a41bbbc18da4851efd7043ffd61878fba6127153be5c6f4a8 -S = b08db35d788332d2bdeb8e89c371858710b0664e464f9b726c92ffa837387e7ff14a885cc776b1ec4763da1c7120c5da133c3dc01de44c93fae6a9e13c3542f5ac6ea44f3ac9892a5b775a535b4723777a43240af123ef78bb1c1d6788098fd148a764290a559ff2637af485d280bed6e1b289e518aee6cbe842b3feedd158c409d13a5f117c8db853bab5b564e43a06a83f4d2748cd718bdb8fe41f5fcdf9f0104dd8125fddb401e8b5ddcad388007c3c86c0e4502c94e67b0d194002f5464d22ca2ec65af465abbd44bf90e3b578a9884b86728fe22705a9ab24549d4c168eb7b3f1c6f6b07a55c3a8347b392e0eb50ae985a7e3eef4cbfe060692b45c6671597c59947d056b9452b2030529705a6793547d75d67298182087193f608163f3599464ab3ffe82539e202679b84df75ad7effd5985b9e08a88d3977dc978b748a9bece9e08b42b88ec6a766989aa03c1ff73445706035cb50fbf01f89c9855784912dc7b911cadacb0fac987e7f5bab76d9658ff84755c70225a4e42bdc84feb -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = 724265b54dd8716ecca57175e3182d40c4ef7a1f0d9e0fc240f095fc75f0fdc64b0a1687246e5f9392b51af10cc7a161e6fcfd9d8081b5e0bdfee4a5b6758eb1b06e34534c51a6ebfe1319a9c0147997084801daf7960835d37d1eceb7fd573589b5e7a22d49ef7ef806972568c95deb121cad5ddba3b1c96bb76a00df50005a -S = b2f503ef1d4b84ee0abdcf78640f1f82de00b2f5fefd803e1322a3e09e617750884b4d6d7e8aa741c93e9b36dae70647c3fae398161729f2f8962f9985157ff7fd7de42d8ae7579602fec0f91d0350a8bb38fb54234d806f3251eb6ee2a3806e3fa846a7add80f0d2dd2fe9977265f5ada5012f739bd3f06925d7b8ce869851bbd5897b819c71effe7a611b1105e68a3edc5b70cede299548e9116841ff1ee624ce0d8d477a18c723ac05c756084f4e7cbfe851db1e044ea175c8603f90a4ea87421e79565b8ad247c9885a41af0a2d1032f2807b731f574d54b6c82af900b0a1815b4e30513c7033e67a1c78329dff1a4542bf28aa5ea78de037bcbd7a9e0740693f71586d2dde6df39a979dc55335854d656a8a4f123b4414504b1a3f3f0f5e7d12ab700d24b9f34df58eccf2371d9e8429f5f206122b3663f99ba02929e8f46aaf061845f793ba8bc7e4de8621bf2d1df9a1ae2fc130a478437c10d2bbd51207dc07af35c88c5807c92b739d3b5a689250ecf86bf1bcc8e3b5238d2884073 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a050004143ea74de96d5511a9072c9cb0dab7868fc0c87e3d -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = a6185cf668fe6bcd1a872da768424d95f6d52792a0342c580617887948aa03aa0e862562cce09ea44400e5184cf51e61d18841ab1c6e798354c2caec44b2f7af5f78a3f2018cb60cf817029843ab27c81932b3fd2e258e9431ff960299f08623a1d51ccf91687baf40b4ce4ed7cd2e73d7bdc6af5ec13432a6b633e2cece77af -S = a31dc7740083a5c5b17c2b4549d4ff97405b2de7a5d878ba927fe7cba62de764685a23f65cdfbe9d0ae2060434443f8b18d8032e7d7b952428dab81cd158ea3946d17c28d1bb160e6e8da0be12489206cc1c57670da9277e53ffd10a3a4883796d9389e2a361e335efe34e91d6d12e78f606a7e79fa3afc7640396d72cf34cf39150e7784110ba4c703d34747ce050c0d679ef7b1e72cc9e049e4ec583b9aae258d08560e74ba41d4917d8f41c1d4a3b8f04bb76c99b36f738619e6c3b977f716f1229da7d54287c0209403ceb35e98e77cc37499b7c2127254ddec1826d8ed6fb83ffa13e4727ad2329d6c85df002025b0639399a050bc2ee13ef43d4b5cf25a36cc0c9fa27c2e2523093dc48a2b1f66aab351965866459f6c4bb59827cdef8058311a81713c011f8f77f819c906be90fc9e09b6c5cd8ded0da32a30e756ac1fc26282af539dba2398ab21a254067fa338479714fa3b37fd7d7e6032e6b9e5cd31f23972b1aedc53778ceb8a39d3b2b3337e694be843e35dcfc310b09f560f0 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = f5df0f6986dd3e9cf4c243af92a6a69fba85406eb7944318e2d47ac80ce7d24c1c231ac6f9e507a5ab277bd4bd550631e55dae41e706eb22b682f6c1dc46434d1d194ceb576b91abade9ddbae44ecada0d7c871065cbd99c79a1602e8e431c573fea303e681ae594432ff1cad139fa817c095642fa8c156f74584179e8856454 -S = aa1f614775143e046d4ab4d317f2a69a319e82f91dd4e9e3cde226c5ff87bca2093afefa76890fd8a2cefe38c96aa94dfe9efe7e3975425f77bc6b4b13f2c84e8ee80aa7ebd95683a95ae0255f0923faecce58b02c6dc9ac9336801fd0a768d6df0a0b705d8e1402fb8f769ed32f8cb890be42b86a1035d73f01ff6757bd02a7e99449a5849f0f2d0003ef53773a0b13cc07e53a81a7914892238ef798faad7660f9caea94abc282870714d1e9bf7d29840f0beea5cf4addb6bda8b441db30dd43e207249577db9af55c674cc58ba2cefaf1a4fb03ee766f45dc46aacd12c7cc5508371db63f2b971e6842819a33b3535a1592787bdb0544317f88cfd63e43dcc987472cfbafdaa5923b3737165f979ebfb647d86f6d2a8dd5137484225164b19f063fca9cc72f516b2402983f7e5a643f8cb299870166b04177daeb90ea978e957d5f7a918063253d7144f589019c7691c6198f830b86d9c8a97af6d530d0c1126b377d5f450ee9eebe33a9b135774624f575caa08871c549f2d074552ca2b6 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = e3fc380f53d94344f864766b7f1ca420e59f430ff31d120a080bff5a181c4753f56ddf2ccdff130df46b6d68e4d1d88d83120579a43f0eefcf5159cb451ac0923f7bee4d77d80c98e9c99ef6db12a7671bd6143d8807572bd321539f87187851478e2f1c574a780e5fe6d1bb6bc75bd635533802a75d37e59ce4b37ee7feb8b9 -S = 6556cf98dad966f1c91e0fc492d74f52a7896d1901409047bc630f4b4e97044cb9f142e6560467aab4d65a302d856f72c15332873e0a8b646b3c70bfa8d522c50906c240289741e5e9d11f77a640b7d96707c959d130355fb2a2fd65af4bef7f05ef9496f630f79139d90556a970e1110d12ef10a1b7e74e6dcf7a39ae299ef8649c06d745104ca65b82b52eaa0f00f936525065221a690a65afd7699d93c70405403cc13a72d944dcc0efcd431604aa638515033cfb499207de58a798a22c047d18dc825abead4848c7f521eb1ddb2a10af5fd7bbdf9eca83fea139f6a015b614d7126652a302786850f400c05c2945de31cdbf0ae83c3e39c80a1860d233f17e5925a211b1a35e1e7bd72cc1785f9674f858b43759542809a3d9e241d29a62519424c8215815e0e85bd1374ef99ec64f08b3e84e3a6c04918462098329c97d8522aae23e3d5511d6489a1155774916946e7e0e10979905c5cb603561fb6004dcfc30ad2b6817272be904e928c4951eded095e75a5f7726f255b01a85211bf4 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = 167c1cf3b93548a9248cba2d5024da528f9a23bbcdb883a915ec051157f8adf268eaa3e54a4f95f6aea456b2b70dcb81014a0736e2e6b5e5efb1b6f4c2710c75fbd5f7b385aa5d0b1b516ffe0a718a8438e95ba26509473eb1010a335e999ea1d8235e86f2ae6b93737d4f38d1b8e0023c606726de88025e62c347f3b3d92a1b -S = 674ee4315853c10823b2d0da2e4b13b6125b9ab7ec5458fa09139ae74dd16b83f88a75bbff1b7d70a3d099d12c6a84661dc4097ddf5b569a5f3d1ff4de4b595dfc0a6726d1e6d1962af78a94ed73fd2104fcedafb61097f8753b5e8420e17e284179e7fbd16d3ca50ed0a66c5c2ea1e412f3f758ec18f6fc07e69164f71a8a1d779365a5042f5ab514005937da2b92b5120b62590134888134176f5cafbbb4a98f08c4e2d581e0ad9deb2caa666f36d4ee13e3be6a31861e4609479dcd4796b9064e7164aa7569230baba4fdcda388bff7d2c52645e9d4331c76cd2726eaa7039078fc0f74a47882bc0a47ffbb43e284d6dc4532e94f4bafa5e17d8dd2f108cb2f3b206e06eacd8a901a6e1f7c82ea45959c3de898560678aaa052ea9d9217e97b2a30de1cf6649fccac679f15317423078edf88af05080b679a581be29a76d8cc20ea7d33ec576ae8aef7d58c1b3126f6efa0941434b6dea5c0ffe8f404f1d37cacc3c5e853ad269a18bbc19720cd214eccc813d95ec62a0f083d2d0e66224e -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c20f660487ee230a6692b24f4eab6705e71f3b31197c1b445b5986def -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = 2524a5d692240e9c82d0d620a0b7a08c3f71ee679bd78a676174268672363f57e469479b4ae6021036883189fce06e43b82a5777927fee2c404c404fcd024505990f0840a20e0791013add3db8291e92aab7837beb4047533a12d0f7cc21921f4cfd31ee1f02e5c7ecce23635cf97a201e00bb9c2f815c8358ae1ea5f8fcee4c -S = b7ef6a53edc10ca9d6a16678c2cc38ee3859dfec0ed0012c788c5981fe2a1d04103acb6179c176d9f9003eb86db354fd504107c7921608e131cb3d4642ea87c0be3e91e7e85943e7ba650db959eeee710b0cec5817990de252244e95aafae943b9828f11da0e490d11b5990ca2d3254095f3ffc0defc38e5d9d87e3088a84d002844b8fb7231cc7d69539bcefa4eb345168529a12cbf866a76bc1f46c112b25099f91290222b839ba7167e8bb99a001d139e18a231c6fd5c7ddde5a0799b2885f8d32b77b620fa555d43bcfa1cdb897e53d8786f7fa2a734cf881994fd8b71148a3b96791c18d28fb6e39e9acea7e61a03b3367a1eed28c15ffed710389c6b047ac5cecc30cf4a9b0ac2648204c72ba48a7957e7190e4d34bd8a55e3e488e61cc64f1130d81f5a182d480fe032aa7f7302ab386eac8666c2213b103872564c11ac0e63f1b9a2946f3e185a0815e4ee2aab57a592344afb8568d70979e62077d5256fed2aa02d800ebadd4d9b26d7ec7ef0b3edf89d2fadbeed40f35b54897f49 -SaltVal = 00 -Result = P - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = 93af2807782787ccbdda1f2d60e56c455c5ef40f152fcfd7f62466ee59427ba2a75b6a6dc0dfae6d9df5a61434ca99219b29f9cf714de44c7af3f06c89b3289fa38f522161cd7470960296033270c8396691679009f49d173b48272648b75b4ccf7569892398e1bdf12a7561237c017505bec8b9a6cd0020824c92825df61b91 -S = c0aff8cf59e543109654e1bd05a2fac0a13782cf26cff6978a07e72b6aa64ab84dba40836ec1504a83a51374e32f09dee79845cda7aa9fb6c75a9bde61616addd9bef949f55d5a638615e3947c64fe8d8a85bb54ef6e71090b7c84812da8d4af8929c1964f27820435a587318c148f9221fdb4b63ce7f43c22a0e840bdfc56ec1205fbc5735158a1a6624869e4ca791d95b2fa01b1e1434709014549f4c0998a0574c6711d1a4295b653317db362f151b371a851535601de3d66d03c24fcce8116c1242e523a074754231f3c70e9e2985a5228021fd6389823a48b5aa2a70febcd61aec23fe98f6a9f305d588289c6e3f2522b6c28a94bdb27bc81b44a39a0b826572ea40a9772b9e3aff50106bd77b2a5ccaa1b901eee1d8ea6e037f7815110fefaf2cba69c55f7035d2771b095ce38d13553798c400e2f7d407fd0b3dcdb38d8592c4edfc5e5cece6aff1be8de3769a3269fc2a99d1ecc98c0ffae39313c1827b81d361074f9d1919829e23e20d0f2e361417b35da1eee8849899ed2f199fe -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041c9cf324cc0a040165d93508d7218c029560c75dc71785fa64343930ecefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = 38f06d35930bdafb5aa674262c796b395036f3a54103e9e26a2ebabd2e1c81f42b836f00c0d97032cc0d0b01b9748aa3ba065cda50cab711138f82a7afdd718b2d2b7209745248e30f4275a430f45e31f5a0aaa1eb2feb4ed1f3802c9e96ba5ac5503df7b75da937a9af7ab698e02d0c8b6aa5a1191accc32ac27df5022fa28a -S = 0ea93bb8e9b4639bc999e044c328e9991b5986dec71937465695d5ede0a28d5f152cd19cee3794ce1391a2cef186a92a789e46f70d7ab5e38d0d02ada5a9bcb558ab77fc06ab08db51d159cd9648a49cdd7239748ca02eea81e3e08758cc4054e279e1a98d77a2cb9ff77649c84e843f02d61b98ab73788da32b8fbd9e7d0338089ff2697341e4fee7cc72b73093e098b361a76eb0d56072b9bd04aeb05eae4c918027dc6f3c12607c504031d54e456af36be5c711b544bcba137fe415e96c25d5931a4524bff801bcd5f771370d42157ab1304c201ab6654dfa4f5f933aef840b74feedf08a3c8d74ca4de6fe562950bb7e5c3d901a3eebe1bfb2c6b6ec24b44535bd0f89b6ba7ff65378a65781ccc5243a9578f74f90f894447c49d240d6e118e92ebfcd8079326174b55291ecf57bf39813df3651f690eb1c5d8056b8bd50cbac145e909138c37a6844a5b624da4be9d13a988a5c43e2b49d11f035a92a098a59071b26231b024c1f6fad1920c2059cb53838215c6be939b2db31ba595ad3 -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = 49da6ae32f9149781533adb07e035a916ad270052b7ee57f74b931e1b30b4b9ea01ad51b162a935c23e022dc5b4be7bc71254520085513d7c6b94d3aaa230956a0a1ad4d530260f94395bed31734d01334813b198e70b70cbe06c3c1566098de71f65b3f8e2196989edbe95c5bc6fddedc71bab766d6ba678627fd3f5ccade7e -S = 1273aec2765d853e0dbc6819df05d3c008cf12a14078d0398ad1c833340e8aa656e463f170324879d99e14a10f67e29b5b09b9dbe71e93b298c61db9c47426064dc5a95d250cb06fdd9d3258a6112180a390df3a82aefabbe5c3083e0978725da87104c50d9e831d24ad9545f3c11eade633638589e04685f671e68a6ece18c856521d91d4d74fda95879ee39a45ac139416472c3a5ba6fa17d744745da2a7a5ca1b2d38e813d2058f7fa54a2787e464a9764b11f7421f6fcabbf982f4046b4d4ef7f0e86caf038265c0f1711b2ce4ddcc5a70b8f77337fa219c1068f15f8533d99e9773313159f04f746d629129f03e517280d3c41f304e531cb8ab3e6c5a097700e9f890026274cf9deb9e80836636b3dfb2133d24cbd7c5174e89ac5e28dc2523b13b4e1031913e172eca410c3ac3cac74734b45f8448a531aca430f0d00d3bfbaede84d9c4220ea88017edea356d19e30678ea5f82ea7537192f10489ff50e40eed9f4f78075a37613df24d5da59fd075f1a45cc9d7a61a2ef8274c0e7ff -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = a455b7d1b3b32ef7daa94505fe97b16726745409dfadbfc9df30f52ce7c3714fee9b6b217b2a58d05338b0815435f344a1ceee47ffbe3b4a7fe707525ea117a229520de7243fe8b3eda1cb2c5dfcff06afac3aaee4c022c8650c0ddceb7a0b4c9ca1268a7799e887f10d1e6fe091dc939936c1a7555c7c2ddac88f3157f75337 -S = b92a17bc07f74204ac547672fd12d01df6888ed332d1453aa423e504c11c4828e500edb7ccf8071f1f98c4b68a7fdbe665a3b82fec5acbde24a0be40bace89bcb59d4f9b83323e6f3cd0656cf9334974b02d437155d6d37a02de832a8356a88f83cce253b4bce850d9c5e00e89a6bfe1ef7215d64b68a259b8f25fab901f5e6f9f0a8b508c554f2b1162ba358fa5270c6ded1e36af3f47c3558523eb1c3c7d6373e4679324481300e8af1737ee62b840001659678987017d2212c4387dd16105dd81f77b40357f607a7d5bd6ce07f7ee5d7ac4cd6d0df5136751d438000b26e4d36585ccb743102fadb674251a870396a3c0c91f6df33af415c196f7de0746d2060b28b456bad9b0c81d22a58f2e9ce06371b5d40a8eb1d0fb98a1610fb734e9fdd48fc553b08dc13dab29328cc3ba552557e2bc4c245c247cc7549a03bd2b616c01e98b04ea835d0f02c6d13939f62264d28aeadce370df07e722057254aa312f0abcfd306431d880330fed7d76337f58eca8a24bf3860a8c758a6df39d95e9 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = d262295e4f40d1ddaecf5fcd56af7b80625a4cd83c64a3ad6d02766fb3ca910d54b98815b37af01c21e5ce60f5c750acdfe1bb7c7933a5621f7a64a801f7c637767203b7947feff8fd007491fbeb40c7d04dbbb0478f3c988ff87ca349744bb4e094818e19d53839eb2538a890a3b398dca733bbce02d0166587a6a7b4ca864c -S = b27d86aba157581c706913aefc77e7ac3c9d4946c646a6f7ff78d4c1c19d0488637c010dff274cedf37014fe1c89d29018daab58b5aada55fbc35cc973290d3f4a7e7c61f78fb3216793d087adbcda38d963fea102b4240a09cdd433086248173f201171ae10014b0c785b5c374c0fc2a38e021f98d78954aefe53244d01cff67b7991ba28dbb1127f21ebba54440d31f5ab3bfa6be1b7d6696445e47f071232be25b08da70ac8ec00603910f9706d6f3692de55d1e646cc7c34a4887cd692e69db28e00a5de8c8d2a618e351f7714c59ebc419231e36d6debba2d3a054ecfb9bf6268e6507aa96823acd635f6d31b6d716ae10425c9661a0a8b7b8797d2d90d27336faa572a13b33dffb81918b42c70c28f0ae88ffc923120cc50ee8f5d9025f71936b606bf44b8d1f26dce76b1b13f2b6c3c5903407e846fce2dc7e3d7fbfd00693e4c25dd96ede4e29473d8edb7532b729010df0aa73d81386c470af3326fb3bdbae500965c0bcc7697e92f8cffc14ea29e5021b56d4f78a668c72a57bf86 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = c9e861253ff04d978781a7a45099445db4fbacba1c821e905eb6d4bd299d87a5a3d436e350dd243836bb20c73fbc0885de9790ebf5b640eef7d5bc304acc4878efa98b606402934dc98a1aa443e1083b9eb1390e36f67f34179deb11635148ccf492e9034307a5be88151fa223b04b683b712d8da5e9e44a0736e8c63dd3908b -S = af1a58738c5900de8d3be297fcd89458a2c11b90532dbf31acb6a4bb1ef2141e866637bd59e7af286f396bffa1fb46e13c2ddf0591df51a8ec29691c03d734ba37727421806cca1650cf172cbca3c60876992af88037e6e43902eca5c2c91ba7cf8a408adcb5545bb4151f05a31db4bfb17978aaba5b5bc626c07880f52c47f2f53d60b5197f4374695ded18f18dea635940740a3c5aee8caa9f01ce9fb02ee9bb66743fab75e63e2233089302044085c5e0ddb723aa142e0ba9f30abeb47782655d980dd7869caf0ca65b25958395dbff5fbac082141bc6cec4f032c60e973e0a6b1421f5126b5ecaf92f4873077dcca2d90b492ecfecb1fd76512ad2726f9c036206bc34deab19dd39182b8616eda9f97745f2e09432ae55ddd6ec683bd366e45668dffad941e7458e01afda6e3a232fb715799975cd9d81130d73f834300f2657112d57d661ea7705e912854676e50c43ace1093ba5bf579627e97e2539d6b0fe53741541487f89c2fac52fc97dd4dfe0b58c9637cbbd84011a80adeb3789 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420bd0a68c45ca3504eff3fd99a411e4930d50450c1dfaf869af04bbec14d10a9c0 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = b44a3b7de7c8b57126fa95ae13853b28a221ce78d84d2330d242e06b0825e1a8d380dad82df33eb5b82760560304d90008242940f987a1363c888034b40f5c884209c3958b152329fc80e70a0c74e3d2c16cf2fd76ebdd41db6e7f1e3d9f27b508cb3edd8a962a74f9ee71f3b83d2245d6e371dad8e3a1f7b8dc27502d3c0cd8 -S = 7f0b8969669053c26cb0051e0c182fa688375ed6afdd39f7982d88bdf8d422e9c9ce4ab5d1f63a18db785031d17a3286d7cc1349d1ebfd764522cab0962fcb1e071394d00b4595231e8fb7db6d10e659ce8158ebe78e7ea60818d0276a2645cf2dea02d12e9447652259dd12a93936cf2cc0259d03fac70ccf47c99dd8e0b5cc9f90916a961e9b16f9e80b51dfdb38a6efefdb5e2dbd7359a292b89d8aed8868b7e9fc444a262a04a331894a57ef0eb2be8ecf79c6481fa8bee709bbfe6cdcebf04325e98ea156e82a4cb87afd1d69eca37f4dca02c319c3f83f65cb12aad441f8cb92e48ae789626b3662158148a61d8bad4b265df2fdb03730b947f5e542d9ef319e271fa27e598d39c9e6b645b610f96836ddc5523263a98f901f9b47e3046fe324702732a62206fcaf7373df7d987d236574b8b66bff55518ee403ed9e9763e366c26bf3ae47c8f1be461bcc6dedf549b3ea7d5649b5d7bbcbcbbbbeeda04218b861044f3115b684cd82a71be509345ffef5d5326071c4c63d119e86ff38 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420e3b41f283a3ef951ad52a3dd58c46db1518442328f512485699894018fa1ab54efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = 0d0547eee5ac01f37f29f03aadcfa560adbd5b02b5182d23cf9787cde745dbfb228295b7724b508068bc4aee49d3159963779036a1b916035e59f566778c22d0a4fc2be808116ce6066f863c57c00d7c59b38176aa4480a0f63f39bc0dff24b4397cf1c9ce85beec02498c6cff1cf4d23778160af842d3c3404f3c17d227496f -S = 8b3380702deaf0e22ef08ca6c3c9e68616de1359a1cfd5f03968148a837f11f15474046c6434aa2a69005855ca945556c04ec3b57daccb2605683474eeae4fffeb19c221ee5c61b54b0914dc0ae7253d72e6d73b669f52651ff2d25e513e565d3648e6d5eeee63891ace75b924a2143dda487d8076174784165b105663719273ea6b42209ec456bf1f433b117e02e6a5bb35e285618cabebf49a8fbdf046b05bbd37020dece2afd1f6c9bd2fc804ba09bdb0d8aa7af0de45b7ff616d051106f6727415a460a62983817e373474666dcc8260a3ebfd59341f01990e6d8b7d15092c3d7dedc2d4190d75374d138bb414610834d48c9bc23c43d1ea96c7e9294a2d803c26a427e4a2b5f86f19bc7d10da9aaee219291c94d7a3052211f6c5b739168e544747b8090705a63671df1ba7a82d8cc5e76b5475acae66455fe377cf52156549d7431191573f60ffdd24d6640610f4515e3801a526d49fefc2d1b59456e3337485cab9955afada0ad5e33deba6944d98b24c24731acc54b78ea1cd2808fa -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = 9802b7acc01de6de29215e2878ea1ddec20fefe95963e56ce5c203a7b60a391b586795ee68d4b692a7de84a24dab1e0ca03c1475c4efd7d9d5486d7233f069dc1dfe1b768276040b130f8cb29d3af8f2965f962af66a3a304886ee390028e6f90f50b20bb50cb792963de021119d91d8cd01ddd094dcf8ba6505efc2c4ba96ba -S = 99e39af2014f011fbb413ec25a428af8ee4bf6f2adb3fd20964d551ad8355c46cdfe35c955cff611d299f533852288ad20b901d80e048ca80eb3cacd83e638e15953413e3018076e91b1064b2c0d615c8bd6b9098f7e3b6da919470636135b926c97124e943e987355c6d71d683136c8fa9698f15c0ed3abf9ab7f03f5e565f1f1b1b056d7d1ecbbd1d7afc5a45bce19984c8ff9a92437d832f89f0cfc5700d18482c4d63376fdbb851ba2a1f272df06718faaba2e9e1c8ee1bd3a3aca58a02aad3437f89fbfbea5f12b8ebc336b8dc942058c80e099c60ed6ca6ce128faec8343aede16c44ea97e1ac1073e24f5499772b8abdad9c8c33922bcdac1068715c74f4822b4e9109a8020270997db56299052f14132a1d7b19820e380ea74a68236de72be5d33f4e89c5fed4ca643f6ed7a3f505aad27a22b6ff694597c883896fffba2ef4fe81cf44cfe342ed6fa127cf31c58a16a5a35919cf2cc3adb47c6c84f660bd9e2dcc4b8b29beaef329affd4b5cff2c59cebaf3648624485c4cf94e9ec -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d060960864801650304020205000430825058944465183ce7f88365fe96cbadd70cebade9f1469771f0a1bb5ef6e86c4e3e35d2a34393aad10183ead0436783efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = b438d4fd3a46058f4eecae06d9bf1d43c54eb5ebb504446bf350903aa902335e55f9a93277fba8668ce4af474003e241e0c115a20e8327a0b8d2919e4bba3eab236f9e4c4737f67b5383faefb55f9d9e1c0d28812eed89977aa1ee2cad6d935b08e4d8d211c197d58913b4869f9df663637c15107d0a14571f03d06d38e6da76 -S = efe705f492c2f05595143b7d2fede01de8d4ed8aa6730d5db7540d9353bdce15cad57eef7e66e98a0fc3d34e223be094c5f60dedb8c89f5c3e4f6b10f5d41415e098741bcd4324558655b215217582daebfd44d2154748a707d2219f68a1e9d97a75900329dfc0d7a28b1929775bd37fb66524945b6b86635dba4f2e7a95da17301a1522effe0728edf148e7007810ad509d8d541e6520b83247052e9e79a84746f11f469eb4db1446f5dce3519f09d8b4f154b0f3c403d23a37e89aa68683027b76fcbdf373496216aeda698b2fb8785e364bf2bd2449277c0d8420ceb2c157f8663a35c02f1c4a4aa86c7753ed755e60c022a4bb3106da295f3a2a72f2c861c619b8726f1749b9bae639589b72e9e34eb9176608f2a38daee1329de2f28291216b8c77a7409eb5c1d7e351e906f1f25a26c6df4abf3038658f7cdcfa3e1fd611efb4cc6c5167c4f76e2100d02612e12d2e696c80ce977e7a150e477ae0b67af577a62a6b57e6bfb9ce19f56979008076c73f018e5479de5c69bf1ebf5aca53 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = fc06f66ce9cb46deaf65f79666dcfa90b09d1e2fecd7e2caac268767696f6ac6760b91a233278433836a5ef780d923b26df854b4eb32c15a707b9fd7f634da34f04fad9682b36fc0f1e2b0d859d9846e9e381fbaa4a2a225c367350c756056c0521b70d13f38b08ce21314c259a4c5cb2ba3a6cb7eef2d348b30728c50bb8571 -S = 6106401f71a67b9b68fedb23595f45492fc7eec4557a00a5638aae54d3854dbd87d2f66eb94cea8c02f466a85983a37fd202ccad8892eee14e3301fc132c530b36b31383739ed7a51433e90cb7ccf1c17a0a512d249e70a3d51b7dda16680946872856e5901c726d3bf2af49fc264c3c6a373d9135e802a8ca37ba891c9e13c21dea83ddd6c55c25867872e18c0a726d5fe6dd3d6ddddfa0cff7246a63dd38cbd738945afbb3be72c55cc2ef38f56d596619970312d93a9322098601193d1dd537e1041b46e8ab5d67b40a069b4153d365742a32ff81defb4fd00782695b81b124959d33c29e88a1d911c4da17dc32d41c1b5f1836ae1654d56feb9a55a488a2a97a92ddfd9c754713309f661739cb2baef671bf41a3e74452690e0131bd3a3675316d296d696b0f07a50516897043a5b2f090bbb618d822245f5fa5aa7125551aa988ffb289e8804bd5149cc8ff372496a5071ae7f8583a8755effea0c6599116ae5b8a3f94ef2f4e6d440c9304d6a091ebf14fcd8700ad5367a21e6e8105ed -SaltVal = 00 -Result = P - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = c2fd970b5b17cd1a58dc8423f1354f7feb5fc86a609c7b59c229ff8e1d6f66e99c7dd8014fb67a732bc7947a53ddf4c096148d743832649df595adae436a305ad820f2a96c1c124cc0aff12edf45954ba3df50c57cc39c346d714a3e57dadc697acd2f2c39b25d4c1d7ae1661dd6fcc71da75884b4b6ecc832a61f68e22730bd -S = 861383c21c18f931fc4fb352d846e725e39cc117c4324952344cd007b6a00ccf08fc79048545fab5c30fb356460d5af25a63f83871dea84d464ce4179cbe5e6fd09a384c45ad046101a9460238eb3f445e8911970cb9c43d096f70b78f3434cca05cbf8ee861f6bb6cee9e123a24cbf6ebc5021d3a9a55c7ff08c6bb274a7736f34fa7c04029c246f2c70751e51a4607484ec87e816a3a5c92c06a10f512709fc4365a7c80941109b1cba4dd7ee79d4c3f851a32763807425e5b7583d49e97f337f270e6387f99dd21d62c9db52406d3376a5e549782625813634a8fd237e7ac477355f4be7e05e2a9c3cde9ede554026ffe1ac3e8f545a4d49ad39c2aee4b52c45440983f25c276ed58ea5fac719c5332655113dd768d93311cb6dbff54357f40c23b4bb9c20c7bf0525150e71e17e486eaec90d2263c9758447bc02739a14cb7c3e60cf376b9326a861951d6d38ee291e59219757a9de264cfdbd4b4601b8413161b927daff25504e0361f6669af8cea75f35969c910c3c5e1890597931164 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = cf28960fc5ef7fd91e051ca12516ba961ce953d48492fb3598e97a6a1b3a3b4b533e656c564a47f184c7f9a355e240435584b31e6c851ce1631d21afa49b24714159676d38ef741bf6a7bc3319317e0b7a98ea206b7587f23d63d21606b22886a060e53bf544cefe7a8dac7bfa6b3a97950c410308ca02112fa3d4c7c8e90e33 -S = defe54ece1df4a9e2f9b2ec712b2047be979113674458c3e1409777a8c568bf43b4455fd4197ab42fc514e3595cec0d46f3302cf556889820e1c9cfd38c642ea09adefa815727b6c06b2a194e095f2696e35f3611c19129a86bf60b11799b6587bef89082a631cbea67fc4d77c7dc998afb8caae59e7a63a5792cbaddfad6e3bf8a0d0fee650b7a9cd502211dac3743642075a2a563ee20c05393992c776869a6eb4a206de21e72ec27be193537a32dfa65831bd13c66f6aeb2bcb6239ef31b2d7e8deb309be4f639c7ef9d3e6147e15a8a9dbace13315a3267bc4ad07ce02575a8b279b37646b871b33ddce57a8170c422474c2aa5bfd5323288753628562f0afc715576c027f7f125793dbbfce3fbaf79fc032bcd9214983fddf1d3a083819399c107e2913de535dfbfb267cd0e0602d6836a902c6589bd1f35dc07146c166d26592d8d52fca9a82340c0da7303602531f8144aa1f704e66380e07fe3c54e13b1361a427531a399616b4ce74ee9633347dd29112e180c5ed263c0153f3500a -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d0609608648016503040202050004307d7ca11cef0aa9200c55b78df8c91c41266ce955d1fb2622cd36ec797f3ddf70eff54c77a2904cfcb282cce545a31094 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = 835eab9bf266d49ac4c672c5765511461a3261dd04ab8bddc75ec577609e253ab019b2db30b7c132e0c57f868052ca0a03d945a74121abfcec6263a4c5a955b70f7dfd9344c3bddc08df78c15b1c5c81124eff2e88b6aeb29125020faf64b3eb89d4b14b9852719f245d85ff6f7b70b430d8b8fa42313d049ef0c8418799e7de -S = 7f96dcefcdd212f01c585dc3bdb38f3168eed84c77eba3d9c5e052cf84fb059974ea282c5d5a4773e13f4d23206c3ef731dbada06ccb827a75c4002a267554f2d2290e2cc23791f8db52aaffc7e2af981f9ea55d8eeb9abcaf379cc47dfa54d28b59686e737e2e4c3a4c9039ddfe637dff0f1ae77ad9fbab078ab9a81259785880890fbb32c70301877b6f53591862f45463bc7c25da257b8fc798f7d3d115d6a7b2228543b81e768516d8f29f645165c1378623c3e32dc6ca08c452665038db2ef5ee432857e60eec20c6ba75981833cb78c8cbd18bc3243d4959ed8ea4e5cc3102e1180530fde85e837188e029717a6c9444265d5bf297b44bcce7367e3579f09928e97257f48f935a869b72c53be1d3eab08dd10cbff54bb099d2e9a2d3ea9acaadd2c2e7c0ab89f58d265941eae9b1bd31d544c4baa8132859869284154b7f9b99fc98cecf104473437cd6960a768f044a655034403896cafa00fd89b9968097d2cfc90215fb1b6e068c0cd6224aa5f73013e1cddedfa80d3dbdc0bde0b7 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d06096086480165030402030500044092c353394e0845afea273cc4747df99a1d7a0474ab8902f073a0c432a27adbc8398de33e7d5b73c3cb4df25e6067981f237b11f009d9c1e547af65322d32905d -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = 62440e53c9081680b721630cf3071ed102fe0ccef99906c98f7ca93876654e62ec6e3cc28d8c1dac6b5caf33601fbc49a3024c289aa419f1efd24393e69545efee6e283a76e0f7a2012f72347d6806fdd0a1fd6fb582f307c604892dd9795d5c90cd39822c0b8aaaa22214d8f1eae534b262876bf13c7a533b9be1cef81b7cf0 -S = 646d7a66aea8b4a22f75881e6647ba0f207bd5cd15e019468138fd126e1c7f660a97aa55634646cd8e5e584b6bc29a4cd213cf222657ff6526b7e0ecfaf56c0a90ec4f17a297b0f8523bdf39cc612757867272409c65e8b2eb463cb134560d021f60a81ff4eb08aa97cbd6c07cc3b32422442724029be186995c2694ee4def6009a7a1a8b3c9eea48d634ab3b84c0c9566ede4eddcc5e59338ba5aa304502c637f9ecd0b707e841d0b7befddef4fe0875809fe386122882ab02e9d06af3b9953d8416cee296decddc3b2e36329434f567d57330c418624c5a70cf7611552fc2fb420af0ab0ea2c6ca4b19a0854e6db10662a7fdaea3c015e53524617cc29afb9cfa9065e1065d95d288f395402667caf80d7b4a3a91f5b681ff10518e5c01ddf0f20c359ebcce526091164d5718cb49b9a42bbb57361865384e8e2e162abd7629b1fd242892d5164c012dc07650c70cee79a2ccd13f424b574eb1f6cef662cde18302038bad6e100a4e7b949b9f1a87de5a2d6352ab830be1138d9b83c4f8992 -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = 7c38bdb32ddcea204a99b5f953ff3d6e0adbefcdd40804f661884a0f8fd328798c6fdc023bc1085cda236dcee137f6292d7af8fe5d1cb80e7d0f2e02e25e085c54c0f2ae736d15095330ddb96abd002fac46bc3ff449608ca6ac0d40920bbe001c51861f9a851911fee78e23b53c636acf66c2f95f370257258771316a84514b -S = 0d07f7c0cbe4a84df3fc088750c9c503ecdba6c37a72ffb15a2da05b5c99740c894427cbcd6cb2c8ee70f35175e70f226c466761356e07009ca88752ae2cff5d7b2e7f2da77a36b68de59db7f5182abe88cb95b52d766d721b5fec504f6aa7b9ceaa9dca1241a5819d4d48ede38c045d625442b27b8384dab964616885cbfca944a747f024032da7b3a3fce0b02254e08c8b9e48646407e69aa317df5706888fc13f091602e1affc23f17cd50ef4275e321a102c2b066975ee8a0dd3111cb0e88037ba98ba477ec67737024ae92edcd7d944bfe2863336a59026052bbf2280d542db1cc70f06a9509805db6651f795b0b4d74f94fbb06d2d4149321f9334f5fdba395cd852e46ff2ffecd063a96ce5d2d5b15cc075c243b30be7a260fcd6891ee3063fe3898037c79309fa043fe210974a1ed96c14bd0f0db1055f710367e55d702ef3a9bdb9215368407312dd415f420bf0a90f67c53c9474219f36adee08220b0798d14c455e57ee8ee47f2b8c7eaf8d5f8474a9d2f51d49a785ed4626407c -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffff003051300d060960864801650304020305000440a780cdcf06d5af7e658c9a0afab551db2fe1c5d86b54dfab86d5c10acffe37c4c8ef7b65dc13a26c2330ad19d34f1065d99ce4376e6b9886cf30792e9430de25efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = df8787cd9718e6bde708b9998cad4e91c7d58afc60b719efeb2ac80f4a152ea3732792ee74c809bbb44fdf397b753809b409f796f2e6dfa5b223f82de08935689c4a532a3def047296934d3e794f2da47af57f1ff501212753cc5604880369e3e058942afc771f09173ccc518f23738aa000ea4072f0279d568fa93d4c6b143d -S = 8407b86a4d3715092fcb38c7d55a528182cd6cd94186a86cc654bec9be3d472ba908d5288c1393619f1a4ea1322ae01d47f321a414d0cb1e00fa37c71364319b2e3f6935f00f0b5518806e8c21504b2784f14c739d186df08091139a911d7c8612b4ec15f17ea9f069898f4f820c9b8aeb5ea34aad293637c532c47b9a258d633614afb0cacc5ca475fd4d3e24fd25809df22f14c20289a7808806cacce46eba40d33f3392e72ce6316ce02866955ffe0558510b26c303c37c773f387d93739b77e053d896f078d0487cc4085712e2e5b42a6031e3d01808e94b8219304a6756233dbab0a2f133d088e67a2cd4392f4d688bf4f4ac4ee9a3a099f7389c5d8ac5f09f55cd831cee52306727581792455ff2fba50592a7b2b686fe4e7444866a2ff69cdd68895f84a1f9864b7f36c6ae89853adc517fe8b9a8fdfdc78ba03f91dc582dea4fd387858ff90dbcf9cf3878632b5b8448e19a797485ad4bb9d2c28b1e7ac717ffd4639617d4d4ebd44a556561fbef00e66b99c5ada41bfccab314aa06 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = a24b2fc765c9953c545043a7ee2edf6c1887925c6f5301d9dba67f3a67348071501451ea5bc407b76c6eb6eb5569e343ec033b0c607e8540cd58d5f30dd002edd2a55b99f121961e015609cb25a81db8268bffaac58e98384f99c02c7172ae2c4e86b39acfe729b83a91a61007f17513efa84600458c240789efa8af3b256c75 -S = 960d6a156414272675d2c09a340d9e053e96e8ba3737ebb8a11d4829ec9287e6997594549cfe6e7f60018074a90d1e89272672f4a464d969ddf7b634a34c36d15b16c542911ddc2805bde86b5716b8c8e9e2dd81133ae4d70469803dda409e8e8f6c0ae0785652528c02f49732c4d2dd6a33bdf93c17ce851e8d3d7ded4636d63f34f4fb2e43531bc61d2dce3f60cf2e521cd5cd7a5f19c35fb0bad328975676fd7958bdc7a957d0c1ea3a30f9141a39b67e101c9e9832cfa63b4b09568d5d13f50ad24af42d4fa9b6a0c3fd95be4a4d7efbe2a89fb7d675054fd5630c120e48af7b7caee23fe5ba2dfeeadb31aca63fcc729e4cb352315cd06f8e62e9b727b9a8b8ee179c69afd09b4d5cf5a8ddb281607374a526d462d40ed43e9197d871485fe84f8b07ae7ff7bb411d128b9a63cde123945201873f5f257ebee48b0bd68c3486352530819f0b01330217e4acf76e43f676e33bc803cd11cca82d7d0cc0e7c14b58c65300a877b443bef4e75d3ae079e13b4719d2993dcd3f90d234956b99 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 04c4f6f1fab0aceabd3acb55e65cde8e827e671e60339af201352d1c2c1677758dd2b42e54e8f7cca6c1e6038e47b7603086561db3aeb25d73e7bfc8a5ca27042df99119d7f5ade9b8d3a03ebde5783e915334d460cd1a7dad1bd0285b454150248ceeb366dcbcca68a14e7cf660dec0280f59f27ef0334ff4eb5e2e104fa6f7d3a13f312740a3ba0afe61dcc5338b1c3256d81b7a722c2453edd8f5314e30ebaab9fb5ff157f8b37e1c4245d72d82f0c53532c39dc891b4342682f1c9a8434b3cdc5da460b174c948fa20fa960e53735f4c9bb7ee77ae0db7a9d0082bf3b2b5d80ccff914256809abc88c697d3ce0346455be8cde06d5920f74fe841d94bed59dce7f2b96e5d708432a56ac6409563c93a3a8ffe3c1cf9daebb9bb77405b551b13a40b253a819a3aa0164cda1979bb859c2f63da926cbaf3701e30efbe721ffaaa3317e4233d51628427679cb0c46556ff2cd4d6f3fb1a647695edd7601378daf8b27b7f0b3836586b9fb1d30666c06f494d0f62ca96b7bf0f6bce76395a009 -Msg = d8b0d39a21a7b7d11541c35ba83329b6320896e86f165a13cab1c94adb9ee1a32eca2d8d463ce864e14966437e07b01a1d046f0046370bca4c3613dcd3aae03f900075f45062aa883ce68ae95b05f978584e9a5f865bef252105c280d7d4c46a86b9757648004365ad80f6f447154bf96c50dfae376c4f4dd0849edded04d74b -S = 2b5652f5be8741b03959eb713e46299a62ed69bc11c1e774c3683af9494e7bb8e51bc4e4d8de1e65fabcf1b4995ff065612fb5cd1812ac7a2c1a0aca8d76c66a3dbea40f426d55a6d60572ae28d3444f059ac714b79e9cb1b9bf443315b85e872a4e20fc69ea1b89c01398b1dd528de6410b48c141b1f7e70ac888393b81b20a8fd6add6ce8a423f4f8e57c6860cdac522349b9215e0c1b25c78a7d94852cdadd5e3f0a4baf2975b60a17cb0e3b9c79060b4ea0eaa153e1500cc05c283ac300e3da7b91aecbb10a50e86a1ed74120a0770d0608893fe6eadee193a20d920291c71df799e620aae96b263f4567962fcfaab4caaa4f06d9d0052a5e2ed8c2f62328a973e2f39568507f6445c7e883e81858df862804c419e3ee5c6bab1832521e841da32bac64a4d89400a2f7d447796f441d3784df53187305fab96ea4faef0cb1229cabdb8cf07c9177b8ebd977c4ed6f260a9b9e97d5d4918cb0370e71ca008db73913f2d519b99b376575a808761dd144d74fd8a7b68f38d5021f8b0533e41 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -n = cf92efc93d89c560e4cff3e81fb72672bf010ae82335c342ed80c0eace8fd0333470dfe2d327f9ebe0ede4f39b0260144d1ec783dffda1f883c0a41cd21e9244d1ab2e4869d765c7e1506e5c1be03db067be54e887daaa13e0d5122e872373891a0480c56d8ced157d316a8ec314bb9f15fa49c0ffc0d78f913ec2dcf354bcfdae2bc031febc69c4fe9c51c05dcec9c1d3004dc8a9c62234d91e4dbd5f9455d94814bd6feef8697efdd9c93af4a9b1ca2e9023109905242eb82977bb4866a81220f8232558af67296b34a19b818e5c07ba53b6e4b270ccf67cc7149c79bf875fff248f4f6f86fa4e9a10dfc162b4c4accbd5f76e4afc89c5339a35f960c7e5d156058bde8c9a49aceb5fea67a09325348a8d573e304e9d133f77913c785e5725d615432d6a258dd4038011a7e19369de19878e945e9d4191148550bdbe5bc22aab57703dc880c3bc08c2df1327ebbf5bb9c2e75082e998dc48685511958c4e7b895dd6be533ffe84d5aee6511480e6547b89144136b8aa41c6942c00f5ed42b7 - -p = ea7777733c9695e5bfc71a4de384aa8d9556b620f13d50a4b3523d95efab4c5c037fe788c98ae85b11b3ae884eed6f3b8f5bcf5ab1b7b20ad3f44f760b2287cc57937487d73c44f4395d48ef746548eeb9101a42a6d27299be78fcc6160da8c550fa46f9cd7252b91f0d110bbdb3ddaffbbcbc60395538565a266b0f78325a4fd5fe846615f5bab1ab0b306392a1d5853da8e03cd00aab4b9045c5d898594373cfe55654169f1c7eb22dc87c7497db4a729b27ab95cccbc4f44bb8a51c0bbba7 - -q = e2a332843df5531bcd8a06e30e3cd414e9a201b2e27b610f944f6d915a5396b5508eda547a3a9425426d988428f87f71b58f40dcb02b012095ad2ccd43c4c4aaf510fafa7388fbff8a190dbdb98fda002db90ba0f0c819045df960e5d7747654ba73baff92a630b08bd78c1629ca8cc839678b87081a54c3d27b34617d2a53bc87fd43ea3e5eda402fee3d18e06f3ed1c2e0e81861e95766de7aceca9fb003e945f8bd43de9f1edc154241f926e5c761109fa4e9cb359ac778f0c6f748fae271 - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = b04cbe36549d4a58dd6ecf23afa174b2c45b9f664d14b8939cea3178403bc3757272fa78b021f3b9a75165a75616de2171664fea032acb5758968c4b1ab63765ba4a607811d4513c48ef0743f5e27e2e86752f20e304d6734fd178aa8f9ea5a74f7cfb1fc1deeb4a87f1c0dfd330dc3fcd3345f035c7614e4944fe7de91b95a2 -S = a4d1579f4732ce97ffaf6852183ec36900945fd9283be8bc50a1dcf81e8c4f277d5aacec934a5fb6951f97efb5636986e06ba302e964d118cedb83fb6a308772dff6d77080ad390ea8e8f401f5e2ab4feffa25559e699e49ce08004b15c49a7915f28099aeebfcbb3d22426a51caa71097fc5fbccf0cef1610c17cfe76587cea2f6a04cb7893394a736fe2d9b4b72093c5109b086b6f2301b7dc7bbab0cde72828407175946cc275d17da0fc63da6159492d70a341613971926be6623b262df63f1b9c9e9917622f365ecae401123baf3e33c2dc04555804e2b6b3dc14ca263121a510ee44c9a4602c005956f1d41e0b6c68ad78200fef0ccaf8ed668239e196c55e11fa57ce96bf8457baa139db776a43b98951b500850170bb57ec17cf796bfa73799d48b24da7fc85f828a6c1287459735b34148ccf84de1379bd2c13b8cff140ce6f8140b8cb8326374def23122b1fe8f015d6b62be5d99a04e62c88e3f611414ccca66193fa31a51cbe9c88d85c9b3bf6802ae24f4f4263a7b92251a82c -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = feb972fee487cdd8d18f8a681042624f51dfa8639f96dcf693ee7e5cc76420a78e54bfb5e21d536d9e81a545ee4a610703336cd60b05776c6001d5a5ff7e89413dd3a4e5b577ce648567223dbac83f6508ce9b46bfdc1b07faede10e193266c372fcc89744dd6546ec0aa8585c0423eec878debba263ef51c9794b9efec8dcb6 -S = 879feb8b92579291f651e8b476d5414e46ebfba0c85b4907a7479d5327c6f582356ac2fd6dd59414b9df5a465a24cefdc39f19c6e814545745710c9098d15385c7823996cb6509c20e359dba1fa6bfd5e22b41aae1a8de26aff1c26427033f6b3d7f4f8c28a3e398c52c8e5221785f4926b9230eefa264b1684d598310a6e09919409e34a693f3c508aae0d861867fa680f0712a1b7019c850b00216ad194e80357a06a995c9da2bbd9f2189f939b228e5487ac83318def7dbe3752c656653517e475764b375f54a26f848e697aece0acba9cc3b722d37fbcfecb40b5a2b7adde54f02f9fa0cf3b2769ed2d4f81879822e01a289cb9b632e15a9ea45e09e962ee27964992f3a406ac9c72d3d0f97563e8296df97d7ca6383e6643d0b499896768846023f901ee0397b229ccdb706701ad048a7d7f17c52b46fd9288c4a6f5d47c0fd6fb55ff74299ef8b3e1b4c2d72af4c24876b6f68bf7ec74359ffff8461f9a9893c9157e0f022e0453dbb87515d71d64178044048c6e161e6730e23e79973 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414da0d47de632ee4adb50d8031bed0027c846d752b -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 08511714a11c3770946e03091a2826e5efaec9a10f9870c0bdab1e42ca07c07814a1c8184df4198dfef42390cb444ffcf8a89dde2cbd8bcc75e83a798d8ccc865c80109abdc061b48562cbc0c2cc706940252a2f520972b9ce81816c5a32b43ce6d435c27ae6d88f32a043c1872a52d4cf0bbaba07e4ec2dd15e3c44b9614244 -S = 136b4e04197fdc938eff67044168e7dc31ff57b7885d9b41df0d3efd5251a5f91e641b73cfc7732ed326519773c6cc77648f2db4ccd056d52f7314e3f3009eed7f2120155a3566a307cf268adb6c004d435957370dfe06570d626c75db422915e34aa53707ab99998c6d8c0978c0dff28585f628a5077873465b6372bc24a9374fc6edbfbb8cf8833e51cd0cd9df4d3edf0a59a531811599666a2617cea298476300de1fe3e12e45a861f28e66982ef0dd41674276779a92ff9307eeae1159e2526641cd18eab80b43a83deacb075e60864804d9da39eb1cedab591906d4b428af9ae9451c06e6a3b90fb3999808a93c883ac59f80b4d1e3a32a824d1affbfe6332c7527745bf8272ca22bdd508822a655e0e4346343233e1068bdbb866eb512bc47abdd8ac777a2b93e12809e8576b898f97a341621a1fed89db77449b590344e8147d0e81beaad44f74abfef11181c6ec161e96045ee3d0f7dc96c53c6baf7dbc385dbce0d6a054970987b392db1f237778dfb667ae9a4f7133c3d49e78e30 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 5f474c3407a08ec87ce50ba52183d2b605d61768ace41d03134c593aee79d401341bd19eddd8b003eb3e125ba7fd3ee32d53c3fb2ac75f7de51a204d7c7bc93170fa77e3643f8465227cac95dfa06e01c0ceb5fc9d0db8f204411ff8815a67a71ccb872b243dd4972b85227b52d42cb9c72e36948b1ef00a79a79e64847d760b -S = 65e8cec81b96a92cabcd2acf178afd01ea7ac429634804dab05faca839e1dead2387a4a4c702863bd0522c3a6847960f604bceaa5b56cc78f1ccc535e9c387c70f929bdfb564da2c4f8653b74065affa5c754ad6ffb1be0e02918b1e066f14e5abf499b75d176106ac67b6d2ea954eee902afc8816e5c9b143a6820c4ee4c8ab76fc20442bde40a0dcca8f64de6955df646e3790074ae0d11501242d6499022eb9597eb39ae68f52152f71e5b1500ccdf46dc8909dbae8ac5869d21ef30029b0bb3881df988161b7dd3f80d9f0a9631ec6e95a33e02f2e3e736c086ba17d7f803ce670ea9186be3da26e552d656aa915b5f0aa0fd80e32f318670ee05d0a52a8ddf56bdfdcf1f413b66f4d3173b8f6dfbf8e2434c467f6c340b93e597c1cb2f114e103d7c03973c6d10fb357b5ec91e47f03cb6a794f8b4c3eaa6b2be6ea9a3fd34417373aadddcd9dccdb95fc71a639ea99e0641d5aeb63d59477b8b8629a4012e35a3e167ef445b085403018f7a2c731b88dbb843c3cfca5c367d29dae8346 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a050004140221cce979dddc3f07b69ad9575641e343384e9defefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 23adfc8012add4adaac91852a169e42d92552d70b56ca413ed98dd6e0901b1074381e1a90d59fbb60e2282bd6706494f3a2f200f6d80b209ab83ae45aca3259bb79c34c8652fe2c2a71a4b490a47ffbf3a44a539c5f3e4d622838350f29eced085e43c07a099507a7e9abd1d1496cd249a7a0316462d00235b7ea3b7625b744f -S = c789f344e0f4e0c291bee6336b3d7d2314b0fa847970df318ea8ebba2de399914ccdd085ca5c48913ebe9851a29e40545db646d958b9370e0c59b249119b67efb26cd864e226b289c62edda506560ae976f764d575515483bd13093b28ee85d4ea62fde932d0a77dbd81c971e7f4386fb79c7f4fde362df166255e05bac5289d8f74562be2daf26513472f472b68828b402c4570a5cb8fb027518a29c3c78a35a9fae810aa6aa2bf0333850d6f71eef951c4c7f315f00be29682121e471cb8fd05b556e995d96e51d4d56f0369abacf234d19e43e737467c14e82e05732d521276b81d8a75eae5a096692ded6f5b56fdd22b719a3541ff98dca661778c25f6188c756543bca8b8ef5a29bd801826fa613b349cc24e69ff4017805e181fcfbd8e947a3d38400fea81a18cb8c151a304e6e39c0e86b57ee0d0b1acd7c052ed94818cad2a6e75de2bc7c46fa9ffd9d37b9ce05ca53cdce91ae58bddafd5fc626ae71073b1efa0015cc9df589ae73cda5563f60774fd559e565250af8b9f2834d2d2 -SaltVal = 00 -Result = P - -SHAAlg = SHA1 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 94f581408cfaecd499c20c50ce61b30fb294b95bf1a84c79529788e7e97547e18e0a3b298ec13a08a0c1d8901a593b2564a12b3cad5e6961de27427fccc6635cb2e1ef63dedacfa6aaf34a23aeb6d54634942cb0eccca137e28eb42eac60e5e6e8c2c674e60d54b5a1a18790f43f287b0ab4e34117b89d024515087bf20c7487 -S = 2e43df8eca870c60a75965eccf79952b6251f216e8ab745226963ba9200b8ba9a99f9093a5b3df5f64e496b73b8ce077b76f4badae288c3e979796f88049ff2ff7cc0401b0f31c48487d01b4ce4854c4f5afb9cdf7b10ca196b665efefe4be742b2db236a379660170c3f684ab76b69de13a3053c403e8e14394379a0e1a6b6ea6ec501e95c17d6c7c728e08315777d29cbafa972d483d7e7ff5d9b97a8c7606300a03e57b92cf727cbcb6f14ae3c22ff2d417481ffc180a378e4fb1a72efeca8231b5fcba6b1561659d8ad96dde28a2f4360ddfce2c598428012abb2ea530b3dcfebab4e3b550cea5894deff740ace9ef4bfd42337cb2d186d2cd05a27e35d37e04093ffc0751f80ca4ac2c3b197c9cc60756029ee0febdbff2c9cd69cd0423a37fe4560a1f8805ce591455dbe56bef0cf8616901f682bfcc1b58049fc8e3ba40f28611822413b1a04d5ead7bf3cf0ecd94ef6bfd4716f1b1c4d82f70ba8e71de91f84b804512dc037bc17a3de87a74e8c37ee921e2c1a03e7cc9768e3059dc -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 2456ef08c07fc1ec469aa9c73b677af225a9f5f6f8d0e150d1d65e71e6677609bd44f5859de97ad6436ecf75d5ab76a41c9f84f6ed13b311e87ab2b3661cbff3ac7378ca65d5eed14f54fc4c34e3d7681cbae5c1c1fbd3274395e2a21d6881b358ab21ddfe8b4564d215d8553e56c4c68dc1c05f5ad1691a48ef9546f495e4d2 -S = 0631ccf756acdd39dcf45947556f56418b598b25512f9851ecc826e8e15ef8312b12896c5046736df8c36c1e80d43abf9dadfdecdaf48b6a79a09200008695e2c7469c837edce5bcc6c86506908be7942dc6e498f9806a921180cd0b997211afa495d1de016a1b98ba5aad0ef0b0b1f1ac7c8dd5feaa44ae69f8edd6fbe7a4b196ff96077090d2bcc05a675bccec3ab7d3b6b63adbd97626494e57d03ccec82a4ebeb2641b07228de82ce892e24df312f2df624235b00495b444232c205a5001c0db68c06ef7112c8427ae0d563b53b16f9fb1bef64e59cac4694884204f3cf3022ee2471c158e70ffd552ccd582f92eaacbcda5a43d4e4d4b2e72b2193e34b03b9ffbd47da3c0482593440910dfc334d74fc1d0dc11e74210fd31fcdccb7ca2d01931ea6c75faf1f7a32c8115b0661ee1e3457090b97cd35ae36d34b06da17c047e785a5da9d23c048dea4c766849792ae07ec95ffea56686fffd71fba54d44fe8e3d2dbe742a97acdbd7d54fe3a78d08bee547664a0f1dd1544b509b5d12fb -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 29fd9ed0a8ca9609d8e67edcffcbf733f15581633c2449b1a2414115cc04763e3c359fd58471f106b5cf3b3d1bc42e2d2744fc17ad2a264950da8ee53a25d4e3106ddf592409bafaedeaa2ddb57f5d8192d7cd0d9706c4dc4bc91a385a6dfd668bec89e4f25a98ee677fdc4637c62b35195619cd637ecc727d560c9996a39ace -S = 71265c24f74301a5c2cb797274c15af942ff4b98aad737596c4195fb698a69396cfb5e967359faa0f091931fd0ead53859ae16c1fb18b071b20dc0e8936b58a6dc8eadc773ab583525b1b9c01112c75acec69221d5a214eb2295a26ecd476ec37d8f2ff62f7dbb7452f306d3c4851b67a57fe3e6d7ff98489e47ec0768e3d701f13719f0d8f11281ca4fd6bc1dabed86c9d51fe187ba5a1d3187465e2181e4fc76cbc0ac42f287e9e4013dab1926e19d02bc5d7b84605111f5d2fd63229cc27d8a0e3378646d90a44726aa6f0a528e86a9b9ae709aec1a924400b67da5fc4d2cf307b810e66bca0120b659659882699994764d3eb992ea3521f40e8fde04af2f84e73e33ae5172f969b05e11f55872db50c1d0287bd331850025e3a62c25c26deec2605a4012c0c7ae8454e3c27ba299858930f3b384188c41b5302c83f9032e45bc9995f3ec5b3e5de246eb0bb791afa31523277c26a590fa67bbec78b7934d876f8a8ade9e12190411829625a845f0cfa48bfbcc0af544a8952d52eaedeafd -SaltVal = 00 -Result = P - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 092a5bc0943f3cf6a6295b47ebfa4c872f57f1a10c8a4040c6d246cf73fd6ca45f39fa78ae28d91b43329d65e11fc37090e5360443be1853b77ec0e79e24ffd8fdafa842d3334ff6fb2b50705311140a1e2c8f6fa7aa0d5128ee2f5fe92b3071ac326d06498825f196bc7d4f89f7c7bca1d503c78173a6a3dfca9b1f9c3b88d7 -S = 31e1288d0923e5de3feb553eff8781fcc91fd118f13e2c931e2ec8d3a102344e9f2069bcd3e9b863911013ce2e6e58948123435fdbaefa122e8393cd84abc653559b2958d643ed93431639123aac801ec52578b8e8250d21d32a7edcba7d639f890c3675f664db36fa859ee340d9c90d560b6e1b07a82811a0ac875e0061ac86ac352d33c1760c3ecaa86977efa971f415e3c4d878e5c4d6cedf865b048d78359c1b063713bc20f89a77962998f253920855f80cdfa21f54cbdafac23e259f6de785f8b298aa9e0363a4f098ac1136b036f40c8ccb87de2751ebe4bd4791be851537352b5e813fd1f82d3042853c44fdf645d47dccf149288ebd41b4a583a8887fb01ed1dc7cea237a53649f62a94e3e1724cd409eda8194d39c047b58c43b3210050ebfa39551a4d1128ae519ba23b20456f0d5ed259342f71e1a40d3b84a27afa1d26a1e4d3e365975e9e92c52802dbde13a239748b1644b528cd824c503e6dd4cb1d146cbf1d5a96e20c388bac4bea7b484c337c7b733ab6715bd92dcbc12 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c87593553a6906097c51fe2ef6f4de291844e6c083f4abcf7f2d581fb -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 729c6a3b890e20387db4ebdeaef7e1036a7e59af6da5952ba72ba55a402a874cda4d9311163d17cb595c3e07d0b6364eb13591f6c414ec3e2395cf9b3ef7d54c21a20d34faa69fe9d563b309ab898ecd9b44fee077b0f97182938187784bca94cf059f4e3d3002ba7a321389475933a8af1468138d6303ea4e8c81c6f810b04d -S = 31a04b5bb1588d4410472beaf2d6ff86d514c30456ef16df2e0b92dd9f26b7782aa0d363d1e3035546d7c91c6cfd05a21190f597103f3900ca12b51922eabbba0f9df47010efcd5394263987c7b79bf8df94ae0318aba4a14caaf791f4a0807bead368a129e201d466e9e70868471e2cad83324e1f70650a2e1d11d9aa539c98e29f1991226357e3585eaac9c856027aa3ac418fa72f00ab71738dd6baa3e8e8af0f30fb58c02f50c50bbd64b6dc1d693fd5d548ce2e0e0dad0ac2936cd3bd1c16ea2ffcd1d2fdc683aa5a0461158aa5e621ceebe36a705d4a2813e5a1b8adeb44718d1af3124849bbb3859db3f8114374c6680cc80222b214ee737744eaf1b7bd400345782fb4df6fdd9e4116714028886e250847e7455ec466465bddd55bc4f67e5ca6048e95653592c9d0bd689dc1ec88aa642f253568d3cc00d3bd719b90e8227c3a1a924f58a8ba5fa68e0b932bf3be5441e601a8466111c8ea6eca21039d8605244aa07952e6918291a2a58ed90f111ea075954cedb1967d4d80bd208f -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 1399504353d5ebc7064355b017edfefe97729cdd100720cb16bce8fd200136ff9668e19c2bac4afd6df392159a500a3cb68ceb19da2648c6cf98402fdcdc78bbdb2fc92f921535cf419d20c678e6bcc72be2c6f5085a700008329e9145ef54e90b766fc531169484aac9678b57b7fde91ffc933742ab80c2ea1368ed0441b3d0 -S = 19e0165b14491e2f84f6eb55f7d0e3bfa5ce45d20067a7809def939408a90b0cb60b3733081960a0917981a89c8907ba50622411958982b37554b40235c28bd478a06d0cfc3aa628c6685fb739a4f72cbd3fa6b6fca3b2e927a7a79fe2d6513ad8e04317ded8873e446eacc8e600380d450cfaddf32523ed7bd339f3f61638bdbbf80ea2cbaffc51b2e14aef079a491eaf55c7da79189327070e0c66daa906646095b2c0062850d9269a456bb13e632e5954208fa9d9a576bf14c958741f7e30372709c20a209d0fdfb0e18608a65f049565b25a77afb4a3d79a49e9fced249f6045d95c83f0ea4b8595288eb022620a1a6e6768239fc95867c575338514bb8d16f4595b6463a0bc576f1edb72c2cc4344b1000f43447207f2ca9049c86c6ec92f1f74b6811b65534808ef659af5e3f283a39b9921ab906a51a9043bc34dd023c54f2a682f0867bf543ac02b55a13920f8c5295b0aae650af71083f7562c84bad2bb0685b0d6101978ab5d789b88c3785d82a01f154795084b6e363235b10fec -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = c783252ef5e96363cb48e544342f0b82a98334cfa425d5a158cfc8339f3fe6cd3498d746220529c77c9fa0d14f91cd82d579e214eb12c5a6c511633fe14c471039216bf9bd164e4f00bd46dd32db18284ec8c6f89419a8133a7dbe4c5fe545bc40e88850ae65f984c06a806dc55413fd7c3887838882a6711edc81620152085b -S = 516e3483482b42a740c475678c4954ddeddca4f5d3cbb9474aa7fe7ade371f4ec09d497ad8f4bcc33f60dfefdbe3bb66268f5bf25eff3a6f4d58b2295c82dd977933e237fbb140f9c095bb31b091e0d8ce862a588a827a3ed7a0a6b407c534c37fe6e89b047042de8119db826edb202cbbd6188820371d7aaea860f08e23cf927fafcea8f398c3e189cdacbe458f3804131b6cb8f32bdea4c8e88dbab79b5493928a794aa125a102c2af675e8a1654489651214793bd7b8e86bb237f5fd19ba5c902986687e18390604a5fbe531cef3d1cda48c7dfefe053bb3142ba153256b1aacabee463dc63e7d74179e83101aed8e9c140f51ea45c94c9114f22d9ba63aef338b87c975f3453fccb06ded002477a073f40a4e3a42df7bb588a5aa830fbefa8c7f2bf363bfe43e236d25f8c0d0adab69e3b3b1ccc756a5e8edf180cc5ef3d18eaea6ae4d09e407a1783ee6a4a5505a90df31d310dd150e6aedb20bb97b2551e6e96223aac0b3484a6179498d1b4c2412090ad5a4d3dbc0fec1d11d8d0a813 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041caca1cfaac92548bc1743c2fbf38354db0247dc19de0004601b8c68cbefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 5c0231e10a12e268e08dbd3b86845a1907e6bf853552e12e482a68afc7e9b378acb61c0cc3397d6e53adf3d50036e1a7f07538a52d5af6634a3aedfc4a22c603bd6a45bd2c8dcf8db73829affda082293c19b4ffb9e5c7a76349b6bcb3e676f7d647355a0eb7e0ae5655e730456a448834f9bafaa3985ae0d97f4c58cbdfcc3a -S = 1d7b0e1ea89523699cb8ca51a9086043c1d3c4e2d0d0dc5e1a6f3688d318f7db0d2a5272f71915ee2439db175714b2c38e8c0b27264c8ee01bd1b292b66197e023f6b49dea082b469cd30289aa5b2079e6342789b1cbace05ce265e5fb1716947989e5ccbdf4779a37bd4b748ffc91c2944259ae2de9582334b6df1c839160e4e704cc8a771d371507a68c61f3a06c46a41e3aef02162e9f20c85ef51b3f15562d2b9a512ef0e81ad60f9934be2a2cf7e5f54813244d360148334c40fc8a2e65335bacac5b9a607d70d4296f56803de8c0840653ae2837a7e826dd4569896555395bc0d4262d9fc025f400859421bfa8cd5841a3375e22efc9c1538e78795e28b6eea359da14ca3c44ee30d16e7359b7d83d47b6744099c345ec60bf2fde687d0f81db3718d3a79e4ae86a0c3bb47ef0618342f103d6e6f7ba89d4a4a520b1a61b2d8d3c5f178a46166631b58921b7e0aeed15c175e85f76575b746359ea831f87c261695896125032d7ad4ad26014abfd7742d5396dc1516f46dd273cee88bc -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 70125f4abfb1179f8c2b4f4cc30386a6fbce13786050b848f0e27adbeb16b0fb849e5b77dd6ab56c32110dc35572d1fb5a9bed2893ea533cbf71db867e9f4e78081dbdad1ff7182b42fcfce52467cb845cbf02665efbc7e7aaeac2e043d22e6e635830f56d9f676423b4c4ba192a9cc96901fb39a9cd3cd11a13d6f222f77964 -S = a06c4d12aba140f9db9ae4dad7a507c241cfc073fe16cccb8e99c0793a0a605097a0538bb4849089473050ae1873fd369c2295dc98b5561f975a66d32caa6ebbf887428b163a9a0515a0f614f636e8e8a87993c11fb334195de25c3cc9103a9e01f5bf2b6b6bba1786b0ef02e17c9256aa8fc714fe5bd7c905e240c2dd120662ff4ed31c229df92e0c819ca384735235e5f817c9a844b733c4c125498ad5493d1651ef8833886d98b409b41709fd0d0c20b0c91c666cdd4443dc0aec4e3d9a844d28b40b36be972a99ceebe68b955fa699229bb393bb65f32f139cbc42b20be0481aca045f965ed2caca3d4f7802bac775fd0032967570d826361620b32a2f230600aabddaf976b1998c9a5ec545fec80522f16876c4fc77e0867867bfab4b167fbee839b83b7f5d647a902e3118a167b0a7c7fbbc31f23c8b9606429c66c46a3cd7498e14a94fb315360a1668025ee35bb49fa614250fefd9236b8d3be9bdb271f865b460910149449e7d22df7dee27db29aa123bc31915cded3def0249d2a3 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 29d9cfca7319f6e6ae00ba6de43e9f20e140ec7b45f76095d7dc21491c31f5932989b43cb58afeba72f229529ed87d7fd435a49729a25cac74636fb0eda5e5ddfa047854455048051291d0ced04819e7edf82d7defe5cf9dc11c69544ab346154452015a4cf33e8e35e5972ba217da20d4937175c0492131650ef87c5ce48001 -S = ac2b892951ec306c6fc6c0550d633819a2d4f073001665cbaa7eceb96972e7b0358fd49f1fddfefbe16cfdb78fa15e4174b5d3e398268da9eb23e6b7cd8bcb679079106f583390462850e44b23aaf0a59dc9780d0f3b15bb93368da8fdefb979b2220241af3e60e5c1e2bcf23e2e8657438cabc2ba22e4081889d94f2abcafca0dee1e81ef1c29d3164d86fb50d28ebcf89e362f9eda07cd85206b9351c6092d37f0cbd1765aa81c4e0e18bb01d204a3073e1b60fe67c6233862f1739f223cf79160154c138f01d4428e76980e0dd9c21e1a701d05a6e67acf7f257275b383e506bcdcd54a80fafe266e87eb36b3c076589d1696916ccc88e4af50d8f3766e6dde0e530cf747d814a591e5da6bc977eb25b43df723e28e3ff226253d07043abf1b8f5a013b2651de9dfa34b7ffd94baf8fb1459b9fe305bd58064138a0ede6af36298f3444086f1a7d0c723ecfcd6404fd267bb20ad48f6655a9a0886868a83a214957b40af02064692661c1b191aa828339495b3de0c789856f80e5b2d569fd -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d06096086480165030402010500042038dfa46ebe6244537c96b22aaa7542f8cf5a10069d87d81b37f93a2ff7323cb2 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = adb245d4c5c72ee661b657c6efc444f8b1bce6b8c0e1bf905028472935a48d62a742219f42b6326350b5f4224b6544509e128fbeac22f026134b9805320373a8e938098a9f42a2dd8a16ad672abc628f1703a7b8fd7330cde583eb1db60c9b6afbfec23ce652c57b953f4b3d95b1e6dda5f7f54dbcbbc9ad4d38061cc9a74cce -S = 7f25b51b4d94f2220ff257205e640272376993e698cce9fc5a9b429ecf8a3d6d4150341df129b74030afd5d092858153cdd01a38a586c05871632525ad7b9d433dd9f8b1436d3d62efe46501665e075e918c39f775ad6e1e3e4883a529024193891d9463b0d1424a42890d5c05058d8925fb4c446510f12afd6457b50cb611eb0ca641b8f2f2c0afa4f03e98d154447497a4640405676e003f8a2cae21458d56c59785e34f54000b6105e85e25e4c380db43c71b990d3653ac344e2bc72bff987d6c5249205f2770998725e88125309a7c49dc28f9e6fc8a1340f9dab47fc6507d3d99fa876c330ee8183827db1cfa6c05179bd49d5e4bd6b467d559731417c9b19d0d265bd7cce858178e15cda9eda4b1ace1f6a492251c4e591945d2749d7ce65e8c03d57277e6bcb0f097c13504f006405e879616d95b5b75005118830beaab13538943044da67867877da87f29183fc05ca754df6c5bff810b6e5dc64b9e50ad29da9fc74a2fd20ccac5a300928ced1c3eb719e44e3b21071746fc559b1f -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = bbaa076712216e08ed954528d8309ee685afcd901d6865c4d48b63d5c0a8a870eb71ad80a7c2724e21deb7ed39fc6fd5910272cee49072109a4030a8992cef1d5db129544b7382b142a1fa7f747b66927411212a8f4dff1b6033822b9f6851bc3af1e5aba73e8677786776a630b56c645564436ec6a7f42e4fedc2277b63b494 -S = 477b191f2d027ad6621e38d56aad700749444fd895238f9dae3633176505d798d670ab5e85df8fc42906949ba36090a14577e9b179e6704be20f1d3ec2ff00b9f038a71956ee353f358f608d1728164fdd3b90213152049f2b3588237a8c1530f5333f0b89f07443fadaf09e80122ecf2af6c2dbadd5e189f35f9c2cd680118a2793190d0d63f83e13edbabfbd01031b6875d9c7fcd38bff3587021ef04f1ea0777ac67e76aa1b0773109b869075ae2c4c1f0121782ad767a7d0e78f3170c3e3243309ad36378a698f39fc6591463dbe9c84292bc4a44b4874320f9c5cc3cdca879f2a015362dcacc5c74cccc2bfe05f0773f3a836e1ec511c72d9fc7317deb4b2af5976bdfd1fabbe15b3f99b498647d92f818f658f8398c031cf2f364ffc106e75ece8f1cb87af2592fc4661f80c45e76fec99545c54dda470a019ba9a26068f05517defdba0d423029580ffce95b3ae1e5c8a882806f40ffc3b78640d6b311c2de8b0d51bf82a1ccf304975bc413d5f7e2222d91e5d650ba601594283aa49 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 7e5a48ece8abf0637665d2cc4df0476da66a82006aefc2100018cca662c1992577104c739db3675984683d2d43c3abaea52c032fc42749f8dad8a2e953c6096027df445d66bc16e41527b7a338da81d5308aec664724bc588a577965d75220e636cf18f36c5067cccea8267754be32abee8e25ed1b7085f9b79d3b6314ef467e -S = 8b08c4fadf5a33065be2fe7b2487190aaa863d150c819bedd2de321ec34b9f397e5ceba241c998d1138080867a2931660f6d720099698a473b10fab8c6c1ac99bba21ec964db0e9de0424d12565bf20978a6041b8c72019f910c286781c7979a98047abe06850d282644f6b7f375c6bd6af8509727b0d64d851902baade451f6af0c21967e4d545a535ada7f59f23d90992ab1268dab4797907527b9929cef18ea468e4803ddd69f44627577e9cec0ed8219a659db94d46f560cc1c32fc36537f9fbd568e26d22d070c82805cd17cdf80ef8ff1129f5254984ea7e13f3b1d40f7d9c304f49b504b634807f77dfe73cab854d3b98878dac4d33d13289d1fbe9e1b2f3c75f6ef5e4deb2bbd8e56ee6353f2a5d9c28d4640b01777b3bf743e4acd53e2e413dee01bba20d1811c62c3ffb27fa6a6a522dca12cba25c0b5c2f02d3f6b4593789741aa8d2e111b81e34fbed7ea544405dc0edf263283fd28249665001488c67f9ca067569f82c52587ec438b54516d1d84acff50719049e64edd562ad -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420c46cd19378dbc903c60d48ba8ef26b1ff32f64f6612a2fc01dd770c878eceb8befefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 2bc088c8b2a4af1e90a9023b3216fdbf89aab7710e8b0bd6037ff503fb5e3eaf9cc85c8ca41394d82a87612e27ce19a334a6ce0e95d972a7776f3fd47622563f6212a72c43ba100a9a23c947ea57ff697719bf5b4ed3160485d0771ec4ab5c460508304f97816ddc69e4022e859bf73adb6b53ff40623e16b60a638beee398eb -S = c42b0d458924349b4510e4805a6f199b29defe24c7220c54d1ddc44117bc05c5b25858939708333c8fcae96efc75e1df6c6b429b2f0e3f9ac21a59e15c1a976fa91294c11e255139725d5b9ceffce0bffc93166057d191be06435d68a64e0d790731f00fdd868dd2881546f467b52d3fd240cea6b6e3883db18facbb67ff858918de576f275d6a0fef13fa135665928a043390607b964a8d395117f886c661d9a9f8d3a2d863292bb2d82c987487180dc2fe859fc20fc5ba849399fbc2a5bbc414fb244003b1887d945580d2bae524d24de03fc14e5595e7471f14cb212cff64d561de03d5a85304a51883a10c259ab729e750f8a424f769eb8ce2f12c2ce2b3835b0ac9b219a22b5725149d65681c525eaa55ddea7f674ebc833f74464302597cf603d95fba141b8ddbaf3a540df6ef9bda7146f4d104a9287a4a55bcc5f7cb4dafde9c437d2172cebab2278ce97441cd1e091e3d18429fae503e1cc23319ca6abcdef6f8562a11fe7fa1b283f4c81a3025668bfe995dac330bd0a3ac869985 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d06096086480165030402020500043034a99a927444c010c6a1e59848fda5efa3d6f47f1dc62aa4a8c085308632d72f89e37e9f74f5947755a2dec1ddcdcdf2efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 52e616af9542cd632f93bc2f3d510bef3dd341572014ffdaa0b6eecbd447f6c302c4b142b45b1f990e759b075ef40d22f5b96278366a3977ec72df8ae1497e85acf59143cad19b8df08d193ea076b5a5fbf7bc2bd660d2360fe7e54d21ed5f7cf782a0fafe2aab097ee11f1e2a5e6a42f69539b8287f32e0b21de65bbfbb0170 -S = cb647fd846c24b61bf5bd7893de079147a8fb4d447bdf26aa871d7ef83de578a383d932b152bc28ba4baa5ccb15e499e338b2a5e3606533c62915a26ebd8351212c226265bf097af9e30f113566921dda511c72fe0fb114eba47bfcdd052032abed1f69e144ee7c347f62f730b96aa42b75e23773d2a65f0d5f63e01c395ffe6c9a87c2364c05983e4c676af4b57a2190a2bb7f5f1b96574663a13540f51da353be8876879a1ac90b10a5acd42a69b6ab45ca194fed641acdb89fcc2d93325028f01a3149795a2d95887e29e161902da1708410d37cab1987d4f3265b9ade7c1bff7b385ec9ea1221fe00a285a77b5ad37f1e8519326d7baab48fcd70aa52dc2e6f8e7270e2c9c99f21b30d217a62969bfb584ddcac60959f71d0ae16cce6a41126c9c597970a79da11e7302ec710df8890afd0b133306b8f8a2e1c67a6f0103cef6b13fe4c1b19415759291267b3fb0dfd552d83ac856f85859589c69d911c9e498160906833664437456739116626d03f6f2028d869218b418b6b9360d536e -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 11a710487cbb1b9392d6f6c305b105f68df8d5d6384e0cc10292a028a5604835b2db30b1e1aaf124a541c03e0462e575a6e370f02cb127a4c315c2bdf8365b3fcee020ed0d834b6ade7f549e959e645bcee20e40bb823adebc2f611a309b00d28c3c46c4aa4e10ab631718aa5f6e69ee2c7e17908ec82cb81667e508f6981f38 -S = 378ea4183be0744a9b81e57577e197b4b20f3e9cb7fc455def83eecac3f470e758557b741796439947eb6b97b46b3e67c12f30452c04ccc3801496db5e3df3b5f6442b7086eaaf36ee1a43746926e78cb43317259970b71dcc9127fb41668845f0bc7a938addcbefc7ff19025f4c35da5efdb74884a98872119983bd0c1db06489b7530caefcc81822e74fa635ed4aa441a48b8b7d6d64f1a489d50fea892b2296c6b1c24829e7f7a23c186dee29d88bed157386e4090caee36fe5984aa09cc222db2f5985dff56fa97da47202fe49efac993ecedba74132e144e3ca1a5702127dda6ad91e133aa6e53d3d5cb8c81b1397b8c8ea2b55714f6559f198d8ffa7aecbb12b2d4bd99eb697a3d26ca55694f2f1e99e543d6be90e4a21214ce3082d0848f3c141c98becd7f986d5684e67a8cc5b783d90aaa7e0e2f30616f59f38ee150ca41101c4f20ade865add34fed3727b745db406e91dbdeffc40875dfdf2ff0dc62a8d392b4272630d3b17ccdfe39313e7f8f265b2770942f500396d2e2d97f9 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430eb5d1d6ac4370fbf37da65a4a43e31015aaba587ed2b1720edc90282ab022f9581f3fd35e174a5be58edd5f9a9aaddf3 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 979982a68d0d60a1200990ebf8a49a7b7db3d1e83f9ad9d9946267bc830c48bbe025a5ebb99b85c7f1cf93de2beb22c8e9766e5ef526242b01f5251d8a768780026add2d2d8fb9ffccb86f8779221b01d206e586d96b83839b3e006910a4bca6438fb5d5b2900431f8ecab50a9f18d0e7e8abec7b212fdc9ab667f08dd3eef14 -S = ac48451dfee18a468ebfebb7300d03efd9231ee21d9a3e3bdb5db9f5ce8d3e1ccb9af7284d5a98a00c39cf62d9c4a46c0374808b0dc01bc57ac8a61682a7784279d090d5d57c5b4f36cb468fc9200e3c28818f5e8cb14bbec20dc460f2721cddb09233f64b0fcf7fa00c165395a681ebe52fc8673d7b18003c4387ca6c9487f02912cc15e525531e1d40aa79881e2c6b2038c5938476d4649f20957cb0405c6f1dfb14c1986235b7f8f18ebe3c47600ab80f841c100ebba3e042d865d0fb8de4708da33493fadc509683bfdd16c00c5cec1fdd7d3017f4a0718a615dc7122202a54ea7429966e6f818a4096db8f0ef3e530780f09eab5d96bff59869fb8c85ed059a3ad8dc3d5613f3300a8ed17754228ab4e38dc24dd8127ac8d4cb7a68af8aefc87e94344c46868c1562942e188c9618be86bfa09d12a16aa0b52a7ab493fec12eb8f4898bd000ace4c2520d6713772b524dfaa86655fc5dd140d1d7ed49db225c93845b41ecd10b8dfea26adf2761733cf0d330feb9cd024bc4b906fa14ff -SaltVal = 00 -Result = P - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 7fa4945a374691fad437ab261e2c9068c7221fb14ea96f4a2483130d0e6d9cd5ca3d6033f52d7a632c77127e7222dff0d11be92d448794a0d558dae4031ed83766208c2c96acdda048abdbeeba78496752f359fc82d1b63eee36c789d185337b9c77a0abe16ac19870fc8fe0c0d9d6b390d1f486cd2edd0cb74463624049b58a -S = 9e8ed5b7a3863ca22b2c2fdcd28ad09e69346c8d14262c7800e85ddf71b845bf31d2101fcb91fbce1f227ee1c72210f29d995404ea2e4b31b41a71173884570c2fa0753facadaae01038e6b897940e386b601e972d84095cd7e51345348d45a653c1ce707210b017c1b32ff4904eadcd34097af48a430a0147499a9d9ee8a765258b94fa56b0185bb0789cd222941eeaa8356964d2b1b12c81c0ad0440725ee6360c9e2f2885047c5b6f2069590c0f85352f5936e183d78e5a152f6337e1643bb37de221291191fa4226973f9fde3c688fd214c49ba3ca6df5a09bbf4523ead8682835944b1f7175ae038f84955dab509e0d68b5d9da75eba60e11e4e9ebb4d0f2dee448694f952eb3ad39e740516f129d12874e29ceb895dc87dfbb2ce4f208d1e646c347f9682dce4b71ac53ebca2a499ce64112279ac439f5942c8d04f2bf5e699000efde4909e6b6b62cfb52ee384e31beb22b1799731c543c4a95303f8fd32a14d7c0fcc4b449c9782af392800d2f7bc37369293f49c1cb94b2921dd407 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 831c38ca5421eab1edb3600fce5acce059ff4c5b38b56d69fcdaee5c045fc6dea164672777084574277f92b42b654c8401517a5d8baeb30cb6c6df635a20422f610cb66a2c7c37b13215a5f8ea86c67cec198bf95387941d6511f53d76cc3b48093daaf93925c950579e2142d56741b0627d059657eb188552e2b853200cb911 -S = 5c95df8ef637f77033e66934588956aabf334f0f5ca5efa1bb0e5b1c58fd313cdacb4d9f3163305e048d2f33a9d101fd6c0670f96d67b466d11f03d3aba60bdc04869e3a17aae7c80080e146c114413bb6f6016653baf26d3516fc05fef13149dd552bf5149cddaa46b783e625d5a3a0b859563e9f467d9a2723e5efd041a92a9837d4b652219d4a9799b35cb3df6c80b8467338b0e7c325e0dc1ee22387af8877e66c6f6a9b0d12a83db08dd4a843dc0e7d0aef5f0ca9cff1db415f2dfdeeb3a0525b2cd32c07dbf39eb9a3a132b9f764b66ec0ac6cbe0e770e1afb063cd1cbcfd8e8b39e10c290ab4a8500b0729a1240c772ef5adb065965ba3a4536e2ee0058cb11ea58834a5ff267fb11e90160c7a433bc1af9a044e208265e4c62b5940fde0e168a8863bb398305acc367cdb1c3b70f39ef051ce9614a125c3241bdaf42d8416d4efbc003f698878829dc2cdb1dc1f7c0ffb1af30b8d807b459403336a2eae1a6a497e95a0667a2f547b5d40bd97f9d76259c3ce91f1209a00e8da48fec -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 939cc087cba5d8eae6cd3884251f4d60808bdc82f2e6f013183217befa20cd5929d339c80ae7171e71b2f60671c9a36273c6e53186496ab6f63d02d7205d0bc384f62cd71cee47c3ed05a8e8db5b8305c1339d13c1f6496dd97b9634b785c7f2cf8d037daac24e1f814fb8f30adcd49292576cef4cf47380e9723b9f68a1e92f -S = c80363c21f7f20d91361e148b0a76c33ab2109b8c8e34609f567b49ec9675f1c04452715371913685f9a2f88effc90f3ac16665a2dbc81ccbdb4cdf677b66752fe07577c9a2986e48bc03e12126bb5212d7e821adb66c4eb96c267eb898db16f0fdc52f8f98797281d8411aaa4949d41815133a79a7f6f8cb3893fa1e28a37ee6c550e17772d5be34cf4b2cb16f119fbf9d5f41c411e1d2561d33aecfd9fcc425e287a650b127d11ddb2fe49a82ad3e7cfa84a4da75615ae23d0cbc45d58b7cd4123105ce3444a52412bbf09c08036f10d03d79ee735741858017181262fb5e2f817e0c53d3def1fe84c53807933bfdbb2ac2eec4fd96d638255364033e38ae5f9cdab1241938c1f6dcb14067bd236cb69809d95349d9c1723b39b71192cfe0c8a204c142a2a72d67f124ad6b8804d3b5ea149c7a1e884025fe56bc7ebf925d34ca62c285d3b290eb38fb24e59ad7c47914b98d55cf8d1685f1d08d1e919f314994a348499a68d3c669872a113bc119fdede411f4318dfffc8082e442784b68b -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 118a21ca36aa54b42804f7fb07874ba74e14bf3906dfc4343a19dddcaaccf53ec306f670cf39971a6ae2763535696613ce480aa0ff70a3e735e826d834b892480a058039417dfb5c59f693d47651ad3d55a51ded849af779d312a17b060f2d93ccd1e6acf53e2981df87775f3109c72ccc7121a8ff2468f3fade785086987128 -S = 5d1fbfceec266986ee94603ef2f57ff87959bcb7f1677fc871f97b5e73bbafb6885957eb04616a3a9bd010fa46c8a5c40831944a7f506d165ef3cfa4d3a7bf0768360e8dc0444c2b7a2e05106cdbd6e3ab029c11ebd701fcee53bc46acd269582ecd7635178b850ebf2522d16bb4e6671ee7dd1d417cf0d23baa26237e03fc0650462c1d113dd450e4465ff18d3a9871fe5fbcaf554d14c0bad78752b4c048356ffed2f80ec319ba816c60d06e270c656c8687be145df46baafb686a9b74df7347c8712dfe671b33aad8b3b7eeaf6322a8e770891c8e03526e1c6ea4fb9dd03413d646b3ac78a3f6b28ff87612616dcf87efbe12ebcb6933bfeb714961e8e153f96ffdbf7777f6109be52a936a13986e4e8229535f51a679f7d7aad4acf1824bf0616517785b864f5f19d275406ec53089a04a4f1b820d167b5ad3ba36910a9730722dfc58fad54f1e0d7f761f5d4ed3bff3037f79361fcefe723647c65811f4ac66dd6dc4e3f5b4bb1cd0f3d2aaf000251b69b9464a35bb7f7540b1249dd39d -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d06096086480165030402030500044022b0603ccde4538899af30bbe52e2e4d6e62ca5f5e69a0e7cfe914a193af2e5788f6bf85199a7098078438b5d2a3b694b926526033922915953e113bc4b56d3eefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = 465c2bbd78a5f3bcb387d0db7910e9b2d0b827948d949a67d2cc19b2d64f29f8e4c52145a7c68b06a449cc1d085f0835a421405336e6bdaeeabab2c1200c1d9e70a7ee85ebe46bb5a41dd382706441a8e975d4dfb9ea0db015ae788687b48f08f1e9dba6cf675c72bceb2b3238895eb3a89e2c609e0752125b90b42a92af48de -S = 902cd4cb495e446e0b4d4cc1944fd9cddb126dcb60543dc32c4ed0eb4e72182b1a13459746e4ae37805e23808cec5974083911f1c3f155e09a3223b03aa145128c9a2ead1c7010dbf43231b6ba5fce2ca77734e543139118475f5f3eb9db6c0dd00b01b7a48a1b4c65cabf9260d22776bd4168a7f7b8b81099ffb60d6ee00356cc16cfee9026fd318ef4f0e71288daf10e06b6789fe0c590ccb7c448b7426dca0329453633d98fd3917562a2df5c2a1ffb07f82354b8e3b1a508908314245767542b856938e019ff4ee00c46ced5b8b836b57b9d0999742b2e23dcb15e66c49401495dfa7267360eb0493722abe6c89cb92d47aeac5218a4a949b4d7c4ea23c7448995294424995ef6b873959fa8f670e764a59cae39e998459f9eb03f3f640a6c4a6c39a9532c48db61b5d6031e7098bbd836f5ef887c20f00e6f8d3e82a7cf3f3fd027cc315b85e93205b78e29b9307d25f6c38498bbfeb08a0aca6975f241df0bb9e27e99dca0b555ed294a23071664a7fc9039838a892bd4cf9696763637 -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = cc848fc93ced6a3252fe844053b56f8b8df90ac8ebdbb035c81baf3801eefc424efe25fad2b38698f0b1c08e61a2676e8335fb08f4661ad26001f38e9761fe26e37eebdb9827d89eec8bc6be09fe4ec461fa909c42646df5aa11f6e95c8923e1330bc9b3b7d1c60eee947e1875538c55ce51b1cbfc5d10644d559e9378edd43a -S = a2771501c8d96b8f29f456930f1551f648abc58e214854d44c1bc32de90c2a8d269ebb1c30456e710fe411483b4c931d40a7c300e731ab0897f976e5c5aced427bb462acb998ddc23031c84efe0d187930254e0e0e1f20c9155ba23f7d2a02f1b390db18c71d37f175d13f44e421279ed5d803ef7946ceb364dfb42114b2943b446ae2eab8932f19a87eb449adcae98223f333a47eb028dcdbb9a8fea2018b3e9bae3420d99d288daf1c13f9eb9932814d530d1f8cd0f496ab21aa984f5f2df5fc5f56a6e7431542864f2ee78108eb4ffdf98d50b8bbfff626da4f166881d8126442331ab8d4d30492473a6af9c1fbb08fbbfb6bdc828d2c2419a302800d21e91aaeb39a453858f6f2a3675afe000de678e5095b9b885d1b02c153dfc48b33470fe8521afa1d36a18e2ebb81d58e1cfed3c0125bc8c5635cb88ac78e03aa6d661dfac9bd2844aaf98b6ac7c753543865c70a34c9f49b33fa63bc7b4f0b4a38279fc413482f2757b287c31f83c786d5a55438c00d1f3bff8479ed3992cce425a0 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d0609608648016503040203050004403c1940aad46377052b5ca5f32e427fc60524134f6b125784071ecd029233a6b878b85b7f3c9a7ccd4838fb9352a468d02f64a6e19ffcf2e2158aef7f09033d5d -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = b493cdbc8bf23247fcb00bc4ad61ee808ccdcfaecde823ff2f04467382451a6e6655f20e555aaebce425270145accd9b11bb8ed144e6fa038ac2a585b955cdae9eca3d2bfc697199d2c7fb54dd3a26895e90d8931d01bd84ae61a101f39b1e54e25a78bc8809c5074efe51637cf24072fbb5759c5f1fb3a9254a028f38fe5588 -S = 301c7cfbd1d8fe0d725cc8854a9ba1c7b16a3e4c0e357373a57cf22386bc562615cea5e5359d90eac51e558a15580622585f4144905b4dcdecca2e42f68010aaf8be6a17cf2fd4a5ec77871c2229912dd6318f365214939e785d2e9d23c75eaf8cb3c9ec8a21d15cf7186aa3e92e1c1209f054c335fbd61ac9c48244ecb4d607e3bed905a930f9605855e9b220129ecff5239eab8260fe7cca7d07af495a134dcd63dbd71c72205d11613ba89925f7bbe36c2909e9dfd40596f2b6956e749c3710587d4f1c304acbadf83c29caacd3a1b3f0dd332560fb8802be3af45e6e09aaae57d8b8c75441f310ddd927a3279243817943719451b94cd6d3cd62c8e1c15070c2fda9baa2534018279d36ccc15fac086cae7d430c44276517d1e32082a6de8d0cd7d88900f9cf4a5e7012074834b9783734dd1524e191a63e0c6eeaa5632f6ff2c92f3d05589791d8e717f4833cb5640d2444074e881419cd521fb7f5f847fc1852c8e17ee7c7eb3d808c9870b1f81ea69a54b361b65c535e0dff70278c61 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 22987d4c34ec4b902622a8a6aff3dbbdca802c7c05de4b35d2402027226d4d5dde12cffb23315451fad250d344806558b7852140a554f05415f570af785a6db622f1dd0c11a3e64bfae2bd0f59fab4f2bbf50e26c14f1c58a578d85d1685e896d9ab6acb9242278394dd91c275d8c9efd8ff0c4ad54ace97ed8a75cf7de374d4f25ca008551f66f62a6f62f564f7cc4af8800cf6c6f65b08ceda624a3a98b8f98c0374e7fd2966ea7fa44c347e1c484c5d1805d81980db5d1eb193f48c111c02b8a4e987a505ea5bfa50956717f77a3b89e47fd8251eaf35b3863c3e32a01b6271d8f793074aea4d0ba7eec8d1cd23aa967c7bde7c2ef919a1a9744902fac439ac3ada0f604e2c1edbfc4349bdc50060f0a0b2e46ec8ad9385d63342c1cf5eaca1c68ade01acd711b96f3e165458d53ba6108bc784dcf36926a5f2e2217fd8afb78f46a7935cb27707a192ee7379c72b74342fd48d7e43b1a446a01264eb2bda68954b310faaf5dc57b524a4942b35f17eb7b69ca39e609e398e9cbb6d7bc61b -Msg = a97ba5b9773d187153d602d121ec843f36ccc618105046af44067093b78e6e11114441fa6f2011a759dac139f351c725772d3bf1e2c32d38ee3a3cf441ec64fde40f18ccf6959185a25065354e5a5b5715b47e9e782d70ee508601ab07d30037082452b6746540151783154a9ad1e9ddfaa9b8a73956b7da5331e741730beac9 -S = 2f2c9aea6942c5a24b4e5e04875eb5c6f44e83d89ccf1f13455890e2d61f2b7ab464355c5cd0e7e9aecf004a0b85d0cee852a9681f4792899731f984e2c06e47b8dfc4424e4cef5b9f15def45d528a3a275fb4fe7a194ee7b10a6f9694e8e1659d95a6f915fd79e3406e05136b244213ccf67c5e2055adbffa85896591d7abff96f6e68494dcfc48440bf66cae21d1752544933bd22154756ad15a3c664188cca88b5f23a6acdc151e62f7d0bfa9cd60429031736d7df76bf2c12f37c338a1174eb42cb740c5d38c1cf1b682aab8d49443016cbe397cc0c44374f29502d997bde22a45efd0e7c801ffdcf1b3e42e93b955ecc0eac9f5b71c349504e8b2973d894f0d33edfcd07f9fb6b3cbee593448bef9590391d13b661e2dd18f70b43b59f2e79d65905f9ffd8ce0117e06e610f34fcc8dfc72d6f0440e2e6f882747c5416bb8c3ef6ec702164b51309d3df33a3846237a2f0ea8dd39ffbe0a8d549cdddd063d7d5a65fa27acb62f46ea9f467dc0defd426cecda8afcccadd1fa3e483d5fd2 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -[mod = 4096] - -n = b10935650754c1a27e54f9ee525c77045d1a056baedc8c1ba05a3d66322c8e2e41689ca02b8e6ec55d3331cd714e161b35c774311540c6410cc3b130e65cec325377ccf18a5d77054afaa737e65b68662327627f5d1092df98c08b60a3ba67599b1406986f441528d2f1f5d6fe5ec6b8aa797dbdb3162876b08298237af81c7004863576af572ddd66c487cf32a82d0f9fe260f8f2681613208aec55723622f50d3cb3bd33b1226d5b5b9ea2c97a2c59054e31536849ec2f0f2597c077e621ddea0a22ddfb1df925c9f1941cd431afce0398d28e736cfeab3dd7f062a65a2a4c1ddca1f32afa03b4ddfd8b7ca40cc0ce2ed42229d753f03cc6d8bcdca76ab7c2703c5ddad08aa9bf9a27740a8b23168c6b55917bd3d5c1c057c34d1efb1411da51ab745519bd92b9432fea8fadcb9a70e5dc3adcd3081d3333507b7b998886e988296628dd7265e64eab557712556cc492377f15a078dcb620a6e7f051a1fb8754efdca3de253dd0aad4205b032659e4a4fb307f074fbde340702b5911acb34737d7834600cf2ac77f62f83ccc9ba78ff911021b9f8ad1bf421430ae0d64916944b504542c0f6263c48e5e233ef1869df1efc2ccf6f4a95e4db2de7b4cb1a992bef6573511bab4bf2cd58e72a0c235f56dfc182df4dfffb69433a5677415f35d84f5125f5200eb57868cce6b74c5833417990e318372c9239a36dca1a0b28809 - -p = bd4e8bb7fd7ef1e39d71de06b0001bdadcc81b0edf2226e0d056b7eea70b2249000279cc1c04b1ac2919014fc3fb8b62baca3e261601fb0a58a9f67f03cd60085b2d43906d36ad014f321012a9bde9617478a0c10201afd53f2207de3648afd1d737afadf7fd2c0b9824d4f66b2c7dfe93390888ac088c680c27b1b2486659ccfa8986c8c23f78f18b5815a410328e629e7440221bffd8ec4722bba3420da5234f898f8cd7e6d7dcb1349bc4a0b665b41d930e3957cfdc88797aee5b2b27dafb5ba0949e3dd892f490212dfd249f4b1d99fd3b72695ee0652997127f0b9b417fa8365ba9fd103b978309d9baa9d401902cc107cb8d2af7ce04660900e3707ab3 -q = ef67f69838735c055145d21fccb42298642177fe3fadc39070a95e4fc04ff058aeaf9070b4eb2de1cca72d8533bc55206d2ce9f2895b148da67c89e5b6496ba682f76bcaef69306a7fa4fbd41a838bdf0fab3e7b56c27a8c18dc4bf970364dff7427cdcc6f532b49712282370a718b7d5287bfc02c4abc35ccb2eab3777f5e0d8a27ff9ebe13e725aa0a0cd48aee1fa33ea6b4ea965ba42fcce7af3c528a6675cedf4969640f2ca73345dfd322620df9dcf16520195df8232061e2bc89c12de24838f255e7b1c17713ba435d5a351e263350198b3fb881b8ce0acb5aa58b7afaff184489d167c9af21e40e2ba9fa69b44a3854329385c97df0de24dc283a4053 - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 200ee1828829d9fd27576e253ea700245c38c5ae78fc76e33dbc4877a55d1e10c961fdeff8b1c0d306990d1ae614872a7b4a450fac578465b74e9879c77d29abc8f39b177a40ce74c47c083b4c8b2f0c449e3c4f87fdec17e405b84bb96c0807c4cda44037606ba70a0847d0959460945e3e90b4307818be6de99135a4b225ec -S = 33d2c45a355afbb8eb5f64fbdc4bd3719afbcba36d5d4bbc697887ecb7e7ecaf99bb31798977e3385544fd4c44efe1b05f2a34119bafcd6377c24f57c030498f6d96148677079ffa05a253e9499d6b13d3c02d5347dd3263045919f1a7169f4297cb4ead2340e6706269a8607b1575044e75adcb94cc7db8ed80a776ff1e56d1ac13ed7d82439750d51904337c63bea9a059a056f30bbb8c1c721a0d666cb843b1a8223b197a9f48e3941a9f6d8cf022dc4edca612d057b2548986698f2a53266f49e7995640eebe929fceda0d33eb24437113edaea93e8d7892ab14b25e851b88808b470a90bdcff021e798ffbed003b3b9c8d53e4a1cf77aa7b5016a2ca41d4da22ebe498c73bb3d0239cf41ef7f404fd609d390c8c1a0d2f0a6817cd3ef966196d64c89524032b6ddfdc6f9d6876d6b9e1c55010969238af5f2ab616bbc9234445d07f2462aa907b31a08677fcb9236206187e00888b53e925c334f4993d3f18ad6db81ced54b666fc6513da7a4e8a8f1c0eaeb6819cce7cbd27de9f9c9718d900297247e41a704b7613221fa114cf145a1cdabf4217eee25678a24420c4a75f8d444069c976ef95d61e5abed512c01cff4b864038ec8e4aa877ac501664d48be5aba39a35df9b3b1ef01a25ebede122b1797494442420e0f0d0d4b7c49d85f9ffdb102a7a1e0ce6e4a99d9690a80958ed548e5beadec583c192316fc7311 -SaltVal = 00 -Result = P - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = e0dd55521da6bd181813a02ed22eb20e2f5d9070573846be5d9814c91ff072ba6de1514b6d08a4373d1b1feedb343e8e426c8a0fd6ac18bd02c052ec20adf9e799456b294df822d035ed7e4e4652c46299f06647ca02852b9e47b4e2e856ffdcad322c54861e40cb46b245b5dd2f4b727c10ad7ffae195ee7754c2133f928981 -S = 2c89c5c5b481ae5b632c628ac42501f9df48347c2ffdc7d06526d2884bd5dfa01591a0a197bc87c0c3e2b9fbd6934a29fe5039fcf5b5fc89c1731fda7e274e706826740dc352d95c470ec799bf4123e7d673060de89d217acc23ae544ef70e4bcff3af691123216582b4fb6bc277a1c364acd0bc7a689de95e2a90d762ef4ce7284ae0a9d42f0ff37a2f6a40da956cb08ef0520df1e5c9462ebb5694d93ab5ea7ab7cb3f1812eb06ffda74f651d15439797ee0597fd00c5c08ff08ceff35a44875afd485126a9044c0635c4ec60992dbeb9cb9be19541b019a270c85e2c7a31a687f96f13b75a11e1cccc0257a7a9baf665553ffd34802aa23f0db466ec35d8d5a0d6a560c75b0ed1f434ce06e23ea582e53851c59824e476686d027810f7b46f31e88969b8274bb3116277ec1a3982f26d6918d4919b2fbbd161af81786842b57c9dd7f388323dc377aa64dac6782abbac9ab3558cfa8c989b8df8ac5be897c848cfe00407ffc9de8f3dc94a263182523c31efac84120c3262158d9190908479fcf24343192b86991a15a2fbea0ed8ba12d7644af798be3205538ce4e45a437e116a1faaf527614e57a4fe2299c383fa2383a57b7e950eee956dfaad4dec984a239fa4e09586113659126658581b62de9eedda4a921589b02d2f24c57f2827b4044b8709bd688a8a114fc9c875973ef145ca1211698bde58ad273c67b6a5c44 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 22b5d51cc4048a5a3188dff7caabe8c2f2d8b59fcd3032da477f4cbb596e555b88faaab5ae249300fcea6a3d4077000c64973cc3376d05c171686200f173e0ea486c356e7bd8225205d59ecb1c4f304b35779d9aca71c3285b4dc5a2b33968c36cf5bd6db58701f8532fc1cae69d41276e621f4b0da534b60f17bbc82729b58d -S = 297bb0df8a838904aab3f7a517cc87b6f5f4e53e314a2f6d0270fc34ec94da9341cf86aa8f7de3220485f0598a5907ac559e89bbbb1e6ce4fa2f1a17cb5c8696bbce34480ca4f7b2bfa2d446e028359fdeb265af0e3e1bf3232712cd06ae681d7c5e8107fd9b088931ec27893a0f2ec6b1b9a1e53e0da9a3e19a2bc840366acb9452099fe221f28a6a8913f2d866d3d0d4127ec3a96c71099e5ec63be473390c4aeb9cfec8a651e812807bf8b3dcf75fad8372382f86556924ab57dcfd59a02b9f3b2da272c1c738fa6f1fc3a78cdeaa91120cce66b9b3287037c1858645e418fa74a5ad75196e0d10d38052cd4ab8e5aba58805b4bd58daae20a801491d042180019cd41b70559fd9dbd1cb505c7f7feac497405697866753a8d3e2a92f854a988a50f3554ea0aab86e79d5516db5f729cfd4e2d1c7bc754d00d75de863dbc5c254748e805da04492ff230aaa89ecee80b5501128bc37646fee92c3714e26fda4a120f684dfc043bc26cba3347a3defceedf425e729ebc0f7199a348f29e500a0cf50bbc71375b0c7324f41db18f7e3091c9435f3238ca879e61684ec7c5e05ceb3835d4a3efa4d07ab918a4c0b10f01fc8207e15aeab15d21fdf032960fe5235447bd5c6eddda747e8d9e11c3d05612ca1491cc5d1314946e45e3aa1c6b1756dc906168684685133375a7d7cb69ab04eab56cbba728e70ae8d4deccf4139a7 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 709fa24119653806778374d1d9574c92fef4959886c61958a97ae96a2918f5d48572d98b70c2fa37818fd2372cd088e5f154c41bd361c1f60c9ca4d9ff280cb56e12ea88eded932497b91332ff0ac4766a6620553beed494ae401562c99d379990477c41792d2a561fcae0ca3a4b29cecff0524ea4b479baf730e70c6fbda007 -S = 0b7c22e20bb685bcd1d871bd2466cbf02994e50238895ac17cb51bc630b646f3ccf7d1c572478d762648e958e8fe1cc1d6a3b5eb6ce85bef9a01945cfe9755cf2d55875ed9cc0b1980e54d9d11a64a4855fccfaa3c3f4973bea94717b18bc4960734bce689a6581061a85e6a6e316540d209e6044c5bee56fbde7319716094ebf240133b1c2dab38565846f0603efc68ba43c36f439f49f8ad9110833156a72435948c3581c2d5bc1dd40441a5d63200252cc9e8af7bad81f5513313ac3c3665a03cf2d89c98b736d3ae566a175a979885d4d1bc87913eb1c755de17d2c80bf91baa108027af75e55ef8c5f13d26b4ff88ba3fc4b9aabfb36f90927678a2838e374eb764a3773d769ecfe9fbee806b30d3b1828fa1aa8a082563ce38279f26c09b898ee863e5eaa868d9a52a35612cbc5e87e5202d5f1fe6608e0d20ffa9641588a8e60cd0f06b8455f72378ec5e75015b4e3933c3a8d8c72e204db29e3327f8d3c30f8b9150760673b572c0a1af15b0344ffc3e5d405a208fb96b2f8f03c63806351ae34108dd8f9018a6220c67d962c76fb09579bea1c43121d467e05684f267d7633caa14cec7c81fce053aa121922c190f042bbcb08e37dffc6b7f7e022fe9c937882c27fd8b4e8002a53efd9e7c32cdbee30b373bd40d547c07696b3e854e4fa66b4fd7b9ef41b8f6ca5e6e7acea19e6e624d61e24494bd93ae7226d686 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 6b9b00a0420a1869f6fe4de18f707dfa850983b626efba9737dfbd56de7c71d8c0e6465d668fb9fbe54a1e4bbea59c6203797902bbbf971288a53f4c87e21e3678468d531f95169ae9953327d36658318812343cc965358f12ff4ae97ba7ec70dce25fea34c4352f4c0715de975aba505dfb3eca188899f71f1365958174e46e -S = 7b08a6191987f3def583b16c365017b9a9f4baa76826ef12593e448fd5d7cc49d441fe7ac0edee5dbd1685a7295a724bc0b1137e8860930f12bdda8527b60c3ab08546d887f77e74315d4a6be9d4531413914645d51c05008a7e145257af7e7a1e41d949f284be7a7f1ac71885275da46ad75b45d6f19785f0a7a4f18124eb8b2d3692ca9d7c3b2cd05fe1df60ebebeff90cdb7b18b20a704acf64407de123a553cbf21c2468a25595fe2e2f6c0516221efb0f5057d92d0e64e0d95c1e5500467fe7c1742561fd0ed03fdbe4795a9a7457c3eba1033e11af6ae64e59bb9c84412fe89551d52435bb0b717cfb8b029413ea796f6b69212649c97e5a7f2e2ac50eff7b1485a251154c6da8609765e3e3b5cc155f0316c0f8a3f6630177a881e3546ba1dfa404430a0910f71531b892c6964abe8cfddadf60a301427d9d43bd8bfffcc68ddbb1df8b718f07ef794d95f47650b0608c5e5beef2edd339021152c5cd33d6737ff3c5f5aff14ef447274a7cd727e4f9530e40470989e60e0849eb3eec1a124feac7b452dcb5ff002225bbacb420a60afeb10781e7784140aad0f76b01b00343835caff44983b0e681154478b951845cd26b852f279ea45f4f6887ba29976c48fc618a7eee9b7b110fc00f495f015264ac6e0e88ae0129748da755264ee4b1289882a1cbff971d6e87545cd670875c0ebf2464f1133ba5ef764d49cb98 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a0500041427b561ce228f7d5f0f8a9b1a35af930ab5a9cfa6efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = dbee53378324652b696ae9daee6d6ceb27bbd30533cb49efcc3e7cf51b64098ed102343d7352ddb5f54cb0408b249b61bc1485b8b85b3d27eb86b033d2ee60ad0e821191b7c6c52ef21ceb87c643d4fa2b1d661f64b514f38f800e367be3b411b9f651fcf68806df8863047746d0fefc9d5edf01e0e0b89be0b5fcc5bd4cef03 -S = 24d07b55df196ab4f27c5c1008b49b54d726af278fad7408c8006262756037498841b35db44ea4ef7514a1edb148da8ef08fef64ee14c3059e6983526acfa9e6e64af6e056e0e6a602c9656253829adf8bdd43950885e3a6a8f202d90a728e0377242fa09cd3de5108b8b06b44d968f10e3652cd8840daac895b08923b981ad4ae2bf4ecbd230afb18c1fbd645eb993b40ba4e0aecee894d76bb414e33c1ed752abc8c8d950b4a16868337b40dbcd9707b3c28b5d59dfbfbce57dbcb54238f86fc7ce2c6a5386388a73da4e65c5b2a48d620819760a6f64b34cea861fa0703bbcb80524c63ff64c673250e1cd922cc3fdce9849e9c57fdbf3312c2f5517abd501ee26bb06e7ee25e58b3051944e0e47e6074a9af1f6e6ab3879057eb82519521856dc94e70e4b8663d8e2af2064b75847cf02d814a77a64bd395cc1f3357ae466f4d9ffb5f0b808d770b854ea44295984a938337729d301f28bbc5e332e27dc023c96db9bef26664d4a3d10993fd6942372254ec5639ed69905eee6b6afb2bda04685d34e3d1e7e1b8fabf9fc1a0418623c014e27b9acf277097108cbccec1be5527e7baa2ab100d8ad16ad1046f84e728ad3daa98a681c7cbd520d1ef131dd5d588325b390ff12e7b565c04de481c03dbb16f24f96a9241437ad31aefeb336ff3a1669aecf15302b26528f90b0ccb1853881d89318edbf3929ec5bc45ad5cc8 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a050004149f14ee6f6cd3ed793d7fa5a7dceafe71ee86f6c6 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 1d9f5b7a9786d2d493b4277ed95816559e6521ea07fa308deb217baadbbda9595fbe39308397225b92f2b6ef22a2cc7c50d91ee24d9bf0651a72f3038f646804a22288d4e682240e522f89d9449fa677c546711b0f0a86fb4df611a7a132ef996b33100dc92f20135ad466e24839ec6f8515e03e542f3a780c159f3f1811853e -S = 287a3784de71ed88e4621273a477d5570a0db6dd00d528ae7378858a01e7412a6ed335f30e0b4672d61a6f248ddfcf40ac8d827f847355fb0751e4ba40ecfcb9373a0439200778ce27391480c21938515d174db382e27d57148fd235b7663b9d4bd4b1f8bf1134900bccc5a0dd53bbac5336363d8976e01804b9cd089700fbe7ac7bf61f511e8fc3d0cd28f6e6207ef9d5757b762ee96facb746d7c514526b5c6afc71879e359130bbbde3110b9fd1d35c2c4be5a0246a53b164b3c6b5ebc96f10657d2faa629bbff44cdab4fb9aef359251f3b7e33d96bc96caa65a4ce7ca31ce65be880560469712de61585c59c3513bbe87dca0076670b142fb8e6e65b18f21ed0d931a1712a4c6d62cdb6411626d70593e97716b22d10d3bfb6420f8471e6c75509f6495bc1505a8bf8172512cc20dc76875d3adec3a29dd7fe79e258344e8cd8094520d1e4e07e20092e5a4dfdecc30625e9547b23c6a27abc6dc058a2e51f769f6a232fbd09577da3a137401cd1c6e4c7ae959a52fdcf1f7aa4856db6e58fff070e20becbb735dcc3c7a2208ad7cef837891d20281e2045d47a37ab9e7eef5234de2d0e9e5c33b48bf8d9475f96fa368a87cd3bb82b0ef167f5533ed365e73b8e64657dc9c616794d4508042bf5b727d60cfdbc4999e8429d02ef91156cc74942fc08e85a9e08630887dfa4d820bc90c96eaea99af4b6c90beca889fe2 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = a96a3d33f00d283002fe250940244a11048a4bbd3c6d3d5858939ff767de9ab07c2088075731b4a9413f605d38660d374c80f60e493fde3196790b565dc293d3ec40d6115cbb4c3d70f48140bf385df21634a98a180bcf5a27a6e1b9884cdd40c172303946d4785455c48e9c1fc2c4aa284e6b18f0fa9939d3c329072ea1025d -S = 553b659961b3c76e6ae1f2cc56928e90488c5a6c8c8f6be7885824cd69730b356a57a42f7da21ee061bbdf8354a6ffb3b4c96948a7547c77e6786afd77bd6507aa159919d0eb56384610a18a971c396f994cb6f2b426fcb0b96a12836ae99f6f1e91de39a90c6df4e88af34dd59ece75f1d841466eb72634ae73fb66b952e4a7f071f09777033faf0bfae8fe80d7b45c3e46b063c06adaa71ea66e8bace380d35fc8dc3d61cc4687655b89f2a74a41f29f8ea4b77a806a0239bff08c596392e5a78472af3cbba23bcf8145ab3cabc66d04bab15a8330cbd6f626673fd16c8a30a6c4eb110690e2d5bcddb327619887a12475e0d598866123b2604e3d14750e5593276e3830f11cbaa30f7ee61479ee05788f1f7616053b98599bb5246261de3e90df969d0f84dc41066305ca493e5c814cd199590e6ee20317ad9acea9ec22b57185d334c17855485edcc3d2d7e939800c12d02b4bf818c72bc03d9d06c228aebbe9dc7d018349fc9ed8ad34249e05a99cecf3dfff0e2061af2e6357518758b1ce23db5bb2d69fe5fbe64b3e08b193c30c647233a60372e64cb550f90a923321cec4ec692b3d2caadab37b6fb3826d591449ae2ca3a6a754df669f3a5beda1b191a8a2107c649d69234d83ceab0a1c0f65bbb9d7f518a0106c655b86b3a280dfc8c75548612b01bad47e7b1c232a0af34e7de7291eb9e747292e78b61fa0c174 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = cb9fd0e59bc6d0c1b1ca328db6bd9205ca50ab8526e81dc000f46eb5af7d4edf10fe1fac2877b4310bbd591cfc1414ead5ff2b5aaa57e621a99b96df4487d65293e811c9f3ae45dcf443065b721bc584018d52798fe1a0f144aac92dad56512e1a03af254494092b330440325ffb2c3b169f29ca1dadd2979ac80c87311147da -S = 7a0a3a76ee0fd8be7ab380c909d18702fb0ee2730c61bdb7fe5623fe62137145bd555dd1945ace3c46888afa725359bfa21028dbcec113d14948a95a3ef8fde2a454d56627de249a7548306ca4c042037ec8ded524926237d69bd4099383e0fe68cbfa1d13542955aeca3fb27e1c21dbec1f6b763c0e5df2efb9e3b0a5a5ee439c91832361f27237f7570e0fbe93ccaba416a2495daa38a7adc15c5f39ceaeeb9240ef19e6e58a07567fa3d8fe5cc375ba28d15395a8afe98b71162609a06ae34035f6e92e7e58c6e814aa9714880fc8403bef091396ea465bdede70706e514431ece1a30b6b0e640456a3c353a790b5e9fcd1a75177aaa092af6cb07221df11b9dfd9f9e7be02b2433841cb7e3db33a5e4010b0c411e7c823af510c80c5930279b7f655c52d7abe24050561c5ea2f290a8e59d17ed8f7873446ac329095814b47d2710648090aa52b4e969298968e313f7f7e49599bb01fe361e1d16ff10d25eab366ea47aed18c98fb87c1ff915bf040db4a46458e12173823e541a47f7fa92377db3070cca6ffb9b78e36fb90fd662f47605b8872b8556c886b84a774dce72f92f8f673f55f8bf24153c9f18753ebae13d999ddb8caa25fc75ec58f29adff866dd5ea68aaee641d9e34c3783187c3383f57a88ef1b72e90ff9f512a6061ba922954f63cbc0726b2935adee477a14e6b38e7115be26b314e456c65d56b3a07 -SaltVal = 00 -Result = P - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 0bdae31979864502cc9e0cc38b9d97ccb0aa40a0076de142d72197e9c4eac5fbf4695c39718e5a37ceae91100ed6aa57c15e695170c133613baccdc3c154667d400dd893fd192b7be7bd5ad0779a5a4bda3b59ee52eb4482dac98b44091e28dc38edde8ee7ccbeb45df3f06c8f93b08e436997e175921c8efaa15ad463ef14fe -S = 34a41f46718ae045c386405e56268514a7baa1fe63c6a4e1c963b1a43010720caee088df14f3ae4681a5a63f89966ba2ec3243fdb80514a977004680770bc8e7069acc7aab3130532064a74f14e86356708f32829ca06e0749af4c6fd8210e2137bfacd11087630828afc4a15d01f8bc1c1a59eee3b6815e4168017dd572136af46860d0ec0d8b24d342d8502c09528fe02ca39c78daa7eb6c6ab0d9f063d92338f68aa7b165b05d044e7f9cb9ba1f059058c15b088a3087d6797658523b3f3950ff37c7fe135886b0b309b5e3d259993e1373e7c86626497c573264d928ec0c3d653cbee9403f12de12c7790c54e0bed9cbbe70aa78094972bd921cd0dfed81ea6e91df914e83e75dbc714eb89e7dcf3dd4d71450424898133a9bc67bd4e103422cbea4adac473efb16c6b10ebe089ee60034e0c599f66f836574f7207180cd6de83e3708128d867439a90748676fee209dec01acd90d5003fcf7dd1e919bbb3ace60cad0964081a8eaed261c5eddc7384297731cf9cf892730b938e8aeeedd60b06617fe7639c2f3493bf96cff12df30b19ae86c8edb0867f5476b6c381301ba9cd3ccd39b12ba11222068878550cda07e217185eea14f75bc44512490d1aefa18ed11729867e4e16eab49770747cdca5d4c39b451d50ac9432c42bf3122da7472fd58d95ce0937d33818449ece98b64ab39d1d0e0ed5e6ac11f5b119dec8f -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c0b8e0726c9d9bb66179c5fbffb9b336ce88a54e819789583af5fface -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 0f46bac55d9e2d3bcf07f70ffccc050fc35fd35232a87629a69de0533413607048d368b88cf193ed0c59e68e97ab574e68498bc506aee4646801bbae5de9eaa52ba48e8376530bab649850dfff635cb3db090042f897e71fe965d58f36ee2cf500deb48de36d9b5d21ecbb69fc9d1c2763c8ba32d10b884273f2b45c89c82d46 -S = 5ac96146da56064477b2994f953f31906fb9f546553551c4c76b4811074194dd0a4622e3a53e6c9d13404dae87e4f13b7142bea20336ee033295f2ed94405d7ec0351d880c78d753ca18dcb6b39735c588e656aceae827c273068097b39d1567f921a4f2305f7543fe2efeb0ec47a0dba7849ba4e919c388cf05de325c2399cf84f1a167a0895a783e167732020826d5735e8b0b7cba4ee338ff586cde712eaf638e7163ba45ef94818f73e7b7160243ac366dce1730b9ac0937532607f9d5f24f9fdb1e227150d0df91a8ebd951e7aacb371c0ed053c204b22735ed7688d587cba4a23f7857d05fdf97cce9f363389832c35ad291757c0ff8ff1e5a5075aa97856cff7838d3ecda3450a7c9d27f0617ec80c94a2e2a09028fca6e613f902399ef4f783e768f8f62e097a2dc52dbe096bab99cc4d01ca7020d72d0566cd6b8b0df6c1a1123247097b8ecd978925a540e05c2acd9d65d3e64a6b05702824380c1a24bd67d66f2b623f962e89087f08c5695b3f9655fdf24856a9f6561f4191ac338d67e90bc0c747ef7cd5a115d47aaa9d048ebc84c098383260fee49bdb446d1a153e51b0041a5e34bf71ef2d9b579067138a492e6ac8a693da58d5ff37743de28411d56090ee31f9e08cfb8566c7067635a30ed65cc24d40e1084d6c4164740d0770a88a287897b34fc4490a7f565827d8139577c0052f4760ef17c5f5978a3 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041ce07ae5bb44ac73b9490d62cb7f02d236e95b023c7aba070143c6243cefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = ec287cdb5ee54e8441dcc0662f98420233406c61c6bd9255fd1f9701003d069bbe9c5e71df93ae2afaac624f094c5d0a1a97482d478e2975e77a3711068eed5e13c85df5d918c7e7b1c46a47f50b9ae9b709136ab3da8d7083029033120c8a3d53721f6e33bdc042cced7f57db1b2129745d7520f4eae5ce387f4b710c0106c0 -S = 30a67f084b071c9e0d5c5f3f797cd89441932da1e5cf9b7788855d03f6f2a52d6519ae67ea7616d76f2a73016dec5663f6e337c9c26ab3a4e0bb6d3f8ea18d0ebb1693ca5419b9cd19fe747f486f8bdc40164da9d7024d7fc675b7f87b702615ba523b59a747550a26bdb8a80a57dd14698a17b6ed4c4f04fbcb3ad98a2190f02f508b681a517663a3c0a4516f92f87cd9077b674e716099e36dc50ad24f98bb74a6afd0f85318a67abdab02fa2853d206acf49f941706cdb0e632244f2be99ca1aa9cf36f2383c1092371031a99b7342714fffffbbac48ebe8fc7a1f31c40834090d7dd9d905047ec08aa0c73d1b2a3cdf6c10d3930db3f8675a97ec1cb175142725bdce1d73dc97f656ac1441c967475e46b7a94ed38d067def9a54bfaeca15a49780f5caf2e42ad3b5df0787c1c06844b28b68dfb0d675e235a4114920e327e870e2346572c3b04aa29ec476933470a0e56fdf3ec0f5e1baa35265637cad3b24de388eb4b68403b4b6652ac1c258cc56bc4cd9d3d804632da9eb23445154fbf26d2eefa30ec2916a54b052ce58baddf426680477aabbee34fc6d98e57af4342b2942c77dd8695103487203a77d4f8e4ee066bf003f45cdcabe7b57b46b34084bf22eb5c905ac76df823a0e9343fbe4a868a6e0adb58bb5725b8da3c03933d95b4012498557bb78d096b810be5f403b9063243bbec780de51ce927d7294ff4 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = c9228bd9823d98cc91944bd362aba13e16f6cfc78d9fea74c383e8be607ec7f28ae80cd8fe5f6f935fc7d5c8cd907e02ba378055f910744218426fdbf01334277a66a7c8e58185dbe51453204d77945be0343ffa64c570f7f99f5e00a96f8dd640a345f35e2c426fca82ad2409e94b1130f4f5fcf647485b0da09d75b3193bc5 -S = 7ddff91ff1168c9bf0843a1da3c141e1856e312c0d83c4052b9c134d3b0fa82a53e4e1923b051be39fb6245d6acda63026161feed4e2d56d83677ebb347b1849d479b3da628b02a3a411f86c443e7807f6b5239950bf2b060da1c6905dc75ec2e4236b8cdd77419361abd4720267ce447c104f437afab32af9e1b4c0104989ebefbaa7ec0c18a065a0c38a79ccd9e40eac3554d78f3dafdce7acf06e19e7e2792cd7c70bf1f0eb15e32c7d6c41331ad8c8a1bd70d4bf74e64548175d913999aa673c995bbe8ae3e68c362e3427c116290a9680d6d7b4be07de3cdeac0a0723699be8ad032f794610510ec4f61eaf355e56e15d053007b1d228a91b1f576597c1c78636c2202ff55c070eb3242b48eada77b90777001067fe61907ebccce40bb6b6361add71717c3a429267147b341bfa8bf0400512c538948a9171f2d0aa278aef5b950b5b7722b372ed5c2ba1e18562f0fd7b7da7566f61f5adf1f8ed1023605f360872cd963286bb5685cfda4968f412922df0b9b7cd0ffd8dbd16a2382b6893b4d075bd0965f4f7e4e2c09b0bd00217fa6bcf9e0ac71309e071c4ca0077bcca9c60ee5226ef058ff8b7a076d68cf161b13dc90d51f65babe1f4727396f070af6b3dce92586e0d31028e6adcfcbc32c71551c7d688cf9c32fbb26d03c5fabd455fc716d9a9cb82a740a6a46627d80c75035b0bf02dac08ed6f45539f035885 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 91e945fbaa97924f3e6d9ad222bb01e935b7b41df0c2207a3eeca2348eb93e9127269302bce70e9341f35f86fd42293bdfd5fe5415f88a16dbc40e1191e7110311a852fa3f2500b9e2df2d5db2798140b1bd2b1ebfe01d76690779330309468cf67768295adacf87c83bee9d69e96fc0537625c41603426491bdcae30ba847f4 -S = 34dd79f3254da1471173aff6aaf54ec5a8633b468af99d925ec258438f3bade74fd1f23c631f94e6db57b3fec9b05ffb18013cc090bcb1f871e011241b352549e9dc72349681c10bdeb1ef00f99d4a70c48488d812bb621d0e3b926876b91da56541176dcea55152d31915f9e633620886f6264c70c2875019afd51eea4ac8cafc17842e2e035233d4679cb22d329a671b061a2da194d00dfe6a3d6ea3c3b10369e0558b68456b241e7c368e2492bd0d5cbbdab42a8526acc04cf2ed43944708e99980b31bdac37e754850c0370da4ac8b71b5147ddc91dcb7509df44b3fad89c2cb4e147255b064ffa9ff758a55c045f27bdb4b12107e1820530431a28baa16da02925ffc8e84cbc7ecf70c2dab46e246ac51888a198d85dbbdf4be40e674e562533667240e043a6e8a7d1a026af2ecf6a1cd24934f6469e28b14bea0f46cd333b1043d837b5b21022c9f7dd7713f8576152431746b54c9cb9a7ed3bb5c7d027281cbdf9377187fd584b8761f5f6972ef357cf8c54c9009d9e650aeb4c9d718919706d48ac76c404875e95d60b5cfc06588e1bef0ae95c31d13a27edb86dfb643d9d2f08373d7af39783804123202f796b1a01da28932a103a817c368f9e8bc8764cb949e351e0cfeac9087eca02e097662020927940b84dce30f22eb053c02f6345f6de59c2428a0c462020650db4e93c515304bd6fdfbf882d29034fe218c -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420a20a34a9c3d9d0e915b9f010007a3c625bf71d96211c68cee82075ad2dfd21e7efefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = c63bd2db43b2e094aeeb020514d2439f6d8d04d0c40b403398e0140481507ed617a965880fd7d975a7329deb459ae2df5ac656de8dd95d4716369eb86796c2c6125878f1e718bdd65c825aa73368aed95613ad1c06d7299034ea51362f7777a580ed16fe129d13219784432126652ef6291c1272762e2b77bca43266211a24da -S = 18fe9f7495370f1b1a8318e33ef759e72fd463d358de45d4aa412b1c149607681d12d7da6b7640ff21b53745387e6a5c9effca633c0c6d1e7c150ac6b622981167fad90fdef6b0bc71bf87cf7aaff12afeb60c823d95b32e29f84fe500248207d792d27965f915cd9527a666985223b4b2e7d72b1819cea49c825c304eec56632188b0907b54e2fd9d805a53e58acd08b291532d9500c64ff406d54c0f43e16c5a6f40499d20383e6537bda582b5081d0db95bead3b436c7d12d5c9ac695d4b660c79feafaee8b79f4fd9147cb5a14f5c8700c868d24bf0bd086397deee79284b3a79e9b68560ed6e863da75da37d324edf13243556f66982745b2ae931e3f2348fd8c3f206b183cd8768183c92ce6a0daccaface91f3ad6dda20d5c604b5c474918fb124c494f76d68ca7192ef25bca03648eae43008f9c3482bdb7b086ea92d41ba3a243bba037f7f08dfc6912218dca0fb97a11acd0ec3432d1fa4fd73f4d810843606374c780b8fef34ec13fa6e26ca05124d8029cf7ee6f9cc90ddc1196e29c4a6ec9feaca4c2050053a212838ab901bb9df01e31b6519a9d4f019ae5bebe1bcafc92f79ec70bb1e1f1db62cd964b8a15171edc72081daf239b0f9306921444032295b4c7428873e142fd20ed2f2e598fa346f2a76579045c727de99294e2245db6d62061d1a2cae226f0aade7da4bc32fc6e750483cc20fb2f017178be -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = d34ec8c4045b0433954c81096a09dc82a0c6c799157bac1d2a949407c7ea480ba0f3b56db735951622014ce70f5d104d05424d166d084883501e029e62fe5fcd406087a8f6ae8d08c4b94f6022aa9d51013b9d7854276d8bcfde0ba4ee7e72dc3aff061cc8ad323002dc501da9d7c9b51b197d68d2c0655d2e3e76c27452c960 -S = 4082a6bb4453970119c7f4cd61253f441fba30c004ddda4ef25f6b9f30edfd3d2db0f207e8b7c34f2d9ee23d692c850a29e70906a98fabdfebb5fac91722dbab0f19ea0b3952041cc448fa9e3eb8b54965e068a2a0df68b44f2839b9d10ed07f9d92039772bf6fe6a6d4db2531a03d7eebc15a125b87ec9899cf7b14911dcc4f0880b2196e165c1e45edc0de4abf859f30d87e3bfc3cbd69ed066aeef26869ec70012f0c1d1e13ba1bed0a6260d0c412c8e4aa6fd0f8b716ce33fc5bbf3562e98c307b1b8e617b26aa3f55e3dc063f7ffe4d03844b0da97411f3996fd94416648724148bffc5900f1f9b908f2c6ff5ad20c90d3f5ebd76e3aadab7b9e9e55ef50ecf4d923249a83cc59167e65bf6593aeeccd750ef0c3f1029dae3fe1ee23678ea70406a4e4f9f1165a48c16659d367e2f1748e104ed1f898db701336c680400818cebb47529fcd1f9da787a025c316a2baf2c1d32eba2eab393830eee7a2465d0e43c19362e64266883be22d85a0efa83f3f837d206bfc96993d16199712f6947b39cf0875b3744d96705ea19c8a173aeba23c6a049aa668a66f2c6559cba601c4a8737fe512509e90eb5751abe5c45f22e9fe31dc936b7e80544daa4e26cb9d088a623ad6a7e70902196a0973b8bae0866513360a05265ba92e96fd8e7a09e35a239a0d2499713ca0e7b5dabb06d162fac90a75e9b6483b3513787b66b9f85 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d0609608648016503040201050004206befb2ccaf4b531cf9ffc53f938035025cfdb7eeae29da84ebec94e716c003f8 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 8f937d50d24a1a6ed858d2e3de56e5c23b917d5a936c87b84effc06d48041391caf42207ba6d23030ed7edca864752b99ba3b089b308c3d19668bdcc2578995d4ac9ac502b347de3a37cd685f22f1bddb3cddb0e0f2ca53a311b1d45f9464edbf55a42b48d69d0167d8fb69c89d6e8376b57277211a2d4fa0560075d2d37dc12 -S = 2df1e58e7491739bb027c6315a70eebbcf37b8e5958df07578a589a47cbaf1edb23ff2e676f2f273a1cc0babd22e0bff874529cfd6479ae5c7250f06579eb212dd3f4058c476abae8e94c89afe05746c3aea93155cf03195ce5f4eced399d2b61aab7f4060b69844cbff6303d264c4755be78af001d125af461fececad8f46a9c4b07420ca63c4212f80a751fcca6a4737684543fcf07b39089baa9995394766f69239479e7c9778c644e022dd4ec7e07a769aa75db2571e58a5e0ba1e4377e9677092bc9dee9d9dbb448441da8f4385b4d4f8ccff4b3dc3c3c3ac8ba11a6ce8caafa930108ba3603c5b0ef65a02a7afebebf605aa88511513a69b3086fdfc25c588c4d61a06219d0d5643410d3ae4d78b2f695efe4e0b82161c53bb9d4b8a83692bb16de8da18b4a6c2abbd0f6b0e24229077fd6c3bca918bc9d9f4518598238df0c925f8587fff0852c44e8107ccbc1ce6a9be3b0941c3b28bb03c87eeb959d719dba9a64a338c7b9931cdf6bb169686de1f8de0e1fa74d03419d164f2c8bd2030562705d1470415e48144181dfd31cdd4219b5d22f9a4c659923cf5c4edbde18e8277dae11264c11423c5481402e80af223f0c4faea0c2c7aefacbf513962c2f16af353ffae1414b408f726eeb946d7c4c8577e72d8f1d49ae2301cf70abee46d286a6fac1b888c334538abb3b830fae595bbb19ea9dce46a343da031117c -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = ef737d90f65532a2693ef41fe916a2b970c411409d3801c54caf50ff6a326eee086011bdad6e2aedf16c17b047ca1a931b1a0a601d174843dce7f52b969d62734e02c8c220953a30d2d0d7aaabad449788695abb2c881b5cd819eba41b3bfd47ece00b66f6d14ab233f39dd4bcc8080de03868197392625a68ce9a32a31525b1 -S = 6d2d3c16eed39f5b46ffc45a8476c0778bda78d2dfd246ebcfbc74f88c5ab742cab942de2da36e1ec2cf65a43b4ff04927021211b35d6b6b2136ef1d69671aa8b95f6b55be4751a54b8df1bd87518e4a736bff9ef849cf7bc212734b77a7fcfd3ba99327884685a146294ba0a45233b03e97a27af2f615952261cbfdb1b5bac0f5fadbb8decbc4b16ac96606242a9489f20fa74f726d3c45e0e0c515382288a8ac19ccd3eec7ac94d30019dcbfbf77f9dd592531eb1ef4eacf9c38ccc0414317a3d7eecbac02a130b8bfda18f4e0fa6a5bcab44d35e020afdfda351afa1f9feab93579861d2ac39e6c8499b8b5777a6be5ac77b3ecdb12fe8189b0bfc00a4a3e4e6041e2d52a5112e8af45e5d0a45f0b88ef66ca29076738ed07129be4493916bd885e128359e860ad8f0c0d8fb649710cc76a0d3ea701a2ba1d7e77ff9b037c51f93e9b9e162f71da900c07b42ce0f02fa633e8e987cd063b8659f25d190f3d35105f70edb65201dd67d9565cf4e718f4db2f57569c8c88f20ec11aae3ba3bc1bc78c29b2364acf2f964fd2165fe82d8721f1b16b668804468f0697643d1bd0efc5d45f8c27b7804b4931e210a1eb789c8422d7795a9b156fd9762a56fa27b7d5adb2357797ba50dea7ffd217025876ade111d504799ef8fec084e061ca0b884899701a9265969a9a027c5337cb0e1e86d3d5d1b8a0a80eda33c8936b436c83 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 5e59add32c339dd10f33de88b32b8cfc1dd8fe7684693e27633bbc0dcce7431bff7e2b943b13d1b8d47a44a286504171093b62a6e57392cd8882c4609648e5e880410e65580bfff0e422c99ff1efcaa9e901decaa89ad4e98c6d1ff9cba6ce1d0a2bbf0f2b210fc266b3d4469b0e0fede6b0dcac75e3ecc3968435a01409e801 -S = 5d7f2def0ab2f104974b66e6a7ed79a4cbe4d9c6ab4bed75f442703fdaecf0e76eef5fa5c13163b4fa661137c877e4416a3fbb4a15a2dd534267ab860ae73bb97abb5e48bd5ac60108baf4aa28eaa5b3aed8f84adf06063e575b39c932a565ac9689a6ea93359f5e5c384bd41af7627df06169ad4728e9b17f5cc7855b5e2a88d4417142bce9b45ffd82e785c6cc8774e3c78fa637ac69c90a2198909fb1b611ba28ec978b1813bfcedc2a4ab6f8a2f457a146be5a6ef6ef90a91caa3553f96a743ef0f3c2a057ffee3ea2b4a3a2c7e9b26ee2e531f8b17216080096527df06b83bc11ecb977053e5d81f6c3e30e0fc5d4353bcb7bd97906ae7eb4bb1670fe28a8bd674c836e395953d3c3e64503818e3c563284c7d21545e7038d3dffa0182b5e6a7ca50e07d7dbd3614c4b2006a4f1a14b77c3dabf98459cd33ec5b325118f9e65b851a155b3f73267950c92078c70fc5dff3e9f07a9c5ef42fc210b5d2b24a9dec7db05c12e492decaf4b448c9545ee492dc0c2a4a5bff2ed32a8a0ca0a41b7f7455e622763319054e1212c0297bb604452f82393a3a96f54b1a141da0edeef052d2f0382375e501d67b1a83d0b02bdd9c99fd68063b908da1738e88b2da99979abbf73e60a4a295d24fda59db64486bfd7eb5b8dab06dd22202d58422bd450f1f698d7ba51f71ef556c5bad3d1461481677e501dde5b613fb2ccf85fb40f -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 655d108236ed81085d937f81dd9056d691a1dd531f2507f32a81b5dec9c4ce30388792fcce182b912fd785fbc3df60cd67e9a41e626ef4d29a0c851b082b313e69e0c79b3612a6e8d7db8abd1430a555ccc5f293e92bc643933ba8a3a4b862215c30586757231995bb6834cdb6cb4df528fb6fb89ca4a4ce7dd8c37e87b38a61 -S = 3363dc1b2f8be1f660baf2b61348786a7305f4bc3e7f030318a743893e41feb40636f768a286c0e82f0638eece2d7f53f8b5c8c5052e6a942e9a99fef85e8d5f2d83e6768515ca14c8e8dce14717af8fd5a2ef209c9b8bd314e5297eb48aabdb7875d1c33efbe9d18ef9021ec41cb54926bd3542243db8c576d8bcfc61b5dc6bc8f37b91e3d631bfed66d97e9a39aa815a8c138932d4b6087b5413c888e97caa07b54541f22cda57a9d06b92047276bd21bc5ed946650ce7f9b07cc2e150bf14233e8571a8f09259dc1620e6f55609b2f2a257dfe250649de5e7dc42fd7503809d0ca8344cc92571a91ca99abe1d22bb6f56e84ab0ccbbca0d8267fadf08017fe98ec57088234e81546386ea48725e0edffff0738ccc99aeff1f3977be58761373749175e7adb270ca322f15f866a668b3473f5587ca80fb61200acb3c09bbc087419a5d4a3408131571d06f09607f8d0b07a285b79d041842e5cbb682e11db41b0c36784c4c4895d007f076d3e3ed2a13d9f0601cd4e95ed492dd57505f76f119eb3fe56c899c20aa745335fa2df73552e95ae596b1ceb67e3a533b2df1ea1ed661fe5b46e1e31b753211eb44fe683e26fa1faee65adede0c86c788a067cd1c885ccbfc0066fa94070a310cdcd19003b6b7fc836c79f19e7e402a549850719c3cc3fb4cea67de4332680c3b891e0aa42693bf113fb7210e6b0d470d30335a69 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = ab8fbba0e6a56a02b0b42f139cd656416b9bb654da952b09bf1a46fd544542cdd33e3a7c43bb9a1591c7d491e2c354fa28aab5d1f39935ae8b8e66263b6f27f1ef4fd34c02eeb89d517ecb5694ad991beedf8127c2bb21ecc9ea0ef9611bc821284beddaca43ace317627d2a599c0fece4c3821eee05d70ca1b7a5406f510da5 -S = 87615e72a27b387de06e4e8bc3f2e70d24d061abb00a8a006456ff0b8bee03924307420517eccb0eee44c1f8a7458e13c0694c1bf7855d5ab1202807339bc82cb5cb3974b83d4000751fdced787295387acb814c2ffb4f636704de4595bf281d544f72d676bf59768389d92bbb08ad9662481129af3ea0ff2a0faadad65c93ab0029ee0ddff3ecd02e0bae13c4597de92cbddd6fcd9ba4d83688db7c278ca55e5c15b061993a1a53984efffc0ed72f55f79f3d11581ade9b651a6ddb5ad4863e3b9798d2bdd7c346174b114778f49ebde94c53c406ecc6812fec601995236ee09a8df5d0663ec4cb49fc47599b2b884cde458d6cba31abac1d3900fba8d9a053f02ceec3dc9f372b285634a3b21d4c7182c891523fc75bb8e49494d5f5eb4dd001c40fc549f9f586e60fd2f9b3b3dff4c8d33978193599de8471d2db11a4586f2be00c2f03d818ccee82f183f784c88a5d04e14ec99ef808e3e68333fefdaa414be5d7e817de3472ab212c40de7f172b3e62d203d7da871573f4f1fcd0f01f49258413e726cd91a79f465dc0ab69962436dcf52162c09fdbc151853327fe69a51ea91a339138742d555b40be06df4ddd594cc51baeac5738c96d0218363461bae49da0418fc3330adfd9ec008e89e2342a9084800893b2eb86e40e27da0500a171e234098079b91e08780d5d4e3308e5158bf7b4de557662311c533c9daf553a -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 450171e919ecc10bbf1d05f41eee02eab8eede088a31263433eb1652593d14b7494f7de1dd9fa465a39918283b6726d2010a9f80edaadcbab72afea43e007a782a44d633d006ad8f57e5f93219dd92254c61f187e2aa3a83ad4e7a7fc7142c9631070349bac9e371232a307880f94cc9e11b5b8532d94a78607e0f4bbe2232fb -S = 0471456bd38ff2a5adeb19b73c35de60f07d7907479f9e6d5735dca75ebd3ef499194917287ae0c3334a5b97f2be41598917a5d880b3d021c61a7acfe9083441661f56fb984ec6717986c558a10d108fac9e00bbd5adbd817a7684edd424e612c8a7f60ff1c8056067f0eee1c6ce3a4ceb6c27c735f0fdc93cfb521b529e1002659e6fe9cddcc79c218a84ee59b7355a43b47b5c4ece8535e0874cca866e3981dec3d1996d4dd05afab27bb5dae9d6ac9dc39e957329eb273254c4e7784a29db26696bd0ff872eede9fff869c35487643755d9cd5bae01c7858b123e4f9688b1d2607f349d52c828dd6d76ff41514565564d39038814841a0441c232411c8afcb15073739f5d5c537138b9bbda60bfd2cfea2847678ffbab73eb02fcaba9e4cabd7768bc0c3a6009dd78f02a8d791f5e1e30d7358b5a642cf0a1a838b954b76a15386109926595b2862de80ddfea98e6218efb925cf5d6434b93045cad5bfd1af36e63a98c14b8f5c6974f04e5e52243bf7cffdc8cb9c0a35fc3250943d07037b319cafef02a2fd21c39aaa3da9f171f1e9c9613ff97d3a6770e7639ecbfa7e47804d8833e8212064d091e02801869bcb2bbbfc2be5d21b2da790ddd7973b6f5b9d6c763cfa503c6243851461490dfab31cccc6621fd91fc1ae28b4b1d393cb1e41d397852acd98fa35b93b6b4dd92e2d5fac7665d8c0b3f7d03ad3048b6854b -SaltVal = 00 -Result = P - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 105048a958c92670205618120e4f1f5f40af63b03d2dc8272ba8c13743c8696683e3d051a21d92f149d4af1e803b9651674483ae26c40b4226d2f689826f4c33b86db227a589f7c9b0dbeb784570705b8535d35e3b165c771268232e0684265c19b5993347557d7ebb32742a4337d4060248fac7656de14f5833f32fb94f1e6a -S = 82bd70e07ba8994dae47a4f8d639168e5e9aa2cf70cc3c011482d170efcaa8aae5d2c8e46d63a583c20d9b7ee21e39b86429aa4550c9f2df8a955a43e2ebd3ff99e1ff3625285de3d506a95e183c664374eaccf0ecfe6d1fdbdbd33f61696064815a21e43600fe7bd45830208970bd63eaff3d2d796740fe1917196bcdffa4107f6b143a7283dff052c1b732fbb545d2772fc725cb0f1f69689b57ea25a8e54c6d68bd10026b911134f034c9f9499f001c71e67a1668dcf11e3974c6ca2658a4dae79a103b1bc3e01195b8ca7da0a09923eabb8f7d035598383404fd7145946931cf2f577c3d2356aff6e2b37f4b084c00943de3c90b9f944f42af472a7eab05cb33d144ad0b36c2d3343f67af4c78bd1fa86b5dd66c9edbba788278dc063c2a6754c114ecbf5e12ce76ea97b9b83431f215f2670a5f23e27b1614330671d3f4b5701ac57bb8fc8a4eb33d2203d3a4faaa1513471d94446a6bf170a78389738567da8206f8e2a6d906a428253e7a2bd95b26ede968d6781b5247bdaa067988f671f9049da2fd3e81a9a0e419cf077d54d524fa561a395af3d443ef4e56f217fa5e981dd693999caa88da4a58bb7cf5bd0136ba939f507fca7ba93fb95c8e33837576230a28f2e66ae1c566f480b16f7f3c770128ffac3b2fa8dc33f1455f8178b1c4dde3d2df25c49d9d2458fcbc1c1c5c33dccda3987f50455f898609622063 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d0609608648016503040202050004303bcaa2105477a151f58e5854c43aea16ba8a3f7aec859c767b4c972f6516065230af636d2de691db4bf4eca0591d5df8 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = c74267ab7b27fc613890220c1b77f9205b8a8b4a7c8aa4f8c5f1e41bf5d7122b3216b36c42addb71fd6244de02ac9d72aacf24443a49774c5d6da726d14e8f1360de644112578d4ca1dab4042d561d7131ac3614b6117070c6b34ec9249fbb2c3ae2a1af53eeb7fa0a409b0602402025d869e94356a9376bea0bff8d5693407e -S = 5daace94b6042b542d3ad0dbfd6987222d598febc1e612c89c008c8ae828767cb3248235febf65a100367753aa8c75445b08aca203a83d471b090c4b40eccf1a375e15e6db3cb49eab5db7bd30dd0ad2750ec9eeb09f1ca646f2cd7941cc53c1a5bd982032dad6c022f4958785fa37caed46c67fdb8fd0b8571494a255a0d8e093b79811b013e8bdd0636345c59fb31d1daef1ff7c8d777721cca8b5997cea173c2044ca0b0c552136ef57d5dbdc9383f034daaa20a61d6db7ba504d0ca67d9d3cc8df5c52603a870010d7024d7fc67ff2b719551ce5b1dcb3228c7c17b0772e3160ff940789935c563b72ad97302fbd276a7d17c8d6ac70866d945be4a19b3ed1256339c005a03c1bb0be9549d25a94daa4459ae2f6d3b2b4ebfddc545f76c3fd761016d3a4a79301c6d94d4f84ee9da965f1c9ef2239c6a7cdd28f4badb57580177b395fee7c684b70c43d92b5f5718e3353dda2ca34e10f0a1595474b3f0cfd90ffcd10c3ce987ed72da95aff0d967b582f9c7ba4067b77f728986bfa3fec94cca5104d361c185caaaa1daf8ae9a54553190d54e16c86604172cd53ff7b37060152d1fbc61e54817580aaa6a99ac1e577161c718c6810a735abf2cad04c51c901b26540e0546fe218be87b12929f2aacd48d9768c51d690820876b1a73bf3d8c86fbf3d37a0f2f8aa9f39dc8b86e3990001cb3ce8fe75d41ad863fa54acfb -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d06096086480165030402020500043041bc09c6fe8e745e4fbb2fa6312743e27bb5e82870600e0f80b1147e6ea9f392710548d938b910d106960f7d1989f8d0efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = c0af5d4f3251d02d37abc8770b5884391a66e7a1700087bc714a0280ca8d910fa794df3a27561b440cd54be9b845e49f5571981c535b701817221a54f12984db4f76aa883158acc8dd4d23a1d422b5f4045ce7ff3fd73325ecad5bf2fd59fc5a211d66413aa1ab4111dcf6a748371ebe91f07b511ebdf96b59b36a61d4652112 -S = 326963d3bb01390b62b4dc1326248ba0c0bc44b240e7b01fd5b05bb138777b31cec22ac0b0d53279ddeb14d86ef2acec7b0c3ba1c8e587513279ecfd6b912717d316ec7bb6aecd56004f9a110e3dafaf3f3f9997549e8b65751d1c4574dcf16a0df08ab705289a9b53930f2bf90c0a6a8f461c69d659929cc2b8514f6c08e07c0c542ec8bb2ab42512f48d8c866f4db4a309af0114e6b9ba1c382f48580a9befad7dbc1d9611de97fede893243fadd94dd78e99f43199d76ea3707d6c8a2e1339b534238bf1bcdf5c2b7144b616872c7a08d4d6399228d508d01c81e7dc345527ef087ccd983f94fccc1f5f8db9a34eee662484881f38eca79426ad87f4ad7ec35dc46c835ae5b38b8bdad63515d710eea32b8024558dc1929e704225debd4e9a770706c78057678199e4d006d185556f27bdfcf5330bbe9cde8271316f460efa53840dfaa30cc1f230395c4f12d7e0a0ae57d71297dcce3834a27b4f29a2c8381eeec3ef4e71a2b54ff1ee09147385f5e41fedb3c3df398cb53e1d19c97fc0f5f85f2fdd0b42cf2065fb68b7a2850e065016e9c3b88e4a0d17370cc63f771de00536c57739625372ec08d8241672ce3aac63dc843d17a227a7f6c68b85eb39e4074bd7ed49682242b213ceedada0db1f2ad978620c43aa88325284588a5244f82083c4420572e30486bd40902b71319c9b246ae9bd7d994f9396ff2bbe844ef -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 42c5ea617a25f019329ee172e4932485518dabd01983249189597473b4a6616cc5ba8ee693e0ad1d76e0f0c85ac8c0fb11ecb24cee2cb7358f7593b9fa8b904aec0573eb6d99af92a899d9d0fabe5cb349256eec9797422dd60d7fd5fe73f2cf5ead7fb72fd85e3f6fd284d2edfc5e77a03ec5f73c4c2f420728220fe9e9efc3 -S = 6836dff1bea541916b9ccce2695e921ff27a737ac54f4a5c3b2facee80a8dd3bbfe86c93a1af8da5c6b3a92c445dfac7e215fa9f3d67c9589dba858a223f326afeb8f5d0f92f28ac4e3671c22b5b4e0b4266f776aca928bb0309929f2c452b62d462675cef09388e5720cf0cb99351d44059790720db82ce014d7e795826833284bd4205c64e1330e30e09ff6220f62c013c117ace4f4286cd46e52694c4925aba12a5278e47de910dcdd820396febe5179bbc6ccecdac1883bd408530bde92e93c49db2c6fbb42e9705f29703763b21a8172489d2831889bb060505040940e60f7c5cb9f58327c3d3f7cf7e18ad60e877edb65222a699d4acdcb358fbc87e1e461468cfdc82a8cd7fb1f82e05378737f4aa741a63ddf6039b23e1aa19d94e7087915899685add8a8da8f64a93707be0b6354c8e9a8aefc7484bb45cd0beca493a4a0aef0b6aaae801866b905683c582bf39f9cc0768d880c6e4b331da86506b298c180cf95fa45e532483c55544371468088b4e378f37976c397e09f89081f0f0b6f4ba3be6929957f55f14a88f6beb456b70e6fbc6227e98c1e8a4a6f734c9080c13ed58bcfb3456cbbc217653835000f54956d839d4073571d8a42fa2294df1a747e88af53a16df1834203009cccd6d61304739872ab92be79a4462125ebc8bba909ca2b4d91b9e520d6c681c2f92070f156e31a6875122993e1d94fc3568 -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 3ad62d183432746cfbdac6d9c87148bf13df52e906f67c573156fc407f8d2f576983754e69164298b20172741e02dd27683c2c889bdaebc2caf5df5602b7995f7dc14b1a18cbdba5078a3607c8d7e771550de8c49eb3b752365bade94dc98c0ede585786299a661b643fb99cae388d26441c2da2f7ca0b8fde500f02480b2fea -S = 817ef0cbd8bbe2c93d49bbc09c5d5fdb0c36ad983f0e1f45b41026d3efabad67c69aeb07a0bcffd57c4c6ce95857ab1dd6e786f83d2bc7460366cf051019168bfc56edee99aca9b3862a77c8a9c22787b35004624a7baf963b6e1be2530b0ee43fe44bf21f52e23b2ea0dd7a9cbd77c960d9269bc9efe867f10bab0d27eee85fe95fa90ada2171e9c0acd17ccc6132983276d0c6f1260b8e20ab84ab4eaabb5db220ae7becb26f05e32df93d2a759a9d2d94fa6cfb2a54ef20ea8f486cf587eb2977fdf17e4b65bfd66497aab225254d53cba4b18c9b4c8e30e6f5010eae0d19d53b17c9ba8ba0afb5109dc45f7e39e604f57d1bdfe3a2354346f462036599815578c497a9829be3fd73b4d7fca27385cbe44faabefbc25fd599c3e817a606dc53544e6e10cf3182fdb806441d470f16168237685e2a384391c3b15663cfe9a00f938fb7f9362752e4377217c06c7419a2426bfbf76b503be486a2b90146e9c75718b208c8fc492f47d17e4e8f3ec9b1dd5a067cf1e4ced4617243217518653ee3f30ab3a2c3f95ad15e6939f88e169c643ed2056d594fba35c8e8fcda9f7a5fbf17ffc42ccefac0aeb95cada9b48fc4a9456626ec017b8dd995cab7720cdb7c093ffbd3b2c149cacd7a2328b6ec825376d19ff693a8c8beddb9cf2c67cc22bec90f1d4e0a310d7d7f81582b56fd2127fd7a9c1d3b8d1050ebbbf06be49da1f1 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d0609608648016503040203050004404f6c763ce96f5274b8ea00e1e795e0afcc8a1d1fec8879a033437d0c153b2ef5ed766002b39b50a10f9cc919f57cd0679b82940ad47bc8b5961061fe1575eaac -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 96c824575d1e537b1f8d27dda15040ab262f9416f0f61260032786362becbd41404fe9f8a9ad46b81f68fe16b3dd4b741396dbd209c078e744dfe8705bc012c90faf63bad1eb70938457dd7b83727d05e689ba04012c38a12edeb5aacd10342d88515a46dcbf1835d4c18ab318f81f872772fb54e12199b5488cb58b87c56996 -S = 336a1580b52f2b15e7fe7eefe6d4503fe0985bfcca17e5379d17d210be01e44394adce8d1c482db58ff71b6ba418b069fe15153ffac74b3f7190df14791f8532adf655721a5d113df77d164226b941cabc035853b795db3dbfe64a0a89fa8728071cec0bc1264cd9c7d43b429cbf868cd7e2ce9f5f71c6b1c9705ff2d99f99fffc6bd964e4aa85ae127e074a95e396551418acc46fd22d61711cc4dfd51428130b0036c54120723bccc8268d9f1739488e4874c7fd77a207a28b97f463fa0667adfddb34adeb6f11bbc1ea2e057120ccbae92c3504d14fa4d87768e435b1479237b61178e48232c6884c94f0f287cbd135ddb9629678d7097f8c966d1b74f288a8d307764cc34e3690be4e790c57627ff1e6ee2572afaef68dccaf441575dd5112341f91c0f20efc8a75047672c190403e8d5aeb1005e2040502d7cce97cc8977315aaef7fcc9c5b0029246839134dc72f72dc2e80e1d3d5e48881dd71f6b2accf21635252d82adedcf86f58dbfda3ea1c0624fcfbef191a89a43d5fbd62cf6142cb26c4cdf9cfc0d8c993b3e80d551ec56b29734ba77dcdb03cc20912ad85efc48d314c42b15120ecfcc03d85a43f2ae733fd2decde46e535aa84415bcc7de4203869ff945176b9e7047c5953bf241e3b537a93e62b412cd81591d658e7f55c4bce859bfc56683abea7e6e1f87f807ae05c52ab504f0341d301ad06429fd964 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = d44ccfb041a426cbcea27f0d5e2a77b21074beb5c175bfe5d39a833b2cbcd26b81519cb9d4df980e3bb72b4be4df8bdd56502492f9613baad984d132a730ca8d011e4e54f2b87060bdcf0d24d68cf74032a95354c0e0401238a4ba981310bdfcda1dad28a417f5e8db52ef413e1904052ce714a41fda1745776405157944f4df -S = 5272ca5de6f01c255f59460bf1789ad5fef5cd25345d701c045c3623933f6d44389c5cb6eb3746b0aa75ad49cd5900223ff998d5752ca0c164dffa90cd4a3857de3f4c66e9d3c19bdebc842babc4b0fa60bdf53b76efd35de73230e283a590f4f4a9b7658ab1e1e0e5631534710ae18c7b866e79be08cbf3c30bbe6c0daec86237c439a7f63e57640263a75ed980f5180dea5874e2af8348bb15b833055936abdd01f8e5d913499382496691b6c60b5b2aae76b8c51794dbf9d9e852e62c410e9981b5663c59a0e5ba5c1545643de0fc9397150518d7e6122334246e277570ae2bdc4e84e916096000a44ec2e68943589d62b24f45594f35a2b7197ec665d45c3d9d403e7510f536a0e214cc6e3391c0494c5d52508e777b851157ff091995f4e0d2131f9e40fa4e81091e46cc40c0459a4f2d5c198222f0c7b39a5e2fe86a6f964a966d1e66ea550627d4b21c90cf3beeb8c4901a2ca47ed8b3581f37852f582382922ddf0fe0e322ef9409ae860b251699220efbd41f09968d2787d4b7a79ec4828b9ba1702b5da7751546ef626f2c7507ca4201e1845f39af9d813a45eff6ec0c234ff31eb9c8c2f78a0d70952ddf010ed03279390e13d6ea464171831ef86855816f9eb25c44e94ea5a40a6f134a55197415c7b621c7ae5cb29ed27e9bab16c1b6e7747e1462e64b99f5b8d07aed6c92ebdda2802269cfa3827d3e65c8ee -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d060960864801650304020305000440b6f769c5eb51469bed21e0e25d8eb3b9f5909a58eaee7435ba9dfcc3bddd272f82d00c6c7992f5caacb7814315f1f58aece9fda52a15a6a80a179c02bc194614efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 25e0b881e32da938611b4156525ce24216c168837fa84479ecb72207e9984adb6eb7393bb3d607b1469d9b7c3f4fdbbefaa4b0218850919a7d66a954b315129c39eb99f7dc08df5c4c8c90968f3ce37b66ee184ef3d485f83d308521aa2649d28c319eafa2aec87031a1ff5d7e933ca56a2410593425fb865981b7976fca021b9d7c3198312fcfea5d0093a62b4a7c49a985c005c3a7ad816e270b25c507fc36be1c4cc0a07cb7c6fa130240062793b18047189aa5e79b16fe80a6955191f5910b701bc1aee6dcd5cefd57194bf54d8e208ae41202744190d5ec8bcc2f977f11461a5cb4306fc9b73afff2863a7b580d454bb1fb8dccb1cbef27945109a8f5a3d2b1a32566aa4e8c01a62a1d735117ff5a6a3cc7e70756e7df10e97ee75c5f8ef89fb0a97d7a35698069f59a9f365d4396ab9a764c2fbefb840faf5f57737801b73ac6f9f524167b4f3a567aff999a0db10d55d82155720a5ddc63c35b6a632a3da59c16bd0c143c437661dcd339652ae42f54f8b2d8e52672613772abfe8cf0d6ebbbccc764b51b3eda2ae28d4ba8747a430ccc32c73baea63d050b86210c485ac9554606070764cd06b423efdda4059fc45ffd7193f7123d14014d5bbe5b542476e7bfdc4905731a0d9987fe4a68cf6077c3df63778af08a1f4eb8f00a4a8e03aa8726f43fa829d87c2d0a32e16b47a3f0472a6368ec50a144234c802e6919 -Msg = 1fa4b8433fa5d5d2228abd92b49e6147f7ed6c79a557102517e406b26557d026cf06429a5be840ecc0f0c9b38399357860c3ba23ebbd35b377a3273237eafee8a33997d01d7a0048d532820cea0ddf65d2bed89efb05f2b8b2117a5f4509c71c64e6bfcbcd839d5029f7f1863022e7781486cdd41d58d09c90d7061fd6ddb228 -S = a65d94748b11294edf430b91e649a7fcbce5d47ab1084c0dac64033e582360f7cc18c1b7e71f8cfa3c0677505fba6769af39bbadeddf6b3ea1031b103f3fd72f3c4d56ff6a75fc2e16c4eeee8a1d4be05e001fe210d07c1df1e62d17b9d9def6d981df183c97b4bfba226cf88dab793eef75fc99b028100ed522e98de4dd5c26fd954a928619ad6024ae454f11f1b56c0c7f04442bbdf4ca282bc76f7f054d5195a5ca398d06e8f149b0044d310b74eac7a14c2dd9999ea248f9a332b62ef97867a4e4e312305860a8797c5f9bb66ca4fe13c054e55948b1e54dfbad12015854fd4ee347bb19bc2b59930056a712f090fccd9b31c96b3426ddbb16c4cfe130b0f8327fd61e1df46e093f6232cddc3f9b43d8b5a7b8edab6937d869353cc3fbf8d050879b8fd8793912f06a603a1936476247ea140212530397e3ca5a593899198e9d3ca1eff1ba302a0713183c7e2d60a5492fcd8b1df4e787dee2d305153ea690d81b194205a54425c1e1df4364a20082868f09b5d11b5e5ebb77e41b5eb91d4ac73a75d29f7bfba2e056dc8d19a483c4256f68a3f4e80e2f8a801cc1401286dbe15636c653a80dcbc73f249fcbaf4b446e21e9cabca231615d44578e2f8466f22e9b2b03d21e2f4e19623d15361336763a28dd989bd5a912fba53bc4d5ea1c790ba81f5fa21ac1a0fb43fe5a550108a27041c7e854e7aef824a29ce7ffeb62 -SaltVal = 00 -Result = F (3 - Signature changed ) - -n = b10935650754c1a27e54f9ee525c77045d1a056baedc8c1ba05a3d66322c8e2e41689ca02b8e6ec55d3331cd714e161b35c774311540c6410cc3b130e65cec325377ccf18a5d77054afaa737e65b68662327627f5d1092df98c08b60a3ba67599b1406986f441528d2f1f5d6fe5ec6b8aa797dbdb3162876b08298237af81c7004863576af572ddd66c487cf32a82d0f9fe260f8f2681613208aec55723622f50d3cb3bd33b1226d5b5b9ea2c97a2c59054e31536849ec2f0f2597c077e621ddea0a22ddfb1df925c9f1941cd431afce0398d28e736cfeab3dd7f062a65a2a4c1ddca1f32afa03b4ddfd8b7ca40cc0ce2ed42229d753f03cc6d8bcdca76ab7c2703c5ddad08aa9bf9a27740a8b23168c6b55917bd3d5c1c057c34d1efb1411da51ab745519bd92b9432fea8fadcb9a70e5dc3adcd3081d3333507b7b998886e988296628dd7265e64eab557712556cc492377f15a078dcb620a6e7f051a1fb8754efdca3de253dd0aad4205b032659e4a4fb307f074fbde340702b5911acb34737d7834600cf2ac77f62f83ccc9ba78ff911021b9f8ad1bf421430ae0d64916944b504542c0f6263c48e5e233ef1869df1efc2ccf6f4a95e4db2de7b4cb1a992bef6573511bab4bf2cd58e72a0c235f56dfc182df4dfffb69433a5677415f35d84f5125f5200eb57868cce6b74c5833417990e318372c9239a36dca1a0b28809 - -p = bd4e8bb7fd7ef1e39d71de06b0001bdadcc81b0edf2226e0d056b7eea70b2249000279cc1c04b1ac2919014fc3fb8b62baca3e261601fb0a58a9f67f03cd60085b2d43906d36ad014f321012a9bde9617478a0c10201afd53f2207de3648afd1d737afadf7fd2c0b9824d4f66b2c7dfe93390888ac088c680c27b1b2486659ccfa8986c8c23f78f18b5815a410328e629e7440221bffd8ec4722bba3420da5234f898f8cd7e6d7dcb1349bc4a0b665b41d930e3957cfdc88797aee5b2b27dafb5ba0949e3dd892f490212dfd249f4b1d99fd3b72695ee0652997127f0b9b417fa8365ba9fd103b978309d9baa9d401902cc107cb8d2af7ce04660900e3707ab3 - -q = ef67f69838735c055145d21fccb42298642177fe3fadc39070a95e4fc04ff058aeaf9070b4eb2de1cca72d8533bc55206d2ce9f2895b148da67c89e5b6496ba682f76bcaef69306a7fa4fbd41a838bdf0fab3e7b56c27a8c18dc4bf970364dff7427cdcc6f532b49712282370a718b7d5287bfc02c4abc35ccb2eab3777f5e0d8a27ff9ebe13e725aa0a0cd48aee1fa33ea6b4ea965ba42fcce7af3c528a6675cedf4969640f2ca73345dfd322620df9dcf16520195df8232061e2bc89c12de24838f255e7b1c17713ba435d5a351e263350198b3fb881b8ce0acb5aa58b7afaff184489d167c9af21e40e2ba9fa69b44a3854329385c97df0de24dc283a4053 - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = d65a050fc06c9f176a6be7a7bcb0a9f074112ea5c7fb03b04bc2fb25143477741d74e5e2ea06873a6c2676bf255ee6668d57ab42b3f0fd40278d781418b16673bad04183ea5e7490152c620056f4a989de33a8a199363f360f78d5a0882ba0d4731520da089ded812d26b351969b7bc1314b2caac1f851fcc82a1cb0abc9abfd -S = 77e7756da33c3918b94a1faae80f2081606e9646ccf2be6aa16f2b4fbfdb8ba57fdcf61e892cf9b77d60df62c07e56fa34177df466710c7f3b4c5084647bc9c9a52d66d080b3a1d6fac9d439cb6f207a72f70337ca9c357e16278f6f846f7028345dc0ea8139359ad62a103c43a922293afd300436d76daa5a92f940df6f21f1c442ee3d4aa8488defebf29127e11413cddf4471fc5324ac14ffc97403505867105ccaee26c742082472f6dee0d985f05777d6faacb166f34da96057be40530df9b1076b645272d154614fad693d4d5270670a20b71103c0e740114f3585c2ae02a4865e0277a76eb173bc2ad65db5e0a9aabc5d47f903643a1cff148703991ddc4e05ba766712a93d3243bcd714d067c8fb54eea3c3b5e69cef976c8794471b5afbcf7e327f14258410394d388ce095e5a623a406d33238d2c37a29eb1d099a2730185da1b2e295a55f74b555a6d6beec7fa7b9b76d916e9f487547d06356ed9e3ba818e31825e97b465174a7fb8404b7da84020f555247c2f03a407ce5afe07d3d9df9c94147697d0591ed2ff6776ee778cd74c07e071bd8b2260cab2e0eabb4c97af8d5ebdbac9323b0a73a9d93d27a635d8d5af1651de596afd4c9012f9f8840d05e80a2afe47399cefebb70450fc4b501fd69f67867123e95a6ba653f69cfe3cb5a38e3ffd92d2a37fda91c06e59eef42c836b50050f8b9fa808a4a114b -SaltVal = 00 -Result = P - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 7228696b438ee71ee4be5fe548af7423508c3de7e370f6cd416ff61f94d5e140c9b21f4b9d968df7fb9972be859eb43e71d94cdf968ff7b6c61d2ea95f3c59d41d83402c322ec262991dc90ba7207dfde371b8fc1782ba96a7f91f4b22f90ef117a4b2572adeee2966534c13d5bb37294e5d6b878fd1a9348c0baf4d0695675f -S = 34d3fb114d6871eeb6a9cc9960d655df44d2a5c8f1d8bbf1b3b03896f5ba8178c2e92f8c420d537bf9f8e23866c11d0e02e67431a1506b35f97a85ef220635a28eaa76659fc8fe07d0d4f06fc43c2c4ff96f8e27965078c67abcab78faa4299d345ed81a442698ca99d1c0e4f0baed8095dce5d30add437c1f06f79c215cab5ff88eb280de1b75c3f19f8a9c8810143be9e127b04fc0316d65e7cb4af7786886663062d88ffcd0e64c5e359874db6bb63f91e92c14a4f3893d6beb209d4e009d646d14d01dd3a84f445ad2f54877e0b529356d561665e7be8332c33dbce60d0b2075cd88af0bdc6a0d8edc2efdfdacdc5bdb4bd3537f28ee523c1a355cbf94c04329fef5c75726c047caa8119ccc4e9d60f203b0fa48400e07e9270758b99b0fafa65c0cbaf40cd3408716e257c539cb6aee3e171830e70db3a5110ef5a2561f87bf9b56ca69a61f7abb1b0be64d2627d7d78055f4ecec34c9f9768cf2c21f5ce656d069799476ba6c2b223a17dfaa6e958b046658e545ec4a28e2b6565bc320296ea2a8360b6f980d8e81567a7c40a32c82e2576ebe9e2ca68c46239e2638737075c3a0c0dc68795331700cdf2ed1c81b44b69afbbc7776e08ba794be48f16dbbd8d21505d8749deaa470aca86c27314675553afe88a96b80a67e4257c95a57bb3e9262977588717b54814250cce8bcf8e260ec58c6866903bb3f635148bfa9 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414e3a0e0ee761eba5ffabbc08ba0f2fd689e143a3a -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 92e658a7f7bef5990043c260671864572e070d373345af8304f76923f4f4464e6fcd26ae8a0bfcbfdeb73a7997208a2ec8d8bfb502000bc824c572ab742b7e0eef0a3535de554856aaa28d43f1e7af48d9822557a57d6062860f4909b366ea75bba36b841a2741260b0da2079ef73c6e0a0e26654444171ad1ddd685d82df14b -S = 4496155562e965348a09e9a67ab0009c2b74275a209729eba350db82e066527d9294cea63a56ba53718250b86c64d29b327cae24be1d1b6e3eb996e539e213af4739a5fb52970e89d6ffb0e4f7074603ae6bc2afe88379fe8685fed5c2e30183199702b2028ce39192b35ce3a7111573b148ccc6b7bb15c6aacc4a72819b860f3704a0660241a5339ce3ac7eabb8eba25370d690a0c478b3be35f3613e6be74fd9904d32bc51762d9c921276159e4bb5930aee4ac654b51c5c77b84af7f71c4b88714b1c1bf23ba28d3ddf32906a1497bcd86fe2d8a6f369d145439119028c82d0cc2eab42a4775193d7c3db38c1b86c4a4c697d726e924120852dd747da3bbc77a906f367cc5f9303b6a4cd076bfd4237975ec9cef8ed1d637f25ac0ee20d1bfd918db031102913f8258de26d3319268d97983d29899b8a394db559a95f0fa46ec4fdd77ca0d901aebf952c321bf38c2e6e7943af071a7492b5220e4ee1a376c9c254cd958a743d47b458a93d993b3f011d81afcb5421ffd4305bf6385084ab3fd2159aaa76510a0bc20abf5bcb36beabf9e1dce3472961998e6aad1a68935283e62d49334fd1a3e56cac2681a9a172686022e1ccb5a215333da9dff877ee2b38484e4824f28eaab90d2f10973cb67f0b0ff7b32733464d1553f18306eda6cb50155a4047e0e39dff11524f97819f73bc3482df0e7d65bcbcbd4dd23f845dd0 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = d51a8b58c08bd2f5d5cdcb0dc596e5a2999e86d6ffa6fc09e5b9b64246b2b4d044fe3c3178a3cf3286815b58f4d8b27f3c0b3bc11fa4e7993d976748e3cb9d7824d650202b0923a7cfacc84c688a71c5e1b187260f739f0541b0aadc19586bae9a2b2fee81c3b89cd9d57ab1cab40abdb216d3cf771b0b951b8be5c4905f08ba -S = 068f422fa9bb79c8f18de3cc684be48ed59521ad0ea3a36326f0e4f96db1f2380b4e6a8d67f15a13b68ab0aee7a7b4d0166d94ccc1ac522de51052ee303c56ffad6d72912443ac8433c4e10229d9b9b605977bcf9ef69e33006c50e6077f6f0ac5d56cb9ef36c3de96653748a9d720841c9e4993fdde385ef8d5197b8da2c9c9b029e58d5d28c8a4d017556f31d45ec3dafd5f92a99c5342f31207b7ca9574ed043279f0cf6b5ecb4927425e149609009b5fd0295faa4a189d093f9635de49c8caf34200ccaace04c42c2f57136618932556a20ed057d60dfd87c8343d3a1a3b8d7b760453877ec67a535676c97ea65fc5623b9b7eeb5419840a27d872b199686381093aef3e968af7c4faee2e88fe7904212e6733c6571102cddb6d222e51aa19eaa59afb7799b0590fa6114c0d0ad5a4b09b104c3b0d1f31c8e90d8abf26516b72c7d0b1533bc66ce4d0e25d08454fa766522a4278080a42eb51d064101c1d845361d4ba69809d1340ab354f907986f759ca18d62861370fc4a5fe147aa6504387f1a5285629e3fc92b53abaf66d9bc135818748f59902752359f074f831a87fe7fee433a8b564e61b07500bc0610f8f17a172f92117edaa9b9e6f5858326590328cc9f12ef630f14b1459f3e6db8f665cc9be64285ad681f5728bf1b1507a72769f1db7ac1231d123b6cbe57f647adf4956b5237e7f754ff910278de89a7c -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = ce5ccd9b81d0103e99c4bdd8216b4cd75f4063174ea2eda94fc16cd31bbe9057fc0e08f83d20983bde3f6c6b8db9acdfd24150808a92368596557181d445e5a04e91112db2812b58035d72378d8bc00a1ef75ec373b81dc6f1f0a2ed96f302cf2eac8f42ca3df11e6ee678440a28b0dfab2a36eaf35bcbf3c759a71e47120f6c -S = adb58e2ca61b110bcc5697d845e3f035fa8ee93203f12475ae3a81ca0a9820d799724b3323aeee7d3d6e978f324c84738d6b56c37dbd15b71bdac3a4102576886978db6d78a0c0291886e3eea01f1e95565789d3998a2613557202cb598d560c1e158e3c30d89a4add63fbebd361a17f332c5c69857b648813cd90c2ba48b720601e9b0533c6baa740223dbd8682fe0ddce8a6d9bac06931ce4d0516ca1cfd9cb06cad6fdfc1faededca19480c247a39c5e4815e79dfcabe5f4fbb0ed9ba17b4f7e25f1c55ed71c31a5e559c60158bd66ba199bba3e091e20393377b3a4561b9f07aaed7c0dd77d41984cf47bf34359b3a513618c4595be045750d47788b22cdf102d7d10726605706b772d2e773215f52b9c073855018022848ad75d7483aea8a34af5a900025f71f0b46c587a550dcbfa011902bdc870d6cea895640e4c775c954e11a3423fc9e0d6ea4421408816ca066586a37210c7ac8aedf032413bdadb41c0e6ff5c57d4a77f71067274d43ad9960b895734aae6a1176ded2883303e24100398a4cca23dae13d018391a8756adaaba709354b799f22f27d4a5517967acbf694e066056c49da87df46829c1e4062c535c17b72989d7eb045903665576e6144478e8938b0b2fb4a916f9f2f65990b683c49adeb6e6d6ab7a7c29c530217626d1429025b7cf627f72c4c588ae86ac1a1aec4120bd4108943675e53bb837e -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffff003021300906052b0e03021a05000414970d2e4e51ca9f81fe2e46fe8ee73b728122b0eaefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = d8807c9c2e144010d462ddeb70445182165168be1a5f33c22346b6cd81e7e162c16dc2a77ed3f80c7aa76b2ced0d3af81c06f5122ef20d773b548861a7d6f96cae8db0f73f7d2ecd0e60dc05e5a3fc263ab2df8f07755816d61a72f01b165ed1c766af531a1bca9cb915973b000f7d5499dc8efd4eeffee71b21da4188aff6d9 -S = 9e7c462e899885020d173f427cd4e15994749339dce4f39a1916635010d984b6d627da831d4264ae8f929eb66b8b14938ae12ea74e4a51877facfd402d0b6945a299ac6b63ac800dee3c2d5e64c4feea4ded7b3523f4fbd950e8647c32fe9b2eab6c64d74fc90d8318d52e482e811f74c1990b80d07622a35d7ee430c5beca1997f942117e48146413a3d07cb42ab16657176edfea16f5ac4cef9870689ac51edda514099ed6665b289e0ad9071b35c9ebcf06b0517260e47a516ff852f278fdd7b3f54db18bc5491a44dc87dcdb92a3e9282f7de19db80424703af856a361a9c9f685c3b16efb5474cbe23c8f04e3d5c5fdd0ae9dc5d73f9f04e267bb4aff348c55e2139fe554dabdf99e90b0ad20a01c1e02af92fee0d8a22136f8953bf999500a6d1a5478c9c6ecfe123b068085928354efadd5a9e41e66a15d73dd5966eead4d39491ee2d74bb6ee5608089ece479e53d599f9c19392ca064761688317d0d178a627b7a9059093107f727f754fd538e223cc6f01ad991c4c35164394f4a60da9de6b1b2dcedd892eafe4e3b04b99ea2f6459a2dda8eb7ac7020bb12656207470362c0a10ea79cf3d5512353aa87cefadd601f25ae15068049d2dc158c04a3a8e00ee4b8af3a430890b572c414b28abf2aa14c5403a1fd918baacc4f6b4f80446dec87ef2c808697f0fdb8f142876d8b7d8d90536e3119bba38fb4e1672ec -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = aefe857b2bd74d6bbc3d1376cac4aa6df362be9d5d77c5f54a0c336bed58ed9b7d8901b187c1948a885e1c16bb7ecf0130c25a921e53d7d37a23f9f2c8768ae732a01857d710ebb8658d3ab7eac09ed6e7f3c65aa7186d64ce0d895e351ec598f5cc3233c2cc393f7b53d520fe91ff36417b69bd9fce6ef16f514976db5a86f8 -S = 30de099e81b7207862eaee842f7bbca8db96c4348cfc148da9ab9bd6479ca79f09d9cfbeab93c20f58351d18f7b88cba4c1ddafb46ae5331b75d216cbf6fac92cca17f2cf7142cd42007be50a24a1c53ddd69890673ebcf6d476854fd0a5f76e7c53b40890855ac801ff2088e0d427ad02d8e43d499a06670ab6e8b43f661c16295f7c6b04ac5494ccf27bc49b5c65233af02d6c15cbcccf40aca45929fc413c566bd07616748b9e5cc8562879c2782c1345973f7777f56ad0dc290458b6f3b5a88f160a8eaf8ad0fc394b283c1acdf9bcf2eccf88164f1b868d07a05b7239e4858c2f3d076a299a1ce032ee4967f7da07198d3ca26912e9ad2db79ea8f49f21544e82f6e231651805e934524899ef854255998c1cc59de1ae49e482ac801e3c678626b3b79bb6be296af03c863f89c73a87bed864636eed84c0a5ff05cdec57a3ec76071137fdb3cdde2c4f03c3bbcffeef28f298dd13fe669396e8fcc3a478f4f3793693e8183d96425ebb92f41ae373aeed30182f8a6bbe6b3440ab2a22ad0199bc59fd631e221223abd2358ee6b8e879b2aac64fb41257fc5983ac3e2de5386819042832a8bf53313c0d77767d53a148bddc46638acfd626b908b056c71292c0f9d1b1ced4f2d2ae70e70de9b3dfe6b150314225f21c03b8b53baac3432a72767c09f360393feb18854ea884e8326b94c225d871cbb003bb94d91a74b358 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 4793168aa3ac854a7e0bd652b8a57666d96ddc389aca257da748fc46a38ebd8e6c90da0fa1057d5b621c6f27576a38eaf42788a7fb9bd50642d346aab698d0bfa0a29fd22708b7e616fbdbc4e0b4ad92e2ab18a7e70aeb9ef161c6a9379b3a286a312c7b3c9d7a142312e2d05a6a1f872a6054e267ffae6c3d5a45ec2d7e44f3 -S = 9d2457bf29a45871f04f476eb7a43238d3ddfc7c61fc2ad160335cd1c42ae0da5eeb2ee10f2528ba1e645d27b306f9e833b86ab62b1c4785d9249be1ea9e83e80a5b3a774f2af61d6b536d7670833bca21406cf5dbdcbd2a9e17b2679dd33b026351943e841a7ba4fa3f18e2e278a9db180757021fad06befdbe75f6c77a36518a2c3b88b6329849fbb1007c7ddb7e278b64e319f93b4713717282e5845a168b7825b47f23223793a7a93adf68d5b83c6ed2b6cfd850a8c81589032047fdac6fe091e0369a07919329845612a797dc7f9adfab30255e672d8fa8639a597e556b215e83115fe2268f1c9870b1ba0caee15a26c45acac368baff4018eea4414eddd86678e30d2a46ed879ed6795641af64cdae0f94686c134e1f05dd4f59936e1450a26f2927de6c44247bdfceba2b14cbafcded775da0fb0b81baeeb35e52fbd44d7a4668fb4c832ac0a9c622dce6889a1df6d15ab6c956dc4249127eb7f1b45379e56ca7caaf89617491f5ff38daaa5f0d58bf8eb0138919e3e9bbfce08861b92df0124647bc175bb000d8d0661c71d27294dbdf1112d1461081a931c036d5b2e204e94bb3a31502d055cd74869fe7ef5ef78657a194b9b4900f8882c25668d5e1abf37b038a716a2735bbfbed06b2b55b514f24dbae2e570b9b6164707fd4307b7730a48d3395f372be552402c7c1afb94516294c7823e4e295cff2f2e866ed -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302d300d06096086480165030402040500041cd79527d7b3e43885192c0577d81561869ffcca8d1a7ebf268ef448d2efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 8a64b6cc5b6a7947d76c4f7392be0e56cab7831b4a04710a8e42d7b828cd727b63d2832125acd2e21a6df3920ebac81c9bdd472b05157d2a6230d36ffe5c91b3fd3ba0c6423594809012eafbefc88dff52919fbe764177c20dd7e6231c52bffda2c696217aaec70b8284bb15fd8f66ea36fd143c673166bad85e973c4b550441 -S = 9d579f90d7339f303ac17951057363d529d1b448daa7d7025d93b111aeaa5a1087a7063515b01f30d245a6d27dc2074a51f33273405f6db2ffc466d96b822b1224f07aa8075b9abf044ad120eeb39b2e48d5f4c9f7aa1657ccc639873eae8b9218f3e800eb560d5a04e2797fb8ff3f7c320f7122eaf227febf6ae3a8e2042074b7d22222be95ede069af032315fc264ea1a85af5de920f1ee1ee3696850b581f2eb4c342d5df7aff1ad5b8164f9ec08f77e60c0afc256de6ef1a18e1e113a60e7b5ba8a0c665c0cbedb4a56a146a1662c8ec88d5796e9352c36f73a5f5845659a0711c818b0b4f7a20abc52a31474f8a51678aea7a13cd3d361ebdc758fbf90af9764bd757c7505b834105f0ba803f444f4e17310fbd76d4ae2205ab134a6134819ab329e1a58a7382624ddc2bb3f54ef41b6549cfd1158a3c363e4c0a5b3474dc75baeb43baf99df031210be3a9ec4c4e910768715b4763b4f3ccf60af91984e17495f4064cdeb4d7b280c8c5565a6c774960bf2c71a917b955f258eaca5b0bb9f48de529b258828c138d606b4531b7f621b9b9c1753db014e8202e94e8ad10c18925ae170ec08d0a38fd493f022a618bbadffabe015ee21414d893cdf20226330b94970d2d9ce45bf63a664febba1cbc3d6fc20ef8f2283265d1fad429bc4c0c010022113fc81bafe06afbd7b6af26f369fe526936d233f5616dc5ddc7eaa1 -SaltVal = 00 -Result = P - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 9186fc389b58e4aa051fc5a96912c940f4c0159780a5062300fcba1a1fd5d32a2467776a19a79b912c1a826655e780773930040e4fa2d661414b9c0995aca3b58c10dc204a1c254038a6cac1a7cb4cb1b63b617d75d83b1c4a800d8a9426cc788f28334278dc0921f16ca6a2a6e5b456318a33cb3b6ebfbce4421685656bd5d9 -S = 2e7a8b6a247395fc2c4aa4f0fbb4073fc25923bd456da34955a1fbdc66049fa20d093818d0f65611dee0ce14d15cabf313096d629866bc3b12ac8805b9c0487c92cd5500bb5f1258c8769bcb0bb0ac0024d611f317896c472cb9fbe100a40ee6910331e77120bdb6d31603774a49ec63fa0d5a66bcc1d21caacc647e4942efaf53f28bf4c8685b536615ce951ef1f9b790fb1e5e423aa581b54d3ea30b8cebd8bd939f17d0bcf551bf36d3d0080d808291cd60240aa8a6ce963c5688da23fbb992d45a4075feb1263310cea1148ff2ef382b2fc2f96eef811b338be205a0791adb7c07895dec70d75ea4f6a3d94b7a9b072be6b5d72f964e74decce749f3d7ec84e929a1db42e7451e50d50a79631a44ae1dc38eb4e541640b421ac93d33917680888288e063011d80fbce554bec874b0a4d4670210a9fb9f73858e1c0ac7c98d01b1065f2e8dfae52ece1a4d3fdd46d48b1dd0d77bff7fbdf899672c9306cffb4c070f83551002dc564307730448b34258e7ab7a0db18250950752636e34484b7e9063479b2266e639a4a6d3bcb3c9471f1e466c5339e10007751e7392b8591194ab85e00760debf22dcaf83774d1ebf59af46859c264bba1387b6cee391b131b9f633bded7f1dddf7a370742f40a3ed1ef7f5a312e5e26077109ea298c8932d4abd003bc407cab7612db67a94840a381ea7cd084e4d1825eca83ab84ea7043 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 9c8697689a09da7917bd79af7bc026c32837849ff5f03a1ede464513fa45928cad0fcc581e7e73c6eb0b2eb01cef62b8568803d251fdaa038c25e86840a5db799259fe8f0cf645a44eed6a5a0192813f0d7dd3500c30e9bcfefbe7ea3e1d1cbcb52cd6164db77b9aa829d5b613f0aee1b5df9d210cd11fd19b90e9a1dcf57dde -S = 5cccfe2cb4098226ce3988f1fdde318bd67a4488d48c8dd57b678d4808f0627010ccda741f0420ff14324c67489fe4b55356b5fa14219a6484331cb32df6c649e449d077d35276e2508dff31a421357befdcd05049fe9f3a19fc2b65f7b336e89e953414c708533bdd4c256f6541c87be7c32c2d6a34da805c63ba836dc3ae5ff01f4669185cdb2a57054f2d5645b4010075567374fa60d06dcee10595d35c961e350604d7423e5beb754ae5f34d3c144526ae2cb9583eca938da7c7b26765d5d2816a30bc390be5f1325f2eb9a934cbf9311911127b91aae4aa4c418192954bd89ebef8c54d575248e3827a38ef50486d0fc2ce1080c0d8d750c1bb3dacda49cbb95706fd4af5a915418131f429f50b55de551ec23516200bd5cfc31410d74e1ca7bbf79180f3de84ffa56de13e7f6651928065abd8d3bac5d18ae6e3e3801f102ebc7d08c20f9e9f591351e03c9ca3f6d12ef6bbe356916467154c30306e0519b853b4d073f10f0808a7e2dc22e55d4894c100ee5ca7209e4eeab9a346defe83d0ac34699c4776e1c63ad4807746cd1c05f4fd0f32c2183145eee8ad6df8c16aa00c33ccb871cbe373ff04bfb064bfdf30b8b096123e2e137952194765dbde4d12fb846e9baad76f1eb00ac0ec2c44945095eba3aa812a3d33b96d1a966829cf4ba7a98e8c794abeb2152237e8a261f014a19c2b110d1c6444f8fd8d69d733 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 4eab894093e01b38e38a8fc8b4d6ada3bc337ad1b30615035a9fdf24bc6cde30b46d6449afe8eb08b35e4411a1bdf1eab7d7cf0d5813f83b1063e714d376dde5852e84c1c054d2d3d18b31f20382dd76216e8d4a36b8554397f2cbb023106933cad532cf4c8b984143f79e94648c3af002dffdb3d35bf5c2f736d32236a349c2 -S = 96d24cb0170440b5a493d313a500c9d095952899b669494cc182f0616d0da2918f4644961a6480e127459f63551bfff6e72f3ba3cc5bd8f529c8bf9e2bb90c9c12e2e70448e4ee1923ae1e3561fb6b5bbefccdd9634903bea982d9be5521914e8d70a51606cfc1ab9806f68487998ddf94e00af91f64b7dc739a62d98dfca35ddf4ef4f2c318b3b5dbb58d0b892fe0932d48d4d8ce0f88eeffc9dc5b8f4ddd9f493a3b03c62679bf261ba8a3e9c98e478e9cc74296714a0e8d16f0246a1e77c48c6ecc43b4c0aaff9a04e6594ce508d4185ac5e189d2c0a124cde1d65e832981dc49a699f9c6f978f0949078be9fcc545d33568b632bee58999fe83a2670d24c03b8f306385674fe3120be26e12325abb051514c95a60b3369d04ad92b85423d7da9a06bfde71265fcf8c9fed0b320909a1f4c66f4b5b6259a4938983c8f547fdfb630a64779a5c835d82c5435f60ef8887ca47fca7767a27c267c9d1efc09018e86340f4ba3961ddcefdd2bab540fd9c038d16ec723b31da7b54f0138cb54aa979d726c96ed2de5b4cd238cbc54ea0440217c87667eeced158009580a66e7432062c5cc108648cd6e52e2aef481891cf7963efffd5f2c5d9d468ea32748b9295bd6d64ecd8744b4a5d44baa2346b2e23a88639b3e6de22d58b201b896bc58c916d748563d0f68d90819cd749f9218f715a012d0e7388dae82363815e389033e -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c25980db8b2660bb031224d824ac443d7f673a16ff6f4ca64774cd52c -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = b49b676c4b56eeedca153f915c23079f3e9b87a7d02b4565ec1702e77681edf234e716a3e0ed25527c5d4cbbe66c7a60ac3fd22921ad5b4eb147f97671959c21faa3b74378bcf431fe7626c11def7eadb455033909ac3c1619cb2f852da890c0aed632953a4cc154f768b3eb28347c50fee7011fb0af5085cead8e5cd2413097 -S = 410a01190f07def9bbe6b2834634d4f84c4f626e9e286d504c9393dcc751b76327443ab10e9e9da673e668831c231050b8c37c6fd0a92b814924ee73f0b6a2838c7c6bb39f02918ce05a701f92e38680e8c43c75a57ec2fc818316e0e32b85a5126b2ffaf9340338121379a57ea00b1529ca11cd5b6f444654ebf079bc44e3bb487943580f768b2a2ef9a31b0cca4c0c811124e1492b32f4c2a393bd67335a310ec1cb4cf908613c552a9dc68a99f2e633475e5f24c9140a813ca1539f63c7e241b700f202edbeb1133a043d61e93baef9f3a4c0f8e6cd14f9c2a8aaede1486e0f8da8c19b5a2147357f6059da419078e631e48f6a9cf888d22aaaa22073a896bff816ac5dc940b2383397f76255ae9559ec0812444d47f5b3205595c9db1a74b7dd40c704fdfdbe786713a3b79dc52b0c882bbb8a62aa01d8569966ebc00ea4fe5df212ee4a875afc85f48464cacd874b7a63f705cba529b43a14c483032d616f7b965f9784ec1fda02b05a5d310b11b4df17ec35c828b129218d4158dcc58753f5e208ad8a97e32451da1fd591101ad2f93fcd1e6f5d6fb7b468da1937fab4ccc8e9f3e95a4160b2055e8634bbd0798bf0fdeb658a435a21028fa7cd4be555767573e09d5053941aa0814ab314c45bb94a36997e576a026d017ec7a519237d82297f15c1906fc5866c1a3f6096ddb33576fc68e39c6bcd8f087355a12fd94d -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004203a75e4efbd95ceba73b7671c870d5cd4613bae5fdfabf22e8b5b18fab56f620fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = b31156951f5d041c1a01991b23102d5bb4acad22c777804d994a6a9fae2ab15915777f0bed6788a928b3ece18f905fac06e1872412aba59598c978d6e8e15fdaf996bd82f6ffa1b5fa58a7b319f819a69f835a7b9c6185efa06f51edc3f43817e8d6d8a3430e996819599038c730a37106fbeecf6d82668438a4bc8b474b8539 -S = 9bd1789015404f8537c89ccb750e04b5fdf82b0daa5d56f40ae64459aa23931ee5d8812cfd01102e3749024a881d3e7a13269b8ce17cbe725cab71c53e218d4b97d4f1274247b112a4376fef4686ff0ddede255e8b085d763eedb7f17eddfded5bbfb0121a3f4b6d47f1bcef7aa871817fcffde3f7ebd75c00c5ab1f6d5b2a6f5a4ecf92a9aecf902711572123eac011bf9a406bf4da6ee6411fef5b82aea8038396052e3801381061e5ac04b8f1d0ddfb678f28920fb5ac471a7046383204d5add6bbe78b9a7c9ab1b3f9b4b5984bfc8a03794075cb101bba0aa2fc170cf6da9401850ddd86357b962582f9bf0e174ed42ce101692008e2ecb51fc1185be19017a43e6bb08e2df7082cc9221895f159eefefaff9d8f3290c9f76934d34882c97989d4afd6a42f3815f7d474a7d020c797c13a9b4786d68ca8a700fe3e0abd1df9563344f0a7bba30d043fc5fc1d3d585f54efaa45cddba963383a0a1f979d48e8ae4fd633ec6698ea4f1e14c6fa2a7f6024524e6db1b0b66160398919c4faccd105d82c54fc98335b531baa9a7c96582ae05be7d93b0fa3e92fcb7a2f30950e3f31fa21270882d7a0e75cafc87fbb387bff937d45be79e95d973684a9f2b486f6649436ceb8deda18aac63c0103c705361ac5b318647aa632d98edf09c3ebba86afcc00f3ebd27505b926a59f67dc8b436d75c5a449e13808aef13e805c35dc -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = bafd723d8ef5602cd03f8cc4f54c398a7a6ff4277a2cc9c77fb2b6bf98a66072ab2205750dfeb2f1504eb6495c2b56fdc1b7c2cf4c5b4824d953c8ac676d6845720d881d7d75f917ee4369711e3b22a3b147f58a23bc70c5a4df586026a853afb4c6e47d05e29c6751288f8263040644f02973a127d8aa74895f4d21fbe08878 -S = 4b5029ded3d15dcb29534fc7f46330bf5fb64ebbb4602874e26364aa52614fd05218973224b1936af01aae5990bccbd92c2a6d20d170acdf782020b2a4ee8ccf5fb9402838cf0017af1bb0e2b5cd69c08b2f4ef222f1340972d21e3218fdde4ba3af10c3baf88883698897c52c7b34d84659468400d4d403355d59f1e21812d8304510dd8bb2963c47d91099dc36d7f0e19f69cba4a83b40f49e332d543c7489c62fb3513dba94e9e98fbcdb2e8d71ff544b774b9303b5e8ab1102e4bb34cd6a4839fc007a5031d87b778e858f20127bb09ce92b96c149915a87a2829532c3608d77425ce38f2697df9fa992baa90900e85bf6eb7100ccb6667e093b376b45230c6ab901de3541fc5dafd0cfd9abaabf7d88908261d36f1146757189f51d167a7294abe9be9a16028718ca3dbbab7e5d43ecb428c2956cf1d44c3e8a875e0b9e3c978fb489988b72f04a9cbd06488162d27498b52298b7efa3aee0937cb0a03740d82d43e9b108b0fd5e80ea34336fc5f711c8d62f74011b893d41742449ba91fce88522cc76208bf901fbcaf84e9662ab9ef109b63d03a45b7e1d4075b2ba5323417f675f61c915dfaed6810f663bffcae467bc6bd7772103a0a1e445f2dab341025ba4c2bfc93ece19c64dde97ab7be7c00f9064bdf2a1fe7c4af045a2362d371dc30e26b8e25bfb258c4b479e5109baa194dfa4382669b0734f1b6ab63c7e -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 65d1c1c5f2aede8f6ef03b53d0ffac64ae6b9666b18a000e4763ec2997cae7e0bacddf3a284f35e270f3132b2d3c005135f2b10213c7221cb83ae6b96dbcbc690c1162be70faae0e2a11da7475f420186da586b07b31fc471490a43da3cd7190c367f359b2f6719a0211393692703441bd4ebd7ad111b316c32dcdc021462edd -S = 7dcd0def685ce0d0dc10cf783ff7e71f69c18d7edf9e32dd583d46201d961cdc1f8381b5dea980ef331ccf27b2db4f7bca619b29c92e04284b14c6c2ed9bb62c323ad22130641834a4fd703dfb714d8d17939b34b9bda15a018b24bb596de618208c65feb7c262b8dbd4f6b10fac674855b5bd1fc15fd1faee28e39bc495867df3847af4c2b8b40bf3e5694c84ec4fca9deec321ae730ef0b10329318e34331e21ae5bc21bffb025821881d54d9a3f7adbb96fab78f1aa6392fa4fd8db78bd3e2bfdef787054c9c85cc2e07fdff85c48341d587b7ff55f9c96e32ef06aef9df62d5f9ab837f3538d822f862120d2e4cf6abb43c620a7cf08a8a72d3d9dc0f7d02d4c6fe620d3d43891696d7ee9731fe448a12070f573043378f3a2acb470fa7eaf01873af3deaa0906f28fbba9fd4b5b05dd806711427a36fbf9d82f627f1620f9d48fc10c2d1f32c88826faa6f49ea6918daab391079c37a76ff76a6a8696567b319c3adbdd0ee5c2dff7ea8411c52f719ece66297797d3ccc99de851f14cd061dfee6288766149dbf4df8ef4554848f22e3d461f3b9eda7d7cfbd2e5b60b434d86507ad1e7718064b030d470307c22ff18439b2ed3e1f757eede270f4ef8b6e75ce824d0e65f02631ec87782e7b4b39bcbb152230c93087676707206fd4966a4d7953931ce284eb7ff9d5b9bb7a86ad7dd561d334b0052a6a23b25ae9a05dd -SaltVal = 00 -Result = P - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 01fdd22335a45577e5cc758f73df444818c364cb28096c6197678e88bd687746566277bdcda9e200ba02b625a95a7d9b1db875bed471efa94d9bf54b88c32fbe0de308d32f8e0cf2926e9421ebf0a662073e17420f6ef2af0af81e0aa36e3a7d2c67cc8fe4bd9bf575f859abc1098544de3c907f5f683f1ad66850eb97cf602c -S = 2369b3beff47a12b51b8ca1d8fca20136ba94bfc7c16ebe84d322bd65d569af515521c1ab131ea2afeb2620c823b1753a28d0207c7b9e97eacb303a62da587a7a0417b75b8979f492dd16d5f8cf9cf181777f25954b91acb34c7e688d60fc78054d496ad8d6082678aeb7ddd87b02c07c3fbc627ff44bd89d7a151a4ef01e0a9066e19a2fb6271f0a47d7409fc08ad9990e5fc9fb297ee72c50a39bb1302273cf7a042a85e44d48548d859790cd126fa64bb72cf40beda6b651c7e957b8cbeaa7248de8fed106ccc3106ecc1fd0f91584dac294e0747032c854e60dcfb6ff82b6f7df1ef478a69978a558df0b1021fab6d84cf9f76ce0b574768ce12f5d3d44cd54f21339f7189532f7e960f3544a53c70a7027b782089904ef763bfd8d538654076c822fc0df2b1f7cfe297c9f260371023011ef3bb191c0772cc0edf5aae1897e2314988b1a10ba503907fc1b49cd675d766c65a12bd60bb7da104d7fdf9f2987dfcefcd9a27caeb56d2a564b64d1e86d95fca84e6413d1fdf716595ce476fb8e3c3e71c3e574c5222e706177da384a3c21c4f1a418a799513ab32a0c315916ddec5fb80139a7fe05624538be2130cc26101604504714ea0258672049f0f432bda7c4fcde9337423203e1d6323c090e11668470bfd4a2f910ac5c2c15739f3433e6d38fa8685d4ecb2f837a9282ad8c110ee083daf05b0ed7ec04f4711cb1d -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = e880d3f9d8365b9f6e1bf535b95344a882d374417ec91227c73821268de36aae096d131fb3be7343b5a9251c9fcb5be15cb67543654fd3f43474e76afce28ee19756a09fc0f3c57b82e48ba0f042b68f1738d863316521591c81778f0a44c90c7983a101669df94ebd1550481580fdba9aa2c22a4ad4a45d65a8fa1d1ed0c539 -S = 486292eec1aff1481ee618d78c8f28d59aba6cccd74d1d0e82502d1b27df2871f55348713ac01f9ea9dd6dbb8150a3df926326dc136957f91dad72104f2327b19d3890155cd5f018464c7c2c4c3509b2f47426b119fb124046180b2ec409c4a59da8098baa59a97a100c7539785d893932b9efaf2fe5197220d1706b96ce89911883cf50d96e1f8290bd320f47ed916f9254b9cd4be55f85dccbcd0c5731b2432810182ddbd37ecbda7229e9e3bf46c7af5878c8ff4c96f55bc0c46b57a88f8d5e756a682bb279b1672d43edb783b8a4eb4c25b42702dae46db934af12b7fd3852a5a2dbd307e4730aa1c993f5054152547a8a76ec07d47e296fd55b6d405481b9283d4fa2d262a38772b10da63286f009208d6a98f4174c2ee64f790dbd47c2508224d0a96d3eace8938d719ea730f026b6e7deb0eddc967a68d78b34eb8fb3138bff69d484203c5b7c00bfa230a01957911f5589226228d16080003fc1f7b6d544e7b2a46f97b70d111ee1d846535a84dfd43c2b42a90bfe373d9319846bc069cfe2ce7a23f41e0934c97b3964c2b892dc2f66231f8b6185ef6570d4ca31841cf9b562daa5914d185aba76ba58d66592f3237954424b103dfa20268f049c9749330084d007f7c2cd5405b1b1da06a75662f4f7c280430dfcb9bc37bdba64200273d13c319ad247ad7e20ae26920767ba43b2b1a02ab22b188fa5a12108d170 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d0609608648016503040201050004205ea6db376f12859c355a917d06abfb3f5f97736f5bbb23f71ec1de277ba047f2 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 1179b364278cc399916b066e7ea2adda5701135fe737fd3cbfa320e3d966e3ad7bbd67cd5e8ec4831040969297d0b9f3572150cb36940c9bfdd9abb60105bef904e4b0b6569004f13f42decfa269c54bdaf9a72be8061d32d091f19840a2deb77397960755bb0a4ce81ae50ee694594aa8311f6746b4b96b0073fb6fdc65c951 -S = 96c8373de5bb82b7da57e144e219250dbba46fccb74e1c325e3bf19c16fd38e2a71e642fcbb6f0fc8ef77739ce1b8aff04a967573b1bc71c894dd5bb29f3de66736608f4f4383c0d5329a2a7fb127a243544acf40d245e2068bb21a8dce0b4d7e81e165086afa43929b44e45f3a5d77d57505a86651da1dd4fbe0fb6f83b37423e670e06c810db19cdfb2d1d36c441903affe00f12078b229cb368ee5e63c451ce391f1eb1161076fcfb9dc2f499de5a6b948dd2b3dad0e6cc1ded8b27129197fa0998d6fcd117c37cd4745d844d6443d0e32a7d6cb34510d1270f31b25f7f2b4f5deb8bb94b7638f058a59eedd80837beac603775c67edf03957a6ffcf7c18c8a376a02bbb9eacc175904c0b5c09d29ecceca5ddb3d8143a6afbd89a1a3b372e2c7eebff1223b1bb4f1a26c4fcb6605f1326c6e4a25c9ca7eea8441b0495f53b7c6015fda720e62e1023fb039f1e3cf1ae9490f46ff75e0b5bfcd354f91e0aca5a4ce22e64876002e304bb7eb1212171225de212e0ac5304907bc803b61066cf68083832033f4902cda8e6ef109c638346f0598fb27f38f2ef130c81f78d5721b89b949d364f0336e3b4b982b7213aa7afc9aa35f5fbad2286f4a4639cd981c7908012b4787ab506d3bb745c9a8232253d59c24bcd60f95ae74debd5967491ad8b5ae564a09a79de6438090bea658b232d0dd620e548e020e9971ed4bcae5aa -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 7a143960d5a8c615dd58a10ba92eb257888befe939812d105f7d36412f291b146c90cc8f9584e5a75d3ccb045b42f805038d9304d5e944dbd4a046a63a53becb6a294b38262cdeec02efccb918742148fe4e385df503885c63b4c10d8400189c5c25dee4f06858ecb5b8cbb2498ed6286117047d0395a29df503cefb75f7d18e -S = 5d5f734d2700f3dcdf27489b57adb3b488de71bad11e6146dada53b80e4b5bcba10695996a7b52f89aab2f3ff43c17355deea644c2ac94fd760dc45aacb4471137a93ae4d9c4fccef44742682f0f985f26da2bc70bbacb95550f99b9003851b7a998bb1535218f7e47d41c52b79736f3005ebe8f46c5d4fcda4c7ae36bf68ac8c527d8589bb841abcb6d0cf12a797622c4275548abfd2c46d35132e5cd631da7f16c05129fbd1647a470f73c7417ac85ff85e71c433c849f5123353e49ce5d6bfbada544e4aee9887262a8c51b5cf6ddcfa15aff2315ad910d74e92245945309f71815dfc23d4b830536f68ad444637a808077650590407e25923247aaf53df43fa90d465ee06d9a9a5a7ae86d8a2180d70430e4916e7005ffb4858712edab095f8a691e2260c3fd56a4311dc25b4ed8c4ea0e43e4bb44ca26ca8ef674019218af0559de44bc0cc5f9463575ec28f3fc9d7a4d0e9b00972044b01187ca06d0dc7f0c5ea336c0e2290e1367d12101f293dab4139124c217cde848e7e4a0f15b3d3805767f88aeec07bda40dd23826afcdca5caebdf54c32021113d711b6bf07300a2ec7dde75d550c93562a30e93810c9ab3ed830a719e02df7dbcd62c4316692b69ae722a01c462e5cbd31ebef67602fdcc9580e6e326d77a4f2a0ad079acf2c2592748f9dd7c7ca7560e4cb3e7b60e9906b8bf02fde02c9c5e0645caed699d1 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430fd72258dc3162b6f2eb1784384443649d457af90d1c6bd30c443b7e3ce562e7d7e660afd677d87d01695dba2597a886f -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 8b48c7483bab7109f4d05b8cee9338be36640bb068fbffeab94892013ba9f96c5d60c093b144b229f3b6f8bc46d7858ac0f9b197295323fc00f8f582bf0a136f612ae4a020342dd883293258986d1eb07e33a4d42735e7725ca89783026f5d219b8f7a9810e3abbfad114f896dbccbd778fb2e90ea0a11f4d640c22d8b41a127 -S = 5ec4ad5490edb3c268798a03c1fd36d43cd64e6665ede2dc2cd77d833f15edb7b836fb7c31a9a6135b4ea1c84f8ea7513883d8d38037d7f086d50d69fd730fe300b5c0090f4c7cba382fe27f7ecd56a0df98f6b9e656f11169c717fe8636fb2cc6ecbd4a44ea73f91b9189b640bcf51870ff97b23a4dcaac6e4852a8862c73f80f89e25daeeab317dcc570fd7503421989334ed729d453e2b372a58ef37fc773b25d6911aa52a11d516d1011b052c0f9f33306965525c4605884980a2ba24deece8271d65c1623cee181dba8f953a577d989e1d7f6d5393920cfdb9361ec22c10bc85926cd37f3289b1efa6ceeb78e7a1d1b54be2865aeeaa9dddd4aaa2c72353338c247411463af28004fe154b3e41fc88f137c6ab9c240e98f0441237111f9fea9709f41b45cb601d91ee24725a62e0f04a72aaada19b8a25da14b86fa2a5c7f4a359fde437d7a2b9b6553b6dda023e03d3996dffeb8511eb67959c2c647e28f8e9c0c17e412308105a10c0bc4d2820c7d6acd718c1ff38fd1e27db4dc07d2f12f45f2eb8f414861bbace017c6bc4ac46f815269f68212e1c0a3fca93622fda40102194efc58c816146048d49af8717faa6e58251db269f1fd075816da19ff5a5fb0a9ecebacb276b3bca5f6050b33cf50e065320fd703ec4779b3488f1cacdc6a8d469e9f0b5a97f7632efc417bc9efd2ea18d768b27b8863e753588dc3a5 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 9e1d1d96ec18b95c118a04d5d8dc554d705565e87ae1048961110af3ea62912e0cc2612d0150acad9d64fc60dfcf694bc6640f6c65b7bfa13a24f5c5bc130a1c337babf1cca58a7ded33530bc660e25a2989b3439bed9a9babb1b45b82279dfebc4fe32b769ebb94a8fff31eb618284241ce39b3430bfb415bbe2ffd6524b19e -S = 728ea547f16aac9bc1449a5614fc3612292831c3596d2897ee8426c04c353f4fc19590bfd790660833fce2152b026327eebe9c934aa8db566bf63938486bf8699bbb6f2cc7882ed6e9e9cb2d3b0647a5355616604576b12d26123bd60732b2e240e9015a7c4044a0ace6f18d522ba55bc9bed1cf88f94680150d05d6a8bc58e74862f7588993892859f88c92e6516f02d57fb4475a4c4872a211ee03d5152b2111ac0f46e9d826f1dfca27a1ded9888b8a573e6702f116475a93cb2d7e6301ac8742f3dc2c48403e4205082b7e4f8fb21b814c6f94634a50e83e4a3c0900906b162621360d506eea63954581771c72b2abf6bd5bf0505e3a8329ca8e1af6b497ddd7695237fe454b8a06498e4308c0b7f79102ef07977932a57927e2c4dbb3b1199ffeb33e244f536a19375fb5ee25279b425eda4693cef0a4904f8ace80e7a1916740563e4fcc18ec4356dfd8f351fb3969b704233e6c877ce339e7e38e98e0dcfebcb0668dab057171e643b6669dc187f9ea8dda2eaa295b8f88a8ba8f4cfb579d5d33681f0a306f2f20821b67613e18545059b2f6e8049770fe4b280ba849ba38dc6e70949cf6ca160910653a7e3a2c36af5fa1eac778216ee33a60e67dac7ceb7a35cf6bd926e1a16160e303e46afdfa28b018a872f205309035da90752c179f8d4de48f671c08a6a43f7bebd4c49391514783e6989897fabbfdcd87f196 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 45036afedca29e7386c707f029cd67ba4740e7eddd38146d8be5271ef46c895868f19695c1f5a26d8ae339c567e5ab43b0fcc8056050e9922ec53010f9ce10b869860f88d4fdca375ecf3a6e65fc37351cf33aac75f067fb4588cb8ba383e27790e95c3dde5f20ba4ab49255ecb8117ad14dc44ae6c09790175980f7b930077b -S = 634e95db19d75fdb681e468e2e9f991ea38bebcd5e44717148be6c79625136182c8c3b136f09529d3f95e42d4da796a4b9010fdf3d3a483e5c78ccea3ae200a382f1c690a01e2f450dc1128c014f533bae31237d48890a5bcfb3996aecf790d18e6601d9b12022d7f134b1243965727a8ebc1479dfab096298a116440818aaf961ed9aa730e3df72f7d115f57e1294ff53549161b66d6f15f3219323fb067bcc492e9320c7b706613cca0ef030aeae3fe14d04dbc2416ea6d0ef89ac48e0ba83c90e33df7dbe215da1c7c70bfba0cf1ba2ceef1900c76c9216d9c5db17c9d3e2401814609defd932c47b864a65e9c30f75e63f2609ec2416405ef072240092dd23f835fd415d190eefe2afb80f5c02ab433946062d3bcb5c18f009677e43f5e02fcd4a330eaebac40dc788e4fc6890c1c75e22cc2e801153018b316d0bdb0adaf9b2fd98e4ba7b3507ce1f1627c006a49ed81177cbbb5a37cb952ca93655ef2fc4dc34532f9f5ce35906682a295230a0824934dc9ade9ae445d4f5342395badae4371c23635bfc03effc650595381a352cbb8c9c8a353bf795799b3d41520a966f48b7fbb28389f6eeb02c62ae21f7776e8a65b7b0fe6b10f0a498ba9d2ab503cd7e8b79fed5c1a9239766f577266a868db7b74e274b82107cb2b6e8dd04149d556258bfb92b5fa0ae4f05f407191bc28774159066857383d64d5b567e44e706 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003041300d060960864801650304020205000430cb91c002dfd7118dbc156c9b6c6faaebf14d2d79a0d28a084b2fef838a9fbab5fd2e5f9d6ee8b032d4f6588e5219fb02efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 4d72aa3953630bbc1c51a7fb6c7e0375938e8afbeef430c1b0ab56b6e226ed11a989df2cc819aa9665f14e6410f86ac7010fa2e4a18f43df4df22a3956d0e25d4c0e0c757c520482b7b9c1ac55cdfdd67ab19676989f35a435952d71ef4aa679bd67fabc77f45fa99910c77c44e604ca85dc305ada0d4c37f2fa2703b57c818e -S = 13e21486fe238e70f645edfb21dc32ea0f415e5e260483799870d947151362a7249f700818014c1707016d71a83c389ee6f17354e20b55402f4c6036dff827d237fc7b24cfb2b5398fb34beb35d2d61b5c4d089ef832c219162484d453587869f1139d7fd3497ff4189517ecbb2d314c049d4e86dafc418c716c3e4c2803ea03c66b90b93c620aafac05e4252212200dd1448e34914da304148d1466e5e32edaf6743fa43c307f24ec1a0d46b4bb941945a2ed7c02da826476522cf7fe329268774052310d4b817a4058d9ae6084b4f1428ea1fa5a5dc0e666ff9466480b9f1d6142890010fc2ca3ee46db1ab084a524bea1c27b89adc87ceaea0a1d9e8d83358cfc20997b8c94204c80871c0e9da89b224ba42181743b285157d3eae18f19f8a38a102e53d2378aa241b5300a20592bc487651264dcf9084c3b1f0095e848f1af5a940a25ce3d0ae660ebe9ea09858bb366451fe8f4d1dfcf018938db14bc4efb1c4a2a7f5b08facbf81256ffc0453e4ba14744d1611e85cba35baa9302bbe959dfc2c0b96c932063fe40991c2ee47bc1ed97999f8e5f747f8138691db117784a5800ad4d210caebdbc3ba84e8fceee3bf59ff163c7ec9c0eaa468813a1fa8215464f390fc62d45993db71a7e56c4a022fd4ee377a725e87a2415877a6365b086c76bd2702abb265ec3b37b198eb84e9ce6e1037848c10bc132aa2f8e1af165 -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 709abcd4c8297d89f8e4a5446dd32ee612838200c5a990950b091e21029661d997dbcb35f89924ac4db2dcbea345a038281b2bb49e425f5f0af794ffacca303434fc77fd332ca57fd0323a02bc4c963d6878c5d375209c1d6cfc052aaf359704afc66a356028298aea2e6817a22e387b3861f966318c705898e01aabf11fbfd3 -S = 95fbadad59d07287451d54b9645279f6fc62ea2c6dcdea2d49548a992844d46b559be0328662c2be146e3812aa9bfb073ef21f2c73dafdce8297d70a04ab3bae8e0237f6da726621da82066ec76afca2340e3ec256ab5f3e0bb53833c78770ba95e39a7f844e9e483a6cb7f98d496e4eea095f08d809b422dada7dc779303939e5dcc644bbd0b22a339bbee4a9203005aa34a276ca5c1135418c705b8d70284ef279f49421304b28d1ef8606ccb2c9591ef36b418ff3f52933ce1b059d9a3d04e483c2baafb719131f29f1fbfabb85c7bf0b979ae3377a35fb877eab9dcc630759d18b3974a999bfab9704953d661ca6449cacbace130869c2b0751d205c5c6ffbeaf3017e9bce964b2d4b6af2ee8bc9897b6df0d53b061e89918eabc9ed4f46da59748576e816c5bdd0c847a411948d43509e994ba816d6391b041f23c9d70d004e9d3c09fa717c4531af5b8dca8393d28dbfe3b07d6a88da2383181050bb033b8f21546432f62caf52cfb364e87ae5fea1c6e2948e39aeeaba89797163fb2b3bd35d8bb8832218a5d931d351e9cee457504ae70c09b51004c826c913cbf61f570504951e02b1e47e9ab3dc47b44559e77d79b734790a1faedef901d267129139c66c992f039ab42d15635ca1ced47ab12ba87e12fec8bb574c9dcd94e7c6ef54a75fd568755042e8d928f344c65497b3183eda9534db97a90b24927d77e2e3 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 2be1649aab8e12b337a5d974ebe354a0ce3e74f4fc76c45a05edf16090b889e844f60321e86000b6c822d0455bea3812243e72fdd61276b1bb9a781f565db22b488b63a47090187a56e92a2bca36887fc891b6759f1f167d52e467e73fdc8b9cfe478d0c8c44e267a9a1ef107ef2cc4f83e04846a0c42d269375c5a2915d9ca4 -S = 11a6268f9ab602dca7444e9e821e9e9dbf2ff6f875f255d8dc202f953d91d6bd13c74697c70412131091a062f7511b06264d083ed49b24ad429d35e9fb02326fbb2b206dada13f5aab60b5b3db5df6b83e80eb946e199206dc2fc7246ffc6f663217fb5ff2ca14eed28a58ba010b5ce47993b4b66ff00bcd20720a4a6df35a81aba6d277b2ac3fe65dd7089b6fb918831c54165aa833fd84fddc5350bedd1517bbb180dc63016a10668add62ce782292af053a1419970cce6c6740d9654b62d836b7446db56267e08aa204fbc3d3352c196c6b757cb08f137b0653bf362249dc7a7162eb3d82764b51b8f7676401e89c3437ea3fef7b727a096143033d2dff653107e6bf20f9586b2ab75a164d5ab84cd0bc6e04749ad4599c80e4edff189c472b02c91b31955284c42aa5390d83defd8c4c24f14e2aa9668fcfb0b683fd7702da5330e73cba32b77a1c197c4385b5ba5e0ce2e5a3732838fe136020b870c238ddf5900b662dbed59e9664754b63cc4b8fa3766797b2120924d712935f4a591e61d292782bd6029b3eb434e33c06dc53d1152471c000dd8e9eec094ba6b3dd5d5e71e23039480df29c2b00fffb5358bb5628adf89260445ce4ea3cc4a701af52d382ed2e9c1db9837c29e211332f9b6c176630f307c5b0d0e28a1a09fd285ce2c12d1f18269cb1a04e5c1c1740fbe8af04edd32abffd09ca5641806520eab220 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d060960864801650304020305000440a6e9bd72eb12cb01af08cd796b9a5d7f70e34e1c142af67f862971169f7110687017d74eac1c5d45f013743c20ae189d7c9c61802770a915b37a0ffba5ee490d -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = 1dce67cb88490ddb92b9528b478d3cd681c51ddeb0a76f3cd7b40394d7da5b6cf0eb543e854e07cb1ff5f2b3b58e53432bfed58e180b6ebfcc5888ad92975fb032faaab4baea7d8b7efc6e885e21f749471d1bd4fd3a4ce6173d8d874b99d4e2ebe3b254b08635c3b7b80e31c9acef90df0937d8e59cd158bf4959498a4881a9 -S = a73f90dd956d119b2364f15b1772eb3398cc0dfa717bef2d0180ffb42c5a6a9f6240e56297fffc3ec10b8527678e37c126a033cce08451a5052575ad1e471801df563e447e57626a09a5b218aa5d1b3ae3dafa8a43e0f5b187f9d11333cd07a52a9b0844bf61f37f9107fb9770ecc17f1858767475e9e63945bebf12c54a25f9759cfa4b11c605d41cc2b7aadb786a03fc41146ab249d984f6b78c89af37a6d788c67f0575faba520cda93288479f02c83e78122ae5b88ceb6ecdc429f5e8cffc9e1fc78d8c4e638c74fc905a2ecf6fb2e797a1d8b86d458d0d594836f66b801445e743d33a5f936138a1c18dcd08f6a826fdbe71bac84dea0884e5310316d9a28b50d5f40d441d5385db88f4934b4fb85538e9838ae64f9055da047f8d49d432feee879301bed3cb7c2774179fd4f76813284a492d1c89df758ad141eab289c504bddf9934753d94588c2c9fafd69b6b261ce320c103bbba0842e9e2e14fd88d17319f9a7596a55701c22226e255d06f5dbcd432a930758725ae73adce8be417d7a94a712d5c5b3809441557b348720a35da7de59923e59c92df63de405fd913fd7fbf3407c72455d3be934e3d7a878bdaf88498842fe533a03387ac4a6271f0c3621c33424f610eaaaf6878fc99660b2f8833935b6eba90636eeb9b9f52fc0f3244183e59caf31d890b22cca748c80abf9837808b4a1fbb9cd5c9a9b84a2dd -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = f0b048e510fd9d75f3d7bf3f460ece324aaa452f6e2c2d6a23179114ecaf3137b4017ae16523b684b6bd819d45c87c94e59645e33913a67b824a0c63b52b3ba3d18b41606f6ca8489a7ff031e2e73dfcac404cc0cce0ab25565c2a0db04e8d7aec5683ac555fdc894824f64246f2783446af430c501ba62f4756d15907a38d83 -S = 05eb7a32c9cefdabc9208a080b7542bdd0e1e2e4a8529c29a7529527207a0b5105464d0cc445e7e64fe2a9be5cfe6635d4fc1ae7bb7ee36b86fb2ac72ac7d53af6b1dc6df2c85d9aa3513ecbce8ecfb1926332f3119a4bfae1b01b2565376be9872cbc7bbfed88a4d2e67a78587ca53e09863bf21ac1350bb38e009c3c458d2df736b1212e7980d0a3735925cabf39ad4da1b98e9e7a6e4f73aa048d8d686297fc6885e5a939e3195908e17d32f7e78d22e9eaf3e9373ed923f0b2d6b45497351cdbc9fb8ba0aa912223121a24b2b44b291743bc3ece0d3911c4d54ce82f883493805273b0fbcc964ae9529b83e6f22d0aedc8b6f8b2a410abbce970cfa44e30c9b97ffb312d5a53d904d5e99a86745a70c6c9f8f3303c31b39dd587211cc49c973837d89117583ce5be56ce263976d9c19303b7d8971bd1bc0a7bfed7af8ac90329a628a85cee99a3c5e9bddaf857467a8fd3b015345e983946a1a22c4bd2c18e3af937555a08dcdaa055a8fed0e06ebf19f5890ed0dcae6e031e9150810d654925a9347add44fafab80d3bc8342e9f41e60ab742d17d368e02e82d56418c22ef10021431c00af4e21b7436aaca8b67dd7c5b1519ecf0c414491c1bd8a1ab3fcb1bee7d202673c0a080f56ae2966605132998c79ea59bc6aeab631bc0064187f11ef3273d5c6459ba6ebef569b99ac751ec0edc37492c7c563991a0dbeb2710 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = aaf54244327c90f0aec7add583fb42cfae696074fefd5c9a80d9dd1a3b3d33d31eaaeaf137479f6f268313dad0fc7e5858a026ea4b112fee1a4eb5e8ce911881f77397d0e55621d91b046753019436afd98e0455f44fc93126ae106e77df4d811b98716aa573bc367794d2c97d8b12da1b7b233f637ccf6b8c3f15359ff179db -S = 0524037b884cfc8ed0047ca0cce7f7cfda9893c065ea6a1ebf673398e23a56aa4b0a179f1b776a3bb716ea83f0f9f863661aaefe7f50da0d714d9cdea2408a09708d50aa4c6bc6ab31240341098a1d8951c82e4708a5cba44d0d0b98b09dc8f8781ea59d9d6dc168bf80d50e67fb53763aebc6dc12b19ee6ef47b838d58f1bee5f6f3a263a430b22f633195ed0d32a92c08b2a4e75807f1b56edac08a6a87720c611ed497dc184974ad7d3fc17dac4c409a44c3fd29a35259fac0ac2395f81be0fcfedacc8044397f4fbc858640af552b2cab5f85a042d41050470f7fa485ed38a0fee6f9e935611e33b50264ca04f8fc1c6e15d20d10b023ae7768b0b87f99fd298e7663fdaf5dda0f61c019ce0516daa8db07f46dede1ad63f8839e58e3c33e69df238c3481b7ebcbeaf448b986ccfb09b3cb62249ecea2315be42cc6876b7ad17a79a10d8bb4cb83b7e33fd28218b58690daf5de8da3824bae1bc9d84a8c9c09b5f4d67497d2d5b215bd530d41decf24d32d1c73beae4e6edd3d2859f11c7d8ae60673c94f1a233e285aa2bf8be8de7c5791bb6bc624ed74bc1de32796bf656c744dfa9ebc3958b71f2f26a9d28de16927aa2923e6b897c3c3c1f719b3239d1e59a136890b21efe97081cdcdc69a39668791fc4089fccb694a77a88101358ffb961792ca3c41b15bb81e1edd7fe403ebce86ff17c5534d441d946b7763806 -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 1d8188e62be3759b150e29a7b864be80ba2f00e747cf6caf45645f91085cc25d0ae6c4c55c97bd20e4dddda23d8d03af33a13e082e3576602ccb4832d10f7cb30de94cd2ec64e92b8c7f1bdea66491665b313b153a2d6dcfeecac1e5709f113999d8abc4128b58dc232853a3d50fcbc971beea4a4883b1691d6b195b3f295a12ab6bb393c7e3dcfa3bcb6bf7ddc6b22d4550657ed311590330172763930905d38234c89f889d85bce48f451b21945cb980e25d8de6b6fcb2828643f5695105a4fc5705cfa9da5430f6fd98af78b2f2a255eecdc268922a71dfa3fd65c6645c6204fa1afddc7f009e24ff973f70accacd07ce05b1a3e352b4cbceca24c691c94acb40f9ec6f1964a3c73d4b50ad1279598711ffbd1e2ba3e283cb33d0189ed5341b2991aeb6ccf331e23d49f473adf4524a50d876089c824488b1a9d9253d9f3471ab73cceacdc169bff8b6ed6258a940ad03454ee148c86376c6c35971db2a4901980fdc3e78d1149aeccc32424162bc1fdf115e5d2a138b914397d3384bd4921ddbaa251569f71d61aace4b5d947eec59fe57827cdd38c5dd01a0f7beccc0f80662073a52aee4faa558a5c1e9f98327fe91e29340f678c8734e5790994c1ac8d9da22b57cb2bab896d45a2eb0524cc8457275dd61f6c4eec4c2f697a07d33d07a46685c95ec2658259a7bc0dad3d9529ac5485de5cb014e9b7dc7cb6e2bf781 -Msg = aaf63b5ed0e0aeb7ef3da4f134dbc2e8942acc27029e7366e5556f51c9face8b54e98cf37c936326f824e445f464c7f809db80b26c39133766f5285c0433620e0febed963e48561bab4ea06984c094f103415810a0b9439485faf07c42a491ffc24586d07dc52fa1f002fee64ab7d0db69a27dc804e6ad832aaeee37eb130465 -S = 28cf265ebfccf2400d6129058b7168cdd9fd44f44a74630d8df79d306b41a82d9ff0e7e08ba01d31514ddc3ef87dff19321346aab5c67959c551695cfdf04bfbb0ab74affb9edc69b9aa6eebef1d4fb7b1ecf7fa30ad5834136de2510fa774a24799b6f5e6410f4f14354c010f7f9e4976d7772ccfdeab7eeff704e9531ec3db509c1f0913144a444dff8e36f9f50e6c2c7a693c5ed440d95b721664aff953a18f033df5ce2fbc2902d9fe4644f10d50f69abbc7d2f58a80e6b6b4c94d75fa53bdec788315e87c103e81dff4c5cf7c5f1fb14a3019cc89a871328969ba9d12fb14326458ef1df1dce42b02ad17db4bbc75161e66aecbdba7ebbf1709fb208642e3e1a3c12738440502cd235d6a43a08d24f6a397b0a5b86d0a8456e939d4422934917905b3772e2c5736ffc0b3cc8b8bbc1c9629ac37d54def02ec83a106a6537adcb6559ea3cb2024a1007384e604fc64ee9fde2aedd129348c7fc34b240dc841fc45b2fd2c9ec16264b067f139bba8f3c31bcb4291b71e590bc953fd63d1ee44a901d47fcba0d12150ebde6f50209646831e10cf3fa7e129e5504fbcdf4832f5589f191925dd85ea7d11031cfcefa5ed4f9bde552c4270930204d37c37faa8dedcbc2838a36fd425d2bbad87660fbf8df20610e666a9c382b81b27b0cb172a188c46bed70dfca37563129376b2d6e78d4be92b81978031a84eee45f9731a2a -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d0609608648016503040203050004400ab1a89aa9fb0c29b4163f44d7662e24023b152d820dc90168548295c7e1b5836d3de20a9fae39be49bcc40d0c54e271a4f6fbf4050c315553dcb6a3db8b5eabefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -n = a74f2eeb83f4f87768ad1068802b453e7b9808db9d1758ce52ccc70c3cbc4cef2afccf66b1116896fa27acc8cd779b4df59757e24bcc0e69f409b638cba8adbad885f95680dc4a7423d576c448cc38b00ec0292ea3323bd1eabe2bcb6d9e9c94665eda88dae5bcfdac2a3ca71b6d3bfd31cddda0f41f14dc5ddef946a9f779398b05e46678d2e490ac28c8807e9991bdc00ecc28d1b7cf63b6f3f47961080fc45e43729013366c654e1189888cfdb7458fbd56ba3b29756087ad1a0f86bc5e1637f7c6f881343033bec98c22e5c22d91ec2576c66214aa895d08c29707e0c181c666727767f5cb99835eb35a75d44033e5fbf947f7ca249861d5fa5b5d1cd4845d4d241048bfe2b06ffec934665ce371c826a2bb4c2de1dbd115a1e220465c6eb9d26297e2f9187726926e33f6ac7154ed73148aab86813b11b7fc043a969c8b9477aeb6305a73e10cd9db0cd5dd323a9c7ddc08accc214b4a555da9cde05f3a351948e56848d543ea504071f6251e035af576e04e55725516e215ce5b40c13f4029caeee38e4183c834127c857e1a0ce52e2db2faca43542eed0fc2331980be2e70ed938e007d1ef56f103f800dac041bae43d2117fc7030da4f4a87b1161c7cdd46de4098d10167e028fae2eea05da82c687ad82817efa65e973845b5a103424d17234fa78da06984549569443fb9c8755c4627a5b04992e15c0823b45a855 - -p = d86293ff70f21a0aaf50f3e91a38fbd29c3e84a034b5a9d5ead0dfdf0707cd9a85bc5e17c51f149c804f9feb00c2aec790e605b53108cf008e7636ff32e0329af9049e0bc48b91e2712deb4c0b1c2e943da090ea0dfe4e64c79f4242366eb8761a827e64d7fd3ae66b340093a21024418db44dc8305fcb097b942b2f7c790835d27e24a9653eb7af54aa06482f6438d4676965d602f3f1f8939e184f6ac9c9df083fb862d617af4516d824f419e11157b208009cec826538f80331286925a47da40e6317914dcab19706831ec84f58d158d945a354d3d2d1900ba044e25741168d334c5100ad408591212f26481759d46a735fa5f14b650bc5ee0e4f059538cf - -q = c5f08c5456b320360fa4338f92b57a8c6715fb6ddcb07c2d0ff93b6549e7df6e8d3dafc5710f02b42d82f62ff2d365fd7d9b1518eb512f55cf10f347829aa961ba9edb5c5e36c1d899b4fd462e9e89050bf7edcb20c0b54771bf22056a7f2091739878dfc53047ea7cc2af9ced1fccee39b2e9502307f44b1e8f3065aa9d2a45e1b5ee174d067a32fd3573f8d85c17fe3153736e9b2ed6a9fe068530eafdb0c42c7ca5cc9fbf44f84594b324965f537f1862f2ec303b42a838ae892dd1a59b577b7506c663638c837b67d6e6d03066b71967ce938b381f91f50fa526089fd146f62977cc41111597481d9c3af2c099279be8e6cc9fe7c64d394f9298b44a4d9b - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = e5f707f500cc4d0d36ebec7b49ded4c1c1d8fd4186f5a1a5aec2a97e9400652b2aa57ffd90243299e5eeb79d5d3900869300a9d1214b2c606fb05420c81af4e9b3c9d8a5809afcb52189fc903b74ccad7d22a9a431834f9010396db75b58566d276af935f9b7132a92c3a39d0c179f002644e502dd2674fc3c66dc8c7442f37f -S = 84108250f5183b7a1957f5ce9c10b762fa7cf3444f76485c0b5033e1f922d45ca86feb96407efcefabd35bafa24b1f3e5d86ffdced1c3757e23017bc2a816e940391eaec9c2b1e01c1f29119b4064c60a2f5ed91162b308e21f70374815e916f134f7e8907a8fc120dea9cc15c53741ae1d1146942a06d0e1d297ec0fcd1e7024bacf58b0b64ab63f95ee3e3f3893a6a892c8c949ce1ad5664196bc7370411d6c18ac7b3998e5d9d35e6c649f9205f0453ebdbc9eb6da6b4aa549b2af507deb7ac776a89b43b87e01be516e4ba36cecea8fa598321beeb7eff47e7561b52be6ca99fe8114b9be68b0f77c5d8769c35fa04d5c4894d331e7a1d65f25b44ca95e8074931bda83dbb36ee622582112fd918a732afe4040280395fa87dd566e69b3668b295a53aeb3ade6835b32dc8bde3e59f6b6ee36322b39d50c14cc98f7af082468be675b73548f5194dd4c907d99db54f785097cb9ed28c812bee694ec4ee85a8d41501d0a70d82cd8316c2b63d06e2e502be79b5a1f7c06735eb5b850cb0562a117972f171e04870caa751064db6fc4b2d64a2ddbdcf1d17f6952b630b86d6124bf6a7449cc57ed4cafa192756571fcaea3e0a52a92baf4d18f7b61ac404876b1f7e6a53498bb9eccbfe94992a1f326017cdf91039266d9a3deed3dcb124ae6aa96402f80372881a207dd833b4ae38d9d9f5ea2f30a4fa45e566e33e1e1388 -SaltVal = 00 -Result = P - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 5eaae0a318af7626f80e9c31a4e7bc127d24e823c80b1efc0c13cbe7baf78d95130a3d0f47ca2deedab7aecf4c66d602f9d180823ef1932add8f8825a35726a7482e90da96c5821ccd6ed867472f5010581590b578cb6b71a46b60510194630cc3bde1ee4dc9fe1699db21e1db6bb2a6619a22a4bec22c3827525b541dd9cd2c -S = 0d5434fa33a83f13477d6ebecc596e1847218ed9dc99e9d75a175a85d3bebf47ac7fa9b537d48f49cafc12ad3b239a7407f56a27b9dc4ce222ac838a6bdffe594fab2c6d0bc15365a3e90f6765e837ad864105decfa723101affc6c87dbfa0cc0234b9f1fe033d34bd9a5c4fca3a5e228b3ee3c75bbf000a6ab654c2448a43a6b4d2439ee84bd125fb44688a942e847dba0ccf781840a0341516080bf7dc1ed725b566c07e846840d02ab8fca219127ba0f7fec701c79a1a8c7e1a3db32985eac37a2d15b8e22ba159a78bfaab05f00934c95c1aa8d9b350af9ee17de47a69ec25a05572fa57ae33d9ef1d7f1f6d149870c96b2c3f266df32e1e9ff28c718bd03d1b1a7ae7b63fe22a82c2b7879c117c7d16a805efda0925c02aa5759653dc6cae6f1d5ab02d718c78403e40ca30a9f5473777927980d142845178535dcef705d3ffc0f650ce17e8e984da4bf98a78c0436dcb00f96c8aa5f893ce4c2f5088d87d6ce2c90b09a107e3431c0cf855f641d964866b56f409e9bc7bc6147ea3838c1d78c833c973f2f3040872cae6d226aa77e95ac907dd514bfc3534f76621c4b663a0886fcf34e5f741a2dcad200943da40b38da72d6d60eb3ea0489ba6ebc1d0a5b19c966cfa87d72ff8ced17ac770f4ac20c88ccb2e3feae775bcd9747a5c87ac38c7294c7a99c04e1a421b14fbea33dac05f7efa2c0fdf6988cd8f15ac6751 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = f11684d68056464935458c80bb76ecc5ffb35a4c35ef4cc51d7c1c32847fadf60da0512f3106ea46858250c53b0af368ec6ac27695364b51df03234ca3d688beaddd4555c05dd6acdbeccd1fbbe074dea107b4405599355a6b6ac7d1c56401ec593527ed344551a2bfebca3742e0b74ea6f4f9517fff54074a1bd066f2105fa9 -S = 61caa531f63359df1779d5765223207864a01b218fca9a8ca97c125987b1aeca6e0f667276421e708f4f6943df074c48b58384cec8e773e60b4d2c2ecd9db62afd9ddaaba4398d98618ee89c6ea170ff53ad6bc0c08fbb3ec07954fdcf980df778b36c823f42844be7793e78d70248139fd8f6b8cef38d2f5a93e8c5c0b5f5f879f3f929da5b7d9d9727c808ece9290570051238b75dc13decda4e619800acff51f99538f97db8dbeeadf8f54bcc58c06433a3e018dc9bf8ffa876534cd4d2f3b5e88021e8141f0356d01f5198704ac9ebf3d4433f92e12afd6dd6ce5a734800fc874a0f1a4281f7120380db8f27d2cc54fc51291d68c2b031a046426243d2e1c34cae5302685e1eea7aee04d01a1cd4326297fc605af8a6ca1943dc43d9cacf9e713b9cf427628b54ef0da3bb13eb64b9dfdb9e173176c693453ebbcfeeb9b637bc9bfa401fd63f1edcd6fdba3504f73c7f2305683c8a58ab77250813cfe94fda23da973d3db920e3134e94efa3ecb5f43211b3d12c2ac67d7d43fc7237cb629bc8b2bcfe8593945feb32d3a9d2828a2e16efa56111c3d1e6406e8a738313b615a9ee30edb4d03028b7ea0545efaaddcb2a941129530f67e1d9d870a529c6c649ba7db4bf2878e268f7794943a19a0b9d230250491a870cdcecf971bd7e66bbab6a6e9ffaf5f8b727f00532a609975c78820b48b0af715ecaf6867bebfbd708 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443021300906052b0e03021a05000414f3c22813bf0da5f5ce5244a03ccc74c41a51caea -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 6b7c63bb3b14afdc085c08805123108fef29976a4c856c74d34473d1a553f86d8e9f4340377a6dd19d4172f9c13b86eaa2c5ad6f68ac8676e2db67cb3236af26c7c558688c15cc225fdbfa57c5dba883dc080bdb91ed95d7124b0eee8704e6a0fd37cabaa2ad75d63874c921c4c91e61863cda362e0e419f4dde8fc10a8444e4 -S = 2980e019c0c7e460c720ca8e45e8742a14a5c712db17cf51e8a5fc7ccd6b2878c4c609b1ccc6258493a965a444bcddb6a21dc129119f4425d1a707555a6b50bdbbe0cdbdf0abcdfaf8cff67c2056e2e9df573f425dd0f56fb1ce3e8171e12ef6e9b0062d5b393fd61b723801a9f57bd8dcdf01d0965641607e3c952715a729e71622a3695e16e92b7f8028c3ac25edaf3ebc34bde80113fa8d4d4f7a56b6aa0100cfea550a220a22ed7b24d35f2e89ab0709ab7e3478fc1a61f94b6726d5c3120e2de4cd8ea7f5c5651f425d4435c1de0696babe95094397324711e4e7892e287fe8131f976f263c0ef209bd78a248b1c72813c963ebfd52162ea9a6065aa32b0a97bb33eb39e3bcca888e6f92afb8f3891317bba4fbaaa27f638bd7900801683ab6a4f66d0101246c1aede70ddd6367d255f21e86ee48734df39549501ecd4367f6b59e386a9a42874cf0db6af11c998d29a62392d1bcc40f2feaaff847aee8bce8a93af3f1c0280966f9836af3098c10260dc6db8372939d020e863919e228f0df85ac23f67a5cd84e7a564bfae74a307140e636f10681514383d0b270d03cdd969b5e2eb5fec36af874b1d7f387b7ba69daba036527474fcc803f823cb17734e8faa073cf470ce65e480bb137332422a55d3bbc72a148758ee0a222f8febe8f8d99c1051df894132dea5b0387b5753719253ff3dcf94b006f2c83e06b4fa3 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 3be0bbfc2f5d6da14c29e7dddaf4630f902fe246117bce54b661dd248e43384da392dde67f42419def7b3a0307921d2a66372372bcf012a089c61930273dfbed0a8a70be4701c8c353cdd1a00de3fb19ff39bae0e1322caa5f5dfc881d608675f72f3b2b8d82473cff85725df5d14405e39b6d378b2b649bc3904dd47893200e -S = 632af5e0d55d9eb7d4230c6818d1a178df225d91919423df4168a3e1fe2142f1f26f00c5666dfe6817b2a27f3c2fe6546ca747d74467f85ac0b73b8e34639e8448e0a560b1bc3ec827819db0df2d22874106205f93dd0d903926ec0478a5361e7a9878c6974a8c095d1b5779d783823d4355ebe24762045229ea839d05a177ffabd39738488ff449111238397da1266eb97ce6e3c63c7cb9ab2950140ac4a94dd148520dd67527c48d086e20bb6e18a26fba04a81008e35e0cf04388eb4ae9a1193d4806bd2b771117dd2ee2f349b01805dc056e5f0f3ca4df9c15562d6e1c9fb611059136fa581125c383f6cdf2ca7f7bdfa6cc8d7a2aeb1e2ef7799941f2c6c8a34021be8c771ce3e37aaf31157f91c37ea9ee02e6ecd3001ec30bcd6a45258ec7761d967798402ad5976f22542e5604d58627fafba14bc5bf3145861eed0165484286a2bfa0e17a37710b3a17bf9090f3493c81ccac46078084dd2eb43456cbeac804224083b5a9bbac414a57332086b8e8b0881707d41d4089066e36469b0085da76c6fc16d2486b3f7fe31964f928d3d902c3d5598df2f72d1a2d5436779985bc9e7264d07448f792a7f394aa36c9534be9ca7f431e90729481d0397ad8e4db9f4a429f238f7e1cea5c03795d82beea3ccdec38ee4b727272a9eb520e943ef2a1ffb10cb9e8147e1ea0b1d3208810b891b37f9ed8722a93328468b9fbcd -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a05000414a42c6b6337793e971d69173bb994a17471dc3642efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA1 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 25627026d11f380f939eac2156adb1bdc2e9c087bb318c782b5ae52f0224dc887b6d2870a0a5c8f81082eaa800f50c15805c61b5fff976f312a3157f71bb6ae84262646c9be95e0f4289ffeab7555ec6746c6ae973738a30f143805e72de93b405a8edc2c9d4427cb01cb29083b5f1f72682a5ca1e880f5850a2ee750b75a015 -S = 3c76bc9dfff017dbc6ce8cddfb1066ab8e669761c9a3ba229229eda74f05d7790c0993883aab90d16c2fc358a7117f8118c9147c69810f2fe1d7cd4220c5df5bc67ce3d2abbff139083bb6d6c48f6122f71b30f20e37e39f760f9c3b317bb26d6a14fd864d97d13c9a1dd7480c03727a6b6fb2b1b74340678a68c0efbcd36a39d42bc8dff44eb78d1ab4131b80eb4cbcbb6687f0cda506320882dcd70c1839c653a026179a0615175660fe557f45867fe6d883cb808db01ab41efcc0cd2137355fd2ebed412516c8003213a523068e47ed03e58f529af079a5f86bada203793808d0454e8170c666b2638c248df1e6b9a0cad05a94f9710d7912d833e3a474a58b450e10a22188444b18dce363b1bb3cfba548206fe448e84a608694f060e71bc17e50c1c777b6fe8f0d2f480f154b90ac5c6ec274a62d23d72a263cf0fe797c5a1b226d612c2007b502b42c9cebe5fe27b5e2b731852ab7db8eaa8fdc005072c96ed55284cc59985aad5528100062ee96c482e9539cc0b5a5e30954ab4a386beef0dae13c681ad8729a4b3dad39739892f2789f18c5b517ec2ccdb2b9d539ee51546783e633efe4d22363858090a0f501ce4acb8231e2515bb06f02ff6b42ffc62b30056f71ef4ab1952b614c32711bf8211f99a97bd3d3c5780142f3730e7763a476584efe9d8bb8839d27c405f52306f3d4db3168a094316c699e9190479e -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = d40724deeeb76472778ad98431d2e2061239d0178df747d81349e77cda1e2c9fdd1393d924a1ff9245955a182bc17fee16f25868e32243748eeebbbbf54a34e9de7346483c250e94ae0fd20b4984e3c39773c840df999846a7f5a8ec787c66f2e10f8554beaa5b1fbbde87841381d62b9ea468ca0ac50ef56846f738eb1e8c63 -S = 258f159cb8bb860c3c3db9d6b59a44600190f0076d1f2ac163b52081e01fe2e7423861ed9bb5df8b40d4d1354dd74219c71247bbdec4be0e90910f827da0565b6d13c5f60db49e0932220c1861dfb3f0b13a5fa74477aa329ab24913ca918ba7cd4e72fa532e044910f6a72cb525853f926b752adc76d39bbb9a265206c9820c3e331670103fb82a9a0071dcc48ccc1a650ea1c95341a48476af0a9b0e4286d96f0a976d3884ba97e5aa78909748947996f233ba02d6586a375dbaa81f3f00f880352f7e1842dad59733a40bd0c9393276c47b8baa99e8404b1f539d09cd6958007b297ac8c82f66fe2768fcf572766522a104d2de11435a19d2d1ad77221ed22d045a227f437752f3029f6cc55a99511f1febecbd45d529e216803b335cc206810d19804874760f66872c8575022f7eabfe437924b931d18e8156f33e6eac5d5f1540476359c130781a436b17f3bc23eac0f9fdc06e9123109bfba7d9a7eccbafe6ffa87f6c872d952e7fb3f6f2f73455d0f4f7fc63a744e7713219425e746d7d2f9564c4cd1a6301cdd78b0945debc122d85adb52b3cce920b22e77f0c835a87da3a2c9ec3c0938551f76f229b7c734242c6b78eb7ede1424368834e94d9f7df0070dd4d5c7503b5b023508483c4977b0a69e4183e83b88fcd924df78387b916ba475d9cc922deabef2dd07a3920870ef1a8105d6a6aaafb3210a7b1848b81 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44302d300d06096086480165030402040500041c560c52ba7c3dc1e996063b94d4238054241198d156f307d890406f06 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 662e6fd267dd8f2e5f0fe89034e4b0a6e8241a256dc8cd6bbbbd966421e459aad85d4ef0de0569a0013d1ac33aee37223dca37aa4ed4a0155622c2c736e1a6f65b9b420e93b5ee541f3c1cc909e14351b8411c14c16a1125009bf362e84ceb9b176eb3f62df40591df92546a47c5bb7c7e13332b6d9408e2e0b18efbdc2c10df -S = 76070d1cc628d84353c5535dfd3dc19573a91911217d3f9382de19b3d51f3f5607c7f88d82bdca4871b5361f39b8316b45a9bdb3775a69714bdaaded31dedd9716a8ae202c0237732b935c469ba22adb7dd67f67f5717787a6bc33e303af0f341cf202f8696c72f54772bd619c7929afb2785912701e91d96f9005942e6d11fbd757239a5cafbc93ca098c5632424f7b930e69457cc8810cc9ac3b5a1d1e17009ee45887a632cab31c9d9dab6e843481a09e5a7ca77be9d3d5b0d668689bdb82e4e2e43310fbddd5774d482b43cfc1499196ca521fc58bed44971eb15d216ee55b125ea8f65439425dfe1007d0be5418113484e1ee9b1fe3ab25625ac624eecbd03ff9e1b7dc66503afb625ff659917635098442af02696feb0b2d9559c19505cfde72470d34dd1719655874c8d4c23a94d5f91da9aedfc38e96e271ecbeaf924d7a9313cdcf6f485cfb1f3107c3ce8e0fa06a326ed75732738d52a094e9babf6e14f3f67ed48a09797020c9ad48a31aebcf4fe0e0b4d1c128a0f90f2bfdd520c566559747802367e95d45cc8202a479fead34c90c4663f313f3db337cc244a85eb595a904ac9c8c213fa6e762a251a4b84e733b7990aaa92a358ef369732f2224b5d37692f48f8cf6589034755347eff0c34725236d3d55ec27ae919e6d255025e4d2636b6c07807c66751942d9362143de6133a90f3d3503d9b50f91d549a7 -SaltVal = 00 -EM with hash moved = 0001ffffffffff00302d300d06096086480165030402040500041c58df3479e243f7dbe552ec444cc92a91f478808b02c5c6b5c28d44d0efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = c65baead3c9c432956e7da3ecd9f9b81b220c054b3f6f9b79a4e0f6116a9c810bed80c1d5324455345cd0c0179b6014e4a5efacdce1261515a61d70348d11db1f7d0356914edc4471848bb8b124736eea78ba5375723290902ff41ffaaa7a5fb7a2d72ba075f88acd742300320bc030ad19107b9d6911a86980f947dc4942893 -S = 6676debdc5c1d257b6bf532f1f61981e769e3bf0676b5050a8dbc65ed78ed3b88c687d0213ab1c0ad73b8606e2e2e9ffe7ee8f9b20a532a3fd59945b9f371d13807e36da1aed420d4390c26980cf70465e3dedc22368b09117e4606257677132a7c92e73c0633718290535915c512d629bd3db35306f264c5681e4b48e3f5e63f46289e41d74ab29a099c637132d2b8a04bf7649e4fbb0a6b3f37873d2c001d7833c9bb1f4de8043858223dd005ef43c6ea6e0806d2958ead96fa89af9119b2ac16b6302e9f23c5a2d79a2d6c4bf5b576ab07de117857ad4766606e52de3b1cfd368746425c74154cd814e63ee05d419c9f05038683970019b24961de26f0312203358cf5a69fc3a8c34376774d93a07e8ee8cb4e49d3c8061cd988ea9a96973b07dc8a8b96db165a0f287df5a538304a9b05e2ee294c155e17bef1df251297213904b56fbd3770d6587e0f610b291d0be288bd744315aebacdd71d00316f9d169d542108747a10aa65c36398eee21d7c580d088871e9c7be4b590f78b8f315f92e6970ba9fb9f929af324d02a281972cf2841155de6a76b54c1316c818f9c21c52eb8ad063b53aab1b22e72054ecfcd833efbd3d0da69c3730e81d48f54cd9c22da891fc589b3b61b5a226bf54d401e576f2ce86c9b651cba2d93d63e2e3181a97baa20a15f6e584dc30e1dfcf1a3d2b69803eb84d3ed4f1e153b76f14def51 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 953446b04306756e65d0cd8bdc3960a0713b59fdc73c90ea8d7b5b33f8aea6e371ea464f8bc28a5637b313e83bc0e6c5e059c087eb81aae3cf30cc2c21f686184ce2bdc786a2730103eb9bc0681c2bee821e726f388eac62be1ed4a40c38b9968fe554211eee59f72f410c1b4b9556a3bf5118bd95aabff0c20c19a4a1bc67e5 -S = 179296ecacedd93047d4442e8dd5a0de7e2799f45ceaf381cde74f3dfb96d5afaac92bae3df1a572c24757eb2cf91b970cd038278623d6cda864d2db12a763b94198dcb47e6041100ad6308403ad35859d19ff3608dd6dda433c4a30f53dae2d615e612cdb0c0fd4543243b02e873a3ad6a7315b0144a9c1ecd18c446781d7a8cfea621f646a219d6d108b5679520158c3d51287425cc920e65c94eeb01f9b92bb16d167e60906e30e9d2dc8a3fb8d509bfc406994e3d0a39e27d13b3ed5015c61c624e1f3425793c6b0a96a4982997715163ea2ffbcf38680edc6f03a9981d0283053bb3b84061e5c5ec886ff6cbed8041980a49af1ab383f349ea01be6bb0fac45be52a853770e9b0e8f1ddf69a18edbd858eed11c0c8739379de177074aab7c9e20d1783ee7dc46c186eb3966abd35ab08df3574db45b674858b3baddac03fa27d818eac14d3edf5f53852a6e42b052aca9b1ec392d70d53ed10af5b8b5e0df1a6318c558ca47740dee0e5293319a398f01e92743a425a8d4940b65bd16ad266c0db2eb5d53dc3532c98edbad8faf955d65811003a2d887374218bc4504b82b710dc828d838638ff3e8a25cc898c8d210626388132b9e023900d4867350c72ae8c3bd6f0c4d2732294403c1b6b2ef03670e44b2e33e05c5a00299e070a237186b85271a196908609a996cb386d20e285ed3446bd0f03a184aa47998625cc5 -SaltVal = 00 -Result = P - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 4a51133aae088367ed396b7e7c5115f017ee32fc10e9cbd2e8947af91c40d9ee41033b0e53b89ab54b46d1a8ef260bb0ee1f7c882c544ff95b81df44cb8229c0831582c490e085c79db650c6c416f0e7a4f4195bb4bc1a88d695116830e35b2c370f4f260c8a2ce50c0f4fa2a329aadb60f6713d4f2a16c78356782df26b587a -S = 0eb8a7a48915663d4feb5c00c37b1862c248e9305c2644f40b32654b1899e0469554dee6495c6142588d25c7b04d9e498422902307bb8a861ffe02bd3e15eb521241f69afc928325c85508e698dfb5f2ecbdb555829a6c0a1ed7f97a711ade294107101bcae30d469734e7344ab29b03d7bcfb364d219d3d984c1f5915bee9fb6e2255cdcb0e8500bf69d9c8751dacad6e966438eddbe6325141fbdddb4d9c45554e467df872a0dcf5fe9e12b7bf610117bd0662cf2d97c33988c2244283dbd3cf8657c69a94bc48ccb22fff87308eebf175874dca3d5baad98adcfcad551b8f397f76a96f02f398f7e1a5c5d49ad6490d2476b03eca81e806089b5f88c368cc63421f20f54e6b3eff6c020fb3f7a6df34c2592dfa3f45327541ebfdc7f6f37e6ae0609fdd6aae6add86b9a793023bcb0bdcdb051e17ff51ccfde476a87c04a5b2f5ce11e014360dd9547996dffa7c075f7eb4d2d779443ba313af95670a33ecf0db05c7fea3760e53d08707441d7ce6f068d45c746d047ce7fca96106b100d704363bcf82e0b384f789284b8e472581a52004a7632fb6c8d4bce4e325a321d0ed7873aa62b9098c73ba4cd185a5ad2e99850c57167dc75561d630fa9e9b2094c2f327f6f3d097121be3d1444d941002861feddc38ddde941a223d9f525bf5acfe4e5ca39bf39e5f37b5db29bae077d451198f1e0d99fc93185c2810f602cd1d -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA224 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = d9b8ac36d3fe6d7e9c008affd1752d4b928c1f1787dae8da249738972b0b85f67243f69ae60880afd0124fc2577867d6466b8bb410245d82121bc897177a9b8e21d17699670bea189aa1dc6b6c0d2a04538292c08adacf775ad004d2976f5e5c6dcaf5dc5deef4e38215faa1191cc0fc4037fbe4fee484e0841db6edb2d21789 -S = 14ba242af3387b7b0489a0012f787986254b084dfb24cd31d7aa143756886345462f6d98ee33e8477cf0606c60c99b585b52dd301975f7400e73d5cbdf7d91ddc5b7262b615d39f2d0ae48bd5695a61630b082ec78cde6d91dc4b3fd518c413bea61a966b1d5b316cd3878a91d80a64d52f5ef24da2378c43e528b4b912d823bce8987a9b908ac884fba7a03a2129996a60859761d8498e5b9e0c9afd9aaa901c8abfcd80a940ddd9731351deb918cc6177ce0c12cbb27695487e9de6fa23203dad7137e9eadc5259a3c850530c2283e1178c0b2395eedf183c3cf78ea4f3c20b3e80017f669ffc97649f439bd6476ab484b04e0de8e96b596b1994b6a99d732e54886daf9ec82d22e2bccab9ca64db92e1299302eeb031c667aebb0509f6a39e22f2bae56e7cbc06c9a1ab76c16ce0fe5ad92155b330f31830a1df7af51f1178e8aece7bf595152b2530199193eae8c4586af91eb1f713c45b08a87b75d825dee919881ccd9a6448dd2bd0767fadb16415c305825d7db8e01d89ca97821f0293acfb1e85b08d83349f37e99131d3766636d6c7f61afc77c059035cc090e95e987687f3d764264d2c82c1ae4c4766365977365f30b26ba23755dcb6b1545433284a4129dc39625156057f23c44103ba0f02706b16f630ccea0fe204d43d9ef162f0bf17fbf83a10816b66365cfd5b9c4aaa08ec8e1260540e9fdc19fcfd2dd91 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 9b1f5c7d045d72035019a18dac59247ac99cd251dfc74557f2623b6054043ce56b0c7e57b49205b3089e0e571e97ae1452feb784a45cdb9d04781487cdce43ab8f3d170d110030db96df844660a6029073d776669b9cad71b0ffd928195d36e88f18ee46238d3ba48346cb0279706817b48fd8a0cb7002f97f5f53ea419b60c3 -S = 3a9992cd8247ecf8ee650608b4520bbab5fa1774b8381c702930216b0dc6b9040b0dcae567c552ff5870a438d478c805edb56f396e9dfa422464b9559091aa231cc83ba676029936c204e58e473d93a8bb598135463614df6a54dc050f8db86bcfbc942979c3f011b8db0cea0b6bb0695ea1fb8c2f5872e4d89d9ae066b62b062156bba2ccf2be26ee1dce469219f387ec865f16d5b6babde6d0eca2efe1c9a51ec9f1f44a3cefe4eb054d33b80cf945c8bf530b9f8f924952d02fa75c410f3a57dbc2307f03a2cb9455f8a02e1b36b75f0f64087dcae1e639cd360da5d6a7394dcb7c1baeb4b323783cd3fbd207d8faaa5cc3b93867be4d47d934260129f0e51fd1dfb78b3c7c59f02b71be439722ed22654db5c1dc24b83785490ced8d0b97e11f85ee42f95582802446a38d812d59efbc6012a5dadf162aa0979a5de4fb7e4a19b4531c1b11231cb509f3dc05c74d90a1e2a8d9e6168da9fd226d5e53e0cd5ef93fc7ed638287207932f2b1451bab5c4bcabedf244585fa27e1a526cd9c7535768078c2b447cb30b6687d373295d6983ffa31083fd5230eb3574c4b65cb4bce0059d8e77e240d6be41f63fe98e94e76ea9969d8874f92c971a98d184ad6f78c33d5a1051a33b99c2d481ca3c06372f639d78e9601c20f93368ce8a1830d0c5b67aced9f2af6d3e8770321b209e271645e6909e251d31be1156d99f1204ab3 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 82f869cafa1e8bec3d9891bf59cf8f15a0581b41f223afe13ff64efb471a6a4ca45506dc0b1818d6cff83197a6625f05b08b5322b5a7bfe1af5b02388874077624d96ad7a2bedd55df1bcbc23c5d3b14a25bf600c38beccaa276d45b55691394096edfe2487aa41277e8a667a326e9ea7daf4e02a239fe44202f0b8c3661554d -S = 94d64e8a8f8ff9fb1fc76207b8be1a45f76f09bd0287baec04cc53e08639542dbaeeeaff537b0de30d63ffd961080d3b94708d60b364990c6db0c8ad673e6670f2c476ad7d7a957bf3c46e09fcca93812daf509ed7b88b182ce6f8315ec4787da0b4a0a09f6f48f2cd4a2cb3257abbb1b5c921a0db8c9de8bc64b98f4c347e27d5d063e232e4cfbaae6cb78effedf18ee5f7af1765cb95a3a8db21cf94166de19a0180f7c152f6b25ea2a68703d5d4443c27523baaa08cbedd2e489b0235f2203165f13169e7df9d930fbd7556fd594571a38f4eeb5b428694ac5b9858d233cc2bfe0d21e2fd6f599479024369b7f102b1624ba4160c48028017aae2fa815f7fa439b1545dec9b9e372f7cd8323c8bbf7e182b064deef2b65731d18d2241899f4f573fd9421a4b9a809e9876188db404cb262485761fd9bb315fd69db37601da5805e8e3fa7a64f654a11259c0764b28e53bffcf03d71683ece0fb9571aac451c085c1190353ed1c7a07bc03bd4abd0ce68c6a848a17720dcbb03231e1f505f1a6275d422dd89de55c0d70ada23f5240626c42e64bf33b668c69b6aad7b16534bb10d1aef16ee155df6b0ed2d3768e48171c62838a84c982713aaa5e982370fe10625687a5a960bfb205f85531dc093ba443abf4d22abf519b7db2afc36bae0c10283a551e5aa41c942c9a28fe199522da96b4bc2d640453c6bb495c258578fe -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443031300d060960864801650304020105000420b2b9f428aca658a676034a1382b07d422f560f637c9fd49e258e742e065a852c -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = ee7d5046460f07173172b1dfc3382667b6080522b99da7580a115183475caefa82187ccc938785efb2d6d19a45a31aeff6be80dd092c7e45ec721d5b10106750f84b1f2e902faf03bfd562413fe2d365ad50a6d7dc7175116f300d04a79bdbb7799ea132e4116d9a81f6cc9d5cfb3b110247ded7db727506bad58b45b305f079 -S = 0642e1315d86676ff3f00490d4a2b8285333c7f7a14a152543d85a9f15fb2d54d60519d1896697b1ca9469c382469725455a7124191bc438b3566ed434bf318097e396c049aba9fc85a293ed4187d16bffeef55229cb52b950b504621cf13d683ccd6a0fb53e00d358551a8989c7afc09e34ec90f8286e7413de3decad04496b5a749a081c0e82ff71f6838780808270d72265e9abcf87f0e1f4439f0f7b3ab95729d4041a502573f94aa8fb1989dde4c2287335818f0fd03a72b4e6811249f665b0d05acff32069d80f570782f568bc851c434d82cc94fa168b6f2619a57a97284789bc41d9bbb29749bbbc3470c774079af80eba8287a2d53f4e14df1e619cc8b5e7709d5c54cd4b0cdcc8693c3d04b460c382531e749638736226a9ac2605f82eca3e3df3dae4f2e7cc70e0d39fd2772f193a4df10a25b58bfbc5497a0ee98e8f60cccedb1152741e52e53bbf3ec1a23bfa44b73753c60d69c1615c58739f2f093fbfd6c9ab25799cdd9e8b65bcac94af0ebab3f66780c3fdb486cb20427db12a97fd0257f1b7c956733304c4d30e3faa78c27bba260d697be1ef36eaae6c87d49f36112d7964ed7683fa47597fe58b212f19f4cc1d88805cad324fdf4ee05687421e827266d452a851401cc02c4af7a61fb1bd40f772bc1cca4e5955710f2e9ea23bec04ed7e3054fe8f1170c70935ee22384a43e82e1e855be59d428f8f -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 27331a2203df81efd7f4d19278bcbd4050c32f8fb6df3a93786e5147b6dfb62ff774343c764511f0bd893fc27511d2c47d15b7833933a22f2db548fcca13cfc787b882fd3409cab98ba4592c09e5a942fcafa582dc69a637de46a0cdc7ca9e7dfe8a6b2de63392916acd8997da412a02f519625447882df2b5aac283560c0a99 -S = 4bd55acc43b26d2e69cdee990682e40580642fcaa9c0057c2f3c6e3cff14234f8e7304ef16cd79ef50c6e52ea8b02a46915ec21371556d217da4f3820eff0dfbc1a3dfe8bb43756e2e829d4bb240742e604e1d6b1e3dcaf69f346839e0351cad7b10c165f34603864c47e6a01420e677a421352f4a20a18814b1fc0db029825ba182732ae1480cb1e18fd1ecfc6d0fb6b6bb32944580aad72dc7e9f0f9dd41c114f8a5e77a1a07da0b51ea830a5877ba964460d45ac122829976d459dd7e49b74130c201d413ac78525f75463f69bd2c9da63c848be84a240368b7dc004e4c26273e5ee4a0bbe2903bb59cc2200fafd222fa59a5cbce12ce1a375ad512284043aa4d44abf3846d9d21b3a27c28b03d5cac655f91fd17a9d0a15f450db44a09aee6deb337ff3837bd85045c2f716ea147f098ec2560655492427291a1619404c77985c860643e85e01a767a8367ea387f930686becd9cf51e6da3a5183ac306d30b42d7b41646355f77192939af92a248d9243144d6ed0c440c60e656d535d5e656d8d22df272daeb01336ed4f57f5dee8f8514d7a100e996ce32d06c1bdcfa8d490a53d0f4329052491e5f3173f0430f07f18869f866f8403a389b2be6b68efb44dcad6537a2e305500acda845b5f50e91433ad84a094c12c0a38682bdc3a54fd3f6b322cc72fbd2ec805748f7e82ee3e5fc4603140e3b0813cf81e1861fb2e4 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = c8ef4787dbd28656118a8cf26f182c77f48ffab67b6b522be3239c306c02cf6f6432349d041a6d6695eab5a3d67369d3a23dc8c9ced3f7a2516247faa782bb607754c50673cd51bd7f5104211684c611ea5d7e63cb7c1cd5cabddd469e0dca26477c832bf1943a451ae902d5f7f24a1a1417a4eb3c0bccac985ce57b1a4905aa -S = 578c8c3166a0199da16eb3f93eebe5d2bfc3ee668432bcd26d8c87ab349137f5392f60b66578eaaf47c3fc7ed0101ee650b51fd522f8d06474345eaa73e253f8b1c133a9a874c6234381ba4b8dc0494d1ff5d65167b0c46adb12538cfbc75ce1042e4d69cfaa4ef5083c08f91f03b295e0433597e0aea94dc596fd015b4770db71592b9f41e3b587313148a4a2784f1bde2755034bd99b15ae982e0e4ad4c9dc8f8d8ab06d692251520c813b540f5b514f88827ab94b879cf61bfbadff5277239079b90d023826f2a8f330c37bb3279d0ebf0659196cedbd91a347e8e0235a009d7f39fdad4faaffca75f6343fea2ec8c588776b64ec1371c90046ba5b6bb148a75c7748e11649442a77ed80e76a23b1c761b9e3636e3147ac6fe408fede1f4c7c7b8ca651abbbbd20d131218e2e43bcd2252b1b180678d9196c6067a0473c8c73f0610973807746b44c2bde619a5e4f4cb3371e260c47eaf31e935c025b523c39b659098369fff0215e17edda2985247c90b3d84676110e1344d538aa34dced5f97c71921406adca7bc1ec54ca66c43b7321497a71310f70184aa3691451f5207f455ad947e33c9f22f7a96fdc970c325a286848413fb092271a295bc0de317c0b76a2617fb0fdf2c792bcce16b9c3f5c4f03dddd7ca4b1adaa6f4dee058b1b3a2326086e5140ad8618c0c7517b148f1054b897548f881961d54bcea391f7a8 -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d06096086480165030402010500042077cab6a7538318a9ab5fb2c9399130c8fdd3064629374b4a49b2b88bee0e6463efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA256 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 5d5e9a1c2ab1b7c859c7cdbb21caf3fe77ace0bfdfb05af6832df249828fef2c8a9e884ca903562e60070813fa9f59201ba63fbb9c6965389668dcb5bd5b0e42f074f3460ee4871e0aa07b0642652a3d0cf9d06492b5f627e14031203c9d0cf8b66843d0005c32df7f198c5ca124509e7230f9826a9cf60d893c5952a75cd396 -S = 5b460ece8562655899aa4ffa98650e7043766b0b2735662ceaf6958df776efbb60c92330790a57cc26093db03f6dd9a02f0046de5f71397d496ffe41d70f4a0b2e98c0c080dbb546726cc4808e70cdb31d84c23c021c45b617c7778d102bad94ba0f98980211eff7ccdd43ea61c17d08f9e319bf6b36b56ca3dcd8b12a240d81cee2b7a7eb234dc822f610e2bc712eb1d9562d826f8fa902107487949fba4538ddbf5d41d161c55fb3fedd6d2c6f90ec177d672e136f1352f4d07d5c21f0173928292e310fbf40ea6d9e974ee5db68501069310b6255e0a541bcb335934e15f6e504807884cd46c91efa9e224f8402fcaef986da5f159a35a40ea221afcb9e00aaf968cacb7d720c2aa1c5025cbd2ae9e3857e857e9bb82981e43f3f197c1286ca0819a7caff78e3621807f2682fa10a49e7091419d99ff0f42ccd22c5b455ca8214117aaad92e46cfd8598dbb533b38d8a4d5f8cafe6caab99468a7bf540f5a7f15414c76b5b404a6cb855af8ad7d62c60959e489a40ded9898a3ee04fdd3de2f8ef95a207b226daa9e4ddcc688e7636fbaeddafc0282f5924f7ffca4f9cdd8115bb17c36ac2b8804c3afaccc1ed4057b97b59d01705cbeea65cac20c6623cdd66cccede7f1db9d98d567e5c48116159b8113f8247a879e0990c2a3ac8c817bf6c98902f8b497621a53ddbccb07d01b7f8694a45ee68d2d04a33cb3535db2e6 -SaltVal = 00 -Result = P - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 0a5d9e0c5ffd0d0eab672509388aa606fb5063e26d23aef59ab011f274eb3f0e6e5349654677159922b90dbcdf521470a696be4cc079c082ab53a5bf6de0c353288b6e92efec6b7ad88fa79652f72921b9e2466f28cf14898fbe2118053764845f8d735c0164f7f9f4715d5e3981cf635dbd63134e2c92526d79ebc3e4f708e8 -S = 31af3922e01de9d2ad34e11b89c1ec21ad76c2913375137206c779459c2db5fa9f180c1a061393f1106c7bd7c0c19e316f37f47f462e1fd870d05332ebaa582579f15e48729e5f8380c947f563244d08aa2104570334c60fa0a01a9f0bf9aae07e2e7c3e5de6acc71f8b3aabb9fe6036674d8eefee4fe7c0e5d3d9323e3fa92931c1a19689e53f4fa53381c4b73f8d91577ca7ce8128b88e8340b63f2e89a4618138c68ee53fb05ca95c94ecfc2526eebc9a38930c12c6f4416db316c507dbee0fe64a3bc66041aaf95f67d9a0294d97b4a4579e0f946fbf7309f042307fd3611f5ff2aab4a738410b62327d2b57cbfd05c5af3e6d61c794732fdf160e61b8bc6a4d3511668d2340bf6d2d1d46bd960e9be045d83bb71a93f1d9f72c67d8e318dc9c78da55758b660e2b1feb7ced2e8ff0a4a29e5febcb40078c92b8019db63551ab866959732aeba71a94df7c35d753e5a831da820d45f09a530176ed964387dda6e7e047302428583c16ace2f4a90f86539c756c0b7baf80a1475851920107fb9f742db3086067fa0c8a6a326f14ba69f8dee961e5cd7407dd5e6d74e81730492d03f825cceb96f2261f2d6b3bb48df1ccc07b9830df23aa26aac452d99d61bab38735b9daae68caa8a36ac7b57e01d181e6ad3321851bf42cfe627c0e2526af37abe7a8f454d754adbd24fccae6778547651d281354e2b167a21cb2e58a86 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = c265cc1668d494b6dbbf477f187eed2a862a49392b00b180200a1de342fc7d612b5c505261e572eccc2e350c6e87b4344e2364cfb57decbd9df4370b67b8c702ccea4c6416ff75f2906606313b6a2b6ec2590b00b0e6a1cde1ccc71036b494598d59e8d5f1ea45cf0db0e177e7f0f9e2cb136753840477b9d3daf77819b78d6c -S = 7b6e5c6672b76a49b637135878e9738da6b1ad1710a1f8c557c5de7c3a5364d4927f3497d6b7daedb931a65e3433dbfde8791af39c97e90437155a3eb3fc96c37d2b0a51126faee5706b0b73c63413f9082d6f0a3d2ad7fcc69e935c016a4abbb2295135bcef8c078e11e262c0c1038f4311926823cb1b148dd8e63942a927e806a84260e51341ff99eb02fa053dc9258b4113da1d76d0734f81234a51a196139171a90c60c9a6f6baadd3e3b99769bd1890984b3e434f94e9f27c7086d86ee86d45ddbd7130bde845b6c47b6dca29edcd6f7898a42e499555700683732feb4c2e200c0fb1e11c0f314682ead943aca08e276eacc1d67e02018690d159a7d50561bec7087c5e21b32bcf2b27c0245f410df9c137696f014befa4a0c13fe7302b44393bfe6e3747cd88ec2dff0c639bbca4e7ecb77f7989a35c2acdb6a9dbb70092a9b7f4f4c8c8d9f7286d9666b24393c95e2cc256c03645944fc7b194a73be5a6acca491c0a98e551aadf5b002a1c42d57149f6788697eda81d1735a85442b6b313ba798c92ec0464a4f02ec3cd5059694428e0961c93e75155d1e5f965e5956a82d7f9ebc51fae9ed151710768ff1c172ae2b68c81da2190575a35cbb5f9eb52f56ba5f838d05d40c35b9fe901a75d5d96e09b85841d68d055bca786514fc6249b136a22870379dbd54576a91b646406ed12445521b67c694e94626ed15f09 -SaltVal = 00 -EM with hash moved = 0001ffffffffff003041300d060960864801650304020205000430c0d206b5a6126ec9a86519315cb38f2484d00f36f2065d3a0dfe6f34657ad926ff281b90d8187ae2c2eb45c68643c352efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = f1fb8e6cfdfc5dd3931e8fb5c92b974650224e935787f170acfe69b22418d09f3e6d30a303eb8e45306d2758978ff976c3c185aadb9bd46dc871b8d49a2654072845def5f74da4465e4d4d91e7b162d0f75c0d11b2f7206e1988583e7546e48df9ac21caa3cca8c063e68ac87f39da3c36196c2ea442dd5ae56cd35a7d1f8619 -S = 2c0ce9b108db78aebb905e421bd0a993b38d9e6b66bba9cf5a9ad72fea11f0ea2a8eec30e7947fbd552c63535f2097e4d6ccf07024e833967a119abb869327d880ca2c21c3f32dd559eb8fb6090107832aa884eea6c9284231a6869013cb0654b3cf17cc87b39a9b7612e2c91f77ccbc1736d1c7e5816694632fed14bb764c4c4f5f80193b6fb9247026a3e754805f00cb8a73b62f01b6ca9206890aa3008e63a2ca87a0eb54affe1e94f2a676060921620ef8bfc8563abfc9006b8ed0f7c71cb8a987daa6d96c0b819e4d1cf279417998e8d9f7f4334186923a10d3ea888e0b8d8699494c9e5a0468345f1a93a79b436b864a4f84c74f77d95ac7095156d96d4b83000177cc33c8ff9f555bf5afd2968708eee4b10a397ab76c3ff22766caf8d3836b5d5fa7a580bceb6245063bfa74fa9d79cf2c61b8ab92a92ffd93eabeae820ddd5f4c94301bd7210b18142126267a1b2ef3f8725110ad570a7d46ef5a18fd32b031ebf23d0c4f56e134f76b667217d486845f93e965bca006934ef68d5e11f8edb1adcffaaa51b5b0f42959473c53348709ffea3963436dd7794aadee13aa24e1872152b9bbd031e71700a8924556b703c7be70d33e523d9ddddacf0641756468872c7ad17b71208c78fa993561d54aa6255b6abc5d1b9ea7c58f28554a76acc9f662e186a1aff26e6f7ce8c9ac20fb64cadfec72a08ece04b51bda01a7 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 879645d6b8014a368de5b3f59c0f6d61d05150fd6978461c447db0af5d00055c92f1bcd0aa916d55959933a7f5b85403de432482da2926a5312575316737623d05545f899d5d1c11084eefe2f2b8792d9971879ad18936de4c815b9018b821386926f4aa994c9e926d6bb04f9af52405874140ed5582bef01dfa2975786b8a77 -S = 2287114cfb12bbdf370c453bb39e68bea8c24afa1db85239b54f7ced68798dce71ccc3a283859cb67717b7d0299f28238cf05c9016e867203afc345498a98cc933165d1d2103263f0556ad6b89a408227b3d68909f1c31460f818da5a389033004e5d89909661995a6c98fa3a59a56869cefe67d06a7e5580e288a1d69eeffb1aed49e77adfa674123690d42f83411d807ee7fd5a2b21c055ebf9d393733c1fe96d9a9678814fbed5cf5478a54edb8e432524d0c05022a5b477c4fe901ae8b4a8e8d00b1519075fe5e160eb5b1c090a7b1deb970c7f900dd47c47bebcb3fb5334be683dadaf023660d0d82ac0de747f0982cc31428ebcabb03ab4eb46750331fa88db48c15b40dd18a83dce93e7e769db6dd32cb99a78243233d509528b03825ddd5eaf2f29b68396e23293607e8bd5455c23843f63304d5d3865943434b61f471e2b3464f37fadd3d29dd104b36c9f6f859f4d84446364fb56af34e9eb15882519b072b890d682b254d6461f997e056b42452a2346ac6f0653845d456b20c3a273a7d421295ff91871fb525c7274471ecdfa93c9358067dd4911a3010b629d0c2b3a2db23af2a4510d6230522b170b61e804ebf561c7ecf45c5b741c37141ee407809901d557e2c8f88e7a719f2d3b5952928722e96311b9a1ba5106cd5ae9d8d101d583d321fd42c68cf4c28d944ab9433153831e3884556d485c927970f25 -SaltVal = 00 -Result = P - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 92b5088f66c761117eefe5d57d490b0a2d8f735adaed7065f910c46f0e81aa55cc311ac67d5548afa4736ef7e1bdcb6d169febffc8942a2cc83d74bc12b44eaef51e1a72747f9658edd3a749f85a55b5923316cc7b2c4ff1dcd9186b2de3405e56a390fa14ef54f39f3418318ac5b0c8ea737b2aba5ee89c7e0b38e627b6864f -S = 50758bef01ca5623082d4fb6888e9c27598bdefd63abd5168c8a122d4bc26e45d50736136f9f28848b082f18ae69cc2c3cba98f3458cbe71167a6629ea604a606b7a10fba68edd1576367ef0551b1c0dac9ab830ba41d7c9825ddab0a4cf01c62669d3c7f434e18c6bba0c6b931f6317f66f0aa6694441bbb9cfb74220920d9d861a857cd984c0e35666eded9d6d67fead62231f2cef40fe4252d02aaa3b12418d26cb646128fa69e13c57f90a85a7606859f84da62feace94bfb607cbb8fce4c23006b1a3f0aa6724072ade5c1cc2c664556edb9d40ff63d0de44b35a68e81aea98e98d52883c4fe41cca6f1f09398251f28d30165f34b74b008af8742b93c8fb7586cef90efa60e0542f3f5f85dbee12b3008c834a13c587dbda2e570dd12149390fb7e8788b46502046e0e158c3aede9c789895af2508663d7d1b9ede251321800db59575bd7971bb9a93a2c0ad2ec377f0268e7b6eb404c0cc02055d0e69726176f39b8826b1bcf8f4df7a7ede44a5ebe2d862825d6b1c11e9a30ab838789bee11344aa1d88e8495792c68344fa889ee8c2dfa418b5fcd18ba7cce65018fb6ea8d00dee814084eac349f5a233f34b2921cc0f09b5f6b6aa4cdaf90196f14ea66dcc9ab1ccc4acc1ca2d097bff923252db6d19db50e877f6848e3a14dc8d799fd8a8722aa6e98b5b4e53225af9d2c40811c6967e525db1993ed1539fcecde -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443041300d060960864801650304020205000430d6b9bb354aa8acf8326afd721b8bbb21603ef5d2f897c52cc0f27f9169f5bb894168a77ee4a65079fd68e9b38a7a4ea9 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA384 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 9a5592fd0be381aad74258865cab802a5f161df848a2e3a38e382af2706b45c0e6a31048d77bc99f8c672182659a9252ca27f25d6566495f8e99e04907cf9a40ea0987e9df9cb7e492d64c9665e4d32c62f3d5dc7396a86ed5688bfccaf2f3f68ecf1f688d0df280d3d7024bc451edbf0dc4ecfedafbaad94aed56931f9cf6e8 -S = 6b95909cfb0edba3177083097f74edac27b652bfd73575efac3db0971290bd7718b5a5491724c095a25c1a75b67a24a9e7caea4e2319637abe40efc0c5ce640a879978aac6ec898a4cce02b87cffb59f0c27c1c01759d7f698adf77003e033e70895e64a1f50f8cc471f61cb8e4c37a6a32e0875551b558314442fd7880c1fc74046b960f6fb4938ca6a7b1fc709cb046cb51c5fcf32c5d8e63324c88cd3ba6ff43406688771d1fd5ace55ccd8c90a96f403461f65c1cafd3068c4be660ccd740f34edcc1b4c57ee0e5ea5a3c2b9d76e583a9d1c70f480f508d589e72dfb0e5a6355bd70a2f90bddc1847d582d426f37b1060e475bfc62ca3133f4431407b948cbbf8ef4ec6488d773c5a840ffe2bf2cdd8a9aa753d0e66733daa5837f26eee99be7ac230fe0437898b6f9cf8e92419f0ee112d0475dfed75f8a8dfa4fe2f1e7d54da8fed8bd883f7326890f74a61beb22ad9822536bd3780f8a18573d16376f4f393e8e2305decfea889933b92d673569b4038d49547cde3c11e4f1331ded794c6fdb266c02048ce0be47b829e9be709ceaea89c3acfb12741332d147d8fe981b146955a29186f1b44f69ea276e78448d5752117eae565cfa54e6dda92387f330542dd30bb9426e1965a76a5a438f55ce22d252fd8e62df04c4e8c7a719385d4d56f37194f7e03368d17fe8165ed176d636b3b55fb99c483d707d160543561a -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = e0e52ff4aaaab424199c5cf2a172d1ebe64f7b6e2096fe19c400048161ec3c26c7f6a3a66fca0230173bb73cad8fb9796e1dd7074f1b40e79cb148b0df516983034b8840b99c7afa1b07c7a98f68ae1fef44693ee7a4b2679e2485359847286cdb0d692c50c8276b6d2b13a211a4b8c5afecb979afdc5a821182427a547480c9 -S = 8c61782fa17abd9424bd4df6333f775a1a36cb913fc3324d4a860c4619ab778ec699e88cbf7d55d8b9e7c9a4bf760ff1238c1b65f3d3afb50702c844706e855187ca2fbc92c18f5ac9558b8b719f7e985d791caf719721c66673026c393fd6fe4aaad8829188e5978ed401256ab8ece9d6713b55a0b8cce1c33b9dc333ed48d83bbbab4290471866d1d4d3e239daa5f315e18a19f78d7679ea1ba028032dfbca40ab0ac436f948a129c7d182911d0452548755a90dffa2294a4089c2a46352b1e76e06c203e230a0229989ddab4171deeef125af7ad0be3f28dd2d3cdaf25ef500d8d7134546bc79806ad7bc8dbdfd882f6924148b2480cffdd9d4ef0235385c76687fe669822ae14238736c4e8fa48d494ea578a6a940f07be7284274dbe9aabba9b6077d253eeaecd483f60763f8baee3d5e27a7c820c103160df87f875b10ffad7d810283fe118fd040b0e64b8b007aaa049a5ea739f85ad8245e0223f3bb3c66904bb89bb58eed61324ceb4b49b951de42d1ffff7ed9905050d05c73f34946562d5d39acf768f7be5292f20448bc5b61795fe077631587abc5465e67fff8118dbefda942bdbbe673eab46142f047d0359f112f64ba92eb54ee45b349bcb3befb89e31080d48303c90acafa4aa09466348b50f2923d29c1f9bf34dad7b3246653c7fd20f480b33ef3d9e116ddda73b7791f2fc5fc4c31bcac2bde5b79691f -SaltVal = 00 -Result = P - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 2fd1aa7be544c3206a9d43464b3fcd90f3f8cf48d08ec099b59ba6fe7d9bdcfaf244120aed1695d8be32d1b1cd6f143982ab945d635fb48a7c76831c0460851a3d62b7209c30cd9c2abdbe3d2a5282a9fcde1a6f418dd23c409bc351896b9b34d7d3a1a63bbaf3d677e612d4a80fa14829386a64b33fa217c9b26e8453e4a6b2 -S = 560a204f8a24adc61ac4d3c8de48304d9c59f6faf1bf1059bf1edb7e786ad81d95d6e17acfc30d84a151ff5496507da3094b7464839443d5530e22d6316076fadb5ffa013319230b14115e0905a997f4019dad2abde8d415a2b040bc6413c172a620a878d3695f70ffceb14fbeeb4538bf3c9b905e5907cba8ed8fc4a6ef9eeb863c99251abfaa9c483198618f2858a0c2d04a3f7e1e51128c9309303e01182cbfa20ea398c02354247fb30d32e977e6ea2dcc97be8921149257d13e31dde63b4992b167dd87f53116114a6344a3913ee313b4361d9258a2b10e9cefb19d0455466574bd58c0f284f99362737d0ad83d3ed0d587084f4e677a6748d68c1e3fee364600905873bb10de67b02e0aca45273ddb2f667aa22e885231b2bede0b541b79d2adf5e251be56e43b2577bba5244838471ed6899871016372771f88ebde49a776bb11697f15e50d490be4e52f95868f01bbd8ca549a60c50f1e99ddfe399f76fea48567e6abc0a845ddac6e963964624e38e1fb56565f99f3cdd7ddb7aebc3c53c7d82c6e3eeb058d128b4bacaca5f5fc8b037818d34c732fd15aeb70b0d688a233b5f91b65ff1f68cfa6f3a55b144840a9979996dfcfdf84cd9b02d385a842b27121cbe645155521e2c53ba3f1747af5609950b0cc808f33402dbb94fd1128fe9b309850b9ef11e82ec0498d595ff6436aab76a4df49047d76e5342c14b1 -SaltVal = 00 -Result = F (1 - Message changed) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 6ed981437f350723c4f1677f7bacdb78d12a22a19b3ed30646edf16d11d0bfdb79bad65af59b74fae4a41716c4ac4bd8a4d3c0ffdc659fe0fb011eab01fa53f0cffd4562dbf449da282b8c9f76b1ece4b6020c92c0e2a748488c24a00e0c6bb556eaf8e298082dcc78cdeda2f88366a3edfe2ee1b07f924515d82bd4a1d0b230 -S = 4684f8bc41880feaebaf54fc8cbb1d85c378db4bb916a7e162fa6683667b2f6df1e41e722f57e027486dd2c89ec035e2fe88ec082bbc105422b9116362bb00fac7f687297a858a08bea678d8489ce7cc27133c4f0acba0c7aee1daa55938ba2fc8957e6dca7493c0f054cc8a61d96b1d2689b1af69b491f58aeb6b3011827ad0d60bf1385402d4c7e7dac0f6f1259e7069a788816cce8db301639007ed1224bbdcbef9447df741cdb6a1f03796398372eb86ed8c995d281326a834688010becd7c737096de2573eb210035f14b937cf614cab6d1717711685e029b7b23d922bf2d6d63e354af5cf1b8609d021196e04a4e1baab203b1adce2b9c4bdf5a9a989157d2832867abc5173e5944ff070c9f7b06a14373fac3bfd76a73129e4cd0420c4696da9ef6f672f4cc9973434bcd2f0e351fe4509138d20a55bf73e42365da8d7ba3dd74b86055a785d346546de0f9837ecbcf52d6658e16e657b20428a8003a9b31d9f69e8206da1068fea98ea282a8731d96fe5e5be7d0b68c9eaf16090eea1f424e4cc5a509f8d6efb97f846d8ff1bd739288deeeecee6d0122eff6efbba9541ee1b2387f2092022df8584521d556bdc7ff9c8914d35a7b44075382fa3f03a3d4ec1ad11539cdf3b92eb37da08949c7ddbc2108e228c4548f41224b4da41098ae67a048be0fd22254a49186360bd0cea7877621130af6b8abfb490a108ab0 -SaltVal = 00 -Result = F (2 - Public Key e changed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 3a33da20cfb3e3ac722e7df7865330b8f62a73d9119a1f21992e240f16197b0970775cb6bdd5b0a858f4c93e33ca51c86eca80ed2865924a95d1795c5009cfa0f3150ef8e68b03517456808324b6527846887291ccc880455b546c0ca2f2777beb955ab0efdcc4f0efdc0a8f001f1a10a7ecb28ea5c9cf5b143f67e6b3dd5ae2 -S = 2fd9e8beeb55cf3640f615951e25b1731e1c51b4a1a2f251ff2761c3de6393c00f1ee2876e103a38c3149eafb804efa687b953eaf86b270d6cef192869aacc206f2018067df43db0ad8de6687ecd0535ed299180521066553ae2e6ed21604193eac012986767e48aea294fa3769482bcd2c167723707284dbcc7849d8320220319f7087baae33e7d05cab1e1430d3b2ba0e9ec5c5620f097c13b5a5a7c286ec9061f1963d27aafd79e2a217da1cb99389a5335ceb7690db3ce5cac022a542c14be25cb3e090400653a46863f443bd40807c546916b8090098fc5416744aa8d167bbcd48d718f5fee47339ec5446bbcb53ff6270f761e57589c399b558a24da5a5b3121a4a296e1ee1e01395f20b967c6cfaf2dd92e6e9fbc7c866b910570808e8dc87b66a8d9518dd9829f71f6a5e7e544e86551d907fcf2da2f4707e19586c19598a063ec1bfb252d91449f22ca90f2f88bbc6266ede3c19912a2481f70795a0a6ab6c1644a9458f9dce7a6459587135f5e3f20944a00d0874ff3b748a12a81e54a33da1a65df5dd932dbd979c79116e7d1138d35abf18b2a82c364490975c118c194c102a7c0eae6c629ec8043f9c55b63e55eacb3b352250ef5fa489ace55ec6b0771711aefd26f35483dacabe89fd15e248f669b5b2c343ba9de80b523432b9a0e4b05486c0132c4e1608f49efd481aed7b6da2ddd78fd5bafefcef2f074 -SaltVal = 00 -EM with trailer wrong =0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff443051300d060960864801650304020305000440ece68078ae14353fad83f9da0bc52f954e4f83bdc06abda384df386e15c66759f7a78859e7627c41d5c146cb5f8a46a147f1bb3ce2fbccd6d7efaa3d098c0a64 -Result = F (5 - Format of the EM is incorrect - 00 on end of pad removed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 244581a2b06130d1af01b83ab281dc252d97481cd92819575660a0781501637975fb65e22c3ea83fe9ccefd13812c884a578ca2124371cc5b06a37923369eca4a652a84679e8f76635a1474760faef76a10e6fff2467f9e0401431be57fb32d7fe71d1385e082530daa84704f3e256e46880be1ea161ba924d8418664b623dfb -S = 45b532bc216a9e6c0b58ef1e500e0cfc11cb85614faa4301e5c373acbb46f1fa655975b8fe4d50098f5b1ffff7e45db3e339b27b2d6d3349fa952922b876dd333c862bacf6cf4d3b1b98fca4adc2a4674b0397326ebad63a553f97cbf763d5549e982b999eaa77dfa074311d236936056a2f097385136ea5d82f76190e4a896bd5c2ef3580eb98340b136dae2215c3ec324ad44fa1920213fc6985faa58fab2a5ab4f1c268dc1489c4f257e54c573247a6e32640780f7345dcd7c371de12696a2fff5d94ab9677914d3d21fd0b436405b8122f410a3374ed67c8b414120a1c50c18b6a8acaff5bb68b2ced8036d30045378402e4cd193cfab277e9808045b30c65f947f39c4b3b25af8130a46d03fef6ab01c8d3a5807ff6a96628523fcd8447f24d11cbad36b5553f5d4c8051739a700d6113d48e3c28bee871fc00c46b013e887ba957ab45911f056d4b98c00b4e6b5b02b1d674918b90b40ca688e096ad0705d6f72e4999b0cbe9ed94cb297df6872e02fbd3ed2a8be758d4e6af7fa416b14d6785852b2a06d001e1b10e9829e3c6ad27bb2f1ce05104115decac07ff9c4e3cbb0bc0d264e9f27e9dcb48a9d8ce44b5e6cb37defc81e282071eb0ea06285c5afed12fa5b509a54449dbcd19431ad4522348ab0aed336c351709d3aa717d1e453362bc65d041af2fa7c1328231420741b433373e78d98f23940d6e59c132e7 -SaltVal = 00 -Result = F (3 - Signature changed ) - -SHAAlg = SHA512 -e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 -d = 09d77b3b07c31dacabcdf1e8078a1321cb08f1765488e71b320c0bb56cfc04868a0edf060a6a6f90691164844852546dff634167aa1b0fe81d69fba8fcebcdfbee9e781425b29af7c5df6156d71b1264b592d53efa8a7bfd4a0b2fc0ac1863904241d09ea376ecffdcf36cfac560c74b210c1c1886d4a6dfc94959f5190e8ea9082d85e7e8fd58bd374db170f86362ed0b4c2a2084ce93ba924a95e905b52e1a9c2215cc3d5d8de7d76a718080c3a15e71ddf60af46bd9ba62557a00e9ced85ba8f0751dad3f4e212957265c67de3eea774d7f7514d40a0814880b724bc1ed43de7e7f34334ab19f9e50dd5fac9403c6d14b0ea9e1663e63510c96419c10c134de0eb4ecf88918f782e272ececca42a6c04898a0c738eceea3319e81c0e6fb4236fdaaa191b196a7e8fc39e35a88d844b2c2f0929f029e49b03f1b65804ced3594c1304fe2ae987ab4d24a7faed4da097d58c94125884d095b59d26f2fd207e4dca58c54c0a74115d2f635a97e86e484ea8fe5a25a0dfb787fcefbe53f4dcc299ed23802b79ae2cd433227128eed0bd640bb5f51c93707379fd715c7a39b69c559fb8ff6d43eadb2eae2034d93c0c7f39b5e50044aa201d4d0c3036e4004201d558c4b87e31bfbd10654032808d9133200f8ca8e8206ea26fe2a3ef27005d2b245bb91c528fbe9a45687e94aaae83cbe25b452b3c26bc17c3efda7818f24201d -Msg = 24c8f1e99508bd234cf1161e94b439ac41e6392994d4ff685e178fee68688e5e13b501353c7458b76237ab2a0b80434163d75cdb271b29eec11619bdb55359523b349a282d3f142824b9cbd6df7611cde4ef4c696995f9c37465f1e242bdeb2fe66e432a3212fa5cdaa0fd8cd73daa360a55903922eb76d0bf2d9fc3d74c4ddf -S = 3941bb2afeacc1962b51ffecb000ed9406ba6e0935006203eac5aab1e35b980e6b3bbacf6d79f249e2c0fcd4259298d659870fbfa7e5c78d0e72aec15768e9e9d7353369ef2c91240645dfe40d85f68026bc4aff204798ad20cdf05a66640f6885ab633597636cd5af965ef1d2bdcc5dd0922f23e150ba67cdf148421d6ed43349b2ab426af2c9609eda45b980c842c2817513f8d0ec7c1b404fe07a7269088e359948fa05a6d63d3002f88ccd3167dc30242a42a07b17940a4f5763013800fefced30d42daef920e15d167e6bef092d440be42624e6f855ab7842a8871140dc17458f479933e082f1794a4c56cb338d31ca4f5bc6983dc2ec124e6785b16a0530b4c7e33488da83a184aff5448277a61c32cf6a8a4995a939552e0cad8d37da113b7806510577af56f9abfc7a37c566405be6d0b3271d8dd9071a0e83c51467f2fd3d22c805bc9ea025d1b1033a99235acb145729df2b6dcd761196c74b02f8aec2b53d19c20be6b3f7e46c21690737c675d46d240d6774278c0dc7db0a817b570cd493530d2acc0685bb1d51a81992ba45a3acbb690467fcd2524deef1b2efd643cac753d86a760c9428427a7b5cfe2624efdcca0f4c2c02ae67c3e3df01c4a19c3172377b425834c1c376366eab600693f63ece2d6ff94412f768a9dba4d202d70a9324f76b2f58295015164213c71d3bae7b90edd800ada1d972353f320c -SaltVal = 00 -EM with hash moved = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d060960864801650304020305000440f8b77aee7f4480f3de4575717e774c7735f9d46cfbc3706fcc2cbfed078b75fa59223ba0cda570d5bdf5ba1bd9d087f37e36b22b65552b85cfcc01a7b30c7f78efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef -Result = F (4 - Format of the EM is incorrect - hash moved to left ) diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js deleted file mode 100644 index 1436196..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js +++ /dev/null @@ -1,416 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const precompile = require('../../helpers/precompiles'); -const { P256SigningKey, NonNativeSigner } = require('../../helpers/signers'); - -const TEST_MESSAGE = ethers.id('OpenZeppelin'); -const TEST_MESSAGE_HASH = ethers.hashMessage(TEST_MESSAGE); - -const WRONG_MESSAGE = ethers.id('Nope'); -const WRONG_MESSAGE_HASH = ethers.hashMessage(WRONG_MESSAGE); - -const aliceP256 = new NonNativeSigner(P256SigningKey.random()); -const bobP256 = new NonNativeSigner(P256SigningKey.random()); - -async function fixture() { - const [signer, extraSigner, other] = await ethers.getSigners(); - const mock = await ethers.deployContract('$SignatureChecker'); - const wallet = await ethers.deployContract('ERC1271WalletMock', [signer]); - const wallet2 = await ethers.deployContract('ERC1271WalletMock', [extraSigner]); - const malicious = await ethers.deployContract('ERC1271MaliciousMock'); - const signature = await signer.signMessage(TEST_MESSAGE); - const verifier = await ethers.deployContract('ERC7913P256Verifier'); - - return { signer, other, extraSigner, mock, wallet, wallet2, malicious, signature, verifier }; -} - -describe('SignatureChecker (ERC1271)', function () { - before('deploying', async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('EOA account', function () { - it('with matching signer and signature', async function () { - await expect( - this.mock.$isValidSignatureNow(ethers.Typed.address(this.signer.address), TEST_MESSAGE_HASH, this.signature), - ).to.eventually.be.true; - }); - - it('with invalid signer', async function () { - await expect( - this.mock.$isValidSignatureNow(ethers.Typed.address(this.other.address), TEST_MESSAGE_HASH, this.signature), - ).to.eventually.be.false; - }); - - it('with invalid signature', async function () { - await expect( - this.mock.$isValidSignatureNow(ethers.Typed.address(this.signer.address), WRONG_MESSAGE_HASH, this.signature), - ).to.eventually.be.false; - }); - }); - - describe('ERC1271 wallet', function () { - for (const fn of ['isValidERC1271SignatureNow', 'isValidSignatureNow']) { - describe(fn, function () { - it('with matching signer and signature', async function () { - await expect( - this.mock.getFunction(`$${fn}`)( - ethers.Typed.address(this.wallet.target), - TEST_MESSAGE_HASH, - this.signature, - ), - ).to.eventually.be.true; - }); - - it('with invalid signer', async function () { - await expect( - this.mock.getFunction(`$${fn}`)(ethers.Typed.address(this.mock.target), TEST_MESSAGE_HASH, this.signature), - ).to.eventually.be.false; - }); - - it('with identity precompile', async function () { - await expect( - this.mock.getFunction(`$${fn}`)( - ethers.Typed.address(precompile.identity), - TEST_MESSAGE_HASH, - this.signature, - ), - ).to.eventually.be.false; - }); - - it('with invalid signature', async function () { - await expect( - this.mock.getFunction(`$${fn}`)( - ethers.Typed.address(this.wallet.target), - WRONG_MESSAGE_HASH, - this.signature, - ), - ).to.eventually.be.false; - }); - - it('with malicious wallet', async function () { - await expect( - this.mock.getFunction(`$${fn}`)( - ethers.Typed.address(this.malicious.target), - TEST_MESSAGE_HASH, - this.signature, - ), - ).to.eventually.be.false; - }); - }); - } - }); - - describe('ERC7913', function () { - describe('isValidSignatureNow', function () { - describe('with EOA signer', function () { - it('with matching signer and signature', async function () { - const eoaSigner = ethers.zeroPadValue(this.signer.address, 20); - const signature = await this.signer.signMessage(TEST_MESSAGE); - await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(eoaSigner), TEST_MESSAGE_HASH, signature)).to - .eventually.be.true; - }); - - it('with invalid signer', async function () { - const eoaSigner = ethers.zeroPadValue(this.other.address, 20); - const signature = await this.signer.signMessage(TEST_MESSAGE); - await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(eoaSigner), TEST_MESSAGE_HASH, signature)).to - .eventually.be.false; - }); - - it('with invalid signature', async function () { - const eoaSigner = ethers.zeroPadValue(this.signer.address, 20); - const signature = await this.signer.signMessage(TEST_MESSAGE); - await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(eoaSigner), WRONG_MESSAGE_HASH, signature)).to - .eventually.be.false; - }); - }); - - describe('with ERC-1271 wallet', function () { - it('with matching signer and signature', async function () { - const walletSigner = ethers.zeroPadValue(this.wallet.target, 20); - const signature = await this.signer.signMessage(TEST_MESSAGE); - await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(walletSigner), TEST_MESSAGE_HASH, signature)) - .to.eventually.be.true; - }); - - it('with invalid signer', async function () { - const walletSigner = ethers.zeroPadValue(this.mock.target, 20); - const signature = await this.signer.signMessage(TEST_MESSAGE); - await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(walletSigner), TEST_MESSAGE_HASH, signature)) - .to.eventually.be.false; - }); - - it('with invalid signature', async function () { - const walletSigner = ethers.zeroPadValue(this.wallet.target, 20); - const signature = await this.signer.signMessage(TEST_MESSAGE); - await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(walletSigner), WRONG_MESSAGE_HASH, signature)) - .to.eventually.be.false; - }); - }); - - describe('with ERC-7913 verifier', function () { - it('with matching signer and signature', async function () { - const signer = ethers.concat([ - this.verifier.target, - aliceP256.signingKey.publicKey.qx, - aliceP256.signingKey.publicKey.qy, - ]); - const signature = await aliceP256.signMessage(TEST_MESSAGE); - - await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(signer), TEST_MESSAGE_HASH, signature)).to - .eventually.be.true; - }); - - it('with invalid verifier', async function () { - const signer = ethers.concat([ - this.mock.target, // invalid verifier - aliceP256.signingKey.publicKey.qx, - aliceP256.signingKey.publicKey.qy, - ]); - const signature = await aliceP256.signMessage(TEST_MESSAGE); - - await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(signer), TEST_MESSAGE_HASH, signature)).to - .eventually.be.false; - }); - - it('with invalid key', async function () { - const signer = ethers.concat([this.verifier.target, ethers.randomBytes(32)]); - const signature = await aliceP256.signMessage(TEST_MESSAGE); - - await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(signer), TEST_MESSAGE_HASH, signature)).to - .eventually.be.false; - }); - - it('with invalid signature', async function () { - const signer = ethers.concat([ - this.verifier.target, - aliceP256.signingKey.publicKey.qx, - aliceP256.signingKey.publicKey.qy, - ]); - const signature = ethers.randomBytes(65); // invalid (random) signature - - await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(signer), TEST_MESSAGE_HASH, signature)).to - .eventually.be.false; - }); - - it('with signer too short', async function () { - const signer = ethers.randomBytes(19); // too short - const signature = await aliceP256.signMessage(TEST_MESSAGE); - await expect(this.mock.$isValidSignatureNow(ethers.Typed.bytes(signer), TEST_MESSAGE_HASH, signature)).to - .eventually.be.false; - }); - }); - }); - - describe('areValidSignaturesNow', function () { - const sortSigners = (...signers) => - signers.sort(({ signer: a }, { signer: b }) => ethers.keccak256(b) - ethers.keccak256(a)); - - it('should validate a single signature', async function () { - const signer = ethers.zeroPadValue(this.signer.address, 20); - const signature = await this.signer.signMessage(TEST_MESSAGE); - - await expect(this.mock.$areValidSignaturesNow(TEST_MESSAGE_HASH, [signer], [signature])).to.eventually.be.true; - }); - - it('should validate multiple signatures with different signer types', async function () { - const signers = sortSigners( - { - signer: ethers.zeroPadValue(this.signer.address, 20), - signature: await this.signer.signMessage(TEST_MESSAGE), - }, - { - signer: ethers.zeroPadValue(this.wallet.target, 20), - signature: await this.signer.signMessage(TEST_MESSAGE), - }, - { - signer: ethers.concat([ - this.verifier.target, - aliceP256.signingKey.publicKey.qx, - aliceP256.signingKey.publicKey.qy, - ]), - signature: await aliceP256.signMessage(TEST_MESSAGE), - }, - ); - - await expect( - this.mock.$areValidSignaturesNow( - TEST_MESSAGE_HASH, - signers.map(({ signer }) => signer), - signers.map(({ signature }) => signature), - ), - ).to.eventually.be.true; - }); - - it('should validate multiple EOA signatures', async function () { - const signers = sortSigners( - { - signer: ethers.zeroPadValue(this.signer.address, 20), - signature: await this.signer.signMessage(TEST_MESSAGE), - }, - { - signer: ethers.zeroPadValue(this.extraSigner.address, 20), - signature: await this.extraSigner.signMessage(TEST_MESSAGE), - }, - ); - - await expect( - this.mock.$areValidSignaturesNow( - TEST_MESSAGE_HASH, - signers.map(({ signer }) => signer), - signers.map(({ signature }) => signature), - ), - ).to.eventually.be.true; - }); - - it('should validate multiple ERC-1271 wallet signatures', async function () { - const signers = sortSigners( - { - signer: ethers.zeroPadValue(this.wallet.target, 20), - signature: await this.signer.signMessage(TEST_MESSAGE), - }, - { - signer: ethers.zeroPadValue(this.wallet2.target, 20), - signature: await this.extraSigner.signMessage(TEST_MESSAGE), - }, - ); - - await expect( - this.mock.$areValidSignaturesNow( - TEST_MESSAGE_HASH, - signers.map(({ signer }) => signer), - signers.map(({ signature }) => signature), - ), - ).to.eventually.be.true; - }); - - it('should validate multiple ERC-7913 signatures (ordered by ID)', async function () { - const signers = sortSigners( - { - signer: ethers.concat([ - this.verifier.target, - aliceP256.signingKey.publicKey.qx, - aliceP256.signingKey.publicKey.qy, - ]), - signature: await aliceP256.signMessage(TEST_MESSAGE), - }, - { - signer: ethers.concat([ - this.verifier.target, - bobP256.signingKey.publicKey.qx, - bobP256.signingKey.publicKey.qy, - ]), - signature: await bobP256.signMessage(TEST_MESSAGE), - }, - ); - - await expect( - this.mock.$areValidSignaturesNow( - TEST_MESSAGE_HASH, - signers.map(({ signer }) => signer), - signers.map(({ signature }) => signature), - ), - ).to.eventually.be.true; - }); - - it('should validate multiple ERC-7913 signatures (unordered)', async function () { - const signers = sortSigners( - { - signer: ethers.concat([ - this.verifier.target, - aliceP256.signingKey.publicKey.qx, - aliceP256.signingKey.publicKey.qy, - ]), - signature: await aliceP256.signMessage(TEST_MESSAGE), - }, - { - signer: ethers.concat([ - this.verifier.target, - bobP256.signingKey.publicKey.qx, - bobP256.signingKey.publicKey.qy, - ]), - signature: await bobP256.signMessage(TEST_MESSAGE), - }, - ).reverse(); // reverse - - await expect( - this.mock.$areValidSignaturesNow( - TEST_MESSAGE_HASH, - signers.map(({ signer }) => signer), - signers.map(({ signature }) => signature), - ), - ).to.eventually.be.true; - }); - - it('should return false if any signature is invalid', async function () { - const signers = sortSigners( - { - signer: ethers.zeroPadValue(this.signer.address, 20), - signature: await this.signer.signMessage(TEST_MESSAGE), - }, - { - signer: ethers.zeroPadValue(this.extraSigner.address, 20), - signature: await this.extraSigner.signMessage(WRONG_MESSAGE), - }, - ); - - await expect( - this.mock.$areValidSignaturesNow( - TEST_MESSAGE_HASH, - signers.map(({ signer }) => signer), - signers.map(({ signature }) => signature), - ), - ).to.eventually.be.false; - }); - - it('should return false if there are duplicate signers', async function () { - const signers = sortSigners( - { - signer: ethers.zeroPadValue(this.signer.address, 20), - signature: await this.signer.signMessage(TEST_MESSAGE), - }, - { - signer: ethers.zeroPadValue(this.signer.address, 20), - signature: await this.signer.signMessage(TEST_MESSAGE), - }, - ); - - await expect( - this.mock.$areValidSignaturesNow( - TEST_MESSAGE_HASH, - signers.map(({ signer }) => signer), - signers.map(({ signature }) => signature), - ), - ).to.eventually.be.false; - }); - - it('should return false if signatures array length does not match signers array length', async function () { - const signers = sortSigners( - { - signer: ethers.zeroPadValue(this.signer.address, 20), - signature: await this.signer.signMessage(TEST_MESSAGE), - }, - { - signer: ethers.zeroPadValue(this.extraSigner.address, 20), - signature: await this.extraSigner.signMessage(TEST_MESSAGE), - }, - ); - - await expect( - this.mock.$areValidSignaturesNow( - TEST_MESSAGE_HASH, - signers.map(({ signer }) => signer), - signers.map(({ signature }) => signature).slice(1), - ), - ).to.eventually.be.false; - }); - - it('should pass with empty arrays', async function () { - await expect(this.mock.$areValidSignaturesNow(TEST_MESSAGE_HASH, [], [])).to.eventually.be.true; - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ecdsa_secp256r1_sha256_p1363_test.json b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ecdsa_secp256r1_sha256_p1363_test.json deleted file mode 100644 index 9cd94cf..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/cryptography/ecdsa_secp256r1_sha256_p1363_test.json +++ /dev/null @@ -1,3719 +0,0 @@ -{ - "algorithm" : "ECDSA", - "generatorVersion" : "0.8r12", - "numberOfTests" : 219, - "header" : [ - "Test vectors of type EcdsaVerify are meant for the verification", - "of IEEE P1363 encoded ECDSA signatures." - ], - "notes" : { - "EdgeCase" : "Edge case values such as r=1 and s=0 can lead to forgeries if the ECDSA implementation does not check boundaries and computes s^(-1)==0.", - "PointDuplication" : "Some implementations of ECDSA do not handle duplication and points at infinity correctly. This is a test vector that has been specially crafted to check for such an omission.", - "SigSize" : "The size of the signature should always be twice the number of bytes of the size of the order. But some libraries accept signatures with less bytes." - }, - "schema" : "ecdsa_p1363_verify_schema.json", - "testGroups" : [ - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "KSexBRK64-3c_kZ4KBKLrSkDJpkZ9whgacjE32xzKDg", - "y" : "x3h5ZOqsAOWSH7FJimD0YGdms9loUAFVjRqXTnNBUT4" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "042927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e", - "wx" : "2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838", - "wy" : "00c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200042927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKSexBRK64+3c/kZ4KBKLrSkDJpkZ\n9whgacjE32xzKDjHeHlk6qwA5ZIfsUmKYPRgZ2az2WhQAVWNGpdOc0FRPg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 1, - "comment" : "signature malleability", - "msg" : "313233343030", - "sig" : "2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e184cd60b855d442f5b3c7b11eb6c4e0ae7525fe710fab9aa7c77a67f79e6fadd76", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 2, - "comment" : "Modified r or s, e.g. by adding or subtracting the order of the group", - "msg" : "313233343030", - "sig" : "012ba3a8bd6b94d5ed80a6d9d1190a436ebccc0833490686deac8635bcb9bf536900b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db", - "result" : "invalid", - "flags" : [] - }, - { - "tcId" : 3, - "comment" : "Modified r or s, e.g. by adding or subtracting the order of the group", - "msg" : "313233343030", - "sig" : "d45c5740946b2a147f59262ee6f5bc90bd01ed280528b62b3aed5fc93f06f739b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db", - "result" : "invalid", - "flags" : [] - }, - { - "tcId" : 4, - "comment" : "Modified r or s, e.g. by adding or subtracting the order of the group", - "msg" : "313233343030", - "sig" : "012ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e1800b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db", - "result" : "invalid", - "flags" : [] - }, - { - "tcId" : 5, - "comment" : "Modified r or s, e.g. by adding or subtracting the order of the group", - "msg" : "313233343030", - "sig" : "d45c5741946b2a137f59262ee6f5bc91001af27a5e1117a64733950642a3d1e8b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db", - "result" : "invalid", - "flags" : [] - }, - { - "tcId" : 6, - "comment" : "Modified r or s, e.g. by adding or subtracting the order of the group", - "msg" : "313233343030", - "sig" : "002ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e1801b329f478a2bbd0a6c384ee1493b1f518276e0e4a5375928d6fcd160c11cb6d2c", - "result" : "invalid", - "flags" : [] - }, - { - "tcId" : 7, - "comment" : "Modified r or s, e.g. by adding or subtracting the order of the group", - "msg" : "313233343030", - "sig" : "002ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e1801b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db", - "result" : "invalid", - "flags" : [] - }, - { - "tcId" : 8, - "comment" : "Modified r or s, e.g. by adding or subtracting the order of the group", - "msg" : "313233343030", - "sig" : "2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e184cd60b865d442f5a3c7b11eb6c4e0ae79578ec6353a20bf783ecb4b6ea97b825", - "result" : "invalid", - "flags" : [] - }, - { - "tcId" : 9, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 10, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 11, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "0000000000000000000000000000000000000000000000000000000000000000ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 12, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "0000000000000000000000000000000000000000000000000000000000000000ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 13, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "0000000000000000000000000000000000000000000000000000000000000000ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 14, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "0000000000000000000000000000000000000000000000000000000000000000ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 15, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "0000000000000000000000000000000000000000000000000000000000000000ffffffff00000001000000000000000000000001000000000000000000000000", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 16, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 17, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 18, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "0000000000000000000000000000000000000000000000000000000000000001ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 19, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "0000000000000000000000000000000000000000000000000000000000000001ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 20, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "0000000000000000000000000000000000000000000000000000000000000001ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 21, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "0000000000000000000000000000000000000000000000000000000000000001ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 22, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "0000000000000000000000000000000000000000000000000000000000000001ffffffff00000001000000000000000000000001000000000000000000000000", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 23, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325510000000000000000000000000000000000000000000000000000000000000000", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 24, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325510000000000000000000000000000000000000000000000000000000000000001", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 25, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 26, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 27, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 28, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 29, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551ffffffff00000001000000000000000000000001000000000000000000000000", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 30, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325500000000000000000000000000000000000000000000000000000000000000000", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 31, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325500000000000000000000000000000000000000000000000000000000000000001", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 32, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 33, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 34, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 35, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 36, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550ffffffff00000001000000000000000000000001000000000000000000000000", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 37, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325520000000000000000000000000000000000000000000000000000000000000000", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 38, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325520000000000000000000000000000000000000000000000000000000000000001", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 39, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 40, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 41, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 42, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 43, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552ffffffff00000001000000000000000000000001000000000000000000000000", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 44, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 45, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 46, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000001000000000000000000000000ffffffffffffffffffffffffffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 47, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000001000000000000000000000000ffffffffffffffffffffffffffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 48, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000001000000000000000000000000ffffffffffffffffffffffffffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 49, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000001000000000000000000000000ffffffffffffffffffffffffffffffff00000001000000000000000000000000ffffffffffffffffffffffff", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 50, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000001000000000000000000000000ffffffffffffffffffffffffffffffff00000001000000000000000000000001000000000000000000000000", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 51, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 52, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 53, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000001000000000000000000000001000000000000000000000000ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 54, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000001000000000000000000000001000000000000000000000000ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 55, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000001000000000000000000000001000000000000000000000000ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 56, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000001000000000000000000000001000000000000000000000000ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 57, - "comment" : "Signature with special case values for r and s", - "msg" : "313233343030", - "sig" : "ffffffff00000001000000000000000000000001000000000000000000000000ffffffff00000001000000000000000000000001000000000000000000000000", - "result" : "invalid", - "flags" : [ - "EdgeCase" - ] - }, - { - "tcId" : 58, - "comment" : "Edge case for Shamir multiplication", - "msg" : "3639383139", - "sig" : "64a1aab5000d0e804f3e2fc02bdee9be8ff312334e2ba16d11547c97711c898e6af015971cc30be6d1a206d4e013e0997772a2f91d73286ffd683b9bb2cf4f1b", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 59, - "comment" : "special case hash", - "msg" : "343236343739373234", - "sig" : "16aea964a2f6506d6f78c81c91fc7e8bded7d397738448de1e19a0ec580bf266252cd762130c6667cfe8b7bc47d27d78391e8e80c578d1cd38c3ff033be928e9", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 60, - "comment" : "special case hash", - "msg" : "37313338363834383931", - "sig" : "9cc98be2347d469bf476dfc26b9b733df2d26d6ef524af917c665baccb23c882093496459effe2d8d70727b82462f61d0ec1b7847929d10ea631dacb16b56c32", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 61, - "comment" : "special case hash", - "msg" : "3130333539333331363638", - "sig" : "73b3c90ecd390028058164524dde892703dce3dea0d53fa8093999f07ab8aa432f67b0b8e20636695bb7d8bf0a651c802ed25a395387b5f4188c0c4075c88634", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 62, - "comment" : "special case hash", - "msg" : "33393439343031323135", - "sig" : "bfab3098252847b328fadf2f89b95c851a7f0eb390763378f37e90119d5ba3ddbdd64e234e832b1067c2d058ccb44d978195ccebb65c2aaf1e2da9b8b4987e3b", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 63, - "comment" : "special case hash", - "msg" : "31333434323933303739", - "sig" : "204a9784074b246d8bf8bf04a4ceb1c1f1c9aaab168b1596d17093c5cd21d2cd51cce41670636783dc06a759c8847868a406c2506fe17975582fe648d1d88b52", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 64, - "comment" : "special case hash", - "msg" : "33373036323131373132", - "sig" : "ed66dc34f551ac82f63d4aa4f81fe2cb0031a91d1314f835027bca0f1ceeaa0399ca123aa09b13cd194a422e18d5fda167623c3f6e5d4d6abb8953d67c0c48c7", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 65, - "comment" : "special case hash", - "msg" : "333433363838373132", - "sig" : "060b700bef665c68899d44f2356a578d126b062023ccc3c056bf0f60a237012b8d186c027832965f4fcc78a3366ca95dedbb410cbef3f26d6be5d581c11d3610", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 66, - "comment" : "special case hash", - "msg" : "31333531353330333730", - "sig" : "9f6adfe8d5eb5b2c24d7aa7934b6cf29c93ea76cd313c9132bb0c8e38c96831db26a9c9e40e55ee0890c944cf271756c906a33e66b5bd15e051593883b5e9902", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 67, - "comment" : "special case hash", - "msg" : "36353533323033313236", - "sig" : "a1af03ca91677b673ad2f33615e56174a1abf6da168cebfa8868f4ba273f16b720aa73ffe48afa6435cd258b173d0c2377d69022e7d098d75caf24c8c5e06b1c", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 68, - "comment" : "special case hash", - "msg" : "31353634333436363033", - "sig" : "fdc70602766f8eed11a6c99a71c973d5659355507b843da6e327a28c11893db93df5349688a085b137b1eacf456a9e9e0f6d15ec0078ca60a7f83f2b10d21350", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 69, - "comment" : "special case hash", - "msg" : "34343239353339313137", - "sig" : "b516a314f2fce530d6537f6a6c49966c23456f63c643cf8e0dc738f7b876e675d39ffd033c92b6d717dd536fbc5efdf1967c4bd80954479ba66b0120cd16fff2", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 70, - "comment" : "special case hash", - "msg" : "3130393533323631333531", - "sig" : "3b2cbf046eac45842ecb7984d475831582717bebb6492fd0a485c101e29ff0a84c9b7b47a98b0f82de512bc9313aaf51701099cac5f76e68c8595fc1c1d99258", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 71, - "comment" : "special case hash", - "msg" : "35393837333530303431", - "sig" : "30c87d35e636f540841f14af54e2f9edd79d0312cfa1ab656c3fb15bfde48dcf47c15a5a82d24b75c85a692bd6ecafeb71409ede23efd08e0db9abf6340677ed", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 72, - "comment" : "special case hash", - "msg" : "33343633303036383738", - "sig" : "38686ff0fda2cef6bc43b58cfe6647b9e2e8176d168dec3c68ff262113760f52067ec3b651f422669601662167fa8717e976e2db5e6a4cf7c2ddabb3fde9d67d", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 73, - "comment" : "special case hash", - "msg" : "39383137333230323837", - "sig" : "44a3e23bf314f2b344fc25c7f2de8b6af3e17d27f5ee844b225985ab6e2775cf2d48e223205e98041ddc87be532abed584f0411f5729500493c9cc3f4dd15e86", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 74, - "comment" : "special case hash", - "msg" : "33323232303431303436", - "sig" : "2ded5b7ec8e90e7bf11f967a3d95110c41b99db3b5aa8d330eb9d638781688e97d5792c53628155e1bfc46fb1a67e3088de049c328ae1f44ec69238a009808f9", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 75, - "comment" : "special case hash", - "msg" : "36363636333037313034", - "sig" : "bdae7bcb580bf335efd3bc3d31870f923eaccafcd40ec2f605976f15137d8b8ff6dfa12f19e525270b0106eecfe257499f373a4fb318994f24838122ce7ec3c7", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 76, - "comment" : "special case hash", - "msg" : "31303335393531383938", - "sig" : "50f9c4f0cd6940e162720957ffff513799209b78596956d21ece251c2401f1c6d7033a0a787d338e889defaaabb106b95a4355e411a59c32aa5167dfab244726", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 77, - "comment" : "special case hash", - "msg" : "31383436353937313935", - "sig" : "f612820687604fa01906066a378d67540982e29575d019aabe90924ead5c860d3f9367702dd7dd4f75ea98afd20e328a1a99f4857b316525328230ce294b0fef", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 78, - "comment" : "special case hash", - "msg" : "33313336303436313839", - "sig" : "9505e407657d6e8bc93db5da7aa6f5081f61980c1949f56b0f2f507da5782a7ac60d31904e3669738ffbeccab6c3656c08e0ed5cb92b3cfa5e7f71784f9c5021", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 79, - "comment" : "special case hash", - "msg" : "32363633373834323534", - "sig" : "bbd16fbbb656b6d0d83e6a7787cd691b08735aed371732723e1c68a40404517d9d8e35dba96028b7787d91315be675877d2d097be5e8ee34560e3e7fd25c0f00", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 80, - "comment" : "special case hash", - "msg" : "31363532313030353234", - "sig" : "2ec9760122db98fd06ea76848d35a6da442d2ceef7559a30cf57c61e92df327e7ab271da90859479701fccf86e462ee3393fb6814c27b760c4963625c0a19878", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 81, - "comment" : "special case hash", - "msg" : "35373438303831363936", - "sig" : "54e76b7683b6650baa6a7fc49b1c51eed9ba9dd463221f7a4f1005a89fe00c592ea076886c773eb937ec1cc8374b7915cfd11b1c1ae1166152f2f7806a31c8fd", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 82, - "comment" : "special case hash", - "msg" : "36333433393133343638", - "sig" : "5291deaf24659ffbbce6e3c26f6021097a74abdbb69be4fb10419c0c496c946665d6fcf336d27cc7cdb982bb4e4ecef5827f84742f29f10abf83469270a03dc3", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 83, - "comment" : "special case hash", - "msg" : "31353431313033353938", - "sig" : "207a3241812d75d947419dc58efb05e8003b33fc17eb50f9d15166a88479f107cdee749f2e492b213ce80b32d0574f62f1c5d70793cf55e382d5caadf7592767", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 84, - "comment" : "special case hash", - "msg" : "3130343738353830313238", - "sig" : "6554e49f82a855204328ac94913bf01bbe84437a355a0a37c0dee3cf81aa7728aea00de2507ddaf5c94e1e126980d3df16250a2eaebc8be486effe7f22b4f929", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 85, - "comment" : "special case hash", - "msg" : "3130353336323835353638", - "sig" : "a54c5062648339d2bff06f71c88216c26c6e19b4d80a8c602990ac82707efdfce99bbe7fcfafae3e69fd016777517aa01056317f467ad09aff09be73c9731b0d", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 86, - "comment" : "special case hash", - "msg" : "393533393034313035", - "sig" : "975bd7157a8d363b309f1f444012b1a1d23096593133e71b4ca8b059cff37eaf7faa7a28b1c822baa241793f2abc930bd4c69840fe090f2aacc46786bf919622", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 87, - "comment" : "special case hash", - "msg" : "393738383438303339", - "sig" : "5694a6f84b8f875c276afd2ebcfe4d61de9ec90305afb1357b95b3e0da43885e0dffad9ffd0b757d8051dec02ebdf70d8ee2dc5c7870c0823b6ccc7c679cbaa4", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 88, - "comment" : "special case hash", - "msg" : "33363130363732343432", - "sig" : "a0c30e8026fdb2b4b4968a27d16a6d08f7098f1a98d21620d7454ba9790f1ba65e470453a8a399f15baf463f9deceb53acc5ca64459149688bd2760c65424339", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 89, - "comment" : "special case hash", - "msg" : "31303534323430373035", - "sig" : "614ea84acf736527dd73602cd4bb4eea1dfebebd5ad8aca52aa0228cf7b99a88737cc85f5f2d2f60d1b8183f3ed490e4de14368e96a9482c2a4dd193195c902f", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 90, - "comment" : "special case hash", - "msg" : "35313734343438313937", - "sig" : "bead6734ebe44b810d3fb2ea00b1732945377338febfd439a8d74dfbd0f942fa6bb18eae36616a7d3cad35919fd21a8af4bbe7a10f73b3e036a46b103ef56e2a", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 91, - "comment" : "special case hash", - "msg" : "31393637353631323531", - "sig" : "499625479e161dacd4db9d9ce64854c98d922cbf212703e9654fae182df9bad242c177cf37b8193a0131108d97819edd9439936028864ac195b64fca76d9d693", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 92, - "comment" : "special case hash", - "msg" : "33343437323533333433", - "sig" : "08f16b8093a8fb4d66a2c8065b541b3d31e3bfe694f6b89c50fb1aaa6ff6c9b29d6455e2d5d1779748573b611cb95d4a21f967410399b39b535ba3e5af81ca2e", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 93, - "comment" : "special case hash", - "msg" : "333638323634333138", - "sig" : "be26231b6191658a19dd72ddb99ed8f8c579b6938d19bce8eed8dc2b338cb5f8e1d9a32ee56cffed37f0f22b2dcb57d5c943c14f79694a03b9c5e96952575c89", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 94, - "comment" : "special case hash", - "msg" : "33323631313938363038", - "sig" : "15e76880898316b16204ac920a02d58045f36a229d4aa4f812638c455abe0443e74d357d3fcb5c8c5337bd6aba4178b455ca10e226e13f9638196506a1939123", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 95, - "comment" : "special case hash", - "msg" : "39363738373831303934", - "sig" : "352ecb53f8df2c503a45f9846fc28d1d31e6307d3ddbffc1132315cc07f16dad1348dfa9c482c558e1d05c5242ca1c39436726ecd28258b1899792887dd0a3c6", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 96, - "comment" : "special case hash", - "msg" : "34393538383233383233", - "sig" : "4a40801a7e606ba78a0da9882ab23c7677b8642349ed3d652c5bfa5f2a9558fb3a49b64848d682ef7f605f2832f7384bdc24ed2925825bf8ea77dc5981725782", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 97, - "comment" : "special case hash", - "msg" : "383234363337383337", - "sig" : "eacc5e1a8304a74d2be412b078924b3bb3511bac855c05c9e5e9e44df3d61e967451cd8e18d6ed1885dd827714847f96ec4bb0ed4c36ce9808db8f714204f6d1", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 98, - "comment" : "special case hash", - "msg" : "3131303230383333373736", - "sig" : "2f7a5e9e5771d424f30f67fdab61e8ce4f8cd1214882adb65f7de94c31577052ac4e69808345809b44acb0b2bd889175fb75dd050c5a449ab9528f8f78daa10c", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 99, - "comment" : "special case hash", - "msg" : "313333383731363438", - "sig" : "ffcda40f792ce4d93e7e0f0e95e1a2147dddd7f6487621c30a03d710b330021979938b55f8a17f7ed7ba9ade8f2065a1fa77618f0b67add8d58c422c2453a49a", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 100, - "comment" : "special case hash", - "msg" : "333232313434313632", - "sig" : "81f2359c4faba6b53d3e8c8c3fcc16a948350f7ab3a588b28c17603a431e39a8cd6f6a5cc3b55ead0ff695d06c6860b509e46d99fccefb9f7f9e101857f74300", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 101, - "comment" : "special case hash", - "msg" : "3130363836363535353436", - "sig" : "dfc8bf520445cbb8ee1596fb073ea283ea130251a6fdffa5c3f5f2aaf75ca808048e33efce147c9dd92823640e338e68bfd7d0dc7a4905b3a7ac711e577e90e7", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 102, - "comment" : "special case hash", - "msg" : "3632313535323436", - "sig" : "ad019f74c6941d20efda70b46c53db166503a0e393e932f688227688ba6a576293320eb7ca0710255346bdbb3102cdcf7964ef2e0988e712bc05efe16c199345", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 103, - "comment" : "special case hash", - "msg" : "37303330383138373734", - "sig" : "ac8096842e8add68c34e78ce11dd71e4b54316bd3ebf7fffdeb7bd5a3ebc1883f5ca2f4f23d674502d4caf85d187215d36e3ce9f0ce219709f21a3aac003b7a8", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 104, - "comment" : "special case hash", - "msg" : "35393234353233373434", - "sig" : "677b2d3a59b18a5ff939b70ea002250889ddcd7b7b9d776854b4943693fb92f76b4ba856ade7677bf30307b21f3ccda35d2f63aee81efd0bab6972cc0795db55", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 105, - "comment" : "special case hash", - "msg" : "31343935353836363231", - "sig" : "479e1ded14bcaed0379ba8e1b73d3115d84d31d4b7c30e1f05e1fc0d5957cfb0918f79e35b3d89487cf634a4f05b2e0c30857ca879f97c771e877027355b2443", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 106, - "comment" : "special case hash", - "msg" : "34303035333134343036", - "sig" : "43dfccd0edb9e280d9a58f01164d55c3d711e14b12ac5cf3b64840ead512a0a31dbe33fa8ba84533cd5c4934365b3442ca1174899b78ef9a3199f49584389772", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 107, - "comment" : "special case hash", - "msg" : "33303936343537353132", - "sig" : "5b09ab637bd4caf0f4c7c7e4bca592fea20e9087c259d26a38bb4085f0bbff1145b7eb467b6748af618e9d80d6fdcd6aa24964e5a13f885bca8101de08eb0d75", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 108, - "comment" : "special case hash", - "msg" : "32373834303235363230", - "sig" : "5e9b1c5a028070df5728c5c8af9b74e0667afa570a6cfa0114a5039ed15ee06fb1360907e2d9785ead362bb8d7bd661b6c29eeffd3c5037744edaeb9ad990c20", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 109, - "comment" : "special case hash", - "msg" : "32363138373837343138", - "sig" : "0671a0a85c2b72d54a2fb0990e34538b4890050f5a5712f6d1a7a5fb8578f32edb1846bab6b7361479ab9c3285ca41291808f27fd5bd4fdac720e5854713694c", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 110, - "comment" : "special case hash", - "msg" : "31363432363235323632", - "sig" : "7673f8526748446477dbbb0590a45492c5d7d69859d301abbaedb35b2095103a3dc70ddf9c6b524d886bed9e6af02e0e4dec0d417a414fed3807ef4422913d7c", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 111, - "comment" : "special case hash", - "msg" : "36383234313839343336", - "sig" : "7f085441070ecd2bb21285089ebb1aa6450d1a06c36d3ff39dfd657a796d12b5249712012029870a2459d18d47da9aa492a5e6cb4b2d8dafa9e4c5c54a2b9a8b", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 112, - "comment" : "special case hash", - "msg" : "343834323435343235", - "sig" : "914c67fb61dd1e27c867398ea7322d5ab76df04bc5aa6683a8e0f30a5d287348fa07474031481dda4953e3ac1959ee8cea7e66ec412b38d6c96d28f6d37304ea", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "CtmVACiNRmlAAx1yqfVEWk1DeEZAhVvwpph00t5f4QM", - "y" : "xQEebvLELc1Q1dPSn5mubrosgMkkT0xUIvCXn_DDul4" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "040ad99500288d466940031d72a9f5445a4d43784640855bf0a69874d2de5fe103c5011e6ef2c42dcd50d5d3d29f99ae6eba2c80c9244f4c5422f0979ff0c3ba5e", - "wx" : "0ad99500288d466940031d72a9f5445a4d43784640855bf0a69874d2de5fe103", - "wy" : "00c5011e6ef2c42dcd50d5d3d29f99ae6eba2c80c9244f4c5422f0979ff0c3ba5e" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200040ad99500288d466940031d72a9f5445a4d43784640855bf0a69874d2de5fe103c5011e6ef2c42dcd50d5d3d29f99ae6eba2c80c9244f4c5422f0979ff0c3ba5e", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECtmVACiNRmlAAx1yqfVEWk1DeEZA\nhVvwpph00t5f4QPFAR5u8sQtzVDV09Kfma5uuiyAySRPTFQi8Jef8MO6Xg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 113, - "comment" : "k*G has a large x-coordinate", - "msg" : "313233343030", - "sig" : "000000000000000000000000000000004319055358e8617b0c46353d039cdaabffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 114, - "comment" : "r too large", - "msg" : "313233343030", - "sig" : "ffffffff00000001000000000000000000000000fffffffffffffffffffffffcffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e", - "result" : "invalid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "qwX9nQ3ia5zm9IGWUtn8aRk9CqOY8PuoAT4JxYIgRVQ", - "y" : "GSNScSKMeGdZCV0St1rwaS3UED8Z9qjDL0lDWh6bjUU" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04ab05fd9d0de26b9ce6f4819652d9fc69193d0aa398f0fba8013e09c58220455419235271228c786759095d12b75af0692dd4103f19f6a8c32f49435a1e9b8d45", - "wx" : "00ab05fd9d0de26b9ce6f4819652d9fc69193d0aa398f0fba8013e09c582204554", - "wy" : "19235271228c786759095d12b75af0692dd4103f19f6a8c32f49435a1e9b8d45" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004ab05fd9d0de26b9ce6f4819652d9fc69193d0aa398f0fba8013e09c58220455419235271228c786759095d12b75af0692dd4103f19f6a8c32f49435a1e9b8d45", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEqwX9nQ3ia5zm9IGWUtn8aRk9CqOY\n8PuoAT4JxYIgRVQZI1JxIox4Z1kJXRK3WvBpLdQQPxn2qMMvSUNaHpuNRQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 115, - "comment" : "r,s are large", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "gJhPOaH_OKhqaKpCAba-Xfv-z4diGXELB7rfb91MbFY", - "y" : "Ef65c5DZgm56Bt-0GHHJQNdEFe08rCCJ8URQGbtV7ZU" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "0480984f39a1ff38a86a68aa4201b6be5dfbfecf876219710b07badf6fdd4c6c5611feb97390d9826e7a06dfb41871c940d74415ed3cac2089f1445019bb55ed95", - "wx" : "0080984f39a1ff38a86a68aa4201b6be5dfbfecf876219710b07badf6fdd4c6c56", - "wy" : "11feb97390d9826e7a06dfb41871c940d74415ed3cac2089f1445019bb55ed95" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000480984f39a1ff38a86a68aa4201b6be5dfbfecf876219710b07badf6fdd4c6c5611feb97390d9826e7a06dfb41871c940d74415ed3cac2089f1445019bb55ed95", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgJhPOaH/OKhqaKpCAba+Xfv+z4di\nGXELB7rfb91MbFYR/rlzkNmCbnoG37QYcclA10QV7TysIInxRFAZu1XtlQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 116, - "comment" : "r and s^-1 have a large Hamming weight", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd909135bdb6799286170f5ead2de4f6511453fe50914f3df2de54a36383df8dd4", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "QgG0JylEIBwylPW6qaMjK23Wh0lfzBmnCpW8YCtPfAU", - "y" : "lcN-up7oFxwbtaxv6vdTvDb0Y-Ou8WYpVywMCo-wgA4" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "044201b4272944201c3294f5baa9a3232b6dd687495fcc19a70a95bc602b4f7c0595c37eba9ee8171c1bb5ac6feaf753bc36f463e3aef16629572c0c0a8fb0800e", - "wx" : "4201b4272944201c3294f5baa9a3232b6dd687495fcc19a70a95bc602b4f7c05", - "wy" : "0095c37eba9ee8171c1bb5ac6feaf753bc36f463e3aef16629572c0c0a8fb0800e" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200044201b4272944201c3294f5baa9a3232b6dd687495fcc19a70a95bc602b4f7c0595c37eba9ee8171c1bb5ac6feaf753bc36f463e3aef16629572c0c0a8fb0800e", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQgG0JylEIBwylPW6qaMjK23Wh0lf\nzBmnCpW8YCtPfAWVw366nugXHBu1rG/q91O8NvRj467xZilXLAwKj7CADg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 117, - "comment" : "r and s^-1 have a large Hamming weight", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd27b4577ca009376f71303fd5dd227dcef5deb773ad5f5a84360644669ca249a5", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "pxr2TeUSakpOAreSLWbOlBXOiKTJ0lUU2RCCyHJayVc", - "y" : "XUdyPI--WAuzaf7JwmZdjjCkNbmTJkVILnyfEehyKWs" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04a71af64de5126a4a4e02b7922d66ce9415ce88a4c9d25514d91082c8725ac9575d47723c8fbe580bb369fec9c2665d8e30a435b9932645482e7c9f11e872296b", - "wx" : "00a71af64de5126a4a4e02b7922d66ce9415ce88a4c9d25514d91082c8725ac957", - "wy" : "5d47723c8fbe580bb369fec9c2665d8e30a435b9932645482e7c9f11e872296b" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004a71af64de5126a4a4e02b7922d66ce9415ce88a4c9d25514d91082c8725ac9575d47723c8fbe580bb369fec9c2665d8e30a435b9932645482e7c9f11e872296b", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpxr2TeUSakpOAreSLWbOlBXOiKTJ\n0lUU2RCCyHJayVddR3I8j75YC7Np/snCZl2OMKQ1uZMmRUgufJ8R6HIpaw==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 118, - "comment" : "small r and s", - "msg" : "313233343030", - "sig" : "00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000001", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 119, - "comment" : "incorrect size of signature", - "msg" : "313233343030", - "sig" : "0501", - "result" : "acceptable", - "flags" : [ - "SigSize" - ] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "ZifOxPBzHqI_wpMfkOvlt1cvWX0g3wj8KzHujvFrFXI", - "y" : "YXDtd9jQoU_FycPEyb5_DT7hj3CbsnXq8gc-JY_mlKU" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "046627cec4f0731ea23fc2931f90ebe5b7572f597d20df08fc2b31ee8ef16b15726170ed77d8d0a14fc5c9c3c4c9be7f0d3ee18f709bb275eaf2073e258fe694a5", - "wx" : "6627cec4f0731ea23fc2931f90ebe5b7572f597d20df08fc2b31ee8ef16b1572", - "wy" : "6170ed77d8d0a14fc5c9c3c4c9be7f0d3ee18f709bb275eaf2073e258fe694a5" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200046627cec4f0731ea23fc2931f90ebe5b7572f597d20df08fc2b31ee8ef16b15726170ed77d8d0a14fc5c9c3c4c9be7f0d3ee18f709bb275eaf2073e258fe694a5", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZifOxPBzHqI/wpMfkOvlt1cvWX0g\n3wj8KzHujvFrFXJhcO132NChT8XJw8TJvn8NPuGPcJuyderyBz4lj+aUpQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 120, - "comment" : "small r and s", - "msg" : "313233343030", - "sig" : "00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000003", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 121, - "comment" : "incorrect size of signature", - "msg" : "313233343030", - "sig" : "0503", - "result" : "acceptable", - "flags" : [ - "SigSize" - ] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "WnyIJehWkczh9edUTFTnPxSvwBDLcxNDJiyn7Fp39b8", - "y" : "727fYqRJfBvXsUf7bD0irzw5v86V8w4ToW09eygS-BM" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "045a7c8825e85691cce1f5e7544c54e73f14afc010cb731343262ca7ec5a77f5bfef6edf62a4497c1bd7b147fb6c3d22af3c39bfce95f30e13a16d3d7b2812f813", - "wx" : "5a7c8825e85691cce1f5e7544c54e73f14afc010cb731343262ca7ec5a77f5bf", - "wy" : "00ef6edf62a4497c1bd7b147fb6c3d22af3c39bfce95f30e13a16d3d7b2812f813" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200045a7c8825e85691cce1f5e7544c54e73f14afc010cb731343262ca7ec5a77f5bfef6edf62a4497c1bd7b147fb6c3d22af3c39bfce95f30e13a16d3d7b2812f813", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWnyIJehWkczh9edUTFTnPxSvwBDL\ncxNDJiyn7Fp39b/vbt9ipEl8G9exR/tsPSKvPDm/zpXzDhOhbT17KBL4Ew==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 122, - "comment" : "small r and s", - "msg" : "313233343030", - "sig" : "00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000005", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 123, - "comment" : "incorrect size of signature", - "msg" : "313233343030", - "sig" : "0505", - "result" : "acceptable", - "flags" : [ - "SigSize" - ] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "y-DCkTLNc4Nk_t1gMVKZDASOXi__mW2IP6bKynl4xzc", - "y" : "cK9qjORMtBIksmA2BvTATRiOgL_3zDGtUYnUqw1w6ME" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04cbe0c29132cd738364fedd603152990c048e5e2fff996d883fa6caca7978c73770af6a8ce44cb41224b2603606f4c04d188e80bff7cc31ad5189d4ab0d70e8c1", - "wx" : "00cbe0c29132cd738364fedd603152990c048e5e2fff996d883fa6caca7978c737", - "wy" : "70af6a8ce44cb41224b2603606f4c04d188e80bff7cc31ad5189d4ab0d70e8c1" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004cbe0c29132cd738364fedd603152990c048e5e2fff996d883fa6caca7978c73770af6a8ce44cb41224b2603606f4c04d188e80bff7cc31ad5189d4ab0d70e8c1", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEy+DCkTLNc4Nk/t1gMVKZDASOXi//\nmW2IP6bKynl4xzdwr2qM5Ey0EiSyYDYG9MBNGI6Av/fMMa1RidSrDXDowQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 124, - "comment" : "small r and s", - "msg" : "313233343030", - "sig" : "00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 125, - "comment" : "incorrect size of signature", - "msg" : "313233343030", - "sig" : "0506", - "result" : "acceptable", - "flags" : [ - "SigSize" - ] - }, - { - "tcId" : 126, - "comment" : "r is larger than n", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325560000000000000000000000000000000000000000000000000000000000000006", - "result" : "invalid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "S-QXgJcALw3qto8NmhMODtM6Z5XQKiB5bbg0RLA34Tk", - "y" : "IPEwUeDuzc_OTazqD1DR8kfKpmnxk8G0B1tRriltLVY" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "044be4178097002f0deab68f0d9a130e0ed33a6795d02a20796db83444b037e13920f13051e0eecdcfce4dacea0f50d1f247caa669f193c1b4075b51ae296d2d56", - "wx" : "4be4178097002f0deab68f0d9a130e0ed33a6795d02a20796db83444b037e139", - "wy" : "20f13051e0eecdcfce4dacea0f50d1f247caa669f193c1b4075b51ae296d2d56" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200044be4178097002f0deab68f0d9a130e0ed33a6795d02a20796db83444b037e13920f13051e0eecdcfce4dacea0f50d1f247caa669f193c1b4075b51ae296d2d56", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAES+QXgJcALw3qto8NmhMODtM6Z5XQ\nKiB5bbg0RLA34Tkg8TBR4O7Nz85NrOoPUNHyR8qmafGTwbQHW1GuKW0tVg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 127, - "comment" : "s is larger than n", - "msg" : "313233343030", - "sig" : "0000000000000000000000000000000000000000000000000000000000000005ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc75fbd8", - "result" : "invalid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "0Pc3kiA3Fq_UvkMp-qSNJp8VMT67ujedd4PJe_PokNk", - "y" : "lx9KMgZgW-wheCv14nXHFEF-j1ZlSea8aGkNI2PInME" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04d0f73792203716afd4be4329faa48d269f15313ebbba379d7783c97bf3e890d9971f4a3206605bec21782bf5e275c714417e8f566549e6bc68690d2363c89cc1", - "wx" : "00d0f73792203716afd4be4329faa48d269f15313ebbba379d7783c97bf3e890d9", - "wy" : "00971f4a3206605bec21782bf5e275c714417e8f566549e6bc68690d2363c89cc1" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004d0f73792203716afd4be4329faa48d269f15313ebbba379d7783c97bf3e890d9971f4a3206605bec21782bf5e275c714417e8f566549e6bc68690d2363c89cc1", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0Pc3kiA3Fq/UvkMp+qSNJp8VMT67\nujedd4PJe/PokNmXH0oyBmBb7CF4K/XidccUQX6PVmVJ5rxoaQ0jY8icwQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 128, - "comment" : "small r and s^-1", - "msg" : "313233343030", - "sig" : "00000000000000000000000000000000000000000000000000000000000001008f1e3c7862c58b16bb76eddbb76eddbb516af4f63f2d74d76e0d28c9bb75ea88", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "SDiyvjWmJ2qA754igUD52bls6Dt6JU9xzN67uAVM4F8", - "y" : "-py8EjyRmxngAjgZjQQGkEO9ZgqCiBQFH8uKrHOKbGs" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "044838b2be35a6276a80ef9e228140f9d9b96ce83b7a254f71ccdebbb8054ce05ffa9cbc123c919b19e00238198d04069043bd660a828814051fcb8aac738a6c6b", - "wx" : "4838b2be35a6276a80ef9e228140f9d9b96ce83b7a254f71ccdebbb8054ce05f", - "wy" : "00fa9cbc123c919b19e00238198d04069043bd660a828814051fcb8aac738a6c6b" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200044838b2be35a6276a80ef9e228140f9d9b96ce83b7a254f71ccdebbb8054ce05ffa9cbc123c919b19e00238198d04069043bd660a828814051fcb8aac738a6c6b", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESDiyvjWmJ2qA754igUD52bls6Dt6\nJU9xzN67uAVM4F/6nLwSPJGbGeACOBmNBAaQQ71mCoKIFAUfy4qsc4psaw==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 129, - "comment" : "smallish r and s^-1", - "msg" : "313233343030", - "sig" : "000000000000000000000000000000000000000000000000002d9b4d347952d6ef3043e7329581dbb3974497710ab11505ee1c87ff907beebadd195a0ffe6d7a", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "c5OYPKMKUgu8R4PcmWB0aqtETvUgwKjncRGapOdLD2Q", - "y" : "6de-GrAaC_Ym5wmGPmpIbbrzJ5OvzPd04sbNJ7GFdSY" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "047393983ca30a520bbc4783dc9960746aab444ef520c0a8e771119aa4e74b0f64e9d7be1ab01a0bf626e709863e6a486dbaf32793afccf774e2c6cd27b1857526", - "wx" : "7393983ca30a520bbc4783dc9960746aab444ef520c0a8e771119aa4e74b0f64", - "wy" : "00e9d7be1ab01a0bf626e709863e6a486dbaf32793afccf774e2c6cd27b1857526" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200047393983ca30a520bbc4783dc9960746aab444ef520c0a8e771119aa4e74b0f64e9d7be1ab01a0bf626e709863e6a486dbaf32793afccf774e2c6cd27b1857526", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc5OYPKMKUgu8R4PcmWB0aqtETvUg\nwKjncRGapOdLD2Tp174asBoL9ibnCYY+akhtuvMnk6/M93Tixs0nsYV1Jg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 130, - "comment" : "100-bit r and small s^-1", - "msg" : "313233343030", - "sig" : "000000000000000000000000000000000000001033e67e37b32b445580bf4eff8b748b74000000008b748b748b748b7466e769ad4a16d3dcd87129b8e91d1b4d", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "WsMxoRA_6WZpc3nzVqk381BYigVHfjCIUbilAtXfzcU", - "y" : "_pmT30tXk5srjaCVv215QmUgTP4DvplaAuZdQIyHHAs" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "045ac331a1103fe966697379f356a937f350588a05477e308851b8a502d5dfcdc5fe9993df4b57939b2b8da095bf6d794265204cfe03be995a02e65d408c871c0b", - "wx" : "5ac331a1103fe966697379f356a937f350588a05477e308851b8a502d5dfcdc5", - "wy" : "00fe9993df4b57939b2b8da095bf6d794265204cfe03be995a02e65d408c871c0b" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200045ac331a1103fe966697379f356a937f350588a05477e308851b8a502d5dfcdc5fe9993df4b57939b2b8da095bf6d794265204cfe03be995a02e65d408c871c0b", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWsMxoRA/6WZpc3nzVqk381BYigVH\nfjCIUbilAtXfzcX+mZPfS1eTmyuNoJW/bXlCZSBM/gO+mVoC5l1AjIccCw==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 131, - "comment" : "small r and 100 bit s^-1", - "msg" : "313233343030", - "sig" : "0000000000000000000000000000000000000000000000000000000000000100ef9f6ba4d97c09d03178fa20b4aaad83be3cf9cb824a879fec3270fc4b81ef5b", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "HSCb6N4t6HcJWjmdOQTHTMRY2Sbie7jljl6uV2fEFQk", - "y" : "3VngTCFPexjc41H8KlSYk6aGDoAWPzjMYKTyydBA2Mk" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "041d209be8de2de877095a399d3904c74cc458d926e27bb8e58e5eae5767c41509dd59e04c214f7b18dce351fc2a549893a6860e80163f38cc60a4f2c9d040d8c9", - "wx" : "1d209be8de2de877095a399d3904c74cc458d926e27bb8e58e5eae5767c41509", - "wy" : "00dd59e04c214f7b18dce351fc2a549893a6860e80163f38cc60a4f2c9d040d8c9" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200041d209be8de2de877095a399d3904c74cc458d926e27bb8e58e5eae5767c41509dd59e04c214f7b18dce351fc2a549893a6860e80163f38cc60a4f2c9d040d8c9", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHSCb6N4t6HcJWjmdOQTHTMRY2Sbi\ne7jljl6uV2fEFQndWeBMIU97GNzjUfwqVJiTpoYOgBY/OMxgpPLJ0EDYyQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 132, - "comment" : "100-bit r and s^-1", - "msg" : "313233343030", - "sig" : "00000000000000000000000000000000000000062522bbd3ecbe7c39e93e7c25ef9f6ba4d97c09d03178fa20b4aaad83be3cf9cb824a879fec3270fc4b81ef5b", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "CDU5--5EYl46yq-i_LQTSTks7wYzobj6vs7gwTOxDpk", - "y" : "kVwevnvwDfhTUZZ3ClgEeuKkAvJjJrt9QdTXYWM3kR4" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04083539fbee44625e3acaafa2fcb41349392cef0633a1b8fabecee0c133b10e99915c1ebe7bf00df8535196770a58047ae2a402f26326bb7d41d4d7616337911e", - "wx" : "083539fbee44625e3acaafa2fcb41349392cef0633a1b8fabecee0c133b10e99", - "wy" : "00915c1ebe7bf00df8535196770a58047ae2a402f26326bb7d41d4d7616337911e" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004083539fbee44625e3acaafa2fcb41349392cef0633a1b8fabecee0c133b10e99915c1ebe7bf00df8535196770a58047ae2a402f26326bb7d41d4d7616337911e", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECDU5++5EYl46yq+i/LQTSTks7wYz\nobj6vs7gwTOxDpmRXB6+e/AN+FNRlncKWAR64qQC8mMmu31B1NdhYzeRHg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 133, - "comment" : "r and s^-1 are close to n", - "msg" : "313233343030", - "sig" : "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6324d5555555550000000055555555555555553ef7a8e48d07df81a693439654210c70", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "ius2inAnpNZKveo3OQwMHWom85ni2XNN4es9Dhk3OHQ", - "y" : "Bb0Tg0cV4duum4dc8HvVXhtmkcf3U2rvOxm_ekrfV20" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "048aeb368a7027a4d64abdea37390c0c1d6a26f399e2d9734de1eb3d0e1937387405bd13834715e1dbae9b875cf07bd55e1b6691c7f7536aef3b19bf7a4adf576d", - "wx" : "008aeb368a7027a4d64abdea37390c0c1d6a26f399e2d9734de1eb3d0e19373874", - "wy" : "05bd13834715e1dbae9b875cf07bd55e1b6691c7f7536aef3b19bf7a4adf576d" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200048aeb368a7027a4d64abdea37390c0c1d6a26f399e2d9734de1eb3d0e1937387405bd13834715e1dbae9b875cf07bd55e1b6691c7f7536aef3b19bf7a4adf576d", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEius2inAnpNZKveo3OQwMHWom85ni\n2XNN4es9Dhk3OHQFvRODRxXh266bh1zwe9VeG2aRx/dTau87Gb96St9XbQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 134, - "comment" : "s == 1", - "msg" : "313233343030", - "sig" : "555555550000000055555555555555553ef7a8e48d07df81a693439654210c700000000000000000000000000000000000000000000000000000000000000001", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 135, - "comment" : "s == 0", - "msg" : "313233343030", - "sig" : "555555550000000055555555555555553ef7a8e48d07df81a693439654210c700000000000000000000000000000000000000000000000000000000000000000", - "result" : "invalid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "tTPUaV3VuMXgd1flXm5Rb34siPoCOeI_YOjsB91w8oc", - "y" : "GxNO5YzFgyeEVoY_M8OoXYgffUo5hQFD4p1OrwCa_kc" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04b533d4695dd5b8c5e07757e55e6e516f7e2c88fa0239e23f60e8ec07dd70f2871b134ee58cc583278456863f33c3a85d881f7d4a39850143e29d4eaf009afe47", - "wx" : "00b533d4695dd5b8c5e07757e55e6e516f7e2c88fa0239e23f60e8ec07dd70f287", - "wy" : "1b134ee58cc583278456863f33c3a85d881f7d4a39850143e29d4eaf009afe47" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004b533d4695dd5b8c5e07757e55e6e516f7e2c88fa0239e23f60e8ec07dd70f2871b134ee58cc583278456863f33c3a85d881f7d4a39850143e29d4eaf009afe47", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEtTPUaV3VuMXgd1flXm5Rb34siPoC\nOeI/YOjsB91w8ocbE07ljMWDJ4RWhj8zw6hdiB99SjmFAUPinU6vAJr+Rw==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 136, - "comment" : "point at infinity during verify", - "msg" : "313233343030", - "sig" : "7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8555555550000000055555555555555553ef7a8e48d07df81a693439654210c70", - "result" : "invalid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "9Q03G5G_sdfRThMjUjvDqoy_LFf54oTeYoyLRTZ4e4Y", - "y" : "-UrYh6yU1SckfNLn0MixKRxVPJcwQFOAsUy7IJ9fot0" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04f50d371b91bfb1d7d14e1323523bc3aa8cbf2c57f9e284de628c8b4536787b86f94ad887ac94d527247cd2e7d0c8b1291c553c9730405380b14cbb209f5fa2dd", - "wx" : "00f50d371b91bfb1d7d14e1323523bc3aa8cbf2c57f9e284de628c8b4536787b86", - "wy" : "00f94ad887ac94d527247cd2e7d0c8b1291c553c9730405380b14cbb209f5fa2dd" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004f50d371b91bfb1d7d14e1323523bc3aa8cbf2c57f9e284de628c8b4536787b86f94ad887ac94d527247cd2e7d0c8b1291c553c9730405380b14cbb209f5fa2dd", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9Q03G5G/sdfRThMjUjvDqoy/LFf5\n4oTeYoyLRTZ4e4b5StiHrJTVJyR80ufQyLEpHFU8lzBAU4CxTLsgn1+i3Q==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 137, - "comment" : "edge case for signature malleability", - "msg" : "313233343030", - "sig" : "7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a97fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "aOxuKY6v4WU5FWzlehSwSnBHwiG6_DpYLq6w2FfE2UY", - "y" : "l77RrxeFARf9s5sjJPIgpWmO0WxCaiczW7OFrIym-zA" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "0468ec6e298eafe16539156ce57a14b04a7047c221bafc3a582eaeb0d857c4d94697bed1af17850117fdb39b2324f220a5698ed16c426a27335bb385ac8ca6fb30", - "wx" : "68ec6e298eafe16539156ce57a14b04a7047c221bafc3a582eaeb0d857c4d946", - "wy" : "0097bed1af17850117fdb39b2324f220a5698ed16c426a27335bb385ac8ca6fb30" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000468ec6e298eafe16539156ce57a14b04a7047c221bafc3a582eaeb0d857c4d94697bed1af17850117fdb39b2324f220a5698ed16c426a27335bb385ac8ca6fb30", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaOxuKY6v4WU5FWzlehSwSnBHwiG6\n/DpYLq6w2FfE2UaXvtGvF4UBF/2zmyMk8iClaY7RbEJqJzNbs4WsjKb7MA==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 138, - "comment" : "edge case for signature malleability", - "msg" : "313233343030", - "sig" : "7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a97fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "adoDZHNNLlMP7OlAGSZf77eBoPGwj2yIl732VXknyLg", - "y" : "ZtLTx9zVGLI9cmlg8Gmtcakz2G74q7zOiyD3HiqEcAI" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "0469da0364734d2e530fece94019265fefb781a0f1b08f6c8897bdf6557927c8b866d2d3c7dcd518b23d726960f069ad71a933d86ef8abbcce8b20f71e2a847002", - "wx" : "69da0364734d2e530fece94019265fefb781a0f1b08f6c8897bdf6557927c8b8", - "wy" : "66d2d3c7dcd518b23d726960f069ad71a933d86ef8abbcce8b20f71e2a847002" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000469da0364734d2e530fece94019265fefb781a0f1b08f6c8897bdf6557927c8b866d2d3c7dcd518b23d726960f069ad71a933d86ef8abbcce8b20f71e2a847002", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEadoDZHNNLlMP7OlAGSZf77eBoPGw\nj2yIl732VXknyLhm0tPH3NUYsj1yaWDwaa1xqTPYbvirvM6LIPceKoRwAg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 139, - "comment" : "u1 == 1", - "msg" : "313233343030", - "sig" : "555555550000000055555555555555553ef7a8e48d07df81a693439654210c70bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "2K3AACOo7cAlduK2Pj4wYhpHHisjIGIBh78GehrB_zI", - "y" : "M-K1DsCYB6zLNhMf_5XtEqCahrTqlpCqMoYVdrojYuE" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04d8adc00023a8edc02576e2b63e3e30621a471e2b2320620187bf067a1ac1ff3233e2b50ec09807accb36131fff95ed12a09a86b4ea9690aa32861576ba2362e1", - "wx" : "00d8adc00023a8edc02576e2b63e3e30621a471e2b2320620187bf067a1ac1ff32", - "wy" : "33e2b50ec09807accb36131fff95ed12a09a86b4ea9690aa32861576ba2362e1" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004d8adc00023a8edc02576e2b63e3e30621a471e2b2320620187bf067a1ac1ff3233e2b50ec09807accb36131fff95ed12a09a86b4ea9690aa32861576ba2362e1", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2K3AACOo7cAlduK2Pj4wYhpHHisj\nIGIBh78GehrB/zIz4rUOwJgHrMs2Ex//le0SoJqGtOqWkKoyhhV2uiNi4Q==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 140, - "comment" : "u1 == n - 1", - "msg" : "313233343030", - "sig" : "555555550000000055555555555555553ef7a8e48d07df81a693439654210c7044a5ad0ad0636d9f12bc9e0a6bdd5e1cbcb012ea7bf091fcec15b0c43202d52e", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "NiOslzztClb6bYgvA6fVx-3KAs_HskAfqzaQ2-dat4U", - "y" : "jbBpCOZLKGE9pyV-c385eT2o5xO6BkO5LpuzJSvn-P4" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "043623ac973ced0a56fa6d882f03a7d5c7edca02cfc7b2401fab3690dbe75ab7858db06908e64b28613da7257e737f39793da8e713ba0643b92e9bb3252be7f8fe", - "wx" : "3623ac973ced0a56fa6d882f03a7d5c7edca02cfc7b2401fab3690dbe75ab785", - "wy" : "008db06908e64b28613da7257e737f39793da8e713ba0643b92e9bb3252be7f8fe" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200043623ac973ced0a56fa6d882f03a7d5c7edca02cfc7b2401fab3690dbe75ab7858db06908e64b28613da7257e737f39793da8e713ba0643b92e9bb3252be7f8fe", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENiOslzztClb6bYgvA6fVx+3KAs/H\nskAfqzaQ2+dat4WNsGkI5ksoYT2nJX5zfzl5PajnE7oGQ7kum7MlK+f4/g==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 141, - "comment" : "u2 == 1", - "msg" : "313233343030", - "sig" : "555555550000000055555555555555553ef7a8e48d07df81a693439654210c70555555550000000055555555555555553ef7a8e48d07df81a693439654210c70", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "zwTqd-liJSPYlLk_9S3DAnsxlZUDtvo4kOXgQmP5IvE", - "y" : "6FKPt8AGs5g8i4QA5XtO1xdAwvOXVDiCEZm-3q7Ksuk" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04cf04ea77e9622523d894b93ff52dc3027b31959503b6fa3890e5e04263f922f1e8528fb7c006b3983c8b8400e57b4ed71740c2f3975438821199bedeaecab2e9", - "wx" : "00cf04ea77e9622523d894b93ff52dc3027b31959503b6fa3890e5e04263f922f1", - "wy" : "00e8528fb7c006b3983c8b8400e57b4ed71740c2f3975438821199bedeaecab2e9" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004cf04ea77e9622523d894b93ff52dc3027b31959503b6fa3890e5e04263f922f1e8528fb7c006b3983c8b8400e57b4ed71740c2f3975438821199bedeaecab2e9", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzwTqd+liJSPYlLk/9S3DAnsxlZUD\ntvo4kOXgQmP5IvHoUo+3wAazmDyLhADle07XF0DC85dUOIIRmb7ersqy6Q==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 142, - "comment" : "u2 == n - 1", - "msg" : "313233343030", - "sig" : "555555550000000055555555555555553ef7a8e48d07df81a693439654210c70aaaaaaaa00000000aaaaaaaaaaaaaaaa7def51c91a0fbf034d26872ca84218e1", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "23osihq1c-WSncJAd7UI1-aD1JInmWvaPp942-_3c1A", - "y" : "T0F_O8mogHXC4KrdWhMxFzDPfMdqgvEaNurwimyZogY" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04db7a2c8a1ab573e5929dc24077b508d7e683d49227996bda3e9f78dbeff773504f417f3bc9a88075c2e0aadd5a13311730cf7cc76a82f11a36eaf08a6c99a206", - "wx" : "00db7a2c8a1ab573e5929dc24077b508d7e683d49227996bda3e9f78dbeff77350", - "wy" : "4f417f3bc9a88075c2e0aadd5a13311730cf7cc76a82f11a36eaf08a6c99a206" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004db7a2c8a1ab573e5929dc24077b508d7e683d49227996bda3e9f78dbeff773504f417f3bc9a88075c2e0aadd5a13311730cf7cc76a82f11a36eaf08a6c99a206", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE23osihq1c+WSncJAd7UI1+aD1JIn\nmWvaPp942+/3c1BPQX87yaiAdcLgqt1aEzEXMM98x2qC8Ro26vCKbJmiBg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 143, - "comment" : "edge case for u1", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffde91e1ba60fdedb76a46bcb51dc0b8b4b7e019f0a28721885fa5d3a8196623397", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "3q0Rx6WzloYvIZdNxHUvre_5lO_pu9BatBN2XqgLbh8", - "y" : "HePwZA6Kxu3Pic_1PEDiZbuUB4o0NzbfB6oDGPx_4f8" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04dead11c7a5b396862f21974dc4752fadeff994efe9bbd05ab413765ea80b6e1f1de3f0640e8ac6edcf89cff53c40e265bb94078a343736df07aa0318fc7fe1ff", - "wx" : "00dead11c7a5b396862f21974dc4752fadeff994efe9bbd05ab413765ea80b6e1f", - "wy" : "1de3f0640e8ac6edcf89cff53c40e265bb94078a343736df07aa0318fc7fe1ff" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004dead11c7a5b396862f21974dc4752fadeff994efe9bbd05ab413765ea80b6e1f1de3f0640e8ac6edcf89cff53c40e265bb94078a343736df07aa0318fc7fe1ff", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3q0Rx6WzloYvIZdNxHUvre/5lO/p\nu9BatBN2XqgLbh8d4/BkDorG7c+Jz/U8QOJlu5QHijQ3Nt8HqgMY/H/h/w==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 144, - "comment" : "edge case for u1", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdea5843ffeb73af94313ba4831b53fe24f799e525b1e8e8c87b59b95b430ad9", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "0LxHLg18geuu06bvlsGGE7sf6m-ZQyb76A4A395nx-k", - "y" : "mGxyPqSEPUg4m5RvZK1WyDrXD_F7qFM1Zn0bufphnv0" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04d0bc472e0d7c81ebaed3a6ef96c18613bb1fea6f994326fbe80e00dfde67c7e9986c723ea4843d48389b946f64ad56c83ad70ff17ba85335667d1bb9fa619efd", - "wx" : "00d0bc472e0d7c81ebaed3a6ef96c18613bb1fea6f994326fbe80e00dfde67c7e9", - "wy" : "00986c723ea4843d48389b946f64ad56c83ad70ff17ba85335667d1bb9fa619efd" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004d0bc472e0d7c81ebaed3a6ef96c18613bb1fea6f994326fbe80e00dfde67c7e9986c723ea4843d48389b946f64ad56c83ad70ff17ba85335667d1bb9fa619efd", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0LxHLg18geuu06bvlsGGE7sf6m+Z\nQyb76A4A395nx+mYbHI+pIQ9SDiblG9krVbIOtcP8XuoUzVmfRu5+mGe/Q==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 145, - "comment" : "edge case for u1", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd03ffcabf2f1b4d2a65190db1680d62bb994e41c5251cd73b3c3dfc5e5bafc035", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "oKRMqUfWairLc2AIucCNGrKtA3duAmQPeEldRY3VHDI", - "y" : "Yzf-XPjEYEsfHECdwthy1ClKR2JCDfQ6MKI5LkBCat0" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04a0a44ca947d66a2acb736008b9c08d1ab2ad03776e02640f78495d458dd51c326337fe5cf8c4604b1f1c409dc2d872d4294a4762420df43a30a2392e40426add", - "wx" : "00a0a44ca947d66a2acb736008b9c08d1ab2ad03776e02640f78495d458dd51c32", - "wy" : "6337fe5cf8c4604b1f1c409dc2d872d4294a4762420df43a30a2392e40426add" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004a0a44ca947d66a2acb736008b9c08d1ab2ad03776e02640f78495d458dd51c326337fe5cf8c4604b1f1c409dc2d872d4294a4762420df43a30a2392e40426add", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoKRMqUfWairLc2AIucCNGrKtA3du\nAmQPeEldRY3VHDJjN/5c+MRgSx8cQJ3C2HLUKUpHYkIN9DowojkuQEJq3Q==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 146, - "comment" : "edge case for u1", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd4dfbc401f971cd304b33dfdb17d0fed0fe4c1a88ae648e0d2847f74977534989", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "ycIRUpDQCLRftl-tD2AjiSmMJUILd1AZ1Ctiw86Klrc", - "y" : "OHfSWoCA3ALZh8pzDwQFwsnb76xG-eYBzD8G6XE5c_0" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04c9c2115290d008b45fb65fad0f602389298c25420b775019d42b62c3ce8a96b73877d25a8080dc02d987ca730f0405c2c9dbefac46f9e601cc3f06e9713973fd", - "wx" : "00c9c2115290d008b45fb65fad0f602389298c25420b775019d42b62c3ce8a96b7", - "wy" : "3877d25a8080dc02d987ca730f0405c2c9dbefac46f9e601cc3f06e9713973fd" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004c9c2115290d008b45fb65fad0f602389298c25420b775019d42b62c3ce8a96b73877d25a8080dc02d987ca730f0405c2c9dbefac46f9e601cc3f06e9713973fd", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEycIRUpDQCLRftl+tD2AjiSmMJUIL\nd1AZ1Ctiw86Klrc4d9JagIDcAtmHynMPBAXCydvvrEb55gHMPwbpcTlz/Q==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 147, - "comment" : "edge case for u1", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbc4024761cd2ffd43dfdb17d0fed112b988977055cd3a8e54971eba9cda5ca71", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "Xsoe9MKH3dxmuLzPG4jookwAGJYvPF5--oO8Gl_2Az4", - "y" : "XnnEyywkW4xFq9zoqOTadY2SpgfDLNQH7K7yLxyTSnE" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "045eca1ef4c287dddc66b8bccf1b88e8a24c0018962f3c5e7efa83bc1a5ff6033e5e79c4cb2c245b8c45abdce8a8e4da758d92a607c32cd407ecaef22f1c934a71", - "wx" : "5eca1ef4c287dddc66b8bccf1b88e8a24c0018962f3c5e7efa83bc1a5ff6033e", - "wy" : "5e79c4cb2c245b8c45abdce8a8e4da758d92a607c32cd407ecaef22f1c934a71" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200045eca1ef4c287dddc66b8bccf1b88e8a24c0018962f3c5e7efa83bc1a5ff6033e5e79c4cb2c245b8c45abdce8a8e4da758d92a607c32cd407ecaef22f1c934a71", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXsoe9MKH3dxmuLzPG4jookwAGJYv\nPF5++oO8Gl/2Az5eecTLLCRbjEWr3Oio5Np1jZKmB8Ms1AfsrvIvHJNKcQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 148, - "comment" : "edge case for u1", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd788048ed39a5ffa77bfb62fa1fda2257742bf35d128fb3459f2a0c909ee86f91", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "XKqgMOf98OSTa8erWpY1PgoB5BMMP4vyLUc-MXAppHo", - "y" : "3ratxGL3BY8qINNx6XAiVOmyAWQgBbPO2pJrQrF4vvk" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "045caaa030e7fdf0e4936bc7ab5a96353e0a01e4130c3f8bf22d473e317029a47adeb6adc462f7058f2a20d371e9702254e9b201642005b3ceda926b42b178bef9", - "wx" : "5caaa030e7fdf0e4936bc7ab5a96353e0a01e4130c3f8bf22d473e317029a47a", - "wy" : "00deb6adc462f7058f2a20d371e9702254e9b201642005b3ceda926b42b178bef9" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200045caaa030e7fdf0e4936bc7ab5a96353e0a01e4130c3f8bf22d473e317029a47adeb6adc462f7058f2a20d371e9702254e9b201642005b3ceda926b42b178bef9", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXKqgMOf98OSTa8erWpY1PgoB5BMM\nP4vyLUc+MXAppHretq3EYvcFjyog03HpcCJU6bIBZCAFs87akmtCsXi++Q==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 149, - "comment" : "edge case for u1", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd476d9131fd381bd917d0fed112bc9e0a5924b5ed5b11167edd8b23582b3cb15e", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "wv0gusBuVVu4rAzmnrHqIPg6H8NQHIpmRpsaMfYZsJg", - "y" : "YjcFB3n1K2Fb17jXaiX8lcou0yUlx18n_8h6w5fmy68" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04c2fd20bac06e555bb8ac0ce69eb1ea20f83a1fc3501c8a66469b1a31f619b0986237050779f52b615bd7b8d76a25fc95ca2ed32525c75f27ffc87ac397e6cbaf", - "wx" : "00c2fd20bac06e555bb8ac0ce69eb1ea20f83a1fc3501c8a66469b1a31f619b098", - "wy" : "6237050779f52b615bd7b8d76a25fc95ca2ed32525c75f27ffc87ac397e6cbaf" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004c2fd20bac06e555bb8ac0ce69eb1ea20f83a1fc3501c8a66469b1a31f619b0986237050779f52b615bd7b8d76a25fc95ca2ed32525c75f27ffc87ac397e6cbaf", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwv0gusBuVVu4rAzmnrHqIPg6H8NQ\nHIpmRpsaMfYZsJhiNwUHefUrYVvXuNdqJfyVyi7TJSXHXyf/yHrDl+bLrw==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 150, - "comment" : "edge case for u1", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8374253e3e21bd154448d0a8f640fe46fafa8b19ce78d538f6cc0a19662d3601", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "P9ahyn93-zsLvnJsNyAQBoQm4R6mrnjOF77a5LuobO0", - "y" : "A85VFkBr-M-quHRerBzWkBitb1C1Rhhy3fxW4Ns8j_Q" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "043fd6a1ca7f77fb3b0bbe726c372010068426e11ea6ae78ce17bedae4bba86ced03ce5516406bf8cfaab8745eac1cd69018ad6f50b5461872ddfc56e0db3c8ff4", - "wx" : "3fd6a1ca7f77fb3b0bbe726c372010068426e11ea6ae78ce17bedae4bba86ced", - "wy" : "03ce5516406bf8cfaab8745eac1cd69018ad6f50b5461872ddfc56e0db3c8ff4" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200043fd6a1ca7f77fb3b0bbe726c372010068426e11ea6ae78ce17bedae4bba86ced03ce5516406bf8cfaab8745eac1cd69018ad6f50b5461872ddfc56e0db3c8ff4", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEP9ahyn93+zsLvnJsNyAQBoQm4R6m\nrnjOF77a5LuobO0DzlUWQGv4z6q4dF6sHNaQGK1vULVGGHLd/Fbg2zyP9A==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 151, - "comment" : "edge case for u1", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd357cfd3be4d01d413c5b9ede36cba5452c11ee7fe14879e749ae6a2d897a52d6", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "nLjlHielrjtiSmDW3DJzTkmJ2yDpvKPt4e33sIaRERQ", - "y" : "tMEEqzxnfks21lVuitX1I0EKGfLid6qJX8VzIrRCdUQ" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "049cb8e51e27a5ae3b624a60d6dc32734e4989db20e9bca3ede1edf7b086911114b4c104ab3c677e4b36d6556e8ad5f523410a19f2e277aa895fc57322b4427544", - "wx" : "009cb8e51e27a5ae3b624a60d6dc32734e4989db20e9bca3ede1edf7b086911114", - "wy" : "00b4c104ab3c677e4b36d6556e8ad5f523410a19f2e277aa895fc57322b4427544" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200049cb8e51e27a5ae3b624a60d6dc32734e4989db20e9bca3ede1edf7b086911114b4c104ab3c677e4b36d6556e8ad5f523410a19f2e277aa895fc57322b4427544", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnLjlHielrjtiSmDW3DJzTkmJ2yDp\nvKPt4e33sIaRERS0wQSrPGd+SzbWVW6K1fUjQQoZ8uJ3qolfxXMitEJ1RA==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 152, - "comment" : "edge case for u1", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd29798c5c0ee287d4a5e8e6b799fd86b8df5225298e6ffc807cd2f2bc27a0a6d8", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "o-UsFW3K8QUCYgt5VbwrQLx47z1WnhIjwmJRLY9JYCo", - "y" : "SiA58xwQlwJK08yG5XMh3gMjVUY0hhZM8ZKUSXffFH8" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04a3e52c156dcaf10502620b7955bc2b40bc78ef3d569e1223c262512d8f49602a4a2039f31c1097024ad3cc86e57321de032355463486164cf192944977df147f", - "wx" : "00a3e52c156dcaf10502620b7955bc2b40bc78ef3d569e1223c262512d8f49602a", - "wy" : "4a2039f31c1097024ad3cc86e57321de032355463486164cf192944977df147f" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004a3e52c156dcaf10502620b7955bc2b40bc78ef3d569e1223c262512d8f49602a4a2039f31c1097024ad3cc86e57321de032355463486164cf192944977df147f", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEo+UsFW3K8QUCYgt5VbwrQLx47z1W\nnhIjwmJRLY9JYCpKIDnzHBCXAkrTzIblcyHeAyNVRjSGFkzxkpRJd98Ufw==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 153, - "comment" : "edge case for u1", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd0b70f22c781092452dca1a5711fa3a5a1f72add1bf52c2ff7cae4820b30078dd", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "8Zt4kocg1b7o5nD7kAEPsVw3v5G1ilFXw_PAWbJlXog", - "y" : "z3AeyWL7ShHc8nP13DV-WEaFYMfP65QtB0q9QykmBQk" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04f19b78928720d5bee8e670fb90010fb15c37bf91b58a5157c3f3c059b2655e88cf701ec962fb4a11dcf273f5dc357e58468560c7cfeb942d074abd4329260509", - "wx" : "00f19b78928720d5bee8e670fb90010fb15c37bf91b58a5157c3f3c059b2655e88", - "wy" : "00cf701ec962fb4a11dcf273f5dc357e58468560c7cfeb942d074abd4329260509" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004f19b78928720d5bee8e670fb90010fb15c37bf91b58a5157c3f3c059b2655e88cf701ec962fb4a11dcf273f5dc357e58468560c7cfeb942d074abd4329260509", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8Zt4kocg1b7o5nD7kAEPsVw3v5G1\nilFXw/PAWbJlXojPcB7JYvtKEdzyc/XcNX5YRoVgx8/rlC0HSr1DKSYFCQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 154, - "comment" : "edge case for u1", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd16e1e458f021248a5b9434ae23f474b43ee55ba37ea585fef95c90416600f1ba", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "g6dERZ7N-wGlz1KyegW7czdILSQvI117TLiTRVRckKg", - "y" : "wF1JM3uWSYEyh96f_pA1X9kF3188MpRYKBIfN8xQ3m4" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "0483a744459ecdfb01a5cf52b27a05bb7337482d242f235d7b4cb89345545c90a8c05d49337b9649813287de9ffe90355fd905df5f3c32945828121f37cc50de6e", - "wx" : "0083a744459ecdfb01a5cf52b27a05bb7337482d242f235d7b4cb89345545c90a8", - "wy" : "00c05d49337b9649813287de9ffe90355fd905df5f3c32945828121f37cc50de6e" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000483a744459ecdfb01a5cf52b27a05bb7337482d242f235d7b4cb89345545c90a8c05d49337b9649813287de9ffe90355fd905df5f3c32945828121f37cc50de6e", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEg6dERZ7N+wGlz1KyegW7czdILSQv\nI117TLiTRVRckKjAXUkze5ZJgTKH3p/+kDVf2QXfXzwylFgoEh83zFDebg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 155, - "comment" : "edge case for u1", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd2252d6856831b6cf895e4f0535eeaf0e5e5809753df848fe760ad86219016a97", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "3RPGs0xWmC3a4STwOd_SP0sZu-iM7o5SiuUeXW86Idc", - "y" : "v61MLm8mP-XrWcqXTQOfwOTDNFaS-1Mgva5L07QqRf8" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04dd13c6b34c56982ddae124f039dfd23f4b19bbe88cee8e528ae51e5d6f3a21d7bfad4c2e6f263fe5eb59ca974d039fc0e4c3345692fb5320bdae4bd3b42a45ff", - "wx" : "00dd13c6b34c56982ddae124f039dfd23f4b19bbe88cee8e528ae51e5d6f3a21d7", - "wy" : "00bfad4c2e6f263fe5eb59ca974d039fc0e4c3345692fb5320bdae4bd3b42a45ff" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004dd13c6b34c56982ddae124f039dfd23f4b19bbe88cee8e528ae51e5d6f3a21d7bfad4c2e6f263fe5eb59ca974d039fc0e4c3345692fb5320bdae4bd3b42a45ff", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3RPGs0xWmC3a4STwOd/SP0sZu+iM\n7o5SiuUeXW86Ide/rUwubyY/5etZypdNA5/A5MM0VpL7UyC9rkvTtCpF/w==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 156, - "comment" : "edge case for u1", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd81ffe55f178da695b28c86d8b406b15dab1a9e39661a3ae017fbe390ac0972c3", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "Z-b2Wc3ehpovZfCU6U5bTfrWNrv5UZL-7tAbDz3rdGA", - "y" : "o34KUfJYt661Hf5ZL1z9VoW75YcSyNkjPGKIZDfDi6A" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "0467e6f659cdde869a2f65f094e94e5b4dfad636bbf95192feeed01b0f3deb7460a37e0a51f258b7aeb51dfe592f5cfd5685bbe58712c8d9233c62886437c38ba0", - "wx" : "67e6f659cdde869a2f65f094e94e5b4dfad636bbf95192feeed01b0f3deb7460", - "wy" : "00a37e0a51f258b7aeb51dfe592f5cfd5685bbe58712c8d9233c62886437c38ba0" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000467e6f659cdde869a2f65f094e94e5b4dfad636bbf95192feeed01b0f3deb7460a37e0a51f258b7aeb51dfe592f5cfd5685bbe58712c8d9233c62886437c38ba0", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZ+b2Wc3ehpovZfCU6U5bTfrWNrv5\nUZL+7tAbDz3rdGCjfgpR8li3rrUd/lkvXP1WhbvlhxLI2SM8YohkN8OLoA==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 157, - "comment" : "edge case for u2", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd7fffffffaaaaaaaaffffffffffffffffe9a2538f37b28a2c513dee40fecbb71a", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "LrZBJQWuwFxlRfApkyCH5JDQVRHo7B9Zlhe7Nn-eyq8", - "y" : "gF9R78xIA0A_mxrgEkiQ8GpD_tzdsxgw9maa8pKJXLA" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "042eb6412505aec05c6545f029932087e490d05511e8ec1f599617bb367f9ecaaf805f51efcc4803403f9b1ae0124890f06a43fedcddb31830f6669af292895cb0", - "wx" : "2eb6412505aec05c6545f029932087e490d05511e8ec1f599617bb367f9ecaaf", - "wy" : "00805f51efcc4803403f9b1ae0124890f06a43fedcddb31830f6669af292895cb0" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200042eb6412505aec05c6545f029932087e490d05511e8ec1f599617bb367f9ecaaf805f51efcc4803403f9b1ae0124890f06a43fedcddb31830f6669af292895cb0", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELrZBJQWuwFxlRfApkyCH5JDQVRHo\n7B9Zlhe7Nn+eyq+AX1HvzEgDQD+bGuASSJDwakP+3N2zGDD2ZprykolcsA==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 158, - "comment" : "edge case for u2", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdb62f26b5f2a2b26f6de86d42ad8a13da3ab3cccd0459b201de009e526adf21f2", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "hNtkWGjqs146n9gOBW4uhVQ146a2jXWlCoVGJf4NfzU", - "y" : "bSWJrGVe3JoR7z4HXt3amr-S5yFxVw73v0Oi7jkzjP4" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "0484db645868eab35e3a9fd80e056e2e855435e3a6b68d75a50a854625fe0d7f356d2589ac655edc9a11ef3e075eddda9abf92e72171570ef7bf43a2ee39338cfe", - "wx" : "0084db645868eab35e3a9fd80e056e2e855435e3a6b68d75a50a854625fe0d7f35", - "wy" : "6d2589ac655edc9a11ef3e075eddda9abf92e72171570ef7bf43a2ee39338cfe" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000484db645868eab35e3a9fd80e056e2e855435e3a6b68d75a50a854625fe0d7f356d2589ac655edc9a11ef3e075eddda9abf92e72171570ef7bf43a2ee39338cfe", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhNtkWGjqs146n9gOBW4uhVQ146a2\njXWlCoVGJf4NfzVtJYmsZV7cmhHvPgde3dqav5LnIXFXDve/Q6LuOTOM/g==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 159, - "comment" : "edge case for u2", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbb1d9ac949dd748cd02bbbe749bd351cd57b38bb61403d700686aa7b4c90851e", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "kbnkfFYnhmLXXAmDsiyo6mqlBZt6L_djfrKXXjhq1mM", - "y" : "SaqP8oPQ93wY1tEdwGIWX9E8PAMQZ5wUCDAqFoVOz70" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "0491b9e47c56278662d75c0983b22ca8ea6aa5059b7a2ff7637eb2975e386ad66349aa8ff283d0f77c18d6d11dc062165fd13c3c0310679c1408302a16854ecfbd", - "wx" : "0091b9e47c56278662d75c0983b22ca8ea6aa5059b7a2ff7637eb2975e386ad663", - "wy" : "49aa8ff283d0f77c18d6d11dc062165fd13c3c0310679c1408302a16854ecfbd" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000491b9e47c56278662d75c0983b22ca8ea6aa5059b7a2ff7637eb2975e386ad66349aa8ff283d0f77c18d6d11dc062165fd13c3c0310679c1408302a16854ecfbd", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkbnkfFYnhmLXXAmDsiyo6mqlBZt6\nL/djfrKXXjhq1mNJqo/yg9D3fBjW0R3AYhZf0Tw8AxBnnBQIMCoWhU7PvQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 160, - "comment" : "edge case for u2", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd66755a00638cdaec1c732513ca0234ece52545dac11f816e818f725b4f60aaf2", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "8-wvE8rwTQGStH-0xTEfttTcawqegC5TJ_fsXujkg00", - "y" : "-X4-Rot9Dbhn1uz-geKw-VMd-H79tHwTOKwyH-_lpDI" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04f3ec2f13caf04d0192b47fb4c5311fb6d4dc6b0a9e802e5327f7ec5ee8e4834df97e3e468b7d0db867d6ecfe81e2b0f9531df87efdb47c1338ac321fefe5a432", - "wx" : "00f3ec2f13caf04d0192b47fb4c5311fb6d4dc6b0a9e802e5327f7ec5ee8e4834d", - "wy" : "00f97e3e468b7d0db867d6ecfe81e2b0f9531df87efdb47c1338ac321fefe5a432" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004f3ec2f13caf04d0192b47fb4c5311fb6d4dc6b0a9e802e5327f7ec5ee8e4834df97e3e468b7d0db867d6ecfe81e2b0f9531df87efdb47c1338ac321fefe5a432", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8+wvE8rwTQGStH+0xTEfttTcawqe\ngC5TJ/fsXujkg035fj5Gi30NuGfW7P6B4rD5Ux34fv20fBM4rDIf7+WkMg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 161, - "comment" : "edge case for u2", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd55a00c9fcdaebb6032513ca0234ecfffe98ebe492fdf02e48ca48e982beb3669", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "2SsgCu_Ktqx9r9msry-hCzGAI1uPRrRQPkaTxnD8zIg", - "y" : "XvLzrr9bMXR1M2JWdo98Ge-3NS0n5MzK3IW2uKuSLHI" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04d92b200aefcab6ac7dafd9acaf2fa10b3180235b8f46b4503e4693c670fccc885ef2f3aebf5b317475336256768f7c19efb7352d27e4cccadc85b6b8ab922c72", - "wx" : "00d92b200aefcab6ac7dafd9acaf2fa10b3180235b8f46b4503e4693c670fccc88", - "wy" : "5ef2f3aebf5b317475336256768f7c19efb7352d27e4cccadc85b6b8ab922c72" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004d92b200aefcab6ac7dafd9acaf2fa10b3180235b8f46b4503e4693c670fccc885ef2f3aebf5b317475336256768f7c19efb7352d27e4cccadc85b6b8ab922c72", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2SsgCu/Ktqx9r9msry+hCzGAI1uP\nRrRQPkaTxnD8zIhe8vOuv1sxdHUzYlZ2j3wZ77c1LSfkzMrchba4q5Iscg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 162, - "comment" : "edge case for u2", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdab40193f9b5d76c064a27940469d9fffd31d7c925fbe05c919491d3057d66cd2", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "Cog2HrkuzKJiWzjl-Yu6u5a_F5s9dvxIFAo7zYgVI80", - "y" : "5r31YDP4SlBUA1WXN12QhmqiyWuGpBzPbt6_RymK1Ik" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "040a88361eb92ecca2625b38e5f98bbabb96bf179b3d76fc48140a3bcd881523cde6bdf56033f84a5054035597375d90866aa2c96b86a41ccf6edebf47298ad489", - "wx" : "0a88361eb92ecca2625b38e5f98bbabb96bf179b3d76fc48140a3bcd881523cd", - "wy" : "00e6bdf56033f84a5054035597375d90866aa2c96b86a41ccf6edebf47298ad489" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200040a88361eb92ecca2625b38e5f98bbabb96bf179b3d76fc48140a3bcd881523cde6bdf56033f84a5054035597375d90866aa2c96b86a41ccf6edebf47298ad489", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECog2HrkuzKJiWzjl+Yu6u5a/F5s9\ndvxIFAo7zYgVI83mvfVgM/hKUFQDVZc3XZCGaqLJa4akHM9u3r9HKYrUiQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 163, - "comment" : "edge case for u2", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdca0234ebb5fdcb13ca0234ecffffffffcb0dadbbc7f549f8a26b4408d0dc8600", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "0PsXzNj6_oJ-DBr8XY2ANm4rIOfxSlY6K6UEadhDdeg", - "y" : "aGEladOeK7n1VDVVZGRt6ZrGAsxjSc-MHiNqfedjfZM" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04d0fb17ccd8fafe827e0c1afc5d8d80366e2b20e7f14a563a2ba50469d84375e868612569d39e2bb9f554355564646de99ac602cc6349cf8c1e236a7de7637d93", - "wx" : "00d0fb17ccd8fafe827e0c1afc5d8d80366e2b20e7f14a563a2ba50469d84375e8", - "wy" : "68612569d39e2bb9f554355564646de99ac602cc6349cf8c1e236a7de7637d93" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004d0fb17ccd8fafe827e0c1afc5d8d80366e2b20e7f14a563a2ba50469d84375e868612569d39e2bb9f554355564646de99ac602cc6349cf8c1e236a7de7637d93", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0PsXzNj6/oJ+DBr8XY2ANm4rIOfx\nSlY6K6UEadhDdehoYSVp054rufVUNVVkZG3pmsYCzGNJz4weI2p952N9kw==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 164, - "comment" : "edge case for u2", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbfffffff3ea3677e082b9310572620ae19933a9e65b285598711c77298815ad3", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "g28zu8HcDT06u87w2R8R4qxBgQdsmvCiKx5DCdPtsnY", - "y" : "mrRD_2-QHjDHc4Z1gpl8K-wrDLgSDXYCNvOpW76IH3U" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04836f33bbc1dc0d3d3abbcef0d91f11e2ac4181076c9af0a22b1e4309d3edb2769ab443ff6f901e30c773867582997c2bec2b0cb8120d760236f3a95bbe881f75", - "wx" : "00836f33bbc1dc0d3d3abbcef0d91f11e2ac4181076c9af0a22b1e4309d3edb276", - "wy" : "009ab443ff6f901e30c773867582997c2bec2b0cb8120d760236f3a95bbe881f75" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004836f33bbc1dc0d3d3abbcef0d91f11e2ac4181076c9af0a22b1e4309d3edb2769ab443ff6f901e30c773867582997c2bec2b0cb8120d760236f3a95bbe881f75", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEg28zu8HcDT06u87w2R8R4qxBgQds\nmvCiKx5DCdPtsnaatEP/b5AeMMdzhnWCmXwr7CsMuBINdgI286lbvogfdQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 165, - "comment" : "edge case for u2", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd266666663bbbbbbbe6666666666666665b37902e023fab7c8f055d86e5cc41f4", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "kvmfvpc-1KKZcZuu5LQydBI3A03sjXK6UQPLM-Vf7rg", - "y" : "Az3Q6RE0xzQXSInz688behrAV2cokoDuenlM69bmlpc" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "0492f99fbe973ed4a299719baee4b432741237034dec8d72ba5103cb33e55feeb8033dd0e91134c734174889f3ebcf1b7a1ac05767289280ee7a794cebd6e69697", - "wx" : "0092f99fbe973ed4a299719baee4b432741237034dec8d72ba5103cb33e55feeb8", - "wy" : "033dd0e91134c734174889f3ebcf1b7a1ac05767289280ee7a794cebd6e69697" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000492f99fbe973ed4a299719baee4b432741237034dec8d72ba5103cb33e55feeb8033dd0e91134c734174889f3ebcf1b7a1ac05767289280ee7a794cebd6e69697", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkvmfvpc+1KKZcZuu5LQydBI3A03s\njXK6UQPLM+Vf7rgDPdDpETTHNBdIifPrzxt6GsBXZyiSgO56eUzr1uaWlw==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 166, - "comment" : "edge case for u2", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbfffffff36db6db7a492492492492492146c573f4c6dfc8d08a443e258970b09", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "01uljaMBl9N45hjsD6fi4tEs_9c-u7IEnRMLukNK8J4", - "y" : "_4OYbmh15B6kMrdYWkmzpsd8uzxHkZ-OgodMeUY1wdI" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04d35ba58da30197d378e618ec0fa7e2e2d12cffd73ebbb2049d130bba434af09eff83986e6875e41ea432b7585a49b3a6c77cbb3c47919f8e82874c794635c1d2", - "wx" : "00d35ba58da30197d378e618ec0fa7e2e2d12cffd73ebbb2049d130bba434af09e", - "wy" : "00ff83986e6875e41ea432b7585a49b3a6c77cbb3c47919f8e82874c794635c1d2" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004d35ba58da30197d378e618ec0fa7e2e2d12cffd73ebbb2049d130bba434af09eff83986e6875e41ea432b7585a49b3a6c77cbb3c47919f8e82874c794635c1d2", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE01uljaMBl9N45hjsD6fi4tEs/9c+\nu7IEnRMLukNK8J7/g5huaHXkHqQyt1haSbOmx3y7PEeRn46Ch0x5RjXB0g==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 167, - "comment" : "edge case for u2", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbfffffff2aaaaaab7fffffffffffffffc815d0e60b3e596ecb1ad3a27cfd49c4", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "hlHOSQ8bRtc_P_R1FJvikTZpczSlGdfdqwclyNB5MiQ", - "y" : "4RxlvYypLci8mugpEfC1J1HOId2QA65gkAvYJfWQzCg" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "048651ce490f1b46d73f3ff475149be29136697334a519d7ddab0725c8d0793224e11c65bd8ca92dc8bc9ae82911f0b52751ce21dd9003ae60900bd825f590cc28", - "wx" : "008651ce490f1b46d73f3ff475149be29136697334a519d7ddab0725c8d0793224", - "wy" : "00e11c65bd8ca92dc8bc9ae82911f0b52751ce21dd9003ae60900bd825f590cc28" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200048651ce490f1b46d73f3ff475149be29136697334a519d7ddab0725c8d0793224e11c65bd8ca92dc8bc9ae82911f0b52751ce21dd9003ae60900bd825f590cc28", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhlHOSQ8bRtc/P/R1FJvikTZpczSl\nGdfdqwclyNB5MiThHGW9jKktyLya6CkR8LUnUc4h3ZADrmCQC9gl9ZDMKA==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 168, - "comment" : "edge case for u2", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd7fffffff55555555ffffffffffffffffd344a71e6f651458a27bdc81fd976e37", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "bY4bEsgxoNqHlWUP-V8QHtkh2eL3KxWxzaypgmuc_G0", - "y" : "721j4rxcCJVwOUpLyfiS1ebHpqY3sgRppYwQatSGvzc" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "046d8e1b12c831a0da8795650ff95f101ed921d9e2f72b15b1cdaca9826b9cfc6def6d63e2bc5c089570394a4bc9f892d5e6c7a6a637b20469a58c106ad486bf37", - "wx" : "6d8e1b12c831a0da8795650ff95f101ed921d9e2f72b15b1cdaca9826b9cfc6d", - "wy" : "00ef6d63e2bc5c089570394a4bc9f892d5e6c7a6a637b20469a58c106ad486bf37" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200046d8e1b12c831a0da8795650ff95f101ed921d9e2f72b15b1cdaca9826b9cfc6def6d63e2bc5c089570394a4bc9f892d5e6c7a6a637b20469a58c106ad486bf37", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbY4bEsgxoNqHlWUP+V8QHtkh2eL3\nKxWxzaypgmuc/G3vbWPivFwIlXA5SkvJ+JLV5sempjeyBGmljBBq1Ia/Nw==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 169, - "comment" : "edge case for u2", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd3fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192aa", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "CuWAuukztO8pl8vbsJIjKMqaQQ9ieg99_yTLTZIOFUI", - "y" : "iRHn-Mw2WoqI64FCGjYczCuZ4wnY3Nmpi6g8OUnYk-M" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "040ae580bae933b4ef2997cbdbb0922328ca9a410f627a0f7dff24cb4d920e15428911e7f8cc365a8a88eb81421a361ccc2b99e309d8dcd9a98ba83c3949d893e3", - "wx" : "0ae580bae933b4ef2997cbdbb0922328ca9a410f627a0f7dff24cb4d920e1542", - "wy" : "008911e7f8cc365a8a88eb81421a361ccc2b99e309d8dcd9a98ba83c3949d893e3" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200040ae580bae933b4ef2997cbdbb0922328ca9a410f627a0f7dff24cb4d920e15428911e7f8cc365a8a88eb81421a361ccc2b99e309d8dcd9a98ba83c3949d893e3", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECuWAuukztO8pl8vbsJIjKMqaQQ9i\neg99/yTLTZIOFUKJEef4zDZaiojrgUIaNhzMK5njCdjc2amLqDw5SdiT4w==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 170, - "comment" : "edge case for u2", - "msg" : "313233343030", - "sig" : "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd5d8ecd64a4eeba466815ddf3a4de9a8e6abd9c5db0a01eb80343553da648428f", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "W4Ev1SGq-mmDWoSczm-962mDtELSRE_nDhNMAn_EaWM", - "y" : "g4pA8qNgkukATpLY2UDPVjhVDOZyzouNThXrpUmSSek" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "045b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc46963838a40f2a36092e9004e92d8d940cf5638550ce672ce8b8d4e15eba5499249e9", - "wx" : "5b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc46963", - "wy" : "00838a40f2a36092e9004e92d8d940cf5638550ce672ce8b8d4e15eba5499249e9" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200045b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc46963838a40f2a36092e9004e92d8d940cf5638550ce672ce8b8d4e15eba5499249e9", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW4Ev1SGq+mmDWoSczm+962mDtELS\nRE/nDhNMAn/EaWODikDyo2CS6QBOktjZQM9WOFUM5nLOi41OFeulSZJJ6Q==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 171, - "comment" : "point duplication during verification", - "msg" : "313233343030", - "sig" : "6f2347cab7dd76858fe0555ac3bc99048c4aacafdfb6bcbe05ea6c42c4934569bb726660235793aa9957a61e76e00c2c435109cf9a15dd624d53f4301047856b", - "result" : "valid", - "flags" : [ - "PointDuplication" - ] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "W4Ev1SGq-mmDWoSczm-962mDtELSRE_nDhNMAn_EaWM", - "y" : "fHW_DFyfbRf_sW0nJr8wqceq8xqNMXRyseoUWrZtthY" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "045b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc469637c75bf0c5c9f6d17ffb16d2726bf30a9c7aaf31a8d317472b1ea145ab66db616", - "wx" : "5b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc46963", - "wy" : "7c75bf0c5c9f6d17ffb16d2726bf30a9c7aaf31a8d317472b1ea145ab66db616" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200045b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc469637c75bf0c5c9f6d17ffb16d2726bf30a9c7aaf31a8d317472b1ea145ab66db616", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW4Ev1SGq+mmDWoSczm+962mDtELS\nRE/nDhNMAn/EaWN8db8MXJ9tF/+xbScmvzCpx6rzGo0xdHKx6hRatm22Fg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 172, - "comment" : "duplication bug", - "msg" : "313233343030", - "sig" : "6f2347cab7dd76858fe0555ac3bc99048c4aacafdfb6bcbe05ea6c42c4934569bb726660235793aa9957a61e76e00c2c435109cf9a15dd624d53f4301047856b", - "result" : "invalid", - "flags" : [ - "PointDuplication" - ] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "at2oK5AmGw8xn6oNh4ZlprbaSX8JyQMXYiLDSs_vcqY", - "y" : "R-b1DcxArV2bWfdgK7Ii-tcaQb9eH530lZo2TGLkiNk" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "046adda82b90261b0f319faa0d878665a6b6da497f09c903176222c34acfef72a647e6f50dcc40ad5d9b59f7602bb222fad71a41bf5e1f9df4959a364c62e488d9", - "wx" : "6adda82b90261b0f319faa0d878665a6b6da497f09c903176222c34acfef72a6", - "wy" : "47e6f50dcc40ad5d9b59f7602bb222fad71a41bf5e1f9df4959a364c62e488d9" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200046adda82b90261b0f319faa0d878665a6b6da497f09c903176222c34acfef72a647e6f50dcc40ad5d9b59f7602bb222fad71a41bf5e1f9df4959a364c62e488d9", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEat2oK5AmGw8xn6oNh4ZlprbaSX8J\nyQMXYiLDSs/vcqZH5vUNzECtXZtZ92ArsiL61xpBv14fnfSVmjZMYuSI2Q==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 173, - "comment" : "point with x-coordinate 0", - "msg" : "313233343030", - "sig" : "0000000000000000000000000000000000000000000000000000000000000001555555550000000055555555555555553ef7a8e48d07df81a693439654210c70", - "result" : "invalid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "L8oNCkeRTed-1W5-zMMnamARIMbfAGnIJcj2oByfOCA", - "y" : "ZfNFCh0XxrJJiaOb6xx97PyoOE-9wpRBjl2Aezxu194" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "042fca0d0a47914de77ed56e7eccc3276a601120c6df0069c825c8f6a01c9f382065f3450a1d17c6b24989a39beb1c7decfca8384fbdc294418e5d807b3c6ed7de", - "wx" : "2fca0d0a47914de77ed56e7eccc3276a601120c6df0069c825c8f6a01c9f3820", - "wy" : "65f3450a1d17c6b24989a39beb1c7decfca8384fbdc294418e5d807b3c6ed7de" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200042fca0d0a47914de77ed56e7eccc3276a601120c6df0069c825c8f6a01c9f382065f3450a1d17c6b24989a39beb1c7decfca8384fbdc294418e5d807b3c6ed7de", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEL8oNCkeRTed+1W5+zMMnamARIMbf\nAGnIJcj2oByfOCBl80UKHRfGskmJo5vrHH3s/Kg4T73ClEGOXYB7PG7X3g==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 174, - "comment" : "point with x-coordinate 0", - "msg" : "313233343030", - "sig" : "010000000000000000000000000000000000000000000000000000000000000000003333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aa9", - "result" : "invalid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "3YbTtfShPoURCDt4ACCBxT_0Z_EevZilGmM9t2Zl0lA", - "y" : "RdXIIAyJ8voQ2Ek0kibSHY367W_41cs-G34XR068GPc" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04dd86d3b5f4a13e8511083b78002081c53ff467f11ebd98a51a633db76665d25045d5c8200c89f2fa10d849349226d21d8dfaed6ff8d5cb3e1b7e17474ebc18f7", - "wx" : "00dd86d3b5f4a13e8511083b78002081c53ff467f11ebd98a51a633db76665d250", - "wy" : "45d5c8200c89f2fa10d849349226d21d8dfaed6ff8d5cb3e1b7e17474ebc18f7" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004dd86d3b5f4a13e8511083b78002081c53ff467f11ebd98a51a633db76665d25045d5c8200c89f2fa10d849349226d21d8dfaed6ff8d5cb3e1b7e17474ebc18f7", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3YbTtfShPoURCDt4ACCBxT/0Z/Ee\nvZilGmM9t2Zl0lBF1cggDIny+hDYSTSSJtIdjfrtb/jVyz4bfhdHTrwY9w==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 175, - "comment" : "comparison with point at infinity ", - "msg" : "313233343030", - "sig" : "555555550000000055555555555555553ef7a8e48d07df81a693439654210c703333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aa9", - "result" : "invalid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "T-pVsyyzKsoMEsTNCr-05ksPWlFuV4wBZZGpP1oPvMU", - "y" : "19P9ELK-ZoxUeyEva7FMiPD-zTiopLLHhe075izksoA" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "044fea55b32cb32aca0c12c4cd0abfb4e64b0f5a516e578c016591a93f5a0fbcc5d7d3fd10b2be668c547b212f6bb14c88f0fecd38a8a4b2c785ed3be62ce4b280", - "wx" : "4fea55b32cb32aca0c12c4cd0abfb4e64b0f5a516e578c016591a93f5a0fbcc5", - "wy" : "00d7d3fd10b2be668c547b212f6bb14c88f0fecd38a8a4b2c785ed3be62ce4b280" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200044fea55b32cb32aca0c12c4cd0abfb4e64b0f5a516e578c016591a93f5a0fbcc5d7d3fd10b2be668c547b212f6bb14c88f0fecd38a8a4b2c785ed3be62ce4b280", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAET+pVsyyzKsoMEsTNCr+05ksPWlFu\nV4wBZZGpP1oPvMXX0/0Qsr5mjFR7IS9rsUyI8P7NOKiksseF7TvmLOSygA==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 176, - "comment" : "extreme value for k and edgecase s", - "msg" : "313233343030", - "sig" : "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978555555550000000055555555555555553ef7a8e48d07df81a693439654210c70", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "xqdxUnAkIneSFwpvju5zW_Mrf5ivZp6tKZgC4y18MQc", - "y" : "vDtLXmWriHu9NDVys-VhkmH-Ogc-L_14QS9yaGfbWJ4" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04c6a771527024227792170a6f8eee735bf32b7f98af669ead299802e32d7c3107bc3b4b5e65ab887bbd343572b3e5619261fe3a073e2ffd78412f726867db589e", - "wx" : "00c6a771527024227792170a6f8eee735bf32b7f98af669ead299802e32d7c3107", - "wy" : "00bc3b4b5e65ab887bbd343572b3e5619261fe3a073e2ffd78412f726867db589e" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004c6a771527024227792170a6f8eee735bf32b7f98af669ead299802e32d7c3107bc3b4b5e65ab887bbd343572b3e5619261fe3a073e2ffd78412f726867db589e", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExqdxUnAkIneSFwpvju5zW/Mrf5iv\nZp6tKZgC4y18MQe8O0teZauIe700NXKz5WGSYf46Bz4v/XhBL3JoZ9tYng==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 177, - "comment" : "extreme value for k and s^-1", - "msg" : "313233343030", - "sig" : "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978b6db6db6249249254924924924924924625bd7a09bec4ca81bcdd9f8fd6b63cc", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "hRwrutCOVOx6mvmfSfA2RNbsbVmyB_7JjehafRW5Vu8", - "y" : "zumWAoMEUHVoS0EL6ND3SUuRqiN59gcnMZ8Q3esP6dY" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04851c2bbad08e54ec7a9af99f49f03644d6ec6d59b207fec98de85a7d15b956efcee9960283045075684b410be8d0f7494b91aa2379f60727319f10ddeb0fe9d6", - "wx" : "00851c2bbad08e54ec7a9af99f49f03644d6ec6d59b207fec98de85a7d15b956ef", - "wy" : "00cee9960283045075684b410be8d0f7494b91aa2379f60727319f10ddeb0fe9d6" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004851c2bbad08e54ec7a9af99f49f03644d6ec6d59b207fec98de85a7d15b956efcee9960283045075684b410be8d0f7494b91aa2379f60727319f10ddeb0fe9d6", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhRwrutCOVOx6mvmfSfA2RNbsbVmy\nB/7JjehafRW5Vu/O6ZYCgwRQdWhLQQvo0PdJS5GqI3n2BycxnxDd6w/p1g==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 178, - "comment" : "extreme value for k and s^-1", - "msg" : "313233343030", - "sig" : "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978cccccccc00000000cccccccccccccccc971f2ef152794b9d8fc7d568c9e8eaa7", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "9kF8imcFhOOIZ2lJ5T2n_FWRH_aDGNG_MGEgWssZxI8", - "y" : "jyt0PfNK0PcmdKy3UFkpeEd5zZrJFsNmnq1DAmq21D8" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04f6417c8a670584e388676949e53da7fc55911ff68318d1bf3061205acb19c48f8f2b743df34ad0f72674acb7505929784779cd9ac916c3669ead43026ab6d43f", - "wx" : "00f6417c8a670584e388676949e53da7fc55911ff68318d1bf3061205acb19c48f", - "wy" : "008f2b743df34ad0f72674acb7505929784779cd9ac916c3669ead43026ab6d43f" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004f6417c8a670584e388676949e53da7fc55911ff68318d1bf3061205acb19c48f8f2b743df34ad0f72674acb7505929784779cd9ac916c3669ead43026ab6d43f", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9kF8imcFhOOIZ2lJ5T2n/FWRH/aD\nGNG/MGEgWssZxI+PK3Q980rQ9yZ0rLdQWSl4R3nNmskWw2aerUMCarbUPw==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 179, - "comment" : "extreme value for k and s^-1", - "msg" : "313233343030", - "sig" : "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc476699783333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aaa", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "UBQhJ3vkWl7v7GxjmTDWNgMlZa9CDPM3P1V_qn-KBkM", - "y" : "hnPWy2B24c_Nx9_nOEyOXKwI10UB8q5uicrRldCqE3E" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04501421277be45a5eefec6c639930d636032565af420cf3373f557faa7f8a06438673d6cb6076e1cfcdc7dfe7384c8e5cac08d74501f2ae6e89cad195d0aa1371", - "wx" : "501421277be45a5eefec6c639930d636032565af420cf3373f557faa7f8a0643", - "wy" : "008673d6cb6076e1cfcdc7dfe7384c8e5cac08d74501f2ae6e89cad195d0aa1371" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004501421277be45a5eefec6c639930d636032565af420cf3373f557faa7f8a06438673d6cb6076e1cfcdc7dfe7384c8e5cac08d74501f2ae6e89cad195d0aa1371", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUBQhJ3vkWl7v7GxjmTDWNgMlZa9C\nDPM3P1V/qn+KBkOGc9bLYHbhz83H3+c4TI5crAjXRQHyrm6JytGV0KoTcQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 180, - "comment" : "extreme value for k and s^-1", - "msg" : "313233343030", - "sig" : "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc4766997849249248db6db6dbb6db6db6db6db6db5a8b230d0b2b51dcd7ebf0c9fef7c185", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "DZNb-f_BFaUnc19ynKikyiPuAaSJSt8ONBWshOgIuzQ", - "y" : "MZWjdi_qKe04kSvZ6mxP3nDDBQiTpDdYUM5h2C66M8U" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "040d935bf9ffc115a527735f729ca8a4ca23ee01a4894adf0e3415ac84e808bb343195a3762fea29ed38912bd9ea6c4fde70c3050893a4375850ce61d82eba33c5", - "wx" : "0d935bf9ffc115a527735f729ca8a4ca23ee01a4894adf0e3415ac84e808bb34", - "wy" : "3195a3762fea29ed38912bd9ea6c4fde70c3050893a4375850ce61d82eba33c5" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200040d935bf9ffc115a527735f729ca8a4ca23ee01a4894adf0e3415ac84e808bb343195a3762fea29ed38912bd9ea6c4fde70c3050893a4375850ce61d82eba33c5", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDZNb+f/BFaUnc19ynKikyiPuAaSJ\nSt8ONBWshOgIuzQxlaN2L+op7TiRK9nqbE/ecMMFCJOkN1hQzmHYLrozxQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 181, - "comment" : "extreme value for k", - "msg" : "313233343030", - "sig" : "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc4766997816a4502e2781e11ac82cbc9d1edd8c981584d13e18411e2f6e0478c34416e3bb", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "Xln1Bwhka-iliTVQFDCOYLZo-2cBliBsQedI5k5NyiE", - "y" : "XeN_7lyXvK9xRNW0WZgvUu7q-98Dqsuv7zjiE2JKAd4" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "045e59f50708646be8a589355014308e60b668fb670196206c41e748e64e4dca215de37fee5c97bcaf7144d5b459982f52eeeafbdf03aacbafef38e213624a01de", - "wx" : "5e59f50708646be8a589355014308e60b668fb670196206c41e748e64e4dca21", - "wy" : "5de37fee5c97bcaf7144d5b459982f52eeeafbdf03aacbafef38e213624a01de" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200045e59f50708646be8a589355014308e60b668fb670196206c41e748e64e4dca215de37fee5c97bcaf7144d5b459982f52eeeafbdf03aacbafef38e213624a01de", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXln1Bwhka+iliTVQFDCOYLZo+2cB\nliBsQedI5k5NyiFd43/uXJe8r3FE1bRZmC9S7ur73wOqy6/vOOITYkoB3g==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 182, - "comment" : "extreme value for k and edgecase s", - "msg" : "313233343030", - "sig" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296555555550000000055555555555555553ef7a8e48d07df81a693439654210c70", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "Fp-3lzJYQ_r_L3pbVEXani_WIm9--Q7wv-kkEEsC244", - "y" : "e7uN5mLHubHPmyL3ouWCvUbVgdaIeO-yuGGxMdih1mc" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04169fb797325843faff2f7a5b5445da9e2fd6226f7ef90ef0bfe924104b02db8e7bbb8de662c7b9b1cf9b22f7a2e582bd46d581d68878efb2b861b131d8a1d667", - "wx" : "169fb797325843faff2f7a5b5445da9e2fd6226f7ef90ef0bfe924104b02db8e", - "wy" : "7bbb8de662c7b9b1cf9b22f7a2e582bd46d581d68878efb2b861b131d8a1d667" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004169fb797325843faff2f7a5b5445da9e2fd6226f7ef90ef0bfe924104b02db8e7bbb8de662c7b9b1cf9b22f7a2e582bd46d581d68878efb2b861b131d8a1d667", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFp+3lzJYQ/r/L3pbVEXani/WIm9+\n+Q7wv+kkEEsC2457u43mYse5sc+bIvei5YK9RtWB1oh477K4YbEx2KHWZw==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 183, - "comment" : "extreme value for k and s^-1", - "msg" : "313233343030", - "sig" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296b6db6db6249249254924924924924924625bd7a09bec4ca81bcdd9f8fd6b63cc", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "JxzYnAABQwlrYtTp5MqIWu8vcCPRiv_a-Le1SJgUh1Q", - "y" : "ChxulU4yEIQ1tV-jhbD3ZIGmCbkUnMtLArLKR_6OTaU" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04271cd89c000143096b62d4e9e4ca885aef2f7023d18affdaf8b7b548981487540a1c6e954e32108435b55fa385b0f76481a609b9149ccb4b02b2ca47fe8e4da5", - "wx" : "271cd89c000143096b62d4e9e4ca885aef2f7023d18affdaf8b7b54898148754", - "wy" : "0a1c6e954e32108435b55fa385b0f76481a609b9149ccb4b02b2ca47fe8e4da5" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004271cd89c000143096b62d4e9e4ca885aef2f7023d18affdaf8b7b548981487540a1c6e954e32108435b55fa385b0f76481a609b9149ccb4b02b2ca47fe8e4da5", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJxzYnAABQwlrYtTp5MqIWu8vcCPR\niv/a+Le1SJgUh1QKHG6VTjIQhDW1X6OFsPdkgaYJuRScy0sCsspH/o5NpQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 184, - "comment" : "extreme value for k and s^-1", - "msg" : "313233343030", - "sig" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296cccccccc00000000cccccccccccccccc971f2ef152794b9d8fc7d568c9e8eaa7", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "PQvH7Y8J0st920brwe15mrFWOpq4S_UkWHoiCv5JnBI", - "y" : "4i3Ds8EDgkpPN42WrbCkCKvxnOfWiqYkT3jLIW-j-N8" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "043d0bc7ed8f09d2cb7ddb46ebc1ed799ab1563a9ab84bf524587a220afe499c12e22dc3b3c103824a4f378d96adb0a408abf19ce7d68aa6244f78cb216fa3f8df", - "wx" : "3d0bc7ed8f09d2cb7ddb46ebc1ed799ab1563a9ab84bf524587a220afe499c12", - "wy" : "00e22dc3b3c103824a4f378d96adb0a408abf19ce7d68aa6244f78cb216fa3f8df" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200043d0bc7ed8f09d2cb7ddb46ebc1ed799ab1563a9ab84bf524587a220afe499c12e22dc3b3c103824a4f378d96adb0a408abf19ce7d68aa6244f78cb216fa3f8df", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPQvH7Y8J0st920brwe15mrFWOpq4\nS/UkWHoiCv5JnBLiLcOzwQOCSk83jZatsKQIq/Gc59aKpiRPeMshb6P43w==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 185, - "comment" : "extreme value for k and s^-1", - "msg" : "313233343030", - "sig" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2963333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aaa", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "psiFreGkxWb5uwENBml0q7KBeX-nASiMchvL0jZjqbc", - "y" : "LkJLaQlXFo0ZOmCW_HeisASpx9Rn4Afh8gWEWPmK8xY" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04a6c885ade1a4c566f9bb010d066974abb281797fa701288c721bcbd23663a9b72e424b690957168d193a6096fc77a2b004a9c7d467e007e1f2058458f98af316", - "wx" : "00a6c885ade1a4c566f9bb010d066974abb281797fa701288c721bcbd23663a9b7", - "wy" : "2e424b690957168d193a6096fc77a2b004a9c7d467e007e1f2058458f98af316" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004a6c885ade1a4c566f9bb010d066974abb281797fa701288c721bcbd23663a9b72e424b690957168d193a6096fc77a2b004a9c7d467e007e1f2058458f98af316", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpsiFreGkxWb5uwENBml0q7KBeX+n\nASiMchvL0jZjqbcuQktpCVcWjRk6YJb8d6KwBKnH1GfgB+HyBYRY+YrzFg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 186, - "comment" : "extreme value for k and s^-1", - "msg" : "313233343030", - "sig" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29649249248db6db6dbb6db6db6db6db6db5a8b230d0b2b51dcd7ebf0c9fef7c185", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "jTwsLDt2W6gonmrDgSVyolv3XfYth6tzMMO9utnr-lw", - "y" : "TGhFRC1mk1sjhXjUOuxU98qhYh0a8kHUYy4LeAxCP10" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "048d3c2c2c3b765ba8289e6ac3812572a25bf75df62d87ab7330c3bdbad9ebfa5c4c6845442d66935b238578d43aec54f7caa1621d1af241d4632e0b780c423f5d", - "wx" : "008d3c2c2c3b765ba8289e6ac3812572a25bf75df62d87ab7330c3bdbad9ebfa5c", - "wy" : "4c6845442d66935b238578d43aec54f7caa1621d1af241d4632e0b780c423f5d" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200048d3c2c2c3b765ba8289e6ac3812572a25bf75df62d87ab7330c3bdbad9ebfa5c4c6845442d66935b238578d43aec54f7caa1621d1af241d4632e0b780c423f5d", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjTwsLDt2W6gonmrDgSVyolv3XfYt\nh6tzMMO9utnr+lxMaEVELWaTWyOFeNQ67FT3yqFiHRryQdRjLgt4DEI/XQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 187, - "comment" : "extreme value for k", - "msg" : "313233343030", - "sig" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29616a4502e2781e11ac82cbc9d1edd8c981584d13e18411e2f6e0478c34416e3bb", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpY", - "y" : "T-NC4v4af5uO5-tKfA-eFivOM1drMV7Oy7ZAaDe_UfU" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", - "wx" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", - "wy" : "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaxfR8uEsQkf4vOblY6RA8ncDfYEt\n6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9Q==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 188, - "comment" : "testing point duplication", - "msg" : "313233343030", - "sig" : "bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2", - "result" : "invalid", - "flags" : [] - }, - { - "tcId" : 189, - "comment" : "testing point duplication", - "msg" : "313233343030", - "sig" : "44a5ad0ad0636d9f12bc9e0a6bdd5e1cbcb012ea7bf091fcec15b0c43202d52e249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2", - "result" : "invalid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpY", - "y" : "sBy9HAHlgGVxGBS1g_Bh6dQxzKmUzqExNEm_l8hArgo" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296b01cbd1c01e58065711814b583f061e9d431cca994cea1313449bf97c840ae0a", - "wx" : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", - "wy" : "00b01cbd1c01e58065711814b583f061e9d431cca994cea1313449bf97c840ae0a" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296b01cbd1c01e58065711814b583f061e9d431cca994cea1313449bf97c840ae0a", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaxfR8uEsQkf4vOblY6RA8ncDfYEt\n6zOg9KE5RdiYwpawHL0cAeWAZXEYFLWD8GHp1DHMqZTOoTE0Sb+XyECuCg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 190, - "comment" : "testing point duplication", - "msg" : "313233343030", - "sig" : "bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2", - "result" : "invalid", - "flags" : [] - }, - { - "tcId" : 191, - "comment" : "testing point duplication", - "msg" : "313233343030", - "sig" : "44a5ad0ad0636d9f12bc9e0a6bdd5e1cbcb012ea7bf091fcec15b0c43202d52e249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2", - "result" : "invalid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "BKrsc2NXJvIT-4qeZNo7hjLkFJWpRNAEW1IuunJA-tU", - "y" : "h9kxV5iqo6W6AXdXh87QXqr3tOCfyB1tGqVG6DZdUl0" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "0404aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad587d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d", - "wx" : "04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5", - "wy" : "0087d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000404aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad587d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBKrsc2NXJvIT+4qeZNo7hjLkFJWp\nRNAEW1IuunJA+tWH2TFXmKqjpboBd1eHztBeqve04J/IHW0apUboNl1SXQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 192, - "comment" : "pseudorandom signature", - "msg" : "", - "sig" : "b292a619339f6e567a305c951c0dcbcc42d16e47f219f9e98e76e09d8770b34a0177e60492c5a8242f76f07bfe3661bde59ec2a17ce5bd2dab2abebdf89a62e2", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 193, - "comment" : "pseudorandom signature", - "msg" : "4d7367", - "sig" : "530bd6b0c9af2d69ba897f6b5fb59695cfbf33afe66dbadcf5b8d2a2a6538e23d85e489cb7a161fd55ededcedbf4cc0c0987e3e3f0f242cae934c72caa3f43e9", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 194, - "comment" : "pseudorandom signature", - "msg" : "313233343030", - "sig" : "a8ea150cb80125d7381c4c1f1da8e9de2711f9917060406a73d7904519e51388f3ab9fa68bd47973a73b2d40480c2ba50c22c9d76ec217257288293285449b86", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 195, - "comment" : "pseudorandom signature", - "msg" : "0000000000000000000000000000000000000000", - "sig" : "986e65933ef2ed4ee5aada139f52b70539aaf63f00a91f29c69178490d57fb713dafedfb8da6189d372308cbf1489bbbdabf0c0217d1c0ff0f701aaa7a694b9c", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "TzN8z9Z3JqgF5PFgCuKEnfOAfsoRc4Ajn72BaQAAAAA", - "y" : "7Z3qEkzIw5ZBZBHpiMMPQn61BK9DoxRs1d9-pgZm1oU" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "044f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685", - "wx" : "4f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000", - "wy" : "00ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200044f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETzN8z9Z3JqgF5PFgCuKEnfOAfsoR\nc4Ajn72BaQAAAADtneoSTMjDlkFkEemIww9CfrUEr0OjFGzV336mBmbWhQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 196, - "comment" : "x-coordinate of the public key has many trailing 0's", - "msg" : "4d657373616765", - "sig" : "d434e262a49eab7781e353a3565e482550dd0fd5defa013c7f29745eff3569f19b0c0a93f267fb6052fd8077be769c2b98953195d7bc10de844218305c6ba17a", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 197, - "comment" : "x-coordinate of the public key has many trailing 0's", - "msg" : "4d657373616765", - "sig" : "0fe774355c04d060f76d79fd7a772e421463489221bf0a33add0be9b1979110b500dcba1c69a8fbd43fa4f57f743ce124ca8b91a1f325f3fac6181175df55737", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 198, - "comment" : "x-coordinate of the public key has many trailing 0's", - "msg" : "4d657373616765", - "sig" : "bb40bf217bed3fb3950c7d39f03d36dc8e3b2cd79693f125bfd06595ee1135e3541bf3532351ebb032710bdb6a1bf1bfc89a1e291ac692b3fa4780745bb55677", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "PPA9YU2JOc_UmaB4c_rCgWGPBrj_h-gBXD9JcmUASTU", - "y" : "hPoXTXkccr8s44gKiWDdKnx6EzioL4Wp5Zzb3oAAAAA" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "043cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f49726500493584fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000", - "wx" : "3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935", - "wy" : "0084fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200043cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f49726500493584fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPPA9YU2JOc/UmaB4c/rCgWGPBrj/\nh+gBXD9JcmUASTWE+hdNeRxyvyzjiAqJYN0qfHoTOKgvhanlnNvegAAAAA==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 199, - "comment" : "y-coordinate of the public key has many trailing 0's", - "msg" : "4d657373616765", - "sig" : "664eb7ee6db84a34df3c86ea31389a5405badd5ca99231ff556d3e75a233e73a59f3c752e52eca46137642490a51560ce0badc678754b8f72e51a2901426a1bd", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 200, - "comment" : "y-coordinate of the public key has many trailing 0's", - "msg" : "4d657373616765", - "sig" : "4cd0429bbabd2827009d6fcd843d4ce39c3e42e2d1631fd001985a79d1fd8b439638bf12dd682f60be7ef1d0e0d98f08b7bca77a1a2b869ae466189d2acdabe3", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 201, - "comment" : "y-coordinate of the public key has many trailing 0's", - "msg" : "4d657373616765", - "sig" : "e56c6ea2d1b017091c44d8b6cb62b9f460e3ce9aed5e5fd41e8added97c56c04a308ec31f281e955be20b457e463440b4fcf2b80258078207fc1378180f89b55", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "PPA9YU2JOc_UmaB4c_rCgWGPBrj_h-gBXD9JcmUASTU", - "y" : "ewXosYbjjUHTHHf1dp8i1YOF7MhX0HpWGmMkIX____8" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "043cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f4972650049357b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff", - "wx" : "3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935", - "wy" : "7b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200043cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f4972650049357b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPPA9YU2JOc/UmaB4c/rCgWGPBrj/\nh+gBXD9JcmUASTV7BeixhuONQdMcd/V2nyLVg4XsyFfQelYaYyQhf////w==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 202, - "comment" : "y-coordinate of the public key has many trailing 1's", - "msg" : "4d657373616765", - "sig" : "1158a08d291500b4cabed3346d891eee57c176356a2624fb011f8fbbf3466830228a8c486a736006e082325b85290c5bc91f378b75d487dda46798c18f285519", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 203, - "comment" : "y-coordinate of the public key has many trailing 1's", - "msg" : "4d657373616765", - "sig" : "b1db9289649f59410ea36b0c0fc8d6aa2687b29176939dd23e0dde56d309fa9d3e1535e4280559015b0dbd987366dcf43a6d1af5c23c7d584e1c3f48a1251336", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 204, - "comment" : "y-coordinate of the public key has many trailing 1's", - "msg" : "4d657373616765", - "sig" : "b7b16e762286cb96446aa8d4e6e7578b0a341a79f2dd1a220ac6f0ca4e24ed86ddc60a700a139b04661c547d07bbb0721780146df799ccf55e55234ecb8f12bc", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "KCnDH6ouQA40TtlLyj_NBUWVbrz-itD236X_jv____8", - "y" : "oBqvrwAOUlhYVa-nZ2reKEETCZBS31fn6zvTfr65Ii4" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "042829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffffa01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e", - "wx" : "2829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffff", - "wy" : "00a01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d030107034200042829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffffa01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKCnDH6ouQA40TtlLyj/NBUWVbrz+\nitD236X/jv////+gGq+vAA5SWFhVr6dnat4oQRMJkFLfV+frO9N+vrkiLg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 205, - "comment" : "x-coordinate of the public key has many trailing 1's", - "msg" : "4d657373616765", - "sig" : "d82a7c2717261187c8e00d8df963ff35d796edad36bc6e6bd1c91c670d9105b43dcabddaf8fcaa61f4603e7cbac0f3c0351ecd5988efb23f680d07debd139929", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 206, - "comment" : "x-coordinate of the public key has many trailing 1's", - "msg" : "4d657373616765", - "sig" : "5eb9c8845de68eb13d5befe719f462d77787802baff30ce96a5cba063254af782c026ae9be2e2a5e7ca0ff9bbd92fb6e44972186228ee9a62b87ddbe2ef66fb5", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 207, - "comment" : "x-coordinate of the public key has many trailing 1's", - "msg" : "4d657373616765", - "sig" : "96843dd03c22abd2f3b782b170239f90f277921becc117d0404a8e4e36230c28f2be378f526f74a543f67165976de9ed9a31214eb4d7e6db19e1ede123dd991d", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "____-UgIHmoEWN2PnnOPJmX_kFmtaqwHCDGMTKmnpPU", - "y" : "Woq8ui3ahHQxHuVBSblzyuDA-4lVetC_eOZSmhZjvXM" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f55a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73", - "wx" : "00fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f5", - "wy" : "5a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f55a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE////+UgIHmoEWN2PnnOPJmX/kFmt\naqwHCDGMTKmnpPVairy6LdqEdDEe5UFJuXPK4MD7iVV60L945lKaFmO9cw==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 208, - "comment" : "x-coordinate of the public key is large", - "msg" : "4d657373616765", - "sig" : "766456dce1857c906f9996af729339464d27e9d98edc2d0e3b760297067421f6402385ecadae0d8081dccaf5d19037ec4e55376eced699e93646bfbbf19d0b41", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 209, - "comment" : "x-coordinate of the public key is large", - "msg" : "4d657373616765", - "sig" : "c605c4b2edeab20419e6518a11b2dbc2b97ed8b07cced0b19c34f777de7b9fd9edf0f612c5f46e03c719647bc8af1b29b2cde2eda700fb1cff5e159d47326dba", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 210, - "comment" : "x-coordinate of the public key is large", - "msg" : "4d657373616765", - "sig" : "d48b68e6cabfe03cf6141c9ac54141f210e64485d9929ad7b732bfe3b7eb8a84feedae50c61bd00e19dc26f9b7e2265e4508c389109ad2f208f0772315b6c941", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "AAAAA_oV-WOUnV8DpvXH-G-eABXusjrrv_EXOTe6dI4", - "y" : "EJmHIHDo6HxVX6E2Wcyl1_rc_LACPqiJVIykivK6fnE" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "0400000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71", - "wx" : "03fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e", - "wy" : "1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d0301070342000400000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAAAAA/oV+WOUnV8DpvXH+G+eABXu\nsjrrv/EXOTe6dI4QmYcgcOjofFVfoTZZzKXX+tz8sAI+qIlUjKSK8rp+cQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 211, - "comment" : "x-coordinate of the public key is small", - "msg" : "4d657373616765", - "sig" : "b7c81457d4aeb6aa65957098569f0479710ad7f6595d5874c35a93d12a5dd4c7b7961a0b652878c2d568069a432ca18a1a9199f2ca574dad4b9e3a05c0a1cdb3", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 212, - "comment" : "x-coordinate of the public key is small", - "msg" : "4d657373616765", - "sig" : "6b01332ddb6edfa9a30a1321d5858e1ee3cf97e263e669f8de5e9652e76ff3f75939545fced457309a6a04ace2bd0f70139c8f7d86b02cb1cc58f9e69e96cd5a", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 213, - "comment" : "x-coordinate of the public key is small", - "msg" : "4d657373616765", - "sig" : "efdb884720eaeadc349f9fc356b6c0344101cd2fd8436b7d0e6a4fb93f106361f24bee6ad5dc05f7613975473aadf3aacba9e77de7d69b6ce48cb60d8113385d", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "vLspFMefBF6qbsu8YSgWs75dLWeWcH2BJen4UcGK8BU", - "y" : "AAAAABNSu0oPoupMzrmrY91oSt5aESe88wCmmKcZO8I" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2", - "wx" : "00bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015", - "wy" : "1352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvLspFMefBF6qbsu8YSgWs75dLWeW\ncH2BJen4UcGK8BUAAAAAE1K7Sg+i6kzOuatj3WhK3loRJ7zzAKaYpxk7wg==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 214, - "comment" : "y-coordinate of the public key is small", - "msg" : "4d657373616765", - "sig" : "31230428405560dcb88fb5a646836aea9b23a23dd973dcbe8014c87b8b20eb070f9344d6e812ce166646747694a41b0aaf97374e19f3c5fb8bd7ae3d9bd0beff", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 215, - "comment" : "y-coordinate of the public key is small", - "msg" : "4d657373616765", - "sig" : "caa797da65b320ab0d5c470cda0b36b294359c7db9841d679174db34c4855743cf543a62f23e212745391aaf7505f345123d2685ee3b941d3de6d9b36242e5a0", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 216, - "comment" : "y-coordinate of the public key is small", - "msg" : "4d657373616765", - "sig" : "7e5f0ab5d900d3d3d7867657e5d6d36519bc54084536e7d21c336ed8001859459450c07f201faec94b82dfb322e5ac676688294aad35aa72e727ff0b19b646aa", - "result" : "valid", - "flags" : [] - } - ] - }, - { - "jwk" : { - "crv" : "P-256", - "kid" : "none", - "kty" : "EC", - "x" : "vLspFMefBF6qbsu8YSgWs75dLWeWcH2BJen4UcGK8BU", - "y" : "_____uytRLbwXRWzMUZUnCKXtSKl7thDDP9ZZ1jmxD0" - }, - "key" : { - "curve" : "secp256r1", - "keySize" : 256, - "type" : "EcPublicKey", - "uncompressed" : "04bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d", - "wx" : "00bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015", - "wy" : "00fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d" - }, - "keyDer" : "3059301306072a8648ce3d020106082a8648ce3d03010703420004bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d", - "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvLspFMefBF6qbsu8YSgWs75dLWeW\ncH2BJen4UcGK8BX////+7K1EtvBdFbMxRlScIpe1IqXu2EMM/1lnWObEPQ==\n-----END PUBLIC KEY-----", - "sha" : "SHA-256", - "type" : "EcdsaP1363Verify", - "tests" : [ - { - "tcId" : 217, - "comment" : "y-coordinate of the public key is large", - "msg" : "4d657373616765", - "sig" : "d7d70c581ae9e3f66dc6a480bf037ae23f8a1e4a2136fe4b03aa69f0ca25b35689c460f8a5a5c2bbba962c8a3ee833a413e85658e62a59e2af41d9127cc47224", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 218, - "comment" : "y-coordinate of the public key is large", - "msg" : "4d657373616765", - "sig" : "341c1b9ff3c83dd5e0dfa0bf68bcdf4bb7aa20c625975e5eeee34bb396266b3472b69f061b750fd5121b22b11366fad549c634e77765a017902a67099e0a4469", - "result" : "valid", - "flags" : [] - }, - { - "tcId" : 219, - "comment" : "y-coordinate of the public key is large", - "msg" : "4d657373616765", - "sig" : "70bebe684cdcb5ca72a42f0d873879359bd1781a591809947628d313a3814f67aec03aca8f5587a4d535fa31027bbe9cc0e464b1c3577f4c2dcde6b2094798a9", - "result" : "valid", - "flags" : [] - } - ] - } - ] -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js deleted file mode 100644 index 8117c69..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js +++ /dev/null @@ -1,18 +0,0 @@ -const { ethers } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { shouldSupportInterfaces } = require('./SupportsInterface.behavior'); - -async function fixture() { - return { - mock: await ethers.deployContract('$ERC165'), - }; -} - -describe('ERC165', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - shouldSupportInterfaces(); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js deleted file mode 100644 index 1bbe8a5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js +++ /dev/null @@ -1,245 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -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'; - -async function fixture() { - return { mock: await ethers.deployContract('$ERC165Checker') }; -} - -describe('ERC165Checker', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('ERC165 missing return data', function () { - before(async function () { - this.target = await ethers.deployContract('ERC165MissingData'); - }); - - it('does not support ERC165', async function () { - expect(await this.mock.$supportsERC165(this.target)).to.be.false; - }); - - it('does not support mock interface via supportsInterface', async function () { - expect(await this.mock.$supportsInterface(this.target, DUMMY_ID)).to.be.false; - }); - - it('does not support mock interface via supportsAllInterfaces', async function () { - expect(await this.mock.$supportsAllInterfaces(this.target, [DUMMY_ID])).to.be.false; - }); - - it('does not support mock interface via getSupportedInterfaces', async function () { - expect(await this.mock.$getSupportedInterfaces(this.target, [DUMMY_ID])).to.deep.equal([false]); - }); - - it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { - expect(await this.mock.$supportsERC165InterfaceUnchecked(this.target, DUMMY_ID)).to.be.false; - }); - }); - - describe('ERC165 malicious return data', function () { - beforeEach(async function () { - this.target = await ethers.deployContract('ERC165MaliciousData'); - }); - - it('does not support ERC165', async function () { - expect(await this.mock.$supportsERC165(this.target)).to.be.false; - }); - - it('does not support mock interface via supportsInterface', async function () { - expect(await this.mock.$supportsInterface(this.target, DUMMY_ID)).to.be.false; - }); - - it('does not support mock interface via supportsAllInterfaces', async function () { - expect(await this.mock.$supportsAllInterfaces(this.target, [DUMMY_ID])).to.be.false; - }); - - it('does not support mock interface via getSupportedInterfaces', async function () { - expect(await this.mock.$getSupportedInterfaces(this.target, [DUMMY_ID])).to.deep.equal([false]); - }); - - it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { - expect(await this.mock.$supportsERC165InterfaceUnchecked(this.target, DUMMY_ID)).to.be.true; - }); - }); - - describe('ERC165 not supported', function () { - beforeEach(async function () { - this.target = await ethers.deployContract('ERC165NotSupported'); - }); - - it('does not support ERC165', async function () { - expect(await this.mock.$supportsERC165(this.target)).to.be.false; - }); - - it('does not support mock interface via supportsInterface', async function () { - expect(await this.mock.$supportsInterface(this.target, DUMMY_ID)).to.be.false; - }); - - it('does not support mock interface via supportsAllInterfaces', async function () { - expect(await this.mock.$supportsAllInterfaces(this.target, [DUMMY_ID])).to.be.false; - }); - - it('does not support mock interface via getSupportedInterfaces', async function () { - expect(await this.mock.$getSupportedInterfaces(this.target, [DUMMY_ID])).to.deep.equal([false]); - }); - - it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { - expect(await this.mock.$supportsERC165InterfaceUnchecked(this.target, DUMMY_ID)).to.be.false; - }); - }); - - describe('ERC165 supported', function () { - beforeEach(async function () { - this.target = await ethers.deployContract('ERC165InterfacesSupported', [[]]); - }); - - it('supports ERC165', async function () { - expect(await this.mock.$supportsERC165(this.target)).to.be.true; - }); - - it('does not support mock interface via supportsInterface', async function () { - expect(await this.mock.$supportsInterface(this.target, DUMMY_ID)).to.be.false; - }); - - it('does not support mock interface via supportsAllInterfaces', async function () { - expect(await this.mock.$supportsAllInterfaces(this.target, [DUMMY_ID])).to.be.false; - }); - - it('does not support mock interface via getSupportedInterfaces', async function () { - expect(await this.mock.$getSupportedInterfaces(this.target, [DUMMY_ID])).to.deep.equal([false]); - }); - - it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { - expect(await this.mock.$supportsERC165InterfaceUnchecked(this.target, DUMMY_ID)).to.be.false; - }); - }); - - describe('ERC165 and single interface supported', function () { - beforeEach(async function () { - this.target = await ethers.deployContract('ERC165InterfacesSupported', [[DUMMY_ID]]); - }); - - it('supports ERC165', async function () { - expect(await this.mock.$supportsERC165(this.target)).to.be.true; - }); - - it('supports mock interface via supportsInterface', async function () { - expect(await this.mock.$supportsInterface(this.target, DUMMY_ID)).to.be.true; - }); - - it('supports mock interface via supportsAllInterfaces', async function () { - expect(await this.mock.$supportsAllInterfaces(this.target, [DUMMY_ID])).to.be.true; - }); - - it('supports mock interface via getSupportedInterfaces', async function () { - expect(await this.mock.$getSupportedInterfaces(this.target, [DUMMY_ID])).to.deep.equal([true]); - }); - - it('supports mock interface via supportsERC165InterfaceUnchecked', async function () { - expect(await this.mock.$supportsERC165InterfaceUnchecked(this.target, DUMMY_ID)).to.be.true; - }); - }); - - describe('ERC165 and many interfaces supported', function () { - const supportedInterfaces = [DUMMY_ID, DUMMY_ID_2, DUMMY_ID_3]; - beforeEach(async function () { - this.target = await ethers.deployContract('ERC165InterfacesSupported', [supportedInterfaces]); - }); - - it('supports ERC165', async function () { - expect(await this.mock.$supportsERC165(this.target)).to.be.true; - }); - - it('supports each interfaceId via supportsInterface', async function () { - for (const interfaceId of supportedInterfaces) { - expect(await this.mock.$supportsInterface(this.target, interfaceId)).to.be.true; - } - }); - - it('supports all interfaceIds via supportsAllInterfaces', async function () { - expect(await this.mock.$supportsAllInterfaces(this.target, supportedInterfaces)).to.be.true; - }); - - it('supports none of the interfaces queried via supportsAllInterfaces', async function () { - const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2]; - - expect(await this.mock.$supportsAllInterfaces(this.target, interfaceIdsToTest)).to.be.false; - }); - - it('supports not all of the interfaces queried via supportsAllInterfaces', async function () { - const interfaceIdsToTest = [...supportedInterfaces, DUMMY_UNSUPPORTED_ID]; - expect(await this.mock.$supportsAllInterfaces(this.target, interfaceIdsToTest)).to.be.false; - }); - - it('supports all interfaceIds via getSupportedInterfaces', async function () { - expect(await this.mock.$getSupportedInterfaces(this.target, supportedInterfaces)).to.deep.equal( - supportedInterfaces.map(i => supportedInterfaces.includes(i)), - ); - }); - - it('supports none of the interfaces queried via getSupportedInterfaces', async function () { - const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2]; - - expect(await this.mock.$getSupportedInterfaces(this.target, interfaceIdsToTest)).to.deep.equal( - interfaceIdsToTest.map(i => supportedInterfaces.includes(i)), - ); - }); - - it('supports not all of the interfaces queried via getSupportedInterfaces', async function () { - const interfaceIdsToTest = [...supportedInterfaces, DUMMY_UNSUPPORTED_ID]; - - expect(await this.mock.$getSupportedInterfaces(this.target, interfaceIdsToTest)).to.deep.equal( - interfaceIdsToTest.map(i => supportedInterfaces.includes(i)), - ); - }); - - it('supports each interfaceId via supportsERC165InterfaceUnchecked', async function () { - for (const interfaceId of supportedInterfaces) { - expect(await this.mock.$supportsERC165InterfaceUnchecked(this.target, interfaceId)).to.be.true; - } - }); - }); - - describe('account address does not support ERC165', function () { - it('does not support ERC165', async function () { - expect(await this.mock.$supportsERC165(DUMMY_ACCOUNT)).to.be.false; - }); - - it('does not support mock interface via supportsInterface', async function () { - expect(await this.mock.$supportsInterface(DUMMY_ACCOUNT, DUMMY_ID)).to.be.false; - }); - - it('does not support mock interface via supportsAllInterfaces', async function () { - expect(await this.mock.$supportsAllInterfaces(DUMMY_ACCOUNT, [DUMMY_ID])).to.be.false; - }); - - it('does not support mock interface via getSupportedInterfaces', async function () { - expect(await this.mock.$getSupportedInterfaces(DUMMY_ACCOUNT, [DUMMY_ID])).to.deep.equal([false]); - }); - - it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { - expect(await this.mock.$supportsERC165InterfaceUnchecked(DUMMY_ACCOUNT, DUMMY_ID)).to.be.false; - }); - }); - - it('Return bomb resistance', async function () { - this.target = await ethers.deployContract('ERC165ReturnBombMock'); - - const { gasUsed: gasUsed1 } = await this.mock.$supportsInterface.send(this.target, DUMMY_ID).then(tx => tx.wait()); - expect(gasUsed1).to.be.lessThan(120_000n); // 3*30k + 21k + some margin - - const { gasUsed: gasUsed2 } = await this.mock.$getSupportedInterfaces - .send(this.target, [DUMMY_ID, DUMMY_ID_2, DUMMY_ID_3, DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2]) - .then(tx => tx.wait()); - - expect(gasUsed2).to.be.lessThan(250_000n); // (2+5)*30k + 21k + some margin - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js deleted file mode 100644 index 6e716d1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js +++ /dev/null @@ -1,166 +0,0 @@ -const { expect } = require('chai'); -const { interfaceId } = require('../../helpers/methods'); -const { mapValues } = require('../../helpers/iterate'); - -const INVALID_ID = '0xffffffff'; -const GOVERNOR_INTERFACE = [ - '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)', -]; -const SIGNATURES = { - 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)', - ], - ERC1155MetadataURI: ['uri(uint256)'], - ERC1155Receiver: [ - 'onERC1155Received(address,address,uint256,uint256,bytes)', - 'onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)', - ], - ERC1363: [ - 'transferAndCall(address,uint256)', - 'transferAndCall(address,uint256,bytes)', - 'transferFromAndCall(address,address,uint256)', - 'transferFromAndCall(address,address,uint256,bytes)', - 'approveAndCall(address,uint256)', - 'approveAndCall(address,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: GOVERNOR_INTERFACE, - Governor_5_3: GOVERNOR_INTERFACE.concat('getProposalId(address[],uint256[],bytes[],bytes32)'), - ERC2981: ['royaltyInfo(uint256,uint256)'], - ERC6909: [ - 'balanceOf(address,uint256)', - 'allowance(address,address,uint256)', - 'isOperator(address,address)', - 'transfer(address,uint256,uint256)', - 'transferFrom(address,address,uint256,uint256)', - 'approve(address,uint256,uint256)', - 'setOperator(address,bool)', - ], -}; - -const INTERFACE_IDS = mapValues(SIGNATURES, interfaceId); - -function shouldSupportInterfaces(interfaces = [], signatures = SIGNATURES) { - // case where only signatures are provided - if (!Array.isArray(interfaces)) { - signatures = interfaces; - interfaces = Object.keys(interfaces); - } - - interfaces.unshift('ERC165'); - signatures.ERC165 = SIGNATURES.ERC165; - const interfaceIds = mapValues(signatures, interfaceId, ([name]) => interfaces.includes(name)); - - describe('ERC165', function () { - beforeEach(function () { - this.contractUnderTest = this.mock || this.token; - }); - - describe('when the interfaceId is supported', function () { - it('uses less than 30k gas', async function () { - for (const k of interfaces) { - const interfaceId = interfaceIds[k] ?? k; - expect(await this.contractUnderTest.supportsInterface.estimateGas(interfaceId)).to.lte(30_000n); - } - }); - - it('returns true', async function () { - for (const k of interfaces) { - const interfaceId = interfaceIds[k] ?? k; - expect(await this.contractUnderTest.supportsInterface(interfaceId), `does not support ${k}`).to.be.true; - } - }); - }); - - describe('when the interfaceId is not supported', function () { - it('uses less than 30k', async function () { - expect(await this.contractUnderTest.supportsInterface.estimateGas(INVALID_ID)).to.lte(30_000n); - }); - - it('returns false', async function () { - expect(await this.contractUnderTest.supportsInterface(INVALID_ID), `supports ${INVALID_ID}`).to.be.false; - }); - }); - - 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 (signatures[k] === undefined) continue; - - // Check the presence of each function in the contract's interface - for (const fnSig of signatures[k]) { - expect(this.contractUnderTest.interface.hasFunction(fnSig), `did not find ${fnSig}`).to.be.true; - } - } - }); - }); -} - -module.exports = { - SIGNATURES, - INTERFACE_IDS, - shouldSupportInterfaces, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.t.sol deleted file mode 100644 index 3c83feb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.t.sol +++ /dev/null @@ -1,349 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {Test, stdError} from "forge-std/Test.sol"; - -import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; - -contract MathTest is Test { - function testSymbolicTernary(bool f, uint256 a, uint256 b) public pure { - assertEq(Math.ternary(f, a, b), f ? a : b); - } - - // ADD512 & MUL512 - function testAdd512(uint256 a, uint256 b) public pure { - (uint256 high, uint256 low) = Math.add512(a, b); - - // test against tryAdd - (bool success, uint256 result) = Math.tryAdd(a, b); - if (success) { - assertEq(high, 0); - assertEq(low, result); - } else { - assertEq(high, 1); - } - - // test against unchecked - unchecked { - assertEq(low, a + b); // unchecked allow overflow - } - } - - function testMul512(uint256 a, uint256 b) public pure { - (uint256 high, uint256 low) = Math.mul512(a, b); - - // test against tryMul - (bool success, uint256 result) = Math.tryMul(a, b); - if (success) { - assertEq(high, 0); - assertEq(low, result); - } else { - assertGt(high, 0); - } - - // test against unchecked - unchecked { - assertEq(low, a * b); // unchecked allow overflow - } - - // test against alternative method - (uint256 _high, uint256 _low) = _mulKaratsuba(a, b); - assertEq(high, _high); - assertEq(low, _low); - } - - // MIN & MAX - function testSymbolicMinMax(uint256 a, uint256 b) public pure { - assertEq(Math.min(a, b), a < b ? a : b); - assertEq(Math.max(a, b), a > b ? a : b); - } - - // CEILDIV - function testCeilDiv(uint256 a, uint256 b) public pure { - vm.assume(b > 0); - - uint256 result = Math.ceilDiv(a, b); - - if (result == 0) { - assertEq(a, 0); - } else { - uint256 expect = a / b; - if (expect * b < a) { - expect += 1; - } - assertEq(result, expect); - } - } - - // SQRT - function testSqrt(uint256 input, uint8 r) public pure { - 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; - } - - // INV - function testInvMod(uint256 value, uint256 p) public pure { - _testInvMod(value, p, true); - } - - function testInvMod2(uint256 seed) public pure { - uint256 p = 2; // prime - _testInvMod(bound(seed, 1, p - 1), p, false); - } - - function testInvMod17(uint256 seed) public pure { - uint256 p = 17; // prime - _testInvMod(bound(seed, 1, p - 1), p, false); - } - - function testInvMod65537(uint256 seed) public pure { - uint256 p = 65537; // prime - _testInvMod(bound(seed, 1, p - 1), p, false); - } - - function testInvModP256(uint256 seed) public pure { - uint256 p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff; // prime - _testInvMod(bound(seed, 1, p - 1), p, false); - } - - function _testInvMod(uint256 value, uint256 p, bool allowZero) private pure { - uint256 inverse = Math.invMod(value, p); - if (inverse != 0) { - assertEq(mulmod(value, inverse, p), 1); - assertLt(inverse, p); - } else { - assertTrue(allowZero); - } - } - - // LOG2 - function testLog2(uint256 input, uint8 r) public pure { - 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 pure { - 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 pure { - 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 pure { - // Full precision for x * y - (uint256 xyHi, uint256 xyLo) = Math.mul512(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) = Math.mul512(q, d); - // Add remainder of x * y / d (computed as rem = (x * y % d)) - (uint256 c, uint256 qdRemLo) = Math.add512(qdLo, mulmod(x, y, d)); - uint256 qdRemHi = qdHi + c; - - // Full precision check that x * y = q * d + rem - assertEq(xyHi, qdRemHi); - assertEq(xyLo, qdRemLo); - } - - /// forge-config: default.allow_internal_expect_revert = true - function testMulDivDomain(uint256 x, uint256 y, uint256 d) public { - (uint256 xyHi, ) = Math.mul512(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 - vm.expectRevert(d == 0 ? stdError.divisionError : stdError.arithmeticError); - Math.mulDiv(x, y, d); - } - - // MOD EXP - /// forge-config: default.allow_internal_expect_revert = true - function testModExp(uint256 b, uint256 e, uint256 m) public { - if (m == 0) { - vm.expectRevert(stdError.divisionError); - } - uint256 result = Math.modExp(b, e, m); - assertLt(result, m); - assertEq(result, _nativeModExp(b, e, m)); - } - - function testTryModExp(uint256 b, uint256 e, uint256 m) public view { - (bool success, uint256 result) = Math.tryModExp(b, e, m); - assertEq(success, m != 0); - if (success) { - assertLt(result, m); - assertEq(result, _nativeModExp(b, e, m)); - } else { - assertEq(result, 0); - } - } - - /// forge-config: default.allow_internal_expect_revert = true - function testModExpMemory(uint256 b, uint256 e, uint256 m) public { - if (m == 0) { - vm.expectRevert(stdError.divisionError); - } - bytes memory result = Math.modExp(abi.encodePacked(b), abi.encodePacked(e), abi.encodePacked(m)); - assertEq(result.length, 0x20); - uint256 res = abi.decode(result, (uint256)); - assertLt(res, m); - assertEq(res, _nativeModExp(b, e, m)); - } - - function testTryModExpMemory(uint256 b, uint256 e, uint256 m) public view { - (bool success, bytes memory result) = Math.tryModExp( - abi.encodePacked(b), - abi.encodePacked(e), - abi.encodePacked(m) - ); - if (success) { - assertEq(result.length, 0x20); // m is a uint256, so abi.encodePacked(m).length is 0x20 - uint256 res = abi.decode(result, (uint256)); - assertLt(res, m); - assertEq(res, _nativeModExp(b, e, m)); - } else { - assertEq(result.length, 0); - } - } - - // Helpers - function _asRounding(uint8 r) private pure returns (Math.Rounding) { - vm.assume(r < uint8(type(Math.Rounding).max)); - return Math.Rounding(r); - } - - function _mulKaratsuba(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 _nativeModExp(uint256 b, uint256 e, uint256 m) private pure returns (uint256) { - if (m == 1) return 0; - uint256 r = 1; - while (e > 0) { - if (e % 2 > 0) { - r = mulmod(r, b, m); - } - b = mulmod(b, b, m); - e >>= 1; - } - return r; - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.test.js deleted file mode 100644 index 6a09938..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/Math.test.js +++ /dev/null @@ -1,713 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -const { Rounding } = require('../../helpers/enums'); -const { min, max, modExp } = require('../../helpers/math'); -const { generators } = require('../../helpers/random'); -const { product, range } = require('../../helpers/iterate'); - -const RoundingDown = [Rounding.Floor, Rounding.Trunc]; -const RoundingUp = [Rounding.Ceil, Rounding.Expand]; - -const bytes = (value, width = undefined) => ethers.Typed.bytes(ethers.toBeHex(value, width)); -const uint256 = value => ethers.Typed.uint256(value); -bytes.zero = '0x'; -uint256.zero = 0n; - -const testCommutative = (fn, lhs, rhs, expected, ...extra) => - Promise.all([ - expect(fn(lhs, rhs, ...extra)).to.eventually.deep.equal(expected), - expect(fn(rhs, lhs, ...extra)).to.eventually.deep.equal(expected), - ]); - -const splitHighLow = n => [n / (1n << 256n), n % (1n << 256n)]; - -async function fixture() { - const mock = await ethers.deployContract('$Math'); - - // disambiguation, we use the version with explicit rounding - mock.$mulDiv = mock['$mulDiv(uint256,uint256,uint256,uint8)']; - mock.$sqrt = mock['$sqrt(uint256,uint8)']; - mock.$log2 = mock['$log2(uint256,uint8)']; - mock.$log10 = mock['$log10(uint256,uint8)']; - mock.$log256 = mock['$log256(uint256,uint8)']; - - return { mock }; -} - -describe('Math', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('add512', function () { - it('adds correctly without reverting', async function () { - const values = [0n, 1n, 17n, 42n, ethers.MaxUint256 - 1n, ethers.MaxUint256]; - for (const [a, b] of product(values, values)) { - await expect(this.mock.$add512(a, b)).to.eventually.deep.equal(splitHighLow(a + b)); - } - }); - }); - - describe('mul512', function () { - it('multiplies correctly without reverting', async function () { - const values = [0n, 1n, 17n, 42n, ethers.MaxUint256 - 1n, ethers.MaxUint256]; - for (const [a, b] of product(values, values)) { - await expect(this.mock.$mul512(a, b)).to.eventually.deep.equal(splitHighLow(a * b)); - } - }); - }); - - describe('tryAdd', function () { - it('adds correctly', async function () { - const a = 5678n; - const b = 1234n; - await testCommutative(this.mock.$tryAdd, a, b, [true, a + b]); - }); - - it('reverts on addition overflow', async function () { - const a = ethers.MaxUint256; - const b = 1n; - await testCommutative(this.mock.$tryAdd, a, b, [false, 0n]); - }); - }); - - describe('trySub', function () { - it('subtracts correctly', async function () { - const a = 5678n; - const b = 1234n; - await expect(this.mock.$trySub(a, b)).to.eventually.deep.equal([true, a - b]); - }); - - it('reverts if subtraction result would be negative', async function () { - const a = 1234n; - const b = 5678n; - await expect(this.mock.$trySub(a, b)).to.eventually.deep.equal([false, 0n]); - }); - }); - - describe('tryMul', function () { - it('multiplies correctly', async function () { - const a = 1234n; - const b = 5678n; - await testCommutative(this.mock.$tryMul, a, b, [true, a * b]); - }); - - it('multiplies by zero correctly', async function () { - const a = 0n; - const b = 5678n; - await testCommutative(this.mock.$tryMul, a, b, [true, a * b]); - }); - - it('reverts on multiplication overflow', async function () { - const a = ethers.MaxUint256; - const b = 2n; - await testCommutative(this.mock.$tryMul, a, b, [false, 0n]); - }); - }); - - describe('tryDiv', function () { - it('divides correctly', async function () { - const a = 5678n; - const b = 5678n; - await expect(this.mock.$tryDiv(a, b)).to.eventually.deep.equal([true, a / b]); - }); - - it('divides zero correctly', async function () { - const a = 0n; - const b = 5678n; - await expect(this.mock.$tryDiv(a, b)).to.eventually.deep.equal([true, a / b]); - }); - - it('returns complete number result on non-even division', async function () { - const a = 7000n; - const b = 5678n; - await expect(this.mock.$tryDiv(a, b)).to.eventually.deep.equal([true, a / b]); - }); - - it('reverts on division by zero', async function () { - const a = 5678n; - const b = 0n; - await expect(this.mock.$tryDiv(a, b)).to.eventually.deep.equal([false, 0n]); - }); - }); - - describe('tryMod', function () { - describe('modulos correctly', function () { - it('when the dividend is smaller than the divisor', async function () { - const a = 284n; - const b = 5678n; - await expect(this.mock.$tryMod(a, b)).to.eventually.deep.equal([true, a % b]); - }); - - it('when the dividend is equal to the divisor', async function () { - const a = 5678n; - const b = 5678n; - await expect(this.mock.$tryMod(a, b)).to.eventually.deep.equal([true, a % b]); - }); - - it('when the dividend is larger than the divisor', async function () { - const a = 7000n; - const b = 5678n; - await expect(this.mock.$tryMod(a, b)).to.eventually.deep.equal([true, a % b]); - }); - - it('when the dividend is a multiple of the divisor', async function () { - const a = 17034n; // 17034 == 5678 * 3 - const b = 5678n; - await expect(this.mock.$tryMod(a, b)).to.eventually.deep.equal([true, a % b]); - }); - }); - - it('reverts with a 0 divisor', async function () { - const a = 5678n; - const b = 0n; - await expect(this.mock.$tryMod(a, b)).to.eventually.deep.equal([false, 0n]); - }); - }); - - describe('saturatingAdd', function () { - it('adds correctly', async function () { - const a = 5678n; - const b = 1234n; - await testCommutative(this.mock.$saturatingAdd, a, b, a + b); - await testCommutative(this.mock.$saturatingAdd, a, 0n, a); - await testCommutative(this.mock.$saturatingAdd, ethers.MaxUint256, 0n, ethers.MaxUint256); - }); - - it('bounds on addition overflow', async function () { - await testCommutative(this.mock.$saturatingAdd, ethers.MaxUint256, 1n, ethers.MaxUint256); - await expect(this.mock.$saturatingAdd(ethers.MaxUint256, ethers.MaxUint256)).to.eventually.equal( - ethers.MaxUint256, - ); - }); - }); - - describe('saturatingSub', function () { - it('subtracts correctly', async function () { - const a = 5678n; - const b = 1234n; - await expect(this.mock.$saturatingSub(a, b)).to.eventually.equal(a - b); - await expect(this.mock.$saturatingSub(a, a)).to.eventually.equal(0n); - await expect(this.mock.$saturatingSub(a, 0n)).to.eventually.equal(a); - await expect(this.mock.$saturatingSub(0n, a)).to.eventually.equal(0n); - await expect(this.mock.$saturatingSub(ethers.MaxUint256, 1n)).to.eventually.equal(ethers.MaxUint256 - 1n); - }); - - it('bounds on subtraction overflow', async function () { - await expect(this.mock.$saturatingSub(0n, 1n)).to.eventually.equal(0n); - await expect(this.mock.$saturatingSub(1n, 2n)).to.eventually.equal(0n); - await expect(this.mock.$saturatingSub(1n, ethers.MaxUint256)).to.eventually.equal(0n); - await expect(this.mock.$saturatingSub(ethers.MaxUint256 - 1n, ethers.MaxUint256)).to.eventually.equal(0n); - }); - }); - - describe('saturatingMul', function () { - it('multiplies correctly', async function () { - const a = 1234n; - const b = 5678n; - await testCommutative(this.mock.$saturatingMul, a, b, a * b); - }); - - it('multiplies by zero correctly', async function () { - const a = 0n; - const b = 5678n; - await testCommutative(this.mock.$saturatingMul, a, b, 0n); - }); - - it('bounds on multiplication overflow', async function () { - const a = ethers.MaxUint256; - const b = 2n; - await testCommutative(this.mock.$saturatingMul, a, b, ethers.MaxUint256); - }); - }); - - describe('max', function () { - it('is correctly detected in both position', async function () { - await testCommutative(this.mock.$max, 1234n, 5678n, max(1234n, 5678n)); - }); - }); - - describe('min', function () { - it('is correctly detected in both position', async function () { - await testCommutative(this.mock.$min, 1234n, 5678n, min(1234n, 5678n)); - }); - }); - - describe('average', function () { - it('is correctly calculated with two odd numbers', async function () { - const a = 57417n; - const b = 95431n; - await expect(this.mock.$average(a, b)).to.eventually.equal((a + b) / 2n); - }); - - it('is correctly calculated with two even numbers', async function () { - const a = 42304n; - const b = 84346n; - await expect(this.mock.$average(a, b)).to.eventually.equal((a + b) / 2n); - }); - - it('is correctly calculated with one even and one odd number', async function () { - const a = 57417n; - const b = 84346n; - await expect(this.mock.$average(a, b)).to.eventually.equal((a + b) / 2n); - }); - - it('is correctly calculated with two max uint256 numbers', async function () { - const a = ethers.MaxUint256; - await expect(this.mock.$average(a, a)).to.eventually.equal(a); - }); - }); - - describe('ceilDiv', function () { - it('reverts on zero division', async function () { - const a = 2n; - const b = 0n; - // It's unspecified because it's a low level 0 division error - await expect(this.mock.$ceilDiv(a, b)).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO); - }); - - it('does not round up a zero result', async function () { - const a = 0n; - const b = 2n; - const r = 0n; - await expect(this.mock.$ceilDiv(a, b)).to.eventually.equal(r); - }); - - it('does not round up on exact division', async function () { - const a = 10n; - const b = 5n; - const r = 2n; - await expect(this.mock.$ceilDiv(a, b)).to.eventually.equal(r); - }); - - it('rounds up on division with remainders', async function () { - const a = 42n; - const b = 13n; - const r = 4n; - await expect(this.mock.$ceilDiv(a, b)).to.eventually.equal(r); - }); - - it('does not overflow', async function () { - const a = ethers.MaxUint256; - const b = 2n; - const r = 1n << 255n; - await expect(this.mock.$ceilDiv(a, b)).to.eventually.equal(r); - }); - - it('correctly computes max uint256 divided by 1', async function () { - const a = ethers.MaxUint256; - const b = 1n; - const r = ethers.MaxUint256; - await expect(this.mock.$ceilDiv(a, b)).to.eventually.equal(r); - }); - }); - - describe('mulDiv', function () { - it('divide by 0', async function () { - const a = 1n; - const b = 1n; - const c = 0n; - await expect(this.mock.$mulDiv(a, b, c, Rounding.Floor)).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO); - }); - - it('reverts with result higher than 2 ^ 256', async function () { - const a = 5n; - const b = ethers.MaxUint256; - const c = 2n; - await expect(this.mock.$mulDiv(a, b, c, Rounding.Floor)).to.be.revertedWithPanic( - PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW, - ); - }); - - describe('does round down', function () { - it('small values', async function () { - for (const rounding of RoundingDown) { - await expect(this.mock.$mulDiv(3n, 4n, 5n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$mulDiv(3n, 5n, 5n, rounding)).to.eventually.equal(3n); - } - }); - - it('large values', async function () { - for (const rounding of RoundingDown) { - await expect(this.mock.$mulDiv(42n, ethers.MaxUint256 - 1n, ethers.MaxUint256, rounding)).to.eventually.equal( - 41n, - ); - - await expect(this.mock.$mulDiv(17n, ethers.MaxUint256, ethers.MaxUint256, rounding)).to.eventually.equal(17n); - - await expect( - this.mock.$mulDiv(ethers.MaxUint256 - 1n, ethers.MaxUint256 - 1n, ethers.MaxUint256, rounding), - ).to.eventually.equal(ethers.MaxUint256 - 2n); - - await expect( - this.mock.$mulDiv(ethers.MaxUint256, ethers.MaxUint256 - 1n, ethers.MaxUint256, rounding), - ).to.eventually.equal(ethers.MaxUint256 - 1n); - - await expect( - this.mock.$mulDiv(ethers.MaxUint256, ethers.MaxUint256, ethers.MaxUint256, rounding), - ).to.eventually.equal(ethers.MaxUint256); - } - }); - }); - - describe('does round up', function () { - it('small values', async function () { - for (const rounding of RoundingUp) { - await expect(this.mock.$mulDiv(3n, 4n, 5n, rounding)).to.eventually.equal(3n); - await expect(this.mock.$mulDiv(3n, 5n, 5n, rounding)).to.eventually.equal(3n); - } - }); - - it('large values', async function () { - for (const rounding of RoundingUp) { - await expect(this.mock.$mulDiv(42n, ethers.MaxUint256 - 1n, ethers.MaxUint256, rounding)).to.eventually.equal( - 42n, - ); - - await expect(this.mock.$mulDiv(17n, ethers.MaxUint256, ethers.MaxUint256, rounding)).to.eventually.equal(17n); - - await expect( - this.mock.$mulDiv(ethers.MaxUint256 - 1n, ethers.MaxUint256 - 1n, ethers.MaxUint256, rounding), - ).to.eventually.equal(ethers.MaxUint256 - 1n); - - await expect( - this.mock.$mulDiv(ethers.MaxUint256, ethers.MaxUint256 - 1n, ethers.MaxUint256, rounding), - ).to.eventually.equal(ethers.MaxUint256 - 1n); - - await expect( - this.mock.$mulDiv(ethers.MaxUint256, ethers.MaxUint256, ethers.MaxUint256, rounding), - ).to.eventually.equal(ethers.MaxUint256); - } - }); - }); - }); - - describe('mulShr', function () { - it('reverts with result higher than 2 ^ 256', async function () { - const a = 5n; - const b = ethers.MaxUint256; - const c = 1n; - await expect(this.mock.$mulShr(a, b, c, Rounding.Floor)).to.be.revertedWithPanic( - PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW, - ); - }); - - describe('does round down', function () { - it('small values', async function () { - for (const rounding of RoundingDown) { - await expect(this.mock.$mulShr(3n, 5n, 1n, rounding)).to.eventually.equal(7n); - await expect(this.mock.$mulShr(3n, 5n, 2n, rounding)).to.eventually.equal(3n); - } - }); - - it('large values', async function () { - for (const rounding of RoundingDown) { - await expect(this.mock.$mulShr(42n, ethers.MaxUint256, 255n, rounding)).to.eventually.equal(83n); - - await expect(this.mock.$mulShr(17n, ethers.MaxUint256, 255n, rounding)).to.eventually.equal(33n); - - await expect(this.mock.$mulShr(ethers.MaxUint256, ethers.MaxInt256 + 1n, 255n, rounding)).to.eventually.equal( - ethers.MaxUint256, - ); - - await expect(this.mock.$mulShr(ethers.MaxUint256, ethers.MaxInt256, 255n, rounding)).to.eventually.equal( - ethers.MaxUint256 - 2n, - ); - } - }); - }); - - describe('does round up', function () { - it('small values', async function () { - for (const rounding of RoundingUp) { - await expect(this.mock.$mulShr(3n, 5n, 1n, rounding)).to.eventually.equal(8n); - await expect(this.mock.$mulShr(3n, 5n, 2n, rounding)).to.eventually.equal(4n); - } - }); - - it('large values', async function () { - for (const rounding of RoundingUp) { - await expect(this.mock.$mulShr(42n, ethers.MaxUint256, 255n, rounding)).to.eventually.equal(84n); - - await expect(this.mock.$mulShr(17n, ethers.MaxUint256, 255n, rounding)).to.eventually.equal(34n); - - await expect(this.mock.$mulShr(ethers.MaxUint256, ethers.MaxInt256 + 1n, 255n, rounding)).to.eventually.equal( - ethers.MaxUint256, - ); - - await expect(this.mock.$mulShr(ethers.MaxUint256, ethers.MaxInt256, 255n, rounding)).to.eventually.equal( - ethers.MaxUint256 - 1n, - ); - } - }); - }); - }); - - describe('invMod', function () { - for (const factors of [ - [0n], - [1n], - [2n], - [17n], - [65537n], - [0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffn], - [3n, 5n], - [3n, 7n], - [47n, 53n], - ]) { - const p = factors.reduce((acc, f) => acc * f, 1n); - - describe(`using p=${p} which is ${p > 1 && factors.length > 1 ? 'not ' : ''}a prime`, function () { - it('trying to inverse 0 returns 0', async function () { - await expect(this.mock.$invMod(0, p)).to.eventually.equal(0n); - await expect(this.mock.$invMod(p, p)).to.eventually.equal(0n); // p is 0 mod p - }); - - if (p != 0) { - for (const value of Array.from({ length: 16 }, generators.uint256)) { - const isInversible = factors.every(f => value % f); - it(`trying to inverse ${value}`, async function () { - const result = await this.mock.$invMod(value, p); - if (isInversible) { - expect((value * result) % p).to.equal(1n); - } else { - expect(result).to.equal(0n); - } - }); - } - } - }); - } - }); - - describe('modExp', function () { - for (const [name, type] of Object.entries({ uint256, bytes })) { - describe(`with ${name} inputs`, function () { - it('is correctly calculating modulus', async function () { - const b = 3n; - const e = 200n; - const m = 50n; - - await expect(this.mock.$modExp(type(b), type(e), type(m))).to.eventually.equal(type(b ** e % m).value); - }); - - it('is correctly reverting when modulus is zero', async function () { - const b = 3n; - const e = 200n; - const m = 0n; - - await expect(this.mock.$modExp(type(b), type(e), type(m))).to.be.revertedWithPanic( - PANIC_CODES.DIVISION_BY_ZERO, - ); - }); - }); - } - - describe('with large bytes inputs', function () { - for (const [[b, log2b], [e, log2e], [m, log2m]] of product( - range(320, 512, 64).map(e => [2n ** BigInt(e) + 1n, e]), - range(320, 512, 64).map(e => [2n ** BigInt(e) + 1n, e]), - range(320, 512, 64).map(e => [2n ** BigInt(e) + 1n, e]), - )) { - it(`calculates b ** e % m (b=2**${log2b}+1) (e=2**${log2e}+1) (m=2**${log2m}+1)`, async function () { - const mLength = ethers.dataLength(ethers.toBeHex(m)); - - await expect(this.mock.$modExp(bytes(b), bytes(e), bytes(m))).to.eventually.equal( - bytes(modExp(b, e, m), mLength).value, - ); - }); - } - }); - }); - - describe('tryModExp', function () { - for (const [name, type] of Object.entries({ uint256, bytes })) { - describe(`with ${name} inputs`, function () { - it('is correctly calculating modulus', async function () { - const b = 3n; - const e = 200n; - const m = 50n; - - await expect(this.mock.$tryModExp(type(b), type(e), type(m))).to.eventually.deep.equal([ - true, - type(b ** e % m).value, - ]); - }); - - it('is correctly reverting when modulus is zero', async function () { - const b = 3n; - const e = 200n; - const m = 0n; - - await expect(this.mock.$tryModExp(type(b), type(e), type(m))).to.eventually.deep.equal([false, type.zero]); - }); - }); - } - - describe('with large bytes inputs', function () { - for (const [[b, log2b], [e, log2e], [m, log2m]] of product( - range(320, 513, 64).map(e => [2n ** BigInt(e) + 1n, e]), - range(320, 513, 64).map(e => [2n ** BigInt(e) + 1n, e]), - range(320, 513, 64).map(e => [2n ** BigInt(e) + 1n, e]), - )) { - it(`calculates b ** e % m (b=2**${log2b}+1) (e=2**${log2e}+1) (m=2**${log2m}+1)`, async function () { - const mLength = ethers.dataLength(ethers.toBeHex(m)); - - await expect(this.mock.$tryModExp(bytes(b), bytes(e), bytes(m))).to.eventually.deep.equal([ - true, - bytes(modExp(b, e, m), mLength).value, - ]); - }); - } - }); - }); - - describe('sqrt', function () { - it('rounds down', async function () { - for (const rounding of RoundingDown) { - await expect(this.mock.$sqrt(0n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$sqrt(1n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$sqrt(2n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$sqrt(3n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$sqrt(4n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$sqrt(144n, rounding)).to.eventually.equal(12n); - await expect(this.mock.$sqrt(999999n, rounding)).to.eventually.equal(999n); - await expect(this.mock.$sqrt(1000000n, rounding)).to.eventually.equal(1000n); - await expect(this.mock.$sqrt(1000001n, rounding)).to.eventually.equal(1000n); - await expect(this.mock.$sqrt(1002000n, rounding)).to.eventually.equal(1000n); - await expect(this.mock.$sqrt(1002001n, rounding)).to.eventually.equal(1001n); - await expect(this.mock.$sqrt(ethers.MaxUint256, rounding)).to.eventually.equal( - 340282366920938463463374607431768211455n, - ); - } - }); - - it('rounds up', async function () { - for (const rounding of RoundingUp) { - await expect(this.mock.$sqrt(0n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$sqrt(1n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$sqrt(2n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$sqrt(3n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$sqrt(4n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$sqrt(144n, rounding)).to.eventually.equal(12n); - await expect(this.mock.$sqrt(999999n, rounding)).to.eventually.equal(1000n); - await expect(this.mock.$sqrt(1000000n, rounding)).to.eventually.equal(1000n); - await expect(this.mock.$sqrt(1000001n, rounding)).to.eventually.equal(1001n); - await expect(this.mock.$sqrt(1002000n, rounding)).to.eventually.equal(1001n); - await expect(this.mock.$sqrt(1002001n, rounding)).to.eventually.equal(1001n); - await expect(this.mock.$sqrt(ethers.MaxUint256, rounding)).to.eventually.equal( - 340282366920938463463374607431768211456n, - ); - } - }); - }); - - describe('log', function () { - describe('log2', function () { - it('rounds down', async function () { - for (const rounding of RoundingDown) { - await expect(this.mock.$log2(0n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log2(1n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log2(2n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log2(3n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log2(4n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log2(5n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log2(6n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log2(7n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log2(8n, rounding)).to.eventually.equal(3n); - await expect(this.mock.$log2(9n, rounding)).to.eventually.equal(3n); - await expect(this.mock.$log2(ethers.MaxUint256, rounding)).to.eventually.equal(255n); - } - }); - - it('rounds up', async function () { - for (const rounding of RoundingUp) { - await expect(this.mock.$log2(0n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log2(1n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log2(2n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log2(3n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log2(4n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log2(5n, rounding)).to.eventually.equal(3n); - await expect(this.mock.$log2(6n, rounding)).to.eventually.equal(3n); - await expect(this.mock.$log2(7n, rounding)).to.eventually.equal(3n); - await expect(this.mock.$log2(8n, rounding)).to.eventually.equal(3n); - await expect(this.mock.$log2(9n, rounding)).to.eventually.equal(4n); - await expect(this.mock.$log2(ethers.MaxUint256, rounding)).to.eventually.equal(256n); - } - }); - }); - - describe('log10', function () { - it('rounds down', async function () { - for (const rounding of RoundingDown) { - await expect(this.mock.$log10(0n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log10(1n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log10(2n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log10(9n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log10(10n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log10(11n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log10(99n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log10(100n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log10(101n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log10(999n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log10(1000n, rounding)).to.eventually.equal(3n); - await expect(this.mock.$log10(1001n, rounding)).to.eventually.equal(3n); - await expect(this.mock.$log10(ethers.MaxUint256, rounding)).to.eventually.equal(77n); - } - }); - - it('rounds up', async function () { - for (const rounding of RoundingUp) { - await expect(this.mock.$log10(0n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log10(1n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log10(2n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log10(9n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log10(10n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log10(11n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log10(99n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log10(100n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log10(101n, rounding)).to.eventually.equal(3n); - await expect(this.mock.$log10(999n, rounding)).to.eventually.equal(3n); - await expect(this.mock.$log10(1000n, rounding)).to.eventually.equal(3n); - await expect(this.mock.$log10(1001n, rounding)).to.eventually.equal(4n); - await expect(this.mock.$log10(ethers.MaxUint256, rounding)).to.eventually.equal(78n); - } - }); - }); - - describe('log256', function () { - it('rounds down', async function () { - for (const rounding of RoundingDown) { - await expect(this.mock.$log256(0n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log256(1n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log256(2n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log256(255n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log256(256n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log256(257n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log256(65535n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log256(65536n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log256(65537n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log256(ethers.MaxUint256, rounding)).to.eventually.equal(31n); - } - }); - - it('rounds up', async function () { - for (const rounding of RoundingUp) { - await expect(this.mock.$log256(0n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log256(1n, rounding)).to.eventually.equal(0n); - await expect(this.mock.$log256(2n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log256(255n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log256(256n, rounding)).to.eventually.equal(1n); - await expect(this.mock.$log256(257n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log256(65535n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log256(65536n, rounding)).to.eventually.equal(2n); - await expect(this.mock.$log256(65537n, rounding)).to.eventually.equal(3n); - await expect(this.mock.$log256(ethers.MaxUint256, rounding)).to.eventually.equal(32n); - } - }); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js deleted file mode 100644 index ab62406..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js +++ /dev/null @@ -1,159 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { range } = require('../../helpers/iterate'); - -async function fixture() { - const mock = await ethers.deployContract('$SafeCast'); - return { mock }; -} - -describe('SafeCast', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - for (const bits of range(8, 256, 8).map(ethers.toBigInt)) { - const maxValue = 2n ** bits - 1n; - - describe(`toUint${bits}`, () => { - it('downcasts 0', async function () { - expect(await this.mock[`$toUint${bits}`](0n)).is.equal(0n); - }); - - it('downcasts 1', async function () { - expect(await this.mock[`$toUint${bits}`](1n)).is.equal(1n); - }); - - it(`downcasts 2^${bits} - 1 (${maxValue})`, async function () { - expect(await this.mock[`$toUint${bits}`](maxValue)).is.equal(maxValue); - }); - - it(`reverts when downcasting 2^${bits} (${maxValue + 1n})`, async function () { - await expect(this.mock[`$toUint${bits}`](maxValue + 1n)) - .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintDowncast') - .withArgs(bits, maxValue + 1n); - }); - - it(`reverts when downcasting 2^${bits} + 1 (${maxValue + 2n})`, async function () { - await expect(this.mock[`$toUint${bits}`](maxValue + 2n)) - .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintDowncast') - .withArgs(bits, maxValue + 2n); - }); - }); - } - - describe('toUint256', () => { - it('casts 0', async function () { - expect(await this.mock.$toUint256(0n)).is.equal(0n); - }); - - it('casts 1', async function () { - expect(await this.mock.$toUint256(1n)).is.equal(1n); - }); - - it(`casts INT256_MAX (${ethers.MaxInt256})`, async function () { - expect(await this.mock.$toUint256(ethers.MaxInt256)).is.equal(ethers.MaxInt256); - }); - - it('reverts when casting -1', async function () { - await expect(this.mock.$toUint256(-1n)) - .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntToUint') - .withArgs(-1n); - }); - - it(`reverts when casting INT256_MIN (${ethers.MinInt256})`, async function () { - await expect(this.mock.$toUint256(ethers.MinInt256)) - .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntToUint') - .withArgs(ethers.MinInt256); - }); - }); - - for (const bits of range(8, 256, 8).map(ethers.toBigInt)) { - const minValue = -(2n ** (bits - 1n)); - const maxValue = 2n ** (bits - 1n) - 1n; - - describe(`toInt${bits}`, () => { - it('downcasts 0', async function () { - expect(await this.mock[`$toInt${bits}`](0n)).is.equal(0n); - }); - - it('downcasts 1', async function () { - expect(await this.mock[`$toInt${bits}`](1n)).is.equal(1n); - }); - - it('downcasts -1', async function () { - expect(await this.mock[`$toInt${bits}`](-1n)).is.equal(-1n); - }); - - it(`downcasts -2^${bits - 1n} (${minValue})`, async function () { - expect(await this.mock[`$toInt${bits}`](minValue)).is.equal(minValue); - }); - - it(`downcasts 2^${bits - 1n} - 1 (${maxValue})`, async function () { - expect(await this.mock[`$toInt${bits}`](maxValue)).is.equal(maxValue); - }); - - it(`reverts when downcasting -2^${bits - 1n} - 1 (${minValue - 1n})`, async function () { - await expect(this.mock[`$toInt${bits}`](minValue - 1n)) - .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast') - .withArgs(bits, minValue - 1n); - }); - - it(`reverts when downcasting -2^${bits - 1n} - 2 (${minValue - 2n})`, async function () { - await expect(this.mock[`$toInt${bits}`](minValue - 2n)) - .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast') - .withArgs(bits, minValue - 2n); - }); - - it(`reverts when downcasting 2^${bits - 1n} (${maxValue + 1n})`, async function () { - await expect(this.mock[`$toInt${bits}`](maxValue + 1n)) - .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast') - .withArgs(bits, maxValue + 1n); - }); - - it(`reverts when downcasting 2^${bits - 1n} + 1 (${maxValue + 2n})`, async function () { - await expect(this.mock[`$toInt${bits}`](maxValue + 2n)) - .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast') - .withArgs(bits, maxValue + 2n); - }); - }); - } - - describe('toInt256', () => { - it('casts 0', async function () { - expect(await this.mock.$toInt256(0)).is.equal(0n); - }); - - it('casts 1', async function () { - expect(await this.mock.$toInt256(1)).is.equal(1n); - }); - - it(`casts INT256_MAX (${ethers.MaxInt256})`, async function () { - expect(await this.mock.$toInt256(ethers.MaxInt256)).is.equal(ethers.MaxInt256); - }); - - it(`reverts when casting INT256_MAX + 1 (${ethers.MaxInt256 + 1n})`, async function () { - await expect(this.mock.$toInt256(ethers.MaxInt256 + 1n)) - .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintToInt') - .withArgs(ethers.MaxInt256 + 1n); - }); - - it(`reverts when casting UINT256_MAX (${ethers.MaxUint256})`, async function () { - await expect(this.mock.$toInt256(ethers.MaxUint256)) - .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintToInt') - .withArgs(ethers.MaxUint256); - }); - }); - - describe('toUint (bool)', function () { - it('toUint(false) should be 0', async function () { - expect(await this.mock.$toUint(false)).to.equal(0n); - }); - - it('toUint(true) should be 1', async function () { - expect(await this.mock.$toUint(true)).to.equal(1n); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.t.sol deleted file mode 100644 index 98a40a1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.t.sol +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import {Test} from "forge-std/Test.sol"; - -import {Math} from "../../../contracts/utils/math/Math.sol"; -import {SignedMath} from "../../../contracts/utils/math/SignedMath.sol"; - -contract SignedMathTest is Test { - function testSymbolicTernary(bool f, int256 a, int256 b) public pure { - assertEq(SignedMath.ternary(f, a, b), f ? a : b); - } - - // MIN & MAX - function testSymbolicMinMax(int256 a, int256 b) public pure { - assertEq(SignedMath.min(a, b), a < b ? a : b); - assertEq(SignedMath.max(a, b), a > b ? a : b); - } - - // MIN - function testSymbolicMin(int256 a, int256 b) public pure { - int256 result = SignedMath.min(a, b); - - assertLe(result, a); - assertLe(result, b); - assertTrue(result == a || result == b); - } - - // MAX - function testSymbolicMax(int256 a, int256 b) public pure { - int256 result = SignedMath.max(a, b); - - assertGe(result, a); - assertGe(result, b); - assertTrue(result == a || result == b); - } - - // AVERAGE - // 1. simple test, not full int256 range - function testAverage1(int256 a, int256 b) public pure { - a = bound(a, type(int256).min / 2, type(int256).max / 2); - b = bound(b, type(int256).min / 2, type(int256).max / 2); - - int256 result = SignedMath.average(a, b); - - assertEq(result, (a + b) / 2); - } - - // 2. more complex test, full int256 range - function testAverage2(int256 a, int256 b) public pure { - (int256 result, int256 min, int256 max) = ( - SignedMath.average(a, b), - SignedMath.min(a, b), - SignedMath.max(a, b) - ); - - // average must be between `a` and `b` - assertGe(result, min); - assertLe(result, max); - - unchecked { - // must be unchecked in order to support `a = type(int256).min, b = type(int256).max` - uint256 deltaLower = uint256(result - min); - uint256 deltaUpper = uint256(max - result); - uint256 remainder = uint256((a & 1) ^ (b & 1)); - assertEq(remainder, Math.max(deltaLower, deltaUpper) - Math.min(deltaLower, deltaUpper)); - } - } - - // ABS - function testSymbolicAbs(int256 a) public pure { - uint256 result = SignedMath.abs(a); - - unchecked { - // must be unchecked in order to support `n = type(int256).min` - assertEq(result, a < 0 ? uint256(-a) : uint256(a)); - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js deleted file mode 100644 index 877f3b4..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js +++ /dev/null @@ -1,53 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { min, max } = require('../../helpers/math'); - -async function testCommutative(fn, lhs, rhs, expected, ...extra) { - expect(await fn(lhs, rhs, ...extra)).to.deep.equal(expected); - expect(await fn(rhs, lhs, ...extra)).to.deep.equal(expected); -} - -async function fixture() { - const mock = await ethers.deployContract('$SignedMath'); - return { mock }; -} - -describe('SignedMath', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('max', function () { - it('is correctly detected in both position', async function () { - await testCommutative(this.mock.$max, -1234n, 5678n, max(-1234n, 5678n)); - }); - }); - - describe('min', function () { - it('is correctly detected in both position', async function () { - await testCommutative(this.mock.$min, -1234n, 5678n, min(-1234n, 5678n)); - }); - }); - - describe('average', function () { - it('is correctly calculated with various input', async function () { - for (const x of [ethers.MinInt256, -57417n, -42304n, -4n, -3n, 0n, 3n, 4n, 42304n, 57417n, ethers.MaxInt256]) { - for (const y of [ethers.MinInt256, -57417n, -42304n, -5n, -2n, 0n, 2n, 5n, 42304n, 57417n, ethers.MaxInt256]) { - expect(await this.mock.$average(x, y)).to.equal((x + y) / 2n); - } - } - }); - }); - - describe('abs', function () { - const abs = x => (x < 0n ? -x : x); - - for (const n of [ethers.MinInt256, ethers.MinInt256 + 1n, -1n, 0n, 1n, ethers.MaxInt256 - 1n, ethers.MaxInt256]) { - it(`correctly computes the absolute value of ${n}`, async function () { - expect(await this.mock.$abs(n)).to.equal(abs(n)); - }); - } - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js deleted file mode 100644 index 5662ab1..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js +++ /dev/null @@ -1,149 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -async function fixture() { - const bitmap = await ethers.deployContract('$BitMaps'); - return { bitmap }; -} - -describe('BitMap', function () { - const keyA = 7891n; - const keyB = 451n; - const keyC = 9592328n; - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('starts empty', async function () { - expect(await this.bitmap.$get(0, keyA)).to.be.false; - expect(await this.bitmap.$get(0, keyB)).to.be.false; - expect(await this.bitmap.$get(0, keyC)).to.be.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.be.true; - expect(await this.bitmap.$get(0, keyB)).to.be.false; - expect(await this.bitmap.$get(0, keyC)).to.be.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.be.false; - expect(await this.bitmap.$get(0, keyB)).to.be.false; - expect(await this.bitmap.$get(0, keyC)).to.be.false; - }); - - it('set several consecutive keys', async function () { - await this.bitmap.$setTo(0, keyA + 0n, true); - await this.bitmap.$setTo(0, keyA + 1n, true); - await this.bitmap.$setTo(0, keyA + 2n, true); - await this.bitmap.$setTo(0, keyA + 3n, true); - await this.bitmap.$setTo(0, keyA + 4n, true); - await this.bitmap.$setTo(0, keyA + 2n, false); - await this.bitmap.$setTo(0, keyA + 4n, false); - expect(await this.bitmap.$get(0, keyA + 0n)).to.be.true; - expect(await this.bitmap.$get(0, keyA + 1n)).to.be.true; - expect(await this.bitmap.$get(0, keyA + 2n)).to.be.false; - expect(await this.bitmap.$get(0, keyA + 3n)).to.be.true; - expect(await this.bitmap.$get(0, keyA + 4n)).to.be.false; - }); - }); - - describe('set', function () { - it('adds a key', async function () { - await this.bitmap.$set(0, keyA); - expect(await this.bitmap.$get(0, keyA)).to.be.true; - expect(await this.bitmap.$get(0, keyB)).to.be.false; - expect(await this.bitmap.$get(0, keyC)).to.be.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.be.true; - expect(await this.bitmap.$get(0, keyB)).to.be.true; - expect(await this.bitmap.$get(0, keyC)).to.be.false; - }); - - it('adds several consecutive keys', async function () { - await this.bitmap.$set(0, keyA + 0n); - await this.bitmap.$set(0, keyA + 1n); - await this.bitmap.$set(0, keyA + 3n); - expect(await this.bitmap.$get(0, keyA + 0n)).to.be.true; - expect(await this.bitmap.$get(0, keyA + 1n)).to.be.true; - expect(await this.bitmap.$get(0, keyA + 2n)).to.be.false; - expect(await this.bitmap.$get(0, keyA + 3n)).to.be.true; - expect(await this.bitmap.$get(0, keyA + 4n)).to.be.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.be.false; - expect(await this.bitmap.$get(0, keyB)).to.be.true; - expect(await this.bitmap.$get(0, keyC)).to.be.false; - }); - - it('removes consecutive added keys', async function () { - await this.bitmap.$set(0, keyA + 0n); - await this.bitmap.$set(0, keyA + 1n); - await this.bitmap.$set(0, keyA + 3n); - await this.bitmap.$unset(0, keyA + 1n); - expect(await this.bitmap.$get(0, keyA + 0n)).to.be.true; - expect(await this.bitmap.$get(0, keyA + 1n)).to.be.false; - expect(await this.bitmap.$get(0, keyA + 2n)).to.be.false; - expect(await this.bitmap.$get(0, keyA + 3n)).to.be.true; - expect(await this.bitmap.$get(0, keyA + 4n)).to.be.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.be.true; - expect(await this.bitmap.$get(0, keyB)).to.be.false; - expect(await this.bitmap.$get(0, keyC)).to.be.true; - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.t.sol deleted file mode 100644 index 74d8fb8..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.t.sol +++ /dev/null @@ -1,332 +0,0 @@ -// 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 "@openzeppelin/contracts/utils/math/SafeCast.sol"; -import {Checkpoints} from "@openzeppelin/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 will 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 pure returns (uint32) { - return SafeCast.toUint32(bound(uint256(x), uint256(min), uint256(max))); - } - - function _prepareKeys(uint32[] memory keys, uint32 maxSpread) internal pure { - 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 view { - (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 will 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 pure returns (uint48) { - return SafeCast.toUint48(bound(uint256(x), uint256(min), uint256(max))); - } - - function _prepareKeys(uint48[] memory keys, uint48 maxSpread) internal pure { - 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 view { - (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 will 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 pure returns (uint96) { - return SafeCast.toUint96(bound(uint256(x), uint256(min), uint256(max))); - } - - function _prepareKeys(uint96[] memory keys, uint96 maxSpread) internal pure { - 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 view { - (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/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.test.js deleted file mode 100644 index fd22544..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.test.js +++ /dev/null @@ -1,146 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { VALUE_SIZES } = require('../../../scripts/generate/templates/Checkpoints.opts'); - -describe('Checkpoints', function () { - for (const length of VALUE_SIZES) { - describe(`Trace${length}`, function () { - const fixture = async () => { - const mock = await ethers.deployContract('$Checkpoints'); - const methods = { - at: (...args) => mock.getFunction(`$at_Checkpoints_Trace${length}`)(0, ...args), - latest: (...args) => mock.getFunction(`$latest_Checkpoints_Trace${length}`)(0, ...args), - latestCheckpoint: (...args) => mock.getFunction(`$latestCheckpoint_Checkpoints_Trace${length}`)(0, ...args), - length: (...args) => mock.getFunction(`$length_Checkpoints_Trace${length}`)(0, ...args), - push: (...args) => mock.getFunction(`$push(uint256,uint${256 - length},uint${length})`)(0, ...args), - lowerLookup: (...args) => mock.getFunction(`$lowerLookup(uint256,uint${256 - length})`)(0, ...args), - upperLookup: (...args) => mock.getFunction(`$upperLookup(uint256,uint${256 - length})`)(0, ...args), - upperLookupRecent: (...args) => - mock.getFunction(`$upperLookupRecent(uint256,uint${256 - length})`)(0, ...args), - }; - - return { mock, methods }; - }; - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('without checkpoints', function () { - it('at zero reverts', async function () { - // Reverts with array out of bound access, which is unspecified - await expect(this.methods.at(0)).to.be.reverted; - }); - - it('returns zero as latest value', async function () { - expect(await this.methods.latest()).to.equal(0n); - - const ckpt = await this.methods.latestCheckpoint(); - expect(ckpt[0]).to.be.false; - expect(ckpt[1]).to.equal(0n); - expect(ckpt[2]).to.equal(0n); - }); - - it('lookup returns 0', async function () { - expect(await this.methods.lowerLookup(0)).to.equal(0n); - expect(await this.methods.upperLookup(0)).to.equal(0n); - expect(await this.methods.upperLookupRecent(0)).to.equal(0n); - }); - }); - - describe('with checkpoints', function () { - beforeEach('pushing checkpoints', async function () { - this.checkpoints = [ - { key: 2n, value: 17n }, - { key: 3n, value: 42n }, - { key: 5n, value: 101n }, - { key: 7n, value: 23n }, - { key: 11n, value: 99n }, - ]; - 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.equal(value); - expect(at._key).to.equal(key); - } - }); - - it('length', async function () { - expect(await this.methods.length()).to.equal(this.checkpoints.length); - }); - - it('returns latest value', async function () { - const latest = this.checkpoints.at(-1); - expect(await this.methods.latest()).to.equal(latest.value); - expect(await this.methods.latestCheckpoint()).to.deep.equal([true, latest.key, latest.value]); - }); - - it('cannot push values in the past', async function () { - await expect(this.methods.push(this.checkpoints.at(-1).key - 1n, 0n)).to.be.revertedWithCustomError( - this.mock, - 'CheckpointUnorderedInsertion', - ); - }); - - it('can update last value', async function () { - const newValue = 42n; - - // check length before the update - expect(await this.methods.length()).to.equal(this.checkpoints.length); - - // update last key - await this.methods.push(this.checkpoints.at(-1).key, newValue); - expect(await this.methods.latest()).to.equal(newValue); - - // check that length did not change - expect(await this.methods.length()).to.equal(this.checkpoints.length); - }); - - it('lower lookup', async function () { - for (let i = 0; i < 14; ++i) { - const value = this.checkpoints.find(x => i <= x.key)?.value || 0n; - - expect(await this.methods.lowerLookup(i)).to.equal(value); - } - }); - - it('upper lookup & upperLookupRecent', async function () { - for (let i = 0; i < 14; ++i) { - const value = this.checkpoints.findLast(x => i >= x.key)?.value || 0n; - - expect(await this.methods.upperLookup(i)).to.equal(value); - expect(await this.methods.upperLookupRecent(i)).to.equal(value); - } - }); - - it('upperLookupRecent with more than 5 checkpoints', async function () { - const moreCheckpoints = [ - { key: 12n, value: 22n }, - { key: 13n, value: 131n }, - { key: 17n, value: 45n }, - { key: 19n, value: 31452n }, - { key: 21n, value: 0n }, - ]; - 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 = allCheckpoints.findLast(x => i >= x.key)?.value || 0n; - expect(await this.methods.upperLookup(i)).to.equal(value); - expect(await this.methods.upperLookupRecent(i)).to.equal(value); - } - }); - }); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/CircularBuffer.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/CircularBuffer.test.js deleted file mode 100644 index e79ba69..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/CircularBuffer.test.js +++ /dev/null @@ -1,83 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -const { generators } = require('../../helpers/random'); - -const LENGTH = 4; - -async function fixture() { - const mock = await ethers.deployContract('$CircularBuffer'); - await mock.$setup(0, LENGTH); - return { mock }; -} - -describe('CircularBuffer', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('reverts on invalid setup', async function () { - await expect(this.mock.$setup(0, 0)).to.be.revertedWithCustomError(this.mock, 'InvalidBufferSize'); - }); - - it('starts empty', async function () { - expect(await this.mock.$count(0)).to.equal(0n); - expect(await this.mock.$length(0)).to.equal(LENGTH); - expect(await this.mock.$includes(0, ethers.ZeroHash)).to.be.false; - await expect(this.mock.$last(0, 0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); - }); - - it('push', async function () { - const values = Array.from({ length: LENGTH + 3 }, generators.bytes32); - - for (const [i, value] of values.map((v, i) => [i, v])) { - // push value - await this.mock.$push(0, value); - - // view of the values - const pushed = values.slice(0, i + 1); - const stored = pushed.slice(-LENGTH); - const dropped = pushed.slice(0, -LENGTH); - - // check count - expect(await this.mock.$length(0)).to.equal(LENGTH); - expect(await this.mock.$count(0)).to.equal(stored.length); - - // check last - for (const j in stored) { - expect(await this.mock.$last(0, j)).to.equal(stored.at(-j - 1)); - } - await expect(this.mock.$last(0, stored.length + 1)).to.be.revertedWithPanic( - PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS, - ); - - // check included and non-included values - for (const v of stored) { - expect(await this.mock.$includes(0, v)).to.be.true; - } - for (const v of dropped) { - expect(await this.mock.$includes(0, v)).to.be.false; - } - expect(await this.mock.$includes(0, ethers.ZeroHash)).to.be.false; - } - }); - - it('clear', async function () { - const value = generators.bytes32(); - await this.mock.$push(0, value); - - expect(await this.mock.$count(0)).to.equal(1n); - expect(await this.mock.$length(0)).to.equal(LENGTH); - expect(await this.mock.$includes(0, value)).to.be.true; - await this.mock.$last(0, 0); // not revert - - await this.mock.$clear(0); - - expect(await this.mock.$count(0)).to.equal(0n); - expect(await this.mock.$length(0)).to.equal(LENGTH); - expect(await this.mock.$includes(0, value)).to.be.false; - await expect(this.mock.$last(0, 0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js deleted file mode 100644 index 3615dfb..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js +++ /dev/null @@ -1,102 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -async function fixture() { - const mock = await ethers.deployContract('$DoubleEndedQueue'); - - /** Rebuild the content of the deque as a JS array. */ - const getContent = () => - mock.$length(0).then(length => Promise.all(Array.from({ length: Number(length) }, (_, i) => mock.$at(0, i)))); - - return { mock, getContent }; -} - -describe('DoubleEndedQueue', function () { - const coder = ethers.AbiCoder.defaultAbiCoder(); - const bytesA = coder.encode(['uint256'], [0xdeadbeef]); - const bytesB = coder.encode(['uint256'], [0x0123456789]); - const bytesC = coder.encode(['uint256'], [0x42424242]); - const bytesD = coder.encode(['uint256'], [0x171717]); - - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('when empty', function () { - it('getters', async function () { - expect(await this.mock.$empty(0)).to.be.true; - expect(await this.getContent()).to.have.ordered.members([]); - }); - - it('reverts on accesses', async function () { - await expect(this.mock.$popBack(0)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY); - await expect(this.mock.$popFront(0)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY); - await expect(this.mock.$back(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); - await expect(this.mock.$front(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); - }); - }); - - describe('when not empty', function () { - beforeEach(async function () { - await this.mock.$pushBack(0, bytesB); - await this.mock.$pushFront(0, bytesA); - await this.mock.$pushBack(0, bytesC); - this.content = [bytesA, bytesB, bytesC]; - }); - - it('getters', async function () { - expect(await this.mock.$empty(0)).to.be.false; - expect(await this.mock.$length(0)).to.equal(this.content.length); - expect(await this.mock.$front(0)).to.equal(this.content[0]); - expect(await this.mock.$back(0)).to.equal(this.content[this.content.length - 1]); - expect(await this.getContent()).to.have.ordered.members(this.content); - }); - - it('out of bounds access', async function () { - await expect(this.mock.$at(0, this.content.length)).to.be.revertedWithPanic( - PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS, - ); - }); - - describe('push', function () { - it('front', async function () { - await this.mock.$pushFront(0, bytesD); - this.content.unshift(bytesD); // add element at the beginning - - expect(await this.getContent()).to.have.ordered.members(this.content); - }); - - it('back', async function () { - await this.mock.$pushBack(0, bytesD); - this.content.push(bytesD); // add element at the end - - expect(await this.getContent()).to.have.ordered.members(this.content); - }); - }); - - describe('pop', function () { - it('front', async function () { - const value = this.content.shift(); // remove first element - await expect(this.mock.$popFront(0)).to.emit(this.mock, 'return$popFront').withArgs(value); - - expect(await this.getContent()).to.have.ordered.members(this.content); - }); - - it('back', async function () { - const value = this.content.pop(); // remove last element - await expect(this.mock.$popBack(0)).to.emit(this.mock, 'return$popBack').withArgs(value); - - expect(await this.getContent()).to.have.ordered.members(this.content); - }); - }); - - it('clear', async function () { - await this.mock.$clear(0); - - expect(await this.mock.$empty(0)).to.be.true; - expect(await this.getContent()).to.have.ordered.members([]); - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js deleted file mode 100644 index 4074b07..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js +++ /dev/null @@ -1,214 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); - -const zip = (array1, array2) => array1.map((item, index) => [item, array2[index]]); - -function shouldBehaveLikeMap() { - async function expectMembersMatch(methods, keys, values) { - expect(keys.length).to.equal(values.length); - expect(await methods.length()).to.equal(keys.length); - expect([...(await methods.keys())]).to.have.members(keys); - - for (const [key, value] of zip(keys, values)) { - expect(await methods.contains(key)).to.be.true; - expect(await methods.get(key)).to.equal(value); - } - - expect(await Promise.all(keys.map((_, index) => methods.at(index)))).to.have.deep.members(zip(keys, values)); - } - - it('starts empty', async function () { - expect(await this.methods.contains(this.keyA)).to.be.false; - - await expectMembersMatch(this.methods, [], []); - }); - - describe('set', function () { - it('adds a key', async function () { - await expect(this.methods.set(this.keyA, this.valueA)).to.emit(this.mock, this.events.setReturn).withArgs(true); - - await expectMembersMatch(this.methods, [this.keyA], [this.valueA]); - }); - - it('adds several keys', async function () { - await this.methods.set(this.keyA, this.valueA); - await this.methods.set(this.keyB, this.valueB); - - await expectMembersMatch(this.methods, [this.keyA, this.keyB], [this.valueA, this.valueB]); - expect(await this.methods.contains(this.keyC)).to.be.false; - }); - - it('returns false when adding keys already in the set', async function () { - await this.methods.set(this.keyA, this.valueA); - - await expect(this.methods.set(this.keyA, this.valueA)).to.emit(this.mock, this.events.setReturn).withArgs(false); - - await expectMembersMatch(this.methods, [this.keyA], [this.valueA]); - }); - - it('updates values for keys already in the set', async function () { - await this.methods.set(this.keyA, this.valueA); - await this.methods.set(this.keyA, this.valueB); - - await expectMembersMatch(this.methods, [this.keyA], [this.valueB]); - }); - }); - - describe('remove', function () { - it('removes added keys', async function () { - await this.methods.set(this.keyA, this.valueA); - - await expect(this.methods.remove(this.keyA)).to.emit(this.mock, this.events.removeReturn).withArgs(true); - - expect(await this.methods.contains(this.keyA)).to.be.false; - await expectMembersMatch(this.methods, [], []); - }); - - it('returns false when removing keys not in the set', async function () { - await expect(await this.methods.remove(this.keyA)) - .to.emit(this.mock, this.events.removeReturn) - .withArgs(false); - - expect(await this.methods.contains(this.keyA)).to.be.false; - }); - - it('adds and removes multiple keys', async function () { - // [] - - await this.methods.set(this.keyA, this.valueA); - await this.methods.set(this.keyC, this.valueC); - - // [A, C] - - await this.methods.remove(this.keyA); - await this.methods.remove(this.keyB); - - // [C] - - await this.methods.set(this.keyB, this.valueB); - - // [C, B] - - await this.methods.set(this.keyA, this.valueA); - await this.methods.remove(this.keyC); - - // [A, B] - - await this.methods.set(this.keyA, this.valueA); - await this.methods.set(this.keyB, this.valueB); - - // [A, B] - - await this.methods.set(this.keyC, this.valueC); - await this.methods.remove(this.keyA); - - // [B, C] - - await this.methods.set(this.keyA, this.valueA); - await this.methods.remove(this.keyB); - - // [A, C] - - await expectMembersMatch(this.methods, [this.keyA, this.keyC], [this.valueA, this.valueC]); - - expect(await this.methods.contains(this.keyA)).to.be.true; - expect(await this.methods.contains(this.keyB)).to.be.false; - expect(await this.methods.contains(this.keyC)).to.be.true; - }); - }); - - describe('clear', function () { - it('clears a single entry', async function () { - await this.methods.set(this.keyA, this.valueA); - - await this.methods.clear(); - - expect(await this.methods.contains(this.keyA)).to.be.false; - await expectMembersMatch(this.methods, [], []); - }); - - it('clears multiple entries', async function () { - await this.methods.set(this.keyA, this.valueA); - await this.methods.set(this.keyB, this.valueB); - await this.methods.set(this.keyC, this.valueC); - - await this.methods.clear(); - - expect(await this.methods.contains(this.keyA)).to.be.false; - expect(await this.methods.contains(this.keyB)).to.be.false; - expect(await this.methods.contains(this.keyC)).to.be.false; - await expectMembersMatch(this.methods, [], []); - }); - - it('does not revert on empty map', async function () { - await this.methods.clear(); - }); - - it('clear then add entry', async function () { - await this.methods.set(this.keyA, this.valueA); - await this.methods.set(this.keyB, this.valueB); - await this.methods.set(this.keyC, this.valueC); - - await this.methods.clear(); - - await this.methods.set(this.keyA, this.valueA); - - expect(await this.methods.contains(this.keyA)).to.be.true; - expect(await this.methods.contains(this.keyB)).to.be.false; - expect(await this.methods.contains(this.keyC)).to.be.false; - await expectMembersMatch(this.methods, [this.keyA], [this.valueA]); - }); - }); - - describe('read', function () { - beforeEach(async function () { - await this.methods.set(this.keyA, this.valueA); - }); - - describe('get', function () { - it('existing value', async function () { - expect(await this.methods.get(this.keyA)).to.equal(this.valueA); - }); - - it('missing value', async function () { - await expect(this.methods.get(this.keyB)) - .to.be.revertedWithCustomError(this.mock, this.error ?? 'EnumerableMapNonexistentKey') - .withArgs( - this.key?.memory || this.value?.memory - ? this.keyB - : ethers.AbiCoder.defaultAbiCoder().encode([this.key.type], [this.keyB]), - ); - }); - }); - - describe('tryGet', function () { - it('existing value', async function () { - expect(await this.methods.tryGet(this.keyA)).to.have.ordered.members([true, this.valueA]); - }); - - it('missing value', async function () { - expect(await this.methods.tryGet(this.keyB)).to.have.ordered.members([false, this.zeroValue]); - }); - }); - }); - - it('keys (full & paginated)', async function () { - const keys = [this.keyA, this.keyB, this.keyC]; - await this.methods.set(this.keyA, this.valueA); - await this.methods.set(this.keyB, this.valueB); - await this.methods.set(this.keyC, this.valueC); - - // get all values - expect([...(await this.methods.keys())]).to.deep.equal(keys); - - // try pagination - for (const begin of [0, 1, 2, 3, 4]) - for (const end of [0, 1, 2, 3, 4]) { - expect([...(await this.methods.keysPage(begin, end))]).to.deep.equal(keys.slice(begin, end)); - } - }); -} - -module.exports = { - shouldBehaveLikeMap, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js deleted file mode 100644 index 567c82d..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js +++ /dev/null @@ -1,83 +0,0 @@ -const { ethers } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { mapValues } = require('../../helpers/iterate'); -const { generators } = require('../../helpers/random'); -const { MAP_TYPES, typeDescr, toMapTypeDescr } = require('../../../scripts/generate/templates/Enumerable.opts'); - -const { shouldBehaveLikeMap } = require('./EnumerableMap.behavior'); - -// Add Bytes32ToBytes32Map that must be tested but is not part of the generated types. -MAP_TYPES.unshift(toMapTypeDescr({ key: typeDescr({ type: 'bytes32' }), value: typeDescr({ type: 'bytes32' }) })); - -async function fixture() { - const mock = await ethers.deployContract('$EnumerableMap'); - - const env = Object.fromEntries( - MAP_TYPES.map(({ name, key, value }) => [ - name, - { - key, - value, - keys: Array.from({ length: 3 }, generators[key.type]), - values: Array.from({ length: 3 }, generators[value.type]), - zeroValue: generators[value.type].zero, - methods: mapValues( - MAP_TYPES.filter(map => map.key.name == key.name).length == 1 - ? { - set: `$set(uint256,${key.type},${value.type})`, - get: `$get(uint256,${key.type})`, - tryGet: `$tryGet(uint256,${key.type})`, - remove: `$remove(uint256,${key.type})`, - contains: `$contains(uint256,${key.type})`, - clear: `$clear_EnumerableMap_${name}(uint256)`, - length: `$length_EnumerableMap_${name}(uint256)`, - at: `$at_EnumerableMap_${name}(uint256,uint256)`, - keys: `$keys_EnumerableMap_${name}(uint256)`, - keysPage: `$keys_EnumerableMap_${name}(uint256,uint256,uint256)`, - } - : { - set: `$set(uint256,${key.type},${value.type})`, - get: `$get_EnumerableMap_${name}(uint256,${key.type})`, - tryGet: `$tryGet_EnumerableMap_${name}(uint256,${key.type})`, - remove: `$remove_EnumerableMap_${name}(uint256,${key.type})`, - contains: `$contains_EnumerableMap_${name}(uint256,${key.type})`, - clear: `$clear_EnumerableMap_${name}(uint256)`, - length: `$length_EnumerableMap_${name}(uint256)`, - at: `$at_EnumerableMap_${name}(uint256,uint256)`, - keys: `$keys_EnumerableMap_${name}(uint256)`, - keysPage: `$keys_EnumerableMap_${name}(uint256,uint256,uint256)`, - }, - fnSig => - (...args) => - mock.getFunction(fnSig)(0, ...args), - ), - events: { - setReturn: `return$set_EnumerableMap_${name}_${key.type}_${value.type}`, - removeReturn: `return$remove_EnumerableMap_${name}_${key.type}`, - }, - error: key.memory || value.memory ? `EnumerableMapNonexistent${key.name}Key` : `EnumerableMapNonexistentKey`, - }, - ]), - ); - - return { mock, env }; -} - -describe('EnumerableMap', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - for (const { name, key, value } of MAP_TYPES) { - describe(`${name} (enumerable map from ${key.type} to ${value.type})`, function () { - beforeEach(async function () { - Object.assign(this, this.env[name]); - [this.keyA, this.keyB, this.keyC] = this.keys; - [this.valueA, this.valueB, this.valueC] = this.values; - }); - - shouldBehaveLikeMap(); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js deleted file mode 100644 index 286563b..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js +++ /dev/null @@ -1,175 +0,0 @@ -const { expect } = require('chai'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -function shouldBehaveLikeSet() { - async function expectMembersMatch(methods, values) { - expect(await methods.length()).to.equal(values.length); - for (const value of values) expect(await methods.contains(value)).to.be.true; - - expect(await Promise.all(values.map((_, index) => methods.at(index)))).to.have.deep.members(values); - expect([...(await methods.values())]).to.have.deep.members(values); - } - - it('starts empty', async function () { - expect(await this.methods.contains(this.valueA)).to.be.false; - - await expectMembersMatch(this.methods, []); - }); - - describe('add', function () { - it('adds a value', async function () { - await expect(this.methods.add(this.valueA)).to.emit(this.mock, this.events.addReturn).withArgs(true); - - await expectMembersMatch(this.methods, [this.valueA]); - }); - - it('adds several values', async function () { - await this.methods.add(this.valueA); - await this.methods.add(this.valueB); - - await expectMembersMatch(this.methods, [this.valueA, this.valueB]); - expect(await this.methods.contains(this.valueC)).to.be.false; - }); - - it('returns false when adding values already in the set', async function () { - await this.methods.add(this.valueA); - - await expect(this.methods.add(this.valueA)).to.emit(this.mock, this.events.addReturn).withArgs(false); - - await expectMembersMatch(this.methods, [this.valueA]); - }); - }); - - describe('at', function () { - it('reverts when retrieving non-existent elements', async function () { - await expect(this.methods.at(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); - }); - - it('retrieves existing element', async function () { - await this.methods.add(this.valueA); - expect(await this.methods.at(0)).to.deep.equal(this.valueA); - }); - }); - - describe('remove', function () { - it('removes added values', async function () { - await this.methods.add(this.valueA); - - await expect(this.methods.remove(this.valueA)).to.emit(this.mock, this.events.removeReturn).withArgs(true); - - expect(await this.methods.contains(this.valueA)).to.be.false; - await expectMembersMatch(this.methods, []); - }); - - it('returns false when removing values not in the set', async function () { - await expect(this.methods.remove(this.valueA)).to.emit(this.mock, this.events.removeReturn).withArgs(false); - - expect(await this.methods.contains(this.valueA)).to.be.false; - }); - - it('adds and removes multiple values', async function () { - // [] - - await this.methods.add(this.valueA); - await this.methods.add(this.valueC); - - // [A, C] - - await this.methods.remove(this.valueA); - await this.methods.remove(this.valueB); - - // [C] - - await this.methods.add(this.valueB); - - // [C, B] - - await this.methods.add(this.valueA); - await this.methods.remove(this.valueC); - - // [A, B] - - await this.methods.add(this.valueA); - await this.methods.add(this.valueB); - - // [A, B] - - await this.methods.add(this.valueC); - await this.methods.remove(this.valueA); - - // [B, C] - - await this.methods.add(this.valueA); - await this.methods.remove(this.valueB); - - // [A, C] - - await expectMembersMatch(this.methods, [this.valueA, this.valueC]); - - expect(await this.methods.contains(this.valueB)).to.be.false; - }); - }); - - describe('clear', function () { - it('clears a single value', async function () { - await this.methods.add(this.valueA); - - await this.methods.clear(); - - expect(await this.methods.contains(this.valueA)).to.be.false; - await expectMembersMatch(this.methods, []); - }); - - it('clears multiple values', async function () { - await this.methods.add(this.valueA); - await this.methods.add(this.valueB); - await this.methods.add(this.valueC); - - await this.methods.clear(); - - expect(await this.methods.contains(this.valueA)).to.be.false; - expect(await this.methods.contains(this.valueB)).to.be.false; - expect(await this.methods.contains(this.valueC)).to.be.false; - await expectMembersMatch(this.methods, []); - }); - - it('does not revert on empty set', async function () { - await this.methods.clear(); - }); - - it('clear then add value', async function () { - await this.methods.add(this.valueA); - await this.methods.add(this.valueB); - await this.methods.add(this.valueC); - - await this.methods.clear(); - - await this.methods.add(this.valueA); - - expect(await this.methods.contains(this.valueA)).to.be.true; - expect(await this.methods.contains(this.valueB)).to.be.false; - expect(await this.methods.contains(this.valueC)).to.be.false; - await expectMembersMatch(this.methods, [this.valueA]); - }); - }); - - it('values (full & paginated)', async function () { - const values = [this.valueA, this.valueB, this.valueC]; - await this.methods.add(this.valueA); - await this.methods.add(this.valueB); - await this.methods.add(this.valueC); - - // get all values - expect([...(await this.methods.values())]).to.deep.equal(values); - - // try pagination - for (const begin of [0, 1, 2, 3, 4]) - for (const end of [0, 1, 2, 3, 4]) { - expect([...(await this.methods.valuesPage(begin, end))]).to.deep.equal(values.slice(begin, end)); - } - }); -} - -module.exports = { - shouldBehaveLikeSet, -}; diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js deleted file mode 100644 index 135bdf5..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js +++ /dev/null @@ -1,66 +0,0 @@ -const { ethers } = require('hardhat'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { mapValues } = require('../../helpers/iterate'); -const { generators } = require('../../helpers/random'); -const { SET_TYPES } = require('../../../scripts/generate/templates/Enumerable.opts'); - -const { shouldBehaveLikeSet } = require('./EnumerableSet.behavior'); - -const getMethods = (mock, fnSigs) => - mapValues( - fnSigs, - fnSig => - (...args) => - mock.getFunction(fnSig)(0, ...args), - ); - -async function fixture() { - const mock = await ethers.deployContract('$EnumerableSet'); - - const env = Object.fromEntries( - SET_TYPES.map(({ name, value }) => [ - name, - { - value, - values: Array.from( - { length: 3 }, - value.size ? () => Array.from({ length: value.size }, generators[value.base]) : generators[value.type], - ), - methods: getMethods(mock, { - add: `$add(uint256,${value.type})`, - remove: `$remove(uint256,${value.type})`, - contains: `$contains(uint256,${value.type})`, - clear: `$clear_EnumerableSet_${name}(uint256)`, - length: `$length_EnumerableSet_${name}(uint256)`, - at: `$at_EnumerableSet_${name}(uint256,uint256)`, - values: `$values_EnumerableSet_${name}(uint256)`, - valuesPage: `$values_EnumerableSet_${name}(uint256,uint256,uint256)`, - }), - events: { - addReturn: `return$add_EnumerableSet_${name}_${value.type.replace(/[[\]]/g, '_')}`, - removeReturn: `return$remove_EnumerableSet_${name}_${value.type.replace(/[[\]]/g, '_')}`, - }, - }, - ]), - ); - - return { mock, env }; -} - -describe('EnumerableSet', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - for (const { name, value } of SET_TYPES) { - describe(`${name} (enumerable set of ${value.type})`, function () { - beforeEach(function () { - Object.assign(this, this.env[name]); - [this.valueA, this.valueB, this.valueC] = this.values; - }); - - shouldBehaveLikeSet(); - }); - } -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.t.sol b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.t.sol deleted file mode 100644 index ba7d770..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.t.sol +++ /dev/null @@ -1,74 +0,0 @@ -// 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"; -import {Heap} from "@openzeppelin/contracts/utils/structs/Heap.sol"; -import {Comparators} from "@openzeppelin/contracts/utils/Comparators.sol"; - -contract Uint256HeapTest is Test { - using Heap for Heap.Uint256Heap; - - Heap.Uint256Heap internal heap; - - function _validateHeap(function(uint256, uint256) view returns (bool) comp) internal view { - for (uint32 i = 1; i < heap.length(); ++i) { - assertFalse(comp(heap.tree[i], heap.tree[(i - 1) / 2])); - } - } - - function testFuzz(uint256[] calldata input) public { - vm.assume(input.length < 0x20); - assertEq(heap.length(), 0); - - uint256 min = type(uint256).max; - for (uint256 i = 0; i < input.length; ++i) { - heap.insert(input[i]); - assertEq(heap.length(), i + 1); - _validateHeap(Comparators.lt); - - min = Math.min(min, input[i]); - assertEq(heap.peek(), min); - } - - uint256 max = 0; - for (uint256 i = 0; i < input.length; ++i) { - uint256 top = heap.peek(); - uint256 pop = heap.pop(); - assertEq(heap.length(), input.length - i - 1); - _validateHeap(Comparators.lt); - - assertEq(pop, top); - assertGe(pop, max); - max = pop; - } - } - - function testFuzzGt(uint256[] calldata input) public { - vm.assume(input.length < 0x20); - assertEq(heap.length(), 0); - - uint256 max = 0; - for (uint256 i = 0; i < input.length; ++i) { - heap.insert(input[i], Comparators.gt); - assertEq(heap.length(), i + 1); - _validateHeap(Comparators.gt); - - max = Math.max(max, input[i]); - assertEq(heap.peek(), max); - } - - uint256 min = type(uint256).max; - for (uint256 i = 0; i < input.length; ++i) { - uint256 top = heap.peek(); - uint256 pop = heap.pop(Comparators.gt); - assertEq(heap.length(), input.length - i - 1); - _validateHeap(Comparators.gt); - - assertEq(pop, top); - assertLe(pop, min); - min = pop; - } - } -} diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.test.js deleted file mode 100644 index 6d75120..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/Heap.test.js +++ /dev/null @@ -1,113 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); - -async function fixture() { - const mock = await ethers.deployContract('$Heap'); - return { mock }; -} - -describe('Heap', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('Uint256Heap', function () { - it('starts empty', async function () { - expect(await this.mock.$length(0)).to.equal(0n); - }); - - it('peek, pop and replace from empty', async function () { - await expect(this.mock.$peek(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); - await expect(this.mock.$pop(0)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY); - await expect(this.mock.$replace(0, 0n)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY); - }); - - it('clear', async function () { - await this.mock.$insert(0, 42n); - - expect(await this.mock.$length(0)).to.equal(1n); - expect(await this.mock.$peek(0)).to.equal(42n); - - await this.mock.$clear(0); - - expect(await this.mock.$length(0)).to.equal(0n); - await expect(this.mock.$peek(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); - }); - - it('support duplicated items', async function () { - expect(await this.mock.$length(0)).to.equal(0n); - - // insert 5 times - await this.mock.$insert(0, 42n); - await this.mock.$insert(0, 42n); - await this.mock.$insert(0, 42n); - await this.mock.$insert(0, 42n); - await this.mock.$insert(0, 42n); - - // pop 5 times - await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n); - await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n); - await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n); - await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n); - await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n); - - // popping a 6th time panics - await expect(this.mock.$pop(0)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY); - }); - - it('insert, pop and replace', async function () { - const heap = []; - for (const { op, value } of [ - { op: 'insert', value: 712 }, // [712] - { op: 'insert', value: 20 }, // [20, 712] - { op: 'insert', value: 4337 }, // [20, 712, 4437] - { op: 'pop' }, // 20, [712, 4437] - { op: 'insert', value: 1559 }, // [712, 1559, 4437] - { op: 'insert', value: 165 }, // [165, 712, 1559, 4437] - { op: 'insert', value: 155 }, // [155, 165, 712, 1559, 4437] - { op: 'insert', value: 7702 }, // [155, 165, 712, 1559, 4437, 7702] - { op: 'pop' }, // 155, [165, 712, 1559, 4437, 7702] - { op: 'replace', value: 721 }, // 165, [712, 721, 1559, 4437, 7702] - { op: 'pop' }, // 712, [721, 1559, 4437, 7702] - { op: 'pop' }, // 721, [1559, 4437, 7702] - { op: 'pop' }, // 1559, [4437, 7702] - { op: 'pop' }, // 4437, [7702] - { op: 'pop' }, // 7702, [] - { op: 'pop' }, // panic - { op: 'replace', value: '1363' }, // panic - ]) { - switch (op) { - case 'insert': - await this.mock.$insert(0, value); - heap.push(value); - heap.sort((a, b) => a - b); - break; - case 'pop': - if (heap.length == 0) { - await expect(this.mock.$pop(0)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY); - } else { - await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(heap.shift()); - } - break; - case 'replace': - if (heap.length == 0) { - await expect(this.mock.$replace(0, value)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY); - } else { - await expect(this.mock.$replace(0, value)).to.emit(this.mock, 'return$replace').withArgs(heap.shift()); - heap.push(value); - heap.sort((a, b) => a - b); - } - break; - } - expect(await this.mock.$length(0)).to.equal(heap.length); - if (heap.length == 0) { - await expect(this.mock.$peek(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS); - } else { - expect(await this.mock.$peek(0)).to.equal(heap[0]); - } - } - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/MerkleTree.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/MerkleTree.test.js deleted file mode 100644 index f0380ed..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/structs/MerkleTree.test.js +++ /dev/null @@ -1,180 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); -const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic'); -const { StandardMerkleTree } = require('@openzeppelin/merkle-tree'); - -const { generators } = require('../../helpers/random'); -const { range } = require('../../helpers/iterate'); - -const DEPTH = 4; // 16 slots - -const makeTree = (leaves = [], length = 2 ** DEPTH, zero = ethers.ZeroHash) => - StandardMerkleTree.of( - [] - .concat( - leaves, - Array.from({ length: length - leaves.length }, () => zero), - ) - .map(leaf => [leaf]), - ['bytes32'], - { sortLeaves: false }, - ); - -const ZERO = makeTree().leafHash([ethers.ZeroHash]); - -async function fixture() { - const mock = await ethers.deployContract('MerkleTreeMock'); - await mock.setup(DEPTH, ZERO); - return { mock }; -} - -describe('MerkleTree', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - it('sets initial values at setup', async function () { - const merkleTree = makeTree(); - - await expect(this.mock.root()).to.eventually.equal(merkleTree.root); - await expect(this.mock.depth()).to.eventually.equal(DEPTH); - await expect(this.mock.nextLeafIndex()).to.eventually.equal(0n); - }); - - describe('push', function () { - it('pushing correctly updates the tree', async function () { - const leaves = []; - - // for each leaf slot - for (const i in range(2 ** DEPTH)) { - // generate random leaf - leaves.push(generators.bytes32()); - - // rebuild tree. - const tree = makeTree(leaves); - const hash = tree.leafHash(tree.at(i)); - - // push value to tree - await expect(this.mock.push(hash)).to.emit(this.mock, 'LeafInserted').withArgs(hash, i, tree.root); - - // check tree - await expect(this.mock.root()).to.eventually.equal(tree.root); - await expect(this.mock.nextLeafIndex()).to.eventually.equal(BigInt(i) + 1n); - } - }); - - it('pushing to a full tree reverts', async function () { - await Promise.all(Array.from({ length: 2 ** Number(DEPTH) }).map(() => this.mock.push(ethers.ZeroHash))); - - await expect(this.mock.push(ethers.ZeroHash)).to.be.revertedWithPanic(PANIC_CODES.TOO_MUCH_MEMORY_ALLOCATED); - }); - }); - - describe('update', function () { - for (const { leafCount, leafIndex } of range(2 ** DEPTH + 1).flatMap(leafCount => - range(leafCount).map(leafIndex => ({ leafCount, leafIndex })), - )) - it(`updating a leaf correctly updates the tree (leaf #${leafIndex + 1}/${leafCount})`, async function () { - // initial tree - const leaves = Array.from({ length: leafCount }, generators.bytes32); - const oldTree = makeTree(leaves); - - // fill tree and verify root - for (const i in leaves) { - await this.mock.push(oldTree.leafHash(oldTree.at(i))); - } - await expect(this.mock.root()).to.eventually.equal(oldTree.root); - - // create updated tree - leaves[leafIndex] = generators.bytes32(); - const newTree = makeTree(leaves); - - const oldLeafHash = oldTree.leafHash(oldTree.at(leafIndex)); - const newLeafHash = newTree.leafHash(newTree.at(leafIndex)); - - // perform update - await expect(this.mock.update(leafIndex, oldLeafHash, newLeafHash, oldTree.getProof(leafIndex))) - .to.emit(this.mock, 'LeafUpdated') - .withArgs(oldLeafHash, newLeafHash, leafIndex, newTree.root); - - // verify updated root - await expect(this.mock.root()).to.eventually.equal(newTree.root); - - // if there is still room in the tree, fill it - for (const i of range(leafCount, 2 ** DEPTH)) { - // push new value and rebuild tree - leaves.push(generators.bytes32()); - const nextTree = makeTree(leaves); - - // push and verify root - await this.mock.push(nextTree.leafHash(nextTree.at(i))); - await expect(this.mock.root()).to.eventually.equal(nextTree.root); - } - }); - - it('replacing a leaf that was not previously pushed reverts', async function () { - // changing leaf 0 on an empty tree - await expect(this.mock.update(1, ZERO, ZERO, [])) - .to.be.revertedWithCustomError(this.mock, 'MerkleTreeUpdateInvalidIndex') - .withArgs(1, 0); - }); - - it('replacing a leaf using an invalid proof reverts', async function () { - const leafCount = 4; - const leafIndex = 2; - - const leaves = Array.from({ length: leafCount }, generators.bytes32); - const tree = makeTree(leaves); - - // fill tree and verify root - for (const i in leaves) { - await this.mock.push(tree.leafHash(tree.at(i))); - } - await expect(this.mock.root()).to.eventually.equal(tree.root); - - const oldLeafHash = tree.leafHash(tree.at(leafIndex)); - const newLeafHash = generators.bytes32(); - const proof = tree.getProof(leafIndex); - // invalid proof (tamper) - proof[1] = generators.bytes32(); - - await expect(this.mock.update(leafIndex, oldLeafHash, newLeafHash, proof)).to.be.revertedWithCustomError( - this.mock, - 'MerkleTreeUpdateInvalidProof', - ); - }); - }); - - it('reset', async function () { - // empty tree - const emptyTree = makeTree(); - - // tree with one element - const leaves = [generators.bytes32()]; - const tree = makeTree(leaves); - const hash = tree.leafHash(tree.at(0)); - - // root should be that of a zero tree - expect(await this.mock.root()).to.equal(emptyTree.root); - expect(await this.mock.nextLeafIndex()).to.equal(0n); - - // push leaf and check root - await expect(this.mock.push(hash)).to.emit(this.mock, 'LeafInserted').withArgs(hash, 0, tree.root); - - expect(await this.mock.root()).to.equal(tree.root); - expect(await this.mock.nextLeafIndex()).to.equal(1n); - - // reset tree - await this.mock.setup(DEPTH, ZERO); - - expect(await this.mock.root()).to.equal(emptyTree.root); - expect(await this.mock.nextLeafIndex()).to.equal(0n); - - // re-push leaf and check root - await expect(this.mock.push(hash)).to.emit(this.mock, 'LeafInserted').withArgs(hash, 0, tree.root); - - expect(await this.mock.root()).to.equal(tree.root); - expect(await this.mock.nextLeafIndex()).to.equal(1n); - }); -}); diff --git a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/types/Time.test.js b/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/types/Time.test.js deleted file mode 100644 index 3ab6fef..0000000 --- a/typescript/packages/account-modules/lib/openzeppelin-contracts/test/utils/types/Time.test.js +++ /dev/null @@ -1,135 +0,0 @@ -const { ethers } = require('hardhat'); -const { expect } = require('chai'); -const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); - -const { product } = require('../../helpers/iterate'); -const { max } = require('../../helpers/math'); -const time = require('../../helpers/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) => { - value = ethers.toBigInt(value); - size = ethers.toBigInt(size); - expect(value).to.be.greaterThanOrEqual(0n, `value is not a valid uint${size}`); - expect(value).to.be.lessThan(1n << size, `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, -]; - -async function fixture() { - const mock = await ethers.deployContract('$Time'); - return { mock }; -} - -describe('Time', function () { - beforeEach(async function () { - Object.assign(this, await loadFixture(fixture)); - }); - - describe('clocks', function () { - it('timestamp', async function () { - expect(await this.mock.$timestamp()).to.equal(await time.clock.timestamp()); - }); - - it('block number', async function () { - expect(await this.mock.$blockNumber()).to.equal(await time.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 () { - expect(await this.mock.$pack(valueBefore, valueAfter, effect)).to.equal(delay); - expect(packDelay({ valueBefore, valueAfter, effect })).to.equal(delay); - }); - - it('unpack', async function () { - expect(await this.mock.$unpack(delay)).to.deep.equal([valueBefore, valueAfter, effect]); - - expect(unpackDelay(delay)).to.deep.equal({ - valueBefore, - valueAfter, - effect, - }); - }); - }); - - it('toDelay', async function () { - for (const value of [...SOME_VALUES, MAX_UINT32]) { - expect(await this.mock.$toDelay(value).then(unpackDelay)).to.deep.equal({ - valueBefore: 0n, - valueAfter: value, - effect: 0n, - }); - } - }); - - it('get & getFull', async function () { - const timepoint = await time.clock.timestamp(); - 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.equal(isPast ? valueAfter : valueBefore); - expect(await this.mock.$getFull(delay)).to.deep.equal([ - isPast ? valueAfter : valueBefore, - isPast ? 0n : valueAfter, - isPast ? 0n : effect, - ]); - } - }); - - it('withUpdate', async function () { - const timepoint = await time.clock.timestamp(); - 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); - - expect( - await this.mock.$withUpdate(packDelay({ valueBefore, valueAfter, effect }), newvalueAfter, minSetback), - ).to.deep.equal([ - packDelay({ - valueBefore: expectedvalueBefore, - valueAfter: newvalueAfter, - effect: timepoint + expectedSetback, - }), - timepoint + expectedSetback, - ]); - } - }); - }); -}); diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gas-snapshot b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gas-snapshot deleted file mode 100644 index a37218e..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gas-snapshot +++ /dev/null @@ -1,3 +0,0 @@ -SafeSingletonDeployerTest:test_deploy_createsAtExpectedAddress() (gas: 110747) -SafeSingletonDeployerTest:test_deploy_createsContractCorrectly() (gas: 100784) -SafeSingletonDeployerTest:test_deploy_reverts() (gas: 41137) \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.github/workflows/test.yml b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.github/workflows/test.yml deleted file mode 100644 index fb3a71c..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.github/workflows/test.yml +++ /dev/null @@ -1,86 +0,0 @@ -name: Forge CI - -on: - pull_request: - branches: - - main - -env: - FOUNDRY_PROFILE: ci - -jobs: - forge-test: - name: Run Forge Tests and Checks - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: nightly - - - name: Run Forge build - run: | - forge --version - forge build --sizes - id: build - - - name: Run Forge tests - run: | - forge test -vvv - id: test - - - name: Check formatting - run: | - forge fmt --check - id: fmt - - forge-coverage: - name: Run Coverage Reporting - 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: Install forge dependencies - run: forge install - - - name: Install lcov - run: | - sudo apt-get install lcov - id: lcov - - - name: Run coverage - run: | - forge coverage --report summary --report lcov - - - name: Prune coverage - run: | - lcov --remove ./lcov.info -o ./lcov-filtered.info 'test/*' 'script/*' 'src/utils/*' - - - name: Submit coverage to Coveralls - uses: coverallsapp/github-action@master - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - path-to-lcov: ./lcov-filtered.info - flag-name: foundry - parallel: true - - finish: - needs: forge-coverage - if: ${{ always() }} - runs-on: ubuntu-latest - steps: - - name: Coveralls Finished - uses: coverallsapp/github-action@v2 - with: - parallel-finished: true diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitignore b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitignore deleted file mode 100644 index 85198aa..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# Compiler files -cache/ -out/ - -# Ignores development broadcast logs -!/broadcast -/broadcast/*/31337/ -/broadcast/**/dry-run/ - -# Docs -docs/ - -# Dotenv file -.env diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitmodules b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitmodules deleted file mode 100644 index 888d42d..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "lib/forge-std"] - path = lib/forge-std - url = https://github.com/foundry-rs/forge-std diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/README.md b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/README.md deleted file mode 100644 index 853c64d..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/README.md +++ /dev/null @@ -1,9 +0,0 @@ - -# Solidity Safe Singleton Factory Deployer -This is a Solidity library for using [Safe Singleton Factory](https://github.com/safe-global/safe-singleton-factory). At the code level, this factory matches [Arachnid's Determinstic Deployment Proxy](https://github.com/Arachnid/deterministic-deployment-proxy). It is different from other deterministic deployment factories in that Safe holds the private key and has NOT shared any presigned transactions. This can help avoid accidental or malicious nonce increments via presigned transactions with invalid gas values for a certain network. - -Safe has currently deployed this factory to 252 chains and it has the same address on 248. - -I made this library so that this factory would be easiser to use with Forge deployment scripts, as there seem to only be existing tools for Hardhat. - -Example usage in [`ExampleDeploy.s.sol`](https://github.com/wilsoncusack/safe-singleton-deployer-sol/blob/main/scripts/ExampleDeploy.s.sol) diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/foundry.toml b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/foundry.toml deleted file mode 100644 index 25b918f..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/foundry.toml +++ /dev/null @@ -1,6 +0,0 @@ -[profile.default] -src = "src" -out = "out" -libs = ["lib"] - -# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitattributes b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitattributes deleted file mode 100644 index 27042d4..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -src/Vm.sol linguist-generated diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.github/workflows/ci.yml b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.github/workflows/ci.yml deleted file mode 100644 index cb241ae..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.github/workflows/ci.yml +++ /dev/null @@ -1,134 +0,0 @@ -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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.github/workflows/sync.yml b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.github/workflows/sync.yml deleted file mode 100644 index 5a9e9d5..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.github/workflows/sync.yml +++ /dev/null @@ -1,29 +0,0 @@ -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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitignore b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitignore deleted file mode 100644 index 756106d..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -cache/ -out/ -.vscode -.idea diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/LICENSE-APACHE b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/LICENSE-APACHE deleted file mode 100644 index cf01a49..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/LICENSE-APACHE +++ /dev/null @@ -1,203 +0,0 @@ -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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/LICENSE-MIT b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/LICENSE-MIT deleted file mode 100644 index 28f9830..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/README.md b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/README.md deleted file mode 100644 index 0cb8660..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/README.md +++ /dev/null @@ -1,250 +0,0 @@ -# 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 - -Contains various assertions. - -### `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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/foundry.toml b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/foundry.toml deleted file mode 100644 index c873eaa..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/foundry.toml +++ /dev/null @@ -1,21 +0,0 @@ -[profile.default] -fs_permissions = [{ access = "read-write", path = "./"}] - -[rpc_endpoints] -# The RPC URLs are modified versions of the default for testing initialization. -mainnet = "https://eth-mainnet.alchemyapi.io/v2/WV407BEiBmjNJfKo9Uo_55u0z0ITyCOX" # 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/package.json b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/package.json deleted file mode 100644 index acc004b..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "forge-std", - "version": "1.7.6", - "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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/scripts/vm.py b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/scripts/vm.py deleted file mode 100755 index f0537db..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/scripts/vm.py +++ /dev/null @@ -1,635 +0,0 @@ -#!/usr/bin/env python3 - -import copy -import json -import re -import subprocess -from enum import Enum as PyEnum -from typing import Callable -from urllib import request - -VoidFn = Callable[[], None] - -CHEATCODES_JSON_URL = "https://raw.githubusercontent.com/foundry-rs/foundry/master/crates/cheatcodes/assets/cheatcodes.json" -OUT_PATH = "src/Vm.sol" - -VM_SAFE_DOC = """\ -/// 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. -""" - -VM_DOC = """\ -/// 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. -""" - - -def main(): - json_str = request.urlopen(CHEATCODES_JSON_URL).read().decode("utf-8") - contract = Cheatcodes.from_json(json_str) - - ccs = contract.cheatcodes - ccs = list(filter(lambda cc: cc.status not in ["experimental", "internal"], ccs)) - ccs.sort(key=lambda cc: cc.func.id) - - safe = list(filter(lambda cc: cc.safety == "safe", ccs)) - safe.sort(key=CmpCheatcode) - unsafe = list(filter(lambda cc: cc.safety == "unsafe", ccs)) - unsafe.sort(key=CmpCheatcode) - assert len(safe) + len(unsafe) == len(ccs) - - prefix_with_group_headers(safe) - prefix_with_group_headers(unsafe) - - out = "" - - out += "// Automatically @generated by scripts/vm.py. Do not modify manually.\n\n" - - pp = CheatcodesPrinter( - spdx_identifier="MIT OR Apache-2.0", - solidity_requirement=">=0.6.2 <0.9.0", - abicoder_pragma=True, - ) - pp.p_prelude() - pp.prelude = False - out += pp.finish() - - out += "\n\n" - out += VM_SAFE_DOC - vm_safe = Cheatcodes( - # TODO: Custom errors were introduced in 0.8.4 - errors=[], # contract.errors - events=contract.events, - enums=contract.enums, - structs=contract.structs, - cheatcodes=safe, - ) - pp.p_contract(vm_safe, "VmSafe") - out += pp.finish() - - out += "\n\n" - out += VM_DOC - vm_unsafe = Cheatcodes( - errors=[], - events=[], - enums=[], - structs=[], - cheatcodes=unsafe, - ) - pp.p_contract(vm_unsafe, "Vm", "VmSafe") - out += pp.finish() - - # Compatibility with <0.8.0 - def memory_to_calldata(m: re.Match) -> str: - return " calldata " + m.group(1) - - out = re.sub(r" memory (.*returns)", memory_to_calldata, out) - - with open(OUT_PATH, "w") as f: - f.write(out) - - forge_fmt = ["forge", "fmt", OUT_PATH] - res = subprocess.run(forge_fmt) - assert res.returncode == 0, f"command failed: {forge_fmt}" - - print(f"Wrote to {OUT_PATH}") - - -class CmpCheatcode: - cheatcode: "Cheatcode" - - def __init__(self, cheatcode: "Cheatcode"): - self.cheatcode = cheatcode - - def __lt__(self, other: "CmpCheatcode") -> bool: - return cmp_cheatcode(self.cheatcode, other.cheatcode) < 0 - - def __eq__(self, other: "CmpCheatcode") -> bool: - return cmp_cheatcode(self.cheatcode, other.cheatcode) == 0 - - def __gt__(self, other: "CmpCheatcode") -> bool: - return cmp_cheatcode(self.cheatcode, other.cheatcode) > 0 - - -def cmp_cheatcode(a: "Cheatcode", b: "Cheatcode") -> int: - if a.group != b.group: - return -1 if a.group < b.group else 1 - if a.status != b.status: - return -1 if a.status < b.status else 1 - if a.safety != b.safety: - return -1 if a.safety < b.safety else 1 - if a.func.id != b.func.id: - return -1 if a.func.id < b.func.id else 1 - return 0 - - -# HACK: A way to add group header comments without having to modify printer code -def prefix_with_group_headers(cheats: list["Cheatcode"]): - s = set() - for i, cheat in enumerate(cheats): - if cheat.group in s: - continue - - s.add(cheat.group) - - c = copy.deepcopy(cheat) - c.func.description = "" - c.func.declaration = f"// ======== {group(c.group)} ========" - cheats.insert(i, c) - return cheats - - -def group(s: str) -> str: - if s == "evm": - return "EVM" - if s == "json": - return "JSON" - return s[0].upper() + s[1:] - - -class Visibility(PyEnum): - EXTERNAL: str = "external" - PUBLIC: str = "public" - INTERNAL: str = "internal" - PRIVATE: str = "private" - - def __str__(self): - return self.value - - -class Mutability(PyEnum): - PURE: str = "pure" - VIEW: str = "view" - NONE: str = "" - - def __str__(self): - return self.value - - -class Function: - id: str - description: str - declaration: str - visibility: Visibility - mutability: Mutability - signature: str - selector: str - selector_bytes: bytes - - def __init__( - self, - id: str, - description: str, - declaration: str, - visibility: Visibility, - mutability: Mutability, - signature: str, - selector: str, - selector_bytes: bytes, - ): - self.id = id - self.description = description - self.declaration = declaration - self.visibility = visibility - self.mutability = mutability - self.signature = signature - self.selector = selector - self.selector_bytes = selector_bytes - - @staticmethod - def from_dict(d: dict) -> "Function": - return Function( - d["id"], - d["description"], - d["declaration"], - Visibility(d["visibility"]), - Mutability(d["mutability"]), - d["signature"], - d["selector"], - bytes(d["selectorBytes"]), - ) - - -class Cheatcode: - func: Function - group: str - status: str - safety: str - - def __init__(self, func: Function, group: str, status: str, safety: str): - self.func = func - self.group = group - self.status = status - self.safety = safety - - @staticmethod - def from_dict(d: dict) -> "Cheatcode": - return Cheatcode( - Function.from_dict(d["func"]), - str(d["group"]), - str(d["status"]), - str(d["safety"]), - ) - - -class Error: - name: str - description: str - declaration: str - - def __init__(self, name: str, description: str, declaration: str): - self.name = name - self.description = description - self.declaration = declaration - - @staticmethod - def from_dict(d: dict) -> "Error": - return Error(**d) - - -class Event: - name: str - description: str - declaration: str - - def __init__(self, name: str, description: str, declaration: str): - self.name = name - self.description = description - self.declaration = declaration - - @staticmethod - def from_dict(d: dict) -> "Event": - return Event(**d) - - -class EnumVariant: - name: str - description: str - - def __init__(self, name: str, description: str): - self.name = name - self.description = description - - -class Enum: - name: str - description: str - variants: list[EnumVariant] - - def __init__(self, name: str, description: str, variants: list[EnumVariant]): - self.name = name - self.description = description - self.variants = variants - - @staticmethod - def from_dict(d: dict) -> "Enum": - return Enum( - d["name"], - d["description"], - list(map(lambda v: EnumVariant(**v), d["variants"])), - ) - - -class StructField: - name: str - ty: str - description: str - - def __init__(self, name: str, ty: str, description: str): - self.name = name - self.ty = ty - self.description = description - - -class Struct: - name: str - description: str - fields: list[StructField] - - def __init__(self, name: str, description: str, fields: list[StructField]): - self.name = name - self.description = description - self.fields = fields - - @staticmethod - def from_dict(d: dict) -> "Struct": - return Struct( - d["name"], - d["description"], - list(map(lambda f: StructField(**f), d["fields"])), - ) - - -class Cheatcodes: - errors: list[Error] - events: list[Event] - enums: list[Enum] - structs: list[Struct] - cheatcodes: list[Cheatcode] - - def __init__( - self, - errors: list[Error], - events: list[Event], - enums: list[Enum], - structs: list[Struct], - cheatcodes: list[Cheatcode], - ): - self.errors = errors - self.events = events - self.enums = enums - self.structs = structs - self.cheatcodes = cheatcodes - - @staticmethod - def from_dict(d: dict) -> "Cheatcodes": - return Cheatcodes( - errors=[Error.from_dict(e) for e in d["errors"]], - events=[Event.from_dict(e) for e in d["events"]], - enums=[Enum.from_dict(e) for e in d["enums"]], - structs=[Struct.from_dict(e) for e in d["structs"]], - cheatcodes=[Cheatcode.from_dict(e) for e in d["cheatcodes"]], - ) - - @staticmethod - def from_json(s) -> "Cheatcodes": - return Cheatcodes.from_dict(json.loads(s)) - - @staticmethod - def from_json_file(file_path: str) -> "Cheatcodes": - with open(file_path, "r") as f: - return Cheatcodes.from_dict(json.load(f)) - - -class Item(PyEnum): - ERROR: str = "error" - EVENT: str = "event" - ENUM: str = "enum" - STRUCT: str = "struct" - FUNCTION: str = "function" - - -class ItemOrder: - _list: list[Item] - - def __init__(self, list: list[Item]) -> None: - assert len(list) <= len(Item), "list must not contain more items than Item" - assert len(list) == len(set(list)), "list must not contain duplicates" - self._list = list - pass - - def get_list(self) -> list[Item]: - return self._list - - @staticmethod - def default() -> "ItemOrder": - return ItemOrder( - [ - Item.ERROR, - Item.EVENT, - Item.ENUM, - Item.STRUCT, - Item.FUNCTION, - ] - ) - - -class CheatcodesPrinter: - buffer: str - - prelude: bool - spdx_identifier: str - solidity_requirement: str - abicoder_v2: bool - - block_doc_style: bool - - indent_level: int - _indent_str: str - - nl_str: str - - items_order: ItemOrder - - def __init__( - self, - buffer: str = "", - prelude: bool = True, - spdx_identifier: str = "UNLICENSED", - solidity_requirement: str = "", - abicoder_pragma: bool = False, - block_doc_style: bool = False, - indent_level: int = 0, - indent_with: int | str = 4, - nl_str: str = "\n", - items_order: ItemOrder = ItemOrder.default(), - ): - self.prelude = prelude - self.spdx_identifier = spdx_identifier - self.solidity_requirement = solidity_requirement - self.abicoder_v2 = abicoder_pragma - self.block_doc_style = block_doc_style - self.buffer = buffer - self.indent_level = indent_level - self.nl_str = nl_str - - if isinstance(indent_with, int): - assert indent_with >= 0 - self._indent_str = " " * indent_with - elif isinstance(indent_with, str): - self._indent_str = indent_with - else: - assert False, "indent_with must be int or str" - - self.items_order = items_order - - def finish(self) -> str: - ret = self.buffer.rstrip() - self.buffer = "" - return ret - - def p_contract(self, contract: Cheatcodes, name: str, inherits: str = ""): - if self.prelude: - self.p_prelude(contract) - - self._p_str("interface ") - name = name.strip() - if name != "": - self._p_str(name) - self._p_str(" ") - if inherits != "": - self._p_str("is ") - self._p_str(inherits) - self._p_str(" ") - self._p_str("{") - self._p_nl() - self._with_indent(lambda: self._p_items(contract)) - self._p_str("}") - self._p_nl() - - def _p_items(self, contract: Cheatcodes): - for item in self.items_order.get_list(): - if item == Item.ERROR: - self.p_errors(contract.errors) - elif item == Item.EVENT: - self.p_events(contract.events) - elif item == Item.ENUM: - self.p_enums(contract.enums) - elif item == Item.STRUCT: - self.p_structs(contract.structs) - elif item == Item.FUNCTION: - self.p_functions(contract.cheatcodes) - else: - assert False, f"unknown item {item}" - - def p_prelude(self, contract: Cheatcodes | None = None): - self._p_str(f"// SPDX-License-Identifier: {self.spdx_identifier}") - self._p_nl() - - if self.solidity_requirement != "": - req = self.solidity_requirement - elif contract and len(contract.errors) > 0: - req = ">=0.8.4 <0.9.0" - else: - req = ">=0.6.0 <0.9.0" - self._p_str(f"pragma solidity {req};") - self._p_nl() - - if self.abicoder_v2: - self._p_str("pragma experimental ABIEncoderV2;") - self._p_nl() - - self._p_nl() - - def p_errors(self, errors: list[Error]): - for error in errors: - self._p_line(lambda: self.p_error(error)) - - def p_error(self, error: Error): - self._p_comment(error.description, doc=True) - self._p_line(lambda: self._p_str(error.declaration)) - - def p_events(self, events: list[Event]): - for event in events: - self._p_line(lambda: self.p_event(event)) - - def p_event(self, event: Event): - self._p_comment(event.description, doc=True) - self._p_line(lambda: self._p_str(event.declaration)) - - def p_enums(self, enums: list[Enum]): - for enum in enums: - self._p_line(lambda: self.p_enum(enum)) - - def p_enum(self, enum: Enum): - self._p_comment(enum.description, doc=True) - self._p_line(lambda: self._p_str(f"enum {enum.name} {{")) - self._with_indent(lambda: self.p_enum_variants(enum.variants)) - self._p_line(lambda: self._p_str("}")) - - def p_enum_variants(self, variants: list[EnumVariant]): - for i, variant in enumerate(variants): - self._p_indent() - self._p_comment(variant.description) - - self._p_indent() - self._p_str(variant.name) - if i < len(variants) - 1: - self._p_str(",") - self._p_nl() - - def p_structs(self, structs: list[Struct]): - for struct in structs: - self._p_line(lambda: self.p_struct(struct)) - - def p_struct(self, struct: Struct): - self._p_comment(struct.description, doc=True) - self._p_line(lambda: self._p_str(f"struct {struct.name} {{")) - self._with_indent(lambda: self.p_struct_fields(struct.fields)) - self._p_line(lambda: self._p_str("}")) - - def p_struct_fields(self, fields: list[StructField]): - for field in fields: - self._p_line(lambda: self.p_struct_field(field)) - - def p_struct_field(self, field: StructField): - self._p_comment(field.description) - self._p_indented(lambda: self._p_str(f"{field.ty} {field.name};")) - - def p_functions(self, cheatcodes: list[Cheatcode]): - for cheatcode in cheatcodes: - self._p_line(lambda: self.p_function(cheatcode.func)) - - def p_function(self, func: Function): - self._p_comment(func.description, doc=True) - self._p_line(lambda: self._p_str(func.declaration)) - - def _p_comment(self, s: str, doc: bool = False): - s = s.strip() - if s == "": - return - - s = map(lambda line: line.lstrip(), s.split("\n")) - if self.block_doc_style: - self._p_str("/*") - if doc: - self._p_str("*") - self._p_nl() - for line in s: - self._p_indent() - self._p_str(" ") - if doc: - self._p_str("* ") - self._p_str(line) - self._p_nl() - self._p_indent() - self._p_str(" */") - self._p_nl() - else: - first_line = True - for line in s: - if not first_line: - self._p_indent() - first_line = False - - if doc: - self._p_str("/// ") - else: - self._p_str("// ") - self._p_str(line) - self._p_nl() - - def _with_indent(self, f: VoidFn): - self._inc_indent() - f() - self._dec_indent() - - def _p_line(self, f: VoidFn): - self._p_indent() - f() - self._p_nl() - - def _p_indented(self, f: VoidFn): - self._p_indent() - f() - - def _p_indent(self): - for _ in range(self.indent_level): - self._p_str(self._indent_str) - - def _p_nl(self): - self._p_str(self.nl_str) - - def _p_str(self, txt: str): - self.buffer += txt - - def _inc_indent(self): - self.indent_level += 1 - - def _dec_indent(self): - self.indent_level -= 1 - - -if __name__ == "__main__": - main() diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Base.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Base.sol deleted file mode 100644 index 851ac0c..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Base.sol +++ /dev/null @@ -1,35 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Script.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Script.sol deleted file mode 100644 index 94e75f6..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Script.sol +++ /dev/null @@ -1,27 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdAssertions.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdAssertions.sol deleted file mode 100644 index a6d0f13..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdAssertions.sol +++ /dev/null @@ -1,669 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2 <0.9.0; -pragma experimental ABIEncoderV2; - -import {Vm} from "./Vm.sol"; - -abstract contract StdAssertions { - Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); - - event log(string); - event logs(bytes); - - event log_address(address); - event log_bytes32(bytes32); - event log_int(int256); - event log_uint(uint256); - 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, int256 val, uint256 decimals); - event log_named_decimal_uint(string key, uint256 val, uint256 decimals); - event log_named_int(string key, int256 val); - event log_named_uint(string key, uint256 val); - event log_named_bytes(string key, bytes val); - event log_named_string(string key, string val); - - 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); - - bool private _failed; - - function failed() public view returns (bool) { - if (_failed) { - return _failed; - } else { - return vm.load(address(vm), bytes32("failed")) != bytes32(0); - } - } - - function fail() internal virtual { - vm.store(address(vm), bytes32("failed"), bytes32(uint256(1))); - _failed = true; - } - - function assertTrue(bool data) internal pure virtual { - vm.assertTrue(data); - } - - function assertTrue(bool data, string memory err) internal pure virtual { - vm.assertTrue(data, err); - } - - function assertFalse(bool data) internal pure virtual { - vm.assertFalse(data); - } - - function assertFalse(bool data, string memory err) internal pure virtual { - vm.assertFalse(data, err); - } - - function assertEq(bool left, bool right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bool left, bool right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(uint256 left, uint256 right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(uint256 left, uint256 right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertEqDecimal(left, right, decimals); - } - - function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertEqDecimal(left, right, decimals, err); - } - - function assertEq(int256 left, int256 right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(int256 left, int256 right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEqDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertEqDecimal(left, right, decimals); - } - - function assertEqDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertEqDecimal(left, right, decimals, err); - } - - function assertEq(address left, address right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(address left, address right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(bytes32 left, bytes32 right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bytes32 left, bytes32 right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq32(bytes32 left, bytes32 right) internal pure virtual { - assertEq(left, right); - } - - function assertEq32(bytes32 left, bytes32 right, string memory err) internal pure virtual { - assertEq(left, right, err); - } - - function assertEq(string memory left, string memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(string memory left, string memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(bytes memory left, bytes memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bytes memory left, bytes memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(bool[] memory left, bool[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bool[] memory left, bool[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(uint256[] memory left, uint256[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(uint256[] memory left, uint256[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(int256[] memory left, int256[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(int256[] memory left, int256[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(address[] memory left, address[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(address[] memory left, address[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(bytes32[] memory left, bytes32[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bytes32[] memory left, bytes32[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(string[] memory left, string[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(string[] memory left, string[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - function assertEq(bytes[] memory left, bytes[] memory right) internal pure virtual { - vm.assertEq(left, right); - } - - function assertEq(bytes[] memory left, bytes[] memory right, string memory err) internal pure virtual { - vm.assertEq(left, right, err); - } - - // Legacy helper - function assertEqUint(uint256 left, uint256 right) internal pure virtual { - assertEq(left, right); - } - - function assertNotEq(bool left, bool right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bool left, bool right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(uint256 left, uint256 right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(uint256 left, uint256 right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertNotEqDecimal(left, right, decimals); - } - - function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) - internal - pure - virtual - { - vm.assertNotEqDecimal(left, right, decimals, err); - } - - function assertNotEq(int256 left, int256 right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(int256 left, int256 right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertNotEqDecimal(left, right, decimals); - } - - function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertNotEqDecimal(left, right, decimals, err); - } - - function assertNotEq(address left, address right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(address left, address right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(bytes32 left, bytes32 right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bytes32 left, bytes32 right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq32(bytes32 left, bytes32 right) internal pure virtual { - assertNotEq(left, right); - } - - function assertNotEq32(bytes32 left, bytes32 right, string memory err) internal pure virtual { - assertNotEq(left, right, err); - } - - function assertNotEq(string memory left, string memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(string memory left, string memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(bytes memory left, bytes memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bytes memory left, bytes memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(bool[] memory left, bool[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bool[] memory left, bool[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(uint256[] memory left, uint256[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(uint256[] memory left, uint256[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(int256[] memory left, int256[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(int256[] memory left, int256[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(address[] memory left, address[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(address[] memory left, address[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(bytes32[] memory left, bytes32[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bytes32[] memory left, bytes32[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(string[] memory left, string[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(string[] memory left, string[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertNotEq(bytes[] memory left, bytes[] memory right) internal pure virtual { - vm.assertNotEq(left, right); - } - - function assertNotEq(bytes[] memory left, bytes[] memory right, string memory err) internal pure virtual { - vm.assertNotEq(left, right, err); - } - - function assertLt(uint256 left, uint256 right) internal pure virtual { - vm.assertLt(left, right); - } - - function assertLt(uint256 left, uint256 right, string memory err) internal pure virtual { - vm.assertLt(left, right, err); - } - - function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertLtDecimal(left, right, decimals); - } - - function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertLtDecimal(left, right, decimals, err); - } - - function assertLt(int256 left, int256 right) internal pure virtual { - vm.assertLt(left, right); - } - - function assertLt(int256 left, int256 right, string memory err) internal pure virtual { - vm.assertLt(left, right, err); - } - - function assertLtDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertLtDecimal(left, right, decimals); - } - - function assertLtDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertLtDecimal(left, right, decimals, err); - } - - function assertGt(uint256 left, uint256 right) internal pure virtual { - vm.assertGt(left, right); - } - - function assertGt(uint256 left, uint256 right, string memory err) internal pure virtual { - vm.assertGt(left, right, err); - } - - function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertGtDecimal(left, right, decimals); - } - - function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertGtDecimal(left, right, decimals, err); - } - - function assertGt(int256 left, int256 right) internal pure virtual { - vm.assertGt(left, right); - } - - function assertGt(int256 left, int256 right, string memory err) internal pure virtual { - vm.assertGt(left, right, err); - } - - function assertGtDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertGtDecimal(left, right, decimals); - } - - function assertGtDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertGtDecimal(left, right, decimals, err); - } - - function assertLe(uint256 left, uint256 right) internal pure virtual { - vm.assertLe(left, right); - } - - function assertLe(uint256 left, uint256 right, string memory err) internal pure virtual { - vm.assertLe(left, right, err); - } - - function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertLeDecimal(left, right, decimals); - } - - function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertLeDecimal(left, right, decimals, err); - } - - function assertLe(int256 left, int256 right) internal pure virtual { - vm.assertLe(left, right); - } - - function assertLe(int256 left, int256 right, string memory err) internal pure virtual { - vm.assertLe(left, right, err); - } - - function assertLeDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertLeDecimal(left, right, decimals); - } - - function assertLeDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertLeDecimal(left, right, decimals, err); - } - - function assertGe(uint256 left, uint256 right) internal pure virtual { - vm.assertGe(left, right); - } - - function assertGe(uint256 left, uint256 right, string memory err) internal pure virtual { - vm.assertGe(left, right, err); - } - - function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual { - vm.assertGeDecimal(left, right, decimals); - } - - function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertGeDecimal(left, right, decimals, err); - } - - function assertGe(int256 left, int256 right) internal pure virtual { - vm.assertGe(left, right); - } - - function assertGe(int256 left, int256 right, string memory err) internal pure virtual { - vm.assertGe(left, right, err); - } - - function assertGeDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual { - vm.assertGeDecimal(left, right, decimals); - } - - function assertGeDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual { - vm.assertGeDecimal(left, right, decimals, err); - } - - function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) internal pure virtual { - vm.assertApproxEqAbs(left, right, maxDelta); - } - - function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string memory err) - internal - pure - virtual - { - vm.assertApproxEqAbs(left, right, maxDelta, err); - } - - function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) - internal - pure - virtual - { - vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals); - } - - function assertApproxEqAbsDecimal( - uint256 left, - uint256 right, - uint256 maxDelta, - uint256 decimals, - string memory err - ) internal pure virtual { - vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals, err); - } - - function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) internal pure virtual { - vm.assertApproxEqAbs(left, right, maxDelta); - } - - function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string memory err) internal pure virtual { - vm.assertApproxEqAbs(left, right, maxDelta, err); - } - - function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) - internal - pure - virtual - { - vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals); - } - - function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals, string memory err) - internal - pure - virtual - { - vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals, err); - } - - function assertApproxEqRel( - uint256 left, - uint256 right, - uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% - ) internal pure virtual { - vm.assertApproxEqRel(left, right, maxPercentDelta); - } - - function assertApproxEqRel( - uint256 left, - uint256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - string memory err - ) internal pure virtual { - vm.assertApproxEqRel(left, right, maxPercentDelta, err); - } - - function assertApproxEqRelDecimal( - uint256 left, - uint256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - uint256 decimals - ) internal pure virtual { - vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals); - } - - function assertApproxEqRelDecimal( - uint256 left, - uint256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - uint256 decimals, - string memory err - ) internal pure virtual { - vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals, err); - } - - function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) internal pure virtual { - vm.assertApproxEqRel(left, right, maxPercentDelta); - } - - function assertApproxEqRel( - int256 left, - int256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - string memory err - ) internal pure virtual { - vm.assertApproxEqRel(left, right, maxPercentDelta, err); - } - - function assertApproxEqRelDecimal( - int256 left, - int256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - uint256 decimals - ) internal pure virtual { - vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals); - } - - function assertApproxEqRelDecimal( - int256 left, - int256 right, - uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% - uint256 decimals, - string memory err - ) internal pure virtual { - vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals, err); - } - - // Inhertied from DSTest, not used but kept for backwards-compatibility - function checkEq0(bytes memory left, bytes memory right) internal pure returns (bool) { - return keccak256(left) == keccak256(right); - } - - function assertEq0(bytes memory left, bytes memory right) internal pure virtual { - assertEq(left, right); - } - - function assertEq0(bytes memory left, bytes memory right, string memory err) internal pure virtual { - assertEq(left, right, err); - } - - function assertNotEq0(bytes memory left, bytes memory right) internal pure virtual { - assertNotEq(left, right); - } - - function assertNotEq0(bytes memory left, bytes memory right, string memory err) internal pure virtual { - assertNotEq(left, right, err); - } - - 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); - revert("assertion failed"); - } - - 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); - revert("assertion failed"); - } - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdChains.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdChains.sol deleted file mode 100644 index 27e1bf2..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdChains.sol +++ /dev/null @@ -1,250 +0,0 @@ -// 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 - 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) { - 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' - // The upstream error thrown by forge for failing cheats changed so we check both the old and new versions - bytes memory oldNotFoundError = - abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias))); - bytes memory newNotFoundError = abi.encodeWithSignature( - "CheatcodeError(string)", string(abi.encodePacked("invalid rpc url: ", chainAlias)) - ); - bytes32 errHash = keccak256(err); - if ( - (errHash != keccak256(oldNotFoundError) && errHash != keccak256(newNotFoundError)) - || 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://eth-mainnet.alchemyapi.io/v2/pwc5rmJhrdoaSEfimoKEmsvOjKSmPDrP") - ); - 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")); - setChainWithDefaultRpcUrl("fraxtal", ChainData("Fraxtal", 252, "https://rpc.frax.com")); - setChainWithDefaultRpcUrl("fraxtal_testnet", ChainData("Fraxtal Testnet", 2522, "https://rpc.testnet.frax.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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdCheats.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdCheats.sol deleted file mode 100644 index f293313..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdCheats.sol +++ /dev/null @@ -1,817 +0,0 @@ -// 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_StdCheats("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_StdCheats(string memory p0) private view { - (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string)", p0)); - status; - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdError.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdError.sol deleted file mode 100644 index a302191..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdError.sol +++ /dev/null @@ -1,15 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdInvariant.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdInvariant.sol deleted file mode 100644 index bcd9ac0..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdInvariant.sol +++ /dev/null @@ -1,107 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdJson.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdJson.sol deleted file mode 100644 index 6dbde83..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdJson.sol +++ /dev/null @@ -1,179 +0,0 @@ -// 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(""); -// json.readUint(""); -// ``` -// To write: -// ``` -// using stdJson for string; -// string memory json = "json"; -// json.serialize("a", uint256(123)); -// string memory semiFinal = json.serialize("b", string("test")); -// string memory finalJson = json.serialize("c", semiFinal); -// finalJson.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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdMath.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdMath.sol deleted file mode 100644 index 459523b..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdMath.sol +++ /dev/null @@ -1,43 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStorage.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStorage.sol deleted file mode 100644 index ffd668c..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStorage.sol +++ /dev/null @@ -1,473 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2 <0.9.0; - -import {Vm} from "./Vm.sol"; - -struct FindData { - uint256 slot; - uint256 offsetLeft; - uint256 offsetRight; - bool found; -} - -struct StdStorage { - mapping(address => mapping(bytes4 => mapping(bytes32 => FindData))) finds; - bytes32[] _keys; - bytes4 _sig; - uint256 _depth; - address _target; - bytes32 _set; - bool _enable_packed_slots; - bytes _calldata; -} - -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"))))); - uint256 constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935; - - function sigs(string memory sigStr) internal pure returns (bytes4) { - return bytes4(keccak256(bytes(sigStr))); - } - - function getCallParams(StdStorage storage self) internal view returns (bytes memory) { - if (self._calldata.length == 0) { - return flatten(self._keys); - } else { - return self._calldata; - } - } - - // Calls target contract with configured parameters - function callTarget(StdStorage storage self) internal view returns (bool, bytes32) { - bytes memory cald = abi.encodePacked(self._sig, getCallParams(self)); - (bool success, bytes memory rdat) = self._target.staticcall(cald); - bytes32 result = bytesToBytes32(rdat, 32 * self._depth); - - return (success, result); - } - - // Tries mutating slot value to determine if the targeted value is stored in it. - // If current value is 0, then we are setting slot value to type(uint256).max - // Otherwise, we set it to 0. That way, return value should always be affected. - function checkSlotMutatesCall(StdStorage storage self, bytes32 slot) internal returns (bool) { - bytes32 prevSlotValue = vm.load(self._target, slot); - (bool success, bytes32 prevReturnValue) = callTarget(self); - - bytes32 testVal = prevReturnValue == bytes32(0) ? bytes32(UINT256_MAX) : bytes32(0); - vm.store(self._target, slot, testVal); - - (, bytes32 newReturnValue) = callTarget(self); - - vm.store(self._target, slot, prevSlotValue); - - return (success && (prevReturnValue != newReturnValue)); - } - - // Tries setting one of the bits in slot to 1 until return value changes. - // Index of resulted bit is an offset packed slot has from left/right side - function findOffset(StdStorage storage self, bytes32 slot, bool left) internal returns (bool, uint256) { - for (uint256 offset = 0; offset < 256; offset++) { - uint256 valueToPut = left ? (1 << (255 - offset)) : (1 << offset); - vm.store(self._target, slot, bytes32(valueToPut)); - - (bool success, bytes32 data) = callTarget(self); - - if (success && (uint256(data) > 0)) { - return (true, offset); - } - } - return (false, 0); - } - - function findOffsets(StdStorage storage self, bytes32 slot) internal returns (bool, uint256, uint256) { - bytes32 prevSlotValue = vm.load(self._target, slot); - - (bool foundLeft, uint256 offsetLeft) = findOffset(self, slot, true); - (bool foundRight, uint256 offsetRight) = findOffset(self, slot, false); - - // `findOffset` may mutate slot value, so we are setting it to initial value - vm.store(self._target, slot, prevSlotValue); - return (foundLeft && foundRight, offsetLeft, offsetRight); - } - - function find(StdStorage storage self) internal returns (FindData storage) { - return find(self, true); - } - - /// @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, bool _clear) internal returns (FindData storage) { - address who = self._target; - bytes4 fsig = self._sig; - uint256 field_depth = self._depth; - bytes memory params = getCallParams(self); - - // calldata to test against - if (self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found) { - if (_clear) { - clear(self); - } - return self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))]; - } - vm.record(); - (, bytes32 callResult) = callTarget(self); - (bytes32[] memory reads,) = vm.accesses(address(who)); - - if (reads.length == 0) { - revert("stdStorage find(StdStorage): No storage use detected for target."); - } else { - 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 (!checkSlotMutatesCall(self, reads[i])) { - continue; - } - - (uint256 offsetLeft, uint256 offsetRight) = (0, 0); - - if (self._enable_packed_slots) { - bool found; - (found, offsetLeft, offsetRight) = findOffsets(self, reads[i]); - if (!found) { - continue; - } - } - - // Check that value between found offsets is equal to the current call result - uint256 curVal = (uint256(prev) & getMaskByOffsets(offsetLeft, offsetRight)) >> offsetRight; - - if (uint256(callResult) != curVal) { - continue; - } - - emit SlotFound(who, fsig, keccak256(abi.encodePacked(params, field_depth)), uint256(reads[i])); - self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))] = - FindData(uint256(reads[i]), offsetLeft, offsetRight, true); - break; - } - } - - require( - self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found, - "stdStorage find(StdStorage): Slot(s) not found." - ); - - if (_clear) { - clear(self); - } - return self.finds[who][fsig][keccak256(abi.encodePacked(params, 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_calldata(StdStorage storage self, bytes memory _calldata) internal returns (StdStorage storage) { - self._calldata = _calldata; - 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 enable_packed_slots(StdStorage storage self) internal returns (StdStorage storage) { - self._enable_packed_slots = true; - 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) { - FindData storage data = find(self, false); - uint256 mask = getMaskByOffsets(data.offsetLeft, data.offsetRight); - uint256 value = (uint256(vm.load(self._target, bytes32(data.slot))) & mask) >> data.offsetRight; - clear(self); - return abi.encode(value); - } - - 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, true).slot - 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, true).slot - 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; - } - - function clear(StdStorage storage self) internal { - delete self._target; - delete self._sig; - delete self._keys; - delete self._depth; - delete self._enable_packed_slots; - delete self._calldata; - } - - // Returns mask which contains non-zero bits for values between `offsetLeft` and `offsetRight` - // (slotValue & mask) >> offsetRight will be the value of the given packed variable - function getMaskByOffsets(uint256 offsetLeft, uint256 offsetRight) internal pure returns (uint256 mask) { - // mask = ((1 << (256 - (offsetRight + offsetLeft))) - 1) << offsetRight; - // using assembly because (1 << 256) causes overflow - assembly { - mask := shl(offsetRight, sub(shl(sub(256, add(offsetRight, offsetLeft)), 1), 1)) - } - } - - // Returns slot value with updated packed variable. - function getUpdatedSlotValue(bytes32 curValue, uint256 varValue, uint256 offsetLeft, uint256 offsetRight) - internal - pure - returns (bytes32 newValue) - { - return bytes32((uint256(curValue) & ~getMaskByOffsets(offsetLeft, offsetRight)) | (varValue << offsetRight)); - } -} - -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 find(self, true); - } - - function find(StdStorage storage self, bool _clear) internal returns (uint256) { - return stdStorageSafe.find(self, _clear).slot; - } - - 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 with_calldata(StdStorage storage self, bytes memory _calldata) internal returns (StdStorage storage) { - return stdStorageSafe.with_calldata(self, _calldata); - } - - function enable_packed_slots(StdStorage storage self) internal returns (StdStorage storage) { - return stdStorageSafe.enable_packed_slots(self); - } - - function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { - return stdStorageSafe.depth(self, _depth); - } - - function clear(StdStorage storage self) internal { - stdStorageSafe.clear(self); - } - - 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; - bytes memory params = stdStorageSafe.getCallParams(self); - - if (!self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found) { - find(self, false); - } - FindData storage data = self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))]; - if ((data.offsetLeft + data.offsetRight) > 0) { - uint256 maxVal = 2 ** (256 - (data.offsetLeft + data.offsetRight)); - require( - uint256(set) < maxVal, - string( - abi.encodePacked( - "stdStorage find(StdStorage): Packed slot. We can't fit value greater than ", - vm.toString(maxVal) - ) - ) - ); - } - bytes32 curVal = vm.load(who, bytes32(data.slot)); - bytes32 valToSet = stdStorageSafe.getUpdatedSlotValue(curVal, uint256(set), data.offsetLeft, data.offsetRight); - - vm.store(who, bytes32(data.slot), valToSet); - - (bool success, bytes32 callResult) = stdStorageSafe.callTarget(self); - - if (!success || callResult != set) { - vm.store(who, bytes32(data.slot), curVal); - revert("stdStorage find(StdStorage): Failed to write value."); - } - clear(self); - } - - 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); - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStyle.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStyle.sol deleted file mode 100644 index d371e0c..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdStyle.sol +++ /dev/null @@ -1,333 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdToml.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdToml.sol deleted file mode 100644 index ef88db6..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdToml.sol +++ /dev/null @@ -1,179 +0,0 @@ -// 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 TOML files -// To parse: -// ``` -// using stdToml for string; -// string memory toml = vm.readFile(""); -// toml.readUint(""); -// ``` -// To write: -// ``` -// using stdToml for string; -// string memory json = "json"; -// json.serialize("a", uint256(123)); -// string memory semiFinal = json.serialize("b", string("test")); -// string memory finalJson = json.serialize("c", semiFinal); -// finalJson.write(""); -// ``` - -library stdToml { - VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); - - function parseRaw(string memory toml, string memory key) internal pure returns (bytes memory) { - return vm.parseToml(toml, key); - } - - function readUint(string memory toml, string memory key) internal pure returns (uint256) { - return vm.parseTomlUint(toml, key); - } - - function readUintArray(string memory toml, string memory key) internal pure returns (uint256[] memory) { - return vm.parseTomlUintArray(toml, key); - } - - function readInt(string memory toml, string memory key) internal pure returns (int256) { - return vm.parseTomlInt(toml, key); - } - - function readIntArray(string memory toml, string memory key) internal pure returns (int256[] memory) { - return vm.parseTomlIntArray(toml, key); - } - - function readBytes32(string memory toml, string memory key) internal pure returns (bytes32) { - return vm.parseTomlBytes32(toml, key); - } - - function readBytes32Array(string memory toml, string memory key) internal pure returns (bytes32[] memory) { - return vm.parseTomlBytes32Array(toml, key); - } - - function readString(string memory toml, string memory key) internal pure returns (string memory) { - return vm.parseTomlString(toml, key); - } - - function readStringArray(string memory toml, string memory key) internal pure returns (string[] memory) { - return vm.parseTomlStringArray(toml, key); - } - - function readAddress(string memory toml, string memory key) internal pure returns (address) { - return vm.parseTomlAddress(toml, key); - } - - function readAddressArray(string memory toml, string memory key) internal pure returns (address[] memory) { - return vm.parseTomlAddressArray(toml, key); - } - - function readBool(string memory toml, string memory key) internal pure returns (bool) { - return vm.parseTomlBool(toml, key); - } - - function readBoolArray(string memory toml, string memory key) internal pure returns (bool[] memory) { - return vm.parseTomlBoolArray(toml, key); - } - - function readBytes(string memory toml, string memory key) internal pure returns (bytes memory) { - return vm.parseTomlBytes(toml, key); - } - - function readBytesArray(string memory toml, string memory key) internal pure returns (bytes[] memory) { - return vm.parseTomlBytesArray(toml, 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.writeToml(jsonKey, path); - } - - function write(string memory jsonKey, string memory path, string memory valueKey) internal { - vm.writeToml(jsonKey, path, valueKey); - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdUtils.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdUtils.sol deleted file mode 100644 index 0f61305..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/StdUtils.sol +++ /dev/null @@ -1,226 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2 <0.9.0; - -pragma experimental ABIEncoderV2; - -import {IMulticall3} from "./interfaces/IMulticall3.sol"; -import {MockERC20} from "./mocks/MockERC20.sol"; -import {MockERC721} from "./mocks/MockERC721.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 pure virtual returns (uint256 result) { - result = _bound(x, min, max); - console2_log_StdUtils("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 pure virtual returns (int256 result) { - result = _bound(x, min, max); - console2_log_StdUtils("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) { - console2_log_StdUtils("computeCreateAddress is deprecated. Please use vm.computeCreateAddress instead."); - return vm.computeCreateAddress(deployer, nonce); - } - - function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) - internal - pure - virtual - returns (address) - { - console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead."); - return vm.computeCreate2Address(salt, initcodeHash, deployer); - } - - /// @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) { - console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead."); - return vm.computeCreate2Address(salt, initCodeHash); - } - - /// @dev returns an initialized mock ERC20 contract - function deployMockERC20(string memory name, string memory symbol, uint8 decimals) - internal - returns (MockERC20 mock) - { - mock = new MockERC20(); - mock.initialize(name, symbol, decimals); - } - - /// @dev returns an initialized mock ERC721 contract - function deployMockERC721(string memory name, string memory symbol) internal returns (MockERC721 mock) { - mock = new MockERC721(); - mock.initialize(name, symbol); - } - - /// @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))); - } - - // This section is used to prevent the compilation of console, which shortens the compilation time when console is - // not used elsewhere. We also trick the compiler into letting us make the console log methods as `pure` to avoid - // any breaking changes to function signatures. - 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 = CONSOLE2_ADDRESS; - /// @solidity memory-safe-assembly - assembly { - let payloadStart := add(payload, 32) - let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) - } - } - - function console2_log_StdUtils(string memory p0) private pure { - _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); - } - - function console2_log_StdUtils(string memory p0, uint256 p1) private pure { - _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); - } - - function console2_log_StdUtils(string memory p0, string memory p1) private pure { - _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Test.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Test.sol deleted file mode 100644 index 5ff60ea..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Test.sol +++ /dev/null @@ -1,33 +0,0 @@ -// 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 {stdToml} from "./StdToml.sol"; -import {StdUtils} from "./StdUtils.sol"; -import {Vm} from "./Vm.sol"; - -// 📦 BOILERPLATE -import {TestBase} from "./Base.sol"; - -// ⭐️ TEST -abstract contract Test is TestBase, StdAssertions, StdChains, StdCheats, StdInvariant, StdUtils { - // Note: IS_TEST() must return true. - bool public IS_TEST = true; -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Vm.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Vm.sol deleted file mode 100644 index 313d020..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/Vm.sol +++ /dev/null @@ -1,1638 +0,0 @@ -// Automatically @generated by scripts/vm.py. Do not modify manually. - -// SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity >=0.6.2 <0.9.0; -pragma experimental ABIEncoderV2; - -/// 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 { - /// A modification applied to either `msg.sender` or `tx.origin`. Returned by `readCallers`. - enum CallerMode { - // No caller modification is currently active. - None, - // A one time broadcast triggered by a `vm.broadcast()` call is currently active. - Broadcast, - // A recurrent broadcast triggered by a `vm.startBroadcast()` call is currently active. - RecurrentBroadcast, - // A one time prank triggered by a `vm.prank()` call is currently active. - Prank, - // A recurrent prank triggered by a `vm.startPrank()` call is currently active. - RecurrentPrank - } - - /// The kind of account access that occurred. - enum AccountAccessKind { - // The account was called. - Call, - // The account was called via delegatecall. - DelegateCall, - // The account was called via callcode. - CallCode, - // The account was called via staticcall. - StaticCall, - // The account was created. - Create, - // The account was selfdestructed. - SelfDestruct, - // Synthetic access indicating the current context has resumed after a previous sub-context (AccountAccess). - Resume, - // The account's balance was read. - Balance, - // The account's codesize was read. - Extcodesize, - // The account's codehash was read. - Extcodehash, - // The account's code was copied. - Extcodecopy - } - - /// An Ethereum log. Returned by `getRecordedLogs`. - struct Log { - // The topics of the log, including the signature, if any. - bytes32[] topics; - // The raw data of the log. - bytes data; - // The address of the log's emitter. - address emitter; - } - - /// An RPC URL and its alias. Returned by `rpcUrlStructs`. - struct Rpc { - // The alias of the RPC URL. - string key; - // The RPC URL. - string url; - } - - /// An RPC log object. Returned by `eth_getLogs`. - struct EthGetLogs { - // The address of the log's emitter. - address emitter; - // The topics of the log, including the signature, if any. - bytes32[] topics; - // The raw data of the log. - bytes data; - // The block hash. - bytes32 blockHash; - // The block number. - uint64 blockNumber; - // The transaction hash. - bytes32 transactionHash; - // The transaction index in the block. - uint64 transactionIndex; - // The log index. - uint256 logIndex; - // Whether the log was removed. - bool removed; - } - - /// A single entry in a directory listing. Returned by `readDir`. - struct DirEntry { - // The error message, if any. - string errorMessage; - // The path of the entry. - string path; - // The depth of the entry. - uint64 depth; - // Whether the entry is a directory. - bool isDir; - // Whether the entry is a symlink. - bool isSymlink; - } - - /// Metadata information about a file. - /// This structure is returned from the `fsMetadata` function and represents known - /// metadata about a file such as its permissions, size, modification - /// times, etc. - struct FsMetadata { - // True if this metadata is for a directory. - bool isDir; - // True if this metadata is for a symlink. - bool isSymlink; - // The size of the file, in bytes, this metadata is for. - uint256 length; - // True if this metadata is for a readonly (unwritable) file. - bool readOnly; - // The last modification time listed in this metadata. - uint256 modified; - // The last access time of this metadata. - uint256 accessed; - // The creation time listed in this metadata. - uint256 created; - } - - /// A wallet with a public and private key. - struct Wallet { - // The wallet's address. - address addr; - // The wallet's public key `X`. - uint256 publicKeyX; - // The wallet's public key `Y`. - uint256 publicKeyY; - // The wallet's private key. - uint256 privateKey; - } - - /// The result of a `tryFfi` call. - struct FfiResult { - // The exit code of the call. - int32 exitCode; - // The optionally hex-decoded `stdout` data. - bytes stdout; - // The `stderr` data. - bytes stderr; - } - - /// Information on the chain and fork. - struct ChainInfo { - // The fork identifier. Set to zero if no fork is active. - uint256 forkId; - // The chain ID of the current fork. - uint256 chainId; - } - - /// The result of a `stopAndReturnStateDiff` call. - struct AccountAccess { - // The chain and fork the access occurred. - ChainInfo chainInfo; - // The kind of account access that determines what the account is. - // If kind is Call, DelegateCall, StaticCall or CallCode, then the account is the callee. - // If kind is Create, then the account is the newly created account. - // If kind is SelfDestruct, then the account is the selfdestruct recipient. - // If kind is a Resume, then account represents a account context that has resumed. - AccountAccessKind kind; - // The account that was accessed. - // It's either the account created, callee or a selfdestruct recipient for CREATE, CALL or SELFDESTRUCT. - address account; - // What accessed the account. - address accessor; - // If the account was initialized or empty prior to the access. - // An account is considered initialized if it has code, a - // non-zero nonce, or a non-zero balance. - bool initialized; - // The previous balance of the accessed account. - uint256 oldBalance; - // The potential new balance of the accessed account. - // That is, all balance changes are recorded here, even if reverts occurred. - uint256 newBalance; - // Code of the account deployed by CREATE. - bytes deployedCode; - // Value passed along with the account access - uint256 value; - // Input data provided to the CREATE or CALL - bytes data; - // If this access reverted in either the current or parent context. - bool reverted; - // An ordered list of storage accesses made during an account access operation. - StorageAccess[] storageAccesses; - // Call depth traversed during the recording of state differences - uint64 depth; - } - - /// The storage accessed during an `AccountAccess`. - struct StorageAccess { - // The account whose storage was accessed. - address account; - // The slot that was accessed. - bytes32 slot; - // If the access was a write. - bool isWrite; - // The previous value of the slot. - bytes32 previousValue; - // The new value of the slot. - bytes32 newValue; - // If the access was reverted. - bool reverted; - } - - // ======== Environment ======== - - /// Gets the environment variable `name` and parses it as `address`. - /// Reverts if the variable was not found or could not be parsed. - function envAddress(string calldata name) external view returns (address value); - - /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value); - - /// Gets the environment variable `name` and parses it as `bool`. - /// Reverts if the variable was not found or could not be parsed. - function envBool(string calldata name) external view returns (bool value); - - /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value); - - /// Gets the environment variable `name` and parses it as `bytes32`. - /// Reverts if the variable was not found or could not be parsed. - function envBytes32(string calldata name) external view returns (bytes32 value); - - /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value); - - /// Gets the environment variable `name` and parses it as `bytes`. - /// Reverts if the variable was not found or could not be parsed. - function envBytes(string calldata name) external view returns (bytes memory value); - - /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value); - - /// Gets the environment variable `name` and parses it as `int256`. - /// Reverts if the variable was not found or could not be parsed. - function envInt(string calldata name) external view returns (int256 value); - - /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value); - - /// Gets the environment variable `name` and parses it as `bool`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, bool defaultValue) external view returns (bool value); - - /// Gets the environment variable `name` and parses it as `uint256`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, uint256 defaultValue) external view returns (uint256 value); - - /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, address[] calldata defaultValue) - external - view - returns (address[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue) - external - view - returns (bytes32[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, string[] calldata defaultValue) - external - view - returns (string[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue) - external - view - returns (bytes[] memory value); - - /// Gets the environment variable `name` and parses it as `int256`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, int256 defaultValue) external view returns (int256 value); - - /// Gets the environment variable `name` and parses it as `address`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, address defaultValue) external view returns (address value); - - /// Gets the environment variable `name` and parses it as `bytes32`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, bytes32 defaultValue) external view returns (bytes32 value); - - /// Gets the environment variable `name` and parses it as `string`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata defaultValue) external view returns (string memory value); - - /// Gets the environment variable `name` and parses it as `bytes`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, bytes calldata defaultValue) external view returns (bytes memory value); - - /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue) - external - view - returns (bool[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue) - external - view - returns (uint256[] memory value); - - /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`. - /// Reverts if the variable could not be parsed. - /// Returns `defaultValue` if the variable was not found. - function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue) - external - view - returns (int256[] memory value); - - /// Gets the environment variable `name` and parses it as `string`. - /// Reverts if the variable was not found or could not be parsed. - function envString(string calldata name) external view returns (string memory value); - - /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envString(string calldata name, string calldata delim) external view returns (string[] memory value); - - /// Gets the environment variable `name` and parses it as `uint256`. - /// Reverts if the variable was not found or could not be parsed. - function envUint(string calldata name) external view returns (uint256 value); - - /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`. - /// Reverts if the variable was not found or could not be parsed. - function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value); - - /// Sets environment variables. - function setEnv(string calldata name, string calldata value) external; - - // ======== EVM ======== - - /// 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); - - /// Gets the address for a given private key. - function addr(uint256 privateKey) external pure returns (address keyAddr); - - /// Gets all the logs according to specified filter. - function eth_getLogs(uint256 fromBlock, uint256 toBlock, address target, bytes32[] calldata topics) - external - returns (EthGetLogs[] memory logs); - - /// Gets the current `block.number`. - /// You should use this instead of `block.number` if you use `vm.roll`, as `block.number` is assumed to be constant across a transaction, - /// and as a result will get optimized out by the compiler. - /// See https://github.com/foundry-rs/foundry/issues/6180 - function getBlockNumber() external view returns (uint256 height); - - /// Gets the current `block.timestamp`. - /// You should use this instead of `block.timestamp` if you use `vm.warp`, as `block.timestamp` is assumed to be constant across a transaction, - /// and as a result will get optimized out by the compiler. - /// See https://github.com/foundry-rs/foundry/issues/6180 - function getBlockTimestamp() external view returns (uint256 timestamp); - - /// 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); - - /// 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 nonce of an account. - function getNonce(address account) external view returns (uint64 nonce); - - /// Gets all the recorded logs. - function getRecordedLogs() external returns (Log[] memory logs); - - /// Loads a storage slot from an address. - function load(address target, bytes32 slot) external view returns (bytes32 data); - - /// Pauses gas metering (i.e. gas usage is not counted). Noop if already paused. - function pauseGasMetering() external; - - /// Records all storage reads and writes. - function record() external; - - /// Record all the transaction logs. - function recordLogs() external; - - /// Resumes gas metering (i.e. gas usage is counted again). Noop if already on. - function resumeGasMetering() external; - - /// Performs an Ethereum JSON-RPC request to the current fork URL. - function rpc(string calldata method, string calldata params) external returns (bytes memory data); - - /// Signs `digest` with `privateKey` using the secp256r1 curve. - function signP256(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 s); - - /// Signs `digest` with `privateKey` using the secp256k1 curve. - function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); - - /// Starts recording all map SSTOREs for later retrieval. - function startMappingRecording() external; - - /// Record all account accesses as part of CREATE, CALL or SELFDESTRUCT opcodes in order, - /// along with the context of the calls - function startStateDiffRecording() external; - - /// Returns an ordered array of all account accesses from a `vm.startStateDiffRecording` session. - function stopAndReturnStateDiff() external returns (AccountAccess[] memory accountAccesses); - - /// Stops recording all map SSTOREs for later retrieval and clears the recorded data. - function stopMappingRecording() external; - - // ======== Filesystem ======== - - /// 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; - - /// Returns true if the given path points to an existing entity, else returns false. - function exists(string calldata path) external returns (bool result); - - /// Performs a foreign function call via the terminal. - function ffi(string[] calldata commandInput) external returns (bytes memory 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); - - /// 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); - - /// 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); - - /// Reads the directory at the given path recursively, up to `maxDepth`. - /// `maxDepth` defaults to 1, meaning only the direct children of the given directory will be returned. - /// Follows symbolic links if `followLinks` is true. - function readDir(string calldata path) external view returns (DirEntry[] memory entries); - - /// See `readDir(string)`. - function readDir(string calldata path, uint64 maxDepth) external view returns (DirEntry[] memory entries); - - /// See `readDir(string)`. - 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; - - /// 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); - - /// Returns the time since unix epoch in milliseconds. - function unixTime() external returns (uint256 milliseconds); - - /// 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; - - // ======== JSON ======== - - /// Checks if `key` exists in a JSON object - /// `keyExists` is being deprecated in favor of `keyExistsJson`. It will be removed in future versions. - function keyExists(string calldata json, string calldata key) external view returns (bool); - - /// Checks if `key` exists in a JSON object. - function keyExistsJson(string calldata json, string calldata key) external view returns (bool); - - /// Parses a string of JSON data at `key` and coerces it to `address`. - function parseJsonAddress(string calldata json, string calldata key) external pure returns (address); - - /// Parses a string of JSON data at `key` and coerces it to `address[]`. - function parseJsonAddressArray(string calldata json, string calldata key) - external - pure - returns (address[] memory); - - /// Parses a string of JSON data at `key` and coerces it to `bool`. - function parseJsonBool(string calldata json, string calldata key) external pure returns (bool); - - /// Parses a string of JSON data at `key` and coerces it to `bool[]`. - function parseJsonBoolArray(string calldata json, string calldata key) external pure returns (bool[] memory); - - /// Parses a string of JSON data at `key` and coerces it to `bytes`. - function parseJsonBytes(string calldata json, string calldata key) external pure returns (bytes memory); - - /// Parses a string of JSON data at `key` and coerces it to `bytes32`. - function parseJsonBytes32(string calldata json, string calldata key) external pure returns (bytes32); - - /// Parses a string of JSON data at `key` and coerces it to `bytes32[]`. - function parseJsonBytes32Array(string calldata json, string calldata key) - external - pure - returns (bytes32[] memory); - - /// Parses a string of JSON data at `key` and coerces it to `bytes[]`. - function parseJsonBytesArray(string calldata json, string calldata key) external pure returns (bytes[] memory); - - /// Parses a string of JSON data at `key` and coerces it to `int256`. - function parseJsonInt(string calldata json, string calldata key) external pure returns (int256); - - /// Parses a string of JSON data at `key` and coerces it to `int256[]`. - function parseJsonIntArray(string calldata json, string calldata key) external pure returns (int256[] memory); - - /// Returns an array of all the keys in a JSON object. - function parseJsonKeys(string calldata json, string calldata key) external pure returns (string[] memory keys); - - /// Parses a string of JSON data at `key` and coerces it to `string`. - function parseJsonString(string calldata json, string calldata key) external pure returns (string memory); - - /// Parses a string of JSON data at `key` and coerces it to `string[]`. - function parseJsonStringArray(string calldata json, string calldata key) external pure returns (string[] memory); - - /// Parses a string of JSON data at `key` and coerces it to `uint256`. - function parseJsonUint(string calldata json, string calldata key) external pure returns (uint256); - - /// Parses a string of JSON data at `key` and coerces it to `uint256[]`. - function parseJsonUintArray(string calldata json, string calldata key) external pure returns (uint256[] memory); - - /// ABI-encodes a JSON object. - function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData); - - /// ABI-encodes a JSON object at `key`. - function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData); - - /// See `serializeJson`. - function serializeAddress(string calldata objectKey, string calldata valueKey, address value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBool(string calldata objectKey, string calldata valueKey, bool value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeInt(string calldata objectKey, string calldata valueKey, int256 value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values) - external - returns (string memory json); - - /// Serializes a key and value to a JSON object stored in-memory that can be later written to a file. - /// 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); - - /// See `serializeJson`. - function serializeString(string calldata objectKey, string calldata valueKey, string calldata value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) - external - returns (string memory json); - - /// See `serializeJson`. - function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) - external - returns (string memory json); - - /// 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; - - // ======== Scripting ======== - - /// 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; - - // ======== String ======== - - /// Parses the given `string` into an `address`. - function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue); - - /// Parses the given `string` into a `bool`. - function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue); - - /// Parses the given `string` into `bytes`. - function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue); - - /// Parses the given `string` into a `bytes32`. - function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue); - - /// Parses the given `string` into a `int256`. - function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue); - - /// Parses the given `string` into a `uint256`. - function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue); - - /// Replaces occurrences of `from` in the given `string` with `to`. - function replace(string calldata input, string calldata from, string calldata to) - external - pure - returns (string memory output); - - /// Splits the given `string` into an array of strings divided by the `delimiter`. - function split(string calldata input, string calldata delimiter) external pure returns (string[] memory outputs); - - /// Converts the given `string` value to Lowercase. - function toLowercase(string calldata input) external pure returns (string memory output); - - /// Converts the given value to a `string`. - function toString(address value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(bytes calldata value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(bytes32 value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(bool value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(uint256 value) external pure returns (string memory stringifiedValue); - - /// Converts the given value to a `string`. - function toString(int256 value) external pure returns (string memory stringifiedValue); - - /// Converts the given `string` value to Uppercase. - function toUppercase(string calldata input) external pure returns (string memory output); - - /// Trims leading and trailing whitespace from the given `string` value. - function trim(string calldata input) external pure returns (string memory output); - - // ======== Testing ======== - - /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. - /// Formats values with decimals in failure message. - function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertApproxEqAbsDecimal( - uint256 left, - uint256 right, - uint256 maxDelta, - uint256 decimals, - string calldata error - ) external pure; - - /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. - /// Formats values with decimals in failure message. - function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertApproxEqAbsDecimal( - int256 left, - int256 right, - uint256 maxDelta, - uint256 decimals, - string calldata error - ) external pure; - - /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. - function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) external pure; - - /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`. - /// Includes error message into revert string on failure. - function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string calldata error) external pure; - - /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. - function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) external pure; - - /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`. - /// Includes error message into revert string on failure. - function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string calldata error) external pure; - - /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Formats values with decimals in failure message. - function assertApproxEqRelDecimal(uint256 left, uint256 right, uint256 maxPercentDelta, uint256 decimals) - external - pure; - - /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertApproxEqRelDecimal( - uint256 left, - uint256 right, - uint256 maxPercentDelta, - uint256 decimals, - string calldata error - ) external pure; - - /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Formats values with decimals in failure message. - function assertApproxEqRelDecimal(int256 left, int256 right, uint256 maxPercentDelta, uint256 decimals) - external - pure; - - /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertApproxEqRelDecimal( - int256 left, - int256 right, - uint256 maxPercentDelta, - uint256 decimals, - string calldata error - ) external pure; - - /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta) external pure; - - /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Includes error message into revert string on failure. - function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta, string calldata error) - external - pure; - - /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) external pure; - - /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`. - /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100% - /// Includes error message into revert string on failure. - function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta, string calldata error) - external - pure; - - /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message. - function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message. - /// Includes error message into revert string on failure. - function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Asserts that two `int256` values are equal, formatting them with decimals in failure message. - function assertEqDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Asserts that two `int256` values are equal, formatting them with decimals in failure message. - /// Includes error message into revert string on failure. - function assertEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Asserts that two `bool` values are equal. - function assertEq(bool left, bool right) external pure; - - /// Asserts that two `bool` values are equal and includes error message into revert string on failure. - function assertEq(bool left, bool right, string calldata error) external pure; - - /// Asserts that two `string` values are equal. - function assertEq(string calldata left, string calldata right) external pure; - - /// Asserts that two `string` values are equal and includes error message into revert string on failure. - function assertEq(string calldata left, string calldata right, string calldata error) external pure; - - /// Asserts that two `bytes` values are equal. - function assertEq(bytes calldata left, bytes calldata right) external pure; - - /// Asserts that two `bytes` values are equal and includes error message into revert string on failure. - function assertEq(bytes calldata left, bytes calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bool` values are equal. - function assertEq(bool[] calldata left, bool[] calldata right) external pure; - - /// Asserts that two arrays of `bool` values are equal and includes error message into revert string on failure. - function assertEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `uint256 values are equal. - function assertEq(uint256[] calldata left, uint256[] calldata right) external pure; - - /// Asserts that two arrays of `uint256` values are equal and includes error message into revert string on failure. - function assertEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `int256` values are equal. - function assertEq(int256[] calldata left, int256[] calldata right) external pure; - - /// Asserts that two arrays of `int256` values are equal and includes error message into revert string on failure. - function assertEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure; - - /// Asserts that two `uint256` values are equal. - function assertEq(uint256 left, uint256 right) external pure; - - /// Asserts that two arrays of `address` values are equal. - function assertEq(address[] calldata left, address[] calldata right) external pure; - - /// Asserts that two arrays of `address` values are equal and includes error message into revert string on failure. - function assertEq(address[] calldata left, address[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bytes32` values are equal. - function assertEq(bytes32[] calldata left, bytes32[] calldata right) external pure; - - /// Asserts that two arrays of `bytes32` values are equal and includes error message into revert string on failure. - function assertEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `string` values are equal. - function assertEq(string[] calldata left, string[] calldata right) external pure; - - /// Asserts that two arrays of `string` values are equal and includes error message into revert string on failure. - function assertEq(string[] calldata left, string[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bytes` values are equal. - function assertEq(bytes[] calldata left, bytes[] calldata right) external pure; - - /// Asserts that two arrays of `bytes` values are equal and includes error message into revert string on failure. - function assertEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure; - - /// Asserts that two `uint256` values are equal and includes error message into revert string on failure. - function assertEq(uint256 left, uint256 right, string calldata error) external pure; - - /// Asserts that two `int256` values are equal. - function assertEq(int256 left, int256 right) external pure; - - /// Asserts that two `int256` values are equal and includes error message into revert string on failure. - function assertEq(int256 left, int256 right, string calldata error) external pure; - - /// Asserts that two `address` values are equal. - function assertEq(address left, address right) external pure; - - /// Asserts that two `address` values are equal and includes error message into revert string on failure. - function assertEq(address left, address right, string calldata error) external pure; - - /// Asserts that two `bytes32` values are equal. - function assertEq(bytes32 left, bytes32 right) external pure; - - /// Asserts that two `bytes32` values are equal and includes error message into revert string on failure. - function assertEq(bytes32 left, bytes32 right, string calldata error) external pure; - - /// Asserts that the given condition is false. - function assertFalse(bool condition) external pure; - - /// Asserts that the given condition is false and includes error message into revert string on failure. - function assertFalse(bool condition, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than or equal to second. - /// Formats values with decimals in failure message. - function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than or equal to second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be greater than or equal to second. - /// Formats values with decimals in failure message. - function assertGeDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects first value to be greater than or equal to second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertGeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than or equal to second. - function assertGe(uint256 left, uint256 right) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than or equal to second. - /// Includes error message into revert string on failure. - function assertGe(uint256 left, uint256 right, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be greater than or equal to second. - function assertGe(int256 left, int256 right) external pure; - - /// Compares two `int256` values. Expects first value to be greater than or equal to second. - /// Includes error message into revert string on failure. - function assertGe(int256 left, int256 right, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than second. - /// Formats values with decimals in failure message. - function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be greater than second. - /// Formats values with decimals in failure message. - function assertGtDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects first value to be greater than second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertGtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than second. - function assertGt(uint256 left, uint256 right) external pure; - - /// Compares two `uint256` values. Expects first value to be greater than second. - /// Includes error message into revert string on failure. - function assertGt(uint256 left, uint256 right, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be greater than second. - function assertGt(int256 left, int256 right) external pure; - - /// Compares two `int256` values. Expects first value to be greater than second. - /// Includes error message into revert string on failure. - function assertGt(int256 left, int256 right, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be less than or equal to second. - /// Formats values with decimals in failure message. - function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects first value to be less than or equal to second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be less than or equal to second. - /// Formats values with decimals in failure message. - function assertLeDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects first value to be less than or equal to second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertLeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be less than or equal to second. - function assertLe(uint256 left, uint256 right) external pure; - - /// Compares two `uint256` values. Expects first value to be less than or equal to second. - /// Includes error message into revert string on failure. - function assertLe(uint256 left, uint256 right, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be less than or equal to second. - function assertLe(int256 left, int256 right) external pure; - - /// Compares two `int256` values. Expects first value to be less than or equal to second. - /// Includes error message into revert string on failure. - function assertLe(int256 left, int256 right, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be less than second. - /// Formats values with decimals in failure message. - function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Compares two `uint256` values. Expects first value to be less than second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be less than second. - /// Formats values with decimals in failure message. - function assertLtDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Compares two `int256` values. Expects first value to be less than second. - /// Formats values with decimals in failure message. Includes error message into revert string on failure. - function assertLtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Compares two `uint256` values. Expects first value to be less than second. - function assertLt(uint256 left, uint256 right) external pure; - - /// Compares two `uint256` values. Expects first value to be less than second. - /// Includes error message into revert string on failure. - function assertLt(uint256 left, uint256 right, string calldata error) external pure; - - /// Compares two `int256` values. Expects first value to be less than second. - function assertLt(int256 left, int256 right) external pure; - - /// Compares two `int256` values. Expects first value to be less than second. - /// Includes error message into revert string on failure. - function assertLt(int256 left, int256 right, string calldata error) external pure; - - /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message. - function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure; - - /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message. - /// Includes error message into revert string on failure. - function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure; - - /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message. - function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) external pure; - - /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message. - /// Includes error message into revert string on failure. - function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure; - - /// Asserts that two `bool` values are not equal. - function assertNotEq(bool left, bool right) external pure; - - /// Asserts that two `bool` values are not equal and includes error message into revert string on failure. - function assertNotEq(bool left, bool right, string calldata error) external pure; - - /// Asserts that two `string` values are not equal. - function assertNotEq(string calldata left, string calldata right) external pure; - - /// Asserts that two `string` values are not equal and includes error message into revert string on failure. - function assertNotEq(string calldata left, string calldata right, string calldata error) external pure; - - /// Asserts that two `bytes` values are not equal. - function assertNotEq(bytes calldata left, bytes calldata right) external pure; - - /// Asserts that two `bytes` values are not equal and includes error message into revert string on failure. - function assertNotEq(bytes calldata left, bytes calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bool` values are not equal. - function assertNotEq(bool[] calldata left, bool[] calldata right) external pure; - - /// Asserts that two arrays of `bool` values are not equal and includes error message into revert string on failure. - function assertNotEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `uint256` values are not equal. - function assertNotEq(uint256[] calldata left, uint256[] calldata right) external pure; - - /// Asserts that two arrays of `uint256` values are not equal and includes error message into revert string on failure. - function assertNotEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `int256` values are not equal. - function assertNotEq(int256[] calldata left, int256[] calldata right) external pure; - - /// Asserts that two arrays of `int256` values are not equal and includes error message into revert string on failure. - function assertNotEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure; - - /// Asserts that two `uint256` values are not equal. - function assertNotEq(uint256 left, uint256 right) external pure; - - /// Asserts that two arrays of `address` values are not equal. - function assertNotEq(address[] calldata left, address[] calldata right) external pure; - - /// Asserts that two arrays of `address` values are not equal and includes error message into revert string on failure. - function assertNotEq(address[] calldata left, address[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bytes32` values are not equal. - function assertNotEq(bytes32[] calldata left, bytes32[] calldata right) external pure; - - /// Asserts that two arrays of `bytes32` values are not equal and includes error message into revert string on failure. - function assertNotEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `string` values are not equal. - function assertNotEq(string[] calldata left, string[] calldata right) external pure; - - /// Asserts that two arrays of `string` values are not equal and includes error message into revert string on failure. - function assertNotEq(string[] calldata left, string[] calldata right, string calldata error) external pure; - - /// Asserts that two arrays of `bytes` values are not equal. - function assertNotEq(bytes[] calldata left, bytes[] calldata right) external pure; - - /// Asserts that two arrays of `bytes` values are not equal and includes error message into revert string on failure. - function assertNotEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure; - - /// Asserts that two `uint256` values are not equal and includes error message into revert string on failure. - function assertNotEq(uint256 left, uint256 right, string calldata error) external pure; - - /// Asserts that two `int256` values are not equal. - function assertNotEq(int256 left, int256 right) external pure; - - /// Asserts that two `int256` values are not equal and includes error message into revert string on failure. - function assertNotEq(int256 left, int256 right, string calldata error) external pure; - - /// Asserts that two `address` values are not equal. - function assertNotEq(address left, address right) external pure; - - /// Asserts that two `address` values are not equal and includes error message into revert string on failure. - function assertNotEq(address left, address right, string calldata error) external pure; - - /// Asserts that two `bytes32` values are not equal. - function assertNotEq(bytes32 left, bytes32 right) external pure; - - /// Asserts that two `bytes32` values are not equal and includes error message into revert string on failure. - function assertNotEq(bytes32 left, bytes32 right, string calldata error) external pure; - - /// Asserts that the given condition is true. - function assertTrue(bool condition) external pure; - - /// Asserts that the given condition is true and includes error message into revert string on failure. - function assertTrue(bool condition, string calldata error) external pure; - - /// 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 as structs. - function rpcUrlStructs() external view returns (Rpc[] memory urls); - - /// Returns all rpc urls and their aliases `[alias, url][]`. - function rpcUrls() external view returns (string[2][] memory urls); - - /// Suspends execution of the main thread for `duration` milliseconds. - function sleep(uint256 duration) external; - - // ======== Toml ======== - - /// Checks if `key` exists in a TOML table. - function keyExistsToml(string calldata toml, string calldata key) external view returns (bool); - - /// Parses a string of TOML data at `key` and coerces it to `address`. - function parseTomlAddress(string calldata toml, string calldata key) external pure returns (address); - - /// Parses a string of TOML data at `key` and coerces it to `address[]`. - function parseTomlAddressArray(string calldata toml, string calldata key) - external - pure - returns (address[] memory); - - /// Parses a string of TOML data at `key` and coerces it to `bool`. - function parseTomlBool(string calldata toml, string calldata key) external pure returns (bool); - - /// Parses a string of TOML data at `key` and coerces it to `bool[]`. - function parseTomlBoolArray(string calldata toml, string calldata key) external pure returns (bool[] memory); - - /// Parses a string of TOML data at `key` and coerces it to `bytes`. - function parseTomlBytes(string calldata toml, string calldata key) external pure returns (bytes memory); - - /// Parses a string of TOML data at `key` and coerces it to `bytes32`. - function parseTomlBytes32(string calldata toml, string calldata key) external pure returns (bytes32); - - /// Parses a string of TOML data at `key` and coerces it to `bytes32[]`. - function parseTomlBytes32Array(string calldata toml, string calldata key) - external - pure - returns (bytes32[] memory); - - /// Parses a string of TOML data at `key` and coerces it to `bytes[]`. - function parseTomlBytesArray(string calldata toml, string calldata key) external pure returns (bytes[] memory); - - /// Parses a string of TOML data at `key` and coerces it to `int256`. - function parseTomlInt(string calldata toml, string calldata key) external pure returns (int256); - - /// Parses a string of TOML data at `key` and coerces it to `int256[]`. - function parseTomlIntArray(string calldata toml, string calldata key) external pure returns (int256[] memory); - - /// Returns an array of all the keys in a TOML table. - function parseTomlKeys(string calldata toml, string calldata key) external pure returns (string[] memory keys); - - /// Parses a string of TOML data at `key` and coerces it to `string`. - function parseTomlString(string calldata toml, string calldata key) external pure returns (string memory); - - /// Parses a string of TOML data at `key` and coerces it to `string[]`. - function parseTomlStringArray(string calldata toml, string calldata key) external pure returns (string[] memory); - - /// Parses a string of TOML data at `key` and coerces it to `uint256`. - function parseTomlUint(string calldata toml, string calldata key) external pure returns (uint256); - - /// Parses a string of TOML data at `key` and coerces it to `uint256[]`. - function parseTomlUintArray(string calldata toml, string calldata key) external pure returns (uint256[] memory); - - /// ABI-encodes a TOML table. - function parseToml(string calldata toml) external pure returns (bytes memory abiEncodedData); - - /// ABI-encodes a TOML table at `key`. - function parseToml(string calldata toml, string calldata key) external pure returns (bytes memory abiEncodedData); - - /// Takes serialized JSON, converts to TOML and write a serialized TOML to a file. - function writeToml(string calldata json, string calldata path) external; - - /// Takes serialized JSON, converts to TOML and write a serialized TOML table to an **existing** TOML file, replacing a value with key = - /// This is useful to replace a specific value of a TOML file, without having to parse the entire thing. - function writeToml(string calldata json, string calldata path, string calldata valueKey) external; - - // ======== Utilities ======== - - /// Compute the address of a contract created with CREATE2 using the given CREATE2 deployer. - function computeCreate2Address(bytes32 salt, bytes32 initCodeHash, address deployer) - external - pure - returns (address); - - /// Compute the address of a contract created with CREATE2 using the default CREATE2 deployer. - function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) external pure returns (address); - - /// Compute the address a contract will be deployed at for a given deployer address and nonce. - function computeCreateAddress(address deployer, uint256 nonce) external pure returns (address); - - /// 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); - - /// 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); - - /// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language - /// at the derivation path `m/44'/60'/0'/0/{index}`. - function deriveKey(string calldata mnemonic, uint32 index, string calldata language) - external - pure - returns (uint256 privateKey); - - /// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language - /// at `{derivationPath}{index}`. - function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index, string calldata language) - external - pure - returns (uint256 privateKey); - - /// Gets the label for the specified address. - function getLabel(address account) external view returns (string memory currentLabel); - - /// Get a `Wallet`'s nonce. - function getNonce(Wallet calldata wallet) external returns (uint64 nonce); - - /// Labels an address in call traces. - function label(address account, string calldata newLabel) external; - - /// Adds a private key to the local forge wallet and returns the address. - function rememberKey(uint256 privateKey) external returns (address keyAddr); - - /// Signs data with a `Wallet`. - function sign(Wallet calldata wallet, bytes32 digest) external returns (uint8 v, bytes32 r, bytes32 s); - - /// Encodes a `bytes` value to a base64url string. - function toBase64URL(bytes calldata data) external pure returns (string memory); - - /// Encodes a `string` value to a base64url string. - function toBase64URL(string calldata data) external pure returns (string memory); - - /// Encodes a `bytes` value to a base64 string. - function toBase64(bytes calldata data) external pure returns (string memory); - - /// Encodes a `string` value to a base64 string. - function toBase64(string calldata data) external pure returns (string memory); -} - -/// 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 ======== - - /// Returns the identifier of the currently active fork. Reverts if no fork is currently active. - function activeFork() external view returns (uint256 forkId); - - /// In forking mode, explicitly grant the given address cheatcode access. - function allowCheatcodes(address account) external; - - /// Sets `block.chainid`. - function chainId(uint256 newChainId) external; - - /// Clears all mocked calls. - function clearMockedCalls() external; - - /// Sets `block.coinbase`. - function coinbase(address newCoinbase) external; - - /// 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 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 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 the latest block and returns the identifier of the fork. - function createSelectFork(string calldata urlOrAlias) 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); - - /// Sets an address' balance. - function deal(address account, uint256 newBalance) external; - - /// Removes the snapshot with the given ID created by `snapshot`. - /// Takes the snapshot ID to delete. - /// Returns `true` if the snapshot was successfully deleted. - /// Returns `false` if the snapshot does not exist. - function deleteSnapshot(uint256 snapshotId) external returns (bool success); - - /// Removes _all_ snapshots previously created by `snapshot`. - function deleteSnapshots() external; - - /// Sets `block.difficulty`. - /// Not available on EVM versions from Paris onwards. Use `prevrandao` instead. - /// Reverts if used on unsupported EVM versions. - function difficulty(uint256 newDifficulty) external; - - /// Dump a genesis JSON file's `allocs` to disk. - function dumpState(string calldata pathToStateJson) external; - - /// Sets an address' code. - function etch(address target, bytes calldata newRuntimeBytecode) external; - - /// Sets `block.basefee`. - function fee(uint256 newBasefee) external; - - /// Returns true if the account is marked as persistent. - function isPersistent(address account) external view returns (bool persistent); - - /// Load a genesis JSON file's `allocs` into the in-memory revm state. - function loadAllocs(string calldata pathToAllocsJson) 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; - - /// See `makePersistent(address)`. - function makePersistent(address account0, address account1) external; - - /// See `makePersistent(address)`. - function makePersistent(address account0, address account1, address account2) external; - - /// See `makePersistent(address)`. - function makePersistent(address[] calldata accounts) 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; - - /// 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; - - /// Sets the *next* call's `msg.sender` to be the input address. - function prank(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 `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; - - /// 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); - - /// Resets the nonce of an account to 0 for EOAs and 1 for contract accounts. - function resetNonce(address account) external; - - /// Revert the state of the EVM to a previous snapshot - /// Takes the snapshot ID to revert to. - /// Returns `true` if the snapshot was successfully reverted. - /// Returns `false` if the snapshot does not exist. - /// **Note:** This does not automatically delete the snapshot. To delete the snapshot use `deleteSnapshot`. - function revertTo(uint256 snapshotId) external returns (bool success); - - /// Revert the state of the EVM to a previous snapshot and automatically deletes the snapshots - /// Takes the snapshot ID to revert to. - /// Returns `true` if the snapshot was successfully reverted and deleted. - /// Returns `false` if the snapshot does not exist. - function revertToAndDelete(uint256 snapshotId) external returns (bool success); - - /// Revokes persistent status from the address, previously added via `makePersistent`. - function revokePersistent(address account) external; - - /// See `revokePersistent(address)`. - function revokePersistent(address[] calldata accounts) external; - - /// Sets `block.height`. - function roll(uint256 newHeight) external; - - /// 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; - - /// 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; - - /// 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); - - /// Sets all subsequent calls' `msg.sender` to be the input address until `stopPrank` is called. - function startPrank(address msgSender) 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; - - /// Stores a value to an address' storage slot. - function store(address target, bytes32 slot, bytes32 value) 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; - - /// Sets `tx.gasprice`. - function txGasPrice(uint256 newGasPrice) external; - - /// Sets `block.timestamp`. - function warp(uint256 newTimestamp) external; - - // ======== Testing ======== - - /// 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; - - /// 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; - - /// 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 with any revert data. - function expectRevert() external; - - /// Expects an error on next call that starts with the revert data. - function expectRevert(bytes4 revertData) external; - - /// Expects an error on next call that exactly matches the revert data. - function expectRevert(bytes calldata revertData) 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; - - /// Stops all safe memory expectation in the current subcontext. - function stopExpectSafeMemory() external; -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/console.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/console.sol deleted file mode 100644 index ad57e53..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/console.sol +++ /dev/null @@ -1,1533 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/console2.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/console2.sol deleted file mode 100644 index c1e2cd7..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/console2.sol +++ /dev/null @@ -1,1558 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC1155.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC1155.sol deleted file mode 100644 index f7dd2b4..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC1155.sol +++ /dev/null @@ -1,105 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC165.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC165.sol deleted file mode 100644 index 9af4bf8..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC165.sol +++ /dev/null @@ -1,12 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC20.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC20.sol deleted file mode 100644 index ba40806..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC20.sol +++ /dev/null @@ -1,43 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC4626.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC4626.sol deleted file mode 100644 index bfe3a11..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC4626.sol +++ /dev/null @@ -1,190 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC721.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC721.sol deleted file mode 100644 index 0a16f45..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IERC721.sol +++ /dev/null @@ -1,164 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IMulticall3.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IMulticall3.sol deleted file mode 100644 index 0d031b7..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/interfaces/IMulticall3.sol +++ /dev/null @@ -1,73 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC20.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC20.sol deleted file mode 100644 index 2a022fa..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC20.sol +++ /dev/null @@ -1,234 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2 <0.9.0; - -import {IERC20} from "../interfaces/IERC20.sol"; - -/// @notice This is a mock contract of the ERC20 standard for testing purposes only, it SHOULD NOT be used in production. -/// @dev Forked from: https://github.com/transmissions11/solmate/blob/0384dbaaa4fcb5715738a9254a7c0a4cb62cf458/src/tokens/ERC20.sol -contract MockERC20 is IERC20 { - /*////////////////////////////////////////////////////////////// - METADATA STORAGE - //////////////////////////////////////////////////////////////*/ - - string internal _name; - - string internal _symbol; - - uint8 internal _decimals; - - function name() external view override returns (string memory) { - return _name; - } - - function symbol() external view override returns (string memory) { - return _symbol; - } - - function decimals() external view override returns (uint8) { - return _decimals; - } - - /*////////////////////////////////////////////////////////////// - ERC20 STORAGE - //////////////////////////////////////////////////////////////*/ - - uint256 internal _totalSupply; - - mapping(address => uint256) internal _balanceOf; - - mapping(address => mapping(address => uint256)) internal _allowance; - - function totalSupply() external view override returns (uint256) { - return _totalSupply; - } - - function balanceOf(address owner) external view override returns (uint256) { - return _balanceOf[owner]; - } - - function allowance(address owner, address spender) external view override returns (uint256) { - return _allowance[owner][spender]; - } - - /*////////////////////////////////////////////////////////////// - EIP-2612 STORAGE - //////////////////////////////////////////////////////////////*/ - - uint256 internal INITIAL_CHAIN_ID; - - bytes32 internal INITIAL_DOMAIN_SEPARATOR; - - mapping(address => uint256) public nonces; - - /*////////////////////////////////////////////////////////////// - INITIALIZE - //////////////////////////////////////////////////////////////*/ - - /// @dev A bool to track whether the contract has been initialized. - bool private initialized; - - /// @dev To hide constructor warnings across solc versions due to different constructor visibility requirements and - /// syntaxes, we add an initialization function that can be called only once. - function initialize(string memory name_, string memory symbol_, uint8 decimals_) public { - require(!initialized, "ALREADY_INITIALIZED"); - - _name = name_; - _symbol = symbol_; - _decimals = decimals_; - - INITIAL_CHAIN_ID = _pureChainId(); - INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); - - initialized = true; - } - - /*////////////////////////////////////////////////////////////// - ERC20 LOGIC - //////////////////////////////////////////////////////////////*/ - - function approve(address spender, uint256 amount) public virtual override returns (bool) { - _allowance[msg.sender][spender] = amount; - - emit Approval(msg.sender, spender, amount); - - return true; - } - - function transfer(address to, uint256 amount) public virtual override returns (bool) { - _balanceOf[msg.sender] = _sub(_balanceOf[msg.sender], amount); - _balanceOf[to] = _add(_balanceOf[to], amount); - - emit Transfer(msg.sender, to, amount); - - return true; - } - - function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { - uint256 allowed = _allowance[from][msg.sender]; // Saves gas for limited approvals. - - if (allowed != ~uint256(0)) _allowance[from][msg.sender] = _sub(allowed, amount); - - _balanceOf[from] = _sub(_balanceOf[from], amount); - _balanceOf[to] = _add(_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"); - - 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 _pureChainId() == 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"), - _pureChainId(), - address(this) - ) - ); - } - - /*////////////////////////////////////////////////////////////// - INTERNAL MINT/BURN LOGIC - //////////////////////////////////////////////////////////////*/ - - function _mint(address to, uint256 amount) internal virtual { - _totalSupply = _add(_totalSupply, amount); - _balanceOf[to] = _add(_balanceOf[to], amount); - - emit Transfer(address(0), to, amount); - } - - function _burn(address from, uint256 amount) internal virtual { - _balanceOf[from] = _sub(_balanceOf[from], amount); - _totalSupply = _sub(_totalSupply, amount); - - emit Transfer(from, address(0), amount); - } - - /*////////////////////////////////////////////////////////////// - INTERNAL SAFE MATH LOGIC - //////////////////////////////////////////////////////////////*/ - - function _add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "ERC20: addition overflow"); - return c; - } - - function _sub(uint256 a, uint256 b) internal pure returns (uint256) { - require(a >= b, "ERC20: subtraction underflow"); - return a - b; - } - - /*////////////////////////////////////////////////////////////// - HELPERS - //////////////////////////////////////////////////////////////*/ - - // 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(); - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC721.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC721.sol deleted file mode 100644 index f21151b..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/mocks/MockERC721.sol +++ /dev/null @@ -1,235 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.2 <0.9.0; - -import {IERC721Metadata} from "../interfaces/IERC721.sol"; - -/// @notice This is a mock contract of the ERC721 standard for testing purposes only, it SHOULD NOT be used in production. -/// @dev Forked from: https://github.com/transmissions11/solmate/blob/0384dbaaa4fcb5715738a9254a7c0a4cb62cf458/src/tokens/ERC721.sol -contract MockERC721 is IERC721Metadata { - /*////////////////////////////////////////////////////////////// - METADATA STORAGE/LOGIC - //////////////////////////////////////////////////////////////*/ - - string internal _name; - - string internal _symbol; - - function name() external view override returns (string memory) { - return _name; - } - - function symbol() external view override returns (string memory) { - return _symbol; - } - - function tokenURI(uint256 id) public view virtual override returns (string memory) {} - - /*////////////////////////////////////////////////////////////// - ERC721 BALANCE/OWNER STORAGE - //////////////////////////////////////////////////////////////*/ - - mapping(uint256 => address) internal _ownerOf; - - mapping(address => uint256) internal _balanceOf; - - function ownerOf(uint256 id) public view virtual override returns (address owner) { - require((owner = _ownerOf[id]) != address(0), "NOT_MINTED"); - } - - function balanceOf(address owner) public view virtual override returns (uint256) { - require(owner != address(0), "ZERO_ADDRESS"); - - return _balanceOf[owner]; - } - - /*////////////////////////////////////////////////////////////// - ERC721 APPROVAL STORAGE - //////////////////////////////////////////////////////////////*/ - - mapping(uint256 => address) internal _getApproved; - - mapping(address => mapping(address => bool)) internal _isApprovedForAll; - - function getApproved(uint256 id) public view virtual override returns (address) { - return _getApproved[id]; - } - - function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { - return _isApprovedForAll[owner][operator]; - } - - /*////////////////////////////////////////////////////////////// - INITIALIZE - //////////////////////////////////////////////////////////////*/ - - /// @dev A bool to track whether the contract has been initialized. - bool private initialized; - - /// @dev To hide constructor warnings across solc versions due to different constructor visibility requirements and - /// syntaxes, we add an initialization function that can be called only once. - function initialize(string memory name_, string memory symbol_) public { - require(!initialized, "ALREADY_INITIALIZED"); - - _name = name_; - _symbol = symbol_; - - initialized = true; - } - - /*////////////////////////////////////////////////////////////// - ERC721 LOGIC - //////////////////////////////////////////////////////////////*/ - - function approve(address spender, uint256 id) public payable virtual override { - 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 override { - _isApprovedForAll[msg.sender][operator] = approved; - - emit ApprovalForAll(msg.sender, operator, approved); - } - - function transferFrom(address from, address to, uint256 id) public payable virtual override { - 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. - _balanceOf[from]--; - - _balanceOf[to]++; - - _ownerOf[id] = to; - - delete _getApproved[id]; - - emit Transfer(from, to, id); - } - - function safeTransferFrom(address from, address to, uint256 id) public payable virtual override { - transferFrom(from, to, id); - - require( - !_isContract(to) - || IERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") - == IERC721TokenReceiver.onERC721Received.selector, - "UNSAFE_RECIPIENT" - ); - } - - function safeTransferFrom(address from, address to, uint256 id, bytes memory data) - public - payable - virtual - override - { - transferFrom(from, to, id); - - require( - !_isContract(to) - || IERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) - == IERC721TokenReceiver.onERC721Received.selector, - "UNSAFE_RECIPIENT" - ); - } - - /*////////////////////////////////////////////////////////////// - ERC165 LOGIC - //////////////////////////////////////////////////////////////*/ - - function supportsInterface(bytes4 interfaceId) public view virtual override 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. - - _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"); - - _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( - !_isContract(to) - || IERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") - == IERC721TokenReceiver.onERC721Received.selector, - "UNSAFE_RECIPIENT" - ); - } - - function _safeMint(address to, uint256 id, bytes memory data) internal virtual { - _mint(to, id); - - require( - !_isContract(to) - || IERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) - == IERC721TokenReceiver.onERC721Received.selector, - "UNSAFE_RECIPIENT" - ); - } - - /*////////////////////////////////////////////////////////////// - HELPERS - //////////////////////////////////////////////////////////////*/ - - function _isContract(address _addr) private view returns (bool) { - uint256 codeLength; - - // Assembly required for versions < 0.8.0 to check extcodesize. - assembly { - codeLength := extcodesize(_addr) - } - - return codeLength > 0; - } -} - -interface IERC721TokenReceiver { - function onERC721Received(address, address, uint256, bytes calldata) external returns (bytes4); -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/safeconsole.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/safeconsole.sol deleted file mode 100644 index 5714d09..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/src/safeconsole.sol +++ /dev/null @@ -1,13248 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdAssertions.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdAssertions.t.sol deleted file mode 100644 index ea79468..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdAssertions.t.sol +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import "../src/StdAssertions.sol"; -import {Vm} from "../src/Vm.sol"; - -interface VmInternal is Vm { - function _expectCheatcodeRevert(bytes memory message) external; -} - -contract StdAssertionsTest is StdAssertions { - string constant errorMessage = "User provided message"; - uint256 constant maxDecimals = 77; - - bool constant SHOULD_REVERT = true; - bool constant SHOULD_RETURN = false; - - bool constant STRICT_REVERT_DATA = true; - bool constant NON_STRICT_REVERT_DATA = false; - - VmInternal constant vm = VmInternal(address(uint160(uint256(keccak256("hevm cheat code"))))); - - 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)); - - assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); - } - - 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._expectCheatcodeRevert( - bytes( - string.concat( - "Call return data does not match: ", vm.toString(returnDataA), " != ", vm.toString(returnDataB) - ) - ) - ); - assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); - } - - 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)); - - assertEqCall(targetA, callDataA, targetB, callDataB, NON_STRICT_REVERT_DATA); - } - - 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._expectCheatcodeRevert( - bytes( - string.concat( - "Call revert data does not match: ", vm.toString(revertDataA), " != ", vm.toString(revertDataB) - ) - ) - ); - assertEqCall(targetA, callDataA, targetB, callDataB, STRICT_REVERT_DATA); - } - - 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.expectRevert(bytes("assertion failed")); - this.assertEqCallExternal(targetA, callDataA, targetB, callDataB, strictRevertData); - - vm.expectRevert(bytes("assertion failed")); - this.assertEqCallExternal(targetB, callDataB, targetA, callDataA, strictRevertData); - } - - // Helper function to test outcome of assertEqCall via `expect` cheatcodes - function assertEqCallExternal( - address targetA, - bytes memory callDataA, - address targetB, - bytes memory callDataB, - bool strictRevertData - ) public { - assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); - } - - function testFailFail() public { - fail(); - } -} - -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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdChains.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdChains.t.sol deleted file mode 100644 index 4c3283a..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdChains.t.sol +++ /dev/null @@ -1,221 +0,0 @@ -// 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://eth-mainnet.alchemyapi.io/v2/WV407BEiBmjNJfKo9Uo_55u0z0ITyCOX"); - 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://eth-mainnet.alchemyapi.io/v2/WV407BEiBmjNJfKo9Uo_55u0z0ITyCOX"); - - // 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"); - } - - // Named with a leading underscore to clarify this is not intended to be run as a normal test, - // and is intended to be used in the below `test_Rpcs` test. - 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. - // Currently commented out since this is slow and public RPCs are flaky, often resulting in failing CI. - // function test_Rpcs() 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"); - // _testRpc("fraxtal"); - // _testRpc("fraxtal_testnet"); - // } - - 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(); - stdChainsMock.exposed_getChain(31337); - vm.expectRevert(); - stdChainsMock.exposed_getChain("sepolia"); - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdCheats.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdCheats.t.sol deleted file mode 100644 index e96cb52..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdCheats.t.sol +++ /dev/null @@ -1,618 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import "../src/StdCheats.sol"; -import "../src/Test.sol"; -import "../src/StdJson.sol"; -import "../src/StdToml.sol"; -import "../src/interfaces/IERC20.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 test_DealToken() 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 pure { - 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 view { - 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 view { - 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(); - - 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 pure { - 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 view { - 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 view { - 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 view { - assumeNotBlacklisted(USDT, addr); - assertFalse(USDTLike(USDT).isBlackListed(addr)); - } - - function test_dealUSDC() external { - // roll fork to the point when USDC contract updated to store balance in packed slots - vm.rollFork(19279215); - - uint256 balance = 100e6; - deal(USDC, address(this), balance); - assertEq(IERC20(USDC).balanceOf(address(this)), balance); - } -} - -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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdError.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdError.t.sol deleted file mode 100644 index a306eaa..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdError.t.sol +++ /dev/null @@ -1,120 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdJson.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdJson.t.sol deleted file mode 100644 index e32b92e..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdJson.t.sol +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import "../src/Test.sol"; - -contract StdJsonTest is Test { - using stdJson for string; - - string root; - string path; - - function setUp() public { - root = vm.projectRoot(); - path = string.concat(root, "/test/fixtures/test.json"); - } - - struct SimpleJson { - uint256 a; - string b; - } - - struct NestedJson { - uint256 a; - string b; - SimpleJson c; - } - - function test_readJson() public view { - string memory json = vm.readFile(path); - assertEq(json.readUint(".a"), 123); - } - - function test_writeJson() public { - string memory json = "json"; - json.serialize("a", uint256(123)); - string memory semiFinal = json.serialize("b", string("test")); - string memory finalJson = json.serialize("c", semiFinal); - finalJson.write(path); - - string memory json_ = vm.readFile(path); - bytes memory data = json_.parseRaw("$"); - NestedJson memory decodedData = abi.decode(data, (NestedJson)); - - assertEq(decodedData.a, 123); - assertEq(decodedData.b, "test"); - assertEq(decodedData.c.a, 123); - assertEq(decodedData.c.b, "test"); - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdMath.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdMath.t.sol deleted file mode 100644 index ed0f9ba..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdMath.t.sol +++ /dev/null @@ -1,212 +0,0 @@ -// 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 pure { - 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 pure { - uint256 manualAbs = getAbs(a); - - uint256 abs = stdMath.abs(a); - - assertEq(abs, manualAbs); - } - - function test_GetDelta_Uint() external pure { - 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 pure { - 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 pure { - 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 pure { - 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 pure { - 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 pure { - 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStorage.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStorage.t.sol deleted file mode 100644 index e1e6aa0..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStorage.t.sol +++ /dev/null @@ -1,463 +0,0 @@ -// 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 testFuzz_StorageCheckedWriteMapPacked(address addr, uint128 value) public { - stdstore.enable_packed_slots().target(address(test)).sig(test.read_struct_lower.selector).with_key(addr) - .checked_write(value); - assertEq(test.read_struct_lower(addr), value); - - stdstore.enable_packed_slots().target(address(test)).sig(test.read_struct_upper.selector).with_key(addr) - .checked_write(value); - assertEq(test.read_struct_upper(addr), value); - } - - function test_StorageCheckedWriteMapPackedFullSuccess() 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 testFuzz_StorageNativePack(uint248 val1, uint248 val2, bool boolVal1, bool boolVal2) public { - stdstore.enable_packed_slots().target(address(test)).sig(test.tA.selector).checked_write(val1); - stdstore.enable_packed_slots().target(address(test)).sig(test.tB.selector).checked_write(boolVal1); - stdstore.enable_packed_slots().target(address(test)).sig(test.tC.selector).checked_write(boolVal2); - stdstore.enable_packed_slots().target(address(test)).sig(test.tD.selector).checked_write(val2); - - assertEq(test.tA(), val1); - assertEq(test.tB(), boolVal1); - assertEq(test.tC(), boolVal2); - assertEq(test.tD(), val2); - } - - 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); - } - - function testFuzzPacked(uint256 val, uint8 elemToGet) public { - // This function tries an assortment of packed slots, shifts meaning number of elements - // that are packed. Shiftsizes are the size of each element, i.e. 8 means a data type that is 8 bits, 16 == 16 bits, etc. - // Combined, these determine how a slot is packed. Making it random is too hard to avoid global rejection limit - // and make it performant. - - // change the number of shifts - for (uint256 i = 1; i < 5; i++) { - uint256 shifts = i; - - elemToGet = uint8(bound(elemToGet, 0, shifts - 1)); - - uint256[] memory shiftSizes = new uint256[](shifts); - for (uint256 j; j < shifts; j++) { - shiftSizes[j] = 8 * (j + 1); - } - - test.setRandomPacking(val); - - uint256 leftBits; - uint256 rightBits; - for (uint256 j; j < shiftSizes.length; j++) { - if (j < elemToGet) { - leftBits += shiftSizes[j]; - } else if (elemToGet != j) { - rightBits += shiftSizes[j]; - } - } - - // we may have some right bits unaccounted for - leftBits += 256 - (leftBits + shiftSizes[elemToGet] + rightBits); - // clear left bits, then clear right bits and realign - uint256 expectedValToRead = (val << leftBits) >> (leftBits + rightBits); - - uint256 readVal = stdstore.target(address(test)).enable_packed_slots().sig( - "getRandomPacked(uint8,uint8[],uint8)" - ).with_calldata(abi.encode(shifts, shiftSizes, elemToGet)).read_uint(); - - assertEq(readVal, expectedValToRead); - } - } - - function testFuzzPacked2(uint256 nvars, uint256 seed) public { - // Number of random variables to generate. - nvars = bound(nvars, 1, 20); - - // This will decrease as we generate values in the below loop. - uint256 bitsRemaining = 256; - - // Generate a random value and size for each variable. - uint256[] memory vals = new uint256[](nvars); - uint256[] memory sizes = new uint256[](nvars); - uint256[] memory offsets = new uint256[](nvars); - - for (uint256 i = 0; i < nvars; i++) { - // Generate a random value and size. - offsets[i] = i == 0 ? 0 : offsets[i - 1] + sizes[i - 1]; - - uint256 nvarsRemaining = nvars - i; - uint256 maxVarSize = bitsRemaining - nvarsRemaining + 1; - sizes[i] = bound(uint256(keccak256(abi.encodePacked(seed, i + 256))), 1, maxVarSize); - bitsRemaining -= sizes[i]; - - uint256 maxVal; - uint256 varSize = sizes[i]; - assembly { - // mask = (1 << varSize) - 1 - maxVal := sub(shl(varSize, 1), 1) - } - vals[i] = bound(uint256(keccak256(abi.encodePacked(seed, i))), 0, maxVal); - } - - // Pack all values into the slot. - for (uint256 i = 0; i < nvars; i++) { - stdstore.enable_packed_slots().target(address(test)).sig("getRandomPacked(uint256,uint256)").with_key( - sizes[i] - ).with_key(offsets[i]).checked_write(vals[i]); - } - - // Verify the read data matches. - for (uint256 i = 0; i < nvars; i++) { - uint256 readVal = stdstore.enable_packed_slots().target(address(test)).sig( - "getRandomPacked(uint256,uint256)" - ).with_key(sizes[i]).with_key(offsets[i]).read_uint(); - - uint256 retVal = test.getRandomPacked(sizes[i], offsets[i]); - - assertEq(readVal, vals[i]); - assertEq(retVal, vals[i]); - } - } -} - -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"); - - uint256 randomPacking; - - 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; - } - - function setRandomPacking(uint256 val) public { - randomPacking = val; - } - - function _getMask(uint256 size) internal pure returns (uint256 mask) { - assembly { - // mask = (1 << size) - 1 - mask := sub(shl(size, 1), 1) - } - } - - function setRandomPacking(uint256 val, uint256 size, uint256 offset) public { - // Generate mask based on the size of the value - uint256 mask = _getMask(size); - // Zero out all bits for the word we're about to set - uint256 cleanedWord = randomPacking & ~(mask << offset); - // Place val in the correct spot of the cleaned word - randomPacking = cleanedWord | val << offset; - } - - function getRandomPacked(uint256 size, uint256 offset) public view returns (uint256) { - // Generate mask based on the size of the value - uint256 mask = _getMask(size); - // Shift to place the bits in the correct position, and use mask to zero out remaining bits - return (randomPacking >> offset) & mask; - } - - function getRandomPacked(uint8 shifts, uint8[] memory shiftSizes, uint8 elem) public view returns (uint256) { - require(elem < shifts, "!elem"); - uint256 leftBits; - uint256 rightBits; - - for (uint256 i; i < shiftSizes.length; i++) { - if (i < elem) { - leftBits += shiftSizes[i]; - } else if (elem != i) { - rightBits += shiftSizes[i]; - } - } - - // we may have some right bits unaccounted for - leftBits += 256 - (leftBits + shiftSizes[elem] + rightBits); - - // clear left bits, then clear right bits and realign - return (randomPacking << leftBits) >> (leftBits + rightBits); - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStyle.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStyle.t.sol deleted file mode 100644 index e12c005..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdStyle.t.sol +++ /dev/null @@ -1,110 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdToml.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdToml.t.sol deleted file mode 100644 index 631b1b5..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdToml.t.sol +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import "../src/Test.sol"; - -contract StdTomlTest is Test { - using stdToml for string; - - string root; - string path; - - function setUp() public { - root = vm.projectRoot(); - path = string.concat(root, "/test/fixtures/test.toml"); - } - - struct SimpleToml { - uint256 a; - string b; - } - - struct NestedToml { - uint256 a; - string b; - SimpleToml c; - } - - function test_readToml() public view { - string memory json = vm.readFile(path); - assertEq(json.readUint(".a"), 123); - } - - function test_writeToml() public { - string memory json = "json"; - json.serialize("a", uint256(123)); - string memory semiFinal = json.serialize("b", string("test")); - string memory finalJson = json.serialize("c", semiFinal); - finalJson.write(path); - - string memory toml = vm.readFile(path); - bytes memory data = toml.parseRaw("$"); - NestedToml memory decodedData = abi.decode(data, (NestedToml)); - - assertEq(decodedData.a, 123); - assertEq(decodedData.b, "test"); - assertEq(decodedData.c.a, 123); - assertEq(decodedData.c.b, "test"); - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdUtils.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdUtils.t.sol deleted file mode 100644 index 4994c6c..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/StdUtils.t.sol +++ /dev/null @@ -1,342 +0,0 @@ -// 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 pure returns (int256) { - return bound(num, min, max); - } - - function exposed_bound(uint256 num, uint256 min, uint256 max) external pure 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 pure { - 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 pure { - 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 pure { - 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 pure { - 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 pure { - 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 pure { - 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 pure { - 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 pure { - 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 pure { - 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 pure { - 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 pure { - 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 pure { - 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 pure { - 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 pure { - 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 pure { - 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 pure { - address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; - uint256 nonce = 14; - address createAddress = computeCreateAddress(deployer, nonce); - assertEq(createAddress, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); - } - - /*////////////////////////////////////////////////////////////////////////// - COMPUTE CREATE2 ADDRESS - //////////////////////////////////////////////////////////////////////////*/ - - function test_ComputeCreate2Address() external pure { - 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 pure { - 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/Vm.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/Vm.t.sol deleted file mode 100644 index 4ff3d7e..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/Vm.t.sol +++ /dev/null @@ -1,15 +0,0 @@ -// 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 pure { - assertEq(type(VmSafe).interfaceId, bytes4(0xce9c7617), "VmSafe"); - assertEq(type(Vm).interfaceId, bytes4(0xaf68a970), "Vm"); - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationScript.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationScript.sol deleted file mode 100644 index e205cff..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationScript.sol +++ /dev/null @@ -1,10 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationScriptBase.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationScriptBase.sol deleted file mode 100644 index ce8e0e9..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationScriptBase.sol +++ /dev/null @@ -1,10 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationTest.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationTest.sol deleted file mode 100644 index 9beeafe..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationTest.sol +++ /dev/null @@ -1,10 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationTestBase.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationTestBase.sol deleted file mode 100644 index e993535..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/compilation/CompilationTestBase.sol +++ /dev/null @@ -1,10 +0,0 @@ -// 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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/broadcast.log.json b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/broadcast.log.json deleted file mode 100644 index 0a0200b..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/broadcast.log.json +++ /dev/null @@ -1,187 +0,0 @@ -{ - "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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.json b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.json deleted file mode 100644 index caebf6d..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "a": 123, - "b": "test", - "c": { - "a": 123, - "b": "test" - } -} \ No newline at end of file diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.toml b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.toml deleted file mode 100644 index 60692bc..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/fixtures/test.toml +++ /dev/null @@ -1,6 +0,0 @@ -a = 123 -b = "test" - -[c] -a = 123 -b = "test" diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC20.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC20.t.sol deleted file mode 100644 index e246810..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC20.t.sol +++ /dev/null @@ -1,441 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {MockERC20} from "../../src/mocks/MockERC20.sol"; -import {StdCheats} from "../../src/StdCheats.sol"; -import {Test} from "../../src/Test.sol"; - -contract Token_ERC20 is MockERC20 { - constructor(string memory name, string memory symbol, uint8 decimals) { - initialize(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); - } -} - -contract MockERC20Test is StdCheats, Test { - Token_ERC20 token; - - bytes32 constant PERMIT_TYPEHASH = - keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); - - function setUp() public { - token = new Token_ERC20("Token", "TKN", 18); - } - - function invariantMetadata() public view { - 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); - - vm.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); - - vm.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 = vm.addr(privateKey); - - (uint8 v, bytes32 r, bytes32 s) = vm.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); - - vm.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); - - vm.prank(from); - token.approve(address(this), 1e18); - - token.transferFrom(from, address(0xBEEF), 1e18); - } - - function testFailPermitBadNonce() public { - uint256 privateKey = 0xBEEF; - address owner = vm.addr(privateKey); - - (uint8 v, bytes32 r, bytes32 s) = vm.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 = vm.addr(privateKey); - - (uint8 v, bytes32 r, bytes32 s) = vm.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 = vm.addr(privateKey); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign( - privateKey, - keccak256( - abi.encodePacked( - "\x19\x01", - token.DOMAIN_SEPARATOR(), - keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(0xCAFE), 1e18, 0, oldTimestamp)) - ) - ) - ); - - vm.warp(block.timestamp + 1); - token.permit(owner, address(0xCAFE), 1e18, oldTimestamp, v, r, s); - } - - function testFailPermitReplay() public { - uint256 privateKey = 0xBEEF; - address owner = vm.addr(privateKey); - - (uint8 v, bytes32 r, bytes32 s) = vm.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 { - Token_ERC20 tkn = new Token_ERC20(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); - - vm.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 = vm.addr(privateKey); - - (uint8 v, bytes32 r, bytes32 s) = vm.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); - - vm.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); - - vm.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 = vm.addr(privateKey); - - (uint8 v, bytes32 r, bytes32 s) = vm.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 = vm.addr(privateKey); - - (uint8 v, bytes32 r, bytes32 s) = vm.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 = vm.addr(privateKey); - - (uint8 v, bytes32 r, bytes32 s) = vm.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 = vm.addr(privateKey); - - (uint8 v, bytes32 r, bytes32 s) = vm.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); - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC721.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC721.t.sol deleted file mode 100644 index f986d79..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/lib/forge-std/test/mocks/MockERC721.t.sol +++ /dev/null @@ -1,721 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; - -import {MockERC721, IERC721TokenReceiver} from "../../src/mocks/MockERC721.sol"; -import {StdCheats} from "../../src/StdCheats.sol"; -import {Test} from "../../src/Test.sol"; - -contract ERC721Recipient is IERC721TokenReceiver { - 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 IERC721TokenReceiver.onERC721Received.selector; - } -} - -contract RevertingERC721Recipient is IERC721TokenReceiver { - function onERC721Received(address, address, uint256, bytes calldata) public virtual override returns (bytes4) { - revert(string(abi.encodePacked(IERC721TokenReceiver.onERC721Received.selector))); - } -} - -contract WrongReturnDataERC721Recipient is IERC721TokenReceiver { - function onERC721Received(address, address, uint256, bytes calldata) public virtual override returns (bytes4) { - return 0xCAFEBEEF; - } -} - -contract NonERC721Recipient {} - -contract Token_ERC721 is MockERC721 { - constructor(string memory _name, string memory _symbol) { - initialize(_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); - } -} - -contract MockERC721Test is StdCheats, Test { - Token_ERC721 token; - - function setUp() public { - token = new Token_ERC721("Token", "TKN"); - } - - function invariantMetadata() public view { - 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); - - vm.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)); - - vm.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); - - vm.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); - - vm.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); - - vm.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); - - vm.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); - assertEq(recipient.data(), ""); - } - - function testSafeTransferFromToERC721RecipientWithData() public { - address from = address(0xABCD); - ERC721Recipient recipient = new ERC721Recipient(); - - token.mint(from, 1337); - - vm.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); - assertEq(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); - assertEq(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); - assertEq(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 Token_ERC721(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); - - vm.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)); - - vm.expectRevert("NOT_MINTED"); - token.ownerOf(id); - } - - function testApproveAll(address to, bool approved) public { - token.setApprovalForAll(to, approved); - - assertEq(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); - - vm.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); - - vm.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); - - vm.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); - - vm.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); - assertEq(recipient.data(), ""); - } - - function testSafeTransferFromToERC721RecipientWithData(uint256 id, bytes calldata data) public { - address from = address(0xABCD); - ERC721Recipient recipient = new ERC721Recipient(); - - token.mint(from, id); - - vm.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); - assertEq(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); - assertEq(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); - assertEq(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/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/scripts/ExampleDeploy.s.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/scripts/ExampleDeploy.s.sol deleted file mode 100644 index 8a01f52..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/scripts/ExampleDeploy.s.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.13; - -import {Script, console2} from "forge-std/Script.sol"; - -import {SafeSingletonDeployer} from "../src/SafeSingletonDeployer.sol"; -import {Mock} from "../test/Mock.sol"; - -contract ExampleDeployScript is Script { - function run() public { - uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - - SafeSingletonDeployer.broadcastDeploy({ - deployerPrivateKey: deployerPrivateKey, - creationCode: type(Mock).creationCode, - args: abi.encode(1), - salt: bytes32("0x1234") - }); - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/src/SafeSingletonDeployer.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/src/SafeSingletonDeployer.sol deleted file mode 100644 index d53d49f..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/src/SafeSingletonDeployer.sol +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {VmSafe} from "forge-std/Vm.sol"; - -/// @notice Library for deploying contracts using Safe's Singleton Factory -/// https://github.com/safe-global/safe-singleton-factory -library SafeSingletonDeployer { - error DeployFailed(); - - address constant SAFE_SINGLETON_FACTORY = 0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7; - VmSafe private constant VM = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); - - function computeAddress(bytes memory creationCode, bytes32 salt) public pure returns (address) { - return computeAddress(creationCode, "", salt); - } - - function computeAddress(bytes memory creationCode, bytes memory args, bytes32 salt) public pure returns (address) { - return VM.computeCreate2Address({ - salt: salt, - initCodeHash: _hashInitCode(creationCode, args), - deployer: SAFE_SINGLETON_FACTORY - }); - } - - function broadcastDeploy(bytes memory creationCode, bytes memory args, bytes32 salt) internal returns (address) { - VM.broadcast(); - return _deploy(creationCode, args, salt); - } - - function broadcastDeploy(bytes memory creationCode, bytes32 salt) internal returns (address) { - VM.broadcast(); - return _deploy(creationCode, "", salt); - } - - function broadcastDeploy(address deployer, bytes memory creationCode, bytes memory args, bytes32 salt) - internal - returns (address) - { - VM.broadcast(deployer); - return _deploy(creationCode, args, salt); - } - - function broadcastDeploy(address deployer, bytes memory creationCode, bytes32 salt) internal returns (address) { - VM.broadcast(deployer); - return _deploy(creationCode, "", salt); - } - - function broadcastDeploy(uint256 deployerPrivateKey, bytes memory creationCode, bytes memory args, bytes32 salt) - internal - returns (address) - { - VM.broadcast(deployerPrivateKey); - return _deploy(creationCode, args, salt); - } - - function broadcastDeploy(uint256 deployerPrivateKey, bytes memory creationCode, bytes32 salt) - internal - returns (address) - { - VM.broadcast(deployerPrivateKey); - return _deploy(creationCode, "", salt); - } - - /// @dev Allows calling without Forge broadcast - function deploy(bytes memory creationCode, bytes memory args, bytes32 salt) internal returns (address) { - return _deploy(creationCode, args, salt); - } - - /// @dev Allows calling without Forge broadcast - function deploy(bytes memory creationCode, bytes32 salt) internal returns (address) { - return _deploy(creationCode, "", salt); - } - - function _deploy(bytes memory creationCode, bytes memory args, bytes32 salt) private returns (address) { - bytes memory callData = abi.encodePacked(salt, creationCode, args); - - (bool success, bytes memory result) = SAFE_SINGLETON_FACTORY.call(callData); - - if (!success) { - // contract does not pass on revert reason - // https://github.com/Arachnid/deterministic-deployment-proxy/blob/master/source/deterministic-deployment-proxy.yul#L13 - revert DeployFailed(); - } - - return address(bytes20(result)); - } - - function _hashInitCode(bytes memory creationCode, bytes memory args) private pure returns (bytes32) { - return keccak256(abi.encodePacked(creationCode, args)); - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/Mock.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/Mock.sol deleted file mode 100644 index 3c33499..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/Mock.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -contract Mock { - uint256 public value; - - constructor(uint256 startValue) { - value = startValue; - } - - function setValue(uint256 value_) public returns (uint256) { - return value = value_; - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/MockReverting.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/MockReverting.sol deleted file mode 100644 index 7fa3794..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/MockReverting.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -contract MockReverting { - error MyError(); - - constructor() { - revert MyError(); - } -} diff --git a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/SafeSingletonDeployer.t.sol b/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/SafeSingletonDeployer.t.sol deleted file mode 100644 index 859be79..0000000 --- a/typescript/packages/account-modules/lib/safe-singleton-deployer-sol/test/SafeSingletonDeployer.t.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {Test} from "forge-std/Test.sol"; - -import {SafeSingletonDeployer} from "../src/SafeSingletonDeployer.sol"; - -import {Mock} from "./Mock.sol"; -import {MockReverting} from "./MockReverting.sol"; - -contract SafeSingletonDeployerTest is Test { - // cast code 0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7 --rpc-url https://mainnet.base.org - bytes factoryCode = - hex"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3"; - - function setUp() public { - vm.etch(SafeSingletonDeployer.SAFE_SINGLETON_FACTORY, factoryCode); - } - - function test_deploy_createsAtExpectedAddress() public { - address expectedAddress = - SafeSingletonDeployer.computeAddress(type(Mock).creationCode, abi.encode(1), bytes32("0x1234")); - assertEq(expectedAddress.code, ""); - address returnAddress = SafeSingletonDeployer.deploy({ - creationCode: type(Mock).creationCode, - args: abi.encode(1), - salt: bytes32("0x1234") - }); - assertEq(returnAddress, expectedAddress); - assertNotEq(expectedAddress.code, ""); - } - - function test_deploy_createsContractCorrectly() public { - uint256 startValue = 1; - address mock = SafeSingletonDeployer.deploy({ - creationCode: type(Mock).creationCode, - args: abi.encode(1), - salt: bytes32("0x1234") - }); - assertEq(startValue, Mock(mock).value()); - uint256 newValue = 2; - Mock(mock).setValue(newValue); - assertEq(newValue, Mock(mock).value()); - } - - function test_deploy_reverts() public { - vm.expectRevert(); - SafeSingletonDeployer.deploy({ - creationCode: type(MockReverting).creationCode, - args: abi.encode(1), - salt: bytes32("0x1234") - }); - } -} diff --git a/typescript/packages/account-modules/script/CalculateStorageSlot.s.sol b/typescript/packages/account-modules/script/CalculateStorageSlot.s.sol deleted file mode 100644 index 7fbacdd..0000000 --- a/typescript/packages/account-modules/script/CalculateStorageSlot.s.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {Script, console} from "forge-std/Script.sol"; -import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; - -contract CalculateStorageSlot is Script { - using SlotDerivation for string; - - function run() public { - // AutoTopUpExecutor storage slot - string memory topUpNamespace = "autotopup.storage.AutoTopUpExecutor"; - bytes32 topUpSlot = topUpNamespace.erc7201Slot(); - console.log("AutoTopUpExecutor Namespace:", topUpNamespace); - console.log("AutoTopUpExecutor Storage slot:"); - console.logBytes32(topUpSlot); - - console.log(""); - - // AutoCollectExecutor storage slot - string memory collectNamespace = "autocollect.storage.AutoCollectExecutor"; - bytes32 collectSlot = collectNamespace.erc7201Slot(); - console.log("AutoCollectExecutor Namespace:", collectNamespace); - console.log("AutoCollectExecutor Storage slot:"); - console.logBytes32(collectSlot); - } -} diff --git a/typescript/packages/account-modules/script/Deploy.s.sol b/typescript/packages/account-modules/script/Deploy.s.sol deleted file mode 100644 index 931afa5..0000000 --- a/typescript/packages/account-modules/script/Deploy.s.sol +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {Script, console} from "forge-std/Script.sol"; -import {SafeSingletonDeployer} from "safe-singleton-deployer/SafeSingletonDeployer.sol"; -import {AutoTopUpExecutor} from "../src/AutoTopUpExecutor.sol"; -import {AutoCollectExecutor} from "../src/AutoCollectExecutor.sol"; - -contract Deploy is Script { - // Use meaningful salts for deterministic addresses across chains - bytes32 constant AUTO_TOPUP_SALT = keccak256("AutoTopUpExecutor.v1"); - bytes32 constant AUTO_COLLECT_SALT = keccak256("AutoCollectExecutor.v1"); - - function run() external returns (address autoTopUp, address autoCollect) { - // Get deployer from environment - uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - - console.log("=== Deploying Account Modules ==="); - console.log("Deployer:", vm.addr(deployerPrivateKey)); - console.log(""); - - vm.startBroadcast(deployerPrivateKey); - - // Deploy AutoTopUpExecutor using Safe Singleton Factory - console.log("Deploying AutoTopUpExecutor..."); - autoTopUp = _deploySingleton( - type(AutoTopUpExecutor).creationCode, - "", // No constructor args - AUTO_TOPUP_SALT, - "AutoTopUpExecutor" - ); - - // Deploy AutoCollectExecutor using Safe Singleton Factory - console.log("Deploying AutoCollectExecutor..."); - autoCollect = _deploySingleton( - type(AutoCollectExecutor).creationCode, - "", // No constructor args - AUTO_COLLECT_SALT, - "AutoCollectExecutor" - ); - - vm.stopBroadcast(); - - // Log deployment summary - console.log(""); - console.log("=== Deployment Summary ==="); - console.log("AutoTopUpExecutor:", autoTopUp); - console.log("AutoCollectExecutor:", autoCollect); - console.log(""); - console.log("These addresses will be consistent across all chains!"); - console.log("========================="); - } - - function _deploySingleton( - bytes memory creationCode, - bytes memory constructorArgs, - bytes32 salt, - string memory contractName - ) internal returns (address deployed) { - // Use SafeSingletonDeployer.deploy (not broadcastDeploy) since we're already broadcasting - deployed = SafeSingletonDeployer.deploy(creationCode, constructorArgs, salt); - - console.log(string.concat(contractName, " deployed at:"), deployed); - - // Verify deployment - require(deployed.code.length > 0, string.concat(contractName, " deployment failed")); - } - - // Helper function to predict addresses without deploying - function predict() external view { - console.log("=== Predicted Addresses ==="); - - // Predict AutoTopUpExecutor address - address predictedAutoTopUp = - SafeSingletonDeployer.computeAddress(type(AutoTopUpExecutor).creationCode, AUTO_TOPUP_SALT); - console.log("AutoTopUpExecutor:", predictedAutoTopUp); - - // Predict AutoCollectExecutor address - address predictedAutoCollect = - SafeSingletonDeployer.computeAddress(type(AutoCollectExecutor).creationCode, AUTO_COLLECT_SALT); - console.log("AutoCollectExecutor:", predictedAutoCollect); - - console.log("==========================="); - } -} diff --git a/typescript/packages/account-modules/script/README.md b/typescript/packages/account-modules/script/README.md deleted file mode 100644 index d02fbf6..0000000 --- a/typescript/packages/account-modules/script/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Account Modules Deployment Scripts - -## Deploy.s.sol - -Deploys the AutoTopUpExecutor and AutoCollectExecutor modules using Safe's Singleton Factory for deterministic addresses across all chains. - -### Usage - -#### Predict Addresses (without deploying) -```bash -forge script script/Deploy.s.sol:Deploy --sig "predict()" -``` - -#### Deploy to a Network -```bash -# Set required environment variables -export PRIVATE_KEY= - -# Deploy to Base Sepolia -forge script script/Deploy.s.sol:Deploy \ - --rpc-url \ - --broadcast \ - --verify - -# Deploy to Base Mainnet -forge script script/Deploy.s.sol:Deploy \ - --rpc-url \ - --broadcast \ - --verify -``` - -### Deployed Addresses - -The modules will be deployed to the same addresses on all chains: -- **AutoTopUpExecutor**: `0x92Be8FA04bF1d9Ee311F4B2754Ca22252ccA18D4` -- **AutoCollectExecutor**: `0x6647fA97ff1f04614A0A960dcF499545c4DcC431` - -### Notes - -- The contracts are deployed as immutable singletons (no upgradeability, no owner) -- Addresses are deterministic using Safe Singleton Factory -- The factory is deployed on 250+ chains at: `0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7` \ No newline at end of file diff --git a/typescript/packages/account-modules/script/verify.sh b/typescript/packages/account-modules/script/verify.sh deleted file mode 100755 index d33727c..0000000 --- a/typescript/packages/account-modules/script/verify.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -# Script to verify deployed contracts on Basescan/Etherscan -# Usage: ./verify.sh [network] -# Example: ./verify.sh base-sepolia - -NETWORK=${1:-base-sepolia} - -# Contract addresses (same on all chains) -AUTO_TOPUP_ADDRESS="0x92Be8FA04bF1d9Ee311F4B2754Ca22252ccA18D4" -AUTO_COLLECT_ADDRESS="0x6647fA97ff1f04614A0A960dcF499545c4DcC431" - -echo "Verifying contracts on $NETWORK..." -echo "" - -# Verify AutoTopUpExecutor -echo "Verifying AutoTopUpExecutor at $AUTO_TOPUP_ADDRESS..." -forge verify-contract \ - --chain $NETWORK \ - --num-of-optimizations 200 \ - --compiler-version v0.8.30 \ - $AUTO_TOPUP_ADDRESS \ - src/AutoTopUpExecutor.sol:AutoTopUpExecutor - -echo "" - -# Verify AutoCollectExecutor -echo "Verifying AutoCollectExecutor at $AUTO_COLLECT_ADDRESS..." -forge verify-contract \ - --chain $NETWORK \ - --num-of-optimizations 200 \ - --compiler-version v0.8.30 \ - $AUTO_COLLECT_ADDRESS \ - src/AutoCollectExecutor.sol:AutoCollectExecutor - -echo "" -echo "Verification complete!" -echo "" -echo "View verified contracts:" -echo "- AutoTopUpExecutor: https://sepolia.basescan.org/address/$AUTO_TOPUP_ADDRESS#code" -echo "- AutoCollectExecutor: https://sepolia.basescan.org/address/$AUTO_COLLECT_ADDRESS#code" diff --git a/typescript/packages/account-modules/src/AutoCollectExecutor.sol b/typescript/packages/account-modules/src/AutoCollectExecutor.sol deleted file mode 100644 index cef3065..0000000 --- a/typescript/packages/account-modules/src/AutoCollectExecutor.sol +++ /dev/null @@ -1,558 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {IAutoCollectExecutor} from "./IAutoCollectExecutor.sol"; -import {ERC7579ExecutorBase} from "modulekit/src/module-bases/ERC7579ExecutorBase.sol"; -import {IModule} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; -import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; -import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; - -/** - * @title AutoCollectExecutor - * @notice ERC-7579 executor module for automatic ERC-20 token collection from service accounts - * @dev Enables permissionless triggering of pre-configured collections from service accounts to main accounts - */ -contract AutoCollectExecutor is IAutoCollectExecutor, ERC7579ExecutorBase, ReentrancyGuard { - using EnumerableSet for EnumerableSet.Bytes32Set; - - // ============ Storage ============ - - /// @dev ERC-7201 namespace for storage - /// @custom:storage-location erc7201:autocollect.storage.AutoCollectExecutor - // keccak256(abi.encode(uint256(keccak256("autocollect.storage.AutoCollectExecutor")) - 1)) & ~bytes32(uint256(0xff)) - bytes32 private constant STORAGE_NAMESPACE = 0x6ede4012bbf78b7156310dfe77e035f310125e160497f34e20b746b314ff2200; - - /// @custom:storage-namespace AutoCollectStorage - struct AutoCollectStorage { - // Config ID => user configuration - mapping(bytes32 => CollectConfig) configs; - // Config ID => internal state - mapping(bytes32 => CollectState) states; - // Account => set of config IDs - mapping(address => EnumerableSet.Bytes32Set) accountConfigs; - // Account => initialized status - mapping(address => bool) initializedAccounts; - } - - // ============ Constructor ============ - - constructor() {} - - // ============ Storage Access ============ - - function _getStorage() private pure returns (AutoCollectStorage storage $) { - assembly { - $.slot := STORAGE_NAMESPACE - } - } - - // ============ Module Management (ERC-7579) ============ - - /** - * @notice Called when module is installed for an account - * @param data Encoded initial configurations (optional) - * @dev Format: abi.encode(address[], CollectConfig[]) - * @dev Parallel arrays: assets and configs at same indices - */ - function onInstall(bytes calldata data) external override(IAutoCollectExecutor, IModule) { - AutoCollectStorage storage $ = _getStorage(); - address account = msg.sender; - - // Prevent double initialization - require(!$.initializedAccounts[account], "Already initialized"); - - // Mark account as initialized - $.initializedAccounts[account] = true; - - uint256 configCount = 0; - - // Optional: decode and set initial configurations - if (data.length > 0) { - // Decode as parallel arrays: assets and configs - (address[] memory assets, CollectConfig[] memory configs) = abi.decode(data, (address[], CollectConfig[])); - - // Validate array lengths match - require(assets.length == configs.length, InvalidConfigurationArrays()); - - configCount = assets.length; - - // Process each configuration using the public function - // This handles all validation, state initialization, and event emission - for (uint256 i = 0; i < assets.length; i++) { - configureCollection(assets[i], configs[i]); - } - } - - emit ModuleInstalled(account, configCount); - } - - /** - * @notice Called when module is uninstalled for an account - * @dev Additional data parameter is unused - */ - function onUninstall(bytes calldata) external override(IAutoCollectExecutor, IModule) { - AutoCollectStorage storage $ = _getStorage(); - - // Clean up all configs for this account - address account = msg.sender; - bytes32[] memory configIds = $.accountConfigs[account].values(); - - // Iterate in reverse to efficiently remove from set while deleting configs - for (uint256 i = configIds.length; i > 0; i--) { - bytes32 configId = configIds[i - 1]; - delete $.configs[configId]; - delete $.states[configId]; - $.accountConfigs[account].remove(configId); - } - - // Mark account as uninitialized - delete $.initializedAccounts[account]; - - emit ModuleUninstalled(account, configIds.length); - } - - /** - * @notice Returns whether this module is of a certain type - * @param _typeId The type ID to check - * @return True if this module is an executor (type 0x01) - */ - function isModuleType(uint256 _typeId) external pure override(IAutoCollectExecutor, IModule) returns (bool) { - return _typeId == TYPE_EXECUTOR; - } - - // ============ Configuration Management ============ - - /** - * @notice Configure a new collection or update an existing one - * @param asset The ERC-20 token address - * @param config The collection configuration - * @return configId The generated config ID - */ - function configureCollection(address asset, CollectConfig memory config) public returns (bytes32 configId) { - require(asset != address(0), InvalidAsset()); - require(config.target != address(0), InvalidTarget()); - - AutoCollectStorage storage $ = _getStorage(); - - // Check if module is initialized for this account - require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); - - configId = generateConfigId(msg.sender, asset); - - // Check if this is a new config - if ($.states[configId].asset == address(0)) { - // Initialize state for new config - $.states[configId] = CollectState({asset: asset, lastCollectDate: 0}); - - // Add to account's config set - $.accountConfigs[msg.sender].add(configId); - } - - // Update the configuration - _configureCollection(configId, config); - } - - /** - * @notice Update an existing collection configuration by ID - * @param configId The config ID to update - * @param config The new configuration - */ - function configureCollectionById(bytes32 configId, CollectConfig memory config) external { - AutoCollectStorage storage $ = _getStorage(); - - // Check if module is initialized for this account - require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); - - // Verify config exists and caller owns it - require($.states[configId].asset != address(0), ConfigNotFound()); - require($.accountConfigs[msg.sender].contains(configId), Unauthorized(configId, msg.sender)); - - // Update the configuration - _configureCollection(configId, config); - } - - /** - * @dev Internal function to configure a collection - * @dev IMPORTANT: This function does NOT validate that the config exists or belongs to the caller. - * @dev Caller must perform these checks before calling this function. - * @param configId The config ID to configure - * @param config The configuration to apply - */ - function _configureCollection(bytes32 configId, CollectConfig memory config) internal { - require(config.target != address(0), InvalidTarget()); - - AutoCollectStorage storage $ = _getStorage(); - CollectState memory state = $.states[configId]; - - bool wasEnabled = $.configs[configId].enabled; - $.configs[configId] = config; - - emit CollectionConfigured(msg.sender, state.asset, config.target, configId, config); - - // Emit enable/disable events if status changed - if (config.enabled && !wasEnabled) { - emit CollectionEnabled(msg.sender, state.asset, configId); - } else if (!config.enabled && wasEnabled) { - emit CollectionDisabled(msg.sender, state.asset, configId); - } - } - - /** - * @notice Enable a collection configuration by asset address - * @param asset The asset address - */ - function enableCollection(address asset) external { - bytes32 configId = generateConfigId(msg.sender, asset); - enableCollection(configId); - } - - /** - * @notice Enable a collection configuration by config ID - * @param configId The config ID to enable - */ - function enableCollection(bytes32 configId) public { - AutoCollectStorage storage $ = _getStorage(); - - // Check if module is initialized for this account - require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); - - CollectState memory state = $.states[configId]; - require(state.asset != address(0), ConfigNotFound()); - - // Verify caller owns this config - address account = msg.sender; - require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); - - if (!$.configs[configId].enabled) { - $.configs[configId].enabled = true; - emit CollectionEnabled(account, state.asset, configId); - } - } - - /** - * @notice Disable a collection configuration by asset address - * @param asset The asset address - */ - function disableCollection(address asset) external { - bytes32 configId = generateConfigId(msg.sender, asset); - disableCollection(configId); - } - - /** - * @notice Disable a collection configuration by config ID - * @param configId The config ID to disable - */ - function disableCollection(bytes32 configId) public { - AutoCollectStorage storage $ = _getStorage(); - - // Check if module is initialized for this account - require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); - - CollectState memory state = $.states[configId]; - require(state.asset != address(0), ConfigNotFound()); - - // Verify caller owns this config - address account = msg.sender; - require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); - - if ($.configs[configId].enabled) { - $.configs[configId].enabled = false; - emit CollectionDisabled(account, state.asset, configId); - } - } - - // ============ Execution ============ - - /** - * @notice Trigger all collections for a specific account - * @param account The service account to trigger collections for - * @dev Emits CollectionExecuted for each successful collection - */ - function triggerAllCollections(address account) external nonReentrant { - AutoCollectStorage storage $ = _getStorage(); - - // Check if module is initialized for this account - require($.initializedAccounts[account], ModuleNotInitialized(account)); - - bytes32[] memory configIds = $.accountConfigs[account].values(); - - // Calculate date once for all configs - (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); - - for (uint256 i = 0; i < configIds.length; i++) { - _tryExecuteCollection(configIds[i], account, year, month, day); - } - } - - /** - * @notice Trigger a specific collection by asset - * @param account The service account to collect from - * @param asset The asset to collect - * @dev Emits CollectionExecuted if successful, CollectionSkipped if conditions not met - */ - function triggerCollection(address account, address asset) external nonReentrant { - AutoCollectStorage storage $ = _getStorage(); - - // Check if module is initialized for this account - require($.initializedAccounts[account], ModuleNotInitialized(account)); - - bytes32 configId = generateConfigId(account, asset); - - // Verify config exists and belongs to the account - require($.states[configId].asset != address(0), ConfigNotFound()); - require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); - - // Calculate current date - (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); - - _tryExecuteCollection(configId, account, year, month, day); - } - - /** - * @notice Execute a collection transfer (external for try-catch) - * @param account The service account to transfer from - * @param asset The token address - * @param target The target address to transfer to - * @param amount The amount to transfer - * @dev Must be external/public for try-catch. Only callable by this contract. - */ - function _executeCollectionTransfer(address account, address asset, address target, uint256 amount) external { - require(msg.sender == address(this), "Only self"); - - bytes memory result = - _execute(account, asset, 0, abi.encodeWithSelector(IERC20.transfer.selector, target, amount)); - - // Check return value (handle non-standard tokens like USDT that don't return bool) - if (result.length > 0) { - require(result.length == 32, InvalidTransferReturn(result)); - require(abi.decode(result, (bool)), TransferReturnedFalse(result)); - } - } - - /** - * @dev Internal function to attempt a collection execution - * @param configId The config ID to execute - * @param account The service account that owns the configuration - * @param year Current year - * @param month Current month (1-12) - * @param day Current day (1-31) - * @dev Emits CollectionExecuted on success, CollectionSkipped for conditions not met - * @dev Uses graceful failure handling - does not revert on collection failures - */ - function _tryExecuteCollection(bytes32 configId, address account, uint256 year, uint256 month, uint256 day) - private - { - AutoCollectStorage storage $ = _getStorage(); - - CollectConfig memory config = $.configs[configId]; - CollectState storage state = $.states[configId]; - - // Validate and calculate collection - (bool canExecute, uint256 currentBalance, uint256 collectAmount, uint256 currentDate,) = - _validateAndCalculateCollection(config, state, account, year, month, day); - - if (!canExecute) { - // Always emit skip event for complete visibility - emit CollectionSkipped( - account, state.asset, configId, currentBalance, config.threshold, config.minimumRemaining, collectAmount - ); - return; - } - - // Try to execute transfer - wrapped in try-catch to prevent batch operation failure - // If this fails, other collections in the batch can still succeed - try this._executeCollectionTransfer(account, state.asset, config.target, collectAmount) { - // Update state AFTER successful transfer - state.lastCollectDate = currentDate; - emit CollectionExecuted(account, state.asset, config.target, configId, collectAmount); - } catch Error(string memory reason) { - emit CollectionFailed(account, state.asset, configId, reason); - } catch (bytes memory) { - emit CollectionFailed(account, state.asset, configId, "Transfer failed"); - } - } - - /** - * @dev Validates if a collection can be executed and calculates the amount - * @param config The collection configuration - * @param state The collection state (storage pointer for reading) - * @param account The service account - * @param year Current year - * @param month Current month (1-12) - * @param day Current day (1-31) - * @return canExecute Whether the collection can be executed - * @return currentBalance The current balance of the asset in the account - * @return collectAmount The amount that would be collected (balance - minimumRemaining) - * @return currentDate The encoded current date (YYYYMMDD) - * @return reason Error message if cannot execute - */ - function _validateAndCalculateCollection( - CollectConfig memory config, - CollectState memory state, - address account, - uint256 year, - uint256 month, - uint256 day - ) - private - view - returns ( - bool canExecute, - uint256 currentBalance, - uint256 collectAmount, - uint256 currentDate, - string memory reason - ) - { - // Check if enabled - if (!config.enabled) { - return (false, 0, 0, 0, "Collection not enabled"); - } - - // Check once per day limit using calendar days - currentDate = year * 10000 + month * 100 + day; - if (currentDate <= state.lastCollectDate) { - return (false, 0, 0, currentDate, "Already collected today"); - } - - // Get current balance - currentBalance = IERC20(state.asset).balanceOf(account); - - // Calculate collect amount (balance minus what we want to keep) - collectAmount = currentBalance >= config.minimumRemaining ? currentBalance - config.minimumRemaining : 0; - - // Check for zero balance (skip collection) - if (currentBalance == 0) { - return (false, currentBalance, collectAmount, currentDate, "Balance is zero"); - } - - // Check threshold requirement - if (currentBalance < config.threshold) { - return (false, currentBalance, collectAmount, currentDate, "Balance below threshold"); - } - - // Skip if nothing to collect - if (collectAmount == 0) { - return (false, currentBalance, collectAmount, currentDate, "Collect amount would be zero"); - } - - return (true, currentBalance, collectAmount, currentDate, ""); - } - - // ============ View Functions ============ - - /// @inheritdoc IAutoCollectExecutor - function isInitialized(address smartAccount) external view override(IAutoCollectExecutor, IModule) returns (bool) { - AutoCollectStorage storage $ = _getStorage(); - return $.initializedAccounts[smartAccount]; - } - - /** - * @notice Generate a config ID for given parameters - * @param account The service account - * @param asset The token address - * @return The generated config ID - */ - function generateConfigId(address account, address asset) public pure returns (bytes32) { - return keccak256(abi.encode("CollectConfig", account, asset)); - } - - /** - * @notice Get all collection configurations for an account - * @param account The account to query - * @return configs Array of configurations - * @return states Array of states - */ - function getCollectionConfigs(address account) - external - view - returns (CollectConfig[] memory configs, CollectState[] memory states) - { - AutoCollectStorage storage $ = _getStorage(); - - bytes32[] memory configIds = $.accountConfigs[account].values(); - configs = new CollectConfig[](configIds.length); - states = new CollectState[](configIds.length); - - for (uint256 i = 0; i < configIds.length; i++) { - configs[i] = $.configs[configIds[i]]; - states[i] = $.states[configIds[i]]; - } - } - - /** - * @notice Check if a collection can be executed - * @param account The account that owns the config - * @param asset The asset to check - * @return canExecute Whether the collection can be executed - * @return reason Reason if cannot execute - */ - function canExecuteCollection(address account, address asset) - external - view - returns (bool canExecute, string memory reason) - { - AutoCollectStorage storage $ = _getStorage(); - - bytes32 configId = generateConfigId(account, asset); - CollectConfig memory config = $.configs[configId]; - CollectState memory state = $.states[configId]; - - if (state.asset == address(0)) { - return (false, "Config not found"); - } - - if (!$.accountConfigs[account].contains(configId)) { - return (false, "Account doesn't own config"); - } - - if (!config.enabled) { - return (false, "Collection disabled"); - } - - // Get current date - (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); - - // Use shared validation logic - (bool canExec,,,, string memory errorReason) = - _validateAndCalculateCollection(config, state, account, year, month, day); - - return (canExec, errorReason); - } - - /** - * @notice Get collection config by asset - * @param account The service account - * @param asset The token address - * @return config The configuration - * @return state The state - */ - function getCollectionConfig(address account, address asset) - external - view - returns (CollectConfig memory config, CollectState memory state) - { - bytes32 configId = generateConfigId(account, asset); - AutoCollectStorage storage $ = _getStorage(); - config = $.configs[configId]; - state = $.states[configId]; - } - - /** - * @notice Get collection config by config ID - * @param configId The config ID - * @return config The configuration - * @return state The state - */ - function getCollectionConfigById(bytes32 configId) - external - view - returns (CollectConfig memory config, CollectState memory state) - { - AutoCollectStorage storage $ = _getStorage(); - config = $.configs[configId]; - state = $.states[configId]; - } -} diff --git a/typescript/packages/account-modules/src/AutoTopUpExecutor.sol b/typescript/packages/account-modules/src/AutoTopUpExecutor.sol deleted file mode 100644 index effb355..0000000 --- a/typescript/packages/account-modules/src/AutoTopUpExecutor.sol +++ /dev/null @@ -1,551 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {IAutoTopUpExecutor} from "./IAutoTopUpExecutor.sol"; -import {ERC7579ExecutorBase} from "modulekit/src/module-bases/ERC7579ExecutorBase.sol"; -import {IModule} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; -import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; -import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; - -/** - * @title AutoTopUpExecutor - * @notice ERC-7579 executor module for automatic ERC-20 token balance management - * @dev Enables permissionless triggering of pre-configured top-ups from Safe accounts to agent accounts - */ -contract AutoTopUpExecutor is IAutoTopUpExecutor, ERC7579ExecutorBase, ReentrancyGuard { - using EnumerableSet for EnumerableSet.Bytes32Set; - using SafeERC20 for IERC20; - - // ============ Storage ============ - - /// @dev ERC-7201 namespace for storage - /// @custom:storage-location erc7201:autotopup.storage.AutoTopUpExecutor - // keccak256(abi.encode(uint256(keccak256("autotopup.storage.AutoTopUpExecutor")) - 1)) & ~bytes32(uint256(0xff)) - bytes32 private constant STORAGE_NAMESPACE = 0xf1fdef444005737c1eaec423fc423d55d53d0a09b4618f0f50ba7fb8df2b0400; - - /// @custom:storage-namespace AutoTopUpStorage - struct AutoTopUpStorage { - // Config ID => user configuration - mapping(bytes32 => TopUpConfig) configs; - // Config ID => internal state - mapping(bytes32 => TopUpState) states; - // Account => set of config IDs - mapping(address => EnumerableSet.Bytes32Set) accountConfigs; - // Account => initialized status - mapping(address => bool) initializedAccounts; - } - - // ============ Constructor ============ - - constructor() {} - - // ============ Storage Access ============ - - function _getStorage() private pure returns (AutoTopUpStorage storage $) { - assembly { - $.slot := STORAGE_NAMESPACE - } - } - - // ============ Module Management (ERC-7579) ============ - - /** - * @notice Called when module is installed for an account - * @param data Encoded initial configurations (optional) - * @dev Format: abi.encode(address[], address[], TopUpConfig[]) - * @dev Parallel arrays: agents, assets, and configs at same indices - */ - function onInstall(bytes calldata data) external override(IAutoTopUpExecutor, IModule) { - AutoTopUpStorage storage $ = _getStorage(); - address account = msg.sender; - - // Prevent double initialization - require(!$.initializedAccounts[account], "Already initialized"); - - // Mark account as initialized - $.initializedAccounts[account] = true; - - uint256 configCount = 0; - - // Optional: decode and set initial configurations - if (data.length > 0) { - // Decode as parallel arrays: agents, assets, and configs - (address[] memory agents, address[] memory assets, TopUpConfig[] memory configs) = - abi.decode(data, (address[], address[], TopUpConfig[])); - - // Validate array lengths match - require(agents.length == assets.length && agents.length == configs.length, InvalidConfigurationArrays()); - - configCount = agents.length; - - // Process each configuration using the public function - // This handles all validation, state initialization, and event emission - for (uint256 i = 0; i < agents.length; i++) { - configureTopUp(agents[i], assets[i], configs[i]); - } - } - - emit ModuleInstalled(account, configCount); - } - - /** - * @notice Called when module is uninstalled for an account - * @dev Additional data parameter is unused - */ - function onUninstall(bytes calldata) external override(IAutoTopUpExecutor, IModule) { - AutoTopUpStorage storage $ = _getStorage(); - - // Clean up all configs for this account - address account = msg.sender; - bytes32[] memory configIds = $.accountConfigs[account].values(); - - // Iterate in reverse to efficiently remove from set while deleting configs - for (uint256 i = configIds.length; i > 0; i--) { - bytes32 configId = configIds[i - 1]; - delete $.configs[configId]; - delete $.states[configId]; - $.accountConfigs[account].remove(configId); - } - - // Mark account as uninitialized - delete $.initializedAccounts[account]; - - emit ModuleUninstalled(account, configIds.length); - } - - /** - * @notice Returns whether this module is of a certain type - * @param _typeId The type ID to check - * @return True if this module is an executor (type 0x01) - */ - function isModuleType(uint256 _typeId) external pure override(IAutoTopUpExecutor, IModule) returns (bool) { - return _typeId == TYPE_EXECUTOR; - } - - // ============ Configuration Management ============ - - /** - * @notice Configure a new top-up or update an existing one - * @param agent The agent account to top up - * @param asset The ERC-20 token address - * @param config The top-up configuration - * @return configId The generated config ID - */ - function configureTopUp(address agent, address asset, TopUpConfig memory config) public returns (bytes32 configId) { - require(agent != address(0) && agent != msg.sender, InvalidAgent()); - require(asset != address(0), InvalidAsset()); - - AutoTopUpStorage storage $ = _getStorage(); - - // Check if module is initialized for this account - require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); - - configId = generateConfigId(msg.sender, agent, asset); - - // Check if this is a new config - if ($.states[configId].agent == address(0)) { - // Initialize state for new config - $.states[configId] = - TopUpState({agent: agent, asset: asset, lastTopUpDay: 0, monthlySpent: 0, lastResetMonth: 0}); - - // Add to account's config set - $.accountConfigs[msg.sender].add(configId); - } - - // Update the configuration - _configureTopUp(configId, config); - } - - /** - * @notice Update an existing top-up configuration by ID - * @param configId The config ID to update - * @param config The new configuration - */ - function configureTopUpById(bytes32 configId, TopUpConfig memory config) external { - AutoTopUpStorage storage $ = _getStorage(); - - // Check if module is initialized for this account - require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); - - // Verify config exists and caller owns it - require($.states[configId].agent != address(0), ConfigNotFound()); - require($.accountConfigs[msg.sender].contains(configId), Unauthorized(configId, msg.sender)); - - // Update the configuration - _configureTopUp(configId, config); - } - - /** - * @dev Internal function to configure a top-up - * @dev IMPORTANT: This function does NOT validate that the config exists or belongs to the caller. - * @dev Caller must perform these checks before calling this function. - * @param configId The config ID to configure - * @param config The configuration to apply - */ - function _configureTopUp(bytes32 configId, TopUpConfig memory config) internal { - // Note: dailyLimit can be greater than monthlyLimit for use cases where users want - // monthly budget constraints but no daily restrictions - require(config.dailyLimit > 0 && config.monthlyLimit > 0, InvalidConfiguration()); - - AutoTopUpStorage storage $ = _getStorage(); - TopUpState memory state = $.states[configId]; - - bool wasEnabled = $.configs[configId].enabled; - $.configs[configId] = config; - - emit TopUpConfigured(msg.sender, state.agent, state.asset, configId, config); - - // Emit enable/disable events if status changed - if (config.enabled && !wasEnabled) { - emit TopUpEnabled(msg.sender, state.agent, state.asset, configId); - } else if (!config.enabled && wasEnabled) { - emit TopUpDisabled(msg.sender, state.agent, state.asset, configId); - } - } - - /** - * @notice Enable a top-up configuration - * @param configId The config ID to enable - */ - function enableTopUp(bytes32 configId) external { - AutoTopUpStorage storage $ = _getStorage(); - - // Check if module is initialized for this account - require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); - - TopUpState memory state = $.states[configId]; - require(state.agent != address(0), ConfigNotFound()); - - // Verify caller owns this config - address account = msg.sender; - require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); - - if (!$.configs[configId].enabled) { - $.configs[configId].enabled = true; - emit TopUpEnabled(account, state.agent, state.asset, configId); - } - } - - /** - * @notice Disable a top-up configuration - * @param configId The config ID to disable - */ - function disableTopUp(bytes32 configId) external { - AutoTopUpStorage storage $ = _getStorage(); - - // Check if module is initialized for this account - require($.initializedAccounts[msg.sender], ModuleNotInitialized(msg.sender)); - - TopUpState memory state = $.states[configId]; - require(state.agent != address(0), ConfigNotFound()); - - // Verify caller owns this config - address account = msg.sender; - require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); - - if ($.configs[configId].enabled) { - $.configs[configId].enabled = false; - emit TopUpDisabled(account, state.agent, state.asset, configId); - } - } - - // ============ Execution ============ - - /** - * @notice Trigger all top-ups for a specific account - * @param account The account to trigger top-ups for - * @dev Emits TopUpExecuted for each successful top-up - */ - function triggerTopUps(address account) external nonReentrant { - AutoTopUpStorage storage $ = _getStorage(); - - // Check if module is initialized for this account - require($.initializedAccounts[account], ModuleNotInitialized(account)); - - bytes32[] memory configIds = $.accountConfigs[account].values(); - - // Calculate date once for all configs - (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); - - for (uint256 i = 0; i < configIds.length; i++) { - _tryExecuteTopUp(configIds[i], account, year, month, day); - } - } - - /** - * @notice Trigger a specific top-up by config ID - * @param account The account that owns the config - * @param configId The config ID to trigger - * @dev Emits TopUpExecuted if successful, reverts on transfer failure - */ - function triggerTopUp(address account, bytes32 configId) external nonReentrant { - AutoTopUpStorage storage $ = _getStorage(); - - // Check if module is initialized for this account - require($.initializedAccounts[account], ModuleNotInitialized(account)); - - // Verify config exists and belongs to the account - require($.states[configId].agent != address(0), ConfigNotFound()); - require($.accountConfigs[account].contains(configId), Unauthorized(configId, account)); - - // Calculate current date - (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); - - _tryExecuteTopUp(configId, account, year, month, day); - } - - /** - * @notice Execute a top-up transfer (external for try-catch) - * @param account The main account to transfer from - * @param asset The token address - * @param agent The agent account to transfer to - * @param amount The amount to transfer - * @dev Must be external/public for try-catch. Only callable by this contract. - */ - function _executeTopUpTransfer(address account, address asset, address agent, uint256 amount) external { - require(msg.sender == address(this), "Only self"); - - bytes memory result = - _execute(account, asset, 0, abi.encodeWithSelector(IERC20.transfer.selector, agent, amount)); - - // Check return value (handle non-standard tokens like USDT that don't return bool) - if (result.length > 0) { - require(result.length == 32, InvalidTransferReturn(result)); - require(abi.decode(result, (bool)), TransferReturnedFalse(result)); - } - } - - /** - * @dev Internal function to attempt a top-up execution - * @param configId The config ID to execute - * @param account The Safe account that owns the configuration - * @param year Current year - * @param month Current month (1-12) - * @param day Current day (1-31) - * @dev Emits TopUpExecuted on success, TopUpFailed for insufficient balance - * @dev Reverts on transfer failure (indicates configuration error) - */ - /** - * @dev Validates if a top-up can be executed and calculates the amount - * @param config The top-up configuration - * @param state The top-up state (storage pointer for reading) - * @param account The Safe account - * @param year Current year - * @param month Current month (1-12) - * @param day Current day (1-31) - * @return canExecute Whether the top-up can be executed - * @return topUpAmount The amount to top up (0 if cannot execute) - * @return currentDay The encoded current day (YYYYMMDD) - * @return currentMonth The encoded current month (year * 12 + month) - * @return reason Error message if cannot execute - */ - function _validateAndCalculateTopUp( - TopUpConfig memory config, - TopUpState memory state, - address account, - uint256 year, - uint256 month, - uint256 day - ) - private - view - returns (bool canExecute, uint256 topUpAmount, uint256 currentDay, uint256 currentMonth, string memory reason) - { - // Check if enabled - if (!config.enabled) { - return (false, 0, 0, 0, "Top-up not enabled"); - } - - // Check once per day limit using calendar days - currentDay = year * 10000 + month * 100 + day; - if (currentDay <= state.lastTopUpDay) { - return (false, 0, currentDay, 0, "Already topped up today"); - } - - // Check monthly limit using calendar months - currentMonth = year * 12 + month; - uint256 monthlySpent = state.monthlySpent; - if (currentMonth > state.lastResetMonth) { - monthlySpent = 0; // Will be reset in actual execution - } - - // Check if agent needs top-up - uint256 agentBalance = IERC20(state.asset).balanceOf(state.agent); - if (agentBalance >= config.dailyLimit) { - return (false, 0, currentDay, currentMonth, "Agent balance sufficient"); - } - - // Calculate top-up amount - topUpAmount = config.dailyLimit - agentBalance; - - // Apply monthly limit - if (monthlySpent + topUpAmount > config.monthlyLimit) { - topUpAmount = config.monthlyLimit - monthlySpent; - if (topUpAmount == 0) { - return (false, 0, currentDay, currentMonth, "Monthly limit reached"); - } - } - - // Check account has sufficient balance - if (IERC20(state.asset).balanceOf(account) < topUpAmount) { - return (false, 0, currentDay, currentMonth, "Insufficient account balance"); - } - - return (true, topUpAmount, currentDay, currentMonth, ""); - } - - function _tryExecuteTopUp(bytes32 configId, address account, uint256 year, uint256 month, uint256 day) private { - AutoTopUpStorage storage $ = _getStorage(); - - TopUpConfig memory config = $.configs[configId]; - TopUpState storage state = $.states[configId]; - - // Validate and calculate top-up - (bool canExecute, uint256 topUpAmount, uint256 currentDay, uint256 currentMonth, string memory reason) = - _validateAndCalculateTopUp(config, state, account, year, month, day); - - if (!canExecute) { - // Only emit failure for insufficient balance (not for normal conditions like already topped up) - if (keccak256(bytes(reason)) == keccak256(bytes("Insufficient account balance"))) { - emit TopUpFailed(account, state.agent, state.asset, configId, reason); - } - return; - } - - // Try to execute transfer - wrapped in try-catch to prevent batch operation failure - // If this fails, other top-ups in the batch can still succeed - try this._executeTopUpTransfer(account, state.asset, state.agent, topUpAmount) { - // Update state AFTER successful transfer - - // Reset monthly counter if needed - if (currentMonth > state.lastResetMonth) { - state.monthlySpent = 0; - state.lastResetMonth = currentMonth; - } - - state.lastTopUpDay = currentDay; - state.monthlySpent += topUpAmount; - - emit TopUpExecuted(account, state.agent, state.asset, configId, topUpAmount); - } catch Error(string memory errorReason) { - emit TopUpFailed(account, state.agent, state.asset, configId, errorReason); - } catch (bytes memory) { - emit TopUpFailed(account, state.agent, state.asset, configId, "Transfer failed"); - } - } - - // ============ View Functions ============ - - /// @inheritdoc IAutoTopUpExecutor - function isInitialized(address smartAccount) external view override(IAutoTopUpExecutor, IModule) returns (bool) { - AutoTopUpStorage storage $ = _getStorage(); - return $.initializedAccounts[smartAccount]; - } - - /** - * @notice Generate a config ID for given parameters - * @param account The Safe account - * @param agent The agent account - * @param asset The token address - * @return The generated config ID - */ - function generateConfigId(address account, address agent, address asset) public pure returns (bytes32) { - return keccak256(abi.encode("TopUpConfig", account, agent, asset)); - } - - /** - * @notice Get all top-up configurations for an account - * @param account The account to query - * @return configs Array of configurations - * @return states Array of states - */ - function getTopUpConfigs(address account) - external - view - returns (TopUpConfig[] memory configs, TopUpState[] memory states) - { - AutoTopUpStorage storage $ = _getStorage(); - - bytes32[] memory configIds = $.accountConfigs[account].values(); - configs = new TopUpConfig[](configIds.length); - states = new TopUpState[](configIds.length); - - for (uint256 i = 0; i < configIds.length; i++) { - configs[i] = $.configs[configIds[i]]; - states[i] = $.states[configIds[i]]; - } - } - - /** - * @notice Check if a top-up can be executed - * @param account The account that owns the config - * @param configId The config ID to check - * @return canExecute Whether the top-up can be executed - * @return reason Reason if cannot execute - */ - function canExecuteTopUp(address account, bytes32 configId) - external - view - returns (bool canExecute, string memory reason) - { - AutoTopUpStorage storage $ = _getStorage(); - - TopUpConfig memory config = $.configs[configId]; - TopUpState memory state = $.states[configId]; - - if (state.agent == address(0)) { - return (false, "Config not found"); - } - - if (!$.accountConfigs[account].contains(configId)) { - return (false, "Account doesn't own config"); - } - - if (!config.enabled) { - return (false, "Top-up disabled"); - } - - // Get current date - (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); - - // Use shared validation logic - (bool canExec,,,, string memory errorReason) = - _validateAndCalculateTopUp(config, state, account, year, month, day); - - return (canExec, errorReason); - } - - /** - * @notice Get top-up by config ID - * @param configId The config ID - * @return config The configuration - * @return state The state - */ - function getTopUpById(bytes32 configId) external view returns (TopUpConfig memory config, TopUpState memory state) { - AutoTopUpStorage storage $ = _getStorage(); - config = $.configs[configId]; - state = $.states[configId]; - } - - /** - * @notice Get top-up by account, agent, and asset - * @param account The Safe account - * @param agent The agent account - * @param asset The token address - * @return config The configuration - * @return state The state - */ - function getTopUp(address account, address agent, address asset) - external - view - returns (TopUpConfig memory config, TopUpState memory state) - { - bytes32 configId = generateConfigId(account, agent, asset); - AutoTopUpStorage storage $ = _getStorage(); - config = $.configs[configId]; - state = $.states[configId]; - } -} diff --git a/typescript/packages/account-modules/src/IAutoCollectExecutor.sol b/typescript/packages/account-modules/src/IAutoCollectExecutor.sol deleted file mode 100644 index caeb7b9..0000000 --- a/typescript/packages/account-modules/src/IAutoCollectExecutor.sol +++ /dev/null @@ -1,214 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -/** - * @title IAutoCollectExecutor - * @notice Interface for the ERC-7579 executor module that manages automatic ERC-20 token collection - * @dev Enables permissionless triggering of pre-configured collections from service accounts to main accounts - */ -interface IAutoCollectExecutor { - // ============ Structs ============ - - /// @notice User-configurable parameters - struct CollectConfig { - address target; // Main account to collect funds to - uint256 threshold; // Minimum balance to trigger collection (0 = no threshold) - uint256 minimumRemaining; // Minimum amount to leave in account after collection (0 = collect all) - bool enabled; // Configuration active status - } - - /// @notice Immutable identity and internal state (not user-editable) - struct CollectState { - address asset; // ERC-20 token address (immutable, part of config ID) - uint256 lastCollectDate; // Last collection date (YYYYMMDD format) - } - - // ============ Events ============ - - event ModuleInstalled(address indexed account, uint256 initialConfigs); - - event ModuleUninstalled(address indexed account, uint256 removedConfigs); - - event CollectionConfigured( - address indexed account, address indexed asset, address target, bytes32 indexed configId, CollectConfig config - ); - - event CollectionExecuted( - address indexed account, address indexed asset, address target, bytes32 indexed configId, uint256 amount - ); - - event CollectionSkipped( - address indexed account, - address indexed asset, - bytes32 indexed configId, - uint256 balance, - uint256 threshold, - uint256 minimumRemaining, - uint256 collectAmount - ); - - event CollectionFailed(address indexed account, address indexed asset, bytes32 indexed configId, string reason); - - event CollectionEnabled(address indexed account, address indexed asset, bytes32 indexed configId); - - event CollectionDisabled(address indexed account, address indexed asset, bytes32 indexed configId); - - // ============ Errors ============ - - error ModuleNotInitialized(address account); - error InvalidConfiguration(); - error ConfigNotFound(); - error Unauthorized(bytes32 configId, address caller); - error InvalidAsset(); - error InvalidTarget(); - error AlreadyCollectedToday(); - error BalanceBelowThreshold(); - error InvalidConfigurationArrays(); - error TransferFailed(); - error InvalidTransferReturn(bytes result); - error TransferReturnedFalse(bytes result); - - // ============ Module Management (ERC-7579) ============ - - /** - * @notice Called when module is installed for an account - * @param data Encoded initial configurations (optional) - * @dev Format: abi.encode(address[], CollectConfig[]) - * @dev Parallel arrays: assets and configs at same indices - */ - function onInstall(bytes calldata data) external; - - /** - * @notice Called when module is uninstalled for an account - * @dev Additional data parameter is unused - */ - function onUninstall(bytes calldata) external; - - /** - * @notice Returns whether this module is of a certain type - * @param _typeId The type ID to check - * @return True if this module is an executor (type 0x01) - */ - function isModuleType(uint256 _typeId) external pure returns (bool); - - /** - * @notice Check if module is initialized for an account - * @param smartAccount The account to check - * @return Whether the module is initialized - */ - function isInitialized(address smartAccount) external view returns (bool); - - // ============ Configuration Management ============ - - /** - * @notice Configure a new collection or update an existing one - * @param asset The ERC-20 token address - * @param config The collection configuration - * @return configId The generated config ID - */ - function configureCollection(address asset, CollectConfig memory config) external returns (bytes32 configId); - - /** - * @notice Update an existing collection configuration by ID - * @param configId The config ID to update - * @param config The new configuration - */ - function configureCollectionById(bytes32 configId, CollectConfig memory config) external; - - /** - * @notice Enable a collection configuration by asset address - * @param asset The asset address - */ - function enableCollection(address asset) external; - - /** - * @notice Enable a collection configuration by config ID - * @param configId The config ID to enable - */ - function enableCollection(bytes32 configId) external; - - /** - * @notice Disable a collection configuration by asset address - * @param asset The asset address - */ - function disableCollection(address asset) external; - - /** - * @notice Disable a collection configuration by config ID - * @param configId The config ID to disable - */ - function disableCollection(bytes32 configId) external; - - // ============ Execution ============ - - /** - * @notice Trigger all collections for a specific account - * @param account The service account to trigger collections for - * @dev Emits CollectionExecuted for each successful collection - */ - function triggerAllCollections(address account) external; - - /** - * @notice Trigger a specific collection by asset - * @param account The service account to collect from - * @param asset The asset to collect - * @dev Emits CollectionExecuted if successful, CollectionSkipped if conditions not met - */ - function triggerCollection(address account, address asset) external; - - // ============ View Functions ============ - - /** - * @notice Generate a config ID for given parameters - * @param account The service account - * @param asset The token address - * @return The generated config ID - */ - function generateConfigId(address account, address asset) external pure returns (bytes32); - - /** - * @notice Get all collection configurations for an account - * @param account The account to query - * @return configs Array of configurations - * @return states Array of states - */ - function getCollectionConfigs(address account) - external - view - returns (CollectConfig[] memory configs, CollectState[] memory states); - - /** - * @notice Check if a collection can be executed - * @param account The account that owns the config - * @param asset The asset to check - * @return canExecute Whether the collection can be executed - * @return reason Reason if cannot execute - */ - function canExecuteCollection(address account, address asset) - external - view - returns (bool canExecute, string memory reason); - - /** - * @notice Get collection config by asset - * @param account The service account - * @param asset The token address - * @return config The configuration - * @return state The state - */ - function getCollectionConfig(address account, address asset) - external - view - returns (CollectConfig memory config, CollectState memory state); - - /** - * @notice Get collection config by config ID - * @param configId The config ID - * @return config The configuration - * @return state The state - */ - function getCollectionConfigById(bytes32 configId) - external - view - returns (CollectConfig memory config, CollectState memory state); -} diff --git a/typescript/packages/account-modules/src/IAutoTopUpExecutor.sol b/typescript/packages/account-modules/src/IAutoTopUpExecutor.sol deleted file mode 100644 index 1f27799..0000000 --- a/typescript/packages/account-modules/src/IAutoTopUpExecutor.sol +++ /dev/null @@ -1,198 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -/** - * @title IAutoTopUpExecutor - * @notice Interface for the ERC-7579 executor module that manages automatic ERC-20 token balance top-ups - * @dev Enables permissionless triggering of pre-configured top-ups from Safe accounts to agent accounts - */ -interface IAutoTopUpExecutor { - // ============ Structs ============ - - /// @notice User-configurable parameters - struct TopUpConfig { - uint256 dailyLimit; // Target balance to maintain (max top-up per day) - uint256 monthlyLimit; // Maximum total top-ups per month - bool enabled; // Configuration active status - } - - /// @notice Immutable identity and internal state (not user-editable) - struct TopUpState { - address agent; // Target agent account (immutable, part of config ID) - address asset; // ERC-20 token address (immutable, part of config ID) - uint256 lastTopUpDay; // Last top-up day (year * 10000 + month * 100 + day) - uint256 monthlySpent; // Amount topped up this month - uint256 lastResetMonth; // Last reset month (year * 12 + month) - } - - // ============ Events ============ - - event ModuleInstalled(address indexed account, uint256 initialConfigs); - - event ModuleUninstalled(address indexed account, uint256 removedConfigs); - - event TopUpConfigured( - address indexed account, address indexed agent, address asset, bytes32 indexed configId, TopUpConfig config - ); - - event TopUpExecuted( - address indexed account, address indexed agent, address asset, bytes32 indexed configId, uint256 amount - ); - - event TopUpFailed( - address indexed account, address indexed agent, address asset, bytes32 indexed configId, string reason - ); - - event TopUpEnabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId); - - event TopUpDisabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId); - - // ============ Errors ============ - - error ModuleNotInitialized(address account); - error InvalidConfiguration(); - error ConfigNotFound(); - error Unauthorized(bytes32 configId, address caller); - error InvalidAgent(); - error InvalidAsset(); - error AlreadyToppedUpToday(); - error MonthlyLimitExceeded(); - error InsufficientBalance(); - error TopUpNotEnabled(); - error TransferFailed(); - error InvalidTransferReturn(bytes result); - error TransferReturnedFalse(bytes result); - error InvalidConfigurationArrays(); - - // ============ Module Management (ERC-7579) ============ - - /** - * @notice Called when module is installed for an account - * @param data Encoded initial configurations (optional) - * @dev Format: abi.encode(address[], address[], TopUpConfig[]) - * @dev Parallel arrays: agents, assets, and configs at same indices - */ - function onInstall(bytes calldata data) external; - - /** - * @notice Called when module is uninstalled for an account - * @dev Additional data parameter is unused - */ - function onUninstall(bytes calldata) external; - - /** - * @notice Returns whether this module is of a certain type - * @param _typeId The type ID to check - * @return True if this module is an executor (type 0x01) - */ - function isModuleType(uint256 _typeId) external pure returns (bool); - - /** - * @notice Check if module is initialized for an account - * @param smartAccount The account to check - * @return Whether the module is initialized - */ - function isInitialized(address smartAccount) external view returns (bool); - - // ============ Configuration Management ============ - - /** - * @notice Configure a new top-up or update an existing one - * @param agent The agent account to top up - * @param asset The ERC-20 token address - * @param config The top-up configuration - * @return configId The generated config ID - */ - function configureTopUp(address agent, address asset, TopUpConfig memory config) external returns (bytes32 configId); - - /** - * @notice Update an existing top-up configuration by ID - * @param configId The config ID to update - * @param config The new configuration - */ - function configureTopUpById(bytes32 configId, TopUpConfig memory config) external; - - /** - * @notice Enable a top-up configuration - * @param configId The config ID to enable - */ - function enableTopUp(bytes32 configId) external; - - /** - * @notice Disable a top-up configuration - * @param configId The config ID to disable - */ - function disableTopUp(bytes32 configId) external; - - // ============ Execution ============ - - /** - * @notice Trigger all top-ups for a specific account - * @param account The account to trigger top-ups for - * @dev Emits TopUpExecuted for each successful top-up - */ - function triggerTopUps(address account) external; - - /** - * @notice Trigger a specific top-up by config ID - * @param account The account that owns the config - * @param configId The config ID to trigger - * @dev Emits TopUpExecuted if successful, reverts on transfer failure - */ - function triggerTopUp(address account, bytes32 configId) external; - - // ============ View Functions ============ - - /** - * @notice Generate a config ID for given parameters - * @param account The Safe account - * @param agent The agent account - * @param asset The token address - * @return The generated config ID - */ - function generateConfigId(address account, address agent, address asset) external pure returns (bytes32); - - /** - * @notice Get all top-up configurations for an account - * @param account The account to query - * @return configs Array of configurations - * @return states Array of states - */ - function getTopUpConfigs(address account) - external - view - returns (TopUpConfig[] memory configs, TopUpState[] memory states); - - /** - * @notice Check if a top-up can be executed - * @param account The account that owns the config - * @param configId The config ID to check - * @return canExecute Whether the top-up can be executed - * @return reason Reason if cannot execute - */ - function canExecuteTopUp(address account, bytes32 configId) - external - view - returns (bool canExecute, string memory reason); - - /** - * @notice Get top-up by config ID - * @param configId The config ID - * @return config The configuration - * @return state The state - */ - function getTopUpById(bytes32 configId) external view returns (TopUpConfig memory config, TopUpState memory state); - - /** - * @notice Get top-up by account, agent, and asset - * @param account The Safe account - * @param agent The agent account - * @param asset The token address - * @return config The configuration - * @return state The state - */ - function getTopUp(address account, address agent, address asset) - external - view - returns (TopUpConfig memory config, TopUpState memory state); -} diff --git a/typescript/packages/account-modules/test/AutoCollectExecutor.integration.t.sol b/typescript/packages/account-modules/test/AutoCollectExecutor.integration.t.sol deleted file mode 100644 index d03be8b..0000000 --- a/typescript/packages/account-modules/test/AutoCollectExecutor.integration.t.sol +++ /dev/null @@ -1,675 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {Test, Vm, console2} from "forge-std/Test.sol"; -import { - RhinestoneModuleKit, - AccountType, - AccountInstance, - UserOpData -} from "modulekit/src/test/RhinestoneModuleKit.sol"; -import {ModuleKitHelpers} from "modulekit/src/test/ModuleKitHelpers.sol"; -import {AutoCollectExecutor} from "../src/AutoCollectExecutor.sol"; -import {IAutoCollectExecutor} from "../src/IAutoCollectExecutor.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { - IModule, - MODULE_TYPE_VALIDATOR, - MODULE_TYPE_EXECUTOR, - MODULE_TYPE_FALLBACK, - MODULE_TYPE_HOOK -} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; -import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; - -// Import mocks -import {MockERC20} from "./mocks/MockERC20.sol"; -import {MockUSDT} from "./mocks/MockUSDT.sol"; -import {MaliciousCollectToken} from "./mocks/MaliciousCollectToken.sol"; - -// Integration tests using RhinestoneModuleKit for proper Safe interaction -contract AutoCollectExecutorIntegrationTest is Test, RhinestoneModuleKit { - using SafeERC20 for IERC20; - using ModuleKitHelpers for AccountInstance; - - // Main contracts - AutoCollectExecutor public executor; - MockERC20 public token; - MockUSDT public usdt; - - // Test accounts - AccountInstance public serviceAccount; - address public mainAccount; - address public stranger; - - // Test constants - uint256 constant THRESHOLD = 10 ether; - uint256 constant INITIAL_SERVICE_BALANCE = 100 ether; - uint256 constant INITIAL_MAIN_BALANCE = 1000 ether; - - // Events from the module - event ModuleInstalled(address indexed account, uint256 initialConfigs); - event ModuleUninstalled(address indexed account, uint256 removedConfigs); - event CollectionConfigured( - address indexed account, - address indexed asset, - address target, - bytes32 indexed configId, - IAutoCollectExecutor.CollectConfig config - ); - event CollectionExecuted( - address indexed account, address indexed asset, address target, bytes32 indexed configId, uint256 amount - ); - event CollectionSkipped( - address indexed account, - address indexed asset, - bytes32 indexed configId, - uint256 balance, - uint256 threshold, - uint256 minimumRemaining, - uint256 collectAmount - ); - event CollectionFailed(address indexed account, address indexed asset, bytes32 indexed configId, string reason); - - function setUp() public { - // Initialize ModuleKit with Safe account type - super.init(); - - // Create test addresses - mainAccount = makeAddr("mainAccount"); - stranger = makeAddr("stranger"); - - // Deploy tokens - token = new MockERC20("Test Token", "TEST"); - usdt = new MockUSDT(); - - // Deploy AutoCollectExecutor module as singleton - executor = new AutoCollectExecutor(); - - // Create a Safe service account instance - serviceAccount = makeAccountInstance("service-account"); - - // Fund service account with tokens - token.mint(serviceAccount.account, INITIAL_SERVICE_BALANCE); - usdt.mint(serviceAccount.account, INITIAL_SERVICE_BALANCE); - - // Give main account some initial balance - token.mint(mainAccount, INITIAL_MAIN_BALANCE); - usdt.mint(mainAccount, INITIAL_MAIN_BALANCE); - } - - // ============ Module Installation with Safe ============ - - function test_Integration_InstallModule() public { - // Install the module on the service account using ModuleKit - // Note: Event emissions during UserOp execution cannot be tested with expectEmit - // due to ModuleKit's internal use of recordLogs(). Events are tested in unit tests. - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - // Verify module is properly installed and initialized - assertTrue(executor.isInitialized(serviceAccount.account)); - assertTrue(serviceAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); - } - - function test_Integration_InstallWithInitialConfigs() public { - // Prepare installation data with initial configurations - address[] memory assets = new address[](2); - IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](2); - - assets[0] = address(token); - assets[1] = address(usdt); - configs[0] = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - configs[1] = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD * 2, minimumRemaining: 0, enabled: true - }); - - bytes memory installData = abi.encode(assets, configs); - - // Install with initial configs using ModuleKit - // Events during UserOp execution are tested in unit tests - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), installData); - - // Verify configs were created - (IAutoCollectExecutor.CollectConfig[] memory retrievedConfigs,) = - executor.getCollectionConfigs(serviceAccount.account); - assertEq(retrievedConfigs.length, 2); - assertTrue(serviceAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); - } - - // ============ Execution Tests with Safe ============ - - function test_Integration_TriggerCollection_Success() public { - // Install module using ModuleKit - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(serviceAccount.account); - bytes32 configId = executor.configureCollection(address(token), config); - - // Check balances before - uint256 serviceBalanceBefore = token.balanceOf(serviceAccount.account); - uint256 mainBalanceBefore = token.balanceOf(mainAccount); - assertEq(serviceBalanceBefore, INITIAL_SERVICE_BALANCE); - - // Expect the CollectionExecuted event - vm.expectEmit(true, true, true, true); - emit CollectionExecuted(serviceAccount.account, address(token), mainAccount, configId, serviceBalanceBefore); - - // Anyone can trigger the collection (permissionless) - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(token)); - - // Check balances after - assertEq(token.balanceOf(serviceAccount.account), 0); // All collected - assertEq(token.balanceOf(mainAccount), mainBalanceBefore + serviceBalanceBefore); - } - - function test_Integration_TriggerCollection_NonStandardToken() public { - // Test with USDT-style token that has non-standard transfer - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(serviceAccount.account); - bytes32 configId = executor.configureCollection(address(usdt), config); - - // Check initial state - uint256 serviceBalanceBefore = usdt.balanceOf(serviceAccount.account); - uint256 mainBalanceBefore = usdt.balanceOf(mainAccount); - - // Trigger collection with non-standard token - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(usdt)); - - // Verify transfer succeeded despite non-standard return - assertEq(usdt.balanceOf(serviceAccount.account), 0); - assertEq(usdt.balanceOf(mainAccount), mainBalanceBefore + serviceBalanceBefore); - } - - function test_Integration_TriggerAllCollections_BatchExecution() public { - // Setup multiple configs for the same account - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - // Configure collections for different tokens - vm.startPrank(serviceAccount.account); - IAutoCollectExecutor.CollectConfig memory tokenConfig = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - IAutoCollectExecutor.CollectConfig memory usdtConfig = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - executor.configureCollection(address(token), tokenConfig); - executor.configureCollection(address(usdt), usdtConfig); - vm.stopPrank(); - - // Record balances before - uint256 serviceTokenBefore = token.balanceOf(serviceAccount.account); - uint256 serviceUsdtBefore = usdt.balanceOf(serviceAccount.account); - uint256 mainTokenBefore = token.balanceOf(mainAccount); - uint256 mainUsdtBefore = usdt.balanceOf(mainAccount); - - // Trigger all collections for the service account - vm.prank(stranger); - executor.triggerAllCollections(serviceAccount.account); - - // Should have executed 2 collections (verify by checking balances) - assertEq(token.balanceOf(serviceAccount.account), 0); - assertEq(usdt.balanceOf(serviceAccount.account), 0); - assertEq(token.balanceOf(mainAccount), mainTokenBefore + serviceTokenBefore); - assertEq(usdt.balanceOf(mainAccount), mainUsdtBefore + serviceUsdtBefore); - } - - // ============ Daily Limit Tests ============ - - function test_Integration_DailyLimitReset() public { - // Setup config - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(serviceAccount.account); - bytes32 configId = executor.configureCollection(address(token), config); - - // First collection (service has 100 ether, above threshold) - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(token)); - assertEq(token.balanceOf(serviceAccount.account), 0); - - // Add some tokens back - token.mint(serviceAccount.account, 50 ether); - - // Try to collect again same day - should fail (already collected today) - (bool canExecute, string memory reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); - assertFalse(canExecute); - assertEq(reason, "Already collected today"); - - // Move to next day - vm.warp(block.timestamp + 1 days); - - // Now can execute again (new day, service has 50 ether above threshold) - (canExecute, reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); - assertTrue(canExecute); - assertEq(reason, ""); - - // Execute the collection - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(token)); - assertEq(token.balanceOf(serviceAccount.account), 0); - } - - function test_Integration_ThresholdEnforcement() public { - // Setup config with high threshold - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - uint256 highThreshold = INITIAL_SERVICE_BALANCE + 50 ether; - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: highThreshold, minimumRemaining: 0, enabled: true - }); - - vm.prank(serviceAccount.account); - bytes32 configId = executor.configureCollection(address(token), config); - - uint256 currentBalance = token.balanceOf(serviceAccount.account); - - // Should not collect - balance below threshold - vm.expectEmit(true, true, true, true); - emit CollectionSkipped( - serviceAccount.account, - address(token), - configId, - currentBalance, - highThreshold, - 0, // minimumRemaining - currentBalance // would collect (balance - 0) - ); - - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(token)); - - // Balance should not change - assertEq(token.balanceOf(serviceAccount.account), INITIAL_SERVICE_BALANCE); - - // Add more tokens to exceed threshold - token.mint(serviceAccount.account, 60 ether); - - // Now should be able to collect - (bool canExecute, string memory reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); - assertTrue(canExecute); - assertEq(reason, ""); - } - - // ============ Module Uninstall Tests ============ - - function test_Integration_UninstallModule_CleansState() - public - withModuleStorageClearValidation(serviceAccount, address(executor)) - { - // Install and configure using ModuleKit - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - vm.startPrank(serviceAccount.account); - IAutoCollectExecutor.CollectConfig memory tokenConfig = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - IAutoCollectExecutor.CollectConfig memory usdtConfig = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD * 2, minimumRemaining: 0, enabled: true - }); - executor.configureCollection(address(token), tokenConfig); - executor.configureCollection(address(usdt), usdtConfig); - vm.stopPrank(); - - // Verify configs exist - (IAutoCollectExecutor.CollectConfig[] memory configs,) = executor.getCollectionConfigs(serviceAccount.account); - assertEq(configs.length, 2); - - // Uninstall module using ModuleKit - // Events during UserOp execution are tested in unit tests - serviceAccount.uninstallModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - // Verify state is cleaned - assertFalse(executor.isInitialized(serviceAccount.account)); - assertFalse(serviceAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); - (configs,) = executor.getCollectionConfigs(serviceAccount.account); - assertEq(configs.length, 0); - } - - // ============ Reentrancy Protection Tests ============ - - function test_Integration_ReentrancyProtection() public { - // Deploy malicious token - MaliciousCollectToken malToken = new MaliciousCollectToken(); - - // Setup module with malicious token using ModuleKit - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(serviceAccount.account); - executor.configureCollection(address(malToken), config); - - // Set reentrancy target - malicious token will try to call back - malToken.setTarget(executor, serviceAccount.account, address(malToken)); - - // Fund service account with malicious tokens - malToken.mint(serviceAccount.account, INITIAL_SERVICE_BALANCE); - - // Try to trigger - reentrancy guard should prevent issues - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(malToken)); - - // Should have completed successfully despite reentrancy attempt - // Full balance should be collected - assertEq(malToken.balanceOf(serviceAccount.account), 0); - assertEq(malToken.balanceOf(mainAccount), INITIAL_SERVICE_BALANCE); - } - - // ============ Access Control Tests ============ - - function test_Integration_ModuleNotInitialized() public { - // Don't install module - test that uninitialized accounts can't configure - // Stranger cannot configure without module being installed for their account - vm.prank(stranger); - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); - executor.configureCollection(address(token), config); - } - - function test_Integration_CrossAccountConfigurationBlocked() public { - // Install module for serviceAccount only - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - // Service account can configure for itself - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(serviceAccount.account); - bytes32 configId = executor.configureCollection(address(token), config); - - // Stranger cannot modify service account's configs (module not initialized for stranger) - vm.prank(stranger); - vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); - executor.disableCollection(configId); - } - - // ============ Edge Case Tests ============ - - function test_Integration_ZeroBalanceSkipped() public { - // Setup module using ModuleKit - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, - threshold: 0, // Zero threshold - minimumRemaining: 0, - enabled: true - }); - - vm.prank(serviceAccount.account); - bytes32 configId = executor.configureCollection(address(token), config); - - // Drain service account balance - vm.prank(serviceAccount.account); - token.transfer(mainAccount, INITIAL_SERVICE_BALANCE); - - uint256 currentBalance = token.balanceOf(serviceAccount.account); - assertEq(currentBalance, 0); - - // Try to trigger - should skip due to zero balance - vm.expectEmit(true, true, true, true); - emit CollectionSkipped( - serviceAccount.account, - address(token), - configId, - 0, // balance - 0, // threshold - 0, // minimumRemaining - 0 // would collect - ); - - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(token)); - - // Balance should remain zero - assertEq(token.balanceOf(serviceAccount.account), 0); - } - - function test_Integration_DisabledConfigSkipped() public { - // Setup module using ModuleKit - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(serviceAccount.account); - bytes32 configId = executor.configureCollection(address(token), config); - - // Disable the configuration - vm.prank(serviceAccount.account); - executor.disableCollection(configId); - - uint256 serviceBalanceBefore = token.balanceOf(serviceAccount.account); - uint256 mainBalanceBefore = token.balanceOf(mainAccount); - - // Try to trigger - should not execute (disabled) - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(token)); - - // Balances should not change - assertEq(token.balanceOf(serviceAccount.account), serviceBalanceBefore); - assertEq(token.balanceOf(mainAccount), mainBalanceBefore); - } - - function test_Integration_PartialCollectionAfterThresholdChange() public { - // Setup with low threshold initially - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(serviceAccount.account); - bytes32 configId = executor.configureCollection(address(token), config); - - // First collection should work (100 ether > 10 ether threshold) - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(token)); - assertEq(token.balanceOf(serviceAccount.account), 0); - - // Add some tokens back - token.mint(serviceAccount.account, 5 ether); - - // Update threshold to be higher than current balance - vm.prank(serviceAccount.account); - IAutoCollectExecutor.CollectConfig memory newConfig = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: 20 ether, minimumRemaining: 0, enabled: true - }); - executor.configureCollectionById(configId, newConfig); - - // Move to next day - vm.warp(block.timestamp + 1 days); - - // Should not collect due to threshold (5 ether < 20 ether) - (bool canExecute, string memory reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); - assertFalse(canExecute); - assertEq(reason, "Balance below threshold"); - } - - // ============ Multi-Day Collection Tests ============ - - function test_Integration_CollectionAcrossDays() public { - // Setup config with zero threshold (collect any amount) - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - vm.prank(serviceAccount.account); - IAutoCollectExecutor.CollectConfig memory config = - IAutoCollectExecutor.CollectConfig({target: mainAccount, threshold: 0, minimumRemaining: 0, enabled: true}); - executor.configureCollection(address(token), config); - - // Day 1: Collect all balance - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(token)); - assertEq(token.balanceOf(serviceAccount.account), 0); - - // Add some tokens back same day - token.mint(serviceAccount.account, 30 ether); - - // Should not collect again same day - (bool canExecute, string memory reason) = executor.canExecuteCollection(serviceAccount.account, address(token)); - assertFalse(canExecute); - assertEq(reason, "Already collected today"); - - // Move to next day - vm.warp(block.timestamp + 1 days); - - // Day 2: Should be able to collect again - uint256 mainBalanceBeforeDay2 = token.balanceOf(mainAccount); - - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(token)); - - // Should have collected the 30 ether - assertEq(token.balanceOf(serviceAccount.account), 0); - assertEq(token.balanceOf(mainAccount), mainBalanceBeforeDay2 + 30 ether); - } - - // ============ Module Type Tests ============ - - function test_Integration_ModuleType() public { - // Verify module type - should only be true for EXECUTOR type - assertTrue(executor.isModuleType(MODULE_TYPE_EXECUTOR)); - assertFalse(executor.isModuleType(MODULE_TYPE_VALIDATOR)); - assertFalse(executor.isModuleType(MODULE_TYPE_FALLBACK)); - assertFalse(executor.isModuleType(MODULE_TYPE_HOOK)); - } - - // ============ Complex Scenarios ============ - - function test_Integration_MultipleServiceAccounts() public { - // Create second service account - AccountInstance memory serviceAccount2 = makeAccountInstance("service-account-2"); - - // Fund second service account - token.mint(serviceAccount2.account, INITIAL_SERVICE_BALANCE); - - // Install module on both accounts - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - serviceAccount2.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - // Configure collections on both accounts to same main account - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(serviceAccount.account); - executor.configureCollection(address(token), config); - - vm.prank(serviceAccount2.account); - executor.configureCollection(address(token), config); - - uint256 mainBalanceBefore = token.balanceOf(mainAccount); - - // Trigger collections from both accounts - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(token)); - - vm.prank(stranger); - executor.triggerCollection(serviceAccount2.account, address(token)); - - // Both service accounts should be drained, main should receive both balances - assertEq(token.balanceOf(serviceAccount.account), 0); - assertEq(token.balanceOf(serviceAccount2.account), 0); - assertEq(token.balanceOf(mainAccount), mainBalanceBefore + (INITIAL_SERVICE_BALANCE * 2)); - } - - function test_Integration_ConfigurationUpdatesAfterExecution() public { - // Setup and execute first collection - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(serviceAccount.account); - bytes32 configId = executor.configureCollection(address(token), config); - - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(token)); - - // Add tokens back - token.mint(serviceAccount.account, 40 ether); - - // Update configuration to new target - address newMainAccount = makeAddr("newMainAccount"); - vm.prank(serviceAccount.account); - IAutoCollectExecutor.CollectConfig memory newConfig = IAutoCollectExecutor.CollectConfig({ - target: newMainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - executor.configureCollectionById(configId, newConfig); - - // Move to next day and collect again - vm.warp(block.timestamp + 1 days); - - uint256 newMainBalanceBefore = token.balanceOf(newMainAccount); - - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(token)); - - // Should collect to new target - assertEq(token.balanceOf(serviceAccount.account), 0); - assertEq(token.balanceOf(newMainAccount), newMainBalanceBefore + 40 ether); - } - - // ============ Integration Tests for MinimumRemaining ============ - - function test_Integration_PartialCollectionWithMinimumRemaining() public { - // Setup: Service account with 100 tokens, collect with 30 minimumRemaining - // Expected: Collect 70, leave 30 - uint256 minimumRemaining = 30 ether; - uint256 threshold = 50 ether; - - // Install module - serviceAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - // Configure collection with minimumRemaining - vm.prank(serviceAccount.account); - bytes32 configId = executor.configureCollection( - address(token), - IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true - }) - ); - - // Verify initial balances - assertEq(token.balanceOf(serviceAccount.account), INITIAL_SERVICE_BALANCE); - assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE); - - // Trigger collection - vm.prank(stranger); - executor.triggerCollection(serviceAccount.account, address(token)); - - // Verify partial collection - should leave minimumRemaining - uint256 expectedCollected = INITIAL_SERVICE_BALANCE - minimumRemaining; - assertEq(token.balanceOf(serviceAccount.account), minimumRemaining); - assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollected); - - // Verify config state persists - (IAutoCollectExecutor.CollectConfig memory config,) = executor.getCollectionConfigById(configId); - assertEq(config.minimumRemaining, minimumRemaining); - } -} diff --git a/typescript/packages/account-modules/test/AutoCollectExecutor.t.sol b/typescript/packages/account-modules/test/AutoCollectExecutor.t.sol deleted file mode 100644 index 6080146..0000000 --- a/typescript/packages/account-modules/test/AutoCollectExecutor.t.sol +++ /dev/null @@ -1,1192 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {Test, console2} from "forge-std/Test.sol"; -import {AutoCollectExecutor} from "../src/AutoCollectExecutor.sol"; -import {IAutoCollectExecutor} from "../src/IAutoCollectExecutor.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; -import { - MODULE_TYPE_VALIDATOR, - MODULE_TYPE_EXECUTOR, - MODULE_TYPE_FALLBACK, - MODULE_TYPE_HOOK -} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; - -// Import mocks -import {MockERC20} from "./mocks/MockERC20.sol"; -import {MockUSDT} from "./mocks/MockUSDT.sol"; -import {MockSafe} from "./mocks/MockSafe.sol"; -import {MockTokenReturnsFalse} from "./mocks/MockTokenReturnsFalse.sol"; - -// Test contract with proper inheritance for module testing -contract AutoCollectExecutorTest is Test { - // Main contracts - AutoCollectExecutor public executor; - MockERC20 public token; - MockUSDT public usdt; - MockSafe public serviceAccount; - - // Test addresses - address public owner; - address public mainAccount; - address public stranger; - - // Test constants - uint256 constant THRESHOLD = 10 ether; - uint256 constant INITIAL_SERVICE_BALANCE = 100 ether; - uint256 constant INITIAL_MAIN_BALANCE = 1000 ether; - - // Events to test - event ModuleInstalled(address indexed account, uint256 initialConfigs); - event ModuleUninstalled(address indexed account, uint256 removedConfigs); - event CollectionConfigured( - address indexed account, - address indexed asset, - address target, - bytes32 indexed configId, - IAutoCollectExecutor.CollectConfig config - ); - event CollectionExecuted( - address indexed account, address indexed asset, address target, bytes32 indexed configId, uint256 amount - ); - event CollectionSkipped( - address indexed account, - address indexed asset, - bytes32 indexed configId, - uint256 balance, - uint256 threshold, - uint256 minimumRemaining, - uint256 collectAmount - ); - event CollectionFailed(address indexed account, address indexed asset, bytes32 indexed configId, string reason); - event CollectionEnabled(address indexed account, address indexed asset, bytes32 indexed configId); - event CollectionDisabled(address indexed account, address indexed asset, bytes32 indexed configId); - - function setUp() public { - // Set up test accounts - owner = makeAddr("owner"); - mainAccount = makeAddr("mainAccount"); - stranger = makeAddr("stranger"); - - // Deploy test tokens - token = new MockERC20("Test Token", "TEST"); - usdt = new MockUSDT(); - - // Deploy mock service account (Safe) - serviceAccount = new MockSafe(owner); - - // Deploy AutoCollectExecutor as singleton - executor = new AutoCollectExecutor(); - - // Enable executor as module on service account - vm.prank(owner); - serviceAccount.enableModule(address(executor)); - - // Fund service account with tokens - token.mint(address(serviceAccount), INITIAL_SERVICE_BALANCE); - usdt.mint(address(serviceAccount), INITIAL_SERVICE_BALANCE); - - // Give main account some initial balance - token.mint(mainAccount, INITIAL_MAIN_BALANCE); - usdt.mint(mainAccount, INITIAL_MAIN_BALANCE); - } - - // ============ Module Installation Tests ============ - - function test_OnInstall_EmptyData() public { - // Install module without initial configs - vm.expectEmit(true, false, false, true); - emit ModuleInstalled(address(serviceAccount), 0); - - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - assertTrue(executor.isInitialized(address(serviceAccount))); - } - - function test_OnInstall_WithSingleConfig() public { - // Prepare installation data - address[] memory assets = new address[](1); - IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](1); - - assets[0] = address(token); - configs[0] = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - bytes memory installData = abi.encode(assets, configs); - - // Calculate expected config ID - bytes32 configId = executor.generateConfigId(address(serviceAccount), address(token)); - - // Expect events - vm.expectEmit(true, true, true, true); - emit CollectionConfigured(address(serviceAccount), address(token), mainAccount, configId, configs[0]); - - vm.expectEmit(true, true, true, true); - emit CollectionEnabled(address(serviceAccount), address(token), configId); - - vm.expectEmit(true, false, false, true); - emit ModuleInstalled(address(serviceAccount), 1); - - vm.prank(address(serviceAccount)); - executor.onInstall(installData); - - assertTrue(executor.isInitialized(address(serviceAccount))); - - // Verify config was created - (IAutoCollectExecutor.CollectConfig memory config,) = executor.getCollectionConfigById(configId); - assertEq(config.target, mainAccount); - assertEq(config.threshold, THRESHOLD); - assertEq(config.minimumRemaining, 0); - assertTrue(config.enabled); - } - - function test_OnInstall_RevertInvalidAsset() public { - // Try to install with zero address asset - address[] memory assets = new address[](1); - IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](1); - - assets[0] = address(0); // Invalid - configs[0] = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - bytes memory installData = abi.encode(assets, configs); - - vm.prank(address(serviceAccount)); - vm.expectRevert(IAutoCollectExecutor.InvalidAsset.selector); - executor.onInstall(installData); - } - - function test_OnInstall_RevertInvalidTarget() public { - // Try to install with zero address target - address[] memory assets = new address[](1); - IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](1); - - assets[0] = address(token); - configs[0] = IAutoCollectExecutor.CollectConfig({ - target: address(0), threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); // Invalid target - - bytes memory installData = abi.encode(assets, configs); - - vm.prank(address(serviceAccount)); - vm.expectRevert(IAutoCollectExecutor.InvalidTarget.selector); - executor.onInstall(installData); - } - - // ============ Module Uninstallation Tests ============ - - function test_OnUninstall_CleansUpAllState() public { - // First install with configs - address[] memory assets = new address[](2); - IAutoCollectExecutor.CollectConfig[] memory configs = new IAutoCollectExecutor.CollectConfig[](2); - - assets[0] = address(token); - assets[1] = address(usdt); - configs[0] = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - configs[1] = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - executor.onInstall(abi.encode(assets, configs)); - - // Verify installation - assertTrue(executor.isInitialized(address(serviceAccount))); - (IAutoCollectExecutor.CollectConfig[] memory retrievedConfigs,) = - executor.getCollectionConfigs(address(serviceAccount)); - assertEq(retrievedConfigs.length, 2); - - // Now uninstall - vm.expectEmit(true, false, false, true); - emit ModuleUninstalled(address(serviceAccount), 2); - - vm.prank(address(serviceAccount)); - executor.onUninstall(""); - - // Verify all state is cleaned - assertFalse(executor.isInitialized(address(serviceAccount))); - (retrievedConfigs,) = executor.getCollectionConfigs(address(serviceAccount)); - assertEq(retrievedConfigs.length, 0); - } - - // ============ Configuration Management Tests ============ - - function test_ConfigureCollection_NewConfig() public { - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - bytes32 expectedConfigId = executor.generateConfigId(address(serviceAccount), address(token)); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection(address(token), config); - - assertEq(configId, expectedConfigId); - - // Verify config was created - (IAutoCollectExecutor.CollectConfig memory retrievedConfig, IAutoCollectExecutor.CollectState memory state) = - executor.getCollectionConfigById(configId); - assertEq(retrievedConfig.target, mainAccount); - assertEq(retrievedConfig.threshold, THRESHOLD); - assertTrue(retrievedConfig.enabled); - assertEq(state.asset, address(token)); - assertEq(state.lastCollectDate, 0); - } - - function test_ConfigureCollection_RevertInvalidAsset() public { - // Setup: Install module - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - // Try to configure with zero address asset - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.InvalidAsset.selector)); - executor.configureCollection(address(0), config); - } - - function test_ConfigureCollection_RevertInvalidTarget() public { - // Setup: Install module - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - // Try to configure with zero address target - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: address(0), threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.InvalidTarget.selector)); - executor.configureCollection(address(token), config); - } - - function test_ConfigureCollection_ZeroThreshold() public { - // Setup: Install module - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - // Test with zero threshold (should be valid - collect any balance) - IAutoCollectExecutor.CollectConfig memory config = - IAutoCollectExecutor.CollectConfig({target: mainAccount, threshold: 0, minimumRemaining: 0, enabled: true}); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection(address(token), config); - - // Verify config was created successfully - (IAutoCollectExecutor.CollectConfig memory retrievedConfig,) = executor.getCollectionConfigById(configId); - assertEq(retrievedConfig.target, mainAccount); - assertEq(retrievedConfig.threshold, 0); - assertTrue(retrievedConfig.enabled); - } - - function test_ConfigureCollection_RevertNotInitialized() public { - // Don't install module - try to configure - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - vm.expectRevert( - abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, address(serviceAccount)) - ); - executor.configureCollection(address(token), config); - } - - // ============ Enable/Disable Tests ============ - - function test_EnableDisableCollection() public { - // Setup config (enabled by default) - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection(address(token), config); - - // Disable it - vm.expectEmit(true, true, true, true); - emit CollectionDisabled(address(serviceAccount), address(token), configId); - - vm.prank(address(serviceAccount)); - executor.disableCollection(configId); - - // Verify it's disabled - (IAutoCollectExecutor.CollectConfig memory retrievedConfig,) = executor.getCollectionConfigById(configId); - assertFalse(retrievedConfig.enabled); - - // Enable it again - vm.expectEmit(true, true, true, true); - emit CollectionEnabled(address(serviceAccount), address(token), configId); - - vm.prank(address(serviceAccount)); - executor.enableCollection(configId); - - // Verify it's enabled - (retrievedConfig,) = executor.getCollectionConfigById(configId); - assertTrue(retrievedConfig.enabled); - } - - function test_EnableDisable_RevertUnauthorized() public { - // Setup config as service account - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection(address(token), config); - - // Try to disable as stranger (should fail - module not initialized) - vm.prank(stranger); - vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); - executor.disableCollection(configId); - - // Try to enable as stranger (should fail - module not initialized) - vm.prank(stranger); - vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); - executor.enableCollection(configId); - } - - // ============ Configuration By ID Tests ============ - - function test_ConfigureCollectionById_Success() public { - // Setup: Install module and create initial config - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection(address(token), config); - - // Update config by ID - address newTarget = makeAddr("newTarget"); - uint256 newThreshold = THRESHOLD * 2; - IAutoCollectExecutor.CollectConfig memory newConfig = IAutoCollectExecutor.CollectConfig({ - target: newTarget, threshold: newThreshold, minimumRemaining: 0, enabled: true - }); - - vm.expectEmit(true, true, true, true); - emit CollectionConfigured(address(serviceAccount), address(token), newTarget, configId, newConfig); - - vm.prank(address(serviceAccount)); - executor.configureCollectionById(configId, newConfig); - - // Verify config was updated - (IAutoCollectExecutor.CollectConfig memory retrievedConfig,) = executor.getCollectionConfigById(configId); - assertEq(retrievedConfig.target, newTarget); - assertEq(retrievedConfig.threshold, newThreshold); - assertTrue(retrievedConfig.enabled); - } - - function test_ConfigureCollectionById_RevertConfigNotFound() public { - // Install module but use non-existent configId - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - bytes32 nonExistentConfigId = keccak256("nonexistent"); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ConfigNotFound.selector)); - executor.configureCollectionById(nonExistentConfigId, config); - } - - function test_ConfigureCollectionById_RevertUnauthorized() public { - // Setup: Service account creates a config - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection(address(token), config); - - // Stranger tries to update service account's config - IAutoCollectExecutor.CollectConfig memory newConfig = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD * 2, minimumRemaining: 0, enabled: true - }); - - vm.prank(stranger); - vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, stranger)); - executor.configureCollectionById(configId, newConfig); - } - - // ============ Execution Tests ============ - - function test_TriggerCollection_Success() public { - // Setup: Install module and configure collection - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection(address(token), config); - - // Service account has balance above threshold - uint256 serviceBalanceBefore = token.balanceOf(address(serviceAccount)); - uint256 mainBalanceBefore = token.balanceOf(mainAccount); - assertEq(serviceBalanceBefore, INITIAL_SERVICE_BALANCE); - - // Expect the CollectionExecuted event - vm.expectEmit(true, true, true, true); - emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, serviceBalanceBefore); - - // Trigger the collection - executor.triggerCollection(address(serviceAccount), address(token)); - - // Verify the collection was executed (full balance transferred) - assertEq(token.balanceOf(address(serviceAccount)), 0); - assertEq(token.balanceOf(mainAccount), mainBalanceBefore + serviceBalanceBefore); - } - - function test_TriggerCollection_SkippedBelowThreshold() public { - // Setup with high threshold - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - uint256 highThreshold = INITIAL_SERVICE_BALANCE + 1 ether; - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: highThreshold, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection(address(token), config); - - uint256 currentBalance = token.balanceOf(address(serviceAccount)); - - // Expect CollectionSkipped event - vm.expectEmit(true, true, true, true); - emit CollectionSkipped( - address(serviceAccount), - address(token), - configId, - currentBalance, - highThreshold, - 0, // minimumRemaining - currentBalance // would collect - ); - - // Trigger collection - should be skipped - executor.triggerCollection(address(serviceAccount), address(token)); - - // Balance should not change - assertEq(token.balanceOf(address(serviceAccount)), INITIAL_SERVICE_BALANCE); - } - - function test_TriggerAllCollections_MultipleAssets() public { - // Setup multiple configs for the same account - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - // Configure collections for both tokens - IAutoCollectExecutor.CollectConfig memory tokenConfig = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - IAutoCollectExecutor.CollectConfig memory usdtConfig = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.startPrank(address(serviceAccount)); - executor.configureCollection(address(token), tokenConfig); - executor.configureCollection(address(usdt), usdtConfig); - vm.stopPrank(); - - // Record balances before - uint256 serviceTokenBefore = token.balanceOf(address(serviceAccount)); - uint256 serviceUsdtBefore = usdt.balanceOf(address(serviceAccount)); - uint256 mainTokenBefore = token.balanceOf(mainAccount); - uint256 mainUsdtBefore = usdt.balanceOf(mainAccount); - - // Trigger all collections - vm.prank(stranger); - executor.triggerAllCollections(address(serviceAccount)); - - // Should have executed 2 collections - assertEq(token.balanceOf(address(serviceAccount)), 0); - assertEq(usdt.balanceOf(address(serviceAccount)), 0); - assertEq(token.balanceOf(mainAccount), mainTokenBefore + serviceTokenBefore); - assertEq(usdt.balanceOf(mainAccount), mainUsdtBefore + serviceUsdtBefore); - } - - // ============ Daily Limit Tests ============ - - function test_DailyLimitReset() public { - // Setup config - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection(address(token), config); - - // First collection should work - (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); - assertTrue(canExecute); - assertEq(reason, ""); - - // Actually execute the collection - executor.triggerCollection(address(serviceAccount), address(token)); - - // Add some tokens back to service account - token.mint(address(serviceAccount), 50 ether); - - // Should not be able to collect again same day - (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); - assertFalse(canExecute); - assertEq(reason, "Already collected today"); - - // Move to next day - vm.warp(block.timestamp + 1 days); - - // Now should be able to collect again - (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); - assertTrue(canExecute); - assertEq(reason, ""); - } - - // ============ View Function Tests ============ - - function test_CanExecuteCollection_Conditions() public { - // Setup - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - executor.configureCollection(address(token), config); - - // Should be able to execute (service balance is above threshold) - (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); - assertTrue(canExecute); - assertEq(reason, ""); - - // Test with disabled config - bytes32 configId = executor.generateConfigId(address(serviceAccount), address(token)); - vm.prank(address(serviceAccount)); - executor.disableCollection(configId); - - (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); - assertFalse(canExecute); - assertEq(reason, "Collection disabled"); - } - - function test_GetCollectionConfig_Success() public { - // Setup: Install module and create config - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection(address(token), config); - - // Test getCollectionConfig function - ( - IAutoCollectExecutor.CollectConfig memory retrievedConfig, - IAutoCollectExecutor.CollectState memory retrievedState - ) = executor.getCollectionConfig(address(serviceAccount), address(token)); - - assertEq(retrievedConfig.target, mainAccount); - assertEq(retrievedConfig.threshold, THRESHOLD); - assertTrue(retrievedConfig.enabled); - assertEq(retrievedState.asset, address(token)); - assertEq(retrievedState.lastCollectDate, 0); - } - - function test_GetCollectionConfig_NonExistentConfig() public { - // Test getCollectionConfig with non-existent config - (IAutoCollectExecutor.CollectConfig memory config, IAutoCollectExecutor.CollectState memory state) = - executor.getCollectionConfig(address(serviceAccount), address(token)); - - // Should return zero values for non-existent config - assertEq(config.target, address(0)); - assertEq(config.threshold, 0); - assertEq(config.minimumRemaining, 0); - assertFalse(config.enabled); - assertEq(state.asset, address(0)); - assertEq(state.lastCollectDate, 0); - } - - function test_CanExecuteCollection_ConfigNotFound() public { - bytes32 configId = executor.generateConfigId(address(serviceAccount), address(token)); - - (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); - - assertFalse(canExecute); - assertEq(reason, "Config not found"); - } - - function test_GetCollectionConfigs() public { - // Install module and create multiple configs - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - IAutoCollectExecutor.CollectConfig memory tokenConfig = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - IAutoCollectExecutor.CollectConfig memory usdtConfig = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD * 2, minimumRemaining: 0, enabled: true - }); - - vm.startPrank(address(serviceAccount)); - executor.configureCollection(address(token), tokenConfig); - executor.configureCollection(address(usdt), usdtConfig); - vm.stopPrank(); - - // Get all configs - (IAutoCollectExecutor.CollectConfig[] memory configs, IAutoCollectExecutor.CollectState[] memory states) = - executor.getCollectionConfigs(address(serviceAccount)); - - assertEq(configs.length, 2); - assertEq(states.length, 2); - - // Verify configs (order might vary due to EnumerableSet) - bool foundToken = false; - bool foundUsdt = false; - - for (uint256 i = 0; i < configs.length; i++) { - if (states[i].asset == address(token)) { - foundToken = true; - assertEq(configs[i].target, mainAccount); - assertEq(configs[i].threshold, THRESHOLD); - assertTrue(configs[i].enabled); - } else if (states[i].asset == address(usdt)) { - foundUsdt = true; - assertEq(configs[i].target, mainAccount); - assertEq(configs[i].threshold, THRESHOLD * 2); - assertTrue(configs[i].enabled); - } - } - - assertTrue(foundToken); - assertTrue(foundUsdt); - } - - // ============ Date Boundary Tests ============ - - function test_YearTransition() public { - // Setup config - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - executor.configureCollection(address(token), config); - - // Set time to Dec 31, 2023 - vm.warp(1704067199); // Dec 31, 2023 23:59:59 UTC - - // Execute collection on last day of year - executor.triggerCollection(address(serviceAccount), address(token)); - - // Add tokens back - token.mint(address(serviceAccount), 50 ether); - - // Should not execute again same day - (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); - assertFalse(canExecute); - assertEq(reason, "Already collected today"); - - // Move to Jan 1, 2024 (next year) - vm.warp(1704067200); // Jan 1, 2024 00:00:00 UTC - - // Should be able to execute (new day and new year) - (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); - assertTrue(canExecute); - assertEq(reason, ""); - } - - function test_LeapYearFebruary() public { - // Setup config - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - executor.configureCollection(address(token), config); - - // Set time to Feb 28, 2024 (leap year) - vm.warp(1709078400); // Feb 28, 2024 00:00:00 UTC - - // Execute collection on Feb 28 - executor.triggerCollection(address(serviceAccount), address(token)); - - // Add tokens back - token.mint(address(serviceAccount), 50 ether); - - // Move to Feb 29 (leap day) - vm.warp(1709164800); // Feb 29, 2024 00:00:00 UTC - - // Should be able to execute on leap day - (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); - assertTrue(canExecute); - assertEq(reason, ""); - - executor.triggerCollection(address(serviceAccount), address(token)); - - // Add tokens back again - token.mint(address(serviceAccount), 50 ether); - - // Move to March 1 - vm.warp(1709251200); // March 1, 2024 00:00:00 UTC - - // Should be able to execute on March 1 - (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); - assertTrue(canExecute); - assertEq(reason, ""); - } - - // ============ Fuzz Tests ============ - - function testFuzz_DailyExecutionLimit(uint32 startTimestamp, uint32 timeDelta) public { - // Test that daily execution limit is enforced across various start times and deltas - // Bound start timestamp to reasonable range (year 2020-2030) - uint256 startTime = bound(uint256(startTimestamp), 1577836800, 1893456000); // 2020-2030 - vm.warp(startTime); - - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - executor.configureCollection(address(token), config); - - // Execute first collection - executor.triggerCollection(address(serviceAccount), address(token)); - - // Add tokens back - token.mint(address(serviceAccount), 50 ether); - - // Calculate seconds remaining in current calendar day - (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); - uint256 endOfDay = BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day) + 86400 - 1; - uint256 secondsLeftInDay = endOfDay - block.timestamp; - - // Bound time delta to stay within current calendar day - uint256 deltaSeconds = bound(uint256(timeDelta), 0, secondsLeftInDay); - vm.warp(block.timestamp + deltaSeconds); - - // Should not be able to execute again same calendar day - (bool canExecute, string memory reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); - assertFalse(canExecute); - assertEq(reason, "Already collected today"); - - // Move to next calendar day - vm.warp(block.timestamp + (secondsLeftInDay - deltaSeconds) + 1); - - // Now should be able to execute - (canExecute, reason) = executor.canExecuteCollection(address(serviceAccount), address(token)); - assertTrue(canExecute); - assertEq(reason, ""); - } - - function testFuzz_ConfigurationThresholds(uint256 threshold) public { - // Bound to reasonable values - threshold = bound(threshold, 0, type(uint128).max); - - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - // Should succeed with any threshold - IAutoCollectExecutor.CollectConfig memory config = IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: threshold, minimumRemaining: 0, enabled: true - }); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection(address(token), config); - - // Verify config was stored correctly - (IAutoCollectExecutor.CollectConfig memory retrieved,) = executor.getCollectionConfigById(configId); - assertEq(retrieved.target, mainAccount); - assertEq(retrieved.threshold, threshold); - assertTrue(retrieved.enabled); - } - - // ============ Module Type Tests ============ - - function test_IsModuleType() public { - assertTrue(executor.isModuleType(MODULE_TYPE_EXECUTOR)); - assertFalse(executor.isModuleType(MODULE_TYPE_VALIDATOR)); - assertFalse(executor.isModuleType(MODULE_TYPE_FALLBACK)); - assertFalse(executor.isModuleType(MODULE_TYPE_HOOK)); - } - - // ============ Error Cases Tests ============ - - function test_TriggerCollection_RevertModuleNotInitialized() public { - // Don't install module - try to trigger - vm.expectRevert( - abi.encodeWithSelector(IAutoCollectExecutor.ModuleNotInitialized.selector, address(serviceAccount)) - ); - executor.triggerCollection(address(serviceAccount), address(token)); - } - - function test_TriggerCollection_RevertConfigNotFound() public { - // Install module but don't create config - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - vm.expectRevert(abi.encodeWithSelector(IAutoCollectExecutor.ConfigNotFound.selector)); - executor.triggerCollection(address(serviceAccount), address(token)); - } - - // ============ MinimumRemaining Tests ============ - - function test_CollectWithMinimumRemaining() public { - // Setup: 100 USDC balance, threshold 50, minimumRemaining 20 - // Expected: Collect 80, leave 20 - uint256 minimumRemaining = 20 ether; - uint256 threshold = 50 ether; - - // Install and configure - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection( - address(token), - IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true - }) - ); - - // Verify initial balance - assertEq(token.balanceOf(address(serviceAccount)), INITIAL_SERVICE_BALANCE); - assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE); - - // Trigger collection - uint256 expectedCollectAmount = INITIAL_SERVICE_BALANCE - minimumRemaining; - - vm.expectEmit(true, true, true, true); - emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, expectedCollectAmount); - - executor.triggerCollection(address(serviceAccount), address(token)); - - // Verify balances - assertEq(token.balanceOf(address(serviceAccount)), minimumRemaining); - assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollectAmount); - } - - function test_CollectWithZeroThresholdAndMinimumRemaining() public { - // Setup: 100 USDC balance, threshold 0, minimumRemaining 30 - // Expected: Collect 70, leave 30 - uint256 minimumRemaining = 30 ether; - uint256 threshold = 0; - - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection( - address(token), - IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true - }) - ); - - // Trigger collection - uint256 expectedCollectAmount = INITIAL_SERVICE_BALANCE - minimumRemaining; - - vm.expectEmit(true, true, true, true); - emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, expectedCollectAmount); - - executor.triggerCollection(address(serviceAccount), address(token)); - - // Verify balances - assertEq(token.balanceOf(address(serviceAccount)), minimumRemaining); - assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollectAmount); - } - - function test_SkipCollectionWhenMinimumRemainingEqualsBalance() public { - // Setup: 50 USDC balance, threshold 20, minimumRemaining 50 - // Expected: Skip (collect amount = 0) - uint256 balance = 50 ether; - uint256 minimumRemaining = 50 ether; - uint256 threshold = 20 ether; - - // Set service account balance to exactly minimumRemaining - token.burn(address(serviceAccount), INITIAL_SERVICE_BALANCE - balance); - - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection( - address(token), - IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true - }) - ); - - // Expect CollectionSkipped event - vm.expectEmit(true, true, true, true); - emit CollectionSkipped( - address(serviceAccount), - address(token), - configId, - balance, // current balance - threshold, - minimumRemaining, - 0 // would collect amount - ); - - executor.triggerCollection(address(serviceAccount), address(token)); - - // Verify balances unchanged - assertEq(token.balanceOf(address(serviceAccount)), balance); - assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE); - } - - function test_SkipCollectionWhenMinimumRemainingExceedsBalance() public { - // Setup: 40 USDC balance, threshold 20, minimumRemaining 50 - // Expected: Skip (can't leave 50 when we only have 40) - uint256 balance = 40 ether; - uint256 minimumRemaining = 50 ether; - uint256 threshold = 20 ether; - - // Set service account balance - token.burn(address(serviceAccount), INITIAL_SERVICE_BALANCE - balance); - - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection( - address(token), - IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true - }) - ); - - // Expect CollectionSkipped event - vm.expectEmit(true, true, true, true); - emit CollectionSkipped( - address(serviceAccount), - address(token), - configId, - balance, // current balance - threshold, - minimumRemaining, - 0 // would collect amount (balance < minimumRemaining, so 0) - ); - - executor.triggerCollection(address(serviceAccount), address(token)); - - // Verify balances unchanged - assertEq(token.balanceOf(address(serviceAccount)), balance); - assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE); - } - - function test_MinimumRemainingGreaterThanThreshold() public { - // Setup: 100 USDC balance, threshold 10, minimumRemaining 80 - // Expected: Collect 20, leave 80 (triggers at 10 but keeps 80) - uint256 minimumRemaining = 80 ether; - uint256 threshold = 10 ether; - - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection( - address(token), - IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true - }) - ); - - // Trigger collection - uint256 expectedCollectAmount = INITIAL_SERVICE_BALANCE - minimumRemaining; - - vm.expectEmit(true, true, true, true); - emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, expectedCollectAmount); - - executor.triggerCollection(address(serviceAccount), address(token)); - - // Verify balances - assertEq(token.balanceOf(address(serviceAccount)), minimumRemaining); - assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollectAmount); - } - - function test_MinimumRemainingEqualsThreshold() public { - // Setup: 100 USDC balance, threshold 50, minimumRemaining 50 - // Expected: Collect 50, leave 50 - uint256 minimumRemaining = 50 ether; - uint256 threshold = 50 ether; - - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection( - address(token), - IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true - }) - ); - - // Trigger collection - uint256 expectedCollectAmount = INITIAL_SERVICE_BALANCE - minimumRemaining; - - vm.expectEmit(true, true, true, true); - emit CollectionExecuted(address(serviceAccount), address(token), mainAccount, configId, expectedCollectAmount); - - executor.triggerCollection(address(serviceAccount), address(token)); - - // Verify balances - assertEq(token.balanceOf(address(serviceAccount)), minimumRemaining); - assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + expectedCollectAmount); - } - - function test_CollectionSkippedEventIncludesMinimumRemaining() public { - // Verify new event parameters are emitted correctly when skipping - uint256 threshold = 200 ether; // Higher than balance - uint256 minimumRemaining = 10 ether; - - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection( - address(token), - IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: threshold, minimumRemaining: minimumRemaining, enabled: true - }) - ); - - uint256 currentBalance = INITIAL_SERVICE_BALANCE; - uint256 wouldCollect = currentBalance - minimumRemaining; - - // Expect CollectionSkipped with all parameters - vm.expectEmit(true, true, true, true); - emit CollectionSkipped( - address(serviceAccount), address(token), configId, currentBalance, threshold, minimumRemaining, wouldCollect - ); - - executor.triggerCollection(address(serviceAccount), address(token)); - } - - // ============ Batch Failure Tests ============ - - function test_TriggerAllCollections_PartialFailure() public { - // Test that if one collection fails, others still succeed - // This demonstrates resilience of batch operations with try-catch - - // Import the bad token mock - MockTokenReturnsFalse badToken = new MockTokenReturnsFalse(); - badToken.mint(address(serviceAccount), INITIAL_SERVICE_BALANCE); - - // Install module - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - // Configure 3 collections: good token, bad token, good USDT - vm.prank(address(serviceAccount)); - bytes32 goodConfigId1 = executor.configureCollection( - address(token), - IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }) - ); - - vm.prank(address(serviceAccount)); - bytes32 badConfigId = executor.configureCollection( - address(badToken), - IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }) - ); - - vm.prank(address(serviceAccount)); - bytes32 goodConfigId2 = executor.configureCollection( - address(usdt), - IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }) - ); - - // Trigger all collections - should not revert despite badToken failure - executor.triggerAllCollections(address(serviceAccount)); - - // Verify: good tokens collected, bad token remained - assertEq(token.balanceOf(address(serviceAccount)), 0); - assertEq(token.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + INITIAL_SERVICE_BALANCE); - - assertEq(badToken.balanceOf(address(serviceAccount)), INITIAL_SERVICE_BALANCE); // Failed - balance unchanged - assertEq(badToken.balanceOf(mainAccount), 0); - - assertEq(usdt.balanceOf(address(serviceAccount)), 0); - assertEq(usdt.balanceOf(mainAccount), INITIAL_MAIN_BALANCE + INITIAL_SERVICE_BALANCE); - } - - function test_CollectionFailed_EmitsCorrectReason() public { - // Test that CollectionFailed event contains meaningful error message - MockTokenReturnsFalse badToken = new MockTokenReturnsFalse(); - badToken.mint(address(serviceAccount), INITIAL_SERVICE_BALANCE); - - vm.prank(address(serviceAccount)); - executor.onInstall(""); - - vm.prank(address(serviceAccount)); - bytes32 configId = executor.configureCollection( - address(badToken), - IAutoCollectExecutor.CollectConfig({ - target: mainAccount, threshold: THRESHOLD, minimumRemaining: 0, enabled: true - }) - ); - - // Should emit CollectionFailed with generic reason (custom errors fall to catch(bytes)) - vm.expectEmit(true, true, true, true); - emit CollectionFailed(address(serviceAccount), address(badToken), configId, "Transfer failed"); - - executor.triggerCollection(address(serviceAccount), address(badToken)); - - // Verify state was NOT updated (no collection happened) - (, IAutoCollectExecutor.CollectState memory state) = executor.getCollectionConfigById(configId); - assertEq(state.lastCollectDate, 0); // Should remain 0 since transfer failed - } -} diff --git a/typescript/packages/account-modules/test/AutoTopUpExecutor.integration.t.sol b/typescript/packages/account-modules/test/AutoTopUpExecutor.integration.t.sol deleted file mode 100644 index 77e78a5..0000000 --- a/typescript/packages/account-modules/test/AutoTopUpExecutor.integration.t.sol +++ /dev/null @@ -1,441 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {Test, Vm, console2} from "forge-std/Test.sol"; -import { - RhinestoneModuleKit, - AccountType, - AccountInstance, - UserOpData -} from "modulekit/src/test/RhinestoneModuleKit.sol"; -import {ModuleKitHelpers} from "modulekit/src/test/ModuleKitHelpers.sol"; -import {AutoTopUpExecutor} from "../src/AutoTopUpExecutor.sol"; -import {IAutoTopUpExecutor} from "../src/IAutoTopUpExecutor.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { - IModule, - MODULE_TYPE_VALIDATOR, - MODULE_TYPE_EXECUTOR, - MODULE_TYPE_FALLBACK, - MODULE_TYPE_HOOK -} from "modulekit/src/accounts/common/interfaces/IERC7579Module.sol"; -import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; - -// Import mocks -import {MockERC20} from "./mocks/MockERC20.sol"; -import {MockUSDT} from "./mocks/MockUSDT.sol"; -import {MaliciousToken} from "./mocks/MaliciousToken.sol"; - -// Integration tests using RhinestoneModuleKit for proper Safe interaction -contract AutoTopUpExecutorIntegrationTest is Test, RhinestoneModuleKit { - using SafeERC20 for IERC20; - using ModuleKitHelpers for AccountInstance; - - // Main contracts - AutoTopUpExecutor public executor; - MockERC20 public token; - MockUSDT public usdt; - - // Test accounts - AccountInstance public safeAccount; - address public agent1; - address public agent2; - address public stranger; - - // Test constants - uint256 constant DAILY_LIMIT = 100 ether; - uint256 constant MONTHLY_LIMIT = 1000 ether; - uint256 constant INITIAL_SAFE_BALANCE = 10000 ether; - uint256 constant INITIAL_AGENT_BALANCE = 50 ether; - - // Events from the module - event ModuleInstalled(address indexed account, uint256 initialConfigs); - event ModuleUninstalled(address indexed account, uint256 removedConfigs); - event TopUpConfigured( - address indexed account, - address indexed agent, - address asset, - bytes32 indexed configId, - IAutoTopUpExecutor.TopUpConfig config - ); - event TopUpExecuted( - address indexed account, address indexed agent, address asset, bytes32 indexed configId, uint256 amount - ); - event TopUpFailed( - address indexed account, address indexed agent, address asset, bytes32 indexed configId, string reason - ); - - function setUp() public { - // Initialize ModuleKit with Safe account type - super.init(); - - // Create test addresses - agent1 = makeAddr("agent1"); - agent2 = makeAddr("agent2"); - stranger = makeAddr("stranger"); - - // Deploy tokens - token = new MockERC20("Test Token", "TEST"); - usdt = new MockUSDT(); - - // Deploy AutoTopUpExecutor module as singleton - executor = new AutoTopUpExecutor(); - - // Create a Safe account instance - safeAccount = makeAccountInstance("safe-account"); - - // Fund Safe account with tokens - token.mint(safeAccount.account, INITIAL_SAFE_BALANCE); - usdt.mint(safeAccount.account, INITIAL_SAFE_BALANCE); - - // Give agents some initial balance (below daily limit) - token.mint(agent1, INITIAL_AGENT_BALANCE); - token.mint(agent2, INITIAL_AGENT_BALANCE); - usdt.mint(agent1, INITIAL_AGENT_BALANCE); - usdt.mint(agent2, INITIAL_AGENT_BALANCE); - } - - // ============ Module Installation with Safe ============ - - function test_Integration_InstallModule() public { - // Install the module on the Safe account using ModuleKit - // Note: Event emissions during UserOp execution cannot be tested with expectEmit - // due to ModuleKit's internal use of recordLogs(). Events are tested in unit tests. - safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - // Verify module is properly installed and initialized - assertTrue(executor.isInitialized(safeAccount.account)); - assertTrue(safeAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); - } - - function test_Integration_InstallWithInitialConfigs() public { - // Prepare installation data with initial configurations - address[] memory agents = new address[](2); - address[] memory assets = new address[](2); - IAutoTopUpExecutor.TopUpConfig[] memory configs = new IAutoTopUpExecutor.TopUpConfig[](2); - - agents[0] = agent1; - agents[1] = agent2; - assets[0] = address(token); - assets[1] = address(token); - - configs[0] = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - configs[1] = IAutoTopUpExecutor.TopUpConfig({ - dailyLimit: DAILY_LIMIT / 2, monthlyLimit: MONTHLY_LIMIT / 2, enabled: false - }); - - bytes memory installData = abi.encode(agents, assets, configs); - - // Install with initial configs using ModuleKit - // Events during UserOp execution are tested in unit tests - safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), installData); - - // Verify configs were created - (IAutoTopUpExecutor.TopUpConfig[] memory retrievedConfigs,) = executor.getTopUpConfigs(safeAccount.account); - assertEq(retrievedConfigs.length, 2); - assertTrue(safeAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); - } - - // ============ Execution Tests with Safe ============ - - function test_Integration_TriggerTopUp_Success() public { - // Install module using ModuleKit - safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(safeAccount.account); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Check agent balance before - uint256 agentBalanceBefore = token.balanceOf(agent1); - assertEq(agentBalanceBefore, INITIAL_AGENT_BALANCE); - - // Calculate expected top-up amount - uint256 expectedTopUp = DAILY_LIMIT - agentBalanceBefore; - - // Expect the TopUpExecuted event - vm.expectEmit(true, true, true, true); - emit TopUpExecuted(safeAccount.account, agent1, address(token), configId, expectedTopUp); - - // Anyone can trigger the top-up (permissionless) - vm.prank(stranger); - executor.triggerTopUp(safeAccount.account, configId); - - // Check agent balance after - uint256 agentBalanceAfter = token.balanceOf(agent1); - assertEq(agentBalanceAfter, DAILY_LIMIT); - - // Check Safe balance decreased - assertEq(token.balanceOf(safeAccount.account), INITIAL_SAFE_BALANCE - expectedTopUp); - } - - function test_Integration_TriggerTopUp_NonStandardToken() public { - // Test with USDT-style token that has non-standard transfer - safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(safeAccount.account); - bytes32 configId = executor.configureTopUp(agent1, address(usdt), config); - - // Check initial state - uint256 agentBalanceBefore = usdt.balanceOf(agent1); - uint256 expectedTopUp = DAILY_LIMIT - agentBalanceBefore; - - // Trigger top-up with non-standard token - vm.prank(stranger); - executor.triggerTopUp(safeAccount.account, configId); - - // Verify transfer succeeded despite non-standard return - assertEq(usdt.balanceOf(agent1), DAILY_LIMIT); - assertEq(usdt.balanceOf(safeAccount.account), INITIAL_SAFE_BALANCE - expectedTopUp); - } - - function test_Integration_TriggerTopUps_BatchExecution() public { - // Setup multiple configs for the same account - safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - // Configure multiple agents with different tokens - vm.startPrank(safeAccount.account); - executor.configureTopUp(agent1, address(token), config); - executor.configureTopUp(agent2, address(token), config); - executor.configureTopUp(agent1, address(usdt), config); - vm.stopPrank(); - - // Record balances before - uint256 agent1TokenBefore = token.balanceOf(agent1); - uint256 agent2TokenBefore = token.balanceOf(agent2); - uint256 agent1UsdtBefore = usdt.balanceOf(agent1); - - // Trigger all top-ups for the Safe account - vm.prank(stranger); - executor.triggerTopUps(safeAccount.account); - - // Should have executed 3 top-ups (verify by checking balances) - - // Verify all balances were topped up - assertEq(token.balanceOf(agent1), DAILY_LIMIT); - assertEq(token.balanceOf(agent2), DAILY_LIMIT); - assertEq(usdt.balanceOf(agent1), DAILY_LIMIT); - } - - // ============ Daily/Monthly Limit Tests ============ - - function test_Integration_DailyLimitReset() public { - // Setup config with low daily limit - safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: 60 ether, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(safeAccount.account); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // First top-up (agent1 has 50 ether, needs 10 ether to reach 60) - vm.prank(stranger); - executor.triggerTopUp(safeAccount.account, configId); - assertEq(token.balanceOf(agent1), 60 ether); - - // Spend some tokens - vm.prank(agent1); - token.transfer(agent2, 20 ether); - assertEq(token.balanceOf(agent1), 40 ether); - - // Try to top-up again same day - should fail (already topped up today) - (bool canExecute, string memory reason) = executor.canExecuteTopUp(safeAccount.account, configId); - assertFalse(canExecute); - assertEq(reason, "Already topped up today"); - - // Move to next day - vm.warp(block.timestamp + 1 days); - - // Now can execute again (new day, agent balance is 40, needs 20 to reach 60) - (canExecute, reason) = executor.canExecuteTopUp(safeAccount.account, configId); - assertTrue(canExecute); - assertEq(reason, ""); - - // Execute the top-up - vm.prank(stranger); - executor.triggerTopUp(safeAccount.account, configId); - assertEq(token.balanceOf(agent1), 60 ether); - } - - function test_Integration_MonthlyLimitEnforcement() public { - // Setup config with low monthly limit - safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoTopUpExecutor.TopUpConfig memory config = IAutoTopUpExecutor.TopUpConfig({ - dailyLimit: 100 ether, - monthlyLimit: 120 ether, // Just above one top-up (50 ether needed initially) - enabled: true - }); - - vm.prank(safeAccount.account); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // First top-up should work (agent has 50 ether, needs 50 ether to reach 100) - vm.prank(stranger); - executor.triggerTopUp(safeAccount.account, configId); - assertEq(token.balanceOf(agent1), 100 ether); - - // Spend most tokens - vm.prank(agent1); - token.transfer(agent2, 90 ether); - assertEq(token.balanceOf(agent1), 10 ether); - - // Move to next day to allow another top-up - vm.warp(block.timestamp + 1 days); - - // Second top-up should be partial (would need 90 ether, but only 70 left in monthly limit) - // Monthly spent: 50 ether, limit: 120 ether, remaining: 70 ether - vm.prank(stranger); - executor.triggerTopUp(safeAccount.account, configId); - - // Balance should be: 10 (current) + 70 (remaining monthly limit) = 80 ether - assertEq(token.balanceOf(agent1), 80 ether); - - // Move to next day and try again - should fail (monthly limit reached) - vm.warp(block.timestamp + 1 days); - vm.prank(agent1); - token.transfer(agent2, 10 ether); // Spend some to be below daily limit - - (bool canExecute, string memory reason) = executor.canExecuteTopUp(safeAccount.account, configId); - assertFalse(canExecute); - assertEq(reason, "Monthly limit reached"); - } - - // ============ Module Uninstall Tests ============ - - function test_Integration_UninstallModule_CleansState() - public - withModuleStorageClearValidation(safeAccount, address(executor)) - { - // Install and configure using ModuleKit - safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.startPrank(safeAccount.account); - executor.configureTopUp(agent1, address(token), config); - executor.configureTopUp(agent2, address(usdt), config); - vm.stopPrank(); - - // Verify configs exist - (IAutoTopUpExecutor.TopUpConfig[] memory configs,) = executor.getTopUpConfigs(safeAccount.account); - assertEq(configs.length, 2); - - // Uninstall module using ModuleKit - // Events during UserOp execution are tested in unit tests - safeAccount.uninstallModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - // Verify state is cleaned - assertFalse(executor.isInitialized(safeAccount.account)); - assertFalse(safeAccount.isModuleInstalled(MODULE_TYPE_EXECUTOR, address(executor))); - (configs,) = executor.getTopUpConfigs(safeAccount.account); - assertEq(configs.length, 0); - } - - // ============ Reentrancy Protection Tests ============ - - function test_Integration_ReentrancyProtection() public { - // Deploy malicious token - MaliciousToken malToken = new MaliciousToken(); - - // Setup module with malicious token using ModuleKit - safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(safeAccount.account); - bytes32 configId = executor.configureTopUp(agent1, address(malToken), config); - - // Set reentrancy target - malToken.setTarget(executor, configId); - - // Fund Safe with malicious tokens - malToken.mint(safeAccount.account, INITIAL_SAFE_BALANCE); - - // Try to trigger - reentrancy guard should prevent issues - vm.prank(stranger); - executor.triggerTopUp(safeAccount.account, configId); - - // Should have completed successfully despite reentrancy attempt - assertEq(malToken.balanceOf(agent1), DAILY_LIMIT); - } - - // ============ Access Control Tests ============ - - function test_Integration_ModuleNotInitialized() public { - // Don't install module - test that uninitialised accounts can't configure - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - // Stranger cannot configure without module being installed for their account - vm.prank(stranger); - vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); - executor.configureTopUp(agent1, address(token), config); - } - - function test_Integration_CrossAccountConfigurationBlocked() public { - // Install module for safeAccount only - safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - // Safe account can configure for itself - vm.prank(safeAccount.account); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Stranger cannot modify safe account's configs (module not initialized for stranger) - vm.prank(stranger); - vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); - executor.disableTopUp(configId); - } - - // ============ Edge Case Tests ============ - - function test_Integration_InsufficientSafeBalance() public { - // Setup module using ModuleKit - safeAccount.installModule(MODULE_TYPE_EXECUTOR, address(executor), ""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(safeAccount.account); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Drain Safe balance - vm.prank(safeAccount.account); - token.transfer(agent2, INITIAL_SAFE_BALANCE); - - // Try to trigger - should fail due to insufficient balance - vm.expectEmit(true, true, true, true); - emit TopUpFailed(safeAccount.account, agent1, address(token), configId, "Insufficient account balance"); - - vm.prank(stranger); - executor.triggerTopUp(safeAccount.account, configId); - - // Agent balance should not change - assertEq(token.balanceOf(agent1), INITIAL_AGENT_BALANCE); - } - - function test_Integration_ModuleType() public { - // Verify module type - should only be true for EXECUTOR type - assertTrue(executor.isModuleType(MODULE_TYPE_EXECUTOR)); - assertFalse(executor.isModuleType(MODULE_TYPE_VALIDATOR)); - assertFalse(executor.isModuleType(MODULE_TYPE_FALLBACK)); - assertFalse(executor.isModuleType(MODULE_TYPE_HOOK)); - } -} diff --git a/typescript/packages/account-modules/test/AutoTopUpExecutor.t.sol b/typescript/packages/account-modules/test/AutoTopUpExecutor.t.sol deleted file mode 100644 index 4a865b9..0000000 --- a/typescript/packages/account-modules/test/AutoTopUpExecutor.t.sol +++ /dev/null @@ -1,941 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {Test, console2} from "forge-std/Test.sol"; -import {AutoTopUpExecutor} from "../src/AutoTopUpExecutor.sol"; -import {IAutoTopUpExecutor} from "../src/IAutoTopUpExecutor.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {BokkyPooBahsDateTimeLibrary} from "BokkyPooBahsDateTimeLibrary/contracts/BokkyPooBahsDateTimeLibrary.sol"; - -// Import mocks -import {MockERC20} from "./mocks/MockERC20.sol"; -import {MockUSDT} from "./mocks/MockUSDT.sol"; -import {MockSafe} from "./mocks/MockSafe.sol"; -import {MockTokenBadReturn} from "./mocks/MockTokenBadReturn.sol"; -import {MockTokenReturnsFalse} from "./mocks/MockTokenReturnsFalse.sol"; - -// Test contract with proper inheritance for module testing -contract AutoTopUpExecutorTest is Test { - // Main contracts - AutoTopUpExecutor public executor; - MockERC20 public token; - MockUSDT public usdt; - MockSafe public safe; - - // Test addresses - address public owner; - address public agent1; - address public agent2; - address public stranger; - - // Test constants - uint256 constant DAILY_LIMIT = 100 ether; - uint256 constant MONTHLY_LIMIT = 1000 ether; - uint256 constant INITIAL_SAFE_BALANCE = 10000 ether; - uint256 constant INITIAL_AGENT_BALANCE = 50 ether; // Below daily limit - - // Events to test - event ModuleInstalled(address indexed account, uint256 initialConfigs); - event ModuleUninstalled(address indexed account, uint256 removedConfigs); - event TopUpConfigured( - address indexed account, - address indexed agent, - address asset, - bytes32 indexed configId, - IAutoTopUpExecutor.TopUpConfig config - ); - event TopUpExecuted( - address indexed account, address indexed agent, address asset, bytes32 indexed configId, uint256 amount - ); - event TopUpFailed( - address indexed account, address indexed agent, address asset, bytes32 indexed configId, string reason - ); - event TopUpEnabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId); - event TopUpDisabled(address indexed account, address indexed agent, address asset, bytes32 indexed configId); - - function setUp() public { - // Set up test accounts - owner = makeAddr("owner"); - stranger = makeAddr("stranger"); - agent1 = makeAddr("agent1"); - agent2 = makeAddr("agent2"); - - // Deploy test tokens - token = new MockERC20("Test Token", "TEST"); - usdt = new MockUSDT(); - - // Deploy mock Safe - safe = new MockSafe(owner); - - // Deploy AutoTopUpExecutor as singleton - executor = new AutoTopUpExecutor(); - - // Enable executor as module on Safe - vm.prank(owner); - safe.enableModule(address(executor)); - - // Fund Safe with tokens - token.mint(address(safe), INITIAL_SAFE_BALANCE); - usdt.mint(address(safe), INITIAL_SAFE_BALANCE); - - // Give agents some initial balance (below daily limit) - token.mint(agent1, INITIAL_AGENT_BALANCE); - token.mint(agent2, INITIAL_AGENT_BALANCE); - usdt.mint(agent1, INITIAL_AGENT_BALANCE); - usdt.mint(agent2, INITIAL_AGENT_BALANCE); - } - - // ============ Module Installation Tests ============ - - function test_OnInstall_EmptyData() public { - // Install module without initial configs - vm.expectEmit(true, false, false, true); - emit ModuleInstalled(address(safe), 0); - - vm.prank(address(safe)); - executor.onInstall(""); - - assertTrue(executor.isInitialized(address(safe))); - } - - function test_OnInstall_WithSingleConfig() public { - // Prepare installation data - address[] memory agents = new address[](1); - address[] memory assets = new address[](1); - IAutoTopUpExecutor.TopUpConfig[] memory configs = new IAutoTopUpExecutor.TopUpConfig[](1); - - agents[0] = agent1; - assets[0] = address(token); - configs[0] = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - bytes memory installData = abi.encode(agents, assets, configs); - - // Calculate expected config ID - bytes32 configId = executor.generateConfigId(address(safe), agent1, address(token)); - - // Expect events - vm.expectEmit(true, true, true, true); - emit TopUpConfigured(address(safe), agent1, address(token), configId, configs[0]); - - vm.expectEmit(true, true, true, true); - emit TopUpEnabled(address(safe), agent1, address(token), configId); - - vm.expectEmit(true, false, false, true); - emit ModuleInstalled(address(safe), 1); - - vm.prank(address(safe)); - executor.onInstall(installData); - - assertTrue(executor.isInitialized(address(safe))); - - // Verify config was created - (IAutoTopUpExecutor.TopUpConfig memory config,) = executor.getTopUpById(configId); - assertEq(config.dailyLimit, DAILY_LIMIT); - assertEq(config.monthlyLimit, MONTHLY_LIMIT); - assertTrue(config.enabled); - } - - function test_OnInstall_RevertInvalidAgent() public { - // Try to install with zero address agent - address[] memory agents = new address[](1); - address[] memory assets = new address[](1); - IAutoTopUpExecutor.TopUpConfig[] memory configs = new IAutoTopUpExecutor.TopUpConfig[](1); - - agents[0] = address(0); // Invalid - assets[0] = address(token); - configs[0] = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - bytes memory installData = abi.encode(agents, assets, configs); - - vm.prank(address(safe)); - vm.expectRevert(IAutoTopUpExecutor.InvalidAgent.selector); - executor.onInstall(installData); - } - - // ============ Module Uninstallation Tests ============ - - function test_OnUninstall_CleansUpAllState() public { - // First install with configs - address[] memory agents = new address[](2); - address[] memory assets = new address[](2); - IAutoTopUpExecutor.TopUpConfig[] memory configs = new IAutoTopUpExecutor.TopUpConfig[](2); - - agents[0] = agent1; - agents[1] = agent2; - assets[0] = address(token); - assets[1] = address(token); - - for (uint256 i = 0; i < 2; i++) { - configs[i] = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - } - - vm.prank(address(safe)); - executor.onInstall(abi.encode(agents, assets, configs)); - - // Verify installation - assertTrue(executor.isInitialized(address(safe))); - (IAutoTopUpExecutor.TopUpConfig[] memory retrievedConfigs,) = executor.getTopUpConfigs(address(safe)); - assertEq(retrievedConfigs.length, 2); - - // Now uninstall - vm.expectEmit(true, false, false, true); - emit ModuleUninstalled(address(safe), 2); - - vm.prank(address(safe)); - executor.onUninstall(""); - - // Verify all state is cleaned - assertFalse(executor.isInitialized(address(safe))); - (retrievedConfigs,) = executor.getTopUpConfigs(address(safe)); - assertEq(retrievedConfigs.length, 0); - } - - // ============ Configuration Management Tests ============ - - function test_ConfigureTopUp_NewConfig() public { - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - bytes32 expectedConfigId = executor.generateConfigId(address(safe), agent1, address(token)); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - assertEq(configId, expectedConfigId); - - // Verify config was created - (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig, IAutoTopUpExecutor.TopUpState memory state) = - executor.getTopUpById(configId); - assertEq(retrievedConfig.dailyLimit, DAILY_LIMIT); - assertEq(retrievedConfig.monthlyLimit, MONTHLY_LIMIT); - assertTrue(retrievedConfig.enabled); - assertEq(state.agent, agent1); - assertEq(state.asset, address(token)); - } - - function test_ConfigureTopUp_RevertInvalidAgent_ZeroAddress() public { - // Setup: Install module - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - // Try to configure with zero address agent - vm.prank(address(safe)); - vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.InvalidAgent.selector)); - executor.configureTopUp(address(0), address(token), config); - } - - function test_ConfigureTopUp_RevertInvalidAgent_SameAsAccount() public { - // Setup: Install module - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - // Try to configure with agent same as account (msg.sender) - vm.prank(address(safe)); - vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.InvalidAgent.selector)); - executor.configureTopUp(address(safe), address(token), config); - } - - function test_ConfigureTopUp_RevertInvalidAsset() public { - // Setup: Install module - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - // Try to configure with zero address asset - vm.prank(address(safe)); - vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.InvalidAsset.selector)); - executor.configureTopUp(agent1, address(0), config); - } - - function test_ConfigureTopUp_MaxValues() public { - // Setup: Install module - vm.prank(address(safe)); - executor.onInstall(""); - - // Test with maximum uint256 values - IAutoTopUpExecutor.TopUpConfig memory config = IAutoTopUpExecutor.TopUpConfig({ - dailyLimit: type(uint256).max, monthlyLimit: type(uint256).max, enabled: true - }); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Verify config was created successfully - (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig,) = executor.getTopUpById(configId); - assertEq(retrievedConfig.dailyLimit, type(uint256).max); - assertEq(retrievedConfig.monthlyLimit, type(uint256).max); - assertTrue(retrievedConfig.enabled); - } - - function test_ConfigureTopUp_RevertInvalidConfiguration() public { - vm.prank(address(safe)); - executor.onInstall(""); - - // Zero daily limit - IAutoTopUpExecutor.TopUpConfig memory config1 = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: 0, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - vm.expectRevert(IAutoTopUpExecutor.InvalidConfiguration.selector); - executor.configureTopUp(agent1, address(token), config1); - - // Zero monthly limit - IAutoTopUpExecutor.TopUpConfig memory config2 = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: 0, enabled: true}); - - vm.prank(address(safe)); - vm.expectRevert(IAutoTopUpExecutor.InvalidConfiguration.selector); - executor.configureTopUp(agent1, address(token), config2); - } - - // ============ Enable/Disable Tests ============ - - function test_EnableDisableTopUp() public { - // Setup disabled config - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: false}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Enable it - vm.expectEmit(true, true, true, true); - emit TopUpEnabled(address(safe), agent1, address(token), configId); - - vm.prank(address(safe)); - executor.enableTopUp(configId); - - // Verify it's enabled - (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig,) = executor.getTopUpById(configId); - assertTrue(retrievedConfig.enabled); - - // Disable it - vm.expectEmit(true, true, true, true); - emit TopUpDisabled(address(safe), agent1, address(token), configId); - - vm.prank(address(safe)); - executor.disableTopUp(configId); - - // Verify it's disabled - (retrievedConfig,) = executor.getTopUpById(configId); - assertFalse(retrievedConfig.enabled); - } - - function test_EnableDisable_RevertUnauthorized() public { - // Setup config as safe account - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: false}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Try to enable as stranger (should fail - module not initialized) - vm.prank(stranger); - vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); - executor.enableTopUp(configId); - - // Try to disable as stranger (should fail - module not initialized) - vm.prank(stranger); - vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); - executor.disableTopUp(configId); - - // Now test with an initialized but unauthorized account - address otherAccount = makeAddr("otherAccount"); - vm.prank(otherAccount); - executor.onInstall(""); - - // Try to enable config owned by safe account (should fail - unauthorized) - vm.prank(otherAccount); - vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.Unauthorized.selector, configId, otherAccount)); - executor.enableTopUp(configId); - } - - // ============ View Function Tests ============ - - function test_ConfigureTopUpById_Success() public { - // Setup: Install module and create initial config - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory initialConfig = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: false}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), initialConfig); - - // Update config by ID - IAutoTopUpExecutor.TopUpConfig memory newConfig = IAutoTopUpExecutor.TopUpConfig({ - dailyLimit: DAILY_LIMIT * 2, monthlyLimit: MONTHLY_LIMIT * 3, enabled: true - }); - - vm.expectEmit(true, true, true, true); - emit TopUpConfigured(address(safe), agent1, address(token), configId, newConfig); - vm.expectEmit(true, true, true, true); - emit TopUpEnabled(address(safe), agent1, address(token), configId); - - vm.prank(address(safe)); - executor.configureTopUpById(configId, newConfig); - - // Verify config was updated - (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig,) = executor.getTopUpById(configId); - assertEq(retrievedConfig.dailyLimit, DAILY_LIMIT * 2); - assertEq(retrievedConfig.monthlyLimit, MONTHLY_LIMIT * 3); - assertTrue(retrievedConfig.enabled); - } - - function test_ConfigureTopUpById_RevertModuleNotInitialized() public { - // Don't install module for safe - bytes32 configId = keccak256("dummy"); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, address(safe))); - executor.configureTopUpById(configId, config); - } - - function test_ConfigureTopUpById_RevertConfigNotFound() public { - // Install module but use non-existent configId - vm.prank(address(safe)); - executor.onInstall(""); - - bytes32 nonExistentConfigId = keccak256("nonexistent"); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ConfigNotFound.selector)); - executor.configureTopUpById(nonExistentConfigId, config); - } - - function test_ConfigureTopUpById_RevertUnauthorized() public { - // Setup: Safe creates a config - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Stranger tries to update safe's config - IAutoTopUpExecutor.TopUpConfig memory newConfig = IAutoTopUpExecutor.TopUpConfig({ - dailyLimit: DAILY_LIMIT * 2, monthlyLimit: MONTHLY_LIMIT * 2, enabled: false - }); - - vm.prank(stranger); - vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.ModuleNotInitialized.selector, stranger)); - executor.configureTopUpById(configId, newConfig); - } - - function test_ConfigureTopUpById_RevertInvalidConfiguration() public { - // Setup: Install module and create initial config - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory initialConfig = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), initialConfig); - - // Try to update with invalid config (zero daily limit) - IAutoTopUpExecutor.TopUpConfig memory invalidConfig = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: 0, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - vm.expectRevert(abi.encodeWithSelector(IAutoTopUpExecutor.InvalidConfiguration.selector)); - executor.configureTopUpById(configId, invalidConfig); - } - - function test_TriggerTopUp_EmitsEvent() public { - // Setup: Install module and configure top-up - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Agent has low balance, needs top-up - uint256 agentBalanceBefore = token.balanceOf(agent1); - uint256 expectedTopUp = DAILY_LIMIT - agentBalanceBefore; - - // Expect the TopUpExecuted event - vm.expectEmit(true, true, true, true); - emit TopUpExecuted(address(safe), agent1, address(token), configId, expectedTopUp); - - // Trigger the top-up - executor.triggerTopUp(address(safe), configId); - - // Verify the top-up was executed - assertEq(token.balanceOf(agent1), DAILY_LIMIT); - } - - function test_CanExecuteTopUp_Conditions() public { - // Setup - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Should be able to execute (agent balance is below daily limit) - (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); - assertTrue(canExecute); - assertEq(reason, ""); - - // Fund agent to be above daily limit - token.mint(agent1, DAILY_LIMIT); - - // Should not be able to execute now - (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); - assertFalse(canExecute); - assertEq(reason, "Agent balance sufficient"); - - // Test with disabled config - vm.prank(address(safe)); - executor.disableTopUp(configId); - - (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); - assertFalse(canExecute); - assertEq(reason, "Top-up disabled"); - } - - function test_TransferValidation_InvalidReturn() public { - // Setup: Install module and configure top-up - vm.prank(address(safe)); - executor.onInstall(""); - - // Create a token that returns malformed data - MockTokenBadReturn badToken = new MockTokenBadReturn(); - badToken.mint(address(safe), INITIAL_SAFE_BALANCE); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(badToken), config); - - // Should emit TopUpFailed when transfer returns malformed data (now caught by try-catch) - vm.prank(stranger); - vm.expectEmit(true, true, true, true); - emit TopUpFailed(address(safe), agent1, address(badToken), configId, "Transfer failed"); - executor.triggerTopUp(address(safe), configId); - - // Verify state was NOT updated (no top-up happened) - (, IAutoTopUpExecutor.TopUpState memory state) = executor.getTopUpById(configId); - assertEq(state.lastTopUpDay, 0); // Should remain 0 since transfer failed - assertEq(state.monthlySpent, 0); // Should remain 0 since transfer failed - } - - function test_TransferValidation_ReturnsFalse() public { - // Setup: Install module and configure top-up - vm.prank(address(safe)); - executor.onInstall(""); - - // Create a token that returns false on transfer - MockTokenReturnsFalse falseToken = new MockTokenReturnsFalse(); - falseToken.mint(address(safe), INITIAL_SAFE_BALANCE); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(falseToken), config); - - // Should emit TopUpFailed when transfer returns false (now caught by try-catch) - vm.prank(stranger); - vm.expectEmit(true, true, true, true); - emit TopUpFailed(address(safe), agent1, address(falseToken), configId, "Transfer failed"); - executor.triggerTopUp(address(safe), configId); - - // Verify state was NOT updated (no top-up happened) - (, IAutoTopUpExecutor.TopUpState memory state) = executor.getTopUpById(configId); - assertEq(state.lastTopUpDay, 0); // Should remain 0 since transfer failed - assertEq(state.monthlySpent, 0); // Should remain 0 since transfer failed - } - - function test_GetTopUp_Success() public { - // Setup: Install module and create config - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Test getTopUp function - (IAutoTopUpExecutor.TopUpConfig memory retrievedConfig, IAutoTopUpExecutor.TopUpState memory retrievedState) = - executor.getTopUp(address(safe), agent1, address(token)); - - assertEq(retrievedConfig.dailyLimit, DAILY_LIMIT); - assertEq(retrievedConfig.monthlyLimit, MONTHLY_LIMIT); - assertTrue(retrievedConfig.enabled); - assertEq(retrievedState.agent, agent1); - assertEq(retrievedState.asset, address(token)); - } - - function test_GetTopUp_NonExistentConfig() public { - // Test getTopUp with non-existent config - (IAutoTopUpExecutor.TopUpConfig memory config, IAutoTopUpExecutor.TopUpState memory state) = - executor.getTopUp(address(safe), agent1, address(token)); - - // Should return zero values for non-existent config - assertEq(config.dailyLimit, 0); - assertEq(config.monthlyLimit, 0); - assertFalse(config.enabled); - assertEq(state.agent, address(0)); - assertEq(state.asset, address(0)); - } - - function test_CanExecuteTopUp_ConfigNotFound() public { - bytes32 nonExistentConfigId = keccak256("nonexistent"); - - (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), nonExistentConfigId); - - assertFalse(canExecute); - assertEq(reason, "Config not found"); - } - - function test_CanExecuteTopUp_AccountDoesntOwnConfig() public { - // Setup: Safe creates a config - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Try to check canExecute with different account (stranger) - (bool canExecute, string memory reason) = executor.canExecuteTopUp(stranger, configId); - - assertFalse(canExecute); - assertEq(reason, "Account doesn't own config"); - } - - function test_GetTopUpConfigs() public { - // Install module and create multiple configs - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config1 = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - IAutoTopUpExecutor.TopUpConfig memory config2 = IAutoTopUpExecutor.TopUpConfig({ - dailyLimit: DAILY_LIMIT / 2, monthlyLimit: MONTHLY_LIMIT / 2, enabled: false - }); - - vm.startPrank(address(safe)); - executor.configureTopUp(agent1, address(token), config1); - executor.configureTopUp(agent2, address(usdt), config2); - vm.stopPrank(); - - // Get all configs - (IAutoTopUpExecutor.TopUpConfig[] memory configs, IAutoTopUpExecutor.TopUpState[] memory states) = - executor.getTopUpConfigs(address(safe)); - - assertEq(configs.length, 2); - assertEq(states.length, 2); - - // Verify first config - assertEq(configs[0].dailyLimit, DAILY_LIMIT); - assertEq(configs[0].monthlyLimit, MONTHLY_LIMIT); - assertTrue(configs[0].enabled); - - // Verify second config - assertEq(configs[1].dailyLimit, DAILY_LIMIT / 2); - assertEq(configs[1].monthlyLimit, MONTHLY_LIMIT / 2); - assertFalse(configs[1].enabled); - } - - // ============ Date Boundary Tests ============ - - function test_DailyLimitReset() public { - // Setup config with daily limit - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // First execution should work - (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); - assertTrue(canExecute); - assertEq(reason, ""); - - // Actually execute the top-up - vm.prank(address(safe)); - executor.triggerTopUp(address(safe), configId); - - // Should not be able to execute again same day (daily limit enforced) - (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); - assertFalse(canExecute); - assertEq(reason, "Already topped up today"); - - // Move to next day - vm.warp(block.timestamp + 1 days); - - // Now check - should not execute because agent balance is sufficient - (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); - assertFalse(canExecute); - assertEq(reason, "Agent balance sufficient"); - - // Reduce agent balance to need another top-up - vm.prank(agent1); - token.transfer(agent2, 60 ether); - - // Now should be able to execute - (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); - assertTrue(canExecute); - assertEq(reason, ""); - } - - function test_MonthlyLimitReset() public { - // Setup config with low monthly limit (just enough for 2 top-ups) - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = IAutoTopUpExecutor.TopUpConfig({ - dailyLimit: DAILY_LIMIT, - monthlyLimit: 110 ether, // Allows ~2 top-ups of 50 ether each - enabled: true - }); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // First top-up should work - vm.prank(address(safe)); - executor.triggerTopUp(address(safe), configId); - assertEq(token.balanceOf(agent1), DAILY_LIMIT); - - // Spend tokens and move to next day - vm.prank(agent1); - token.transfer(agent2, 90 ether); - vm.warp(block.timestamp + 1 days); - - // Second top-up should work (still within monthly limit) - vm.prank(address(safe)); - executor.triggerTopUp(address(safe), configId); - - // After second top-up, agent should have less than daily limit due to monthly limit - // Monthly limit is 110 ether, already spent 50 ether, so can only top up 60 ether more - // Agent had 10 ether, topped up by 60 ether to reach 70 ether - assertEq(token.balanceOf(agent1), 70 ether); - - // Spend tokens and move to next day (transfer less than balance) - vm.prank(agent1); - token.transfer(agent2, 60 ether); - vm.warp(block.timestamp + 1 days); - - // Third top-up should fail (monthly limit reached) - (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); - assertFalse(canExecute); - assertEq(reason, "Monthly limit reached"); - - // Move to next month (30 days forward to ensure month change) - vm.warp(block.timestamp + 30 days); - - // Should be able to execute again (new month) - (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); - assertTrue(canExecute); - assertEq(reason, ""); - - // Execute to verify it actually works - vm.prank(address(safe)); - executor.triggerTopUp(address(safe), configId); - assertEq(token.balanceOf(agent1), DAILY_LIMIT); - } - - function test_YearTransition() public { - // Setup config - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Set time to Dec 31, 2023 - vm.warp(1704067199); // Dec 31, 2023 23:59:59 UTC - - // Execute top-up on last day of year - vm.prank(address(safe)); - executor.triggerTopUp(address(safe), configId); - - // Reduce balance to need another top-up - vm.prank(agent1); - token.transfer(agent2, 60 ether); - - // Should not execute again same day - (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); - assertFalse(canExecute); - assertEq(reason, "Already topped up today"); - - // Move to Jan 1, 2024 (next year) - vm.warp(1704067200); // Jan 1, 2024 00:00:00 UTC - - // Should be able to execute (new day and new year) - (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); - assertTrue(canExecute); - assertEq(reason, ""); - - // Verify execution works - vm.prank(address(safe)); - executor.triggerTopUp(address(safe), configId); - assertEq(token.balanceOf(agent1), DAILY_LIMIT); - } - - function test_LeapYearFebruary() public { - // Setup config - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Set time to Feb 28, 2024 (leap year) - vm.warp(1709078400); // Feb 28, 2024 00:00:00 UTC - - // Execute top-up on Feb 28 - vm.prank(address(safe)); - executor.triggerTopUp(address(safe), configId); - - // Reduce balance - vm.prank(agent1); - token.transfer(agent2, 60 ether); - - // Move to Feb 29 (leap day) - vm.warp(1709164800); // Feb 29, 2024 00:00:00 UTC - - // Should be able to execute on leap day - (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); - assertTrue(canExecute); - assertEq(reason, ""); - - vm.prank(address(safe)); - executor.triggerTopUp(address(safe), configId); - - // Reduce balance again - vm.prank(agent1); - token.transfer(agent2, 60 ether); - - // Move to March 1 - vm.warp(1709251200); // March 1, 2024 00:00:00 UTC - - // Should be able to execute on March 1 - (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); - assertTrue(canExecute); - assertEq(reason, ""); - } - - // ============ Fuzz Tests ============ - - function testFuzz_DailyExecutionLimit(uint32 startTimestamp, uint32 timeDelta) public { - // Test that daily execution limit is enforced across various start times and deltas - // Bound start timestamp to reasonable range (year 2020-2030) - uint256 startTime = bound(uint256(startTimestamp), 1577836800, 1893456000); // 2020-2030 - vm.warp(startTime); - - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: DAILY_LIMIT, monthlyLimit: MONTHLY_LIMIT, enabled: true}); - - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Execute first top-up - vm.prank(address(safe)); - executor.triggerTopUp(address(safe), configId); - - // Reduce balance to need another top-up - vm.prank(agent1); - token.transfer(agent2, 60 ether); - - // Calculate seconds remaining in current calendar day - (uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(block.timestamp); - uint256 endOfDay = BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day) + 86400 - 1; - uint256 secondsLeftInDay = endOfDay - block.timestamp; - - // Bound time delta to stay within current calendar day - uint256 deltaSeconds = bound(uint256(timeDelta), 0, secondsLeftInDay); - vm.warp(block.timestamp + deltaSeconds); - - // Should not be able to execute again same calendar day - (bool canExecute, string memory reason) = executor.canExecuteTopUp(address(safe), configId); - assertFalse(canExecute); - assertEq(reason, "Already topped up today"); - - // Move to next calendar day - vm.warp(block.timestamp + (secondsLeftInDay - deltaSeconds) + 1); - - // Now should be able to execute - (canExecute, reason) = executor.canExecuteTopUp(address(safe), configId); - assertTrue(canExecute); - assertEq(reason, ""); - } - - function testFuzz_ConfigurationLimits(uint256 dailyLimit, uint256 monthlyLimit) public { - // Bound to reasonable values - dailyLimit = bound(dailyLimit, 1, type(uint128).max); - monthlyLimit = bound(monthlyLimit, 1, type(uint128).max); - - vm.prank(address(safe)); - executor.onInstall(""); - - IAutoTopUpExecutor.TopUpConfig memory config = - IAutoTopUpExecutor.TopUpConfig({dailyLimit: dailyLimit, monthlyLimit: monthlyLimit, enabled: true}); - - // Should succeed with valid limits - vm.prank(address(safe)); - bytes32 configId = executor.configureTopUp(agent1, address(token), config); - - // Verify config was stored correctly - (IAutoTopUpExecutor.TopUpConfig memory retrieved,) = executor.getTopUpById(configId); - assertEq(retrieved.dailyLimit, dailyLimit); - assertEq(retrieved.monthlyLimit, monthlyLimit); - } -} diff --git a/typescript/packages/account-modules/test/mocks/MaliciousCollectToken.sol b/typescript/packages/account-modules/test/mocks/MaliciousCollectToken.sol deleted file mode 100644 index fffb1df..0000000 --- a/typescript/packages/account-modules/test/mocks/MaliciousCollectToken.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import {AutoCollectExecutor} from "../../src/AutoCollectExecutor.sol"; - -// Malicious token that tries to re-enter during transfer for collection tests -contract MaliciousCollectToken is ERC20 { - AutoCollectExecutor public target; - address public targetAccount; - address public targetAsset; - - constructor() ERC20("MaliciousCollect", "MALCOL") {} - - function setTarget(AutoCollectExecutor _target, address _account, address _asset) external { - target = _target; - targetAccount = _account; - targetAsset = _asset; - } - - function mint(address to, uint256 amount) external { - _mint(to, amount); - } - - function transfer(address to, uint256 amount) public override returns (bool) { - // Try to re-enter during transfer - if (address(target) != address(0)) { - try target.triggerCollection(targetAccount, targetAsset) {} catch {} - } - return super.transfer(to, amount); - } -} diff --git a/typescript/packages/account-modules/test/mocks/MaliciousToken.sol b/typescript/packages/account-modules/test/mocks/MaliciousToken.sol deleted file mode 100644 index e88e6b3..0000000 --- a/typescript/packages/account-modules/test/mocks/MaliciousToken.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import {AutoTopUpExecutor} from "../../src/AutoTopUpExecutor.sol"; - -// Malicious token that tries to re-enter during transfer -contract MaliciousToken is ERC20 { - AutoTopUpExecutor public target; - bytes32 public targetConfigId; - - constructor() ERC20("Malicious", "MAL") {} - - function setTarget(AutoTopUpExecutor _target, bytes32 _configId) external { - target = _target; - targetConfigId = _configId; - } - - function mint(address to, uint256 amount) external { - _mint(to, amount); - } - - function transfer(address to, uint256 amount) public override returns (bool) { - // Try to re-enter during transfer - if (address(target) != address(0)) { - try target.triggerTopUp(address(this), targetConfigId) {} catch {} - } - return super.transfer(to, amount); - } -} diff --git a/typescript/packages/account-modules/test/mocks/MockERC20.sol b/typescript/packages/account-modules/test/mocks/MockERC20.sol deleted file mode 100644 index 96c6a65..0000000 --- a/typescript/packages/account-modules/test/mocks/MockERC20.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - -contract MockERC20 is ERC20 { - constructor(string memory name, string memory symbol) ERC20(name, symbol) {} - - function mint(address to, uint256 amount) external { - _mint(to, amount); - } - - function burn(address from, uint256 amount) external { - _burn(from, amount); - } -} diff --git a/typescript/packages/account-modules/test/mocks/MockSafe.sol b/typescript/packages/account-modules/test/mocks/MockSafe.sol deleted file mode 100644 index 18d90ab..0000000 --- a/typescript/packages/account-modules/test/mocks/MockSafe.sol +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {ModeCode} from "modulekit/src/accounts/common/lib/ModeLib.sol"; -import {ExecutionLib} from "modulekit/src/accounts/erc7579/lib/ExecutionLib.sol"; - -// Mock Safe contract for testing ERC-7579 module execution -contract MockSafe { - mapping(address => bool) public isModuleEnabled; - - // Storage for execution results - bool public lastExecutionSuccess; - bytes public lastExecutionResult; - - // Mock owner for testing - address public owner; - - constructor(address _owner) { - owner = _owner; - } - - function enableModule(address module) external { - require(msg.sender == owner, "Only owner"); - isModuleEnabled[module] = true; - } - - // ERC-7579 compatible execution function - // This is called by the module's _execute function via ERC7579ExecutorBase - function executeFromExecutor( - ModeCode, // mode - we ignore this in the mock - bytes calldata executionCalldata - ) - external - payable - returns (bytes[] memory returnData) - { - require(isModuleEnabled[msg.sender], "Module not enabled"); - - // Decode the execution calldata - // For single execution mode, it's encoded as (target, value, callData) - (address target, uint256 value, bytes memory data) = ExecutionLib.decodeSingle(executionCalldata); - - // Execute the call - bool success; - bytes memory result; - (success, result) = target.call{value: value}(data); - lastExecutionSuccess = success; - lastExecutionResult = result; - - if (!success) { - // Bubble up the revert reason - assembly { - revert(add(result, 32), mload(result)) - } - } - - // Return as array (ERC-7579 expects array of results) - returnData = new bytes[](1); - returnData[0] = result; - - return returnData; - } -} diff --git a/typescript/packages/account-modules/test/mocks/MockTokenBadReturn.sol b/typescript/packages/account-modules/test/mocks/MockTokenBadReturn.sol deleted file mode 100644 index 28a2b79..0000000 --- a/typescript/packages/account-modules/test/mocks/MockTokenBadReturn.sol +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -// Mock ERC20 token that returns malformed data (not 32 bytes) on transfer -contract MockTokenBadReturn { - mapping(address => uint256) private _balances; - mapping(address => mapping(address => uint256)) private _allowances; - uint256 private _totalSupply; - - string public name = "Bad Return Token"; - string public symbol = "BAD"; - uint8 public decimals = 18; - - function totalSupply() public view returns (uint256) { - return _totalSupply; - } - - function balanceOf(address account) public view returns (uint256) { - return _balances[account]; - } - - function allowance(address owner, address spender) public view returns (uint256) { - return _allowances[owner][spender]; - } - - function approve(address spender, uint256 amount) external returns (bool) { - _allowances[msg.sender][spender] = amount; - return true; - } - - function transfer(address to, uint256 amount) external returns (bool) { - require(_balances[msg.sender] >= amount, "Insufficient balance"); - _balances[msg.sender] -= amount; - _balances[to] += amount; - - // Return malformed data (64 bytes instead of 32) - assembly { - let ptr := mload(0x40) - mstore(ptr, 0x0000000000000000000000000000000000000000000000000000000000000001) - mstore(add(ptr, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000001) - return(ptr, 0x40) - } - } - - function transferFrom(address from, address to, uint256 amount) external returns (bool) { - require(_balances[from] >= amount, "Insufficient balance"); - require(_allowances[from][msg.sender] >= amount, "Insufficient allowance"); - - _balances[from] -= amount; - _balances[to] += amount; - _allowances[from][msg.sender] -= amount; - - return true; - } - - function mint(address to, uint256 amount) external { - _balances[to] += amount; - _totalSupply += amount; - } -} diff --git a/typescript/packages/account-modules/test/mocks/MockTokenReturnsFalse.sol b/typescript/packages/account-modules/test/mocks/MockTokenReturnsFalse.sol deleted file mode 100644 index 1310406..0000000 --- a/typescript/packages/account-modules/test/mocks/MockTokenReturnsFalse.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -// Mock ERC20 token that returns false on transfer -contract MockTokenReturnsFalse { - mapping(address => uint256) private _balances; - mapping(address => mapping(address => uint256)) private _allowances; - uint256 private _totalSupply; - - string public name = "False Return Token"; - string public symbol = "FALSE"; - uint8 public decimals = 18; - - function totalSupply() public view returns (uint256) { - return _totalSupply; - } - - function balanceOf(address account) public view returns (uint256) { - return _balances[account]; - } - - function allowance(address owner, address spender) public view returns (uint256) { - return _allowances[owner][spender]; - } - - function approve(address spender, uint256 amount) external returns (bool) { - _allowances[msg.sender][spender] = amount; - return true; - } - - function transfer(address to, uint256 amount) external returns (bool) { - require(_balances[msg.sender] >= amount, "Insufficient balance"); - _balances[msg.sender] -= amount; - _balances[to] += amount; - - // Always return false even on successful transfer - return false; - } - - function transferFrom(address from, address to, uint256 amount) external returns (bool) { - require(_balances[from] >= amount, "Insufficient balance"); - require(_allowances[from][msg.sender] >= amount, "Insufficient allowance"); - - _balances[from] -= amount; - _balances[to] += amount; - _allowances[from][msg.sender] -= amount; - - return true; - } - - function mint(address to, uint256 amount) external { - _balances[to] += amount; - _totalSupply += amount; - } -} diff --git a/typescript/packages/account-modules/test/mocks/MockUSDT.sol b/typescript/packages/account-modules/test/mocks/MockUSDT.sol deleted file mode 100644 index 39ccb57..0000000 --- a/typescript/packages/account-modules/test/mocks/MockUSDT.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -// Mock ERC20 token that returns nothing on transfer (like USDT) -contract MockUSDT { - mapping(address => uint256) private _balances; - mapping(address => mapping(address => uint256)) private _allowances; - uint256 private _totalSupply; - - string public name = "Mock USDT"; - string public symbol = "mUSDT"; - uint8 public decimals = 6; - - function totalSupply() public view returns (uint256) { - return _totalSupply; - } - - function balanceOf(address account) public view returns (uint256) { - return _balances[account]; - } - - function allowance(address owner, address spender) public view returns (uint256) { - return _allowances[owner][spender]; - } - - // USDT-style transfer that returns nothing - function transfer(address to, uint256 amount) external { - require(_balances[msg.sender] >= amount, "Insufficient balance"); - _balances[msg.sender] -= amount; - _balances[to] += amount; - // No return value - mimics USDT behavior - } - - function approve(address spender, uint256 amount) external returns (bool) { - _allowances[msg.sender][spender] = amount; - return true; - } - - function transferFrom(address from, address to, uint256 amount) external returns (bool) { - require(_balances[from] >= amount, "Insufficient balance"); - require(_allowances[from][msg.sender] >= amount, "Insufficient allowance"); - - _balances[from] -= amount; - _balances[to] += amount; - _allowances[from][msg.sender] -= amount; - - return true; - } - - function mint(address to, uint256 amount) external { - _balances[to] += amount; - _totalSupply += amount; - } -} From ef1d15bee55d98c67a0ca6a61e12c9245787f958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Wed, 7 Jan 2026 10:42:02 -0300 Subject: [PATCH 3/3] lint: md files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .prettierignore | 3 ++ solidity/account-modules/README.md | 15 ++++-- .../docs/auto-collect/architecture.md | 41 +++++++++------ .../docs/auto-top-up/architecture.md | 50 ++++++++++++++++--- solidity/account-modules/script/README.md | 8 ++- 5 files changed, 87 insertions(+), 30 deletions(-) diff --git a/.prettierignore b/.prettierignore index f7ebd59..3ce4a66 100644 --- a/.prettierignore +++ b/.prettierignore @@ -18,3 +18,6 @@ tmp/ # Lock files pnpm-lock.yaml uv.lock + +# Solidity submodules (have their own prettier configs) +solidity/**/lib/ diff --git a/solidity/account-modules/README.md b/solidity/account-modules/README.md index 1e67976..07118cc 100644 --- a/solidity/account-modules/README.md +++ b/solidity/account-modules/README.md @@ -5,12 +5,14 @@ ERC-7579 compliant executor modules for smart account automation in the x402 pay ## Modules ### AutoTopUpModule + - Automatically tops up agent accounts when balance falls below threshold - Configurable per-agent limits (daily, monthly) - Permissionless triggering with proper checks - Used by: Main accounts to fund agent accounts -### AutoCollectModule +### AutoCollectModule + - Automatically collects payments from service accounts - Configurable collection thresholds (amount and time) - Batch collection optimization @@ -19,14 +21,16 @@ ERC-7579 compliant executor modules for smart account automation in the x402 pay ## Architecture All modules implement the ERC-7579 executor module interface: + - `onInstall(bytes calldata data)` - Module installation -- `onUninstall(bytes calldata data)` - Module removal +- `onUninstall(bytes calldata data)` - Module removal - `isModuleType(uint256 typeID)` - Returns true for executor type (0x01) - `isInitialized(address account)` - Check if module is initialized for account ## Deployment -The modules are deployed as immutable singletons using Safe's Singleton Factory, ensuring the same addresses across all chains: +The modules are deployed as immutable singletons using Safe's Singleton Factory, ensuring the same addresses across all +chains: - **AutoTopUpExecutor**: `0x16f13052FbFFfcE34E5752b7F4CFF881a030F40B` - **AutoCollectExecutor**: `0x29864bd91370886c38dE9Fe95F5589E7EbE15130` @@ -59,11 +63,12 @@ forge test forge script script/Deploy.s.sol --rpc-url $RPC_URL --broadcast ``` -**Important**: ModuleKit requires its node modules to be installed for proper compilation. This step (`pnpm install` in the modulekit directory) must be performed after cloning the repository and before building. +**Important**: ModuleKit requires its node modules to be installed for proper compilation. This step (`pnpm install` in +the modulekit directory) must be performed after cloning the repository and before building. ## Security - Non-custodial design - modules only execute based on user-defined rules - Access control via ERC-7579 standards - Immutable singleton contracts - no upgradeability, no owner -- Comprehensive event logging \ No newline at end of file +- Comprehensive event logging diff --git a/solidity/account-modules/docs/auto-collect/architecture.md b/solidity/account-modules/docs/auto-collect/architecture.md index 5da5185..f7d1d78 100644 --- a/solidity/account-modules/docs/auto-collect/architecture.md +++ b/solidity/account-modules/docs/auto-collect/architecture.md @@ -2,7 +2,9 @@ ## Overview -AutoCollectExecutor is an ERC-7579 executor module that automatically collects funds from service accounts to a main seller account. It mirrors the AutoTopUpExecutor pattern but reverses the transfer direction - collecting funds FROM the account where the module is installed TO a configured target account. +AutoCollectExecutor is an ERC-7579 executor module that automatically collects funds from service accounts to a main +seller account. It mirrors the AutoTopUpExecutor pattern but reverses the transfer direction - collecting funds FROM the +account where the module is installed TO a configured target account. ## Key Design Principles @@ -43,22 +45,26 @@ configId = keccak256(abi.encode("CollectConfig", serviceAccount, asset)) ### Core Functions #### Module Lifecycle + - `onInstall(bytes calldata data)` - Install with optional initial configurations - `onUninstall(bytes calldata)` - Clean up all configurations and state - `isModuleType(uint256 typeID)` - Returns MODULE_TYPE_EXECUTOR constant - `isInitialized(address account)` - Check if module is initialized for account #### Configuration Management + - `configureCollection(address asset, CollectConfig config)` - Create/update config for msg.sender - `enableCollection(bytes32 configId)` - Enable collection for a config - `disableCollection(bytes32 configId)` - Disable collection for a config #### Collection Execution + - `triggerCollection(address account, address asset)` - Trigger collection for specific asset on account - `triggerAllCollections(address account)` - Trigger all enabled collections for specific account - `canExecuteCollection(address account, address asset)` - Check if collection can execute #### View Functions + - `getCollectionConfig(address account, address asset)` - Get specific config - `getCollectionConfigs(address account)` - Get all configs for an account - `getCollectionState(address account, address asset)` - Get collection state @@ -66,6 +72,7 @@ configId = keccak256(abi.encode("CollectConfig", serviceAccount, asset)) ## Execution Flow ### Collection Trigger Flow + ``` 1. External caller → triggerCollection(account, asset) 2. Module validates: @@ -85,6 +92,7 @@ configId = keccak256(abi.encode("CollectConfig", serviceAccount, asset)) ``` ### Calendar Day Tracking + - Uses BokkyPooBah's DateTime Library (same as AutoTopUpExecutor) - Dates encoded as YYYYMMDD (e.g., 20240829) - All timestamps are UTC-based @@ -103,7 +111,7 @@ configId = keccak256(abi.encode("CollectConfig", serviceAccount, asset)) - ReentrancyGuard on execution functions 3. **Token Safety** - - Execute transfers via Safe's _execute() (like AutoTopUpExecutor) + - Execute transfers via Safe's \_execute() (like AutoTopUpExecutor) - Handle non-standard token returns by checking returndata length - Decode and validate return value if present - Zero-value transfer protection @@ -160,12 +168,12 @@ event CollectionDisabled(address indexed account, address indexed asset); - Asset must be valid ERC-20 contract - Threshold and minimumRemaining can both be 0 -3. **Date Boundaries** +4. **Date Boundaries** - Month transitions handled correctly - Year transitions handled correctly - Leap years considered -4. **Token Edge Cases** +5. **Token Edge Cases** - Non-standard return values (USDT) - Tokens with transfer fees - Balance changes between check and transfer (handled gracefully by skipping collection) @@ -184,18 +192,19 @@ event CollectionDisabled(address indexed account, address indexed asset); ## Differences from AutoTopUpExecutor -| Aspect | AutoTopUpExecutor | AutoCollectExecutor | -|--------|-------------------|---------------------| -| Installation | On main account | On service accounts | -| Transfer Direction | Main → Agent accounts | Service account → Main | -| Config Storage | Per (agent, asset) | Per (asset) on each account | -| Limits | Daily/Monthly amounts | Once per calendar day | -| Threshold | Top-up when below | Collect when above | -| Target | Multiple agents | Single main account | +| Aspect | AutoTopUpExecutor | AutoCollectExecutor | +| ------------------ | --------------------- | --------------------------- | +| Installation | On main account | On service accounts | +| Transfer Direction | Main → Agent accounts | Service account → Main | +| Config Storage | Per (agent, asset) | Per (asset) on each account | +| Limits | Daily/Monthly amounts | Once per calendar day | +| Threshold | Top-up when below | Collect when above | +| Target | Multiple agents | Single main account | ## Integration with Safe Accounts Service accounts will have AutoCollectExecutor installed as an ERC-7579 module: + ```solidity Safe Service Account ├── Owner: User's Privy Wallet @@ -229,24 +238,26 @@ Safe Service Account ## Implementation Notes ### Upgradeability + - Use UUPS proxy pattern (same as AutoTopUpExecutor) - OwnableUpgradeable for upgrade admin control - ERC-7201 namespaced storage for upgrade safety ### Dependencies + - BokkyPooBah's DateTime Library (already in lib/) - OpenZeppelin contracts upgradeable (including EnumerableSet) - ModuleKit for ERC-7579 compliance -- ERC7579ExecutorBase for _execute() functionality +- ERC7579ExecutorBase for \_execute() functionality ## Implementation Checklist - [ ] Core contract implementation (UUPS upgradeable) - [ ] Interface extraction (IAutoCollectExecutor) -- [ ] Token transfer via _execute() with returndata validation +- [ ] Token transfer via \_execute() with returndata validation - [ ] Calendar-based date tracking with DateTime library - [ ] Event and error definitions - [ ] Unit tests following AutoTopUpExecutor.t.sol patterns - [ ] Integration tests with ModuleKit - [ ] Gas optimization and forge fmt -- [ ] Security review \ No newline at end of file +- [ ] Security review diff --git a/solidity/account-modules/docs/auto-top-up/architecture.md b/solidity/account-modules/docs/auto-top-up/architecture.md index 6fc7821..db65f70 100644 --- a/solidity/account-modules/docs/auto-top-up/architecture.md +++ b/solidity/account-modules/docs/auto-top-up/architecture.md @@ -2,22 +2,27 @@ ## Overview -The AutoTopUpExecutor is an ERC-7579 executor module that enables automatic balance management for Safe smart accounts. It allows anyone to trigger pre-configured ERC-20 token transfers from a main Safe account to designated agent accounts when their balances fall below specified thresholds. +The AutoTopUpExecutor is an ERC-7579 executor module that enables automatic balance management for Safe smart accounts. +It allows anyone to trigger pre-configured ERC-20 token transfers from a main Safe account to designated agent accounts +when their balances fall below specified thresholds. ## Core Design Principles ### 1. Non-Custodial Architecture + - Module operates as part of the Safe's execution context - Never holds funds directly - User maintains full control over configuration and can disable at any time - Executions happen through Safe's module system ### 2. Permissionless Triggering + - Anyone can call the trigger function to execute configured top-ups - Security enforced through on-chain configuration and limits - Primary automation through our keeper infrastructure (with option for users to self-host) ### 3. Multi-Agent Support + - Single module instance manages multiple agent configurations - Each agent has independent thresholds, amounts, and limits - Efficient batch operations for checking and executing multiple top-ups @@ -25,14 +30,17 @@ The AutoTopUpExecutor is an ERC-7579 executor module that enables automatic bala ## Technical Architecture ### Module Type + - **Type**: Executor Module (0x01) - **Standard**: ERC-7579 compliant - **Base**: Rhinestone ModuleKit's `ERC7579ExecutorBase` - **Upgradeable**: Yes, using UUPS pattern with OpenZeppelin ### Storage Pattern + - **ERC-7201**: Namespaced storage for upgrade safety - **Storage Layout**: + ```solidity // User-configurable parameters struct TopUpConfig { @@ -53,16 +61,17 @@ The AutoTopUpExecutor is an ERC-7579 executor module that enables automatic bala struct AutoTopUpStorage { // Config ID => user configuration mapping(bytes32 => TopUpConfig) configs; - + // Config ID => internal state mapping(bytes32 => TopUpState) states; - + // Account => set of config IDs mapping(address => EnumerableSet.Bytes32Set) accountConfigs; } ``` -- **Config ID Generation**: `keccak256(abi.encode("TopUpConfig", account, agent, asset))` returns bytes32 for unique configs +- **Config ID Generation**: `keccak256(abi.encode("TopUpConfig", account, agent, asset))` returns bytes32 for unique + configs - **Namespaced IDs**: "TopUpConfig" prefix prevents collision with other system hashes - **Per-Account Execution**: Each account's configs are triggered separately to avoid gas limits - **Gas Optimization**: EnumerableSet allows O(1) add/remove and efficient iteration within an account @@ -70,10 +79,11 @@ The AutoTopUpExecutor is an ERC-7579 executor module that enables automatic bala ### Key Functions #### Module Interface (ERC-7579 via ModuleKit) + ```solidity // Inherited from ERC7579ExecutorBase function onInstall(bytes calldata data) external -function onUninstall(bytes calldata data) external +function onUninstall(bytes calldata data) external function isModuleType(uint256 typeID) external view returns (bool) function isInitialized(address smartAccount) external view returns (bool) @@ -84,6 +94,7 @@ function isInitialized(address smartAccount) external view returns (bool) ``` #### Configuration Management + ```solidity function configureTopUp( address agent, @@ -101,12 +112,14 @@ function enableTopUp(bytes32 configId) external ``` #### Execution + ```solidity function triggerTopUps(address account) external returns (bytes32[] memory executed) function triggerTopUp(bytes32 configId) external returns (bool executed) ``` #### View Functions + ```solidity function generateConfigId(address account, address agent, address asset) external pure returns (bytes32) function getTopUpConfigs(address account) external view returns (TopUpConfig[] memory, TopUpState[] memory) @@ -118,11 +131,13 @@ function getTopUp(address account, address agent, address asset) external view r ## Execution Flow ### 1. Installation + 1. Safe owner calls module management to install AutoTopUpExecutor 2. Module's `onInstall` is called with initial configurations (optional) 3. Module registers the Safe account as initialized ### 2. Configuration + 1. Safe owner sends transaction to module to configure top-ups 2. Config ID generated: `keccak256(abi.encode("TopUpConfig", account, agent, asset))` 3. `configureTopUp()` creates new or updates existing config for agent/asset pair @@ -133,6 +148,7 @@ function getTopUp(address account, address agent, address asset) external view r 8. Frontend/keeper can precompute config IDs using `generateConfigId()` ### 3. Triggering + 1. Keeper calls `triggerTopUps(account)` for each account (separate transactions) 2. Module iterates through all enabled configurations for that specific account 3. For each configuration: @@ -143,6 +159,7 @@ function getTopUp(address account, address agent, address asset) external view r - Update `lastTopUpTime` and `monthlySpent` ### 4. Limit Management + - **Daily**: Enforced by once-per-day check using `lastTopUpTime` - **Monthly**: Reset on the 1st of each month (tracked via `lastResetMonth`) - **Top-up calculation**: Always maintains balance up to `dailyLimit`, respecting `monthlyLimit` @@ -151,21 +168,25 @@ function getTopUp(address account, address agent, address asset) external view r ## Security Considerations ### Access Control + - Only Safe account can configure its own top-ups - Configuration updates require Safe transaction - No admin keys or external control ### Limit Enforcement + - Once-per-day enforcement prevents abuse - Monthly budget caps provide spending control - Simple calculation: top up to daily limit, not exceeding monthly budget ### Reentrancy Protection + - OpenZeppelin's ReentrancyGuard on all state-changing functions - Checks-effects-interactions pattern - State updates before external calls ### Validation + - Balance checks before transfers - Sufficient Safe balance validation - Asset address validation (ensure valid ERC-20 contract) @@ -174,11 +195,13 @@ function getTopUp(address account, address agent, address asset) external view r ## Gas Optimization ### Batch Operations + - Per-account batch execution (all configs for one account in one tx) - Bounded gas usage per transaction - Keeper maintains off-chain list of accounts to service ### Storage Efficiency + - EnumerableSet for per-account config tracking - O(1) config lookups via mapping - Config IDs prevent duplicate account/agent/asset combinations @@ -187,17 +210,20 @@ function getTopUp(address account, address agent, address asset) external view r ## Integration Points ### ERC-7579 Module System + - Registered as executor module (type 0x01) - Uses ModuleKit's `_execute()` helpers for execution - Works across all ERC-7579 compliant accounts (Safe, Kernel, Biconomy) ### Token Contracts + - ERC20 interface for balance checks - OpenZeppelin's SafeERC20 for safe token transfers -- Transfers executed via Safe module system (using _execute) +- Transfers executed via Safe module system (using \_execute) - No direct token approvals needed ### Monitoring & Events + ```solidity event TopUpConfigured(address indexed account, address indexed agent, address asset, bytes32 indexed configId, TopUpConfig config) event TopUpExecuted(address indexed account, address indexed agent, address asset, bytes32 indexed configId, uint256 amount) @@ -212,24 +238,28 @@ event TopUpDisabled(address indexed account, address indexed agent, address asse ## Future Enhancements ### Post-MVP Improvements + 1. **Native Token Support**: ETH/MATIC/etc. alongside ERC-20s 2. **Off-chain Signatures**: Gasless configuration updates via EIP-712 signed messages ## Testing Strategy ### Unit Tests + - Configuration CRUD operations - Daily limit enforcement (once per day) - Monthly limit tracking and resets - Balance calculation logic (top up to daily limit) -### Integration Tests +### Integration Tests + - Safe module installation/uninstallation using ModuleKit test utilities - Token transfer execution through Safe - Multi-account scenarios using ModuleKit's `makeAccountInstance` - Cross-implementation tests (Safe, Kernel, Biconomy) - lower priority ### Security Tests + - Reentrancy attempts - Limit bypass attempts (trying to trigger multiple times per day) - Unauthorized configuration changes @@ -238,6 +268,7 @@ event TopUpDisabled(address indexed account, address indexed agent, address asse ## Implementation Stack ### Dependencies + - **ModuleKit** (v0.5.9+): Rhinestone's development kit for ERC-7579 modules - Provides `ERC7579ExecutorBase` for executor functionality - Built-in test utilities for multi-account testing (Safe, Kernel, Biconomy) @@ -249,6 +280,7 @@ event TopUpDisabled(address indexed account, address indexed agent, address asse - **OpenZeppelin Contracts**: For ERC20 interface and security utilities ### Inheritance Chain + ``` AutoTopUpExecutor ├── ERC7579ExecutorBase (from ModuleKit) @@ -261,6 +293,7 @@ AutoTopUpExecutor ## Deployment Considerations ### Deployment Steps + 1. Deploy implementation contract 2. Deploy proxy with initializer 3. Register in Rhinestone module registry @@ -268,5 +301,6 @@ AutoTopUpExecutor 5. Utilize ModuleKit's deployment helpers ### Monitoring + - Subgraph for indexing all contract events -- Track and alert on failed top-ups (especially during initial rollout) \ No newline at end of file +- Track and alert on failed top-ups (especially during initial rollout) diff --git a/solidity/account-modules/script/README.md b/solidity/account-modules/script/README.md index d02fbf6..ac456f5 100644 --- a/solidity/account-modules/script/README.md +++ b/solidity/account-modules/script/README.md @@ -2,16 +2,19 @@ ## Deploy.s.sol -Deploys the AutoTopUpExecutor and AutoCollectExecutor modules using Safe's Singleton Factory for deterministic addresses across all chains. +Deploys the AutoTopUpExecutor and AutoCollectExecutor modules using Safe's Singleton Factory for deterministic addresses +across all chains. ### Usage #### Predict Addresses (without deploying) + ```bash forge script script/Deploy.s.sol:Deploy --sig "predict()" ``` #### Deploy to a Network + ```bash # Set required environment variables export PRIVATE_KEY= @@ -32,6 +35,7 @@ forge script script/Deploy.s.sol:Deploy \ ### Deployed Addresses The modules will be deployed to the same addresses on all chains: + - **AutoTopUpExecutor**: `0x92Be8FA04bF1d9Ee311F4B2754Ca22252ccA18D4` - **AutoCollectExecutor**: `0x6647fA97ff1f04614A0A960dcF499545c4DcC431` @@ -39,4 +43,4 @@ The modules will be deployed to the same addresses on all chains: - The contracts are deployed as immutable singletons (no upgradeability, no owner) - Addresses are deterministic using Safe Singleton Factory -- The factory is deployed on 250+ chains at: `0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7` \ No newline at end of file +- The factory is deployed on 250+ chains at: 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 z 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�%Y5@MSyC#8E-c4W=h3xls!eWGApPoE(_giI^5 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�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﫳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

    uDAXVjwEX$UW6zfZ;LYe% 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 z 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�%Y5@MSyC#8E-c4W=h3xls!eWGApPoE(_giI^5 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�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﫳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